From 773fd1a707f5abff63c4fd47b73580faba65d468 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 15:58:05 -0500 Subject: [PATCH 0001/4206] initial commit --- library/compiler-builtins/.gitignore | 3 + library/compiler-builtins/Cargo.toml | 4 + library/compiler-builtins/LICENSE-APACHE | 201 +++++++++++++++++++++++ library/compiler-builtins/LICENSE-MIT | 25 +++ library/compiler-builtins/README.md | 23 +++ library/compiler-builtins/src/arm.rs | 67 ++++++++ library/compiler-builtins/src/lib.rs | 43 +++++ library/compiler-builtins/src/test.rs | 25 +++ library/compiler-builtins/src/x86_64.rs | 9 + 9 files changed, 400 insertions(+) create mode 100644 library/compiler-builtins/.gitignore create mode 100644 library/compiler-builtins/Cargo.toml create mode 100644 library/compiler-builtins/LICENSE-APACHE create mode 100644 library/compiler-builtins/LICENSE-MIT create mode 100644 library/compiler-builtins/README.md create mode 100644 library/compiler-builtins/src/arm.rs create mode 100644 library/compiler-builtins/src/lib.rs create mode 100644 library/compiler-builtins/src/test.rs create mode 100644 library/compiler-builtins/src/x86_64.rs diff --git a/library/compiler-builtins/.gitignore b/library/compiler-builtins/.gitignore new file mode 100644 index 0000000000000..b203ea61f2a48 --- /dev/null +++ b/library/compiler-builtins/.gitignore @@ -0,0 +1,3 @@ +*.rs.bk +Cargo.lock +target diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml new file mode 100644 index 0000000000000..663d9b109a40c --- /dev/null +++ b/library/compiler-builtins/Cargo.toml @@ -0,0 +1,4 @@ +[package] +authors = ["Jorge Aparicio "] +name = "rustc_builtins" +version = "0.1.0" diff --git a/library/compiler-builtins/LICENSE-APACHE b/library/compiler-builtins/LICENSE-APACHE new file mode 100644 index 0000000000000..16fe87b06e802 --- /dev/null +++ b/library/compiler-builtins/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/library/compiler-builtins/LICENSE-MIT b/library/compiler-builtins/LICENSE-MIT new file mode 100644 index 0000000000000..a43445e6cd1b9 --- /dev/null +++ b/library/compiler-builtins/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 Jorge Aparicio + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md new file mode 100644 index 0000000000000..f54664faece09 --- /dev/null +++ b/library/compiler-builtins/README.md @@ -0,0 +1,23 @@ +[![Build Status][status]](https://travis-ci.org/japaric/rustc-builtins) + +[status]: https://travis-ci.org/japaric/rustc-builtins.svg?branch=master + +# `rustc-builtins` + +> [WIP] Porting `compiler-rt` intrinsics to Rust + +## License + +Licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the +work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any +additional terms or conditions. diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs new file mode 100644 index 0000000000000..0be06a4dfbb99 --- /dev/null +++ b/library/compiler-builtins/src/arm.rs @@ -0,0 +1,67 @@ +use core::intrinsics; + +macro_rules! defer { + ($($symbol:ident),+ -> $routine:ident) => { + $( + #[naked] + #[no_mangle] + pub extern "C" fn $symbol() { + unsafe { + asm!(concat!("b ", stringify!($routine))); + intrinsics::unreachable(); + } + } + )+ + } +} + +// FIXME only `__aeabi_memcmp` should be defined like this. The `*4` and `*8` variants should be +// defined as aliases of `__aeabi_memcmp` +defer!(__aeabi_memcmp, __aeabi_memcmp4, __aeabi_memcmp8 -> memcmp); + +// FIXME same issue as `__aeabi_memcmp*` +defer!(__aeabi_memcpy, __aeabi_memcpy4, __aeabi_memcpy8 -> memcpy); + +// FIXME same issue as `__aeabi_memcmp*` +defer!(__aeabi_memmove, __aeabi_memmove4, __aeabi_memmove8 -> memmove); + +macro_rules! memset { + ($($symbol:ident),+) => { + $( + #[naked] + #[no_mangle] + pub extern "C" fn $symbol() { + unsafe { + asm!("mov r3, r1 + mov r1, r2 + mov r2, r3 + b memset"); + intrinsics::unreachable(); + } + } + )+ + } +} + +// FIXME same issue as `__aeabi_memcmp*` +memset!(__aeabi_memset, __aeabi_memset4, __aeabi_memset8); + +macro_rules! memclr { + ($($symbol:ident),+) => { + $( + #[naked] + #[no_mangle] + pub extern "C" fn $symbol() { + unsafe { + asm!("mov r2, r1 + mov r1, #0 + b memset"); + intrinsics::unreachable(); + } + } + )+ + } +} + +// FIXME same issue as `__aeabi_memcmp*` +memclr!(__aeabi_memclr, __aeabi_memclr4, __aeabi_memclr8); diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs new file mode 100644 index 0000000000000..838e62a296bf4 --- /dev/null +++ b/library/compiler-builtins/src/lib.rs @@ -0,0 +1,43 @@ +#![allow(unused_features)] +#![cfg_attr(not(test), no_std)] +#![feature(asm)] +#![feature(core_intrinsics)] +#![feature(naked_functions)] +// TODO(rust-lang/rust#35021) uncomment when that PR lands +// #![feature(rustc_builtins)] + +#[cfg(test)] +extern crate core; + +use core::mem; + +#[cfg(target_arch = "arm")] +pub mod arm; + +#[cfg(target_arch = "x86_64")] +pub mod x86_64; + +#[cfg(test)] +mod test; + +const CHAR_BITS: usize = 8; + +macro_rules! absv_i2 { + ($intrinsic:ident : $ty:ty) => { + #[no_mangle] + pub extern "C" fn $intrinsic(x: $ty) -> $ty { + let n = mem::size_of::<$ty>() * CHAR_BITS; + if x == 1 << (n - 1) { + panic!(); + } + let y = x >> (n - 1); + (x ^ y) - y + } + + } +} + +absv_i2!(__absvsi2: i32); +absv_i2!(__absvdi2: i64); +// TODO(rust-lang/35118)? +// absv_i2!(__absvti2, i128); diff --git a/library/compiler-builtins/src/test.rs b/library/compiler-builtins/src/test.rs new file mode 100644 index 0000000000000..9abfec7e800bb --- /dev/null +++ b/library/compiler-builtins/src/test.rs @@ -0,0 +1,25 @@ +use std::panic; + +macro_rules! absv_i2 { + ($intrinsic:ident: $ty:ident) => { + #[test] + fn $intrinsic() { + assert!(panic::catch_unwind(|| ::$intrinsic(::std::$ty::MIN)).is_err()); + assert_eq!(::$intrinsic(::std::$ty::MIN + 1), ::std::$ty::MAX); + assert_eq!(::$intrinsic(::std::$ty::MIN + 2), ::std::$ty::MAX - 1); + assert_eq!(::$intrinsic(-1), 1); + assert_eq!(::$intrinsic(-2), 2); + assert_eq!(::$intrinsic(0), 0); + assert_eq!(::$intrinsic(1), 1); + assert_eq!(::$intrinsic(2), 2); + assert_eq!(::$intrinsic(2), 2); + assert_eq!(::$intrinsic(::std::$ty::MAX - 1), ::std::$ty::MAX - 1); + assert_eq!(::$intrinsic(::std::$ty::MAX), ::std::$ty::MAX); + } + } +} + +absv_i2!(__absvsi2: i32); +absv_i2!(__absvdi2: i64); +// TODO(rust-lang/35118)? +// absv_i2!(__absvti2: i128); diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs new file mode 100644 index 0000000000000..d4ea0f759de3e --- /dev/null +++ b/library/compiler-builtins/src/x86_64.rs @@ -0,0 +1,9 @@ +#[no_mangle] +pub extern "C" fn __floatdisf(x: i64) -> f32 { + x as f32 +} + +#[no_mangle] +pub extern "C" fn __floatdidf(x: i64) -> f64 { + x as f64 +} From 51db348a3f640214300026a238131939773bad1c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 16:01:28 -0500 Subject: [PATCH 0002/4206] README: link back to rust-lang/rust issue --- library/compiler-builtins/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index f54664faece09..e2fc6a17131b8 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -6,6 +6,10 @@ > [WIP] Porting `compiler-rt` intrinsics to Rust +See [rust-lang/rust#35437][0]. + +[0]: https://github.com/rust-lang/rust/issues/35437 + ## License Licensed under either of From 178fa2a806c0e1d12b0df9183505c6c36c14ab58 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 16:55:30 -0500 Subject: [PATCH 0003/4206] travis CI --- library/compiler-builtins/.travis.yml | 61 +++++++++++++++++++++++++ library/compiler-builtins/ci/env.sh | 23 ++++++++++ library/compiler-builtins/ci/install.sh | 31 +++++++++++++ library/compiler-builtins/ci/script.sh | 48 +++++++++++++++++++ 4 files changed, 163 insertions(+) create mode 100644 library/compiler-builtins/.travis.yml create mode 100644 library/compiler-builtins/ci/env.sh create mode 100644 library/compiler-builtins/ci/install.sh create mode 100644 library/compiler-builtins/ci/script.sh diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml new file mode 100644 index 0000000000000..63faac24cdea9 --- /dev/null +++ b/library/compiler-builtins/.travis.yml @@ -0,0 +1,61 @@ +language: generic + +matrix: + include: + - env: TARGET=aarch64-unknown-linux-gnu + os: linux + dist: trusty + sudo: required + addons: + apt: + packages: + - binfmt-support + - qemu-user-static + - env: TARGET=arm-unknown-linux-gnueabi + os: linux + sudo: required + addons: + apt: + packages: + - binfmt-support + - gcc-arm-linux-gnueabi + - libc6-armel-cross + - qemu-user-static + - env: TARGET=arm-unknown-linux-gnueabihf + os: linux + sudo: required + addons: + apt: + packages: &armhf + - binfmt-support + - gcc-arm-linux-gnueabihf + - libc6-armhf-cross + - qemu-user-static + - env: TARGET=armv7-unknown-linux-gnueabihf + os: linux + sudo: required + addons: + apt: + packages: *armhf + - env: TARGET=i686-apple-darwin + os: osx + - env: TARGET=i686-unknown-linux-gnu + os: linux + addons: + apt: + packages: + - gcc-multilib + - env: TARGET=x86_64-apple-darwin + os: osx + - env: TARGET=x86_64-unknown-linux-gnu + os: linux + +install: + - bash ci/install.sh + +script: + - bash ci/script.sh + +notifications: + email: + on_success: never diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh new file mode 100644 index 0000000000000..ad76689789d33 --- /dev/null +++ b/library/compiler-builtins/ci/env.sh @@ -0,0 +1,23 @@ +case $TRAVIS_OS_NAME in + linux) + export HOST=x86_64-unknown-linux-gnu + ;; + osx) + export HOST=x86_64-apple-darwin + ;; +esac + +case $TARGET in + aarch64-unknown-linux-gnu) + export PREFIX=aarch64-linux-gnu- + export QEMU_LD_PREFIX=/usr/aarch64-linux-gnu + ;; + arm*-unknown-linux-gnueabi) + export PREFIX=arm-linux-gnueabi- + export QEMU_LD_PREFIX=/usr/arm-linux-gnueabi + ;; + arm*-unknown-linux-gnueabihf) + export PREFIX=arm-linux-gnueabihf- + export QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf + ;; +esac diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh new file mode 100644 index 0000000000000..a66c5d0ee1fad --- /dev/null +++ b/library/compiler-builtins/ci/install.sh @@ -0,0 +1,31 @@ +set -ex + +. $(dirname $0)/env.sh + +build() { + cargo build --target $TARGET + cargo build --target $TARGET --release +} + +run_tests() { + if [[ $QEMU_LD_PREFIX ]]; then + export RUST_TEST_THREADS=1 + fi + + cargo test --target $TARGET + cargo test --target $TARGET --release +} + +inspect() { + ${PREFIX}nm -g --defined-only target/**/debug/*.rlib + ${PREFIX}objdump target/**/debug/*.rlib + ${PREFIX}objdump target/**/release/*.rlib +} + +main() { + build + run_tests + inspect +} + +main diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh new file mode 100644 index 0000000000000..c2fcdb8078eaa --- /dev/null +++ b/library/compiler-builtins/ci/script.sh @@ -0,0 +1,48 @@ +set -ex + +. $(dirname $0)/env.sh + +install_c_toolchain() { + case $TARGET in + aarch64-unknown-linux-gnu) + sudo apt-get install -y --no-install-recommends \ + gcc-aarch64-linux-gnu libc6-arm64-cross libc6-dev-arm64-cross + ;; + *) + ;; + esac +} + +install_rust() { + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain=nightly + + rustc -V + cargo -V +} + +add_rustup_target() { + if [[ $TARGET != $HOST ]]; then + rustup target add $TARGET + fi +} + +configure_cargo() { + if [[ $PREFIX ]]; then + ${PREFIX}gcc -v + + mkdir -p .cargo + cat >>.cargo/config < Date: Sun, 7 Aug 2016 16:58:44 -0500 Subject: [PATCH 0004/4206] set $PATH --- library/compiler-builtins/.travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 63faac24cdea9..364e4d940cc9b 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -50,6 +50,9 @@ matrix: - env: TARGET=x86_64-unknown-linux-gnu os: linux +before_install: + - export PATH="$PATH:$HOME/.cargo/bin" + install: - bash ci/install.sh From 898869871e8479942d1cc9225a91b415bdc4368a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 16:59:54 -0500 Subject: [PATCH 0005/4206] only test on master --- library/compiler-builtins/.travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 364e4d940cc9b..27a141355864e 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -59,6 +59,10 @@ install: script: - bash ci/script.sh +branches: + only: + - master + notifications: email: on_success: never From 5dbc8d97298e3e50919382d96146190be3e0fc69 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 17:03:44 -0500 Subject: [PATCH 0006/4206] swap install.sh and script.sh --- library/compiler-builtins/ci/install.sh | 49 +++++++++++++++++-------- library/compiler-builtins/ci/script.sh | 49 ++++++++----------------- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index a66c5d0ee1fad..c2fcdb8078eaa 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -2,30 +2,47 @@ set -ex . $(dirname $0)/env.sh -build() { - cargo build --target $TARGET - cargo build --target $TARGET --release +install_c_toolchain() { + case $TARGET in + aarch64-unknown-linux-gnu) + sudo apt-get install -y --no-install-recommends \ + gcc-aarch64-linux-gnu libc6-arm64-cross libc6-dev-arm64-cross + ;; + *) + ;; + esac } -run_tests() { - if [[ $QEMU_LD_PREFIX ]]; then - export RUST_TEST_THREADS=1 - fi +install_rust() { + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain=nightly + + rustc -V + cargo -V +} - cargo test --target $TARGET - cargo test --target $TARGET --release +add_rustup_target() { + if [[ $TARGET != $HOST ]]; then + rustup target add $TARGET + fi } -inspect() { - ${PREFIX}nm -g --defined-only target/**/debug/*.rlib - ${PREFIX}objdump target/**/debug/*.rlib - ${PREFIX}objdump target/**/release/*.rlib +configure_cargo() { + if [[ $PREFIX ]]; then + ${PREFIX}gcc -v + + mkdir -p .cargo + cat >>.cargo/config <>.cargo/config < Date: Sun, 7 Aug 2016 17:07:12 -0500 Subject: [PATCH 0007/4206] install libc6-dev for ARM targets --- library/compiler-builtins/.travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 27a141355864e..d8ff366262c00 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -20,6 +20,7 @@ matrix: - binfmt-support - gcc-arm-linux-gnueabi - libc6-armel-cross + - libc6-dev-armel-cross - qemu-user-static - env: TARGET=arm-unknown-linux-gnueabihf os: linux @@ -30,6 +31,7 @@ matrix: - binfmt-support - gcc-arm-linux-gnueabihf - libc6-armhf-cross + - libc6-dev-armhf-cross - qemu-user-static - env: TARGET=armv7-unknown-linux-gnueabihf os: linux From 0921a91b267f994ba6a479f76b47de427e272307 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 17:07:58 -0500 Subject: [PATCH 0008/4206] fix objdump commands --- library/compiler-builtins/ci/script.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index a66c5d0ee1fad..5952f7ecbfa56 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -18,8 +18,8 @@ run_tests() { inspect() { ${PREFIX}nm -g --defined-only target/**/debug/*.rlib - ${PREFIX}objdump target/**/debug/*.rlib - ${PREFIX}objdump target/**/release/*.rlib + ${PREFIX}objdump -Cd target/**/debug/*.rlib + ${PREFIX}objdump -Cd target/**/release/*.rlib } main() { From f8099c755e14a9c9d6f65fb8216ef27df7d48d72 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 17:10:36 -0500 Subject: [PATCH 0009/4206] use container-based infrastructure --- library/compiler-builtins/.travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index d8ff366262c00..c09c3bb49bf89 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -1,4 +1,5 @@ language: generic +sudo: false matrix: include: From 4cbba5979d53b04373061384f87becd16b2a90b6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 17:13:29 -0500 Subject: [PATCH 0010/4206] ignore objdump exit code --- library/compiler-builtins/ci/script.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 5952f7ecbfa56..01f6ff5057011 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -18,8 +18,10 @@ run_tests() { inspect() { ${PREFIX}nm -g --defined-only target/**/debug/*.rlib + set +e ${PREFIX}objdump -Cd target/**/debug/*.rlib ${PREFIX}objdump -Cd target/**/release/*.rlib + set -e } main() { From 48d9ff7e805d9fe0b213145c530af58f6dc4bc60 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 17:18:37 -0500 Subject: [PATCH 0011/4206] nm: drop --defined-only flag it doesn't work on macOS --- library/compiler-builtins/ci/script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 01f6ff5057011..c3e1a65fc2991 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -17,7 +17,7 @@ run_tests() { } inspect() { - ${PREFIX}nm -g --defined-only target/**/debug/*.rlib + ${PREFIX}nm -g target/**/debug/*.rlib set +e ${PREFIX}objdump -Cd target/**/debug/*.rlib ${PREFIX}objdump -Cd target/**/release/*.rlib From a0de8f0bdb898c0559b785c4e4aff2035404cce1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 17:23:30 -0500 Subject: [PATCH 0012/4206] macOS: install binutils --- library/compiler-builtins/ci/install.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index c2fcdb8078eaa..595a985cecfc6 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -13,6 +13,16 @@ install_c_toolchain() { esac } +install_binutils() { + case $TRAVIS_OS_NAME in + osx) + brew install binutils + ;; + *) + ;; + esac +} + install_rust() { curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain=nightly From 3cea133b4c391725f0a7eb33ec8545f99198853f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 17:29:31 -0500 Subject: [PATCH 0013/4206] macOS: use gnu binutils --- library/compiler-builtins/ci/env.sh | 4 ++++ library/compiler-builtins/ci/script.sh | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index ad76689789d33..92f0c3ecabd28 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -1,9 +1,13 @@ case $TRAVIS_OS_NAME in linux) export HOST=x86_64-unknown-linux-gnu + export NM=nm + export OBJDUMP=objdump ;; osx) export HOST=x86_64-apple-darwin + export NM=gnm + export OBJDUMP=gobjdump ;; esac diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index c3e1a65fc2991..c1748fcd73ebb 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -17,10 +17,10 @@ run_tests() { } inspect() { - ${PREFIX}nm -g target/**/debug/*.rlib + $PREFIX$NM -g --defined-only target/**/debug/*.rlib set +e - ${PREFIX}objdump -Cd target/**/debug/*.rlib - ${PREFIX}objdump -Cd target/**/release/*.rlib + $PREFIX$OBJDUMP -Cd target/**/debug/*.rlib + $PREFIX$OBJDUMP -Cd target/**/release/*.rlib set -e } From 3ccdc29e4dc1216bd5cce4055a83c5491ee84045 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 17:32:53 -0500 Subject: [PATCH 0014/4206] macOS: actually install binutils --- library/compiler-builtins/ci/install.sh | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 595a985cecfc6..3d11092f8c014 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -2,21 +2,21 @@ set -ex . $(dirname $0)/env.sh -install_c_toolchain() { - case $TARGET in - aarch64-unknown-linux-gnu) - sudo apt-get install -y --no-install-recommends \ - gcc-aarch64-linux-gnu libc6-arm64-cross libc6-dev-arm64-cross +install_binutils() { + case $TRAVIS_OS_NAME in + osx) + brew install binutils ;; *) ;; esac } -install_binutils() { - case $TRAVIS_OS_NAME in - osx) - brew install binutils +install_c_toolchain() { + case $TARGET in + aarch64-unknown-linux-gnu) + sudo apt-get install -y --no-install-recommends \ + gcc-aarch64-linux-gnu libc6-arm64-cross libc6-dev-arm64-cross ;; *) ;; @@ -49,6 +49,7 @@ EOF } main() { + install_binutils install_c_toolchain install_rust add_rustup_target From c691a4e475a1b5295858e8c0d9cb75516300c153 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 21:05:42 -0500 Subject: [PATCH 0015/4206] README: add Contributing and Progress sections --- library/compiler-builtins/README.md | 306 ++++++++++++++++++++++++++++ 1 file changed, 306 insertions(+) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index e2fc6a17131b8..f24f173c2fca1 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -10,6 +10,312 @@ See [rust-lang/rust#35437][0]. [0]: https://github.com/rust-lang/rust/issues/35437 +## Contributing + +1. Pick one or more intrinsics from the [pending list][/#progress]. +2. Fork this repository +3. Port the intrinsic(s) and their corresponding [unit tests][1] from their [C implementation][2] to + Rust. +4. Send a Pull Request (PR) +5. Once the PR passes our extensive [testing infrastructure][3], we'll merge it! +6. Celebrate :tada: + +[1]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/test/builtins/Unit +[2]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/lib/builtins +[3]: https://travis-ci.org/japaric/rustc-builtins + +## Progress + +The intrinsics that involve quadruple precision floating point numbers ("`f128`") has been crossed +off because Rust doesn't support them. + +- [ ] absvdi2.c +- [ ] absvsi2.c +- [ ] absvti2.c +- [ ] adddf3.c +- [ ] addsf3.c +- [ ] addtf3.c +- [ ] addvdi3.c +- [ ] addvsi3.c +- [ ] addvti3.c +- [ ] apple_versioning.c +- [ ] arm/adddf3vfp.S +- [ ] arm/addsf3vfp.S +- [ ] arm/aeabi_cdcmp.S +- [ ] arm/aeabi_cdcmpeq_check_nan.c +- [ ] arm/aeabi_cfcmp.S +- [ ] arm/aeabi_cfcmpeq_check_nan.c +- [ ] arm/aeabi_dcmp.S +- [ ] arm/aeabi_div0.c +- [ ] arm/aeabi_drsub.c +- [ ] arm/aeabi_fcmp.S +- [ ] arm/aeabi_frsub.c +- [ ] arm/aeabi_idivmod.S +- [ ] arm/aeabi_ldivmod.S +- [ ] arm/aeabi_uidivmod.S +- [ ] arm/aeabi_uldivmod.S +- [ ] arm/bswapdi2.S +- [ ] arm/bswapsi2.S +- [ ] arm/clzdi2.S +- [ ] arm/clzsi2.S +- [ ] arm/comparesf2.S +- [ ] arm/divdf3vfp.S +- [ ] arm/divmodsi4.S +- [ ] arm/divsf3vfp.S +- [ ] arm/divsi3.S +- [ ] arm/eqdf2vfp.S +- [ ] arm/eqsf2vfp.S +- [ ] arm/extendsfdf2vfp.S +- [ ] arm/fixdfsivfp.S +- [ ] arm/fixsfsivfp.S +- [ ] arm/fixunsdfsivfp.S +- [ ] arm/fixunssfsivfp.S +- [ ] arm/floatsidfvfp.S +- [ ] arm/floatsisfvfp.S +- [ ] arm/floatunssidfvfp.S +- [ ] arm/floatunssisfvfp.S +- [ ] arm/gedf2vfp.S +- [ ] arm/gesf2vfp.S +- [ ] arm/gtdf2vfp.S +- [ ] arm/gtsf2vfp.S +- [ ] arm/ledf2vfp.S +- [ ] arm/lesf2vfp.S +- [ ] arm/ltdf2vfp.S +- [ ] arm/ltsf2vfp.S +- [ ] arm/modsi3.S +- [ ] arm/muldf3vfp.S +- [ ] arm/mulsf3vfp.S +- [ ] arm/nedf2vfp.S +- [ ] arm/negdf2vfp.S +- [ ] arm/negsf2vfp.S +- [ ] arm/nesf2vfp.S +- [ ] arm/restore_vfp_d8_d15_regs.S +- [ ] arm/save_vfp_d8_d15_regs.S +- [ ] arm/softfloat-alias.list +- [ ] arm/subdf3vfp.S +- [ ] arm/subsf3vfp.S +- [ ] arm/switch16.S +- [ ] arm/switch32.S +- [ ] arm/switch8.S +- [ ] arm/switchu8.S +- [ ] arm/sync_fetch_and_add_4.S +- [ ] arm/sync_fetch_and_add_8.S +- [ ] arm/sync_fetch_and_and_4.S +- [ ] arm/sync_fetch_and_and_8.S +- [ ] arm/sync_fetch_and_max_4.S +- [ ] arm/sync_fetch_and_max_8.S +- [ ] arm/sync_fetch_and_min_4.S +- [ ] arm/sync_fetch_and_min_8.S +- [ ] arm/sync_fetch_and_nand_4.S +- [ ] arm/sync_fetch_and_nand_8.S +- [ ] arm/sync_fetch_and_or_4.S +- [ ] arm/sync_fetch_and_or_8.S +- [ ] arm/sync_fetch_and_sub_4.S +- [ ] arm/sync_fetch_and_sub_8.S +- [ ] arm/sync_fetch_and_umax_4.S +- [ ] arm/sync_fetch_and_umax_8.S +- [ ] arm/sync_fetch_and_umin_4.S +- [ ] arm/sync_fetch_and_umin_8.S +- [ ] arm/sync_fetch_and_xor_4.S +- [ ] arm/sync_fetch_and_xor_8.S +- [ ] arm/sync_synchronize.S +- [ ] arm/truncdfsf2vfp.S +- [ ] arm/udivmodsi4.S +- [ ] arm/udivsi3.S +- [ ] arm/umodsi3.S +- [ ] arm/unorddf2vfp.S +- [ ] arm/unordsf2vfp.S +- [ ] ashldi3.c +- [ ] ashlti3.c +- [ ] ashrdi3.c +- [ ] ashrti3.c +- [ ] atomic.c +- [ ] atomic_flag_clear.c +- [ ] atomic_flag_clear_explicit.c +- [ ] atomic_flag_test_and_set.c +- [ ] atomic_flag_test_and_set_explicit.c +- [ ] atomic_signal_fence.c +- [ ] atomic_thread_fence.c +- [ ] clear_cache.c +- [ ] clzdi2.c +- [ ] clzsi2.c +- [ ] clzti2.c +- [ ] cmpdi2.c +- [ ] cmpti2.c +- [ ] comparedf2.c +- [ ] comparesf2.c +- [ ] comparetf2.c +- [ ] cpu_model.c +- [ ] ctzdi2.c +- [ ] ctzsi2.c +- [ ] ctzti2.c +- [ ] divdc3.c +- [ ] divdf3.c +- [ ] divdi3.c +- [ ] divmoddi4.c +- [ ] divmodsi4.c +- [ ] divsc3.c +- [ ] divsf3.c +- [ ] divsi3.c +- [ ] divtc3.c +- [ ] divtf3.c +- [ ] divti3.c +- [ ] divxc3.c +- [ ] emutls.c +- [ ] enable_execute_stack.c +- [ ] eprintf.c +- [ ] extenddftf2.c +- [ ] extendhfsf2.c +- [ ] extendsfdf2.c +- [ ] extendsftf2.c +- [ ] ffsdi2.c +- [ ] ffsti2.c +- [ ] fixdfdi.c +- [ ] fixdfsi.c +- [ ] fixdfti.c +- [ ] fixsfdi.c +- [ ] fixsfsi.c +- [ ] fixsfti.c +- [ ] fixtfdi.c +- [ ] fixtfsi.c +- [ ] fixtfti.c +- [ ] fixunsdfdi.c +- [ ] fixunsdfsi.c +- [ ] fixunsdfti.c +- [ ] fixunssfdi.c +- [ ] fixunssfsi.c +- [ ] fixunssfti.c +- [ ] fixunstfdi.c +- [ ] fixunstfsi.c +- [ ] fixunstfti.c +- [ ] floatdidf.c +- [ ] floatdisf.c +- [ ] floatditf.c +- [ ] floatsidf.c +- [ ] floatsisf.c +- [ ] floatsitf.c +- [ ] floattidf.c +- [ ] floattisf.c +- [ ] floatundidf.c +- [ ] floatundisf.c +- [ ] floatunditf.c +- [ ] floatunsidf.c +- [ ] floatunsisf.c +- [ ] floatunsitf.c +- [ ] floatuntidf.c +- [ ] floatuntisf.c +- [ ] gcc_personality_v0.c +- [ ] i386/ashldi3.S +- [ ] i386/ashrdi3.S +- [ ] i386/chkstk.S +- [ ] i386/chkstk2.S +- [ ] i386/divdi3.S +- [ ] i386/floatdidf.S +- [ ] i386/floatdisf.S +- [ ] i386/floatundidf.S +- [ ] i386/floatundisf.S +- [ ] i386/lshrdi3.S +- [ ] i386/moddi3.S +- [ ] i386/muldi3.S +- [ ] i386/udivdi3.S +- [ ] i386/umoddi3.S +- [ ] int_util.c +- [ ] lshrdi3.c +- [ ] lshrti3.c +- [ ] moddi3.c +- [ ] modsi3.c +- [ ] modti3.c +- [ ] muldc3.c +- [ ] muldf3.c +- [ ] muldi3.c +- [ ] mulodi4.c +- [ ] mulosi4.c +- [ ] muloti4.c +- [ ] mulsc3.c +- [ ] mulsf3.c +- [ ] multc3.c +- [ ] multf3.c +- [ ] multi3.c +- [ ] mulvdi3.c +- [ ] mulvsi3.c +- [ ] mulvti3.c +- [ ] mulxc3.c +- [ ] negdf2.c +- [ ] negdi2.c +- [ ] negsf2.c +- [ ] negti2.c +- [ ] negvdi2.c +- [ ] negvsi2.c +- [ ] negvti2.c +- [ ] paritydi2.c +- [ ] paritysi2.c +- [ ] parityti2.c +- [ ] popcountdi2.c +- [ ] popcountsi2.c +- [ ] popcountti2.c +- [ ] powidf2.c +- [ ] powisf2.c +- [ ] powitf2.c +- [ ] ppc/divtc3.c +- [ ] ppc/fixtfdi.c +- [ ] ppc/fixunstfdi.c +- [ ] ppc/floatditf.c +- [ ] ppc/floatunditf.c +- [ ] ppc/gcc_qadd.c +- [ ] ppc/gcc_qdiv.c +- [ ] ppc/gcc_qmul.c +- [ ] ppc/gcc_qsub.c +- [ ] ppc/multc3.c +- [ ] ppc/restFP.S +- [ ] ppc/saveFP.S +- [ ] subdf3.c +- [ ] subsf3.c +- [ ] subtf3.c +- [ ] subvdi3.c +- [ ] subvsi3.c +- [ ] subvti3.c +- [ ] trampoline_setup.c +- [ ] truncdfhf2.c +- [ ] truncdfsf2.c +- [ ] truncsfhf2.c +- [ ] trunctfdf2.c +- [ ] trunctfsf2.c +- [ ] ucmpdi2.c +- [ ] ucmpti2.c +- [ ] udivdi3.c +- [ ] udivmoddi4.c +- [ ] udivmodsi4.c +- [ ] udivmodti4.c +- [ ] udivsi3.c +- [ ] udivti3.c +- [ ] umoddi3.c +- [ ] umodsi3.c +- [ ] umodti3.c +- [ ] x86_64/chkstk.S +- [ ] x86_64/chkstk2.S +- [ ] x86_64/floatundidf.S +- [ ] x86_64/floatundisf.S +- [x] arm/aeabi_memcmp.S +- [x] arm/aeabi_memcpy.S +- [x] arm/aeabi_memmove.S +- [x] arm/aeabi_memset.S +- [x] x86_64/floatdidf.c +- [x] x86_64/floatdisf.c +- ~~fixunsxfdi.c~~ +- ~~fixunsxfsi.c~~ +- ~~fixunsxfti.c~~ +- ~~fixxfdi.c~~ +- ~~fixxfti.c~~ +- ~~floatdixf.c~~ +- ~~floattixf.c~~ +- ~~floatundixf.c~~ +- ~~floatuntixf.c~~ +- ~~i386/floatdixf.S~~ +- ~~i386/floatundixf.S~~ +- ~~powixf2.c~~ +- ~~x86_64/floatdixf.c~~ +- ~~x86_64/floatundixf.S~~ + ## License Licensed under either of From f271e63915ac5a3e5d45b7349ae441e33751099e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Aug 2016 21:22:15 -0500 Subject: [PATCH 0016/4206] CI: allow failures for TARGET=armv7-unknown-linux-gnueabihf --- library/compiler-builtins/.travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index c09c3bb49bf89..7ede66cce92d1 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -52,6 +52,10 @@ matrix: os: osx - env: TARGET=x86_64-unknown-linux-gnu os: linux + allow_failures: + # FIXME(#2) + - env: TARGET=armv7-unknown-linux-gnueabihf + os: linux before_install: - export PATH="$PATH:$HOME/.cargo/bin" From 1b0cfdc47703f01cc565e1258d662c65f0fb0041 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 8 Aug 2016 06:54:00 +0100 Subject: [PATCH 0017/4206] Clean up function list in README --- library/compiler-builtins/README.md | 154 +++++++++++++++------------- 1 file changed, 80 insertions(+), 74 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index f24f173c2fca1..de26d893118d0 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -26,19 +26,14 @@ See [rust-lang/rust#35437][0]. ## Progress -The intrinsics that involve quadruple precision floating point numbers ("`f128`") has been crossed -off because Rust doesn't support them. - - [ ] absvdi2.c - [ ] absvsi2.c - [ ] absvti2.c - [ ] adddf3.c - [ ] addsf3.c -- [ ] addtf3.c - [ ] addvdi3.c - [ ] addvsi3.c - [ ] addvti3.c -- [ ] apple_versioning.c - [ ] arm/adddf3vfp.S - [ ] arm/addsf3vfp.S - [ ] arm/aeabi_cdcmp.S @@ -98,27 +93,6 @@ off because Rust doesn't support them. - [ ] arm/switch32.S - [ ] arm/switch8.S - [ ] arm/switchu8.S -- [ ] arm/sync_fetch_and_add_4.S -- [ ] arm/sync_fetch_and_add_8.S -- [ ] arm/sync_fetch_and_and_4.S -- [ ] arm/sync_fetch_and_and_8.S -- [ ] arm/sync_fetch_and_max_4.S -- [ ] arm/sync_fetch_and_max_8.S -- [ ] arm/sync_fetch_and_min_4.S -- [ ] arm/sync_fetch_and_min_8.S -- [ ] arm/sync_fetch_and_nand_4.S -- [ ] arm/sync_fetch_and_nand_8.S -- [ ] arm/sync_fetch_and_or_4.S -- [ ] arm/sync_fetch_and_or_8.S -- [ ] arm/sync_fetch_and_sub_4.S -- [ ] arm/sync_fetch_and_sub_8.S -- [ ] arm/sync_fetch_and_umax_4.S -- [ ] arm/sync_fetch_and_umax_8.S -- [ ] arm/sync_fetch_and_umin_4.S -- [ ] arm/sync_fetch_and_umin_8.S -- [ ] arm/sync_fetch_and_xor_4.S -- [ ] arm/sync_fetch_and_xor_8.S -- [ ] arm/sync_synchronize.S - [ ] arm/truncdfsf2vfp.S - [ ] arm/udivmodsi4.S - [ ] arm/udivsi3.S @@ -129,14 +103,6 @@ off because Rust doesn't support them. - [ ] ashlti3.c - [ ] ashrdi3.c - [ ] ashrti3.c -- [ ] atomic.c -- [ ] atomic_flag_clear.c -- [ ] atomic_flag_clear_explicit.c -- [ ] atomic_flag_test_and_set.c -- [ ] atomic_flag_test_and_set_explicit.c -- [ ] atomic_signal_fence.c -- [ ] atomic_thread_fence.c -- [ ] clear_cache.c - [ ] clzdi2.c - [ ] clzsi2.c - [ ] clzti2.c @@ -144,30 +110,18 @@ off because Rust doesn't support them. - [ ] cmpti2.c - [ ] comparedf2.c - [ ] comparesf2.c -- [ ] comparetf2.c -- [ ] cpu_model.c - [ ] ctzdi2.c - [ ] ctzsi2.c - [ ] ctzti2.c -- [ ] divdc3.c - [ ] divdf3.c - [ ] divdi3.c - [ ] divmoddi4.c - [ ] divmodsi4.c -- [ ] divsc3.c - [ ] divsf3.c - [ ] divsi3.c -- [ ] divtc3.c -- [ ] divtf3.c - [ ] divti3.c -- [ ] divxc3.c -- [ ] emutls.c -- [ ] enable_execute_stack.c -- [ ] eprintf.c -- [ ] extenddftf2.c - [ ] extendhfsf2.c - [ ] extendsfdf2.c -- [ ] extendsftf2.c - [ ] ffsdi2.c - [ ] ffsti2.c - [ ] fixdfdi.c @@ -176,35 +130,24 @@ off because Rust doesn't support them. - [ ] fixsfdi.c - [ ] fixsfsi.c - [ ] fixsfti.c -- [ ] fixtfdi.c -- [ ] fixtfsi.c -- [ ] fixtfti.c - [ ] fixunsdfdi.c - [ ] fixunsdfsi.c - [ ] fixunsdfti.c - [ ] fixunssfdi.c - [ ] fixunssfsi.c - [ ] fixunssfti.c -- [ ] fixunstfdi.c -- [ ] fixunstfsi.c -- [ ] fixunstfti.c - [ ] floatdidf.c - [ ] floatdisf.c -- [ ] floatditf.c - [ ] floatsidf.c - [ ] floatsisf.c -- [ ] floatsitf.c - [ ] floattidf.c - [ ] floattisf.c - [ ] floatundidf.c - [ ] floatundisf.c -- [ ] floatunditf.c - [ ] floatunsidf.c - [ ] floatunsisf.c -- [ ] floatunsitf.c - [ ] floatuntidf.c - [ ] floatuntisf.c -- [ ] gcc_personality_v0.c - [ ] i386/ashldi3.S - [ ] i386/ashrdi3.S - [ ] i386/chkstk.S @@ -219,27 +162,21 @@ off because Rust doesn't support them. - [ ] i386/muldi3.S - [ ] i386/udivdi3.S - [ ] i386/umoddi3.S -- [ ] int_util.c - [ ] lshrdi3.c - [ ] lshrti3.c - [ ] moddi3.c - [ ] modsi3.c - [ ] modti3.c -- [ ] muldc3.c - [ ] muldf3.c - [ ] muldi3.c - [ ] mulodi4.c - [ ] mulosi4.c - [ ] muloti4.c -- [ ] mulsc3.c - [ ] mulsf3.c -- [ ] multc3.c -- [ ] multf3.c - [ ] multi3.c - [ ] mulvdi3.c - [ ] mulvsi3.c - [ ] mulvti3.c -- [ ] mulxc3.c - [ ] negdf2.c - [ ] negdi2.c - [ ] negsf2.c @@ -255,31 +192,20 @@ off because Rust doesn't support them. - [ ] popcountti2.c - [ ] powidf2.c - [ ] powisf2.c -- [ ] powitf2.c -- [ ] ppc/divtc3.c -- [ ] ppc/fixtfdi.c -- [ ] ppc/fixunstfdi.c -- [ ] ppc/floatditf.c -- [ ] ppc/floatunditf.c - [ ] ppc/gcc_qadd.c - [ ] ppc/gcc_qdiv.c - [ ] ppc/gcc_qmul.c - [ ] ppc/gcc_qsub.c -- [ ] ppc/multc3.c - [ ] ppc/restFP.S - [ ] ppc/saveFP.S - [ ] subdf3.c - [ ] subsf3.c -- [ ] subtf3.c - [ ] subvdi3.c - [ ] subvsi3.c - [ ] subvti3.c -- [ ] trampoline_setup.c - [ ] truncdfhf2.c - [ ] truncdfsf2.c - [ ] truncsfhf2.c -- [ ] trunctfdf2.c -- [ ] trunctfsf2.c - [ ] ucmpdi2.c - [ ] ucmpti2.c - [ ] udivdi3.c @@ -301,21 +227,101 @@ off because Rust doesn't support them. - [x] arm/aeabi_memset.S - [x] x86_64/floatdidf.c - [x] x86_64/floatdisf.c + +## Unimplemented functions + +These builtins involve floating-point types ("`f128`", "`f80`" and complex numbers) that are not supported by Rust. + +- ~~addtf3.c~~ +- ~~comparetf2.c~~ +- ~~divdc3.c~~ +- ~~divsc3.c~~ +- ~~divtc3.c~~ +- ~~divtf3.c~~ +- ~~divxc3.c~~ +- ~~extenddftf2.c~~ +- ~~extendsftf2.c~~ +- ~~fixtfdi.c~~ +- ~~fixtfsi.c~~ +- ~~fixtfti.c~~ +- ~~fixunstfdi.c~~ +- ~~fixunstfsi.c~~ +- ~~fixunstfti.c~~ - ~~fixunsxfdi.c~~ - ~~fixunsxfsi.c~~ - ~~fixunsxfti.c~~ - ~~fixxfdi.c~~ - ~~fixxfti.c~~ +- ~~floatditf.c~~ - ~~floatdixf.c~~ +- ~~floatsitf.c~~ - ~~floattixf.c~~ +- ~~floatunditf.c~~ - ~~floatundixf.c~~ +- ~~floatunsitf.c~~ - ~~floatuntixf.c~~ - ~~i386/floatdixf.S~~ - ~~i386/floatundixf.S~~ +- ~~muldc3.c~~ +- ~~mulsc3.c~~ +- ~~multc3.c~~ +- ~~multf3.c~~ +- ~~mulxc3.c~~ +- ~~powitf2.c~~ - ~~powixf2.c~~ +- ~~ppc/divtc3.c~~ +- ~~ppc/fixtfdi.c~~ +- ~~ppc/fixunstfdi.c~~ +- ~~ppc/floatditf.c~~ +- ~~ppc/floatunditf.c~~ +- ~~ppc/multc3.c~~ +- ~~subtf3.c~~ +- ~~trunctfdf2.c~~ +- ~~trunctfsf2.c~~ - ~~x86_64/floatdixf.c~~ - ~~x86_64/floatundixf.S~~ +Rust only exposes atomic types on platforms that support them, and therefore does not need to fall back to software implementations. + +- ~~arm/sync_fetch_and_add_4.S~~ +- ~~arm/sync_fetch_and_add_8.S~~ +- ~~arm/sync_fetch_and_and_4.S~~ +- ~~arm/sync_fetch_and_and_8.S~~ +- ~~arm/sync_fetch_and_max_4.S~~ +- ~~arm/sync_fetch_and_max_8.S~~ +- ~~arm/sync_fetch_and_min_4.S~~ +- ~~arm/sync_fetch_and_min_8.S~~ +- ~~arm/sync_fetch_and_nand_4.S~~ +- ~~arm/sync_fetch_and_nand_8.S~~ +- ~~arm/sync_fetch_and_or_4.S~~ +- ~~arm/sync_fetch_and_or_8.S~~ +- ~~arm/sync_fetch_and_sub_4.S~~ +- ~~arm/sync_fetch_and_sub_8.S~~ +- ~~arm/sync_fetch_and_umax_4.S~~ +- ~~arm/sync_fetch_and_umax_8.S~~ +- ~~arm/sync_fetch_and_umin_4.S~~ +- ~~arm/sync_fetch_and_umin_8.S~~ +- ~~arm/sync_fetch_and_xor_4.S~~ +- ~~arm/sync_fetch_and_xor_8.S~~ +- ~~arm/sync_synchronize.S~~ +- ~~atomic.c~~ +- ~~atomic_flag_clear.c~~ +- ~~atomic_flag_clear_explicit.c~~ +- ~~atomic_flag_test_and_set.c~~ +- ~~atomic_flag_test_and_set_explicit.c~~ +- ~~atomic_signal_fence.c~~ +- ~~atomic_thread_fence.c~~ + +Miscellaneous functionality that is not used by Rust. + +- ~~apple_versioning.c~~ +- ~~clear_cache.c~~ +- ~~emutls.c~~ +- ~~enable_execute_stack.c~~ +- ~~eprintf.c~~ +- ~~gcc_personality_v0.c~~ +- ~~trampoline_setup.c~~ + ## License Licensed under either of From 9fbd25b4cd7e8b688efd9e7a12403124146e8fee Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 8 Aug 2016 07:20:39 +0100 Subject: [PATCH 0018/4206] Rewrite the arm mem* builtins without asm and naked functions --- library/compiler-builtins/src/arm.rs | 123 ++++++++++++++------------- 1 file changed, 65 insertions(+), 58 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 0be06a4dfbb99..d2544f588d443 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,67 +1,74 @@ -use core::intrinsics; - -macro_rules! defer { - ($($symbol:ident),+ -> $routine:ident) => { - $( - #[naked] - #[no_mangle] - pub extern "C" fn $symbol() { - unsafe { - asm!(concat!("b ", stringify!($routine))); - intrinsics::unreachable(); - } - } - )+ - } +extern "C" { + fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32; + fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; + fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; + fn memset(dest: *mut u8, c: i32, n: usize) -> *mut u8; } -// FIXME only `__aeabi_memcmp` should be defined like this. The `*4` and `*8` variants should be -// defined as aliases of `__aeabi_memcmp` -defer!(__aeabi_memcmp, __aeabi_memcmp4, __aeabi_memcmp8 -> memcmp); - -// FIXME same issue as `__aeabi_memcmp*` -defer!(__aeabi_memcpy, __aeabi_memcpy4, __aeabi_memcpy8 -> memcpy); +// FIXME: The `*4` and `*8` variants should be defined as aliases. -// FIXME same issue as `__aeabi_memcmp*` -defer!(__aeabi_memmove, __aeabi_memmove4, __aeabi_memmove8 -> memmove); +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { + memcmp(s1, s2, n) +} +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memcmp4(s1: *const u8, s2: *const u8, n: usize) -> i32 { + memcmp(s1, s2, n) +} +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memcmp8(s1: *const u8, s2: *const u8, n: usize) -> i32 { + memcmp(s1, s2, n) +} -macro_rules! memset { - ($($symbol:ident),+) => { - $( - #[naked] - #[no_mangle] - pub extern "C" fn $symbol() { - unsafe { - asm!("mov r3, r1 - mov r1, r2 - mov r2, r3 - b memset"); - intrinsics::unreachable(); - } - } - )+ - } +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { + memcpy(dest, src, n); +} +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { + memcpy(dest, src, n); +} +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { + memcpy(dest, src, n); } -// FIXME same issue as `__aeabi_memcmp*` -memset!(__aeabi_memset, __aeabi_memset4, __aeabi_memset8); +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { + memmove(dest, src, n); +} +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { + memmove(dest, src, n); +} +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { + memmove(dest, src, n); +} -macro_rules! memclr { - ($($symbol:ident),+) => { - $( - #[naked] - #[no_mangle] - pub extern "C" fn $symbol() { - unsafe { - asm!("mov r2, r1 - mov r1, #0 - b memset"); - intrinsics::unreachable(); - } - } - )+ - } +// Note the different argument order +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { + memset(dest, c, n); +} +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { + memset(dest, c, n); +} +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { + memset(dest, c, n); } -// FIXME same issue as `__aeabi_memcmp*` -memclr!(__aeabi_memclr, __aeabi_memclr4, __aeabi_memclr8); +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { + memset(dest, 0, n); +} +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { + memset(dest, 0, n); +} +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { + memset(dest, 0, n); +} From 1260f145b3e656cc04c2950bd97eb9ac7145d8e1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 01:58:16 -0500 Subject: [PATCH 0019/4206] CI: AppVeyor --- library/compiler-builtins/appveyor.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 library/compiler-builtins/appveyor.yml diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml new file mode 100644 index 0000000000000..e7a6a5e4013ae --- /dev/null +++ b/library/compiler-builtins/appveyor.yml @@ -0,0 +1,24 @@ +environment: + global: + matrix: + - TARGET=i686-pc-windows-msvc + - TARGET=x86_64-pc-windows-msvc + +install: + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-$%7Benv:TARGET%7D.exe" + - rust-nightly-%TARGET%.exe + - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - rustc -Vv + - cargo -V + +build: false + +test_script: + - cargo build + - cargo build --release + - cargo test + - cargo test --release + +branches: + only: + - master From 74ca884c6da1fef2db211a0e6c16322bb5d54d67 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 01:59:37 -0500 Subject: [PATCH 0020/4206] fix the syntax --- library/compiler-builtins/appveyor.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index e7a6a5e4013ae..f051e3b567e9a 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -1,8 +1,7 @@ environment: - global: - matrix: - - TARGET=i686-pc-windows-msvc - - TARGET=x86_64-pc-windows-msvc + matrix: + - TARGET: i686-pc-windows-msvc + - TARGET: x86_64-pc-windows-msvc install: - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-$%7Benv:TARGET%7D.exe" From e414f9a954419a5194975a0b1a174c2484b19491 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 02:05:24 -0500 Subject: [PATCH 0021/4206] properly call the rust installer to not require user input --- library/compiler-builtins/appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index f051e3b567e9a..d27883dc90157 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -5,7 +5,7 @@ environment: install: - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-$%7Benv:TARGET%7D.exe" - - rust-nightly-%TARGET%.exe + - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin - rustc -Vv - cargo -V From 6f22c85b25b31485328334ca147d82010d038ef6 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 8 Aug 2016 08:16:54 +0100 Subject: [PATCH 0022/4206] Remove builtins that are not called by LLVM --- library/compiler-builtins/README.md | 141 ++++++++++++++------------- library/compiler-builtins/src/arm.rs | 14 --- 2 files changed, 72 insertions(+), 83 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index de26d893118d0..a08f4d26208ad 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -26,34 +26,16 @@ See [rust-lang/rust#35437][0]. ## Progress -- [ ] absvdi2.c -- [ ] absvsi2.c -- [ ] absvti2.c - [ ] adddf3.c - [ ] addsf3.c -- [ ] addvdi3.c -- [ ] addvsi3.c -- [ ] addvti3.c - [ ] arm/adddf3vfp.S - [ ] arm/addsf3vfp.S -- [ ] arm/aeabi_cdcmp.S -- [ ] arm/aeabi_cdcmpeq_check_nan.c -- [ ] arm/aeabi_cfcmp.S -- [ ] arm/aeabi_cfcmpeq_check_nan.c - [ ] arm/aeabi_dcmp.S -- [ ] arm/aeabi_div0.c -- [ ] arm/aeabi_drsub.c - [ ] arm/aeabi_fcmp.S -- [ ] arm/aeabi_frsub.c - [ ] arm/aeabi_idivmod.S - [ ] arm/aeabi_ldivmod.S - [ ] arm/aeabi_uidivmod.S - [ ] arm/aeabi_uldivmod.S -- [ ] arm/bswapdi2.S -- [ ] arm/bswapsi2.S -- [ ] arm/clzdi2.S -- [ ] arm/clzsi2.S -- [ ] arm/comparesf2.S - [ ] arm/divdf3vfp.S - [ ] arm/divmodsi4.S - [ ] arm/divsf3vfp.S @@ -84,15 +66,9 @@ See [rust-lang/rust#35437][0]. - [ ] arm/negdf2vfp.S - [ ] arm/negsf2vfp.S - [ ] arm/nesf2vfp.S -- [ ] arm/restore_vfp_d8_d15_regs.S -- [ ] arm/save_vfp_d8_d15_regs.S - [ ] arm/softfloat-alias.list - [ ] arm/subdf3vfp.S - [ ] arm/subsf3vfp.S -- [ ] arm/switch16.S -- [ ] arm/switch32.S -- [ ] arm/switch8.S -- [ ] arm/switchu8.S - [ ] arm/truncdfsf2vfp.S - [ ] arm/udivmodsi4.S - [ ] arm/udivsi3.S @@ -103,27 +79,13 @@ See [rust-lang/rust#35437][0]. - [ ] ashlti3.c - [ ] ashrdi3.c - [ ] ashrti3.c -- [ ] clzdi2.c -- [ ] clzsi2.c -- [ ] clzti2.c -- [ ] cmpdi2.c -- [ ] cmpti2.c -- [ ] comparedf2.c -- [ ] comparesf2.c -- [ ] ctzdi2.c -- [ ] ctzsi2.c -- [ ] ctzti2.c - [ ] divdf3.c - [ ] divdi3.c -- [ ] divmoddi4.c -- [ ] divmodsi4.c - [ ] divsf3.c - [ ] divsi3.c - [ ] divti3.c - [ ] extendhfsf2.c - [ ] extendsfdf2.c -- [ ] ffsdi2.c -- [ ] ffsti2.c - [ ] fixdfdi.c - [ ] fixdfsi.c - [ ] fixdfti.c @@ -174,44 +136,14 @@ See [rust-lang/rust#35437][0]. - [ ] muloti4.c - [ ] mulsf3.c - [ ] multi3.c -- [ ] mulvdi3.c -- [ ] mulvsi3.c -- [ ] mulvti3.c -- [ ] negdf2.c -- [ ] negdi2.c -- [ ] negsf2.c -- [ ] negti2.c -- [ ] negvdi2.c -- [ ] negvsi2.c -- [ ] negvti2.c -- [ ] paritydi2.c -- [ ] paritysi2.c -- [ ] parityti2.c -- [ ] popcountdi2.c -- [ ] popcountsi2.c -- [ ] popcountti2.c - [ ] powidf2.c - [ ] powisf2.c -- [ ] ppc/gcc_qadd.c -- [ ] ppc/gcc_qdiv.c -- [ ] ppc/gcc_qmul.c -- [ ] ppc/gcc_qsub.c -- [ ] ppc/restFP.S -- [ ] ppc/saveFP.S - [ ] subdf3.c - [ ] subsf3.c -- [ ] subvdi3.c -- [ ] subvsi3.c -- [ ] subvti3.c - [ ] truncdfhf2.c - [ ] truncdfsf2.c - [ ] truncsfhf2.c -- [ ] ucmpdi2.c -- [ ] ucmpti2.c - [ ] udivdi3.c -- [ ] udivmoddi4.c -- [ ] udivmodsi4.c -- [ ] udivmodti4.c - [ ] udivsi3.c - [ ] udivti3.c - [ ] umoddi3.c @@ -221,7 +153,6 @@ See [rust-lang/rust#35437][0]. - [ ] x86_64/chkstk2.S - [ ] x86_64/floatundidf.S - [ ] x86_64/floatundisf.S -- [x] arm/aeabi_memcmp.S - [x] arm/aeabi_memcpy.S - [x] arm/aeabi_memmove.S - [x] arm/aeabi_memset.S @@ -274,6 +205,10 @@ These builtins involve floating-point types ("`f128`", "`f80`" and complex numbe - ~~ppc/fixunstfdi.c~~ - ~~ppc/floatditf.c~~ - ~~ppc/floatunditf.c~~ +- ~~ppc/gcc_qadd.c~~ +- ~~ppc/gcc_qdiv.c~~ +- ~~ppc/gcc_qmul.c~~ +- ~~ppc/gcc_qsub.c~~ - ~~ppc/multc3.c~~ - ~~subtf3.c~~ - ~~trunctfdf2.c~~ @@ -281,6 +216,74 @@ These builtins involve floating-point types ("`f128`", "`f80`" and complex numbe - ~~x86_64/floatdixf.c~~ - ~~x86_64/floatundixf.S~~ +These builtins are never called by LLVM. + +- ~~absvdi2.c~~ +- ~~absvsi2.c~~ +- ~~absvti2.c~~ +- ~~addvdi3.c~~ +- ~~addvsi3.c~~ +- ~~addvti3.c~~ +- ~~arm/aeabi_cdcmp.S~~ +- ~~arm/aeabi_cdcmpeq_check_nan.c~~ +- ~~arm/aeabi_cfcmp.S~~ +- ~~arm/aeabi_cfcmpeq_check_nan.c~~ +- ~~arm/aeabi_div0.c~~ +- ~~arm/aeabi_drsub.c~~ +- ~~arm/aeabi_frsub.c~~ +- ~~arm/aeabi_memcmp.S~~ +- ~~arm/bswapdi2.S~~ +- ~~arm/bswapsi2.S~~ +- ~~arm/clzdi2.S~~ +- ~~arm/clzsi2.S~~ +- ~~arm/comparesf2.S~~ +- ~~arm/restore_vfp_d8_d15_regs.S~~ +- ~~arm/save_vfp_d8_d15_regs.S~~ +- ~~arm/switch16.S~~ +- ~~arm/switch32.S~~ +- ~~arm/switch8.S~~ +- ~~arm/switchu8.S~~ +- ~~clzdi2.c~~ +- ~~clzsi2.c~~ +- ~~clzti2.c~~ +- ~~cmpdi2.c~~ +- ~~cmpti2.c~~ +- ~~comparedf2.c~~ +- ~~comparesf2.c~~ +- ~~ctzdi2.c~~ +- ~~ctzsi2.c~~ +- ~~ctzti2.c~~ +- ~~divmoddi4.c~~ +- ~~divmodsi4.c~~ +- ~~ffsdi2.c~~ +- ~~ffsti2.c~~ +- ~~mulvdi3.c~~ +- ~~mulvsi3.c~~ +- ~~mulvti3.c~~ +- ~~negdf2.c~~ +- ~~negdi2.c~~ +- ~~negsf2.c~~ +- ~~negti2.c~~ +- ~~negvdi2.c~~ +- ~~negvsi2.c~~ +- ~~negvti2.c~~ +- ~~paritydi2.c~~ +- ~~paritysi2.c~~ +- ~~parityti2.c~~ +- ~~popcountdi2.c~~ +- ~~popcountsi2.c~~ +- ~~popcountti2.c~~ +- ~~ppc/restFP.S~~ +- ~~ppc/saveFP.S~~ +- ~~subvdi3.c~~ +- ~~subvsi3.c~~ +- ~~subvti3.c~~ +- ~~ucmpdi2.c~~ +- ~~ucmpti2.c~~ +- ~~udivmoddi4.c~~ +- ~~udivmodsi4.c~~ +- ~~udivmodti4.c~~ + Rust only exposes atomic types on platforms that support them, and therefore does not need to fall back to software implementations. - ~~arm/sync_fetch_and_add_4.S~~ diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index d2544f588d443..7beb91aa958a6 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,5 +1,4 @@ extern "C" { - fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32; fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; fn memset(dest: *mut u8, c: i32, n: usize) -> *mut u8; @@ -7,19 +6,6 @@ extern "C" { // FIXME: The `*4` and `*8` variants should be defined as aliases. -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { - memcmp(s1, s2, n) -} -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memcmp4(s1: *const u8, s2: *const u8, n: usize) -> i32 { - memcmp(s1, s2, n) -} -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memcmp8(s1: *const u8, s2: *const u8, n: usize) -> i32 { - memcmp(s1, s2, n) -} - #[no_mangle] pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { memcpy(dest, src, n); From 68e0b7657c935e21c9f4b715b02846cc7efeeab2 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 8 Aug 2016 08:27:22 +0100 Subject: [PATCH 0023/4206] Remove the x86-specific floating-point builtins --- library/compiler-builtins/README.md | 25 ++++++++++++++----------- library/compiler-builtins/src/lib.rs | 3 --- library/compiler-builtins/src/x86_64.rs | 9 --------- 3 files changed, 14 insertions(+), 23 deletions(-) delete mode 100644 library/compiler-builtins/src/x86_64.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index a08f4d26208ad..c68882985aa77 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -34,6 +34,9 @@ See [rust-lang/rust#35437][0]. - [ ] arm/aeabi_fcmp.S - [ ] arm/aeabi_idivmod.S - [ ] arm/aeabi_ldivmod.S +- [x] arm/aeabi_memcpy.S +- [x] arm/aeabi_memmove.S +- [x] arm/aeabi_memset.S - [ ] arm/aeabi_uidivmod.S - [ ] arm/aeabi_uldivmod.S - [ ] arm/divdf3vfp.S @@ -115,10 +118,6 @@ See [rust-lang/rust#35437][0]. - [ ] i386/chkstk.S - [ ] i386/chkstk2.S - [ ] i386/divdi3.S -- [ ] i386/floatdidf.S -- [ ] i386/floatdisf.S -- [ ] i386/floatundidf.S -- [ ] i386/floatundisf.S - [ ] i386/lshrdi3.S - [ ] i386/moddi3.S - [ ] i386/muldi3.S @@ -151,13 +150,6 @@ See [rust-lang/rust#35437][0]. - [ ] umodti3.c - [ ] x86_64/chkstk.S - [ ] x86_64/chkstk2.S -- [ ] x86_64/floatundidf.S -- [ ] x86_64/floatundisf.S -- [x] arm/aeabi_memcpy.S -- [x] arm/aeabi_memmove.S -- [x] arm/aeabi_memset.S -- [x] x86_64/floatdidf.c -- [x] x86_64/floatdisf.c ## Unimplemented functions @@ -325,6 +317,17 @@ Miscellaneous functionality that is not used by Rust. - ~~gcc_personality_v0.c~~ - ~~trampoline_setup.c~~ +Floating-point implementations of builtins that are only called from soft-float code. It would be better to simply use the generic soft-float versions in this case. + +- ~~i386/floatdidf.S~~ +- ~~i386/floatdisf.S~~ +- ~~i386/floatundidf.S~~ +- ~~i386/floatundisf.S~~ +- ~~x86_64/floatundidf.S~~ +- ~~x86_64/floatundisf.S~~ +- ~~x86_64/floatdidf.c~~ +- ~~x86_64/floatdisf.c~~ + ## License Licensed under either of diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 838e62a296bf4..01aca7674c224 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -14,9 +14,6 @@ use core::mem; #[cfg(target_arch = "arm")] pub mod arm; -#[cfg(target_arch = "x86_64")] -pub mod x86_64; - #[cfg(test)] mod test; diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs deleted file mode 100644 index d4ea0f759de3e..0000000000000 --- a/library/compiler-builtins/src/x86_64.rs +++ /dev/null @@ -1,9 +0,0 @@ -#[no_mangle] -pub extern "C" fn __floatdisf(x: i64) -> f32 { - x as f32 -} - -#[no_mangle] -pub extern "C" fn __floatdidf(x: i64) -> f64 { - x as f64 -} From 2431cd754bc23ec556e15b80f8cf566aa830da82 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 19:31:37 -0500 Subject: [PATCH 0024/4206] CI: test powerpc-unknown-linux-gnu --- library/compiler-builtins/.travis.yml | 11 +++++++++++ library/compiler-builtins/ci/env.sh | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 7ede66cce92d1..7e22c1d4b7d3e 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -48,6 +48,17 @@ matrix: apt: packages: - gcc-multilib + - env: TARGET=powerpc-unknown-linux-gnu + os: linux + sudo: required + addons: + apt: + packages: + - binfmt-support + - gcc-powerpc-linux-gnu + - libc6-powerpc-cross + - libc6-dev-powerpc-cross + - qemu-user-static - env: TARGET=x86_64-apple-darwin os: osx - env: TARGET=x86_64-unknown-linux-gnu diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 92f0c3ecabd28..fa1b1f0cdf36a 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -24,4 +24,8 @@ case $TARGET in export PREFIX=arm-linux-gnueabihf- export QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf ;; + powerpc-unknown-linux-gnu) + export PREFIX=powerpc-linux-gnu- + export QEMU_LD_PREFIX=/usr/powerpc-linux-gnu + ;; esac From e0be22eb4429c6869ced1f6a0a2444ac3dd20301 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 19:36:20 -0500 Subject: [PATCH 0025/4206] use trusty --- library/compiler-builtins/.travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 7e22c1d4b7d3e..e13bd112f53d8 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -50,6 +50,7 @@ matrix: - gcc-multilib - env: TARGET=powerpc-unknown-linux-gnu os: linux + dist: trusty sudo: required addons: apt: From a1b1c8d66a686909ea9d3d935bdf51cb7bf8e0d8 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 19:44:55 -0500 Subject: [PATCH 0026/4206] CI: test powerpc64le-unknown-linux-gnu --- library/compiler-builtins/.travis.yml | 12 ++++++++++++ library/compiler-builtins/ci/env.sh | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index e13bd112f53d8..8f6a27018a890 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -60,6 +60,18 @@ matrix: - libc6-powerpc-cross - libc6-dev-powerpc-cross - qemu-user-static + - env: TARGET=powerpc64le-unknown-linux-gnu + os: linux + dist: trusty + sudo: required + addons: + apt: + packages: + - binfmt-support + - gcc-powerpc64le-linux-gnu + - libc6-ppc64el-cross + - libc6-dev-ppc64el-cross + - qemu-user-static - env: TARGET=x86_64-apple-darwin os: osx - env: TARGET=x86_64-unknown-linux-gnu diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index fa1b1f0cdf36a..0bfc810858acb 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -28,4 +28,8 @@ case $TARGET in export PREFIX=powerpc-linux-gnu- export QEMU_LD_PREFIX=/usr/powerpc-linux-gnu ;; + powerpc64le-unknown-linux-gnu) + export PREFIX=powerpc64le-linux-gnu- + export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu + ;; esac From e813daef4b4050c05c5415dea35e38ce2392a9ab Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 20:04:17 -0500 Subject: [PATCH 0027/4206] explicitly use qemu-ppc64le --- library/compiler-builtins/.travis.yml | 2 +- library/compiler-builtins/ci/env.sh | 1 + library/compiler-builtins/ci/script.sh | 11 +++++++++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 8f6a27018a890..ba1c5369d128c 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -71,7 +71,7 @@ matrix: - gcc-powerpc64le-linux-gnu - libc6-ppc64el-cross - libc6-dev-ppc64el-cross - - qemu-user-static + - qemu-user - env: TARGET=x86_64-apple-darwin os: osx - env: TARGET=x86_64-unknown-linux-gnu diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 0bfc810858acb..29707a4b08c70 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -30,6 +30,7 @@ case $TARGET in ;; powerpc64le-unknown-linux-gnu) export PREFIX=powerpc64le-linux-gnu- + export QEMU=qemu-ppc64le export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu ;; esac diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index c1748fcd73ebb..0249a531cd3a2 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -12,8 +12,15 @@ run_tests() { export RUST_TEST_THREADS=1 fi - cargo test --target $TARGET - cargo test --target $TARGET --release + if [[ $QEMU ]]; then + cargo test --target $TARGET --no-run + $QEMU target/**/debug/rustc_builtins-* + cargo test --target $TARGET --release --no-run + $QEMU target/**/release/rustc_builtins-* + else + cargo test --target $TARGET + cargo test --target $TARGET --release + fi } inspect() { From 4c52ab7a895021549ef7e1979066cdaab2dc1fcc Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 20:37:04 -0500 Subject: [PATCH 0028/4206] run in xenial (docker) --- library/compiler-builtins/.travis.yml | 1 + library/compiler-builtins/ci/env.sh | 1 + library/compiler-builtins/ci/install.sh | 22 +++++++++++++++++----- library/compiler-builtins/ci/script.sh | 16 +++++++++++++--- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index ba1c5369d128c..aecd54618c085 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -63,6 +63,7 @@ matrix: - env: TARGET=powerpc64le-unknown-linux-gnu os: linux dist: trusty + services: docker sudo: required addons: apt: diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 29707a4b08c70..ed4e1b0b6511e 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -29,6 +29,7 @@ case $TARGET in export QEMU_LD_PREFIX=/usr/powerpc-linux-gnu ;; powerpc64le-unknown-linux-gnu) + export DOCKER=y export PREFIX=powerpc64le-linux-gnu- export QEMU=qemu-ppc64le export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 3d11092f8c014..79af908946c9b 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -2,6 +2,15 @@ set -ex . $(dirname $0)/env.sh +install_qemu() { + case $TARGET in + powerpc64-unknown-linux-gnu) + sudo apt-get install -y --no-install-recommends \ + qemu-user + ;; + esac +} + install_binutils() { case $TRAVIS_OS_NAME in osx) @@ -49,11 +58,14 @@ EOF } main() { - install_binutils - install_c_toolchain - install_rust - add_rustup_target - configure_cargo + if [[ -z $DOCKER ]]; then + install_qemu + install_binutils + install_c_toolchain + install_rust + add_rustup_target + configure_cargo + fi } main diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 0249a531cd3a2..b3f7c17a3e5ec 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -32,9 +32,19 @@ inspect() { } main() { - build - run_tests - inspect + if [[ $DOCKER ]]; then + docker run \ + -e TARGET=$TARGET \ + -e TRAVIS_OS_NAME=$TRAVIS_OS_NAME \ + -v $(pwd)/ci:/mnt \ + ubuntu:16.04 \ + sh -c "bash /mnt/install.sh; bash /mnt/script.sh" + else + build + run_tests + inspect + fi + } main From a2fd9ed440a2aeca262fb17baf17e8e690aed6d7 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 20:41:08 -0500 Subject: [PATCH 0029/4206] install toolchain in docker --- library/compiler-builtins/.travis.yml | 9 --------- library/compiler-builtins/ci/install.sh | 6 +++++- library/compiler-builtins/ci/script.sh | 4 ++-- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index aecd54618c085..dee71f7022f3a 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -62,17 +62,8 @@ matrix: - qemu-user-static - env: TARGET=powerpc64le-unknown-linux-gnu os: linux - dist: trusty services: docker sudo: required - addons: - apt: - packages: - - binfmt-support - - gcc-powerpc64le-linux-gnu - - libc6-ppc64el-cross - - libc6-dev-ppc64el-cross - - qemu-user - env: TARGET=x86_64-apple-darwin os: osx - env: TARGET=x86_64-unknown-linux-gnu diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 79af908946c9b..80a1023b3c386 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -25,7 +25,11 @@ install_c_toolchain() { case $TARGET in aarch64-unknown-linux-gnu) sudo apt-get install -y --no-install-recommends \ - gcc-aarch64-linux-gnu libc6-arm64-cross libc6-dev-arm64-cross + gcc-aarch64-linux-gnu libc6-dev-arm64-cross + ;; + powerpc64-unknown-linux-gnu) + sudo apt-get install -y --no-install-recommends \ + gcc-powerpc64le-linux-gnu libc6-dev-ppc64le-cross ;; *) ;; diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index b3f7c17a3e5ec..1013208bb9d97 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -36,9 +36,9 @@ main() { docker run \ -e TARGET=$TARGET \ -e TRAVIS_OS_NAME=$TRAVIS_OS_NAME \ - -v $(pwd)/ci:/mnt \ + -v $(pwd):/mnt \ ubuntu:16.04 \ - sh -c "bash /mnt/install.sh; bash /mnt/script.sh" + sh -c "cd /mnt; bash ci/install.sh; bash ci/script.sh" else build run_tests From 3d3248119a505d26432e60c892adba4b56de1616 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 20:45:46 -0500 Subject: [PATCH 0030/4206] enable docker --- library/compiler-builtins/.travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index dee71f7022f3a..6d3d4311a40c4 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -62,7 +62,8 @@ matrix: - qemu-user-static - env: TARGET=powerpc64le-unknown-linux-gnu os: linux - services: docker + services: + - docker sudo: required - env: TARGET=x86_64-apple-darwin os: osx From 87004d454cdef106a7df67054117bae3fd4c100b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 20:53:33 -0500 Subject: [PATCH 0031/4206] don't recursively call docker --- library/compiler-builtins/.travis.yml | 3 +-- library/compiler-builtins/ci/env.sh | 4 +++- library/compiler-builtins/ci/script.sh | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 6d3d4311a40c4..dee71f7022f3a 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -62,8 +62,7 @@ matrix: - qemu-user-static - env: TARGET=powerpc64le-unknown-linux-gnu os: linux - services: - - docker + services: docker sudo: required - env: TARGET=x86_64-apple-darwin os: osx diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index ed4e1b0b6511e..7458372baf814 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -29,7 +29,9 @@ case $TARGET in export QEMU_LD_PREFIX=/usr/powerpc-linux-gnu ;; powerpc64le-unknown-linux-gnu) - export DOCKER=y + if [[ -z $DOCKER ]]; then + export DOCKER=y + fi export PREFIX=powerpc64le-linux-gnu- export QEMU=qemu-ppc64le export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 1013208bb9d97..1e23656791bbc 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -32,8 +32,9 @@ inspect() { } main() { - if [[ $DOCKER ]]; then + if [[ $DOCKER == "y" ]]; then docker run \ + -e DOCKER=n \ -e TARGET=$TARGET \ -e TRAVIS_OS_NAME=$TRAVIS_OS_NAME \ -v $(pwd):/mnt \ @@ -44,7 +45,6 @@ main() { run_tests inspect fi - } main From f31fd01713df99e654a3faf40293dcdbc783b544 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 21:02:07 -0500 Subject: [PATCH 0032/4206] set PATH inside docker --- library/compiler-builtins/ci/script.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 1e23656791bbc..56625fafc5450 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -39,7 +39,10 @@ main() { -e TRAVIS_OS_NAME=$TRAVIS_OS_NAME \ -v $(pwd):/mnt \ ubuntu:16.04 \ - sh -c "cd /mnt; bash ci/install.sh; bash ci/script.sh" + sh -c 'cd /mnt; + export PATH="$PATH:$HOME/.cargo/bin"; + bash ci/install.sh; + bash ci/script.sh' else build run_tests From ed2f8c937ea28ec1ce5f3b249c2ef4643a039426 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 21:14:04 -0500 Subject: [PATCH 0033/4206] don't skip install phase inside docker --- library/compiler-builtins/ci/install.sh | 2 +- library/compiler-builtins/ci/script.sh | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 80a1023b3c386..69f6ebcf36dfb 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -62,7 +62,7 @@ EOF } main() { - if [[ -z $DOCKER ]]; then + if [[ ${DOCKER:-n} != "y" ]]; then install_qemu install_binutils install_c_toolchain diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 56625fafc5450..4a6dce7a8a9d2 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -39,7 +39,8 @@ main() { -e TRAVIS_OS_NAME=$TRAVIS_OS_NAME \ -v $(pwd):/mnt \ ubuntu:16.04 \ - sh -c 'cd /mnt; + sh -c 'set -ex; + cd /mnt; export PATH="$PATH:$HOME/.cargo/bin"; bash ci/install.sh; bash ci/script.sh' From f9d1455b29959b64c0652e7af6cac326d4e594e0 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 21:20:46 -0500 Subject: [PATCH 0034/4206] install curl inside docker --- library/compiler-builtins/ci/install.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 69f6ebcf36dfb..3c87ddb6ad34c 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -2,6 +2,13 @@ set -ex . $(dirname $0)/env.sh +install_deps() { + if [[ ${DOCKER} == "y" ]]; then + apt-get install -y --no-install-recommends \ + ca-certificates curl + fi +} + install_qemu() { case $TARGET in powerpc64-unknown-linux-gnu) @@ -63,6 +70,7 @@ EOF main() { if [[ ${DOCKER:-n} != "y" ]]; then + install_deps install_qemu install_binutils install_c_toolchain From eb5a86b261948f4a6e8407203fc69ebce3ce5ae1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 21:27:08 -0500 Subject: [PATCH 0035/4206] really install curl inside docker --- library/compiler-builtins/ci/env.sh | 1 + library/compiler-builtins/ci/install.sh | 2 +- library/compiler-builtins/ci/script.sh | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 7458372baf814..f1aa4fe2cd2da 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -29,6 +29,7 @@ case $TARGET in export QEMU_LD_PREFIX=/usr/powerpc-linux-gnu ;; powerpc64le-unknown-linux-gnu) + # NOTE $DOCKER values: 'y' (yes, call docker), 'i' (inside a docker container) or 'n' ("no) if [[ -z $DOCKER ]]; then export DOCKER=y fi diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 3c87ddb6ad34c..c545eedf1a52c 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -3,7 +3,7 @@ set -ex . $(dirname $0)/env.sh install_deps() { - if [[ ${DOCKER} == "y" ]]; then + if [[ ${DOCKER} == "i" ]]; then apt-get install -y --no-install-recommends \ ca-certificates curl fi diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 4a6dce7a8a9d2..65d74a332a290 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -34,7 +34,7 @@ inspect() { main() { if [[ $DOCKER == "y" ]]; then docker run \ - -e DOCKER=n \ + -e DOCKER=i \ -e TARGET=$TARGET \ -e TRAVIS_OS_NAME=$TRAVIS_OS_NAME \ -v $(pwd):/mnt \ From ce538c66184576694e2cc0ccfe62aad2b20cc3d2 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 21:32:12 -0500 Subject: [PATCH 0036/4206] apt-get update --- library/compiler-builtins/ci/install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index c545eedf1a52c..d7eac145dfb07 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -4,6 +4,7 @@ set -ex install_deps() { if [[ ${DOCKER} == "i" ]]; then + apt-get update apt-get install -y --no-install-recommends \ ca-certificates curl fi From d24e0e07a32d767495f84645a3747431cecd3614 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 21:37:48 -0500 Subject: [PATCH 0037/4206] fix installation of c toolchain --- library/compiler-builtins/ci/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index d7eac145dfb07..2635c8984aa79 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -35,7 +35,7 @@ install_c_toolchain() { sudo apt-get install -y --no-install-recommends \ gcc-aarch64-linux-gnu libc6-dev-arm64-cross ;; - powerpc64-unknown-linux-gnu) + powerpc64le-unknown-linux-gnu) sudo apt-get install -y --no-install-recommends \ gcc-powerpc64le-linux-gnu libc6-dev-ppc64le-cross ;; From 5e6dc52747f8aa5d3a6542c51b801a61e325f0fa Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 21:43:01 -0500 Subject: [PATCH 0038/4206] no sudo --- library/compiler-builtins/ci/install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 2635c8984aa79..0000e45756233 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -36,8 +36,8 @@ install_c_toolchain() { gcc-aarch64-linux-gnu libc6-dev-arm64-cross ;; powerpc64le-unknown-linux-gnu) - sudo apt-get install -y --no-install-recommends \ - gcc-powerpc64le-linux-gnu libc6-dev-ppc64le-cross + apt-get install -y --no-install-recommends \ + gcc-powerpc64le-linux-gnu libc6-dev-ppc64le-cross ;; *) ;; From 32758212c87a74a15c4774aee11ddebb032b44cd Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 21:43:13 -0500 Subject: [PATCH 0039/4206] put first in the queue --- library/compiler-builtins/.travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index dee71f7022f3a..7f90c44ad750b 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -3,6 +3,10 @@ sudo: false matrix: include: + - env: TARGET=powerpc64le-unknown-linux-gnu + os: linux + services: docker + sudo: required - env: TARGET=aarch64-unknown-linux-gnu os: linux dist: trusty @@ -60,10 +64,6 @@ matrix: - libc6-powerpc-cross - libc6-dev-powerpc-cross - qemu-user-static - - env: TARGET=powerpc64le-unknown-linux-gnu - os: linux - services: docker - sudo: required - env: TARGET=x86_64-apple-darwin os: osx - env: TARGET=x86_64-unknown-linux-gnu From 378bab2a11f4d6edb74f708b66f568e6914adce4 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 21:46:24 -0500 Subject: [PATCH 0040/4206] fix package name --- library/compiler-builtins/ci/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 0000e45756233..867ac00e743bc 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -37,7 +37,7 @@ install_c_toolchain() { ;; powerpc64le-unknown-linux-gnu) apt-get install -y --no-install-recommends \ - gcc-powerpc64le-linux-gnu libc6-dev-ppc64le-cross + gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross ;; *) ;; From c3a501ec3b84a6927097a4389c1b1ecebeb0ac60 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 21:49:31 -0500 Subject: [PATCH 0041/4206] fix target name in case --- library/compiler-builtins/ci/install.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 867ac00e743bc..ae94e949d2435 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -12,9 +12,9 @@ install_deps() { install_qemu() { case $TARGET in - powerpc64-unknown-linux-gnu) - sudo apt-get install -y --no-install-recommends \ - qemu-user + powerpc64le-unknown-linux-gnu) + apt-get install -y --no-install-recommends \ + qemu-user ;; esac } From 808ff7d4696afcebc790f5a18ff67481917b78fc Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 21:57:18 -0500 Subject: [PATCH 0042/4206] allow failure --- library/compiler-builtins/.travis.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 7f90c44ad750b..3ae43eba3f823 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -3,10 +3,6 @@ sudo: false matrix: include: - - env: TARGET=powerpc64le-unknown-linux-gnu - os: linux - services: docker - sudo: required - env: TARGET=aarch64-unknown-linux-gnu os: linux dist: trusty @@ -64,6 +60,10 @@ matrix: - libc6-powerpc-cross - libc6-dev-powerpc-cross - qemu-user-static + - env: TARGET=powerpc64le-unknown-linux-gnu + os: linux + services: docker + sudo: required - env: TARGET=x86_64-apple-darwin os: osx - env: TARGET=x86_64-unknown-linux-gnu @@ -72,6 +72,9 @@ matrix: # FIXME(#2) - env: TARGET=armv7-unknown-linux-gnueabihf os: linux + # FIXME QEMU blows up + - env: TARGET=powerpc64le-unknown-linux-gnu + os: linux before_install: - export PATH="$PATH:$HOME/.cargo/bin" From cb83ffc7f740f24052dbc9afff1f26ab48afa772 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 22:03:44 -0500 Subject: [PATCH 0043/4206] CI: test mips-unknown-linux-gnu --- library/compiler-builtins/.travis.yml | 4 ++++ library/compiler-builtins/ci/env.sh | 10 +++++++++- library/compiler-builtins/ci/install.sh | 5 +++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 3ae43eba3f823..e6667a7e4b51d 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -48,6 +48,10 @@ matrix: apt: packages: - gcc-multilib + - env: TARGET=mips-unknown-linux-gnu + os: linux + services: docker + sudo: required - env: TARGET=powerpc-unknown-linux-gnu os: linux dist: trusty diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index f1aa4fe2cd2da..eadaae478f9f7 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -24,12 +24,20 @@ case $TARGET in export PREFIX=arm-linux-gnueabihf- export QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf ;; + mips-unknown-linux-gnu) + # NOTE $DOCKER values: 'y' (yes, call docker), 'i' (inside a docker container) or 'n' ("no) + if [[ -z $DOCKER ]]; then + export DOCKER=y + fi + export PREFIX=mips-linux-gnu- + export QEMU=qemu-mips + export QEMU_LD_PREFIX=/usr/mips-linux-gnu + ;; powerpc-unknown-linux-gnu) export PREFIX=powerpc-linux-gnu- export QEMU_LD_PREFIX=/usr/powerpc-linux-gnu ;; powerpc64le-unknown-linux-gnu) - # NOTE $DOCKER values: 'y' (yes, call docker), 'i' (inside a docker container) or 'n' ("no) if [[ -z $DOCKER ]]; then export DOCKER=y fi diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index ae94e949d2435..e306cdf1f5693 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -12,6 +12,7 @@ install_deps() { install_qemu() { case $TARGET in + mips-unknown-linux-gnu | powerpc64le-unknown-linux-gnu) apt-get install -y --no-install-recommends \ qemu-user @@ -35,6 +36,10 @@ install_c_toolchain() { sudo apt-get install -y --no-install-recommends \ gcc-aarch64-linux-gnu libc6-dev-arm64-cross ;; + mips-unknown-linux-gnu) + apt-get install -y --no-install-recommends \ + gcc-mips-linux-gnu libc6-dev-mips-cross + ;; powerpc64le-unknown-linux-gnu) apt-get install -y --no-install-recommends \ gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross From b458b433979dd5ab1d4a84f5ff0c16dfa7ba77af Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 22:31:14 -0500 Subject: [PATCH 0044/4206] fix case syntax --- library/compiler-builtins/ci/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index e306cdf1f5693..edabee74373b4 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -12,7 +12,7 @@ install_deps() { install_qemu() { case $TARGET in - mips-unknown-linux-gnu | + mips-unknown-linux-gnu | \ powerpc64le-unknown-linux-gnu) apt-get install -y --no-install-recommends \ qemu-user From 04c097a6e399bc8f9a0494a784a5de69a8a218bf Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 22:47:37 -0500 Subject: [PATCH 0045/4206] allow failure --- library/compiler-builtins/.travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index e6667a7e4b51d..46cdb6610b0ce 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -77,6 +77,9 @@ matrix: - env: TARGET=armv7-unknown-linux-gnueabihf os: linux # FIXME QEMU blows up + - env: TARGET=mips-unknown-linux-gnu + os: linux + # FIXME QEMU blows up - env: TARGET=powerpc64le-unknown-linux-gnu os: linux From e9f11c6f121409213efe6acc6274ac25c6b773d8 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 21:59:31 -0500 Subject: [PATCH 0046/4206] CI: test powerpc64-unknown-linux-gnu --- library/compiler-builtins/.travis.yml | 7 +++++++ library/compiler-builtins/ci/env.sh | 8 ++++++++ library/compiler-builtins/ci/install.sh | 5 +++++ 3 files changed, 20 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 46cdb6610b0ce..008cc3dabc029 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -64,6 +64,10 @@ matrix: - libc6-powerpc-cross - libc6-dev-powerpc-cross - qemu-user-static + - env: TARGET=powerpc64-unknown-linux-gnu + os: linux + services: docker + sudo: required - env: TARGET=powerpc64le-unknown-linux-gnu os: linux services: docker @@ -80,6 +84,9 @@ matrix: - env: TARGET=mips-unknown-linux-gnu os: linux # FIXME QEMU blows up + - env: TARGET=powerpc64-unknown-linux-gnu + os: linux + # FIXME QEMU blows up - env: TARGET=powerpc64le-unknown-linux-gnu os: linux diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index eadaae478f9f7..81b89014abcf0 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -37,6 +37,14 @@ case $TARGET in export PREFIX=powerpc-linux-gnu- export QEMU_LD_PREFIX=/usr/powerpc-linux-gnu ;; + powerpc64-unknown-linux-gnu) + if [[ -z $DOCKER ]]; then + export DOCKER=y + fi + export PREFIX=powerpc64-linux-gnu- + export QEMU=qemu-ppc64 + export QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu + ;; powerpc64le-unknown-linux-gnu) if [[ -z $DOCKER ]]; then export DOCKER=y diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index edabee74373b4..85fcc4d6b5b3e 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -13,6 +13,7 @@ install_deps() { install_qemu() { case $TARGET in mips-unknown-linux-gnu | \ + powerpc64-unknown-linux-gnu | \ powerpc64le-unknown-linux-gnu) apt-get install -y --no-install-recommends \ qemu-user @@ -40,6 +41,10 @@ install_c_toolchain() { apt-get install -y --no-install-recommends \ gcc-mips-linux-gnu libc6-dev-mips-cross ;; + powerpc64-unknown-linux-gnu) + apt-get install -y --no-install-recommends \ + gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross + ;; powerpc64le-unknown-linux-gnu) apt-get install -y --no-install-recommends \ gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross From 59a8ab6c87df5e730a4ccf4cf9e2d5c3ee503e1e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 8 Aug 2016 23:07:33 -0500 Subject: [PATCH 0047/4206] CI: test mipsel-unknown-linux-gnu --- library/compiler-builtins/.travis.yml | 4 ++++ library/compiler-builtins/ci/env.sh | 9 +++++++++ library/compiler-builtins/ci/install.sh | 5 +++++ 3 files changed, 18 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 008cc3dabc029..dacfd705a5018 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -52,6 +52,10 @@ matrix: os: linux services: docker sudo: required + - env: TARGET=mipsel-unknown-linux-gnu + os: linux + services: docker + sudo: required - env: TARGET=powerpc-unknown-linux-gnu os: linux dist: trusty diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 81b89014abcf0..fb3d1ef26f763 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -33,6 +33,15 @@ case $TARGET in export QEMU=qemu-mips export QEMU_LD_PREFIX=/usr/mips-linux-gnu ;; + mipsel-unknown-linux-gnu) + # NOTE $DOCKER values: 'y' (yes, call docker), 'i' (inside a docker container) or 'n' ("no) + if [[ -z $DOCKER ]]; then + export DOCKER=y + fi + export PREFIX=mipsel-linux-gnu- + export QEMU=qemu-mipsel + export QEMU_LD_PREFIX=/usr/mipsel-linux-gnu + ;; powerpc-unknown-linux-gnu) export PREFIX=powerpc-linux-gnu- export QEMU_LD_PREFIX=/usr/powerpc-linux-gnu diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 85fcc4d6b5b3e..82c4c59b37ca5 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -13,6 +13,7 @@ install_deps() { install_qemu() { case $TARGET in mips-unknown-linux-gnu | \ + mipsel-unknown-linux-gnu | \ powerpc64-unknown-linux-gnu | \ powerpc64le-unknown-linux-gnu) apt-get install -y --no-install-recommends \ @@ -41,6 +42,10 @@ install_c_toolchain() { apt-get install -y --no-install-recommends \ gcc-mips-linux-gnu libc6-dev-mips-cross ;; + mipsel-unknown-linux-gnu) + apt-get install -y --no-install-recommends \ + gcc-mipsel-linux-gnu libc6-dev-mipsel-cross + ;; powerpc64-unknown-linux-gnu) apt-get install -y --no-install-recommends \ gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross From 4d0da42b082460879b7f925d92dd45b1ec42706e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 9 Aug 2016 11:48:51 -0500 Subject: [PATCH 0048/4206] don't run tests on targets that have QEMU issues cc #2 --- library/compiler-builtins/.travis.yml | 13 ------------- library/compiler-builtins/ci/env.sh | 15 +++++++++++++-- library/compiler-builtins/ci/script.sh | 8 ++++++-- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index dacfd705a5018..c1b6dd4fbd1cf 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -80,19 +80,6 @@ matrix: os: osx - env: TARGET=x86_64-unknown-linux-gnu os: linux - allow_failures: - # FIXME(#2) - - env: TARGET=armv7-unknown-linux-gnueabihf - os: linux - # FIXME QEMU blows up - - env: TARGET=mips-unknown-linux-gnu - os: linux - # FIXME QEMU blows up - - env: TARGET=powerpc64-unknown-linux-gnu - os: linux - # FIXME QEMU blows up - - env: TARGET=powerpc64le-unknown-linux-gnu - os: linux before_install: - export PATH="$PATH:$HOME/.cargo/bin" diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index fb3d1ef26f763..ee3bd163e8cba 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -20,11 +20,19 @@ case $TARGET in export PREFIX=arm-linux-gnueabi- export QEMU_LD_PREFIX=/usr/arm-linux-gnueabi ;; - arm*-unknown-linux-gnueabihf) + arm-unknown-linux-gnueabihf) + export PREFIX=arm-linux-gnueabihf- + export QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf + ;; + armv7-unknown-linux-gnueabihf) + # See #2 + export DONT_RUN_TESTS=y export PREFIX=arm-linux-gnueabihf- export QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf ;; mips-unknown-linux-gnu) + # See #2 + export DONT_RUN_TESTS=y # NOTE $DOCKER values: 'y' (yes, call docker), 'i' (inside a docker container) or 'n' ("no) if [[ -z $DOCKER ]]; then export DOCKER=y @@ -34,7 +42,6 @@ case $TARGET in export QEMU_LD_PREFIX=/usr/mips-linux-gnu ;; mipsel-unknown-linux-gnu) - # NOTE $DOCKER values: 'y' (yes, call docker), 'i' (inside a docker container) or 'n' ("no) if [[ -z $DOCKER ]]; then export DOCKER=y fi @@ -47,6 +54,8 @@ case $TARGET in export QEMU_LD_PREFIX=/usr/powerpc-linux-gnu ;; powerpc64-unknown-linux-gnu) + # See #2 + export DONT_RUN_TESTS=y if [[ -z $DOCKER ]]; then export DOCKER=y fi @@ -55,6 +64,8 @@ case $TARGET in export QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu ;; powerpc64le-unknown-linux-gnu) + # See #2 + export DONT_RUN_TESTS=y if [[ -z $DOCKER ]]; then export DOCKER=y fi diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 65d74a332a290..16b6e763f0354 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -14,9 +14,13 @@ run_tests() { if [[ $QEMU ]]; then cargo test --target $TARGET --no-run - $QEMU target/**/debug/rustc_builtins-* + if [[ -z $DONT_RUN_TESTS ]]; then + $QEMU target/**/debug/rustc_builtins-* + fi cargo test --target $TARGET --release --no-run - $QEMU target/**/release/rustc_builtins-* + if [[ -z $DONT_RUN_TESTS ]]; then + $QEMU target/**/release/rustc_builtins-* + fi else cargo test --target $TARGET cargo test --target $TARGET --release From b191b89e87cf308ff6ded22a78b76509003f88cb Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 9 Aug 2016 11:53:49 -0500 Subject: [PATCH 0049/4206] fix armv7 --- library/compiler-builtins/ci/script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 16b6e763f0354..c0074ec080821 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -21,7 +21,7 @@ run_tests() { if [[ -z $DONT_RUN_TESTS ]]; then $QEMU target/**/release/rustc_builtins-* fi - else + else if [[ -z $DONT_RUN_TESTS ]]; then cargo test --target $TARGET cargo test --target $TARGET --release fi From d6acb778e485d7c5d779c71963e9d7a34de5a242 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 9 Aug 2016 12:04:24 -0500 Subject: [PATCH 0050/4206] fix bash syntax --- library/compiler-builtins/ci/script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index c0074ec080821..099e42ea3b059 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -21,7 +21,7 @@ run_tests() { if [[ -z $DONT_RUN_TESTS ]]; then $QEMU target/**/release/rustc_builtins-* fi - else if [[ -z $DONT_RUN_TESTS ]]; then + elif [[ -z $DONT_RUN_TESTS ]]; then cargo test --target $TARGET cargo test --target $TARGET --release fi From 3aa17dec7a41a16582650e1cbc6f541057efe31f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 9 Aug 2016 12:25:49 -0500 Subject: [PATCH 0051/4206] CI: test i586-unknown-linux-gnu --- library/compiler-builtins/.travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index c1b6dd4fbd1cf..45b3d03fb7ecc 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -42,6 +42,12 @@ matrix: packages: *armhf - env: TARGET=i686-apple-darwin os: osx + - env: TARGET=i586-unknown-linux-gnu + os: linux + addons: + apt: + packages: + - gcc-multilib - env: TARGET=i686-unknown-linux-gnu os: linux addons: From a601cae4b4f80569009333f37fec83a136d8b820 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 9 Aug 2016 12:43:37 -0500 Subject: [PATCH 0052/4206] use trusty --- library/compiler-builtins/.travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 45b3d03fb7ecc..b3fd61d8a81d3 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -44,6 +44,7 @@ matrix: os: osx - env: TARGET=i586-unknown-linux-gnu os: linux + dist: trusty addons: apt: packages: From 5e8812c57419c645929c1c8741139391dafd66da Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 9 Aug 2016 15:37:24 -0500 Subject: [PATCH 0053/4206] use docker --- library/compiler-builtins/.travis.yml | 7 ++----- library/compiler-builtins/ci/env.sh | 7 ++++++- library/compiler-builtins/ci/install.sh | 4 ++++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index b3fd61d8a81d3..13e843e4de346 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -44,11 +44,8 @@ matrix: os: osx - env: TARGET=i586-unknown-linux-gnu os: linux - dist: trusty - addons: - apt: - packages: - - gcc-multilib + services: docker + sudo: required - env: TARGET=i686-unknown-linux-gnu os: linux addons: diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index ee3bd163e8cba..09b86f2f09320 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -30,10 +30,15 @@ case $TARGET in export PREFIX=arm-linux-gnueabihf- export QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf ;; + i586-unknown-linux-gnu) + # NOTE $DOCKER values: 'y' (yes, call docker), 'i' (inside a docker container) or 'n' ("no) + if [[ -z $DOCKER ]]; then + export DOCKER=y + fi + ;; mips-unknown-linux-gnu) # See #2 export DONT_RUN_TESTS=y - # NOTE $DOCKER values: 'y' (yes, call docker), 'i' (inside a docker container) or 'n' ("no) if [[ -z $DOCKER ]]; then export DOCKER=y fi diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 82c4c59b37ca5..c97a45daef355 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -38,6 +38,10 @@ install_c_toolchain() { sudo apt-get install -y --no-install-recommends \ gcc-aarch64-linux-gnu libc6-dev-arm64-cross ;; + i586-unknown-linux-gnu) + apt-get install -y --no-install-recommends \ + gcc libc6-dev-i386 + ;; mips-unknown-linux-gnu) apt-get install -y --no-install-recommends \ gcc-mips-linux-gnu libc6-dev-mips-cross From 57c1e1344eac777b415e8bb8931f2abdbe3f92fd Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 9 Aug 2016 15:37:51 -0500 Subject: [PATCH 0054/4206] put the target first --- library/compiler-builtins/.travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 13e843e4de346..dae5b40b2d059 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -3,6 +3,10 @@ sudo: false matrix: include: + - env: TARGET=i586-unknown-linux-gnu + os: linux + services: docker + sudo: required - env: TARGET=aarch64-unknown-linux-gnu os: linux dist: trusty @@ -42,10 +46,6 @@ matrix: packages: *armhf - env: TARGET=i686-apple-darwin os: osx - - env: TARGET=i586-unknown-linux-gnu - os: linux - services: docker - sudo: required - env: TARGET=i686-unknown-linux-gnu os: linux addons: From 4e6c1b1be3cb0e205e7ac2397706bcb4f65d2fe1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 9 Aug 2016 15:46:57 -0500 Subject: [PATCH 0055/4206] add libgcc --- library/compiler-builtins/ci/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index c97a45daef355..e34433c894f7a 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -40,7 +40,7 @@ install_c_toolchain() { ;; i586-unknown-linux-gnu) apt-get install -y --no-install-recommends \ - gcc libc6-dev-i386 + gcc libc6-dev-i386 libgcc1 ;; mips-unknown-linux-gnu) apt-get install -y --no-install-recommends \ From f484596465376ad861a80f5f351a18ccf4485617 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 9 Aug 2016 15:55:25 -0500 Subject: [PATCH 0056/4206] 32-bit version of libgcc --- library/compiler-builtins/ci/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index e34433c894f7a..8226e1784f026 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -40,7 +40,7 @@ install_c_toolchain() { ;; i586-unknown-linux-gnu) apt-get install -y --no-install-recommends \ - gcc libc6-dev-i386 libgcc1 + gcc libc6-dev-i386 lib32gcc1 ;; mips-unknown-linux-gnu) apt-get install -y --no-install-recommends \ From 3d2573086fcccd9df7121ec57d4c44ef569c88fa Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 9 Aug 2016 16:17:06 -0500 Subject: [PATCH 0057/4206] libgcc_s dev version --- library/compiler-builtins/ci/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 8226e1784f026..9251f79a37d96 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -40,7 +40,7 @@ install_c_toolchain() { ;; i586-unknown-linux-gnu) apt-get install -y --no-install-recommends \ - gcc libc6-dev-i386 lib32gcc1 + gcc libc6-dev-i386 lib32gcc-5-dev ;; mips-unknown-linux-gnu) apt-get install -y --no-install-recommends \ From 1d924aa047a82ad6b7b9dadffc13fe4d7813c246 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 10 Aug 2016 11:50:41 -0500 Subject: [PATCH 0058/4206] mips: run test on 32-bit QEMU cc #2 --- library/compiler-builtins/ci/env.sh | 2 -- library/compiler-builtins/ci/install.sh | 9 ++++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 09b86f2f09320..6ec927d50f739 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -37,8 +37,6 @@ case $TARGET in fi ;; mips-unknown-linux-gnu) - # See #2 - export DONT_RUN_TESTS=y if [[ -z $DOCKER ]]; then export DOCKER=y fi diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 9251f79a37d96..074b5eac015d0 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -12,13 +12,18 @@ install_deps() { install_qemu() { case $TARGET in - mips-unknown-linux-gnu | \ mipsel-unknown-linux-gnu | \ powerpc64-unknown-linux-gnu | \ powerpc64le-unknown-linux-gnu) apt-get install -y --no-install-recommends \ qemu-user ;; + mips-unknown-linux-gnu) + dpkg --add-architecture i386 + apt-get update + apt-get install -y --no-install-recommends \ + qemu-user:i386 + ;; esac } @@ -58,8 +63,6 @@ install_c_toolchain() { apt-get install -y --no-install-recommends \ gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross ;; - *) - ;; esac } From 989cd751cc5ee1850be988e222f7db6ecbed4b58 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 10 Aug 2016 13:01:22 -0500 Subject: [PATCH 0059/4206] ppc64: test on 32-bit QEMU --- library/compiler-builtins/ci/env.sh | 2 -- library/compiler-builtins/ci/install.sh | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 6ec927d50f739..472983ff91897 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -57,8 +57,6 @@ case $TARGET in export QEMU_LD_PREFIX=/usr/powerpc-linux-gnu ;; powerpc64-unknown-linux-gnu) - # See #2 - export DONT_RUN_TESTS=y if [[ -z $DOCKER ]]; then export DOCKER=y fi diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 074b5eac015d0..d60571db3d090 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -13,12 +13,12 @@ install_deps() { install_qemu() { case $TARGET in mipsel-unknown-linux-gnu | \ - powerpc64-unknown-linux-gnu | \ powerpc64le-unknown-linux-gnu) apt-get install -y --no-install-recommends \ qemu-user ;; - mips-unknown-linux-gnu) + mips-unknown-linux-gnu | \ + powerpc64-unknown-linux-gnu) dpkg --add-architecture i386 apt-get update apt-get install -y --no-install-recommends \ From 2880fd70ad0504a56925609c9ffd229a6a7a7617 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 11 Aug 2016 05:28:15 +0100 Subject: [PATCH 0060/4206] Add traits for integer operations --- library/compiler-builtins/src/lib.rs | 63 ++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 01aca7674c224..3ef13549e5a5b 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -9,21 +9,76 @@ #[cfg(test)] extern crate core; -use core::mem; - #[cfg(target_arch = "arm")] pub mod arm; #[cfg(test)] mod test; -const CHAR_BITS: usize = 8; +/// Trait for some basic operations on integers +trait Int { + fn bits() -> usize; +} + +// TODO: Once i128/u128 support lands, we'll want to add impls for those as well +impl Int for u32 { + fn bits() -> usize { 32 } +} +impl Int for i32 { + fn bits() -> usize { 32 } +} +impl Int for u64 { + fn bits() -> usize { 64 } +} +impl Int for i64 { + fn bits() -> usize { 64 } +} + +/// Trait to convert an integer to/from smaller parts +trait LargeInt { + type LowHalf; + type HighHalf; + + fn low(self) -> Self::LowHalf; + fn high(self) -> Self::HighHalf; + fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self; +} + +// TODO: Once i128/u128 support lands, we'll want to add impls for those as well +impl LargeInt for u64 { + type LowHalf = u32; + type HighHalf = u32; + + fn low(self) -> u32 { + self as u32 + } + fn high(self) -> u32 { + (self >> 32) as u32 + } + fn from_parts(low: u32, high: u32) -> u64 { + low as u64 | ((high as u64) << 32) + } +} +impl LargeInt for i64 { + type LowHalf = u32; + type HighHalf = i32; + + fn low(self) -> u32 { + self as u32 + } + fn high(self) -> i32 { + (self >> 32) as i32 + } + fn from_parts(low: u32, high: i32) -> i64 { + low as i64 | ((high as i64) << 32) + } +} macro_rules! absv_i2 { ($intrinsic:ident : $ty:ty) => { #[no_mangle] pub extern "C" fn $intrinsic(x: $ty) -> $ty { - let n = mem::size_of::<$ty>() * CHAR_BITS; + let n = <$ty>::bits(); if x == 1 << (n - 1) { panic!(); } From 2eb2ac115d217249f543d24ee21a8604488b6074 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 10 Aug 2016 19:12:37 -0500 Subject: [PATCH 0061/4206] port udivmoddi4 and __aeabi_uldivmod --- library/compiler-builtins/Cargo.toml | 3 + library/compiler-builtins/src/arm.rs | 17 ++ library/compiler-builtins/src/lib.rs | 259 ++++++++++++++++++++++++++ library/compiler-builtins/src/test.rs | 21 ++- 4 files changed, 299 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 663d9b109a40c..dfd1fdeeee153 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -2,3 +2,6 @@ authors = ["Jorge Aparicio "] name = "rustc_builtins" version = "0.1.0" + +[dev-dependencies] +quickcheck = "0.3.1" diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 7beb91aa958a6..55e9bb9faaa19 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,3 +1,20 @@ +use core::mem; + +#[repr(C)] +pub struct u64x2 { + a: u64, + b: u64, +} + +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_uldivmod(num: u64, den: u64) -> u64x2 { + + let mut rem = mem::uninitialized(); + let quot = ::__udivmoddi4(num, den, &mut rem); + + u64x2 { a: quot, b: rem } +} + extern "C" { fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 3ef13549e5a5b..e5caa83dcbf67 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -8,6 +8,9 @@ #[cfg(test)] extern crate core; +#[cfg(test)] +#[macro_use] +extern crate quickcheck; #[cfg(target_arch = "arm")] pub mod arm; @@ -15,6 +18,8 @@ pub mod arm; #[cfg(test)] mod test; +use core::mem; + /// Trait for some basic operations on integers trait Int { fn bits() -> usize; @@ -93,3 +98,257 @@ absv_i2!(__absvsi2: i32); absv_i2!(__absvdi2: i64); // TODO(rust-lang/35118)? // absv_i2!(__absvti2, i128); + +#[no_mangle] +pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 { + #[cfg(target_endian = "little")] + #[repr(C)] + #[derive(Debug)] + struct words { + low: u32, + high: u32, + } + + #[cfg(target_endian = "big")] + #[repr(C)] + #[derive(Debug)] + struct words { + high: u32, + low: u32, + } + + impl words { + fn all(&mut self) -> &mut u64 { + unsafe { mem::transmute(self) } + } + + fn u64(&self) -> u64 { + unsafe { *(self as *const _ as *const u64) } + } + } + + impl From for words { + fn from(x: u64) -> words { + unsafe { mem::transmute(x) } + } + } + + let u32_bits = u32::bits() as u32; + let u64_bits = u64::bits() as u32; + + let n = words::from(a); + let d = words::from(b); + + // NOTE X is unknown, K != 0 + if n.high == 0 { + return if d.high == 0 { + // 0 X + // --- + // 0 X + + if let Some(rem) = unsafe { rem.as_mut() } { + *rem = u64::from(n.low % d.low); + } + u64::from(n.low / d.low) + } else + // d.high != 0 + { + // 0 X + // --- + // K X + + if let Some(rem) = unsafe { rem.as_mut() } { + *rem = u64::from(n.low); + } + 0 + }; + } + + let mut sr; + // NOTE IMO it should be possible to leave these "uninitialized" (just declare them here) + // because these variables get initialized below, but if I do that the compiler complains about + // them being used before being initialized. + let mut q = words { low: 0, high: 0 }; + let mut r = words { low: 0, high: 0 }; + + // n.high != 0 + if d.low == 0 { + if d.high == 0 { + // K X + // --- + // 0 0 + + // NOTE copied verbatim from compiler-rt, but does division by zero even make sense? + if let Some(rem) = unsafe { rem.as_mut() } { + *rem = u64::from(n.high % d.low); + } + return u64::from(n.high / d.low); + } + + // d.high != 0 + if n.low == 0 { + // K 0 + // --- + // K 0 + + if let Some(rem) = unsafe { rem.as_mut() } { + *rem = words { + low: 0, + high: n.high % d.high, + } + .u64(); + } + return u64::from(n.high / d.high); + } + + // n.low != 0 + // K K + // --- + // K 0 + + if d.high.is_power_of_two() { + if let Some(rem) = unsafe { rem.as_mut() } { + *rem = words { + low: n.low, + high: n.high & (d.high - 1), + } + .u64() + } + + return u64::from(n.high >> d.high.trailing_zeros()); + } + + sr = d.high.leading_zeros().wrapping_sub(n.high.leading_zeros()); + + // D > N + if sr > u32_bits - 2 { + if let Some(rem) = unsafe { rem.as_mut() } { + *rem = n.u64(); + } + return 0; + } + + sr = sr + 1; + + // 1 <= sr <= u32_bits - 1 + // *q.all() = n.u64() << (u64_bits - sr); + q.low = 0; + q.high = n.low << (u32_bits - sr); + // *r.all() = n.u64() >> sr + r.high = n.high >> sr; + r.low = (n.high << (u32_bits - sr)) | (n.low >> sr); + } else + // d.low != 0 + { + if d.high == 0 { + // K X + // --- + // 0 K + if d.low.is_power_of_two() { + if let Some(rem) = unsafe { rem.as_mut() } { + *rem = u64::from(n.low & (d.low - 1)); + } + + return if d.low == 1 { + n.u64() + } else { + let sr = d.low.trailing_zeros(); + words { + low: (n.high << (u32_bits - sr)) | (n.low >> sr), + high: n.high >> sr, + } + .u64() + }; + } + + sr = 1 + u32_bits + d.low.leading_zeros() - n.high.leading_zeros(); + + // 2 <= sr <= u64_bits - 1 + // *q.all() = n.u64() << (u64_bits - sr) + // *r.all() = n.u64() >> sr; + if sr == u32_bits { + q.low = 0; + q.high = n.low; + r.high = 0; + r.low = n.high; + } else if sr < u32_bits + // 2 <= sr <= u32_bits - 1 + { + q.low = 0; + q.high = n.low << (u32_bits - sr); + r.high = n.high >> sr; + r.low = (n.high << (u32_bits - sr)) | (n.low >> sr); + } else + // u32_bits + 1 <= sr <= u64_bits - 1 + { + q.low = n.low << (u64_bits - sr); + q.high = (n.high << (u64_bits - sr)) | (n.low >> (sr - u32_bits)); + r.high = 0; + r.low = n.high >> (sr - u32_bits); + } + + } else + // d.high != 0 + { + // K X + // --- + // K K + + sr = d.high.leading_zeros().wrapping_sub(n.high.leading_zeros()); + + // D > N + if sr > u32_bits - 1 { + if let Some(rem) = unsafe { rem.as_mut() } { + *rem = a; + return 0; + } + } + + sr += 1; + + // 1 <= sr <= u32_bits + // *q.all() = n.u64() << (u64_bits - sr) + q.low = 0; + if sr == u32_bits { + q.high = n.low; + r.high = 0; + r.low = n.high; + } else { + q.high = n.low << (u32_bits - sr); + r.high = n.high >> sr; + r.low = (n.high << (u32_bits - sr)) | (n.low >> sr); + } + } + } + + // Not a special case + // q and r are initialized with + // *q.all() = n.u64() << (u64_bits - sr) + // *.r.all() = n.u64() >> sr + // 1 <= sr <= u64_bits - 1 + let mut carry = 0; + + for _ in 0..sr { + // r:q = ((r:q) << 1) | carry + r.high = (r.high << 1) | (r.low >> (u32_bits - 1)); + r.low = (r.low << 1) | (q.high >> (u32_bits - 1)); + q.high = (q.high << 1) | (q.low >> (u32_bits - 1)); + q.low = (q.low << 1) | carry; + + // carry = 0 + // if r.u64() >= d.u64() { + // *r.all() -= d.u64(); + // carry = 1; + // } + + let s = (d.u64().wrapping_sub(r.u64()).wrapping_sub(1)) as i64 >> (u64_bits - 1); + carry = (s & 1) as u32; + *r.all() -= d.u64() & s as u64; + } + + *q.all() = (q.u64() << 1) | carry as u64; + if let Some(rem) = unsafe { rem.as_mut() } { + *rem = r.u64(); + } + q.u64() +} diff --git a/library/compiler-builtins/src/test.rs b/library/compiler-builtins/src/test.rs index 9abfec7e800bb..8d5a42c9e7995 100644 --- a/library/compiler-builtins/src/test.rs +++ b/library/compiler-builtins/src/test.rs @@ -1,4 +1,6 @@ -use std::panic; +use std::{mem, panic}; + +use quickcheck::TestResult; macro_rules! absv_i2 { ($intrinsic:ident: $ty:ident) => { @@ -23,3 +25,20 @@ absv_i2!(__absvsi2: i32); absv_i2!(__absvdi2: i64); // TODO(rust-lang/35118)? // absv_i2!(__absvti2: i128); + +quickcheck! { + fn udivmoddi4(a: (u32, u32), b: (u32, u32)) -> TestResult { + let (a, b) = unsafe { + (mem::transmute(a), mem::transmute(b)) + }; + + if b == 0 { + TestResult::discard() + } else { + let mut r = 0; + let q = ::__udivmoddi4(a, b, &mut r); + + TestResult::from_bool(q * b + r == a) + } + } +} From 003d4d15215f03278f021dba7efbaa936988f354 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 10 Aug 2016 19:51:18 -0500 Subject: [PATCH 0062/4206] some targets need gcc to be installed --- library/compiler-builtins/ci/install.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index d60571db3d090..e1635301d1eca 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -49,19 +49,19 @@ install_c_toolchain() { ;; mips-unknown-linux-gnu) apt-get install -y --no-install-recommends \ - gcc-mips-linux-gnu libc6-dev-mips-cross + gcc gcc-mips-linux-gnu libc6-dev-mips-cross ;; mipsel-unknown-linux-gnu) apt-get install -y --no-install-recommends \ - gcc-mipsel-linux-gnu libc6-dev-mipsel-cross + gcc gcc-mipsel-linux-gnu libc6-dev-mipsel-cross ;; powerpc64-unknown-linux-gnu) apt-get install -y --no-install-recommends \ - gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross + gcc gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross ;; powerpc64le-unknown-linux-gnu) apt-get install -y --no-install-recommends \ - gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross + gcc gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross ;; esac } From 2aaa38504fd3dc9e1a89252e2e797093c825dfda Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 10 Aug 2016 20:00:51 -0500 Subject: [PATCH 0063/4206] and libc6-dev --- library/compiler-builtins/ci/install.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index e1635301d1eca..9c971c67a66e3 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -49,19 +49,19 @@ install_c_toolchain() { ;; mips-unknown-linux-gnu) apt-get install -y --no-install-recommends \ - gcc gcc-mips-linux-gnu libc6-dev-mips-cross + gcc gcc-mips-linux-gnu libc6-dev libc6-dev-mips-cross ;; mipsel-unknown-linux-gnu) apt-get install -y --no-install-recommends \ - gcc gcc-mipsel-linux-gnu libc6-dev-mipsel-cross + gcc gcc-mipsel-linux-gnu libc6-dev libc6-dev-mipsel-cross ;; powerpc64-unknown-linux-gnu) apt-get install -y --no-install-recommends \ - gcc gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross + gcc gcc-powerpc64-linux-gnu libc6-dev libc6-dev-ppc64-cross ;; powerpc64le-unknown-linux-gnu) apt-get install -y --no-install-recommends \ - gcc gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross + gcc gcc-powerpc64le-linux-gnu libc6-dev libc6-dev-ppc64el-cross ;; esac } From 4c93f051952746b8a830a868f2fcd331ae93c35c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 10 Aug 2016 23:40:35 -0500 Subject: [PATCH 0064/4206] port __udivmodsi4, aeabi_uidivmod and udivsi3 also rewrite these last two new aeabi intrinsics as naked functions --- library/compiler-builtins/src/arm.rs | 37 +++++++++++----- library/compiler-builtins/src/lib.rs | 61 +++++++++++++++++++++++++++ library/compiler-builtins/src/test.rs | 13 ++++++ 3 files changed, 100 insertions(+), 11 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 55e9bb9faaa19..bcfc6c86eb579 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,18 +1,33 @@ -use core::mem; +use core::intrinsics; -#[repr(C)] -pub struct u64x2 { - a: u64, - b: u64, +// TODO use `global_asm!` +#[naked] +#[no_mangle] +pub unsafe extern "aapcs" fn __aeabi_uidivmod() { + asm!("push { lr } + sub sp, sp, #4 + mov r2, sp + bl __udivmodsi4 + ldr r1, [sp] + add sp, sp, #4 + pop { pc }"); + intrinsics::unreachable(); } +// TODO use `global_asm!` +#[naked] #[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_uldivmod(num: u64, den: u64) -> u64x2 { - - let mut rem = mem::uninitialized(); - let quot = ::__udivmoddi4(num, den, &mut rem); - - u64x2 { a: quot, b: rem } +pub unsafe extern "aapcs" fn __aeabi_uldivmod() { + asm!("push {r11, lr} + sub sp, sp, #16 + add r12, sp, #8 + str r12, [sp] + bl __udivmoddi4 + ldr r2, [sp, #8] + ldr r3, [sp, #12] + add sp, sp, #16 + pop {r11, pc}"); + intrinsics::unreachable(); } extern "C" { diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index e5caa83dcbf67..2c016a73c41ab 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -352,3 +352,64 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 { } q.u64() } + +#[no_mangle] +pub extern "C" fn __udivmodsi4(a: u32, b: u32, rem: *mut u32) -> u32 { + let d = __udivsi3(a, b); + if let Some(rem) = unsafe {rem.as_mut()} { + *rem = a - (d*b); + } + return d; +} + +#[no_mangle] +pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { + let u32_bits = u32::bits() as u32; + + // Special cases + if d == 0 { + return 0; // ?! + } + + if n == 0 { + return 0; + } + + let mut sr = d.leading_zeros().wrapping_sub(n.leading_zeros()); + + // d > n + if sr > u32_bits - 1 { + return 0; + } + + // d == 1 + if sr == u32_bits - 1 { + return n; + } + + sr = sr + 1; + + // 1 <= sr <= u32_bits - 1 + let mut q = n << (u32_bits - sr); + let mut r = n >> sr; + + let mut carry = 0; + for _ in 0..sr { + // r:q = ((r:q) << 1) | carry + r = (r << 1) | (q >> (u32_bits - 1)); + q = (q << 1) | carry; + + // carry = 0; + // if r > d { + // r -= d; + // carry = 1; + // } + + let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32_bits - 1); + carry = (s & 1) as u32; + r -= d & s as u32; + } + + q = (q << 1) | carry; + q +} diff --git a/library/compiler-builtins/src/test.rs b/library/compiler-builtins/src/test.rs index 8d5a42c9e7995..40e2885fba77a 100644 --- a/library/compiler-builtins/src/test.rs +++ b/library/compiler-builtins/src/test.rs @@ -42,3 +42,16 @@ quickcheck! { } } } + +quickcheck! { + fn udivmodsi4(a: u32, b: u32) -> TestResult { + if b == 0 { + TestResult::discard() + } else { + let mut r = 0; + let q = ::__udivmodsi4(a, b, &mut r); + + TestResult::from_bool(q * b + r == a) + } + } +} From 6d663ebb9ca4e3f5b0e08ba46b3a6f5fb1da783f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 11 Aug 2016 00:31:49 -0500 Subject: [PATCH 0065/4206] *mut T -> Option<&mut T> --- library/compiler-builtins/src/lib.rs | 24 ++++++++++++------------ library/compiler-builtins/src/test.rs | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 2c016a73c41ab..d2dcbdc2ac171 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -100,7 +100,7 @@ absv_i2!(__absvdi2: i64); // absv_i2!(__absvti2, i128); #[no_mangle] -pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 { +pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: Option<&mut u64>) -> u64 { #[cfg(target_endian = "little")] #[repr(C)] #[derive(Debug)] @@ -146,7 +146,7 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 { // --- // 0 X - if let Some(rem) = unsafe { rem.as_mut() } { + if let Some(rem) = rem { *rem = u64::from(n.low % d.low); } u64::from(n.low / d.low) @@ -157,7 +157,7 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 { // --- // K X - if let Some(rem) = unsafe { rem.as_mut() } { + if let Some(rem) = rem { *rem = u64::from(n.low); } 0 @@ -179,7 +179,7 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 { // 0 0 // NOTE copied verbatim from compiler-rt, but does division by zero even make sense? - if let Some(rem) = unsafe { rem.as_mut() } { + if let Some(rem) = rem { *rem = u64::from(n.high % d.low); } return u64::from(n.high / d.low); @@ -191,7 +191,7 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 { // --- // K 0 - if let Some(rem) = unsafe { rem.as_mut() } { + if let Some(rem) = rem { *rem = words { low: 0, high: n.high % d.high, @@ -207,7 +207,7 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 { // K 0 if d.high.is_power_of_two() { - if let Some(rem) = unsafe { rem.as_mut() } { + if let Some(rem) = rem { *rem = words { low: n.low, high: n.high & (d.high - 1), @@ -222,7 +222,7 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 { // D > N if sr > u32_bits - 2 { - if let Some(rem) = unsafe { rem.as_mut() } { + if let Some(rem) = rem { *rem = n.u64(); } return 0; @@ -245,7 +245,7 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 { // --- // 0 K if d.low.is_power_of_two() { - if let Some(rem) = unsafe { rem.as_mut() } { + if let Some(rem) = rem { *rem = u64::from(n.low & (d.low - 1)); } @@ -298,7 +298,7 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 { // D > N if sr > u32_bits - 1 { - if let Some(rem) = unsafe { rem.as_mut() } { + if let Some(rem) = rem { *rem = a; return 0; } @@ -347,16 +347,16 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 { } *q.all() = (q.u64() << 1) | carry as u64; - if let Some(rem) = unsafe { rem.as_mut() } { + if let Some(rem) = rem { *rem = r.u64(); } q.u64() } #[no_mangle] -pub extern "C" fn __udivmodsi4(a: u32, b: u32, rem: *mut u32) -> u32 { +pub extern "C" fn __udivmodsi4(a: u32, b: u32, rem: Option<&mut u32>) -> u32 { let d = __udivsi3(a, b); - if let Some(rem) = unsafe {rem.as_mut()} { + if let Some(rem) = rem { *rem = a - (d*b); } return d; diff --git a/library/compiler-builtins/src/test.rs b/library/compiler-builtins/src/test.rs index 40e2885fba77a..62cf59ce5a0a3 100644 --- a/library/compiler-builtins/src/test.rs +++ b/library/compiler-builtins/src/test.rs @@ -36,7 +36,7 @@ quickcheck! { TestResult::discard() } else { let mut r = 0; - let q = ::__udivmoddi4(a, b, &mut r); + let q = ::__udivmoddi4(a, b, Some(&mut r)); TestResult::from_bool(q * b + r == a) } @@ -49,7 +49,7 @@ quickcheck! { TestResult::discard() } else { let mut r = 0; - let q = ::__udivmodsi4(a, b, &mut r); + let q = ::__udivmodsi4(a, b, Some(&mut r)); TestResult::from_bool(q * b + r == a) } From 6be47a352480d34266926b7c32c470f2721d3107 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 11 Aug 2016 00:33:27 -0500 Subject: [PATCH 0066/4206] move return into if branches --- library/compiler-builtins/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index d2dcbdc2ac171..581189f3e38af 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -141,7 +141,7 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: Option<&mut u64>) -> u64 { // NOTE X is unknown, K != 0 if n.high == 0 { - return if d.high == 0 { + if d.high == 0 { // 0 X // --- // 0 X @@ -149,7 +149,7 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: Option<&mut u64>) -> u64 { if let Some(rem) = rem { *rem = u64::from(n.low % d.low); } - u64::from(n.low / d.low) + return u64::from(n.low / d.low); } else // d.high != 0 { @@ -160,7 +160,7 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: Option<&mut u64>) -> u64 { if let Some(rem) = rem { *rem = u64::from(n.low); } - 0 + return 0; }; } From d66ff75198290c3a7318f881ab342dfb82b74292 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 11 Aug 2016 00:36:19 -0500 Subject: [PATCH 0067/4206] note about calling convention --- library/compiler-builtins/src/arm.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index bcfc6c86eb579..51206eda47e13 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,5 +1,7 @@ use core::intrinsics; +// NOTE This function and the one below are implemented using assembly because they using a custom +// calling convention which can't be implemented using a normal Rust function // TODO use `global_asm!` #[naked] #[no_mangle] From 24344f1dcae9a7fcd2db9dce323993786e0544f3 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 11 Aug 2016 01:15:51 -0500 Subject: [PATCH 0068/4206] refactor: use Int traits, words -> U64, fmt --- library/compiler-builtins/src/lib.rs | 220 +++++++++++++-------------- 1 file changed, 109 insertions(+), 111 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 581189f3e38af..527f4442446d1 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -18,8 +18,6 @@ pub mod arm; #[cfg(test)] mod test; -use core::mem; - /// Trait for some basic operations on integers trait Int { fn bits() -> usize; @@ -27,16 +25,24 @@ trait Int { // TODO: Once i128/u128 support lands, we'll want to add impls for those as well impl Int for u32 { - fn bits() -> usize { 32 } + fn bits() -> usize { + 32 + } } impl Int for i32 { - fn bits() -> usize { 32 } + fn bits() -> usize { + 32 + } } impl Int for u64 { - fn bits() -> usize { 64 } + fn bits() -> usize { + 64 + } } impl Int for i64 { - fn bits() -> usize { 64 } + fn bits() -> usize { + 64 + } } /// Trait to convert an integer to/from smaller parts @@ -99,131 +105,124 @@ absv_i2!(__absvdi2: i64); // TODO(rust-lang/35118)? // absv_i2!(__absvti2, i128); +/// Return `n / d` and `*rem = n % d` #[no_mangle] -pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: Option<&mut u64>) -> u64 { +pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { + use core::ops::{Index, IndexMut, RangeFull}; + #[cfg(target_endian = "little")] #[repr(C)] - #[derive(Debug)] - struct words { + struct U64 { low: u32, high: u32, } #[cfg(target_endian = "big")] #[repr(C)] - #[derive(Debug)] - struct words { + struct U64 { high: u32, low: u32, } - impl words { - fn all(&mut self) -> &mut u64 { - unsafe { mem::transmute(self) } - } + impl Index for U64 { + type Output = u64; - fn u64(&self) -> u64 { - unsafe { *(self as *const _ as *const u64) } + fn index(&self, _: RangeFull) -> &u64 { + unsafe { &*(self as *const _ as *const u64) } } } - impl From for words { - fn from(x: u64) -> words { - unsafe { mem::transmute(x) } + impl IndexMut for U64 { + fn index_mut(&mut self, _: RangeFull) -> &mut u64 { + unsafe { &mut *(self as *const _ as *mut u64) } } } let u32_bits = u32::bits() as u32; let u64_bits = u64::bits() as u32; - let n = words::from(a); - let d = words::from(b); - // NOTE X is unknown, K != 0 - if n.high == 0 { - if d.high == 0 { + if n.high() == 0 { + if d.high() == 0 { // 0 X // --- // 0 X if let Some(rem) = rem { - *rem = u64::from(n.low % d.low); + *rem = u64::from(n.low() % d.low()); } - return u64::from(n.low / d.low); + return u64::from(n.low() / d.low()); } else - // d.high != 0 - { + // d.high() != 0 + { // 0 X // --- // K X if let Some(rem) = rem { - *rem = u64::from(n.low); + *rem = u64::from(n.low()); } return 0; }; } let mut sr; - // NOTE IMO it should be possible to leave these "uninitialized" (just declare them here) - // because these variables get initialized below, but if I do that the compiler complains about - // them being used before being initialized. - let mut q = words { low: 0, high: 0 }; - let mut r = words { low: 0, high: 0 }; - - // n.high != 0 - if d.low == 0 { - if d.high == 0 { + let mut q = U64 { low: 0, high: 0 }; + let mut r = U64 { low: 0, high: 0 }; + + // n.high() != 0 + if d.low() == 0 { + if d.high() == 0 { // K X // --- // 0 0 - // NOTE copied verbatim from compiler-rt, but does division by zero even make sense? + // NOTE copied verbatim from compiler-rt. This probably lets the intrinsic decide how to + // handle the division by zero (SIGFPE, 0, etc.). But this part shouldn't be reachable + // from safe code. if let Some(rem) = rem { - *rem = u64::from(n.high % d.low); + *rem = u64::from(n.high() % d.low()); } - return u64::from(n.high / d.low); + return u64::from(n.high() / d.low()); } - // d.high != 0 - if n.low == 0 { + // d.high() != 0 + if n.low() == 0 { // K 0 // --- // K 0 if let Some(rem) = rem { - *rem = words { - low: 0, - high: n.high % d.high, - } - .u64(); + *rem = U64 { + low: 0, + high: n.high() % d.high(), + }[..]; } - return u64::from(n.high / d.high); + return u64::from(n.high() / d.high()); } - // n.low != 0 + // n.low() != 0 // K K // --- // K 0 - if d.high.is_power_of_two() { + if d.high().is_power_of_two() { if let Some(rem) = rem { - *rem = words { - low: n.low, - high: n.high & (d.high - 1), - } - .u64() + *rem = U64 { + low: n.low(), + high: n.high() & (d.high() - 1), + }[..]; } - return u64::from(n.high >> d.high.trailing_zeros()); + return u64::from(n.high() >> d.high().trailing_zeros()); } - sr = d.high.leading_zeros().wrapping_sub(n.high.leading_zeros()); + sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); // D > N if sr > u32_bits - 2 { if let Some(rem) = rem { - *rem = n.u64(); + *rem = n; } return 0; } @@ -231,75 +230,74 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: Option<&mut u64>) -> u64 { sr = sr + 1; // 1 <= sr <= u32_bits - 1 - // *q.all() = n.u64() << (u64_bits - sr); + // q = n << (u64_bits - sr); q.low = 0; - q.high = n.low << (u32_bits - sr); - // *r.all() = n.u64() >> sr - r.high = n.high >> sr; - r.low = (n.high << (u32_bits - sr)) | (n.low >> sr); + q.high = n.low() << (u32_bits - sr); + // r = n >> sr + r.high = n.high() >> sr; + r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr); } else - // d.low != 0 + // d.low() != 0 { - if d.high == 0 { + if d.high() == 0 { // K X // --- // 0 K - if d.low.is_power_of_two() { + if d.low().is_power_of_two() { if let Some(rem) = rem { - *rem = u64::from(n.low & (d.low - 1)); + *rem = u64::from(n.low() & (d.low() - 1)); } - return if d.low == 1 { - n.u64() + if d.low() == 1 { + return n; } else { - let sr = d.low.trailing_zeros(); - words { - low: (n.high << (u32_bits - sr)) | (n.low >> sr), - high: n.high >> sr, - } - .u64() + let sr = d.low().trailing_zeros(); + return U64 { + low: (n.high() << (u32_bits - sr)) | (n.low() >> sr), + high: n.high() >> sr, + }[..]; }; } - sr = 1 + u32_bits + d.low.leading_zeros() - n.high.leading_zeros(); + sr = 1 + u32_bits + d.low().leading_zeros() - n.high().leading_zeros(); // 2 <= sr <= u64_bits - 1 - // *q.all() = n.u64() << (u64_bits - sr) - // *r.all() = n.u64() >> sr; + // q = n << (u64_bits - sr) + // r = n >> sr; if sr == u32_bits { q.low = 0; - q.high = n.low; + q.high = n.low(); r.high = 0; - r.low = n.high; + r.low = n.high(); } else if sr < u32_bits // 2 <= sr <= u32_bits - 1 { q.low = 0; - q.high = n.low << (u32_bits - sr); - r.high = n.high >> sr; - r.low = (n.high << (u32_bits - sr)) | (n.low >> sr); + q.high = n.low() << (u32_bits - sr); + r.high = n.high() >> sr; + r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr); } else // u32_bits + 1 <= sr <= u64_bits - 1 { - q.low = n.low << (u64_bits - sr); - q.high = (n.high << (u64_bits - sr)) | (n.low >> (sr - u32_bits)); + q.low = n.low() << (u64_bits - sr); + q.high = (n.high() << (u64_bits - sr)) | (n.low() >> (sr - u32_bits)); r.high = 0; - r.low = n.high >> (sr - u32_bits); + r.low = n.high() >> (sr - u32_bits); } } else - // d.high != 0 + // d.high() != 0 { // K X // --- // K K - sr = d.high.leading_zeros().wrapping_sub(n.high.leading_zeros()); + sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); // D > N if sr > u32_bits - 1 { if let Some(rem) = rem { - *rem = a; + *rem = n; return 0; } } @@ -307,61 +305,61 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: Option<&mut u64>) -> u64 { sr += 1; // 1 <= sr <= u32_bits - // *q.all() = n.u64() << (u64_bits - sr) + // q = n << (u64_bits - sr) q.low = 0; if sr == u32_bits { - q.high = n.low; + q.high = n.low(); r.high = 0; - r.low = n.high; + r.low = n.high(); } else { - q.high = n.low << (u32_bits - sr); - r.high = n.high >> sr; - r.low = (n.high << (u32_bits - sr)) | (n.low >> sr); + q.high = n.low() << (u32_bits - sr); + r.high = n.high() >> sr; + r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr); } } } // Not a special case // q and r are initialized with - // *q.all() = n.u64() << (u64_bits - sr) - // *.r.all() = n.u64() >> sr + // q = n << (u64_bits - sr) + // r = n >> sr // 1 <= sr <= u64_bits - 1 let mut carry = 0; for _ in 0..sr { // r:q = ((r:q) << 1) | carry - r.high = (r.high << 1) | (r.low >> (u32_bits - 1)); - r.low = (r.low << 1) | (q.high >> (u32_bits - 1)); - q.high = (q.high << 1) | (q.low >> (u32_bits - 1)); - q.low = (q.low << 1) | carry; + r[..] = (r[..] << 1) | (q[..] >> 63); + q[..] = (q[..] << 1) | carry as u64; // carry = 0 - // if r.u64() >= d.u64() { - // *r.all() -= d.u64(); + // if r >= d { + // r -= d; // carry = 1; // } - let s = (d.u64().wrapping_sub(r.u64()).wrapping_sub(1)) as i64 >> (u64_bits - 1); + let s = (d.wrapping_sub(r[..]).wrapping_sub(1)) as i64 >> (u64_bits - 1); carry = (s & 1) as u32; - *r.all() -= d.u64() & s as u64; + r[..] -= d & s as u64; } - *q.all() = (q.u64() << 1) | carry as u64; + q[..] = (q[..] << 1) | carry as u64; if let Some(rem) = rem { - *rem = r.u64(); + *rem = r[..]; } - q.u64() + q[..] } +/// Return `n / d` and `*rem = n % d` #[no_mangle] pub extern "C" fn __udivmodsi4(a: u32, b: u32, rem: Option<&mut u32>) -> u32 { let d = __udivsi3(a, b); if let Some(rem) = rem { - *rem = a - (d*b); + *rem = a - (d * b); } return d; } +/// Return `n / d` #[no_mangle] pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { let u32_bits = u32::bits() as u32; From bcd525fe6181f4ad1f925a4952be24acf69d0424 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 11 Aug 2016 01:26:27 -0500 Subject: [PATCH 0069/4206] put div intrinsics in their own module + some docs --- library/compiler-builtins/src/div.rs | 278 +++++++++++++++++++++ library/compiler-builtins/src/lib.rs | 341 +++----------------------- library/compiler-builtins/src/test.rs | 4 +- 3 files changed, 314 insertions(+), 309 deletions(-) create mode 100644 library/compiler-builtins/src/div.rs diff --git a/library/compiler-builtins/src/div.rs b/library/compiler-builtins/src/div.rs new file mode 100644 index 0000000000000..cb6568e9de109 --- /dev/null +++ b/library/compiler-builtins/src/div.rs @@ -0,0 +1,278 @@ +use {Int, LargeInt, U64}; + +/// Returns `n / d` +#[no_mangle] +pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { + let u32_bits = u32::bits() as u32; + + // Special cases + if d == 0 { + return 0; // ?! + } + + if n == 0 { + return 0; + } + + let mut sr = d.leading_zeros().wrapping_sub(n.leading_zeros()); + + // d > n + if sr > u32_bits - 1 { + return 0; + } + + // d == 1 + if sr == u32_bits - 1 { + return n; + } + + sr = sr + 1; + + // 1 <= sr <= u32_bits - 1 + let mut q = n << (u32_bits - sr); + let mut r = n >> sr; + + let mut carry = 0; + for _ in 0..sr { + // r:q = ((r:q) << 1) | carry + r = (r << 1) | (q >> (u32_bits - 1)); + q = (q << 1) | carry; + + // carry = 0; + // if r > d { + // r -= d; + // carry = 1; + // } + + let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32_bits - 1); + carry = (s & 1) as u32; + r -= d & s as u32; + } + + q = (q << 1) | carry; + q +} + +/// Returns `n / d` and sets `*rem = n % d` +#[no_mangle] +pub extern "C" fn __udivmodsi4(a: u32, b: u32, rem: Option<&mut u32>) -> u32 { + let d = __udivsi3(a, b); + if let Some(rem) = rem { + *rem = a - (d * b); + } + return d; +} + +/// Returns `n / d` and sets `*rem = n % d` +#[no_mangle] +pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { + let u32_bits = u32::bits() as u32; + let u64_bits = u64::bits() as u32; + + // NOTE X is unknown, K != 0 + if n.high() == 0 { + if d.high() == 0 { + // 0 X + // --- + // 0 X + + if let Some(rem) = rem { + *rem = u64::from(n.low() % d.low()); + } + return u64::from(n.low() / d.low()); + } else + // d.high() != 0 + { + // 0 X + // --- + // K X + + if let Some(rem) = rem { + *rem = u64::from(n.low()); + } + return 0; + }; + } + + let mut sr; + let mut q = U64 { low: 0, high: 0 }; + let mut r = U64 { low: 0, high: 0 }; + + // n.high() != 0 + if d.low() == 0 { + if d.high() == 0 { + // K X + // --- + // 0 0 + + // NOTE copied verbatim from compiler-rt. This probably lets the intrinsic decide how to + // handle the division by zero (SIGFPE, 0, etc.). But this part shouldn't be reachable + // from safe code. + if let Some(rem) = rem { + *rem = u64::from(n.high() % d.low()); + } + return u64::from(n.high() / d.low()); + } + + // d.high() != 0 + if n.low() == 0 { + // K 0 + // --- + // K 0 + + if let Some(rem) = rem { + *rem = U64 { + low: 0, + high: n.high() % d.high(), + }[..]; + } + return u64::from(n.high() / d.high()); + } + + // n.low() != 0 + // K K + // --- + // K 0 + + if d.high().is_power_of_two() { + if let Some(rem) = rem { + *rem = U64 { + low: n.low(), + high: n.high() & (d.high() - 1), + }[..]; + } + + return u64::from(n.high() >> d.high().trailing_zeros()); + } + + sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); + + // D > N + if sr > u32_bits - 2 { + if let Some(rem) = rem { + *rem = n; + } + return 0; + } + + sr = sr + 1; + + // 1 <= sr <= u32_bits - 1 + // q = n << (u64_bits - sr); + q.low = 0; + q.high = n.low() << (u32_bits - sr); + // r = n >> sr + r.high = n.high() >> sr; + r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr); + } else + // d.low() != 0 + { + if d.high() == 0 { + // K X + // --- + // 0 K + if d.low().is_power_of_two() { + if let Some(rem) = rem { + *rem = u64::from(n.low() & (d.low() - 1)); + } + + if d.low() == 1 { + return n; + } else { + let sr = d.low().trailing_zeros(); + return U64 { + low: (n.high() << (u32_bits - sr)) | (n.low() >> sr), + high: n.high() >> sr, + }[..]; + }; + } + + sr = 1 + u32_bits + d.low().leading_zeros() - n.high().leading_zeros(); + + // 2 <= sr <= u64_bits - 1 + // q = n << (u64_bits - sr) + // r = n >> sr; + if sr == u32_bits { + q.low = 0; + q.high = n.low(); + r.high = 0; + r.low = n.high(); + } else if sr < u32_bits + // 2 <= sr <= u32_bits - 1 + { + q.low = 0; + q.high = n.low() << (u32_bits - sr); + r.high = n.high() >> sr; + r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr); + } else + // u32_bits + 1 <= sr <= u64_bits - 1 + { + q.low = n.low() << (u64_bits - sr); + q.high = (n.high() << (u64_bits - sr)) | (n.low() >> (sr - u32_bits)); + r.high = 0; + r.low = n.high() >> (sr - u32_bits); + } + + } else + // d.high() != 0 + { + // K X + // --- + // K K + + sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); + + // D > N + if sr > u32_bits - 1 { + if let Some(rem) = rem { + *rem = n; + return 0; + } + } + + sr += 1; + + // 1 <= sr <= u32_bits + // q = n << (u64_bits - sr) + q.low = 0; + if sr == u32_bits { + q.high = n.low(); + r.high = 0; + r.low = n.high(); + } else { + q.high = n.low() << (u32_bits - sr); + r.high = n.high() >> sr; + r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr); + } + } + } + + // Not a special case + // q and r are initialized with + // q = n << (u64_bits - sr) + // r = n >> sr + // 1 <= sr <= u64_bits - 1 + let mut carry = 0; + + for _ in 0..sr { + // r:q = ((r:q) << 1) | carry + r[..] = (r[..] << 1) | (q[..] >> 63); + q[..] = (q[..] << 1) | carry as u64; + + // carry = 0 + // if r >= d { + // r -= d; + // carry = 1; + // } + + let s = (d.wrapping_sub(r[..]).wrapping_sub(1)) as i64 >> (u64_bits - 1); + carry = (s & 1) as u32; + r[..] -= d & s as u64; + } + + q[..] = (q[..] << 1) | carry as u64; + if let Some(rem) = rem { + *rem = r[..]; + } + q[..] +} diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 527f4442446d1..3a24025b67c48 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -15,9 +15,13 @@ extern crate quickcheck; #[cfg(target_arch = "arm")] pub mod arm; +pub mod div; + #[cfg(test)] mod test; +use core::ops::{Index, IndexMut, RangeFull}; + /// Trait for some basic operations on integers trait Int { fn bits() -> usize; @@ -85,6 +89,36 @@ impl LargeInt for i64 { } } +/// Union-like access to the 32-bit words that make an `u64`: `x.low` and `x.high`. The whole `u64` +/// can be accessed via the expression `x[..]`, which can be used in lvalue or rvalue position. +#[cfg(target_endian = "little")] +#[repr(C)] +struct U64 { + low: u32, + high: u32, +} + +#[cfg(target_endian = "big")] +#[repr(C)] +struct U64 { + high: u32, + low: u32, +} + +impl Index for U64 { + type Output = u64; + + fn index(&self, _: RangeFull) -> &u64 { + unsafe { &*(self as *const _ as *const u64) } + } +} + +impl IndexMut for U64 { + fn index_mut(&mut self, _: RangeFull) -> &mut u64 { + unsafe { &mut *(self as *const _ as *mut u64) } + } +} + macro_rules! absv_i2 { ($intrinsic:ident : $ty:ty) => { #[no_mangle] @@ -104,310 +138,3 @@ absv_i2!(__absvsi2: i32); absv_i2!(__absvdi2: i64); // TODO(rust-lang/35118)? // absv_i2!(__absvti2, i128); - -/// Return `n / d` and `*rem = n % d` -#[no_mangle] -pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { - use core::ops::{Index, IndexMut, RangeFull}; - - #[cfg(target_endian = "little")] - #[repr(C)] - struct U64 { - low: u32, - high: u32, - } - - #[cfg(target_endian = "big")] - #[repr(C)] - struct U64 { - high: u32, - low: u32, - } - - impl Index for U64 { - type Output = u64; - - fn index(&self, _: RangeFull) -> &u64 { - unsafe { &*(self as *const _ as *const u64) } - } - } - - impl IndexMut for U64 { - fn index_mut(&mut self, _: RangeFull) -> &mut u64 { - unsafe { &mut *(self as *const _ as *mut u64) } - } - } - - let u32_bits = u32::bits() as u32; - let u64_bits = u64::bits() as u32; - - // NOTE X is unknown, K != 0 - if n.high() == 0 { - if d.high() == 0 { - // 0 X - // --- - // 0 X - - if let Some(rem) = rem { - *rem = u64::from(n.low() % d.low()); - } - return u64::from(n.low() / d.low()); - } else - // d.high() != 0 - { - // 0 X - // --- - // K X - - if let Some(rem) = rem { - *rem = u64::from(n.low()); - } - return 0; - }; - } - - let mut sr; - let mut q = U64 { low: 0, high: 0 }; - let mut r = U64 { low: 0, high: 0 }; - - // n.high() != 0 - if d.low() == 0 { - if d.high() == 0 { - // K X - // --- - // 0 0 - - // NOTE copied verbatim from compiler-rt. This probably lets the intrinsic decide how to - // handle the division by zero (SIGFPE, 0, etc.). But this part shouldn't be reachable - // from safe code. - if let Some(rem) = rem { - *rem = u64::from(n.high() % d.low()); - } - return u64::from(n.high() / d.low()); - } - - // d.high() != 0 - if n.low() == 0 { - // K 0 - // --- - // K 0 - - if let Some(rem) = rem { - *rem = U64 { - low: 0, - high: n.high() % d.high(), - }[..]; - } - return u64::from(n.high() / d.high()); - } - - // n.low() != 0 - // K K - // --- - // K 0 - - if d.high().is_power_of_two() { - if let Some(rem) = rem { - *rem = U64 { - low: n.low(), - high: n.high() & (d.high() - 1), - }[..]; - } - - return u64::from(n.high() >> d.high().trailing_zeros()); - } - - sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); - - // D > N - if sr > u32_bits - 2 { - if let Some(rem) = rem { - *rem = n; - } - return 0; - } - - sr = sr + 1; - - // 1 <= sr <= u32_bits - 1 - // q = n << (u64_bits - sr); - q.low = 0; - q.high = n.low() << (u32_bits - sr); - // r = n >> sr - r.high = n.high() >> sr; - r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr); - } else - // d.low() != 0 - { - if d.high() == 0 { - // K X - // --- - // 0 K - if d.low().is_power_of_two() { - if let Some(rem) = rem { - *rem = u64::from(n.low() & (d.low() - 1)); - } - - if d.low() == 1 { - return n; - } else { - let sr = d.low().trailing_zeros(); - return U64 { - low: (n.high() << (u32_bits - sr)) | (n.low() >> sr), - high: n.high() >> sr, - }[..]; - }; - } - - sr = 1 + u32_bits + d.low().leading_zeros() - n.high().leading_zeros(); - - // 2 <= sr <= u64_bits - 1 - // q = n << (u64_bits - sr) - // r = n >> sr; - if sr == u32_bits { - q.low = 0; - q.high = n.low(); - r.high = 0; - r.low = n.high(); - } else if sr < u32_bits - // 2 <= sr <= u32_bits - 1 - { - q.low = 0; - q.high = n.low() << (u32_bits - sr); - r.high = n.high() >> sr; - r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr); - } else - // u32_bits + 1 <= sr <= u64_bits - 1 - { - q.low = n.low() << (u64_bits - sr); - q.high = (n.high() << (u64_bits - sr)) | (n.low() >> (sr - u32_bits)); - r.high = 0; - r.low = n.high() >> (sr - u32_bits); - } - - } else - // d.high() != 0 - { - // K X - // --- - // K K - - sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); - - // D > N - if sr > u32_bits - 1 { - if let Some(rem) = rem { - *rem = n; - return 0; - } - } - - sr += 1; - - // 1 <= sr <= u32_bits - // q = n << (u64_bits - sr) - q.low = 0; - if sr == u32_bits { - q.high = n.low(); - r.high = 0; - r.low = n.high(); - } else { - q.high = n.low() << (u32_bits - sr); - r.high = n.high() >> sr; - r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr); - } - } - } - - // Not a special case - // q and r are initialized with - // q = n << (u64_bits - sr) - // r = n >> sr - // 1 <= sr <= u64_bits - 1 - let mut carry = 0; - - for _ in 0..sr { - // r:q = ((r:q) << 1) | carry - r[..] = (r[..] << 1) | (q[..] >> 63); - q[..] = (q[..] << 1) | carry as u64; - - // carry = 0 - // if r >= d { - // r -= d; - // carry = 1; - // } - - let s = (d.wrapping_sub(r[..]).wrapping_sub(1)) as i64 >> (u64_bits - 1); - carry = (s & 1) as u32; - r[..] -= d & s as u64; - } - - q[..] = (q[..] << 1) | carry as u64; - if let Some(rem) = rem { - *rem = r[..]; - } - q[..] -} - -/// Return `n / d` and `*rem = n % d` -#[no_mangle] -pub extern "C" fn __udivmodsi4(a: u32, b: u32, rem: Option<&mut u32>) -> u32 { - let d = __udivsi3(a, b); - if let Some(rem) = rem { - *rem = a - (d * b); - } - return d; -} - -/// Return `n / d` -#[no_mangle] -pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { - let u32_bits = u32::bits() as u32; - - // Special cases - if d == 0 { - return 0; // ?! - } - - if n == 0 { - return 0; - } - - let mut sr = d.leading_zeros().wrapping_sub(n.leading_zeros()); - - // d > n - if sr > u32_bits - 1 { - return 0; - } - - // d == 1 - if sr == u32_bits - 1 { - return n; - } - - sr = sr + 1; - - // 1 <= sr <= u32_bits - 1 - let mut q = n << (u32_bits - sr); - let mut r = n >> sr; - - let mut carry = 0; - for _ in 0..sr { - // r:q = ((r:q) << 1) | carry - r = (r << 1) | (q >> (u32_bits - 1)); - q = (q << 1) | carry; - - // carry = 0; - // if r > d { - // r -= d; - // carry = 1; - // } - - let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32_bits - 1); - carry = (s & 1) as u32; - r -= d & s as u32; - } - - q = (q << 1) | carry; - q -} diff --git a/library/compiler-builtins/src/test.rs b/library/compiler-builtins/src/test.rs index 62cf59ce5a0a3..f1fa4f331ff0f 100644 --- a/library/compiler-builtins/src/test.rs +++ b/library/compiler-builtins/src/test.rs @@ -36,7 +36,7 @@ quickcheck! { TestResult::discard() } else { let mut r = 0; - let q = ::__udivmoddi4(a, b, Some(&mut r)); + let q = ::div::__udivmoddi4(a, b, Some(&mut r)); TestResult::from_bool(q * b + r == a) } @@ -49,7 +49,7 @@ quickcheck! { TestResult::discard() } else { let mut r = 0; - let q = ::__udivmodsi4(a, b, Some(&mut r)); + let q = ::div::__udivmodsi4(a, b, Some(&mut r)); TestResult::from_bool(q * b + r == a) } From 01a8a996b5c477466657ba0ac1bc6ae07eaaca4d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 11 Aug 2016 01:42:34 -0500 Subject: [PATCH 0070/4206] don't transmute in test --- library/compiler-builtins/src/test.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/src/test.rs b/library/compiler-builtins/src/test.rs index f1fa4f331ff0f..fa8691c8f6830 100644 --- a/library/compiler-builtins/src/test.rs +++ b/library/compiler-builtins/src/test.rs @@ -1,4 +1,4 @@ -use std::{mem, panic}; +use std::panic; use quickcheck::TestResult; @@ -27,31 +27,30 @@ absv_i2!(__absvdi2: i64); // absv_i2!(__absvti2: i128); quickcheck! { - fn udivmoddi4(a: (u32, u32), b: (u32, u32)) -> TestResult { - let (a, b) = unsafe { - (mem::transmute(a), mem::transmute(b)) - }; + fn udivmoddi4(n: (u32, u32), d: (u32, u32)) -> TestResult { + let n = ::U64 { low: n.0, high: n.1 }[..]; + let d = ::U64 { low: d.0, high: d.1 }[..]; - if b == 0 { + if d == 0 { TestResult::discard() } else { let mut r = 0; - let q = ::div::__udivmoddi4(a, b, Some(&mut r)); + let q = ::div::__udivmoddi4(n, d, Some(&mut r)); - TestResult::from_bool(q * b + r == a) + TestResult::from_bool(q * d + r == n) } } } quickcheck! { - fn udivmodsi4(a: u32, b: u32) -> TestResult { - if b == 0 { + fn udivmodsi4(n: u32, d: u32) -> TestResult { + if d == 0 { TestResult::discard() } else { let mut r = 0; - let q = ::div::__udivmodsi4(a, b, Some(&mut r)); + let q = ::div::__udivmodsi4(n, d, Some(&mut r)); - TestResult::from_bool(q * b + r == a) + TestResult::from_bool(q * d + r == n) } } } From 57a3f411dded66bdccfcc9190713167a33f79f80 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 11 Aug 2016 01:45:48 -0500 Subject: [PATCH 0071/4206] address second row of review --- library/compiler-builtins/src/div.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/library/compiler-builtins/src/div.rs b/library/compiler-builtins/src/div.rs index cb6568e9de109..44d59b70cf916 100644 --- a/library/compiler-builtins/src/div.rs +++ b/library/compiler-builtins/src/div.rs @@ -7,7 +7,7 @@ pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { // Special cases if d == 0 { - return 0; // ?! + panic!("Division by zero"); } if n == 0 { @@ -49,8 +49,7 @@ pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { r -= d & s as u32; } - q = (q << 1) | carry; - q + (q << 1) | carry } /// Returns `n / d` and sets `*rem = n % d` @@ -105,13 +104,7 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { // --- // 0 0 - // NOTE copied verbatim from compiler-rt. This probably lets the intrinsic decide how to - // handle the division by zero (SIGFPE, 0, etc.). But this part shouldn't be reachable - // from safe code. - if let Some(rem) = rem { - *rem = u64::from(n.high() % d.low()); - } - return u64::from(n.high() / d.low()); + panic!("Division by zero"); } // d.high() != 0 From 25b25d5e8e044e89fcb661ce445e4292873865b5 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 11 Aug 2016 01:52:48 -0500 Subject: [PATCH 0072/4206] appveyor: inspect binaries --- library/compiler-builtins/appveyor.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index d27883dc90157..06255fa1d4318 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -17,6 +17,8 @@ test_script: - cargo build --release - cargo test - cargo test --release + - dumpbin /disasm target/debug/librustc_builtins.rlib + - dumpbin /disasm target/release/librustc_builtins.rlib branches: only: From f22f7cdd865c6f046c66a466eec438548dc4bb52 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 11 Aug 2016 02:12:01 -0500 Subject: [PATCH 0073/4206] README: cross out a few intrinsics for the TODO list --- library/compiler-builtins/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index c68882985aa77..32f85cdb206ef 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -32,8 +32,8 @@ See [rust-lang/rust#35437][0]. - [ ] arm/addsf3vfp.S - [ ] arm/aeabi_dcmp.S - [ ] arm/aeabi_fcmp.S -- [ ] arm/aeabi_idivmod.S -- [ ] arm/aeabi_ldivmod.S +- [x] arm/aeabi_idivmod.S +- [x] arm/aeabi_ldivmod.S - [x] arm/aeabi_memcpy.S - [x] arm/aeabi_memmove.S - [x] arm/aeabi_memset.S @@ -143,6 +143,8 @@ See [rust-lang/rust#35437][0]. - [ ] truncdfsf2.c - [ ] truncsfhf2.c - [ ] udivdi3.c +- [x] udivmoddi4.c +- [x] udivmodsi4.c - [ ] udivsi3.c - [ ] udivti3.c - [ ] umoddi3.c @@ -272,8 +274,6 @@ These builtins are never called by LLVM. - ~~subvti3.c~~ - ~~ucmpdi2.c~~ - ~~ucmpti2.c~~ -- ~~udivmoddi4.c~~ -- ~~udivmodsi4.c~~ - ~~udivmodti4.c~~ Rust only exposes atomic types on platforms that support them, and therefore does not need to fall back to software implementations. From 07afa89f10205ea0db16a1752936ba1488b70eca Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 11 Aug 2016 08:18:06 +0100 Subject: [PATCH 0074/4206] Remove the absv implementation, it isn't needed by Rust --- library/compiler-builtins/src/lib.rs | 20 -------------------- library/compiler-builtins/src/test.rs | 24 ------------------------ 2 files changed, 44 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 3a24025b67c48..196f37c338fcc 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -118,23 +118,3 @@ impl IndexMut for U64 { unsafe { &mut *(self as *const _ as *mut u64) } } } - -macro_rules! absv_i2 { - ($intrinsic:ident : $ty:ty) => { - #[no_mangle] - pub extern "C" fn $intrinsic(x: $ty) -> $ty { - let n = <$ty>::bits(); - if x == 1 << (n - 1) { - panic!(); - } - let y = x >> (n - 1); - (x ^ y) - y - } - - } -} - -absv_i2!(__absvsi2: i32); -absv_i2!(__absvdi2: i64); -// TODO(rust-lang/35118)? -// absv_i2!(__absvti2, i128); diff --git a/library/compiler-builtins/src/test.rs b/library/compiler-builtins/src/test.rs index fa8691c8f6830..96e0c12738b8d 100644 --- a/library/compiler-builtins/src/test.rs +++ b/library/compiler-builtins/src/test.rs @@ -2,30 +2,6 @@ use std::panic; use quickcheck::TestResult; -macro_rules! absv_i2 { - ($intrinsic:ident: $ty:ident) => { - #[test] - fn $intrinsic() { - assert!(panic::catch_unwind(|| ::$intrinsic(::std::$ty::MIN)).is_err()); - assert_eq!(::$intrinsic(::std::$ty::MIN + 1), ::std::$ty::MAX); - assert_eq!(::$intrinsic(::std::$ty::MIN + 2), ::std::$ty::MAX - 1); - assert_eq!(::$intrinsic(-1), 1); - assert_eq!(::$intrinsic(-2), 2); - assert_eq!(::$intrinsic(0), 0); - assert_eq!(::$intrinsic(1), 1); - assert_eq!(::$intrinsic(2), 2); - assert_eq!(::$intrinsic(2), 2); - assert_eq!(::$intrinsic(::std::$ty::MAX - 1), ::std::$ty::MAX - 1); - assert_eq!(::$intrinsic(::std::$ty::MAX), ::std::$ty::MAX); - } - } -} - -absv_i2!(__absvsi2: i32); -absv_i2!(__absvdi2: i64); -// TODO(rust-lang/35118)? -// absv_i2!(__absvti2: i128); - quickcheck! { fn udivmoddi4(n: (u32, u32), d: (u32, u32)) -> TestResult { let n = ::U64 { low: n.0, high: n.1 }[..]; From 1a60c3d52f314f2c984d238c993318005eee12a0 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 13 Aug 2016 09:51:54 +0100 Subject: [PATCH 0075/4206] Various changes --- library/compiler-builtins/README.md | 62 +++--- library/compiler-builtins/src/arm.rs | 87 ++++---- library/compiler-builtins/src/div.rs | 271 ----------------------- library/compiler-builtins/src/lib.rs | 56 +---- library/compiler-builtins/src/mul.rs | 99 +++++++++ library/compiler-builtins/src/shift.rs | 93 ++++++++ library/compiler-builtins/src/test.rs | 32 --- library/compiler-builtins/src/udiv.rs | 290 +++++++++++++++++++++++++ 8 files changed, 568 insertions(+), 422 deletions(-) delete mode 100644 library/compiler-builtins/src/div.rs create mode 100644 library/compiler-builtins/src/mul.rs create mode 100644 library/compiler-builtins/src/shift.rs delete mode 100644 library/compiler-builtins/src/test.rs create mode 100644 library/compiler-builtins/src/udiv.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 32f85cdb206ef..73a25e9d7dce9 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -37,8 +37,8 @@ See [rust-lang/rust#35437][0]. - [x] arm/aeabi_memcpy.S - [x] arm/aeabi_memmove.S - [x] arm/aeabi_memset.S -- [ ] arm/aeabi_uidivmod.S -- [ ] arm/aeabi_uldivmod.S +- [x] arm/aeabi_uidivmod.S +- [x] arm/aeabi_uldivmod.S - [ ] arm/divdf3vfp.S - [ ] arm/divmodsi4.S - [ ] arm/divsf3vfp.S @@ -78,41 +78,30 @@ See [rust-lang/rust#35437][0]. - [ ] arm/umodsi3.S - [ ] arm/unorddf2vfp.S - [ ] arm/unordsf2vfp.S -- [ ] ashldi3.c -- [ ] ashlti3.c -- [ ] ashrdi3.c -- [ ] ashrti3.c +- [x] ashldi3.c +- [x] ashrdi3.c - [ ] divdf3.c - [ ] divdi3.c - [ ] divsf3.c - [ ] divsi3.c -- [ ] divti3.c - [ ] extendhfsf2.c - [ ] extendsfdf2.c - [ ] fixdfdi.c - [ ] fixdfsi.c -- [ ] fixdfti.c - [ ] fixsfdi.c - [ ] fixsfsi.c -- [ ] fixsfti.c - [ ] fixunsdfdi.c - [ ] fixunsdfsi.c -- [ ] fixunsdfti.c - [ ] fixunssfdi.c - [ ] fixunssfsi.c -- [ ] fixunssfti.c - [ ] floatdidf.c - [ ] floatdisf.c - [ ] floatsidf.c - [ ] floatsisf.c -- [ ] floattidf.c -- [ ] floattisf.c - [ ] floatundidf.c - [ ] floatundisf.c - [ ] floatunsidf.c - [ ] floatunsisf.c -- [ ] floatuntidf.c -- [ ] floatuntisf.c - [ ] i386/ashldi3.S - [ ] i386/ashrdi3.S - [ ] i386/chkstk.S @@ -123,18 +112,14 @@ See [rust-lang/rust#35437][0]. - [ ] i386/muldi3.S - [ ] i386/udivdi3.S - [ ] i386/umoddi3.S -- [ ] lshrdi3.c -- [ ] lshrti3.c +- [x] lshrdi3.c - [ ] moddi3.c - [ ] modsi3.c -- [ ] modti3.c - [ ] muldf3.c -- [ ] muldi3.c -- [ ] mulodi4.c -- [ ] mulosi4.c -- [ ] muloti4.c +- [x] muldi3.c +- [x] mulodi4.c +- [x] mulosi4.c - [ ] mulsf3.c -- [ ] multi3.c - [ ] powidf2.c - [ ] powisf2.c - [ ] subdf3.c @@ -142,17 +127,36 @@ See [rust-lang/rust#35437][0]. - [ ] truncdfhf2.c - [ ] truncdfsf2.c - [ ] truncsfhf2.c -- [ ] udivdi3.c +- [x] udivdi3.c - [x] udivmoddi4.c - [x] udivmodsi4.c -- [ ] udivsi3.c -- [ ] udivti3.c -- [ ] umoddi3.c -- [ ] umodsi3.c -- [ ] umodti3.c +- [x] udivsi3.c +- [x] umoddi3.c +- [x] umodsi3.c - [ ] x86_64/chkstk.S - [ ] x86_64/chkstk2.S +These builtins are needed to support 128-bit integers, which are in the process of being added to Rust. + +- [ ] ashlti3.c +- [ ] ashrti3.c +- [ ] divti3.c +- [ ] fixdfti.c +- [ ] fixsfti.c +- [ ] fixunsdfti.c +- [ ] fixunssfti.c +- [ ] floattidf.c +- [ ] floattisf.c +- [ ] floatuntidf.c +- [ ] floatuntisf.c +- [ ] lshrti3.c +- [ ] modti3.c +- [ ] muloti4.c +- [ ] multi3.c +- [ ] udivmodti4.c +- [ ] udivti3.c +- [ ] umodti3.c + ## Unimplemented functions These builtins involve floating-point types ("`f128`", "`f80`" and complex numbers) that are not supported by Rust. diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 51206eda47e13..0759b55d4af3f 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -2,33 +2,28 @@ use core::intrinsics; // NOTE This function and the one below are implemented using assembly because they using a custom // calling convention which can't be implemented using a normal Rust function -// TODO use `global_asm!` #[naked] -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_uidivmod() { - asm!("push { lr } - sub sp, sp, #4 - mov r2, sp - bl __udivmodsi4 - ldr r1, [sp] - add sp, sp, #4 - pop { pc }"); +#[cfg_attr(not(test), no_mangle)] +pub unsafe fn __aeabi_uidivmod() { + asm!("push {lr} + sub sp, sp, #4 + mov r2, sp + bl __udivmodsi4 + ldr r1, [sp], #4 + pop {pc}"); intrinsics::unreachable(); } -// TODO use `global_asm!` #[naked] -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_uldivmod() { - asm!("push {r11, lr} - sub sp, sp, #16 - add r12, sp, #8 - str r12, [sp] - bl __udivmoddi4 - ldr r2, [sp, #8] - ldr r3, [sp, #12] - add sp, sp, #16 - pop {r11, pc}"); +#[cfg_attr(not(test), no_mangle)] +pub unsafe fn __aeabi_uldivmod() { + asm!("push {lr} + sub r12, sp, #12 + str r12, [sp, #-20]! + bl __udivmoddi4 + ldrd r2, r3, [sp, #8] + add sp, sp, #20 + pop {pc}"); intrinsics::unreachable(); } @@ -40,55 +35,55 @@ extern "C" { // FIXME: The `*4` and `*8` variants should be defined as aliases. -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { +#[cfg_attr(not(test), no_mangle)] +pub unsafe extern "C" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { memcpy(dest, src, n); } -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { +#[cfg_attr(not(test), no_mangle)] +pub unsafe extern "C" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { memcpy(dest, src, n); } -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { +#[cfg_attr(not(test), no_mangle)] +pub unsafe extern "C" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { memcpy(dest, src, n); } -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { +#[cfg_attr(not(test), no_mangle)] +pub unsafe extern "C" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { memmove(dest, src, n); } -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { +#[cfg_attr(not(test), no_mangle)] +pub unsafe extern "C" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { memmove(dest, src, n); } -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { +#[cfg_attr(not(test), no_mangle)] +pub unsafe extern "C" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { memmove(dest, src, n); } // Note the different argument order -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { +#[cfg_attr(not(test), no_mangle)] +pub unsafe extern "C" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { memset(dest, c, n); } -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { +#[cfg_attr(not(test), no_mangle)] +pub unsafe extern "C" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { memset(dest, c, n); } -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { +#[cfg_attr(not(test), no_mangle)] +pub unsafe extern "C" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { memset(dest, c, n); } -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { +#[cfg_attr(not(test), no_mangle)] +pub unsafe extern "C" fn __aeabi_memclr(dest: *mut u8, n: usize) { memset(dest, 0, n); } -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { +#[cfg_attr(not(test), no_mangle)] +pub unsafe extern "C" fn __aeabi_memclr4(dest: *mut u8, n: usize) { memset(dest, 0, n); } -#[no_mangle] -pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { +#[cfg_attr(not(test), no_mangle)] +pub unsafe extern "C" fn __aeabi_memclr8(dest: *mut u8, n: usize) { memset(dest, 0, n); } diff --git a/library/compiler-builtins/src/div.rs b/library/compiler-builtins/src/div.rs deleted file mode 100644 index 44d59b70cf916..0000000000000 --- a/library/compiler-builtins/src/div.rs +++ /dev/null @@ -1,271 +0,0 @@ -use {Int, LargeInt, U64}; - -/// Returns `n / d` -#[no_mangle] -pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { - let u32_bits = u32::bits() as u32; - - // Special cases - if d == 0 { - panic!("Division by zero"); - } - - if n == 0 { - return 0; - } - - let mut sr = d.leading_zeros().wrapping_sub(n.leading_zeros()); - - // d > n - if sr > u32_bits - 1 { - return 0; - } - - // d == 1 - if sr == u32_bits - 1 { - return n; - } - - sr = sr + 1; - - // 1 <= sr <= u32_bits - 1 - let mut q = n << (u32_bits - sr); - let mut r = n >> sr; - - let mut carry = 0; - for _ in 0..sr { - // r:q = ((r:q) << 1) | carry - r = (r << 1) | (q >> (u32_bits - 1)); - q = (q << 1) | carry; - - // carry = 0; - // if r > d { - // r -= d; - // carry = 1; - // } - - let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32_bits - 1); - carry = (s & 1) as u32; - r -= d & s as u32; - } - - (q << 1) | carry -} - -/// Returns `n / d` and sets `*rem = n % d` -#[no_mangle] -pub extern "C" fn __udivmodsi4(a: u32, b: u32, rem: Option<&mut u32>) -> u32 { - let d = __udivsi3(a, b); - if let Some(rem) = rem { - *rem = a - (d * b); - } - return d; -} - -/// Returns `n / d` and sets `*rem = n % d` -#[no_mangle] -pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { - let u32_bits = u32::bits() as u32; - let u64_bits = u64::bits() as u32; - - // NOTE X is unknown, K != 0 - if n.high() == 0 { - if d.high() == 0 { - // 0 X - // --- - // 0 X - - if let Some(rem) = rem { - *rem = u64::from(n.low() % d.low()); - } - return u64::from(n.low() / d.low()); - } else - // d.high() != 0 - { - // 0 X - // --- - // K X - - if let Some(rem) = rem { - *rem = u64::from(n.low()); - } - return 0; - }; - } - - let mut sr; - let mut q = U64 { low: 0, high: 0 }; - let mut r = U64 { low: 0, high: 0 }; - - // n.high() != 0 - if d.low() == 0 { - if d.high() == 0 { - // K X - // --- - // 0 0 - - panic!("Division by zero"); - } - - // d.high() != 0 - if n.low() == 0 { - // K 0 - // --- - // K 0 - - if let Some(rem) = rem { - *rem = U64 { - low: 0, - high: n.high() % d.high(), - }[..]; - } - return u64::from(n.high() / d.high()); - } - - // n.low() != 0 - // K K - // --- - // K 0 - - if d.high().is_power_of_two() { - if let Some(rem) = rem { - *rem = U64 { - low: n.low(), - high: n.high() & (d.high() - 1), - }[..]; - } - - return u64::from(n.high() >> d.high().trailing_zeros()); - } - - sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); - - // D > N - if sr > u32_bits - 2 { - if let Some(rem) = rem { - *rem = n; - } - return 0; - } - - sr = sr + 1; - - // 1 <= sr <= u32_bits - 1 - // q = n << (u64_bits - sr); - q.low = 0; - q.high = n.low() << (u32_bits - sr); - // r = n >> sr - r.high = n.high() >> sr; - r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr); - } else - // d.low() != 0 - { - if d.high() == 0 { - // K X - // --- - // 0 K - if d.low().is_power_of_two() { - if let Some(rem) = rem { - *rem = u64::from(n.low() & (d.low() - 1)); - } - - if d.low() == 1 { - return n; - } else { - let sr = d.low().trailing_zeros(); - return U64 { - low: (n.high() << (u32_bits - sr)) | (n.low() >> sr), - high: n.high() >> sr, - }[..]; - }; - } - - sr = 1 + u32_bits + d.low().leading_zeros() - n.high().leading_zeros(); - - // 2 <= sr <= u64_bits - 1 - // q = n << (u64_bits - sr) - // r = n >> sr; - if sr == u32_bits { - q.low = 0; - q.high = n.low(); - r.high = 0; - r.low = n.high(); - } else if sr < u32_bits - // 2 <= sr <= u32_bits - 1 - { - q.low = 0; - q.high = n.low() << (u32_bits - sr); - r.high = n.high() >> sr; - r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr); - } else - // u32_bits + 1 <= sr <= u64_bits - 1 - { - q.low = n.low() << (u64_bits - sr); - q.high = (n.high() << (u64_bits - sr)) | (n.low() >> (sr - u32_bits)); - r.high = 0; - r.low = n.high() >> (sr - u32_bits); - } - - } else - // d.high() != 0 - { - // K X - // --- - // K K - - sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); - - // D > N - if sr > u32_bits - 1 { - if let Some(rem) = rem { - *rem = n; - return 0; - } - } - - sr += 1; - - // 1 <= sr <= u32_bits - // q = n << (u64_bits - sr) - q.low = 0; - if sr == u32_bits { - q.high = n.low(); - r.high = 0; - r.low = n.high(); - } else { - q.high = n.low() << (u32_bits - sr); - r.high = n.high() >> sr; - r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr); - } - } - } - - // Not a special case - // q and r are initialized with - // q = n << (u64_bits - sr) - // r = n >> sr - // 1 <= sr <= u64_bits - 1 - let mut carry = 0; - - for _ in 0..sr { - // r:q = ((r:q) << 1) | carry - r[..] = (r[..] << 1) | (q[..] >> 63); - q[..] = (q[..] << 1) | carry as u64; - - // carry = 0 - // if r >= d { - // r -= d; - // carry = 1; - // } - - let s = (d.wrapping_sub(r[..]).wrapping_sub(1)) as i64 >> (u64_bits - 1); - carry = (s & 1) as u32; - r[..] -= d & s as u64; - } - - q[..] = (q[..] << 1) | carry as u64; - if let Some(rem) = rem { - *rem = r[..]; - } - q[..] -} diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 196f37c338fcc..6d5580b8e1873 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,13 +1,14 @@ #![allow(unused_features)] -#![cfg_attr(not(test), no_std)] +#![no_std] #![feature(asm)] #![feature(core_intrinsics)] #![feature(naked_functions)] // TODO(rust-lang/rust#35021) uncomment when that PR lands // #![feature(rustc_builtins)] -#[cfg(test)] -extern crate core; +// We disable #[no_mangle] for tests so that we can verify the test results +// against the native compiler-rt implementations of the builtins. + #[cfg(test)] #[macro_use] extern crate quickcheck; @@ -15,36 +16,33 @@ extern crate quickcheck; #[cfg(target_arch = "arm")] pub mod arm; -pub mod div; - -#[cfg(test)] -mod test; - -use core::ops::{Index, IndexMut, RangeFull}; +pub mod udiv; +pub mod mul; +pub mod shift; /// Trait for some basic operations on integers trait Int { - fn bits() -> usize; + fn bits() -> u32; } // TODO: Once i128/u128 support lands, we'll want to add impls for those as well impl Int for u32 { - fn bits() -> usize { + fn bits() -> u32 { 32 } } impl Int for i32 { - fn bits() -> usize { + fn bits() -> u32 { 32 } } impl Int for u64 { - fn bits() -> usize { + fn bits() -> u32 { 64 } } impl Int for i64 { - fn bits() -> usize { + fn bits() -> u32 { 64 } } @@ -88,33 +86,3 @@ impl LargeInt for i64 { low as i64 | ((high as i64) << 32) } } - -/// Union-like access to the 32-bit words that make an `u64`: `x.low` and `x.high`. The whole `u64` -/// can be accessed via the expression `x[..]`, which can be used in lvalue or rvalue position. -#[cfg(target_endian = "little")] -#[repr(C)] -struct U64 { - low: u32, - high: u32, -} - -#[cfg(target_endian = "big")] -#[repr(C)] -struct U64 { - high: u32, - low: u32, -} - -impl Index for U64 { - type Output = u64; - - fn index(&self, _: RangeFull) -> &u64 { - unsafe { &*(self as *const _ as *const u64) } - } -} - -impl IndexMut for U64 { - fn index_mut(&mut self, _: RangeFull) -> &mut u64 { - unsafe { &mut *(self as *const _ as *mut u64) } - } -} diff --git a/library/compiler-builtins/src/mul.rs b/library/compiler-builtins/src/mul.rs new file mode 100644 index 0000000000000..a4350b5f7fffa --- /dev/null +++ b/library/compiler-builtins/src/mul.rs @@ -0,0 +1,99 @@ +use {Int, LargeInt}; + +macro_rules! mul { + ($intrinsic:ident: $ty:ty) => { + /// Returns `a * b` + #[cfg_attr(not(test), no_mangle)] + pub extern fn $intrinsic(a: $ty, b: $ty) -> $ty { + let half_bits = <$ty>::bits() / 4; + let lower_mask = !0 >> half_bits; + let mut low = (a.low() & lower_mask) * (b.low() & lower_mask); + let mut t = low >> half_bits; + low &= lower_mask; + t += (a.low() >> half_bits) * (b.low() & lower_mask); + low += (t & lower_mask) << half_bits; + let mut high = t >> half_bits; + t = low >> half_bits; + low &= lower_mask; + t += (b.low() >> half_bits) * (a.low() & lower_mask); + low += (t & lower_mask) << half_bits; + high += t >> half_bits; + high += (a.low() >> half_bits) * (b.low() >> half_bits); + high += a.high().wrapping_mul(b.low()) + a.low().wrapping_mul(b.high()); + <$ty>::from_parts(low, high) + } + } +} + +macro_rules! mulo { + ($intrinsic:ident: $ty:ty) => { + /// Returns `a * b` and sets `*overflow = 1` if `a * b` overflows + #[cfg_attr(not(test), no_mangle)] + pub extern fn $intrinsic(a: $ty, b: $ty, overflow: &mut i32) -> $ty { + *overflow = 0; + let result = a.wrapping_mul(b); + if a == <$ty>::min_value() { + if b != 0 && b != 1 { + *overflow = 1; + } + return result; + } + if b == <$ty>::min_value() { + if a != 0 && a != 1 { + *overflow = 1; + } + return result; + } + + let sa = a >> (<$ty>::bits() - 1); + let abs_a = (a ^ sa) - sa; + let sb = b >> (<$ty>::bits() - 1); + let abs_b = (b ^ sb) - sb; + if abs_a < 2 || abs_b < 2 { + return result; + } + if sa == sb { + if abs_a > <$ty>::max_value() / abs_b { + *overflow = 1; + } + } else { + if abs_a > <$ty>::min_value() / -abs_b { + *overflow = 1; + } + } + result + } + } +} + +mul!(__muldi4: u64); +mulo!(__mulosi4: i32); +mulo!(__mulodi4: i64); + +#[cfg(test)] +mod tests { + quickcheck! { + fn muldi(a: u64, b: u64) -> bool { + let r = super::__muldi4(a, b); + r == a.wrapping_mul(b) + } + + fn mulosi(a: i32, b: i32) -> bool { + let mut overflow = 2; + let r = super::__mulosi4(a, b, &mut overflow); + if overflow != 0 && overflow != 1 { + return false; + } + (r, overflow != 0) == a.overflowing_mul(b) + } + + fn mulodi(a: i64, b: i64) -> bool { + let mut overflow = 2; + let r = super::__mulodi4(a, b, &mut overflow); + if overflow != 0 && overflow != 1 { + return false; + } + (r, overflow != 0) == a.overflowing_mul(b) + } + } +} diff --git a/library/compiler-builtins/src/shift.rs b/library/compiler-builtins/src/shift.rs new file mode 100644 index 0000000000000..909d6f47f5a15 --- /dev/null +++ b/library/compiler-builtins/src/shift.rs @@ -0,0 +1,93 @@ +use {Int, LargeInt}; + +macro_rules! ashl { + ($intrinsic:ident: $ty:ty) => { + /// Returns `a << b`, requires `b < $ty::bits()` + #[cfg_attr(not(test), no_mangle)] + pub extern fn $intrinsic(a: $ty, b: u32) -> $ty { + let half_bits = <$ty>::bits() / 2; + if b & half_bits != 0 { + <$ty>::from_parts(0, a.low() << (b - half_bits)) + } else if b == 0 { + a + } else { + <$ty>::from_parts(a.low() << b, (a.high() << b) | (a.low() >> (half_bits - b))) + } + } + } +} + +macro_rules! ashr { + ($intrinsic:ident: $ty:ty) => { + /// Returns arithmetic `a >> b`, requires `b < $ty::bits()` + #[cfg_attr(not(test), no_mangle)] + pub extern fn $intrinsic(a: $ty, b: u32) -> $ty { + let half_bits = <$ty>::bits() / 2; + if b & half_bits != 0 { + <$ty>::from_parts((a.high() >> (b - half_bits)) as <$ty as LargeInt>::LowHalf, + a.high() >> (half_bits - 1)) + } else if b == 0 { + a + } else { + let high_unsigned = a.high() as <$ty as LargeInt>::LowHalf; + <$ty>::from_parts((high_unsigned << (half_bits - b)) | (a.low() >> b), + a.high() >> b) + } + } + } +} + +macro_rules! lshr { + ($intrinsic:ident: $ty:ty) => { + /// Returns logical `a >> b`, requires `b < $ty::bits()` + #[cfg_attr(not(test), no_mangle)] + pub extern fn $intrinsic(a: $ty, b: u32) -> $ty { + let half_bits = <$ty>::bits() / 2; + if b & half_bits != 0 { + <$ty>::from_parts(a.high() >> (b - half_bits), 0) + } else if b == 0 { + a + } else { + <$ty>::from_parts((a.high() << (half_bits - b)) | (a.low() >> b), a.high() >> b) + } + } + } +} + +ashl!(__ashldi3: u64); +ashr!(__ashrdi3: i64); +lshr!(__lshrdi3: u64); + +#[cfg(test)] +mod tests { + use quickcheck::TestResult; + + quickcheck! { + fn ashldi(a: u64, b: u32) -> TestResult { + if b >= 64 { + TestResult::discard() + } else { + let r = super::__ashldi3(a, b); + TestResult::from_bool(r == a << b) + } + } + + fn ashrdi(a: i64, b: u32) -> TestResult { + if b >= 64 { + TestResult::discard() + } else { + let r = super::__ashrdi3(a, b); + TestResult::from_bool(r == a >> b) + } + } + + fn lshrdi(a: u64, b: u32) -> TestResult { + if b >= 64 { + TestResult::discard() + } else { + let r = super::__lshrdi3(a, b); + TestResult::from_bool(r == a >> b) + } + } + } +} diff --git a/library/compiler-builtins/src/test.rs b/library/compiler-builtins/src/test.rs deleted file mode 100644 index 96e0c12738b8d..0000000000000 --- a/library/compiler-builtins/src/test.rs +++ /dev/null @@ -1,32 +0,0 @@ -use std::panic; - -use quickcheck::TestResult; - -quickcheck! { - fn udivmoddi4(n: (u32, u32), d: (u32, u32)) -> TestResult { - let n = ::U64 { low: n.0, high: n.1 }[..]; - let d = ::U64 { low: d.0, high: d.1 }[..]; - - if d == 0 { - TestResult::discard() - } else { - let mut r = 0; - let q = ::div::__udivmoddi4(n, d, Some(&mut r)); - - TestResult::from_bool(q * d + r == n) - } - } -} - -quickcheck! { - fn udivmodsi4(n: u32, d: u32) -> TestResult { - if d == 0 { - TestResult::discard() - } else { - let mut r = 0; - let q = ::div::__udivmodsi4(n, d, Some(&mut r)); - - TestResult::from_bool(q * d + r == n) - } - } -} diff --git a/library/compiler-builtins/src/udiv.rs b/library/compiler-builtins/src/udiv.rs new file mode 100644 index 0000000000000..95a550f9b9d5e --- /dev/null +++ b/library/compiler-builtins/src/udiv.rs @@ -0,0 +1,290 @@ +use core::mem; +use {Int, LargeInt}; + +/// Returns `n / d` +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { + // Special cases + if d == 0 { + panic!("Division by zero"); + } + + if n == 0 { + return 0; + } + + let mut sr = d.leading_zeros().wrapping_sub(n.leading_zeros()); + + // d > n + if sr > u32::bits() - 1 { + return 0; + } + + // d == 1 + if sr == u32::bits() - 1 { + return n; + } + + sr += 1; + + // 1 <= sr <= u32::bits() - 1 + let mut q = n << (u32::bits() - sr); + let mut r = n >> sr; + + let mut carry = 0; + for _ in 0..sr { + // r:q = ((r:q) << 1) | carry + r = (r << 1) | (q >> (u32::bits() - 1)); + q = (q << 1) | carry; + + // carry = 0; + // if r > d { + // r -= d; + // carry = 1; + // } + + let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32::bits() - 1); + carry = (s & 1) as u32; + r -= d & s as u32; + } + + (q << 1) | carry +} + +/// Returns `n % d` +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { + n - __udivsi3(n, d) * d +} + +/// Returns `n / d` and sets `*rem = n % d` +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { + let q = __udivsi3(n, d); + if let Some(rem) = rem { + *rem = n - (q * d); + } + q +} + +/// Returns `n / d` +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { + __udivmoddi4(n, d, None) +} + +/// Returns `n % d` +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __umoddi3(a: u64, b: u64) -> u64 { + let mut rem = unsafe { mem::uninitialized() }; + __udivmoddi4(a, b, Some(&mut rem)); + rem +} + +/// Returns `n / d` and sets `*rem = n % d` +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { + // NOTE X is unknown, K != 0 + if n.high() == 0 { + if d.high() == 0 { + // 0 X + // --- + // 0 X + if let Some(rem) = rem { + *rem = u64::from(n.low() % d.low()); + } + return u64::from(n.low() / d.low()); + } else { + // 0 X + // --- + // K X + if let Some(rem) = rem { + *rem = n; + } + return 0; + }; + } + + let mut sr; + let mut q; + let mut r; + + if d.low() == 0 { + if d.high() == 0 { + // K X + // --- + // 0 0 + panic!("Division by zero"); + } + + if n.low() == 0 { + // K 0 + // --- + // K 0 + if let Some(rem) = rem { + *rem = u64::from_parts(0, n.high() % d.high()); + } + return u64::from(n.high() / d.high()); + } + + // K K + // --- + // K 0 + + if d.high().is_power_of_two() { + if let Some(rem) = rem { + *rem = u64::from_parts(n.low(), n.high() & (d.high() - 1)); + } + return u64::from(n.high() >> d.high().trailing_zeros()); + } + + sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); + + // D > N + if sr > u32::bits() - 2 { + if let Some(rem) = rem { + *rem = n; + } + return 0; + } + + sr += 1; + + // 1 <= sr <= u32::bits() - 1 + q = n << (u64::bits() - sr); + r = n >> sr; + } else { + if d.high() == 0 { + // K X + // --- + // 0 K + if d.low().is_power_of_two() { + if let Some(rem) = rem { + *rem = u64::from(n.low() & (d.low() - 1)); + } + + if d.low() == 1 { + return n; + } else { + let sr = d.low().trailing_zeros(); + return n >> sr; + }; + } + + sr = 1 + u32::bits() + d.low().leading_zeros() - n.high().leading_zeros(); + + // 2 <= sr <= u64::bits() - 1 + q = n << (u64::bits() - sr); + r = n >> sr; + } else { + // K X + // --- + // K K + sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); + + // D > N + if sr > u32::bits() - 1 { + if let Some(rem) = rem { + *rem = n; + return 0; + } + } + + sr += 1; + + // 1 <= sr <= u32::bits() + q = n << (u64::bits() - sr); + r = n >> sr; + } + } + + // Not a special case + // q and r are initialized with + // q = n << (u64::bits() - sr) + // r = n >> sr + // 1 <= sr <= u64::bits() - 1 + let mut carry = 0; + + for _ in 0..sr { + // r:q = ((r:q) << 1) | carry + r = (r << 1) | (q >> (u64::bits() - 1)); + q = (q << 1) | carry as u64; + + // carry = 0 + // if r >= d { + // r -= d; + // carry = 1; + // } + let s = (d.wrapping_sub(r).wrapping_sub(1)) as i64 >> (u64::bits() - 1); + carry = (s & 1) as u32; + r -= d & s as u64; + } + + if let Some(rem) = rem { + *rem = r; + } + (q << 1) | carry as u64 +} + +#[cfg(test)] +mod tests { + use quickcheck::TestResult; + + quickcheck!{ + fn udivdi3(n: u64, d: u64) -> TestResult { + if d == 0 { + TestResult::discard() + } else { + let q = super::__udivdi3(n, d); + TestResult::from_bool(q == n / d) + } + } + + fn umoddi3(n: u64, d: u64) -> TestResult { + if d == 0 { + TestResult::discard() + } else { + let r = super::__umoddi3(n, d); + TestResult::from_bool(r == n % d) + } + } + + fn udivmoddi4(n: u64, d: u64) -> TestResult { + if d == 0 { + TestResult::discard() + } else { + let mut r = 0; + let q = super::__udivmoddi4(n, d, Some(&mut r)); + TestResult::from_bool(q == n / d && r == n % d) + } + } + + fn udivsi3(n: u32, d: u32) -> TestResult { + if d == 0 { + TestResult::discard() + } else { + let q = super::__udivsi3(n, d); + TestResult::from_bool(q == n / d) + } + } + + fn umodsi3(n: u32, d: u32) -> TestResult { + if d == 0 { + TestResult::discard() + } else { + let r = super::__umodsi3(n, d); + TestResult::from_bool(r == n % d) + } + } + + fn udivmodsi4(n: u32, d: u32) -> TestResult { + if d == 0 { + TestResult::discard() + } else { + let mut r = 0; + let q = super::__udivmodsi4(n, d, Some(&mut r)); + TestResult::from_bool(q == n / d && r == n % d) + } + } + } +} From d668c385aca6fc02501bfc78d8561e7e2cdb076f Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 13 Aug 2016 17:29:38 +0100 Subject: [PATCH 0076/4206] Fix inline assembly to work on ARMv6-M --- library/compiler-builtins/src/arm.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 0759b55d4af3f..ad2b39a27f32c 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -9,7 +9,8 @@ pub unsafe fn __aeabi_uidivmod() { sub sp, sp, #4 mov r2, sp bl __udivmodsi4 - ldr r1, [sp], #4 + ldr r1, [sp] + add sp, sp, #4 pop {pc}"); intrinsics::unreachable(); } @@ -17,13 +18,15 @@ pub unsafe fn __aeabi_uidivmod() { #[naked] #[cfg_attr(not(test), no_mangle)] pub unsafe fn __aeabi_uldivmod() { - asm!("push {lr} - sub r12, sp, #12 - str r12, [sp, #-20]! + asm!("push {r4, lr} + sub sp, sp, #16 + add r4, sp, #8 + str r4, [sp] bl __udivmoddi4 - ldrd r2, r3, [sp, #8] - add sp, sp, #20 - pop {pc}"); + ldr r2, [sp, #8] + ldr r3, [sp, #12] + add sp, sp, #16 + pop {r4, pc}"); intrinsics::unreachable(); } From 1b757d626d6af7d4d002464557d143cb779320ca Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 11:32:52 -0500 Subject: [PATCH 0077/4206] CI: test ARM Cortex targets closes #32 --- library/compiler-builtins/.travis.yml | 29 +++++++++++++++++++ library/compiler-builtins/ci/env.sh | 12 +++++--- library/compiler-builtins/ci/install.sh | 9 ++++-- library/compiler-builtins/ci/script.sh | 12 ++++---- .../compiler-builtins/thumbv6m-none-eabi.json | 10 +++++++ .../thumbv7em-none-eabi.json | 8 +++++ .../compiler-builtins/thumbv7m-none-eabi.json | 8 +++++ 7 files changed, 76 insertions(+), 12 deletions(-) create mode 100644 library/compiler-builtins/thumbv6m-none-eabi.json create mode 100644 library/compiler-builtins/thumbv7em-none-eabi.json create mode 100644 library/compiler-builtins/thumbv7m-none-eabi.json diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index dae5b40b2d059..cb3800665c9b0 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -3,6 +3,25 @@ sudo: false matrix: include: + - env: TARGET=thumbv6m-none-eabi + os: linux + dist: trusty + addons: + apt: + packages: &cortex + - binutils-arm-none-eabi + - env: TARGET=thumbv7m-none-eabi + os: linux + dist: trusty + addons: + apt: + packages: *cortex + - env: TARGET=thumbv7em-none-eabi + os: linux + dist: trusty + addons: + apt: + packages: *cortex - env: TARGET=i586-unknown-linux-gnu os: linux services: docker @@ -84,6 +103,16 @@ matrix: os: osx - env: TARGET=x86_64-unknown-linux-gnu os: linux + allow_failures: + # Issue #2. Flaky test + - env: TARGET=arm-unknown-linux-gnueabi + os: linux + # Issue #2. Flaky test + - env: TARGET=arm-unknown-linux-gnueabihf + os: linux + # Issue #2. Flaky test + - env: TARGET=armv7-unknown-linux-gnueabihf + os: linux before_install: - export PATH="$PATH:$HOME/.cargo/bin" diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 472983ff91897..17f5f9cd2674f 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -25,8 +25,6 @@ case $TARGET in export QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf ;; armv7-unknown-linux-gnueabihf) - # See #2 - export DONT_RUN_TESTS=y export PREFIX=arm-linux-gnueabihf- export QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf ;; @@ -65,13 +63,19 @@ case $TARGET in export QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu ;; powerpc64le-unknown-linux-gnu) - # See #2 - export DONT_RUN_TESTS=y if [[ -z $DOCKER ]]; then export DOCKER=y fi export PREFIX=powerpc64le-linux-gnu- export QEMU=qemu-ppc64le export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu + # Issue #2. QEMU doesn't work + export RUN_TESTS=n + ;; + thumbv*-none-eabi) + export CARGO=xargo + export PREFIX=arm-none-eabi- + # Bare metal targets. No `std` or `test` crates for these targets. + export RUN_TESTS=n ;; esac diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 9c971c67a66e3..86dfefe375e10 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -32,8 +32,6 @@ install_binutils() { osx) brew install binutils ;; - *) - ;; esac } @@ -79,6 +77,12 @@ add_rustup_target() { fi } +install_xargo() { + if [[ $CARGO == "xargo" ]]; then + curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | bash -s -- --from japaric/xargo + fi +} + configure_cargo() { if [[ $PREFIX ]]; then ${PREFIX}gcc -v @@ -99,6 +103,7 @@ main() { install_c_toolchain install_rust add_rustup_target + install_xargo configure_cargo fi } diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 099e42ea3b059..f68b72b7b8529 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -3,8 +3,8 @@ set -ex . $(dirname $0)/env.sh build() { - cargo build --target $TARGET - cargo build --target $TARGET --release + ${CARGO:-cargo} build --target $TARGET + ${CARGO:-cargo} build --target $TARGET --release } run_tests() { @@ -14,14 +14,14 @@ run_tests() { if [[ $QEMU ]]; then cargo test --target $TARGET --no-run - if [[ -z $DONT_RUN_TESTS ]]; then + if [[ ${RUN_TESTS:-y} == "y" ]]; then $QEMU target/**/debug/rustc_builtins-* fi cargo test --target $TARGET --release --no-run - if [[ -z $DONT_RUN_TESTS ]]; then + if [[ ${RUN_TESTS:-y} == "y" ]]; then $QEMU target/**/release/rustc_builtins-* fi - elif [[ -z $DONT_RUN_TESTS ]]; then + elif [[ ${RUN_TESTS:-y} == "y" ]]; then cargo test --target $TARGET cargo test --target $TARGET --release fi @@ -50,8 +50,8 @@ main() { bash ci/script.sh' else build - run_tests inspect + run_tests fi } diff --git a/library/compiler-builtins/thumbv6m-none-eabi.json b/library/compiler-builtins/thumbv6m-none-eabi.json new file mode 100644 index 0000000000000..9c92d4e33332c --- /dev/null +++ b/library/compiler-builtins/thumbv6m-none-eabi.json @@ -0,0 +1,10 @@ +{ + "arch": "arm", + "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "features": "+strict-align", + "llvm-target": "thumbv6m-none-eabi", + "max-atomic-width": 0, + "os": "none", + "target-endian": "little", + "target-pointer-width": "32" +} diff --git a/library/compiler-builtins/thumbv7em-none-eabi.json b/library/compiler-builtins/thumbv7em-none-eabi.json new file mode 100644 index 0000000000000..ce49c83ffdaa3 --- /dev/null +++ b/library/compiler-builtins/thumbv7em-none-eabi.json @@ -0,0 +1,8 @@ +{ + "arch": "arm", + "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "llvm-target": "thumbv7em-none-eabi", + "os": "none", + "target-endian": "little", + "target-pointer-width": "32" +} diff --git a/library/compiler-builtins/thumbv7m-none-eabi.json b/library/compiler-builtins/thumbv7m-none-eabi.json new file mode 100644 index 0000000000000..313a5e66f71d3 --- /dev/null +++ b/library/compiler-builtins/thumbv7m-none-eabi.json @@ -0,0 +1,8 @@ +{ + "arch": "arm", + "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "llvm-target": "thumbv7m-none-eabi", + "os": "none", + "target-endian": "little", + "target-pointer-width": "32" +} From 5e69a93dfb4720428b2fc415586dc13ba10c53b7 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 12:21:33 -0500 Subject: [PATCH 0078/4206] binutils -> gcc? --- library/compiler-builtins/.travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index cb3800665c9b0..f71438c87fba9 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -9,7 +9,7 @@ matrix: addons: apt: packages: &cortex - - binutils-arm-none-eabi + - gcc-arm-none-eabi - env: TARGET=thumbv7m-none-eabi os: linux dist: trusty From b5b26a0384f17388cd6985fb14070accae3fbd84 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 12:41:50 -0500 Subject: [PATCH 0079/4206] install binutils manually --- library/compiler-builtins/.travis.yml | 13 +++---------- library/compiler-builtins/ci/install.sh | 7 +++++++ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index f71438c87fba9..4fe9705229a80 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -6,22 +6,15 @@ matrix: - env: TARGET=thumbv6m-none-eabi os: linux dist: trusty - addons: - apt: - packages: &cortex - - gcc-arm-none-eabi + sudo: required - env: TARGET=thumbv7m-none-eabi os: linux dist: trusty - addons: - apt: - packages: *cortex + sudo: required - env: TARGET=thumbv7em-none-eabi os: linux dist: trusty - addons: - apt: - packages: *cortex + sudo: required - env: TARGET=i586-unknown-linux-gnu os: linux services: docker diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 86dfefe375e10..57131eb94d098 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -33,6 +33,13 @@ install_binutils() { brew install binutils ;; esac + + case $TARGET in + thumbv*-none-eabi) + sudo apt-get install -y --no-install-recommends \ + binutils-arm-none-eabi + ;; + esac } install_c_toolchain() { From a3a0604b8e8866f09878e26f22d431bc176de3f1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 12:45:19 -0500 Subject: [PATCH 0080/4206] no rust-std for these targets --- library/compiler-builtins/ci/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 57131eb94d098..b1e596db88f4f 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -79,7 +79,7 @@ install_rust() { } add_rustup_target() { - if [[ $TARGET != $HOST ]]; then + if [[ $TARGET != $HOST && ${CARGO:-cargo} == "cargo" ]]; then rustup target add $TARGET fi } From c135ca31573ff41d00ceda3666590d6c7b3f8e1e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 12:47:59 -0500 Subject: [PATCH 0081/4206] binutils -> gcc --- library/compiler-builtins/ci/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index b1e596db88f4f..8486eb874e7f5 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -37,7 +37,7 @@ install_binutils() { case $TARGET in thumbv*-none-eabi) sudo apt-get install -y --no-install-recommends \ - binutils-arm-none-eabi + gcc-arm-none-eabi ;; esac } From 2684ea570cdd4ae82bd550d3f5fb47460a71460e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 12:55:09 -0500 Subject: [PATCH 0082/4206] change Xargo installation path --- library/compiler-builtins/ci/install.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 8486eb874e7f5..84441ce393a5a 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -86,7 +86,8 @@ add_rustup_target() { install_xargo() { if [[ $CARGO == "xargo" ]]; then - curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | bash -s -- --from japaric/xargo + curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ + bash -s -- --from japaric/xargo --at $HOME/.cargo/bin fi } From da0515756ad0f39856e2684a2a766741cf68f5ab Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 12:58:44 -0500 Subject: [PATCH 0083/4206] install libssh2 --- library/compiler-builtins/ci/install.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 84441ce393a5a..3bd806d8714d6 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -86,6 +86,8 @@ add_rustup_target() { install_xargo() { if [[ $CARGO == "xargo" ]]; then + sudo apt-get install -y --no-install-recommends \ + libssh2-1 curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ bash -s -- --from japaric/xargo --at $HOME/.cargo/bin fi From 5581cc40af00edb82258f621a28ba6ea5a584d7f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 16:58:44 -0500 Subject: [PATCH 0084/4206] quickcheck: better generation of input arguments closes #31 --- library/compiler-builtins/src/lib.rs | 8 +- library/compiler-builtins/src/mul.rs | 11 ++- library/compiler-builtins/src/qc.rs | 123 +++++++++++++++++++++++++ library/compiler-builtins/src/shift.rs | 11 ++- library/compiler-builtins/src/udiv.rs | 19 ++-- 5 files changed, 159 insertions(+), 13 deletions(-) create mode 100644 library/compiler-builtins/src/qc.rs diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 6d5580b8e1873..823170a413ec9 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,8 +1,8 @@ #![allow(unused_features)] -#![no_std] #![feature(asm)] #![feature(core_intrinsics)] #![feature(naked_functions)] +#![cfg_attr(not(test), no_std)] // TODO(rust-lang/rust#35021) uncomment when that PR lands // #![feature(rustc_builtins)] @@ -13,6 +13,9 @@ #[macro_use] extern crate quickcheck; +#[cfg(test)] +extern crate core; + #[cfg(target_arch = "arm")] pub mod arm; @@ -20,6 +23,9 @@ pub mod udiv; pub mod mul; pub mod shift; +#[cfg(test)] +mod qc; + /// Trait for some basic operations on integers trait Int { fn bits() -> u32; diff --git a/library/compiler-builtins/src/mul.rs b/library/compiler-builtins/src/mul.rs index a4350b5f7fffa..b93fdb7663916 100644 --- a/library/compiler-builtins/src/mul.rs +++ b/library/compiler-builtins/src/mul.rs @@ -72,13 +72,17 @@ mulo!(__mulodi4: i64); #[cfg(test)] mod tests { + use qc::{I32, I64, U64}; + quickcheck! { - fn muldi(a: u64, b: u64) -> bool { + fn muldi(a: U64, b: U64) -> bool { + let (a, b) = (a.0, b.0); let r = super::__muldi4(a, b); r == a.wrapping_mul(b) } - fn mulosi(a: i32, b: i32) -> bool { + fn mulosi(a: I32, b: I32) -> bool { + let (a, b) = (a.0, b.0); let mut overflow = 2; let r = super::__mulosi4(a, b, &mut overflow); if overflow != 0 && overflow != 1 { @@ -87,7 +91,8 @@ mod tests { (r, overflow != 0) == a.overflowing_mul(b) } - fn mulodi(a: i64, b: i64) -> bool { + fn mulodi(a: I64, b: I64) -> bool { + let (a, b) = (a.0, b.0); let mut overflow = 2; let r = super::__mulodi4(a, b, &mut overflow); if overflow != 0 && overflow != 1 { diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs new file mode 100644 index 0000000000000..6b37cceb7fd45 --- /dev/null +++ b/library/compiler-builtins/src/qc.rs @@ -0,0 +1,123 @@ +// When testing functions, QuickCheck (QC) uses small values for integer (`u*`/`i*`) arguments +// (~ `[-100, 100]`), but these values don't stress all the code paths in our intrinsics. Here we +// create newtypes over the primitive integer types with the goal of having full control over the +// random values that will be used to test our intrinsics. + +use std::boxed::Box; +use std::fmt; + +use quickcheck::{Arbitrary, Gen}; + +use LargeInt; + +// Generates values in the full range of the integer type +macro_rules! arbitrary { + ($TY:ident : $ty:ident) => { + #[derive(Clone, Copy)] + pub struct $TY(pub $ty); + + impl Arbitrary for $TY { + fn arbitrary(g: &mut G) -> $TY + where G: Gen + { + $TY(g.gen()) + } + + fn shrink(&self) -> Box> { + struct Shrinker { + x: $ty, + } + + impl Iterator for Shrinker { + type Item = $TY; + + fn next(&mut self) -> Option<$TY> { + self.x /= 2; + if self.x == 0 { + None + } else { + Some($TY(self.x)) + } + } + } + + if self.0 == 0 { + ::quickcheck::empty_shrinker() + } else { + Box::new(Shrinker { x: self.0 }) + } + } + } + + impl fmt::Debug for $TY { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } + } + } +} + +arbitrary!(I32: i32); +arbitrary!(U32: u32); + +// These integers are "too large". If we generate e.g. `u64` values in the full range then there's +// only `1 / 2^32` chance of seeing a value smaller than `2^32` (i.e. whose higher "word" (32-bits) +// is `0`)! But this is an important group of values to tests because we have special code paths for +// them. Instead we'll generate e.g. `u64` integers this way: uniformly pick between (a) setting the +// low word to 0 and generating a random high word, (b) vice versa: high word to 0 and random low +// word or (c) generate both words randomly. This let's cover better the code paths in our +// intrinsics. +macro_rules! arbitrary_large { + ($TY:ident : $ty:ident) => { + #[derive(Clone, Copy)] + pub struct $TY(pub $ty); + + impl Arbitrary for $TY { + fn arbitrary(g: &mut G) -> $TY + where G: Gen + { + if g.gen() { + $TY($ty::from_parts(g.gen(), g.gen())) + } else if g.gen() { + $TY($ty::from_parts(0, g.gen())) + } else { + $TY($ty::from_parts(g.gen(), 0)) + } + } + + fn shrink(&self) -> Box> { + struct Shrinker { + x: $ty, + } + + impl Iterator for Shrinker { + type Item = $TY; + + fn next(&mut self) -> Option<$TY> { + self.x /= 2; + if self.x == 0 { + None + } else { + Some($TY(self.x)) + } + } + } + + if self.0 == 0 { + ::quickcheck::empty_shrinker() + } else { + Box::new(Shrinker { x: self.0 }) + } + } + } + + impl fmt::Debug for $TY { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } + } + } +} + +arbitrary_large!(I64: i64); +arbitrary_large!(U64: u64); diff --git a/library/compiler-builtins/src/shift.rs b/library/compiler-builtins/src/shift.rs index 909d6f47f5a15..7fa88abffb24e 100644 --- a/library/compiler-builtins/src/shift.rs +++ b/library/compiler-builtins/src/shift.rs @@ -61,9 +61,12 @@ lshr!(__lshrdi3: u64); #[cfg(test)] mod tests { use quickcheck::TestResult; + use qc::{I64, U64}; + // NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64) quickcheck! { - fn ashldi(a: u64, b: u32) -> TestResult { + fn ashldi(a: U64, b: u32) -> TestResult { + let a = a.0; if b >= 64 { TestResult::discard() } else { @@ -72,7 +75,8 @@ mod tests { } } - fn ashrdi(a: i64, b: u32) -> TestResult { + fn ashrdi(a: I64, b: u32) -> TestResult { + let a = a.0; if b >= 64 { TestResult::discard() } else { @@ -81,7 +85,8 @@ mod tests { } } - fn lshrdi(a: u64, b: u32) -> TestResult { + fn lshrdi(a: U64, b: u32) -> TestResult { + let a = a.0; if b >= 64 { TestResult::discard() } else { diff --git a/library/compiler-builtins/src/udiv.rs b/library/compiler-builtins/src/udiv.rs index 95a550f9b9d5e..f1037c6df07f4 100644 --- a/library/compiler-builtins/src/udiv.rs +++ b/library/compiler-builtins/src/udiv.rs @@ -229,9 +229,11 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { #[cfg(test)] mod tests { use quickcheck::TestResult; + use qc::{U32, U64}; quickcheck!{ - fn udivdi3(n: u64, d: u64) -> TestResult { + fn udivdi3(n: U64, d: U64) -> TestResult { + let (n, d) = (n.0, d.0); if d == 0 { TestResult::discard() } else { @@ -240,7 +242,8 @@ mod tests { } } - fn umoddi3(n: u64, d: u64) -> TestResult { + fn umoddi3(n: U64, d: U64) -> TestResult { + let (n, d) = (n.0, d.0); if d == 0 { TestResult::discard() } else { @@ -249,7 +252,8 @@ mod tests { } } - fn udivmoddi4(n: u64, d: u64) -> TestResult { + fn udivmoddi4(n: U64, d: U64) -> TestResult { + let (n, d) = (n.0, d.0); if d == 0 { TestResult::discard() } else { @@ -259,7 +263,8 @@ mod tests { } } - fn udivsi3(n: u32, d: u32) -> TestResult { + fn udivsi3(n: U32, d: U32) -> TestResult { + let (n, d) = (n.0, d.0); if d == 0 { TestResult::discard() } else { @@ -268,7 +273,8 @@ mod tests { } } - fn umodsi3(n: u32, d: u32) -> TestResult { + fn umodsi3(n: U32, d: U32) -> TestResult { + let (n, d) = (n.0, d.0); if d == 0 { TestResult::discard() } else { @@ -277,7 +283,8 @@ mod tests { } } - fn udivmodsi4(n: u32, d: u32) -> TestResult { + fn udivmodsi4(n: U32, d: U32) -> TestResult { + let (n, d) = (n.0, d.0); if d == 0 { TestResult::discard() } else { From 7b46e31124afceae32263161c317d1cb4aa6492e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 17:22:12 -0500 Subject: [PATCH 0085/4206] CI: run all Linux targets inside docker --- library/compiler-builtins/.travis.yml | 65 +---------------- library/compiler-builtins/ci/env.sh | 26 ++----- library/compiler-builtins/ci/install.sh | 93 +++++-------------------- library/compiler-builtins/ci/script.sh | 25 ++++--- 4 files changed, 36 insertions(+), 173 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 4fe9705229a80..7542351d1cd34 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -1,97 +1,39 @@ language: generic -sudo: false +sudo: required +services: docker matrix: include: - env: TARGET=thumbv6m-none-eabi os: linux - dist: trusty - sudo: required - env: TARGET=thumbv7m-none-eabi os: linux - dist: trusty - sudo: required - env: TARGET=thumbv7em-none-eabi os: linux - dist: trusty - sudo: required - env: TARGET=i586-unknown-linux-gnu os: linux - services: docker - sudo: required - env: TARGET=aarch64-unknown-linux-gnu os: linux - dist: trusty - sudo: required - addons: - apt: - packages: - - binfmt-support - - qemu-user-static - env: TARGET=arm-unknown-linux-gnueabi os: linux - sudo: required - addons: - apt: - packages: - - binfmt-support - - gcc-arm-linux-gnueabi - - libc6-armel-cross - - libc6-dev-armel-cross - - qemu-user-static - env: TARGET=arm-unknown-linux-gnueabihf os: linux - sudo: required - addons: - apt: - packages: &armhf - - binfmt-support - - gcc-arm-linux-gnueabihf - - libc6-armhf-cross - - libc6-dev-armhf-cross - - qemu-user-static - env: TARGET=armv7-unknown-linux-gnueabihf os: linux - sudo: required - addons: - apt: - packages: *armhf - env: TARGET=i686-apple-darwin os: osx - env: TARGET=i686-unknown-linux-gnu os: linux - addons: - apt: - packages: - - gcc-multilib - env: TARGET=mips-unknown-linux-gnu os: linux - services: docker - sudo: required - env: TARGET=mipsel-unknown-linux-gnu os: linux - services: docker - sudo: required - env: TARGET=powerpc-unknown-linux-gnu os: linux - dist: trusty - sudo: required - addons: - apt: - packages: - - binfmt-support - - gcc-powerpc-linux-gnu - - libc6-powerpc-cross - - libc6-dev-powerpc-cross - - qemu-user-static - env: TARGET=powerpc64-unknown-linux-gnu os: linux - services: docker - sudo: required - env: TARGET=powerpc64le-unknown-linux-gnu os: linux - services: docker - sudo: required - env: TARGET=x86_64-apple-darwin os: osx - env: TARGET=x86_64-unknown-linux-gnu @@ -107,9 +49,6 @@ matrix: - env: TARGET=armv7-unknown-linux-gnueabihf os: linux -before_install: - - export PATH="$PATH:$HOME/.cargo/bin" - install: - bash ci/install.sh diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 17f5f9cd2674f..a8c7003394e81 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -28,26 +28,14 @@ case $TARGET in export PREFIX=arm-linux-gnueabihf- export QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf ;; - i586-unknown-linux-gnu) - # NOTE $DOCKER values: 'y' (yes, call docker), 'i' (inside a docker container) or 'n' ("no) - if [[ -z $DOCKER ]]; then - export DOCKER=y - fi - ;; mips-unknown-linux-gnu) - if [[ -z $DOCKER ]]; then - export DOCKER=y - fi export PREFIX=mips-linux-gnu- - export QEMU=qemu-mips + # export QEMU=qemu-mips export QEMU_LD_PREFIX=/usr/mips-linux-gnu ;; mipsel-unknown-linux-gnu) - if [[ -z $DOCKER ]]; then - export DOCKER=y - fi export PREFIX=mipsel-linux-gnu- - export QEMU=qemu-mipsel + # export QEMU=qemu-mipsel export QEMU_LD_PREFIX=/usr/mipsel-linux-gnu ;; powerpc-unknown-linux-gnu) @@ -55,19 +43,13 @@ case $TARGET in export QEMU_LD_PREFIX=/usr/powerpc-linux-gnu ;; powerpc64-unknown-linux-gnu) - if [[ -z $DOCKER ]]; then - export DOCKER=y - fi export PREFIX=powerpc64-linux-gnu- - export QEMU=qemu-ppc64 + # export QEMU=qemu-ppc64 export QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu ;; powerpc64le-unknown-linux-gnu) - if [[ -z $DOCKER ]]; then - export DOCKER=y - fi export PREFIX=powerpc64le-linux-gnu- - export QEMU=qemu-ppc64le + # export QEMU=qemu-ppc64le export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu # Issue #2. QEMU doesn't work export RUN_TESTS=n diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 3bd806d8714d6..e3b7ce84fb57c 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -2,77 +2,33 @@ set -ex . $(dirname $0)/env.sh -install_deps() { - if [[ ${DOCKER} == "i" ]]; then - apt-get update - apt-get install -y --no-install-recommends \ - ca-certificates curl - fi -} - install_qemu() { - case $TARGET in - mipsel-unknown-linux-gnu | \ - powerpc64le-unknown-linux-gnu) + case ${QEMU_ARCH:-$TRAVIS_OS_NAME} in + i386) + dpkg --add-architecture $QEMU_ARCH apt-get install -y --no-install-recommends \ - qemu-user + binfmt-support qemu-user-static:$QEMU_ARCH ;; - mips-unknown-linux-gnu | \ - powerpc64-unknown-linux-gnu) - dpkg --add-architecture i386 + linux) apt-get update apt-get install -y --no-install-recommends \ - qemu-user:i386 + binfmt-support qemu-user-static ;; esac } install_binutils() { - case $TRAVIS_OS_NAME in - osx) - brew install binutils - ;; - esac - - case $TARGET in - thumbv*-none-eabi) - sudo apt-get install -y --no-install-recommends \ - gcc-arm-none-eabi - ;; - esac -} - -install_c_toolchain() { - case $TARGET in - aarch64-unknown-linux-gnu) - sudo apt-get install -y --no-install-recommends \ - gcc-aarch64-linux-gnu libc6-dev-arm64-cross - ;; - i586-unknown-linux-gnu) - apt-get install -y --no-install-recommends \ - gcc libc6-dev-i386 lib32gcc-5-dev - ;; - mips-unknown-linux-gnu) - apt-get install -y --no-install-recommends \ - gcc gcc-mips-linux-gnu libc6-dev libc6-dev-mips-cross - ;; - mipsel-unknown-linux-gnu) - apt-get install -y --no-install-recommends \ - gcc gcc-mipsel-linux-gnu libc6-dev libc6-dev-mipsel-cross - ;; - powerpc64-unknown-linux-gnu) - apt-get install -y --no-install-recommends \ - gcc gcc-powerpc64-linux-gnu libc6-dev libc6-dev-ppc64-cross - ;; - powerpc64le-unknown-linux-gnu) - apt-get install -y --no-install-recommends \ - gcc gcc-powerpc64le-linux-gnu libc6-dev libc6-dev-ppc64el-cross - ;; - esac + if [[ $TRAVIS_OS_NAME == "osx" ]]; then + brew install binutils + fi } install_rust() { - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain=nightly + if [[ $TRAVIS_OS_NAME == "osx" ]]; then + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain=nightly + else + rustup default nightly + fi rustc -V cargo -V @@ -86,35 +42,18 @@ add_rustup_target() { install_xargo() { if [[ $CARGO == "xargo" ]]; then - sudo apt-get install -y --no-install-recommends \ - libssh2-1 curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --from japaric/xargo --at $HOME/.cargo/bin - fi -} - -configure_cargo() { - if [[ $PREFIX ]]; then - ${PREFIX}gcc -v - - mkdir -p .cargo - cat >>.cargo/config < Date: Sat, 13 Aug 2016 17:24:52 -0500 Subject: [PATCH 0086/4206] fix bash syntax --- library/compiler-builtins/ci/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index e3b7ce84fb57c..bdb0fa1d77a07 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -48,7 +48,7 @@ install_xargo() { } main() { - if [[ $TRAVIS_OS_NAME == "osx" || ${IN_DOCKER_CONTAINER:-n} == "y" ]] + if [[ $TRAVIS_OS_NAME == "osx" || ${IN_DOCKER_CONTAINER:-n} == "y" ]]; then install_qemu install_binutils install_rust From cc6aab07ea63447f97412b25510bc800d9c90554 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 17:27:18 -0500 Subject: [PATCH 0087/4206] actually enter docker --- library/compiler-builtins/ci/script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 4243fb028736d..e119044b618aa 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -36,7 +36,7 @@ run_tests() { } main() { - if [[ $DOCKER == "y" ]]; then + if [[ $TRAVIS_OS_NAME == "linux" ]]; then local tag=2016-08-13 docker run \ From a8f3f4eae63076d7250153cf7b99b53fcf6bac80 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 17:32:08 -0500 Subject: [PATCH 0088/4206] use trusty --- library/compiler-builtins/.travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 7542351d1cd34..99a2729aa77a1 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -1,6 +1,7 @@ +dist: trusty language: generic -sudo: required services: docker +sudo: required matrix: include: From c7a48515ac8ac035a9f08f17465f3bf26e97a2a6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 17:36:00 -0500 Subject: [PATCH 0089/4206] don't call docker inside docker --- library/compiler-builtins/ci/script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index e119044b618aa..847530a142ccf 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -36,7 +36,7 @@ run_tests() { } main() { - if [[ $TRAVIS_OS_NAME == "linux" ]]; then + if [[ $TRAVIS_OS_NAME == "linux" && ${IN_DOCKER_CONTAINER:-n} == "n" ]]; then local tag=2016-08-13 docker run \ From 0433fc0deba61035ecc3c329347afe9b0bf4dadf Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 17:43:40 -0500 Subject: [PATCH 0090/4206] sort targets --- library/compiler-builtins/.travis.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 99a2729aa77a1..53b5706656021 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -5,14 +5,6 @@ sudo: required matrix: include: - - env: TARGET=thumbv6m-none-eabi - os: linux - - env: TARGET=thumbv7m-none-eabi - os: linux - - env: TARGET=thumbv7em-none-eabi - os: linux - - env: TARGET=i586-unknown-linux-gnu - os: linux - env: TARGET=aarch64-unknown-linux-gnu os: linux - env: TARGET=arm-unknown-linux-gnueabi @@ -21,6 +13,8 @@ matrix: os: linux - env: TARGET=armv7-unknown-linux-gnueabihf os: linux + - env: TARGET=i586-unknown-linux-gnu + os: linux - env: TARGET=i686-apple-darwin os: osx - env: TARGET=i686-unknown-linux-gnu @@ -35,6 +29,12 @@ matrix: os: linux - env: TARGET=powerpc64le-unknown-linux-gnu os: linux + - env: TARGET=thumbv6m-none-eabi + os: linux + - env: TARGET=thumbv7em-none-eabi + os: linux + - env: TARGET=thumbv7m-none-eabi + os: linux - env: TARGET=x86_64-apple-darwin os: osx - env: TARGET=x86_64-unknown-linux-gnu From 54e090113afc22725c1c4aec187952e0134cc0ee Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 17:45:43 -0500 Subject: [PATCH 0091/4206] no need to explicitly call qemu-$ARCH --- library/compiler-builtins/ci/env.sh | 4 ---- library/compiler-builtins/ci/script.sh | 11 +---------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index a8c7003394e81..89660a13e6673 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -30,12 +30,10 @@ case $TARGET in ;; mips-unknown-linux-gnu) export PREFIX=mips-linux-gnu- - # export QEMU=qemu-mips export QEMU_LD_PREFIX=/usr/mips-linux-gnu ;; mipsel-unknown-linux-gnu) export PREFIX=mipsel-linux-gnu- - # export QEMU=qemu-mipsel export QEMU_LD_PREFIX=/usr/mipsel-linux-gnu ;; powerpc-unknown-linux-gnu) @@ -44,12 +42,10 @@ case $TARGET in ;; powerpc64-unknown-linux-gnu) export PREFIX=powerpc64-linux-gnu- - # export QEMU=qemu-ppc64 export QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu ;; powerpc64le-unknown-linux-gnu) export PREFIX=powerpc64le-linux-gnu- - # export QEMU=qemu-ppc64le export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu # Issue #2. QEMU doesn't work export RUN_TESTS=n diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 847530a142ccf..3b00ff62aa197 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -20,16 +20,7 @@ run_tests() { export RUST_TEST_THREADS=1 fi - if [[ $QEMU ]]; then - cargo test --target $TARGET --no-run - if [[ ${RUN_TESTS:-y} == "y" ]]; then - $QEMU target/**/debug/rustc_builtins-* - fi - cargo test --target $TARGET --release --no-run - if [[ ${RUN_TESTS:-y} == "y" ]]; then - $QEMU target/**/release/rustc_builtins-* - fi - elif [[ ${RUN_TESTS:-y} == "y" ]]; then + if [[ ${RUN_TESTS:-y} == "y" ]]; then cargo test --target $TARGET cargo test --target $TARGET --release fi From b80d5f6912cb8360a0eb9f33468f67bf8b30b718 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 17:46:12 -0500 Subject: [PATCH 0092/4206] arm targets no longer have flaky tests --- library/compiler-builtins/.travis.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 53b5706656021..2b0154aeb2c39 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -39,16 +39,6 @@ matrix: os: osx - env: TARGET=x86_64-unknown-linux-gnu os: linux - allow_failures: - # Issue #2. Flaky test - - env: TARGET=arm-unknown-linux-gnueabi - os: linux - # Issue #2. Flaky test - - env: TARGET=arm-unknown-linux-gnueabihf - os: linux - # Issue #2. Flaky test - - env: TARGET=armv7-unknown-linux-gnueabihf - os: linux install: - bash ci/install.sh From 7a5032317ec28129dace653ad71d62e35914a5f3 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 17:53:26 -0500 Subject: [PATCH 0093/4206] need to set PATH for macos --- library/compiler-builtins/.travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 2b0154aeb2c39..e74b68002ffa9 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -40,6 +40,9 @@ matrix: - env: TARGET=x86_64-unknown-linux-gnu os: linux +before_install: + - export PATH="$PATH:$HOME/.cargo/bin" + install: - bash ci/install.sh From 2160b520ff00bc04c9d798c114e91de06fed5378 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 18:00:49 -0500 Subject: [PATCH 0094/4206] enable tests for ppc64le --- library/compiler-builtins/ci/env.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 89660a13e6673..c3591cbee6e39 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -47,8 +47,6 @@ case $TARGET in powerpc64le-unknown-linux-gnu) export PREFIX=powerpc64le-linux-gnu- export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu - # Issue #2. QEMU doesn't work - export RUN_TESTS=n ;; thumbv*-none-eabi) export CARGO=xargo From b8b7cbeabd94dbc046ae35efa5524a3fac382071 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 18:20:52 -0500 Subject: [PATCH 0095/4206] qemu-ppc64le still doesn't work --- library/compiler-builtins/ci/env.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index c3591cbee6e39..50f19b2781fd1 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -47,6 +47,7 @@ case $TARGET in powerpc64le-unknown-linux-gnu) export PREFIX=powerpc64le-linux-gnu- export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu + export RUN_TESTS=n ;; thumbv*-none-eabi) export CARGO=xargo From f7864eb3cd29389854555ffaef26e2418ab91ab7 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 18:45:00 -0500 Subject: [PATCH 0096/4206] fix a bug in udivmoddi4 --- library/compiler-builtins/src/udiv.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/udiv.rs b/library/compiler-builtins/src/udiv.rs index f1037c6df07f4..82932e313144f 100644 --- a/library/compiler-builtins/src/udiv.rs +++ b/library/compiler-builtins/src/udiv.rs @@ -186,8 +186,8 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { if sr > u32::bits() - 1 { if let Some(rem) = rem { *rem = n; - return 0; } + return 0; } sr += 1; From ebb3175dc0f1c5cefcaf06d8e6761d9b7f3c1304 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 18:47:10 -0500 Subject: [PATCH 0097/4206] use wrapping_add in muldi4 --- library/compiler-builtins/src/mul.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/mul.rs b/library/compiler-builtins/src/mul.rs index b93fdb7663916..77dba26ec3c74 100644 --- a/library/compiler-builtins/src/mul.rs +++ b/library/compiler-builtins/src/mul.rs @@ -19,7 +19,7 @@ macro_rules! mul { low += (t & lower_mask) << half_bits; high += t >> half_bits; high += (a.low() >> half_bits) * (b.low() >> half_bits); - high += a.high().wrapping_mul(b.low()) + a.low().wrapping_mul(b.high()); + high = high.wrapping_add(a.high().wrapping_mul(b.low()).wrapping_add(a.low().wrapping_mul(b.high()))); <$ty>::from_parts(low, high) } } From 18265c1061c65001c5b558af604f342b97a986f6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 18:58:41 -0500 Subject: [PATCH 0098/4206] try 32-bit qemu for ppc64le --- library/compiler-builtins/.travis.yml | 4 ++-- library/compiler-builtins/ci/env.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index e74b68002ffa9..7259cc0b11f14 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -5,6 +5,8 @@ sudo: required matrix: include: + - env: TARGET=powerpc64le-unknown-linux-gnu + os: linux - env: TARGET=aarch64-unknown-linux-gnu os: linux - env: TARGET=arm-unknown-linux-gnueabi @@ -27,8 +29,6 @@ matrix: os: linux - env: TARGET=powerpc64-unknown-linux-gnu os: linux - - env: TARGET=powerpc64le-unknown-linux-gnu - os: linux - env: TARGET=thumbv6m-none-eabi os: linux - env: TARGET=thumbv7em-none-eabi diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 50f19b2781fd1..bb1bd262549fd 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -46,8 +46,8 @@ case $TARGET in ;; powerpc64le-unknown-linux-gnu) export PREFIX=powerpc64le-linux-gnu- + export QEMU_ARCH=i386 export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu - export RUN_TESTS=n ;; thumbv*-none-eabi) export CARGO=xargo From 2d84d8acd40d75ccdc12889d3c423b3cec6d1449 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 19:30:30 -0500 Subject: [PATCH 0099/4206] add missing apt-get update --- library/compiler-builtins/ci/install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index bdb0fa1d77a07..6e527b5c3cf55 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -6,6 +6,7 @@ install_qemu() { case ${QEMU_ARCH:-$TRAVIS_OS_NAME} in i386) dpkg --add-architecture $QEMU_ARCH + apt-get update apt-get install -y --no-install-recommends \ binfmt-support qemu-user-static:$QEMU_ARCH ;; From 44aa941787d632bf5364300e689716f519386424 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 19:56:34 -0500 Subject: [PATCH 0100/4206] disable tests for ppc64le, drop logic around QEMU_ARCH --- library/compiler-builtins/ci/env.sh | 4 +++- library/compiler-builtins/ci/install.sh | 8 +------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index bb1bd262549fd..55249950b3c24 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -46,8 +46,10 @@ case $TARGET in ;; powerpc64le-unknown-linux-gnu) export PREFIX=powerpc64le-linux-gnu- - export QEMU_ARCH=i386 export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu + # QEMU crashes, even running the simplest cross compiled C program: + # `int main() { return 0; }` + export RUN_TESTS=n ;; thumbv*-none-eabi) export CARGO=xargo diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 6e527b5c3cf55..db862cc334905 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -3,13 +3,7 @@ set -ex . $(dirname $0)/env.sh install_qemu() { - case ${QEMU_ARCH:-$TRAVIS_OS_NAME} in - i386) - dpkg --add-architecture $QEMU_ARCH - apt-get update - apt-get install -y --no-install-recommends \ - binfmt-support qemu-user-static:$QEMU_ARCH - ;; + case $TRAVIS_OS_NAME in linux) apt-get update apt-get install -y --no-install-recommends \ From a87180452ea4b9c198588b29345420ea32644997 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 20:25:16 -0500 Subject: [PATCH 0101/4206] sort targets --- library/compiler-builtins/.travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 7259cc0b11f14..e74b68002ffa9 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -5,8 +5,6 @@ sudo: required matrix: include: - - env: TARGET=powerpc64le-unknown-linux-gnu - os: linux - env: TARGET=aarch64-unknown-linux-gnu os: linux - env: TARGET=arm-unknown-linux-gnueabi @@ -29,6 +27,8 @@ matrix: os: linux - env: TARGET=powerpc64-unknown-linux-gnu os: linux + - env: TARGET=powerpc64le-unknown-linux-gnu + os: linux - env: TARGET=thumbv6m-none-eabi os: linux - env: TARGET=thumbv7em-none-eabi From 657a0cd18aa2c2e6f1925f98eac5e0b7415d27c8 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 12 Aug 2016 21:20:56 -0500 Subject: [PATCH 0102/4206] add weak `memcpy` et al symbols closes #28 --- library/compiler-builtins/src/lib.rs | 3 ++ library/compiler-builtins/src/mem.rs | 60 ++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 library/compiler-builtins/src/mem.rs diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 823170a413ec9..a802d1b9bf41e 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,10 +1,12 @@ #![allow(unused_features)] #![feature(asm)] #![feature(core_intrinsics)] +#![feature(linkage)] #![feature(naked_functions)] #![cfg_attr(not(test), no_std)] // TODO(rust-lang/rust#35021) uncomment when that PR lands // #![feature(rustc_builtins)] +#![no_builtins] // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. @@ -20,6 +22,7 @@ extern crate core; pub mod arm; pub mod udiv; +pub mod mem; pub mod mul; pub mod shift; diff --git a/library/compiler-builtins/src/mem.rs b/library/compiler-builtins/src/mem.rs new file mode 100644 index 0000000000000..7a9403404f1ca --- /dev/null +++ b/library/compiler-builtins/src/mem.rs @@ -0,0 +1,60 @@ +// NOTE Copied verbatim from the rlibc crate +// cf. https://crates.io/crates/rlibc + +#[linkage = "weak"] +#[no_mangle] +pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { + let mut i = 0; + while i < n { + *dest.offset(i as isize) = *src.offset(i as isize); + i += 1; + } + dest +} + +#[linkage = "weak"] +#[no_mangle] +pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { + if src < dest as *const u8 { + // copy from end + let mut i = n; + while i != 0 { + i -= 1; + *dest.offset(i as isize) = *src.offset(i as isize); + } + } else { + // copy from beginning + let mut i = 0; + while i < n { + *dest.offset(i as isize) = *src.offset(i as isize); + i += 1; + } + } + dest +} + +#[linkage = "weak"] +#[no_mangle] +pub unsafe extern "C" fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8 { + let mut i = 0; + while i < n { + *s.offset(i as isize) = c as u8; + i += 1; + } + s +} + +#[linkage = "weak"] +#[no_mangle] +pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { + let mut i = 0; + while i < n { + let a = *s1.offset(i as isize); + let b = *s2.offset(i as isize); + if a != b { + return a as i32 - b as i32; + } + i += 1; + } + 0 +} From a8c6135b384f0fee0605325fc982991a67f4d5ab Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 12:16:52 -0500 Subject: [PATCH 0103/4206] exclude windows and macos --- library/compiler-builtins/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index a802d1b9bf41e..2d1c8399cfbb8 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -4,9 +4,9 @@ #![feature(linkage)] #![feature(naked_functions)] #![cfg_attr(not(test), no_std)] +#![no_builtins] // TODO(rust-lang/rust#35021) uncomment when that PR lands // #![feature(rustc_builtins)] -#![no_builtins] // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. @@ -22,6 +22,7 @@ extern crate core; pub mod arm; pub mod udiv; +#[cfg(all(not(windows), not(target_os = "macos")))] pub mod mem; pub mod mul; pub mod shift; From 670f4e32aa8a509384f86e95445c810fa7d118c5 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 13 Aug 2016 12:26:58 -0500 Subject: [PATCH 0104/4206] check presence of weak symbols --- library/compiler-builtins/ci/script.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 3b00ff62aa197..c271456a9dd02 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -9,10 +9,21 @@ build() { inspect() { $PREFIX$NM -g --defined-only target/**/debug/*.rlib + set +e $PREFIX$OBJDUMP -Cd target/**/debug/*.rlib $PREFIX$OBJDUMP -Cd target/**/release/*.rlib set -e + + # Check presence of weak symbols + case $TRAVIS_OS_NAME in + linux) + local symbols=( memcmp memcpy memmove memset ) + for symbol in "${symbols[@]}"; do + $PREFIX$NM target/**/debug/*.rlib | grep -q "W $symbol" + done + ;; + esac } run_tests() { From ae75d02bdd1b0606b8c6c9857d78edb300c473c7 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 14 Aug 2016 21:59:48 -0500 Subject: [PATCH 0105/4206] use rlibc crate instead --- library/compiler-builtins/Cargo.toml | 6 +++ library/compiler-builtins/src/lib.rs | 5 ++- library/compiler-builtins/src/mem.rs | 60 ---------------------------- 3 files changed, 9 insertions(+), 62 deletions(-) delete mode 100644 library/compiler-builtins/src/mem.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index dfd1fdeeee153..48f6ee0ce3d2e 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -3,5 +3,11 @@ authors = ["Jorge Aparicio "] name = "rustc_builtins" version = "0.1.0" +[dependencies] +rlibc = { git = "https://github.com/alexcrichton/rlibc", optional = true } + [dev-dependencies] quickcheck = "0.3.1" + +[features] +default = ["rlibc/weak"] diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 2d1c8399cfbb8..7b621dd3d193e 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -18,12 +18,13 @@ extern crate quickcheck; #[cfg(test)] extern crate core; +#[cfg(all(not(windows), not(target_os = "macos")))] +extern crate rlibc; + #[cfg(target_arch = "arm")] pub mod arm; pub mod udiv; -#[cfg(all(not(windows), not(target_os = "macos")))] -pub mod mem; pub mod mul; pub mod shift; diff --git a/library/compiler-builtins/src/mem.rs b/library/compiler-builtins/src/mem.rs deleted file mode 100644 index 7a9403404f1ca..0000000000000 --- a/library/compiler-builtins/src/mem.rs +++ /dev/null @@ -1,60 +0,0 @@ -// NOTE Copied verbatim from the rlibc crate -// cf. https://crates.io/crates/rlibc - -#[linkage = "weak"] -#[no_mangle] -pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { - let mut i = 0; - while i < n { - *dest.offset(i as isize) = *src.offset(i as isize); - i += 1; - } - dest -} - -#[linkage = "weak"] -#[no_mangle] -pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { - if src < dest as *const u8 { - // copy from end - let mut i = n; - while i != 0 { - i -= 1; - *dest.offset(i as isize) = *src.offset(i as isize); - } - } else { - // copy from beginning - let mut i = 0; - while i < n { - *dest.offset(i as isize) = *src.offset(i as isize); - i += 1; - } - } - dest -} - -#[linkage = "weak"] -#[no_mangle] -pub unsafe extern "C" fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8 { - let mut i = 0; - while i < n { - *s.offset(i as isize) = c as u8; - i += 1; - } - s -} - -#[linkage = "weak"] -#[no_mangle] -pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { - let mut i = 0; - while i < n { - let a = *s1.offset(i as isize); - let b = *s2.offset(i as isize); - if a != b { - return a as i32 - b as i32; - } - i += 1; - } - 0 -} From b193bf698d25f8bf44d1eb6866dcf047fbd0266f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 14 Aug 2016 22:08:36 -0500 Subject: [PATCH 0106/4206] remove unused feature gates --- library/compiler-builtins/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 7b621dd3d193e..ed4916f249b18 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,6 +1,4 @@ -#![allow(unused_features)] #![feature(asm)] -#![feature(core_intrinsics)] #![feature(linkage)] #![feature(naked_functions)] #![cfg_attr(not(test), no_std)] From de150c17015e60f9e863857675bb269559bc4652 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 15 Aug 2016 20:22:58 -0500 Subject: [PATCH 0107/4206] adjust test: weak symbols are now in librlibc.rlib --- library/compiler-builtins/ci/script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index c271456a9dd02..75584786943f8 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -20,7 +20,7 @@ inspect() { linux) local symbols=( memcmp memcpy memmove memset ) for symbol in "${symbols[@]}"; do - $PREFIX$NM target/**/debug/*.rlib | grep -q "W $symbol" + $PREFIX$NM target/**/debug/deps/librlibc*.rlib | grep -q "W $symbol" done ;; esac From 63a87352d8e73f1e9cd41edd0ee3e1a56dc6e73e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 15 Aug 2016 21:08:04 -0500 Subject: [PATCH 0108/4206] add core_intrinsics feature gate --- library/compiler-builtins/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index ed4916f249b18..2263fda000334 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,4 +1,5 @@ #![feature(asm)] +#![feature(core_intrinsics)] #![feature(linkage)] #![feature(naked_functions)] #![cfg_attr(not(test), no_std)] From f0dbe4c07c16c42e049ee12509e48d04cbe45d74 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Tue, 16 Aug 2016 17:46:46 -0500 Subject: [PATCH 0109/4206] Add x86_64 builtins --- library/compiler-builtins/src/lib.rs | 3 ++ library/compiler-builtins/src/x86_64.rs | 67 +++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 library/compiler-builtins/src/x86_64.rs diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 2263fda000334..7941b201eb140 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -23,6 +23,9 @@ extern crate rlibc; #[cfg(target_arch = "arm")] pub mod arm; +#[cfg(target_arch = "x86_64")] +pub mod x86_64; + pub mod udiv; pub mod mul; pub mod shift; diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs new file mode 100644 index 0000000000000..5df365c593182 --- /dev/null +++ b/library/compiler-builtins/src/x86_64.rs @@ -0,0 +1,67 @@ +use core::intrinsics; + +// NOTE These functions are implemented using assembly because they using a custom +// calling convention which can't be implemented using a normal Rust function +#[cfg(windows)] +#[naked] +#[cfg_attr(not(test), no_mangle)] +pub unsafe fn ___chkstk_ms() { + asm!("push %rcx + push %rax + cmp $$0x1000,%rax + lea 24(%rsp),%rcx + jb 1f + 2: + sub $$0x1000,%rcx + test %rcx,(%rcx) + sub $$0x1000,%rax + cmp $$0x1000,%rax + ja 2b + 1: + sub %rax,%rcx + test %rcx,(%rcx) + pop %rax + pop %rcx + ret"); + intrinsics::unreachable(); +} + +#[cfg(windows)] +#[naked] +#[cfg_attr(not(test), no_mangle)] +pub unsafe fn __alloca() { + asm!("mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx"); + // The original behavior had __alloca fall through to ___chkstk here, but + // I don't believe that this behavior is guaranteed, and a program that uses + // only __alloca could have ___chkstk removed by --gc-sections. Call + // ___chkstk here to guarantee that neither of those happen. + ___chkstk(); +} + +#[cfg(windows)] +#[naked] +#[cfg_attr(not(test), no_mangle)] +pub unsafe fn ___chkstk() { + asm!("push %rcx + cmp $$0x1000,%rax + lea 16(%rsp),%rcx // rsp before calling this routine -> rcx + jb 1f + 2: + sub $$0x1000,%rcx + test %rcx,(%rcx) + sub $$0x1000,%rax + cmp $$0x1000,%rax + ja 2b + 1: + sub %rax,%rcx + test %rcx,(%rcx) + + lea 8(%rsp),%rax // load pointer to the return address into rax + mov %rcx,%rsp // install the new top of stack pointer into rsp + mov -8(%rax),%rcx // restore rcx + push (%rax) // push return address onto the stack + sub %rsp,%rax // restore the original value in rax + ret"); + intrinsics::unreachable(); +} + From 7e238f997391be1ea5baf5e947eb99dcaf496ae2 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Wed, 17 Aug 2016 12:11:38 -0500 Subject: [PATCH 0110/4206] Use `jmp` to implement __alloca fallthrough --- library/compiler-builtins/src/x86_64.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 5df365c593182..8368593d66533 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -30,12 +30,9 @@ pub unsafe fn ___chkstk_ms() { #[naked] #[cfg_attr(not(test), no_mangle)] pub unsafe fn __alloca() { - asm!("mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx"); - // The original behavior had __alloca fall through to ___chkstk here, but - // I don't believe that this behavior is guaranteed, and a program that uses - // only __alloca could have ___chkstk removed by --gc-sections. Call - // ___chkstk here to guarantee that neither of those happen. - ___chkstk(); + asm!("mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx + jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable"); + intrinsics::unreachable(); } #[cfg(windows)] From 22331947eabea06e12d906a08d6c5afe27b1b3a3 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Wed, 17 Aug 2016 12:53:56 -0500 Subject: [PATCH 0111/4206] Disable mangling for msvc stack builtins This prevents linker errors in test builds due to the `jmp` instruction in __alloca --- library/compiler-builtins/src/x86_64.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 8368593d66533..8bc33096dfcd4 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -2,9 +2,13 @@ use core::intrinsics; // NOTE These functions are implemented using assembly because they using a custom // calling convention which can't be implemented using a normal Rust function + +// NOTE These functions are never mangled as they are not tested against compiler-rt +// and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca + #[cfg(windows)] #[naked] -#[cfg_attr(not(test), no_mangle)] +#[no_mangle] pub unsafe fn ___chkstk_ms() { asm!("push %rcx push %rax @@ -28,7 +32,7 @@ pub unsafe fn ___chkstk_ms() { #[cfg(windows)] #[naked] -#[cfg_attr(not(test), no_mangle)] +#[no_mangle] pub unsafe fn __alloca() { asm!("mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable"); @@ -37,7 +41,7 @@ pub unsafe fn __alloca() { #[cfg(windows)] #[naked] -#[cfg_attr(not(test), no_mangle)] +#[no_mangle] pub unsafe fn ___chkstk() { asm!("push %rcx cmp $$0x1000,%rax From 0ce86ac501cc5fe4ec172385a8cf6bc5ef7a1378 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Wed, 17 Aug 2016 13:12:06 -0500 Subject: [PATCH 0112/4206] Appveyor: Source vcvarsall to get dumpbin in path --- library/compiler-builtins/appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 06255fa1d4318..77f69590ca725 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -17,6 +17,7 @@ test_script: - cargo build --release - cargo test - cargo test --release + - CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" - dumpbin /disasm target/debug/librustc_builtins.rlib - dumpbin /disasm target/release/librustc_builtins.rlib From 77ffc1f9a0ad15dadd8748d5ab4d452c9a84d8c8 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Wed, 17 Aug 2016 13:56:35 -0500 Subject: [PATCH 0113/4206] Appveyor: Ignore errors from dumpbin parsing rlib --- library/compiler-builtins/appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 77f69590ca725..4bb03def78278 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -18,8 +18,8 @@ test_script: - cargo test - cargo test --release - CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" - - dumpbin /disasm target/debug/librustc_builtins.rlib - - dumpbin /disasm target/release/librustc_builtins.rlib + - dumpbin /disasm target/debug/librustc_builtins.rlib || exit 0 + - dumpbin /disasm target/release/librustc_builtins.rlib || exit 0 branches: only: From f9c8ca854a33a8a95126fea9a601500984419785 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Wed, 17 Aug 2016 14:35:48 -0500 Subject: [PATCH 0114/4206] Check off x86_64 builtins in README [ci ignore] --- library/compiler-builtins/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 73a25e9d7dce9..4ff8b45865130 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -133,8 +133,8 @@ See [rust-lang/rust#35437][0]. - [x] udivsi3.c - [x] umoddi3.c - [x] umodsi3.c -- [ ] x86_64/chkstk.S -- [ ] x86_64/chkstk2.S +- [x] x86_64/chkstk.S +- [x] x86_64/chkstk2.S These builtins are needed to support 128-bit integers, which are in the process of being added to Rust. From 3fddb6b427bbbfc44254d1c9d151d50f6716f01c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 18 Aug 2016 21:27:16 -0500 Subject: [PATCH 0115/4206] rename muldi4 to muldi3 closes #42 --- library/compiler-builtins/src/mul.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/mul.rs b/library/compiler-builtins/src/mul.rs index 77dba26ec3c74..cb313964b8bc9 100644 --- a/library/compiler-builtins/src/mul.rs +++ b/library/compiler-builtins/src/mul.rs @@ -66,7 +66,7 @@ macro_rules! mulo { } } -mul!(__muldi4: u64); +mul!(__muldi3: u64); mulo!(__mulosi4: i32); mulo!(__mulodi4: i64); @@ -77,7 +77,7 @@ mod tests { quickcheck! { fn muldi(a: U64, b: U64) -> bool { let (a, b) = (a.0, b.0); - let r = super::__muldi4(a, b); + let r = super::__muldi3(a, b); r == a.wrapping_mul(b) } From 161234b8b30fb443c7a7a6d3be869833ab1803a5 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 18 Aug 2016 17:20:24 +0100 Subject: [PATCH 0116/4206] Add signed division functions --- library/compiler-builtins/README.md | 24 ++--- library/compiler-builtins/src/arm.rs | 40 +++++++- library/compiler-builtins/src/lib.rs | 1 + library/compiler-builtins/src/mul.rs | 4 +- library/compiler-builtins/src/sdiv.rs | 121 +++++++++++++++++++++++++ library/compiler-builtins/src/shift.rs | 6 +- 6 files changed, 178 insertions(+), 18 deletions(-) create mode 100644 library/compiler-builtins/src/sdiv.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 73a25e9d7dce9..9199c963377ea 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -40,9 +40,9 @@ See [rust-lang/rust#35437][0]. - [x] arm/aeabi_uidivmod.S - [x] arm/aeabi_uldivmod.S - [ ] arm/divdf3vfp.S -- [ ] arm/divmodsi4.S +- [ ] arm/divmodsi4.S (generic version is done) - [ ] arm/divsf3vfp.S -- [ ] arm/divsi3.S +- [ ] arm/divsi3.S (generic version is done) - [ ] arm/eqdf2vfp.S - [ ] arm/eqsf2vfp.S - [ ] arm/extendsfdf2vfp.S @@ -62,7 +62,7 @@ See [rust-lang/rust#35437][0]. - [ ] arm/lesf2vfp.S - [ ] arm/ltdf2vfp.S - [ ] arm/ltsf2vfp.S -- [ ] arm/modsi3.S +- [ ] arm/modsi3.S (generic version is done) - [ ] arm/muldf3vfp.S - [ ] arm/mulsf3vfp.S - [ ] arm/nedf2vfp.S @@ -73,17 +73,19 @@ See [rust-lang/rust#35437][0]. - [ ] arm/subdf3vfp.S - [ ] arm/subsf3vfp.S - [ ] arm/truncdfsf2vfp.S -- [ ] arm/udivmodsi4.S -- [ ] arm/udivsi3.S -- [ ] arm/umodsi3.S +- [ ] arm/udivmodsi4.S (generic version is done) +- [ ] arm/udivsi3.S (generic version is done) +- [ ] arm/umodsi3.S (generic version is done) - [ ] arm/unorddf2vfp.S - [ ] arm/unordsf2vfp.S - [x] ashldi3.c - [x] ashrdi3.c - [ ] divdf3.c -- [ ] divdi3.c +- [x] divdi3.c +- [x] divmoddi4.c +- [x] divmodsi4.c - [ ] divsf3.c -- [ ] divsi3.c +- [x] divsi3.c - [ ] extendhfsf2.c - [ ] extendsfdf2.c - [ ] fixdfdi.c @@ -113,8 +115,8 @@ See [rust-lang/rust#35437][0]. - [ ] i386/udivdi3.S - [ ] i386/umoddi3.S - [x] lshrdi3.c -- [ ] moddi3.c -- [ ] modsi3.c +- [x] moddi3.c +- [x] modsi3.c - [ ] muldf3.c - [x] muldi3.c - [x] mulodi4.c @@ -251,8 +253,6 @@ These builtins are never called by LLVM. - ~~ctzdi2.c~~ - ~~ctzsi2.c~~ - ~~ctzti2.c~~ -- ~~divmoddi4.c~~ -- ~~divmodsi4.c~~ - ~~ffsdi2.c~~ - ~~ffsti2.c~~ - ~~mulvdi3.c~~ diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index ad2b39a27f32c..285871f15e59f 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,6 +1,6 @@ use core::intrinsics; -// NOTE This function and the one below are implemented using assembly because they using a custom +// NOTE This function and the ones below are implemented using assembly because they using a custom // calling convention which can't be implemented using a normal Rust function #[naked] #[cfg_attr(not(test), no_mangle)] @@ -30,6 +30,44 @@ pub unsafe fn __aeabi_uldivmod() { intrinsics::unreachable(); } +#[naked] +#[cfg_attr(not(test), no_mangle)] +pub unsafe fn __aeabi_idivmod() { + asm!("push {r0, r1, r4, lr} + bl __divsi3 + pop {r1, r2} + muls r2, r2, r0 + subs r1, r1, r2 + pop {r4, pc}"); + intrinsics::unreachable(); +} + +#[naked] +#[cfg_attr(not(test), no_mangle)] +pub unsafe fn __aeabi_ldivmod() { + asm!("push {r4, lr} + sub sp, sp, #16 + add r4, sp, #8 + str r4, [sp] + bl __divmoddi4 + ldr r2, [sp, #8] + ldr r3, [sp, #12] + add sp, sp, #16 + pop {r4, pc}"); + intrinsics::unreachable(); +} + +// TODO: These two functions should be defined as aliases +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __aeabi_uidiv(a: u32, b: u32) -> u32 { + ::udiv::__udivsi3(a, b) +} + +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __aeabi_idiv(a: i32, b: i32) -> i32 { + ::sdiv::__divsi3(a, b) +} + extern "C" { fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 2263fda000334..e61a75d88df10 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -24,6 +24,7 @@ extern crate rlibc; pub mod arm; pub mod udiv; +pub mod sdiv; pub mod mul; pub mod shift; diff --git a/library/compiler-builtins/src/mul.rs b/library/compiler-builtins/src/mul.rs index 77dba26ec3c74..73c1a6f78ddcb 100644 --- a/library/compiler-builtins/src/mul.rs +++ b/library/compiler-builtins/src/mul.rs @@ -4,7 +4,7 @@ macro_rules! mul { ($intrinsic:ident: $ty:ty) => { /// Returns `a * b` #[cfg_attr(not(test), no_mangle)] - pub extern fn $intrinsic(a: $ty, b: $ty) -> $ty { + pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { let half_bits = <$ty>::bits() / 4; let lower_mask = !0 >> half_bits; let mut low = (a.low() & lower_mask) * (b.low() & lower_mask); @@ -29,7 +29,7 @@ macro_rules! mulo { ($intrinsic:ident: $ty:ty) => { /// Returns `a * b` and sets `*overflow = 1` if `a * b` overflows #[cfg_attr(not(test), no_mangle)] - pub extern fn $intrinsic(a: $ty, b: $ty, overflow: &mut i32) -> $ty { + pub extern "C" fn $intrinsic(a: $ty, b: $ty, overflow: &mut i32) -> $ty { *overflow = 0; let result = a.wrapping_mul(b); if a == <$ty>::min_value() { diff --git a/library/compiler-builtins/src/sdiv.rs b/library/compiler-builtins/src/sdiv.rs new file mode 100644 index 0000000000000..b1231618b79b2 --- /dev/null +++ b/library/compiler-builtins/src/sdiv.rs @@ -0,0 +1,121 @@ +use Int; + +macro_rules! div { + ($intrinsic:ident: $ty:ty, $uty:ty) => { + /// Returns `a / b` + #[cfg_attr(not(test), no_mangle)] + pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { + let s_a = a >> (<$ty>::bits() - 1); + let s_b = b >> (<$ty>::bits() - 1); + let a = (a ^ s_a) - s_a; + let b = (b ^ s_b) - s_b; + let s = s_a ^ s_b; + let r = (a as $uty) / (b as $uty); + (r as $ty ^ s) - s + } + } +} + +macro_rules! mod_ { + ($intrinsic:ident: $ty:ty, $uty:ty) => { + /// Returns `a % b` + #[cfg_attr(not(test), no_mangle)] + pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { + let s = b >> (<$ty>::bits() - 1); + let b = (b ^ s) - s; + let s = a >> (<$ty>::bits() - 1); + let a = (a ^ s) - s; + let r = (a as $uty) % (b as $uty); + (r as $ty ^ s) - s + } + } +} + +macro_rules! divmod { + ($intrinsic:ident, $div:ident: $ty:ty) => { + /// Returns `a / b` and sets `*rem = n % d` + #[cfg_attr(not(test), no_mangle)] + pub extern "C" fn $intrinsic(a: $ty, b: $ty, rem: &mut $ty) -> $ty { + let r = $div(a, b); + *rem = a - (r * b); + r + } + } +} + +div!(__divsi3: i32, u32); +div!(__divdi3: i64, u64); +mod_!(__modsi3: i32, u32); +mod_!(__moddi3: i64, u64); +divmod!(__divmodsi4, __divsi3: i32); +divmod!(__divmoddi4, __divdi3: i64); + +#[cfg(test)] +mod tests { + use quickcheck::TestResult; + use qc::{U32, U64}; + + quickcheck!{ + fn divdi3(n: U64, d: U64) -> TestResult { + let (n, d) = (n.0 as i64, d.0 as i64); + if d == 0 { + TestResult::discard() + } else { + let q = super::__divdi3(n, d); + TestResult::from_bool(q == n / d) + } + } + + fn moddi3(n: U64, d: U64) -> TestResult { + let (n, d) = (n.0 as i64, d.0 as i64); + if d == 0 { + TestResult::discard() + } else { + let r = super::__moddi3(n, d); + TestResult::from_bool(r == n % d) + } + } + + fn divmoddi4(n: U64, d: U64) -> TestResult { + let (n, d) = (n.0 as i64, d.0 as i64); + if d == 0 { + TestResult::discard() + } else { + let mut r = 0; + let q = super::__divmoddi4(n, d, &mut r); + TestResult::from_bool(q == n / d && r == n % d) + } + } + + fn divsi3(n: U32, d: U32) -> TestResult { + let (n, d) = (n.0 as i32, d.0 as i32); + if d == 0 { + TestResult::discard() + } else { + let q = super::__divsi3(n, d); + TestResult::from_bool(q == n / d) + } + } + + fn modsi3(n: U32, d: U32) -> TestResult { + let (n, d) = (n.0 as i32, d.0 as i32); + if d == 0 { + TestResult::discard() + } else { + let r = super::__modsi3(n, d); + TestResult::from_bool(r == n % d) + } + } + + fn divmodsi4(n: U32, d: U32) -> TestResult { + let (n, d) = (n.0 as i32, d.0 as i32); + if d == 0 { + TestResult::discard() + } else { + let mut r = 0; + let q = super::__divmodsi4(n, d, &mut r); + TestResult::from_bool(q == n / d && r == n % d) + } + } + } +} diff --git a/library/compiler-builtins/src/shift.rs b/library/compiler-builtins/src/shift.rs index 7fa88abffb24e..ccbfe13fae083 100644 --- a/library/compiler-builtins/src/shift.rs +++ b/library/compiler-builtins/src/shift.rs @@ -4,7 +4,7 @@ macro_rules! ashl { ($intrinsic:ident: $ty:ty) => { /// Returns `a << b`, requires `b < $ty::bits()` #[cfg_attr(not(test), no_mangle)] - pub extern fn $intrinsic(a: $ty, b: u32) -> $ty { + pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { let half_bits = <$ty>::bits() / 2; if b & half_bits != 0 { <$ty>::from_parts(0, a.low() << (b - half_bits)) @@ -21,7 +21,7 @@ macro_rules! ashr { ($intrinsic:ident: $ty:ty) => { /// Returns arithmetic `a >> b`, requires `b < $ty::bits()` #[cfg_attr(not(test), no_mangle)] - pub extern fn $intrinsic(a: $ty, b: u32) -> $ty { + pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { let half_bits = <$ty>::bits() / 2; if b & half_bits != 0 { <$ty>::from_parts((a.high() >> (b - half_bits)) as <$ty as LargeInt>::LowHalf, @@ -41,7 +41,7 @@ macro_rules! lshr { ($intrinsic:ident: $ty:ty) => { /// Returns logical `a >> b`, requires `b < $ty::bits()` #[cfg_attr(not(test), no_mangle)] - pub extern fn $intrinsic(a: $ty, b: u32) -> $ty { + pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { let half_bits = <$ty>::bits() / 2; if b & half_bits != 0 { <$ty>::from_parts(a.high() >> (b - half_bits), 0) From 59fe09c493d03174f50ef08d902a355602c8ebd8 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 19 Aug 2016 12:12:07 +0100 Subject: [PATCH 0117/4206] Add tests for ARM division builtins --- library/compiler-builtins/src/arm.rs | 81 ++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 285871f15e59f..4555d5b1302e2 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -128,3 +128,84 @@ pub unsafe extern "C" fn __aeabi_memclr4(dest: *mut u8, n: usize) { pub unsafe extern "C" fn __aeabi_memclr8(dest: *mut u8, n: usize) { memset(dest, 0, n); } + + +#[cfg(test)] +mod tests { + use quickcheck::TestResult; + use qc::{U32, U64}; + + quickcheck!{ + fn uldivmod(n: U64, d: U64) -> TestResult { + let (n, d) = (n.0, d.0); + if d == 0 { + TestResult::discard() + } else { + let q: u64; + let r: u64; + unsafe { + // The inline asm is a bit tricky here, LLVM will allocate + // both r0 and r1 when we specify a 64-bit value for {r0}. + asm!("bl __aeabi_uldivmod" + : "={r0}" (q), "={r2}" (r) + : "{r0}" (n), "{r2}" (d) + : "r12", "lr", "flags"); + } + TestResult::from_bool(q == n / d && r == n % d) + } + } + + fn uidivmod(n: U32, d: U32) -> TestResult { + let (n, d) = (n.0, d.0); + if d == 0 { + TestResult::discard() + } else { + let q: u32; + let r: u32; + unsafe { + asm!("bl __aeabi_uidivmod" + : "={r0}" (q), "={r1}" (r) + : "{r0}" (n), "{r1}" (d) + : "r2", "r3", "r12", "lr", "flags"); + } + TestResult::from_bool(q == n / d && r == n % d) + } + } + + fn ldivmod(n: U64, d: U64) -> TestResult { + let (n, d) = (n.0 as i64, d.0 as i64); + if d == 0 { + TestResult::discard() + } else { + let q: i64; + let r: i64; + unsafe { + // The inline asm is a bit tricky here, LLVM will allocate + // both r0 and r1 when we specify a 64-bit value for {r0}. + asm!("bl __aeabi_ldivmod" + : "={r0}" (q), "={r2}" (r) + : "{r0}" (n), "{r2}" (d) + : "r12", "lr", "flags"); + } + TestResult::from_bool(q == n / d && r == n % d) + } + } + + fn idivmod(n: U32, d: U32) -> TestResult { + let (n, d) = (n.0 as i32, d.0 as i32); + if d == 0 { + TestResult::discard() + } else { + let q: i32; + let r: i32; + unsafe { + asm!("bl __aeabi_idivmod" + : "={r0}" (q), "={r1}" (r) + : "{r0}" (n), "{r1}" (d) + : "r2", "r3", "r12", "lr", "flags"); + } + TestResult::from_bool(q == n / d && r == n % d) + } + } + } +} From 35d68d8ab23069005002dd2107219f867917f0fc Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Wed, 17 Aug 2016 15:50:24 -0500 Subject: [PATCH 0118/4206] Move integer functions to separate module --- library/compiler-builtins/src/arm.rs | 4 +- library/compiler-builtins/src/int/mod.rs | 73 +++++++++++++++++++ .../compiler-builtins/src/{ => int}/mul.rs | 2 +- .../compiler-builtins/src/{ => int}/sdiv.rs | 2 +- .../compiler-builtins/src/{ => int}/shift.rs | 2 +- .../compiler-builtins/src/{ => int}/udiv.rs | 2 +- library/compiler-builtins/src/lib.rs | 73 +------------------ library/compiler-builtins/src/qc.rs | 2 +- 8 files changed, 82 insertions(+), 78 deletions(-) create mode 100644 library/compiler-builtins/src/int/mod.rs rename library/compiler-builtins/src/{ => int}/mul.rs (99%) rename library/compiler-builtins/src/{ => int}/sdiv.rs (99%) rename library/compiler-builtins/src/{ => int}/shift.rs (99%) rename library/compiler-builtins/src/{ => int}/udiv.rs (99%) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 4555d5b1302e2..b46b0ea77f59f 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -60,12 +60,12 @@ pub unsafe fn __aeabi_ldivmod() { // TODO: These two functions should be defined as aliases #[cfg_attr(not(test), no_mangle)] pub extern "C" fn __aeabi_uidiv(a: u32, b: u32) -> u32 { - ::udiv::__udivsi3(a, b) + ::int::udiv::__udivsi3(a, b) } #[cfg_attr(not(test), no_mangle)] pub extern "C" fn __aeabi_idiv(a: i32, b: i32) -> i32 { - ::sdiv::__divsi3(a, b) + ::int::sdiv::__divsi3(a, b) } extern "C" { diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs new file mode 100644 index 0000000000000..37e05377a2e56 --- /dev/null +++ b/library/compiler-builtins/src/int/mod.rs @@ -0,0 +1,73 @@ + +pub mod mul; +pub mod sdiv; +pub mod shift; +pub mod udiv; + +/// Trait for some basic operations on integers +pub trait Int { + /// Returns the bitwidth of the int type + fn bits() -> u32; +} + +// TODO: Once i128/u128 support lands, we'll want to add impls for those as well +impl Int for u32 { + fn bits() -> u32 { + 32 + } +} +impl Int for i32 { + fn bits() -> u32 { + 32 + } +} +impl Int for u64 { + fn bits() -> u32 { + 64 + } +} +impl Int for i64 { + fn bits() -> u32 { + 64 + } +} + +/// Trait to convert an integer to/from smaller parts +pub trait LargeInt { + type LowHalf; + type HighHalf; + + fn low(self) -> Self::LowHalf; + fn high(self) -> Self::HighHalf; + fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self; +} + +// TODO: Once i128/u128 support lands, we'll want to add impls for those as well +impl LargeInt for u64 { + type LowHalf = u32; + type HighHalf = u32; + + fn low(self) -> u32 { + self as u32 + } + fn high(self) -> u32 { + (self >> 32) as u32 + } + fn from_parts(low: u32, high: u32) -> u64 { + low as u64 | ((high as u64) << 32) + } +} +impl LargeInt for i64 { + type LowHalf = u32; + type HighHalf = i32; + + fn low(self) -> u32 { + self as u32 + } + fn high(self) -> i32 { + (self >> 32) as i32 + } + fn from_parts(low: u32, high: i32) -> i64 { + low as i64 | ((high as i64) << 32) + } +} diff --git a/library/compiler-builtins/src/mul.rs b/library/compiler-builtins/src/int/mul.rs similarity index 99% rename from library/compiler-builtins/src/mul.rs rename to library/compiler-builtins/src/int/mul.rs index 2c4ce52ed93b5..3d6844473b935 100644 --- a/library/compiler-builtins/src/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -1,4 +1,4 @@ -use {Int, LargeInt}; +use int::{Int, LargeInt}; macro_rules! mul { ($intrinsic:ident: $ty:ty) => { diff --git a/library/compiler-builtins/src/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs similarity index 99% rename from library/compiler-builtins/src/sdiv.rs rename to library/compiler-builtins/src/int/sdiv.rs index b1231618b79b2..72ddbca5d5b95 100644 --- a/library/compiler-builtins/src/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -1,4 +1,4 @@ -use Int; +use int::Int; macro_rules! div { ($intrinsic:ident: $ty:ty, $uty:ty) => { diff --git a/library/compiler-builtins/src/shift.rs b/library/compiler-builtins/src/int/shift.rs similarity index 99% rename from library/compiler-builtins/src/shift.rs rename to library/compiler-builtins/src/int/shift.rs index ccbfe13fae083..96ae6dbad2513 100644 --- a/library/compiler-builtins/src/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -1,4 +1,4 @@ -use {Int, LargeInt}; +use int::{Int, LargeInt}; macro_rules! ashl { ($intrinsic:ident: $ty:ty) => { diff --git a/library/compiler-builtins/src/udiv.rs b/library/compiler-builtins/src/int/udiv.rs similarity index 99% rename from library/compiler-builtins/src/udiv.rs rename to library/compiler-builtins/src/int/udiv.rs index 82932e313144f..f3ec720c105c7 100644 --- a/library/compiler-builtins/src/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -1,5 +1,5 @@ use core::mem; -use {Int, LargeInt}; +use int::{Int, LargeInt}; /// Returns `n / d` #[cfg_attr(not(test), no_mangle)] diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 1351c3896858e..b817d74fda60c 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -20,83 +20,14 @@ extern crate core; #[cfg(all(not(windows), not(target_os = "macos")))] extern crate rlibc; +pub mod int; + #[cfg(target_arch = "arm")] pub mod arm; #[cfg(target_arch = "x86_64")] pub mod x86_64; -pub mod udiv; -pub mod sdiv; -pub mod mul; -pub mod shift; - #[cfg(test)] mod qc; -/// Trait for some basic operations on integers -trait Int { - fn bits() -> u32; -} - -// TODO: Once i128/u128 support lands, we'll want to add impls for those as well -impl Int for u32 { - fn bits() -> u32 { - 32 - } -} -impl Int for i32 { - fn bits() -> u32 { - 32 - } -} -impl Int for u64 { - fn bits() -> u32 { - 64 - } -} -impl Int for i64 { - fn bits() -> u32 { - 64 - } -} - -/// Trait to convert an integer to/from smaller parts -trait LargeInt { - type LowHalf; - type HighHalf; - - fn low(self) -> Self::LowHalf; - fn high(self) -> Self::HighHalf; - fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self; -} - -// TODO: Once i128/u128 support lands, we'll want to add impls for those as well -impl LargeInt for u64 { - type LowHalf = u32; - type HighHalf = u32; - - fn low(self) -> u32 { - self as u32 - } - fn high(self) -> u32 { - (self >> 32) as u32 - } - fn from_parts(low: u32, high: u32) -> u64 { - low as u64 | ((high as u64) << 32) - } -} -impl LargeInt for i64 { - type LowHalf = u32; - type HighHalf = i32; - - fn low(self) -> u32 { - self as u32 - } - fn high(self) -> i32 { - (self >> 32) as i32 - } - fn from_parts(low: u32, high: i32) -> i64 { - low as i64 | ((high as i64) << 32) - } -} diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs index 6b37cceb7fd45..eccde7650cc0c 100644 --- a/library/compiler-builtins/src/qc.rs +++ b/library/compiler-builtins/src/qc.rs @@ -8,7 +8,7 @@ use std::fmt; use quickcheck::{Arbitrary, Gen}; -use LargeInt; +use int::LargeInt; // Generates values in the full range of the integer type macro_rules! arbitrary { From fe3c35131f7a83e2b2245bd462b77749b9010bfc Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Wed, 17 Aug 2016 15:51:37 -0500 Subject: [PATCH 0119/4206] Implement soft float add builtins --- library/compiler-builtins/README.md | 4 +- library/compiler-builtins/src/float/add.rs | 326 +++++++++++++++++++++ library/compiler-builtins/src/float/mod.rs | 65 ++++ library/compiler-builtins/src/lib.rs | 1 + 4 files changed, 394 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/src/float/add.rs create mode 100644 library/compiler-builtins/src/float/mod.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 8f229a1370df5..67e7b25433e9e 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -26,8 +26,8 @@ See [rust-lang/rust#35437][0]. ## Progress -- [ ] adddf3.c -- [ ] addsf3.c +- [x] adddf3.c +- [x] addsf3.c - [ ] arm/adddf3vfp.S - [ ] arm/addsf3vfp.S - [ ] arm/aeabi_dcmp.S diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs new file mode 100644 index 0000000000000..3fffac35d7b54 --- /dev/null +++ b/library/compiler-builtins/src/float/add.rs @@ -0,0 +1,326 @@ +use core::num::Wrapping; +use float::Float; + +macro_rules! add { + ($intrinsic:ident: $ty:ty) => { + /// Returns `a + b` + #[allow(unused_parens)] + #[cfg_attr(not(test), no_mangle)] + pub extern fn $intrinsic(a: $ty, b: $ty) -> $ty { + let one = Wrapping(1 as <$ty as Float>::Int); + let zero = Wrapping(0 as <$ty as Float>::Int); + + let bits = Wrapping(<$ty>::bits() as <$ty as Float>::Int); + let significand_bits = Wrapping(<$ty>::significand_bits() as <$ty as Float>::Int); + let exponent_bits = bits - significand_bits - one; + let max_exponent = (one << exponent_bits.0 as usize) - one; + + let implicit_bit = one << significand_bits.0 as usize; + let significand_mask = implicit_bit - one; + let sign_bit = one << (significand_bits + exponent_bits).0 as usize; + let abs_mask = sign_bit - one; + let exponent_mask = abs_mask ^ significand_mask; + let inf_rep = exponent_mask; + let quiet_bit = implicit_bit >> 1; + let qnan_rep = exponent_mask | quiet_bit; + + let mut a_rep = Wrapping(a.repr()); + let mut b_rep = Wrapping(b.repr()); + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; + + // Detect if a or b is zero, infinity, or NaN. + if a_abs - one >= inf_rep - one || + b_abs - one >= inf_rep - one { + // NaN + anything = qNaN + if a_abs > inf_rep { + return (<$ty as Float>::from_repr((a_abs | quiet_bit).0)); + } + // anything + NaN = qNaN + if b_abs > inf_rep { + return (<$ty as Float>::from_repr((b_abs | quiet_bit).0)); + } + + if a_abs == inf_rep { + // +/-infinity + -/+infinity = qNaN + if (a.repr() ^ b.repr()) == sign_bit.0 { + return (<$ty as Float>::from_repr(qnan_rep.0)); + } else { + // +/-infinity + anything remaining = +/- infinity + return a; + } + } + + // anything remaining + +/-infinity = +/-infinity + if b_abs == inf_rep { + return b; + } + + // zero + anything = anything + if a_abs.0 == 0 { + // but we need to get the sign right for zero + zero + if b_abs.0 == 0 { + return (<$ty as Float>::from_repr(a.repr() & b.repr())); + } else { + return b; + } + } + + // anything + zero = anything + if b_abs.0 == 0 { + return a; + } + } + + // Swap a and b if necessary so that a has the larger absolute value. + if b_abs > a_abs { + let temp = a_rep; + a_rep = b_rep; + b_rep = temp; + } + + // Extract the exponent and significand from the (possibly swapped) a and b. + let mut a_exponent = Wrapping((a_rep >> significand_bits.0 as usize & max_exponent).0 as i32); + let mut b_exponent = Wrapping((b_rep >> significand_bits.0 as usize & max_exponent).0 as i32); + let mut a_significand = a_rep & significand_mask; + let mut b_significand = b_rep & significand_mask; + + // normalize any denormals, and adjust the exponent accordingly. + if a_exponent.0 == 0 { + let (exponent, significand) = <$ty>::normalize(a_significand.0); + a_exponent = Wrapping(exponent); + a_significand = Wrapping(significand); + } + if b_exponent.0 == 0 { + let (exponent, significand) = <$ty>::normalize(b_significand.0); + b_exponent = Wrapping(exponent); + b_significand = Wrapping(significand); + } + + // The sign of the result is the sign of the larger operand, a. If they + // have opposite signs, we are performing a subtraction; otherwise addition. + let result_sign = a_rep & sign_bit; + let subtraction = ((a_rep ^ b_rep) & sign_bit) != zero; + + // Shift the significands to give us round, guard and sticky, and or in the + // implicit significand bit. (If we fell through from the denormal path it + // was already set by normalize(), but setting it twice won't hurt + // anything.) + a_significand = (a_significand | implicit_bit) << 3; + b_significand = (b_significand | implicit_bit) << 3; + + // Shift the significand of b by the difference in exponents, with a sticky + // bottom bit to get rounding correct. + let align = Wrapping((a_exponent - b_exponent).0 as <$ty as Float>::Int); + if align.0 != 0 { + if align < bits { + let sticky = ((b_significand << (bits - align).0 as usize).0 != 0) as <$ty as Float>::Int; + b_significand = (b_significand >> align.0 as usize) | Wrapping(sticky); + } else { + b_significand = one; // sticky; b is known to be non-zero. + } + } + if subtraction { + a_significand -= b_significand; + // If a == -b, return +zero. + if a_significand.0 == 0 { + return (<$ty as Float>::from_repr(0)); + } + + // If partial cancellation occured, we need to left-shift the result + // and adjust the exponent: + if a_significand < implicit_bit << 3 { + let shift = a_significand.0.leading_zeros() as i32 + - (implicit_bit << 3).0.leading_zeros() as i32; + a_significand <<= shift as usize; + a_exponent -= Wrapping(shift); + } + } else /* addition */ { + a_significand += b_significand; + + // If the addition carried up, we need to right-shift the result and + // adjust the exponent: + if (a_significand & implicit_bit << 4).0 != 0 { + let sticky = ((a_significand & one).0 != 0) as <$ty as Float>::Int; + a_significand = a_significand >> 1 | Wrapping(sticky); + a_exponent += Wrapping(1); + } + } + + // If we have overflowed the type, return +/- infinity: + if a_exponent >= Wrapping(max_exponent.0 as i32) { + return (<$ty>::from_repr((inf_rep | result_sign).0)); + } + + if a_exponent.0 <= 0 { + // Result is denormal before rounding; the exponent is zero and we + // need to shift the significand. + let shift = Wrapping((Wrapping(1) - a_exponent).0 as <$ty as Float>::Int); + let sticky = ((a_significand << (bits - shift).0 as usize).0 != 0) as <$ty as Float>::Int; + a_significand = a_significand >> shift.0 as usize | Wrapping(sticky); + a_exponent = Wrapping(0); + } + + // Low three bits are round, guard, and sticky. + let round_guard_sticky: i32 = (a_significand.0 & 0x7) as i32; + + // Shift the significand into place, and mask off the implicit bit. + let mut result = a_significand >> 3 & significand_mask; + + // Insert the exponent and sign. + result |= Wrapping(a_exponent.0 as <$ty as Float>::Int) << significand_bits.0 as usize; + result |= result_sign; + + // Final rounding. The result may overflow to infinity, but that is the + // correct result in that case. + if round_guard_sticky > 0x4 { result += one; } + if round_guard_sticky == 0x4 { result += result & one; } + return (<$ty>::from_repr(result.0)); + } + } +} + +add!(__addsf3: f32); +add!(__adddf3: f64); + +// FIXME: Implement these using aliases +#[cfg(target_arch = "arm")] +#[cfg_attr(not(test), no_mangle)] +pub extern fn __aeabi_dadd(a: f64, b: f64) -> f64 { + __adddf3(a, b) +} + +#[cfg(target_arch = "arm")] +#[cfg_attr(not(test), no_mangle)] +pub extern fn __aeabi_fadd(a: f32, b: f32) -> f32 { + __addsf3(a, b) +} + +#[cfg(test)] +mod tests { + use core::{f32, f64}; + use qc::{U32, U64}; + use float::Float; + + // NOTE The tests below have special handing for NaN values. + // Because NaN != NaN, the floating-point representations must be used + // Because there are many diffferent values of NaN, and the implementation + // doesn't care about calculating the 'correct' one, if both values are NaN + // the values are considered equivalent. + + // TODO: Add F32/F64 to qc so that they print the right values (at the very least) + quickcheck! { + fn addsf3(a: U32, b: U32) -> bool { + let (a, b) = (f32::from_repr(a.0), f32::from_repr(b.0)); + let x = super::__addsf3(a, b); + let y = a + b; + if !(x.is_nan() && y.is_nan()) { + x.repr() == y.repr() + } else { + true + } + } + + fn adddf3(a: U64, b: U64) -> bool { + let (a, b) = (f64::from_repr(a.0), f64::from_repr(b.0)); + let x = super::__adddf3(a, b); + let y = a + b; + if !(x.is_nan() && y.is_nan()) { + x.repr() == y.repr() + } else { + true + } + } + } + + // More tests for special float values + + #[test] + fn test_float_tiny_plus_tiny() { + let tiny = f32::from_repr(1); + let r = super::__addsf3(tiny, tiny); + assert_eq!(r, tiny + tiny); + } + + #[test] + fn test_double_tiny_plus_tiny() { + let tiny = f64::from_repr(1); + let r = super::__adddf3(tiny, tiny); + assert_eq!(r, tiny + tiny); + } + + #[test] + fn test_float_small_plus_small() { + let a = f32::from_repr(327); + let b = f32::from_repr(256); + let r = super::__addsf3(a, b); + assert_eq!(r, a + b); + } + + #[test] + fn test_double_small_plus_small() { + let a = f64::from_repr(327); + let b = f64::from_repr(256); + let r = super::__adddf3(a, b); + assert_eq!(r, a + b); + } + + #[test] + fn test_float_one_plus_one() { + let r = super::__addsf3(1f32, 1f32); + assert_eq!(r, 1f32 + 1f32); + } + + #[test] + fn test_double_one_plus_one() { + let r = super::__adddf3(1f64, 1f64); + assert_eq!(r, 1f64 + 1f64); + } + + #[test] + fn test_float_different_nan() { + let a = f32::from_repr(1); + let b = f32::from_repr(0b11111111100100010001001010101010); + let x = super::__addsf3(a, b); + let y = a + b; + if !(x.is_nan() && y.is_nan()) { + assert_eq!(x.repr(), y.repr()); + } + } + + #[test] + fn test_double_different_nan() { + let a = f64::from_repr(1); + let b = f64::from_repr( + 0b1111111111110010001000100101010101001000101010000110100011101011); + let x = super::__adddf3(a, b); + let y = a + b; + if !(x.is_nan() && y.is_nan()) { + assert_eq!(x.repr(), y.repr()); + } + } + + #[test] + fn test_float_nan() { + let r = super::__addsf3(f32::NAN, 1.23); + assert_eq!(r.repr(), f32::NAN.repr()); + } + + #[test] + fn test_double_nan() { + let r = super::__adddf3(f64::NAN, 1.23); + assert_eq!(r.repr(), f64::NAN.repr()); + } + + #[test] + fn test_float_inf() { + let r = super::__addsf3(f32::INFINITY, -123.4); + assert_eq!(r, f32::INFINITY); + } + + #[test] + fn test_double_inf() { + let r = super::__adddf3(f64::INFINITY, -123.4); + assert_eq!(r, f64::INFINITY); + } +} diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs new file mode 100644 index 0000000000000..ceb2155cc9fd0 --- /dev/null +++ b/library/compiler-builtins/src/float/mod.rs @@ -0,0 +1,65 @@ +use core::mem; + +pub mod add; + +/// Trait for some basic operations on floats +pub trait Float: Sized { + /// A uint of the same with as the float + type Int; + + /// Returns the bitwidth of the float type + fn bits() -> u32; + + /// Returns the bitwidth of the significand + fn significand_bits() -> u32; + + /// Returns `self` transmuted to `Self::Int` + fn repr(self) -> Self::Int; + + /// Returns a `Self::Int` transmuted back to `Self` + fn from_repr(a: Self::Int) -> Self; + + /// Returns (normalized exponent, normalized significand) + fn normalize(significand: Self::Int) -> (i32, Self::Int); +} + +impl Float for f32 { + type Int = u32; + fn bits() -> u32 { + 32 + } + fn significand_bits() -> u32 { + 23 + } + fn repr(self) -> Self::Int { + unsafe { mem::transmute(self) } + } + fn from_repr(a: Self::Int) -> Self { + unsafe { mem::transmute(a) } + } + fn normalize(significand: Self::Int) -> (i32, Self::Int) { + let shift = significand.leading_zeros() + .wrapping_sub((1u32 << Self::significand_bits()).leading_zeros()); + (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) + } +} +impl Float for f64 { + type Int = u64; + fn bits() -> u32 { + 64 + } + fn significand_bits() -> u32 { + 52 + } + fn repr(self) -> Self::Int { + unsafe { mem::transmute(self) } + } + fn from_repr(a: Self::Int) -> Self { + unsafe { mem::transmute(a) } + } + fn normalize(significand: Self::Int) -> (i32, Self::Int) { + let shift = significand.leading_zeros() + .wrapping_sub((1u64 << Self::significand_bits()).leading_zeros()); + (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) + } +} diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index b817d74fda60c..9efebcd36b2b5 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -21,6 +21,7 @@ extern crate core; extern crate rlibc; pub mod int; +pub mod float; #[cfg(target_arch = "arm")] pub mod arm; From e4dabb8c3239ed4699db304dce542eefbcc18182 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 20 Aug 2016 22:17:50 -0500 Subject: [PATCH 0120/4206] qc: bias towards generation of edge cases --- library/compiler-builtins/src/qc.rs | 35 +++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs index 6b37cceb7fd45..fcb0b0880e5b8 100644 --- a/library/compiler-builtins/src/qc.rs +++ b/library/compiler-builtins/src/qc.rs @@ -20,7 +20,18 @@ macro_rules! arbitrary { fn arbitrary(g: &mut G) -> $TY where G: Gen { - $TY(g.gen()) + // NOTE Generate edge cases with a 10% chance + let t = if g.gen_weighted_bool(10) { + *g.choose(&[ + $ty::min_value(), + 0, + $ty::max_value(), + ]).unwrap() + } else { + g.gen() + }; + + $TY(t) } fn shrink(&self) -> Box> { @@ -76,13 +87,23 @@ macro_rules! arbitrary_large { fn arbitrary(g: &mut G) -> $TY where G: Gen { - if g.gen() { - $TY($ty::from_parts(g.gen(), g.gen())) - } else if g.gen() { - $TY($ty::from_parts(0, g.gen())) + // NOTE Generate edge cases with a 10% chance + let t = if g.gen_weighted_bool(10) { + *g.choose(&[ + $ty::min_value(), + 0, + $ty::max_value(), + ]).unwrap() } else { - $TY($ty::from_parts(g.gen(), 0)) - } + match g.gen_range(0, 3) { + 0 => $ty::from_parts(g.gen(), g.gen()), + 1 => $ty::from_parts(0, g.gen()), + 2 => $ty::from_parts(g.gen(), 0), + _ => unreachable!(), + } + }; + + $TY(t) } fn shrink(&self) -> Box> { From 30428ec88f66c3da56f4ad42368ea81da9aebd6a Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Sat, 20 Aug 2016 22:30:02 -0500 Subject: [PATCH 0121/4206] Use mem::swap to swap variables --- library/compiler-builtins/src/float/add.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 3fffac35d7b54..f36e0c1e3f54f 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -74,9 +74,7 @@ macro_rules! add { // Swap a and b if necessary so that a has the larger absolute value. if b_abs > a_abs { - let temp = a_rep; - a_rep = b_rep; - b_rep = temp; + ::core::mem::swap(&mut a_rep, &mut b_rep); } // Extract the exponent and significand from the (possibly swapped) a and b. From 43ce7db752551bbbdf7408bc6b36436a3000a1a5 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 21 Aug 2016 11:09:32 -0500 Subject: [PATCH 0122/4206] only show disassembly of optimized build we can't really compare the disassembly of the debug build to libcompiler-rt.a anyways --- library/compiler-builtins/appveyor.yml | 1 - library/compiler-builtins/ci/script.sh | 1 - 2 files changed, 2 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 4bb03def78278..5cf0b48f1e9be 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -18,7 +18,6 @@ test_script: - cargo test - cargo test --release - CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" - - dumpbin /disasm target/debug/librustc_builtins.rlib || exit 0 - dumpbin /disasm target/release/librustc_builtins.rlib || exit 0 branches: diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 75584786943f8..84e7ee7af53e3 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -11,7 +11,6 @@ inspect() { $PREFIX$NM -g --defined-only target/**/debug/*.rlib set +e - $PREFIX$OBJDUMP -Cd target/**/debug/*.rlib $PREFIX$OBJDUMP -Cd target/**/release/*.rlib set -e From ae9d29429727c7c018c2d4c7c1a8dea321a3b14a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 21 Aug 2016 11:24:58 -0500 Subject: [PATCH 0123/4206] use utility function to compare the repr of floats follow up of #43 --- library/compiler-builtins/src/float/add.rs | 36 ++++++++-------------- library/compiler-builtins/src/float/mod.rs | 22 +++++++++++++ 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index f36e0c1e3f54f..3ebc92b32378c 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -1,4 +1,6 @@ +use core::mem; use core::num::Wrapping; + use float::Float; macro_rules! add { @@ -74,7 +76,7 @@ macro_rules! add { // Swap a and b if necessary so that a has the larger absolute value. if b_abs > a_abs { - ::core::mem::swap(&mut a_rep, &mut b_rep); + mem::swap(&mut a_rep, &mut b_rep); } // Extract the exponent and significand from the (possibly swapped) a and b. @@ -212,22 +214,14 @@ mod tests { let (a, b) = (f32::from_repr(a.0), f32::from_repr(b.0)); let x = super::__addsf3(a, b); let y = a + b; - if !(x.is_nan() && y.is_nan()) { - x.repr() == y.repr() - } else { - true - } + x.eq_repr(y) } fn adddf3(a: U64, b: U64) -> bool { let (a, b) = (f64::from_repr(a.0), f64::from_repr(b.0)); let x = super::__adddf3(a, b); let y = a + b; - if !(x.is_nan() && y.is_nan()) { - x.repr() == y.repr() - } else { - true - } + x.eq_repr(y) } } @@ -237,14 +231,14 @@ mod tests { fn test_float_tiny_plus_tiny() { let tiny = f32::from_repr(1); let r = super::__addsf3(tiny, tiny); - assert_eq!(r, tiny + tiny); + assert!(r.eq_repr(tiny + tiny)); } #[test] fn test_double_tiny_plus_tiny() { let tiny = f64::from_repr(1); let r = super::__adddf3(tiny, tiny); - assert_eq!(r, tiny + tiny); + assert!(r.eq_repr(tiny + tiny)); } #[test] @@ -252,7 +246,7 @@ mod tests { let a = f32::from_repr(327); let b = f32::from_repr(256); let r = super::__addsf3(a, b); - assert_eq!(r, a + b); + assert!(r.eq_repr(a + b)); } #[test] @@ -260,19 +254,19 @@ mod tests { let a = f64::from_repr(327); let b = f64::from_repr(256); let r = super::__adddf3(a, b); - assert_eq!(r, a + b); + assert!(r.eq_repr(a + b)); } #[test] fn test_float_one_plus_one() { let r = super::__addsf3(1f32, 1f32); - assert_eq!(r, 1f32 + 1f32); + assert!(r.eq_repr(1f32 + 1f32)); } #[test] fn test_double_one_plus_one() { let r = super::__adddf3(1f64, 1f64); - assert_eq!(r, 1f64 + 1f64); + assert!(r.eq_repr(1f64 + 1f64)); } #[test] @@ -281,9 +275,7 @@ mod tests { let b = f32::from_repr(0b11111111100100010001001010101010); let x = super::__addsf3(a, b); let y = a + b; - if !(x.is_nan() && y.is_nan()) { - assert_eq!(x.repr(), y.repr()); - } + assert!(x.eq_repr(y)); } #[test] @@ -293,9 +285,7 @@ mod tests { 0b1111111111110010001000100101010101001000101010000110100011101011); let x = super::__adddf3(a, b); let y = a + b; - if !(x.is_nan() && y.is_nan()) { - assert_eq!(x.repr(), y.repr()); - } + assert!(x.eq_repr(y)); } #[test] diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index ceb2155cc9fd0..bd9194bfb7925 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -16,6 +16,12 @@ pub trait Float: Sized { /// Returns `self` transmuted to `Self::Int` fn repr(self) -> Self::Int; + #[cfg(test)] + /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be + /// represented in multiple different ways. This methods returns `true` if two NaNs are + /// compared. + fn eq_repr(self, rhs: Self) -> bool; + /// Returns a `Self::Int` transmuted back to `Self` fn from_repr(a: Self::Int) -> Self; @@ -34,6 +40,14 @@ impl Float for f32 { fn repr(self) -> Self::Int { unsafe { mem::transmute(self) } } + #[cfg(test)] + fn eq_repr(self, rhs: Self) -> bool { + if self.is_nan() && rhs.is_nan() { + true + } else { + self.repr() == rhs.repr() + } + } fn from_repr(a: Self::Int) -> Self { unsafe { mem::transmute(a) } } @@ -54,6 +68,14 @@ impl Float for f64 { fn repr(self) -> Self::Int { unsafe { mem::transmute(self) } } + #[cfg(test)] + fn eq_repr(self, rhs: Self) -> bool { + if self.is_nan() && rhs.is_nan() { + true + } else { + self.repr() == rhs.repr() + } + } fn from_repr(a: Self::Int) -> Self { unsafe { mem::transmute(a) } } From 6a96cf52b6b57810c945447e4474b74cbd972f18 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Sun, 21 Aug 2016 13:31:08 -0500 Subject: [PATCH 0124/4206] Add a `Porting Reminders` section to the README --- library/compiler-builtins/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 67e7b25433e9e..6dae6654f42c1 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -24,6 +24,20 @@ See [rust-lang/rust#35437][0]. [2]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/lib/builtins [3]: https://travis-ci.org/japaric/rustc-builtins +### Porting Reminders + +1. [Rust][4] and [C][5] have slightly different operator precedence. C evaluates comparisons (`== !=`) before bitwise operations (`& | ^`), while Rust evaluates the other way. +2. C assumes wrapping operations everywhere. Rust panics on overflow when in debug mode. Consider using the [Wrapping][6] type or the explicit [wrapping_*][7] functions where applicable. +3. Note [C implicit casts][8], especially integer promotion. Rust is much more explicit about casting, so be sure that any cast which affects the output is ported to the Rust implementation. +4. Rust has [many functions][9] for integer or floating point manipulation in the standard library. Consider using one of these functions rather than porting a new one. + +[4]: https://doc.rust-lang.org/reference.html#operator-precedence +[5]: http://en.cppreference.com/w/c/language/operator_precedence +[6]: https://doc.rust-lang.org/core/num/struct.Wrapping.html +[7]: https://doc.rust-lang.org/std/primitive.i32.html#method.wrapping_add +[8]: http://en.cppreference.com/w/cpp/language/implicit_conversion +[9]: https://doc.rust-lang.org/std/primitive.i32.html + ## Progress - [x] adddf3.c From 5e867a2b984b92954f4560011cc7888072dd38a9 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Sun, 21 Aug 2016 16:51:50 -0500 Subject: [PATCH 0125/4206] travis: Use wgetpaste to post disassemblies to gist --- library/compiler-builtins/ci/install.sh | 12 ++++++++++++ library/compiler-builtins/ci/script.sh | 7 ++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index db862cc334905..08dce43d36c86 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -42,6 +42,17 @@ install_xargo() { fi } +install_wgetpaste() { + if [[ $TRAVIS_OS_NAME == "osx" ]]; then + brew install wgetpaste + else + curl -O http://wgetpaste.zlin.dk/wgetpaste-2.28.tar.bz2 + tar -xvf wgetpaste-2.28.tar.bz2 + sudo mv ./wgetpaste-2.28/wgetpaste /usr/bin + rm -r wgetpaste-2.28* + fi +} + main() { if [[ $TRAVIS_OS_NAME == "osx" || ${IN_DOCKER_CONTAINER:-n} == "y" ]]; then install_qemu @@ -49,6 +60,7 @@ main() { install_rust add_rustup_target install_xargo + install_wgetpaste fi } diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 84e7ee7af53e3..89c535223e014 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -2,6 +2,11 @@ set -ex . $(dirname $0)/env.sh +gist() { + wgetpaste -s gists -d "'$1' from commit '$TRAVIS_COMMIT' on branch '$TRAVIS_BRANCH'" + echo "Disassembly available at the above URL." +} + build() { ${CARGO:-cargo} build --target $TARGET ${CARGO:-cargo} build --target $TARGET --release @@ -11,7 +16,7 @@ inspect() { $PREFIX$NM -g --defined-only target/**/debug/*.rlib set +e - $PREFIX$OBJDUMP -Cd target/**/release/*.rlib + $PREFIX$OBJDUMP -Cd target/**/release/*.rlib | gist "$TARGET/rustc-builtins.rlib" set -e # Check presence of weak symbols From ed393f32a19386cef17a2ec182844cc6a34e3fa1 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Sun, 21 Aug 2016 17:04:48 -0500 Subject: [PATCH 0126/4206] appveyor: Use gist to post disassembly --- library/compiler-builtins/appveyor.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 5cf0b48f1e9be..afca023dc9895 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -7,6 +7,7 @@ install: - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-$%7Benv:TARGET%7D.exe" - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - gem install gist - rustc -Vv - cargo -V @@ -17,8 +18,12 @@ test_script: - cargo build --release - cargo test - cargo test --release - - CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" - - dumpbin /disasm target/release/librustc_builtins.rlib || exit 0 + +on_success: + - cmd: | + CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" + dumpbin /disasm target/release/librustc_builtins.rlib | + gist -d "'%TARGET%/rustc-builtins.rlib' from commit '%APPVEYOR_REPO_COMMIT%' on branch '%APPVEYOR_REPO_branch%'" branches: only: From 79411ae643aacaed213b796d691624ff6b1732f6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 22 Aug 2016 18:03:21 -0500 Subject: [PATCH 0127/4206] use the gist crate but not on OSX because it doesn't work there closes #53 cc #51 --- library/compiler-builtins/appveyor.yml | 5 ++--- library/compiler-builtins/ci/install.sh | 12 ---------- library/compiler-builtins/ci/script.sh | 30 ++++++++++++++++--------- 3 files changed, 21 insertions(+), 26 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index afca023dc9895..ef3194cbe58c8 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -21,9 +21,8 @@ test_script: on_success: - cmd: | - CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" - dumpbin /disasm target/release/librustc_builtins.rlib | - gist -d "'%TARGET%/rustc-builtins.rlib' from commit '%APPVEYOR_REPO_COMMIT%' on branch '%APPVEYOR_REPO_branch%'" + CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" + dumpbin /disasm target/release/librustc_builtins.rlib | gist -d "'%TARGET%/rustc-builtins.rlib' from commit '%APPVEYOR_REPO_COMMIT%' on branch '%APPVEYOR_REPO_branch%'" branches: only: diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 08dce43d36c86..db862cc334905 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -42,17 +42,6 @@ install_xargo() { fi } -install_wgetpaste() { - if [[ $TRAVIS_OS_NAME == "osx" ]]; then - brew install wgetpaste - else - curl -O http://wgetpaste.zlin.dk/wgetpaste-2.28.tar.bz2 - tar -xvf wgetpaste-2.28.tar.bz2 - sudo mv ./wgetpaste-2.28/wgetpaste /usr/bin - rm -r wgetpaste-2.28* - fi -} - main() { if [[ $TRAVIS_OS_NAME == "osx" || ${IN_DOCKER_CONTAINER:-n} == "y" ]]; then install_qemu @@ -60,7 +49,6 @@ main() { install_rust add_rustup_target install_xargo - install_wgetpaste fi } diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 89c535223e014..ef6905b28a90b 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -2,8 +2,8 @@ set -ex . $(dirname $0)/env.sh -gist() { - wgetpaste -s gists -d "'$1' from commit '$TRAVIS_COMMIT' on branch '$TRAVIS_BRANCH'" +gist_it() { + gist -ap -f "'$1' from commit '$TRAVIS_COMMIT' on branch '$TRAVIS_BRANCH'" echo "Disassembly available at the above URL." } @@ -16,18 +16,24 @@ inspect() { $PREFIX$NM -g --defined-only target/**/debug/*.rlib set +e - $PREFIX$OBJDUMP -Cd target/**/release/*.rlib | gist "$TARGET/rustc-builtins.rlib" - set -e - - # Check presence of weak symbols case $TRAVIS_OS_NAME in linux) - local symbols=( memcmp memcpy memmove memset ) - for symbol in "${symbols[@]}"; do - $PREFIX$NM target/**/debug/deps/librlibc*.rlib | grep -q "W $symbol" - done + $PREFIX$OBJDUMP -Cd target/**/release/*.rlib | gist_it "$TARGET/rustc-builtins.rlib" + ;; + osx) + $PREFIX$OBJDUMP -Cd target/**/release/*.rlib ;; esac + set -e + + # Check presence of weak symbols + if [[ $TRAVIS_OS_NAME = "linux" ]]; then + local symbols=( memcmp memcpy memmove memset ) + for symbol in "${symbols[@]}"; do + $PREFIX$NM target/**/debug/deps/librlibc*.rlib | grep -q "W $symbol" + done + fi + } run_tests() { @@ -43,12 +49,14 @@ run_tests() { main() { if [[ $TRAVIS_OS_NAME == "linux" && ${IN_DOCKER_CONTAINER:-n} == "n" ]]; then - local tag=2016-08-13 + local tag=2016-08-22 docker run \ --privileged \ -e IN_DOCKER_CONTAINER=y \ -e TARGET=$TARGET \ + -e TRAVIS_BRANCH=$TRAVIS_BRANCH \ + -e TRAVIS_COMMIT=$TRAVIS_COMMIT \ -e TRAVIS_OS_NAME=$TRAVIS_OS_NAME \ -v $(pwd):/mnt \ japaric/rustc-builtins:$tag \ From bcf5a641df944a2f5293c999be7d31e19e6a714e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 23 Aug 2016 20:17:39 -0500 Subject: [PATCH 0128/4206] README: fix link --- library/compiler-builtins/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 6dae6654f42c1..55f215316a944 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -12,7 +12,7 @@ See [rust-lang/rust#35437][0]. ## Contributing -1. Pick one or more intrinsics from the [pending list][/#progress]. +1. Pick one or more intrinsics from the [pending list][#progress]. 2. Fork this repository 3. Port the intrinsic(s) and their corresponding [unit tests][1] from their [C implementation][2] to Rust. From 72db6febd0aa0224d8632cb5e443f863792ebf8f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 23 Aug 2016 20:23:28 -0500 Subject: [PATCH 0129/4206] README: add AppVeyor badge --- library/compiler-builtins/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 55f215316a944..4eeadb17ec50f 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -1,6 +1,8 @@ -[![Build Status][status]](https://travis-ci.org/japaric/rustc-builtins) +[![Travis][travis]](https://travis-ci.org/japaric/rustc-builtins) +[![AppVeyor][appveyor]](https://ci.appveyor.com/project/japaric/rustc-builtins) -[status]: https://travis-ci.org/japaric/rustc-builtins.svg?branch=master +[travis]: https://travis-ci.org/japaric/rustc-builtins.svg?branch=master +[appveyor]: https://ci.appveyor.com/api/projects/status/mofi55r3px9pv3o7?svg=true # `rustc-builtins` From ff17cfaa46812d27ab1858499af1f8d091a4b4e8 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 23 Aug 2016 20:35:30 -0500 Subject: [PATCH 0130/4206] README: when and how to use this crate --- library/compiler-builtins/README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 4eeadb17ec50f..3d0ded11bfeb0 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -12,6 +12,27 @@ See [rust-lang/rust#35437][0]. [0]: https://github.com/rust-lang/rust/issues/35437 +## When and how to use this crate? + +If you are working with a target that doesn't have binary releases of std available via rustup (this +probably means you are building the core crate yourself) and need compiler-rt intrinsics (i.e. you +are probably getting linker errors when building an executable: "undefined reference to +__aeabi_memcpy"), you can use this crate to get those intrinsics and solve the linker errors. To do +that, simply add this crate as a Cargo dependency (it doesn't matter where in the dependency graph +this crate ends up, as long as it's there): + +``` toml +[dependencies] +rustc-builtins = { git = "https://github.com/japaric/rustc-builtins" } +``` + +If you still get an "undefined reference to $INTRINSIC" error after that change, that means that we +haven't ported `$INTRINSIC` to Rust yet! Please open [an issue] with the name of the intrinsic and +the LLVM triple (e.g. thumbv7m-none-eabi) of the target you are using. That way we can prioritize +porting that particular intrinsic. + +[an issue]: https://github.com/japaric/rustc-builtins/issues + ## Contributing 1. Pick one or more intrinsics from the [pending list][#progress]. From 185143e90f6d2636ae8f1c61ced7b05555e46492 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 23 Aug 2016 20:46:36 -0500 Subject: [PATCH 0131/4206] use the gist gem instead of the gist crate hopefully this will work on osx and will make everything more uniform (appveyor is already using the gem instead of the crate) closes #51 --- library/compiler-builtins/.travis.yml | 2 +- library/compiler-builtins/ci/install.sh | 17 ++++++++++------- library/compiler-builtins/ci/script.sh | 13 +++---------- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index e74b68002ffa9..b7a44d99a5119 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -1,5 +1,5 @@ dist: trusty -language: generic +language: ruby services: docker sudo: required diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index db862cc334905..d912771e0fd09 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -3,13 +3,15 @@ set -ex . $(dirname $0)/env.sh install_qemu() { - case $TRAVIS_OS_NAME in - linux) - apt-get update - apt-get install -y --no-install-recommends \ - binfmt-support qemu-user-static - ;; - esac + if [[ $TRAVIS_OS_NAME = "linux" ]]; then + apt-get update + apt-get install -y --no-install-recommends \ + binfmt-support qemu-user-static + fi +} + +install_gist() { + gem install gist } install_binutils() { @@ -45,6 +47,7 @@ install_xargo() { main() { if [[ $TRAVIS_OS_NAME == "osx" || ${IN_DOCKER_CONTAINER:-n} == "y" ]]; then install_qemu + install_gist install_binutils install_rust add_rustup_target diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index ef6905b28a90b..7f518a794502a 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -3,7 +3,7 @@ set -ex . $(dirname $0)/env.sh gist_it() { - gist -ap -f "'$1' from commit '$TRAVIS_COMMIT' on branch '$TRAVIS_BRANCH'" + gist -d "'$TARGET/rustc-builtins.rlib' from commit '$TRAVIS_COMMIT' on branch '$TRAVIS_BRANCH'" echo "Disassembly available at the above URL." } @@ -16,14 +16,7 @@ inspect() { $PREFIX$NM -g --defined-only target/**/debug/*.rlib set +e - case $TRAVIS_OS_NAME in - linux) - $PREFIX$OBJDUMP -Cd target/**/release/*.rlib | gist_it "$TARGET/rustc-builtins.rlib" - ;; - osx) - $PREFIX$OBJDUMP -Cd target/**/release/*.rlib - ;; - esac + $PREFIX$OBJDUMP -Cd target/**/release/*.rlib | gist_it set -e # Check presence of weak symbols @@ -49,7 +42,7 @@ run_tests() { main() { if [[ $TRAVIS_OS_NAME == "linux" && ${IN_DOCKER_CONTAINER:-n} == "n" ]]; then - local tag=2016-08-22 + local tag=2016-08-13 docker run \ --privileged \ From 1ae3b2927080f00888cf2cfe82e7d11d654e4f85 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 23 Aug 2016 21:19:18 -0500 Subject: [PATCH 0132/4206] use newer docker image it comes with ruby pre-installed --- library/compiler-builtins/ci/script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 7f518a794502a..911f40218b4e7 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -42,7 +42,7 @@ run_tests() { main() { if [[ $TRAVIS_OS_NAME == "linux" && ${IN_DOCKER_CONTAINER:-n} == "n" ]]; then - local tag=2016-08-13 + local tag=2016-08-24 docker run \ --privileged \ From 2e516532d1004cf96224d1494aea96e1c1a2517d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 23 Aug 2016 21:20:57 -0500 Subject: [PATCH 0133/4206] set language: ruby on osx only --- library/compiler-builtins/.travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index b7a44d99a5119..7a7a9bf5d7986 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -1,5 +1,5 @@ dist: trusty -language: ruby +language: generic services: docker sudo: required @@ -16,6 +16,7 @@ matrix: - env: TARGET=i586-unknown-linux-gnu os: linux - env: TARGET=i686-apple-darwin + language: ruby os: osx - env: TARGET=i686-unknown-linux-gnu os: linux @@ -36,6 +37,7 @@ matrix: - env: TARGET=thumbv7m-none-eabi os: linux - env: TARGET=x86_64-apple-darwin + language: ruby os: osx - env: TARGET=x86_64-unknown-linux-gnu os: linux From 90d58ada7a7a5402530810cf702935262886ffa5 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 27 Aug 2016 11:37:35 -0500 Subject: [PATCH 0134/4206] appveyor: use rustup --- library/compiler-builtins/appveyor.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index ef3194cbe58c8..669500a38e413 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -4,9 +4,9 @@ environment: - TARGET: x86_64-pc-windows-msvc install: - - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-$%7Benv:TARGET%7D.exe" - - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" - - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - curl -sSf -o rustup-init.exe https://win.rustup.rs + - rustup-init.exe --default-host %TARGET% --default-toolchain nightly -y + - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - gem install gist - rustc -Vv - cargo -V From 62d5f589086b07ca3f82bffb04e162430aed0fa3 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 27 Aug 2016 12:34:39 -0500 Subject: [PATCH 0135/4206] print rustup version --- library/compiler-builtins/ci/install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index d912771e0fd09..50e223cdd6c7f 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -27,6 +27,7 @@ install_rust() { rustup default nightly fi + rustup -V rustc -V cargo -V } From a8774eb192291f3b652159803a61fb09ec4c373d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 29 Aug 2016 19:31:49 -0500 Subject: [PATCH 0136/4206] travis: simplify ci scripts --- library/compiler-builtins/.travis.yml | 3 - library/compiler-builtins/ci/env.sh | 95 +++++++++++-------------- library/compiler-builtins/ci/install.sh | 12 ++-- library/compiler-builtins/ci/script.sh | 14 ++-- 4 files changed, 54 insertions(+), 70 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 7a7a9bf5d7986..6759c4e2864a5 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -42,9 +42,6 @@ matrix: - env: TARGET=x86_64-unknown-linux-gnu os: linux -before_install: - - export PATH="$PATH:$HOME/.cargo/bin" - install: - bash ci/install.sh diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 55249950b3c24..9addf551b77aa 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -1,60 +1,49 @@ case $TRAVIS_OS_NAME in linux) - export HOST=x86_64-unknown-linux-gnu - export NM=nm - export OBJDUMP=objdump + HOST=x86_64-unknown-linux-gnu + NM=nm + OBJDUMP=objdump + LINUX=y ;; osx) - export HOST=x86_64-apple-darwin - export NM=gnm - export OBJDUMP=gobjdump + HOST=x86_64-apple-darwin + NM=gnm + OBJDUMP=gobjdump + OSX=y ;; esac -case $TARGET in - aarch64-unknown-linux-gnu) - export PREFIX=aarch64-linux-gnu- - export QEMU_LD_PREFIX=/usr/aarch64-linux-gnu - ;; - arm*-unknown-linux-gnueabi) - export PREFIX=arm-linux-gnueabi- - export QEMU_LD_PREFIX=/usr/arm-linux-gnueabi - ;; - arm-unknown-linux-gnueabihf) - export PREFIX=arm-linux-gnueabihf- - export QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf - ;; - armv7-unknown-linux-gnueabihf) - export PREFIX=arm-linux-gnueabihf- - export QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf - ;; - mips-unknown-linux-gnu) - export PREFIX=mips-linux-gnu- - export QEMU_LD_PREFIX=/usr/mips-linux-gnu - ;; - mipsel-unknown-linux-gnu) - export PREFIX=mipsel-linux-gnu- - export QEMU_LD_PREFIX=/usr/mipsel-linux-gnu - ;; - powerpc-unknown-linux-gnu) - export PREFIX=powerpc-linux-gnu- - export QEMU_LD_PREFIX=/usr/powerpc-linux-gnu - ;; - powerpc64-unknown-linux-gnu) - export PREFIX=powerpc64-linux-gnu- - export QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu - ;; - powerpc64le-unknown-linux-gnu) - export PREFIX=powerpc64le-linux-gnu- - export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu - # QEMU crashes, even running the simplest cross compiled C program: - # `int main() { return 0; }` - export RUN_TESTS=n - ;; - thumbv*-none-eabi) - export CARGO=xargo - export PREFIX=arm-none-eabi- - # Bare metal targets. No `std` or `test` crates for these targets. - export RUN_TESTS=n - ;; -esac +# NOTE For rustup +export PATH="$HOME/.cargo/bin:$PATH" + +CARGO=cargo +RUN_TESTS=y + +# NOTE For the host and its 32-bit variants we don't need prefixed tools or QEMU +if [[ $TARGET != $HOST && ! $TARGET =~ ^i.86- ]]; then + GCC_TRIPLE=${TARGET//unknown-/} + + case $TARGET in + armv7-unknown-linux-gnueabihf) + GCC_TRIPLE=arm-linux-gnueabihf + ;; + powerpc64le-unknown-linux-gnu) + # QEMU crashes even when executing the simplest cross compiled C program: + # `int main() { return 0; }` + RUN_TESTS=n + ;; + thumbv*-none-eabi) + CARGO=xargo + GCC_TRIPLE=arm-none-eabi + # Bare metal targets. No `std` or `test` crates for these targets. + RUN_TESTS=n + ;; + esac + + if [[ $RUN_TESTS == y ]]; then + # NOTE(export) so this can reach the processes that `cargo test` spawns + export QEMU_LD_PREFIX=/usr/$GCC_TRIPLE + fi + + PREFIX=$GCC_TRIPLE- +fi diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 50e223cdd6c7f..ee01f34944bea 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -3,7 +3,7 @@ set -ex . $(dirname $0)/env.sh install_qemu() { - if [[ $TRAVIS_OS_NAME = "linux" ]]; then + if [[ $QEMU_LD_PREFIX ]]; then apt-get update apt-get install -y --no-install-recommends \ binfmt-support qemu-user-static @@ -15,13 +15,13 @@ install_gist() { } install_binutils() { - if [[ $TRAVIS_OS_NAME == "osx" ]]; then + if [[ $OSX ]]; then brew install binutils fi } install_rust() { - if [[ $TRAVIS_OS_NAME == "osx" ]]; then + if [[ $OSX ]]; then curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain=nightly else rustup default nightly @@ -33,20 +33,20 @@ install_rust() { } add_rustup_target() { - if [[ $TARGET != $HOST && ${CARGO:-cargo} == "cargo" ]]; then + if [[ $TARGET != $HOST && $CARGO == cargo ]]; then rustup target add $TARGET fi } install_xargo() { - if [[ $CARGO == "xargo" ]]; then + if [[ $CARGO == xargo ]]; then curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ bash -s -- --from japaric/xargo --at /root/.cargo/bin fi } main() { - if [[ $TRAVIS_OS_NAME == "osx" || ${IN_DOCKER_CONTAINER:-n} == "y" ]]; then + if [[ $OSX || ${IN_DOCKER_CONTAINER:-n} == y ]]; then install_qemu install_gist install_binutils diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 911f40218b4e7..29cad854e8818 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -8,8 +8,8 @@ gist_it() { } build() { - ${CARGO:-cargo} build --target $TARGET - ${CARGO:-cargo} build --target $TARGET --release + $CARGO build --tartet $TARGET + $CARGO build --target $TARGET --release } inspect() { @@ -20,7 +20,7 @@ inspect() { set -e # Check presence of weak symbols - if [[ $TRAVIS_OS_NAME = "linux" ]]; then + if [[ $LINUX ]]; then local symbols=( memcmp memcpy memmove memset ) for symbol in "${symbols[@]}"; do $PREFIX$NM target/**/debug/deps/librlibc*.rlib | grep -q "W $symbol" @@ -34,14 +34,14 @@ run_tests() { export RUST_TEST_THREADS=1 fi - if [[ ${RUN_TESTS:-y} == "y" ]]; then + if [[ $RUN_TESTS == y ]]; then cargo test --target $TARGET cargo test --target $TARGET --release fi } main() { - if [[ $TRAVIS_OS_NAME == "linux" && ${IN_DOCKER_CONTAINER:-n} == "n" ]]; then + if [[ $LINUX && ${IN_DOCKER_CONTAINER:-n} == n ]]; then local tag=2016-08-24 docker run \ @@ -53,9 +53,7 @@ main() { -e TRAVIS_OS_NAME=$TRAVIS_OS_NAME \ -v $(pwd):/mnt \ japaric/rustc-builtins:$tag \ - sh -c 'set -ex; - cd /mnt; - export PATH="$PATH:/root/.cargo/bin"; + sh -c 'cd /mnt; bash ci/install.sh; bash ci/script.sh' else From 17386437c853e12a300028c4c58fa62917de0f3c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 29 Aug 2016 20:36:52 -0500 Subject: [PATCH 0137/4206] fix typo --- library/compiler-builtins/ci/script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 29cad854e8818..20e574166ee89 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -8,7 +8,7 @@ gist_it() { } build() { - $CARGO build --tartet $TARGET + $CARGO build --target $TARGET $CARGO build --target $TARGET --release } From 80f867f306353c15ef73eed94423ddbb7dfbf73e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 29 Aug 2016 20:37:41 -0500 Subject: [PATCH 0138/4206] pin xargo and gist versions --- library/compiler-builtins/ci/install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index ee01f34944bea..45ad243fb993c 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -11,7 +11,7 @@ install_qemu() { } install_gist() { - gem install gist + gem install gist -v 4.5.0 } install_binutils() { @@ -41,7 +41,7 @@ add_rustup_target() { install_xargo() { if [[ $CARGO == xargo ]]; then curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --from japaric/xargo --at /root/.cargo/bin + bash -s -- --from japaric/xargo --at /root/.cargo/bin --vers 0.1.5 fi } From d253b6a2e4d6f01230f0f2103e9f7a8e070af732 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 29 Aug 2016 21:21:59 -0500 Subject: [PATCH 0139/4206] travis: use latest docker image --- library/compiler-builtins/ci/script.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 20e574166ee89..38c6b32376e3a 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -42,8 +42,7 @@ run_tests() { main() { if [[ $LINUX && ${IN_DOCKER_CONTAINER:-n} == n ]]; then - local tag=2016-08-24 - + # NOTE The Dockerfile of this image is in the docker branch of this repository docker run \ --privileged \ -e IN_DOCKER_CONTAINER=y \ @@ -52,7 +51,7 @@ main() { -e TRAVIS_COMMIT=$TRAVIS_COMMIT \ -e TRAVIS_OS_NAME=$TRAVIS_OS_NAME \ -v $(pwd):/mnt \ - japaric/rustc-builtins:$tag \ + japaric/rustc-builtins \ sh -c 'cd /mnt; bash ci/install.sh; bash ci/script.sh' From a88958c673a4afdc4dfca44af43399c70e2f0538 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 29 Aug 2016 21:25:23 -0500 Subject: [PATCH 0140/4206] install less stuff it's already installed in the docker image --- library/compiler-builtins/ci/install.sh | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh index 45ad243fb993c..86095e33e8980 100644 --- a/library/compiler-builtins/ci/install.sh +++ b/library/compiler-builtins/ci/install.sh @@ -11,7 +11,9 @@ install_qemu() { } install_gist() { - gem install gist -v 4.5.0 + if [[ $OSX ]]; then + gem install gist -v 4.5.0 + fi } install_binutils() { @@ -38,13 +40,6 @@ add_rustup_target() { fi } -install_xargo() { - if [[ $CARGO == xargo ]]; then - curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --from japaric/xargo --at /root/.cargo/bin --vers 0.1.5 - fi -} - main() { if [[ $OSX || ${IN_DOCKER_CONTAINER:-n} == y ]]; then install_qemu @@ -52,7 +47,6 @@ main() { install_binutils install_rust add_rustup_target - install_xargo fi } From e237a46f40da18a841e5add04f517f5b156e491c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 29 Aug 2016 21:35:53 -0500 Subject: [PATCH 0141/4206] tell cargo which linker to use --- library/compiler-builtins/ci/env.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index 9addf551b77aa..feeac221389b5 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -40,6 +40,8 @@ if [[ $TARGET != $HOST && ! $TARGET =~ ^i.86- ]]; then ;; esac + export CARGO_TARGET_$(echo $TARGET | tr a-z- A-Z_)_LINKER=$GCC_TRIPLE-gcc + if [[ $RUN_TESTS == y ]]; then # NOTE(export) so this can reach the processes that `cargo test` spawns export QEMU_LD_PREFIX=/usr/$GCC_TRIPLE From becf6eea62817dd8f5ade044afac56af2303674e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 10 Sep 2016 16:49:32 -0500 Subject: [PATCH 0142/4206] homu-ify --- library/compiler-builtins/.travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 6759c4e2864a5..5496bb2913155 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -50,8 +50,10 @@ script: branches: only: - - master + - auto + - try notifications: email: on_success: never + webhooks: https://homu.herokuapp.com/travis From 4553b1fc764e89ce6f319145f2fd94e2f8aaa28e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 10 Sep 2016 16:54:54 -0500 Subject: [PATCH 0143/4206] appveyor: test on auto and try only --- library/compiler-builtins/appveyor.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 669500a38e413..b34efc21e61ea 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -26,4 +26,5 @@ on_success: branches: only: - - master + - auto + - try From 74459fdf121c388d52db7edea1fcbbc69b9a9d7b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 10 Sep 2016 18:37:35 -0500 Subject: [PATCH 0144/4206] test for homu --- library/compiler-builtins/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 3d0ded11bfeb0..536cec739cdf0 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -1,8 +1,8 @@ [![Travis][travis]](https://travis-ci.org/japaric/rustc-builtins) [![AppVeyor][appveyor]](https://ci.appveyor.com/project/japaric/rustc-builtins) -[travis]: https://travis-ci.org/japaric/rustc-builtins.svg?branch=master [appveyor]: https://ci.appveyor.com/api/projects/status/mofi55r3px9pv3o7?svg=true +[travis]: https://travis-ci.org/japaric/rustc-builtins.svg?branch=master # `rustc-builtins` From 152f5150f66d9122898a9b8e99bc7affa225104c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 10 Sep 2016 19:12:50 -0500 Subject: [PATCH 0145/4206] homu test --- library/compiler-builtins/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 536cec739cdf0..edccd301838af 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -1,5 +1,5 @@ -[![Travis][travis]](https://travis-ci.org/japaric/rustc-builtins) [![AppVeyor][appveyor]](https://ci.appveyor.com/project/japaric/rustc-builtins) +[![Travis][travis]](https://travis-ci.org/japaric/rustc-builtins) [appveyor]: https://ci.appveyor.com/api/projects/status/mofi55r3px9pv3o7?svg=true [travis]: https://travis-ci.org/japaric/rustc-builtins.svg?branch=master From 656cd2b30820022f0189c83988970209c5e6dc18 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 16 Sep 2016 15:53:14 -0500 Subject: [PATCH 0146/4206] test our implementations against gcc_s if it exposes the same intrinsics that we implement -- gcc_s doesn't implement all the intrinsics for all the architectures. closes #65 --- library/compiler-builtins/Cargo.toml | 3 ++ library/compiler-builtins/gcc_s/Cargo.toml | 7 +++ library/compiler-builtins/gcc_s/src/lib.rs | 51 +++++++++++++++++++++ library/compiler-builtins/src/float/add.rs | 18 ++++++-- library/compiler-builtins/src/int/mul.rs | 32 +++++++++++-- library/compiler-builtins/src/int/sdiv.rs | 53 +++++++++++++++++++--- library/compiler-builtins/src/int/shift.rs | 22 +++++++-- library/compiler-builtins/src/int/udiv.rs | 53 +++++++++++++++++++--- library/compiler-builtins/src/lib.rs | 3 ++ 9 files changed, 220 insertions(+), 22 deletions(-) create mode 100644 library/compiler-builtins/gcc_s/Cargo.toml create mode 100644 library/compiler-builtins/gcc_s/src/lib.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 48f6ee0ce3d2e..229cec7470657 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -7,7 +7,10 @@ version = "0.1.0" rlibc = { git = "https://github.com/alexcrichton/rlibc", optional = true } [dev-dependencies] +gcc_s = { path = "gcc_s" } quickcheck = "0.3.1" [features] default = ["rlibc/weak"] + +[workspace] diff --git a/library/compiler-builtins/gcc_s/Cargo.toml b/library/compiler-builtins/gcc_s/Cargo.toml new file mode 100644 index 0000000000000..4e3080fa408e3 --- /dev/null +++ b/library/compiler-builtins/gcc_s/Cargo.toml @@ -0,0 +1,7 @@ +[package] +authors = ["Jorge Aparicio "] +name = "gcc_s" +version = "0.1.0" + +[dependencies] +libloading = "0.3.0" diff --git a/library/compiler-builtins/gcc_s/src/lib.rs b/library/compiler-builtins/gcc_s/src/lib.rs new file mode 100644 index 0000000000000..b053a5b8e35f8 --- /dev/null +++ b/library/compiler-builtins/gcc_s/src/lib.rs @@ -0,0 +1,51 @@ +#![feature(drop_types_in_const)] + +extern crate libloading; + +use std::sync::{Once, ONCE_INIT}; + +use libloading::Library; + +static mut GCC_S: Option = None; + +fn gcc_s() -> &'static Library { + unsafe { + static INIT: Once = ONCE_INIT; + + INIT.call_once(|| { + GCC_S = Some(Library::new("libgcc_s.so.1").unwrap()); + }); + GCC_S.as_ref().unwrap() + } +} + +macro_rules! declare { + ($symbol:ident: fn($($i:ty),+) -> $o:ty) => { + pub fn $symbol() -> Option $o> { + unsafe { + gcc_s().get(concat!("__", stringify!($symbol)).as_bytes()).ok().map(|s| *s) + } + } + } +} + +declare!(ashldi3: fn(u64, u32) -> u64); +declare!(ashrdi3: fn(i64, u32) -> i64); +declare!(divdi3: fn(i64, i64) -> i64); +declare!(divmoddi4: fn(i64, i64, &mut i64) -> i64); +declare!(divmodsi4: fn(i32, i32, &mut i32) -> i32); +declare!(divsi3: fn(i32, i32) -> i32); +declare!(lshrdi3: fn(u64, u32) -> u64); +declare!(moddi3: fn(i64, i64) -> i64); +declare!(modsi3: fn(i32, i32) -> i32); +declare!(muldi3: fn(u64, u64) -> u64); +declare!(mulodi4: fn(i64, i64, &mut i32) -> i64); +declare!(mulosi4: fn(i32, i32, &mut i32) -> i32); +declare!(udivdi3: fn(u64, u64) -> u64); +declare!(udivmoddi4: fn(u64, u64, Option<&mut u64>) -> u64); +declare!(udivmodsi4: fn(u32, u32, Option<&mut u32>) -> u32); +declare!(udivsi3: fn(u32, u32) -> u32); +declare!(umoddi3: fn(u64, u64) -> u64); +declare!(umodsi3: fn(u32, u32) -> u32); +declare!(addsf3: fn(f32, f32) -> f32); +declare!(adddf3: fn(f64, f64) -> f64); diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 3ebc92b32378c..13c7aba678b79 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -199,6 +199,8 @@ pub extern fn __aeabi_fadd(a: f32, b: f32) -> f32 { #[cfg(test)] mod tests { use core::{f32, f64}; + + use gcc_s; use qc::{U32, U64}; use float::Float; @@ -213,15 +215,23 @@ mod tests { fn addsf3(a: U32, b: U32) -> bool { let (a, b) = (f32::from_repr(a.0), f32::from_repr(b.0)); let x = super::__addsf3(a, b); - let y = a + b; - x.eq_repr(y) + + if let Some(addsf3) = gcc_s::addsf3() { + x.eq_repr(unsafe { addsf3(a, b) }) + } else { + x.eq_repr(a + b) + } } fn adddf3(a: U64, b: U64) -> bool { let (a, b) = (f64::from_repr(a.0), f64::from_repr(b.0)); let x = super::__adddf3(a, b); - let y = a + b; - x.eq_repr(y) + + if let Some(adddf3) = gcc_s::adddf3() { + x.eq_repr(unsafe { adddf3(a, b) }) + } else { + x.eq_repr(a + b) + } } } diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 3d6844473b935..4ea65bd28dcf7 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -72,13 +72,19 @@ mulo!(__mulodi4: i64); #[cfg(test)] mod tests { + use gcc_s; use qc::{I32, I64, U64}; quickcheck! { fn muldi(a: U64, b: U64) -> bool { let (a, b) = (a.0, b.0); let r = super::__muldi3(a, b); - r == a.wrapping_mul(b) + + if let Some(muldi3) = gcc_s::muldi3() { + r == unsafe { muldi3(a, b) } + } else { + r == a.wrapping_mul(b) + } } fn mulosi(a: I32, b: I32) -> bool { @@ -88,7 +94,17 @@ mod tests { if overflow != 0 && overflow != 1 { return false; } - (r, overflow != 0) == a.overflowing_mul(b) + + if let Some(mulosi4) = gcc_s::mulosi4() { + let mut gcc_s_overflow = 2; + let gcc_s_r = unsafe { + mulosi4(a, b, &mut gcc_s_overflow) + }; + + (r, overflow) == (gcc_s_r, gcc_s_overflow) + } else { + (r, overflow != 0) == a.overflowing_mul(b) + } } fn mulodi(a: I64, b: I64) -> bool { @@ -98,7 +114,17 @@ mod tests { if overflow != 0 && overflow != 1 { return false; } - (r, overflow != 0) == a.overflowing_mul(b) + + if let Some(mulodi4) = gcc_s::mulodi4() { + let mut gcc_s_overflow = 2; + let gcc_s_r = unsafe { + mulodi4(a, b, &mut gcc_s_overflow) + }; + + (r, overflow) == (gcc_s_r, gcc_s_overflow) + } else { + (r, overflow != 0) == a.overflowing_mul(b) + } } } } diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 72ddbca5d5b95..50ad0e0a5254b 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -52,6 +52,7 @@ divmod!(__divmoddi4, __divdi3: i64); #[cfg(test)] mod tests { + use gcc_s; use quickcheck::TestResult; use qc::{U32, U64}; @@ -62,7 +63,12 @@ mod tests { TestResult::discard() } else { let q = super::__divdi3(n, d); - TestResult::from_bool(q == n / d) + + if let Some(divdi3) = gcc_s::divdi3() { + TestResult::from_bool(q == unsafe { divdi3(n, d) }) + } else { + TestResult::from_bool(q == n / d) + } } } @@ -72,7 +78,12 @@ mod tests { TestResult::discard() } else { let r = super::__moddi3(n, d); - TestResult::from_bool(r == n % d) + + if let Some(moddi3) = gcc_s::moddi3() { + TestResult::from_bool(r == unsafe { moddi3(n, d) }) + } else { + TestResult::from_bool(r == n % d) + } } } @@ -83,7 +94,17 @@ mod tests { } else { let mut r = 0; let q = super::__divmoddi4(n, d, &mut r); - TestResult::from_bool(q == n / d && r == n % d) + + if let Some(divmoddi4) = gcc_s::divmoddi4() { + let mut gcc_s_r = 0; + let gcc_s_q = unsafe { + divmoddi4(n, d, &mut gcc_s_r) + }; + + TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) + } else { + TestResult::from_bool(q == n / d && r == n % d) + } } } @@ -93,7 +114,12 @@ mod tests { TestResult::discard() } else { let q = super::__divsi3(n, d); - TestResult::from_bool(q == n / d) + + if let Some(divsi3) = gcc_s::divsi3() { + TestResult::from_bool(q == unsafe { divsi3(n, d)}) + } else { + TestResult::from_bool(q == n / d) + } } } @@ -103,7 +129,12 @@ mod tests { TestResult::discard() } else { let r = super::__modsi3(n, d); - TestResult::from_bool(r == n % d) + + if let Some(modsi3) = gcc_s::modsi3() { + TestResult::from_bool(r == unsafe { modsi3(n, d) }) + } else { + TestResult::from_bool(r == n % d) + } } } @@ -114,7 +145,17 @@ mod tests { } else { let mut r = 0; let q = super::__divmodsi4(n, d, &mut r); - TestResult::from_bool(q == n / d && r == n % d) + + if let Some(divmodsi4) = gcc_s::divmodsi4() { + let mut gcc_s_r = 0; + let gcc_s_q = unsafe { + divmodsi4(n, d, &mut gcc_s_r) + }; + + TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) + } else { + TestResult::from_bool(q == n / d && r == n % d) + } } } } diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 96ae6dbad2513..c7be81171c4a4 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -60,6 +60,7 @@ lshr!(__lshrdi3: u64); #[cfg(test)] mod tests { + use gcc_s; use quickcheck::TestResult; use qc::{I64, U64}; @@ -71,7 +72,12 @@ mod tests { TestResult::discard() } else { let r = super::__ashldi3(a, b); - TestResult::from_bool(r == a << b) + + if let Some(ashldi3) = gcc_s::ashldi3() { + TestResult::from_bool(r == unsafe { ashldi3(a, b) }) + } else { + TestResult::from_bool(r == a << b) + } } } @@ -81,7 +87,12 @@ mod tests { TestResult::discard() } else { let r = super::__ashrdi3(a, b); - TestResult::from_bool(r == a >> b) + + if let Some(ashrdi3) = gcc_s::ashrdi3() { + TestResult::from_bool(r == unsafe { ashrdi3(a, b) }) + } else { + TestResult::from_bool(r == a >> b) + } } } @@ -91,7 +102,12 @@ mod tests { TestResult::discard() } else { let r = super::__lshrdi3(a, b); - TestResult::from_bool(r == a >> b) + + if let Some(lshrdi3) = gcc_s::lshrdi3() { + TestResult::from_bool(r == unsafe { lshrdi3(a, b) }) + } else { + TestResult::from_bool(r == a >> b) + } } } } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index f3ec720c105c7..8c9d06f21dfa3 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -228,6 +228,7 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { #[cfg(test)] mod tests { + use gcc_s; use quickcheck::TestResult; use qc::{U32, U64}; @@ -238,7 +239,12 @@ mod tests { TestResult::discard() } else { let q = super::__udivdi3(n, d); - TestResult::from_bool(q == n / d) + + if let Some(udivdi3) = gcc_s::udivdi3() { + TestResult::from_bool(q == unsafe { udivdi3(n, d) }) + } else { + TestResult::from_bool(q == n / d) + } } } @@ -248,7 +254,12 @@ mod tests { TestResult::discard() } else { let r = super::__umoddi3(n, d); - TestResult::from_bool(r == n % d) + + if let Some(umoddi3) = gcc_s::umoddi3() { + TestResult::from_bool(r == unsafe { umoddi3(n, d) }) + } else { + TestResult::from_bool(r == n % d) + } } } @@ -259,7 +270,17 @@ mod tests { } else { let mut r = 0; let q = super::__udivmoddi4(n, d, Some(&mut r)); - TestResult::from_bool(q == n / d && r == n % d) + + if let Some(udivmoddi4) = gcc_s::udivmoddi4() { + let mut gcc_s_r = 0; + let gcc_s_q = unsafe { + udivmoddi4(n, d, Some(&mut gcc_s_r)) + }; + + TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) + } else { + TestResult::from_bool(q == n / d && r == n % d) + } } } @@ -269,7 +290,12 @@ mod tests { TestResult::discard() } else { let q = super::__udivsi3(n, d); - TestResult::from_bool(q == n / d) + + if let Some(udivsi3) = gcc_s::udivsi3() { + TestResult::from_bool(q == unsafe { udivsi3(n, d) }) + } else { + TestResult::from_bool(q == n / d) + } } } @@ -279,7 +305,12 @@ mod tests { TestResult::discard() } else { let r = super::__umodsi3(n, d); - TestResult::from_bool(r == n % d) + + if let Some(umodsi3) = gcc_s::umodsi3() { + TestResult::from_bool(r == unsafe { umodsi3(n, d) }) + } else { + TestResult::from_bool(r == n % d) + } } } @@ -290,7 +321,17 @@ mod tests { } else { let mut r = 0; let q = super::__udivmodsi4(n, d, Some(&mut r)); - TestResult::from_bool(q == n / d && r == n % d) + + if let Some(udivmodsi4) = gcc_s::udivmodsi4() { + let mut gcc_s_r = 0; + let gcc_s_q = unsafe { + udivmodsi4(n, d, Some(&mut gcc_s_r)) + }; + + TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) + } else { + TestResult::from_bool(q == n / d && r == n % d) + } } } } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 9efebcd36b2b5..cba1604c0e18a 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -17,6 +17,9 @@ extern crate quickcheck; #[cfg(test)] extern crate core; +#[cfg(test)] +extern crate gcc_s; + #[cfg(all(not(windows), not(target_os = "macos")))] extern crate rlibc; From 0ae6c5db880ba919ba58c91134202a0a42c05cb1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 17 Sep 2016 19:54:29 -0500 Subject: [PATCH 0147/4206] osx: link to dylib, windows: always return None --- library/compiler-builtins/gcc_s/src/lib.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/gcc_s/src/lib.rs b/library/compiler-builtins/gcc_s/src/lib.rs index b053a5b8e35f8..fa034b0b3ddfe 100644 --- a/library/compiler-builtins/gcc_s/src/lib.rs +++ b/library/compiler-builtins/gcc_s/src/lib.rs @@ -8,17 +8,34 @@ use libloading::Library; static mut GCC_S: Option = None; +#[cfg(not(windows))] fn gcc_s() -> &'static Library { + #[cfg(not(target_os = "macos"))] + const LIBGCC_S: &'static str = "libgcc_s.so.1"; + + #[cfg(target_os = "macos")] + const LIBGCC_S: &'static str = "libgcc_s.1.dylib"; + unsafe { static INIT: Once = ONCE_INIT; INIT.call_once(|| { - GCC_S = Some(Library::new("libgcc_s.so.1").unwrap()); + GCC_S = Some(Library::new(LIBGCC_S).unwrap()); }); GCC_S.as_ref().unwrap() } } +#[cfg(windows)] +macro_rules! declare { + ($symbol:ident: fn($($i:ty),+) -> $o:ty) => { + pub fn $symbol() -> Option $o> { + None + } + } +} + +#[cfg(not(windows))] macro_rules! declare { ($symbol:ident: fn($($i:ty),+) -> $o:ty) => { pub fn $symbol() -> Option $o> { From 294c6a93d85df4c1808fc05e8bdf072b256befee Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 17 Sep 2016 21:10:41 -0500 Subject: [PATCH 0148/4206] avoid division overflow in idivmod test --- library/compiler-builtins/src/arm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index b46b0ea77f59f..903672fc8fc57 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -193,7 +193,7 @@ mod tests { fn idivmod(n: U32, d: U32) -> TestResult { let (n, d) = (n.0 as i32, d.0 as i32); - if d == 0 { + if d == 0 || (n == i32::min_value() && d == -1) { TestResult::discard() } else { let q: i32; From 7a56ac6bb420a44fdfaa02ad1a1c8a0f5969b5be Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 21 Sep 2016 21:14:38 -0500 Subject: [PATCH 0149/4206] armhf: don't compare our impls against gcc_s --- library/compiler-builtins/Cargo.toml | 1 + library/compiler-builtins/build.rs | 7 +++++++ library/compiler-builtins/src/float/add.rs | 23 ++++++++++++++-------- 3 files changed, 23 insertions(+), 8 deletions(-) create mode 100644 library/compiler-builtins/build.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 229cec7470657..d378461802ab6 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,5 +1,6 @@ [package] authors = ["Jorge Aparicio "] +build = "build.rs" name = "rustc_builtins" version = "0.1.0" diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs new file mode 100644 index 0000000000000..1ff0c06218f35 --- /dev/null +++ b/library/compiler-builtins/build.rs @@ -0,0 +1,7 @@ +use std::env; + +fn main() { + if env::var("TARGET").unwrap().ends_with("hf") { + println!("cargo:rustc-cfg=gnueabihf") + } +} diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 13c7aba678b79..0943e2e3bbcb9 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -216,10 +216,15 @@ mod tests { let (a, b) = (f32::from_repr(a.0), f32::from_repr(b.0)); let x = super::__addsf3(a, b); - if let Some(addsf3) = gcc_s::addsf3() { - x.eq_repr(unsafe { addsf3(a, b) }) - } else { - x.eq_repr(a + b) + match gcc_s::addsf3() { + // NOTE(cfg) for some reason, on hard float targets, our implementation doesn't + // match the output of its gcc_s counterpart. Until we investigate further, we'll + // just avoid testing against gcc_s on those targets. Do note that our + // implementation matches the output of the FPU instruction on *hard* float targets + // and matches its gcc_s counterpart on *soft* float targets. + #[cfg(not(gnueabihf))] + Some(addsf3) => x.eq_repr(unsafe { addsf3(a, b) }), + _ => x.eq_repr(a + b), } } @@ -227,10 +232,12 @@ mod tests { let (a, b) = (f64::from_repr(a.0), f64::from_repr(b.0)); let x = super::__adddf3(a, b); - if let Some(adddf3) = gcc_s::adddf3() { - x.eq_repr(unsafe { adddf3(a, b) }) - } else { - x.eq_repr(a + b) + match gcc_s::adddf3() { + // NOTE(cfg) See NOTE above + #[cfg(not(gnueabihf))] + Some(adddf3) => x.eq_repr(unsafe { adddf3(a, b) }), + _ => x.eq_repr(a + b), + } } } From bc61db2e36cbd7776aaac320b628abee494b50e2 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 21 Sep 2016 21:38:06 -0500 Subject: [PATCH 0150/4206] don't test always against gcc_s instead test half of the time against gcc_s and the other half test against the native operation (\*). (\*) Not all the targets have available a native version of the intrinsics under test. On those targets we'll end up testing our implementation against itself half of the time. This is not much of a problem because we do several quickcheck runs per intrinsic. --- library/compiler-builtins/Cargo.toml | 10 ++- library/compiler-builtins/src/float/add.rs | 10 +-- library/compiler-builtins/src/int/mul.rs | 45 +++++++------ library/compiler-builtins/src/int/sdiv.rs | 74 ++++++++++++---------- library/compiler-builtins/src/int/shift.rs | 31 +++++---- library/compiler-builtins/src/int/udiv.rs | 74 ++++++++++++---------- library/compiler-builtins/src/lib.rs | 3 + 7 files changed, 141 insertions(+), 106 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index d378461802ab6..e086f7c6ffb67 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -5,11 +5,17 @@ name = "rustc_builtins" version = "0.1.0" [dependencies] -rlibc = { git = "https://github.com/alexcrichton/rlibc", optional = true } + +[dependencies.rlibc] +git = "https://github.com/alexcrichton/rlibc" +optional = true [dev-dependencies] -gcc_s = { path = "gcc_s" } quickcheck = "0.3.1" +rand = "0.3.14" + +[dev-dependencies.gcc_s] +path = "gcc_s" [features] default = ["rlibc/weak"] diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 0943e2e3bbcb9..14ff2f45e2233 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -200,9 +200,11 @@ pub extern fn __aeabi_fadd(a: f32, b: f32) -> f32 { mod tests { use core::{f32, f64}; - use gcc_s; - use qc::{U32, U64}; use float::Float; + use qc::{U32, U64}; + + use gcc_s; + use rand; // NOTE The tests below have special handing for NaN values. // Because NaN != NaN, the floating-point representations must be used @@ -223,7 +225,7 @@ mod tests { // implementation matches the output of the FPU instruction on *hard* float targets // and matches its gcc_s counterpart on *soft* float targets. #[cfg(not(gnueabihf))] - Some(addsf3) => x.eq_repr(unsafe { addsf3(a, b) }), + Some(addsf3) if rand::random() => x.eq_repr(unsafe { addsf3(a, b) }), _ => x.eq_repr(a + b), } } @@ -235,7 +237,7 @@ mod tests { match gcc_s::adddf3() { // NOTE(cfg) See NOTE above #[cfg(not(gnueabihf))] - Some(adddf3) => x.eq_repr(unsafe { adddf3(a, b) }), + Some(adddf3) if rand::random() => x.eq_repr(unsafe { adddf3(a, b) }), _ => x.eq_repr(a + b), } diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 4ea65bd28dcf7..dea3499d4c556 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -72,18 +72,19 @@ mulo!(__mulodi4: i64); #[cfg(test)] mod tests { - use gcc_s; use qc::{I32, I64, U64}; + use gcc_s; + use rand; + quickcheck! { fn muldi(a: U64, b: U64) -> bool { let (a, b) = (a.0, b.0); let r = super::__muldi3(a, b); - if let Some(muldi3) = gcc_s::muldi3() { - r == unsafe { muldi3(a, b) } - } else { - r == a.wrapping_mul(b) + match gcc_s::muldi3() { + Some(muldi3) if rand::random() => r == unsafe { muldi3(a, b) }, + _ => r == a.wrapping_mul(b), } } @@ -95,15 +96,16 @@ mod tests { return false; } - if let Some(mulosi4) = gcc_s::mulosi4() { - let mut gcc_s_overflow = 2; - let gcc_s_r = unsafe { - mulosi4(a, b, &mut gcc_s_overflow) - }; + match gcc_s::mulosi4() { + Some(mulosi4) if rand::random() => { + let mut gcc_s_overflow = 2; + let gcc_s_r = unsafe { + mulosi4(a, b, &mut gcc_s_overflow) + }; - (r, overflow) == (gcc_s_r, gcc_s_overflow) - } else { - (r, overflow != 0) == a.overflowing_mul(b) + (r, overflow) == (gcc_s_r, gcc_s_overflow) + }, + _ => (r, overflow != 0) == a.overflowing_mul(b), } } @@ -115,15 +117,16 @@ mod tests { return false; } - if let Some(mulodi4) = gcc_s::mulodi4() { - let mut gcc_s_overflow = 2; - let gcc_s_r = unsafe { - mulodi4(a, b, &mut gcc_s_overflow) - }; + match gcc_s::mulodi4() { + Some(mulodi4) if rand::random() => { + let mut gcc_s_overflow = 2; + let gcc_s_r = unsafe { + mulodi4(a, b, &mut gcc_s_overflow) + }; - (r, overflow) == (gcc_s_r, gcc_s_overflow) - } else { - (r, overflow != 0) == a.overflowing_mul(b) + (r, overflow) == (gcc_s_r, gcc_s_overflow) + }, + _ => (r, overflow != 0) == a.overflowing_mul(b), } } } diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 50ad0e0a5254b..fcb9ed9d9e847 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -52,9 +52,11 @@ divmod!(__divmoddi4, __divdi3: i64); #[cfg(test)] mod tests { + use qc::{U32, U64}; + use gcc_s; use quickcheck::TestResult; - use qc::{U32, U64}; + use rand; quickcheck!{ fn divdi3(n: U64, d: U64) -> TestResult { @@ -64,10 +66,11 @@ mod tests { } else { let q = super::__divdi3(n, d); - if let Some(divdi3) = gcc_s::divdi3() { - TestResult::from_bool(q == unsafe { divdi3(n, d) }) - } else { - TestResult::from_bool(q == n / d) + match gcc_s::divdi3() { + Some(divdi3) if rand::random() => { + TestResult::from_bool(q == unsafe { divdi3(n, d) }) + }, + _ => TestResult::from_bool(q == n / d), } } } @@ -79,10 +82,11 @@ mod tests { } else { let r = super::__moddi3(n, d); - if let Some(moddi3) = gcc_s::moddi3() { - TestResult::from_bool(r == unsafe { moddi3(n, d) }) - } else { - TestResult::from_bool(r == n % d) + match gcc_s::moddi3() { + Some(moddi3) if rand::random() => { + TestResult::from_bool(r == unsafe { moddi3(n, d) }) + }, + _ => TestResult::from_bool(r == n % d), } } } @@ -95,15 +99,16 @@ mod tests { let mut r = 0; let q = super::__divmoddi4(n, d, &mut r); - if let Some(divmoddi4) = gcc_s::divmoddi4() { - let mut gcc_s_r = 0; - let gcc_s_q = unsafe { - divmoddi4(n, d, &mut gcc_s_r) - }; + match gcc_s::divmoddi4() { + Some(divmoddi4) if rand::random() => { + let mut gcc_s_r = 0; + let gcc_s_q = unsafe { + divmoddi4(n, d, &mut gcc_s_r) + }; - TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) - } else { - TestResult::from_bool(q == n / d && r == n % d) + TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) + }, + _ => TestResult::from_bool(q == n / d && r == n % d), } } } @@ -115,10 +120,11 @@ mod tests { } else { let q = super::__divsi3(n, d); - if let Some(divsi3) = gcc_s::divsi3() { - TestResult::from_bool(q == unsafe { divsi3(n, d)}) - } else { - TestResult::from_bool(q == n / d) + match gcc_s::divsi3() { + Some(divsi3) if rand::random() => { + TestResult::from_bool(q == unsafe { divsi3(n, d)}) + }, + _ => TestResult::from_bool(q == n / d), } } } @@ -130,10 +136,11 @@ mod tests { } else { let r = super::__modsi3(n, d); - if let Some(modsi3) = gcc_s::modsi3() { - TestResult::from_bool(r == unsafe { modsi3(n, d) }) - } else { - TestResult::from_bool(r == n % d) + match gcc_s::modsi3() { + Some(modsi3) if rand::random() => { + TestResult::from_bool(r == unsafe { modsi3(n, d) }) + }, + _ => TestResult::from_bool(r == n % d), } } } @@ -146,15 +153,16 @@ mod tests { let mut r = 0; let q = super::__divmodsi4(n, d, &mut r); - if let Some(divmodsi4) = gcc_s::divmodsi4() { - let mut gcc_s_r = 0; - let gcc_s_q = unsafe { - divmodsi4(n, d, &mut gcc_s_r) - }; + match gcc_s::divmodsi4() { + Some(divmodsi4) if rand::random() => { + let mut gcc_s_r = 0; + let gcc_s_q = unsafe { + divmodsi4(n, d, &mut gcc_s_r) + }; - TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) - } else { - TestResult::from_bool(q == n / d && r == n % d) + TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) + }, + _ => TestResult::from_bool(q == n / d && r == n % d), } } } diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index c7be81171c4a4..bafc9dbe0ce43 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -60,9 +60,11 @@ lshr!(__lshrdi3: u64); #[cfg(test)] mod tests { + use qc::{I64, U64}; + use gcc_s; use quickcheck::TestResult; - use qc::{I64, U64}; + use rand; // NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64) quickcheck! { @@ -73,10 +75,11 @@ mod tests { } else { let r = super::__ashldi3(a, b); - if let Some(ashldi3) = gcc_s::ashldi3() { - TestResult::from_bool(r == unsafe { ashldi3(a, b) }) - } else { - TestResult::from_bool(r == a << b) + match gcc_s::ashldi3() { + Some(ashldi3) if rand::random() => { + TestResult::from_bool(r == unsafe { ashldi3(a, b) }) + }, + _ => TestResult::from_bool(r == a << b), } } } @@ -88,10 +91,11 @@ mod tests { } else { let r = super::__ashrdi3(a, b); - if let Some(ashrdi3) = gcc_s::ashrdi3() { - TestResult::from_bool(r == unsafe { ashrdi3(a, b) }) - } else { - TestResult::from_bool(r == a >> b) + match gcc_s::ashrdi3() { + Some(ashrdi3) if rand::random() => { + TestResult::from_bool(r == unsafe { ashrdi3(a, b) }) + }, + _ => TestResult::from_bool(r == a >> b), } } } @@ -103,10 +107,11 @@ mod tests { } else { let r = super::__lshrdi3(a, b); - if let Some(lshrdi3) = gcc_s::lshrdi3() { - TestResult::from_bool(r == unsafe { lshrdi3(a, b) }) - } else { - TestResult::from_bool(r == a >> b) + match gcc_s::lshrdi3() { + Some(lshrdi3) if rand::random() => { + TestResult::from_bool(r == unsafe { lshrdi3(a, b) }) + }, + _ => TestResult::from_bool(r == a >> b), } } } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 8c9d06f21dfa3..89793c8a82ec1 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -228,9 +228,11 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { #[cfg(test)] mod tests { + use qc::{U32, U64}; + use gcc_s; use quickcheck::TestResult; - use qc::{U32, U64}; + use rand; quickcheck!{ fn udivdi3(n: U64, d: U64) -> TestResult { @@ -240,10 +242,11 @@ mod tests { } else { let q = super::__udivdi3(n, d); - if let Some(udivdi3) = gcc_s::udivdi3() { - TestResult::from_bool(q == unsafe { udivdi3(n, d) }) - } else { - TestResult::from_bool(q == n / d) + match gcc_s::udivdi3() { + Some(udivdi3) if rand::random() => { + TestResult::from_bool(q == unsafe { udivdi3(n, d) }) + }, + _ => TestResult::from_bool(q == n / d), } } } @@ -255,10 +258,11 @@ mod tests { } else { let r = super::__umoddi3(n, d); - if let Some(umoddi3) = gcc_s::umoddi3() { - TestResult::from_bool(r == unsafe { umoddi3(n, d) }) - } else { - TestResult::from_bool(r == n % d) + match gcc_s::umoddi3() { + Some(umoddi3) if rand::random() => { + TestResult::from_bool(r == unsafe { umoddi3(n, d) }) + }, + _ => TestResult::from_bool(r == n % d), } } } @@ -271,15 +275,16 @@ mod tests { let mut r = 0; let q = super::__udivmoddi4(n, d, Some(&mut r)); - if let Some(udivmoddi4) = gcc_s::udivmoddi4() { - let mut gcc_s_r = 0; - let gcc_s_q = unsafe { - udivmoddi4(n, d, Some(&mut gcc_s_r)) - }; + match gcc_s::udivmoddi4() { + Some(udivmoddi4) if rand::random() => { + let mut gcc_s_r = 0; + let gcc_s_q = unsafe { + udivmoddi4(n, d, Some(&mut gcc_s_r)) + }; - TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) - } else { - TestResult::from_bool(q == n / d && r == n % d) + TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) + }, + _ => TestResult::from_bool(q == n / d && r == n % d), } } } @@ -291,10 +296,11 @@ mod tests { } else { let q = super::__udivsi3(n, d); - if let Some(udivsi3) = gcc_s::udivsi3() { - TestResult::from_bool(q == unsafe { udivsi3(n, d) }) - } else { - TestResult::from_bool(q == n / d) + match gcc_s::udivsi3() { + Some(udivsi3) if rand::random() => { + TestResult::from_bool(q == unsafe { udivsi3(n, d) }) + }, + _ => TestResult::from_bool(q == n / d), } } } @@ -306,10 +312,11 @@ mod tests { } else { let r = super::__umodsi3(n, d); - if let Some(umodsi3) = gcc_s::umodsi3() { - TestResult::from_bool(r == unsafe { umodsi3(n, d) }) - } else { - TestResult::from_bool(r == n % d) + match gcc_s::umodsi3() { + Some(umodsi3) if rand::random() => { + TestResult::from_bool(r == unsafe { umodsi3(n, d) }) + }, + _ => TestResult::from_bool(r == n % d), } } } @@ -322,15 +329,16 @@ mod tests { let mut r = 0; let q = super::__udivmodsi4(n, d, Some(&mut r)); - if let Some(udivmodsi4) = gcc_s::udivmodsi4() { - let mut gcc_s_r = 0; - let gcc_s_q = unsafe { - udivmodsi4(n, d, Some(&mut gcc_s_r)) - }; + match gcc_s::udivmodsi4() { + Some(udivmodsi4) if rand::random() => { + let mut gcc_s_r = 0; + let gcc_s_q = unsafe { + udivmodsi4(n, d, Some(&mut gcc_s_r)) + }; - TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) - } else { - TestResult::from_bool(q == n / d && r == n % d) + TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) + }, + _ => TestResult::from_bool(q == n / d && r == n % d), } } } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index cba1604c0e18a..88bbbec359419 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -20,6 +20,9 @@ extern crate core; #[cfg(test)] extern crate gcc_s; +#[cfg(test)] +extern crate rand; + #[cfg(all(not(windows), not(target_os = "macos")))] extern crate rlibc; From 34f17b2ecf2718868d1c74d188dc461761adab5c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 22 Sep 2016 06:15:05 -0500 Subject: [PATCH 0151/4206] test the thumbv7em-none-eabihf target --- library/compiler-builtins/.travis.yml | 2 ++ library/compiler-builtins/ci/env.sh | 2 +- library/compiler-builtins/thumbv7em-none-eabihf.json | 9 +++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/thumbv7em-none-eabihf.json diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 5496bb2913155..d4a1319c7b6ec 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -34,6 +34,8 @@ matrix: os: linux - env: TARGET=thumbv7em-none-eabi os: linux + - env: TARGET=thumbv7em-none-eabihf + os: linux - env: TARGET=thumbv7m-none-eabi os: linux - env: TARGET=x86_64-apple-darwin diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh index feeac221389b5..6275107b55c64 100644 --- a/library/compiler-builtins/ci/env.sh +++ b/library/compiler-builtins/ci/env.sh @@ -32,7 +32,7 @@ if [[ $TARGET != $HOST && ! $TARGET =~ ^i.86- ]]; then # `int main() { return 0; }` RUN_TESTS=n ;; - thumbv*-none-eabi) + thumbv*-none-eabi*) CARGO=xargo GCC_TRIPLE=arm-none-eabi # Bare metal targets. No `std` or `test` crates for these targets. diff --git a/library/compiler-builtins/thumbv7em-none-eabihf.json b/library/compiler-builtins/thumbv7em-none-eabihf.json new file mode 100644 index 0000000000000..bb0b87eb41f60 --- /dev/null +++ b/library/compiler-builtins/thumbv7em-none-eabihf.json @@ -0,0 +1,9 @@ +{ + "arch": "arm", + "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "features": "+vfp4", + "llvm-target": "thumbv7em-none-eabihf", + "os": "none", + "target-endian": "little", + "target-pointer-width": "32" +} From a83c11232ea6d59ea750990834ca94ced5fb315e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 17 Sep 2016 21:10:41 -0500 Subject: [PATCH 0152/4206] avoid division overflow in idivmod test --- library/compiler-builtins/src/arm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index b46b0ea77f59f..903672fc8fc57 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -193,7 +193,7 @@ mod tests { fn idivmod(n: U32, d: U32) -> TestResult { let (n, d) = (n.0 as i32, d.0 as i32); - if d == 0 { + if d == 0 || (n == i32::min_value() && d == -1) { TestResult::discard() } else { let q: i32; From a5b15eef7106bcf385e07116786d58895fd97fbf Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 22 Sep 2016 11:56:34 -0500 Subject: [PATCH 0153/4206] fix build.rs we don't want to match musleabihf targets --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 1ff0c06218f35..298b656a114e3 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1,7 +1,7 @@ use std::env; fn main() { - if env::var("TARGET").unwrap().ends_with("hf") { + if env::var("TARGET").unwrap().ends_with("gnueabihf") { println!("cargo:rustc-cfg=gnueabihf") } } From 2d630eedfdfe076b71b2562bf14e5aec63028d16 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 22 Sep 2016 12:44:22 -0500 Subject: [PATCH 0154/4206] add missing aeabi aliases --- library/compiler-builtins/src/arm.rs | 36 ++++++++++++++++++++-- library/compiler-builtins/src/float/add.rs | 13 -------- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index b46b0ea77f59f..17423cd8fa3c6 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -57,10 +57,15 @@ pub unsafe fn __aeabi_ldivmod() { intrinsics::unreachable(); } -// TODO: These two functions should be defined as aliases +// TODO: These aeabi_* functions should be defined as aliases #[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __aeabi_uidiv(a: u32, b: u32) -> u32 { - ::int::udiv::__udivsi3(a, b) +pub extern "C" fn __aeabi_dadd(a: f64, b: f64) -> f64 { + ::float::add::__adddf3(a, b) +} + +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __aeabi_fadd(a: f32, b: f32) -> f32 { + ::float::add::__addsf3(a, b) } #[cfg_attr(not(test), no_mangle)] @@ -68,6 +73,31 @@ pub extern "C" fn __aeabi_idiv(a: i32, b: i32) -> i32 { ::int::sdiv::__divsi3(a, b) } +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __aeabi_lasr(a: i64, b: u32) -> i64 { + ::int::shift::__ashrdi3(a, b) +} + +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __aeabi_llsl(a: u64, b: u32) -> u64 { + ::int::shift::__ashldi3(a, b) +} + +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __aeabi_llsr(a: u64, b: u32) -> u64 { + ::int::shift::__lshrdi3(a, b) +} + +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __aeabi_lmul(a: u64, b: u64) -> u64 { + ::int::mul::__muldi3(a, b) +} + +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __aeabi_uidiv(a: u32, b: u32) -> u32 { + ::int::udiv::__udivsi3(a, b) +} + extern "C" { fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 3ebc92b32378c..076a462862ec7 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -183,19 +183,6 @@ macro_rules! add { add!(__addsf3: f32); add!(__adddf3: f64); -// FIXME: Implement these using aliases -#[cfg(target_arch = "arm")] -#[cfg_attr(not(test), no_mangle)] -pub extern fn __aeabi_dadd(a: f64, b: f64) -> f64 { - __adddf3(a, b) -} - -#[cfg(target_arch = "arm")] -#[cfg_attr(not(test), no_mangle)] -pub extern fn __aeabi_fadd(a: f32, b: f32) -> f32 { - __addsf3(a, b) -} - #[cfg(test)] mod tests { use core::{f32, f64}; From 2dc91bd96cbf4fefb38bd025539bc86c3ee59319 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 22 Sep 2016 14:46:05 -0500 Subject: [PATCH 0155/4206] put weak mem* symbols behind an opt-in Cargo feature closes #64 cc #66 --- library/compiler-builtins/.travis.yml | 8 ++++++++ library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/ci/script.sh | 25 ++++++++++++++++++++----- library/compiler-builtins/src/lib.rs | 2 +- 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index d4a1319c7b6ec..74f3a08a045d9 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -32,12 +32,20 @@ matrix: os: linux - env: TARGET=thumbv6m-none-eabi os: linux + - env: TARGET=thumbv6m-none-eabi WEAK=true + os: linux - env: TARGET=thumbv7em-none-eabi os: linux + - env: TARGET=thumbv7em-none-eabi WEAK=true + os: linux - env: TARGET=thumbv7em-none-eabihf os: linux + - env: TARGET=thumbv7em-none-eabihf WEAK=true + os: linux - env: TARGET=thumbv7m-none-eabi os: linux + - env: TARGET=thumbv7m-none-eabi WEAK=true + os: linux - env: TARGET=x86_64-apple-darwin language: ruby os: osx diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index e086f7c6ffb67..ae28057e2a9ca 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -18,6 +18,6 @@ rand = "0.3.14" path = "gcc_s" [features] -default = ["rlibc/weak"] +weak = ["rlibc/weak"] [workspace] diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh index 38c6b32376e3a..9dffac5f16e68 100644 --- a/library/compiler-builtins/ci/script.sh +++ b/library/compiler-builtins/ci/script.sh @@ -8,8 +8,13 @@ gist_it() { } build() { - $CARGO build --target $TARGET - $CARGO build --target $TARGET --release + if [[ $WEAK ]]; then + $CARGO build --features weak --target $TARGET + $CARGO build --features weak --target $TARGET --release + else + $CARGO build --target $TARGET + $CARGO build --target $TARGET --release + fi } inspect() { @@ -19,12 +24,21 @@ inspect() { $PREFIX$OBJDUMP -Cd target/**/release/*.rlib | gist_it set -e - # Check presence of weak symbols - if [[ $LINUX ]]; then + # Check presence/absence of weak symbols + if [[ $WEAK ]]; then local symbols=( memcmp memcpy memmove memset ) for symbol in "${symbols[@]}"; do - $PREFIX$NM target/**/debug/deps/librlibc*.rlib | grep -q "W $symbol" + $PREFIX$NM target/$TARGET/debug/deps/librlibc-*.rlib | grep -q "W $symbol" done + else + set +e + ls target/$TARGET/debug/deps/librlibc-*.rlib + + if [[ $? == 0 ]]; then + exit 1 + fi + + set -e fi } @@ -50,6 +64,7 @@ main() { -e TRAVIS_BRANCH=$TRAVIS_BRANCH \ -e TRAVIS_COMMIT=$TRAVIS_COMMIT \ -e TRAVIS_OS_NAME=$TRAVIS_OS_NAME \ + -e WEAK=$WEAK \ -v $(pwd):/mnt \ japaric/rustc-builtins \ sh -c 'cd /mnt; diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 88bbbec359419..7f2d39180ff31 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -23,7 +23,7 @@ extern crate gcc_s; #[cfg(test)] extern crate rand; -#[cfg(all(not(windows), not(target_os = "macos")))] +#[cfg(feature = "weak")] extern crate rlibc; pub mod int; From e7c804a9b020c6172273a660e38ed86b6362e22c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 26 Sep 2016 22:22:10 -0700 Subject: [PATCH 0156/4206] Expand and refactor teting infrastructure This commit moves over most of the testing infrastructure to in-tree docker images that are all dispatched to from Travis (no other test configuration). This allows versioning modifications to the test infrastructure as well as the code itself. Additionally separate docker images allows for easy modification of one without worrying about tampering of others as well as easy addition of new targets by simply adding a new `Dockerfile`. Additionally this commit bundles the master version of the `compiler-rt` source repository from `llvm-mirror/compiler-rt` to test against. The compiler-rt library itself is compiled as a `cdylib` which is then dynamically located at runtime and we look for symbols in. There's a few hoops here, but they currently get the job done. All tests now execute against both gcc_s and compiler-rt, and this testing strategy is now all hidden behind a macro as well (refactoring all existing tests along the way). --- library/compiler-builtins/.gitmodules | 3 + library/compiler-builtins/.travis.yml | 65 +++++----- library/compiler-builtins/Cargo.toml | 5 +- library/compiler-builtins/README.md | 6 +- library/compiler-builtins/appveyor.yml | 1 + library/compiler-builtins/build.rs | 1 + .../aarch64-unknown-linux-gnu/Dockerfile | 10 ++ .../arm-unknown-linux-gnueabi/Dockerfile | 10 ++ .../arm-unknown-linux-gnueabihf/Dockerfile | 9 ++ .../armv7-unknown-linux-gnueabihf/Dockerfile | 9 ++ .../docker/i586-unknown-linux-gnu/Dockerfile | 5 + .../docker/i686-unknown-linux-gnu/Dockerfile | 5 + .../docker/mips-unknown-linux-gnu/Dockerfile | 12 ++ .../mipsel-unknown-linux-gnu/Dockerfile | 12 ++ .../powerpc-unknown-linux-gnu/Dockerfile | 12 ++ .../powerpc64-unknown-linux-gnu/Dockerfile | 13 ++ .../powerpc64le-unknown-linux-gnu/Dockerfile | 13 ++ .../x86_64-unknown-linux-gnu/Dockerfile | 6 + library/compiler-builtins/ci/env.sh | 51 -------- library/compiler-builtins/ci/install.sh | 53 -------- library/compiler-builtins/ci/run-docker.sh | 29 +++++ library/compiler-builtins/ci/script.sh | 80 ------------ .../compiler-builtins/compiler-rt/Cargo.toml | 8 ++ .../compiler-rt/compiler-rt-cdylib/Cargo.toml | 11 ++ .../compiler-rt/compiler-rt-cdylib/build.rs | 68 ++++++++++ .../compiler-rt-cdylib/compiler-rt | 1 + .../compiler-rt/compiler-rt-cdylib/src/lib.rs | 60 +++++++++ .../compiler-builtins/compiler-rt/src/lib.rs | 35 +++++ library/compiler-builtins/gcc_s/src/lib.rs | 39 +----- library/compiler-builtins/src/float/add.rs | 65 +++++----- library/compiler-builtins/src/float/mod.rs | 6 +- library/compiler-builtins/src/int/mul.rs | 58 +++------ library/compiler-builtins/src/int/sdiv.rs | 104 +++++---------- library/compiler-builtins/src/int/shift.rs | 45 ++----- library/compiler-builtins/src/int/udiv.rs | 100 ++++----------- library/compiler-builtins/src/lib.rs | 11 +- library/compiler-builtins/src/qc.rs | 121 ++++++++++++++++++ library/compiler-builtins/src/x86_64.rs | 2 + 38 files changed, 621 insertions(+), 523 deletions(-) create mode 100644 library/compiler-builtins/.gitmodules create mode 100644 library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/ci/env.sh delete mode 100644 library/compiler-builtins/ci/install.sh create mode 100644 library/compiler-builtins/ci/run-docker.sh delete mode 100644 library/compiler-builtins/ci/script.sh create mode 100644 library/compiler-builtins/compiler-rt/Cargo.toml create mode 100644 library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml create mode 100644 library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs create mode 160000 library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt create mode 100644 library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs create mode 100644 library/compiler-builtins/compiler-rt/src/lib.rs diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules new file mode 100644 index 0000000000000..fe501bba96562 --- /dev/null +++ b/library/compiler-builtins/.gitmodules @@ -0,0 +1,3 @@ +[submodule "compiler-rt/compiler-rt-cdylib/compiler-rt"] + path = compiler-rt/compiler-rt-cdylib/compiler-rt + url = https://github.com/llvm-mirror/compiler-rt diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 74f3a08a045d9..47252a4179418 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -1,62 +1,63 @@ dist: trusty -language: generic +language: rust services: docker sudo: required +rust: nightly +cache: cargo matrix: include: - env: TARGET=aarch64-unknown-linux-gnu - os: linux - env: TARGET=arm-unknown-linux-gnueabi - os: linux + # FIXME(rust-lang/rust#36518) + rust: nightly-2016-09-21 - env: TARGET=arm-unknown-linux-gnueabihf - os: linux - env: TARGET=armv7-unknown-linux-gnueabihf - os: linux - env: TARGET=i586-unknown-linux-gnu - os: linux - env: TARGET=i686-apple-darwin - language: ruby + # FIXME(rust-lang/rust#36793) + rust: nightly-2016-09-10 os: osx - env: TARGET=i686-unknown-linux-gnu - os: linux + # FIXME(rust-lang/rust#36793) + rust: nightly-2016-09-10 - env: TARGET=mips-unknown-linux-gnu - os: linux - env: TARGET=mipsel-unknown-linux-gnu - os: linux - env: TARGET=powerpc-unknown-linux-gnu - os: linux - env: TARGET=powerpc64-unknown-linux-gnu - os: linux - - env: TARGET=powerpc64le-unknown-linux-gnu - os: linux + # QEMU crashes even when executing the simplest cross compiled C program: + # `int main() { return 0; }` + - env: TARGET=powerpc64le-unknown-linux-gnu NO_RUN=1 - env: TARGET=thumbv6m-none-eabi - os: linux - - env: TARGET=thumbv6m-none-eabi WEAK=true - os: linux + install: cargo install xargo --debug -f + script: $HOME/.cargo/bin/xargo build --target $TARGET - env: TARGET=thumbv7em-none-eabi - os: linux - - env: TARGET=thumbv7em-none-eabi WEAK=true - os: linux + install: cargo install xargo --debug -f + script: $HOME/.cargo/bin/xargo build --target $TARGET - env: TARGET=thumbv7em-none-eabihf - os: linux - - env: TARGET=thumbv7em-none-eabihf WEAK=true - os: linux - - env: TARGET=thumbv7m-none-eabi - os: linux - - env: TARGET=thumbv7m-none-eabi WEAK=true - os: linux + install: cargo install xargo --debug -f + script: $HOME/.cargo/bin/xargo build --target $TARGET - env: TARGET=x86_64-apple-darwin - language: ruby os: osx - - env: TARGET=x86_64-unknown-linux-gnu - os: linux +env: TARGET=x86_64-unknown-linux-gnu + +before_install: + - test "$TRAVIS_OS_NAME" = "osx" || docker run --rm --privileged multiarch/qemu-user-static:register install: - - bash ci/install.sh + - curl https://static.rust-lang.org/rustup.sh | + sh -s -- --add-target=$TARGET --disable-sudo -y --prefix=`rustc --print sysroot` script: - - bash ci/script.sh + - cargo generate-lockfile + - if [[ $TRAVIS_OS_NAME = "linux" ]]; then + sudo apt-get remove -y qemu-user-static && + sudo apt-get install -y qemu-user-static && + sh ci/run-docker.sh $TARGET; + else + cargo test --target $TARGET && + cargo test --target $TARGET --release; + fi branches: only: diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index ae28057e2a9ca..6e75a116bbf0a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -13,9 +13,8 @@ optional = true [dev-dependencies] quickcheck = "0.3.1" rand = "0.3.14" - -[dev-dependencies.gcc_s] -path = "gcc_s" +gcc_s = { path = "gcc_s" } +compiler-rt = { path = "compiler-rt" } [features] weak = ["rlibc/weak"] diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index edccd301838af..28d86043ad5c5 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -16,8 +16,8 @@ See [rust-lang/rust#35437][0]. If you are working with a target that doesn't have binary releases of std available via rustup (this probably means you are building the core crate yourself) and need compiler-rt intrinsics (i.e. you -are probably getting linker errors when building an executable: "undefined reference to -__aeabi_memcpy"), you can use this crate to get those intrinsics and solve the linker errors. To do +are probably getting linker errors when building an executable: `undefined reference to +__aeabi_memcpy`), you can use this crate to get those intrinsics and solve the linker errors. To do that, simply add this crate as a Cargo dependency (it doesn't matter where in the dependency graph this crate ends up, as long as it's there): @@ -52,7 +52,7 @@ porting that particular intrinsic. 1. [Rust][4] and [C][5] have slightly different operator precedence. C evaluates comparisons (`== !=`) before bitwise operations (`& | ^`), while Rust evaluates the other way. 2. C assumes wrapping operations everywhere. Rust panics on overflow when in debug mode. Consider using the [Wrapping][6] type or the explicit [wrapping_*][7] functions where applicable. 3. Note [C implicit casts][8], especially integer promotion. Rust is much more explicit about casting, so be sure that any cast which affects the output is ported to the Rust implementation. -4. Rust has [many functions][9] for integer or floating point manipulation in the standard library. Consider using one of these functions rather than porting a new one. +4. Rust has [many functions][9] for integer or floating point manipulation in the standard library. Consider using one of these functions rather than porting a new one. [4]: https://doc.rust-lang.org/reference.html#operator-precedence [5]: http://en.cppreference.com/w/c/language/operator_precedence diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index b34efc21e61ea..0e64977c1752a 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -4,6 +4,7 @@ environment: - TARGET: x86_64-pc-windows-msvc install: + - git submodule update --init - curl -sSf -o rustup-init.exe https://win.rustup.rs - rustup-init.exe --default-host %TARGET% --default-toolchain nightly -y - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 298b656a114e3..3ef6c2895542e 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4,4 +4,5 @@ fn main() { if env::var("TARGET").unwrap().ends_with("gnueabihf") { println!("cargo:rustc-cfg=gnueabihf") } + println!("cargo:rerun-if-changed=build.rs"); } diff --git a/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile new file mode 100644 index 0000000000000..6a68154d1920a --- /dev/null +++ b/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,10 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-aarch64-linux-gnu libc6-dev-arm64-cross \ + qemu-user-static +ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ + PATH=$PATH:/rust/bin \ + QEMU_LD_PREFIX=/usr/aarch64-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile new file mode 100644 index 0000000000000..36efcd73cccb5 --- /dev/null +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile @@ -0,0 +1,10 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-linux-gnueabi libc6-dev-armel-cross qemu-user-static +ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER=arm-linux-gnueabi-gcc \ + PATH=$PATH:/rust/bin \ + QEMU_LD_PREFIX=/usr/arm-linux-gnueabi \ + RUST_TEST_THREADS=1 + diff --git a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile new file mode 100644 index 0000000000000..83e7e52e8f27b --- /dev/null +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile @@ -0,0 +1,9 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static +ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + PATH=$PATH:/rust/bin \ + QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile new file mode 100644 index 0000000000000..adc15a5c5c5f3 --- /dev/null +++ b/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile @@ -0,0 +1,9 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static +ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + PATH=$PATH:/rust/bin \ + QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile new file mode 100644 index 0000000000000..63450ff9e0efc --- /dev/null +++ b/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile @@ -0,0 +1,5 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc-multilib libc6-dev ca-certificates +ENV PATH=$PATH:/rust/bin diff --git a/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile new file mode 100644 index 0000000000000..63450ff9e0efc --- /dev/null +++ b/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile @@ -0,0 +1,5 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc-multilib libc6-dev ca-certificates +ENV PATH=$PATH:/rust/bin diff --git a/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile new file mode 100644 index 0000000000000..328152471f883 --- /dev/null +++ b/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile @@ -0,0 +1,12 @@ +FROM ubuntu:16.04 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-mips-linux-gnu libc6-dev-mips-cross \ + binfmt-support qemu-user-static qemu-system-mips + +ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER=mips-linux-gnu-gcc \ + PATH=$PATH:/rust/bin \ + QEMU_LD_PREFIX=/usr/mips-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile new file mode 100644 index 0000000000000..088c45f04a863 --- /dev/null +++ b/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile @@ -0,0 +1,12 @@ +FROM ubuntu:16.04 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-mipsel-linux-gnu libc6-dev-mipsel-cross \ + binfmt-support qemu-user-static + +ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER=mipsel-linux-gnu-gcc \ + PATH=$PATH:/rust/bin \ + QEMU_LD_PREFIX=/usr/mipsel-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile new file mode 100644 index 0000000000000..542afa2f4d91a --- /dev/null +++ b/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile @@ -0,0 +1,12 @@ +FROM ubuntu:16.04 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user-static ca-certificates \ + gcc-powerpc-linux-gnu libc6-dev-powerpc-cross \ + qemu-system-ppc + +ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER=powerpc-linux-gnu-gcc \ + PATH=$PATH:/rust/bin \ + QEMU_LD_PREFIX=/usr/powerpc-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile new file mode 100644 index 0000000000000..f4559c7de99f7 --- /dev/null +++ b/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,13 @@ +FROM ubuntu:16.04 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross \ + binfmt-support qemu-user-static qemu-system-ppc + +ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER=powerpc64-linux-gnu-gcc \ + CC_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-gcc \ + PATH=$PATH:/rust/bin \ + QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile new file mode 100644 index 0000000000000..9a777883d248b --- /dev/null +++ b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile @@ -0,0 +1,13 @@ +FROM ubuntu:16.04 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user-static ca-certificates \ + gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross \ + qemu-system-ppc + +ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER=powerpc64le-linux-gnu-gcc \ + CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \ + PATH=$PATH:/rust/bin \ + QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu \ + RUST_TEST_THREADS=1 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 new file mode 100644 index 0000000000000..a5704bb64b4e4 --- /dev/null +++ b/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,6 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates +ENV PATH=$PATH:/rust/bin + diff --git a/library/compiler-builtins/ci/env.sh b/library/compiler-builtins/ci/env.sh deleted file mode 100644 index 6275107b55c64..0000000000000 --- a/library/compiler-builtins/ci/env.sh +++ /dev/null @@ -1,51 +0,0 @@ -case $TRAVIS_OS_NAME in - linux) - HOST=x86_64-unknown-linux-gnu - NM=nm - OBJDUMP=objdump - LINUX=y - ;; - osx) - HOST=x86_64-apple-darwin - NM=gnm - OBJDUMP=gobjdump - OSX=y - ;; -esac - -# NOTE For rustup -export PATH="$HOME/.cargo/bin:$PATH" - -CARGO=cargo -RUN_TESTS=y - -# NOTE For the host and its 32-bit variants we don't need prefixed tools or QEMU -if [[ $TARGET != $HOST && ! $TARGET =~ ^i.86- ]]; then - GCC_TRIPLE=${TARGET//unknown-/} - - case $TARGET in - armv7-unknown-linux-gnueabihf) - GCC_TRIPLE=arm-linux-gnueabihf - ;; - powerpc64le-unknown-linux-gnu) - # QEMU crashes even when executing the simplest cross compiled C program: - # `int main() { return 0; }` - RUN_TESTS=n - ;; - thumbv*-none-eabi*) - CARGO=xargo - GCC_TRIPLE=arm-none-eabi - # Bare metal targets. No `std` or `test` crates for these targets. - RUN_TESTS=n - ;; - esac - - export CARGO_TARGET_$(echo $TARGET | tr a-z- A-Z_)_LINKER=$GCC_TRIPLE-gcc - - if [[ $RUN_TESTS == y ]]; then - # NOTE(export) so this can reach the processes that `cargo test` spawns - export QEMU_LD_PREFIX=/usr/$GCC_TRIPLE - fi - - PREFIX=$GCC_TRIPLE- -fi diff --git a/library/compiler-builtins/ci/install.sh b/library/compiler-builtins/ci/install.sh deleted file mode 100644 index 86095e33e8980..0000000000000 --- a/library/compiler-builtins/ci/install.sh +++ /dev/null @@ -1,53 +0,0 @@ -set -ex - -. $(dirname $0)/env.sh - -install_qemu() { - if [[ $QEMU_LD_PREFIX ]]; then - apt-get update - apt-get install -y --no-install-recommends \ - binfmt-support qemu-user-static - fi -} - -install_gist() { - if [[ $OSX ]]; then - gem install gist -v 4.5.0 - fi -} - -install_binutils() { - if [[ $OSX ]]; then - brew install binutils - fi -} - -install_rust() { - if [[ $OSX ]]; then - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain=nightly - else - rustup default nightly - fi - - rustup -V - rustc -V - cargo -V -} - -add_rustup_target() { - if [[ $TARGET != $HOST && $CARGO == cargo ]]; then - rustup target add $TARGET - fi -} - -main() { - if [[ $OSX || ${IN_DOCKER_CONTAINER:-n} == y ]]; then - install_qemu - install_gist - install_binutils - install_rust - add_rustup_target - fi -} - -main diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh new file mode 100644 index 0000000000000..8ef024e822246 --- /dev/null +++ b/library/compiler-builtins/ci/run-docker.sh @@ -0,0 +1,29 @@ +# Small script to run tests for a target (or all targets) inside all the +# respective docker images. + +set -ex + +run() { + echo $1 + CMD="cargo test --target $1" + if [ "$NO_RUN" = "1" ]; then + CMD="$CMD --no-run" + fi + docker build -t libc ci/docker/$1 + docker run \ + -v `rustc --print sysroot`:/rust:ro \ + -v `pwd`:/checkout:ro \ + -e CARGO_TARGET_DIR=/tmp/target \ + -w /checkout \ + --privileged \ + -it libc \ + bash -c "$CMD && $CMD --release" +} + +if [ -z "$1" ]; then + for d in `ls ci/docker/`; do + run $d + done +else + run $1 +fi diff --git a/library/compiler-builtins/ci/script.sh b/library/compiler-builtins/ci/script.sh deleted file mode 100644 index 9dffac5f16e68..0000000000000 --- a/library/compiler-builtins/ci/script.sh +++ /dev/null @@ -1,80 +0,0 @@ -set -ex - -. $(dirname $0)/env.sh - -gist_it() { - gist -d "'$TARGET/rustc-builtins.rlib' from commit '$TRAVIS_COMMIT' on branch '$TRAVIS_BRANCH'" - echo "Disassembly available at the above URL." -} - -build() { - if [[ $WEAK ]]; then - $CARGO build --features weak --target $TARGET - $CARGO build --features weak --target $TARGET --release - else - $CARGO build --target $TARGET - $CARGO build --target $TARGET --release - fi -} - -inspect() { - $PREFIX$NM -g --defined-only target/**/debug/*.rlib - - set +e - $PREFIX$OBJDUMP -Cd target/**/release/*.rlib | gist_it - set -e - - # Check presence/absence of weak symbols - if [[ $WEAK ]]; then - local symbols=( memcmp memcpy memmove memset ) - for symbol in "${symbols[@]}"; do - $PREFIX$NM target/$TARGET/debug/deps/librlibc-*.rlib | grep -q "W $symbol" - done - else - set +e - ls target/$TARGET/debug/deps/librlibc-*.rlib - - if [[ $? == 0 ]]; then - exit 1 - fi - - set -e - fi - -} - -run_tests() { - if [[ $QEMU_LD_PREFIX ]]; then - export RUST_TEST_THREADS=1 - fi - - if [[ $RUN_TESTS == y ]]; then - cargo test --target $TARGET - cargo test --target $TARGET --release - fi -} - -main() { - if [[ $LINUX && ${IN_DOCKER_CONTAINER:-n} == n ]]; then - # NOTE The Dockerfile of this image is in the docker branch of this repository - docker run \ - --privileged \ - -e IN_DOCKER_CONTAINER=y \ - -e TARGET=$TARGET \ - -e TRAVIS_BRANCH=$TRAVIS_BRANCH \ - -e TRAVIS_COMMIT=$TRAVIS_COMMIT \ - -e TRAVIS_OS_NAME=$TRAVIS_OS_NAME \ - -e WEAK=$WEAK \ - -v $(pwd):/mnt \ - japaric/rustc-builtins \ - sh -c 'cd /mnt; - bash ci/install.sh; - bash ci/script.sh' - else - build - inspect - run_tests - fi -} - -main diff --git a/library/compiler-builtins/compiler-rt/Cargo.toml b/library/compiler-builtins/compiler-rt/Cargo.toml new file mode 100644 index 0000000000000..cac87733a6290 --- /dev/null +++ b/library/compiler-builtins/compiler-rt/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "compiler-rt" +version = "0.1.0" +authors = ["Alex Crichton "] + +[dependencies] +compiler-rt-cdylib = { path = "compiler-rt-cdylib" } +libloading = "0.3" diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml new file mode 100644 index 0000000000000..3c64d23d37e94 --- /dev/null +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "compiler-rt-cdylib" +version = "0.1.0" +authors = ["Alex Crichton "] +build = "build.rs" + +[lib] +crate-type = ["cdylib"] + +[build-dependencies] +gcc = "0.3" diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs new file mode 100644 index 0000000000000..b9b56a627b034 --- /dev/null +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs @@ -0,0 +1,68 @@ +extern crate gcc; + +use std::env; +use std::path::Path; +use std::process::Command; + +struct Sources { + files: Vec<&'static str>, +} + +impl Sources { + fn new() -> Sources { + Sources { files: Vec::new() } + } + + fn extend(&mut self, sources: &[&'static str]) { + self.files.extend(sources); + } +} + +fn main() { + if !Path::new("compiler-rt/.git").exists() { + let _ = Command::new("git").args(&["submodule", "update", "--init"]) + .status(); + } + + let target = env::var("TARGET").expect("TARGET was not set"); + let cfg = &mut gcc::Config::new(); + + if target.contains("msvc") { + cfg.define("__func__", Some("__FUNCTION__")); + } else { + cfg.flag("-fno-builtin"); + cfg.flag("-fomit-frame-pointer"); + cfg.flag("-ffreestanding"); + } + + let mut sources = Sources::new(); + + sources.extend(&[ + "muldi3.c", + "mulosi4.c", + "mulodi4.c", + "divsi3.c", + "divdi3.c", + "modsi3.c", + "moddi3.c", + "divmodsi4.c", + "divmoddi4.c", + "ashldi3.c", + "ashrdi3.c", + "lshrdi3.c", + "udivdi3.c", + "umoddi3.c", + "udivmoddi4.c", + "udivsi3.c", + "umodsi3.c", + "udivmodsi4.c", + "adddf3.c", + "addsf3.c", + ]); + + for src in sources.files.iter() { + cfg.file(Path::new("compiler-rt/lib/builtins").join(src)); + } + + cfg.compile("libcompiler-rt.a"); +} diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt new file mode 160000 index 0000000000000..515106ebc0722 --- /dev/null +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt @@ -0,0 +1 @@ +Subproject commit 515106ebc07227b85336816ef77bc39506b8fd26 diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs new file mode 100644 index 0000000000000..57584832ff805 --- /dev/null +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs @@ -0,0 +1,60 @@ +#![feature(lang_items)] +#![no_std] + +extern { + fn __ashldi3(); + fn __ashrdi3(); + fn __divdi3(); + fn __divmoddi4(); + fn __divmodsi4(); + fn __divsi3(); + fn __lshrdi3(); + fn __moddi3(); + fn __modsi3(); + fn __muldi3(); + fn __mulodi4(); + fn __mulosi4(); + fn __udivdi3(); + fn __udivmoddi4(); + fn __udivmodsi4(); + fn __udivsi3(); + fn __umoddi3(); + fn __umodsi3(); + fn __addsf3(); + fn __adddf3(); +} + +macro_rules! declare { + ($func:ident, $sym:ident) => { + #[no_mangle] + pub extern fn $func() -> usize { + $sym as usize + } + } +} + +declare!(___ashldi3, __ashldi3); +declare!(___ashrdi3, __ashrdi3); +declare!(___divdi3, __divdi3); +declare!(___divmoddi4, __divmoddi4); +declare!(___divmodsi4, __divmodsi4); +declare!(___divsi3, __divsi3); +declare!(___lshrdi3, __lshrdi3); +declare!(___moddi3, __moddi3); +declare!(___modsi3, __modsi3); +declare!(___muldi3, __muldi3); +declare!(___mulodi4, __mulodi4); +declare!(___mulosi4, __mulosi4); +declare!(___udivdi3, __udivdi3); +declare!(___udivmoddi4, __udivmoddi4); +declare!(___udivmodsi4, __udivmodsi4); +declare!(___udivsi3, __udivsi3); +declare!(___umoddi3, __umoddi3); +declare!(___umodsi3, __umodsi3); +declare!(___addsf3, __addsf3); +declare!(___adddf3, __adddf3); + +#[lang = "eh_personality"] +fn eh_personality() {} +#[lang = "panic_fmt"] +fn panic_fmt() {} diff --git a/library/compiler-builtins/compiler-rt/src/lib.rs b/library/compiler-builtins/compiler-rt/src/lib.rs new file mode 100644 index 0000000000000..ca99f397f5540 --- /dev/null +++ b/library/compiler-builtins/compiler-rt/src/lib.rs @@ -0,0 +1,35 @@ +#![feature(drop_types_in_const)] + +extern crate libloading; + +use std::sync::{Once, ONCE_INIT}; +use std::env; + +use libloading::Library; + +fn compiler_rt() -> &'static Library { + let dir = env::current_exe().unwrap(); + let cdylib = dir.parent().unwrap().read_dir().unwrap().map(|c| { + c.unwrap().path() + }).find(|path| { + path.file_name().unwrap().to_str().unwrap().contains("compiler_rt_cdylib") + }).unwrap(); + + unsafe { + static mut COMPILER_RT: Option = None; + static INIT: Once = ONCE_INIT; + + INIT.call_once(|| { + COMPILER_RT = Some(Library::new(&cdylib).unwrap()); + }); + COMPILER_RT.as_ref().unwrap() + } +} + +pub fn get(sym: &str) -> usize { + unsafe { + let sym = format!("_{}", sym); + let f: fn() -> usize = *compiler_rt().get(sym.as_bytes()).unwrap(); + f() + } +} diff --git a/library/compiler-builtins/gcc_s/src/lib.rs b/library/compiler-builtins/gcc_s/src/lib.rs index fa034b0b3ddfe..e3417ffb591b7 100644 --- a/library/compiler-builtins/gcc_s/src/lib.rs +++ b/library/compiler-builtins/gcc_s/src/lib.rs @@ -27,42 +27,13 @@ fn gcc_s() -> &'static Library { } #[cfg(windows)] -macro_rules! declare { - ($symbol:ident: fn($($i:ty),+) -> $o:ty) => { - pub fn $symbol() -> Option $o> { - None - } - } +pub fn get(_sym: &str) -> Option { + None } #[cfg(not(windows))] -macro_rules! declare { - ($symbol:ident: fn($($i:ty),+) -> $o:ty) => { - pub fn $symbol() -> Option $o> { - unsafe { - gcc_s().get(concat!("__", stringify!($symbol)).as_bytes()).ok().map(|s| *s) - } - } +pub fn get(sym: &str) -> Option { + unsafe { + gcc_s().get(sym.as_bytes()).ok().map(|s| *s) } } - -declare!(ashldi3: fn(u64, u32) -> u64); -declare!(ashrdi3: fn(i64, u32) -> i64); -declare!(divdi3: fn(i64, i64) -> i64); -declare!(divmoddi4: fn(i64, i64, &mut i64) -> i64); -declare!(divmodsi4: fn(i32, i32, &mut i32) -> i32); -declare!(divsi3: fn(i32, i32) -> i32); -declare!(lshrdi3: fn(u64, u32) -> u64); -declare!(moddi3: fn(i64, i64) -> i64); -declare!(modsi3: fn(i32, i32) -> i32); -declare!(muldi3: fn(u64, u64) -> u64); -declare!(mulodi4: fn(i64, i64, &mut i32) -> i64); -declare!(mulosi4: fn(i32, i32, &mut i32) -> i32); -declare!(udivdi3: fn(u64, u64) -> u64); -declare!(udivmoddi4: fn(u64, u64, Option<&mut u64>) -> u64); -declare!(udivmodsi4: fn(u32, u32, Option<&mut u32>) -> u32); -declare!(udivsi3: fn(u32, u32) -> u32); -declare!(umoddi3: fn(u64, u64) -> u64); -declare!(umodsi3: fn(u32, u32) -> u32); -declare!(addsf3: fn(f32, f32) -> f32); -declare!(adddf3: fn(f64, f64) -> f64); diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 7c3856a0ab385..1e7a651c96cee 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -89,12 +89,12 @@ macro_rules! add { if a_exponent.0 == 0 { let (exponent, significand) = <$ty>::normalize(a_significand.0); a_exponent = Wrapping(exponent); - a_significand = Wrapping(significand); + a_significand = Wrapping(significand); } if b_exponent.0 == 0 { let (exponent, significand) = <$ty>::normalize(b_significand.0); b_exponent = Wrapping(exponent); - b_significand = Wrapping(significand); + b_significand = Wrapping(significand); } // The sign of the result is the sign of the larger operand, a. If they @@ -123,8 +123,8 @@ macro_rules! add { if subtraction { a_significand -= b_significand; // If a == -b, return +zero. - if a_significand.0 == 0 { - return (<$ty as Float>::from_repr(0)); + if a_significand.0 == 0 { + return (<$ty as Float>::from_repr(0)); } // If partial cancellation occured, we need to left-shift the result @@ -148,7 +148,7 @@ macro_rules! add { } // If we have overflowed the type, return +/- infinity: - if a_exponent >= Wrapping(max_exponent.0 as i32) { + if a_exponent >= Wrapping(max_exponent.0 as i32) { return (<$ty>::from_repr((inf_rep | result_sign).0)); } @@ -190,47 +190,46 @@ mod tests { use float::Float; use qc::{U32, U64}; - use gcc_s; - use rand; - // NOTE The tests below have special handing for NaN values. // Because NaN != NaN, the floating-point representations must be used // Because there are many diffferent values of NaN, and the implementation // doesn't care about calculating the 'correct' one, if both values are NaN // the values are considered equivalent. + struct FRepr(F); + + impl PartialEq for FRepr { + fn eq(&self, other: &FRepr) -> bool { + // NOTE(cfg) for some reason, on hard float targets, our implementation doesn't + // match the output of its gcc_s counterpart. Until we investigate further, we'll + // just avoid testing against gcc_s on those targets. Do note that our + // implementation matches the output of the FPU instruction on *hard* float targets + // and matches its gcc_s counterpart on *soft* float targets. + if cfg!(gnueabihf) { + return true + } + self.0.eq_repr(other.0) + } + } + // TODO: Add F32/F64 to qc so that they print the right values (at the very least) - quickcheck! { - fn addsf3(a: U32, b: U32) -> bool { + check! { + fn __addsf3(f: extern fn(f32, f32) -> f32, + a: U32, + b: U32) + -> Option > { let (a, b) = (f32::from_repr(a.0), f32::from_repr(b.0)); - let x = super::__addsf3(a, b); - - match gcc_s::addsf3() { - // NOTE(cfg) for some reason, on hard float targets, our implementation doesn't - // match the output of its gcc_s counterpart. Until we investigate further, we'll - // just avoid testing against gcc_s on those targets. Do note that our - // implementation matches the output of the FPU instruction on *hard* float targets - // and matches its gcc_s counterpart on *soft* float targets. - #[cfg(not(gnueabihf))] - Some(addsf3) if rand::random() => x.eq_repr(unsafe { addsf3(a, b) }), - _ => x.eq_repr(a + b), - } + Some(FRepr(f(a, b))) } - fn adddf3(a: U64, b: U64) -> bool { + fn __adddf3(f: extern fn(f64, f64) -> f64, + a: U64, + b: U64) -> Option > { let (a, b) = (f64::from_repr(a.0), f64::from_repr(b.0)); - let x = super::__adddf3(a, b); - - match gcc_s::adddf3() { - // NOTE(cfg) See NOTE above - #[cfg(not(gnueabihf))] - Some(adddf3) if rand::random() => x.eq_repr(unsafe { adddf3(a, b) }), - _ => x.eq_repr(a + b), - - } + Some(FRepr(f(a, b))) } } - + // More tests for special float values #[test] diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index bd9194bfb7925..cee2b73987392 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -3,10 +3,10 @@ use core::mem; pub mod add; /// Trait for some basic operations on floats -pub trait Float: Sized { +pub trait Float: Sized + Copy { /// A uint of the same with as the float type Int; - + /// Returns the bitwidth of the float type fn bits() -> u32; @@ -22,7 +22,7 @@ pub trait Float: Sized { /// compared. fn eq_repr(self, rhs: Self) -> bool; - /// Returns a `Self::Int` transmuted back to `Self` + /// Returns a `Self::Int` transmuted back to `Self` fn from_repr(a: Self::Int) -> Self; /// Returns (normalized exponent, normalized significand) diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index dea3499d4c556..ea48ca9c070e3 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -74,60 +74,34 @@ mulo!(__mulodi4: i64); mod tests { use qc::{I32, I64, U64}; - use gcc_s; - use rand; - - quickcheck! { - fn muldi(a: U64, b: U64) -> bool { - let (a, b) = (a.0, b.0); - let r = super::__muldi3(a, b); - - match gcc_s::muldi3() { - Some(muldi3) if rand::random() => r == unsafe { muldi3(a, b) }, - _ => r == a.wrapping_mul(b), - } + check! { + fn __muldi3(f: extern fn(u64, u64) -> u64, a: U64, b: U64) + -> Option { + Some(f(a.0, b.0)) } - fn mulosi(a: I32, b: I32) -> bool { + fn __mulosi4(f: extern fn(i32, i32, &mut i32) -> i32, + a: I32, + b: I32) -> Option<(i32, i32)> { let (a, b) = (a.0, b.0); let mut overflow = 2; - let r = super::__mulosi4(a, b, &mut overflow); + let r = f(a, b, &mut overflow); if overflow != 0 && overflow != 1 { - return false; - } - - match gcc_s::mulosi4() { - Some(mulosi4) if rand::random() => { - let mut gcc_s_overflow = 2; - let gcc_s_r = unsafe { - mulosi4(a, b, &mut gcc_s_overflow) - }; - - (r, overflow) == (gcc_s_r, gcc_s_overflow) - }, - _ => (r, overflow != 0) == a.overflowing_mul(b), + return None } + Some((r, overflow)) } - fn mulodi(a: I64, b: I64) -> bool { + fn __mulodi4(f: extern fn(i64, i64, &mut i32) -> i64, + a: I64, + b: I64) -> Option<(i64, i32)> { let (a, b) = (a.0, b.0); let mut overflow = 2; - let r = super::__mulodi4(a, b, &mut overflow); + let r = f(a, b, &mut overflow); if overflow != 0 && overflow != 1 { - return false; - } - - match gcc_s::mulodi4() { - Some(mulodi4) if rand::random() => { - let mut gcc_s_overflow = 2; - let gcc_s_r = unsafe { - mulodi4(a, b, &mut gcc_s_overflow) - }; - - (r, overflow) == (gcc_s_r, gcc_s_overflow) - }, - _ => (r, overflow != 0) == a.overflowing_mul(b), + return None } + Some((r, overflow)) } } } diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index fcb9ed9d9e847..7a8e38e5e6d01 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -54,116 +54,70 @@ divmod!(__divmoddi4, __divdi3: i64); mod tests { use qc::{U32, U64}; - use gcc_s; - use quickcheck::TestResult; - use rand; - - quickcheck!{ - fn divdi3(n: U64, d: U64) -> TestResult { + check! { + fn __divdi3(f: extern fn(i64, i64) -> i64, n: U64, d: U64) -> Option { let (n, d) = (n.0 as i64, d.0 as i64); if d == 0 { - TestResult::discard() + None } else { - let q = super::__divdi3(n, d); - - match gcc_s::divdi3() { - Some(divdi3) if rand::random() => { - TestResult::from_bool(q == unsafe { divdi3(n, d) }) - }, - _ => TestResult::from_bool(q == n / d), - } + Some(f(n, d)) } } - fn moddi3(n: U64, d: U64) -> TestResult { + fn __moddi3(f: extern fn(i64, i64) -> i64, n: U64, d: U64) -> Option { let (n, d) = (n.0 as i64, d.0 as i64); if d == 0 { - TestResult::discard() + None } else { - let r = super::__moddi3(n, d); - - match gcc_s::moddi3() { - Some(moddi3) if rand::random() => { - TestResult::from_bool(r == unsafe { moddi3(n, d) }) - }, - _ => TestResult::from_bool(r == n % d), - } + Some(f(n, d)) } } - fn divmoddi4(n: U64, d: U64) -> TestResult { + fn __divmoddi4(f: extern fn(i64, i64, &mut i64) -> i64, + n: U64, + d: U64) -> Option<(i64, i64)> { let (n, d) = (n.0 as i64, d.0 as i64); if d == 0 { - TestResult::discard() + None } else { let mut r = 0; - let q = super::__divmoddi4(n, d, &mut r); - - match gcc_s::divmoddi4() { - Some(divmoddi4) if rand::random() => { - let mut gcc_s_r = 0; - let gcc_s_q = unsafe { - divmoddi4(n, d, &mut gcc_s_r) - }; - - TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) - }, - _ => TestResult::from_bool(q == n / d && r == n % d), - } + let q = f(n, d, &mut r); + Some((q, r)) } } - fn divsi3(n: U32, d: U32) -> TestResult { + fn __divsi3(f: extern fn(i32, i32) -> i32, + n: U32, + d: U32) -> Option { let (n, d) = (n.0 as i32, d.0 as i32); if d == 0 { - TestResult::discard() + None } else { - let q = super::__divsi3(n, d); - - match gcc_s::divsi3() { - Some(divsi3) if rand::random() => { - TestResult::from_bool(q == unsafe { divsi3(n, d)}) - }, - _ => TestResult::from_bool(q == n / d), - } + Some(f(n, d)) } } - fn modsi3(n: U32, d: U32) -> TestResult { + fn __modsi3(f: extern fn(i32, i32) -> i32, + n: U32, + d: U32) -> Option { let (n, d) = (n.0 as i32, d.0 as i32); if d == 0 { - TestResult::discard() + None } else { - let r = super::__modsi3(n, d); - - match gcc_s::modsi3() { - Some(modsi3) if rand::random() => { - TestResult::from_bool(r == unsafe { modsi3(n, d) }) - }, - _ => TestResult::from_bool(r == n % d), - } + Some(f(n, d)) } } - fn divmodsi4(n: U32, d: U32) -> TestResult { + fn __divmodsi4(f: extern fn(i32, i32, &mut i32) -> i32, + n: U32, + d: U32) -> Option<(i32, i32)> { let (n, d) = (n.0 as i32, d.0 as i32); if d == 0 { - TestResult::discard() + None } else { let mut r = 0; - let q = super::__divmodsi4(n, d, &mut r); - - match gcc_s::divmodsi4() { - Some(divmodsi4) if rand::random() => { - let mut gcc_s_r = 0; - let gcc_s_q = unsafe { - divmodsi4(n, d, &mut gcc_s_r) - }; - - TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) - }, - _ => TestResult::from_bool(q == n / d && r == n % d), - } + let q = f(n, d, &mut r); + Some((q, r)) } } } diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index bafc9dbe0ce43..4fc23918cbfc6 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -62,57 +62,32 @@ lshr!(__lshrdi3: u64); mod tests { use qc::{I64, U64}; - use gcc_s; - use quickcheck::TestResult; - use rand; - // NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64) - quickcheck! { - fn ashldi(a: U64, b: u32) -> TestResult { + check! { + fn __ashldi3(f: extern fn(u64, u32) -> u64, a: U64, b: u32) -> Option { let a = a.0; if b >= 64 { - TestResult::discard() + None } else { - let r = super::__ashldi3(a, b); - - match gcc_s::ashldi3() { - Some(ashldi3) if rand::random() => { - TestResult::from_bool(r == unsafe { ashldi3(a, b) }) - }, - _ => TestResult::from_bool(r == a << b), - } + Some(f(a, b)) } } - fn ashrdi(a: I64, b: u32) -> TestResult { + fn __ashrdi3(f: extern fn(i64, u32) -> i64, a: I64, b: u32) -> Option { let a = a.0; if b >= 64 { - TestResult::discard() + None } else { - let r = super::__ashrdi3(a, b); - - match gcc_s::ashrdi3() { - Some(ashrdi3) if rand::random() => { - TestResult::from_bool(r == unsafe { ashrdi3(a, b) }) - }, - _ => TestResult::from_bool(r == a >> b), - } + Some(f(a, b)) } } - fn lshrdi(a: U64, b: u32) -> TestResult { + fn __lshrdi3(f: extern fn(u64, u32) -> u64, a: U64, b: u32) -> Option { let a = a.0; if b >= 64 { - TestResult::discard() + None } else { - let r = super::__lshrdi3(a, b); - - match gcc_s::lshrdi3() { - Some(lshrdi3) if rand::random() => { - TestResult::from_bool(r == unsafe { lshrdi3(a, b) }) - }, - _ => TestResult::from_bool(r == a >> b), - } + Some(f(a, b)) } } } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 89793c8a82ec1..2c2089ab71e10 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -230,116 +230,66 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { mod tests { use qc::{U32, U64}; - use gcc_s; - use quickcheck::TestResult; - use rand; - - quickcheck!{ - fn udivdi3(n: U64, d: U64) -> TestResult { + check! { + fn __udivdi3(f: extern fn(u64, u64) -> u64, n: U64, d: U64) -> Option { let (n, d) = (n.0, d.0); if d == 0 { - TestResult::discard() + None } else { - let q = super::__udivdi3(n, d); - - match gcc_s::udivdi3() { - Some(udivdi3) if rand::random() => { - TestResult::from_bool(q == unsafe { udivdi3(n, d) }) - }, - _ => TestResult::from_bool(q == n / d), - } + Some(f(n, d)) } } - fn umoddi3(n: U64, d: U64) -> TestResult { + fn __umoddi3(f: extern fn(u64, u64) -> u64, n: U64, d: U64) -> Option { let (n, d) = (n.0, d.0); if d == 0 { - TestResult::discard() + None } else { - let r = super::__umoddi3(n, d); - - match gcc_s::umoddi3() { - Some(umoddi3) if rand::random() => { - TestResult::from_bool(r == unsafe { umoddi3(n, d) }) - }, - _ => TestResult::from_bool(r == n % d), - } + Some(f(n, d)) } } - fn udivmoddi4(n: U64, d: U64) -> TestResult { + fn __udivmoddi4(f: extern fn(u64, u64, Option<&mut u64>) -> u64, + n: U64, + d: U64) -> Option<(u64, u64)> { let (n, d) = (n.0, d.0); if d == 0 { - TestResult::discard() + None } else { let mut r = 0; - let q = super::__udivmoddi4(n, d, Some(&mut r)); - - match gcc_s::udivmoddi4() { - Some(udivmoddi4) if rand::random() => { - let mut gcc_s_r = 0; - let gcc_s_q = unsafe { - udivmoddi4(n, d, Some(&mut gcc_s_r)) - }; - - TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) - }, - _ => TestResult::from_bool(q == n / d && r == n % d), - } + let q = f(n, d, Some(&mut r)); + Some((q, r)) } } - fn udivsi3(n: U32, d: U32) -> TestResult { + fn __udivsi3(f: extern fn(u32, u32) -> u32, n: U32, d: U32) -> Option { let (n, d) = (n.0, d.0); if d == 0 { - TestResult::discard() + None } else { - let q = super::__udivsi3(n, d); - - match gcc_s::udivsi3() { - Some(udivsi3) if rand::random() => { - TestResult::from_bool(q == unsafe { udivsi3(n, d) }) - }, - _ => TestResult::from_bool(q == n / d), - } + Some(f(n, d)) } } - fn umodsi3(n: U32, d: U32) -> TestResult { + fn __umodsi3(f: extern fn(u32, u32) -> u32, n: U32, d: U32) -> Option { let (n, d) = (n.0, d.0); if d == 0 { - TestResult::discard() + None } else { - let r = super::__umodsi3(n, d); - - match gcc_s::umodsi3() { - Some(umodsi3) if rand::random() => { - TestResult::from_bool(r == unsafe { umodsi3(n, d) }) - }, - _ => TestResult::from_bool(r == n % d), - } + Some(f(n, d)) } } - fn udivmodsi4(n: U32, d: U32) -> TestResult { + fn __udivmodsi4(f: extern fn(u32, u32, Option<&mut u32>) -> u32, + n: U32, + d: U32) -> Option<(u32, u32)> { let (n, d) = (n.0, d.0); if d == 0 { - TestResult::discard() + None } else { let mut r = 0; - let q = super::__udivmodsi4(n, d, Some(&mut r)); - - match gcc_s::udivmodsi4() { - Some(udivmodsi4) if rand::random() => { - let mut gcc_s_r = 0; - let gcc_s_q = unsafe { - udivmodsi4(n, d, Some(&mut gcc_s_r)) - }; - - TestResult::from_bool(q == gcc_s_q && r == gcc_s_r) - }, - _ => TestResult::from_bool(q == n / d && r == n % d), - } + let q = f(n, d, Some(&mut r)); + Some((q, r)) } } } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 7f2d39180ff31..bb51e4050c01e 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -20,12 +20,19 @@ extern crate core; #[cfg(test)] extern crate gcc_s; +#[cfg(test)] +extern crate compiler_rt; + #[cfg(test)] extern crate rand; #[cfg(feature = "weak")] extern crate rlibc; +#[cfg(test)] +#[macro_use] +mod qc; + pub mod int; pub mod float; @@ -34,7 +41,3 @@ pub mod arm; #[cfg(target_arch = "x86_64")] pub mod x86_64; - -#[cfg(test)] -mod qc; - diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs index 8f102c01a44e6..1450a4ec8b383 100644 --- a/library/compiler-builtins/src/qc.rs +++ b/library/compiler-builtins/src/qc.rs @@ -142,3 +142,124 @@ macro_rules! arbitrary_large { arbitrary_large!(I64: i64); arbitrary_large!(U64: u64); + +// Convenience macro to test intrinsics against their reference implementations. +// +// Each intrinsic is tested against both the `gcc_s` library as well as +// `compiler-rt`. These libraries are defined in the `gcc_s` crate as well as +// the `compiler-rt` crate in this repository. Both load a dynamic library and +// lookup symbols through that dynamic library to ensure that we're using the +// right intrinsic. +// +// This macro hopefully allows you to define a bare minimum of how to test an +// intrinsic without worrying about these implementation details. A sample +// invocation looks like: +// +// +// check! { +// // First argument is the function we're testing (either from this lib +// // or a dynamically loaded one. Further arguments are all generated by +// // quickcheck. +// fn __my_intrinsic(f: extern fn(i32) -> i32, +// a: I32) +// -> Option<(i32, i64)> { +// +// // Discard tests by returning Some +// if a.0 == 0 { +// return None +// } +// +// // Return the result via `Some` if the test can run +// let mut other_result = 0; +// let result = f(a.0, &mut other_result); +// Some((result, other_result)) +// } +// } +// +// If anything returns `None` then the test is discarded, otherwise the two +// results are compared for equality and the test fails if this equality check +// fails. +macro_rules! check { + ($( + fn $name:ident($f:ident: extern fn($($farg:ty),*) -> $fret:ty, + $($arg:ident: $t:ty),*) + -> Option<$ret:ty> + { + $($code:tt)* + } + )*) => ( + $( + fn $name($f: extern fn($($farg),*) -> $fret, + $($arg: $t),*) -> Option<$ret> { + $($code)* + } + )* + + mod _compiler_rt { + use qc::*; + use std::mem; + use quickcheck::TestResult; + + $( + #[test] + fn $name() { + fn my_check($($arg:$t),*) -> TestResult { + let my_answer = super::$name(super::super::$name, + $($arg),*); + let compiler_rt_fn = ::compiler_rt::get(stringify!($name)); + unsafe { + let compiler_rt_answer = + super::$name(mem::transmute(compiler_rt_fn), + $($arg),*); + match (my_answer, compiler_rt_answer) { + (None, _) | (_, None) => TestResult::discard(), + (Some(a), Some(b)) => { + TestResult::from_bool(a == b) + } + } + } + } + + ::quickcheck::quickcheck(my_check as fn($($t),*) -> TestResult) + } + )* + } + + mod _gcc_s { + use qc::*; + use std::mem; + use quickcheck::TestResult; + + $( + #[test] + fn $name() { + fn my_check($($arg:$t),*) -> TestResult { + let my_answer = super::$name(super::super::$name, + $($arg),*); + let gcc_s_fn = ::gcc_s::get(stringify!($name)).unwrap(); + unsafe { + let gcc_s_answer = + super::$name(mem::transmute(gcc_s_fn), + $($arg),*); + match (my_answer, gcc_s_answer) { + (None, _) | (_, None) => TestResult::discard(), + (Some(a), Some(b)) => { + TestResult::from_bool(a == b) + } + } + } + } + + // If it's not in libgcc, or we couldn't find libgcc, then + // just ignore this. We should have tests through + // compiler-rt in any case + if ::gcc_s::get(stringify!($name)).is_none() { + return + } + + ::quickcheck::quickcheck(my_check as fn($($t),*) -> TestResult) + } + )* + } + ) +} diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 8bc33096dfcd4..e38147aaff8f5 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -1,3 +1,5 @@ +#![allow(unused_imports)] + use core::intrinsics; // NOTE These functions are implemented using assembly because they using a custom From df0eb9981eba7484e473696c34fc0e89e43c780a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 29 Sep 2016 06:43:25 -0500 Subject: [PATCH 0157/4206] appveyor: stop gisting the disassembly it's flaky in its current form and Travis is not producing gist either. --- library/compiler-builtins/appveyor.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 0e64977c1752a..52afc97ef5e5e 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -8,7 +8,6 @@ install: - curl -sSf -o rustup-init.exe https://win.rustup.rs - rustup-init.exe --default-host %TARGET% --default-toolchain nightly -y - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - - gem install gist - rustc -Vv - cargo -V @@ -20,11 +19,6 @@ test_script: - cargo test - cargo test --release -on_success: - - cmd: | - CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" - dumpbin /disasm target/release/librustc_builtins.rlib | gist -d "'%TARGET%/rustc-builtins.rlib' from commit '%APPVEYOR_REPO_COMMIT%' on branch '%APPVEYOR_REPO_branch%'" - branches: only: - auto From cb9b1f82e32ca15e77f22b7132ab57f31138e935 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 26 Sep 2016 15:55:11 -0500 Subject: [PATCH 0158/4206] add an opt-in cargo feature to build intrinsics from compiler-rt source closes #63 cc #66 --- library/compiler-builtins/Cargo.toml | 6 + library/compiler-builtins/build.rs | 426 +++++++++++++++++- library/compiler-builtins/src/arm.rs | 2 + .../compiler-builtins/src/bin/intrinsics.rs | 399 ++++++++++++++++ library/compiler-builtins/src/float/add.rs | 3 +- library/compiler-builtins/src/int/mul.rs | 2 + library/compiler-builtins/src/int/sdiv.rs | 17 +- library/compiler-builtins/src/int/shift.rs | 5 + library/compiler-builtins/src/int/udiv.rs | 19 +- library/compiler-builtins/src/lib.rs | 3 + library/compiler-builtins/src/x86_64.rs | 1 - .../compiler-builtins/thumbv6m-none-eabi.json | 2 + .../thumbv7em-none-eabi.json | 2 + .../thumbv7em-none-eabihf.json | 2 + .../compiler-builtins/thumbv7m-none-eabi.json | 2 + 15 files changed, 883 insertions(+), 8 deletions(-) create mode 100644 library/compiler-builtins/src/bin/intrinsics.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 6e75a116bbf0a..93f7d19701252 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -4,6 +4,10 @@ build = "build.rs" name = "rustc_builtins" version = "0.1.0" +[build-dependencies] +gcc = "0.3.35" +rustc-cfg = "0.1.2" + [dependencies] [dependencies.rlibc] @@ -17,6 +21,8 @@ gcc_s = { path = "gcc_s" } compiler-rt = { path = "compiler-rt" } [features] +# Build the missing intrinsics from compiler-rt C source code +c = [] weak = ["rlibc/weak"] [workspace] diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 3ef6c2895542e..2333bb1cd003e 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1,8 +1,430 @@ +extern crate gcc; +extern crate rustc_cfg; + +use std::collections::BTreeMap; use std::env; +use std::path::Path; + +use rustc_cfg::Cfg; + +struct Sources { + // SYMBOL -> PATH TO SOURCE + map: BTreeMap<&'static str, &'static str>, +} + +impl Sources { + fn new() -> Sources { + Sources { map: BTreeMap::new() } + } + + fn extend(&mut self, sources: &[&'static str]) { + // NOTE Some intrinsics have both a generic implementation (e.g. + // `floatdidf.c`) and an arch optimized implementation + // (`x86_64/floatdidf.c`). In those cases, we keep the arch optimized + // implementation and discard the generic implementation. If we don't + // and keep both implementations, the linker will yell at us about + // duplicate symbols! + for &src in sources { + let symbol = Path::new(src).file_stem().unwrap().to_str().unwrap(); + if src.contains("/") { + // Arch-optimized implementation (preferred) + self.map.insert(symbol, src); + } else { + // Generic implementation + if !self.map.contains_key(symbol) { + self.map.insert(symbol, src); + } + } + } + } + + fn remove(&mut self, symbols: &[&str]) { + for symbol in symbols { + self.map.remove(*symbol).unwrap(); + } + } +} fn main() { - if env::var("TARGET").unwrap().ends_with("gnueabihf") { + println!("cargo:rerun-if-changed=build.rs"); + + let target = env::var("TARGET").unwrap(); + let Cfg { ref target_arch, ref target_os, ref target_env, ref target_vendor, .. } = + Cfg::new(&target).unwrap(); + // 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.split('-').collect::>(); + let target_vendor = target_vendor.as_ref().unwrap(); + + // Build missing intrinsics from compiler-rt C source code + if env::var_os("CARGO_FEATURE_C").is_some() { + let cfg = &mut gcc::Config::new(); + + if target_env == "msvc" { + // Don't pull in extra libraries on MSVC + cfg.flag("/Zl"); + + // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP + cfg.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("-fomit-frame-pointer"); + cfg.flag("-ffreestanding"); + } + + // NOTE Most of the ARM intrinsics are written in assembly. Tell gcc which arch we are going to + // target to make sure that the assembly implementations really work for the target. If the + // implementation is not valid for the arch, then gcc will error when compiling it. + if llvm_target[0].starts_with("thumb") { + cfg.flag("-mthumb"); + + if llvm_target.last() == Some(&"eabihf") { + cfg.flag("-mfloat-abi=hard"); + } + } + + if llvm_target[0] == "thumbv6m" { + cfg.flag("-march=armv6-m"); + } + + if llvm_target[0] == "thumbv7m" { + cfg.flag("-march=armv7-m"); + } + + if llvm_target[0] == "thumbv7em" { + cfg.flag("-march=armv7e-m"); + } + + let mut sources = Sources::new(); + sources.extend(&["absvdi2.c", + "absvsi2.c", + "addvdi3.c", + "addvsi3.c", + "apple_versioning.c", + "clear_cache.c", + "clzdi2.c", + "clzsi2.c", + "cmpdi2.c", + "comparedf2.c", + "comparesf2.c", + "ctzdi2.c", + "ctzsi2.c", + "divdc3.c", + "divdf3.c", + "divsc3.c", + "divsf3.c", + "divxc3.c", + "extendsfdf2.c", + "extendhfsf2.c", + "ffsdi2.c", + "fixdfdi.c", + "fixdfsi.c", + "fixsfdi.c", + "fixsfsi.c", + "fixunsdfdi.c", + "fixunsdfsi.c", + "fixunssfdi.c", + "fixunssfsi.c", + "fixunsxfdi.c", + "fixunsxfsi.c", + "fixxfdi.c", + "floatdidf.c", + "floatdisf.c", + "floatdixf.c", + "floatsidf.c", + "floatsisf.c", + "floatundidf.c", + "floatundisf.c", + "floatundixf.c", + "floatunsidf.c", + "floatunsisf.c", + "int_util.c", + "muldc3.c", + "muldf3.c", + "muloti4.c", + "mulsc3.c", + "mulsf3.c", + "mulvdi3.c", + "mulvsi3.c", + "mulxc3.c", + "negdf2.c", + "negdi2.c", + "negsf2.c", + "negvdi2.c", + "negvsi2.c", + "paritydi2.c", + "paritysi2.c", + "popcountdi2.c", + "popcountsi2.c", + "powidf2.c", + "powisf2.c", + "powixf2.c", + "subdf3.c", + "subsf3.c", + "subvdi3.c", + "subvsi3.c", + "truncdfhf2.c", + "truncdfsf2.c", + "truncsfhf2.c", + "ucmpdi2.c"]); + + if target_os != "ios" { + sources.extend(&["absvti2.c", + "addtf3.c", + "addvti3.c", + "ashlti3.c", + "ashrti3.c", + "clzti2.c", + "cmpti2.c", + "ctzti2.c", + "divtf3.c", + "divti3.c", + "ffsti2.c", + "fixdfti.c", + "fixsfti.c", + "fixunsdfti.c", + "fixunssfti.c", + "fixunsxfti.c", + "fixxfti.c", + "floattidf.c", + "floattisf.c", + "floattixf.c", + "floatuntidf.c", + "floatuntisf.c", + "floatuntixf.c", + "lshrti3.c", + "modti3.c", + "multf3.c", + "multi3.c", + "mulvti3.c", + "negti2.c", + "negvti2.c", + "parityti2.c", + "popcountti2.c", + "powitf2.c", + "subtf3.c", + "subvti3.c", + "trampoline_setup.c", + "ucmpti2.c", + "udivmodti4.c", + "udivti3.c", + "umodti3.c"]); + } + + if target_vendor == "apple" { + sources.extend(&["atomic_flag_clear.c", + "atomic_flag_clear_explicit.c", + "atomic_flag_test_and_set.c", + "atomic_flag_test_and_set_explicit.c", + "atomic_signal_fence.c", + "atomic_thread_fence.c"]); + } + + if target_os != "windows" && target_os != "none" { + sources.extend(&["emutls.c"]); + } + + if target_env == "msvc" { + if target_arch == "x86_64" { + sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]); + } + } else { + if target_os != "freebsd" { + sources.extend(&["gcc_personality_v0.c"]); + } + + if target_arch == "x86_64" { + sources.extend(&["x86_64/chkstk.S", + "x86_64/chkstk2.S", + "x86_64/floatdidf.c", + "x86_64/floatdisf.c", + "x86_64/floatdixf.c", + "x86_64/floatundidf.S", + "x86_64/floatundisf.S", + "x86_64/floatundixf.S"]); + } + + if target_arch == "x86" { + sources.extend(&["i386/ashldi3.S", + "i386/ashrdi3.S", + "i386/chkstk.S", + "i386/chkstk2.S", + "i386/divdi3.S", + "i386/floatdidf.S", + "i386/floatdisf.S", + "i386/floatdixf.S", + "i386/floatundidf.S", + "i386/floatundisf.S", + "i386/floatundixf.S", + "i386/lshrdi3.S", + "i386/moddi3.S", + "i386/muldi3.S", + "i386/udivdi3.S", + "i386/umoddi3.S"]); + } + } + + if target_arch == "arm" && target_os != "ios" { + sources.extend(&["arm/aeabi_cdcmp.S", + "arm/aeabi_cdcmpeq_check_nan.c", + "arm/aeabi_cfcmp.S", + "arm/aeabi_cfcmpeq_check_nan.c", + "arm/aeabi_dcmp.S", + "arm/aeabi_div0.c", + "arm/aeabi_drsub.c", + "arm/aeabi_fcmp.S", + "arm/aeabi_frsub.c", + "arm/bswapdi2.S", + "arm/bswapsi2.S", + "arm/clzdi2.S", + "arm/clzsi2.S", + "arm/comparesf2.S", + "arm/divmodsi4.S", + "arm/divsi3.S", + "arm/modsi3.S", + "arm/switch16.S", + "arm/switch32.S", + "arm/switch8.S", + "arm/switchu8.S", + "arm/sync_synchronize.S", + "arm/udivmodsi4.S", + "arm/udivsi3.S", + "arm/umodsi3.S"]); + } + + if llvm_target[0] == "armv7" { + sources.extend(&["arm/sync_fetch_and_add_4.S", + "arm/sync_fetch_and_add_8.S", + "arm/sync_fetch_and_and_4.S", + "arm/sync_fetch_and_and_8.S", + "arm/sync_fetch_and_max_4.S", + "arm/sync_fetch_and_max_8.S", + "arm/sync_fetch_and_min_4.S", + "arm/sync_fetch_and_min_8.S", + "arm/sync_fetch_and_nand_4.S", + "arm/sync_fetch_and_nand_8.S", + "arm/sync_fetch_and_or_4.S", + "arm/sync_fetch_and_or_8.S", + "arm/sync_fetch_and_sub_4.S", + "arm/sync_fetch_and_sub_8.S", + "arm/sync_fetch_and_umax_4.S", + "arm/sync_fetch_and_umax_8.S", + "arm/sync_fetch_and_umin_4.S", + "arm/sync_fetch_and_umin_8.S", + "arm/sync_fetch_and_xor_4.S", + "arm/sync_fetch_and_xor_8.S"]); + } + + if llvm_target.last().unwrap().ends_with("eabihf") { + if !llvm_target[0].starts_with("thumbv7em") { + sources.extend(&["arm/adddf3vfp.S", + "arm/addsf3vfp.S", + "arm/divdf3vfp.S", + "arm/divsf3vfp.S", + "arm/eqdf2vfp.S", + "arm/eqsf2vfp.S", + "arm/extendsfdf2vfp.S", + "arm/fixdfsivfp.S", + "arm/fixsfsivfp.S", + "arm/fixunsdfsivfp.S", + "arm/fixunssfsivfp.S", + "arm/floatsidfvfp.S", + "arm/floatsisfvfp.S", + "arm/floatunssidfvfp.S", + "arm/floatunssisfvfp.S", + "arm/gedf2vfp.S", + "arm/gesf2vfp.S", + "arm/gtdf2vfp.S", + "arm/gtsf2vfp.S", + "arm/ledf2vfp.S", + "arm/lesf2vfp.S", + "arm/ltdf2vfp.S", + "arm/ltsf2vfp.S", + "arm/muldf3vfp.S", + "arm/mulsf3vfp.S", + "arm/nedf2vfp.S", + "arm/nesf2vfp.S", + "arm/restore_vfp_d8_d15_regs.S", + "arm/save_vfp_d8_d15_regs.S", + "arm/subdf3vfp.S", + "arm/subsf3vfp.S"]); + } + + sources.extend(&["arm/negdf2vfp.S", "arm/negsf2vfp.S"]); + + } + + if target_arch == "aarch64" { + sources.extend(&["comparetf2.c", + "extenddftf2.c", + "extendsftf2.c", + "fixtfdi.c", + "fixtfsi.c", + "fixtfti.c", + "fixunstfdi.c", + "fixunstfsi.c", + "fixunstfti.c", + "floatditf.c", + "floatsitf.c", + "floatunditf.c", + "floatunsitf.c", + "multc3.c", + "trunctfdf2.c", + "trunctfsf2.c"]); + } + + // Remove the assembly implementations that won't compile for the target + if llvm_target[0] == "thumbv6m" { + sources.remove(&["aeabi_cdcmp", + "aeabi_cfcmp", + "aeabi_dcmp", + "aeabi_fcmp", + "clzdi2", + "clzsi2", + "comparesf2", + "divmodsi4", + "divsi3", + "modsi3", + "switch16", + "switch32", + "switch8", + "switchu8", + "udivmodsi4", + "udivsi3", + "umodsi3"]); + + // But use some generic implementations where possible + sources.extend(&["clzdi2.c", "clzsi2.c"]) + } + + if llvm_target[0] == "thumbv7m" || llvm_target[0] == "thumbv7em" { + sources.remove(&["aeabi_cdcmp", "aeabi_cfcmp"]); + } + + for src in sources.map.values() { + cfg.file(Path::new("compiler-rt/lib/builtins").join(src)); + } + + cfg.compile("libcompiler-rt.a"); + } + + // To filter away some flaky test (see src/float/add.rs for details) + if llvm_target.last() == Some(&"gnueabihf") { println!("cargo:rustc-cfg=gnueabihf") } - println!("cargo:rerun-if-changed=build.rs"); + + // To compile intrinsics.rs for thumb targets, where there is no libc + if llvm_target[0].starts_with("thumb") { + println!("cargo:rustc-cfg=thumb") + } + + // compiler-rt `cfg`s away some intrinsics for thumbv6m because that target doesn't have full + // THUMBv2 support. We have to cfg our code accordingly. + if llvm_target[0] == "thumbv6m" { + println!("cargo:rustc-cfg=thumbv6m") + } } diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 4fe243c68d2b0..b74458f11a244 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -68,6 +68,7 @@ pub extern "C" fn __aeabi_fadd(a: f32, b: f32) -> f32 { ::float::add::__addsf3(a, b) } +#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] #[cfg_attr(not(test), no_mangle)] pub extern "C" fn __aeabi_idiv(a: i32, b: i32) -> i32 { ::int::sdiv::__divsi3(a, b) @@ -93,6 +94,7 @@ pub extern "C" fn __aeabi_lmul(a: u64, b: u64) -> u64 { ::int::mul::__muldi3(a, b) } +#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] #[cfg_attr(not(test), no_mangle)] pub extern "C" fn __aeabi_uidiv(a: u32, b: u32) -> u32 { ::int::udiv::__udivsi3(a, b) diff --git a/library/compiler-builtins/src/bin/intrinsics.rs b/library/compiler-builtins/src/bin/intrinsics.rs new file mode 100644 index 0000000000000..5e234855cf1be --- /dev/null +++ b/library/compiler-builtins/src/bin/intrinsics.rs @@ -0,0 +1,399 @@ +// By compiling this file we check that all the intrinsics we care about continue to be provided by +// the `rustc_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(unused_features)] +#![deny(dead_code)] +#![feature(core_float)] +#![feature(lang_items)] +#![feature(libc)] +#![feature(start)] +#![no_std] +#![cfg_attr(thumb, no_main)] + +#[cfg(not(thumb))] +extern crate libc; +extern crate rustc_builtins; + +// NOTE cfg(not(thumbv6m)) means that the operation is not supported on ARMv6-M at all. Not even +// compiler-rt provides a C/assembly implementation. + +// Every function in this module maps will be lowered to an intrinsic by LLVM, if the platform +// doesn't have native support for the operation used in the function. ARM has a naming convention +// convention for its intrinsics that's different from other architectures; that's why some function +// have an additional comment: the function name is the ARM name for the intrinsic and the comment +// in the non-ARM name for the intrinsic. +#[cfg(feature = "c")] +mod intrinsics { + use core::num::Float; + + // trunccdfsf2 + pub fn aeabi_d2f(x: f64) -> f32 { + x as f32 + } + + // fixdfsi + pub fn aeabi_d2i(x: f64) -> i32 { + x as i32 + } + + // fixdfdi + #[cfg(not(thumbv6m))] + pub fn aeabi_d2l(x: f64) -> i64 { + x as i64 + } + + #[cfg(thumbv6m)] + pub fn aeabi_d2l(_: f64) -> i64 { + 0 + } + + // fixunsdfsi + pub fn aeabi_d2uiz(x: f64) -> u32 { + x as u32 + } + + // fixunsdfdi + #[cfg(not(thumbv6m))] + pub fn aeabi_d2ulz(x: f64) -> u64 { + x as u64 + } + + #[cfg(thumbv6m)] + pub fn aeabi_d2ulz(_: f64) -> u64 { + 0 + } + + // adddf3 + pub fn aeabi_dadd(a: f64, b: f64) -> f64 { + a + b + } + + // eqdf2 + #[cfg(not(thumbv6m))] + pub fn aeabi_dcmpeq(a: f64, b: f64) -> bool { + a == b + } + + #[cfg(thumbv6m)] + pub fn aeabi_dcmpeq(_: f64, _: f64) -> bool { + true + } + + // gtdf2 + #[cfg(not(thumbv6m))] + pub fn aeabi_dcmpgt(a: f64, b: f64) -> bool { + a > b + } + + #[cfg(thumbv6m)] + pub fn aeabi_dcmpgt(_: f64, _: f64) -> bool { + true + } + + // ltdf2 + #[cfg(not(thumbv6m))] + pub fn aeabi_dcmplt(a: f64, b: f64) -> bool { + a < b + } + + #[cfg(thumbv6m)] + pub fn aeabi_dcmplt(_: f64, _: f64) -> bool { + true + } + + // divdf3 + pub fn aeabi_ddiv(a: f64, b: f64) -> f64 { + a / b + } + + // muldf3 + pub fn aeabi_dmul(a: f64, b: f64) -> f64 { + a * b + } + + // subdf3 + pub fn aeabi_dsub(a: f64, b: f64) -> f64 { + a - b + } + + // extendsfdf2 + pub fn aeabi_f2d(x: f32) -> f64 { + x as f64 + } + + // fixsfsi + pub fn aeabi_f2iz(x: f32) -> i32 { + x as i32 + } + + // fixsfdi + #[cfg(not(thumbv6m))] + pub fn aeabi_f2lz(x: f32) -> i64 { + x as i64 + } + + #[cfg(thumbv6m)] + pub fn aeabi_f2lz(_: f32) -> i64 { + 0 + } + + // fixunssfsi + pub fn aeabi_f2uiz(x: f32) -> u32 { + x as u32 + } + + // fixunssfdi + #[cfg(not(thumbv6m))] + pub fn aeabi_f2ulz(x: f32) -> u64 { + x as u64 + } + + #[cfg(thumbv6m)] + pub fn aeabi_f2ulz(_: f32) -> u64 { + 0 + } + + // addsf3 + pub fn aeabi_fadd(a: f32, b: f32) -> f32 { + a + b + } + + // eqsf2 + #[cfg(not(thumbv6m))] + pub fn aeabi_fcmpeq(a: f32, b: f32) -> bool { + a == b + } + + #[cfg(thumbv6m)] + pub fn aeabi_fcmpeq(_: f32, _: f32) -> bool { + true + } + + // gtsf2 + #[cfg(not(thumbv6m))] + pub fn aeabi_fcmpgt(a: f32, b: f32) -> bool { + a > b + } + + #[cfg(thumbv6m)] + pub fn aeabi_fcmpgt(_: f32, _: f32) -> bool { + true + } + + // ltsf2 + #[cfg(not(thumbv6m))] + pub fn aeabi_fcmplt(a: f32, b: f32) -> bool { + a < b + } + + #[cfg(thumbv6m)] + pub fn aeabi_fcmplt(_: f32, _: f32) -> bool { + true + } + + // divsf3 + pub fn aeabi_fdiv(a: f32, b: f32) -> f32 { + a / b + } + + // mulsf3 + pub fn aeabi_fmul(a: f32, b: f32) -> f32 { + a * b + } + + // subsf3 + pub fn aeabi_fsub(a: f32, b: f32) -> f32 { + a - b + } + + // floatsidf + pub fn aeabi_i2d(x: i32) -> f64 { + x as f64 + } + + // floatsisf + pub fn aeabi_i2f(x: i32) -> f32 { + x as f32 + } + + pub fn aeabi_idiv(a: i32, b: i32) -> i32 { + a.wrapping_div(b) + } + + pub fn aeabi_idivmod(a: i32, b: i32) -> i32 { + a % b + } + + // floatdidf + pub fn aeabi_l2d(x: i64) -> f64 { + x as f64 + } + + // floatdisf + pub fn aeabi_l2f(x: i64) -> f32 { + x as f32 + } + + // divdi3 + pub fn aeabi_ldivmod(a: i64, b: i64) -> i64 { + a / b + } + + // muldi3 + pub fn aeabi_lmul(a: i64, b: i64) -> i64 { + a.wrapping_mul(b) + } + + // floatunsidf + pub fn aeabi_ui2d(x: u32) -> f64 { + x as f64 + } + + // floatunsisf + pub fn aeabi_ui2f(x: u32) -> f32 { + x as f32 + } + + pub fn aeabi_uidiv(a: u32, b: u32) -> u32 { + a / b + } + + pub fn aeabi_uidivmod(a: u32, b: u32) -> u32 { + a % b + } + + // floatundidf + pub fn aeabi_ul2d(x: u64) -> f64 { + x as f64 + } + + // floatundisf + pub fn aeabi_ul2f(x: u64) -> f32 { + x as f32 + } + + // udivdi3 + pub fn aeabi_uldivmod(a: u64, b: u64) -> u64 { + a * b + } + + pub fn moddi3(a: i64, b: i64) -> i64 { + a % b + } + + pub fn mulodi4(a: i64, b: i64) -> i64 { + a * b + } + + pub fn powidf2(a: f64, b: i32) -> f64 { + a.powi(b) + } + + pub fn powisf2(a: f32, b: i32) -> f32 { + a.powi(b) + } + + pub fn umoddi3(a: u64, b: u64) -> u64 { + a % b + } +} + +#[cfg(feature = "c")] +fn run() { + use intrinsics::*; + + aeabi_d2f(2.); + aeabi_d2i(2.); + aeabi_d2l(2.); + aeabi_d2uiz(2.); + aeabi_d2ulz(2.); + aeabi_dadd(2., 3.); + aeabi_dcmpeq(2., 3.); + aeabi_dcmpgt(2., 3.); + aeabi_dcmplt(2., 3.); + aeabi_ddiv(2., 3.); + aeabi_dmul(2., 3.); + aeabi_dsub(2., 3.); + aeabi_f2d(2.); + aeabi_f2iz(2.); + aeabi_f2lz(2.); + aeabi_f2uiz(2.); + aeabi_f2ulz(2.); + aeabi_fadd(2., 3.); + aeabi_fcmpeq(2., 3.); + aeabi_fcmpgt(2., 3.); + aeabi_fcmplt(2., 3.); + aeabi_fdiv(2., 3.); + aeabi_fmul(2., 3.); + aeabi_fsub(2., 3.); + aeabi_i2d(2); + aeabi_i2f(2); + aeabi_idiv(2, 3); + aeabi_idivmod(2, 3); + aeabi_l2d(2); + aeabi_l2f(2); + aeabi_ldivmod(2, 3); + aeabi_lmul(2, 3); + aeabi_ui2d(2); + aeabi_ui2f(2); + aeabi_uidiv(2, 3); + aeabi_uidivmod(2, 3); + aeabi_ul2d(2); + aeabi_ul2f(2); + aeabi_uldivmod(2, 3); + moddi3(2, 3); + mulodi4(2, 3); + powidf2(2., 3); + powisf2(2., 3); + umoddi3(2, 3); +} + +#[cfg(all(feature = "c", not(thumb)))] +#[start] +fn main(_: isize, _: *const *const u8) -> isize { + run(); + + 0 +} + +#[cfg(all(not(feature = "c"), not(thumb)))] +#[start] +fn main(_: isize, _: *const *const u8) -> isize { + 0 +} + +#[cfg(all(feature = "c", thumb))] +#[no_mangle] +pub fn _start() -> ! { + run(); + loop {} +} + +#[cfg(all(not(feature = "c"), thumb))] +#[no_mangle] +pub fn _start() -> ! { + loop {} +} + +// ARM targets need these symbols +#[no_mangle] +pub fn __aeabi_unwind_cpp_pr0() {} + +#[no_mangle] +pub fn __aeabi_unwind_cpp_pr1() {} + +// Avoid "undefined reference to `_Unwind_Resume`" errors +#[allow(non_snake_case)] +#[no_mangle] +pub fn _Unwind_Resume() {} + +// Lang items +#[cfg(not(test))] +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[cfg(not(test))] +#[lang = "panic_fmt"] +extern "C" fn panic_fmt() {} diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 1e7a651c96cee..7707850217cba 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -286,8 +286,7 @@ mod tests { #[test] fn test_double_different_nan() { let a = f64::from_repr(1); - let b = f64::from_repr( - 0b1111111111110010001000100101010101001000101010000110100011101011); + let b = f64::from_repr(0b1111111111110010001000100101010101001000101010000110100011101011); let x = super::__adddf3(a, b); let y = a + b; assert!(x.eq_repr(y)); diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index ea48ca9c070e3..e04e86ccb80b9 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -66,7 +66,9 @@ macro_rules! mulo { } } +#[cfg(not(all(feature = "c", target_arch = "x86")))] mul!(__muldi3: u64); + mulo!(__mulosi4: i32); mulo!(__mulodi4: i64); diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 7a8e38e5e6d01..37f5dd7df62bb 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -36,18 +36,33 @@ macro_rules! divmod { /// Returns `a / b` and sets `*rem = n % d` #[cfg_attr(not(test), no_mangle)] pub extern "C" fn $intrinsic(a: $ty, b: $ty, rem: &mut $ty) -> $ty { - let r = $div(a, b); + #[cfg(all(feature = "c", any(target_arch = "x86")))] + extern { + fn $div(a: $ty, b: $ty) -> $ty; + } + + let r = unsafe { $div(a, b) }; *rem = a - (r * b); r } } } +#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] div!(__divsi3: i32, u32); + +#[cfg(not(all(feature = "c", target_arch = "x86")))] div!(__divdi3: i64, u64); + +#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] mod_!(__modsi3: i32, u32); + +#[cfg(not(all(feature = "c", target_arch = "x86")))] mod_!(__moddi3: i64, u64); + +#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] divmod!(__divmodsi4, __divsi3: i32); + divmod!(__divmoddi4, __divdi3: i64); #[cfg(test)] diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 4fc23918cbfc6..995f8d609256f 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -54,8 +54,13 @@ macro_rules! lshr { } } +#[cfg(not(all(feature = "c", target_arch = "x86")))] ashl!(__ashldi3: u64); + +#[cfg(not(all(feature = "c", target_arch = "x86")))] ashr!(__ashrdi3: i64); + +#[cfg(not(all(feature = "c", target_arch = "x86")))] lshr!(__lshrdi3: u64); #[cfg(test)] diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 2c2089ab71e10..3de18b4a0ca34 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -2,6 +2,7 @@ use core::mem; use int::{Int, LargeInt}; /// Returns `n / d` +#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] #[cfg_attr(not(test), no_mangle)] pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { // Special cases @@ -52,15 +53,27 @@ pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { } /// Returns `n % d` +#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] #[cfg_attr(not(test), no_mangle)] pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { - n - __udivsi3(n, d) * d + #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios")))] + extern "C" { + fn __udivsi3(n: u32, d: u32) -> u32; + } + + n - unsafe { __udivsi3(n, d) * d } } /// Returns `n / d` and sets `*rem = n % d` +#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] #[cfg_attr(not(test), no_mangle)] pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { - let q = __udivsi3(n, d); + #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios")))] + extern "C" { + fn __udivsi3(n: u32, d: u32) -> u32; + } + + let q = unsafe { __udivsi3(n, d) }; if let Some(rem) = rem { *rem = n - (q * d); } @@ -69,11 +82,13 @@ pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { /// Returns `n / d` #[cfg_attr(not(test), no_mangle)] +#[cfg(not(all(feature = "c", target_arch = "x86")))] pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { __udivmoddi4(n, d, None) } /// Returns `n % d` +#[cfg(not(all(feature = "c", target_arch = "x86")))] #[cfg_attr(not(test), no_mangle)] pub extern "C" fn __umoddi3(a: u64, b: u64) -> u64 { let mut rem = unsafe { mem::uninitialized() }; diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index bb51e4050c01e..acc56c98a69c9 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -10,6 +10,9 @@ // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. +// NOTE cfg(all(feature = "c", ..)) indicate that compiler-rt provides an arch optimized +// implementation of that intrinsic and we'll prefer to use that + #[cfg(test)] #[macro_use] extern crate quickcheck; diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index e38147aaff8f5..072f964dd70c1 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -67,4 +67,3 @@ pub unsafe fn ___chkstk() { ret"); intrinsics::unreachable(); } - diff --git a/library/compiler-builtins/thumbv6m-none-eabi.json b/library/compiler-builtins/thumbv6m-none-eabi.json index 9c92d4e33332c..4b409cff04939 100644 --- a/library/compiler-builtins/thumbv6m-none-eabi.json +++ b/library/compiler-builtins/thumbv6m-none-eabi.json @@ -1,10 +1,12 @@ { "arch": "arm", "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "executables": true, "features": "+strict-align", "llvm-target": "thumbv6m-none-eabi", "max-atomic-width": 0, "os": "none", + "pre-link-args": ["-nostartfiles"], "target-endian": "little", "target-pointer-width": "32" } diff --git a/library/compiler-builtins/thumbv7em-none-eabi.json b/library/compiler-builtins/thumbv7em-none-eabi.json index ce49c83ffdaa3..2ac47c8f829b4 100644 --- a/library/compiler-builtins/thumbv7em-none-eabi.json +++ b/library/compiler-builtins/thumbv7em-none-eabi.json @@ -1,8 +1,10 @@ { "arch": "arm", "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "executables": true, "llvm-target": "thumbv7em-none-eabi", "os": "none", + "pre-link-args": ["-nostartfiles"], "target-endian": "little", "target-pointer-width": "32" } diff --git a/library/compiler-builtins/thumbv7em-none-eabihf.json b/library/compiler-builtins/thumbv7em-none-eabihf.json index bb0b87eb41f60..55ed3fd885d5d 100644 --- a/library/compiler-builtins/thumbv7em-none-eabihf.json +++ b/library/compiler-builtins/thumbv7em-none-eabihf.json @@ -1,9 +1,11 @@ { "arch": "arm", "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "executables": true, "features": "+vfp4", "llvm-target": "thumbv7em-none-eabihf", "os": "none", + "pre-link-args": ["-nostartfiles"], "target-endian": "little", "target-pointer-width": "32" } diff --git a/library/compiler-builtins/thumbv7m-none-eabi.json b/library/compiler-builtins/thumbv7m-none-eabi.json index 313a5e66f71d3..9635efa8d785e 100644 --- a/library/compiler-builtins/thumbv7m-none-eabi.json +++ b/library/compiler-builtins/thumbv7m-none-eabi.json @@ -1,8 +1,10 @@ { "arch": "arm", "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "executables": true, "llvm-target": "thumbv7m-none-eabi", "os": "none", + "pre-link-args": ["-nostartfiles"], "target-endian": "little", "target-pointer-width": "32" } From a57a63fe08fcea954284f11981f38f0bfd553ad9 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 29 Sep 2016 18:50:04 -0500 Subject: [PATCH 0159/4206] adapt to new testing infrastructure --- library/compiler-builtins/.travis.yml | 18 ++---- library/compiler-builtins/build.rs | 2 +- .../ci/docker/thumbv6m-none-eabi/Dockerfile | 8 +++ .../ci/docker/thumbv7em-none-eabi/Dockerfile | 8 +++ .../docker/thumbv7em-none-eabihf/Dockerfile | 8 +++ .../ci/docker/thumbv7m-none-eabi/Dockerfile | 8 +++ library/compiler-builtins/ci/run-docker.sh | 10 +-- library/compiler-builtins/ci/run.sh | 63 +++++++++++++++++++ 8 files changed, 105 insertions(+), 20 deletions(-) create mode 100644 library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile create mode 100644 library/compiler-builtins/ci/run.sh diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 47252a4179418..5b84ae5fd6fea 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -3,7 +3,6 @@ language: rust services: docker sudo: required rust: nightly -cache: cargo matrix: include: @@ -25,18 +24,11 @@ matrix: - env: TARGET=mipsel-unknown-linux-gnu - env: TARGET=powerpc-unknown-linux-gnu - env: TARGET=powerpc64-unknown-linux-gnu - # QEMU crashes even when executing the simplest cross compiled C program: - # `int main() { return 0; }` - - env: TARGET=powerpc64le-unknown-linux-gnu NO_RUN=1 + - env: TARGET=powerpc64le-unknown-linux-gnu - env: TARGET=thumbv6m-none-eabi - install: cargo install xargo --debug -f - script: $HOME/.cargo/bin/xargo build --target $TARGET - env: TARGET=thumbv7em-none-eabi - install: cargo install xargo --debug -f - script: $HOME/.cargo/bin/xargo build --target $TARGET - env: TARGET=thumbv7em-none-eabihf - install: cargo install xargo --debug -f - script: $HOME/.cargo/bin/xargo build --target $TARGET + - env: TARGET=thumbv7m-none-eabi - env: TARGET=x86_64-apple-darwin os: osx env: TARGET=x86_64-unknown-linux-gnu @@ -45,8 +37,10 @@ before_install: - test "$TRAVIS_OS_NAME" = "osx" || docker run --rm --privileged multiarch/qemu-user-static:register install: - - curl https://static.rust-lang.org/rustup.sh | - sh -s -- --add-target=$TARGET --disable-sudo -y --prefix=`rustc --print sysroot` + - if case $TARGET in thumb*) false;; *) true;; esac; then + curl https://static.rust-lang.org/rustup.sh | + sh -s -- --add-target=$TARGET --disable-sudo -y --prefix=`rustc --print sysroot`; + fi script: - cargo generate-lockfile diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 2333bb1cd003e..f58ea5bb64f71 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -406,7 +406,7 @@ fn main() { } for src in sources.map.values() { - cfg.file(Path::new("compiler-rt/lib/builtins").join(src)); + cfg.file(Path::new("compiler-rt/compiler-rt-cdylib/compiler-rt/lib/builtins").join(src)); } cfg.compile("libcompiler-rt.a"); diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile new file mode 100644 index 0000000000000..c6f7209f3a3b0 --- /dev/null +++ b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -0,0 +1,8 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev +ENV AR_thumbv6m_none_eabi=arm-none-eabi-ar \ + CARGO_TARGET_THUMBV6M_NONE_EABI_LINKER=arm-none-eabi-gcc \ + CC_thumbv6m_none_eabi=arm-none-eabi-gcc \ + PATH=$PATH:/rust/bin diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile new file mode 100644 index 0000000000000..016097b2eab7b --- /dev/null +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -0,0 +1,8 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev +ENV AR_thumbv7em_none_eabi=arm-none-eabi-ar \ + CARGO_TARGET_THUMBV7EM_NONE_EABI_LINKER=arm-none-eabi-gcc \ + CC_thumbv7em_none_eabi=arm-none-eabi-gcc \ + PATH=$PATH:/rust/bin diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile new file mode 100644 index 0000000000000..c7188ef588678 --- /dev/null +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -0,0 +1,8 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev +ENV AR_thumbv7em_none_eabihf=arm-none-eabi-ar \ + CARGO_TARGET_THUMBV7EM_NONE_EABIHF_LINKER=arm-none-eabi-gcc \ + CC_thumbv7em_none_eabihf=arm-none-eabi-gcc \ + PATH=$PATH:/rust/bin diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile new file mode 100644 index 0000000000000..542cc92018715 --- /dev/null +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -0,0 +1,8 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev +ENV AR_thumbv7m_none_eabi=arm-none-eabi-ar \ + CARGO_TARGET_THUMBV7M_NONE_EABI_LINKER=arm-none-eabi-gcc \ + CC_thumbv7m_none_eabi=arm-none-eabi-gcc \ + PATH=$PATH:/rust/bin diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 8ef024e822246..69127148546de 100644 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -5,19 +5,15 @@ set -ex run() { echo $1 - CMD="cargo test --target $1" - if [ "$NO_RUN" = "1" ]; then - CMD="$CMD --no-run" - fi - docker build -t libc ci/docker/$1 + docker build -t $1 ci/docker/$1 docker run \ -v `rustc --print sysroot`:/rust:ro \ -v `pwd`:/checkout:ro \ -e CARGO_TARGET_DIR=/tmp/target \ -w /checkout \ --privileged \ - -it libc \ - bash -c "$CMD && $CMD --release" + -it $1 \ + sh ci/run.sh $1 } if [ -z "$1" ]; then diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh new file mode 100644 index 0000000000000..866ddc20e1729 --- /dev/null +++ b/library/compiler-builtins/ci/run.sh @@ -0,0 +1,63 @@ +# Test our implementation +case $1 in + thumb*) + curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ + bash -s -- --at /usr/bin --from japaric/xargo --tag v0.1.10 + xargo build --target $1 + xargo build --target $1 --release + ;; + # QEMU crashes even when executing the simplest cross compiled C program: + # `int main() { return 0; }` + powerpc64le-unknown-linux-gnu) + cargo test --target $1 --no-run + cargo test --target $1 --no-run --release + ;; + *) + cargo test --target $1 + cargo test --target $1 --release + ;; +esac + +# Verify that we haven't drop any intrinsic/symbol +case $1 in + thumb*) + xargo build --features c --target $1 --bin intrinsics + ;; + *) + cargo build --features c --target $1 --bin intrinsics + ;; +esac + +# Look out for duplicated symbols when we include the compiler-rt (C) implementation +PREFIX=$(echo $1 | sed -e 's/unknown-//') +case $1 in + armv7-*) + PREFIX=arm-linux-gnueabihf- + ;; + thumb*) + PREFIX=arm-none-eabi- + ;; + *-unknown-linux-gnu | *-apple-darwin) + PREFIX= + ;; +esac + +case $TRAVIS_OS_NAME in + osx) + NM=gnm + + # NOTE OSx's nm doesn't accept the `--defined-only` or provide an equivalent. + # Use GNU nm instead + brew install binutils + ;; + *) + NM=nm + ;; +esac + +$PREFIX$NM -g --defined-only /tmp/target/${1}/debug/librustc_builtins.rlib | \ + sort | uniq -d | grep 'T __' + +if test $? = 0; then + exit 1 +fi From 148ac030d482f57b4362f54ea01952cd4039008d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 29 Sep 2016 19:20:34 -0500 Subject: [PATCH 0160/4206] ignore duplicated get_pc_thunk symbols --- library/compiler-builtins/ci/run.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 866ddc20e1729..237c50582805e 100644 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -55,8 +55,9 @@ case $TRAVIS_OS_NAME in ;; esac +# NOTE On i586, It's normal that the get_pc_thunk symbol appears several times so ignore it $PREFIX$NM -g --defined-only /tmp/target/${1}/debug/librustc_builtins.rlib | \ - sort | uniq -d | grep 'T __' + sort | uniq -d | grep -v __x86.get_pc_thunk | grep 'T __' if test $? = 0; then exit 1 From 9a9f025347c1a36cc448edae964530ff900198e1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 29 Sep 2016 19:45:59 -0500 Subject: [PATCH 0161/4206] build.rs: print rerun-if-change for all the C/asm sources --- library/compiler-builtins/build.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index f58ea5bb64f71..a05a1a590ad2f 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -406,7 +406,9 @@ fn main() { } for src in sources.map.values() { - cfg.file(Path::new("compiler-rt/compiler-rt-cdylib/compiler-rt/lib/builtins").join(src)); + let src = Path::new("compiler-rt/compiler-rt-cdylib/compiler-rt/lib/builtins").join(src); + cfg.file(&src); + println!("cargo:rerun-if-changed={}", src.display()); } cfg.compile("libcompiler-rt.a"); From eeaaebc9ac12dbbaaec36828be3ce38b625530c5 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 29 Sep 2016 19:47:44 -0500 Subject: [PATCH 0162/4206] only x86-ish targets can use an unprefixed nm --- 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 237c50582805e..c0406e33f2313 100644 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -37,7 +37,7 @@ case $1 in thumb*) PREFIX=arm-none-eabi- ;; - *-unknown-linux-gnu | *-apple-darwin) + *86*-*) PREFIX= ;; esac From fde45da3327835212a51fe38c3de2a45a1db1e1b Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Thu, 29 Sep 2016 20:48:20 -0500 Subject: [PATCH 0163/4206] Add floating point deconstruction helpers --- library/compiler-builtins/src/float/add.rs | 2 +- library/compiler-builtins/src/float/mod.rs | 38 ++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 7707850217cba..a462168b9508f 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -14,7 +14,7 @@ macro_rules! add { let bits = Wrapping(<$ty>::bits() as <$ty as Float>::Int); let significand_bits = Wrapping(<$ty>::significand_bits() as <$ty as Float>::Int); - let exponent_bits = bits - significand_bits - one; + let exponent_bits = Wrapping(<$ty>::exponent_bits() as <$ty as Float>::Int); let max_exponent = (one << exponent_bits.0 as usize) - one; let implicit_bit = one << significand_bits.0 as usize; diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index cee2b73987392..a44faade8e150 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -10,6 +10,9 @@ pub trait Float: Sized + Copy { /// Returns the bitwidth of the float type fn bits() -> u32; + /// Returns the bitwidth of the exponent + fn exponent_bits() -> u32; + /// Returns the bitwidth of the significand fn significand_bits() -> u32; @@ -25,6 +28,15 @@ pub trait Float: Sized + Copy { /// Returns a `Self::Int` transmuted back to `Self` fn from_repr(a: Self::Int) -> Self; + /// Returns the sign bit of `self` + fn sign(self) -> bool; + + /// Returns the exponent portion of `self`, shifted to the right + fn exponent(self) -> Self::Int; + + /// Returns the significand portion of `self` + fn significand(self) -> Self::Int; + /// Returns (normalized exponent, normalized significand) fn normalize(significand: Self::Int) -> (i32, Self::Int); } @@ -34,6 +46,9 @@ impl Float for f32 { fn bits() -> u32 { 32 } + fn exponent_bits() -> u32 { + 8 + } fn significand_bits() -> u32 { 23 } @@ -51,6 +66,16 @@ impl Float for f32 { fn from_repr(a: Self::Int) -> Self { unsafe { mem::transmute(a) } } + fn sign(self) -> bool { + (self.repr() & 1 << Self::bits()) != 0 + } + fn exponent(self) -> Self::Int { + self.repr() >> Self::significand_bits() + & ((1 << Self::exponent_bits()) - 1) + } + fn significand(self) -> Self::Int { + self.repr() & ((1 << Self::significand_bits()) - 1) + } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros() .wrapping_sub((1u32 << Self::significand_bits()).leading_zeros()); @@ -62,6 +87,9 @@ impl Float for f64 { fn bits() -> u32 { 64 } + fn exponent_bits() -> u32 { + 11 + } fn significand_bits() -> u32 { 52 } @@ -79,6 +107,16 @@ impl Float for f64 { fn from_repr(a: Self::Int) -> Self { unsafe { mem::transmute(a) } } + fn sign(self) -> bool { + (self.repr() & 1 << Self::bits()) != 0 + } + fn exponent(self) -> Self::Int { + self.repr() >> Self::significand_bits() + & ((1 << Self::exponent_bits()) - 1) + } + fn significand(self) -> Self::Int { + self.repr() & ((1 << Self::significand_bits()) - 1) + } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros() .wrapping_sub((1u64 << Self::significand_bits()).leading_zeros()); From ca01aa45ff1ed89038df3b6cdbaf8e2d237fa157 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Thu, 29 Sep 2016 20:48:28 -0500 Subject: [PATCH 0164/4206] Cleanup add builtin assignments --- library/compiler-builtins/src/float/add.rs | 42 +++++++++++----------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index a462168b9508f..395f7e853a1f9 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -9,27 +9,27 @@ macro_rules! add { #[allow(unused_parens)] #[cfg_attr(not(test), no_mangle)] pub extern fn $intrinsic(a: $ty, b: $ty) -> $ty { - let one = Wrapping(1 as <$ty as Float>::Int); - let zero = Wrapping(0 as <$ty as Float>::Int); - - let bits = Wrapping(<$ty>::bits() as <$ty as Float>::Int); - let significand_bits = Wrapping(<$ty>::significand_bits() as <$ty as Float>::Int); - let exponent_bits = Wrapping(<$ty>::exponent_bits() as <$ty as Float>::Int); - let max_exponent = (one << exponent_bits.0 as usize) - one; - - let implicit_bit = one << significand_bits.0 as usize; - let significand_mask = implicit_bit - one; - let sign_bit = one << (significand_bits + exponent_bits).0 as usize; - let abs_mask = sign_bit - one; - let exponent_mask = abs_mask ^ significand_mask; - let inf_rep = exponent_mask; - let quiet_bit = implicit_bit >> 1; - let qnan_rep = exponent_mask | quiet_bit; - - let mut a_rep = Wrapping(a.repr()); - let mut b_rep = Wrapping(b.repr()); - let a_abs = a_rep & abs_mask; - let b_abs = b_rep & abs_mask; + let one = Wrapping(1 as <$ty as Float>::Int); + let zero = Wrapping(0 as <$ty as Float>::Int); + + let bits = Wrapping(<$ty>::bits() as <$ty as Float>::Int); + let significand_bits = Wrapping(<$ty>::significand_bits() as <$ty as Float>::Int); + let exponent_bits = Wrapping(<$ty>::exponent_bits() as <$ty as Float>::Int); + let max_exponent = (one << exponent_bits.0 as usize) - one; + + let implicit_bit = one << significand_bits.0 as usize; + let significand_mask = implicit_bit - one; + let sign_bit = one << (significand_bits + exponent_bits).0 as usize; + let abs_mask = sign_bit - one; + let exponent_mask = abs_mask ^ significand_mask; + let inf_rep = exponent_mask; + let quiet_bit = implicit_bit >> 1; + let qnan_rep = exponent_mask | quiet_bit; + + let mut a_rep = Wrapping(a.repr()); + let mut b_rep = Wrapping(b.repr()); + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; // Detect if a or b is zero, infinity, or NaN. if a_abs - one >= inf_rep - one || From 43d85fa5cb25faec4109ad471737966d569bd690 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Thu, 29 Sep 2016 20:48:33 -0500 Subject: [PATCH 0165/4206] Add Quickcheck types for float tests --- library/compiler-builtins/src/float/add.rs | 103 ++------------------- library/compiler-builtins/src/float/mod.rs | 73 +++++++++++---- library/compiler-builtins/src/qc.rs | 55 +++++++++++ 3 files changed, 118 insertions(+), 113 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 395f7e853a1f9..7c9f11a1195aa 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -188,7 +188,7 @@ mod tests { use core::{f32, f64}; use float::Float; - use qc::{U32, U64}; + use qc::{F32, F64}; // NOTE The tests below have special handing for NaN values. // Because NaN != NaN, the floating-point representations must be used @@ -212,107 +212,18 @@ mod tests { } } - // TODO: Add F32/F64 to qc so that they print the right values (at the very least) check! { fn __addsf3(f: extern fn(f32, f32) -> f32, - a: U32, - b: U32) + a: F32, + b: F32) -> Option > { - let (a, b) = (f32::from_repr(a.0), f32::from_repr(b.0)); - Some(FRepr(f(a, b))) + Some(FRepr(f(a.0, b.0))) } fn __adddf3(f: extern fn(f64, f64) -> f64, - a: U64, - b: U64) -> Option > { - let (a, b) = (f64::from_repr(a.0), f64::from_repr(b.0)); - Some(FRepr(f(a, b))) + a: F64, + b: F64) -> Option > { + Some(FRepr(f(a.0, b.0))) } } - - // More tests for special float values - - #[test] - fn test_float_tiny_plus_tiny() { - let tiny = f32::from_repr(1); - let r = super::__addsf3(tiny, tiny); - assert!(r.eq_repr(tiny + tiny)); - } - - #[test] - fn test_double_tiny_plus_tiny() { - let tiny = f64::from_repr(1); - let r = super::__adddf3(tiny, tiny); - assert!(r.eq_repr(tiny + tiny)); - } - - #[test] - fn test_float_small_plus_small() { - let a = f32::from_repr(327); - let b = f32::from_repr(256); - let r = super::__addsf3(a, b); - assert!(r.eq_repr(a + b)); - } - - #[test] - fn test_double_small_plus_small() { - let a = f64::from_repr(327); - let b = f64::from_repr(256); - let r = super::__adddf3(a, b); - assert!(r.eq_repr(a + b)); - } - - #[test] - fn test_float_one_plus_one() { - let r = super::__addsf3(1f32, 1f32); - assert!(r.eq_repr(1f32 + 1f32)); - } - - #[test] - fn test_double_one_plus_one() { - let r = super::__adddf3(1f64, 1f64); - assert!(r.eq_repr(1f64 + 1f64)); - } - - #[test] - fn test_float_different_nan() { - let a = f32::from_repr(1); - let b = f32::from_repr(0b11111111100100010001001010101010); - let x = super::__addsf3(a, b); - let y = a + b; - assert!(x.eq_repr(y)); - } - - #[test] - fn test_double_different_nan() { - let a = f64::from_repr(1); - let b = f64::from_repr(0b1111111111110010001000100101010101001000101010000110100011101011); - let x = super::__adddf3(a, b); - let y = a + b; - assert!(x.eq_repr(y)); - } - - #[test] - fn test_float_nan() { - let r = super::__addsf3(f32::NAN, 1.23); - assert_eq!(r.repr(), f32::NAN.repr()); - } - - #[test] - fn test_double_nan() { - let r = super::__adddf3(f64::NAN, 1.23); - assert_eq!(r.repr(), f64::NAN.repr()); - } - - #[test] - fn test_float_inf() { - let r = super::__addsf3(f32::INFINITY, -123.4); - assert_eq!(r, f32::INFINITY); - } - - #[test] - fn test_double_inf() { - let r = super::__adddf3(f64::INFINITY, -123.4); - assert_eq!(r, f64::INFINITY); - } } diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index a44faade8e150..8aa6328ce0648 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -16,17 +16,14 @@ pub trait Float: Sized + Copy { /// Returns the bitwidth of the significand fn significand_bits() -> u32; - /// Returns `self` transmuted to `Self::Int` - fn repr(self) -> Self::Int; + /// Returns a mask for the sign bit of `self` + fn sign_mask() -> Self::Int; - #[cfg(test)] - /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be - /// represented in multiple different ways. This methods returns `true` if two NaNs are - /// compared. - fn eq_repr(self, rhs: Self) -> bool; + /// Returns a mask for the exponent portion of `self` + fn exponent_mask() -> Self::Int; - /// Returns a `Self::Int` transmuted back to `Self` - fn from_repr(a: Self::Int) -> Self; + /// Returns a mask for the significand portion of `self` + fn significand_mask() -> Self::Int; /// Returns the sign bit of `self` fn sign(self) -> bool; @@ -37,6 +34,21 @@ pub trait Float: Sized + Copy { /// Returns the significand portion of `self` fn significand(self) -> Self::Int; + /// Returns `self` transmuted to `Self::Int` + fn repr(self) -> Self::Int; + + #[cfg(test)] + /// 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 a `Self::Int` transmuted back to `Self` + fn from_repr(a: Self::Int) -> Self; + + /// Constructs a `Self` from its parts + fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self; + /// Returns (normalized exponent, normalized significand) fn normalize(significand: Self::Int) -> (i32, Self::Int); } @@ -52,6 +64,15 @@ impl Float for f32 { fn significand_bits() -> u32 { 23 } + fn sign_mask() -> Self::Int { + 1 << (Self::bits() - 1) + } + fn exponent_mask() -> Self::Int { + ((1 << Self::exponent_bits()) - 1) << Self::significand_bits() + } + fn significand_mask() -> Self::Int { + (1 << Self::significand_bits()) - 1 + } fn repr(self) -> Self::Int { unsafe { mem::transmute(self) } } @@ -66,15 +87,20 @@ impl Float for f32 { fn from_repr(a: Self::Int) -> Self { unsafe { mem::transmute(a) } } + + fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { + Self::from_repr(((sign as Self::Int) << (Self::bits() - 1)) | + exponent & Self::exponent_mask() | + significand & Self::significand_mask()) + } fn sign(self) -> bool { - (self.repr() & 1 << Self::bits()) != 0 + (self.repr() & Self::sign_mask()) != 0 } fn exponent(self) -> Self::Int { - self.repr() >> Self::significand_bits() - & ((1 << Self::exponent_bits()) - 1) + self.repr() >> Self::significand_bits() & Self::exponent_mask() } fn significand(self) -> Self::Int { - self.repr() & ((1 << Self::significand_bits()) - 1) + self.repr() & Self::significand_mask() } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros() @@ -93,6 +119,15 @@ impl Float for f64 { fn significand_bits() -> u32 { 52 } + fn sign_mask() -> Self::Int { + 1 << (Self::bits() - 1) + } + fn exponent_mask() -> Self::Int { + ((1 << Self::exponent_bits()) - 1) << Self::significand_bits() + } + fn significand_mask() -> Self::Int { + (1 << Self::significand_bits()) - 1 + } fn repr(self) -> Self::Int { unsafe { mem::transmute(self) } } @@ -107,15 +142,19 @@ impl Float for f64 { fn from_repr(a: Self::Int) -> Self { unsafe { mem::transmute(a) } } + fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { + Self::from_repr(((sign as Self::Int) << (Self::bits() - 1)) | + exponent & Self::exponent_mask() | + significand & Self::significand_mask()) + } fn sign(self) -> bool { - (self.repr() & 1 << Self::bits()) != 0 + (self.repr() & Self::sign_mask()) != 0 } fn exponent(self) -> Self::Int { - self.repr() >> Self::significand_bits() - & ((1 << Self::exponent_bits()) - 1) + self.repr() >> Self::significand_bits() & Self::exponent_mask() } fn significand(self) -> Self::Int { - self.repr() & ((1 << Self::significand_bits()) - 1) + self.repr() & Self::significand_mask() } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros() diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs index 1450a4ec8b383..9d4fff305f6b5 100644 --- a/library/compiler-builtins/src/qc.rs +++ b/library/compiler-builtins/src/qc.rs @@ -5,10 +5,12 @@ use std::boxed::Box; use std::fmt; +use core::{f32, f64}; use quickcheck::{Arbitrary, Gen}; use int::LargeInt; +use float::Float; // Generates values in the full range of the integer type macro_rules! arbitrary { @@ -71,6 +73,7 @@ macro_rules! arbitrary { arbitrary!(I32: i32); arbitrary!(U32: u32); + // These integers are "too large". If we generate e.g. `u64` values in the full range then there's // only `1 / 2^32` chance of seeing a value smaller than `2^32` (i.e. whose higher "word" (32-bits) // is `0`)! But this is an important group of values to tests because we have special code paths for @@ -143,6 +146,57 @@ macro_rules! arbitrary_large { arbitrary_large!(I64: i64); arbitrary_large!(U64: u64); + +macro_rules! arbitrary_float { + ($TY:ident : $ty:ident) => { + #[derive(Clone, Copy)] + pub struct $TY(pub $ty); + + impl Arbitrary for $TY { + fn arbitrary(g: &mut G) -> $TY + where G: Gen + { + let special = [ + -0.0, 0.0, $ty::NAN, $ty::INFINITY, -$ty::INFINITY + ]; + + if g.gen_weighted_bool(10) { // Random special case + $TY(*g.choose(&special).unwrap()) + } else if g.gen_weighted_bool(10) { // NaN variants + let sign: bool = g.gen(); + let exponent: <$ty as Float>::Int = g.gen(); + let significand: <$ty as Float>::Int = 0; + $TY($ty::from_parts(sign, exponent, significand)) + } else if g.gen() { // Denormalized + let sign: bool = g.gen(); + let exponent: <$ty as Float>::Int = 0; + let significand: <$ty as Float>::Int = g.gen(); + $TY($ty::from_parts(sign, exponent, significand)) + } else { // Random anything + let sign: bool = g.gen(); + let exponent: <$ty as Float>::Int = g.gen(); + let significand: <$ty as Float>::Int = g.gen(); + $TY($ty::from_parts(sign, exponent, significand)) + } + } + + fn shrink(&self) -> Box> { + ::quickcheck::empty_shrinker() + } + } + + impl fmt::Debug for $TY { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } + } + } +} + +arbitrary_float!(F32: f32); +arbitrary_float!(F64: f64); + + // Convenience macro to test intrinsics against their reference implementations. // // Each intrinsic is tested against both the `gcc_s` library as well as @@ -263,3 +317,4 @@ macro_rules! check { } ) } + From 92204dce54b277b9f5c4260ecaf5c0ec4eb7d219 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Sep 2016 17:21:54 -0500 Subject: [PATCH 0166/4206] cache Cargo artifacts notable changes in the docker-based testing infrastructure - the docker containers can now modify $CARGO_HOME, to re-use the outer Cargo registry, and the target directory to re-use build artifacts. - the docker containers are removed when their execution finishes because it's no longer necessary to re-start them to inspect them because all the interesting output is in the outer target directory --- library/compiler-builtins/.travis.yml | 7 ++-- .../aarch64-unknown-linux-gnu/Dockerfile | 1 - .../arm-unknown-linux-gnueabi/Dockerfile | 1 - .../arm-unknown-linux-gnueabihf/Dockerfile | 1 - .../armv7-unknown-linux-gnueabihf/Dockerfile | 1 - .../docker/i586-unknown-linux-gnu/Dockerfile | 1 - .../docker/i686-unknown-linux-gnu/Dockerfile | 1 - .../docker/mips-unknown-linux-gnu/Dockerfile | 1 - .../mipsel-unknown-linux-gnu/Dockerfile | 1 - .../powerpc-unknown-linux-gnu/Dockerfile | 1 - .../powerpc64-unknown-linux-gnu/Dockerfile | 1 - .../powerpc64le-unknown-linux-gnu/Dockerfile | 2 -- .../ci/docker/thumbv6m-none-eabi/Dockerfile | 1 - .../ci/docker/thumbv7em-none-eabi/Dockerfile | 1 - .../docker/thumbv7em-none-eabihf/Dockerfile | 1 - .../ci/docker/thumbv7m-none-eabi/Dockerfile | 1 - .../x86_64-unknown-linux-gnu/Dockerfile | 2 -- library/compiler-builtins/ci/run-docker.sh | 32 +++++++++++++------ library/compiler-builtins/ci/run.sh | 5 ++- 19 files changed, 30 insertions(+), 32 deletions(-) mode change 100644 => 100755 library/compiler-builtins/ci/run.sh diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 5b84ae5fd6fea..31957119f4131 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -1,3 +1,4 @@ +cache: cargo dist: trusty language: rust services: docker @@ -45,14 +46,16 @@ install: script: - cargo generate-lockfile - if [[ $TRAVIS_OS_NAME = "linux" ]]; then - sudo apt-get remove -y qemu-user-static && - sudo apt-get install -y qemu-user-static && sh ci/run-docker.sh $TARGET; else cargo test --target $TARGET && cargo test --target $TARGET --release; fi +after_success: + # Travis can't cache files that are not readable by "others" + - chmod -R a+r /home/travis/.cargo + branches: only: - auto 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 6a68154d1920a..d9a243fa26c52 100644 --- a/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -5,6 +5,5 @@ RUN apt-get install -y --no-install-recommends \ gcc-aarch64-linux-gnu libc6-dev-arm64-cross \ qemu-user-static ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ - PATH=$PATH:/rust/bin \ QEMU_LD_PREFIX=/usr/aarch64-linux-gnu \ RUST_TEST_THREADS=1 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 36efcd73cccb5..cb4d021bb948d 100644 --- a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile @@ -4,7 +4,6 @@ RUN apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-linux-gnueabi libc6-dev-armel-cross qemu-user-static ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER=arm-linux-gnueabi-gcc \ - PATH=$PATH:/rust/bin \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabi \ RUST_TEST_THREADS=1 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 83e7e52e8f27b..985abeceaba70 100644 --- a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile @@ -4,6 +4,5 @@ RUN apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ - PATH=$PATH:/rust/bin \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ RUST_TEST_THREADS=1 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 adc15a5c5c5f3..94cae18ccb96b 100644 --- a/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile @@ -4,6 +4,5 @@ RUN apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ - PATH=$PATH:/rust/bin \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ RUST_TEST_THREADS=1 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 63450ff9e0efc..3254b1a347a5b 100644 --- a/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile @@ -2,4 +2,3 @@ FROM ubuntu:16.04 RUN apt-get update RUN apt-get install -y --no-install-recommends \ gcc-multilib libc6-dev ca-certificates -ENV PATH=$PATH:/rust/bin 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 63450ff9e0efc..3254b1a347a5b 100644 --- a/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile @@ -2,4 +2,3 @@ FROM ubuntu:16.04 RUN apt-get update RUN apt-get install -y --no-install-recommends \ gcc-multilib libc6-dev ca-certificates -ENV PATH=$PATH:/rust/bin 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 328152471f883..e332b540394d9 100644 --- a/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile @@ -7,6 +7,5 @@ RUN apt-get install -y --no-install-recommends \ binfmt-support qemu-user-static qemu-system-mips ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER=mips-linux-gnu-gcc \ - PATH=$PATH:/rust/bin \ QEMU_LD_PREFIX=/usr/mips-linux-gnu \ RUST_TEST_THREADS=1 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 088c45f04a863..28f77be64d7ee 100644 --- a/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile @@ -7,6 +7,5 @@ RUN apt-get install -y --no-install-recommends \ binfmt-support qemu-user-static ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER=mipsel-linux-gnu-gcc \ - PATH=$PATH:/rust/bin \ QEMU_LD_PREFIX=/usr/mipsel-linux-gnu \ RUST_TEST_THREADS=1 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 542afa2f4d91a..8106728b96e16 100644 --- a/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile @@ -7,6 +7,5 @@ RUN apt-get install -y --no-install-recommends \ qemu-system-ppc ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER=powerpc-linux-gnu-gcc \ - PATH=$PATH:/rust/bin \ QEMU_LD_PREFIX=/usr/powerpc-linux-gnu \ RUST_TEST_THREADS=1 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 f4559c7de99f7..3259b4d9244ed 100644 --- a/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile @@ -8,6 +8,5 @@ RUN apt-get install -y --no-install-recommends \ ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER=powerpc64-linux-gnu-gcc \ CC_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-gcc \ - PATH=$PATH:/rust/bin \ QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu \ RUST_TEST_THREADS=1 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 9a777883d248b..bd0a182a88659 100644 --- a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile @@ -7,7 +7,5 @@ RUN apt-get install -y --no-install-recommends \ qemu-system-ppc ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER=powerpc64le-linux-gnu-gcc \ - CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \ - PATH=$PATH:/rust/bin \ QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile index c6f7209f3a3b0..6f4997546bd02 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -5,4 +5,3 @@ RUN apt-get install -y --no-install-recommends \ ENV AR_thumbv6m_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV6M_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv6m_none_eabi=arm-none-eabi-gcc \ - PATH=$PATH:/rust/bin diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile index 016097b2eab7b..5d26c92271781 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -5,4 +5,3 @@ RUN apt-get install -y --no-install-recommends \ ENV AR_thumbv7em_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv7em_none_eabi=arm-none-eabi-gcc \ - PATH=$PATH:/rust/bin diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile index c7188ef588678..f223320c2e324 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -5,4 +5,3 @@ RUN apt-get install -y --no-install-recommends \ ENV AR_thumbv7em_none_eabihf=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_NONE_EABIHF_LINKER=arm-none-eabi-gcc \ CC_thumbv7em_none_eabihf=arm-none-eabi-gcc \ - PATH=$PATH:/rust/bin diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile index 542cc92018715..e0121034c8a1a 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -5,4 +5,3 @@ RUN apt-get install -y --no-install-recommends \ ENV AR_thumbv7m_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7M_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv7m_none_eabi=arm-none-eabi-gcc \ - PATH=$PATH:/rust/bin 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 a5704bb64b4e4..2ca8ee99c7c3a 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 @@ -2,5 +2,3 @@ FROM ubuntu:16.04 RUN apt-get update RUN apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates -ENV PATH=$PATH:/rust/bin - diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 69127148546de..82eacbac0ab04 100644 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -4,16 +4,30 @@ set -ex run() { - echo $1 - docker build -t $1 ci/docker/$1 + local gid=$(id -g) \ + group=$(id -g -n) \ + target=$1 \ + uid=$(id -u) \ + user=$(id -u -n) + + echo $target + docker build -t $target ci/docker/$target docker run \ - -v `rustc --print sysroot`:/rust:ro \ - -v `pwd`:/checkout:ro \ - -e CARGO_TARGET_DIR=/tmp/target \ - -w /checkout \ - --privileged \ - -it $1 \ - sh ci/run.sh $1 + --rm \ + -e CARGO_HOME=/cargo \ + -e CARGO_TARGET_DIR=/target \ + -v $HOME/.cargo:/cargo \ + -v `pwd`/target:/target \ + -v `pwd`:/checkout:ro \ + -v `rustc --print sysroot`:/rust:ro \ + -w /checkout \ + -it $target \ + sh -c " +groupadd -g $gid $group +useradd -m -g $gid -u $uid $user +chown $user /cargo /target +su -c 'PATH=\$PATH:/rust/bin ci/run.sh $target' $user +" } if [ -z "$1" ]; then diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh old mode 100644 new mode 100755 index c0406e33f2313..206b2e9ed3c51 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -44,10 +44,9 @@ esac case $TRAVIS_OS_NAME in osx) - NM=gnm - # NOTE OSx's nm doesn't accept the `--defined-only` or provide an equivalent. # Use GNU nm instead + NM=gnm brew install binutils ;; *) @@ -56,7 +55,7 @@ case $TRAVIS_OS_NAME in esac # NOTE On i586, It's normal that the get_pc_thunk symbol appears several times so ignore it -$PREFIX$NM -g --defined-only /tmp/target/${1}/debug/librustc_builtins.rlib | \ +$PREFIX$NM -g --defined-only /target/${1}/debug/librustc_builtins.rlib | \ sort | uniq -d | grep -v __x86.get_pc_thunk | grep 'T __' if test $? = 0; then From 9e1f8322e5f2d4d81ce3445400154185397c4c38 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Sep 2016 18:09:52 -0500 Subject: [PATCH 0167/4206] do chmod jut before the script phase ends --- library/compiler-builtins/.travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 31957119f4131..4ea6ddc416f99 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -51,8 +51,6 @@ script: cargo test --target $TARGET && cargo test --target $TARGET --release; fi - -after_success: # Travis can't cache files that are not readable by "others" - chmod -R a+r /home/travis/.cargo From f707dda057608d56e1e0c6946fe2baa0fa80c3e9 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Sep 2016 18:25:40 -0500 Subject: [PATCH 0168/4206] /home/travis -> $HOME --- library/compiler-builtins/.travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 4ea6ddc416f99..7b3efe474a00c 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -52,7 +52,7 @@ script: cargo test --target $TARGET --release; fi # Travis can't cache files that are not readable by "others" - - chmod -R a+r /home/travis/.cargo + - chmod -R a+r $HOME/.cargo branches: only: From d44e127053a93218c1555640c9ebc7f415c84727 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Sep 2016 18:37:41 -0500 Subject: [PATCH 0169/4206] use `docker run --user` instead of manually creating a user --- library/compiler-builtins/ci/run-docker.sh | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 82eacbac0ab04..d80e758313d8a 100644 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -4,16 +4,18 @@ set -ex run() { - local gid=$(id -g) \ - group=$(id -g -n) \ - target=$1 \ - uid=$(id -u) \ - user=$(id -u -n) + local target=$1 echo $target + + # This directory needs to exist before calling docker, otherwise docker will create it but it + # will be owned by root + mkdir -p target + docker build -t $target ci/docker/$target docker run \ --rm \ + --user $(id -u):$(id -g) \ -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ -v $HOME/.cargo:/cargo \ @@ -22,12 +24,7 @@ run() { -v `rustc --print sysroot`:/rust:ro \ -w /checkout \ -it $target \ - sh -c " -groupadd -g $gid $group -useradd -m -g $gid -u $uid $user -chown $user /cargo /target -su -c 'PATH=\$PATH:/rust/bin ci/run.sh $target' $user -" + sh -c "PATH=\$PATH:/rust/bin ci/run.sh $target" } if [ -z "$1" ]; then From 0864c9d6a221c69f8644199991e56f5458f63347 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Sep 2016 19:04:48 -0500 Subject: [PATCH 0170/4206] fix nm call the prefix was missing a '-', i.e. arm-linux-gnueabinm was being called. This also sets -e in run.sh to catch this sort of errors. --- library/compiler-builtins/ci/run.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 206b2e9ed3c51..e07c82fd0b667 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -1,3 +1,5 @@ +set -e + # Test our implementation case $1 in thumb*) @@ -29,7 +31,7 @@ case $1 in esac # Look out for duplicated symbols when we include the compiler-rt (C) implementation -PREFIX=$(echo $1 | sed -e 's/unknown-//') +PREFIX=$(echo $1 | sed -e 's/unknown-//')- case $1 in armv7-*) PREFIX=arm-linux-gnueabihf- @@ -55,8 +57,10 @@ case $TRAVIS_OS_NAME in esac # NOTE On i586, It's normal that the get_pc_thunk symbol appears several times so ignore it -$PREFIX$NM -g --defined-only /target/${1}/debug/librustc_builtins.rlib | \ - sort | uniq -d | grep -v __x86.get_pc_thunk | grep 'T __' +stdout=$($PREFIX$NM -g --defined-only /target/${1}/debug/librustc_builtins.rlib) + +set +e +echo $stdout | sort | uniq -d | grep -v __x86.get_pc_thunk | grep 'T __' if test $? = 0; then exit 1 From 7009fd238d261eb84f353a122cb31cedc30c6899 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Sep 2016 19:12:17 -0500 Subject: [PATCH 0171/4206] Revert "Merge pull request #48 from mattico/add_float_quickcheck" This reverts commit e34a6058df470e5b3d187c947ac41a294994c414, reversing changes made to cab88e6133b0db9c6663ffd8b2f65cb35e8a9dda. --- library/compiler-builtins/src/float/add.rs | 145 +++++++++++++++++---- library/compiler-builtins/src/float/mod.rs | 79 +---------- library/compiler-builtins/src/qc.rs | 55 -------- 3 files changed, 118 insertions(+), 161 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 7c9f11a1195aa..7707850217cba 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -9,27 +9,27 @@ macro_rules! add { #[allow(unused_parens)] #[cfg_attr(not(test), no_mangle)] pub extern fn $intrinsic(a: $ty, b: $ty) -> $ty { - let one = Wrapping(1 as <$ty as Float>::Int); - let zero = Wrapping(0 as <$ty as Float>::Int); - - let bits = Wrapping(<$ty>::bits() as <$ty as Float>::Int); - let significand_bits = Wrapping(<$ty>::significand_bits() as <$ty as Float>::Int); - let exponent_bits = Wrapping(<$ty>::exponent_bits() as <$ty as Float>::Int); - let max_exponent = (one << exponent_bits.0 as usize) - one; - - let implicit_bit = one << significand_bits.0 as usize; - let significand_mask = implicit_bit - one; - let sign_bit = one << (significand_bits + exponent_bits).0 as usize; - let abs_mask = sign_bit - one; - let exponent_mask = abs_mask ^ significand_mask; - let inf_rep = exponent_mask; - let quiet_bit = implicit_bit >> 1; - let qnan_rep = exponent_mask | quiet_bit; - - let mut a_rep = Wrapping(a.repr()); - let mut b_rep = Wrapping(b.repr()); - let a_abs = a_rep & abs_mask; - let b_abs = b_rep & abs_mask; + let one = Wrapping(1 as <$ty as Float>::Int); + let zero = Wrapping(0 as <$ty as Float>::Int); + + let bits = Wrapping(<$ty>::bits() as <$ty as Float>::Int); + let significand_bits = Wrapping(<$ty>::significand_bits() as <$ty as Float>::Int); + let exponent_bits = bits - significand_bits - one; + let max_exponent = (one << exponent_bits.0 as usize) - one; + + let implicit_bit = one << significand_bits.0 as usize; + let significand_mask = implicit_bit - one; + let sign_bit = one << (significand_bits + exponent_bits).0 as usize; + let abs_mask = sign_bit - one; + let exponent_mask = abs_mask ^ significand_mask; + let inf_rep = exponent_mask; + let quiet_bit = implicit_bit >> 1; + let qnan_rep = exponent_mask | quiet_bit; + + let mut a_rep = Wrapping(a.repr()); + let mut b_rep = Wrapping(b.repr()); + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; // Detect if a or b is zero, infinity, or NaN. if a_abs - one >= inf_rep - one || @@ -188,7 +188,7 @@ mod tests { use core::{f32, f64}; use float::Float; - use qc::{F32, F64}; + use qc::{U32, U64}; // NOTE The tests below have special handing for NaN values. // Because NaN != NaN, the floating-point representations must be used @@ -212,18 +212,107 @@ mod tests { } } + // TODO: Add F32/F64 to qc so that they print the right values (at the very least) check! { fn __addsf3(f: extern fn(f32, f32) -> f32, - a: F32, - b: F32) + a: U32, + b: U32) -> Option > { - Some(FRepr(f(a.0, b.0))) + let (a, b) = (f32::from_repr(a.0), f32::from_repr(b.0)); + Some(FRepr(f(a, b))) } fn __adddf3(f: extern fn(f64, f64) -> f64, - a: F64, - b: F64) -> Option > { - Some(FRepr(f(a.0, b.0))) + a: U64, + b: U64) -> Option > { + let (a, b) = (f64::from_repr(a.0), f64::from_repr(b.0)); + Some(FRepr(f(a, b))) } } + + // More tests for special float values + + #[test] + fn test_float_tiny_plus_tiny() { + let tiny = f32::from_repr(1); + let r = super::__addsf3(tiny, tiny); + assert!(r.eq_repr(tiny + tiny)); + } + + #[test] + fn test_double_tiny_plus_tiny() { + let tiny = f64::from_repr(1); + let r = super::__adddf3(tiny, tiny); + assert!(r.eq_repr(tiny + tiny)); + } + + #[test] + fn test_float_small_plus_small() { + let a = f32::from_repr(327); + let b = f32::from_repr(256); + let r = super::__addsf3(a, b); + assert!(r.eq_repr(a + b)); + } + + #[test] + fn test_double_small_plus_small() { + let a = f64::from_repr(327); + let b = f64::from_repr(256); + let r = super::__adddf3(a, b); + assert!(r.eq_repr(a + b)); + } + + #[test] + fn test_float_one_plus_one() { + let r = super::__addsf3(1f32, 1f32); + assert!(r.eq_repr(1f32 + 1f32)); + } + + #[test] + fn test_double_one_plus_one() { + let r = super::__adddf3(1f64, 1f64); + assert!(r.eq_repr(1f64 + 1f64)); + } + + #[test] + fn test_float_different_nan() { + let a = f32::from_repr(1); + let b = f32::from_repr(0b11111111100100010001001010101010); + let x = super::__addsf3(a, b); + let y = a + b; + assert!(x.eq_repr(y)); + } + + #[test] + fn test_double_different_nan() { + let a = f64::from_repr(1); + let b = f64::from_repr(0b1111111111110010001000100101010101001000101010000110100011101011); + let x = super::__adddf3(a, b); + let y = a + b; + assert!(x.eq_repr(y)); + } + + #[test] + fn test_float_nan() { + let r = super::__addsf3(f32::NAN, 1.23); + assert_eq!(r.repr(), f32::NAN.repr()); + } + + #[test] + fn test_double_nan() { + let r = super::__adddf3(f64::NAN, 1.23); + assert_eq!(r.repr(), f64::NAN.repr()); + } + + #[test] + fn test_float_inf() { + let r = super::__addsf3(f32::INFINITY, -123.4); + assert_eq!(r, f32::INFINITY); + } + + #[test] + fn test_double_inf() { + let r = super::__adddf3(f64::INFINITY, -123.4); + assert_eq!(r, f64::INFINITY); + } } diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 8aa6328ce0648..cee2b73987392 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -10,45 +10,21 @@ pub trait Float: Sized + Copy { /// Returns the bitwidth of the float type fn bits() -> u32; - /// Returns the bitwidth of the exponent - fn exponent_bits() -> u32; - /// Returns the bitwidth of the significand fn significand_bits() -> u32; - /// Returns a mask for the sign bit of `self` - fn sign_mask() -> Self::Int; - - /// Returns a mask for the exponent portion of `self` - fn exponent_mask() -> Self::Int; - - /// Returns a mask for the significand portion of `self` - fn significand_mask() -> Self::Int; - - /// Returns the sign bit of `self` - fn sign(self) -> bool; - - /// Returns the exponent portion of `self`, shifted to the right - fn exponent(self) -> Self::Int; - - /// Returns the significand portion of `self` - fn significand(self) -> Self::Int; - /// Returns `self` transmuted to `Self::Int` fn repr(self) -> Self::Int; #[cfg(test)] /// 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 + /// represented in multiple different ways. This methods returns `true` if two NaNs are /// compared. fn eq_repr(self, rhs: Self) -> bool; /// Returns a `Self::Int` transmuted back to `Self` fn from_repr(a: Self::Int) -> Self; - /// Constructs a `Self` from its parts - fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self; - /// Returns (normalized exponent, normalized significand) fn normalize(significand: Self::Int) -> (i32, Self::Int); } @@ -58,21 +34,9 @@ impl Float for f32 { fn bits() -> u32 { 32 } - fn exponent_bits() -> u32 { - 8 - } fn significand_bits() -> u32 { 23 } - fn sign_mask() -> Self::Int { - 1 << (Self::bits() - 1) - } - fn exponent_mask() -> Self::Int { - ((1 << Self::exponent_bits()) - 1) << Self::significand_bits() - } - fn significand_mask() -> Self::Int { - (1 << Self::significand_bits()) - 1 - } fn repr(self) -> Self::Int { unsafe { mem::transmute(self) } } @@ -87,21 +51,6 @@ impl Float for f32 { fn from_repr(a: Self::Int) -> Self { unsafe { mem::transmute(a) } } - - fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_repr(((sign as Self::Int) << (Self::bits() - 1)) | - exponent & Self::exponent_mask() | - significand & Self::significand_mask()) - } - fn sign(self) -> bool { - (self.repr() & Self::sign_mask()) != 0 - } - fn exponent(self) -> Self::Int { - self.repr() >> Self::significand_bits() & Self::exponent_mask() - } - fn significand(self) -> Self::Int { - self.repr() & Self::significand_mask() - } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros() .wrapping_sub((1u32 << Self::significand_bits()).leading_zeros()); @@ -113,21 +62,9 @@ impl Float for f64 { fn bits() -> u32 { 64 } - fn exponent_bits() -> u32 { - 11 - } fn significand_bits() -> u32 { 52 } - fn sign_mask() -> Self::Int { - 1 << (Self::bits() - 1) - } - fn exponent_mask() -> Self::Int { - ((1 << Self::exponent_bits()) - 1) << Self::significand_bits() - } - fn significand_mask() -> Self::Int { - (1 << Self::significand_bits()) - 1 - } fn repr(self) -> Self::Int { unsafe { mem::transmute(self) } } @@ -142,20 +79,6 @@ impl Float for f64 { fn from_repr(a: Self::Int) -> Self { unsafe { mem::transmute(a) } } - fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_repr(((sign as Self::Int) << (Self::bits() - 1)) | - exponent & Self::exponent_mask() | - significand & Self::significand_mask()) - } - fn sign(self) -> bool { - (self.repr() & Self::sign_mask()) != 0 - } - fn exponent(self) -> Self::Int { - self.repr() >> Self::significand_bits() & Self::exponent_mask() - } - fn significand(self) -> Self::Int { - self.repr() & Self::significand_mask() - } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros() .wrapping_sub((1u64 << Self::significand_bits()).leading_zeros()); diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs index 9d4fff305f6b5..1450a4ec8b383 100644 --- a/library/compiler-builtins/src/qc.rs +++ b/library/compiler-builtins/src/qc.rs @@ -5,12 +5,10 @@ use std::boxed::Box; use std::fmt; -use core::{f32, f64}; use quickcheck::{Arbitrary, Gen}; use int::LargeInt; -use float::Float; // Generates values in the full range of the integer type macro_rules! arbitrary { @@ -73,7 +71,6 @@ macro_rules! arbitrary { arbitrary!(I32: i32); arbitrary!(U32: u32); - // These integers are "too large". If we generate e.g. `u64` values in the full range then there's // only `1 / 2^32` chance of seeing a value smaller than `2^32` (i.e. whose higher "word" (32-bits) // is `0`)! But this is an important group of values to tests because we have special code paths for @@ -146,57 +143,6 @@ macro_rules! arbitrary_large { arbitrary_large!(I64: i64); arbitrary_large!(U64: u64); - -macro_rules! arbitrary_float { - ($TY:ident : $ty:ident) => { - #[derive(Clone, Copy)] - pub struct $TY(pub $ty); - - impl Arbitrary for $TY { - fn arbitrary(g: &mut G) -> $TY - where G: Gen - { - let special = [ - -0.0, 0.0, $ty::NAN, $ty::INFINITY, -$ty::INFINITY - ]; - - if g.gen_weighted_bool(10) { // Random special case - $TY(*g.choose(&special).unwrap()) - } else if g.gen_weighted_bool(10) { // NaN variants - let sign: bool = g.gen(); - let exponent: <$ty as Float>::Int = g.gen(); - let significand: <$ty as Float>::Int = 0; - $TY($ty::from_parts(sign, exponent, significand)) - } else if g.gen() { // Denormalized - let sign: bool = g.gen(); - let exponent: <$ty as Float>::Int = 0; - let significand: <$ty as Float>::Int = g.gen(); - $TY($ty::from_parts(sign, exponent, significand)) - } else { // Random anything - let sign: bool = g.gen(); - let exponent: <$ty as Float>::Int = g.gen(); - let significand: <$ty as Float>::Int = g.gen(); - $TY($ty::from_parts(sign, exponent, significand)) - } - } - - fn shrink(&self) -> Box> { - ::quickcheck::empty_shrinker() - } - } - - impl fmt::Debug for $TY { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.0, f) - } - } - } -} - -arbitrary_float!(F32: f32); -arbitrary_float!(F64: f64); - - // Convenience macro to test intrinsics against their reference implementations. // // Each intrinsic is tested against both the `gcc_s` library as well as @@ -317,4 +263,3 @@ macro_rules! check { } ) } - From cea4ff6d255f7bcffa6f0c26966a6ba7521a5d23 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Sep 2016 20:08:29 -0500 Subject: [PATCH 0172/4206] add back the mysterious apt-get install qemu-user-static --- library/compiler-builtins/.travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 7b3efe474a00c..e8931afad8dd0 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -46,6 +46,8 @@ install: script: - cargo generate-lockfile - if [[ $TRAVIS_OS_NAME = "linux" ]]; then + sudo apt-get remove -y qemu-user-static && + sudo apt-get install -y qemu-user-static && sh ci/run-docker.sh $TARGET; else cargo test --target $TARGET && From 9b1c06948d3ee1d8087b43b995e143b43e705dff Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Sep 2016 20:20:15 -0500 Subject: [PATCH 0173/4206] fix Xargo installation --- .../compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile | 2 ++ .../compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile | 2 ++ .../ci/docker/thumbv7em-none-eabihf/Dockerfile | 2 ++ .../compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile | 2 ++ library/compiler-builtins/ci/run.sh | 2 -- 5 files changed, 8 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile index 6f4997546bd02..52c969342cc77 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -2,6 +2,8 @@ FROM ubuntu:16.04 RUN apt-get update RUN apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev +RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ + bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.10 ENV AR_thumbv6m_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV6M_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv6m_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile index 5d26c92271781..5825fce99835a 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -2,6 +2,8 @@ FROM ubuntu:16.04 RUN apt-get update RUN apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev +RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ + bash -s -- --at /usr/bin --from japaric/xargo --tag v0.1.10 ENV AR_thumbv7em_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv7em_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile index f223320c2e324..7b2046ae70c52 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -2,6 +2,8 @@ FROM ubuntu:16.04 RUN apt-get update RUN apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev +RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ + bash -s -- --at /usr/bin --from japaric/xargo --tag v0.1.10 ENV AR_thumbv7em_none_eabihf=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_NONE_EABIHF_LINKER=arm-none-eabi-gcc \ CC_thumbv7em_none_eabihf=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile index e0121034c8a1a..f3dce39971426 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -2,6 +2,8 @@ FROM ubuntu:16.04 RUN apt-get update RUN apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev +RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ + bash -s -- --at /usr/bin --from japaric/xargo --tag v0.1.10 ENV AR_thumbv7m_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7M_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv7m_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index e07c82fd0b667..eae37deb2efa3 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -3,8 +3,6 @@ set -e # Test our implementation case $1 in thumb*) - curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --at /usr/bin --from japaric/xargo --tag v0.1.10 xargo build --target $1 xargo build --target $1 --release ;; From 20926bc1fd603ddd44bab16c9a0c94c8a5b75ce0 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Sep 2016 20:21:15 -0500 Subject: [PATCH 0174/4206] give Xargo a $HOME --- library/compiler-builtins/ci/run-docker.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index d80e758313d8a..5608cedc4677e 100644 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -24,7 +24,7 @@ run() { -v `rustc --print sysroot`:/rust:ro \ -w /checkout \ -it $target \ - sh -c "PATH=\$PATH:/rust/bin ci/run.sh $target" + sh -c "HOME=/tmp PATH=\$PATH:/rust/bin ci/run.sh $target" } if [ -z "$1" ]; then From dd34b80ea0c629524404392496cafd3ea0ca6f72 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Sep 2016 20:41:59 -0500 Subject: [PATCH 0175/4206] pick target during Xargo installation --- .../compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile | 2 +- .../ci/docker/thumbv7em-none-eabihf/Dockerfile | 2 +- .../compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile index 5825fce99835a..6f5b478e4adc8 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -3,7 +3,7 @@ RUN apt-get update RUN apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --at /usr/bin --from japaric/xargo --tag v0.1.10 + bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.10 ENV AR_thumbv7em_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv7em_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile index 7b2046ae70c52..3cd8acae9a4c3 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -3,7 +3,7 @@ RUN apt-get update RUN apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --at /usr/bin --from japaric/xargo --tag v0.1.10 + bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.10 ENV AR_thumbv7em_none_eabihf=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_NONE_EABIHF_LINKER=arm-none-eabi-gcc \ CC_thumbv7em_none_eabihf=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile index f3dce39971426..88adb2ddd6e61 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -3,7 +3,7 @@ RUN apt-get update RUN apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --at /usr/bin --from japaric/xargo --tag v0.1.10 + bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.10 ENV AR_thumbv7m_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7M_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv7m_none_eabi=arm-none-eabi-gcc \ From ab4e4bfd71e6c4b6c1a7481fff70dc7e2d52c737 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Sun, 2 Oct 2016 14:21:09 -0500 Subject: [PATCH 0176/4206] Initial implementation of multitester --- library/compiler-builtins/src/float/add.rs | 15 ++-- library/compiler-builtins/src/qc.rs | 80 +++++++++------------- 2 files changed, 41 insertions(+), 54 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 7707850217cba..63baf0068cbd1 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -186,16 +186,13 @@ add!(__adddf3: f64); #[cfg(test)] mod tests { use core::{f32, f64}; + use core::fmt; use float::Float; use qc::{U32, U64}; - // NOTE The tests below have special handing for NaN values. - // Because NaN != NaN, the floating-point representations must be used - // Because there are many diffferent values of NaN, and the implementation - // doesn't care about calculating the 'correct' one, if both values are NaN - // the values are considered equivalent. - + // TODO: Move this to F32/F64 in qc.rs + #[derive(Copy, Clone)] struct FRepr(F); impl PartialEq for FRepr { @@ -212,6 +209,12 @@ mod tests { } } + impl fmt::Debug for FRepr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } + } + // TODO: Add F32/F64 to qc so that they print the right values (at the very least) check! { fn __addsf3(f: extern fn(f32, f32) -> f32, diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs index 1450a4ec8b383..f7696b58de59e 100644 --- a/library/compiler-builtins/src/qc.rs +++ b/library/compiler-builtins/src/qc.rs @@ -195,7 +195,7 @@ macro_rules! check { } )* - mod _compiler_rt { + mod _test { use qc::*; use std::mem; use quickcheck::TestResult; @@ -207,56 +207,40 @@ macro_rules! check { let my_answer = super::$name(super::super::$name, $($arg),*); let compiler_rt_fn = ::compiler_rt::get(stringify!($name)); - unsafe { - let compiler_rt_answer = - super::$name(mem::transmute(compiler_rt_fn), - $($arg),*); - match (my_answer, compiler_rt_answer) { - (None, _) | (_, None) => TestResult::discard(), - (Some(a), Some(b)) => { - TestResult::from_bool(a == b) - } - } - } - } - - ::quickcheck::quickcheck(my_check as fn($($t),*) -> TestResult) - } - )* - } - - mod _gcc_s { - use qc::*; - use std::mem; - use quickcheck::TestResult; - - $( - #[test] - fn $name() { - fn my_check($($arg:$t),*) -> TestResult { - let my_answer = super::$name(super::super::$name, - $($arg),*); - let gcc_s_fn = ::gcc_s::get(stringify!($name)).unwrap(); - unsafe { - let gcc_s_answer = - super::$name(mem::transmute(gcc_s_fn), - $($arg),*); - match (my_answer, gcc_s_answer) { - (None, _) | (_, None) => TestResult::discard(), - (Some(a), Some(b)) => { - TestResult::from_bool(a == b) - } - } + let compiler_rt_answer = unsafe { + super::$name(mem::transmute(compiler_rt_fn), + $($arg),*) + }; + let gcc_s_answer = + match ::gcc_s::get(stringify!($name)) { + Some(f) => unsafe { + Some(super::$name(mem::transmute(f), + $($arg),*)) + }, + None => None, + }; + + let print_values = || { + print!("{} - Args: ", stringify!($name)); + $(print!("{:?} ", $arg);)* + print!("\n"); + println!(" rustc-builtins: {:?}", my_answer); + println!(" compiler_rt: {:?}", compiler_rt_answer); + println!(" gcc_s: {:?}", gcc_s_answer); + }; + + if my_answer != compiler_rt_answer { + print_values(); + TestResult::from_bool(false) + } else if gcc_s_answer.is_some() && + my_answer != gcc_s_answer.unwrap() { + print_values(); + TestResult::from_bool(false) + } else { + TestResult::from_bool(true) } } - // If it's not in libgcc, or we couldn't find libgcc, then - // just ignore this. We should have tests through - // compiler-rt in any case - if ::gcc_s::get(stringify!($name)).is_none() { - return - } - ::quickcheck::quickcheck(my_check as fn($($t),*) -> TestResult) } )* From e4997a2026340fd6a63edb79d679dbdb164cb4b3 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 2 Oct 2016 19:05:01 -0500 Subject: [PATCH 0177/4206] hide the thumbv* target files due to how Cargo works, the rustc-cfg in build.rs was picking our target specifications rather than the one the user meant to use. Placing our target files in any place other than the root of the Cargo project avoids the issue. --- library/compiler-builtins/ci/run.sh | 2 ++ library/compiler-builtins/{ => targets}/thumbv6m-none-eabi.json | 0 .../compiler-builtins/{ => targets}/thumbv7em-none-eabi.json | 0 .../compiler-builtins/{ => targets}/thumbv7em-none-eabihf.json | 0 library/compiler-builtins/{ => targets}/thumbv7m-none-eabi.json | 0 5 files changed, 2 insertions(+) rename library/compiler-builtins/{ => targets}/thumbv6m-none-eabi.json (100%) rename library/compiler-builtins/{ => targets}/thumbv7em-none-eabi.json (100%) rename library/compiler-builtins/{ => targets}/thumbv7em-none-eabihf.json (100%) rename library/compiler-builtins/{ => targets}/thumbv7m-none-eabi.json (100%) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index eae37deb2efa3..e938bc18c740b 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -3,6 +3,8 @@ set -e # Test our implementation case $1 in thumb*) + export RUST_TARGET_PATH=/checkout/targets + xargo build --target $1 xargo build --target $1 --release ;; diff --git a/library/compiler-builtins/thumbv6m-none-eabi.json b/library/compiler-builtins/targets/thumbv6m-none-eabi.json similarity index 100% rename from library/compiler-builtins/thumbv6m-none-eabi.json rename to library/compiler-builtins/targets/thumbv6m-none-eabi.json diff --git a/library/compiler-builtins/thumbv7em-none-eabi.json b/library/compiler-builtins/targets/thumbv7em-none-eabi.json similarity index 100% rename from library/compiler-builtins/thumbv7em-none-eabi.json rename to library/compiler-builtins/targets/thumbv7em-none-eabi.json diff --git a/library/compiler-builtins/thumbv7em-none-eabihf.json b/library/compiler-builtins/targets/thumbv7em-none-eabihf.json similarity index 100% rename from library/compiler-builtins/thumbv7em-none-eabihf.json rename to library/compiler-builtins/targets/thumbv7em-none-eabihf.json diff --git a/library/compiler-builtins/thumbv7m-none-eabi.json b/library/compiler-builtins/targets/thumbv7m-none-eabi.json similarity index 100% rename from library/compiler-builtins/thumbv7m-none-eabi.json rename to library/compiler-builtins/targets/thumbv7m-none-eabi.json From e6bc8007dd49f63d8b0b62ee436aae27ea7893a1 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Fri, 30 Sep 2016 17:15:44 -0500 Subject: [PATCH 0178/4206] Implement powi_f2 --- library/compiler-builtins/README.md | 4 +- .../compiler-rt/compiler-rt-cdylib/build.rs | 2 + .../compiler-rt/compiler-rt-cdylib/src/lib.rs | 4 ++ library/compiler-builtins/src/float/add.rs | 27 +--------- library/compiler-builtins/src/float/mod.rs | 29 ++++++++++ library/compiler-builtins/src/float/pow.rs | 53 +++++++++++++++++++ 6 files changed, 91 insertions(+), 28 deletions(-) create mode 100644 library/compiler-builtins/src/float/pow.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 28d86043ad5c5..20b153d7dc192 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -159,8 +159,8 @@ porting that particular intrinsic. - [x] mulodi4.c - [x] mulosi4.c - [ ] mulsf3.c -- [ ] powidf2.c -- [ ] powisf2.c +- [x] powidf2.c +- [x] powisf2.c - [ ] subdf3.c - [ ] subsf3.c - [ ] truncdfhf2.c diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs index b9b56a627b034..4eb76389570a2 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs @@ -58,6 +58,8 @@ fn main() { "udivmodsi4.c", "adddf3.c", "addsf3.c", + "powidf2.c", + "powisf2.c", ]); for src in sources.files.iter() { diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs index 57584832ff805..81affa2421ab1 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs @@ -22,6 +22,8 @@ extern { fn __umodsi3(); fn __addsf3(); fn __adddf3(); + fn __powisf2(); + fn __powidf2(); } macro_rules! declare { @@ -53,6 +55,8 @@ declare!(___umoddi3, __umoddi3); declare!(___umodsi3, __umodsi3); declare!(___addsf3, __addsf3); declare!(___adddf3, __adddf3); +declare!(___powisf2, __powisf2); +declare!(___powidf2, __powidf2); #[lang = "eh_personality"] fn eh_personality() {} diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 63baf0068cbd1..243c391b56554 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -186,35 +186,10 @@ add!(__adddf3: f64); #[cfg(test)] mod tests { use core::{f32, f64}; - use core::fmt; - use float::Float; + use float::{Float, FRepr}; use qc::{U32, U64}; - // TODO: Move this to F32/F64 in qc.rs - #[derive(Copy, Clone)] - struct FRepr(F); - - impl PartialEq for FRepr { - fn eq(&self, other: &FRepr) -> bool { - // NOTE(cfg) for some reason, on hard float targets, our implementation doesn't - // match the output of its gcc_s counterpart. Until we investigate further, we'll - // just avoid testing against gcc_s on those targets. Do note that our - // implementation matches the output of the FPU instruction on *hard* float targets - // and matches its gcc_s counterpart on *soft* float targets. - if cfg!(gnueabihf) { - return true - } - self.0.eq_repr(other.0) - } - } - - impl fmt::Debug for FRepr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } - } - // TODO: Add F32/F64 to qc so that they print the right values (at the very least) check! { fn __addsf3(f: extern fn(f32, f32) -> f32, diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index cee2b73987392..8bd574deb1718 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,6 +1,8 @@ use core::mem; +use core::fmt; pub mod add; +pub mod pow; /// Trait for some basic operations on floats pub trait Float: Sized + Copy { @@ -85,3 +87,30 @@ impl Float for f64 { (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) } } + +// TODO: Move this to F32/F64 in qc.rs +#[cfg(test)] +#[derive(Copy, Clone)] +pub struct FRepr(F); + +#[cfg(test)] +impl PartialEq for FRepr { + fn eq(&self, other: &FRepr) -> bool { + // NOTE(cfg) for some reason, on hard float targets, our implementation doesn't + // match the output of its gcc_s counterpart. Until we investigate further, we'll + // just avoid testing against gcc_s on those targets. Do note that our + // implementation matches the output of the FPU instruction on *hard* float targets + // and matches its gcc_s counterpart on *soft* float targets. + if cfg!(gnueabihf) { + return true + } + self.0.eq_repr(other.0) + } +} + +#[cfg(test)] +impl fmt::Debug for FRepr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs new file mode 100644 index 0000000000000..14b3b9ace6aa8 --- /dev/null +++ b/library/compiler-builtins/src/float/pow.rs @@ -0,0 +1,53 @@ + +macro_rules! pow { + ($intrinsic:ident: $fty:ty, $ity:ty) => { + /// Returns `a` raised to the power `b` + #[cfg_attr(not(test), no_mangle)] + pub extern "C" fn $intrinsic(a: $fty, b: $ity) -> $fty { + let (mut a, mut b) = (a, b); + let recip = b < 0; + let mut r: $fty = 1.0; + loop { + if (b & 1) != 0 { + r *= a; + } + b /= 2; + if b == 0 { + break; + } + a *= a; + } + + if recip { + 1.0 / r + } else { + r + } + } + } +} + +pow!(__powisf2: f32, i32); +pow!(__powidf2: f64, i32); + +#[cfg(test)] +mod tests { + use float::{Float, FRepr}; + use qc::{I32, U32, U64}; + + check! { + fn __powisf2(f: extern fn(f32, i32) -> f32, + a: U32, + b: I32) -> Option > { + let (a, b) = (f32::from_repr(a.0), b.0); + Some(FRepr(f(a, b))) + } + + fn __powidf2(f: extern fn(f64, i32) -> f64, + a: U64, + b: I32) -> Option > { + let (a, b) = (f64::from_repr(a.0), b.0); + Some(FRepr(f(a, b))) + } + } +} From 4e7d7c7cd832dd7fee4568a0e81c519af53c8769 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 3 Oct 2016 09:12:13 -0500 Subject: [PATCH 0179/4206] bump rustc-cfg version and show a better error message when it fails --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/build.rs | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 93f7d19701252..c198d9f3ccb69 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -6,7 +6,7 @@ version = "0.1.0" [build-dependencies] gcc = "0.3.35" -rustc-cfg = "0.1.2" +rustc-cfg = "0.2.0" [dependencies] diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index a05a1a590ad2f..cf9a24e3b1f78 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -2,8 +2,9 @@ extern crate gcc; extern crate rustc_cfg; use std::collections::BTreeMap; -use std::env; +use std::io::Write; use std::path::Path; +use std::{env, io, process}; use rustc_cfg::Cfg; @@ -50,7 +51,10 @@ fn main() { let target = env::var("TARGET").unwrap(); let Cfg { ref target_arch, ref target_os, ref target_env, ref target_vendor, .. } = - Cfg::new(&target).unwrap(); + Cfg::new(&target).unwrap_or_else(|e| { + writeln!(io::stderr(), "{}", e).ok(); + process::exit(1) + }); // 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. From 27adb57c40706466dbe2ffd4e5bca7b15e01cb92 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 3 Oct 2016 20:19:56 -0500 Subject: [PATCH 0180/4206] fix duplicate symbol test --- 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 e938bc18c740b..c3618132b675b 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -60,7 +60,7 @@ esac stdout=$($PREFIX$NM -g --defined-only /target/${1}/debug/librustc_builtins.rlib) set +e -echo $stdout | sort | uniq -d | grep -v __x86.get_pc_thunk | grep 'T __' +echo "$stdout" | sort | uniq -d | grep -v __x86.get_pc_thunk | grep 'T __' if test $? = 0; then exit 1 From d0c93bef1b3894390c9a02b9a98467d0c0a1ef55 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 3 Oct 2016 20:52:14 -0500 Subject: [PATCH 0181/4206] stop compiling compiler-rt implementations to avoid duplicate symbols --- library/compiler-builtins/build.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index a05a1a590ad2f..856a6bcfa332a 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -160,8 +160,6 @@ fn main() { "paritysi2.c", "popcountdi2.c", "popcountsi2.c", - "powidf2.c", - "powisf2.c", "powixf2.c", "subdf3.c", "subsf3.c", From fcc7ca7f80b3672e7c828ae99cd23005c18d3e30 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 3 Oct 2016 23:26:49 -0500 Subject: [PATCH 0182/4206] switch compiler-rt to rust-lang's fork this fork has been patched against the UB in floatsidf and floasisf closes #85 --- library/compiler-builtins/.gitmodules | 2 +- .../compiler-rt/compiler-rt-cdylib/compiler-rt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index fe501bba96562..d86b9fa3414ad 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -1,3 +1,3 @@ [submodule "compiler-rt/compiler-rt-cdylib/compiler-rt"] path = compiler-rt/compiler-rt-cdylib/compiler-rt - url = https://github.com/llvm-mirror/compiler-rt + url = https://github.com/rust-lang/compiler-rt diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt index 515106ebc0722..f03ba5a4e8bf1 160000 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt @@ -1 +1 @@ -Subproject commit 515106ebc07227b85336816ef77bc39506b8fd26 +Subproject commit f03ba5a4e8bf16dcf42dd742a4ce255c36321356 From b56315e9a73fcb3e906b9fb4b9b024fe585f5500 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 5 Oct 2016 21:34:16 -0500 Subject: [PATCH 0183/4206] switch to a current nightly --- library/compiler-builtins/.travis.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index e8931afad8dd0..511e69c56718f 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -1,26 +1,20 @@ cache: cargo dist: trusty language: rust +rust: nightly services: docker sudo: required -rust: nightly matrix: include: - env: TARGET=aarch64-unknown-linux-gnu - env: TARGET=arm-unknown-linux-gnueabi - # FIXME(rust-lang/rust#36518) - rust: nightly-2016-09-21 - env: TARGET=arm-unknown-linux-gnueabihf - env: TARGET=armv7-unknown-linux-gnueabihf - env: TARGET=i586-unknown-linux-gnu - env: TARGET=i686-apple-darwin - # FIXME(rust-lang/rust#36793) - rust: nightly-2016-09-10 os: osx - env: TARGET=i686-unknown-linux-gnu - # FIXME(rust-lang/rust#36793) - rust: nightly-2016-09-10 - env: TARGET=mips-unknown-linux-gnu - env: TARGET=mipsel-unknown-linux-gnu - env: TARGET=powerpc-unknown-linux-gnu From b2b40931c65dedb9c7552565a06b869ab5199243 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 5 Oct 2016 22:13:55 -0500 Subject: [PATCH 0184/4206] switch back to old nightly for the arm-gnueabi target --- library/compiler-builtins/.travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 511e69c56718f..a7bea0f912f38 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -9,6 +9,8 @@ matrix: include: - env: TARGET=aarch64-unknown-linux-gnu - env: TARGET=arm-unknown-linux-gnueabi + # FIXME(rust-lang/rust#36518) + rust: nightly-2016-09-21 - env: TARGET=arm-unknown-linux-gnueabihf - env: TARGET=armv7-unknown-linux-gnueabihf - env: TARGET=i586-unknown-linux-gnu From dbd5f05f31ea467f5519967ab432f362260a27b1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 6 Oct 2016 23:20:09 -0500 Subject: [PATCH 0185/4206] drop the target files --- .../ci/docker/thumbv6m-none-eabi/Dockerfile | 2 +- .../ci/docker/thumbv7em-none-eabi/Dockerfile | 2 +- .../ci/docker/thumbv7em-none-eabihf/Dockerfile | 2 +- .../ci/docker/thumbv7m-none-eabi/Dockerfile | 2 +- library/compiler-builtins/ci/run.sh | 2 -- .../targets/thumbv6m-none-eabi.json | 12 ------------ .../targets/thumbv7em-none-eabi.json | 10 ---------- .../targets/thumbv7em-none-eabihf.json | 11 ----------- .../targets/thumbv7m-none-eabi.json | 10 ---------- 9 files changed, 4 insertions(+), 49 deletions(-) delete mode 100644 library/compiler-builtins/targets/thumbv6m-none-eabi.json delete mode 100644 library/compiler-builtins/targets/thumbv7em-none-eabi.json delete mode 100644 library/compiler-builtins/targets/thumbv7em-none-eabihf.json delete mode 100644 library/compiler-builtins/targets/thumbv7m-none-eabi.json diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile index 52c969342cc77..4a4556673f22a 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -3,7 +3,7 @@ RUN apt-get update RUN apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.10 + bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.13 ENV AR_thumbv6m_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV6M_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv6m_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile index 6f5b478e4adc8..84cd8d7af0748 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -3,7 +3,7 @@ RUN apt-get update RUN apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.10 + bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.13 ENV AR_thumbv7em_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv7em_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile index 3cd8acae9a4c3..62ba127312208 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -3,7 +3,7 @@ RUN apt-get update RUN apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.10 + bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.13 ENV AR_thumbv7em_none_eabihf=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_NONE_EABIHF_LINKER=arm-none-eabi-gcc \ CC_thumbv7em_none_eabihf=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile index 88adb2ddd6e61..42baa3c9a1965 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -3,7 +3,7 @@ RUN apt-get update RUN apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.10 + bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.13 ENV AR_thumbv7m_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7M_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv7m_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index c3618132b675b..455bb2e400d97 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -3,8 +3,6 @@ set -e # Test our implementation case $1 in thumb*) - export RUST_TARGET_PATH=/checkout/targets - xargo build --target $1 xargo build --target $1 --release ;; diff --git a/library/compiler-builtins/targets/thumbv6m-none-eabi.json b/library/compiler-builtins/targets/thumbv6m-none-eabi.json deleted file mode 100644 index 4b409cff04939..0000000000000 --- a/library/compiler-builtins/targets/thumbv6m-none-eabi.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "arch": "arm", - "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", - "executables": true, - "features": "+strict-align", - "llvm-target": "thumbv6m-none-eabi", - "max-atomic-width": 0, - "os": "none", - "pre-link-args": ["-nostartfiles"], - "target-endian": "little", - "target-pointer-width": "32" -} diff --git a/library/compiler-builtins/targets/thumbv7em-none-eabi.json b/library/compiler-builtins/targets/thumbv7em-none-eabi.json deleted file mode 100644 index 2ac47c8f829b4..0000000000000 --- a/library/compiler-builtins/targets/thumbv7em-none-eabi.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "arch": "arm", - "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", - "executables": true, - "llvm-target": "thumbv7em-none-eabi", - "os": "none", - "pre-link-args": ["-nostartfiles"], - "target-endian": "little", - "target-pointer-width": "32" -} diff --git a/library/compiler-builtins/targets/thumbv7em-none-eabihf.json b/library/compiler-builtins/targets/thumbv7em-none-eabihf.json deleted file mode 100644 index 55ed3fd885d5d..0000000000000 --- a/library/compiler-builtins/targets/thumbv7em-none-eabihf.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "arch": "arm", - "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", - "executables": true, - "features": "+vfp4", - "llvm-target": "thumbv7em-none-eabihf", - "os": "none", - "pre-link-args": ["-nostartfiles"], - "target-endian": "little", - "target-pointer-width": "32" -} diff --git a/library/compiler-builtins/targets/thumbv7m-none-eabi.json b/library/compiler-builtins/targets/thumbv7m-none-eabi.json deleted file mode 100644 index 9635efa8d785e..0000000000000 --- a/library/compiler-builtins/targets/thumbv7m-none-eabi.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "arch": "arm", - "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", - "executables": true, - "llvm-target": "thumbv7m-none-eabi", - "os": "none", - "pre-link-args": ["-nostartfiles"], - "target-endian": "little", - "target-pointer-width": "32" -} From 92734e88ff42d1c3cd7599c5e82124ae5c2dba96 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 7 Oct 2016 07:13:55 -0500 Subject: [PATCH 0186/4206] pass -nostartfiles to the linker --- library/compiler-builtins/.cargo/config | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 library/compiler-builtins/.cargo/config diff --git a/library/compiler-builtins/.cargo/config b/library/compiler-builtins/.cargo/config new file mode 100644 index 0000000000000..b538953458298 --- /dev/null +++ b/library/compiler-builtins/.cargo/config @@ -0,0 +1,11 @@ +[target.thumbv6m-none-eabi] +rustflags = ["-C", "link-arg=-nostartfiles"] + +[target.thumbv7m-none-eabi] +rustflags = ["-C", "link-arg=-nostartfiles"] + +[target.thumbv7em-none-eabi] +rustflags = ["-C", "link-arg=-nostartfiles"] + +[target.thumbv7em-none-eabihf] +rustflags = ["-C", "link-arg=-nostartfiles"] \ No newline at end of file From 3911f499902b22b15ccfae5d6a48efb7e25b4f84 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 5 Oct 2016 23:01:58 -0500 Subject: [PATCH 0187/4206] run the full test suite on osx --- library/compiler-builtins/.travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index a7bea0f912f38..6e159cc211dfc 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -46,8 +46,7 @@ script: sudo apt-get install -y qemu-user-static && sh ci/run-docker.sh $TARGET; else - cargo test --target $TARGET && - cargo test --target $TARGET --release; + sh ci/run.sh $TARGET; fi # Travis can't cache files that are not readable by "others" - chmod -R a+r $HOME/.cargo From b0b7453ea3d2457af456e337df22d6e786270913 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 7 Oct 2016 14:29:34 -0500 Subject: [PATCH 0188/4206] fix path to .rlib on OSX --- library/compiler-builtins/ci/run.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 455bb2e400d97..7dc9be178a95b 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -55,7 +55,13 @@ case $TRAVIS_OS_NAME in esac # NOTE On i586, It's normal that the get_pc_thunk symbol appears several times so ignore it -stdout=$($PREFIX$NM -g --defined-only /target/${1}/debug/librustc_builtins.rlib) +if [ $TRAVIS_OS_NAME = osx ]; then + path=target/${1}/debug/librustc_builtins.rlib +else + path=/target/${1}/debug/librustc_builtins.rlib +fi + +stdout=$($PREFIX$NM -g --defined-only $path) set +e echo "$stdout" | sort | uniq -d | grep -v __x86.get_pc_thunk | grep 'T __' From 9f4632c82971f757f17b53b969161b483c8dc46c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Sep 2016 17:30:05 -0500 Subject: [PATCH 0189/4206] panic! -> abort closes #79 --- library/compiler-builtins/src/int/udiv.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 3de18b4a0ca34..8a9da9f41bc2c 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -1,4 +1,4 @@ -use core::mem; +use core::{intrinsics, mem}; use int::{Int, LargeInt}; /// Returns `n / d` @@ -7,7 +7,11 @@ use int::{Int, LargeInt}; pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { // Special cases if d == 0 { - panic!("Division by zero"); + // NOTE This should be unreachable in safe Rust because the program will panic before + // this intrinsic is called + unsafe { + intrinsics::abort() + } } if n == 0 { @@ -129,7 +133,11 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { // K X // --- // 0 0 - panic!("Division by zero"); + // NOTE This should be unreachable in safe Rust because the program will panic before + // this intrinsic is called + unsafe { + intrinsics::abort() + } } if n.low() == 0 { From fbf1cc0b75b979d31f65fa1edbadbc3a9bae4562 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Sep 2016 23:10:30 -0500 Subject: [PATCH 0190/4206] check that we don't have any call to panic in our implementations --- library/compiler-builtins/Cargo.toml | 3 + library/compiler-builtins/ci/run.sh | 10 ++ .../compiler-builtins/src/bin/intrinsics.rs | 106 ++++++++++-------- 3 files changed, 75 insertions(+), 44 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index c198d9f3ccb69..b3a5cf4d6b39e 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -26,3 +26,6 @@ c = [] weak = ["rlibc/weak"] [workspace] + +[profile.release] +lto = true diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 7dc9be178a95b..6a0906b8dfb5b 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -28,6 +28,16 @@ case $1 in ;; esac +# Verify that there are no undefined symbols to `panic` within our implementations +case $1 in + thumb*) + xargo build --features c --target $1 --bin intrinsics --release + ;; + *) + cargo build --features c --target $1 --bin intrinsics --release + ;; +esac + # Look out for duplicated symbols when we include the compiler-rt (C) implementation PREFIX=$(echo $1 | sed -e 's/unknown-//')- case $1 in diff --git a/library/compiler-builtins/src/bin/intrinsics.rs b/library/compiler-builtins/src/bin/intrinsics.rs index 5e234855cf1be..591765a477ebc 100644 --- a/library/compiler-builtins/src/bin/intrinsics.rs +++ b/library/compiler-builtins/src/bin/intrinsics.rs @@ -302,52 +302,70 @@ mod intrinsics { #[cfg(feature = "c")] fn run() { + use core::ptr; use intrinsics::*; - aeabi_d2f(2.); - aeabi_d2i(2.); - aeabi_d2l(2.); - aeabi_d2uiz(2.); - aeabi_d2ulz(2.); - aeabi_dadd(2., 3.); - aeabi_dcmpeq(2., 3.); - aeabi_dcmpgt(2., 3.); - aeabi_dcmplt(2., 3.); - aeabi_ddiv(2., 3.); - aeabi_dmul(2., 3.); - aeabi_dsub(2., 3.); - aeabi_f2d(2.); - aeabi_f2iz(2.); - aeabi_f2lz(2.); - aeabi_f2uiz(2.); - aeabi_f2ulz(2.); - aeabi_fadd(2., 3.); - aeabi_fcmpeq(2., 3.); - aeabi_fcmpgt(2., 3.); - aeabi_fcmplt(2., 3.); - aeabi_fdiv(2., 3.); - aeabi_fmul(2., 3.); - aeabi_fsub(2., 3.); - aeabi_i2d(2); - aeabi_i2f(2); - aeabi_idiv(2, 3); - aeabi_idivmod(2, 3); - aeabi_l2d(2); - aeabi_l2f(2); - aeabi_ldivmod(2, 3); - aeabi_lmul(2, 3); - aeabi_ui2d(2); - aeabi_ui2f(2); - aeabi_uidiv(2, 3); - aeabi_uidivmod(2, 3); - aeabi_ul2d(2); - aeabi_ul2f(2); - aeabi_uldivmod(2, 3); - moddi3(2, 3); - mulodi4(2, 3); - powidf2(2., 3); - powisf2(2., 3); - umoddi3(2, 3); + // We use volatile load/stores to prevent LLVM from optimizing away the intrinsics during LTO + macro_rules! arg { + () => { + unsafe { + ptr::read_volatile(0x0 as *const _) + } + } + } + + macro_rules! ret { + ($e:expr) => { + unsafe { + ptr::write_volatile(0x0 as *mut _, $e) + } + } + } + + ret!(aeabi_d2f(arg!())); + ret!(aeabi_d2i(arg!())); + ret!(aeabi_d2l(arg!())); + ret!(aeabi_d2uiz(arg!())); + ret!(aeabi_d2ulz(arg!())); + ret!(aeabi_dadd(arg!(), arg!())); + ret!(aeabi_dcmpeq(arg!(), arg!())); + ret!(aeabi_dcmpgt(arg!(), arg!())); + ret!(aeabi_dcmplt(arg!(), arg!())); + ret!(aeabi_ddiv(arg!(), arg!())); + ret!(aeabi_dmul(arg!(), arg!())); + ret!(aeabi_dsub(arg!(), arg!())); + ret!(aeabi_f2d(arg!())); + ret!(aeabi_f2iz(arg!())); + ret!(aeabi_f2lz(arg!())); + ret!(aeabi_f2uiz(arg!())); + ret!(aeabi_f2ulz(arg!())); + ret!(aeabi_fadd(arg!(), arg!())); + ret!(aeabi_fcmpeq(arg!(), arg!())); + ret!(aeabi_fcmpgt(arg!(), arg!())); + ret!(aeabi_fcmplt(arg!(), arg!())); + ret!(aeabi_fdiv(arg!(), arg!())); + ret!(aeabi_fmul(arg!(), arg!())); + ret!(aeabi_fsub(arg!(), arg!())); + ret!(aeabi_i2d(arg!())); + ret!(aeabi_i2f(arg!())); + ret!(aeabi_idiv(arg!(), arg!())); + ret!(aeabi_idivmod(arg!(), arg!())); + ret!(aeabi_l2d(arg!())); + ret!(aeabi_l2f(arg!())); + ret!(aeabi_ldivmod(arg!(), arg!())); + ret!(aeabi_lmul(arg!(), arg!())); + ret!(aeabi_ui2d(arg!())); + ret!(aeabi_ui2f(arg!())); + ret!(aeabi_uidiv(arg!(), arg!())); + ret!(aeabi_uidivmod(arg!(), arg!())); + ret!(aeabi_ul2d(arg!())); + ret!(aeabi_ul2f(arg!())); + ret!(aeabi_uldivmod(arg!(), arg!())); + ret!(moddi3(arg!(), arg!())); + ret!(mulodi4(arg!(), arg!())); + ret!(powidf2(arg!(), arg!())); + ret!(powisf2(arg!(), arg!())); + ret!(umoddi3(arg!(), arg!())); } #[cfg(all(feature = "c", not(thumb)))] From c9e3feb5e30591cca73a7c2fa990e9d21f672f2c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 5 Oct 2016 20:45:40 -0500 Subject: [PATCH 0191/4206] insert more `abort()` calls where division by zero may occur --- library/compiler-builtins/src/int/sdiv.rs | 14 ++++++++++++++ library/compiler-builtins/src/int/udiv.rs | 8 ++++++++ 2 files changed, 22 insertions(+) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 37f5dd7df62bb..d60dda9899968 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -1,3 +1,5 @@ +use core::intrinsics; + use int::Int; macro_rules! div { @@ -10,6 +12,12 @@ macro_rules! div { let a = (a ^ s_a) - s_a; let b = (b ^ s_b) - s_b; let s = s_a ^ s_b; + + if b == 0 { + unsafe { + intrinsics::abort() + } + } let r = (a as $uty) / (b as $uty); (r as $ty ^ s) - s } @@ -25,6 +33,12 @@ macro_rules! mod_ { let b = (b ^ s) - s; let s = a >> (<$ty>::bits() - 1); let a = (a ^ s) - s; + + if b == 0 { + unsafe { + intrinsics::abort() + } + } let r = (a as $uty) % (b as $uty); (r as $ty ^ s) - s } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 8a9da9f41bc2c..bb1546c3ac344 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -109,6 +109,14 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { // 0 X // --- // 0 X + // NOTE This should be unreachable in safe Rust because the program will panic before + // this intrinsic is called + if d.low() == 0 { + unsafe { + intrinsics::abort() + } + } + if let Some(rem) = rem { *rem = u64::from(n.low() % d.low()); } From a02ecc8eeff47be8eb6641d558e0121ae5499fa6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 7 Oct 2016 10:17:44 -0500 Subject: [PATCH 0192/4206] get profile.dev (-debug-assertions) + LTO working --- library/compiler-builtins/Cargo.toml | 6 +-- library/compiler-builtins/ci/run.sh | 6 ++- library/compiler-builtins/src/float/pow.rs | 5 +- library/compiler-builtins/src/int/sdiv.rs | 14 +---- library/compiler-builtins/src/int/udiv.rs | 15 ++---- library/compiler-builtins/src/lib.rs | 60 ++++++++++++++++++++++ 6 files changed, 76 insertions(+), 30 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index b3a5cf4d6b39e..eefb0b26663de 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -25,7 +25,7 @@ compiler-rt = { path = "compiler-rt" } c = [] weak = ["rlibc/weak"] -[workspace] +[profile.dev] +debug-assertions = false -[profile.release] -lto = true +[workspace] diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 6a0906b8dfb5b..df27e35626fe1 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -31,10 +31,12 @@ esac # Verify that there are no undefined symbols to `panic` within our implementations case $1 in thumb*) - xargo build --features c --target $1 --bin intrinsics --release + xargo rustc --features c --target $1 --bin intrinsics -- -C lto + xargo rustc --features c --target $1 --bin intrinsics --release -- -C lto ;; *) - cargo build --features c --target $1 --bin intrinsics --release + cargo rustc --features c --target $1 --bin intrinsics -- -C lto + cargo rustc --features c --target $1 --bin intrinsics --release -- -C lto ;; esac diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index 14b3b9ace6aa8..c02c76f770951 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -1,6 +1,7 @@ +use core::intrinsics; macro_rules! pow { - ($intrinsic:ident: $fty:ty, $ity:ty) => { + ($intrinsic:ident: $fty:ty, $ity:ident) => { /// Returns `a` raised to the power `b` #[cfg_attr(not(test), no_mangle)] pub extern "C" fn $intrinsic(a: $fty, b: $ity) -> $fty { @@ -11,7 +12,7 @@ macro_rules! pow { if (b & 1) != 0 { r *= a; } - b /= 2; + b = sdiv!($ity, b, 2); if b == 0 { break; } diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index d60dda9899968..6f96b800bd89f 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -13,12 +13,7 @@ macro_rules! div { let b = (b ^ s_b) - s_b; let s = s_a ^ s_b; - if b == 0 { - unsafe { - intrinsics::abort() - } - } - let r = (a as $uty) / (b as $uty); + let r = udiv!((a as $uty), (b as $uty)); (r as $ty ^ s) - s } } @@ -34,12 +29,7 @@ macro_rules! mod_ { let s = a >> (<$ty>::bits() - 1); let a = (a ^ s) - s; - if b == 0 { - unsafe { - intrinsics::abort() - } - } - let r = (a as $uty) % (b as $uty); + let r = urem!((a as $uty), (b as $uty)); (r as $ty ^ s) - s } } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index bb1546c3ac344..999dcec05528b 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -109,18 +109,11 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { // 0 X // --- // 0 X - // NOTE This should be unreachable in safe Rust because the program will panic before - // this intrinsic is called - if d.low() == 0 { - unsafe { - intrinsics::abort() - } - } if let Some(rem) = rem { - *rem = u64::from(n.low() % d.low()); + *rem = u64::from(urem!(n.low(), d.low())); } - return u64::from(n.low() / d.low()); + return u64::from(udiv!(n.low(), d.low())); } else { // 0 X // --- @@ -153,9 +146,9 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { // --- // K 0 if let Some(rem) = rem { - *rem = u64::from_parts(0, n.high() % d.high()); + *rem = u64::from_parts(0, urem!(n.high(), d.high())); } - return u64::from(n.high() / d.high()); + return u64::from(udiv!(n.high(), d.high())); } // K K diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index acc56c98a69c9..351be02f78ff1 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -13,6 +13,66 @@ // NOTE cfg(all(feature = "c", ..)) indicate that compiler-rt provides an arch optimized // implementation of that intrinsic and we'll prefer to use that +macro_rules! udiv { + ($a:expr, $b:expr) => { + unsafe { + let a = $a; + let b = $b; + + if b == 0 { + intrinsics::abort() + } else { + intrinsics::unchecked_div(a, b) + } + } + } +} + +macro_rules! sdiv { + ($sty:ident, $a:expr, $b:expr) => { + unsafe { + let a = $a; + let b = $b; + + if b == 0 || (b == -1 && a == $sty::min_value()) { + intrinsics::abort() + } else { + intrinsics::unchecked_div(a, b) + } + } + } +} + +macro_rules! urem { + ($a:expr, $b:expr) => { + unsafe { + let a = $a; + let b = $b; + + if b == 0 { + intrinsics::abort() + } else { + intrinsics::unchecked_rem(a, b) + } + } + } +} + +macro_rules! srem { + ($sty:ty, $a:expr, $b:expr) => { + unsafe { + let a = $a; + let b = $b; + + if b == 0 || (b == -1 && a == $sty::min_value()) { + intrinsics::abort() + } else { + intrinsics::unchecked_rem(a, b) + } + } + } +} + #[cfg(test)] #[macro_use] extern crate quickcheck; From d05514cb20cef5a7886b33b0ae306e2e15911dfc Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 7 Oct 2016 17:48:37 -0500 Subject: [PATCH 0193/4206] fix unsafe warnings --- library/compiler-builtins/Cargo.toml | 3 --- library/compiler-builtins/ci/run.sh | 5 +++-- library/compiler-builtins/src/bin/intrinsics.rs | 4 +--- library/compiler-builtins/src/float/mod.rs | 1 + library/compiler-builtins/src/float/pow.rs | 2 -- library/compiler-builtins/src/int/sdiv.rs | 6 ++---- library/compiler-builtins/src/lib.rs | 17 +++++++++-------- 7 files changed, 16 insertions(+), 22 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index eefb0b26663de..c198d9f3ccb69 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -25,7 +25,4 @@ compiler-rt = { path = "compiler-rt" } c = [] weak = ["rlibc/weak"] -[profile.dev] -debug-assertions = false - [workspace] diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index df27e35626fe1..0ac9d683b3f57 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -29,13 +29,14 @@ case $1 in esac # Verify that there are no undefined symbols to `panic` within our implementations +# TODO(#79) fix the undefined references problem for debug-assertions+lto case $1 in thumb*) - xargo rustc --features c --target $1 --bin intrinsics -- -C lto + RUSTFLAGS="-C debug-assertions=no" xargo rustc --features c --target $1 --bin intrinsics -- -C lto xargo rustc --features c --target $1 --bin intrinsics --release -- -C lto ;; *) - cargo rustc --features c --target $1 --bin intrinsics -- -C lto + RUSTFLAGS="-C debug-assertions=no" cargo rustc --features c --target $1 --bin intrinsics -- -C lto cargo rustc --features c --target $1 --bin intrinsics --release -- -C lto ;; esac diff --git a/library/compiler-builtins/src/bin/intrinsics.rs b/library/compiler-builtins/src/bin/intrinsics.rs index 591765a477ebc..ca01a9d0d8501 100644 --- a/library/compiler-builtins/src/bin/intrinsics.rs +++ b/library/compiler-builtins/src/bin/intrinsics.rs @@ -308,9 +308,7 @@ fn run() { // We use volatile load/stores to prevent LLVM from optimizing away the intrinsics during LTO macro_rules! arg { () => { - unsafe { - ptr::read_volatile(0x0 as *const _) - } + ptr::read_volatile(0x0 as *const _) } } diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 8bd574deb1718..7dc084d4f7955 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,4 +1,5 @@ use core::mem; +#[cfg(test)] use core::fmt; pub mod add; diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index c02c76f770951..838805f949207 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -1,5 +1,3 @@ -use core::intrinsics; - macro_rules! pow { ($intrinsic:ident: $fty:ty, $ity:ident) => { /// Returns `a` raised to the power `b` diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 6f96b800bd89f..a1d119f3b1b54 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -1,5 +1,3 @@ -use core::intrinsics; - use int::Int; macro_rules! div { @@ -13,7 +11,7 @@ macro_rules! div { let b = (b ^ s_b) - s_b; let s = s_a ^ s_b; - let r = udiv!((a as $uty), (b as $uty)); + let r = udiv!(a as $uty, b as $uty); (r as $ty ^ s) - s } } @@ -29,7 +27,7 @@ macro_rules! mod_ { let s = a >> (<$ty>::bits() - 1); let a = (a ^ s) - s; - let r = urem!((a as $uty), (b as $uty)); + let r = urem!(a as $uty, b as $uty); (r as $ty ^ s) - s } } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 351be02f78ff1..f5a12afd2208f 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -13,6 +13,7 @@ // NOTE cfg(all(feature = "c", ..)) indicate that compiler-rt provides an arch optimized // implementation of that intrinsic and we'll prefer to use that +// TODO(rust-lang/rust#37029) use e.g. checked_div(_).unwrap_or_else(|| abort()) macro_rules! udiv { ($a:expr, $b:expr) => { unsafe { @@ -20,9 +21,9 @@ macro_rules! udiv { let b = $b; if b == 0 { - intrinsics::abort() + ::core::intrinsics::abort() } else { - intrinsics::unchecked_div(a, b) + ::core::intrinsics::unchecked_div(a, b) } } } @@ -35,9 +36,9 @@ macro_rules! sdiv { let b = $b; if b == 0 || (b == -1 && a == $sty::min_value()) { - intrinsics::abort() + ::core::intrinsics::abort() } else { - intrinsics::unchecked_div(a, b) + ::core::intrinsics::unchecked_div(a, b) } } } @@ -50,9 +51,9 @@ macro_rules! urem { let b = $b; if b == 0 { - intrinsics::abort() + ::core::intrinsics::abort() } else { - intrinsics::unchecked_rem(a, b) + ::core::intrinsics::unchecked_rem(a, b) } } } @@ -65,9 +66,9 @@ macro_rules! srem { let b = $b; if b == 0 || (b == -1 && a == $sty::min_value()) { - intrinsics::abort() + ::core::intrinsics::abort() } else { - intrinsics::unchecked_rem(a, b) + ::core::intrinsics::unchecked_rem(a, b) } } } From 2056d001cfd666a4fb1c5bd8d24df5d1d04b2c96 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 7 Oct 2016 18:26:21 -0500 Subject: [PATCH 0194/4206] use test::black_box instead of ptr::*_volatile both prevent LLVM from optimizing away the intrinsics but the former doesn't produce an `intrinsics` binary that segfaults --- library/compiler-builtins/ci/run.sh | 2 +- .../compiler-builtins/src/bin/intrinsics.rs | 113 ++++++++---------- 2 files changed, 53 insertions(+), 62 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 0ac9d683b3f57..3846049ea134d 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -32,7 +32,7 @@ esac # TODO(#79) fix the undefined references problem for debug-assertions+lto case $1 in thumb*) - RUSTFLAGS="-C debug-assertions=no" xargo rustc --features c --target $1 --bin intrinsics -- -C lto + RUSTFLAGS="-C debug-assertions=no -C link-arg=-nostartfiles" xargo rustc --features c --target $1 --bin intrinsics -- -C lto xargo rustc --features c --target $1 --bin intrinsics --release -- -C lto ;; *) diff --git a/library/compiler-builtins/src/bin/intrinsics.rs b/library/compiler-builtins/src/bin/intrinsics.rs index ca01a9d0d8501..e11e415cc75cc 100644 --- a/library/compiler-builtins/src/bin/intrinsics.rs +++ b/library/compiler-builtins/src/bin/intrinsics.rs @@ -4,13 +4,14 @@ // to link due to the missing intrinsic (symbol). #![allow(unused_features)] +#![cfg_attr(thumb, no_main)] #![deny(dead_code)] +#![feature(asm)] #![feature(core_float)] #![feature(lang_items)] #![feature(libc)] #![feature(start)] #![no_std] -#![cfg_attr(thumb, no_main)] #[cfg(not(thumb))] extern crate libc; @@ -302,68 +303,58 @@ mod intrinsics { #[cfg(feature = "c")] fn run() { - use core::ptr; use intrinsics::*; - // We use volatile load/stores to prevent LLVM from optimizing away the intrinsics during LTO - macro_rules! arg { - () => { - ptr::read_volatile(0x0 as *const _) - } - } - - macro_rules! ret { - ($e:expr) => { - unsafe { - ptr::write_volatile(0x0 as *mut _, $e) - } - } - } - - ret!(aeabi_d2f(arg!())); - ret!(aeabi_d2i(arg!())); - ret!(aeabi_d2l(arg!())); - ret!(aeabi_d2uiz(arg!())); - ret!(aeabi_d2ulz(arg!())); - ret!(aeabi_dadd(arg!(), arg!())); - ret!(aeabi_dcmpeq(arg!(), arg!())); - ret!(aeabi_dcmpgt(arg!(), arg!())); - ret!(aeabi_dcmplt(arg!(), arg!())); - ret!(aeabi_ddiv(arg!(), arg!())); - ret!(aeabi_dmul(arg!(), arg!())); - ret!(aeabi_dsub(arg!(), arg!())); - ret!(aeabi_f2d(arg!())); - ret!(aeabi_f2iz(arg!())); - ret!(aeabi_f2lz(arg!())); - ret!(aeabi_f2uiz(arg!())); - ret!(aeabi_f2ulz(arg!())); - ret!(aeabi_fadd(arg!(), arg!())); - ret!(aeabi_fcmpeq(arg!(), arg!())); - ret!(aeabi_fcmpgt(arg!(), arg!())); - ret!(aeabi_fcmplt(arg!(), arg!())); - ret!(aeabi_fdiv(arg!(), arg!())); - ret!(aeabi_fmul(arg!(), arg!())); - ret!(aeabi_fsub(arg!(), arg!())); - ret!(aeabi_i2d(arg!())); - ret!(aeabi_i2f(arg!())); - ret!(aeabi_idiv(arg!(), arg!())); - ret!(aeabi_idivmod(arg!(), arg!())); - ret!(aeabi_l2d(arg!())); - ret!(aeabi_l2f(arg!())); - ret!(aeabi_ldivmod(arg!(), arg!())); - ret!(aeabi_lmul(arg!(), arg!())); - ret!(aeabi_ui2d(arg!())); - ret!(aeabi_ui2f(arg!())); - ret!(aeabi_uidiv(arg!(), arg!())); - ret!(aeabi_uidivmod(arg!(), arg!())); - ret!(aeabi_ul2d(arg!())); - ret!(aeabi_ul2f(arg!())); - ret!(aeabi_uldivmod(arg!(), arg!())); - ret!(moddi3(arg!(), arg!())); - ret!(mulodi4(arg!(), arg!())); - ret!(powidf2(arg!(), arg!())); - ret!(powisf2(arg!(), arg!())); - ret!(umoddi3(arg!(), arg!())); + // A copy of "test::black_box". Used to prevent LLVM from optimizing away the intrinsics during LTO + fn bb(dummy: T) -> T { + unsafe { asm!("" : : "r"(&dummy)) } + dummy + } + + bb(aeabi_d2f(bb(2.))); + bb(aeabi_d2i(bb(2.))); + bb(aeabi_d2l(bb(2.))); + bb(aeabi_d2uiz(bb(2.))); + bb(aeabi_d2ulz(bb(2.))); + bb(aeabi_dadd(bb(2.), bb(3.))); + bb(aeabi_dcmpeq(bb(2.), bb(3.))); + bb(aeabi_dcmpgt(bb(2.), bb(3.))); + bb(aeabi_dcmplt(bb(2.), bb(3.))); + bb(aeabi_ddiv(bb(2.), bb(3.))); + bb(aeabi_dmul(bb(2.), bb(3.))); + bb(aeabi_dsub(bb(2.), bb(3.))); + bb(aeabi_f2d(bb(2.))); + bb(aeabi_f2iz(bb(2.))); + bb(aeabi_f2lz(bb(2.))); + bb(aeabi_f2uiz(bb(2.))); + bb(aeabi_f2ulz(bb(2.))); + bb(aeabi_fadd(bb(2.), bb(3.))); + bb(aeabi_fcmpeq(bb(2.), bb(3.))); + bb(aeabi_fcmpgt(bb(2.), bb(3.))); + bb(aeabi_fcmplt(bb(2.), bb(3.))); + bb(aeabi_fdiv(bb(2.), bb(3.))); + bb(aeabi_fmul(bb(2.), bb(3.))); + bb(aeabi_fsub(bb(2.), bb(3.))); + bb(aeabi_i2d(bb(2))); + bb(aeabi_i2f(bb(2))); + bb(aeabi_idiv(bb(2), bb(3))); + bb(aeabi_idivmod(bb(2), bb(3))); + bb(aeabi_l2d(bb(2))); + bb(aeabi_l2f(bb(2))); + bb(aeabi_ldivmod(bb(2), bb(3))); + bb(aeabi_lmul(bb(2), bb(3))); + bb(aeabi_ui2d(bb(2))); + bb(aeabi_ui2f(bb(2))); + bb(aeabi_uidiv(bb(2), bb(3))); + bb(aeabi_uidivmod(bb(2), bb(3))); + bb(aeabi_ul2d(bb(2))); + bb(aeabi_ul2f(bb(2))); + bb(aeabi_uldivmod(bb(2), bb(3))); + bb(moddi3(bb(2), bb(3))); + bb(mulodi4(bb(2), bb(3))); + bb(powidf2(bb(2.), bb(3))); + bb(powisf2(bb(2.), bb(3))); + bb(umoddi3(bb(2), bb(3))); } #[cfg(all(feature = "c", not(thumb)))] From 8692e64db9d862e48e8c1b0d4efc76aa256168f6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Oct 2016 16:18:18 -0500 Subject: [PATCH 0195/4206] add a rustbuild cargo feature for integration with rust-lang/rust --- library/compiler-builtins/build.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 046085a9d07c3..c0fdb52ec8a43 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -407,8 +407,15 @@ fn main() { sources.remove(&["aeabi_cdcmp", "aeabi_cfcmp"]); } + let root = if env::var_os("CARGO_FEATURE_RUSTBUILD").is_some() { + Path::new("../../libcompiler_builtins") + } else { + Path::new(".") + }; + + let src_dir = root.join("compiler-rt/compiler-rt-cdylib/compiler-rt/lib/builtins"); for src in sources.map.values() { - let src = Path::new("compiler-rt/compiler-rt-cdylib/compiler-rt/lib/builtins").join(src); + let src = src_dir.join(src); cfg.file(&src); println!("cargo:rerun-if-changed={}", src.display()); } From 5f5c973cbe7fd642172081a10e12174235535053 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Oct 2016 16:43:38 -0500 Subject: [PATCH 0196/4206] set crate_name and crate_type in src/lib.rs --- library/compiler-builtins/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index f5a12afd2208f..6eaf2b1e7982c 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,3 +1,5 @@ +#![crate_name = "compiler_builtins"] +#![crate_type = "rlib"] #![feature(asm)] #![feature(core_intrinsics)] #![feature(linkage)] From 622a760d91db5f41fe381757d466d2c88c582b8b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Oct 2016 16:45:24 -0500 Subject: [PATCH 0197/4206] add the compiler_builtins feature to src/lib.rs --- library/compiler-builtins/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 6eaf2b1e7982c..3adddd5cd17db 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,13 +1,13 @@ +#![cfg_attr(not(test), no_std)] +#![compiler_builtins] #![crate_name = "compiler_builtins"] #![crate_type = "rlib"] #![feature(asm)] +#![feature(compiler_builtins)] #![feature(core_intrinsics)] #![feature(linkage)] #![feature(naked_functions)] -#![cfg_attr(not(test), no_std)] #![no_builtins] -// TODO(rust-lang/rust#35021) uncomment when that PR lands -// #![feature(rustc_builtins)] // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. From 14c32a0369d72fb2d52832610b59b1df740e728a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Oct 2016 19:05:21 -0500 Subject: [PATCH 0198/4206] rename to compiler_builtins, add rust-lang/rust-ish crate attributes --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/src/lib.rs | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index c198d9f3ccb69..6455a6ef3ab0f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] build = "build.rs" -name = "rustc_builtins" +name = "compiler_builtins" version = "0.1.0" [build-dependencies] diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 3adddd5cd17db..bcc56e535848a 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,13 +1,23 @@ +#![cfg_attr(not(stage0), deny(warnings))] #![cfg_attr(not(test), no_std)] #![compiler_builtins] #![crate_name = "compiler_builtins"] #![crate_type = "rlib"] +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://doc.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/nightly/", + html_playground_url = "https://play.rust-lang.org/", + test(attr(deny(warnings))))] #![feature(asm)] #![feature(compiler_builtins)] #![feature(core_intrinsics)] #![feature(linkage)] #![feature(naked_functions)] +#![feature(staged_api)] #![no_builtins] +#![unstable(feature = "compiler_builtins", + reason = "Compiler builtins. Will never become stable.", + issue = "0")] // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. From 3fe4f1c687afb8d1195124e64caa09ea325f53f0 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Oct 2016 19:45:34 -0500 Subject: [PATCH 0199/4206] fix warnings --- library/compiler-builtins/ci/run.sh | 4 +++- library/compiler-builtins/src/bin/intrinsics.rs | 3 ++- library/compiler-builtins/src/int/sdiv.rs | 7 ++++++- library/compiler-builtins/src/int/udiv.rs | 16 ++++++++++++++-- library/compiler-builtins/src/lib.rs | 4 ++-- 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 3846049ea134d..90441bdc9345c 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -1,4 +1,6 @@ -set -e +set -ex + +export RUST_BACKTRACE=1 # Test our implementation case $1 in diff --git a/library/compiler-builtins/src/bin/intrinsics.rs b/library/compiler-builtins/src/bin/intrinsics.rs index e11e415cc75cc..db6d7d93d6456 100644 --- a/library/compiler-builtins/src/bin/intrinsics.rs +++ b/library/compiler-builtins/src/bin/intrinsics.rs @@ -7,6 +7,7 @@ #![cfg_attr(thumb, no_main)] #![deny(dead_code)] #![feature(asm)] +#![feature(compiler_builtins_lib)] #![feature(core_float)] #![feature(lang_items)] #![feature(libc)] @@ -15,7 +16,7 @@ #[cfg(not(thumb))] extern crate libc; -extern crate rustc_builtins; +extern crate compiler_builtins; // NOTE cfg(not(thumbv6m)) means that the operation is not supported on ARMv6-M at all. Not even // compiler-rt provides a C/assembly implementation. diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index a1d119f3b1b54..b54132290afb5 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -43,7 +43,12 @@ macro_rules! divmod { fn $div(a: $ty, b: $ty) -> $ty; } - let r = unsafe { $div(a, b) }; + let r = match () { + #[cfg(not(all(feature = "c", any(target_arch = "x86"))))] + () => $div(a, b), + #[cfg(all(feature = "c", any(target_arch = "x86")))] + () => unsafe { $div(a, b) }, + }; *rem = a - (r * b); r } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 999dcec05528b..4a14d3ce99cb2 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -65,7 +65,14 @@ pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { fn __udivsi3(n: u32, d: u32) -> u32; } - n - unsafe { __udivsi3(n, d) * d } + let q = match () { + #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios")))] + () => unsafe { __udivsi3(n, d) }, + #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] + () => __udivsi3(n, d), + }; + + n - q * d } /// Returns `n / d` and sets `*rem = n % d` @@ -77,7 +84,12 @@ pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { fn __udivsi3(n: u32, d: u32) -> u32; } - let q = unsafe { __udivsi3(n, d) }; + let q = match () { + #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios")))] + () => unsafe { __udivsi3(n, d) }, + #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] + () => __udivsi3(n, d), + }; if let Some(rem) = rem { *rem = n - (q * d); } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index bcc56e535848a..0efb20b5dec89 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,6 +1,6 @@ #![cfg_attr(not(stage0), deny(warnings))] #![cfg_attr(not(test), no_std)] -#![compiler_builtins] +#![cfg_attr(rustbuild, compiler_builtins)] #![crate_name = "compiler_builtins"] #![crate_type = "rlib"] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", @@ -15,7 +15,7 @@ #![feature(naked_functions)] #![feature(staged_api)] #![no_builtins] -#![unstable(feature = "compiler_builtins", +#![unstable(feature = "compiler_builtins_lib", reason = "Compiler builtins. Will never become stable.", issue = "0")] From 77b5865b0471e175ce60feb15eec22c2f4594b02 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Oct 2016 20:21:11 -0500 Subject: [PATCH 0200/4206] fix more warnings --- library/compiler-builtins/src/int/mul.rs | 4 +++- library/compiler-builtins/src/int/shift.rs | 1 + library/compiler-builtins/src/int/udiv.rs | 4 +++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index e04e86ccb80b9..db9f0d9e0c692 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -1,4 +1,6 @@ -use int::{Int, LargeInt}; +#[cfg(not(all(feature = "c", target_arch = "x86")))] +use int::LargeInt; +use int::Int; macro_rules! mul { ($intrinsic:ident: $ty:ty) => { diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 995f8d609256f..9338f07ce7e4c 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -1,3 +1,4 @@ +#[cfg(not(all(feature = "c", target_arch = "x86")))] use int::{Int, LargeInt}; macro_rules! ashl { diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 4a14d3ce99cb2..b60c875178430 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -1,4 +1,4 @@ -use core::{intrinsics, mem}; +use core::intrinsics; use int::{Int, LargeInt}; /// Returns `n / d` @@ -107,6 +107,8 @@ pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { #[cfg(not(all(feature = "c", target_arch = "x86")))] #[cfg_attr(not(test), no_mangle)] pub extern "C" fn __umoddi3(a: u64, b: u64) -> u64 { + use core::mem; + let mut rem = unsafe { mem::uninitialized() }; __udivmoddi4(a, b, Some(&mut rem)); rem From fcb19597cfd266ede3e43bcee1c4f74169f9031e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Oct 2016 20:52:49 -0500 Subject: [PATCH 0201/4206] ci/run.sh: remove debug stuff --- library/compiler-builtins/ci/run.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 90441bdc9345c..3846049ea134d 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -1,6 +1,4 @@ -set -ex - -export RUST_BACKTRACE=1 +set -e # Test our implementation case $1 in From 7928431aea83ff9d43d9e8bfaea70c9734b7fbad Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 12 Oct 2016 17:38:14 +0000 Subject: [PATCH 0202/4206] Correct the license to that of upstream compiler-rt As this is a derivative work we must maintain the same license terms. --- library/compiler-builtins/LICENSE-APACHE | 201 ----------------------- library/compiler-builtins/LICENSE-MIT | 25 --- library/compiler-builtins/LICENSE.TXT | 91 ++++++++++ library/compiler-builtins/README.md | 11 +- 4 files changed, 96 insertions(+), 232 deletions(-) delete mode 100644 library/compiler-builtins/LICENSE-APACHE delete mode 100644 library/compiler-builtins/LICENSE-MIT create mode 100644 library/compiler-builtins/LICENSE.TXT diff --git a/library/compiler-builtins/LICENSE-APACHE b/library/compiler-builtins/LICENSE-APACHE deleted file mode 100644 index 16fe87b06e802..0000000000000 --- a/library/compiler-builtins/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/library/compiler-builtins/LICENSE-MIT b/library/compiler-builtins/LICENSE-MIT deleted file mode 100644 index a43445e6cd1b9..0000000000000 --- a/library/compiler-builtins/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2016 Jorge Aparicio - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/library/compiler-builtins/LICENSE.TXT b/library/compiler-builtins/LICENSE.TXT new file mode 100644 index 0000000000000..92bbe113ab2a1 --- /dev/null +++ b/library/compiler-builtins/LICENSE.TXT @@ -0,0 +1,91 @@ +============================================================================== +compiler-builtins License +============================================================================== + +The compiler-builtins crate is dual licensed under both the University of +Illinois "BSD-Like" license and the MIT license. As a user of this code you may +choose to use it under either license. As a contributor, you agree to allow +your code to be used under both. + +Full text of the relevant licenses is included below. + +============================================================================== + +University of Illinois/NCSA +Open Source License + +Copyright (c) 2009-2016 by the contributors listed in CREDITS.TXT + +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== + +Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +============================================================================== +Copyrights and Licenses for Third Party Software Distributed with LLVM: +============================================================================== +The LLVM software contains code written by third parties. Such software will +have its own individual LICENSE.TXT file in the directory in which it appears. +This file will describe the copyrights, license, and restrictions which apply +to that code. + +The disclaimer of warranty in the University of Illinois Open Source License +applies to all code in the LLVM Distribution, and nothing in any of the +other licenses gives permission to use the names of the LLVM Team or the +University of Illinois to endorse or promote products derived from this +Software. + diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 20b153d7dc192..0a5b33a4a7c95 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -371,13 +371,12 @@ Floating-point implementations of builtins that are only called from soft-float ## License -Licensed under either of +The compiler-builtins crate is dual licensed under both the University of +Illinois "BSD-Like" license and the MIT license. As a user of this code you may +choose to use it under either license. As a contributor, you agree to allow +your code to be used under both. -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. +Full text of the relevant licenses is in LICENSE.TXT. ### Contribution From b4f4913e6baa5652d950143c5f716bafc36ce38b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 13 Oct 2016 20:50:30 -0500 Subject: [PATCH 0203/4206] README: remove the Contribution sub-section which still referred to the Apache-2 license and is now deprecated by the updated License section cc @brson --- library/compiler-builtins/README.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 0a5b33a4a7c95..aab37939b81eb 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -377,9 +377,3 @@ choose to use it under either license. As a contributor, you agree to allow your code to be used under both. Full text of the relevant licenses is in LICENSE.TXT. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the -work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any -additional terms or conditions. From ab4d5e62fbc6ed60074918be045d0fba727f5f30 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 14 Oct 2016 09:59:21 -0500 Subject: [PATCH 0204/4206] fix the powerpc64le target by selecting a CPU that's compatible with the instructions that `rustc` generates --- .../ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile | 1 + library/compiler-builtins/ci/run.sh | 10 ++-------- library/compiler-builtins/src/bin/intrinsics.rs | 2 +- 3 files changed, 4 insertions(+), 9 deletions(-) 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 bd0a182a88659..ba1b3c287bf96 100644 --- a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile @@ -7,5 +7,6 @@ RUN apt-get install -y --no-install-recommends \ qemu-system-ppc ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER=powerpc64le-linux-gnu-gcc \ + QEMU_CPU=POWER8 \ QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 3846049ea134d..0159e2389130d 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -6,12 +6,6 @@ case $1 in xargo build --target $1 xargo build --target $1 --release ;; - # QEMU crashes even when executing the simplest cross compiled C program: - # `int main() { return 0; }` - powerpc64le-unknown-linux-gnu) - cargo test --target $1 --no-run - cargo test --target $1 --no-run --release - ;; *) cargo test --target $1 cargo test --target $1 --release @@ -69,9 +63,9 @@ esac # NOTE On i586, It's normal that the get_pc_thunk symbol appears several times so ignore it if [ $TRAVIS_OS_NAME = osx ]; then - path=target/${1}/debug/librustc_builtins.rlib + path=target/${1}/debug/libcompiler_builtins.rlib else - path=/target/${1}/debug/librustc_builtins.rlib + path=/target/${1}/debug/libcompiler_builtins.rlib fi stdout=$($PREFIX$NM -g --defined-only $path) diff --git a/library/compiler-builtins/src/bin/intrinsics.rs b/library/compiler-builtins/src/bin/intrinsics.rs index db6d7d93d6456..5a4a34503cc6f 100644 --- a/library/compiler-builtins/src/bin/intrinsics.rs +++ b/library/compiler-builtins/src/bin/intrinsics.rs @@ -1,5 +1,5 @@ // By compiling this file we check that all the intrinsics we care about continue to be provided by -// the `rustc_builtins` crate regardless of the changes we make to it. If we, by mistake, stop +// 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). From 8ab8bd78899706af5c97cae2a31f2f12aa0844bf Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 14 Oct 2016 11:44:45 -0700 Subject: [PATCH 0205/4206] Update webhook url --- library/compiler-builtins/.travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 6e159cc211dfc..96b11376377c7 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -59,4 +59,4 @@ branches: notifications: email: on_success: never - webhooks: https://homu.herokuapp.com/travis + webhooks: https://buildbot.rust-lang.org/homu/travis From 7f70040462b7a9c491d21e8911c65d41600dca79 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 14 Oct 2016 11:58:02 -0700 Subject: [PATCH 0206/4206] Update CI configs * Run on the master branch (to get previews) * Pass --target on AppVeyor (oops) * Use the current nightly for arm (I think that bug is fixed) --- library/compiler-builtins/.travis.yml | 7 ------- library/compiler-builtins/appveyor.yml | 13 ++++--------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 6e159cc211dfc..e53b678fb1efc 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -9,8 +9,6 @@ matrix: include: - env: TARGET=aarch64-unknown-linux-gnu - env: TARGET=arm-unknown-linux-gnueabi - # FIXME(rust-lang/rust#36518) - rust: nightly-2016-09-21 - env: TARGET=arm-unknown-linux-gnueabihf - env: TARGET=armv7-unknown-linux-gnueabihf - env: TARGET=i586-unknown-linux-gnu @@ -51,11 +49,6 @@ script: # Travis can't cache files that are not readable by "others" - chmod -R a+r $HOME/.cargo -branches: - only: - - auto - - try - notifications: email: on_success: never diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 52afc97ef5e5e..f27347c338de7 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -14,12 +14,7 @@ install: build: false test_script: - - cargo build - - cargo build --release - - cargo test - - cargo test --release - -branches: - only: - - auto - - try + - cargo build --target %TARGET% + - cargo build --release --target %TARGET% + - cargo test --target %TARGET% + - cargo test --release --target %TARGET% From b92c6caa068f2862af471dfe8fcb7f8053054ee7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 14 Oct 2016 15:45:25 -0700 Subject: [PATCH 0207/4206] More small updates to the README --- library/compiler-builtins/README.md | 32 ++++++++++++++++++----------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index aab37939b81eb..1eee9eb0d696f 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -1,11 +1,8 @@ -[![AppVeyor][appveyor]](https://ci.appveyor.com/project/japaric/rustc-builtins) -[![Travis][travis]](https://travis-ci.org/japaric/rustc-builtins) - -[appveyor]: https://ci.appveyor.com/api/projects/status/mofi55r3px9pv3o7?svg=true -[travis]: https://travis-ci.org/japaric/rustc-builtins.svg?branch=master - # `rustc-builtins` +[![Build status](https://ci.appveyor.com/api/projects/status/eusnjps5ui3d305p?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/compiler-builtins) +[![Build Status](https://travis-ci.org/rust-lang-nursery/compiler-builtins.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/compiler-builtins) + > [WIP] Porting `compiler-rt` intrinsics to Rust See [rust-lang/rust#35437][0]. @@ -23,15 +20,26 @@ this crate ends up, as long as it's there): ``` toml [dependencies] -rustc-builtins = { git = "https://github.com/japaric/rustc-builtins" } +compiler-builtins = { git = "https://github.com/rustc-lang-nursery/compiler-builtins" } ``` -If you still get an "undefined reference to $INTRINSIC" error after that change, that means that we -haven't ported `$INTRINSIC` to Rust yet! Please open [an issue] with the name of the intrinsic and -the LLVM triple (e.g. thumbv7m-none-eabi) of the target you are using. That way we can prioritize +If you still get an "undefined reference to $INTRINSIC" error after that change, +that means that we haven't ported `$INTRINSIC` to Rust yet! Please open [an +issue] with the name of the intrinsic and the LLVM triple (e.g. +thumbv7m-none-eabi) of the target you are using. That way we can prioritize porting that particular intrinsic. -[an issue]: https://github.com/japaric/rustc-builtins/issues +If you've got a C compiler available for your target then while we implement +this intrinsic you can temporarily enable a fallback to the actual compiler-rt +implementation as well for unimplemented intrinsics: + +```toml +[dependencies.compiler-builtins] +git = "https://github.com/rustc-lang-nursery/compiler-builtins" +features = ["c"] +``` + +[an issue]: https://github.com/rust-lang-nursery/compiler-builtins/issues ## Contributing @@ -45,7 +53,7 @@ porting that particular intrinsic. [1]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/test/builtins/Unit [2]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/lib/builtins -[3]: https://travis-ci.org/japaric/rustc-builtins +[3]: https://travis-ci.org/rust-lang-nursery/compiler-builtins ### Porting Reminders From 04639c2f5471ebd8707224eb132defda5e65ee58 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 14 Oct 2016 19:59:00 -0500 Subject: [PATCH 0208/4206] update the title as well --- library/compiler-builtins/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 1eee9eb0d696f..f2b97ed5e3e31 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -1,4 +1,4 @@ -# `rustc-builtins` +# `compiler-builtins` [![Build status](https://ci.appveyor.com/api/projects/status/eusnjps5ui3d305p?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/compiler-builtins) [![Build Status](https://travis-ci.org/rust-lang-nursery/compiler-builtins.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/compiler-builtins) From 533c78afaf358e7f276ca0991b2529f0d44f905f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 14 Oct 2016 20:26:59 -0500 Subject: [PATCH 0209/4206] test the mips64 targets --- library/compiler-builtins/.travis.yml | 2 ++ .../mips64-unknown-linux-gnuabi64/Dockerfile | 14 ++++++++++++++ .../mips64el-unknown-linux-gnuabi64/Dockerfile | 13 +++++++++++++ 3 files changed, 29 insertions(+) create mode 100644 library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 6e159cc211dfc..776c5269707cd 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -18,6 +18,8 @@ matrix: os: osx - env: TARGET=i686-unknown-linux-gnu - env: TARGET=mips-unknown-linux-gnu + - env: TARGET=mips64-unknown-linux-gnuabi64 + - env: TARGET=mips64el-unknown-linux-gnuabi64 - env: TARGET=mipsel-unknown-linux-gnu - env: TARGET=powerpc-unknown-linux-gnu - env: TARGET=powerpc64-unknown-linux-gnu diff --git a/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile new file mode 100644 index 0000000000000..92b1d93b8fdca --- /dev/null +++ b/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile @@ -0,0 +1,14 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + ca-certificates \ + gcc \ + gcc-mips64-linux-gnuabi64 \ + libc6-dev \ + libc6-dev-mips64-cross \ + qemu-user-static +RUN apt-get install -y --no-install-recommends qemu-system-mips +ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER=mips64-linux-gnuabi64-gcc \ + CC_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-gcc \ + QEMU_LD_PREFIX=/usr/mips64-linux-gnuabi64 \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile new file mode 100644 index 0000000000000..adba7783fa0f1 --- /dev/null +++ b/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile @@ -0,0 +1,13 @@ +FROM ubuntu:16.04 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + ca-certificates \ + gcc \ + gcc-mips64el-linux-gnuabi64 \ + libc6-dev \ + libc6-dev-mips64el-cross \ + qemu-user-static +ENV CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_LINKER=mips64el-linux-gnuabi64-gcc \ + CC_mips64el_unknown_linux_gnuabi64=mips64el-linux-gnuabi64-gcc \ + QEMU_LD_PREFIX=/usr/mips64el-linux-gnuabi64 \ + RUST_TEST_THREADS=1 From f511f6775224b09eccd50553c5ae83aa2e2b3cb2 Mon Sep 17 00:00:00 2001 From: Phaiax Date: Sat, 15 Oct 2016 19:18:12 +0200 Subject: [PATCH 0210/4206] Fix url in readme --- library/compiler-builtins/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index f2b97ed5e3e31..54e8b61859673 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -20,7 +20,7 @@ this crate ends up, as long as it's there): ``` toml [dependencies] -compiler-builtins = { git = "https://github.com/rustc-lang-nursery/compiler-builtins" } +compiler_builtins = { git = "https://github.com/rust-lang-nursery/compiler-builtins" } ``` If you still get an "undefined reference to $INTRINSIC" error after that change, @@ -34,8 +34,8 @@ this intrinsic you can temporarily enable a fallback to the actual compiler-rt implementation as well for unimplemented intrinsics: ```toml -[dependencies.compiler-builtins] -git = "https://github.com/rustc-lang-nursery/compiler-builtins" +[dependencies.compiler_builtins] +git = "https://github.com/rust-lang-nursery/compiler-builtins" features = ["c"] ``` From 7ecc55fbefac06bea7fe2af37533f73e8bd8a381 Mon Sep 17 00:00:00 2001 From: Phaiax Date: Sat, 15 Oct 2016 20:35:38 +0200 Subject: [PATCH 0211/4206] Update gcc-rs dependency to 0.3.36 --- library/compiler-builtins/Cargo.toml | 2 +- .../compiler-rt/compiler-rt-cdylib/Cargo.toml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 6455a6ef3ab0f..58ce4513ca554 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -5,8 +5,8 @@ name = "compiler_builtins" version = "0.1.0" [build-dependencies] -gcc = "0.3.35" rustc-cfg = "0.2.0" +gcc = "0.3.36" [dependencies] diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml index 3c64d23d37e94..ec9c6af183154 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml @@ -8,4 +8,5 @@ build = "build.rs" crate-type = ["cdylib"] [build-dependencies] -gcc = "0.3" +gcc = "0.3.36" + From 53c19053e406a8462b9ecd276d8af18b7d976c5f Mon Sep 17 00:00:00 2001 From: Christopher Serr Date: Sun, 16 Oct 2016 13:53:31 +0200 Subject: [PATCH 0212/4206] Fix a few clippy warnings --- library/compiler-builtins/src/float/add.rs | 3 +- library/compiler-builtins/src/int/udiv.rs | 72 +++++++++++----------- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 243c391b56554..92ba8216fbd9a 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -175,7 +175,8 @@ macro_rules! add { // correct result in that case. if round_guard_sticky > 0x4 { result += one; } if round_guard_sticky == 0x4 { result += result & one; } - return (<$ty>::from_repr(result.0)); + + <$ty>::from_repr(result.0) } } } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index b60c875178430..3c5629e1a517e 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -191,49 +191,47 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { // 1 <= sr <= u32::bits() - 1 q = n << (u64::bits() - sr); r = n >> sr; - } else { - if d.high() == 0 { - // K X - // --- - // 0 K - if d.low().is_power_of_two() { - if let Some(rem) = rem { - *rem = u64::from(n.low() & (d.low() - 1)); - } - - if d.low() == 1 { - return n; - } else { - let sr = d.low().trailing_zeros(); - return n >> sr; - }; + } else if d.high() == 0 { + // K X + // --- + // 0 K + if d.low().is_power_of_two() { + if let Some(rem) = rem { + *rem = u64::from(n.low() & (d.low() - 1)); } - sr = 1 + u32::bits() + d.low().leading_zeros() - n.high().leading_zeros(); + if d.low() == 1 { + return n; + } else { + let sr = d.low().trailing_zeros(); + return n >> sr; + }; + } - // 2 <= sr <= u64::bits() - 1 - q = n << (u64::bits() - sr); - r = n >> sr; - } else { - // K X - // --- - // K K - sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); - - // D > N - if sr > u32::bits() - 1 { - if let Some(rem) = rem { - *rem = n; - } - return 0; - } + sr = 1 + u32::bits() + d.low().leading_zeros() - n.high().leading_zeros(); - sr += 1; + // 2 <= sr <= u64::bits() - 1 + q = n << (u64::bits() - sr); + r = n >> sr; + } else { + // K X + // --- + // K K + sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); - // 1 <= sr <= u32::bits() - q = n << (u64::bits() - sr); - r = n >> sr; + // D > N + if sr > u32::bits() - 1 { + if let Some(rem) = rem { + *rem = n; + } + return 0; } + + sr += 1; + + // 1 <= sr <= u32::bits() + q = n << (u64::bits() - sr); + r = n >> sr; } // Not a special case From 1074677eb0a3ebb4273d811a199ca66bdb944831 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 19 Oct 2016 11:19:06 -0500 Subject: [PATCH 0213/4206] mention that 'extern crate compiler_builtins' must be used in some crate that's part of the dependency graph of the crate one's building. --- library/compiler-builtins/README.md | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 54e8b61859673..d66d88828bffe 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -11,18 +11,26 @@ See [rust-lang/rust#35437][0]. ## When and how to use this crate? -If you are working with a target that doesn't have binary releases of std available via rustup (this -probably means you are building the core crate yourself) and need compiler-rt intrinsics (i.e. you -are probably getting linker errors when building an executable: `undefined reference to -__aeabi_memcpy`), you can use this crate to get those intrinsics and solve the linker errors. To do -that, simply add this crate as a Cargo dependency (it doesn't matter where in the dependency graph -this crate ends up, as long as it's there): +If you are working with a target that doesn't have binary releases of std +available via rustup (this probably means you are building the core crate +yourself) and need compiler-rt intrinsics (i.e. you are probably getting linker +errors when building an executable: `undefined reference to __aeabi_memcpy`), +you can use this crate to get those intrinsics and solve the linker errors. To +do that, add this crate somewhere in the dependency graph of the crate you are +building: ``` toml +# Cargo.toml [dependencies] compiler_builtins = { git = "https://github.com/rust-lang-nursery/compiler-builtins" } ``` +``` rust +extern crate compiler_builtins; + +// ... +``` + If you still get an "undefined reference to $INTRINSIC" error after that change, that means that we haven't ported `$INTRINSIC` to Rust yet! Please open [an issue] with the name of the intrinsic and the LLVM triple (e.g. From 9b4553de1c2b3091240c39d4f46c669a07f8b38c Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Mon, 3 Oct 2016 11:58:16 -0500 Subject: [PATCH 0214/4206] Add float quickcheck --- library/compiler-builtins/build.rs | 4 +- library/compiler-builtins/src/float/add.rs | 113 +++------------------ library/compiler-builtins/src/float/mod.rs | 78 ++++++++------ library/compiler-builtins/src/float/pow.rs | 17 ++-- library/compiler-builtins/src/qc.rs | 57 +++++++++++ 5 files changed, 127 insertions(+), 142 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index c0fdb52ec8a43..9f7a8fdedb85f 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -424,8 +424,8 @@ fn main() { } // To filter away some flaky test (see src/float/add.rs for details) - if llvm_target.last() == Some(&"gnueabihf") { - println!("cargo:rustc-cfg=gnueabihf") + if llvm_target.last().unwrap().contains("gnueabi") { + println!("cargo:rustc-cfg=gnueabi") } // To compile intrinsics.rs for thumb targets, where there is no libc diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 92ba8216fbd9a..814b99b26c8d6 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -184,114 +184,27 @@ macro_rules! add { add!(__addsf3: f32); add!(__adddf3: f64); -#[cfg(test)] +// NOTE(cfg) for some reason, on arm-unknown-linux-gnueabi*, our implementation doesn't +// match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll +// just avoid testing against them on those targets. Do note that our implementation gives the +// correct answer; gcc_s and compiler-rt are incorrect in this case. +#[cfg(all(test, not(gnueabi)))] mod tests { use core::{f32, f64}; + use qc::{F32, F64}; - use float::{Float, FRepr}; - use qc::{U32, U64}; - - // TODO: Add F32/F64 to qc so that they print the right values (at the very least) check! { fn __addsf3(f: extern fn(f32, f32) -> f32, - a: U32, - b: U32) - -> Option > { - let (a, b) = (f32::from_repr(a.0), f32::from_repr(b.0)); - Some(FRepr(f(a, b))) + a: F32, + b: F32) + -> Option { + Some(F32(f(a.0, b.0))) } fn __adddf3(f: extern fn(f64, f64) -> f64, - a: U64, - b: U64) -> Option > { - let (a, b) = (f64::from_repr(a.0), f64::from_repr(b.0)); - Some(FRepr(f(a, b))) + a: F64, + b: F64) -> Option { + Some(F64(f(a.0, b.0))) } } - - // More tests for special float values - - #[test] - fn test_float_tiny_plus_tiny() { - let tiny = f32::from_repr(1); - let r = super::__addsf3(tiny, tiny); - assert!(r.eq_repr(tiny + tiny)); - } - - #[test] - fn test_double_tiny_plus_tiny() { - let tiny = f64::from_repr(1); - let r = super::__adddf3(tiny, tiny); - assert!(r.eq_repr(tiny + tiny)); - } - - #[test] - fn test_float_small_plus_small() { - let a = f32::from_repr(327); - let b = f32::from_repr(256); - let r = super::__addsf3(a, b); - assert!(r.eq_repr(a + b)); - } - - #[test] - fn test_double_small_plus_small() { - let a = f64::from_repr(327); - let b = f64::from_repr(256); - let r = super::__adddf3(a, b); - assert!(r.eq_repr(a + b)); - } - - #[test] - fn test_float_one_plus_one() { - let r = super::__addsf3(1f32, 1f32); - assert!(r.eq_repr(1f32 + 1f32)); - } - - #[test] - fn test_double_one_plus_one() { - let r = super::__adddf3(1f64, 1f64); - assert!(r.eq_repr(1f64 + 1f64)); - } - - #[test] - fn test_float_different_nan() { - let a = f32::from_repr(1); - let b = f32::from_repr(0b11111111100100010001001010101010); - let x = super::__addsf3(a, b); - let y = a + b; - assert!(x.eq_repr(y)); - } - - #[test] - fn test_double_different_nan() { - let a = f64::from_repr(1); - let b = f64::from_repr(0b1111111111110010001000100101010101001000101010000110100011101011); - let x = super::__adddf3(a, b); - let y = a + b; - assert!(x.eq_repr(y)); - } - - #[test] - fn test_float_nan() { - let r = super::__addsf3(f32::NAN, 1.23); - assert_eq!(r.repr(), f32::NAN.repr()); - } - - #[test] - fn test_double_nan() { - let r = super::__adddf3(f64::NAN, 1.23); - assert_eq!(r.repr(), f64::NAN.repr()); - } - - #[test] - fn test_float_inf() { - let r = super::__addsf3(f32::INFINITY, -123.4); - assert_eq!(r, f32::INFINITY); - } - - #[test] - fn test_double_inf() { - let r = super::__adddf3(f64::INFINITY, -123.4); - assert_eq!(r, f64::INFINITY); - } } diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 7dc084d4f7955..134c32dc7452f 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,6 +1,4 @@ use core::mem; -#[cfg(test)] -use core::fmt; pub mod add; pub mod pow; @@ -16,22 +14,41 @@ pub trait Float: Sized + Copy { /// Returns the bitwidth of the significand fn significand_bits() -> u32; + /// Returns the bitwidth of the exponent + fn exponent_bits() -> u32 { + Self::bits() - Self::significand_bits() - 1 + } + + /// Returns a mask for the sign bit + fn sign_mask() -> Self::Int; + + /// Returns a mask for the significand + fn significand_mask() -> Self::Int; + + /// Returns a mask for the exponent + fn exponent_mask() -> Self::Int; + /// Returns `self` transmuted to `Self::Int` fn repr(self) -> Self::Int; #[cfg(test)] /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be - /// represented in multiple different ways. This methods returns `true` if two NaNs are + /// represented in multiple different ways. This method returns `true` if two NaNs are /// compared. fn eq_repr(self, rhs: Self) -> bool; /// Returns a `Self::Int` transmuted back to `Self` fn from_repr(a: Self::Int) -> Self; + /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. + fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self; + /// Returns (normalized exponent, normalized significand) fn normalize(significand: Self::Int) -> (i32, Self::Int); } +// FIXME: Some of this can be removed if RFC Issue #1424 is resolved +// https://github.com/rust-lang/rfcs/issues/1424 impl Float for f32 { type Int = u32; fn bits() -> u32 { @@ -40,6 +57,15 @@ impl Float for f32 { fn significand_bits() -> u32 { 23 } + fn sign_mask() -> Self::Int { + 1 << (Self::bits() - 1) + } + fn significand_mask() -> Self::Int { + (1 << Self::significand_bits()) - 1 + } + fn exponent_mask() -> Self::Int { + !(Self::sign_mask() | Self::significand_mask()) + } fn repr(self) -> Self::Int { unsafe { mem::transmute(self) } } @@ -54,6 +80,11 @@ impl Float for f32 { fn from_repr(a: Self::Int) -> Self { unsafe { mem::transmute(a) } } + fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { + Self::from_repr(((sign as Self::Int) << (Self::bits() - 1)) | + ((exponent << Self::significand_bits()) & Self::exponent_mask()) | + (significand & Self::significand_mask())) + } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros() .wrapping_sub((1u32 << Self::significand_bits()).leading_zeros()); @@ -68,6 +99,15 @@ impl Float for f64 { fn significand_bits() -> u32 { 52 } + fn sign_mask() -> Self::Int { + 1 << (Self::bits() - 1) + } + fn significand_mask() -> Self::Int { + (1 << Self::significand_bits()) - 1 + } + fn exponent_mask() -> Self::Int { + !(Self::sign_mask() | Self::significand_mask()) + } fn repr(self) -> Self::Int { unsafe { mem::transmute(self) } } @@ -82,36 +122,14 @@ impl Float for f64 { fn from_repr(a: Self::Int) -> Self { unsafe { mem::transmute(a) } } + fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { + Self::from_repr(((sign as Self::Int) << (Self::bits() - 1)) | + ((exponent << Self::significand_bits()) & Self::exponent_mask()) | + (significand & Self::significand_mask())) + } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros() .wrapping_sub((1u64 << Self::significand_bits()).leading_zeros()); (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) } } - -// TODO: Move this to F32/F64 in qc.rs -#[cfg(test)] -#[derive(Copy, Clone)] -pub struct FRepr(F); - -#[cfg(test)] -impl PartialEq for FRepr { - fn eq(&self, other: &FRepr) -> bool { - // NOTE(cfg) for some reason, on hard float targets, our implementation doesn't - // match the output of its gcc_s counterpart. Until we investigate further, we'll - // just avoid testing against gcc_s on those targets. Do note that our - // implementation matches the output of the FPU instruction on *hard* float targets - // and matches its gcc_s counterpart on *soft* float targets. - if cfg!(gnueabihf) { - return true - } - self.0.eq_repr(other.0) - } -} - -#[cfg(test)] -impl fmt::Debug for FRepr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index 838805f949207..290d0f54d95bc 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -31,22 +31,19 @@ pow!(__powidf2: f64, i32); #[cfg(test)] mod tests { - use float::{Float, FRepr}; - use qc::{I32, U32, U64}; + use qc::{I32, F32, F64}; check! { fn __powisf2(f: extern fn(f32, i32) -> f32, - a: U32, - b: I32) -> Option > { - let (a, b) = (f32::from_repr(a.0), b.0); - Some(FRepr(f(a, b))) + a: F32, + b: I32) -> Option { + Some(F32(f(a.0, b.0))) } fn __powidf2(f: extern fn(f64, i32) -> f64, - a: U64, - b: I32) -> Option > { - let (a, b) = (f64::from_repr(a.0), b.0); - Some(FRepr(f(a, b))) + a: F64, + b: I32) -> Option { + Some(F64(f(a.0, b.0))) } } } diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs index f7696b58de59e..74fcb42c8592d 100644 --- a/library/compiler-builtins/src/qc.rs +++ b/library/compiler-builtins/src/qc.rs @@ -5,10 +5,12 @@ use std::boxed::Box; use std::fmt; +use core::{f32, f64}; use quickcheck::{Arbitrary, Gen}; use int::LargeInt; +use float::Float; // Generates values in the full range of the integer type macro_rules! arbitrary { @@ -143,6 +145,61 @@ macro_rules! arbitrary_large { arbitrary_large!(I64: i64); arbitrary_large!(U64: u64); +macro_rules! arbitrary_float { + ($TY:ident : $ty:ident) => { + #[derive(Clone, Copy)] + pub struct $TY(pub $ty); + + impl Arbitrary for $TY { + fn arbitrary(g: &mut G) -> $TY + where G: Gen + { + let special = [ + -0.0, 0.0, $ty::NAN, $ty::INFINITY, -$ty::INFINITY + ]; + + if g.gen_weighted_bool(10) { // Random special case + $TY(*g.choose(&special).unwrap()) + } else if g.gen_weighted_bool(10) { // NaN variants + let sign: bool = g.gen(); + let exponent: <$ty as Float>::Int = g.gen(); + let significand: <$ty as Float>::Int = 0; + $TY($ty::from_parts(sign, exponent, significand)) + } else if g.gen() { // Denormalized + let sign: bool = g.gen(); + let exponent: <$ty as Float>::Int = 0; + let significand: <$ty as Float>::Int = g.gen(); + $TY($ty::from_parts(sign, exponent, significand)) + } else { // Random anything + let sign: bool = g.gen(); + let exponent: <$ty as Float>::Int = g.gen(); + let significand: <$ty as Float>::Int = g.gen(); + $TY($ty::from_parts(sign, exponent, significand)) + } + } + + fn shrink(&self) -> Box> { + ::quickcheck::empty_shrinker() + } + } + + impl fmt::Debug for $TY { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } + } + + impl PartialEq for $TY { + fn eq(&self, other: &$TY) -> bool { + self.0.eq_repr(other.0) + } + } + } +} + +arbitrary_float!(F32: f32); +arbitrary_float!(F64: f64); + // Convenience macro to test intrinsics against their reference implementations. // // Each intrinsic is tested against both the `gcc_s` library as well as From 94c0d475bc24b132efb08ad1ca1b8b992078b82b Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Sat, 12 Nov 2016 15:30:57 -0600 Subject: [PATCH 0215/4206] Use correct lib name in qc test failure --- library/compiler-builtins/src/qc.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs index 74fcb42c8592d..5dbc56f24a8fb 100644 --- a/library/compiler-builtins/src/qc.rs +++ b/library/compiler-builtins/src/qc.rs @@ -281,9 +281,9 @@ macro_rules! check { print!("{} - Args: ", stringify!($name)); $(print!("{:?} ", $arg);)* print!("\n"); - println!(" rustc-builtins: {:?}", my_answer); - println!(" compiler_rt: {:?}", compiler_rt_answer); - println!(" gcc_s: {:?}", gcc_s_answer); + println!(" compiler-builtins: {:?}", my_answer); + println!(" compiler_rt: {:?}", compiler_rt_answer); + println!(" gcc_s: {:?}", gcc_s_answer); }; if my_answer != compiler_rt_answer { From 430c92cc9a0cd6e338bb1327bfaa31df729999a0 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Sat, 12 Nov 2016 15:31:19 -0600 Subject: [PATCH 0216/4206] Use better cfg name for arm-linux tests --- library/compiler-builtins/build.rs | 5 +++-- library/compiler-builtins/src/float/add.rs | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 9f7a8fdedb85f..6e7833013eedd 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -424,8 +424,9 @@ fn main() { } // To filter away some flaky test (see src/float/add.rs for details) - if llvm_target.last().unwrap().contains("gnueabi") { - println!("cargo:rustc-cfg=gnueabi") + if llvm_target[0].starts_with("arm") && + llvm_target.last().unwrap().contains("gnueabi") { + println!("cargo:rustc-cfg=arm_linux") } // To compile intrinsics.rs for thumb targets, where there is no libc diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 814b99b26c8d6..0b2490a8ce9ae 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -184,11 +184,11 @@ macro_rules! add { add!(__addsf3: f32); add!(__adddf3: f64); -// NOTE(cfg) for some reason, on arm-unknown-linux-gnueabi*, our implementation doesn't +// NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabi*, our implementation doesn't // match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll // just avoid testing against them on those targets. Do note that our implementation gives the // correct answer; gcc_s and compiler-rt are incorrect in this case. -#[cfg(all(test, not(gnueabi)))] +#[cfg(all(test, not(arm_linux)))] mod tests { use core::{f32, f64}; use qc::{F32, F64}; From 2c99644aa793fefd3c5788765bd506fa63336950 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Sat, 12 Nov 2016 15:09:47 -0600 Subject: [PATCH 0217/4206] Fix apt 404s in Docker `apt update` and `apt install` should be in the same Docker RUN statement, otherwise `apt update` will be cached and `apt install` will 404 if a package no longer exists. --- .../ci/docker/aarch64-unknown-linux-gnu/Dockerfile | 10 +++++----- .../ci/docker/arm-unknown-linux-gnueabi/Dockerfile | 8 ++++---- .../ci/docker/arm-unknown-linux-gnueabihf/Dockerfile | 8 ++++---- .../ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile | 8 ++++---- .../ci/docker/i586-unknown-linux-gnu/Dockerfile | 6 +++--- .../ci/docker/i686-unknown-linux-gnu/Dockerfile | 6 +++--- .../ci/docker/mips-unknown-linux-gnu/Dockerfile | 10 +++++----- .../ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile | 8 ++++---- .../docker/mips64el-unknown-linux-gnuabi64/Dockerfile | 4 ++-- .../ci/docker/mipsel-unknown-linux-gnu/Dockerfile | 10 +++++----- .../ci/docker/powerpc-unknown-linux-gnu/Dockerfile | 10 +++++----- .../ci/docker/powerpc64-unknown-linux-gnu/Dockerfile | 10 +++++----- .../ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile | 10 +++++----- .../ci/docker/thumbv6m-none-eabi/Dockerfile | 4 ++-- .../ci/docker/thumbv7em-none-eabi/Dockerfile | 4 ++-- .../ci/docker/thumbv7em-none-eabihf/Dockerfile | 4 ++-- .../ci/docker/thumbv7m-none-eabi/Dockerfile | 4 ++-- .../ci/docker/x86_64-unknown-linux-gnu/Dockerfile | 6 +++--- 18 files changed, 65 insertions(+), 65 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 d9a243fa26c52..fe05867e37969 100644 --- a/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -1,9 +1,9 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-aarch64-linux-gnu libc6-dev-arm64-cross \ - qemu-user-static +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-aarch64-linux-gnu libc6-dev-arm64-cross \ + qemu-user-static ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ QEMU_LD_PREFIX=/usr/aarch64-linux-gnu \ RUST_TEST_THREADS=1 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 cb4d021bb948d..8a09c20c43e3c 100644 --- a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile @@ -1,8 +1,8 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-linux-gnueabi libc6-dev-armel-cross qemu-user-static +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-linux-gnueabi libc6-dev-armel-cross qemu-user-static ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER=arm-linux-gnueabi-gcc \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabi \ RUST_TEST_THREADS=1 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 985abeceaba70..57d830d1cd5e0 100644 --- a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile @@ -1,8 +1,8 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ RUST_TEST_THREADS=1 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 94cae18ccb96b..a2f3cf177a268 100644 --- a/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile @@ -1,8 +1,8 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ RUST_TEST_THREADS=1 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 3254b1a347a5b..fb32306090bd4 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 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ - gcc-multilib libc6-dev ca-certificates +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc-multilib libc6-dev ca-certificates 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 3254b1a347a5b..fb32306090bd4 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 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ - gcc-multilib libc6-dev ca-certificates +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc-multilib libc6-dev ca-certificates 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 e332b540394d9..9d69f1dfea329 100644 --- a/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile @@ -1,10 +1,10 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-mips-linux-gnu libc6-dev-mips-cross \ - binfmt-support qemu-user-static qemu-system-mips +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-mips-linux-gnu libc6-dev-mips-cross \ + binfmt-support qemu-user-static qemu-system-mips ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER=mips-linux-gnu-gcc \ QEMU_LD_PREFIX=/usr/mips-linux-gnu \ 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 92b1d93b8fdca..16b6c878ff00f 100644 --- a/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile @@ -1,13 +1,13 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ ca-certificates \ gcc \ gcc-mips64-linux-gnuabi64 \ libc6-dev \ libc6-dev-mips64-cross \ - qemu-user-static -RUN apt-get install -y --no-install-recommends qemu-system-mips + qemu-user-static \ + apt-get install -y --no-install-recommends qemu-system-mips ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER=mips64-linux-gnuabi64-gcc \ CC_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-gcc \ QEMU_LD_PREFIX=/usr/mips64-linux-gnuabi64 \ 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 adba7783fa0f1..13f770fcc53ed 100644 --- a/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ ca-certificates \ gcc \ gcc-mips64el-linux-gnuabi64 \ 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 28f77be64d7ee..0afd5e7f503ab 100644 --- a/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile @@ -1,10 +1,10 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-mipsel-linux-gnu libc6-dev-mipsel-cross \ - binfmt-support qemu-user-static +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-mipsel-linux-gnu libc6-dev-mipsel-cross \ + binfmt-support qemu-user-static ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER=mipsel-linux-gnu-gcc \ QEMU_LD_PREFIX=/usr/mipsel-linux-gnu \ 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 8106728b96e16..6e65a04db7cd9 100644 --- a/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile @@ -1,10 +1,10 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ - gcc libc6-dev qemu-user-static ca-certificates \ - gcc-powerpc-linux-gnu libc6-dev-powerpc-cross \ - qemu-system-ppc +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user-static ca-certificates \ + gcc-powerpc-linux-gnu libc6-dev-powerpc-cross \ + qemu-system-ppc ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER=powerpc-linux-gnu-gcc \ QEMU_LD_PREFIX=/usr/powerpc-linux-gnu \ 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 3259b4d9244ed..eb86808f648a7 100644 --- a/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile @@ -1,10 +1,10 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross \ - binfmt-support qemu-user-static qemu-system-ppc +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross \ + binfmt-support qemu-user-static qemu-system-ppc ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER=powerpc64-linux-gnu-gcc \ CC_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-gcc \ 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 ba1b3c287bf96..adb4106d3ef3a 100644 --- a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile @@ -1,10 +1,10 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ - gcc libc6-dev qemu-user-static ca-certificates \ - gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross \ - qemu-system-ppc +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user-static ca-certificates \ + gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross \ + qemu-system-ppc ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER=powerpc64le-linux-gnu-gcc \ QEMU_CPU=POWER8 \ diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile index 4a4556673f22a..8e92cc0709d7a 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.13 diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile index 84cd8d7af0748..65f95643bdde8 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.13 diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile index 62ba127312208..e368168a789e1 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.13 diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile index 42baa3c9a1965..3db646b9a6b54 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.13 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 2ca8ee99c7c3a..efc7b26c609eb 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 @@ FROM ubuntu:16.04 -RUN apt-get update -RUN apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates From a5d8d0d9f5ff3cfded51f1f5eeed3a9e46c37a2d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 12 Nov 2016 17:36:59 -0500 Subject: [PATCH 0218/4206] merge apt-get commands --- .../ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 16b6c878ff00f..ef6eeaad59f2d 100644 --- a/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile @@ -7,7 +7,7 @@ RUN apt-get update && \ libc6-dev \ libc6-dev-mips64-cross \ qemu-user-static \ - apt-get install -y --no-install-recommends qemu-system-mips + qemu-system-mips ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER=mips64-linux-gnuabi64-gcc \ CC_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-gcc \ QEMU_LD_PREFIX=/usr/mips64-linux-gnuabi64 \ From 03e9f74fb89c0e723c551b84a29f3f4ea766bcb6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 16 Nov 2016 14:34:26 -0500 Subject: [PATCH 0219/4206] update the compiler-rt submodule to pick up the fixes for rust-lang/rust#37559 and rust-lang/rust#37630 --- .../compiler-rt/compiler-rt-cdylib/compiler-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt index f03ba5a4e8bf1..3bc0272cab9fd 160000 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt @@ -1 +1 @@ -Subproject commit f03ba5a4e8bf16dcf42dd742a4ce255c36321356 +Subproject commit 3bc0272cab9fdcfc2ef4df9625ec3c9d5909db79 From 865ed6f133627772d6b02d4a44cd8fae447ef294 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 18 Nov 2016 09:40:20 -0800 Subject: [PATCH 0220/4206] Define VISIBILITY_HIDDEN when compiling objects Apparently compiler-rt passed this and we just forgot to. Fixes visibility of some symbols on 32-bit Linux. --- library/compiler-builtins/build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 6e7833013eedd..e6ad4c6a13b72 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -78,6 +78,7 @@ fn main() { cfg.flag("-fvisibility=hidden"); cfg.flag("-fomit-frame-pointer"); cfg.flag("-ffreestanding"); + cfg.define("VISIBILITY_HIDDEN", None); } // NOTE Most of the ARM intrinsics are written in assembly. Tell gcc which arch we are going to From 42b4300d36fbe5c30056e6f9f0a55ca0353ff69b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 23 Nov 2016 12:47:42 -0500 Subject: [PATCH 0221/4206] CI: use Xargo 0.2.x this version uses the rust-src component that rustup installs instead of fetching the source tarball from static.r-l.o, which sometimes went wrong due to the fallible logic that Xargo 0.1.x used --- library/compiler-builtins/.travis.yml | 11 +++++++---- .../ci/docker/thumbv6m-none-eabi/Dockerfile | 4 ++-- .../ci/docker/thumbv7em-none-eabi/Dockerfile | 4 ++-- .../ci/docker/thumbv7em-none-eabihf/Dockerfile | 4 ++-- .../ci/docker/thumbv7m-none-eabi/Dockerfile | 4 ++-- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index f4ccbadeac6b7..7ca18a915141f 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -34,10 +34,13 @@ before_install: - test "$TRAVIS_OS_NAME" = "osx" || docker run --rm --privileged multiarch/qemu-user-static:register install: - - if case $TARGET in thumb*) false;; *) true;; esac; then - curl https://static.rust-lang.org/rustup.sh | - sh -s -- --add-target=$TARGET --disable-sudo -y --prefix=`rustc --print sysroot`; - fi + - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $TRAVIS_RUST_VERSION + - source ~/.cargo/env + - case $TARGET in + x86_64-apple-darwin | x86_64-unknown-linux-gnu) ;; + thumbv*-none-eabi*) rustup component add rust-src ;; + *) rustup target add $TARGET;; + esac script: - cargo generate-lockfile diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile index 8e92cc0709d7a..09c3203b480d3 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -2,8 +2,8 @@ FROM ubuntu:16.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev -RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.13 +RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ + sh -s -- --git japaric/xargo --tag v0.2.1 --target x86_64-unknown-linux-gnu --to /usr/bin ENV AR_thumbv6m_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV6M_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv6m_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile index 65f95643bdde8..73ebf8101833f 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -2,8 +2,8 @@ FROM ubuntu:16.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev -RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.13 +RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ + sh -s -- --git japaric/xargo --tag v0.2.1 --target x86_64-unknown-linux-gnu --to /usr/bin ENV AR_thumbv7em_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv7em_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile index e368168a789e1..7ec622b721198 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -2,8 +2,8 @@ FROM ubuntu:16.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev -RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.13 +RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ + sh -s -- --git japaric/xargo --tag v0.2.1 --target x86_64-unknown-linux-gnu --to /usr/bin ENV AR_thumbv7em_none_eabihf=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_NONE_EABIHF_LINKER=arm-none-eabi-gcc \ CC_thumbv7em_none_eabihf=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile index 3db646b9a6b54..f5a493195342e 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -2,8 +2,8 @@ FROM ubuntu:16.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev -RUN curl -sf "https://raw.githubusercontent.com/japaric/rust-everywhere/master/install.sh" | \ - bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.13 +RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ + sh -s -- --git japaric/xargo --tag v0.2.1 --target x86_64-unknown-linux-gnu --to /usr/bin ENV AR_thumbv7m_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7M_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv7m_none_eabi=arm-none-eabi-gcc \ From 0abb6e20e6eae6d2ae461644965aa94b379f202e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 11 Dec 2016 11:17:21 -0500 Subject: [PATCH 0222/4206] fix the test suite for the thumb targets --- library/compiler-builtins/.travis.yml | 5 +++++ library/compiler-builtins/ci/run.sh | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 7ca18a915141f..e5fcf195a8065 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -22,10 +22,15 @@ matrix: - env: TARGET=powerpc-unknown-linux-gnu - env: TARGET=powerpc64-unknown-linux-gnu - env: TARGET=powerpc64le-unknown-linux-gnu + # NOTE(nightly-2016-12-05) work around for rust-lang/rust#38281 - env: TARGET=thumbv6m-none-eabi + rust: nightly-2016-12-05 - env: TARGET=thumbv7em-none-eabi + rust: nightly-2016-12-05 - env: TARGET=thumbv7em-none-eabihf + rust: nightly-2016-12-05 - env: TARGET=thumbv7m-none-eabi + rust: nightly-2016-12-05 - env: TARGET=x86_64-apple-darwin os: osx env: TARGET=x86_64-unknown-linux-gnu diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 0159e2389130d..221748fd4886b 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -1,4 +1,4 @@ -set -e +set -ex # Test our implementation case $1 in From 8a415ef044345d42e090773861cb7ea30aeee60b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 11 Dec 2016 11:33:21 -0500 Subject: [PATCH 0223/4206] pin all the targets to nightly-2016-12-05 --- library/compiler-builtins/.travis.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index e5fcf195a8065..156dbe0c9d82f 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -1,7 +1,8 @@ cache: cargo dist: trusty language: rust -rust: nightly +# NOTE(nightly-2016-12-05) work around for rust-lang/rust#38281 +rust: nightly-2016-12-05 services: docker sudo: required @@ -22,15 +23,10 @@ matrix: - env: TARGET=powerpc-unknown-linux-gnu - env: TARGET=powerpc64-unknown-linux-gnu - env: TARGET=powerpc64le-unknown-linux-gnu - # NOTE(nightly-2016-12-05) work around for rust-lang/rust#38281 - env: TARGET=thumbv6m-none-eabi - rust: nightly-2016-12-05 - env: TARGET=thumbv7em-none-eabi - rust: nightly-2016-12-05 - env: TARGET=thumbv7em-none-eabihf - rust: nightly-2016-12-05 - env: TARGET=thumbv7m-none-eabi - rust: nightly-2016-12-05 - env: TARGET=x86_64-apple-darwin os: osx env: TARGET=x86_64-unknown-linux-gnu From fc81b547e612afc64a1f9ae6ea2d2fad6dbe1205 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 11 Dec 2016 14:58:05 -0500 Subject: [PATCH 0224/4206] work around rust-lang/cargo#3340 --- library/compiler-builtins/.travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 156dbe0c9d82f..61b17134072c4 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -44,6 +44,8 @@ install: esac script: + # work around rust-lang/cargo#3340 + - export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt - cargo generate-lockfile - if [[ $TRAVIS_OS_NAME = "linux" ]]; then sudo apt-get remove -y qemu-user-static && From b90b5107a7a8ea66f8ab635b105413c396ea7782 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 11 Dec 2016 15:26:18 -0500 Subject: [PATCH 0225/4206] don't set SSL_CERT_FILE for OSX --- library/compiler-builtins/.travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 61b17134072c4..82ca5d8222c57 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -45,7 +45,8 @@ install: script: # work around rust-lang/cargo#3340 - - export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt + - test "$TRAVIS_OS_NAME" = "osx" || + export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt - cargo generate-lockfile - if [[ $TRAVIS_OS_NAME = "linux" ]]; then sudo apt-get remove -y qemu-user-static && From 6da988a43a27b0db272c05da50720782c54f5a85 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 11 Dec 2016 16:18:43 -0500 Subject: [PATCH 0226/4206] by default, mark this crate as the #![compiler_builtins] crate as this is how most users will want to use this crate --- library/compiler-builtins/Cargo.toml | 4 ++++ library/compiler-builtins/ci/run.sh | 14 +++++++------- library/compiler-builtins/src/lib.rs | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 58ce4513ca554..95364233e9d4a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -23,6 +23,10 @@ compiler-rt = { path = "compiler-rt" } [features] # Build the missing intrinsics from compiler-rt C source code c = [] +# Mark this crate as the #![compiler_builtins] crate +compiler-builtins = [] +default = ["compiler-builtins"] +rustbuild = ["compiler-builtins"] weak = ["rlibc/weak"] [workspace] diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 0159e2389130d..c9e0736c3d8da 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -7,8 +7,8 @@ case $1 in xargo build --target $1 --release ;; *) - cargo test --target $1 - cargo test --target $1 --release + cargo test --no-default-features --target $1 + cargo test --no-default-features --target $1 --release ;; esac @@ -18,7 +18,7 @@ case $1 in xargo build --features c --target $1 --bin intrinsics ;; *) - cargo build --features c --target $1 --bin intrinsics + cargo build --no-default-features --features c --target $1 --bin intrinsics ;; esac @@ -26,12 +26,12 @@ esac # TODO(#79) fix the undefined references problem for debug-assertions+lto case $1 in thumb*) - RUSTFLAGS="-C debug-assertions=no -C link-arg=-nostartfiles" xargo rustc --features c --target $1 --bin intrinsics -- -C lto - xargo rustc --features c --target $1 --bin intrinsics --release -- -C lto + RUSTFLAGS="-C debug-assertions=no -C link-arg=-nostartfiles" xargo rustc --no-default-features --features c --target $1 --bin intrinsics -- -C lto + xargo rustc --no-default-features --features c --target $1 --bin intrinsics --release -- -C lto ;; *) - RUSTFLAGS="-C debug-assertions=no" cargo rustc --features c --target $1 --bin intrinsics -- -C lto - cargo rustc --features c --target $1 --bin intrinsics --release -- -C lto + RUSTFLAGS="-C debug-assertions=no" cargo rustc --no-default-features --features c --target $1 --bin intrinsics -- -C lto + cargo rustc --no-default-features --features c --target $1 --bin intrinsics --release -- -C lto ;; esac diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 0efb20b5dec89..dc8f4111d8987 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,6 +1,6 @@ #![cfg_attr(not(stage0), deny(warnings))] #![cfg_attr(not(test), no_std)] -#![cfg_attr(rustbuild, compiler_builtins)] +#![cfg_attr(feature = "compiler-builtins", compiler_builtins)] #![crate_name = "compiler_builtins"] #![crate_type = "rlib"] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", From 45ebf21c0b03f0e04b7714a521a71028ffd9cf68 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 11 Dec 2016 16:54:41 -0500 Subject: [PATCH 0227/4206] fix appveyor --- library/compiler-builtins/appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index f27347c338de7..c05bfdfc2b604 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -16,5 +16,5 @@ build: false test_script: - cargo build --target %TARGET% - cargo build --release --target %TARGET% - - cargo test --target %TARGET% - - cargo test --release --target %TARGET% + - cargo test --no-default-features --target %TARGET% + - cargo test --no-default-features --release --target %TARGET% From b8d66520352af21a8e53f04363ddd3a040d7dcba Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 17 Dec 2016 23:01:47 -0500 Subject: [PATCH 0228/4206] add implementations of memcpy et al behind the "mem" Cargo feature, which used to be named "weak" fixes #126 --- library/compiler-builtins/Cargo.toml | 9 +---- library/compiler-builtins/src/arm.rs | 4 ++ library/compiler-builtins/src/lib.rs | 7 ++-- library/compiler-builtins/src/mem.rs | 59 ++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 11 deletions(-) create mode 100644 library/compiler-builtins/src/mem.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 95364233e9d4a..83405787a021b 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -8,12 +8,6 @@ version = "0.1.0" rustc-cfg = "0.2.0" gcc = "0.3.36" -[dependencies] - -[dependencies.rlibc] -git = "https://github.com/alexcrichton/rlibc" -optional = true - [dev-dependencies] quickcheck = "0.3.1" rand = "0.3.14" @@ -26,7 +20,8 @@ c = [] # Mark this crate as the #![compiler_builtins] crate compiler-builtins = [] default = ["compiler-builtins"] +# Include implementations of memory operations like memcpy +mem = [] rustbuild = ["compiler-builtins"] -weak = ["rlibc/weak"] [workspace] diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index b74458f11a244..345ff241dbe4f 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,5 +1,8 @@ use core::intrinsics; +#[cfg(feature = "mem")] +use mem::{memcpy, memmove, memset}; + // NOTE This function and the ones below are implemented using assembly because they using a custom // calling convention which can't be implemented using a normal Rust function #[naked] @@ -100,6 +103,7 @@ pub extern "C" fn __aeabi_uidiv(a: u32, b: u32) -> u32 { ::int::udiv::__udivsi3(a, b) } +#[cfg(not(feature = "mem"))] extern "C" { fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index dc8f4111d8987..b104def30cc8f 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -11,7 +11,6 @@ #![feature(asm)] #![feature(compiler_builtins)] #![feature(core_intrinsics)] -#![feature(linkage)] #![feature(naked_functions)] #![feature(staged_api)] #![no_builtins] @@ -102,9 +101,6 @@ extern crate compiler_rt; #[cfg(test)] extern crate rand; -#[cfg(feature = "weak")] -extern crate rlibc; - #[cfg(test)] #[macro_use] mod qc; @@ -112,6 +108,9 @@ mod qc; pub mod int; pub mod float; +#[cfg(feature = "mem")] +pub mod mem; + #[cfg(target_arch = "arm")] pub mod arm; diff --git a/library/compiler-builtins/src/mem.rs b/library/compiler-builtins/src/mem.rs new file mode 100644 index 0000000000000..31d6712d0d358 --- /dev/null +++ b/library/compiler-builtins/src/mem.rs @@ -0,0 +1,59 @@ +#[no_mangle] +pub unsafe extern "C" fn memcpy(dest: *mut u8, + src: *const u8, + n: usize) + -> *mut u8 { + let mut i = 0; + while i < n { + *dest.offset(i as isize) = *src.offset(i as isize); + i += 1; + } + dest +} + +#[no_mangle] +pub unsafe extern "C" fn memmove(dest: *mut u8, + src: *const u8, + n: usize) + -> *mut u8 { + if src < dest as *const u8 { + // copy from end + let mut i = n; + while i != 0 { + i -= 1; + *dest.offset(i as isize) = *src.offset(i as isize); + } + } else { + // copy from beginning + let mut i = 0; + while i < n { + *dest.offset(i as isize) = *src.offset(i as isize); + i += 1; + } + } + dest +} + +#[no_mangle] +pub unsafe extern "C" fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8 { + let mut i = 0; + while i < n { + *s.offset(i as isize) = c as u8; + i += 1; + } + s +} + +#[no_mangle] +pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { + let mut i = 0; + while i < n { + let a = *s1.offset(i as isize); + let b = *s2.offset(i as isize); + if a != b { + return a as i32 - b as i32; + } + i += 1; + } + 0 +} From a2671118ae95417715bacc803661fb2b410b9c32 Mon Sep 17 00:00:00 2001 From: Vadzim Dambrouski Date: Mon, 19 Dec 2016 05:11:01 +0300 Subject: [PATCH 0229/4206] Fix memset arguments for MSP430 target. On MSP430 second argument to memset has i16 type instead of i32. --- library/compiler-builtins/src/mem.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/mem.rs b/library/compiler-builtins/src/mem.rs index 31d6712d0d358..a7d267c500311 100644 --- a/library/compiler-builtins/src/mem.rs +++ b/library/compiler-builtins/src/mem.rs @@ -1,3 +1,10 @@ +#[allow(warnings)] +#[cfg(target_pointer_width = "16")] +type c_int = i16; +#[allow(warnings)] +#[cfg(not(target_pointer_width = "16"))] +type c_int = i32; + #[no_mangle] pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, @@ -35,7 +42,7 @@ pub unsafe extern "C" fn memmove(dest: *mut u8, } #[no_mangle] -pub unsafe extern "C" fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8 { +pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { let mut i = 0; while i < n { *s.offset(i as isize) = c as u8; From af00bd119832a37366f4a67a19f9556d68bd1d74 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Dec 2016 21:56:29 -0500 Subject: [PATCH 0230/4206] bump rustc-cfg dependency to v0.3.0 the older no longer works with recent nightlies as target_family disappeared from `rustc --print cfg`'s output --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 83405787a021b..5fb89f462bc8a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -5,7 +5,7 @@ name = "compiler_builtins" version = "0.1.0" [build-dependencies] -rustc-cfg = "0.2.0" +rustc-cfg = "0.3.0" gcc = "0.3.36" [dev-dependencies] From 3ed64e2b500e9464898bf67ea2ca48b9d09a1f26 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Dec 2016 23:18:17 -0500 Subject: [PATCH 0231/4206] CI: use a recent nightly - add #[no_mangle] to the panic_fmt lang item to adjust to changes in the visibility algorithm - adjust to changes in the layout of Cargo's target directory - use a newer Xargo to reduce the build time of the sysroot (only core is compiled as part of the sysroot now) --- library/compiler-builtins/.travis.yml | 3 +-- .../ci/docker/thumbv6m-none-eabi/Dockerfile | 2 +- .../ci/docker/thumbv7em-none-eabi/Dockerfile | 2 +- .../docker/thumbv7em-none-eabihf/Dockerfile | 2 +- .../ci/docker/thumbv7m-none-eabi/Dockerfile | 2 +- library/compiler-builtins/ci/run.sh | 24 +++++++++++-------- .../compiler-builtins/src/bin/intrinsics.rs | 1 + 7 files changed, 20 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 82ca5d8222c57..96bd24ab2f9e8 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -1,8 +1,7 @@ cache: cargo dist: trusty language: rust -# NOTE(nightly-2016-12-05) work around for rust-lang/rust#38281 -rust: nightly-2016-12-05 +rust: nightly services: docker sudo: required diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile index 09c3203b480d3..2a2d127e1d23b 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -3,7 +3,7 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ - sh -s -- --git japaric/xargo --tag v0.2.1 --target x86_64-unknown-linux-gnu --to /usr/bin + sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin ENV AR_thumbv6m_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV6M_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv6m_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile index 73ebf8101833f..fda5dcbe6f840 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -3,7 +3,7 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ - sh -s -- --git japaric/xargo --tag v0.2.1 --target x86_64-unknown-linux-gnu --to /usr/bin + sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin ENV AR_thumbv7em_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv7em_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile index 7ec622b721198..5395e7449a9cf 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -3,7 +3,7 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ - sh -s -- --git japaric/xargo --tag v0.2.1 --target x86_64-unknown-linux-gnu --to /usr/bin + sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin ENV AR_thumbv7em_none_eabihf=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_NONE_EABIHF_LINKER=arm-none-eabi-gcc \ CC_thumbv7em_none_eabihf=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile index f5a493195342e..e09c020a223cf 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -3,7 +3,7 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ - sh -s -- --git japaric/xargo --tag v0.2.1 --target x86_64-unknown-linux-gnu --to /usr/bin + sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin ENV AR_thumbv7m_none_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7M_NONE_EABI_LINKER=arm-none-eabi-gcc \ CC_thumbv7m_none_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 382d70fe87b87..b30fad10fc868 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -26,7 +26,7 @@ esac # TODO(#79) fix the undefined references problem for debug-assertions+lto case $1 in thumb*) - RUSTFLAGS="-C debug-assertions=no -C link-arg=-nostartfiles" xargo rustc --no-default-features --features c --target $1 --bin intrinsics -- -C lto + RUSTFLAGS="-C debug-assertions=no" xargo rustc --no-default-features --features c --target $1 --bin intrinsics -- -C lto -C link-arg=-nostartfiles xargo rustc --no-default-features --features c --target $1 --bin intrinsics --release -- -C lto ;; *) @@ -61,18 +61,22 @@ case $TRAVIS_OS_NAME in ;; esac -# NOTE On i586, It's normal that the get_pc_thunk symbol appears several times so ignore it if [ $TRAVIS_OS_NAME = osx ]; then - path=target/${1}/debug/libcompiler_builtins.rlib + path=target/${1}/debug/deps/libcompiler_builtins-*.rlib else - path=/target/${1}/debug/libcompiler_builtins.rlib + path=/target/${1}/debug/deps/libcompiler_builtins-*.rlib fi -stdout=$($PREFIX$NM -g --defined-only $path) +for rlib in $(echo $path); do + stdout=$($PREFIX$NM -g --defined-only $rlib) -set +e -echo "$stdout" | sort | uniq -d | grep -v __x86.get_pc_thunk | grep 'T __' + # NOTE On i586, It's normal that the get_pc_thunk symbol appears several times so ignore it + set +e + echo "$stdout" | sort | uniq -d | grep -v __x86.get_pc_thunk | grep 'T __' -if test $? = 0; then - exit 1 -fi + if test $? = 0; then + exit 1 + fi +done + +true diff --git a/library/compiler-builtins/src/bin/intrinsics.rs b/library/compiler-builtins/src/bin/intrinsics.rs index 5a4a34503cc6f..b0de331afd4c8 100644 --- a/library/compiler-builtins/src/bin/intrinsics.rs +++ b/library/compiler-builtins/src/bin/intrinsics.rs @@ -403,5 +403,6 @@ pub fn _Unwind_Resume() {} extern "C" fn eh_personality() {} #[cfg(not(test))] +#[no_mangle] #[lang = "panic_fmt"] extern "C" fn panic_fmt() {} From acbca64291e2ad303b732cb0a0cb6097ecd15db5 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 31 Dec 2016 10:04:16 -0500 Subject: [PATCH 0232/4206] more #[no_mangle] --- library/compiler-builtins/src/bin/intrinsics.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/bin/intrinsics.rs b/library/compiler-builtins/src/bin/intrinsics.rs index b0de331afd4c8..e0b619f55989b 100644 --- a/library/compiler-builtins/src/bin/intrinsics.rs +++ b/library/compiler-builtins/src/bin/intrinsics.rs @@ -400,9 +400,10 @@ pub fn _Unwind_Resume() {} // Lang items #[cfg(not(test))] #[lang = "eh_personality"] +#[no_mangle] extern "C" fn eh_personality() {} #[cfg(not(test))] -#[no_mangle] #[lang = "panic_fmt"] +#[no_mangle] extern "C" fn panic_fmt() {} From da48de46016c0214bf43aca7e5f6bc41ab731367 Mon Sep 17 00:00:00 2001 From: James Duley Date: Mon, 2 Jan 2017 22:57:38 +1300 Subject: [PATCH 0233/4206] mul.rs: use wrapping_mul not plain rustc in debug mode with a plain multiplication will call @llvm.umul.with.overflow.* which may call the builtin resulting in infinite recursion. --- library/compiler-builtins/src/int/mul.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index db9f0d9e0c692..0403aa9006030 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -9,18 +9,18 @@ macro_rules! mul { pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { let half_bits = <$ty>::bits() / 4; let lower_mask = !0 >> half_bits; - let mut low = (a.low() & lower_mask) * (b.low() & lower_mask); + let mut low = (a.low() & lower_mask).wrapping_mul(b.low() & lower_mask); let mut t = low >> half_bits; low &= lower_mask; - t += (a.low() >> half_bits) * (b.low() & lower_mask); + t += (a.low() >> half_bits).wrapping_mul(b.low() & lower_mask); low += (t & lower_mask) << half_bits; let mut high = t >> half_bits; t = low >> half_bits; low &= lower_mask; - t += (b.low() >> half_bits) * (a.low() & lower_mask); + t += (b.low() >> half_bits).wrapping_mul(a.low() & lower_mask); low += (t & lower_mask) << half_bits; high += t >> half_bits; - high += (a.low() >> half_bits) * (b.low() >> half_bits); + high += (a.low() >> half_bits).wrapping_mul(b.low() >> half_bits); high = high.wrapping_add(a.high().wrapping_mul(b.low()).wrapping_add(a.low().wrapping_mul(b.high()))); <$ty>::from_parts(low, high) } From e6bb6db8eb0f83233d57e174e2ea56d9a11aa34b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 26 Jan 2017 16:17:23 -0500 Subject: [PATCH 0234/4206] fix the build the unused macro_use crate lint has tightened; fix the new warnings --- library/compiler-builtins/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index b104def30cc8f..04bf2d05c95db 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -86,7 +86,7 @@ macro_rules! srem { } #[cfg(test)] -#[macro_use] +#[cfg_attr(target_arch = "arm", macro_use)] extern crate quickcheck; #[cfg(test)] From b6e0dd2bf28f8ff17e4430ddc4bd1cba098e2173 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 4 Jan 2017 01:42:57 +0100 Subject: [PATCH 0235/4206] Add i128 to lib.rs as feature --- library/compiler-builtins/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 04bf2d05c95db..21d7902b2c22a 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -13,6 +13,7 @@ #![feature(core_intrinsics)] #![feature(naked_functions)] #![feature(staged_api)] +#![feature(i128_type)] #![no_builtins] #![unstable(feature = "compiler_builtins_lib", reason = "Compiler builtins. Will never become stable.", From 8bb1010d51e65ef9565c3b7ee839ce2d5f7297bf Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 4 Jan 2017 01:52:47 +0100 Subject: [PATCH 0236/4206] int module: macro-ify trait impls and add {u,i}128 support --- library/compiler-builtins/src/int/mod.rs | 79 +++++++++++------------- 1 file changed, 35 insertions(+), 44 deletions(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 37e05377a2e56..bbe4b7bfd5d11 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -10,28 +10,25 @@ pub trait Int { fn bits() -> u32; } -// TODO: Once i128/u128 support lands, we'll want to add impls for those as well -impl Int for u32 { - fn bits() -> u32 { - 32 - } -} -impl Int for i32 { - fn bits() -> u32 { - 32 - } -} -impl Int for u64 { - fn bits() -> u32 { - 64 - } -} -impl Int for i64 { - fn bits() -> u32 { - 64 +macro_rules! int_impl { + ($ity:ty, $sty:ty, $bits:expr) => { + impl Int for $ity { + fn bits() -> u32 { + $bits + } + } + impl Int for $sty { + fn bits() -> u32 { + $bits + } + } } } +int_impl!(i32, u32, 32); +int_impl!(i64, u64, 64); +int_impl!(i128, u128, 128); + /// Trait to convert an integer to/from smaller parts pub trait LargeInt { type LowHalf; @@ -42,32 +39,26 @@ pub trait LargeInt { fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self; } -// TODO: Once i128/u128 support lands, we'll want to add impls for those as well -impl LargeInt for u64 { - type LowHalf = u32; - type HighHalf = u32; +macro_rules! large_int { + ($ty:ty, $tylow:ty, $tyhigh:ty, $halfbits:expr) => { + impl LargeInt for $ty { + type LowHalf = $tylow; + type HighHalf = $tyhigh; - fn low(self) -> u32 { - self as u32 - } - fn high(self) -> u32 { - (self >> 32) as u32 - } - fn from_parts(low: u32, high: u32) -> u64 { - low as u64 | ((high as u64) << 32) + fn low(self) -> $tylow { + self as $tylow + } + fn high(self) -> $tyhigh { + (self >> $halfbits) as $tyhigh + } + fn from_parts(low: $tylow, high: $tyhigh) -> $ty { + low as $ty | ((high as $ty) << $halfbits) + } + } } } -impl LargeInt for i64 { - type LowHalf = u32; - type HighHalf = i32; - fn low(self) -> u32 { - self as u32 - } - fn high(self) -> i32 { - (self >> 32) as i32 - } - fn from_parts(low: u32, high: i32) -> i64 { - low as i64 | ((high as i64) << 32) - } -} +large_int!(u64, u32, u32, 32); +large_int!(i64, u32, i32, 32); +large_int!(u128, u64, u64, 64); +large_int!(i128, u64, i64, 64); From 19700fb03daaa88a11ec99d5a1bc84c8ce658204 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 4 Jan 2017 02:42:03 +0100 Subject: [PATCH 0237/4206] i128 mul intrinsics --- library/compiler-builtins/README.md | 4 ++-- library/compiler-builtins/build.rs | 2 -- library/compiler-builtins/src/int/mul.rs | 27 +++++++++++++++++------- library/compiler-builtins/src/lib.rs | 3 +++ 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index d66d88828bffe..8e81dde84a57a 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -206,8 +206,8 @@ These builtins are needed to support 128-bit integers, which are in the process - [ ] floatuntisf.c - [ ] lshrti3.c - [ ] modti3.c -- [ ] muloti4.c -- [ ] multi3.c +- [x] muloti4.c +- [x] multi3.c - [ ] udivmodti4.c - [ ] udivti3.c - [ ] umodti3.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index e6ad4c6a13b72..0ecb0d0c60b50 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -150,7 +150,6 @@ fn main() { "int_util.c", "muldc3.c", "muldf3.c", - "muloti4.c", "mulsc3.c", "mulsf3.c", "mulvdi3.c", @@ -202,7 +201,6 @@ fn main() { "lshrti3.c", "modti3.c", "multf3.c", - "multi3.c", "mulvti3.c", "negti2.c", "negvti2.c", diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 0403aa9006030..d46bc90303f5e 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -1,9 +1,8 @@ -#[cfg(not(all(feature = "c", target_arch = "x86")))] use int::LargeInt; use int::Int; macro_rules! mul { - ($intrinsic:ident: $ty:ty) => { + ($intrinsic:ident: $ty:ty, $tyh:ty) => { /// Returns `a * b` #[cfg_attr(not(test), no_mangle)] pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { @@ -14,14 +13,15 @@ macro_rules! mul { low &= lower_mask; t += (a.low() >> half_bits).wrapping_mul(b.low() & lower_mask); low += (t & lower_mask) << half_bits; - let mut high = t >> half_bits; + let mut high = (t >> half_bits) as $tyh; t = low >> half_bits; low &= lower_mask; t += (b.low() >> half_bits).wrapping_mul(a.low() & lower_mask); low += (t & lower_mask) << half_bits; - high += t >> half_bits; - high += (a.low() >> half_bits).wrapping_mul(b.low() >> half_bits); - high = high.wrapping_add(a.high().wrapping_mul(b.low()).wrapping_add(a.low().wrapping_mul(b.high()))); + high += (t >> half_bits) as $tyh; + high += (a.low() >> half_bits).wrapping_mul(b.low() >> half_bits) as $tyh; + high = high.wrapping_add(a.high().wrapping_mul(b.low() as $tyh)) + .wrapping_add((a.low() as $tyh).wrapping_mul(b.high())); <$ty>::from_parts(low, high) } } @@ -29,9 +29,13 @@ macro_rules! mul { macro_rules! mulo { ($intrinsic:ident: $ty:ty) => { + // Default is "C" ABI + mulo!($intrinsic: $ty, "C"); + }; + ($intrinsic:ident: $ty:ty, $abi:tt) => { /// Returns `a * b` and sets `*overflow = 1` if `a * b` overflows #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $intrinsic(a: $ty, b: $ty, overflow: &mut i32) -> $ty { + pub extern $abi fn $intrinsic(a: $ty, b: $ty, overflow: &mut i32) -> $ty { *overflow = 0; let result = a.wrapping_mul(b); if a == <$ty>::min_value() { @@ -69,11 +73,18 @@ macro_rules! mulo { } #[cfg(not(all(feature = "c", target_arch = "x86")))] -mul!(__muldi3: u64); +mul!(__muldi3: u64, u32); + +mul!(__multi3: i128, i64); mulo!(__mulosi4: i32); mulo!(__mulodi4: i64); +#[cfg(all(windows, target_pointer_width="64"))] +mulo!(__muloti4: i128, "unadjusted"); +#[cfg(not(all(windows, target_pointer_width="64")))] +mulo!(__muloti4: i128); + #[cfg(test)] mod tests { use qc::{I32, I64, U64}; diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 21d7902b2c22a..f637ff52b96d4 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -14,6 +14,9 @@ #![feature(naked_functions)] #![feature(staged_api)] #![feature(i128_type)] +#![feature(repr_simd)] +#![feature(abi_unadjusted)] +#![allow(unused_features)] #![no_builtins] #![unstable(feature = "compiler_builtins_lib", reason = "Compiler builtins. Will never become stable.", From a38eee9ea1bd00395ed97e7898cd1cd772f73d22 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 4 Jan 2017 03:04:27 +0100 Subject: [PATCH 0238/4206] i128 shift intrinsics --- library/compiler-builtins/README.md | 6 +++--- library/compiler-builtins/build.rs | 3 --- library/compiler-builtins/src/int/shift.rs | 7 ++++++- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 8e81dde84a57a..8a8c2d174f65d 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -193,8 +193,8 @@ features = ["c"] These builtins are needed to support 128-bit integers, which are in the process of being added to Rust. -- [ ] ashlti3.c -- [ ] ashrti3.c +- [x] ashlti3.c +- [x] ashrti3.c - [ ] divti3.c - [ ] fixdfti.c - [ ] fixsfti.c @@ -204,7 +204,7 @@ These builtins are needed to support 128-bit integers, which are in the process - [ ] floattisf.c - [ ] floatuntidf.c - [ ] floatuntisf.c -- [ ] lshrti3.c +- [x] lshrti3.c - [ ] modti3.c - [x] muloti4.c - [x] multi3.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 0ecb0d0c60b50..082592541d009 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -178,8 +178,6 @@ fn main() { sources.extend(&["absvti2.c", "addtf3.c", "addvti3.c", - "ashlti3.c", - "ashrti3.c", "clzti2.c", "cmpti2.c", "ctzti2.c", @@ -198,7 +196,6 @@ fn main() { "floatuntidf.c", "floatuntisf.c", "floatuntixf.c", - "lshrti3.c", "modti3.c", "multf3.c", "mulvti3.c", diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 9338f07ce7e4c..5c8dd5c6a4702 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -1,4 +1,3 @@ -#[cfg(not(all(feature = "c", target_arch = "x86")))] use int::{Int, LargeInt}; macro_rules! ashl { @@ -58,12 +57,18 @@ macro_rules! lshr { #[cfg(not(all(feature = "c", target_arch = "x86")))] ashl!(__ashldi3: u64); +ashl!(__ashlti3: u128); + #[cfg(not(all(feature = "c", target_arch = "x86")))] ashr!(__ashrdi3: i64); +ashr!(__ashrti3: i128); + #[cfg(not(all(feature = "c", target_arch = "x86")))] lshr!(__lshrdi3: u64); +lshr!(__lshrti3: u128); + #[cfg(test)] mod tests { use qc::{I64, U64}; From 9fd610d8591f0bca467587ac060cae3d6b05f2ff Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 5 Jan 2017 02:22:44 +0100 Subject: [PATCH 0239/4206] Macro-ify udivmod --- library/compiler-builtins/src/int/mod.rs | 15 ++ library/compiler-builtins/src/int/mul.rs | 16 +- library/compiler-builtins/src/int/udiv.rs | 255 +++++++++++----------- 3 files changed, 154 insertions(+), 132 deletions(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index bbe4b7bfd5d11..647410ccbf8ef 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -1,3 +1,14 @@ +macro_rules! hty { + ($ty:ty) => { + <$ty as LargeInt>::HighHalf + } +} + +macro_rules! os_ty { + ($ty:ty) => { + <$ty as Int>::OtherSign + } +} pub mod mul; pub mod sdiv; @@ -6,6 +17,8 @@ pub mod udiv; /// Trait for some basic operations on integers pub trait Int { + /// Type with the same width but other signedness + type OtherSign; /// Returns the bitwidth of the int type fn bits() -> u32; } @@ -13,11 +26,13 @@ pub trait Int { macro_rules! int_impl { ($ity:ty, $sty:ty, $bits:expr) => { impl Int for $ity { + type OtherSign = $sty; fn bits() -> u32 { $bits } } impl Int for $sty { + type OtherSign = $ity; fn bits() -> u32 { $bits } diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index d46bc90303f5e..45a712834649a 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -2,7 +2,7 @@ use int::LargeInt; use int::Int; macro_rules! mul { - ($intrinsic:ident: $ty:ty, $tyh:ty) => { + ($intrinsic:ident: $ty:ty) => { /// Returns `a * b` #[cfg_attr(not(test), no_mangle)] pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { @@ -13,15 +13,15 @@ macro_rules! mul { low &= lower_mask; t += (a.low() >> half_bits).wrapping_mul(b.low() & lower_mask); low += (t & lower_mask) << half_bits; - let mut high = (t >> half_bits) as $tyh; + let mut high = (t >> half_bits) as hty!($ty); t = low >> half_bits; low &= lower_mask; t += (b.low() >> half_bits).wrapping_mul(a.low() & lower_mask); low += (t & lower_mask) << half_bits; - high += (t >> half_bits) as $tyh; - high += (a.low() >> half_bits).wrapping_mul(b.low() >> half_bits) as $tyh; - high = high.wrapping_add(a.high().wrapping_mul(b.low() as $tyh)) - .wrapping_add((a.low() as $tyh).wrapping_mul(b.high())); + high += (t >> half_bits) as hty!($ty); + high += (a.low() >> half_bits).wrapping_mul(b.low() >> half_bits) as hty!($ty); + high = high.wrapping_add(a.high().wrapping_mul(b.low() as hty!($ty))) + .wrapping_add((a.low() as hty!($ty)).wrapping_mul(b.high())); <$ty>::from_parts(low, high) } } @@ -73,9 +73,9 @@ macro_rules! mulo { } #[cfg(not(all(feature = "c", target_arch = "x86")))] -mul!(__muldi3: u64, u32); +mul!(__muldi3: u64); -mul!(__multi3: i128, i64); +mul!(__multi3: i128); mulo!(__mulosi4: i32); mulo!(__mulodi4: i64); diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 3c5629e1a517e..a1a9503a79e02 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -114,152 +114,159 @@ pub extern "C" fn __umoddi3(a: u64, b: u64) -> u64 { rem } -/// Returns `n / d` and sets `*rem = n % d` -#[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { - // NOTE X is unknown, K != 0 - if n.high() == 0 { - if d.high() == 0 { - // 0 X - // --- - // 0 X +macro_rules! udivmod_inner { + ($n:expr, $d:expr, $rem:expr, $ty:ty) => {{ + let (n, d, rem) = ($n, $d, $rem); + // NOTE X is unknown, K != 0 + if n.high() == 0 { + if d.high() == 0 { + // 0 X + // --- + // 0 X + + if let Some(rem) = rem { + *rem = <$ty>::from(urem!(n.low(), d.low())); + } + return <$ty>::from(udiv!(n.low(), d.low())); + } else { + // 0 X + // --- + // K X + if let Some(rem) = rem { + *rem = n; + } + return 0; + }; + } - if let Some(rem) = rem { - *rem = u64::from(urem!(n.low(), d.low())); + let mut sr; + let mut q; + let mut r; + + if d.low() == 0 { + if d.high() == 0 { + // K X + // --- + // 0 0 + // NOTE This should be unreachable in safe Rust because the program will panic before + // this intrinsic is called + unsafe { + intrinsics::abort() + } } - return u64::from(udiv!(n.low(), d.low())); - } else { - // 0 X - // --- - // K X - if let Some(rem) = rem { - *rem = n; - } - return 0; - }; - } - - let mut sr; - let mut q; - let mut r; - if d.low() == 0 { - if d.high() == 0 { - // K X - // --- - // 0 0 - // NOTE This should be unreachable in safe Rust because the program will panic before - // this intrinsic is called - unsafe { - intrinsics::abort() + if n.low() == 0 { + // K 0 + // --- + // K 0 + if let Some(rem) = rem { + *rem = <$ty>::from_parts(0, urem!(n.high(), d.high())); + } + return <$ty>::from(udiv!(n.high(), d.high())); } - } - if n.low() == 0 { - // K 0 + // K K // --- // K 0 - if let Some(rem) = rem { - *rem = u64::from_parts(0, urem!(n.high(), d.high())); + + if d.high().is_power_of_two() { + if let Some(rem) = rem { + *rem = <$ty>::from_parts(n.low(), n.high() & (d.high() - 1)); + } + return <$ty>::from(n.high() >> d.high().trailing_zeros()); } - return u64::from(udiv!(n.high(), d.high())); - } - // K K - // --- - // K 0 + sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); - if d.high().is_power_of_two() { - if let Some(rem) = rem { - *rem = u64::from_parts(n.low(), n.high() & (d.high() - 1)); + // D > N + if sr > ::bits() - 2 { + if let Some(rem) = rem { + *rem = n; + } + return 0; } - return u64::from(n.high() >> d.high().trailing_zeros()); - } - sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); + sr += 1; - // D > N - if sr > u32::bits() - 2 { - if let Some(rem) = rem { - *rem = n; + // 1 <= sr <= ::bits() - 1 + q = n << (<$ty>::bits() - sr); + r = n >> sr; + } else if d.high() == 0 { + // K X + // --- + // 0 K + if d.low().is_power_of_two() { + if let Some(rem) = rem { + *rem = <$ty>::from(n.low() & (d.low() - 1)); + } + + if d.low() == 1 { + return n; + } else { + let sr = d.low().trailing_zeros(); + return n >> sr; + }; } - return 0; - } - sr += 1; - - // 1 <= sr <= u32::bits() - 1 - q = n << (u64::bits() - sr); - r = n >> sr; - } else if d.high() == 0 { - // K X - // --- - // 0 K - if d.low().is_power_of_two() { - if let Some(rem) = rem { - *rem = u64::from(n.low() & (d.low() - 1)); - } + sr = 1 + ::bits() + d.low().leading_zeros() - n.high().leading_zeros(); - if d.low() == 1 { - return n; - } else { - let sr = d.low().trailing_zeros(); - return n >> sr; - }; - } - - sr = 1 + u32::bits() + d.low().leading_zeros() - n.high().leading_zeros(); - - // 2 <= sr <= u64::bits() - 1 - q = n << (u64::bits() - sr); - r = n >> sr; - } else { - // K X - // --- - // K K - sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); - - // D > N - if sr > u32::bits() - 1 { - if let Some(rem) = rem { - *rem = n; + // 2 <= sr <= u64::bits() - 1 + q = n << (<$ty>::bits() - sr); + r = n >> sr; + } else { + // K X + // --- + // K K + sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); + + // D > N + if sr > ::bits() - 1 { + if let Some(rem) = rem { + *rem = n; + } + return 0; } - return 0; - } - sr += 1; + sr += 1; - // 1 <= sr <= u32::bits() - q = n << (u64::bits() - sr); - r = n >> sr; - } - - // Not a special case - // q and r are initialized with - // q = n << (u64::bits() - sr) - // r = n >> sr - // 1 <= sr <= u64::bits() - 1 - let mut carry = 0; + // 1 <= sr <= ::bits() + q = n << (<$ty>::bits() - sr); + r = n >> sr; + } - for _ in 0..sr { - // r:q = ((r:q) << 1) | carry - r = (r << 1) | (q >> (u64::bits() - 1)); - q = (q << 1) | carry as u64; + // Not a special case + // q and r are initialized with + // q = n << (u64::bits() - sr) + // r = n >> sr + // 1 <= sr <= u64::bits() - 1 + let mut carry = 0; + + for _ in 0..sr { + // r:q = ((r:q) << 1) | carry + r = (r << 1) | (q >> (<$ty>::bits() - 1)); + q = (q << 1) | carry as $ty; + + // carry = 0 + // if r >= d { + // r -= d; + // carry = 1; + // } + let s = (d.wrapping_sub(r).wrapping_sub(1)) as os_ty!($ty) >> (<$ty>::bits() - 1); + carry = (s & 1) as hty!($ty); + r -= d & s as $ty; + } - // carry = 0 - // if r >= d { - // r -= d; - // carry = 1; - // } - let s = (d.wrapping_sub(r).wrapping_sub(1)) as i64 >> (u64::bits() - 1); - carry = (s & 1) as u32; - r -= d & s as u64; - } + if let Some(rem) = rem { + *rem = r; + } + (q << 1) | carry as $ty + }} +} - if let Some(rem) = rem { - *rem = r; - } - (q << 1) | carry as u64 +/// Returns `n / d` and sets `*rem = n % d` +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { + udivmod_inner!(n, d, rem, u64) } #[cfg(test)] From 37a62269dce4a8790aaca7623d0aace955fbd773 Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 5 Jan 2017 15:08:56 +0100 Subject: [PATCH 0240/4206] u128 udiv intrinsics --- library/compiler-builtins/README.md | 6 +- library/compiler-builtins/build.rs | 5 +- library/compiler-builtins/src/int/udiv.rs | 69 ++++++++++++++++++----- library/compiler-builtins/src/lib.rs | 11 ++++ 4 files changed, 71 insertions(+), 20 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 8a8c2d174f65d..7397810ceae37 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -208,9 +208,9 @@ These builtins are needed to support 128-bit integers, which are in the process - [ ] modti3.c - [x] muloti4.c - [x] multi3.c -- [ ] udivmodti4.c -- [ ] udivti3.c -- [ ] umodti3.c +- [x] udivmodti4.c +- [x] udivti3.c +- [x] umodti3.c ## Unimplemented functions diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 082592541d009..5219a0400b419 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -207,10 +207,7 @@ fn main() { "subtf3.c", "subvti3.c", "trampoline_setup.c", - "ucmpti2.c", - "udivmodti4.c", - "udivti3.c", - "umodti3.c"]); + "ucmpti2.c"]); } if target_vendor == "apple" { diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index a1a9503a79e02..44a1149b9b244 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -96,23 +96,44 @@ pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { q } -/// Returns `n / d` -#[cfg_attr(not(test), no_mangle)] -#[cfg(not(all(feature = "c", target_arch = "x86")))] -pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { - __udivmoddi4(n, d, None) +macro_rules! div_mod_intrinsics { + ($udiv_intr:ident, $umod_intr:ident : $ty:ty) => { + div_mod_intrinsics!($udiv_intr, $umod_intr : $ty, + __udivmoddi4); + }; + ($udiv_intr:ident, $umod_intr:ident : $ty:ty, $divmod_intr:expr) => { + div_mod_intrinsics!($udiv_intr, $umod_intr : $ty, + $divmod_intr, $ty, |i|{ i }); + }; + ($udiv_intr:ident, $umod_intr:ident : $ty:ty, $divmod_intr:expr, + $tyret:ty, $conv:expr) => { + /// Returns `n / d` + #[cfg_attr(not(test), no_mangle)] + pub extern "C" fn $udiv_intr(n: $ty, d: $ty) -> $tyret { + let r = $divmod_intr(n, d, None); + ($conv)(r) + } + + /// Returns `n % d` + #[cfg_attr(not(test), no_mangle)] + pub extern "C" fn $umod_intr(a: $ty, b: $ty) -> $tyret { + use core::mem; + + let mut rem = unsafe { mem::uninitialized() }; + $divmod_intr(a, b, Some(&mut rem)); + ($conv)(rem) + } + } } -/// Returns `n % d` #[cfg(not(all(feature = "c", target_arch = "x86")))] -#[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __umoddi3(a: u64, b: u64) -> u64 { - use core::mem; +div_mod_intrinsics!(__udivdi3, __umoddi3: u64); - let mut rem = unsafe { mem::uninitialized() }; - __udivmoddi4(a, b, Some(&mut rem)); - rem -} +#[cfg(not(all(windows, target_pointer_width="64")))] +div_mod_intrinsics!(__udivti3, __umodti3: u128, u128_div_mod); + +#[cfg(all(windows, target_pointer_width="64"))] +div_mod_intrinsics!(__udivti3, __umodti3: u128, u128_div_mod, ::U64x2, ::conv); macro_rules! udivmod_inner { ($n:expr, $d:expr, $rem:expr, $ty:ty) => {{ @@ -269,6 +290,28 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { udivmod_inner!(n, d, rem, u64) } +macro_rules! udivmodti4 { + ($tyret:ty, $conv:expr) => { + /// Returns `n / d` and sets `*rem = n % d` + #[cfg_attr(not(test), no_mangle)] + pub extern "C" fn __udivmodti4(n: u128, d: u128, rem: Option<&mut u128>) -> $tyret { + let r = u128_div_mod(n, d, rem); + ($conv)(r) + } + } +} + +/// Returns `n / d` and sets `*rem = n % d` +fn u128_div_mod(n: u128, d: u128, rem: Option<&mut u128>) -> u128 { + udivmod_inner!(n, d, rem, u128) +} + +#[cfg(all(windows, target_pointer_width="64"))] +udivmodti4!(::U64x2, ::conv); + +#[cfg(not(all(windows, target_pointer_width="64")))] +udivmodti4!(u128, |i|{ i }); + #[cfg(test)] mod tests { use qc::{U32, U64}; diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index f637ff52b96d4..559e1a7270cf8 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -89,6 +89,17 @@ macro_rules! srem { } } +// Hack for LLVM expectations for ABI on windows +#[cfg(all(windows, target_pointer_width="64"))] +#[repr(simd)] +pub struct U64x2(u64, u64); + +#[cfg(all(windows, target_pointer_width="64"))] +fn conv(i: u128) -> U64x2 { + use int::LargeInt; + U64x2(i.low(), i.high()) +} + #[cfg(test)] #[cfg_attr(target_arch = "arm", macro_use)] extern crate quickcheck; From b1561fc1950c333b6ca36b56412351faa410a562 Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 5 Jan 2017 15:23:45 +0100 Subject: [PATCH 0241/4206] u128 sdiv intrinsics --- library/compiler-builtins/README.md | 4 ++-- library/compiler-builtins/build.rs | 2 -- library/compiler-builtins/src/int/sdiv.rs | 26 +++++++++++++++++++---- library/compiler-builtins/src/lib.rs | 7 ++++++ 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 7397810ceae37..0810edf5bd1c0 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -195,7 +195,7 @@ These builtins are needed to support 128-bit integers, which are in the process - [x] ashlti3.c - [x] ashrti3.c -- [ ] divti3.c +- [x] divti3.c - [ ] fixdfti.c - [ ] fixsfti.c - [ ] fixunsdfti.c @@ -205,7 +205,7 @@ These builtins are needed to support 128-bit integers, which are in the process - [ ] floatuntidf.c - [ ] floatuntisf.c - [x] lshrti3.c -- [ ] modti3.c +- [x] modti3.c - [x] muloti4.c - [x] multi3.c - [x] udivmodti4.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 5219a0400b419..ca58b6758b11d 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -182,7 +182,6 @@ fn main() { "cmpti2.c", "ctzti2.c", "divtf3.c", - "divti3.c", "ffsti2.c", "fixdfti.c", "fixsfti.c", @@ -196,7 +195,6 @@ fn main() { "floatuntidf.c", "floatuntisf.c", "floatuntixf.c", - "modti3.c", "multf3.c", "mulvti3.c", "negti2.c", diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index b54132290afb5..84f72f1fdc4e7 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -2,9 +2,12 @@ use int::Int; macro_rules! div { ($intrinsic:ident: $ty:ty, $uty:ty) => { + div!($intrinsic: $ty, $uty, $ty, |i| {i}); + }; + ($intrinsic:ident: $ty:ty, $uty:ty, $tyret:ty, $conv:expr) => { /// Returns `a / b` #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { + pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $tyret { let s_a = a >> (<$ty>::bits() - 1); let s_b = b >> (<$ty>::bits() - 1); let a = (a ^ s_a) - s_a; @@ -12,23 +15,26 @@ macro_rules! div { let s = s_a ^ s_b; let r = udiv!(a as $uty, b as $uty); - (r as $ty ^ s) - s + ($conv)((r as $ty ^ s) - s) } } } macro_rules! mod_ { ($intrinsic:ident: $ty:ty, $uty:ty) => { + mod_!($intrinsic: $ty, $uty, $ty, |i| {i}); + }; + ($intrinsic:ident: $ty:ty, $uty:ty, $tyret:ty, $conv:expr) => { /// Returns `a % b` #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { + pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $tyret { let s = b >> (<$ty>::bits() - 1); let b = (b ^ s) - s; let s = a >> (<$ty>::bits() - 1); let a = (a ^ s) - s; let r = urem!(a as $uty, b as $uty); - (r as $ty ^ s) - s + ($conv)((r as $ty ^ s) - s) } } } @@ -61,12 +67,24 @@ div!(__divsi3: i32, u32); #[cfg(not(all(feature = "c", target_arch = "x86")))] div!(__divdi3: i64, u64); +#[cfg(not(all(windows, target_pointer_width="64")))] +div!(__divti3: i128, u128); + +#[cfg(all(windows, target_pointer_width="64"))] +div!(__divti3: i128, u128, ::U64x2, ::sconv); + #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] mod_!(__modsi3: i32, u32); #[cfg(not(all(feature = "c", target_arch = "x86")))] mod_!(__moddi3: i64, u64); +#[cfg(not(all(windows, target_pointer_width="64")))] +mod_!(__modti3: i128, u128); + +#[cfg(all(windows, target_pointer_width="64"))] +mod_!(__modti3: i128, u128, ::U64x2, ::sconv); + #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] divmod!(__divmodsi4, __divsi3: i32); diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 559e1a7270cf8..0a80ad260c71a 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -100,6 +100,13 @@ fn conv(i: u128) -> U64x2 { U64x2(i.low(), i.high()) } +#[cfg(all(windows, target_pointer_width="64"))] +fn sconv(i: i128) -> U64x2 { + use int::LargeInt; + let j = i as u128; + U64x2(j.low(), j.high()) +} + #[cfg(test)] #[cfg_attr(target_arch = "arm", macro_use)] extern crate quickcheck; From aeda7382d7bf10f16e1ead3184a8ac15696a2a1b Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 6 Jan 2017 06:30:37 +0100 Subject: [PATCH 0242/4206] Add newly implemented intrinsics to test file --- .../compiler-builtins/src/bin/intrinsics.rs | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/library/compiler-builtins/src/bin/intrinsics.rs b/library/compiler-builtins/src/bin/intrinsics.rs index e0b619f55989b..4c5c8842bb9ec 100644 --- a/library/compiler-builtins/src/bin/intrinsics.rs +++ b/library/compiler-builtins/src/bin/intrinsics.rs @@ -12,6 +12,7 @@ #![feature(lang_items)] #![feature(libc)] #![feature(start)] +#![feature(i128_type)] #![no_std] #[cfg(not(thumb))] @@ -300,6 +301,42 @@ mod intrinsics { pub fn umoddi3(a: u64, b: u64) -> u64 { a % b } + + pub fn muloti4(a: u128, b: u128) -> Option { + a.checked_mul(b) + } + + pub fn multi3(a: u128, b: u128) -> u128 { + a.wrapping_mul(b) + } + + pub fn ashlti3(a: u128, b: usize) -> u128 { + a >> b + } + + pub fn ashrti3(a: u128, b: usize) -> u128 { + a << b + } + + pub fn lshrti3(a: i128, b: usize) -> i128 { + a >> b + } + + pub fn udivti3(a: u128, b: u128) -> u128 { + a / b + } + + pub fn umodti3(a: u128, b: u128) -> u128 { + a % b + } + + pub fn divti3(a: i128, b: i128) -> i128 { + a / b + } + + pub fn modti3(a: i128, b: i128) -> i128 { + a % b + } } #[cfg(feature = "c")] @@ -356,6 +393,15 @@ fn run() { bb(powidf2(bb(2.), bb(3))); bb(powisf2(bb(2.), bb(3))); bb(umoddi3(bb(2), bb(3))); + bb(muloti4(bb(2), bb(2))); + bb(multi3(bb(2), bb(2))); + bb(ashlti3(bb(2), bb(2))); + bb(ashrti3(bb(2), bb(2))); + bb(lshrti3(bb(2), bb(2))); + bb(udivti3(bb(2), bb(2))); + bb(umodti3(bb(2), bb(2))); + bb(divti3(bb(2), bb(2))); + bb(modti3(bb(2), bb(2))); } #[cfg(all(feature = "c", not(thumb)))] From f15bf972bd1b41fff714eaf2993ddc621f798502 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 3 Feb 2017 22:06:36 +0100 Subject: [PATCH 0243/4206] Add quickcheck tests --- .../compiler-rt/compiler-rt-cdylib/build.rs | 11 +++++ .../compiler-rt/compiler-rt-cdylib/src/lib.rs | 27 +++++++++++ library/compiler-builtins/src/int/mul.rs | 24 ++++++++++ library/compiler-builtins/src/int/sdiv.rs | 26 +++++++++++ library/compiler-builtins/src/int/shift.rs | 36 +++++++++++++++ library/compiler-builtins/src/int/udiv.rs | 45 +++++++++++++++++++ library/compiler-builtins/src/qc.rs | 2 + 7 files changed, 171 insertions(+) diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs index 4eb76389570a2..5fc18f1eae956 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs @@ -60,6 +60,17 @@ fn main() { "addsf3.c", "powidf2.c", "powisf2.c", + // 128 bit integers + "lshrti3.c", + "modti3.c", + "muloti4.c", + "multi3.c", + "udivmodti4.c", + "udivti3.c", + "umodti3.c", + "ashlti3.c", + "ashrti3.c", + "divti3.c", ]); for src in sources.files.iter() { diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs index 81affa2421ab1..268da50d6f177 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs @@ -58,6 +58,33 @@ declare!(___adddf3, __adddf3); declare!(___powisf2, __powisf2); declare!(___powidf2, __powidf2); +#[cfg(all(not(windows), target_pointer_width="64"))] +pub mod int_128 { + extern { + fn __lshrti3(); + fn __modti3(); + fn __muloti4(); + fn __multi3(); + fn __udivmodti4(); + fn __udivti3(); + fn __umodti3(); + fn __ashlti3(); + fn __ashrti3(); + fn __divti3(); + } + + declare!(___lshrti3, __lshrti3); + declare!(___modti3, __modti3); + declare!(___muloti4, __muloti4); + declare!(___multi3, __multi3); + declare!(___udivmodti4, __udivmodti4); + declare!(___udivti3, __udivti3); + declare!(___umodti3, __umodti3); + declare!(___ashlti3, __ashlti3); + declare!(___ashrti3, __ashrti3); + declare!(___divti3, __divti3); +} + #[lang = "eh_personality"] fn eh_personality() {} #[lang = "panic_fmt"] diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 45a712834649a..c2aece0ea8bd0 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -120,3 +120,27 @@ mod tests { } } } + +#[cfg(test)] +#[cfg(all(not(windows), target_pointer_width="64"))] +mod tests_i128 { + use qc::I128; + + check! { + fn __multi3(f: extern fn(i128, i128) -> i128, a: I128, b: I128) + -> Option { + Some(f(a.0, b.0)) + } + fn __muloti4(f: extern fn(i128, i128, &mut i32) -> i128, + a: I128, + b: I128) -> Option<(i128, i32)> { + let (a, b) = (a.0, b.0); + let mut overflow = 2; + let r = f(a, b, &mut overflow); + if overflow != 0 && overflow != 1 { + return None + } + Some((r, overflow)) + } + } +} diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 84f72f1fdc4e7..97e1939919ae3 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -162,3 +162,29 @@ mod tests { } } } + +#[cfg(test)] +#[cfg(all(not(windows), target_pointer_width="64"))] +mod tests_i128 { + use qc::U128; + + check! { + fn __divti3(f: extern fn(i128, i128) -> i128, n: U128, d: U128) -> Option { + let (n, d) = (n.0 as i128, d.0 as i128); + if d == 0 { + None + } else { + Some(f(n, d)) + } + } + + fn __modti3(f: extern fn(i128, i128) -> i128, n: U128, d: U128) -> Option { + let (n, d) = (n.0 as i128, d.0 as i128); + if d == 0 { + None + } else { + Some(f(n, d)) + } + } + } +} diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 5c8dd5c6a4702..2993d9286bcad 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -103,3 +103,39 @@ mod tests { } } } + +#[cfg(test)] +#[cfg(all(not(windows), target_pointer_width="64"))] +mod tests_i128 { + use qc::{I128, U128}; + + // NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64) + check! { + fn __ashlti3(f: extern fn(u128, u32) -> u128, a: U128, b: u32) -> Option { + let a = a.0; + if b >= 64 { + None + } else { + Some(f(a, b)) + } + } + + fn __ashrti3(f: extern fn(i128, u32) -> i128, a: I128, b: u32) -> Option { + let a = a.0; + if b >= 64 { + None + } else { + Some(f(a, b)) + } + } + + fn __lshrti3(f: extern fn(u128, u32) -> u128, a: U128, b: u32) -> Option { + let a = a.0; + if b >= 128 { + None + } else { + Some(f(a, b)) + } + } + } +} diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 44a1149b9b244..735d388c19909 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -380,3 +380,48 @@ mod tests { } } } + +#[cfg(test)] +#[cfg(all(not(windows), target_pointer_width="64"))] +mod tests_i128 { + use qc::U128; + + check! { + fn __udivti3(f: extern fn(u128, u128) -> u128, + n: U128, + d: U128) -> Option { + let (n, d) = (n.0, d.0); + if d == 0 { + None + } else { + Some(f(n, d)) + } + } + + fn __umodti3(f: extern fn(u128, u128) -> u128, + n: U128, + d: U128) -> Option { + let (n, d) = (n.0, d.0); + if d == 0 { + None + } else { + Some(f(n, d)) + } + } + + fn __udivmodti4(f: extern fn(u128, u128, Option<&mut u128>) -> u128, + n: U128, + d: U128) -> Option { + let (n, d) = (n.0, d.0); + if d == 0 { + None + } else { + // FIXME fix the segfault when the remainder is requested + /*let mut r = 0; + let q = f(n, d, Some(&mut r)); + Some((q, r))*/ + Some(f(n, d, None)) + } + } + } +} diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs index 5dbc56f24a8fb..ea0faaceca5e5 100644 --- a/library/compiler-builtins/src/qc.rs +++ b/library/compiler-builtins/src/qc.rs @@ -144,6 +144,8 @@ macro_rules! arbitrary_large { arbitrary_large!(I64: i64); arbitrary_large!(U64: u64); +arbitrary_large!(I128: i128); +arbitrary_large!(U128: u128); macro_rules! arbitrary_float { ($TY:ident : $ty:ident) => { From a01ee168c43131e01816293a6a8cc1ef375767dc Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 4 Feb 2017 01:39:19 +0100 Subject: [PATCH 0244/4206] Panic when invalid overflow value is returned --- library/compiler-builtins/src/int/mul.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index c2aece0ea8bd0..1ccaf04d6348c 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -102,7 +102,7 @@ mod tests { let mut overflow = 2; let r = f(a, b, &mut overflow); if overflow != 0 && overflow != 1 { - return None + panic!("Invalid value {} for overflow", overflow); } Some((r, overflow)) } @@ -114,7 +114,7 @@ mod tests { let mut overflow = 2; let r = f(a, b, &mut overflow); if overflow != 0 && overflow != 1 { - return None + panic!("Invalid value {} for overflow", overflow); } Some((r, overflow)) } @@ -138,7 +138,7 @@ mod tests_i128 { let mut overflow = 2; let r = f(a, b, &mut overflow); if overflow != 0 && overflow != 1 { - return None + panic!("Invalid value {} for overflow", overflow); } Some((r, overflow)) } From 48ef4907b3cc707aa1d0910058e88e93ef883f51 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 3 Feb 2017 20:00:24 -0500 Subject: [PATCH 0245/4206] add rebuild logic to compiler-rt-cdylib fixes #136 --- .../compiler-rt/compiler-rt-cdylib/build.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs index 4eb76389570a2..a4d53ccf7ff34 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs @@ -62,9 +62,16 @@ fn main() { "powisf2.c", ]); + let builtins_dir = Path::new("compiler-rt/lib/builtins"); for src in sources.files.iter() { - cfg.file(Path::new("compiler-rt/lib/builtins").join(src)); + cfg.file(builtins_dir.join(src)); } cfg.compile("libcompiler-rt.a"); + + println!("cargo:rerun-if-changed=build.rs"); + + for source in sources.files.iter() { + println!("cargo:rerun-if-changed={}", builtins_dir.join(source).display()); + } } From 70bda6dd1cd5424143f331cedea8f9bea5bd58b9 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 4 Feb 2017 12:17:04 +0100 Subject: [PATCH 0246/4206] Disable quickcheck tests on mips Two reasons: * the C versions __divti3 and __modti3 are apparently broken, at least when used in quickcheck. They change their own arguments. * compiler_rt's support for mips is disabled already on clang [1]. Its desireable to support working "cargo test" on that compiler as well, and not greet the tester with linker errors. [1]: http://llvm.org/viewvc/llvm-project?view=revision&revision=224488 --- .../compiler-rt/compiler-rt-cdylib/src/lib.rs | 5 ++++- library/compiler-builtins/src/int/mul.rs | 5 ++++- library/compiler-builtins/src/int/sdiv.rs | 7 +++++-- library/compiler-builtins/src/int/shift.rs | 5 ++++- library/compiler-builtins/src/int/udiv.rs | 5 ++++- 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs index 268da50d6f177..a724614832183 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs @@ -58,7 +58,10 @@ declare!(___adddf3, __adddf3); declare!(___powisf2, __powisf2); declare!(___powidf2, __powidf2); -#[cfg(all(not(windows), target_pointer_width="64"))] +#[cfg(all(not(windows), + not(target_arch = "mips64"), + not(target_arch = "mips64el"), + target_pointer_width="64"))] pub mod int_128 { extern { fn __lshrti3(); diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 1ccaf04d6348c..27709e5214656 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -122,7 +122,10 @@ mod tests { } #[cfg(test)] -#[cfg(all(not(windows), target_pointer_width="64"))] +#[cfg(all(not(windows), + not(target_arch = "mips64"), + not(target_arch = "mips64el"), + target_pointer_width="64"))] mod tests_i128 { use qc::I128; diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 97e1939919ae3..023fad44d3c9e 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -164,11 +164,14 @@ mod tests { } #[cfg(test)] -#[cfg(all(not(windows), target_pointer_width="64"))] +#[cfg(all(not(windows), + not(target_arch = "mips64"), + not(target_arch = "mips64el"), + target_pointer_width="64"))] mod tests_i128 { use qc::U128; - check! { + fn __divti3(f: extern fn(i128, i128) -> i128, n: U128, d: U128) -> Option { let (n, d) = (n.0 as i128, d.0 as i128); if d == 0 { diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 2993d9286bcad..e5dc38fdac501 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -105,7 +105,10 @@ mod tests { } #[cfg(test)] -#[cfg(all(not(windows), target_pointer_width="64"))] +#[cfg(all(not(windows), + not(target_arch = "mips64"), + not(target_arch = "mips64el"), + target_pointer_width="64"))] mod tests_i128 { use qc::{I128, U128}; diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 735d388c19909..57d5fe549d841 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -382,7 +382,10 @@ mod tests { } #[cfg(test)] -#[cfg(all(not(windows), target_pointer_width="64"))] +#[cfg(all(not(windows), + not(target_arch = "mips64"), + not(target_arch = "mips64el"), + target_pointer_width="64"))] mod tests_i128 { use qc::U128; From a13d0e2b137a568eb74c35acc4f356911dd74cd9 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 6 Feb 2017 15:10:02 -0500 Subject: [PATCH 0247/4206] Don't build gcc_personality_v0.c on NetBSD either rust-lang/rust#39425 --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index ca58b6758b11d..16c721c6f3a6b 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -226,7 +226,7 @@ fn main() { sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]); } } else { - if target_os != "freebsd" { + if target_os != "freebsd" && !target.contains("netbsd") { sources.extend(&["gcc_personality_v0.c"]); } From 2c7368702bca9037a14ee5225dd87307e2a8c398 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 6 Feb 2017 15:11:09 -0500 Subject: [PATCH 0248/4206] Don't build any native compiler-builtin components for emscripten rust-lang/rust#36339 --- library/compiler-builtins/build.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 16c721c6f3a6b..6d9801300aab2 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -50,6 +50,12 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); let target = env::var("TARGET").unwrap(); + + // Emscripten's runtime includes all the builtins + if target.contains("emscripten") { + return; + } + let Cfg { ref target_arch, ref target_os, ref target_env, ref target_vendor, .. } = Cfg::new(&target).unwrap_or_else(|e| { writeln!(io::stderr(), "{}", e).ok(); From bdb136a50ea5d086d94fc68e5ca34437b7e7f9da Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 6 Feb 2017 15:11:51 -0500 Subject: [PATCH 0249/4206] libcompiler_builtins: Don't build emutls.c Rather than improving the check, let's ditch emutls.c entirely. rust-lang/rust#38877 --- library/compiler-builtins/build.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 6d9801300aab2..a0e986dd78fda 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -223,10 +223,6 @@ fn main() { "atomic_thread_fence.c"]); } - if target_os != "windows" && target_os != "none" { - sources.extend(&["emutls.c"]); - } - if target_env == "msvc" { if target_arch == "x86_64" { sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]); From 263f16a81b6db6d250cc73a66e985e92d5770450 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 6 Feb 2017 15:12:34 -0500 Subject: [PATCH 0250/4206] travis: Expand the `cross` linux image rust-lang/rust#39111 --- library/compiler-builtins/build.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index a0e986dd78fda..f29a48322a8cb 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -116,7 +116,6 @@ fn main() { "addvdi3.c", "addvsi3.c", "apple_versioning.c", - "clear_cache.c", "clzdi2.c", "clzsi2.c", "cmpdi2.c", From ee172768d27d4dd8ff5b3e4c5f874a580712b55b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 6 Feb 2017 15:13:40 -0500 Subject: [PATCH 0251/4206] std: Remove unused objects from compiler-builtins rust-lang/rust#38623 --- library/compiler-builtins/build.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index f29a48322a8cb..125813e465966 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -181,12 +181,10 @@ fn main() { if target_os != "ios" { sources.extend(&["absvti2.c", - "addtf3.c", "addvti3.c", "clzti2.c", "cmpti2.c", "ctzti2.c", - "divtf3.c", "ffsti2.c", "fixdfti.c", "fixsfti.c", @@ -200,16 +198,12 @@ fn main() { "floatuntidf.c", "floatuntisf.c", "floatuntixf.c", - "multf3.c", "mulvti3.c", "negti2.c", "negvti2.c", "parityti2.c", "popcountti2.c", - "powitf2.c", - "subtf3.c", "subvti3.c", - "trampoline_setup.c", "ucmpti2.c"]); } From c261f82cab8bfab1e700dafa2c6019e64d120c17 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 6 Feb 2017 15:16:16 -0500 Subject: [PATCH 0252/4206] target.contains -> target_os == --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 125813e465966..79fbcf3402da2 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -221,7 +221,7 @@ fn main() { sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]); } } else { - if target_os != "freebsd" && !target.contains("netbsd") { + if target_os != "freebsd" && target_os != "netbsd" { sources.extend(&["gcc_personality_v0.c"]); } From 3a4e6ce2f413b13797fc5fecfc04150926c662b1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 7 Feb 2017 09:41:26 -0500 Subject: [PATCH 0253/4206] use AAPCS calling convention on all aeabi intrinsics also, on ARM, inline(always) the actual implementation of the intrinsics so we end with code like this: ``` 00000000 <__aeabi_dadd>: (implementation here) ``` instead of "trampolines" like this: ``` 00000000 <__aeabi_dadd>: (shuffle registers) (call __adddf3) 00000000 <__adddf3>: (implementation here) ``` closes #116 --- library/compiler-builtins/src/arm.rs | 40 +++++++++++----------- library/compiler-builtins/src/float/add.rs | 3 +- library/compiler-builtins/src/int/mul.rs | 3 +- library/compiler-builtins/src/int/sdiv.rs | 3 +- library/compiler-builtins/src/int/shift.rs | 4 +++ library/compiler-builtins/src/int/udiv.rs | 3 +- library/compiler-builtins/src/lib.rs | 4 +++ 7 files changed, 36 insertions(+), 24 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 345ff241dbe4f..67947a1c8e787 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -62,44 +62,44 @@ pub unsafe fn __aeabi_ldivmod() { // TODO: These aeabi_* functions should be defined as aliases #[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __aeabi_dadd(a: f64, b: f64) -> f64 { +pub extern "aapcs" fn __aeabi_dadd(a: f64, b: f64) -> f64 { ::float::add::__adddf3(a, b) } #[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __aeabi_fadd(a: f32, b: f32) -> f32 { +pub extern "aapcs" fn __aeabi_fadd(a: f32, b: f32) -> f32 { ::float::add::__addsf3(a, b) } #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] #[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __aeabi_idiv(a: i32, b: i32) -> i32 { +pub extern "aapcs" fn __aeabi_idiv(a: i32, b: i32) -> i32 { ::int::sdiv::__divsi3(a, b) } #[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __aeabi_lasr(a: i64, b: u32) -> i64 { +pub extern "aapcs" fn __aeabi_lasr(a: i64, b: u32) -> i64 { ::int::shift::__ashrdi3(a, b) } #[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __aeabi_llsl(a: u64, b: u32) -> u64 { +pub extern "aapcs" fn __aeabi_llsl(a: u64, b: u32) -> u64 { ::int::shift::__ashldi3(a, b) } #[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __aeabi_llsr(a: u64, b: u32) -> u64 { +pub extern "aapcs" fn __aeabi_llsr(a: u64, b: u32) -> u64 { ::int::shift::__lshrdi3(a, b) } #[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __aeabi_lmul(a: u64, b: u64) -> u64 { +pub extern "aapcs" fn __aeabi_lmul(a: u64, b: u64) -> u64 { ::int::mul::__muldi3(a, b) } #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] #[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __aeabi_uidiv(a: u32, b: u32) -> u32 { +pub extern "aapcs" fn __aeabi_uidiv(a: u32, b: u32) -> u32 { ::int::udiv::__udivsi3(a, b) } @@ -113,55 +113,55 @@ extern "C" { // FIXME: The `*4` and `*8` variants should be defined as aliases. #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { +pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { memcpy(dest, src, n); } #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { +pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { memcpy(dest, src, n); } #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { +pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { memcpy(dest, src, n); } #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { +pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { memmove(dest, src, n); } #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { +pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { memmove(dest, src, n); } #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { +pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { memmove(dest, src, n); } // Note the different argument order #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { +pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { memset(dest, c, n); } #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { +pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { memset(dest, c, n); } #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { +pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { memset(dest, c, n); } #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn __aeabi_memclr(dest: *mut u8, n: usize) { +pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { memset(dest, 0, n); } #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn __aeabi_memclr4(dest: *mut u8, n: usize) { +pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { memset(dest, 0, n); } #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn __aeabi_memclr8(dest: *mut u8, n: usize) { +pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { memset(dest, 0, n); } diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 0b2490a8ce9ae..8bb5b4b39c001 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -7,7 +7,8 @@ macro_rules! add { ($intrinsic:ident: $ty:ty) => { /// Returns `a + b` #[allow(unused_parens)] - #[cfg_attr(not(test), no_mangle)] + #[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] + #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] pub extern fn $intrinsic(a: $ty, b: $ty) -> $ty { let one = Wrapping(1 as <$ty as Float>::Int); let zero = Wrapping(0 as <$ty as Float>::Int); diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 27709e5214656..046382ad5b23d 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -4,7 +4,8 @@ use int::Int; macro_rules! mul { ($intrinsic:ident: $ty:ty) => { /// Returns `a * b` - #[cfg_attr(not(test), no_mangle)] + #[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] + #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { let half_bits = <$ty>::bits() / 4; let lower_mask = !0 >> half_bits; diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 023fad44d3c9e..2676428802bcd 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -42,7 +42,8 @@ macro_rules! mod_ { macro_rules! divmod { ($intrinsic:ident, $div:ident: $ty:ty) => { /// Returns `a / b` and sets `*rem = n % d` - #[cfg_attr(not(test), no_mangle)] + #[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] + #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] pub extern "C" fn $intrinsic(a: $ty, b: $ty, rem: &mut $ty) -> $ty { #[cfg(all(feature = "c", any(target_arch = "x86")))] extern { diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index e5dc38fdac501..b93b7bf7afa39 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -4,6 +4,8 @@ macro_rules! ashl { ($intrinsic:ident: $ty:ty) => { /// Returns `a << b`, requires `b < $ty::bits()` #[cfg_attr(not(test), no_mangle)] + #[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] + #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { let half_bits = <$ty>::bits() / 2; if b & half_bits != 0 { @@ -21,6 +23,8 @@ macro_rules! ashr { ($intrinsic:ident: $ty:ty) => { /// Returns arithmetic `a >> b`, requires `b < $ty::bits()` #[cfg_attr(not(test), no_mangle)] + #[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] + #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { let half_bits = <$ty>::bits() / 2; if b & half_bits != 0 { diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 57d5fe549d841..820c4cfba6918 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -3,7 +3,8 @@ use int::{Int, LargeInt}; /// Returns `n / d` #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] +#[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { // Special cases if d == 0 { diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 0a80ad260c71a..0da336e950b15 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -28,6 +28,10 @@ // NOTE cfg(all(feature = "c", ..)) indicate that compiler-rt provides an arch optimized // implementation of that intrinsic and we'll prefer to use that +// NOTE(aapcs, aeabi, arm) ARM targets use intrinsics named __aeabi_* instead of the intrinsics +// that follow "x86 naming convention" (e.g. addsf3). Those aeabi intrinsics must adhere to the +// AAPCS calling convention (`extern "aapcs"`) because that's how LLVM will call them. + // TODO(rust-lang/rust#37029) use e.g. checked_div(_).unwrap_or_else(|| abort()) macro_rules! udiv { ($a:expr, $b:expr) => { From 57deccf6defa78af40ee413b304d986d8b7dea41 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 7 Feb 2017 12:51:18 -0500 Subject: [PATCH 0254/4206] ARM: keep some non-aeabi symbols around - multi3: there's no aeabi equivalent - divmod{s,d}i4: these are directly called by __aeabi_{l,i}divmod - add{s,d}f3: required by the C sub{s,d}f3 implementation but make sure they also use the AAPCS calling convention --- library/compiler-builtins/src/float/add.rs | 20 ++++++++++++++------ library/compiler-builtins/src/int/mul.rs | 20 ++++++++++++++------ library/compiler-builtins/src/int/sdiv.rs | 15 +++++++++------ library/compiler-builtins/src/int/udiv.rs | 6 +++--- 4 files changed, 40 insertions(+), 21 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 8bb5b4b39c001..65a718634fe4d 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -4,12 +4,11 @@ use core::num::Wrapping; use float::Float; macro_rules! add { - ($intrinsic:ident: $ty:ty) => { + ($abi:tt, $intrinsic:ident: $ty:ty) => { /// Returns `a + b` #[allow(unused_parens)] - #[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] - #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] - pub extern fn $intrinsic(a: $ty, b: $ty) -> $ty { + #[cfg_attr(not(test), no_mangle)] + pub extern $abi fn $intrinsic(a: $ty, b: $ty) -> $ty { let one = Wrapping(1 as <$ty as Float>::Int); let zero = Wrapping(0 as <$ty as Float>::Int); @@ -182,8 +181,17 @@ macro_rules! add { } } -add!(__addsf3: f32); -add!(__adddf3: f64); +#[cfg(target_arch = "arm")] +add!("aapcs", __addsf3: f32); + +#[cfg(not(target_arch = "arm"))] +add!("C", __addsf3: f32); + +#[cfg(target_arch = "arm")] +add!("aapcs", __adddf3: f64); + +#[cfg(not(target_arch = "arm"))] +add!("C", __adddf3: f64); // NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabi*, our implementation doesn't // match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 046382ad5b23d..64ceb723124ff 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -2,11 +2,11 @@ use int::LargeInt; use int::Int; macro_rules! mul { - ($intrinsic:ident: $ty:ty) => { + ($(#[$attr:meta])+ | + $abi:tt, $intrinsic:ident: $ty:ty) => { /// Returns `a * b` - #[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] - #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] - pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { + $(#[$attr])+ + pub extern $abi fn $intrinsic(a: $ty, b: $ty) -> $ty { let half_bits = <$ty>::bits() / 4; let lower_mask = !0 >> half_bits; let mut low = (a.low() & lower_mask).wrapping_mul(b.low() & lower_mask); @@ -74,9 +74,17 @@ macro_rules! mulo { } #[cfg(not(all(feature = "c", target_arch = "x86")))] -mul!(__muldi3: u64); +mul!(#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] + #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] + | "C", __muldi3: u64); + +#[cfg(not(target_arch = "arm"))] +mul!(#[cfg_attr(not(test), no_mangle)] + | "C", __multi3: i128); -mul!(__multi3: i128); +#[cfg(target_arch = "arm")] +mul!(#[cfg_attr(not(test), no_mangle)] + | "aapcs", __multi3: i128); mulo!(__mulosi4: i32); mulo!(__mulodi4: i64); diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 2676428802bcd..7a3e6e75733c6 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -40,11 +40,10 @@ macro_rules! mod_ { } macro_rules! divmod { - ($intrinsic:ident, $div:ident: $ty:ty) => { + ($abi:tt, $intrinsic:ident, $div:ident: $ty:ty) => { /// Returns `a / b` and sets `*rem = n % d` - #[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] - #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] - pub extern "C" fn $intrinsic(a: $ty, b: $ty, rem: &mut $ty) -> $ty { + #[cfg_attr(not(test), no_mangle)] + pub extern $abi fn $intrinsic(a: $ty, b: $ty, rem: &mut $ty) -> $ty { #[cfg(all(feature = "c", any(target_arch = "x86")))] extern { fn $div(a: $ty, b: $ty) -> $ty; @@ -87,9 +86,13 @@ mod_!(__modti3: i128, u128); mod_!(__modti3: i128, u128, ::U64x2, ::sconv); #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] -divmod!(__divmodsi4, __divsi3: i32); +divmod!("C", __divmodsi4, __divsi3: i32); + +#[cfg(target_arch = "arm")] +divmod!("aapcs", __divmoddi4, __divdi3: i64); -divmod!(__divmoddi4, __divdi3: i64); +#[cfg(not(target_arch = "arm"))] +divmod!("C", __divmoddi4, __divdi3: i64); #[cfg(test)] mod tests { diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 820c4cfba6918..453ab005e0ad4 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -80,15 +80,15 @@ pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] #[cfg_attr(not(test), no_mangle)] pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { - #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios")))] + #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m)))] extern "C" { fn __udivsi3(n: u32, d: u32) -> u32; } let q = match () { - #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios")))] + #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m)))] () => unsafe { __udivsi3(n, d) }, - #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] + #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] () => __udivsi3(n, d), }; if let Some(rem) = rem { From 0dfe91f7cf2f0c6b498aee45c1575ecd726fa6e4 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 7 Feb 2017 23:07:51 -0500 Subject: [PATCH 0255/4206] adjust the check! macro to accept AAPCS intrinsics --- library/compiler-builtins/src/float/add.rs | 4 +-- library/compiler-builtins/src/float/pow.rs | 4 +-- library/compiler-builtins/src/int/mul.rs | 10 +++---- library/compiler-builtins/src/int/sdiv.rs | 31 ++++++++++++++++------ library/compiler-builtins/src/int/shift.rs | 12 ++++----- library/compiler-builtins/src/int/udiv.rs | 18 ++++++------- library/compiler-builtins/src/qc.rs | 7 +++-- 7 files changed, 52 insertions(+), 34 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 65a718634fe4d..992d149f45824 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -203,14 +203,14 @@ mod tests { use qc::{F32, F64}; check! { - fn __addsf3(f: extern fn(f32, f32) -> f32, + fn __addsf3(f: extern "C" fn(f32, f32) -> f32, a: F32, b: F32) -> Option { Some(F32(f(a.0, b.0))) } - fn __adddf3(f: extern fn(f64, f64) -> f64, + fn __adddf3(f: extern "C" fn(f64, f64) -> f64, a: F64, b: F64) -> Option { Some(F64(f(a.0, b.0))) diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index 290d0f54d95bc..52aba5df68caf 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -34,13 +34,13 @@ mod tests { use qc::{I32, F32, F64}; check! { - fn __powisf2(f: extern fn(f32, i32) -> f32, + fn __powisf2(f: extern "C" fn(f32, i32) -> f32, a: F32, b: I32) -> Option { Some(F32(f(a.0, b.0))) } - fn __powidf2(f: extern fn(f64, i32) -> f64, + fn __powidf2(f: extern "C" fn(f64, i32) -> f64, a: F64, b: I32) -> Option { Some(F64(f(a.0, b.0))) diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 64ceb723124ff..7b0d033b0b4e0 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -99,12 +99,12 @@ mod tests { use qc::{I32, I64, U64}; check! { - fn __muldi3(f: extern fn(u64, u64) -> u64, a: U64, b: U64) + fn __muldi3(f: extern "C" fn(u64, u64) -> u64, a: U64, b: U64) -> Option { Some(f(a.0, b.0)) } - fn __mulosi4(f: extern fn(i32, i32, &mut i32) -> i32, + fn __mulosi4(f: extern "C" fn(i32, i32, &mut i32) -> i32, a: I32, b: I32) -> Option<(i32, i32)> { let (a, b) = (a.0, b.0); @@ -116,7 +116,7 @@ mod tests { Some((r, overflow)) } - fn __mulodi4(f: extern fn(i64, i64, &mut i32) -> i64, + fn __mulodi4(f: extern "C" fn(i64, i64, &mut i32) -> i64, a: I64, b: I64) -> Option<(i64, i32)> { let (a, b) = (a.0, b.0); @@ -139,11 +139,11 @@ mod tests_i128 { use qc::I128; check! { - fn __multi3(f: extern fn(i128, i128) -> i128, a: I128, b: I128) + fn __multi3(f: extern "C" fn(i128, i128) -> i128, a: I128, b: I128) -> Option { Some(f(a.0, b.0)) } - fn __muloti4(f: extern fn(i128, i128, &mut i32) -> i128, + fn __muloti4(f: extern "C" fn(i128, i128, &mut i32) -> i128, a: I128, b: I128) -> Option<(i128, i32)> { let (a, b) = (a.0, b.0); diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 7a3e6e75733c6..51d9c37697651 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -99,7 +99,7 @@ mod tests { use qc::{U32, U64}; check! { - fn __divdi3(f: extern fn(i64, i64) -> i64, n: U64, d: U64) -> Option { + fn __divdi3(f: extern "C" fn(i64, i64) -> i64, n: U64, d: U64) -> Option { let (n, d) = (n.0 as i64, d.0 as i64); if d == 0 { None @@ -108,7 +108,7 @@ mod tests { } } - fn __moddi3(f: extern fn(i64, i64) -> i64, n: U64, d: U64) -> Option { + fn __moddi3(f: extern "C" fn(i64, i64) -> i64, n: U64, d: U64) -> Option { let (n, d) = (n.0 as i64, d.0 as i64); if d == 0 { None @@ -117,7 +117,8 @@ mod tests { } } - fn __divmoddi4(f: extern fn(i64, i64, &mut i64) -> i64, + #[cfg(target_arch = "arm")] + fn __divmoddi4(f: extern "aapcs" fn(i64, i64, &mut i64) -> i64, n: U64, d: U64) -> Option<(i64, i64)> { let (n, d) = (n.0 as i64, d.0 as i64); @@ -130,7 +131,21 @@ mod tests { } } - fn __divsi3(f: extern fn(i32, i32) -> i32, + #[cfg(not(target_arch = "arm"))] + fn __divmoddi4(f: extern "C" fn(i64, i64, &mut i64) -> i64, + n: U64, + d: U64) -> Option<(i64, i64)> { + let (n, d) = (n.0 as i64, d.0 as i64); + if d == 0 { + None + } else { + let mut r = 0; + let q = f(n, d, &mut r); + Some((q, r)) + } + } + + fn __divsi3(f: extern "C" fn(i32, i32) -> i32, n: U32, d: U32) -> Option { let (n, d) = (n.0 as i32, d.0 as i32); @@ -141,7 +156,7 @@ mod tests { } } - fn __modsi3(f: extern fn(i32, i32) -> i32, + fn __modsi3(f: extern "C" fn(i32, i32) -> i32, n: U32, d: U32) -> Option { let (n, d) = (n.0 as i32, d.0 as i32); @@ -152,7 +167,7 @@ mod tests { } } - fn __divmodsi4(f: extern fn(i32, i32, &mut i32) -> i32, + fn __divmodsi4(f: extern "C" fn(i32, i32, &mut i32) -> i32, n: U32, d: U32) -> Option<(i32, i32)> { let (n, d) = (n.0 as i32, d.0 as i32); @@ -176,7 +191,7 @@ mod tests_i128 { use qc::U128; check! { - fn __divti3(f: extern fn(i128, i128) -> i128, n: U128, d: U128) -> Option { + fn __divti3(f: extern "C" fn(i128, i128) -> i128, n: U128, d: U128) -> Option { let (n, d) = (n.0 as i128, d.0 as i128); if d == 0 { None @@ -185,7 +200,7 @@ mod tests_i128 { } } - fn __modti3(f: extern fn(i128, i128) -> i128, n: U128, d: U128) -> Option { + fn __modti3(f: extern "C" fn(i128, i128) -> i128, n: U128, d: U128) -> Option { let (n, d) = (n.0 as i128, d.0 as i128); if d == 0 { None diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index b93b7bf7afa39..fdd2f6ce2b5da 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -79,7 +79,7 @@ mod tests { // NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64) check! { - fn __ashldi3(f: extern fn(u64, u32) -> u64, a: U64, b: u32) -> Option { + fn __ashldi3(f: extern "C" fn(u64, u32) -> u64, a: U64, b: u32) -> Option { let a = a.0; if b >= 64 { None @@ -88,7 +88,7 @@ mod tests { } } - fn __ashrdi3(f: extern fn(i64, u32) -> i64, a: I64, b: u32) -> Option { + fn __ashrdi3(f: extern "C" fn(i64, u32) -> i64, a: I64, b: u32) -> Option { let a = a.0; if b >= 64 { None @@ -97,7 +97,7 @@ mod tests { } } - fn __lshrdi3(f: extern fn(u64, u32) -> u64, a: U64, b: u32) -> Option { + fn __lshrdi3(f: extern "C" fn(u64, u32) -> u64, a: U64, b: u32) -> Option { let a = a.0; if b >= 64 { None @@ -118,7 +118,7 @@ mod tests_i128 { // NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64) check! { - fn __ashlti3(f: extern fn(u128, u32) -> u128, a: U128, b: u32) -> Option { + fn __ashlti3(f: extern "C" fn(u128, u32) -> u128, a: U128, b: u32) -> Option { let a = a.0; if b >= 64 { None @@ -127,7 +127,7 @@ mod tests_i128 { } } - fn __ashrti3(f: extern fn(i128, u32) -> i128, a: I128, b: u32) -> Option { + fn __ashrti3(f: extern "C" fn(i128, u32) -> i128, a: I128, b: u32) -> Option { let a = a.0; if b >= 64 { None @@ -136,7 +136,7 @@ mod tests_i128 { } } - fn __lshrti3(f: extern fn(u128, u32) -> u128, a: U128, b: u32) -> Option { + fn __lshrti3(f: extern "C" fn(u128, u32) -> u128, a: U128, b: u32) -> Option { let a = a.0; if b >= 128 { None diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 453ab005e0ad4..6c125bb750c07 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -318,7 +318,7 @@ mod tests { use qc::{U32, U64}; check! { - fn __udivdi3(f: extern fn(u64, u64) -> u64, n: U64, d: U64) -> Option { + fn __udivdi3(f: extern "C" fn(u64, u64) -> u64, n: U64, d: U64) -> Option { let (n, d) = (n.0, d.0); if d == 0 { None @@ -327,7 +327,7 @@ mod tests { } } - fn __umoddi3(f: extern fn(u64, u64) -> u64, n: U64, d: U64) -> Option { + fn __umoddi3(f: extern "C" fn(u64, u64) -> u64, n: U64, d: U64) -> Option { let (n, d) = (n.0, d.0); if d == 0 { None @@ -336,7 +336,7 @@ mod tests { } } - fn __udivmoddi4(f: extern fn(u64, u64, Option<&mut u64>) -> u64, + fn __udivmoddi4(f: extern "C" fn(u64, u64, Option<&mut u64>) -> u64, n: U64, d: U64) -> Option<(u64, u64)> { let (n, d) = (n.0, d.0); @@ -349,7 +349,7 @@ mod tests { } } - fn __udivsi3(f: extern fn(u32, u32) -> u32, n: U32, d: U32) -> Option { + fn __udivsi3(f: extern "C" fn(u32, u32) -> u32, n: U32, d: U32) -> Option { let (n, d) = (n.0, d.0); if d == 0 { None @@ -358,7 +358,7 @@ mod tests { } } - fn __umodsi3(f: extern fn(u32, u32) -> u32, n: U32, d: U32) -> Option { + fn __umodsi3(f: extern "C" fn(u32, u32) -> u32, n: U32, d: U32) -> Option { let (n, d) = (n.0, d.0); if d == 0 { None @@ -367,7 +367,7 @@ mod tests { } } - fn __udivmodsi4(f: extern fn(u32, u32, Option<&mut u32>) -> u32, + fn __udivmodsi4(f: extern "C" fn(u32, u32, Option<&mut u32>) -> u32, n: U32, d: U32) -> Option<(u32, u32)> { let (n, d) = (n.0, d.0); @@ -391,7 +391,7 @@ mod tests_i128 { use qc::U128; check! { - fn __udivti3(f: extern fn(u128, u128) -> u128, + fn __udivti3(f: extern "C" fn(u128, u128) -> u128, n: U128, d: U128) -> Option { let (n, d) = (n.0, d.0); @@ -402,7 +402,7 @@ mod tests_i128 { } } - fn __umodti3(f: extern fn(u128, u128) -> u128, + fn __umodti3(f: extern "C" fn(u128, u128) -> u128, n: U128, d: U128) -> Option { let (n, d) = (n.0, d.0); @@ -413,7 +413,7 @@ mod tests_i128 { } } - fn __udivmodti4(f: extern fn(u128, u128, Option<&mut u128>) -> u128, + fn __udivmodti4(f: extern "C" fn(u128, u128, Option<&mut u128>) -> u128, n: U128, d: U128) -> Option { let (n, d) = (n.0, d.0); diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs index ea0faaceca5e5..306508f6c48f4 100644 --- a/library/compiler-builtins/src/qc.rs +++ b/library/compiler-builtins/src/qc.rs @@ -240,7 +240,8 @@ arbitrary_float!(F64: f64); // fails. macro_rules! check { ($( - fn $name:ident($f:ident: extern fn($($farg:ty),*) -> $fret:ty, + $(#[$cfg:meta])* + fn $name:ident($f:ident: extern $abi:tt fn($($farg:ty),*) -> $fret:ty, $($arg:ident: $t:ty),*) -> Option<$ret:ty> { @@ -248,7 +249,8 @@ macro_rules! check { } )*) => ( $( - fn $name($f: extern fn($($farg),*) -> $fret, + $(#[$cfg])* + fn $name($f: extern $abi fn($($farg),*) -> $fret, $($arg: $t),*) -> Option<$ret> { $($code)* } @@ -260,6 +262,7 @@ macro_rules! check { use quickcheck::TestResult; $( + $(#[$cfg])* #[test] fn $name() { fn my_check($($arg:$t),*) -> TestResult { From 9916fa670c2ec00e3b1085f27d3144fb3d3d5f60 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 8 Feb 2017 10:10:40 -0500 Subject: [PATCH 0256/4206] implement float subtraction as a + (-b) --- library/compiler-builtins/build.rs | 2 - .../compiler-rt/compiler-rt-cdylib/build.rs | 2 + .../compiler-rt/compiler-rt-cdylib/src/lib.rs | 4 ++ library/compiler-builtins/src/arm.rs | 12 ++++- library/compiler-builtins/src/float/mod.rs | 1 + library/compiler-builtins/src/float/sub.rs | 45 +++++++++++++++++++ 6 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/src/float/sub.rs diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 79fbcf3402da2..532e23217ee3c 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -170,8 +170,6 @@ fn main() { "popcountdi2.c", "popcountsi2.c", "powixf2.c", - "subdf3.c", - "subsf3.c", "subvdi3.c", "subvsi3.c", "truncdfhf2.c", diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs index 269070c4a34c1..0f36143e2f8c8 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs @@ -60,6 +60,8 @@ fn main() { "addsf3.c", "powidf2.c", "powisf2.c", + "subdf3.c", + "subsf3.c", // 128 bit integers "lshrti3.c", "modti3.c", diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs index a724614832183..b76e1fd6fa17a 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs @@ -24,6 +24,8 @@ extern { fn __adddf3(); fn __powisf2(); fn __powidf2(); + fn __subsf3(); + fn __subdf3(); } macro_rules! declare { @@ -57,6 +59,8 @@ declare!(___addsf3, __addsf3); declare!(___adddf3, __adddf3); declare!(___powisf2, __powisf2); declare!(___powidf2, __powidf2); +declare!(___subsf3, __subsf3); +declare!(___subdf3, __subdf3); #[cfg(all(not(windows), not(target_arch = "mips64"), diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 67947a1c8e787..f2027e7b8909d 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -60,7 +60,6 @@ pub unsafe fn __aeabi_ldivmod() { intrinsics::unreachable(); } -// TODO: These aeabi_* functions should be defined as aliases #[cfg_attr(not(test), no_mangle)] pub extern "aapcs" fn __aeabi_dadd(a: f64, b: f64) -> f64 { ::float::add::__adddf3(a, b) @@ -71,6 +70,16 @@ pub extern "aapcs" fn __aeabi_fadd(a: f32, b: f32) -> f32 { ::float::add::__addsf3(a, b) } +#[cfg_attr(not(test), no_mangle)] +pub extern "aapcs" fn __aeabi_dsub(a: f64, b: f64) -> f64 { + ::float::sub::__subdf3(a, b) +} + +#[cfg_attr(not(test), no_mangle)] +pub extern "aapcs" fn __aeabi_fsub(a: f32, b: f32) -> f32 { + ::float::sub::__subsf3(a, b) +} + #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] #[cfg_attr(not(test), no_mangle)] pub extern "aapcs" fn __aeabi_idiv(a: i32, b: i32) -> i32 { @@ -103,6 +112,7 @@ pub extern "aapcs" fn __aeabi_uidiv(a: u32, b: u32) -> u32 { ::int::udiv::__udivsi3(a, b) } +// TODO: These aeabi_* functions should be defined as aliases #[cfg(not(feature = "mem"))] extern "C" { fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 134c32dc7452f..08a1b6d727f88 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -2,6 +2,7 @@ use core::mem; pub mod add; pub mod pow; +pub mod sub; /// Trait for some basic operations on floats pub trait Float: Sized + Copy { diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs new file mode 100644 index 0000000000000..928d73821030e --- /dev/null +++ b/library/compiler-builtins/src/float/sub.rs @@ -0,0 +1,45 @@ +use float::Float; + +macro_rules! sub { + ($(#[$attr:meta])* + | $intrinsic:ident: $ty:ty) => { + /// Returns `a - b` + $(#[$attr])* + pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { + a + <$ty>::from_repr(b.repr() ^ <$ty>::sign_mask()) + } + } +} + +sub!(#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] + #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] + | __subsf3: f32); + +sub!(#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] + #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] + | __subdf3: f64); + +// NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabi*, our implementation doesn't +// match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll +// just avoid testing against them on those targets. Do note that our implementation gives the +// correct answer; gcc_s and compiler-rt are incorrect in this case. +#[cfg(all(test, not(arm_linux)))] +mod tests { + use core::{f32, f64}; + use qc::{F32, F64}; + + check! { + fn __subsf3(f: extern "C" fn(f32, f32) -> f32, + a: F32, + b: F32) + -> Option { + Some(F32(f(a.0, b.0))) + } + + fn __subdf3(f: extern "C" fn(f64, f64) -> f64, + a: F64, + b: F64) -> Option { + Some(F64(f(a.0, b.0))) + } + } +} From f96c8b825044b4374bdefcc4ed3c2905fbe2862f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 19 Feb 2017 15:49:59 -0500 Subject: [PATCH 0257/4206] make the gcc crate optional it's only required when the "c" feature is enabled --- library/compiler-builtins/Cargo.toml | 7 +- library/compiler-builtins/build.rs | 638 ++++++++++++++------------- 2 files changed, 329 insertions(+), 316 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 5fb89f462bc8a..a82aad55fe45a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -6,7 +6,10 @@ version = "0.1.0" [build-dependencies] rustc-cfg = "0.3.0" -gcc = "0.3.36" + +[build-dependencies.gcc] +optional = true +version = "0.3.36" [dev-dependencies] quickcheck = "0.3.1" @@ -16,7 +19,7 @@ compiler-rt = { path = "compiler-rt" } [features] # Build the missing intrinsics from compiler-rt C source code -c = [] +c = ["gcc"] # Mark this crate as the #![compiler_builtins] crate compiler-builtins = [] default = ["compiler-builtins"] diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 532e23217ee3c..6c96284731bc6 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1,18 +1,23 @@ +#[cfg(feature = "c")] extern crate gcc; extern crate rustc_cfg; +#[cfg(feature = "c")] use std::collections::BTreeMap; use std::io::Write; +#[cfg(feature = "c")] use std::path::Path; use std::{env, io, process}; use rustc_cfg::Cfg; +#[cfg(feature = "c")] struct Sources { // SYMBOL -> PATH TO SOURCE map: BTreeMap<&'static str, &'static str>, } +#[cfg(feature = "c")] impl Sources { fn new() -> Sources { Sources { map: BTreeMap::new() } @@ -65,346 +70,351 @@ fn main() { // 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.split('-').collect::>(); - let target_vendor = target_vendor.as_ref().unwrap(); // Build missing intrinsics from compiler-rt C source code - if env::var_os("CARGO_FEATURE_C").is_some() { - let cfg = &mut gcc::Config::new(); - - if target_env == "msvc" { - // Don't pull in extra libraries on MSVC - cfg.flag("/Zl"); - - // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP - cfg.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("-fomit-frame-pointer"); - cfg.flag("-ffreestanding"); - cfg.define("VISIBILITY_HIDDEN", None); - } + match () { + #[cfg(feature = "c")] + () => { + let target_vendor = target_vendor.as_ref().unwrap(); + let cfg = &mut gcc::Config::new(); + + if target_env == "msvc" { + // Don't pull in extra libraries on MSVC + cfg.flag("/Zl"); + + // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP + cfg.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("-fomit-frame-pointer"); + cfg.flag("-ffreestanding"); + cfg.define("VISIBILITY_HIDDEN", None); + } - // NOTE Most of the ARM intrinsics are written in assembly. Tell gcc which arch we are going to - // target to make sure that the assembly implementations really work for the target. If the - // implementation is not valid for the arch, then gcc will error when compiling it. - if llvm_target[0].starts_with("thumb") { - cfg.flag("-mthumb"); + // NOTE Most of the ARM intrinsics are written in assembly. Tell gcc which arch we are going to + // target to make sure that the assembly implementations really work for the target. If the + // implementation is not valid for the arch, then gcc will error when compiling it. + if llvm_target[0].starts_with("thumb") { + cfg.flag("-mthumb"); - if llvm_target.last() == Some(&"eabihf") { - cfg.flag("-mfloat-abi=hard"); + if llvm_target.last() == Some(&"eabihf") { + cfg.flag("-mfloat-abi=hard"); + } } - } - if llvm_target[0] == "thumbv6m" { - cfg.flag("-march=armv6-m"); - } - - if llvm_target[0] == "thumbv7m" { - cfg.flag("-march=armv7-m"); - } + if llvm_target[0] == "thumbv6m" { + cfg.flag("-march=armv6-m"); + } - if llvm_target[0] == "thumbv7em" { - cfg.flag("-march=armv7e-m"); - } + if llvm_target[0] == "thumbv7m" { + cfg.flag("-march=armv7-m"); + } - let mut sources = Sources::new(); - sources.extend(&["absvdi2.c", - "absvsi2.c", - "addvdi3.c", - "addvsi3.c", - "apple_versioning.c", - "clzdi2.c", - "clzsi2.c", - "cmpdi2.c", - "comparedf2.c", - "comparesf2.c", - "ctzdi2.c", - "ctzsi2.c", - "divdc3.c", - "divdf3.c", - "divsc3.c", - "divsf3.c", - "divxc3.c", - "extendsfdf2.c", - "extendhfsf2.c", - "ffsdi2.c", - "fixdfdi.c", - "fixdfsi.c", - "fixsfdi.c", - "fixsfsi.c", - "fixunsdfdi.c", - "fixunsdfsi.c", - "fixunssfdi.c", - "fixunssfsi.c", - "fixunsxfdi.c", - "fixunsxfsi.c", - "fixxfdi.c", - "floatdidf.c", - "floatdisf.c", - "floatdixf.c", - "floatsidf.c", - "floatsisf.c", - "floatundidf.c", - "floatundisf.c", - "floatundixf.c", - "floatunsidf.c", - "floatunsisf.c", - "int_util.c", - "muldc3.c", - "muldf3.c", - "mulsc3.c", - "mulsf3.c", - "mulvdi3.c", - "mulvsi3.c", - "mulxc3.c", - "negdf2.c", - "negdi2.c", - "negsf2.c", - "negvdi2.c", - "negvsi2.c", - "paritydi2.c", - "paritysi2.c", - "popcountdi2.c", - "popcountsi2.c", - "powixf2.c", - "subvdi3.c", - "subvsi3.c", - "truncdfhf2.c", - "truncdfsf2.c", - "truncsfhf2.c", - "ucmpdi2.c"]); - - if target_os != "ios" { - sources.extend(&["absvti2.c", - "addvti3.c", - "clzti2.c", - "cmpti2.c", - "ctzti2.c", - "ffsti2.c", - "fixdfti.c", - "fixsfti.c", - "fixunsdfti.c", - "fixunssfti.c", - "fixunsxfti.c", - "fixxfti.c", - "floattidf.c", - "floattisf.c", - "floattixf.c", - "floatuntidf.c", - "floatuntisf.c", - "floatuntixf.c", - "mulvti3.c", - "negti2.c", - "negvti2.c", - "parityti2.c", - "popcountti2.c", - "subvti3.c", - "ucmpti2.c"]); - } + if llvm_target[0] == "thumbv7em" { + cfg.flag("-march=armv7e-m"); + } - if target_vendor == "apple" { - sources.extend(&["atomic_flag_clear.c", - "atomic_flag_clear_explicit.c", - "atomic_flag_test_and_set.c", - "atomic_flag_test_and_set_explicit.c", - "atomic_signal_fence.c", - "atomic_thread_fence.c"]); - } + let mut sources = Sources::new(); + sources.extend(&["absvdi2.c", + "absvsi2.c", + "addvdi3.c", + "addvsi3.c", + "apple_versioning.c", + "clzdi2.c", + "clzsi2.c", + "cmpdi2.c", + "comparedf2.c", + "comparesf2.c", + "ctzdi2.c", + "ctzsi2.c", + "divdc3.c", + "divdf3.c", + "divsc3.c", + "divsf3.c", + "divxc3.c", + "extendsfdf2.c", + "extendhfsf2.c", + "ffsdi2.c", + "fixdfdi.c", + "fixdfsi.c", + "fixsfdi.c", + "fixsfsi.c", + "fixunsdfdi.c", + "fixunsdfsi.c", + "fixunssfdi.c", + "fixunssfsi.c", + "fixunsxfdi.c", + "fixunsxfsi.c", + "fixxfdi.c", + "floatdidf.c", + "floatdisf.c", + "floatdixf.c", + "floatsidf.c", + "floatsisf.c", + "floatundidf.c", + "floatundisf.c", + "floatundixf.c", + "floatunsidf.c", + "floatunsisf.c", + "int_util.c", + "muldc3.c", + "muldf3.c", + "mulsc3.c", + "mulsf3.c", + "mulvdi3.c", + "mulvsi3.c", + "mulxc3.c", + "negdf2.c", + "negdi2.c", + "negsf2.c", + "negvdi2.c", + "negvsi2.c", + "paritydi2.c", + "paritysi2.c", + "popcountdi2.c", + "popcountsi2.c", + "powixf2.c", + "subvdi3.c", + "subvsi3.c", + "truncdfhf2.c", + "truncdfsf2.c", + "truncsfhf2.c", + "ucmpdi2.c"]); + + if target_os != "ios" { + sources.extend(&["absvti2.c", + "addvti3.c", + "clzti2.c", + "cmpti2.c", + "ctzti2.c", + "ffsti2.c", + "fixdfti.c", + "fixsfti.c", + "fixunsdfti.c", + "fixunssfti.c", + "fixunsxfti.c", + "fixxfti.c", + "floattidf.c", + "floattisf.c", + "floattixf.c", + "floatuntidf.c", + "floatuntisf.c", + "floatuntixf.c", + "mulvti3.c", + "negti2.c", + "negvti2.c", + "parityti2.c", + "popcountti2.c", + "subvti3.c", + "ucmpti2.c"]); + } - if target_env == "msvc" { - if target_arch == "x86_64" { - sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]); + if target_vendor == "apple" { + sources.extend(&["atomic_flag_clear.c", + "atomic_flag_clear_explicit.c", + "atomic_flag_test_and_set.c", + "atomic_flag_test_and_set_explicit.c", + "atomic_signal_fence.c", + "atomic_thread_fence.c"]); } - } else { - if target_os != "freebsd" && target_os != "netbsd" { - sources.extend(&["gcc_personality_v0.c"]); + + if target_env == "msvc" { + if target_arch == "x86_64" { + sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]); + } + } else { + if target_os != "freebsd" && target_os != "netbsd" { + sources.extend(&["gcc_personality_v0.c"]); + } + + if target_arch == "x86_64" { + sources.extend(&["x86_64/chkstk.S", + "x86_64/chkstk2.S", + "x86_64/floatdidf.c", + "x86_64/floatdisf.c", + "x86_64/floatdixf.c", + "x86_64/floatundidf.S", + "x86_64/floatundisf.S", + "x86_64/floatundixf.S"]); + } + + if target_arch == "x86" { + sources.extend(&["i386/ashldi3.S", + "i386/ashrdi3.S", + "i386/chkstk.S", + "i386/chkstk2.S", + "i386/divdi3.S", + "i386/floatdidf.S", + "i386/floatdisf.S", + "i386/floatdixf.S", + "i386/floatundidf.S", + "i386/floatundisf.S", + "i386/floatundixf.S", + "i386/lshrdi3.S", + "i386/moddi3.S", + "i386/muldi3.S", + "i386/udivdi3.S", + "i386/umoddi3.S"]); + } } - if target_arch == "x86_64" { - sources.extend(&["x86_64/chkstk.S", - "x86_64/chkstk2.S", - "x86_64/floatdidf.c", - "x86_64/floatdisf.c", - "x86_64/floatdixf.c", - "x86_64/floatundidf.S", - "x86_64/floatundisf.S", - "x86_64/floatundixf.S"]); + if target_arch == "arm" && target_os != "ios" { + sources.extend(&["arm/aeabi_cdcmp.S", + "arm/aeabi_cdcmpeq_check_nan.c", + "arm/aeabi_cfcmp.S", + "arm/aeabi_cfcmpeq_check_nan.c", + "arm/aeabi_dcmp.S", + "arm/aeabi_div0.c", + "arm/aeabi_drsub.c", + "arm/aeabi_fcmp.S", + "arm/aeabi_frsub.c", + "arm/bswapdi2.S", + "arm/bswapsi2.S", + "arm/clzdi2.S", + "arm/clzsi2.S", + "arm/comparesf2.S", + "arm/divmodsi4.S", + "arm/divsi3.S", + "arm/modsi3.S", + "arm/switch16.S", + "arm/switch32.S", + "arm/switch8.S", + "arm/switchu8.S", + "arm/sync_synchronize.S", + "arm/udivmodsi4.S", + "arm/udivsi3.S", + "arm/umodsi3.S"]); } - if target_arch == "x86" { - sources.extend(&["i386/ashldi3.S", - "i386/ashrdi3.S", - "i386/chkstk.S", - "i386/chkstk2.S", - "i386/divdi3.S", - "i386/floatdidf.S", - "i386/floatdisf.S", - "i386/floatdixf.S", - "i386/floatundidf.S", - "i386/floatundisf.S", - "i386/floatundixf.S", - "i386/lshrdi3.S", - "i386/moddi3.S", - "i386/muldi3.S", - "i386/udivdi3.S", - "i386/umoddi3.S"]); + if llvm_target[0] == "armv7" { + sources.extend(&["arm/sync_fetch_and_add_4.S", + "arm/sync_fetch_and_add_8.S", + "arm/sync_fetch_and_and_4.S", + "arm/sync_fetch_and_and_8.S", + "arm/sync_fetch_and_max_4.S", + "arm/sync_fetch_and_max_8.S", + "arm/sync_fetch_and_min_4.S", + "arm/sync_fetch_and_min_8.S", + "arm/sync_fetch_and_nand_4.S", + "arm/sync_fetch_and_nand_8.S", + "arm/sync_fetch_and_or_4.S", + "arm/sync_fetch_and_or_8.S", + "arm/sync_fetch_and_sub_4.S", + "arm/sync_fetch_and_sub_8.S", + "arm/sync_fetch_and_umax_4.S", + "arm/sync_fetch_and_umax_8.S", + "arm/sync_fetch_and_umin_4.S", + "arm/sync_fetch_and_umin_8.S", + "arm/sync_fetch_and_xor_4.S", + "arm/sync_fetch_and_xor_8.S"]); } - } - if target_arch == "arm" && target_os != "ios" { - sources.extend(&["arm/aeabi_cdcmp.S", - "arm/aeabi_cdcmpeq_check_nan.c", - "arm/aeabi_cfcmp.S", - "arm/aeabi_cfcmpeq_check_nan.c", - "arm/aeabi_dcmp.S", - "arm/aeabi_div0.c", - "arm/aeabi_drsub.c", - "arm/aeabi_fcmp.S", - "arm/aeabi_frsub.c", - "arm/bswapdi2.S", - "arm/bswapsi2.S", - "arm/clzdi2.S", - "arm/clzsi2.S", - "arm/comparesf2.S", - "arm/divmodsi4.S", - "arm/divsi3.S", - "arm/modsi3.S", - "arm/switch16.S", - "arm/switch32.S", - "arm/switch8.S", - "arm/switchu8.S", - "arm/sync_synchronize.S", - "arm/udivmodsi4.S", - "arm/udivsi3.S", - "arm/umodsi3.S"]); - } + if llvm_target.last().unwrap().ends_with("eabihf") { + if !llvm_target[0].starts_with("thumbv7em") { + sources.extend(&["arm/adddf3vfp.S", + "arm/addsf3vfp.S", + "arm/divdf3vfp.S", + "arm/divsf3vfp.S", + "arm/eqdf2vfp.S", + "arm/eqsf2vfp.S", + "arm/extendsfdf2vfp.S", + "arm/fixdfsivfp.S", + "arm/fixsfsivfp.S", + "arm/fixunsdfsivfp.S", + "arm/fixunssfsivfp.S", + "arm/floatsidfvfp.S", + "arm/floatsisfvfp.S", + "arm/floatunssidfvfp.S", + "arm/floatunssisfvfp.S", + "arm/gedf2vfp.S", + "arm/gesf2vfp.S", + "arm/gtdf2vfp.S", + "arm/gtsf2vfp.S", + "arm/ledf2vfp.S", + "arm/lesf2vfp.S", + "arm/ltdf2vfp.S", + "arm/ltsf2vfp.S", + "arm/muldf3vfp.S", + "arm/mulsf3vfp.S", + "arm/nedf2vfp.S", + "arm/nesf2vfp.S", + "arm/restore_vfp_d8_d15_regs.S", + "arm/save_vfp_d8_d15_regs.S", + "arm/subdf3vfp.S", + "arm/subsf3vfp.S"]); + } - if llvm_target[0] == "armv7" { - sources.extend(&["arm/sync_fetch_and_add_4.S", - "arm/sync_fetch_and_add_8.S", - "arm/sync_fetch_and_and_4.S", - "arm/sync_fetch_and_and_8.S", - "arm/sync_fetch_and_max_4.S", - "arm/sync_fetch_and_max_8.S", - "arm/sync_fetch_and_min_4.S", - "arm/sync_fetch_and_min_8.S", - "arm/sync_fetch_and_nand_4.S", - "arm/sync_fetch_and_nand_8.S", - "arm/sync_fetch_and_or_4.S", - "arm/sync_fetch_and_or_8.S", - "arm/sync_fetch_and_sub_4.S", - "arm/sync_fetch_and_sub_8.S", - "arm/sync_fetch_and_umax_4.S", - "arm/sync_fetch_and_umax_8.S", - "arm/sync_fetch_and_umin_4.S", - "arm/sync_fetch_and_umin_8.S", - "arm/sync_fetch_and_xor_4.S", - "arm/sync_fetch_and_xor_8.S"]); - } + sources.extend(&["arm/negdf2vfp.S", "arm/negsf2vfp.S"]); - if llvm_target.last().unwrap().ends_with("eabihf") { - if !llvm_target[0].starts_with("thumbv7em") { - sources.extend(&["arm/adddf3vfp.S", - "arm/addsf3vfp.S", - "arm/divdf3vfp.S", - "arm/divsf3vfp.S", - "arm/eqdf2vfp.S", - "arm/eqsf2vfp.S", - "arm/extendsfdf2vfp.S", - "arm/fixdfsivfp.S", - "arm/fixsfsivfp.S", - "arm/fixunsdfsivfp.S", - "arm/fixunssfsivfp.S", - "arm/floatsidfvfp.S", - "arm/floatsisfvfp.S", - "arm/floatunssidfvfp.S", - "arm/floatunssisfvfp.S", - "arm/gedf2vfp.S", - "arm/gesf2vfp.S", - "arm/gtdf2vfp.S", - "arm/gtsf2vfp.S", - "arm/ledf2vfp.S", - "arm/lesf2vfp.S", - "arm/ltdf2vfp.S", - "arm/ltsf2vfp.S", - "arm/muldf3vfp.S", - "arm/mulsf3vfp.S", - "arm/nedf2vfp.S", - "arm/nesf2vfp.S", - "arm/restore_vfp_d8_d15_regs.S", - "arm/save_vfp_d8_d15_regs.S", - "arm/subdf3vfp.S", - "arm/subsf3vfp.S"]); } - sources.extend(&["arm/negdf2vfp.S", "arm/negsf2vfp.S"]); - - } + if target_arch == "aarch64" { + sources.extend(&["comparetf2.c", + "extenddftf2.c", + "extendsftf2.c", + "fixtfdi.c", + "fixtfsi.c", + "fixtfti.c", + "fixunstfdi.c", + "fixunstfsi.c", + "fixunstfti.c", + "floatditf.c", + "floatsitf.c", + "floatunditf.c", + "floatunsitf.c", + "multc3.c", + "trunctfdf2.c", + "trunctfsf2.c"]); + } - if target_arch == "aarch64" { - sources.extend(&["comparetf2.c", - "extenddftf2.c", - "extendsftf2.c", - "fixtfdi.c", - "fixtfsi.c", - "fixtfti.c", - "fixunstfdi.c", - "fixunstfsi.c", - "fixunstfti.c", - "floatditf.c", - "floatsitf.c", - "floatunditf.c", - "floatunsitf.c", - "multc3.c", - "trunctfdf2.c", - "trunctfsf2.c"]); - } + // Remove the assembly implementations that won't compile for the target + if llvm_target[0] == "thumbv6m" { + sources.remove(&["aeabi_cdcmp", + "aeabi_cfcmp", + "aeabi_dcmp", + "aeabi_fcmp", + "clzdi2", + "clzsi2", + "comparesf2", + "divmodsi4", + "divsi3", + "modsi3", + "switch16", + "switch32", + "switch8", + "switchu8", + "udivmodsi4", + "udivsi3", + "umodsi3"]); + + // But use some generic implementations where possible + sources.extend(&["clzdi2.c", "clzsi2.c"]) + } - // Remove the assembly implementations that won't compile for the target - if llvm_target[0] == "thumbv6m" { - sources.remove(&["aeabi_cdcmp", - "aeabi_cfcmp", - "aeabi_dcmp", - "aeabi_fcmp", - "clzdi2", - "clzsi2", - "comparesf2", - "divmodsi4", - "divsi3", - "modsi3", - "switch16", - "switch32", - "switch8", - "switchu8", - "udivmodsi4", - "udivsi3", - "umodsi3"]); - - // But use some generic implementations where possible - sources.extend(&["clzdi2.c", "clzsi2.c"]) - } + if llvm_target[0] == "thumbv7m" || llvm_target[0] == "thumbv7em" { + sources.remove(&["aeabi_cdcmp", "aeabi_cfcmp"]); + } - if llvm_target[0] == "thumbv7m" || llvm_target[0] == "thumbv7em" { - sources.remove(&["aeabi_cdcmp", "aeabi_cfcmp"]); - } + let root = if env::var_os("CARGO_FEATURE_RUSTBUILD").is_some() { + Path::new("../../libcompiler_builtins") + } else { + Path::new(".") + }; + + let src_dir = root.join("compiler-rt/compiler-rt-cdylib/compiler-rt/lib/builtins"); + for src in sources.map.values() { + let src = src_dir.join(src); + cfg.file(&src); + println!("cargo:rerun-if-changed={}", src.display()); + } - let root = if env::var_os("CARGO_FEATURE_RUSTBUILD").is_some() { - Path::new("../../libcompiler_builtins") - } else { - Path::new(".") - }; - - let src_dir = root.join("compiler-rt/compiler-rt-cdylib/compiler-rt/lib/builtins"); - for src in sources.map.values() { - let src = src_dir.join(src); - cfg.file(&src); - println!("cargo:rerun-if-changed={}", src.display()); + cfg.compile("libcompiler-rt.a"); } - - cfg.compile("libcompiler-rt.a"); + #[cfg(not(feature = "c"))] + () => {} } // To filter away some flaky test (see src/float/add.rs for details) From cd96f5305064ef4eb6551c329c4cd4d2f5e6588d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 6 Mar 2017 10:34:27 -0500 Subject: [PATCH 0258/4206] fix infinite recursion in divmoddi4 / mulodi4 on ARMv7-M processors, divmoddi4 was calling mulodi4 and mulodi4 was calling divmoddi4 leading to infinite recursion. This commit breaks the cycle by using wrapping multiplication in divmoddi4. fixes #145 --- library/compiler-builtins/src/int/sdiv.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 51d9c37697651..d00f89a278813 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -55,7 +55,9 @@ macro_rules! divmod { #[cfg(all(feature = "c", any(target_arch = "x86")))] () => unsafe { $div(a, b) }, }; - *rem = a - (r * b); + // NOTE won't overflow because it's using the result from the + // previous division + *rem = a - r.wrapping_mul(b); r } } From b3e33508a057206a5b486ba35c4efd065f2b714c Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Tue, 6 Dec 2016 05:16:19 +0100 Subject: [PATCH 0259/4206] impl (unsigned/signed) int to single/double precision float conversion based on llvm algorithms. --- .../compiler-rt/compiler-rt-cdylib/build.rs | 6 + .../compiler-rt/compiler-rt-cdylib/src/lib.rs | 12 ++ library/compiler-builtins/src/arm.rs | 6 + library/compiler-builtins/src/float/conv.rs | 133 ++++++++++++++++++ library/compiler-builtins/src/float/mod.rs | 10 ++ library/compiler-builtins/src/int/mod.rs | 87 +++++++++--- 6 files changed, 238 insertions(+), 16 deletions(-) mode change 100644 => 100755 library/compiler-builtins/src/arm.rs create mode 100755 library/compiler-builtins/src/float/conv.rs mode change 100644 => 100755 library/compiler-builtins/src/int/mod.rs diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs index 0f36143e2f8c8..98c5f884f3048 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs @@ -62,6 +62,12 @@ fn main() { "powisf2.c", "subdf3.c", "subsf3.c", + "floatsisf.c", + "floatsidf.c", + "floatdidf.c", + "floatunsisf.c", + "floatunsidf.c", + "floatundidf.c", // 128 bit integers "lshrti3.c", "modti3.c", diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs index b76e1fd6fa17a..e72613ad0b1a6 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs @@ -26,6 +26,12 @@ extern { fn __powidf2(); fn __subsf3(); fn __subdf3(); + fn __floatsisf(); + fn __floatsidf(); + fn __floatdidf(); + fn __floatunsisf(); + fn __floatunsidf(); + fn __floatundidf(); } macro_rules! declare { @@ -61,6 +67,12 @@ declare!(___powisf2, __powisf2); declare!(___powidf2, __powidf2); declare!(___subsf3, __subsf3); declare!(___subdf3, __subdf3); +declare!(___floatsisf, __floatsisf); +declare!(___floatsidf, __floatsidf); +declare!(___floatdidf, __floatdidf); +declare!(___floatunsisf, __floatunsisf); +declare!(___floatunsidf, __floatunsidf); +declare!(___floatundidf, __floatundidf); #[cfg(all(not(windows), not(target_arch = "mips64"), diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs old mode 100644 new mode 100755 index f2027e7b8909d..63f52500d4bcc --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -112,6 +112,12 @@ pub extern "aapcs" fn __aeabi_uidiv(a: u32, b: u32) -> u32 { ::int::udiv::__udivsi3(a, b) } +#[cfg(not(feature = "c"))] +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __aeabi_ui2d(a: u32) -> f64 { + ::float::conv::__floatunsidf(a) +} + // TODO: These aeabi_* functions should be defined as aliases #[cfg(not(feature = "mem"))] extern "C" { diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs new file mode 100755 index 0000000000000..629af3c63533f --- /dev/null +++ b/library/compiler-builtins/src/float/conv.rs @@ -0,0 +1,133 @@ +use float::Float; +use int::Int; + +macro_rules! fp_overflow { + (infinity, $fty:ty, $sign: expr) => { + return { + <$fty as Float>::from_parts( + $sign, + <$fty as Float>::exponent_max() as <$fty as Float>::Int, + 0 as <$fty as Float>::Int) + } + } +} + +macro_rules! fp_convert { + ($intrinsic:ident: $ity:ty, $fty:ty) => { + + pub extern "C" fn $intrinsic(i: $ity) -> $fty { + if i == 0 { + return 0.0 + } + + let mant_dig = <$fty>::significand_bits() + 1; + let exponent_bias = <$fty>::exponent_bias(); + + let n = <$ity>::bits(); + let (s, a) = i.extract_sign(); + let mut a = a; + + // number of significant digits + let sd = n - a.leading_zeros(); + + // exponent + let mut e = sd - 1; + + if <$ity>::bits() < mant_dig { + return <$fty>::from_parts(s, + (e + exponent_bias) as <$fty as Float>::Int, + (a as <$fty as Float>::Int) << (mant_dig - e - 1)) + } + + a = if sd > mant_dig { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit MANT_DIG-1 bits to the right of 1 + * Q = bit MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + let mant_dig_plus_one = mant_dig + 1; + let mant_dig_plus_two = mant_dig + 2; + a = if sd == mant_dig_plus_one { + a << 1 + } else if sd == mant_dig_plus_two { + a + } else { + (a >> (sd - mant_dig_plus_two)) as <$ity as Int>::UnsignedInt | + ((a & <$ity as Int>::UnsignedInt::max_value()).wrapping_shl((n + mant_dig_plus_two) - sd) != 0) as <$ity as Int>::UnsignedInt + }; + + /* finish: */ + a |= ((a & 4) != 0) as <$ity as Int>::UnsignedInt; /* Or P into R */ + a += 1; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + + /* a is now rounded to mant_dig or mant_dig+1 bits */ + if (a & (1 << mant_dig)) != 0 { + a >>= 1; e += 1; + } + a + /* a is now rounded to mant_dig bits */ + } else { + a.wrapping_shl(mant_dig - sd) + /* a is now rounded to mant_dig bits */ + }; + + <$fty>::from_parts(s, + (e + exponent_bias) as <$fty as Float>::Int, + a as <$fty as Float>::Int) + } + } +} + +fp_convert!(__floatsisf: i32, f32); +fp_convert!(__floatsidf: i32, f64); +fp_convert!(__floatdidf: i64, f64); +fp_convert!(__floatunsisf: u32, f32); +fp_convert!(__floatunsidf: u32, f64); +fp_convert!(__floatundidf: u64, f64); + +// NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabihf, our implementation doesn't +// match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll +// just avoid testing against them on those targets. Do note that our implementation gives the +// correct answer; gcc_s and compiler-rt are incorrect in this case. +// +#[cfg(all(test, not(arm_linux)))] +mod tests { + use qc::{I32, U32, I64, U64, F32, F64}; + + check! { + fn __floatsisf(f: extern fn(i32) -> f32, + a: I32) + -> Option { + Some(F32(f(a.0))) + } + fn __floatsidf(f: extern fn(i32) -> f64, + a: I32) + -> Option { + Some(F64(f(a.0))) + } + fn __floatdidf(f: extern fn(i64) -> f64, + a: I64) + -> Option { + Some(F64(f(a.0))) + } + fn __floatunsisf(f: extern fn(u32) -> f32, + a: U32) + -> Option { + Some(F32(f(a.0))) + } + fn __floatunsidf(f: extern fn(u32) -> f64, + a: U32) + -> Option { + Some(F64(f(a.0))) + } + fn __floatundidf(f: extern fn(u64) -> f64, + a: U64) + -> Option { + Some(F64(f(a.0))) + } + } +} diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 08a1b6d727f88..6176d5ab17952 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,5 +1,6 @@ use core::mem; +pub mod conv; pub mod add; pub mod pow; pub mod sub; @@ -19,6 +20,15 @@ pub trait Float: Sized + Copy { fn exponent_bits() -> u32 { Self::bits() - Self::significand_bits() - 1 } + /// Returns the maximum value of the exponent + fn exponent_max() -> u32 { + (1 << Self::exponent_bits()) - 1 + } + + /// Returns the exponent bias value + fn exponent_bias() -> u32 { + Self::exponent_max() >> 1 + } /// Returns a mask for the sign bit fn sign_mask() -> Self::Int; diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs old mode 100644 new mode 100755 index 647410ccbf8ef..4fc8c19f22c18 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -19,30 +19,85 @@ pub mod udiv; pub trait Int { /// Type with the same width but other signedness type OtherSign; + /// Unsigned version of Self + type UnsignedInt; + /// Returns the bitwidth of the int type fn bits() -> u32; + + /// Extracts the sign from self and returns a tuple. + /// + /// # Examples + /// + /// ```rust,ignore + /// let i = -25_i32; + /// let (sign, u) = i.extract_sign(); + /// assert_eq!(sign, true); + /// assert_eq!(u, 25_u32); + /// ``` + fn extract_sign(self) -> (bool, Self::UnsignedInt); } -macro_rules! int_impl { - ($ity:ty, $sty:ty, $bits:expr) => { - impl Int for $ity { - type OtherSign = $sty; - fn bits() -> u32 { - $bits - } - } - impl Int for $sty { - type OtherSign = $ity; - fn bits() -> u32 { - $bits - } +// TODO: Once i128/u128 support lands, we'll want to add impls for those as well +impl Int for u32 { + type OtherSign = i32; + type UnsignedInt = u32; + + fn bits() -> u32 { + 32 + } + + fn extract_sign(self) -> (bool, u32) { + (false, self) + } +} + +impl Int for i32 { + type OtherSign = u32; + type UnsignedInt = u32; + + fn bits() -> u32 { + 32 + } + + fn extract_sign(self) -> (bool, u32) { + if self < 0 { + (true, !(self as u32) + 1) + } else { + (false, self as u32) } } } -int_impl!(i32, u32, 32); -int_impl!(i64, u64, 64); -int_impl!(i128, u128, 128); +impl Int for u64 { + type OtherSign = i64; + type UnsignedInt = u64; + + fn bits() -> u32 { + 64 + } + + fn extract_sign(self) -> (bool, u64) { + (false, self) + } +} + +impl Int for i64 { + type OtherSign = u64; + type UnsignedInt = u64; + + fn bits() -> u32 { + 64 + } + + fn extract_sign(self) -> (bool, u64) { + if self < 0 { + (true, !(self as u64) + 1) + } else { + (false, self as u64) + } + } +} /// Trait to convert an integer to/from smaller parts pub trait LargeInt { From ef3de28eaff1e1539b4a77a89fd52f675ddb01bb Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Sun, 5 Feb 2017 10:57:36 +0100 Subject: [PATCH 0260/4206] implement float/double to (u)int conversion. --- .../compiler-rt/compiler-rt-cdylib/build.rs | 8 ++ .../compiler-rt/compiler-rt-cdylib/src/lib.rs | 16 +++ library/compiler-builtins/src/float/conv.rs | 109 ++++++++++++++++++ library/compiler-builtins/src/float/mod.rs | 10 ++ library/compiler-builtins/src/qc.rs | 4 +- 5 files changed, 145 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs index 98c5f884f3048..c07ea70cfd9d8 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs @@ -68,6 +68,14 @@ fn main() { "floatunsisf.c", "floatunsidf.c", "floatundidf.c", + "fixsfsi.c", + "fixsfdi.c", + "fixdfsi.c", + "fixdfdi.c", + "fixunssfsi.c", + "fixunssfdi.c", + "fixunsdfsi.c", + "fixunsdfdi.c", // 128 bit integers "lshrti3.c", "modti3.c", diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs index e72613ad0b1a6..2f08314bb88c3 100644 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs +++ b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs @@ -32,6 +32,14 @@ extern { fn __floatunsisf(); fn __floatunsidf(); fn __floatundidf(); + fn __fixsfsi(); + fn __fixsfdi(); + fn __fixdfsi(); + fn __fixdfdi(); + fn __fixunssfsi(); + fn __fixunssfdi(); + fn __fixunsdfsi(); + fn __fixunsdfdi(); } macro_rules! declare { @@ -73,6 +81,14 @@ declare!(___floatdidf, __floatdidf); declare!(___floatunsisf, __floatunsisf); declare!(___floatunsidf, __floatunsidf); declare!(___floatundidf, __floatundidf); +declare!(___fixsfsi, __fixsfsi); +declare!(___fixsfdi, __fixsfdi); +declare!(___fixdfsi, __fixdfsi); +declare!(___fixdfdi, __fixdfdi); +declare!(___fixunssfsi, __fixunssfsi); +declare!(___fixunssfdi, __fixunssfdi); +declare!(___fixunsdfsi, __fixunsdfsi); +declare!(___fixunsdfdi, __fixunsdfdi); #[cfg(all(not(windows), not(target_arch = "mips64"), diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 629af3c63533f..93437c84057f3 100755 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -89,6 +89,73 @@ fp_convert!(__floatunsisf: u32, f32); fp_convert!(__floatunsidf: u32, f64); fp_convert!(__floatundidf: u64, f64); +#[derive(PartialEq, Debug)] +enum Sign { + Positive, + Negative +} +macro_rules! fp_fix { + ($intrinsic:ident: $fty:ty, $ity:ty) => { + pub extern "C" fn $intrinsic(f: $fty) -> $ity { + let fixint_min = <$ity>::min_value(); + let fixint_max = <$ity>::max_value(); + let fixint_bits = <$ity>::bits() as usize; + let fixint_unsigned = fixint_min == 0; + + let sign_bit = <$fty>::sign_mask(); + let significand_bits = <$fty>::significand_bits() as usize; + let exponent_bias = <$fty>::exponent_bias() as usize; + //let exponent_max = <$fty>::exponent_max() as usize; + + // Break a into sign, exponent, significand + let a_rep = <$fty>::repr(f); + let a_abs = a_rep & !sign_bit; + + // this is used to work around -1 not being available for unsigned + let sign = if (a_rep & sign_bit) == 0 { Sign::Positive } else { Sign::Negative }; + let mut exponent = (a_abs >> significand_bits) as usize; + let significand = (a_abs & <$fty>::significand_mask()) | <$fty>::implicit_bit(); + + // if < 1 or unsigned & negative + if exponent < exponent_bias || + fixint_unsigned && sign == Sign::Negative { + return 0 + } + exponent -= exponent_bias; + + // If the value is infinity, saturate. + // If the value is too large for the integer type, 0. + if exponent >= (if fixint_unsigned {fixint_bits} else {fixint_bits -1}) { + return if sign == Sign::Positive {fixint_max} else {fixint_min} + } + // If 0 <= exponent < significand_bits, right shift to get the result. + // Otherwise, shift left. + // (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned + let r = if exponent < significand_bits { + (significand >> (significand_bits - exponent)) as $ity + } else { + (significand as $ity) << (exponent - significand_bits) + }; + + if sign == Sign::Negative { + (!r).wrapping_add(1) + } else { + r + } + } + } +} + +fp_fix!(__fixsfsi: f32, i32); +fp_fix!(__fixsfdi: f32, i64); +fp_fix!(__fixdfsi: f64, i32); +fp_fix!(__fixdfdi: f64, i64); + +fp_fix!(__fixunssfsi: f32, u32); +fp_fix!(__fixunssfdi: f32, u64); +fp_fix!(__fixunsdfsi: f64, u32); +fp_fix!(__fixunsdfdi: f64, u64); + // NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabihf, our implementation doesn't // match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll // just avoid testing against them on those targets. Do note that our implementation gives the @@ -129,5 +196,47 @@ mod tests { -> Option { Some(F64(f(a.0))) } + + fn __fixsfsi(f: extern fn(f32) -> i32, + a: F32) + -> Option { + Some(I32(f(a.0))) + } + fn __fixsfdi(f: extern fn(f32) -> i64, + a: F32) + -> Option { + Some(I64(f(a.0))) + } + fn __fixdfsi(f: extern fn(f64) -> i32, + a: F64) + -> Option { + Some(I32(f(a.0))) + } + fn __fixdfdi(f: extern fn(f64) -> i64, + a: F64) + -> Option { + Some(I64(f(a.0))) + } + + fn __fixunssfsi(f: extern fn(f32) -> u32, + a: F32) + -> Option { + Some(U32(f(a.0))) + } + fn __fixunssfdi(f: extern fn(f32) -> u64, + a: F32) + -> Option { + Some(U64(f(a.0))) + } + fn __fixunsdfsi(f: extern fn(f64) -> u32, + a: F64) + -> Option { + Some(U32(f(a.0))) + } + fn __fixunsdfdi(f: extern fn(f64) -> u64, + a: F64) + -> Option { + Some(U64(f(a.0))) + } } } diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 6176d5ab17952..46e3e5d9585f0 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -36,6 +36,9 @@ pub trait Float: Sized + Copy { /// Returns a mask for the significand fn significand_mask() -> Self::Int; + // Returns the implicit bit of the float format + fn implicit_bit() -> Self::Int; + /// Returns a mask for the exponent fn exponent_mask() -> Self::Int; @@ -68,6 +71,9 @@ impl Float for f32 { fn significand_bits() -> u32 { 23 } + fn implicit_bit() -> Self::Int { + 1 << Self::significand_bits() + } fn sign_mask() -> Self::Int { 1 << (Self::bits() - 1) } @@ -110,6 +116,10 @@ impl Float for f64 { fn significand_bits() -> u32 { 52 } + // Returns the implicit bit of the float format + fn implicit_bit() -> Self::Int { + 1 << Self::significand_bits() + } fn sign_mask() -> Self::Int { 1 << (Self::bits() - 1) } diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs index 306508f6c48f4..675bcc67702fc 100644 --- a/library/compiler-builtins/src/qc.rs +++ b/library/compiler-builtins/src/qc.rs @@ -15,7 +15,7 @@ use float::Float; // Generates values in the full range of the integer type macro_rules! arbitrary { ($TY:ident : $ty:ident) => { - #[derive(Clone, Copy)] + #[derive(Clone, Copy, PartialEq)] pub struct $TY(pub $ty); impl Arbitrary for $TY { @@ -82,7 +82,7 @@ arbitrary!(U32: u32); // intrinsics. macro_rules! arbitrary_large { ($TY:ident : $ty:ident) => { - #[derive(Clone, Copy)] + #[derive(Clone, Copy, PartialEq)] pub struct $TY(pub $ty); impl Arbitrary for $TY { From 77889226f7159a333543aee468361bb707061e84 Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Mon, 6 Feb 2017 06:26:55 +0100 Subject: [PATCH 0261/4206] exclude from tests values out of integer range (and NaN). --- library/compiler-builtins/src/float/conv.rs | 40 ++++++++++++++++----- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 93437c84057f3..00259ecddda49 100755 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -200,43 +200,67 @@ mod tests { fn __fixsfsi(f: extern fn(f32) -> i32, a: F32) -> Option { - Some(I32(f(a.0))) + if a.0 > (i32::max_value() as f32) || + a.0 < (i32::min_value() as f32) || a.0.is_nan() { + None + } else { Some(I32(f(a.0))) } } fn __fixsfdi(f: extern fn(f32) -> i64, a: F32) -> Option { - Some(I64(f(a.0))) + if a.0 > (i64::max_value() as f32) || + a.0 < (i64::min_value() as f32) || a.0.is_nan() { + None + } else { Some(I64(f(a.0))) } } fn __fixdfsi(f: extern fn(f64) -> i32, a: F64) -> Option { - Some(I32(f(a.0))) + if a.0 > (i32::max_value() as f64) || + a.0 < (i32::min_value() as f64) || a.0.is_nan() { + None + } else { Some(I32(f(a.0))) } } fn __fixdfdi(f: extern fn(f64) -> i64, a: F64) -> Option { - Some(I64(f(a.0))) + if a.0 > (i64::max_value() as f64) || + a.0 < (i64::min_value() as f64) || a.0.is_nan() { + None + } else { Some(I64(f(a.0))) } } fn __fixunssfsi(f: extern fn(f32) -> u32, a: F32) -> Option { - Some(U32(f(a.0))) + if a.0 > (u32::max_value() as f32) || + a.0 < (u32::min_value() as f32) || a.0.is_nan() { + None + } else { Some(U32(f(a.0))) } } fn __fixunssfdi(f: extern fn(f32) -> u64, a: F32) -> Option { - Some(U64(f(a.0))) + if a.0 > (u64::max_value() as f32) || + a.0 < (u64::min_value() as f32) || a.0.is_nan() { + None + } else { Some(U64(f(a.0))) } } fn __fixunsdfsi(f: extern fn(f64) -> u32, a: F64) -> Option { - Some(U32(f(a.0))) + if a.0 > (u32::max_value() as f64) || + a.0 < (u32::min_value() as f64) || a.0.is_nan() { + None + } else { Some(U32(f(a.0))) } } fn __fixunsdfdi(f: extern fn(f64) -> u64, a: F64) -> Option { - Some(U64(f(a.0))) + if a.0 <= (u64::max_value() as f64) || + a.0 >= (u64::min_value() as f64) || a.0.is_nan() { + None + } else { Some(U64(f(a.0))) } } } } From 1f26fea5d47b219488c9b792f6d911c1edbe6b76 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 6 Mar 2017 12:17:10 -0500 Subject: [PATCH 0262/4206] refactor 'impl Int' --- library/compiler-builtins/src/int/mod.rs | 81 +++++++++--------------- 1 file changed, 29 insertions(+), 52 deletions(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 4fc8c19f22c18..a94a070ca062d 100755 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -38,67 +38,44 @@ pub trait Int { fn extract_sign(self) -> (bool, Self::UnsignedInt); } -// TODO: Once i128/u128 support lands, we'll want to add impls for those as well -impl Int for u32 { - type OtherSign = i32; - type UnsignedInt = u32; - - fn bits() -> u32 { - 32 - } - - fn extract_sign(self) -> (bool, u32) { - (false, self) - } -} - -impl Int for i32 { - type OtherSign = u32; - type UnsignedInt = u32; - - fn bits() -> u32 { - 32 - } +macro_rules! int_impl { + ($ity:ty, $uty:ty, $bits:expr) => { + impl Int for $uty { + type OtherSign = $ity; + type UnsignedInt = $uty; + + fn bits() -> u32 { + $bits + } - fn extract_sign(self) -> (bool, u32) { - if self < 0 { - (true, !(self as u32) + 1) - } else { - (false, self as u32) + fn extract_sign(self) -> (bool, $uty) { + (false, self) + } } - } -} - -impl Int for u64 { - type OtherSign = i64; - type UnsignedInt = u64; - - fn bits() -> u32 { - 64 - } - fn extract_sign(self) -> (bool, u64) { - (false, self) - } -} + impl Int for $ity { + type OtherSign = $uty; + type UnsignedInt = $uty; -impl Int for i64 { - type OtherSign = u64; - type UnsignedInt = u64; - - fn bits() -> u32 { - 64 - } + fn bits() -> u32 { + $bits + } - fn extract_sign(self) -> (bool, u64) { - if self < 0 { - (true, !(self as u64) + 1) - } else { - (false, self as u64) + fn extract_sign(self) -> (bool, $uty) { + if self < 0 { + (true, !(self as $uty) + 1) + } else { + (false, self as $uty) + } + } } } } +int_impl!(i32, u32, 32); +int_impl!(i64, u64, 64); +int_impl!(i128, u128, 128); + /// Trait to convert an integer to/from smaller parts pub trait LargeInt { type LowHalf; From 0ecfe751b5e26db8fe86316f5af269cce6a11a42 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 6 Mar 2017 12:17:41 -0500 Subject: [PATCH 0263/4206] fix quickcheck tests the check! macro syntax has changed --- library/compiler-builtins/src/float/conv.rs | 28 ++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 00259ecddda49..75a392efce191 100755 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -166,38 +166,38 @@ mod tests { use qc::{I32, U32, I64, U64, F32, F64}; check! { - fn __floatsisf(f: extern fn(i32) -> f32, + fn __floatsisf(f: extern "C" fn(i32) -> f32, a: I32) -> Option { Some(F32(f(a.0))) } - fn __floatsidf(f: extern fn(i32) -> f64, + fn __floatsidf(f: extern "C" fn(i32) -> f64, a: I32) -> Option { Some(F64(f(a.0))) } - fn __floatdidf(f: extern fn(i64) -> f64, + fn __floatdidf(f: extern "C" fn(i64) -> f64, a: I64) -> Option { Some(F64(f(a.0))) } - fn __floatunsisf(f: extern fn(u32) -> f32, + fn __floatunsisf(f: extern "C" fn(u32) -> f32, a: U32) -> Option { Some(F32(f(a.0))) } - fn __floatunsidf(f: extern fn(u32) -> f64, + fn __floatunsidf(f: extern "C" fn(u32) -> f64, a: U32) -> Option { Some(F64(f(a.0))) } - fn __floatundidf(f: extern fn(u64) -> f64, + fn __floatundidf(f: extern "C" fn(u64) -> f64, a: U64) -> Option { Some(F64(f(a.0))) } - fn __fixsfsi(f: extern fn(f32) -> i32, + fn __fixsfsi(f: extern "C" fn(f32) -> i32, a: F32) -> Option { if a.0 > (i32::max_value() as f32) || @@ -205,7 +205,7 @@ mod tests { None } else { Some(I32(f(a.0))) } } - fn __fixsfdi(f: extern fn(f32) -> i64, + fn __fixsfdi(f: extern "C" fn(f32) -> i64, a: F32) -> Option { if a.0 > (i64::max_value() as f32) || @@ -213,7 +213,7 @@ mod tests { None } else { Some(I64(f(a.0))) } } - fn __fixdfsi(f: extern fn(f64) -> i32, + fn __fixdfsi(f: extern "C" fn(f64) -> i32, a: F64) -> Option { if a.0 > (i32::max_value() as f64) || @@ -221,7 +221,7 @@ mod tests { None } else { Some(I32(f(a.0))) } } - fn __fixdfdi(f: extern fn(f64) -> i64, + fn __fixdfdi(f: extern "C" fn(f64) -> i64, a: F64) -> Option { if a.0 > (i64::max_value() as f64) || @@ -230,7 +230,7 @@ mod tests { } else { Some(I64(f(a.0))) } } - fn __fixunssfsi(f: extern fn(f32) -> u32, + fn __fixunssfsi(f: extern "C" fn(f32) -> u32, a: F32) -> Option { if a.0 > (u32::max_value() as f32) || @@ -238,7 +238,7 @@ mod tests { None } else { Some(U32(f(a.0))) } } - fn __fixunssfdi(f: extern fn(f32) -> u64, + fn __fixunssfdi(f: extern "C" fn(f32) -> u64, a: F32) -> Option { if a.0 > (u64::max_value() as f32) || @@ -246,7 +246,7 @@ mod tests { None } else { Some(U64(f(a.0))) } } - fn __fixunsdfsi(f: extern fn(f64) -> u32, + fn __fixunsdfsi(f: extern "C" fn(f64) -> u32, a: F64) -> Option { if a.0 > (u32::max_value() as f64) || @@ -254,7 +254,7 @@ mod tests { None } else { Some(U32(f(a.0))) } } - fn __fixunsdfdi(f: extern fn(f64) -> u64, + fn __fixunsdfdi(f: extern "C" fn(f64) -> u64, a: F64) -> Option { if a.0 <= (u64::max_value() as f64) || From 74c6b91677c7ea6dcab65da58f304d1c465301dc Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 6 Mar 2017 17:46:11 -0500 Subject: [PATCH 0264/4206] fix debug assertion in divdi3 fixes #148 --- library/compiler-builtins/src/int/sdiv.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 51d9c37697651..f9fd4668741ac 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -10,8 +10,12 @@ macro_rules! div { pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $tyret { let s_a = a >> (<$ty>::bits() - 1); let s_b = b >> (<$ty>::bits() - 1); - let a = (a ^ s_a) - s_a; - let b = (b ^ s_b) - s_b; + // NOTE it's OK to overflow here because of the `as $uty` cast below + // This whole operation is computing the absolute value of the inputs + // So some overflow will happen when dealing with e.g. `i64::MIN` + // where the absolute value is `(-i64::MIN) as u64` + let a = (a ^ s_a).wrapping_sub(s_a); + let b = (b ^ s_b).wrapping_sub(s_b); let s = s_a ^ s_b; let r = udiv!(a as $uty, b as $uty); From 0ef737f5570124d6478dd4637a1a01bcc484a370 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 13 Mar 2017 20:40:44 -0500 Subject: [PATCH 0265/4206] fix debug assertion in modsi3 / moddi3 fixes #151 this fix is very similar to #149 --- library/compiler-builtins/src/int/sdiv.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 7f30eaf26e812..19065602970cd 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -33,9 +33,10 @@ macro_rules! mod_ { #[cfg_attr(not(test), no_mangle)] pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $tyret { let s = b >> (<$ty>::bits() - 1); - let b = (b ^ s) - s; + // NOTE(wrapping_sub) see comment in the `div` macro + let b = (b ^ s).wrapping_sub(s); let s = a >> (<$ty>::bits() - 1); - let a = (a ^ s) - s; + let a = (a ^ s).wrapping_sub(s); let r = urem!(a as $uty, b as $uty); ($conv)((r as $ty ^ s) - s) From 07064c2239af3d9fe83839334d5845f064c4ac97 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 8 Apr 2017 10:18:19 -0500 Subject: [PATCH 0266/4206] test out of range condition using f64 to avoid imprecision due to rounding to f32 --- library/compiler-builtins/src/float/conv.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 75a392efce191..2781ff5562135 100755 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -200,16 +200,16 @@ mod tests { fn __fixsfsi(f: extern "C" fn(f32) -> i32, a: F32) -> Option { - if a.0 > (i32::max_value() as f32) || - a.0 < (i32::min_value() as f32) || a.0.is_nan() { + if (a.0 as f64) > (i32::max_value() as f64) || + (a.0 as f64) < (i32::min_value() as f64) || a.0.is_nan() { None } else { Some(I32(f(a.0))) } } fn __fixsfdi(f: extern "C" fn(f32) -> i64, a: F32) -> Option { - if a.0 > (i64::max_value() as f32) || - a.0 < (i64::min_value() as f32) || a.0.is_nan() { + if (a.0 as f64) > (i64::max_value() as f64) || + (a.0 as f64) < (i64::min_value() as f64) || a.0.is_nan() { None } else { Some(I64(f(a.0))) } } @@ -233,16 +233,16 @@ mod tests { fn __fixunssfsi(f: extern "C" fn(f32) -> u32, a: F32) -> Option { - if a.0 > (u32::max_value() as f32) || - a.0 < (u32::min_value() as f32) || a.0.is_nan() { + if (a.0 as f64) > (u32::max_value() as f64) || + (a.0 as f64) < (u32::min_value() as f64) || a.0.is_nan() { None } else { Some(U32(f(a.0))) } } fn __fixunssfdi(f: extern "C" fn(f32) -> u64, a: F32) -> Option { - if a.0 > (u64::max_value() as f32) || - a.0 < (u64::min_value() as f32) || a.0.is_nan() { + if (a.0 as f64) > (u64::max_value() as f64) || + (a.0 as f64) < (u64::min_value() as f64) || a.0.is_nan() { None } else { Some(U64(f(a.0))) } } From 8316333dc6081cfdbfb62e4b7b31beb7bacdafdb Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 11:11:23 -0500 Subject: [PATCH 0267/4206] move compiler-rt submodule --- library/compiler-builtins/.gitmodules | 2 +- .../{compiler-rt/compiler-rt-cdylib => c}/compiler-rt | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename library/compiler-builtins/{compiler-rt/compiler-rt-cdylib => c}/compiler-rt (100%) diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index d86b9fa3414ad..ed1a78f9fb340 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -1,3 +1,3 @@ [submodule "compiler-rt/compiler-rt-cdylib/compiler-rt"] - path = compiler-rt/compiler-rt-cdylib/compiler-rt + path = c/compiler-rt url = https://github.com/rust-lang/compiler-rt diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt b/library/compiler-builtins/c/compiler-rt similarity index 100% rename from library/compiler-builtins/compiler-rt/compiler-rt-cdylib/compiler-rt rename to library/compiler-builtins/c/compiler-rt From 05a5f4681fa8bee5cea856c7d6717dda798bb683 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 11:14:05 -0500 Subject: [PATCH 0268/4206] remove the current test suite --- library/compiler-builtins/Cargo.toml | 6 - library/compiler-builtins/src/float/add.rs | 25 ----- library/compiler-builtins/src/float/conv.rs | 109 ------------------ library/compiler-builtins/src/float/pow.rs | 19 ---- library/compiler-builtins/src/float/sub.rs | 25 ----- library/compiler-builtins/src/int/mul.rs | 63 ----------- library/compiler-builtins/src/int/sdiv.rs | 117 -------------------- library/compiler-builtins/src/int/shift.rs | 74 ------------- library/compiler-builtins/src/int/udiv.rs | 117 -------------------- library/compiler-builtins/src/lib.rs | 17 --- 10 files changed, 572 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index a82aad55fe45a..fdd3b2a7d663a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -11,12 +11,6 @@ rustc-cfg = "0.3.0" optional = true version = "0.3.36" -[dev-dependencies] -quickcheck = "0.3.1" -rand = "0.3.14" -gcc_s = { path = "gcc_s" } -compiler-rt = { path = "compiler-rt" } - [features] # Build the missing intrinsics from compiler-rt C source code c = ["gcc"] diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 992d149f45824..5024a728b040c 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -192,28 +192,3 @@ add!("aapcs", __adddf3: f64); #[cfg(not(target_arch = "arm"))] add!("C", __adddf3: f64); - -// NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabi*, our implementation doesn't -// match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll -// just avoid testing against them on those targets. Do note that our implementation gives the -// correct answer; gcc_s and compiler-rt are incorrect in this case. -#[cfg(all(test, not(arm_linux)))] -mod tests { - use core::{f32, f64}; - use qc::{F32, F64}; - - check! { - fn __addsf3(f: extern "C" fn(f32, f32) -> f32, - a: F32, - b: F32) - -> Option { - Some(F32(f(a.0, b.0))) - } - - fn __adddf3(f: extern "C" fn(f64, f64) -> f64, - a: F64, - b: F64) -> Option { - Some(F64(f(a.0, b.0))) - } - } -} diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 2781ff5562135..e04b26bf536a6 100755 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -155,112 +155,3 @@ fp_fix!(__fixunssfsi: f32, u32); fp_fix!(__fixunssfdi: f32, u64); fp_fix!(__fixunsdfsi: f64, u32); fp_fix!(__fixunsdfdi: f64, u64); - -// NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabihf, our implementation doesn't -// match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll -// just avoid testing against them on those targets. Do note that our implementation gives the -// correct answer; gcc_s and compiler-rt are incorrect in this case. -// -#[cfg(all(test, not(arm_linux)))] -mod tests { - use qc::{I32, U32, I64, U64, F32, F64}; - - check! { - fn __floatsisf(f: extern "C" fn(i32) -> f32, - a: I32) - -> Option { - Some(F32(f(a.0))) - } - fn __floatsidf(f: extern "C" fn(i32) -> f64, - a: I32) - -> Option { - Some(F64(f(a.0))) - } - fn __floatdidf(f: extern "C" fn(i64) -> f64, - a: I64) - -> Option { - Some(F64(f(a.0))) - } - fn __floatunsisf(f: extern "C" fn(u32) -> f32, - a: U32) - -> Option { - Some(F32(f(a.0))) - } - fn __floatunsidf(f: extern "C" fn(u32) -> f64, - a: U32) - -> Option { - Some(F64(f(a.0))) - } - fn __floatundidf(f: extern "C" fn(u64) -> f64, - a: U64) - -> Option { - Some(F64(f(a.0))) - } - - fn __fixsfsi(f: extern "C" fn(f32) -> i32, - a: F32) - -> Option { - if (a.0 as f64) > (i32::max_value() as f64) || - (a.0 as f64) < (i32::min_value() as f64) || a.0.is_nan() { - None - } else { Some(I32(f(a.0))) } - } - fn __fixsfdi(f: extern "C" fn(f32) -> i64, - a: F32) - -> Option { - if (a.0 as f64) > (i64::max_value() as f64) || - (a.0 as f64) < (i64::min_value() as f64) || a.0.is_nan() { - None - } else { Some(I64(f(a.0))) } - } - fn __fixdfsi(f: extern "C" fn(f64) -> i32, - a: F64) - -> Option { - if a.0 > (i32::max_value() as f64) || - a.0 < (i32::min_value() as f64) || a.0.is_nan() { - None - } else { Some(I32(f(a.0))) } - } - fn __fixdfdi(f: extern "C" fn(f64) -> i64, - a: F64) - -> Option { - if a.0 > (i64::max_value() as f64) || - a.0 < (i64::min_value() as f64) || a.0.is_nan() { - None - } else { Some(I64(f(a.0))) } - } - - fn __fixunssfsi(f: extern "C" fn(f32) -> u32, - a: F32) - -> Option { - if (a.0 as f64) > (u32::max_value() as f64) || - (a.0 as f64) < (u32::min_value() as f64) || a.0.is_nan() { - None - } else { Some(U32(f(a.0))) } - } - fn __fixunssfdi(f: extern "C" fn(f32) -> u64, - a: F32) - -> Option { - if (a.0 as f64) > (u64::max_value() as f64) || - (a.0 as f64) < (u64::min_value() as f64) || a.0.is_nan() { - None - } else { Some(U64(f(a.0))) } - } - fn __fixunsdfsi(f: extern "C" fn(f64) -> u32, - a: F64) - -> Option { - if a.0 > (u32::max_value() as f64) || - a.0 < (u32::min_value() as f64) || a.0.is_nan() { - None - } else { Some(U32(f(a.0))) } - } - fn __fixunsdfdi(f: extern "C" fn(f64) -> u64, - a: F64) - -> Option { - if a.0 <= (u64::max_value() as f64) || - a.0 >= (u64::min_value() as f64) || a.0.is_nan() { - None - } else { Some(U64(f(a.0))) } - } - } -} diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index 52aba5df68caf..5e28d95d8d292 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -28,22 +28,3 @@ macro_rules! pow { pow!(__powisf2: f32, i32); pow!(__powidf2: f64, i32); - -#[cfg(test)] -mod tests { - use qc::{I32, F32, F64}; - - check! { - fn __powisf2(f: extern "C" fn(f32, i32) -> f32, - a: F32, - b: I32) -> Option { - Some(F32(f(a.0, b.0))) - } - - fn __powidf2(f: extern "C" fn(f64, i32) -> f64, - a: F64, - b: I32) -> Option { - Some(F64(f(a.0, b.0))) - } - } -} diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index 928d73821030e..a4fd8841d17e6 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -18,28 +18,3 @@ sub!(#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] sub!(#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] | __subdf3: f64); - -// NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabi*, our implementation doesn't -// match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll -// just avoid testing against them on those targets. Do note that our implementation gives the -// correct answer; gcc_s and compiler-rt are incorrect in this case. -#[cfg(all(test, not(arm_linux)))] -mod tests { - use core::{f32, f64}; - use qc::{F32, F64}; - - check! { - fn __subsf3(f: extern "C" fn(f32, f32) -> f32, - a: F32, - b: F32) - -> Option { - Some(F32(f(a.0, b.0))) - } - - fn __subdf3(f: extern "C" fn(f64, f64) -> f64, - a: F64, - b: F64) -> Option { - Some(F64(f(a.0, b.0))) - } - } -} diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 7b0d033b0b4e0..5381eddea41ea 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -93,66 +93,3 @@ mulo!(__mulodi4: i64); mulo!(__muloti4: i128, "unadjusted"); #[cfg(not(all(windows, target_pointer_width="64")))] mulo!(__muloti4: i128); - -#[cfg(test)] -mod tests { - use qc::{I32, I64, U64}; - - check! { - fn __muldi3(f: extern "C" fn(u64, u64) -> u64, a: U64, b: U64) - -> Option { - Some(f(a.0, b.0)) - } - - fn __mulosi4(f: extern "C" fn(i32, i32, &mut i32) -> i32, - a: I32, - b: I32) -> Option<(i32, i32)> { - let (a, b) = (a.0, b.0); - let mut overflow = 2; - let r = f(a, b, &mut overflow); - if overflow != 0 && overflow != 1 { - panic!("Invalid value {} for overflow", overflow); - } - Some((r, overflow)) - } - - fn __mulodi4(f: extern "C" fn(i64, i64, &mut i32) -> i64, - a: I64, - b: I64) -> Option<(i64, i32)> { - let (a, b) = (a.0, b.0); - let mut overflow = 2; - let r = f(a, b, &mut overflow); - if overflow != 0 && overflow != 1 { - panic!("Invalid value {} for overflow", overflow); - } - Some((r, overflow)) - } - } -} - -#[cfg(test)] -#[cfg(all(not(windows), - not(target_arch = "mips64"), - not(target_arch = "mips64el"), - target_pointer_width="64"))] -mod tests_i128 { - use qc::I128; - - check! { - fn __multi3(f: extern "C" fn(i128, i128) -> i128, a: I128, b: I128) - -> Option { - Some(f(a.0, b.0)) - } - fn __muloti4(f: extern "C" fn(i128, i128, &mut i32) -> i128, - a: I128, - b: I128) -> Option<(i128, i32)> { - let (a, b) = (a.0, b.0); - let mut overflow = 2; - let r = f(a, b, &mut overflow); - if overflow != 0 && overflow != 1 { - panic!("Invalid value {} for overflow", overflow); - } - Some((r, overflow)) - } - } -} diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 19065602970cd..557689814f629 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -100,120 +100,3 @@ divmod!("aapcs", __divmoddi4, __divdi3: i64); #[cfg(not(target_arch = "arm"))] divmod!("C", __divmoddi4, __divdi3: i64); - -#[cfg(test)] -mod tests { - use qc::{U32, U64}; - - check! { - fn __divdi3(f: extern "C" fn(i64, i64) -> i64, n: U64, d: U64) -> Option { - let (n, d) = (n.0 as i64, d.0 as i64); - if d == 0 { - None - } else { - Some(f(n, d)) - } - } - - fn __moddi3(f: extern "C" fn(i64, i64) -> i64, n: U64, d: U64) -> Option { - let (n, d) = (n.0 as i64, d.0 as i64); - if d == 0 { - None - } else { - Some(f(n, d)) - } - } - - #[cfg(target_arch = "arm")] - fn __divmoddi4(f: extern "aapcs" fn(i64, i64, &mut i64) -> i64, - n: U64, - d: U64) -> Option<(i64, i64)> { - let (n, d) = (n.0 as i64, d.0 as i64); - if d == 0 { - None - } else { - let mut r = 0; - let q = f(n, d, &mut r); - Some((q, r)) - } - } - - #[cfg(not(target_arch = "arm"))] - fn __divmoddi4(f: extern "C" fn(i64, i64, &mut i64) -> i64, - n: U64, - d: U64) -> Option<(i64, i64)> { - let (n, d) = (n.0 as i64, d.0 as i64); - if d == 0 { - None - } else { - let mut r = 0; - let q = f(n, d, &mut r); - Some((q, r)) - } - } - - fn __divsi3(f: extern "C" fn(i32, i32) -> i32, - n: U32, - d: U32) -> Option { - let (n, d) = (n.0 as i32, d.0 as i32); - if d == 0 { - None - } else { - Some(f(n, d)) - } - } - - fn __modsi3(f: extern "C" fn(i32, i32) -> i32, - n: U32, - d: U32) -> Option { - let (n, d) = (n.0 as i32, d.0 as i32); - if d == 0 { - None - } else { - Some(f(n, d)) - } - } - - fn __divmodsi4(f: extern "C" fn(i32, i32, &mut i32) -> i32, - n: U32, - d: U32) -> Option<(i32, i32)> { - let (n, d) = (n.0 as i32, d.0 as i32); - if d == 0 { - None - } else { - let mut r = 0; - let q = f(n, d, &mut r); - Some((q, r)) - } - } - } -} - -#[cfg(test)] -#[cfg(all(not(windows), - not(target_arch = "mips64"), - not(target_arch = "mips64el"), - target_pointer_width="64"))] -mod tests_i128 { - use qc::U128; - check! { - - fn __divti3(f: extern "C" fn(i128, i128) -> i128, n: U128, d: U128) -> Option { - let (n, d) = (n.0 as i128, d.0 as i128); - if d == 0 { - None - } else { - Some(f(n, d)) - } - } - - fn __modti3(f: extern "C" fn(i128, i128) -> i128, n: U128, d: U128) -> Option { - let (n, d) = (n.0 as i128, d.0 as i128); - if d == 0 { - None - } else { - Some(f(n, d)) - } - } - } -} diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index fdd2f6ce2b5da..8b5c4a16eaa46 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -72,77 +72,3 @@ ashr!(__ashrti3: i128); lshr!(__lshrdi3: u64); lshr!(__lshrti3: u128); - -#[cfg(test)] -mod tests { - use qc::{I64, U64}; - - // NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64) - check! { - fn __ashldi3(f: extern "C" fn(u64, u32) -> u64, a: U64, b: u32) -> Option { - let a = a.0; - if b >= 64 { - None - } else { - Some(f(a, b)) - } - } - - fn __ashrdi3(f: extern "C" fn(i64, u32) -> i64, a: I64, b: u32) -> Option { - let a = a.0; - if b >= 64 { - None - } else { - Some(f(a, b)) - } - } - - fn __lshrdi3(f: extern "C" fn(u64, u32) -> u64, a: U64, b: u32) -> Option { - let a = a.0; - if b >= 64 { - None - } else { - Some(f(a, b)) - } - } - } -} - -#[cfg(test)] -#[cfg(all(not(windows), - not(target_arch = "mips64"), - not(target_arch = "mips64el"), - target_pointer_width="64"))] -mod tests_i128 { - use qc::{I128, U128}; - - // NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64) - check! { - fn __ashlti3(f: extern "C" fn(u128, u32) -> u128, a: U128, b: u32) -> Option { - let a = a.0; - if b >= 64 { - None - } else { - Some(f(a, b)) - } - } - - fn __ashrti3(f: extern "C" fn(i128, u32) -> i128, a: I128, b: u32) -> Option { - let a = a.0; - if b >= 64 { - None - } else { - Some(f(a, b)) - } - } - - fn __lshrti3(f: extern "C" fn(u128, u32) -> u128, a: U128, b: u32) -> Option { - let a = a.0; - if b >= 128 { - None - } else { - Some(f(a, b)) - } - } - } -} diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 6c125bb750c07..e8db7460125e9 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -312,120 +312,3 @@ udivmodti4!(::U64x2, ::conv); #[cfg(not(all(windows, target_pointer_width="64")))] udivmodti4!(u128, |i|{ i }); - -#[cfg(test)] -mod tests { - use qc::{U32, U64}; - - check! { - fn __udivdi3(f: extern "C" fn(u64, u64) -> u64, n: U64, d: U64) -> Option { - let (n, d) = (n.0, d.0); - if d == 0 { - None - } else { - Some(f(n, d)) - } - } - - fn __umoddi3(f: extern "C" fn(u64, u64) -> u64, n: U64, d: U64) -> Option { - let (n, d) = (n.0, d.0); - if d == 0 { - None - } else { - Some(f(n, d)) - } - } - - fn __udivmoddi4(f: extern "C" fn(u64, u64, Option<&mut u64>) -> u64, - n: U64, - d: U64) -> Option<(u64, u64)> { - let (n, d) = (n.0, d.0); - if d == 0 { - None - } else { - let mut r = 0; - let q = f(n, d, Some(&mut r)); - Some((q, r)) - } - } - - fn __udivsi3(f: extern "C" fn(u32, u32) -> u32, n: U32, d: U32) -> Option { - let (n, d) = (n.0, d.0); - if d == 0 { - None - } else { - Some(f(n, d)) - } - } - - fn __umodsi3(f: extern "C" fn(u32, u32) -> u32, n: U32, d: U32) -> Option { - let (n, d) = (n.0, d.0); - if d == 0 { - None - } else { - Some(f(n, d)) - } - } - - fn __udivmodsi4(f: extern "C" fn(u32, u32, Option<&mut u32>) -> u32, - n: U32, - d: U32) -> Option<(u32, u32)> { - let (n, d) = (n.0, d.0); - if d == 0 { - None - } else { - let mut r = 0; - let q = f(n, d, Some(&mut r)); - Some((q, r)) - } - } - } -} - -#[cfg(test)] -#[cfg(all(not(windows), - not(target_arch = "mips64"), - not(target_arch = "mips64el"), - target_pointer_width="64"))] -mod tests_i128 { - use qc::U128; - - check! { - fn __udivti3(f: extern "C" fn(u128, u128) -> u128, - n: U128, - d: U128) -> Option { - let (n, d) = (n.0, d.0); - if d == 0 { - None - } else { - Some(f(n, d)) - } - } - - fn __umodti3(f: extern "C" fn(u128, u128) -> u128, - n: U128, - d: U128) -> Option { - let (n, d) = (n.0, d.0); - if d == 0 { - None - } else { - Some(f(n, d)) - } - } - - fn __udivmodti4(f: extern "C" fn(u128, u128, Option<&mut u128>) -> u128, - n: U128, - d: U128) -> Option { - let (n, d) = (n.0, d.0); - if d == 0 { - None - } else { - // FIXME fix the segfault when the remainder is requested - /*let mut r = 0; - let q = f(n, d, Some(&mut r)); - Some((q, r))*/ - Some(f(n, d, None)) - } - } - } -} diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 0da336e950b15..8c7820bf99b0d 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -111,26 +111,9 @@ fn sconv(i: i128) -> U64x2 { U64x2(j.low(), j.high()) } -#[cfg(test)] -#[cfg_attr(target_arch = "arm", macro_use)] -extern crate quickcheck; - #[cfg(test)] extern crate core; -#[cfg(test)] -extern crate gcc_s; - -#[cfg(test)] -extern crate compiler_rt; - -#[cfg(test)] -extern crate rand; - -#[cfg(test)] -#[macro_use] -mod qc; - pub mod int; pub mod float; From 199c7a8dcbd06cf409a6ba02a5ad2eb3283365ad Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 11:19:16 -0500 Subject: [PATCH 0269/4206] refactor build.rs to not depend on rustc-cfg it now uses the CARGO_CFG_TARGET variables provided by Cargo --- library/compiler-builtins/Cargo.toml | 3 - library/compiler-builtins/build.rs | 761 +++++++++++++-------------- 2 files changed, 375 insertions(+), 389 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index fdd3b2a7d663a..aea0c38840fba 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -4,9 +4,6 @@ build = "build.rs" name = "compiler_builtins" version = "0.1.0" -[build-dependencies] -rustc-cfg = "0.3.0" - [build-dependencies.gcc] optional = true version = "0.3.36" diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 6c96284731bc6..145f71575d257 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1,55 +1,4 @@ -#[cfg(feature = "c")] -extern crate gcc; -extern crate rustc_cfg; - -#[cfg(feature = "c")] -use std::collections::BTreeMap; -use std::io::Write; -#[cfg(feature = "c")] -use std::path::Path; -use std::{env, io, process}; - -use rustc_cfg::Cfg; - -#[cfg(feature = "c")] -struct Sources { - // SYMBOL -> PATH TO SOURCE - map: BTreeMap<&'static str, &'static str>, -} - -#[cfg(feature = "c")] -impl Sources { - fn new() -> Sources { - Sources { map: BTreeMap::new() } - } - - fn extend(&mut self, sources: &[&'static str]) { - // NOTE Some intrinsics have both a generic implementation (e.g. - // `floatdidf.c`) and an arch optimized implementation - // (`x86_64/floatdidf.c`). In those cases, we keep the arch optimized - // implementation and discard the generic implementation. If we don't - // and keep both implementations, the linker will yell at us about - // duplicate symbols! - for &src in sources { - let symbol = Path::new(src).file_stem().unwrap().to_str().unwrap(); - if src.contains("/") { - // Arch-optimized implementation (preferred) - self.map.insert(symbol, src); - } else { - // Generic implementation - if !self.map.contains_key(symbol) { - self.map.insert(symbol, src); - } - } - } - } - - fn remove(&mut self, symbols: &[&str]) { - for symbol in symbols { - self.map.remove(*symbol).unwrap(); - } - } -} +use std::env; fn main() { println!("cargo:rerun-if-changed=build.rs"); @@ -61,376 +10,416 @@ fn main() { return; } - let Cfg { ref target_arch, ref target_os, ref target_env, ref target_vendor, .. } = - Cfg::new(&target).unwrap_or_else(|e| { - writeln!(io::stderr(), "{}", e).ok(); - process::exit(1) - }); // 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.split('-').collect::>(); // Build missing intrinsics from compiler-rt C source code - match () { - #[cfg(feature = "c")] - () => { - let target_vendor = target_vendor.as_ref().unwrap(); - let cfg = &mut gcc::Config::new(); - - if target_env == "msvc" { - // Don't pull in extra libraries on MSVC - cfg.flag("/Zl"); - - // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP - cfg.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("-fomit-frame-pointer"); - cfg.flag("-ffreestanding"); - cfg.define("VISIBILITY_HIDDEN", None); - } + #[cfg(feature = "c")] + c::compile(&llvm_target); - // NOTE Most of the ARM intrinsics are written in assembly. Tell gcc which arch we are going to - // target to make sure that the assembly implementations really work for the target. If the - // implementation is not valid for the arch, then gcc will error when compiling it. - if llvm_target[0].starts_with("thumb") { - cfg.flag("-mthumb"); + // To compile intrinsics.rs for thumb targets, where there is no libc + if llvm_target[0].starts_with("thumb") { + println!("cargo:rustc-cfg=thumb") + } - if llvm_target.last() == Some(&"eabihf") { - cfg.flag("-mfloat-abi=hard"); - } - } + // compiler-rt `cfg`s away some intrinsics for thumbv6m because that target doesn't have full + // THUMBv2 support. We have to cfg our code accordingly. + if llvm_target[0] == "thumbv6m" { + println!("cargo:rustc-cfg=thumbv6m") + } +} - if llvm_target[0] == "thumbv6m" { - cfg.flag("-march=armv6-m"); - } +#[cfg(feature = "c")] +mod c { + extern crate gcc; - if llvm_target[0] == "thumbv7m" { - cfg.flag("-march=armv7-m"); - } + use std::collections::BTreeMap; + use std::env; + use std::io::Write; + use std::path::Path; - if llvm_target[0] == "thumbv7em" { - cfg.flag("-march=armv7e-m"); - } + struct Sources { + // SYMBOL -> PATH TO SOURCE + map: BTreeMap<&'static str, &'static str>, + } - let mut sources = Sources::new(); - sources.extend(&["absvdi2.c", - "absvsi2.c", - "addvdi3.c", - "addvsi3.c", - "apple_versioning.c", - "clzdi2.c", - "clzsi2.c", - "cmpdi2.c", - "comparedf2.c", - "comparesf2.c", - "ctzdi2.c", - "ctzsi2.c", - "divdc3.c", - "divdf3.c", - "divsc3.c", - "divsf3.c", - "divxc3.c", - "extendsfdf2.c", - "extendhfsf2.c", - "ffsdi2.c", - "fixdfdi.c", - "fixdfsi.c", - "fixsfdi.c", - "fixsfsi.c", - "fixunsdfdi.c", - "fixunsdfsi.c", - "fixunssfdi.c", - "fixunssfsi.c", - "fixunsxfdi.c", - "fixunsxfsi.c", - "fixxfdi.c", - "floatdidf.c", - "floatdisf.c", - "floatdixf.c", - "floatsidf.c", - "floatsisf.c", - "floatundidf.c", - "floatundisf.c", - "floatundixf.c", - "floatunsidf.c", - "floatunsisf.c", - "int_util.c", - "muldc3.c", - "muldf3.c", - "mulsc3.c", - "mulsf3.c", - "mulvdi3.c", - "mulvsi3.c", - "mulxc3.c", - "negdf2.c", - "negdi2.c", - "negsf2.c", - "negvdi2.c", - "negvsi2.c", - "paritydi2.c", - "paritysi2.c", - "popcountdi2.c", - "popcountsi2.c", - "powixf2.c", - "subvdi3.c", - "subvsi3.c", - "truncdfhf2.c", - "truncdfsf2.c", - "truncsfhf2.c", - "ucmpdi2.c"]); - - if target_os != "ios" { - sources.extend(&["absvti2.c", - "addvti3.c", - "clzti2.c", - "cmpti2.c", - "ctzti2.c", - "ffsti2.c", - "fixdfti.c", - "fixsfti.c", - "fixunsdfti.c", - "fixunssfti.c", - "fixunsxfti.c", - "fixxfti.c", - "floattidf.c", - "floattisf.c", - "floattixf.c", - "floatuntidf.c", - "floatuntisf.c", - "floatuntixf.c", - "mulvti3.c", - "negti2.c", - "negvti2.c", - "parityti2.c", - "popcountti2.c", - "subvti3.c", - "ucmpti2.c"]); + impl Sources { + fn new() -> Sources { + Sources { map: BTreeMap::new() } + } + + fn extend(&mut self, sources: &[&'static str]) { + // NOTE Some intrinsics have both a generic implementation (e.g. + // `floatdidf.c`) and an arch optimized implementation + // (`x86_64/floatdidf.c`). In those cases, we keep the arch optimized + // implementation and discard the generic implementation. If we don't + // and keep both implementations, the linker will yell at us about + // duplicate symbols! + for &src in sources { + let symbol = Path::new(src).file_stem().unwrap().to_str().unwrap(); + if src.contains("/") { + // Arch-optimized implementation (preferred) + self.map.insert(symbol, src); + } else { + // Generic implementation + if !self.map.contains_key(symbol) { + self.map.insert(symbol, src); + } + } } + } - if target_vendor == "apple" { - sources.extend(&["atomic_flag_clear.c", - "atomic_flag_clear_explicit.c", - "atomic_flag_test_and_set.c", - "atomic_flag_test_and_set_explicit.c", - "atomic_signal_fence.c", - "atomic_thread_fence.c"]); + fn remove(&mut self, symbols: &[&str]) { + for symbol in symbols { + self.map.remove(*symbol).unwrap(); } + } + } - if target_env == "msvc" { - if target_arch == "x86_64" { - sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]); - } - } else { - if target_os != "freebsd" && target_os != "netbsd" { - sources.extend(&["gcc_personality_v0.c"]); - } + /// Compile intrinsics from the compiler-rt C source code + pub fn compile(llvm_target: &[&str]){ + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap(); + let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); + let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap(); + + let cfg = &mut gcc::Config::new(); + + if target_env == "msvc" { + // Don't pull in extra libraries on MSVC + cfg.flag("/Zl"); + + // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP + cfg.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("-fomit-frame-pointer"); + cfg.flag("-ffreestanding"); + cfg.define("VISIBILITY_HIDDEN", None); + } - if target_arch == "x86_64" { - sources.extend(&["x86_64/chkstk.S", - "x86_64/chkstk2.S", - "x86_64/floatdidf.c", - "x86_64/floatdisf.c", - "x86_64/floatdixf.c", - "x86_64/floatundidf.S", - "x86_64/floatundisf.S", - "x86_64/floatundixf.S"]); - } + // NOTE Most of the ARM intrinsics are written in assembly. Tell gcc which arch we are going to + // target to make sure that the assembly implementations really work for the target. If the + // implementation is not valid for the arch, then gcc will error when compiling it. + if llvm_target[0].starts_with("thumb") { + cfg.flag("-mthumb"); - if target_arch == "x86" { - sources.extend(&["i386/ashldi3.S", - "i386/ashrdi3.S", - "i386/chkstk.S", - "i386/chkstk2.S", - "i386/divdi3.S", - "i386/floatdidf.S", - "i386/floatdisf.S", - "i386/floatdixf.S", - "i386/floatundidf.S", - "i386/floatundisf.S", - "i386/floatundixf.S", - "i386/lshrdi3.S", - "i386/moddi3.S", - "i386/muldi3.S", - "i386/udivdi3.S", - "i386/umoddi3.S"]); - } + if llvm_target.last() == Some(&"eabihf") { + cfg.flag("-mfloat-abi=hard"); } + } - if target_arch == "arm" && target_os != "ios" { - sources.extend(&["arm/aeabi_cdcmp.S", - "arm/aeabi_cdcmpeq_check_nan.c", - "arm/aeabi_cfcmp.S", - "arm/aeabi_cfcmpeq_check_nan.c", - "arm/aeabi_dcmp.S", - "arm/aeabi_div0.c", - "arm/aeabi_drsub.c", - "arm/aeabi_fcmp.S", - "arm/aeabi_frsub.c", - "arm/bswapdi2.S", - "arm/bswapsi2.S", - "arm/clzdi2.S", - "arm/clzsi2.S", - "arm/comparesf2.S", - "arm/divmodsi4.S", - "arm/divsi3.S", - "arm/modsi3.S", - "arm/switch16.S", - "arm/switch32.S", - "arm/switch8.S", - "arm/switchu8.S", - "arm/sync_synchronize.S", - "arm/udivmodsi4.S", - "arm/udivsi3.S", - "arm/umodsi3.S"]); - } + if llvm_target[0] == "thumbv6m" { + cfg.flag("-march=armv6-m"); + } - if llvm_target[0] == "armv7" { - sources.extend(&["arm/sync_fetch_and_add_4.S", - "arm/sync_fetch_and_add_8.S", - "arm/sync_fetch_and_and_4.S", - "arm/sync_fetch_and_and_8.S", - "arm/sync_fetch_and_max_4.S", - "arm/sync_fetch_and_max_8.S", - "arm/sync_fetch_and_min_4.S", - "arm/sync_fetch_and_min_8.S", - "arm/sync_fetch_and_nand_4.S", - "arm/sync_fetch_and_nand_8.S", - "arm/sync_fetch_and_or_4.S", - "arm/sync_fetch_and_or_8.S", - "arm/sync_fetch_and_sub_4.S", - "arm/sync_fetch_and_sub_8.S", - "arm/sync_fetch_and_umax_4.S", - "arm/sync_fetch_and_umax_8.S", - "arm/sync_fetch_and_umin_4.S", - "arm/sync_fetch_and_umin_8.S", - "arm/sync_fetch_and_xor_4.S", - "arm/sync_fetch_and_xor_8.S"]); - } + if llvm_target[0] == "thumbv7m" { + cfg.flag("-march=armv7-m"); + } - if llvm_target.last().unwrap().ends_with("eabihf") { - if !llvm_target[0].starts_with("thumbv7em") { - sources.extend(&["arm/adddf3vfp.S", - "arm/addsf3vfp.S", - "arm/divdf3vfp.S", - "arm/divsf3vfp.S", - "arm/eqdf2vfp.S", - "arm/eqsf2vfp.S", - "arm/extendsfdf2vfp.S", - "arm/fixdfsivfp.S", - "arm/fixsfsivfp.S", - "arm/fixunsdfsivfp.S", - "arm/fixunssfsivfp.S", - "arm/floatsidfvfp.S", - "arm/floatsisfvfp.S", - "arm/floatunssidfvfp.S", - "arm/floatunssisfvfp.S", - "arm/gedf2vfp.S", - "arm/gesf2vfp.S", - "arm/gtdf2vfp.S", - "arm/gtsf2vfp.S", - "arm/ledf2vfp.S", - "arm/lesf2vfp.S", - "arm/ltdf2vfp.S", - "arm/ltsf2vfp.S", - "arm/muldf3vfp.S", - "arm/mulsf3vfp.S", - "arm/nedf2vfp.S", - "arm/nesf2vfp.S", - "arm/restore_vfp_d8_d15_regs.S", - "arm/save_vfp_d8_d15_regs.S", - "arm/subdf3vfp.S", - "arm/subsf3vfp.S"]); - } + if llvm_target[0] == "thumbv7em" { + cfg.flag("-march=armv7e-m"); + } - sources.extend(&["arm/negdf2vfp.S", "arm/negsf2vfp.S"]); + let mut sources = Sources::new(); + sources.extend(&["absvdi2.c", + "absvsi2.c", + "addvdi3.c", + "addvsi3.c", + "apple_versioning.c", + "clzdi2.c", + "clzsi2.c", + "cmpdi2.c", + "comparedf2.c", + "comparesf2.c", + "ctzdi2.c", + "ctzsi2.c", + "divdc3.c", + "divdf3.c", + "divsc3.c", + "divsf3.c", + "divxc3.c", + "extendsfdf2.c", + "extendhfsf2.c", + "ffsdi2.c", + "fixdfdi.c", + "fixdfsi.c", + "fixsfdi.c", + "fixsfsi.c", + "fixunsdfdi.c", + "fixunsdfsi.c", + "fixunssfdi.c", + "fixunssfsi.c", + "fixunsxfdi.c", + "fixunsxfsi.c", + "fixxfdi.c", + "floatdidf.c", + "floatdisf.c", + "floatdixf.c", + "floatsidf.c", + "floatsisf.c", + "floatundidf.c", + "floatundisf.c", + "floatundixf.c", + "floatunsidf.c", + "floatunsisf.c", + "int_util.c", + "muldc3.c", + "muldf3.c", + "mulsc3.c", + "mulsf3.c", + "mulvdi3.c", + "mulvsi3.c", + "mulxc3.c", + "negdf2.c", + "negdi2.c", + "negsf2.c", + "negvdi2.c", + "negvsi2.c", + "paritydi2.c", + "paritysi2.c", + "popcountdi2.c", + "popcountsi2.c", + "powixf2.c", + "subvdi3.c", + "subvsi3.c", + "truncdfhf2.c", + "truncdfsf2.c", + "truncsfhf2.c", + "ucmpdi2.c"]); + + if target_os != "ios" { + sources.extend(&["absvti2.c", + "addvti3.c", + "clzti2.c", + "cmpti2.c", + "ctzti2.c", + "ffsti2.c", + "fixdfti.c", + "fixsfti.c", + "fixunsdfti.c", + "fixunssfti.c", + "fixunsxfti.c", + "fixxfti.c", + "floattidf.c", + "floattisf.c", + "floattixf.c", + "floatuntidf.c", + "floatuntisf.c", + "floatuntixf.c", + "mulvti3.c", + "negti2.c", + "negvti2.c", + "parityti2.c", + "popcountti2.c", + "subvti3.c", + "ucmpti2.c"]); + } - } + if target_vendor == "apple" { + sources.extend(&["atomic_flag_clear.c", + "atomic_flag_clear_explicit.c", + "atomic_flag_test_and_set.c", + "atomic_flag_test_and_set_explicit.c", + "atomic_signal_fence.c", + "atomic_thread_fence.c"]); + } - if target_arch == "aarch64" { - sources.extend(&["comparetf2.c", - "extenddftf2.c", - "extendsftf2.c", - "fixtfdi.c", - "fixtfsi.c", - "fixtfti.c", - "fixunstfdi.c", - "fixunstfsi.c", - "fixunstfti.c", - "floatditf.c", - "floatsitf.c", - "floatunditf.c", - "floatunsitf.c", - "multc3.c", - "trunctfdf2.c", - "trunctfsf2.c"]); + if target_env == "msvc" { + if target_arch == "x86_64" { + sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]); + } + } else { + if target_os != "freebsd" && target_os != "netbsd" { + sources.extend(&["gcc_personality_v0.c"]); } - // Remove the assembly implementations that won't compile for the target - if llvm_target[0] == "thumbv6m" { - sources.remove(&["aeabi_cdcmp", - "aeabi_cfcmp", - "aeabi_dcmp", - "aeabi_fcmp", - "clzdi2", - "clzsi2", - "comparesf2", - "divmodsi4", - "divsi3", - "modsi3", - "switch16", - "switch32", - "switch8", - "switchu8", - "udivmodsi4", - "udivsi3", - "umodsi3"]); - - // But use some generic implementations where possible - sources.extend(&["clzdi2.c", "clzsi2.c"]) + if target_arch == "x86_64" { + sources.extend(&["x86_64/chkstk.S", + "x86_64/chkstk2.S", + "x86_64/floatdidf.c", + "x86_64/floatdisf.c", + "x86_64/floatdixf.c", + "x86_64/floatundidf.S", + "x86_64/floatundisf.S", + "x86_64/floatundixf.S"]); } - if llvm_target[0] == "thumbv7m" || llvm_target[0] == "thumbv7em" { - sources.remove(&["aeabi_cdcmp", "aeabi_cfcmp"]); + if target_arch == "x86" { + sources.extend(&["i386/ashldi3.S", + "i386/ashrdi3.S", + "i386/chkstk.S", + "i386/chkstk2.S", + "i386/divdi3.S", + "i386/floatdidf.S", + "i386/floatdisf.S", + "i386/floatdixf.S", + "i386/floatundidf.S", + "i386/floatundisf.S", + "i386/floatundixf.S", + "i386/lshrdi3.S", + "i386/moddi3.S", + "i386/muldi3.S", + "i386/udivdi3.S", + "i386/umoddi3.S"]); } + } - let root = if env::var_os("CARGO_FEATURE_RUSTBUILD").is_some() { - Path::new("../../libcompiler_builtins") - } else { - Path::new(".") - }; - - let src_dir = root.join("compiler-rt/compiler-rt-cdylib/compiler-rt/lib/builtins"); - for src in sources.map.values() { - let src = src_dir.join(src); - cfg.file(&src); - println!("cargo:rerun-if-changed={}", src.display()); + if target_arch == "arm" && target_os != "ios" { + sources.extend(&["arm/aeabi_cdcmp.S", + "arm/aeabi_cdcmpeq_check_nan.c", + "arm/aeabi_cfcmp.S", + "arm/aeabi_cfcmpeq_check_nan.c", + "arm/aeabi_dcmp.S", + "arm/aeabi_div0.c", + "arm/aeabi_drsub.c", + "arm/aeabi_fcmp.S", + "arm/aeabi_frsub.c", + "arm/bswapdi2.S", + "arm/bswapsi2.S", + "arm/clzdi2.S", + "arm/clzsi2.S", + "arm/comparesf2.S", + "arm/divmodsi4.S", + "arm/divsi3.S", + "arm/modsi3.S", + "arm/switch16.S", + "arm/switch32.S", + "arm/switch8.S", + "arm/switchu8.S", + "arm/sync_synchronize.S", + "arm/udivmodsi4.S", + "arm/udivsi3.S", + "arm/umodsi3.S"]); + } + + if llvm_target[0] == "armv7" { + sources.extend(&["arm/sync_fetch_and_add_4.S", + "arm/sync_fetch_and_add_8.S", + "arm/sync_fetch_and_and_4.S", + "arm/sync_fetch_and_and_8.S", + "arm/sync_fetch_and_max_4.S", + "arm/sync_fetch_and_max_8.S", + "arm/sync_fetch_and_min_4.S", + "arm/sync_fetch_and_min_8.S", + "arm/sync_fetch_and_nand_4.S", + "arm/sync_fetch_and_nand_8.S", + "arm/sync_fetch_and_or_4.S", + "arm/sync_fetch_and_or_8.S", + "arm/sync_fetch_and_sub_4.S", + "arm/sync_fetch_and_sub_8.S", + "arm/sync_fetch_and_umax_4.S", + "arm/sync_fetch_and_umax_8.S", + "arm/sync_fetch_and_umin_4.S", + "arm/sync_fetch_and_umin_8.S", + "arm/sync_fetch_and_xor_4.S", + "arm/sync_fetch_and_xor_8.S"]); + } + + if llvm_target.last().unwrap().ends_with("eabihf") { + if !llvm_target[0].starts_with("thumbv7em") { + sources.extend(&["arm/adddf3vfp.S", + "arm/addsf3vfp.S", + "arm/divdf3vfp.S", + "arm/divsf3vfp.S", + "arm/eqdf2vfp.S", + "arm/eqsf2vfp.S", + "arm/extendsfdf2vfp.S", + "arm/fixdfsivfp.S", + "arm/fixsfsivfp.S", + "arm/fixunsdfsivfp.S", + "arm/fixunssfsivfp.S", + "arm/floatsidfvfp.S", + "arm/floatsisfvfp.S", + "arm/floatunssidfvfp.S", + "arm/floatunssisfvfp.S", + "arm/gedf2vfp.S", + "arm/gesf2vfp.S", + "arm/gtdf2vfp.S", + "arm/gtsf2vfp.S", + "arm/ledf2vfp.S", + "arm/lesf2vfp.S", + "arm/ltdf2vfp.S", + "arm/ltsf2vfp.S", + "arm/muldf3vfp.S", + "arm/mulsf3vfp.S", + "arm/nedf2vfp.S", + "arm/nesf2vfp.S", + "arm/restore_vfp_d8_d15_regs.S", + "arm/save_vfp_d8_d15_regs.S", + "arm/subdf3vfp.S", + "arm/subsf3vfp.S"]); } - cfg.compile("libcompiler-rt.a"); + sources.extend(&["arm/negdf2vfp.S", "arm/negsf2vfp.S"]); + } - #[cfg(not(feature = "c"))] - () => {} - } - // To filter away some flaky test (see src/float/add.rs for details) - if llvm_target[0].starts_with("arm") && - llvm_target.last().unwrap().contains("gnueabi") { - println!("cargo:rustc-cfg=arm_linux") - } + if target_arch == "aarch64" { + sources.extend(&["comparetf2.c", + "extenddftf2.c", + "extendsftf2.c", + "fixtfdi.c", + "fixtfsi.c", + "fixtfti.c", + "fixunstfdi.c", + "fixunstfsi.c", + "fixunstfti.c", + "floatditf.c", + "floatsitf.c", + "floatunditf.c", + "floatunsitf.c", + "multc3.c", + "trunctfdf2.c", + "trunctfsf2.c"]); + } - // To compile intrinsics.rs for thumb targets, where there is no libc - if llvm_target[0].starts_with("thumb") { - println!("cargo:rustc-cfg=thumb") - } + // Remove the assembly implementations that won't compile for the target + if llvm_target[0] == "thumbv6m" { + sources.remove(&["aeabi_cdcmp", + "aeabi_cfcmp", + "aeabi_dcmp", + "aeabi_fcmp", + "clzdi2", + "clzsi2", + "comparesf2", + "divmodsi4", + "divsi3", + "modsi3", + "switch16", + "switch32", + "switch8", + "switchu8", + "udivmodsi4", + "udivsi3", + "umodsi3"]); + + // But use some generic implementations where possible + sources.extend(&["clzdi2.c", "clzsi2.c"]) + } - // compiler-rt `cfg`s away some intrinsics for thumbv6m because that target doesn't have full - // THUMBv2 support. We have to cfg our code accordingly. - if llvm_target[0] == "thumbv6m" { - println!("cargo:rustc-cfg=thumbv6m") + if llvm_target[0] == "thumbv7m" || llvm_target[0] == "thumbv7em" { + sources.remove(&["aeabi_cdcmp", "aeabi_cfcmp"]); + } + + let root = if env::var_os("CARGO_FEATURE_RUSTBUILD").is_some() { + Path::new("../../libcompiler_builtins") + } else { + Path::new(".") + }; + + let src_dir = root.join("c/compiler-rt/lib/builtins"); + for src in sources.map.values() { + let src = src_dir.join(src); + cfg.file(&src); + println!("cargo:rerun-if-changed={}", src.display()); + } + + cfg.compile("libcompiler-rt.a"); } } From 5b2585403daf4187a465a254032864d164dd95c3 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 11:22:17 -0500 Subject: [PATCH 0270/4206] remove unused Cargo subprojects --- .../compiler-builtins/compiler-rt/Cargo.toml | 8 -- .../compiler-rt/compiler-rt-cdylib/Cargo.toml | 12 -- .../compiler-rt/compiler-rt-cdylib/build.rs | 104 --------------- .../compiler-rt/compiler-rt-cdylib/src/lib.rs | 126 ------------------ .../compiler-builtins/compiler-rt/src/lib.rs | 35 ----- library/compiler-builtins/gcc_s/Cargo.toml | 7 - library/compiler-builtins/gcc_s/src/lib.rs | 39 ------ 7 files changed, 331 deletions(-) delete mode 100644 library/compiler-builtins/compiler-rt/Cargo.toml delete mode 100644 library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml delete mode 100644 library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs delete mode 100644 library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs delete mode 100644 library/compiler-builtins/compiler-rt/src/lib.rs delete mode 100644 library/compiler-builtins/gcc_s/Cargo.toml delete mode 100644 library/compiler-builtins/gcc_s/src/lib.rs diff --git a/library/compiler-builtins/compiler-rt/Cargo.toml b/library/compiler-builtins/compiler-rt/Cargo.toml deleted file mode 100644 index cac87733a6290..0000000000000 --- a/library/compiler-builtins/compiler-rt/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "compiler-rt" -version = "0.1.0" -authors = ["Alex Crichton "] - -[dependencies] -compiler-rt-cdylib = { path = "compiler-rt-cdylib" } -libloading = "0.3" diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml deleted file mode 100644 index ec9c6af183154..0000000000000 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "compiler-rt-cdylib" -version = "0.1.0" -authors = ["Alex Crichton "] -build = "build.rs" - -[lib] -crate-type = ["cdylib"] - -[build-dependencies] -gcc = "0.3.36" - diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs deleted file mode 100644 index c07ea70cfd9d8..0000000000000 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/build.rs +++ /dev/null @@ -1,104 +0,0 @@ -extern crate gcc; - -use std::env; -use std::path::Path; -use std::process::Command; - -struct Sources { - files: Vec<&'static str>, -} - -impl Sources { - fn new() -> Sources { - Sources { files: Vec::new() } - } - - fn extend(&mut self, sources: &[&'static str]) { - self.files.extend(sources); - } -} - -fn main() { - if !Path::new("compiler-rt/.git").exists() { - let _ = Command::new("git").args(&["submodule", "update", "--init"]) - .status(); - } - - let target = env::var("TARGET").expect("TARGET was not set"); - let cfg = &mut gcc::Config::new(); - - if target.contains("msvc") { - cfg.define("__func__", Some("__FUNCTION__")); - } else { - cfg.flag("-fno-builtin"); - cfg.flag("-fomit-frame-pointer"); - cfg.flag("-ffreestanding"); - } - - let mut sources = Sources::new(); - - sources.extend(&[ - "muldi3.c", - "mulosi4.c", - "mulodi4.c", - "divsi3.c", - "divdi3.c", - "modsi3.c", - "moddi3.c", - "divmodsi4.c", - "divmoddi4.c", - "ashldi3.c", - "ashrdi3.c", - "lshrdi3.c", - "udivdi3.c", - "umoddi3.c", - "udivmoddi4.c", - "udivsi3.c", - "umodsi3.c", - "udivmodsi4.c", - "adddf3.c", - "addsf3.c", - "powidf2.c", - "powisf2.c", - "subdf3.c", - "subsf3.c", - "floatsisf.c", - "floatsidf.c", - "floatdidf.c", - "floatunsisf.c", - "floatunsidf.c", - "floatundidf.c", - "fixsfsi.c", - "fixsfdi.c", - "fixdfsi.c", - "fixdfdi.c", - "fixunssfsi.c", - "fixunssfdi.c", - "fixunsdfsi.c", - "fixunsdfdi.c", - // 128 bit integers - "lshrti3.c", - "modti3.c", - "muloti4.c", - "multi3.c", - "udivmodti4.c", - "udivti3.c", - "umodti3.c", - "ashlti3.c", - "ashrti3.c", - "divti3.c", - ]); - - let builtins_dir = Path::new("compiler-rt/lib/builtins"); - for src in sources.files.iter() { - cfg.file(builtins_dir.join(src)); - } - - cfg.compile("libcompiler-rt.a"); - - println!("cargo:rerun-if-changed=build.rs"); - - for source in sources.files.iter() { - println!("cargo:rerun-if-changed={}", builtins_dir.join(source).display()); - } -} diff --git a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs b/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs deleted file mode 100644 index 2f08314bb88c3..0000000000000 --- a/library/compiler-builtins/compiler-rt/compiler-rt-cdylib/src/lib.rs +++ /dev/null @@ -1,126 +0,0 @@ -#![feature(lang_items)] -#![no_std] - -extern { - fn __ashldi3(); - fn __ashrdi3(); - fn __divdi3(); - fn __divmoddi4(); - fn __divmodsi4(); - fn __divsi3(); - fn __lshrdi3(); - fn __moddi3(); - fn __modsi3(); - fn __muldi3(); - fn __mulodi4(); - fn __mulosi4(); - fn __udivdi3(); - fn __udivmoddi4(); - fn __udivmodsi4(); - fn __udivsi3(); - fn __umoddi3(); - fn __umodsi3(); - fn __addsf3(); - fn __adddf3(); - fn __powisf2(); - fn __powidf2(); - fn __subsf3(); - fn __subdf3(); - fn __floatsisf(); - fn __floatsidf(); - fn __floatdidf(); - fn __floatunsisf(); - fn __floatunsidf(); - fn __floatundidf(); - fn __fixsfsi(); - fn __fixsfdi(); - fn __fixdfsi(); - fn __fixdfdi(); - fn __fixunssfsi(); - fn __fixunssfdi(); - fn __fixunsdfsi(); - fn __fixunsdfdi(); -} - -macro_rules! declare { - ($func:ident, $sym:ident) => { - #[no_mangle] - pub extern fn $func() -> usize { - $sym as usize - } - } -} - -declare!(___ashldi3, __ashldi3); -declare!(___ashrdi3, __ashrdi3); -declare!(___divdi3, __divdi3); -declare!(___divmoddi4, __divmoddi4); -declare!(___divmodsi4, __divmodsi4); -declare!(___divsi3, __divsi3); -declare!(___lshrdi3, __lshrdi3); -declare!(___moddi3, __moddi3); -declare!(___modsi3, __modsi3); -declare!(___muldi3, __muldi3); -declare!(___mulodi4, __mulodi4); -declare!(___mulosi4, __mulosi4); -declare!(___udivdi3, __udivdi3); -declare!(___udivmoddi4, __udivmoddi4); -declare!(___udivmodsi4, __udivmodsi4); -declare!(___udivsi3, __udivsi3); -declare!(___umoddi3, __umoddi3); -declare!(___umodsi3, __umodsi3); -declare!(___addsf3, __addsf3); -declare!(___adddf3, __adddf3); -declare!(___powisf2, __powisf2); -declare!(___powidf2, __powidf2); -declare!(___subsf3, __subsf3); -declare!(___subdf3, __subdf3); -declare!(___floatsisf, __floatsisf); -declare!(___floatsidf, __floatsidf); -declare!(___floatdidf, __floatdidf); -declare!(___floatunsisf, __floatunsisf); -declare!(___floatunsidf, __floatunsidf); -declare!(___floatundidf, __floatundidf); -declare!(___fixsfsi, __fixsfsi); -declare!(___fixsfdi, __fixsfdi); -declare!(___fixdfsi, __fixdfsi); -declare!(___fixdfdi, __fixdfdi); -declare!(___fixunssfsi, __fixunssfsi); -declare!(___fixunssfdi, __fixunssfdi); -declare!(___fixunsdfsi, __fixunsdfsi); -declare!(___fixunsdfdi, __fixunsdfdi); - -#[cfg(all(not(windows), - not(target_arch = "mips64"), - not(target_arch = "mips64el"), - target_pointer_width="64"))] -pub mod int_128 { - extern { - fn __lshrti3(); - fn __modti3(); - fn __muloti4(); - fn __multi3(); - fn __udivmodti4(); - fn __udivti3(); - fn __umodti3(); - fn __ashlti3(); - fn __ashrti3(); - fn __divti3(); - } - - declare!(___lshrti3, __lshrti3); - declare!(___modti3, __modti3); - declare!(___muloti4, __muloti4); - declare!(___multi3, __multi3); - declare!(___udivmodti4, __udivmodti4); - declare!(___udivti3, __udivti3); - declare!(___umodti3, __umodti3); - declare!(___ashlti3, __ashlti3); - declare!(___ashrti3, __ashrti3); - declare!(___divti3, __divti3); -} - -#[lang = "eh_personality"] -fn eh_personality() {} -#[lang = "panic_fmt"] -fn panic_fmt() {} diff --git a/library/compiler-builtins/compiler-rt/src/lib.rs b/library/compiler-builtins/compiler-rt/src/lib.rs deleted file mode 100644 index ca99f397f5540..0000000000000 --- a/library/compiler-builtins/compiler-rt/src/lib.rs +++ /dev/null @@ -1,35 +0,0 @@ -#![feature(drop_types_in_const)] - -extern crate libloading; - -use std::sync::{Once, ONCE_INIT}; -use std::env; - -use libloading::Library; - -fn compiler_rt() -> &'static Library { - let dir = env::current_exe().unwrap(); - let cdylib = dir.parent().unwrap().read_dir().unwrap().map(|c| { - c.unwrap().path() - }).find(|path| { - path.file_name().unwrap().to_str().unwrap().contains("compiler_rt_cdylib") - }).unwrap(); - - unsafe { - static mut COMPILER_RT: Option = None; - static INIT: Once = ONCE_INIT; - - INIT.call_once(|| { - COMPILER_RT = Some(Library::new(&cdylib).unwrap()); - }); - COMPILER_RT.as_ref().unwrap() - } -} - -pub fn get(sym: &str) -> usize { - unsafe { - let sym = format!("_{}", sym); - let f: fn() -> usize = *compiler_rt().get(sym.as_bytes()).unwrap(); - f() - } -} diff --git a/library/compiler-builtins/gcc_s/Cargo.toml b/library/compiler-builtins/gcc_s/Cargo.toml deleted file mode 100644 index 4e3080fa408e3..0000000000000 --- a/library/compiler-builtins/gcc_s/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -authors = ["Jorge Aparicio "] -name = "gcc_s" -version = "0.1.0" - -[dependencies] -libloading = "0.3.0" diff --git a/library/compiler-builtins/gcc_s/src/lib.rs b/library/compiler-builtins/gcc_s/src/lib.rs deleted file mode 100644 index e3417ffb591b7..0000000000000 --- a/library/compiler-builtins/gcc_s/src/lib.rs +++ /dev/null @@ -1,39 +0,0 @@ -#![feature(drop_types_in_const)] - -extern crate libloading; - -use std::sync::{Once, ONCE_INIT}; - -use libloading::Library; - -static mut GCC_S: Option = None; - -#[cfg(not(windows))] -fn gcc_s() -> &'static Library { - #[cfg(not(target_os = "macos"))] - const LIBGCC_S: &'static str = "libgcc_s.so.1"; - - #[cfg(target_os = "macos")] - const LIBGCC_S: &'static str = "libgcc_s.1.dylib"; - - unsafe { - static INIT: Once = ONCE_INIT; - - INIT.call_once(|| { - GCC_S = Some(Library::new(LIBGCC_S).unwrap()); - }); - GCC_S.as_ref().unwrap() - } -} - -#[cfg(windows)] -pub fn get(_sym: &str) -> Option { - None -} - -#[cfg(not(windows))] -pub fn get(sym: &str) -> Option { - unsafe { - gcc_s().get(sym.as_bytes()).ok().map(|s| *s) - } -} From dfc1a7d814b323ce032a96431dea1e8b55be2a98 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 11:23:03 -0500 Subject: [PATCH 0271/4206] move the compiler-rt submodule to the root --- library/compiler-builtins/.gitmodules | 2 +- library/compiler-builtins/build.rs | 3 +-- library/compiler-builtins/{c => }/compiler-rt | 0 3 files changed, 2 insertions(+), 3 deletions(-) rename library/compiler-builtins/{c => }/compiler-rt (100%) diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index ed1a78f9fb340..bbdcf701cd615 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -1,3 +1,3 @@ [submodule "compiler-rt/compiler-rt-cdylib/compiler-rt"] - path = c/compiler-rt + path = compiler-rt url = https://github.com/rust-lang/compiler-rt diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 145f71575d257..46aa05e77495f 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -37,7 +37,6 @@ mod c { use std::collections::BTreeMap; use std::env; - use std::io::Write; use std::path::Path; struct Sources { @@ -413,7 +412,7 @@ mod c { Path::new(".") }; - let src_dir = root.join("c/compiler-rt/lib/builtins"); + let src_dir = root.join("compiler-rt/lib/builtins"); for src in sources.map.values() { let src = src_dir.join(src); cfg.file(&src); diff --git a/library/compiler-builtins/c/compiler-rt b/library/compiler-builtins/compiler-rt similarity index 100% rename from library/compiler-builtins/c/compiler-rt rename to library/compiler-builtins/compiler-rt From 447ebe4f915a366e44f6538f1e3b3c2a83251fff Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 11:29:31 -0500 Subject: [PATCH 0272/4206] rustfmt --- library/compiler-builtins/build.rs | 514 ++++++++++++++++------------- 1 file changed, 280 insertions(+), 234 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 46aa05e77495f..cc778642b8c4b 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -78,7 +78,7 @@ mod c { } /// Compile intrinsics from the compiler-rt C source code - pub fn compile(llvm_target: &[&str]){ + pub fn compile(llvm_target: &[&str]) { let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap(); let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); @@ -102,9 +102,9 @@ mod c { cfg.define("VISIBILITY_HIDDEN", None); } - // NOTE Most of the ARM intrinsics are written in assembly. Tell gcc which arch we are going to - // target to make sure that the assembly implementations really work for the target. If the - // implementation is not valid for the arch, then gcc will error when compiling it. + // NOTE Most of the ARM intrinsics are written in assembly. Tell gcc which arch we are going + // to target to make sure that the assembly implementations really work for the target. If + // the implementation is not valid for the arch, then gcc will error when compiling it. if llvm_target[0].starts_with("thumb") { cfg.flag("-mthumb"); @@ -126,112 +126,130 @@ mod c { } let mut sources = Sources::new(); - sources.extend(&["absvdi2.c", - "absvsi2.c", - "addvdi3.c", - "addvsi3.c", - "apple_versioning.c", - "clzdi2.c", - "clzsi2.c", - "cmpdi2.c", - "comparedf2.c", - "comparesf2.c", - "ctzdi2.c", - "ctzsi2.c", - "divdc3.c", - "divdf3.c", - "divsc3.c", - "divsf3.c", - "divxc3.c", - "extendsfdf2.c", - "extendhfsf2.c", - "ffsdi2.c", - "fixdfdi.c", - "fixdfsi.c", - "fixsfdi.c", - "fixsfsi.c", - "fixunsdfdi.c", - "fixunsdfsi.c", - "fixunssfdi.c", - "fixunssfsi.c", - "fixunsxfdi.c", - "fixunsxfsi.c", - "fixxfdi.c", - "floatdidf.c", - "floatdisf.c", - "floatdixf.c", - "floatsidf.c", - "floatsisf.c", - "floatundidf.c", - "floatundisf.c", - "floatundixf.c", - "floatunsidf.c", - "floatunsisf.c", - "int_util.c", - "muldc3.c", - "muldf3.c", - "mulsc3.c", - "mulsf3.c", - "mulvdi3.c", - "mulvsi3.c", - "mulxc3.c", - "negdf2.c", - "negdi2.c", - "negsf2.c", - "negvdi2.c", - "negvsi2.c", - "paritydi2.c", - "paritysi2.c", - "popcountdi2.c", - "popcountsi2.c", - "powixf2.c", - "subvdi3.c", - "subvsi3.c", - "truncdfhf2.c", - "truncdfsf2.c", - "truncsfhf2.c", - "ucmpdi2.c"]); + sources.extend( + &[ + "absvdi2.c", + "absvsi2.c", + "addvdi3.c", + "addvsi3.c", + "apple_versioning.c", + "clzdi2.c", + "clzsi2.c", + "cmpdi2.c", + "comparedf2.c", + "comparesf2.c", + "ctzdi2.c", + "ctzsi2.c", + "divdc3.c", + "divdf3.c", + "divsc3.c", + "divsf3.c", + "divxc3.c", + "extendsfdf2.c", + "extendhfsf2.c", + "ffsdi2.c", + "fixdfdi.c", + "fixdfsi.c", + "fixsfdi.c", + "fixsfsi.c", + "fixunsdfdi.c", + "fixunsdfsi.c", + "fixunssfdi.c", + "fixunssfsi.c", + "fixunsxfdi.c", + "fixunsxfsi.c", + "fixxfdi.c", + "floatdidf.c", + "floatdisf.c", + "floatdixf.c", + "floatsidf.c", + "floatsisf.c", + "floatundidf.c", + "floatundisf.c", + "floatundixf.c", + "floatunsidf.c", + "floatunsisf.c", + "int_util.c", + "muldc3.c", + "muldf3.c", + "mulsc3.c", + "mulsf3.c", + "mulvdi3.c", + "mulvsi3.c", + "mulxc3.c", + "negdf2.c", + "negdi2.c", + "negsf2.c", + "negvdi2.c", + "negvsi2.c", + "paritydi2.c", + "paritysi2.c", + "popcountdi2.c", + "popcountsi2.c", + "powixf2.c", + "subvdi3.c", + "subvsi3.c", + "truncdfhf2.c", + "truncdfsf2.c", + "truncsfhf2.c", + "ucmpdi2.c", + ], + ); if target_os != "ios" { - sources.extend(&["absvti2.c", - "addvti3.c", - "clzti2.c", - "cmpti2.c", - "ctzti2.c", - "ffsti2.c", - "fixdfti.c", - "fixsfti.c", - "fixunsdfti.c", - "fixunssfti.c", - "fixunsxfti.c", - "fixxfti.c", - "floattidf.c", - "floattisf.c", - "floattixf.c", - "floatuntidf.c", - "floatuntisf.c", - "floatuntixf.c", - "mulvti3.c", - "negti2.c", - "negvti2.c", - "parityti2.c", - "popcountti2.c", - "subvti3.c", - "ucmpti2.c"]); + sources.extend( + &[ + "absvti2.c", + "addvti3.c", + "clzti2.c", + "cmpti2.c", + "ctzti2.c", + "ffsti2.c", + "fixdfti.c", + "fixsfti.c", + "fixunsdfti.c", + "fixunssfti.c", + "fixunsxfti.c", + "fixxfti.c", + "floattidf.c", + "floattisf.c", + "floattixf.c", + "floatuntidf.c", + "floatuntisf.c", + "floatuntixf.c", + "mulvti3.c", + "negti2.c", + "negvti2.c", + "parityti2.c", + "popcountti2.c", + "subvti3.c", + "ucmpti2.c", + ], + ); } if target_vendor == "apple" { - sources.extend(&["atomic_flag_clear.c", - "atomic_flag_clear_explicit.c", - "atomic_flag_test_and_set.c", - "atomic_flag_test_and_set_explicit.c", - "atomic_signal_fence.c", - "atomic_thread_fence.c"]); + sources.extend( + &[ + "atomic_flag_clear.c", + "atomic_flag_clear_explicit.c", + "atomic_flag_test_and_set.c", + "atomic_flag_test_and_set_explicit.c", + "atomic_signal_fence.c", + "atomic_thread_fence.c", + ], + ); } if target_env == "msvc" { if target_arch == "x86_64" { - sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]); + sources.extend( + &[ + "x86_64/floatdidf.c", + "x86_64/floatdisf.c", + "x86_64/floatdixf.c", + ], + ); } } else { if target_os != "freebsd" && target_os != "netbsd" { @@ -239,120 +257,140 @@ mod c { } if target_arch == "x86_64" { - sources.extend(&["x86_64/chkstk.S", - "x86_64/chkstk2.S", - "x86_64/floatdidf.c", - "x86_64/floatdisf.c", - "x86_64/floatdixf.c", - "x86_64/floatundidf.S", - "x86_64/floatundisf.S", - "x86_64/floatundixf.S"]); + sources.extend( + &[ + "x86_64/chkstk.S", + "x86_64/chkstk2.S", + "x86_64/floatdidf.c", + "x86_64/floatdisf.c", + "x86_64/floatdixf.c", + "x86_64/floatundidf.S", + "x86_64/floatundisf.S", + "x86_64/floatundixf.S", + ], + ); } if target_arch == "x86" { - sources.extend(&["i386/ashldi3.S", - "i386/ashrdi3.S", - "i386/chkstk.S", - "i386/chkstk2.S", - "i386/divdi3.S", - "i386/floatdidf.S", - "i386/floatdisf.S", - "i386/floatdixf.S", - "i386/floatundidf.S", - "i386/floatundisf.S", - "i386/floatundixf.S", - "i386/lshrdi3.S", - "i386/moddi3.S", - "i386/muldi3.S", - "i386/udivdi3.S", - "i386/umoddi3.S"]); + sources.extend( + &[ + "i386/ashldi3.S", + "i386/ashrdi3.S", + "i386/chkstk.S", + "i386/chkstk2.S", + "i386/divdi3.S", + "i386/floatdidf.S", + "i386/floatdisf.S", + "i386/floatdixf.S", + "i386/floatundidf.S", + "i386/floatundisf.S", + "i386/floatundixf.S", + "i386/lshrdi3.S", + "i386/moddi3.S", + "i386/muldi3.S", + "i386/udivdi3.S", + "i386/umoddi3.S", + ], + ); } } if target_arch == "arm" && target_os != "ios" { - sources.extend(&["arm/aeabi_cdcmp.S", - "arm/aeabi_cdcmpeq_check_nan.c", - "arm/aeabi_cfcmp.S", - "arm/aeabi_cfcmpeq_check_nan.c", - "arm/aeabi_dcmp.S", - "arm/aeabi_div0.c", - "arm/aeabi_drsub.c", - "arm/aeabi_fcmp.S", - "arm/aeabi_frsub.c", - "arm/bswapdi2.S", - "arm/bswapsi2.S", - "arm/clzdi2.S", - "arm/clzsi2.S", - "arm/comparesf2.S", - "arm/divmodsi4.S", - "arm/divsi3.S", - "arm/modsi3.S", - "arm/switch16.S", - "arm/switch32.S", - "arm/switch8.S", - "arm/switchu8.S", - "arm/sync_synchronize.S", - "arm/udivmodsi4.S", - "arm/udivsi3.S", - "arm/umodsi3.S"]); + sources.extend( + &[ + "arm/aeabi_cdcmp.S", + "arm/aeabi_cdcmpeq_check_nan.c", + "arm/aeabi_cfcmp.S", + "arm/aeabi_cfcmpeq_check_nan.c", + "arm/aeabi_dcmp.S", + "arm/aeabi_div0.c", + "arm/aeabi_drsub.c", + "arm/aeabi_fcmp.S", + "arm/aeabi_frsub.c", + "arm/bswapdi2.S", + "arm/bswapsi2.S", + "arm/clzdi2.S", + "arm/clzsi2.S", + "arm/comparesf2.S", + "arm/divmodsi4.S", + "arm/divsi3.S", + "arm/modsi3.S", + "arm/switch16.S", + "arm/switch32.S", + "arm/switch8.S", + "arm/switchu8.S", + "arm/sync_synchronize.S", + "arm/udivmodsi4.S", + "arm/udivsi3.S", + "arm/umodsi3.S", + ], + ); } if llvm_target[0] == "armv7" { - sources.extend(&["arm/sync_fetch_and_add_4.S", - "arm/sync_fetch_and_add_8.S", - "arm/sync_fetch_and_and_4.S", - "arm/sync_fetch_and_and_8.S", - "arm/sync_fetch_and_max_4.S", - "arm/sync_fetch_and_max_8.S", - "arm/sync_fetch_and_min_4.S", - "arm/sync_fetch_and_min_8.S", - "arm/sync_fetch_and_nand_4.S", - "arm/sync_fetch_and_nand_8.S", - "arm/sync_fetch_and_or_4.S", - "arm/sync_fetch_and_or_8.S", - "arm/sync_fetch_and_sub_4.S", - "arm/sync_fetch_and_sub_8.S", - "arm/sync_fetch_and_umax_4.S", - "arm/sync_fetch_and_umax_8.S", - "arm/sync_fetch_and_umin_4.S", - "arm/sync_fetch_and_umin_8.S", - "arm/sync_fetch_and_xor_4.S", - "arm/sync_fetch_and_xor_8.S"]); + sources.extend( + &[ + "arm/sync_fetch_and_add_4.S", + "arm/sync_fetch_and_add_8.S", + "arm/sync_fetch_and_and_4.S", + "arm/sync_fetch_and_and_8.S", + "arm/sync_fetch_and_max_4.S", + "arm/sync_fetch_and_max_8.S", + "arm/sync_fetch_and_min_4.S", + "arm/sync_fetch_and_min_8.S", + "arm/sync_fetch_and_nand_4.S", + "arm/sync_fetch_and_nand_8.S", + "arm/sync_fetch_and_or_4.S", + "arm/sync_fetch_and_or_8.S", + "arm/sync_fetch_and_sub_4.S", + "arm/sync_fetch_and_sub_8.S", + "arm/sync_fetch_and_umax_4.S", + "arm/sync_fetch_and_umax_8.S", + "arm/sync_fetch_and_umin_4.S", + "arm/sync_fetch_and_umin_8.S", + "arm/sync_fetch_and_xor_4.S", + "arm/sync_fetch_and_xor_8.S", + ], + ); } if llvm_target.last().unwrap().ends_with("eabihf") { if !llvm_target[0].starts_with("thumbv7em") { - sources.extend(&["arm/adddf3vfp.S", - "arm/addsf3vfp.S", - "arm/divdf3vfp.S", - "arm/divsf3vfp.S", - "arm/eqdf2vfp.S", - "arm/eqsf2vfp.S", - "arm/extendsfdf2vfp.S", - "arm/fixdfsivfp.S", - "arm/fixsfsivfp.S", - "arm/fixunsdfsivfp.S", - "arm/fixunssfsivfp.S", - "arm/floatsidfvfp.S", - "arm/floatsisfvfp.S", - "arm/floatunssidfvfp.S", - "arm/floatunssisfvfp.S", - "arm/gedf2vfp.S", - "arm/gesf2vfp.S", - "arm/gtdf2vfp.S", - "arm/gtsf2vfp.S", - "arm/ledf2vfp.S", - "arm/lesf2vfp.S", - "arm/ltdf2vfp.S", - "arm/ltsf2vfp.S", - "arm/muldf3vfp.S", - "arm/mulsf3vfp.S", - "arm/nedf2vfp.S", - "arm/nesf2vfp.S", - "arm/restore_vfp_d8_d15_regs.S", - "arm/save_vfp_d8_d15_regs.S", - "arm/subdf3vfp.S", - "arm/subsf3vfp.S"]); + sources.extend( + &[ + "arm/adddf3vfp.S", + "arm/addsf3vfp.S", + "arm/divdf3vfp.S", + "arm/divsf3vfp.S", + "arm/eqdf2vfp.S", + "arm/eqsf2vfp.S", + "arm/extendsfdf2vfp.S", + "arm/fixdfsivfp.S", + "arm/fixsfsivfp.S", + "arm/fixunsdfsivfp.S", + "arm/fixunssfsivfp.S", + "arm/floatsidfvfp.S", + "arm/floatsisfvfp.S", + "arm/floatunssidfvfp.S", + "arm/floatunssisfvfp.S", + "arm/gedf2vfp.S", + "arm/gesf2vfp.S", + "arm/gtdf2vfp.S", + "arm/gtsf2vfp.S", + "arm/ledf2vfp.S", + "arm/lesf2vfp.S", + "arm/ltdf2vfp.S", + "arm/ltsf2vfp.S", + "arm/muldf3vfp.S", + "arm/mulsf3vfp.S", + "arm/nedf2vfp.S", + "arm/nesf2vfp.S", + "arm/restore_vfp_d8_d15_regs.S", + "arm/save_vfp_d8_d15_regs.S", + "arm/subdf3vfp.S", + "arm/subsf3vfp.S", + ], + ); } sources.extend(&["arm/negdf2vfp.S", "arm/negsf2vfp.S"]); @@ -360,43 +398,51 @@ mod c { } if target_arch == "aarch64" { - sources.extend(&["comparetf2.c", - "extenddftf2.c", - "extendsftf2.c", - "fixtfdi.c", - "fixtfsi.c", - "fixtfti.c", - "fixunstfdi.c", - "fixunstfsi.c", - "fixunstfti.c", - "floatditf.c", - "floatsitf.c", - "floatunditf.c", - "floatunsitf.c", - "multc3.c", - "trunctfdf2.c", - "trunctfsf2.c"]); + sources.extend( + &[ + "comparetf2.c", + "extenddftf2.c", + "extendsftf2.c", + "fixtfdi.c", + "fixtfsi.c", + "fixtfti.c", + "fixunstfdi.c", + "fixunstfsi.c", + "fixunstfti.c", + "floatditf.c", + "floatsitf.c", + "floatunditf.c", + "floatunsitf.c", + "multc3.c", + "trunctfdf2.c", + "trunctfsf2.c", + ], + ); } // Remove the assembly implementations that won't compile for the target if llvm_target[0] == "thumbv6m" { - sources.remove(&["aeabi_cdcmp", - "aeabi_cfcmp", - "aeabi_dcmp", - "aeabi_fcmp", - "clzdi2", - "clzsi2", - "comparesf2", - "divmodsi4", - "divsi3", - "modsi3", - "switch16", - "switch32", - "switch8", - "switchu8", - "udivmodsi4", - "udivsi3", - "umodsi3"]); + sources.remove( + &[ + "aeabi_cdcmp", + "aeabi_cfcmp", + "aeabi_dcmp", + "aeabi_fcmp", + "clzdi2", + "clzsi2", + "comparesf2", + "divmodsi4", + "divsi3", + "modsi3", + "switch16", + "switch32", + "switch8", + "switchu8", + "udivmodsi4", + "udivsi3", + "umodsi3", + ], + ); // But use some generic implementations where possible sources.extend(&["clzdi2.c", "clzsi2.c"]) From af0d6847d704f3e8e2b9574b5688d9ce72b0d67e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 14:38:17 -0500 Subject: [PATCH 0273/4206] no_std compatible tester --- library/compiler-builtins/Cargo.toml | 11 +- library/compiler-builtins/build.rs | 2508 +++++++++++++++++ library/compiler-builtins/src/float/conv.rs | 1 + library/compiler-builtins/tests/adddf3.rs | 8 + library/compiler-builtins/tests/addsf3.rs | 8 + library/compiler-builtins/tests/ashldi3.rs | 8 + library/compiler-builtins/tests/ashlti3.rs | 8 + library/compiler-builtins/tests/ashrdi3.rs | 8 + library/compiler-builtins/tests/ashrti3.rs | 8 + library/compiler-builtins/tests/divdi3.rs | 8 + library/compiler-builtins/tests/divmoddi4.rs | 8 + library/compiler-builtins/tests/divmodsi4.rs | 8 + library/compiler-builtins/tests/divsi3.rs | 8 + library/compiler-builtins/tests/divti3.rs | 8 + library/compiler-builtins/tests/lshrdi3.rs | 8 + library/compiler-builtins/tests/lshrti3.rs | 8 + library/compiler-builtins/tests/moddi3.rs | 8 + library/compiler-builtins/tests/modsi3.rs | 8 + library/compiler-builtins/tests/modti3.rs | 8 + library/compiler-builtins/tests/muldi3.rs | 8 + library/compiler-builtins/tests/mulodi4.rs | 8 + library/compiler-builtins/tests/mulosi4.rs | 8 + library/compiler-builtins/tests/muloti4.rs | 8 + library/compiler-builtins/tests/multi3.rs | 8 + library/compiler-builtins/tests/powidf2.rs | 8 + library/compiler-builtins/tests/powisf2.rs | 8 + library/compiler-builtins/tests/subdf3.rs | 8 + library/compiler-builtins/tests/subsf3.rs | 8 + library/compiler-builtins/tests/udivdi3.rs | 8 + library/compiler-builtins/tests/udivmoddi4.rs | 8 + library/compiler-builtins/tests/udivmodsi4.rs | 8 + library/compiler-builtins/tests/udivmodti4.rs | 8 + library/compiler-builtins/tests/udivsi3.rs | 8 + library/compiler-builtins/tests/udivti3.rs | 8 + library/compiler-builtins/tests/umoddi3.rs | 8 + library/compiler-builtins/tests/umodsi3.rs | 8 + library/compiler-builtins/tests/umodti3.rs | 8 + .../thumbv6m-linux-eabi.json | 24 + .../thumbv7em-linux-eabi.json | 23 + .../thumbv7em-linux-eabihf.json | 24 + .../thumbv7m-linux-eabi.json | 23 + 41 files changed, 2883 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/tests/adddf3.rs create mode 100644 library/compiler-builtins/tests/addsf3.rs create mode 100644 library/compiler-builtins/tests/ashldi3.rs create mode 100644 library/compiler-builtins/tests/ashlti3.rs create mode 100644 library/compiler-builtins/tests/ashrdi3.rs create mode 100644 library/compiler-builtins/tests/ashrti3.rs create mode 100644 library/compiler-builtins/tests/divdi3.rs create mode 100644 library/compiler-builtins/tests/divmoddi4.rs create mode 100644 library/compiler-builtins/tests/divmodsi4.rs create mode 100644 library/compiler-builtins/tests/divsi3.rs create mode 100644 library/compiler-builtins/tests/divti3.rs create mode 100644 library/compiler-builtins/tests/lshrdi3.rs create mode 100644 library/compiler-builtins/tests/lshrti3.rs create mode 100644 library/compiler-builtins/tests/moddi3.rs create mode 100644 library/compiler-builtins/tests/modsi3.rs create mode 100644 library/compiler-builtins/tests/modti3.rs create mode 100644 library/compiler-builtins/tests/muldi3.rs create mode 100644 library/compiler-builtins/tests/mulodi4.rs create mode 100644 library/compiler-builtins/tests/mulosi4.rs create mode 100644 library/compiler-builtins/tests/muloti4.rs create mode 100644 library/compiler-builtins/tests/multi3.rs create mode 100644 library/compiler-builtins/tests/powidf2.rs create mode 100644 library/compiler-builtins/tests/powisf2.rs create mode 100644 library/compiler-builtins/tests/subdf3.rs create mode 100644 library/compiler-builtins/tests/subsf3.rs create mode 100644 library/compiler-builtins/tests/udivdi3.rs create mode 100644 library/compiler-builtins/tests/udivmoddi4.rs create mode 100644 library/compiler-builtins/tests/udivmodsi4.rs create mode 100644 library/compiler-builtins/tests/udivmodti4.rs create mode 100644 library/compiler-builtins/tests/udivsi3.rs create mode 100644 library/compiler-builtins/tests/udivti3.rs create mode 100644 library/compiler-builtins/tests/umoddi3.rs create mode 100644 library/compiler-builtins/tests/umodsi3.rs create mode 100644 library/compiler-builtins/tests/umodti3.rs create mode 100644 library/compiler-builtins/thumbv6m-linux-eabi.json create mode 100644 library/compiler-builtins/thumbv7em-linux-eabi.json create mode 100644 library/compiler-builtins/thumbv7em-linux-eabihf.json create mode 100644 library/compiler-builtins/thumbv7m-linux-eabi.json diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index aea0c38840fba..bc0d105a7907a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -4,17 +4,22 @@ build = "build.rs" name = "compiler_builtins" version = "0.1.0" +[build-dependencies] +rand = "0.3.15" + [build-dependencies.gcc] optional = true version = "0.3.36" +[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 = { git = "https://github.com/japaric/utest", default-features = false } +utest-macros = { git = "https://github.com/japaric/utest" } + [features] -# Build the missing intrinsics from compiler-rt C source code c = ["gcc"] -# Mark this crate as the #![compiler_builtins] crate compiler-builtins = [] default = ["compiler-builtins"] -# Include implementations of memory operations like memcpy mem = [] rustbuild = ["compiler-builtins"] diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index cc778642b8c4b..a3834290aa24f 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1,3 +1,5 @@ +#![feature(i128_type)] + use std::env; fn main() { @@ -15,6 +17,9 @@ fn main() { // custom targets, which can have arbitrary names. let llvm_target = target.split('-').collect::>(); + // Build test files + tests::generate(); + // Build missing intrinsics from compiler-rt C source code #[cfg(feature = "c")] c::compile(&llvm_target); @@ -31,6 +36,2509 @@ fn main() { } } +mod tests { + extern crate rand; + + use std::collections::HashSet; + use std::fmt::Write; + use std::fs::File; + use std::hash::Hash; + use std::path::PathBuf; + use std::{env, mem}; + + use self::rand::Rng; + + const NTESTS: usize = 10_000; + + macro_rules! test { + ($($intrinsic:ident,)+) => { + $( + mk_file::<$intrinsic>(); + )+ + } + } + + pub fn generate() { + // TODO move to main + test! { + // float/add.rs + Adddf3, + Addsf3, + + // float/conv.rs + // Fixdfdi, + // Fixdfsi, + // Fixsfdi, + // Fixsfsi, + // Fixunsdfdi, + // Fixunsdfsi, + // Fixunssfdi, + // Fixunssfsi, + // Floatdidf, + // Floatsidf, + // Floatsisf, + // Floatundidf, + // Floatunsidf, + // Floatunsisf, + + // float/pow.rs + Powidf2, + Powisf2, + + // float/sub.rs + Subdf3, + Subsf3, + + // int/mul.rs + Muldi3, + Mulodi4, + Mulosi4, + Muloti4, + Multi3, + + // int/sdiv.rs + Divdi3, + Divmoddi4, + Divmodsi4, + Divsi3, + Divti3, + Moddi3, + Modsi3, + Modti3, + + // int/shift.rs + Ashldi3, + Ashlti3, + Ashrdi3, + Ashrti3, + Lshrdi3, + Lshrti3, + + // int/udiv.rs + Udivdi3, + Udivmoddi4, + Udivmodsi4, + Udivmodti4, + Udivsi3, + Udivti3, + Umoddi3, + Umodsi3, + Umodti3, + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Adddf3 { + a: u64, + b: u64, + c: u64, + } + + impl TestCase for Adddf3 { + fn name() -> &'static str { + "adddf3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f64(rng); + let b = gen_f64(rng); + let c = a + b; + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() || c.is_nan() { + return None; + } + + Some( + Adddf3 { + a: to_u64(a), + b: to_u64(b), + c: to_u64(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::add::__adddf3; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +fn to_u64(x: f64) -> u64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64, u64), u64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn adddf3() { + for &((a, b), c) in TEST_CASES { + let c_ = __adddf3(mk_f64(a), mk_f64(b)); + assert_eq!(((a, b), c), ((a, b), to_u64(c_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Addsf3 { + a: u32, + b: u32, + c: u32, + } + + impl TestCase for Addsf3 { + fn name() -> &'static str { + "addsf3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f32(rng); + let b = gen_f32(rng); + let c = a + b; + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() || c.is_nan() { + return None; + } + + Some( + Addsf3 { + a: to_u32(a), + b: to_u32(b), + c: to_u32(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::add::__addsf3; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +fn to_u32(x: f32) -> u32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32, u32), u32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn addsf3() { + for &((a, b), c) in TEST_CASES { + let c_ = __addsf3(mk_f32(a), mk_f32(b)); + assert_eq!(((a, b), c), ((a, b), to_u32(c_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Ashldi3 { + a: u64, + b: u32, + c: u64, + } + + impl TestCase for Ashldi3 { + fn name() -> &'static str { + "ashldi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u64(rng); + let b = (rng.gen::() % 64) as u32; + let c = a << b; + + Some(Ashldi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::shift::__ashldi3; + +static TEST_CASES: &[((u64, u32), u64)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn ashldi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __ashldi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Ashlti3 { + a: u128, + b: u32, + c: u128, + } + + impl TestCase for Ashlti3 { + fn name() -> &'static str { + "ashlti3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u128(rng); + let b = (rng.gen::() % 128) as u32; + let c = a << b; + + Some(Ashlti3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::shift::__ashlti3; + +static TEST_CASES: &[((u128, u32), u128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn ashlti3() { + for &((a, b), c) in TEST_CASES { + let c_ = __ashlti3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Ashrdi3 { + a: i64, + b: u32, + c: i64, + } + + impl TestCase for Ashrdi3 { + fn name() -> &'static str { + "ashrdi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i64(rng); + let b = (rng.gen::() % 64) as u32; + let c = a >> b; + + Some(Ashrdi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::shift::__ashrdi3; + +static TEST_CASES: &[((i64, u32), i64)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn ashrdi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __ashrdi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Ashrti3 { + a: i128, + b: u32, + c: i128, + } + + impl TestCase for Ashrti3 { + fn name() -> &'static str { + "ashrti3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i128(rng); + let b = (rng.gen::() % 128) as u32; + let c = a >> b; + + Some(Ashrti3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::shift::__ashrti3; + +static TEST_CASES: &[((i128, u32), i128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn ashrti3() { + for &((a, b), c) in TEST_CASES { + let c_ = __ashrti3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Divmoddi4 { + a: i64, + b: i64, + c: i64, + rem: i64, + } + + impl TestCase for Divmoddi4 { + fn name() -> &'static str { + "divmoddi4" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i64(rng); + let b = gen_i64(rng); + if b == 0 { + return None; + } + let c = a / b; + let rem = a % b; + + Some(Divmoddi4 { a, b, c, rem }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {rem})),", + a = self.a, + b = self.b, + c = self.c, + rem = self.rem + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__divmoddi4; + +static TEST_CASES: &[((i64, i64), (i64, i64))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divmoddi4() { + for &((a, b), (c, rem)) in TEST_CASES { + let mut rem_ = 0; + let c_ = __divmoddi4(a, b, &mut rem_); + assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Divdi3 { + a: i64, + b: i64, + c: i64, + } + + impl TestCase for Divdi3 { + fn name() -> &'static str { + "divdi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i64(rng); + let b = gen_i64(rng); + if b == 0 { + return None; + } + let c = a / b; + + Some(Divdi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__divdi3; + +static TEST_CASES: &[((i64, i64), i64)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divdi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __divdi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Divmodsi4 { + a: i32, + b: i32, + c: i32, + rem: i32, + } + + impl TestCase for Divmodsi4 { + fn name() -> &'static str { + "divmodsi4" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i32(rng); + let b = gen_i32(rng); + if b == 0 { + return None; + } + let c = a / b; + let rem = a % b; + + Some(Divmodsi4 { a, b, c, rem }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {rem})),", + a = self.a, + b = self.b, + c = self.c, + rem = self.rem + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__divmodsi4; + +static TEST_CASES: &[((i32, i32), (i32, i32))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divmodsi4() { + for &((a, b), (c, rem)) in TEST_CASES { + let mut rem_ = 0; + let c_ = __divmodsi4(a, b, &mut rem_); + assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Divsi3 { + a: i32, + b: i32, + c: i32, + } + + impl TestCase for Divsi3 { + fn name() -> &'static str { + "divsi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i32(rng); + let b = gen_i32(rng); + if b == 0 { + return None; + } + let c = a / b; + + Some(Divsi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__divsi3; + +static TEST_CASES: &[((i32, i32), i32)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divsi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __divsi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Divti3 { + a: i128, + b: i128, + c: i128, + } + + impl TestCase for Divti3 { + fn name() -> &'static str { + "divti3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i128(rng); + let b = gen_i128(rng); + if b == 0 { + return None; + } + let c = a / b; + + Some(Divti3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__divti3; + +static TEST_CASES: &[((i128, i128), i128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divti3() { + for &((a, b), c) in TEST_CASES { + let c_ = __divti3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Moddi3 { + a: i64, + b: i64, + c: i64, + } + + impl TestCase for Moddi3 { + fn name() -> &'static str { + "moddi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i64(rng); + let b = gen_i64(rng); + if b == 0 { + return None; + } + let c = a % b; + + Some(Moddi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__moddi3; + +static TEST_CASES: &[((i64, i64), i64)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn moddi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __moddi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Modsi3 { + a: i32, + b: i32, + c: i32, + } + + impl TestCase for Modsi3 { + fn name() -> &'static str { + "modsi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i32(rng); + let b = gen_i32(rng); + if b == 0 { + return None; + } + let c = a % b; + + Some(Modsi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__modsi3; + +static TEST_CASES: &[((i32, i32), i32)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn modsi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __modsi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Modti3 { + a: i128, + b: i128, + c: i128, + } + + impl TestCase for Modti3 { + fn name() -> &'static str { + "modti3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i128(rng); + let b = gen_i128(rng); + if b == 0 { + return None; + } + let c = a % b; + + Some(Modti3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__modti3; + +static TEST_CASES: &[((i128, i128), i128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn modti3() { + for &((a, b), c) in TEST_CASES { + let c_ = __modti3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + struct Muldi3 { + a: u64, + b: u64, + c: u64, + } + + impl TestCase for Muldi3 { + fn name() -> &'static str { + "muldi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u64(rng); + let b = gen_u64(rng); + let c = a.wrapping_mul(b); + + Some(Muldi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::mul::__muldi3; + +static TEST_CASES: &[((u64, u64), u64)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn muldi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __muldi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Mulodi4 { + a: i64, + b: i64, + c: i64, + overflow: u32, + } + + impl TestCase for Mulodi4 { + fn name() -> &'static str { + "mulodi4" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + { + let a = gen_i64(rng); + let b = gen_i64(rng); + let c = a.wrapping_mul(b); + let overflow = if a.checked_mul(b).is_some() { 0 } else { 1 }; + + Some(Mulodi4 { a, b, c, overflow }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {overflow})),", + a = self.a, + b = self.b, + c = self.c, + overflow = self.overflow + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::mul::__mulodi4; + +static TEST_CASES: &[((i64, i64), (i64, i32))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn mulodi4() { + let mut overflow_ = 2; + for &((a, b), (c, overflow)) in TEST_CASES { + let c_ = __mulodi4(a, b, &mut overflow_); + assert_eq!(((a, b), (c, overflow)), ((a, b), (c_, overflow_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Mulosi4 { + a: i32, + b: i32, + c: i32, + overflow: u32, + } + + impl TestCase for Mulosi4 { + fn name() -> &'static str { + "mulosi4" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + { + let a = gen_i32(rng); + let b = gen_i32(rng); + let c = a.wrapping_mul(b); + let overflow = if a.checked_mul(b).is_some() { 0 } else { 1 }; + + Some(Mulosi4 { a, b, c, overflow }) + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::mul::__mulosi4; + +static TEST_CASES: &[((i32, i32), (i32, i32))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn mulosi4() { + let mut overflow_ = 2; + for &((a, b), (c, overflow)) in TEST_CASES { + let c_ = __mulosi4(a, b, &mut overflow_); + assert_eq!(((a, b), (c, overflow)), ((a, b), (c_, overflow_))); + } +} +" + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {overflow})),", + a = self.a, + b = self.b, + c = self.c, + overflow = self.overflow + ) + .unwrap(); + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Muloti4 { + a: i128, + b: i128, + c: i128, + overflow: u32, + } + + impl TestCase for Muloti4 { + fn name() -> &'static str { + "muloti4" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + { + let a = gen_i128(rng); + let b = gen_i128(rng); + let c = a.wrapping_mul(b); + let overflow = if a.checked_mul(b).is_some() { 0 } else { 1 }; + + Some(Muloti4 { a, b, c, overflow }) + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::mul::__muloti4; + +static TEST_CASES: &[((i128, i128), (i128, i32))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn muloti4() { + let mut overflow_ = 2; + for &((a, b), (c, overflow)) in TEST_CASES { + let c_ = __muloti4(a, b, &mut overflow_); + assert_eq!(((a, b), (c, overflow)), ((a, b), (c_, overflow_))); + } +} +" + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {overflow})),", + a = self.a, + b = self.b, + c = self.c, + overflow = self.overflow + ) + .unwrap(); + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Multi3 { + a: i128, + b: i128, + c: i128, + } + + impl TestCase for Multi3 { + fn name() -> &'static str { + "multi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i128(rng); + let b = gen_i128(rng); + let c = a.wrapping_mul(b); + + Some(Multi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::mul::__multi3; + +static TEST_CASES: &[((i128, i128), i128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn multi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __multi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Powidf2 { + a: u64, + b: i32, + c: u64, + } + + impl TestCase for Powidf2 { + fn name() -> &'static str { + "powidf2" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f64(rng); + let b = gen_i32(rng); + let c = a.powi(b); + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets + if a.is_nan() || c.is_nan() { + return None; + } + + Some( + Powidf2 { + a: to_u64(a), + b, + c: to_u64(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::pow::__powidf2; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +fn to_u64(x: f64) -> u64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64, i32), u64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn powidf2() { + for &((a, b), c) in TEST_CASES { + let c_ = __powidf2(mk_f64(a), b); + assert_eq!(((a, b), c), ((a, b), to_u64(c_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Powisf2 { + a: u32, + b: i32, + c: u32, + } + + impl TestCase for Powisf2 { + fn name() -> &'static str { + "powisf2" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f32(rng); + let b = gen_i32(rng); + let c = a.powi(b); + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets + if a.is_nan() || c.is_nan() { + return None; + } + + Some( + Powisf2 { + a: to_u32(a), + b, + c: to_u32(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::pow::__powisf2; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +fn to_u32(x: f32) -> u32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32, i32), u32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn powisf2() { + for &((a, b), c) in TEST_CASES { + let c_ = __powisf2(mk_f32(a), b); + assert_eq!(((a, b), c), ((a, b), to_u32(c_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Lshrdi3 { + a: u64, + b: u32, + c: u64, + } + + impl TestCase for Lshrdi3 { + fn name() -> &'static str { + "lshrdi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u64(rng); + let b = (rng.gen::() % 64) as u32; + let c = a >> b; + + Some(Lshrdi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::shift::__lshrdi3; + +static TEST_CASES: &[((u64, u32), u64)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn lshrdi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __lshrdi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Lshrti3 { + a: u128, + b: u32, + c: u128, + } + + impl TestCase for Lshrti3 { + fn name() -> &'static str { + "lshrti3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u128(rng); + let b = (rng.gen::() % 128) as u32; + let c = a >> b; + + Some(Lshrti3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::shift::__lshrti3; + +static TEST_CASES: &[((u128, u32), u128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn lshrti3() { + for &((a, b), c) in TEST_CASES { + let c_ = __lshrti3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Subdf3 { + a: u64, + b: u64, + c: u64, + } + + impl TestCase for Subdf3 { + fn name() -> &'static str { + "subdf3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f64(rng); + let b = gen_f64(rng); + let c = a - b; + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() || c.is_nan() { + return None; + } + + Some( + Subdf3 { + a: to_u64(a), + b: to_u64(b), + c: to_u64(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::sub::__subdf3; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +fn to_u64(x: f64) -> u64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64, u64), u64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn subdf3() { + for &((a, b), c) in TEST_CASES { + let c_ = __subdf3(mk_f64(a), mk_f64(b)); + assert_eq!(((a, b), c), ((a, b), to_u64(c_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Subsf3 { + a: u32, + b: u32, + c: u32, + } + + impl TestCase for Subsf3 { + fn name() -> &'static str { + "subsf3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f32(rng); + let b = gen_f32(rng); + let c = a - b; + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() || c.is_nan() { + return None; + } + + Some( + Subsf3 { + a: to_u32(a), + b: to_u32(b), + c: to_u32(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::sub::__subsf3; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +fn to_u32(x: f32) -> u32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32, u32), u32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn subsf3() { + for &((a, b), c) in TEST_CASES { + let c_ = __subsf3(mk_f32(a), mk_f32(b)); + assert_eq!(((a, b), c), ((a, b), to_u32(c_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Udivdi3 { + a: u64, + b: u64, + c: u64, + } + + impl TestCase for Udivdi3 { + fn name() -> &'static str { + "udivdi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u64(rng); + let b = gen_u64(rng); + if b == 0 { + return None; + } + let c = a / b; + + Some(Udivdi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::udiv::__udivdi3; + +static TEST_CASES: &[((u64, u64), u64)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn udivdi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __udivdi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Udivmoddi4 { + a: u64, + b: u64, + c: u64, + rem: u64, + } + + impl TestCase for Udivmoddi4 { + fn name() -> &'static str { + "udivmoddi4" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u64(rng); + let b = gen_u64(rng); + if b == 0 { + return None; + } + let c = a / b; + let rem = a % b; + + Some(Udivmoddi4 { a, b, c, rem }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {rem})),", + a = self.a, + b = self.b, + c = self.c, + rem = self.rem + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::udiv::__udivmoddi4; + +static TEST_CASES: &[((u64, u64), (u64, u64))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn udivmoddi4() { + for &((a, b), (c, rem)) in TEST_CASES { + let mut rem_ = 0; + let c_ = __udivmoddi4(a, b, Some(&mut rem_)); + assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Udivmodsi4 { + a: u32, + b: u32, + c: u32, + rem: u32, + } + + impl TestCase for Udivmodsi4 { + fn name() -> &'static str { + "udivmodsi4" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u32(rng); + let b = gen_u32(rng); + if b == 0 { + return None; + } + let c = a / b; + let rem = a % b; + + Some(Udivmodsi4 { a, b, c, rem }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {rem})),", + a = self.a, + b = self.b, + c = self.c, + rem = self.rem + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::udiv::__udivmodsi4; + +static TEST_CASES: &[((u32, u32), (u32, u32))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn udivmodsi4() { + for &((a, b), (c, rem)) in TEST_CASES { + let mut rem_ = 0; + let c_ = __udivmodsi4(a, b, Some(&mut rem_)); + assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Udivmodti4 { + a: u128, + b: u128, + c: u128, + rem: u128, + } + + impl TestCase for Udivmodti4 { + fn name() -> &'static str { + "udivmodti4" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u128(rng); + let b = gen_u128(rng); + if b == 0 { + return None; + } + let c = a / b; + let rem = a % b; + + Some(Udivmodti4 { a, b, c, rem }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {rem})),", + a = self.a, + b = self.b, + c = self.c, + rem = self.rem + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::udiv::__udivmodti4; + +static TEST_CASES: &[((u128, u128), (u128, u128))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn udivmodti4() { + for &((a, b), (c, rem)) in TEST_CASES { + let mut rem_ = 0; + let c_ = __udivmodti4(a, b, Some(&mut rem_)); + assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Udivsi3 { + a: u32, + b: u32, + c: u32, + } + + impl TestCase for Udivsi3 { + fn name() -> &'static str { + "udivsi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u32(rng); + let b = gen_u32(rng); + if b == 0 { + return None; + } + let c = a / b; + + Some(Udivsi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::udiv::__udivsi3; + +static TEST_CASES: &[((u32, u32), u32)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn udivsi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __udivsi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Udivti3 { + a: u128, + b: u128, + c: u128, + } + + impl TestCase for Udivti3 { + fn name() -> &'static str { + "udivti3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u128(rng); + let b = gen_u128(rng); + if b == 0 { + return None; + } + let c = a / b; + + Some(Udivti3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::udiv::__udivti3; + +static TEST_CASES: &[((u128, u128), u128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn udivti3() { + for &((a, b), c) in TEST_CASES { + let c_ = __udivti3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Umoddi3 { + a: u64, + b: u64, + c: u64, + } + + impl TestCase for Umoddi3 { + fn name() -> &'static str { + "umoddi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u64(rng); + let b = gen_u64(rng); + if b == 0 { + return None; + } + let c = a % b; + + Some(Umoddi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::udiv::__umoddi3; + +static TEST_CASES: &[((u64, u64), u64)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn umoddi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __umoddi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Umodsi3 { + a: u32, + b: u32, + c: u32, + } + + impl TestCase for Umodsi3 { + fn name() -> &'static str { + "umodsi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u32(rng); + let b = gen_u32(rng); + if b == 0 { + return None; + } + let c = a % b; + + Some(Umodsi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::udiv::__umodsi3; + +static TEST_CASES: &[((u32, u32), u32)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn umodsi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __umodsi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Umodti3 { + a: u128, + b: u128, + c: u128, + } + + impl TestCase for Umodti3 { + fn name() -> &'static str { + "umodti3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u128(rng); + let b = gen_u128(rng); + if b == 0 { + return None; + } + let c = a % b; + + Some(Umodti3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::udiv::__umodti3; + +static TEST_CASES: &[((u128, u128), u128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn umodti3() { + for &((a, b), c) in TEST_CASES { + let c_ = __umodti3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + trait TestCase { + /// Name of the intrinsic to test + fn name() -> &'static str; + /// Generates a valid test case + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized; + /// Stringifies a test case + fn to_string(&self, buffer: &mut String); + /// Prologue of the test file + fn prologue() -> &'static str; + /// Epilogue of the test file + fn epilogue() -> &'static str; + } + + const PROLOGUE: &'static str = r#" +extern crate compiler_builtins; + +// test runner +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +extern crate utest_cortex_m_qemu; + +// overrides `panic!` +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +#[macro_use] +extern crate utest_macros; + +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +macro_rules! panic { + ($($tt:tt)*) => { + upanic!($($tt)*); + }; +} +"#; + + macro_rules! gen_int { + ($name:ident, $ity:ident, $hty:ident) => { + fn $name(rng: &mut R) -> $ity + where + R: Rng, + { + let mut mk = || if rng.gen_weighted_bool(10) { + *rng.choose(&[::std::$hty::MAX, 0, ::std::$hty::MIN]).unwrap() + } else { + rng.gen::<$hty>() + }; + unsafe { mem::transmute([mk(), mk()]) } + } + + } + } + + gen_int!(gen_i32, i32, i16); + gen_int!(gen_i64, i64, i32); + gen_int!(gen_i128, i128, i64); + + macro_rules! gen_float { + ($name:ident, + $fty:ident, + $uty:ident, + $bits:expr, + $significand_bits:expr) => { + pub fn $name(rng: &mut R) -> $fty + where + R: Rng, + { + const BITS: u8 = $bits; + const SIGNIFICAND_BITS: u8 = $significand_bits; + + const SIGNIFICAND_MASK: $uty = (1 << SIGNIFICAND_BITS) - 1; + const SIGN_MASK: $uty = (1 << (BITS - 1)); + const EXPONENT_MASK: $uty = !(SIGN_MASK | SIGNIFICAND_MASK); + + fn mk_f32(sign: bool, exponent: $uty, significand: $uty) -> $fty { + unsafe { + mem::transmute(((sign as $uty) << (BITS - 1)) | + ((exponent & EXPONENT_MASK) << + SIGNIFICAND_BITS) | + (significand & SIGNIFICAND_MASK)) + } + } + + if rng.gen_weighted_bool(10) { + // Special values + *rng.choose(&[-0.0, + 0.0, + ::std::$fty::NAN, + ::std::$fty::INFINITY, + -::std::$fty::INFINITY]) + .unwrap() + } else if rng.gen_weighted_bool(10) { + // NaN patterns + mk_f32(rng.gen(), rng.gen(), 0) + } else if rng.gen() { + // Denormalized + mk_f32(rng.gen(), 0, rng.gen()) + } else { + // Random anything + mk_f32(rng.gen(), rng.gen(), rng.gen()) + } + } + } + } + + gen_float!(gen_f32, f32, u32, 32, 23); + gen_float!(gen_f64, f64, u64, 64, 52); + + pub fn gen_u128(rng: &mut R) -> u128 + where + R: Rng, + { + gen_i128(rng) as u128 + } + + pub fn gen_u32(rng: &mut R) -> u32 + where + R: Rng, + { + gen_i32(rng) as u32 + } + + fn gen_u64(rng: &mut R) -> u64 + where + R: Rng, + { + gen_i64(rng) as u64 + } + + pub fn to_u32(x: f32) -> u32 { + unsafe { mem::transmute(x) } + } + + pub fn to_u64(x: f64) -> u64 { + unsafe { mem::transmute(x) } + } + + fn mk_tests(mut n: usize, rng: &mut R) -> String + where + T: Eq + Hash + TestCase, + R: Rng, + { + let mut buffer = PROLOGUE.to_owned(); + buffer.push_str(T::prologue()); + let mut cases = HashSet::new(); + while n != 0 { + if let Some(case) = T::generate(rng) { + if cases.contains(&case) { + continue; + } + case.to_string(&mut buffer); + n -= 1; + cases.insert(case); + } + } + buffer.push_str(T::epilogue()); + buffer + } + + fn mk_file() + where + T: Eq + Hash + TestCase, + { + use std::io::Write; + + let rng = &mut rand::thread_rng(); + let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let out_file = out_dir.join(format!("{}.rs", T::name())); + let contents = mk_tests::(NTESTS, rng); + + File::create(out_file) + .unwrap() + .write_all(contents.as_bytes()) + .unwrap(); + } +} + #[cfg(feature = "c")] mod c { extern crate gcc; diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index e04b26bf536a6..efe590ab43be2 100755 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -94,6 +94,7 @@ enum Sign { Positive, Negative } + macro_rules! fp_fix { ($intrinsic:ident: $fty:ty, $ity:ty) => { pub extern "C" fn $intrinsic(f: $fty) -> $ity { diff --git a/library/compiler-builtins/tests/adddf3.rs b/library/compiler-builtins/tests/adddf3.rs new file mode 100644 index 0000000000000..3129330afaf5e --- /dev/null +++ b/library/compiler-builtins/tests/adddf3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/adddf3.rs")); diff --git a/library/compiler-builtins/tests/addsf3.rs b/library/compiler-builtins/tests/addsf3.rs new file mode 100644 index 0000000000000..b5c9c3dfebdb9 --- /dev/null +++ b/library/compiler-builtins/tests/addsf3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/addsf3.rs")); diff --git a/library/compiler-builtins/tests/ashldi3.rs b/library/compiler-builtins/tests/ashldi3.rs new file mode 100644 index 0000000000000..1116375d3ef35 --- /dev/null +++ b/library/compiler-builtins/tests/ashldi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/ashldi3.rs")); diff --git a/library/compiler-builtins/tests/ashlti3.rs b/library/compiler-builtins/tests/ashlti3.rs new file mode 100644 index 0000000000000..4c799cf8822a9 --- /dev/null +++ b/library/compiler-builtins/tests/ashlti3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/ashlti3.rs")); diff --git a/library/compiler-builtins/tests/ashrdi3.rs b/library/compiler-builtins/tests/ashrdi3.rs new file mode 100644 index 0000000000000..a0a2b6cb13af1 --- /dev/null +++ b/library/compiler-builtins/tests/ashrdi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/ashrdi3.rs")); diff --git a/library/compiler-builtins/tests/ashrti3.rs b/library/compiler-builtins/tests/ashrti3.rs new file mode 100644 index 0000000000000..b147051c2d93a --- /dev/null +++ b/library/compiler-builtins/tests/ashrti3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/ashrti3.rs")); diff --git a/library/compiler-builtins/tests/divdi3.rs b/library/compiler-builtins/tests/divdi3.rs new file mode 100644 index 0000000000000..4bdce54156eda --- /dev/null +++ b/library/compiler-builtins/tests/divdi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/divdi3.rs")); diff --git a/library/compiler-builtins/tests/divmoddi4.rs b/library/compiler-builtins/tests/divmoddi4.rs new file mode 100644 index 0000000000000..9ddd85a829fcf --- /dev/null +++ b/library/compiler-builtins/tests/divmoddi4.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/divmoddi4.rs")); diff --git a/library/compiler-builtins/tests/divmodsi4.rs b/library/compiler-builtins/tests/divmodsi4.rs new file mode 100644 index 0000000000000..6fe80e9756918 --- /dev/null +++ b/library/compiler-builtins/tests/divmodsi4.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/divmodsi4.rs")); diff --git a/library/compiler-builtins/tests/divsi3.rs b/library/compiler-builtins/tests/divsi3.rs new file mode 100644 index 0000000000000..e6440d782c778 --- /dev/null +++ b/library/compiler-builtins/tests/divsi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/divsi3.rs")); diff --git a/library/compiler-builtins/tests/divti3.rs b/library/compiler-builtins/tests/divti3.rs new file mode 100644 index 0000000000000..62d9789d0f87b --- /dev/null +++ b/library/compiler-builtins/tests/divti3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/divti3.rs")); diff --git a/library/compiler-builtins/tests/lshrdi3.rs b/library/compiler-builtins/tests/lshrdi3.rs new file mode 100644 index 0000000000000..b1a2331b196ac --- /dev/null +++ b/library/compiler-builtins/tests/lshrdi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/lshrdi3.rs")); diff --git a/library/compiler-builtins/tests/lshrti3.rs b/library/compiler-builtins/tests/lshrti3.rs new file mode 100644 index 0000000000000..2ee32ce71f4d2 --- /dev/null +++ b/library/compiler-builtins/tests/lshrti3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/lshrti3.rs")); diff --git a/library/compiler-builtins/tests/moddi3.rs b/library/compiler-builtins/tests/moddi3.rs new file mode 100644 index 0000000000000..6a58a77ab49dc --- /dev/null +++ b/library/compiler-builtins/tests/moddi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/moddi3.rs")); diff --git a/library/compiler-builtins/tests/modsi3.rs b/library/compiler-builtins/tests/modsi3.rs new file mode 100644 index 0000000000000..46ad8cd33cdce --- /dev/null +++ b/library/compiler-builtins/tests/modsi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/modsi3.rs")); diff --git a/library/compiler-builtins/tests/modti3.rs b/library/compiler-builtins/tests/modti3.rs new file mode 100644 index 0000000000000..1a363f7cb4191 --- /dev/null +++ b/library/compiler-builtins/tests/modti3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/modti3.rs")); diff --git a/library/compiler-builtins/tests/muldi3.rs b/library/compiler-builtins/tests/muldi3.rs new file mode 100644 index 0000000000000..d771e8a6bde32 --- /dev/null +++ b/library/compiler-builtins/tests/muldi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/muldi3.rs")); diff --git a/library/compiler-builtins/tests/mulodi4.rs b/library/compiler-builtins/tests/mulodi4.rs new file mode 100644 index 0000000000000..071a295810f78 --- /dev/null +++ b/library/compiler-builtins/tests/mulodi4.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/mulodi4.rs")); diff --git a/library/compiler-builtins/tests/mulosi4.rs b/library/compiler-builtins/tests/mulosi4.rs new file mode 100644 index 0000000000000..3ec4336d118b3 --- /dev/null +++ b/library/compiler-builtins/tests/mulosi4.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/mulosi4.rs")); diff --git a/library/compiler-builtins/tests/muloti4.rs b/library/compiler-builtins/tests/muloti4.rs new file mode 100644 index 0000000000000..262b46465920b --- /dev/null +++ b/library/compiler-builtins/tests/muloti4.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/muloti4.rs")); diff --git a/library/compiler-builtins/tests/multi3.rs b/library/compiler-builtins/tests/multi3.rs new file mode 100644 index 0000000000000..db5253874386c --- /dev/null +++ b/library/compiler-builtins/tests/multi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/multi3.rs")); diff --git a/library/compiler-builtins/tests/powidf2.rs b/library/compiler-builtins/tests/powidf2.rs new file mode 100644 index 0000000000000..dde5f03eb9cb9 --- /dev/null +++ b/library/compiler-builtins/tests/powidf2.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/powidf2.rs")); diff --git a/library/compiler-builtins/tests/powisf2.rs b/library/compiler-builtins/tests/powisf2.rs new file mode 100644 index 0000000000000..3e0baeb73cecb --- /dev/null +++ b/library/compiler-builtins/tests/powisf2.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/powisf2.rs")); diff --git a/library/compiler-builtins/tests/subdf3.rs b/library/compiler-builtins/tests/subdf3.rs new file mode 100644 index 0000000000000..13f695718e1aa --- /dev/null +++ b/library/compiler-builtins/tests/subdf3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/subdf3.rs")); diff --git a/library/compiler-builtins/tests/subsf3.rs b/library/compiler-builtins/tests/subsf3.rs new file mode 100644 index 0000000000000..7be426c453140 --- /dev/null +++ b/library/compiler-builtins/tests/subsf3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/subsf3.rs")); diff --git a/library/compiler-builtins/tests/udivdi3.rs b/library/compiler-builtins/tests/udivdi3.rs new file mode 100644 index 0000000000000..d87091c7d84d0 --- /dev/null +++ b/library/compiler-builtins/tests/udivdi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/udivdi3.rs")); diff --git a/library/compiler-builtins/tests/udivmoddi4.rs b/library/compiler-builtins/tests/udivmoddi4.rs new file mode 100644 index 0000000000000..a9444c10db352 --- /dev/null +++ b/library/compiler-builtins/tests/udivmoddi4.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/udivmoddi4.rs")); diff --git a/library/compiler-builtins/tests/udivmodsi4.rs b/library/compiler-builtins/tests/udivmodsi4.rs new file mode 100644 index 0000000000000..e93bfe1e55281 --- /dev/null +++ b/library/compiler-builtins/tests/udivmodsi4.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/udivmodsi4.rs")); diff --git a/library/compiler-builtins/tests/udivmodti4.rs b/library/compiler-builtins/tests/udivmodti4.rs new file mode 100644 index 0000000000000..1f9ed27992631 --- /dev/null +++ b/library/compiler-builtins/tests/udivmodti4.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/udivmodti4.rs")); diff --git a/library/compiler-builtins/tests/udivsi3.rs b/library/compiler-builtins/tests/udivsi3.rs new file mode 100644 index 0000000000000..d6433e7c31ddd --- /dev/null +++ b/library/compiler-builtins/tests/udivsi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/udivsi3.rs")); diff --git a/library/compiler-builtins/tests/udivti3.rs b/library/compiler-builtins/tests/udivti3.rs new file mode 100644 index 0000000000000..fc602fd28af03 --- /dev/null +++ b/library/compiler-builtins/tests/udivti3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/udivti3.rs")); diff --git a/library/compiler-builtins/tests/umoddi3.rs b/library/compiler-builtins/tests/umoddi3.rs new file mode 100644 index 0000000000000..09a114ee6b949 --- /dev/null +++ b/library/compiler-builtins/tests/umoddi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/umoddi3.rs")); diff --git a/library/compiler-builtins/tests/umodsi3.rs b/library/compiler-builtins/tests/umodsi3.rs new file mode 100644 index 0000000000000..aa56e819c2748 --- /dev/null +++ b/library/compiler-builtins/tests/umodsi3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/umodsi3.rs")); diff --git a/library/compiler-builtins/tests/umodti3.rs b/library/compiler-builtins/tests/umodti3.rs new file mode 100644 index 0000000000000..63a0bf28f2f55 --- /dev/null +++ b/library/compiler-builtins/tests/umodti3.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/umodti3.rs")); diff --git a/library/compiler-builtins/thumbv6m-linux-eabi.json b/library/compiler-builtins/thumbv6m-linux-eabi.json new file mode 100644 index 0000000000000..d3ac24dfc5e91 --- /dev/null +++ b/library/compiler-builtins/thumbv6m-linux-eabi.json @@ -0,0 +1,24 @@ +{ + "abi-blacklist": [ + "stdcall", + "fastcall", + "vectorcall", + "win64", + "sysv64" + ], + "arch": "arm", + "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "env": "", + "executables": true, + "features": "+strict-align", + "linker": "arm-none-eabi-gcc", + "llvm-target": "thumbv6m-none-eabi", + "max-atomic-width": 0, + "os": "linux", + "panic-strategy": "abort", + "pre-link-args": ["-nostartfiles"], + "relocation-model": "static", + "target-endian": "little", + "target-pointer-width": "32", + "vendor": "" +} diff --git a/library/compiler-builtins/thumbv7em-linux-eabi.json b/library/compiler-builtins/thumbv7em-linux-eabi.json new file mode 100644 index 0000000000000..af6ea94eebdd4 --- /dev/null +++ b/library/compiler-builtins/thumbv7em-linux-eabi.json @@ -0,0 +1,23 @@ +{ + "abi-blacklist": [ + "stdcall", + "fastcall", + "vectorcall", + "win64", + "sysv64" + ], + "arch": "arm", + "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "env": "", + "executables": true, + "linker": "arm-none-eabi-gcc", + "llvm-target": "thumbv7em-none-eabi", + "max-atomic-width": 32, + "os": "linux", + "panic-strategy": "abort", + "pre-link-args": ["-nostartfiles"], + "relocation-model": "static", + "target-endian": "little", + "target-pointer-width": "32", + "vendor": "" +} diff --git a/library/compiler-builtins/thumbv7em-linux-eabihf.json b/library/compiler-builtins/thumbv7em-linux-eabihf.json new file mode 100644 index 0000000000000..536d28c951dfc --- /dev/null +++ b/library/compiler-builtins/thumbv7em-linux-eabihf.json @@ -0,0 +1,24 @@ +{ + "abi-blacklist": [ + "stdcall", + "fastcall", + "vectorcall", + "win64", + "sysv64" + ], + "arch": "arm", + "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "env": "", + "executables": true, + "features": "+vfp4,+d16,+fp-only-sp", + "linker": "arm-none-eabi-gcc", + "llvm-target": "thumbv7em-none-eabihf", + "max-atomic-width": 32, + "os": "linux", + "panic-strategy": "abort", + "pre-link-args": ["-nostartfiles"], + "relocation-model": "static", + "target-endian": "little", + "target-pointer-width": "32", + "vendor": "" +} diff --git a/library/compiler-builtins/thumbv7m-linux-eabi.json b/library/compiler-builtins/thumbv7m-linux-eabi.json new file mode 100644 index 0000000000000..02ed839cc82d9 --- /dev/null +++ b/library/compiler-builtins/thumbv7m-linux-eabi.json @@ -0,0 +1,23 @@ +{ + "abi-blacklist": [ + "stdcall", + "fastcall", + "vectorcall", + "win64", + "sysv64" + ], + "arch": "arm", + "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", + "env": "", + "executables": true, + "linker": "arm-none-eabi-gcc", + "llvm-target": "thumbv7m-none-eabi", + "max-atomic-width": 32, + "os": "linux", + "panic-strategy": "abort", + "pre-link-args": ["-nostartfiles"], + "relocation-model": "static", + "target-endian": "little", + "target-pointer-width": "32", + "vendor": "" +} From 62091bb12492006566e746d30d6cf54552548aa2 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 16:12:49 -0500 Subject: [PATCH 0274/4206] test float/conv.rs --- library/compiler-builtins/Cargo.toml | 22 +- library/compiler-builtins/build.rs | 1230 ++++++++++++++--- library/compiler-builtins/tests/fixdfdi.rs | 8 + library/compiler-builtins/tests/fixdfsi.rs | 8 + library/compiler-builtins/tests/fixsfdi.rs | 8 + library/compiler-builtins/tests/fixsfsi.rs | 8 + library/compiler-builtins/tests/fixunsdfdi.rs | 8 + library/compiler-builtins/tests/fixunsdfsi.rs | 8 + library/compiler-builtins/tests/fixunssfdi.rs | 8 + library/compiler-builtins/tests/fixunssfsi.rs | 8 + library/compiler-builtins/tests/floatdidf.rs | 8 + library/compiler-builtins/tests/floatsidf.rs | 8 + library/compiler-builtins/tests/floatsisf.rs | 8 + .../compiler-builtins/tests/floatundidf.rs | 8 + .../compiler-builtins/tests/floatunsidf.rs | 8 + .../compiler-builtins/tests/floatunsisf.rs | 8 + 16 files changed, 1187 insertions(+), 177 deletions(-) create mode 100644 library/compiler-builtins/tests/fixdfdi.rs create mode 100644 library/compiler-builtins/tests/fixdfsi.rs create mode 100644 library/compiler-builtins/tests/fixsfdi.rs create mode 100644 library/compiler-builtins/tests/fixsfsi.rs create mode 100644 library/compiler-builtins/tests/fixunsdfdi.rs create mode 100644 library/compiler-builtins/tests/fixunsdfsi.rs create mode 100644 library/compiler-builtins/tests/fixunssfdi.rs create mode 100644 library/compiler-builtins/tests/fixunssfsi.rs create mode 100644 library/compiler-builtins/tests/floatdidf.rs create mode 100644 library/compiler-builtins/tests/floatsidf.rs create mode 100644 library/compiler-builtins/tests/floatsisf.rs create mode 100644 library/compiler-builtins/tests/floatundidf.rs create mode 100644 library/compiler-builtins/tests/floatunsidf.rs create mode 100644 library/compiler-builtins/tests/floatunsisf.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index bc0d105a7907a..2aefba8bc3f6a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -5,17 +5,13 @@ name = "compiler_builtins" version = "0.1.0" [build-dependencies] +cast = "0.2.0" rand = "0.3.15" [build-dependencies.gcc] optional = true version = "0.3.36" -[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 = { git = "https://github.com/japaric/utest", default-features = false } -utest-macros = { git = "https://github.com/japaric/utest" } - [features] c = ["gcc"] compiler-builtins = [] @@ -23,4 +19,20 @@ default = ["compiler-builtins"] mem = [] rustbuild = ["compiler-builtins"] +[target] + +[target."cfg(all(target_arch = \"arm\", not(any(target_env = \"gnu\", target_env = \"musl\")), target_os = \"linux\"))"] + +[target."cfg(all(target_arch = \"arm\", not(any(target_env = \"gnu\", target_env = \"musl\")), target_os = \"linux\"))".dev-dependencies] + +[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" + +[target."cfg(all(target_arch = \"arm\", not(any(target_env = \"gnu\", target_env = \"musl\")), target_os = \"linux\"))".dev-dependencies.utest-cortex-m-qemu] +default-features = false +git = "https://github.com/japaric/utest" + +[target."cfg(all(target_arch = \"arm\", not(any(target_env = \"gnu\", target_env = \"musl\")), target_os = \"linux\"))".dev-dependencies.utest-macros] +git = "https://github.com/japaric/utest" + [workspace] diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index a3834290aa24f..d27eb7898e0fe 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -37,6 +37,7 @@ fn main() { } mod tests { + extern crate cast; extern crate rand; use std::collections::HashSet; @@ -46,6 +47,7 @@ mod tests { use std::path::PathBuf; use std::{env, mem}; + use self::cast::{f32, f64, u32, u64, i32, i64}; use self::rand::Rng; const NTESTS: usize = 10_000; @@ -66,20 +68,20 @@ mod tests { Addsf3, // float/conv.rs - // Fixdfdi, - // Fixdfsi, - // Fixsfdi, - // Fixsfsi, - // Fixunsdfdi, - // Fixunsdfsi, - // Fixunssfdi, - // Fixunssfsi, - // Floatdidf, - // Floatsidf, - // Floatsisf, - // Floatundidf, - // Floatunsidf, - // Floatunsisf, + Fixdfdi, + Fixdfsi, + Fixsfdi, + Fixsfsi, + Fixunsdfdi, + Fixunsdfsi, + Fixunssfdi, + Fixunssfsi, + Floatdidf, + Floatsidf, + Floatsisf, + Floatundidf, + Floatunsidf, + Floatunsisf, // float/pow.rs Powidf2, @@ -129,9 +131,9 @@ mod tests { #[derive(Eq, Hash, PartialEq)] pub struct Adddf3 { - a: u64, - b: u64, - c: u64, + a: u64, // f64 + b: u64, // f64 + c: u64, // f64 } impl TestCase for Adddf3 { @@ -216,9 +218,9 @@ fn adddf3() { #[derive(Eq, Hash, PartialEq)] pub struct Addsf3 { - a: u32, - b: u32, - c: u32, + a: u32, // f32 + b: u32, // f32 + c: u32, // f32 } impl TestCase for Addsf3 { @@ -563,23 +565,892 @@ fn ashrti3() { } fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {rem})),", - a = self.a, - b = self.b, - c = self.c, - rem = self.rem - ) - .unwrap(); + writeln!( + buffer, + "(({a}, {b}), ({c}, {rem})),", + a = self.a, + b = self.b, + c = self.c, + rem = self.rem + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__divmoddi4; + +static TEST_CASES: &[((i64, i64), (i64, i64))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divmoddi4() { + for &((a, b), (c, rem)) in TEST_CASES { + let mut rem_ = 0; + let c_ = __divmoddi4(a, b, &mut rem_); + assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Divdi3 { + a: i64, + b: i64, + c: i64, + } + + impl TestCase for Divdi3 { + fn name() -> &'static str { + "divdi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i64(rng); + let b = gen_i64(rng); + if b == 0 { + return None; + } + let c = a / b; + + Some(Divdi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__divdi3; + +static TEST_CASES: &[((i64, i64), i64)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divdi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __divdi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Divmodsi4 { + a: i32, + b: i32, + c: i32, + rem: i32, + } + + impl TestCase for Divmodsi4 { + fn name() -> &'static str { + "divmodsi4" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i32(rng); + let b = gen_i32(rng); + if b == 0 { + return None; + } + let c = a / b; + let rem = a % b; + + Some(Divmodsi4 { a, b, c, rem }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {rem})),", + a = self.a, + b = self.b, + c = self.c, + rem = self.rem + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__divmodsi4; + +static TEST_CASES: &[((i32, i32), (i32, i32))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divmodsi4() { + for &((a, b), (c, rem)) in TEST_CASES { + let mut rem_ = 0; + let c_ = __divmodsi4(a, b, &mut rem_); + assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Divsi3 { + a: i32, + b: i32, + c: i32, + } + + impl TestCase for Divsi3 { + fn name() -> &'static str { + "divsi3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i32(rng); + let b = gen_i32(rng); + if b == 0 { + return None; + } + let c = a / b; + + Some(Divsi3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__divsi3; + +static TEST_CASES: &[((i32, i32), i32)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divsi3() { + for &((a, b), c) in TEST_CASES { + let c_ = __divsi3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Divti3 { + a: i128, + b: i128, + c: i128, + } + + impl TestCase for Divti3 { + fn name() -> &'static str { + "divti3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i128(rng); + let b = gen_i128(rng); + if b == 0 { + return None; + } + let c = a / b; + + Some(Divti3 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sdiv::__divti3; + +static TEST_CASES: &[((i128, i128), i128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divti3() { + for &((a, b), c) in TEST_CASES { + let c_ = __divti3(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Fixdfdi { + a: u64, // f64 + b: i64, + } + + impl TestCase for Fixdfdi { + fn name() -> &'static str { + "fixdfdi" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f64(rng); + i64(a).ok().map(|b| Fixdfdi { a: to_u64(a), b }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__fixdfdi; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64,), i64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn fixdfdi() { + for &((a,), b) in TEST_CASES { + let b_ = __fixdfdi(mk_f64(a)); + assert_eq!(((a,), b), ((a,), b_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Fixdfsi { + a: u64, // f64 + b: i32, + } + + impl TestCase for Fixdfsi { + fn name() -> &'static str { + "fixdfsi" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f64(rng); + i32(a).ok().map(|b| Fixdfsi { a: to_u64(a), b }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__fixdfsi; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64,), i32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn fixdfdi() { + for &((a,), b) in TEST_CASES { + let b_ = __fixdfsi(mk_f64(a)); + assert_eq!(((a,), b), ((a,), b_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Fixsfdi { + a: u32, // f32 + b: i64, + } + + impl TestCase for Fixsfdi { + fn name() -> &'static str { + "fixsfdi" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f32(rng); + i64(a).ok().map(|b| Fixsfdi { a: to_u32(a), b }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__fixsfdi; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32,), i64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn fixsfdi() { + for &((a,), b) in TEST_CASES { + let b_ = __fixsfdi(mk_f32(a)); + assert_eq!(((a,), b), ((a,), b_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Fixsfsi { + a: u32, // f32 + b: i32, + } + + impl TestCase for Fixsfsi { + fn name() -> &'static str { + "fixsfsi" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f32(rng); + i32(a).ok().map(|b| Fixsfsi { a: to_u32(a), b }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__fixsfsi; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32,), i32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn fixsfdi() { + for &((a,), b) in TEST_CASES { + let b_ = __fixsfsi(mk_f32(a)); + assert_eq!(((a,), b), ((a,), b_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Fixunsdfdi { + a: u64, // f64 + b: u64, + } + + impl TestCase for Fixunsdfdi { + fn name() -> &'static str { + "fixunsdfdi" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f64(rng); + u64(a).ok().map(|b| Fixunsdfdi { a: to_u64(a), b }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__fixunsdfdi; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64,), u64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn fixunsdfdi() { + for &((a,), b) in TEST_CASES { + let b_ = __fixunsdfdi(mk_f64(a)); + assert_eq!(((a,), b), ((a,), b_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Fixunsdfsi { + a: u64, // f64 + b: u32, + } + + impl TestCase for Fixunsdfsi { + fn name() -> &'static str { + "fixunsdfsi" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f64(rng); + u32(a).ok().map(|b| Fixunsdfsi { a: to_u64(a), b }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__fixunsdfsi; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64,), u32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn fixunsdfdi() { + for &((a,), b) in TEST_CASES { + let b_ = __fixunsdfsi(mk_f64(a)); + assert_eq!(((a,), b), ((a,), b_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Fixunssfdi { + a: u32, // f32 + b: u64, + } + + impl TestCase for Fixunssfdi { + fn name() -> &'static str { + "fixunssfdi" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f32(rng); + u64(a).ok().map(|b| Fixunssfdi { a: to_u32(a), b }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__fixunssfdi; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32,), u64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn fixunssfdi() { + for &((a,), b) in TEST_CASES { + let b_ = __fixunssfdi(mk_f32(a)); + assert_eq!(((a,), b), ((a,), b_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Fixunssfsi { + a: u32, // f32 + b: u32, + } + + impl TestCase for Fixunssfsi { + fn name() -> &'static str { + "fixunssfsi" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f32(rng); + u32(a).ok().map(|b| Fixunssfsi { a: to_u32(a), b }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__fixunssfsi; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32,), u32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn fixunssfsi() { + for &((a,), b) in TEST_CASES { + let b_ = __fixunssfsi(mk_f32(a)); + assert_eq!(((a,), b), ((a,), b_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Floatdidf { + a: i64, + b: u64, // f64 + } + + impl TestCase for Floatdidf { + fn name() -> &'static str { + "floatdidf" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i64(rng); + Some( + Floatdidf { + a, + b: to_u64(f64(a)), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__floatdidf; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((i64,), u64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn floatdidf() { + for &((a,), b) in TEST_CASES { + let b_ = __floatdidf(a); + assert_eq!(((a,), mk_f64(b)), ((a,), b_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Floatsidf { + a: i32, + b: u64, // f64 + } + + impl TestCase for Floatsidf { + fn name() -> &'static str { + "floatsidf" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i32(rng); + Some( + Floatsidf { + a, + b: to_u64(f64(a)), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); } fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__divmoddi4; + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__floatsidf; -static TEST_CASES: &[((i64, i64), (i64, i64))] = &[ -" +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((i32,), u64)] = &[ +"# } fn epilogue() -> &'static str { @@ -587,11 +1458,10 @@ static TEST_CASES: &[((i64, i64), (i64, i64))] = &[ ]; #[test] -fn divmoddi4() { - for &((a, b), (c, rem)) in TEST_CASES { - let mut rem_ = 0; - let c_ = __divmoddi4(a, b, &mut rem_); - assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); +fn floatsidf() { + for &((a,), b) in TEST_CASES { + let b_ = __floatsidf(a); + assert_eq!(((a,), mk_f64(b)), ((a,), b_)); } } " @@ -599,15 +1469,14 @@ fn divmoddi4() { } #[derive(Eq, Hash, PartialEq)] - pub struct Divdi3 { - a: i64, - b: i64, - c: i64, + pub struct Floatsisf { + a: i32, + b: u32, // f32 } - impl TestCase for Divdi3 { + impl TestCase for Floatsisf { fn name() -> &'static str { - "divdi3" + "floatsisf" } fn generate(rng: &mut R) -> Option @@ -615,33 +1484,39 @@ fn divmoddi4() { R: Rng, Self: Sized, { - let a = gen_i64(rng); - let b = gen_i64(rng); - if b == 0 { - return None; - } - let c = a / b; - - Some(Divdi3 { a, b, c }) + let a = gen_i32(rng); + Some( + Floatsisf { + a, + b: to_u32(f32(a)), + }, + ) } fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); } fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__divdi3; + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__floatsisf; -static TEST_CASES: &[((i64, i64), i64)] = &[ -" +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((i32,), u32)] = &[ +"# } fn epilogue() -> &'static str { @@ -649,10 +1524,10 @@ static TEST_CASES: &[((i64, i64), i64)] = &[ ]; #[test] -fn divdi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __divdi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); +fn floatsisf() { + for &((a,), b) in TEST_CASES { + let b_ = __floatsisf(a); + assert_eq!(((a,), mk_f32(b)), ((a,), b_)); } } " @@ -660,16 +1535,14 @@ fn divdi3() { } #[derive(Eq, Hash, PartialEq)] - pub struct Divmodsi4 { - a: i32, - b: i32, - c: i32, - rem: i32, + pub struct Floatundidf { + a: u64, + b: u64, // f64 } - impl TestCase for Divmodsi4 { + impl TestCase for Floatundidf { fn name() -> &'static str { - "divmodsi4" + "floatundidf" } fn generate(rng: &mut R) -> Option @@ -677,35 +1550,39 @@ fn divdi3() { R: Rng, Self: Sized, { - let a = gen_i32(rng); - let b = gen_i32(rng); - if b == 0 { - return None; - } - let c = a / b; - let rem = a % b; - - Some(Divmodsi4 { a, b, c, rem }) + let a = gen_u64(rng); + Some( + Floatundidf { + a, + b: to_u64(f64(a)), + }, + ) } fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {rem})),", - a = self.a, - b = self.b, - c = self.c, - rem = self.rem - ) - .unwrap(); + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); } fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__divmodsi4; + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__floatundidf; -static TEST_CASES: &[((i32, i32), (i32, i32))] = &[ -" +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64,), u64)] = &[ +"# } fn epilogue() -> &'static str { @@ -713,11 +1590,10 @@ static TEST_CASES: &[((i32, i32), (i32, i32))] = &[ ]; #[test] -fn divmodsi4() { - for &((a, b), (c, rem)) in TEST_CASES { - let mut rem_ = 0; - let c_ = __divmodsi4(a, b, &mut rem_); - assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); +fn floatundidf() { + for &((a,), b) in TEST_CASES { + let b_ = __floatundidf(a); + assert_eq!(((a,), mk_f64(b)), ((a,), b_)); } } " @@ -725,15 +1601,14 @@ fn divmodsi4() { } #[derive(Eq, Hash, PartialEq)] - pub struct Divsi3 { - a: i32, - b: i32, - c: i32, + pub struct Floatunsidf { + a: u32, + b: u64, // f64 } - impl TestCase for Divsi3 { + impl TestCase for Floatunsidf { fn name() -> &'static str { - "divsi3" + "floatunsidf" } fn generate(rng: &mut R) -> Option @@ -741,33 +1616,39 @@ fn divmodsi4() { R: Rng, Self: Sized, { - let a = gen_i32(rng); - let b = gen_i32(rng); - if b == 0 { - return None; - } - let c = a / b; - - Some(Divsi3 { a, b, c }) + let a = gen_u32(rng); + Some( + Floatunsidf { + a, + b: to_u64(f64(a)), + }, + ) } fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); } fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__divsi3; + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__floatunsidf; -static TEST_CASES: &[((i32, i32), i32)] = &[ -" +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32,), u64)] = &[ +"# } fn epilogue() -> &'static str { @@ -775,10 +1656,10 @@ static TEST_CASES: &[((i32, i32), i32)] = &[ ]; #[test] -fn divsi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __divsi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); +fn floatunsidf() { + for &((a,), b) in TEST_CASES { + let b_ = __floatunsidf(a); + assert_eq!(((a,), mk_f64(b)), ((a,), b_)); } } " @@ -786,15 +1667,14 @@ fn divsi3() { } #[derive(Eq, Hash, PartialEq)] - pub struct Divti3 { - a: i128, - b: i128, - c: i128, + pub struct Floatunsisf { + a: u32, + b: u32, // f32 } - impl TestCase for Divti3 { + impl TestCase for Floatunsisf { fn name() -> &'static str { - "divti3" + "floatunsisf" } fn generate(rng: &mut R) -> Option @@ -802,33 +1682,39 @@ fn divsi3() { R: Rng, Self: Sized, { - let a = gen_i128(rng); - let b = gen_i128(rng); - if b == 0 { - return None; - } - let c = a / b; - - Some(Divti3 { a, b, c }) + let a = gen_u32(rng); + Some( + Floatunsisf { + a, + b: to_u32(f32(a)), + }, + ) } fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); } fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__divti3; + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__floatunsisf; -static TEST_CASES: &[((i128, i128), i128)] = &[ -" +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32,), u32)] = &[ +"# } fn epilogue() -> &'static str { @@ -836,10 +1722,10 @@ static TEST_CASES: &[((i128, i128), i128)] = &[ ]; #[test] -fn divti3() { - for &((a, b), c) in TEST_CASES { - let c_ = __divti3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); +fn floatunsisf() { + for &((a,), b) in TEST_CASES { + let b_ = __floatunsisf(a); + assert_eq!(((a,), mk_f32(b)), ((a,), b_)); } } " @@ -1330,9 +2216,9 @@ fn multi3() { #[derive(Eq, Hash, PartialEq)] pub struct Powidf2 { - a: u64, + a: u64, // f64 b: i32, - c: u64, + c: u64, // f64 } impl TestCase for Powidf2 { @@ -1417,9 +2303,9 @@ fn powidf2() { #[derive(Eq, Hash, PartialEq)] pub struct Powisf2 { - a: u32, + a: u32, // f32 b: i32, - c: u32, + c: u32, // f32 } impl TestCase for Powisf2 { @@ -1620,9 +2506,9 @@ fn lshrti3() { #[derive(Eq, Hash, PartialEq)] pub struct Subdf3 { - a: u64, - b: u64, - c: u64, + a: u64, // f64 + b: u64, // f64 + c: u64, // f64 } impl TestCase for Subdf3 { @@ -1707,9 +2593,9 @@ fn subdf3() { #[derive(Eq, Hash, PartialEq)] pub struct Subsf3 { - a: u32, - b: u32, - c: u32, + a: u32, // f32 + b: u32, // f32 + c: u32, // f32 } impl TestCase for Subsf3 { diff --git a/library/compiler-builtins/tests/fixdfdi.rs b/library/compiler-builtins/tests/fixdfdi.rs new file mode 100644 index 0000000000000..b66477502bbe9 --- /dev/null +++ b/library/compiler-builtins/tests/fixdfdi.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/fixdfdi.rs")); diff --git a/library/compiler-builtins/tests/fixdfsi.rs b/library/compiler-builtins/tests/fixdfsi.rs new file mode 100644 index 0000000000000..2677eec747af8 --- /dev/null +++ b/library/compiler-builtins/tests/fixdfsi.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/fixdfsi.rs")); diff --git a/library/compiler-builtins/tests/fixsfdi.rs b/library/compiler-builtins/tests/fixsfdi.rs new file mode 100644 index 0000000000000..e38952be59324 --- /dev/null +++ b/library/compiler-builtins/tests/fixsfdi.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/fixsfdi.rs")); diff --git a/library/compiler-builtins/tests/fixsfsi.rs b/library/compiler-builtins/tests/fixsfsi.rs new file mode 100644 index 0000000000000..242b4c16940ce --- /dev/null +++ b/library/compiler-builtins/tests/fixsfsi.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/fixsfsi.rs")); diff --git a/library/compiler-builtins/tests/fixunsdfdi.rs b/library/compiler-builtins/tests/fixunsdfdi.rs new file mode 100644 index 0000000000000..13b35ba4a179a --- /dev/null +++ b/library/compiler-builtins/tests/fixunsdfdi.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/fixunsdfdi.rs")); diff --git a/library/compiler-builtins/tests/fixunsdfsi.rs b/library/compiler-builtins/tests/fixunsdfsi.rs new file mode 100644 index 0000000000000..32faf360c30ff --- /dev/null +++ b/library/compiler-builtins/tests/fixunsdfsi.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/fixunsdfsi.rs")); diff --git a/library/compiler-builtins/tests/fixunssfdi.rs b/library/compiler-builtins/tests/fixunssfdi.rs new file mode 100644 index 0000000000000..24e6f6e350894 --- /dev/null +++ b/library/compiler-builtins/tests/fixunssfdi.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/fixunssfdi.rs")); diff --git a/library/compiler-builtins/tests/fixunssfsi.rs b/library/compiler-builtins/tests/fixunssfsi.rs new file mode 100644 index 0000000000000..da02cd94578ef --- /dev/null +++ b/library/compiler-builtins/tests/fixunssfsi.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/fixunssfsi.rs")); diff --git a/library/compiler-builtins/tests/floatdidf.rs b/library/compiler-builtins/tests/floatdidf.rs new file mode 100644 index 0000000000000..2b3dcb5928cf2 --- /dev/null +++ b/library/compiler-builtins/tests/floatdidf.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/floatdidf.rs")); diff --git a/library/compiler-builtins/tests/floatsidf.rs b/library/compiler-builtins/tests/floatsidf.rs new file mode 100644 index 0000000000000..ffee7e271131f --- /dev/null +++ b/library/compiler-builtins/tests/floatsidf.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/floatsidf.rs")); diff --git a/library/compiler-builtins/tests/floatsisf.rs b/library/compiler-builtins/tests/floatsisf.rs new file mode 100644 index 0000000000000..c03ab7f9dd59d --- /dev/null +++ b/library/compiler-builtins/tests/floatsisf.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/floatsisf.rs")); diff --git a/library/compiler-builtins/tests/floatundidf.rs b/library/compiler-builtins/tests/floatundidf.rs new file mode 100644 index 0000000000000..0b8338512452f --- /dev/null +++ b/library/compiler-builtins/tests/floatundidf.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/floatundidf.rs")); diff --git a/library/compiler-builtins/tests/floatunsidf.rs b/library/compiler-builtins/tests/floatunsidf.rs new file mode 100644 index 0000000000000..e25a69f5beaf9 --- /dev/null +++ b/library/compiler-builtins/tests/floatunsidf.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/floatunsidf.rs")); diff --git a/library/compiler-builtins/tests/floatunsisf.rs b/library/compiler-builtins/tests/floatunsisf.rs new file mode 100644 index 0000000000000..c0b9fd8b0b97f --- /dev/null +++ b/library/compiler-builtins/tests/floatunsisf.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/floatunsisf.rs")); From 0869e5b93a9f73167bcb85cf866149da2afac09a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 16:35:08 -0500 Subject: [PATCH 0275/4206] remove arm tests from the old test suite --- library/compiler-builtins/src/arm.rs | 81 ---------------------------- 1 file changed, 81 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 63f52500d4bcc..cf960c5aa1ab9 100755 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -180,84 +180,3 @@ pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { memset(dest, 0, n); } - - -#[cfg(test)] -mod tests { - use quickcheck::TestResult; - use qc::{U32, U64}; - - quickcheck!{ - fn uldivmod(n: U64, d: U64) -> TestResult { - let (n, d) = (n.0, d.0); - if d == 0 { - TestResult::discard() - } else { - let q: u64; - let r: u64; - unsafe { - // The inline asm is a bit tricky here, LLVM will allocate - // both r0 and r1 when we specify a 64-bit value for {r0}. - asm!("bl __aeabi_uldivmod" - : "={r0}" (q), "={r2}" (r) - : "{r0}" (n), "{r2}" (d) - : "r12", "lr", "flags"); - } - TestResult::from_bool(q == n / d && r == n % d) - } - } - - fn uidivmod(n: U32, d: U32) -> TestResult { - let (n, d) = (n.0, d.0); - if d == 0 { - TestResult::discard() - } else { - let q: u32; - let r: u32; - unsafe { - asm!("bl __aeabi_uidivmod" - : "={r0}" (q), "={r1}" (r) - : "{r0}" (n), "{r1}" (d) - : "r2", "r3", "r12", "lr", "flags"); - } - TestResult::from_bool(q == n / d && r == n % d) - } - } - - fn ldivmod(n: U64, d: U64) -> TestResult { - let (n, d) = (n.0 as i64, d.0 as i64); - if d == 0 { - TestResult::discard() - } else { - let q: i64; - let r: i64; - unsafe { - // The inline asm is a bit tricky here, LLVM will allocate - // both r0 and r1 when we specify a 64-bit value for {r0}. - asm!("bl __aeabi_ldivmod" - : "={r0}" (q), "={r2}" (r) - : "{r0}" (n), "{r2}" (d) - : "r12", "lr", "flags"); - } - TestResult::from_bool(q == n / d && r == n % d) - } - } - - fn idivmod(n: U32, d: U32) -> TestResult { - let (n, d) = (n.0 as i32, d.0 as i32); - if d == 0 || (n == i32::min_value() && d == -1) { - TestResult::discard() - } else { - let q: i32; - let r: i32; - unsafe { - asm!("bl __aeabi_idivmod" - : "={r0}" (q), "={r1}" (r) - : "{r0}" (n), "{r1}" (d) - : "r2", "r3", "r12", "lr", "flags"); - } - TestResult::from_bool(q == n / d && r == n % d) - } - } - } -} From 74eedd0f17d4e8383fe987d3f599987e31872711 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 17:13:07 -0500 Subject: [PATCH 0276/4206] make float* intrinsics testable on thumb there are no intrinsics for float equality atm, so transmute to an integer before comparing --- library/compiler-builtins/build.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index d27eb7898e0fe..2c8cff7295c78 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1379,7 +1379,7 @@ use core::mem; use std::mem; use compiler_builtins::float::conv::__floatdidf; -fn mk_f64(x: u64) -> f64 { +fn to_u64(x: f64) -> u64 { unsafe { mem::transmute(x) } } @@ -1395,7 +1395,7 @@ static TEST_CASES: &[((i64,), u64)] = &[ fn floatdidf() { for &((a,), b) in TEST_CASES { let b_ = __floatdidf(a); - assert_eq!(((a,), mk_f64(b)), ((a,), b_)); + assert_eq!(((a,), b), ((a,), to_u64(b_))); } } " @@ -1445,7 +1445,7 @@ use core::mem; use std::mem; use compiler_builtins::float::conv::__floatsidf; -fn mk_f64(x: u64) -> f64 { +fn to_u64(x: f64) -> u64 { unsafe { mem::transmute(x) } } @@ -1461,7 +1461,7 @@ static TEST_CASES: &[((i32,), u64)] = &[ fn floatsidf() { for &((a,), b) in TEST_CASES { let b_ = __floatsidf(a); - assert_eq!(((a,), mk_f64(b)), ((a,), b_)); + assert_eq!(((a,), b), ((a,), to_u64(b_))); } } " @@ -1511,7 +1511,7 @@ use core::mem; use std::mem; use compiler_builtins::float::conv::__floatsisf; -fn mk_f32(x: u32) -> f32 { +fn to_u32(x: f32) -> u32 { unsafe { mem::transmute(x) } } @@ -1527,7 +1527,7 @@ static TEST_CASES: &[((i32,), u32)] = &[ fn floatsisf() { for &((a,), b) in TEST_CASES { let b_ = __floatsisf(a); - assert_eq!(((a,), mk_f32(b)), ((a,), b_)); + assert_eq!(((a,), b), ((a,), to_u32(b_))); } } " @@ -1577,7 +1577,7 @@ use core::mem; use std::mem; use compiler_builtins::float::conv::__floatundidf; -fn mk_f64(x: u64) -> f64 { +fn to_u64(x: f64) -> u64 { unsafe { mem::transmute(x) } } @@ -1593,7 +1593,7 @@ static TEST_CASES: &[((u64,), u64)] = &[ fn floatundidf() { for &((a,), b) in TEST_CASES { let b_ = __floatundidf(a); - assert_eq!(((a,), mk_f64(b)), ((a,), b_)); + assert_eq!(((a,), b), ((a,), to_u64(b_))); } } " @@ -1643,7 +1643,7 @@ use core::mem; use std::mem; use compiler_builtins::float::conv::__floatunsidf; -fn mk_f64(x: u64) -> f64 { +fn to_u64(x: f64) -> u64 { unsafe { mem::transmute(x) } } @@ -1659,7 +1659,7 @@ static TEST_CASES: &[((u32,), u64)] = &[ fn floatunsidf() { for &((a,), b) in TEST_CASES { let b_ = __floatunsidf(a); - assert_eq!(((a,), mk_f64(b)), ((a,), b_)); + assert_eq!(((a,), b), ((a,), to_u64(b_))); } } " @@ -1709,7 +1709,7 @@ use core::mem; use std::mem; use compiler_builtins::float::conv::__floatunsisf; -fn mk_f32(x: u32) -> f32 { +fn to_u32(x: f32) -> u32 { unsafe { mem::transmute(x) } } @@ -1725,7 +1725,7 @@ static TEST_CASES: &[((u32,), u32)] = &[ fn floatunsisf() { for &((a,), b) in TEST_CASES { let b_ = __floatunsisf(a); - assert_eq!(((a,), mk_f32(b)), ((a,), b_)); + assert_eq!(((a,), b), ((a,), to_u32(b_))); } } " From d8576a4f8b71882257f81a15c270a86eb98635b1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 17:16:13 -0500 Subject: [PATCH 0277/4206] modify the CI setup to run tests on the thumb targets --- .../Dockerfile | 8 ++--- .../Dockerfile | 8 ++--- .../Dockerfile | 8 ++--- .../Dockerfile | 8 ++--- library/compiler-builtins/ci/run.sh | 30 +++++++++++++++++-- 5 files changed, 44 insertions(+), 18 deletions(-) rename library/compiler-builtins/ci/docker/{thumbv6m-none-eabi => thumbv6m-linux-eabi}/Dockerfile (59%) rename library/compiler-builtins/ci/docker/{thumbv7em-none-eabihf => thumbv7em-linux-eabi}/Dockerfile (59%) rename library/compiler-builtins/ci/docker/{thumbv7m-none-eabi => thumbv7em-linux-eabihf}/Dockerfile (58%) rename library/compiler-builtins/ci/docker/{thumbv7em-none-eabi => thumbv7m-linux-eabi}/Dockerfile (59%) diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile similarity index 59% rename from library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile rename to library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile index 2a2d127e1d23b..d26035618e6ec 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile @@ -1,9 +1,9 @@ FROM ubuntu:16.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ - ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev + ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin -ENV AR_thumbv6m_none_eabi=arm-none-eabi-ar \ - CARGO_TARGET_THUMBV6M_NONE_EABI_LINKER=arm-none-eabi-gcc \ - CC_thumbv6m_none_eabi=arm-none-eabi-gcc \ +ENV AR_thumbv6m_linux_eabi=arm-none-eabi-ar \ + CARGO_TARGET_THUMBV6M_LINUX_EABI_LINKER=arm-none-eabi-gcc \ + CC_thumbv6m_linux_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile similarity index 59% rename from library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile rename to library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile index 5395e7449a9cf..d630352a721f1 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile @@ -1,9 +1,9 @@ FROM ubuntu:16.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ - ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev + ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin -ENV AR_thumbv7em_none_eabihf=arm-none-eabi-ar \ - CARGO_TARGET_THUMBV7EM_NONE_EABIHF_LINKER=arm-none-eabi-gcc \ - CC_thumbv7em_none_eabihf=arm-none-eabi-gcc \ +ENV AR_thumbv7em_linux_eabi=arm-none-eabi-ar \ + CARGO_TARGET_THUMBV7EM_LINUX_EABI_LINKER=arm-none-eabi-gcc \ + CC_thumbv7em_linux_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile similarity index 58% rename from library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile rename to library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile index e09c020a223cf..6f30729fa9e42 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile @@ -1,9 +1,9 @@ FROM ubuntu:16.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ - ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev + ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin -ENV AR_thumbv7m_none_eabi=arm-none-eabi-ar \ - CARGO_TARGET_THUMBV7M_NONE_EABI_LINKER=arm-none-eabi-gcc \ - CC_thumbv7m_none_eabi=arm-none-eabi-gcc \ +ENV AR_thumbv7em_linux_eabihf=arm-none-eabi-ar \ + CARGO_TARGET_THUMBV7EM_LINUX_EABIHF_LINKER=arm-none-eabi-gcc \ + CC_thumbv7em_linux_eabihf=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile similarity index 59% rename from library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile rename to library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile index fda5dcbe6f840..a7dbad6472453 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile @@ -1,9 +1,9 @@ FROM ubuntu:16.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ - ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev + ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin -ENV AR_thumbv7em_none_eabi=arm-none-eabi-ar \ - CARGO_TARGET_THUMBV7EM_NONE_EABI_LINKER=arm-none-eabi-gcc \ - CC_thumbv7em_none_eabi=arm-none-eabi-gcc \ +ENV AR_thumbv7m_linux_eabi=arm-none-eabi-ar \ + CARGO_TARGET_THUMBV7M_LINUX_EABI_LINKER=arm-none-eabi-gcc \ + CC_thumbv7m_linux_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index b30fad10fc868..17c54ef04279e 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -3,8 +3,34 @@ set -ex # Test our implementation case $1 in thumb*) - xargo build --target $1 - xargo build --target $1 --release + for t in $(ls tests); do + t=${t%.rs} + + # TODO(#154) enable these tests when aeabi_*mul are implemented + case $t in + powi*f2) + continue + ;; + esac + + # FIXME(#150) debug assertion in divmoddi4 + case $1 in + thumbv6m-*) + case $t in + divdi3 | divmoddi4 | moddi3 | modsi3 | udivmoddi4 | udivmodsi4 | umoddi3 | \ + umodsi3) + continue + ;; + esac + ;; + esac + + xargo test --test $t --target $1 --features mem --no-run + qemu-arm-static target/${1}/debug/$t-* + + xargo test --test $t --target $1 --features mem --no-run --release + qemu-arm-static target/${1}/release/$t-* + done ;; *) cargo test --no-default-features --target $1 From 9c0fe5be3daf5102ad857ff81df5e660ae6666bb Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 17:27:25 -0500 Subject: [PATCH 0278/4206] put test generation behind a Cargo feature to reduce build time for the most common case of not running tests --- library/compiler-builtins/Cargo.toml | 23 ++++++++--------------- library/compiler-builtins/build.rs | 2 ++ library/compiler-builtins/ci/run.sh | 8 ++++---- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 2aefba8bc3f6a..59f6b404abdd0 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -5,8 +5,8 @@ name = "compiler_builtins" version = "0.1.0" [build-dependencies] -cast = "0.2.0" -rand = "0.3.15" +cast = { version = "0.2.0", optional = true } +rand = { version = "0.3.15", optional = true } [build-dependencies.gcc] optional = true @@ -18,21 +18,14 @@ compiler-builtins = [] default = ["compiler-builtins"] mem = [] rustbuild = ["compiler-builtins"] +# generate tests +gen-tests = ["cast", "rand"] -[target] +[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" } -[target."cfg(all(target_arch = \"arm\", not(any(target_env = \"gnu\", target_env = \"musl\")), target_os = \"linux\"))"] -[target."cfg(all(target_arch = \"arm\", not(any(target_env = \"gnu\", target_env = \"musl\")), target_os = \"linux\"))".dev-dependencies] - -[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" - -[target."cfg(all(target_arch = \"arm\", not(any(target_env = \"gnu\", target_env = \"musl\")), target_os = \"linux\"))".dev-dependencies.utest-cortex-m-qemu] -default-features = false -git = "https://github.com/japaric/utest" - -[target."cfg(all(target_arch = \"arm\", not(any(target_env = \"gnu\", target_env = \"musl\")), target_os = \"linux\"))".dev-dependencies.utest-macros] -git = "https://github.com/japaric/utest" [workspace] diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 2c8cff7295c78..ac75e6ede881a 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -18,6 +18,7 @@ fn main() { let llvm_target = target.split('-').collect::>(); // Build test files + #[cfg(feature = "gen-tests")] tests::generate(); // Build missing intrinsics from compiler-rt C source code @@ -36,6 +37,7 @@ fn main() { } } +#[cfg(feature = "gen-tests")] mod tests { extern crate cast; extern crate rand; diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 17c54ef04279e..771f8812a029a 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -25,16 +25,16 @@ case $1 in ;; esac - xargo test --test $t --target $1 --features mem --no-run + xargo test --test $t --target $1 --features 'mem gen-tests' --no-run qemu-arm-static target/${1}/debug/$t-* - xargo test --test $t --target $1 --features mem --no-run --release + xargo test --test $t --target $1 --features 'mem gen-tests' --no-run --release qemu-arm-static target/${1}/release/$t-* done ;; *) - cargo test --no-default-features --target $1 - cargo test --no-default-features --target $1 --release + cargo test --no-default-features --features gen-tests --target $1 + cargo test --no-default-features --features gen-tests --target $1 --release ;; esac From 750b26267f9c66c41c3f51c6859402e7cf496bed Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 17:46:33 -0500 Subject: [PATCH 0279/4206] appveyor: cargo test requires the gen-tests feature --- library/compiler-builtins/appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index c05bfdfc2b604..80d943c4b52ec 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -16,5 +16,5 @@ build: false test_script: - cargo build --target %TARGET% - cargo build --release --target %TARGET% - - cargo test --no-default-features --target %TARGET% - - cargo test --no-default-features --release --target %TARGET% + - cargo test --no-default-features --feature gen-tests --target %TARGET% + - cargo test --no-default-features --feature gen-tests --release --target %TARGET% From a606075c9bdcc61f54c6a82499ee244de82a5487 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 17:59:45 -0500 Subject: [PATCH 0280/4206] .travis.yml: thumbs target have been renamed --- library/compiler-builtins/.travis.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 96bd24ab2f9e8..3c26d624777d3 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -22,10 +22,10 @@ matrix: - env: TARGET=powerpc-unknown-linux-gnu - env: TARGET=powerpc64-unknown-linux-gnu - env: TARGET=powerpc64le-unknown-linux-gnu - - env: TARGET=thumbv6m-none-eabi - - env: TARGET=thumbv7em-none-eabi - - env: TARGET=thumbv7em-none-eabihf - - env: TARGET=thumbv7m-none-eabi + - env: TARGET=thumbv6m-linux-eabi + - env: TARGET=thumbv7em-linux-eabi + - env: TARGET=thumbv7em-linux-eabihf + - env: TARGET=thumbv7m-linux-eabi - env: TARGET=x86_64-apple-darwin os: osx env: TARGET=x86_64-unknown-linux-gnu @@ -38,7 +38,7 @@ install: - source ~/.cargo/env - case $TARGET in x86_64-apple-darwin | x86_64-unknown-linux-gnu) ;; - thumbv*-none-eabi*) rustup component add rust-src ;; + thumbv*eabi*) rustup component add rust-src ;; *) rustup target add $TARGET;; esac From 09f95517b19245357a41edc13998581839bf06d7 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 18:00:16 -0500 Subject: [PATCH 0281/4206] travis: don't reinstall rustup travis now installs rust using rustup --- library/compiler-builtins/.travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 3c26d624777d3..108b12a014f68 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -34,8 +34,6 @@ before_install: - test "$TRAVIS_OS_NAME" = "osx" || docker run --rm --privileged multiarch/qemu-user-static:register install: - - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $TRAVIS_RUST_VERSION - - source ~/.cargo/env - case $TARGET in x86_64-apple-darwin | x86_64-unknown-linux-gnu) ;; thumbv*eabi*) rustup component add rust-src ;; From f80b2c4af2a0c429525f7b739c808fa1f8a69878 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 20:10:45 -0500 Subject: [PATCH 0282/4206] s/feature/features/g --- library/compiler-builtins/appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 80d943c4b52ec..61e5d6ce76f1d 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -16,5 +16,5 @@ build: false test_script: - cargo build --target %TARGET% - cargo build --release --target %TARGET% - - cargo test --no-default-features --feature gen-tests --target %TARGET% - - cargo test --no-default-features --feature gen-tests --release --target %TARGET% + - cargo test --no-default-features --features gen-tests --target %TARGET% + - cargo test --no-default-features --features gen-tests --release --target %TARGET% From 2f64ef08701e94aeff9b9407dca4ed1ecb23f482 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 11 Apr 2017 11:24:33 -0500 Subject: [PATCH 0283/4206] ignore i128 div / mul tests on MIPS there's an unfixed bug. See #137 --- library/compiler-builtins/tests/divti3.rs | 2 ++ library/compiler-builtins/tests/modti3.rs | 2 ++ library/compiler-builtins/tests/muloti4.rs | 2 ++ library/compiler-builtins/tests/udivmodti4.rs | 2 ++ library/compiler-builtins/tests/udivti3.rs | 2 ++ library/compiler-builtins/tests/umodti3.rs | 2 ++ 6 files changed, 12 insertions(+) diff --git a/library/compiler-builtins/tests/divti3.rs b/library/compiler-builtins/tests/divti3.rs index 62d9789d0f87b..7919f8fe396a3 100644 --- a/library/compiler-builtins/tests/divti3.rs +++ b/library/compiler-builtins/tests/divti3.rs @@ -5,4 +5,6 @@ target_os = "linux", test), no_std)] +// FIXME(#137) +#[cfg(not(target_arch = "mips"))] include!(concat!(env!("OUT_DIR"), "/divti3.rs")); diff --git a/library/compiler-builtins/tests/modti3.rs b/library/compiler-builtins/tests/modti3.rs index 1a363f7cb4191..62129cd04d3c3 100644 --- a/library/compiler-builtins/tests/modti3.rs +++ b/library/compiler-builtins/tests/modti3.rs @@ -5,4 +5,6 @@ target_os = "linux", test), no_std)] +// FIXME(#137) +#[cfg(not(target_arch = "mips"))] include!(concat!(env!("OUT_DIR"), "/modti3.rs")); diff --git a/library/compiler-builtins/tests/muloti4.rs b/library/compiler-builtins/tests/muloti4.rs index 262b46465920b..358c57ec528a8 100644 --- a/library/compiler-builtins/tests/muloti4.rs +++ b/library/compiler-builtins/tests/muloti4.rs @@ -5,4 +5,6 @@ target_os = "linux", test), no_std)] +// FIXME(#137) +#[cfg(not(target_arch = "mips"))] include!(concat!(env!("OUT_DIR"), "/muloti4.rs")); diff --git a/library/compiler-builtins/tests/udivmodti4.rs b/library/compiler-builtins/tests/udivmodti4.rs index 1f9ed27992631..8185ec0e78971 100644 --- a/library/compiler-builtins/tests/udivmodti4.rs +++ b/library/compiler-builtins/tests/udivmodti4.rs @@ -5,4 +5,6 @@ target_os = "linux", test), no_std)] +// FIXME(#137) +#[cfg(not(target_arch = "mips"))] include!(concat!(env!("OUT_DIR"), "/udivmodti4.rs")); diff --git a/library/compiler-builtins/tests/udivti3.rs b/library/compiler-builtins/tests/udivti3.rs index fc602fd28af03..cefddda8f8698 100644 --- a/library/compiler-builtins/tests/udivti3.rs +++ b/library/compiler-builtins/tests/udivti3.rs @@ -5,4 +5,6 @@ target_os = "linux", test), no_std)] +// FIXME(#137) +#[cfg(not(target_arch = "mips"))] include!(concat!(env!("OUT_DIR"), "/udivti3.rs")); diff --git a/library/compiler-builtins/tests/umodti3.rs b/library/compiler-builtins/tests/umodti3.rs index 63a0bf28f2f55..57e651b2710f1 100644 --- a/library/compiler-builtins/tests/umodti3.rs +++ b/library/compiler-builtins/tests/umodti3.rs @@ -5,4 +5,6 @@ target_os = "linux", test), no_std)] +// FIXME(#137) +#[cfg(not(target_arch = "mips"))] include!(concat!(env!("OUT_DIR"), "/umodti3.rs")); From 692906c58a805b234e404840f14ed9d81a215b3e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 11 Apr 2017 11:32:44 -0500 Subject: [PATCH 0284/4206] adapt the thumb target specs to upstream linker-flavor changes --- library/compiler-builtins/.cargo/config | 11 ----------- library/compiler-builtins/thumbv6m-linux-eabi.json | 5 ++++- library/compiler-builtins/thumbv7em-linux-eabi.json | 5 ++++- library/compiler-builtins/thumbv7em-linux-eabihf.json | 5 ++++- library/compiler-builtins/thumbv7m-linux-eabi.json | 5 ++++- 5 files changed, 16 insertions(+), 15 deletions(-) delete mode 100644 library/compiler-builtins/.cargo/config diff --git a/library/compiler-builtins/.cargo/config b/library/compiler-builtins/.cargo/config deleted file mode 100644 index b538953458298..0000000000000 --- a/library/compiler-builtins/.cargo/config +++ /dev/null @@ -1,11 +0,0 @@ -[target.thumbv6m-none-eabi] -rustflags = ["-C", "link-arg=-nostartfiles"] - -[target.thumbv7m-none-eabi] -rustflags = ["-C", "link-arg=-nostartfiles"] - -[target.thumbv7em-none-eabi] -rustflags = ["-C", "link-arg=-nostartfiles"] - -[target.thumbv7em-none-eabihf] -rustflags = ["-C", "link-arg=-nostartfiles"] \ No newline at end of file diff --git a/library/compiler-builtins/thumbv6m-linux-eabi.json b/library/compiler-builtins/thumbv6m-linux-eabi.json index d3ac24dfc5e91..dd0cb61bc09ff 100644 --- a/library/compiler-builtins/thumbv6m-linux-eabi.json +++ b/library/compiler-builtins/thumbv6m-linux-eabi.json @@ -12,11 +12,14 @@ "executables": true, "features": "+strict-align", "linker": "arm-none-eabi-gcc", + "linker-flavor": "gcc", "llvm-target": "thumbv6m-none-eabi", "max-atomic-width": 0, "os": "linux", "panic-strategy": "abort", - "pre-link-args": ["-nostartfiles"], + "pre-link-args": { + "gcc": ["-nostartfiles"] + }, "relocation-model": "static", "target-endian": "little", "target-pointer-width": "32", diff --git a/library/compiler-builtins/thumbv7em-linux-eabi.json b/library/compiler-builtins/thumbv7em-linux-eabi.json index af6ea94eebdd4..eef29f5cc7a5c 100644 --- a/library/compiler-builtins/thumbv7em-linux-eabi.json +++ b/library/compiler-builtins/thumbv7em-linux-eabi.json @@ -11,11 +11,14 @@ "env": "", "executables": true, "linker": "arm-none-eabi-gcc", + "linker-flavor": "gcc", "llvm-target": "thumbv7em-none-eabi", "max-atomic-width": 32, "os": "linux", "panic-strategy": "abort", - "pre-link-args": ["-nostartfiles"], + "pre-link-args": { + "gcc": ["-nostartfiles"] + }, "relocation-model": "static", "target-endian": "little", "target-pointer-width": "32", diff --git a/library/compiler-builtins/thumbv7em-linux-eabihf.json b/library/compiler-builtins/thumbv7em-linux-eabihf.json index 536d28c951dfc..5d72ec3b47892 100644 --- a/library/compiler-builtins/thumbv7em-linux-eabihf.json +++ b/library/compiler-builtins/thumbv7em-linux-eabihf.json @@ -12,11 +12,14 @@ "executables": true, "features": "+vfp4,+d16,+fp-only-sp", "linker": "arm-none-eabi-gcc", + "linker-flavor": "gcc", "llvm-target": "thumbv7em-none-eabihf", "max-atomic-width": 32, "os": "linux", "panic-strategy": "abort", - "pre-link-args": ["-nostartfiles"], + "pre-link-args": { + "gcc": ["-nostartfiles"] + }, "relocation-model": "static", "target-endian": "little", "target-pointer-width": "32", diff --git a/library/compiler-builtins/thumbv7m-linux-eabi.json b/library/compiler-builtins/thumbv7m-linux-eabi.json index 02ed839cc82d9..1e8a7f0086fb3 100644 --- a/library/compiler-builtins/thumbv7m-linux-eabi.json +++ b/library/compiler-builtins/thumbv7m-linux-eabi.json @@ -11,11 +11,14 @@ "env": "", "executables": true, "linker": "arm-none-eabi-gcc", + "linker-flavor": "gcc", "llvm-target": "thumbv7m-none-eabi", "max-atomic-width": 32, "os": "linux", "panic-strategy": "abort", - "pre-link-args": ["-nostartfiles"], + "pre-link-args": { + "gcc": ["-nostartfiles"] + }, "relocation-model": "static", "target-endian": "little", "target-pointer-width": "32", From 4de2ff7b9d6db673989ebf7388447424e4293ee9 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 11 Apr 2017 14:28:31 -0500 Subject: [PATCH 0285/4206] appveyor: make the host x86_64 when testing the i686 target --- library/compiler-builtins/appveyor.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 61e5d6ce76f1d..7c82726850709 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -6,8 +6,12 @@ environment: install: - git submodule update --init - curl -sSf -o rustup-init.exe https://win.rustup.rs - - rustup-init.exe --default-host %TARGET% --default-toolchain nightly -y + - rustup-init.exe --default-host x86_64-pc-windows-msvc --default-toolchain nightly -y - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin + - ps: >- + If ($Env:TARGET -eq 'i686-pc-windows-msvc') { + rustup target add $Env:TARGET + } - rustc -Vv - cargo -V From 5b8965c9de461275758a7aef7cbeee619e42537a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 11 Apr 2017 14:47:23 -0500 Subject: [PATCH 0286/4206] i128 test: transmute intrinsic output before comparing on Windows, these intrinsics return a U64x2 type because of ABI requirements --- library/compiler-builtins/build.rs | 86 ++++++++++++++++++++++++------ 1 file changed, 71 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index ac75e6ede881a..5d48ec6ff897e 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -189,6 +189,7 @@ use core::mem; target_os = "linux", test)))] use std::mem; + use compiler_builtins::float::add::__adddf3; fn mk_f64(x: u64) -> f64 { @@ -828,11 +829,22 @@ fn divsi3() { } fn prologue() -> &'static str { - " + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; + use compiler_builtins::int::sdiv::__divti3; static TEST_CASES: &[((i128, i128), i128)] = &[ -" +"# } fn epilogue() -> &'static str { @@ -842,7 +854,7 @@ static TEST_CASES: &[((i128, i128), i128)] = &[ #[test] fn divti3() { for &((a, b), c) in TEST_CASES { - let c_ = __divti3(a, b); + let c_: i128 = unsafe { mem::transmute(__divti3(a, b)) }; assert_eq!(((a, b), c), ((a, b), c_)); } } @@ -1895,11 +1907,22 @@ fn modsi3() { } fn prologue() -> &'static str { - " + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; + use compiler_builtins::int::sdiv::__modti3; static TEST_CASES: &[((i128, i128), i128)] = &[ -" +"# } fn epilogue() -> &'static str { @@ -1909,7 +1932,7 @@ static TEST_CASES: &[((i128, i128), i128)] = &[ #[test] fn modti3() { for &((a, b), c) in TEST_CASES { - let c_ = __modti3(a, b); + let c_: i128 = unsafe { mem::transmute(__modti3(a, b)) }; assert_eq!(((a, b), c), ((a, b), c_)); } } @@ -2913,11 +2936,22 @@ fn udivmodsi4() { } fn prologue() -> &'static str { - " + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; + use compiler_builtins::int::udiv::__udivmodti4; static TEST_CASES: &[((u128, u128), (u128, u128))] = &[ -" +"# } fn epilogue() -> &'static str { @@ -2928,7 +2962,7 @@ static TEST_CASES: &[((u128, u128), (u128, u128))] = &[ fn udivmodti4() { for &((a, b), (c, rem)) in TEST_CASES { let mut rem_ = 0; - let c_ = __udivmodti4(a, b, Some(&mut rem_)); + let c_: u128 = unsafe { mem::transmute(__udivmodti4(a, b, Some(&mut rem_))) }; assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); } } @@ -3036,11 +3070,22 @@ fn udivsi3() { } fn prologue() -> &'static str { - " + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; + use compiler_builtins::int::udiv::__udivti3; static TEST_CASES: &[((u128, u128), u128)] = &[ -" +"# } fn epilogue() -> &'static str { @@ -3050,7 +3095,7 @@ static TEST_CASES: &[((u128, u128), u128)] = &[ #[test] fn udivti3() { for &((a, b), c) in TEST_CASES { - let c_ = __udivti3(a, b); + let c_: u128 = unsafe { mem::transmute(__udivti3(a, b)) }; assert_eq!(((a, b), c), ((a, b), c_)); } } @@ -3219,11 +3264,22 @@ fn umodsi3() { } fn prologue() -> &'static str { - " + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; + use compiler_builtins::int::udiv::__umodti3; static TEST_CASES: &[((u128, u128), u128)] = &[ -" +"# } fn epilogue() -> &'static str { @@ -3233,7 +3289,7 @@ static TEST_CASES: &[((u128, u128), u128)] = &[ #[test] fn umodti3() { for &((a, b), c) in TEST_CASES { - let c_ = __umodti3(a, b); + let c_: u128 = unsafe { mem::transmute(__umodti3(a, b)) }; assert_eq!(((a, b), c), ((a, b), c_)); } } From 3043cf860c4172d2a5eb1b4965dd119950122e88 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 11 Apr 2017 14:53:19 -0500 Subject: [PATCH 0287/4206] powershell -> cmd.exe --- library/compiler-builtins/appveyor.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 7c82726850709..f5a4c62f04c11 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -8,10 +8,7 @@ install: - curl -sSf -o rustup-init.exe https://win.rustup.rs - rustup-init.exe --default-host x86_64-pc-windows-msvc --default-toolchain nightly -y - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - - ps: >- - If ($Env:TARGET -eq 'i686-pc-windows-msvc') { - rustup target add $Env:TARGET - } + - if "%TARGET%"=="i686-pc-windows-msvc" ( rustup target add %TARGET% ) - rustc -Vv - cargo -V From 1e48efeaef0c43e2125a4be9328f59e0a79f7a61 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 11 Apr 2017 15:03:21 -0500 Subject: [PATCH 0288/4206] Revert "i128 test: transmute intrinsic output before comparing" This reverts commit 46085a2313ba196e3aab85a3380a07c6bd838fda. --- library/compiler-builtins/build.rs | 86 ++++++------------------------ 1 file changed, 15 insertions(+), 71 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 5d48ec6ff897e..ac75e6ede881a 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -189,7 +189,6 @@ use core::mem; target_os = "linux", test)))] use std::mem; - use compiler_builtins::float::add::__adddf3; fn mk_f64(x: u64) -> f64 { @@ -829,22 +828,11 @@ fn divsi3() { } fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; - + " use compiler_builtins::int::sdiv::__divti3; static TEST_CASES: &[((i128, i128), i128)] = &[ -"# +" } fn epilogue() -> &'static str { @@ -854,7 +842,7 @@ static TEST_CASES: &[((i128, i128), i128)] = &[ #[test] fn divti3() { for &((a, b), c) in TEST_CASES { - let c_: i128 = unsafe { mem::transmute(__divti3(a, b)) }; + let c_ = __divti3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } @@ -1907,22 +1895,11 @@ fn modsi3() { } fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; - + " use compiler_builtins::int::sdiv::__modti3; static TEST_CASES: &[((i128, i128), i128)] = &[ -"# +" } fn epilogue() -> &'static str { @@ -1932,7 +1909,7 @@ static TEST_CASES: &[((i128, i128), i128)] = &[ #[test] fn modti3() { for &((a, b), c) in TEST_CASES { - let c_: i128 = unsafe { mem::transmute(__modti3(a, b)) }; + let c_ = __modti3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } @@ -2936,22 +2913,11 @@ fn udivmodsi4() { } fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; - + " use compiler_builtins::int::udiv::__udivmodti4; static TEST_CASES: &[((u128, u128), (u128, u128))] = &[ -"# +" } fn epilogue() -> &'static str { @@ -2962,7 +2928,7 @@ static TEST_CASES: &[((u128, u128), (u128, u128))] = &[ fn udivmodti4() { for &((a, b), (c, rem)) in TEST_CASES { let mut rem_ = 0; - let c_: u128 = unsafe { mem::transmute(__udivmodti4(a, b, Some(&mut rem_))) }; + let c_ = __udivmodti4(a, b, Some(&mut rem_)); assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); } } @@ -3070,22 +3036,11 @@ fn udivsi3() { } fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; - + " use compiler_builtins::int::udiv::__udivti3; static TEST_CASES: &[((u128, u128), u128)] = &[ -"# +" } fn epilogue() -> &'static str { @@ -3095,7 +3050,7 @@ static TEST_CASES: &[((u128, u128), u128)] = &[ #[test] fn udivti3() { for &((a, b), c) in TEST_CASES { - let c_: u128 = unsafe { mem::transmute(__udivti3(a, b)) }; + let c_ = __udivti3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } @@ -3264,22 +3219,11 @@ fn umodsi3() { } fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; - + " use compiler_builtins::int::udiv::__umodti3; static TEST_CASES: &[((u128, u128), u128)] = &[ -"# +" } fn epilogue() -> &'static str { @@ -3289,7 +3233,7 @@ static TEST_CASES: &[((u128, u128), u128)] = &[ #[test] fn umodti3() { for &((a, b), c) in TEST_CASES { - let c_: u128 = unsafe { mem::transmute(__umodti3(a, b)) }; + let c_ = __umodti3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } From 05b6e8fa6c0aaede86dfa6db6ec5f629318e9e42 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 11 Apr 2017 15:08:52 -0500 Subject: [PATCH 0289/4206] ignore i128 tests on windows see #158 --- library/compiler-builtins/tests/divti3.rs | 3 ++- library/compiler-builtins/tests/modti3.rs | 3 ++- library/compiler-builtins/tests/udivmodti4.rs | 3 ++- library/compiler-builtins/tests/udivti3.rs | 3 ++- library/compiler-builtins/tests/umodti3.rs | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/tests/divti3.rs b/library/compiler-builtins/tests/divti3.rs index 7919f8fe396a3..4c897896e3df3 100644 --- a/library/compiler-builtins/tests/divti3.rs +++ b/library/compiler-builtins/tests/divti3.rs @@ -6,5 +6,6 @@ test), no_std)] // FIXME(#137) -#[cfg(not(target_arch = "mips"))] +// FIXME(#158) +#[cfg(not(any(target_arch = "mips"), windows))] include!(concat!(env!("OUT_DIR"), "/divti3.rs")); diff --git a/library/compiler-builtins/tests/modti3.rs b/library/compiler-builtins/tests/modti3.rs index 62129cd04d3c3..191bd9b6f912f 100644 --- a/library/compiler-builtins/tests/modti3.rs +++ b/library/compiler-builtins/tests/modti3.rs @@ -6,5 +6,6 @@ test), no_std)] // FIXME(#137) -#[cfg(not(target_arch = "mips"))] +// FIXME(#158) +#[cfg(not(any(target_arch = "mips"), windows))] include!(concat!(env!("OUT_DIR"), "/modti3.rs")); diff --git a/library/compiler-builtins/tests/udivmodti4.rs b/library/compiler-builtins/tests/udivmodti4.rs index 8185ec0e78971..daeb81075d583 100644 --- a/library/compiler-builtins/tests/udivmodti4.rs +++ b/library/compiler-builtins/tests/udivmodti4.rs @@ -6,5 +6,6 @@ test), no_std)] // FIXME(#137) -#[cfg(not(target_arch = "mips"))] +// FIXME(#158) +#[cfg(not(any(target_arch = "mips"), windows))] include!(concat!(env!("OUT_DIR"), "/udivmodti4.rs")); diff --git a/library/compiler-builtins/tests/udivti3.rs b/library/compiler-builtins/tests/udivti3.rs index cefddda8f8698..5315f310926ad 100644 --- a/library/compiler-builtins/tests/udivti3.rs +++ b/library/compiler-builtins/tests/udivti3.rs @@ -6,5 +6,6 @@ test), no_std)] // FIXME(#137) -#[cfg(not(target_arch = "mips"))] +// FIXME(#158) +#[cfg(not(any(target_arch = "mips"), windows))] include!(concat!(env!("OUT_DIR"), "/udivti3.rs")); diff --git a/library/compiler-builtins/tests/umodti3.rs b/library/compiler-builtins/tests/umodti3.rs index 57e651b2710f1..22a4180b375a2 100644 --- a/library/compiler-builtins/tests/umodti3.rs +++ b/library/compiler-builtins/tests/umodti3.rs @@ -6,5 +6,6 @@ test), no_std)] // FIXME(#137) -#[cfg(not(target_arch = "mips"))] +// FIXME(#158) +#[cfg(not(any(target_arch = "mips"), windows))] include!(concat!(env!("OUT_DIR"), "/umodti3.rs")); From 0666ed145ae591c8c195e7f64c4be4f5c082c4db Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 11 Apr 2017 15:17:05 -0500 Subject: [PATCH 0290/4206] fix cfg syntax --- library/compiler-builtins/tests/divti3.rs | 2 +- library/compiler-builtins/tests/modti3.rs | 2 +- library/compiler-builtins/tests/udivmodti4.rs | 2 +- library/compiler-builtins/tests/udivti3.rs | 2 +- library/compiler-builtins/tests/umodti3.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/tests/divti3.rs b/library/compiler-builtins/tests/divti3.rs index 4c897896e3df3..c86785fe8134b 100644 --- a/library/compiler-builtins/tests/divti3.rs +++ b/library/compiler-builtins/tests/divti3.rs @@ -7,5 +7,5 @@ // FIXME(#137) // FIXME(#158) -#[cfg(not(any(target_arch = "mips"), windows))] +#[cfg(not(any(target_arch = "mips", windows)))] include!(concat!(env!("OUT_DIR"), "/divti3.rs")); diff --git a/library/compiler-builtins/tests/modti3.rs b/library/compiler-builtins/tests/modti3.rs index 191bd9b6f912f..2ce42ac46f4d1 100644 --- a/library/compiler-builtins/tests/modti3.rs +++ b/library/compiler-builtins/tests/modti3.rs @@ -7,5 +7,5 @@ // FIXME(#137) // FIXME(#158) -#[cfg(not(any(target_arch = "mips"), windows))] +#[cfg(not(any(target_arch = "mips", windows)))] include!(concat!(env!("OUT_DIR"), "/modti3.rs")); diff --git a/library/compiler-builtins/tests/udivmodti4.rs b/library/compiler-builtins/tests/udivmodti4.rs index daeb81075d583..5629d617bd376 100644 --- a/library/compiler-builtins/tests/udivmodti4.rs +++ b/library/compiler-builtins/tests/udivmodti4.rs @@ -7,5 +7,5 @@ // FIXME(#137) // FIXME(#158) -#[cfg(not(any(target_arch = "mips"), windows))] +#[cfg(not(any(target_arch = "mips", windows)))] include!(concat!(env!("OUT_DIR"), "/udivmodti4.rs")); diff --git a/library/compiler-builtins/tests/udivti3.rs b/library/compiler-builtins/tests/udivti3.rs index 5315f310926ad..350922563ffd5 100644 --- a/library/compiler-builtins/tests/udivti3.rs +++ b/library/compiler-builtins/tests/udivti3.rs @@ -7,5 +7,5 @@ // FIXME(#137) // FIXME(#158) -#[cfg(not(any(target_arch = "mips"), windows))] +#[cfg(not(any(target_arch = "mips", windows)))] include!(concat!(env!("OUT_DIR"), "/udivti3.rs")); diff --git a/library/compiler-builtins/tests/umodti3.rs b/library/compiler-builtins/tests/umodti3.rs index 22a4180b375a2..5807bcff395e3 100644 --- a/library/compiler-builtins/tests/umodti3.rs +++ b/library/compiler-builtins/tests/umodti3.rs @@ -7,5 +7,5 @@ // FIXME(#137) // FIXME(#158) -#[cfg(not(any(target_arch = "mips"), windows))] +#[cfg(not(any(target_arch = "mips", windows)))] include!(concat!(env!("OUT_DIR"), "/umodti3.rs")); From 8dad658a6bb796366f0a333b56f8bd7d6b71f1ba Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 11 Apr 2017 17:09:05 -0500 Subject: [PATCH 0291/4206] move intrinsics test from src/bin to examples with this change the libc crate is not required when calling `cargo build -p compiler-builtins` --- library/compiler-builtins/ci/run.sh | 12 ++++++------ .../{src/bin => examples}/intrinsics.rs | 0 2 files changed, 6 insertions(+), 6 deletions(-) rename library/compiler-builtins/{src/bin => examples}/intrinsics.rs (100%) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 771f8812a029a..4a28e8a1894b5 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -41,10 +41,10 @@ esac # Verify that we haven't drop any intrinsic/symbol case $1 in thumb*) - xargo build --features c --target $1 --bin intrinsics + xargo build --features c --target $1 --example intrinsics ;; *) - cargo build --no-default-features --features c --target $1 --bin intrinsics + cargo build --no-default-features --features c --target $1 --example intrinsics ;; esac @@ -52,12 +52,12 @@ esac # TODO(#79) fix the undefined references problem for debug-assertions+lto case $1 in thumb*) - RUSTFLAGS="-C debug-assertions=no" xargo rustc --no-default-features --features c --target $1 --bin intrinsics -- -C lto -C link-arg=-nostartfiles - xargo rustc --no-default-features --features c --target $1 --bin intrinsics --release -- -C lto + RUSTFLAGS="-C debug-assertions=no" xargo rustc --no-default-features --features c --target $1 --example intrinsics -- -C lto -C link-arg=-nostartfiles + xargo rustc --no-default-features --features c --target $1 --example intrinsics --release -- -C lto ;; *) - RUSTFLAGS="-C debug-assertions=no" cargo rustc --no-default-features --features c --target $1 --bin intrinsics -- -C lto - cargo rustc --no-default-features --features c --target $1 --bin intrinsics --release -- -C lto + RUSTFLAGS="-C debug-assertions=no" cargo rustc --no-default-features --features c --target $1 --example intrinsics -- -C lto + cargo rustc --no-default-features --features c --target $1 --example intrinsics --release -- -C lto ;; esac diff --git a/library/compiler-builtins/src/bin/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs similarity index 100% rename from library/compiler-builtins/src/bin/intrinsics.rs rename to library/compiler-builtins/examples/intrinsics.rs From 32540055709d9bd657e07ff92e9087f5bbaf4d3e Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 5 May 2017 23:31:41 +0200 Subject: [PATCH 0292/4206] Rename float conversion macros to something nicer --- library/compiler-builtins/src/float/conv.rs | 32 ++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index efe590ab43be2..37aaa1cdab264 100755 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -12,7 +12,7 @@ macro_rules! fp_overflow { } } -macro_rules! fp_convert { +macro_rules! int_to_float { ($intrinsic:ident: $ity:ty, $fty:ty) => { pub extern "C" fn $intrinsic(i: $ity) -> $fty { @@ -82,12 +82,12 @@ macro_rules! fp_convert { } } -fp_convert!(__floatsisf: i32, f32); -fp_convert!(__floatsidf: i32, f64); -fp_convert!(__floatdidf: i64, f64); -fp_convert!(__floatunsisf: u32, f32); -fp_convert!(__floatunsidf: u32, f64); -fp_convert!(__floatundidf: u64, f64); +int_to_float!(__floatsisf: i32, f32); +int_to_float!(__floatsidf: i32, f64); +int_to_float!(__floatdidf: i64, f64); +int_to_float!(__floatunsisf: u32, f32); +int_to_float!(__floatunsidf: u32, f64); +int_to_float!(__floatundidf: u64, f64); #[derive(PartialEq, Debug)] enum Sign { @@ -95,7 +95,7 @@ enum Sign { Negative } -macro_rules! fp_fix { +macro_rules! float_to_int { ($intrinsic:ident: $fty:ty, $ity:ty) => { pub extern "C" fn $intrinsic(f: $fty) -> $ity { let fixint_min = <$ity>::min_value(); @@ -147,12 +147,12 @@ macro_rules! fp_fix { } } -fp_fix!(__fixsfsi: f32, i32); -fp_fix!(__fixsfdi: f32, i64); -fp_fix!(__fixdfsi: f64, i32); -fp_fix!(__fixdfdi: f64, i64); +float_to_int!(__fixsfsi: f32, i32); +float_to_int!(__fixsfdi: f32, i64); +float_to_int!(__fixdfsi: f64, i32); +float_to_int!(__fixdfdi: f64, i64); -fp_fix!(__fixunssfsi: f32, u32); -fp_fix!(__fixunssfdi: f32, u64); -fp_fix!(__fixunsdfsi: f64, u32); -fp_fix!(__fixunsdfdi: f64, u64); +float_to_int!(__fixunssfsi: f32, u32); +float_to_int!(__fixunssfdi: f32, u64); +float_to_int!(__fixunsdfsi: f64, u32); +float_to_int!(__fixunsdfdi: f64, u64); From 21db51b3f85280b1085ffff06b98214018258f48 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 6 May 2017 00:42:59 +0200 Subject: [PATCH 0293/4206] Mark some float related intrinsics as implemented in README.md They have been implemented since --- library/compiler-builtins/README.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 0810edf5bd1c0..2cd28d495eeea 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -141,22 +141,22 @@ features = ["c"] - [x] divsi3.c - [ ] extendhfsf2.c - [ ] extendsfdf2.c -- [ ] fixdfdi.c -- [ ] fixdfsi.c -- [ ] fixsfdi.c -- [ ] fixsfsi.c -- [ ] fixunsdfdi.c -- [ ] fixunsdfsi.c -- [ ] fixunssfdi.c -- [ ] fixunssfsi.c -- [ ] floatdidf.c +- [x] fixdfdi.c +- [x] fixdfsi.c +- [x] fixsfdi.c +- [x] fixsfsi.c +- [x] fixunsdfdi.c +- [x] fixunsdfsi.c +- [x] fixunssfdi.c +- [x] fixunssfsi.c +- [x] floatdidf.c - [ ] floatdisf.c -- [ ] floatsidf.c -- [ ] floatsisf.c -- [ ] floatundidf.c +- [x] floatsidf.c +- [x] floatsisf.c +- [x] floatundidf.c - [ ] floatundisf.c -- [ ] floatunsidf.c -- [ ] floatunsisf.c +- [x] floatunsidf.c +- [x] floatunsisf.c - [ ] i386/ashldi3.S - [ ] i386/ashrdi3.S - [ ] i386/chkstk.S From 7e5af82760db6ecc28f4ab52b3a8d3952b732c47 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 6 May 2017 02:22:54 +0200 Subject: [PATCH 0294/4206] Add i128 <-> float conversion functions --- library/compiler-builtins/src/float/conv.rs | 36 +++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 37aaa1cdab264..3413812a5acc4 100755 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -14,8 +14,11 @@ macro_rules! fp_overflow { macro_rules! int_to_float { ($intrinsic:ident: $ity:ty, $fty:ty) => { + int_to_float!($intrinsic: $ity, $fty, "C"); + }; + ($intrinsic:ident: $ity:ty, $fty:ty, $abi:tt) => { - pub extern "C" fn $intrinsic(i: $ity) -> $fty { + pub extern $abi fn $intrinsic(i: $ity) -> $fty { if i == 0 { return 0.0 } @@ -82,12 +85,25 @@ macro_rules! int_to_float { } } +macro_rules! int_to_float_unadj_on_win { + ($intrinsic:ident: $ity:ty, $fty:ty) => { + #[cfg(all(windows, target_pointer_width="64"))] + int_to_float!($intrinsic: $ity, $fty, "unadjusted"); + #[cfg(not(all(windows, target_pointer_width="64")))] + int_to_float!($intrinsic: $ity, $fty, "C"); + }; +} + int_to_float!(__floatsisf: i32, f32); int_to_float!(__floatsidf: i32, f64); int_to_float!(__floatdidf: i64, f64); +int_to_float_unadj_on_win!(__floattisf: i128, f32); +int_to_float_unadj_on_win!(__floattidf: i128, f64); int_to_float!(__floatunsisf: u32, f32); int_to_float!(__floatunsidf: u32, f64); int_to_float!(__floatundidf: u64, f64); +int_to_float_unadj_on_win!(__floatuntisf: u128, f32); +int_to_float_unadj_on_win!(__floatuntidf: u128, f64); #[derive(PartialEq, Debug)] enum Sign { @@ -97,7 +113,10 @@ enum Sign { macro_rules! float_to_int { ($intrinsic:ident: $fty:ty, $ity:ty) => { - pub extern "C" fn $intrinsic(f: $fty) -> $ity { + float_to_int!($intrinsic: $fty, $ity, "C"); + }; + ($intrinsic:ident: $fty:ty, $ity:ty, $abi:tt) => { + pub extern $abi fn $intrinsic(f: $fty) -> $ity { let fixint_min = <$ity>::min_value(); let fixint_max = <$ity>::max_value(); let fixint_bits = <$ity>::bits() as usize; @@ -147,12 +166,25 @@ macro_rules! float_to_int { } } +macro_rules! float_to_int_unadj_on_win { + ($intrinsic:ident: $fty:ty, $ity:ty) => { + #[cfg(all(windows, target_pointer_width="64"))] + float_to_int!($intrinsic: $fty, $ity, "unadjusted"); + #[cfg(not(all(windows, target_pointer_width="64")))] + float_to_int!($intrinsic: $fty, $ity, "C"); + }; +} + float_to_int!(__fixsfsi: f32, i32); float_to_int!(__fixsfdi: f32, i64); +float_to_int_unadj_on_win!(__fixsfti: f32, i128); float_to_int!(__fixdfsi: f64, i32); float_to_int!(__fixdfdi: f64, i64); +float_to_int_unadj_on_win!(__fixdfti: f64, i128); float_to_int!(__fixunssfsi: f32, u32); float_to_int!(__fixunssfdi: f32, u64); +float_to_int_unadj_on_win!(__fixunssfti: f32, u128); float_to_int!(__fixunsdfsi: f64, u32); float_to_int!(__fixunsdfdi: f64, u64); +float_to_int_unadj_on_win!(__fixunsdfti: f64, u128); From c8b5bb756c10dca567be643e4721dbf607aa2924 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 6 May 2017 05:36:40 +0200 Subject: [PATCH 0295/4206] Use cast 0.2.1 for i128 support --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 59f6b404abdd0..3503438fc4f75 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -5,7 +5,7 @@ name = "compiler_builtins" version = "0.1.0" [build-dependencies] -cast = { version = "0.2.0", optional = true } +cast = { version = "0.2.1", features = ["x128"], optional = true } rand = { version = "0.3.15", optional = true } [build-dependencies.gcc] From 7e072454110395e06fc802cd74e0bd339324f1c9 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 6 May 2017 05:20:20 +0200 Subject: [PATCH 0296/4206] Implement tests for floattidf and floattisf --- library/compiler-builtins/build.rs | 136 ++++++++++++++++++- library/compiler-builtins/tests/floattidf.rs | 8 ++ library/compiler-builtins/tests/floattisf.rs | 8 ++ 3 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/tests/floattidf.rs create mode 100644 library/compiler-builtins/tests/floattisf.rs diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index ac75e6ede881a..bbe9dafa8d8bc 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -49,7 +49,7 @@ mod tests { use std::path::PathBuf; use std::{env, mem}; - use self::cast::{f32, f64, u32, u64, i32, i64}; + use self::cast::{f32, f64, u32, u64, u128, i32, i64, i128}; use self::rand::Rng; const NTESTS: usize = 10_000; @@ -81,6 +81,8 @@ mod tests { Floatdidf, Floatsidf, Floatsisf, + Floattisf, + Floattidf, Floatundidf, Floatunsidf, Floatunsisf, @@ -1536,6 +1538,138 @@ fn floatsisf() { } } + #[derive(Eq, Hash, PartialEq)] + pub struct Floattisf { + a: i128, + b: u32, // f32 + } + + impl TestCase for Floattisf { + fn name() -> &'static str { + "floattisf" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i128(rng); + Some( + Floattisf { + a, + b: to_u32(f32(a)), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__floattisf; + +fn to_u32(x: f32) -> u32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((i128,), u32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn floattisf() { + for &((a,), b) in TEST_CASES { + let b_ = __floattisf(a); + assert_eq!(((a,), b), ((a,), to_u32(b_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Floattidf { + a: i128, + b: u64, // f64 + } + + impl TestCase for Floattidf { + fn name() -> &'static str { + "floattidf" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i128(rng); + Some( + Floattidf { + a, + b: to_u64(f64(a)), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__floattidf; + +fn to_u64(x: f64) -> u64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((i128,), u64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn floattidf() { + for &((a,), b) in TEST_CASES { + let b_ = __floattidf(a); + assert_eq!(((a,), b), ((a,), to_u64(b_))); + } +} +" + } + } + #[derive(Eq, Hash, PartialEq)] pub struct Floatundidf { a: u64, diff --git a/library/compiler-builtins/tests/floattidf.rs b/library/compiler-builtins/tests/floattidf.rs new file mode 100644 index 0000000000000..4e4f84ddb01b9 --- /dev/null +++ b/library/compiler-builtins/tests/floattidf.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/floattidf.rs")); diff --git a/library/compiler-builtins/tests/floattisf.rs b/library/compiler-builtins/tests/floattisf.rs new file mode 100644 index 0000000000000..2a0657d3d00e9 --- /dev/null +++ b/library/compiler-builtins/tests/floattisf.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/floattisf.rs")); From 390e1e99c9f1ccc19d864b18fd1dd553f6a91bb9 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 6 May 2017 05:24:20 +0200 Subject: [PATCH 0297/4206] Implement tests for fixdfti and fixsfti --- library/compiler-builtins/build.rs | 124 +++++++++++++++++++++ library/compiler-builtins/tests/fixdfti.rs | 8 ++ library/compiler-builtins/tests/fixsfti.rs | 8 ++ 3 files changed, 140 insertions(+) create mode 100644 library/compiler-builtins/tests/fixdfti.rs create mode 100644 library/compiler-builtins/tests/fixsfti.rs diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index bbe9dafa8d8bc..42f2b477155b7 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -74,6 +74,8 @@ mod tests { Fixdfsi, Fixsfdi, Fixsfsi, + Fixsfti, + Fixdfti, Fixunsdfdi, Fixunsdfsi, Fixunssfdi, @@ -1096,6 +1098,128 @@ fn fixsfdi() { } } + #[derive(Eq, Hash, PartialEq)] + pub struct Fixsfti { + a: u32, // f32 + b: i128, + } + + impl TestCase for Fixsfti { + fn name() -> &'static str { + "fixsfti" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f32(rng); + i128(a).ok().map(|b| Fixsfti { a: to_u32(a), b }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__fixsfti; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32,), i128)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn fixsfti() { + for &((a,), b) in TEST_CASES { + let b_ = __fixsfti(mk_f32(a)); + assert_eq!(((a,), b), ((a,), b_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Fixdfti { + a: u64, // f64 + b: i128, + } + + impl TestCase for Fixdfti { + fn name() -> &'static str { + "fixdfti" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f64(rng); + i128(a).ok().map(|b| Fixdfti { a: to_u64(a), b }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__fixdfti; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64,), i128)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn fixdfti() { + for &((a,), b) in TEST_CASES { + let b_ = __fixdfti(mk_f64(a)); + assert_eq!(((a,), b), ((a,), b_)); + } +} +" + } + } + #[derive(Eq, Hash, PartialEq)] pub struct Fixunsdfdi { a: u64, // f64 diff --git a/library/compiler-builtins/tests/fixdfti.rs b/library/compiler-builtins/tests/fixdfti.rs new file mode 100644 index 0000000000000..5bae55e99f38a --- /dev/null +++ b/library/compiler-builtins/tests/fixdfti.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/fixdfti.rs")); diff --git a/library/compiler-builtins/tests/fixsfti.rs b/library/compiler-builtins/tests/fixsfti.rs new file mode 100644 index 0000000000000..653157df26ba9 --- /dev/null +++ b/library/compiler-builtins/tests/fixsfti.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/fixsfti.rs")); From 273211c01b9c7cc912b5ee1f16c06f306ae2a0b6 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 6 May 2017 05:28:40 +0200 Subject: [PATCH 0298/4206] Implement tests for fixunsdfti and fixunssfti --- library/compiler-builtins/build.rs | 124 ++++++++++++++++++ library/compiler-builtins/tests/fixunsdfti.rs | 8 ++ library/compiler-builtins/tests/fixunssfti.rs | 8 ++ 3 files changed, 140 insertions(+) create mode 100644 library/compiler-builtins/tests/fixunsdfti.rs create mode 100644 library/compiler-builtins/tests/fixunssfti.rs diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 42f2b477155b7..7af47178a4c68 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -80,6 +80,8 @@ mod tests { Fixunsdfsi, Fixunssfdi, Fixunssfsi, + Fixunssfti, + Fixunsdfti, Floatdidf, Floatsidf, Floatsisf, @@ -1464,6 +1466,128 @@ fn fixunssfsi() { } } + #[derive(Eq, Hash, PartialEq)] + pub struct Fixunssfti { + a: u32, // f32 + b: u128, + } + + impl TestCase for Fixunssfti { + fn name() -> &'static str { + "fixunssfti" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f32(rng); + u128(a).ok().map(|b| Fixunssfti { a: to_u32(a), b }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__fixunssfti; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32,), u128)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn fixunssfti() { + for &((a,), b) in TEST_CASES { + let b_ = __fixunssfti(mk_f32(a)); + assert_eq!(((a,), b), ((a,), b_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Fixunsdfti { + a: u64, // f64 + b: u128, + } + + impl TestCase for Fixunsdfti { + fn name() -> &'static str { + "fixunsdfti" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f64(rng); + u128(a).ok().map(|b| Fixunsdfti { a: to_u64(a), b }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__fixunsdfti; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64,), u128)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn fixunsdfti() { + for &((a,), b) in TEST_CASES { + let b_ = __fixunsdfti(mk_f64(a)); + assert_eq!(((a,), b), ((a,), b_)); + } +} +" + } + } + #[derive(Eq, Hash, PartialEq)] pub struct Floatdidf { a: i64, diff --git a/library/compiler-builtins/tests/fixunsdfti.rs b/library/compiler-builtins/tests/fixunsdfti.rs new file mode 100644 index 0000000000000..615e7b33b8dbf --- /dev/null +++ b/library/compiler-builtins/tests/fixunsdfti.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/fixunsdfti.rs")); diff --git a/library/compiler-builtins/tests/fixunssfti.rs b/library/compiler-builtins/tests/fixunssfti.rs new file mode 100644 index 0000000000000..d67f9e794e0e9 --- /dev/null +++ b/library/compiler-builtins/tests/fixunssfti.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/fixunssfti.rs")); From ee6be10895b00b35fd1f500ffbfd98e78b52cffd Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 6 May 2017 05:32:51 +0200 Subject: [PATCH 0299/4206] Implement tests for floatuntidf and floatuntisf --- library/compiler-builtins/build.rs | 134 ++++++++++++++++++ .../compiler-builtins/tests/floatuntidf.rs | 8 ++ .../compiler-builtins/tests/floatuntisf.rs | 8 ++ 3 files changed, 150 insertions(+) create mode 100644 library/compiler-builtins/tests/floatuntidf.rs create mode 100644 library/compiler-builtins/tests/floatuntisf.rs diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 7af47178a4c68..bcb7fbe0f30a3 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -90,6 +90,8 @@ mod tests { Floatundidf, Floatunsidf, Floatunsisf, + Floatuntisf, + Floatuntidf, // float/pow.rs Powidf2, @@ -2116,6 +2118,138 @@ fn floatunsisf() { } } + #[derive(Eq, Hash, PartialEq)] + pub struct Floatuntisf { + a: u128, + b: u32, // f32 + } + + impl TestCase for Floatuntisf { + fn name() -> &'static str { + "floatuntisf" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u128(rng); + Some( + Floatuntisf { + a, + b: to_u32(f32(a)), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__floatuntisf; + +fn to_u32(x: f32) -> u32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u128,), u32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn floatuntisf() { + for &((a,), b) in TEST_CASES { + let b_ = __floatuntisf(a); + assert_eq!(((a,), b), ((a,), to_u32(b_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Floatuntidf { + a: u128, + b: u64, // f64 + } + + impl TestCase for Floatuntidf { + fn name() -> &'static str { + "floatuntidf" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u128(rng); + Some( + Floatuntidf { + a, + b: to_u64(f64(a)), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::conv::__floatuntidf; + +fn to_u64(x: f64) -> u64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u128,), u64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn floatuntidf() { + for &((a,), b) in TEST_CASES { + let b_ = __floatuntidf(a); + assert_eq!(((a,), b), ((a,), to_u64(b_))); + } +} +" + } + } + #[derive(Eq, Hash, PartialEq)] pub struct Moddi3 { a: i64, diff --git a/library/compiler-builtins/tests/floatuntidf.rs b/library/compiler-builtins/tests/floatuntidf.rs new file mode 100644 index 0000000000000..4ea272e97d113 --- /dev/null +++ b/library/compiler-builtins/tests/floatuntidf.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/floatuntidf.rs")); diff --git a/library/compiler-builtins/tests/floatuntisf.rs b/library/compiler-builtins/tests/floatuntisf.rs new file mode 100644 index 0000000000000..74cd853e49ecd --- /dev/null +++ b/library/compiler-builtins/tests/floatuntisf.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/floatuntisf.rs")); From 313d3bb49f794f1ca44dfdc060cc6c832660f9b7 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 6 May 2017 15:29:43 +0200 Subject: [PATCH 0300/4206] Adjust for changed cast function --- library/compiler-builtins/build.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index bcb7fbe0f30a3..7c4135d745a08 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -2135,12 +2135,13 @@ fn floatunsisf() { Self: Sized, { let a = gen_u128(rng); - Some( + let f_a = f32(a); + f_a.ok().map(|f| { Floatuntisf { a, - b: to_u32(f32(a)), - }, - ) + b: to_u32(f), + } + }) } fn to_string(&self, buffer: &mut String) { From 2aaaa38e25caf19a93b70f5be6a81b03bf9bfdc1 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 6 May 2017 05:33:28 +0200 Subject: [PATCH 0301/4206] Mark the functions just implemented in README.md --- library/compiler-builtins/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 2cd28d495eeea..5f59b44b1a8b0 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -196,14 +196,14 @@ These builtins are needed to support 128-bit integers, which are in the process - [x] ashlti3.c - [x] ashrti3.c - [x] divti3.c -- [ ] fixdfti.c -- [ ] fixsfti.c -- [ ] fixunsdfti.c -- [ ] fixunssfti.c -- [ ] floattidf.c -- [ ] floattisf.c -- [ ] floatuntidf.c -- [ ] floatuntisf.c +- [x] fixdfti.c +- [x] fixsfti.c +- [x] fixunsdfti.c +- [x] fixunssfti.c +- [x] floattidf.c +- [x] floattisf.c +- [x] floatuntidf.c +- [x] floatuntisf.c - [x] lshrti3.c - [x] modti3.c - [x] muloti4.c From 31048e53b5a24dc690a584c5d3f31c5fe55b1851 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 6 May 2017 05:34:50 +0200 Subject: [PATCH 0302/4206] Fix test name gotten wrong --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 7c4135d745a08..ba8c5e0de7ae5 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1092,7 +1092,7 @@ static TEST_CASES: &[((u32,), i32)] = &[ ]; #[test] -fn fixsfdi() { +fn fixsfsi() { for &((a,), b) in TEST_CASES { let b_ = __fixsfsi(mk_f32(a)); assert_eq!(((a,), b), ((a,), b_)); From 197b7e6d97836201690668e794d1dc1f59ff8c67 Mon Sep 17 00:00:00 2001 From: est31 Date: Sun, 7 May 2017 03:03:58 +0200 Subject: [PATCH 0303/4206] Print generated files --- library/compiler-builtins/build.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index ba8c5e0de7ae5..1ae8b41eab99f 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -3934,7 +3934,9 @@ macro_rules! panic { let rng = &mut rand::thread_rng(); let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); - let out_file = out_dir.join(format!("{}.rs", T::name())); + let out_file_name = format!("{}.rs", T::name()); + let out_file = out_dir.join(&out_file_name); + println!("Generating {}", out_file_name); let contents = mk_tests::(NTESTS, rng); File::create(out_file) From ddc95ea11c324c47186cb176674bfe0441b21a7c Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 8 May 2017 00:05:00 +0200 Subject: [PATCH 0304/4206] Update cast to 0.2.2 to fix bug in debug mode --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 3503438fc4f75..e23c66605a830 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -5,7 +5,7 @@ name = "compiler_builtins" version = "0.1.0" [build-dependencies] -cast = { version = "0.2.1", features = ["x128"], optional = true } +cast = { version = "0.2.2", features = ["x128"], optional = true } rand = { version = "0.3.15", optional = true } [build-dependencies.gcc] From 6eeab2e62f85bbf0f95d89c0c94f785231a19f23 Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 8 May 2017 00:49:36 +0200 Subject: [PATCH 0305/4206] floattidf, floatuntidf: ignore differences smaller than 2 in test Its possible that the generated f64 is different from the expected one by one bit. This is legal when both values are equally close to the i128/u128. --- library/compiler-builtins/build.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 1ae8b41eab99f..1b2aab149ba8f 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1913,7 +1913,8 @@ static TEST_CASES: &[((i128,), u64)] = &[ fn floattidf() { for &((a,), b) in TEST_CASES { let b_ = __floattidf(a); - assert_eq!(((a,), b), ((a,), to_u64(b_))); + let diff = if to_u64(b_) > b { to_u64(b_) - b } else { b - to_u64(b_) }; + assert_eq!(((a,), b, true), ((a,), b, diff <= 1)); } } " @@ -2244,7 +2245,8 @@ static TEST_CASES: &[((u128,), u64)] = &[ fn floatuntidf() { for &((a,), b) in TEST_CASES { let b_ = __floatuntidf(a); - assert_eq!(((a,), b), ((a,), to_u64(b_))); + let diff = if to_u64(b_) > b { to_u64(b_) - b } else { b - to_u64(b_) }; + assert_eq!(((a,), b, true), ((a,), b, diff <= 1)); } } " From 915c2fd0d3abf822db468f7648785503552266c1 Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 8 May 2017 04:03:16 +0200 Subject: [PATCH 0306/4206] Fix overflow bug when creating the absolute value Previously, the tests failed on some platforms due to it. --- library/compiler-builtins/src/int/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index a94a070ca062d..768b6b4c18f77 100755 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -63,7 +63,7 @@ macro_rules! int_impl { fn extract_sign(self) -> (bool, $uty) { if self < 0 { - (true, !(self as $uty) + 1) + (true, (!(self as $uty)).wrapping_add(1)) } else { (false, self as $uty) } From 4c69bfaff4bb2307e02fe6913f8f8d74b07a5ec1 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 10 May 2017 02:41:29 +0200 Subject: [PATCH 0307/4206] Build.rs: better debug output --- library/compiler-builtins/build.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 1b2aab149ba8f..c8179fe9eb9aa 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1913,8 +1913,9 @@ static TEST_CASES: &[((i128,), u64)] = &[ fn floattidf() { for &((a,), b) in TEST_CASES { let b_ = __floattidf(a); - let diff = if to_u64(b_) > b { to_u64(b_) - b } else { b - to_u64(b_) }; - assert_eq!(((a,), b, true), ((a,), b, diff <= 1)); + let g_b = to_u64(b_); + let diff = if g_b > b { g_b - b } else { b - g_b }; + assert_eq!(((a,), b, g_b, true), ((a,), b, g_b, diff <= 1)); } } " @@ -2245,8 +2246,9 @@ static TEST_CASES: &[((u128,), u64)] = &[ fn floatuntidf() { for &((a,), b) in TEST_CASES { let b_ = __floatuntidf(a); - let diff = if to_u64(b_) > b { to_u64(b_) - b } else { b - to_u64(b_) }; - assert_eq!(((a,), b, true), ((a,), b, diff <= 1)); + let g_b = to_u64(b_); + let diff = if g_b > b { g_b - b } else { b - g_b }; + assert_eq!(((a,), b, g_b, true), ((a,), b, g_b, diff <= 1)); } } " From 1b379a495d49e8bd0bac3f455e2a45dfaf799993 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 1 Jun 2017 07:40:50 -0500 Subject: [PATCH 0308/4206] remove unused macros to fix warnings --- library/compiler-builtins/src/float/conv.rs | 11 ----------- library/compiler-builtins/src/lib.rs | 15 --------------- 2 files changed, 26 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 3413812a5acc4..8905f12fafa40 100755 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -1,17 +1,6 @@ use float::Float; use int::Int; -macro_rules! fp_overflow { - (infinity, $fty:ty, $sign: expr) => { - return { - <$fty as Float>::from_parts( - $sign, - <$fty as Float>::exponent_max() as <$fty as Float>::Int, - 0 as <$fty as Float>::Int) - } - } -} - macro_rules! int_to_float { ($intrinsic:ident: $ity:ty, $fty:ty) => { int_to_float!($intrinsic: $ity, $fty, "C"); diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 8c7820bf99b0d..03f7258d13e79 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -78,21 +78,6 @@ macro_rules! urem { } } -macro_rules! srem { - ($sty:ty, $a:expr, $b:expr) => { - unsafe { - let a = $a; - let b = $b; - - if b == 0 || (b == -1 && a == $sty::min_value()) { - ::core::intrinsics::abort() - } else { - ::core::intrinsics::unchecked_rem(a, b) - } - } - } -} - // Hack for LLVM expectations for ABI on windows #[cfg(all(windows, target_pointer_width="64"))] #[repr(simd)] From 0f2515b715f65f19ba46b5afaa4610e868517a32 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 22 Jun 2017 14:00:31 -0700 Subject: [PATCH 0309/4206] Test with the 'c' feature enabled on CI --- library/compiler-builtins/Cargo.toml | 4 +++ library/compiler-builtins/appveyor.yml | 4 ++- library/compiler-builtins/ci/run.sh | 2 ++ .../compiler-builtins/examples/intrinsics.rs | 25 +++++-------------- 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index e23c66605a830..69b9c03c03d09 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -27,5 +27,9 @@ utest-cortex-m-qemu = { default-features = false, git = "https://github.com/japa%20utest-macros%20=%20%7B%20git%20="https://github.com/japaric/utest" } +[[example]] +name = "intrinsics" +required-features = ["c"] + [workspace] diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index f5a4c62f04c11..2bef109367c8a 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -5,7 +5,7 @@ environment: install: - git submodule update --init - - curl -sSf -o rustup-init.exe https://win.rustup.rs + - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - rustup-init.exe --default-host x86_64-pc-windows-msvc --default-toolchain nightly -y - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - if "%TARGET%"=="i686-pc-windows-msvc" ( rustup target add %TARGET% ) @@ -18,4 +18,6 @@ test_script: - cargo build --target %TARGET% - cargo build --release --target %TARGET% - cargo test --no-default-features --features gen-tests --target %TARGET% + - cargo test --no-default-features --features "gen-tests c" --target %TARGET% - cargo test --no-default-features --features gen-tests --release --target %TARGET% + - cargo test --no-default-features --features "gen-tests c" --release --target %TARGET% diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 4a28e8a1894b5..02b9bf11248f3 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -34,7 +34,9 @@ case $1 in ;; *) cargo test --no-default-features --features gen-tests --target $1 + cargo test --no-default-features --features 'gen-tests c' --target $1 cargo test --no-default-features --features gen-tests --target $1 --release + cargo test --no-default-features --features 'gen-tests c' --target $1 --release ;; esac diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 4c5c8842bb9ec..4015ac318a284 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -6,17 +6,17 @@ #![allow(unused_features)] #![cfg_attr(thumb, no_main)] #![deny(dead_code)] +#![feature(alloc_system)] #![feature(asm)] #![feature(compiler_builtins_lib)] #![feature(core_float)] #![feature(lang_items)] -#![feature(libc)] #![feature(start)] #![feature(i128_type)] #![no_std] #[cfg(not(thumb))] -extern crate libc; +extern crate alloc_system; extern crate compiler_builtins; // NOTE cfg(not(thumbv6m)) means that the operation is not supported on ARMv6-M at all. Not even @@ -27,7 +27,6 @@ extern crate compiler_builtins; // convention for its intrinsics that's different from other architectures; that's why some function // have an additional comment: the function name is the ARM name for the intrinsic and the comment // in the non-ARM name for the intrinsic. -#[cfg(feature = "c")] mod intrinsics { use core::num::Float; @@ -339,7 +338,6 @@ mod intrinsics { } } -#[cfg(feature = "c")] fn run() { use intrinsics::*; @@ -404,33 +402,20 @@ fn run() { bb(modti3(bb(2), bb(2))); } -#[cfg(all(feature = "c", not(thumb)))] +#[cfg(not(thumb))] #[start] fn main(_: isize, _: *const *const u8) -> isize { run(); - - 0 -} - -#[cfg(all(not(feature = "c"), not(thumb)))] -#[start] -fn main(_: isize, _: *const *const u8) -> isize { 0 } -#[cfg(all(feature = "c", thumb))] +#[cfg(thumb)] #[no_mangle] pub fn _start() -> ! { run(); loop {} } -#[cfg(all(not(feature = "c"), thumb))] -#[no_mangle] -pub fn _start() -> ! { - loop {} -} - // ARM targets need these symbols #[no_mangle] pub fn __aeabi_unwind_cpp_pr0() {} @@ -447,9 +432,11 @@ pub fn _Unwind_Resume() {} #[cfg(not(test))] #[lang = "eh_personality"] #[no_mangle] +#[allow(private_no_mangle_fns)] extern "C" fn eh_personality() {} #[cfg(not(test))] #[lang = "panic_fmt"] #[no_mangle] +#[allow(private_no_mangle_fns)] extern "C" fn panic_fmt() {} From bd4a416457b75b7d717ac7e3ebe71c39903d41e5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 22 Jun 2017 22:03:07 -0700 Subject: [PATCH 0310/4206] Use traits instead of macros for shift intrinsics This is an attempt to tidy up the definition of intrinsics by making them more rust-like at the definition site and using traits instead of macros for the definition. Additionally the helper macro, `intrinsics!`, now fills in a definition for #[cfg]'d off intrinsics when compiling with C code --- library/compiler-builtins/src/int/mod.rs | 43 ++++++- library/compiler-builtins/src/int/shift.rs | 130 ++++++++++++--------- library/compiler-builtins/src/lib.rs | 3 + library/compiler-builtins/src/macros.rs | 51 ++++++++ 4 files changed, 166 insertions(+), 61 deletions(-) create mode 100644 library/compiler-builtins/src/macros.rs diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 768b6b4c18f77..11a31acee546c 100755 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -1,3 +1,5 @@ +use core::ops; + macro_rules! hty { ($ty:ty) => { <$ty as LargeInt>::HighHalf @@ -16,15 +18,25 @@ pub mod shift; pub mod udiv; /// Trait for some basic operations on integers -pub trait Int { +pub trait Int: + Copy + + PartialEq + + ops::Shl + + ops::Shr + + ops::BitOr + + // ops::BitAnd + +{ /// Type with the same width but other signedness - type OtherSign; + type OtherSign: Int; /// Unsigned version of Self - type UnsignedInt; + type UnsignedInt: Int; /// Returns the bitwidth of the int type fn bits() -> u32; + /// Returns the zero representation of this number + fn zero() -> Self; + /// Extracts the sign from self and returns a tuple. /// /// # Examples @@ -36,6 +48,9 @@ pub trait Int { /// assert_eq!(u, 25_u32); /// ``` fn extract_sign(self) -> (bool, Self::UnsignedInt); + + /// Convert to a signed representation + fn unsigned(self) -> Self::UnsignedInt; } macro_rules! int_impl { @@ -44,6 +59,10 @@ macro_rules! int_impl { type OtherSign = $ity; type UnsignedInt = $uty; + fn zero() -> Self { + 0 + } + fn bits() -> u32 { $bits } @@ -51,6 +70,10 @@ macro_rules! int_impl { fn extract_sign(self) -> (bool, $uty) { (false, self) } + + fn unsigned(self) -> $uty { + self + } } impl Int for $ity { @@ -61,6 +84,10 @@ macro_rules! int_impl { $bits } + fn zero() -> Self { + 0 + } + fn extract_sign(self) -> (bool, $uty) { if self < 0 { (true, (!(self as $uty)).wrapping_add(1)) @@ -68,6 +95,10 @@ macro_rules! int_impl { (false, self as $uty) } } + + fn unsigned(self) -> $uty { + self as $uty + } } } } @@ -77,9 +108,9 @@ int_impl!(i64, u64, 64); int_impl!(i128, u128, 128); /// Trait to convert an integer to/from smaller parts -pub trait LargeInt { - type LowHalf; - type HighHalf; +pub trait LargeInt: Int { + type LowHalf: Int; + type HighHalf: Int; fn low(self) -> Self::LowHalf; fn high(self) -> Self::HighHalf; diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 8b5c4a16eaa46..23a49acb9070c 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -1,74 +1,94 @@ use int::{Int, LargeInt}; -macro_rules! ashl { - ($intrinsic:ident: $ty:ty) => { - /// Returns `a << b`, requires `b < $ty::bits()` - #[cfg_attr(not(test), no_mangle)] - #[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] - #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] - pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { - let half_bits = <$ty>::bits() / 2; - if b & half_bits != 0 { - <$ty>::from_parts(0, a.low() << (b - half_bits)) - } else if b == 0 { - a - } else { - <$ty>::from_parts(a.low() << b, (a.high() << b) | (a.low() >> (half_bits - b))) - } +trait Ashl: Int + LargeInt { + /// Returns `a << b`, requires `b < $ty::bits()` + fn ashl(self, offset: u32) -> Self + where Self: LargeInt::LowHalf>, + { + let half_bits = Self::bits() / 2; + if offset & half_bits != 0 { + Self::from_parts(Int::zero(), self.low() << (offset - half_bits)) + } else if offset == 0 { + self + } else { + Self::from_parts(self.low() << offset, + (self.high() << offset) | + (self.low() >> (half_bits - offset))) } } } -macro_rules! ashr { - ($intrinsic:ident: $ty:ty) => { - /// Returns arithmetic `a >> b`, requires `b < $ty::bits()` - #[cfg_attr(not(test), no_mangle)] - #[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] - #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] - pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { - let half_bits = <$ty>::bits() / 2; - if b & half_bits != 0 { - <$ty>::from_parts((a.high() >> (b - half_bits)) as <$ty as LargeInt>::LowHalf, - a.high() >> (half_bits - 1)) - } else if b == 0 { - a - } else { - let high_unsigned = a.high() as <$ty as LargeInt>::LowHalf; - <$ty>::from_parts((high_unsigned << (half_bits - b)) | (a.low() >> b), - a.high() >> b) - } +impl Ashl for u64 {} +impl Ashl for u128 {} + +trait Ashr: Int + LargeInt { + /// Returns arithmetic `a >> b`, requires `b < $ty::bits()` + fn ashr(self, offset: u32) -> Self + where Self: LargeInt::HighHalf as Int>::UnsignedInt>, + { + let half_bits = Self::bits() / 2; + if offset & half_bits != 0 { + Self::from_parts((self.high() >> (offset - half_bits)).unsigned(), + self.high() >> (half_bits - 1)) + } else if offset == 0 { + self + } else { + let high_unsigned = self.high().unsigned(); + Self::from_parts((high_unsigned << (half_bits - offset)) | (self.low() >> offset), + self.high() >> offset) } } } -macro_rules! lshr { - ($intrinsic:ident: $ty:ty) => { - /// Returns logical `a >> b`, requires `b < $ty::bits()` - #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { - let half_bits = <$ty>::bits() / 2; - if b & half_bits != 0 { - <$ty>::from_parts(a.high() >> (b - half_bits), 0) - } else if b == 0 { - a - } else { - <$ty>::from_parts((a.high() << (half_bits - b)) | (a.low() >> b), a.high() >> b) - } +impl Ashr for i64 {} +impl Ashr for i128 {} + +trait Lshr: Int + LargeInt { + /// Returns logical `a >> b`, requires `b < $ty::bits()` + fn lshr(self, offset: u32) -> Self + where Self: LargeInt::LowHalf>, + { + let half_bits = Self::bits() / 2; + if offset & half_bits != 0 { + Self::from_parts(self.high() >> (offset - half_bits), Int::zero()) + } else if offset == 0 { + self + } else { + Self::from_parts((self.high() << (half_bits - offset)) | + (self.low() >> offset), + self.high() >> offset) } } } -#[cfg(not(all(feature = "c", target_arch = "x86")))] -ashl!(__ashldi3: u64); +impl Lshr for u64 {} +impl Lshr for u128 {} -ashl!(__ashlti3: u128); +intrinsics! { + #[cfg(not(all(feature = "c", target_arch = "x86")))] + pub extern "C" fn __ashldi3(a: u64, b: u32) -> u64 { + a.ashl(b) + } + + pub extern "C" fn __ashlti3(a: u128, b: u32) -> u128 { + a.ashl(b) + } -#[cfg(not(all(feature = "c", target_arch = "x86")))] -ashr!(__ashrdi3: i64); + #[cfg(not(all(feature = "c", target_arch = "x86")))] + pub extern "C" fn __ashrdi3(a: i64, b: u32) -> i64 { + a.ashr(b) + } -ashr!(__ashrti3: i128); + pub extern "C" fn __ashrti3(a: i128, b: u32) -> i128 { + a.ashr(b) + } -#[cfg(not(all(feature = "c", target_arch = "x86")))] -lshr!(__lshrdi3: u64); + #[cfg(not(all(feature = "c", target_arch = "x86")))] + pub extern "C" fn __lshrdi3(a: u64, b: u32) -> u64 { + a.lshr(b) + } -lshr!(__lshrti3: u128); + pub extern "C" fn __lshrti3(a: u128, b: u32) -> u128 { + a.lshr(b) + } +} diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 03f7258d13e79..b1e739ffe1e62 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -99,6 +99,9 @@ fn sconv(i: i128) -> U64x2 { #[cfg(test)] extern crate core; +#[macro_use] +mod macros; + pub mod int; pub mod float; diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs new file mode 100644 index 0000000000000..a5a535bc56cb1 --- /dev/null +++ b/library/compiler-builtins/src/macros.rs @@ -0,0 +1,51 @@ +macro_rules! intrinsics { + () => (); + ( + #[cfg(not(all(feature = "c", $($cfg_clause:tt)*)))] + $(#[$attr:meta])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + + #[cfg(all(feature = "c", not($($cfg_clause)*)))] + $(#[$attr])* + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + extern $abi { + fn $name($($argname: $ty),*) -> $ret; + } + unsafe { + $name($($argname),*) + } + } + + #[cfg(not(all(feature = "c", not($($cfg_clause)*))))] + intrinsics! { + $(#[$attr])* + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + + ( + $(#[$attr:meta])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + $(#[$attr])* + #[cfg_attr(not(test), no_mangle)] + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + $($body)* + } + + intrinsics!($($rest)*); + ); +} From 13d1c5ce1835e258c97599ed40e2d3af7eccfc92 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 22 Jun 2017 22:04:40 -0700 Subject: [PATCH 0311/4206] Remove executable bit from mod.rs --- library/compiler-builtins/src/int/mod.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 library/compiler-builtins/src/int/mod.rs diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs old mode 100755 new mode 100644 From 285a69b29cd4b2f40c954cffcc72c711c3291530 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 22 Jun 2017 22:36:37 -0700 Subject: [PATCH 0312/4206] Port mul intrinsics to traits Also add a few features to the `intrinsics!` macro --- library/compiler-builtins/src/int/mod.rs | 68 +++++++++- library/compiler-builtins/src/int/mul.rs | 153 ++++++++++++----------- library/compiler-builtins/src/macros.rs | 66 ++++++++++ 3 files changed, 208 insertions(+), 79 deletions(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 11a31acee546c..02e34129612c4 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -20,11 +20,19 @@ pub mod udiv; /// Trait for some basic operations on integers pub trait Int: Copy + - PartialEq + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::Add + + ops::Sub + + ops::Div + ops::Shl + ops::Shr + ops::BitOr + - // ops::BitAnd + + ops::BitXor + + ops::BitAnd + + ops::BitAndAssign + + ops::Not + { /// Type with the same width but other signedness type OtherSign: Int; @@ -34,8 +42,8 @@ pub trait Int: /// Returns the bitwidth of the int type fn bits() -> u32; - /// Returns the zero representation of this number fn zero() -> Self; + fn one() -> Self; /// Extracts the sign from self and returns a tuple. /// @@ -51,6 +59,12 @@ pub trait Int: /// Convert to a signed representation fn unsigned(self) -> Self::UnsignedInt; + + // copied from primitive integers, but put in a trait + fn max_value() -> Self; + fn min_value() -> Self; + fn wrapping_add(self, other: Self) -> Self; + fn wrapping_mul(self, other: Self) -> Self; } macro_rules! int_impl { @@ -63,6 +77,10 @@ macro_rules! int_impl { 0 } + fn one() -> Self { + 1 + } + fn bits() -> u32 { $bits } @@ -74,6 +92,22 @@ macro_rules! int_impl { fn unsigned(self) -> $uty { self } + + fn max_value() -> Self { + ::max_value() + } + + fn min_value() -> Self { + ::min_value() + } + + fn wrapping_add(self, other: Self) -> Self { + ::wrapping_add(self, other) + } + + fn wrapping_mul(self, other: Self) -> Self { + ::wrapping_mul(self, other) + } } impl Int for $ity { @@ -88,6 +122,10 @@ macro_rules! int_impl { 0 } + fn one() -> Self { + 1 + } + fn extract_sign(self) -> (bool, $uty) { if self < 0 { (true, (!(self as $uty)).wrapping_add(1)) @@ -99,6 +137,22 @@ macro_rules! int_impl { fn unsigned(self) -> $uty { self as $uty } + + fn max_value() -> Self { + ::max_value() + } + + fn min_value() -> Self { + ::min_value() + } + + fn wrapping_add(self, other: Self) -> Self { + ::wrapping_add(self, other) + } + + fn wrapping_mul(self, other: Self) -> Self { + ::wrapping_mul(self, other) + } } } } @@ -113,7 +167,9 @@ pub trait LargeInt: Int { type HighHalf: Int; fn low(self) -> Self::LowHalf; + fn low_as_high(low: Self::LowHalf) -> Self::HighHalf; fn high(self) -> Self::HighHalf; + fn high_as_low(low: Self::HighHalf) -> Self::LowHalf; fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self; } @@ -126,9 +182,15 @@ macro_rules! large_int { fn low(self) -> $tylow { self as $tylow } + fn low_as_high(low: $tylow) -> $tyhigh { + low as $tyhigh + } fn high(self) -> $tyhigh { (self >> $halfbits) as $tyhigh } + fn high_as_low(high: $tyhigh) -> $tylow { + high as $tylow + } fn from_parts(low: $tylow, high: $tyhigh) -> $ty { low as $ty | ((high as $ty) << $halfbits) } diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 5381eddea41ea..73f95a361da26 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -1,95 +1,96 @@ +use core::ops; + use int::LargeInt; use int::Int; -macro_rules! mul { - ($(#[$attr:meta])+ | - $abi:tt, $intrinsic:ident: $ty:ty) => { - /// Returns `a * b` - $(#[$attr])+ - pub extern $abi fn $intrinsic(a: $ty, b: $ty) -> $ty { - let half_bits = <$ty>::bits() / 4; - let lower_mask = !0 >> half_bits; - let mut low = (a.low() & lower_mask).wrapping_mul(b.low() & lower_mask); - let mut t = low >> half_bits; - low &= lower_mask; - t += (a.low() >> half_bits).wrapping_mul(b.low() & lower_mask); - low += (t & lower_mask) << half_bits; - let mut high = (t >> half_bits) as hty!($ty); - t = low >> half_bits; - low &= lower_mask; - t += (b.low() >> half_bits).wrapping_mul(a.low() & lower_mask); - low += (t & lower_mask) << half_bits; - high += (t >> half_bits) as hty!($ty); - high += (a.low() >> half_bits).wrapping_mul(b.low() >> half_bits) as hty!($ty); - high = high.wrapping_add(a.high().wrapping_mul(b.low() as hty!($ty))) - .wrapping_add((a.low() as hty!($ty)).wrapping_mul(b.high())); - <$ty>::from_parts(low, high) - } +trait Mul: LargeInt { + fn mul(self, other: Self) -> Self { + let half_bits = Self::bits() / 4; + let lower_mask = !<::LowHalf>::zero() >> half_bits; + let mut low = (self.low() & lower_mask).wrapping_mul(other.low() & lower_mask); + let mut t = low >> half_bits; + low &= lower_mask; + t += (self.low() >> half_bits).wrapping_mul(other.low() & lower_mask); + low += (t & lower_mask) << half_bits; + let mut high = Self::low_as_high(t >> half_bits); + t = low >> half_bits; + low &= lower_mask; + t += (other.low() >> half_bits).wrapping_mul(self.low() & lower_mask); + low += (t & lower_mask) << half_bits; + high += Self::low_as_high(t >> half_bits); + high += Self::low_as_high((self.low() >> half_bits).wrapping_mul(other.low() >> half_bits)); + high = high.wrapping_add(self.high().wrapping_mul(Self::low_as_high(other.low()))) + .wrapping_add(Self::low_as_high(self.low()).wrapping_mul(other.high())); + Self::from_parts(low, high) } } -macro_rules! mulo { - ($intrinsic:ident: $ty:ty) => { - // Default is "C" ABI - mulo!($intrinsic: $ty, "C"); - }; - ($intrinsic:ident: $ty:ty, $abi:tt) => { - /// Returns `a * b` and sets `*overflow = 1` if `a * b` overflows - #[cfg_attr(not(test), no_mangle)] - pub extern $abi fn $intrinsic(a: $ty, b: $ty, overflow: &mut i32) -> $ty { - *overflow = 0; - let result = a.wrapping_mul(b); - if a == <$ty>::min_value() { - if b != 0 && b != 1 { - *overflow = 1; - } - return result; +impl Mul for u64 {} +impl Mul for i128 {} + +trait Mulo: Int + ops::Neg { + fn mulo(self, other: Self, overflow: &mut i32) -> Self { + *overflow = 0; + let result = self.wrapping_mul(other); + if self == Self::min_value() { + if other != Self::zero() && other != Self::one() { + *overflow = 1; } - if b == <$ty>::min_value() { - if a != 0 && a != 1 { - *overflow = 1; - } - return result; + return result; + } + if other == Self::min_value() { + if self != Self::zero() && self != Self::one() { + *overflow = 1; } + return result; + } - let sa = a >> (<$ty>::bits() - 1); - let abs_a = (a ^ sa) - sa; - let sb = b >> (<$ty>::bits() - 1); - let abs_b = (b ^ sb) - sb; - if abs_a < 2 || abs_b < 2 { - return result; + let sa = self >> (Self::bits() - 1); + let abs_a = (self ^ sa) - sa; + let sb = other >> (Self::bits() - 1); + let abs_b = (other ^ sb) - sb; + let two = Self::one() + Self::one(); + if abs_a < two || abs_b < two { + return result; + } + if sa == sb { + if abs_a > Self::max_value() / abs_b { + *overflow = 1; } - if sa == sb { - if abs_a > <$ty>::max_value() / abs_b { - *overflow = 1; - } - } else { - if abs_a > <$ty>::min_value() / -abs_b { - *overflow = 1; - } + } else { + if abs_a > Self::min_value() / -abs_b { + *overflow = 1; } - result } + result } } -#[cfg(not(all(feature = "c", target_arch = "x86")))] -mul!(#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] - #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] - | "C", __muldi3: u64); +impl Mulo for i32 {} +impl Mulo for i64 {} +impl Mulo for i128 {} -#[cfg(not(target_arch = "arm"))] -mul!(#[cfg_attr(not(test), no_mangle)] - | "C", __multi3: i128); +intrinsics! { + #[cfg(not(all(feature = "c", target_arch = "x86")))] + pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 { + a.mul(b) + } -#[cfg(target_arch = "arm")] -mul!(#[cfg_attr(not(test), no_mangle)] - | "aapcs", __multi3: i128); + #[aapcs_on_arm] + pub extern "C" fn __multi3(a: i128, b: i128) -> i128 { + a.mul(b) + } + + pub extern "C" fn __mulosi4(a: i32, b: i32, oflow: &mut i32) -> i32 { + a.mulo(b, oflow) + } -mulo!(__mulosi4: i32); -mulo!(__mulodi4: i64); + pub extern "C" fn __mulodi4(a: i64, b: i64, oflow: &mut i32) -> i64 { + a.mulo(b, oflow) + } -#[cfg(all(windows, target_pointer_width="64"))] -mulo!(__muloti4: i128, "unadjusted"); -#[cfg(not(all(windows, target_pointer_width="64")))] -mulo!(__muloti4: i128); + #[unadjusted_on_win64] + pub extern "C" fn __muloti4(a: i128, b: i128, oflow: &mut i32) -> i128 { + a.mulo(b, oflow) + } +} diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index a5a535bc56cb1..c0c94b7db722e 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -1,5 +1,10 @@ macro_rules! intrinsics { () => (); + + // Anything which has a `not(feature = "c")` we'll generate a shim function + // which calls out to the C function if the `c` feature is enabled. + // Otherwise if the `c` feature isn't enabled then we'll just have a normal + // intrinsic. ( #[cfg(not(all(feature = "c", $($cfg_clause:tt)*)))] $(#[$attr:meta])* @@ -32,6 +37,67 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); + // We recognize the `#[aapcs_only_on_arm]` attribute here and generate the + // same intrinsic but force it to have the `"aapcs"` calling convention on + // ARM and `"C"` elsewhere. + ( + #[aapcs_on_arm] + $(#[$attr:meta])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(target_arch = "arm")] + intrinsics! { + $(#[$attr])* + pub extern "aapcs" fn $name( $($argname: $ty),* ) -> $ret { + $($body)* + } + } + + #[cfg(not(target_arch = "arm"))] + intrinsics! { + $(#[$attr])* + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + + // Like aapcs above we recognize an attribute for the "unadjusted" abi on + // win64 for some methods. + ( + #[unadjusted_on_win64] + $(#[$attr:meta])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(all(windows, target_pointer_width = "64"))] + intrinsics! { + $(#[$attr])* + pub extern "unadjusted" fn $name( $($argname: $ty),* ) -> $ret { + $($body)* + } + } + + #[cfg(not(all(windows, target_pointer_width = "64")))] + intrinsics! { + $(#[$attr])* + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + ( $(#[$attr:meta])* pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { From e80da4a48a8d02541bd2c221810ecfa002aa5626 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 22 Jun 2017 23:09:28 -0700 Subject: [PATCH 0313/4206] Port sdiv to traits + `intrinsics!` Enhance `intrinsics!` along the way! --- library/compiler-builtins/src/int/mod.rs | 37 ++++- library/compiler-builtins/src/int/mul.rs | 2 +- library/compiler-builtins/src/int/sdiv.rs | 165 ++++++++++----------- library/compiler-builtins/src/int/shift.rs | 6 +- library/compiler-builtins/src/lib.rs | 4 + library/compiler-builtins/src/macros.rs | 59 +++++++- 6 files changed, 183 insertions(+), 90 deletions(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 02e34129612c4..9ad3d88852fb8 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -57,14 +57,17 @@ pub trait Int: /// ``` fn extract_sign(self) -> (bool, Self::UnsignedInt); - /// Convert to a signed representation fn unsigned(self) -> Self::UnsignedInt; + fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; // copied from primitive integers, but put in a trait fn max_value() -> Self; fn min_value() -> Self; fn wrapping_add(self, other: Self) -> Self; fn wrapping_mul(self, other: Self) -> Self; + fn wrapping_sub(self, other: Self) -> Self; + fn checked_div(self, other: Self) -> Option; + fn checked_rem(self, other: Self) -> Option; } macro_rules! int_impl { @@ -93,6 +96,10 @@ macro_rules! int_impl { self } + fn from_unsigned(me: $uty) -> Self { + me + } + fn max_value() -> Self { ::max_value() } @@ -108,6 +115,18 @@ macro_rules! int_impl { fn wrapping_mul(self, other: Self) -> Self { ::wrapping_mul(self, other) } + + fn wrapping_sub(self, other: Self) -> Self { + ::wrapping_sub(self, other) + } + + fn checked_div(self, other: Self) -> Option { + ::checked_div(self, other) + } + + fn checked_rem(self, other: Self) -> Option { + ::checked_rem(self, other) + } } impl Int for $ity { @@ -138,6 +157,10 @@ macro_rules! int_impl { self as $uty } + fn from_unsigned(me: $uty) -> Self { + me as $ity + } + fn max_value() -> Self { ::max_value() } @@ -153,6 +176,18 @@ macro_rules! int_impl { fn wrapping_mul(self, other: Self) -> Self { ::wrapping_mul(self, other) } + + fn wrapping_sub(self, other: Self) -> Self { + ::wrapping_sub(self, other) + } + + fn checked_div(self, other: Self) -> Option { + ::checked_div(self, other) + } + + fn checked_rem(self, other: Self) -> Option { + ::checked_rem(self, other) + } } } } diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 73f95a361da26..4b0831d8ee5ba 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -71,7 +71,7 @@ impl Mulo for i64 {} impl Mulo for i128 {} intrinsics! { - #[cfg(not(all(feature = "c", target_arch = "x86")))] + #[use_c_shim_if(target_arch = "x86")] pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 { a.mul(b) } diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 557689814f629..310eb9f82fc4f 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -1,102 +1,101 @@ use int::Int; -macro_rules! div { - ($intrinsic:ident: $ty:ty, $uty:ty) => { - div!($intrinsic: $ty, $uty, $ty, |i| {i}); - }; - ($intrinsic:ident: $ty:ty, $uty:ty, $tyret:ty, $conv:expr) => { - /// Returns `a / b` - #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $tyret { - let s_a = a >> (<$ty>::bits() - 1); - let s_b = b >> (<$ty>::bits() - 1); - // NOTE it's OK to overflow here because of the `as $uty` cast below - // This whole operation is computing the absolute value of the inputs - // So some overflow will happen when dealing with e.g. `i64::MIN` - // where the absolute value is `(-i64::MIN) as u64` - let a = (a ^ s_a).wrapping_sub(s_a); - let b = (b ^ s_b).wrapping_sub(s_b); - let s = s_a ^ s_b; - - let r = udiv!(a as $uty, b as $uty); - ($conv)((r as $ty ^ s) - s) - } +trait Div: Int { + /// Returns `a / b` + fn div(self, other: Self) -> Self { + let s_a = self >> (Self::bits() - 1); + let s_b = other >> (Self::bits() - 1); + // NOTE it's OK to overflow here because of the `as $uty` cast below + // This whole operation is computing the absolute value of the inputs + // So some overflow will happen when dealing with e.g. `i64::MIN` + // where the absolute value is `(-i64::MIN) as u64` + let a = (self ^ s_a).wrapping_sub(s_a); + let b = (other ^ s_b).wrapping_sub(s_b); + let s = s_a ^ s_b; + + let r = a.unsigned().checked_div(b.unsigned()) + .unwrap_or_else(|| ::abort()); + (Self::from_unsigned(r) ^ s) - s } } -macro_rules! mod_ { - ($intrinsic:ident: $ty:ty, $uty:ty) => { - mod_!($intrinsic: $ty, $uty, $ty, |i| {i}); - }; - ($intrinsic:ident: $ty:ty, $uty:ty, $tyret:ty, $conv:expr) => { - /// Returns `a % b` - #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $tyret { - let s = b >> (<$ty>::bits() - 1); - // NOTE(wrapping_sub) see comment in the `div` macro - let b = (b ^ s).wrapping_sub(s); - let s = a >> (<$ty>::bits() - 1); - let a = (a ^ s).wrapping_sub(s); - - let r = urem!(a as $uty, b as $uty); - ($conv)((r as $ty ^ s) - s) - } +impl Div for i32 {} +impl Div for i64 {} +impl Div for i128 {} + +trait Mod: Int { + /// Returns `a % b` + fn mod_(self, other: Self) -> Self { + let s = other >> (Self::bits() - 1); + // NOTE(wrapping_sub) see comment in the `div` + let b = (other ^ s).wrapping_sub(s); + let s = self >> (Self::bits() - 1); + let a = (self ^ s).wrapping_sub(s); + + let r = a.unsigned().checked_rem(b.unsigned()) + .unwrap_or_else(|| ::abort()); + (Self::from_unsigned(r) ^ s) - s } } -macro_rules! divmod { - ($abi:tt, $intrinsic:ident, $div:ident: $ty:ty) => { - /// Returns `a / b` and sets `*rem = n % d` - #[cfg_attr(not(test), no_mangle)] - pub extern $abi fn $intrinsic(a: $ty, b: $ty, rem: &mut $ty) -> $ty { - #[cfg(all(feature = "c", any(target_arch = "x86")))] - extern { - fn $div(a: $ty, b: $ty) -> $ty; - } - - let r = match () { - #[cfg(not(all(feature = "c", any(target_arch = "x86"))))] - () => $div(a, b), - #[cfg(all(feature = "c", any(target_arch = "x86")))] - () => unsafe { $div(a, b) }, - }; - // NOTE won't overflow because it's using the result from the - // previous division - *rem = a - r.wrapping_mul(b); - r - } +impl Mod for i32 {} +impl Mod for i64 {} +impl Mod for i128 {} + +trait Divmod: Int { + /// Returns `a / b` and sets `*rem = n % d` + fn divmod(self, other: Self, rem: &mut Self, div: F) -> Self + where F: Fn(Self, Self) -> Self, + { + let r = div(self, other); + // NOTE won't overflow because it's using the result from the + // previous division + *rem = self - r.wrapping_mul(other); + r } } -#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] -div!(__divsi3: i32, u32); +impl Divmod for i32 {} +impl Divmod for i64 {} -#[cfg(not(all(feature = "c", target_arch = "x86")))] -div!(__divdi3: i64, u64); - -#[cfg(not(all(windows, target_pointer_width="64")))] -div!(__divti3: i128, u128); - -#[cfg(all(windows, target_pointer_width="64"))] -div!(__divti3: i128, u128, ::U64x2, ::sconv); +intrinsics! { + #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), not(thumbv6m)))] + pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 { + a.div(b) + } -#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] -mod_!(__modsi3: i32, u32); + #[use_c_shim_if(target_arch = "x86")] + pub extern "C" fn __divdi3(a: i64, b: i64) -> i64 { + a.div(b) + } -#[cfg(not(all(feature = "c", target_arch = "x86")))] -mod_!(__moddi3: i64, u64); + #[win64_128bit_abi_hack] + pub extern "C" fn __divti3(a: i128, b: i128) -> i128 { + a.div(b) + } -#[cfg(not(all(windows, target_pointer_width="64")))] -mod_!(__modti3: i128, u128); + #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios")))] + pub extern "C" fn __modsi3(a: i32, b: i32) -> i32 { + a.mod_(b) + } -#[cfg(all(windows, target_pointer_width="64"))] -mod_!(__modti3: i128, u128, ::U64x2, ::sconv); + #[use_c_shim_if(target_arch = "x86")] + pub extern "C" fn __moddi3(a: i64, b: i64) -> i64 { + a.mod_(b) + } -#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] -divmod!("C", __divmodsi4, __divsi3: i32); + #[win64_128bit_abi_hack] + pub extern "C" fn __modti3(a: i128, b: i128) -> i128 { + a.mod_(b) + } -#[cfg(target_arch = "arm")] -divmod!("aapcs", __divmoddi4, __divdi3: i64); + #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios")))] + pub extern "C" fn __divmodsi4(a: i32, b: i32, rem: &mut i32) -> i32 { + a.divmod(b, rem, |a, b| __divsi3(a, b)) + } -#[cfg(not(target_arch = "arm"))] -divmod!("C", __divmoddi4, __divdi3: i64); + #[aapcs_on_arm] + pub extern "C" fn __divmoddi4(a: i64, b: i64, rem: &mut i64) -> i64 { + a.divmod(b, rem, |a, b| __divdi3(a, b)) + } +} diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 23a49acb9070c..746d02ded8a55 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -65,7 +65,7 @@ impl Lshr for u64 {} impl Lshr for u128 {} intrinsics! { - #[cfg(not(all(feature = "c", target_arch = "x86")))] + #[use_c_shim_if(target_arch = "x86")] pub extern "C" fn __ashldi3(a: u64, b: u32) -> u64 { a.ashl(b) } @@ -74,7 +74,7 @@ intrinsics! { a.ashl(b) } - #[cfg(not(all(feature = "c", target_arch = "x86")))] + #[use_c_shim_if(target_arch = "x86")] pub extern "C" fn __ashrdi3(a: i64, b: u32) -> i64 { a.ashr(b) } @@ -83,7 +83,7 @@ intrinsics! { a.ashr(b) } - #[cfg(not(all(feature = "c", target_arch = "x86")))] + #[use_c_shim_if(target_arch = "x86")] pub extern "C" fn __lshrdi3(a: u64, b: u32) -> u64 { a.lshr(b) } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index b1e739ffe1e62..a55752a68ed8b 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -99,6 +99,10 @@ fn sconv(i: i128) -> U64x2 { #[cfg(test)] extern crate core; +fn abort() -> ! { + unsafe { core::intrinsics::abort() } +} + #[macro_use] mod macros; diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index c0c94b7db722e..5c98774070146 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -6,7 +6,7 @@ macro_rules! intrinsics { // Otherwise if the `c` feature isn't enabled then we'll just have a normal // intrinsic. ( - #[cfg(not(all(feature = "c", $($cfg_clause:tt)*)))] + #[use_c_shim_if($($cfg_clause:tt)*)] $(#[$attr:meta])* pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { $($body:tt)* @@ -37,7 +37,7 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); - // We recognize the `#[aapcs_only_on_arm]` attribute here and generate the + // We recognize the `#[aapcs_on_arm]` attribute here and generate the // same intrinsic but force it to have the `"aapcs"` calling convention on // ARM and `"C"` elsewhere. ( @@ -98,6 +98,39 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); + // Another attribute we recognize is an "abi hack" for win64 to get the 128 + // bit calling convention correct. + ( + #[win64_128bit_abi_hack] + $(#[$attr:meta])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(all(windows, target_pointer_width = "64"))] + intrinsics! { + $(#[$attr])* + pub extern $abi fn $name( $($argname: $ty),* ) + -> ::macros::win64_abi_hack::U64x2 + { + let e: $ret = { $($body)* }; + ::macros::win64_abi_hack::U64x2::from(e) + } + } + + #[cfg(not(all(windows, target_pointer_width = "64")))] + intrinsics! { + $(#[$attr])* + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + ( $(#[$attr:meta])* pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { @@ -115,3 +148,25 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); } + +// Hack for LLVM expectations for ABI on windows +#[cfg(all(windows, target_pointer_width="64"))] +pub mod win64_abi_hack { + #[repr(simd)] + pub struct U64x2(u64, u64); + + impl From for U64x2 { + fn from(i: i128) -> U64x2 { + use int::LargeInt; + let j = i as u128; + U64x2(j.low(), j.high()) + } + } + + impl From for U64x2 { + fn from(i: u128) -> U64x2 { + use int::LargeInt; + U64x2(i.low(), i.high()) + } + } +} From dd059dd1fc724428c4d75d991f2921875c1d000c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 22 Jun 2017 23:23:36 -0700 Subject: [PATCH 0314/4206] Port udiv to the `intrinsics!` macro --- library/compiler-builtins/src/int/udiv.rs | 268 +++++++++------------- 1 file changed, 112 insertions(+), 156 deletions(-) diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index e8db7460125e9..5ef46dec4216d 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -1,140 +1,6 @@ use core::intrinsics; -use int::{Int, LargeInt}; - -/// Returns `n / d` -#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] -#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] -#[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] -pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { - // Special cases - if d == 0 { - // NOTE This should be unreachable in safe Rust because the program will panic before - // this intrinsic is called - unsafe { - intrinsics::abort() - } - } - - if n == 0 { - return 0; - } - - let mut sr = d.leading_zeros().wrapping_sub(n.leading_zeros()); - - // d > n - if sr > u32::bits() - 1 { - return 0; - } - - // d == 1 - if sr == u32::bits() - 1 { - return n; - } - - sr += 1; - - // 1 <= sr <= u32::bits() - 1 - let mut q = n << (u32::bits() - sr); - let mut r = n >> sr; - - let mut carry = 0; - for _ in 0..sr { - // r:q = ((r:q) << 1) | carry - r = (r << 1) | (q >> (u32::bits() - 1)); - q = (q << 1) | carry; - - // carry = 0; - // if r > d { - // r -= d; - // carry = 1; - // } - let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32::bits() - 1); - carry = (s & 1) as u32; - r -= d & s as u32; - } - - (q << 1) | carry -} - -/// Returns `n % d` -#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] -#[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { - #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios")))] - extern "C" { - fn __udivsi3(n: u32, d: u32) -> u32; - } - - let q = match () { - #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios")))] - () => unsafe { __udivsi3(n, d) }, - #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))] - () => __udivsi3(n, d), - }; - - n - q * d -} - -/// Returns `n / d` and sets `*rem = n % d` -#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] -#[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { - #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m)))] - extern "C" { - fn __udivsi3(n: u32, d: u32) -> u32; - } - - let q = match () { - #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m)))] - () => unsafe { __udivsi3(n, d) }, - #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] - () => __udivsi3(n, d), - }; - if let Some(rem) = rem { - *rem = n - (q * d); - } - q -} - -macro_rules! div_mod_intrinsics { - ($udiv_intr:ident, $umod_intr:ident : $ty:ty) => { - div_mod_intrinsics!($udiv_intr, $umod_intr : $ty, - __udivmoddi4); - }; - ($udiv_intr:ident, $umod_intr:ident : $ty:ty, $divmod_intr:expr) => { - div_mod_intrinsics!($udiv_intr, $umod_intr : $ty, - $divmod_intr, $ty, |i|{ i }); - }; - ($udiv_intr:ident, $umod_intr:ident : $ty:ty, $divmod_intr:expr, - $tyret:ty, $conv:expr) => { - /// Returns `n / d` - #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $udiv_intr(n: $ty, d: $ty) -> $tyret { - let r = $divmod_intr(n, d, None); - ($conv)(r) - } - - /// Returns `n % d` - #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $umod_intr(a: $ty, b: $ty) -> $tyret { - use core::mem; - - let mut rem = unsafe { mem::uninitialized() }; - $divmod_intr(a, b, Some(&mut rem)); - ($conv)(rem) - } - } -} - -#[cfg(not(all(feature = "c", target_arch = "x86")))] -div_mod_intrinsics!(__udivdi3, __umoddi3: u64); - -#[cfg(not(all(windows, target_pointer_width="64")))] -div_mod_intrinsics!(__udivti3, __umodti3: u128, u128_div_mod); - -#[cfg(all(windows, target_pointer_width="64"))] -div_mod_intrinsics!(__udivti3, __umodti3: u128, u128_div_mod, ::U64x2, ::conv); +use int::{Int, LargeInt}; macro_rules! udivmod_inner { ($n:expr, $d:expr, $rem:expr, $ty:ty) => {{ @@ -285,30 +151,120 @@ macro_rules! udivmod_inner { }} } -/// Returns `n / d` and sets `*rem = n % d` -#[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { - udivmod_inner!(n, d, rem, u64) -} +intrinsics! { + #[use_c_shim_if(all(target_arch = "arm", + not(target_os = "ios"), + not(thumbv6m)))] + /// Returns `n / d` + pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { + // Special cases + if d == 0 { + // NOTE This should be unreachable in safe Rust because the program will panic before + // this intrinsic is called + unsafe { + intrinsics::abort() + } + } + + if n == 0 { + return 0; + } + + let mut sr = d.leading_zeros().wrapping_sub(n.leading_zeros()); + + // d > n + if sr > u32::bits() - 1 { + return 0; + } + + // d == 1 + if sr == u32::bits() - 1 { + return n; + } + + sr += 1; + + // 1 <= sr <= u32::bits() - 1 + let mut q = n << (u32::bits() - sr); + let mut r = n >> sr; + + let mut carry = 0; + for _ in 0..sr { + // r:q = ((r:q) << 1) | carry + r = (r << 1) | (q >> (u32::bits() - 1)); + q = (q << 1) | carry; + + // carry = 0; + // if r > d { + // r -= d; + // carry = 1; + // } -macro_rules! udivmodti4 { - ($tyret:ty, $conv:expr) => { - /// Returns `n / d` and sets `*rem = n % d` - #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn __udivmodti4(n: u128, d: u128, rem: Option<&mut u128>) -> $tyret { - let r = u128_div_mod(n, d, rem); - ($conv)(r) + let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32::bits() - 1); + carry = (s & 1) as u32; + r -= d & s as u32; } + + (q << 1) | carry } -} -/// Returns `n / d` and sets `*rem = n % d` -fn u128_div_mod(n: u128, d: u128, rem: Option<&mut u128>) -> u128 { - udivmod_inner!(n, d, rem, u128) -} + #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios")))] + /// Returns `n % d` + pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { + let q = __udivsi3(n, d); + n - q * d + } + + #[use_c_shim_if(all(target_arch = "arm", + not(target_os = "ios"), + not(thumbv6m)))] + /// Returns `n / d` and sets `*rem = n % d` + pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { + let q = __udivsi3(n, d); + if let Some(rem) = rem { + *rem = n - (q * d); + } + q + } -#[cfg(all(windows, target_pointer_width="64"))] -udivmodti4!(::U64x2, ::conv); + #[use_c_shim_if(target_arch = "x86")] + /// Returns `n / d` + pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { + __udivmoddi4(n, d, None) + } -#[cfg(not(all(windows, target_pointer_width="64")))] -udivmodti4!(u128, |i|{ i }); + #[use_c_shim_if(target_arch = "x86")] + /// Returns `n % d` + pub extern "C" fn __umoddi3(n: u64, d: u64) -> u64 { + let mut rem = 0; + __udivmoddi4(n, d, Some(&mut rem)); + rem + } + + #[win64_128bit_abi_hack] + /// Returns `n / d` + pub extern "C" fn __udivti3(n: u128, d: u128) -> u128 { + __udivmodti4(n, d, None) + } + + #[win64_128bit_abi_hack] + /// Returns `n % d` + pub extern "C" fn __umodti3(n: u128, d: u128) -> u128 { + let mut rem = 0; + __udivmodti4(n, d, Some(&mut rem)); + rem + } + + /// Returns `n / d` and sets `*rem = n % d` + pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { + udivmod_inner!(n, d, rem, u64) + } + + #[win64_128bit_abi_hack] + /// Returns `n / d` and sets `*rem = n % d` + pub extern "C" fn __udivmodti4(n: u128, + d: u128, + rem: Option<&mut u128>) -> u128 { + udivmod_inner!(n, d, rem, u128) + } +} From 0d1138fad343291f4ea2e527904408d8a98a7694 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 22 Jun 2017 23:36:50 -0700 Subject: [PATCH 0315/4206] Fix the abi hack on windows --- library/compiler-builtins/src/lib.rs | 18 ------------------ library/compiler-builtins/src/macros.rs | 22 +++++++++++++++------- 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index a55752a68ed8b..6d44fb1a185e9 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -78,24 +78,6 @@ macro_rules! urem { } } -// Hack for LLVM expectations for ABI on windows -#[cfg(all(windows, target_pointer_width="64"))] -#[repr(simd)] -pub struct U64x2(u64, u64); - -#[cfg(all(windows, target_pointer_width="64"))] -fn conv(i: u128) -> U64x2 { - use int::LargeInt; - U64x2(i.low(), i.high()) -} - -#[cfg(all(windows, target_pointer_width="64"))] -fn sconv(i: i128) -> U64x2 { - use int::LargeInt; - let j = i as u128; - U64x2(j.low(), j.high()) -} - #[cfg(test)] extern crate core; diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 5c98774070146..70e44da59c1ec 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -110,13 +110,21 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( #[cfg(all(windows, target_pointer_width = "64"))] - intrinsics! { - $(#[$attr])* - pub extern $abi fn $name( $($argname: $ty),* ) - -> ::macros::win64_abi_hack::U64x2 - { - let e: $ret = { $($body)* }; - ::macros::win64_abi_hack::U64x2::from(e) + $(#[$attr])* + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + $($body)* + } + + #[cfg(all(windows, target_pointer_width = "64"))] + pub mod $name { + + intrinsics! { + pub extern $abi fn $name( $($argname: $ty),* ) + -> ::macros::win64_abi_hack::U64x2 + { + let e: $ret = super::$name($($argname),*); + ::macros::win64_abi_hack::U64x2::from(e) + } } } From 107cbd36a0c1e074ef69a76272ff8affc68824d9 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 22 Jun 2017 23:41:28 -0700 Subject: [PATCH 0316/4206] Try to fix linkage on windows --- library/compiler-builtins/examples/intrinsics.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 4015ac318a284..5336422a39ac6 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -416,6 +416,10 @@ pub fn _start() -> ! { loop {} } +#[cfg(windows)] +#[link(name = "kernel32")] +extern {} + // ARM targets need these symbols #[no_mangle] pub fn __aeabi_unwind_cpp_pr0() {} From e892808fddf398d9120aee84d547fd0726acb3d2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 22 Jun 2017 23:44:27 -0700 Subject: [PATCH 0317/4206] Test 64-bit linux --- library/compiler-builtins/.travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 108b12a014f68..fa9a27866afe1 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -28,7 +28,7 @@ matrix: - env: TARGET=thumbv7m-linux-eabi - env: TARGET=x86_64-apple-darwin os: osx -env: TARGET=x86_64-unknown-linux-gnu + - env: TARGET=x86_64-unknown-linux-gnu before_install: - test "$TRAVIS_OS_NAME" = "osx" || docker run --rm --privileged multiarch/qemu-user-static:register From 1740b0b0f5701eacb059f533d021aa90f18f9c0a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 06:53:09 -0700 Subject: [PATCH 0318/4206] More windows linkage guesses --- library/compiler-builtins/examples/intrinsics.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 5336422a39ac6..cabe917641fae 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -418,6 +418,7 @@ pub fn _start() -> ! { #[cfg(windows)] #[link(name = "kernel32")] +#[link(name = "msvcrt")] extern {} // ARM targets need these symbols From 0aead6b3d843d962bf4c57331dc86ea582541fec Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 06:58:05 -0700 Subject: [PATCH 0319/4206] Require the `compiler-builtins` target for the example --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 69b9c03c03d09..08bf5fd02f71f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -29,7 +29,7 @@ utest-macros = { git = "https://github.com/japaric/utest" } [[example]] name = "intrinsics" -required-features = ["c"] +required-features = ["c", "compiler-builtins"] [workspace] From 48c4569e9172d2ad434901287283d5d15bf301c5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 07:01:18 -0700 Subject: [PATCH 0320/4206] Build the intrinsics example separately --- library/compiler-builtins/appveyor.yml | 4 ++-- library/compiler-builtins/ci/run.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 2bef109367c8a..66cd96e48ea53 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -15,8 +15,8 @@ install: build: false test_script: - - cargo build --target %TARGET% - - cargo build --release --target %TARGET% + - cargo build --target %TARGET% --example intrinsics + - cargo build --release --target %TARGET% --example intrinsics - cargo test --no-default-features --features gen-tests --target %TARGET% - cargo test --no-default-features --features "gen-tests c" --target %TARGET% - cargo test --no-default-features --features gen-tests --release --target %TARGET% diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 02b9bf11248f3..0d52e73071222 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -46,7 +46,7 @@ case $1 in xargo build --features c --target $1 --example intrinsics ;; *) - cargo build --no-default-features --features c --target $1 --example intrinsics + cargo build --features c --target $1 --example intrinsics ;; esac From b6497f5283bbb01a09e1cb36088d20cd2f09be11 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 07:36:08 -0700 Subject: [PATCH 0321/4206] Build tweaks --- library/compiler-builtins/appveyor.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 66cd96e48ea53..2dce7ceb6df2a 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -15,8 +15,10 @@ install: build: false test_script: - - cargo build --target %TARGET% --example intrinsics - - cargo build --release --target %TARGET% --example intrinsics + - cargo build --target %TARGET% + - cargo build --target %TARGET% --features c --example intrinsics + - cargo build --release --target %TARGET% + - cargo build --release --target %TARGET% --features c --example intrinsics - cargo test --no-default-features --features gen-tests --target %TARGET% - cargo test --no-default-features --features "gen-tests c" --target %TARGET% - cargo test --no-default-features --features gen-tests --release --target %TARGET% From 5a36c4b54bbb6d7a8752ca0a8c14df3bf4e8b369 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 07:52:38 -0700 Subject: [PATCH 0322/4206] Use more intrinsics on msvc --- library/compiler-builtins/src/int/mul.rs | 2 +- library/compiler-builtins/src/int/sdiv.rs | 4 ++-- library/compiler-builtins/src/int/shift.rs | 6 +++--- library/compiler-builtins/src/int/udiv.rs | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 4b0831d8ee5ba..cb3fbd620bf71 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -71,7 +71,7 @@ impl Mulo for i64 {} impl Mulo for i128 {} intrinsics! { - #[use_c_shim_if(target_arch = "x86")] + #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 { a.mul(b) } diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 310eb9f82fc4f..8d856303755c0 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -64,7 +64,7 @@ intrinsics! { a.div(b) } - #[use_c_shim_if(target_arch = "x86")] + #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] pub extern "C" fn __divdi3(a: i64, b: i64) -> i64 { a.div(b) } @@ -79,7 +79,7 @@ intrinsics! { a.mod_(b) } - #[use_c_shim_if(target_arch = "x86")] + #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] pub extern "C" fn __moddi3(a: i64, b: i64) -> i64 { a.mod_(b) } diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 746d02ded8a55..b0103ceaf205d 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -65,7 +65,7 @@ impl Lshr for u64 {} impl Lshr for u128 {} intrinsics! { - #[use_c_shim_if(target_arch = "x86")] + #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] pub extern "C" fn __ashldi3(a: u64, b: u32) -> u64 { a.ashl(b) } @@ -74,7 +74,7 @@ intrinsics! { a.ashl(b) } - #[use_c_shim_if(target_arch = "x86")] + #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] pub extern "C" fn __ashrdi3(a: i64, b: u32) -> i64 { a.ashr(b) } @@ -83,7 +83,7 @@ intrinsics! { a.ashr(b) } - #[use_c_shim_if(target_arch = "x86")] + #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] pub extern "C" fn __lshrdi3(a: u64, b: u32) -> u64 { a.lshr(b) } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 5ef46dec4216d..77e9c3f42a6b9 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -227,13 +227,13 @@ intrinsics! { q } - #[use_c_shim_if(target_arch = "x86")] + #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] /// Returns `n / d` pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { __udivmoddi4(n, d, None) } - #[use_c_shim_if(target_arch = "x86")] + #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] /// Returns `n % d` pub extern "C" fn __umoddi3(n: u64, d: u64) -> u64 { let mut rem = 0; From 57b8dd1812f6e97844dce891cf696241d3d60322 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 07:54:31 -0700 Subject: [PATCH 0323/4206] Fix use_c_shim_if --- library/compiler-builtins/src/macros.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 70e44da59c1ec..740eae293858a 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -15,7 +15,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( - #[cfg(all(feature = "c", not($($cfg_clause)*)))] + #[cfg(all(feature = "c", $($cfg_clause)*))] $(#[$attr])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { extern $abi { @@ -26,7 +26,7 @@ macro_rules! intrinsics { } } - #[cfg(not(all(feature = "c", not($($cfg_clause)*))))] + #[cfg(not(all(feature = "c", $($cfg_clause)*)))] intrinsics! { $(#[$attr])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { From 43bb211be8467cdf55cbb82116e2db17aaa13799 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 08:19:11 -0700 Subject: [PATCH 0324/4206] Fix travis intrinsics builds --- library/compiler-builtins/ci/run.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 0d52e73071222..0f25a533f5c58 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -54,11 +54,11 @@ esac # TODO(#79) fix the undefined references problem for debug-assertions+lto case $1 in thumb*) - RUSTFLAGS="-C debug-assertions=no" xargo rustc --no-default-features --features c --target $1 --example intrinsics -- -C lto -C link-arg=-nostartfiles + RUSTFLAGS="-C debug-assertions=no" xargo rustc --features c --target $1 --example intrinsics -- -C lto -C link-arg=-nostartfiles xargo rustc --no-default-features --features c --target $1 --example intrinsics --release -- -C lto ;; *) - RUSTFLAGS="-C debug-assertions=no" cargo rustc --no-default-features --features c --target $1 --example intrinsics -- -C lto + RUSTFLAGS="-C debug-assertions=no" cargo rustc --features c --target $1 --example intrinsics -- -C lto cargo rustc --no-default-features --features c --target $1 --example intrinsics --release -- -C lto ;; esac From b6a4de6be55a3cfc5b3d13c110dc1079a49f902e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 08:35:24 -0700 Subject: [PATCH 0325/4206] Fix features needed for the intrinsics example --- library/compiler-builtins/ci/run.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 0f25a533f5c58..8ac8845c922c8 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -55,11 +55,11 @@ esac case $1 in thumb*) RUSTFLAGS="-C debug-assertions=no" xargo rustc --features c --target $1 --example intrinsics -- -C lto -C link-arg=-nostartfiles - xargo rustc --no-default-features --features c --target $1 --example intrinsics --release -- -C lto + xargo rustc --features c --target $1 --example intrinsics --release -- -C lto ;; *) RUSTFLAGS="-C debug-assertions=no" cargo rustc --features c --target $1 --example intrinsics -- -C lto - cargo rustc --no-default-features --features c --target $1 --example intrinsics --release -- -C lto + cargo rustc --features c --target $1 --example intrinsics --release -- -C lto ;; esac From e798d1bf8163203ebbd7d4d22816020588a07d93 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 09:59:49 -0700 Subject: [PATCH 0326/4206] Enable `mem` for intrinsics on linux --- library/compiler-builtins/ci/run.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 8ac8845c922c8..6977455c72b87 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -43,10 +43,10 @@ esac # Verify that we haven't drop any intrinsic/symbol case $1 in thumb*) - xargo build --features c --target $1 --example intrinsics + xargo build --features 'c mem' --target $1 --example intrinsics ;; *) - cargo build --features c --target $1 --example intrinsics + cargo build --features 'c mem' --target $1 --example intrinsics ;; esac @@ -54,12 +54,12 @@ esac # TODO(#79) fix the undefined references problem for debug-assertions+lto case $1 in thumb*) - RUSTFLAGS="-C debug-assertions=no" xargo rustc --features c --target $1 --example intrinsics -- -C lto -C link-arg=-nostartfiles - xargo rustc --features c --target $1 --example intrinsics --release -- -C lto + RUSTFLAGS="-C debug-assertions=no" xargo rustc --features 'c mem' --target $1 --example intrinsics -- -C lto -C link-arg=-nostartfiles + xargo rustc --features 'c mem' --target $1 --example intrinsics --release -- -C lto ;; *) - RUSTFLAGS="-C debug-assertions=no" cargo rustc --features c --target $1 --example intrinsics -- -C lto - cargo rustc --features c --target $1 --example intrinsics --release -- -C lto + RUSTFLAGS="-C debug-assertions=no" cargo rustc --features 'c mem' --target $1 --example intrinsics -- -C lto + cargo rustc --features 'c mem' --target $1 --example intrinsics --release -- -C lto ;; esac From e8d550ee512c06b7abe85d565b57e7d75d8ce182 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 10:44:29 -0700 Subject: [PATCH 0327/4206] Less verbose output on symbol check --- library/compiler-builtins/ci/run.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 6977455c72b87..e5c89247dd7e3 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -77,7 +77,7 @@ case $1 in ;; esac -case $TRAVIS_OS_NAME in +case "$TRAVIS_OS_NAME" in osx) # NOTE OSx's nm doesn't accept the `--defined-only` or provide an equivalent. # Use GNU nm instead @@ -89,14 +89,15 @@ case $TRAVIS_OS_NAME in ;; esac -if [ $TRAVIS_OS_NAME = osx ]; then +if [ "$TRAVIS_OS_NAME" = osx ]; then path=target/${1}/debug/deps/libcompiler_builtins-*.rlib else path=/target/${1}/debug/deps/libcompiler_builtins-*.rlib fi for rlib in $(echo $path); do - stdout=$($PREFIX$NM -g --defined-only $rlib) + set +x + stdout=$($PREFIX$NM -g --defined-only $rlib 2>&1) # NOTE On i586, It's normal that the get_pc_thunk symbol appears several times so ignore it set +e @@ -105,6 +106,7 @@ for rlib in $(echo $path); do if test $? = 0; then exit 1 fi + set -ex done true From c53d1c7b7deb7ea430cfe78636e65df6622a0036 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 10:44:59 -0700 Subject: [PATCH 0328/4206] Remove executable bit from conv.rs --- library/compiler-builtins/src/float/conv.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 library/compiler-builtins/src/float/conv.rs diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs old mode 100755 new mode 100644 From bf2f5b5808f9fc00aec0d7baebf8479851e4dbd9 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 11:05:25 -0700 Subject: [PATCH 0329/4206] Convert float intrinsics to the `intrinsics!` macro --- library/compiler-builtins/src/float/add.rs | 324 ++++++++++---------- library/compiler-builtins/src/float/conv.rs | 238 ++++++++------ library/compiler-builtins/src/float/pow.rs | 52 ++-- library/compiler-builtins/src/float/sub.rs | 23 +- library/compiler-builtins/src/int/udiv.rs | 22 +- library/compiler-builtins/src/lib.rs | 46 --- 6 files changed, 349 insertions(+), 356 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 5024a728b040c..1b1ac3f00875f 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -3,192 +3,190 @@ use core::num::Wrapping; use float::Float; +/// Returns `a + b` macro_rules! add { - ($abi:tt, $intrinsic:ident: $ty:ty) => { - /// Returns `a + b` - #[allow(unused_parens)] - #[cfg_attr(not(test), no_mangle)] - pub extern $abi fn $intrinsic(a: $ty, b: $ty) -> $ty { - let one = Wrapping(1 as <$ty as Float>::Int); - let zero = Wrapping(0 as <$ty as Float>::Int); - - let bits = Wrapping(<$ty>::bits() as <$ty as Float>::Int); - let significand_bits = Wrapping(<$ty>::significand_bits() as <$ty as Float>::Int); - let exponent_bits = bits - significand_bits - one; - let max_exponent = (one << exponent_bits.0 as usize) - one; - - let implicit_bit = one << significand_bits.0 as usize; - let significand_mask = implicit_bit - one; - let sign_bit = one << (significand_bits + exponent_bits).0 as usize; - let abs_mask = sign_bit - one; - let exponent_mask = abs_mask ^ significand_mask; - let inf_rep = exponent_mask; - let quiet_bit = implicit_bit >> 1; - let qnan_rep = exponent_mask | quiet_bit; - - let mut a_rep = Wrapping(a.repr()); - let mut b_rep = Wrapping(b.repr()); - let a_abs = a_rep & abs_mask; - let b_abs = b_rep & abs_mask; - - // Detect if a or b is zero, infinity, or NaN. - if a_abs - one >= inf_rep - one || - b_abs - one >= inf_rep - one { - // NaN + anything = qNaN - if a_abs > inf_rep { - return (<$ty as Float>::from_repr((a_abs | quiet_bit).0)); - } - // anything + NaN = qNaN - if b_abs > inf_rep { - return (<$ty as Float>::from_repr((b_abs | quiet_bit).0)); - } - - if a_abs == inf_rep { - // +/-infinity + -/+infinity = qNaN - if (a.repr() ^ b.repr()) == sign_bit.0 { - return (<$ty as Float>::from_repr(qnan_rep.0)); - } else { - // +/-infinity + anything remaining = +/- infinity - return a; - } - } + ($a:expr, $b:expr, $ty:ty) => ({ + let a = $a; + let b = $b; + let one = Wrapping(1 as <$ty as Float>::Int); + let zero = Wrapping(0 as <$ty as Float>::Int); + + let bits = Wrapping(<$ty>::bits() as <$ty as Float>::Int); + let significand_bits = Wrapping(<$ty>::significand_bits() as <$ty as Float>::Int); + let exponent_bits = bits - significand_bits - one; + let max_exponent = (one << exponent_bits.0 as usize) - one; + + let implicit_bit = one << significand_bits.0 as usize; + let significand_mask = implicit_bit - one; + let sign_bit = one << (significand_bits + exponent_bits).0 as usize; + let abs_mask = sign_bit - one; + let exponent_mask = abs_mask ^ significand_mask; + let inf_rep = exponent_mask; + let quiet_bit = implicit_bit >> 1; + let qnan_rep = exponent_mask | quiet_bit; + + let mut a_rep = Wrapping(a.repr()); + let mut b_rep = Wrapping(b.repr()); + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; + + // Detect if a or b is zero, infinity, or NaN. + if a_abs - one >= inf_rep - one || + b_abs - one >= inf_rep - one { + // NaN + anything = qNaN + if a_abs > inf_rep { + return <$ty as Float>::from_repr((a_abs | quiet_bit).0); + } + // anything + NaN = qNaN + if b_abs > inf_rep { + return <$ty as Float>::from_repr((b_abs | quiet_bit).0); + } - // anything remaining + +/-infinity = +/-infinity - if b_abs == inf_rep { - return b; + if a_abs == inf_rep { + // +/-infinity + -/+infinity = qNaN + if (a.repr() ^ b.repr()) == sign_bit.0 { + return <$ty as Float>::from_repr(qnan_rep.0); + } else { + // +/-infinity + anything remaining = +/- infinity + return a; } + } - // zero + anything = anything - if a_abs.0 == 0 { - // but we need to get the sign right for zero + zero - if b_abs.0 == 0 { - return (<$ty as Float>::from_repr(a.repr() & b.repr())); - } else { - return b; - } - } + // anything remaining + +/-infinity = +/-infinity + if b_abs == inf_rep { + return b; + } - // anything + zero = anything + // zero + anything = anything + if a_abs.0 == 0 { + // but we need to get the sign right for zero + zero if b_abs.0 == 0 { - return a; + return <$ty as Float>::from_repr(a.repr() & b.repr()); + } else { + return b; } } - // Swap a and b if necessary so that a has the larger absolute value. - if b_abs > a_abs { - mem::swap(&mut a_rep, &mut b_rep); + // anything + zero = anything + if b_abs.0 == 0 { + return a; } + } - // Extract the exponent and significand from the (possibly swapped) a and b. - let mut a_exponent = Wrapping((a_rep >> significand_bits.0 as usize & max_exponent).0 as i32); - let mut b_exponent = Wrapping((b_rep >> significand_bits.0 as usize & max_exponent).0 as i32); - let mut a_significand = a_rep & significand_mask; - let mut b_significand = b_rep & significand_mask; - - // normalize any denormals, and adjust the exponent accordingly. - if a_exponent.0 == 0 { - let (exponent, significand) = <$ty>::normalize(a_significand.0); - a_exponent = Wrapping(exponent); - a_significand = Wrapping(significand); - } - if b_exponent.0 == 0 { - let (exponent, significand) = <$ty>::normalize(b_significand.0); - b_exponent = Wrapping(exponent); - b_significand = Wrapping(significand); - } + // Swap a and b if necessary so that a has the larger absolute value. + if b_abs > a_abs { + mem::swap(&mut a_rep, &mut b_rep); + } - // The sign of the result is the sign of the larger operand, a. If they - // have opposite signs, we are performing a subtraction; otherwise addition. - let result_sign = a_rep & sign_bit; - let subtraction = ((a_rep ^ b_rep) & sign_bit) != zero; - - // Shift the significands to give us round, guard and sticky, and or in the - // implicit significand bit. (If we fell through from the denormal path it - // was already set by normalize(), but setting it twice won't hurt - // anything.) - a_significand = (a_significand | implicit_bit) << 3; - b_significand = (b_significand | implicit_bit) << 3; - - // Shift the significand of b by the difference in exponents, with a sticky - // bottom bit to get rounding correct. - let align = Wrapping((a_exponent - b_exponent).0 as <$ty as Float>::Int); - if align.0 != 0 { - if align < bits { - let sticky = ((b_significand << (bits - align).0 as usize).0 != 0) as <$ty as Float>::Int; - b_significand = (b_significand >> align.0 as usize) | Wrapping(sticky); - } else { - b_significand = one; // sticky; b is known to be non-zero. - } - } - if subtraction { - a_significand -= b_significand; - // If a == -b, return +zero. - if a_significand.0 == 0 { - return (<$ty as Float>::from_repr(0)); - } + // Extract the exponent and significand from the (possibly swapped) a and b. + let mut a_exponent = Wrapping((a_rep >> significand_bits.0 as usize & max_exponent).0 as i32); + let mut b_exponent = Wrapping((b_rep >> significand_bits.0 as usize & max_exponent).0 as i32); + let mut a_significand = a_rep & significand_mask; + let mut b_significand = b_rep & significand_mask; + + // normalize any denormals, and adjust the exponent accordingly. + if a_exponent.0 == 0 { + let (exponent, significand) = <$ty>::normalize(a_significand.0); + a_exponent = Wrapping(exponent); + a_significand = Wrapping(significand); + } + if b_exponent.0 == 0 { + let (exponent, significand) = <$ty>::normalize(b_significand.0); + b_exponent = Wrapping(exponent); + b_significand = Wrapping(significand); + } - // If partial cancellation occured, we need to left-shift the result - // and adjust the exponent: - if a_significand < implicit_bit << 3 { - let shift = a_significand.0.leading_zeros() as i32 - - (implicit_bit << 3).0.leading_zeros() as i32; - a_significand <<= shift as usize; - a_exponent -= Wrapping(shift); - } - } else /* addition */ { - a_significand += b_significand; - - // If the addition carried up, we need to right-shift the result and - // adjust the exponent: - if (a_significand & implicit_bit << 4).0 != 0 { - let sticky = ((a_significand & one).0 != 0) as <$ty as Float>::Int; - a_significand = a_significand >> 1 | Wrapping(sticky); - a_exponent += Wrapping(1); - } + // The sign of the result is the sign of the larger operand, a. If they + // have opposite signs, we are performing a subtraction; otherwise addition. + let result_sign = a_rep & sign_bit; + let subtraction = ((a_rep ^ b_rep) & sign_bit) != zero; + + // Shift the significands to give us round, guard and sticky, and or in the + // implicit significand bit. (If we fell through from the denormal path it + // was already set by normalize(), but setting it twice won't hurt + // anything.) + a_significand = (a_significand | implicit_bit) << 3; + b_significand = (b_significand | implicit_bit) << 3; + + // Shift the significand of b by the difference in exponents, with a sticky + // bottom bit to get rounding correct. + let align = Wrapping((a_exponent - b_exponent).0 as <$ty as Float>::Int); + if align.0 != 0 { + if align < bits { + let sticky = ((b_significand << (bits - align).0 as usize).0 != 0) as <$ty as Float>::Int; + b_significand = (b_significand >> align.0 as usize) | Wrapping(sticky); + } else { + b_significand = one; // sticky; b is known to be non-zero. } - - // If we have overflowed the type, return +/- infinity: - if a_exponent >= Wrapping(max_exponent.0 as i32) { - return (<$ty>::from_repr((inf_rep | result_sign).0)); + } + if subtraction { + a_significand -= b_significand; + // If a == -b, return +zero. + if a_significand.0 == 0 { + return <$ty as Float>::from_repr(0); } - if a_exponent.0 <= 0 { - // Result is denormal before rounding; the exponent is zero and we - // need to shift the significand. - let shift = Wrapping((Wrapping(1) - a_exponent).0 as <$ty as Float>::Int); - let sticky = ((a_significand << (bits - shift).0 as usize).0 != 0) as <$ty as Float>::Int; - a_significand = a_significand >> shift.0 as usize | Wrapping(sticky); - a_exponent = Wrapping(0); + // If partial cancellation occured, we need to left-shift the result + // and adjust the exponent: + if a_significand < implicit_bit << 3 { + let shift = a_significand.0.leading_zeros() as i32 + - (implicit_bit << 3).0.leading_zeros() as i32; + a_significand <<= shift as usize; + a_exponent -= Wrapping(shift); } + } else /* addition */ { + a_significand += b_significand; + + // If the addition carried up, we need to right-shift the result and + // adjust the exponent: + if (a_significand & implicit_bit << 4).0 != 0 { + let sticky = ((a_significand & one).0 != 0) as <$ty as Float>::Int; + a_significand = a_significand >> 1 | Wrapping(sticky); + a_exponent += Wrapping(1); + } + } - // Low three bits are round, guard, and sticky. - let round_guard_sticky: i32 = (a_significand.0 & 0x7) as i32; + // If we have overflowed the type, return +/- infinity: + if a_exponent >= Wrapping(max_exponent.0 as i32) { + return <$ty>::from_repr((inf_rep | result_sign).0); + } - // Shift the significand into place, and mask off the implicit bit. - let mut result = a_significand >> 3 & significand_mask; + if a_exponent.0 <= 0 { + // Result is denormal before rounding; the exponent is zero and we + // need to shift the significand. + let shift = Wrapping((Wrapping(1) - a_exponent).0 as <$ty as Float>::Int); + let sticky = ((a_significand << (bits - shift).0 as usize).0 != 0) as <$ty as Float>::Int; + a_significand = a_significand >> shift.0 as usize | Wrapping(sticky); + a_exponent = Wrapping(0); + } - // Insert the exponent and sign. - result |= Wrapping(a_exponent.0 as <$ty as Float>::Int) << significand_bits.0 as usize; - result |= result_sign; + // Low three bits are round, guard, and sticky. + let round_guard_sticky: i32 = (a_significand.0 & 0x7) as i32; - // Final rounding. The result may overflow to infinity, but that is the - // correct result in that case. - if round_guard_sticky > 0x4 { result += one; } - if round_guard_sticky == 0x4 { result += result & one; } + // Shift the significand into place, and mask off the implicit bit. + let mut result = a_significand >> 3 & significand_mask; - <$ty>::from_repr(result.0) - } - } -} + // Insert the exponent and sign. + result |= Wrapping(a_exponent.0 as <$ty as Float>::Int) << significand_bits.0 as usize; + result |= result_sign; -#[cfg(target_arch = "arm")] -add!("aapcs", __addsf3: f32); + // Final rounding. The result may overflow to infinity, but that is the + // correct result in that case. + if round_guard_sticky > 0x4 { result += one; } + if round_guard_sticky == 0x4 { result += result & one; } -#[cfg(not(target_arch = "arm"))] -add!("C", __addsf3: f32); + <$ty>::from_repr(result.0) + }) +} -#[cfg(target_arch = "arm")] -add!("aapcs", __adddf3: f64); +intrinsics! { + #[aapcs_on_arm] + pub extern "C" fn __addsf3(a: f32, b: f32) -> f32 { + add!(a, b, f32) + } -#[cfg(not(target_arch = "arm"))] -add!("C", __adddf3: f64); + #[aapcs_on_arm] + pub extern "C" fn __adddf3(a: f64, b: f64) -> f64 { + add!(a, b, f64) + } +} diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 8905f12fafa40..edf9ee610fe29 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -2,12 +2,8 @@ use float::Float; use int::Int; macro_rules! int_to_float { - ($intrinsic:ident: $ity:ty, $fty:ty) => { - int_to_float!($intrinsic: $ity, $fty, "C"); - }; - ($intrinsic:ident: $ity:ty, $fty:ty, $abi:tt) => { - - pub extern $abi fn $intrinsic(i: $ity) -> $fty { + ($i:expr, $ity:ty, $fty:ty) => ({ + let i = $i; if i == 0 { return 0.0 } @@ -70,29 +66,54 @@ macro_rules! int_to_float { <$fty>::from_parts(s, (e + exponent_bias) as <$fty as Float>::Int, a as <$fty as Float>::Int) + }) +} + +intrinsics! { + pub extern "C" fn __floatsisf(i: i32) -> f32 { + int_to_float!(i, i32, f32) } + + pub extern "C" fn __floatsidf(i: i32) -> f64 { + int_to_float!(i, i32, f64) } -} -macro_rules! int_to_float_unadj_on_win { - ($intrinsic:ident: $ity:ty, $fty:ty) => { - #[cfg(all(windows, target_pointer_width="64"))] - int_to_float!($intrinsic: $ity, $fty, "unadjusted"); - #[cfg(not(all(windows, target_pointer_width="64")))] - int_to_float!($intrinsic: $ity, $fty, "C"); - }; -} + pub extern "C" fn __floatdidf(i: i64) -> f64 { + int_to_float!(i, i64, f64) + } -int_to_float!(__floatsisf: i32, f32); -int_to_float!(__floatsidf: i32, f64); -int_to_float!(__floatdidf: i64, f64); -int_to_float_unadj_on_win!(__floattisf: i128, f32); -int_to_float_unadj_on_win!(__floattidf: i128, f64); -int_to_float!(__floatunsisf: u32, f32); -int_to_float!(__floatunsidf: u32, f64); -int_to_float!(__floatundidf: u64, f64); -int_to_float_unadj_on_win!(__floatuntisf: u128, f32); -int_to_float_unadj_on_win!(__floatuntidf: u128, f64); + #[unadjusted_on_win64] + pub extern "C" fn __floattisf(i: i128) -> f32 { + int_to_float!(i, i128, f32) + } + + #[unadjusted_on_win64] + pub extern "C" fn __floattidf(i: i128) -> f64 { + int_to_float!(i, i128, f64) + } + + pub extern "C" fn __floatunsisf(i: u32) -> f32 { + int_to_float!(i, u32, f32) + } + + pub extern "C" fn __floatunsidf(i: u32) -> f64 { + int_to_float!(i, u32, f64) + } + + pub extern "C" fn __floatundidf(i: u64) -> f64 { + int_to_float!(i, u64, f64) + } + + #[unadjusted_on_win64] + pub extern "C" fn __floatuntisf(i: u128) -> f32 { + int_to_float!(i, u128, f32) + } + + #[unadjusted_on_win64] + pub extern "C" fn __floatuntidf(i: u128) -> f64 { + int_to_float!(i, u128, f64) + } +} #[derive(PartialEq, Debug)] enum Sign { @@ -101,79 +122,106 @@ enum Sign { } macro_rules! float_to_int { - ($intrinsic:ident: $fty:ty, $ity:ty) => { - float_to_int!($intrinsic: $fty, $ity, "C"); - }; - ($intrinsic:ident: $fty:ty, $ity:ty, $abi:tt) => { - pub extern $abi fn $intrinsic(f: $fty) -> $ity { - let fixint_min = <$ity>::min_value(); - let fixint_max = <$ity>::max_value(); - let fixint_bits = <$ity>::bits() as usize; - let fixint_unsigned = fixint_min == 0; - - let sign_bit = <$fty>::sign_mask(); - let significand_bits = <$fty>::significand_bits() as usize; - let exponent_bias = <$fty>::exponent_bias() as usize; - //let exponent_max = <$fty>::exponent_max() as usize; - - // Break a into sign, exponent, significand - let a_rep = <$fty>::repr(f); - let a_abs = a_rep & !sign_bit; - - // this is used to work around -1 not being available for unsigned - let sign = if (a_rep & sign_bit) == 0 { Sign::Positive } else { Sign::Negative }; - let mut exponent = (a_abs >> significand_bits) as usize; - let significand = (a_abs & <$fty>::significand_mask()) | <$fty>::implicit_bit(); - - // if < 1 or unsigned & negative - if exponent < exponent_bias || - fixint_unsigned && sign == Sign::Negative { - return 0 - } - exponent -= exponent_bias; + ($f:expr, $fty:ty, $ity:ty) => ({ + let f = $f; + let fixint_min = <$ity>::min_value(); + let fixint_max = <$ity>::max_value(); + let fixint_bits = <$ity>::bits() as usize; + let fixint_unsigned = fixint_min == 0; + + let sign_bit = <$fty>::sign_mask(); + let significand_bits = <$fty>::significand_bits() as usize; + let exponent_bias = <$fty>::exponent_bias() as usize; + //let exponent_max = <$fty>::exponent_max() as usize; + + // Break a into sign, exponent, significand + let a_rep = <$fty>::repr(f); + let a_abs = a_rep & !sign_bit; + + // this is used to work around -1 not being available for unsigned + let sign = if (a_rep & sign_bit) == 0 { Sign::Positive } else { Sign::Negative }; + let mut exponent = (a_abs >> significand_bits) as usize; + let significand = (a_abs & <$fty>::significand_mask()) | <$fty>::implicit_bit(); + + // if < 1 or unsigned & negative + if exponent < exponent_bias || + fixint_unsigned && sign == Sign::Negative { + return 0 + } + exponent -= exponent_bias; - // If the value is infinity, saturate. - // If the value is too large for the integer type, 0. - if exponent >= (if fixint_unsigned {fixint_bits} else {fixint_bits -1}) { - return if sign == Sign::Positive {fixint_max} else {fixint_min} - } - // If 0 <= exponent < significand_bits, right shift to get the result. - // Otherwise, shift left. - // (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned - let r = if exponent < significand_bits { - (significand >> (significand_bits - exponent)) as $ity - } else { - (significand as $ity) << (exponent - significand_bits) - }; + // If the value is infinity, saturate. + // If the value is too large for the integer type, 0. + if exponent >= (if fixint_unsigned {fixint_bits} else {fixint_bits -1}) { + return if sign == Sign::Positive {fixint_max} else {fixint_min} + } + // If 0 <= exponent < significand_bits, right shift to get the result. + // Otherwise, shift left. + // (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned + let r = if exponent < significand_bits { + (significand >> (significand_bits - exponent)) as $ity + } else { + (significand as $ity) << (exponent - significand_bits) + }; - if sign == Sign::Negative { - (!r).wrapping_add(1) - } else { - r - } + if sign == Sign::Negative { + (!r).wrapping_add(1) + } else { + r } - } + }) } -macro_rules! float_to_int_unadj_on_win { - ($intrinsic:ident: $fty:ty, $ity:ty) => { - #[cfg(all(windows, target_pointer_width="64"))] - float_to_int!($intrinsic: $fty, $ity, "unadjusted"); - #[cfg(not(all(windows, target_pointer_width="64")))] - float_to_int!($intrinsic: $fty, $ity, "C"); - }; -} +intrinsics! { + pub extern "C" fn __fixsfsi(f: f32) -> i32 { + float_to_int!(f, f32, i32) + } + + pub extern "C" fn __fixsfdi(f: f32) -> i64 { + float_to_int!(f, f32, i64) + } + + #[unadjusted_on_win64] + pub extern "C" fn __fixsfti(f: f32) -> i128 { + float_to_int!(f, f32, i128) + } + + pub extern "C" fn __fixdfsi(f: f64) -> i32 { + float_to_int!(f, f64, i32) + } + + pub extern "C" fn __fixdfdi(f: f64) -> i64 { + float_to_int!(f, f64, i64) + } -float_to_int!(__fixsfsi: f32, i32); -float_to_int!(__fixsfdi: f32, i64); -float_to_int_unadj_on_win!(__fixsfti: f32, i128); -float_to_int!(__fixdfsi: f64, i32); -float_to_int!(__fixdfdi: f64, i64); -float_to_int_unadj_on_win!(__fixdfti: f64, i128); - -float_to_int!(__fixunssfsi: f32, u32); -float_to_int!(__fixunssfdi: f32, u64); -float_to_int_unadj_on_win!(__fixunssfti: f32, u128); -float_to_int!(__fixunsdfsi: f64, u32); -float_to_int!(__fixunsdfdi: f64, u64); -float_to_int_unadj_on_win!(__fixunsdfti: f64, u128); + #[unadjusted_on_win64] + pub extern "C" fn __fixdfti(f: f64) -> i128 { + float_to_int!(f, f64, i128) + } + + pub extern "C" fn __fixunssfsi(f: f32) -> u32 { + float_to_int!(f, f32, u32) + } + + pub extern "C" fn __fixunssfdi(f: f32) -> u64 { + float_to_int!(f, f32, u64) + } + + #[unadjusted_on_win64] + pub extern "C" fn __fixunssfti(f: f32) -> u128 { + float_to_int!(f, f32, u128) + } + + pub extern "C" fn __fixunsdfsi(f: f64) -> u32 { + float_to_int!(f, f64, u32) + } + + pub extern "C" fn __fixunsdfdi(f: f64) -> u64 { + float_to_int!(f, f64, u64) + } + + #[unadjusted_on_win64] + pub extern "C" fn __fixunsdfti(f: f64) -> u128 { + float_to_int!(f, f64, u128) + } +} diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index 5e28d95d8d292..f5c5757d8bc42 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -1,30 +1,34 @@ +/// Returns `a` raised to the power `b` macro_rules! pow { - ($intrinsic:ident: $fty:ty, $ity:ident) => { - /// Returns `a` raised to the power `b` - #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $intrinsic(a: $fty, b: $ity) -> $fty { - let (mut a, mut b) = (a, b); - let recip = b < 0; - let mut r: $fty = 1.0; - loop { - if (b & 1) != 0 { - r *= a; - } - b = sdiv!($ity, b, 2); - if b == 0 { - break; - } - a *= a; + ($a: expr, $b: expr) => ({ + let (mut a, mut b) = ($a, $b); + let recip = b < 0; + let mut r = 1.0; + loop { + if (b & 1) != 0 { + r *= a; } - - if recip { - 1.0 / r - } else { - r + b = b.checked_div(2).unwrap_or_else(|| ::abort()); + if b == 0 { + break; } + a *= a; } - } + + if recip { + 1.0 / r + } else { + r + } + }) } -pow!(__powisf2: f32, i32); -pow!(__powidf2: f64, i32); +intrinsics! { + pub extern "C" fn __powisf2(a: f32, b: i32) -> f32 { + pow!(a, b) + } + + pub extern "C" fn __powidf2(a: f64, b: i32) -> f64 { + pow!(a, b) + } +} diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index a4fd8841d17e6..a82a9437e0f97 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -1,20 +1,11 @@ use float::Float; -macro_rules! sub { - ($(#[$attr:meta])* - | $intrinsic:ident: $ty:ty) => { - /// Returns `a - b` - $(#[$attr])* - pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty { - a + <$ty>::from_repr(b.repr() ^ <$ty>::sign_mask()) - } +intrinsics! { + pub extern "C" fn __subsf3(a: f32, b: f32) -> f32 { + a + f32::from_repr(b.repr() ^ f32::sign_mask()) } -} - -sub!(#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] - #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] - | __subsf3: f32); -sub!(#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] - #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] - | __subdf3: f64); + pub extern "C" fn __subdf3(a: f64, b: f64) -> f64 { + a + f64::from_repr(b.repr() ^ f64::sign_mask()) + } +} diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 77e9c3f42a6b9..90ac729bf98d2 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -1,5 +1,3 @@ -use core::intrinsics; - use int::{Int, LargeInt}; macro_rules! udivmod_inner { @@ -13,9 +11,11 @@ macro_rules! udivmod_inner { // 0 X if let Some(rem) = rem { - *rem = <$ty>::from(urem!(n.low(), d.low())); + *rem = <$ty>::from(n.low().checked_rem(d.low()) + .unwrap_or_else(|| ::abort())); } - return <$ty>::from(udiv!(n.low(), d.low())); + return <$ty>::from(n.low().checked_div(d.low()) + .unwrap_or_else(|| ::abort())); } else { // 0 X // --- @@ -38,9 +38,7 @@ macro_rules! udivmod_inner { // 0 0 // NOTE This should be unreachable in safe Rust because the program will panic before // this intrinsic is called - unsafe { - intrinsics::abort() - } + ::abort(); } if n.low() == 0 { @@ -48,9 +46,11 @@ macro_rules! udivmod_inner { // --- // K 0 if let Some(rem) = rem { - *rem = <$ty>::from_parts(0, urem!(n.high(), d.high())); + *rem = <$ty>::from_parts(0, n.high().checked_rem(d.high()) + .unwrap_or_else(|| ::abort())); } - return <$ty>::from(udiv!(n.high(), d.high())); + return <$ty>::from(n.high().checked_div(d.high()) + .unwrap_or_else(|| ::abort())); } // K K @@ -161,9 +161,7 @@ intrinsics! { if d == 0 { // NOTE This should be unreachable in safe Rust because the program will panic before // this intrinsic is called - unsafe { - intrinsics::abort() - } + ::abort(); } if n == 0 { diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 6d44fb1a185e9..3fa7923b4475f 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -32,52 +32,6 @@ // that follow "x86 naming convention" (e.g. addsf3). Those aeabi intrinsics must adhere to the // AAPCS calling convention (`extern "aapcs"`) because that's how LLVM will call them. -// TODO(rust-lang/rust#37029) use e.g. checked_div(_).unwrap_or_else(|| abort()) -macro_rules! udiv { - ($a:expr, $b:expr) => { - unsafe { - let a = $a; - let b = $b; - - if b == 0 { - ::core::intrinsics::abort() - } else { - ::core::intrinsics::unchecked_div(a, b) - } - } - } -} - -macro_rules! sdiv { - ($sty:ident, $a:expr, $b:expr) => { - unsafe { - let a = $a; - let b = $b; - - if b == 0 || (b == -1 && a == $sty::min_value()) { - ::core::intrinsics::abort() - } else { - ::core::intrinsics::unchecked_div(a, b) - } - } - } -} - -macro_rules! urem { - ($a:expr, $b:expr) => { - unsafe { - let a = $a; - let b = $b; - - if b == 0 { - ::core::intrinsics::abort() - } else { - ::core::intrinsics::unchecked_rem(a, b) - } - } - } -} - #[cfg(test)] extern crate core; From d20a774a4aeb6a580f272c38bef91618a8c4ac61 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 11:13:31 -0700 Subject: [PATCH 0330/4206] Remove defined intrinsics from build.rs No need to load these from C! --- library/compiler-builtins/build.rs | 32 ------------------------------ 1 file changed, 32 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index c8179fe9eb9aa..171622cb0dadb 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4066,28 +4066,8 @@ mod c { "divxc3.c", "extendsfdf2.c", "extendhfsf2.c", - "ffsdi2.c", - "fixdfdi.c", - "fixdfsi.c", - "fixsfdi.c", - "fixsfsi.c", - "fixunsdfdi.c", - "fixunsdfsi.c", - "fixunssfdi.c", - "fixunssfsi.c", - "fixunsxfdi.c", - "fixunsxfsi.c", - "fixxfdi.c", - "floatdidf.c", "floatdisf.c", - "floatdixf.c", - "floatsidf.c", - "floatsisf.c", - "floatundidf.c", "floatundisf.c", - "floatundixf.c", - "floatunsidf.c", - "floatunsisf.c", "int_util.c", "muldc3.c", "muldf3.c", @@ -4124,18 +4104,6 @@ mod c { "cmpti2.c", "ctzti2.c", "ffsti2.c", - "fixdfti.c", - "fixsfti.c", - "fixunsdfti.c", - "fixunssfti.c", - "fixunsxfti.c", - "fixxfti.c", - "floattidf.c", - "floattisf.c", - "floattixf.c", - "floatuntidf.c", - "floatuntisf.c", - "floatuntixf.c", "mulvti3.c", "negti2.c", "negvti2.c", From 0e5562c38dabf672e69736d7fa9afbcc3fbece7b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 11:21:15 -0700 Subject: [PATCH 0331/4206] Remove executable bit on arm.rs --- library/compiler-builtins/src/arm.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 library/compiler-builtins/src/arm.rs diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs old mode 100755 new mode 100644 From 11d3cffd309ba4148a41b5f4c6aab1b56858d44b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 11:21:36 -0700 Subject: [PATCH 0332/4206] Remove unused rust file --- library/compiler-builtins/src/qc.rs | 311 ---------------------------- 1 file changed, 311 deletions(-) delete mode 100644 library/compiler-builtins/src/qc.rs diff --git a/library/compiler-builtins/src/qc.rs b/library/compiler-builtins/src/qc.rs deleted file mode 100644 index 675bcc67702fc..0000000000000 --- a/library/compiler-builtins/src/qc.rs +++ /dev/null @@ -1,311 +0,0 @@ -// When testing functions, QuickCheck (QC) uses small values for integer (`u*`/`i*`) arguments -// (~ `[-100, 100]`), but these values don't stress all the code paths in our intrinsics. Here we -// create newtypes over the primitive integer types with the goal of having full control over the -// random values that will be used to test our intrinsics. - -use std::boxed::Box; -use std::fmt; -use core::{f32, f64}; - -use quickcheck::{Arbitrary, Gen}; - -use int::LargeInt; -use float::Float; - -// Generates values in the full range of the integer type -macro_rules! arbitrary { - ($TY:ident : $ty:ident) => { - #[derive(Clone, Copy, PartialEq)] - pub struct $TY(pub $ty); - - impl Arbitrary for $TY { - fn arbitrary(g: &mut G) -> $TY - where G: Gen - { - // NOTE Generate edge cases with a 10% chance - let t = if g.gen_weighted_bool(10) { - *g.choose(&[ - $ty::min_value(), - 0, - $ty::max_value(), - ]).unwrap() - } else { - g.gen() - }; - - $TY(t) - } - - fn shrink(&self) -> Box> { - struct Shrinker { - x: $ty, - } - - impl Iterator for Shrinker { - type Item = $TY; - - fn next(&mut self) -> Option<$TY> { - self.x /= 2; - if self.x == 0 { - None - } else { - Some($TY(self.x)) - } - } - } - - if self.0 == 0 { - ::quickcheck::empty_shrinker() - } else { - Box::new(Shrinker { x: self.0 }) - } - } - } - - impl fmt::Debug for $TY { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.0, f) - } - } - } -} - -arbitrary!(I32: i32); -arbitrary!(U32: u32); - -// These integers are "too large". If we generate e.g. `u64` values in the full range then there's -// only `1 / 2^32` chance of seeing a value smaller than `2^32` (i.e. whose higher "word" (32-bits) -// is `0`)! But this is an important group of values to tests because we have special code paths for -// them. Instead we'll generate e.g. `u64` integers this way: uniformly pick between (a) setting the -// low word to 0 and generating a random high word, (b) vice versa: high word to 0 and random low -// word or (c) generate both words randomly. This let's cover better the code paths in our -// intrinsics. -macro_rules! arbitrary_large { - ($TY:ident : $ty:ident) => { - #[derive(Clone, Copy, PartialEq)] - pub struct $TY(pub $ty); - - impl Arbitrary for $TY { - fn arbitrary(g: &mut G) -> $TY - where G: Gen - { - // NOTE Generate edge cases with a 10% chance - let t = if g.gen_weighted_bool(10) { - *g.choose(&[ - $ty::min_value(), - 0, - $ty::max_value(), - ]).unwrap() - } else { - match g.gen_range(0, 3) { - 0 => $ty::from_parts(g.gen(), g.gen()), - 1 => $ty::from_parts(0, g.gen()), - 2 => $ty::from_parts(g.gen(), 0), - _ => unreachable!(), - } - }; - - $TY(t) - } - - fn shrink(&self) -> Box> { - struct Shrinker { - x: $ty, - } - - impl Iterator for Shrinker { - type Item = $TY; - - fn next(&mut self) -> Option<$TY> { - self.x /= 2; - if self.x == 0 { - None - } else { - Some($TY(self.x)) - } - } - } - - if self.0 == 0 { - ::quickcheck::empty_shrinker() - } else { - Box::new(Shrinker { x: self.0 }) - } - } - } - - impl fmt::Debug for $TY { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.0, f) - } - } - } -} - -arbitrary_large!(I64: i64); -arbitrary_large!(U64: u64); -arbitrary_large!(I128: i128); -arbitrary_large!(U128: u128); - -macro_rules! arbitrary_float { - ($TY:ident : $ty:ident) => { - #[derive(Clone, Copy)] - pub struct $TY(pub $ty); - - impl Arbitrary for $TY { - fn arbitrary(g: &mut G) -> $TY - where G: Gen - { - let special = [ - -0.0, 0.0, $ty::NAN, $ty::INFINITY, -$ty::INFINITY - ]; - - if g.gen_weighted_bool(10) { // Random special case - $TY(*g.choose(&special).unwrap()) - } else if g.gen_weighted_bool(10) { // NaN variants - let sign: bool = g.gen(); - let exponent: <$ty as Float>::Int = g.gen(); - let significand: <$ty as Float>::Int = 0; - $TY($ty::from_parts(sign, exponent, significand)) - } else if g.gen() { // Denormalized - let sign: bool = g.gen(); - let exponent: <$ty as Float>::Int = 0; - let significand: <$ty as Float>::Int = g.gen(); - $TY($ty::from_parts(sign, exponent, significand)) - } else { // Random anything - let sign: bool = g.gen(); - let exponent: <$ty as Float>::Int = g.gen(); - let significand: <$ty as Float>::Int = g.gen(); - $TY($ty::from_parts(sign, exponent, significand)) - } - } - - fn shrink(&self) -> Box> { - ::quickcheck::empty_shrinker() - } - } - - impl fmt::Debug for $TY { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.0, f) - } - } - - impl PartialEq for $TY { - fn eq(&self, other: &$TY) -> bool { - self.0.eq_repr(other.0) - } - } - } -} - -arbitrary_float!(F32: f32); -arbitrary_float!(F64: f64); - -// Convenience macro to test intrinsics against their reference implementations. -// -// Each intrinsic is tested against both the `gcc_s` library as well as -// `compiler-rt`. These libraries are defined in the `gcc_s` crate as well as -// the `compiler-rt` crate in this repository. Both load a dynamic library and -// lookup symbols through that dynamic library to ensure that we're using the -// right intrinsic. -// -// This macro hopefully allows you to define a bare minimum of how to test an -// intrinsic without worrying about these implementation details. A sample -// invocation looks like: -// -// -// check! { -// // First argument is the function we're testing (either from this lib -// // or a dynamically loaded one. Further arguments are all generated by -// // quickcheck. -// fn __my_intrinsic(f: extern fn(i32) -> i32, -// a: I32) -// -> Option<(i32, i64)> { -// -// // Discard tests by returning Some -// if a.0 == 0 { -// return None -// } -// -// // Return the result via `Some` if the test can run -// let mut other_result = 0; -// let result = f(a.0, &mut other_result); -// Some((result, other_result)) -// } -// } -// -// If anything returns `None` then the test is discarded, otherwise the two -// results are compared for equality and the test fails if this equality check -// fails. -macro_rules! check { - ($( - $(#[$cfg:meta])* - fn $name:ident($f:ident: extern $abi:tt fn($($farg:ty),*) -> $fret:ty, - $($arg:ident: $t:ty),*) - -> Option<$ret:ty> - { - $($code:tt)* - } - )*) => ( - $( - $(#[$cfg])* - fn $name($f: extern $abi fn($($farg),*) -> $fret, - $($arg: $t),*) -> Option<$ret> { - $($code)* - } - )* - - mod _test { - use qc::*; - use std::mem; - use quickcheck::TestResult; - - $( - $(#[$cfg])* - #[test] - fn $name() { - fn my_check($($arg:$t),*) -> TestResult { - let my_answer = super::$name(super::super::$name, - $($arg),*); - let compiler_rt_fn = ::compiler_rt::get(stringify!($name)); - let compiler_rt_answer = unsafe { - super::$name(mem::transmute(compiler_rt_fn), - $($arg),*) - }; - let gcc_s_answer = - match ::gcc_s::get(stringify!($name)) { - Some(f) => unsafe { - Some(super::$name(mem::transmute(f), - $($arg),*)) - }, - None => None, - }; - - let print_values = || { - print!("{} - Args: ", stringify!($name)); - $(print!("{:?} ", $arg);)* - print!("\n"); - println!(" compiler-builtins: {:?}", my_answer); - println!(" compiler_rt: {:?}", compiler_rt_answer); - println!(" gcc_s: {:?}", gcc_s_answer); - }; - - if my_answer != compiler_rt_answer { - print_values(); - TestResult::from_bool(false) - } else if gcc_s_answer.is_some() && - my_answer != gcc_s_answer.unwrap() { - print_values(); - TestResult::from_bool(false) - } else { - TestResult::from_bool(true) - } - } - - ::quickcheck::quickcheck(my_check as fn($($t),*) -> TestResult) - } - )* - } - ) -} From 4dbe3aaf2de7a866bb5011cc78874155bf60d3d3 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 11:52:22 -0700 Subject: [PATCH 0333/4206] Use `nm` to weed out panics --- library/compiler-builtins/ci/run.sh | 13 ++++++++++++- library/compiler-builtins/src/float/conv.rs | 2 ++ library/compiler-builtins/src/int/mul.rs | 4 ++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index e5c89247dd7e3..3316a43c61e27 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -63,7 +63,6 @@ case $1 in ;; esac -# Look out for duplicated symbols when we include the compiler-rt (C) implementation PREFIX=$(echo $1 | sed -e 's/unknown-//')- case $1 in armv7-*) @@ -95,6 +94,7 @@ else path=/target/${1}/debug/deps/libcompiler_builtins-*.rlib fi +# Look out for duplicated symbols when we include the compiler-rt (C) implementation for rlib in $(echo $path); do set +x stdout=$($PREFIX$NM -g --defined-only $rlib 2>&1) @@ -109,4 +109,15 @@ for rlib in $(echo $path); do set -ex done +# Ensure no references to a panicking function +for rlib in $(echo $path); do + set +x + $PREFIX$NM -u $rlib 2>&1 | grep panicking + + if test $? = 0; then + exit 1 + fi + set -ex +done + true diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index edf9ee610fe29..053c6816e5b32 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -78,6 +78,7 @@ intrinsics! { int_to_float!(i, i32, f64) } + #[use_c_shim_if(any(target_arch = "x86", target_arch = "x86_64"))] pub extern "C" fn __floatdidf(i: i64) -> f64 { int_to_float!(i, i64, f64) } @@ -100,6 +101,7 @@ intrinsics! { int_to_float!(i, u32, f64) } + #[use_c_shim_if(any(target_arch = "x86", target_arch = "x86_64"))] pub extern "C" fn __floatundidf(i: u64) -> f64 { int_to_float!(i, u64, f64) } diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index cb3fbd620bf71..9241ee6a4c03c 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -54,11 +54,11 @@ trait Mulo: Int + ops::Neg { return result; } if sa == sb { - if abs_a > Self::max_value() / abs_b { + if abs_a > Self::max_value().checked_div(abs_b).unwrap_or_else(|| ::abort()) { *overflow = 1; } } else { - if abs_a > Self::min_value() / -abs_b { + if abs_a > Self::min_value().checked_div(-abs_b).unwrap_or_else(|| ::abort()) { *overflow = 1; } } From f091d059040c080c0ff215062aef35cbb48fd2d8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 12:02:28 -0700 Subject: [PATCH 0334/4206] Tweak usage of C shims on MSVC --- library/compiler-builtins/src/float/conv.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 053c6816e5b32..ca95b110434dc 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -78,7 +78,10 @@ intrinsics! { int_to_float!(i, i32, f64) } - #[use_c_shim_if(any(target_arch = "x86", target_arch = "x86_64"))] + #[use_c_shim_if(any( + all(not(target_env = "msvc"), target_arch = "x86", target_arch = "x86_64"), + all(target_env = "msvc", target_arch = "x86_64"), + ))] pub extern "C" fn __floatdidf(i: i64) -> f64 { int_to_float!(i, i64, f64) } @@ -101,7 +104,8 @@ intrinsics! { int_to_float!(i, u32, f64) } - #[use_c_shim_if(any(target_arch = "x86", target_arch = "x86_64"))] + #[use_c_shim_if(all(any(target_arch = "x86", target_arch = "x86_64"), + not(target_env = "msvc")))] pub extern "C" fn __floatundidf(i: u64) -> f64 { int_to_float!(i, u64, f64) } From 78b290b61c7a27c0dd6e09397971a2e5de90071d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 13:28:24 -0700 Subject: [PATCH 0335/4206] Deal with floatdidf on x86_64 Apparently LLVM will lower this down to just an instruction --- library/compiler-builtins/build.rs | 2 -- library/compiler-builtins/src/float/conv.rs | 13 ++++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 171622cb0dadb..e66b3ab3bbeab 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4132,7 +4132,6 @@ mod c { if target_arch == "x86_64" { sources.extend( &[ - "x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c", ], @@ -4148,7 +4147,6 @@ mod c { &[ "x86_64/chkstk.S", "x86_64/chkstk2.S", - "x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c", "x86_64/floatundidf.S", diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index ca95b110434dc..ca05c2830603f 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -78,12 +78,15 @@ intrinsics! { int_to_float!(i, i32, f64) } - #[use_c_shim_if(any( - all(not(target_env = "msvc"), target_arch = "x86", target_arch = "x86_64"), - all(target_env = "msvc", target_arch = "x86_64"), - ))] + #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] pub extern "C" fn __floatdidf(i: i64) -> f64 { - int_to_float!(i, i64, f64) + // On x86_64 LLVM will use native instructions for this conversion, we + // can just do it directly + if cfg!(target_arch = "x86_64") { + i as f64 + } else { + int_to_float!(i, i64, f64) + } } #[unadjusted_on_win64] From 6db18f65366162e2da22091f9a750184eee7979f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 15:16:07 -0700 Subject: [PATCH 0336/4206] Handle aeabi aliasing Objects in compiler-rt may have two symbols, so this makes sure that we don't bring in those objects by accident by defining the aliases ourselves. --- library/compiler-builtins/ci/run.sh | 30 ++++----- library/compiler-builtins/src/arm.rs | 58 ----------------- library/compiler-builtins/src/float/add.rs | 2 + library/compiler-builtins/src/float/conv.rs | 14 +++++ library/compiler-builtins/src/float/sub.rs | 2 + library/compiler-builtins/src/int/mul.rs | 1 + library/compiler-builtins/src/int/sdiv.rs | 1 + library/compiler-builtins/src/int/shift.rs | 3 + library/compiler-builtins/src/int/udiv.rs | 1 + library/compiler-builtins/src/macros.rs | 69 ++++++++++++++++----- 10 files changed, 95 insertions(+), 86 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 3316a43c61e27..f61b90f81759b 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -50,19 +50,6 @@ case $1 in ;; esac -# Verify that there are no undefined symbols to `panic` within our implementations -# TODO(#79) fix the undefined references problem for debug-assertions+lto -case $1 in - thumb*) - RUSTFLAGS="-C debug-assertions=no" xargo rustc --features 'c mem' --target $1 --example intrinsics -- -C lto -C link-arg=-nostartfiles - xargo rustc --features 'c mem' --target $1 --example intrinsics --release -- -C lto - ;; - *) - RUSTFLAGS="-C debug-assertions=no" cargo rustc --features 'c mem' --target $1 --example intrinsics -- -C lto - cargo rustc --features 'c mem' --target $1 --example intrinsics --release -- -C lto - ;; -esac - PREFIX=$(echo $1 | sed -e 's/unknown-//')- case $1 in armv7-*) @@ -109,9 +96,24 @@ for rlib in $(echo $path); do set -ex done +rm -f $path + +# Verify that there are no undefined symbols to `panic` within our implementations +# TODO(#79) fix the undefined references problem for debug-assertions+lto +case $1 in + thumb*) + RUSTFLAGS="-C debug-assertions=no" xargo rustc --features 'c mem' --target $1 --example intrinsics -- -C lto -C link-arg=-nostartfiles + xargo rustc --features 'c mem' --target $1 --example intrinsics --release -- -C lto + ;; + *) + RUSTFLAGS="-C debug-assertions=no" cargo rustc --features 'c mem' --target $1 --example intrinsics -- -C lto + cargo rustc --features 'c mem' --target $1 --example intrinsics --release -- -C lto + ;; +esac + # Ensure no references to a panicking function for rlib in $(echo $path); do - set +x + set +ex $PREFIX$NM -u $rlib 2>&1 | grep panicking if test $? = 0; then diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index cf960c5aa1ab9..6e1c8f2b0b2d7 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -60,64 +60,6 @@ pub unsafe fn __aeabi_ldivmod() { intrinsics::unreachable(); } -#[cfg_attr(not(test), no_mangle)] -pub extern "aapcs" fn __aeabi_dadd(a: f64, b: f64) -> f64 { - ::float::add::__adddf3(a, b) -} - -#[cfg_attr(not(test), no_mangle)] -pub extern "aapcs" fn __aeabi_fadd(a: f32, b: f32) -> f32 { - ::float::add::__addsf3(a, b) -} - -#[cfg_attr(not(test), no_mangle)] -pub extern "aapcs" fn __aeabi_dsub(a: f64, b: f64) -> f64 { - ::float::sub::__subdf3(a, b) -} - -#[cfg_attr(not(test), no_mangle)] -pub extern "aapcs" fn __aeabi_fsub(a: f32, b: f32) -> f32 { - ::float::sub::__subsf3(a, b) -} - -#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] -#[cfg_attr(not(test), no_mangle)] -pub extern "aapcs" fn __aeabi_idiv(a: i32, b: i32) -> i32 { - ::int::sdiv::__divsi3(a, b) -} - -#[cfg_attr(not(test), no_mangle)] -pub extern "aapcs" fn __aeabi_lasr(a: i64, b: u32) -> i64 { - ::int::shift::__ashrdi3(a, b) -} - -#[cfg_attr(not(test), no_mangle)] -pub extern "aapcs" fn __aeabi_llsl(a: u64, b: u32) -> u64 { - ::int::shift::__ashldi3(a, b) -} - -#[cfg_attr(not(test), no_mangle)] -pub extern "aapcs" fn __aeabi_llsr(a: u64, b: u32) -> u64 { - ::int::shift::__lshrdi3(a, b) -} - -#[cfg_attr(not(test), no_mangle)] -pub extern "aapcs" fn __aeabi_lmul(a: u64, b: u64) -> u64 { - ::int::mul::__muldi3(a, b) -} - -#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] -#[cfg_attr(not(test), no_mangle)] -pub extern "aapcs" fn __aeabi_uidiv(a: u32, b: u32) -> u32 { - ::int::udiv::__udivsi3(a, b) -} - -#[cfg(not(feature = "c"))] -#[cfg_attr(not(test), no_mangle)] -pub extern "C" fn __aeabi_ui2d(a: u32) -> f64 { - ::float::conv::__floatunsidf(a) -} - // TODO: These aeabi_* functions should be defined as aliases #[cfg(not(feature = "mem"))] extern "C" { diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 1b1ac3f00875f..696d886fb6978 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -181,11 +181,13 @@ macro_rules! add { intrinsics! { #[aapcs_on_arm] + #[arm_aeabi_alias = __aeabi_fadd] pub extern "C" fn __addsf3(a: f32, b: f32) -> f32 { add!(a, b, f32) } #[aapcs_on_arm] + #[arm_aeabi_alias = __aeabi_dadd] pub extern "C" fn __adddf3(a: f64, b: f64) -> f64 { add!(a, b, f64) } diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index ca05c2830603f..8fc2a2a795111 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -70,15 +70,18 @@ macro_rules! int_to_float { } intrinsics! { + #[arm_aeabi_alias = __aeabi_i2f] pub extern "C" fn __floatsisf(i: i32) -> f32 { int_to_float!(i, i32, f32) } + #[arm_aeabi_alias = __aeabi_i2d] pub extern "C" fn __floatsidf(i: i32) -> f64 { int_to_float!(i, i32, f64) } #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[arm_aeabi_alias = __aeabi_l2d] pub extern "C" fn __floatdidf(i: i64) -> f64 { // On x86_64 LLVM will use native instructions for this conversion, we // can just do it directly @@ -99,16 +102,19 @@ intrinsics! { int_to_float!(i, i128, f64) } + #[arm_aeabi_alias = __aeabi_ui2f] pub extern "C" fn __floatunsisf(i: u32) -> f32 { int_to_float!(i, u32, f32) } + #[arm_aeabi_alias = __aeabi_ui2d] pub extern "C" fn __floatunsidf(i: u32) -> f64 { int_to_float!(i, u32, f64) } #[use_c_shim_if(all(any(target_arch = "x86", target_arch = "x86_64"), not(target_env = "msvc")))] + #[arm_aeabi_alias = __aeabi_ul2d] pub extern "C" fn __floatundidf(i: u64) -> f64 { int_to_float!(i, u64, f64) } @@ -182,10 +188,12 @@ macro_rules! float_to_int { } intrinsics! { + #[arm_aeabi_alias = __aeabi_f2iz] pub extern "C" fn __fixsfsi(f: f32) -> i32 { float_to_int!(f, f32, i32) } + #[arm_aeabi_alias = __aeabi_f2lz] pub extern "C" fn __fixsfdi(f: f32) -> i64 { float_to_int!(f, f32, i64) } @@ -195,10 +203,12 @@ intrinsics! { float_to_int!(f, f32, i128) } + #[arm_aeabi_alias = __aeabi_d2iz] pub extern "C" fn __fixdfsi(f: f64) -> i32 { float_to_int!(f, f64, i32) } + #[arm_aeabi_alias = __aeabi_d2lz] pub extern "C" fn __fixdfdi(f: f64) -> i64 { float_to_int!(f, f64, i64) } @@ -208,10 +218,12 @@ intrinsics! { float_to_int!(f, f64, i128) } + #[arm_aeabi_alias = __aeabi_f2uiz] pub extern "C" fn __fixunssfsi(f: f32) -> u32 { float_to_int!(f, f32, u32) } + #[arm_aeabi_alias = __aeabi_f2ulz] pub extern "C" fn __fixunssfdi(f: f32) -> u64 { float_to_int!(f, f32, u64) } @@ -221,10 +233,12 @@ intrinsics! { float_to_int!(f, f32, u128) } + #[arm_aeabi_alias = __aeabi_d2uiz] pub extern "C" fn __fixunsdfsi(f: f64) -> u32 { float_to_int!(f, f64, u32) } + #[arm_aeabi_alias = __aeabi_d2ulz] pub extern "C" fn __fixunsdfdi(f: f64) -> u64 { float_to_int!(f, f64, u64) } diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index a82a9437e0f97..4fa436db6136c 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -1,10 +1,12 @@ use float::Float; intrinsics! { + #[arm_aeabi_alias = __aeabi_fsub] pub extern "C" fn __subsf3(a: f32, b: f32) -> f32 { a + f32::from_repr(b.repr() ^ f32::sign_mask()) } + #[arm_aeabi_alias = __aeabi_dsub] pub extern "C" fn __subdf3(a: f64, b: f64) -> f64 { a + f64::from_repr(b.repr() ^ f64::sign_mask()) } diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 9241ee6a4c03c..d61a6b474cdcc 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -72,6 +72,7 @@ impl Mulo for i128 {} intrinsics! { #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[arm_aeabi_alias = __aeabi_lmul] pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 { a.mul(b) } diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 8d856303755c0..6ce7ffd42ce40 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -60,6 +60,7 @@ impl Divmod for i64 {} intrinsics! { #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), not(thumbv6m)))] + #[arm_aeabi_alias = __aeabi_idiv] pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 { a.div(b) } diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index b0103ceaf205d..a9b6c05d3d34c 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -66,6 +66,7 @@ impl Lshr for u128 {} intrinsics! { #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[arm_aeabi_alias = __aeabi_llsl] pub extern "C" fn __ashldi3(a: u64, b: u32) -> u64 { a.ashl(b) } @@ -75,6 +76,7 @@ intrinsics! { } #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[arm_aeabi_alias = __aeabi_lasr] pub extern "C" fn __ashrdi3(a: i64, b: u32) -> i64 { a.ashr(b) } @@ -84,6 +86,7 @@ intrinsics! { } #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[arm_aeabi_alias = __aeabi_llsr] pub extern "C" fn __lshrdi3(a: u64, b: u32) -> u64 { a.lshr(b) } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 90ac729bf98d2..27baff95775ca 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -155,6 +155,7 @@ intrinsics! { #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), not(thumbv6m)))] + #[arm_aeabi_alias = __aeabi_uidiv] /// Returns `n / d` pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { // Special cases diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 740eae293858a..2e65e9659f406 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -7,7 +7,7 @@ macro_rules! intrinsics { // intrinsic. ( #[use_c_shim_if($($cfg_clause:tt)*)] - $(#[$attr:meta])* + $(#[$($attr:tt)*])* pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { $($body:tt)* } @@ -16,7 +16,6 @@ macro_rules! intrinsics { ) => ( #[cfg(all(feature = "c", $($cfg_clause)*))] - $(#[$attr])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { extern $abi { fn $name($($argname: $ty),*) -> $ret; @@ -28,7 +27,7 @@ macro_rules! intrinsics { #[cfg(not(all(feature = "c", $($cfg_clause)*)))] intrinsics! { - $(#[$attr])* + $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } @@ -42,7 +41,7 @@ macro_rules! intrinsics { // ARM and `"C"` elsewhere. ( #[aapcs_on_arm] - $(#[$attr:meta])* + $(#[$($attr:tt)*])* pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { $($body:tt)* } @@ -51,7 +50,7 @@ macro_rules! intrinsics { ) => ( #[cfg(target_arch = "arm")] intrinsics! { - $(#[$attr])* + $(#[$($attr)*])* pub extern "aapcs" fn $name( $($argname: $ty),* ) -> $ret { $($body)* } @@ -59,7 +58,7 @@ macro_rules! intrinsics { #[cfg(not(target_arch = "arm"))] intrinsics! { - $(#[$attr])* + $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } @@ -72,7 +71,7 @@ macro_rules! intrinsics { // win64 for some methods. ( #[unadjusted_on_win64] - $(#[$attr:meta])* + $(#[$($attr:tt)*])* pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { $($body:tt)* } @@ -81,7 +80,7 @@ macro_rules! intrinsics { ) => ( #[cfg(all(windows, target_pointer_width = "64"))] intrinsics! { - $(#[$attr])* + $(#[$($attr)*])* pub extern "unadjusted" fn $name( $($argname: $ty),* ) -> $ret { $($body)* } @@ -89,7 +88,7 @@ macro_rules! intrinsics { #[cfg(not(all(windows, target_pointer_width = "64")))] intrinsics! { - $(#[$attr])* + $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } @@ -102,7 +101,7 @@ macro_rules! intrinsics { // bit calling convention correct. ( #[win64_128bit_abi_hack] - $(#[$attr:meta])* + $(#[$($attr:tt)*])* pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { $($body:tt)* } @@ -110,7 +109,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( #[cfg(all(windows, target_pointer_width = "64"))] - $(#[$attr])* + $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } @@ -130,7 +129,7 @@ macro_rules! intrinsics { #[cfg(not(all(windows, target_pointer_width = "64")))] intrinsics! { - $(#[$attr])* + $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } @@ -139,15 +138,57 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); + // A bunch of intrinsics on ARM are aliased in the standard compiler-rt + // build under `__aeabi_*` aliases, and LLVM will call these instead of the + // original function. Handle that here ( - $(#[$attr:meta])* + #[arm_aeabi_alias = $alias:ident] + $(#[$($attr:tt)*])* pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { $($body:tt)* } $($rest:tt)* ) => ( - $(#[$attr])* + #[cfg(target_arch = "arm")] + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + $($body)* + } + + #[cfg(target_arch = "arm")] + pub mod $name { + intrinsics! { + pub extern "aapcs" fn $alias( $($argname: $ty),* ) -> $ret { + super::$name($($argname),*) + } + + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + super::$name($($argname),*) + } + } + } + + #[cfg(not(target_arch = "arm"))] + intrinsics! { + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + + ( + $(#[$($attr:tt)*])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + $(#[$($attr)*])* #[cfg_attr(not(test), no_mangle)] pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* From e8efe11f71c6ca4f04340aa0ac5678a47e789909 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 16:28:50 -0700 Subject: [PATCH 0337/4206] Shore up docs in the macros module --- library/compiler-builtins/src/macros.rs | 89 +++++++++++++++++++++---- 1 file changed, 77 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 2e65e9659f406..6e34066f19f86 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -1,10 +1,63 @@ +//! Macros shared throughout the compiler-builtins implementation + +/// The "main macro" used for defining intrinsics. +/// +/// The compiler-builtins library is super platform-specific with tons of crazy +/// little tweaks for various platforms. As a result it *could* involve a lot fo +/// #[cfg] and macro soup, but the intention is that this macro alleviates a lof +/// of that complexity. Ideally this macro has all the weird ABI things +/// platforms need and elsewhere in this library it just looks like normal Rust +/// code. +/// +/// This macro is structured to be invoked with a bunch of functions that looks +/// like: +/// +/// intrinsics! { +/// pub extern "C" fn foo(a: i32) -> u32 { +/// // ... +/// } +/// +/// #[nonstandard_attribute] +/// pub extern "C" fn bar(a: i32) -> u32 { +/// // ... +/// } +/// } +/// +/// Each function is defined in a manner that looks like a normal Rust function. +/// The macro then accepts a few nonstandard attributes that can decorate +/// various functions. Each of the attributes is documented below with what it +/// can do, and each of them slightly tweaks how further expansion happens. +/// +/// A quick overview of attributes supported right now are: +/// +/// * `use_c_shim_if` - takes a #[cfg] directive and falls back to the +/// C-compiled version if `feature = "c"` is specified. +/// * `aapcs_on_arm` - forces the ABI of the function to be `"aapcs"` on ARM and +/// the specified ABI everywhere else. +/// * `unadjusted_on_win64` - like `aapcs_on_arm` this switches to the +/// `"unadjusted"` abi on Win64 and the specified abi elsewhere. +/// * `win64_128bit_abi_hack` - this attribute is used for 128-bit integer +/// intrinsics where the ABI is slightly tweaked on Windows platforms, but +/// it's a normal ABI elsewhere for returning a 128 bit integer. +/// * `arm_aeabi_alias` - handles the "aliasing" of various intrinsics on ARM +/// their otherwise typical names to other prefixed ones. +/// macro_rules! intrinsics { () => (); - // Anything which has a `not(feature = "c")` we'll generate a shim function - // which calls out to the C function if the `c` feature is enabled. - // Otherwise if the `c` feature isn't enabled then we'll just have a normal - // intrinsic. + // Right now there's a bunch of architecture-optimized intrinsics in the + // stock compiler-rt implementation. Not all of these have been ported over + // to Rust yet so when the `c` feature of this crate is enabled we fall back + // to the architecture-specific versions which should be more optimized. The + // purpose of this macro is to easily allow specifying this. + // + // The argument to `use_c_shim_if` is a `#[cfg]` directive which, when true, + // will cause this crate's exported version of `$name` to just redirect to + // the C implementation. No symbol named `$name` will be in the object file + // for this crate itself. + // + // When the `#[cfg]` directive is false, or when the `c` feature is + // disabled, the provided implementation is used instead. ( #[use_c_shim_if($($cfg_clause:tt)*)] $(#[$($attr:tt)*])* @@ -97,8 +150,13 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); - // Another attribute we recognize is an "abi hack" for win64 to get the 128 - // bit calling convention correct. + // Some intrinsics on win64 which return a 128-bit integer have an.. unusual + // calling convention. That's managed here with this "abi hack" which alters + // the generated symbol's ABI. + // + // This will still define a function in this crate with the given name and + // signature, but the actual symbol for the intrinsic may have a slightly + // different ABI on win64. ( #[win64_128bit_abi_hack] $(#[$($attr:tt)*])* @@ -119,10 +177,10 @@ macro_rules! intrinsics { intrinsics! { pub extern $abi fn $name( $($argname: $ty),* ) - -> ::macros::win64_abi_hack::U64x2 + -> ::macros::win64_128bit_abi_hack::U64x2 { let e: $ret = super::$name($($argname),*); - ::macros::win64_abi_hack::U64x2::from(e) + ::macros::win64_128bit_abi_hack::U64x2::from(e) } } } @@ -140,7 +198,8 @@ macro_rules! intrinsics { // A bunch of intrinsics on ARM are aliased in the standard compiler-rt // build under `__aeabi_*` aliases, and LLVM will call these instead of the - // original function. Handle that here + // original function. The aliasing here is used to generate these symbols in + // the object file. ( #[arm_aeabi_alias = $alias:ident] $(#[$($attr:tt)*])* @@ -151,7 +210,6 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( #[cfg(target_arch = "arm")] - $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } @@ -180,6 +238,12 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); + // This is the final catch-all rule. At this point we just generate an + // intrinsic with a conditional `#[no_mangle]` directive to avoid + // interfereing with duplicate symbols and whatnot. + // + // After the intrinsic is defined we just continue with the rest of the + // input we were given. ( $(#[$($attr:tt)*])* pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { @@ -198,9 +262,10 @@ macro_rules! intrinsics { ); } -// Hack for LLVM expectations for ABI on windows +// Hack for LLVM expectations for ABI on windows. This is used by the +// `#[win64_128bit_abi_hack]` attribute recognized above #[cfg(all(windows, target_pointer_width="64"))] -pub mod win64_abi_hack { +pub mod win64_128bit_abi_hack { #[repr(simd)] pub struct U64x2(u64, u64); From 4bb783da70e7fa61fd3c01a957d9c85ac497297e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 20:20:42 -0700 Subject: [PATCH 0338/4206] Remove the travis cache --- library/compiler-builtins/.travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index fa9a27866afe1..8a9d1faa1dca2 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -1,4 +1,3 @@ -cache: cargo dist: trusty language: rust rust: nightly @@ -52,8 +51,6 @@ script: else sh ci/run.sh $TARGET; fi - # Travis can't cache files that are not readable by "others" - - chmod -R a+r $HOME/.cargo notifications: email: From af944595d07e2a66d1f518096e666d7f7ea0eda9 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 20:35:25 -0700 Subject: [PATCH 0339/4206] Try testing MinGW targets --- library/compiler-builtins/appveyor.yml | 21 ++++++++++++-- .../compiler-builtins/examples/intrinsics.rs | 28 +++++++++++-------- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 2dce7ceb6df2a..70049bf5130c2 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -3,12 +3,29 @@ environment: - TARGET: i686-pc-windows-msvc - TARGET: x86_64-pc-windows-msvc + # Ensure MinGW works, but we need to download the 32-bit MinGW compiler from a + # custom location. + - TARGET: i686-pc-windows-gnu + MINGW_URL: https://s3.amazonaws.com/rust-lang-ci + MINGW_ARCHIVE: i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z + MINGW_DIR: mingw32 + - TARGET: x86_64-pc-windows-gnu + MSYS_BITS: 64 + install: - git submodule update --init - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - rustup-init.exe --default-host x86_64-pc-windows-msvc --default-toolchain nightly -y - - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - - if "%TARGET%"=="i686-pc-windows-msvc" ( rustup target add %TARGET% ) + - if NOT "%TARGET%" == "x86_64-pc-windows-msvc" rustup target add %TARGET% + + # Use the system msys if we can + - if defined MSYS_BITS set PATH=C:\msys64\mingw%MSYS_BITS%\bin;C:\msys64\usr\bin;%PATH% + + # download a custom compiler otherwise + - if defined MINGW_URL appveyor DownloadFile %MINGW_URL%/%MINGW_ARCHIVE% + - if defined MINGW_URL 7z x -y %MINGW_ARCHIVE% > nul + - if defined MINGW_URL set PATH=C:\Python27;%CD%\%MINGW_DIR%\bin;C:\msys64\usr\bin;%PATH% + - rustc -Vv - cargo -V diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index cabe917641fae..7db241eddbb01 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -12,12 +12,14 @@ #![feature(core_float)] #![feature(lang_items)] #![feature(start)] +#![feature(panic_unwind)] #![feature(i128_type)] #![no_std] #[cfg(not(thumb))] extern crate alloc_system; extern crate compiler_builtins; +extern crate panic_unwind; // NOTE cfg(not(thumbv6m)) means that the operation is not supported on ARMv6-M at all. Not even // compiler-rt provides a C/assembly implementation. @@ -400,6 +402,20 @@ fn run() { bb(umodti3(bb(2), bb(2))); bb(divti3(bb(2), bb(2))); bb(modti3(bb(2), bb(2))); + + something_with_a_dtor(&|| assert_eq!(bb(1), 1)); +} + +fn something_with_a_dtor(f: &Fn()) { + struct A<'a>(&'a (Fn() + 'a)); + + impl<'a> Drop for A<'a> { + fn drop(&mut self) { + (self.0)(); + } + } + let _a = A(f); + f(); } #[cfg(not(thumb))] @@ -428,18 +444,6 @@ pub fn __aeabi_unwind_cpp_pr0() {} #[no_mangle] pub fn __aeabi_unwind_cpp_pr1() {} -// Avoid "undefined reference to `_Unwind_Resume`" errors -#[allow(non_snake_case)] -#[no_mangle] -pub fn _Unwind_Resume() {} - -// Lang items -#[cfg(not(test))] -#[lang = "eh_personality"] -#[no_mangle] -#[allow(private_no_mangle_fns)] -extern "C" fn eh_personality() {} - #[cfg(not(test))] #[lang = "panic_fmt"] #[no_mangle] From bbaf9fd85a9b7b59df028a1963100ba371136ac1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 20:43:51 -0700 Subject: [PATCH 0340/4206] Don't build chkstk on x86_64 --- library/compiler-builtins/build.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index e66b3ab3bbeab..7c09987ad0ae7 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4145,8 +4145,6 @@ mod c { if target_arch == "x86_64" { sources.extend( &[ - "x86_64/chkstk.S", - "x86_64/chkstk2.S", "x86_64/floatdisf.c", "x86_64/floatdixf.c", "x86_64/floatundidf.S", From d3e78c5f6f338db025b685dab29495fdb84c20d7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 21:09:24 -0700 Subject: [PATCH 0341/4206] Don't compile assembly on x86_64 Windows They've all got the wrong ABI... --- library/compiler-builtins/build.rs | 24 ++++++++++++--------- library/compiler-builtins/src/float/conv.rs | 2 +- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 7c09987ad0ae7..06e1155bae401 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4142,16 +4142,20 @@ mod c { sources.extend(&["gcc_personality_v0.c"]); } - if target_arch == "x86_64" { - sources.extend( - &[ - "x86_64/floatdisf.c", - "x86_64/floatdixf.c", - "x86_64/floatundidf.S", - "x86_64/floatundisf.S", - "x86_64/floatundixf.S", - ], - ); + // None of these seem to be used on x86_64 windows, and they've all + // got the wrong ABI anyway, so we want to avoid them. + if target_os != "windows" { + if target_arch == "x86_64" { + sources.extend( + &[ + "x86_64/floatdisf.c", + "x86_64/floatdixf.c", + "x86_64/floatundidf.S", + "x86_64/floatundisf.S", + "x86_64/floatundixf.S", + ], + ); + } } if target_arch == "x86" { diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 8fc2a2a795111..ec77f2bf873e8 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -113,7 +113,7 @@ intrinsics! { } #[use_c_shim_if(all(any(target_arch = "x86", target_arch = "x86_64"), - not(target_env = "msvc")))] + not(windows)))] #[arm_aeabi_alias = __aeabi_ul2d] pub extern "C" fn __floatundidf(i: u64) -> f64 { int_to_float!(i, u64, f64) From d5279752b062b1749a93c0b229e82bafb255fe1b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 21:11:31 -0700 Subject: [PATCH 0342/4206] Don't derive Debug for Sign --- library/compiler-builtins/src/float/conv.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index ec77f2bf873e8..e12349cfff99f 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -130,7 +130,7 @@ intrinsics! { } } -#[derive(PartialEq, Debug)] +#[derive(PartialEq)] enum Sign { Positive, Negative From 80112d198d8bc429d91c8984878e858cd832b802 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 21:23:52 -0700 Subject: [PATCH 0343/4206] Use the same CI script on AppVeyor --- library/compiler-builtins/appveyor.yml | 14 +++----------- library/compiler-builtins/ci/run.sh | 6 +++--- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 70049bf5130c2..6a602132f65b2 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -10,7 +10,6 @@ environment: MINGW_ARCHIVE: i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z MINGW_DIR: mingw32 - TARGET: x86_64-pc-windows-gnu - MSYS_BITS: 64 install: - git submodule update --init @@ -18,8 +17,8 @@ install: - rustup-init.exe --default-host x86_64-pc-windows-msvc --default-toolchain nightly -y - if NOT "%TARGET%" == "x86_64-pc-windows-msvc" rustup target add %TARGET% - # Use the system msys if we can - - if defined MSYS_BITS set PATH=C:\msys64\mingw%MSYS_BITS%\bin;C:\msys64\usr\bin;%PATH% + # Use the system msys + - set PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH% # download a custom compiler otherwise - if defined MINGW_URL appveyor DownloadFile %MINGW_URL%/%MINGW_ARCHIVE% @@ -32,11 +31,4 @@ install: build: false test_script: - - cargo build --target %TARGET% - - cargo build --target %TARGET% --features c --example intrinsics - - cargo build --release --target %TARGET% - - cargo build --release --target %TARGET% --features c --example intrinsics - - cargo test --no-default-features --features gen-tests --target %TARGET% - - cargo test --no-default-features --features "gen-tests c" --target %TARGET% - - cargo test --no-default-features --features gen-tests --release --target %TARGET% - - cargo test --no-default-features --features "gen-tests c" --release --target %TARGET% + - sh ci/run.sh %TARGET% diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index f61b90f81759b..c727bdfb96940 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -75,10 +75,10 @@ case "$TRAVIS_OS_NAME" in ;; esac -if [ "$TRAVIS_OS_NAME" = osx ]; then - path=target/${1}/debug/deps/libcompiler_builtins-*.rlib -else +if [ -d /target ]; then path=/target/${1}/debug/deps/libcompiler_builtins-*.rlib +else + path=target/${1}/debug/deps/libcompiler_builtins-*.rlib fi # Look out for duplicated symbols when we include the compiler-rt (C) implementation From c785055bd9bc9f11c6c0ae4d2c76b544575d40f2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 21:31:54 -0700 Subject: [PATCH 0344/4206] Remove usage of unwrap_or_else --- library/compiler-builtins/src/float/pow.rs | 4 +++- library/compiler-builtins/src/int/mod.rs | 27 ++++++++++++++-------- library/compiler-builtins/src/int/mul.rs | 4 ++-- library/compiler-builtins/src/int/sdiv.rs | 6 ++--- library/compiler-builtins/src/int/udiv.rs | 12 ++++------ 5 files changed, 28 insertions(+), 25 deletions(-) diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index f5c5757d8bc42..bc15dc088879c 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -1,3 +1,5 @@ +use int::Int; + /// Returns `a` raised to the power `b` macro_rules! pow { ($a: expr, $b: expr) => ({ @@ -8,7 +10,7 @@ macro_rules! pow { if (b & 1) != 0 { r *= a; } - b = b.checked_div(2).unwrap_or_else(|| ::abort()); + b = b.aborting_div(2); if b == 0 { break; } diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 9ad3d88852fb8..0334a4acb8ba7 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -66,8 +66,15 @@ pub trait Int: fn wrapping_add(self, other: Self) -> Self; fn wrapping_mul(self, other: Self) -> Self; fn wrapping_sub(self, other: Self) -> Self; - fn checked_div(self, other: Self) -> Option; - fn checked_rem(self, other: Self) -> Option; + fn aborting_div(self, other: Self) -> Self; + fn aborting_rem(self, other: Self) -> Self; +} + +fn unwrap(t: Option) -> T { + match t { + Some(t) => t, + None => ::abort(), + } } macro_rules! int_impl { @@ -120,12 +127,12 @@ macro_rules! int_impl { ::wrapping_sub(self, other) } - fn checked_div(self, other: Self) -> Option { - ::checked_div(self, other) + fn aborting_div(self, other: Self) -> Self { + unwrap(::checked_div(self, other)) } - fn checked_rem(self, other: Self) -> Option { - ::checked_rem(self, other) + fn aborting_rem(self, other: Self) -> Self { + unwrap(::checked_rem(self, other)) } } @@ -181,12 +188,12 @@ macro_rules! int_impl { ::wrapping_sub(self, other) } - fn checked_div(self, other: Self) -> Option { - ::checked_div(self, other) + fn aborting_div(self, other: Self) -> Self { + unwrap(::checked_div(self, other)) } - fn checked_rem(self, other: Self) -> Option { - ::checked_rem(self, other) + fn aborting_rem(self, other: Self) -> Self { + unwrap(::checked_rem(self, other)) } } } diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index d61a6b474cdcc..98a8987e1d49f 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -54,11 +54,11 @@ trait Mulo: Int + ops::Neg { return result; } if sa == sb { - if abs_a > Self::max_value().checked_div(abs_b).unwrap_or_else(|| ::abort()) { + if abs_a > Self::max_value().aborting_div(abs_b) { *overflow = 1; } } else { - if abs_a > Self::min_value().checked_div(-abs_b).unwrap_or_else(|| ::abort()) { + if abs_a > Self::min_value().aborting_div(-abs_b) { *overflow = 1; } } diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 6ce7ffd42ce40..6dd090f394a75 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -13,8 +13,7 @@ trait Div: Int { let b = (other ^ s_b).wrapping_sub(s_b); let s = s_a ^ s_b; - let r = a.unsigned().checked_div(b.unsigned()) - .unwrap_or_else(|| ::abort()); + let r = a.unsigned().aborting_div(b.unsigned()); (Self::from_unsigned(r) ^ s) - s } } @@ -32,8 +31,7 @@ trait Mod: Int { let s = self >> (Self::bits() - 1); let a = (self ^ s).wrapping_sub(s); - let r = a.unsigned().checked_rem(b.unsigned()) - .unwrap_or_else(|| ::abort()); + let r = a.unsigned().aborting_rem(b.unsigned()); (Self::from_unsigned(r) ^ s) - s } } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 27baff95775ca..471f01d078ac5 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -11,11 +11,9 @@ macro_rules! udivmod_inner { // 0 X if let Some(rem) = rem { - *rem = <$ty>::from(n.low().checked_rem(d.low()) - .unwrap_or_else(|| ::abort())); + *rem = <$ty>::from(n.low().aborting_rem(d.low())); } - return <$ty>::from(n.low().checked_div(d.low()) - .unwrap_or_else(|| ::abort())); + return <$ty>::from(n.low().aborting_div(d.low())) } else { // 0 X // --- @@ -46,11 +44,9 @@ macro_rules! udivmod_inner { // --- // K 0 if let Some(rem) = rem { - *rem = <$ty>::from_parts(0, n.high().checked_rem(d.high()) - .unwrap_or_else(|| ::abort())); + *rem = <$ty>::from_parts(0, n.high().aborting_rem(d.high())); } - return <$ty>::from(n.high().checked_div(d.high()) - .unwrap_or_else(|| ::abort())); + return <$ty>::from(n.high().aborting_div(d.high())) } // K K From 1614443a6886c5ba2b0ef9adc01635ed5bf70bf6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 21:36:36 -0700 Subject: [PATCH 0345/4206] Try to fix run.sh on AppVeyor --- library/compiler-builtins/appveyor.yml | 2 ++ library/compiler-builtins/ci/run.sh | 38 ++++++++++++++------------ 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 6a602132f65b2..1eaaf76591734 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -1,4 +1,6 @@ environment: + DEBUG_LTO_BUILD_DOESNT_WORK: 1 + INTRINSICS_FAILS_WITH_MEM_FEATURE: 1 matrix: - TARGET: i686-pc-windows-msvc - TARGET: x86_64-pc-windows-msvc diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index c727bdfb96940..eb60636af2892 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -1,5 +1,19 @@ set -ex +case $1 in + thumb*) + cargo=xargo + ;; + *) + cargo=cargo + ;; +esac + +INTRINSICS_FEATURES="c" +if [ -z "$INTRINSICS_FAILS_WITH_MEM_FEATURE" ]; then + INTRINSICS_FEATURES="$INTRINSICS_FEATURES mem" +fi + # Test our implementation case $1 in thumb*) @@ -41,14 +55,7 @@ case $1 in esac # Verify that we haven't drop any intrinsic/symbol -case $1 in - thumb*) - xargo build --features 'c mem' --target $1 --example intrinsics - ;; - *) - cargo build --features 'c mem' --target $1 --example intrinsics - ;; -esac +$cargo build --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics PREFIX=$(echo $1 | sed -e 's/unknown-//')- case $1 in @@ -100,16 +107,11 @@ rm -f $path # Verify that there are no undefined symbols to `panic` within our implementations # TODO(#79) fix the undefined references problem for debug-assertions+lto -case $1 in - thumb*) - RUSTFLAGS="-C debug-assertions=no" xargo rustc --features 'c mem' --target $1 --example intrinsics -- -C lto -C link-arg=-nostartfiles - xargo rustc --features 'c mem' --target $1 --example intrinsics --release -- -C lto - ;; - *) - RUSTFLAGS="-C debug-assertions=no" cargo rustc --features 'c mem' --target $1 --example intrinsics -- -C lto - cargo rustc --features 'c mem' --target $1 --example intrinsics --release -- -C lto - ;; -esac +if [ -z "$DEBUG_LTO_BUILD_DOESNT_WORK" ]; then + RUSTFLAGS="-C debug-assertions=no" \ + $cargo rustc --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics -- -C lto +fi +$cargo rustc --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics --release -- -C lto # Ensure no references to a panicking function for rlib in $(echo $path); do From 4dfb2c5f097c918f624011b401e31abdac593ad4 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Jun 2017 21:38:55 -0700 Subject: [PATCH 0346/4206] Fix appveyor PATH --- library/compiler-builtins/appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index 1eaaf76591734..ebc903560f603 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -17,6 +17,7 @@ install: - git submodule update --init - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - rustup-init.exe --default-host x86_64-pc-windows-msvc --default-toolchain nightly -y + - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - if NOT "%TARGET%" == "x86_64-pc-windows-msvc" rustup target add %TARGET% # Use the system msys From cec593c2aa1acaad439760387604fb3a1ecc2aa2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 24 Jun 2017 10:04:00 -0700 Subject: [PATCH 0347/4206] Tweak testing and such: * Don't run `intrinsics` tests on thumb * Disable `compiler_builtins` attribute on `feature = "gen-tests"` * Disable mangling on `feature = "gen-tests"` instead of `cfg(test)` --- library/compiler-builtins/Cargo.toml | 7 ++++-- library/compiler-builtins/appveyor.yml | 10 +++++++- library/compiler-builtins/ci/run.sh | 32 ++++++++++++++++++------- library/compiler-builtins/src/lib.rs | 3 ++- library/compiler-builtins/src/macros.rs | 4 ++-- 5 files changed, 42 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 08bf5fd02f71f..c717311d8fc40 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -18,7 +18,12 @@ compiler-builtins = [] default = ["compiler-builtins"] mem = [] rustbuild = ["compiler-builtins"] + # generate tests +# +# Note that this is an internal-only feature used in testing, this should not +# be relied on with crates.io! Enabling this may expose you to breaking +# changes. gen-tests = ["cast", "rand"] [target.'cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux"))'.dev-dependencies] @@ -26,10 +31,8 @@ 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" } - [[example]] name = "intrinsics" required-features = ["c", "compiler-builtins"] - [workspace] diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index ebc903560f603..e51ddab740e32 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -1,17 +1,25 @@ environment: - DEBUG_LTO_BUILD_DOESNT_WORK: 1 + # It's... a little unclear why the memcpy symbols clash on linux but not on + # other platforms. Would be great to not differ on this though! INTRINSICS_FAILS_WITH_MEM_FEATURE: 1 + matrix: - TARGET: i686-pc-windows-msvc - TARGET: x86_64-pc-windows-msvc # Ensure MinGW works, but we need to download the 32-bit MinGW compiler from a # custom location. + # + # Note that the MinGW builds have tons of references to + # `rust_eh_unwind_resume` in the debug LTO builds that aren't optimized out, + # so we skip that test for now. Would be great to not skip it! - TARGET: i686-pc-windows-gnu MINGW_URL: https://s3.amazonaws.com/rust-lang-ci MINGW_ARCHIVE: i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z MINGW_DIR: mingw32 + DEBUG_LTO_BUILD_DOESNT_WORK: 1 - TARGET: x86_64-pc-windows-gnu + DEBUG_LTO_BUILD_DOESNT_WORK: 1 install: - git submodule update --init diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index eb60636af2892..f1acaced8e999 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -10,6 +10,10 @@ case $1 in esac INTRINSICS_FEATURES="c" + +# Some architectures like ARM apparently seem to require the `mem` feature +# enabled to successfully compile the `intrinsics` example, and... we're not +# sure why! if [ -z "$INTRINSICS_FAILS_WITH_MEM_FEATURE" ]; then INTRINSICS_FEATURES="$INTRINSICS_FEATURES mem" fi @@ -47,16 +51,13 @@ case $1 in done ;; *) - cargo test --no-default-features --features gen-tests --target $1 - cargo test --no-default-features --features 'gen-tests c' --target $1 - cargo test --no-default-features --features gen-tests --target $1 --release - cargo test --no-default-features --features 'gen-tests c' --target $1 --release + cargo test --features gen-tests --target $1 + cargo test --features 'gen-tests c' --target $1 + cargo test --features gen-tests --target $1 --release + cargo test --features 'gen-tests c' --target $1 --release ;; esac -# Verify that we haven't drop any intrinsic/symbol -$cargo build --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics - PREFIX=$(echo $1 | sed -e 's/unknown-//')- case $1 in armv7-*) @@ -105,7 +106,22 @@ done rm -f $path -# Verify that there are no undefined symbols to `panic` within our implementations +# Verification of the `intrinsics` program doesn't work on thumb targets right +# now. +case $1 in + thumb*) + exit 0 + ;; + *) + ;; +esac + +# Verify that we haven't drop any intrinsic/symbol +$cargo build --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics + +# Verify that there are no undefined symbols to `panic` within our +# implementations +# # TODO(#79) fix the undefined references problem for debug-assertions+lto if [ -z "$DEBUG_LTO_BUILD_DOESNT_WORK" ]; then RUSTFLAGS="-C debug-assertions=no" \ diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 3fa7923b4475f..3f8a57edfceba 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,6 +1,7 @@ #![cfg_attr(not(stage0), deny(warnings))] #![cfg_attr(not(test), no_std)] -#![cfg_attr(feature = "compiler-builtins", compiler_builtins)] +#![cfg_attr(all(feature = "compiler-builtins", + not(feature = "gen-tests")), compiler_builtins)] #![crate_name = "compiler_builtins"] #![crate_type = "rlib"] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 6e34066f19f86..6bf9d26fc6f0b 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -240,7 +240,7 @@ macro_rules! intrinsics { // This is the final catch-all rule. At this point we just generate an // intrinsic with a conditional `#[no_mangle]` directive to avoid - // interfereing with duplicate symbols and whatnot. + // interfereing with duplicate symbols and whatnot during testing. // // After the intrinsic is defined we just continue with the rest of the // input we were given. @@ -253,7 +253,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( $(#[$($attr)*])* - #[cfg_attr(not(test), no_mangle)] + #[cfg_attr(not(feature = "gen-tests"), no_mangle)] pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } From cf1419e538d81446a52b0d7f00f8731b969676a1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 24 Jun 2017 10:12:17 -0700 Subject: [PATCH 0348/4206] Add a FIXME for Windows --- library/compiler-builtins/ci/run.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index f1acaced8e999..2709617e7e2e2 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -94,9 +94,17 @@ for rlib in $(echo $path); do set +x stdout=$($PREFIX$NM -g --defined-only $rlib 2>&1) - # NOTE On i586, It's normal that the get_pc_thunk symbol appears several times so ignore it + # NOTE On i586, It's normal that the get_pc_thunk symbol appears several + # times so ignore it + # + # FIXME(#167) - we shouldn't ignore `__builtin_cl` style symbols here. set +e - echo "$stdout" | sort | uniq -d | grep -v __x86.get_pc_thunk | grep 'T __' + echo "$stdout" | \ + sort | \ + uniq -d | \ + grep -v __x86.get_pc_thunk | \ + grep -v __builtin_cl | \ + grep 'T __' if test $? = 0; then exit 1 From 90dab55cb0c3e7bb7df26167abbd0b18f56e81c0 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 24 Jun 2017 10:22:49 -0700 Subject: [PATCH 0349/4206] Don't try to work with `cargo test` --- library/compiler-builtins/ci/run.sh | 8 ++++---- library/compiler-builtins/src/lib.rs | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 2709617e7e2e2..bda44156402e2 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -51,10 +51,10 @@ case $1 in done ;; *) - cargo test --features gen-tests --target $1 - cargo test --features 'gen-tests c' --target $1 - cargo test --features gen-tests --target $1 --release - cargo test --features 'gen-tests c' --target $1 --release + cargo test --no-default-features --features gen-tests --target $1 + cargo test --no-default-features --features 'gen-tests c' --target $1 + cargo test --no-default-features --features gen-tests --target $1 --release + cargo test --no-default-features --features 'gen-tests c' --target $1 --release ;; esac diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 3f8a57edfceba..3fa7923b4475f 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,7 +1,6 @@ #![cfg_attr(not(stage0), deny(warnings))] #![cfg_attr(not(test), no_std)] -#![cfg_attr(all(feature = "compiler-builtins", - not(feature = "gen-tests")), compiler_builtins)] +#![cfg_attr(feature = "compiler-builtins", compiler_builtins)] #![crate_name = "compiler_builtins"] #![crate_type = "rlib"] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", From 3eff54a4eeca72cfc10911d30eca24a4dff995c1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 24 Jun 2017 11:34:10 -0700 Subject: [PATCH 0350/4206] Don't generate unmangled aeabi with gen-tests The symbols they delgate to also don't exist... --- library/compiler-builtins/src/arm.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 6e1c8f2b0b2d7..8d5808c82db9e 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -7,6 +7,7 @@ use mem::{memcpy, memmove, memset}; // calling convention which can't be implemented using a normal Rust function #[naked] #[cfg_attr(not(test), no_mangle)] +#[cfg(not(feature = "gen-tests"))] pub unsafe fn __aeabi_uidivmod() { asm!("push {lr} sub sp, sp, #4 @@ -20,6 +21,7 @@ pub unsafe fn __aeabi_uidivmod() { #[naked] #[cfg_attr(not(test), no_mangle)] +#[cfg(not(feature = "gen-tests"))] pub unsafe fn __aeabi_uldivmod() { asm!("push {r4, lr} sub sp, sp, #16 @@ -35,6 +37,7 @@ pub unsafe fn __aeabi_uldivmod() { #[naked] #[cfg_attr(not(test), no_mangle)] +#[cfg(not(feature = "gen-tests"))] pub unsafe fn __aeabi_idivmod() { asm!("push {r0, r1, r4, lr} bl __divsi3 @@ -47,6 +50,7 @@ pub unsafe fn __aeabi_idivmod() { #[naked] #[cfg_attr(not(test), no_mangle)] +#[cfg(not(feature = "gen-tests"))] pub unsafe fn __aeabi_ldivmod() { asm!("push {r4, lr} sub sp, sp, #16 From e8964fc7dd5280fb29f5c99c48a1f8484b7dce55 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 24 Jun 2017 11:36:05 -0700 Subject: [PATCH 0351/4206] Don't build gcc_personality_v0 --- library/compiler-builtins/build.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 06e1155bae401..bfb0ad9797d0e 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4138,10 +4138,6 @@ mod c { ); } } else { - if target_os != "freebsd" && target_os != "netbsd" { - sources.extend(&["gcc_personality_v0.c"]); - } - // None of these seem to be used on x86_64 windows, and they've all // got the wrong ABI anyway, so we want to avoid them. if target_os != "windows" { From e7008c8609c3f017057a33ddf1e529b8e2407976 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 24 Jun 2017 11:43:57 -0700 Subject: [PATCH 0352/4206] Don't check for references to panics with debug assertions --- library/compiler-builtins/ci/run.sh | 3 ++- library/compiler-builtins/src/arm.rs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index bda44156402e2..008d9ca9d44f1 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -125,7 +125,8 @@ case $1 in esac # Verify that we haven't drop any intrinsic/symbol -$cargo build --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics +RUSTFLAGS="-C debug-assertions=no" \ + $cargo build --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics # Verify that there are no undefined symbols to `panic` within our # implementations diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 8d5808c82db9e..1e234b7d88537 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,3 +1,4 @@ +#[cfg(not(feature = "gen-tests"))] use core::intrinsics; #[cfg(feature = "mem")] From 60028c1d9d7f64005dc785263ac7b2d3964ed8ff Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 24 Jun 2017 12:22:31 -0700 Subject: [PATCH 0353/4206] Enable 128-bit integer tests on Windows Closes #158 --- library/compiler-builtins/tests/divti3.rs | 3 +-- library/compiler-builtins/tests/modti3.rs | 3 +-- library/compiler-builtins/tests/udivmodti4.rs | 3 +-- library/compiler-builtins/tests/udivti3.rs | 3 +-- library/compiler-builtins/tests/umodti3.rs | 3 +-- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/library/compiler-builtins/tests/divti3.rs b/library/compiler-builtins/tests/divti3.rs index c86785fe8134b..7919f8fe396a3 100644 --- a/library/compiler-builtins/tests/divti3.rs +++ b/library/compiler-builtins/tests/divti3.rs @@ -6,6 +6,5 @@ test), no_std)] // FIXME(#137) -// FIXME(#158) -#[cfg(not(any(target_arch = "mips", windows)))] +#[cfg(not(target_arch = "mips"))] include!(concat!(env!("OUT_DIR"), "/divti3.rs")); diff --git a/library/compiler-builtins/tests/modti3.rs b/library/compiler-builtins/tests/modti3.rs index 2ce42ac46f4d1..62129cd04d3c3 100644 --- a/library/compiler-builtins/tests/modti3.rs +++ b/library/compiler-builtins/tests/modti3.rs @@ -6,6 +6,5 @@ test), no_std)] // FIXME(#137) -// FIXME(#158) -#[cfg(not(any(target_arch = "mips", windows)))] +#[cfg(not(target_arch = "mips"))] include!(concat!(env!("OUT_DIR"), "/modti3.rs")); diff --git a/library/compiler-builtins/tests/udivmodti4.rs b/library/compiler-builtins/tests/udivmodti4.rs index 5629d617bd376..8185ec0e78971 100644 --- a/library/compiler-builtins/tests/udivmodti4.rs +++ b/library/compiler-builtins/tests/udivmodti4.rs @@ -6,6 +6,5 @@ test), no_std)] // FIXME(#137) -// FIXME(#158) -#[cfg(not(any(target_arch = "mips", windows)))] +#[cfg(not(target_arch = "mips"))] include!(concat!(env!("OUT_DIR"), "/udivmodti4.rs")); diff --git a/library/compiler-builtins/tests/udivti3.rs b/library/compiler-builtins/tests/udivti3.rs index 350922563ffd5..cefddda8f8698 100644 --- a/library/compiler-builtins/tests/udivti3.rs +++ b/library/compiler-builtins/tests/udivti3.rs @@ -6,6 +6,5 @@ test), no_std)] // FIXME(#137) -// FIXME(#158) -#[cfg(not(any(target_arch = "mips", windows)))] +#[cfg(not(target_arch = "mips"))] include!(concat!(env!("OUT_DIR"), "/udivti3.rs")); diff --git a/library/compiler-builtins/tests/umodti3.rs b/library/compiler-builtins/tests/umodti3.rs index 5807bcff395e3..57e651b2710f1 100644 --- a/library/compiler-builtins/tests/umodti3.rs +++ b/library/compiler-builtins/tests/umodti3.rs @@ -6,6 +6,5 @@ test), no_std)] // FIXME(#137) -// FIXME(#158) -#[cfg(not(any(target_arch = "mips", windows)))] +#[cfg(not(target_arch = "mips"))] include!(concat!(env!("OUT_DIR"), "/umodti3.rs")); From f9db3c5b324beef1dd81bd471c13e51d9168a687 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 24 Jun 2017 12:44:00 -0700 Subject: [PATCH 0354/4206] Don't test mangled names on thumb We are both the "real compiler-rt" and the "to be tested one". --- library/compiler-builtins/Cargo.toml | 1 + library/compiler-builtins/ci/run.sh | 9 +++--- library/compiler-builtins/src/arm.rs | 37 +++++++++++-------------- library/compiler-builtins/src/macros.rs | 2 +- library/compiler-builtins/src/mem.rs | 8 +++--- 5 files changed, 27 insertions(+), 30 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index c717311d8fc40..070d8f8c7a0f0 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -18,6 +18,7 @@ compiler-builtins = [] default = ["compiler-builtins"] mem = [] rustbuild = ["compiler-builtins"] +mangled-names = [] # generate tests # diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 008d9ca9d44f1..d285b36653844 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -51,10 +51,11 @@ case $1 in done ;; *) - cargo test --no-default-features --features gen-tests --target $1 - cargo test --no-default-features --features 'gen-tests c' --target $1 - cargo test --no-default-features --features gen-tests --target $1 --release - cargo test --no-default-features --features 'gen-tests c' --target $1 --release + run="cargo test --no-default-features --target $1" + $run --features 'gen-tests mangled-names' + $run --features 'gen-tests mangled-names' --release + $run --features 'gen-tests mangled-names c' + $run --features 'gen-tests mangled-names c' --release ;; esac diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 1e234b7d88537..81e0afdd00b44 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,4 +1,3 @@ -#[cfg(not(feature = "gen-tests"))] use core::intrinsics; #[cfg(feature = "mem")] @@ -7,8 +6,7 @@ use mem::{memcpy, memmove, memset}; // NOTE This function and the ones below are implemented using assembly because they using a custom // calling convention which can't be implemented using a normal Rust function #[naked] -#[cfg_attr(not(test), no_mangle)] -#[cfg(not(feature = "gen-tests"))] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_uidivmod() { asm!("push {lr} sub sp, sp, #4 @@ -21,8 +19,7 @@ pub unsafe fn __aeabi_uidivmod() { } #[naked] -#[cfg_attr(not(test), no_mangle)] -#[cfg(not(feature = "gen-tests"))] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_uldivmod() { asm!("push {r4, lr} sub sp, sp, #16 @@ -37,8 +34,7 @@ pub unsafe fn __aeabi_uldivmod() { } #[naked] -#[cfg_attr(not(test), no_mangle)] -#[cfg(not(feature = "gen-tests"))] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_idivmod() { asm!("push {r0, r1, r4, lr} bl __divsi3 @@ -50,8 +46,7 @@ pub unsafe fn __aeabi_idivmod() { } #[naked] -#[cfg_attr(not(test), no_mangle)] -#[cfg(not(feature = "gen-tests"))] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_ldivmod() { asm!("push {r4, lr} sub sp, sp, #16 @@ -75,55 +70,55 @@ extern "C" { // FIXME: The `*4` and `*8` variants should be defined as aliases. -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { memcpy(dest, src, n); } -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { memcpy(dest, src, n); } -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { memcpy(dest, src, n); } -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { memmove(dest, src, n); } -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { memmove(dest, src, n); } -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { memmove(dest, src, n); } // Note the different argument order -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { memset(dest, c, n); } -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { memset(dest, c, n); } -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { memset(dest, c, n); } -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { memset(dest, 0, n); } -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { memset(dest, 0, n); } -#[cfg_attr(not(test), no_mangle)] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { memset(dest, 0, n); } diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 6bf9d26fc6f0b..188508f5cc673 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -253,7 +253,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( $(#[$($attr)*])* - #[cfg_attr(not(feature = "gen-tests"), no_mangle)] + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } diff --git a/library/compiler-builtins/src/mem.rs b/library/compiler-builtins/src/mem.rs index a7d267c500311..cb8baec273ebc 100644 --- a/library/compiler-builtins/src/mem.rs +++ b/library/compiler-builtins/src/mem.rs @@ -5,7 +5,7 @@ type c_int = i16; #[cfg(not(target_pointer_width = "16"))] type c_int = i32; -#[no_mangle] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) @@ -18,7 +18,7 @@ pub unsafe extern "C" fn memcpy(dest: *mut u8, dest } -#[no_mangle] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) @@ -41,7 +41,7 @@ pub unsafe extern "C" fn memmove(dest: *mut u8, dest } -#[no_mangle] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { let mut i = 0; while i < n { @@ -51,7 +51,7 @@ pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { s } -#[no_mangle] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { let mut i = 0; while i < n { From 0e404583e82cd044b9561e493b3997609cb0fafa Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 24 Jun 2017 21:51:34 -0700 Subject: [PATCH 0355/4206] Address review comments --- library/compiler-builtins/src/macros.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 188508f5cc673..f6d7db709340c 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -3,8 +3,8 @@ /// The "main macro" used for defining intrinsics. /// /// The compiler-builtins library is super platform-specific with tons of crazy -/// little tweaks for various platforms. As a result it *could* involve a lot fo -/// #[cfg] and macro soup, but the intention is that this macro alleviates a lof +/// little tweaks for various platforms. As a result it *could* involve a lot of +/// #[cfg] and macro soup, but the intention is that this macro alleviates a lot /// of that complexity. Ideally this macro has all the weird ABI things /// platforms need and elsewhere in this library it just looks like normal Rust /// code. @@ -220,10 +220,6 @@ macro_rules! intrinsics { pub extern "aapcs" fn $alias( $($argname: $ty),* ) -> $ret { super::$name($($argname),*) } - - pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { - super::$name($($argname),*) - } } } From 6792390e3ef1d6eae76802949a07859d9eaabcb7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 25 Jun 2017 09:25:54 -0700 Subject: [PATCH 0356/4206] Enable the `intrinsics` program on thumb --- library/compiler-builtins/ci/run.sh | 12 +----------- library/compiler-builtins/examples/intrinsics.rs | 14 ++++++++++++-- library/compiler-builtins/src/arm.rs | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index d285b36653844..9562b7fd8a979 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -115,19 +115,9 @@ done rm -f $path -# Verification of the `intrinsics` program doesn't work on thumb targets right -# now. -case $1 in - thumb*) - exit 0 - ;; - *) - ;; -esac - # Verify that we haven't drop any intrinsic/symbol RUSTFLAGS="-C debug-assertions=no" \ - $cargo build --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics + $cargo build --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics -v # Verify that there are no undefined symbols to `panic` within our # implementations diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 7db241eddbb01..e7c55e835ed3d 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -12,13 +12,14 @@ #![feature(core_float)] #![feature(lang_items)] #![feature(start)] -#![feature(panic_unwind)] #![feature(i128_type)] +#![cfg_attr(windows, feature(panic_unwind))] #![no_std] #[cfg(not(thumb))] extern crate alloc_system; extern crate compiler_builtins; +#[cfg(windows)] extern crate panic_unwind; // NOTE cfg(not(thumbv6m)) means that the operation is not supported on ARMv6-M at all. Not even @@ -444,7 +445,16 @@ pub fn __aeabi_unwind_cpp_pr0() {} #[no_mangle] pub fn __aeabi_unwind_cpp_pr1() {} -#[cfg(not(test))] +#[cfg(not(windows))] +#[allow(non_snake_case)] +#[no_mangle] +pub fn _Unwind_Resume() {} + +#[cfg(not(windows))] +#[lang = "eh_personality"] +#[no_mangle] +pub extern "C" fn eh_personality() {} + #[lang = "panic_fmt"] #[no_mangle] #[allow(private_no_mangle_fns)] diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 81e0afdd00b44..389bf9aaa9639 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -37,7 +37,7 @@ pub unsafe fn __aeabi_uldivmod() { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_idivmod() { asm!("push {r0, r1, r4, lr} - bl __divsi3 + bl __aeabi_idiv pop {r1, r2} muls r2, r2, r0 subs r1, r1, r2 From 326c0bb597ddda686ef6e11d446e026eac026b7b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 27 Jun 2017 22:48:57 -0500 Subject: [PATCH 0357/4206] enable tests now that #150 has been fixed --- library/compiler-builtins/ci/run.sh | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 9562b7fd8a979..c37ca489f93ce 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -31,18 +31,6 @@ case $1 in ;; esac - # FIXME(#150) debug assertion in divmoddi4 - case $1 in - thumbv6m-*) - case $t in - divdi3 | divmoddi4 | moddi3 | modsi3 | udivmoddi4 | udivmodsi4 | umoddi3 | \ - umodsi3) - continue - ;; - esac - ;; - esac - xargo test --test $t --target $1 --features 'mem gen-tests' --no-run qemu-arm-static target/${1}/debug/$t-* From f096e02f636eeade93dedfd6659ffe16d3e192f0 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 29 Jun 2017 22:40:58 -0500 Subject: [PATCH 0358/4206] optimize 32-bit aligned mem{cpy,clr,set} intrinsics for ARM this reduces the execution time of all these routines by 40-70% --- library/compiler-builtins/src/arm.rs | 82 ++++-- library/compiler-builtins/src/lib.rs | 2 +- library/compiler-builtins/src/mem.rs | 8 +- .../compiler-builtins/tests/aeabi_memclr.rs | 58 ++++ .../compiler-builtins/tests/aeabi_memcpy.rs | 69 +++++ .../compiler-builtins/tests/aeabi_memset.rs | 274 ++++++++++++++++++ 6 files changed, 463 insertions(+), 30 deletions(-) create mode 100644 library/compiler-builtins/tests/aeabi_memclr.rs create mode 100644 library/compiler-builtins/tests/aeabi_memcpy.rs create mode 100644 library/compiler-builtins/tests/aeabi_memset.rs diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 389bf9aaa9639..227ab0515f5fb 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,7 +1,6 @@ -use core::intrinsics; +use core::{intrinsics, ptr}; -#[cfg(feature = "mem")] -use mem::{memcpy, memmove, memset}; +use mem; // NOTE This function and the ones below are implemented using assembly because they using a custom // calling convention which can't be implemented using a normal Rust function @@ -60,65 +59,98 @@ pub unsafe fn __aeabi_ldivmod() { intrinsics::unreachable(); } -// TODO: These aeabi_* functions should be defined as aliases -#[cfg(not(feature = "mem"))] -extern "C" { - fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; - fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; - fn memset(dest: *mut u8, c: i32, n: usize) -> *mut u8; -} - // FIXME: The `*4` and `*8` variants should be defined as aliases. #[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { - memcpy(dest, src, n); + mem::memcpy(dest, src, n); } + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { - memcpy(dest, src, n); +#[linkage = "weak"] +pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, mut n: usize) { + let mut dest = dest as *mut u32; + let mut src = src as *mut u32; + + while n >= 4 { + ptr::write(dest, ptr::read(src)); + dest = dest.offset(1); + src = src.offset(1); + n -= 4; + } + + __aeabi_memcpy(dest as *mut u8, src as *const u8, n); } + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { - memcpy(dest, src, n); + __aeabi_memcpy4(dest, src, n); } #[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { - memmove(dest, src, n); + mem::memmove(dest, src, n); } + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { - memmove(dest, src, n); + __aeabi_memmove(dest, src, n); } + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { - memmove(dest, src, n); + __aeabi_memmove(dest, src, n); } // Note the different argument order #[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { - memset(dest, c, n); + mem::memset(dest, c, n); } + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { - memset(dest, c, n); +#[linkage = "weak"] +pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, mut n: usize, c: i32) { + let mut dest = dest as *mut u32; + + let byte = (c as u32) & 0xff; + let c = (byte << 24) | (byte << 16) | (byte << 8) | byte; + + while n >= 4 { + ptr::write(dest, c); + dest = dest.offset(1); + n -= 4; + } + + __aeabi_memset(dest as *mut u8, n, byte as i32); } + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { - memset(dest, c, n); + __aeabi_memset4(dest, n, c); } #[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { - memset(dest, 0, n); + __aeabi_memset(dest, n, 0); } + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { - memset(dest, 0, n); + __aeabi_memset4(dest, n, 0); } + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { - memset(dest, 0, n); + __aeabi_memset4(dest, n, 0); } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 3fa7923b4475f..39bf854d09c86 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -16,6 +16,7 @@ #![feature(i128_type)] #![feature(repr_simd)] #![feature(abi_unadjusted)] +#![feature(linkage)] #![allow(unused_features)] #![no_builtins] #![unstable(feature = "compiler_builtins_lib", @@ -45,7 +46,6 @@ mod macros; pub mod int; pub mod float; -#[cfg(feature = "mem")] pub mod mem; #[cfg(target_arch = "arm")] diff --git a/library/compiler-builtins/src/mem.rs b/library/compiler-builtins/src/mem.rs index cb8baec273ebc..c56391c4d3d49 100644 --- a/library/compiler-builtins/src/mem.rs +++ b/library/compiler-builtins/src/mem.rs @@ -5,7 +5,7 @@ type c_int = i16; #[cfg(not(target_pointer_width = "16"))] type c_int = i32; -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) @@ -18,7 +18,7 @@ pub unsafe extern "C" fn memcpy(dest: *mut u8, dest } -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) @@ -41,7 +41,7 @@ pub unsafe extern "C" fn memmove(dest: *mut u8, dest } -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { let mut i = 0; while i < n { @@ -51,7 +51,7 @@ pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { s } -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { let mut i = 0; while i < n { diff --git a/library/compiler-builtins/tests/aeabi_memclr.rs b/library/compiler-builtins/tests/aeabi_memclr.rs new file mode 100644 index 0000000000000..72e944e4c74e4 --- /dev/null +++ b/library/compiler-builtins/tests/aeabi_memclr.rs @@ -0,0 +1,58 @@ +#![cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + feature = "mem"))] +#![feature(compiler_builtins_lib)] +#![no_std] + +extern crate compiler_builtins; + +// test runner +extern crate utest_cortex_m_qemu; + +// overrides `panic!` +#[macro_use] +extern crate utest_macros; + +use core::mem; + +macro_rules! panic { + ($($tt:tt)*) => { + upanic!($($tt)*); + }; +} + +extern "C" { + fn __aeabi_memclr4(dest: *mut u8, n: usize); + fn __aeabi_memset4(dest: *mut u8, n: usize, c: u32); +} + +struct Aligned { + array: [u8; 8], + _alignment: [u32; 0], +} + +impl Aligned { + fn new() -> Self { + Aligned { + array: [0; 8], + _alignment: [], + } + } +} + +#[test] +fn memclr4() { + let mut aligned = Aligned::new();; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + + for n in 0..9 { + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, 0xff); + __aeabi_memclr4(xs.as_mut_ptr(), n); + } + + assert!(xs[0..n].iter().all(|x| *x == 0)); + } +} diff --git a/library/compiler-builtins/tests/aeabi_memcpy.rs b/library/compiler-builtins/tests/aeabi_memcpy.rs new file mode 100644 index 0000000000000..2ba942c23c16c --- /dev/null +++ b/library/compiler-builtins/tests/aeabi_memcpy.rs @@ -0,0 +1,69 @@ +#![cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + feature = "mem"))] +#![feature(compiler_builtins_lib)] +#![no_std] + +extern crate compiler_builtins; + +// test runner +extern crate utest_cortex_m_qemu; + +// overrides `panic!` +#[macro_use] +extern crate utest_macros; + +macro_rules! panic { + ($($tt:tt)*) => { + upanic!($($tt)*); + }; +} + +extern "C" { + fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize); + fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize); +} + +struct Aligned { + array: [u8; 8], + _alignment: [u32; 0], +} + +impl Aligned { + fn new(array: [u8; 8]) -> Self { + Aligned { + array: array, + _alignment: [], + } + } +} + +#[test] +fn memcpy() { + let mut dest = [0; 4]; + let src = [0xde, 0xad, 0xbe, 0xef]; + + for n in 0..dest.len() { + dest.copy_from_slice(&[0; 4]); + + unsafe { __aeabi_memcpy(dest.as_mut_ptr(), src.as_ptr(), n) } + + assert_eq!(&dest[0..n], &src[0..n]) + } +} + +#[test] +fn memcpy4() { + let mut aligned = Aligned::new([0; 8]); + let dest = &mut aligned.array; + let src = [0xde, 0xad, 0xbe, 0xef, 0xba, 0xad, 0xf0, 0x0d]; + + for n in 0..dest.len() { + dest.copy_from_slice(&[0; 8]); + + unsafe { __aeabi_memcpy4(dest.as_mut_ptr(), src.as_ptr(), n) } + + assert_eq!(&dest[0..n], &src[0..n]) + } +} diff --git a/library/compiler-builtins/tests/aeabi_memset.rs b/library/compiler-builtins/tests/aeabi_memset.rs new file mode 100644 index 0000000000000..0919f149124f0 --- /dev/null +++ b/library/compiler-builtins/tests/aeabi_memset.rs @@ -0,0 +1,274 @@ +#![cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + feature = "mem"))] +#![feature(compiler_builtins_lib)] +#![no_std] + +extern crate compiler_builtins; + +// test runner +extern crate utest_cortex_m_qemu; + +// overrides `panic!` +#[macro_use] +extern crate utest_macros; + +use core::mem; + +macro_rules! panic { + ($($tt:tt)*) => { + upanic!($($tt)*); + }; +} + +extern "C" { + fn __aeabi_memset4(dest: *mut u8, n: usize, c: u32); +} + +struct Aligned { + array: [u8; 8], + _alignment: [u32; 0], +} + +impl Aligned { + fn new(array: [u8; 8]) -> Self { + Aligned { + array: array, + _alignment: [], + } + } +} + +#[test] +fn zero() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), 0, c) + } + + assert_eq!(*xs, [0; 8]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), 0, c) + } + + assert_eq!(*xs, [1; 8]); +} + +#[test] +fn one() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 1; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0, 0, 0, 0, 0, 0, 0]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 1, 1, 1, 1, 1, 1, 1]); +} + +#[test] +fn two() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 2; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0, 0, 0, 0, 0, 0]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 1, 1, 1, 1, 1, 1]); +} + +#[test] +fn three() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 3; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0, 0, 0, 0, 0]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 1, 1, 1, 1, 1]); +} + +#[test] +fn four() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 4; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0, 0, 0, 0]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 1, 1, 1, 1]); +} + +#[test] +fn five() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 5; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0, 0, 0]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 1, 1, 1]); +} + +#[test] +fn six() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 6; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0, 0]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 1, 1]); +} + +#[test] +fn seven() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 7; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 1]); +} + +#[test] +fn eight() { + let mut aligned = Aligned::new([0u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let n = 8; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef]); + + let mut aligned = Aligned::new([1u8; 8]);; + assert_eq!(mem::align_of_val(&aligned), 4); + let xs = &mut aligned.array; + let c = 0xdeadbeef; + + unsafe { + __aeabi_memset4(xs.as_mut_ptr(), n, c) + } + + assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef]); +} From b9d62916825a11ebaf06df2598b23404df57a30a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Jun 2017 18:06:25 -0500 Subject: [PATCH 0359/4206] no aeabi_mem* symbols on iOS, weak symbols on thumb, normal symbols elsewhere --- library/compiler-builtins/src/arm.rs | 38 ++++++++++++++++++---------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 227ab0515f5fb..b72ff97ea3156 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -61,14 +61,16 @@ pub unsafe fn __aeabi_ldivmod() { // FIXME: The `*4` and `*8` variants should be defined as aliases. +#[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] +#[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { mem::memcpy(dest, src, n); } +#[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] +#[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, mut n: usize) { let mut dest = dest as *mut u32; let mut src = src as *mut u32; @@ -83,39 +85,45 @@ pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, mut __aeabi_memcpy(dest as *mut u8, src as *const u8, n); } +#[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] +#[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memcpy4(dest, src, n); } +#[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] +#[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { mem::memmove(dest, src, n); } +#[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] +#[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memmove(dest, src, n); } +#[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] +#[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memmove(dest, src, n); } -// Note the different argument order +#[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] +#[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { + // Note the different argument order mem::memset(dest, c, n); } +#[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] +#[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, mut n: usize, c: i32) { let mut dest = dest as *mut u32; @@ -131,26 +139,30 @@ pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, mut n: usize, c: i32 __aeabi_memset(dest as *mut u8, n, byte as i32); } +#[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] +#[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { __aeabi_memset4(dest, n, c); } +#[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] +#[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { __aeabi_memset(dest, n, 0); } +#[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] +#[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); } +#[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] +#[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); } From 37538e8c2a6855595f84fec4e322eaddab775119 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 1 Jul 2017 00:31:45 -0700 Subject: [PATCH 0360/4206] Update compiler-rt submodule Needed to pull in some recent changes with rust-lang/rust --- library/compiler-builtins/compiler-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-rt b/library/compiler-builtins/compiler-rt index 3bc0272cab9fd..c8a8767c56ad3 160000 --- a/library/compiler-builtins/compiler-rt +++ b/library/compiler-builtins/compiler-rt @@ -1 +1 @@ -Subproject commit 3bc0272cab9fdcfc2ef4df9625ec3c9d5909db79 +Subproject commit c8a8767c56ad3d3f4eb45c87b95026936fb9aa35 From e48cd1180be56826f4b53503627c9fabfab8deaf Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 3 Jul 2017 08:16:01 -0700 Subject: [PATCH 0361/4206] Use the Rust implementation of udivsi3 on ARM Although compiler-rt presumably has a more optimized implementation written in assembly, it appears buggy for whatever reason, causing #173. For now let's see if integration into rust-lang/rust will work with the Rust-defined implementation! --- library/compiler-builtins/build.rs | 17 +++++++++++++---- library/compiler-builtins/src/int/sdiv.rs | 1 - library/compiler-builtins/src/int/udiv.rs | 3 --- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index bfb0ad9797d0e..17df4b6435a5c 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4196,7 +4196,6 @@ mod c { "arm/clzsi2.S", "arm/comparesf2.S", "arm/divmodsi4.S", - "arm/divsi3.S", "arm/modsi3.S", "arm/switch16.S", "arm/switch32.S", @@ -4204,8 +4203,20 @@ mod c { "arm/switchu8.S", "arm/sync_synchronize.S", "arm/udivmodsi4.S", - "arm/udivsi3.S", "arm/umodsi3.S", + + // Exclude these two files for now even though we haven't + // translated their implementation into Rust yet (#173). + // They appear... buggy? The `udivsi3` implementation was + // the one that seemed buggy, but the `divsi3` file + // references a symbol from `udivsi3` so we compile them + // both with the Rust versions. + // + // Note that if these are added back they should be removed + // from thumbv6m below. + // + // "arm/divsi3.S", + // "arm/udivsi3.S", ], ); } @@ -4315,14 +4326,12 @@ mod c { "clzsi2", "comparesf2", "divmodsi4", - "divsi3", "modsi3", "switch16", "switch32", "switch8", "switchu8", "udivmodsi4", - "udivsi3", "umodsi3", ], ); diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 6dd090f394a75..c949c3394d2d0 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -57,7 +57,6 @@ impl Divmod for i32 {} impl Divmod for i64 {} intrinsics! { - #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), not(thumbv6m)))] #[arm_aeabi_alias = __aeabi_idiv] pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 { a.div(b) diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 471f01d078ac5..de276147e3d6e 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -148,9 +148,6 @@ macro_rules! udivmod_inner { } intrinsics! { - #[use_c_shim_if(all(target_arch = "arm", - not(target_os = "ios"), - not(thumbv6m)))] #[arm_aeabi_alias = __aeabi_uidiv] /// Returns `n / d` pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { From ebcf7fac6a90bb4b5deaf7fda4ad71d3a00a7b2e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 3 Jul 2017 14:57:42 -0700 Subject: [PATCH 0362/4206] Compile ffsdi2 with `rustbuild` feature This is not used by LLVM/Rust, but is apparently used by gcc/C which jemalloc can require at least. --- library/compiler-builtins/README.md | 4 +++- library/compiler-builtins/build.rs | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 5f59b44b1a8b0..a0e2a29ed157b 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -306,7 +306,7 @@ These builtins are never called by LLVM. - ~~ctzdi2.c~~ - ~~ctzsi2.c~~ - ~~ctzti2.c~~ -- ~~ffsdi2.c~~ +- ~~ffsdi2.c~~ - this is [called by gcc][jemalloc-fail] though! - ~~ffsti2.c~~ - ~~mulvdi3.c~~ - ~~mulvsi3.c~~ @@ -333,6 +333,8 @@ These builtins are never called by LLVM. - ~~ucmpti2.c~~ - ~~udivmodti4.c~~ +[jemalloc-fail]: https://travis-ci.org/rust-lang/rust/jobs/249772758 + Rust only exposes atomic types on platforms that support them, and therefore does not need to fall back to software implementations. - ~~arm/sync_fetch_and_add_4.S~~ diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 17df4b6435a5c..221964554135f 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4095,6 +4095,16 @@ mod c { ], ); + // When compiling in rustbuild (the rust-lang/rust repo) this library + // also needs to satisfy intrinsics that jemalloc or C in general may + // need, so include a few more that aren't typically needed by + // LLVM/Rust. + if env::var_os("CARGO_FEATURE_RUSTBUILD").is_some() { + sources.exend(&[ + "ffsdi2.c", + ]); + } + if target_os != "ios" { sources.extend( &[ From a32ae6d6b6c660b021663f4def7a6f8419cc8657 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 3 Jul 2017 15:28:03 -0700 Subject: [PATCH 0363/4206] Fix a typo in the build script --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 221964554135f..d4c4ad247de72 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4100,7 +4100,7 @@ mod c { // need, so include a few more that aren't typically needed by // LLVM/Rust. if env::var_os("CARGO_FEATURE_RUSTBUILD").is_some() { - sources.exend(&[ + sources.extend(&[ "ffsdi2.c", ]); } From 79b55c48ca5f657aab2ced4067c07c93cdff96d6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 3 Jul 2017 19:11:34 -0700 Subject: [PATCH 0364/4206] Fix unused imports on iOS --- library/compiler-builtins/src/arm.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index b72ff97ea3156..fa86e969146eb 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,6 +1,4 @@ -use core::{intrinsics, ptr}; - -use mem; +use core::intrinsics; // NOTE This function and the ones below are implemented using assembly because they using a custom // calling convention which can't be implemented using a normal Rust function @@ -65,13 +63,15 @@ pub unsafe fn __aeabi_ldivmod() { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { - mem::memcpy(dest, src, n); + ::mem::memcpy(dest, src, n); } #[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, mut n: usize) { + use core::ptr; + let mut dest = dest as *mut u32; let mut src = src as *mut u32; @@ -96,7 +96,7 @@ pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: u #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { - mem::memmove(dest, src, n); + ::mem::memmove(dest, src, n); } #[cfg(not(target_os = "ios"))] @@ -118,13 +118,15 @@ pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: #[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { // Note the different argument order - mem::memset(dest, c, n); + ::mem::memset(dest, c, n); } #[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, mut n: usize, c: i32) { + use core::ptr; + let mut dest = dest as *mut u32; let byte = (c as u32) & 0xff; From f771aac37a2ca080f86b4731fe702ce7359a22de Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 5 Jul 2017 22:18:19 -0700 Subject: [PATCH 0365/4206] Add `__rust_probestack` intrinsic Will be required for rust-lang/rust#42816 --- library/compiler-builtins/src/lib.rs | 2 + library/compiler-builtins/src/probestack.rs | 112 ++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 library/compiler-builtins/src/probestack.rs diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 39bf854d09c86..b8cf83e2125d2 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -53,3 +53,5 @@ pub mod arm; #[cfg(target_arch = "x86_64")] pub mod x86_64; + +pub mod probestack; diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs new file mode 100644 index 0000000000000..e59fe861a7e7f --- /dev/null +++ b/library/compiler-builtins/src/probestack.rs @@ -0,0 +1,112 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module defines the `__rust_probestack` intrinsic which is used in the +//! implementation of "stack probes" on certain platforms. +//! +//! The purpose of a stack probe is to provide a static guarantee that if a +//! thread has a guard page then a stack overflow is guaranteed to hit that +//! guard page. If a function did not have a stack probe then there's a risk of +//! having a stack frame *larger* than the guard page, so a function call could +//! skip over the guard page entirely and then later hit maybe the heap or +//! another thread, possibly leading to security vulnerabilities such as [The +//! Stack Clash], for example. +//! +//! [The Stack Clash]: https://blog.qualys.com/securitylabs/2017/06/19/the-stack-clash +//! +//! The `__rust_probestack` is called in the prologue of functions whose stack +//! size is larger than the guard page, for example larger than 4096 bytes on +//! x86. This function is then responsible for "touching" all pages relevant to +//! the stack to ensure that that if any of them are the guard page we'll hit +//! them guaranteed. +//! +//! The precise ABI for how this function operates is defined by LLVM. There's +//! no real documentation as to what this is, so you'd basically need to read +//! the LLVM source code for reference. Often though the test cases can be +//! illuminating as to the ABI that's generated, or just looking at the output +//! of `llc`. +//! +//! Note that `#[naked]` is typically used here for the stack probe because the +//! ABI corresponds to no actual ABI. +//! +//! Finally it's worth noting that at the time of this writing LLVM only has +//! support for stack probes on x86 and x86_64. There's no support for stack +//! 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(windows))] // Windows already has builtins to do this + +#[naked] +#[no_mangle] +#[cfg(target_arch = "x86_64")] +pub unsafe extern fn __rust_probestack() { + // Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax, + // ensuring that if any pages are unmapped we'll make a page fault. + // + // The ABI here is that the stack frame size is located in `%eax`. Upon + // return we're not supposed to modify `%esp` or `%eax`. + asm!(" + lea 8(%rsp),%r11 // rsp before calling this routine -> r11 + + // Main loop, taken in one page increments. We're decrementing r11 by + // a page each time until there's less than a page remaining. We're + // guaranteed that this function isn't called unless there's more than a + // page needed + 2: + sub $$0x1000,%r11 + test %r11,(%r11) + sub $$0x1000,%rax + cmp $$0x1000,%rax + ja 2b + + // Finish up the last remaining stack space requested, getting the last + // bits out of rax + sub %rax,%r11 + test %r11,(%r11) + + // We now know that %r11 is (%rsp + 8 - %rax) so to recover rax + // we calculate (%rsp + 8) - %r11 which will give us %rax + lea 8(%rsp),%rax + sub %r11,%rax + + ret + "); + ::core::intrinsics::unreachable(); +} + +#[naked] +#[no_mangle] +#[cfg(target_arch = "x86")] +pub unsafe extern fn __rust_probestack() { + // This is the same as x86_64 above, only translated for 32-bit sizes. Note + // that on Unix we're expected to restore everything as it was, this + // function basically can't tamper with anything. + // + // The ABI here is the same as x86_64, except everything is 32-bits large. + asm!(" + push %ecx + lea 8(%esp),%ecx + 2: + sub $$0x1000,%ecx + test %ecx,(%ecx) + sub $$0x1000,%eax + cmp $$0x1000,%eax + ja 2b + + sub %eax,%ecx + test %ecx,(%ecx) + + lea 8(%esp),%eax + sub %ecx,%eax + pop %ecx + ret + "); + ::core::intrinsics::unreachable(); +} From f4e92e379c010913b8adda7273b41198e31d4c9a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 7 Jul 2017 10:16:03 -0700 Subject: [PATCH 0366/4206] Tweak definition of probestack functions It looks like the old `__rust_probestack` routine is incompatible with newer linux kernels. My best guess for this is that the kernel's auto-growth logic is failing to trigger, causing what looks like a legitimate segfault to get delivered. My best guess for why *that's* happening is that the faulting address is below `%rsp`, whereas previously all faulting stack addresses were above `%rsp`. The probestack routine does not modify `%rsp` as it's probing the stack, and presumably newer kernels are interpreting this as a legitimate violation. This commit tweaks the probestack routine to instead update `%rsp` incrementally as probing happens. The ABI of the function, however, requires that `%rsp` isn't changed as part of the function so it's restored at the end to the previous value. --- library/compiler-builtins/src/probestack.rs | 46 +++++++++++---------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index e59fe861a7e7f..e1224fe7ace77 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -53,28 +53,33 @@ pub unsafe extern fn __rust_probestack() { // The ABI here is that the stack frame size is located in `%eax`. Upon // return we're not supposed to modify `%esp` or `%eax`. asm!(" - lea 8(%rsp),%r11 // rsp before calling this routine -> r11 + mov %rax,%r11 // duplicate %rax as we're clobbering %r11 - // Main loop, taken in one page increments. We're decrementing r11 by + // Main loop, taken in one page increments. We're decrementing rsp by // a page each time until there's less than a page remaining. We're // guaranteed that this function isn't called unless there's more than a - // page needed + // page needed. + // + // Note that we're also testing against `8(%rsp)` to account for the 8 + // bytes pushed on the stack orginally with our return address. Using + // `8(%rsp)` simulates us testing the stack pointer in the caller's + // context. 2: + sub $$0x1000,%rsp + test %rsp,8(%rsp) sub $$0x1000,%r11 - test %r11,(%r11) - sub $$0x1000,%rax - cmp $$0x1000,%rax + cmp $$0x1000,%r11 ja 2b // Finish up the last remaining stack space requested, getting the last - // bits out of rax - sub %rax,%r11 - test %r11,(%r11) + // bits out of r11 + sub %r11,%rsp + test %rsp,8(%rsp) - // We now know that %r11 is (%rsp + 8 - %rax) so to recover rax - // we calculate (%rsp + 8) - %r11 which will give us %rax - lea 8(%rsp),%rax - sub %r11,%rax + // Restore the stack pointer to what it previously was when entering + // this function. The caller will readjust the stack pointer after we + // return. + add %rax,%rsp ret "); @@ -92,19 +97,18 @@ pub unsafe extern fn __rust_probestack() { // The ABI here is the same as x86_64, except everything is 32-bits large. asm!(" push %ecx - lea 8(%esp),%ecx + mov %eax,%ecx 2: + sub $$0x1000,%esp + test %esp,8(%esp) sub $$0x1000,%ecx - test %ecx,(%ecx) - sub $$0x1000,%eax - cmp $$0x1000,%eax + cmp $$0x1000,%ecx ja 2b - sub %eax,%ecx - test %ecx,(%ecx) + sub %ecx,%esp + test %esp,8(%esp) - lea 8(%esp),%eax - sub %ecx,%eax + add %eax,%esp pop %ecx ret "); From 2fa53c4b67702063258f6464fea6ed50a6b949a7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 7 Jul 2017 11:20:04 -0700 Subject: [PATCH 0367/4206] Don't mangle probes all the time --- library/compiler-builtins/build.rs | 19 +++++++++++-------- library/compiler-builtins/ci/run.sh | 1 + .../compiler-builtins/examples/intrinsics.rs | 6 ++++++ library/compiler-builtins/src/float/conv.rs | 5 +++-- library/compiler-builtins/src/probestack.rs | 4 ++-- library/compiler-builtins/src/x86_64.rs | 6 +++--- 6 files changed, 26 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index d4c4ad247de72..25cc5204d2e7f 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -21,9 +21,14 @@ fn main() { #[cfg(feature = "gen-tests")] tests::generate(); - // Build missing intrinsics from compiler-rt C source code - #[cfg(feature = "c")] - c::compile(&llvm_target); + // 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 = "mangled-names") { + #[cfg(feature = "c")] + c::compile(&llvm_target); + } // To compile intrinsics.rs for thumb targets, where there is no libc if llvm_target[0].starts_with("thumb") { @@ -4099,11 +4104,9 @@ mod c { // also needs to satisfy intrinsics that jemalloc or C in general may // need, so include a few more that aren't typically needed by // LLVM/Rust. - if env::var_os("CARGO_FEATURE_RUSTBUILD").is_some() { - sources.extend(&[ - "ffsdi2.c", - ]); - } + sources.extend(&[ + "ffsdi2.c", + ]); if target_os != "ios" { sources.extend( diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index c37ca489f93ce..9a32ee9ea64c8 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -93,6 +93,7 @@ for rlib in $(echo $path); do uniq -d | \ grep -v __x86.get_pc_thunk | \ grep -v __builtin_cl | \ + grep -v __builtin_ctz | \ grep 'T __' if test $? = 0; then diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index e7c55e835ed3d..3820887895de0 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -13,6 +13,8 @@ #![feature(lang_items)] #![feature(start)] #![feature(i128_type)] +#![feature(global_allocator)] +#![feature(allocator_api)] #![cfg_attr(windows, feature(panic_unwind))] #![no_std] @@ -22,6 +24,10 @@ extern crate compiler_builtins; #[cfg(windows)] extern crate panic_unwind; +#[cfg(not(thumb))] +#[global_allocator] +static A: alloc_system::System = alloc_system::System; + // NOTE cfg(not(thumbv6m)) means that the operation is not supported on ARMv6-M at all. Not even // compiler-rt provides a C/assembly implementation. diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index e12349cfff99f..f2fd01d37b054 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -112,8 +112,9 @@ intrinsics! { int_to_float!(i, u32, f64) } - #[use_c_shim_if(all(any(target_arch = "x86", target_arch = "x86_64"), - not(windows)))] + #[use_c_shim_if(all(not(target_env = "msvc"), + any(target_arch = "x86", + all(not(windows), target_arch = "x86_64"))))] #[arm_aeabi_alias = __aeabi_ul2d] pub extern "C" fn __floatundidf(i: u64) -> f64 { int_to_float!(i, u64, f64) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index e1224fe7ace77..329e2726511ce 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -44,7 +44,7 @@ #![cfg(not(windows))] // Windows already has builtins to do this #[naked] -#[no_mangle] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg(target_arch = "x86_64")] pub unsafe extern fn __rust_probestack() { // Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax, @@ -87,7 +87,7 @@ pub unsafe extern fn __rust_probestack() { } #[naked] -#[no_mangle] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg(target_arch = "x86")] pub unsafe extern fn __rust_probestack() { // This is the same as x86_64 above, only translated for 32-bit sizes. Note diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 072f964dd70c1..64cc06c983454 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -10,7 +10,7 @@ use core::intrinsics; #[cfg(windows)] #[naked] -#[no_mangle] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn ___chkstk_ms() { asm!("push %rcx push %rax @@ -34,7 +34,7 @@ pub unsafe fn ___chkstk_ms() { #[cfg(windows)] #[naked] -#[no_mangle] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __alloca() { asm!("mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable"); @@ -43,7 +43,7 @@ pub unsafe fn __alloca() { #[cfg(windows)] #[naked] -#[no_mangle] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn ___chkstk() { asm!("push %rcx cmp $$0x1000,%rax From 45a7693962e75ae0653645328aa2c78e8708cb24 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Wed, 12 Jul 2017 22:40:49 +0100 Subject: [PATCH 0368/4206] Don't include custom chkstk on MSVC MSVC includes its own __chkstk so these aren't used. --- library/compiler-builtins/src/x86_64.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 64cc06c983454..bc3c4ee4c5550 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -8,7 +8,7 @@ use core::intrinsics; // NOTE These functions are never mangled as they are not tested against compiler-rt // and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca -#[cfg(windows)] +#[cfg(all(windows, target_env = "gnu"))] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn ___chkstk_ms() { @@ -32,7 +32,7 @@ pub unsafe fn ___chkstk_ms() { intrinsics::unreachable(); } -#[cfg(windows)] +#[cfg(all(windows, target_env = "gnu"))] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __alloca() { @@ -41,7 +41,7 @@ pub unsafe fn __alloca() { intrinsics::unreachable(); } -#[cfg(windows)] +#[cfg(all(windows, target_env = "gnu"))] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn ___chkstk() { From e377364051476d90183aa916b0d375b86a6079a8 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Sat, 22 Jul 2017 23:10:30 +0200 Subject: [PATCH 0369/4206] Avoid memcpy references in unoptimized code --- library/compiler-builtins/src/float/add.rs | 6 ++++-- library/compiler-builtins/src/int/udiv.rs | 13 +++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 696d886fb6978..a4b763b7e7833 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -1,4 +1,3 @@ -use core::mem; use core::num::Wrapping; use float::Float; @@ -75,7 +74,10 @@ macro_rules! add { // Swap a and b if necessary so that a has the larger absolute value. if b_abs > a_abs { - mem::swap(&mut a_rep, &mut b_rep); + // Don't use mem::swap because it may generate references to memcpy in unoptimized code. + let tmp = a_rep; + a_rep = b_rep; + b_rep = tmp; } // Extract the exponent and significand from the (possibly swapped) a and b. diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index de276147e3d6e..b8d949128d375 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -125,7 +125,11 @@ macro_rules! udivmod_inner { // 1 <= sr <= u64::bits() - 1 let mut carry = 0; - for _ in 0..sr { + // Don't use a range because they may generate references to memcpy in unoptimized code + let mut i = 0; + while i < sr { + i += 1; + // r:q = ((r:q) << 1) | carry r = (r << 1) | (q >> (<$ty>::bits() - 1)); q = (q << 1) | carry as $ty; @@ -181,7 +185,12 @@ intrinsics! { let mut r = n >> sr; let mut carry = 0; - for _ in 0..sr { + + // Don't use a range because they may generate references to memcpy in unoptimized code + let mut i = 0; + while i < sr { + i += 1; + // r:q = ((r:q) << 1) | carry r = (r << 1) | (q >> (u32::bits() - 1)); q = (q << 1) | carry; From 21c82e419de2fc9caced36646a706d0bd0bc5995 Mon Sep 17 00:00:00 2001 From: Geoff Yoerger Date: Mon, 21 Aug 2017 16:17:04 -0500 Subject: [PATCH 0370/4206] Fix README relative link. --- library/compiler-builtins/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index a0e2a29ed157b..3571200aa3bc0 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -51,7 +51,7 @@ features = ["c"] ## Contributing -1. Pick one or more intrinsics from the [pending list][#progress]. +1. Pick one or more intrinsics from the [pending list](#progress). 2. Fork this repository 3. Port the intrinsic(s) and their corresponding [unit tests][1] from their [C implementation][2] to Rust. From 465ba28996b25e4531b9d1a2e9ec72d68efb4326 Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 7 Sep 2017 07:49:34 +0200 Subject: [PATCH 0371/4206] Update the gcc crate to 0.3.53 and disable compilation warnings They are inside the compiler-rt submodule, about which we don't have direct control over. --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/build.rs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 070d8f8c7a0f0..d7419902d7aa1 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -10,7 +10,7 @@ rand = { version = "0.3.15", optional = true } [build-dependencies.gcc] optional = true -version = "0.3.36" +version = "0.3.53" [features] c = ["gcc"] diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 25cc5204d2e7f..6d4e274fadc06 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4008,7 +4008,9 @@ mod c { let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap(); - let cfg = &mut gcc::Config::new(); + let cfg = &mut gcc::Build::new(); + + cfg.warnings(false); if target_env == "msvc" { // Don't pull in extra libraries on MSVC From ffd4e7639f9bc61f68277982dce53c7a7819186b Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Sun, 10 Sep 2017 09:30:47 -0400 Subject: [PATCH 0372/4206] Remove unused rustbuild feature I can't tell if this was ever used, but it's not used today. --- library/compiler-builtins/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index d7419902d7aa1..84cefb2d280ff 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -17,7 +17,6 @@ c = ["gcc"] compiler-builtins = [] default = ["compiler-builtins"] mem = [] -rustbuild = ["compiler-builtins"] mangled-names = [] # generate tests From 0b2a017b944424f3c318c2d375493233b01a5254 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 12 Sep 2017 19:09:43 -0400 Subject: [PATCH 0373/4206] Update rustbuild commentary Also use `cfg!(feature = "rustbuild")` instead of the environment variable to ease grep-ability. --- library/compiler-builtins/build.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 6d4e274fadc06..8b5695ba422d2 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4106,9 +4106,11 @@ mod c { // also needs to satisfy intrinsics that jemalloc or C in general may // need, so include a few more that aren't typically needed by // LLVM/Rust. - sources.extend(&[ - "ffsdi2.c", - ]); + if cfg!(feature = "rustbuild") { + sources.extend(&[ + "ffsdi2.c", + ]); + } if target_os != "ios" { sources.extend( @@ -4359,7 +4361,9 @@ mod c { sources.remove(&["aeabi_cdcmp", "aeabi_cfcmp"]); } - let root = if env::var_os("CARGO_FEATURE_RUSTBUILD").is_some() { + // When compiling in rustbuild (the rust-lang/rust repo) this build + // script runs from a directory other than this root directory. + let root = if cfg!(feature = "rustbuild") { Path::new("../../libcompiler_builtins") } else { Path::new(".") From 985e578acdd1225e36b6df2583188f110af48911 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 13 Sep 2017 21:01:40 +0200 Subject: [PATCH 0374/4206] Refactor int builtins to use associated consts --- library/compiler-builtins/src/float/conv.rs | 6 ++-- library/compiler-builtins/src/int/mod.rs | 34 ++++++------------ library/compiler-builtins/src/int/mul.rs | 14 ++++---- library/compiler-builtins/src/int/sdiv.rs | 10 +++--- library/compiler-builtins/src/int/shift.rs | 16 ++++----- library/compiler-builtins/src/int/udiv.rs | 38 ++++++++++----------- 6 files changed, 52 insertions(+), 66 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index f2fd01d37b054..fdd7fd8ccd15e 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -11,7 +11,7 @@ macro_rules! int_to_float { let mant_dig = <$fty>::significand_bits() + 1; let exponent_bias = <$fty>::exponent_bias(); - let n = <$ity>::bits(); + let n = <$ity>::BITS; let (s, a) = i.extract_sign(); let mut a = a; @@ -21,7 +21,7 @@ macro_rules! int_to_float { // exponent let mut e = sd - 1; - if <$ity>::bits() < mant_dig { + if <$ity>::BITS < mant_dig { return <$fty>::from_parts(s, (e + exponent_bias) as <$fty as Float>::Int, (a as <$fty as Float>::Int) << (mant_dig - e - 1)) @@ -142,7 +142,7 @@ macro_rules! float_to_int { let f = $f; let fixint_min = <$ity>::min_value(); let fixint_max = <$ity>::max_value(); - let fixint_bits = <$ity>::bits() as usize; + let fixint_bits = <$ity>::BITS as usize; let fixint_unsigned = fixint_min == 0; let sign_bit = <$fty>::sign_mask(); diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 0334a4acb8ba7..7f9a85c41938c 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -39,11 +39,11 @@ pub trait Int: /// Unsigned version of Self type UnsignedInt: Int; - /// Returns the bitwidth of the int type - fn bits() -> u32; + /// The bitwidth of the int type + const BITS: u32; - fn zero() -> Self; - fn one() -> Self; + const ZERO: Self; + const ONE: Self; /// Extracts the sign from self and returns a tuple. /// @@ -83,17 +83,10 @@ macro_rules! int_impl { type OtherSign = $ity; type UnsignedInt = $uty; - fn zero() -> Self { - 0 - } - - fn one() -> Self { - 1 - } + const BITS: u32 = $bits; - fn bits() -> u32 { - $bits - } + const ZERO: Self = 0; + const ONE: Self = 1; fn extract_sign(self) -> (bool, $uty) { (false, self) @@ -140,17 +133,10 @@ macro_rules! int_impl { type OtherSign = $uty; type UnsignedInt = $uty; - fn bits() -> u32 { - $bits - } - - fn zero() -> Self { - 0 - } + const BITS: u32 = $bits; - fn one() -> Self { - 1 - } + const ZERO: Self = 0; + const ONE: Self = 1; fn extract_sign(self) -> (bool, $uty) { if self < 0 { diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 98a8987e1d49f..a4b2ebd7fb773 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -5,8 +5,8 @@ use int::Int; trait Mul: LargeInt { fn mul(self, other: Self) -> Self { - let half_bits = Self::bits() / 4; - let lower_mask = !<::LowHalf>::zero() >> half_bits; + let half_bits = Self::BITS / 4; + let lower_mask = !<::LowHalf>::ZERO >> half_bits; let mut low = (self.low() & lower_mask).wrapping_mul(other.low() & lower_mask); let mut t = low >> half_bits; low &= lower_mask; @@ -33,23 +33,23 @@ trait Mulo: Int + ops::Neg { *overflow = 0; let result = self.wrapping_mul(other); if self == Self::min_value() { - if other != Self::zero() && other != Self::one() { + if other != Self::ZERO && other != Self::ONE { *overflow = 1; } return result; } if other == Self::min_value() { - if self != Self::zero() && self != Self::one() { + if self != Self::ZERO && self != Self::ONE { *overflow = 1; } return result; } - let sa = self >> (Self::bits() - 1); + let sa = self >> (Self::BITS - 1); let abs_a = (self ^ sa) - sa; - let sb = other >> (Self::bits() - 1); + let sb = other >> (Self::BITS - 1); let abs_b = (other ^ sb) - sb; - let two = Self::one() + Self::one(); + let two = Self::ONE + Self::ONE; if abs_a < two || abs_b < two { return result; } diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index c949c3394d2d0..ff8fa61e4b9e6 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -3,9 +3,9 @@ use int::Int; trait Div: Int { /// Returns `a / b` fn div(self, other: Self) -> Self { - let s_a = self >> (Self::bits() - 1); - let s_b = other >> (Self::bits() - 1); - // NOTE it's OK to overflow here because of the `as $uty` cast below + let s_a = self >> (Self::BITS - 1); + let s_b = other >> (Self::BITS - 1); + // NOTE it's OK to overflow here because of the `.unsigned()` below. // This whole operation is computing the absolute value of the inputs // So some overflow will happen when dealing with e.g. `i64::MIN` // where the absolute value is `(-i64::MIN) as u64` @@ -25,10 +25,10 @@ impl Div for i128 {} trait Mod: Int { /// Returns `a % b` fn mod_(self, other: Self) -> Self { - let s = other >> (Self::bits() - 1); + let s = other >> (Self::BITS - 1); // NOTE(wrapping_sub) see comment in the `div` let b = (other ^ s).wrapping_sub(s); - let s = self >> (Self::bits() - 1); + let s = self >> (Self::BITS - 1); let a = (self ^ s).wrapping_sub(s); let r = a.unsigned().aborting_rem(b.unsigned()); diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index a9b6c05d3d34c..805d7059623a8 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -1,13 +1,13 @@ use int::{Int, LargeInt}; trait Ashl: Int + LargeInt { - /// Returns `a << b`, requires `b < $ty::bits()` + /// Returns `a << b`, requires `b < Self::BITS` fn ashl(self, offset: u32) -> Self where Self: LargeInt::LowHalf>, { - let half_bits = Self::bits() / 2; + let half_bits = Self::BITS / 2; if offset & half_bits != 0 { - Self::from_parts(Int::zero(), self.low() << (offset - half_bits)) + Self::from_parts(Int::ZERO, self.low() << (offset - half_bits)) } else if offset == 0 { self } else { @@ -22,11 +22,11 @@ impl Ashl for u64 {} impl Ashl for u128 {} trait Ashr: Int + LargeInt { - /// Returns arithmetic `a >> b`, requires `b < $ty::bits()` + /// Returns arithmetic `a >> b`, requires `b < Self::BITS` fn ashr(self, offset: u32) -> Self where Self: LargeInt::HighHalf as Int>::UnsignedInt>, { - let half_bits = Self::bits() / 2; + let half_bits = Self::BITS / 2; if offset & half_bits != 0 { Self::from_parts((self.high() >> (offset - half_bits)).unsigned(), self.high() >> (half_bits - 1)) @@ -44,13 +44,13 @@ impl Ashr for i64 {} impl Ashr for i128 {} trait Lshr: Int + LargeInt { - /// Returns logical `a >> b`, requires `b < $ty::bits()` + /// Returns logical `a >> b`, requires `b < Self::BITS` fn lshr(self, offset: u32) -> Self where Self: LargeInt::LowHalf>, { - let half_bits = Self::bits() / 2; + let half_bits = Self::BITS / 2; if offset & half_bits != 0 { - Self::from_parts(self.high() >> (offset - half_bits), Int::zero()) + Self::from_parts(self.high() >> (offset - half_bits), Int::ZERO) } else if offset == 0 { self } else { diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index b8d949128d375..74a2ac3387dc5 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -63,7 +63,7 @@ macro_rules! udivmod_inner { sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); // D > N - if sr > ::bits() - 2 { + if sr > ::BITS - 2 { if let Some(rem) = rem { *rem = n; } @@ -72,8 +72,8 @@ macro_rules! udivmod_inner { sr += 1; - // 1 <= sr <= ::bits() - 1 - q = n << (<$ty>::bits() - sr); + // 1 <= sr <= ::BITS - 1 + q = n << (<$ty>::BITS - sr); r = n >> sr; } else if d.high() == 0 { // K X @@ -92,10 +92,10 @@ macro_rules! udivmod_inner { }; } - sr = 1 + ::bits() + d.low().leading_zeros() - n.high().leading_zeros(); + sr = 1 + ::BITS + d.low().leading_zeros() - n.high().leading_zeros(); - // 2 <= sr <= u64::bits() - 1 - q = n << (<$ty>::bits() - sr); + // 2 <= sr <= u64::BITS - 1 + q = n << (<$ty>::BITS - sr); r = n >> sr; } else { // K X @@ -104,7 +104,7 @@ macro_rules! udivmod_inner { sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); // D > N - if sr > ::bits() - 1 { + if sr > ::BITS - 1 { if let Some(rem) = rem { *rem = n; } @@ -113,16 +113,16 @@ macro_rules! udivmod_inner { sr += 1; - // 1 <= sr <= ::bits() - q = n << (<$ty>::bits() - sr); + // 1 <= sr <= ::BITS + q = n << (<$ty>::BITS - sr); r = n >> sr; } // Not a special case // q and r are initialized with - // q = n << (u64::bits() - sr) + // q = n << (u64::BITS - sr) // r = n >> sr - // 1 <= sr <= u64::bits() - 1 + // 1 <= sr <= u64::BITS - 1 let mut carry = 0; // Don't use a range because they may generate references to memcpy in unoptimized code @@ -131,7 +131,7 @@ macro_rules! udivmod_inner { i += 1; // r:q = ((r:q) << 1) | carry - r = (r << 1) | (q >> (<$ty>::bits() - 1)); + r = (r << 1) | (q >> (<$ty>::BITS - 1)); q = (q << 1) | carry as $ty; // carry = 0 @@ -139,7 +139,7 @@ macro_rules! udivmod_inner { // r -= d; // carry = 1; // } - let s = (d.wrapping_sub(r).wrapping_sub(1)) as os_ty!($ty) >> (<$ty>::bits() - 1); + let s = (d.wrapping_sub(r).wrapping_sub(1)) as os_ty!($ty) >> (<$ty>::BITS - 1); carry = (s & 1) as hty!($ty); r -= d & s as $ty; } @@ -169,19 +169,19 @@ intrinsics! { let mut sr = d.leading_zeros().wrapping_sub(n.leading_zeros()); // d > n - if sr > u32::bits() - 1 { + if sr > u32::BITS - 1 { return 0; } // d == 1 - if sr == u32::bits() - 1 { + if sr == u32::BITS - 1 { return n; } sr += 1; - // 1 <= sr <= u32::bits() - 1 - let mut q = n << (u32::bits() - sr); + // 1 <= sr <= u32::BITS - 1 + let mut q = n << (u32::BITS - sr); let mut r = n >> sr; let mut carry = 0; @@ -192,7 +192,7 @@ intrinsics! { i += 1; // r:q = ((r:q) << 1) | carry - r = (r << 1) | (q >> (u32::bits() - 1)); + r = (r << 1) | (q >> (u32::BITS - 1)); q = (q << 1) | carry; // carry = 0; @@ -201,7 +201,7 @@ intrinsics! { // carry = 1; // } - let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32::bits() - 1); + let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32::BITS - 1); carry = (s & 1) as u32; r -= d & s as u32; } From 218eafcc68b40c1a19c306d891c68962b9d157ed Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 13 Sep 2017 22:08:15 +0200 Subject: [PATCH 0375/4206] Refactor float builtins to use associated consts --- library/compiler-builtins/src/float/add.rs | 4 +- library/compiler-builtins/src/float/conv.rs | 12 +- library/compiler-builtins/src/float/mod.rs | 116 ++++++++------------ library/compiler-builtins/src/float/sub.rs | 4 +- 4 files changed, 56 insertions(+), 80 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index a4b763b7e7833..2d380c13c2650 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -10,8 +10,8 @@ macro_rules! add { let one = Wrapping(1 as <$ty as Float>::Int); let zero = Wrapping(0 as <$ty as Float>::Int); - let bits = Wrapping(<$ty>::bits() as <$ty as Float>::Int); - let significand_bits = Wrapping(<$ty>::significand_bits() as <$ty as Float>::Int); + let bits = Wrapping(<$ty>::BITS as <$ty as Float>::Int); + let significand_bits = Wrapping(<$ty>::SIGNIFICAND_BITS as <$ty as Float>::Int); let exponent_bits = bits - significand_bits - one; let max_exponent = (one << exponent_bits.0 as usize) - one; diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index fdd7fd8ccd15e..33644ce56aaf3 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -8,8 +8,8 @@ macro_rules! int_to_float { return 0.0 } - let mant_dig = <$fty>::significand_bits() + 1; - let exponent_bias = <$fty>::exponent_bias(); + let mant_dig = <$fty>::SIGNIFICAND_BITS + 1; + let exponent_bias = <$fty>::EXPONENT_BIAS; let n = <$ity>::BITS; let (s, a) = i.extract_sign(); @@ -145,9 +145,9 @@ macro_rules! float_to_int { let fixint_bits = <$ity>::BITS as usize; let fixint_unsigned = fixint_min == 0; - let sign_bit = <$fty>::sign_mask(); - let significand_bits = <$fty>::significand_bits() as usize; - let exponent_bias = <$fty>::exponent_bias() as usize; + let sign_bit = <$fty>::SIGN_MASK; + let significand_bits = <$fty>::SIGNIFICAND_BITS as usize; + let exponent_bias = <$fty>::EXPONENT_BIAS as usize; //let exponent_max = <$fty>::exponent_max() as usize; // Break a into sign, exponent, significand @@ -157,7 +157,7 @@ macro_rules! float_to_int { // this is used to work around -1 not being available for unsigned let sign = if (a_rep & sign_bit) == 0 { Sign::Positive } else { Sign::Negative }; let mut exponent = (a_abs >> significand_bits) as usize; - let significand = (a_abs & <$fty>::significand_mask()) | <$fty>::implicit_bit(); + let significand = (a_abs & <$fty>::SIGNIFICAND_MASK) | <$fty>::IMPLICIT_BIT; // if < 1 or unsigned & negative if exponent < exponent_bias || diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 46e3e5d9585f0..078c5110c2fb8 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,5 +1,7 @@ use core::mem; +use super::int::Int; + pub mod conv; pub mod add; pub mod pow; @@ -8,39 +10,34 @@ pub mod sub; /// Trait for some basic operations on floats pub trait Float: Sized + Copy { /// A uint of the same with as the float - type Int; + type Int: Int; - /// Returns the bitwidth of the float type - fn bits() -> u32; + /// The bitwidth of the float type + const BITS: u32; - /// Returns the bitwidth of the significand - fn significand_bits() -> u32; + /// The bitwidth of the significand + const SIGNIFICAND_BITS: u32; - /// Returns the bitwidth of the exponent - fn exponent_bits() -> u32 { - Self::bits() - Self::significand_bits() - 1 - } - /// Returns the maximum value of the exponent - fn exponent_max() -> u32 { - (1 << Self::exponent_bits()) - 1 - } + /// The bitwidth of the exponent + const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1; - /// Returns the exponent bias value - fn exponent_bias() -> u32 { - Self::exponent_max() >> 1 - } + /// The maximum value of the exponent + const EXPONENT_MAX: u32 = (1 << Self::EXPONENT_BITS) - 1; + + /// The exponent bias value + const EXPONENT_BIAS: u32 = Self::EXPONENT_MAX >> 1; - /// Returns a mask for the sign bit - fn sign_mask() -> Self::Int; + /// A mask for the sign bit + const SIGN_MASK: Self::Int; - /// Returns a mask for the significand - fn significand_mask() -> Self::Int; + /// A mask for the significand + const SIGNIFICAND_MASK: Self::Int; - // Returns the implicit bit of the float format - fn implicit_bit() -> Self::Int; + // The implicit bit of the float format + const IMPLICIT_BIT: Self::Int; - /// Returns a mask for the exponent - fn exponent_mask() -> Self::Int; + /// A mask for the exponent + const EXPONENT_MASK: Self::Int; /// Returns `self` transmuted to `Self::Int` fn repr(self) -> Self::Int; @@ -65,24 +62,14 @@ pub trait Float: Sized + Copy { // https://github.com/rust-lang/rfcs/issues/1424 impl Float for f32 { type Int = u32; - fn bits() -> u32 { - 32 - } - fn significand_bits() -> u32 { - 23 - } - fn implicit_bit() -> Self::Int { - 1 << Self::significand_bits() - } - fn sign_mask() -> Self::Int { - 1 << (Self::bits() - 1) - } - fn significand_mask() -> Self::Int { - (1 << Self::significand_bits()) - 1 - } - fn exponent_mask() -> Self::Int { - !(Self::sign_mask() | Self::significand_mask()) - } + const BITS: u32 = 32; + const SIGNIFICAND_BITS: u32 = 23; + + const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); + const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1; + const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; + const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); + fn repr(self) -> Self::Int { unsafe { mem::transmute(self) } } @@ -98,37 +85,26 @@ impl Float for f32 { unsafe { mem::transmute(a) } } fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_repr(((sign as Self::Int) << (Self::bits() - 1)) | - ((exponent << Self::significand_bits()) & Self::exponent_mask()) | - (significand & Self::significand_mask())) + Self::from_repr(((sign as Self::Int) << (Self::BITS - 1)) | + ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) | + (significand & Self::SIGNIFICAND_MASK)) } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros() - .wrapping_sub((1u32 << Self::significand_bits()).leading_zeros()); + .wrapping_sub((1u32 << Self::SIGNIFICAND_BITS).leading_zeros()); (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) } } impl Float for f64 { type Int = u64; - fn bits() -> u32 { - 64 - } - fn significand_bits() -> u32 { - 52 - } - // Returns the implicit bit of the float format - fn implicit_bit() -> Self::Int { - 1 << Self::significand_bits() - } - fn sign_mask() -> Self::Int { - 1 << (Self::bits() - 1) - } - fn significand_mask() -> Self::Int { - (1 << Self::significand_bits()) - 1 - } - fn exponent_mask() -> Self::Int { - !(Self::sign_mask() | Self::significand_mask()) - } + const BITS: u32 = 64; + const SIGNIFICAND_BITS: u32 = 52; + + const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); + const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1; + const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; + const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); + fn repr(self) -> Self::Int { unsafe { mem::transmute(self) } } @@ -144,13 +120,13 @@ impl Float for f64 { unsafe { mem::transmute(a) } } fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_repr(((sign as Self::Int) << (Self::bits() - 1)) | - ((exponent << Self::significand_bits()) & Self::exponent_mask()) | - (significand & Self::significand_mask())) + Self::from_repr(((sign as Self::Int) << (Self::BITS - 1)) | + ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) | + (significand & Self::SIGNIFICAND_MASK)) } fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand.leading_zeros() - .wrapping_sub((1u64 << Self::significand_bits()).leading_zeros()); + .wrapping_sub((1u64 << Self::SIGNIFICAND_BITS).leading_zeros()); (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) } } diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index 4fa436db6136c..ed7dd2c0aaaf1 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -3,11 +3,11 @@ use float::Float; intrinsics! { #[arm_aeabi_alias = __aeabi_fsub] pub extern "C" fn __subsf3(a: f32, b: f32) -> f32 { - a + f32::from_repr(b.repr() ^ f32::sign_mask()) + a + f32::from_repr(b.repr() ^ f32::SIGN_MASK) } #[arm_aeabi_alias = __aeabi_dsub] pub extern "C" fn __subdf3(a: f64, b: f64) -> f64 { - a + f64::from_repr(b.repr() ^ f64::sign_mask()) + a + f64::from_repr(b.repr() ^ f64::SIGN_MASK) } } From cec214f0d7eb60e895254b3951a032438a2773e7 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 13 Sep 2017 22:44:56 +0200 Subject: [PATCH 0376/4206] Introduce a float_impl! macro to avoid duplication --- library/compiler-builtins/src/float/mod.rs | 106 ++++++++------------- 1 file changed, 39 insertions(+), 67 deletions(-) diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 078c5110c2fb8..33e1479a6bf35 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -60,73 +60,45 @@ pub trait Float: Sized + Copy { // FIXME: Some of this can be removed if RFC Issue #1424 is resolved // https://github.com/rust-lang/rfcs/issues/1424 -impl Float for f32 { - type Int = u32; - const BITS: u32 = 32; - const SIGNIFICAND_BITS: u32 = 23; - - const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); - const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1; - const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; - const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); - - fn repr(self) -> Self::Int { - unsafe { mem::transmute(self) } - } - #[cfg(test)] - fn eq_repr(self, rhs: Self) -> bool { - if self.is_nan() && rhs.is_nan() { - true - } else { - self.repr() == rhs.repr() - } - } - fn from_repr(a: Self::Int) -> Self { - unsafe { mem::transmute(a) } - } - fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_repr(((sign as Self::Int) << (Self::BITS - 1)) | - ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) | - (significand & Self::SIGNIFICAND_MASK)) - } - fn normalize(significand: Self::Int) -> (i32, Self::Int) { - let shift = significand.leading_zeros() - .wrapping_sub((1u32 << Self::SIGNIFICAND_BITS).leading_zeros()); - (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) - } -} -impl Float for f64 { - type Int = u64; - const BITS: u32 = 64; - const SIGNIFICAND_BITS: u32 = 52; - - const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); - const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1; - const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; - const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); - - fn repr(self) -> Self::Int { - unsafe { mem::transmute(self) } - } - #[cfg(test)] - fn eq_repr(self, rhs: Self) -> bool { - if self.is_nan() && rhs.is_nan() { - true - } else { - self.repr() == rhs.repr() +macro_rules! float_impl { + ($ty:ident, $ity:ident, $bits:expr, $significand_bits:expr) => { + impl Float for $ty { + type Int = $ity; + const BITS: u32 = $bits; + const SIGNIFICAND_BITS: u32 = $significand_bits; + + const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); + const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1; + const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; + const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); + + fn repr(self) -> Self::Int { + unsafe { mem::transmute(self) } + } + #[cfg(test)] + fn eq_repr(self, rhs: Self) -> bool { + if self.is_nan() && rhs.is_nan() { + true + } else { + self.repr() == rhs.repr() + } + } + fn from_repr(a: Self::Int) -> Self { + unsafe { mem::transmute(a) } + } + fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { + Self::from_repr(((sign as Self::Int) << (Self::BITS - 1)) | + ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) | + (significand & Self::SIGNIFICAND_MASK)) + } + fn normalize(significand: Self::Int) -> (i32, Self::Int) { + let shift = significand.leading_zeros() + .wrapping_sub((Self::Int::ONE << Self::SIGNIFICAND_BITS).leading_zeros()); + (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) + } } } - fn from_repr(a: Self::Int) -> Self { - unsafe { mem::transmute(a) } - } - fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_repr(((sign as Self::Int) << (Self::BITS - 1)) | - ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) | - (significand & Self::SIGNIFICAND_MASK)) - } - fn normalize(significand: Self::Int) -> (i32, Self::Int) { - let shift = significand.leading_zeros() - .wrapping_sub((1u64 << Self::SIGNIFICAND_BITS).leading_zeros()); - (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) - } } + +float_impl!(f32, u32, 32, 23); +float_impl!(f64, u64, 64, 52); From 515ea7157a55e5c870e4935f8560c8c3ccdbf9dd Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 14 Sep 2017 00:10:16 +0200 Subject: [PATCH 0377/4206] Use the newly added ONE constant in float addition --- library/compiler-builtins/src/float/add.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 2d380c13c2650..e6cb726fd48d2 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -1,5 +1,6 @@ use core::num::Wrapping; +use int::Int; use float::Float; /// Returns `a + b` @@ -7,8 +8,8 @@ macro_rules! add { ($a:expr, $b:expr, $ty:ty) => ({ let a = $a; let b = $b; - let one = Wrapping(1 as <$ty as Float>::Int); - let zero = Wrapping(0 as <$ty as Float>::Int); + let one = Wrapping(<$ty as Float>::Int::ONE); + let zero = Wrapping(<$ty as Float>::Int::ZERO); let bits = Wrapping(<$ty>::BITS as <$ty as Float>::Int); let significand_bits = Wrapping(<$ty>::SIGNIFICAND_BITS as <$ty as Float>::Int); From 3b5d6d7aa9eb563f547067a62704e561eee9e4a5 Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 14 Sep 2017 01:57:52 +0200 Subject: [PATCH 0378/4206] Extend the Float trait by some constants and supertraits --- library/compiler-builtins/src/float/mod.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 33e1479a6bf35..23aef32e5ded0 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,4 +1,5 @@ use core::mem; +use core::ops; use super::int::Int; @@ -8,10 +9,23 @@ pub mod pow; pub mod sub; /// Trait for some basic operations on floats -pub trait Float: Sized + Copy { +pub trait Float: + Copy + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::MulAssign + + ops::Add + + ops::Sub + + ops::Div + + ops::Rem + +{ /// A uint of the same with as the float type Int: Int; + const ZERO: Self; + const ONE: Self; + /// The bitwidth of the float type const BITS: u32; @@ -64,6 +78,9 @@ macro_rules! float_impl { ($ty:ident, $ity:ident, $bits:expr, $significand_bits:expr) => { impl Float for $ty { type Int = $ity; + const ZERO: Self = 0.0; + const ONE: Self = 1.0; + const BITS: u32 = $bits; const SIGNIFICAND_BITS: u32 = $significand_bits; From 57a3b2fe4824aec06a426a84cf98dcb3216e3672 Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 14 Sep 2017 01:59:02 +0200 Subject: [PATCH 0379/4206] Don't use a macro for pow calculation --- library/compiler-builtins/src/float/pow.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index bc15dc088879c..f879c1a1f8106 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -1,11 +1,12 @@ use int::Int; +use float::Float; -/// Returns `a` raised to the power `b` -macro_rules! pow { - ($a: expr, $b: expr) => ({ - let (mut a, mut b) = ($a, $b); +trait Pow: Float { + /// Returns `a` raised to the power `b` + fn pow(self, mut b: i32) -> Self { + let mut a = self; let recip = b < 0; - let mut r = 1.0; + let mut r = Self::ONE; loop { if (b & 1) != 0 { r *= a; @@ -18,19 +19,22 @@ macro_rules! pow { } if recip { - 1.0 / r + Self::ONE / r } else { r } - }) + } } +impl Pow for f32 {} +impl Pow for f64 {} + intrinsics! { pub extern "C" fn __powisf2(a: f32, b: i32) -> f32 { - pow!(a, b) + a.pow(b) } pub extern "C" fn __powidf2(a: f64, b: i32) -> f64 { - pow!(a, b) + a.pow(b) } } From 6f19051513b2ebce272a54aa85f205eab1345c23 Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 14 Sep 2017 02:08:28 +0200 Subject: [PATCH 0380/4206] Don't use the Wrapping wrapper in float addition Inspired by a patch by mattico. --- library/compiler-builtins/src/float/add.rs | 106 ++++++++++----------- 1 file changed, 52 insertions(+), 54 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index e6cb726fd48d2..fae14f07c3eba 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -1,5 +1,3 @@ -use core::num::Wrapping; - use int::Int; use float::Float; @@ -8,44 +6,44 @@ macro_rules! add { ($a:expr, $b:expr, $ty:ty) => ({ let a = $a; let b = $b; - let one = Wrapping(<$ty as Float>::Int::ONE); - let zero = Wrapping(<$ty as Float>::Int::ZERO); + let one = <$ty as Float>::Int::ONE; + let zero = <$ty as Float>::Int::ZERO; - let bits = Wrapping(<$ty>::BITS as <$ty as Float>::Int); - let significand_bits = Wrapping(<$ty>::SIGNIFICAND_BITS as <$ty as Float>::Int); - let exponent_bits = bits - significand_bits - one; - let max_exponent = (one << exponent_bits.0 as usize) - one; + let bits = <$ty>::BITS as <$ty as Float>::Int; + let significand_bits = <$ty>::SIGNIFICAND_BITS as <$ty as Float>::Int; + let exponent_bits = <$ty>::EXPONENT_BITS as <$ty as Float>::Int; + let max_exponent = (one << exponent_bits as usize) - one; - let implicit_bit = one << significand_bits.0 as usize; + let implicit_bit = one << significand_bits as usize; let significand_mask = implicit_bit - one; - let sign_bit = one << (significand_bits + exponent_bits).0 as usize; + let sign_bit = <$ty>::SIGN_MASK as <$ty as Float>::Int; let abs_mask = sign_bit - one; let exponent_mask = abs_mask ^ significand_mask; let inf_rep = exponent_mask; let quiet_bit = implicit_bit >> 1; let qnan_rep = exponent_mask | quiet_bit; - let mut a_rep = Wrapping(a.repr()); - let mut b_rep = Wrapping(b.repr()); + let mut a_rep = a.repr(); + let mut b_rep = b.repr(); let a_abs = a_rep & abs_mask; let b_abs = b_rep & abs_mask; // Detect if a or b is zero, infinity, or NaN. - if a_abs - one >= inf_rep - one || - b_abs - one >= inf_rep - one { + if a_abs.wrapping_sub(one) >= inf_rep - one || + b_abs.wrapping_sub(one) >= inf_rep - one { // NaN + anything = qNaN if a_abs > inf_rep { - return <$ty as Float>::from_repr((a_abs | quiet_bit).0); + return <$ty as Float>::from_repr(a_abs | quiet_bit); } // anything + NaN = qNaN if b_abs > inf_rep { - return <$ty as Float>::from_repr((b_abs | quiet_bit).0); + return <$ty as Float>::from_repr(b_abs | quiet_bit); } if a_abs == inf_rep { // +/-infinity + -/+infinity = qNaN - if (a.repr() ^ b.repr()) == sign_bit.0 { - return <$ty as Float>::from_repr(qnan_rep.0); + if (a.repr() ^ b.repr()) == sign_bit { + return <$ty as Float>::from_repr(qnan_rep); } else { // +/-infinity + anything remaining = +/- infinity return a; @@ -58,9 +56,9 @@ macro_rules! add { } // zero + anything = anything - if a_abs.0 == 0 { + if a_abs == 0 { // but we need to get the sign right for zero + zero - if b_abs.0 == 0 { + if b_abs == 0 { return <$ty as Float>::from_repr(a.repr() & b.repr()); } else { return b; @@ -68,7 +66,7 @@ macro_rules! add { } // anything + zero = anything - if b_abs.0 == 0 { + if b_abs == 0 { return a; } } @@ -82,21 +80,21 @@ macro_rules! add { } // Extract the exponent and significand from the (possibly swapped) a and b. - let mut a_exponent = Wrapping((a_rep >> significand_bits.0 as usize & max_exponent).0 as i32); - let mut b_exponent = Wrapping((b_rep >> significand_bits.0 as usize & max_exponent).0 as i32); + let mut a_exponent = ((a_rep >> significand_bits) & max_exponent) as i32; + let mut b_exponent = ((b_rep >> significand_bits) & max_exponent) as i32; let mut a_significand = a_rep & significand_mask; let mut b_significand = b_rep & significand_mask; // normalize any denormals, and adjust the exponent accordingly. - if a_exponent.0 == 0 { - let (exponent, significand) = <$ty>::normalize(a_significand.0); - a_exponent = Wrapping(exponent); - a_significand = Wrapping(significand); + if a_exponent == 0 { + let (exponent, significand) = <$ty>::normalize(a_significand); + a_exponent = exponent; + a_significand = significand; } - if b_exponent.0 == 0 { - let (exponent, significand) = <$ty>::normalize(b_significand.0); - b_exponent = Wrapping(exponent); - b_significand = Wrapping(significand); + if b_exponent == 0 { + let (exponent, significand) = <$ty>::normalize(b_significand); + b_exponent = exponent; + b_significand = significand; } // The sign of the result is the sign of the larger operand, a. If they @@ -113,64 +111,64 @@ macro_rules! add { // Shift the significand of b by the difference in exponents, with a sticky // bottom bit to get rounding correct. - let align = Wrapping((a_exponent - b_exponent).0 as <$ty as Float>::Int); - if align.0 != 0 { + let align = a_exponent.wrapping_sub(b_exponent) as <$ty as Float>::Int; + if align != 0 { if align < bits { - let sticky = ((b_significand << (bits - align).0 as usize).0 != 0) as <$ty as Float>::Int; - b_significand = (b_significand >> align.0 as usize) | Wrapping(sticky); + let sticky = (b_significand << (bits.wrapping_sub(align) as usize) != 0) as <$ty as Float>::Int; + b_significand = (b_significand >> align as usize) | sticky; } else { b_significand = one; // sticky; b is known to be non-zero. } } if subtraction { - a_significand -= b_significand; + a_significand = a_significand.wrapping_sub(b_significand); // If a == -b, return +zero. - if a_significand.0 == 0 { + if a_significand == 0 { return <$ty as Float>::from_repr(0); } // If partial cancellation occured, we need to left-shift the result // and adjust the exponent: if a_significand < implicit_bit << 3 { - let shift = a_significand.0.leading_zeros() as i32 - - (implicit_bit << 3).0.leading_zeros() as i32; + let shift = a_significand.leading_zeros() as i32 + - (implicit_bit << 3).leading_zeros() as i32; a_significand <<= shift as usize; - a_exponent -= Wrapping(shift); + a_exponent -= shift; } } else /* addition */ { a_significand += b_significand; // If the addition carried up, we need to right-shift the result and // adjust the exponent: - if (a_significand & implicit_bit << 4).0 != 0 { - let sticky = ((a_significand & one).0 != 0) as <$ty as Float>::Int; - a_significand = a_significand >> 1 | Wrapping(sticky); - a_exponent += Wrapping(1); + if a_significand & implicit_bit << 4 != 0 { + let sticky = (a_significand & one != 0) as <$ty as Float>::Int; + a_significand = a_significand >> 1 | sticky; + a_exponent += 1; } } // If we have overflowed the type, return +/- infinity: - if a_exponent >= Wrapping(max_exponent.0 as i32) { - return <$ty>::from_repr((inf_rep | result_sign).0); + if a_exponent >= max_exponent as i32 { + return <$ty>::from_repr(inf_rep | result_sign); } - if a_exponent.0 <= 0 { + if a_exponent <= 0 { // Result is denormal before rounding; the exponent is zero and we // need to shift the significand. - let shift = Wrapping((Wrapping(1) - a_exponent).0 as <$ty as Float>::Int); - let sticky = ((a_significand << (bits - shift).0 as usize).0 != 0) as <$ty as Float>::Int; - a_significand = a_significand >> shift.0 as usize | Wrapping(sticky); - a_exponent = Wrapping(0); + let shift = (1 - a_exponent) as <$ty as Float>::Int; + let sticky = ((a_significand << bits.wrapping_sub(shift) as usize) != 0) as <$ty as Float>::Int; + a_significand = a_significand >> shift as usize | sticky; + a_exponent = 0; } // Low three bits are round, guard, and sticky. - let round_guard_sticky: i32 = (a_significand.0 & 0x7) as i32; + let round_guard_sticky: i32 = (a_significand & 0x7) as i32; // Shift the significand into place, and mask off the implicit bit. let mut result = a_significand >> 3 & significand_mask; // Insert the exponent and sign. - result |= Wrapping(a_exponent.0 as <$ty as Float>::Int) << significand_bits.0 as usize; + result |= (a_exponent as <$ty as Float>::Int) << (significand_bits as usize); result |= result_sign; // Final rounding. The result may overflow to infinity, but that is the @@ -178,7 +176,7 @@ macro_rules! add { if round_guard_sticky > 0x4 { result += one; } if round_guard_sticky == 0x4 { result += result & one; } - <$ty>::from_repr(result.0) + <$ty>::from_repr(result) }) } From f1bab6229dbae2890ed49d227e2c36fe12d9923b Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 14 Sep 2017 14:59:32 +0200 Subject: [PATCH 0381/4206] Convert float_to_int! into a function --- library/compiler-builtins/src/float/conv.rs | 125 ++++++++++---------- library/compiler-builtins/src/int/mod.rs | 25 ++++ 2 files changed, 88 insertions(+), 62 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 33644ce56aaf3..52fdf95599874 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -1,5 +1,5 @@ use float::Float; -use int::Int; +use int::{Int, CastInto}; macro_rules! int_to_float { ($i:expr, $ity:ty, $fty:ty) => ({ @@ -137,115 +137,116 @@ enum Sign { Negative } -macro_rules! float_to_int { - ($f:expr, $fty:ty, $ity:ty) => ({ - let f = $f; - let fixint_min = <$ity>::min_value(); - let fixint_max = <$ity>::max_value(); - let fixint_bits = <$ity>::BITS as usize; - let fixint_unsigned = fixint_min == 0; - - let sign_bit = <$fty>::SIGN_MASK; - let significand_bits = <$fty>::SIGNIFICAND_BITS as usize; - let exponent_bias = <$fty>::EXPONENT_BIAS as usize; - //let exponent_max = <$fty>::exponent_max() as usize; - - // Break a into sign, exponent, significand - let a_rep = <$fty>::repr(f); - let a_abs = a_rep & !sign_bit; - - // this is used to work around -1 not being available for unsigned - let sign = if (a_rep & sign_bit) == 0 { Sign::Positive } else { Sign::Negative }; - let mut exponent = (a_abs >> significand_bits) as usize; - let significand = (a_abs & <$fty>::SIGNIFICAND_MASK) | <$fty>::IMPLICIT_BIT; - - // if < 1 or unsigned & negative - if exponent < exponent_bias || - fixint_unsigned && sign == Sign::Negative { - return 0 - } - exponent -= exponent_bias; - - // If the value is infinity, saturate. - // If the value is too large for the integer type, 0. - if exponent >= (if fixint_unsigned {fixint_bits} else {fixint_bits -1}) { - return if sign == Sign::Positive {fixint_max} else {fixint_min} - } - // If 0 <= exponent < significand_bits, right shift to get the result. - // Otherwise, shift left. - // (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned - let r = if exponent < significand_bits { - (significand >> (significand_bits - exponent)) as $ity - } else { - (significand as $ity) << (exponent - significand_bits) - }; - - if sign == Sign::Negative { - (!r).wrapping_add(1) - } else { - r - } - }) +fn float_to_int(f: F) -> I where + F::Int: CastInto, + F::Int: CastInto, +{ + let f = f; + let fixint_min = I::min_value(); + let fixint_max = I::max_value(); + let fixint_bits = I::BITS; + let fixint_unsigned = fixint_min == I::ZERO; + + let sign_bit = F::SIGN_MASK; + let significand_bits = F::SIGNIFICAND_BITS; + let exponent_bias = F::EXPONENT_BIAS; + //let exponent_max = F::exponent_max() as usize; + + // Break a into sign, exponent, significand + let a_rep = F::repr(f); + let a_abs = a_rep & !sign_bit; + + // this is used to work around -1 not being available for unsigned + let sign = if (a_rep & sign_bit) == F::Int::ZERO { Sign::Positive } else { Sign::Negative }; + let mut exponent: u32 = (a_abs >> significand_bits).cast(); + let significand = (a_abs & F::SIGNIFICAND_MASK) | F::IMPLICIT_BIT; + + // if < 1 or unsigned & negative + if exponent < exponent_bias || + fixint_unsigned && sign == Sign::Negative { + return I::ZERO; + } + exponent -= exponent_bias; + + // If the value is infinity, saturate. + // If the value is too large for the integer type, 0. + if exponent >= (if fixint_unsigned {fixint_bits} else {fixint_bits -1}) { + return if sign == Sign::Positive {fixint_max} else {fixint_min} + } + // If 0 <= exponent < significand_bits, right shift to get the result. + // Otherwise, shift left. + // (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned + let r: I = if exponent < significand_bits { + (significand >> (significand_bits - exponent)).cast() + } else { + (significand << (exponent - significand_bits)).cast() + }; + + if sign == Sign::Negative { + (!r).wrapping_add(I::ONE) + } else { + r + } } intrinsics! { #[arm_aeabi_alias = __aeabi_f2iz] pub extern "C" fn __fixsfsi(f: f32) -> i32 { - float_to_int!(f, f32, i32) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_f2lz] pub extern "C" fn __fixsfdi(f: f32) -> i64 { - float_to_int!(f, f32, i64) + float_to_int(f) } #[unadjusted_on_win64] pub extern "C" fn __fixsfti(f: f32) -> i128 { - float_to_int!(f, f32, i128) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_d2iz] pub extern "C" fn __fixdfsi(f: f64) -> i32 { - float_to_int!(f, f64, i32) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_d2lz] pub extern "C" fn __fixdfdi(f: f64) -> i64 { - float_to_int!(f, f64, i64) + float_to_int(f) } #[unadjusted_on_win64] pub extern "C" fn __fixdfti(f: f64) -> i128 { - float_to_int!(f, f64, i128) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_f2uiz] pub extern "C" fn __fixunssfsi(f: f32) -> u32 { - float_to_int!(f, f32, u32) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_f2ulz] pub extern "C" fn __fixunssfdi(f: f32) -> u64 { - float_to_int!(f, f32, u64) + float_to_int(f) } #[unadjusted_on_win64] pub extern "C" fn __fixunssfti(f: f32) -> u128 { - float_to_int!(f, f32, u128) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_d2uiz] pub extern "C" fn __fixunsdfsi(f: f64) -> u32 { - float_to_int!(f, f64, u32) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_d2ulz] pub extern "C" fn __fixunsdfdi(f: f64) -> u64 { - float_to_int!(f, f64, u64) + float_to_int(f) } #[unadjusted_on_win64] pub extern "C" fn __fixunsdfti(f: f64) -> u128 { - float_to_int!(f, f64, u128) + float_to_int(f) } } diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 7f9a85c41938c..f4d5c0a3be87b 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -230,3 +230,28 @@ large_int!(u64, u32, u32, 32); large_int!(i64, u32, i32, 32); large_int!(u128, u64, u64, 64); large_int!(i128, u64, i64, 64); + +/// Trait to express (possibly lossy) casting of integers +pub trait CastInto: Copy { + fn cast(self) -> T; +} + +macro_rules! cast_into { + ($ty:ty) => { + cast_into!($ty; usize, isize, u32, i32, u64, i64, u128, i128); + }; + ($ty:ty; $($into:ty),*) => {$( + impl CastInto<$into> for $ty { + fn cast(self) -> $into { + self as $into + } + } + )*}; +} + +cast_into!(u32); +cast_into!(i32); +cast_into!(u64); +cast_into!(i64); +cast_into!(u128); +cast_into!(i128); From 13477e488f5cd49f0bd9cd84556d3a4edfdb0cee Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 14 Sep 2017 16:32:50 +0200 Subject: [PATCH 0382/4206] Convert int_to_float! to a function --- library/compiler-builtins/src/float/conv.rs | 136 ++++++++++---------- library/compiler-builtins/src/int/mod.rs | 32 ++++- 2 files changed, 101 insertions(+), 67 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 52fdf95599874..f358a17bd57ab 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -1,83 +1,87 @@ use float::Float; use int::{Int, CastInto}; -macro_rules! int_to_float { - ($i:expr, $ity:ty, $fty:ty) => ({ - let i = $i; - if i == 0 { - return 0.0 - } +fn int_to_float(i: I) -> F where + F::Int: CastInto, + F::Int: CastInto, + I::UnsignedInt: CastInto, + u32: CastInto, +{ + if i == I::ZERO { + return F::ZERO; + } - let mant_dig = <$fty>::SIGNIFICAND_BITS + 1; - let exponent_bias = <$fty>::EXPONENT_BIAS; + let two = I::UnsignedInt::ONE + I::UnsignedInt::ONE; + let four = two + two; + let mant_dig = F::SIGNIFICAND_BITS + 1; + let exponent_bias = F::EXPONENT_BIAS; - let n = <$ity>::BITS; - let (s, a) = i.extract_sign(); - let mut a = a; + let n = I::BITS; + let (s, a) = i.extract_sign(); + let mut a = a; - // number of significant digits - let sd = n - a.leading_zeros(); + // number of significant digits + let sd = n - a.leading_zeros(); - // exponent - let mut e = sd - 1; + // exponent + let mut e = sd - 1; - if <$ity>::BITS < mant_dig { - return <$fty>::from_parts(s, - (e + exponent_bias) as <$fty as Float>::Int, - (a as <$fty as Float>::Int) << (mant_dig - e - 1)) - } + if I::BITS < mant_dig { + return F::from_parts(s, + (e + exponent_bias).cast(), + a.cast() << (mant_dig - e - 1)); + } - a = if sd > mant_dig { - /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx - * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR - * 12345678901234567890123456 - * 1 = msb 1 bit - * P = bit MANT_DIG-1 bits to the right of 1 - * Q = bit MANT_DIG bits to the right of 1 - * R = "or" of all bits to the right of Q - */ - let mant_dig_plus_one = mant_dig + 1; - let mant_dig_plus_two = mant_dig + 2; - a = if sd == mant_dig_plus_one { - a << 1 - } else if sd == mant_dig_plus_two { - a - } else { - (a >> (sd - mant_dig_plus_two)) as <$ity as Int>::UnsignedInt | - ((a & <$ity as Int>::UnsignedInt::max_value()).wrapping_shl((n + mant_dig_plus_two) - sd) != 0) as <$ity as Int>::UnsignedInt - }; - - /* finish: */ - a |= ((a & 4) != 0) as <$ity as Int>::UnsignedInt; /* Or P into R */ - a += 1; /* round - this step may add a significant bit */ - a >>= 2; /* dump Q and R */ - - /* a is now rounded to mant_dig or mant_dig+1 bits */ - if (a & (1 << mant_dig)) != 0 { - a >>= 1; e += 1; - } + a = if sd > mant_dig { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit MANT_DIG-1 bits to the right of 1 + * Q = bit MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + let mant_dig_plus_one = mant_dig + 1; + let mant_dig_plus_two = mant_dig + 2; + a = if sd == mant_dig_plus_one { + a << 1 + } else if sd == mant_dig_plus_two { a - /* a is now rounded to mant_dig bits */ } else { - a.wrapping_shl(mant_dig - sd) - /* a is now rounded to mant_dig bits */ + (a >> (sd - mant_dig_plus_two)) | + Int::from_bool((a & I::UnsignedInt::max_value()).wrapping_shl((n + mant_dig_plus_two) - sd) != Int::ZERO) }; - <$fty>::from_parts(s, - (e + exponent_bias) as <$fty as Float>::Int, - a as <$fty as Float>::Int) - }) + /* finish: */ + a |= Int::from_bool((a & four) != I::UnsignedInt::ZERO); /* Or P into R */ + a += Int::ONE; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + + /* a is now rounded to mant_dig or mant_dig+1 bits */ + if (a & (I::UnsignedInt::ONE << mant_dig)) != Int::ZERO { + a >>= 1; e += 1; + } + a + /* a is now rounded to mant_dig bits */ + } else { + a.wrapping_shl(mant_dig - sd) + /* a is now rounded to mant_dig bits */ + }; + + F::from_parts(s, + (e + exponent_bias).cast(), + a.cast()) } intrinsics! { #[arm_aeabi_alias = __aeabi_i2f] pub extern "C" fn __floatsisf(i: i32) -> f32 { - int_to_float!(i, i32, f32) + int_to_float(i) } #[arm_aeabi_alias = __aeabi_i2d] pub extern "C" fn __floatsidf(i: i32) -> f64 { - int_to_float!(i, i32, f64) + int_to_float(i) } #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] @@ -88,28 +92,28 @@ intrinsics! { if cfg!(target_arch = "x86_64") { i as f64 } else { - int_to_float!(i, i64, f64) + int_to_float(i) } } #[unadjusted_on_win64] pub extern "C" fn __floattisf(i: i128) -> f32 { - int_to_float!(i, i128, f32) + int_to_float(i) } #[unadjusted_on_win64] pub extern "C" fn __floattidf(i: i128) -> f64 { - int_to_float!(i, i128, f64) + int_to_float(i) } #[arm_aeabi_alias = __aeabi_ui2f] pub extern "C" fn __floatunsisf(i: u32) -> f32 { - int_to_float!(i, u32, f32) + int_to_float(i) } #[arm_aeabi_alias = __aeabi_ui2d] pub extern "C" fn __floatunsidf(i: u32) -> f64 { - int_to_float!(i, u32, f64) + int_to_float(i) } #[use_c_shim_if(all(not(target_env = "msvc"), @@ -117,17 +121,17 @@ intrinsics! { all(not(windows), target_arch = "x86_64"))))] #[arm_aeabi_alias = __aeabi_ul2d] pub extern "C" fn __floatundidf(i: u64) -> f64 { - int_to_float!(i, u64, f64) + int_to_float(i) } #[unadjusted_on_win64] pub extern "C" fn __floatuntisf(i: u128) -> f32 { - int_to_float!(i, u128, f32) + int_to_float(i) } #[unadjusted_on_win64] pub extern "C" fn __floatuntidf(i: u128) -> f64 { - int_to_float!(i, u128, f64) + int_to_float(i) } } diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index f4d5c0a3be87b..c184301f5e204 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -23,6 +23,9 @@ pub trait Int: PartialEq + PartialOrd + ops::AddAssign + + ops::BitAndAssign + + ops::BitOrAssign + + ops::ShrAssign + ops::Add + ops::Sub + ops::Div + @@ -31,7 +34,6 @@ pub trait Int: ops::BitOr + ops::BitXor + ops::BitAnd + - ops::BitAndAssign + ops::Not + { /// Type with the same width but other signedness @@ -60,14 +62,18 @@ pub trait Int: fn unsigned(self) -> Self::UnsignedInt; fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; + fn from_bool(b: bool) -> Self; + // copied from primitive integers, but put in a trait fn max_value() -> Self; fn min_value() -> Self; fn wrapping_add(self, other: Self) -> Self; fn wrapping_mul(self, other: Self) -> Self; fn wrapping_sub(self, other: Self) -> Self; + fn wrapping_shl(self, other: u32) -> Self; fn aborting_div(self, other: Self) -> Self; fn aborting_rem(self, other: Self) -> Self; + fn leading_zeros(self) -> u32; } fn unwrap(t: Option) -> T { @@ -100,6 +106,10 @@ macro_rules! int_impl { me } + fn from_bool(b: bool) -> Self { + b as $uty + } + fn max_value() -> Self { ::max_value() } @@ -120,6 +130,10 @@ macro_rules! int_impl { ::wrapping_sub(self, other) } + fn wrapping_shl(self, other: u32) -> Self { + ::wrapping_shl(self, other) + } + fn aborting_div(self, other: Self) -> Self { unwrap(::checked_div(self, other)) } @@ -127,6 +141,10 @@ macro_rules! int_impl { fn aborting_rem(self, other: Self) -> Self { unwrap(::checked_rem(self, other)) } + + fn leading_zeros(self) -> u32 { + ::leading_zeros(self) + } } impl Int for $ity { @@ -154,6 +172,10 @@ macro_rules! int_impl { me as $ity } + fn from_bool(b: bool) -> Self { + b as $ity + } + fn max_value() -> Self { ::max_value() } @@ -174,6 +196,10 @@ macro_rules! int_impl { ::wrapping_sub(self, other) } + fn wrapping_shl(self, other: u32) -> Self { + ::wrapping_shl(self, other) + } + fn aborting_div(self, other: Self) -> Self { unwrap(::checked_div(self, other)) } @@ -181,6 +207,10 @@ macro_rules! int_impl { fn aborting_rem(self, other: Self) -> Self { unwrap(::checked_rem(self, other)) } + + fn leading_zeros(self) -> u32 { + ::leading_zeros(self) + } } } } From f2794913f3c324c68306d20acef9c6568fb074ee Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 14 Sep 2017 17:33:44 +0200 Subject: [PATCH 0383/4206] Convert add! to a function --- library/compiler-builtins/src/float/add.rs | 317 +++++++++++---------- library/compiler-builtins/src/int/mod.rs | 1 + 2 files changed, 160 insertions(+), 158 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index fae14f07c3eba..d355cb1ff27d3 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -1,195 +1,196 @@ -use int::Int; +use int::{Int, CastInto}; use float::Float; /// Returns `a + b` -macro_rules! add { - ($a:expr, $b:expr, $ty:ty) => ({ - let a = $a; - let b = $b; - let one = <$ty as Float>::Int::ONE; - let zero = <$ty as Float>::Int::ZERO; - - let bits = <$ty>::BITS as <$ty as Float>::Int; - let significand_bits = <$ty>::SIGNIFICAND_BITS as <$ty as Float>::Int; - let exponent_bits = <$ty>::EXPONENT_BITS as <$ty as Float>::Int; - let max_exponent = (one << exponent_bits as usize) - one; - - let implicit_bit = one << significand_bits as usize; - let significand_mask = implicit_bit - one; - let sign_bit = <$ty>::SIGN_MASK as <$ty as Float>::Int; - let abs_mask = sign_bit - one; - let exponent_mask = abs_mask ^ significand_mask; - let inf_rep = exponent_mask; - let quiet_bit = implicit_bit >> 1; - let qnan_rep = exponent_mask | quiet_bit; - - let mut a_rep = a.repr(); - let mut b_rep = b.repr(); - let a_abs = a_rep & abs_mask; - let b_abs = b_rep & abs_mask; - - // Detect if a or b is zero, infinity, or NaN. - if a_abs.wrapping_sub(one) >= inf_rep - one || - b_abs.wrapping_sub(one) >= inf_rep - one { - // NaN + anything = qNaN - if a_abs > inf_rep { - return <$ty as Float>::from_repr(a_abs | quiet_bit); - } - // anything + NaN = qNaN - if b_abs > inf_rep { - return <$ty as Float>::from_repr(b_abs | quiet_bit); - } - - if a_abs == inf_rep { - // +/-infinity + -/+infinity = qNaN - if (a.repr() ^ b.repr()) == sign_bit { - return <$ty as Float>::from_repr(qnan_rep); - } else { - // +/-infinity + anything remaining = +/- infinity - return a; - } - } +fn add(a: F, b: F) -> F where + u32: CastInto, + F::Int: CastInto, + i32: CastInto, + F::Int: CastInto, +{ + let one = F::Int::ONE; + let zero = F::Int::ZERO; + + let bits = F::BITS.cast(); + let significand_bits = F::SIGNIFICAND_BITS; + let max_exponent = F::EXPONENT_MAX; + + let implicit_bit = F::IMPLICIT_BIT; + let significand_mask = F::SIGNIFICAND_MASK; + let sign_bit = F::SIGN_MASK as F::Int; + let abs_mask = sign_bit - one; + let exponent_mask = F::EXPONENT_MASK; + let inf_rep = exponent_mask; + let quiet_bit = implicit_bit >> 1; + let qnan_rep = exponent_mask | quiet_bit; + + let mut a_rep = a.repr(); + let mut b_rep = b.repr(); + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; + + // Detect if a or b is zero, infinity, or NaN. + if a_abs.wrapping_sub(one) >= inf_rep - one || + b_abs.wrapping_sub(one) >= inf_rep - one { + // NaN + anything = qNaN + if a_abs > inf_rep { + return F::from_repr(a_abs | quiet_bit); + } + // anything + NaN = qNaN + if b_abs > inf_rep { + return F::from_repr(b_abs | quiet_bit); + } - // anything remaining + +/-infinity = +/-infinity - if b_abs == inf_rep { - return b; + if a_abs == inf_rep { + // +/-infinity + -/+infinity = qNaN + if (a.repr() ^ b.repr()) == sign_bit { + return F::from_repr(qnan_rep); + } else { + // +/-infinity + anything remaining = +/- infinity + return a; } + } - // zero + anything = anything - if a_abs == 0 { - // but we need to get the sign right for zero + zero - if b_abs == 0 { - return <$ty as Float>::from_repr(a.repr() & b.repr()); - } else { - return b; - } - } + // anything remaining + +/-infinity = +/-infinity + if b_abs == inf_rep { + return b; + } - // anything + zero = anything - if b_abs == 0 { - return a; + // zero + anything = anything + if a_abs == Int::ZERO { + // but we need to get the sign right for zero + zero + if b_abs == Int::ZERO { + return F::from_repr(a.repr() & b.repr()); + } else { + return b; } } - // Swap a and b if necessary so that a has the larger absolute value. - if b_abs > a_abs { - // Don't use mem::swap because it may generate references to memcpy in unoptimized code. - let tmp = a_rep; - a_rep = b_rep; - b_rep = tmp; + // anything + zero = anything + if b_abs == Int::ZERO { + return a; } + } + + // Swap a and b if necessary so that a has the larger absolute value. + if b_abs > a_abs { + // Don't use mem::swap because it may generate references to memcpy in unoptimized code. + let tmp = a_rep; + a_rep = b_rep; + b_rep = tmp; + } - // Extract the exponent and significand from the (possibly swapped) a and b. - let mut a_exponent = ((a_rep >> significand_bits) & max_exponent) as i32; - let mut b_exponent = ((b_rep >> significand_bits) & max_exponent) as i32; - let mut a_significand = a_rep & significand_mask; - let mut b_significand = b_rep & significand_mask; - - // normalize any denormals, and adjust the exponent accordingly. - if a_exponent == 0 { - let (exponent, significand) = <$ty>::normalize(a_significand); - a_exponent = exponent; - a_significand = significand; + // Extract the exponent and significand from the (possibly swapped) a and b. + let mut a_exponent: i32 = ((a_rep & exponent_mask) >> significand_bits).cast(); + let mut b_exponent: i32 = ((b_rep & exponent_mask) >> significand_bits).cast(); + let mut a_significand = a_rep & significand_mask; + let mut b_significand = b_rep & significand_mask; + + // normalize any denormals, and adjust the exponent accordingly. + if a_exponent == 0 { + let (exponent, significand) = F::normalize(a_significand); + a_exponent = exponent; + a_significand = significand; + } + if b_exponent == 0 { + let (exponent, significand) = F::normalize(b_significand); + b_exponent = exponent; + b_significand = significand; + } + + // The sign of the result is the sign of the larger operand, a. If they + // have opposite signs, we are performing a subtraction; otherwise addition. + let result_sign = a_rep & sign_bit; + let subtraction = ((a_rep ^ b_rep) & sign_bit) != zero; + + // Shift the significands to give us round, guard and sticky, and or in the + // implicit significand bit. (If we fell through from the denormal path it + // was already set by normalize(), but setting it twice won't hurt + // anything.) + a_significand = (a_significand | implicit_bit) << 3; + b_significand = (b_significand | implicit_bit) << 3; + + // Shift the significand of b by the difference in exponents, with a sticky + // bottom bit to get rounding correct. + let align = a_exponent.wrapping_sub(b_exponent).cast(); + if align != Int::ZERO { + if align < bits { + let sticky = F::Int::from_bool(b_significand << bits.wrapping_sub(align).cast() != Int::ZERO); + b_significand = (b_significand >> align.cast()) | sticky; + } else { + b_significand = one; // sticky; b is known to be non-zero. } - if b_exponent == 0 { - let (exponent, significand) = <$ty>::normalize(b_significand); - b_exponent = exponent; - b_significand = significand; + } + if subtraction { + a_significand = a_significand.wrapping_sub(b_significand); + // If a == -b, return +zero. + if a_significand == Int::ZERO { + return F::from_repr(Int::ZERO); } - // The sign of the result is the sign of the larger operand, a. If they - // have opposite signs, we are performing a subtraction; otherwise addition. - let result_sign = a_rep & sign_bit; - let subtraction = ((a_rep ^ b_rep) & sign_bit) != zero; - - // Shift the significands to give us round, guard and sticky, and or in the - // implicit significand bit. (If we fell through from the denormal path it - // was already set by normalize(), but setting it twice won't hurt - // anything.) - a_significand = (a_significand | implicit_bit) << 3; - b_significand = (b_significand | implicit_bit) << 3; - - // Shift the significand of b by the difference in exponents, with a sticky - // bottom bit to get rounding correct. - let align = a_exponent.wrapping_sub(b_exponent) as <$ty as Float>::Int; - if align != 0 { - if align < bits { - let sticky = (b_significand << (bits.wrapping_sub(align) as usize) != 0) as <$ty as Float>::Int; - b_significand = (b_significand >> align as usize) | sticky; - } else { - b_significand = one; // sticky; b is known to be non-zero. - } + // If partial cancellation occured, we need to left-shift the result + // and adjust the exponent: + if a_significand < implicit_bit << 3 { + let shift = a_significand.leading_zeros() as i32 + - (implicit_bit << 3).leading_zeros() as i32; + a_significand <<= shift; + a_exponent -= shift; } - if subtraction { - a_significand = a_significand.wrapping_sub(b_significand); - // If a == -b, return +zero. - if a_significand == 0 { - return <$ty as Float>::from_repr(0); - } - - // If partial cancellation occured, we need to left-shift the result - // and adjust the exponent: - if a_significand < implicit_bit << 3 { - let shift = a_significand.leading_zeros() as i32 - - (implicit_bit << 3).leading_zeros() as i32; - a_significand <<= shift as usize; - a_exponent -= shift; - } - } else /* addition */ { - a_significand += b_significand; - - // If the addition carried up, we need to right-shift the result and - // adjust the exponent: - if a_significand & implicit_bit << 4 != 0 { - let sticky = (a_significand & one != 0) as <$ty as Float>::Int; - a_significand = a_significand >> 1 | sticky; - a_exponent += 1; - } + } else /* addition */ { + a_significand += b_significand; + + // If the addition carried up, we need to right-shift the result and + // adjust the exponent: + if a_significand & implicit_bit << 4 != Int::ZERO { + let sticky = F::Int::from_bool(a_significand & one != Int::ZERO); + a_significand = a_significand >> 1 | sticky; + a_exponent += 1; } + } - // If we have overflowed the type, return +/- infinity: - if a_exponent >= max_exponent as i32 { - return <$ty>::from_repr(inf_rep | result_sign); - } + // If we have overflowed the type, return +/- infinity: + if a_exponent >= max_exponent as i32 { + return F::from_repr(inf_rep | result_sign); + } - if a_exponent <= 0 { - // Result is denormal before rounding; the exponent is zero and we - // need to shift the significand. - let shift = (1 - a_exponent) as <$ty as Float>::Int; - let sticky = ((a_significand << bits.wrapping_sub(shift) as usize) != 0) as <$ty as Float>::Int; - a_significand = a_significand >> shift as usize | sticky; - a_exponent = 0; - } + if a_exponent <= 0 { + // Result is denormal before rounding; the exponent is zero and we + // need to shift the significand. + let shift = (1 - a_exponent).cast(); + let sticky = F::Int::from_bool((a_significand << bits.wrapping_sub(shift).cast()) != Int::ZERO); + a_significand = a_significand >> shift.cast() | sticky; + a_exponent = 0; + } - // Low three bits are round, guard, and sticky. - let round_guard_sticky: i32 = (a_significand & 0x7) as i32; + // Low three bits are round, guard, and sticky. + let a_significand_i32: i32 = a_significand.cast(); + let round_guard_sticky: i32 = a_significand_i32 & 0x7; - // Shift the significand into place, and mask off the implicit bit. - let mut result = a_significand >> 3 & significand_mask; + // Shift the significand into place, and mask off the implicit bit. + let mut result = a_significand >> 3 & significand_mask; - // Insert the exponent and sign. - result |= (a_exponent as <$ty as Float>::Int) << (significand_bits as usize); - result |= result_sign; + // Insert the exponent and sign. + result |= a_exponent.cast() << significand_bits; + result |= result_sign; - // Final rounding. The result may overflow to infinity, but that is the - // correct result in that case. - if round_guard_sticky > 0x4 { result += one; } - if round_guard_sticky == 0x4 { result += result & one; } + // Final rounding. The result may overflow to infinity, but that is the + // correct result in that case. + if round_guard_sticky > 0x4 { result += one; } + if round_guard_sticky == 0x4 { result += result & one; } - <$ty>::from_repr(result) - }) + F::from_repr(result) } intrinsics! { #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_fadd] pub extern "C" fn __addsf3(a: f32, b: f32) -> f32 { - add!(a, b, f32) + add(a, b) } #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_dadd] pub extern "C" fn __adddf3(a: f64, b: f64) -> f64 { - add!(a, b, f64) + add(a, b) } } diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index c184301f5e204..c8706c33c5b14 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -25,6 +25,7 @@ pub trait Int: ops::AddAssign + ops::BitAndAssign + ops::BitOrAssign + + ops::ShlAssign + ops::ShrAssign + ops::Add + ops::Sub + From 5ce08df93ec0cbf686c2c43009cc5f5b382e4181 Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 14 Sep 2017 17:39:25 +0200 Subject: [PATCH 0384/4206] Remove duplication by adding a macro --- library/compiler-builtins/src/int/mod.rs | 89 +++++++----------------- 1 file changed, 26 insertions(+), 63 deletions(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index c8706c33c5b14..24b27b1faea7f 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -84,31 +84,15 @@ fn unwrap(t: Option) -> T { } } -macro_rules! int_impl { - ($ity:ty, $uty:ty, $bits:expr) => { - impl Int for $uty { - type OtherSign = $ity; - type UnsignedInt = $uty; - +macro_rules! int_impl_common { + ($ty:ty, $bits:expr) => { const BITS: u32 = $bits; const ZERO: Self = 0; const ONE: Self = 1; - fn extract_sign(self) -> (bool, $uty) { - (false, self) - } - - fn unsigned(self) -> $uty { - self - } - - fn from_unsigned(me: $uty) -> Self { - me - } - fn from_bool(b: bool) -> Self { - b as $uty + b as $ty } fn max_value() -> Self { @@ -146,17 +130,34 @@ macro_rules! int_impl { fn leading_zeros(self) -> u32 { ::leading_zeros(self) } + } +} + +macro_rules! int_impl { + ($ity:ty, $uty:ty, $bits:expr) => { + impl Int for $uty { + type OtherSign = $ity; + type UnsignedInt = $uty; + + fn extract_sign(self) -> (bool, $uty) { + (false, self) + } + + fn unsigned(self) -> $uty { + self + } + + fn from_unsigned(me: $uty) -> Self { + me + } + + int_impl_common!($uty, $bits); } impl Int for $ity { type OtherSign = $uty; type UnsignedInt = $uty; - const BITS: u32 = $bits; - - const ZERO: Self = 0; - const ONE: Self = 1; - fn extract_sign(self) -> (bool, $uty) { if self < 0 { (true, (!(self as $uty)).wrapping_add(1)) @@ -173,45 +174,7 @@ macro_rules! int_impl { me as $ity } - fn from_bool(b: bool) -> Self { - b as $ity - } - - fn max_value() -> Self { - ::max_value() - } - - fn min_value() -> Self { - ::min_value() - } - - fn wrapping_add(self, other: Self) -> Self { - ::wrapping_add(self, other) - } - - fn wrapping_mul(self, other: Self) -> Self { - ::wrapping_mul(self, other) - } - - fn wrapping_sub(self, other: Self) -> Self { - ::wrapping_sub(self, other) - } - - fn wrapping_shl(self, other: u32) -> Self { - ::wrapping_shl(self, other) - } - - fn aborting_div(self, other: Self) -> Self { - unwrap(::checked_div(self, other)) - } - - fn aborting_rem(self, other: Self) -> Self { - unwrap(::checked_rem(self, other)) - } - - fn leading_zeros(self) -> u32 { - ::leading_zeros(self) - } + int_impl_common!($ity, $bits); } } } From 259327c25be9cf89f93b405339ac2b799b4ca4fb Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 15 Sep 2017 15:59:15 -0700 Subject: [PATCH 0385/4206] Update MinGW download location --- library/compiler-builtins/appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml index e51ddab740e32..bb78ad36a2a8e 100644 --- a/library/compiler-builtins/appveyor.yml +++ b/library/compiler-builtins/appveyor.yml @@ -14,8 +14,8 @@ environment: # `rust_eh_unwind_resume` in the debug LTO builds that aren't optimized out, # so we skip that test for now. Would be great to not skip it! - TARGET: i686-pc-windows-gnu - MINGW_URL: https://s3.amazonaws.com/rust-lang-ci - MINGW_ARCHIVE: i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z + MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror + MINGW_ARCHIVE: i686-6.3.0-release-win32-dwarf-rt_v5-rev1.7z MINGW_DIR: mingw32 DEBUG_LTO_BUILD_DOESNT_WORK: 1 - TARGET: x86_64-pc-windows-gnu From 1f98921e44cbe72fd12b225c1119f5190dda1a06 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Fri, 15 Sep 2017 17:18:54 -0500 Subject: [PATCH 0386/4206] Implement x86 chkstk in "rust" --- library/compiler-builtins/README.md | 4 +- library/compiler-builtins/build.rs | 2 - library/compiler-builtins/src/lib.rs | 3 + library/compiler-builtins/src/x86.rs | 71 ++++++++++++++++++++++++ library/compiler-builtins/src/x86_64.rs | 74 +++++++++++++------------ 5 files changed, 114 insertions(+), 40 deletions(-) create mode 100644 library/compiler-builtins/src/x86.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 3571200aa3bc0..635699643411d 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -159,8 +159,8 @@ features = ["c"] - [x] floatunsisf.c - [ ] i386/ashldi3.S - [ ] i386/ashrdi3.S -- [ ] i386/chkstk.S -- [ ] i386/chkstk2.S +- [x] i386/chkstk.S +- [x] i386/chkstk2.S - [ ] i386/divdi3.S - [ ] i386/lshrdi3.S - [ ] i386/moddi3.S diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 8b5695ba422d2..74e506eff7754 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4176,8 +4176,6 @@ mod c { &[ "i386/ashldi3.S", "i386/ashrdi3.S", - "i386/chkstk.S", - "i386/chkstk2.S", "i386/divdi3.S", "i386/floatdidf.S", "i386/floatdisf.S", diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index b8cf83e2125d2..d30a218e3dfea 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -51,6 +51,9 @@ pub mod mem; #[cfg(target_arch = "arm")] pub mod arm; +#[cfg(target_arch = "x86")] +pub mod x86; + #[cfg(target_arch = "x86_64")] pub mod x86_64; diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs new file mode 100644 index 0000000000000..554b08fec0d35 --- /dev/null +++ b/library/compiler-builtins/src/x86.rs @@ -0,0 +1,71 @@ +#![allow(unused_imports)] + +use core::intrinsics; + +// NOTE These functions are implemented using assembly because they using a custom +// calling convention which can't be implemented using a normal Rust function + +// NOTE These functions are never mangled as they are not tested against compiler-rt +// and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca + +#[cfg(all(windows, target_env = "gnu"))] +#[naked] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +pub unsafe fn ___chkstk_ms() { + asm!(" + push %ecx + push %eax + cmp $$0x1000,%eax + lea 12(%esp),%ecx + jb 1f + 2: + sub $$0x1000,%ecx + test %ecx,(%ecx) + sub $$0x1000,%eax + cmp $$0x1000,%eax + ja 2b + 1: + sub %eax,%ecx + test %ecx,(%ecx) + pop %eax + pop %ecx + ret"); + intrinsics::unreachable(); +} + +// FIXME: __alloca should be an alias to __chkstk +#[cfg(all(windows, target_env = "gnu"))] +#[naked] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +pub unsafe fn __alloca() { + asm!("jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable"); + intrinsics::unreachable(); +} + +#[cfg(all(windows, target_env = "gnu"))] +#[naked] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +pub unsafe fn ___chkstk() { + asm!(" + push %ecx + cmp $$0x1000,%eax + lea 8(%esp),%ecx // esp before calling this routine -> ecx + jb 1f + 2: + sub $$0x1000,%ecx + test %ecx,(%ecx) + sub $$0x1000,%eax + cmp $$0x1000,%eax + ja 2b + 1: + sub %eax,%ecx + test %ecx,(%ecx) + + lea 4(%esp),%eax // load pointer to the return address into eax + mov %ecx,%esp // install the new top of stack pointer into esp + mov -4(%eax),%ecx // restore ecx + push (%eax) // push return address onto the stack + sub %esp,%eax // restore the original value in eax + ret"); + intrinsics::unreachable(); +} diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index bc3c4ee4c5550..221161f4ed636 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -12,23 +12,24 @@ use core::intrinsics; #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn ___chkstk_ms() { - asm!("push %rcx - push %rax - cmp $$0x1000,%rax - lea 24(%rsp),%rcx - jb 1f - 2: - sub $$0x1000,%rcx - test %rcx,(%rcx) - sub $$0x1000,%rax - cmp $$0x1000,%rax - ja 2b - 1: - sub %rax,%rcx - test %rcx,(%rcx) - pop %rax - pop %rcx - ret"); + asm!(" + push %rcx + push %rax + cmp $$0x1000,%rax + lea 24(%rsp),%rcx + jb 1f + 2: + sub $$0x1000,%rcx + test %rcx,(%rcx) + sub $$0x1000,%rax + cmp $$0x1000,%rax + ja 2b + 1: + sub %rax,%rcx + test %rcx,(%rcx) + pop %rax + pop %rcx + ret"); intrinsics::unreachable(); } @@ -45,25 +46,26 @@ pub unsafe fn __alloca() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn ___chkstk() { - asm!("push %rcx - cmp $$0x1000,%rax - lea 16(%rsp),%rcx // rsp before calling this routine -> rcx - jb 1f - 2: - sub $$0x1000,%rcx - test %rcx,(%rcx) - sub $$0x1000,%rax - cmp $$0x1000,%rax - ja 2b - 1: - sub %rax,%rcx - test %rcx,(%rcx) + asm!(" + push %rcx + cmp $$0x1000,%rax + lea 16(%rsp),%rcx // rsp before calling this routine -> rcx + jb 1f + 2: + sub $$0x1000,%rcx + test %rcx,(%rcx) + sub $$0x1000,%rax + cmp $$0x1000,%rax + ja 2b + 1: + sub %rax,%rcx + test %rcx,(%rcx) - lea 8(%rsp),%rax // load pointer to the return address into rax - mov %rcx,%rsp // install the new top of stack pointer into rsp - mov -8(%rax),%rcx // restore rcx - push (%rax) // push return address onto the stack - sub %rsp,%rax // restore the original value in rax - ret"); + lea 8(%rsp),%rax // load pointer to the return address into rax + mov %rcx,%rsp // install the new top of stack pointer into rsp + mov -8(%rax),%rcx // restore rcx + push (%rax) // push return address onto the stack + sub %rsp,%rax // restore the original value in rax + ret"); intrinsics::unreachable(); } From 81fe6a9654f4dbf473cec7217ab3d2e13733dc69 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Fri, 15 Sep 2017 18:04:11 -0500 Subject: [PATCH 0387/4206] Don't compile probestack functions during testing --- library/compiler-builtins/src/probestack.rs | 8 ++++---- library/compiler-builtins/src/x86.rs | 12 ++++++------ library/compiler-builtins/src/x86_64.rs | 12 ++++++------ 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 329e2726511ce..13ea5a5f03b38 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -44,8 +44,8 @@ #![cfg(not(windows))] // Windows already has builtins to do this #[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg(target_arch = "x86_64")] +#[no_mangle] +#[cfg(all(target_arch = "x86_64", not(feature = "mangled-names")))] pub unsafe extern fn __rust_probestack() { // Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax, // ensuring that if any pages are unmapped we'll make a page fault. @@ -87,8 +87,8 @@ pub unsafe extern fn __rust_probestack() { } #[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg(target_arch = "x86")] +#[no_mangle] +#[cfg(all(target_arch = "x86", not(feature = "mangled-names")))] pub unsafe extern fn __rust_probestack() { // This is the same as x86_64 above, only translated for 32-bit sizes. Note // that on Unix we're expected to restore everything as it was, this diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs index 554b08fec0d35..3e540e21eff51 100644 --- a/library/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/src/x86.rs @@ -8,9 +8,9 @@ use core::intrinsics; // NOTE These functions are never mangled as they are not tested against compiler-rt // and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca -#[cfg(all(windows, target_env = "gnu"))] +#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] #[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[no_mangle] pub unsafe fn ___chkstk_ms() { asm!(" push %ecx @@ -34,17 +34,17 @@ pub unsafe fn ___chkstk_ms() { } // FIXME: __alloca should be an alias to __chkstk -#[cfg(all(windows, target_env = "gnu"))] +#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] #[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[no_mangle] pub unsafe fn __alloca() { asm!("jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable"); intrinsics::unreachable(); } -#[cfg(all(windows, target_env = "gnu"))] +#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] #[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[no_mangle] pub unsafe fn ___chkstk() { asm!(" push %ecx diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 221161f4ed636..09b008152659e 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -8,9 +8,9 @@ use core::intrinsics; // NOTE These functions are never mangled as they are not tested against compiler-rt // and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca -#[cfg(all(windows, target_env = "gnu"))] +#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] #[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[no_mangle] pub unsafe fn ___chkstk_ms() { asm!(" push %rcx @@ -33,18 +33,18 @@ pub unsafe fn ___chkstk_ms() { intrinsics::unreachable(); } -#[cfg(all(windows, target_env = "gnu"))] +#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] #[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[no_mangle] pub unsafe fn __alloca() { asm!("mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable"); intrinsics::unreachable(); } -#[cfg(all(windows, target_env = "gnu"))] +#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] #[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +#[no_mangle] pub unsafe fn ___chkstk() { asm!(" push %rcx From 0a260ce265bf7585881a3630ff7b6346a8824e94 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 17 Sep 2017 15:24:36 -0700 Subject: [PATCH 0388/4206] Disable empty intrinsics on i686-apple-darwin These all currently just produce empty object files --- library/compiler-builtins/build.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 74e506eff7754..18f32ab1cd807 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4112,7 +4112,9 @@ mod c { ]); } - if target_os != "ios" { + // On iOS and 32-bit OSX these are all just empty intrinsics, no need to + // include them. + if target_os != "ios" && (target_vendor != "apple" || target_arch != "x86") { sources.extend( &[ "absvti2.c", From 46dab7688fe9d85358dc5795cb6549877012824f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 22 Sep 2017 21:30:12 -0700 Subject: [PATCH 0389/4206] Update to the `cc` dependency --- library/compiler-builtins/Cargo.toml | 6 +++--- library/compiler-builtins/build.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 84cefb2d280ff..b7743c2ce06d0 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -8,12 +8,12 @@ version = "0.1.0" cast = { version = "0.2.2", features = ["x128"], optional = true } rand = { version = "0.3.15", optional = true } -[build-dependencies.gcc] +[build-dependencies.cc] optional = true -version = "0.3.53" +version = "1.0" [features] -c = ["gcc"] +c = ["cc"] compiler-builtins = [] default = ["compiler-builtins"] mem = [] diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 18f32ab1cd807..1895201e8fa64 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -3957,7 +3957,7 @@ macro_rules! panic { #[cfg(feature = "c")] mod c { - extern crate gcc; + extern crate cc; use std::collections::BTreeMap; use std::env; @@ -4008,7 +4008,7 @@ mod c { let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap(); - let cfg = &mut gcc::Build::new(); + let cfg = &mut cc::Build::new(); cfg.warnings(false); From 832c7758f94146c16a35de55d1ca100ad4762f50 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 22 Sep 2017 21:31:27 -0700 Subject: [PATCH 0390/4206] Ignore failing test on mips --- library/compiler-builtins/tests/floattidf.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/tests/floattidf.rs b/library/compiler-builtins/tests/floattidf.rs index 4e4f84ddb01b9..c2e798a996352 100644 --- a/library/compiler-builtins/tests/floattidf.rs +++ b/library/compiler-builtins/tests/floattidf.rs @@ -4,5 +4,6 @@ not(any(target_env = "gnu", target_env = "musl")), target_os = "linux", test), no_std)] +#![cfg(not(target_arch = "mips"))] // FIXME(#168) include!(concat!(env!("OUT_DIR"), "/floattidf.rs")); From aef124cc751774aae1ff2f3648a577359c72b459 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 29 Sep 2017 02:19:40 +0200 Subject: [PATCH 0391/4206] Partially revert 482d98318fc1bfd003942c9de4ee1c7e8a0c45f0 This partially reverts "Convert int_to_float! to a function". --- library/compiler-builtins/src/float/conv.rs | 136 ++++++++++---------- 1 file changed, 66 insertions(+), 70 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index f358a17bd57ab..52fdf95599874 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -1,87 +1,83 @@ use float::Float; use int::{Int, CastInto}; -fn int_to_float(i: I) -> F where - F::Int: CastInto, - F::Int: CastInto, - I::UnsignedInt: CastInto, - u32: CastInto, -{ - if i == I::ZERO { - return F::ZERO; - } +macro_rules! int_to_float { + ($i:expr, $ity:ty, $fty:ty) => ({ + let i = $i; + if i == 0 { + return 0.0 + } - let two = I::UnsignedInt::ONE + I::UnsignedInt::ONE; - let four = two + two; - let mant_dig = F::SIGNIFICAND_BITS + 1; - let exponent_bias = F::EXPONENT_BIAS; + let mant_dig = <$fty>::SIGNIFICAND_BITS + 1; + let exponent_bias = <$fty>::EXPONENT_BIAS; - let n = I::BITS; - let (s, a) = i.extract_sign(); - let mut a = a; + let n = <$ity>::BITS; + let (s, a) = i.extract_sign(); + let mut a = a; - // number of significant digits - let sd = n - a.leading_zeros(); + // number of significant digits + let sd = n - a.leading_zeros(); - // exponent - let mut e = sd - 1; + // exponent + let mut e = sd - 1; - if I::BITS < mant_dig { - return F::from_parts(s, - (e + exponent_bias).cast(), - a.cast() << (mant_dig - e - 1)); - } + if <$ity>::BITS < mant_dig { + return <$fty>::from_parts(s, + (e + exponent_bias) as <$fty as Float>::Int, + (a as <$fty as Float>::Int) << (mant_dig - e - 1)) + } - a = if sd > mant_dig { - /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx - * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR - * 12345678901234567890123456 - * 1 = msb 1 bit - * P = bit MANT_DIG-1 bits to the right of 1 - * Q = bit MANT_DIG bits to the right of 1 - * R = "or" of all bits to the right of Q - */ - let mant_dig_plus_one = mant_dig + 1; - let mant_dig_plus_two = mant_dig + 2; - a = if sd == mant_dig_plus_one { - a << 1 - } else if sd == mant_dig_plus_two { + a = if sd > mant_dig { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit MANT_DIG-1 bits to the right of 1 + * Q = bit MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + let mant_dig_plus_one = mant_dig + 1; + let mant_dig_plus_two = mant_dig + 2; + a = if sd == mant_dig_plus_one { + a << 1 + } else if sd == mant_dig_plus_two { + a + } else { + (a >> (sd - mant_dig_plus_two)) as <$ity as Int>::UnsignedInt | + ((a & <$ity as Int>::UnsignedInt::max_value()).wrapping_shl((n + mant_dig_plus_two) - sd) != 0) as <$ity as Int>::UnsignedInt + }; + + /* finish: */ + a |= ((a & 4) != 0) as <$ity as Int>::UnsignedInt; /* Or P into R */ + a += 1; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + + /* a is now rounded to mant_dig or mant_dig+1 bits */ + if (a & (1 << mant_dig)) != 0 { + a >>= 1; e += 1; + } a + /* a is now rounded to mant_dig bits */ } else { - (a >> (sd - mant_dig_plus_two)) | - Int::from_bool((a & I::UnsignedInt::max_value()).wrapping_shl((n + mant_dig_plus_two) - sd) != Int::ZERO) + a.wrapping_shl(mant_dig - sd) + /* a is now rounded to mant_dig bits */ }; - /* finish: */ - a |= Int::from_bool((a & four) != I::UnsignedInt::ZERO); /* Or P into R */ - a += Int::ONE; /* round - this step may add a significant bit */ - a >>= 2; /* dump Q and R */ - - /* a is now rounded to mant_dig or mant_dig+1 bits */ - if (a & (I::UnsignedInt::ONE << mant_dig)) != Int::ZERO { - a >>= 1; e += 1; - } - a - /* a is now rounded to mant_dig bits */ - } else { - a.wrapping_shl(mant_dig - sd) - /* a is now rounded to mant_dig bits */ - }; - - F::from_parts(s, - (e + exponent_bias).cast(), - a.cast()) + <$fty>::from_parts(s, + (e + exponent_bias) as <$fty as Float>::Int, + a as <$fty as Float>::Int) + }) } intrinsics! { #[arm_aeabi_alias = __aeabi_i2f] pub extern "C" fn __floatsisf(i: i32) -> f32 { - int_to_float(i) + int_to_float!(i, i32, f32) } #[arm_aeabi_alias = __aeabi_i2d] pub extern "C" fn __floatsidf(i: i32) -> f64 { - int_to_float(i) + int_to_float!(i, i32, f64) } #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] @@ -92,28 +88,28 @@ intrinsics! { if cfg!(target_arch = "x86_64") { i as f64 } else { - int_to_float(i) + int_to_float!(i, i64, f64) } } #[unadjusted_on_win64] pub extern "C" fn __floattisf(i: i128) -> f32 { - int_to_float(i) + int_to_float!(i, i128, f32) } #[unadjusted_on_win64] pub extern "C" fn __floattidf(i: i128) -> f64 { - int_to_float(i) + int_to_float!(i, i128, f64) } #[arm_aeabi_alias = __aeabi_ui2f] pub extern "C" fn __floatunsisf(i: u32) -> f32 { - int_to_float(i) + int_to_float!(i, u32, f32) } #[arm_aeabi_alias = __aeabi_ui2d] pub extern "C" fn __floatunsidf(i: u32) -> f64 { - int_to_float(i) + int_to_float!(i, u32, f64) } #[use_c_shim_if(all(not(target_env = "msvc"), @@ -121,17 +117,17 @@ intrinsics! { all(not(windows), target_arch = "x86_64"))))] #[arm_aeabi_alias = __aeabi_ul2d] pub extern "C" fn __floatundidf(i: u64) -> f64 { - int_to_float(i) + int_to_float!(i, u64, f64) } #[unadjusted_on_win64] pub extern "C" fn __floatuntisf(i: u128) -> f32 { - int_to_float(i) + int_to_float!(i, u128, f32) } #[unadjusted_on_win64] pub extern "C" fn __floatuntidf(i: u128) -> f64 { - int_to_float(i) + int_to_float!(i, u128, f64) } } From c582a5c1180d93173abe118364d0f8ea58e134b2 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 29 Sep 2017 02:20:27 +0200 Subject: [PATCH 0392/4206] Partially revert a272d753f5c75ab9acb7b282765a3c7517caac25 This partially reverts commit "Convert float_to_int! into a function" --- library/compiler-builtins/src/float/conv.rs | 125 ++++++++++---------- 1 file changed, 62 insertions(+), 63 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 52fdf95599874..33644ce56aaf3 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -1,5 +1,5 @@ use float::Float; -use int::{Int, CastInto}; +use int::Int; macro_rules! int_to_float { ($i:expr, $ity:ty, $fty:ty) => ({ @@ -137,116 +137,115 @@ enum Sign { Negative } -fn float_to_int(f: F) -> I where - F::Int: CastInto, - F::Int: CastInto, -{ - let f = f; - let fixint_min = I::min_value(); - let fixint_max = I::max_value(); - let fixint_bits = I::BITS; - let fixint_unsigned = fixint_min == I::ZERO; - - let sign_bit = F::SIGN_MASK; - let significand_bits = F::SIGNIFICAND_BITS; - let exponent_bias = F::EXPONENT_BIAS; - //let exponent_max = F::exponent_max() as usize; - - // Break a into sign, exponent, significand - let a_rep = F::repr(f); - let a_abs = a_rep & !sign_bit; - - // this is used to work around -1 not being available for unsigned - let sign = if (a_rep & sign_bit) == F::Int::ZERO { Sign::Positive } else { Sign::Negative }; - let mut exponent: u32 = (a_abs >> significand_bits).cast(); - let significand = (a_abs & F::SIGNIFICAND_MASK) | F::IMPLICIT_BIT; - - // if < 1 or unsigned & negative - if exponent < exponent_bias || - fixint_unsigned && sign == Sign::Negative { - return I::ZERO; - } - exponent -= exponent_bias; - - // If the value is infinity, saturate. - // If the value is too large for the integer type, 0. - if exponent >= (if fixint_unsigned {fixint_bits} else {fixint_bits -1}) { - return if sign == Sign::Positive {fixint_max} else {fixint_min} - } - // If 0 <= exponent < significand_bits, right shift to get the result. - // Otherwise, shift left. - // (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned - let r: I = if exponent < significand_bits { - (significand >> (significand_bits - exponent)).cast() - } else { - (significand << (exponent - significand_bits)).cast() - }; - - if sign == Sign::Negative { - (!r).wrapping_add(I::ONE) - } else { - r - } +macro_rules! float_to_int { + ($f:expr, $fty:ty, $ity:ty) => ({ + let f = $f; + let fixint_min = <$ity>::min_value(); + let fixint_max = <$ity>::max_value(); + let fixint_bits = <$ity>::BITS as usize; + let fixint_unsigned = fixint_min == 0; + + let sign_bit = <$fty>::SIGN_MASK; + let significand_bits = <$fty>::SIGNIFICAND_BITS as usize; + let exponent_bias = <$fty>::EXPONENT_BIAS as usize; + //let exponent_max = <$fty>::exponent_max() as usize; + + // Break a into sign, exponent, significand + let a_rep = <$fty>::repr(f); + let a_abs = a_rep & !sign_bit; + + // this is used to work around -1 not being available for unsigned + let sign = if (a_rep & sign_bit) == 0 { Sign::Positive } else { Sign::Negative }; + let mut exponent = (a_abs >> significand_bits) as usize; + let significand = (a_abs & <$fty>::SIGNIFICAND_MASK) | <$fty>::IMPLICIT_BIT; + + // if < 1 or unsigned & negative + if exponent < exponent_bias || + fixint_unsigned && sign == Sign::Negative { + return 0 + } + exponent -= exponent_bias; + + // If the value is infinity, saturate. + // If the value is too large for the integer type, 0. + if exponent >= (if fixint_unsigned {fixint_bits} else {fixint_bits -1}) { + return if sign == Sign::Positive {fixint_max} else {fixint_min} + } + // If 0 <= exponent < significand_bits, right shift to get the result. + // Otherwise, shift left. + // (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned + let r = if exponent < significand_bits { + (significand >> (significand_bits - exponent)) as $ity + } else { + (significand as $ity) << (exponent - significand_bits) + }; + + if sign == Sign::Negative { + (!r).wrapping_add(1) + } else { + r + } + }) } intrinsics! { #[arm_aeabi_alias = __aeabi_f2iz] pub extern "C" fn __fixsfsi(f: f32) -> i32 { - float_to_int(f) + float_to_int!(f, f32, i32) } #[arm_aeabi_alias = __aeabi_f2lz] pub extern "C" fn __fixsfdi(f: f32) -> i64 { - float_to_int(f) + float_to_int!(f, f32, i64) } #[unadjusted_on_win64] pub extern "C" fn __fixsfti(f: f32) -> i128 { - float_to_int(f) + float_to_int!(f, f32, i128) } #[arm_aeabi_alias = __aeabi_d2iz] pub extern "C" fn __fixdfsi(f: f64) -> i32 { - float_to_int(f) + float_to_int!(f, f64, i32) } #[arm_aeabi_alias = __aeabi_d2lz] pub extern "C" fn __fixdfdi(f: f64) -> i64 { - float_to_int(f) + float_to_int!(f, f64, i64) } #[unadjusted_on_win64] pub extern "C" fn __fixdfti(f: f64) -> i128 { - float_to_int(f) + float_to_int!(f, f64, i128) } #[arm_aeabi_alias = __aeabi_f2uiz] pub extern "C" fn __fixunssfsi(f: f32) -> u32 { - float_to_int(f) + float_to_int!(f, f32, u32) } #[arm_aeabi_alias = __aeabi_f2ulz] pub extern "C" fn __fixunssfdi(f: f32) -> u64 { - float_to_int(f) + float_to_int!(f, f32, u64) } #[unadjusted_on_win64] pub extern "C" fn __fixunssfti(f: f32) -> u128 { - float_to_int(f) + float_to_int!(f, f32, u128) } #[arm_aeabi_alias = __aeabi_d2uiz] pub extern "C" fn __fixunsdfsi(f: f64) -> u32 { - float_to_int(f) + float_to_int!(f, f64, u32) } #[arm_aeabi_alias = __aeabi_d2ulz] pub extern "C" fn __fixunsdfdi(f: f64) -> u64 { - float_to_int(f) + float_to_int!(f, f64, u64) } #[unadjusted_on_win64] pub extern "C" fn __fixunsdfti(f: f64) -> u128 { - float_to_int(f) + float_to_int!(f, f64, u128) } } From d43287ac573e5191b5bde493e0a972c1eef01fff Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 3 Oct 2017 02:28:49 -0700 Subject: [PATCH 0393/4206] Update target specs --- library/compiler-builtins/thumbv6m-linux-eabi.json | 1 + library/compiler-builtins/thumbv7em-linux-eabi.json | 1 + library/compiler-builtins/thumbv7em-linux-eabihf.json | 1 + library/compiler-builtins/thumbv7m-linux-eabi.json | 1 + 4 files changed, 4 insertions(+) diff --git a/library/compiler-builtins/thumbv6m-linux-eabi.json b/library/compiler-builtins/thumbv6m-linux-eabi.json index dd0cb61bc09ff..ac736eae686b4 100644 --- a/library/compiler-builtins/thumbv6m-linux-eabi.json +++ b/library/compiler-builtins/thumbv6m-linux-eabi.json @@ -23,5 +23,6 @@ "relocation-model": "static", "target-endian": "little", "target-pointer-width": "32", + "target-c-int-width": "32", "vendor": "" } diff --git a/library/compiler-builtins/thumbv7em-linux-eabi.json b/library/compiler-builtins/thumbv7em-linux-eabi.json index eef29f5cc7a5c..b6d4a6bda7bac 100644 --- a/library/compiler-builtins/thumbv7em-linux-eabi.json +++ b/library/compiler-builtins/thumbv7em-linux-eabi.json @@ -22,5 +22,6 @@ "relocation-model": "static", "target-endian": "little", "target-pointer-width": "32", + "target-c-int-width": "32", "vendor": "" } diff --git a/library/compiler-builtins/thumbv7em-linux-eabihf.json b/library/compiler-builtins/thumbv7em-linux-eabihf.json index 5d72ec3b47892..81cfcd48d56ce 100644 --- a/library/compiler-builtins/thumbv7em-linux-eabihf.json +++ b/library/compiler-builtins/thumbv7em-linux-eabihf.json @@ -23,5 +23,6 @@ "relocation-model": "static", "target-endian": "little", "target-pointer-width": "32", + "target-c-int-width": "32", "vendor": "" } diff --git a/library/compiler-builtins/thumbv7m-linux-eabi.json b/library/compiler-builtins/thumbv7m-linux-eabi.json index 1e8a7f0086fb3..abe037c5bef88 100644 --- a/library/compiler-builtins/thumbv7m-linux-eabi.json +++ b/library/compiler-builtins/thumbv7m-linux-eabi.json @@ -22,5 +22,6 @@ "relocation-model": "static", "target-endian": "little", "target-pointer-width": "32", + "target-c-int-width": "32", "vendor": "" } From c95fefa9f65386687f182878bc2e0334ae802dc7 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 31 Oct 2016 16:03:46 +0000 Subject: [PATCH 0394/4206] Add atomic support for pre-ARMv6 on Linux --- library/compiler-builtins/build.rs | 5 + library/compiler-builtins/src/arm_linux.rs | 170 +++++++++++++++++++++ library/compiler-builtins/src/lib.rs | 3 + 3 files changed, 178 insertions(+) create mode 100644 library/compiler-builtins/src/arm_linux.rs diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 1895201e8fa64..71dec1999aa80 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -40,6 +40,11 @@ fn main() { if llvm_target[0] == "thumbv6m" { println!("cargo:rustc-cfg=thumbv6m") } + + // Only emit the ARM Linux atomic emulation on pre-ARMv6 architectures. + if llvm_target[0] == "armv5te" { + println!("cargo:rustc-cfg=armv5te") + } } #[cfg(feature = "gen-tests")] diff --git a/library/compiler-builtins/src/arm_linux.rs b/library/compiler-builtins/src/arm_linux.rs new file mode 100644 index 0000000000000..d94996d7399e7 --- /dev/null +++ b/library/compiler-builtins/src/arm_linux.rs @@ -0,0 +1,170 @@ +use core::intrinsics; +use core::mem; + +// Kernel-provided user-mode helper functions: +// https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt +unsafe fn __kuser_cmpxchg(oldval: u32, newval: u32, ptr: *mut u32) -> bool { + let out: u32; + // FIXME: we can't use BLX on ARMv4 + asm!("blx ${0}" + : "={r0}" (out) + : "r" (0xffff0fc0u32) + "{r0}" (oldval), + "{r1}" (newval), + "{r2}" (ptr) + : "r3", "r12", "lr", "cc", "memory"); + out == 0 +} +unsafe fn __kuser_memory_barrier() { + // FIXME: we can't use BLX on ARMv4 + asm!("blx ${0}" + : + : "r" (0xffff0fa0u32) + : "lr", "memory"); +} + +// Word-align a pointer +fn align_ptr(ptr: *mut T) -> *mut u32 { + // This gives us a mask of 0 when T == u32 since the pointer is already + // supposed to be aligned, which avoids any masking in that case. + let ptr_mask = 3 & (4 - mem::size_of::()); + (ptr as usize & !ptr_mask) as *mut u32 +} + +// Calculate the shift and mask of a value inside an aligned word +fn get_shift_mask(ptr: *mut T) -> (u32, u32) { + // Mask to get the low byte/halfword/word + let mask = match mem::size_of::() { + 1 => 0xff, + 2 => 0xffff, + 4 => 0xffffffff, + _ => unreachable!(), + }; + + // If we are on big-endian then we need to adjust the shift accordingly + let endian_adjust = if cfg!(target_endian = "little") { + 0 + } else { + 4 - mem::size_of::() as u32 + }; + + // Shift to get the desired element in the word + let ptr_mask = 3 & (4 - mem::size_of::()); + let shift = ((ptr as usize & ptr_mask) as u32 ^ endian_adjust) * 8; + + (shift, mask) +} + +// Extract a value from an aligned word +fn extract_aligned(aligned: u32, shift: u32, mask: u32) -> u32 { + (aligned >> shift) & mask +} + +// Insert a value into an aligned word +fn insert_aligned(aligned: u32, val: u32, shift: u32, mask: u32) -> u32 { + (aligned & !(mask << shift)) | ((val & mask) << shift) +} + +// Generic atomic read-modify-write operation +unsafe fn atomic_rmw u32>(ptr: *mut T, f: F) -> u32 { + let aligned_ptr = align_ptr(ptr); + let (shift, mask) = get_shift_mask(ptr); + + loop { + let curval_aligned = intrinsics::atomic_load_unordered(aligned_ptr); + let curval = extract_aligned(curval_aligned, shift, mask); + let newval = f(curval); + let newval_aligned = insert_aligned(curval_aligned, newval, shift, mask); + if __kuser_cmpxchg(curval_aligned, newval_aligned, aligned_ptr) { + return curval; + } + } +} + +// Generic atomic compare-exchange operation +unsafe fn atomic_cmpxchg(oldval: u32, newval: u32, ptr: *mut T) -> u32 { + let aligned_ptr = align_ptr(ptr); + let (shift, mask) = get_shift_mask(ptr); + + loop { + let curval_aligned = intrinsics::atomic_load_unordered(aligned_ptr); + let curval = extract_aligned(curval_aligned, shift, mask); + if curval != oldval { + return curval; + } + let newval_aligned = insert_aligned(curval_aligned, newval, shift, mask); + if __kuser_cmpxchg(curval_aligned, newval_aligned, aligned_ptr) { + return oldval; + } + } +} + +macro_rules! atomic_rmw { + ($name:ident, $ty:ty, $op:expr) => { + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + pub unsafe extern "C" fn $name(ptr: *mut $ty, val: $ty) -> $ty { + atomic_rmw(ptr, |x| $op(x as $ty, val) as u32) as $ty + } + } +} +macro_rules! atomic_cmpxchg { + ($name:ident, $ty:ty) => { + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + pub unsafe extern "C" fn $name(oldval: $ty, newval: $ty, ptr: *mut $ty) -> $ty { + atomic_cmpxchg(oldval as u32, newval as u32, ptr) as $ty + } + } +} + +atomic_rmw!(__sync_fetch_and_add_1, u8, |a: u8, b: u8| a.wrapping_add(b)); +atomic_rmw!(__sync_fetch_and_add_2, u16, |a: u16, b: u16| a.wrapping_add(b)); +atomic_rmw!(__sync_fetch_and_add_4, u32, |a: u32, b: u32| a.wrapping_add(b)); + +atomic_rmw!(__sync_fetch_and_sub_1, u8, |a: u8, b: u8| a.wrapping_sub(b)); +atomic_rmw!(__sync_fetch_and_sub_2, u16, |a: u16, b: u16| a.wrapping_sub(b)); +atomic_rmw!(__sync_fetch_and_sub_4, u32, |a: u32, b: u32| a.wrapping_sub(b)); + +atomic_rmw!(__sync_fetch_and_and_1, u8, |a: u8, b: u8| a & b); +atomic_rmw!(__sync_fetch_and_and_2, u16, |a: u16, b: u16| a & b); +atomic_rmw!(__sync_fetch_and_and_4, u32, |a: u32, b: u32| a & b); + +atomic_rmw!(__sync_fetch_and_or_1, u8, |a: u8, b: u8| a | b); +atomic_rmw!(__sync_fetch_and_or_2, u16, |a: u16, b: u16| a | b); +atomic_rmw!(__sync_fetch_and_or_4, u32, |a: u32, b: u32| a | b); + +atomic_rmw!(__sync_fetch_and_xor_1, u8, |a: u8, b: u8| a ^ b); +atomic_rmw!(__sync_fetch_and_xor_2, u16, |a: u16, b: u16| a ^ b); +atomic_rmw!(__sync_fetch_and_xor_4, u32, |a: u32, b: u32| a ^ b); + +atomic_rmw!(__sync_fetch_and_nand_1, u8, |a: u8, b: u8| !a & b); +atomic_rmw!(__sync_fetch_and_nand_2, u16, |a: u16, b: u16| !a & b); +atomic_rmw!(__sync_fetch_and_nand_4, u32, |a: u32, b: u32| !a & b); + +atomic_rmw!(__sync_fetch_and_max_1, i8, |a: i8, b: i8| if a > b { a } else { b }); +atomic_rmw!(__sync_fetch_and_max_2, i16, |a: i16, b: i16| if a > b { a } else { b }); +atomic_rmw!(__sync_fetch_and_max_4, i32, |a: i32, b: i32| if a > b { a } else { b }); + +atomic_rmw!(__sync_fetch_and_umax_1, u8, |a: u8, b: u8| if a > b { a } else { b }); +atomic_rmw!(__sync_fetch_and_umax_2, u16, |a: u16, b: u16| if a > b { a } else { b }); +atomic_rmw!(__sync_fetch_and_umax_4, u32, |a: u32, b: u32| if a > b { a } else { b }); + +atomic_rmw!(__sync_fetch_and_min_1, i8, |a: i8, b: i8| if a < b { a } else { b }); +atomic_rmw!(__sync_fetch_and_min_2, i16, |a: i16, b: i16| if a < b { a } else { b }); +atomic_rmw!(__sync_fetch_and_min_4, i32, |a: i32, b: i32| if a < b { a } else { b }); + +atomic_rmw!(__sync_fetch_and_umin_1, u8, |a: u8, b: u8| if a < b { a } else { b }); +atomic_rmw!(__sync_fetch_and_umin_2, u16, |a: u16, b: u16| if a < b { a } else { b }); +atomic_rmw!(__sync_fetch_and_umin_4, u32, |a: u32, b: u32| if a < b { a } else { b }); + +atomic_rmw!(__sync_lock_test_and_set_1, u8, |_: u8, b: u8| b); +atomic_rmw!(__sync_lock_test_and_set_2, u16, |_: u16, b: u16| b); +atomic_rmw!(__sync_lock_test_and_set_4, u32, |_: u32, b: u32| b); + +atomic_cmpxchg!(__sync_val_compare_and_swap_1, u8); +atomic_cmpxchg!(__sync_val_compare_and_swap_2, u16); +atomic_cmpxchg!(__sync_val_compare_and_swap_4, u32); + +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +pub unsafe extern "C" fn __sync_synchronize() { + __kuser_memory_barrier(); +} diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index d30a218e3dfea..8bf3230654a2f 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -51,6 +51,9 @@ pub mod mem; #[cfg(target_arch = "arm")] pub mod arm; +#[cfg(all(armv5te, target_os = "linux", target_arch = "arm"))] +pub mod arm_linux; + #[cfg(target_arch = "x86")] pub mod x86; From 0601024adf733d6dc2c072bda5984d74e051de13 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 7 Oct 2017 22:19:37 +0200 Subject: [PATCH 0395/4206] drop binfmt_misc dependency Instead use the Cargo runner feature. The binfmt_misc approach requires running a privileged container for setup. Not all docker setups support privileged containers so the test suite should be more accessible with this change as no privileged container is needed. --- library/compiler-builtins/.travis.yml | 3 --- .../ci/docker/aarch64-unknown-linux-gnu/Dockerfile | 1 + .../ci/docker/arm-unknown-linux-gnueabi/Dockerfile | 2 +- .../ci/docker/arm-unknown-linux-gnueabihf/Dockerfile | 1 + .../ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile | 1 + .../ci/docker/mips-unknown-linux-gnu/Dockerfile | 1 + .../ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile | 1 + .../ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile | 1 + .../ci/docker/mipsel-unknown-linux-gnu/Dockerfile | 1 + .../ci/docker/powerpc-unknown-linux-gnu/Dockerfile | 1 + .../ci/docker/powerpc64-unknown-linux-gnu/Dockerfile | 1 + .../ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile | 1 + .../compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile | 1 + .../ci/docker/thumbv7em-linux-eabi/Dockerfile | 1 + .../ci/docker/thumbv7em-linux-eabihf/Dockerfile | 1 + .../compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile | 1 + 16 files changed, 15 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 8a9d1faa1dca2..898a600eb4179 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -29,9 +29,6 @@ matrix: os: osx - env: TARGET=x86_64-unknown-linux-gnu -before_install: - - test "$TRAVIS_OS_NAME" = "osx" || docker run --rm --privileged multiarch/qemu-user-static:register - install: - case $TARGET in x86_64-apple-darwin | x86_64-unknown-linux-gnu) ;; 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 fe05867e37969..3f6a63fcb0d45 100644 --- a/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -5,5 +5,6 @@ RUN apt-get update && \ gcc-aarch64-linux-gnu libc6-dev-arm64-cross \ qemu-user-static ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ + CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER=qemu-aarch64-static \ QEMU_LD_PREFIX=/usr/aarch64-linux-gnu \ RUST_TEST_THREADS=1 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 8a09c20c43e3c..1c31b00b4eaac 100644 --- a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile @@ -4,6 +4,6 @@ RUN apt-get update && \ gcc libc6-dev ca-certificates \ gcc-arm-linux-gnueabi libc6-dev-armel-cross qemu-user-static ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER=arm-linux-gnueabi-gcc \ + CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_RUNNER=qemu-arm-static \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabi \ RUST_TEST_THREADS=1 - 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 57d830d1cd5e0..c305b1ba54698 100644 --- a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile @@ -4,5 +4,6 @@ RUN apt-get update && \ gcc libc6-dev ca-certificates \ gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ RUST_TEST_THREADS=1 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 a2f3cf177a268..76f367f142ae6 100644 --- a/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile @@ -4,5 +4,6 @@ RUN apt-get update && \ gcc libc6-dev ca-certificates \ gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ RUST_TEST_THREADS=1 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 9d69f1dfea329..71a9e8032f893 100644 --- a/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile @@ -7,5 +7,6 @@ RUN apt-get update && \ binfmt-support qemu-user-static qemu-system-mips ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER=mips-linux-gnu-gcc \ + CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_RUNNER=qemu-mips-static \ QEMU_LD_PREFIX=/usr/mips-linux-gnu \ RUST_TEST_THREADS=1 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 ef6eeaad59f2d..22239e46d8aa3 100644 --- a/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile @@ -9,6 +9,7 @@ RUN apt-get update && \ qemu-user-static \ qemu-system-mips ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER=mips64-linux-gnuabi64-gcc \ + CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64-static \ CC_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-gcc \ QEMU_LD_PREFIX=/usr/mips64-linux-gnuabi64 \ RUST_TEST_THREADS=1 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 13f770fcc53ed..77f1fd58c473a 100644 --- a/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile @@ -8,6 +8,7 @@ RUN apt-get update && \ libc6-dev-mips64el-cross \ qemu-user-static ENV CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_LINKER=mips64el-linux-gnuabi64-gcc \ + CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64el-static \ CC_mips64el_unknown_linux_gnuabi64=mips64el-linux-gnuabi64-gcc \ QEMU_LD_PREFIX=/usr/mips64el-linux-gnuabi64 \ RUST_TEST_THREADS=1 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 0afd5e7f503ab..98257e768061f 100644 --- a/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile @@ -7,5 +7,6 @@ RUN apt-get update && \ binfmt-support qemu-user-static ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER=mipsel-linux-gnu-gcc \ + CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_RUNNER=qemu-mipsel-static \ QEMU_LD_PREFIX=/usr/mipsel-linux-gnu \ RUST_TEST_THREADS=1 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 6e65a04db7cd9..b6bee385ec48f 100644 --- a/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile @@ -7,5 +7,6 @@ RUN apt-get update && \ qemu-system-ppc ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER=powerpc-linux-gnu-gcc \ + CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc-static \ QEMU_LD_PREFIX=/usr/powerpc-linux-gnu \ RUST_TEST_THREADS=1 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 eb86808f648a7..26dc1dc27261e 100644 --- a/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile @@ -7,6 +7,7 @@ RUN apt-get update && \ binfmt-support qemu-user-static qemu-system-ppc ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER=powerpc64-linux-gnu-gcc \ + CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64-static \ CC_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-gcc \ QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu \ RUST_TEST_THREADS=1 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 adb4106d3ef3a..3b280c0bdc657 100644 --- a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile @@ -7,6 +7,7 @@ RUN apt-get update && \ qemu-system-ppc ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER=powerpc64le-linux-gnu-gcc \ + CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64le-static \ QEMU_CPU=POWER8 \ QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile index d26035618e6ec..ecf90087e1e97 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile @@ -6,4 +6,5 @@ RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin ENV AR_thumbv6m_linux_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV6M_LINUX_EABI_LINKER=arm-none-eabi-gcc \ + CARGO_TARGET_THUMBV6M_LINUX_EABI_RUNNER=qemu-arm-static \ CC_thumbv6m_linux_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile index d630352a721f1..029a55d29a015 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile @@ -6,4 +6,5 @@ RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin ENV AR_thumbv7em_linux_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_LINUX_EABI_LINKER=arm-none-eabi-gcc \ + CARGO_TARGET_THUMBV7EM_LINUX_EABI_RUNNER=qemu-arm-static \ CC_thumbv7em_linux_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile index 6f30729fa9e42..5bf0c76e5be24 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile @@ -6,4 +6,5 @@ RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin ENV AR_thumbv7em_linux_eabihf=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7EM_LINUX_EABIHF_LINKER=arm-none-eabi-gcc \ + CARGO_TARGET_THUMBV7EM_LINUX_EABIHF_RUNNER=qemu-arm-static \ CC_thumbv7em_linux_eabihf=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile index a7dbad6472453..1ffac1f3345e1 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile @@ -6,4 +6,5 @@ RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin ENV AR_thumbv7m_linux_eabi=arm-none-eabi-ar \ CARGO_TARGET_THUMBV7M_LINUX_EABI_LINKER=arm-none-eabi-gcc \ + CARGO_TARGET_THUMBV7M_LINUX_EABI_RUNNER=qemu-arm-static \ CC_thumbv7m_linux_eabi=arm-none-eabi-gcc \ From 4fc3de624a1c83e0f0bc818f9fd9753834a73d03 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 24 Oct 2017 17:03:39 -0700 Subject: [PATCH 0396/4206] Prepare this crate for more wasm32 compatibility This commit prepares the build script for a wasm32 target that doesn't use Emcripten, notably forcing the `mem` feature to get activated and forcibly ignoring the `c` feature, even if activated, for the wasm32 target. --- library/compiler-builtins/build.rs | 16 +++++++++++++--- library/compiler-builtins/src/macros.rs | 6 +++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 71dec1999aa80..e94914b779f89 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -12,6 +12,12 @@ fn main() { return; } + // Forcibly enable memory intrinsics on wasm32 as we don't have a libc to + // provide them. + if target.contains("wasm32") { + println!("cargo:rustc-cfg=feature=\"mem\""); + } + // 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. @@ -25,9 +31,13 @@ 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")] - c::compile(&llvm_target); + if !cfg!(feature = "mangled-names") && cfg!(feature = "c") { + // no C compiler for wasm + if !target.contains("wasm32") { + #[cfg(feature = "c")] + c::compile(&llvm_target); + println!("cargo:rustc-cfg=use_c"); + } } // To compile intrinsics.rs for thumb targets, where there is no libc diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index f6d7db709340c..652c9111de681 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -31,7 +31,7 @@ /// A quick overview of attributes supported right now are: /// /// * `use_c_shim_if` - takes a #[cfg] directive and falls back to the -/// C-compiled version if `feature = "c"` is specified. +/// C-compiled version if `use_c` is specified. /// * `aapcs_on_arm` - forces the ABI of the function to be `"aapcs"` on ARM and /// the specified ABI everywhere else. /// * `unadjusted_on_win64` - like `aapcs_on_arm` this switches to the @@ -68,7 +68,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( - #[cfg(all(feature = "c", $($cfg_clause)*))] + #[cfg(all(use_c, $($cfg_clause)*))] pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { extern $abi { fn $name($($argname: $ty),*) -> $ret; @@ -78,7 +78,7 @@ macro_rules! intrinsics { } } - #[cfg(not(all(feature = "c", $($cfg_clause)*)))] + #[cfg(not(all(use_c, $($cfg_clause)*)))] intrinsics! { $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { From a46f33ce48ded88589926e48fee19eca34dcc6ee Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 Nov 2017 11:14:05 -0700 Subject: [PATCH 0397/4206] Work around OSX on Travis --- library/compiler-builtins/ci/run.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 9a32ee9ea64c8..95dcdfda95927 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -65,6 +65,7 @@ case "$TRAVIS_OS_NAME" in # NOTE OSx's nm doesn't accept the `--defined-only` or provide an equivalent. # Use GNU nm instead NM=gnm + brew update brew install binutils ;; *) From 5923e278c32a8d52a4d9b380c4025ead2a36089b Mon Sep 17 00:00:00 2001 From: Oliver Geller Date: Wed, 8 Nov 2017 17:36:34 -0500 Subject: [PATCH 0398/4206] Implement mulsf3 and muldf3 --- library/compiler-builtins/README.md | 4 +- library/compiler-builtins/build.rs | 230 +++++++++++++++++++++ library/compiler-builtins/src/float/mod.rs | 1 + library/compiler-builtins/src/float/mul.rs | 191 +++++++++++++++++ library/compiler-builtins/src/int/mod.rs | 45 ++++ library/compiler-builtins/tests/muldf3.rs | 7 + library/compiler-builtins/tests/mulsf3.rs | 7 + 7 files changed, 483 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/src/float/mul.rs create mode 100644 library/compiler-builtins/tests/muldf3.rs create mode 100644 library/compiler-builtins/tests/mulsf3.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 635699643411d..d1c57c74ef45d 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -170,11 +170,11 @@ features = ["c"] - [x] lshrdi3.c - [x] moddi3.c - [x] modsi3.c -- [ ] muldf3.c +- [x] muldf3.c - [x] muldi3.c - [x] mulodi4.c - [x] mulosi4.c -- [ ] mulsf3.c +- [x] mulsf3.c - [x] powidf2.c - [x] powisf2.c - [ ] subdf3.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index e94914b779f89..be0b13663568a 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -121,6 +121,10 @@ mod tests { Subdf3, Subsf3, + // float/mul.rs + Mulsf3, + Muldf3, + // int/mul.rs Muldi3, Mulodi4, @@ -3221,6 +3225,181 @@ fn subsf3() { } } + #[derive(Eq, Hash, PartialEq)] + pub struct Mulsf3 { + a: u32, // f32 + b: u32, // f32 + c: u32, // f32 + } + + impl TestCase for Mulsf3 { + fn name() -> &'static str { + "mulsf3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_large_f32(rng); + let b = gen_large_f32(rng); + let c = a * b; + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() || c.is_nan() { + return None; + } + + Some( + Mulsf3 { + a: to_u32(a), + b: to_u32(b), + c: to_u32(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::mul::__mulsf3; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +fn to_u32(x: f32) -> u32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32, u32), u32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn mulsf3() { + for &((a, b), c) in TEST_CASES { + let c_ = __mulsf3(mk_f32(a), mk_f32(b)); + assert_eq!(((a, b), c), ((a, b), to_u32(c_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Muldf3 { + a: u64, // f64 + b: u64, // f64 + c: u64, // f64 + } + + impl TestCase for Muldf3 { + fn name() -> &'static str { + "muldf3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_large_f64(rng); + let b = gen_large_f64(rng); + let c = a * b; + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() || c.is_nan() { + return None; + } + + Some( + Muldf3 { + a: to_u64(a), + b: to_u64(b), + c: to_u64(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::mul::__muldf3; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +fn to_u64(x: f64) -> u64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64, u64), u64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn muldf3() { + for &((a, b), c) in TEST_CASES { + let c_ = __muldf3(mk_f64(a), mk_f64(b)); + assert_eq!(((a, b), c), ((a, b), to_u64(c_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] pub struct Udivdi3 { a: u64, @@ -3899,6 +4078,57 @@ macro_rules! panic { gen_float!(gen_f32, f32, u32, 32, 23); gen_float!(gen_f64, f64, u64, 64, 52); + macro_rules! gen_large_float { + ($name:ident, + $fty:ident, + $uty:ident, + $bits:expr, + $significand_bits:expr) => { + pub fn $name(rng: &mut R) -> $fty + where + R: Rng, + { + const BITS: u8 = $bits; + const SIGNIFICAND_BITS: u8 = $significand_bits; + + const SIGNIFICAND_MASK: $uty = (1 << SIGNIFICAND_BITS) - 1; + const SIGN_MASK: $uty = (1 << (BITS - 1)); + const EXPONENT_MASK: $uty = !(SIGN_MASK | SIGNIFICAND_MASK); + + fn mk_f32(sign: bool, exponent: $uty, significand: $uty) -> $fty { + unsafe { + mem::transmute(((sign as $uty) << (BITS - 1)) | + ((exponent & EXPONENT_MASK) << + SIGNIFICAND_BITS) | + (significand & SIGNIFICAND_MASK)) + } + } + + if rng.gen_weighted_bool(10) { + // Special values + *rng.choose(&[-0.0, + 0.0, + ::std::$fty::NAN, + ::std::$fty::INFINITY, + -::std::$fty::INFINITY]) + .unwrap() + } else if rng.gen_weighted_bool(10) { + // NaN patterns + mk_f32(rng.gen(), rng.gen(), 0) + } else if rng.gen() { + // Denormalized + mk_f32(rng.gen(), 0, rng.gen()) + } else { + // Random anything + rng.gen::<$fty>() + } + } + } + } + + gen_large_float!(gen_large_f32, f32, u32, 32, 23); + gen_large_float!(gen_large_f64, f64, u64, 64, 52); + pub fn gen_u128(rng: &mut R) -> u128 where R: Rng, diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 23aef32e5ded0..55dde9a0245f7 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -7,6 +7,7 @@ pub mod conv; pub mod add; pub mod pow; pub mod sub; +pub mod mul; /// Trait for some basic operations on floats pub trait Float: diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs new file mode 100644 index 0000000000000..696adeaecb3a3 --- /dev/null +++ b/library/compiler-builtins/src/float/mul.rs @@ -0,0 +1,191 @@ +use int::{CastInto, Int, WideInt}; +use float::Float; + +fn mul(a: F, b: F) -> F +where + u32: CastInto, + F::Int: CastInto, + i32: CastInto, + F::Int: CastInto, + F::Int: WideInt, +{ + let one = F::Int::ONE; + let zero = F::Int::ZERO; + + let bits = F::BITS; + let significand_bits = F::SIGNIFICAND_BITS; + let max_exponent = F::EXPONENT_MAX; + + let exponent_bias = F::EXPONENT_BIAS; + + let implicit_bit = F::IMPLICIT_BIT; + let significand_mask = F::SIGNIFICAND_MASK; + let sign_bit = F::SIGN_MASK as F::Int; + let abs_mask = sign_bit - one; + let exponent_mask = F::EXPONENT_MASK; + let inf_rep = exponent_mask; + let quiet_bit = implicit_bit >> 1; + let qnan_rep = exponent_mask | quiet_bit; + let exponent_bits = F::EXPONENT_BITS; + + let a_rep = a.repr(); + let b_rep = b.repr(); + + let a_exponent = (a_rep >> significand_bits) & max_exponent.cast(); + let b_exponent = (b_rep >> significand_bits) & max_exponent.cast(); + let product_sign = (a_rep ^ b_rep) & sign_bit; + + let mut a_significand = a_rep & significand_mask; + let mut b_significand = b_rep & significand_mask; + let mut scale = 0; + + // Detect if a or b is zero, denormal, infinity, or NaN. + if a_exponent.wrapping_sub(one) >= (max_exponent - 1).cast() + || b_exponent.wrapping_sub(one) >= (max_exponent - 1).cast() + { + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; + + // NaN + anything = qNaN + if a_abs > inf_rep { + return F::from_repr(a_rep | quiet_bit); + } + // anything + NaN = qNaN + if b_abs > inf_rep { + return F::from_repr(b_rep | quiet_bit); + } + + if a_abs == inf_rep { + if b_abs != zero { + // infinity * non-zero = +/- infinity + return F::from_repr(a_abs | product_sign); + } else { + // infinity * zero = NaN + return F::from_repr(qnan_rep); + } + } + + if b_abs == inf_rep { + if a_abs != zero { + // infinity * non-zero = +/- infinity + return F::from_repr(b_abs | product_sign); + } else { + // infinity * zero = NaN + return F::from_repr(qnan_rep); + } + } + + // zero * anything = +/- zero + if a_abs == zero { + return F::from_repr(product_sign); + } + + // anything * zero = +/- zero + if b_abs == zero { + return F::from_repr(product_sign); + } + + // one or both of a or b is denormal, the other (if applicable) is a + // normal number. Renormalize one or both of a and b, and set scale to + // include the necessary exponent adjustment. + if a_abs < implicit_bit { + let (exponent, significand) = F::normalize(a_significand); + scale += exponent; + a_significand = significand; + } + + if b_abs < implicit_bit { + let (exponent, significand) = F::normalize(b_significand); + scale += exponent; + b_significand = significand; + } + } + + // Or in the implicit significand bit. (If we fell through from the + // denormal path it was already set by normalize( ), but setting it twice + // won't hurt anything.) + a_significand |= implicit_bit; + b_significand |= implicit_bit; + + // Get the significand of a*b. Before multiplying the significands, shift + // one of them left to left-align it in the field. Thus, the product will + // have (exponentBits + 2) integral digits, all but two of which must be + // zero. Normalizing this result is just a conditional left-shift by one + // and bumping the exponent accordingly. + let (mut product_high, mut product_low) = + ::wide_mul(a_significand, b_significand << exponent_bits); + + let a_exponent_i32: i32 = a_exponent.cast(); + let b_exponent_i32: i32 = b_exponent.cast(); + let mut product_exponent: i32 = a_exponent_i32 + .wrapping_add(b_exponent_i32) + .wrapping_add(scale) + .wrapping_sub(exponent_bias as i32); + + // Normalize the significand, adjust exponent if needed. + if (product_high & implicit_bit) != zero { + product_exponent = product_exponent.wrapping_add(1); + } else { + ::wide_shift_left(&mut product_high, &mut product_low, 1); + } + + // If we have overflowed the type, return +/- infinity. + if product_exponent >= max_exponent as i32 { + return F::from_repr(inf_rep | product_sign); + } + + if product_exponent <= 0 { + // Result is denormal before rounding + // + // If the result is so small that it just underflows to zero, return + // a zero of the appropriate sign. Mathematically there is no need to + // handle this case separately, but we make it a special case to + // simplify the shift logic. + let shift = one.wrapping_sub(product_exponent.cast()).cast(); + if shift >= bits as i32 { + return F::from_repr(product_sign); + } + + // Otherwise, shift the significand of the result so that the round + // bit is the high bit of productLo. + ::wide_shift_right_with_sticky( + &mut product_high, + &mut product_low, + shift, + ) + } else { + // Result is normal before rounding; insert the exponent. + product_high &= significand_mask; + product_high |= product_exponent.cast() << significand_bits; + } + + // Insert the sign of the result: + product_high |= product_sign; + + // Final rounding. The final result may overflow to infinity, or underflow + // to zero, but those are the correct results in those cases. We use the + // default IEEE-754 round-to-nearest, ties-to-even rounding mode. + if product_low > sign_bit { + product_high += one; + } + + if product_low == sign_bit { + product_high += product_high & one; + } + + return F::from_repr(product_high); +} + +intrinsics! { + #[aapcs_on_arm] + #[arm_aeabi_alias = __aeabi_fmul] + pub extern "C" fn __mulsf3(a: f32, b: f32) -> f32 { + mul(a, b) + } + + #[aapcs_on_arm] + #[arm_aeabi_alias = __aeabi_dmul] + pub extern "C" fn __muldf3(a: f64, b: f64) -> f64 { + mul(a, b) + } +} diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 24b27b1faea7f..37dac8cab2734 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -249,3 +249,48 @@ cast_into!(u64); cast_into!(i64); cast_into!(u128); cast_into!(i128); + +pub trait WideInt: Int { + type Output: Int; + + fn wide_mul(self, other: Self) -> (Self, Self); + fn wide_shift_left(&mut self, low: &mut Self, count: i32); + fn wide_shift_right_with_sticky(&mut self, low: &mut Self, count: i32); +} + +macro_rules! impl_wide_int { + ($ty:ty, $tywide:ty, $bits:expr) => { + impl WideInt for $ty { + type Output = $ty; + + fn wide_mul(self, other: Self) -> (Self, Self) { + let product = (self as $tywide).wrapping_mul(other as $tywide); + ((product >> ($bits as $ty)) as $ty, product as $ty) + } + + fn wide_shift_left(&mut self, low: &mut Self, count: i32) { + *self = (*self << count) | (*low >> ($bits - count)); + *low = *low << count; + } + + fn wide_shift_right_with_sticky(&mut self, low: &mut Self, count: i32) { + if count < $bits { + let sticky = *low << ($bits - count); + *low = *self << ($bits - count) | *low >> count | sticky; + *self = *self >> count; + } else if count < 2*$bits { + let sticky = *self << (2*$bits - count) | *low; + *low = *self >> (count - $bits ) | sticky; + *self = 0; + } else { + let sticky = *self | *low; + *self = sticky; + *self = 0; + } + } + } + } +} + +impl_wide_int!(u32, u64, 32); +impl_wide_int!(u64, u128, 64); diff --git a/library/compiler-builtins/tests/muldf3.rs b/library/compiler-builtins/tests/muldf3.rs new file mode 100644 index 0000000000000..82d06d8de3662 --- /dev/null +++ b/library/compiler-builtins/tests/muldf3.rs @@ -0,0 +1,7 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", test), + no_std)] + +include!(concat!(env!("OUT_DIR"), "/muldf3.rs")); diff --git a/library/compiler-builtins/tests/mulsf3.rs b/library/compiler-builtins/tests/mulsf3.rs new file mode 100644 index 0000000000000..fe278d84be21b --- /dev/null +++ b/library/compiler-builtins/tests/mulsf3.rs @@ -0,0 +1,7 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", test), + no_std)] + +include!(concat!(env!("OUT_DIR"), "/mulsf3.rs")); From 99ea83e095d78849827dab71d42c4c29e8c7e8c0 Mon Sep 17 00:00:00 2001 From: Oliver Geller Date: Sun, 12 Nov 2017 14:40:17 -0500 Subject: [PATCH 0399/4206] Implement divsf3 and divdf3 --- library/compiler-builtins/README.md | 4 +- library/compiler-builtins/build.rs | 185 +++++++++ library/compiler-builtins/src/float/div.rs | 457 +++++++++++++++++++++ library/compiler-builtins/src/float/mod.rs | 1 + library/compiler-builtins/tests/divdf3.rs | 7 + library/compiler-builtins/tests/divsf3.rs | 7 + 6 files changed, 659 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/src/float/div.rs create mode 100644 library/compiler-builtins/tests/divdf3.rs create mode 100644 library/compiler-builtins/tests/divsf3.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index d1c57c74ef45d..5606ef4c8463a 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -133,11 +133,11 @@ features = ["c"] - [ ] arm/unordsf2vfp.S - [x] ashldi3.c - [x] ashrdi3.c -- [ ] divdf3.c +- [x] divdf3.c - [x] divdi3.c - [x] divmoddi4.c - [x] divmodsi4.c -- [ ] divsf3.c +- [x] divsf3.c - [x] divsi3.c - [ ] extendhfsf2.c - [ ] extendsfdf2.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index be0b13663568a..2885d9d00c99f 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -125,6 +125,10 @@ mod tests { Mulsf3, Muldf3, + // float/div.rs + Divsf3, + Divdf3, + // int/mul.rs Muldi3, Mulodi4, @@ -3399,6 +3403,187 @@ fn muldf3() { } } + #[derive(Eq, Hash, PartialEq)] + pub struct Divsf3 { + a: u32, // f32 + b: u32, // f32 + c: u32, // f32 + } + + impl TestCase for Divsf3 { + fn name() -> &'static str { + "divsf3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_large_f32(rng); + let b = gen_large_f32(rng); + if b == 0.0 { + return None; + } + let c = a / b; + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() || c.is_nan()|| c.abs() <= unsafe { mem::transmute(16777215u32) } { + return None; + } + + Some( + Divsf3 { + a: to_u32(a), + b: to_u32(b), + c: to_u32(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::div::__divsf3; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +fn to_u32(x: f32) -> u32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32, u32), u32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divsf3() { + for &((a, b), c) in TEST_CASES { + let c_ = __divsf3(mk_f32(a), mk_f32(b)); + assert_eq!(((a, b), c), ((a, b), to_u32(c_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Divdf3 { + a: u64, // f64 + b: u64, // f64 + c: u64, // f64 + } + + impl TestCase for Divdf3 { + fn name() -> &'static str { + "divdf3" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_large_f64(rng); + let b = gen_large_f64(rng); + if b == 0.0 { + return None; + } + let c = a / b; + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() || c.is_nan() + || c.abs() <= unsafe { mem::transmute(4503599627370495u64) } { + return None; + } + + Some( + Divdf3 { + a: to_u64(a), + b: to_u64(b), + c: to_u64(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; +use compiler_builtins::float::div::__divdf3; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +fn to_u64(x: f64) -> u64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64, u64), u64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divdf3() { + for &((a, b), c) in TEST_CASES { + let c_ = __divdf3(mk_f64(a), mk_f64(b)); + assert_eq!(((a, b), c), ((a, b), to_u64(c_))); + } +} +" + } + } + #[derive(Eq, Hash, PartialEq)] pub struct Udivdi3 { diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs new file mode 100644 index 0000000000000..e0e287a9ea315 --- /dev/null +++ b/library/compiler-builtins/src/float/div.rs @@ -0,0 +1,457 @@ +use int::{CastInto, Int, WideInt}; +use float::Float; + + + +fn div32(a: F, b: F) -> F +where + u32: CastInto, + F::Int: CastInto, + i32: CastInto, + F::Int: CastInto, + F::Int: WideInt, +{ + let one = F::Int::ONE; + let zero = F::Int::ZERO; + + // let bits = F::BITS; + let significand_bits = F::SIGNIFICAND_BITS; + let max_exponent = F::EXPONENT_MAX; + + let exponent_bias = F::EXPONENT_BIAS; + + let implicit_bit = F::IMPLICIT_BIT; + let significand_mask = F::SIGNIFICAND_MASK; + let sign_bit = F::SIGN_MASK as F::Int; + let abs_mask = sign_bit - one; + let exponent_mask = F::EXPONENT_MASK; + let inf_rep = exponent_mask; + let quiet_bit = implicit_bit >> 1; + let qnan_rep = exponent_mask | quiet_bit; + + #[inline(always)] + fn negate_u32(a: u32) -> u32 { + (::wrapping_neg(a as i32)) as u32 + } + + let a_rep = a.repr(); + let b_rep = b.repr(); + + let a_exponent = (a_rep >> significand_bits) & max_exponent.cast(); + let b_exponent = (b_rep >> significand_bits) & max_exponent.cast(); + let quotient_sign = (a_rep ^ b_rep) & sign_bit; + + let mut a_significand = a_rep & significand_mask; + let mut b_significand = b_rep & significand_mask; + let mut scale = 0; + + // Detect if a or b is zero, denormal, infinity, or NaN. + if a_exponent.wrapping_sub(one) >= (max_exponent - 1).cast() + || b_exponent.wrapping_sub(one) >= (max_exponent - 1).cast() + { + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; + + // NaN / anything = qNaN + if a_abs > inf_rep { + return F::from_repr(a_rep | quiet_bit); + } + // anything / NaN = qNaN + if b_abs > inf_rep { + return F::from_repr(b_rep | quiet_bit); + } + + if a_abs == inf_rep { + if b_abs == inf_rep { + // infinity / infinity = NaN + return F::from_repr(qnan_rep); + } else { + // infinity / anything else = +/- infinity + return F::from_repr(a_abs | quotient_sign); + } + } + + // anything else / infinity = +/- 0 + if b_abs == inf_rep { + return F::from_repr(quotient_sign); + } + + if a_abs == zero { + if b_abs == zero { + // zero / zero = NaN + return F::from_repr(qnan_rep); + } else { + // zero / anything else = +/- zero + return F::from_repr(quotient_sign); + } + } + + // anything else / zero = +/- infinity + if b_abs == zero { + return F::from_repr(inf_rep | quotient_sign); + } + + // one or both of a or b is denormal, the other (if applicable) is a + // normal number. Renormalize one or both of a and b, and set scale to + // include the necessary exponent adjustment. + if a_abs < implicit_bit { + let (exponent, significand) = F::normalize(a_significand); + scale += exponent; + a_significand = significand; + } + + if b_abs < implicit_bit { + let (exponent, significand) = F::normalize(b_significand); + scale -= exponent; + b_significand = significand; + } + } + + // Or in the implicit significand bit. (If we fell through from the + // denormal path it was already set by normalize( ), but setting it twice + // won't hurt anything.) + a_significand |= implicit_bit; + b_significand |= implicit_bit; + let mut quotient_exponent: i32 = CastInto::::cast(a_exponent) + .wrapping_sub(CastInto::::cast(b_exponent)) + .wrapping_add(scale); + + // Align the significand of b as a Q31 fixed-point number in the range + // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax + // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This + // is accurate to about 3.5 binary digits. + let q31b = CastInto::::cast(b_significand << 8.cast()); + let mut reciprocal = (0x7504f333u32).wrapping_sub(q31b); + + // Now refine the reciprocal estimate using a Newton-Raphson iteration: + // + // x1 = x0 * (2 - x0 * b) + // + // This doubles the number of correct binary digits in the approximation + // with each iteration, so after three iterations, we have about 28 binary + // digits of accuracy. + let mut correction: u32; + correction = negate_u32(((reciprocal as u64).wrapping_mul(q31b as u64) >> 32) as u32); + reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) as u64 >> 31) as u32; + correction = negate_u32(((reciprocal as u64).wrapping_mul(q31b as u64) >> 32) as u32); + reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) as u64 >> 31) as u32; + correction = negate_u32(((reciprocal as u64).wrapping_mul(q31b as u64) >> 32) as u32); + reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) as u64 >> 31) as u32; + + // Exhaustive testing shows that the error in reciprocal after three steps + // is in the interval [-0x1.f58108p-31, 0x1.d0e48cp-29], in line with our + // expectations. We bump the reciprocal by a tiny value to force the error + // to be strictly positive (in the range [0x1.4fdfp-37,0x1.287246p-29], to + // be specific). This also causes 1/1 to give a sensible approximation + // instead of zero (due to overflow). + reciprocal = reciprocal.wrapping_sub(2); + + // The numerical reciprocal is accurate to within 2^-28, lies in the + // interval [0x1.000000eep-1, 0x1.fffffffcp-1], and is strictly smaller + // than the true reciprocal of b. Multiplying a by this reciprocal thus + // gives a numerical q = a/b in Q24 with the following properties: + // + // 1. q < a/b + // 2. q is in the interval [0x1.000000eep-1, 0x1.fffffffcp0) + // 3. the error in q is at most 2^-24 + 2^-27 -- the 2^24 term comes + // from the fact that we truncate the product, and the 2^27 term + // is the error in the reciprocal of b scaled by the maximum + // possible value of a. As a consequence of this error bound, + // either q or nextafter(q) is the correctly rounded + let (mut quotient, _) = ::wide_mul(a_significand << 1, reciprocal.cast()); + + // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0). + // In either case, we are going to compute a residual of the form + // + // r = a - q*b + // + // We know from the construction of q that r satisfies: + // + // 0 <= r < ulp(q)*b + // + // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we + // already have the correct result. The exact halfway case cannot occur. + // We also take this time to right shift quotient if it falls in the [1,2) + // range and adjust the exponent accordingly. + let residual = if quotient < (implicit_bit << 1) { + quotient_exponent = quotient_exponent.wrapping_sub(1); + (a_significand << (significand_bits + 1)).wrapping_sub(quotient.wrapping_mul(b_significand)) + } else { + quotient >>= 1; + (a_significand << significand_bits).wrapping_sub(quotient.wrapping_mul(b_significand)) + }; + + let written_exponent = quotient_exponent.wrapping_add(exponent_bias as i32); + + if written_exponent >= max_exponent as i32 { + // If we have overflowed the exponent, return infinity. + return F::from_repr(inf_rep | quotient_sign); + } else if written_exponent < 1 { + // Flush denormals to zero. In the future, it would be nice to add + // code to round them correctly. + return F::from_repr(quotient_sign); + } else { + let round = ((residual << 1) > b_significand) as u32; + // Clear the implicit bits + let mut abs_result = quotient & significand_mask; + // Insert the exponent + abs_result |= written_exponent.cast() << significand_bits; + // Round + abs_result = abs_result.wrapping_add(round.cast()); + // Insert the sign and return + return F::from_repr(abs_result | quotient_sign); + } +} + +fn div64(a: F, b: F) -> F +where + u32: CastInto, + F::Int: CastInto, + i32: CastInto, + F::Int: CastInto, + u64: CastInto, + F::Int: CastInto, + i64: CastInto, + F::Int: CastInto, + F::Int: WideInt, +{ + let one = F::Int::ONE; + let zero = F::Int::ZERO; + + // let bits = F::BITS; + let significand_bits = F::SIGNIFICAND_BITS; + let max_exponent = F::EXPONENT_MAX; + + let exponent_bias = F::EXPONENT_BIAS; + + let implicit_bit = F::IMPLICIT_BIT; + let significand_mask = F::SIGNIFICAND_MASK; + let sign_bit = F::SIGN_MASK as F::Int; + let abs_mask = sign_bit - one; + let exponent_mask = F::EXPONENT_MASK; + let inf_rep = exponent_mask; + let quiet_bit = implicit_bit >> 1; + let qnan_rep = exponent_mask | quiet_bit; + // let exponent_bits = F::EXPONENT_BITS; + + #[inline(always)] + fn negate_u32(a: u32) -> u32 { + (::wrapping_neg(a as i32)) as u32 + } + + #[inline(always)] + fn negate_u64(a: u64) -> u64 { + (::wrapping_neg(a as i64)) as u64 + } + + let a_rep = a.repr(); + let b_rep = b.repr(); + + let a_exponent = (a_rep >> significand_bits) & max_exponent.cast(); + let b_exponent = (b_rep >> significand_bits) & max_exponent.cast(); + let quotient_sign = (a_rep ^ b_rep) & sign_bit; + + let mut a_significand = a_rep & significand_mask; + let mut b_significand = b_rep & significand_mask; + let mut scale = 0; + + // Detect if a or b is zero, denormal, infinity, or NaN. + if a_exponent.wrapping_sub(one) >= (max_exponent - 1).cast() + || b_exponent.wrapping_sub(one) >= (max_exponent - 1).cast() + { + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; + + // NaN / anything = qNaN + if a_abs > inf_rep { + return F::from_repr(a_rep | quiet_bit); + } + // anything / NaN = qNaN + if b_abs > inf_rep { + return F::from_repr(b_rep | quiet_bit); + } + + if a_abs == inf_rep { + if b_abs == inf_rep { + // infinity / infinity = NaN + return F::from_repr(qnan_rep); + } else { + // infinity / anything else = +/- infinity + return F::from_repr(a_abs | quotient_sign); + } + } + + // anything else / infinity = +/- 0 + if b_abs == inf_rep { + return F::from_repr(quotient_sign); + } + + if a_abs == zero { + if b_abs == zero { + // zero / zero = NaN + return F::from_repr(qnan_rep); + } else { + // zero / anything else = +/- zero + return F::from_repr(quotient_sign); + } + } + + // anything else / zero = +/- infinity + if b_abs == zero { + return F::from_repr(inf_rep | quotient_sign); + } + + // one or both of a or b is denormal, the other (if applicable) is a + // normal number. Renormalize one or both of a and b, and set scale to + // include the necessary exponent adjustment. + if a_abs < implicit_bit { + let (exponent, significand) = F::normalize(a_significand); + scale += exponent; + a_significand = significand; + } + + if b_abs < implicit_bit { + let (exponent, significand) = F::normalize(b_significand); + scale -= exponent; + b_significand = significand; + } + } + + // Or in the implicit significand bit. (If we fell through from the + // denormal path it was already set by normalize( ), but setting it twice + // won't hurt anything.) + a_significand |= implicit_bit; + b_significand |= implicit_bit; + let mut quotient_exponent: i32 = CastInto::::cast(a_exponent) + .wrapping_sub(CastInto::::cast(b_exponent)) + .wrapping_add(scale); + + // Align the significand of b as a Q31 fixed-point number in the range + // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax + // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This + // is accurate to about 3.5 binary digits. + let q31b = CastInto::::cast(b_significand >> 21.cast()); + let mut recip32 = (0x7504f333u32).wrapping_sub(q31b); + + // Now refine the reciprocal estimate using a Newton-Raphson iteration: + // + // x1 = x0 * (2 - x0 * b) + // + // This doubles the number of correct binary digits in the approximation + // with each iteration, so after three iterations, we have about 28 binary + // digits of accuracy. + let mut correction32: u32; + correction32 = negate_u32(((recip32 as u64).wrapping_mul(q31b as u64) >> 32) as u32); + recip32 = ((recip32 as u64).wrapping_mul(correction32 as u64) >> 31) as u32; + correction32 = negate_u32(((recip32 as u64).wrapping_mul(q31b as u64) >> 32) as u32); + recip32 = ((recip32 as u64).wrapping_mul(correction32 as u64) >> 31) as u32; + correction32 = negate_u32(((recip32 as u64).wrapping_mul(q31b as u64) >> 32) as u32); + recip32 = ((recip32 as u64).wrapping_mul(correction32 as u64) >> 31) as u32; + + // recip32 might have overflowed to exactly zero in the preceeding + // computation if the high word of b is exactly 1.0. This would sabotage + // the full-width final stage of the computation that follows, so we adjust + // recip32 downward by one bit. + recip32 = recip32.wrapping_sub(1); + + // We need to perform one more iteration to get us to 56 binary digits; + // The last iteration needs to happen with extra precision. + let q63blo = CastInto::::cast(b_significand << 11.cast()); + let correction: u64; + let mut reciprocal: u64; + correction = negate_u64( + (recip32 as u64) + .wrapping_mul(q31b as u64) + .wrapping_add((recip32 as u64).wrapping_mul(q63blo as u64) >> 32), + ); + let c_hi = (correction >> 32) as u32; + let c_lo = correction as u32; + reciprocal = (recip32 as u64) + .wrapping_mul(c_hi as u64) + .wrapping_add((recip32 as u64).wrapping_mul(c_lo as u64) >> 32); + + // We already adjusted the 32-bit estimate, now we need to adjust the final + // 64-bit reciprocal estimate downward to ensure that it is strictly smaller + // than the infinitely precise exact reciprocal. Because the computation + // of the Newton-Raphson step is truncating at every step, this adjustment + // is small; most of the work is already done. + reciprocal = reciprocal.wrapping_sub(2); + + // The numerical reciprocal is accurate to within 2^-56, lies in the + // interval [0.5, 1.0), and is strictly smaller than the true reciprocal + // of b. Multiplying a by this reciprocal thus gives a numerical q = a/b + // in Q53 with the following properties: + // + // 1. q < a/b + // 2. q is in the interval [0.5, 2.0) + // 3. the error in q is bounded away from 2^-53 (actually, we have a + // couple of bits to spare, but this is all we need). + + // We need a 64 x 64 multiply high to compute q, which isn't a basic + // operation in C, so we need to be a little bit fussy. + // let mut quotient: F::Int = ((((reciprocal as u64) + // .wrapping_mul(CastInto::::cast(a_significand << 1) as u64)) + // >> 32) as u32) + // .cast(); + + // We need a 64 x 64 multiply high to compute q, which isn't a basic + // operation in C, so we need to be a little bit fussy. + let (mut quotient, _) = ::wide_mul(a_significand << 2, reciprocal.cast()); + + + // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0). + // In either case, we are going to compute a residual of the form + // + // r = a - q*b + // + // We know from the construction of q that r satisfies: + // + // 0 <= r < ulp(q)*b + // + // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we + // already have the correct result. The exact halfway case cannot occur. + // We also take this time to right shift quotient if it falls in the [1,2) + // range and adjust the exponent accordingly. + let residual = if quotient < (implicit_bit << 1) { + quotient_exponent = quotient_exponent.wrapping_sub(1); + (a_significand << (significand_bits + 1)).wrapping_sub(quotient.wrapping_mul(b_significand)) + } else { + quotient >>= 1; + (a_significand << significand_bits).wrapping_sub(quotient.wrapping_mul(b_significand)) + }; + + let written_exponent = quotient_exponent.wrapping_add(exponent_bias as i32); + + if written_exponent >= max_exponent as i32 { + // If we have overflowed the exponent, return infinity. + return F::from_repr(inf_rep | quotient_sign); + } else if written_exponent < 1 { + // Flush denormals to zero. In the future, it would be nice to add + // code to round them correctly. + return F::from_repr(quotient_sign); + } else { + let round = ((residual << 1) > b_significand) as u32; + // Clear the implicit bits + let mut abs_result = quotient & significand_mask; + // Insert the exponent + abs_result |= written_exponent.cast() << significand_bits; + // Round + abs_result = abs_result.wrapping_add(round.cast()); + // Insert the sign and return + return F::from_repr(abs_result | quotient_sign); + } +} + + +intrinsics! { + #[arm_aeabi_alias = __aeabi_fdiv] + pub extern "C" fn __divsf3(a: f32, b: f32) -> f32 { + div32(a, b) + } + + #[arm_aeabi_alias = __aeabi_ddiv] + pub extern "C" fn __divdf3(a: f64, b: f64) -> f64 { + div64(a, b) + } + +} diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 55dde9a0245f7..6daf7b8f75f5f 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -8,6 +8,7 @@ pub mod add; pub mod pow; pub mod sub; pub mod mul; +pub mod div; /// Trait for some basic operations on floats pub trait Float: diff --git a/library/compiler-builtins/tests/divdf3.rs b/library/compiler-builtins/tests/divdf3.rs new file mode 100644 index 0000000000000..98d32d1b084cb --- /dev/null +++ b/library/compiler-builtins/tests/divdf3.rs @@ -0,0 +1,7 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", test), + no_std)] + +include!(concat!(env!("OUT_DIR"), "/divdf3.rs")); diff --git a/library/compiler-builtins/tests/divsf3.rs b/library/compiler-builtins/tests/divsf3.rs new file mode 100644 index 0000000000000..5cf3e86ca018c --- /dev/null +++ b/library/compiler-builtins/tests/divsf3.rs @@ -0,0 +1,7 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", test), + no_std)] + +include!(concat!(env!("OUT_DIR"), "/divsf3.rs")); From 3bd28c8b6d2ff270ad1e0d9861f4fa8502fd2ba0 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 15 Nov 2017 12:49:10 -0800 Subject: [PATCH 0400/4206] Add "volatile" and "memory" clobber to asm! that doesn't fall through. Use the "volatile" option and the "memory" clobber on inline asm that does things like return directly, to reduce the chances of compilers rearranging the code. --- library/compiler-builtins/src/arm.rs | 8 ++++---- library/compiler-builtins/src/probestack.rs | 4 ++-- library/compiler-builtins/src/x86.rs | 7 ++++--- library/compiler-builtins/src/x86_64.rs | 12 ++++++++---- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index fa86e969146eb..25fdd52429eef 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -11,7 +11,7 @@ pub unsafe fn __aeabi_uidivmod() { bl __udivmodsi4 ldr r1, [sp] add sp, sp, #4 - pop {pc}"); + pop {pc}" ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -26,7 +26,7 @@ pub unsafe fn __aeabi_uldivmod() { ldr r2, [sp, #8] ldr r3, [sp, #12] add sp, sp, #16 - pop {r4, pc}"); + pop {r4, pc}" ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -38,7 +38,7 @@ pub unsafe fn __aeabi_idivmod() { pop {r1, r2} muls r2, r2, r0 subs r1, r1, r2 - pop {r4, pc}"); + pop {r4, pc}" ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -53,7 +53,7 @@ pub unsafe fn __aeabi_ldivmod() { ldr r2, [sp, #8] ldr r3, [sp, #12] add sp, sp, #16 - pop {r4, pc}"); + pop {r4, pc}" ::: "memory" : "volatile"); intrinsics::unreachable(); } diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 13ea5a5f03b38..34f466e1e3a6c 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -82,7 +82,7 @@ pub unsafe extern fn __rust_probestack() { add %rax,%rsp ret - "); + " ::: "memory" : "volatile"); ::core::intrinsics::unreachable(); } @@ -111,6 +111,6 @@ pub unsafe extern fn __rust_probestack() { add %eax,%esp pop %ecx ret - "); + " ::: "memory" : "volatile"); ::core::intrinsics::unreachable(); } diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs index 3e540e21eff51..035c0a31c4167 100644 --- a/library/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/src/x86.rs @@ -29,7 +29,7 @@ pub unsafe fn ___chkstk_ms() { test %ecx,(%ecx) pop %eax pop %ecx - ret"); + ret" ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -38,7 +38,8 @@ pub unsafe fn ___chkstk_ms() { #[naked] #[no_mangle] pub unsafe fn __alloca() { - asm!("jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable"); + asm!("jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable" + ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -66,6 +67,6 @@ pub unsafe fn ___chkstk() { mov -4(%eax),%ecx // restore ecx push (%eax) // push return address onto the stack sub %esp,%eax // restore the original value in eax - ret"); + ret" ::: "memory" : "volatile"); intrinsics::unreachable(); } diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 09b008152659e..2360ab8a6fa6e 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -29,7 +29,7 @@ pub unsafe fn ___chkstk_ms() { test %rcx,(%rcx) pop %rax pop %rcx - ret"); + ret" ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -38,7 +38,8 @@ pub unsafe fn ___chkstk_ms() { #[no_mangle] pub unsafe fn __alloca() { asm!("mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx - jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable"); + jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable" + ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -46,7 +47,8 @@ pub unsafe fn __alloca() { #[naked] #[no_mangle] pub unsafe fn ___chkstk() { - asm!(" + asm!( + " push %rcx cmp $$0x1000,%rax lea 16(%rsp),%rcx // rsp before calling this routine -> rcx @@ -66,6 +68,8 @@ pub unsafe fn ___chkstk() { mov -8(%rax),%rcx // restore rcx push (%rax) // push return address onto the stack sub %rsp,%rax // restore the original value in rax - ret"); + ret" + ::: "memory" : "volatile" + ); intrinsics::unreachable(); } From 7115a910c8905095bee677ee0ba29793482b132e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 19 Nov 2017 09:07:11 -0800 Subject: [PATCH 0401/4206] Remove divsf3.c from compiler-rt We implement this now! --- library/compiler-builtins/build.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 2885d9d00c99f..e2a63a6cf97b4 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4497,9 +4497,7 @@ mod c { "ctzdi2.c", "ctzsi2.c", "divdc3.c", - "divdf3.c", "divsc3.c", - "divsf3.c", "divxc3.c", "extendsfdf2.c", "extendhfsf2.c", From ff97668431754e6ca892356da88e838bc5e52bd5 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 25 Nov 2017 04:21:05 -0800 Subject: [PATCH 0402/4206] Implement all the 128-bit operator lang items from rust PR 46093 --- library/compiler-builtins/src/int/add.rs | 111 +++++++++++++++++++++ library/compiler-builtins/src/int/mod.rs | 7 ++ library/compiler-builtins/src/int/mul.rs | 37 +++++++ library/compiler-builtins/src/int/sdiv.rs | 11 ++ library/compiler-builtins/src/int/shift.rs | 42 ++++++++ library/compiler-builtins/src/int/sub.rs | 109 ++++++++++++++++++++ library/compiler-builtins/src/int/udiv.rs | 11 ++ library/compiler-builtins/src/lib.rs | 1 + 8 files changed, 329 insertions(+) create mode 100644 library/compiler-builtins/src/int/add.rs create mode 100644 library/compiler-builtins/src/int/sub.rs diff --git a/library/compiler-builtins/src/int/add.rs b/library/compiler-builtins/src/int/add.rs new file mode 100644 index 0000000000000..639d14ac309c7 --- /dev/null +++ b/library/compiler-builtins/src/int/add.rs @@ -0,0 +1,111 @@ +use int::LargeInt; +use int::Int; + +trait Add: LargeInt { + fn add(self, other: Self) -> Self { + let (low, carry) = self.low().overflowing_add(other.low()); + let high = self.high().wrapping_add(other.high()); + let carry = if carry { Self::HighHalf::ONE } else { Self::HighHalf::ZERO }; + Self::from_parts(low, high.wrapping_add(carry)) + } +} + +impl Add for u128 {} + +trait Addo: Int { + fn addo(self, other: Self, overflow: &mut i32) -> Self { + *overflow = 0; + let result = self.wrapping_add(other); + if other >= Self::ZERO { + if result < self { + *overflow = 1; + } + } else { + if result >= self { + *overflow = 1; + } + } + result + } +} + +impl Addo for i128 {} +impl Addo for u128 {} + +#[cfg_attr(not(stage0), lang = "i128_add")] +#[allow(dead_code)] +fn rust_i128_add(a: i128, b: i128) -> i128 { + rust_u128_add(a as _, b as _) as _ +} +#[cfg_attr(not(stage0), lang = "i128_addo")] +#[allow(dead_code)] +fn rust_i128_addo(a: i128, b: i128) -> (i128, bool) { + let mut oflow = 0; + let r = a.addo(b, &mut oflow); + (r, oflow != 0) +} +#[cfg_attr(not(stage0), lang = "u128_add")] +#[allow(dead_code)] +fn rust_u128_add(a: u128, b: u128) -> u128 { + a.add(b) +} +#[cfg_attr(not(stage0), lang = "u128_addo")] +#[allow(dead_code)] +fn rust_u128_addo(a: u128, b: u128) -> (u128, bool) { + let mut oflow = 0; + let r = a.addo(b, &mut oflow); + (r, oflow != 0) +} + +#[test] +fn test_add() { + assert_eq!(rust_u128_add(1, 2), 3); + assert_eq!(rust_u128_add(!0, 3), 2); + assert_eq!(rust_u128_add(1 << 63, 1 << 63), 1 << 64); + assert_eq!(rust_u128_add( + 0x54009B79B43145A0_B781BF1FD491296E_u128, + 0x6019CEECA5354210_839AB51D155FF7F3_u128), + 0xB41A6A66596687B1_3B1C743CE9F12161_u128); + assert_eq!(rust_u128_add( + 0x3AE89C3AACEE47CD_8721275248B38DDB_u128, + 0xEFDD73C41D344744_B0842900C3352A63_u128), + 0x2AC60FFECA228F12_37A550530BE8B83E_u128); + + assert_eq!(rust_i128_add(1, 2), 3); + assert_eq!(rust_i128_add(-1, 3), 2); +} + +#[test] +fn test_addo() { + assert_eq!(rust_u128_addo(1, 2), (3, false)); + assert_eq!(rust_u128_addo(!0, 3), (2, true)); + assert_eq!(rust_u128_addo(1 << 63, 1 << 63), (1 << 64, false)); + assert_eq!(rust_u128_addo( + 0x54009B79B43145A0_B781BF1FD491296E_u128, + 0x6019CEECA5354210_839AB51D155FF7F3_u128), + (0xB41A6A66596687B1_3B1C743CE9F12161_u128, false)); + assert_eq!(rust_u128_addo( + 0x3AE89C3AACEE47CD_8721275248B38DDB_u128, + 0xEFDD73C41D344744_B0842900C3352A63_u128), + (0x2AC60FFECA228F12_37A550530BE8B83E_u128, true)); + + assert_eq!(rust_i128_addo(1, 2), (3, false)); + assert_eq!(rust_i128_addo(-1, 3), (2, false)); + assert_eq!(rust_i128_addo(1 << 63, 1 << 63), (1 << 64, false)); + assert_eq!(rust_i128_addo( + 0x54009B79B43145A0_B781BF1FD491296E_i128, + 0x6019CEECA5354210_839AB51D155FF7F3_i128), + (-0x4BE59599A699784E_C4E38BC3160EDE9F_i128, true)); + assert_eq!(rust_i128_addo( + 0x3AE89C3AACEE47CD_8721275248B38DDB_i128, + -0x10228C3BE2CBB8BB_4F7BD6FF3CCAD59D_i128), + (0x2AC60FFECA228F12_37A550530BE8B83E_i128, false)); + assert_eq!(rust_i128_addo( + -0x54009B79B43145A0_B781BF1FD491296E_i128, + -0x6019CEECA5354210_839AB51D155FF7F3_i128), + (0x4BE59599A699784E_C4E38BC3160EDE9F_i128, true)); + assert_eq!(rust_i128_addo( + -0x3AE89C3AACEE47CD_8721275248B38DDB_i128, + 0x10228C3BE2CBB8BB_4F7BD6FF3CCAD59D_i128), + (-0x2AC60FFECA228F12_37A550530BE8B83E_i128, false)); +} \ No newline at end of file diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 37dac8cab2734..c5490cba79619 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -12,9 +12,11 @@ macro_rules! os_ty { } } +pub mod add; pub mod mul; pub mod sdiv; pub mod shift; +pub mod sub; pub mod udiv; /// Trait for some basic operations on integers @@ -72,6 +74,7 @@ pub trait Int: fn wrapping_mul(self, other: Self) -> Self; fn wrapping_sub(self, other: Self) -> Self; fn wrapping_shl(self, other: u32) -> Self; + fn overflowing_add(self, other: Self) -> (Self, bool); fn aborting_div(self, other: Self) -> Self; fn aborting_rem(self, other: Self) -> Self; fn leading_zeros(self) -> u32; @@ -119,6 +122,10 @@ macro_rules! int_impl_common { ::wrapping_shl(self, other) } + fn overflowing_add(self, other: Self) -> (Self, bool) { + ::overflowing_add(self, other) + } + fn aborting_div(self, other: Self) -> Self { unwrap(::checked_div(self, other)) } diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index a4b2ebd7fb773..9d45fa54b8b27 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -70,6 +70,18 @@ impl Mulo for i32 {} impl Mulo for i64 {} impl Mulo for i128 {} +trait UMulo : Int { + fn mulo(self, other: Self, overflow: &mut i32) -> Self { + *overflow = 0; + let result = self.wrapping_mul(other); + if self > Self::max_value().aborting_div(other) { + *overflow = 1; + } + result + } +} +impl UMulo for u128 {} + intrinsics! { #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] #[arm_aeabi_alias = __aeabi_lmul] @@ -95,3 +107,28 @@ intrinsics! { a.mulo(b, oflow) } } + +#[cfg_attr(not(stage0), lang = "i128_mul")] +#[allow(dead_code)] +fn rust_i128_mul(a: i128, b: i128) -> i128 { + __multi3(a, b) +} +#[cfg_attr(not(stage0), lang = "i128_mulo")] +#[allow(dead_code)] +fn rust_i128_mulo(a: i128, b: i128) -> (i128, bool) { + let mut oflow = 0; + let r = __muloti4(a, b, &mut oflow); + (r, oflow != 0) +} +#[cfg_attr(not(stage0), lang = "u128_mul")] +#[allow(dead_code)] +fn rust_u128_mul(a: u128, b: u128) -> u128 { + __multi3(a as _, b as _) as _ +} +#[cfg_attr(not(stage0), lang = "u128_mulo")] +#[allow(dead_code)] +fn rust_u128_mulo(a: u128, b: u128) -> (u128, bool) { + let mut oflow = 0; + let r = a.mulo(b, &mut oflow); + (r, oflow != 0) +} diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index ff8fa61e4b9e6..6fef631c624d6 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -97,3 +97,14 @@ intrinsics! { a.divmod(b, rem, |a, b| __divdi3(a, b)) } } + +#[cfg_attr(not(stage0), lang = "i128_div")] +#[allow(dead_code)] +fn rust_i128_div(a: i128, b: i128) -> i128 { + __divti3(a, b) +} +#[cfg_attr(not(stage0), lang = "i128_rem")] +#[allow(dead_code)] +fn rust_i128_rem(a: i128, b: i128) -> i128 { + __modti3(a, b) +} diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 805d7059623a8..de6d06b6c68a3 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -95,3 +95,45 @@ intrinsics! { a.lshr(b) } } + +#[cfg_attr(not(stage0), lang = "i128_shl")] +#[allow(dead_code)] +fn rust_i128_shl(a: i128, b: u32) -> i128 { + __ashlti3(a as _, b) as _ +} +#[cfg_attr(not(stage0), lang = "i128_shlo")] +#[allow(dead_code)] +fn rust_i128_shlo(a: i128, b: u128) -> (i128, bool) { + (rust_i128_shl(a, b as _), b >= 128) +} +#[cfg_attr(not(stage0), lang = "u128_shl")] +#[allow(dead_code)] +fn rust_u128_shl(a: u128, b: u32) -> u128 { + __ashlti3(a, b) +} +#[cfg_attr(not(stage0), lang = "u128_shlo")] +#[allow(dead_code)] +fn rust_u128_shlo(a: u128, b: u128) -> (u128, bool) { + (rust_u128_shl(a, b as _), b >= 128) +} + +#[cfg_attr(not(stage0), lang = "i128_shr")] +#[allow(dead_code)] +fn rust_i128_shr(a: i128, b: u32) -> i128 { + __ashrti3(a, b) +} +#[cfg_attr(not(stage0), lang = "i128_shro")] +#[allow(dead_code)] +fn rust_i128_shro(a: i128, b: u128) -> (i128, bool) { + (rust_i128_shr(a, b as _), b >= 128) +} +#[cfg_attr(not(stage0), lang = "u128_shr")] +#[allow(dead_code)] +fn rust_u128_shr(a: u128, b: u32) -> u128 { + __lshrti3(a, b) +} +#[cfg_attr(not(stage0), lang = "u128_shro")] +#[allow(dead_code)] +fn rust_u128_shro(a: u128, b: u128) -> (u128, bool) { + (rust_u128_shr(a, b as _), b >= 128) +} diff --git a/library/compiler-builtins/src/int/sub.rs b/library/compiler-builtins/src/int/sub.rs new file mode 100644 index 0000000000000..4d3dfeb9ff0a2 --- /dev/null +++ b/library/compiler-builtins/src/int/sub.rs @@ -0,0 +1,109 @@ +use int::LargeInt; +use int::Int; + +trait Sub: LargeInt { + fn sub(self, other: Self) -> Self { + let neg_other = (!other).wrapping_add(Self::ONE); + self.wrapping_add(neg_other) + } +} + +impl Sub for u128 {} + +trait Subo: Int { + fn subo(self, other: Self, overflow: &mut i32) -> Self { + *overflow = 0; + let result = self.wrapping_sub(other); + if other >= Self::ZERO { + if result > self { + *overflow = 1; + } + } else { + if result <= self { + *overflow = 1; + } + } + result + } +} + +impl Subo for i128 {} +impl Subo for u128 {} + +#[cfg_attr(not(stage0), lang = "i128_sub")] +#[allow(dead_code)] +fn rust_i128_sub(a: i128, b: i128) -> i128 { + rust_u128_sub(a as _, b as _) as _ +} +#[cfg_attr(not(stage0), lang = "i128_subo")] +#[allow(dead_code)] +fn rust_i128_subo(a: i128, b: i128) -> (i128, bool) { + let mut oflow = 0; + let r = a.subo(b, &mut oflow); + (r, oflow != 0) +} +#[cfg_attr(not(stage0), lang = "u128_sub")] +#[allow(dead_code)] +fn rust_u128_sub(a: u128, b: u128) -> u128 { + a.sub(b) +} +#[cfg_attr(not(stage0), lang = "u128_subo")] +#[allow(dead_code)] +fn rust_u128_subo(a: u128, b: u128) -> (u128, bool) { + let mut oflow = 0; + let r = a.subo(b, &mut oflow); + (r, oflow != 0) +} + +#[test] +fn test_sub() { + assert_eq!(rust_u128_sub(3, 2), 1); + assert_eq!(rust_u128_sub(2, 3), !0); + assert_eq!(rust_u128_sub(1 << 64, 1 << 63), 1 << 63); + assert_eq!(rust_u128_sub( + 0xB41A6A66596687B1_3B1C743CE9F12161_u128, + 0x6019CEECA5354210_839AB51D155FF7F3_u128), + 0x54009B79B43145A0_B781BF1FD491296E_u128); + assert_eq!(rust_u128_sub( + 0x2AC60FFECA228F12_37A550530BE8B83E_u128, + 0xEFDD73C41D344744_B0842900C3352A63_u128), + 0x3AE89C3AACEE47CD_8721275248B38DDB_u128); + + assert_eq!(rust_i128_sub(3, 2), 1); + assert_eq!(rust_i128_sub(2, 3), -1); +} + +#[test] +fn test_subo() { + assert_eq!(rust_u128_subo(3, 2), (1, false)); + assert_eq!(rust_u128_subo(2, 3), (!0, true)); + assert_eq!(rust_u128_subo(1 << 64, 1 << 63), (1 << 63, false)); + assert_eq!(rust_u128_subo( + 0xB41A6A66596687B1_3B1C743CE9F12161_u128, + 0x6019CEECA5354210_839AB51D155FF7F3_u128), + (0x54009B79B43145A0_B781BF1FD491296E_u128, false)); + assert_eq!(rust_u128_subo( + 0x2AC60FFECA228F12_37A550530BE8B83E_u128, + 0xEFDD73C41D344744_B0842900C3352A63_u128), + (0x3AE89C3AACEE47CD_8721275248B38DDB_u128, true)); + + assert_eq!(rust_i128_subo(3, 2), (1, false)); + assert_eq!(rust_i128_subo(2, 3), (-1, false)); + assert_eq!(rust_i128_subo(1 << 64, 1 << 63), (1 << 63, false)); + assert_eq!(rust_i128_subo( + -0x4BE59599A699784E_C4E38BC3160EDE9F_i128, + 0x6019CEECA5354210_839AB51D155FF7F3_i128), + (0x54009B79B43145A0_B781BF1FD491296E_i128, true)); + assert_eq!(rust_i128_subo( + 0x2AC60FFECA228F12_37A550530BE8B83E_i128, + -0x10228C3BE2CBB8BB_4F7BD6FF3CCAD59D_i128), + (0x3AE89C3AACEE47CD_8721275248B38DDB_i128, false)); + assert_eq!(rust_i128_subo( + 0x4BE59599A699784E_C4E38BC3160EDE9F_i128, + -0x6019CEECA5354210_839AB51D155FF7F3_i128), + (-0x54009B79B43145A0_B781BF1FD491296E_i128, true)); + assert_eq!(rust_i128_subo( + -0x2AC60FFECA228F12_37A550530BE8B83E_i128, + 0x10228C3BE2CBB8BB_4F7BD6FF3CCAD59D_i128), + (-0x3AE89C3AACEE47CD_8721275248B38DDB_i128, false)); +} \ No newline at end of file diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 74a2ac3387dc5..0442a8c4a0efc 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -269,3 +269,14 @@ intrinsics! { udivmod_inner!(n, d, rem, u128) } } + +#[cfg_attr(not(stage0), lang = "u128_div")] +#[allow(dead_code)] +fn rust_u128_div(a: u128, b: u128) -> u128 { + __udivti3(a, b) +} +#[cfg_attr(not(stage0), lang = "u128_rem")] +#[allow(dead_code)] +fn rust_u128_rem(a: u128, b: u128) -> u128 { + __umodti3(a, b) +} diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 8bf3230654a2f..ff7885bb3f6dd 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -17,6 +17,7 @@ #![feature(repr_simd)] #![feature(abi_unadjusted)] #![feature(linkage)] +#![feature(lang_items)] #![allow(unused_features)] #![no_builtins] #![unstable(feature = "compiler_builtins_lib", From a35d63583f58a733ebd9b86e1848729ab3f044db Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 25 Nov 2017 05:26:24 -0800 Subject: [PATCH 0403/4206] Tweak addo & subo to try and fix MIPS --- library/compiler-builtins/src/int/add.rs | 21 +++++++++++++++++---- library/compiler-builtins/src/int/sub.rs | 6 +++--- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/src/int/add.rs b/library/compiler-builtins/src/int/add.rs index 639d14ac309c7..4253b64f7ba14 100644 --- a/library/compiler-builtins/src/int/add.rs +++ b/library/compiler-builtins/src/int/add.rs @@ -1,8 +1,8 @@ use int::LargeInt; use int::Int; -trait Add: LargeInt { - fn add(self, other: Self) -> Self { +trait UAdd: LargeInt { + fn uadd(self, other: Self) -> Self { let (low, carry) = self.low().overflowing_add(other.low()); let high = self.high().wrapping_add(other.high()); let carry = if carry { Self::HighHalf::ONE } else { Self::HighHalf::ZERO }; @@ -10,12 +10,25 @@ trait Add: LargeInt { } } +impl UAdd for u128 {} + +trait Add: Int + where ::UnsignedInt: UAdd +{ + fn add(self, other: Self) -> Self { + Self::from_unsigned(self.unsigned().uadd(other.unsigned())) + } +} + impl Add for u128 {} +impl Add for i128 {} -trait Addo: Int { +trait Addo: Add + where ::UnsignedInt: UAdd +{ fn addo(self, other: Self, overflow: &mut i32) -> Self { *overflow = 0; - let result = self.wrapping_add(other); + let result = Add::add(self, other); if other >= Self::ZERO { if result < self { *overflow = 1; diff --git a/library/compiler-builtins/src/int/sub.rs b/library/compiler-builtins/src/int/sub.rs index 4d3dfeb9ff0a2..ba29c10215771 100644 --- a/library/compiler-builtins/src/int/sub.rs +++ b/library/compiler-builtins/src/int/sub.rs @@ -1,5 +1,4 @@ use int::LargeInt; -use int::Int; trait Sub: LargeInt { fn sub(self, other: Self) -> Self { @@ -8,12 +7,13 @@ trait Sub: LargeInt { } } +impl Sub for i128 {} impl Sub for u128 {} -trait Subo: Int { +trait Subo: Sub { fn subo(self, other: Self, overflow: &mut i32) -> Self { *overflow = 0; - let result = self.wrapping_sub(other); + let result = Sub::sub(self, other); if other >= Self::ZERO { if result > self { *overflow = 1; From 51a0396d2a208fd5cd06b3d9350ddcd298edd2fb Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 25 Nov 2017 05:53:53 -0800 Subject: [PATCH 0404/4206] Make them all `pub` --- library/compiler-builtins/src/int/add.rs | 12 ++++------- library/compiler-builtins/src/int/mul.rs | 12 ++++------- library/compiler-builtins/src/int/sdiv.rs | 6 ++---- library/compiler-builtins/src/int/shift.rs | 24 ++++++++-------------- library/compiler-builtins/src/int/sub.rs | 12 ++++------- library/compiler-builtins/src/int/udiv.rs | 6 ++---- 6 files changed, 24 insertions(+), 48 deletions(-) diff --git a/library/compiler-builtins/src/int/add.rs b/library/compiler-builtins/src/int/add.rs index 4253b64f7ba14..b0f7ab6214ab5 100644 --- a/library/compiler-builtins/src/int/add.rs +++ b/library/compiler-builtins/src/int/add.rs @@ -46,25 +46,21 @@ impl Addo for i128 {} impl Addo for u128 {} #[cfg_attr(not(stage0), lang = "i128_add")] -#[allow(dead_code)] -fn rust_i128_add(a: i128, b: i128) -> i128 { +pub fn rust_i128_add(a: i128, b: i128) -> i128 { rust_u128_add(a as _, b as _) as _ } #[cfg_attr(not(stage0), lang = "i128_addo")] -#[allow(dead_code)] -fn rust_i128_addo(a: i128, b: i128) -> (i128, bool) { +pub fn rust_i128_addo(a: i128, b: i128) -> (i128, bool) { let mut oflow = 0; let r = a.addo(b, &mut oflow); (r, oflow != 0) } #[cfg_attr(not(stage0), lang = "u128_add")] -#[allow(dead_code)] -fn rust_u128_add(a: u128, b: u128) -> u128 { +pub fn rust_u128_add(a: u128, b: u128) -> u128 { a.add(b) } #[cfg_attr(not(stage0), lang = "u128_addo")] -#[allow(dead_code)] -fn rust_u128_addo(a: u128, b: u128) -> (u128, bool) { +pub fn rust_u128_addo(a: u128, b: u128) -> (u128, bool) { let mut oflow = 0; let r = a.addo(b, &mut oflow); (r, oflow != 0) diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 9d45fa54b8b27..61c379c7b6885 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -109,25 +109,21 @@ intrinsics! { } #[cfg_attr(not(stage0), lang = "i128_mul")] -#[allow(dead_code)] -fn rust_i128_mul(a: i128, b: i128) -> i128 { +pub fn rust_i128_mul(a: i128, b: i128) -> i128 { __multi3(a, b) } #[cfg_attr(not(stage0), lang = "i128_mulo")] -#[allow(dead_code)] -fn rust_i128_mulo(a: i128, b: i128) -> (i128, bool) { +pub fn rust_i128_mulo(a: i128, b: i128) -> (i128, bool) { let mut oflow = 0; let r = __muloti4(a, b, &mut oflow); (r, oflow != 0) } #[cfg_attr(not(stage0), lang = "u128_mul")] -#[allow(dead_code)] -fn rust_u128_mul(a: u128, b: u128) -> u128 { +pub fn rust_u128_mul(a: u128, b: u128) -> u128 { __multi3(a as _, b as _) as _ } #[cfg_attr(not(stage0), lang = "u128_mulo")] -#[allow(dead_code)] -fn rust_u128_mulo(a: u128, b: u128) -> (u128, bool) { +pub fn rust_u128_mulo(a: u128, b: u128) -> (u128, bool) { let mut oflow = 0; let r = a.mulo(b, &mut oflow); (r, oflow != 0) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 6fef631c624d6..03086646695b8 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -99,12 +99,10 @@ intrinsics! { } #[cfg_attr(not(stage0), lang = "i128_div")] -#[allow(dead_code)] -fn rust_i128_div(a: i128, b: i128) -> i128 { +pub fn rust_i128_div(a: i128, b: i128) -> i128 { __divti3(a, b) } #[cfg_attr(not(stage0), lang = "i128_rem")] -#[allow(dead_code)] -fn rust_i128_rem(a: i128, b: i128) -> i128 { +pub fn rust_i128_rem(a: i128, b: i128) -> i128 { __modti3(a, b) } diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index de6d06b6c68a3..f8faad829a9ce 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -97,43 +97,35 @@ intrinsics! { } #[cfg_attr(not(stage0), lang = "i128_shl")] -#[allow(dead_code)] -fn rust_i128_shl(a: i128, b: u32) -> i128 { +pub fn rust_i128_shl(a: i128, b: u32) -> i128 { __ashlti3(a as _, b) as _ } #[cfg_attr(not(stage0), lang = "i128_shlo")] -#[allow(dead_code)] -fn rust_i128_shlo(a: i128, b: u128) -> (i128, bool) { +pub fn rust_i128_shlo(a: i128, b: u128) -> (i128, bool) { (rust_i128_shl(a, b as _), b >= 128) } #[cfg_attr(not(stage0), lang = "u128_shl")] -#[allow(dead_code)] -fn rust_u128_shl(a: u128, b: u32) -> u128 { +pub fn rust_u128_shl(a: u128, b: u32) -> u128 { __ashlti3(a, b) } #[cfg_attr(not(stage0), lang = "u128_shlo")] -#[allow(dead_code)] -fn rust_u128_shlo(a: u128, b: u128) -> (u128, bool) { +pub fn rust_u128_shlo(a: u128, b: u128) -> (u128, bool) { (rust_u128_shl(a, b as _), b >= 128) } #[cfg_attr(not(stage0), lang = "i128_shr")] -#[allow(dead_code)] -fn rust_i128_shr(a: i128, b: u32) -> i128 { +pub fn rust_i128_shr(a: i128, b: u32) -> i128 { __ashrti3(a, b) } #[cfg_attr(not(stage0), lang = "i128_shro")] -#[allow(dead_code)] -fn rust_i128_shro(a: i128, b: u128) -> (i128, bool) { +pub fn rust_i128_shro(a: i128, b: u128) -> (i128, bool) { (rust_i128_shr(a, b as _), b >= 128) } #[cfg_attr(not(stage0), lang = "u128_shr")] -#[allow(dead_code)] -fn rust_u128_shr(a: u128, b: u32) -> u128 { +pub fn rust_u128_shr(a: u128, b: u32) -> u128 { __lshrti3(a, b) } #[cfg_attr(not(stage0), lang = "u128_shro")] -#[allow(dead_code)] -fn rust_u128_shro(a: u128, b: u128) -> (u128, bool) { +pub fn rust_u128_shro(a: u128, b: u128) -> (u128, bool) { (rust_u128_shr(a, b as _), b >= 128) } diff --git a/library/compiler-builtins/src/int/sub.rs b/library/compiler-builtins/src/int/sub.rs index ba29c10215771..0b0cbf2479f48 100644 --- a/library/compiler-builtins/src/int/sub.rs +++ b/library/compiler-builtins/src/int/sub.rs @@ -31,25 +31,21 @@ impl Subo for i128 {} impl Subo for u128 {} #[cfg_attr(not(stage0), lang = "i128_sub")] -#[allow(dead_code)] -fn rust_i128_sub(a: i128, b: i128) -> i128 { +pub fn rust_i128_sub(a: i128, b: i128) -> i128 { rust_u128_sub(a as _, b as _) as _ } #[cfg_attr(not(stage0), lang = "i128_subo")] -#[allow(dead_code)] -fn rust_i128_subo(a: i128, b: i128) -> (i128, bool) { +pub fn rust_i128_subo(a: i128, b: i128) -> (i128, bool) { let mut oflow = 0; let r = a.subo(b, &mut oflow); (r, oflow != 0) } #[cfg_attr(not(stage0), lang = "u128_sub")] -#[allow(dead_code)] -fn rust_u128_sub(a: u128, b: u128) -> u128 { +pub fn rust_u128_sub(a: u128, b: u128) -> u128 { a.sub(b) } #[cfg_attr(not(stage0), lang = "u128_subo")] -#[allow(dead_code)] -fn rust_u128_subo(a: u128, b: u128) -> (u128, bool) { +pub fn rust_u128_subo(a: u128, b: u128) -> (u128, bool) { let mut oflow = 0; let r = a.subo(b, &mut oflow); (r, oflow != 0) diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 0442a8c4a0efc..6c100f3f86d78 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -271,12 +271,10 @@ intrinsics! { } #[cfg_attr(not(stage0), lang = "u128_div")] -#[allow(dead_code)] -fn rust_u128_div(a: u128, b: u128) -> u128 { +pub fn rust_u128_div(a: u128, b: u128) -> u128 { __udivti3(a, b) } #[cfg_attr(not(stage0), lang = "u128_rem")] -#[allow(dead_code)] -fn rust_u128_rem(a: u128, b: u128) -> u128 { +pub fn rust_u128_rem(a: u128, b: u128) -> u128 { __umodti3(a, b) } From ba376a39125d3890c618450ea5ec960781fda1d8 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 25 Nov 2017 06:24:07 -0800 Subject: [PATCH 0405/4206] Autogenerate the add/sub tests --- library/compiler-builtins/build.rs | 484 +++++++++++++++++++ library/compiler-builtins/src/int/add.rs | 53 -- library/compiler-builtins/src/int/sub.rs | 53 -- library/compiler-builtins/tests/i128_add.rs | 8 + library/compiler-builtins/tests/i128_addo.rs | 8 + library/compiler-builtins/tests/i128_sub.rs | 8 + library/compiler-builtins/tests/i128_subo.rs | 8 + library/compiler-builtins/tests/u128_add.rs | 8 + library/compiler-builtins/tests/u128_addo.rs | 8 + library/compiler-builtins/tests/u128_sub.rs | 8 + library/compiler-builtins/tests/u128_subo.rs | 8 + 11 files changed, 548 insertions(+), 106 deletions(-) create mode 100644 library/compiler-builtins/tests/i128_add.rs create mode 100644 library/compiler-builtins/tests/i128_addo.rs create mode 100644 library/compiler-builtins/tests/i128_sub.rs create mode 100644 library/compiler-builtins/tests/i128_subo.rs create mode 100644 library/compiler-builtins/tests/u128_add.rs create mode 100644 library/compiler-builtins/tests/u128_addo.rs create mode 100644 library/compiler-builtins/tests/u128_sub.rs create mode 100644 library/compiler-builtins/tests/u128_subo.rs diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index e2a63a6cf97b4..d7f6c01becf99 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -129,6 +129,12 @@ mod tests { Divsf3, Divdf3, + // int/add.rs + AddU128, + AddI128, + AddoU128, + AddoI128, + // int/mul.rs Muldi3, Mulodi4, @@ -154,6 +160,12 @@ mod tests { Lshrdi3, Lshrti3, + // int/sub.rs + SubU128, + SubI128, + SuboU128, + SuboI128, + // int/udiv.rs Udivdi3, Udivmoddi4, @@ -341,6 +353,242 @@ fn addsf3() { } } + #[derive(Eq, Hash, PartialEq)] + pub struct AddU128 { + a: u128, + b: u128, + c: u128, + } + + impl TestCase for AddU128 { + fn name() -> &'static str { + "u128_add" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u128(rng); + let b = gen_u128(rng); + let c = a.wrapping_add(b); + + Some(AddU128 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::add::rust_u128_add; + +static TEST_CASES: &[((u128, u128), u128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn u128_add() { + for &((a, b), c) in TEST_CASES { + let c_ = rust_u128_add(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct AddI128 { + a: i128, + b: i128, + c: i128, + } + + impl TestCase for AddI128 { + fn name() -> &'static str { + "i128_add" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i128(rng); + let b = gen_i128(rng); + let c = a.wrapping_add(b); + + Some(AddI128 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::add::rust_i128_add; + +static TEST_CASES: &[((i128, i128), i128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn i128_add() { + for &((a, b), c) in TEST_CASES { + let c_ = rust_i128_add(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct AddoU128 { + a: u128, + b: u128, + c: u128, + d: bool, + } + + impl TestCase for AddoU128 { + fn name() -> &'static str { + "u128_addo" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u128(rng); + let b = gen_u128(rng); + let (c, d) = a.overflowing_add(b); + + Some(AddoU128 { a, b, c, d }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {d})),", + a = self.a, + b = self.b, + c = self.c, + d = self.d + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::add::rust_u128_addo; + +static TEST_CASES: &[((u128, u128), (u128, bool))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn u128_addo() { + for &((a, b), (c, d)) in TEST_CASES { + let (c_, d_) = rust_u128_addo(a, b); + assert_eq!(((a, b), (c, d)), ((a, b), (c_, d_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct AddoI128 { + a: i128, + b: i128, + c: i128, + d: bool, + } + + impl TestCase for AddoI128 { + fn name() -> &'static str { + "i128_addo" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i128(rng); + let b = gen_i128(rng); + let (c, d) = a.overflowing_add(b); + + Some(AddoI128 { a, b, c, d }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {d})),", + a = self.a, + b = self.b, + c = self.c, + d = self.d + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::add::rust_i128_addo; + +static TEST_CASES: &[((i128, i128), (i128, bool))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn i128_addo() { + for &((a, b), (c, d)) in TEST_CASES { + let (c_, d_) = rust_i128_addo(a, b); + assert_eq!(((a, b), (c, d)), ((a, b), (c_, d_))); + } +} +" + } + } + #[derive(Eq, Hash, PartialEq)] pub struct Ashldi3 { a: u64, @@ -3229,6 +3477,242 @@ fn subsf3() { } } + #[derive(Eq, Hash, PartialEq)] + pub struct SubU128 { + a: u128, + b: u128, + c: u128, + } + + impl TestCase for SubU128 { + fn name() -> &'static str { + "u128_sub" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u128(rng); + let b = gen_u128(rng); + let c = a.wrapping_sub(b); + + Some(SubU128 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sub::rust_u128_sub; + +static TEST_CASES: &[((u128, u128), u128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn u128_sub() { + for &((a, b), c) in TEST_CASES { + let c_ = rust_u128_sub(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct SubI128 { + a: i128, + b: i128, + c: i128, + } + + impl TestCase for SubI128 { + fn name() -> &'static str { + "i128_sub" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i128(rng); + let b = gen_i128(rng); + let c = a.wrapping_sub(b); + + Some(SubI128 { a, b, c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sub::rust_i128_sub; + +static TEST_CASES: &[((i128, i128), i128)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn i128_sub() { + for &((a, b), c) in TEST_CASES { + let c_ = rust_i128_sub(a, b); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct SuboU128 { + a: u128, + b: u128, + c: u128, + d: bool, + } + + impl TestCase for SuboU128 { + fn name() -> &'static str { + "u128_subo" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_u128(rng); + let b = gen_u128(rng); + let (c, d) = a.overflowing_sub(b); + + Some(SuboU128 { a, b, c, d }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {d})),", + a = self.a, + b = self.b, + c = self.c, + d = self.d + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sub::rust_u128_subo; + +static TEST_CASES: &[((u128, u128), (u128, bool))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn u128_subo() { + for &((a, b), (c, d)) in TEST_CASES { + let (c_, d_) = rust_u128_subo(a, b); + assert_eq!(((a, b), (c, d)), ((a, b), (c_, d_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct SuboI128 { + a: i128, + b: i128, + c: i128, + d: bool, + } + + impl TestCase for SuboI128 { + fn name() -> &'static str { + "i128_subo" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_i128(rng); + let b = gen_i128(rng); + let (c, d) = a.overflowing_sub(b); + + Some(SuboI128 { a, b, c, d }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), ({c}, {d})),", + a = self.a, + b = self.b, + c = self.c, + d = self.d + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use compiler_builtins::int::sub::rust_i128_subo; + +static TEST_CASES: &[((i128, i128), (i128, bool))] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn i128_subo() { + for &((a, b), (c, d)) in TEST_CASES { + let (c_, d_) = rust_i128_subo(a, b); + assert_eq!(((a, b), (c, d)), ((a, b), (c_, d_))); + } +} +" + } + } + #[derive(Eq, Hash, PartialEq)] pub struct Mulsf3 { a: u32, // f32 diff --git a/library/compiler-builtins/src/int/add.rs b/library/compiler-builtins/src/int/add.rs index b0f7ab6214ab5..5c746c233dda6 100644 --- a/library/compiler-builtins/src/int/add.rs +++ b/library/compiler-builtins/src/int/add.rs @@ -65,56 +65,3 @@ pub fn rust_u128_addo(a: u128, b: u128) -> (u128, bool) { let r = a.addo(b, &mut oflow); (r, oflow != 0) } - -#[test] -fn test_add() { - assert_eq!(rust_u128_add(1, 2), 3); - assert_eq!(rust_u128_add(!0, 3), 2); - assert_eq!(rust_u128_add(1 << 63, 1 << 63), 1 << 64); - assert_eq!(rust_u128_add( - 0x54009B79B43145A0_B781BF1FD491296E_u128, - 0x6019CEECA5354210_839AB51D155FF7F3_u128), - 0xB41A6A66596687B1_3B1C743CE9F12161_u128); - assert_eq!(rust_u128_add( - 0x3AE89C3AACEE47CD_8721275248B38DDB_u128, - 0xEFDD73C41D344744_B0842900C3352A63_u128), - 0x2AC60FFECA228F12_37A550530BE8B83E_u128); - - assert_eq!(rust_i128_add(1, 2), 3); - assert_eq!(rust_i128_add(-1, 3), 2); -} - -#[test] -fn test_addo() { - assert_eq!(rust_u128_addo(1, 2), (3, false)); - assert_eq!(rust_u128_addo(!0, 3), (2, true)); - assert_eq!(rust_u128_addo(1 << 63, 1 << 63), (1 << 64, false)); - assert_eq!(rust_u128_addo( - 0x54009B79B43145A0_B781BF1FD491296E_u128, - 0x6019CEECA5354210_839AB51D155FF7F3_u128), - (0xB41A6A66596687B1_3B1C743CE9F12161_u128, false)); - assert_eq!(rust_u128_addo( - 0x3AE89C3AACEE47CD_8721275248B38DDB_u128, - 0xEFDD73C41D344744_B0842900C3352A63_u128), - (0x2AC60FFECA228F12_37A550530BE8B83E_u128, true)); - - assert_eq!(rust_i128_addo(1, 2), (3, false)); - assert_eq!(rust_i128_addo(-1, 3), (2, false)); - assert_eq!(rust_i128_addo(1 << 63, 1 << 63), (1 << 64, false)); - assert_eq!(rust_i128_addo( - 0x54009B79B43145A0_B781BF1FD491296E_i128, - 0x6019CEECA5354210_839AB51D155FF7F3_i128), - (-0x4BE59599A699784E_C4E38BC3160EDE9F_i128, true)); - assert_eq!(rust_i128_addo( - 0x3AE89C3AACEE47CD_8721275248B38DDB_i128, - -0x10228C3BE2CBB8BB_4F7BD6FF3CCAD59D_i128), - (0x2AC60FFECA228F12_37A550530BE8B83E_i128, false)); - assert_eq!(rust_i128_addo( - -0x54009B79B43145A0_B781BF1FD491296E_i128, - -0x6019CEECA5354210_839AB51D155FF7F3_i128), - (0x4BE59599A699784E_C4E38BC3160EDE9F_i128, true)); - assert_eq!(rust_i128_addo( - -0x3AE89C3AACEE47CD_8721275248B38DDB_i128, - 0x10228C3BE2CBB8BB_4F7BD6FF3CCAD59D_i128), - (-0x2AC60FFECA228F12_37A550530BE8B83E_i128, false)); -} \ No newline at end of file diff --git a/library/compiler-builtins/src/int/sub.rs b/library/compiler-builtins/src/int/sub.rs index 0b0cbf2479f48..abcb45a80eed4 100644 --- a/library/compiler-builtins/src/int/sub.rs +++ b/library/compiler-builtins/src/int/sub.rs @@ -50,56 +50,3 @@ pub fn rust_u128_subo(a: u128, b: u128) -> (u128, bool) { let r = a.subo(b, &mut oflow); (r, oflow != 0) } - -#[test] -fn test_sub() { - assert_eq!(rust_u128_sub(3, 2), 1); - assert_eq!(rust_u128_sub(2, 3), !0); - assert_eq!(rust_u128_sub(1 << 64, 1 << 63), 1 << 63); - assert_eq!(rust_u128_sub( - 0xB41A6A66596687B1_3B1C743CE9F12161_u128, - 0x6019CEECA5354210_839AB51D155FF7F3_u128), - 0x54009B79B43145A0_B781BF1FD491296E_u128); - assert_eq!(rust_u128_sub( - 0x2AC60FFECA228F12_37A550530BE8B83E_u128, - 0xEFDD73C41D344744_B0842900C3352A63_u128), - 0x3AE89C3AACEE47CD_8721275248B38DDB_u128); - - assert_eq!(rust_i128_sub(3, 2), 1); - assert_eq!(rust_i128_sub(2, 3), -1); -} - -#[test] -fn test_subo() { - assert_eq!(rust_u128_subo(3, 2), (1, false)); - assert_eq!(rust_u128_subo(2, 3), (!0, true)); - assert_eq!(rust_u128_subo(1 << 64, 1 << 63), (1 << 63, false)); - assert_eq!(rust_u128_subo( - 0xB41A6A66596687B1_3B1C743CE9F12161_u128, - 0x6019CEECA5354210_839AB51D155FF7F3_u128), - (0x54009B79B43145A0_B781BF1FD491296E_u128, false)); - assert_eq!(rust_u128_subo( - 0x2AC60FFECA228F12_37A550530BE8B83E_u128, - 0xEFDD73C41D344744_B0842900C3352A63_u128), - (0x3AE89C3AACEE47CD_8721275248B38DDB_u128, true)); - - assert_eq!(rust_i128_subo(3, 2), (1, false)); - assert_eq!(rust_i128_subo(2, 3), (-1, false)); - assert_eq!(rust_i128_subo(1 << 64, 1 << 63), (1 << 63, false)); - assert_eq!(rust_i128_subo( - -0x4BE59599A699784E_C4E38BC3160EDE9F_i128, - 0x6019CEECA5354210_839AB51D155FF7F3_i128), - (0x54009B79B43145A0_B781BF1FD491296E_i128, true)); - assert_eq!(rust_i128_subo( - 0x2AC60FFECA228F12_37A550530BE8B83E_i128, - -0x10228C3BE2CBB8BB_4F7BD6FF3CCAD59D_i128), - (0x3AE89C3AACEE47CD_8721275248B38DDB_i128, false)); - assert_eq!(rust_i128_subo( - 0x4BE59599A699784E_C4E38BC3160EDE9F_i128, - -0x6019CEECA5354210_839AB51D155FF7F3_i128), - (-0x54009B79B43145A0_B781BF1FD491296E_i128, true)); - assert_eq!(rust_i128_subo( - -0x2AC60FFECA228F12_37A550530BE8B83E_i128, - 0x10228C3BE2CBB8BB_4F7BD6FF3CCAD59D_i128), - (-0x3AE89C3AACEE47CD_8721275248B38DDB_i128, false)); -} \ No newline at end of file diff --git a/library/compiler-builtins/tests/i128_add.rs b/library/compiler-builtins/tests/i128_add.rs new file mode 100644 index 0000000000000..13af0500cb824 --- /dev/null +++ b/library/compiler-builtins/tests/i128_add.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/i128_add.rs")); diff --git a/library/compiler-builtins/tests/i128_addo.rs b/library/compiler-builtins/tests/i128_addo.rs new file mode 100644 index 0000000000000..306ffac169eac --- /dev/null +++ b/library/compiler-builtins/tests/i128_addo.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/i128_addo.rs")); diff --git a/library/compiler-builtins/tests/i128_sub.rs b/library/compiler-builtins/tests/i128_sub.rs new file mode 100644 index 0000000000000..933fe4f56617c --- /dev/null +++ b/library/compiler-builtins/tests/i128_sub.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/i128_sub.rs")); diff --git a/library/compiler-builtins/tests/i128_subo.rs b/library/compiler-builtins/tests/i128_subo.rs new file mode 100644 index 0000000000000..0c2b67cbbdc9d --- /dev/null +++ b/library/compiler-builtins/tests/i128_subo.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/i128_subo.rs")); diff --git a/library/compiler-builtins/tests/u128_add.rs b/library/compiler-builtins/tests/u128_add.rs new file mode 100644 index 0000000000000..d4b8f2ccb248b --- /dev/null +++ b/library/compiler-builtins/tests/u128_add.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/u128_add.rs")); diff --git a/library/compiler-builtins/tests/u128_addo.rs b/library/compiler-builtins/tests/u128_addo.rs new file mode 100644 index 0000000000000..caff682e8a087 --- /dev/null +++ b/library/compiler-builtins/tests/u128_addo.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/u128_addo.rs")); diff --git a/library/compiler-builtins/tests/u128_sub.rs b/library/compiler-builtins/tests/u128_sub.rs new file mode 100644 index 0000000000000..024266b926382 --- /dev/null +++ b/library/compiler-builtins/tests/u128_sub.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/u128_sub.rs")); diff --git a/library/compiler-builtins/tests/u128_subo.rs b/library/compiler-builtins/tests/u128_subo.rs new file mode 100644 index 0000000000000..b3fb4b854e243 --- /dev/null +++ b/library/compiler-builtins/tests/u128_subo.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test), no_std)] + +include!(concat!(env!("OUT_DIR"), "/u128_subo.rs")); From f468c28f74321ca970d58d75ad7d481b7651f667 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 25 Nov 2017 07:00:26 -0800 Subject: [PATCH 0406/4206] Another attempt at making MIPS happy (I really don't understand how arithmetic makes it segfault...) --- library/compiler-builtins/build.rs | 28 +++-- library/compiler-builtins/src/int/add.rs | 67 ----------- library/compiler-builtins/src/int/addsub.rs | 122 ++++++++++++++++++++ library/compiler-builtins/src/int/mod.rs | 3 +- library/compiler-builtins/src/int/sub.rs | 52 --------- 5 files changed, 136 insertions(+), 136 deletions(-) delete mode 100644 library/compiler-builtins/src/int/add.rs create mode 100644 library/compiler-builtins/src/int/addsub.rs delete mode 100644 library/compiler-builtins/src/int/sub.rs diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index d7f6c01becf99..753978d234c28 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -129,11 +129,15 @@ mod tests { Divsf3, Divdf3, - // int/add.rs + // int/addsub.rs AddU128, AddI128, AddoU128, AddoI128, + SubU128, + SubI128, + SuboU128, + SuboI128, // int/mul.rs Muldi3, @@ -160,12 +164,6 @@ mod tests { Lshrdi3, Lshrti3, - // int/sub.rs - SubU128, - SubI128, - SuboU128, - SuboI128, - // int/udiv.rs Udivdi3, Udivmoddi4, @@ -390,7 +388,7 @@ fn addsf3() { fn prologue() -> &'static str { " -use compiler_builtins::int::add::rust_u128_add; +use compiler_builtins::int::addsub::rust_u128_add; static TEST_CASES: &[((u128, u128), u128)] = &[ " @@ -448,7 +446,7 @@ fn u128_add() { fn prologue() -> &'static str { " -use compiler_builtins::int::add::rust_i128_add; +use compiler_builtins::int::addsub::rust_i128_add; static TEST_CASES: &[((i128, i128), i128)] = &[ " @@ -508,7 +506,7 @@ fn i128_add() { fn prologue() -> &'static str { " -use compiler_builtins::int::add::rust_u128_addo; +use compiler_builtins::int::addsub::rust_u128_addo; static TEST_CASES: &[((u128, u128), (u128, bool))] = &[ " @@ -568,7 +566,7 @@ fn u128_addo() { fn prologue() -> &'static str { " -use compiler_builtins::int::add::rust_i128_addo; +use compiler_builtins::int::addsub::rust_i128_addo; static TEST_CASES: &[((i128, i128), (i128, bool))] = &[ " @@ -3514,7 +3512,7 @@ fn subsf3() { fn prologue() -> &'static str { " -use compiler_builtins::int::sub::rust_u128_sub; +use compiler_builtins::int::addsub::rust_u128_sub; static TEST_CASES: &[((u128, u128), u128)] = &[ " @@ -3572,7 +3570,7 @@ fn u128_sub() { fn prologue() -> &'static str { " -use compiler_builtins::int::sub::rust_i128_sub; +use compiler_builtins::int::addsub::rust_i128_sub; static TEST_CASES: &[((i128, i128), i128)] = &[ " @@ -3632,7 +3630,7 @@ fn i128_sub() { fn prologue() -> &'static str { " -use compiler_builtins::int::sub::rust_u128_subo; +use compiler_builtins::int::addsub::rust_u128_subo; static TEST_CASES: &[((u128, u128), (u128, bool))] = &[ " @@ -3692,7 +3690,7 @@ fn u128_subo() { fn prologue() -> &'static str { " -use compiler_builtins::int::sub::rust_i128_subo; +use compiler_builtins::int::addsub::rust_i128_subo; static TEST_CASES: &[((i128, i128), (i128, bool))] = &[ " diff --git a/library/compiler-builtins/src/int/add.rs b/library/compiler-builtins/src/int/add.rs deleted file mode 100644 index 5c746c233dda6..0000000000000 --- a/library/compiler-builtins/src/int/add.rs +++ /dev/null @@ -1,67 +0,0 @@ -use int::LargeInt; -use int::Int; - -trait UAdd: LargeInt { - fn uadd(self, other: Self) -> Self { - let (low, carry) = self.low().overflowing_add(other.low()); - let high = self.high().wrapping_add(other.high()); - let carry = if carry { Self::HighHalf::ONE } else { Self::HighHalf::ZERO }; - Self::from_parts(low, high.wrapping_add(carry)) - } -} - -impl UAdd for u128 {} - -trait Add: Int - where ::UnsignedInt: UAdd -{ - fn add(self, other: Self) -> Self { - Self::from_unsigned(self.unsigned().uadd(other.unsigned())) - } -} - -impl Add for u128 {} -impl Add for i128 {} - -trait Addo: Add - where ::UnsignedInt: UAdd -{ - fn addo(self, other: Self, overflow: &mut i32) -> Self { - *overflow = 0; - let result = Add::add(self, other); - if other >= Self::ZERO { - if result < self { - *overflow = 1; - } - } else { - if result >= self { - *overflow = 1; - } - } - result - } -} - -impl Addo for i128 {} -impl Addo for u128 {} - -#[cfg_attr(not(stage0), lang = "i128_add")] -pub fn rust_i128_add(a: i128, b: i128) -> i128 { - rust_u128_add(a as _, b as _) as _ -} -#[cfg_attr(not(stage0), lang = "i128_addo")] -pub fn rust_i128_addo(a: i128, b: i128) -> (i128, bool) { - let mut oflow = 0; - let r = a.addo(b, &mut oflow); - (r, oflow != 0) -} -#[cfg_attr(not(stage0), lang = "u128_add")] -pub fn rust_u128_add(a: u128, b: u128) -> u128 { - a.add(b) -} -#[cfg_attr(not(stage0), lang = "u128_addo")] -pub fn rust_u128_addo(a: u128, b: u128) -> (u128, bool) { - let mut oflow = 0; - let r = a.addo(b, &mut oflow); - (r, oflow != 0) -} diff --git a/library/compiler-builtins/src/int/addsub.rs b/library/compiler-builtins/src/int/addsub.rs new file mode 100644 index 0000000000000..7564d896df258 --- /dev/null +++ b/library/compiler-builtins/src/int/addsub.rs @@ -0,0 +1,122 @@ +use int::LargeInt; +use int::Int; + +trait UAddSub: LargeInt { + fn uadd(self, other: Self) -> Self { + let (low, carry) = self.low().overflowing_add(other.low()); + let high = self.high().wrapping_add(other.high()); + let carry = if carry { Self::HighHalf::ONE } else { Self::HighHalf::ZERO }; + Self::from_parts(low, high.wrapping_add(carry)) + } + fn uadd_one(self) -> Self { + let (low, carry) = self.low().overflowing_add(Self::LowHalf::ONE); + let carry = if carry { Self::HighHalf::ONE } else { Self::HighHalf::ZERO }; + Self::from_parts(low, self.high().wrapping_add(carry)) + } + fn usub(self, other: Self) -> Self { + let uneg = (!other).uadd_one(); + self.uadd(uneg) + } +} + +impl UAddSub for u128 {} + +trait AddSub: Int + where ::UnsignedInt: UAddSub +{ + fn add(self, other: Self) -> Self { + Self::from_unsigned(self.unsigned().uadd(other.unsigned())) + } + fn sub(self, other: Self) -> Self { + Self::from_unsigned(self.unsigned().usub(other.unsigned())) + } +} + +impl AddSub for u128 {} +impl AddSub for i128 {} + +trait Addo: AddSub + where ::UnsignedInt: UAddSub +{ + fn addo(self, other: Self, overflow: &mut i32) -> Self { + *overflow = 0; + let result = AddSub::add(self, other); + if other >= Self::ZERO { + if result < self { + *overflow = 1; + } + } else { + if result >= self { + *overflow = 1; + } + } + result + } +} + +impl Addo for i128 {} +impl Addo for u128 {} + +trait Subo: AddSub + where ::UnsignedInt: UAddSub +{ + fn subo(self, other: Self, overflow: &mut i32) -> Self { + *overflow = 0; + let result = AddSub::sub(self, other); + if other >= Self::ZERO { + if result > self { + *overflow = 1; + } + } else { + if result <= self { + *overflow = 1; + } + } + result + } +} + +impl Subo for i128 {} +impl Subo for u128 {} + +#[cfg_attr(not(stage0), lang = "i128_add")] +pub fn rust_i128_add(a: i128, b: i128) -> i128 { + rust_u128_add(a as _, b as _) as _ +} +#[cfg_attr(not(stage0), lang = "i128_addo")] +pub fn rust_i128_addo(a: i128, b: i128) -> (i128, bool) { + let mut oflow = 0; + let r = a.addo(b, &mut oflow); + (r, oflow != 0) +} +#[cfg_attr(not(stage0), lang = "u128_add")] +pub fn rust_u128_add(a: u128, b: u128) -> u128 { + a.add(b) +} +#[cfg_attr(not(stage0), lang = "u128_addo")] +pub fn rust_u128_addo(a: u128, b: u128) -> (u128, bool) { + let mut oflow = 0; + let r = a.addo(b, &mut oflow); + (r, oflow != 0) +} + +#[cfg_attr(not(stage0), lang = "i128_sub")] +pub fn rust_i128_sub(a: i128, b: i128) -> i128 { + rust_u128_sub(a as _, b as _) as _ +} +#[cfg_attr(not(stage0), lang = "i128_subo")] +pub fn rust_i128_subo(a: i128, b: i128) -> (i128, bool) { + let mut oflow = 0; + let r = a.subo(b, &mut oflow); + (r, oflow != 0) +} +#[cfg_attr(not(stage0), lang = "u128_sub")] +pub fn rust_u128_sub(a: u128, b: u128) -> u128 { + a.sub(b) +} +#[cfg_attr(not(stage0), lang = "u128_subo")] +pub fn rust_u128_subo(a: u128, b: u128) -> (u128, bool) { + let mut oflow = 0; + let r = a.subo(b, &mut oflow); + (r, oflow != 0) +} diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index c5490cba79619..b645b21454004 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -12,11 +12,10 @@ macro_rules! os_ty { } } -pub mod add; +pub mod addsub; pub mod mul; pub mod sdiv; pub mod shift; -pub mod sub; pub mod udiv; /// Trait for some basic operations on integers diff --git a/library/compiler-builtins/src/int/sub.rs b/library/compiler-builtins/src/int/sub.rs deleted file mode 100644 index abcb45a80eed4..0000000000000 --- a/library/compiler-builtins/src/int/sub.rs +++ /dev/null @@ -1,52 +0,0 @@ -use int::LargeInt; - -trait Sub: LargeInt { - fn sub(self, other: Self) -> Self { - let neg_other = (!other).wrapping_add(Self::ONE); - self.wrapping_add(neg_other) - } -} - -impl Sub for i128 {} -impl Sub for u128 {} - -trait Subo: Sub { - fn subo(self, other: Self, overflow: &mut i32) -> Self { - *overflow = 0; - let result = Sub::sub(self, other); - if other >= Self::ZERO { - if result > self { - *overflow = 1; - } - } else { - if result <= self { - *overflow = 1; - } - } - result - } -} - -impl Subo for i128 {} -impl Subo for u128 {} - -#[cfg_attr(not(stage0), lang = "i128_sub")] -pub fn rust_i128_sub(a: i128, b: i128) -> i128 { - rust_u128_sub(a as _, b as _) as _ -} -#[cfg_attr(not(stage0), lang = "i128_subo")] -pub fn rust_i128_subo(a: i128, b: i128) -> (i128, bool) { - let mut oflow = 0; - let r = a.subo(b, &mut oflow); - (r, oflow != 0) -} -#[cfg_attr(not(stage0), lang = "u128_sub")] -pub fn rust_u128_sub(a: u128, b: u128) -> u128 { - a.sub(b) -} -#[cfg_attr(not(stage0), lang = "u128_subo")] -pub fn rust_u128_subo(a: u128, b: u128) -> (u128, bool) { - let mut oflow = 0; - let r = a.subo(b, &mut oflow); - (r, oflow != 0) -} From dd0be676655a3df8654fb94361a568110e52f048 Mon Sep 17 00:00:00 2001 From: Jan Teske Date: Sun, 26 Nov 2017 21:53:57 +0100 Subject: [PATCH 0407/4206] Remove mulsf3.c and muldf3.c from compiler-rt. mulsf3 and muldf3 have Rust implementations since 8970485. Remove the C implementations to avoid conflicts. --- library/compiler-builtins/build.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 753978d234c28..4f8db808c1a3e 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4987,9 +4987,7 @@ mod c { "floatundisf.c", "int_util.c", "muldc3.c", - "muldf3.c", "mulsc3.c", - "mulsf3.c", "mulvdi3.c", "mulvsi3.c", "mulxc3.c", From fe9bd52cc15f4ea8414d39bd6583bceb3ec0908c Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 27 Nov 2017 16:13:22 -0500 Subject: [PATCH 0408/4206] Avoid warning spew ...when the compiler doesn't support '-fomit-frame-pointer' on the target architecture. --- library/compiler-builtins/build.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index e2a63a6cf97b4..5a72126175679 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4453,8 +4453,16 @@ mod c { // compiler-rt's build system already cfg.flag("-fno-builtin"); cfg.flag("-fvisibility=hidden"); - cfg.flag("-fomit-frame-pointer"); cfg.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] + // + // Note that compiler-rt's build system also checks + // + // `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); } From 19a725d772e24a69590513d5f4f3aa93db47ba06 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 8 Dec 2017 08:19:28 -0800 Subject: [PATCH 0409/4206] Fix nightly CI Currently we're getting lots of errors about duplicate lang items so deal with this by `#[cfg_attr]`'ing off the lang item attribute in tests. --- library/compiler-builtins/src/int/addsub.rs | 80 +++++++++++---------- library/compiler-builtins/src/int/mul.rs | 40 ++++++----- library/compiler-builtins/src/int/sdiv.rs | 16 +++-- library/compiler-builtins/src/int/shift.rs | 64 +++++++++-------- library/compiler-builtins/src/int/udiv.rs | 16 +++-- library/compiler-builtins/src/macros.rs | 14 ++++ 6 files changed, 127 insertions(+), 103 deletions(-) diff --git a/library/compiler-builtins/src/int/addsub.rs b/library/compiler-builtins/src/int/addsub.rs index 7564d896df258..50b5d10d2593b 100644 --- a/library/compiler-builtins/src/int/addsub.rs +++ b/library/compiler-builtins/src/int/addsub.rs @@ -79,44 +79,46 @@ trait Subo: AddSub impl Subo for i128 {} impl Subo for u128 {} -#[cfg_attr(not(stage0), lang = "i128_add")] -pub fn rust_i128_add(a: i128, b: i128) -> i128 { - rust_u128_add(a as _, b as _) as _ -} -#[cfg_attr(not(stage0), lang = "i128_addo")] -pub fn rust_i128_addo(a: i128, b: i128) -> (i128, bool) { - let mut oflow = 0; - let r = a.addo(b, &mut oflow); - (r, oflow != 0) -} -#[cfg_attr(not(stage0), lang = "u128_add")] -pub fn rust_u128_add(a: u128, b: u128) -> u128 { - a.add(b) -} -#[cfg_attr(not(stage0), lang = "u128_addo")] -pub fn rust_u128_addo(a: u128, b: u128) -> (u128, bool) { - let mut oflow = 0; - let r = a.addo(b, &mut oflow); - (r, oflow != 0) -} +u128_lang_items! { + #[lang = "i128_add"] + pub fn rust_i128_add(a: i128, b: i128) -> i128 { + rust_u128_add(a as _, b as _) as _ + } + #[lang = "i128_addo"] + pub fn rust_i128_addo(a: i128, b: i128) -> (i128, bool) { + let mut oflow = 0; + let r = a.addo(b, &mut oflow); + (r, oflow != 0) + } + #[lang = "u128_add"] + pub fn rust_u128_add(a: u128, b: u128) -> u128 { + a.add(b) + } + #[lang = "u128_addo"] + pub fn rust_u128_addo(a: u128, b: u128) -> (u128, bool) { + let mut oflow = 0; + let r = a.addo(b, &mut oflow); + (r, oflow != 0) + } -#[cfg_attr(not(stage0), lang = "i128_sub")] -pub fn rust_i128_sub(a: i128, b: i128) -> i128 { - rust_u128_sub(a as _, b as _) as _ -} -#[cfg_attr(not(stage0), lang = "i128_subo")] -pub fn rust_i128_subo(a: i128, b: i128) -> (i128, bool) { - let mut oflow = 0; - let r = a.subo(b, &mut oflow); - (r, oflow != 0) -} -#[cfg_attr(not(stage0), lang = "u128_sub")] -pub fn rust_u128_sub(a: u128, b: u128) -> u128 { - a.sub(b) -} -#[cfg_attr(not(stage0), lang = "u128_subo")] -pub fn rust_u128_subo(a: u128, b: u128) -> (u128, bool) { - let mut oflow = 0; - let r = a.subo(b, &mut oflow); - (r, oflow != 0) + #[lang = "i128_sub"] + pub fn rust_i128_sub(a: i128, b: i128) -> i128 { + rust_u128_sub(a as _, b as _) as _ + } + #[lang = "i128_subo"] + pub fn rust_i128_subo(a: i128, b: i128) -> (i128, bool) { + let mut oflow = 0; + let r = a.subo(b, &mut oflow); + (r, oflow != 0) + } + #[lang = "u128_sub"] + pub fn rust_u128_sub(a: u128, b: u128) -> u128 { + a.sub(b) + } + #[lang = "u128_subo"] + pub fn rust_u128_subo(a: u128, b: u128) -> (u128, bool) { + let mut oflow = 0; + let r = a.subo(b, &mut oflow); + (r, oflow != 0) + } } diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 61c379c7b6885..58ca461b085f1 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -108,23 +108,25 @@ intrinsics! { } } -#[cfg_attr(not(stage0), lang = "i128_mul")] -pub fn rust_i128_mul(a: i128, b: i128) -> i128 { - __multi3(a, b) -} -#[cfg_attr(not(stage0), lang = "i128_mulo")] -pub fn rust_i128_mulo(a: i128, b: i128) -> (i128, bool) { - let mut oflow = 0; - let r = __muloti4(a, b, &mut oflow); - (r, oflow != 0) -} -#[cfg_attr(not(stage0), lang = "u128_mul")] -pub fn rust_u128_mul(a: u128, b: u128) -> u128 { - __multi3(a as _, b as _) as _ -} -#[cfg_attr(not(stage0), lang = "u128_mulo")] -pub fn rust_u128_mulo(a: u128, b: u128) -> (u128, bool) { - let mut oflow = 0; - let r = a.mulo(b, &mut oflow); - (r, oflow != 0) +u128_lang_items! { + #[lang = "i128_mul"] + pub fn rust_i128_mul(a: i128, b: i128) -> i128 { + __multi3(a, b) + } + #[lang = "i128_mulo"] + pub fn rust_i128_mulo(a: i128, b: i128) -> (i128, bool) { + let mut oflow = 0; + let r = __muloti4(a, b, &mut oflow); + (r, oflow != 0) + } + #[lang = "u128_mul"] + pub fn rust_u128_mul(a: u128, b: u128) -> u128 { + __multi3(a as _, b as _) as _ + } + #[lang = "u128_mulo"] + pub fn rust_u128_mulo(a: u128, b: u128) -> (u128, bool) { + let mut oflow = 0; + let r = a.mulo(b, &mut oflow); + (r, oflow != 0) + } } diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 03086646695b8..2f09bd51d91be 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -98,11 +98,13 @@ intrinsics! { } } -#[cfg_attr(not(stage0), lang = "i128_div")] -pub fn rust_i128_div(a: i128, b: i128) -> i128 { - __divti3(a, b) -} -#[cfg_attr(not(stage0), lang = "i128_rem")] -pub fn rust_i128_rem(a: i128, b: i128) -> i128 { - __modti3(a, b) +u128_lang_items! { + #[lang = "i128_div"] + pub fn rust_i128_div(a: i128, b: i128) -> i128 { + __divti3(a, b) + } + #[lang = "i128_rem"] + pub fn rust_i128_rem(a: i128, b: i128) -> i128 { + __modti3(a, b) + } } diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index f8faad829a9ce..959fcb0880fbe 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -96,36 +96,38 @@ intrinsics! { } } -#[cfg_attr(not(stage0), lang = "i128_shl")] -pub fn rust_i128_shl(a: i128, b: u32) -> i128 { - __ashlti3(a as _, b) as _ -} -#[cfg_attr(not(stage0), lang = "i128_shlo")] -pub fn rust_i128_shlo(a: i128, b: u128) -> (i128, bool) { - (rust_i128_shl(a, b as _), b >= 128) -} -#[cfg_attr(not(stage0), lang = "u128_shl")] -pub fn rust_u128_shl(a: u128, b: u32) -> u128 { - __ashlti3(a, b) -} -#[cfg_attr(not(stage0), lang = "u128_shlo")] -pub fn rust_u128_shlo(a: u128, b: u128) -> (u128, bool) { - (rust_u128_shl(a, b as _), b >= 128) -} +u128_lang_items! { + #[lang = "i128_shl"] + pub fn rust_i128_shl(a: i128, b: u32) -> i128 { + __ashlti3(a as _, b) as _ + } + #[lang = "i128_shlo"] + pub fn rust_i128_shlo(a: i128, b: u128) -> (i128, bool) { + (rust_i128_shl(a, b as _), b >= 128) + } + #[lang = "u128_shl"] + pub fn rust_u128_shl(a: u128, b: u32) -> u128 { + __ashlti3(a, b) + } + #[lang = "u128_shlo"] + pub fn rust_u128_shlo(a: u128, b: u128) -> (u128, bool) { + (rust_u128_shl(a, b as _), b >= 128) + } -#[cfg_attr(not(stage0), lang = "i128_shr")] -pub fn rust_i128_shr(a: i128, b: u32) -> i128 { - __ashrti3(a, b) -} -#[cfg_attr(not(stage0), lang = "i128_shro")] -pub fn rust_i128_shro(a: i128, b: u128) -> (i128, bool) { - (rust_i128_shr(a, b as _), b >= 128) -} -#[cfg_attr(not(stage0), lang = "u128_shr")] -pub fn rust_u128_shr(a: u128, b: u32) -> u128 { - __lshrti3(a, b) -} -#[cfg_attr(not(stage0), lang = "u128_shro")] -pub fn rust_u128_shro(a: u128, b: u128) -> (u128, bool) { - (rust_u128_shr(a, b as _), b >= 128) + #[lang = "i128_shr"] + pub fn rust_i128_shr(a: i128, b: u32) -> i128 { + __ashrti3(a, b) + } + #[lang = "i128_shro"] + pub fn rust_i128_shro(a: i128, b: u128) -> (i128, bool) { + (rust_i128_shr(a, b as _), b >= 128) + } + #[lang = "u128_shr"] + pub fn rust_u128_shr(a: u128, b: u32) -> u128 { + __lshrti3(a, b) + } + #[lang = "u128_shro"] + pub fn rust_u128_shro(a: u128, b: u128) -> (u128, bool) { + (rust_u128_shr(a, b as _), b >= 128) + } } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 6c100f3f86d78..1d93e177b5b50 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -270,11 +270,13 @@ intrinsics! { } } -#[cfg_attr(not(stage0), lang = "u128_div")] -pub fn rust_u128_div(a: u128, b: u128) -> u128 { - __udivti3(a, b) -} -#[cfg_attr(not(stage0), lang = "u128_rem")] -pub fn rust_u128_rem(a: u128, b: u128) -> u128 { - __umodti3(a, b) +u128_lang_items! { + #[lang = "u128_div"] + pub fn rust_u128_div(a: u128, b: u128) -> u128 { + __udivti3(a, b) + } + #[lang = "u128_rem"] + pub fn rust_u128_rem(a: u128, b: u128) -> u128 { + __umodti3(a, b) + } } diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 652c9111de681..033f14121a83a 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -280,3 +280,17 @@ pub mod win64_128bit_abi_hack { } } } + +macro_rules! u128_lang_items { + ($( + #[lang = $lang:tt] + pub fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + $($body:tt)* + } + )*) => ($( + #[cfg_attr(not(any(stage0, feature = "gen-tests")), lang = $lang)] + pub fn $name( $($argname: $ty),* ) -> $ret { + $($body)* + } + )*) +} From dd2e94ae5bfc178e2379d80afc0fd24cd4254f5e Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 20 Dec 2017 01:44:48 +0000 Subject: [PATCH 0410/4206] Replace inline asm with function calls in __kuser_cmpxchg and __kuser_memory_barrier --- library/compiler-builtins/src/arm_linux.rs | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/src/arm_linux.rs b/library/compiler-builtins/src/arm_linux.rs index d94996d7399e7..a48a9698f3771 100644 --- a/library/compiler-builtins/src/arm_linux.rs +++ b/library/compiler-builtins/src/arm_linux.rs @@ -4,23 +4,12 @@ use core::mem; // Kernel-provided user-mode helper functions: // https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt unsafe fn __kuser_cmpxchg(oldval: u32, newval: u32, ptr: *mut u32) -> bool { - let out: u32; - // FIXME: we can't use BLX on ARMv4 - asm!("blx ${0}" - : "={r0}" (out) - : "r" (0xffff0fc0u32) - "{r0}" (oldval), - "{r1}" (newval), - "{r2}" (ptr) - : "r3", "r12", "lr", "cc", "memory"); - out == 0 + let f: extern "C" fn (u32, u32, *mut u32) -> u32 = mem::transmute(0xffff0fc0u32); + f(oldval, newval, ptr) == 0 } unsafe fn __kuser_memory_barrier() { - // FIXME: we can't use BLX on ARMv4 - asm!("blx ${0}" - : - : "r" (0xffff0fa0u32) - : "lr", "memory"); + let f: extern "C" fn () = mem::transmute(0xffff0fa0u32); + f(); } // Word-align a pointer From af91189aa7e0631e1d86bbbb15b2f32cc66d9618 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 23 Dec 2017 08:45:25 +0100 Subject: [PATCH 0411/4206] Fix argument order for __sync_val_compare_and_swap --- library/compiler-builtins/src/arm_linux.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/arm_linux.rs b/library/compiler-builtins/src/arm_linux.rs index a48a9698f3771..2291edf9f1462 100644 --- a/library/compiler-builtins/src/arm_linux.rs +++ b/library/compiler-builtins/src/arm_linux.rs @@ -71,7 +71,7 @@ unsafe fn atomic_rmw u32>(ptr: *mut T, f: F) -> u32 { } // Generic atomic compare-exchange operation -unsafe fn atomic_cmpxchg(oldval: u32, newval: u32, ptr: *mut T) -> u32 { +unsafe fn atomic_cmpxchg(ptr: *mut T, oldval: u32, newval: u32) -> u32 { let aligned_ptr = align_ptr(ptr); let (shift, mask) = get_shift_mask(ptr); @@ -99,8 +99,8 @@ macro_rules! atomic_rmw { macro_rules! atomic_cmpxchg { ($name:ident, $ty:ty) => { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - pub unsafe extern "C" fn $name(oldval: $ty, newval: $ty, ptr: *mut $ty) -> $ty { - atomic_cmpxchg(oldval as u32, newval as u32, ptr) as $ty + pub unsafe extern "C" fn $name(ptr: *mut $ty, oldval: $ty, newval: $ty) -> $ty { + atomic_cmpxchg(ptr, oldval as u32, newval as u32) as $ty } } } From 90bd768b2013b095beacc3e813fa0f7d0d43f05c Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Tue, 26 Dec 2017 13:01:02 -0200 Subject: [PATCH 0412/4206] Use kernel user helpers for armv4t Rename armv5te cfg to kernel_user_helpers and enable it for armv4t --- library/compiler-builtins/build.rs | 4 ++-- library/compiler-builtins/src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 9c23c20c96545..996a7c04b0515 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -52,8 +52,8 @@ fn main() { } // Only emit the ARM Linux atomic emulation on pre-ARMv6 architectures. - if llvm_target[0] == "armv5te" { - println!("cargo:rustc-cfg=armv5te") + if llvm_target[0] == "armv4t" || llvm_target[0] == "armv5te" { + println!("cargo:rustc-cfg=kernel_user_helpers") } } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index ff7885bb3f6dd..f815a9cf39375 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -52,7 +52,7 @@ pub mod mem; #[cfg(target_arch = "arm")] pub mod arm; -#[cfg(all(armv5te, target_os = "linux", target_arch = "arm"))] +#[cfg(all(kernel_user_helpers, target_os = "linux", target_arch = "arm"))] pub mod arm_linux; #[cfg(target_arch = "x86")] From 4481a6c4ab4019762eaafbfe549ab3d395e66b35 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 26 Dec 2017 10:14:11 -0800 Subject: [PATCH 0413/4206] Disable incremental + LTO This causes errors in more recent versions of rustc --- library/compiler-builtins/ci/run.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 95dcdfda95927..0bc12816ac9a0 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -115,6 +115,7 @@ RUSTFLAGS="-C debug-assertions=no" \ # TODO(#79) fix the undefined references problem for debug-assertions+lto if [ -z "$DEBUG_LTO_BUILD_DOESNT_WORK" ]; then RUSTFLAGS="-C debug-assertions=no" \ + CARGO_INCREMENTAL=0 \ $cargo rustc --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics -- -C lto fi $cargo rustc --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics --release -- -C lto From dbaa47027e6bb67f57ba4fe40400e39ffadfa097 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 26 Dec 2017 12:20:17 -0800 Subject: [PATCH 0414/4206] Work around japaric/xargo#186 temporarily --- library/compiler-builtins/ci/run.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 0bc12816ac9a0..50413cf9f625c 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -1,5 +1,8 @@ set -ex +# FIXME(japarix/xargo#186) this shouldn't be necessary +export RUST_TARGET_PATH=`pwd` + case $1 in thumb*) cargo=xargo From c329f6ef75005926f862333bdb0c185768810501 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 02:57:42 +0000 Subject: [PATCH 0415/4206] comparesf2/comparedf2 are called on soft-float targets. E.g. take a look at the assembly output for: pub fn comparesf2(a: f32, b: f32) -> bool { a > b } pub fn comparedf2(a: f64, b: f64) -> bool { a > b } which will include calls to __gtsf2 and __gtdf2. --- library/compiler-builtins/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 5606ef4c8463a..533850bb70004 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -133,6 +133,8 @@ features = ["c"] - [ ] arm/unordsf2vfp.S - [x] ashldi3.c - [x] ashrdi3.c +- [ ] comparedf2.c +- [ ] comparesf2.c - [x] divdf3.c - [x] divdi3.c - [x] divmoddi4.c @@ -301,8 +303,6 @@ These builtins are never called by LLVM. - ~~clzti2.c~~ - ~~cmpdi2.c~~ - ~~cmpti2.c~~ -- ~~comparedf2.c~~ -- ~~comparesf2.c~~ - ~~ctzdi2.c~~ - ~~ctzsi2.c~~ - ~~ctzti2.c~~ From 24175dd6cae41821aac6f3c6a2fbe32a4bba160a Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 03:41:14 +0000 Subject: [PATCH 0416/4206] Implement comparesf2/comparedf2 intrinsics. --- library/compiler-builtins/README.md | 4 +- library/compiler-builtins/src/float/cmp.rs | 166 +++++++++++++++++++++ library/compiler-builtins/src/float/mod.rs | 1 + 3 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/src/float/cmp.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 533850bb70004..6123fe40b7ceb 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -133,8 +133,8 @@ features = ["c"] - [ ] arm/unordsf2vfp.S - [x] ashldi3.c - [x] ashrdi3.c -- [ ] comparedf2.c -- [ ] comparesf2.c +- [x] comparedf2.c +- [x] comparesf2.c - [x] divdf3.c - [x] divdi3.c - [x] divmoddi4.c diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs new file mode 100644 index 0000000000000..f10860c3b822d --- /dev/null +++ b/library/compiler-builtins/src/float/cmp.rs @@ -0,0 +1,166 @@ +use int::{Int, CastInto}; +use float::Float; + +#[derive(Clone, Copy)] +enum Result { + Less, + Equal, + Greater, + Unordered +} + +impl Result { + fn to_le_abi(self) -> i32 { + match self { + Result::Less => -1, + Result::Equal => 0, + Result::Greater => 1, + Result::Unordered => 1 + } + } + + fn to_ge_abi(self) -> i32 { + match self { + Result::Less => -1, + Result::Equal => 0, + Result::Greater => 1, + Result::Unordered => -1 + } + } +} + +fn cmp(a: F, b: F) -> Result where + u32: CastInto, + F::Int: CastInto, + i32: CastInto, + F::Int: CastInto, +{ + let one = F::Int::ONE; + let zero = F::Int::ZERO; + + let sign_bit = F::SIGN_MASK as F::Int; + let abs_mask = sign_bit - one; + let exponent_mask = F::EXPONENT_MASK; + let inf_rep = exponent_mask; + + let a_rep = a.repr(); + let b_rep = b.repr(); + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; + + // If either a or b is NaN, they are unordered. + if a_abs > inf_rep || b_abs > inf_rep { + return Result::Unordered + } + + // If a and b are both zeros, they are equal. + if a_abs | b_abs == zero { + return Result::Equal + } + + // If at least one of a and b is positive, we get the same result comparing + // a and b as signed integers as we would with a fp_ting-point compare. + if a_rep & b_rep >= zero { + if a_rep < b_rep { + return Result::Less + } else if a_rep == b_rep { + return Result::Equal + } else { + return Result::Greater + } + } + + // Otherwise, both are negative, so we need to flip the sense of the + // comparison to get the correct result. (This assumes a twos- or ones- + // complement integer representation; if integers are represented in a + // sign-magnitude representation, then this flip is incorrect). + else { + if a_rep > b_rep { + return Result::Less + } else if a_rep == b_rep { + return Result::Equal + } else { + return Result::Greater + } + } +} +fn unord(a: F, b: F) -> bool where + u32: CastInto, + F::Int: CastInto, + i32: CastInto, + F::Int: CastInto, +{ + let one = F::Int::ONE; + + let sign_bit = F::SIGN_MASK as F::Int; + let abs_mask = sign_bit - one; + let exponent_mask = F::EXPONENT_MASK; + let inf_rep = exponent_mask; + + let a_rep = a.repr(); + let b_rep = b.repr(); + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; + + a_abs > inf_rep || b_abs > inf_rep +} + +intrinsics! { + pub extern "C" fn __lesf2(a: f32, b: f32) -> i32 { + cmp(a, b).to_le_abi() + } + + pub extern "C" fn __gesf2(a: f32, b: f32) -> i32 { + cmp(a, b).to_ge_abi() + } + + #[arm_aeabi_alias = fcmpun] + pub extern "C" fn __unordsf2(a: f32, b: f32) -> bool { + unord(a, b) + } + + pub extern "C" fn __eqsf2(a: f32, b: f32) -> bool { + cmp(a, b).to_le_abi() != 0 + } + + pub extern "C" fn __ltsf2(a: f32, b: f32) -> bool { + cmp(a, b).to_le_abi() != 0 + } + + pub extern "C" fn __nesf2(a: f32, b: f32) -> bool { + cmp(a, b).to_le_abi() != 0 + } + + pub extern "C" fn __gtsf2(a: f32, b: f32) -> bool { + cmp(a, b).to_ge_abi() != 0 + } + + pub extern "C" fn __ledf2(a: f64, b: f64) -> i32 { + cmp(a, b).to_le_abi() + } + + pub extern "C" fn __gedf2(a: f64, b: f64) -> i32 { + cmp(a, b).to_ge_abi() + } + + #[arm_aeabi_alias = dcmpun] + pub extern "C" fn __unorddf2(a: f64, b: f64) -> bool { + unord(a, b) + } + + pub extern "C" fn __eqdf2(a: f64, b: f64) -> bool { + cmp(a, b).to_le_abi() != 0 + } + + pub extern "C" fn __ltdf2(a: f64, b: f64) -> bool { + cmp(a, b).to_le_abi() != 0 + } + + pub extern "C" fn __nedf2(a: f64, b: f64) -> bool { + cmp(a, b).to_le_abi() != 0 + } + + pub extern "C" fn __gtdf2(a: f32, b: f32) -> bool { + cmp(a, b).to_ge_abi() != 0 + } +} diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 6daf7b8f75f5f..f13256da4b4e3 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -4,6 +4,7 @@ use core::ops; use super::int::Int; pub mod conv; +pub mod cmp; pub mod add; pub mod pow; pub mod sub; From fee371a365e98279d6008e83b838f0ebff7ac75e Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 29 Dec 2017 06:14:51 +0000 Subject: [PATCH 0417/4206] comparesf2/comparedf2: use i32 instead of bool for return type. Note that this changes semantics: pub extern "C" fn __eqsf2(a: f32, b: f32) -> bool { cmp(a, b).to_le_abi() != 0 } is not the same as pub extern "C" fn __eqsf2(a: f32, b: f32) -> i32 { cmp(a, b).to_le_abi() } However, compiler-rt does the latter, so this is actually an improvement. --- library/compiler-builtins/src/float/cmp.rs | 40 +++++++++++----------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index f10860c3b822d..2434deb895c6c 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -115,24 +115,24 @@ intrinsics! { } #[arm_aeabi_alias = fcmpun] - pub extern "C" fn __unordsf2(a: f32, b: f32) -> bool { - unord(a, b) + pub extern "C" fn __unordsf2(a: f32, b: f32) -> i32 { + unord(a, b) as i32 } - pub extern "C" fn __eqsf2(a: f32, b: f32) -> bool { - cmp(a, b).to_le_abi() != 0 + pub extern "C" fn __eqsf2(a: f32, b: f32) -> i32 { + cmp(a, b).to_le_abi() } - pub extern "C" fn __ltsf2(a: f32, b: f32) -> bool { - cmp(a, b).to_le_abi() != 0 + pub extern "C" fn __ltsf2(a: f32, b: f32) -> i32 { + cmp(a, b).to_le_abi() } - pub extern "C" fn __nesf2(a: f32, b: f32) -> bool { - cmp(a, b).to_le_abi() != 0 + pub extern "C" fn __nesf2(a: f32, b: f32) -> i32 { + cmp(a, b).to_le_abi() } - pub extern "C" fn __gtsf2(a: f32, b: f32) -> bool { - cmp(a, b).to_ge_abi() != 0 + pub extern "C" fn __gtsf2(a: f32, b: f32) -> i32 { + cmp(a, b).to_ge_abi() } pub extern "C" fn __ledf2(a: f64, b: f64) -> i32 { @@ -144,23 +144,23 @@ intrinsics! { } #[arm_aeabi_alias = dcmpun] - pub extern "C" fn __unorddf2(a: f64, b: f64) -> bool { - unord(a, b) + pub extern "C" fn __unorddf2(a: f64, b: f64) -> i32 { + unord(a, b) as i32 } - pub extern "C" fn __eqdf2(a: f64, b: f64) -> bool { - cmp(a, b).to_le_abi() != 0 + pub extern "C" fn __eqdf2(a: f64, b: f64) -> i32 { + cmp(a, b).to_le_abi() } - pub extern "C" fn __ltdf2(a: f64, b: f64) -> bool { - cmp(a, b).to_le_abi() != 0 + pub extern "C" fn __ltdf2(a: f64, b: f64) -> i32 { + cmp(a, b).to_le_abi() } - pub extern "C" fn __nedf2(a: f64, b: f64) -> bool { - cmp(a, b).to_le_abi() != 0 + pub extern "C" fn __nedf2(a: f64, b: f64) -> i32 { + cmp(a, b).to_le_abi() } - pub extern "C" fn __gtdf2(a: f32, b: f32) -> bool { - cmp(a, b).to_ge_abi() != 0 + pub extern "C" fn __gtdf2(a: f32, b: f32) -> i32 { + cmp(a, b).to_ge_abi() } } From a0777758df7bd63040d9f8f4937368c69fd24760 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 29 Dec 2017 06:16:35 +0000 Subject: [PATCH 0418/4206] comparesf2/comparedf2: do not build the C versions of intrinsics. --- library/compiler-builtins/build.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 996a7c04b0515..a71139208f7b1 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4982,8 +4982,6 @@ mod c { "clzdi2.c", "clzsi2.c", "cmpdi2.c", - "comparedf2.c", - "comparesf2.c", "ctzdi2.c", "ctzsi2.c", "divdc3.c", From 45112fc65f00b0d12b4cd5e6c842a3b44caca089 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 29 Dec 2017 06:36:09 +0000 Subject: [PATCH 0419/4206] README: update to explain how to run quickcheck-style tests. --- library/compiler-builtins/README.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 6123fe40b7ceb..a7dabe7b5a79a 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -52,16 +52,20 @@ features = ["c"] ## Contributing 1. Pick one or more intrinsics from the [pending list](#progress). -2. Fork this repository -3. Port the intrinsic(s) and their corresponding [unit tests][1] from their [C implementation][2] to - Rust. -4. Send a Pull Request (PR) -5. Once the PR passes our extensive [testing infrastructure][3], we'll merge it! +2. Fork this repository. +3. Port the intrinsic(s) and their corresponding [unit tests][1] from their + [C implementation][2] to Rust. +4. Implement a [test generator][3] to compare the behavior of the ported intrinsic(s) + with their implementation on the testing host. Note that randomized compiler-builtin tests + should be run using `cargo test --features gen-tests`. +4. Send a Pull Request (PR). +5. Once the PR passes our extensive [testing infrastructure][4], we'll merge it! 6. Celebrate :tada: [1]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/test/builtins/Unit [2]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/lib/builtins -[3]: https://travis-ci.org/rust-lang-nursery/compiler-builtins +[3]: https://github.com/rust-lang-nursery/compiler-builtins/blob/0ba07e49264a54cb5bbd4856fcea083bb3fbec15/build.rs#L180-L265 +[4]: https://travis-ci.org/rust-lang-nursery/compiler-builtins ### Porting Reminders From 566e7ede907e6ca84a858aab9e8bce4c6d67d9a6 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 29 Dec 2017 07:49:45 +0000 Subject: [PATCH 0420/4206] comparesf2/comparedf2: fix a signedness bug and add tests. --- library/compiler-builtins/build.rs | 318 +++++++++++++++++++++ library/compiler-builtins/src/float/cmp.rs | 28 +- library/compiler-builtins/src/float/mod.rs | 16 +- library/compiler-builtins/tests/gedf2.rs | 7 + library/compiler-builtins/tests/gesf2.rs | 7 + library/compiler-builtins/tests/ledf2.rs | 7 + library/compiler-builtins/tests/lesf2.rs | 7 + 7 files changed, 376 insertions(+), 14 deletions(-) create mode 100644 library/compiler-builtins/tests/gedf2.rs create mode 100644 library/compiler-builtins/tests/gesf2.rs create mode 100644 library/compiler-builtins/tests/ledf2.rs create mode 100644 library/compiler-builtins/tests/lesf2.rs diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index a71139208f7b1..0a12a757d61bd 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -89,6 +89,12 @@ mod tests { Adddf3, Addsf3, + // float/cmp.rs + Gedf2, + Gesf2, + Ledf2, + Lesf2, + // float/conv.rs Fixdfdi, Fixdfsi, @@ -2529,6 +2535,318 @@ fn floatuntidf() { } } + #[derive(Eq, Hash, PartialEq)] + pub struct Gedf2 { + a: u64, + b: u64, + c: i32, + } + + impl TestCase for Gedf2 { + fn name() -> &'static str { + "gedf2" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f64(rng); + let b = gen_f64(rng); + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() { + return None; + } + + let c; + if a.is_nan() || b.is_nan() { + c = -1; + } else if a < b { + c = -1; + } else if a > b { + c = 1; + } else { + c = 0; + } + + Some(Gedf2 { a: to_u64(a), b: to_u64(b), c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use std::mem; +use compiler_builtins::float::cmp::__gedf2; + +fn to_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64, u64), i32)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn gedf2() { + for &((a, b), c) in TEST_CASES { + let c_ = __gedf2(to_f64(a), to_f64(b)); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Gesf2 { + a: u32, + b: u32, + c: i32, + } + + impl TestCase for Gesf2 { + fn name() -> &'static str { + "gesf2" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f32(rng); + let b = gen_f32(rng); + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() { + return None; + } + + let c; + if a.is_nan() || b.is_nan() { + c = -1; + } else if a < b { + c = -1; + } else if a > b { + c = 1; + } else { + c = 0; + } + + Some(Gesf2 { a: to_u32(a), b: to_u32(b), c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use std::mem; +use compiler_builtins::float::cmp::__gesf2; + +fn to_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32, u32), i32)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn gesf2() { + for &((a, b), c) in TEST_CASES { + let c_ = __gesf2(to_f32(a), to_f32(b)); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Ledf2 { + a: u64, + b: u64, + c: i32, + } + + impl TestCase for Ledf2 { + fn name() -> &'static str { + "ledf2" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f64(rng); + let b = gen_f64(rng); + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() { + return None; + } + + let c; + if a.is_nan() || b.is_nan() { + c = 1; + } else if a < b { + c = -1; + } else if a > b { + c = 1; + } else { + c = 0; + } + + Some(Ledf2 { a: to_u64(a), b: to_u64(b), c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use std::mem; +use compiler_builtins::float::cmp::__ledf2; + +fn to_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64, u64), i32)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn ledf2() { + for &((a, b), c) in TEST_CASES { + let c_ = __ledf2(to_f64(a), to_f64(b)); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Lesf2 { + a: u32, + b: u32, + c: i32, + } + + impl TestCase for Lesf2 { + fn name() -> &'static str { + "lesf2" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_f32(rng); + let b = gen_f32(rng); + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() { + return None; + } + + let c; + if a.is_nan() || b.is_nan() { + c = 1; + } else if a < b { + c = -1; + } else if a > b { + c = 1; + } else { + c = 0; + } + + Some(Lesf2 { a: to_u32(a), b: to_u32(b), c }) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + " +use std::mem; +use compiler_builtins::float::cmp::__lesf2; + +fn to_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32, u32), i32)] = &[ +" + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn lesf2() { + for &((a, b), c) in TEST_CASES { + let c_ = __lesf2(to_f32(a), to_f32(b)); + assert_eq!(((a, b), c), ((a, b), c_)); + } +} +" + } + } + #[derive(Eq, Hash, PartialEq)] pub struct Moddi3 { a: i64, diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 2434deb895c6c..e884872f1d45a 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -1,3 +1,5 @@ +#![allow(unreachable_code)] + use int::{Int, CastInto}; use float::Float; @@ -35,18 +37,19 @@ fn cmp(a: F, b: F) -> Result where i32: CastInto, F::Int: CastInto, { - let one = F::Int::ONE; - let zero = F::Int::ZERO; + let one = F::Int::ONE; + let zero = F::Int::ZERO; + let szero = F::SignedInt::ZERO; let sign_bit = F::SIGN_MASK as F::Int; let abs_mask = sign_bit - one; let exponent_mask = F::EXPONENT_MASK; let inf_rep = exponent_mask; - let a_rep = a.repr(); - let b_rep = b.repr(); - let a_abs = a_rep & abs_mask; - let b_abs = b_rep & abs_mask; + let a_rep = a.repr(); + let b_rep = b.repr(); + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; // If either a or b is NaN, they are unordered. if a_abs > inf_rep || b_abs > inf_rep { @@ -58,12 +61,15 @@ fn cmp(a: F, b: F) -> Result where return Result::Equal } + let a_srep = a.signed_repr(); + let b_srep = b.signed_repr(); + // If at least one of a and b is positive, we get the same result comparing // a and b as signed integers as we would with a fp_ting-point compare. - if a_rep & b_rep >= zero { - if a_rep < b_rep { + if a_srep & b_srep >= szero { + if a_srep < b_srep { return Result::Less - } else if a_rep == b_rep { + } else if a_srep == b_srep { return Result::Equal } else { return Result::Greater @@ -75,9 +81,9 @@ fn cmp(a: F, b: F) -> Result where // complement integer representation; if integers are represented in a // sign-magnitude representation, then this flip is incorrect). else { - if a_rep > b_rep { + if a_srep > b_srep { return Result::Less - } else if a_rep == b_rep { + } else if a_srep == b_srep { return Result::Equal } else { return Result::Greater diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index f13256da4b4e3..51ed6674d1d03 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -26,6 +26,9 @@ pub trait Float: /// A uint of the same with as the float type Int: Int; + /// A int of the same with as the float + type SignedInt: Int; + const ZERO: Self; const ONE: Self; @@ -59,6 +62,9 @@ pub trait Float: /// Returns `self` transmuted to `Self::Int` fn repr(self) -> Self::Int; + /// Returns `self` transmuted to `Self::SignedInt` + fn signed_repr(self) -> Self::SignedInt; + #[cfg(test)] /// 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 @@ -78,9 +84,10 @@ pub trait Float: // FIXME: Some of this can be removed if RFC Issue #1424 is resolved // https://github.com/rust-lang/rfcs/issues/1424 macro_rules! float_impl { - ($ty:ident, $ity:ident, $bits:expr, $significand_bits:expr) => { + ($ty:ident, $ity:ident, $sity:ident, $bits:expr, $significand_bits:expr) => { impl Float for $ty { type Int = $ity; + type SignedInt = $sity; const ZERO: Self = 0.0; const ONE: Self = 1.0; @@ -95,6 +102,9 @@ macro_rules! float_impl { fn repr(self) -> Self::Int { unsafe { mem::transmute(self) } } + fn signed_repr(self) -> Self::SignedInt { + unsafe { mem::transmute(self) } + } #[cfg(test)] fn eq_repr(self, rhs: Self) -> bool { if self.is_nan() && rhs.is_nan() { @@ -120,5 +130,5 @@ macro_rules! float_impl { } } -float_impl!(f32, u32, 32, 23); -float_impl!(f64, u64, 64, 52); +float_impl!(f32, u32, i32, 32, 23); +float_impl!(f64, u64, i64, 64, 52); diff --git a/library/compiler-builtins/tests/gedf2.rs b/library/compiler-builtins/tests/gedf2.rs new file mode 100644 index 0000000000000..e1bea5953951d --- /dev/null +++ b/library/compiler-builtins/tests/gedf2.rs @@ -0,0 +1,7 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", test), + no_std)] + +include!(concat!(env!("OUT_DIR"), "/gedf2.rs")); diff --git a/library/compiler-builtins/tests/gesf2.rs b/library/compiler-builtins/tests/gesf2.rs new file mode 100644 index 0000000000000..760f5a8f5ade5 --- /dev/null +++ b/library/compiler-builtins/tests/gesf2.rs @@ -0,0 +1,7 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", test), + no_std)] + +include!(concat!(env!("OUT_DIR"), "/gesf2.rs")); diff --git a/library/compiler-builtins/tests/ledf2.rs b/library/compiler-builtins/tests/ledf2.rs new file mode 100644 index 0000000000000..3fac17b0f3613 --- /dev/null +++ b/library/compiler-builtins/tests/ledf2.rs @@ -0,0 +1,7 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", test), + no_std)] + +include!(concat!(env!("OUT_DIR"), "/ledf2.rs")); diff --git a/library/compiler-builtins/tests/lesf2.rs b/library/compiler-builtins/tests/lesf2.rs new file mode 100644 index 0000000000000..878861fec1c55 --- /dev/null +++ b/library/compiler-builtins/tests/lesf2.rs @@ -0,0 +1,7 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", test), + no_std)] + +include!(concat!(env!("OUT_DIR"), "/lesf2.rs")); From 746c4717e15db62a09b5f405a2340ced24d4b862 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 29 Dec 2017 18:07:40 +0000 Subject: [PATCH 0421/4206] comparesf2: do not build the assembly versions of intrinsics on ARM. --- library/compiler-builtins/build.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 0a12a757d61bd..cc3121eea4550 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -5443,7 +5443,6 @@ mod c { "arm/bswapsi2.S", "arm/clzdi2.S", "arm/clzsi2.S", - "arm/comparesf2.S", "arm/divmodsi4.S", "arm/modsi3.S", "arm/switch16.S", From 2754f64c1883d48d09bcc202f507f0cca7b2513f Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Fri, 19 Jan 2018 09:04:57 +0100 Subject: [PATCH 0422/4206] Skip aeabi_cdcmp and aeabi_cfcmp on big-endian targets First of all aeabi_cdcmp and aeabi_cfcmp are never called LLVM. Second are little-endian only, so build fail on big-endian targets. Temporally workaround: exclude these files for big-endian targets. --- library/compiler-builtins/build.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index cc3121eea4550..0b27598bfe05b 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -5430,10 +5430,6 @@ mod c { if target_arch == "arm" && target_os != "ios" { sources.extend( &[ - "arm/aeabi_cdcmp.S", - "arm/aeabi_cdcmpeq_check_nan.c", - "arm/aeabi_cfcmp.S", - "arm/aeabi_cfcmpeq_check_nan.c", "arm/aeabi_dcmp.S", "arm/aeabi_div0.c", "arm/aeabi_drsub.c", @@ -5467,6 +5463,20 @@ mod c { // "arm/udivsi3.S", ], ); + + // First of all aeabi_cdcmp and aeabi_cfcmp are never called LLVM. + // Second are little-endian only, so build fail on big-endian targets. + // Temporally workaround: exclude these files for big-endian targets. + if !llvm_target[0].starts_with("thumbeb") && + !llvm_target[0].starts_with("armeb") { + sources.extend( + &[ + "arm/aeabi_cdcmp.S", + "arm/aeabi_cdcmpeq_check_nan.c", + "arm/aeabi_cfcmp.S", + "arm/aeabi_cfcmpeq_check_nan.c", + ], + ); } if llvm_target[0] == "armv7" { From c68621f444fbf9687d590ee9987d22687dc13cc2 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Fri, 19 Jan 2018 19:27:25 +0100 Subject: [PATCH 0423/4206] Fix build issue and comments Fix an unclosed if block --- library/compiler-builtins/build.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 0b27598bfe05b..cb8f810fee33b 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -5464,7 +5464,7 @@ mod c { ], ); - // First of all aeabi_cdcmp and aeabi_cfcmp are never called LLVM. + // First of all aeabi_cdcmp and aeabi_cfcmp are never called by LLVM. // Second are little-endian only, so build fail on big-endian targets. // Temporally workaround: exclude these files for big-endian targets. if !llvm_target[0].starts_with("thumbeb") && @@ -5477,6 +5477,7 @@ mod c { "arm/aeabi_cfcmpeq_check_nan.c", ], ); + } } if llvm_target[0] == "armv7" { From b75149347268413ec2fe4c4131b7e2f5680af3cd Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 24 Jan 2018 15:20:48 -0800 Subject: [PATCH 0424/4206] Fix some typos/bugs with float comparison intrinsics * I believe `__gtdf2` erroneously used `f32` instead of `f64` * Most of these needed `#[arm_aeabi_alias]` to ensure they're correctly called through the alias * Some existing aliases were corrected with the right names --- library/compiler-builtins/build.rs | 2 - library/compiler-builtins/src/float/cmp.rs | 49 ++++++++++++++++++++-- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index cb8f810fee33b..a7351cc990ed1 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -5430,10 +5430,8 @@ mod c { if target_arch == "arm" && target_os != "ios" { sources.extend( &[ - "arm/aeabi_dcmp.S", "arm/aeabi_div0.c", "arm/aeabi_drsub.c", - "arm/aeabi_fcmp.S", "arm/aeabi_frsub.c", "arm/bswapdi2.S", "arm/bswapsi2.S", diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index e884872f1d45a..e3c584084adc4 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -120,7 +120,7 @@ intrinsics! { cmp(a, b).to_ge_abi() } - #[arm_aeabi_alias = fcmpun] + #[arm_aeabi_alias = __aeabi_fcmpun] pub extern "C" fn __unordsf2(a: f32, b: f32) -> i32 { unord(a, b) as i32 } @@ -149,7 +149,7 @@ intrinsics! { cmp(a, b).to_ge_abi() } - #[arm_aeabi_alias = dcmpun] + #[arm_aeabi_alias = __aeabi_dcmpun] pub extern "C" fn __unorddf2(a: f64, b: f64) -> i32 { unord(a, b) as i32 } @@ -166,7 +166,50 @@ intrinsics! { cmp(a, b).to_le_abi() } - pub extern "C" fn __gtdf2(a: f32, b: f32) -> i32 { + pub extern "C" fn __gtdf2(a: f64, b: f64) -> i32 { cmp(a, b).to_ge_abi() } } + +#[cfg(target_arch = "arm")] +intrinsics! { + pub extern "aapcs" fn __aeabi_fcmple(a: f32, b: f32) -> i32 { + (__lesf2(a, b) < 0) as i32 + } + + pub extern "aapcs" fn __aeabi_fcmpge(a: f32, b: f32) -> i32 { + (__gesf2(a, b) >= 0) as i32 + } + + pub extern "aapcs" fn __aeabi_fcmpeq(a: f32, b: f32) -> i32 { + (__eqsf2(a, b) == 0) as i32 + } + + pub extern "aapcs" fn __aeabi_fcmplt(a: f32, b: f32) -> i32 { + (__ltsf2(a, b) < 0) as i32 + } + + pub extern "aapcs" fn __aeabi_fcmpgt(a: f32, b: f32) -> i32 { + (__gtsf2(a, b) > 0) as i32 + } + + pub extern "aapcs" fn __aeabi_dcmple(a: f64, b: f64) -> i32 { + (__ledf2(a, b) <= 0) as i32 + } + + pub extern "aapcs" fn __aeabi_dcmpge(a: f64, b: f64) -> i32 { + (__gedf2(a, b) >= 0) as i32 + } + + pub extern "aapcs" fn __aeabi_dcmpeq(a: f64, b: f64) -> i32 { + (__eqdf2(a, b) == 0) as i32 + } + + pub extern "aapcs" fn __aeabi_dcmplt(a: f64, b: f64) -> i32 { + (__ltdf2(a, b) < 0) as i32 + } + + pub extern "aapcs" fn __aeabi_dcmpgt(a: f64, b: f64) -> i32 { + (__gtdf2(a, b) > 0) as i32 + } +} From ffd4f4d43d25a79267ee011ae249e328257d076a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 23 Jan 2018 15:23:21 -0800 Subject: [PATCH 0425/4206] Update to release_60 of LLVM's compiler-rt --- library/compiler-builtins/.gitmodules | 2 +- library/compiler-builtins/compiler-rt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index bbdcf701cd615..3ff1154f3e795 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -1,3 +1,3 @@ -[submodule "compiler-rt/compiler-rt-cdylib/compiler-rt"] +[submodule "compiler-rt"] path = compiler-rt url = https://github.com/rust-lang/compiler-rt diff --git a/library/compiler-builtins/compiler-rt b/library/compiler-builtins/compiler-rt index c8a8767c56ad3..dfd960b5f1a17 160000 --- a/library/compiler-builtins/compiler-rt +++ b/library/compiler-builtins/compiler-rt @@ -1 +1 @@ -Subproject commit c8a8767c56ad3d3f4eb45c87b95026936fb9aa35 +Subproject commit dfd960b5f1a1751b22738fa34fd27b583f4618db From 9a4e458b488af6992353e81acb87baaf05481f81 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Mon, 29 Jan 2018 19:52:55 +0100 Subject: [PATCH 0426/4206] Add support for mul[s/d]f3vfp and div[s/d]f3vfp Here using `"C"` the compiler will use `"aapcs"` or `"aapcs-vfp"` depending on target configuration. Of course this translates in a call to `__aeabi_fdiv` / `__aeabi_fmul` on non-HF targets. On `eabi` targets with +vfpv2/vfpv3 LLVM generate: vmov s0, r1 vmov s2, r0 vdiv.f32 s0, s2, s0 vmov r0, s0 bx lr On `eabihf` targets with +vfpv3-d16/d32/f32 +fp-only-sp LLVM generate: vdiv.f32 s0, s0, s1 bx lr That's exactly what We need for [div/mul][s/d]f3vfp.S --- library/compiler-builtins/README.md | 8 ++++---- library/compiler-builtins/build.rs | 4 ---- library/compiler-builtins/src/float/div.rs | 7 +++++++ library/compiler-builtins/src/float/mul.rs | 8 ++++++++ 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index a7dabe7b5a79a..cc4852a446ae1 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -96,9 +96,9 @@ features = ["c"] - [x] arm/aeabi_memset.S - [x] arm/aeabi_uidivmod.S - [x] arm/aeabi_uldivmod.S -- [ ] arm/divdf3vfp.S +- [x] arm/divdf3vfp.S - [ ] arm/divmodsi4.S (generic version is done) -- [ ] arm/divsf3vfp.S +- [x] arm/divsf3vfp.S - [ ] arm/divsi3.S (generic version is done) - [ ] arm/eqdf2vfp.S - [ ] arm/eqsf2vfp.S @@ -120,8 +120,8 @@ features = ["c"] - [ ] arm/ltdf2vfp.S - [ ] arm/ltsf2vfp.S - [ ] arm/modsi3.S (generic version is done) -- [ ] arm/muldf3vfp.S -- [ ] arm/mulsf3vfp.S +- [x] arm/muldf3vfp.S +- [x] arm/mulsf3vfp.S - [ ] arm/nedf2vfp.S - [ ] arm/negdf2vfp.S - [ ] arm/negsf2vfp.S diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index a7351cc990ed1..1bb2b0ffc7b7c 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -5511,8 +5511,6 @@ mod c { &[ "arm/adddf3vfp.S", "arm/addsf3vfp.S", - "arm/divdf3vfp.S", - "arm/divsf3vfp.S", "arm/eqdf2vfp.S", "arm/eqsf2vfp.S", "arm/extendsfdf2vfp.S", @@ -5532,8 +5530,6 @@ mod c { "arm/lesf2vfp.S", "arm/ltdf2vfp.S", "arm/ltsf2vfp.S", - "arm/muldf3vfp.S", - "arm/mulsf3vfp.S", "arm/nedf2vfp.S", "arm/nesf2vfp.S", "arm/restore_vfp_d8_d15_regs.S", diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index e0e287a9ea315..94be4f2a5c9fc 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -454,4 +454,11 @@ intrinsics! { div64(a, b) } + pub extern "C" fn __divsf3vfp(a: f32, b: f32) -> f32 { + a / b + } + + pub extern "C" fn __divdf3vfp(a: f64, b: f64) -> f64 { + a / b + } } diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index 696adeaecb3a3..c5c5403521d70 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -188,4 +188,12 @@ intrinsics! { pub extern "C" fn __muldf3(a: f64, b: f64) -> f64 { mul(a, b) } + + pub extern "C" fn __mulsf3vfp(a: f32, b: f32) -> f32 { + a * b + } + + pub extern "C" fn __muldf3vfp(a: f64, b: f64) -> f64 { + a * b + } } From 298629196536e43006d828af5b2a8e6d0e52dbb9 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Tue, 30 Jan 2018 18:48:20 +0100 Subject: [PATCH 0427/4206] __[mul/div]sf3vfp and __[mul/div]df3vfp only on ARM --- library/compiler-builtins/src/float/div.rs | 2 ++ library/compiler-builtins/src/float/mul.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index 94be4f2a5c9fc..ae12bb3214065 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -454,10 +454,12 @@ intrinsics! { div64(a, b) } + #[cfg(target_arch = "arm")] pub extern "C" fn __divsf3vfp(a: f32, b: f32) -> f32 { a / b } + #[cfg(target_arch = "arm")] pub extern "C" fn __divdf3vfp(a: f64, b: f64) -> f64 { a / b } diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index c5c5403521d70..d014bbc90c047 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -189,10 +189,12 @@ intrinsics! { mul(a, b) } + #[cfg(target_arch = "arm")] pub extern "C" fn __mulsf3vfp(a: f32, b: f32) -> f32 { a * b } + #[cfg(target_arch = "arm")] pub extern "C" fn __muldf3vfp(a: f64, b: f64) -> f64 { a * b } From cc3ea0ab935e00d09e11b72a746c113d7d7799f4 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Tue, 30 Jan 2018 20:15:37 +0100 Subject: [PATCH 0428/4206] Add test cases for Mul[s/d]f3vfp and Div[s/d]f3vfp for ARM targets only --- library/compiler-builtins/build.rs | 339 +++++++++++++++++++ library/compiler-builtins/tests/divdf3vfp.rs | 8 + library/compiler-builtins/tests/divsf3vfp.rs | 8 + library/compiler-builtins/tests/muldf3vfp.rs | 8 + library/compiler-builtins/tests/mulsf3vfp.rs | 8 + 5 files changed, 371 insertions(+) create mode 100644 library/compiler-builtins/tests/divdf3vfp.rs create mode 100644 library/compiler-builtins/tests/divsf3vfp.rs create mode 100644 library/compiler-builtins/tests/muldf3vfp.rs create mode 100644 library/compiler-builtins/tests/mulsf3vfp.rs diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 1bb2b0ffc7b7c..a8407b268d2fc 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -130,10 +130,14 @@ mod tests { // float/mul.rs Mulsf3, Muldf3, + Mulsf3vfp, + Muldf3vfp, // float/div.rs Divsf3, Divdf3, + Divsf3vfp, + Divdf3vfp, // int/addsub.rs AddU128, @@ -4203,6 +4207,171 @@ fn muldf3() { } } + #[derive(Eq, Hash, PartialEq)] + pub struct Mulsf3vfp { + a: u32, // f32 + b: u32, // f32 + c: u32, // f32 + } + + impl TestCase for Mulsf3vfp { + fn name() -> &'static str { + "mulsf3vfp" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_large_f32(rng); + let b = gen_large_f32(rng); + let c = a * b; + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() || c.is_nan() { + return None; + } + + Some( + Mulsf3vfp { + a: to_u32(a), + b: to_u32(b), + c: to_u32(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +use compiler_builtins::float::mul::__mulsf3vfp; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +fn to_u32(x: f32) -> u32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32, u32), u32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn mulsf3vfp() { + for &((a, b), c) in TEST_CASES { + let c_ = __mulsf3vfp(mk_f32(a), mk_f32(b)); + assert_eq!(((a, b), c), ((a, b), to_u32(c_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Muldf3vfp { + a: u64, // f64 + b: u64, // f64 + c: u64, // f64 + } + + impl TestCase for Muldf3vfp { + fn name() -> &'static str { + "muldf3vfp" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_large_f64(rng); + let b = gen_large_f64(rng); + let c = a * b; + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() || c.is_nan() { + return None; + } + + Some( + Muldf3vfp { + a: to_u64(a), + b: to_u64(b), + c: to_u64(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +use compiler_builtins::float::mul::__muldf3vfp; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +fn to_u64(x: f64) -> u64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64, u64), u64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn muldf3vfp() { + for &((a, b), c) in TEST_CASES { + let c_ = __muldf3vfp(mk_f64(a), mk_f64(b)); + assert_eq!(((a, b), c), ((a, b), to_u64(c_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] pub struct Divsf3 { a: u32, // f32 @@ -4384,6 +4553,176 @@ fn divdf3() { } } + #[derive(Eq, Hash, PartialEq)] + pub struct Divsf3vfp { + a: u32, // f32 + b: u32, // f32 + c: u32, // f32 + } + + impl TestCase for Divsf3vfp { + fn name() -> &'static str { + "divsf3vfp" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_large_f32(rng); + let b = gen_large_f32(rng); + if b == 0.0 { + return None; + } + let c = a / b; + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() || c.is_nan()|| c.abs() <= unsafe { mem::transmute(16777215u32) } { + return None; + } + + Some( + Divsf3vfp { + a: to_u32(a), + b: to_u32(b), + c: to_u32(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +use compiler_builtins::float::div::__divsf3vfp; + +fn mk_f32(x: u32) -> f32 { + unsafe { mem::transmute(x) } +} + +fn to_u32(x: f32) -> u32 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u32, u32), u32)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divsf3vfp() { + for &((a, b), c) in TEST_CASES { + let c_ = __divsf3vfp(mk_f32(a), mk_f32(b)); + assert_eq!(((a, b), c), ((a, b), to_u32(c_))); + } +} +" + } + } + + #[derive(Eq, Hash, PartialEq)] + pub struct Divdf3vfp { + a: u64, // f64 + b: u64, // f64 + c: u64, // f64 + } + + impl TestCase for Divdf3vfp { + fn name() -> &'static str { + "divdf3vfp" + } + + fn generate(rng: &mut R) -> Option + where + R: Rng, + Self: Sized, + { + let a = gen_large_f64(rng); + let b = gen_large_f64(rng); + if b == 0.0 { + return None; + } + let c = a / b; + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + if a.is_nan() || b.is_nan() || c.is_nan() + || c.abs() <= unsafe { mem::transmute(4503599627370495u64) } { + return None; + } + + Some( + Divdf3vfp { + a: to_u64(a), + b: to_u64(b), + c: to_u64(c), + }, + ) + } + + fn to_string(&self, buffer: &mut String) { + writeln!( + buffer, + "(({a}, {b}), {c}),", + a = self.a, + b = self.b, + c = self.c + ) + .unwrap(); + } + + fn prologue() -> &'static str { + r#" +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +use core::mem; +use compiler_builtins::float::div::__divdf3vfp; + +fn mk_f64(x: u64) -> f64 { + unsafe { mem::transmute(x) } +} + +fn to_u64(x: f64) -> u64 { + unsafe { mem::transmute(x) } +} + +static TEST_CASES: &[((u64, u64), u64)] = &[ +"# + } + + fn epilogue() -> &'static str { + " +]; + +#[test] +fn divdf3vfp() { + for &((a, b), c) in TEST_CASES { + let c_ = __divdf3vfp(mk_f64(a), mk_f64(b)); + assert_eq!(((a, b), c), ((a, b), to_u64(c_))); + } +} +" + } + } #[derive(Eq, Hash, PartialEq)] pub struct Udivdi3 { diff --git a/library/compiler-builtins/tests/divdf3vfp.rs b/library/compiler-builtins/tests/divdf3vfp.rs new file mode 100644 index 0000000000000..9225a5c30a167 --- /dev/null +++ b/library/compiler-builtins/tests/divdf3vfp.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", test), + no_std)] + +#[cfg(target_arch = "arm")] +include!(concat!(env!("OUT_DIR"), "/divdf3vfp.rs")); diff --git a/library/compiler-builtins/tests/divsf3vfp.rs b/library/compiler-builtins/tests/divsf3vfp.rs new file mode 100644 index 0000000000000..0ecc8fe0c8b26 --- /dev/null +++ b/library/compiler-builtins/tests/divsf3vfp.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", test), + no_std)] + +#[cfg(target_arch = "arm")] +include!(concat!(env!("OUT_DIR"), "/divsf3vfp.rs")); diff --git a/library/compiler-builtins/tests/muldf3vfp.rs b/library/compiler-builtins/tests/muldf3vfp.rs new file mode 100644 index 0000000000000..8a717157fb0cd --- /dev/null +++ b/library/compiler-builtins/tests/muldf3vfp.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", test), + no_std)] + +#[cfg(target_arch = "arm")] +include!(concat!(env!("OUT_DIR"), "/muldf3vfp.rs")); diff --git a/library/compiler-builtins/tests/mulsf3vfp.rs b/library/compiler-builtins/tests/mulsf3vfp.rs new file mode 100644 index 0000000000000..4d7f288970a5a --- /dev/null +++ b/library/compiler-builtins/tests/mulsf3vfp.rs @@ -0,0 +1,8 @@ +#![feature(compiler_builtins_lib)] +#![feature(i128_type)] +#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", test), + no_std)] + +#[cfg(target_arch = "arm")] +include!(concat!(env!("OUT_DIR"), "/mulsf3vfp.rs")); From 4c7de1e315e82e6891156b9ce067188a0f374149 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Tue, 30 Jan 2018 23:10:56 +0100 Subject: [PATCH 0429/4206] Fix build errors on arm*-linux-gnueabi I removed std::mem, but We need it. --- library/compiler-builtins/build.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index a8407b268d2fc..12ed31f5d74f0 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4260,6 +4260,11 @@ fn muldf3() { target_os = "linux", test))] use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; use compiler_builtins::float::mul::__mulsf3vfp; fn mk_f32(x: u32) -> f32 { @@ -4342,6 +4347,11 @@ fn mulsf3vfp() { target_os = "linux", test))] use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; use compiler_builtins::float::mul::__muldf3vfp; fn mk_f64(x: u64) -> f64 { @@ -4609,6 +4619,11 @@ fn divdf3() { target_os = "linux", test))] use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; use compiler_builtins::float::div::__divsf3vfp; fn mk_f32(x: u32) -> f32 { @@ -4695,6 +4710,11 @@ fn divsf3vfp() { target_os = "linux", test))] use core::mem; +#[cfg(not(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test)))] +use std::mem; use compiler_builtins::float::div::__divdf3vfp; fn mk_f64(x: u64) -> f64 { From 4d0ea26a26a22da8f8f49350ffb4a78813a47eb1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 31 Jan 2018 07:26:44 -0800 Subject: [PATCH 0430/4206] Allow thumb failures They've been broken for some time anyway --- library/compiler-builtins/.travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 898a600eb4179..efd0b1738e3e5 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -28,6 +28,11 @@ matrix: - env: TARGET=x86_64-apple-darwin os: osx - env: TARGET=x86_64-unknown-linux-gnu + allow_failures: + - env: TARGET=thumbv6m-linux-eabi + - env: TARGET=thumbv7em-linux-eabi + - env: TARGET=thumbv7em-linux-eabihf + - env: TARGET=thumbv7m-linux-eabi install: - case $TARGET in From 41290fe7282f7f89893df59e72fb0867e1598df7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 31 Jan 2018 10:04:01 -0800 Subject: [PATCH 0431/4206] Simplify how testing is done All tests are moved to a separate crate in this repository to enable features by default. Additionally the test generation is moved to a seprate build script and simplified to reduce the amount of boilerplate needed per test. Overall this should still be testing everything, just in a different location! --- library/compiler-builtins/Cargo.toml | 37 +- library/compiler-builtins/build.rs | 5493 ----------------- library/compiler-builtins/ci/run.sh | 10 +- library/compiler-builtins/src/lib.rs | 9 +- library/compiler-builtins/src/macros.rs | 2 +- .../compiler-builtins/testcrate/Cargo.toml | 25 + library/compiler-builtins/testcrate/build.rs | 914 +++ .../compiler-builtins/testcrate/src/lib.rs | 7 + .../{ => testcrate}/tests/aeabi_memclr.rs | 0 .../{ => testcrate}/tests/aeabi_memcpy.rs | 0 .../{ => testcrate}/tests/aeabi_memset.rs | 0 .../testcrate/tests/generated.rs | 6 + library/compiler-builtins/tests/adddf3.rs | 8 - library/compiler-builtins/tests/addsf3.rs | 8 - library/compiler-builtins/tests/ashldi3.rs | 8 - library/compiler-builtins/tests/ashlti3.rs | 8 - library/compiler-builtins/tests/ashrdi3.rs | 8 - library/compiler-builtins/tests/ashrti3.rs | 8 - library/compiler-builtins/tests/divdf3.rs | 7 - library/compiler-builtins/tests/divdf3vfp.rs | 8 - library/compiler-builtins/tests/divdi3.rs | 8 - library/compiler-builtins/tests/divmoddi4.rs | 8 - library/compiler-builtins/tests/divmodsi4.rs | 8 - library/compiler-builtins/tests/divsf3.rs | 7 - library/compiler-builtins/tests/divsf3vfp.rs | 8 - library/compiler-builtins/tests/divsi3.rs | 8 - library/compiler-builtins/tests/divti3.rs | 10 - library/compiler-builtins/tests/fixdfdi.rs | 8 - library/compiler-builtins/tests/fixdfsi.rs | 8 - library/compiler-builtins/tests/fixdfti.rs | 8 - library/compiler-builtins/tests/fixsfdi.rs | 8 - library/compiler-builtins/tests/fixsfsi.rs | 8 - library/compiler-builtins/tests/fixsfti.rs | 8 - library/compiler-builtins/tests/fixunsdfdi.rs | 8 - library/compiler-builtins/tests/fixunsdfsi.rs | 8 - library/compiler-builtins/tests/fixunsdfti.rs | 8 - library/compiler-builtins/tests/fixunssfdi.rs | 8 - library/compiler-builtins/tests/fixunssfsi.rs | 8 - library/compiler-builtins/tests/fixunssfti.rs | 8 - library/compiler-builtins/tests/floatdidf.rs | 8 - library/compiler-builtins/tests/floatsidf.rs | 8 - library/compiler-builtins/tests/floatsisf.rs | 8 - library/compiler-builtins/tests/floattidf.rs | 9 - library/compiler-builtins/tests/floattisf.rs | 8 - .../compiler-builtins/tests/floatundidf.rs | 8 - .../compiler-builtins/tests/floatunsidf.rs | 8 - .../compiler-builtins/tests/floatunsisf.rs | 8 - .../compiler-builtins/tests/floatuntidf.rs | 8 - .../compiler-builtins/tests/floatuntisf.rs | 8 - library/compiler-builtins/tests/gedf2.rs | 7 - library/compiler-builtins/tests/gesf2.rs | 7 - library/compiler-builtins/tests/i128_add.rs | 8 - library/compiler-builtins/tests/i128_addo.rs | 8 - library/compiler-builtins/tests/i128_sub.rs | 8 - library/compiler-builtins/tests/i128_subo.rs | 8 - library/compiler-builtins/tests/ledf2.rs | 7 - library/compiler-builtins/tests/lesf2.rs | 7 - library/compiler-builtins/tests/lshrdi3.rs | 8 - library/compiler-builtins/tests/lshrti3.rs | 8 - library/compiler-builtins/tests/moddi3.rs | 8 - library/compiler-builtins/tests/modsi3.rs | 8 - library/compiler-builtins/tests/modti3.rs | 10 - library/compiler-builtins/tests/muldf3.rs | 7 - library/compiler-builtins/tests/muldf3vfp.rs | 8 - library/compiler-builtins/tests/muldi3.rs | 8 - library/compiler-builtins/tests/mulodi4.rs | 8 - library/compiler-builtins/tests/mulosi4.rs | 8 - library/compiler-builtins/tests/muloti4.rs | 10 - library/compiler-builtins/tests/mulsf3.rs | 7 - library/compiler-builtins/tests/mulsf3vfp.rs | 8 - library/compiler-builtins/tests/multi3.rs | 8 - library/compiler-builtins/tests/powidf2.rs | 8 - library/compiler-builtins/tests/powisf2.rs | 8 - library/compiler-builtins/tests/subdf3.rs | 8 - library/compiler-builtins/tests/subsf3.rs | 8 - library/compiler-builtins/tests/u128_add.rs | 8 - library/compiler-builtins/tests/u128_addo.rs | 8 - library/compiler-builtins/tests/u128_sub.rs | 8 - library/compiler-builtins/tests/u128_subo.rs | 8 - library/compiler-builtins/tests/udivdi3.rs | 8 - library/compiler-builtins/tests/udivmoddi4.rs | 8 - library/compiler-builtins/tests/udivmodsi4.rs | 8 - library/compiler-builtins/tests/udivmodti4.rs | 10 - library/compiler-builtins/tests/udivsi3.rs | 8 - library/compiler-builtins/tests/udivti3.rs | 10 - library/compiler-builtins/tests/umoddi3.rs | 8 - library/compiler-builtins/tests/umodsi3.rs | 8 - library/compiler-builtins/tests/umodti3.rs | 10 - 88 files changed, 981 insertions(+), 6135 deletions(-) create mode 100644 library/compiler-builtins/testcrate/Cargo.toml create mode 100644 library/compiler-builtins/testcrate/build.rs create mode 100644 library/compiler-builtins/testcrate/src/lib.rs rename library/compiler-builtins/{ => testcrate}/tests/aeabi_memclr.rs (100%) rename library/compiler-builtins/{ => testcrate}/tests/aeabi_memcpy.rs (100%) rename library/compiler-builtins/{ => testcrate}/tests/aeabi_memset.rs (100%) create mode 100644 library/compiler-builtins/testcrate/tests/generated.rs delete mode 100644 library/compiler-builtins/tests/adddf3.rs delete mode 100644 library/compiler-builtins/tests/addsf3.rs delete mode 100644 library/compiler-builtins/tests/ashldi3.rs delete mode 100644 library/compiler-builtins/tests/ashlti3.rs delete mode 100644 library/compiler-builtins/tests/ashrdi3.rs delete mode 100644 library/compiler-builtins/tests/ashrti3.rs delete mode 100644 library/compiler-builtins/tests/divdf3.rs delete mode 100644 library/compiler-builtins/tests/divdf3vfp.rs delete mode 100644 library/compiler-builtins/tests/divdi3.rs delete mode 100644 library/compiler-builtins/tests/divmoddi4.rs delete mode 100644 library/compiler-builtins/tests/divmodsi4.rs delete mode 100644 library/compiler-builtins/tests/divsf3.rs delete mode 100644 library/compiler-builtins/tests/divsf3vfp.rs delete mode 100644 library/compiler-builtins/tests/divsi3.rs delete mode 100644 library/compiler-builtins/tests/divti3.rs delete mode 100644 library/compiler-builtins/tests/fixdfdi.rs delete mode 100644 library/compiler-builtins/tests/fixdfsi.rs delete mode 100644 library/compiler-builtins/tests/fixdfti.rs delete mode 100644 library/compiler-builtins/tests/fixsfdi.rs delete mode 100644 library/compiler-builtins/tests/fixsfsi.rs delete mode 100644 library/compiler-builtins/tests/fixsfti.rs delete mode 100644 library/compiler-builtins/tests/fixunsdfdi.rs delete mode 100644 library/compiler-builtins/tests/fixunsdfsi.rs delete mode 100644 library/compiler-builtins/tests/fixunsdfti.rs delete mode 100644 library/compiler-builtins/tests/fixunssfdi.rs delete mode 100644 library/compiler-builtins/tests/fixunssfsi.rs delete mode 100644 library/compiler-builtins/tests/fixunssfti.rs delete mode 100644 library/compiler-builtins/tests/floatdidf.rs delete mode 100644 library/compiler-builtins/tests/floatsidf.rs delete mode 100644 library/compiler-builtins/tests/floatsisf.rs delete mode 100644 library/compiler-builtins/tests/floattidf.rs delete mode 100644 library/compiler-builtins/tests/floattisf.rs delete mode 100644 library/compiler-builtins/tests/floatundidf.rs delete mode 100644 library/compiler-builtins/tests/floatunsidf.rs delete mode 100644 library/compiler-builtins/tests/floatunsisf.rs delete mode 100644 library/compiler-builtins/tests/floatuntidf.rs delete mode 100644 library/compiler-builtins/tests/floatuntisf.rs delete mode 100644 library/compiler-builtins/tests/gedf2.rs delete mode 100644 library/compiler-builtins/tests/gesf2.rs delete mode 100644 library/compiler-builtins/tests/i128_add.rs delete mode 100644 library/compiler-builtins/tests/i128_addo.rs delete mode 100644 library/compiler-builtins/tests/i128_sub.rs delete mode 100644 library/compiler-builtins/tests/i128_subo.rs delete mode 100644 library/compiler-builtins/tests/ledf2.rs delete mode 100644 library/compiler-builtins/tests/lesf2.rs delete mode 100644 library/compiler-builtins/tests/lshrdi3.rs delete mode 100644 library/compiler-builtins/tests/lshrti3.rs delete mode 100644 library/compiler-builtins/tests/moddi3.rs delete mode 100644 library/compiler-builtins/tests/modsi3.rs delete mode 100644 library/compiler-builtins/tests/modti3.rs delete mode 100644 library/compiler-builtins/tests/muldf3.rs delete mode 100644 library/compiler-builtins/tests/muldf3vfp.rs delete mode 100644 library/compiler-builtins/tests/muldi3.rs delete mode 100644 library/compiler-builtins/tests/mulodi4.rs delete mode 100644 library/compiler-builtins/tests/mulosi4.rs delete mode 100644 library/compiler-builtins/tests/muloti4.rs delete mode 100644 library/compiler-builtins/tests/mulsf3.rs delete mode 100644 library/compiler-builtins/tests/mulsf3vfp.rs delete mode 100644 library/compiler-builtins/tests/multi3.rs delete mode 100644 library/compiler-builtins/tests/powidf2.rs delete mode 100644 library/compiler-builtins/tests/powisf2.rs delete mode 100644 library/compiler-builtins/tests/subdf3.rs delete mode 100644 library/compiler-builtins/tests/subsf3.rs delete mode 100644 library/compiler-builtins/tests/u128_add.rs delete mode 100644 library/compiler-builtins/tests/u128_addo.rs delete mode 100644 library/compiler-builtins/tests/u128_sub.rs delete mode 100644 library/compiler-builtins/tests/u128_subo.rs delete mode 100644 library/compiler-builtins/tests/udivdi3.rs delete mode 100644 library/compiler-builtins/tests/udivmoddi4.rs delete mode 100644 library/compiler-builtins/tests/udivmodsi4.rs delete mode 100644 library/compiler-builtins/tests/udivmodti4.rs delete mode 100644 library/compiler-builtins/tests/udivsi3.rs delete mode 100644 library/compiler-builtins/tests/udivti3.rs delete mode 100644 library/compiler-builtins/tests/umoddi3.rs delete mode 100644 library/compiler-builtins/tests/umodsi3.rs delete mode 100644 library/compiler-builtins/tests/umodti3.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index b7743c2ce06d0..0ebeb17f326f9 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,38 +1,37 @@ [package] authors = ["Jorge Aparicio "] -build = "build.rs" name = "compiler_builtins" version = "0.1.0" -[build-dependencies] -cast = { version = "0.2.2", features = ["x128"], optional = true } -rand = { version = "0.3.15", optional = true } +[lib] +test = false -[build-dependencies.cc] -optional = true -version = "1.0" +[build-dependencies] +cc = { optional = true, version = "1.0" } [features] +default = ["compiler-builtins"] + +# Enable compilation of C code in compiler-rt, filling in some more optimized +# implementations and also filling in unimplemented intrinsics c = ["cc"] + +# Flag this library as the unstable compiler-builtins lib compiler-builtins = [] -default = ["compiler-builtins"] + +# Generate memory-related intrinsics like memcpy mem = [] -mangled-names = [] -# generate tests -# -# Note that this is an internal-only feature used in testing, this should not -# be relied on with crates.io! Enabling this may expose you to breaking -# changes. -gen-tests = ["cast", "rand"] +# Mangle all names so this can be linked in with other versions or other +# compiler-rt implementations. Also used for testing +mangled-names = [] -[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" } +# Don't generate lang items for i128 intrisnics and such +no-lang-items = [] [[example]] name = "intrinsics" required-features = ["c", "compiler-builtins"] [workspace] +members = ["testcrate"] diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 12ed31f5d74f0..8beb1288116e5 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1,5 +1,3 @@ -#![feature(i128_type)] - use std::env; fn main() { @@ -23,10 +21,6 @@ fn main() { // custom targets, which can have arbitrary names. let llvm_target = target.split('-').collect::>(); - // Build test files - #[cfg(feature = "gen-tests")] - tests::generate(); - // 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 @@ -57,5493 +51,6 @@ fn main() { } } -#[cfg(feature = "gen-tests")] -mod tests { - extern crate cast; - extern crate rand; - - use std::collections::HashSet; - use std::fmt::Write; - use std::fs::File; - use std::hash::Hash; - use std::path::PathBuf; - use std::{env, mem}; - - use self::cast::{f32, f64, u32, u64, u128, i32, i64, i128}; - use self::rand::Rng; - - const NTESTS: usize = 10_000; - - macro_rules! test { - ($($intrinsic:ident,)+) => { - $( - mk_file::<$intrinsic>(); - )+ - } - } - - pub fn generate() { - // TODO move to main - test! { - // float/add.rs - Adddf3, - Addsf3, - - // float/cmp.rs - Gedf2, - Gesf2, - Ledf2, - Lesf2, - - // float/conv.rs - Fixdfdi, - Fixdfsi, - Fixsfdi, - Fixsfsi, - Fixsfti, - Fixdfti, - Fixunsdfdi, - Fixunsdfsi, - Fixunssfdi, - Fixunssfsi, - Fixunssfti, - Fixunsdfti, - Floatdidf, - Floatsidf, - Floatsisf, - Floattisf, - Floattidf, - Floatundidf, - Floatunsidf, - Floatunsisf, - Floatuntisf, - Floatuntidf, - - // float/pow.rs - Powidf2, - Powisf2, - - // float/sub.rs - Subdf3, - Subsf3, - - // float/mul.rs - Mulsf3, - Muldf3, - Mulsf3vfp, - Muldf3vfp, - - // float/div.rs - Divsf3, - Divdf3, - Divsf3vfp, - Divdf3vfp, - - // int/addsub.rs - AddU128, - AddI128, - AddoU128, - AddoI128, - SubU128, - SubI128, - SuboU128, - SuboI128, - - // int/mul.rs - Muldi3, - Mulodi4, - Mulosi4, - Muloti4, - Multi3, - - // int/sdiv.rs - Divdi3, - Divmoddi4, - Divmodsi4, - Divsi3, - Divti3, - Moddi3, - Modsi3, - Modti3, - - // int/shift.rs - Ashldi3, - Ashlti3, - Ashrdi3, - Ashrti3, - Lshrdi3, - Lshrti3, - - // int/udiv.rs - Udivdi3, - Udivmoddi4, - Udivmodsi4, - Udivmodti4, - Udivsi3, - Udivti3, - Umoddi3, - Umodsi3, - Umodti3, - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Adddf3 { - a: u64, // f64 - b: u64, // f64 - c: u64, // f64 - } - - impl TestCase for Adddf3 { - fn name() -> &'static str { - "adddf3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f64(rng); - let b = gen_f64(rng); - let c = a + b; - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() || c.is_nan() { - return None; - } - - Some( - Adddf3 { - a: to_u64(a), - b: to_u64(b), - c: to_u64(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::add::__adddf3; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64, u64), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn adddf3() { - for &((a, b), c) in TEST_CASES { - let c_ = __adddf3(mk_f64(a), mk_f64(b)); - assert_eq!(((a, b), c), ((a, b), to_u64(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Addsf3 { - a: u32, // f32 - b: u32, // f32 - c: u32, // f32 - } - - impl TestCase for Addsf3 { - fn name() -> &'static str { - "addsf3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f32(rng); - let b = gen_f32(rng); - let c = a + b; - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() || c.is_nan() { - return None; - } - - Some( - Addsf3 { - a: to_u32(a), - b: to_u32(b), - c: to_u32(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::add::__addsf3; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -fn to_u32(x: f32) -> u32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32, u32), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn addsf3() { - for &((a, b), c) in TEST_CASES { - let c_ = __addsf3(mk_f32(a), mk_f32(b)); - assert_eq!(((a, b), c), ((a, b), to_u32(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct AddU128 { - a: u128, - b: u128, - c: u128, - } - - impl TestCase for AddU128 { - fn name() -> &'static str { - "u128_add" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u128(rng); - let b = gen_u128(rng); - let c = a.wrapping_add(b); - - Some(AddU128 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::addsub::rust_u128_add; - -static TEST_CASES: &[((u128, u128), u128)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn u128_add() { - for &((a, b), c) in TEST_CASES { - let c_ = rust_u128_add(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct AddI128 { - a: i128, - b: i128, - c: i128, - } - - impl TestCase for AddI128 { - fn name() -> &'static str { - "i128_add" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i128(rng); - let b = gen_i128(rng); - let c = a.wrapping_add(b); - - Some(AddI128 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::addsub::rust_i128_add; - -static TEST_CASES: &[((i128, i128), i128)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn i128_add() { - for &((a, b), c) in TEST_CASES { - let c_ = rust_i128_add(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct AddoU128 { - a: u128, - b: u128, - c: u128, - d: bool, - } - - impl TestCase for AddoU128 { - fn name() -> &'static str { - "u128_addo" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u128(rng); - let b = gen_u128(rng); - let (c, d) = a.overflowing_add(b); - - Some(AddoU128 { a, b, c, d }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {d})),", - a = self.a, - b = self.b, - c = self.c, - d = self.d - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::addsub::rust_u128_addo; - -static TEST_CASES: &[((u128, u128), (u128, bool))] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn u128_addo() { - for &((a, b), (c, d)) in TEST_CASES { - let (c_, d_) = rust_u128_addo(a, b); - assert_eq!(((a, b), (c, d)), ((a, b), (c_, d_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct AddoI128 { - a: i128, - b: i128, - c: i128, - d: bool, - } - - impl TestCase for AddoI128 { - fn name() -> &'static str { - "i128_addo" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i128(rng); - let b = gen_i128(rng); - let (c, d) = a.overflowing_add(b); - - Some(AddoI128 { a, b, c, d }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {d})),", - a = self.a, - b = self.b, - c = self.c, - d = self.d - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::addsub::rust_i128_addo; - -static TEST_CASES: &[((i128, i128), (i128, bool))] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn i128_addo() { - for &((a, b), (c, d)) in TEST_CASES { - let (c_, d_) = rust_i128_addo(a, b); - assert_eq!(((a, b), (c, d)), ((a, b), (c_, d_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Ashldi3 { - a: u64, - b: u32, - c: u64, - } - - impl TestCase for Ashldi3 { - fn name() -> &'static str { - "ashldi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u64(rng); - let b = (rng.gen::() % 64) as u32; - let c = a << b; - - Some(Ashldi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::shift::__ashldi3; - -static TEST_CASES: &[((u64, u32), u64)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn ashldi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __ashldi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Ashlti3 { - a: u128, - b: u32, - c: u128, - } - - impl TestCase for Ashlti3 { - fn name() -> &'static str { - "ashlti3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u128(rng); - let b = (rng.gen::() % 128) as u32; - let c = a << b; - - Some(Ashlti3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::shift::__ashlti3; - -static TEST_CASES: &[((u128, u32), u128)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn ashlti3() { - for &((a, b), c) in TEST_CASES { - let c_ = __ashlti3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Ashrdi3 { - a: i64, - b: u32, - c: i64, - } - - impl TestCase for Ashrdi3 { - fn name() -> &'static str { - "ashrdi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i64(rng); - let b = (rng.gen::() % 64) as u32; - let c = a >> b; - - Some(Ashrdi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::shift::__ashrdi3; - -static TEST_CASES: &[((i64, u32), i64)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn ashrdi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __ashrdi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Ashrti3 { - a: i128, - b: u32, - c: i128, - } - - impl TestCase for Ashrti3 { - fn name() -> &'static str { - "ashrti3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i128(rng); - let b = (rng.gen::() % 128) as u32; - let c = a >> b; - - Some(Ashrti3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::shift::__ashrti3; - -static TEST_CASES: &[((i128, u32), i128)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn ashrti3() { - for &((a, b), c) in TEST_CASES { - let c_ = __ashrti3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Divmoddi4 { - a: i64, - b: i64, - c: i64, - rem: i64, - } - - impl TestCase for Divmoddi4 { - fn name() -> &'static str { - "divmoddi4" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i64(rng); - let b = gen_i64(rng); - if b == 0 { - return None; - } - let c = a / b; - let rem = a % b; - - Some(Divmoddi4 { a, b, c, rem }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {rem})),", - a = self.a, - b = self.b, - c = self.c, - rem = self.rem - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__divmoddi4; - -static TEST_CASES: &[((i64, i64), (i64, i64))] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn divmoddi4() { - for &((a, b), (c, rem)) in TEST_CASES { - let mut rem_ = 0; - let c_ = __divmoddi4(a, b, &mut rem_); - assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Divdi3 { - a: i64, - b: i64, - c: i64, - } - - impl TestCase for Divdi3 { - fn name() -> &'static str { - "divdi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i64(rng); - let b = gen_i64(rng); - if b == 0 { - return None; - } - let c = a / b; - - Some(Divdi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__divdi3; - -static TEST_CASES: &[((i64, i64), i64)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn divdi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __divdi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Divmodsi4 { - a: i32, - b: i32, - c: i32, - rem: i32, - } - - impl TestCase for Divmodsi4 { - fn name() -> &'static str { - "divmodsi4" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i32(rng); - let b = gen_i32(rng); - if b == 0 { - return None; - } - let c = a / b; - let rem = a % b; - - Some(Divmodsi4 { a, b, c, rem }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {rem})),", - a = self.a, - b = self.b, - c = self.c, - rem = self.rem - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__divmodsi4; - -static TEST_CASES: &[((i32, i32), (i32, i32))] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn divmodsi4() { - for &((a, b), (c, rem)) in TEST_CASES { - let mut rem_ = 0; - let c_ = __divmodsi4(a, b, &mut rem_); - assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Divsi3 { - a: i32, - b: i32, - c: i32, - } - - impl TestCase for Divsi3 { - fn name() -> &'static str { - "divsi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i32(rng); - let b = gen_i32(rng); - if b == 0 { - return None; - } - let c = a / b; - - Some(Divsi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__divsi3; - -static TEST_CASES: &[((i32, i32), i32)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn divsi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __divsi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Divti3 { - a: i128, - b: i128, - c: i128, - } - - impl TestCase for Divti3 { - fn name() -> &'static str { - "divti3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i128(rng); - let b = gen_i128(rng); - if b == 0 { - return None; - } - let c = a / b; - - Some(Divti3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__divti3; - -static TEST_CASES: &[((i128, i128), i128)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn divti3() { - for &((a, b), c) in TEST_CASES { - let c_ = __divti3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Fixdfdi { - a: u64, // f64 - b: i64, - } - - impl TestCase for Fixdfdi { - fn name() -> &'static str { - "fixdfdi" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f64(rng); - i64(a).ok().map(|b| Fixdfdi { a: to_u64(a), b }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__fixdfdi; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64,), i64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn fixdfdi() { - for &((a,), b) in TEST_CASES { - let b_ = __fixdfdi(mk_f64(a)); - assert_eq!(((a,), b), ((a,), b_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Fixdfsi { - a: u64, // f64 - b: i32, - } - - impl TestCase for Fixdfsi { - fn name() -> &'static str { - "fixdfsi" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f64(rng); - i32(a).ok().map(|b| Fixdfsi { a: to_u64(a), b }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__fixdfsi; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64,), i32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn fixdfdi() { - for &((a,), b) in TEST_CASES { - let b_ = __fixdfsi(mk_f64(a)); - assert_eq!(((a,), b), ((a,), b_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Fixsfdi { - a: u32, // f32 - b: i64, - } - - impl TestCase for Fixsfdi { - fn name() -> &'static str { - "fixsfdi" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f32(rng); - i64(a).ok().map(|b| Fixsfdi { a: to_u32(a), b }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__fixsfdi; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32,), i64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn fixsfdi() { - for &((a,), b) in TEST_CASES { - let b_ = __fixsfdi(mk_f32(a)); - assert_eq!(((a,), b), ((a,), b_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Fixsfsi { - a: u32, // f32 - b: i32, - } - - impl TestCase for Fixsfsi { - fn name() -> &'static str { - "fixsfsi" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f32(rng); - i32(a).ok().map(|b| Fixsfsi { a: to_u32(a), b }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__fixsfsi; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32,), i32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn fixsfsi() { - for &((a,), b) in TEST_CASES { - let b_ = __fixsfsi(mk_f32(a)); - assert_eq!(((a,), b), ((a,), b_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Fixsfti { - a: u32, // f32 - b: i128, - } - - impl TestCase for Fixsfti { - fn name() -> &'static str { - "fixsfti" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f32(rng); - i128(a).ok().map(|b| Fixsfti { a: to_u32(a), b }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__fixsfti; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32,), i128)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn fixsfti() { - for &((a,), b) in TEST_CASES { - let b_ = __fixsfti(mk_f32(a)); - assert_eq!(((a,), b), ((a,), b_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Fixdfti { - a: u64, // f64 - b: i128, - } - - impl TestCase for Fixdfti { - fn name() -> &'static str { - "fixdfti" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f64(rng); - i128(a).ok().map(|b| Fixdfti { a: to_u64(a), b }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__fixdfti; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64,), i128)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn fixdfti() { - for &((a,), b) in TEST_CASES { - let b_ = __fixdfti(mk_f64(a)); - assert_eq!(((a,), b), ((a,), b_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Fixunsdfdi { - a: u64, // f64 - b: u64, - } - - impl TestCase for Fixunsdfdi { - fn name() -> &'static str { - "fixunsdfdi" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f64(rng); - u64(a).ok().map(|b| Fixunsdfdi { a: to_u64(a), b }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__fixunsdfdi; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64,), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn fixunsdfdi() { - for &((a,), b) in TEST_CASES { - let b_ = __fixunsdfdi(mk_f64(a)); - assert_eq!(((a,), b), ((a,), b_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Fixunsdfsi { - a: u64, // f64 - b: u32, - } - - impl TestCase for Fixunsdfsi { - fn name() -> &'static str { - "fixunsdfsi" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f64(rng); - u32(a).ok().map(|b| Fixunsdfsi { a: to_u64(a), b }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__fixunsdfsi; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64,), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn fixunsdfdi() { - for &((a,), b) in TEST_CASES { - let b_ = __fixunsdfsi(mk_f64(a)); - assert_eq!(((a,), b), ((a,), b_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Fixunssfdi { - a: u32, // f32 - b: u64, - } - - impl TestCase for Fixunssfdi { - fn name() -> &'static str { - "fixunssfdi" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f32(rng); - u64(a).ok().map(|b| Fixunssfdi { a: to_u32(a), b }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__fixunssfdi; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32,), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn fixunssfdi() { - for &((a,), b) in TEST_CASES { - let b_ = __fixunssfdi(mk_f32(a)); - assert_eq!(((a,), b), ((a,), b_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Fixunssfsi { - a: u32, // f32 - b: u32, - } - - impl TestCase for Fixunssfsi { - fn name() -> &'static str { - "fixunssfsi" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f32(rng); - u32(a).ok().map(|b| Fixunssfsi { a: to_u32(a), b }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__fixunssfsi; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32,), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn fixunssfsi() { - for &((a,), b) in TEST_CASES { - let b_ = __fixunssfsi(mk_f32(a)); - assert_eq!(((a,), b), ((a,), b_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Fixunssfti { - a: u32, // f32 - b: u128, - } - - impl TestCase for Fixunssfti { - fn name() -> &'static str { - "fixunssfti" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f32(rng); - u128(a).ok().map(|b| Fixunssfti { a: to_u32(a), b }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__fixunssfti; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32,), u128)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn fixunssfti() { - for &((a,), b) in TEST_CASES { - let b_ = __fixunssfti(mk_f32(a)); - assert_eq!(((a,), b), ((a,), b_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Fixunsdfti { - a: u64, // f64 - b: u128, - } - - impl TestCase for Fixunsdfti { - fn name() -> &'static str { - "fixunsdfti" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f64(rng); - u128(a).ok().map(|b| Fixunsdfti { a: to_u64(a), b }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__fixunsdfti; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64,), u128)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn fixunsdfti() { - for &((a,), b) in TEST_CASES { - let b_ = __fixunsdfti(mk_f64(a)); - assert_eq!(((a,), b), ((a,), b_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Floatdidf { - a: i64, - b: u64, // f64 - } - - impl TestCase for Floatdidf { - fn name() -> &'static str { - "floatdidf" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i64(rng); - Some( - Floatdidf { - a, - b: to_u64(f64(a)), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__floatdidf; - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((i64,), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn floatdidf() { - for &((a,), b) in TEST_CASES { - let b_ = __floatdidf(a); - assert_eq!(((a,), b), ((a,), to_u64(b_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Floatsidf { - a: i32, - b: u64, // f64 - } - - impl TestCase for Floatsidf { - fn name() -> &'static str { - "floatsidf" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i32(rng); - Some( - Floatsidf { - a, - b: to_u64(f64(a)), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__floatsidf; - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((i32,), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn floatsidf() { - for &((a,), b) in TEST_CASES { - let b_ = __floatsidf(a); - assert_eq!(((a,), b), ((a,), to_u64(b_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Floatsisf { - a: i32, - b: u32, // f32 - } - - impl TestCase for Floatsisf { - fn name() -> &'static str { - "floatsisf" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i32(rng); - Some( - Floatsisf { - a, - b: to_u32(f32(a)), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__floatsisf; - -fn to_u32(x: f32) -> u32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((i32,), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn floatsisf() { - for &((a,), b) in TEST_CASES { - let b_ = __floatsisf(a); - assert_eq!(((a,), b), ((a,), to_u32(b_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Floattisf { - a: i128, - b: u32, // f32 - } - - impl TestCase for Floattisf { - fn name() -> &'static str { - "floattisf" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i128(rng); - Some( - Floattisf { - a, - b: to_u32(f32(a)), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__floattisf; - -fn to_u32(x: f32) -> u32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((i128,), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn floattisf() { - for &((a,), b) in TEST_CASES { - let b_ = __floattisf(a); - assert_eq!(((a,), b), ((a,), to_u32(b_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Floattidf { - a: i128, - b: u64, // f64 - } - - impl TestCase for Floattidf { - fn name() -> &'static str { - "floattidf" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i128(rng); - Some( - Floattidf { - a, - b: to_u64(f64(a)), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__floattidf; - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((i128,), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn floattidf() { - for &((a,), b) in TEST_CASES { - let b_ = __floattidf(a); - let g_b = to_u64(b_); - let diff = if g_b > b { g_b - b } else { b - g_b }; - assert_eq!(((a,), b, g_b, true), ((a,), b, g_b, diff <= 1)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Floatundidf { - a: u64, - b: u64, // f64 - } - - impl TestCase for Floatundidf { - fn name() -> &'static str { - "floatundidf" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u64(rng); - Some( - Floatundidf { - a, - b: to_u64(f64(a)), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__floatundidf; - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64,), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn floatundidf() { - for &((a,), b) in TEST_CASES { - let b_ = __floatundidf(a); - assert_eq!(((a,), b), ((a,), to_u64(b_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Floatunsidf { - a: u32, - b: u64, // f64 - } - - impl TestCase for Floatunsidf { - fn name() -> &'static str { - "floatunsidf" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u32(rng); - Some( - Floatunsidf { - a, - b: to_u64(f64(a)), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__floatunsidf; - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32,), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn floatunsidf() { - for &((a,), b) in TEST_CASES { - let b_ = __floatunsidf(a); - assert_eq!(((a,), b), ((a,), to_u64(b_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Floatunsisf { - a: u32, - b: u32, // f32 - } - - impl TestCase for Floatunsisf { - fn name() -> &'static str { - "floatunsisf" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u32(rng); - Some( - Floatunsisf { - a, - b: to_u32(f32(a)), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__floatunsisf; - -fn to_u32(x: f32) -> u32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32,), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn floatunsisf() { - for &((a,), b) in TEST_CASES { - let b_ = __floatunsisf(a); - assert_eq!(((a,), b), ((a,), to_u32(b_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Floatuntisf { - a: u128, - b: u32, // f32 - } - - impl TestCase for Floatuntisf { - fn name() -> &'static str { - "floatuntisf" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u128(rng); - let f_a = f32(a); - f_a.ok().map(|f| { - Floatuntisf { - a, - b: to_u32(f), - } - }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__floatuntisf; - -fn to_u32(x: f32) -> u32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u128,), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn floatuntisf() { - for &((a,), b) in TEST_CASES { - let b_ = __floatuntisf(a); - assert_eq!(((a,), b), ((a,), to_u32(b_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Floatuntidf { - a: u128, - b: u64, // f64 - } - - impl TestCase for Floatuntidf { - fn name() -> &'static str { - "floatuntidf" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u128(rng); - Some( - Floatuntidf { - a, - b: to_u64(f64(a)), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::conv::__floatuntidf; - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u128,), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn floatuntidf() { - for &((a,), b) in TEST_CASES { - let b_ = __floatuntidf(a); - let g_b = to_u64(b_); - let diff = if g_b > b { g_b - b } else { b - g_b }; - assert_eq!(((a,), b, g_b, true), ((a,), b, g_b, diff <= 1)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Gedf2 { - a: u64, - b: u64, - c: i32, - } - - impl TestCase for Gedf2 { - fn name() -> &'static str { - "gedf2" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f64(rng); - let b = gen_f64(rng); - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() { - return None; - } - - let c; - if a.is_nan() || b.is_nan() { - c = -1; - } else if a < b { - c = -1; - } else if a > b { - c = 1; - } else { - c = 0; - } - - Some(Gedf2 { a: to_u64(a), b: to_u64(b), c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use std::mem; -use compiler_builtins::float::cmp::__gedf2; - -fn to_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64, u64), i32)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn gedf2() { - for &((a, b), c) in TEST_CASES { - let c_ = __gedf2(to_f64(a), to_f64(b)); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Gesf2 { - a: u32, - b: u32, - c: i32, - } - - impl TestCase for Gesf2 { - fn name() -> &'static str { - "gesf2" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f32(rng); - let b = gen_f32(rng); - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() { - return None; - } - - let c; - if a.is_nan() || b.is_nan() { - c = -1; - } else if a < b { - c = -1; - } else if a > b { - c = 1; - } else { - c = 0; - } - - Some(Gesf2 { a: to_u32(a), b: to_u32(b), c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use std::mem; -use compiler_builtins::float::cmp::__gesf2; - -fn to_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32, u32), i32)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn gesf2() { - for &((a, b), c) in TEST_CASES { - let c_ = __gesf2(to_f32(a), to_f32(b)); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Ledf2 { - a: u64, - b: u64, - c: i32, - } - - impl TestCase for Ledf2 { - fn name() -> &'static str { - "ledf2" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f64(rng); - let b = gen_f64(rng); - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() { - return None; - } - - let c; - if a.is_nan() || b.is_nan() { - c = 1; - } else if a < b { - c = -1; - } else if a > b { - c = 1; - } else { - c = 0; - } - - Some(Ledf2 { a: to_u64(a), b: to_u64(b), c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use std::mem; -use compiler_builtins::float::cmp::__ledf2; - -fn to_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64, u64), i32)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn ledf2() { - for &((a, b), c) in TEST_CASES { - let c_ = __ledf2(to_f64(a), to_f64(b)); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Lesf2 { - a: u32, - b: u32, - c: i32, - } - - impl TestCase for Lesf2 { - fn name() -> &'static str { - "lesf2" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f32(rng); - let b = gen_f32(rng); - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() { - return None; - } - - let c; - if a.is_nan() || b.is_nan() { - c = 1; - } else if a < b { - c = -1; - } else if a > b { - c = 1; - } else { - c = 0; - } - - Some(Lesf2 { a: to_u32(a), b: to_u32(b), c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use std::mem; -use compiler_builtins::float::cmp::__lesf2; - -fn to_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32, u32), i32)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn lesf2() { - for &((a, b), c) in TEST_CASES { - let c_ = __lesf2(to_f32(a), to_f32(b)); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Moddi3 { - a: i64, - b: i64, - c: i64, - } - - impl TestCase for Moddi3 { - fn name() -> &'static str { - "moddi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i64(rng); - let b = gen_i64(rng); - if b == 0 { - return None; - } - let c = a % b; - - Some(Moddi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__moddi3; - -static TEST_CASES: &[((i64, i64), i64)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn moddi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __moddi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Modsi3 { - a: i32, - b: i32, - c: i32, - } - - impl TestCase for Modsi3 { - fn name() -> &'static str { - "modsi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i32(rng); - let b = gen_i32(rng); - if b == 0 { - return None; - } - let c = a % b; - - Some(Modsi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__modsi3; - -static TEST_CASES: &[((i32, i32), i32)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn modsi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __modsi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Modti3 { - a: i128, - b: i128, - c: i128, - } - - impl TestCase for Modti3 { - fn name() -> &'static str { - "modti3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i128(rng); - let b = gen_i128(rng); - if b == 0 { - return None; - } - let c = a % b; - - Some(Modti3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::sdiv::__modti3; - -static TEST_CASES: &[((i128, i128), i128)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn modti3() { - for &((a, b), c) in TEST_CASES { - let c_ = __modti3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - struct Muldi3 { - a: u64, - b: u64, - c: u64, - } - - impl TestCase for Muldi3 { - fn name() -> &'static str { - "muldi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u64(rng); - let b = gen_u64(rng); - let c = a.wrapping_mul(b); - - Some(Muldi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::mul::__muldi3; - -static TEST_CASES: &[((u64, u64), u64)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn muldi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __muldi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Mulodi4 { - a: i64, - b: i64, - c: i64, - overflow: u32, - } - - impl TestCase for Mulodi4 { - fn name() -> &'static str { - "mulodi4" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - { - let a = gen_i64(rng); - let b = gen_i64(rng); - let c = a.wrapping_mul(b); - let overflow = if a.checked_mul(b).is_some() { 0 } else { 1 }; - - Some(Mulodi4 { a, b, c, overflow }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {overflow})),", - a = self.a, - b = self.b, - c = self.c, - overflow = self.overflow - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::mul::__mulodi4; - -static TEST_CASES: &[((i64, i64), (i64, i32))] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn mulodi4() { - let mut overflow_ = 2; - for &((a, b), (c, overflow)) in TEST_CASES { - let c_ = __mulodi4(a, b, &mut overflow_); - assert_eq!(((a, b), (c, overflow)), ((a, b), (c_, overflow_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Mulosi4 { - a: i32, - b: i32, - c: i32, - overflow: u32, - } - - impl TestCase for Mulosi4 { - fn name() -> &'static str { - "mulosi4" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - { - let a = gen_i32(rng); - let b = gen_i32(rng); - let c = a.wrapping_mul(b); - let overflow = if a.checked_mul(b).is_some() { 0 } else { 1 }; - - Some(Mulosi4 { a, b, c, overflow }) - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::mul::__mulosi4; - -static TEST_CASES: &[((i32, i32), (i32, i32))] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn mulosi4() { - let mut overflow_ = 2; - for &((a, b), (c, overflow)) in TEST_CASES { - let c_ = __mulosi4(a, b, &mut overflow_); - assert_eq!(((a, b), (c, overflow)), ((a, b), (c_, overflow_))); - } -} -" - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {overflow})),", - a = self.a, - b = self.b, - c = self.c, - overflow = self.overflow - ) - .unwrap(); - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Muloti4 { - a: i128, - b: i128, - c: i128, - overflow: u32, - } - - impl TestCase for Muloti4 { - fn name() -> &'static str { - "muloti4" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - { - let a = gen_i128(rng); - let b = gen_i128(rng); - let c = a.wrapping_mul(b); - let overflow = if a.checked_mul(b).is_some() { 0 } else { 1 }; - - Some(Muloti4 { a, b, c, overflow }) - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::mul::__muloti4; - -static TEST_CASES: &[((i128, i128), (i128, i32))] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn muloti4() { - let mut overflow_ = 2; - for &((a, b), (c, overflow)) in TEST_CASES { - let c_ = __muloti4(a, b, &mut overflow_); - assert_eq!(((a, b), (c, overflow)), ((a, b), (c_, overflow_))); - } -} -" - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {overflow})),", - a = self.a, - b = self.b, - c = self.c, - overflow = self.overflow - ) - .unwrap(); - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Multi3 { - a: i128, - b: i128, - c: i128, - } - - impl TestCase for Multi3 { - fn name() -> &'static str { - "multi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i128(rng); - let b = gen_i128(rng); - let c = a.wrapping_mul(b); - - Some(Multi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::mul::__multi3; - -static TEST_CASES: &[((i128, i128), i128)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn multi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __multi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Powidf2 { - a: u64, // f64 - b: i32, - c: u64, // f64 - } - - impl TestCase for Powidf2 { - fn name() -> &'static str { - "powidf2" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f64(rng); - let b = gen_i32(rng); - let c = a.powi(b); - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets - if a.is_nan() || c.is_nan() { - return None; - } - - Some( - Powidf2 { - a: to_u64(a), - b, - c: to_u64(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::pow::__powidf2; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64, i32), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn powidf2() { - for &((a, b), c) in TEST_CASES { - let c_ = __powidf2(mk_f64(a), b); - assert_eq!(((a, b), c), ((a, b), to_u64(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Powisf2 { - a: u32, // f32 - b: i32, - c: u32, // f32 - } - - impl TestCase for Powisf2 { - fn name() -> &'static str { - "powisf2" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f32(rng); - let b = gen_i32(rng); - let c = a.powi(b); - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets - if a.is_nan() || c.is_nan() { - return None; - } - - Some( - Powisf2 { - a: to_u32(a), - b, - c: to_u32(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::pow::__powisf2; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -fn to_u32(x: f32) -> u32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32, i32), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn powisf2() { - for &((a, b), c) in TEST_CASES { - let c_ = __powisf2(mk_f32(a), b); - assert_eq!(((a, b), c), ((a, b), to_u32(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Lshrdi3 { - a: u64, - b: u32, - c: u64, - } - - impl TestCase for Lshrdi3 { - fn name() -> &'static str { - "lshrdi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u64(rng); - let b = (rng.gen::() % 64) as u32; - let c = a >> b; - - Some(Lshrdi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::shift::__lshrdi3; - -static TEST_CASES: &[((u64, u32), u64)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn lshrdi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __lshrdi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Lshrti3 { - a: u128, - b: u32, - c: u128, - } - - impl TestCase for Lshrti3 { - fn name() -> &'static str { - "lshrti3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u128(rng); - let b = (rng.gen::() % 128) as u32; - let c = a >> b; - - Some(Lshrti3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::shift::__lshrti3; - -static TEST_CASES: &[((u128, u32), u128)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn lshrti3() { - for &((a, b), c) in TEST_CASES { - let c_ = __lshrti3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Subdf3 { - a: u64, // f64 - b: u64, // f64 - c: u64, // f64 - } - - impl TestCase for Subdf3 { - fn name() -> &'static str { - "subdf3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f64(rng); - let b = gen_f64(rng); - let c = a - b; - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() || c.is_nan() { - return None; - } - - Some( - Subdf3 { - a: to_u64(a), - b: to_u64(b), - c: to_u64(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::sub::__subdf3; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64, u64), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn subdf3() { - for &((a, b), c) in TEST_CASES { - let c_ = __subdf3(mk_f64(a), mk_f64(b)); - assert_eq!(((a, b), c), ((a, b), to_u64(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Subsf3 { - a: u32, // f32 - b: u32, // f32 - c: u32, // f32 - } - - impl TestCase for Subsf3 { - fn name() -> &'static str { - "subsf3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_f32(rng); - let b = gen_f32(rng); - let c = a - b; - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() || c.is_nan() { - return None; - } - - Some( - Subsf3 { - a: to_u32(a), - b: to_u32(b), - c: to_u32(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::sub::__subsf3; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -fn to_u32(x: f32) -> u32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32, u32), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn subsf3() { - for &((a, b), c) in TEST_CASES { - let c_ = __subsf3(mk_f32(a), mk_f32(b)); - assert_eq!(((a, b), c), ((a, b), to_u32(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct SubU128 { - a: u128, - b: u128, - c: u128, - } - - impl TestCase for SubU128 { - fn name() -> &'static str { - "u128_sub" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u128(rng); - let b = gen_u128(rng); - let c = a.wrapping_sub(b); - - Some(SubU128 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::addsub::rust_u128_sub; - -static TEST_CASES: &[((u128, u128), u128)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn u128_sub() { - for &((a, b), c) in TEST_CASES { - let c_ = rust_u128_sub(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct SubI128 { - a: i128, - b: i128, - c: i128, - } - - impl TestCase for SubI128 { - fn name() -> &'static str { - "i128_sub" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i128(rng); - let b = gen_i128(rng); - let c = a.wrapping_sub(b); - - Some(SubI128 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::addsub::rust_i128_sub; - -static TEST_CASES: &[((i128, i128), i128)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn i128_sub() { - for &((a, b), c) in TEST_CASES { - let c_ = rust_i128_sub(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct SuboU128 { - a: u128, - b: u128, - c: u128, - d: bool, - } - - impl TestCase for SuboU128 { - fn name() -> &'static str { - "u128_subo" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u128(rng); - let b = gen_u128(rng); - let (c, d) = a.overflowing_sub(b); - - Some(SuboU128 { a, b, c, d }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {d})),", - a = self.a, - b = self.b, - c = self.c, - d = self.d - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::addsub::rust_u128_subo; - -static TEST_CASES: &[((u128, u128), (u128, bool))] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn u128_subo() { - for &((a, b), (c, d)) in TEST_CASES { - let (c_, d_) = rust_u128_subo(a, b); - assert_eq!(((a, b), (c, d)), ((a, b), (c_, d_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct SuboI128 { - a: i128, - b: i128, - c: i128, - d: bool, - } - - impl TestCase for SuboI128 { - fn name() -> &'static str { - "i128_subo" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_i128(rng); - let b = gen_i128(rng); - let (c, d) = a.overflowing_sub(b); - - Some(SuboI128 { a, b, c, d }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {d})),", - a = self.a, - b = self.b, - c = self.c, - d = self.d - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::addsub::rust_i128_subo; - -static TEST_CASES: &[((i128, i128), (i128, bool))] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn i128_subo() { - for &((a, b), (c, d)) in TEST_CASES { - let (c_, d_) = rust_i128_subo(a, b); - assert_eq!(((a, b), (c, d)), ((a, b), (c_, d_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Mulsf3 { - a: u32, // f32 - b: u32, // f32 - c: u32, // f32 - } - - impl TestCase for Mulsf3 { - fn name() -> &'static str { - "mulsf3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_large_f32(rng); - let b = gen_large_f32(rng); - let c = a * b; - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() || c.is_nan() { - return None; - } - - Some( - Mulsf3 { - a: to_u32(a), - b: to_u32(b), - c: to_u32(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::mul::__mulsf3; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -fn to_u32(x: f32) -> u32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32, u32), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn mulsf3() { - for &((a, b), c) in TEST_CASES { - let c_ = __mulsf3(mk_f32(a), mk_f32(b)); - assert_eq!(((a, b), c), ((a, b), to_u32(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Muldf3 { - a: u64, // f64 - b: u64, // f64 - c: u64, // f64 - } - - impl TestCase for Muldf3 { - fn name() -> &'static str { - "muldf3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_large_f64(rng); - let b = gen_large_f64(rng); - let c = a * b; - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() || c.is_nan() { - return None; - } - - Some( - Muldf3 { - a: to_u64(a), - b: to_u64(b), - c: to_u64(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::mul::__muldf3; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64, u64), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn muldf3() { - for &((a, b), c) in TEST_CASES { - let c_ = __muldf3(mk_f64(a), mk_f64(b)); - assert_eq!(((a, b), c), ((a, b), to_u64(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Mulsf3vfp { - a: u32, // f32 - b: u32, // f32 - c: u32, // f32 - } - - impl TestCase for Mulsf3vfp { - fn name() -> &'static str { - "mulsf3vfp" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_large_f32(rng); - let b = gen_large_f32(rng); - let c = a * b; - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() || c.is_nan() { - return None; - } - - Some( - Mulsf3vfp { - a: to_u32(a), - b: to_u32(b), - c: to_u32(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::mul::__mulsf3vfp; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -fn to_u32(x: f32) -> u32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32, u32), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn mulsf3vfp() { - for &((a, b), c) in TEST_CASES { - let c_ = __mulsf3vfp(mk_f32(a), mk_f32(b)); - assert_eq!(((a, b), c), ((a, b), to_u32(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Muldf3vfp { - a: u64, // f64 - b: u64, // f64 - c: u64, // f64 - } - - impl TestCase for Muldf3vfp { - fn name() -> &'static str { - "muldf3vfp" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_large_f64(rng); - let b = gen_large_f64(rng); - let c = a * b; - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() || c.is_nan() { - return None; - } - - Some( - Muldf3vfp { - a: to_u64(a), - b: to_u64(b), - c: to_u64(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::mul::__muldf3vfp; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64, u64), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn muldf3vfp() { - for &((a, b), c) in TEST_CASES { - let c_ = __muldf3vfp(mk_f64(a), mk_f64(b)); - assert_eq!(((a, b), c), ((a, b), to_u64(c_))); - } -} -" - } - } - - - #[derive(Eq, Hash, PartialEq)] - pub struct Divsf3 { - a: u32, // f32 - b: u32, // f32 - c: u32, // f32 - } - - impl TestCase for Divsf3 { - fn name() -> &'static str { - "divsf3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_large_f32(rng); - let b = gen_large_f32(rng); - if b == 0.0 { - return None; - } - let c = a / b; - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() || c.is_nan()|| c.abs() <= unsafe { mem::transmute(16777215u32) } { - return None; - } - - Some( - Divsf3 { - a: to_u32(a), - b: to_u32(b), - c: to_u32(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::div::__divsf3; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -fn to_u32(x: f32) -> u32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32, u32), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn divsf3() { - for &((a, b), c) in TEST_CASES { - let c_ = __divsf3(mk_f32(a), mk_f32(b)); - assert_eq!(((a, b), c), ((a, b), to_u32(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Divdf3 { - a: u64, // f64 - b: u64, // f64 - c: u64, // f64 - } - - impl TestCase for Divdf3 { - fn name() -> &'static str { - "divdf3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_large_f64(rng); - let b = gen_large_f64(rng); - if b == 0.0 { - return None; - } - let c = a / b; - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() || c.is_nan() - || c.abs() <= unsafe { mem::transmute(4503599627370495u64) } { - return None; - } - - Some( - Divdf3 { - a: to_u64(a), - b: to_u64(b), - c: to_u64(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::div::__divdf3; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64, u64), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn divdf3() { - for &((a, b), c) in TEST_CASES { - let c_ = __divdf3(mk_f64(a), mk_f64(b)); - assert_eq!(((a, b), c), ((a, b), to_u64(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Divsf3vfp { - a: u32, // f32 - b: u32, // f32 - c: u32, // f32 - } - - impl TestCase for Divsf3vfp { - fn name() -> &'static str { - "divsf3vfp" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_large_f32(rng); - let b = gen_large_f32(rng); - if b == 0.0 { - return None; - } - let c = a / b; - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() || c.is_nan()|| c.abs() <= unsafe { mem::transmute(16777215u32) } { - return None; - } - - Some( - Divsf3vfp { - a: to_u32(a), - b: to_u32(b), - c: to_u32(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::div::__divsf3vfp; - -fn mk_f32(x: u32) -> f32 { - unsafe { mem::transmute(x) } -} - -fn to_u32(x: f32) -> u32 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u32, u32), u32)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn divsf3vfp() { - for &((a, b), c) in TEST_CASES { - let c_ = __divsf3vfp(mk_f32(a), mk_f32(b)); - assert_eq!(((a, b), c), ((a, b), to_u32(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Divdf3vfp { - a: u64, // f64 - b: u64, // f64 - c: u64, // f64 - } - - impl TestCase for Divdf3vfp { - fn name() -> &'static str { - "divdf3vfp" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_large_f64(rng); - let b = gen_large_f64(rng); - if b == 0.0 { - return None; - } - let c = a / b; - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - if a.is_nan() || b.is_nan() || c.is_nan() - || c.abs() <= unsafe { mem::transmute(4503599627370495u64) } { - return None; - } - - Some( - Divdf3vfp { - a: to_u64(a), - b: to_u64(b), - c: to_u64(c), - }, - ) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - r#" -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -use core::mem; -#[cfg(not(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test)))] -use std::mem; -use compiler_builtins::float::div::__divdf3vfp; - -fn mk_f64(x: u64) -> f64 { - unsafe { mem::transmute(x) } -} - -fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } -} - -static TEST_CASES: &[((u64, u64), u64)] = &[ -"# - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn divdf3vfp() { - for &((a, b), c) in TEST_CASES { - let c_ = __divdf3vfp(mk_f64(a), mk_f64(b)); - assert_eq!(((a, b), c), ((a, b), to_u64(c_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Udivdi3 { - a: u64, - b: u64, - c: u64, - } - - impl TestCase for Udivdi3 { - fn name() -> &'static str { - "udivdi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u64(rng); - let b = gen_u64(rng); - if b == 0 { - return None; - } - let c = a / b; - - Some(Udivdi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::udiv::__udivdi3; - -static TEST_CASES: &[((u64, u64), u64)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn udivdi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __udivdi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Udivmoddi4 { - a: u64, - b: u64, - c: u64, - rem: u64, - } - - impl TestCase for Udivmoddi4 { - fn name() -> &'static str { - "udivmoddi4" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u64(rng); - let b = gen_u64(rng); - if b == 0 { - return None; - } - let c = a / b; - let rem = a % b; - - Some(Udivmoddi4 { a, b, c, rem }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {rem})),", - a = self.a, - b = self.b, - c = self.c, - rem = self.rem - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::udiv::__udivmoddi4; - -static TEST_CASES: &[((u64, u64), (u64, u64))] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn udivmoddi4() { - for &((a, b), (c, rem)) in TEST_CASES { - let mut rem_ = 0; - let c_ = __udivmoddi4(a, b, Some(&mut rem_)); - assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Udivmodsi4 { - a: u32, - b: u32, - c: u32, - rem: u32, - } - - impl TestCase for Udivmodsi4 { - fn name() -> &'static str { - "udivmodsi4" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u32(rng); - let b = gen_u32(rng); - if b == 0 { - return None; - } - let c = a / b; - let rem = a % b; - - Some(Udivmodsi4 { a, b, c, rem }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {rem})),", - a = self.a, - b = self.b, - c = self.c, - rem = self.rem - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::udiv::__udivmodsi4; - -static TEST_CASES: &[((u32, u32), (u32, u32))] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn udivmodsi4() { - for &((a, b), (c, rem)) in TEST_CASES { - let mut rem_ = 0; - let c_ = __udivmodsi4(a, b, Some(&mut rem_)); - assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Udivmodti4 { - a: u128, - b: u128, - c: u128, - rem: u128, - } - - impl TestCase for Udivmodti4 { - fn name() -> &'static str { - "udivmodti4" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u128(rng); - let b = gen_u128(rng); - if b == 0 { - return None; - } - let c = a / b; - let rem = a % b; - - Some(Udivmodti4 { a, b, c, rem }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), ({c}, {rem})),", - a = self.a, - b = self.b, - c = self.c, - rem = self.rem - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::udiv::__udivmodti4; - -static TEST_CASES: &[((u128, u128), (u128, u128))] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn udivmodti4() { - for &((a, b), (c, rem)) in TEST_CASES { - let mut rem_ = 0; - let c_ = __udivmodti4(a, b, Some(&mut rem_)); - assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Udivsi3 { - a: u32, - b: u32, - c: u32, - } - - impl TestCase for Udivsi3 { - fn name() -> &'static str { - "udivsi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u32(rng); - let b = gen_u32(rng); - if b == 0 { - return None; - } - let c = a / b; - - Some(Udivsi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::udiv::__udivsi3; - -static TEST_CASES: &[((u32, u32), u32)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn udivsi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __udivsi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Udivti3 { - a: u128, - b: u128, - c: u128, - } - - impl TestCase for Udivti3 { - fn name() -> &'static str { - "udivti3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u128(rng); - let b = gen_u128(rng); - if b == 0 { - return None; - } - let c = a / b; - - Some(Udivti3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::udiv::__udivti3; - -static TEST_CASES: &[((u128, u128), u128)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn udivti3() { - for &((a, b), c) in TEST_CASES { - let c_ = __udivti3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Umoddi3 { - a: u64, - b: u64, - c: u64, - } - - impl TestCase for Umoddi3 { - fn name() -> &'static str { - "umoddi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u64(rng); - let b = gen_u64(rng); - if b == 0 { - return None; - } - let c = a % b; - - Some(Umoddi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::udiv::__umoddi3; - -static TEST_CASES: &[((u64, u64), u64)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn umoddi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __umoddi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Umodsi3 { - a: u32, - b: u32, - c: u32, - } - - impl TestCase for Umodsi3 { - fn name() -> &'static str { - "umodsi3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u32(rng); - let b = gen_u32(rng); - if b == 0 { - return None; - } - let c = a % b; - - Some(Umodsi3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::udiv::__umodsi3; - -static TEST_CASES: &[((u32, u32), u32)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn umodsi3() { - for &((a, b), c) in TEST_CASES { - let c_ = __umodsi3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - #[derive(Eq, Hash, PartialEq)] - pub struct Umodti3 { - a: u128, - b: u128, - c: u128, - } - - impl TestCase for Umodti3 { - fn name() -> &'static str { - "umodti3" - } - - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized, - { - let a = gen_u128(rng); - let b = gen_u128(rng); - if b == 0 { - return None; - } - let c = a % b; - - Some(Umodti3 { a, b, c }) - } - - fn to_string(&self, buffer: &mut String) { - writeln!( - buffer, - "(({a}, {b}), {c}),", - a = self.a, - b = self.b, - c = self.c - ) - .unwrap(); - } - - fn prologue() -> &'static str { - " -use compiler_builtins::int::udiv::__umodti3; - -static TEST_CASES: &[((u128, u128), u128)] = &[ -" - } - - fn epilogue() -> &'static str { - " -]; - -#[test] -fn umodti3() { - for &((a, b), c) in TEST_CASES { - let c_ = __umodti3(a, b); - assert_eq!(((a, b), c), ((a, b), c_)); - } -} -" - } - } - - trait TestCase { - /// Name of the intrinsic to test - fn name() -> &'static str; - /// Generates a valid test case - fn generate(rng: &mut R) -> Option - where - R: Rng, - Self: Sized; - /// Stringifies a test case - fn to_string(&self, buffer: &mut String); - /// Prologue of the test file - fn prologue() -> &'static str; - /// Epilogue of the test file - fn epilogue() -> &'static str; - } - - const PROLOGUE: &'static str = r#" -extern crate compiler_builtins; - -// test runner -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -extern crate utest_cortex_m_qemu; - -// overrides `panic!` -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -#[macro_use] -extern crate utest_macros; - -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] -macro_rules! panic { - ($($tt:tt)*) => { - upanic!($($tt)*); - }; -} -"#; - - macro_rules! gen_int { - ($name:ident, $ity:ident, $hty:ident) => { - fn $name(rng: &mut R) -> $ity - where - R: Rng, - { - let mut mk = || if rng.gen_weighted_bool(10) { - *rng.choose(&[::std::$hty::MAX, 0, ::std::$hty::MIN]).unwrap() - } else { - rng.gen::<$hty>() - }; - unsafe { mem::transmute([mk(), mk()]) } - } - - } - } - - gen_int!(gen_i32, i32, i16); - gen_int!(gen_i64, i64, i32); - gen_int!(gen_i128, i128, i64); - - macro_rules! gen_float { - ($name:ident, - $fty:ident, - $uty:ident, - $bits:expr, - $significand_bits:expr) => { - pub fn $name(rng: &mut R) -> $fty - where - R: Rng, - { - const BITS: u8 = $bits; - const SIGNIFICAND_BITS: u8 = $significand_bits; - - const SIGNIFICAND_MASK: $uty = (1 << SIGNIFICAND_BITS) - 1; - const SIGN_MASK: $uty = (1 << (BITS - 1)); - const EXPONENT_MASK: $uty = !(SIGN_MASK | SIGNIFICAND_MASK); - - fn mk_f32(sign: bool, exponent: $uty, significand: $uty) -> $fty { - unsafe { - mem::transmute(((sign as $uty) << (BITS - 1)) | - ((exponent & EXPONENT_MASK) << - SIGNIFICAND_BITS) | - (significand & SIGNIFICAND_MASK)) - } - } - - if rng.gen_weighted_bool(10) { - // Special values - *rng.choose(&[-0.0, - 0.0, - ::std::$fty::NAN, - ::std::$fty::INFINITY, - -::std::$fty::INFINITY]) - .unwrap() - } else if rng.gen_weighted_bool(10) { - // NaN patterns - mk_f32(rng.gen(), rng.gen(), 0) - } else if rng.gen() { - // Denormalized - mk_f32(rng.gen(), 0, rng.gen()) - } else { - // Random anything - mk_f32(rng.gen(), rng.gen(), rng.gen()) - } - } - } - } - - gen_float!(gen_f32, f32, u32, 32, 23); - gen_float!(gen_f64, f64, u64, 64, 52); - - macro_rules! gen_large_float { - ($name:ident, - $fty:ident, - $uty:ident, - $bits:expr, - $significand_bits:expr) => { - pub fn $name(rng: &mut R) -> $fty - where - R: Rng, - { - const BITS: u8 = $bits; - const SIGNIFICAND_BITS: u8 = $significand_bits; - - const SIGNIFICAND_MASK: $uty = (1 << SIGNIFICAND_BITS) - 1; - const SIGN_MASK: $uty = (1 << (BITS - 1)); - const EXPONENT_MASK: $uty = !(SIGN_MASK | SIGNIFICAND_MASK); - - fn mk_f32(sign: bool, exponent: $uty, significand: $uty) -> $fty { - unsafe { - mem::transmute(((sign as $uty) << (BITS - 1)) | - ((exponent & EXPONENT_MASK) << - SIGNIFICAND_BITS) | - (significand & SIGNIFICAND_MASK)) - } - } - - if rng.gen_weighted_bool(10) { - // Special values - *rng.choose(&[-0.0, - 0.0, - ::std::$fty::NAN, - ::std::$fty::INFINITY, - -::std::$fty::INFINITY]) - .unwrap() - } else if rng.gen_weighted_bool(10) { - // NaN patterns - mk_f32(rng.gen(), rng.gen(), 0) - } else if rng.gen() { - // Denormalized - mk_f32(rng.gen(), 0, rng.gen()) - } else { - // Random anything - rng.gen::<$fty>() - } - } - } - } - - gen_large_float!(gen_large_f32, f32, u32, 32, 23); - gen_large_float!(gen_large_f64, f64, u64, 64, 52); - - pub fn gen_u128(rng: &mut R) -> u128 - where - R: Rng, - { - gen_i128(rng) as u128 - } - - pub fn gen_u32(rng: &mut R) -> u32 - where - R: Rng, - { - gen_i32(rng) as u32 - } - - fn gen_u64(rng: &mut R) -> u64 - where - R: Rng, - { - gen_i64(rng) as u64 - } - - pub fn to_u32(x: f32) -> u32 { - unsafe { mem::transmute(x) } - } - - pub fn to_u64(x: f64) -> u64 { - unsafe { mem::transmute(x) } - } - - fn mk_tests(mut n: usize, rng: &mut R) -> String - where - T: Eq + Hash + TestCase, - R: Rng, - { - let mut buffer = PROLOGUE.to_owned(); - buffer.push_str(T::prologue()); - let mut cases = HashSet::new(); - while n != 0 { - if let Some(case) = T::generate(rng) { - if cases.contains(&case) { - continue; - } - case.to_string(&mut buffer); - n -= 1; - cases.insert(case); - } - } - buffer.push_str(T::epilogue()); - buffer - } - - fn mk_file() - where - T: Eq + Hash + TestCase, - { - use std::io::Write; - - let rng = &mut rand::thread_rng(); - let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); - let out_file_name = format!("{}.rs", T::name()); - let out_file = out_dir.join(&out_file_name); - println!("Generating {}", out_file_name); - let contents = mk_tests::(NTESTS, rng); - - File::create(out_file) - .unwrap() - .write_all(contents.as_bytes()) - .unwrap(); - } -} - #[cfg(feature = "c")] mod c { extern crate cc; diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 50413cf9f625c..bc40e2d603c55 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -42,11 +42,11 @@ case $1 in done ;; *) - run="cargo test --no-default-features --target $1" - $run --features 'gen-tests mangled-names' - $run --features 'gen-tests mangled-names' --release - $run --features 'gen-tests mangled-names c' - $run --features 'gen-tests mangled-names c' --release + run="cargo test --manifest-path testcrate/Cargo.toml --target $1" + $run + $run --release + $run --features c + $run --features c --release ;; esac diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index f815a9cf39375..8d8d4a2fee00d 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -12,7 +12,6 @@ #![feature(compiler_builtins)] #![feature(core_intrinsics)] #![feature(naked_functions)] -#![feature(staged_api)] #![feature(i128_type)] #![feature(repr_simd)] #![feature(abi_unadjusted)] @@ -20,9 +19,11 @@ #![feature(lang_items)] #![allow(unused_features)] #![no_builtins] -#![unstable(feature = "compiler_builtins_lib", - reason = "Compiler builtins. Will never become stable.", - issue = "0")] +#![cfg_attr(feature = "compiler-builtins", feature(staged_api))] +#![cfg_attr(feature = "compiler-builtins", + unstable(feature = "compiler_builtins_lib", + reason = "Compiler builtins. Will never become stable.", + issue = "0"))] // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 033f14121a83a..58d94958a437f 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -288,7 +288,7 @@ macro_rules! u128_lang_items { $($body:tt)* } )*) => ($( - #[cfg_attr(not(any(stage0, feature = "gen-tests")), lang = $lang)] + #[cfg_attr(not(any(stage0, feature = "no-lang-items")), lang = $lang)] pub fn $name( $($argname: $ty),* ) -> $ret { $($body)* } diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml new file mode 100644 index 0000000000000..834df68775b3e --- /dev/null +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "testcrate" +version = "0.1.0" +authors = ["Alex Crichton "] + +[lib] +test = false +doctest = false + +[build-dependencies] +cast = { version = "0.2.2", features = ["x128"] } +rand = { version = "0.4", features = ["i128_support"] } + +[dependencies.compiler_builtins] +path = ".." +default-features = false +features = ["mangled-names", "no-lang-items"] + +[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/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs new file mode 100644 index 0000000000000..98a0934c0d909 --- /dev/null +++ b/library/compiler-builtins/testcrate/build.rs @@ -0,0 +1,914 @@ +#![feature(i128_type, i128)] + +extern crate cast; +extern crate rand; + +use std::collections::HashMap; +use std::fmt::Write as FmtWrite; +use std::fs::{self, OpenOptions}; +use std::io::Write; +use std::hash::{Hash, Hasher}; +use std::path::PathBuf; +use std::{env, mem}; +use std::fmt; + +use self::cast::{f32, f64, u32, u64, u128, i32, i64, i128}; +use self::rand::Rng; + +const NTESTS: usize = 1_000; + +fn main() { + let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let out_file = out_dir.join("generated.rs"); + drop(fs::remove_file(&out_file)); + + let target = env::var("TARGET").unwrap(); + let target_arch_arm = + target.contains("arm") || + target.contains("thumb"); + let target_arch_mips = target.contains("mips"); + + // TODO accept NaNs. We don't do that right now because we can't check + // for NaN-ness on the thumb targets (due to missing intrinsics) + + // float/add.rs + gen(|(a, b): (MyF64, MyF64)| { + let c = a.0 + b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::add::__adddf3(a, b)"); + gen(|(a, b): (MyF32, MyF32)| { + let c = a.0 + b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::add::__addsf3(a, b)"); + + // float/cmp.rs + gen(|(a, b): (MyF64, MyF64)| { + let (a, b) = (a.0, b.0); + if a.is_nan() || b.is_nan() { + return None; + } + + if a.is_nan() || b.is_nan() { + Some(-1) + } else if a < b { + Some(-1) + } else if a > b { + Some(1) + } else { + Some(0) + } + }, + "compiler_builtins::float::cmp::__gedf2(a, b)"); + gen(|(a, b): (MyF32, MyF32)| { + let (a, b) = (a.0, b.0); + if a.is_nan() || b.is_nan() { + return None; + } + + if a.is_nan() || b.is_nan() { + Some(-1) + } else if a < b { + Some(-1) + } else if a > b { + Some(1) + } else { + Some(0) + } + }, + "compiler_builtins::float::cmp::__gesf2(a, b)"); + gen(|(a, b): (MyF64, MyF64)| { + let (a, b) = (a.0, b.0); + if a.is_nan() || b.is_nan() { + return None; + } + + if a.is_nan() || b.is_nan() { + Some(1) + } else if a < b { + Some(-1) + } else if a > b { + Some(1) + } else { + Some(0) + } + }, + "compiler_builtins::float::cmp::__ledf2(a, b)"); + gen(|(a, b): (MyF32, MyF32)| { + let (a, b) = (a.0, b.0); + if a.is_nan() || b.is_nan() { + return None; + } + + if a.is_nan() || b.is_nan() { + Some(1) + } else if a < b { + Some(-1) + } else if a > b { + Some(1) + } else { + Some(0) + } + }, + "compiler_builtins::float::cmp::__lesf2(a, b)"); + + // float/conv.rs + gen(|a: MyF64| i64(a.0).ok(), + "compiler_builtins::float::conv::__fixdfdi(a)"); + gen(|a: MyF64| i32(a.0).ok(), + "compiler_builtins::float::conv::__fixdfsi(a)"); + gen(|a: MyF32| i64(a.0).ok(), + "compiler_builtins::float::conv::__fixsfdi(a)"); + gen(|a: MyF32| i32(a.0).ok(), + "compiler_builtins::float::conv::__fixsfsi(a)"); + gen(|a: MyF32| i128(a.0).ok(), + "compiler_builtins::float::conv::__fixsfti(a)"); + gen(|a: MyF64| i128(a.0).ok(), + "compiler_builtins::float::conv::__fixdfti(a)"); + gen(|a: MyF64| u64(a.0).ok(), + "compiler_builtins::float::conv::__fixunsdfdi(a)"); + gen(|a: MyF64| u32(a.0).ok(), + "compiler_builtins::float::conv::__fixunsdfsi(a)"); + gen(|a: MyF32| u64(a.0).ok(), + "compiler_builtins::float::conv::__fixunssfdi(a)"); + gen(|a: MyF32| u32(a.0).ok(), + "compiler_builtins::float::conv::__fixunssfsi(a)"); + gen(|a: MyF32| u128(a.0).ok(), + "compiler_builtins::float::conv::__fixunssfti(a)"); + gen(|a: MyF64| u128(a.0).ok(), + "compiler_builtins::float::conv::__fixunsdfti(a)"); + gen(|a: MyI64| Some(f64(a.0)), + "compiler_builtins::float::conv::__floatdidf(a)"); + gen(|a: MyI32| Some(f64(a.0)), + "compiler_builtins::float::conv::__floatsidf(a)"); + gen(|a: MyI32| Some(f32(a.0)), + "compiler_builtins::float::conv::__floatsisf(a)"); + gen(|a: MyU64| Some(f64(a.0)), + "compiler_builtins::float::conv::__floatundidf(a)"); + gen(|a: MyU32| Some(f64(a.0)), + "compiler_builtins::float::conv::__floatunsidf(a)"); + gen(|a: MyU32| Some(f32(a.0)), + "compiler_builtins::float::conv::__floatunsisf(a)"); + gen(|a: MyU128| f32(a.0).ok(), + "compiler_builtins::float::conv::__floatuntisf(a)"); + if !target_arch_mips { + gen(|a: MyI128| Some(f32(a.0)), + "compiler_builtins::float::conv::__floattisf(a)"); + gen(|a: MyI128| Some(f64(a.0)), + "compiler_builtins::float::conv::__floattidf(a)"); + gen(|a: MyU128| Some(f64(a.0)), + "compiler_builtins::float::conv::__floatuntidf(a)"); + } + + // float/pow.rs + gen(|(a, b): (MyF64, MyI32)| { + let c = a.0.powi(b.0); + if a.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::pow::__powidf2(a, b)"); + gen(|(a, b): (MyF32, MyI32)| { + let c = a.0.powi(b.0); + if a.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::pow::__powisf2(a, b)"); + + // float/sub.rs + gen(|(a, b): (MyF64, MyF64)| { + let c = a.0 - b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::sub::__subdf3(a, b)"); + gen(|(a, b): (MyF32, MyF32)| { + let c = a.0 - b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::sub::__subsf3(a, b)"); + + // float/mul.rs + gen(|(a, b): (MyF64, MyF64)| { + let c = a.0 * b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::mul::__muldf3(a, b)"); + gen(|(a, b): (LargeF32, LargeF32)| { + let c = a.0 * b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::mul::__mulsf3(a, b)"); + + if target_arch_arm { + gen(|(a, b): (MyF64, MyF64)| { + let c = a.0 * b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::mul::__muldf3vfp(a, b)"); + gen(|(a, b): (LargeF32, LargeF32)| { + let c = a.0 * b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::mul::__mulsf3vfp(a, b)"); + } + + // float/div.rs + gen(|(a, b): (MyF64, MyF64)| { + if b.0 == 0.0 { + return None + } + let c = a.0 / b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() || + c.abs() <= unsafe { mem::transmute(4503599627370495u64) } + { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::div::__divdf3(a, b)"); + gen(|(a, b): (LargeF32, LargeF32)| { + if b.0 == 0.0 { + return None + } + let c = a.0 / b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() || + c.abs() <= unsafe { mem::transmute(16777215u32) } + { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::div::__divsf3(a, b)"); + + if target_arch_arm { + gen(|(a, b): (MyF64, MyF64)| { + if b.0 == 0.0 { + return None + } + let c = a.0 / b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() || + c.abs() <= unsafe { mem::transmute(4503599627370495u64) } + { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::div::__divdf3vfp(a, b)"); + gen(|(a, b): (LargeF32, LargeF32)| { + if b.0 == 0.0 { + return None + } + let c = a.0 / b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() || + c.abs() <= unsafe { mem::transmute(16777215u32) } + { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::div::__divsf3vfp(a, b)"); + } + + // int/addsub.rs + gen(|(a, b): (MyU128, MyU128)| Some(a.0.wrapping_add(b.0)), + "compiler_builtins::int::addsub::rust_u128_add(a, b)"); + gen(|(a, b): (MyI128, MyI128)| Some(a.0.wrapping_add(b.0)), + "compiler_builtins::int::addsub::rust_i128_add(a, b)"); + gen(|(a, b): (MyU128, MyU128)| Some(a.0.overflowing_add(b.0)), + "compiler_builtins::int::addsub::rust_u128_addo(a, b)"); + gen(|(a, b): (MyI128, MyI128)| Some(a.0.overflowing_add(b.0)), + "compiler_builtins::int::addsub::rust_i128_addo(a, b)"); + gen(|(a, b): (MyU128, MyU128)| Some(a.0.wrapping_sub(b.0)), + "compiler_builtins::int::addsub::rust_u128_sub(a, b)"); + gen(|(a, b): (MyI128, MyI128)| Some(a.0.wrapping_sub(b.0)), + "compiler_builtins::int::addsub::rust_i128_sub(a, b)"); + gen(|(a, b): (MyU128, MyU128)| Some(a.0.overflowing_sub(b.0)), + "compiler_builtins::int::addsub::rust_u128_subo(a, b)"); + gen(|(a, b): (MyI128, MyI128)| Some(a.0.overflowing_sub(b.0)), + "compiler_builtins::int::addsub::rust_i128_subo(a, b)"); + + // int/mul.rs + gen(|(a, b): (MyU64, MyU64)| Some(a.0.wrapping_mul(b.0)), + "compiler_builtins::int::mul::__muldi3(a, b)"); + gen(|(a, b): (MyI64, MyI64)| Some(a.0.overflowing_mul(b.0)), + "{ + let mut o = 2; + let c = compiler_builtins::int::mul::__mulodi4(a, b, &mut o); + (c, match o { 0 => false, 1 => true, _ => panic!() }) + }"); + gen(|(a, b): (MyI32, MyI32)| Some(a.0.overflowing_mul(b.0)), + "{ + let mut o = 2; + let c = compiler_builtins::int::mul::__mulosi4(a, b, &mut o); + (c, match o { 0 => false, 1 => true, _ => panic!() }) + }"); + gen(|(a, b): (MyI128, MyI128)| Some(a.0.wrapping_mul(b.0)), + "compiler_builtins::int::mul::__multi3(a, b)"); + if !target_arch_mips { // FIXME(#137) + gen(|(a, b): (MyI128, MyI128)| Some(a.0.overflowing_mul(b.0)), + "{ + let mut o = 2; + let c = compiler_builtins::int::mul::__muloti4(a, b, &mut o); + (c, match o { 0 => false, 1 => true, _ => panic!() }) + }"); + } + + // int/sdiv.rs + gen(|(a, b): (MyI64, MyI64)| { + if b.0 == 0 { + None + } else { + Some(a.0 / b.0) + } + }, + "compiler_builtins::int::sdiv::__divdi3(a, b)"); + gen(|(a, b): (MyI64, MyI64)| { + if b.0 == 0 { + None + } else { + Some((a.0 / b.0, a.0 % b.0)) + } + }, + "{ + let mut r = 0; + (compiler_builtins::int::sdiv::__divmoddi4(a, b, &mut r), r) + }"); + gen(|(a, b): (MyI32, MyI32)| { + if b.0 == 0 { + None + } else { + Some((a.0 / b.0, a.0 % b.0)) + } + }, + "{ + let mut r = 0; + (compiler_builtins::int::sdiv::__divmodsi4(a, b, &mut r), r) + }"); + gen(|(a, b): (MyI32, MyI32)| { + if b.0 == 0 { + None + } else { + Some(a.0 / b.0) + } + }, + "compiler_builtins::int::sdiv::__divsi3(a, b)"); + gen(|(a, b): (MyI32, MyI32)| { + if b.0 == 0 { + None + } else { + Some(a.0 % b.0) + } + }, + "compiler_builtins::int::sdiv::__modsi3(a, b)"); + gen(|(a, b): (MyI64, MyI64)| { + if b.0 == 0 { + None + } else { + Some(a.0 % b.0) + } + }, + "compiler_builtins::int::sdiv::__moddi3(a, b)"); + if !target_arch_mips { // FIXME(#137) + gen(|(a, b): (MyI128, MyI128)| { + if b.0 == 0 { + None + } else { + Some(a.0 / b.0) + } + }, + "compiler_builtins::int::sdiv::__divti3(a, b)"); + gen(|(a, b): (MyI128, MyI128)| { + if b.0 == 0 { + None + } else { + Some(a.0 % b.0) + } + }, + "compiler_builtins::int::sdiv::__modti3(a, b)"); + } + + // int/shift.rs + gen(|(a, b): (MyU64, MyU32)| Some(a.0 << (b.0 % 64)), + "compiler_builtins::int::shift::__ashldi3(a, b % 64)"); + gen(|(a, b): (MyU128, MyU32)| Some(a.0 << (b.0 % 128)), + "compiler_builtins::int::shift::__ashlti3(a, b % 128)"); + gen(|(a, b): (MyI64, MyU32)| Some(a.0 >> (b.0 % 64)), + "compiler_builtins::int::shift::__ashrdi3(a, b % 64)"); + gen(|(a, b): (MyI128, MyU32)| Some(a.0 >> (b.0 % 128)), + "compiler_builtins::int::shift::__ashrti3(a, b % 128)"); + gen(|(a, b): (MyU64, MyU32)| Some(a.0 >> (b.0 % 64)), + "compiler_builtins::int::shift::__lshrdi3(a, b % 64)"); + gen(|(a, b): (MyU128, MyU32)| Some(a.0 >> (b.0 % 128)), + "compiler_builtins::int::shift::__lshrti3(a, b % 128)"); + + // int/udiv.rs + gen(|(a, b): (MyU64, MyU64)| { + if b.0 == 0 { + None + } else { + Some(a.0 / b.0) + } + }, + "compiler_builtins::int::udiv::__udivdi3(a, b)"); + gen(|(a, b): (MyU64, MyU64)| { + if b.0 == 0 { + None + } else { + Some((a.0 / b.0, a.0 % b.0)) + } + }, + "{ + let mut r = 0; + (compiler_builtins::int::udiv::__udivmoddi4(a, b, Some(&mut r)), r) + }"); + gen(|(a, b): (MyU32, MyU32)| { + if b.0 == 0 { + None + } else { + Some((a.0 / b.0, a.0 % b.0)) + } + }, + "{ + let mut r = 0; + (compiler_builtins::int::udiv::__udivmodsi4(a, b, Some(&mut r)), r) + }"); + gen(|(a, b): (MyU32, MyU32)| { + if b.0 == 0 { + None + } else { + Some(a.0 / b.0) + } + }, + "compiler_builtins::int::udiv::__udivsi3(a, b)"); + gen(|(a, b): (MyU32, MyU32)| { + if b.0 == 0 { + None + } else { + Some(a.0 % b.0) + } + }, + "compiler_builtins::int::udiv::__umodsi3(a, b)"); + gen(|(a, b): (MyU64, MyU64)| { + if b.0 == 0 { + None + } else { + Some(a.0 % b.0) + } + }, + "compiler_builtins::int::udiv::__umoddi3(a, b)"); + if !target_arch_mips { // FIXME(#137) + gen(|(a, b): (MyU128, MyU128)| { + if b.0 == 0 { + None + } else { + Some(a.0 / b.0) + } + }, + "compiler_builtins::int::udiv::__udivti3(a, b)"); + gen(|(a, b): (MyU128, MyU128)| { + if b.0 == 0 { + None + } else { + Some(a.0 % b.0) + } + }, + "compiler_builtins::int::udiv::__umodti3(a, b)"); + gen(|(a, b): (MyU128, MyU128)| { + if b.0 == 0 { + None + } else { + Some((a.0 / b.0, a.0 % b.0)) + } + }, + "{ + let mut r = 0; + (compiler_builtins::int::udiv::__udivmodti4(a, b, Some(&mut r)), r) + }"); + } +} + +macro_rules! gen_float { + ($name:ident, + $fty:ident, + $uty:ident, + $bits:expr, + $significand_bits:expr) => { + pub fn $name(rng: &mut R) -> $fty + where + R: Rng, + { + const BITS: u8 = $bits; + const SIGNIFICAND_BITS: u8 = $significand_bits; + + const SIGNIFICAND_MASK: $uty = (1 << SIGNIFICAND_BITS) - 1; + const SIGN_MASK: $uty = (1 << (BITS - 1)); + const EXPONENT_MASK: $uty = !(SIGN_MASK | SIGNIFICAND_MASK); + + fn mk_f32(sign: bool, exponent: $uty, significand: $uty) -> $fty { + unsafe { + mem::transmute(((sign as $uty) << (BITS - 1)) | + ((exponent & EXPONENT_MASK) << + SIGNIFICAND_BITS) | + (significand & SIGNIFICAND_MASK)) + } + } + + if rng.gen_weighted_bool(10) { + // Special values + *rng.choose(&[-0.0, + 0.0, + ::std::$fty::NAN, + ::std::$fty::INFINITY, + -::std::$fty::INFINITY]) + .unwrap() + } else if rng.gen_weighted_bool(10) { + // NaN patterns + mk_f32(rng.gen(), rng.gen(), 0) + } else if rng.gen() { + // Denormalized + mk_f32(rng.gen(), 0, rng.gen()) + } else { + // Random anything + mk_f32(rng.gen(), rng.gen(), rng.gen()) + } + } + } +} + +gen_float!(gen_f32, f32, u32, 32, 23); +gen_float!(gen_f64, f64, u64, 64, 52); + +macro_rules! gen_large_float { + ($name:ident, + $fty:ident, + $uty:ident, + $bits:expr, + $significand_bits:expr) => { + pub fn $name(rng: &mut R) -> $fty + where + R: Rng, + { + const BITS: u8 = $bits; + const SIGNIFICAND_BITS: u8 = $significand_bits; + + const SIGNIFICAND_MASK: $uty = (1 << SIGNIFICAND_BITS) - 1; + const SIGN_MASK: $uty = (1 << (BITS - 1)); + const EXPONENT_MASK: $uty = !(SIGN_MASK | SIGNIFICAND_MASK); + + fn mk_f32(sign: bool, exponent: $uty, significand: $uty) -> $fty { + unsafe { + mem::transmute(((sign as $uty) << (BITS - 1)) | + ((exponent & EXPONENT_MASK) << + SIGNIFICAND_BITS) | + (significand & SIGNIFICAND_MASK)) + } + } + + if rng.gen_weighted_bool(10) { + // Special values + *rng.choose(&[-0.0, + 0.0, + ::std::$fty::NAN, + ::std::$fty::INFINITY, + -::std::$fty::INFINITY]) + .unwrap() + } else if rng.gen_weighted_bool(10) { + // NaN patterns + mk_f32(rng.gen(), rng.gen(), 0) + } else if rng.gen() { + // Denormalized + mk_f32(rng.gen(), 0, rng.gen()) + } else { + // Random anything + rng.gen::<$fty>() + } + } + } +} + +gen_large_float!(gen_large_f32, f32, u32, 32, 23); +gen_large_float!(gen_large_f64, f64, u64, 64, 52); + +trait TestInput: rand::Rand + Hash + Eq + fmt::Debug { + fn ty_name() -> String; + fn generate_lets(container: &str, cnt: &mut u8) -> String; + fn generate_static(&self, dst: &mut String); +} + +trait TestOutput { + fn ty_name() -> String; + fn generate_static(&self, dst: &mut String); + fn generate_expr(container: &str) -> String; +} + +fn gen(mut generate: F, test: &str) + where F: FnMut(A) -> Option, + A: TestInput + Copy, + R: TestOutput, +{ + let rng = &mut rand::thread_rng(); + let testname = test.split("::") + .last() + .unwrap() + .split("(") + .next() + .unwrap(); + let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let out_file = out_dir.join("generated.rs"); + + let mut testcases = HashMap::new(); + let mut n = NTESTS; + while n > 0 { + let input: A = rng.gen(); + if testcases.contains_key(&input) { + continue + } + let output = match generate(input) { + Some(o) => o, + None => continue, + }; + testcases.insert(input, output); + n -= 1; + } + + let mut contents = String::new(); + contents.push_str(&format!("mod {} {{\nuse super::*;\n", testname)); + contents.push_str("#[test]\n"); + contents.push_str("fn test() {\n"); + contents.push_str(&format!("static TESTS: [({}, {}); {}] = [\n", + A::ty_name(), + R::ty_name(), + NTESTS)); + for (input, output) in testcases { + contents.push_str(" ("); + input.generate_static(&mut contents); + contents.push_str(", "); + output.generate_static(&mut contents); + contents.push_str("),\n"); + } + contents.push_str("];\n"); + + contents.push_str(&format!(r#" + for &(inputs, output) in TESTS.iter() {{ + {} + assert_eq!({}, {}, "inputs {{:?}}", inputs) + }} + "#, + A::generate_lets("inputs", &mut 0), + R::generate_expr("output"), + test, + )); + contents.push_str("\n}\n"); + contents.push_str("\n}\n"); + + OpenOptions::new() + .write(true) + .append(true) + .create(true) + .open(out_file) + .unwrap() + .write_all(contents.as_bytes()) + .unwrap(); +} + +macro_rules! my_float { + ($(struct $name:ident($inner:ident) = $gen:ident;)*) => ($( + #[derive(Debug, Clone, Copy)] + struct $name($inner); + + impl TestInput for $name { + fn ty_name() -> String { + format!("u{}", &stringify!($inner)[1..]) + } + + fn generate_lets(container: &str, cnt: &mut u8) -> String { + let me = *cnt; + *cnt += 1; + format!("let {} = {}::from_bits({});\n", + (b'a' + me) as char, + stringify!($inner), + container) + } + + fn generate_static(&self, dst: &mut String) { + write!(dst, "{}", self.0.to_bits()).unwrap(); + } + } + + impl rand::Rand for $name { + fn rand(r: &mut R) -> $name { + $name($gen(r)) + } + } + + impl Hash for $name { + fn hash(&self, h: &mut H) { + self.0.to_bits().hash(h) + } + } + + impl PartialEq for $name { + fn eq(&self, other: &$name) -> bool { + self.0.to_bits() == other.0.to_bits() + } + } + + impl Eq for $name {} + + )*) +} + +my_float! { + struct MyF64(f64) = gen_f64; + struct LargeF64(f64) = gen_large_f64; + struct MyF32(f32) = gen_f32; + struct LargeF32(f32) = gen_large_f32; +} + +macro_rules! my_integer { + ($(struct $name:ident($inner:ident);)*) => ($( + #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] + struct $name($inner); + + impl TestInput for $name { + fn ty_name() -> String { + stringify!($inner).to_string() + } + + fn generate_lets(container: &str, cnt: &mut u8) -> String { + let me = *cnt; + *cnt += 1; + format!("let {} = {};\n", + (b'a' + me) as char, + container) + } + + fn generate_static(&self, dst: &mut String) { + write!(dst, "{}", self.0).unwrap(); + } + } + + impl rand::Rand for $name { + fn rand(rng: &mut R) -> $name { + let bits = (0 as $inner).count_zeros(); + let mut mk = || { + if rng.gen_weighted_bool(10) { + *rng.choose(&[ + ::std::$inner::MAX >> (bits / 2), + 0, + ::std::$inner::MIN >> (bits / 2), + ]).unwrap() + } else { + rng.gen::<$inner>() + } + }; + let a = mk(); + let b = mk(); + $name((a << (bits / 2)) | (b & (!0 << (bits / 2)))) + } + } + )*) +} + +my_integer! { + struct MyI32(i32); + struct MyI64(i64); + struct MyI128(i128); + struct MyU32(u32); + struct MyU64(u64); + struct MyU128(u128); +} + +impl TestInput for (A, B) + where A: TestInput, + B: TestInput, +{ + fn ty_name() -> String { + format!("({}, {})", A::ty_name(), B::ty_name()) + } + + fn generate_lets(container: &str, cnt: &mut u8) -> String { + format!("{}{}", + A::generate_lets(&format!("{}.0", container), cnt), + B::generate_lets(&format!("{}.1", container), cnt)) + } + + fn generate_static(&self, dst: &mut String) { + dst.push_str("("); + self.0.generate_static(dst); + dst.push_str(", "); + self.1.generate_static(dst); + dst.push_str(")"); + } +} + +impl TestOutput for f64 { + fn ty_name() -> String { + "u64".to_string() + } + + fn generate_static(&self, dst: &mut String) { + write!(dst, "{}", self.to_bits()).unwrap(); + } + + fn generate_expr(container: &str) -> String { + format!("f64::from_bits({})", container) + } +} + +impl TestOutput for f32 { + fn ty_name() -> String { + "u32".to_string() + } + + fn generate_static(&self, dst: &mut String) { + write!(dst, "{}", self.to_bits()).unwrap(); + } + + fn generate_expr(container: &str) -> String { + format!("f32::from_bits({})", container) + } +} + +macro_rules! plain_test_output { + ($($i:tt)*) => ($( + impl TestOutput for $i { + fn ty_name() -> String { + stringify!($i).to_string() + } + + fn generate_static(&self, dst: &mut String) { + write!(dst, "{}", self).unwrap(); + } + + fn generate_expr(container: &str) -> String { + container.to_string() + } + } + )*) +} + +plain_test_output!(i32 i64 i128 u32 u64 u128 bool); + +impl TestOutput for (A, B) + where A: TestOutput, + B: TestOutput, +{ + fn ty_name() -> String { + format!("({}, {})", A::ty_name(), B::ty_name()) + } + + fn generate_static(&self, dst: &mut String) { + dst.push_str("("); + self.0.generate_static(dst); + dst.push_str(", "); + self.1.generate_static(dst); + dst.push_str(")"); + } + + fn generate_expr(container: &str) -> String { + container.to_string() + } +} diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs new file mode 100644 index 0000000000000..31e1bb209f98e --- /dev/null +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -0,0 +1,7 @@ +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/library/compiler-builtins/tests/aeabi_memclr.rs b/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs similarity index 100% rename from library/compiler-builtins/tests/aeabi_memclr.rs rename to library/compiler-builtins/testcrate/tests/aeabi_memclr.rs diff --git a/library/compiler-builtins/tests/aeabi_memcpy.rs b/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs similarity index 100% rename from library/compiler-builtins/tests/aeabi_memcpy.rs rename to library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs diff --git a/library/compiler-builtins/tests/aeabi_memset.rs b/library/compiler-builtins/testcrate/tests/aeabi_memset.rs similarity index 100% rename from library/compiler-builtins/tests/aeabi_memset.rs rename to library/compiler-builtins/testcrate/tests/aeabi_memset.rs diff --git a/library/compiler-builtins/testcrate/tests/generated.rs b/library/compiler-builtins/testcrate/tests/generated.rs new file mode 100644 index 0000000000000..1a43f436e0b41 --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/generated.rs @@ -0,0 +1,6 @@ +#![feature(i128_type)] +#![allow(bad_style)] + +extern crate compiler_builtins; + +include!(concat!(env!("OUT_DIR"), "/generated.rs")); diff --git a/library/compiler-builtins/tests/adddf3.rs b/library/compiler-builtins/tests/adddf3.rs deleted file mode 100644 index 3129330afaf5e..0000000000000 --- a/library/compiler-builtins/tests/adddf3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/adddf3.rs")); diff --git a/library/compiler-builtins/tests/addsf3.rs b/library/compiler-builtins/tests/addsf3.rs deleted file mode 100644 index b5c9c3dfebdb9..0000000000000 --- a/library/compiler-builtins/tests/addsf3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/addsf3.rs")); diff --git a/library/compiler-builtins/tests/ashldi3.rs b/library/compiler-builtins/tests/ashldi3.rs deleted file mode 100644 index 1116375d3ef35..0000000000000 --- a/library/compiler-builtins/tests/ashldi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/ashldi3.rs")); diff --git a/library/compiler-builtins/tests/ashlti3.rs b/library/compiler-builtins/tests/ashlti3.rs deleted file mode 100644 index 4c799cf8822a9..0000000000000 --- a/library/compiler-builtins/tests/ashlti3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/ashlti3.rs")); diff --git a/library/compiler-builtins/tests/ashrdi3.rs b/library/compiler-builtins/tests/ashrdi3.rs deleted file mode 100644 index a0a2b6cb13af1..0000000000000 --- a/library/compiler-builtins/tests/ashrdi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/ashrdi3.rs")); diff --git a/library/compiler-builtins/tests/ashrti3.rs b/library/compiler-builtins/tests/ashrti3.rs deleted file mode 100644 index b147051c2d93a..0000000000000 --- a/library/compiler-builtins/tests/ashrti3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/ashrti3.rs")); diff --git a/library/compiler-builtins/tests/divdf3.rs b/library/compiler-builtins/tests/divdf3.rs deleted file mode 100644 index 98d32d1b084cb..0000000000000 --- a/library/compiler-builtins/tests/divdf3.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", test), - no_std)] - -include!(concat!(env!("OUT_DIR"), "/divdf3.rs")); diff --git a/library/compiler-builtins/tests/divdf3vfp.rs b/library/compiler-builtins/tests/divdf3vfp.rs deleted file mode 100644 index 9225a5c30a167..0000000000000 --- a/library/compiler-builtins/tests/divdf3vfp.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", test), - no_std)] - -#[cfg(target_arch = "arm")] -include!(concat!(env!("OUT_DIR"), "/divdf3vfp.rs")); diff --git a/library/compiler-builtins/tests/divdi3.rs b/library/compiler-builtins/tests/divdi3.rs deleted file mode 100644 index 4bdce54156eda..0000000000000 --- a/library/compiler-builtins/tests/divdi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/divdi3.rs")); diff --git a/library/compiler-builtins/tests/divmoddi4.rs b/library/compiler-builtins/tests/divmoddi4.rs deleted file mode 100644 index 9ddd85a829fcf..0000000000000 --- a/library/compiler-builtins/tests/divmoddi4.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/divmoddi4.rs")); diff --git a/library/compiler-builtins/tests/divmodsi4.rs b/library/compiler-builtins/tests/divmodsi4.rs deleted file mode 100644 index 6fe80e9756918..0000000000000 --- a/library/compiler-builtins/tests/divmodsi4.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/divmodsi4.rs")); diff --git a/library/compiler-builtins/tests/divsf3.rs b/library/compiler-builtins/tests/divsf3.rs deleted file mode 100644 index 5cf3e86ca018c..0000000000000 --- a/library/compiler-builtins/tests/divsf3.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", test), - no_std)] - -include!(concat!(env!("OUT_DIR"), "/divsf3.rs")); diff --git a/library/compiler-builtins/tests/divsf3vfp.rs b/library/compiler-builtins/tests/divsf3vfp.rs deleted file mode 100644 index 0ecc8fe0c8b26..0000000000000 --- a/library/compiler-builtins/tests/divsf3vfp.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", test), - no_std)] - -#[cfg(target_arch = "arm")] -include!(concat!(env!("OUT_DIR"), "/divsf3vfp.rs")); diff --git a/library/compiler-builtins/tests/divsi3.rs b/library/compiler-builtins/tests/divsi3.rs deleted file mode 100644 index e6440d782c778..0000000000000 --- a/library/compiler-builtins/tests/divsi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/divsi3.rs")); diff --git a/library/compiler-builtins/tests/divti3.rs b/library/compiler-builtins/tests/divti3.rs deleted file mode 100644 index 7919f8fe396a3..0000000000000 --- a/library/compiler-builtins/tests/divti3.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -// FIXME(#137) -#[cfg(not(target_arch = "mips"))] -include!(concat!(env!("OUT_DIR"), "/divti3.rs")); diff --git a/library/compiler-builtins/tests/fixdfdi.rs b/library/compiler-builtins/tests/fixdfdi.rs deleted file mode 100644 index b66477502bbe9..0000000000000 --- a/library/compiler-builtins/tests/fixdfdi.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/fixdfdi.rs")); diff --git a/library/compiler-builtins/tests/fixdfsi.rs b/library/compiler-builtins/tests/fixdfsi.rs deleted file mode 100644 index 2677eec747af8..0000000000000 --- a/library/compiler-builtins/tests/fixdfsi.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/fixdfsi.rs")); diff --git a/library/compiler-builtins/tests/fixdfti.rs b/library/compiler-builtins/tests/fixdfti.rs deleted file mode 100644 index 5bae55e99f38a..0000000000000 --- a/library/compiler-builtins/tests/fixdfti.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/fixdfti.rs")); diff --git a/library/compiler-builtins/tests/fixsfdi.rs b/library/compiler-builtins/tests/fixsfdi.rs deleted file mode 100644 index e38952be59324..0000000000000 --- a/library/compiler-builtins/tests/fixsfdi.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/fixsfdi.rs")); diff --git a/library/compiler-builtins/tests/fixsfsi.rs b/library/compiler-builtins/tests/fixsfsi.rs deleted file mode 100644 index 242b4c16940ce..0000000000000 --- a/library/compiler-builtins/tests/fixsfsi.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/fixsfsi.rs")); diff --git a/library/compiler-builtins/tests/fixsfti.rs b/library/compiler-builtins/tests/fixsfti.rs deleted file mode 100644 index 653157df26ba9..0000000000000 --- a/library/compiler-builtins/tests/fixsfti.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/fixsfti.rs")); diff --git a/library/compiler-builtins/tests/fixunsdfdi.rs b/library/compiler-builtins/tests/fixunsdfdi.rs deleted file mode 100644 index 13b35ba4a179a..0000000000000 --- a/library/compiler-builtins/tests/fixunsdfdi.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/fixunsdfdi.rs")); diff --git a/library/compiler-builtins/tests/fixunsdfsi.rs b/library/compiler-builtins/tests/fixunsdfsi.rs deleted file mode 100644 index 32faf360c30ff..0000000000000 --- a/library/compiler-builtins/tests/fixunsdfsi.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/fixunsdfsi.rs")); diff --git a/library/compiler-builtins/tests/fixunsdfti.rs b/library/compiler-builtins/tests/fixunsdfti.rs deleted file mode 100644 index 615e7b33b8dbf..0000000000000 --- a/library/compiler-builtins/tests/fixunsdfti.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/fixunsdfti.rs")); diff --git a/library/compiler-builtins/tests/fixunssfdi.rs b/library/compiler-builtins/tests/fixunssfdi.rs deleted file mode 100644 index 24e6f6e350894..0000000000000 --- a/library/compiler-builtins/tests/fixunssfdi.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/fixunssfdi.rs")); diff --git a/library/compiler-builtins/tests/fixunssfsi.rs b/library/compiler-builtins/tests/fixunssfsi.rs deleted file mode 100644 index da02cd94578ef..0000000000000 --- a/library/compiler-builtins/tests/fixunssfsi.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/fixunssfsi.rs")); diff --git a/library/compiler-builtins/tests/fixunssfti.rs b/library/compiler-builtins/tests/fixunssfti.rs deleted file mode 100644 index d67f9e794e0e9..0000000000000 --- a/library/compiler-builtins/tests/fixunssfti.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/fixunssfti.rs")); diff --git a/library/compiler-builtins/tests/floatdidf.rs b/library/compiler-builtins/tests/floatdidf.rs deleted file mode 100644 index 2b3dcb5928cf2..0000000000000 --- a/library/compiler-builtins/tests/floatdidf.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/floatdidf.rs")); diff --git a/library/compiler-builtins/tests/floatsidf.rs b/library/compiler-builtins/tests/floatsidf.rs deleted file mode 100644 index ffee7e271131f..0000000000000 --- a/library/compiler-builtins/tests/floatsidf.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/floatsidf.rs")); diff --git a/library/compiler-builtins/tests/floatsisf.rs b/library/compiler-builtins/tests/floatsisf.rs deleted file mode 100644 index c03ab7f9dd59d..0000000000000 --- a/library/compiler-builtins/tests/floatsisf.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/floatsisf.rs")); diff --git a/library/compiler-builtins/tests/floattidf.rs b/library/compiler-builtins/tests/floattidf.rs deleted file mode 100644 index c2e798a996352..0000000000000 --- a/library/compiler-builtins/tests/floattidf.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] -#![cfg(not(target_arch = "mips"))] // FIXME(#168) - -include!(concat!(env!("OUT_DIR"), "/floattidf.rs")); diff --git a/library/compiler-builtins/tests/floattisf.rs b/library/compiler-builtins/tests/floattisf.rs deleted file mode 100644 index 2a0657d3d00e9..0000000000000 --- a/library/compiler-builtins/tests/floattisf.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/floattisf.rs")); diff --git a/library/compiler-builtins/tests/floatundidf.rs b/library/compiler-builtins/tests/floatundidf.rs deleted file mode 100644 index 0b8338512452f..0000000000000 --- a/library/compiler-builtins/tests/floatundidf.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/floatundidf.rs")); diff --git a/library/compiler-builtins/tests/floatunsidf.rs b/library/compiler-builtins/tests/floatunsidf.rs deleted file mode 100644 index e25a69f5beaf9..0000000000000 --- a/library/compiler-builtins/tests/floatunsidf.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/floatunsidf.rs")); diff --git a/library/compiler-builtins/tests/floatunsisf.rs b/library/compiler-builtins/tests/floatunsisf.rs deleted file mode 100644 index c0b9fd8b0b97f..0000000000000 --- a/library/compiler-builtins/tests/floatunsisf.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/floatunsisf.rs")); diff --git a/library/compiler-builtins/tests/floatuntidf.rs b/library/compiler-builtins/tests/floatuntidf.rs deleted file mode 100644 index 4ea272e97d113..0000000000000 --- a/library/compiler-builtins/tests/floatuntidf.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/floatuntidf.rs")); diff --git a/library/compiler-builtins/tests/floatuntisf.rs b/library/compiler-builtins/tests/floatuntisf.rs deleted file mode 100644 index 74cd853e49ecd..0000000000000 --- a/library/compiler-builtins/tests/floatuntisf.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/floatuntisf.rs")); diff --git a/library/compiler-builtins/tests/gedf2.rs b/library/compiler-builtins/tests/gedf2.rs deleted file mode 100644 index e1bea5953951d..0000000000000 --- a/library/compiler-builtins/tests/gedf2.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", test), - no_std)] - -include!(concat!(env!("OUT_DIR"), "/gedf2.rs")); diff --git a/library/compiler-builtins/tests/gesf2.rs b/library/compiler-builtins/tests/gesf2.rs deleted file mode 100644 index 760f5a8f5ade5..0000000000000 --- a/library/compiler-builtins/tests/gesf2.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", test), - no_std)] - -include!(concat!(env!("OUT_DIR"), "/gesf2.rs")); diff --git a/library/compiler-builtins/tests/i128_add.rs b/library/compiler-builtins/tests/i128_add.rs deleted file mode 100644 index 13af0500cb824..0000000000000 --- a/library/compiler-builtins/tests/i128_add.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/i128_add.rs")); diff --git a/library/compiler-builtins/tests/i128_addo.rs b/library/compiler-builtins/tests/i128_addo.rs deleted file mode 100644 index 306ffac169eac..0000000000000 --- a/library/compiler-builtins/tests/i128_addo.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/i128_addo.rs")); diff --git a/library/compiler-builtins/tests/i128_sub.rs b/library/compiler-builtins/tests/i128_sub.rs deleted file mode 100644 index 933fe4f56617c..0000000000000 --- a/library/compiler-builtins/tests/i128_sub.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/i128_sub.rs")); diff --git a/library/compiler-builtins/tests/i128_subo.rs b/library/compiler-builtins/tests/i128_subo.rs deleted file mode 100644 index 0c2b67cbbdc9d..0000000000000 --- a/library/compiler-builtins/tests/i128_subo.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/i128_subo.rs")); diff --git a/library/compiler-builtins/tests/ledf2.rs b/library/compiler-builtins/tests/ledf2.rs deleted file mode 100644 index 3fac17b0f3613..0000000000000 --- a/library/compiler-builtins/tests/ledf2.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", test), - no_std)] - -include!(concat!(env!("OUT_DIR"), "/ledf2.rs")); diff --git a/library/compiler-builtins/tests/lesf2.rs b/library/compiler-builtins/tests/lesf2.rs deleted file mode 100644 index 878861fec1c55..0000000000000 --- a/library/compiler-builtins/tests/lesf2.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", test), - no_std)] - -include!(concat!(env!("OUT_DIR"), "/lesf2.rs")); diff --git a/library/compiler-builtins/tests/lshrdi3.rs b/library/compiler-builtins/tests/lshrdi3.rs deleted file mode 100644 index b1a2331b196ac..0000000000000 --- a/library/compiler-builtins/tests/lshrdi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/lshrdi3.rs")); diff --git a/library/compiler-builtins/tests/lshrti3.rs b/library/compiler-builtins/tests/lshrti3.rs deleted file mode 100644 index 2ee32ce71f4d2..0000000000000 --- a/library/compiler-builtins/tests/lshrti3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/lshrti3.rs")); diff --git a/library/compiler-builtins/tests/moddi3.rs b/library/compiler-builtins/tests/moddi3.rs deleted file mode 100644 index 6a58a77ab49dc..0000000000000 --- a/library/compiler-builtins/tests/moddi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/moddi3.rs")); diff --git a/library/compiler-builtins/tests/modsi3.rs b/library/compiler-builtins/tests/modsi3.rs deleted file mode 100644 index 46ad8cd33cdce..0000000000000 --- a/library/compiler-builtins/tests/modsi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/modsi3.rs")); diff --git a/library/compiler-builtins/tests/modti3.rs b/library/compiler-builtins/tests/modti3.rs deleted file mode 100644 index 62129cd04d3c3..0000000000000 --- a/library/compiler-builtins/tests/modti3.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -// FIXME(#137) -#[cfg(not(target_arch = "mips"))] -include!(concat!(env!("OUT_DIR"), "/modti3.rs")); diff --git a/library/compiler-builtins/tests/muldf3.rs b/library/compiler-builtins/tests/muldf3.rs deleted file mode 100644 index 82d06d8de3662..0000000000000 --- a/library/compiler-builtins/tests/muldf3.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", test), - no_std)] - -include!(concat!(env!("OUT_DIR"), "/muldf3.rs")); diff --git a/library/compiler-builtins/tests/muldf3vfp.rs b/library/compiler-builtins/tests/muldf3vfp.rs deleted file mode 100644 index 8a717157fb0cd..0000000000000 --- a/library/compiler-builtins/tests/muldf3vfp.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", test), - no_std)] - -#[cfg(target_arch = "arm")] -include!(concat!(env!("OUT_DIR"), "/muldf3vfp.rs")); diff --git a/library/compiler-builtins/tests/muldi3.rs b/library/compiler-builtins/tests/muldi3.rs deleted file mode 100644 index d771e8a6bde32..0000000000000 --- a/library/compiler-builtins/tests/muldi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/muldi3.rs")); diff --git a/library/compiler-builtins/tests/mulodi4.rs b/library/compiler-builtins/tests/mulodi4.rs deleted file mode 100644 index 071a295810f78..0000000000000 --- a/library/compiler-builtins/tests/mulodi4.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/mulodi4.rs")); diff --git a/library/compiler-builtins/tests/mulosi4.rs b/library/compiler-builtins/tests/mulosi4.rs deleted file mode 100644 index 3ec4336d118b3..0000000000000 --- a/library/compiler-builtins/tests/mulosi4.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/mulosi4.rs")); diff --git a/library/compiler-builtins/tests/muloti4.rs b/library/compiler-builtins/tests/muloti4.rs deleted file mode 100644 index 358c57ec528a8..0000000000000 --- a/library/compiler-builtins/tests/muloti4.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -// FIXME(#137) -#[cfg(not(target_arch = "mips"))] -include!(concat!(env!("OUT_DIR"), "/muloti4.rs")); diff --git a/library/compiler-builtins/tests/mulsf3.rs b/library/compiler-builtins/tests/mulsf3.rs deleted file mode 100644 index fe278d84be21b..0000000000000 --- a/library/compiler-builtins/tests/mulsf3.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", test), - no_std)] - -include!(concat!(env!("OUT_DIR"), "/mulsf3.rs")); diff --git a/library/compiler-builtins/tests/mulsf3vfp.rs b/library/compiler-builtins/tests/mulsf3vfp.rs deleted file mode 100644 index 4d7f288970a5a..0000000000000 --- a/library/compiler-builtins/tests/mulsf3vfp.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", test), - no_std)] - -#[cfg(target_arch = "arm")] -include!(concat!(env!("OUT_DIR"), "/mulsf3vfp.rs")); diff --git a/library/compiler-builtins/tests/multi3.rs b/library/compiler-builtins/tests/multi3.rs deleted file mode 100644 index db5253874386c..0000000000000 --- a/library/compiler-builtins/tests/multi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/multi3.rs")); diff --git a/library/compiler-builtins/tests/powidf2.rs b/library/compiler-builtins/tests/powidf2.rs deleted file mode 100644 index dde5f03eb9cb9..0000000000000 --- a/library/compiler-builtins/tests/powidf2.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/powidf2.rs")); diff --git a/library/compiler-builtins/tests/powisf2.rs b/library/compiler-builtins/tests/powisf2.rs deleted file mode 100644 index 3e0baeb73cecb..0000000000000 --- a/library/compiler-builtins/tests/powisf2.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/powisf2.rs")); diff --git a/library/compiler-builtins/tests/subdf3.rs b/library/compiler-builtins/tests/subdf3.rs deleted file mode 100644 index 13f695718e1aa..0000000000000 --- a/library/compiler-builtins/tests/subdf3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/subdf3.rs")); diff --git a/library/compiler-builtins/tests/subsf3.rs b/library/compiler-builtins/tests/subsf3.rs deleted file mode 100644 index 7be426c453140..0000000000000 --- a/library/compiler-builtins/tests/subsf3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/subsf3.rs")); diff --git a/library/compiler-builtins/tests/u128_add.rs b/library/compiler-builtins/tests/u128_add.rs deleted file mode 100644 index d4b8f2ccb248b..0000000000000 --- a/library/compiler-builtins/tests/u128_add.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/u128_add.rs")); diff --git a/library/compiler-builtins/tests/u128_addo.rs b/library/compiler-builtins/tests/u128_addo.rs deleted file mode 100644 index caff682e8a087..0000000000000 --- a/library/compiler-builtins/tests/u128_addo.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/u128_addo.rs")); diff --git a/library/compiler-builtins/tests/u128_sub.rs b/library/compiler-builtins/tests/u128_sub.rs deleted file mode 100644 index 024266b926382..0000000000000 --- a/library/compiler-builtins/tests/u128_sub.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/u128_sub.rs")); diff --git a/library/compiler-builtins/tests/u128_subo.rs b/library/compiler-builtins/tests/u128_subo.rs deleted file mode 100644 index b3fb4b854e243..0000000000000 --- a/library/compiler-builtins/tests/u128_subo.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/u128_subo.rs")); diff --git a/library/compiler-builtins/tests/udivdi3.rs b/library/compiler-builtins/tests/udivdi3.rs deleted file mode 100644 index d87091c7d84d0..0000000000000 --- a/library/compiler-builtins/tests/udivdi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/udivdi3.rs")); diff --git a/library/compiler-builtins/tests/udivmoddi4.rs b/library/compiler-builtins/tests/udivmoddi4.rs deleted file mode 100644 index a9444c10db352..0000000000000 --- a/library/compiler-builtins/tests/udivmoddi4.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/udivmoddi4.rs")); diff --git a/library/compiler-builtins/tests/udivmodsi4.rs b/library/compiler-builtins/tests/udivmodsi4.rs deleted file mode 100644 index e93bfe1e55281..0000000000000 --- a/library/compiler-builtins/tests/udivmodsi4.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/udivmodsi4.rs")); diff --git a/library/compiler-builtins/tests/udivmodti4.rs b/library/compiler-builtins/tests/udivmodti4.rs deleted file mode 100644 index 8185ec0e78971..0000000000000 --- a/library/compiler-builtins/tests/udivmodti4.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -// FIXME(#137) -#[cfg(not(target_arch = "mips"))] -include!(concat!(env!("OUT_DIR"), "/udivmodti4.rs")); diff --git a/library/compiler-builtins/tests/udivsi3.rs b/library/compiler-builtins/tests/udivsi3.rs deleted file mode 100644 index d6433e7c31ddd..0000000000000 --- a/library/compiler-builtins/tests/udivsi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/udivsi3.rs")); diff --git a/library/compiler-builtins/tests/udivti3.rs b/library/compiler-builtins/tests/udivti3.rs deleted file mode 100644 index cefddda8f8698..0000000000000 --- a/library/compiler-builtins/tests/udivti3.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -// FIXME(#137) -#[cfg(not(target_arch = "mips"))] -include!(concat!(env!("OUT_DIR"), "/udivti3.rs")); diff --git a/library/compiler-builtins/tests/umoddi3.rs b/library/compiler-builtins/tests/umoddi3.rs deleted file mode 100644 index 09a114ee6b949..0000000000000 --- a/library/compiler-builtins/tests/umoddi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/umoddi3.rs")); diff --git a/library/compiler-builtins/tests/umodsi3.rs b/library/compiler-builtins/tests/umodsi3.rs deleted file mode 100644 index aa56e819c2748..0000000000000 --- a/library/compiler-builtins/tests/umodsi3.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -include!(concat!(env!("OUT_DIR"), "/umodsi3.rs")); diff --git a/library/compiler-builtins/tests/umodti3.rs b/library/compiler-builtins/tests/umodti3.rs deleted file mode 100644 index 57e651b2710f1..0000000000000 --- a/library/compiler-builtins/tests/umodti3.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![cfg_attr(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test), no_std)] - -// FIXME(#137) -#[cfg(not(target_arch = "mips"))] -include!(concat!(env!("OUT_DIR"), "/umodti3.rs")); From 07c82d220028bb89c9977e59fc0f0e26f2a517b0 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sun, 4 Feb 2018 09:48:06 +0100 Subject: [PATCH 0432/4206] Fix __aeabi_fcmple and add test cases `le` in __aeabi_fcmple means `less or equal` --- library/compiler-builtins/src/float/cmp.rs | 2 +- library/compiler-builtins/testcrate/build.rs | 92 ++++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index e3c584084adc4..4986d056052b1 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -174,7 +174,7 @@ intrinsics! { #[cfg(target_arch = "arm")] intrinsics! { pub extern "aapcs" fn __aeabi_fcmple(a: f32, b: f32) -> i32 { - (__lesf2(a, b) < 0) as i32 + (__lesf2(a, b) <= 0) as i32 } pub extern "aapcs" fn __aeabi_fcmpge(a: f32, b: f32) -> i32 { diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 98a0934c0d909..a32dc741b35e5 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -121,6 +121,98 @@ fn main() { }, "compiler_builtins::float::cmp::__lesf2(a, b)"); + if target_arch_arm { + gen(|(a, b): (MyF32, MyF32)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + let c = (a.0 <= b.0) as i32; + Some(c) + }, + "compiler_builtins::float::cmp::__aeabi_fcmple(a, b)"); + + gen(|(a, b): (MyF32, MyF32)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + let c = (a.0 >= b.0) as i32; + Some(c) + }, + "compiler_builtins::float::cmp::__aeabi_fcmpge(a, b)"); + + gen(|(a, b): (MyF32, MyF32)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + let c = (a.0 == b.0) as i32; + Some(c) + }, + "compiler_builtins::float::cmp::__aeabi_fcmpeq(a, b)"); + + gen(|(a, b): (MyF32, MyF32)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + let c = (a.0 < b.0) as i32; + Some(c) + }, + "compiler_builtins::float::cmp::__aeabi_fcmplt(a, b)"); + + gen(|(a, b): (MyF32, MyF32)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + let c = (a.0 > b.0) as i32; + Some(c) + }, + "compiler_builtins::float::cmp::__aeabi_fcmpgt(a, b)"); + + gen(|(a, b): (MyF64, MyF64)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + let c = (a.0 <= b.0) as i32; + Some(c) + }, + "compiler_builtins::float::cmp::__aeabi_dcmple(a, b)"); + + gen(|(a, b): (MyF64, MyF64)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + let c = (a.0 >= b.0) as i32; + Some(c) + }, + "compiler_builtins::float::cmp::__aeabi_dcmpge(a, b)"); + + gen(|(a, b): (MyF64, MyF64)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + let c = (a.0 == b.0) as i32; + Some(c) + }, + "compiler_builtins::float::cmp::__aeabi_dcmpeq(a, b)"); + + gen(|(a, b): (MyF64, MyF64)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + let c = (a.0 < b.0) as i32; + Some(c) + }, + "compiler_builtins::float::cmp::__aeabi_dcmplt(a, b)"); + + gen(|(a, b): (MyF64, MyF64)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + let c = (a.0 > b.0) as i32; + Some(c) + }, + "compiler_builtins::float::cmp::__aeabi_dcmpgt(a, b)"); + } + // float/conv.rs gen(|a: MyF64| i64(a.0).ok(), "compiler_builtins::float::conv::__fixdfdi(a)"); From 97e6b3712af601e9f6a450f2d9653e6315596208 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sun, 4 Feb 2018 18:34:31 +0100 Subject: [PATCH 0433/4206] Add support for sub*f3vfp and add*f3vfp As done before for mul and div let's use extern "C" to generate `"aapcs"` or `"aapcs-vfp"` depending on target configuration. --- library/compiler-builtins/README.md | 8 ++-- library/compiler-builtins/build.rs | 4 -- library/compiler-builtins/src/float/add.rs | 10 +++++ library/compiler-builtins/src/float/sub.rs | 10 +++++ library/compiler-builtins/testcrate/build.rs | 43 ++++++++++++++++++++ 5 files changed, 67 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index cc4852a446ae1..97ef340f9e5d8 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -85,8 +85,8 @@ features = ["c"] - [x] adddf3.c - [x] addsf3.c -- [ ] arm/adddf3vfp.S -- [ ] arm/addsf3vfp.S +- [x] arm/adddf3vfp.S +- [x] arm/addsf3vfp.S - [ ] arm/aeabi_dcmp.S - [ ] arm/aeabi_fcmp.S - [x] arm/aeabi_idivmod.S @@ -127,8 +127,8 @@ features = ["c"] - [ ] arm/negsf2vfp.S - [ ] arm/nesf2vfp.S - [ ] arm/softfloat-alias.list -- [ ] arm/subdf3vfp.S -- [ ] arm/subsf3vfp.S +- [x] arm/subdf3vfp.S +- [x] arm/subsf3vfp.S - [ ] arm/truncdfsf2vfp.S - [ ] arm/udivmodsi4.S (generic version is done) - [ ] arm/udivsi3.S (generic version is done) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 8beb1288116e5..89a4a83e42480 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -375,8 +375,6 @@ mod c { if !llvm_target[0].starts_with("thumbv7em") { sources.extend( &[ - "arm/adddf3vfp.S", - "arm/addsf3vfp.S", "arm/eqdf2vfp.S", "arm/eqsf2vfp.S", "arm/extendsfdf2vfp.S", @@ -400,8 +398,6 @@ mod c { "arm/nesf2vfp.S", "arm/restore_vfp_d8_d15_regs.S", "arm/save_vfp_d8_d15_regs.S", - "arm/subdf3vfp.S", - "arm/subsf3vfp.S", ], ); } diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index d355cb1ff27d3..2b6ada81ddc79 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -193,4 +193,14 @@ intrinsics! { pub extern "C" fn __adddf3(a: f64, b: f64) -> f64 { add(a, b) } + + #[cfg(target_arch = "arm")] + pub extern "C" fn __addsf3vfp(a: f32, b: f32) -> f32 { + a + b + } + + #[cfg(target_arch = "arm")] + pub extern "C" fn __adddf3vfp(a: f64, b: f64) -> f64 { + a + b + } } diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index ed7dd2c0aaaf1..c2791bf9291e3 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -10,4 +10,14 @@ intrinsics! { pub extern "C" fn __subdf3(a: f64, b: f64) -> f64 { a + f64::from_repr(b.repr() ^ f64::SIGN_MASK) } + + #[cfg(target_arch = "arm")] + pub extern "C" fn __subsf3vfp(a: f32, b: f32) -> f32 { + a - b + } + + #[cfg(target_arch = "arm")] + pub extern "C" fn __subdf3vfp(a: f64, b: f64) -> f64 { + a - b + } } diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index a32dc741b35e5..a300e28036015 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -51,6 +51,28 @@ fn main() { }, "compiler_builtins::float::add::__addsf3(a, b)"); + if target_arch_arm { + gen(|(a, b): (MyF64, MyF64)| { + let c = a.0 + b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::add::__adddf3vfp(a, b)"); + gen(|(a, b): (LargeF32, LargeF32)| { + let c = a.0 + b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::add::__addsf3vfp(a, b)"); + } + + // float/cmp.rs gen(|(a, b): (MyF64, MyF64)| { let (a, b) = (a.0, b.0); @@ -301,6 +323,27 @@ fn main() { }, "compiler_builtins::float::sub::__subsf3(a, b)"); + if target_arch_arm { + gen(|(a, b): (MyF64, MyF64)| { + let c = a.0 - b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::sub::__subdf3vfp(a, b)"); + gen(|(a, b): (LargeF32, LargeF32)| { + let c = a.0 - b.0; + if a.0.is_nan() || b.0.is_nan() || c.is_nan() { + None + } else { + Some(c) + } + }, + "compiler_builtins::float::sub::__subsf3vfp(a, b)"); + } + // float/mul.rs gen(|(a, b): (MyF64, MyF64)| { let c = a.0 * b.0; From 0af69177f94b6e34c9e05b2e4543566f295a4d6d Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Thu, 8 Feb 2018 18:20:45 +0100 Subject: [PATCH 0434/4206] Add generic conversion from a narrower to a wider FP type Add `extend` module to implement conversion from a narrower to a wider floating-point type. This implementation is only intended to support *widening* operations. Module to convert a *narrower* floating-point will be added in the future. --- library/compiler-builtins/README.md | 2 +- library/compiler-builtins/build.rs | 1 - library/compiler-builtins/src/float/extend.rs | 77 +++++++++++++++++++ library/compiler-builtins/src/float/mod.rs | 1 + library/compiler-builtins/testcrate/build.rs | 9 +++ 5 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/src/float/extend.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 97ef340f9e5d8..30abd928e0200 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -146,7 +146,7 @@ features = ["c"] - [x] divsf3.c - [x] divsi3.c - [ ] extendhfsf2.c -- [ ] extendsfdf2.c +- [x] extendsfdf2.c - [x] fixdfdi.c - [x] fixdfsi.c - [x] fixsfdi.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 89a4a83e42480..0d32e976258d7 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -171,7 +171,6 @@ mod c { "divdc3.c", "divsc3.c", "divxc3.c", - "extendsfdf2.c", "extendhfsf2.c", "floatdisf.c", "floatundisf.c", diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs new file mode 100644 index 0000000000000..1abb23c3f923a --- /dev/null +++ b/library/compiler-builtins/src/float/extend.rs @@ -0,0 +1,77 @@ +use int::{CastInto, Int}; +use float::Float; + +/// Generic conversion from a narrower to a wider IEEE-754 floating-point type +fn extend(a: F) -> R where + F::Int: CastInto, + u64: CastInto, + u32: CastInto, + R::Int: CastInto, + R::Int: CastInto, + u64: CastInto, + F::Int: CastInto, +{ + let src_zero = F::Int::ZERO; + let src_one = F::Int::ONE; + let src_bits = F::BITS; + let src_sign_bits = F::SIGNIFICAND_BITS; + let src_exp_bias = F::EXPONENT_BIAS; + let src_min_normal = F::IMPLICIT_BIT; + let src_infinity = F::EXPONENT_MASK; + let src_sign_mask = F::SIGN_MASK as F::Int; + let src_abs_mask = src_sign_mask - src_one; + let src_qnan = F::SIGNIFICAND_MASK; + let src_nan_code = src_qnan - src_one; + + let dst_bits = R::BITS; + let dst_sign_bits = R::SIGNIFICAND_BITS; + let dst_inf_exp = R::EXPONENT_MAX; + let dst_exp_bias = R::EXPONENT_BIAS; + let dst_min_normal = R::IMPLICIT_BIT; + + let sign_bits_delta = dst_sign_bits - src_sign_bits; + let exp_bias_delta = dst_exp_bias - src_exp_bias; + let a_abs = a.repr() & src_abs_mask; + let mut abs_result = R::Int::ZERO; + + if a_abs.wrapping_sub(src_min_normal) < src_infinity.wrapping_sub(src_min_normal) { + // a is a normal number. + // Extend to the destination type by shifting the significand and + // exponent into the proper position and rebiasing the exponent. + let abs_dst: R::Int = a_abs.cast(); + let bias_dst: R::Int = exp_bias_delta.cast(); + abs_result = abs_dst.wrapping_shl(sign_bits_delta); + abs_result |= bias_dst.wrapping_shl(dst_sign_bits); + } else if a_abs >= src_infinity { + // a is NaN or infinity. + // Conjure the result by beginning with infinity, then setting the qNaN + // bit (if needed) and right-aligning the rest of the trailing NaN + // payload field. + let qnan_dst: R::Int = (a_abs & src_qnan).cast(); + let nan_code_dst: R::Int = (a_abs & src_nan_code).cast(); + let inf_exp_dst: R::Int = dst_inf_exp.cast(); + abs_result = inf_exp_dst.wrapping_shl(dst_sign_bits); + abs_result |= qnan_dst.wrapping_shl(sign_bits_delta); + abs_result |= nan_code_dst.wrapping_shl(sign_bits_delta); + } else if a_abs != src_zero { + // a is denormal. + // Renormalize the significand and clear the leading bit, then insert + // the correct adjusted exponent in the destination type. + let scale = a_abs.leading_zeros() - src_min_normal.leading_zeros(); + let abs_dst: R::Int = a_abs.cast(); + let bias_dst: R::Int = (exp_bias_delta - scale + 1).cast(); + abs_result = abs_dst.wrapping_shl(sign_bits_delta + scale); + abs_result = (abs_result ^ dst_min_normal) | (bias_dst.wrapping_shl(dst_sign_bits)); + } + + let sign_result: R::Int = (a.repr() & src_sign_mask).cast(); + R::from_repr(abs_result | (sign_result.wrapping_shl(dst_bits - src_bits))) +} + +intrinsics! { + #[aapcs_on_arm] + #[arm_aeabi_alias = __aeabi_f2d] + pub extern "C" fn __extendsfdf2(a: f32) -> f64 { + extend(a) + } +} \ No newline at end of file diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 51ed6674d1d03..3bb13abbc5c61 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -10,6 +10,7 @@ pub mod pow; pub mod sub; pub mod mul; pub mod div; +pub mod extend; /// Trait for some basic operations on floats pub trait Float: diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index a300e28036015..9269983c7b76a 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -235,6 +235,15 @@ fn main() { "compiler_builtins::float::cmp::__aeabi_dcmpgt(a, b)"); } + // float/extend.rs + gen(|a: MyF32| { + if a.0.is_nan() { + return None; + } + Some(f64(a.0)) + }, + "compiler_builtins::float::extend::__extendsfdf2(a)"); + // float/conv.rs gen(|a: MyF64| i64(a.0).ok(), "compiler_builtins::float::conv::__fixdfdi(a)"); From 178b78b92491b723ae3914e62674118ad756762e Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Fri, 9 Feb 2018 17:13:45 +0100 Subject: [PATCH 0435/4206] Fix issue extending f32::MIN/MAX to f64 and improve testcrate. I was able to trigger an issue extending f32::MAX or f32::MIN to a f64. Issue was not triggered by `testcrate` mainly because f32::MAX/MIN are not in the list of special values to generate. This PR fix the issue and improve `testcrate` adding MAX/MIN/MIN_POSITIVE in the list of special values. --- library/compiler-builtins/src/float/extend.rs | 2 +- library/compiler-builtins/testcrate/build.rs | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index 1abb23c3f923a..a71b7a12c8adf 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -41,7 +41,7 @@ fn extend(a: F) -> R where let abs_dst: R::Int = a_abs.cast(); let bias_dst: R::Int = exp_bias_delta.cast(); abs_result = abs_dst.wrapping_shl(sign_bits_delta); - abs_result |= bias_dst.wrapping_shl(dst_sign_bits); + abs_result += bias_dst.wrapping_shl(dst_sign_bits); } else if a_abs >= src_infinity { // a is NaN or infinity. // Conjure the result by beginning with infinity, then setting the qNaN diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 9269983c7b76a..40cc1db350c1a 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -703,6 +703,9 @@ macro_rules! gen_float { // Special values *rng.choose(&[-0.0, 0.0, + ::std::$fty::MIN, + ::std::$fty::MIN_POSITIVE, + ::std::$fty::MAX, ::std::$fty::NAN, ::std::$fty::INFINITY, -::std::$fty::INFINITY]) @@ -754,6 +757,9 @@ macro_rules! gen_large_float { // Special values *rng.choose(&[-0.0, 0.0, + ::std::$fty::MIN, + ::std::$fty::MIN_POSITIVE, + ::std::$fty::MAX, ::std::$fty::NAN, ::std::$fty::INFINITY, -::std::$fty::INFINITY]) From f70ccac08e4229480bc2c55bdfef8dd632fa0d7d Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Fri, 9 Feb 2018 20:35:55 +0100 Subject: [PATCH 0436/4206] Fix __subsf3 and __subdf3 on x86 Be sure to do not mix hard-float and soft-float calls. Disassembled code show exactly this. So replace add with an explicit call to __addsf3/__adddf3 This seems the root cause of some sporadic failures. --- library/compiler-builtins/src/float/sub.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index c2791bf9291e3..2afb1409b3220 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -1,14 +1,16 @@ use float::Float; +use float::add::__addsf3; +use float::add::__adddf3; intrinsics! { #[arm_aeabi_alias = __aeabi_fsub] pub extern "C" fn __subsf3(a: f32, b: f32) -> f32 { - a + f32::from_repr(b.repr() ^ f32::SIGN_MASK) + __addsf3(a, f32::from_repr(b.repr() ^ f32::SIGN_MASK)) } #[arm_aeabi_alias = __aeabi_dsub] pub extern "C" fn __subdf3(a: f64, b: f64) -> f64 { - a + f64::from_repr(b.repr() ^ f64::SIGN_MASK) + __adddf3(a, f64::from_repr(b.repr() ^ f64::SIGN_MASK)) } #[cfg(target_arch = "arm")] From 4e1ff92946650486828250957fc27a56780036c3 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sun, 11 Feb 2018 21:17:42 +0100 Subject: [PATCH 0437/4206] Set -mfloat-abi=hard not only for thumb targets --- library/compiler-builtins/build.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 0d32e976258d7..6a057270e5c9e 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -103,7 +103,9 @@ mod c { let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap(); let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap(); - + let target_arch_arm = + target_arch.contains("arm") || + target_arch.contains("thumb"); let cfg = &mut cc::Build::new(); cfg.warnings(false); @@ -137,10 +139,10 @@ mod c { // the implementation is not valid for the arch, then gcc will error when compiling it. if llvm_target[0].starts_with("thumb") { cfg.flag("-mthumb"); + } - if llvm_target.last() == Some(&"eabihf") { - cfg.flag("-mfloat-abi=hard"); - } + if target_arch_arm && llvm_target.last() == Some(&"eabihf") { + cfg.flag("-mfloat-abi=hard"); } if llvm_target[0] == "thumbv6m" { From b2aea631feb69ca6cbff38d6dc6fea9801d78bcd Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sun, 11 Feb 2018 23:46:56 +0100 Subject: [PATCH 0438/4206] Collection of VFP intrinsics Nothing really exciting here. LLVM on hard-float target use native instructions for all listed VFP intrinsics and so resulting implementation is really trivial. Implemented intrinsics: __gesf2vfp __gedf2vfp __gtsf2vfp __gtdf2vfp __ltsf2vfp __ltdf2vfp __nesf2vfp __nedf2vfp __eqsf2vfp __eqdf2vfp __extendsfdf2vfp --- library/compiler-builtins/README.md | 24 +++--- library/compiler-builtins/build.rs | 11 --- library/compiler-builtins/src/float/cmp.rs | 43 ++++++++++ library/compiler-builtins/src/float/extend.rs | 5 ++ library/compiler-builtins/testcrate/build.rs | 80 +++++++++++++++++++ 5 files changed, 140 insertions(+), 23 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 30abd928e0200..8d59594e06e82 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -100,9 +100,9 @@ features = ["c"] - [ ] arm/divmodsi4.S (generic version is done) - [x] arm/divsf3vfp.S - [ ] arm/divsi3.S (generic version is done) -- [ ] arm/eqdf2vfp.S -- [ ] arm/eqsf2vfp.S -- [ ] arm/extendsfdf2vfp.S +- [x] arm/eqdf2vfp.S +- [x] arm/eqsf2vfp.S +- [x] arm/extendsfdf2vfp.S - [ ] arm/fixdfsivfp.S - [ ] arm/fixsfsivfp.S - [ ] arm/fixunsdfsivfp.S @@ -111,22 +111,22 @@ features = ["c"] - [ ] arm/floatsisfvfp.S - [ ] arm/floatunssidfvfp.S - [ ] arm/floatunssisfvfp.S -- [ ] arm/gedf2vfp.S -- [ ] arm/gesf2vfp.S -- [ ] arm/gtdf2vfp.S -- [ ] arm/gtsf2vfp.S +- [x] arm/gedf2vfp.S +- [x] arm/gesf2vfp.S +- [x] arm/gtdf2vfp.S +- [x] arm/gtsf2vfp.S - [ ] arm/ledf2vfp.S - [ ] arm/lesf2vfp.S -- [ ] arm/ltdf2vfp.S -- [ ] arm/ltsf2vfp.S +- [x] arm/ltdf2vfp.S +- [x] arm/ltsf2vfp.S - [ ] arm/modsi3.S (generic version is done) - [x] arm/muldf3vfp.S - [x] arm/mulsf3vfp.S -- [ ] arm/nedf2vfp.S +- [x] arm/nedf2vfp.S - [ ] arm/negdf2vfp.S - [ ] arm/negsf2vfp.S -- [ ] arm/nesf2vfp.S -- [ ] arm/softfloat-alias.list +- [x] arm/nesf2vfp.S +- [x] arm/softfloat-alias.list - [x] arm/subdf3vfp.S - [x] arm/subsf3vfp.S - [ ] arm/truncdfsf2vfp.S diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 6a057270e5c9e..594afbded8130 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -376,9 +376,6 @@ mod c { if !llvm_target[0].starts_with("thumbv7em") { sources.extend( &[ - "arm/eqdf2vfp.S", - "arm/eqsf2vfp.S", - "arm/extendsfdf2vfp.S", "arm/fixdfsivfp.S", "arm/fixsfsivfp.S", "arm/fixunsdfsivfp.S", @@ -387,16 +384,8 @@ mod c { "arm/floatsisfvfp.S", "arm/floatunssidfvfp.S", "arm/floatunssisfvfp.S", - "arm/gedf2vfp.S", - "arm/gesf2vfp.S", - "arm/gtdf2vfp.S", - "arm/gtsf2vfp.S", "arm/ledf2vfp.S", "arm/lesf2vfp.S", - "arm/ltdf2vfp.S", - "arm/ltsf2vfp.S", - "arm/nedf2vfp.S", - "arm/nesf2vfp.S", "arm/restore_vfp_d8_d15_regs.S", "arm/save_vfp_d8_d15_regs.S", ], diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 4986d056052b1..16b059e157d3d 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -212,4 +212,47 @@ intrinsics! { pub extern "aapcs" fn __aeabi_dcmpgt(a: f64, b: f64) -> i32 { (__gtdf2(a, b) > 0) as i32 } + + // On hard-float targets LLVM will use native instructions + // for all VFP intrinsics below + + pub extern "C" fn __gesf2vfp(a: f32, b: f32) -> i32 { + (a >= b) as i32 + } + + pub extern "C" fn __gedf2vfp(a: f64, b: f64) -> i32 { + (a >= b) as i32 + } + + pub extern "C" fn __gtsf2vfp(a: f32, b: f32) -> i32 { + (a > b) as i32 + } + + pub extern "C" fn __gtdf2vfp(a: f64, b: f64) -> i32 { + (a > b) as i32 + } + + pub extern "C" fn __ltsf2vfp(a: f32, b: f32) -> i32 { + (a < b) as i32 + } + + pub extern "C" fn __ltdf2vfp(a: f64, b: f64) -> i32 { + (a < b) as i32 + } + + pub extern "C" fn __nesf2vfp(a: f32, b: f32) -> i32 { + (a != b) as i32 + } + + pub extern "C" fn __nedf2vfp(a: f64, b: f64) -> i32 { + (a != b) as i32 + } + + pub extern "C" fn __eqsf2vfp(a: f32, b: f32) -> i32 { + (a == b) as i32 + } + + pub extern "C" fn __eqdf2vfp(a: f64, b: f64) -> i32 { + (a == b) as i32 + } } diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index a71b7a12c8adf..0ca9cf57a58d3 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -74,4 +74,9 @@ intrinsics! { pub extern "C" fn __extendsfdf2(a: f32) -> f64 { extend(a) } + + #[cfg(target_arch = "arm")] + pub extern "C" fn __extendsfdf2vfp(a: f32) -> f64 { + a as f64 // LLVM generate 'fcvtds' + } } \ No newline at end of file diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 40cc1db350c1a..d3850cc5cb5c4 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -233,6 +233,77 @@ fn main() { Some(c) }, "compiler_builtins::float::cmp::__aeabi_dcmpgt(a, b)"); + + gen(|(a, b): (LargeF32, LargeF32)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + Some((a.0 >= b.0) as i32) + }, + "compiler_builtins::float::cmp::__gesf2vfp(a, b)"); + gen(|(a, b): (MyF64, MyF64)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + Some((a.0 >= b.0) as i32) + }, + "compiler_builtins::float::cmp::__gedf2vfp(a, b)"); + gen(|(a, b): (LargeF32, LargeF32)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + Some((a.0 > b.0) as i32) + }, + "compiler_builtins::float::cmp::__gtsf2vfp(a, b)"); + gen(|(a, b): (MyF64, MyF64)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + Some((a.0 > b.0) as i32) + }, + "compiler_builtins::float::cmp::__gtdf2vfp(a, b)"); + gen(|(a, b): (LargeF32, LargeF32)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + Some((a.0 < b.0) as i32) + }, + "compiler_builtins::float::cmp::__ltsf2vfp(a, b)"); + gen(|(a, b): (MyF64, MyF64)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + Some((a.0 < b.0) as i32) + }, + "compiler_builtins::float::cmp::__ltdf2vfp(a, b)"); + gen(|(a, b): (LargeF32, LargeF32)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + Some((a.0 != b.0) as i32) + }, + "compiler_builtins::float::cmp::__nesf2vfp(a, b)"); + gen(|(a, b): (MyF64, MyF64)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + Some((a.0 != b.0) as i32) + }, + "compiler_builtins::float::cmp::__nedf2vfp(a, b)"); + gen(|(a, b): (LargeF32, LargeF32)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + Some((a.0 == b.0) as i32) + }, + "compiler_builtins::float::cmp::__eqsf2vfp(a, b)"); + gen(|(a, b): (MyF64, MyF64)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + Some((a.0 == b.0) as i32) + }, + "compiler_builtins::float::cmp::__eqdf2vfp(a, b)"); } // float/extend.rs @@ -243,6 +314,15 @@ fn main() { Some(f64(a.0)) }, "compiler_builtins::float::extend::__extendsfdf2(a)"); + if target_arch_arm { + gen(|a: LargeF32| { + if a.0.is_nan() { + return None; + } + Some(f64(a.0)) + }, + "compiler_builtins::float::extend::__extendsfdf2vfp(a)"); + } // float/conv.rs gen(|a: MyF64| i64(a.0).ok(), From 347871f7ecbf2b4ad3101d3292c43e4174dcd460 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Mon, 12 Feb 2018 18:23:55 +0100 Subject: [PATCH 0439/4206] Update Progress list Already implemented, but not marked as done. --- library/compiler-builtins/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 8d59594e06e82..823877b8f5d6f 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -87,8 +87,8 @@ features = ["c"] - [x] addsf3.c - [x] arm/adddf3vfp.S - [x] arm/addsf3vfp.S -- [ ] arm/aeabi_dcmp.S -- [ ] arm/aeabi_fcmp.S +- [x] arm/aeabi_dcmp.S +- [x] arm/aeabi_fcmp.S - [x] arm/aeabi_idivmod.S - [x] arm/aeabi_ldivmod.S - [x] arm/aeabi_memcpy.S @@ -183,8 +183,8 @@ features = ["c"] - [x] mulsf3.c - [x] powidf2.c - [x] powisf2.c -- [ ] subdf3.c -- [ ] subsf3.c +- [x] subdf3.c +- [x] subsf3.c - [ ] truncdfhf2.c - [ ] truncdfsf2.c - [ ] truncsfhf2.c From 63b78c86d93484a3721c53faf9bd60311063b64f Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Fri, 16 Feb 2018 17:31:25 +0100 Subject: [PATCH 0440/4206] Fix thumbv6m build (feature=c) 1. Avoid undefined references as: undefined reference to `__modsi3' undefined reference to `__umodsi3' 2. We can't remove assembly implementations that are not in the list --- library/compiler-builtins/build.rs | 5 ----- library/compiler-builtins/src/int/sdiv.rs | 7 +++++-- library/compiler-builtins/src/int/udiv.rs | 4 +++- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 594afbded8130..9eca26c1dd9b5 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -423,13 +423,8 @@ mod c { if llvm_target[0] == "thumbv6m" { sources.remove( &[ - "aeabi_cdcmp", - "aeabi_cfcmp", - "aeabi_dcmp", - "aeabi_fcmp", "clzdi2", "clzsi2", - "comparesf2", "divmodsi4", "modsi3", "switch16", diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 2f09bd51d91be..2de73b0eab7cc 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -72,7 +72,9 @@ intrinsics! { a.div(b) } - #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios")))] + #[use_c_shim_if(all(target_arch = "arm", + not(target_os = "ios")), + not(thumbv6m))] pub extern "C" fn __modsi3(a: i32, b: i32) -> i32 { a.mod_(b) } @@ -87,7 +89,8 @@ intrinsics! { a.mod_(b) } - #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios")))] + #[use_c_shim_if(all(target_arch = "arm", + not(target_os = "ios"), not(thumbv6m)))] pub extern "C" fn __divmodsi4(a: i32, b: i32, rem: &mut i32) -> i32 { a.divmod(b, rem, |a, b| __divsi3(a, b)) } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 1d93e177b5b50..4382460e78285 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -209,7 +209,9 @@ intrinsics! { (q << 1) | carry } - #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios")))] + #[use_c_shim_if(all(target_arch = "arm", + not(target_os = "ios"), + not(thumbv6m)))] /// Returns `n % d` pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { let q = __udivsi3(n, d); From 64ea229988b28445007e7c15a0d4ebcbbdb4024a Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sun, 18 Feb 2018 18:15:57 +0100 Subject: [PATCH 0441/4206] Fix CI for thumb* targets Main fix is inside 'utest' all the rest are minor fixes due to the new 'testcrate'. Still allow failures on TravisCI for a while. --- library/compiler-builtins/ci/run.sh | 29 ++++++++++--------- .../compiler-builtins/testcrate/Cargo.toml | 11 ++++--- .../compiler-builtins/testcrate/src/lib.rs | 2 ++ .../testcrate/tests/aeabi_memclr.rs | 1 + .../testcrate/tests/aeabi_memcpy.rs | 1 + .../testcrate/tests/aeabi_memset.rs | 1 + .../testcrate/tests/generated.rs | 29 +++++++++++++++++++ 7 files changed, 56 insertions(+), 18 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index bc40e2d603c55..3196400f153c1 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -24,29 +24,30 @@ fi # Test our implementation case $1 in thumb*) - for t in $(ls tests); do + run="xargo test --manifest-path testcrate/Cargo.toml --target $1" + for t in $(ls testcrate/tests); do t=${t%.rs} - # TODO(#154) enable these tests when aeabi_*mul are implemented - case $t in - powi*f2) - continue - ;; - esac - - xargo test --test $t --target $1 --features 'mem gen-tests' --no-run + RUSTFLAGS="-C debug-assertions=no -C lto" \ + CARGO_INCREMENTAL=0 \ + $run --test $t --features 'no_std mem c' --no-run qemu-arm-static target/${1}/debug/$t-* + done - xargo test --test $t --target $1 --features 'mem gen-tests' --no-run --release + for t in $(ls testcrate/tests); do + t=${t%.rs} + RUSTFLAGS="-C lto" \ + CARGO_INCREMENTAL=0 \ + $run --test $t --features 'no_std mem c' --no-run --release qemu-arm-static target/${1}/release/$t-* done ;; *) run="cargo test --manifest-path testcrate/Cargo.toml --target $1" - $run - $run --release - $run --features c - $run --features c --release + $run --features mangled-names + $run --features mangled-names --release + $run --features 'mangled-names c' + $run --features 'mangled-names c' --release ;; esac diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 834df68775b3e..d88acda365d05 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -14,12 +14,15 @@ rand = { version = "0.4", features = ["i128_support"] } [dependencies.compiler_builtins] path = ".." default-features = false -features = ["mangled-names", "no-lang-items"] +features = ["no-lang-items"] [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" } +test = { git = "https://github.com/paoloteti/utest", branch = "ci" } +utest-cortex-m-qemu = { default-features = false, git = "https://github.com/paoloteti/utest", branch = "ci" } +utest-macros = { git = "https://github.com/paoloteti/utest", branch = "ci" } [features] c = ["compiler_builtins/c"] +mem = ["compiler_builtins/mem"] +mangled-names = ["compiler_builtins/mangled-names"] +no_std = [] diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index 31e1bb209f98e..ae9e4e2f5c5a7 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -1,3 +1,5 @@ +#![cfg_attr(feature = "no_std", no_std)] + #[cfg(test)] mod tests { #[test] diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs b/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs index 72e944e4c74e4..08fbd4fa9f245 100644 --- a/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs +++ b/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs @@ -3,6 +3,7 @@ target_os = "linux", feature = "mem"))] #![feature(compiler_builtins_lib)] +#![feature(lang_items)] #![no_std] extern crate compiler_builtins; diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs b/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs index 2ba942c23c16c..76dad899263a5 100644 --- a/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs +++ b/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs @@ -3,6 +3,7 @@ target_os = "linux", feature = "mem"))] #![feature(compiler_builtins_lib)] +#![feature(lang_items)] #![no_std] extern crate compiler_builtins; diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memset.rs b/library/compiler-builtins/testcrate/tests/aeabi_memset.rs index 0919f149124f0..71fe37e3582e7 100644 --- a/library/compiler-builtins/testcrate/tests/aeabi_memset.rs +++ b/library/compiler-builtins/testcrate/tests/aeabi_memset.rs @@ -3,6 +3,7 @@ target_os = "linux", feature = "mem"))] #![feature(compiler_builtins_lib)] +#![feature(lang_items)] #![no_std] extern crate compiler_builtins; diff --git a/library/compiler-builtins/testcrate/tests/generated.rs b/library/compiler-builtins/testcrate/tests/generated.rs index 1a43f436e0b41..1263dc261d6f7 100644 --- a/library/compiler-builtins/testcrate/tests/generated.rs +++ b/library/compiler-builtins/testcrate/tests/generated.rs @@ -1,6 +1,35 @@ +#![feature(compiler_builtins_lib)] #![feature(i128_type)] +#![feature(lang_items, core_float, core_float_bits)] #![allow(bad_style)] +#![allow(unused_imports)] +#![no_std] + +use core::num::Float; extern crate compiler_builtins; +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +extern crate utest_cortex_m_qemu; + +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +#[macro_use] +extern crate utest_macros; + +#[cfg(all(target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test))] +macro_rules! panic { // overrides `panic!` + ($($tt:tt)*) => { + upanic!($($tt)*); + }; +} + include!(concat!(env!("OUT_DIR"), "/generated.rs")); From e319f042fd12e536db438f15d85f49ceeee3ffbe Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sat, 24 Feb 2018 22:48:27 +0100 Subject: [PATCH 0442/4206] Use upstream for utest Fix has been merged into upstream. --- library/compiler-builtins/testcrate/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index d88acda365d05..7544d94fe3dd8 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -17,9 +17,9 @@ default-features = false features = ["no-lang-items"] [target.'cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux"))'.dev-dependencies] -test = { git = "https://github.com/paoloteti/utest", branch = "ci" } -utest-cortex-m-qemu = { default-features = false, git = "https://github.com/paoloteti/utest", branch = "ci" } -utest-macros = { git = "https://github.com/paoloteti/utest", branch = "ci" } +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"] From ef48c1984b78a2b65c593d6fca20dcc77615c454 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sun, 25 Feb 2018 00:22:39 +0100 Subject: [PATCH 0443/4206] testcrate/lib.rs: use #![no_std] unconditionally --- library/compiler-builtins/testcrate/src/lib.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index ae9e4e2f5c5a7..2e7f0d4d752b9 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -1,9 +1 @@ -#![cfg_attr(feature = "no_std", no_std)] - -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} +#![no_std] \ No newline at end of file From 81356ccde422207be4921bc72fc5cd5f61bec5ec Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sun, 25 Feb 2018 01:11:49 +0100 Subject: [PATCH 0444/4206] Keep mangled-names as a default feature --- library/compiler-builtins/ci/run.sh | 14 ++++++++------ library/compiler-builtins/testcrate/Cargo.toml | 1 + 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 3196400f153c1..8ce706c2815d8 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -30,7 +30,8 @@ case $1 in RUSTFLAGS="-C debug-assertions=no -C lto" \ CARGO_INCREMENTAL=0 \ - $run --test $t --features 'no_std mem c' --no-run + $run --test $t --no-default-features \ + --features 'no_std mem c' --no-run qemu-arm-static target/${1}/debug/$t-* done @@ -38,16 +39,17 @@ case $1 in t=${t%.rs} RUSTFLAGS="-C lto" \ CARGO_INCREMENTAL=0 \ - $run --test $t --features 'no_std mem c' --no-run --release + $run --test $t --no-default-features \ + --features 'no_std mem c' --no-run --release qemu-arm-static target/${1}/release/$t-* done ;; *) run="cargo test --manifest-path testcrate/Cargo.toml --target $1" - $run --features mangled-names - $run --features mangled-names --release - $run --features 'mangled-names c' - $run --features 'mangled-names c' --release + $run + $run --release + $run --features c + $run --features c --release ;; esac diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 7544d94fe3dd8..eae66ce2e19f8 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -25,4 +25,5 @@ utest-macros = { git = "https://github.com/japaric/utest" } c = ["compiler_builtins/c"] mem = ["compiler_builtins/mem"] mangled-names = ["compiler_builtins/mangled-names"] +default = ["mangled-names"] no_std = [] From d7799358e41ad35be3b9708e36dc7f047808a059 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sun, 25 Feb 2018 09:19:34 +0100 Subject: [PATCH 0445/4206] Remove no_std features Everything default unconditionally to #![no_std]. --- library/compiler-builtins/ci/run.sh | 6 ++---- library/compiler-builtins/testcrate/Cargo.toml | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 8ce706c2815d8..8c85038f97a7d 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -30,8 +30,7 @@ case $1 in RUSTFLAGS="-C debug-assertions=no -C lto" \ CARGO_INCREMENTAL=0 \ - $run --test $t --no-default-features \ - --features 'no_std mem c' --no-run + $run --test $t --no-default-features --features 'mem c' --no-run qemu-arm-static target/${1}/debug/$t-* done @@ -39,8 +38,7 @@ case $1 in t=${t%.rs} RUSTFLAGS="-C lto" \ CARGO_INCREMENTAL=0 \ - $run --test $t --no-default-features \ - --features 'no_std mem c' --no-run --release + $run --test $t --no-default-features --features 'mem c' --no-run --release qemu-arm-static target/${1}/release/$t-* done ;; diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index eae66ce2e19f8..2a102660b2f75 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -26,4 +26,3 @@ c = ["compiler_builtins/c"] mem = ["compiler_builtins/mem"] mangled-names = ["compiler_builtins/mangled-names"] default = ["mangled-names"] -no_std = [] From 20de84d127eeb07fa4bae34960dcaa35a6124aac Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sun, 25 Feb 2018 17:50:56 +0100 Subject: [PATCH 0446/4206] Add __ledf2vfp and __lesf2vfp Now that `73884ae` is in some nightly release We can add ledf2vfp/leds2vfp and so these two functions be aliased to aeabi_fcmple/aeabi_dcmple on soft-float targets. --- library/compiler-builtins/README.md | 4 ++-- library/compiler-builtins/src/float/cmp.rs | 8 ++++++++ library/compiler-builtins/testcrate/build.rs | 14 ++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 823877b8f5d6f..cef2fb0974a77 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -115,8 +115,8 @@ features = ["c"] - [x] arm/gesf2vfp.S - [x] arm/gtdf2vfp.S - [x] arm/gtsf2vfp.S -- [ ] arm/ledf2vfp.S -- [ ] arm/lesf2vfp.S +- [x] arm/ledf2vfp.S +- [x] arm/lesf2vfp.S - [x] arm/ltdf2vfp.S - [x] arm/ltsf2vfp.S - [ ] arm/modsi3.S (generic version is done) diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 16b059e157d3d..01dd890550bc7 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -240,6 +240,14 @@ intrinsics! { (a < b) as i32 } + pub extern "C" fn __lesf2vfp(a: f32, b: f32) -> i32 { + (a <= b) as i32 + } + + pub extern "C" fn __ledf2vfp(a: f64, b: f64) -> i32 { + (a <= b) as i32 + } + pub extern "C" fn __nesf2vfp(a: f32, b: f32) -> i32 { (a != b) as i32 } diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index d3850cc5cb5c4..92e0b5d4c0127 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -276,6 +276,20 @@ fn main() { Some((a.0 < b.0) as i32) }, "compiler_builtins::float::cmp::__ltdf2vfp(a, b)"); + gen(|(a, b): (LargeF32, LargeF32)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + Some((a.0 <= b.0) as i32) + }, + "compiler_builtins::float::cmp::__lesf2vfp(a, b)"); + gen(|(a, b): (MyF64, MyF64)| { + if a.0.is_nan() || b.0.is_nan() { + return None; + } + Some((a.0 <= b.0) as i32) + }, + "compiler_builtins::float::cmp::__ledf2vfp(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { return None; From 6fedebb1661bdc027e360ac935020d28c969e349 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sun, 25 Feb 2018 18:35:36 +0100 Subject: [PATCH 0447/4206] Add missing test cases for __unordsf2/__unorddf2 --- library/compiler-builtins/testcrate/build.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 92e0b5d4c0127..d50dc5623f543 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -143,6 +143,18 @@ fn main() { }, "compiler_builtins::float::cmp::__lesf2(a, b)"); + gen(|(a, b): (MyF32, MyF32)| { + let c = a.0.is_nan() || b.0.is_nan(); + Some(c as i32) + }, + "compiler_builtins::float::cmp::__unordsf2(a, b)"); + + gen(|(a, b): (MyF64, MyF64)| { + let c = a.0.is_nan() || b.0.is_nan(); + Some(c as i32) + }, + "compiler_builtins::float::cmp::__unorddf2(a, b)"); + if target_arch_arm { gen(|(a, b): (MyF32, MyF32)| { if a.0.is_nan() || b.0.is_nan() { From 9fbdac0e38b7caedbbcf56a60dd977ea915216c0 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sun, 25 Feb 2018 19:23:30 +0100 Subject: [PATCH 0448/4206] TravisCI: remove allow_failures for thumb* targets --- library/compiler-builtins/.travis.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index efd0b1738e3e5..898a600eb4179 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -28,11 +28,6 @@ matrix: - env: TARGET=x86_64-apple-darwin os: osx - env: TARGET=x86_64-unknown-linux-gnu - allow_failures: - - env: TARGET=thumbv6m-linux-eabi - - env: TARGET=thumbv7em-linux-eabi - - env: TARGET=thumbv7em-linux-eabihf - - env: TARGET=thumbv7m-linux-eabi install: - case $TARGET in From ad3a5b682613b106c706b28ad1bf34444a419e17 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sun, 25 Feb 2018 19:49:31 +0100 Subject: [PATCH 0449/4206] Remove ledf2vfp.S and lesf2vfp.S from build list --- library/compiler-builtins/build.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 9eca26c1dd9b5..789311051de42 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -384,8 +384,6 @@ mod c { "arm/floatsisfvfp.S", "arm/floatunssidfvfp.S", "arm/floatunssisfvfp.S", - "arm/ledf2vfp.S", - "arm/lesf2vfp.S", "arm/restore_vfp_d8_d15_regs.S", "arm/save_vfp_d8_d15_regs.S", ], From 09d201db355a208952ba8b03587fa953c8b13302 Mon Sep 17 00:00:00 2001 From: Thomas Winwood Date: Sat, 9 Dec 2017 18:40:36 +0000 Subject: [PATCH 0450/4206] Add __floatdisf and __floatundisf intrinsics --- library/compiler-builtins/README.md | 4 ++-- library/compiler-builtins/src/float/conv.rs | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 5606ef4c8463a..cee6679e16ce3 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -150,11 +150,11 @@ features = ["c"] - [x] fixunssfdi.c - [x] fixunssfsi.c - [x] floatdidf.c -- [ ] floatdisf.c +- [x] floatdisf.c - [x] floatsidf.c - [x] floatsisf.c - [x] floatundidf.c -- [ ] floatundisf.c +- [x] floatundisf.c - [x] floatunsidf.c - [x] floatunsisf.c - [ ] i386/ashldi3.S diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 33644ce56aaf3..53844c17b49df 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -80,6 +80,18 @@ intrinsics! { int_to_float!(i, i32, f64) } + #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[arm_aeabi_alias = __aeabi_l2f] + pub extern "C" fn __floatdisf(i: i64) -> f32 { + // On x86_64 LLVM will use native instructions for this conversion, we + // can just do it directly + if cfg!(target_arch = "x86_64") { + i as f32 + } else { + int_to_float!(i, i64, f32) + } + } + #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] #[arm_aeabi_alias = __aeabi_l2d] pub extern "C" fn __floatdidf(i: i64) -> f64 { @@ -112,6 +124,14 @@ intrinsics! { int_to_float!(i, u32, f64) } + #[use_c_shim_if(all(not(target_env = "msvc"), + any(target_arch = "x86", + all(not(windows), target_arch = "x86_64"))))] + #[arm_aeabi_alias = __aeabi_ul2f] + pub extern "C" fn __floatundisf(i: u64) -> f32 { + int_to_float!(i, u64, f32) + } + #[use_c_shim_if(all(not(target_env = "msvc"), any(target_arch = "x86", all(not(windows), target_arch = "x86_64"))))] From f0f2db7490da3bec0c669a31dc8db4cdcb6c0549 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Sat, 17 Mar 2018 21:37:35 -0500 Subject: [PATCH 0451/4206] i128 is being stabilized --- library/compiler-builtins/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 8d8d4a2fee00d..619b6ac7afbdb 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -12,7 +12,6 @@ #![feature(compiler_builtins)] #![feature(core_intrinsics)] #![feature(naked_functions)] -#![feature(i128_type)] #![feature(repr_simd)] #![feature(abi_unadjusted)] #![feature(linkage)] From b90fa1e14fa86fe402c6d1c1e08384947c19a668 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Sun, 18 Mar 2018 14:07:01 -0500 Subject: [PATCH 0452/4206] Put back feature --- library/compiler-builtins/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 619b6ac7afbdb..f10ba757228ed 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -17,6 +17,7 @@ #![feature(linkage)] #![feature(lang_items)] #![allow(unused_features)] +#![feature(i128_type)] #![no_builtins] #![cfg_attr(feature = "compiler-builtins", feature(staged_api))] #![cfg_attr(feature = "compiler-builtins", From 635855abdd31a066f6bdb6d65da5f29c3f53bb99 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Tue, 20 Mar 2018 19:16:13 -0500 Subject: [PATCH 0453/4206] stable_features allowed temporarily --- library/compiler-builtins/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index f10ba757228ed..819967be4aa1e 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -17,6 +17,7 @@ #![feature(linkage)] #![feature(lang_items)] #![allow(unused_features)] +#![allow(stable_features)] // FIXME(mark-i-m): remove after i128 stabilizes #![feature(i128_type)] #![no_builtins] #![cfg_attr(feature = "compiler-builtins", feature(staged_api))] From f83c8529e7216b44b1dbbabc92bf313d8c57f5e3 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Tue, 27 Mar 2018 11:33:57 +0200 Subject: [PATCH 0454/4206] Fix incorrect names used / generated on ARM --- library/compiler-builtins/src/arm.rs | 67 ++++++++++++++++++++++++- library/compiler-builtins/src/macros.rs | 1 + 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 25fdd52429eef..dbd6f87ca522c 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,7 +1,10 @@ use core::intrinsics; // NOTE This function and the ones below are implemented using assembly because they using a custom -// calling convention which can't be implemented using a normal Rust function +// calling convention which can't be implemented using a normal Rust function. +// NOTE The only difference between the iOS and non-iOS versions of those functions is that the iOS +// versions use 3 leading underscores in the names of called functions instead of 2. +#[cfg(not(target_os = "ios"))] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_uidivmod() { @@ -15,6 +18,21 @@ pub unsafe fn __aeabi_uidivmod() { intrinsics::unreachable(); } +#[cfg(target_os = "ios")] +#[naked] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +pub unsafe fn __aeabi_uidivmod() { + asm!("push {lr} + sub sp, sp, #4 + mov r2, sp + bl ___udivmodsi4 + ldr r1, [sp] + add sp, sp, #4 + pop {pc}" ::: "memory" : "volatile"); + intrinsics::unreachable(); +} + +#[cfg(not(target_os = "ios"))] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_uldivmod() { @@ -30,6 +48,23 @@ pub unsafe fn __aeabi_uldivmod() { intrinsics::unreachable(); } +#[cfg(target_os = "ios")] +#[naked] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +pub unsafe fn __aeabi_uldivmod() { + asm!("push {r4, lr} + sub sp, sp, #16 + add r4, sp, #8 + str r4, [sp] + bl ___udivmoddi4 + ldr r2, [sp, #8] + ldr r3, [sp, #12] + add sp, sp, #16 + pop {r4, pc}" ::: "memory" : "volatile"); + intrinsics::unreachable(); +} + +#[cfg(not(target_os = "ios"))] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_idivmod() { @@ -42,6 +77,20 @@ pub unsafe fn __aeabi_idivmod() { intrinsics::unreachable(); } +#[cfg(target_os = "ios")] +#[naked] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +pub unsafe fn __aeabi_idivmod() { + asm!("push {r0, r1, r4, lr} + bl ___aeabi_idiv + pop {r1, r2} + muls r2, r2, r0 + subs r1, r1, r2 + pop {r4, pc}" ::: "memory" : "volatile"); + intrinsics::unreachable(); +} + +#[cfg(not(target_os = "ios"))] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_ldivmod() { @@ -57,6 +106,22 @@ pub unsafe fn __aeabi_ldivmod() { intrinsics::unreachable(); } +#[cfg(target_os = "ios")] +#[naked] +#[cfg_attr(not(feature = "mangled-names"), no_mangle)] +pub unsafe fn __aeabi_ldivmod() { + asm!("push {r4, lr} + sub sp, sp, #16 + add r4, sp, #8 + str r4, [sp] + bl ___divmoddi4 + ldr r2, [sp, #8] + ldr r3, [sp, #12] + add sp, sp, #16 + pop {r4, pc}" ::: "memory" : "volatile"); + intrinsics::unreachable(); +} + // FIXME: The `*4` and `*8` variants should be defined as aliases. #[cfg(not(target_os = "ios"))] diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 58d94958a437f..5f1ab469a0214 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -210,6 +210,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( #[cfg(target_arch = "arm")] + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } From ed6d12ecea3707d22328818efe9aadfcf0612e19 Mon Sep 17 00:00:00 2001 From: Thomas Winwood Date: Thu, 5 Apr 2018 15:03:44 +0100 Subject: [PATCH 0455/4206] Remove reference to C impl of float[un]disf --- library/compiler-builtins/build.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 9c23c20c96545..ab1cc4b273537 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4991,8 +4991,6 @@ mod c { "divxc3.c", "extendsfdf2.c", "extendhfsf2.c", - "floatdisf.c", - "floatundisf.c", "int_util.c", "muldc3.c", "mulsc3.c", From 99d7dde58d76f72a400d22d5ba27d640ab67992f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 11 May 2018 16:45:30 -0700 Subject: [PATCH 0456/4206] Attempt to fix tests on latest nightly --- library/compiler-builtins/testcrate/build.rs | 214 +++++++++--------- .../testcrate/tests/generated.rs | 7 +- 2 files changed, 108 insertions(+), 113 deletions(-) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index d50dc5623f543..d862e0d0ffbf9 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -1,5 +1,3 @@ -#![feature(i128_type, i128)] - extern crate cast; extern crate rand; @@ -40,7 +38,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::add::__adddf3(a, b)"); + "builtins::float::add::__adddf3(a, b)"); gen(|(a, b): (MyF32, MyF32)| { let c = a.0 + b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { @@ -49,7 +47,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::add::__addsf3(a, b)"); + "builtins::float::add::__addsf3(a, b)"); if target_arch_arm { gen(|(a, b): (MyF64, MyF64)| { @@ -60,7 +58,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::add::__adddf3vfp(a, b)"); + "builtins::float::add::__adddf3vfp(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { let c = a.0 + b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { @@ -69,7 +67,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::add::__addsf3vfp(a, b)"); + "builtins::float::add::__addsf3vfp(a, b)"); } @@ -90,7 +88,7 @@ fn main() { Some(0) } }, - "compiler_builtins::float::cmp::__gedf2(a, b)"); + "builtins::float::cmp::__gedf2(a, b)"); gen(|(a, b): (MyF32, MyF32)| { let (a, b) = (a.0, b.0); if a.is_nan() || b.is_nan() { @@ -107,7 +105,7 @@ fn main() { Some(0) } }, - "compiler_builtins::float::cmp::__gesf2(a, b)"); + "builtins::float::cmp::__gesf2(a, b)"); gen(|(a, b): (MyF64, MyF64)| { let (a, b) = (a.0, b.0); if a.is_nan() || b.is_nan() { @@ -124,7 +122,7 @@ fn main() { Some(0) } }, - "compiler_builtins::float::cmp::__ledf2(a, b)"); + "builtins::float::cmp::__ledf2(a, b)"); gen(|(a, b): (MyF32, MyF32)| { let (a, b) = (a.0, b.0); if a.is_nan() || b.is_nan() { @@ -141,19 +139,19 @@ fn main() { Some(0) } }, - "compiler_builtins::float::cmp::__lesf2(a, b)"); + "builtins::float::cmp::__lesf2(a, b)"); gen(|(a, b): (MyF32, MyF32)| { let c = a.0.is_nan() || b.0.is_nan(); Some(c as i32) }, - "compiler_builtins::float::cmp::__unordsf2(a, b)"); + "builtins::float::cmp::__unordsf2(a, b)"); gen(|(a, b): (MyF64, MyF64)| { let c = a.0.is_nan() || b.0.is_nan(); Some(c as i32) }, - "compiler_builtins::float::cmp::__unorddf2(a, b)"); + "builtins::float::cmp::__unorddf2(a, b)"); if target_arch_arm { gen(|(a, b): (MyF32, MyF32)| { @@ -163,7 +161,7 @@ fn main() { let c = (a.0 <= b.0) as i32; Some(c) }, - "compiler_builtins::float::cmp::__aeabi_fcmple(a, b)"); + "builtins::float::cmp::__aeabi_fcmple(a, b)"); gen(|(a, b): (MyF32, MyF32)| { if a.0.is_nan() || b.0.is_nan() { @@ -172,7 +170,7 @@ fn main() { let c = (a.0 >= b.0) as i32; Some(c) }, - "compiler_builtins::float::cmp::__aeabi_fcmpge(a, b)"); + "builtins::float::cmp::__aeabi_fcmpge(a, b)"); gen(|(a, b): (MyF32, MyF32)| { if a.0.is_nan() || b.0.is_nan() { @@ -181,7 +179,7 @@ fn main() { let c = (a.0 == b.0) as i32; Some(c) }, - "compiler_builtins::float::cmp::__aeabi_fcmpeq(a, b)"); + "builtins::float::cmp::__aeabi_fcmpeq(a, b)"); gen(|(a, b): (MyF32, MyF32)| { if a.0.is_nan() || b.0.is_nan() { @@ -190,7 +188,7 @@ fn main() { let c = (a.0 < b.0) as i32; Some(c) }, - "compiler_builtins::float::cmp::__aeabi_fcmplt(a, b)"); + "builtins::float::cmp::__aeabi_fcmplt(a, b)"); gen(|(a, b): (MyF32, MyF32)| { if a.0.is_nan() || b.0.is_nan() { @@ -199,7 +197,7 @@ fn main() { let c = (a.0 > b.0) as i32; Some(c) }, - "compiler_builtins::float::cmp::__aeabi_fcmpgt(a, b)"); + "builtins::float::cmp::__aeabi_fcmpgt(a, b)"); gen(|(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { @@ -208,7 +206,7 @@ fn main() { let c = (a.0 <= b.0) as i32; Some(c) }, - "compiler_builtins::float::cmp::__aeabi_dcmple(a, b)"); + "builtins::float::cmp::__aeabi_dcmple(a, b)"); gen(|(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { @@ -217,7 +215,7 @@ fn main() { let c = (a.0 >= b.0) as i32; Some(c) }, - "compiler_builtins::float::cmp::__aeabi_dcmpge(a, b)"); + "builtins::float::cmp::__aeabi_dcmpge(a, b)"); gen(|(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { @@ -226,7 +224,7 @@ fn main() { let c = (a.0 == b.0) as i32; Some(c) }, - "compiler_builtins::float::cmp::__aeabi_dcmpeq(a, b)"); + "builtins::float::cmp::__aeabi_dcmpeq(a, b)"); gen(|(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { @@ -235,7 +233,7 @@ fn main() { let c = (a.0 < b.0) as i32; Some(c) }, - "compiler_builtins::float::cmp::__aeabi_dcmplt(a, b)"); + "builtins::float::cmp::__aeabi_dcmplt(a, b)"); gen(|(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { @@ -244,7 +242,7 @@ fn main() { let c = (a.0 > b.0) as i32; Some(c) }, - "compiler_builtins::float::cmp::__aeabi_dcmpgt(a, b)"); + "builtins::float::cmp::__aeabi_dcmpgt(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { @@ -252,84 +250,84 @@ fn main() { } Some((a.0 >= b.0) as i32) }, - "compiler_builtins::float::cmp::__gesf2vfp(a, b)"); + "builtins::float::cmp::__gesf2vfp(a, b)"); gen(|(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 >= b.0) as i32) }, - "compiler_builtins::float::cmp::__gedf2vfp(a, b)"); + "builtins::float::cmp::__gedf2vfp(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 > b.0) as i32) }, - "compiler_builtins::float::cmp::__gtsf2vfp(a, b)"); + "builtins::float::cmp::__gtsf2vfp(a, b)"); gen(|(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 > b.0) as i32) }, - "compiler_builtins::float::cmp::__gtdf2vfp(a, b)"); + "builtins::float::cmp::__gtdf2vfp(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 < b.0) as i32) }, - "compiler_builtins::float::cmp::__ltsf2vfp(a, b)"); + "builtins::float::cmp::__ltsf2vfp(a, b)"); gen(|(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 < b.0) as i32) }, - "compiler_builtins::float::cmp::__ltdf2vfp(a, b)"); + "builtins::float::cmp::__ltdf2vfp(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 <= b.0) as i32) }, - "compiler_builtins::float::cmp::__lesf2vfp(a, b)"); + "builtins::float::cmp::__lesf2vfp(a, b)"); gen(|(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 <= b.0) as i32) }, - "compiler_builtins::float::cmp::__ledf2vfp(a, b)"); + "builtins::float::cmp::__ledf2vfp(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 != b.0) as i32) }, - "compiler_builtins::float::cmp::__nesf2vfp(a, b)"); + "builtins::float::cmp::__nesf2vfp(a, b)"); gen(|(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 != b.0) as i32) }, - "compiler_builtins::float::cmp::__nedf2vfp(a, b)"); + "builtins::float::cmp::__nedf2vfp(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 == b.0) as i32) }, - "compiler_builtins::float::cmp::__eqsf2vfp(a, b)"); + "builtins::float::cmp::__eqsf2vfp(a, b)"); gen(|(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 == b.0) as i32) }, - "compiler_builtins::float::cmp::__eqdf2vfp(a, b)"); + "builtins::float::cmp::__eqdf2vfp(a, b)"); } // float/extend.rs @@ -339,7 +337,7 @@ fn main() { } Some(f64(a.0)) }, - "compiler_builtins::float::extend::__extendsfdf2(a)"); + "builtins::float::extend::__extendsfdf2(a)"); if target_arch_arm { gen(|a: LargeF32| { if a.0.is_nan() { @@ -347,55 +345,55 @@ fn main() { } Some(f64(a.0)) }, - "compiler_builtins::float::extend::__extendsfdf2vfp(a)"); + "builtins::float::extend::__extendsfdf2vfp(a)"); } // float/conv.rs gen(|a: MyF64| i64(a.0).ok(), - "compiler_builtins::float::conv::__fixdfdi(a)"); + "builtins::float::conv::__fixdfdi(a)"); gen(|a: MyF64| i32(a.0).ok(), - "compiler_builtins::float::conv::__fixdfsi(a)"); + "builtins::float::conv::__fixdfsi(a)"); gen(|a: MyF32| i64(a.0).ok(), - "compiler_builtins::float::conv::__fixsfdi(a)"); + "builtins::float::conv::__fixsfdi(a)"); gen(|a: MyF32| i32(a.0).ok(), - "compiler_builtins::float::conv::__fixsfsi(a)"); + "builtins::float::conv::__fixsfsi(a)"); gen(|a: MyF32| i128(a.0).ok(), - "compiler_builtins::float::conv::__fixsfti(a)"); + "builtins::float::conv::__fixsfti(a)"); gen(|a: MyF64| i128(a.0).ok(), - "compiler_builtins::float::conv::__fixdfti(a)"); + "builtins::float::conv::__fixdfti(a)"); gen(|a: MyF64| u64(a.0).ok(), - "compiler_builtins::float::conv::__fixunsdfdi(a)"); + "builtins::float::conv::__fixunsdfdi(a)"); gen(|a: MyF64| u32(a.0).ok(), - "compiler_builtins::float::conv::__fixunsdfsi(a)"); + "builtins::float::conv::__fixunsdfsi(a)"); gen(|a: MyF32| u64(a.0).ok(), - "compiler_builtins::float::conv::__fixunssfdi(a)"); + "builtins::float::conv::__fixunssfdi(a)"); gen(|a: MyF32| u32(a.0).ok(), - "compiler_builtins::float::conv::__fixunssfsi(a)"); + "builtins::float::conv::__fixunssfsi(a)"); gen(|a: MyF32| u128(a.0).ok(), - "compiler_builtins::float::conv::__fixunssfti(a)"); + "builtins::float::conv::__fixunssfti(a)"); gen(|a: MyF64| u128(a.0).ok(), - "compiler_builtins::float::conv::__fixunsdfti(a)"); + "builtins::float::conv::__fixunsdfti(a)"); gen(|a: MyI64| Some(f64(a.0)), - "compiler_builtins::float::conv::__floatdidf(a)"); + "builtins::float::conv::__floatdidf(a)"); gen(|a: MyI32| Some(f64(a.0)), - "compiler_builtins::float::conv::__floatsidf(a)"); + "builtins::float::conv::__floatsidf(a)"); gen(|a: MyI32| Some(f32(a.0)), - "compiler_builtins::float::conv::__floatsisf(a)"); + "builtins::float::conv::__floatsisf(a)"); gen(|a: MyU64| Some(f64(a.0)), - "compiler_builtins::float::conv::__floatundidf(a)"); + "builtins::float::conv::__floatundidf(a)"); gen(|a: MyU32| Some(f64(a.0)), - "compiler_builtins::float::conv::__floatunsidf(a)"); + "builtins::float::conv::__floatunsidf(a)"); gen(|a: MyU32| Some(f32(a.0)), - "compiler_builtins::float::conv::__floatunsisf(a)"); + "builtins::float::conv::__floatunsisf(a)"); gen(|a: MyU128| f32(a.0).ok(), - "compiler_builtins::float::conv::__floatuntisf(a)"); + "builtins::float::conv::__floatuntisf(a)"); if !target_arch_mips { gen(|a: MyI128| Some(f32(a.0)), - "compiler_builtins::float::conv::__floattisf(a)"); + "builtins::float::conv::__floattisf(a)"); gen(|a: MyI128| Some(f64(a.0)), - "compiler_builtins::float::conv::__floattidf(a)"); + "builtins::float::conv::__floattidf(a)"); gen(|a: MyU128| Some(f64(a.0)), - "compiler_builtins::float::conv::__floatuntidf(a)"); + "builtins::float::conv::__floatuntidf(a)"); } // float/pow.rs @@ -407,7 +405,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::pow::__powidf2(a, b)"); + "builtins::float::pow::__powidf2(a, b)"); gen(|(a, b): (MyF32, MyI32)| { let c = a.0.powi(b.0); if a.0.is_nan() || c.is_nan() { @@ -416,7 +414,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::pow::__powisf2(a, b)"); + "builtins::float::pow::__powisf2(a, b)"); // float/sub.rs gen(|(a, b): (MyF64, MyF64)| { @@ -427,7 +425,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::sub::__subdf3(a, b)"); + "builtins::float::sub::__subdf3(a, b)"); gen(|(a, b): (MyF32, MyF32)| { let c = a.0 - b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { @@ -436,7 +434,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::sub::__subsf3(a, b)"); + "builtins::float::sub::__subsf3(a, b)"); if target_arch_arm { gen(|(a, b): (MyF64, MyF64)| { @@ -447,7 +445,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::sub::__subdf3vfp(a, b)"); + "builtins::float::sub::__subdf3vfp(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { let c = a.0 - b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { @@ -456,7 +454,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::sub::__subsf3vfp(a, b)"); + "builtins::float::sub::__subsf3vfp(a, b)"); } // float/mul.rs @@ -468,7 +466,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::mul::__muldf3(a, b)"); + "builtins::float::mul::__muldf3(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { let c = a.0 * b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { @@ -477,7 +475,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::mul::__mulsf3(a, b)"); + "builtins::float::mul::__mulsf3(a, b)"); if target_arch_arm { gen(|(a, b): (MyF64, MyF64)| { @@ -488,7 +486,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::mul::__muldf3vfp(a, b)"); + "builtins::float::mul::__muldf3vfp(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { let c = a.0 * b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { @@ -497,7 +495,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::mul::__mulsf3vfp(a, b)"); + "builtins::float::mul::__mulsf3vfp(a, b)"); } // float/div.rs @@ -514,7 +512,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::div::__divdf3(a, b)"); + "builtins::float::div::__divdf3(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { if b.0 == 0.0 { return None @@ -528,7 +526,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::div::__divsf3(a, b)"); + "builtins::float::div::__divsf3(a, b)"); if target_arch_arm { gen(|(a, b): (MyF64, MyF64)| { @@ -544,7 +542,7 @@ fn main() { Some(c) } }, - "compiler_builtins::float::div::__divdf3vfp(a, b)"); + "builtins::float::div::__divdf3vfp(a, b)"); gen(|(a, b): (LargeF32, LargeF32)| { if b.0 == 0.0 { return None @@ -558,49 +556,49 @@ fn main() { Some(c) } }, - "compiler_builtins::float::div::__divsf3vfp(a, b)"); + "builtins::float::div::__divsf3vfp(a, b)"); } // int/addsub.rs gen(|(a, b): (MyU128, MyU128)| Some(a.0.wrapping_add(b.0)), - "compiler_builtins::int::addsub::rust_u128_add(a, b)"); + "builtins::int::addsub::rust_u128_add(a, b)"); gen(|(a, b): (MyI128, MyI128)| Some(a.0.wrapping_add(b.0)), - "compiler_builtins::int::addsub::rust_i128_add(a, b)"); + "builtins::int::addsub::rust_i128_add(a, b)"); gen(|(a, b): (MyU128, MyU128)| Some(a.0.overflowing_add(b.0)), - "compiler_builtins::int::addsub::rust_u128_addo(a, b)"); + "builtins::int::addsub::rust_u128_addo(a, b)"); gen(|(a, b): (MyI128, MyI128)| Some(a.0.overflowing_add(b.0)), - "compiler_builtins::int::addsub::rust_i128_addo(a, b)"); + "builtins::int::addsub::rust_i128_addo(a, b)"); gen(|(a, b): (MyU128, MyU128)| Some(a.0.wrapping_sub(b.0)), - "compiler_builtins::int::addsub::rust_u128_sub(a, b)"); + "builtins::int::addsub::rust_u128_sub(a, b)"); gen(|(a, b): (MyI128, MyI128)| Some(a.0.wrapping_sub(b.0)), - "compiler_builtins::int::addsub::rust_i128_sub(a, b)"); + "builtins::int::addsub::rust_i128_sub(a, b)"); gen(|(a, b): (MyU128, MyU128)| Some(a.0.overflowing_sub(b.0)), - "compiler_builtins::int::addsub::rust_u128_subo(a, b)"); + "builtins::int::addsub::rust_u128_subo(a, b)"); gen(|(a, b): (MyI128, MyI128)| Some(a.0.overflowing_sub(b.0)), - "compiler_builtins::int::addsub::rust_i128_subo(a, b)"); + "builtins::int::addsub::rust_i128_subo(a, b)"); // int/mul.rs gen(|(a, b): (MyU64, MyU64)| Some(a.0.wrapping_mul(b.0)), - "compiler_builtins::int::mul::__muldi3(a, b)"); + "builtins::int::mul::__muldi3(a, b)"); gen(|(a, b): (MyI64, MyI64)| Some(a.0.overflowing_mul(b.0)), "{ let mut o = 2; - let c = compiler_builtins::int::mul::__mulodi4(a, b, &mut o); + let c = builtins::int::mul::__mulodi4(a, b, &mut o); (c, match o { 0 => false, 1 => true, _ => panic!() }) }"); gen(|(a, b): (MyI32, MyI32)| Some(a.0.overflowing_mul(b.0)), "{ let mut o = 2; - let c = compiler_builtins::int::mul::__mulosi4(a, b, &mut o); + let c = builtins::int::mul::__mulosi4(a, b, &mut o); (c, match o { 0 => false, 1 => true, _ => panic!() }) }"); gen(|(a, b): (MyI128, MyI128)| Some(a.0.wrapping_mul(b.0)), - "compiler_builtins::int::mul::__multi3(a, b)"); + "builtins::int::mul::__multi3(a, b)"); if !target_arch_mips { // FIXME(#137) gen(|(a, b): (MyI128, MyI128)| Some(a.0.overflowing_mul(b.0)), "{ let mut o = 2; - let c = compiler_builtins::int::mul::__muloti4(a, b, &mut o); + let c = builtins::int::mul::__muloti4(a, b, &mut o); (c, match o { 0 => false, 1 => true, _ => panic!() }) }"); } @@ -613,7 +611,7 @@ fn main() { Some(a.0 / b.0) } }, - "compiler_builtins::int::sdiv::__divdi3(a, b)"); + "builtins::int::sdiv::__divdi3(a, b)"); gen(|(a, b): (MyI64, MyI64)| { if b.0 == 0 { None @@ -623,7 +621,7 @@ fn main() { }, "{ let mut r = 0; - (compiler_builtins::int::sdiv::__divmoddi4(a, b, &mut r), r) + (builtins::int::sdiv::__divmoddi4(a, b, &mut r), r) }"); gen(|(a, b): (MyI32, MyI32)| { if b.0 == 0 { @@ -634,7 +632,7 @@ fn main() { }, "{ let mut r = 0; - (compiler_builtins::int::sdiv::__divmodsi4(a, b, &mut r), r) + (builtins::int::sdiv::__divmodsi4(a, b, &mut r), r) }"); gen(|(a, b): (MyI32, MyI32)| { if b.0 == 0 { @@ -643,7 +641,7 @@ fn main() { Some(a.0 / b.0) } }, - "compiler_builtins::int::sdiv::__divsi3(a, b)"); + "builtins::int::sdiv::__divsi3(a, b)"); gen(|(a, b): (MyI32, MyI32)| { if b.0 == 0 { None @@ -651,7 +649,7 @@ fn main() { Some(a.0 % b.0) } }, - "compiler_builtins::int::sdiv::__modsi3(a, b)"); + "builtins::int::sdiv::__modsi3(a, b)"); gen(|(a, b): (MyI64, MyI64)| { if b.0 == 0 { None @@ -659,7 +657,7 @@ fn main() { Some(a.0 % b.0) } }, - "compiler_builtins::int::sdiv::__moddi3(a, b)"); + "builtins::int::sdiv::__moddi3(a, b)"); if !target_arch_mips { // FIXME(#137) gen(|(a, b): (MyI128, MyI128)| { if b.0 == 0 { @@ -668,7 +666,7 @@ fn main() { Some(a.0 / b.0) } }, - "compiler_builtins::int::sdiv::__divti3(a, b)"); + "builtins::int::sdiv::__divti3(a, b)"); gen(|(a, b): (MyI128, MyI128)| { if b.0 == 0 { None @@ -676,22 +674,22 @@ fn main() { Some(a.0 % b.0) } }, - "compiler_builtins::int::sdiv::__modti3(a, b)"); + "builtins::int::sdiv::__modti3(a, b)"); } // int/shift.rs gen(|(a, b): (MyU64, MyU32)| Some(a.0 << (b.0 % 64)), - "compiler_builtins::int::shift::__ashldi3(a, b % 64)"); + "builtins::int::shift::__ashldi3(a, b % 64)"); gen(|(a, b): (MyU128, MyU32)| Some(a.0 << (b.0 % 128)), - "compiler_builtins::int::shift::__ashlti3(a, b % 128)"); + "builtins::int::shift::__ashlti3(a, b % 128)"); gen(|(a, b): (MyI64, MyU32)| Some(a.0 >> (b.0 % 64)), - "compiler_builtins::int::shift::__ashrdi3(a, b % 64)"); + "builtins::int::shift::__ashrdi3(a, b % 64)"); gen(|(a, b): (MyI128, MyU32)| Some(a.0 >> (b.0 % 128)), - "compiler_builtins::int::shift::__ashrti3(a, b % 128)"); + "builtins::int::shift::__ashrti3(a, b % 128)"); gen(|(a, b): (MyU64, MyU32)| Some(a.0 >> (b.0 % 64)), - "compiler_builtins::int::shift::__lshrdi3(a, b % 64)"); + "builtins::int::shift::__lshrdi3(a, b % 64)"); gen(|(a, b): (MyU128, MyU32)| Some(a.0 >> (b.0 % 128)), - "compiler_builtins::int::shift::__lshrti3(a, b % 128)"); + "builtins::int::shift::__lshrti3(a, b % 128)"); // int/udiv.rs gen(|(a, b): (MyU64, MyU64)| { @@ -701,7 +699,7 @@ fn main() { Some(a.0 / b.0) } }, - "compiler_builtins::int::udiv::__udivdi3(a, b)"); + "builtins::int::udiv::__udivdi3(a, b)"); gen(|(a, b): (MyU64, MyU64)| { if b.0 == 0 { None @@ -711,7 +709,7 @@ fn main() { }, "{ let mut r = 0; - (compiler_builtins::int::udiv::__udivmoddi4(a, b, Some(&mut r)), r) + (builtins::int::udiv::__udivmoddi4(a, b, Some(&mut r)), r) }"); gen(|(a, b): (MyU32, MyU32)| { if b.0 == 0 { @@ -722,7 +720,7 @@ fn main() { }, "{ let mut r = 0; - (compiler_builtins::int::udiv::__udivmodsi4(a, b, Some(&mut r)), r) + (builtins::int::udiv::__udivmodsi4(a, b, Some(&mut r)), r) }"); gen(|(a, b): (MyU32, MyU32)| { if b.0 == 0 { @@ -731,7 +729,7 @@ fn main() { Some(a.0 / b.0) } }, - "compiler_builtins::int::udiv::__udivsi3(a, b)"); + "builtins::int::udiv::__udivsi3(a, b)"); gen(|(a, b): (MyU32, MyU32)| { if b.0 == 0 { None @@ -739,7 +737,7 @@ fn main() { Some(a.0 % b.0) } }, - "compiler_builtins::int::udiv::__umodsi3(a, b)"); + "builtins::int::udiv::__umodsi3(a, b)"); gen(|(a, b): (MyU64, MyU64)| { if b.0 == 0 { None @@ -747,7 +745,7 @@ fn main() { Some(a.0 % b.0) } }, - "compiler_builtins::int::udiv::__umoddi3(a, b)"); + "builtins::int::udiv::__umoddi3(a, b)"); if !target_arch_mips { // FIXME(#137) gen(|(a, b): (MyU128, MyU128)| { if b.0 == 0 { @@ -756,7 +754,7 @@ fn main() { Some(a.0 / b.0) } }, - "compiler_builtins::int::udiv::__udivti3(a, b)"); + "builtins::int::udiv::__udivti3(a, b)"); gen(|(a, b): (MyU128, MyU128)| { if b.0 == 0 { None @@ -764,7 +762,7 @@ fn main() { Some(a.0 % b.0) } }, - "compiler_builtins::int::udiv::__umodti3(a, b)"); + "builtins::int::udiv::__umodti3(a, b)"); gen(|(a, b): (MyU128, MyU128)| { if b.0 == 0 { None @@ -774,7 +772,7 @@ fn main() { }, "{ let mut r = 0; - (compiler_builtins::int::udiv::__udivmodti4(a, b, Some(&mut r)), r) + (builtins::int::udiv::__udivmodti4(a, b, Some(&mut r)), r) }"); } } diff --git a/library/compiler-builtins/testcrate/tests/generated.rs b/library/compiler-builtins/testcrate/tests/generated.rs index 1263dc261d6f7..28fe4be59e35f 100644 --- a/library/compiler-builtins/testcrate/tests/generated.rs +++ b/library/compiler-builtins/testcrate/tests/generated.rs @@ -1,13 +1,10 @@ #![feature(compiler_builtins_lib)] -#![feature(i128_type)] -#![feature(lang_items, core_float, core_float_bits)] +#![feature(lang_items)] #![allow(bad_style)] #![allow(unused_imports)] #![no_std] -use core::num::Float; - -extern crate compiler_builtins; +extern crate compiler_builtins as builtins; #[cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), From f58152286aeb8282df4d75e1f55cc9720c558e50 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 11 May 2018 16:52:34 -0700 Subject: [PATCH 0457/4206] More CI fixes --- library/compiler-builtins/examples/intrinsics.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 3820887895de0..57aa95947ed8f 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -12,11 +12,12 @@ #![feature(core_float)] #![feature(lang_items)] #![feature(start)] -#![feature(i128_type)] #![feature(global_allocator)] #![feature(allocator_api)] #![cfg_attr(windows, feature(panic_unwind))] -#![no_std] +#![no_core] + +extern crate core; #[cfg(not(thumb))] extern crate alloc_system; From c207fd3869e9b95add4816a64ce5870d385725ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Sat, 12 May 2018 09:19:28 +0200 Subject: [PATCH 0458/4206] use system library on openbsd compiler_rt is provided by default on OpenBSD, so use it instead of rebuilding it from source. --- library/compiler-builtins/build.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index c625abbfc5b0f..271b010bc4ae9 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -10,6 +10,13 @@ fn main() { return; } + // OpenBSD provides compiler_rt by default, use it instead of rebuilding it from source + if target.contains("openbsd") { + println!("cargo:rustc-link-search=native=/usr/lib"); + println!("cargo:rustc-link-lib=static=compiler_rt"); + return; + } + // Forcibly enable memory intrinsics on wasm32 as we don't have a libc to // provide them. if target.contains("wasm32") { From 5f184b9b567f9e01d940b2d47ec0a7a1ff793f0f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 12 May 2018 07:21:36 -0700 Subject: [PATCH 0459/4206] More attempts for intrinsics example --- .../compiler-builtins/examples/intrinsics.rs | 26 +++---------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 57aa95947ed8f..ddcb1ab863694 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -15,19 +15,11 @@ #![feature(global_allocator)] #![feature(allocator_api)] #![cfg_attr(windows, feature(panic_unwind))] -#![no_core] - -extern crate core; +#![no_std] #[cfg(not(thumb))] -extern crate alloc_system; -extern crate compiler_builtins; -#[cfg(windows)] -extern crate panic_unwind; - -#[cfg(not(thumb))] -#[global_allocator] -static A: alloc_system::System = alloc_system::System; +#[link(name = "c")] +extern {} // NOTE cfg(not(thumbv6m)) means that the operation is not supported on ARMv6-M at all. Not even // compiler-rt provides a C/assembly implementation. @@ -38,8 +30,6 @@ static A: alloc_system::System = alloc_system::System; // have an additional comment: the function name is the ARM name for the intrinsic and the comment // in the non-ARM name for the intrinsic. mod intrinsics { - use core::num::Float; - // trunccdfsf2 pub fn aeabi_d2f(x: f64) -> f32 { x as f32 @@ -299,14 +289,6 @@ mod intrinsics { a * b } - pub fn powidf2(a: f64, b: i32) -> f64 { - a.powi(b) - } - - pub fn powisf2(a: f32, b: i32) -> f32 { - a.powi(b) - } - pub fn umoddi3(a: u64, b: u64) -> u64 { a % b } @@ -398,8 +380,6 @@ fn run() { bb(aeabi_uldivmod(bb(2), bb(3))); bb(moddi3(bb(2), bb(3))); bb(mulodi4(bb(2), bb(3))); - bb(powidf2(bb(2.), bb(3))); - bb(powisf2(bb(2.), bb(3))); bb(umoddi3(bb(2), bb(3))); bb(muloti4(bb(2), bb(2))); bb(multi3(bb(2), bb(2))); From 87fad11100ffa43297928758074a86414cf2dd19 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 14 May 2018 06:55:34 -0700 Subject: [PATCH 0460/4206] Update compiler-rt Pick up a PR we forgot to backport --- library/compiler-builtins/compiler-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-rt b/library/compiler-builtins/compiler-rt index dfd960b5f1a17..54d95ca0bd603 160000 --- a/library/compiler-builtins/compiler-rt +++ b/library/compiler-builtins/compiler-rt @@ -1 +1 @@ -Subproject commit dfd960b5f1a1751b22738fa34fd27b583f4618db +Subproject commit 54d95ca0bd603c322601a61255898e2b8d2a3cae From 3f8bdca10d2f890b603b412988395ca494a144ea Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 14 May 2018 06:56:42 -0700 Subject: [PATCH 0461/4206] Allow failures on thumb for now --- library/compiler-builtins/.travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 898a600eb4179..efd0b1738e3e5 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -28,6 +28,11 @@ matrix: - env: TARGET=x86_64-apple-darwin os: osx - env: TARGET=x86_64-unknown-linux-gnu + allow_failures: + - env: TARGET=thumbv6m-linux-eabi + - env: TARGET=thumbv7em-linux-eabi + - env: TARGET=thumbv7em-linux-eabihf + - env: TARGET=thumbv7m-linux-eabi install: - case $TARGET in From 247819f3a0f7e96b5f9e5f0a6b530c649b54d74a Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Sun, 27 May 2018 23:28:17 +0900 Subject: [PATCH 0462/4206] Fix segfault on probestack with dynamic alloca. --- library/compiler-builtins/src/probestack.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 34f466e1e3a6c..c8883e2f825f7 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -64,6 +64,8 @@ pub unsafe extern fn __rust_probestack() { // bytes pushed on the stack orginally with our return address. Using // `8(%rsp)` simulates us testing the stack pointer in the caller's // context. + cmp $$0x1000,%r11 + jna 3f 2: sub $$0x1000,%rsp test %rsp,8(%rsp) @@ -71,6 +73,7 @@ pub unsafe extern fn __rust_probestack() { cmp $$0x1000,%r11 ja 2b + 3: // Finish up the last remaining stack space requested, getting the last // bits out of r11 sub %r11,%rsp @@ -98,6 +101,9 @@ pub unsafe extern fn __rust_probestack() { asm!(" push %ecx mov %eax,%ecx + + cmp $$0x1000,%ecx + jna 3f 2: sub $$0x1000,%esp test %esp,8(%esp) @@ -105,6 +111,7 @@ pub unsafe extern fn __rust_probestack() { cmp $$0x1000,%ecx ja 2b + 3: sub %ecx,%esp test %esp,8(%esp) From bf7b7b9109d62487511ff3acecb01e80a51e822a Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Mon, 28 May 2018 13:29:35 +0900 Subject: [PATCH 0463/4206] Explain why we need extra check in probestack. --- library/compiler-builtins/src/probestack.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index c8883e2f825f7..52a0414a18fb2 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -64,6 +64,11 @@ pub unsafe extern fn __rust_probestack() { // bytes pushed on the stack orginally with our return address. Using // `8(%rsp)` simulates us testing the stack pointer in the caller's // context. + + // It's usually called when %rax >= 0x1000, but that's not always true. + // Dynamic stack allocation, which is needed to implement unsized + // rvalues, triggers stackprobe even if %rax < 0x1000. + // Thus we have to check %r11 first to avoid segfault. cmp $$0x1000,%r11 jna 3f 2: From b3ffa4f2ebd9a000667563f574d4b28120b7a30d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 29 Jun 2018 09:53:58 -0700 Subject: [PATCH 0464/4206] Upgrade compiler-rt submodule, mostly for sanitizers --- library/compiler-builtins/compiler-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-rt b/library/compiler-builtins/compiler-rt index 54d95ca0bd603..40151c4c1cf77 160000 --- a/library/compiler-builtins/compiler-rt +++ b/library/compiler-builtins/compiler-rt @@ -1 +1 @@ -Subproject commit 54d95ca0bd603c322601a61255898e2b8d2a3cae +Subproject commit 40151c4c1cf77e593e3654e66e25ea423116aaae From 8e271704ef5f758ceaf505af3a7da69b2666f819 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 00:44:28 -0500 Subject: [PATCH 0465/4206] initial commit --- library/compiler-builtins/libm/.gitignore | 5 + library/compiler-builtins/libm/Cargo.toml | 7 + library/compiler-builtins/libm/LICENSE-APACHE | 201 +++++++++++ library/compiler-builtins/libm/LICENSE-MIT | 25 ++ library/compiler-builtins/libm/README.md | 111 ++++++ library/compiler-builtins/libm/ci/script.sh | 12 + library/compiler-builtins/libm/src/fabsf.rs | 3 + library/compiler-builtins/libm/src/lib.rs | 12 + library/compiler-builtins/libm/src/powf.rs | 326 ++++++++++++++++++ library/compiler-builtins/libm/src/scalbnf.rs | 34 ++ library/compiler-builtins/libm/src/sqrtf.rs | 83 +++++ .../libm/test-generator/Cargo.toml | 8 + .../libm/test-generator/README.md | 8 + .../libm/test-generator/src/main.rs | 234 +++++++++++++ 14 files changed, 1069 insertions(+) create mode 100644 library/compiler-builtins/libm/.gitignore create mode 100644 library/compiler-builtins/libm/Cargo.toml create mode 100644 library/compiler-builtins/libm/LICENSE-APACHE create mode 100644 library/compiler-builtins/libm/LICENSE-MIT create mode 100644 library/compiler-builtins/libm/README.md create mode 100644 library/compiler-builtins/libm/ci/script.sh create mode 100644 library/compiler-builtins/libm/src/fabsf.rs create mode 100644 library/compiler-builtins/libm/src/lib.rs create mode 100644 library/compiler-builtins/libm/src/powf.rs create mode 100644 library/compiler-builtins/libm/src/scalbnf.rs create mode 100644 library/compiler-builtins/libm/src/sqrtf.rs create mode 100644 library/compiler-builtins/libm/test-generator/Cargo.toml create mode 100644 library/compiler-builtins/libm/test-generator/README.md create mode 100644 library/compiler-builtins/libm/test-generator/src/main.rs diff --git a/library/compiler-builtins/libm/.gitignore b/library/compiler-builtins/libm/.gitignore new file mode 100644 index 0000000000000..6db0ab6effc41 --- /dev/null +++ b/library/compiler-builtins/libm/.gitignore @@ -0,0 +1,5 @@ +**/*.rs.bk +.#* +/target +/tests +Cargo.lock diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml new file mode 100644 index 0000000000000..96bc290fb3201 --- /dev/null +++ b/library/compiler-builtins/libm/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "libm" +version = "0.1.0" +authors = ["Jorge Aparicio "] + +[workspace] +members = ["test-generator"] \ No newline at end of file diff --git a/library/compiler-builtins/libm/LICENSE-APACHE b/library/compiler-builtins/libm/LICENSE-APACHE new file mode 100644 index 0000000000000..16fe87b06e802 --- /dev/null +++ b/library/compiler-builtins/libm/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/library/compiler-builtins/libm/LICENSE-MIT b/library/compiler-builtins/libm/LICENSE-MIT new file mode 100644 index 0000000000000..432fbea04d382 --- /dev/null +++ b/library/compiler-builtins/libm/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2018 Jorge Aparicio + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md new file mode 100644 index 0000000000000..fe384e118e986 --- /dev/null +++ b/library/compiler-builtins/libm/README.md @@ -0,0 +1,111 @@ +# `libm` + +A port of [MUSL]'s libm to Rust. + +[MUSL]: https://www.musl-libc.org/ + +## Testing + +The test suite of this crate can only be run on x86_64 Linux systems. + +``` +$ # The test suite depends on the `cross` tool so install it if you don't have it +$ cargo install cross + +$ # and the `cross` tool requires docker to be running +$ systemctl start docker + +$ # execute the test suite for the x86_64 target +$ TARGET=x86_64-unknown-linux-gnu bash ci/script.sh + +$ # execute the test suite for the ARMv7 target +$ TARGET=armv7-unknown-linux-gnueabihf bash ci/script.sh +``` + +## Contributing + +- Pick your favorite math function from the list below. +- Look for the C implementation of the function in the [MUSL source code][src]. +- Copy paste the C code into a Rust file in the `src` directory and adjust `src/lib.rs` accordingly. +- Run `cargo watch check` and fix the compiler errors. +- If you can, run the test suite locally. If you can't, no problem! Your PR will be tested + automatically. +- Send us a pull request! +- :tada: + +### Notes + +- To reinterpret a float as an integer use the `to_bits` method. The MUSL code uses the + `GET_FLOAT_WORD` macro, or a union, to do this operation. + +- To reinterpret an integer as a float use the `f32::from_bits` constructor. The MUSL code uses the + `SET_FLOAT_WORD` macro, or a union, to do this operation. + +- Rust code panics on arithmetic overflows when not optimized. You may need to use the [`Wrapping`] + newtype to avoid this problem. + +[src]: https://git.musl-libc.org/cgit/musl/tree/src/math +[`Wrapping`]: https://doc.rust-lang.org/std/num/struct.Wrapping.html + +## Progress + +### Functions wanted by the wasm WG + +cf. [rustwasm/team#84](https://github.com/rustwasm/team/issues/84). + +- [ ] acos +- [ ] asin +- [ ] atan +- [ ] atan2 +- [ ] cbrt +- [ ] cos +- [ ] cosf +- [ ] cosh +- [ ] exp +- [ ] exp2 +- [ ] exp2f +- [ ] expf +- [ ] expm1 +- [ ] fma +- [ ] fmaf +- [ ] fmod +- [ ] fmodf +- [ ] hypot +- [ ] log +- [ ] log10 +- [ ] log10f +- [ ] log1p +- [ ] log2 +- [ ] log2f +- [ ] logf +- [ ] pow +- [x] powf +- [ ] round +- [ ] roundf +- [ ] sin +- [ ] sinf +- [ ] sinh +- [ ] tan +- [ ] tanh + +### Other functions + +- [x] fabsf +- [x] scalbnf +- [x] sqrtf + +## License + +Licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the +work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any +additional terms or conditions. diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh new file mode 100644 index 0000000000000..64550573c0ed1 --- /dev/null +++ b/library/compiler-builtins/libm/ci/script.sh @@ -0,0 +1,12 @@ +set -euxo pipefail + +main() { + cargo run --package test-generator --target x86_64-unknown-linux-musl + if hash cargo-fmt; then + # nicer syntax error messages (if any) + cargo fmt + fi + cross test --target $TARGET --release +} + +main diff --git a/library/compiler-builtins/libm/src/fabsf.rs b/library/compiler-builtins/libm/src/fabsf.rs new file mode 100644 index 0000000000000..be60d06cc8ddf --- /dev/null +++ b/library/compiler-builtins/libm/src/fabsf.rs @@ -0,0 +1,3 @@ +pub fn fabsf(x: f32) -> f32 { + f32::from_bits(x.to_bits() & 0x7fffffff) +} diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs new file mode 100644 index 0000000000000..3d4062f3d4abc --- /dev/null +++ b/library/compiler-builtins/libm/src/lib.rs @@ -0,0 +1,12 @@ +#![deny(warnings)] +#![no_std] + +mod fabsf; +mod powf; +mod scalbnf; +mod sqrtf; + +pub use fabsf::fabsf; +pub use powf::powf; +pub use scalbnf::scalbnf; +pub use sqrtf::sqrtf; diff --git a/library/compiler-builtins/libm/src/powf.rs b/library/compiler-builtins/libm/src/powf.rs new file mode 100644 index 0000000000000..770987c2a09e8 --- /dev/null +++ b/library/compiler-builtins/libm/src/powf.rs @@ -0,0 +1,326 @@ +use {scalbnf, sqrtf}; + +const BP: [f32; 2] = [1.0, 1.5]; +const DP_H: [f32; 2] = [0.0, 5.84960938e-01]; /* 0x3f15c000 */ +const DP_L: [f32; 2] = [0.0, 1.56322085e-06]; /* 0x35d1cfdc */ +const TWO24: f32 = 16777216.0; /* 0x4b800000 */ +const HUGE: f32 = 1.0e30; +const TINY: f32 = 1.0e-30; +const L1: f32 = 6.0000002384e-01; /* 0x3f19999a */ +const L2: f32 = 4.2857143283e-01; /* 0x3edb6db7 */ +const L3: f32 = 3.3333334327e-01; /* 0x3eaaaaab */ +const L4: f32 = 2.7272811532e-01; /* 0x3e8ba305 */ +const L5: f32 = 2.3066075146e-01; /* 0x3e6c3255 */ +const L6: f32 = 2.0697501302e-01; /* 0x3e53f142 */ +const P1: f32 = 1.6666667163e-01; /* 0x3e2aaaab */ +const P2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ +const P3: f32 = 6.6137559770e-05; /* 0x388ab355 */ +const P4: f32 = -1.6533901999e-06; /* 0xb5ddea0e */ +const P5: f32 = 4.1381369442e-08; /* 0x3331bb4c */ +const LG2: f32 = 6.9314718246e-01; /* 0x3f317218 */ +const LG2_H: f32 = 6.93145752e-01; /* 0x3f317200 */ +const LG2_L: f32 = 1.42860654e-06; /* 0x35bfbe8c */ +const OVT: f32 = 4.2995665694e-08; /* -(128-log2(ovfl+.5ulp)) */ +const CP: f32 = 9.6179670095e-01; /* 0x3f76384f =2/(3ln2) */ +const CP_H: f32 = 9.6191406250e-01; /* 0x3f764000 =12b cp */ +const CP_L: f32 = -1.1736857402e-04; /* 0xb8f623c6 =tail of cp_h */ +const IVLN2: f32 = 1.4426950216e+00; +const IVLN2_H: f32 = 1.4426879883e+00; +const IVLN2_L: f32 = 7.0526075433e-06; + +pub fn powf(x: f32, y: f32) -> f32 { + let mut z: f32; + let mut ax: f32; + let z_h: f32; + let z_l: f32; + let mut p_h: f32; + let mut p_l: f32; + let y1: f32; + let mut t1: f32; + let t2: f32; + let mut r: f32; + let s: f32; + let mut sn: f32; + let mut t: f32; + let mut u: f32; + let mut v: f32; + let mut w: f32; + let i: i32; + let mut j: i32; + let mut k: i32; + let mut yisint: i32; + let mut n: i32; + let hx: i32; + let hy: i32; + let mut ix: i32; + let iy: i32; + let mut is: i32; + + hx = x.to_bits() as i32; + hy = y.to_bits() as i32; + + ix = hx & 0x7fffffff; + iy = hy & 0x7fffffff; + + /* x**0 = 1, even if x is NaN */ + if iy == 0 { + return 1.0; + } + + /* 1**y = 1, even if y is NaN */ + if hx == 0x3f800000 { + return 1.0; + } + + /* NaN if either arg is NaN */ + if ix > 0x7f800000 || iy > 0x7f800000 { + return x + y; + } + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if hx < 0 { + if iy >= 0x4b800000 { + yisint = 2; /* even integer y */ + } else if iy >= 0x3f800000 { + k = (iy >> 23) - 0x7f; /* exponent */ + j = iy >> (23 - k); + if (j << (23 - k)) == iy { + yisint = 2 - (j & 1); + } + } + } + + /* special value of y */ + if iy == 0x7f800000 { + /* y is +-inf */ + if ix == 0x3f800000 { + /* (-1)**+-inf is 1 */ + return 1.0; + } else if ix > 0x3f800000 { + /* (|x|>1)**+-inf = inf,0 */ + return if hy >= 0 { y } else { 0.0 }; + } else { + /* (|x|<1)**+-inf = 0,inf */ + return if hy >= 0 { 0.0 } else { -y }; + } + } + if iy == 0x3f800000 { + /* y is +-1 */ + return if hy >= 0 { x } else { 1.0 / x }; + } + + if hy == 0x40000000 { + /* y is 2 */ + return x * x; + } + + if hy == 0x3f000000 { + /* y is 0.5 */ + if hx >= 0 { + /* x >= +0 */ + return sqrtf(x); + } + } + + ax = ::fabsf(x); + /* special value of x */ + if ix == 0x7f800000 || ix == 0 || ix == 0x3f800000 { + /* x is +-0,+-inf,+-1 */ + z = ax; + if hy < 0 { + /* z = (1/|x|) */ + z = 1.0 / z; + } + + if hx < 0 { + if ((ix - 0x3f800000) | yisint) == 0 { + z = (z - z) / (z - z); /* (-1)**non-int is NaN */ + } else if yisint == 1 { + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + } + return z; + } + + sn = 1.0; /* sign of result */ + if hx < 0 { + if yisint == 0 { + /* (x<0)**(non-int) is NaN */ + return (x - x) / (x - x); + } + + if yisint == 1 { + /* (x<0)**(odd int) */ + sn = -1.0; + } + } + + /* |y| is HUGE */ + if iy > 0x4d000000 { + /* if |y| > 2**27 */ + /* over/underflow if x is not close to one */ + if ix < 0x3f7ffff8 { + return if hy < 0 { + sn * HUGE * HUGE + } else { + sn * TINY * TINY + }; + } + + if ix > 0x3f800007 { + return if hy > 0 { + sn * HUGE * HUGE + } else { + sn * TINY * TINY + }; + } + + /* now |1-x| is TINY <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax - 1.; /* t has 20 trailing zeros */ + w = (t * t) * (0.5 - t * (0.333333333333 - t * 0.25)); + u = IVLN2_H * t; /* IVLN2_H has 16 sig. bits */ + v = t * IVLN2_L - w * IVLN2; + t1 = u + v; + is = t1.to_bits() as i32; + t1 = f32::from_bits(is as u32 & 0xfffff000); + t2 = v - (t1 - u); + } else { + let mut s2: f32; + let mut s_h: f32; + let s_l: f32; + let mut t_h: f32; + let mut t_l: f32; + + n = 0; + /* take care subnormal number */ + if ix < 0x00800000 { + ax *= TWO24; + n -= 24; + ix = ax.to_bits() as i32; + } + n += ((ix) >> 23) - 0x7f; + j = ix & 0x007fffff; + /* determine interval */ + ix = j | 0x3f800000; /* normalize ix */ + if j <= 0x1cc471 { + /* |x|> 1) & 0xfffff000) | 0x20000000) as i32; + t_h = f32::from_bits(is as u32 + 0x00400000 + ((k as u32) << 21)); + t_l = ax - (t_h - BP[k as usize]); + s_l = v * ((u - s_h * t_h) - s_h * t_l); + /* compute log(ax) */ + s2 = s * s; + r = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); + r += s_l * (s_h + s); + s2 = s_h * s_h; + t_h = 3.0 + s2 + r; + is = t_h.to_bits() as i32; + t_h = f32::from_bits(is as u32 & 0xfffff000); + t_l = r - ((t_h - 3.0) - s2); + /* u+v = s*(1+...) */ + u = s_h * t_h; + v = s_l * t_h + t_l * s; + /* 2/(3log2)*(s+...) */ + p_h = u + v; + is = p_h.to_bits() as i32; + p_h = f32::from_bits(is as u32 & 0xfffff000); + p_l = v - (p_h - u); + z_h = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = CP_L * p_h + p_l * CP + DP_L[k as usize]; + /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = n as f32; + t1 = ((z_h + z_l) + DP_H[k as usize]) + t; + is = t1.to_bits() as i32; + t1 = f32::from_bits(is as u32 & 0xfffff000); + t2 = z_l - (((t1 - t) - DP_H[k as usize]) - z_h); + }; + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + is = y.to_bits() as i32; + y1 = f32::from_bits(is as u32 & 0xfffff000); + p_l = (y - y1) * t1 + y * t2; + p_h = y1 * t1; + z = p_l + p_h; + j = z.to_bits() as i32; + if j > 0x43000000 { + /* if z > 128 */ + return sn * HUGE * HUGE; /* overflow */ + } else if j == 0x43000000 { + /* if z == 128 */ + if p_l + OVT > z - p_h { + return sn * HUGE * HUGE; /* overflow */ + } + } else if (j & 0x7fffffff) > 0x43160000 { + /* z < -150 */ + // FIXME: check should be (uint32_t)j > 0xc3160000 + return sn * TINY * TINY; /* underflow */ + } else if j as u32 == 0xc3160000 { + /* z == -150 */ + if p_l <= z - p_h { + return sn * TINY * TINY; /* underflow */ + } + } + + /* + * compute 2**(p_h+p_l) + */ + i = j & 0x7fffffff; + k = (i >> 23) - 0x7f; + n = 0; + if i > 0x3f000000 { + /* if |z| > 0.5, set n = [z+0.5] */ + n = j + (0x00800000 >> (k + 1)); + k = ((n & 0x7fffffff) >> 23) - 0x7f; /* new k for n */ + t = f32::from_bits(n as u32 & !(0x007fffff >> k)); + n = ((n & 0x007fffff) | 0x00800000) >> (23 - k); + if j < 0 { + n = -n; + } + p_h -= t; + } + t = p_l + p_h; + is = t.to_bits() as i32; + t = f32::from_bits(is as u32 & 0xffff8000); + u = t * LG2_H; + v = (p_l - (t - p_h)) * LG2 + t * LG2_L; + z = u + v; + w = v - (z - u); + t = z * z; + t1 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); + r = (z * t1) / (t1 - 2.0) - (w + z * w); + z = 1.0 - (r - z); + j = z.to_bits() as i32; + j += n << 23; + if (j >> 23) <= 0 { + /* subnormal output */ + z = scalbnf(z, n); + } else { + z = f32::from_bits(j as u32); + } + return sn * z; +} diff --git a/library/compiler-builtins/libm/src/scalbnf.rs b/library/compiler-builtins/libm/src/scalbnf.rs new file mode 100644 index 0000000000000..2c057ebc57d56 --- /dev/null +++ b/library/compiler-builtins/libm/src/scalbnf.rs @@ -0,0 +1,34 @@ +pub fn scalbnf(mut x: f32, mut n: i32) -> f32 { + let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 + let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 + let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 + + let mut y: f32 = x; + + if n > 127 { + y *= x1p127; + n -= 127; + if n > 127 { + y *= x1p127; + n -= 127; + if n > 127 { + n = 127; + } + } + } else if n < -126 { + y *= x1p_126; + y *= x1p24; + n += 126 - 24; + if n < -126 { + y *= x1p_126; + y *= x1p24; + n += 126 - 24; + if n < -126 { + n = -126; + } + } + } + + x = y * f32::from_bits((0x7f + n as u32) << 23); + x +} diff --git a/library/compiler-builtins/libm/src/sqrtf.rs b/library/compiler-builtins/libm/src/sqrtf.rs new file mode 100644 index 0000000000000..6e92f67d4ab67 --- /dev/null +++ b/library/compiler-builtins/libm/src/sqrtf.rs @@ -0,0 +1,83 @@ +const TINY: f32 = 1.0e-30; + +pub fn sqrtf(x: f32) -> f32 { + let mut z: f32; + let sign: i32 = 0x80000000u32 as i32; + let mut ix: i32; + let mut s: i32; + let mut q: i32; + let mut m: i32; + let mut t: i32; + let mut i: i32; + let mut r: u32; + + ix = x.to_bits() as i32; + + /* take care of Inf and NaN */ + if (ix as u32 & 0x7f800000) == 0x7f800000 { + return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + } + + /* take care of zero */ + if ix <= 0 { + if (ix & !sign) == 0 { + return x; /* sqrt(+-0) = +-0 */ + } + if ix < 0 { + return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ + } + } + + /* normalize x */ + m = ix >> 23; + if m == 0 { + /* subnormal x */ + i = 0; + while ix & 0x00800000 == 0 { + ix <<= 1; + i = i + 1; + } + m -= i - 1; + } + m -= 127; /* unbias exponent */ + ix = (ix & 0x007fffff) | 0x00800000; + if m & 1 == 1 { + /* odd m, double x to make it even */ + ix += ix; + } + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix += ix; + q = 0; + s = 0; + r = 0x01000000; /* r = moving bit from right to left */ + + while r != 0 { + t = s + r as i32; + if t <= ix { + s = t + r as i32; + ix -= t; + q += r as i32; + } + ix += ix; + r >>= 1; + } + + /* use floating add to find out rounding direction */ + if ix != 0 { + z = 1.0 - TINY; /* raise inexact flag */ + if z >= 1.0 { + z = 1.0 + TINY; + if z > 1.0 { + q += 2; + } else { + q += q & 1; + } + } + } + + ix = (q >> 1) + 0x3f000000; + ix += m << 23; + f32::from_bits(ix as u32) +} diff --git a/library/compiler-builtins/libm/test-generator/Cargo.toml b/library/compiler-builtins/libm/test-generator/Cargo.toml new file mode 100644 index 0000000000000..f45d173b45164 --- /dev/null +++ b/library/compiler-builtins/libm/test-generator/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "test-generator" +version = "0.1.0" +authors = ["Jorge Aparicio "] +publish = false + +[dependencies] +rand = "0.5.3" diff --git a/library/compiler-builtins/libm/test-generator/README.md b/library/compiler-builtins/libm/test-generator/README.md new file mode 100644 index 0000000000000..cbacd88f14d2a --- /dev/null +++ b/library/compiler-builtins/libm/test-generator/README.md @@ -0,0 +1,8 @@ +# `test-generator` + +This is a tool to generate test cases for the `libm` crate. + +The generator randomly creates inputs for each math function, then proceeds to compute the +expected output for the given function by running the MUSL *C implementation* of the function and +finally it packs the test cases as a Cargo test file. For this reason, this generator **must** +always be compiled for the `x86_64-unknown-linux-musl` target. diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs new file mode 100644 index 0000000000000..7ee956f730f3e --- /dev/null +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -0,0 +1,234 @@ +// NOTE we intentionally avoid using the `quote` crate here because it doesn't work with the +// `x86_64-unknown-linux-musl` target. + +// NOTE usually the only thing you need to do to test a new math function is to add it to one of the +// macro invocations found in the bottom of this file. + +extern crate rand; + +use std::error::Error; +use std::fmt::Write as _0; +use std::fs::{self, File}; +use std::io::Write as _1; +use std::{i16, u32, u8}; + +use rand::{Rng, SeedableRng, XorShiftRng}; + +// Number of test cases to generate +const NTESTS: usize = 10_000; + +// TODO tweak this function to generate edge cases (zero, infinity, NaN) more often +fn f32(rng: &mut XorShiftRng) -> f32 { + let sign = if rng.gen_bool(0.5) { 1 << 31 } else { 0 }; + let exponent = (rng.gen_range(0, u8::MAX) as u32) << 23; + let mantissa = rng.gen_range(0, u32::MAX) & ((1 << 23) - 1); + + f32::from_bits(sign + exponent + mantissa) +} + +// fn(f32) -> f32 +macro_rules! f32_f32 { + ($($intr:ident,)+) => { + fn f32_f32(rng: &mut XorShiftRng) -> Result<(), Box> { + // MUSL C implementation of the function to test + extern "C" { + $(fn $intr(_: f32) -> f32;)+ + } + + $( + let mut cases = String::new(); + for _ in 0..NTESTS { + let inp = f32(rng); + let out = unsafe { $intr(inp) }; + + let inp = inp.to_bits(); + let out = out.to_bits(); + + write!(cases, "({}, {})", inp, out).unwrap(); + cases.push(','); + } + + let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; + write!(f, " + extern crate libm; + + #[test] + fn {0}() {{ + const CASES: &[(u32, u32)] = &[ + {1} + ]; + + for case in CASES {{ + let (inp, expected) = *case; + + let outf = libm::{0}(f32::from_bits(inp)); + let outi = outf.to_bits(); + + if !((outf.is_nan() && f32::from_bits(expected).is_nan()) || + outi == expected) {{ + panic!( + \"input: {{}}, output: {{}}, expected: {{}}\", + inp, + outi, + expected, + ); + }} + }} + }} +", + stringify!($intr), + cases)?; + )+ + + Ok(()) + } + } +} + +macro_rules! f32f32_f32 { + ($($intr:ident,)+) => { + fn f32f32_f32(rng: &mut XorShiftRng) -> Result<(), Box> { + extern "C" { + $(fn $intr(_: f32, _: f32) -> f32;)+ + } + + $( + let mut cases = String::new(); + for _ in 0..NTESTS { + let i1 = f32(rng); + let i2 = f32(rng); + let out = unsafe { $intr(i1, i2) }; + + let i1 = i1.to_bits(); + let i2 = i2.to_bits(); + let out = out.to_bits(); + + write!(cases, "(({}, {}), {})", i1, i2, out).unwrap(); + cases.push(','); + } + + let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; + write!(f, " + extern crate libm; + + #[test] + fn {0}() {{ + const CASES: &[((u32, u32), u32)] = &[ + {1} + ]; + + for case in CASES {{ + let ((i1, i2), expected) = *case; + + let outf = libm::{0}(f32::from_bits(i1), f32::from_bits(i2)); + let outi = outf.to_bits(); + + if !((outf.is_nan() && f32::from_bits(expected).is_nan()) || + outi == expected) {{ + panic!( + \"input: {{:?}}, output: {{}}, expected: {{}}\", + (i1, i2), + outi, + expected, + ); + }} + }} + }} +", + stringify!($intr), + cases)?; + )+ + + Ok(()) + } + }; +} + +macro_rules! f32i32_f32 { + ($($intr:ident,)+) => { + fn f32i32_f32(rng: &mut XorShiftRng) -> Result<(), Box> { + extern "C" { + $(fn $intr(_: f32, _: i32) -> f32;)+ + } + + $( + let mut cases = String::new(); + for _ in 0..NTESTS { + let i1 = f32(rng); + let i2 = rng.gen_range(i16::MIN, i16::MAX); + let out = unsafe { $intr(i1, i2 as i32) }; + + let i1 = i1.to_bits(); + let out = out.to_bits(); + + write!(cases, "(({}, {}), {})", i1, i2, out).unwrap(); + cases.push(','); + } + + let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; + write!(f, " + extern crate libm; + + #[test] + fn {0}() {{ + const CASES: &[((u32, i16), u32)] = &[ + {1} + ]; + + for case in CASES {{ + let ((i1, i2), expected) = *case; + + let outf = libm::{0}(f32::from_bits(i1), i2 as i32); + let outi = outf.to_bits(); + + if !((outf.is_nan() && f32::from_bits(expected).is_nan()) || + outi == expected) {{ + panic!( + \"input: {{:?}}, output: {{}}, expected: {{}}\", + (i1, i2), + outi, + expected, + ); + }} + }} + }} +", + stringify!($intr), + cases)?; + )+ + + Ok(()) + } + }; +} + +fn main() -> Result<(), Box> { + fs::remove_dir_all("tests").ok(); + fs::create_dir("tests")?; + + let mut rng = XorShiftRng::from_rng(&mut rand::thread_rng())?; + + f32_f32(&mut rng)?; + f32f32_f32(&mut rng)?; + f32i32_f32(&mut rng)?; + + Ok(()) +} + +/* Functions to test */ + +// With signature `fn(f32) -> f32` +f32_f32! { + fabsf, + sqrtf, +} + +// With signature `fn(f32, f32) -> f32` +f32f32_f32! { + powf, +} + +// With signature `fn(f32, i32) -> f32` +f32i32_f32! { + scalbnf, +} From 27c88ea01bdea389b1c8656b269d4cfe9448059f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 00:53:44 -0500 Subject: [PATCH 0466/4206] add CI --- library/compiler-builtins/libm/.travis.yml | 32 ++++++++++++++++++++ library/compiler-builtins/libm/ci/install.sh | 15 +++++++++ library/compiler-builtins/libm/ci/script.sh | 2 +- 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/libm/.travis.yml create mode 100644 library/compiler-builtins/libm/ci/install.sh diff --git a/library/compiler-builtins/libm/.travis.yml b/library/compiler-builtins/libm/.travis.yml new file mode 100644 index 0000000000000..4d8ccc784c60f --- /dev/null +++ b/library/compiler-builtins/libm/.travis.yml @@ -0,0 +1,32 @@ +language: rust +services: docker +sudo: required + +matrix: + include: + - env: TARGET=aarch64-unknown-linux-gnu + - env: TARGET=armv7-unknown-linux-gnueabihf + - env: TARGET=i686-unknown-linux-gnu + - env: TARGET=mips-unknown-linux-gnu + - env: TARGET=mips64-unknown-linux-gnuabi64 + - env: TARGET=mips64el-unknown-linux-gnuabi64 + - env: TARGET=mipsel-unknown-linux-gnu + - env: TARGET=powerpc-unknown-linux-gnu + - env: TARGET=powerpc64-unknown-linux-gnu + - env: TARGET=powerpc64le-unknown-linux-gnu + - env: TARGET=x86_64-unknown-linux-gnu + +before_install: set -e + +install: + - bash ci/install.sh + +script: + - bash ci/script.sh + +after_script: set +e + +cache: cargo + +before_cache: + - chmod -R a+r $HOME/.cargo; diff --git a/library/compiler-builtins/libm/ci/install.sh b/library/compiler-builtins/libm/ci/install.sh new file mode 100644 index 0000000000000..efdbb06c206e5 --- /dev/null +++ b/library/compiler-builtins/libm/ci/install.sh @@ -0,0 +1,15 @@ +set -euxo pipefail + +main() { + if ! hash cross >/dev/null 2>&1; then + cargo install cross + fi + + rustup target add x86_64-unknown-linux-musl + + if [ $TARGET != x86_64-unknown-linux-gnu ]; then + rustup target add $TARGET + fi +} + +main diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh index 64550573c0ed1..caba616edd1fe 100644 --- a/library/compiler-builtins/libm/ci/script.sh +++ b/library/compiler-builtins/libm/ci/script.sh @@ -2,7 +2,7 @@ set -euxo pipefail main() { cargo run --package test-generator --target x86_64-unknown-linux-musl - if hash cargo-fmt; then + if cargo fmt --version >/dev/null 2>&1; then # nicer syntax error messages (if any) cargo fmt fi From 806431c94788b90c1357705e7223210beefcba1e Mon Sep 17 00:00:00 2001 From: ljedrz Date: Thu, 12 Jul 2018 14:40:56 +0200 Subject: [PATCH 0467/4206] Remove #![feature(i128_type)] as i128 is stable --- library/compiler-builtins/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 819967be4aa1e..619b6ac7afbdb 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -17,8 +17,6 @@ #![feature(linkage)] #![feature(lang_items)] #![allow(unused_features)] -#![allow(stable_features)] // FIXME(mark-i-m): remove after i128 stabilizes -#![feature(i128_type)] #![no_builtins] #![cfg_attr(feature = "compiler-builtins", feature(staged_api))] #![cfg_attr(feature = "compiler-builtins", From 4f50a214f793500891006cafb3477b2b9d05a6d8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 12 Jul 2018 08:32:39 -0700 Subject: [PATCH 0468/4206] Try to fix example's compile on nightly --- library/compiler-builtins/examples/intrinsics.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index ddcb1ab863694..6468a83168161 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -14,6 +14,7 @@ #![feature(start)] #![feature(global_allocator)] #![feature(allocator_api)] +#![feature(panic_implementation)] #![cfg_attr(windows, feature(panic_unwind))] #![no_std] @@ -442,7 +443,7 @@ pub fn _Unwind_Resume() {} #[no_mangle] pub extern "C" fn eh_personality() {} -#[lang = "panic_fmt"] -#[no_mangle] -#[allow(private_no_mangle_fns)] -extern "C" fn panic_fmt() {} +#[panic_implementation] +fn panic(x: &core::panic::PanicInfo) -> ! { + loop {} +} From 3ae27657a1501dfad3ea33f586ad4298f35f1027 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 12 Jul 2018 09:29:32 -0700 Subject: [PATCH 0469/4206] Try to fix intrinsics example on nightly --- library/compiler-builtins/Cargo.toml | 3 +++ .../crates/panic-implementation/Cargo.toml | 6 ++++++ .../crates/panic-implementation/src/lib.rs | 11 +++++++++++ library/compiler-builtins/examples/intrinsics.rs | 15 +++++++++------ 4 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/crates/panic-implementation/Cargo.toml create mode 100644 library/compiler-builtins/crates/panic-implementation/src/lib.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 0ebeb17f326f9..311266269199c 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -9,6 +9,9 @@ test = false [build-dependencies] cc = { optional = true, version = "1.0" } +[dev-dependencies] +panic-implementation = { path = 'crates/panic-implementation' } + [features] default = ["compiler-builtins"] diff --git a/library/compiler-builtins/crates/panic-implementation/Cargo.toml b/library/compiler-builtins/crates/panic-implementation/Cargo.toml new file mode 100644 index 0000000000000..a076cbc3cb8eb --- /dev/null +++ b/library/compiler-builtins/crates/panic-implementation/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "panic-implementation" +version = "0.1.0" +authors = ["Alex Crichton "] + +[dependencies] diff --git a/library/compiler-builtins/crates/panic-implementation/src/lib.rs b/library/compiler-builtins/crates/panic-implementation/src/lib.rs new file mode 100644 index 0000000000000..1bb23970f7d3c --- /dev/null +++ b/library/compiler-builtins/crates/panic-implementation/src/lib.rs @@ -0,0 +1,11 @@ +// Hack of a crate until rust-lang/rust#51647 is fixed + +#![feature(no_core, panic_implementation)] +#![no_core] + +extern crate core; + +#[panic_implementation] +fn panic(_: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 6468a83168161..c165fcccaff91 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -12,12 +12,13 @@ #![feature(core_float)] #![feature(lang_items)] #![feature(start)] -#![feature(global_allocator)] #![feature(allocator_api)] #![feature(panic_implementation)] #![cfg_attr(windows, feature(panic_unwind))] #![no_std] +extern crate panic_implementation; + #[cfg(not(thumb))] #[link(name = "c")] extern {} @@ -393,6 +394,13 @@ fn run() { bb(modti3(bb(2), bb(2))); something_with_a_dtor(&|| assert_eq!(bb(1), 1)); + + extern { + fn rust_begin_unwind(); + } + // if bb(false) { + unsafe { rust_begin_unwind(); } + // } } fn something_with_a_dtor(f: &Fn()) { @@ -442,8 +450,3 @@ pub fn _Unwind_Resume() {} #[lang = "eh_personality"] #[no_mangle] pub extern "C" fn eh_personality() {} - -#[panic_implementation] -fn panic(x: &core::panic::PanicInfo) -> ! { - loop {} -} From 5b950eaea2bb38d4974ecc5a96231df6dc42fc99 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 12:20:55 -0500 Subject: [PATCH 0470/4206] use approximate equality with 1 ULP of tolerance --- library/compiler-builtins/libm/src/lib.rs | 6 ++++++ library/compiler-builtins/libm/test-generator/src/main.rs | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 3d4062f3d4abc..cb2110f1fb74e 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -10,3 +10,9 @@ pub use fabsf::fabsf; pub use powf::powf; pub use scalbnf::scalbnf; pub use sqrtf::sqrtf; + +/// Approximate equality with 1 ULP of tolerance +#[doc(hidden)] +pub fn _eqf(a: u32, b: u32) -> bool { + (a as i32).wrapping_sub(b as i32).abs() <= 1 +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 7ee956f730f3e..c406cf340ed13 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -65,7 +65,7 @@ macro_rules! f32_f32 { let outi = outf.to_bits(); if !((outf.is_nan() && f32::from_bits(expected).is_nan()) || - outi == expected) {{ + libm::_eqf(outi, expected)) {{ panic!( \"input: {{}}, output: {{}}, expected: {{}}\", inp, @@ -124,7 +124,7 @@ macro_rules! f32f32_f32 { let outi = outf.to_bits(); if !((outf.is_nan() && f32::from_bits(expected).is_nan()) || - outi == expected) {{ + libm::_eqf(outi, expected)) {{ panic!( \"input: {{:?}}, output: {{}}, expected: {{}}\", (i1, i2), @@ -182,7 +182,7 @@ macro_rules! f32i32_f32 { let outi = outf.to_bits(); if !((outf.is_nan() && f32::from_bits(expected).is_nan()) || - outi == expected) {{ + libm::_eqf(outi, expected)) {{ panic!( \"input: {{:?}}, output: {{}}, expected: {{}}\", (i1, i2), From 69f61b414906005e7e1e4486781f0cf98d683821 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 03:07:28 -0500 Subject: [PATCH 0471/4206] implement fmodf --- library/compiler-builtins/libm/src/fmodf.rs | 89 +++++++++++++++++++ library/compiler-builtins/libm/src/lib.rs | 6 ++ .../libm/test-generator/src/main.rs | 1 + 3 files changed, 96 insertions(+) create mode 100644 library/compiler-builtins/libm/src/fmodf.rs diff --git a/library/compiler-builtins/libm/src/fmodf.rs b/library/compiler-builtins/libm/src/fmodf.rs new file mode 100644 index 0000000000000..a184411a1823c --- /dev/null +++ b/library/compiler-builtins/libm/src/fmodf.rs @@ -0,0 +1,89 @@ +use core::u32; + +use isnanf; + +pub fn fmodf(x: f32, y: f32) -> f32 { + let mut uxi = x.to_bits(); + let mut uyi = y.to_bits(); + let mut ex = (uxi >> 23 & 0xff) as i32; + let mut ey = (uyi >> 23 & 0xff) as i32; + let sx = uxi & 0x80000000; + let mut i; + + if uyi << 1 == 0 || isnanf(y) || ex == 0xff { + return (x * y) / (x * y); + } + + if uxi << 1 <= uyi << 1 { + if uxi << 1 == uyi << 1 { + return 0.0 * x; + } + + return x; + } + + /* normalize x and y */ + if ex == 0 { + i = uxi << 9; + while i >> 31 == 0 { + ex -= 1; + i <<= 1; + } + + uxi <<= -ex + 1; + } else { + uxi &= u32::MAX >> 9; + uxi |= 1 << 23; + } + + if ey == 0 { + i = uyi << 9; + while i >> 31 == 0 { + ey -= 1; + i <<= 1; + } + + uyi <<= -ey + 1; + } else { + uyi &= u32::MAX >> 9; + uyi |= 1 << 23; + } + + /* x mod y */ + while ex > ey { + i = uxi - uyi; + if i >> 31 == 0 { + if i == 0 { + return 0.0 * x; + } + uxi = i; + } + uxi <<= 1; + + ex -= 1; + } + + i = uxi - uyi; + if i >> 31 == 0 { + if i == 0 { + return 0.0 * x; + } + uxi = i; + } + + while uxi >> 23 == 0 { + uxi <<= 1; + ex -= 1; + } + + /* scale result up */ + if ex > 0 { + uxi -= 1 << 23; + uxi |= (ex as u32) << 23; + } else { + uxi >>= -ex + 1; + } + uxi |= sx; + + f32::from_bits(uxi) +} diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index cb2110f1fb74e..41c20b2dae5af 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -2,11 +2,13 @@ #![no_std] mod fabsf; +mod fmodf; mod powf; mod scalbnf; mod sqrtf; pub use fabsf::fabsf; +pub use fmodf::fmodf; pub use powf::powf; pub use scalbnf::scalbnf; pub use sqrtf::sqrtf; @@ -16,3 +18,7 @@ pub use sqrtf::sqrtf; pub fn _eqf(a: u32, b: u32) -> bool { (a as i32).wrapping_sub(b as i32).abs() <= 1 } + +fn isnanf(x: f32) -> bool { + x.to_bits() & 0x7fffffff > 0x7f800000 +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index c406cf340ed13..3e58f7e1a081f 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -225,6 +225,7 @@ f32_f32! { // With signature `fn(f32, f32) -> f32` f32f32_f32! { + fmodf, powf, } From ec5784c1e80717407fe9d79eb7b3d4e6ed812233 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 12:43:25 -0500 Subject: [PATCH 0472/4206] update the README --- library/compiler-builtins/libm/README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index fe384e118e986..ba82123460c2c 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -28,11 +28,18 @@ $ TARGET=armv7-unknown-linux-gnueabihf bash ci/script.sh - Look for the C implementation of the function in the [MUSL source code][src]. - Copy paste the C code into a Rust file in the `src` directory and adjust `src/lib.rs` accordingly. - Run `cargo watch check` and fix the compiler errors. +- Tweak the bottom of `test-generator/src/main.rs` to add your function to the test suite. - If you can, run the test suite locally. If you can't, no problem! Your PR will be tested automatically. - Send us a pull request! - :tada: +[src]: https://git.musl-libc.org/cgit/musl/tree/src/math + +Check [PR #2] for an example. + +[PR #2]: https://github.com/japaric/libm/pull/2 + ### Notes - To reinterpret a float as an integer use the `to_bits` method. The MUSL code uses the @@ -44,7 +51,6 @@ $ TARGET=armv7-unknown-linux-gnueabihf bash ci/script.sh - Rust code panics on arithmetic overflows when not optimized. You may need to use the [`Wrapping`] newtype to avoid this problem. -[src]: https://git.musl-libc.org/cgit/musl/tree/src/math [`Wrapping`]: https://doc.rust-lang.org/std/num/struct.Wrapping.html ## Progress From c044991ee3533505954ad2ddf0b0c713f8cc89f9 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 13:23:40 -0500 Subject: [PATCH 0473/4206] fmodf is done --- library/compiler-builtins/libm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index ba82123460c2c..17c4ee94df561 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -75,7 +75,7 @@ cf. [rustwasm/team#84](https://github.com/rustwasm/team/issues/84). - [ ] fma - [ ] fmaf - [ ] fmod -- [ ] fmodf +- [x] fmodf - [ ] hypot - [ ] log - [ ] log10 From b30af240ad49ec25e1799205c20ea5dd3e2d78c4 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 13:34:19 -0500 Subject: [PATCH 0474/4206] add comment about issue rust-lang/libm#4 --- library/compiler-builtins/libm/ci/script.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh index caba616edd1fe..ee2e458cc036c 100644 --- a/library/compiler-builtins/libm/ci/script.sh +++ b/library/compiler-builtins/libm/ci/script.sh @@ -7,6 +7,9 @@ main() { cargo fmt fi cross test --target $TARGET --release + + # TODO need to fix overflow issues (cf. issue #4) + # cross test --target $TARGET } main From fdfc13afb9c52dca7fa67d93a5206b112d87f0d0 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 14:24:02 -0500 Subject: [PATCH 0475/4206] add test infrastructure for f64 functions --- library/compiler-builtins/libm/README.md | 1 + library/compiler-builtins/libm/src/fabs.rs | 5 + library/compiler-builtins/libm/src/lib.rs | 7 + .../libm/test-generator/src/main.rs | 228 +++++++++++++++++- 4 files changed, 230 insertions(+), 11 deletions(-) create mode 100644 library/compiler-builtins/libm/src/fabs.rs diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 17c4ee94df561..a0b131733d20e 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -96,6 +96,7 @@ cf. [rustwasm/team#84](https://github.com/rustwasm/team/issues/84). ### Other functions +- [x] fabs - [x] fabsf - [x] scalbnf - [x] sqrtf diff --git a/library/compiler-builtins/libm/src/fabs.rs b/library/compiler-builtins/libm/src/fabs.rs new file mode 100644 index 0000000000000..993918efcfbf8 --- /dev/null +++ b/library/compiler-builtins/libm/src/fabs.rs @@ -0,0 +1,5 @@ +use core::u64; + +pub fn fabs(x: f64) -> f64 { + f64::from_bits(x.to_bits() & (u64::MAX / 2)) +} diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 41c20b2dae5af..3f71fe876c6f8 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -1,12 +1,14 @@ #![deny(warnings)] #![no_std] +mod fabs; mod fabsf; mod fmodf; mod powf; mod scalbnf; mod sqrtf; +pub use fabs::fabs; pub use fabsf::fabsf; pub use fmodf::fmodf; pub use powf::powf; @@ -19,6 +21,11 @@ pub fn _eqf(a: u32, b: u32) -> bool { (a as i32).wrapping_sub(b as i32).abs() <= 1 } +#[doc(hidden)] +pub fn _eq(a: u64, b: u64) -> bool { + (a as i64).wrapping_sub(b as i64).abs() <= 1 +} + fn isnanf(x: f32) -> bool { x.to_bits() & 0x7fffffff > 0x7f800000 } diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 3e58f7e1a081f..fb9154aecc691 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -10,14 +10,14 @@ use std::error::Error; use std::fmt::Write as _0; use std::fs::{self, File}; use std::io::Write as _1; -use std::{i16, u32, u8}; +use std::{i16, u16, u32, u64, u8}; use rand::{Rng, SeedableRng, XorShiftRng}; // Number of test cases to generate const NTESTS: usize = 10_000; -// TODO tweak this function to generate edge cases (zero, infinity, NaN) more often +// TODO tweak these functions to generate edge cases (zero, infinity, NaN) more often fn f32(rng: &mut XorShiftRng) -> f32 { let sign = if rng.gen_bool(0.5) { 1 << 31 } else { 0 }; let exponent = (rng.gen_range(0, u8::MAX) as u32) << 23; @@ -26,13 +26,21 @@ fn f32(rng: &mut XorShiftRng) -> f32 { f32::from_bits(sign + exponent + mantissa) } +fn f64(rng: &mut XorShiftRng) -> f64 { + let sign = if rng.gen_bool(0.5) { 1 << 63 } else { 0 }; + let exponent = (rng.gen_range(0, u16::MAX) as u64 & ((1 << 11) - 1)) << 52; + let mantissa = rng.gen_range(0, u64::MAX) & ((1 << 52) - 1); + + f64::from_bits(sign + exponent + mantissa) +} + // fn(f32) -> f32 macro_rules! f32_f32 { - ($($intr:ident,)+) => { + ($($intr:ident,)*) => { fn f32_f32(rng: &mut XorShiftRng) -> Result<(), Box> { // MUSL C implementation of the function to test extern "C" { - $(fn $intr(_: f32) -> f32;)+ + $(fn $intr(_: f32) -> f32;)* } $( @@ -78,18 +86,19 @@ macro_rules! f32_f32 { ", stringify!($intr), cases)?; - )+ + )* Ok(()) } } } +// fn(f32, f32) -> f32 macro_rules! f32f32_f32 { - ($($intr:ident,)+) => { + ($($intr:ident,)*) => { fn f32f32_f32(rng: &mut XorShiftRng) -> Result<(), Box> { extern "C" { - $(fn $intr(_: f32, _: f32) -> f32;)+ + $(fn $intr(_: f32, _: f32) -> f32;)* } $( @@ -137,18 +146,19 @@ macro_rules! f32f32_f32 { ", stringify!($intr), cases)?; - )+ + )* Ok(()) } }; } +// fn(f32, i32) -> f32 macro_rules! f32i32_f32 { - ($($intr:ident,)+) => { + ($($intr:ident,)*) => { fn f32i32_f32(rng: &mut XorShiftRng) -> Result<(), Box> { extern "C" { - $(fn $intr(_: f32, _: i32) -> f32;)+ + $(fn $intr(_: f32, _: i32) -> f32;)* } $( @@ -195,7 +205,185 @@ macro_rules! f32i32_f32 { ", stringify!($intr), cases)?; - )+ + )* + + Ok(()) + } + }; +} + +// fn(f64) -> f64 +macro_rules! f64_f64 { + ($($intr:ident,)*) => { + fn f64_f64(rng: &mut XorShiftRng) -> Result<(), Box> { + // MUSL C implementation of the function to test + extern "C" { + $(fn $intr(_: f64) -> f64;)* + } + + $( + let mut cases = String::new(); + for _ in 0..NTESTS { + let inp = f64(rng); + let out = unsafe { $intr(inp) }; + + let inp = inp.to_bits(); + let out = out.to_bits(); + + write!(cases, "({}, {})", inp, out).unwrap(); + cases.push(','); + } + + let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; + write!(f, " + extern crate libm; + + #[test] + fn {0}() {{ + const CASES: &[(u64, u64)] = &[ + {1} + ]; + + for case in CASES {{ + let (inp, expected) = *case; + + let outf = libm::{0}(f64::from_bits(inp)); + let outi = outf.to_bits(); + + if !((outf.is_nan() && f64::from_bits(expected).is_nan()) || + libm::_eq(outi, expected)) {{ + panic!( + \"input: {{}}, output: {{}}, expected: {{}}\", + inp, + outi, + expected, + ); + }} + }} + }} +", + stringify!($intr), + cases)?; + )* + + Ok(()) + } + } +} + +// fn(f64, f64) -> f64 +macro_rules! f64f64_f64 { + ($($intr:ident,)*) => { + fn f64f64_f64(rng: &mut XorShiftRng) -> Result<(), Box> { + extern "C" { + $(fn $intr(_: f64, _: f64) -> f64;)* + } + + $( + let mut cases = String::new(); + for _ in 0..NTESTS { + let i1 = f64(rng); + let i2 = f64(rng); + let out = unsafe { $intr(i1, i2) }; + + let i1 = i1.to_bits(); + let i2 = i2.to_bits(); + let out = out.to_bits(); + + write!(cases, "(({}, {}), {})", i1, i2, out).unwrap(); + cases.push(','); + } + + let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; + write!(f, " + extern crate libm; + + #[test] + fn {0}() {{ + const CASES: &[((u64, u64), u64)] = &[ + {1} + ]; + + for case in CASES {{ + let ((i1, i2), expected) = *case; + + let outf = libm::{0}(f64::from_bits(i1), f64::from_bits(i2)); + let outi = outf.to_bits(); + + if !((outf.is_nan() && f64::from_bits(expected).is_nan()) || + libm::_eq(outi, expected)) {{ + panic!( + \"input: {{:?}}, output: {{}}, expected: {{}}\", + (i1, i2), + outi, + expected, + ); + }} + }} + }} +", + stringify!($intr), + cases)?; + )* + + Ok(()) + } + }; +} + +// fn(f64, i32) -> f64 +macro_rules! f64i32_f64 { + ($($intr:ident,)*) => { + fn f64i32_f64(rng: &mut XorShiftRng) -> Result<(), Box> { + extern "C" { + $(fn $intr(_: f64, _: i32) -> f64;)* + } + + $( + let mut cases = String::new(); + for _ in 0..NTESTS { + let i1 = f64(rng); + let i2 = rng.gen_range(i16::MIN, i16::MAX); + let out = unsafe { $intr(i1, i2 as i32) }; + + let i1 = i1.to_bits(); + let out = out.to_bits(); + + write!(cases, "(({}, {}), {})", i1, i2, out).unwrap(); + cases.push(','); + } + + let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; + write!(f, " + extern crate libm; + + #[test] + fn {0}() {{ + const CASES: &[((u64, i16), u64)] = &[ + {1} + ]; + + for case in CASES {{ + let ((i1, i2), expected) = *case; + + let outf = libm::{0}(f64::from_bits(i1), i2 as i32); + let outi = outf.to_bits(); + + if !((outf.is_nan() && f64::from_bits(expected).is_nan()) || + libm::_eq(outi, expected)) {{ + panic!( + \"input: {{:?}}, output: {{}}, expected: {{}}\", + (i1, i2), + outi, + expected, + ); + }} + }} + }} +", + stringify!($intr), + cases)?; + )* Ok(()) } @@ -211,6 +399,9 @@ fn main() -> Result<(), Box> { f32_f32(&mut rng)?; f32f32_f32(&mut rng)?; f32i32_f32(&mut rng)?; + f64_f64(&mut rng)?; + f64f64_f64(&mut rng)?; + f64i32_f64(&mut rng)?; Ok(()) } @@ -233,3 +424,18 @@ f32f32_f32! { f32i32_f32! { scalbnf, } + +// With signature `fn(f64) -> f64` +f64_f64! { + fabs, +} + +// With signature `fn(f64, f64) -> f64` +f64f64_f64! { + // fmod, +} + +// With signature `fn(f64, i32) -> f64` +f64i32_f64! { + // scalbn, +} From 3073bdd29a56b6866d1f1aff9cf5457ac860386a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 15:30:32 -0500 Subject: [PATCH 0476/4206] add more testing infrastructure --- .../libm/test-generator/src/main.rs | 188 ++++++++++++++++++ 1 file changed, 188 insertions(+) diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index fb9154aecc691..f933b34dcd004 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -58,6 +58,8 @@ macro_rules! f32_f32 { let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; write!(f, " + #![deny(warnings)] + extern crate libm; #[test] @@ -118,6 +120,8 @@ macro_rules! f32f32_f32 { let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; write!(f, " + #![deny(warnings)] + extern crate libm; #[test] @@ -153,6 +157,74 @@ macro_rules! f32f32_f32 { }; } +// fn(f32, f32, f32) -> f32 +macro_rules! f32f32f32_f32 { + ($($intr:ident,)*) => { + fn f32f32f32_f32(rng: &mut XorShiftRng) -> Result<(), Box> { + extern "C" { + $(fn $intr(_: f32, _: f32, _: f32) -> f32;)* + } + + $( + let mut cases = String::new(); + for _ in 0..NTESTS { + let i1 = f32(rng); + let i2 = f32(rng); + let i3 = f32(rng); + let out = unsafe { $intr(i1, i2, i3) }; + + let i1 = i1.to_bits(); + let i2 = i2.to_bits(); + let i3 = i3.to_bits(); + let out = out.to_bits(); + + write!(cases, "(({}, {}, {}), {})", i1, i2, i3, out).unwrap(); + cases.push(','); + } + + let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; + write!(f, " + #![deny(warnings)] + + extern crate libm; + + #[test] + fn {0}() {{ + const CASES: &[((u32, u32, u32), u32)] = &[ + {1} + ]; + + for case in CASES {{ + let ((i1, i2, i3), expected) = *case; + + let outf = libm::{0}( + f32::from_bits(i1), + f32::from_bits(i2), + f32::from_bits(i3), + ); + let outi = outf.to_bits(); + + if !((outf.is_nan() && f32::from_bits(expected).is_nan()) || + libm::_eqf(outi, expected)) {{ + panic!( + \"input: {{:?}}, output: {{}}, expected: {{}}\", + (i1, i2, i3), + outi, + expected, + ); + }} + }} + }} +", + stringify!($intr), + cases)?; + )* + + Ok(()) + } + }; +} + // fn(f32, i32) -> f32 macro_rules! f32i32_f32 { ($($intr:ident,)*) => { @@ -177,6 +249,8 @@ macro_rules! f32i32_f32 { let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; write!(f, " + #![deny(warnings)] + extern crate libm; #[test] @@ -236,6 +310,8 @@ macro_rules! f64_f64 { let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; write!(f, " + #![deny(warnings)] + extern crate libm; #[test] @@ -296,6 +372,8 @@ macro_rules! f64f64_f64 { let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; write!(f, " + #![deny(warnings)] + extern crate libm; #[test] @@ -331,6 +409,74 @@ macro_rules! f64f64_f64 { }; } +// fn(f64, f64, f64) -> f64 +macro_rules! f64f64f64_f64 { + ($($intr:ident,)*) => { + fn f64f64f64_f64(rng: &mut XorShiftRng) -> Result<(), Box> { + extern "C" { + $(fn $intr(_: f64, _: f64, _: f64) -> f64;)* + } + + $( + let mut cases = String::new(); + for _ in 0..NTESTS { + let i1 = f64(rng); + let i2 = f64(rng); + let i3 = f64(rng); + let out = unsafe { $intr(i1, i2, i3) }; + + let i1 = i1.to_bits(); + let i2 = i2.to_bits(); + let i3 = i3.to_bits(); + let out = out.to_bits(); + + write!(cases, "(({}, {}, {}), {})", i1, i2, i3, out).unwrap(); + cases.push(','); + } + + let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; + write!(f, " + #![deny(warnings)] + + extern crate libm; + + #[test] + fn {0}() {{ + const CASES: &[((u64, u64, u64), u64)] = &[ + {1} + ]; + + for case in CASES {{ + let ((i1, i2, i3), expected) = *case; + + let outf = libm::{0}( + f64::from_bits(i1), + f64::from_bits(i2), + f64::from_bits(i3), + ); + let outi = outf.to_bits(); + + if !((outf.is_nan() && f64::from_bits(expected).is_nan()) || + libm::_eq(outi, expected)) {{ + panic!( + \"input: {{:?}}, output: {{}}, expected: {{}}\", + (i1, i2, i3), + outi, + expected, + ); + }} + }} + }} +", + stringify!($intr), + cases)?; + )* + + Ok(()) + } + }; +} + // fn(f64, i32) -> f64 macro_rules! f64i32_f64 { ($($intr:ident,)*) => { @@ -355,6 +501,8 @@ macro_rules! f64i32_f64 { let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; write!(f, " + #![deny(warnings)] + extern crate libm; #[test] @@ -398,9 +546,11 @@ fn main() -> Result<(), Box> { f32_f32(&mut rng)?; f32f32_f32(&mut rng)?; + f32f32f32_f32(&mut rng)?; f32i32_f32(&mut rng)?; f64_f64(&mut rng)?; f64f64_f64(&mut rng)?; + f64f64f64_f64(&mut rng)?; f64i32_f64(&mut rng)?; Ok(()) @@ -410,6 +560,13 @@ fn main() -> Result<(), Box> { // With signature `fn(f32) -> f32` f32_f32! { + // cosf, + // exp2f, + // expf, + // log10f, + // log2f, + // roundf, + // sinf, fabsf, sqrtf, } @@ -420,6 +577,11 @@ f32f32_f32! { powf, } +// With signature `fn(f32, f32, f32) -> f32` +f32f32f32_f32! { + // fmaf, +} + // With signature `fn(f32, i32) -> f32` f32i32_f32! { scalbnf, @@ -427,12 +589,38 @@ f32i32_f32! { // With signature `fn(f64) -> f64` f64_f64! { + // acos, + // asin, + // atan, + // cbrt, + // cos, + // cosh, + // exp, + // exp2, + // expm1, + // log, + // log10, + // log1p, + // log2, + // round, + // sin, + // sinh, + // tan, + // tanh, fabs, } // With signature `fn(f64, f64) -> f64` f64f64_f64! { + // atan2, // fmod, + // hypot, + // pow, +} + +// With signature `fn(f64, f64, f64) -> f64` +f64f64f64_f64! { + // fma, } // With signature `fn(f64, i32) -> f64` From 8440b96c93c017541c14a3a661aa87d9f9dd6d43 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 15:50:06 -0500 Subject: [PATCH 0477/4206] bors-ng support --- library/compiler-builtins/libm/.travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/compiler-builtins/libm/.travis.yml b/library/compiler-builtins/libm/.travis.yml index 4d8ccc784c60f..0c0832793474e 100644 --- a/library/compiler-builtins/libm/.travis.yml +++ b/library/compiler-builtins/libm/.travis.yml @@ -30,3 +30,9 @@ cache: cargo before_cache: - chmod -R a+r $HOME/.cargo; + +branches: + only: + - master + - staging + - trying From 333d27ab6ac14b315ff826f381596c50b49b97c3 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 18:26:39 -0500 Subject: [PATCH 0478/4206] add more commented out tests --- .../libm/test-generator/src/main.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index f933b34dcd004..a13aa4ef705a5 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -560,19 +560,33 @@ fn main() -> Result<(), Box> { // With signature `fn(f32) -> f32` f32_f32! { + // acosf, + // floorf, + // truncf + // asinf, + // atanf, + // cbrtf, + // ceilf, // cosf, + // coshf, // exp2f, // expf, + // fdimf, // log10f, // log2f, // roundf, // sinf, + // sinhf, + // tanf, + // tanhf, fabsf, sqrtf, } // With signature `fn(f32, f32) -> f32` f32f32_f32! { + // atan2f, + // hypotf, fmodf, powf, } @@ -593,11 +607,13 @@ f64_f64! { // asin, // atan, // cbrt, + // ceil, // cos, // cosh, // exp, // exp2, // expm1, + // floor, // log, // log10, // log1p, @@ -605,14 +621,17 @@ f64_f64! { // round, // sin, // sinh, + // sqrt, // tan, // tanh, + // trunc, fabs, } // With signature `fn(f64, f64) -> f64` f64f64_f64! { // atan2, + // fdim, // fmod, // hypot, // pow, From f31abe2da16d9529d35a8d335998b1e35e2f853b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 18:43:59 -0500 Subject: [PATCH 0479/4206] update the README --- library/compiler-builtins/libm/README.md | 56 +++--------------------- 1 file changed, 7 insertions(+), 49 deletions(-) diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index a0b131733d20e..841199a9f03ee 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -4,6 +4,11 @@ A port of [MUSL]'s libm to Rust. [MUSL]: https://www.musl-libc.org/ +## Goals + +The short term goal of this library is to enable math support (e.g. `sin`, `atan2`) for the +`wasm32-unknown-unknown` target. The longer term goal is to enable math support in the `core` crate. + ## Testing The test suite of this crate can only be run on x86_64 Linux systems. @@ -24,7 +29,7 @@ $ TARGET=armv7-unknown-linux-gnueabihf bash ci/script.sh ## Contributing -- Pick your favorite math function from the list below. +- Pick your favorite math function from the [issue tracker]. - Look for the C implementation of the function in the [MUSL source code][src]. - Copy paste the C code into a Rust file in the `src` directory and adjust `src/lib.rs` accordingly. - Run `cargo watch check` and fix the compiler errors. @@ -34,6 +39,7 @@ $ TARGET=armv7-unknown-linux-gnueabihf bash ci/script.sh - Send us a pull request! - :tada: +[issue tracker]: https://github.com/japaric/libm/issues [src]: https://git.musl-libc.org/cgit/musl/tree/src/math Check [PR #2] for an example. @@ -53,54 +59,6 @@ Check [PR #2] for an example. [`Wrapping`]: https://doc.rust-lang.org/std/num/struct.Wrapping.html -## Progress - -### Functions wanted by the wasm WG - -cf. [rustwasm/team#84](https://github.com/rustwasm/team/issues/84). - -- [ ] acos -- [ ] asin -- [ ] atan -- [ ] atan2 -- [ ] cbrt -- [ ] cos -- [ ] cosf -- [ ] cosh -- [ ] exp -- [ ] exp2 -- [ ] exp2f -- [ ] expf -- [ ] expm1 -- [ ] fma -- [ ] fmaf -- [ ] fmod -- [x] fmodf -- [ ] hypot -- [ ] log -- [ ] log10 -- [ ] log10f -- [ ] log1p -- [ ] log2 -- [ ] log2f -- [ ] logf -- [ ] pow -- [x] powf -- [ ] round -- [ ] roundf -- [ ] sin -- [ ] sinf -- [ ] sinh -- [ ] tan -- [ ] tanh - -### Other functions - -- [x] fabs -- [x] fabsf -- [x] scalbnf -- [x] sqrtf - ## License Licensed under either of From a9e77402601377fa9e9e37924956cf70061eaf7d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 19:16:50 -0500 Subject: [PATCH 0480/4206] re-structure for compiler-builtins integration --- library/compiler-builtins/libm/README.md | 3 ++- library/compiler-builtins/libm/src/lib.rs | 18 ++---------------- .../libm/src/{ => math}/fabs.rs | 1 + .../libm/src/{ => math}/fabsf.rs | 1 + .../libm/src/{ => math}/fmodf.rs | 3 ++- library/compiler-builtins/libm/src/math/mod.rs | 17 +++++++++++++++++ .../libm/src/{ => math}/powf.rs | 5 +++-- .../libm/src/{ => math}/scalbnf.rs | 1 + .../libm/src/{ => math}/sqrtf.rs | 1 + 9 files changed, 30 insertions(+), 20 deletions(-) rename library/compiler-builtins/libm/src/{ => math}/fabs.rs (90%) rename library/compiler-builtins/libm/src/{ => math}/fabsf.rs (88%) rename library/compiler-builtins/libm/src/{ => math}/fmodf.rs (98%) create mode 100644 library/compiler-builtins/libm/src/math/mod.rs rename library/compiler-builtins/libm/src/{ => math}/powf.rs (99%) rename library/compiler-builtins/libm/src/{ => math}/scalbnf.rs (98%) rename library/compiler-builtins/libm/src/{ => math}/sqrtf.rs (99%) diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 841199a9f03ee..55f4654346e67 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -31,7 +31,8 @@ $ TARGET=armv7-unknown-linux-gnueabihf bash ci/script.sh - Pick your favorite math function from the [issue tracker]. - Look for the C implementation of the function in the [MUSL source code][src]. -- Copy paste the C code into a Rust file in the `src` directory and adjust `src/lib.rs` accordingly. +- Copy paste the C code into a Rust file in the `src/math` directory and adjust `src/math/mod.rs` + accordingly. - Run `cargo watch check` and fix the compiler errors. - Tweak the bottom of `test-generator/src/main.rs` to add your function to the test suite. - If you can, run the test suite locally. If you can't, no problem! Your PR will be tested diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 3f71fe876c6f8..4d7cec56f9df1 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -1,19 +1,9 @@ #![deny(warnings)] #![no_std] -mod fabs; -mod fabsf; -mod fmodf; -mod powf; -mod scalbnf; -mod sqrtf; +mod math; -pub use fabs::fabs; -pub use fabsf::fabsf; -pub use fmodf::fmodf; -pub use powf::powf; -pub use scalbnf::scalbnf; -pub use sqrtf::sqrtf; +pub use math::*; /// Approximate equality with 1 ULP of tolerance #[doc(hidden)] @@ -25,7 +15,3 @@ pub fn _eqf(a: u32, b: u32) -> bool { pub fn _eq(a: u64, b: u64) -> bool { (a as i64).wrapping_sub(b as i64).abs() <= 1 } - -fn isnanf(x: f32) -> bool { - x.to_bits() & 0x7fffffff > 0x7f800000 -} diff --git a/library/compiler-builtins/libm/src/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs similarity index 90% rename from library/compiler-builtins/libm/src/fabs.rs rename to library/compiler-builtins/libm/src/math/fabs.rs index 993918efcfbf8..9e081f3f9f69f 100644 --- a/library/compiler-builtins/libm/src/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -1,5 +1,6 @@ use core::u64; +#[inline] pub fn fabs(x: f64) -> f64 { f64::from_bits(x.to_bits() & (u64::MAX / 2)) } diff --git a/library/compiler-builtins/libm/src/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs similarity index 88% rename from library/compiler-builtins/libm/src/fabsf.rs rename to library/compiler-builtins/libm/src/math/fabsf.rs index be60d06cc8ddf..4cc9411169ab2 100644 --- a/library/compiler-builtins/libm/src/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -1,3 +1,4 @@ +#[inline] pub fn fabsf(x: f32) -> f32 { f32::from_bits(x.to_bits() & 0x7fffffff) } diff --git a/library/compiler-builtins/libm/src/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs similarity index 98% rename from library/compiler-builtins/libm/src/fmodf.rs rename to library/compiler-builtins/libm/src/math/fmodf.rs index a184411a1823c..9097752490854 100644 --- a/library/compiler-builtins/libm/src/fmodf.rs +++ b/library/compiler-builtins/libm/src/math/fmodf.rs @@ -1,7 +1,8 @@ use core::u32; -use isnanf; +use super::isnanf; +#[inline] pub fn fmodf(x: f32, y: f32) -> f32 { let mut uxi = x.to_bits(); let mut uyi = y.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs new file mode 100644 index 0000000000000..09d81944c27bd --- /dev/null +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -0,0 +1,17 @@ +mod fabs; +mod fabsf; +mod fmodf; +mod powf; +mod scalbnf; +mod sqrtf; + +pub use self::fabs::fabs; +pub use self::fabsf::fabsf; +pub use self::fmodf::fmodf; +pub use self::powf::powf; +pub use self::scalbnf::scalbnf; +pub use self::sqrtf::sqrtf; + +fn isnanf(x: f32) -> bool { + x.to_bits() & 0x7fffffff > 0x7f800000 +} diff --git a/library/compiler-builtins/libm/src/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs similarity index 99% rename from library/compiler-builtins/libm/src/powf.rs rename to library/compiler-builtins/libm/src/math/powf.rs index 770987c2a09e8..f1dc3a5b86782 100644 --- a/library/compiler-builtins/libm/src/powf.rs +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -1,4 +1,4 @@ -use {scalbnf, sqrtf}; +use super::{fabsf, scalbnf, sqrtf}; const BP: [f32; 2] = [1.0, 1.5]; const DP_H: [f32; 2] = [0.0, 5.84960938e-01]; /* 0x3f15c000 */ @@ -28,6 +28,7 @@ const IVLN2: f32 = 1.4426950216e+00; const IVLN2_H: f32 = 1.4426879883e+00; const IVLN2_L: f32 = 7.0526075433e-06; +#[inline] pub fn powf(x: f32, y: f32) -> f32 { let mut z: f32; let mut ax: f32; @@ -127,7 +128,7 @@ pub fn powf(x: f32, y: f32) -> f32 { } } - ax = ::fabsf(x); + ax = fabsf(x); /* special value of x */ if ix == 0x7f800000 || ix == 0 || ix == 0x3f800000 { /* x is +-0,+-inf,+-1 */ diff --git a/library/compiler-builtins/libm/src/scalbnf.rs b/library/compiler-builtins/libm/src/math/scalbnf.rs similarity index 98% rename from library/compiler-builtins/libm/src/scalbnf.rs rename to library/compiler-builtins/libm/src/math/scalbnf.rs index 2c057ebc57d56..2ae8bf31b772b 100644 --- a/library/compiler-builtins/libm/src/scalbnf.rs +++ b/library/compiler-builtins/libm/src/math/scalbnf.rs @@ -1,3 +1,4 @@ +#[inline] pub fn scalbnf(mut x: f32, mut n: i32) -> f32 { let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 diff --git a/library/compiler-builtins/libm/src/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs similarity index 99% rename from library/compiler-builtins/libm/src/sqrtf.rs rename to library/compiler-builtins/libm/src/math/sqrtf.rs index 6e92f67d4ab67..a265bef48eb26 100644 --- a/library/compiler-builtins/libm/src/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -1,5 +1,6 @@ const TINY: f32 = 1.0e-30; +#[inline] pub fn sqrtf(x: f32) -> f32 { let mut z: f32; let sign: i32 = 0x80000000u32 as i32; From 7aafbaa6042f38635f437762b0a4078cea4a72b9 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 19:57:44 -0500 Subject: [PATCH 0481/4206] add extension traits --- library/compiler-builtins/libm/src/lib.rs | 690 ++++++++++++++++++++++ 1 file changed, 690 insertions(+) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 4d7cec56f9df1..fc9628d919f31 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -1,8 +1,22 @@ +//! Port of MUSL's libm to Rust +//! +//! # Usage +//! +//! You can use this crate in two ways: +//! +//! - By directly using its free functions, e.g. `libm::powf`. +//! +//! - By importing the `F32Ext` and / or `F64Ext` extension traits to add methods like `powf` to the +//! `f32` and `f64` types. Then you'll be able to invoke math functions as methods, e.g. `x.sqrt()`. + #![deny(warnings)] #![no_std] mod math; +#[cfg(todo)] +use core::{f32, f64}; + pub use math::*; /// Approximate equality with 1 ULP of tolerance @@ -15,3 +29,679 @@ pub fn _eqf(a: u32, b: u32) -> bool { pub fn _eq(a: u64, b: u64) -> bool { (a as i64).wrapping_sub(b as i64).abs() <= 1 } + +/// Math support for `f32` +/// +/// NOTE this meant to be a closed extension trait. The only stable way to use this trait is to +/// import it to access its methods. +pub trait F32Ext { + #[cfg(todo)] + fn floor(self) -> Self; + + #[cfg(todo)] + fn ceil(self) -> Self; + + #[cfg(todo)] + fn round(self) -> Self; + + #[cfg(todo)] + fn trunc(self) -> Self; + + #[cfg(todo)] + fn fract(self) -> Self; + + fn abs(self) -> Self; + + #[cfg(todo)] + fn signum(self) -> Self; + + #[cfg(todo)] + fn mul_add(self, a: Self, b: Self) -> Self; + + #[cfg(todo)] + fn div_euc(self, rhs: Self) -> Self; + + #[cfg(todo)] + fn mod_euc(self, rhs: Self) -> Self; + + // NOTE depends on unstable intrinsics::powif32 + // fn powi(self, n: i32) -> Self; + + fn powf(self, n: Self) -> Self; + + fn sqrt(self) -> Self; + + #[cfg(todo)] + fn exp(self) -> Self; + + #[cfg(todo)] + fn exp2(self) -> Self; + + #[cfg(todo)] + fn ln(self) -> Self; + + #[cfg(todo)] + fn log(self, base: Self) -> Self; + + #[cfg(todo)] + fn log2(self) -> Self; + + #[cfg(todo)] + fn log10(self) -> Self; + + #[cfg(todo)] + fn cbrt(self) -> Self; + + #[cfg(todo)] + fn hypot(self, other: Self) -> Self; + + #[cfg(todo)] + fn sin(self) -> Self; + + #[cfg(todo)] + fn cos(self) -> Self; + + #[cfg(todo)] + fn tan(self) -> Self; + + #[cfg(todo)] + fn asin(self) -> Self; + + #[cfg(todo)] + fn acos(self) -> Self; + + #[cfg(todo)] + fn atan(self) -> Self; + + #[cfg(todo)] + fn atan2(self, other: Self) -> Self; + + #[cfg(todo)] + #[inline] + fn sin_cos(self) -> (Self, Self) { + (self.sin(), self.cos()) + } + + #[cfg(todo)] + fn exp_m1(self) -> Self; + + #[cfg(todo)] + fn ln_1p(self) -> Self; + + #[cfg(todo)] + fn sinh(self) -> Self; + + #[cfg(todo)] + fn cosh(self) -> Self; + + #[cfg(todo)] + fn tanh(self) -> Self; + + #[cfg(todo)] + fn asinh(self) -> Self; + + #[cfg(todo)] + fn acosh(self) -> Self; + + #[cfg(todo)] + fn atanh(self) -> Self; +} + +impl F32Ext for f32 { + #[cfg(todo)] + #[inline] + fn floor(self) -> Self { + floorf(self) + } + + #[cfg(todo)] + #[inline] + fn ceil(self) -> Self { + ceilf(self) + } + + #[cfg(todo)] + #[inline] + fn round(self) -> Self { + roundf(self) + } + + #[cfg(todo)] + #[inline] + fn trunc(self) -> Self { + truncf(self) + } + + #[cfg(todo)] + #[inline] + fn fract(self) -> Self { + self - self.trunc() + } + + #[inline] + fn abs(self) -> Self { + fabsf(self) + } + + #[cfg(todo)] + #[inline] + fn mul_add(self, a: Self, b: Self) -> Self { + fmaf(self, a, b) + } + + #[cfg(todo)] + #[inline] + fn div_euc(self, rhs: Self) -> Self { + let q = (self / rhs).trunc(); + if self % rhs < 0.0 { + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; + } + q + } + + #[cfg(todo)] + #[inline] + fn mod_euc(self, rhs: f32) -> f32 { + let r = self % rhs; + if r < 0.0 { + r + rhs.abs() + } else { + r + } + } + + #[inline] + fn powf(self, n: Self) -> Self { + powf(self, n) + } + + #[inline] + fn sqrt(self) -> Self { + sqrtf(self) + } + + #[cfg(todo)] + #[inline] + fn exp(self) -> Self { + expf(self) + } + + #[cfg(todo)] + #[inline] + fn exp2(self) -> Self { + exp2f(self) + } + + #[cfg(todo)] + #[inline] + fn ln(self) -> Self { + logf(self) + } + + #[cfg(todo)] + #[inline] + fn log(self, base: Self) -> Self { + self.ln() / base.ln() + } + + #[cfg(todo)] + #[inline] + fn log2(self) -> Self { + log2f(self) + } + + #[cfg(todo)] + #[inline] + fn log10(self) -> Self { + log10f(self) + } + + #[cfg(todo)] + #[inline] + fn cbrt(self) -> Self { + cbrtf(self) + } + + #[cfg(todo)] + #[inline] + fn hypot(self, other: Self) -> Self { + hypotf(self, other) + } + + #[cfg(todo)] + #[inline] + fn sin(self) -> Self { + sinf(self) + } + + #[cfg(todo)] + #[inline] + fn cos(self) -> Self { + cosf(self) + } + + #[cfg(todo)] + #[inline] + fn tan(self) -> Self { + tanf(self) + } + + #[cfg(todo)] + #[inline] + fn asin(self) -> Self { + asinf(self) + } + + #[cfg(todo)] + #[inline] + fn acos(self) -> Self { + acosf(self) + } + + #[cfg(todo)] + #[inline] + fn atan(self) -> Self { + atanf(self) + } + + #[cfg(todo)] + #[inline] + fn atan2(self, other: Self) -> Self { + atan2f(self, other) + } + + #[cfg(todo)] + #[inline] + fn exp_m1(self) -> Self { + expm1f(self) + } + + #[cfg(todo)] + #[inline] + fn ln_1p(self) -> Self { + log1pf(self) + } + + #[cfg(todo)] + #[inline] + fn sinh(self) -> Self { + sinhf(self) + } + + #[cfg(todo)] + #[inline] + fn cosh(self) -> Self { + coshf(self) + } + + #[cfg(todo)] + #[inline] + fn tanh(self) -> Self { + tanhf(self) + } + + #[cfg(todo)] + #[inline] + fn asinh(self) -> Self { + if self == f32::NEG_INFINITY { + f32::NEG_INFINITY + } else { + (self + ((self * self) + 1.0).sqrt()).ln() + } + } + + #[cfg(todo)] + #[inline] + fn acosh(self) -> Self { + match self { + x if x < 1.0 => f32::NAN, + x => (x + ((x * x) - 1.0).sqrt()).ln(), + } + } + + #[cfg(todo)] + #[inline] + fn atanh(self) -> Self { + 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() + } +} + +/// Math support for `f32` +/// +/// NOTE this meant to be a closed extension trait. The only stable way to use this trait is to +/// import it to access its methods. +pub trait F64Ext { + #[cfg(todo)] + fn floor(self) -> Self; + + #[cfg(todo)] + fn ceil(self) -> Self; + + #[cfg(todo)] + fn round(self) -> Self; + + #[cfg(todo)] + fn trunc(self) -> Self; + + #[cfg(todo)] + fn fract(self) -> Self; + + fn abs(self) -> Self; + + #[cfg(todo)] + fn signum(self) -> Self; + + #[cfg(todo)] + fn mul_add(self, a: Self, b: Self) -> Self; + + #[cfg(todo)] + fn div_euc(self, rhs: Self) -> Self; + + #[cfg(todo)] + fn mod_euc(self, rhs: Self) -> Self; + + // NOTE depends on unstable intrinsics::powif64 + // fn powi(self, n: i32) -> Self; + + #[cfg(todo)] + fn powf(self, n: Self) -> Self; + + #[cfg(todo)] + fn sqrt(self) -> Self; + + #[cfg(todo)] + fn exp(self) -> Self; + + #[cfg(todo)] + fn exp2(self) -> Self; + + #[cfg(todo)] + fn ln(self) -> Self; + + #[cfg(todo)] + fn log(self, base: Self) -> Self; + + #[cfg(todo)] + fn log2(self) -> Self; + + #[cfg(todo)] + fn log10(self) -> Self; + + #[cfg(todo)] + fn cbrt(self) -> Self; + + #[cfg(todo)] + fn hypot(self, other: Self) -> Self; + + #[cfg(todo)] + fn sin(self) -> Self; + + #[cfg(todo)] + fn cos(self) -> Self; + + #[cfg(todo)] + fn tan(self) -> Self; + + #[cfg(todo)] + fn asin(self) -> Self; + + #[cfg(todo)] + fn acos(self) -> Self; + + #[cfg(todo)] + fn atan(self) -> Self; + + #[cfg(todo)] + fn atan2(self, other: Self) -> Self; + + #[cfg(todo)] + #[inline] + fn sin_cos(self) -> (Self, Self) { + (self.sin(), self.cos()) + } + + #[cfg(todo)] + fn exp_m1(self) -> Self; + + #[cfg(todo)] + fn ln_1p(self) -> Self; + + #[cfg(todo)] + fn sinh(self) -> Self; + + #[cfg(todo)] + fn cosh(self) -> Self; + + #[cfg(todo)] + fn tanh(self) -> Self; + + #[cfg(todo)] + fn asinh(self) -> Self; + + #[cfg(todo)] + fn acosh(self) -> Self; + + #[cfg(todo)] + fn atanh(self) -> Self; +} + +impl F64Ext for f64 { + #[cfg(todo)] + #[inline] + fn floor(self) -> Self { + floor(self) + } + + #[cfg(todo)] + #[inline] + fn ceil(self) -> Self { + ceil(self) + } + + #[cfg(todo)] + #[inline] + fn round(self) -> Self { + round(self) + } + + #[cfg(todo)] + #[inline] + fn trunc(self) -> Self { + trunc(self) + } + + #[cfg(todo)] + #[inline] + fn fract(self) -> Self { + self - self.trunc() + } + + #[inline] + fn abs(self) -> Self { + fabs(self) + } + + #[cfg(todo)] + #[inline] + fn mul_add(self, a: Self, b: Self) -> Self { + fma(self, a, b) + } + + #[cfg(todo)] + #[inline] + fn div_euc(self, rhs: Self) -> Self { + let q = (self / rhs).trunc(); + if self % rhs < 0.0 { + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; + } + q + } + + #[cfg(todo)] + #[inline] + fn mod_euc(self, rhs: f32) -> f32 { + let r = self % rhs; + if r < 0.0 { + r + rhs.abs() + } else { + r + } + } + + #[cfg(todo)] + #[inline] + fn powf(self, n: Self) -> Self { + pow(self, n) + } + + #[cfg(todo)] + #[inline] + fn sqrt(self) -> Self { + sqrt(self) + } + + #[cfg(todo)] + #[inline] + fn exp(self) -> Self { + exp(self) + } + + #[cfg(todo)] + #[inline] + fn exp2(self) -> Self { + exp2(self) + } + + #[cfg(todo)] + #[inline] + fn ln(self) -> Self { + log(self) + } + + #[cfg(todo)] + #[inline] + fn log(self, base: Self) -> Self { + self.ln() / base.ln() + } + + #[cfg(todo)] + #[inline] + fn log2(self) -> Self { + log2(self) + } + + #[cfg(todo)] + #[inline] + fn log10(self) -> Self { + log10(self) + } + + #[cfg(todo)] + #[inline] + fn cbrt(self) -> Self { + cbrt(self) + } + + #[cfg(todo)] + #[inline] + fn hypot(self, other: Self) -> Self { + hypot(self, other) + } + + #[cfg(todo)] + #[inline] + fn sin(self) -> Self { + sin(self) + } + + #[cfg(todo)] + #[inline] + fn cos(self) -> Self { + cos(self) + } + + #[cfg(todo)] + #[inline] + fn tan(self) -> Self { + tan(self) + } + + #[cfg(todo)] + #[inline] + fn asin(self) -> Self { + asin(self) + } + + #[cfg(todo)] + #[inline] + fn acos(self) -> Self { + acos(self) + } + + #[cfg(todo)] + #[inline] + fn atan(self) -> Self { + atan(self) + } + + #[cfg(todo)] + #[inline] + fn atan2(self, other: Self) -> Self { + atan2(self, other) + } + + #[cfg(todo)] + #[inline] + fn exp_m1(self) -> Self { + expm1(self) + } + + #[cfg(todo)] + #[inline] + fn ln_1p(self) -> Self { + log1p(self) + } + + #[cfg(todo)] + #[inline] + fn sinh(self) -> Self { + sinh(self) + } + + #[cfg(todo)] + #[inline] + fn cosh(self) -> Self { + cosh(self) + } + + #[cfg(todo)] + #[inline] + fn tanh(self) -> Self { + tanh(self) + } + + #[cfg(todo)] + #[inline] + fn asinh(self) -> Self { + if self == f64::NEG_INFINITY { + f64::NEG_INFINITY + } else { + (self + ((self * self) + 1.0).sqrt()).ln() + } + } + + #[cfg(todo)] + #[inline] + fn acosh(self) -> Self { + match self { + x if x < 1.0 => f64::NAN, + x => (x + ((x * x) - 1.0).sqrt()).ln(), + } + } + + #[cfg(todo)] + #[inline] + fn atanh(self) -> Self { + 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() + } +} From f556a9bbb422e86c76334fe3fe0a3c0382707946 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 20:19:42 -0500 Subject: [PATCH 0482/4206] test source importing this crate --- library/compiler-builtins/libm/Cargo.toml | 2 +- library/compiler-builtins/libm/README.md | 5 ++++- library/compiler-builtins/libm/cb/Cargo.toml | 6 ++++++ library/compiler-builtins/libm/cb/src/lib.rs | 9 +++++++++ library/compiler-builtins/libm/ci/script.sh | 10 ++++++++++ 5 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/libm/cb/Cargo.toml create mode 100644 library/compiler-builtins/libm/cb/src/lib.rs diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 96bc290fb3201..e3498eed03819 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -4,4 +4,4 @@ version = "0.1.0" authors = ["Jorge Aparicio "] [workspace] -members = ["test-generator"] \ No newline at end of file +members = ["cb", "test-generator"] \ No newline at end of file diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 55f4654346e67..cb29baf63a7b1 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -32,7 +32,7 @@ $ TARGET=armv7-unknown-linux-gnueabihf bash ci/script.sh - Pick your favorite math function from the [issue tracker]. - Look for the C implementation of the function in the [MUSL source code][src]. - Copy paste the C code into a Rust file in the `src/math` directory and adjust `src/math/mod.rs` - accordingly. + accordingly. Also, uncomment the corresponding trait method in `src/lib.rs`. - Run `cargo watch check` and fix the compiler errors. - Tweak the bottom of `test-generator/src/main.rs` to add your function to the test suite. - If you can, run the test suite locally. If you can't, no problem! Your PR will be tested @@ -49,6 +49,9 @@ Check [PR #2] for an example. ### Notes +- Only use relative imports within the `math` directory / module, e.g. `use self::fabs::fabs` or +`use super::isnanf`. Absolute imports from core are OK, e.g. `use core::u64`. + - To reinterpret a float as an integer use the `to_bits` method. The MUSL code uses the `GET_FLOAT_WORD` macro, or a union, to do this operation. diff --git a/library/compiler-builtins/libm/cb/Cargo.toml b/library/compiler-builtins/libm/cb/Cargo.toml new file mode 100644 index 0000000000000..40e75dd22fd19 --- /dev/null +++ b/library/compiler-builtins/libm/cb/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "cb" +version = "0.1.0" +authors = ["Jorge Aparicio "] + +[dependencies] diff --git a/library/compiler-builtins/libm/cb/src/lib.rs b/library/compiler-builtins/libm/cb/src/lib.rs new file mode 100644 index 0000000000000..439ba7dc4e63f --- /dev/null +++ b/library/compiler-builtins/libm/cb/src/lib.rs @@ -0,0 +1,9 @@ +//! Fake compiler-builtins crate +//! +//! This is used to test that we can source import `libm` into the compiler-builtins crate. + +#![allow(dead_code)] +#![no_std] + +#[path = "../../src/math/mod.rs"] +mod libm; diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh index ee2e458cc036c..3db6bfeb12d9a 100644 --- a/library/compiler-builtins/libm/ci/script.sh +++ b/library/compiler-builtins/libm/ci/script.sh @@ -1,11 +1,21 @@ set -euxo pipefail main() { + # quick check + cargo check + + # check that we can source import libm into compiler-builtins + cargo check --package cb + + # generate tests cargo run --package test-generator --target x86_64-unknown-linux-musl + if cargo fmt --version >/dev/null 2>&1; then # nicer syntax error messages (if any) cargo fmt fi + + # run tests cross test --target $TARGET --release # TODO need to fix overflow issues (cf. issue #4) From 50f9ad97a58576c4c8aecdf392242736fc11efd8 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 13 Jul 2018 00:40:05 +0000 Subject: [PATCH 0483/4206] Implement `round` --- library/compiler-builtins/libm/src/lib.rs | 6 ++++ .../compiler-builtins/libm/src/math/mod.rs | 2 ++ .../compiler-builtins/libm/src/math/round.rs | 35 +++++++++++++++++++ .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/libm/src/math/round.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index fc9628d919f31..f54366b95ae21 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -12,6 +12,12 @@ #![deny(warnings)] #![no_std] +macro_rules! force_eval { + ($e:expr) => { + unsafe { ::core::ptr::read_volatile(&$e); } + } +} + mod math; #[cfg(todo)] diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 09d81944c27bd..c150a629516c6 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -2,6 +2,7 @@ mod fabs; mod fabsf; mod fmodf; mod powf; +mod round; mod scalbnf; mod sqrtf; @@ -9,6 +10,7 @@ pub use self::fabs::fabs; pub use self::fabsf::fabsf; pub use self::fmodf::fmodf; pub use self::powf::powf; +pub use self::round::round; pub use self::scalbnf::scalbnf; pub use self::sqrtf::sqrtf; diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs new file mode 100644 index 0000000000000..2a9f67c1d0fa2 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -0,0 +1,35 @@ +use core::f64; + +const TOINT: f64 = 1.0 / f64::EPSILON; + +pub fn round(mut x: f64) -> f64 { + let (f, i) = (x, x.to_bits()); + let e: u64 = i >> 52 & 0x7ff; + let mut y: f64; + + if e >= 0x3ff + 52 { + return x; + } + if i >> 63 != 0 { + x = -x; + } + if e < 0x3ff - 1 { + // raise inexact if x!=0 + force_eval!(x + TOINT); + return 0.0 * f; + } + y = x + TOINT - TOINT - x; + if y > 0.5 { + y = y + x - 1.0; + } else if y <= -0.5 { + y = y + x + 1.0; + } else { + y = y + x; + } + + if i >> 63 != 0 { + -y + } else { + y + } +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index a13aa4ef705a5..5ff78ffc8b37d 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -618,7 +618,7 @@ f64_f64! { // log10, // log1p, // log2, - // round, + round, // sin, // sinh, // sqrt, From 3accabd018c1645817d0b0cd234be6c5eae4d73a Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 13 Jul 2018 01:25:46 +0000 Subject: [PATCH 0484/4206] Enable f64::round --- library/compiler-builtins/libm/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index f54366b95ae21..06ef4592dcee0 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -383,7 +383,6 @@ pub trait F64Ext { #[cfg(todo)] fn ceil(self) -> Self; - #[cfg(todo)] fn round(self) -> Self; #[cfg(todo)] @@ -504,7 +503,6 @@ impl F64Ext for f64 { ceil(self) } - #[cfg(todo)] #[inline] fn round(self) -> Self { round(self) From 9395c8002c0bacb90a2a0008ddf709c775ce5a90 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 13 Jul 2018 01:38:04 +0000 Subject: [PATCH 0485/4206] Move the `force_eval!` macro into the math module This fixes the cross-inclusion into the compiler builtins --- library/compiler-builtins/libm/src/lib.rs | 6 ------ library/compiler-builtins/libm/src/math/mod.rs | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 06ef4592dcee0..0d13590c7ecca 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -12,12 +12,6 @@ #![deny(warnings)] #![no_std] -macro_rules! force_eval { - ($e:expr) => { - unsafe { ::core::ptr::read_volatile(&$e); } - } -} - mod math; #[cfg(todo)] diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index c150a629516c6..41359bf8c059a 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -1,3 +1,9 @@ +macro_rules! force_eval { + ($e:expr) => { + unsafe { ::core::ptr::read_volatile(&$e); } + } +} + mod fabs; mod fabsf; mod fmodf; From 505e4ce81c019550d6e90986dc5b328fbc6fd7cc Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 13 Jul 2018 11:10:41 +0300 Subject: [PATCH 0486/4206] add exp and log/ln functions for f32 --- library/compiler-builtins/libm/src/lib.rs | 6 -- .../compiler-builtins/libm/src/math/expf.rs | 76 +++++++++++++++++++ .../compiler-builtins/libm/src/math/logf.rs | 49 ++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 4 + 4 files changed, 129 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/expf.rs create mode 100644 library/compiler-builtins/libm/src/math/logf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 0d13590c7ecca..bb00149dfd245 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -71,16 +71,13 @@ pub trait F32Ext { fn sqrt(self) -> Self; - #[cfg(todo)] fn exp(self) -> Self; #[cfg(todo)] fn exp2(self) -> Self; - #[cfg(todo)] fn ln(self) -> Self; - #[cfg(todo)] fn log(self, base: Self) -> Self; #[cfg(todo)] @@ -220,7 +217,6 @@ impl F32Ext for f32 { sqrtf(self) } - #[cfg(todo)] #[inline] fn exp(self) -> Self { expf(self) @@ -232,13 +228,11 @@ impl F32Ext for f32 { exp2f(self) } - #[cfg(todo)] #[inline] fn ln(self) -> Self { logf(self) } - #[cfg(todo)] #[inline] fn log(self, base: Self) -> Self { self.ln() / base.ln() diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs new file mode 100644 index 0000000000000..c26ff8e64124b --- /dev/null +++ b/library/compiler-builtins/libm/src/math/expf.rs @@ -0,0 +1,76 @@ +use super::scalbnf; + +const HALF : [f32; 2] = [0.5,-0.5]; +const LN2_HI : f32 = 6.9314575195e-01; /* 0x3f317200 */ +const LN2_LO : f32 = 1.4286067653e-06; /* 0x35bfbe8e */ +const INV_LN2 : f32 = 1.4426950216e+00; /* 0x3fb8aa3b */ +/* + * Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]: + * |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74 + */ +const P1 : f32 = 1.6666625440e-1; /* 0xaaaa8f.0p-26 */ +const P2 : f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ + +#[inline] +pub fn expf(mut x: f32) -> f32 { + let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 + let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */ + + let mut hx = x.to_bits() as i32; + let sign = (hx >> 31) as i32; /* sign bit of x */ + let signb : bool = sign != 0; + hx &= 0x7fffffff; /* high word of |x| */ + + /* special cases */ + if hx >= 0x42aeac50 { /* if |x| >= -87.33655f or NaN */ + if hx > 0x7f800000 {/* NaN */ + return x; + } + if (hx >= 0x42b17218) && (!signb) { /* x >= 88.722839f */ + /* overflow */ + x *= x1p127; + return x; + } + if signb { + /* underflow */ + force_eval!(-x1p_126/x); + if hx >= 0x42cff1b5 { /* x <= -103.972084f */ + return 0. + } + } + } + + /* argument reduction */ + let k : i32; + let hi : f32; + let lo : f32; + if hx > 0x3eb17218 { /* if |x| > 0.5 ln2 */ + if hx > 0x3f851592 { /* if |x| > 1.5 ln2 */ + k = (INV_LN2*x + HALF[sign as usize]) as i32; + } else { + k = 1 - sign - sign; + } + let kf = k as f32; + hi = x - kf*LN2_HI; /* k*ln2hi is exact here */ + lo = kf*LN2_LO; + x = hi - lo; + } else if hx > 0x39000000 { /* |x| > 2**-14 */ + k = 0; + hi = x; + lo = 0.; + } else { + /* raise inexact */ + force_eval!(x1p127 + x); + return 1. + x; + } + + /* x is now in primary range */ + let xx = x*x; + let c = x - xx*(P1+xx*P2); + let y = 1. + (x*c/(2.-c) - lo + hi); + if k == 0 { + y + } else { + scalbnf(y, k) + } +} diff --git a/library/compiler-builtins/libm/src/math/logf.rs b/library/compiler-builtins/libm/src/math/logf.rs new file mode 100644 index 0000000000000..f8bbe733aa853 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/logf.rs @@ -0,0 +1,49 @@ +const LN2_HI : f32 = 6.9313812256e-01; /* 0x3f317180 */ +const LN2_LO : f32 = 9.0580006145e-06; /* 0x3717f7d1 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +const LG1 : f32 = 0.66666662693; /* 0xaaaaaa.0p-24*/ +const LG2 : f32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3 : f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4 : f32 = 0.24279078841; /* 0xf89e26.0p-26 */ + +#[inline] +pub fn logf(mut x: f32) -> f32 { + let x1p25 = f32::from_bits(0x4c000000); // 0x1p24f === 2 ^ 25 + + let mut ix = x.to_bits(); + let mut k = 0i32; + + if (ix < 0x00800000) || ((ix>>31) != 0) { /* x < 2**-126 */ + if ix<<1 == 0 { + return -1./(x*x); /* log(+-0)=-inf */ + } + if (ix>>31) != 0 { + return (x-x)/0.; /* log(-#) = NaN */ + } + /* subnormal number, scale up x */ + k -= 25; + x *= x1p25; + ix = x.to_bits(); + } else if ix >= 0x7f800000 { + return x; + } else if ix == 0x3f800000 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += ((ix>>23) as i32) - 0x7f; + ix = (ix & 0x007fffff) + 0x3f3504f3; + x = f32::from_bits(ix); + + let f = x - 1.; + let s = f/(2. + f); + let z = s*s; + let w = z*z; + let t1 = w*(LG2+w*LG4); + let t2 = z*(LG1+w*LG3); + let r = t2 + t1; + let hfsq = 0.5*f*f; + let dk = k as f32; + s*(hfsq+r) + dk*LN2_LO - hfsq + f + dk*LN2_HI +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 41359bf8c059a..5edf6fd740dfd 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -11,6 +11,8 @@ mod powf; mod round; mod scalbnf; mod sqrtf; +mod logf; +mod expf; pub use self::fabs::fabs; pub use self::fabsf::fabsf; @@ -19,6 +21,8 @@ pub use self::powf::powf; pub use self::round::round; pub use self::scalbnf::scalbnf; pub use self::sqrtf::sqrtf; +pub use self::logf::logf; +pub use self::expf::expf; fn isnanf(x: f32) -> bool { x.to_bits() & 0x7fffffff > 0x7f800000 From b8aae8ef23d18bcd03f75252a2164d87da833b9a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 13 Jul 2018 11:16:43 -0500 Subject: [PATCH 0487/4206] enable tests for expf and logf --- library/compiler-builtins/libm/test-generator/src/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 5ff78ffc8b37d..d324c4f09f614 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -570,10 +570,11 @@ f32_f32! { // cosf, // coshf, // exp2f, - // expf, + expf, // fdimf, // log10f, // log2f, + logf, // roundf, // sinf, // sinhf, From 7e419befa1bf59fde2ac4fdd3fd44464e9e1b3c6 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 13 Jul 2018 21:02:11 +0300 Subject: [PATCH 0488/4206] add floor, scalbn; fixes in expf, scalbnf --- library/compiler-builtins/libm/src/lib.rs | 2 -- .../compiler-builtins/libm/src/math/expf.rs | 8 ++--- .../compiler-builtins/libm/src/math/floor.rs | 29 ++++++++++++++++ .../compiler-builtins/libm/src/math/logf.rs | 2 +- .../compiler-builtins/libm/src/math/mod.rs | 26 ++++++++++----- .../compiler-builtins/libm/src/math/scalbn.rs | 33 +++++++++++++++++++ .../libm/src/math/scalbnf.rs | 26 ++++++--------- 7 files changed, 94 insertions(+), 32 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/floor.rs create mode 100644 library/compiler-builtins/libm/src/math/scalbn.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index bb00149dfd245..ed163ff98c79b 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -365,7 +365,6 @@ impl F32Ext for f32 { /// NOTE this meant to be a closed extension trait. The only stable way to use this trait is to /// import it to access its methods. pub trait F64Ext { - #[cfg(todo)] fn floor(self) -> Self; #[cfg(todo)] @@ -479,7 +478,6 @@ pub trait F64Ext { } impl F64Ext for f64 { - #[cfg(todo)] #[inline] fn floor(self) -> Self { floor(self) diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs index c26ff8e64124b..1b645654e3695 100644 --- a/library/compiler-builtins/libm/src/math/expf.rs +++ b/library/compiler-builtins/libm/src/math/expf.rs @@ -13,16 +13,16 @@ const P2 : f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ #[inline] pub fn expf(mut x: f32) -> f32 { - let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 - let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */ + let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 + let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */ - let mut hx = x.to_bits() as i32; + let mut hx = x.to_bits(); let sign = (hx >> 31) as i32; /* sign bit of x */ let signb : bool = sign != 0; hx &= 0x7fffffff; /* high word of |x| */ /* special cases */ - if hx >= 0x42aeac50 { /* if |x| >= -87.33655f or NaN */ + if hx >= 0x42aeac50 { /* if |x| >= -87.33655f or NaN */ if hx > 0x7f800000 {/* NaN */ return x; } diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs new file mode 100644 index 0000000000000..a5fb1757413b8 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -0,0 +1,29 @@ +use core::f64; + +const TOINT : f64 = 1. / f64::EPSILON; + +#[inline] +pub fn floor(x : f64) -> f64 { + let ui = x.to_bits(); + let e = ((ui >> 52) & 0x7ff) as i32; + + if (e >= 0x3ff+52) || (x == 0.) { + return x; + } + /* y = int(x) - x, where int(x) is an integer neighbor of x */ + let y = if (ui >> 63) != 0 { + x - TOINT + TOINT - x + } else { + x + TOINT - TOINT - x + }; + /* special case because of non-nearest rounding modes */ + if e <= 0x3ff-1 { + force_eval!(y); + return if (ui >> 63) != 0 { -1. } else { 0. }; + } + if y > 0. { + x + y - 1. + } else { + x + y + } +} diff --git a/library/compiler-builtins/libm/src/math/logf.rs b/library/compiler-builtins/libm/src/math/logf.rs index f8bbe733aa853..76b4ede195149 100644 --- a/library/compiler-builtins/libm/src/math/logf.rs +++ b/library/compiler-builtins/libm/src/math/logf.rs @@ -8,7 +8,7 @@ const LG4 : f32 = 0.24279078841; /* 0xf89e26.0p-26 */ #[inline] pub fn logf(mut x: f32) -> f32 { - let x1p25 = f32::from_bits(0x4c000000); // 0x1p24f === 2 ^ 25 + let x1p25 = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 let mut ix = x.to_bits(); let mut k = 0i32; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 5edf6fd740dfd..e400badd12939 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -9,20 +9,28 @@ mod fabsf; mod fmodf; mod powf; mod round; +mod scalbn; mod scalbnf; mod sqrtf; mod logf; mod expf; +mod floor; -pub use self::fabs::fabs; -pub use self::fabsf::fabsf; -pub use self::fmodf::fmodf; -pub use self::powf::powf; -pub use self::round::round; -pub use self::scalbnf::scalbnf; -pub use self::sqrtf::sqrtf; -pub use self::logf::logf; -pub use self::expf::expf; +//mod service; + +pub use self::{ + fabs::fabs, + fabsf::fabsf, + fmodf::fmodf, + powf::powf, + round::round, + scalbn::scalbn, + scalbnf::scalbnf, + sqrtf::sqrtf, + logf::logf, + expf::expf, + floor::floor, +}; fn isnanf(x: f32) -> bool { x.to_bits() & 0x7fffffff > 0x7f800000 diff --git a/library/compiler-builtins/libm/src/math/scalbn.rs b/library/compiler-builtins/libm/src/math/scalbn.rs new file mode 100644 index 0000000000000..76e06f03ece25 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/scalbn.rs @@ -0,0 +1,33 @@ +#[inline] +pub fn scalbn(x : f64, mut n: i32) -> f64 { + let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 + let x1p53 = f64::from_bits(0x4340000000000000); // 0x1p53 === 2 ^ 53 + let x1p_1022 = f64::from_bits(0x0010000000000000); // 0x1p-1022 === 2 ^ (-1022) + + let mut y = x; + + if n > 1023 { + y *= x1p1023; + n -= 1023; + if n > 1023 { + y *= x1p1023; + n -= 1023; + if n > 1023 { + n = 1023; + } + } + } else if n < -1022 { + /* make sure final n < -53 to avoid double + rounding in the subnormal range */ + y *= x1p_1022 * x1p53; + n += 1022 - 53; + if n < -1022 { + y *= x1p_1022 * x1p53; + n += 1022 - 53; + if n < -1022 { + n = -1022; + } + } + } + y*f64::from_bits(((0x3ff+n) as u64)<<52) +} diff --git a/library/compiler-builtins/libm/src/math/scalbnf.rs b/library/compiler-builtins/libm/src/math/scalbnf.rs index 2ae8bf31b772b..31f93d323c5c9 100644 --- a/library/compiler-builtins/libm/src/math/scalbnf.rs +++ b/library/compiler-builtins/libm/src/math/scalbnf.rs @@ -1,35 +1,29 @@ #[inline] -pub fn scalbnf(mut x: f32, mut n: i32) -> f32 { - let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 - let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 - let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 - - let mut y: f32 = x; - +pub fn scalbnf(mut x: f32, mut n : i32) -> f32 { + let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 + let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 + let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 + if n > 127 { - y *= x1p127; + x *= x1p127; n -= 127; if n > 127 { - y *= x1p127; + x *= x1p127; n -= 127; if n > 127 { n = 127; } } } else if n < -126 { - y *= x1p_126; - y *= x1p24; + x *= x1p_126 * x1p24; n += 126 - 24; if n < -126 { - y *= x1p_126; - y *= x1p24; + x *= x1p_126 * x1p24; n += 126 - 24; if n < -126 { n = -126; } } } - - x = y * f32::from_bits((0x7f + n as u32) << 23); - x + x * f32::from_bits(((0x7f+n) as u32)<<23) } From 47afc3992ff0df14d89b65f1d8834c62930201a7 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 13 Jul 2018 13:36:59 -0500 Subject: [PATCH 0489/4206] enable tests for floor and scalbn --- library/compiler-builtins/libm/test-generator/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index d324c4f09f614..42e157ad8768f 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -614,7 +614,7 @@ f64_f64! { // exp, // exp2, // expm1, - // floor, + floor, // log, // log10, // log1p, @@ -645,5 +645,5 @@ f64f64f64_f64! { // With signature `fn(f64, i32) -> f64` f64i32_f64! { - // scalbn, + scalbn, } From 8cdd2678306ce916daa42ac6d9f49cd5a7e0473b Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 13 Jul 2018 16:04:30 -0400 Subject: [PATCH 0490/4206] implement trunc and truncf --- library/compiler-builtins/libm/src/lib.rs | 4 ---- .../compiler-builtins/libm/src/math/mod.rs | 4 ++++ .../compiler-builtins/libm/src/math/trunc.rs | 24 +++++++++++++++++++ .../compiler-builtins/libm/src/math/truncf.rs | 24 +++++++++++++++++++ .../libm/test-generator/src/main.rs | 4 ++-- 5 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/trunc.rs create mode 100644 library/compiler-builtins/libm/src/math/truncf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index ed163ff98c79b..fa709ad754a98 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -44,7 +44,6 @@ pub trait F32Ext { #[cfg(todo)] fn round(self) -> Self; - #[cfg(todo)] fn trunc(self) -> Self; #[cfg(todo)] @@ -163,7 +162,6 @@ impl F32Ext for f32 { roundf(self) } - #[cfg(todo)] #[inline] fn trunc(self) -> Self { truncf(self) @@ -372,7 +370,6 @@ pub trait F64Ext { fn round(self) -> Self; - #[cfg(todo)] fn trunc(self) -> Self; #[cfg(todo)] @@ -494,7 +491,6 @@ impl F64Ext for f64 { round(self) } - #[cfg(todo)] #[inline] fn trunc(self) -> Self { trunc(self) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index e400badd12939..71b58dda88323 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -15,6 +15,8 @@ mod sqrtf; mod logf; mod expf; mod floor; +mod trunc; +mod truncf; //mod service; @@ -30,6 +32,8 @@ pub use self::{ logf::logf, expf::expf, floor::floor, + trunc::trunc, + truncf::truncf, }; fn isnanf(x: f32) -> bool { diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs new file mode 100644 index 0000000000000..b50ffd77156a2 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -0,0 +1,24 @@ +use core::f64; + +#[inline] +pub fn trunc(x: f64) -> f64 { + let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 + + let mut i: u64 = x.to_bits(); + let mut e: i64 = (i >> 52 & 0x7ff) as i64 - 0x3ff + 12; + let m: u64; + + if e >= 52 + 12 { + return x; + } + if e < 12 { + e = 1; + } + m = -1i64 as u64 >> e; + if (i & m) == 0 { + return x; + } + force_eval!(x + x1p120); + i &= !m; + f64::from_bits(i) +} diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs new file mode 100644 index 0000000000000..f7d7249e3519b --- /dev/null +++ b/library/compiler-builtins/libm/src/math/truncf.rs @@ -0,0 +1,24 @@ +use core::f32; + +#[inline] +pub fn truncf(x: f32) -> f32 { + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + let mut i: u32 = x.to_bits(); + let mut e: i32 = (i >> 23 & 0xff) as i32 - 0x7f + 9; + let m: u32; + + if e >= 23 + 9 { + return x; + } + if e < 9 { + e = 1; + } + m = -1i32 as u32 >> e; + if (i & m) == 0 { + return x; + } + force_eval!(x + x1p120); + i &= !m; + f32::from_bits(i) +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 42e157ad8768f..6353b257dce3d 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -562,7 +562,7 @@ fn main() -> Result<(), Box> { f32_f32! { // acosf, // floorf, - // truncf + truncf, // asinf, // atanf, // cbrtf, @@ -625,7 +625,7 @@ f64_f64! { // sqrt, // tan, // tanh, - // trunc, + trunc, fabs, } From ece6cc8044835342c0a53b81be56c4029d002089 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 13 Jul 2018 23:23:14 +0300 Subject: [PATCH 0491/4206] add cosf with dependencies --- library/compiler-builtins/libm/src/lib.rs | 2 - .../compiler-builtins/libm/src/math/cosf.rs | 65 +++ .../compiler-builtins/libm/src/math/mod.rs | 4 +- .../libm/src/math/service/cosdf.rs | 13 + .../libm/src/math/service/mod.rs | 11 + .../libm/src/math/service/rem_pio2_large.rs | 489 ++++++++++++++++++ .../libm/src/math/service/rem_pio2f.rs | 44 ++ .../libm/src/math/service/sindf.rs | 14 + 8 files changed, 639 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/cosf.rs create mode 100644 library/compiler-builtins/libm/src/math/service/cosdf.rs create mode 100644 library/compiler-builtins/libm/src/math/service/mod.rs create mode 100644 library/compiler-builtins/libm/src/math/service/rem_pio2_large.rs create mode 100644 library/compiler-builtins/libm/src/math/service/rem_pio2f.rs create mode 100644 library/compiler-builtins/libm/src/math/service/sindf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index ed163ff98c79b..e51a7c2dc4898 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -95,7 +95,6 @@ pub trait F32Ext { #[cfg(todo)] fn sin(self) -> Self; - #[cfg(todo)] fn cos(self) -> Self; #[cfg(todo)] @@ -268,7 +267,6 @@ impl F32Ext for f32 { sinf(self) } - #[cfg(todo)] #[inline] fn cos(self) -> Self { cosf(self) diff --git a/library/compiler-builtins/libm/src/math/cosf.rs b/library/compiler-builtins/libm/src/math/cosf.rs new file mode 100644 index 0000000000000..b1aefd5e32b7b --- /dev/null +++ b/library/compiler-builtins/libm/src/math/cosf.rs @@ -0,0 +1,65 @@ +use super::service::{cosdf, sindf, rem_pio2f}; + +use core::f64::consts::FRAC_PI_2; + +/* Small multiples of pi/2 rounded to double precision. */ +const C1_PIO2 : f64 = 1.*FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ +const C2_PIO2 : f64 = 2.*FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ +const C3_PIO2 : f64 = 3.*FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const C4_PIO2 : f64 = 4.*FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ + +#[inline] +pub fn cosf(x: f32) -> f32 { + let x64 = x as f64; + + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + if ix <= 0x3f490fda { /* |x| ~<= pi/4 */ + if ix < 0x39800000 { /* |x| < 2**-12 */ + /* raise inexact if x != 0 */ + force_eval!(x + x1p120); + return 1.; + } + return cosdf(x64); + } + if ix <= 0x407b53d1 { /* |x| ~<= 5*pi/4 */ + if ix > 0x4016cbe3 { /* |x| ~> 3*pi/4 */ + return -cosdf(if sign { x64+C2_PIO2 } else { x64-C2_PIO2 }); + } else { + if sign { + return sindf(x64 + C1_PIO2); + } else { + return sindf(C1_PIO2 - x64); + } + } + } + if ix <= 0x40e231d5 { /* |x| ~<= 9*pi/4 */ + if ix > 0x40afeddf { /* |x| ~> 7*pi/4 */ + return cosdf(if sign { x64+C4_PIO2 } else { x64-C4_PIO2 }); + } else { + if sign { + return sindf(-x64 - C3_PIO2); + } else { + return sindf(x64 - C3_PIO2); + } + } + } + + /* cos(Inf or NaN) is NaN */ + if ix >= 0x7f800000 { + return x-x; + } + + /* general argument reduction needed */ + let (n, y) = rem_pio2f(x); + match n&3 { + 0 => { cosdf( y) }, + 1 => { sindf(-y) }, + 2 => { -cosdf( y) }, + _ => { sindf( y) }, + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index e400badd12939..bc69aca0f61dd 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -15,8 +15,9 @@ mod sqrtf; mod logf; mod expf; mod floor; +mod cosf; -//mod service; +mod service; pub use self::{ fabs::fabs, @@ -30,6 +31,7 @@ pub use self::{ logf::logf, expf::expf, floor::floor, + cosf::cosf, }; fn isnanf(x: f32) -> bool { diff --git a/library/compiler-builtins/libm/src/math/service/cosdf.rs b/library/compiler-builtins/libm/src/math/service/cosdf.rs new file mode 100644 index 0000000000000..6c5e9d3495a4a --- /dev/null +++ b/library/compiler-builtins/libm/src/math/service/cosdf.rs @@ -0,0 +1,13 @@ +/* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ +const C0 : f64 = -0.499999997251031003120; /* -0x1ffffffd0c5e81.0p-54 */ +const C1 : f64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ +const C2 : f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ +const C3 : f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ + +#[inline] +pub(crate) fn cosdf(x : f64) -> f32 { + let z = x*x; + let w = z*z; + let r = C2+z*C3; + (((1.0+z*C0) + w*C1) + (w*z)*r) as f32 +} diff --git a/library/compiler-builtins/libm/src/math/service/mod.rs b/library/compiler-builtins/libm/src/math/service/mod.rs new file mode 100644 index 0000000000000..96bb09431bad7 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/service/mod.rs @@ -0,0 +1,11 @@ +mod sindf; +mod cosdf; +mod rem_pio2f; +mod rem_pio2_large; + +pub(crate) use self::{ + cosdf::cosdf, + sindf::sindf, + rem_pio2f::rem_pio2f, + rem_pio2_large::rem_pio2_large, +}; diff --git a/library/compiler-builtins/libm/src/math/service/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/service/rem_pio2_large.rs new file mode 100644 index 0000000000000..017fc88bae2ed --- /dev/null +++ b/library/compiler-builtins/libm/src/math/service/rem_pio2_large.rs @@ -0,0 +1,489 @@ +use ::scalbn; +use ::F64Ext; + +/// double x[],y[]; int e0,nx,prec; +/// +/// __rem_pio2_large return the last three digits of N with +/// y = x - N*pi/2 +/// so that |y| < pi/2. +/// +/// The method is to compute the integer (mod 8) and fraction parts of +/// (2/pi)*x without doing the full multiplication. In general we +/// skip the part of the product that are known to be a huge integer ( +/// more accurately, = 0 mod 8 ). Thus the number of operations are +/// independent of the exponent of the input. +/// +/// (2/pi) is represented by an array of 24-bit integers in ipio2[]. +/// +/// Input parameters: +/// x[] The input value (must be positive) is broken into nx +/// pieces of 24-bit integers in double precision format. +/// x[i] will be the i-th 24 bit of x. The scaled exponent +/// of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 +/// match x's up to 24 bits. +/// +/// Example of breaking a double positive z into x[0]+x[1]+x[2]: +/// e0 = ilogb(z)-23 +/// z = scalbn(z,-e0) +/// for i = 0,1,2 +/// x[i] = floor(z) +/// z = (z-x[i])*2**24 +/// +/// y[] ouput result in an array of double precision numbers. +/// The dimension of y[] is: +/// 24-bit precision 1 +/// 53-bit precision 2 +/// 64-bit precision 2 +/// 113-bit precision 3 +/// The actual value is the sum of them. Thus for 113-bit +/// precison, one may have to do something like: +/// +/// long double t,w,r_head, r_tail; +/// t = (long double)y[2] + (long double)y[1]; +/// w = (long double)y[0]; +/// r_head = t+w; +/// r_tail = w - (r_head - t); +/// +/// e0 The exponent of x[0]. Must be <= 16360 or you need to +/// expand the ipio2 table. +/// +/// prec an integer indicating the precision: +/// 0 24 bits (single) +/// 1 53 bits (double) +/// 2 64 bits (extended) +/// 3 113 bits (quad) +/// External function: +/// double scalbn(), floor(); +/// +/// +/// Here is the description of some local variables: +/// +/// jk jk+1 is the initial number of terms of ipio2[] needed +/// in the computation. The minimum and recommended value +/// for jk is 3,4,4,6 for single, double, extended, and quad. +/// jk+1 must be 2 larger than you might expect so that our +/// recomputation test works. (Up to 24 bits in the integer +/// part (the 24 bits of it that we compute) and 23 bits in +/// the fraction part may be lost to cancelation before we +/// recompute.) +/// +/// jz local integer variable indicating the number of +/// terms of ipio2[] used. +/// +/// jx nx - 1 +/// +/// jv index for pointing to the suitable ipio2[] for the +/// computation. In general, we want +/// ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 +/// is an integer. Thus +/// e0-3-24*jv >= 0 or (e0-3)/24 >= jv +/// Hence jv = max(0,(e0-3)/24). +/// +/// jp jp+1 is the number of terms in PIo2[] needed, jp = jk. +/// +/// q[] double array with integral value, representing the +/// 24-bits chunk of the product of x and 2/pi. +/// +/// q0 the corresponding exponent of q[0]. Note that the +/// exponent for q[i] would be q0-24*i. +/// +/// PIo2[] double precision array, obtained by cutting pi/2 +/// into 24 bits chunks. +/// +/// f[] ipio2[] in floating point +/// +/// iq[] integer array by breaking up q[] in 24-bits chunk. +/// +/// fq[] final product of x*(2/pi) in fq[0],..,fq[jk] +/// +/// ih integer. If >0 it indicates q[] is >= 0.5, hence +/// it also indicates the *sign* of the result. + +const INIT_JK : [usize; 4] = [3,4,4,6]; /* initial value for jk */ + +/// Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi +/// +/// integer array, contains the (24*i)-th to (24*i+23)-th +/// bit of 2/pi after binary point. The corresponding +/// floating value is +/// +/// ipio2[i] * 2^(-24(i+1)). +/// +/// NB: This table must have at least (e0-3)/24 + jk terms. +/// For quad precision (e0 <= 16360, jk = 6), this is 686. +#[cfg(not(ldbl_max_exp_more1024))] +const IPIO2 : [i32; 66] = [ + 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, + 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, + 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, + 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, + 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, + 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, + 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, + 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, + 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, + 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, + 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, +]; + +#[cfg(ldbl_max_exp_more1024)] +const IPIO2 : [i32; 690] = [ + 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, + 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, + 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, + 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, + 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, + 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, + 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, + 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, + 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, + 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, + 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, + 0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, + 0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, + 0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35, + 0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, + 0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, + 0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4, + 0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, + 0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, + 0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19, + 0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, + 0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, + 0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6, + 0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, + 0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, + 0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3, + 0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, + 0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, + 0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612, + 0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, + 0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, + 0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B, + 0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, + 0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, + 0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB, + 0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, + 0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, + 0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F, + 0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, + 0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, + 0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B, + 0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, + 0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, + 0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3, + 0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, + 0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, + 0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F, + 0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, + 0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, + 0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51, + 0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, + 0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, + 0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6, + 0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, + 0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, + 0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328, + 0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, + 0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, + 0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B, + 0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, + 0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, + 0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F, + 0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, + 0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, + 0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4, + 0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, + 0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, + 0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30, + 0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, + 0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, + 0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1, + 0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, + 0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, + 0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08, + 0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, + 0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, + 0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4, + 0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, + 0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, + 0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0, + 0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, + 0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, + 0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC, + 0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, + 0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, + 0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7, + 0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, + 0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, + 0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4, + 0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, + 0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, + 0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2, + 0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, + 0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, + 0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569, + 0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, + 0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, + 0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D, + 0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, + 0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, + 0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569, + 0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, + 0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, + 0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41, + 0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, + 0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, + 0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110, + 0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, + 0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, + 0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A, + 0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, + 0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, + 0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616, + 0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, + 0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, +]; + +const PIO2 : [f64; 8] = [ + 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ + 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ + 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ + 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ + 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ + 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ + 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ + 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ +]; + +#[inline] +pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) -> i32 { + let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 + let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) + + #[cfg(not(ldbl_max_exp_more1024))] + assert!(e0 <= 16360); + + let nx = x.len(); + + let mut fw : f64; + let mut n : i32; + let mut ih : i32; + let mut z = 0f64; + let mut f : [f64;20] = [0.;20]; + let mut fq : [f64;20] = [0.;20]; + let mut q : [f64;20] = [0.;20]; + let mut iq : [i32;20] = [0;20]; + + /* initialize jk*/ + let jk = INIT_JK[prec]; + let jp = jk; + + /* determine jx,jv,q0, note that 3>q0 */ + let jx = nx-1; + let mut jv = (e0-3)/24; + if jv < 0 { + jv=0; + } + let mut q0 = e0-24*(jv+1); + let jv = jv as usize; + + /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ + let mut j = (jv-jx) as i32; + let m = jx+jk; + for i in 0..=m { + f[i] = if j<0 { + 0. + } else { + IPIO2[j as usize] as f64 + }; + j += 1 + } + + /* compute q[0],q[1],...q[jk] */ + for i in 0..=jk { + fw = 0f64; + for j in 0..=jx { + fw += x[j]*f[jx+i-j]; + } + q[i] = fw; + } + + let mut jz = jk; + + 'recompute: loop { + /* distill q[] into iq[] reversingly */ + let mut i = 0i32; + let mut z = q[jz]; + for j in (1..=jz).rev() { + fw = (x1p_24*z) as i32 as f64; + iq[i as usize] = (z - x1p24*fw) as i32; + z = q[j-1]+fw; + i += 1; + } + + /* compute n */ + z = scalbn(z, q0); /* actual value of z */ + z -= 8.0*(z*0.125).floor(); /* trim off integer >= 8 */ + n = z as i32; + z -= n as f64; + ih = 0; + if q0 > 0 { /* need iq[jz-1] to determine n */ + i = iq[jz-1] >> (24-q0); + n += i; + iq[jz-1] -= i << (24-q0); + ih = iq[jz-1] >> (23-q0); + } else if q0 == 0 { + ih = iq[jz-1]>>23; + } else if z >= 0.5 { + ih = 2; + } + + if ih > 0 { /* q > 0.5 */ + n += 1; + let mut carry = 0i32; + for i in 0..jz { /* compute 1-q */ + let j = iq[i]; + if carry == 0 { + if j != 0 { + carry = 1; + iq[i] = 0x1000000 - j; + } + } else { + iq[i] = 0xffffff - j; + } + } + if q0 > 0 { /* rare case: chance is 1 in 12 */ + match q0 { + 1 => { iq[jz-1] &= 0x7fffff; }, + 2 => { iq[jz-1] &= 0x3fffff; }, + _ => {} + } + } + if ih == 2 { + z = 1. - z; + if carry != 0 { + z -= scalbn(1., q0); + } + } + } + + /* check if recomputation is needed */ + if z == 0. { + let mut j = 0; + for i in (jk..=jz-1).rev() { + j |= iq[i]; + } + if j == 0 { /* need recomputation */ + let mut k = 1; + while iq[jk-k]==0 { + k += 1; /* k = no. of terms needed */ + } + + for i in (jz+1)..=(jz+k) { /* add q[jz+1] to q[jz+k] */ + f[jx+i] = IPIO2[jv+i] as f64; + fw = 0f64; + for j in 0..=jx { + fw += x[j]*f[jx+i-j]; + } + q[i] = fw; + } + jz += k; + continue 'recompute; + } + } + + break; + } + + /* chop off zero terms */ + if z == 0. { + jz -= 1; + q0 -= 24; + while iq[jz] == 0 { + jz -= 1; + q0 -= 24; + } + } else { /* break z into 24-bit if necessary */ + z = scalbn(z, -q0); + if z >= x1p24 { + fw = (x1p_24*z) as i32 as f64; + iq[jz] = (z - x1p24*fw) as i32; + jz += 1; + q0 += 24; + iq[jz] = fw as i32; + } else { + iq[jz] = z as i32; + } + } + + /* convert integer "bit" chunk to floating-point value */ + fw = scalbn(1., q0); + for i in (0..=jz).rev() { + q[i] = fw*(iq[i] as f64); + fw *= x1p_24; + } + + /* compute PIo2[0,...,jp]*q[jz,...,0] */ + for i in (0..=jz).rev() { + fw = 0f64; + let mut k = 0; + while (k <= jp) && (k <= jz-i) { + fw += PIO2[k]*q[i+k]; + k += 1; + } + fq[jz-i] = fw; + } + + /* compress fq[] into y[] */ + match prec { + 0 => { + fw = 0f64; + for i in (0..=jz).rev() { + fw += fq[i]; + } + y[0] = if ih == 0 { fw } else { -fw }; + }, + 1 | 2 => { + fw = 0f64; + for i in (0..=jz).rev() { + fw += fq[i]; + } + // TODO: drop excess precision here once double_t is used + fw = fw as f64; + y[0] = if ih == 0 { fw } else { -fw }; + fw = fq[0]-fw; + for i in 1..=jz { + fw += fq[i]; + } + y[1] = if ih == 0 { fw } else { -fw }; + }, + 3 => { /* painful */ + for i in (1..=jz).rev() { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for i in (2..=jz).rev() { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + fw = 0f64; + for i in (2..=jz).rev() { + fw += fq[i]; + } + if ih==0 { + y[0] = fq[0]; + y[1] = fq[1]; + y[2] = fw; + } else { + y[0] = -fq[0]; + y[1] = -fq[1]; + y[2] = -fw; + } + }, + _ => { unreachable!() } + } + n & 7 +} diff --git a/library/compiler-builtins/libm/src/math/service/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/service/rem_pio2f.rs new file mode 100644 index 0000000000000..a908ccd9f7516 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/service/rem_pio2f.rs @@ -0,0 +1,44 @@ +use super::rem_pio2_large; + +use core::f64; + +const TOINT : f64 = 1.5 / f64::EPSILON; + +/// 53 bits of 2/pi +const INV_PIO2 : f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ +/// first 25 bits of pi/2 +const PIO2_1 : f64 = 1.57079631090164184570e+00; /* 0x3FF921FB, 0x50000000 */ +/// pi/2 - pio2_1 +const PIO2_1T : f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ + +/// Return the remainder of x rem pi/2 in *y +/// +/// use double precision for everything except passing x +/// use __rem_pio2_large() for large x +#[inline] +pub(crate) fn rem_pio2f(x : f32) -> (i32, f64) { + let x64 = x as f64; + + let mut tx : [f64; 1] = [0.,]; + let mut ty : [f64; 1] = [0.,]; + + let ix = x.to_bits() & 0x7fffffff; + /* 25+53 bit pi is good enough for medium size */ + if ix < 0x4dc90fdb { /* |x| ~< 2^28*(pi/2), medium size */ + /* Use a specialized rint() to get fn. Assume round-to-nearest. */ + let f_n = x64*INV_PIO2 + TOINT - TOINT; + return (f_n as i32, x64 - f_n*PIO2_1 - f_n*PIO2_1T); + } + if ix>=0x7f800000 { /* x is inf or NaN */ + return (0, x64-x64); + } + /* scale x into [2^23, 2^24-1] */ + let sign = (x.to_bits() >> 31) != 0; + let e0 = ((ix>>23) - (0x7f+23)) as i32; /* e0 = ilogb(|x|)-23, positive */ + tx[0] = f32::from_bits(ix - (e0<<23) as u32) as f64; + let n = rem_pio2_large(&tx, &mut ty, e0, 0); + if sign { + return (-n, -ty[0]); + } + (n, ty[0]) +} diff --git a/library/compiler-builtins/libm/src/math/service/sindf.rs b/library/compiler-builtins/libm/src/math/service/sindf.rs new file mode 100644 index 0000000000000..a633545ba80c9 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/service/sindf.rs @@ -0,0 +1,14 @@ +/* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ +const S1 : f64 = -0.166666666416265235595; /* -0x15555554cbac77.0p-55 */ +const S2 : f64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ +const S3 : f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ +const S4 : f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ + +#[inline] +pub(crate) fn sindf(x : f64) -> f32 { + let z = x*x; + let w = z*z; + let r = S3 + z*S4; + let s = z*x; + ((x + s*(S1 + z*S2)) + s*w*r) as f32 +} From ac1b398b4db6d1bdc60d6da8e809487254d17a87 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 13 Jul 2018 15:31:57 -0400 Subject: [PATCH 0492/4206] seal extension traits to prevent external implementation --- library/compiler-builtins/libm/src/lib.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index fa709ad754a98..4deb2e21eee5f 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -32,9 +32,8 @@ pub fn _eq(a: u64, b: u64) -> bool { /// Math support for `f32` /// -/// NOTE this meant to be a closed extension trait. The only stable way to use this trait is to -/// import it to access its methods. -pub trait F32Ext { +/// This trait is sealed and cannot be implemented outside of `libm`. +pub trait F32Ext: private::Sealed { #[cfg(todo)] fn floor(self) -> Self; @@ -360,9 +359,8 @@ impl F32Ext for f32 { /// Math support for `f32` /// -/// NOTE this meant to be a closed extension trait. The only stable way to use this trait is to -/// import it to access its methods. -pub trait F64Ext { +/// This trait is sealed and cannot be implemented outside of `libm`. +pub trait F64Ext: private::Sealed { fn floor(self) -> Self; #[cfg(todo)] @@ -691,3 +689,10 @@ impl F64Ext for f64 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } } + +mod private { + pub trait Sealed {} + + impl Sealed for f32 {} + impl Sealed for f64 {} +} From d8cc25edd3c39a4c9c4add84e9657e7e656c1121 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 13 Jul 2018 23:58:41 +0300 Subject: [PATCH 0493/4206] cosf review --- .../libm/src/math/{service => }/cosdf.rs | 0 library/compiler-builtins/libm/src/math/cosf.rs | 2 +- library/compiler-builtins/libm/src/math/mod.rs | 14 ++++++++++++-- .../libm/src/math/{service => }/rem_pio2_large.rs | 8 ++++---- .../libm/src/math/{service => }/rem_pio2f.rs | 0 .../compiler-builtins/libm/src/math/service/mod.rs | 11 ----------- .../libm/src/math/{service => }/sindf.rs | 0 7 files changed, 17 insertions(+), 18 deletions(-) rename library/compiler-builtins/libm/src/math/{service => }/cosdf.rs (100%) rename library/compiler-builtins/libm/src/math/{service => }/rem_pio2_large.rs (99%) rename library/compiler-builtins/libm/src/math/{service => }/rem_pio2f.rs (100%) delete mode 100644 library/compiler-builtins/libm/src/math/service/mod.rs rename library/compiler-builtins/libm/src/math/{service => }/sindf.rs (100%) diff --git a/library/compiler-builtins/libm/src/math/service/cosdf.rs b/library/compiler-builtins/libm/src/math/cosdf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/service/cosdf.rs rename to library/compiler-builtins/libm/src/math/cosdf.rs diff --git a/library/compiler-builtins/libm/src/math/cosf.rs b/library/compiler-builtins/libm/src/math/cosf.rs index b1aefd5e32b7b..f63724e791eaf 100644 --- a/library/compiler-builtins/libm/src/math/cosf.rs +++ b/library/compiler-builtins/libm/src/math/cosf.rs @@ -1,4 +1,4 @@ -use super::service::{cosdf, sindf, rem_pio2f}; +use super::{cosdf, sindf, rem_pio2f}; use core::f64::consts::FRAC_PI_2; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index bc69aca0f61dd..b8de3c7333381 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -17,8 +17,6 @@ mod expf; mod floor; mod cosf; -mod service; - pub use self::{ fabs::fabs, fabsf::fabsf, @@ -34,6 +32,18 @@ pub use self::{ cosf::cosf, }; +mod sindf; +mod cosdf; +mod rem_pio2f; +mod rem_pio2_large; + +use self::{ + sindf::sindf, + cosdf::cosdf, + rem_pio2f::rem_pio2f, + rem_pio2_large::rem_pio2_large, +}; + fn isnanf(x: f32) -> bool { x.to_bits() & 0x7fffffff > 0x7f800000 } diff --git a/library/compiler-builtins/libm/src/math/service/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs similarity index 99% rename from library/compiler-builtins/libm/src/math/service/rem_pio2_large.rs rename to library/compiler-builtins/libm/src/math/rem_pio2_large.rs index 017fc88bae2ed..deb985f1d1cc3 100644 --- a/library/compiler-builtins/libm/src/math/service/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -1,5 +1,5 @@ -use ::scalbn; -use ::F64Ext; +use super::scalbn; +use super::floor; /// double x[],y[]; int e0,nx,prec; /// @@ -323,8 +323,8 @@ pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) } /* compute n */ - z = scalbn(z, q0); /* actual value of z */ - z -= 8.0*(z*0.125).floor(); /* trim off integer >= 8 */ + z = scalbn(z, q0); /* actual value of z */ + z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */ n = z as i32; z -= n as f64; ih = 0; diff --git a/library/compiler-builtins/libm/src/math/service/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/service/rem_pio2f.rs rename to library/compiler-builtins/libm/src/math/rem_pio2f.rs diff --git a/library/compiler-builtins/libm/src/math/service/mod.rs b/library/compiler-builtins/libm/src/math/service/mod.rs deleted file mode 100644 index 96bb09431bad7..0000000000000 --- a/library/compiler-builtins/libm/src/math/service/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -mod sindf; -mod cosdf; -mod rem_pio2f; -mod rem_pio2_large; - -pub(crate) use self::{ - cosdf::cosdf, - sindf::sindf, - rem_pio2f::rem_pio2f, - rem_pio2_large::rem_pio2_large, -}; diff --git a/library/compiler-builtins/libm/src/math/service/sindf.rs b/library/compiler-builtins/libm/src/math/sindf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/service/sindf.rs rename to library/compiler-builtins/libm/src/math/sindf.rs From 1ba1301250f58ada230ff0211c383e59eb884f6a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 13 Jul 2018 16:32:57 -0500 Subject: [PATCH 0494/4206] catch panics in tests so we can print the inputs that triggered the panic --- .../libm/test-generator/src/main.rs | 223 ++++++++++++------ 1 file changed, 157 insertions(+), 66 deletions(-) diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 6353b257dce3d..ca49179f187e8 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -62,6 +62,8 @@ macro_rules! f32_f32 { extern crate libm; + use std::panic; + #[test] fn {0}() {{ const CASES: &[(u32, u32)] = &[ @@ -71,16 +73,23 @@ macro_rules! f32_f32 { for case in CASES {{ let (inp, expected) = *case; - let outf = libm::{0}(f32::from_bits(inp)); - let outi = outf.to_bits(); - - if !((outf.is_nan() && f32::from_bits(expected).is_nan()) || - libm::_eqf(outi, expected)) {{ + if let Ok(outf) = + panic::catch_unwind(|| libm::{0}(f32::from_bits(inp))) + {{ + let outi = outf.to_bits(); + + if !((outf.is_nan() && f32::from_bits(expected).is_nan()) + || libm::_eqf(outi, expected)) + {{ + panic!( + \"input: {{}}, output: {{}}, expected: {{}}\", + inp, outi, expected, + ); + }} + }} else {{ panic!( - \"input: {{}}, output: {{}}, expected: {{}}\", - inp, - outi, - expected, + \"input: {{}}, output: PANIC, expected: {{}}\", + inp, expected, ); }} }} @@ -124,6 +133,8 @@ macro_rules! f32f32_f32 { extern crate libm; + use std::panic; + #[test] fn {0}() {{ const CASES: &[((u32, u32), u32)] = &[ @@ -133,15 +144,25 @@ macro_rules! f32f32_f32 { for case in CASES {{ let ((i1, i2), expected) = *case; - let outf = libm::{0}(f32::from_bits(i1), f32::from_bits(i2)); - let outi = outf.to_bits(); - - if !((outf.is_nan() && f32::from_bits(expected).is_nan()) || - libm::_eqf(outi, expected)) {{ + if let Ok(outf) = panic::catch_unwind(|| {{ + libm::{0}(f32::from_bits(i1), f32::from_bits(i2)) + }}) {{ + let outi = outf.to_bits(); + + if !((outf.is_nan() && f32::from_bits(expected).is_nan()) + || libm::_eqf(outi, expected)) + {{ + panic!( + \"input: {{:?}}, output: {{}}, expected: {{}}\", + (i1, i2), + outi, + expected, + ); + }} + }} else {{ panic!( - \"input: {{:?}}, output: {{}}, expected: {{}}\", + \"input: {{:?}}, output: PANIC, expected: {{}}\", (i1, i2), - outi, expected, ); }} @@ -188,6 +209,8 @@ macro_rules! f32f32f32_f32 { extern crate libm; + use std::panic; + #[test] fn {0}() {{ const CASES: &[((u32, u32, u32), u32)] = &[ @@ -197,19 +220,29 @@ macro_rules! f32f32f32_f32 { for case in CASES {{ let ((i1, i2, i3), expected) = *case; - let outf = libm::{0}( - f32::from_bits(i1), - f32::from_bits(i2), - f32::from_bits(i3), - ); - let outi = outf.to_bits(); - - if !((outf.is_nan() && f32::from_bits(expected).is_nan()) || - libm::_eqf(outi, expected)) {{ + if let Ok(outf) = panic::catch_unwind(|| {{ + libm::{0}( + f32::from_bits(i1), + f32::from_bits(i2), + f32::from_bits(i3), + ) + }}) {{ + let outi = outf.to_bits(); + + if !((outf.is_nan() && f32::from_bits(expected).is_nan()) + || libm::_eqf(outi, expected)) + {{ + panic!( + \"input: {{:?}}, output: {{}}, expected: {{}}\", + (i1, i2, i3), + outi, + expected, + ); + }} + }} else {{ panic!( - \"input: {{:?}}, output: {{}}, expected: {{}}\", + \"input: {{:?}}, output: PANIC, expected: {{}}\", (i1, i2, i3), - outi, expected, ); }} @@ -253,6 +286,8 @@ macro_rules! f32i32_f32 { extern crate libm; + use std::panic; + #[test] fn {0}() {{ const CASES: &[((u32, i16), u32)] = &[ @@ -262,15 +297,25 @@ macro_rules! f32i32_f32 { for case in CASES {{ let ((i1, i2), expected) = *case; - let outf = libm::{0}(f32::from_bits(i1), i2 as i32); - let outi = outf.to_bits(); - - if !((outf.is_nan() && f32::from_bits(expected).is_nan()) || - libm::_eqf(outi, expected)) {{ + if let Ok(outf) = panic::catch_unwind(|| {{ + libm::{0}(f32::from_bits(i1), i2 as i32) + }}) {{ + let outi = outf.to_bits(); + + if !((outf.is_nan() && f32::from_bits(expected).is_nan()) + || libm::_eqf(outi, expected)) + {{ + panic!( + \"input: {{:?}}, output: {{}}, expected: {{}}\", + (i1, i2), + outi, + expected, + ); + }} + }} else {{ panic!( - \"input: {{:?}}, output: {{}}, expected: {{}}\", + \"input: {{:?}}, output: PANIC, expected: {{}}\", (i1, i2), - outi, expected, ); }} @@ -314,6 +359,8 @@ macro_rules! f64_f64 { extern crate libm; + use std::panic; + #[test] fn {0}() {{ const CASES: &[(u64, u64)] = &[ @@ -323,15 +370,25 @@ macro_rules! f64_f64 { for case in CASES {{ let (inp, expected) = *case; - let outf = libm::{0}(f64::from_bits(inp)); - let outi = outf.to_bits(); - - if !((outf.is_nan() && f64::from_bits(expected).is_nan()) || - libm::_eq(outi, expected)) {{ + if let Ok(outf) = panic::catch_unwind(|| {{ + libm::{0}(f64::from_bits(inp)) + }}) {{ + let outi = outf.to_bits(); + + if !((outf.is_nan() && f64::from_bits(expected).is_nan()) + || libm::_eq(outi, expected)) + {{ + panic!( + \"input: {{}}, output: {{}}, expected: {{}}\", + inp, + outi, + expected, + ); + }} + }} else {{ panic!( - \"input: {{}}, output: {{}}, expected: {{}}\", + \"input: {{}}, output: PANIC, expected: {{}}\", inp, - outi, expected, ); }} @@ -376,6 +433,8 @@ macro_rules! f64f64_f64 { extern crate libm; + use std::panic; + #[test] fn {0}() {{ const CASES: &[((u64, u64), u64)] = &[ @@ -385,15 +444,24 @@ macro_rules! f64f64_f64 { for case in CASES {{ let ((i1, i2), expected) = *case; - let outf = libm::{0}(f64::from_bits(i1), f64::from_bits(i2)); - let outi = outf.to_bits(); - - if !((outf.is_nan() && f64::from_bits(expected).is_nan()) || - libm::_eq(outi, expected)) {{ + if let Ok(outf) = panic::catch_unwind(|| {{ + libm::{0}(f64::from_bits(i1), f64::from_bits(i2)) + }}) {{ + let outi = outf.to_bits(); + + if !((outf.is_nan() && f64::from_bits(expected).is_nan()) || + libm::_eq(outi, expected)) {{ + panic!( + \"input: {{:?}}, output: {{}}, expected: {{}}\", + (i1, i2), + outi, + expected, + ); + }} + }} else {{ panic!( - \"input: {{:?}}, output: {{}}, expected: {{}}\", + \"input: {{:?}}, output: PANIC, expected: {{}}\", (i1, i2), - outi, expected, ); }} @@ -440,6 +508,8 @@ macro_rules! f64f64f64_f64 { extern crate libm; + use std::panic; + #[test] fn {0}() {{ const CASES: &[((u64, u64, u64), u64)] = &[ @@ -449,19 +519,29 @@ macro_rules! f64f64f64_f64 { for case in CASES {{ let ((i1, i2, i3), expected) = *case; - let outf = libm::{0}( - f64::from_bits(i1), - f64::from_bits(i2), - f64::from_bits(i3), - ); - let outi = outf.to_bits(); - - if !((outf.is_nan() && f64::from_bits(expected).is_nan()) || - libm::_eq(outi, expected)) {{ + if let Ok(outf) = panic::catch_unwind(|| {{ + libm::{0}( + f64::from_bits(i1), + f64::from_bits(i2), + f64::from_bits(i3), + ) + }}) {{ + let outi = outf.to_bits(); + + if !((outf.is_nan() && f64::from_bits(expected).is_nan()) + || libm::_eq(outi, expected)) + {{ + panic!( + \"input: {{:?}}, output: {{}}, expected: {{}}\", + (i1, i2, i3), + outi, + expected, + ); + }} + }} else {{ panic!( - \"input: {{:?}}, output: {{}}, expected: {{}}\", + \"input: {{:?}}, output: PANIC, expected: {{}}\", (i1, i2, i3), - outi, expected, ); }} @@ -505,6 +585,8 @@ macro_rules! f64i32_f64 { extern crate libm; + use std::panic; + #[test] fn {0}() {{ const CASES: &[((u64, i16), u64)] = &[ @@ -514,15 +596,24 @@ macro_rules! f64i32_f64 { for case in CASES {{ let ((i1, i2), expected) = *case; - let outf = libm::{0}(f64::from_bits(i1), i2 as i32); - let outi = outf.to_bits(); - - if !((outf.is_nan() && f64::from_bits(expected).is_nan()) || - libm::_eq(outi, expected)) {{ + if let Ok(outf) = panic::catch_unwind(|| {{ + libm::{0}(f64::from_bits(i1), i2 as i32) + }}) {{ + let outi = outf.to_bits(); + + if !((outf.is_nan() && f64::from_bits(expected).is_nan()) || + libm::_eq(outi, expected)) {{ + panic!( + \"input: {{:?}}, output: {{}}, expected: {{}}\", + (i1, i2), + outi, + expected, + ); + }} + }} else {{ panic!( - \"input: {{:?}}, output: {{}}, expected: {{}}\", + \"input: {{:?}}, output: PANIC, expected: {{}}\", (i1, i2), - outi, expected, ); }} From 6dbd8b33035d2f40eb7f4def4f340081d4234ed5 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 13 Jul 2018 17:41:54 -0400 Subject: [PATCH 0495/4206] implement hypotf --- library/compiler-builtins/libm/src/lib.rs | 2 - .../compiler-builtins/libm/src/math/hypotf.rs | 43 +++++++++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 2 + .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/hypotf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index fa709ad754a98..a6702c4a72b79 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -88,7 +88,6 @@ pub trait F32Ext { #[cfg(todo)] fn cbrt(self) -> Self; - #[cfg(todo)] fn hypot(self, other: Self) -> Self; #[cfg(todo)] @@ -254,7 +253,6 @@ impl F32Ext for f32 { cbrtf(self) } - #[cfg(todo)] #[inline] fn hypot(self, other: Self) -> Self { hypotf(self, other) diff --git a/library/compiler-builtins/libm/src/math/hypotf.rs b/library/compiler-builtins/libm/src/math/hypotf.rs new file mode 100644 index 0000000000000..146aab4e44646 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/hypotf.rs @@ -0,0 +1,43 @@ +use core::f32; + +use super::sqrtf; + +#[inline] +pub fn hypotf(mut x: f32, mut y: f32) -> f32 { + let x1p90 = f32::from_bits(0x6c800000); // 0x1p90f === 2 ^ 90 + let x1p_90 = f32::from_bits(0x12800000); // 0x1p-90f === 2 ^ -90 + + let mut uxi = x.to_bits(); + let mut uyi = y.to_bits(); + let uti; + let mut z: f32; + + uxi &= -1i32 as u32 >> 1; + uyi &= -1i32 as u32 >> 1; + if uxi < uyi { + uti = uxi; + uxi = uyi; + uyi = uti; + } + + x = f32::from_bits(uxi); + y = f32::from_bits(uyi); + if uyi == 0xff<<23 { + return y; + } + if uxi >= 0xff<<23 || uyi == 0 || uxi - uyi >= 25<<23 { + return x + y; + } + + z = 1.; + if uxi >= (0x7f+60)<<23 { + z = x1p90; + x *= x1p_90; + y *= x1p_90; + } else if uyi < (0x7f-60)<<23 { + z = x1p_90; + x *= x1p90; + y *= x1p90; + } + z*sqrtf((x as f64 * x as f64 + y as f64 * y as f64) as f32) +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 71b58dda88323..a34ebd767e544 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -17,6 +17,7 @@ mod expf; mod floor; mod trunc; mod truncf; +mod hypotf; //mod service; @@ -34,6 +35,7 @@ pub use self::{ floor::floor, trunc::trunc, truncf::truncf, + hypotf::hypotf, }; fn isnanf(x: f32) -> bool { diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 6353b257dce3d..290952bbd1879 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -587,7 +587,7 @@ f32_f32! { // With signature `fn(f32, f32) -> f32` f32f32_f32! { // atan2f, - // hypotf, + hypotf, fmodf, powf, } From 52dba9843b4f9d2ec2da3f8509ed6c8e48e091e6 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sat, 14 Jul 2018 00:52:28 +0300 Subject: [PATCH 0496/4206] rem_pio2_large comments --- .../libm/src/math/rem_pio2_large.rs | 216 +++++++++--------- 1 file changed, 105 insertions(+), 111 deletions(-) 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 deb985f1d1cc3..809724df41943 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -1,117 +1,20 @@ use super::scalbn; use super::floor; -/// double x[],y[]; int e0,nx,prec; -/// -/// __rem_pio2_large return the last three digits of N with -/// y = x - N*pi/2 -/// so that |y| < pi/2. -/// -/// The method is to compute the integer (mod 8) and fraction parts of -/// (2/pi)*x without doing the full multiplication. In general we -/// skip the part of the product that are known to be a huge integer ( -/// more accurately, = 0 mod 8 ). Thus the number of operations are -/// independent of the exponent of the input. -/// -/// (2/pi) is represented by an array of 24-bit integers in ipio2[]. -/// -/// Input parameters: -/// x[] The input value (must be positive) is broken into nx -/// pieces of 24-bit integers in double precision format. -/// x[i] will be the i-th 24 bit of x. The scaled exponent -/// of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 -/// match x's up to 24 bits. -/// -/// Example of breaking a double positive z into x[0]+x[1]+x[2]: -/// e0 = ilogb(z)-23 -/// z = scalbn(z,-e0) -/// for i = 0,1,2 -/// x[i] = floor(z) -/// z = (z-x[i])*2**24 -/// -/// y[] ouput result in an array of double precision numbers. -/// The dimension of y[] is: -/// 24-bit precision 1 -/// 53-bit precision 2 -/// 64-bit precision 2 -/// 113-bit precision 3 -/// The actual value is the sum of them. Thus for 113-bit -/// precison, one may have to do something like: -/// -/// long double t,w,r_head, r_tail; -/// t = (long double)y[2] + (long double)y[1]; -/// w = (long double)y[0]; -/// r_head = t+w; -/// r_tail = w - (r_head - t); -/// -/// e0 The exponent of x[0]. Must be <= 16360 or you need to -/// expand the ipio2 table. -/// -/// prec an integer indicating the precision: -/// 0 24 bits (single) -/// 1 53 bits (double) -/// 2 64 bits (extended) -/// 3 113 bits (quad) -/// External function: -/// double scalbn(), floor(); -/// -/// -/// Here is the description of some local variables: -/// -/// jk jk+1 is the initial number of terms of ipio2[] needed -/// in the computation. The minimum and recommended value -/// for jk is 3,4,4,6 for single, double, extended, and quad. -/// jk+1 must be 2 larger than you might expect so that our -/// recomputation test works. (Up to 24 bits in the integer -/// part (the 24 bits of it that we compute) and 23 bits in -/// the fraction part may be lost to cancelation before we -/// recompute.) -/// -/// jz local integer variable indicating the number of -/// terms of ipio2[] used. -/// -/// jx nx - 1 -/// -/// jv index for pointing to the suitable ipio2[] for the -/// computation. In general, we want -/// ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 -/// is an integer. Thus -/// e0-3-24*jv >= 0 or (e0-3)/24 >= jv -/// Hence jv = max(0,(e0-3)/24). -/// -/// jp jp+1 is the number of terms in PIo2[] needed, jp = jk. -/// -/// q[] double array with integral value, representing the -/// 24-bits chunk of the product of x and 2/pi. -/// -/// q0 the corresponding exponent of q[0]. Note that the -/// exponent for q[i] would be q0-24*i. -/// -/// PIo2[] double precision array, obtained by cutting pi/2 -/// into 24 bits chunks. -/// -/// f[] ipio2[] in floating point -/// -/// iq[] integer array by breaking up q[] in 24-bits chunk. -/// -/// fq[] final product of x*(2/pi) in fq[0],..,fq[jk] -/// -/// ih integer. If >0 it indicates q[] is >= 0.5, hence -/// it also indicates the *sign* of the result. +// initial value for jk +const INIT_JK : [usize; 4] = [3,4,4,6]; -const INIT_JK : [usize; 4] = [3,4,4,6]; /* initial value for jk */ - -/// Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi -/// -/// integer array, contains the (24*i)-th to (24*i+23)-th -/// bit of 2/pi after binary point. The corresponding -/// floating value is -/// -/// ipio2[i] * 2^(-24(i+1)). -/// -/// NB: This table must have at least (e0-3)/24 + jk terms. -/// For quad precision (e0 <= 16360, jk = 6), this is 686. -#[cfg(not(ldbl_max_exp_more1024))] +// Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi +// +// integer array, contains the (24*i)-th to (24*i+23)-th +// bit of 2/pi after binary point. The corresponding +// floating value is +// +// ipio2[i] * 2^(-24(i+1)). +// +// NB: This table must have at least (e0-3)/24 + jk terms. +// For quad precision (e0 <= 16360, jk = 6), this is 686. +#[cfg(target_pointer_width = "32")] const IPIO2 : [i32; 66] = [ 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, @@ -126,7 +29,7 @@ const IPIO2 : [i32; 66] = [ 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, ]; -#[cfg(ldbl_max_exp_more1024)] +#[cfg(target_pointer_width = "64")] const IPIO2 : [i32; 690] = [ 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, @@ -256,6 +159,97 @@ const PIO2 : [f64; 8] = [ 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ ]; +// fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) -> i32 +// +// Input parameters: +// x[] The input value (must be positive) is broken into nx +// pieces of 24-bit integers in double precision format. +// x[i] will be the i-th 24 bit of x. The scaled exponent +// of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 +// match x's up to 24 bits. +// +// Example of breaking a double positive z into x[0]+x[1]+x[2]: +// e0 = ilogb(z)-23 +// z = scalbn(z,-e0) +// for i = 0,1,2 +// x[i] = floor(z) +// z = (z-x[i])*2**24 +// +// y[] ouput result in an array of double precision numbers. +// The dimension of y[] is: +// 24-bit precision 1 +// 53-bit precision 2 +// 64-bit precision 2 +// 113-bit precision 3 +// The actual value is the sum of them. Thus for 113-bit +// precison, one may have to do something like: +// +// long double t,w,r_head, r_tail; +// t = (long double)y[2] + (long double)y[1]; +// w = (long double)y[0]; +// r_head = t+w; +// r_tail = w - (r_head - t); +// +// e0 The exponent of x[0]. Must be <= 16360 or you need to +// expand the ipio2 table. +// +// prec an integer indicating the precision: +// 0 24 bits (single) +// 1 53 bits (double) +// 2 64 bits (extended) +// 3 113 bits (quad) +// +// Here is the description of some local variables: +// +// jk jk+1 is the initial number of terms of ipio2[] needed +// in the computation. The minimum and recommended value +// for jk is 3,4,4,6 for single, double, extended, and quad. +// jk+1 must be 2 larger than you might expect so that our +// recomputation test works. (Up to 24 bits in the integer +// part (the 24 bits of it that we compute) and 23 bits in +// the fraction part may be lost to cancelation before we +// recompute.) +// +// jz local integer variable indicating the number of +// terms of ipio2[] used. +// +// jx nx - 1 +// +// jv index for pointing to the suitable ipio2[] for the +// computation. In general, we want +// ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 +// is an integer. Thus +// e0-3-24*jv >= 0 or (e0-3)/24 >= jv +// Hence jv = max(0,(e0-3)/24). +// +// jp jp+1 is the number of terms in PIo2[] needed, jp = jk. +// +// q[] double array with integral value, representing the +// 24-bits chunk of the product of x and 2/pi. +// +// q0 the corresponding exponent of q[0]. Note that the +// exponent for q[i] would be q0-24*i. +// +// PIo2[] double precision array, obtained by cutting pi/2 +// into 24 bits chunks. +// +// f[] ipio2[] in floating point +// +// iq[] integer array by breaking up q[] in 24-bits chunk. +// +// fq[] final product of x*(2/pi) in fq[0],..,fq[jk] +// +// ih integer. If >0 it indicates q[] is >= 0.5, hence +// it also indicates the *sign* of the result. + +/// Return the last three digits of N with y = x - N*pi/2 +/// so that |y| < pi/2. +/// +/// The method is to compute the integer (mod 8) and fraction parts of +/// (2/pi)*x without doing the full multiplication. In general we +/// skip the part of the product that are known to be a huge integer ( +/// more accurately, = 0 mod 8 ). Thus the number of operations are +/// independent of the exponent of the input. #[inline] pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) -> i32 { let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 From a372fff7facd658e395ce833ff5de8ac3603a698 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sat, 14 Jul 2018 00:58:02 +0300 Subject: [PATCH 0497/4206] cfg fix --- library/compiler-builtins/libm/src/math/rem_pio2_large.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 809724df41943..18dc721c65188 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -255,7 +255,7 @@ pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) - #[cfg(not(ldbl_max_exp_more1024))] + #[cfg(target_pointer_width = "64")] assert!(e0 <= 16360); let nx = x.len(); From 892cd4f5b83761f2abf96e27c109ad3a6d87bceb Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 13 Jul 2018 18:31:01 -0400 Subject: [PATCH 0498/4206] implement sqrt and hypot --- library/compiler-builtins/libm/src/lib.rs | 4 - .../compiler-builtins/libm/src/math/hypot.rs | 74 ++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 4 + .../compiler-builtins/libm/src/math/sqrt.rs | 129 ++++++++++++++++++ .../libm/test-generator/src/main.rs | 4 +- 5 files changed, 209 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/hypot.rs create mode 100644 library/compiler-builtins/libm/src/math/sqrt.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 0fb555a7b499d..3e25c16db29d9 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -391,7 +391,6 @@ pub trait F64Ext: private::Sealed { #[cfg(todo)] fn powf(self, n: Self) -> Self; - #[cfg(todo)] fn sqrt(self) -> Self; #[cfg(todo)] @@ -415,7 +414,6 @@ pub trait F64Ext: private::Sealed { #[cfg(todo)] fn cbrt(self) -> Self; - #[cfg(todo)] fn hypot(self, other: Self) -> Self; #[cfg(todo)] @@ -536,7 +534,6 @@ impl F64Ext for f64 { pow(self, n) } - #[cfg(todo)] #[inline] fn sqrt(self) -> Self { sqrt(self) @@ -584,7 +581,6 @@ impl F64Ext for f64 { cbrt(self) } - #[cfg(todo)] #[inline] fn hypot(self, other: Self) -> Self { hypot(self, other) 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..dcc17d914fb91 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/hypot.rs @@ -0,0 +1,74 @@ +use core::f64; + +use super::sqrt; + +const SPLIT: f64 = 134217728. + 1.; // 0x1p27 + 1 === (2 ^ 27) + 1 + +fn sq(x: f64) -> (f64, f64) { + let xh: f64; + let xl: f64; + let xc: f64; + + xc = x * SPLIT; + xh = x - xc + xc; + xl = x - xh; + let hi = x*x; + let lo = xh*xh - hi + 2.*xh*xl + xl*xl; + (hi, lo) +} + +#[inline] +pub fn hypot(mut x: f64, mut y: f64) -> f64 { + let x1p700 = f64::from_bits(0x6bb0000000000000); // 0x1p700 === 2 ^ 700 + let x1p_700 = f64::from_bits(0x1430000000000000); // 0x1p-700 === 2 ^ -700 + + let mut uxi = x.to_bits(); + let mut uyi = y.to_bits(); + let uti; + let ex: i64; + let ey: i64; + let mut z: f64; + + /* arrange |x| >= |y| */ + uxi &= -1i64 as u64 >> 1; + uyi &= -1i64 as u64 >> 1; + if uxi < uyi { + uti = uxi; + uxi = uyi; + uyi = uti; + } + + /* special cases */ + ex = (uxi>>52) as i64; + ey = (uyi>>52) as i64; + x = f64::from_bits(uxi); + y = f64::from_bits(uyi); + /* note: hypot(inf,nan) == inf */ + if ey == 0x7ff { + return y; + } + if ex == 0x7ff || uyi == 0 { + return x; + } + /* note: hypot(x,y) ~= x + y*y/x/2 with inexact for small y/x */ + /* 64 difference is enough for ld80 double_t */ + if ex - ey > 64 { + return x + y; + } + + /* precise sqrt argument in nearest rounding mode without overflow */ + /* xh*xh must not overflow and xl*xl must not underflow in sq */ + z = 1.; + if ex > 0x3ff+510 { + z = x1p700; + x *= x1p_700; + y *= x1p_700; + } else if ey < 0x3ff-450 { + z = x1p_700; + x *= x1p700; + y *= x1p700; + } + let (hx, lx) = sq(x); + let (hy, ly) = sq(y); + return z*sqrt(ly+lx+hy+hx); +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index a34ebd767e544..444652e81eff7 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -11,12 +11,14 @@ mod powf; mod round; mod scalbn; mod scalbnf; +mod sqrt; mod sqrtf; mod logf; mod expf; mod floor; mod trunc; mod truncf; +mod hypot; mod hypotf; //mod service; @@ -29,12 +31,14 @@ pub use self::{ round::round, scalbn::scalbn, scalbnf::scalbnf, + sqrt::sqrt, sqrtf::sqrtf, logf::logf, expf::expf, floor::floor, trunc::trunc, truncf::truncf, + hypot::hypot, hypotf::hypotf, }; diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs new file mode 100644 index 0000000000000..49fc58fff03ca --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -0,0 +1,129 @@ +use core::f64; + +const TINY: f64 = 1.0e-300; + +#[inline] +pub fn sqrt(x: f64) -> f64 { + let mut z: f64; + let sign: u32 = 0x80000000; + let mut ix0: i32; + let mut s0: i32; + let mut q: i32; + let mut m: i32; + let mut t: i32; + let mut i: i32; + let mut r: u32; + let mut t1: u32; + let mut s1: u32; + let mut ix1: u32; + let mut q1: u32; + + ix0 = (x.to_bits() >> 32) as i32; + ix1 = x.to_bits() as u32; + + /* take care of Inf and NaN */ + if (ix0&0x7ff00000) == 0x7ff00000 { + return x*x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + } + /* take care of zero */ + if ix0 <= 0 { + if ((ix0&!(sign as i32))|ix1 as i32) == 0 { + return x; /* sqrt(+-0) = +-0 */ + } + if ix0 < 0 { + return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ + } + } + /* normalize x */ + m = ix0>>20; + if m == 0 { /* subnormal x */ + while ix0 == 0 { + m -= 21; + ix0 |= (ix1>>11) as i32; + ix1 <<= 21; + } + i=0; + while (ix0&0x00100000) == 0 { + i += 1; + ix0 <<= 1; + } + m -= i - 1; + ix0 |= (ix1>>(32-i)) as i32; + ix1 <<= i; + } + m -= 1023; /* unbias exponent */ + ix0 = (ix0&0x000fffff)|0x00100000; + if (m & 1) == 1 { /* odd m, double x to make it even */ + ix0 += ix0 + ((ix1&sign)>>31) as i32; + ix1 += ix1; + } + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix0 += ix0 + ((ix1&sign)>>31) as i32; + ix1 += ix1; + q = 0; /* [q,q1] = sqrt(x) */ + q1 = 0; + s0 = 0; + s1 = 0; + r = 0x00200000; /* r = moving bit from right to left */ + + while r != 0 { + t = s0 + r as i32; + if t <= ix0 { + s0 = t + r as i32; + ix0 -= t; + q += r as i32; + } + ix0 += ix0 + ((ix1&sign)>>31) as i32; + ix1 += ix1; + r >>= 1; + } + + r = sign; + while r != 0 { + t1 = s1 + r; + t = s0; + if t < ix0 || (t == ix0 && t1 <= ix1) { + s1 = t1 + r; + if (t1&sign) == sign && (s1&sign) == 0 { + s0 += 1; + } + ix0 -= t; + if ix1 < t1 { + ix0 -= 1; + } + ix1 -= t1; + q1 += r; + } + ix0 += ix0 + ((ix1&sign)>>31) as i32; + ix1 += ix1; + r >>= 1; + } + + /* use floating add to find out rounding direction */ + if (ix0 as u32|ix1) != 0 { + z = 1.0 - TINY; /* raise inexact flag */ + if z >= 1.0 { + z = 1.0 + TINY; + if q1 == 0xffffffff { + q1 = 0; + q+=1; + } else if z > 1.0 { + if q1 == 0xfffffffe { + q += 1; + } + q1 += 2; + } else { + q1 += q1 & 1; + } + } + } + ix0 = (q>>1) + 0x3fe00000; + ix1 = q1>>1; + if (q&1) == 1 { + ix1 |= sign; + } + ix0 += m << 20; + f64::from_bits((ix0 as u64) << 32 | ix1 as u64) +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 8da1a920eef2d..ce20e80d19527 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -713,7 +713,7 @@ f64_f64! { round, // sin, // sinh, - // sqrt, + sqrt, // tan, // tanh, trunc, @@ -725,7 +725,7 @@ f64f64_f64! { // atan2, // fdim, // fmod, - // hypot, + hypot, // pow, } From aaa56fba356a4961baf98ccb8d8ff85c589ea19c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 13 Jul 2018 17:52:58 -0500 Subject: [PATCH 0499/4206] move a chunk of the README into CONTRIBUTING.md --- .../compiler-builtins/libm/CONTRIBUTING.md | 87 +++++++++++++++++++ library/compiler-builtins/libm/README.md | 52 +---------- library/compiler-builtins/libm/src/lib.rs | 2 +- .../compiler-builtins/libm/src/math/trunc.rs | 8 ++ .../compiler-builtins/libm/src/math/truncf.rs | 8 ++ 5 files changed, 105 insertions(+), 52 deletions(-) create mode 100644 library/compiler-builtins/libm/CONTRIBUTING.md diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md new file mode 100644 index 0000000000000..1f0a05a3f8d95 --- /dev/null +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -0,0 +1,87 @@ +# How to contribute + +- Pick your favorite math function from the [issue tracker]. +- Look for the C implementation of the function in the [MUSL source code][src]. +- Copy paste the C code into a Rust file in the `src/math` directory and adjust `src/math/mod.rs` + accordingly. Also, uncomment the corresponding trait method in `src/lib.rs`. +- Run `cargo watch check` and fix the compiler errors. +- Tweak the bottom of `test-generator/src/main.rs` to add your function to the test suite. +- If you can, run the full test suite locally (see the [testing](#testing) section below). If you + can't, no problem! Your PR will be fully tested automatically. Though you may still want to add + and run some unit tests. See the bottom of [`src/math/truncf.rs`] for an example of such tests; + you can run unit tests with the `cargo test --lib` command. +- Send us a pull request! +- :tada: + +[issue tracker]: https://github.com/japaric/libm/issues +[src]: https://git.musl-libc.org/cgit/musl/tree/src/math +[`src/math/truncf.rs`]: https://github.com/japaric/libm/blob/master/src/math/truncf.rs + +Check [PR #65] for an example. + +[PR #65]: https://github.com/japaric/libm/pull/65 + +## Tips and tricks + +- *IMPORTANT* The code in this crate will end up being used in the `core` crate so it can **not** + have any external dependencies (other than `core` itself). + +- Only use relative imports within the `math` directory / module, e.g. `use self::fabs::fabs` or +`use super::isnanf`. Absolute imports from core are OK, e.g. `use core::u64`. + +- To reinterpret a float as an integer use the `to_bits` method. The MUSL code uses the + `GET_FLOAT_WORD` macro, or a union, to do this operation. + +- To reinterpret an integer as a float use the `f32::from_bits` constructor. The MUSL code uses the + `SET_FLOAT_WORD` macro, or a union, to do this operation. + +- You may encounter weird literals like `0x1p127f` in the MUSL code. These are hexadecimal floating + point literals. Rust (the language) doesn't support these kind of literals. The best way I have + found to deal with these literals is to turn them into their integer representation using the + [`hexf!`] macro and then turn them back into floats. See below: + +[`hexf!`]: https://crates.io/crates/hexf + +``` rust +// Step 1: write a program to convert the float into its integer representation +#[macro_use] +extern crate hexf; + +fn main() { + println!("{:#x}", hexf32!("0x1.0p127").to_bits()); +} +``` + +``` console +$ # Step 2: run the program +$ cargo run +0x7f000000 +``` + +``` rust +// Step 3: copy paste the output into libm +let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 12 +``` + +- Rust code panics on arithmetic overflows when not optimized. You may need to use the [`Wrapping`] + newtype to avoid this problem. + +[`Wrapping`]: https://doc.rust-lang.org/std/num/struct.Wrapping.html + +## Testing + +The test suite of this crate can only be run on x86_64 Linux systems using the following commands: + +``` console +$ # The test suite depends on the `cross` tool so install it if you don't have it +$ cargo install cross + +$ # and the `cross` tool requires docker to be running +$ systemctl start docker + +$ # execute the test suite for the x86_64 target +$ TARGET=x86_64-unknown-linux-gnu bash ci/script.sh + +$ # execute the test suite for the ARMv7 target +$ TARGET=armv7-unknown-linux-gnueabihf bash ci/script.sh +``` diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index cb29baf63a7b1..ce731a203d605 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -9,59 +9,9 @@ A port of [MUSL]'s libm to Rust. The short term goal of this library is to enable math support (e.g. `sin`, `atan2`) for the `wasm32-unknown-unknown` target. The longer term goal is to enable math support in the `core` crate. -## Testing - -The test suite of this crate can only be run on x86_64 Linux systems. - -``` -$ # The test suite depends on the `cross` tool so install it if you don't have it -$ cargo install cross - -$ # and the `cross` tool requires docker to be running -$ systemctl start docker - -$ # execute the test suite for the x86_64 target -$ TARGET=x86_64-unknown-linux-gnu bash ci/script.sh - -$ # execute the test suite for the ARMv7 target -$ TARGET=armv7-unknown-linux-gnueabihf bash ci/script.sh -``` - ## Contributing -- Pick your favorite math function from the [issue tracker]. -- Look for the C implementation of the function in the [MUSL source code][src]. -- Copy paste the C code into a Rust file in the `src/math` directory and adjust `src/math/mod.rs` - accordingly. Also, uncomment the corresponding trait method in `src/lib.rs`. -- Run `cargo watch check` and fix the compiler errors. -- Tweak the bottom of `test-generator/src/main.rs` to add your function to the test suite. -- If you can, run the test suite locally. If you can't, no problem! Your PR will be tested - automatically. -- Send us a pull request! -- :tada: - -[issue tracker]: https://github.com/japaric/libm/issues -[src]: https://git.musl-libc.org/cgit/musl/tree/src/math - -Check [PR #2] for an example. - -[PR #2]: https://github.com/japaric/libm/pull/2 - -### Notes - -- Only use relative imports within the `math` directory / module, e.g. `use self::fabs::fabs` or -`use super::isnanf`. Absolute imports from core are OK, e.g. `use core::u64`. - -- To reinterpret a float as an integer use the `to_bits` method. The MUSL code uses the - `GET_FLOAT_WORD` macro, or a union, to do this operation. - -- To reinterpret an integer as a float use the `f32::from_bits` constructor. The MUSL code uses the - `SET_FLOAT_WORD` macro, or a union, to do this operation. - -- Rust code panics on arithmetic overflows when not optimized. You may need to use the [`Wrapping`] - newtype to avoid this problem. - -[`Wrapping`]: https://doc.rust-lang.org/std/num/struct.Wrapping.html +Please check [CONTRIBUTING.md](CONTRIBUTING.md) ## License diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 0fb555a7b499d..32735f7ed6ba3 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -355,7 +355,7 @@ impl F32Ext for f32 { } } -/// Math support for `f32` +/// Math support for `f64` /// /// This trait is sealed and cannot be implemented outside of `libm`. pub trait F64Ext: private::Sealed { diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs index b50ffd77156a2..6bea67cbc1654 100644 --- a/library/compiler-builtins/libm/src/math/trunc.rs +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -22,3 +22,11 @@ pub fn trunc(x: f64) -> f64 { i &= !m; f64::from_bits(i) } + +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::trunc(1.1), 1.0); + } +} diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs index f7d7249e3519b..9d42620d96663 100644 --- a/library/compiler-builtins/libm/src/math/truncf.rs +++ b/library/compiler-builtins/libm/src/math/truncf.rs @@ -22,3 +22,11 @@ pub fn truncf(x: f32) -> f32 { i &= !m; f32::from_bits(i) } + +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::truncf(1.1), 1.0); + } +} From e6576930ef34b5617c0c46faa0937922fed9095d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 13 Jul 2018 19:38:51 -0500 Subject: [PATCH 0500/4206] v0.1.0 --- library/compiler-builtins/libm/CHANGELOG.md | 12 ++++++++++++ library/compiler-builtins/libm/Cargo.toml | 8 +++++++- library/compiler-builtins/libm/README.md | 9 +++++++-- 3 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/CHANGELOG.md diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md new file mode 100644 index 0000000000000..c3e74a8143381 --- /dev/null +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -0,0 +1,12 @@ +# Change Log + +All notable changes to this project will be documented in this file. +This project adheres to [Semantic Versioning](http://semver.org/). + +## [Unreleased] + +## v0.1.0 - 2018-07-13 + +- Initial release + +[Unreleased]: https://github.com/japaric/libm/compare/v0.1.0...HEAD diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index e3498eed03819..5a1ae4a6c92b4 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -1,7 +1,13 @@ [package] +authors = ["Jorge Aparicio "] +categories = ["no-std"] +description = "libm in pure Rust" +documentation = "https://docs.rs/libm" +keywords = ["libm", "math"] +license = "MIT OR Apache-2.0" name = "libm" +repository = "https://github.com/japaric/libm" version = "0.1.0" -authors = ["Jorge Aparicio "] [workspace] members = ["cb", "test-generator"] \ No newline at end of file diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index ce731a203d605..6d8f9c49cc3c2 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -6,8 +6,13 @@ A port of [MUSL]'s libm to Rust. ## Goals -The short term goal of this library is to enable math support (e.g. `sin`, `atan2`) for the -`wasm32-unknown-unknown` target. The longer term goal is to enable math support in the `core` crate. +The short term goal of this library is to [enable math support (e.g. `sin`, `atan2`) for the +`wasm32-unknown-unknown` target][wasm] (cf. [rust-lang-nursery/compiler-builtins][pr]). The longer +term goal is to enable [math support in the `core` crate][core]. + +[wasm]: https://github.com/japaric/libm/milestone/1 +[pr]: https://github.com/rust-lang-nursery/compiler-builtins/pull/248 +[core]: https://github.com/japaric/libm/milestone/2 ## Contributing From 9a9522cf4795a9aaf49458a914c964f98733a8b2 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 13 Jul 2018 20:25:27 -0500 Subject: [PATCH 0501/4206] README: note that this crate is on crates.io and already usable --- library/compiler-builtins/libm/README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 6d8f9c49cc3c2..02de9765a50b2 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -14,6 +14,30 @@ term goal is to enable [math support in the `core` crate][core]. [pr]: https://github.com/rust-lang-nursery/compiler-builtins/pull/248 [core]: https://github.com/japaric/libm/milestone/2 +## Already usable + +This crate is [on crates.io] and can be used today in stable `#![no_std]` programs like this: + +[on crates.io]: https://crates.io/crates/libm + +``` rust +#![no_std] + +extern crate libm; + +use libm::F32Ext; // adds methods to `f32` + +fn foo(x: f32) { + let y = x.sqrt(); + let z = libm::truncf(x); +} +``` + +Not all the math functions are available at the moment. Check the [API docs] to learn what's +currently supported. + +[API docs]: https://docs.rs/libm + ## Contributing Please check [CONTRIBUTING.md](CONTRIBUTING.md) From bc94c70687c467d7fa4c655b90033de99d27211c Mon Sep 17 00:00:00 2001 From: Joseph Ryan Date: Fri, 13 Jul 2018 20:46:09 -0500 Subject: [PATCH 0502/4206] implement roundf --- library/compiler-builtins/libm/src/lib.rs | 2 -- .../compiler-builtins/libm/src/math/mod.rs | 8 +++-- .../compiler-builtins/libm/src/math/roundf.rs | 33 +++++++++++++++++++ .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/roundf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 0d13590c7ecca..b87e82b2ac6a7 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -41,7 +41,6 @@ pub trait F32Ext { #[cfg(todo)] fn ceil(self) -> Self; - #[cfg(todo)] fn round(self) -> Self; #[cfg(todo)] @@ -160,7 +159,6 @@ impl F32Ext for f32 { ceilf(self) } - #[cfg(todo)] #[inline] fn round(self) -> Self { roundf(self) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 41359bf8c059a..8032bdabf9ac2 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -1,7 +1,9 @@ macro_rules! force_eval { ($e:expr) => { - unsafe { ::core::ptr::read_volatile(&$e); } - } + unsafe { + ::core::ptr::read_volatile(&$e); + } + }; } mod fabs; @@ -9,6 +11,7 @@ mod fabsf; mod fmodf; mod powf; mod round; +mod roundf; mod scalbnf; mod sqrtf; @@ -17,6 +20,7 @@ pub use self::fabsf::fabsf; pub use self::fmodf::fmodf; pub use self::powf::powf; pub use self::round::round; +pub use self::roundf::roundf; pub use self::scalbnf::scalbnf; pub use self::sqrtf::sqrtf; diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs new file mode 100644 index 0000000000000..bd2488fa99c8e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/roundf.rs @@ -0,0 +1,33 @@ +use core::f32; + +const TOINT: f32 = 1.0 / f32::EPSILON; + +pub fn roundf(mut x: f32) -> f32 { + let i = x.to_bits(); + let e: u32 = i >> 23 & 0xff; + let mut y: f32; + + if e >= 0x7f + 23 { + return x; + } + if i >> 31 != 0 { + x = -x; + } + if e < 0x7f - 1 { + force_eval!(x + TOINT); + return 0.0 * x; + } + y = x + TOINT - TOINT - x; + if y > 0.5f32 { + y = y + x - 1.0; + } else if y <= -0.5f32 { + y = y + x + 1.0; + } else { + y = y + x; + } + if i >> 31 != 0 { + -y + } else { + y + } +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 5ff78ffc8b37d..2f78a8ed38da3 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -574,7 +574,7 @@ f32_f32! { // fdimf, // log10f, // log2f, - // roundf, + roundf, // sinf, // sinhf, // tanf, From f40b8096aa272135bb3d869e9b1a29535d674b40 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sat, 14 Jul 2018 05:20:09 +0300 Subject: [PATCH 0503/4206] add cosf test --- library/compiler-builtins/libm/test-generator/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 6353b257dce3d..40eac207c1535 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -567,7 +567,7 @@ f32_f32! { // atanf, // cbrtf, // ceilf, - // cosf, + cosf, // coshf, // exp2f, expf, From 6237ba289068254c34fca5ad014a1cf8ba9ccbee Mon Sep 17 00:00:00 2001 From: Jack Mott Date: Fri, 13 Jul 2018 21:32:59 -0500 Subject: [PATCH 0504/4206] adding ceilf and floorf for issues rust-lang/libm#56 and rust-lang/libm#54 --- library/compiler-builtins/libm/src/lib.rs | 4 --- .../compiler-builtins/libm/src/math/ceilf.rs | 29 ++++++++++++++++++ .../compiler-builtins/libm/src/math/floorf.rs | 30 +++++++++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 4 +++ .../libm/test-generator/src/main.rs | 4 +-- 5 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/ceilf.rs create mode 100644 library/compiler-builtins/libm/src/math/floorf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 13e038bfc3be7..783cc9e1818b1 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -34,10 +34,8 @@ pub fn _eq(a: u64, b: u64) -> bool { /// /// This trait is sealed and cannot be implemented outside of `libm`. pub trait F32Ext: private::Sealed { - #[cfg(todo)] fn floor(self) -> Self; - #[cfg(todo)] fn ceil(self) -> Self; #[cfg(todo)] @@ -142,13 +140,11 @@ pub trait F32Ext: private::Sealed { } impl F32Ext for f32 { - #[cfg(todo)] #[inline] fn floor(self) -> Self { floorf(self) } - #[cfg(todo)] #[inline] fn ceil(self) -> Self { ceilf(self) diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs new file mode 100644 index 0000000000000..b4f58bfb86f34 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -0,0 +1,29 @@ +use core::f32; + +pub fn ceilf(x: f32) -> f32 { + let mut ui = x.to_bits(); + let e = (((ui >> 23) & 0xff) - 0x7f) as i32; + + if e >= 23 { + return x; + } + if e >= 0 { + let m = 0x007fffff >> e; + if (ui & m) == 0 { + return x; + } + force_eval!(x + f32::from_bits(0x7b800000)); + if ui >> 31 == 0 { + ui += m; + } + ui &= !m; + } else { + force_eval!(x + f32::from_bits(0x7b800000)); + if ui >> 31 != 0 { + return -0.0; + } else if ui << 1 != 0 { + return 1.0; + } + } + return f32::from_bits(ui); +} diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs new file mode 100644 index 0000000000000..9c263b51828bf --- /dev/null +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -0,0 +1,30 @@ +use core::f32; + +#[inline] +pub fn floorf(x: f32) -> f32 { + let mut ui = x.to_bits(); + let e = (((ui >> 23) & 0xff) - 0x7f) as i32; + + if e >= 23 { + return x; + } + if e >= 0 { + let m: u32 = 0x007fffff >> e; + if (ui & m) == 0 { + return x; + } + force_eval!(x + f32::from_bits(0x7b800000)); + if ui >> 31 != 0 { + ui += m; + } + ui &= !m; + } else { + force_eval!(x + f32::from_bits(0x7b800000)); + if ui >> 31 == 0 { + ui = 0; + } else if ui << 1 != 0 { + return -1.0; + } + } + return f32::from_bits(ui); +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 444652e81eff7..2ddaa27283549 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -4,8 +4,10 @@ macro_rules! force_eval { } } +mod ceilf; mod fabs; mod fabsf; +mod floorf; mod fmodf; mod powf; mod round; @@ -24,8 +26,10 @@ mod hypotf; //mod service; pub use self::{ + ceilf::ceilf, fabs::fabs, fabsf::fabsf, + floorf::floorf, fmodf::fmodf, powf::powf, round::round, diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index ce20e80d19527..1d6168e4bc2af 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -652,12 +652,12 @@ fn main() -> Result<(), Box> { // With signature `fn(f32) -> f32` f32_f32! { // acosf, - // floorf, + floorf, truncf, // asinf, // atanf, // cbrtf, - // ceilf, + ceilf, // cosf, // coshf, // exp2f, From 8bdbe460728b1de630b96a3164bb448b5083a007 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 13 Jul 2018 21:51:07 -0500 Subject: [PATCH 0505/4206] run cargo-fmt --- .../compiler-builtins/libm/src/math/expf.rs | 73 ++++++++++--------- .../compiler-builtins/libm/src/math/floor.rs | 32 ++++---- .../compiler-builtins/libm/src/math/hypot.rs | 14 ++-- .../compiler-builtins/libm/src/math/hypotf.rs | 10 +-- .../compiler-builtins/libm/src/math/logf.rs | 45 ++++++------ .../compiler-builtins/libm/src/math/mod.rs | 32 ++------ .../compiler-builtins/libm/src/math/round.rs | 2 +- .../compiler-builtins/libm/src/math/scalbn.rs | 12 +-- .../libm/src/math/scalbnf.rs | 12 +-- .../compiler-builtins/libm/src/math/sqrt.rs | 60 +++++++-------- 10 files changed, 143 insertions(+), 149 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs index 1b645654e3695..cffb557719f09 100644 --- a/library/compiler-builtins/libm/src/math/expf.rs +++ b/library/compiler-builtins/libm/src/math/expf.rs @@ -1,60 +1,67 @@ use super::scalbnf; -const HALF : [f32; 2] = [0.5,-0.5]; -const LN2_HI : f32 = 6.9314575195e-01; /* 0x3f317200 */ -const LN2_LO : f32 = 1.4286067653e-06; /* 0x35bfbe8e */ -const INV_LN2 : f32 = 1.4426950216e+00; /* 0x3fb8aa3b */ +const HALF: [f32; 2] = [0.5, -0.5]; +const LN2_HI: f32 = 6.9314575195e-01; /* 0x3f317200 */ +const LN2_LO: f32 = 1.4286067653e-06; /* 0x35bfbe8e */ +const INV_LN2: f32 = 1.4426950216e+00; /* 0x3fb8aa3b */ /* * Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]: * |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74 */ -const P1 : f32 = 1.6666625440e-1; /* 0xaaaa8f.0p-26 */ -const P2 : f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ +const P1: f32 = 1.6666625440e-1; /* 0xaaaa8f.0p-26 */ +const P2: f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ #[inline] pub fn expf(mut x: f32) -> f32 { - let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 - let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */ - + let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 + let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */ + let mut hx = x.to_bits(); - let sign = (hx >> 31) as i32; /* sign bit of x */ - let signb : bool = sign != 0; - hx &= 0x7fffffff; /* high word of |x| */ - + let sign = (hx >> 31) as i32; /* sign bit of x */ + let signb: bool = sign != 0; + hx &= 0x7fffffff; /* high word of |x| */ + /* special cases */ - if hx >= 0x42aeac50 { /* if |x| >= -87.33655f or NaN */ - if hx > 0x7f800000 {/* NaN */ + if hx >= 0x42aeac50 { + /* if |x| >= -87.33655f or NaN */ + if hx > 0x7f800000 { + /* NaN */ return x; } - if (hx >= 0x42b17218) && (!signb) { /* x >= 88.722839f */ + if (hx >= 0x42b17218) && (!signb) { + /* x >= 88.722839f */ /* overflow */ x *= x1p127; return x; } if signb { /* underflow */ - force_eval!(-x1p_126/x); - if hx >= 0x42cff1b5 { /* x <= -103.972084f */ - return 0. + force_eval!(-x1p_126 / x); + if hx >= 0x42cff1b5 { + /* x <= -103.972084f */ + return 0.; } } } - + /* argument reduction */ - let k : i32; - let hi : f32; - let lo : f32; - if hx > 0x3eb17218 { /* if |x| > 0.5 ln2 */ - if hx > 0x3f851592 { /* if |x| > 1.5 ln2 */ - k = (INV_LN2*x + HALF[sign as usize]) as i32; + let k: i32; + let hi: f32; + let lo: f32; + if hx > 0x3eb17218 { + /* if |x| > 0.5 ln2 */ + if hx > 0x3f851592 { + /* if |x| > 1.5 ln2 */ + k = (INV_LN2 * x + HALF[sign as usize]) as i32; } else { k = 1 - sign - sign; } let kf = k as f32; - hi = x - kf*LN2_HI; /* k*ln2hi is exact here */ - lo = kf*LN2_LO; + hi = x - kf * LN2_HI; /* k*ln2hi is exact here */ + lo = kf * LN2_LO; x = hi - lo; - } else if hx > 0x39000000 { /* |x| > 2**-14 */ + } else if hx > 0x39000000 { + /* |x| > 2**-14 */ k = 0; hi = x; lo = 0.; @@ -63,11 +70,11 @@ pub fn expf(mut x: f32) -> f32 { force_eval!(x1p127 + x); return 1. + x; } - + /* x is now in primary range */ - let xx = x*x; - let c = x - xx*(P1+xx*P2); - let y = 1. + (x*c/(2.-c) - lo + hi); + let xx = x * x; + let c = x - xx * (P1 + xx * P2); + let y = 1. + (x * c / (2. - c) - lo + hi); if k == 0 { y } else { diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index a5fb1757413b8..997865d39e93c 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -1,27 +1,27 @@ use core::f64; -const TOINT : f64 = 1. / f64::EPSILON; +const TOINT: f64 = 1. / f64::EPSILON; #[inline] -pub fn floor(x : f64) -> f64 { +pub fn floor(x: f64) -> f64 { let ui = x.to_bits(); - let e = ((ui >> 52) & 0x7ff) as i32; + let e = ((ui >> 52) & 0x7ff) as i32; - if (e >= 0x3ff+52) || (x == 0.) { - return x; + if (e >= 0x3ff + 52) || (x == 0.) { + return x; } - /* y = int(x) - x, where int(x) is an integer neighbor of x */ - let y = if (ui >> 63) != 0 { - x - TOINT + TOINT - x - } else { - x + TOINT - TOINT - x + /* y = int(x) - x, where int(x) is an integer neighbor of x */ + let y = if (ui >> 63) != 0 { + x - TOINT + TOINT - x + } else { + x + TOINT - TOINT - x }; - /* special case because of non-nearest rounding modes */ - if e <= 0x3ff-1 { - force_eval!(y); - return if (ui >> 63) != 0 { -1. } else { 0. }; - } - if y > 0. { + /* special case because of non-nearest rounding modes */ + if e <= 0x3ff - 1 { + force_eval!(y); + return if (ui >> 63) != 0 { -1. } else { 0. }; + } + if y > 0. { x + y - 1. } else { x + y diff --git a/library/compiler-builtins/libm/src/math/hypot.rs b/library/compiler-builtins/libm/src/math/hypot.rs index dcc17d914fb91..7ad1baf796c82 100644 --- a/library/compiler-builtins/libm/src/math/hypot.rs +++ b/library/compiler-builtins/libm/src/math/hypot.rs @@ -12,8 +12,8 @@ fn sq(x: f64) -> (f64, f64) { xc = x * SPLIT; xh = x - xc + xc; xl = x - xh; - let hi = x*x; - let lo = xh*xh - hi + 2.*xh*xl + xl*xl; + let hi = x * x; + let lo = xh * xh - hi + 2. * xh * xl + xl * xl; (hi, lo) } @@ -39,8 +39,8 @@ pub fn hypot(mut x: f64, mut y: f64) -> f64 { } /* special cases */ - ex = (uxi>>52) as i64; - ey = (uyi>>52) as i64; + ex = (uxi >> 52) as i64; + ey = (uyi >> 52) as i64; x = f64::from_bits(uxi); y = f64::from_bits(uyi); /* note: hypot(inf,nan) == inf */ @@ -59,16 +59,16 @@ pub fn hypot(mut x: f64, mut y: f64) -> f64 { /* precise sqrt argument in nearest rounding mode without overflow */ /* xh*xh must not overflow and xl*xl must not underflow in sq */ z = 1.; - if ex > 0x3ff+510 { + if ex > 0x3ff + 510 { z = x1p700; x *= x1p_700; y *= x1p_700; - } else if ey < 0x3ff-450 { + } else if ey < 0x3ff - 450 { z = x1p_700; x *= x1p700; y *= x1p700; } let (hx, lx) = sq(x); let (hy, ly) = sq(y); - return z*sqrt(ly+lx+hy+hx); + return z * sqrt(ly + lx + hy + hx); } diff --git a/library/compiler-builtins/libm/src/math/hypotf.rs b/library/compiler-builtins/libm/src/math/hypotf.rs index 146aab4e44646..d59710ada3956 100644 --- a/library/compiler-builtins/libm/src/math/hypotf.rs +++ b/library/compiler-builtins/libm/src/math/hypotf.rs @@ -22,22 +22,22 @@ pub fn hypotf(mut x: f32, mut y: f32) -> f32 { x = f32::from_bits(uxi); y = f32::from_bits(uyi); - if uyi == 0xff<<23 { + if uyi == 0xff << 23 { return y; } - if uxi >= 0xff<<23 || uyi == 0 || uxi - uyi >= 25<<23 { + if uxi >= 0xff << 23 || uyi == 0 || uxi - uyi >= 25 << 23 { return x + y; } z = 1.; - if uxi >= (0x7f+60)<<23 { + if uxi >= (0x7f + 60) << 23 { z = x1p90; x *= x1p_90; y *= x1p_90; - } else if uyi < (0x7f-60)<<23 { + } else if uyi < (0x7f - 60) << 23 { z = x1p_90; x *= x1p90; y *= x1p90; } - z*sqrtf((x as f64 * x as f64 + y as f64 * y as f64) as f32) + z * sqrtf((x as f64 * x as f64 + y as f64 * y as f64) as f32) } diff --git a/library/compiler-builtins/libm/src/math/logf.rs b/library/compiler-builtins/libm/src/math/logf.rs index 76b4ede195149..78c5e94ad92aa 100644 --- a/library/compiler-builtins/libm/src/math/logf.rs +++ b/library/compiler-builtins/libm/src/math/logf.rs @@ -1,24 +1,25 @@ -const LN2_HI : f32 = 6.9313812256e-01; /* 0x3f317180 */ -const LN2_LO : f32 = 9.0580006145e-06; /* 0x3717f7d1 */ +const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ +const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ -const LG1 : f32 = 0.66666662693; /* 0xaaaaaa.0p-24*/ -const LG2 : f32 = 0.40000972152; /* 0xccce13.0p-25 */ -const LG3 : f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ -const LG4 : f32 = 0.24279078841; /* 0xf89e26.0p-26 */ +const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24*/ +const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ #[inline] pub fn logf(mut x: f32) -> f32 { let x1p25 = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 - + let mut ix = x.to_bits(); let mut k = 0i32; - - if (ix < 0x00800000) || ((ix>>31) != 0) { /* x < 2**-126 */ - if ix<<1 == 0 { - return -1./(x*x); /* log(+-0)=-inf */ + + if (ix < 0x00800000) || ((ix >> 31) != 0) { + /* x < 2**-126 */ + if ix << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ } - if (ix>>31) != 0 { - return (x-x)/0.; /* log(-#) = NaN */ + if (ix >> 31) != 0 { + return (x - x) / 0.; /* log(-#) = NaN */ } /* subnormal number, scale up x */ k -= 25; @@ -32,18 +33,18 @@ pub fn logf(mut x: f32) -> f32 { /* reduce x into [sqrt(2)/2, sqrt(2)] */ ix += 0x3f800000 - 0x3f3504f3; - k += ((ix>>23) as i32) - 0x7f; + k += ((ix >> 23) as i32) - 0x7f; ix = (ix & 0x007fffff) + 0x3f3504f3; - x = f32::from_bits(ix); + x = f32::from_bits(ix); let f = x - 1.; - let s = f/(2. + f); - let z = s*s; - let w = z*z; - let t1 = w*(LG2+w*LG4); - let t2 = z*(LG1+w*LG3); + let s = f / (2. + f); + let z = s * s; + let w = z * z; + let t1 = w * (LG2 + w * LG4); + let t2 = z * (LG1 + w * LG3); let r = t2 + t1; - let hfsq = 0.5*f*f; + let hfsq = 0.5 * f * f; let dk = k as f32; - s*(hfsq+r) + dk*LN2_LO - hfsq + f + dk*LN2_HI + s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index d0121048d96b8..c43199f825c39 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -7,10 +7,15 @@ macro_rules! force_eval { } mod ceilf; +mod expf; mod fabs; mod fabsf; +mod floor; mod floorf; mod fmodf; +mod hypot; +mod hypotf; +mod logf; mod powf; mod round; mod roundf; @@ -18,36 +23,15 @@ mod scalbn; mod scalbnf; mod sqrt; mod sqrtf; -mod logf; -mod expf; -mod floor; mod trunc; mod truncf; -mod hypot; -mod hypotf; //mod service; pub use self::{ - ceilf::ceilf, - fabs::fabs, - fabsf::fabsf, - floorf::floorf, - fmodf::fmodf, - powf::powf, - round::round, - roundf::roundf, - scalbn::scalbn, - scalbnf::scalbnf, - sqrt::sqrt, - sqrtf::sqrtf, - logf::logf, - expf::expf, - floor::floor, - trunc::trunc, - truncf::truncf, - hypot::hypot, - hypotf::hypotf, + ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmodf::fmodf, + hypot::hypot, hypotf::hypotf, logf::logf, powf::powf, round::round, roundf::roundf, + scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, }; fn isnanf(x: f32) -> bool { diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs index 2a9f67c1d0fa2..73d431c518395 100644 --- a/library/compiler-builtins/libm/src/math/round.rs +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -26,7 +26,7 @@ pub fn round(mut x: f64) -> f64 { } else { y = y + x; } - + if i >> 63 != 0 { -y } else { diff --git a/library/compiler-builtins/libm/src/math/scalbn.rs b/library/compiler-builtins/libm/src/math/scalbn.rs index 76e06f03ece25..ad81072ddc98c 100644 --- a/library/compiler-builtins/libm/src/math/scalbn.rs +++ b/library/compiler-builtins/libm/src/math/scalbn.rs @@ -1,11 +1,11 @@ #[inline] -pub fn scalbn(x : f64, mut n: i32) -> f64 { - let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 - let x1p53 = f64::from_bits(0x4340000000000000); // 0x1p53 === 2 ^ 53 +pub fn scalbn(x: f64, mut n: i32) -> f64 { + let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 + let x1p53 = f64::from_bits(0x4340000000000000); // 0x1p53 === 2 ^ 53 let x1p_1022 = f64::from_bits(0x0010000000000000); // 0x1p-1022 === 2 ^ (-1022) - + let mut y = x; - + if n > 1023 { y *= x1p1023; n -= 1023; @@ -29,5 +29,5 @@ pub fn scalbn(x : f64, mut n: i32) -> f64 { } } } - y*f64::from_bits(((0x3ff+n) as u64)<<52) + y * f64::from_bits(((0x3ff + n) as u64) << 52) } diff --git a/library/compiler-builtins/libm/src/math/scalbnf.rs b/library/compiler-builtins/libm/src/math/scalbnf.rs index 31f93d323c5c9..901497e5e51d7 100644 --- a/library/compiler-builtins/libm/src/math/scalbnf.rs +++ b/library/compiler-builtins/libm/src/math/scalbnf.rs @@ -1,9 +1,9 @@ #[inline] -pub fn scalbnf(mut x: f32, mut n : i32) -> f32 { - let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 - let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 - let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 - +pub fn scalbnf(mut x: f32, mut n: i32) -> f32 { + let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 + let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 + let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 + if n > 127 { x *= x1p127; n -= 127; @@ -25,5 +25,5 @@ pub fn scalbnf(mut x: f32, mut n : i32) -> f32 { } } } - x * f32::from_bits(((0x7f+n) as u32)<<23) + x * f32::from_bits(((0x7f + n) as u32) << 23) } diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 49fc58fff03ca..17de5a2e03084 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -22,60 +22,62 @@ pub fn sqrt(x: f64) -> f64 { ix1 = x.to_bits() as u32; /* take care of Inf and NaN */ - if (ix0&0x7ff00000) == 0x7ff00000 { - return x*x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + if (ix0 & 0x7ff00000) == 0x7ff00000 { + return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ } /* take care of zero */ if ix0 <= 0 { - if ((ix0&!(sign as i32))|ix1 as i32) == 0 { - return x; /* sqrt(+-0) = +-0 */ + if ((ix0 & !(sign as i32)) | ix1 as i32) == 0 { + return x; /* sqrt(+-0) = +-0 */ } if ix0 < 0 { - return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ + return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ } } /* normalize x */ - m = ix0>>20; - if m == 0 { /* subnormal x */ + m = ix0 >> 20; + if m == 0 { + /* subnormal x */ while ix0 == 0 { m -= 21; - ix0 |= (ix1>>11) as i32; + ix0 |= (ix1 >> 11) as i32; ix1 <<= 21; } - i=0; - while (ix0&0x00100000) == 0 { + i = 0; + while (ix0 & 0x00100000) == 0 { i += 1; ix0 <<= 1; } m -= i - 1; - ix0 |= (ix1>>(32-i)) as i32; + ix0 |= (ix1 >> (32 - i)) as i32; ix1 <<= i; } - m -= 1023; /* unbias exponent */ - ix0 = (ix0&0x000fffff)|0x00100000; - if (m & 1) == 1 { /* odd m, double x to make it even */ - ix0 += ix0 + ((ix1&sign)>>31) as i32; + m -= 1023; /* unbias exponent */ + ix0 = (ix0 & 0x000fffff) | 0x00100000; + if (m & 1) == 1 { + /* odd m, double x to make it even */ + ix0 += ix0 + ((ix1 & sign) >> 31) as i32; ix1 += ix1; } - m >>= 1; /* m = [m/2] */ + m >>= 1; /* m = [m/2] */ /* generate sqrt(x) bit by bit */ - ix0 += ix0 + ((ix1&sign)>>31) as i32; + ix0 += ix0 + ((ix1 & sign) >> 31) as i32; ix1 += ix1; q = 0; /* [q,q1] = sqrt(x) */ q1 = 0; s0 = 0; s1 = 0; - r = 0x00200000; /* r = moving bit from right to left */ + r = 0x00200000; /* r = moving bit from right to left */ while r != 0 { t = s0 + r as i32; if t <= ix0 { - s0 = t + r as i32; + s0 = t + r as i32; ix0 -= t; - q += r as i32; + q += r as i32; } - ix0 += ix0 + ((ix1&sign)>>31) as i32; + ix0 += ix0 + ((ix1 & sign) >> 31) as i32; ix1 += ix1; r >>= 1; } @@ -83,10 +85,10 @@ pub fn sqrt(x: f64) -> f64 { r = sign; while r != 0 { t1 = s1 + r; - t = s0; + t = s0; if t < ix0 || (t == ix0 && t1 <= ix1) { s1 = t1 + r; - if (t1&sign) == sign && (s1&sign) == 0 { + if (t1 & sign) == sign && (s1 & sign) == 0 { s0 += 1; } ix0 -= t; @@ -96,19 +98,19 @@ pub fn sqrt(x: f64) -> f64 { ix1 -= t1; q1 += r; } - ix0 += ix0 + ((ix1&sign)>>31) as i32; + ix0 += ix0 + ((ix1 & sign) >> 31) as i32; ix1 += ix1; r >>= 1; } /* use floating add to find out rounding direction */ - if (ix0 as u32|ix1) != 0 { + if (ix0 as u32 | ix1) != 0 { z = 1.0 - TINY; /* raise inexact flag */ if z >= 1.0 { z = 1.0 + TINY; if q1 == 0xffffffff { q1 = 0; - q+=1; + q += 1; } else if z > 1.0 { if q1 == 0xfffffffe { q += 1; @@ -119,9 +121,9 @@ pub fn sqrt(x: f64) -> f64 { } } } - ix0 = (q>>1) + 0x3fe00000; - ix1 = q1>>1; - if (q&1) == 1 { + ix0 = (q >> 1) + 0x3fe00000; + ix1 = q1 >> 1; + if (q & 1) == 1 { ix1 |= sign; } ix0 += m << 20; From 6e6642b48ca0e66625266e4b106eeec364297f9b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 13 Jul 2018 21:53:01 -0500 Subject: [PATCH 0506/4206] force PR code to be formatted --- library/compiler-builtins/libm/.travis.yml | 2 ++ library/compiler-builtins/libm/ci/install.sh | 2 ++ library/compiler-builtins/libm/ci/script.sh | 6 ++---- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/.travis.yml b/library/compiler-builtins/libm/.travis.yml index 0c0832793474e..ae03b66019734 100644 --- a/library/compiler-builtins/libm/.travis.yml +++ b/library/compiler-builtins/libm/.travis.yml @@ -22,6 +22,8 @@ install: - bash ci/install.sh script: + # code must be already formatted + - cargo fmt -- --check - bash ci/script.sh after_script: set +e diff --git a/library/compiler-builtins/libm/ci/install.sh b/library/compiler-builtins/libm/ci/install.sh index efdbb06c206e5..68dd0f337ac18 100644 --- a/library/compiler-builtins/libm/ci/install.sh +++ b/library/compiler-builtins/libm/ci/install.sh @@ -5,6 +5,8 @@ main() { cargo install cross fi + rustup component add rustfmt-preview + rustup target add x86_64-unknown-linux-musl if [ $TARGET != x86_64-unknown-linux-gnu ]; then diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh index 3db6bfeb12d9a..d290030525085 100644 --- a/library/compiler-builtins/libm/ci/script.sh +++ b/library/compiler-builtins/libm/ci/script.sh @@ -10,10 +10,8 @@ main() { # generate tests cargo run --package test-generator --target x86_64-unknown-linux-musl - if cargo fmt --version >/dev/null 2>&1; then - # nicer syntax error messages (if any) - cargo fmt - fi + # nicer syntax error messages (if any) + cargo fmt # run tests cross test --target $TARGET --release From 131cc1ac449a64d81ca371ae183f3fa2eeec1cf8 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 13 Jul 2018 22:10:08 -0500 Subject: [PATCH 0507/4206] run cargo fmt -- --check on beta --- library/compiler-builtins/libm/.travis.yml | 4 ++-- library/compiler-builtins/libm/ci/install.sh | 7 +++++-- library/compiler-builtins/libm/ci/script.sh | 5 +++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/.travis.yml b/library/compiler-builtins/libm/.travis.yml index ae03b66019734..2bbb60fc64d19 100644 --- a/library/compiler-builtins/libm/.travis.yml +++ b/library/compiler-builtins/libm/.travis.yml @@ -15,6 +15,8 @@ matrix: - env: TARGET=powerpc64-unknown-linux-gnu - env: TARGET=powerpc64le-unknown-linux-gnu - env: TARGET=x86_64-unknown-linux-gnu + - env: TARGET=cargo-fmt + rust: beta before_install: set -e @@ -22,8 +24,6 @@ install: - bash ci/install.sh script: - # code must be already formatted - - cargo fmt -- --check - bash ci/script.sh after_script: set +e diff --git a/library/compiler-builtins/libm/ci/install.sh b/library/compiler-builtins/libm/ci/install.sh index 68dd0f337ac18..4d9552d231bc0 100644 --- a/library/compiler-builtins/libm/ci/install.sh +++ b/library/compiler-builtins/libm/ci/install.sh @@ -1,12 +1,15 @@ set -euxo pipefail main() { + if [ $TARGET = cargo-fmt ]; then + rustup component add rustfmt-preview + return + fi + if ! hash cross >/dev/null 2>&1; then cargo install cross fi - rustup component add rustfmt-preview - rustup target add x86_64-unknown-linux-musl if [ $TARGET != x86_64-unknown-linux-gnu ]; then diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh index d290030525085..a4f1b324d6608 100644 --- a/library/compiler-builtins/libm/ci/script.sh +++ b/library/compiler-builtins/libm/ci/script.sh @@ -1,6 +1,11 @@ set -euxo pipefail main() { + if [ $TARGET = cargo-fmt ]; then + cargo fmt -- --check + return + fi + # quick check cargo check From ea8d02ae0f0eee219144fe2aa96679e384b6d110 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 13 Jul 2018 22:15:21 -0500 Subject: [PATCH 0508/4206] make cargo fmt in ci/script.sh optional --- library/compiler-builtins/libm/ci/script.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh index a4f1b324d6608..f2a294b488f5d 100644 --- a/library/compiler-builtins/libm/ci/script.sh +++ b/library/compiler-builtins/libm/ci/script.sh @@ -15,8 +15,10 @@ main() { # generate tests cargo run --package test-generator --target x86_64-unknown-linux-musl - # nicer syntax error messages (if any) - cargo fmt + if cargo fmt --version >/dev/null 2>&1; then + # nicer syntax error messages (if any) + cargo fmt + fi # run tests cross test --target $TARGET --release From 30c31d32d337c69d1f7ce5142e3ec8dcfaa50d47 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 13 Jul 2018 23:40:57 -0400 Subject: [PATCH 0509/4206] implement log2 and log2f --- library/compiler-builtins/libm/src/lib.rs | 4 - .../compiler-builtins/libm/src/math/log2.rs | 86 +++++++++++++++++++ .../compiler-builtins/libm/src/math/log2f.rs | 71 +++++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 7 +- .../libm/test-generator/src/main.rs | 4 +- 5 files changed, 164 insertions(+), 8 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/log2.rs create mode 100644 library/compiler-builtins/libm/src/math/log2f.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 571cf365c8c8b..0194722af66cc 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -75,7 +75,6 @@ pub trait F32Ext: private::Sealed { fn log(self, base: Self) -> Self; - #[cfg(todo)] fn log2(self) -> Self; #[cfg(todo)] @@ -228,7 +227,6 @@ impl F32Ext for f32 { self.ln() / base.ln() } - #[cfg(todo)] #[inline] fn log2(self) -> Self { log2f(self) @@ -399,7 +397,6 @@ pub trait F64Ext: private::Sealed { #[cfg(todo)] fn log(self, base: Self) -> Self; - #[cfg(todo)] fn log2(self) -> Self; #[cfg(todo)] @@ -557,7 +554,6 @@ impl F64Ext for f64 { self.ln() / base.ln() } - #[cfg(todo)] #[inline] fn log2(self) -> Self { log2(self) diff --git a/library/compiler-builtins/libm/src/math/log2.rs b/library/compiler-builtins/libm/src/math/log2.rs new file mode 100644 index 0000000000000..c0d3263e3b461 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/log2.rs @@ -0,0 +1,86 @@ +use core::f64; + +const IVLN2HI: f64 = 1.44269504072144627571e+00; /* 0x3ff71547, 0x65200000 */ +const IVLN2LO: f64 = 1.67517131648865118353e-10; /* 0x3de705fc, 0x2eefa200 */ +const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +pub fn log2(mut x: f64) -> f64 { + let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 + + let mut ui: u64 = x.to_bits(); + let hfsq: f64; + let f: f64; + let s: f64; + let z: f64; + let r: f64; + let mut w: f64; + let t1: f64; + let t2: f64; + let y: f64; + let mut hi: f64; + let lo: f64; + let mut val_hi: f64; + let mut val_lo: f64; + let mut hx: u32; + let mut k: i32; + + hx = (ui >> 32) as u32; + k = 0; + if hx < 0x00100000 || (hx >> 31) > 0 { + if ui << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if (hx >> 31) > 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale x up */ + k -= 54; + x *= x1p54; + ui = x.to_bits(); + hx = (ui >> 32) as u32; + } else if hx >= 0x7ff00000 { + return x; + } else if hx == 0x3ff00000 && ui << 32 == 0 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (hx >> 20) as i32 - 0x3ff; + hx = (hx & 0x000fffff) + 0x3fe6a09e; + ui = (hx as u64) << 32 | (ui & 0xffffffff); + x = f64::from_bits(ui); + + f = x - 1.0; + hfsq = 0.5 * f * f; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * (LG4 + w * LG6)); + t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + r = t2 + t1; + + /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ + hi = f - hfsq; + ui = hi.to_bits(); + ui &= (-1i64 as u64) << 32; + hi = f64::from_bits(ui); + lo = f - hi - hfsq + s * (hfsq + r); + + val_hi = hi * IVLN2HI; + val_lo = (lo + hi) * IVLN2LO + lo * IVLN2HI; + + /* spadd(val_hi, val_lo, y), except for not using double_t: */ + y = k.into(); + w = y + val_hi; + val_lo += (y - w) + val_hi; + val_hi = w; + + return val_lo + val_hi; +} diff --git a/library/compiler-builtins/libm/src/math/log2f.rs b/library/compiler-builtins/libm/src/math/log2f.rs new file mode 100644 index 0000000000000..47a917bdb8d2e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/log2f.rs @@ -0,0 +1,71 @@ +use core::f32; + +const IVLN2HI: f32 = 1.4428710938e+00; /* 0x3fb8b000 */ +const IVLN2LO: f32 = -1.7605285393e-04; /* 0xb9389ad4 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ +const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ + +pub fn log2f(mut x: f32) -> f32 { + let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 + + let mut ui: u32 = x.to_bits(); + let hfsq: f32; + let f: f32; + let s: f32; + let z: f32; + let r: f32; + let w: f32; + let t1: f32; + let t2: f32; + let mut hi: f32; + let lo: f32; + let mut ix: u32; + let mut k: i32; + + ix = ui; + k = 0; + if ix < 0x00800000 || (ix >> 31) > 0 { + /* x < 2**-126 */ + if ix << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if (ix >> 31) > 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale up x */ + k -= 25; + x *= x1p25f; + ui = x.to_bits(); + ix = ui; + } else if ix >= 0x7f800000 { + return x; + } else if ix == 0x3f800000 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += (ix >> 23) as i32 - 0x7f; + ix = (ix & 0x007fffff) + 0x3f3504f3; + ui = ix; + x = f32::from_bits(ui); + + f = x - 1.0; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * LG4); + t2 = z * (LG1 + w * LG3); + r = t2 + t1; + hfsq = 0.5 * f * f; + + hi = f - hfsq; + ui = hi.to_bits(); + ui &= 0xfffff000; + hi = f32::from_bits(ui); + lo = f - hi - hfsq + s * (hfsq + r); + return (lo + hi) * IVLN2LO + lo * IVLN2HI + hi * IVLN2HI + k as f32; +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index c43199f825c39..a82c1ba7e5926 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -15,6 +15,8 @@ mod floorf; mod fmodf; mod hypot; mod hypotf; +mod log2; +mod log2f; mod logf; mod powf; mod round; @@ -30,8 +32,9 @@ mod truncf; pub use self::{ ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmodf::fmodf, - hypot::hypot, hypotf::hypotf, logf::logf, powf::powf, round::round, roundf::roundf, - scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, + hypot::hypot, hypotf::hypotf, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, + roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, + truncf::truncf, }; fn isnanf(x: f32) -> bool { diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 257232ca694ab..7ec2292c34981 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -664,7 +664,7 @@ f32_f32! { expf, // fdimf, // log10f, - // log2f, + log2f, logf, roundf, // sinf, @@ -709,7 +709,7 @@ f64_f64! { // log, // log10, // log1p, - // log2, + log2, round, // sin, // sinh, From a749e176b170c4527813a5d3191b6f203458870d Mon Sep 17 00:00:00 2001 From: Joseph Ryan Date: Fri, 13 Jul 2018 23:15:36 -0500 Subject: [PATCH 0510/4206] Implement fmod and tweak fmodf --- .../compiler-builtins/libm/src/math/fmod.rs | 80 +++++++++++++++++++ .../compiler-builtins/libm/src/math/fmodf.rs | 4 +- .../compiler-builtins/libm/src/math/mod.rs | 36 +++------ .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 91 insertions(+), 31 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fmod.rs diff --git a/library/compiler-builtins/libm/src/math/fmod.rs b/library/compiler-builtins/libm/src/math/fmod.rs new file mode 100644 index 0000000000000..23f0c4846c4b3 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmod.rs @@ -0,0 +1,80 @@ +use core::u64; + +#[inline] +pub fn fmod(x: f64, y: f64) -> f64 { + let mut uxi = x.to_bits(); + let mut uyi = y.to_bits(); + let mut ex = (uxi >> 52 & 0x7ff) as i64; + let mut ey = (uyi >> 52 & 0x7ff) as i64; + let sx = uxi >> 63; + let mut i; + + if uyi << 1 == 0 || y.is_nan() || ex == 0x7ff { + return (x * y) / (x * y); + } + if uxi << 1 <= uyi << 1 { + if uxi << 1 == uyi << 1 { + return 0.0 * x; + } + return x; + } + + /* normalize x and y */ + if ex == 0 { + i = uxi << 12; + while i >> 63 == 0 { + ex -= 1; + i <<= 1; + } + uxi <<= -ex + 1; + } else { + uxi &= u64::MAX >> 12; + uxi |= 1 << 52; + } + if ey == 0 { + i = uyi << 12; + while i >> 63 == 0 { + ey -= 1; + i <<= 1; + } + uyi <<= -ey + 1; + } else { + uyi &= u64::MAX >> 12; + uyi |= 1 << 52; + } + + /* x mod y */ + while ex > ey { + i = uxi - uyi; + if i >> 63 == 0 { + if i == 0 { + return 0.0 * x; + } + uxi = i; + } + uxi <<= 1; + ex -= 1; + } + i = uxi - uyi; + if i >> 63 == 0 { + if i == 0 { + return 0.0 * x; + } + uxi = i; + } + while uxi >> 52 == 0 { + uxi <<= 1; + ex -= 1; + } + + /* scale result */ + if ex > 0 { + uxi -= 1 << 52; + uxi |= (ex as u64) << 52; + } else { + uxi >>= -ex + 1; + } + uxi |= (sx as u64) << 63; + + f64::from_bits(uxi) +} diff --git a/library/compiler-builtins/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs index 9097752490854..8d0c2d5c82c1b 100644 --- a/library/compiler-builtins/libm/src/math/fmodf.rs +++ b/library/compiler-builtins/libm/src/math/fmodf.rs @@ -1,7 +1,5 @@ use core::u32; -use super::isnanf; - #[inline] pub fn fmodf(x: f32, y: f32) -> f32 { let mut uxi = x.to_bits(); @@ -11,7 +9,7 @@ pub fn fmodf(x: f32, y: f32) -> f32 { let sx = uxi & 0x80000000; let mut i; - if uyi << 1 == 0 || isnanf(y) || ex == 0xff { + if uyi << 1 == 0 || y.is_nan() || ex == 0xff { return (x * y) / (x * y); } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index d0121048d96b8..a81fc174bcb3b 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -7,10 +7,16 @@ macro_rules! force_eval { } mod ceilf; +mod expf; mod fabs; mod fabsf; +mod floor; mod floorf; +mod fmod; mod fmodf; +mod hypot; +mod hypotf; +mod logf; mod powf; mod round; mod roundf; @@ -18,38 +24,14 @@ mod scalbn; mod scalbnf; mod sqrt; mod sqrtf; -mod logf; -mod expf; -mod floor; mod trunc; mod truncf; -mod hypot; -mod hypotf; //mod service; pub use self::{ - ceilf::ceilf, - fabs::fabs, - fabsf::fabsf, - floorf::floorf, - fmodf::fmodf, - powf::powf, - round::round, - roundf::roundf, - scalbn::scalbn, - scalbnf::scalbnf, - sqrt::sqrt, - sqrtf::sqrtf, - logf::logf, - expf::expf, - floor::floor, - trunc::trunc, + ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmod::fmod, + fmodf::fmodf, hypot::hypot, hypotf::hypotf, logf::logf, powf::powf, round::round, + roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, - hypot::hypot, - hypotf::hypotf, }; - -fn isnanf(x: f32) -> bool { - x.to_bits() & 0x7fffffff > 0x7f800000 -} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 257232ca694ab..ee291027d21b2 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -724,7 +724,7 @@ f64_f64! { f64f64_f64! { // atan2, // fdim, - // fmod, + fmod, hypot, // pow, } From 65368071063a2b4a7d117301d67b6f3b66c70d1a Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 14 Jul 2018 00:24:22 -0400 Subject: [PATCH 0511/4206] implement log10 and log10f --- library/compiler-builtins/libm/src/lib.rs | 4 - .../compiler-builtins/libm/src/math/log10.rs | 98 +++++++++++++++++++ .../compiler-builtins/libm/src/math/log10f.rs | 76 ++++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 8 +- .../libm/test-generator/src/main.rs | 4 +- 5 files changed, 181 insertions(+), 9 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/log10.rs create mode 100644 library/compiler-builtins/libm/src/math/log10f.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 0194722af66cc..3ed89f7295077 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -77,7 +77,6 @@ pub trait F32Ext: private::Sealed { fn log2(self) -> Self; - #[cfg(todo)] fn log10(self) -> Self; #[cfg(todo)] @@ -232,7 +231,6 @@ impl F32Ext for f32 { log2f(self) } - #[cfg(todo)] #[inline] fn log10(self) -> Self { log10f(self) @@ -399,7 +397,6 @@ pub trait F64Ext: private::Sealed { fn log2(self) -> Self; - #[cfg(todo)] fn log10(self) -> Self; #[cfg(todo)] @@ -559,7 +556,6 @@ impl F64Ext for f64 { log2(self) } - #[cfg(todo)] #[inline] fn log10(self) -> Self { log10(self) diff --git a/library/compiler-builtins/libm/src/math/log10.rs b/library/compiler-builtins/libm/src/math/log10.rs new file mode 100644 index 0000000000000..137d8966f521c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/log10.rs @@ -0,0 +1,98 @@ +use core::f64; + +const IVLN10HI: f64 = 4.34294481878168880939e-01; /* 0x3fdbcb7b, 0x15200000 */ +const IVLN10LO: f64 = 2.50829467116452752298e-11; /* 0x3dbb9438, 0xca9aadd5 */ +const LOG10_2HI: f64 = 3.01029995663611771306e-01; /* 0x3FD34413, 0x509F6000 */ +const LOG10_2LO: f64 = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */ +const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +#[inline] +pub fn log10(mut x: f64) -> f64 { + let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 + + let mut ui: u64 = x.to_bits(); + let hfsq: f64; + let f: f64; + let s: f64; + let z: f64; + let r: f64; + let mut w: f64; + let t1: f64; + let t2: f64; + let dk: f64; + let y: f64; + let mut hi: f64; + let lo: f64; + let mut val_hi: f64; + let mut val_lo: f64; + let mut hx: u32; + let mut k: i32; + + hx = (ui >> 32) as u32; + k = 0; + if hx < 0x00100000 || (hx >> 31) > 0 { + if ui << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if (hx >> 31) > 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale x up */ + k -= 54; + x *= x1p54; + ui = x.to_bits(); + hx = (ui >> 32) as u32; + } else if hx >= 0x7ff00000 { + return x; + } else if hx == 0x3ff00000 && ui << 32 == 0 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (hx >> 20) as i32 - 0x3ff; + hx = (hx & 0x000fffff) + 0x3fe6a09e; + ui = (hx as u64) << 32 | (ui & 0xffffffff); + x = f64::from_bits(ui); + + f = x - 1.0; + hfsq = 0.5 * f * f; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * (LG4 + w * LG6)); + t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + r = t2 + t1; + + /* See log2.c for details. */ + /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ + hi = f - hfsq; + ui = hi.to_bits(); + ui &= (-1i64 as u64) << 32; + hi = f64::from_bits(ui); + lo = f - hi - hfsq + s * (hfsq + r); + + /* val_hi+val_lo ~ log10(1+f) + k*log10(2) */ + val_hi = hi * IVLN10HI; + dk = k as f64; + y = dk * LOG10_2HI; + val_lo = dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI; + + /* + * Extra precision in for adding y is not strictly needed + * since there is no very large cancellation near x = sqrt(2) or + * x = 1/sqrt(2), but we do it anyway since it costs little on CPUs + * with some parallelism and it reduces the error for many args. + */ + w = y + val_hi; + val_lo += (y - w) + val_hi; + val_hi = w; + + return val_lo + val_hi; +} diff --git a/library/compiler-builtins/libm/src/math/log10f.rs b/library/compiler-builtins/libm/src/math/log10f.rs new file mode 100644 index 0000000000000..58db093441f35 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/log10f.rs @@ -0,0 +1,76 @@ +use core::f32; + +const IVLN10HI: f32 = 4.3432617188e-01; /* 0x3ede6000 */ +const IVLN10LO: f32 = -3.1689971365e-05; /* 0xb804ead9 */ +const LOG10_2HI: f32 = 3.0102920532e-01; /* 0x3e9a2080 */ +const LOG10_2LO: f32 = 7.9034151668e-07; /* 0x355427db */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ +const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ + +#[inline] +pub fn log10f(mut x: f32) -> f32 { + let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 + + let mut ui: u32 = x.to_bits(); + let hfsq: f32; + let f: f32; + let s: f32; + let z: f32; + let r: f32; + let w: f32; + let t1: f32; + let t2: f32; + let dk: f32; + let mut hi: f32; + let lo: f32; + let mut ix: u32; + let mut k: i32; + + ix = ui; + k = 0; + if ix < 0x00800000 || (ix >> 31) > 0 { + /* x < 2**-126 */ + if ix << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if (ix >> 31) > 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale up x */ + k -= 25; + x *= x1p25f; + ui = x.to_bits(); + ix = ui; + } else if ix >= 0x7f800000 { + return x; + } else if ix == 0x3f800000 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += (ix >> 23) as i32 - 0x7f; + ix = (ix & 0x007fffff) + 0x3f3504f3; + ui = ix; + x = f32::from_bits(ui); + + f = x - 1.0; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * LG4); + t2 = z * (LG1 + w * LG3); + r = t2 + t1; + hfsq = 0.5 * f * f; + + hi = f - hfsq; + ui = hi.to_bits(); + ui &= 0xfffff000; + hi = f32::from_bits(ui); + lo = f - hi - hfsq + s * (hfsq + r); + dk = k as f32; + return dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI + hi * IVLN10HI + dk * LOG10_2HI; +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index a82c1ba7e5926..828eef8590858 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -15,6 +15,8 @@ mod floorf; mod fmodf; mod hypot; mod hypotf; +mod log10; +mod log10f; mod log2; mod log2f; mod logf; @@ -32,9 +34,9 @@ mod truncf; pub use self::{ ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmodf::fmodf, - hypot::hypot, hypotf::hypotf, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, - roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, - truncf::truncf, + hypot::hypot, hypotf::hypotf, log10::log10, log10f::log10f, log2::log2, log2f::log2f, + logf::logf, powf::powf, round::round, roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, + sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, }; fn isnanf(x: f32) -> bool { diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 7ec2292c34981..799a354a90af2 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -663,7 +663,7 @@ f32_f32! { // exp2f, expf, // fdimf, - // log10f, + log10f, log2f, logf, roundf, @@ -707,7 +707,7 @@ f64_f64! { // expm1, floor, // log, - // log10, + log10, // log1p, log2, round, From bcafb03f6cdb51d14978de6117180af99829c746 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 13 Jul 2018 23:34:37 -0500 Subject: [PATCH 0512/4206] update CONTRIBUTING --- library/compiler-builtins/libm/CONTRIBUTING.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md index 1f0a05a3f8d95..6f8e984f3004a 100644 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -10,7 +10,8 @@ can't, no problem! Your PR will be fully tested automatically. Though you may still want to add and run some unit tests. See the bottom of [`src/math/truncf.rs`] for an example of such tests; you can run unit tests with the `cargo test --lib` command. -- Send us a pull request! +- Send us a pull request! Make sure to run `cargo fmt` on your code before sending the PR. Also + include "closes #42" in the PR description to close the corresponding issue. - :tada: [issue tracker]: https://github.com/japaric/libm/issues From e9575059748b90eba751e31883b4b0b733e6253b Mon Sep 17 00:00:00 2001 From: Joseph Ryan Date: Fri, 13 Jul 2018 23:56:00 -0500 Subject: [PATCH 0513/4206] Fix log2 --- library/compiler-builtins/libm/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 0194722af66cc..735f8162e5a27 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -229,7 +229,7 @@ impl F32Ext for f32 { #[inline] fn log2(self) -> Self { - log2f(self) + self.log2f(self) } #[cfg(todo)] @@ -556,7 +556,7 @@ impl F64Ext for f64 { #[inline] fn log2(self) -> Self { - log2(self) + self.log2(self) } #[cfg(todo)] From 45d9d8caa60dd8555f27834f0d854f0c9fcf5bba Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sat, 14 Jul 2018 08:13:35 +0300 Subject: [PATCH 0514/4206] fix bug in rem_pio2_large --- .../compiler-builtins/libm/src/math/cosf.rs | 80 +++++++++---------- .../libm/src/math/{cosdf.rs => k_cosf.rs} | 2 +- .../libm/src/math/{sindf.rs => k_sinf.rs} | 2 +- .../compiler-builtins/libm/src/math/mod.rs | 8 +- .../libm/src/math/rem_pio2_large.rs | 8 +- 5 files changed, 50 insertions(+), 50 deletions(-) rename library/compiler-builtins/libm/src/math/{cosdf.rs => k_cosf.rs} (92%) rename library/compiler-builtins/libm/src/math/{sindf.rs => k_sinf.rs} (92%) diff --git a/library/compiler-builtins/libm/src/math/cosf.rs b/library/compiler-builtins/libm/src/math/cosf.rs index f63724e791eaf..ef46d4a15f2d7 100644 --- a/library/compiler-builtins/libm/src/math/cosf.rs +++ b/library/compiler-builtins/libm/src/math/cosf.rs @@ -1,4 +1,4 @@ -use super::{cosdf, sindf, rem_pio2f}; +use super::{k_cosf, k_sinf, rem_pio2f}; use core::f64::consts::FRAC_PI_2; @@ -14,52 +14,52 @@ pub fn cosf(x: f32) -> f32 { let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 - let mut ix = x.to_bits(); - let sign = (ix >> 31) != 0; - ix &= 0x7fffffff; + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; - if ix <= 0x3f490fda { /* |x| ~<= pi/4 */ - if ix < 0x39800000 { /* |x| < 2**-12 */ - /* raise inexact if x != 0 */ - force_eval!(x + x1p120); - return 1.; - } - return cosdf(x64); - } - if ix <= 0x407b53d1 { /* |x| ~<= 5*pi/4 */ - if ix > 0x4016cbe3 { /* |x| ~> 3*pi/4 */ - return -cosdf(if sign { x64+C2_PIO2 } else { x64-C2_PIO2 }); + if ix <= 0x3f490fda { /* |x| ~<= pi/4 */ + if ix < 0x39800000 { /* |x| < 2**-12 */ + /* raise inexact if x != 0 */ + force_eval!(x + x1p120); + return 1.; + } + return k_cosf(x64); + } + if ix <= 0x407b53d1 { /* |x| ~<= 5*pi/4 */ + if ix > 0x4016cbe3 { /* |x| ~> 3*pi/4 */ + return -k_cosf(if sign { x64+C2_PIO2 } else { x64-C2_PIO2 }); } else { - if sign { - return sindf(x64 + C1_PIO2); - } else { - return sindf(C1_PIO2 - x64); + if sign { + return k_sinf(x64 + C1_PIO2); + } else { + return k_sinf(C1_PIO2 - x64); } - } - } - if ix <= 0x40e231d5 { /* |x| ~<= 9*pi/4 */ - if ix > 0x40afeddf { /* |x| ~> 7*pi/4 */ - return cosdf(if sign { x64+C4_PIO2 } else { x64-C4_PIO2 }); - } else { - if sign { - return sindf(-x64 - C3_PIO2); - } else { - return sindf(x64 - C3_PIO2); + } + } + if ix <= 0x40e231d5 { /* |x| ~<= 9*pi/4 */ + if ix > 0x40afeddf { /* |x| ~> 7*pi/4 */ + return k_cosf(if sign { x64+C4_PIO2 } else { x64-C4_PIO2 }); + } else { + if sign { + return k_sinf(-x64 - C3_PIO2); + } else { + return k_sinf(x64 - C3_PIO2); } - } - } + } + } - /* cos(Inf or NaN) is NaN */ - if ix >= 0x7f800000 { - return x-x; + /* cos(Inf or NaN) is NaN */ + if ix >= 0x7f800000 { + return x-x; } - /* general argument reduction needed */ - let (n, y) = rem_pio2f(x); + /* general argument reduction needed */ + let (n, y) = rem_pio2f(x); match n&3 { - 0 => { cosdf( y) }, - 1 => { sindf(-y) }, - 2 => { -cosdf( y) }, - _ => { sindf( y) }, + 0 => { k_cosf( y) }, + 1 => { k_sinf(-y) }, + 2 => { -k_cosf( y) }, + _ => { k_sinf( y) }, } } diff --git a/library/compiler-builtins/libm/src/math/cosdf.rs b/library/compiler-builtins/libm/src/math/k_cosf.rs similarity index 92% rename from library/compiler-builtins/libm/src/math/cosdf.rs rename to library/compiler-builtins/libm/src/math/k_cosf.rs index 6c5e9d3495a4a..5d1ede7af9228 100644 --- a/library/compiler-builtins/libm/src/math/cosdf.rs +++ b/library/compiler-builtins/libm/src/math/k_cosf.rs @@ -5,7 +5,7 @@ const C2 : f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ const C3 : f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ #[inline] -pub(crate) fn cosdf(x : f64) -> f32 { +pub(crate) fn k_cosf(x : f64) -> f32 { let z = x*x; let w = z*z; let r = C2+z*C3; diff --git a/library/compiler-builtins/libm/src/math/sindf.rs b/library/compiler-builtins/libm/src/math/k_sinf.rs similarity index 92% rename from library/compiler-builtins/libm/src/math/sindf.rs rename to library/compiler-builtins/libm/src/math/k_sinf.rs index a633545ba80c9..5eedab3aa64a1 100644 --- a/library/compiler-builtins/libm/src/math/sindf.rs +++ b/library/compiler-builtins/libm/src/math/k_sinf.rs @@ -5,7 +5,7 @@ const S3 : f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ const S4 : f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ #[inline] -pub(crate) fn sindf(x : f64) -> f32 { +pub(crate) fn k_sinf(x : f64) -> f32 { let z = x*x; let w = z*z; let r = S3 + z*S4; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 4900bf94c5316..d844ee153d648 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -36,14 +36,14 @@ pub use self::{ truncf::truncf, }; -mod sindf; -mod cosdf; +mod k_cosf; +mod k_sinf; mod rem_pio2f; mod rem_pio2_large; use self::{ - sindf::sindf, - cosdf::cosdf, + k_cosf::k_cosf, + k_sinf::k_sinf, rem_pio2f::rem_pio2f, rem_pio2_large::rem_pio2_large, }; 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 18dc721c65188..b5fa7e0af6b98 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -1,5 +1,5 @@ -use super::scalbn; -use super::floor; +use math::scalbn; +use math::floor; // initial value for jk const INIT_JK : [usize; 4] = [3,4,4,6]; @@ -263,7 +263,7 @@ pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) let mut fw : f64; let mut n : i32; let mut ih : i32; - let mut z = 0f64; + let mut z : f64; let mut f : [f64;20] = [0.;20]; let mut fq : [f64;20] = [0.;20]; let mut q : [f64;20] = [0.;20]; @@ -308,7 +308,7 @@ pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) 'recompute: loop { /* distill q[] into iq[] reversingly */ let mut i = 0i32; - let mut z = q[jz]; + z = q[jz]; for j in (1..=jz).rev() { fw = (x1p_24*z) as i32 as f64; iq[i as usize] = (z - x1p24*fw) as i32; From 119bb9bd248aca933b27d8dc50892fcf2cca5402 Mon Sep 17 00:00:00 2001 From: Joseph Ryan Date: Sat, 14 Jul 2018 00:15:24 -0500 Subject: [PATCH 0515/4206] Revert log2 breakage --- library/compiler-builtins/libm/src/lib.rs | 4 ++-- library/compiler-builtins/libm/src/math/mod.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 735f8162e5a27..0194722af66cc 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -229,7 +229,7 @@ impl F32Ext for f32 { #[inline] fn log2(self) -> Self { - self.log2f(self) + log2f(self) } #[cfg(todo)] @@ -556,7 +556,7 @@ impl F64Ext for f64 { #[inline] fn log2(self) -> Self { - self.log2(self) + log2(self) } #[cfg(todo)] diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index e75429df59c75..56488c43806b1 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -33,7 +33,7 @@ mod truncf; pub use self::{ ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmod::fmod, - fmodf::fmodf, hypot::hypot, hypotf::hypotf, logf::logf, powf::powf, round::round, - roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, - truncf::truncf, + fmodf::fmodf, hypot::hypot, hypotf::hypotf, log2::log2, log2f::log2f, logf::logf, powf::powf, + round::round, roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, + trunc::trunc, truncf::truncf, }; From 83673acaa42c10f13f2792798ca8528058d09fb7 Mon Sep 17 00:00:00 2001 From: Opal Date: Sat, 14 Jul 2018 16:59:27 +1200 Subject: [PATCH 0516/4206] Add log implementation. Fixes rust-lang/libm#23 --- library/compiler-builtins/libm/src/lib.rs | 4 - .../compiler-builtins/libm/src/math/log.rs | 117 ++++++++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 3 +- .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 120 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/log.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 3ed89f7295077..39eb71e99c9fd 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -389,10 +389,8 @@ pub trait F64Ext: private::Sealed { #[cfg(todo)] fn exp2(self) -> Self; - #[cfg(todo)] fn ln(self) -> Self; - #[cfg(todo)] fn log(self, base: Self) -> Self; fn log2(self) -> Self; @@ -539,13 +537,11 @@ impl F64Ext for f64 { exp2(self) } - #[cfg(todo)] #[inline] fn ln(self) -> Self { log(self) } - #[cfg(todo)] #[inline] fn log(self, base: Self) -> Self { self.ln() / base.ln() diff --git a/library/compiler-builtins/libm/src/math/log.rs b/library/compiler-builtins/libm/src/math/log.rs new file mode 100644 index 0000000000000..48e9fa79a46fd --- /dev/null +++ b/library/compiler-builtins/libm/src/math/log.rs @@ -0,0 +1,117 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* log(x) + * Return the logarithm of x + * + * Method : + * 1. Argument Reduction: find k and f such that + * x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * 2. Approximation of log(1+f). + * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) + * = 2s + 2/3 s**3 + 2/5 s**5 + ....., + * = 2s + s*R + * We use a special Remez algorithm on [0,0.1716] to generate + * a polynomial of degree 14 to approximate R The maximum error + * of this polynomial approximation is bounded by 2**-58.45. In + * other words, + * 2 4 6 8 10 12 14 + * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s + * (the values of Lg1 to Lg7 are listed in the program) + * and + * | 2 14 | -58.45 + * | Lg1*s +...+Lg7*s - R(z) | <= 2 + * | | + * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. + * In order to guarantee error in log below 1ulp, we compute log + * by + * log(1+f) = f - s*(f - R) (if f is not too large) + * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) + * + * 3. Finally, log(x) = k*ln2 + log(1+f). + * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) + * Here ln2 is split into two floating point number: + * ln2_hi + ln2_lo, + * where n*ln2_hi is always exact for |n| < 2000. + * + * Special cases: + * log(x) is NaN with signal if x < 0 (including -INF) ; + * log(+INF) is +INF; log(0) is -INF with signal; + * log(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +const LN2_HI: f64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ +const LN2_LO: f64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ +const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +#[inline] +pub fn log(mut x: f64) -> f64 { + let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 + + let mut ui = x.to_bits(); + let mut hx: u32 = (ui >> 32) as u32; + let mut k: i32 = 0; + + if (hx < 0x00100000) || ((hx >> 31) != 0) { + /* x < 2**-126 */ + if ui << 1 == 0 { + return -1. / (x * x); /* log(+-0)=-inf */ + } + if hx >> 31 != 0 { + return (x - x) / 0.0; /* log(-#) = NaN */ + } + /* subnormal number, scale x up */ + k -= 54; + x *= x1p54; + ui = x.to_bits(); + hx = (ui >> 32) as u32; + } else if hx >= 0x7ff00000 { + return x; + } else if hx == 0x3ff00000 && ui << 32 == 0 { + return 0.; + } + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += ((hx >> 20) as i32) - 0x3ff; + hx = (hx & 0x000fffff) + 0x3fe6a09e; + ui = ((hx as u64) << 32) | (ui & 0xffffffff); + x = f64::from_bits(ui); + + let f: f64 = x - 1.0; + let hfsq: f64 = 0.5 * f * f; + let s: f64 = f / (2.0 + f); + let z: f64 = s * s; + let w: f64 = z * z; + let t1: f64 = w * (LG2 + w * (LG4 + w * LG6)); + let t2: f64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + let r: f64 = t2 + t1; + let dk: f64 = k as f64; + return s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI; +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 828eef8590858..6e514f86f9cb7 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -15,6 +15,7 @@ mod floorf; mod fmodf; mod hypot; mod hypotf; +mod log; mod log10; mod log10f; mod log2; @@ -34,7 +35,7 @@ mod truncf; pub use self::{ ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmodf::fmodf, - hypot::hypot, hypotf::hypotf, log10::log10, log10f::log10f, log2::log2, log2f::log2f, + hypot::hypot, hypotf::hypotf, log::log, log10::log10, log10f::log10f, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, }; diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 799a354a90af2..6f8d3c68a3204 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -706,7 +706,7 @@ f64_f64! { // exp2, // expm1, floor, - // log, + log, log10, // log1p, log2, From 88faf19ca55c94eebff3a113e40158f4413dbb16 Mon Sep 17 00:00:00 2001 From: Joseph Ryan Date: Sat, 14 Jul 2018 00:44:36 -0500 Subject: [PATCH 0517/4206] Run rustfmt --- library/compiler-builtins/libm/src/math/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 8559290814705..afa8cd8ef2339 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -35,7 +35,7 @@ mod truncf; pub use self::{ ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmod::fmod, - fmodf::fmodf, hypot::hypot, hypotf::hypotf, log10::log10, log10f::log10f, log2::log2, - log2f::log2f, logf::logf, powf::powf, round::round, roundf::roundf, scalbn::scalbn, + fmodf::fmodf, hypot::hypot, hypotf::hypotf, log10::log10, log10f::log10f, log2::log2, + log2f::log2f, logf::logf, powf::powf, round::round, roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, }; From ead2d02710a69bb83819a837fd5b9edcad2159a7 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sat, 14 Jul 2018 08:50:53 +0300 Subject: [PATCH 0518/4206] clean duplicates --- library/compiler-builtins/libm/src/math/mod.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 30e7a2c592dbb..00945b258c895 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -27,9 +27,6 @@ mod scalbn; mod scalbnf; mod sqrt; mod sqrtf; -mod logf; -mod expf; -mod floor; mod cosf; mod trunc; mod truncf; From f73c61b76230cbbb8061118ccd228411b7b84031 Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 14 Jul 2018 01:28:00 -0400 Subject: [PATCH 0519/4206] implement log1p and log1pf --- library/compiler-builtins/libm/src/lib.rs | 4 - .../compiler-builtins/libm/src/math/log1p.rs | 142 ++++++++++++++++++ .../compiler-builtins/libm/src/math/log1pf.rs | 97 ++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 8 +- .../libm/test-generator/src/main.rs | 3 +- 5 files changed, 246 insertions(+), 8 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/log1p.rs create mode 100644 library/compiler-builtins/libm/src/math/log1pf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 39eb71e99c9fd..30f879769d0b0 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -114,7 +114,6 @@ pub trait F32Ext: private::Sealed { #[cfg(todo)] fn exp_m1(self) -> Self; - #[cfg(todo)] fn ln_1p(self) -> Self; #[cfg(todo)] @@ -295,7 +294,6 @@ impl F32Ext for f32 { expm1f(self) } - #[cfg(todo)] #[inline] fn ln_1p(self) -> Self { log1pf(self) @@ -432,7 +430,6 @@ pub trait F64Ext: private::Sealed { #[cfg(todo)] fn exp_m1(self) -> Self; - #[cfg(todo)] fn ln_1p(self) -> Self; #[cfg(todo)] @@ -616,7 +613,6 @@ impl F64Ext for f64 { expm1(self) } - #[cfg(todo)] #[inline] fn ln_1p(self) -> Self { log1p(self) diff --git a/library/compiler-builtins/libm/src/math/log1p.rs b/library/compiler-builtins/libm/src/math/log1p.rs new file mode 100644 index 0000000000000..7f7a5125bbb34 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/log1p.rs @@ -0,0 +1,142 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_log1p.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. + * ==================================================== + */ +/* double log1p(double x) + * Return the natural logarithm of 1+x. + * + * Method : + * 1. Argument Reduction: find k and f such that + * 1+x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * Note. If k=0, then f=x is exact. However, if k!=0, then f + * may not be representable exactly. In that case, a correction + * term is need. Let u=1+x rounded. Let c = (1+x)-u, then + * log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u), + * and add back the correction term c/u. + * (Note: when x > 2**53, one can simply return log(x)) + * + * 2. Approximation of log(1+f): See log.c + * + * 3. Finally, log1p(x) = k*ln2 + log(1+f) + c/u. See log.c + * + * Special cases: + * log1p(x) is NaN with signal if x < -1 (including -INF) ; + * log1p(+INF) is +INF; log1p(-1) is -INF with signal; + * log1p(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + * + * Note: Assuming log() return accurate answer, the following + * algorithm can be used to compute log1p(x) to within a few ULP: + * + * u = 1+x; + * if(u==1.0) return x ; else + * return log(u)*(x/(u-1.0)); + * + * See HP-15C Advanced Functions Handbook, p.193. + */ + +use core::f64; + +const LN2_HI: f64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ +const LN2_LO: f64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ +const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ +const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ +const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ +const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ +const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ +const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ +const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +pub fn log1p(x: f64) -> f64 { + let mut ui: u64 = x.to_bits(); + let hfsq: f64; + let mut f: f64 = 0.; + let mut c: f64 = 0.; + let s: f64; + let z: f64; + let r: f64; + let w: f64; + let t1: f64; + let t2: f64; + let dk: f64; + let hx: u32; + let mut hu: u32; + let mut k: i32; + + hx = (ui >> 32) as u32; + k = 1; + if hx < 0x3fda827a || (hx >> 31) > 0 { + /* 1+x < sqrt(2)+ */ + if hx >= 0xbff00000 { + /* x <= -1.0 */ + if x == -1. { + return x / 0.0; /* log1p(-1) = -inf */ + } + return (x - x) / 0.0; /* log1p(x<-1) = NaN */ + } + if hx << 1 < 0x3ca00000 << 1 { + /* |x| < 2**-53 */ + /* underflow if subnormal */ + if (hx & 0x7ff00000) == 0 { + force_eval!(x as f32); + } + return x; + } + if hx <= 0xbfd2bec4 { + /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + k = 0; + c = 0.; + f = x; + } + } else if hx >= 0x7ff00000 { + return x; + } + if k > 0 { + ui = (1. + x).to_bits(); + hu = (ui >> 32) as u32; + hu += 0x3ff00000 - 0x3fe6a09e; + k = (hu >> 20) as i32 - 0x3ff; + /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ + if k < 54 { + c = if k >= 2 { + 1. - (f64::from_bits(ui) - x) + } else { + x - (f64::from_bits(ui) - 1.) + }; + c /= f64::from_bits(ui); + } else { + c = 0.; + } + /* reduce u into [sqrt(2)/2, sqrt(2)] */ + hu = (hu & 0x000fffff) + 0x3fe6a09e; + ui = (hu as u64) << 32 | (ui & 0xffffffff); + f = f64::from_bits(ui) - 1.; + } + hfsq = 0.5 * f * f; + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * (LG4 + w * LG6)); + t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); + r = t2 + t1; + dk = k as f64; + return s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI; +} diff --git a/library/compiler-builtins/libm/src/math/log1pf.rs b/library/compiler-builtins/libm/src/math/log1pf.rs new file mode 100644 index 0000000000000..c8e2422593375 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/log1pf.rs @@ -0,0 +1,97 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_log1pf.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. + * ==================================================== + */ + +use core::f32; + +const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ +const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ +const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ +const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ +const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ + +pub fn log1pf(x: f32) -> f32 { + let mut ui: u32 = x.to_bits(); + let hfsq: f32; + let mut f: f32 = 0.; + let mut c: f32 = 0.; + let s: f32; + let z: f32; + let r: f32; + let w: f32; + let t1: f32; + let t2: f32; + let dk: f32; + let ix: u32; + let mut iu: u32; + let mut k: i32; + + ix = ui; + k = 1; + if ix < 0x3ed413d0 || (ix >> 31) > 0 { + /* 1+x < sqrt(2)+ */ + if ix >= 0xbf800000 { + /* x <= -1.0 */ + if x == -1. { + return x / 0.0; /* log1p(-1)=+inf */ + } + return (x - x) / 0.0; /* log1p(x<-1)=NaN */ + } + if ix << 1 < 0x33800000 << 1 { + /* |x| < 2**-24 */ + /* underflow if subnormal */ + if (ix & 0x7f800000) == 0 { + force_eval!(x * x); + } + return x; + } + if ix <= 0xbe95f619 { + /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + k = 0; + c = 0.; + f = x; + } + } else if ix >= 0x7f800000 { + return x; + } + if k > 0 { + ui = (1. + x).to_bits(); + iu = ui; + iu += 0x3f800000 - 0x3f3504f3; + k = (iu >> 23) as i32 - 0x7f; + /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ + if k < 25 { + c = if k >= 2 { + 1. - (f32::from_bits(ui) - x) + } else { + x - (f32::from_bits(ui) - 1.) + }; + c /= f32::from_bits(ui); + } else { + c = 0.; + } + /* reduce u into [sqrt(2)/2, sqrt(2)] */ + iu = (iu & 0x007fffff) + 0x3f3504f3; + ui = iu; + f = f32::from_bits(ui) - 1.; + } + s = f / (2.0 + f); + z = s * s; + w = z * z; + t1 = w * (LG2 + w * LG4); + t2 = z * (LG1 + w * LG3); + r = t2 + t1; + hfsq = 0.5 * f * f; + dk = k as f32; + return s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI; +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 6e514f86f9cb7..fb5e3df90901d 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -18,6 +18,8 @@ mod hypotf; mod log; mod log10; mod log10f; +mod log1p; +mod log1pf; mod log2; mod log2f; mod logf; @@ -35,9 +37,9 @@ mod truncf; pub use self::{ ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmodf::fmodf, - hypot::hypot, hypotf::hypotf, log::log, log10::log10, log10f::log10f, log2::log2, log2f::log2f, - logf::logf, powf::powf, round::round, roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, - sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, + hypot::hypot, hypotf::hypotf, log::log, log10::log10, log10f::log10f, log1p::log1p, + log1pf::log1pf, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, roundf::roundf, + scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, }; fn isnanf(x: f32) -> bool { diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 6f8d3c68a3204..be5ed0784f8b3 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -664,6 +664,7 @@ f32_f32! { expf, // fdimf, log10f, + log1pf, log2f, logf, roundf, @@ -708,7 +709,7 @@ f64_f64! { floor, log, log10, - // log1p, + log1p, log2, round, // sin, From d03ec1472b73bab2a33ea798bfba689ae86b57c2 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sat, 14 Jul 2018 09:17:41 +0300 Subject: [PATCH 0520/4206] revert changes --- library/compiler-builtins/libm/src/math/rem_pio2_large.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 b5fa7e0af6b98..e1f5d1333905f 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -1,5 +1,5 @@ -use math::scalbn; -use math::floor; +use super::scalbn; +use super::floor; // initial value for jk const INIT_JK : [usize; 4] = [3,4,4,6]; From 6548a83edfe2e3835a14fe636a6be1d086d345bf Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 14 Jul 2018 02:26:19 -0400 Subject: [PATCH 0521/4206] add license and other comments to existing files --- .../compiler-builtins/libm/src/math/expf.rs | 15 ++++ .../compiler-builtins/libm/src/math/log10.rs | 19 +++++ .../compiler-builtins/libm/src/math/log10f.rs | 15 ++++ .../compiler-builtins/libm/src/math/log2.rs | 19 +++++ .../compiler-builtins/libm/src/math/log2f.rs | 15 ++++ .../compiler-builtins/libm/src/math/logf.rs | 15 ++++ .../compiler-builtins/libm/src/math/powf.rs | 15 ++++ .../compiler-builtins/libm/src/math/sqrt.rs | 78 +++++++++++++++++++ .../compiler-builtins/libm/src/math/sqrtf.rs | 15 ++++ 9 files changed, 206 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs index cffb557719f09..8ecc3b6abd61c 100644 --- a/library/compiler-builtins/libm/src/math/expf.rs +++ b/library/compiler-builtins/libm/src/math/expf.rs @@ -1,3 +1,18 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_expf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + use super::scalbnf; const HALF: [f32; 2] = [0.5, -0.5]; diff --git a/library/compiler-builtins/libm/src/math/log10.rs b/library/compiler-builtins/libm/src/math/log10.rs index 137d8966f521c..7c7afefa34562 100644 --- a/library/compiler-builtins/libm/src/math/log10.rs +++ b/library/compiler-builtins/libm/src/math/log10.rs @@ -1,3 +1,22 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log10.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Return the base 10 logarithm of x. See log.c for most comments. + * + * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 + * as in log.c, then combine and scale in extra precision: + * log10(x) = (f - f*f/2 + r)/log(10) + k*log10(2) + */ + use core::f64; const IVLN10HI: f64 = 4.34294481878168880939e-01; /* 0x3fdbcb7b, 0x15200000 */ diff --git a/library/compiler-builtins/libm/src/math/log10f.rs b/library/compiler-builtins/libm/src/math/log10f.rs index 58db093441f35..82b87c044b255 100644 --- a/library/compiler-builtins/libm/src/math/log10f.rs +++ b/library/compiler-builtins/libm/src/math/log10f.rs @@ -1,3 +1,18 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log10f.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. + * ==================================================== + */ +/* + * See comments in log10.c. + */ + use core::f32; const IVLN10HI: f32 = 4.3432617188e-01; /* 0x3ede6000 */ diff --git a/library/compiler-builtins/libm/src/math/log2.rs b/library/compiler-builtins/libm/src/math/log2.rs index c0d3263e3b461..f6640d296c307 100644 --- a/library/compiler-builtins/libm/src/math/log2.rs +++ b/library/compiler-builtins/libm/src/math/log2.rs @@ -1,3 +1,22 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Return the base 2 logarithm of x. See log.c for most comments. + * + * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 + * as in log.c, then combine and scale in extra precision: + * log2(x) = (f - f*f/2 + r)/log(2) + k + */ + use core::f64; const IVLN2HI: f64 = 1.44269504072144627571e+00; /* 0x3ff71547, 0x65200000 */ diff --git a/library/compiler-builtins/libm/src/math/log2f.rs b/library/compiler-builtins/libm/src/math/log2f.rs index 47a917bdb8d2e..c007ff9b097a7 100644 --- a/library/compiler-builtins/libm/src/math/log2f.rs +++ b/library/compiler-builtins/libm/src/math/log2f.rs @@ -1,3 +1,18 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log2f.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. + * ==================================================== + */ +/* + * See comments in log2.c. + */ + use core::f32; const IVLN2HI: f32 = 1.4428710938e+00; /* 0x3fb8b000 */ diff --git a/library/compiler-builtins/libm/src/math/logf.rs b/library/compiler-builtins/libm/src/math/logf.rs index 78c5e94ad92aa..09519104174b5 100644 --- a/library/compiler-builtins/libm/src/math/logf.rs +++ b/library/compiler-builtins/libm/src/math/logf.rs @@ -1,3 +1,18 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_logf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs index f1dc3a5b86782..8d0afe6693cff 100644 --- a/library/compiler-builtins/libm/src/math/powf.rs +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -1,3 +1,18 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_powf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + use super::{fabsf, scalbnf, sqrtf}; const BP: [f32; 2] = [1.0, 1.5]; diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 17de5a2e03084..cbadb49bba03b 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -1,3 +1,81 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_sqrt.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* sqrt(x) + * Return correctly rounded sqrt. + * ------------------------------------------ + * | Use the hardware sqrt if you have one | + * ------------------------------------------ + * Method: + * Bit by bit method using integer arithmetic. (Slow, but portable) + * 1. Normalization + * Scale x to y in [1,4) with even powers of 2: + * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then + * sqrt(x) = 2^k * sqrt(y) + * 2. Bit by bit computation + * Let q = sqrt(y) truncated to i bit after binary point (q = 1), + * i 0 + * i+1 2 + * s = 2*q , and y = 2 * ( y - q ). (1) + * i i i i + * + * To compute q from q , one checks whether + * i+1 i + * + * -(i+1) 2 + * (q + 2 ) <= y. (2) + * i + * -(i+1) + * If (2) is false, then q = q ; otherwise q = q + 2 . + * i+1 i i+1 i + * + * With some algebric manipulation, it is not difficult to see + * that (2) is equivalent to + * -(i+1) + * s + 2 <= y (3) + * i i + * + * The advantage of (3) is that s and y can be computed by + * i i + * the following recurrence formula: + * if (3) is false + * + * s = s , y = y ; (4) + * i+1 i i+1 i + * + * otherwise, + * -i -(i+1) + * s = s + 2 , y = y - s - 2 (5) + * i+1 i i+1 i i + * + * One may easily use induction to prove (4) and (5). + * Note. Since the left hand side of (3) contain only i+2 bits, + * it does not necessary to do a full (53-bit) comparison + * in (3). + * 3. Final rounding + * After generating the 53 bits result, we compute one more bit. + * Together with the remainder, we can decide whether the + * result is exact, bigger than 1/2ulp, or less than 1/2ulp + * (it will never equal to 1/2ulp). + * The rounding mode can be detected by checking whether + * huge + tiny is equal to huge, and whether huge - tiny is + * equal to huge for some floating point number "huge" and "tiny". + * + * Special cases: + * sqrt(+-0) = +-0 ... exact + * sqrt(inf) = inf + * sqrt(-ve) = NaN ... with invalid signal + * sqrt(NaN) = NaN ... with invalid signal for signaling NaN + */ + use core::f64; const TINY: f64 = 1.0e-300; diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index a265bef48eb26..49984689efc28 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -1,3 +1,18 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_sqrtf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + const TINY: f32 = 1.0e-30; #[inline] From d67c2c391b86738246d90ba902b96b79c021a2bd Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sat, 14 Jul 2018 09:33:46 +0300 Subject: [PATCH 0522/4206] cargo fmt --- .../compiler-builtins/libm/src/math/cosf.rs | 46 +- .../compiler-builtins/libm/src/math/k_cosf.rs | 18 +- .../compiler-builtins/libm/src/math/k_sinf.rs | 20 +- .../compiler-builtins/libm/src/math/mod.rs | 19 +- .../libm/src/math/rem_pio2_large.rs | 393 ++++++++---------- .../libm/src/math/rem_pio2f.rs | 32 +- 6 files changed, 249 insertions(+), 279 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/cosf.rs b/library/compiler-builtins/libm/src/math/cosf.rs index ef46d4a15f2d7..79df97e354a37 100644 --- a/library/compiler-builtins/libm/src/math/cosf.rs +++ b/library/compiler-builtins/libm/src/math/cosf.rs @@ -3,32 +3,36 @@ use super::{k_cosf, k_sinf, rem_pio2f}; use core::f64::consts::FRAC_PI_2; /* Small multiples of pi/2 rounded to double precision. */ -const C1_PIO2 : f64 = 1.*FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ -const C2_PIO2 : f64 = 2.*FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ -const C3_PIO2 : f64 = 3.*FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ -const C4_PIO2 : f64 = 4.*FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ +const C1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ +const C2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ +const C3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const C4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ #[inline] pub fn cosf(x: f32) -> f32 { let x64 = x as f64; - + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 - + let mut ix = x.to_bits(); let sign = (ix >> 31) != 0; ix &= 0x7fffffff; - if ix <= 0x3f490fda { /* |x| ~<= pi/4 */ - if ix < 0x39800000 { /* |x| < 2**-12 */ + if ix <= 0x3f490fda { + /* |x| ~<= pi/4 */ + if ix < 0x39800000 { + /* |x| < 2**-12 */ /* raise inexact if x != 0 */ force_eval!(x + x1p120); return 1.; } return k_cosf(x64); } - if ix <= 0x407b53d1 { /* |x| ~<= 5*pi/4 */ - if ix > 0x4016cbe3 { /* |x| ~> 3*pi/4 */ - return -k_cosf(if sign { x64+C2_PIO2 } else { x64-C2_PIO2 }); + if ix <= 0x407b53d1 { + /* |x| ~<= 5*pi/4 */ + if ix > 0x4016cbe3 { + /* |x| ~> 3*pi/4 */ + return -k_cosf(if sign { x64 + C2_PIO2 } else { x64 - C2_PIO2 }); } else { if sign { return k_sinf(x64 + C1_PIO2); @@ -37,9 +41,11 @@ pub fn cosf(x: f32) -> f32 { } } } - if ix <= 0x40e231d5 { /* |x| ~<= 9*pi/4 */ - if ix > 0x40afeddf { /* |x| ~> 7*pi/4 */ - return k_cosf(if sign { x64+C4_PIO2 } else { x64-C4_PIO2 }); + if ix <= 0x40e231d5 { + /* |x| ~<= 9*pi/4 */ + if ix > 0x40afeddf { + /* |x| ~> 7*pi/4 */ + return k_cosf(if sign { x64 + C4_PIO2 } else { x64 - C4_PIO2 }); } else { if sign { return k_sinf(-x64 - C3_PIO2); @@ -51,15 +57,15 @@ pub fn cosf(x: f32) -> f32 { /* cos(Inf or NaN) is NaN */ if ix >= 0x7f800000 { - return x-x; + return x - x; } /* general argument reduction needed */ let (n, y) = rem_pio2f(x); - match n&3 { - 0 => { k_cosf( y) }, - 1 => { k_sinf(-y) }, - 2 => { -k_cosf( y) }, - _ => { k_sinf( y) }, + match n & 3 { + 0 => k_cosf(y), + 1 => k_sinf(-y), + 2 => -k_cosf(y), + _ => k_sinf(y), } } diff --git a/library/compiler-builtins/libm/src/math/k_cosf.rs b/library/compiler-builtins/libm/src/math/k_cosf.rs index 5d1ede7af9228..83d13b2e998ad 100644 --- a/library/compiler-builtins/libm/src/math/k_cosf.rs +++ b/library/compiler-builtins/libm/src/math/k_cosf.rs @@ -1,13 +1,13 @@ /* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ -const C0 : f64 = -0.499999997251031003120; /* -0x1ffffffd0c5e81.0p-54 */ -const C1 : f64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ -const C2 : f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ -const C3 : f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ +const C0: f64 = -0.499999997251031003120; /* -0x1ffffffd0c5e81.0p-54 */ +const C1: f64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ +const C2: f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ +const C3: f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ #[inline] -pub(crate) fn k_cosf(x : f64) -> f32 { - let z = x*x; - let w = z*z; - let r = C2+z*C3; - (((1.0+z*C0) + w*C1) + (w*z)*r) as f32 +pub(crate) fn k_cosf(x: f64) -> f32 { + let z = x * x; + let w = z * z; + let r = C2 + z * C3; + (((1.0 + z * C0) + w * C1) + (w * z) * r) as f32 } diff --git a/library/compiler-builtins/libm/src/math/k_sinf.rs b/library/compiler-builtins/libm/src/math/k_sinf.rs index 5eedab3aa64a1..bb2183afc7cad 100644 --- a/library/compiler-builtins/libm/src/math/k_sinf.rs +++ b/library/compiler-builtins/libm/src/math/k_sinf.rs @@ -1,14 +1,14 @@ /* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ -const S1 : f64 = -0.166666666416265235595; /* -0x15555554cbac77.0p-55 */ -const S2 : f64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ -const S3 : f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ -const S4 : f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ +const S1: f64 = -0.166666666416265235595; /* -0x15555554cbac77.0p-55 */ +const S2: f64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ +const S3: f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ +const S4: f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ #[inline] -pub(crate) fn k_sinf(x : f64) -> f32 { - let z = x*x; - let w = z*z; - let r = S3 + z*S4; - let s = z*x; - ((x + s*(S1 + z*S2)) + s*w*r) as f32 +pub(crate) fn k_sinf(x: f64) -> f32 { + let z = x * x; + let w = z * z; + let r = S3 + z * S4; + let s = z * x; + ((x + s * (S1 + z * S2)) + s * w * r) as f32 } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 00945b258c895..013e70870bbed 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -7,6 +7,7 @@ macro_rules! force_eval { } mod ceilf; +mod cosf; mod expf; mod fabs; mod fabsf; @@ -27,28 +28,22 @@ mod scalbn; mod scalbnf; mod sqrt; mod sqrtf; -mod cosf; mod trunc; mod truncf; pub use self::{ - ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmodf::fmodf, - hypot::hypot, hypotf::hypotf, log10::log10, log10f::log10f, log2::log2, log2f::log2f, - logf::logf, powf::powf, round::round, roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, - sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, cosf::cosf, + ceilf::ceilf, cosf::cosf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, + fmodf::fmodf, hypot::hypot, hypotf::hypotf, log10::log10, log10f::log10f, log2::log2, + log2f::log2f, logf::logf, powf::powf, round::round, roundf::roundf, scalbn::scalbn, + scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, }; mod k_cosf; mod k_sinf; -mod rem_pio2f; mod rem_pio2_large; +mod rem_pio2f; -use self::{ - k_cosf::k_cosf, - k_sinf::k_sinf, - rem_pio2f::rem_pio2f, - rem_pio2_large::rem_pio2_large, -}; +use self::{k_cosf::k_cosf, k_sinf::k_sinf, rem_pio2_large::rem_pio2_large, rem_pio2f::rem_pio2f}; fn isnanf(x: f32) -> bool { x.to_bits() & 0x7fffffff > 0x7f800000 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 e1f5d1333905f..52b47279cd911 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -1,8 +1,8 @@ -use super::scalbn; use super::floor; +use super::scalbn; // initial value for jk -const INIT_JK : [usize; 4] = [3,4,4,6]; +const INIT_JK: [usize; 4] = [3, 4, 4, 6]; // Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi // @@ -15,140 +15,99 @@ const INIT_JK : [usize; 4] = [3,4,4,6]; // NB: This table must have at least (e0-3)/24 + jk terms. // For quad precision (e0 <= 16360, jk = 6), this is 686. #[cfg(target_pointer_width = "32")] -const IPIO2 : [i32; 66] = [ - 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, - 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, - 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, - 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, - 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, - 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, - 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, - 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, - 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, - 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, - 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, +const IPIO2: [i32; 66] = [ + 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, + 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, + 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, 0x3991D6, 0x398353, 0x39F49C, + 0x845F8B, 0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, + 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, 0xF17B3D, 0x0739F7, 0x8A5292, + 0xEA6BFB, 0x5FB11F, 0x8D5D08, 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, + 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA, + 0x73A8C9, 0x60E27B, 0xC08C6B, ]; #[cfg(target_pointer_width = "64")] -const IPIO2 : [i32; 690] = [ - 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, - 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, - 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, - 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, - 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, - 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, - 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, - 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, - 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, - 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, - 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, - 0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, - 0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, - 0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35, - 0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, - 0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, - 0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4, - 0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, - 0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, - 0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19, - 0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, - 0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, - 0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6, - 0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, - 0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, - 0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3, - 0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, - 0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, - 0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612, - 0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, - 0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, - 0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B, - 0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, - 0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, - 0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB, - 0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, - 0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, - 0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F, - 0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, - 0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, - 0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B, - 0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, - 0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, - 0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3, - 0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, - 0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, - 0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F, - 0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, - 0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, - 0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51, - 0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, - 0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, - 0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6, - 0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, - 0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, - 0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328, - 0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, - 0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, - 0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B, - 0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, - 0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, - 0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F, - 0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, - 0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, - 0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4, - 0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, - 0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, - 0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30, - 0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, - 0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, - 0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1, - 0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, - 0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, - 0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08, - 0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, - 0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, - 0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4, - 0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, - 0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, - 0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0, - 0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, - 0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, - 0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC, - 0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, - 0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, - 0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7, - 0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, - 0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, - 0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4, - 0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, - 0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, - 0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2, - 0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, - 0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, - 0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569, - 0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, - 0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, - 0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D, - 0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, - 0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, - 0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569, - 0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, - 0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, - 0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41, - 0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, - 0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, - 0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110, - 0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, - 0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, - 0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A, - 0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, - 0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, - 0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616, - 0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, +const IPIO2: [i32; 690] = [ + 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, + 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, + 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, 0x3991D6, 0x398353, 0x39F49C, + 0x845F8B, 0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, + 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, 0xF17B3D, 0x0739F7, 0x8A5292, + 0xEA6BFB, 0x5FB11F, 0x8D5D08, 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, + 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA, + 0x73A8C9, 0x60E27B, 0xC08C6B, 0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, + 0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, 0xDE4F98, 0x327DBB, 0xC33D26, + 0xEF6B1E, 0x5EF89F, 0x3A1F35, 0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, + 0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, 0x467D86, 0x2D71E3, 0x9AC69B, + 0x006233, 0x7CD2B4, 0x97A7B4, 0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, + 0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, 0xCB2324, 0x778AD6, 0x23545A, + 0xB91F00, 0x1B0AF1, 0xDFCE19, 0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, + 0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, 0xDE3B58, 0x929BDE, 0x2822D2, + 0xE88628, 0x4D58E2, 0x32CAC6, 0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, + 0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, 0xD36710, 0xD8DDAA, 0x425FAE, + 0xCE616A, 0xA4280A, 0xB499D3, 0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, + 0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, 0x36D9CA, 0xD2A828, 0x8D61C2, + 0x77C912, 0x142604, 0x9B4612, 0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, + 0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, 0xC3E7B3, 0x28F8C7, 0x940593, + 0x3E71C1, 0xB3092E, 0xF3450B, 0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, + 0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, 0x9794E8, 0x84E6E2, 0x973199, + 0x6BED88, 0x365F5F, 0x0EFDBB, 0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, + 0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, 0x90AA47, 0x02E774, 0x24D6BD, + 0xA67DF7, 0x72486E, 0xEF169F, 0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, + 0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, 0x10D86D, 0x324832, 0x754C5B, + 0xD4714E, 0x6E5445, 0xC1090B, 0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, + 0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, 0x6AE290, 0x89D988, 0x50722C, + 0xBEA404, 0x940777, 0x7030F3, 0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, + 0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, 0x3BDF08, 0x2B3715, 0xA0805C, + 0x93805A, 0x921110, 0xD8E80F, 0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, + 0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, 0xAA140A, 0x2F2689, 0x768364, + 0x333B09, 0x1A940E, 0xAA3A51, 0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, + 0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, 0x5BC3D8, 0xC492F5, 0x4BADC6, + 0xA5CA4E, 0xCD37A7, 0x36A9E6, 0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, + 0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, 0x306529, 0xBF5657, 0x3AFF47, + 0xB9F96A, 0xF3BE75, 0xDF9328, 0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, + 0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, 0xA8654F, 0xA5C1D2, 0x0F3F0B, + 0xCD785B, 0x76F923, 0x048B7B, 0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, + 0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, 0xDA4886, 0xA05DF7, 0xF480C6, + 0x2FF0AC, 0x9AECDD, 0xBC5C3F, 0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, + 0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, 0x2A1216, 0x2DB7DC, 0xFDE5FA, + 0xFEDB89, 0xFDBE89, 0x6C76E4, 0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, + 0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, 0x48D784, 0x16DF30, 0x432DC7, + 0x356125, 0xCE70C9, 0xB8CB30, 0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, + 0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, 0xC4F133, 0x5F6E13, 0xE4305D, + 0xA92E85, 0xC3B21D, 0x3632A1, 0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, + 0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, 0xCBDA11, 0xD0BE7D, 0xC1DB9B, + 0xBD17AB, 0x81A2CA, 0x5C6A08, 0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, + 0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, 0x4F6A68, 0xA82A4A, 0x5AC44F, + 0xBCF82D, 0x985AD7, 0x95C7F4, 0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, + 0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, 0xD0C0B2, 0x485551, 0x0EFB1E, + 0xC37295, 0x3B06A3, 0x3540C0, 0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, + 0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, 0x3C3ABA, 0x461846, 0x5F7555, + 0xF5BDD2, 0xC6926E, 0x5D2EAC, 0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, + 0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, 0x745D7C, 0xB2AD6B, 0x9D6ECD, + 0x7B723E, 0x6A11C6, 0xA9CFF7, 0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, + 0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, 0xBEFDFD, 0xEF4556, 0x367ED9, + 0x13D9EC, 0xB9BA8B, 0xFC97C4, 0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, + 0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, 0x9C2A3E, 0xCC5F11, 0x4A0BFD, + 0xFBF4E1, 0x6D3B8E, 0x2C86E2, 0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, + 0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, 0xCC2254, 0xDC552A, 0xD6C6C0, + 0x96190B, 0xB8701A, 0x649569, 0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, + 0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, 0x9B5861, 0xBC57E1, 0xC68351, + 0x103ED8, 0x4871DD, 0xDD1C2D, 0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, + 0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, 0x382682, 0x9BE7CA, 0xA40D51, + 0xB13399, 0x0ED7A9, 0x480569, 0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, + 0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, 0x5FD45E, 0xA4677B, 0x7AACBA, + 0xA2F655, 0x23882B, 0x55BA41, 0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, + 0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, 0xAE5ADB, 0x86C547, 0x624385, + 0x3B8621, 0x94792C, 0x876110, 0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, + 0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, 0xB1933D, 0x0B7CBD, 0xDC51A4, + 0x63DD27, 0xDDE169, 0x19949A, 0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, + 0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, 0x4D7E6F, 0x5119A5, 0xABF9B5, + 0xD6DF82, 0x61DD96, 0x023616, 0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, 0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, ]; -const PIO2 : [f64; 8] = [ +const PIO2: [f64; 8] = [ 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ @@ -251,92 +210,91 @@ const PIO2 : [f64; 8] = [ /// more accurately, = 0 mod 8 ). Thus the number of operations are /// independent of the exponent of the input. #[inline] -pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) -> i32 { - let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 +pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { + let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) - + #[cfg(target_pointer_width = "64")] assert!(e0 <= 16360); - + let nx = x.len(); - - let mut fw : f64; - let mut n : i32; - let mut ih : i32; - let mut z : f64; - let mut f : [f64;20] = [0.;20]; - let mut fq : [f64;20] = [0.;20]; - let mut q : [f64;20] = [0.;20]; - let mut iq : [i32;20] = [0;20]; - + + let mut fw: f64; + let mut n: i32; + let mut ih: i32; + let mut z: f64; + let mut f: [f64; 20] = [0.; 20]; + let mut fq: [f64; 20] = [0.; 20]; + let mut q: [f64; 20] = [0.; 20]; + let mut iq: [i32; 20] = [0; 20]; + /* initialize jk*/ let jk = INIT_JK[prec]; let jp = jk; /* determine jx,jv,q0, note that 3>q0 */ - let jx = nx-1; - let mut jv = (e0-3)/24; + let jx = nx - 1; + let mut jv = (e0 - 3) / 24; if jv < 0 { - jv=0; + jv = 0; } - let mut q0 = e0-24*(jv+1); + let mut q0 = e0 - 24 * (jv + 1); let jv = jv as usize; /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ - let mut j = (jv-jx) as i32; - let m = jx+jk; + let mut j = (jv - jx) as i32; + let m = jx + jk; for i in 0..=m { - f[i] = if j<0 { - 0. - } else { - IPIO2[j as usize] as f64 - }; + f[i] = if j < 0 { 0. } else { IPIO2[j as usize] as f64 }; j += 1 } - + /* compute q[0],q[1],...q[jk] */ for i in 0..=jk { fw = 0f64; for j in 0..=jx { - fw += x[j]*f[jx+i-j]; + fw += x[j] * f[jx + i - j]; } q[i] = fw; } - + let mut jz = jk; - + 'recompute: loop { /* distill q[] into iq[] reversingly */ let mut i = 0i32; z = q[jz]; for j in (1..=jz).rev() { - fw = (x1p_24*z) as i32 as f64; - iq[i as usize] = (z - x1p24*fw) as i32; - z = q[j-1]+fw; + fw = (x1p_24 * z) as i32 as f64; + iq[i as usize] = (z - x1p24 * fw) as i32; + z = q[j - 1] + fw; i += 1; } - + /* compute n */ - z = scalbn(z, q0); /* actual value of z */ - z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */ - n = z as i32; + z = scalbn(z, q0); /* actual value of z */ + z -= 8.0 * floor(z * 0.125); /* trim off integer >= 8 */ + n = z as i32; z -= n as f64; ih = 0; - if q0 > 0 { /* need iq[jz-1] to determine n */ - i = iq[jz-1] >> (24-q0); + if q0 > 0 { + /* need iq[jz-1] to determine n */ + i = iq[jz - 1] >> (24 - q0); n += i; - iq[jz-1] -= i << (24-q0); - ih = iq[jz-1] >> (23-q0); + iq[jz - 1] -= i << (24 - q0); + ih = iq[jz - 1] >> (23 - q0); } else if q0 == 0 { - ih = iq[jz-1]>>23; + ih = iq[jz - 1] >> 23; } else if z >= 0.5 { ih = 2; } - - if ih > 0 { /* q > 0.5 */ + + if ih > 0 { + /* q > 0.5 */ n += 1; let mut carry = 0i32; - for i in 0..jz { /* compute 1-q */ + for i in 0..jz { + /* compute 1-q */ let j = iq[i]; if carry == 0 { if j != 0 { @@ -347,10 +305,15 @@ pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) iq[i] = 0xffffff - j; } } - if q0 > 0 { /* rare case: chance is 1 in 12 */ + if q0 > 0 { + /* rare case: chance is 1 in 12 */ match q0 { - 1 => { iq[jz-1] &= 0x7fffff; }, - 2 => { iq[jz-1] &= 0x3fffff; }, + 1 => { + iq[jz - 1] &= 0x7fffff; + } + 2 => { + iq[jz - 1] &= 0x3fffff; + } _ => {} } } @@ -361,24 +324,26 @@ pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) } } } - + /* check if recomputation is needed */ if z == 0. { let mut j = 0; - for i in (jk..=jz-1).rev() { + for i in (jk..=jz - 1).rev() { j |= iq[i]; } - if j == 0 { /* need recomputation */ + if j == 0 { + /* need recomputation */ let mut k = 1; - while iq[jk-k]==0 { - k += 1; /* k = no. of terms needed */ + while iq[jk - k] == 0 { + k += 1; /* k = no. of terms needed */ } - - for i in (jz+1)..=(jz+k) { /* add q[jz+1] to q[jz+k] */ - f[jx+i] = IPIO2[jv+i] as f64; + + for i in (jz + 1)..=(jz + k) { + /* add q[jz+1] to q[jz+k] */ + f[jx + i] = IPIO2[jv + i] as f64; fw = 0f64; for j in 0..=jx { - fw += x[j]*f[jx+i-j]; + fw += x[j] * f[jx + i - j]; } q[i] = fw; } @@ -389,7 +354,7 @@ pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) break; } - + /* chop off zero terms */ if z == 0. { jz -= 1; @@ -398,11 +363,12 @@ pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) jz -= 1; q0 -= 24; } - } else { /* break z into 24-bit if necessary */ + } else { + /* break z into 24-bit if necessary */ z = scalbn(z, -q0); if z >= x1p24 { - fw = (x1p_24*z) as i32 as f64; - iq[jz] = (z - x1p24*fw) as i32; + fw = (x1p_24 * z) as i32 as f64; + iq[jz] = (z - x1p24 * fw) as i32; jz += 1; q0 += 24; iq[jz] = fw as i32; @@ -410,25 +376,25 @@ pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) iq[jz] = z as i32; } } - + /* convert integer "bit" chunk to floating-point value */ fw = scalbn(1., q0); for i in (0..=jz).rev() { - q[i] = fw*(iq[i] as f64); + q[i] = fw * (iq[i] as f64); fw *= x1p_24; } - + /* compute PIo2[0,...,jp]*q[jz,...,0] */ for i in (0..=jz).rev() { fw = 0f64; let mut k = 0; - while (k <= jp) && (k <= jz-i) { - fw += PIO2[k]*q[i+k]; + while (k <= jp) && (k <= jz - i) { + fw += PIO2[k] * q[i + k]; k += 1; } - fq[jz-i] = fw; + fq[jz - i] = fw; } - + /* compress fq[] into y[] */ match prec { 0 => { @@ -437,7 +403,7 @@ pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) fw += fq[i]; } y[0] = if ih == 0 { fw } else { -fw }; - }, + } 1 | 2 => { fw = 0f64; for i in (0..=jz).rev() { @@ -446,38 +412,39 @@ pub(crate) fn rem_pio2_large(x : &[f64], y : &mut [f64], e0 : i32, prec : usize) // TODO: drop excess precision here once double_t is used fw = fw as f64; y[0] = if ih == 0 { fw } else { -fw }; - fw = fq[0]-fw; + fw = fq[0] - fw; for i in 1..=jz { fw += fq[i]; } y[1] = if ih == 0 { fw } else { -fw }; - }, - 3 => { /* painful */ + } + 3 => { + /* painful */ for i in (1..=jz).rev() { - fw = fq[i-1]+fq[i]; - fq[i] += fq[i-1]-fw; - fq[i-1] = fw; + fw = fq[i - 1] + fq[i]; + fq[i] += fq[i - 1] - fw; + fq[i - 1] = fw; } for i in (2..=jz).rev() { - fw = fq[i-1]+fq[i]; - fq[i] += fq[i-1]-fw; - fq[i-1] = fw; + fw = fq[i - 1] + fq[i]; + fq[i] += fq[i - 1] - fw; + fq[i - 1] = fw; } fw = 0f64; for i in (2..=jz).rev() { fw += fq[i]; } - if ih==0 { - y[0] = fq[0]; - y[1] = fq[1]; - y[2] = fw; + if ih == 0 { + y[0] = fq[0]; + y[1] = fq[1]; + y[2] = fw; } else { y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw; } - }, - _ => { unreachable!() } + } + _ => unreachable!(), } n & 7 } diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs index a908ccd9f7516..73ec3775d3dc5 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2f.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2f.rs @@ -2,40 +2,42 @@ use super::rem_pio2_large; use core::f64; -const TOINT : f64 = 1.5 / f64::EPSILON; +const TOINT: f64 = 1.5 / f64::EPSILON; /// 53 bits of 2/pi -const INV_PIO2 : f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ +const INV_PIO2: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ /// first 25 bits of pi/2 -const PIO2_1 : f64 = 1.57079631090164184570e+00; /* 0x3FF921FB, 0x50000000 */ +const PIO2_1: f64 = 1.57079631090164184570e+00; /* 0x3FF921FB, 0x50000000 */ /// pi/2 - pio2_1 -const PIO2_1T : f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ +const PIO2_1T: f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ /// Return the remainder of x rem pi/2 in *y /// /// use double precision for everything except passing x /// use __rem_pio2_large() for large x #[inline] -pub(crate) fn rem_pio2f(x : f32) -> (i32, f64) { +pub(crate) fn rem_pio2f(x: f32) -> (i32, f64) { let x64 = x as f64; - - let mut tx : [f64; 1] = [0.,]; - let mut ty : [f64; 1] = [0.,]; + + let mut tx: [f64; 1] = [0.]; + let mut ty: [f64; 1] = [0.]; let ix = x.to_bits() & 0x7fffffff; /* 25+53 bit pi is good enough for medium size */ - if ix < 0x4dc90fdb { /* |x| ~< 2^28*(pi/2), medium size */ + if ix < 0x4dc90fdb { + /* |x| ~< 2^28*(pi/2), medium size */ /* Use a specialized rint() to get fn. Assume round-to-nearest. */ - let f_n = x64*INV_PIO2 + TOINT - TOINT; - return (f_n as i32, x64 - f_n*PIO2_1 - f_n*PIO2_1T); + let f_n = x64 * INV_PIO2 + TOINT - TOINT; + return (f_n as i32, x64 - f_n * PIO2_1 - f_n * PIO2_1T); } - if ix>=0x7f800000 { /* x is inf or NaN */ - return (0, x64-x64); + if ix >= 0x7f800000 { + /* x is inf or NaN */ + return (0, x64 - x64); } /* scale x into [2^23, 2^24-1] */ let sign = (x.to_bits() >> 31) != 0; - let e0 = ((ix>>23) - (0x7f+23)) as i32; /* e0 = ilogb(|x|)-23, positive */ - tx[0] = f32::from_bits(ix - (e0<<23) as u32) as f64; + let e0 = ((ix >> 23) - (0x7f + 23)) as i32; /* e0 = ilogb(|x|)-23, positive */ + tx[0] = f32::from_bits(ix - (e0 << 23) as u32) as f64; let n = rem_pio2_large(&tx, &mut ty, e0, 0); if sign { return (-n, -ty[0]); From 137d99d55b781f49680de8993f1498bbb7cd5f1f Mon Sep 17 00:00:00 2001 From: Opal Date: Sat, 14 Jul 2018 18:28:11 +1200 Subject: [PATCH 0523/4206] Adding acos implementation --- library/compiler-builtins/libm/src/lib.rs | 2 - .../compiler-builtins/libm/src/math/acos.rs | 108 ++++++++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 10 +- .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 115 insertions(+), 7 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/acos.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 30f879769d0b0..9b3a6457f4abe 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -412,7 +412,6 @@ pub trait F64Ext: private::Sealed { #[cfg(todo)] fn asin(self) -> Self; - #[cfg(todo)] fn acos(self) -> Self; #[cfg(todo)] @@ -589,7 +588,6 @@ impl F64Ext for f64 { asin(self) } - #[cfg(todo)] #[inline] fn acos(self) -> Self { acos(self) diff --git a/library/compiler-builtins/libm/src/math/acos.rs b/library/compiler-builtins/libm/src/math/acos.rs new file mode 100644 index 0000000000000..276e361f3d5c2 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/acos.rs @@ -0,0 +1,108 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_acos.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* acos(x) + * Method : + * acos(x) = pi/2 - asin(x) + * acos(-x) = pi/2 + asin(x) + * For |x|<=0.5 + * acos(x) = pi/2 - (x + x*x^2*R(x^2)) (see asin.c) + * For x>0.5 + * acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2))) + * = 2asin(sqrt((1-x)/2)) + * = 2s + 2s*z*R(z) ...z=(1-x)/2, s=sqrt(z) + * = 2f + (2c + 2s*z*R(z)) + * where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term + * for f so that f+c ~ sqrt(z). + * For x<-0.5 + * acos(x) = pi - 2asin(sqrt((1-|x|)/2)) + * = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + * Function needed: sqrt + */ + +use super::sqrt; + +const PIO2_HI: f64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ +const PIO2_LO: f64 = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */ +const PS0: f64 = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */ +const PS1: f64 = -3.25565818622400915405e-01; /* 0xBFD4D612, 0x03EB6F7D */ +const PS2: f64 = 2.01212532134862925881e-01; /* 0x3FC9C155, 0x0E884455 */ +const PS3: f64 = -4.00555345006794114027e-02; /* 0xBFA48228, 0xB5688F3B */ +const PS4: f64 = 7.91534994289814532176e-04; /* 0x3F49EFE0, 0x7501B288 */ +const PS5: f64 = 3.47933107596021167570e-05; /* 0x3F023DE1, 0x0DFDF709 */ +const QS1: f64 = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */ +const QS2: f64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ +const QS3: f64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ +const QS4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +#[inline] +fn r(z: f64) -> f64 { + let p: f64 = z * (PS0 + z * (PS1 + z * (PS2 + z * (PS3 + z * (PS4 + z * PS5))))); + let q: f64 = 1.0 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4))); + return p / q; +} + +#[inline] +pub fn acos(x: f64) -> f64 { + let x1p_120f = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ -120 + let z: f64; + let w: f64; + let s: f64; + let c: f64; + let df: f64; + let hx: u32; + let ix: u32; + + hx = (x.to_bits() >> 32) as u32; + ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if ix >= 0x3ff00000 { + let lx: u32 = x.to_bits() as u32; + + if (ix - 0x3ff00000 | lx) == 0 { + /* acos(1)=0, acos(-1)=pi */ + if (hx >> 31) != 0 { + return 2. * PIO2_HI + x1p_120f; + } + return 0.; + } + return 0. / (x - x); + } + /* |x| < 0.5 */ + if ix < 0x3fe00000 { + if ix <= 0x3c600000 { + /* |x| < 2**-57 */ + return PIO2_HI + x1p_120f; + } + return PIO2_HI - (x - (PIO2_LO - x * r(x * x))); + } + /* x < -0.5 */ + if (hx >> 31) != 0 { + z = (1.0 + x) * 0.5; + s = sqrt(z); + w = r(z) * s - PIO2_LO; + return 2. * (PIO2_HI - (s + w)); + } + /* x > 0.5 */ + z = (1.0 - x) * 0.5; + s = sqrt(z); + // Set the low 4 bytes to zero + df = f64::from_bits(s.to_bits() & 0xff_ff_ff_ff_00_00_00_00); + + c = (z - df * df) / (s + df); + w = r(z) * s + c; + return 2. * (df + w); +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index fb5e3df90901d..f70555e9cc2a1 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -6,6 +6,7 @@ macro_rules! force_eval { }; } +mod acos; mod ceilf; mod expf; mod fabs; @@ -36,10 +37,11 @@ mod truncf; //mod service; pub use self::{ - ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmodf::fmodf, - hypot::hypot, hypotf::hypotf, log::log, log10::log10, log10f::log10f, log1p::log1p, - log1pf::log1pf, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, roundf::roundf, - scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, + acos::acos, ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, + fmodf::fmodf, hypot::hypot, hypotf::hypotf, log::log, log10::log10, log10f::log10f, + log1p::log1p, log1pf::log1pf, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, + roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, + truncf::truncf, }; fn isnanf(x: f32) -> bool { diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index be5ed0784f8b3..d48851a9e6300 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -696,7 +696,7 @@ f32i32_f32! { // With signature `fn(f64) -> f64` f64_f64! { - // acos, + acos, // asin, // atan, // cbrt, From a7c456363394954ef27cd3db80e476e7349518c0 Mon Sep 17 00:00:00 2001 From: C Jones Date: Sat, 14 Jul 2018 05:48:39 -0400 Subject: [PATCH 0524/4206] Use separate imports instead of {}-grouped imports for better merges Previously every merge would cause conflicts because the {}-group would re-flow, which the merge algorithm can't handle. This will hopefully make rebases and merges go more smoothly while everyone is still adding new modules. --- .../compiler-builtins/libm/src/math/mod.rs | 33 +++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index fb5e3df90901d..78f8991413bd2 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -35,12 +35,33 @@ mod truncf; //mod service; -pub use self::{ - ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmodf::fmodf, - hypot::hypot, hypotf::hypotf, log::log, log10::log10, log10f::log10f, log1p::log1p, - log1pf::log1pf, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, roundf::roundf, - scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, -}; +// Use separated imports instead of {}-grouped imports for easier merging. +pub use self::ceilf::ceilf; +pub use self::expf::expf; +pub use self::fabs::fabs; +pub use self::fabsf::fabsf; +pub use self::floor::floor; +pub use self::floorf::floorf; +pub use self::fmodf::fmodf; +pub use self::hypot::hypot; +pub use self::hypotf::hypotf; +pub use self::log::log; +pub use self::log10::log10; +pub use self::log10f::log10f; +pub use self::log1p::log1p; +pub use self::log1pf::log1pf; +pub use self::log2::log2; +pub use self::log2f::log2f; +pub use self::logf::logf; +pub use self::powf::powf; +pub use self::round::round; +pub use self::roundf::roundf; +pub use self::scalbn::scalbn; +pub use self::scalbnf::scalbnf; +pub use self::sqrt::sqrt; +pub use self::sqrtf::sqrtf; +pub use self::trunc::trunc; +pub use self::truncf::truncf; fn isnanf(x: f32) -> bool { x.to_bits() & 0x7fffffff > 0x7f800000 From 480531461c0ea0eb04cb66d83696323a25d0925a Mon Sep 17 00:00:00 2001 From: Jack Mott Date: Sat, 14 Jul 2018 05:35:07 -0500 Subject: [PATCH 0525/4206] fdimf --- library/compiler-builtins/libm/src/lib.rs | 7 +++++++ library/compiler-builtins/libm/src/math/fdimf.rs | 15 +++++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 10 ++++++---- .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fdimf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 30f879769d0b0..7d8ae903a12f6 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -42,6 +42,8 @@ pub trait F32Ext: private::Sealed { fn trunc(self) -> Self; + fn fdim(self, rhs: Self) -> Self; + #[cfg(todo)] fn fract(self) -> Self; @@ -156,6 +158,11 @@ impl F32Ext for f32 { truncf(self) } + #[inline] + fn fdim(self, rhs: Self) -> Self { + fdimf(self, rhs) + } + #[cfg(todo)] #[inline] fn fract(self) -> Self { diff --git a/library/compiler-builtins/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/src/math/fdimf.rs new file mode 100644 index 0000000000000..3cf65d9beeeff --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fdimf.rs @@ -0,0 +1,15 @@ +use super::isnanf; + +pub fn fdimf(x: f32, y: f32) -> f32 { + if isnanf(x) { + x + } else if isnanf(y) { + y + } else { + if x > y { + x - y + } else { + 0.0 + } + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index fb5e3df90901d..a9ba87aa2ce4a 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -10,6 +10,7 @@ mod ceilf; mod expf; mod fabs; mod fabsf; +mod fdimf; mod floor; mod floorf; mod fmodf; @@ -36,10 +37,11 @@ mod truncf; //mod service; pub use self::{ - ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmodf::fmodf, - hypot::hypot, hypotf::hypotf, log::log, log10::log10, log10f::log10f, log1p::log1p, - log1pf::log1pf, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, roundf::roundf, - scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, + ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, fdimf::fdimf, floor::floor, floorf::floorf, + fmodf::fmodf, hypot::hypot, hypotf::hypotf, log::log, log10::log10, log10f::log10f, + log1p::log1p, log1pf::log1pf, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, + roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, + truncf::truncf, }; fn isnanf(x: f32) -> bool { diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index be5ed0784f8b3..29529356247c2 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -662,7 +662,6 @@ f32_f32! { // coshf, // exp2f, expf, - // fdimf, log10f, log1pf, log2f, @@ -679,6 +678,7 @@ f32_f32! { // With signature `fn(f32, f32) -> f32` f32f32_f32! { // atan2f, + fdimf, hypotf, fmodf, powf, From 643287e1f15268cfa481e0cbd56e57b3f6772117 Mon Sep 17 00:00:00 2001 From: Jack Mott Date: Sat, 14 Jul 2018 06:20:13 -0500 Subject: [PATCH 0526/4206] fdim --- library/compiler-builtins/libm/src/lib.rs | 6 ++++++ library/compiler-builtins/libm/src/math/fdim.rs | 15 +++++++++++++++ library/compiler-builtins/libm/src/math/fdimf.rs | 6 +++--- library/compiler-builtins/libm/src/math/fmodf.rs | 5 ++--- library/compiler-builtins/libm/src/math/mod.rs | 15 ++++++--------- .../libm/test-generator/src/main.rs | 2 +- 6 files changed, 33 insertions(+), 16 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fdim.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 7d8ae903a12f6..df96aadc725b4 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -363,6 +363,8 @@ pub trait F64Ext: private::Sealed { fn trunc(self) -> Self; + fn fdim(self, rhs: Self) -> Self; + #[cfg(todo)] fn fract(self) -> Self; @@ -480,6 +482,10 @@ impl F64Ext for f64 { trunc(self) } + #[inline] + fn fdim(self, rhs: Self) -> Self { + fdim(self, rhs) + } #[cfg(todo)] #[inline] fn fract(self) -> Self { diff --git a/library/compiler-builtins/libm/src/math/fdim.rs b/library/compiler-builtins/libm/src/math/fdim.rs new file mode 100644 index 0000000000000..2b277eab03e18 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fdim.rs @@ -0,0 +1,15 @@ +use core::f64; + +pub fn fdim(x: f64, y: f64) -> f64 { + if x.is_nan() { + x + } else if y.is_nan() { + y + } else { + if x > y { + x - y + } else { + 0.0 + } + } +} diff --git a/library/compiler-builtins/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/src/math/fdimf.rs index 3cf65d9beeeff..44bf2d6806ef3 100644 --- a/library/compiler-builtins/libm/src/math/fdimf.rs +++ b/library/compiler-builtins/libm/src/math/fdimf.rs @@ -1,9 +1,9 @@ -use super::isnanf; +use core::f32; pub fn fdimf(x: f32, y: f32) -> f32 { - if isnanf(x) { + if x.is_nan() { x - } else if isnanf(y) { + } else if y.is_nan() { y } else { if x > y { diff --git a/library/compiler-builtins/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs index 9097752490854..d84cfeb01b831 100644 --- a/library/compiler-builtins/libm/src/math/fmodf.rs +++ b/library/compiler-builtins/libm/src/math/fmodf.rs @@ -1,7 +1,6 @@ +use core::f32; use core::u32; -use super::isnanf; - #[inline] pub fn fmodf(x: f32, y: f32) -> f32 { let mut uxi = x.to_bits(); @@ -11,7 +10,7 @@ pub fn fmodf(x: f32, y: f32) -> f32 { let sx = uxi & 0x80000000; let mut i; - if uyi << 1 == 0 || isnanf(y) || ex == 0xff { + if uyi << 1 == 0 || y.is_nan() || ex == 0xff { return (x * y) / (x * y); } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index a9ba87aa2ce4a..e526314a66736 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -10,6 +10,7 @@ mod ceilf; mod expf; mod fabs; mod fabsf; +mod fdim; mod fdimf; mod floor; mod floorf; @@ -37,13 +38,9 @@ mod truncf; //mod service; pub use self::{ - ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, fdimf::fdimf, floor::floor, floorf::floorf, - fmodf::fmodf, hypot::hypot, hypotf::hypotf, log::log, log10::log10, log10f::log10f, - log1p::log1p, log1pf::log1pf, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, - roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, - truncf::truncf, + ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, fdim::fdim, fdimf::fdimf, floor::floor, + floorf::floorf, fmodf::fmodf, hypot::hypot, hypotf::hypotf, log::log, log10::log10, + log10f::log10f, log1p::log1p, log1pf::log1pf, log2::log2, log2f::log2f, logf::logf, powf::powf, + round::round, roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, + trunc::trunc, truncf::truncf, }; - -fn isnanf(x: f32) -> bool { - x.to_bits() & 0x7fffffff > 0x7f800000 -} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 29529356247c2..bf679ca641919 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -724,7 +724,7 @@ f64_f64! { // With signature `fn(f64, f64) -> f64` f64f64_f64! { // atan2, - // fdim, + fdim, // fmod, hypot, // pow, From 5c2409fcca9e91f862b7f061e253e72270d8505c Mon Sep 17 00:00:00 2001 From: Lucas Marques Date: Sat, 14 Jul 2018 00:23:58 -0300 Subject: [PATCH 0527/4206] implement ceil --- library/compiler-builtins/libm/src/lib.rs | 2 - .../compiler-builtins/libm/src/math/ceil.rs | 39 +++++++++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 10 +++-- 3 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/ceil.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 30f879769d0b0..5af219fccf924 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -349,7 +349,6 @@ impl F32Ext for f32 { pub trait F64Ext: private::Sealed { fn floor(self) -> Self; - #[cfg(todo)] fn ceil(self) -> Self; fn round(self) -> Self; @@ -457,7 +456,6 @@ impl F64Ext for f64 { floor(self) } - #[cfg(todo)] #[inline] fn ceil(self) -> Self { ceil(self) diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs new file mode 100644 index 0000000000000..4db2ca8403682 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -0,0 +1,39 @@ +use core::f64; + +const TOINT: f64 = 1. / f64::EPSILON; + +#[inline] +pub fn ceil(x: f64) -> f64 { + let u: u64 = x.to_bits(); + let e: i64 = (u >> 52 & 0x7ff) as i64; + let y: f64; + + if e >= 0x3ff + 52 || x == 0. { + return x; + } + // y = int(x) - x, where int(x) is an integer neighbor of x + y = if (u >> 63) != 0 { + x - TOINT + TOINT - x + } else { + x + TOINT - TOINT - x + }; + // special case because of non-nearest rounding modes + if e <= 0x3ff - 1 { + force_eval!(y); + return if (u >> 63) != 0 { -0. } else { 1. }; + } + if y < 0. { + x + y + 1. + } else { + x + y + } +} + +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::ceil(1.1), 2.0); + assert_eq!(super::ceil(2.9), 3.0); + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index fb5e3df90901d..7c676095dc9f6 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -6,6 +6,7 @@ macro_rules! force_eval { }; } +mod ceil; mod ceilf; mod expf; mod fabs; @@ -36,10 +37,11 @@ mod truncf; //mod service; pub use self::{ - ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmodf::fmodf, - hypot::hypot, hypotf::hypotf, log::log, log10::log10, log10f::log10f, log1p::log1p, - log1pf::log1pf, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, roundf::roundf, - scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, + ceil::ceil, ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, + fmodf::fmodf, hypot::hypot, hypotf::hypotf, log::log, log10::log10, log10f::log10f, + log1p::log1p, log1pf::log1pf, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, + roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, + truncf::truncf, }; fn isnanf(x: f32) -> bool { From 42e52da01052183a7c8f09e13e7d209bdd7e09c9 Mon Sep 17 00:00:00 2001 From: Lucas Marques Date: Sat, 14 Jul 2018 00:41:03 -0300 Subject: [PATCH 0528/4206] enable test generation for ceil --- library/compiler-builtins/libm/test-generator/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index be5ed0784f8b3..d386da9f650ff 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -700,7 +700,7 @@ f64_f64! { // asin, // atan, // cbrt, - // ceil, + ceil, // cos, // cosh, // exp, From 3a15b30d164cbc5d85d3b4f90c69cae06d2ebdc2 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 14 Jul 2018 18:31:28 +0200 Subject: [PATCH 0529/4206] Implement cosh, exp and expm1 --- .../compiler-builtins/libm/src/math/cosh.rs | 54 ++++++++ .../compiler-builtins/libm/src/math/exp.rs | 84 ++++++++++++ .../compiler-builtins/libm/src/math/expm1.rs | 124 ++++++++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 12 +- .../libm/test-generator/src/main.rs | 6 +- 5 files changed, 273 insertions(+), 7 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/cosh.rs create mode 100644 library/compiler-builtins/libm/src/math/exp.rs create mode 100644 library/compiler-builtins/libm/src/math/expm1.rs diff --git a/library/compiler-builtins/libm/src/math/cosh.rs b/library/compiler-builtins/libm/src/math/cosh.rs new file mode 100644 index 0000000000000..ce541ce148964 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/cosh.rs @@ -0,0 +1,54 @@ +use core::f64; + +use super::exp; +use super::expm1; + +pub fn cosh(mut x: f64) -> f64 { + let t: f64; + /* |x| */ + let mut ui = x.to_bits(); + ui &= !0u64; + x = f64::from_bits(ui); + let w = (ui >> 32) as u32; + + /* |x| < log(2) */ + if w < 0x3fe62e42 { + if w < 0x3ff00000 - (26 << 20) { + /* raise inexact if x!=0 */ + force_eval!(x + f64::from_bits(0x4770000000000000)); + return 1.0; + } + let t = expm1(x); + return 1.0 + t * t / (2.0 * (1.0 + t)); + } + + /* |x| < log(DBL_MAX) */ + if w < 0x40862e42 { + t = exp(x); + /* note: if x>log(0x1p26) then the 1/t is not needed */ + return 0.5 * (t + 1.0 / t); + } + + /* |x| > log(DBL_MAX) or nan */ + /* note: the result is stored to handle overflow */ + t = __expo2(x); + return t; +} + +const K: u32 = 2043; + +pub fn __expo2(x: f64) -> f64 { + let kln2 = f64::from_bits(0x40962066151add8b); + /* note that k is odd and scale*scale overflows */ + let scale = f64::from_bits(((0x3ff + K / 2) << 20) as u64); + /* exp(x - k ln2) * 2**(k-1) */ + return exp(x - kln2) * scale * scale; +} + +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::cosh(1.1), 1.6685185538222564); + } +} diff --git a/library/compiler-builtins/libm/src/math/exp.rs b/library/compiler-builtins/libm/src/math/exp.rs new file mode 100644 index 0000000000000..870bf60853f55 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/exp.rs @@ -0,0 +1,84 @@ +use super::scalbn; + +const HALF: [f64; 2] = [0.5, -0.5]; +const LN2_HI: f64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ +const LN2_LO: f64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ +const INV_LN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */ +const P1: f64 = 1.66666666666666019037e-01; /* 0x3FC55555, 0x5555553E */ +const P2: f64 = -2.77777777770155933842e-03; /* 0xBF66C16C, 0x16BEBD93 */ +const P3: f64 = 6.61375632143793436117e-05; /* 0x3F11566A, 0xAF25DE2C */ +const P4: f64 = -1.65339022054652515390e-06; /* 0xBEBBBD41, 0xC5D26BF1 */ +const P5: f64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ + +#[inline] +pub fn exp(mut x: f64) -> f64 { + let mut hx: u32 = (x.to_bits() >> 32) as u32; + let sign = (hx >> 31) as i32; /* sign bit of x */ + hx &= 0x7fffffff; /* high word of |x| */ + + /* special cases */ + if hx >= 0x4086232b { + /* if |x| >= 708.39... */ + if x.is_nan() { + return x; + } + if x > 709.782712893383973096 { + /* overflow if x!=inf */ + x *= f64::from_bits(0x7fe0000000000000); + return x; + } + if x < -708.39641853226410622 { + /* underflow if x!=-inf */ + force_eval!((f64::from_bits(0xb6a0000000000000) / x) as f32); + if x < -745.13321910194110842 { + return 0.0; + } + } + } + + /* argument reduction */ + let k: i32; + let hi: f64; + let lo: f64; + if hx > 0x3fd62e42 { + /* if |x| > 0.5 ln2 */ + /* if |x| > 0.5 ln2 */ + if hx > 0x3ff0a2b2 { + /* if |x| > 1.5 ln2 */ + k = (INV_LN2 * x + HALF[sign as usize]) as i32; + } else { + k = 1 - sign - sign; + } + let kf = k as f64; + hi = x - kf * LN2_HI; /* k*ln2hi is exact here */ + lo = kf * LN2_LO; + x = hi - lo; + } else if hx > 0x3e300000 { + /* |x| > 2**-14 */ + k = 0; + hi = x; + lo = 0.0; + } else { + /* raise inexact */ + force_eval!(f64::from_bits(0x7fe0000000000000) + x); + return 1.0 + x; + } + + /* x is now in primary range */ + let xx = x * x; + let c = x - xx * (P1 + xx * (P2 + xx * (P3 + xx * (P4 + xx * P5)))); + let y = 1.0 + (x * c / (2.0 - c) - lo + hi); + if k == 0 { + y + } else { + scalbn(y, k) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::exp(1.1), 3.0041660239464334); + } +} diff --git a/library/compiler-builtins/libm/src/math/expm1.rs b/library/compiler-builtins/libm/src/math/expm1.rs new file mode 100644 index 0000000000000..2fc230b05f93c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/expm1.rs @@ -0,0 +1,124 @@ +use core::f64; + +const O_THRESHOLD: f64 = 7.09782712893383973096e+02; /* 0x40862E42, 0xFEFA39EF */ +const LN2_HI: f64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ +const LN2_LO: f64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ +const INVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */ +/* Scaled Q's: Qn_here = 2**n * Qn_above, for R(2*z) where z = hxs = x*x/2: */ +const Q1: f64 = -3.33333333333331316428e-02; /* BFA11111 111110F4 */ +const Q2: f64 = 1.58730158725481460165e-03; /* 3F5A01A0 19FE5585 */ +const Q3: f64 = -7.93650757867487942473e-05; /* BF14CE19 9EAADBB7 */ +const Q4: f64 = 4.00821782732936239552e-06; /* 3ED0CFCA 86E65239 */ +const Q5: f64 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ + +pub fn expm1(mut x: f64) -> f64 { + let hi: f64; + let lo: f64; + let k: i32; + let c: f64; + let mut t: f64; + let mut y: f64; + + let mut ui = x.to_bits() >> 32; + let hx = ui & 0x7fffffff; + let sign = (ui >> 63) as i32; + + /* filter out huge and non-finite argument */ + if hx >= 0x4043687A { + /* if |x|>=56*ln2 */ + if x.is_nan() { + return x; + } + if sign != 0 { + return -1.0; + } + if x > O_THRESHOLD { + x *= f64::from_bits(0x7fe0000000000000); + return x; + } + } + + /* argument reduction */ + if hx > 0x3fd62e42 { + /* if |x| > 0.5 ln2 */ + if hx < 0x3FF0A2B2 { + /* and |x| < 1.5 ln2 */ + if sign == 0 { + hi = x - LN2_HI; + lo = LN2_LO; + k = 1; + } else { + hi = x + LN2_HI; + lo = -LN2_LO; + k = -1; + } + } else { + k = (INVLN2 * x + if sign != 0 { -0.5 } else { 0.5 }) as i32; + t = k as f64; + hi = x - t * LN2_HI; /* t*ln2_hi is exact here */ + lo = t * LN2_LO; + } + x = hi - lo; + c = (hi - x) - lo; + } else if hx < 0x3c900000 { + /* |x| < 2**-54, return x */ + if hx < 0x00100000 { + force_eval!(x as f32); + } + return x; + } else { + c = 0.0; + k = 0; + } + + /* x is now in primary range */ + let hfx = 0.5 * x; + let hxs = x * hfx; + let r1 = 1.0 + hxs * (Q1 + hxs * (Q2 + hxs * (Q3 + hxs * (Q4 + hxs * Q5)))); + t = 3.0 - r1 * hfx; + let mut e = hxs * ((r1 - t) / (6.0 - x * t)); + if k == 0 { + /* c is 0 */ + return x - (x * e - hxs); + } + e = x * (e - c) - c; + e -= hxs; + /* exp(x) ~ 2^k (x_reduced - e + 1) */ + if k == -1 { + return 0.5 * (x - e) - 0.5; + } + if k == 1 { + if x < -0.25 { + return -2.0 * (e - (x + 0.5)); + } + return 1.0 + 2.0 * (x - e); + } + ui = ((0x3ff + k) as u64) << 52; /* 2^k */ + let twopk = f64::from_bits(ui); + if k < 0 || k > 56 { + /* suffice to return exp(x)-1 */ + y = x - e + 1.0; + if k == 1024 { + y = y * 2.0 * f64::from_bits(0x7fe0000000000000); + } else { + y = y * twopk; + } + return y - 1.0; + } + ui = ((0x3ff - k) as u64) << 52; /* 2^-k */ + let uf = f64::from_bits(ui); + if k < 20 { + y = (x - e + (1.0 - uf)) * twopk; + } else { + y = (x - (e + uf) + 1.0) * twopk; + } + y +} + +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::expm1(1.1), 2.0041660239464334); + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index fb5e3df90901d..b4f12b67df8f6 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -7,7 +7,10 @@ macro_rules! force_eval { } mod ceilf; +mod cosh; +mod exp; mod expf; +mod expm1; mod fabs; mod fabsf; mod floor; @@ -36,10 +39,11 @@ mod truncf; //mod service; pub use self::{ - ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, floor::floor, floorf::floorf, fmodf::fmodf, - hypot::hypot, hypotf::hypotf, log::log, log10::log10, log10f::log10f, log1p::log1p, - log1pf::log1pf, log2::log2, log2f::log2f, logf::logf, powf::powf, round::round, roundf::roundf, - scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, + ceilf::ceilf, cosh::cosh, exp::exp, expf::expf, expm1::expm1, fabs::fabs, fabsf::fabsf, + floor::floor, floorf::floorf, fmodf::fmodf, hypot::hypot, hypotf::hypotf, log::log, + log10::log10, log10f::log10f, log1p::log1p, log1pf::log1pf, log2::log2, log2f::log2f, + logf::logf, powf::powf, round::round, roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, + sqrt::sqrt, sqrtf::sqrtf, trunc::trunc, truncf::truncf, }; fn isnanf(x: f32) -> bool { diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index be5ed0784f8b3..b4f11dc1c8bec 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -702,10 +702,10 @@ f64_f64! { // cbrt, // ceil, // cos, - // cosh, - // exp, + cosh, + exp, // exp2, - // expm1, + expm1, floor, log, log10, From 8f93f401810f5f8c3d67d59ca5558b4573006380 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 14 Jul 2018 18:45:54 +0200 Subject: [PATCH 0530/4206] add lib.rs changes --- library/compiler-builtins/libm/src/lib.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 30f879769d0b0..2ef2092e7cf8e 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -381,7 +381,6 @@ pub trait F64Ext: private::Sealed { fn sqrt(self) -> Self; - #[cfg(todo)] fn exp(self) -> Self; #[cfg(todo)] @@ -427,7 +426,6 @@ pub trait F64Ext: private::Sealed { (self.sin(), self.cos()) } - #[cfg(todo)] fn exp_m1(self) -> Self; fn ln_1p(self) -> Self; @@ -435,7 +433,6 @@ pub trait F64Ext: private::Sealed { #[cfg(todo)] fn sinh(self) -> Self; - #[cfg(todo)] fn cosh(self) -> Self; #[cfg(todo)] @@ -522,7 +519,6 @@ impl F64Ext for f64 { sqrt(self) } - #[cfg(todo)] #[inline] fn exp(self) -> Self { exp(self) @@ -607,7 +603,6 @@ impl F64Ext for f64 { atan2(self, other) } - #[cfg(todo)] #[inline] fn exp_m1(self) -> Self { expm1(self) @@ -624,7 +619,6 @@ impl F64Ext for f64 { sinh(self) } - #[cfg(todo)] #[inline] fn cosh(self) -> Self { cosh(self) From 6d5a9699c2c069d324072c90c8b7aa4ccb62ff24 Mon Sep 17 00:00:00 2001 From: Jack Mott Date: Sat, 14 Jul 2018 11:51:46 -0500 Subject: [PATCH 0531/4206] fix rebase merge --- library/compiler-builtins/libm/src/math/mod.rs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 21bd7a480b5fc..324220a35984f 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -42,6 +42,8 @@ pub use self::cosf::cosf; pub use self::expf::expf; pub use self::fabs::fabs; pub use self::fabsf::fabsf; +pub use self::fdim::fdim; +pub use self::fdimf::fdimf; pub use self::floor::floor; pub use self::floorf::floorf; pub use self::fmodf::fmodf; @@ -65,20 +67,9 @@ pub use self::sqrtf::sqrtf; pub use self::trunc::trunc; pub use self::truncf::truncf; -pub use self::{ - ceilf::ceilf, expf::expf, fabs::fabs, fabsf::fabsf, fdim::fdim, fdimf::fdimf, floor::floor, - floorf::floorf, fmodf::fmodf, hypot::hypot, hypotf::hypotf, log::log, log10::log10, - log10f::log10f, log1p::log1p, log1pf::log1pf, log2::log2, log2f::log2f, logf::logf, powf::powf, - round::round, roundf::roundf, scalbn::scalbn, scalbnf::scalbnf, sqrt::sqrt, sqrtf::sqrtf, - trunc::trunc, truncf::truncf, -}; mod k_cosf; mod k_sinf; mod rem_pio2_large; mod rem_pio2f; use self::{k_cosf::k_cosf, k_sinf::k_sinf, rem_pio2_large::rem_pio2_large, rem_pio2f::rem_pio2f}; - -fn isnanf(x: f32) -> bool { - x.to_bits() & 0x7fffffff > 0x7f800000 -} From 92b7592ba28569f3cd64063e174e83cc97fa1194 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 14 Jul 2018 19:14:56 +0200 Subject: [PATCH 0532/4206] add missing bitshift for __expo2 and move it into its own module --- library/compiler-builtins/libm/src/math/cosh.rs | 13 ++----------- library/compiler-builtins/libm/src/math/k_expo2.rs | 12 ++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 8 ++++++-- 3 files changed, 20 insertions(+), 13 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/k_expo2.rs diff --git a/library/compiler-builtins/libm/src/math/cosh.rs b/library/compiler-builtins/libm/src/math/cosh.rs index ce541ce148964..e76edca03799c 100644 --- a/library/compiler-builtins/libm/src/math/cosh.rs +++ b/library/compiler-builtins/libm/src/math/cosh.rs @@ -2,6 +2,7 @@ use core::f64; use super::exp; use super::expm1; +use super::k_expo2; pub fn cosh(mut x: f64) -> f64 { let t: f64; @@ -31,20 +32,10 @@ pub fn cosh(mut x: f64) -> f64 { /* |x| > log(DBL_MAX) or nan */ /* note: the result is stored to handle overflow */ - t = __expo2(x); + t = k_expo2(x); return t; } -const K: u32 = 2043; - -pub fn __expo2(x: f64) -> f64 { - let kln2 = f64::from_bits(0x40962066151add8b); - /* note that k is odd and scale*scale overflows */ - let scale = f64::from_bits(((0x3ff + K / 2) << 20) as u64); - /* exp(x - k ln2) * 2**(k-1) */ - return exp(x - kln2) * scale * scale; -} - #[cfg(test)] mod tests { #[test] diff --git a/library/compiler-builtins/libm/src/math/k_expo2.rs b/library/compiler-builtins/libm/src/math/k_expo2.rs new file mode 100644 index 0000000000000..c67a86550e665 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_expo2.rs @@ -0,0 +1,12 @@ +use super::exp; + +const K: u32 = 2043; +const KLN2: f64 = 1416.0996898839683; + +#[inline] +pub(crate) fn k_expo2(x: f64) -> f64 { + /* note that k is odd and scale*scale overflows */ + let scale = f64::from_bits((((0x3ff + K / 2) << 20) as u64) << 32); + /* exp(x - k ln2) * 2**(k-1) */ + return exp(x - KLN2) * scale * scale; +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 67f482a6f560a..d9e37ee3a6d8f 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -43,8 +43,8 @@ pub use self::ceil::ceil; pub use self::ceilf::ceilf; pub use self::cosf::cosf; pub use self::cosh::cosh; -pub use self::expf::expf; pub use self::exp::exp; +pub use self::expf::expf; pub use self::expm1::expm1; pub use self::fabs::fabs; pub use self::fabsf::fabsf; @@ -72,11 +72,15 @@ pub use self::trunc::trunc; pub use self::truncf::truncf; mod k_cosf; +mod k_expo2; mod k_sinf; mod rem_pio2_large; mod rem_pio2f; -use self::{k_cosf::k_cosf, k_sinf::k_sinf, rem_pio2_large::rem_pio2_large, rem_pio2f::rem_pio2f}; +use self::{ + k_cosf::k_cosf, k_expo2::k_expo2, k_sinf::k_sinf, rem_pio2_large::rem_pio2_large, + rem_pio2f::rem_pio2f, +}; fn isnanf(x: f32) -> bool { x.to_bits() & 0x7fffffff > 0x7f800000 From 722e2e32cce55d857432e823a62fb46652f01b4c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 14 Jul 2018 12:20:10 -0500 Subject: [PATCH 0533/4206] ci: don't test the master master --- library/compiler-builtins/libm/.travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/libm/.travis.yml b/library/compiler-builtins/libm/.travis.yml index 2bbb60fc64d19..223b586ea6daf 100644 --- a/library/compiler-builtins/libm/.travis.yml +++ b/library/compiler-builtins/libm/.travis.yml @@ -35,6 +35,5 @@ before_cache: branches: only: - - master - staging - trying From 08dabf5dca8a182de50c74f39a237b05d8b4a4f7 Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 14 Jul 2018 02:50:23 -0400 Subject: [PATCH 0534/4206] implement exp --- library/compiler-builtins/libm/src/lib.rs | 2 - .../compiler-builtins/libm/src/math/exp.rs | 150 ++++++++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 2 + .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 153 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/exp.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 9095fd892a62e..f112aaaca6b1f 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -378,7 +378,6 @@ pub trait F64Ext: private::Sealed { fn sqrt(self) -> Self; - #[cfg(todo)] fn exp(self) -> Self; #[cfg(todo)] @@ -518,7 +517,6 @@ impl F64Ext for f64 { sqrt(self) } - #[cfg(todo)] #[inline] fn exp(self) -> Self { exp(self) diff --git a/library/compiler-builtins/libm/src/math/exp.rs b/library/compiler-builtins/libm/src/math/exp.rs new file mode 100644 index 0000000000000..cd63b8fb3f159 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/exp.rs @@ -0,0 +1,150 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_exp.c */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* exp(x) + * Returns the exponential of x. + * + * Method + * 1. Argument reduction: + * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658. + * Given x, find r and integer k such that + * + * x = k*ln2 + r, |r| <= 0.5*ln2. + * + * Here r will be represented as r = hi-lo for better + * accuracy. + * + * 2. Approximation of exp(r) by a special rational function on + * the interval [0,0.34658]: + * Write + * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ... + * We use a special Remez algorithm on [0,0.34658] to generate + * a polynomial of degree 5 to approximate R. The maximum error + * of this polynomial approximation is bounded by 2**-59. In + * other words, + * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5 + * (where z=r*r, and the values of P1 to P5 are listed below) + * and + * | 5 | -59 + * | 2.0+P1*z+...+P5*z - R(z) | <= 2 + * | | + * The computation of exp(r) thus becomes + * 2*r + * exp(r) = 1 + ---------- + * R(r) - r + * r*c(r) + * = 1 + r + ----------- (for better accuracy) + * 2 - c(r) + * where + * 2 4 10 + * c(r) = r - (P1*r + P2*r + ... + P5*r ). + * + * 3. Scale back to obtain exp(x): + * From step 1, we have + * exp(x) = 2^k * exp(r) + * + * Special cases: + * exp(INF) is INF, exp(NaN) is NaN; + * exp(-INF) is 0, and + * for finite argument, only exp(0)=1 is exact. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Misc. info. + * For IEEE double + * if x > 709.782712893383973096 then exp(x) overflows + * if x < -745.133219101941108420 then exp(x) underflows + */ + +use super::scalbn; + +const HALF: [f64; 2] = [0.5, -0.5]; +const LN2HI: f64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ +const LN2LO: f64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ +const INVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */ +const P1: f64 = 1.66666666666666019037e-01; /* 0x3FC55555, 0x5555553E */ +const P2: f64 = -2.77777777770155933842e-03; /* 0xBF66C16C, 0x16BEBD93 */ +const P3: f64 = 6.61375632143793436117e-05; /* 0x3F11566A, 0xAF25DE2C */ +const P4: f64 = -1.65339022054652515390e-06; /* 0xBEBBBD41, 0xC5D26BF1 */ +const P5: f64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ + +#[inline] +pub fn exp(mut x: f64) -> f64 { + let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 + let x1p_149 = f64::from_bits(0x36a0000000000000); // 0x1p-149 === 2 ^ -149 + + let hi: f64; + let lo: f64; + let c: f64; + let xx: f64; + let y: f64; + let k: i32; + let sign: i32; + let mut hx: u32; + + hx = (x.to_bits() >> 32) as u32; + sign = (hx >> 31) as i32; + hx &= 0x7fffffff; /* high word of |x| */ + + /* special cases */ + if hx >= 0x4086232b { + /* if |x| >= 708.39... */ + if x.is_nan() { + return x; + } + if x > 709.782712893383973096 { + /* overflow if x!=inf */ + x *= x1p1023; + return x; + } + if x < -708.39641853226410622 { + /* underflow if x!=-inf */ + force_eval!((-x1p_149 / x) as f32); + if x < -745.13321910194110842 { + return 0.; + } + } + } + + /* argument reduction */ + if hx > 0x3fd62e42 { + /* if |x| > 0.5 ln2 */ + if hx >= 0x3ff0a2b2 { + /* if |x| >= 1.5 ln2 */ + k = (INVLN2 * x + HALF[sign as usize]) as i32; + } else { + k = 1 - sign - sign; + } + hi = x - k as f64 * LN2HI; /* k*ln2hi is exact here */ + lo = k as f64 * LN2LO; + x = hi - lo; + } else if hx > 0x3e300000 { + /* if |x| > 2**-28 */ + k = 0; + hi = x; + lo = 0.; + } else { + /* inexact if x!=0 */ + force_eval!(x1p1023 + x); + return 1. + x; + } + + /* x is now in primary range */ + xx = x * x; + c = x - xx * (P1 + xx * (P2 + xx * (P3 + xx * (P4 + xx * P5)))); + y = 1. + (x * c / (2. - c) - lo + hi); + if k == 0 { + y + } else { + scalbn(y, k) + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index ee846ebb9ccc2..2a84b463d9fd1 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -9,6 +9,7 @@ macro_rules! force_eval { mod ceil; mod ceilf; mod cosf; +mod exp; mod expf; mod fabs; mod fabsf; @@ -39,6 +40,7 @@ mod truncf; pub use self::ceil::ceil; pub use self::ceilf::ceilf; pub use self::cosf::cosf; +pub use self::exp::exp; pub use self::expf::expf; pub use self::fabs::fabs; pub use self::fabsf::fabsf; diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 291c30f6394f5..a54d8b2710f54 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -703,7 +703,7 @@ f64_f64! { ceil, // cos, // cosh, - // exp, + exp, // exp2, // expm1, floor, From e22803605379ea10989050707a6a30d02ab8a141 Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 14 Jul 2018 14:07:14 -0400 Subject: [PATCH 0535/4206] implement cbrt and cbrtf --- library/compiler-builtins/libm/src/lib.rs | 4 - .../compiler-builtins/libm/src/math/cbrt.rs | 110 ++++++++++++++++++ .../compiler-builtins/libm/src/math/cbrtf.rs | 72 ++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 4 + .../libm/test-generator/src/main.rs | 4 +- 5 files changed, 188 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/cbrt.rs create mode 100644 library/compiler-builtins/libm/src/math/cbrtf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index f112aaaca6b1f..b175f6864117b 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -79,7 +79,6 @@ pub trait F32Ext: private::Sealed { fn log10(self) -> Self; - #[cfg(todo)] fn cbrt(self) -> Self; fn hypot(self, other: Self) -> Self; @@ -234,7 +233,6 @@ impl F32Ext for f32 { log10f(self) } - #[cfg(todo)] #[inline] fn cbrt(self) -> Self { cbrtf(self) @@ -391,7 +389,6 @@ pub trait F64Ext: private::Sealed { fn log10(self) -> Self; - #[cfg(todo)] fn cbrt(self) -> Self; fn hypot(self, other: Self) -> Self; @@ -548,7 +545,6 @@ impl F64Ext for f64 { log10(self) } - #[cfg(todo)] #[inline] fn cbrt(self) -> Self { cbrt(self) diff --git a/library/compiler-builtins/libm/src/math/cbrt.rs b/library/compiler-builtins/libm/src/math/cbrt.rs new file mode 100644 index 0000000000000..8c37f0b266b8c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/cbrt.rs @@ -0,0 +1,110 @@ +/* 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 */ + +#[inline] +pub fn cbrt(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/cbrtf.rs b/library/compiler-builtins/libm/src/math/cbrtf.rs new file mode 100644 index 0000000000000..878372eefbf83 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/cbrtf.rs @@ -0,0 +1,72 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrtf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ +/* cbrtf(x) + * Return cube root of x + */ + +use core::f32; + +const B1: u32 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */ +const B2: u32 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */ + +#[inline] +pub fn cbrtf(x: f32) -> f32 { + let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 + + let mut r: f64; + let mut t: f64; + let mut ui: u32 = x.to_bits(); + let mut hx: u32 = ui & 0x7fffffff; + + if hx >= 0x7f800000 { + /* cbrt(NaN,INF) is itself */ + return x + x; + } + + /* rough cbrt to 5 bits */ + if hx < 0x00800000 { + /* zero or subnormal? */ + if hx == 0 { + return x; /* cbrt(+-0) is itself */ + } + ui = (x * x1p24).to_bits(); + hx = ui & 0x7fffffff; + hx = hx / 3 + B2; + } else { + hx = hx / 3 + B1; + } + ui &= 0x80000000; + ui |= hx; + + /* + * First step Newton iteration (solving t*t-x/t == 0) to 16 bits. In + * double precision so that its terms can be arranged for efficiency + * without causing overflow or underflow. + */ + t = f32::from_bits(ui) as f64; + r = t * t * t; + t = t * (x as f64 + x as f64 + r) / (x as f64 + r + r); + + /* + * Second step Newton iteration to 47 bits. In double precision for + * efficiency and accuracy. + */ + r = t * t * t; + t = t * (x as f64 + x as f64 + r) / (x as f64 + r + r); + + /* rounding to 24 bits is perfect in round-to-nearest mode */ + t as f32 +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 2a84b463d9fd1..0f112a0cbbee8 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -6,6 +6,8 @@ macro_rules! force_eval { }; } +mod cbrt; +mod cbrtf; mod ceil; mod ceilf; mod cosf; @@ -37,6 +39,8 @@ mod trunc; mod truncf; // Use separated imports instead of {}-grouped imports for easier merging. +pub use self::cbrt::cbrt; +pub use self::cbrtf::cbrtf; pub use self::ceil::ceil; pub use self::ceilf::ceilf; pub use self::cosf::cosf; diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index a54d8b2710f54..0521538deff47 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -656,7 +656,7 @@ f32_f32! { truncf, // asinf, // atanf, - // cbrtf, + cbrtf, cosf, ceilf, // coshf, @@ -699,7 +699,7 @@ f64_f64! { // acos, // asin, // atan, - // cbrt, + cbrt, ceil, // cos, // cosh, From de0682bf64e0bc753b0bb82bffc8f66cad7faa31 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 14 Jul 2018 20:36:28 +0200 Subject: [PATCH 0536/4206] remove exp --- library/compiler-builtins/libm/src/lib.rs | 2 + .../compiler-builtins/libm/src/math/exp.rs | 84 ------------------- .../compiler-builtins/libm/src/math/mod.rs | 2 - .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 3 insertions(+), 87 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/exp.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index e8869fca9ab1c..c53fefb2f297b 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -378,6 +378,7 @@ pub trait F64Ext: private::Sealed { fn sqrt(self) -> Self; + #[cfg(todo)] fn exp(self) -> Self; #[cfg(todo)] @@ -515,6 +516,7 @@ impl F64Ext for f64 { sqrt(self) } + #[cfg(todo)] #[inline] fn exp(self) -> Self { exp(self) diff --git a/library/compiler-builtins/libm/src/math/exp.rs b/library/compiler-builtins/libm/src/math/exp.rs deleted file mode 100644 index 870bf60853f55..0000000000000 --- a/library/compiler-builtins/libm/src/math/exp.rs +++ /dev/null @@ -1,84 +0,0 @@ -use super::scalbn; - -const HALF: [f64; 2] = [0.5, -0.5]; -const LN2_HI: f64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */ -const LN2_LO: f64 = 1.90821492927058770002e-10; /* 0x3dea39ef, 0x35793c76 */ -const INV_LN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */ -const P1: f64 = 1.66666666666666019037e-01; /* 0x3FC55555, 0x5555553E */ -const P2: f64 = -2.77777777770155933842e-03; /* 0xBF66C16C, 0x16BEBD93 */ -const P3: f64 = 6.61375632143793436117e-05; /* 0x3F11566A, 0xAF25DE2C */ -const P4: f64 = -1.65339022054652515390e-06; /* 0xBEBBBD41, 0xC5D26BF1 */ -const P5: f64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ - -#[inline] -pub fn exp(mut x: f64) -> f64 { - let mut hx: u32 = (x.to_bits() >> 32) as u32; - let sign = (hx >> 31) as i32; /* sign bit of x */ - hx &= 0x7fffffff; /* high word of |x| */ - - /* special cases */ - if hx >= 0x4086232b { - /* if |x| >= 708.39... */ - if x.is_nan() { - return x; - } - if x > 709.782712893383973096 { - /* overflow if x!=inf */ - x *= f64::from_bits(0x7fe0000000000000); - return x; - } - if x < -708.39641853226410622 { - /* underflow if x!=-inf */ - force_eval!((f64::from_bits(0xb6a0000000000000) / x) as f32); - if x < -745.13321910194110842 { - return 0.0; - } - } - } - - /* argument reduction */ - let k: i32; - let hi: f64; - let lo: f64; - if hx > 0x3fd62e42 { - /* if |x| > 0.5 ln2 */ - /* if |x| > 0.5 ln2 */ - if hx > 0x3ff0a2b2 { - /* if |x| > 1.5 ln2 */ - k = (INV_LN2 * x + HALF[sign as usize]) as i32; - } else { - k = 1 - sign - sign; - } - let kf = k as f64; - hi = x - kf * LN2_HI; /* k*ln2hi is exact here */ - lo = kf * LN2_LO; - x = hi - lo; - } else if hx > 0x3e300000 { - /* |x| > 2**-14 */ - k = 0; - hi = x; - lo = 0.0; - } else { - /* raise inexact */ - force_eval!(f64::from_bits(0x7fe0000000000000) + x); - return 1.0 + x; - } - - /* x is now in primary range */ - let xx = x * x; - let c = x - xx * (P1 + xx * (P2 + xx * (P3 + xx * (P4 + xx * P5)))); - let y = 1.0 + (x * c / (2.0 - c) - lo + hi); - if k == 0 { - y - } else { - scalbn(y, k) - } -} - -#[cfg(test)] -mod tests { - #[test] - fn sanity_check() { - assert_eq!(super::exp(1.1), 3.0041660239464334); - } -} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index d9e37ee3a6d8f..be17295659a87 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -10,7 +10,6 @@ mod ceil; mod ceilf; mod cosf; mod cosh; -mod exp; mod expf; mod expm1; mod fabs; @@ -43,7 +42,6 @@ pub use self::ceil::ceil; pub use self::ceilf::ceilf; pub use self::cosf::cosf; pub use self::cosh::cosh; -pub use self::exp::exp; pub use self::expf::expf; pub use self::expm1::expm1; pub use self::fabs::fabs; diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 8689870c2f59c..fc2842b0b81f6 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -703,7 +703,7 @@ f64_f64! { ceil, // cos, cosh, - exp, + // exp, // exp2, expm1, floor, From c6aad03ae4f922a8cd453627944669306cb850b6 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 14 Jul 2018 20:51:39 +0200 Subject: [PATCH 0537/4206] remove faulty cosh implementation --- .../compiler-builtins/libm/src/math/cosh.rs | 45 ------------------- .../libm/src/math/k_expo2.rs | 12 ----- 2 files changed, 57 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/cosh.rs delete mode 100644 library/compiler-builtins/libm/src/math/k_expo2.rs diff --git a/library/compiler-builtins/libm/src/math/cosh.rs b/library/compiler-builtins/libm/src/math/cosh.rs deleted file mode 100644 index e76edca03799c..0000000000000 --- a/library/compiler-builtins/libm/src/math/cosh.rs +++ /dev/null @@ -1,45 +0,0 @@ -use core::f64; - -use super::exp; -use super::expm1; -use super::k_expo2; - -pub fn cosh(mut x: f64) -> f64 { - let t: f64; - /* |x| */ - let mut ui = x.to_bits(); - ui &= !0u64; - x = f64::from_bits(ui); - let w = (ui >> 32) as u32; - - /* |x| < log(2) */ - if w < 0x3fe62e42 { - if w < 0x3ff00000 - (26 << 20) { - /* raise inexact if x!=0 */ - force_eval!(x + f64::from_bits(0x4770000000000000)); - return 1.0; - } - let t = expm1(x); - return 1.0 + t * t / (2.0 * (1.0 + t)); - } - - /* |x| < log(DBL_MAX) */ - if w < 0x40862e42 { - t = exp(x); - /* note: if x>log(0x1p26) then the 1/t is not needed */ - return 0.5 * (t + 1.0 / t); - } - - /* |x| > log(DBL_MAX) or nan */ - /* note: the result is stored to handle overflow */ - t = k_expo2(x); - return t; -} - -#[cfg(test)] -mod tests { - #[test] - fn sanity_check() { - assert_eq!(super::cosh(1.1), 1.6685185538222564); - } -} diff --git a/library/compiler-builtins/libm/src/math/k_expo2.rs b/library/compiler-builtins/libm/src/math/k_expo2.rs deleted file mode 100644 index c67a86550e665..0000000000000 --- a/library/compiler-builtins/libm/src/math/k_expo2.rs +++ /dev/null @@ -1,12 +0,0 @@ -use super::exp; - -const K: u32 = 2043; -const KLN2: f64 = 1416.0996898839683; - -#[inline] -pub(crate) fn k_expo2(x: f64) -> f64 { - /* note that k is odd and scale*scale overflows */ - let scale = f64::from_bits((((0x3ff + K / 2) << 20) as u64) << 32); - /* exp(x - k ln2) * 2**(k-1) */ - return exp(x - KLN2) * scale * scale; -} From b544bc360f8edc38fb6d64b1d1527d86cf6be95b Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 14 Jul 2018 20:59:41 +0200 Subject: [PATCH 0538/4206] fix missing changes --- library/compiler-builtins/libm/src/lib.rs | 2 ++ library/compiler-builtins/libm/src/math/mod.rs | 6 +----- library/compiler-builtins/libm/test-generator/src/main.rs | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 8091079a6241a..3a77288118847 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -439,6 +439,7 @@ pub trait F64Ext: private::Sealed { #[cfg(todo)] fn sinh(self) -> Self; + #[cfg(todo)] fn cosh(self) -> Self; #[cfg(todo)] @@ -628,6 +629,7 @@ impl F64Ext for f64 { sinh(self) } + #[cfg(todo)] #[inline] fn cosh(self) -> Self { cosh(self) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 86c181d13236d..65bfb96d08f51 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -9,7 +9,6 @@ macro_rules! force_eval { mod ceil; mod ceilf; mod cosf; -mod cosh; mod exp; mod expf; mod expm1; @@ -44,7 +43,6 @@ mod truncf; pub use self::ceil::ceil; pub use self::ceilf::ceilf; pub use self::cosf::cosf; -pub use self::cosh::cosh; pub use self::exp::exp; pub use self::expf::expf; pub use self::expm1::expm1; @@ -76,12 +74,10 @@ pub use self::trunc::trunc; pub use self::truncf::truncf; mod k_cosf; -mod k_expo2; mod k_sinf; mod rem_pio2_large; mod rem_pio2f; use self::{ - k_cosf::k_cosf, k_expo2::k_expo2, k_sinf::k_sinf, rem_pio2_large::rem_pio2_large, - rem_pio2f::rem_pio2f, + k_cosf::k_cosf, k_sinf::k_sinf, rem_pio2_large::rem_pio2_large, rem_pio2f::rem_pio2f, }; diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index dff949459a28f..6010695cb1d9e 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -702,7 +702,7 @@ f64_f64! { // cbrt, ceil, // cos, - cosh, + // cosh, exp, // exp2, expm1, From 353409ada712abee04099d2a640f2c6ddf1d20e6 Mon Sep 17 00:00:00 2001 From: C Jones Date: Sat, 14 Jul 2018 05:04:46 -0400 Subject: [PATCH 0539/4206] Add exp2f --- library/compiler-builtins/libm/src/lib.rs | 2 - .../compiler-builtins/libm/src/math/exp2f.rs | 130 ++++++++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 2 + .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/exp2f.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index fddb8ca70fb21..c6e01df415e2c 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -70,7 +70,6 @@ pub trait F32Ext: private::Sealed { fn exp(self) -> Self; - #[cfg(todo)] fn exp2(self) -> Self; fn ln(self) -> Self; @@ -214,7 +213,6 @@ impl F32Ext for f32 { expf(self) } - #[cfg(todo)] #[inline] fn exp2(self) -> Self { exp2f(self) diff --git a/library/compiler-builtins/libm/src/math/exp2f.rs b/library/compiler-builtins/libm/src/math/exp2f.rs new file mode 100644 index 0000000000000..947679a8389d3 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/exp2f.rs @@ -0,0 +1,130 @@ +// origin: FreeBSD /usr/src/lib/msun/src/s_exp2f.c +//- +// Copyright (c) 2005 David Schultz +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. + +const TBLSIZE: usize = 16; + +// exp2f(x): compute the base 2 exponential of x +// +// Accuracy: Peak error < 0.501 ulp; location of peak: -0.030110927. +// +// Method: (equally-spaced tables) +// +// Reduce x: +// x = k + y, for integer k and |y| <= 1/2. +// Thus we have exp2f(x) = 2**k * exp2(y). +// +// Reduce y: +// y = i/TBLSIZE + z for integer i near y * TBLSIZE. +// Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z), +// with |z| <= 2**-(TBLSIZE+1). +// +// We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a +// degree-4 minimax polynomial with maximum error under 1.4 * 2**-33. +// Using double precision for everything except the reduction makes +// roundoff error insignificant and simplifies the scaling step. +// +// This method is due to Tang, but I do not use his suggested parameters: +// +// Tang, P. Table-driven Implementation of the Exponential Function +// in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989). +pub fn exp2f(mut x: f32) -> f32 { + let redux = f32::from_bits(0x4b400000) / TBLSIZE as f32; + let p1 = f32::from_bits(0x3f317218); + let p2 = f32::from_bits(0x3e75fdf0); + let p3 = f32::from_bits(0x3d6359a4); + let p4 = f32::from_bits(0x3c1d964e); + + let exp2ft: [f64; TBLSIZE] = [ + f64::from_bits(0x3fe6a09e667f3bcd), + f64::from_bits(0x3fe7a11473eb0187), + f64::from_bits(0x3fe8ace5422aa0db), + f64::from_bits(0x3fe9c49182a3f090), + f64::from_bits(0x3feae89f995ad3ad), + f64::from_bits(0x3fec199bdd85529c), + f64::from_bits(0x3fed5818dcfba487), + f64::from_bits(0x3feea4afa2a490da), + f64::from_bits(0x3ff0000000000000), + f64::from_bits(0x3ff0b5586cf9890f), + f64::from_bits(0x3ff172b83c7d517b), + f64::from_bits(0x3ff2387a6e756238), + f64::from_bits(0x3ff306fe0a31b715), + f64::from_bits(0x3ff3dea64c123422), + f64::from_bits(0x3ff4bfdad5362a27), + f64::from_bits(0x3ff5ab07dd485429), + ]; + + // double_t t, r, z; + // uint32_t ix, i0, k; + + let x1p127 = f32::from_bits(0x7f000000); + + /* Filter out exceptional cases. */ + let ui = f32::to_bits(x); + let ix = ui & 0x7fffffff; + if ix > 0x42fc0000 { + /* |x| > 126 */ + if ix > 0x7f800000 { + /* NaN */ + return x; + } + if ui >= 0x43000000 && ui < 0x80000000 { + /* x >= 128 */ + x *= x1p127; + return x; + } + if ui >= 0x80000000 { + /* x < -126 */ + if ui >= 0xc3160000 || (ui & 0x0000ffff != 0) { + force_eval!(f32::from_bits(0x80000001) / x); + } + if ui >= 0xc3160000 { + /* x <= -150 */ + return 0.0; + } + } + } else if ix <= 0x33000000 { + /* |x| <= 0x1p-25 */ + return 1.0 + x; + } + + /* Reduce x, computing z, i0, and k. */ + let ui = f32::to_bits(x + redux); + let mut i0 = ui; + i0 += TBLSIZE as u32 / 2; + let k = i0 / TBLSIZE as u32; + let ukf = f64::from_bits(((0x3ff + k) as u64) << 52); + i0 &= TBLSIZE as u32 - 1; + let mut uf = f32::from_bits(ui); + uf -= redux; + let z: f64 = (x - uf) as f64; + /* Compute r = exp2(y) = exp2ft[i0] * p(z). */ + let r: f64 = exp2ft[i0 as usize]; + let t: f64 = r as f64 * z; + let r: f64 = r + t * (p1 as f64 + z * p2 as f64) + t * (z * z) * (p3 as f64 + z * p4 as f64); + + /* Scale by 2**k */ + (r * ukf) as f32 +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 59d669ab6a91d..5540ba8382572 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -12,6 +12,7 @@ mod ceil; mod ceilf; mod cosf; mod exp; +mod exp2f; mod expf; mod fabs; mod fabsf; @@ -48,6 +49,7 @@ pub use self::ceil::ceil; pub use self::ceilf::ceilf; pub use self::cosf::cosf; pub use self::exp::exp; +pub use self::exp2f::exp2f; pub use self::expf::expf; pub use self::fabs::fabs; pub use self::fabsf::fabsf; diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index bce4284b3d0e4..dfe912a508b0f 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -660,7 +660,7 @@ f32_f32! { cosf, ceilf, // coshf, - // exp2f, + exp2f, expf, log10f, log1pf, From 62b9897c29deb29345598987b07ab0f4be8d335a Mon Sep 17 00:00:00 2001 From: C Jones Date: Sat, 14 Jul 2018 05:29:43 -0400 Subject: [PATCH 0540/4206] Implement exp2 --- library/compiler-builtins/libm/src/lib.rs | 2 - .../compiler-builtins/libm/src/math/exp2.rs | 383 ++++++++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 2 + .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 386 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/exp2.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index c6e01df415e2c..3f9a65bccd1e6 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -385,7 +385,6 @@ pub trait F64Ext: private::Sealed { fn exp(self) -> Self; - #[cfg(todo)] fn exp2(self) -> Self; fn ln(self) -> Self; @@ -530,7 +529,6 @@ impl F64Ext for f64 { exp(self) } - #[cfg(todo)] #[inline] fn exp2(self) -> Self { exp2(self) diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs new file mode 100644 index 0000000000000..c5bd3608a4398 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -0,0 +1,383 @@ +// origin: FreeBSD /usr/src/lib/msun/src/s_exp2.c */ +//- +// Copyright (c) 2005 David Schultz +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. + +use super::scalbn::scalbn; + +const TBLSIZE: usize = 256; + +// exp2(x): compute the base 2 exponential of x +// +// Accuracy: Peak error < 0.503 ulp for normalized results. +// +// Method: (accurate tables) +// +// Reduce x: +// x = k + y, for integer k and |y| <= 1/2. +// Thus we have exp2(x) = 2**k * exp2(y). +// +// Reduce y: +// y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE. +// Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]), +// with |z - eps[i]| <= 2**-9 + 2**-39 for the table used. +// +// We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via +// a degree-5 minimax polynomial with maximum error under 1.3 * 2**-61. +// The values in exp2t[] and eps[] are chosen such that +// exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such +// that exp2t[i] is accurate to 2**-64. +// +// Note that the range of i is +-TBLSIZE/2, so we actually index the tables +// by i0 = i + TBLSIZE/2. For cache efficiency, exp2t[] and eps[] are +// virtual tables, interleaved in the real table tbl[]. +// +// This method is due to Gal, with many details due to Gal and Bachelis: +// +// Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library +// for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). +pub fn exp2(mut x: f64) -> f64 { + let redux = f64::from_bits(0x4338000000000000) / TBLSIZE as f64; + let p1 = f64::from_bits(0x3fe62e42fefa39ef); + let p2 = f64::from_bits(0x3fcebfbdff82c575); + let p3 = f64::from_bits(0x3fac6b08d704a0a6); + let p4 = f64::from_bits(0x3f83b2ab88f70400); + let p5 = f64::from_bits(0x3f55d88003875c74); + + #[cfg_attr(rustfmt, rustfmt_skip)] + let tbl = [ + // exp2(z + eps) eps + f64::from_bits(0x3fe6a09e667f3d5d), f64::from_bits(0x3d39880000000000), + f64::from_bits(0x3fe6b052fa751744), f64::from_bits(0x3cd8000000000000), + f64::from_bits(0x3fe6c012750bd9fe), f64::from_bits(0xbd28780000000000), + f64::from_bits(0x3fe6cfdcddd476bf), f64::from_bits(0x3d1ec00000000000), + f64::from_bits(0x3fe6dfb23c651a29), f64::from_bits(0xbcd8000000000000), + f64::from_bits(0x3fe6ef9298593ae3), f64::from_bits(0xbcbc000000000000), + f64::from_bits(0x3fe6ff7df9519386), f64::from_bits(0xbd2fd80000000000), + f64::from_bits(0x3fe70f7466f42da3), f64::from_bits(0xbd2c880000000000), + f64::from_bits(0x3fe71f75e8ec5fc3), f64::from_bits(0x3d13c00000000000), + f64::from_bits(0x3fe72f8286eacf05), f64::from_bits(0xbd38300000000000), + f64::from_bits(0x3fe73f9a48a58152), f64::from_bits(0xbd00c00000000000), + f64::from_bits(0x3fe74fbd35d7ccfc), f64::from_bits(0x3d2f880000000000), + f64::from_bits(0x3fe75feb564267f1), f64::from_bits(0x3d03e00000000000), + f64::from_bits(0x3fe77024b1ab6d48), f64::from_bits(0xbd27d00000000000), + f64::from_bits(0x3fe780694fde5d38), f64::from_bits(0xbcdd000000000000), + f64::from_bits(0x3fe790b938ac1d00), f64::from_bits(0x3ce3000000000000), + f64::from_bits(0x3fe7a11473eb0178), f64::from_bits(0xbced000000000000), + f64::from_bits(0x3fe7b17b0976d060), f64::from_bits(0x3d20400000000000), + f64::from_bits(0x3fe7c1ed0130c133), f64::from_bits(0x3ca0000000000000), + f64::from_bits(0x3fe7d26a62ff8636), f64::from_bits(0xbd26900000000000), + f64::from_bits(0x3fe7e2f336cf4e3b), f64::from_bits(0xbd02e00000000000), + f64::from_bits(0x3fe7f3878491c3e8), f64::from_bits(0xbd24580000000000), + f64::from_bits(0x3fe80427543e1b4e), f64::from_bits(0x3d33000000000000), + f64::from_bits(0x3fe814d2add1071a), f64::from_bits(0x3d0f000000000000), + f64::from_bits(0x3fe82589994ccd7e), f64::from_bits(0xbd21c00000000000), + f64::from_bits(0x3fe8364c1eb942d0), f64::from_bits(0x3d29d00000000000), + f64::from_bits(0x3fe8471a4623cab5), f64::from_bits(0x3d47100000000000), + f64::from_bits(0x3fe857f4179f5bbc), f64::from_bits(0x3d22600000000000), + f64::from_bits(0x3fe868d99b4491af), f64::from_bits(0xbd32c40000000000), + f64::from_bits(0x3fe879cad931a395), f64::from_bits(0xbd23000000000000), + f64::from_bits(0x3fe88ac7d98a65b8), f64::from_bits(0xbd2a800000000000), + f64::from_bits(0x3fe89bd0a4785800), f64::from_bits(0xbced000000000000), + f64::from_bits(0x3fe8ace5422aa223), f64::from_bits(0x3d33280000000000), + f64::from_bits(0x3fe8be05bad619fa), f64::from_bits(0x3d42b40000000000), + f64::from_bits(0x3fe8cf3216b54383), f64::from_bits(0xbd2ed00000000000), + f64::from_bits(0x3fe8e06a5e08664c), f64::from_bits(0xbd20500000000000), + f64::from_bits(0x3fe8f1ae99157807), f64::from_bits(0x3d28280000000000), + f64::from_bits(0x3fe902fed0282c0e), f64::from_bits(0xbd1cb00000000000), + f64::from_bits(0x3fe9145b0b91ff96), f64::from_bits(0xbd05e00000000000), + f64::from_bits(0x3fe925c353aa2ff9), f64::from_bits(0x3cf5400000000000), + f64::from_bits(0x3fe93737b0cdc64a), f64::from_bits(0x3d17200000000000), + f64::from_bits(0x3fe948b82b5f98ae), f64::from_bits(0xbd09000000000000), + f64::from_bits(0x3fe95a44cbc852cb), f64::from_bits(0x3d25680000000000), + f64::from_bits(0x3fe96bdd9a766f21), f64::from_bits(0xbd36d00000000000), + f64::from_bits(0x3fe97d829fde4e2a), f64::from_bits(0xbd01000000000000), + f64::from_bits(0x3fe98f33e47a23a3), f64::from_bits(0x3d2d000000000000), + f64::from_bits(0x3fe9a0f170ca0604), f64::from_bits(0xbd38a40000000000), + f64::from_bits(0x3fe9b2bb4d53ff89), f64::from_bits(0x3d355c0000000000), + f64::from_bits(0x3fe9c49182a3f15b), f64::from_bits(0x3d26b80000000000), + f64::from_bits(0x3fe9d674194bb8c5), f64::from_bits(0xbcec000000000000), + f64::from_bits(0x3fe9e86319e3238e), f64::from_bits(0x3d17d00000000000), + f64::from_bits(0x3fe9fa5e8d07f302), f64::from_bits(0x3d16400000000000), + f64::from_bits(0x3fea0c667b5de54d), f64::from_bits(0xbcf5000000000000), + f64::from_bits(0x3fea1e7aed8eb8f6), f64::from_bits(0x3d09e00000000000), + f64::from_bits(0x3fea309bec4a2e27), f64::from_bits(0x3d2ad80000000000), + f64::from_bits(0x3fea42c980460a5d), f64::from_bits(0xbd1af00000000000), + f64::from_bits(0x3fea5503b23e259b), f64::from_bits(0x3d0b600000000000), + f64::from_bits(0x3fea674a8af46213), f64::from_bits(0x3d38880000000000), + f64::from_bits(0x3fea799e1330b3a7), f64::from_bits(0x3d11200000000000), + f64::from_bits(0x3fea8bfe53c12e8d), f64::from_bits(0x3d06c00000000000), + f64::from_bits(0x3fea9e6b5579fcd2), f64::from_bits(0xbd29b80000000000), + f64::from_bits(0x3feab0e521356fb8), f64::from_bits(0x3d2b700000000000), + f64::from_bits(0x3feac36bbfd3f381), f64::from_bits(0x3cd9000000000000), + f64::from_bits(0x3fead5ff3a3c2780), f64::from_bits(0x3ce4000000000000), + f64::from_bits(0x3feae89f995ad2a3), f64::from_bits(0xbd2c900000000000), + f64::from_bits(0x3feafb4ce622f367), f64::from_bits(0x3d16500000000000), + f64::from_bits(0x3feb0e07298db790), f64::from_bits(0x3d2fd40000000000), + f64::from_bits(0x3feb20ce6c9a89a9), f64::from_bits(0x3d12700000000000), + f64::from_bits(0x3feb33a2b84f1a4b), f64::from_bits(0x3d4d470000000000), + f64::from_bits(0x3feb468415b747e7), f64::from_bits(0xbd38380000000000), + f64::from_bits(0x3feb59728de5593a), f64::from_bits(0x3c98000000000000), + f64::from_bits(0x3feb6c6e29f1c56a), f64::from_bits(0x3d0ad00000000000), + f64::from_bits(0x3feb7f76f2fb5e50), f64::from_bits(0x3cde800000000000), + f64::from_bits(0x3feb928cf22749b2), f64::from_bits(0xbd04c00000000000), + f64::from_bits(0x3feba5b030a10603), f64::from_bits(0xbd0d700000000000), + f64::from_bits(0x3febb8e0b79a6f66), f64::from_bits(0x3d0d900000000000), + f64::from_bits(0x3febcc1e904bc1ff), f64::from_bits(0x3d02a00000000000), + f64::from_bits(0x3febdf69c3f3a16f), f64::from_bits(0xbd1f780000000000), + f64::from_bits(0x3febf2c25bd71db8), f64::from_bits(0xbd10a00000000000), + f64::from_bits(0x3fec06286141b2e9), f64::from_bits(0xbd11400000000000), + f64::from_bits(0x3fec199bdd8552e0), f64::from_bits(0x3d0be00000000000), + f64::from_bits(0x3fec2d1cd9fa64ee), f64::from_bits(0xbd09400000000000), + f64::from_bits(0x3fec40ab5fffd02f), f64::from_bits(0xbd0ed00000000000), + f64::from_bits(0x3fec544778fafd15), f64::from_bits(0x3d39660000000000), + f64::from_bits(0x3fec67f12e57d0cb), f64::from_bits(0xbd1a100000000000), + f64::from_bits(0x3fec7ba88988c1b6), f64::from_bits(0xbd58458000000000), + f64::from_bits(0x3fec8f6d9406e733), f64::from_bits(0xbd1a480000000000), + f64::from_bits(0x3feca3405751c4df), f64::from_bits(0x3ccb000000000000), + f64::from_bits(0x3fecb720dcef9094), f64::from_bits(0x3d01400000000000), + f64::from_bits(0x3feccb0f2e6d1689), f64::from_bits(0x3cf0200000000000), + f64::from_bits(0x3fecdf0b555dc412), f64::from_bits(0x3cf3600000000000), + f64::from_bits(0x3fecf3155b5bab3b), f64::from_bits(0xbd06900000000000), + f64::from_bits(0x3fed072d4a0789bc), f64::from_bits(0x3d09a00000000000), + f64::from_bits(0x3fed1b532b08c8fa), f64::from_bits(0xbd15e00000000000), + f64::from_bits(0x3fed2f87080d8a85), f64::from_bits(0x3d1d280000000000), + f64::from_bits(0x3fed43c8eacaa203), f64::from_bits(0x3d01a00000000000), + f64::from_bits(0x3fed5818dcfba491), f64::from_bits(0x3cdf000000000000), + f64::from_bits(0x3fed6c76e862e6a1), f64::from_bits(0xbd03a00000000000), + f64::from_bits(0x3fed80e316c9834e), f64::from_bits(0xbd0cd80000000000), + f64::from_bits(0x3fed955d71ff6090), f64::from_bits(0x3cf4c00000000000), + f64::from_bits(0x3feda9e603db32ae), f64::from_bits(0x3cff900000000000), + f64::from_bits(0x3fedbe7cd63a8325), f64::from_bits(0x3ce9800000000000), + f64::from_bits(0x3fedd321f301b445), f64::from_bits(0xbcf5200000000000), + f64::from_bits(0x3fede7d5641c05bf), f64::from_bits(0xbd1d700000000000), + f64::from_bits(0x3fedfc97337b9aec), f64::from_bits(0xbd16140000000000), + f64::from_bits(0x3fee11676b197d5e), f64::from_bits(0x3d0b480000000000), + f64::from_bits(0x3fee264614f5a3e7), f64::from_bits(0x3d40ce0000000000), + f64::from_bits(0x3fee3b333b16ee5c), f64::from_bits(0x3d0c680000000000), + f64::from_bits(0x3fee502ee78b3fb4), f64::from_bits(0xbd09300000000000), + f64::from_bits(0x3fee653924676d68), f64::from_bits(0xbce5000000000000), + f64::from_bits(0x3fee7a51fbc74c44), f64::from_bits(0xbd07f80000000000), + f64::from_bits(0x3fee8f7977cdb726), f64::from_bits(0xbcf3700000000000), + f64::from_bits(0x3feea4afa2a490e8), f64::from_bits(0x3ce5d00000000000), + f64::from_bits(0x3feeb9f4867ccae4), f64::from_bits(0x3d161a0000000000), + f64::from_bits(0x3feecf482d8e680d), f64::from_bits(0x3cf5500000000000), + f64::from_bits(0x3feee4aaa2188514), f64::from_bits(0x3cc6400000000000), + f64::from_bits(0x3feefa1bee615a13), f64::from_bits(0xbcee800000000000), + f64::from_bits(0x3fef0f9c1cb64106), f64::from_bits(0xbcfa880000000000), + f64::from_bits(0x3fef252b376bb963), f64::from_bits(0xbd2c900000000000), + f64::from_bits(0x3fef3ac948dd7275), f64::from_bits(0x3caa000000000000), + f64::from_bits(0x3fef50765b6e4524), f64::from_bits(0xbcf4f00000000000), + f64::from_bits(0x3fef6632798844fd), f64::from_bits(0x3cca800000000000), + f64::from_bits(0x3fef7bfdad9cbe38), f64::from_bits(0x3cfabc0000000000), + f64::from_bits(0x3fef91d802243c82), f64::from_bits(0xbcd4600000000000), + f64::from_bits(0x3fefa7c1819e908e), f64::from_bits(0xbd0b0c0000000000), + f64::from_bits(0x3fefbdba3692d511), f64::from_bits(0xbcc0e00000000000), + f64::from_bits(0x3fefd3c22b8f7194), f64::from_bits(0xbd10de8000000000), + f64::from_bits(0x3fefe9d96b2a23ee), f64::from_bits(0x3cee430000000000), + f64::from_bits(0x3ff0000000000000), f64::from_bits(0x0), + f64::from_bits(0x3ff00b1afa5abcbe), f64::from_bits(0xbcb3400000000000), + f64::from_bits(0x3ff0163da9fb3303), f64::from_bits(0xbd12170000000000), + f64::from_bits(0x3ff02168143b0282), f64::from_bits(0x3cba400000000000), + f64::from_bits(0x3ff02c9a3e77806c), f64::from_bits(0x3cef980000000000), + f64::from_bits(0x3ff037d42e11bbca), f64::from_bits(0xbcc7400000000000), + f64::from_bits(0x3ff04315e86e7f89), f64::from_bits(0x3cd8300000000000), + f64::from_bits(0x3ff04e5f72f65467), f64::from_bits(0xbd1a3f0000000000), + f64::from_bits(0x3ff059b0d315855a), f64::from_bits(0xbd02840000000000), + f64::from_bits(0x3ff0650a0e3c1f95), f64::from_bits(0x3cf1600000000000), + f64::from_bits(0x3ff0706b29ddf71a), f64::from_bits(0x3d15240000000000), + f64::from_bits(0x3ff07bd42b72a82d), f64::from_bits(0xbce9a00000000000), + f64::from_bits(0x3ff0874518759bd0), f64::from_bits(0x3ce6400000000000), + f64::from_bits(0x3ff092bdf66607c8), f64::from_bits(0xbd00780000000000), + f64::from_bits(0x3ff09e3ecac6f383), f64::from_bits(0xbc98000000000000), + f64::from_bits(0x3ff0a9c79b1f3930), f64::from_bits(0x3cffa00000000000), + f64::from_bits(0x3ff0b5586cf988fc), f64::from_bits(0xbcfac80000000000), + f64::from_bits(0x3ff0c0f145e46c8a), f64::from_bits(0x3cd9c00000000000), + f64::from_bits(0x3ff0cc922b724816), f64::from_bits(0x3d05200000000000), + f64::from_bits(0x3ff0d83b23395dd8), f64::from_bits(0xbcfad00000000000), + f64::from_bits(0x3ff0e3ec32d3d1f3), f64::from_bits(0x3d1bac0000000000), + f64::from_bits(0x3ff0efa55fdfa9a6), f64::from_bits(0xbd04e80000000000), + f64::from_bits(0x3ff0fb66affed2f0), f64::from_bits(0xbd0d300000000000), + f64::from_bits(0x3ff1073028d7234b), f64::from_bits(0x3cf1500000000000), + f64::from_bits(0x3ff11301d0125b5b), f64::from_bits(0x3cec000000000000), + f64::from_bits(0x3ff11edbab5e2af9), f64::from_bits(0x3d16bc0000000000), + f64::from_bits(0x3ff12abdc06c31d5), f64::from_bits(0x3ce8400000000000), + f64::from_bits(0x3ff136a814f2047d), f64::from_bits(0xbd0ed00000000000), + f64::from_bits(0x3ff1429aaea92de9), f64::from_bits(0x3ce8e00000000000), + f64::from_bits(0x3ff14e95934f3138), f64::from_bits(0x3ceb400000000000), + f64::from_bits(0x3ff15a98c8a58e71), f64::from_bits(0x3d05300000000000), + f64::from_bits(0x3ff166a45471c3df), f64::from_bits(0x3d03380000000000), + f64::from_bits(0x3ff172b83c7d5211), f64::from_bits(0x3d28d40000000000), + f64::from_bits(0x3ff17ed48695bb9f), f64::from_bits(0xbd05d00000000000), + f64::from_bits(0x3ff18af9388c8d93), f64::from_bits(0xbd1c880000000000), + f64::from_bits(0x3ff1972658375d66), f64::from_bits(0x3d11f00000000000), + f64::from_bits(0x3ff1a35beb6fcba7), f64::from_bits(0x3d10480000000000), + f64::from_bits(0x3ff1af99f81387e3), f64::from_bits(0xbd47390000000000), + f64::from_bits(0x3ff1bbe084045d54), f64::from_bits(0x3d24e40000000000), + f64::from_bits(0x3ff1c82f95281c43), f64::from_bits(0xbd0a200000000000), + f64::from_bits(0x3ff1d4873168b9b2), f64::from_bits(0x3ce3800000000000), + f64::from_bits(0x3ff1e0e75eb44031), f64::from_bits(0x3ceac00000000000), + f64::from_bits(0x3ff1ed5022fcd938), f64::from_bits(0x3d01900000000000), + f64::from_bits(0x3ff1f9c18438cdf7), f64::from_bits(0xbd1b780000000000), + f64::from_bits(0x3ff2063b88628d8f), f64::from_bits(0x3d2d940000000000), + f64::from_bits(0x3ff212be3578a81e), f64::from_bits(0x3cd8000000000000), + f64::from_bits(0x3ff21f49917ddd41), f64::from_bits(0x3d2b340000000000), + f64::from_bits(0x3ff22bdda2791323), f64::from_bits(0x3d19f80000000000), + f64::from_bits(0x3ff2387a6e7561e7), f64::from_bits(0xbd19c80000000000), + f64::from_bits(0x3ff2451ffb821427), f64::from_bits(0x3d02300000000000), + f64::from_bits(0x3ff251ce4fb2a602), f64::from_bits(0xbd13480000000000), + f64::from_bits(0x3ff25e85711eceb0), f64::from_bits(0x3d12700000000000), + f64::from_bits(0x3ff26b4565e27d16), f64::from_bits(0x3d11d00000000000), + f64::from_bits(0x3ff2780e341de00f), f64::from_bits(0x3d31ee0000000000), + f64::from_bits(0x3ff284dfe1f5633e), f64::from_bits(0xbd14c00000000000), + f64::from_bits(0x3ff291ba7591bb30), f64::from_bits(0xbd13d80000000000), + f64::from_bits(0x3ff29e9df51fdf09), f64::from_bits(0x3d08b00000000000), + f64::from_bits(0x3ff2ab8a66d10e9b), f64::from_bits(0xbd227c0000000000), + f64::from_bits(0x3ff2b87fd0dada3a), f64::from_bits(0x3d2a340000000000), + f64::from_bits(0x3ff2c57e39771af9), f64::from_bits(0xbd10800000000000), + f64::from_bits(0x3ff2d285a6e402d9), f64::from_bits(0xbd0ed00000000000), + f64::from_bits(0x3ff2df961f641579), f64::from_bits(0xbcf4200000000000), + f64::from_bits(0x3ff2ecafa93e2ecf), f64::from_bits(0xbd24980000000000), + f64::from_bits(0x3ff2f9d24abd8822), f64::from_bits(0xbd16300000000000), + f64::from_bits(0x3ff306fe0a31b625), f64::from_bits(0xbd32360000000000), + f64::from_bits(0x3ff31432edeea50b), f64::from_bits(0xbd70df8000000000), + f64::from_bits(0x3ff32170fc4cd7b8), f64::from_bits(0xbd22480000000000), + f64::from_bits(0x3ff32eb83ba8e9a2), f64::from_bits(0xbd25980000000000), + f64::from_bits(0x3ff33c08b2641766), f64::from_bits(0x3d1ed00000000000), + f64::from_bits(0x3ff3496266e3fa27), f64::from_bits(0xbcdc000000000000), + f64::from_bits(0x3ff356c55f929f0f), f64::from_bits(0xbd30d80000000000), + f64::from_bits(0x3ff36431a2de88b9), f64::from_bits(0x3d22c80000000000), + f64::from_bits(0x3ff371a7373aaa39), f64::from_bits(0x3d20600000000000), + f64::from_bits(0x3ff37f26231e74fe), f64::from_bits(0xbd16600000000000), + f64::from_bits(0x3ff38cae6d05d838), f64::from_bits(0xbd0ae00000000000), + f64::from_bits(0x3ff39a401b713ec3), f64::from_bits(0xbd44720000000000), + f64::from_bits(0x3ff3a7db34e5a020), f64::from_bits(0x3d08200000000000), + f64::from_bits(0x3ff3b57fbfec6e95), f64::from_bits(0x3d3e800000000000), + f64::from_bits(0x3ff3c32dc313a8f2), f64::from_bits(0x3cef800000000000), + f64::from_bits(0x3ff3d0e544ede122), f64::from_bits(0xbd17a00000000000), + f64::from_bits(0x3ff3dea64c1234bb), f64::from_bits(0x3d26300000000000), + f64::from_bits(0x3ff3ec70df1c4ecc), f64::from_bits(0xbd48a60000000000), + f64::from_bits(0x3ff3fa4504ac7e8c), f64::from_bits(0xbd3cdc0000000000), + f64::from_bits(0x3ff40822c367a0bb), f64::from_bits(0x3d25b80000000000), + f64::from_bits(0x3ff4160a21f72e95), f64::from_bits(0x3d1ec00000000000), + f64::from_bits(0x3ff423fb27094646), f64::from_bits(0xbd13600000000000), + f64::from_bits(0x3ff431f5d950a920), f64::from_bits(0x3d23980000000000), + f64::from_bits(0x3ff43ffa3f84b9eb), f64::from_bits(0x3cfa000000000000), + f64::from_bits(0x3ff44e0860618919), f64::from_bits(0xbcf6c00000000000), + f64::from_bits(0x3ff45c2042a7d201), f64::from_bits(0xbd0bc00000000000), + f64::from_bits(0x3ff46a41ed1d0016), f64::from_bits(0xbd12800000000000), + f64::from_bits(0x3ff4786d668b3326), f64::from_bits(0x3d30e00000000000), + f64::from_bits(0x3ff486a2b5c13c00), f64::from_bits(0xbd2d400000000000), + f64::from_bits(0x3ff494e1e192af04), f64::from_bits(0x3d0c200000000000), + f64::from_bits(0x3ff4a32af0d7d372), f64::from_bits(0xbd1e500000000000), + f64::from_bits(0x3ff4b17dea6db801), f64::from_bits(0x3d07800000000000), + f64::from_bits(0x3ff4bfdad53629e1), f64::from_bits(0xbd13800000000000), + f64::from_bits(0x3ff4ce41b817c132), f64::from_bits(0x3d00800000000000), + f64::from_bits(0x3ff4dcb299fddddb), f64::from_bits(0x3d2c700000000000), + f64::from_bits(0x3ff4eb2d81d8ab96), f64::from_bits(0xbd1ce00000000000), + f64::from_bits(0x3ff4f9b2769d2d02), f64::from_bits(0x3d19200000000000), + f64::from_bits(0x3ff508417f4531c1), f64::from_bits(0xbd08c00000000000), + f64::from_bits(0x3ff516daa2cf662a), f64::from_bits(0xbcfa000000000000), + f64::from_bits(0x3ff5257de83f51ea), f64::from_bits(0x3d4a080000000000), + f64::from_bits(0x3ff5342b569d4eda), f64::from_bits(0xbd26d80000000000), + f64::from_bits(0x3ff542e2f4f6ac1a), f64::from_bits(0xbd32440000000000), + f64::from_bits(0x3ff551a4ca5d94db), f64::from_bits(0x3d483c0000000000), + f64::from_bits(0x3ff56070dde9116b), f64::from_bits(0x3d24b00000000000), + f64::from_bits(0x3ff56f4736b529de), f64::from_bits(0x3d415a0000000000), + f64::from_bits(0x3ff57e27dbe2c40e), f64::from_bits(0xbd29e00000000000), + f64::from_bits(0x3ff58d12d497c76f), f64::from_bits(0xbd23080000000000), + f64::from_bits(0x3ff59c0827ff0b4c), f64::from_bits(0x3d4dec0000000000), + f64::from_bits(0x3ff5ab07dd485427), f64::from_bits(0xbcc4000000000000), + f64::from_bits(0x3ff5ba11fba87af4), f64::from_bits(0x3d30080000000000), + f64::from_bits(0x3ff5c9268a59460b), f64::from_bits(0xbd26c80000000000), + f64::from_bits(0x3ff5d84590998e3f), f64::from_bits(0x3d469a0000000000), + f64::from_bits(0x3ff5e76f15ad20e1), f64::from_bits(0xbd1b400000000000), + f64::from_bits(0x3ff5f6a320dcebca), f64::from_bits(0x3d17700000000000), + f64::from_bits(0x3ff605e1b976dcb8), f64::from_bits(0x3d26f80000000000), + f64::from_bits(0x3ff6152ae6cdf715), f64::from_bits(0x3d01000000000000), + f64::from_bits(0x3ff6247eb03a5531), f64::from_bits(0xbd15d00000000000), + f64::from_bits(0x3ff633dd1d1929b5), f64::from_bits(0xbd12d00000000000), + f64::from_bits(0x3ff6434634ccc313), f64::from_bits(0xbcea800000000000), + f64::from_bits(0x3ff652b9febc8efa), f64::from_bits(0xbd28600000000000), + f64::from_bits(0x3ff6623882553397), f64::from_bits(0x3d71fe0000000000), + f64::from_bits(0x3ff671c1c708328e), f64::from_bits(0xbd37200000000000), + f64::from_bits(0x3ff68155d44ca97e), f64::from_bits(0x3ce6800000000000), + f64::from_bits(0x3ff690f4b19e9471), f64::from_bits(0xbd29780000000000), + ]; + + // double_t r, t, z; + // uint32_t ix, i0; + // union {double f; uint64_t i;} u = {x}; + // union {uint32_t u; int32_t i;} k; + let x1p1023 = f64::from_bits(0x7fe0000000000000); + let x1p52 = f64::from_bits(0x4330000000000000); + let _0x1p_149 = f64::from_bits(0xb6a0000000000000); + + /* Filter out exceptional cases. */ + let ui = f64::to_bits(x); + let ix = ui >> 32 & 0x7fffffff; + if ix >= 0x408ff000 { + /* |x| >= 1022 or nan */ + if ix >= 0x40900000 && ui >> 63 == 0 { + /* x >= 1024 or nan */ + /* overflow */ + x *= x1p1023; + return x; + } + if ix >= 0x7ff00000 { + /* -inf or -nan */ + return -1.0 / x; + } + if ui >> 63 != 0 { + /* x <= -1022 */ + /* underflow */ + if x <= -1075.0 || x - x1p52 + x1p52 != x { + force_eval!((_0x1p_149 / x) as f32); + } + if x <= -1075.0 { + return 0.0; + } + } + } else if ix < 0x3c900000 { + /* |x| < 0x1p-54 */ + return 1.0 + x; + } + + /* Reduce x, computing z, i0, and k. */ + let ui = f64::to_bits(x + redux); + let mut i0 = ui as u32; + i0 += TBLSIZE as u32 / 2; + let ku = i0 / TBLSIZE as u32 * TBLSIZE as u32; + let ki = ku as i32 / TBLSIZE as i32; + i0 %= TBLSIZE as u32; + let uf = f64::from_bits(ui) - redux; + let mut z = x - uf; + + /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ + let t = tbl[2 * i0 as usize]; /* exp2t[i0] */ + z -= tbl[2 * i0 as usize + 1]; /* eps[i0] */ + let r = t + t * z * (p1 + z * (p2 + z * (p3 + z * (p4 + z * p5)))); + + scalbn(r, ki) +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 5540ba8382572..a15c4e60bdf6f 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -12,6 +12,7 @@ mod ceil; mod ceilf; mod cosf; mod exp; +mod exp2; mod exp2f; mod expf; mod fabs; @@ -49,6 +50,7 @@ pub use self::ceil::ceil; pub use self::ceilf::ceilf; pub use self::cosf::cosf; pub use self::exp::exp; +pub use self::exp2::exp2; pub use self::exp2f::exp2f; pub use self::expf::expf; pub use self::fabs::fabs; diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index dfe912a508b0f..e33f120a71289 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -704,7 +704,7 @@ f64_f64! { // cos, // cosh, exp, - // exp2, + exp2, // expm1, floor, log, From c3d29246bbc6c6ac1017c4992d14ffc64146a4d0 Mon Sep 17 00:00:00 2001 From: C Jones Date: Sat, 14 Jul 2018 15:04:16 -0400 Subject: [PATCH 0541/4206] DRY up the exp2 and exp2f data tables --- .../compiler-builtins/libm/src/math/exp2.rs | 526 +++++++++--------- .../compiler-builtins/libm/src/math/exp2f.rs | 40 +- 2 files changed, 283 insertions(+), 283 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs index c5bd3608a4398..61bfd1015d214 100644 --- a/library/compiler-builtins/libm/src/math/exp2.rs +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -28,6 +28,267 @@ use super::scalbn::scalbn; const TBLSIZE: usize = 256; +#[cfg_attr(rustfmt, rustfmt_skip)] +static TBL: [u64; TBLSIZE * 2] = [ + // exp2(z + eps) eps + 0x3fe6a09e667f3d5d, 0x3d39880000000000, + 0x3fe6b052fa751744, 0x3cd8000000000000, + 0x3fe6c012750bd9fe, 0xbd28780000000000, + 0x3fe6cfdcddd476bf, 0x3d1ec00000000000, + 0x3fe6dfb23c651a29, 0xbcd8000000000000, + 0x3fe6ef9298593ae3, 0xbcbc000000000000, + 0x3fe6ff7df9519386, 0xbd2fd80000000000, + 0x3fe70f7466f42da3, 0xbd2c880000000000, + 0x3fe71f75e8ec5fc3, 0x3d13c00000000000, + 0x3fe72f8286eacf05, 0xbd38300000000000, + 0x3fe73f9a48a58152, 0xbd00c00000000000, + 0x3fe74fbd35d7ccfc, 0x3d2f880000000000, + 0x3fe75feb564267f1, 0x3d03e00000000000, + 0x3fe77024b1ab6d48, 0xbd27d00000000000, + 0x3fe780694fde5d38, 0xbcdd000000000000, + 0x3fe790b938ac1d00, 0x3ce3000000000000, + 0x3fe7a11473eb0178, 0xbced000000000000, + 0x3fe7b17b0976d060, 0x3d20400000000000, + 0x3fe7c1ed0130c133, 0x3ca0000000000000, + 0x3fe7d26a62ff8636, 0xbd26900000000000, + 0x3fe7e2f336cf4e3b, 0xbd02e00000000000, + 0x3fe7f3878491c3e8, 0xbd24580000000000, + 0x3fe80427543e1b4e, 0x3d33000000000000, + 0x3fe814d2add1071a, 0x3d0f000000000000, + 0x3fe82589994ccd7e, 0xbd21c00000000000, + 0x3fe8364c1eb942d0, 0x3d29d00000000000, + 0x3fe8471a4623cab5, 0x3d47100000000000, + 0x3fe857f4179f5bbc, 0x3d22600000000000, + 0x3fe868d99b4491af, 0xbd32c40000000000, + 0x3fe879cad931a395, 0xbd23000000000000, + 0x3fe88ac7d98a65b8, 0xbd2a800000000000, + 0x3fe89bd0a4785800, 0xbced000000000000, + 0x3fe8ace5422aa223, 0x3d33280000000000, + 0x3fe8be05bad619fa, 0x3d42b40000000000, + 0x3fe8cf3216b54383, 0xbd2ed00000000000, + 0x3fe8e06a5e08664c, 0xbd20500000000000, + 0x3fe8f1ae99157807, 0x3d28280000000000, + 0x3fe902fed0282c0e, 0xbd1cb00000000000, + 0x3fe9145b0b91ff96, 0xbd05e00000000000, + 0x3fe925c353aa2ff9, 0x3cf5400000000000, + 0x3fe93737b0cdc64a, 0x3d17200000000000, + 0x3fe948b82b5f98ae, 0xbd09000000000000, + 0x3fe95a44cbc852cb, 0x3d25680000000000, + 0x3fe96bdd9a766f21, 0xbd36d00000000000, + 0x3fe97d829fde4e2a, 0xbd01000000000000, + 0x3fe98f33e47a23a3, 0x3d2d000000000000, + 0x3fe9a0f170ca0604, 0xbd38a40000000000, + 0x3fe9b2bb4d53ff89, 0x3d355c0000000000, + 0x3fe9c49182a3f15b, 0x3d26b80000000000, + 0x3fe9d674194bb8c5, 0xbcec000000000000, + 0x3fe9e86319e3238e, 0x3d17d00000000000, + 0x3fe9fa5e8d07f302, 0x3d16400000000000, + 0x3fea0c667b5de54d, 0xbcf5000000000000, + 0x3fea1e7aed8eb8f6, 0x3d09e00000000000, + 0x3fea309bec4a2e27, 0x3d2ad80000000000, + 0x3fea42c980460a5d, 0xbd1af00000000000, + 0x3fea5503b23e259b, 0x3d0b600000000000, + 0x3fea674a8af46213, 0x3d38880000000000, + 0x3fea799e1330b3a7, 0x3d11200000000000, + 0x3fea8bfe53c12e8d, 0x3d06c00000000000, + 0x3fea9e6b5579fcd2, 0xbd29b80000000000, + 0x3feab0e521356fb8, 0x3d2b700000000000, + 0x3feac36bbfd3f381, 0x3cd9000000000000, + 0x3fead5ff3a3c2780, 0x3ce4000000000000, + 0x3feae89f995ad2a3, 0xbd2c900000000000, + 0x3feafb4ce622f367, 0x3d16500000000000, + 0x3feb0e07298db790, 0x3d2fd40000000000, + 0x3feb20ce6c9a89a9, 0x3d12700000000000, + 0x3feb33a2b84f1a4b, 0x3d4d470000000000, + 0x3feb468415b747e7, 0xbd38380000000000, + 0x3feb59728de5593a, 0x3c98000000000000, + 0x3feb6c6e29f1c56a, 0x3d0ad00000000000, + 0x3feb7f76f2fb5e50, 0x3cde800000000000, + 0x3feb928cf22749b2, 0xbd04c00000000000, + 0x3feba5b030a10603, 0xbd0d700000000000, + 0x3febb8e0b79a6f66, 0x3d0d900000000000, + 0x3febcc1e904bc1ff, 0x3d02a00000000000, + 0x3febdf69c3f3a16f, 0xbd1f780000000000, + 0x3febf2c25bd71db8, 0xbd10a00000000000, + 0x3fec06286141b2e9, 0xbd11400000000000, + 0x3fec199bdd8552e0, 0x3d0be00000000000, + 0x3fec2d1cd9fa64ee, 0xbd09400000000000, + 0x3fec40ab5fffd02f, 0xbd0ed00000000000, + 0x3fec544778fafd15, 0x3d39660000000000, + 0x3fec67f12e57d0cb, 0xbd1a100000000000, + 0x3fec7ba88988c1b6, 0xbd58458000000000, + 0x3fec8f6d9406e733, 0xbd1a480000000000, + 0x3feca3405751c4df, 0x3ccb000000000000, + 0x3fecb720dcef9094, 0x3d01400000000000, + 0x3feccb0f2e6d1689, 0x3cf0200000000000, + 0x3fecdf0b555dc412, 0x3cf3600000000000, + 0x3fecf3155b5bab3b, 0xbd06900000000000, + 0x3fed072d4a0789bc, 0x3d09a00000000000, + 0x3fed1b532b08c8fa, 0xbd15e00000000000, + 0x3fed2f87080d8a85, 0x3d1d280000000000, + 0x3fed43c8eacaa203, 0x3d01a00000000000, + 0x3fed5818dcfba491, 0x3cdf000000000000, + 0x3fed6c76e862e6a1, 0xbd03a00000000000, + 0x3fed80e316c9834e, 0xbd0cd80000000000, + 0x3fed955d71ff6090, 0x3cf4c00000000000, + 0x3feda9e603db32ae, 0x3cff900000000000, + 0x3fedbe7cd63a8325, 0x3ce9800000000000, + 0x3fedd321f301b445, 0xbcf5200000000000, + 0x3fede7d5641c05bf, 0xbd1d700000000000, + 0x3fedfc97337b9aec, 0xbd16140000000000, + 0x3fee11676b197d5e, 0x3d0b480000000000, + 0x3fee264614f5a3e7, 0x3d40ce0000000000, + 0x3fee3b333b16ee5c, 0x3d0c680000000000, + 0x3fee502ee78b3fb4, 0xbd09300000000000, + 0x3fee653924676d68, 0xbce5000000000000, + 0x3fee7a51fbc74c44, 0xbd07f80000000000, + 0x3fee8f7977cdb726, 0xbcf3700000000000, + 0x3feea4afa2a490e8, 0x3ce5d00000000000, + 0x3feeb9f4867ccae4, 0x3d161a0000000000, + 0x3feecf482d8e680d, 0x3cf5500000000000, + 0x3feee4aaa2188514, 0x3cc6400000000000, + 0x3feefa1bee615a13, 0xbcee800000000000, + 0x3fef0f9c1cb64106, 0xbcfa880000000000, + 0x3fef252b376bb963, 0xbd2c900000000000, + 0x3fef3ac948dd7275, 0x3caa000000000000, + 0x3fef50765b6e4524, 0xbcf4f00000000000, + 0x3fef6632798844fd, 0x3cca800000000000, + 0x3fef7bfdad9cbe38, 0x3cfabc0000000000, + 0x3fef91d802243c82, 0xbcd4600000000000, + 0x3fefa7c1819e908e, 0xbd0b0c0000000000, + 0x3fefbdba3692d511, 0xbcc0e00000000000, + 0x3fefd3c22b8f7194, 0xbd10de8000000000, + 0x3fefe9d96b2a23ee, 0x3cee430000000000, + 0x3ff0000000000000, 0x0, + 0x3ff00b1afa5abcbe, 0xbcb3400000000000, + 0x3ff0163da9fb3303, 0xbd12170000000000, + 0x3ff02168143b0282, 0x3cba400000000000, + 0x3ff02c9a3e77806c, 0x3cef980000000000, + 0x3ff037d42e11bbca, 0xbcc7400000000000, + 0x3ff04315e86e7f89, 0x3cd8300000000000, + 0x3ff04e5f72f65467, 0xbd1a3f0000000000, + 0x3ff059b0d315855a, 0xbd02840000000000, + 0x3ff0650a0e3c1f95, 0x3cf1600000000000, + 0x3ff0706b29ddf71a, 0x3d15240000000000, + 0x3ff07bd42b72a82d, 0xbce9a00000000000, + 0x3ff0874518759bd0, 0x3ce6400000000000, + 0x3ff092bdf66607c8, 0xbd00780000000000, + 0x3ff09e3ecac6f383, 0xbc98000000000000, + 0x3ff0a9c79b1f3930, 0x3cffa00000000000, + 0x3ff0b5586cf988fc, 0xbcfac80000000000, + 0x3ff0c0f145e46c8a, 0x3cd9c00000000000, + 0x3ff0cc922b724816, 0x3d05200000000000, + 0x3ff0d83b23395dd8, 0xbcfad00000000000, + 0x3ff0e3ec32d3d1f3, 0x3d1bac0000000000, + 0x3ff0efa55fdfa9a6, 0xbd04e80000000000, + 0x3ff0fb66affed2f0, 0xbd0d300000000000, + 0x3ff1073028d7234b, 0x3cf1500000000000, + 0x3ff11301d0125b5b, 0x3cec000000000000, + 0x3ff11edbab5e2af9, 0x3d16bc0000000000, + 0x3ff12abdc06c31d5, 0x3ce8400000000000, + 0x3ff136a814f2047d, 0xbd0ed00000000000, + 0x3ff1429aaea92de9, 0x3ce8e00000000000, + 0x3ff14e95934f3138, 0x3ceb400000000000, + 0x3ff15a98c8a58e71, 0x3d05300000000000, + 0x3ff166a45471c3df, 0x3d03380000000000, + 0x3ff172b83c7d5211, 0x3d28d40000000000, + 0x3ff17ed48695bb9f, 0xbd05d00000000000, + 0x3ff18af9388c8d93, 0xbd1c880000000000, + 0x3ff1972658375d66, 0x3d11f00000000000, + 0x3ff1a35beb6fcba7, 0x3d10480000000000, + 0x3ff1af99f81387e3, 0xbd47390000000000, + 0x3ff1bbe084045d54, 0x3d24e40000000000, + 0x3ff1c82f95281c43, 0xbd0a200000000000, + 0x3ff1d4873168b9b2, 0x3ce3800000000000, + 0x3ff1e0e75eb44031, 0x3ceac00000000000, + 0x3ff1ed5022fcd938, 0x3d01900000000000, + 0x3ff1f9c18438cdf7, 0xbd1b780000000000, + 0x3ff2063b88628d8f, 0x3d2d940000000000, + 0x3ff212be3578a81e, 0x3cd8000000000000, + 0x3ff21f49917ddd41, 0x3d2b340000000000, + 0x3ff22bdda2791323, 0x3d19f80000000000, + 0x3ff2387a6e7561e7, 0xbd19c80000000000, + 0x3ff2451ffb821427, 0x3d02300000000000, + 0x3ff251ce4fb2a602, 0xbd13480000000000, + 0x3ff25e85711eceb0, 0x3d12700000000000, + 0x3ff26b4565e27d16, 0x3d11d00000000000, + 0x3ff2780e341de00f, 0x3d31ee0000000000, + 0x3ff284dfe1f5633e, 0xbd14c00000000000, + 0x3ff291ba7591bb30, 0xbd13d80000000000, + 0x3ff29e9df51fdf09, 0x3d08b00000000000, + 0x3ff2ab8a66d10e9b, 0xbd227c0000000000, + 0x3ff2b87fd0dada3a, 0x3d2a340000000000, + 0x3ff2c57e39771af9, 0xbd10800000000000, + 0x3ff2d285a6e402d9, 0xbd0ed00000000000, + 0x3ff2df961f641579, 0xbcf4200000000000, + 0x3ff2ecafa93e2ecf, 0xbd24980000000000, + 0x3ff2f9d24abd8822, 0xbd16300000000000, + 0x3ff306fe0a31b625, 0xbd32360000000000, + 0x3ff31432edeea50b, 0xbd70df8000000000, + 0x3ff32170fc4cd7b8, 0xbd22480000000000, + 0x3ff32eb83ba8e9a2, 0xbd25980000000000, + 0x3ff33c08b2641766, 0x3d1ed00000000000, + 0x3ff3496266e3fa27, 0xbcdc000000000000, + 0x3ff356c55f929f0f, 0xbd30d80000000000, + 0x3ff36431a2de88b9, 0x3d22c80000000000, + 0x3ff371a7373aaa39, 0x3d20600000000000, + 0x3ff37f26231e74fe, 0xbd16600000000000, + 0x3ff38cae6d05d838, 0xbd0ae00000000000, + 0x3ff39a401b713ec3, 0xbd44720000000000, + 0x3ff3a7db34e5a020, 0x3d08200000000000, + 0x3ff3b57fbfec6e95, 0x3d3e800000000000, + 0x3ff3c32dc313a8f2, 0x3cef800000000000, + 0x3ff3d0e544ede122, 0xbd17a00000000000, + 0x3ff3dea64c1234bb, 0x3d26300000000000, + 0x3ff3ec70df1c4ecc, 0xbd48a60000000000, + 0x3ff3fa4504ac7e8c, 0xbd3cdc0000000000, + 0x3ff40822c367a0bb, 0x3d25b80000000000, + 0x3ff4160a21f72e95, 0x3d1ec00000000000, + 0x3ff423fb27094646, 0xbd13600000000000, + 0x3ff431f5d950a920, 0x3d23980000000000, + 0x3ff43ffa3f84b9eb, 0x3cfa000000000000, + 0x3ff44e0860618919, 0xbcf6c00000000000, + 0x3ff45c2042a7d201, 0xbd0bc00000000000, + 0x3ff46a41ed1d0016, 0xbd12800000000000, + 0x3ff4786d668b3326, 0x3d30e00000000000, + 0x3ff486a2b5c13c00, 0xbd2d400000000000, + 0x3ff494e1e192af04, 0x3d0c200000000000, + 0x3ff4a32af0d7d372, 0xbd1e500000000000, + 0x3ff4b17dea6db801, 0x3d07800000000000, + 0x3ff4bfdad53629e1, 0xbd13800000000000, + 0x3ff4ce41b817c132, 0x3d00800000000000, + 0x3ff4dcb299fddddb, 0x3d2c700000000000, + 0x3ff4eb2d81d8ab96, 0xbd1ce00000000000, + 0x3ff4f9b2769d2d02, 0x3d19200000000000, + 0x3ff508417f4531c1, 0xbd08c00000000000, + 0x3ff516daa2cf662a, 0xbcfa000000000000, + 0x3ff5257de83f51ea, 0x3d4a080000000000, + 0x3ff5342b569d4eda, 0xbd26d80000000000, + 0x3ff542e2f4f6ac1a, 0xbd32440000000000, + 0x3ff551a4ca5d94db, 0x3d483c0000000000, + 0x3ff56070dde9116b, 0x3d24b00000000000, + 0x3ff56f4736b529de, 0x3d415a0000000000, + 0x3ff57e27dbe2c40e, 0xbd29e00000000000, + 0x3ff58d12d497c76f, 0xbd23080000000000, + 0x3ff59c0827ff0b4c, 0x3d4dec0000000000, + 0x3ff5ab07dd485427, 0xbcc4000000000000, + 0x3ff5ba11fba87af4, 0x3d30080000000000, + 0x3ff5c9268a59460b, 0xbd26c80000000000, + 0x3ff5d84590998e3f, 0x3d469a0000000000, + 0x3ff5e76f15ad20e1, 0xbd1b400000000000, + 0x3ff5f6a320dcebca, 0x3d17700000000000, + 0x3ff605e1b976dcb8, 0x3d26f80000000000, + 0x3ff6152ae6cdf715, 0x3d01000000000000, + 0x3ff6247eb03a5531, 0xbd15d00000000000, + 0x3ff633dd1d1929b5, 0xbd12d00000000000, + 0x3ff6434634ccc313, 0xbcea800000000000, + 0x3ff652b9febc8efa, 0xbd28600000000000, + 0x3ff6623882553397, 0x3d71fe0000000000, + 0x3ff671c1c708328e, 0xbd37200000000000, + 0x3ff68155d44ca97e, 0x3ce6800000000000, + 0x3ff690f4b19e9471, 0xbd29780000000000, +]; + // exp2(x): compute the base 2 exponential of x // // Accuracy: Peak error < 0.503 ulp for normalized results. @@ -65,267 +326,6 @@ pub fn exp2(mut x: f64) -> f64 { let p4 = f64::from_bits(0x3f83b2ab88f70400); let p5 = f64::from_bits(0x3f55d88003875c74); - #[cfg_attr(rustfmt, rustfmt_skip)] - let tbl = [ - // exp2(z + eps) eps - f64::from_bits(0x3fe6a09e667f3d5d), f64::from_bits(0x3d39880000000000), - f64::from_bits(0x3fe6b052fa751744), f64::from_bits(0x3cd8000000000000), - f64::from_bits(0x3fe6c012750bd9fe), f64::from_bits(0xbd28780000000000), - f64::from_bits(0x3fe6cfdcddd476bf), f64::from_bits(0x3d1ec00000000000), - f64::from_bits(0x3fe6dfb23c651a29), f64::from_bits(0xbcd8000000000000), - f64::from_bits(0x3fe6ef9298593ae3), f64::from_bits(0xbcbc000000000000), - f64::from_bits(0x3fe6ff7df9519386), f64::from_bits(0xbd2fd80000000000), - f64::from_bits(0x3fe70f7466f42da3), f64::from_bits(0xbd2c880000000000), - f64::from_bits(0x3fe71f75e8ec5fc3), f64::from_bits(0x3d13c00000000000), - f64::from_bits(0x3fe72f8286eacf05), f64::from_bits(0xbd38300000000000), - f64::from_bits(0x3fe73f9a48a58152), f64::from_bits(0xbd00c00000000000), - f64::from_bits(0x3fe74fbd35d7ccfc), f64::from_bits(0x3d2f880000000000), - f64::from_bits(0x3fe75feb564267f1), f64::from_bits(0x3d03e00000000000), - f64::from_bits(0x3fe77024b1ab6d48), f64::from_bits(0xbd27d00000000000), - f64::from_bits(0x3fe780694fde5d38), f64::from_bits(0xbcdd000000000000), - f64::from_bits(0x3fe790b938ac1d00), f64::from_bits(0x3ce3000000000000), - f64::from_bits(0x3fe7a11473eb0178), f64::from_bits(0xbced000000000000), - f64::from_bits(0x3fe7b17b0976d060), f64::from_bits(0x3d20400000000000), - f64::from_bits(0x3fe7c1ed0130c133), f64::from_bits(0x3ca0000000000000), - f64::from_bits(0x3fe7d26a62ff8636), f64::from_bits(0xbd26900000000000), - f64::from_bits(0x3fe7e2f336cf4e3b), f64::from_bits(0xbd02e00000000000), - f64::from_bits(0x3fe7f3878491c3e8), f64::from_bits(0xbd24580000000000), - f64::from_bits(0x3fe80427543e1b4e), f64::from_bits(0x3d33000000000000), - f64::from_bits(0x3fe814d2add1071a), f64::from_bits(0x3d0f000000000000), - f64::from_bits(0x3fe82589994ccd7e), f64::from_bits(0xbd21c00000000000), - f64::from_bits(0x3fe8364c1eb942d0), f64::from_bits(0x3d29d00000000000), - f64::from_bits(0x3fe8471a4623cab5), f64::from_bits(0x3d47100000000000), - f64::from_bits(0x3fe857f4179f5bbc), f64::from_bits(0x3d22600000000000), - f64::from_bits(0x3fe868d99b4491af), f64::from_bits(0xbd32c40000000000), - f64::from_bits(0x3fe879cad931a395), f64::from_bits(0xbd23000000000000), - f64::from_bits(0x3fe88ac7d98a65b8), f64::from_bits(0xbd2a800000000000), - f64::from_bits(0x3fe89bd0a4785800), f64::from_bits(0xbced000000000000), - f64::from_bits(0x3fe8ace5422aa223), f64::from_bits(0x3d33280000000000), - f64::from_bits(0x3fe8be05bad619fa), f64::from_bits(0x3d42b40000000000), - f64::from_bits(0x3fe8cf3216b54383), f64::from_bits(0xbd2ed00000000000), - f64::from_bits(0x3fe8e06a5e08664c), f64::from_bits(0xbd20500000000000), - f64::from_bits(0x3fe8f1ae99157807), f64::from_bits(0x3d28280000000000), - f64::from_bits(0x3fe902fed0282c0e), f64::from_bits(0xbd1cb00000000000), - f64::from_bits(0x3fe9145b0b91ff96), f64::from_bits(0xbd05e00000000000), - f64::from_bits(0x3fe925c353aa2ff9), f64::from_bits(0x3cf5400000000000), - f64::from_bits(0x3fe93737b0cdc64a), f64::from_bits(0x3d17200000000000), - f64::from_bits(0x3fe948b82b5f98ae), f64::from_bits(0xbd09000000000000), - f64::from_bits(0x3fe95a44cbc852cb), f64::from_bits(0x3d25680000000000), - f64::from_bits(0x3fe96bdd9a766f21), f64::from_bits(0xbd36d00000000000), - f64::from_bits(0x3fe97d829fde4e2a), f64::from_bits(0xbd01000000000000), - f64::from_bits(0x3fe98f33e47a23a3), f64::from_bits(0x3d2d000000000000), - f64::from_bits(0x3fe9a0f170ca0604), f64::from_bits(0xbd38a40000000000), - f64::from_bits(0x3fe9b2bb4d53ff89), f64::from_bits(0x3d355c0000000000), - f64::from_bits(0x3fe9c49182a3f15b), f64::from_bits(0x3d26b80000000000), - f64::from_bits(0x3fe9d674194bb8c5), f64::from_bits(0xbcec000000000000), - f64::from_bits(0x3fe9e86319e3238e), f64::from_bits(0x3d17d00000000000), - f64::from_bits(0x3fe9fa5e8d07f302), f64::from_bits(0x3d16400000000000), - f64::from_bits(0x3fea0c667b5de54d), f64::from_bits(0xbcf5000000000000), - f64::from_bits(0x3fea1e7aed8eb8f6), f64::from_bits(0x3d09e00000000000), - f64::from_bits(0x3fea309bec4a2e27), f64::from_bits(0x3d2ad80000000000), - f64::from_bits(0x3fea42c980460a5d), f64::from_bits(0xbd1af00000000000), - f64::from_bits(0x3fea5503b23e259b), f64::from_bits(0x3d0b600000000000), - f64::from_bits(0x3fea674a8af46213), f64::from_bits(0x3d38880000000000), - f64::from_bits(0x3fea799e1330b3a7), f64::from_bits(0x3d11200000000000), - f64::from_bits(0x3fea8bfe53c12e8d), f64::from_bits(0x3d06c00000000000), - f64::from_bits(0x3fea9e6b5579fcd2), f64::from_bits(0xbd29b80000000000), - f64::from_bits(0x3feab0e521356fb8), f64::from_bits(0x3d2b700000000000), - f64::from_bits(0x3feac36bbfd3f381), f64::from_bits(0x3cd9000000000000), - f64::from_bits(0x3fead5ff3a3c2780), f64::from_bits(0x3ce4000000000000), - f64::from_bits(0x3feae89f995ad2a3), f64::from_bits(0xbd2c900000000000), - f64::from_bits(0x3feafb4ce622f367), f64::from_bits(0x3d16500000000000), - f64::from_bits(0x3feb0e07298db790), f64::from_bits(0x3d2fd40000000000), - f64::from_bits(0x3feb20ce6c9a89a9), f64::from_bits(0x3d12700000000000), - f64::from_bits(0x3feb33a2b84f1a4b), f64::from_bits(0x3d4d470000000000), - f64::from_bits(0x3feb468415b747e7), f64::from_bits(0xbd38380000000000), - f64::from_bits(0x3feb59728de5593a), f64::from_bits(0x3c98000000000000), - f64::from_bits(0x3feb6c6e29f1c56a), f64::from_bits(0x3d0ad00000000000), - f64::from_bits(0x3feb7f76f2fb5e50), f64::from_bits(0x3cde800000000000), - f64::from_bits(0x3feb928cf22749b2), f64::from_bits(0xbd04c00000000000), - f64::from_bits(0x3feba5b030a10603), f64::from_bits(0xbd0d700000000000), - f64::from_bits(0x3febb8e0b79a6f66), f64::from_bits(0x3d0d900000000000), - f64::from_bits(0x3febcc1e904bc1ff), f64::from_bits(0x3d02a00000000000), - f64::from_bits(0x3febdf69c3f3a16f), f64::from_bits(0xbd1f780000000000), - f64::from_bits(0x3febf2c25bd71db8), f64::from_bits(0xbd10a00000000000), - f64::from_bits(0x3fec06286141b2e9), f64::from_bits(0xbd11400000000000), - f64::from_bits(0x3fec199bdd8552e0), f64::from_bits(0x3d0be00000000000), - f64::from_bits(0x3fec2d1cd9fa64ee), f64::from_bits(0xbd09400000000000), - f64::from_bits(0x3fec40ab5fffd02f), f64::from_bits(0xbd0ed00000000000), - f64::from_bits(0x3fec544778fafd15), f64::from_bits(0x3d39660000000000), - f64::from_bits(0x3fec67f12e57d0cb), f64::from_bits(0xbd1a100000000000), - f64::from_bits(0x3fec7ba88988c1b6), f64::from_bits(0xbd58458000000000), - f64::from_bits(0x3fec8f6d9406e733), f64::from_bits(0xbd1a480000000000), - f64::from_bits(0x3feca3405751c4df), f64::from_bits(0x3ccb000000000000), - f64::from_bits(0x3fecb720dcef9094), f64::from_bits(0x3d01400000000000), - f64::from_bits(0x3feccb0f2e6d1689), f64::from_bits(0x3cf0200000000000), - f64::from_bits(0x3fecdf0b555dc412), f64::from_bits(0x3cf3600000000000), - f64::from_bits(0x3fecf3155b5bab3b), f64::from_bits(0xbd06900000000000), - f64::from_bits(0x3fed072d4a0789bc), f64::from_bits(0x3d09a00000000000), - f64::from_bits(0x3fed1b532b08c8fa), f64::from_bits(0xbd15e00000000000), - f64::from_bits(0x3fed2f87080d8a85), f64::from_bits(0x3d1d280000000000), - f64::from_bits(0x3fed43c8eacaa203), f64::from_bits(0x3d01a00000000000), - f64::from_bits(0x3fed5818dcfba491), f64::from_bits(0x3cdf000000000000), - f64::from_bits(0x3fed6c76e862e6a1), f64::from_bits(0xbd03a00000000000), - f64::from_bits(0x3fed80e316c9834e), f64::from_bits(0xbd0cd80000000000), - f64::from_bits(0x3fed955d71ff6090), f64::from_bits(0x3cf4c00000000000), - f64::from_bits(0x3feda9e603db32ae), f64::from_bits(0x3cff900000000000), - f64::from_bits(0x3fedbe7cd63a8325), f64::from_bits(0x3ce9800000000000), - f64::from_bits(0x3fedd321f301b445), f64::from_bits(0xbcf5200000000000), - f64::from_bits(0x3fede7d5641c05bf), f64::from_bits(0xbd1d700000000000), - f64::from_bits(0x3fedfc97337b9aec), f64::from_bits(0xbd16140000000000), - f64::from_bits(0x3fee11676b197d5e), f64::from_bits(0x3d0b480000000000), - f64::from_bits(0x3fee264614f5a3e7), f64::from_bits(0x3d40ce0000000000), - f64::from_bits(0x3fee3b333b16ee5c), f64::from_bits(0x3d0c680000000000), - f64::from_bits(0x3fee502ee78b3fb4), f64::from_bits(0xbd09300000000000), - f64::from_bits(0x3fee653924676d68), f64::from_bits(0xbce5000000000000), - f64::from_bits(0x3fee7a51fbc74c44), f64::from_bits(0xbd07f80000000000), - f64::from_bits(0x3fee8f7977cdb726), f64::from_bits(0xbcf3700000000000), - f64::from_bits(0x3feea4afa2a490e8), f64::from_bits(0x3ce5d00000000000), - f64::from_bits(0x3feeb9f4867ccae4), f64::from_bits(0x3d161a0000000000), - f64::from_bits(0x3feecf482d8e680d), f64::from_bits(0x3cf5500000000000), - f64::from_bits(0x3feee4aaa2188514), f64::from_bits(0x3cc6400000000000), - f64::from_bits(0x3feefa1bee615a13), f64::from_bits(0xbcee800000000000), - f64::from_bits(0x3fef0f9c1cb64106), f64::from_bits(0xbcfa880000000000), - f64::from_bits(0x3fef252b376bb963), f64::from_bits(0xbd2c900000000000), - f64::from_bits(0x3fef3ac948dd7275), f64::from_bits(0x3caa000000000000), - f64::from_bits(0x3fef50765b6e4524), f64::from_bits(0xbcf4f00000000000), - f64::from_bits(0x3fef6632798844fd), f64::from_bits(0x3cca800000000000), - f64::from_bits(0x3fef7bfdad9cbe38), f64::from_bits(0x3cfabc0000000000), - f64::from_bits(0x3fef91d802243c82), f64::from_bits(0xbcd4600000000000), - f64::from_bits(0x3fefa7c1819e908e), f64::from_bits(0xbd0b0c0000000000), - f64::from_bits(0x3fefbdba3692d511), f64::from_bits(0xbcc0e00000000000), - f64::from_bits(0x3fefd3c22b8f7194), f64::from_bits(0xbd10de8000000000), - f64::from_bits(0x3fefe9d96b2a23ee), f64::from_bits(0x3cee430000000000), - f64::from_bits(0x3ff0000000000000), f64::from_bits(0x0), - f64::from_bits(0x3ff00b1afa5abcbe), f64::from_bits(0xbcb3400000000000), - f64::from_bits(0x3ff0163da9fb3303), f64::from_bits(0xbd12170000000000), - f64::from_bits(0x3ff02168143b0282), f64::from_bits(0x3cba400000000000), - f64::from_bits(0x3ff02c9a3e77806c), f64::from_bits(0x3cef980000000000), - f64::from_bits(0x3ff037d42e11bbca), f64::from_bits(0xbcc7400000000000), - f64::from_bits(0x3ff04315e86e7f89), f64::from_bits(0x3cd8300000000000), - f64::from_bits(0x3ff04e5f72f65467), f64::from_bits(0xbd1a3f0000000000), - f64::from_bits(0x3ff059b0d315855a), f64::from_bits(0xbd02840000000000), - f64::from_bits(0x3ff0650a0e3c1f95), f64::from_bits(0x3cf1600000000000), - f64::from_bits(0x3ff0706b29ddf71a), f64::from_bits(0x3d15240000000000), - f64::from_bits(0x3ff07bd42b72a82d), f64::from_bits(0xbce9a00000000000), - f64::from_bits(0x3ff0874518759bd0), f64::from_bits(0x3ce6400000000000), - f64::from_bits(0x3ff092bdf66607c8), f64::from_bits(0xbd00780000000000), - f64::from_bits(0x3ff09e3ecac6f383), f64::from_bits(0xbc98000000000000), - f64::from_bits(0x3ff0a9c79b1f3930), f64::from_bits(0x3cffa00000000000), - f64::from_bits(0x3ff0b5586cf988fc), f64::from_bits(0xbcfac80000000000), - f64::from_bits(0x3ff0c0f145e46c8a), f64::from_bits(0x3cd9c00000000000), - f64::from_bits(0x3ff0cc922b724816), f64::from_bits(0x3d05200000000000), - f64::from_bits(0x3ff0d83b23395dd8), f64::from_bits(0xbcfad00000000000), - f64::from_bits(0x3ff0e3ec32d3d1f3), f64::from_bits(0x3d1bac0000000000), - f64::from_bits(0x3ff0efa55fdfa9a6), f64::from_bits(0xbd04e80000000000), - f64::from_bits(0x3ff0fb66affed2f0), f64::from_bits(0xbd0d300000000000), - f64::from_bits(0x3ff1073028d7234b), f64::from_bits(0x3cf1500000000000), - f64::from_bits(0x3ff11301d0125b5b), f64::from_bits(0x3cec000000000000), - f64::from_bits(0x3ff11edbab5e2af9), f64::from_bits(0x3d16bc0000000000), - f64::from_bits(0x3ff12abdc06c31d5), f64::from_bits(0x3ce8400000000000), - f64::from_bits(0x3ff136a814f2047d), f64::from_bits(0xbd0ed00000000000), - f64::from_bits(0x3ff1429aaea92de9), f64::from_bits(0x3ce8e00000000000), - f64::from_bits(0x3ff14e95934f3138), f64::from_bits(0x3ceb400000000000), - f64::from_bits(0x3ff15a98c8a58e71), f64::from_bits(0x3d05300000000000), - f64::from_bits(0x3ff166a45471c3df), f64::from_bits(0x3d03380000000000), - f64::from_bits(0x3ff172b83c7d5211), f64::from_bits(0x3d28d40000000000), - f64::from_bits(0x3ff17ed48695bb9f), f64::from_bits(0xbd05d00000000000), - f64::from_bits(0x3ff18af9388c8d93), f64::from_bits(0xbd1c880000000000), - f64::from_bits(0x3ff1972658375d66), f64::from_bits(0x3d11f00000000000), - f64::from_bits(0x3ff1a35beb6fcba7), f64::from_bits(0x3d10480000000000), - f64::from_bits(0x3ff1af99f81387e3), f64::from_bits(0xbd47390000000000), - f64::from_bits(0x3ff1bbe084045d54), f64::from_bits(0x3d24e40000000000), - f64::from_bits(0x3ff1c82f95281c43), f64::from_bits(0xbd0a200000000000), - f64::from_bits(0x3ff1d4873168b9b2), f64::from_bits(0x3ce3800000000000), - f64::from_bits(0x3ff1e0e75eb44031), f64::from_bits(0x3ceac00000000000), - f64::from_bits(0x3ff1ed5022fcd938), f64::from_bits(0x3d01900000000000), - f64::from_bits(0x3ff1f9c18438cdf7), f64::from_bits(0xbd1b780000000000), - f64::from_bits(0x3ff2063b88628d8f), f64::from_bits(0x3d2d940000000000), - f64::from_bits(0x3ff212be3578a81e), f64::from_bits(0x3cd8000000000000), - f64::from_bits(0x3ff21f49917ddd41), f64::from_bits(0x3d2b340000000000), - f64::from_bits(0x3ff22bdda2791323), f64::from_bits(0x3d19f80000000000), - f64::from_bits(0x3ff2387a6e7561e7), f64::from_bits(0xbd19c80000000000), - f64::from_bits(0x3ff2451ffb821427), f64::from_bits(0x3d02300000000000), - f64::from_bits(0x3ff251ce4fb2a602), f64::from_bits(0xbd13480000000000), - f64::from_bits(0x3ff25e85711eceb0), f64::from_bits(0x3d12700000000000), - f64::from_bits(0x3ff26b4565e27d16), f64::from_bits(0x3d11d00000000000), - f64::from_bits(0x3ff2780e341de00f), f64::from_bits(0x3d31ee0000000000), - f64::from_bits(0x3ff284dfe1f5633e), f64::from_bits(0xbd14c00000000000), - f64::from_bits(0x3ff291ba7591bb30), f64::from_bits(0xbd13d80000000000), - f64::from_bits(0x3ff29e9df51fdf09), f64::from_bits(0x3d08b00000000000), - f64::from_bits(0x3ff2ab8a66d10e9b), f64::from_bits(0xbd227c0000000000), - f64::from_bits(0x3ff2b87fd0dada3a), f64::from_bits(0x3d2a340000000000), - f64::from_bits(0x3ff2c57e39771af9), f64::from_bits(0xbd10800000000000), - f64::from_bits(0x3ff2d285a6e402d9), f64::from_bits(0xbd0ed00000000000), - f64::from_bits(0x3ff2df961f641579), f64::from_bits(0xbcf4200000000000), - f64::from_bits(0x3ff2ecafa93e2ecf), f64::from_bits(0xbd24980000000000), - f64::from_bits(0x3ff2f9d24abd8822), f64::from_bits(0xbd16300000000000), - f64::from_bits(0x3ff306fe0a31b625), f64::from_bits(0xbd32360000000000), - f64::from_bits(0x3ff31432edeea50b), f64::from_bits(0xbd70df8000000000), - f64::from_bits(0x3ff32170fc4cd7b8), f64::from_bits(0xbd22480000000000), - f64::from_bits(0x3ff32eb83ba8e9a2), f64::from_bits(0xbd25980000000000), - f64::from_bits(0x3ff33c08b2641766), f64::from_bits(0x3d1ed00000000000), - f64::from_bits(0x3ff3496266e3fa27), f64::from_bits(0xbcdc000000000000), - f64::from_bits(0x3ff356c55f929f0f), f64::from_bits(0xbd30d80000000000), - f64::from_bits(0x3ff36431a2de88b9), f64::from_bits(0x3d22c80000000000), - f64::from_bits(0x3ff371a7373aaa39), f64::from_bits(0x3d20600000000000), - f64::from_bits(0x3ff37f26231e74fe), f64::from_bits(0xbd16600000000000), - f64::from_bits(0x3ff38cae6d05d838), f64::from_bits(0xbd0ae00000000000), - f64::from_bits(0x3ff39a401b713ec3), f64::from_bits(0xbd44720000000000), - f64::from_bits(0x3ff3a7db34e5a020), f64::from_bits(0x3d08200000000000), - f64::from_bits(0x3ff3b57fbfec6e95), f64::from_bits(0x3d3e800000000000), - f64::from_bits(0x3ff3c32dc313a8f2), f64::from_bits(0x3cef800000000000), - f64::from_bits(0x3ff3d0e544ede122), f64::from_bits(0xbd17a00000000000), - f64::from_bits(0x3ff3dea64c1234bb), f64::from_bits(0x3d26300000000000), - f64::from_bits(0x3ff3ec70df1c4ecc), f64::from_bits(0xbd48a60000000000), - f64::from_bits(0x3ff3fa4504ac7e8c), f64::from_bits(0xbd3cdc0000000000), - f64::from_bits(0x3ff40822c367a0bb), f64::from_bits(0x3d25b80000000000), - f64::from_bits(0x3ff4160a21f72e95), f64::from_bits(0x3d1ec00000000000), - f64::from_bits(0x3ff423fb27094646), f64::from_bits(0xbd13600000000000), - f64::from_bits(0x3ff431f5d950a920), f64::from_bits(0x3d23980000000000), - f64::from_bits(0x3ff43ffa3f84b9eb), f64::from_bits(0x3cfa000000000000), - f64::from_bits(0x3ff44e0860618919), f64::from_bits(0xbcf6c00000000000), - f64::from_bits(0x3ff45c2042a7d201), f64::from_bits(0xbd0bc00000000000), - f64::from_bits(0x3ff46a41ed1d0016), f64::from_bits(0xbd12800000000000), - f64::from_bits(0x3ff4786d668b3326), f64::from_bits(0x3d30e00000000000), - f64::from_bits(0x3ff486a2b5c13c00), f64::from_bits(0xbd2d400000000000), - f64::from_bits(0x3ff494e1e192af04), f64::from_bits(0x3d0c200000000000), - f64::from_bits(0x3ff4a32af0d7d372), f64::from_bits(0xbd1e500000000000), - f64::from_bits(0x3ff4b17dea6db801), f64::from_bits(0x3d07800000000000), - f64::from_bits(0x3ff4bfdad53629e1), f64::from_bits(0xbd13800000000000), - f64::from_bits(0x3ff4ce41b817c132), f64::from_bits(0x3d00800000000000), - f64::from_bits(0x3ff4dcb299fddddb), f64::from_bits(0x3d2c700000000000), - f64::from_bits(0x3ff4eb2d81d8ab96), f64::from_bits(0xbd1ce00000000000), - f64::from_bits(0x3ff4f9b2769d2d02), f64::from_bits(0x3d19200000000000), - f64::from_bits(0x3ff508417f4531c1), f64::from_bits(0xbd08c00000000000), - f64::from_bits(0x3ff516daa2cf662a), f64::from_bits(0xbcfa000000000000), - f64::from_bits(0x3ff5257de83f51ea), f64::from_bits(0x3d4a080000000000), - f64::from_bits(0x3ff5342b569d4eda), f64::from_bits(0xbd26d80000000000), - f64::from_bits(0x3ff542e2f4f6ac1a), f64::from_bits(0xbd32440000000000), - f64::from_bits(0x3ff551a4ca5d94db), f64::from_bits(0x3d483c0000000000), - f64::from_bits(0x3ff56070dde9116b), f64::from_bits(0x3d24b00000000000), - f64::from_bits(0x3ff56f4736b529de), f64::from_bits(0x3d415a0000000000), - f64::from_bits(0x3ff57e27dbe2c40e), f64::from_bits(0xbd29e00000000000), - f64::from_bits(0x3ff58d12d497c76f), f64::from_bits(0xbd23080000000000), - f64::from_bits(0x3ff59c0827ff0b4c), f64::from_bits(0x3d4dec0000000000), - f64::from_bits(0x3ff5ab07dd485427), f64::from_bits(0xbcc4000000000000), - f64::from_bits(0x3ff5ba11fba87af4), f64::from_bits(0x3d30080000000000), - f64::from_bits(0x3ff5c9268a59460b), f64::from_bits(0xbd26c80000000000), - f64::from_bits(0x3ff5d84590998e3f), f64::from_bits(0x3d469a0000000000), - f64::from_bits(0x3ff5e76f15ad20e1), f64::from_bits(0xbd1b400000000000), - f64::from_bits(0x3ff5f6a320dcebca), f64::from_bits(0x3d17700000000000), - f64::from_bits(0x3ff605e1b976dcb8), f64::from_bits(0x3d26f80000000000), - f64::from_bits(0x3ff6152ae6cdf715), f64::from_bits(0x3d01000000000000), - f64::from_bits(0x3ff6247eb03a5531), f64::from_bits(0xbd15d00000000000), - f64::from_bits(0x3ff633dd1d1929b5), f64::from_bits(0xbd12d00000000000), - f64::from_bits(0x3ff6434634ccc313), f64::from_bits(0xbcea800000000000), - f64::from_bits(0x3ff652b9febc8efa), f64::from_bits(0xbd28600000000000), - f64::from_bits(0x3ff6623882553397), f64::from_bits(0x3d71fe0000000000), - f64::from_bits(0x3ff671c1c708328e), f64::from_bits(0xbd37200000000000), - f64::from_bits(0x3ff68155d44ca97e), f64::from_bits(0x3ce6800000000000), - f64::from_bits(0x3ff690f4b19e9471), f64::from_bits(0xbd29780000000000), - ]; - // double_t r, t, z; // uint32_t ix, i0; // union {double f; uint64_t i;} u = {x}; @@ -375,8 +375,8 @@ pub fn exp2(mut x: f64) -> f64 { let mut z = x - uf; /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ - let t = tbl[2 * i0 as usize]; /* exp2t[i0] */ - z -= tbl[2 * i0 as usize + 1]; /* eps[i0] */ + let t = f64::from_bits(TBL[2 * i0 as usize]); /* exp2t[i0] */ + z -= f64::from_bits(TBL[2 * i0 as usize + 1]); /* eps[i0] */ let r = t + t * z * (p1 + z * (p2 + z * (p3 + z * (p4 + z * p5)))); scalbn(r, ki) diff --git a/library/compiler-builtins/libm/src/math/exp2f.rs b/library/compiler-builtins/libm/src/math/exp2f.rs index 947679a8389d3..79929ce90e067 100644 --- a/library/compiler-builtins/libm/src/math/exp2f.rs +++ b/library/compiler-builtins/libm/src/math/exp2f.rs @@ -26,6 +26,25 @@ const TBLSIZE: usize = 16; +static EXP2FT: [u64; TBLSIZE] = [ + 0x3fe6a09e667f3bcd, + 0x3fe7a11473eb0187, + 0x3fe8ace5422aa0db, + 0x3fe9c49182a3f090, + 0x3feae89f995ad3ad, + 0x3fec199bdd85529c, + 0x3fed5818dcfba487, + 0x3feea4afa2a490da, + 0x3ff0000000000000, + 0x3ff0b5586cf9890f, + 0x3ff172b83c7d517b, + 0x3ff2387a6e756238, + 0x3ff306fe0a31b715, + 0x3ff3dea64c123422, + 0x3ff4bfdad5362a27, + 0x3ff5ab07dd485429, +]; + // exp2f(x): compute the base 2 exponential of x // // Accuracy: Peak error < 0.501 ulp; location of peak: -0.030110927. @@ -57,25 +76,6 @@ pub fn exp2f(mut x: f32) -> f32 { let p3 = f32::from_bits(0x3d6359a4); let p4 = f32::from_bits(0x3c1d964e); - let exp2ft: [f64; TBLSIZE] = [ - f64::from_bits(0x3fe6a09e667f3bcd), - f64::from_bits(0x3fe7a11473eb0187), - f64::from_bits(0x3fe8ace5422aa0db), - f64::from_bits(0x3fe9c49182a3f090), - f64::from_bits(0x3feae89f995ad3ad), - f64::from_bits(0x3fec199bdd85529c), - f64::from_bits(0x3fed5818dcfba487), - f64::from_bits(0x3feea4afa2a490da), - f64::from_bits(0x3ff0000000000000), - f64::from_bits(0x3ff0b5586cf9890f), - f64::from_bits(0x3ff172b83c7d517b), - f64::from_bits(0x3ff2387a6e756238), - f64::from_bits(0x3ff306fe0a31b715), - f64::from_bits(0x3ff3dea64c123422), - f64::from_bits(0x3ff4bfdad5362a27), - f64::from_bits(0x3ff5ab07dd485429), - ]; - // double_t t, r, z; // uint32_t ix, i0, k; @@ -121,7 +121,7 @@ pub fn exp2f(mut x: f32) -> f32 { uf -= redux; let z: f64 = (x - uf) as f64; /* Compute r = exp2(y) = exp2ft[i0] * p(z). */ - let r: f64 = exp2ft[i0 as usize]; + let r: f64 = f64::from_bits(EXP2FT[i0 as usize]); let t: f64 = r as f64 * z; let r: f64 = r + t * (p1 as f64 + z * p2 as f64) + t * (z * z) * (p3 as f64 + z * p4 as f64); From a60a31ab9017209b8359dc5c97649faecb7b99f6 Mon Sep 17 00:00:00 2001 From: C Jones Date: Sat, 14 Jul 2018 15:25:09 -0400 Subject: [PATCH 0542/4206] Add some extra notes to CONTRIBUTING --- library/compiler-builtins/libm/CONTRIBUTING.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md index 6f8e984f3004a..680c40e80e7d8 100644 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -28,7 +28,7 @@ Check [PR #65] for an example. have any external dependencies (other than `core` itself). - Only use relative imports within the `math` directory / module, e.g. `use self::fabs::fabs` or -`use super::isnanf`. Absolute imports from core are OK, e.g. `use core::u64`. +`use super::k_cos`. Absolute imports from core are OK, e.g. `use core::u64`. - To reinterpret a float as an integer use the `to_bits` method. The MUSL code uses the `GET_FLOAT_WORD` macro, or a union, to do this operation. @@ -36,6 +36,13 @@ Check [PR #65] for an example. - To reinterpret an integer as a float use the `f32::from_bits` constructor. The MUSL code uses the `SET_FLOAT_WORD` macro, or a union, to do this operation. +- You may use other methods from core like `f64::is_nan`, etc. as appropriate. + +- If you're implementing one of the private double-underscore functions, take a look at the + "source" name in the comment at the top for an idea for alternate naming. For example, `__sin` + was renamed to `k_sin` after the FreeBSD source code naming. Do `use` these private functions in + `mod.rs`. + - You may encounter weird literals like `0x1p127f` in the MUSL code. These are hexadecimal floating point literals. Rust (the language) doesn't support these kind of literals. The best way I have found to deal with these literals is to turn them into their integer representation using the From 65b49bb7a0fa37ff6fd9481844fc0af56e2a613f Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 14 Jul 2018 15:21:23 -0400 Subject: [PATCH 0543/4206] implement fma --- library/compiler-builtins/libm/src/lib.rs | 2 - .../compiler-builtins/libm/src/math/fma.rs | 201 ++++++++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 2 + .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 204 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fma.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index bef4667875a23..c3a20059330c4 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -366,7 +366,6 @@ pub trait F64Ext: private::Sealed { #[cfg(todo)] fn signum(self) -> Self; - #[cfg(todo)] fn mul_add(self, a: Self, b: Self) -> Self; #[cfg(todo)] @@ -485,7 +484,6 @@ impl F64Ext for f64 { fabs(self) } - #[cfg(todo)] #[inline] fn mul_add(self, a: Self, b: Self) -> Self { fma(self, a, b) diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs new file mode 100644 index 0000000000000..99a27164a81ec --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -0,0 +1,201 @@ +use core::{f32, f64}; + +use super::scalbn; + +const ZEROINFNAN: i32 = 0x7ff - 0x3ff - 52 - 1; + +struct Num { + m: u64, + e: i32, + sign: i32, +} + +#[inline] +fn normalize(x: f64) -> Num { + let x1p63: f64 = f64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63 + + let mut ix: u64 = x.to_bits(); + let mut e: i32 = (ix >> 52) as i32; + let sign: i32 = e & 0x800; + e &= 0x7ff; + if e == 0 { + ix = (x * x1p63).to_bits(); + e = (ix >> 52) as i32 & 0x7ff; + e = if e != 0 { e - 63 } else { 0x800 }; + } + ix &= (1 << 52) - 1; + ix |= 1 << 52; + ix <<= 1; + e -= 0x3ff + 52 + 1; + Num { m: ix, e, sign } +} + +#[inline] +fn mul(x: u64, y: u64) -> (u64, u64) { + let t1: u64; + let t2: u64; + let t3: u64; + let xlo: u64 = x as u32 as u64; + let xhi: u64 = x >> 32; + let ylo: u64 = y as u32 as u64; + let yhi: u64 = y >> 32; + + t1 = xlo * ylo; + t2 = xlo * yhi + xhi * ylo; + t3 = xhi * yhi; + let lo = t1 + (t2 << 32); + let hi = t3 + (t2 >> 32) + (t1 > lo) as u64; + (hi, lo) +} + +#[inline] +pub fn fma(x: f64, y: f64, z: f64) -> f64 { + let x1p63: f64 = f64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63 + let x0_ffffff8p_63 = f64::from_bits(0x3bfffffff0000000); // 0x0.ffffff8p-63 + + /* normalize so top 10bits and last bit are 0 */ + let nx = normalize(x); + let ny = normalize(y); + let nz = normalize(z); + + if nx.e >= ZEROINFNAN || ny.e >= ZEROINFNAN { + return x * y + z; + } + if nz.e >= ZEROINFNAN { + if nz.e > ZEROINFNAN { + /* z==0 */ + return x * y + z; + } + return z; + } + + /* mul: r = x*y */ + let zhi: u64; + let zlo: u64; + let (mut rhi, mut rlo) = mul(nx.m, ny.m); + /* either top 20 or 21 bits of rhi and last 2 bits of rlo are 0 */ + + /* align exponents */ + let mut e: i32 = nx.e + ny.e; + let mut d: i32 = nz.e - e; + /* shift bits z<<=kz, r>>=kr, so kz+kr == d, set e = e+kr (== ez-kz) */ + if d > 0 { + if d < 64 { + zlo = nz.m << d; + zhi = nz.m >> 64 - d; + } else { + zlo = 0; + zhi = nz.m; + e = nz.e - 64; + d -= 64; + if d == 0 { + } else if d < 64 { + rlo = rhi << 64 - d | rlo >> d | ((rlo << 64 - d) != 0) as u64; + rhi = rhi >> d; + } else { + rlo = 1; + rhi = 0; + } + } + } else { + zhi = 0; + d = -d; + if d == 0 { + zlo = nz.m; + } else if d < 64 { + zlo = nz.m >> d | ((nz.m << 64 - d) != 0) as u64; + } else { + zlo = 1; + } + } + + /* add */ + let mut sign: i32 = nx.sign ^ ny.sign; + let samesign: bool = (sign ^ nz.sign) == 0; + let mut nonzero: i32 = 1; + if samesign { + /* r += z */ + rlo += zlo; + rhi += zhi + (rlo < zlo) as u64; + } else { + /* r -= z */ + let t = rlo; + rlo -= zlo; + rhi = rhi - zhi - (t < rlo) as u64; + if (rhi >> 63) != 0 { + rlo = (-(rlo as i64)) as u64; + rhi = (-(rhi as i64)) as u64 - (rlo != 0) as u64; + sign = (sign == 0) as i32; + } + nonzero = (rhi != 0) as i32; + } + + /* set rhi to top 63bit of the result (last bit is sticky) */ + if nonzero != 0 { + e += 64; + d = rhi.leading_zeros() as i32 - 1; + /* note: d > 0 */ + rhi = rhi << d | rlo >> 64 - d | ((rlo << d) != 0) as u64; + } else if rlo != 0 { + d = rlo.leading_zeros() as i32 - 1; + if d < 0 { + rhi = rlo >> 1 | (rlo & 1); + } else { + rhi = rlo << d; + } + } else { + /* exact +-0 */ + return x * y + z; + } + e -= d; + + /* convert to double */ + let mut i: i64 = rhi as i64; /* i is in [1<<62,(1<<63)-1] */ + if sign != 0 { + i = -i; + } + let mut r: f64 = i as f64; /* |r| is in [0x1p62,0x1p63] */ + + if e < -1022 - 62 { + /* result is subnormal before rounding */ + if e == -1022 - 63 { + let mut c: f64 = x1p63; + if sign != 0 { + c = -c; + } + if r == c { + /* min normal after rounding, underflow depends + on arch behaviour which can be imitated by + a double to float conversion */ + let fltmin: f32 = (x0_ffffff8p_63 * f32::MIN_POSITIVE as f64 * r) as f32; + return f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * fltmin as f64; + } + /* one bit is lost when scaled, add another top bit to + only round once at conversion if it is inexact */ + if (rhi << 53) != 0 { + i = (rhi >> 1 | (rhi & 1) | 1 << 62) as i64; + if sign != 0 { + i = -i; + } + r = i as f64; + r = 2. * r - c; /* remove top bit */ + + /* raise underflow portably, such that it + cannot be optimized away */ + { + let tiny: f64 = f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * r; + r += (tiny * tiny) * (r - r); + } + } + } else { + /* only round once when scaled */ + d = 10; + i = ((rhi >> d | ((rhi << 64 - d) != 0) as u64) << d) as i64; + if sign != 0 { + i = -i; + } + r = i as f64; + } + } + scalbn(r, e) +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 828e3cb1a7e3f..c9a34fae42b7b 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -22,6 +22,7 @@ mod fdim; mod fdimf; mod floor; mod floorf; +mod fma; mod fmod; mod fmodf; mod hypot; @@ -61,6 +62,7 @@ pub use self::fdim::fdim; pub use self::fdimf::fdimf; pub use self::floor::floor; pub use self::floorf::floorf; +pub use self::fma::fma; pub use self::fmod::fmod; pub use self::fmodf::fmodf; pub use self::hypot::hypot; diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index e5b8fdc1d4f36..f4b7cd7cafb87 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -732,7 +732,7 @@ f64f64_f64! { // With signature `fn(f64, f64, f64) -> f64` f64f64f64_f64! { - // fma, + fma, } // With signature `fn(f64, i32) -> f64` From a377d0d79b16bbcff76bbed4f0fa7d79ba0da621 Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 14 Jul 2018 14:49:22 -0400 Subject: [PATCH 0544/4206] allow some functions to be inlined --- library/compiler-builtins/libm/src/math/ceilf.rs | 1 + library/compiler-builtins/libm/src/math/exp2.rs | 1 + library/compiler-builtins/libm/src/math/exp2f.rs | 1 + library/compiler-builtins/libm/src/math/fdim.rs | 1 + library/compiler-builtins/libm/src/math/fdimf.rs | 1 + library/compiler-builtins/libm/src/math/hypot.rs | 1 + library/compiler-builtins/libm/src/math/log1p.rs | 1 + library/compiler-builtins/libm/src/math/log1pf.rs | 1 + library/compiler-builtins/libm/src/math/log2.rs | 1 + library/compiler-builtins/libm/src/math/log2f.rs | 1 + library/compiler-builtins/libm/src/math/round.rs | 1 + library/compiler-builtins/libm/src/math/roundf.rs | 1 + 12 files changed, 12 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index b4f58bfb86f34..16bffb3002e59 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -1,5 +1,6 @@ use core::f32; +#[inline] pub fn ceilf(x: f32) -> f32 { let mut ui = x.to_bits(); let e = (((ui >> 23) & 0xff) - 0x7f) as i32; diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs index 61bfd1015d214..0ab11989679bc 100644 --- a/library/compiler-builtins/libm/src/math/exp2.rs +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -318,6 +318,7 @@ static TBL: [u64; TBLSIZE * 2] = [ // // Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library // for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). +#[inline] pub fn exp2(mut x: f64) -> f64 { let redux = f64::from_bits(0x4338000000000000) / TBLSIZE as f64; let p1 = f64::from_bits(0x3fe62e42fefa39ef); diff --git a/library/compiler-builtins/libm/src/math/exp2f.rs b/library/compiler-builtins/libm/src/math/exp2f.rs index 79929ce90e067..a3f6db8c5b365 100644 --- a/library/compiler-builtins/libm/src/math/exp2f.rs +++ b/library/compiler-builtins/libm/src/math/exp2f.rs @@ -69,6 +69,7 @@ static EXP2FT: [u64; TBLSIZE] = [ // // Tang, P. Table-driven Implementation of the Exponential Function // in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989). +#[inline] pub fn exp2f(mut x: f32) -> f32 { let redux = f32::from_bits(0x4b400000) / TBLSIZE as f32; let p1 = f32::from_bits(0x3f317218); diff --git a/library/compiler-builtins/libm/src/math/fdim.rs b/library/compiler-builtins/libm/src/math/fdim.rs index 2b277eab03e18..1daae4ebc227d 100644 --- a/library/compiler-builtins/libm/src/math/fdim.rs +++ b/library/compiler-builtins/libm/src/math/fdim.rs @@ -1,5 +1,6 @@ use core::f64; +#[inline] pub fn fdim(x: f64, y: f64) -> f64 { if x.is_nan() { x diff --git a/library/compiler-builtins/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/src/math/fdimf.rs index 44bf2d6806ef3..953e0c8dfafcc 100644 --- a/library/compiler-builtins/libm/src/math/fdimf.rs +++ b/library/compiler-builtins/libm/src/math/fdimf.rs @@ -1,5 +1,6 @@ use core::f32; +#[inline] pub fn fdimf(x: f32, y: f32) -> f32 { if x.is_nan() { x diff --git a/library/compiler-builtins/libm/src/math/hypot.rs b/library/compiler-builtins/libm/src/math/hypot.rs index 7ad1baf796c82..f011415fdc64f 100644 --- a/library/compiler-builtins/libm/src/math/hypot.rs +++ b/library/compiler-builtins/libm/src/math/hypot.rs @@ -4,6 +4,7 @@ use super::sqrt; const SPLIT: f64 = 134217728. + 1.; // 0x1p27 + 1 === (2 ^ 27) + 1 +#[inline] fn sq(x: f64) -> (f64, f64) { let xh: f64; let xl: f64; diff --git a/library/compiler-builtins/libm/src/math/log1p.rs b/library/compiler-builtins/libm/src/math/log1p.rs index 7f7a5125bbb34..f42669deeaee7 100644 --- a/library/compiler-builtins/libm/src/math/log1p.rs +++ b/library/compiler-builtins/libm/src/math/log1p.rs @@ -65,6 +65,7 @@ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +#[inline] pub fn log1p(x: f64) -> f64 { let mut ui: u64 = x.to_bits(); let hfsq: f64; diff --git a/library/compiler-builtins/libm/src/math/log1pf.rs b/library/compiler-builtins/libm/src/math/log1pf.rs index c8e2422593375..e6e1c14c8c5f5 100644 --- a/library/compiler-builtins/libm/src/math/log1pf.rs +++ b/library/compiler-builtins/libm/src/math/log1pf.rs @@ -20,6 +20,7 @@ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ +#[inline] pub fn log1pf(x: f32) -> f32 { let mut ui: u32 = x.to_bits(); let hfsq: f32; diff --git a/library/compiler-builtins/libm/src/math/log2.rs b/library/compiler-builtins/libm/src/math/log2.rs index f6640d296c307..35eb9bf72b274 100644 --- a/library/compiler-builtins/libm/src/math/log2.rs +++ b/library/compiler-builtins/libm/src/math/log2.rs @@ -29,6 +29,7 @@ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +#[inline] pub fn log2(mut x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 diff --git a/library/compiler-builtins/libm/src/math/log2f.rs b/library/compiler-builtins/libm/src/math/log2f.rs index c007ff9b097a7..8684b142f8be2 100644 --- a/library/compiler-builtins/libm/src/math/log2f.rs +++ b/library/compiler-builtins/libm/src/math/log2f.rs @@ -23,6 +23,7 @@ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ +#[inline] pub fn log2f(mut x: f32) -> f32 { let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs index 73d431c518395..1a6e754489c1c 100644 --- a/library/compiler-builtins/libm/src/math/round.rs +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -2,6 +2,7 @@ use core::f64; const TOINT: f64 = 1.0 / f64::EPSILON; +#[inline] pub fn round(mut x: f64) -> f64 { let (f, i) = (x, x.to_bits()); let e: u64 = i >> 52 & 0x7ff; diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs index bd2488fa99c8e..7dd79557a9d3b 100644 --- a/library/compiler-builtins/libm/src/math/roundf.rs +++ b/library/compiler-builtins/libm/src/math/roundf.rs @@ -2,6 +2,7 @@ use core::f32; const TOINT: f32 = 1.0 / f32::EPSILON; +#[inline] pub fn roundf(mut x: f32) -> f32 { let i = x.to_bits(); let e: u32 = i >> 23 & 0xff; From f03a65b37279890082fcdeaebdc90409eab7fc6b Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 14 Jul 2018 22:41:48 +0200 Subject: [PATCH 0545/4206] rustfmt --- library/compiler-builtins/libm/src/math/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index b2c01f6514f5c..d5f4e0d54bc17 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -90,6 +90,4 @@ mod k_sinf; mod rem_pio2_large; mod rem_pio2f; -use self::{ - k_cosf::k_cosf, k_sinf::k_sinf, rem_pio2_large::rem_pio2_large, rem_pio2f::rem_pio2f, -}; +use self::{k_cosf::k_cosf, k_sinf::k_sinf, rem_pio2_large::rem_pio2_large, rem_pio2f::rem_pio2f}; From ccde9e02e7573c05c4add6653f93ba483da42d6f Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sat, 14 Jul 2018 18:57:12 +0300 Subject: [PATCH 0546/4206] acosf asinf atanf expm1f sinf tanf --- library/compiler-builtins/libm/src/lib.rs | 12 -- .../compiler-builtins/libm/src/math/acosf.rs | 59 +++++++++ .../compiler-builtins/libm/src/math/asinf.rs | 52 ++++++++ .../compiler-builtins/libm/src/math/atanf.rs | 95 +++++++++++++++ .../compiler-builtins/libm/src/math/expm1f.rs | 112 ++++++++++++++++++ .../compiler-builtins/libm/src/math/k_tanf.rs | 35 ++++++ .../compiler-builtins/libm/src/math/mod.rs | 18 ++- .../compiler-builtins/libm/src/math/sinf.rs | 77 ++++++++++++ .../compiler-builtins/libm/src/math/tanf.rs | 62 ++++++++++ .../libm/test-generator/src/main.rs | 11 +- 10 files changed, 515 insertions(+), 18 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/acosf.rs create mode 100644 library/compiler-builtins/libm/src/math/asinf.rs create mode 100644 library/compiler-builtins/libm/src/math/atanf.rs create mode 100644 library/compiler-builtins/libm/src/math/expm1f.rs create mode 100644 library/compiler-builtins/libm/src/math/k_tanf.rs create mode 100644 library/compiler-builtins/libm/src/math/sinf.rs create mode 100644 library/compiler-builtins/libm/src/math/tanf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 27925e806c095..df7ee813fbaf3 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -84,21 +84,16 @@ pub trait F32Ext: private::Sealed { fn hypot(self, other: Self) -> Self; - #[cfg(todo)] fn sin(self) -> Self; fn cos(self) -> Self; - #[cfg(todo)] fn tan(self) -> Self; - #[cfg(todo)] fn asin(self) -> Self; - #[cfg(todo)] fn acos(self) -> Self; - #[cfg(todo)] fn atan(self) -> Self; #[cfg(todo)] @@ -110,7 +105,6 @@ pub trait F32Ext: private::Sealed { (self.sin(), self.cos()) } - #[cfg(todo)] fn exp_m1(self) -> Self; fn ln_1p(self) -> Self; @@ -248,7 +242,6 @@ impl F32Ext for f32 { hypotf(self, other) } - #[cfg(todo)] #[inline] fn sin(self) -> Self { sinf(self) @@ -259,25 +252,21 @@ impl F32Ext for f32 { cosf(self) } - #[cfg(todo)] #[inline] fn tan(self) -> Self { tanf(self) } - #[cfg(todo)] #[inline] fn asin(self) -> Self { asinf(self) } - #[cfg(todo)] #[inline] fn acos(self) -> Self { acosf(self) } - #[cfg(todo)] #[inline] fn atan(self) -> Self { atanf(self) @@ -289,7 +278,6 @@ impl F32Ext for f32 { atan2f(self, other) } - #[cfg(todo)] #[inline] fn exp_m1(self) -> Self { expm1f(self) diff --git a/library/compiler-builtins/libm/src/math/acosf.rs b/library/compiler-builtins/libm/src/math/acosf.rs new file mode 100644 index 0000000000000..bbe29c17c131f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/acosf.rs @@ -0,0 +1,59 @@ +use super::sqrtf::sqrtf; + +const PIO2_HI: f32 = 1.5707962513e+00; /* 0x3fc90fda */ +const PIO2_LO: f32 = 7.5497894159e-08; /* 0x33a22168 */ +const P_S0: f32 = 1.6666586697e-01; +const P_S1: f32 = -4.2743422091e-02; +const P_S2: f32 = -8.6563630030e-03; +const Q_S1: f32 = -7.0662963390e-01; + +fn r(z: f32) -> f32 { + let p = z * (P_S0 + z * (P_S1 + z * P_S2)); + let q = 1. + z * Q_S1; + p / q +} + +#[inline] +pub fn acosf(x: f32) -> f32 { + let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) + + let z: f32; + let w: f32; + let s: f32; + + let mut hx = x.to_bits(); + let ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if ix >= 0x3f800000 { + if ix == 0x3f800000 { + if (hx >> 31) != 0 { + return 2. * PIO2_HI + x1p_120; + } + return 0.; + } + return 0. / (x - x); + } + /* |x| < 0.5 */ + if ix < 0x3f000000 { + if ix <= 0x32800000 { + /* |x| < 2**-26 */ + return PIO2_HI + x1p_120; + } + return PIO2_HI - (x - (PIO2_LO - x * r(x * x))); + } + /* x < -0.5 */ + if (hx >> 31) != 0 { + z = (1. + x) * 0.5; + s = sqrtf(z); + w = r(z) * s - PIO2_LO; + return 2. * (PIO2_HI - (s + w)); + } + /* x > 0.5 */ + z = (1. - x) * 0.5; + s = sqrtf(z); + hx = s.to_bits(); + let df = f32::from_bits(hx & 0xfffff000); + let c = (z - df * df) / (s + df); + w = r(z) * s + c; + 2. * (df + w) +} diff --git a/library/compiler-builtins/libm/src/math/asinf.rs b/library/compiler-builtins/libm/src/math/asinf.rs new file mode 100644 index 0000000000000..597be4cb7f989 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/asinf.rs @@ -0,0 +1,52 @@ +use super::fabsf::fabsf; +use super::sqrt::sqrt; + +const PIO2: f64 = 1.570796326794896558e+00; + +/* coefficients for R(x^2) */ +const P_S0: f32 = 1.6666586697e-01; +const P_S1: f32 = -4.2743422091e-02; +const P_S2: f32 = -8.6563630030e-03; +const Q_S1: f32 = -7.0662963390e-01; + +fn r(z: f32) -> f32 { + let p = z * (P_S0 + z * (P_S1 + z * P_S2)); + let q = 1. + z * Q_S1; + p / q +} + +#[inline] +pub fn asinf(mut x: f32) -> f32 { + let x1p_120 = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ (-120) + + let hx = x.to_bits(); + let ix = hx & 0x7fffffff; + + if ix >= 0x3f800000 { + /* |x| >= 1 */ + if ix == 0x3f800000 { + /* |x| == 1 */ + return ((x as f64) * PIO2 + x1p_120) as f32; /* asin(+-1) = +-pi/2 with inexact */ + } + return 0. / (x - x); /* asin(|x|>1) is NaN */ + } + + if ix < 0x3f000000 { + /* |x| < 0.5 */ + /* if 0x1p-126 <= |x| < 0x1p-12, avoid raising underflow */ + if (ix < 0x39800000) && (ix >= 0x00800000) { + return x; + } + return x + x * r(x * x); + } + + /* 1 > |x| >= 0.5 */ + let z = (1. - fabsf(x)) * 0.5; + let s = sqrt(z as f64); + x = (PIO2 - 2. * (s + s * (r(z) as f64))) as f32; + if (hx >> 31) != 0 { + -x + } else { + x + } +} diff --git a/library/compiler-builtins/libm/src/math/atanf.rs b/library/compiler-builtins/libm/src/math/atanf.rs new file mode 100644 index 0000000000000..01c41f4ce1781 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/atanf.rs @@ -0,0 +1,95 @@ +use super::fabsf; + +const ATAN_HI: [f32; 4] = [ + 4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */ + 7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */ + 9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */ + 1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */ +]; + +const ATAN_LO: [f32; 4] = [ + 5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */ + 3.7748947079e-08, /* atan(1.0)lo 0x33222168 */ + 3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */ + 7.5497894159e-08, /* atan(inf)lo 0x33a22168 */ +]; + +const A_T: [f32; 5] = [ + 3.3333328366e-01, + -1.9999158382e-01, + 1.4253635705e-01, + -1.0648017377e-01, + 6.1687607318e-02, +]; + +#[inline] +pub fn atanf(mut x: f32) -> f32 { + let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) + + let z: f32; + + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + if ix >= 0x4c800000 { + /* if |x| >= 2**26 */ + if x.is_nan() { + return x; + } + z = ATAN_HI[3] + x1p_120; + return if sign { -z } else { z }; + } + let id = if ix < 0x3ee00000 { + /* |x| < 0.4375 */ + if ix < 0x39800000 { + /* |x| < 2**-12 */ + if ix < 0x00800000 { + /* raise underflow for subnormal x */ + force_eval!(x * x); + } + return x; + } + -1 + } else { + x = fabsf(x); + if ix < 0x3f980000 { + /* |x| < 1.1875 */ + if ix < 0x3f300000 { + /* 7/16 <= |x| < 11/16 */ + x = (2. * x - 1.) / (2. + x); + 0 + } else { + /* 11/16 <= |x| < 19/16 */ + x = (x - 1.) / (x + 1.); + 1 + } + } else { + if ix < 0x401c0000 { + /* |x| < 2.4375 */ + x = (x - 1.5) / (1. + 1.5 * x); + 2 + } else { + /* 2.4375 <= |x| < 2**26 */ + x = -1. / x; + 3 + } + } + }; + /* end of argument reduction */ + z = x * x; + let w = z * z; + /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ + let s1 = z * (A_T[0] + w * (A_T[2] + w * A_T[4])); + let s2 = w * (A_T[1] + w * A_T[3]); + if id < 0 { + return x - x * (s1 + s2); + } + let id = id as usize; + let z = ATAN_HI[id] - ((x * (s1 + s2) - ATAN_LO[id]) - x); + if sign { + -z + } else { + z + } +} diff --git a/library/compiler-builtins/libm/src/math/expm1f.rs b/library/compiler-builtins/libm/src/math/expm1f.rs new file mode 100644 index 0000000000000..011e09b693d99 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/expm1f.rs @@ -0,0 +1,112 @@ +const O_THRESHOLD: f32 = 8.8721679688e+01; /* 0x42b17180 */ +const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ +const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ +const INV_LN2: f32 = 1.4426950216e+00; /* 0x3fb8aa3b */ +/* + * Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]: + * |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04 + * Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c): + */ +const Q1: f32 = -3.3333212137e-2; /* -0x888868.0p-28 */ +const Q2: f32 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ + +#[inline] +pub fn expm1f(mut x: f32) -> f32 { + let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 + + let mut hx = x.to_bits(); + let sign = (hx >> 31) != 0; + hx &= 0x7fffffff; + + /* filter out huge and non-finite argument */ + if hx >= 0x4195b844 { + /* if |x|>=27*ln2 */ + if hx > 0x7f800000 { + /* NaN */ + return x; + } + if sign { + return -1.; + } + if x > O_THRESHOLD { + x *= x1p127; + return x; + } + } + + let k: i32; + let hi: f32; + let lo: f32; + let mut c = 0f32; + /* argument reduction */ + if hx > 0x3eb17218 { + /* if |x| > 0.5 ln2 */ + if hx < 0x3F851592 { + /* and |x| < 1.5 ln2 */ + if !sign { + hi = x - LN2_HI; + lo = LN2_LO; + k = 1; + } else { + hi = x + LN2_HI; + lo = -LN2_LO; + k = -1; + } + } else { + k = (INV_LN2 * x + (if sign { -0.5 } else { 0.5 })) as i32; + let t = k as f32; + hi = x - t * LN2_HI; /* t*ln2_hi is exact here */ + lo = t * LN2_LO; + } + x = hi - lo; + c = (hi - x) - lo; + } else if hx < 0x33000000 { + /* when |x|<2**-25, return x */ + if hx < 0x00800000 { + force_eval!(x * x); + } + return x; + } else { + k = 0; + } + + /* x is now in primary range */ + let hfx = 0.5 * x; + let hxs = x * hfx; + let r1 = 1. + hxs * (Q1 + hxs * Q2); + let t = 3. - r1 * hfx; + let mut e = hxs * ((r1 - t) / (6. - x * t)); + if k == 0 { + /* c is 0 */ + return x - (x * e - hxs); + } + e = x * (e - c) - c; + e -= hxs; + /* exp(x) ~ 2^k (x_reduced - e + 1) */ + if k == -1 { + return 0.5 * (x - e) - 0.5; + } + if k == 1 { + if x < -0.25 { + return -2. * (e - (x + 0.5)); + } + return 1. + 2. * (x - e); + } + let twopk = f32::from_bits(((0x7f + k) << 23) as u32); /* 2^k */ + if (k < 0) || (k > 56) { + /* suffice to return exp(x)-1 */ + let mut y = x - e + 1.; + if k == 128 { + y = y * 2. * x1p127; + } else { + y = y * twopk; + } + return y - 1.; + } + let uf = f32::from_bits(((0x7f - k) << 23) as u32); /* 2^-k */ + if k < 23 { + (x - e + (1. - uf)) * twopk + } else { + (x - (e + uf) + 1.) * twopk + } +} diff --git a/library/compiler-builtins/libm/src/math/k_tanf.rs b/library/compiler-builtins/libm/src/math/k_tanf.rs new file mode 100644 index 0000000000000..db2e0caa7a5ef --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_tanf.rs @@ -0,0 +1,35 @@ +/* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */ +const T: [f64; 6] = [ + 0.333331395030791399758, /* 0x15554d3418c99f.0p-54 */ + 0.133392002712976742718, /* 0x1112fd38999f72.0p-55 */ + 0.0533812378445670393523, /* 0x1b54c91d865afe.0p-57 */ + 0.0245283181166547278873, /* 0x191df3908c33ce.0p-58 */ + 0.00297435743359967304927, /* 0x185dadfcecf44e.0p-61 */ + 0.00946564784943673166728, /* 0x1362b9bf971bcd.0p-59 */ +]; + +#[inline] +pub(crate) fn k_tanf(x: f64, odd: bool) -> f32 { + let z = x * x; + /* + * Split up the polynomial into small independent terms to give + * opportunities for parallel evaluation. The chosen splitting is + * micro-optimized for Athlons (XP, X64). It costs 2 multiplications + * relative to Horner's method on sequential machines. + * + * We add the small terms from lowest degree up for efficiency on + * non-sequential machines (the lowest degree terms tend to be ready + * earlier). Apart from this, we don't care about order of + * operations, and don't need to to care since we have precision to + * spare. However, the chosen splitting is good for accuracy too, + * and would give results as accurate as Horner's method if the + * small terms were added from highest degree down. + */ + let mut r = T[4] + z * T[5]; + let t = T[2] + z * T[3]; + let w = z * z; + let s = z * x; + let u = T[0] + z * T[1]; + r = (x + s * u) + (s * w) * (t + w * r); + (if odd { -1. / r } else { r }) as f32 +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index c903d37876209..792d05623f3b8 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -7,6 +7,9 @@ macro_rules! force_eval { } mod acos; +mod acosf; +mod asinf; +mod atanf; mod cbrt; mod cbrtf; mod ceil; @@ -17,6 +20,7 @@ mod exp2; mod exp2f; mod expf; mod expm1; +mod expm1f; mod fabs; mod fabsf; mod fdim; @@ -41,13 +45,18 @@ mod round; mod roundf; mod scalbn; mod scalbnf; +mod sinf; mod sqrt; mod sqrtf; +mod tanf; mod trunc; mod truncf; // Use separated imports instead of {}-grouped imports for easier merging. pub use self::acos::acos; +pub use self::acosf::acosf; +pub use self::asinf::asinf; +pub use self::atanf::atanf; pub use self::cbrt::cbrt; pub use self::cbrtf::cbrtf; pub use self::ceil::ceil; @@ -58,6 +67,7 @@ pub use self::exp2::exp2; pub use self::exp2f::exp2f; pub use self::expf::expf; pub use self::expm1::expm1; +pub use self::expm1f::expm1f; pub use self::fabs::fabs; pub use self::fabsf::fabsf; pub use self::fdim::fdim; @@ -82,14 +92,20 @@ pub use self::round::round; pub use self::roundf::roundf; pub use self::scalbn::scalbn; pub use self::scalbnf::scalbnf; +pub use self::sinf::sinf; pub use self::sqrt::sqrt; pub use self::sqrtf::sqrtf; +pub use self::tanf::tanf; pub use self::trunc::trunc; pub use self::truncf::truncf; mod k_cosf; mod k_sinf; +mod k_tanf; mod rem_pio2_large; mod rem_pio2f; -use self::{k_cosf::k_cosf, k_sinf::k_sinf, rem_pio2_large::rem_pio2_large, rem_pio2f::rem_pio2f}; +use self::{ + k_cosf::k_cosf, k_sinf::k_sinf, k_tanf::k_tanf, rem_pio2_large::rem_pio2_large, + rem_pio2f::rem_pio2f, +}; diff --git a/library/compiler-builtins/libm/src/math/sinf.rs b/library/compiler-builtins/libm/src/math/sinf.rs new file mode 100644 index 0000000000000..09f62cddcae35 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sinf.rs @@ -0,0 +1,77 @@ +use super::{k_cosf, k_sinf, rem_pio2f}; + +use core::f64::consts::FRAC_PI_2; + +/* Small multiples of pi/2 rounded to double precision. */ +const S1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ +const S2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ +const S3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const S4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ + +#[inline] +pub fn sinf(x: f32) -> f32 { + let x64 = x as f64; + + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + if ix <= 0x3f490fda { + /* |x| ~<= pi/4 */ + if ix < 0x39800000 { + /* |x| < 2**-12 */ + /* raise inexact if x!=0 and underflow if subnormal */ + force_eval!(if ix < 0x00800000 { + x / x1p120 + } else { + x + x1p120 + }); + return x; + } + return k_sinf(x64); + } + if ix <= 0x407b53d1 { + /* |x| ~<= 5*pi/4 */ + if ix <= 0x4016cbe3 { + /* |x| ~<= 3pi/4 */ + if sign { + return -k_cosf(x64 + S1_PIO2); + } else { + return k_cosf(x64 - S1_PIO2); + } + } + return k_sinf(if sign { + -(x64 + S2_PIO2) + } else { + -(x64 - S2_PIO2) + }); + } + if ix <= 0x40e231d5 { + /* |x| ~<= 9*pi/4 */ + if ix <= 0x40afeddf { + /* |x| ~<= 7*pi/4 */ + if sign { + return k_cosf(x64 + S3_PIO2); + } else { + return -k_cosf(x64 - S3_PIO2); + } + } + return k_sinf(if sign { x64 + S4_PIO2 } else { x64 - S4_PIO2 }); + } + + /* sin(Inf or NaN) is NaN */ + if ix >= 0x7f800000 { + return x - x; + } + + /* general argument reduction needed */ + let (n, y) = rem_pio2f(x); + match n & 3 { + 0 => k_sinf(y), + 1 => k_cosf(y), + 2 => return k_sinf(-y), + _ => -k_cosf(y), + } +} diff --git a/library/compiler-builtins/libm/src/math/tanf.rs b/library/compiler-builtins/libm/src/math/tanf.rs new file mode 100644 index 0000000000000..6bfbe06c1b4be --- /dev/null +++ b/library/compiler-builtins/libm/src/math/tanf.rs @@ -0,0 +1,62 @@ +use super::{k_tanf, rem_pio2f}; + +use core::f64::consts::FRAC_PI_2; + +/* Small multiples of pi/2 rounded to double precision. */ +const T1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ +const T2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ +const T3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const T4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ + +#[inline] +pub fn tanf(x: f32) -> f32 { + let x64 = x as f64; + + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + if ix <= 0x3f490fda { + /* |x| ~<= pi/4 */ + if ix < 0x39800000 { + /* |x| < 2**-12 */ + /* raise inexact if x!=0 and underflow if subnormal */ + force_eval!(if ix < 0x00800000 { + x / x1p120 + } else { + x + x1p120 + }); + return x; + } + return k_tanf(x64, false); + } + if ix <= 0x407b53d1 { + /* |x| ~<= 5*pi/4 */ + if ix <= 0x4016cbe3 { + /* |x| ~<= 3pi/4 */ + return k_tanf(if sign { x64 + T1_PIO2 } else { x64 - T1_PIO2 }, true); + } else { + return k_tanf(if sign { x64 + T2_PIO2 } else { x64 - T2_PIO2 }, false); + } + } + if ix <= 0x40e231d5 { + /* |x| ~<= 9*pi/4 */ + if ix <= 0x40afeddf { + /* |x| ~<= 7*pi/4 */ + return k_tanf(if sign { x64 + T3_PIO2 } else { x64 - T3_PIO2 }, true); + } else { + return k_tanf(if sign { x64 + T4_PIO2 } else { x64 - T4_PIO2 }, false); + } + } + + /* tan(Inf or NaN) is NaN */ + if ix >= 0x7f800000 { + return x - x; + } + + /* argument reduction */ + let (n, y) = rem_pio2f(x); + k_tanf(y, n & 1 != 0) +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index aa50f57cdb72c..0f93606500f6f 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -651,25 +651,26 @@ fn main() -> Result<(), Box> { // With signature `fn(f32) -> f32` f32_f32! { - // acosf, + acosf, floorf, truncf, - // asinf, - // atanf, + asinf, + atanf, cbrtf, cosf, ceilf, // coshf, exp2f, expf, + expm1f, log10f, log1pf, log2f, logf, roundf, - // sinf, + sinf, // sinhf, - // tanf, + tanf, // tanhf, fabsf, sqrtf, From 1d39d059e5eb25a84191245af804b68db954d032 Mon Sep 17 00:00:00 2001 From: vjackson725 Date: Sat, 14 Jul 2018 23:10:26 +1000 Subject: [PATCH 0547/4206] add an implemetation of asin Fixes rust-lang/libm#7 Additonally adds inline functions for macros dealing with low and high words of f64s to the root module. Also, the muslc code used a hexdecimal float. This shouldn't be needed because Rust implements floating point parsing well. --- .../compiler-builtins/libm/src/math/asin.rs | 113 ++++++++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 28 +++++ .../libm/test-generator/src/main.rs | 2 +- 3 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/libm/src/math/asin.rs diff --git a/library/compiler-builtins/libm/src/math/asin.rs b/library/compiler-builtins/libm/src/math/asin.rs new file mode 100644 index 0000000000000..720169bdcf0ba --- /dev/null +++ b/library/compiler-builtins/libm/src/math/asin.rs @@ -0,0 +1,113 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_asin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* asin(x) + * Method : + * Since asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ... + * we approximate asin(x) on [0,0.5] by + * asin(x) = x + x*x^2*R(x^2) + * where + * R(x^2) is a rational approximation of (asin(x)-x)/x^3 + * and its remez error is bounded by + * |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75) + * + * For x in [0.5,1] + * asin(x) = pi/2-2*asin(sqrt((1-x)/2)) + * Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2; + * then for x>0.98 + * asin(x) = pi/2 - 2*(s+s*z*R(z)) + * = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo) + * For x<=0.98, let pio4_hi = pio2_hi/2, then + * f = hi part of s; + * c = sqrt(z) - f = (z-f*f)/(s+f) ...f+c=sqrt(z) + * and + * asin(x) = pi/2 - 2*(s+s*z*R(z)) + * = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo) + * = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c)) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + */ + +use super::{fabs, get_high_word, get_low_word, sqrt, with_set_low_word}; + +const PIO2_HI: f64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ +const PIO2_LO: f64 = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */ +/* coefficients for R(x^2) */ +const P_S0: f64 = 1.66666666666666657415e-01; /* 0x3FC55555, 0x55555555 */ +const P_S1: f64 = -3.25565818622400915405e-01; /* 0xBFD4D612, 0x03EB6F7D */ +const P_S2: f64 = 2.01212532134862925881e-01; /* 0x3FC9C155, 0x0E884455 */ +const P_S3: f64 = -4.00555345006794114027e-02; /* 0xBFA48228, 0xB5688F3B */ +const P_S4: f64 = 7.91534994289814532176e-04; /* 0x3F49EFE0, 0x7501B288 */ +const P_S5: f64 = 3.47933107596021167570e-05; /* 0x3F023DE1, 0x0DFDF709 */ +const Q_S1: f64 = -2.40339491173441421878e+00; /* 0xC0033A27, 0x1C8A2D4B */ +const Q_S2: f64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ +const Q_S3: f64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ +const Q_S4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +fn comp_r(z: f64) -> f64 { + let p = z * (P_S0 + z * (P_S1 + z * (P_S2 + z * (P_S3 + z * (P_S4 + z * P_S5))))); + let q = 1.0 + z * (Q_S1 + z * (Q_S2 + z * (Q_S3 + z * Q_S4))); + return p / q; +} + +pub fn asin(mut x: f64) -> f64 { + let z: f64; + let r: f64; + let s: f64; + let hx: u32; + let ix: u32; + + hx = get_high_word(x); + ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if ix >= 0x3ff00000 { + let lx: u32; + lx = get_low_word(x); + if (ix - 0x3ff00000 | lx) == 0 { + /* asin(1) = +-pi/2 with inexact */ + return x * PIO2_HI + f64::from_bits(0x3870000000000000); + } else { + return 0.0 / (x - x); + } + } + /* |x| < 0.5 */ + if ix < 0x3fe00000 { + /* if 0x1p-1022 <= |x| < 0x1p-26, avoid raising underflow */ + if ix < 0x3e500000 && ix >= 0x00100000 { + return x; + } else { + return x + x * comp_r(x * x); + } + } + /* 1 > |x| >= 0.5 */ + z = (1.0 - fabs(x)) * 0.5; + s = sqrt(z); + r = comp_r(z); + if ix >= 0x3fef3333 { + /* if |x| > 0.975 */ + x = PIO2_HI - (2. * (s + s * r) - PIO2_LO); + } else { + let f: f64; + let c: f64; + /* f+c = sqrt(z) */ + f = with_set_low_word(s, 0); + c = (z - f * f) / (s + f); + x = 0.5 * PIO2_HI - (2.0 * s * r - (PIO2_LO - 2.0 * c) - (0.5 * PIO2_HI - 2.0 * f)); + } + if hx >> 31 != 0 { + return -x; + } else { + return x; + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 792d05623f3b8..42c596857d7e5 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -8,6 +8,7 @@ macro_rules! force_eval { mod acos; mod acosf; +mod asin; mod asinf; mod atanf; mod cbrt; @@ -55,6 +56,7 @@ mod truncf; // Use separated imports instead of {}-grouped imports for easier merging. pub use self::acos::acos; pub use self::acosf::acosf; +pub use self::asin::asin; pub use self::asinf::asinf; pub use self::atanf::atanf; pub use self::cbrt::cbrt; @@ -109,3 +111,29 @@ use self::{ k_cosf::k_cosf, k_sinf::k_sinf, k_tanf::k_tanf, rem_pio2_large::rem_pio2_large, rem_pio2f::rem_pio2f, }; + +#[inline] +pub fn get_high_word(x: f64) -> u32 { + (x.to_bits() >> 32) as u32 +} + +#[inline] +pub fn get_low_word(x: f64) -> u32 { + x.to_bits() as u32 +} + +#[inline] +pub fn with_set_high_word(f: f64, hi: u32) -> f64 { + let mut tmp = f.to_bits(); + tmp &= 0x00000000_ffffffff; + tmp |= (hi as u64) << 32; + f64::from_bits(tmp) +} + +#[inline] +pub fn with_set_low_word(f: f64, lo: u32) -> f64 { + let mut tmp = f.to_bits(); + tmp &= 0xffffffff_00000000; + tmp |= lo as u64; + f64::from_bits(tmp) +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 0f93606500f6f..b639cf11b19aa 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -698,7 +698,7 @@ f32i32_f32! { // With signature `fn(f64) -> f64` f64_f64! { acos, - // asin, + asin, // atan, cbrt, ceil, From 802f6a2b46689fed5a37fbea4c0aa7a64a8522db Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 14 Jul 2018 16:58:24 -0500 Subject: [PATCH 0548/4206] v0.1.1 --- library/compiler-builtins/libm/CHANGELOG.md | 38 ++++++++++++++++++++- library/compiler-builtins/libm/Cargo.toml | 2 +- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index c3e74a8143381..3a496527bc040 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -5,8 +5,44 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.1.1] - 2018-07-14 + +### Added + +- acos +- acosf +- asin +- asinf +- atanf +- cbrt +- cbrtf +- ceil +- ceilf +- cosf +- exp +- exp2 +- exp2f +- expm1 +- expm1f +- fdim +- fdimf +- floorf +- fma +- fmod +- log +- log2 +- log10 +- log10f +- log1p +- log1pf +- log2f +- roundf +- sinf +- tanf + ## v0.1.0 - 2018-07-13 - Initial release -[Unreleased]: https://github.com/japaric/libm/compare/v0.1.0...HEAD +[Unreleased]: https://github.com/japaric/libm/compare/v0.1.1...HEAD +[v0.1.1]: https://github.com/japaric/libm/compare/v0.1.0...v0.1.1 diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 5a1ae4a6c92b4..a82fc99a7e7ab 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -7,7 +7,7 @@ keywords = ["libm", "math"] license = "MIT OR Apache-2.0" name = "libm" repository = "https://github.com/japaric/libm" -version = "0.1.0" +version = "0.1.1" [workspace] members = ["cb", "test-generator"] \ No newline at end of file From 440a1b7273e663ce0c7680aba62efe744d2ab556 Mon Sep 17 00:00:00 2001 From: C Jones Date: Fri, 13 Jul 2018 22:10:30 -0400 Subject: [PATCH 0549/4206] Implement part of sin/cos with quadrant selection unimplemented --- library/compiler-builtins/libm/src/lib.rs | 4 - .../compiler-builtins/libm/src/math/cos.rs | 73 +++++ .../compiler-builtins/libm/src/math/mod.rs | 14 +- .../compiler-builtins/libm/src/math/sin.rs | 80 +++++ .../libm/src/math/trig_common.rs | 289 ++++++++++++++++++ 5 files changed, 452 insertions(+), 8 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/cos.rs create mode 100644 library/compiler-builtins/libm/src/math/sin.rs create mode 100644 library/compiler-builtins/libm/src/math/trig_common.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index df7ee813fbaf3..0b9efeeb338a6 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -386,10 +386,8 @@ pub trait F64Ext: private::Sealed { fn hypot(self, other: Self) -> Self; - #[cfg(todo)] fn sin(self) -> Self; - #[cfg(todo)] fn cos(self) -> Self; #[cfg(todo)] @@ -548,13 +546,11 @@ impl F64Ext for f64 { hypot(self, other) } - #[cfg(todo)] #[inline] fn sin(self) -> Self { sin(self) } - #[cfg(todo)] #[inline] fn cos(self) -> Self { cos(self) diff --git a/library/compiler-builtins/libm/src/math/cos.rs b/library/compiler-builtins/libm/src/math/cos.rs new file mode 100644 index 0000000000000..91412c6489a7a --- /dev/null +++ b/library/compiler-builtins/libm/src/math/cos.rs @@ -0,0 +1,73 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cos.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. + * ==================================================== + */ + +use math::trig_common::{_cos, _sin, rem_pio2}; + +// cos(x) +// Return cosine function of x. +// +// kernel function: +// __sin ... sine function on [-pi/4,pi/4] +// __cos ... cosine function on [-pi/4,pi/4] +// __rem_pio2 ... argument reduction routine +// +// Method. +// Let S,C and T denote the sin, cos and tan respectively on +// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 +// in [-pi/4 , +pi/4], and let n = k mod 4. +// We have +// +// n sin(x) cos(x) tan(x) +// ---------------------------------------------------------- +// 0 S C T +// 1 C -S -1/T +// 2 -S -C T +// 3 -C S -1/T +// ---------------------------------------------------------- +// +// Special cases: +// Let trig be any of sin, cos, or tan. +// trig(+-INF) is NaN, with signals; +// trig(NaN) is that NaN; +// +// Accuracy: +// TRIG(x) returns trig(x) nearly rounded +// +pub fn cos(x: f64) -> f64 { + let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + + /* |x| ~< pi/4 */ + if ix <= 0x3fe921fb { + if ix < 0x3e46a09e { + /* if x < 2**-27 * sqrt(2) */ + /* raise inexact if x != 0 */ + if x as i32 == 0 { + return 1.0; + } + } + return _cos(x, 0.0); + } + + /* cos(Inf or NaN) is NaN */ + if ix >= 0x7ff00000 { + return x - x; + } + + /* argument reduction needed */ + let (n, y0, y1) = rem_pio2(x); + match n & 3 { + 0 => _cos(y0, y1), + 1 => -_sin(y0, y1, 1), + 2 => -_cos(y0, y1), + _ => _sin(y0, y1, 1), + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 42c596857d7e5..a657da810e334 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -15,6 +15,7 @@ mod cbrt; mod cbrtf; mod ceil; mod ceilf; +mod cos; mod cosf; mod exp; mod exp2; @@ -46,6 +47,7 @@ mod round; mod roundf; mod scalbn; mod scalbnf; +mod sin; mod sinf; mod sqrt; mod sqrtf; @@ -63,6 +65,7 @@ pub use self::cbrt::cbrt; pub use self::cbrtf::cbrtf; pub use self::ceil::ceil; pub use self::ceilf::ceilf; +pub use self::cos::cos; pub use self::cosf::cosf; pub use self::exp::exp; pub use self::exp2::exp2; @@ -94,6 +97,7 @@ pub use self::round::round; pub use self::roundf::roundf; pub use self::scalbn::scalbn; pub use self::scalbnf::scalbnf; +pub use self::sin::sin; pub use self::sinf::sinf; pub use self::sqrt::sqrt; pub use self::sqrtf::sqrtf; @@ -106,11 +110,13 @@ mod k_sinf; mod k_tanf; mod rem_pio2_large; mod rem_pio2f; +mod trig_common; -use self::{ - k_cosf::k_cosf, k_sinf::k_sinf, k_tanf::k_tanf, rem_pio2_large::rem_pio2_large, - rem_pio2f::rem_pio2f, -}; +use self::k_cosf::k_cosf; +use self::k_sinf::k_sinf; +use self::k_tanf::k_tanf; +use self::rem_pio2_large::rem_pio2_large; +use self::rem_pio2f::rem_pio2f; #[inline] pub fn get_high_word(x: f64) -> u32 { diff --git a/library/compiler-builtins/libm/src/math/sin.rs b/library/compiler-builtins/libm/src/math/sin.rs new file mode 100644 index 0000000000000..0717c1ae3edf2 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sin.rs @@ -0,0 +1,80 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.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. + * ==================================================== + */ + +use core::f64; + +use math::trig_common::{_cos, _sin, rem_pio2}; + +// sin(x) +// Return sine function of x. +// +// kernel function: +// __sin ... sine function on [-pi/4,pi/4] +// __cos ... cose function on [-pi/4,pi/4] +// __rem_pio2 ... argument reduction routine +// +// Method. +// Let S,C and T denote the sin, cos and tan respectively on +// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 +// in [-pi/4 , +pi/4], and let n = k mod 4. +// We have +// +// n sin(x) cos(x) tan(x) +// ---------------------------------------------------------- +// 0 S C T +// 1 C -S -1/T +// 2 -S -C T +// 3 -C S -1/T +// ---------------------------------------------------------- +// +// Special cases: +// Let trig be any of sin, cos, or tan. +// trig(+-INF) is NaN, with signals; +// trig(NaN) is that NaN; +// +// Accuracy: +// TRIG(x) returns trig(x) nearly rounded +pub fn sin(x: f64) -> f64 { + let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 + + /* High word of x. */ + let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + + /* |x| ~< pi/4 */ + if ix <= 0x3fe921fb { + if ix < 0x3e500000 { + /* |x| < 2**-26 */ + /* raise inexact if x != 0 and underflow if subnormal*/ + if ix < 0x00100000 { + force_eval!(x / x1p120); + } else { + force_eval!(x + x1p120); + } + return x; + } + return _sin(x, 0.0, 0); + } + + /* sin(Inf or NaN) is NaN */ + if ix >= 0x7ff00000 { + return x - x; + } + + /* argument reduction needed */ + let (n, y0, y1) = rem_pio2(x); + match n & 3 { + 0 => _sin(y0, y1, 1), + 1 => _cos(y0, y1), + 2 => -_sin(y0, y1, 1), + _ => -_cos(y0, y1), + } +} diff --git a/library/compiler-builtins/libm/src/math/trig_common.rs b/library/compiler-builtins/libm/src/math/trig_common.rs new file mode 100644 index 0000000000000..59e75e2dd6b95 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/trig_common.rs @@ -0,0 +1,289 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* origin: FreeBSD /usr/src/lib/msun/src/k_sin.c */ + +const S1: f64 = -1.66666666666666324348e-01; /* 0xBFC55555, 0x55555549 */ +const S2: f64 = 8.33333333332248946124e-03; /* 0x3F811111, 0x1110F8A6 */ +const S3: f64 = -1.98412698298579493134e-04; /* 0xBF2A01A0, 0x19C161D5 */ +const S4: f64 = 2.75573137070700676789e-06; /* 0x3EC71DE3, 0x57B1FE7D */ +const S5: f64 = -2.50507602534068634195e-08; /* 0xBE5AE5E6, 0x8A2B9CEB */ +const S6: f64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ + +// kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 +// Input x is assumed to be bounded by ~pi/4 in magnitude. +// Input y is the tail of x. +// Input iy indicates whether y is 0. (if iy=0, y assume to be 0). +// +// Algorithm +// 1. Since sin(-x) = -sin(x), we need only to consider positive x. +// 2. Callers must return sin(-0) = -0 without calling here since our +// odd polynomial is not evaluated in a way that preserves -0. +// Callers may do the optimization sin(x) ~ x for tiny x. +// 3. sin(x) is approximated by a polynomial of degree 13 on +// [0,pi/4] +// 3 13 +// sin(x) ~ x + S1*x + ... + S6*x +// where +// +// |sin(x) 2 4 6 8 10 12 | -58 +// |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 +// | x | +// +// 4. sin(x+y) = sin(x) + sin'(x')*y +// ~ sin(x) + (1-x*x/2)*y +// For better accuracy, let +// 3 2 2 2 2 +// r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) +// then 3 2 +// sin(x) = x + (S1*x + (x *(r-y/2)+y)) +pub fn _sin(x: f64, y: f64, iy: i32) -> f64 { + let z = x * x; + let w = z * z; + let r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6); + let v = z * x; + if iy == 0 { + x + v * (S1 + z * r) + } else { + x - ((z * (0.5 * y - v * r) - y) - v * S1) + } +} + +/* origin: FreeBSD /usr/src/lib/msun/src/k_cos.c */ +const C1: f64 = 4.16666666666666019037e-02; /* 0x3FA55555, 0x5555554C */ +const C2: f64 = -1.38888888888741095749e-03; /* 0xBF56C16C, 0x16C15177 */ +const C3: f64 = 2.48015872894767294178e-05; /* 0x3EFA01A0, 0x19CB1590 */ +const C4: f64 = -2.75573143513906633035e-07; /* 0xBE927E4F, 0x809C52AD */ +const C5: f64 = 2.08757232129817482790e-09; /* 0x3E21EE9E, 0xBDB4B1C4 */ +const C6: f64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ + +// kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 +// Input x is assumed to be bounded by ~pi/4 in magnitude. +// Input y is the tail of x. +// +// Algorithm +// 1. Since cos(-x) = cos(x), we need only to consider positive x. +// 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. +// 3. cos(x) is approximated by a polynomial of degree 14 on +// [0,pi/4] +// 4 14 +// cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x +// where the remez error is +// +// | 2 4 6 8 10 12 14 | -58 +// |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 +// | | +// +// 4 6 8 10 12 14 +// 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then +// cos(x) ~ 1 - x*x/2 + r +// since cos(x+y) ~ cos(x) - sin(x)*y +// ~ cos(x) - x*y, +// a correction term is necessary in cos(x) and hence +// cos(x+y) = 1 - (x*x/2 - (r - x*y)) +// For better accuracy, rearrange to +// cos(x+y) ~ w + (tmp + (r-x*y)) +// where w = 1 - x*x/2 and tmp is a tiny correction term +// (1 - x*x/2 == w + tmp exactly in infinite precision). +// The exactness of w + tmp in infinite precision depends on w +// and tmp having the same precision as x. If they have extra +// precision due to compiler bugs, then the extra precision is +// only good provided it is retained in all terms of the final +// expression for cos(). Retention happens in all cases tested +// under FreeBSD, so don't pessimize things by forcibly clipping +// any extra precision in w. +pub fn _cos(x: f64, y: f64) -> f64 { + let z = x * x; + let w = z * z; + let r = z * (C1 + z * (C2 + z * C3)) + w * w * (C4 + z * (C5 + z * C6)); + let hz = 0.5 * z; + let w = 1.0 - hz; + w + (((1.0 - w) - hz) + (z * r - x * y)) +} + +// origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.c +// Optimized by Bruce D. Evans. */ + +// #if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +// #define EPS DBL_EPSILON +const EPS: f64 = 2.2204460492503131e-16; +// #elif FLT_EVAL_METHOD==2 +// #define EPS LDBL_EPSILON +// #endif + +// TODO: Support FLT_EVAL_METHOD? + +#[allow(unused, non_upper_case_globals)] +const toint: f64 = 1.5 / EPS; +/// 53 bits of 2/pi +#[allow(unused, non_upper_case_globals)] +const invpio2: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ +/// first 33 bits of pi/2 +#[allow(unused, non_upper_case_globals)] +const pio2_1: f64 = 1.57079632673412561417e+00; /* 0x3FF921FB, 0x54400000 */ +/// pi/2 - pio2_1 +#[allow(unused, non_upper_case_globals)] +const pio2_1t: f64 = 6.07710050650619224932e-11; /* 0x3DD0B461, 0x1A626331 */ +/// second 33 bits of pi/2 +#[allow(unused, non_upper_case_globals)] +const pio2_2: f64 = 6.07710050630396597660e-11; /* 0x3DD0B461, 0x1A600000 */ +/// pi/2 - (pio2_1+pio2_2) +#[allow(unused, non_upper_case_globals)] +const pio2_2t: f64 = 2.02226624879595063154e-21; /* 0x3BA3198A, 0x2E037073 */ +/// third 33 bits of pi/2 +#[allow(unused, non_upper_case_globals)] +const pio2_3: f64 = 2.02226624871116645580e-21; /* 0x3BA3198A, 0x2E000000 */ +/// pi/2 - (pio2_1+pio2_2+pio2_3) +#[allow(unused, non_upper_case_globals)] +const pio2_3t: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ + +/* __rem_pio2(x,y) + * + * return the remainder of x rem pi/2 in y[0]+y[1] + * use __rem_pio2_large() for large x + */ + +/* caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ +/* +{ + union {double f; uint64_t i;} u = {x}; + double_t z,w,t,r,fn; + double tx[3],ty[2]; + uint32_t ix; + int sign, n, ex, ey, i; + + sign = u.i>>63; + ix = u.i>>32 & 0x7fffffff; + if (ix <= 0x400f6a7a) { /* |x| ~<= 5pi/4 */ + if ((ix & 0xfffff) == 0x921fb) /* |x| ~= pi/2 or 2pi/2 */ + goto medium; /* cancellation -- use medium case */ + if (ix <= 0x4002d97c) { /* |x| ~<= 3pi/4 */ + if (!sign) { + z = x - pio2_1; /* one round good to 85 bits */ + y[0] = z - pio2_1t; + y[1] = (z-y[0]) - pio2_1t; + return 1; + } else { + z = x + pio2_1; + y[0] = z + pio2_1t; + y[1] = (z-y[0]) + pio2_1t; + return -1; + } + } else { + if (!sign) { + z = x - 2*pio2_1; + y[0] = z - 2*pio2_1t; + y[1] = (z-y[0]) - 2*pio2_1t; + return 2; + } else { + z = x + 2*pio2_1; + y[0] = z + 2*pio2_1t; + y[1] = (z-y[0]) + 2*pio2_1t; + return -2; + } + } + } + if (ix <= 0x401c463b) { /* |x| ~<= 9pi/4 */ + if (ix <= 0x4015fdbc) { /* |x| ~<= 7pi/4 */ + if (ix == 0x4012d97c) /* |x| ~= 3pi/2 */ + goto medium; + if (!sign) { + z = x - 3*pio2_1; + y[0] = z - 3*pio2_1t; + y[1] = (z-y[0]) - 3*pio2_1t; + return 3; + } else { + z = x + 3*pio2_1; + y[0] = z + 3*pio2_1t; + y[1] = (z-y[0]) + 3*pio2_1t; + return -3; + } + } else { + if (ix == 0x401921fb) /* |x| ~= 4pi/2 */ + goto medium; + if (!sign) { + z = x - 4*pio2_1; + y[0] = z - 4*pio2_1t; + y[1] = (z-y[0]) - 4*pio2_1t; + return 4; + } else { + z = x + 4*pio2_1; + y[0] = z + 4*pio2_1t; + y[1] = (z-y[0]) + 4*pio2_1t; + return -4; + } + } + } + if (ix < 0x413921fb) { /* |x| ~< 2^20*(pi/2), medium size */ +medium: + /* rint(x/(pi/2)), Assume round-to-nearest. */ + fn = (double_t)x*invpio2 + toint - toint; + n = (int32_t)fn; + r = x - fn*pio2_1; + w = fn*pio2_1t; /* 1st round, good to 85 bits */ + y[0] = r - w; + u.f = y[0]; + ey = u.i>>52 & 0x7ff; + ex = ix>>20; + if (ex - ey > 16) { /* 2nd round, good to 118 bits */ + t = r; + w = fn*pio2_2; + r = t - w; + w = fn*pio2_2t - ((t-r)-w); + y[0] = r - w; + u.f = y[0]; + ey = u.i>>52 & 0x7ff; + if (ex - ey > 49) { /* 3rd round, good to 151 bits, covers all cases */ + t = r; + w = fn*pio2_3; + r = t - w; + w = fn*pio2_3t - ((t-r)-w); + y[0] = r - w; + } + } + y[1] = (r - y[0]) - w; + return n; + } + /* + * all other (large) arguments + */ + if (ix >= 0x7ff00000) { /* x is inf or NaN */ + y[0] = y[1] = x - x; + return 0; + } + /* set z = scalbn(|x|,-ilogb(x)+23) */ + u.f = x; + u.i &= (uint64_t)-1>>12; + u.i |= (uint64_t)(0x3ff + 23)<<52; + z = u.f; + for (i=0; i < 2; i++) { + tx[i] = (double)(int32_t)z; + z = (z-tx[i])*0x1p24; + } + tx[i] = z; + /* skip zero terms, first term is non-zero */ + while (tx[i] == 0.0) + i--; + n = __rem_pio2_large(tx,ty,(int)(ix>>20)-(0x3ff+23),i+1,1); + if (sign) { + y[0] = -ty[0]; + y[1] = -ty[1]; + return -n; + } + y[0] = ty[0]; + y[1] = ty[1]; + return n; +} +*/ + +pub fn rem_pio2(_x: f64) -> (i32, f64, f64) { + unimplemented!() +} From b2751897d2fde5c7aa0ec30b7d45b714011cd0dd Mon Sep 17 00:00:00 2001 From: C Jones Date: Fri, 13 Jul 2018 23:03:21 -0400 Subject: [PATCH 0550/4206] Convert rem_pio2 code, split up modules --- .../compiler-builtins/libm/src/math/cos.rs | 39 ++- .../compiler-builtins/libm/src/math/exp2.rs | 2 +- .../compiler-builtins/libm/src/math/k_cos.rs | 62 ++++ .../compiler-builtins/libm/src/math/k_sin.rs | 57 ++++ .../compiler-builtins/libm/src/math/mod.rs | 10 +- .../libm/src/math/rem_pio2.rs | 187 ++++++++++++ .../compiler-builtins/libm/src/math/sin.rs | 41 ++- .../libm/src/math/trig_common.rs | 289 ------------------ .../libm/test-generator/src/main.rs | 4 +- 9 files changed, 356 insertions(+), 335 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/k_cos.rs create mode 100644 library/compiler-builtins/libm/src/math/k_sin.rs create mode 100644 library/compiler-builtins/libm/src/math/rem_pio2.rs delete mode 100644 library/compiler-builtins/libm/src/math/trig_common.rs diff --git a/library/compiler-builtins/libm/src/math/cos.rs b/library/compiler-builtins/libm/src/math/cos.rs index 91412c6489a7a..e6e9b373674c0 100644 --- a/library/compiler-builtins/libm/src/math/cos.rs +++ b/library/compiler-builtins/libm/src/math/cos.rs @@ -1,24 +1,23 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_cos.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. - * ==================================================== - */ +// origin: FreeBSD /usr/src/lib/msun/src/s_cos.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. +// ==================================================== -use math::trig_common::{_cos, _sin, rem_pio2}; +use super::{k_cos, k_sin, rem_pio2}; // cos(x) // Return cosine function of x. // // kernel function: -// __sin ... sine function on [-pi/4,pi/4] -// __cos ... cosine function on [-pi/4,pi/4] -// __rem_pio2 ... argument reduction routine +// k_sin ... sine function on [-pi/4,pi/4] +// k_cos ... cosine function on [-pi/4,pi/4] +// rem_pio2 ... argument reduction routine // // Method. // Let S,C and T denote the sin, cos and tan respectively on @@ -54,7 +53,7 @@ pub fn cos(x: f64) -> f64 { return 1.0; } } - return _cos(x, 0.0); + return k_cos(x, 0.0); } /* cos(Inf or NaN) is NaN */ @@ -65,9 +64,9 @@ pub fn cos(x: f64) -> f64 { /* argument reduction needed */ let (n, y0, y1) = rem_pio2(x); match n & 3 { - 0 => _cos(y0, y1), - 1 => -_sin(y0, y1, 1), - 2 => -_cos(y0, y1), - _ => _sin(y0, y1, 1), + 0 => k_cos(y0, y1), + 1 => -k_sin(y0, y1, 1), + 2 => -k_cos(y0, y1), + _ => k_sin(y0, y1, 1), } } diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs index 0ab11989679bc..3952e93007e13 100644 --- a/library/compiler-builtins/libm/src/math/exp2.rs +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -24,7 +24,7 @@ // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. -use super::scalbn::scalbn; +use super::scalbn; const TBLSIZE: usize = 256; diff --git a/library/compiler-builtins/libm/src/math/k_cos.rs b/library/compiler-builtins/libm/src/math/k_cos.rs new file mode 100644 index 0000000000000..693950d1d418e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_cos.rs @@ -0,0 +1,62 @@ +// origin: FreeBSD /usr/src/lib/msun/src/k_cos.c +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunSoft, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +const C1: f64 = 4.16666666666666019037e-02; /* 0x3FA55555, 0x5555554C */ +const C2: f64 = -1.38888888888741095749e-03; /* 0xBF56C16C, 0x16C15177 */ +const C3: f64 = 2.48015872894767294178e-05; /* 0x3EFA01A0, 0x19CB1590 */ +const C4: f64 = -2.75573143513906633035e-07; /* 0xBE927E4F, 0x809C52AD */ +const C5: f64 = 2.08757232129817482790e-09; /* 0x3E21EE9E, 0xBDB4B1C4 */ +const C6: f64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ + +// kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 +// Input x is assumed to be bounded by ~pi/4 in magnitude. +// Input y is the tail of x. +// +// Algorithm +// 1. Since cos(-x) = cos(x), we need only to consider positive x. +// 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. +// 3. cos(x) is approximated by a polynomial of degree 14 on +// [0,pi/4] +// 4 14 +// cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x +// where the remez error is +// +// | 2 4 6 8 10 12 14 | -58 +// |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 +// | | +// +// 4 6 8 10 12 14 +// 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then +// cos(x) ~ 1 - x*x/2 + r +// since cos(x+y) ~ cos(x) - sin(x)*y +// ~ cos(x) - x*y, +// a correction term is necessary in cos(x) and hence +// cos(x+y) = 1 - (x*x/2 - (r - x*y)) +// For better accuracy, rearrange to +// cos(x+y) ~ w + (tmp + (r-x*y)) +// where w = 1 - x*x/2 and tmp is a tiny correction term +// (1 - x*x/2 == w + tmp exactly in infinite precision). +// The exactness of w + tmp in infinite precision depends on w +// and tmp having the same precision as x. If they have extra +// precision due to compiler bugs, then the extra precision is +// only good provided it is retained in all terms of the final +// expression for cos(). Retention happens in all cases tested +// under FreeBSD, so don't pessimize things by forcibly clipping +// any extra precision in w. +#[inline] +pub fn k_cos(x: f64, y: f64) -> f64 { + let z = x * x; + let w = z * z; + let r = z * (C1 + z * (C2 + z * C3)) + w * w * (C4 + z * (C5 + z * C6)); + let hz = 0.5 * z; + let w = 1.0 - hz; + w + (((1.0 - w) - hz) + (z * r - x * y)) +} diff --git a/library/compiler-builtins/libm/src/math/k_sin.rs b/library/compiler-builtins/libm/src/math/k_sin.rs new file mode 100644 index 0000000000000..3e07c3594475e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_sin.rs @@ -0,0 +1,57 @@ +// origin: FreeBSD /usr/src/lib/msun/src/k_sin.c +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunSoft, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +const S1: f64 = -1.66666666666666324348e-01; /* 0xBFC55555, 0x55555549 */ +const S2: f64 = 8.33333333332248946124e-03; /* 0x3F811111, 0x1110F8A6 */ +const S3: f64 = -1.98412698298579493134e-04; /* 0xBF2A01A0, 0x19C161D5 */ +const S4: f64 = 2.75573137070700676789e-06; /* 0x3EC71DE3, 0x57B1FE7D */ +const S5: f64 = -2.50507602534068634195e-08; /* 0xBE5AE5E6, 0x8A2B9CEB */ +const S6: f64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ + +// kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 +// Input x is assumed to be bounded by ~pi/4 in magnitude. +// Input y is the tail of x. +// Input iy indicates whether y is 0. (if iy=0, y assume to be 0). +// +// Algorithm +// 1. Since sin(-x) = -sin(x), we need only to consider positive x. +// 2. Callers must return sin(-0) = -0 without calling here since our +// odd polynomial is not evaluated in a way that preserves -0. +// Callers may do the optimization sin(x) ~ x for tiny x. +// 3. sin(x) is approximated by a polynomial of degree 13 on +// [0,pi/4] +// 3 13 +// sin(x) ~ x + S1*x + ... + S6*x +// where +// +// |sin(x) 2 4 6 8 10 12 | -58 +// |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 +// | x | +// +// 4. sin(x+y) = sin(x) + sin'(x')*y +// ~ sin(x) + (1-x*x/2)*y +// For better accuracy, let +// 3 2 2 2 2 +// r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) +// then 3 2 +// sin(x) = x + (S1*x + (x *(r-y/2)+y)) +#[inline] +pub fn k_sin(x: f64, y: f64, iy: i32) -> f64 { + let z = x * x; + let w = z * z; + let r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6); + let v = z * x; + if iy == 0 { + x + v * (S1 + z * r) + } else { + x - ((z * (0.5 * y - v * r) - y) - v * S1) + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index a657da810e334..7b3d9abee697a 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -6,6 +6,7 @@ macro_rules! force_eval { }; } +// Public modules mod acos; mod acosf; mod asin; @@ -105,16 +106,23 @@ pub use self::tanf::tanf; pub use self::trunc::trunc; pub use self::truncf::truncf; +// Private modules +mod k_cos; mod k_cosf; +mod k_sin; mod k_sinf; mod k_tanf; +mod rem_pio2; mod rem_pio2_large; mod rem_pio2f; -mod trig_common; +// Private re-imports +use self::k_cos::k_cos; use self::k_cosf::k_cosf; +use self::k_sin::k_sin; use self::k_sinf::k_sinf; use self::k_tanf::k_tanf; +use self::rem_pio2::rem_pio2; use self::rem_pio2_large::rem_pio2_large; use self::rem_pio2f::rem_pio2f; diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs new file mode 100644 index 0000000000000..68db7056b63c5 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -0,0 +1,187 @@ +// origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.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. */ + +use super::rem_pio2_large; + +// #if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +// #define EPS DBL_EPSILON +const EPS: f64 = 2.2204460492503131e-16; +// #elif FLT_EVAL_METHOD==2 +// #define EPS LDBL_EPSILON +// #endif + +// TODO: Support FLT_EVAL_METHOD? + +const TO_INT: f64 = 1.5 / EPS; +/// 53 bits of 2/pi +const INV_PIO2: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ +/// first 33 bits of pi/2 +const PIO2_1: f64 = 1.57079632673412561417e+00; /* 0x3FF921FB, 0x54400000 */ +/// pi/2 - PIO2_1 +const PIO2_1T: f64 = 6.07710050650619224932e-11; /* 0x3DD0B461, 0x1A626331 */ +/// second 33 bits of pi/2 +const PIO2_2: f64 = 6.07710050630396597660e-11; /* 0x3DD0B461, 0x1A600000 */ +/// pi/2 - (PIO2_1+PIO2_2) +const PIO2_2T: f64 = 2.02226624879595063154e-21; /* 0x3BA3198A, 0x2E037073 */ +/// third 33 bits of pi/2 +const PIO2_3: f64 = 2.02226624871116645580e-21; /* 0x3BA3198A, 0x2E000000 */ +/// pi/2 - (PIO2_1+PIO2_2+PIO2_3) +const PIO2_3T: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ + +// return the remainder of x rem pi/2 in y[0]+y[1] +// use rem_pio2_large() for large x +// +// caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ +pub fn rem_pio2(x: f64) -> (i32, f64, f64) { + let x1p24 = f64::from_bits(0x7041); + + let sign = (f64::to_bits(x) >> 63) as i32; + let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + + fn medium(x: f64, ix: u32) -> (i32, f64, f64) { + /* rint(x/(pi/2)), Assume round-to-nearest. */ + let f_n = x as f64 * INV_PIO2 + TO_INT - TO_INT; + let n = f_n as i32; + let mut r = x - f_n * PIO2_1; + let mut w = f_n * PIO2_1T; /* 1st round, good to 85 bits */ + let mut y0 = r - w; + let ui = f64::to_bits(y0); + let ey = (ui >> 52) as i32 & 0x7ff; + let ex = (ix >> 20) as i32; + if ex - ey > 16 { + /* 2nd round, good to 118 bits */ + let t = r; + w = f_n * PIO2_2; + r = t - w; + w = f_n * PIO2_2T - ((t - r) - w); + y0 = r - w; + let ey = (f64::to_bits(y0) >> 52) as i32 & 0x7ff; + if ex - ey > 49 { + /* 3rd round, good to 151 bits, covers all cases */ + let t = r; + w = f_n * PIO2_3; + r = t - w; + w = f_n * PIO2_3T - ((t - r) - w); + y0 = r - w; + } + } + let y1 = (r - y0) - w; + return (n, y0, y1); + } + + if ix <= 0x400f6a7a { + /* |x| ~<= 5pi/4 */ + if (ix & 0xfffff) == 0x921fb { + /* |x| ~= pi/2 or 2pi/2 */ + medium(x, ix); /* cancellation -- use medium case */ + } + if ix <= 0x4002d97c { + /* |x| ~<= 3pi/4 */ + if sign == 0 { + let z = x - PIO2_1; /* one round good to 85 bits */ + let y0 = z - PIO2_1T; + let y1 = (z - y0) - PIO2_1T; + return (1, y0, y1); + } else { + let z = x + PIO2_1; + let y0 = z + PIO2_1T; + let y1 = (z - y0) + PIO2_1T; + return (-1, y0, y1); + } + } else { + if sign == 0 { + let z = x - 2.0 * PIO2_1; + let y0 = z - 2.0 * PIO2_1T; + let y1 = (z - y0) - 2.0 * PIO2_1T; + return (2, y0, y1); + } else { + let z = x + 2.0 * PIO2_1; + let y0 = z + 2.0 * PIO2_1T; + let y1 = (z - y0) + 2.0 * PIO2_1T; + return (-2, y0, y1); + } + } + } + if ix <= 0x401c463b { + /* |x| ~<= 9pi/4 */ + if ix <= 0x4015fdbc { + /* |x| ~<= 7pi/4 */ + if ix == 0x4012d97c { + /* |x| ~= 3pi/2 */ + return medium(x, ix); + } + if sign == 0 { + let z = x - 3.0 * PIO2_1; + let y0 = z - 3.0 * PIO2_1T; + let y1 = (z - y0) - 3.0 * PIO2_1T; + return (3, y0, y1); + } else { + let z = x + 3.0 * PIO2_1; + let y0 = z + 3.0 * PIO2_1T; + let y1 = (z - y0) + 3.0 * PIO2_1T; + return (-3, y0, y1); + } + } else { + if ix == 0x401921fb { + /* |x| ~= 4pi/2 */ + return medium(x, ix); + } + if sign == 0 { + let z = x - 4.0 * PIO2_1; + let y0 = z - 4.0 * PIO2_1T; + let y1 = (z - y0) - 4.0 * PIO2_1T; + return (4, y0, y1); + } else { + let z = x + 4.0 * PIO2_1; + let y0 = z + 4.0 * PIO2_1T; + let y1 = (z - y0) + 4.0 * PIO2_1T; + return (-4, y0, y1); + } + } + } + if ix < 0x413921fb { + /* |x| ~< 2^20*(pi/2), medium size */ + return medium(x, ix); + } + /* + * all other (large) arguments + */ + if ix >= 0x7ff00000 { + /* x is inf or NaN */ + let y0 = x - x; + let y1 = y0; + return (0, y0, y1); + } + /* set z = scalbn(|x|,-ilogb(x)+23) */ + let mut ui = f64::to_bits(x); + ui &= (!1) >> 12; + ui |= (0x3ff + 23) << 52; + let mut z = f64::from_bits(ui); + let mut tx = [0.0; 3]; + for i in 0..2 { + tx[i] = z as i32 as f64; + z = (z - tx[i]) * x1p24; + } + tx[2] = z; + /* skip zero terms, first term is non-zero */ + let mut i = 2; + while tx[i] == 0.0 { + i -= 1; + } + let mut ty = [0.0; 3]; + let n = rem_pio2_large(&tx[..=i], &mut ty, ((ix >> 20) - (0x3ff + 23)) as i32, 1); + if sign != 0 { + return (-n, -ty[0], -ty[1]); + } + return (n, ty[0], ty[1]); +} diff --git a/library/compiler-builtins/libm/src/math/sin.rs b/library/compiler-builtins/libm/src/math/sin.rs index 0717c1ae3edf2..13eb30248ab71 100644 --- a/library/compiler-builtins/libm/src/math/sin.rs +++ b/library/compiler-builtins/libm/src/math/sin.rs @@ -1,26 +1,23 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.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. - * ==================================================== - */ - -use core::f64; +// origin: FreeBSD /usr/src/lib/msun/src/s_sin.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. +// ==================================================== -use math::trig_common::{_cos, _sin, rem_pio2}; +use super::{k_cos, k_sin, rem_pio2}; // sin(x) // Return sine function of x. // // kernel function: -// __sin ... sine function on [-pi/4,pi/4] -// __cos ... cose function on [-pi/4,pi/4] -// __rem_pio2 ... argument reduction routine +// k_sin ... sine function on [-pi/4,pi/4] +// k_cos ... cose function on [-pi/4,pi/4] +// rem_pio2 ... argument reduction routine // // Method. // Let S,C and T denote the sin, cos and tan respectively on @@ -61,7 +58,7 @@ pub fn sin(x: f64) -> f64 { } return x; } - return _sin(x, 0.0, 0); + return k_sin(x, 0.0, 0); } /* sin(Inf or NaN) is NaN */ @@ -72,9 +69,9 @@ pub fn sin(x: f64) -> f64 { /* argument reduction needed */ let (n, y0, y1) = rem_pio2(x); match n & 3 { - 0 => _sin(y0, y1, 1), - 1 => _cos(y0, y1), - 2 => -_sin(y0, y1, 1), - _ => -_cos(y0, y1), + 0 => k_sin(y0, y1, 1), + 1 => k_cos(y0, y1), + 2 => -k_sin(y0, y1, 1), + _ => -k_cos(y0, y1), } } diff --git a/library/compiler-builtins/libm/src/math/trig_common.rs b/library/compiler-builtins/libm/src/math/trig_common.rs deleted file mode 100644 index 59e75e2dd6b95..0000000000000 --- a/library/compiler-builtins/libm/src/math/trig_common.rs +++ /dev/null @@ -1,289 +0,0 @@ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -/* origin: FreeBSD /usr/src/lib/msun/src/k_sin.c */ - -const S1: f64 = -1.66666666666666324348e-01; /* 0xBFC55555, 0x55555549 */ -const S2: f64 = 8.33333333332248946124e-03; /* 0x3F811111, 0x1110F8A6 */ -const S3: f64 = -1.98412698298579493134e-04; /* 0xBF2A01A0, 0x19C161D5 */ -const S4: f64 = 2.75573137070700676789e-06; /* 0x3EC71DE3, 0x57B1FE7D */ -const S5: f64 = -2.50507602534068634195e-08; /* 0xBE5AE5E6, 0x8A2B9CEB */ -const S6: f64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ - -// kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 -// Input x is assumed to be bounded by ~pi/4 in magnitude. -// Input y is the tail of x. -// Input iy indicates whether y is 0. (if iy=0, y assume to be 0). -// -// Algorithm -// 1. Since sin(-x) = -sin(x), we need only to consider positive x. -// 2. Callers must return sin(-0) = -0 without calling here since our -// odd polynomial is not evaluated in a way that preserves -0. -// Callers may do the optimization sin(x) ~ x for tiny x. -// 3. sin(x) is approximated by a polynomial of degree 13 on -// [0,pi/4] -// 3 13 -// sin(x) ~ x + S1*x + ... + S6*x -// where -// -// |sin(x) 2 4 6 8 10 12 | -58 -// |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 -// | x | -// -// 4. sin(x+y) = sin(x) + sin'(x')*y -// ~ sin(x) + (1-x*x/2)*y -// For better accuracy, let -// 3 2 2 2 2 -// r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) -// then 3 2 -// sin(x) = x + (S1*x + (x *(r-y/2)+y)) -pub fn _sin(x: f64, y: f64, iy: i32) -> f64 { - let z = x * x; - let w = z * z; - let r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6); - let v = z * x; - if iy == 0 { - x + v * (S1 + z * r) - } else { - x - ((z * (0.5 * y - v * r) - y) - v * S1) - } -} - -/* origin: FreeBSD /usr/src/lib/msun/src/k_cos.c */ -const C1: f64 = 4.16666666666666019037e-02; /* 0x3FA55555, 0x5555554C */ -const C2: f64 = -1.38888888888741095749e-03; /* 0xBF56C16C, 0x16C15177 */ -const C3: f64 = 2.48015872894767294178e-05; /* 0x3EFA01A0, 0x19CB1590 */ -const C4: f64 = -2.75573143513906633035e-07; /* 0xBE927E4F, 0x809C52AD */ -const C5: f64 = 2.08757232129817482790e-09; /* 0x3E21EE9E, 0xBDB4B1C4 */ -const C6: f64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ - -// kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 -// Input x is assumed to be bounded by ~pi/4 in magnitude. -// Input y is the tail of x. -// -// Algorithm -// 1. Since cos(-x) = cos(x), we need only to consider positive x. -// 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. -// 3. cos(x) is approximated by a polynomial of degree 14 on -// [0,pi/4] -// 4 14 -// cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x -// where the remez error is -// -// | 2 4 6 8 10 12 14 | -58 -// |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 -// | | -// -// 4 6 8 10 12 14 -// 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then -// cos(x) ~ 1 - x*x/2 + r -// since cos(x+y) ~ cos(x) - sin(x)*y -// ~ cos(x) - x*y, -// a correction term is necessary in cos(x) and hence -// cos(x+y) = 1 - (x*x/2 - (r - x*y)) -// For better accuracy, rearrange to -// cos(x+y) ~ w + (tmp + (r-x*y)) -// where w = 1 - x*x/2 and tmp is a tiny correction term -// (1 - x*x/2 == w + tmp exactly in infinite precision). -// The exactness of w + tmp in infinite precision depends on w -// and tmp having the same precision as x. If they have extra -// precision due to compiler bugs, then the extra precision is -// only good provided it is retained in all terms of the final -// expression for cos(). Retention happens in all cases tested -// under FreeBSD, so don't pessimize things by forcibly clipping -// any extra precision in w. -pub fn _cos(x: f64, y: f64) -> f64 { - let z = x * x; - let w = z * z; - let r = z * (C1 + z * (C2 + z * C3)) + w * w * (C4 + z * (C5 + z * C6)); - let hz = 0.5 * z; - let w = 1.0 - hz; - w + (((1.0 - w) - hz) + (z * r - x * y)) -} - -// origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.c -// Optimized by Bruce D. Evans. */ - -// #if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 -// #define EPS DBL_EPSILON -const EPS: f64 = 2.2204460492503131e-16; -// #elif FLT_EVAL_METHOD==2 -// #define EPS LDBL_EPSILON -// #endif - -// TODO: Support FLT_EVAL_METHOD? - -#[allow(unused, non_upper_case_globals)] -const toint: f64 = 1.5 / EPS; -/// 53 bits of 2/pi -#[allow(unused, non_upper_case_globals)] -const invpio2: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ -/// first 33 bits of pi/2 -#[allow(unused, non_upper_case_globals)] -const pio2_1: f64 = 1.57079632673412561417e+00; /* 0x3FF921FB, 0x54400000 */ -/// pi/2 - pio2_1 -#[allow(unused, non_upper_case_globals)] -const pio2_1t: f64 = 6.07710050650619224932e-11; /* 0x3DD0B461, 0x1A626331 */ -/// second 33 bits of pi/2 -#[allow(unused, non_upper_case_globals)] -const pio2_2: f64 = 6.07710050630396597660e-11; /* 0x3DD0B461, 0x1A600000 */ -/// pi/2 - (pio2_1+pio2_2) -#[allow(unused, non_upper_case_globals)] -const pio2_2t: f64 = 2.02226624879595063154e-21; /* 0x3BA3198A, 0x2E037073 */ -/// third 33 bits of pi/2 -#[allow(unused, non_upper_case_globals)] -const pio2_3: f64 = 2.02226624871116645580e-21; /* 0x3BA3198A, 0x2E000000 */ -/// pi/2 - (pio2_1+pio2_2+pio2_3) -#[allow(unused, non_upper_case_globals)] -const pio2_3t: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ - -/* __rem_pio2(x,y) - * - * return the remainder of x rem pi/2 in y[0]+y[1] - * use __rem_pio2_large() for large x - */ - -/* caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ -/* -{ - union {double f; uint64_t i;} u = {x}; - double_t z,w,t,r,fn; - double tx[3],ty[2]; - uint32_t ix; - int sign, n, ex, ey, i; - - sign = u.i>>63; - ix = u.i>>32 & 0x7fffffff; - if (ix <= 0x400f6a7a) { /* |x| ~<= 5pi/4 */ - if ((ix & 0xfffff) == 0x921fb) /* |x| ~= pi/2 or 2pi/2 */ - goto medium; /* cancellation -- use medium case */ - if (ix <= 0x4002d97c) { /* |x| ~<= 3pi/4 */ - if (!sign) { - z = x - pio2_1; /* one round good to 85 bits */ - y[0] = z - pio2_1t; - y[1] = (z-y[0]) - pio2_1t; - return 1; - } else { - z = x + pio2_1; - y[0] = z + pio2_1t; - y[1] = (z-y[0]) + pio2_1t; - return -1; - } - } else { - if (!sign) { - z = x - 2*pio2_1; - y[0] = z - 2*pio2_1t; - y[1] = (z-y[0]) - 2*pio2_1t; - return 2; - } else { - z = x + 2*pio2_1; - y[0] = z + 2*pio2_1t; - y[1] = (z-y[0]) + 2*pio2_1t; - return -2; - } - } - } - if (ix <= 0x401c463b) { /* |x| ~<= 9pi/4 */ - if (ix <= 0x4015fdbc) { /* |x| ~<= 7pi/4 */ - if (ix == 0x4012d97c) /* |x| ~= 3pi/2 */ - goto medium; - if (!sign) { - z = x - 3*pio2_1; - y[0] = z - 3*pio2_1t; - y[1] = (z-y[0]) - 3*pio2_1t; - return 3; - } else { - z = x + 3*pio2_1; - y[0] = z + 3*pio2_1t; - y[1] = (z-y[0]) + 3*pio2_1t; - return -3; - } - } else { - if (ix == 0x401921fb) /* |x| ~= 4pi/2 */ - goto medium; - if (!sign) { - z = x - 4*pio2_1; - y[0] = z - 4*pio2_1t; - y[1] = (z-y[0]) - 4*pio2_1t; - return 4; - } else { - z = x + 4*pio2_1; - y[0] = z + 4*pio2_1t; - y[1] = (z-y[0]) + 4*pio2_1t; - return -4; - } - } - } - if (ix < 0x413921fb) { /* |x| ~< 2^20*(pi/2), medium size */ -medium: - /* rint(x/(pi/2)), Assume round-to-nearest. */ - fn = (double_t)x*invpio2 + toint - toint; - n = (int32_t)fn; - r = x - fn*pio2_1; - w = fn*pio2_1t; /* 1st round, good to 85 bits */ - y[0] = r - w; - u.f = y[0]; - ey = u.i>>52 & 0x7ff; - ex = ix>>20; - if (ex - ey > 16) { /* 2nd round, good to 118 bits */ - t = r; - w = fn*pio2_2; - r = t - w; - w = fn*pio2_2t - ((t-r)-w); - y[0] = r - w; - u.f = y[0]; - ey = u.i>>52 & 0x7ff; - if (ex - ey > 49) { /* 3rd round, good to 151 bits, covers all cases */ - t = r; - w = fn*pio2_3; - r = t - w; - w = fn*pio2_3t - ((t-r)-w); - y[0] = r - w; - } - } - y[1] = (r - y[0]) - w; - return n; - } - /* - * all other (large) arguments - */ - if (ix >= 0x7ff00000) { /* x is inf or NaN */ - y[0] = y[1] = x - x; - return 0; - } - /* set z = scalbn(|x|,-ilogb(x)+23) */ - u.f = x; - u.i &= (uint64_t)-1>>12; - u.i |= (uint64_t)(0x3ff + 23)<<52; - z = u.f; - for (i=0; i < 2; i++) { - tx[i] = (double)(int32_t)z; - z = (z-tx[i])*0x1p24; - } - tx[i] = z; - /* skip zero terms, first term is non-zero */ - while (tx[i] == 0.0) - i--; - n = __rem_pio2_large(tx,ty,(int)(ix>>20)-(0x3ff+23),i+1,1); - if (sign) { - y[0] = -ty[0]; - y[1] = -ty[1]; - return -n; - } - y[0] = ty[0]; - y[1] = ty[1]; - return n; -} -*/ - -pub fn rem_pio2(_x: f64) -> (i32, f64, f64) { - unimplemented!() -} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index b639cf11b19aa..c8e35cea7b00c 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -702,7 +702,7 @@ f64_f64! { // atan, cbrt, ceil, - // cos, + cos, // cosh, exp, exp2, @@ -713,7 +713,7 @@ f64_f64! { log1p, log2, round, - // sin, + sin, // sinh, sqrt, // tan, From 75428a13cf93a710deabaa2ab475984e1f26e18c Mon Sep 17 00:00:00 2001 From: C Jones Date: Sat, 14 Jul 2018 18:40:52 -0400 Subject: [PATCH 0551/4206] Fix x1p24 constant --- library/compiler-builtins/libm/src/math/rem_pio2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 68db7056b63c5..47bab6e65f195 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -43,7 +43,7 @@ const PIO2_3T: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ // // caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ pub fn rem_pio2(x: f64) -> (i32, f64, f64) { - let x1p24 = f64::from_bits(0x7041); + let x1p24 = f64::from_bits(0x4170000000000000); let sign = (f64::to_bits(x) >> 63) as i32; let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; From b61b0046c0dbc98cca990131adee22cfc599c4ec Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sun, 15 Jul 2018 02:06:20 +0300 Subject: [PATCH 0552/4206] coshf tanhf and atan2f --- library/compiler-builtins/libm/src/lib.rs | 6 -- .../compiler-builtins/libm/src/math/atan2f.rs | 71 +++++++++++++++++++ .../compiler-builtins/libm/src/math/coshf.rs | 33 +++++++++ .../libm/src/math/k_expo2f.rs | 14 ++++ .../compiler-builtins/libm/src/math/mod.rs | 11 ++- .../compiler-builtins/libm/src/math/tanhf.rs | 39 ++++++++++ .../libm/test-generator/src/main.rs | 6 +- 7 files changed, 169 insertions(+), 11 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/atan2f.rs create mode 100644 library/compiler-builtins/libm/src/math/coshf.rs create mode 100644 library/compiler-builtins/libm/src/math/k_expo2f.rs create mode 100644 library/compiler-builtins/libm/src/math/tanhf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index df7ee813fbaf3..969e7c45b5e41 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -96,7 +96,6 @@ pub trait F32Ext: private::Sealed { fn atan(self) -> Self; - #[cfg(todo)] fn atan2(self, other: Self) -> Self; #[cfg(todo)] @@ -112,10 +111,8 @@ pub trait F32Ext: private::Sealed { #[cfg(todo)] fn sinh(self) -> Self; - #[cfg(todo)] fn cosh(self) -> Self; - #[cfg(todo)] fn tanh(self) -> Self; #[cfg(todo)] @@ -272,7 +269,6 @@ impl F32Ext for f32 { atanf(self) } - #[cfg(todo)] #[inline] fn atan2(self, other: Self) -> Self { atan2f(self, other) @@ -294,13 +290,11 @@ impl F32Ext for f32 { sinhf(self) } - #[cfg(todo)] #[inline] fn cosh(self) -> Self { coshf(self) } - #[cfg(todo)] #[inline] fn tanh(self) -> Self { tanhf(self) diff --git a/library/compiler-builtins/libm/src/math/atan2f.rs b/library/compiler-builtins/libm/src/math/atan2f.rs new file mode 100644 index 0000000000000..a232ffdd61dc9 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/atan2f.rs @@ -0,0 +1,71 @@ +use super::atanf; +use super::fabsf; + +const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ +const PI_LO: f32 = -8.7422776573e-08; /* 0xb3bbbd2e */ + +#[inline] +pub fn atan2f(y: f32, x: f32) -> f32 { + if x.is_nan() || y.is_nan() { + return x + y; + } + let mut ix = x.to_bits(); + let mut iy = y.to_bits(); + + if ix == 0x3f800000 { + /* x=1.0 */ + return atanf(y); + } + let m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */ + ix &= 0x7fffffff; + iy &= 0x7fffffff; + + /* when y = 0 */ + if iy == 0 { + return match m { + 0 | 1 => y, /* atan(+-0,+anything)=+-0 */ + 2 => PI, /* atan(+0,-anything) = pi */ + 3 | _ => -PI, /* atan(-0,-anything) =-pi */ + }; + } + /* when x = 0 */ + if ix == 0 { + return if m & 1 != 0 { -PI / 2. } else { PI / 2. }; + } + /* when x is INF */ + if ix == 0x7f800000 { + return if iy == 0x7f800000 { + match m { + 0 => PI / 4., /* atan(+INF,+INF) */ + 1 => -PI / 4., /* atan(-INF,+INF) */ + 2 => 3. * PI / 4., /* atan(+INF,-INF)*/ + 3 | _ => -3. * PI / 4., /* atan(-INF,-INF)*/ + } + } else { + match m { + 0 => 0., /* atan(+...,+INF) */ + 1 => -0., /* atan(-...,+INF) */ + 2 => PI, /* atan(+...,-INF) */ + 3 | _ => -PI, /* atan(-...,-INF) */ + } + }; + } + /* |y/x| > 0x1p26 */ + if (ix + (26 << 23) < iy) || (iy == 0x7f800000) { + return if m & 1 != 0 { -PI / 2. } else { PI / 2. }; + } + + /* z = atan(|y/x|) with correct underflow */ + let z = if (m & 2 != 0) && (iy + (26 << 23) < ix) { + /*|y/x| < 0x1p-26, x < 0 */ + 0. + } else { + atanf(fabsf(y / x)) + }; + match m { + 0 => z, /* atan(+,+) */ + 1 => -z, /* atan(-,+) */ + 2 => PI - (z - PI_LO), /* atan(+,-) */ + _ => (z - PI_LO) - PI, /* case 3 */ /* atan(-,-) */ + } +} diff --git a/library/compiler-builtins/libm/src/math/coshf.rs b/library/compiler-builtins/libm/src/math/coshf.rs new file mode 100644 index 0000000000000..bd468f5da712c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/coshf.rs @@ -0,0 +1,33 @@ +use super::expf; +use super::expm1f; +use super::k_expo2f; + +#[inline] +pub fn coshf(mut x: f32) -> f32 { + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + /* |x| */ + let mut ix = x.to_bits(); + ix &= 0x7fffffff; + x = f32::from_bits(ix); + let w = ix; + + /* |x| < log(2) */ + if w < 0x3f317217 { + if w < (0x3f800000 - (12 << 23)) { + force_eval!(x + x1p120); + return 1.; + } + let t = expm1f(x); + return 1. + t * t / (2. * (1. + t)); + } + + /* |x| < log(FLT_MAX) */ + if w < 0x42b17217 { + let t = expf(x); + return 0.5 * (t + 1. / t); + } + + /* |x| > log(FLT_MAX) or nan */ + k_expo2f(x) +} diff --git a/library/compiler-builtins/libm/src/math/k_expo2f.rs b/library/compiler-builtins/libm/src/math/k_expo2f.rs new file mode 100644 index 0000000000000..031a0bdd0365c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_expo2f.rs @@ -0,0 +1,14 @@ +use super::expf; + +/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ +const K: i32 = 235; +const K_LN2: f32 = 162.89; /* 0x1.45c778p+7f */ + +/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ +#[inline] +pub(crate) fn k_expo2f(x: f32) -> f32 { + /* note that k is odd and scale*scale overflows */ + let scale = f32::from_bits(((0x7f + K / 2) as u32) << 23); + /* exp(x - k ln2) * 2**(k-1) */ + expf(x - K_LN2) * scale * scale +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 42c596857d7e5..1ac5472576b2e 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -10,12 +10,14 @@ mod acos; mod acosf; mod asin; mod asinf; +mod atan2f; mod atanf; mod cbrt; mod cbrtf; mod ceil; mod ceilf; mod cosf; +mod coshf; mod exp; mod exp2; mod exp2f; @@ -50,6 +52,7 @@ mod sinf; mod sqrt; mod sqrtf; mod tanf; +mod tanhf; mod trunc; mod truncf; @@ -58,12 +61,14 @@ pub use self::acos::acos; pub use self::acosf::acosf; pub use self::asin::asin; pub use self::asinf::asinf; +pub use self::atan2f::atan2f; pub use self::atanf::atanf; pub use self::cbrt::cbrt; pub use self::cbrtf::cbrtf; pub use self::ceil::ceil; pub use self::ceilf::ceilf; pub use self::cosf::cosf; +pub use self::coshf::coshf; pub use self::exp::exp; pub use self::exp2::exp2; pub use self::exp2f::exp2f; @@ -98,18 +103,20 @@ pub use self::sinf::sinf; pub use self::sqrt::sqrt; pub use self::sqrtf::sqrtf; pub use self::tanf::tanf; +pub use self::tanhf::tanhf; pub use self::trunc::trunc; pub use self::truncf::truncf; mod k_cosf; +mod k_expo2f; mod k_sinf; mod k_tanf; mod rem_pio2_large; mod rem_pio2f; use self::{ - k_cosf::k_cosf, k_sinf::k_sinf, k_tanf::k_tanf, rem_pio2_large::rem_pio2_large, - rem_pio2f::rem_pio2f, + k_cosf::k_cosf, k_expo2f::k_expo2f, k_sinf::k_sinf, k_tanf::k_tanf, + rem_pio2_large::rem_pio2_large, rem_pio2f::rem_pio2f, }; #[inline] diff --git a/library/compiler-builtins/libm/src/math/tanhf.rs b/library/compiler-builtins/libm/src/math/tanhf.rs new file mode 100644 index 0000000000000..98a1b60c29be2 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/tanhf.rs @@ -0,0 +1,39 @@ +use super::expm1f; + +#[inline] +pub fn tanhf(mut x: f32) -> f32 { + /* x = |x| */ + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + x = f32::from_bits(ix); + let w = ix; + + let tt = if w > 0x3f0c9f54 { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if w > 0x41200000 { + /* |x| > 10 */ + 1. + 0. / x + } else { + let t = expm1f(2. * x); + 1. - 2. / (t + 2.) + } + } else if w > 0x3e82c578 { + /* |x| > log(5/3)/2 ~= 0.2554 */ + let t = expm1f(2. * x); + t / (t + 2.) + } else if w >= 0x00800000 { + /* |x| >= 0x1p-126 */ + let t = expm1f(-2. * x); + -t / (t + 2.) + } else { + /* |x| is subnormal */ + force_eval!(x * x); + x + }; + if sign { + -tt + } else { + tt + } +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index b639cf11b19aa..1c261b2ebafec 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -659,7 +659,7 @@ f32_f32! { cbrtf, cosf, ceilf, - // coshf, + coshf, exp2f, expf, expm1f, @@ -671,14 +671,14 @@ f32_f32! { sinf, // sinhf, tanf, - // tanhf, + tanhf, fabsf, sqrtf, } // With signature `fn(f32, f32) -> f32` f32f32_f32! { - // atan2f, + atan2f, fdimf, hypotf, fmodf, From dde8131c1e8ecb9c55d1b5f6888ce70d55119cd3 Mon Sep 17 00:00:00 2001 From: C Jones Date: Sat, 14 Jul 2018 19:23:01 -0400 Subject: [PATCH 0553/4206] Implement sinh This also adds expo2 for the __expo2 function, and combine_words() to replace the INSERT_WORDS macro. Closes rust-lang/libm#35 --- library/compiler-builtins/libm/src/lib.rs | 2 - .../compiler-builtins/libm/src/math/expo2.rs | 13 +++++ .../compiler-builtins/libm/src/math/mod.rs | 9 ++++ .../compiler-builtins/libm/src/math/sinh.rs | 48 +++++++++++++++++++ .../libm/test-generator/src/main.rs | 2 +- 5 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/expo2.rs create mode 100644 library/compiler-builtins/libm/src/math/sinh.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 0b9efeeb338a6..ee864a36cf2e1 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -414,7 +414,6 @@ pub trait F64Ext: private::Sealed { fn ln_1p(self) -> Self; - #[cfg(todo)] fn sinh(self) -> Self; #[cfg(todo)] @@ -595,7 +594,6 @@ impl F64Ext for f64 { log1p(self) } - #[cfg(todo)] #[inline] fn sinh(self) -> Self { sinh(self) diff --git a/library/compiler-builtins/libm/src/math/expo2.rs b/library/compiler-builtins/libm/src/math/expo2.rs new file mode 100644 index 0000000000000..8a121b0a287a0 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/expo2.rs @@ -0,0 +1,13 @@ +use super::{combine_words, exp}; + +/* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */ +pub(crate) fn expo2(x: f64) -> f64 { + /* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */ + const K: i32 = 2043; + let kln2 = f64::from_bits(0x40962066151add8b); + + /* note that k is odd and scale*scale overflows */ + let scale = combine_words(((0x3ff + K / 2) as u32) << 20, 0); + /* exp(x - k ln2) * 2**(k-1) */ + return exp(x - kln2) * scale * scale; +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 7b3d9abee697a..19d8ad58d8666 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -50,6 +50,7 @@ mod scalbn; mod scalbnf; mod sin; mod sinf; +mod sinh; mod sqrt; mod sqrtf; mod tanf; @@ -100,6 +101,7 @@ pub use self::scalbn::scalbn; pub use self::scalbnf::scalbnf; pub use self::sin::sin; pub use self::sinf::sinf; +pub use self::sinh::sinh; pub use self::sqrt::sqrt; pub use self::sqrtf::sqrtf; pub use self::tanf::tanf; @@ -107,6 +109,7 @@ pub use self::trunc::trunc; pub use self::truncf::truncf; // Private modules +mod expo2; mod k_cos; mod k_cosf; mod k_sin; @@ -117,6 +120,7 @@ mod rem_pio2_large; mod rem_pio2f; // Private re-imports +use self::expo2::expo2; use self::k_cos::k_cos; use self::k_cosf::k_cosf; use self::k_sin::k_sin; @@ -151,3 +155,8 @@ pub fn with_set_low_word(f: f64, lo: u32) -> f64 { tmp |= lo as u64; f64::from_bits(tmp) } + +#[inline] +fn combine_words(hi: u32, lo: u32) -> f64 { + f64::from_bits((hi as u64) << 32 | lo as u64) +} diff --git a/library/compiler-builtins/libm/src/math/sinh.rs b/library/compiler-builtins/libm/src/math/sinh.rs new file mode 100644 index 0000000000000..0579871719a8d --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sinh.rs @@ -0,0 +1,48 @@ +use super::{expm1, expo2}; + +// sinh(x) = (exp(x) - 1/exp(x))/2 +// = (exp(x)-1 + (exp(x)-1)/exp(x))/2 +// = x + x^3/6 + o(x^5) +// +pub fn sinh(x: f64) -> f64 { + // union {double f; uint64_t i;} u = {.f = x}; + // uint32_t w; + // double t, h, absx; + + let mut uf: f64 = x; + let mut ui: u64 = f64::to_bits(uf); + let w: u32; + let t: f64; + let mut h: f64; + let absx: f64; + + h = 0.5; + if ui >> 63 != 0 { + h = -h; + } + /* |x| */ + ui &= !1 / 2; + uf = f64::from_bits(ui); + absx = uf; + w = (ui >> 32) as u32; + + /* |x| < log(DBL_MAX) */ + if w < 0x40862e42 { + t = expm1(absx); + if w < 0x3ff00000 { + if w < 0x3ff00000 - (26 << 20) { + /* note: inexact and underflow are raised by expm1 */ + /* note: this branch avoids spurious underflow */ + return x; + } + return h * (2.0 * t - t * t / (t + 1.0)); + } + /* note: |x|>log(0x1p26)+eps could be just h*exp(x) */ + return h * (t + t / (t + 1.0)); + } + + /* |x| > log(DBL_MAX) or nan */ + /* note: the result is stored to handle overflow */ + t = 2.0 * h * expo2(absx); + return t; +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index c8e35cea7b00c..758db9f527fb6 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -714,7 +714,7 @@ f64_f64! { log2, round, sin, - // sinh, + sinh, sqrt, // tan, // tanh, From 0be652de3a29a7dcb5817c17f746543616980c1f Mon Sep 17 00:00:00 2001 From: C Jones Date: Sat, 14 Jul 2018 16:08:41 -0400 Subject: [PATCH 0554/4206] Implement tan Also includes implementing the private k_tan function. Closes rust-lang/libm#36 --- library/compiler-builtins/libm/src/lib.rs | 2 - .../compiler-builtins/libm/src/math/k_tan.rs | 105 ++++++++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 4 + .../compiler-builtins/libm/src/math/tan.rs | 69 ++++++++++++ .../libm/test-generator/src/main.rs | 2 +- 5 files changed, 179 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/k_tan.rs create mode 100644 library/compiler-builtins/libm/src/math/tan.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 0b9efeeb338a6..e6f286a9edc6e 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -390,7 +390,6 @@ pub trait F64Ext: private::Sealed { fn cos(self) -> Self; - #[cfg(todo)] fn tan(self) -> Self; #[cfg(todo)] @@ -556,7 +555,6 @@ impl F64Ext for f64 { cos(self) } - #[cfg(todo)] #[inline] fn tan(self) -> Self { tan(self) diff --git a/library/compiler-builtins/libm/src/math/k_tan.rs b/library/compiler-builtins/libm/src/math/k_tan.rs new file mode 100644 index 0000000000000..b0dd317a2e727 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_tan.rs @@ -0,0 +1,105 @@ +// origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ +// +// ==================================================== +// Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. +// +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== + +// kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 +// Input x is assumed to be bounded by ~pi/4 in magnitude. +// Input y is the tail of x. +// Input odd indicates whether tan (if odd = 0) or -1/tan (if odd = 1) is returned. +// +// Algorithm +// 1. Since tan(-x) = -tan(x), we need only to consider positive x. +// 2. Callers must return tan(-0) = -0 without calling here since our +// odd polynomial is not evaluated in a way that preserves -0. +// Callers may do the optimization tan(x) ~ x for tiny x. +// 3. tan(x) is approximated by a odd polynomial of degree 27 on +// [0,0.67434] +// 3 27 +// tan(x) ~ x + T1*x + ... + T13*x +// where +// +// |tan(x) 2 4 26 | -59.2 +// |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2 +// | x | +// +// Note: tan(x+y) = tan(x) + tan'(x)*y +// ~ tan(x) + (1+x*x)*y +// Therefore, for better accuracy in computing tan(x+y), let +// 3 2 2 2 2 +// r = x *(T2+x *(T3+x *(...+x *(T12+x *T13)))) +// then +// 3 2 +// tan(x+y) = x + (T1*x + (x *(r+y)+y)) +// +// 4. For x in [0.67434,pi/4], let y = pi/4 - x, then +// tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y)) +// = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y))) +static T: [f64; 13] = [ + 3.33333333333334091986e-01, /* 3FD55555, 55555563 */ + 1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */ + 5.39682539762260521377e-02, /* 3FABA1BA, 1BB341FE */ + 2.18694882948595424599e-02, /* 3F9664F4, 8406D637 */ + 8.86323982359930005737e-03, /* 3F8226E3, E96E8493 */ + 3.59207910759131235356e-03, /* 3F6D6D22, C9560328 */ + 1.45620945432529025516e-03, /* 3F57DBC8, FEE08315 */ + 5.88041240820264096874e-04, /* 3F4344D8, F2F26501 */ + 2.46463134818469906812e-04, /* 3F3026F7, 1A8D1068 */ + 7.81794442939557092300e-05, /* 3F147E88, A03792A6 */ + 7.14072491382608190305e-05, /* 3F12B80F, 32F0A7E9 */ + -1.85586374855275456654e-05, /* BEF375CB, DB605373 */ + 2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */ +]; +const PIO4: f64 = 7.85398163397448278999e-01; /* 3FE921FB, 54442D18 */ +const PIO4_LO: f64 = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ + +pub(crate) fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { + let hx = (f64::to_bits(x) >> 32) as u32; + let big = (hx & 0x7fffffff) >= 0x3FE59428; /* |x| >= 0.6744 */ + if big { + let sign = hx >> 31; + if sign != 0 { + x = -x; + y = -y; + } + x = (PIO4 - x) + (PIO4_LO - y); + y = 0.0; + } + let z = x * x; + let w = z * z; + /* + * Break x^5*(T[1]+x^2*T[2]+...) into + * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) + + * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12])) + */ + let r = T[1] + w * (T[3] + w * (T[5] + w * (T[7] + w * (T[9] + w * T[11])))); + let v = z * (T[2] + w * (T[4] + w * (T[6] + w * (T[8] + w * (T[10] + w * T[12]))))); + let s = z * x; + let r = y + z * (s * (r + v) + y) + s * T[0]; + let w = x + r; + if big { + let sign = hx >> 31; + let s = 1.0 - 2.0 * odd as f64; + let v = s - 2.0 * (x + (r - w * w / (w + s))); + return if sign != 0 { -v } else { v }; + } + if odd == 0 { + return w; + } + /* -1.0/(x+r) has up to 2ulp error, so compute it accurately */ + let w0 = zero_low_word(w); + let v = r - (w0 - x); /* w0+v = r+x */ + let a = -1.0 / w; + let a0 = zero_low_word(a); + a0 + a * (1.0 + a0 * w0 + a0 * v) +} + +#[inline] +fn zero_low_word(x: f64) -> f64 { + f64::from_bits(f64::to_bits(x) & 0xFFFF_FFFF_0000_0000) +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 7b3d9abee697a..a6ce52394cf4d 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -52,6 +52,7 @@ mod sin; mod sinf; mod sqrt; mod sqrtf; +mod tan; mod tanf; mod trunc; mod truncf; @@ -102,6 +103,7 @@ pub use self::sin::sin; pub use self::sinf::sinf; pub use self::sqrt::sqrt; pub use self::sqrtf::sqrtf; +pub use self::tan::tan; pub use self::tanf::tanf; pub use self::trunc::trunc; pub use self::truncf::truncf; @@ -111,6 +113,7 @@ mod k_cos; mod k_cosf; mod k_sin; mod k_sinf; +mod k_tan; mod k_tanf; mod rem_pio2; mod rem_pio2_large; @@ -121,6 +124,7 @@ use self::k_cos::k_cos; use self::k_cosf::k_cosf; use self::k_sin::k_sin; use self::k_sinf::k_sinf; +use self::k_tan::k_tan; use self::k_tanf::k_tanf; use self::rem_pio2::rem_pio2; use self::rem_pio2_large::rem_pio2_large; diff --git a/library/compiler-builtins/libm/src/math/tan.rs b/library/compiler-builtins/libm/src/math/tan.rs new file mode 100644 index 0000000000000..92bbb6221229d --- /dev/null +++ b/library/compiler-builtins/libm/src/math/tan.rs @@ -0,0 +1,69 @@ +// origin: FreeBSD /usr/src/lib/msun/src/s_tan.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. +// ==================================================== + +use super::{k_tan, rem_pio2}; + +// tan(x) +// Return tangent function of x. +// +// kernel function: +// k_tan ... tangent function on [-pi/4,pi/4] +// rem_pio2 ... argument reduction routine +// +// Method. +// Let S,C and T denote the sin, cos and tan respectively on +// [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 +// in [-pi/4 , +pi/4], and let n = k mod 4. +// We have +// +// n sin(x) cos(x) tan(x) +// ---------------------------------------------------------- +// 0 S C T +// 1 C -S -1/T +// 2 -S -C T +// 3 -C S -1/T +// ---------------------------------------------------------- +// +// Special cases: +// Let trig be any of sin, cos, or tan. +// trig(+-INF) is NaN, with signals; +// trig(NaN) is that NaN; +// +// Accuracy: +// TRIG(x) returns trig(x) nearly rounded +pub fn tan(x: f64) -> f64 { + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + /* |x| ~< pi/4 */ + if ix <= 0x3fe921fb { + if ix < 0x3e400000 { + /* |x| < 2**-27 */ + /* raise inexact if x!=0 and underflow if subnormal */ + force_eval!(if ix < 0x00100000 { + x / x1p120 as f64 + } else { + x + x1p120 as f64 + }); + return x; + } + return k_tan(x, 0.0, 0); + } + + /* tan(Inf or NaN) is NaN */ + if ix >= 0x7ff00000 { + return x - x; + } + + /* argument reduction */ + let (n, y0, y1) = rem_pio2(x); + k_tan(y0, y1, n & 1) +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index c8e35cea7b00c..5d47cb2a45b6f 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -716,7 +716,7 @@ f64_f64! { sin, // sinh, sqrt, - // tan, + tan, // tanh, trunc, fabs, From f8e937fa466f721925073225a1a2177eee8b8e81 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sun, 15 Jul 2018 07:01:26 +0300 Subject: [PATCH 0555/4206] sinf, fix constant in k_expo2f --- library/compiler-builtins/libm/src/lib.rs | 2 -- .../libm/src/math/k_expo2f.rs | 4 +-- .../compiler-builtins/libm/src/math/mod.rs | 2 ++ .../compiler-builtins/libm/src/math/sinhf.rs | 30 +++++++++++++++++++ .../libm/test-generator/src/main.rs | 2 +- 5 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/sinhf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 1ed07873421ec..45213a25f7ab5 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -108,7 +108,6 @@ pub trait F32Ext: private::Sealed { fn ln_1p(self) -> Self; - #[cfg(todo)] fn sinh(self) -> Self; fn cosh(self) -> Self; @@ -284,7 +283,6 @@ impl F32Ext for f32 { log1pf(self) } - #[cfg(todo)] #[inline] fn sinh(self) -> Self { sinhf(self) diff --git a/library/compiler-builtins/libm/src/math/k_expo2f.rs b/library/compiler-builtins/libm/src/math/k_expo2f.rs index 031a0bdd0365c..e2eaa4e6bb024 100644 --- a/library/compiler-builtins/libm/src/math/k_expo2f.rs +++ b/library/compiler-builtins/libm/src/math/k_expo2f.rs @@ -2,13 +2,13 @@ use super::expf; /* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ const K: i32 = 235; -const K_LN2: f32 = 162.89; /* 0x1.45c778p+7f */ /* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ #[inline] pub(crate) fn k_expo2f(x: f32) -> f32 { + let k_ln2 = f32::from_bits(0x4322e3bc); /* note that k is odd and scale*scale overflows */ let scale = f32::from_bits(((0x7f + K / 2) as u32) << 23); /* exp(x - k ln2) * 2**(k-1) */ - expf(x - K_LN2) * scale * scale + expf(x - k_ln2) * scale * scale } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index a29f2fb0ab43f..eda6b5b729312 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -53,6 +53,7 @@ mod scalbnf; mod sin; mod sinf; mod sinh; +mod sinhf; mod sqrt; mod sqrtf; mod tan; @@ -108,6 +109,7 @@ pub use self::scalbnf::scalbnf; pub use self::sin::sin; pub use self::sinf::sinf; pub use self::sinh::sinh; +pub use self::sinhf::sinhf; pub use self::sqrt::sqrt; pub use self::sqrtf::sqrtf; pub use self::tan::tan; diff --git a/library/compiler-builtins/libm/src/math/sinhf.rs b/library/compiler-builtins/libm/src/math/sinhf.rs new file mode 100644 index 0000000000000..90c4b9312819f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sinhf.rs @@ -0,0 +1,30 @@ +use super::expm1f; +use super::k_expo2f; + +#[inline] +pub fn sinhf(x: f32) -> f32 { + let mut h = 0.5f32; + let mut ix = x.to_bits(); + if (ix >> 31) != 0 { + h = -h; + } + /* |x| */ + ix &= 0x7fffffff; + let absx = f32::from_bits(ix); + let w = ix; + + /* |x| < log(FLT_MAX) */ + if w < 0x42b17217 { + let t = expm1f(absx); + if w < 0x3f800000 { + if w < (0x3f800000 - (12 << 23)) { + return x; + } + return h * (2. * t - t * t / (t + 1.)); + } + return h * (t + t / (t + 1.)); + } + + /* |x| > logf(FLT_MAX) or nan */ + 2. * h * k_expo2f(absx) +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 6708891f3ed3c..7caada4ef3e94 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -669,7 +669,7 @@ f32_f32! { logf, roundf, sinf, - // sinhf, + sinhf, tanf, tanhf, fabsf, From 76b675c202bd964d1c3e86c9a806f6aeffc4c0f2 Mon Sep 17 00:00:00 2001 From: Joseph Ryan Date: Sun, 15 Jul 2018 01:17:46 -0500 Subject: [PATCH 0556/4206] implement atan2 --- library/compiler-builtins/libm/src/lib.rs | 2 - .../compiler-builtins/libm/src/math/atan2.rs | 72 +++++++++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 2 + .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/atan2.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 45213a25f7ab5..e7abce540af4f 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -392,7 +392,6 @@ pub trait F64Ext: private::Sealed { #[cfg(todo)] fn atan(self) -> Self; - #[cfg(todo)] fn atan2(self, other: Self) -> Self; #[cfg(todo)] @@ -568,7 +567,6 @@ impl F64Ext for f64 { atan(self) } - #[cfg(todo)] #[inline] fn atan2(self, other: Self) -> Self { atan2(self, other) diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs new file mode 100644 index 0000000000000..324b1e937f94f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -0,0 +1,72 @@ +use super::atan; +use super::fabs; + +const PI: f64 = 3.1415926535897931160E+00; /* 0x400921FB, 0x54442D18 */ +const PI_LO: f64 = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ + +#[inline] +pub fn atan2(y: f64, x: f64) -> f64 { + if x.is_nan() || y.is_nan() { + return x + y; + } + let mut ix = (x.to_bits() >> 32) as u32; + let lx = x.to_bits() as u32; + let mut iy = (y.to_bits() >> 32) as u32; + let ly = y.to_bits() as u32; + if (ix - 0x3ff00000 | lx) == 0 { + /* x = 1.0 */ + return atan(y); + } + let m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */ + ix &= 0x7fffffff; + iy &= 0x7fffffff; + + /* when y = 0 */ + if (iy | ly) == 0 { + return match m { + 0 | 1 => y, /* atan(+-0,+anything)=+-0 */ + 2 => PI, /* atan(+0,-anything) = PI */ + _ => -PI, /* atan(-0,-anything) =-PI */ + }; + } + /* when x = 0 */ + if (ix | lx) == 0 { + return if m & 1 != 0 { -PI / 2.0 } else { PI / 2.0 }; + } + /* when x is INF */ + if ix == 0x7ff00000 { + if iy == 0x7ff00000 { + return match m { + 0 => PI / 4.0, /* atan(+INF,+INF) */ + 1 => -PI / 4.0, /* atan(-INF,+INF) */ + 2 => 3.0 * PI / 4.0, /* atan(+INF,-INF) */ + _ => -3.0 * PI / 4.0, /* atan(-INF,-INF) */ + }; + } else { + return match m { + 0 => 0.0, /* atan(+...,+INF) */ + 1 => -0.0, /* atan(-...,+INF) */ + 2 => PI, /* atan(+...,-INF) */ + _ => -PI, /* atan(-...,-INF) */ + }; + } + } + /* |y/x| > 0x1p64 */ + if ix + (64 << 20) < iy || iy == 0x7ff00000 { + return if m & 1 != 0 { -PI / 2.0 } else { PI / 2.0 }; + } + + /* z = atan(|y/x|) without spurious underflow */ + let z = if (m & 2 != 0) && iy + (64 << 20) < ix { + /* |y/x| < 0x1p-64, x<0 */ + 0.0 + } else { + atan(fabs(y / x)) + }; + match m { + 0 => z, /* atan(+,+) */ + 1 => -z, /* atan(-,+) */ + 2 => PI - (z - PI_LO), /* atan(+,-) */ + _ => (z - PI_LO) - PI, /* atan(-,-) */ + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index eda6b5b729312..07032dcfbca5b 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -11,6 +11,7 @@ mod acos; mod acosf; mod asin; mod asinf; +mod atan2; mod atan2f; mod atanf; mod cbrt; @@ -67,6 +68,7 @@ pub use self::acos::acos; pub use self::acosf::acosf; pub use self::asin::asin; pub use self::asinf::asinf; +pub use self::atan2::atan2; pub use self::atan2f::atan2f; pub use self::atanf::atanf; pub use self::cbrt::cbrt; diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 7caada4ef3e94..e65f0f69bb04a 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -724,7 +724,7 @@ f64_f64! { // With signature `fn(f64, f64) -> f64` f64f64_f64! { - // atan2, + atan2, fdim, fmod, hypot, From 14c3113694d81ed7e4c2dbe7877c2c73e32864f3 Mon Sep 17 00:00:00 2001 From: C Jones Date: Sat, 14 Jul 2018 19:42:47 -0400 Subject: [PATCH 0557/4206] Implement tanh Closes rust-lang/libm#37 --- library/compiler-builtins/libm/src/lib.rs | 2 - .../compiler-builtins/libm/src/math/mod.rs | 2 + .../compiler-builtins/libm/src/math/tanh.rs | 52 +++++++++++++++++++ .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/tanh.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 45213a25f7ab5..1eea30667bd09 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -410,7 +410,6 @@ pub trait F64Ext: private::Sealed { #[cfg(todo)] fn cosh(self) -> Self; - #[cfg(todo)] fn tanh(self) -> Self; #[cfg(todo)] @@ -595,7 +594,6 @@ impl F64Ext for f64 { cosh(self) } - #[cfg(todo)] #[inline] fn tanh(self) -> Self { tanh(self) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index eda6b5b729312..5fc787c82178d 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -58,6 +58,7 @@ mod sqrt; mod sqrtf; mod tan; mod tanf; +mod tanh; mod tanhf; mod trunc; mod truncf; @@ -114,6 +115,7 @@ pub use self::sqrt::sqrt; pub use self::sqrtf::sqrtf; pub use self::tan::tan; pub use self::tanf::tanf; +pub use self::tanh::tanh; pub use self::tanhf::tanhf; pub use self::trunc::trunc; pub use self::truncf::truncf; diff --git a/library/compiler-builtins/libm/src/math/tanh.rs b/library/compiler-builtins/libm/src/math/tanh.rs new file mode 100644 index 0000000000000..657d7e0e276dc --- /dev/null +++ b/library/compiler-builtins/libm/src/math/tanh.rs @@ -0,0 +1,52 @@ +use super::expm1; + +/* tanh(x) = (exp(x) - exp(-x))/(exp(x) + exp(-x)) + * = (exp(2*x) - 1)/(exp(2*x) - 1 + 2) + * = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2) + */ +pub fn tanh(mut x: f64) -> f64 { + let mut uf: f64 = x; + let mut ui: u64 = f64::to_bits(uf); + + let w: u32; + let sign: bool; + let mut t: f64; + + /* x = |x| */ + sign = ui >> 63 != 0; + ui &= !1 / 2; + uf = f64::from_bits(ui); + x = uf; + w = (ui >> 32) as u32; + + if w > 0x3fe193ea { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if w > 0x40340000 { + /* |x| > 20 or nan */ + /* note: this branch avoids raising overflow */ + t = 1.0 - 0.0 / x; + } else { + t = expm1(2.0 * x); + t = 1.0 - 2.0 / (t + 2.0); + } + } else if w > 0x3fd058ae { + /* |x| > log(5/3)/2 ~= 0.2554 */ + t = expm1(2.0 * x); + t = t / (t + 2.0); + } else if w >= 0x00100000 { + /* |x| >= 0x1p-1022, up to 2ulp error in [0.1,0.2554] */ + t = expm1(-2.0 * x); + t = -t / (t + 2.0); + } else { + /* |x| is subnormal */ + /* note: the branch above would not raise underflow in [0x1p-1023,0x1p-1022) */ + force_eval!(x as f32); + t = x; + } + + if sign { + -t + } else { + t + } +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 7caada4ef3e94..1d619cd9292b1 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -717,7 +717,7 @@ f64_f64! { sinh, sqrt, tan, - // tanh, + tanh, trunc, fabs, } From 865fedeac63f00c180c62b279f01eade7dee0761 Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 14 Jul 2018 15:22:41 -0400 Subject: [PATCH 0558/4206] implement fmaf --- library/compiler-builtins/libm/src/lib.rs | 2 - .../compiler-builtins/libm/src/math/fmaf.rs | 94 +++++++++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 2 + .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fmaf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 45213a25f7ab5..f0fdd464c6448 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -52,7 +52,6 @@ pub trait F32Ext: private::Sealed { #[cfg(todo)] fn signum(self) -> Self; - #[cfg(todo)] fn mul_add(self, a: Self, b: Self) -> Self; #[cfg(todo)] @@ -161,7 +160,6 @@ impl F32Ext for f32 { fabsf(self) } - #[cfg(todo)] #[inline] fn mul_add(self, a: Self, b: Self) -> Self { fmaf(self, a, b) diff --git a/library/compiler-builtins/libm/src/math/fmaf.rs b/library/compiler-builtins/libm/src/math/fmaf.rs new file mode 100644 index 0000000000000..70d2c54a27e37 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmaf.rs @@ -0,0 +1,94 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_fmaf.c */ +/*- + * Copyright (c) 2005-2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +use core::f32; +use core::ptr::read_volatile; + +/* + * Fused multiply-add: Compute x * y + z with a single rounding error. + * + * A double has more than twice as much precision than a float, so + * direct double-precision arithmetic suffices, except where double + * rounding occurs. + */ +#[inline] +pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { + let xy: f64; + let mut result: f64; + let mut ui: u64; + let e: i32; + + xy = x as f64 * y as f64; + result = xy + z as f64; + ui = result.to_bits(); + e = (ui >> 52) as i32 & 0x7ff; + /* Common case: The double precision result is fine. */ + if ( + /* not a halfway case */ + ui & 0x1fffffff) != 0x10000000 || + /* NaN */ + e == 0x7ff || + /* exact */ + (result - xy == z as f64 && result - z as f64 == xy) || + /* not round-to-nearest */ + fegetround() != FE_TONEAREST + { + /* + underflow may not be raised correctly, example: + fmaf(0x1p-120f, 0x1p-120f, 0x1p-149f) + */ + if e < 0x3ff - 126 && e >= 0x3ff - 149 && fetestexcept(FE_INEXACT) { + feclearexcept(FE_INEXACT); + /* TODO: gcc and clang bug workaround */ + let vz: f32 = unsafe { read_volatile(&z) }; + result = xy + vz as f64; + if fetestexcept(FE_INEXACT) { + feraiseexcept(FE_UNDERFLOW); + } else { + feraiseexcept(FE_INEXACT); + } + } + z = result as f32; + return z; + } + + /* + * If result is inexact, and exactly halfway between two float values, + * we need to adjust the low-order bit in the direction of the error. + */ + fesetround(FE_TOWARDZERO); + let vxy: f64 = unsafe { read_volatile(&xy) }; /* XXX work around gcc CSE bug */ + let mut adjusted_result: f64 = vxy + z as f64; + fesetround(FE_TONEAREST); + if result == adjusted_result { + ui = adjusted_result.to_bits(); + ui += 1; + adjusted_result = f64::from_bits(ui); + } + z = adjusted_result as f32; + z +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index eda6b5b729312..ad9aead7c386b 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -33,6 +33,7 @@ mod fdimf; mod floor; mod floorf; mod fma; +mod fmaf; mod fmod; mod fmodf; mod hypot; @@ -89,6 +90,7 @@ pub use self::fdimf::fdimf; pub use self::floor::floor; pub use self::floorf::floorf; pub use self::fma::fma; +pub use self::fmaf::fmaf; pub use self::fmod::fmod; pub use self::fmodf::fmodf; pub use self::hypot::hypot; diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 7caada4ef3e94..a2a301d133cf0 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -687,7 +687,7 @@ f32f32_f32! { // With signature `fn(f32, f32, f32) -> f32` f32f32f32_f32! { - // fmaf, + fmaf, } // With signature `fn(f32, i32) -> f32` From 7084ce52b709905a823b6f371487eab6bbf57148 Mon Sep 17 00:00:00 2001 From: Erik Date: Sun, 15 Jul 2018 13:14:29 -0400 Subject: [PATCH 0559/4206] add dummy fenv implementation --- .../compiler-builtins/libm/src/math/fenv.rs | 33 +++++++++++++++++++ .../compiler-builtins/libm/src/math/fmaf.rs | 14 +++++--- .../compiler-builtins/libm/src/math/mod.rs | 1 + 3 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fenv.rs diff --git a/library/compiler-builtins/libm/src/math/fenv.rs b/library/compiler-builtins/libm/src/math/fenv.rs new file mode 100644 index 0000000000000..652e6032452b3 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fenv.rs @@ -0,0 +1,33 @@ +// src: musl/src/fenv/fenv.c +/* Dummy functions for archs lacking fenv implementation */ + +pub(crate) const FE_UNDERFLOW: i32 = 0; +pub(crate) const FE_INEXACT: i32 = 0; + +pub(crate) const FE_TONEAREST: i32 = 0; +pub(crate) const FE_TOWARDZERO: i32 = 0; + +#[inline] +pub(crate) fn feclearexcept(_mask: i32) -> i32 { + 0 +} + +#[inline] +pub(crate) fn feraiseexcept(_mask: i32) -> i32 { + 0 +} + +#[inline] +pub(crate) fn fetestexcept(_mask: i32) -> i32 { + 0 +} + +#[inline] +pub(crate) fn fegetround() -> i32 { + FE_TONEAREST +} + +#[inline] +pub(crate) fn fesetround(_r: i32) -> i32 { + 0 +} diff --git a/library/compiler-builtins/libm/src/math/fmaf.rs b/library/compiler-builtins/libm/src/math/fmaf.rs index 70d2c54a27e37..25b04fc239667 100644 --- a/library/compiler-builtins/libm/src/math/fmaf.rs +++ b/library/compiler-builtins/libm/src/math/fmaf.rs @@ -28,6 +28,11 @@ use core::f32; use core::ptr::read_volatile; +use super::fenv::{ + feclearexcept, fegetround, feraiseexcept, fesetround, fetestexcept, FE_INEXACT, FE_TONEAREST, + FE_TOWARDZERO, FE_UNDERFLOW, +}; + /* * Fused multiply-add: Compute x * y + z with a single rounding error. * @@ -61,12 +66,12 @@ pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { underflow may not be raised correctly, example: fmaf(0x1p-120f, 0x1p-120f, 0x1p-149f) */ - if e < 0x3ff - 126 && e >= 0x3ff - 149 && fetestexcept(FE_INEXACT) { + if e < 0x3ff - 126 && e >= 0x3ff - 149 && fetestexcept(FE_INEXACT) != 0 { feclearexcept(FE_INEXACT); - /* TODO: gcc and clang bug workaround */ + // prevent `xy + vz` from being CSE'd with `xy + z` above let vz: f32 = unsafe { read_volatile(&z) }; result = xy + vz as f64; - if fetestexcept(FE_INEXACT) { + if fetestexcept(FE_INEXACT) != 0 { feraiseexcept(FE_UNDERFLOW); } else { feraiseexcept(FE_INEXACT); @@ -81,7 +86,8 @@ pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { * we need to adjust the low-order bit in the direction of the error. */ fesetround(FE_TOWARDZERO); - let vxy: f64 = unsafe { read_volatile(&xy) }; /* XXX work around gcc CSE bug */ + // prevent `vxy + z` from being CSE'd with `xy + z` above + let vxy: f64 = unsafe { read_volatile(&xy) }; let mut adjusted_result: f64 = vxy + z as f64; fesetround(FE_TONEAREST); if result == adjusted_result { diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index ad9aead7c386b..92db426bf21d2 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -122,6 +122,7 @@ pub use self::truncf::truncf; // Private modules mod expo2; +mod fenv; mod k_cos; mod k_cosf; mod k_expo2f; From ee33990f46cd2c1c8039a00e0f486f0afe8dcfdc Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 15 Jul 2018 13:24:09 -0500 Subject: [PATCH 0560/4206] update CHANGELOG; make utility functions private --- library/compiler-builtins/libm/CHANGELOG.md | 13 +++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 9 +++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index 3a496527bc040..107813b081364 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -5,6 +5,19 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Added + +- atan2f +- cos +- coshf +- fmaf +- sin +- sinh +- sinhf +- tan +- tanh +- tanhf + ## [v0.1.1] - 2018-07-14 ### Added diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index c6a3424d8ad2f..7fa4252077d7c 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -150,17 +150,18 @@ use self::rem_pio2_large::rem_pio2_large; use self::rem_pio2f::rem_pio2f; #[inline] -pub fn get_high_word(x: f64) -> u32 { +fn get_high_word(x: f64) -> u32 { (x.to_bits() >> 32) as u32 } #[inline] -pub fn get_low_word(x: f64) -> u32 { +fn get_low_word(x: f64) -> u32 { x.to_bits() as u32 } +#[allow(dead_code)] #[inline] -pub fn with_set_high_word(f: f64, hi: u32) -> f64 { +fn with_set_high_word(f: f64, hi: u32) -> f64 { let mut tmp = f.to_bits(); tmp &= 0x00000000_ffffffff; tmp |= (hi as u64) << 32; @@ -168,7 +169,7 @@ pub fn with_set_high_word(f: f64, hi: u32) -> f64 { } #[inline] -pub fn with_set_low_word(f: f64, lo: u32) -> f64 { +fn with_set_low_word(f: f64, lo: u32) -> f64 { let mut tmp = f.to_bits(); tmp &= 0xffffffff_00000000; tmp |= lo as u64; From 60db814b549b8d28d88f4898bc085e48bdd3146a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 15 Jul 2018 14:50:00 -0500 Subject: [PATCH 0561/4206] add more copyright notices --- library/compiler-builtins/libm/src/math/acosf.rs | 15 +++++++++++++++ library/compiler-builtins/libm/src/math/asinf.rs | 15 +++++++++++++++ library/compiler-builtins/libm/src/math/atanf.rs | 15 +++++++++++++++ library/compiler-builtins/libm/src/math/cosf.rs | 16 ++++++++++++++++ library/compiler-builtins/libm/src/math/expm1.rs | 12 ++++++++++++ .../compiler-builtins/libm/src/math/expm1f.rs | 15 +++++++++++++++ .../compiler-builtins/libm/src/math/k_cosf.rs | 16 ++++++++++++++++ .../compiler-builtins/libm/src/math/k_sinf.rs | 16 ++++++++++++++++ .../compiler-builtins/libm/src/math/k_tanf.rs | 11 +++++++++++ .../libm/src/math/rem_pio2_large.rs | 12 ++++++++++++ .../compiler-builtins/libm/src/math/rem_pio2f.rs | 16 ++++++++++++++++ library/compiler-builtins/libm/src/math/sinf.rs | 16 ++++++++++++++++ library/compiler-builtins/libm/src/math/tanf.rs | 16 ++++++++++++++++ 13 files changed, 191 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/acosf.rs b/library/compiler-builtins/libm/src/math/acosf.rs index bbe29c17c131f..ff07fe9350169 100644 --- a/library/compiler-builtins/libm/src/math/acosf.rs +++ b/library/compiler-builtins/libm/src/math/acosf.rs @@ -1,3 +1,18 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_acosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + use super::sqrtf::sqrtf; const PIO2_HI: f32 = 1.5707962513e+00; /* 0x3fc90fda */ diff --git a/library/compiler-builtins/libm/src/math/asinf.rs b/library/compiler-builtins/libm/src/math/asinf.rs index 597be4cb7f989..86944bb005764 100644 --- a/library/compiler-builtins/libm/src/math/asinf.rs +++ b/library/compiler-builtins/libm/src/math/asinf.rs @@ -1,3 +1,18 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_asinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + use super::fabsf::fabsf; use super::sqrt::sqrt; diff --git a/library/compiler-builtins/libm/src/math/atanf.rs b/library/compiler-builtins/libm/src/math/atanf.rs index 01c41f4ce1781..b05152e2bc3e7 100644 --- a/library/compiler-builtins/libm/src/math/atanf.rs +++ b/library/compiler-builtins/libm/src/math/atanf.rs @@ -1,3 +1,18 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_atanf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + use super::fabsf; const ATAN_HI: [f32; 4] = [ diff --git a/library/compiler-builtins/libm/src/math/cosf.rs b/library/compiler-builtins/libm/src/math/cosf.rs index 79df97e354a37..23faacdc26cf7 100644 --- a/library/compiler-builtins/libm/src/math/cosf.rs +++ b/library/compiler-builtins/libm/src/math/cosf.rs @@ -1,3 +1,19 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + use super::{k_cosf, k_sinf, rem_pio2f}; use core::f64::consts::FRAC_PI_2; diff --git a/library/compiler-builtins/libm/src/math/expm1.rs b/library/compiler-builtins/libm/src/math/expm1.rs index 48082cd745cf3..a00396524e8de 100644 --- a/library/compiler-builtins/libm/src/math/expm1.rs +++ b/library/compiler-builtins/libm/src/math/expm1.rs @@ -1,3 +1,15 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1.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. + * ==================================================== + */ + use core::f64; const O_THRESHOLD: f64 = 7.09782712893383973096e+02; /* 0x40862E42, 0xFEFA39EF */ diff --git a/library/compiler-builtins/libm/src/math/expm1f.rs b/library/compiler-builtins/libm/src/math/expm1f.rs index 011e09b693d99..8f581733acd69 100644 --- a/library/compiler-builtins/libm/src/math/expm1f.rs +++ b/library/compiler-builtins/libm/src/math/expm1f.rs @@ -1,3 +1,18 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + const O_THRESHOLD: f32 = 8.8721679688e+01; /* 0x42b17180 */ const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ diff --git a/library/compiler-builtins/libm/src/math/k_cosf.rs b/library/compiler-builtins/libm/src/math/k_cosf.rs index 83d13b2e998ad..75579ef9bf495 100644 --- a/library/compiler-builtins/libm/src/math/k_cosf.rs +++ b/library/compiler-builtins/libm/src/math/k_cosf.rs @@ -1,3 +1,19 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_cosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + /* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ const C0: f64 = -0.499999997251031003120; /* -0x1ffffffd0c5e81.0p-54 */ const C1: f64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ diff --git a/library/compiler-builtins/libm/src/math/k_sinf.rs b/library/compiler-builtins/libm/src/math/k_sinf.rs index bb2183afc7cad..bb519c9c09e91 100644 --- a/library/compiler-builtins/libm/src/math/k_sinf.rs +++ b/library/compiler-builtins/libm/src/math/k_sinf.rs @@ -1,3 +1,19 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + /* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ const S1: f64 = -0.166666666416265235595; /* -0x15555554cbac77.0p-55 */ const S2: f64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ diff --git a/library/compiler-builtins/libm/src/math/k_tanf.rs b/library/compiler-builtins/libm/src/math/k_tanf.rs index db2e0caa7a5ef..6d3da1dcc8063 100644 --- a/library/compiler-builtins/libm/src/math/k_tanf.rs +++ b/library/compiler-builtins/libm/src/math/k_tanf.rs @@ -1,3 +1,14 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + /* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */ const T: [f64; 6] = [ 0.333331395030791399758, /* 0x15554d3418c99f.0p-54 */ 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 52b47279cd911..462eb0345157e 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -1,3 +1,15 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_rem_pio2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + use super::floor; use super::scalbn; diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs index 73ec3775d3dc5..e2368d93db64f 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2f.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2f.rs @@ -1,3 +1,19 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + use super::rem_pio2_large; use core::f64; diff --git a/library/compiler-builtins/libm/src/math/sinf.rs b/library/compiler-builtins/libm/src/math/sinf.rs index 09f62cddcae35..c9b02bcdc5138 100644 --- a/library/compiler-builtins/libm/src/math/sinf.rs +++ b/library/compiler-builtins/libm/src/math/sinf.rs @@ -1,3 +1,19 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + use super::{k_cosf, k_sinf, rem_pio2f}; use core::f64::consts::FRAC_PI_2; diff --git a/library/compiler-builtins/libm/src/math/tanf.rs b/library/compiler-builtins/libm/src/math/tanf.rs index 6bfbe06c1b4be..15a462d4e19f9 100644 --- a/library/compiler-builtins/libm/src/math/tanf.rs +++ b/library/compiler-builtins/libm/src/math/tanf.rs @@ -1,3 +1,19 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_tanf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + use super::{k_tanf, rem_pio2f}; use core::f64::consts::FRAC_PI_2; From 57848a73097269a3beaab1c20613953d37c68f99 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 15 Jul 2018 16:00:09 -0500 Subject: [PATCH 0562/4206] inline more functions; add more methods to F{32,64}Ext --- library/compiler-builtins/libm/src/lib.rs | 56 ++++++------------- .../compiler-builtins/libm/src/math/acosf.rs | 1 + .../compiler-builtins/libm/src/math/asin.rs | 2 + .../compiler-builtins/libm/src/math/asinf.rs | 1 + .../compiler-builtins/libm/src/math/cos.rs | 1 + .../compiler-builtins/libm/src/math/expm1.rs | 2 +- .../compiler-builtins/libm/src/math/expo2.rs | 3 +- .../compiler-builtins/libm/src/math/fenv.rs | 18 +++--- .../compiler-builtins/libm/src/math/k_cosf.rs | 2 +- .../libm/src/math/k_expo2f.rs | 2 +- .../compiler-builtins/libm/src/math/k_sinf.rs | 2 +- .../compiler-builtins/libm/src/math/k_tan.rs | 3 +- .../compiler-builtins/libm/src/math/k_tanf.rs | 2 +- .../libm/src/math/rem_pio2.rs | 2 + .../libm/src/math/rem_pio2_large.rs | 2 +- .../libm/src/math/rem_pio2f.rs | 2 +- .../compiler-builtins/libm/src/math/sin.rs | 1 + .../compiler-builtins/libm/src/math/sinh.rs | 1 + .../compiler-builtins/libm/src/math/tan.rs | 1 + .../compiler-builtins/libm/src/math/tanh.rs | 1 + 20 files changed, 49 insertions(+), 56 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 644091bb74dbf..bd4bff98db7e0 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -14,18 +14,19 @@ mod math; -#[cfg(todo)] use core::{f32, f64}; pub use math::*; /// Approximate equality with 1 ULP of tolerance #[doc(hidden)] +#[inline] pub fn _eqf(a: u32, b: u32) -> bool { (a as i32).wrapping_sub(b as i32).abs() <= 1 } #[doc(hidden)] +#[inline] pub fn _eq(a: u64, b: u64) -> bool { (a as i64).wrapping_sub(b as i64).abs() <= 1 } @@ -33,7 +34,7 @@ pub fn _eq(a: u64, b: u64) -> bool { /// Math support for `f32` /// /// This trait is sealed and cannot be implemented outside of `libm`. -pub trait F32Ext: private::Sealed { +pub trait F32Ext: private::Sealed + Sized { fn floor(self) -> Self; fn ceil(self) -> Self; @@ -44,20 +45,17 @@ pub trait F32Ext: private::Sealed { fn fdim(self, rhs: Self) -> Self; - #[cfg(todo)] fn fract(self) -> Self; fn abs(self) -> Self; - #[cfg(todo)] - fn signum(self) -> Self; + // NOTE depends on unstable intrinsics::copysignf32 + // fn signum(self) -> Self; fn mul_add(self, a: Self, b: Self) -> Self; - #[cfg(todo)] fn div_euc(self, rhs: Self) -> Self; - #[cfg(todo)] fn mod_euc(self, rhs: Self) -> Self; // NOTE depends on unstable intrinsics::powif32 @@ -97,9 +95,11 @@ pub trait F32Ext: private::Sealed { fn atan2(self, other: Self) -> Self; - #[cfg(todo)] #[inline] - fn sin_cos(self) -> (Self, Self) { + fn sin_cos(self) -> (Self, Self) + where + Self: Copy, + { (self.sin(), self.cos()) } @@ -113,13 +113,10 @@ pub trait F32Ext: private::Sealed { fn tanh(self) -> Self; - #[cfg(todo)] fn asinh(self) -> Self; - #[cfg(todo)] fn acosh(self) -> Self; - #[cfg(todo)] fn atanh(self) -> Self; } @@ -149,7 +146,6 @@ impl F32Ext for f32 { fdimf(self, rhs) } - #[cfg(todo)] #[inline] fn fract(self) -> Self { self - self.trunc() @@ -165,7 +161,6 @@ impl F32Ext for f32 { fmaf(self, a, b) } - #[cfg(todo)] #[inline] fn div_euc(self, rhs: Self) -> Self { let q = (self / rhs).trunc(); @@ -175,7 +170,6 @@ impl F32Ext for f32 { q } - #[cfg(todo)] #[inline] fn mod_euc(self, rhs: f32) -> f32 { let r = self % rhs; @@ -296,7 +290,6 @@ impl F32Ext for f32 { tanhf(self) } - #[cfg(todo)] #[inline] fn asinh(self) -> Self { if self == f32::NEG_INFINITY { @@ -306,7 +299,6 @@ impl F32Ext for f32 { } } - #[cfg(todo)] #[inline] fn acosh(self) -> Self { match self { @@ -315,7 +307,6 @@ impl F32Ext for f32 { } } - #[cfg(todo)] #[inline] fn atanh(self) -> Self { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() @@ -325,7 +316,7 @@ impl F32Ext for f32 { /// Math support for `f64` /// /// This trait is sealed and cannot be implemented outside of `libm`. -pub trait F64Ext: private::Sealed { +pub trait F64Ext: private::Sealed + Sized { fn floor(self) -> Self; fn ceil(self) -> Self; @@ -336,20 +327,17 @@ pub trait F64Ext: private::Sealed { fn fdim(self, rhs: Self) -> Self; - #[cfg(todo)] fn fract(self) -> Self; fn abs(self) -> Self; - #[cfg(todo)] - fn signum(self) -> Self; + // NOTE depends on unstable intrinsics::copysignf64 + // fn signum(self) -> Self; fn mul_add(self, a: Self, b: Self) -> Self; - #[cfg(todo)] fn div_euc(self, rhs: Self) -> Self; - #[cfg(todo)] fn mod_euc(self, rhs: Self) -> Self; // NOTE depends on unstable intrinsics::powif64 @@ -382,7 +370,6 @@ pub trait F64Ext: private::Sealed { fn tan(self) -> Self; - #[cfg(todo)] fn asin(self) -> Self; fn acos(self) -> Self; @@ -393,9 +380,11 @@ pub trait F64Ext: private::Sealed { #[cfg(todo)] fn atan2(self, other: Self) -> Self; - #[cfg(todo)] #[inline] - fn sin_cos(self) -> (Self, Self) { + fn sin_cos(self) -> (Self, Self) + where + Self: Copy, + { (self.sin(), self.cos()) } @@ -410,13 +399,10 @@ pub trait F64Ext: private::Sealed { fn tanh(self) -> Self; - #[cfg(todo)] fn asinh(self) -> Self; - #[cfg(todo)] fn acosh(self) -> Self; - #[cfg(todo)] fn atanh(self) -> Self; } @@ -445,7 +431,7 @@ impl F64Ext for f64 { fn fdim(self, rhs: Self) -> Self { fdim(self, rhs) } - #[cfg(todo)] + #[inline] fn fract(self) -> Self { self - self.trunc() @@ -461,7 +447,6 @@ impl F64Ext for f64 { fma(self, a, b) } - #[cfg(todo)] #[inline] fn div_euc(self, rhs: Self) -> Self { let q = (self / rhs).trunc(); @@ -471,9 +456,8 @@ impl F64Ext for f64 { q } - #[cfg(todo)] #[inline] - fn mod_euc(self, rhs: f32) -> f32 { + fn mod_euc(self, rhs: f64) -> f64 { let r = self % rhs; if r < 0.0 { r + rhs.abs() @@ -548,7 +532,6 @@ impl F64Ext for f64 { tan(self) } - #[cfg(todo)] #[inline] fn asin(self) -> Self { asin(self) @@ -597,7 +580,6 @@ impl F64Ext for f64 { tanh(self) } - #[cfg(todo)] #[inline] fn asinh(self) -> Self { if self == f64::NEG_INFINITY { @@ -607,7 +589,6 @@ impl F64Ext for f64 { } } - #[cfg(todo)] #[inline] fn acosh(self) -> Self { match self { @@ -616,7 +597,6 @@ impl F64Ext for f64 { } } - #[cfg(todo)] #[inline] fn atanh(self) -> Self { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() diff --git a/library/compiler-builtins/libm/src/math/acosf.rs b/library/compiler-builtins/libm/src/math/acosf.rs index ff07fe9350169..469601caba4d7 100644 --- a/library/compiler-builtins/libm/src/math/acosf.rs +++ b/library/compiler-builtins/libm/src/math/acosf.rs @@ -22,6 +22,7 @@ const P_S1: f32 = -4.2743422091e-02; const P_S2: f32 = -8.6563630030e-03; const Q_S1: f32 = -7.0662963390e-01; +#[inline] fn r(z: f32) -> f32 { let p = z * (P_S0 + z * (P_S1 + z * P_S2)); let q = 1. + z * Q_S1; diff --git a/library/compiler-builtins/libm/src/math/asin.rs b/library/compiler-builtins/libm/src/math/asin.rs index 720169bdcf0ba..a0bb4918c5a4c 100644 --- a/library/compiler-builtins/libm/src/math/asin.rs +++ b/library/compiler-builtins/libm/src/math/asin.rs @@ -55,12 +55,14 @@ const Q_S2: f64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ const Q_S3: f64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ const Q_S4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ +#[inline] fn comp_r(z: f64) -> f64 { let p = z * (P_S0 + z * (P_S1 + z * (P_S2 + z * (P_S3 + z * (P_S4 + z * P_S5))))); let q = 1.0 + z * (Q_S1 + z * (Q_S2 + z * (Q_S3 + z * Q_S4))); return p / q; } +#[inline] pub fn asin(mut x: f64) -> f64 { let z: f64; let r: f64; diff --git a/library/compiler-builtins/libm/src/math/asinf.rs b/library/compiler-builtins/libm/src/math/asinf.rs index 86944bb005764..79c85d81d0068 100644 --- a/library/compiler-builtins/libm/src/math/asinf.rs +++ b/library/compiler-builtins/libm/src/math/asinf.rs @@ -24,6 +24,7 @@ const P_S1: f32 = -4.2743422091e-02; const P_S2: f32 = -8.6563630030e-03; const Q_S1: f32 = -7.0662963390e-01; +#[inline] fn r(z: f32) -> f32 { let p = z * (P_S0 + z * (P_S1 + z * P_S2)); let q = 1. + z * Q_S1; diff --git a/library/compiler-builtins/libm/src/math/cos.rs b/library/compiler-builtins/libm/src/math/cos.rs index e6e9b373674c0..df16b5c36a840 100644 --- a/library/compiler-builtins/libm/src/math/cos.rs +++ b/library/compiler-builtins/libm/src/math/cos.rs @@ -41,6 +41,7 @@ use super::{k_cos, k_sin, rem_pio2}; // Accuracy: // TRIG(x) returns trig(x) nearly rounded // +#[inline] pub fn cos(x: f64) -> f64 { let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; diff --git a/library/compiler-builtins/libm/src/math/expm1.rs b/library/compiler-builtins/libm/src/math/expm1.rs index a00396524e8de..9da064ee77362 100644 --- a/library/compiler-builtins/libm/src/math/expm1.rs +++ b/library/compiler-builtins/libm/src/math/expm1.rs @@ -23,7 +23,7 @@ const Q3: f64 = -7.93650757867487942473e-05; /* BF14CE19 9EAADBB7 */ const Q4: f64 = 4.00821782732936239552e-06; /* 3ED0CFCA 86E65239 */ const Q5: f64 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ -#[allow(warnings)] +#[inline] pub fn expm1(mut x: f64) -> f64 { let hi: f64; let lo: f64; diff --git a/library/compiler-builtins/libm/src/math/expo2.rs b/library/compiler-builtins/libm/src/math/expo2.rs index 8a121b0a287a0..39f9815c40471 100644 --- a/library/compiler-builtins/libm/src/math/expo2.rs +++ b/library/compiler-builtins/libm/src/math/expo2.rs @@ -1,7 +1,8 @@ use super::{combine_words, exp}; /* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */ -pub(crate) fn expo2(x: f64) -> f64 { +#[inline] +pub fn expo2(x: f64) -> f64 { /* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */ const K: i32 = 2043; let kln2 = f64::from_bits(0x40962066151add8b); diff --git a/library/compiler-builtins/libm/src/math/fenv.rs b/library/compiler-builtins/libm/src/math/fenv.rs index 652e6032452b3..63bb203682068 100644 --- a/library/compiler-builtins/libm/src/math/fenv.rs +++ b/library/compiler-builtins/libm/src/math/fenv.rs @@ -1,33 +1,33 @@ // src: musl/src/fenv/fenv.c /* Dummy functions for archs lacking fenv implementation */ -pub(crate) const FE_UNDERFLOW: i32 = 0; -pub(crate) const FE_INEXACT: i32 = 0; +pub const FE_UNDERFLOW: i32 = 0; +pub const FE_INEXACT: i32 = 0; -pub(crate) const FE_TONEAREST: i32 = 0; -pub(crate) const FE_TOWARDZERO: i32 = 0; +pub const FE_TONEAREST: i32 = 0; +pub const FE_TOWARDZERO: i32 = 0; #[inline] -pub(crate) fn feclearexcept(_mask: i32) -> i32 { +pub fn feclearexcept(_mask: i32) -> i32 { 0 } #[inline] -pub(crate) fn feraiseexcept(_mask: i32) -> i32 { +pub fn feraiseexcept(_mask: i32) -> i32 { 0 } #[inline] -pub(crate) fn fetestexcept(_mask: i32) -> i32 { +pub fn fetestexcept(_mask: i32) -> i32 { 0 } #[inline] -pub(crate) fn fegetround() -> i32 { +pub fn fegetround() -> i32 { FE_TONEAREST } #[inline] -pub(crate) fn fesetround(_r: i32) -> i32 { +pub fn fesetround(_r: i32) -> i32 { 0 } diff --git a/library/compiler-builtins/libm/src/math/k_cosf.rs b/library/compiler-builtins/libm/src/math/k_cosf.rs index 75579ef9bf495..4aa10c0f08945 100644 --- a/library/compiler-builtins/libm/src/math/k_cosf.rs +++ b/library/compiler-builtins/libm/src/math/k_cosf.rs @@ -21,7 +21,7 @@ const C2: f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ const C3: f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ #[inline] -pub(crate) fn k_cosf(x: f64) -> f32 { +pub fn k_cosf(x: f64) -> f32 { let z = x * x; let w = z * z; let r = C2 + z * C3; diff --git a/library/compiler-builtins/libm/src/math/k_expo2f.rs b/library/compiler-builtins/libm/src/math/k_expo2f.rs index e2eaa4e6bb024..ec2a2c5e2b8ad 100644 --- a/library/compiler-builtins/libm/src/math/k_expo2f.rs +++ b/library/compiler-builtins/libm/src/math/k_expo2f.rs @@ -5,7 +5,7 @@ const K: i32 = 235; /* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ #[inline] -pub(crate) fn k_expo2f(x: f32) -> f32 { +pub fn k_expo2f(x: f32) -> f32 { let k_ln2 = f32::from_bits(0x4322e3bc); /* note that k is odd and scale*scale overflows */ let scale = f32::from_bits(((0x7f + K / 2) as u32) << 23); diff --git a/library/compiler-builtins/libm/src/math/k_sinf.rs b/library/compiler-builtins/libm/src/math/k_sinf.rs index bb519c9c09e91..1c5f5f98a48f6 100644 --- a/library/compiler-builtins/libm/src/math/k_sinf.rs +++ b/library/compiler-builtins/libm/src/math/k_sinf.rs @@ -21,7 +21,7 @@ const S3: f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ const S4: f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ #[inline] -pub(crate) fn k_sinf(x: f64) -> f32 { +pub fn k_sinf(x: f64) -> f32 { let z = x * x; let w = z * z; let r = S3 + z * S4; diff --git a/library/compiler-builtins/libm/src/math/k_tan.rs b/library/compiler-builtins/libm/src/math/k_tan.rs index b0dd317a2e727..e9ba21499d015 100644 --- a/library/compiler-builtins/libm/src/math/k_tan.rs +++ b/library/compiler-builtins/libm/src/math/k_tan.rs @@ -58,7 +58,8 @@ static T: [f64; 13] = [ const PIO4: f64 = 7.85398163397448278999e-01; /* 3FE921FB, 54442D18 */ const PIO4_LO: f64 = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ -pub(crate) fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { +#[inline] +pub fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { let hx = (f64::to_bits(x) >> 32) as u32; let big = (hx & 0x7fffffff) >= 0x3FE59428; /* |x| >= 0.6744 */ if big { diff --git a/library/compiler-builtins/libm/src/math/k_tanf.rs b/library/compiler-builtins/libm/src/math/k_tanf.rs index 6d3da1dcc8063..b9ccf2570f35b 100644 --- a/library/compiler-builtins/libm/src/math/k_tanf.rs +++ b/library/compiler-builtins/libm/src/math/k_tanf.rs @@ -20,7 +20,7 @@ const T: [f64; 6] = [ ]; #[inline] -pub(crate) fn k_tanf(x: f64, odd: bool) -> f32 { +pub fn k_tanf(x: f64, odd: bool) -> f32 { let z = x * x; /* * Split up the polynomial into small independent terms to give diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 47bab6e65f195..6e655e7d41929 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -42,12 +42,14 @@ const PIO2_3T: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ // use rem_pio2_large() for large x // // caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ +#[inline] pub fn rem_pio2(x: f64) -> (i32, f64, f64) { let x1p24 = f64::from_bits(0x4170000000000000); let sign = (f64::to_bits(x) >> 63) as i32; let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; + #[inline] fn medium(x: f64, ix: u32) -> (i32, f64, f64) { /* rint(x/(pi/2)), Assume round-to-nearest. */ let f_n = x as f64 * INV_PIO2 + TO_INT - TO_INT; 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 462eb0345157e..745b700a5eb2f 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -222,7 +222,7 @@ const PIO2: [f64; 8] = [ /// more accurately, = 0 mod 8 ). Thus the number of operations are /// independent of the exponent of the input. #[inline] -pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { +pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs index e2368d93db64f..5e7a7d43904d4 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2f.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2f.rs @@ -32,7 +32,7 @@ const PIO2_1T: f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ /// use double precision for everything except passing x /// use __rem_pio2_large() for large x #[inline] -pub(crate) fn rem_pio2f(x: f32) -> (i32, f64) { +pub fn rem_pio2f(x: f32) -> (i32, f64) { let x64 = x as f64; let mut tx: [f64; 1] = [0.]; diff --git a/library/compiler-builtins/libm/src/math/sin.rs b/library/compiler-builtins/libm/src/math/sin.rs index 13eb30248ab71..e749094e6681d 100644 --- a/library/compiler-builtins/libm/src/math/sin.rs +++ b/library/compiler-builtins/libm/src/math/sin.rs @@ -40,6 +40,7 @@ use super::{k_cos, k_sin, rem_pio2}; // // Accuracy: // TRIG(x) returns trig(x) nearly rounded +#[inline] pub fn sin(x: f64) -> f64 { let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 diff --git a/library/compiler-builtins/libm/src/math/sinh.rs b/library/compiler-builtins/libm/src/math/sinh.rs index 0579871719a8d..684e8e30984a1 100644 --- a/library/compiler-builtins/libm/src/math/sinh.rs +++ b/library/compiler-builtins/libm/src/math/sinh.rs @@ -4,6 +4,7 @@ use super::{expm1, expo2}; // = (exp(x)-1 + (exp(x)-1)/exp(x))/2 // = x + x^3/6 + o(x^5) // +#[inline] pub fn sinh(x: f64) -> f64 { // union {double f; uint64_t i;} u = {.f = x}; // uint32_t w; diff --git a/library/compiler-builtins/libm/src/math/tan.rs b/library/compiler-builtins/libm/src/math/tan.rs index 92bbb6221229d..5a5f178a51ccd 100644 --- a/library/compiler-builtins/libm/src/math/tan.rs +++ b/library/compiler-builtins/libm/src/math/tan.rs @@ -39,6 +39,7 @@ use super::{k_tan, rem_pio2}; // // Accuracy: // TRIG(x) returns trig(x) nearly rounded +#[inline] pub fn tan(x: f64) -> f64 { let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 diff --git a/library/compiler-builtins/libm/src/math/tanh.rs b/library/compiler-builtins/libm/src/math/tanh.rs index 657d7e0e276dc..1c3dd0be438ef 100644 --- a/library/compiler-builtins/libm/src/math/tanh.rs +++ b/library/compiler-builtins/libm/src/math/tanh.rs @@ -4,6 +4,7 @@ use super::expm1; * = (exp(2*x) - 1)/(exp(2*x) - 1 + 2) * = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2) */ +#[inline] pub fn tanh(mut x: f64) -> f64 { let mut uf: f64 = x; let mut ui: u64 = f64::to_bits(uf); From 06aba076817ff1b01287e136e0aea8941baa93bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A1ssio=20Kirch?= Date: Sun, 15 Jul 2018 19:49:12 -0300 Subject: [PATCH 0563/4206] implement cosh --- library/compiler-builtins/libm/src/lib.rs | 2 -- .../compiler-builtins/libm/src/math/cosh.rs | 34 +++++++++++++++++++ .../libm/src/math/k_expo2.rs | 14 ++++++++ .../compiler-builtins/libm/src/math/mod.rs | 4 +++ 4 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/cosh.rs create mode 100644 library/compiler-builtins/libm/src/math/k_expo2.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 45213a25f7ab5..3a1785357bf6a 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -407,7 +407,6 @@ pub trait F64Ext: private::Sealed { fn sinh(self) -> Self; - #[cfg(todo)] fn cosh(self) -> Self; #[cfg(todo)] @@ -589,7 +588,6 @@ impl F64Ext for f64 { sinh(self) } - #[cfg(todo)] #[inline] fn cosh(self) -> Self { cosh(self) diff --git a/library/compiler-builtins/libm/src/math/cosh.rs b/library/compiler-builtins/libm/src/math/cosh.rs new file mode 100644 index 0000000000000..54c0a61dc058b --- /dev/null +++ b/library/compiler-builtins/libm/src/math/cosh.rs @@ -0,0 +1,34 @@ +use super::exp; +use super::expm1; +use super::k_expo2; + +#[inline] +pub fn cosh(mut x: f64) -> f64 { + /* |x| */ + let mut ix = x.to_bits(); + ix &= 0x7fffffffffffffff; + x = f64::from_bits(ix); + let w = ix >> 32; + let w = w as u32; + + /* |x| < log(2) */ + if w < 0x3fe62e42 { + if w < 0x3ff00000 - (26 << 20) { + let x1p120 = f64::from_bits(0x4770000000000000); + force_eval!(x + x1p120); + return 1.; + } + let t = expm1(x); // exponential minus 1 + return 1. + t * t / (2. * (1. + t)); + } + + /* |x| < log(DBL_MAX) */ + if w < 0x40862e42 { + let t = exp(x); + /* note: if x>log(0x1p26) then the 1/t is not needed */ + return 0.5 * (t + 1. / t); + } + + /* |x| > log(DBL_MAX) or nan */ + k_expo2(x) +} diff --git a/library/compiler-builtins/libm/src/math/k_expo2.rs b/library/compiler-builtins/libm/src/math/k_expo2.rs new file mode 100644 index 0000000000000..7a4045dfc7b64 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_expo2.rs @@ -0,0 +1,14 @@ +use super::exp; + +/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ +const K: i64 = 2043; + +/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ +#[inline] +pub(crate) fn k_expo2(x: f64) -> f64 { + let k_ln2 = f64::from_bits(0x40962066151add8b); + /* note that k is odd and scale*scale overflows */ + let scale = f64::from_bits(((0x3ff + K / 2) as u64) << 20); + /* exp(x - k ln2) * 2**(k-1) */ + exp(x - k_ln2) * scale * scale +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index eda6b5b729312..3b3822711d652 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -19,6 +19,7 @@ mod ceil; mod ceilf; mod cos; mod cosf; +mod cosh; mod coshf; mod exp; mod exp2; @@ -75,6 +76,7 @@ pub use self::ceil::ceil; pub use self::ceilf::ceilf; pub use self::cos::cos; pub use self::cosf::cosf; +pub use self::cosh::cosh; pub use self::coshf::coshf; pub use self::exp::exp; pub use self::exp2::exp2; @@ -122,6 +124,7 @@ pub use self::truncf::truncf; mod expo2; mod k_cos; mod k_cosf; +mod k_expo2; mod k_expo2f; mod k_sin; mod k_sinf; @@ -135,6 +138,7 @@ mod rem_pio2f; use self::expo2::expo2; use self::k_cos::k_cos; use self::k_cosf::k_cosf; +use self::k_expo2::k_expo2; use self::k_expo2f::k_expo2f; use self::k_sin::k_sin; use self::k_sinf::k_sinf; From bbf1c5432a76f59ab1771bf92a4e46a5afe99693 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 15 Jul 2018 18:13:09 -0500 Subject: [PATCH 0564/4206] enable tests for cosh --- library/compiler-builtins/libm/test-generator/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 7caada4ef3e94..897f16d6c91db 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -703,7 +703,7 @@ f64_f64! { cbrt, ceil, cos, - // cosh, + cosh, exp, exp2, expm1, From 1e617876949964277328a2dde5914128f0fb9d33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A1ssio=20Kirch?= Date: Sun, 15 Jul 2018 21:35:08 -0300 Subject: [PATCH 0565/4206] unused cast removed --- library/compiler-builtins/libm/src/math/cosh.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/cosh.rs b/library/compiler-builtins/libm/src/math/cosh.rs index 54c0a61dc058b..f3f7fbfbeb16f 100644 --- a/library/compiler-builtins/libm/src/math/cosh.rs +++ b/library/compiler-builtins/libm/src/math/cosh.rs @@ -9,7 +9,6 @@ pub fn cosh(mut x: f64) -> f64 { ix &= 0x7fffffffffffffff; x = f64::from_bits(ix); let w = ix >> 32; - let w = w as u32; /* |x| < log(2) */ if w < 0x3fe62e42 { From e8e11976299cb5e58a0b2bbdbd0fd9537f23afff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A1ssio=20Kirch?= Date: Sun, 15 Jul 2018 21:36:22 -0300 Subject: [PATCH 0566/4206] words insertion on k_expo2 --- library/compiler-builtins/libm/src/math/k_expo2.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/k_expo2.rs b/library/compiler-builtins/libm/src/math/k_expo2.rs index 7a4045dfc7b64..e295c7a534629 100644 --- a/library/compiler-builtins/libm/src/math/k_expo2.rs +++ b/library/compiler-builtins/libm/src/math/k_expo2.rs @@ -1,14 +1,14 @@ use super::exp; /* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ -const K: i64 = 2043; +const K: i32 = 2043; /* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ #[inline] pub(crate) fn k_expo2(x: f64) -> f64 { let k_ln2 = f64::from_bits(0x40962066151add8b); /* note that k is odd and scale*scale overflows */ - let scale = f64::from_bits(((0x3ff + K / 2) as u64) << 20); + let scale = f64::from_bits(((((0x3ff + K / 2) as u32) << 20) as u64) << 32); /* exp(x - k ln2) * 2**(k-1) */ exp(x - k_ln2) * scale * scale } From b1b06f583a9b4b7627311b71aeac77da8f7cd95f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Mon, 16 Jul 2018 06:17:38 +0200 Subject: [PATCH 0567/4206] openbsd: doesn't use `static` as it could result duplicated symbols --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 271b010bc4ae9..a7091d541f4c9 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -13,7 +13,7 @@ fn main() { // OpenBSD provides compiler_rt by default, use it instead of rebuilding it from source if target.contains("openbsd") { println!("cargo:rustc-link-search=native=/usr/lib"); - println!("cargo:rustc-link-lib=static=compiler_rt"); + println!("cargo:rustc-link-lib=compiler_rt"); return; } From 99830bac40414e37df5663cda2b46a81a086a1d0 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 16 Jul 2018 13:03:40 -0500 Subject: [PATCH 0568/4206] test edge cases --- library/compiler-builtins/libm/ci/script.sh | 5 - .../libm/test-generator/Cargo.toml | 1 + .../libm/test-generator/src/main.rs | 92 ++++++++++++++----- 3 files changed, 70 insertions(+), 28 deletions(-) diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh index f2a294b488f5d..cf37ac1ca64ba 100644 --- a/library/compiler-builtins/libm/ci/script.sh +++ b/library/compiler-builtins/libm/ci/script.sh @@ -15,11 +15,6 @@ main() { # generate tests cargo run --package test-generator --target x86_64-unknown-linux-musl - if cargo fmt --version >/dev/null 2>&1; then - # nicer syntax error messages (if any) - cargo fmt - fi - # run tests cross test --target $TARGET --release diff --git a/library/compiler-builtins/libm/test-generator/Cargo.toml b/library/compiler-builtins/libm/test-generator/Cargo.toml index f45d173b45164..b810d9daf6305 100644 --- a/library/compiler-builtins/libm/test-generator/Cargo.toml +++ b/library/compiler-builtins/libm/test-generator/Cargo.toml @@ -6,3 +6,4 @@ publish = false [dependencies] rand = "0.5.3" +itertools = "0.7.8" diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 7c48031c174fe..e22e2018640d1 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -4,13 +4,15 @@ // NOTE usually the only thing you need to do to test a new math function is to add it to one of the // macro invocations found in the bottom of this file. +#[macro_use] +extern crate itertools; extern crate rand; use std::error::Error; use std::fmt::Write as _0; use std::fs::{self, File}; use std::io::Write as _1; -use std::{i16, u16, u32, u64, u8}; +use std::{f32, f64, i16, u16, u32, u64, u8}; use rand::{Rng, SeedableRng, XorShiftRng}; @@ -34,6 +36,30 @@ fn f64(rng: &mut XorShiftRng) -> f64 { f64::from_bits(sign + exponent + mantissa) } +const EDGE_CASES32: &[f32] = &[ + -0., + 0., + f32::EPSILON, + f32::INFINITY, + f32::MAX, + f32::MIN, + f32::MIN_POSITIVE, + f32::NAN, + f32::NEG_INFINITY, +]; + +const EDGE_CASES64: &[f64] = &[ + -0., + 0., + f64::EPSILON, + f64::INFINITY, + f64::MAX, + f64::MIN, + f64::MIN_POSITIVE, + f64::NAN, + f64::NEG_INFINITY, +]; + // fn(f32) -> f32 macro_rules! f32_f32 { ($($intr:ident,)*) => { @@ -45,8 +71,9 @@ macro_rules! f32_f32 { $( let mut cases = String::new(); - for _ in 0..NTESTS { - let inp = f32(rng); + + // random inputs + for inp in EDGE_CASES32.iter().cloned().chain((0..NTESTS).map(|_| f32(rng))) { let out = unsafe { $intr(inp) }; let inp = inp.to_bits(); @@ -112,11 +139,17 @@ macro_rules! f32f32_f32 { $(fn $intr(_: f32, _: f32) -> f32;)* } + let mut rng2 = rng.clone(); + let mut rng3 = rng.clone(); $( let mut cases = String::new(); - for _ in 0..NTESTS { - let i1 = f32(rng); - let i2 = f32(rng); + for (i1, i2) in iproduct!( + EDGE_CASES32.iter().cloned(), + EDGE_CASES32.iter().cloned() + ).chain(EDGE_CASES32.iter().map(|i1| (*i1, f32(rng)))) + .chain(EDGE_CASES32.iter().map(|i2| (f32(&mut rng2), *i2))) + .chain((0..NTESTS).map(|_| (f32(&mut rng3), f32(&mut rng3)))) + { let out = unsafe { $intr(i1, i2) }; let i1 = i1.to_bits(); @@ -186,12 +219,16 @@ macro_rules! f32f32f32_f32 { $(fn $intr(_: f32, _: f32, _: f32) -> f32;)* } + let mut rng2 = rng.clone(); $( let mut cases = String::new(); - for _ in 0..NTESTS { - let i1 = f32(rng); - let i2 = f32(rng); - let i3 = f32(rng); + for (i1, i2, i3) in iproduct!( + EDGE_CASES32.iter().cloned(), + EDGE_CASES32.iter().cloned(), + EDGE_CASES32.iter().cloned() + ).chain(EDGE_CASES32.iter().map(|i1| (*i1, f32(rng), f32(rng)))) + .chain((0..NTESTS).map(|_| (f32(&mut rng2), f32(&mut rng2), f32(&mut rng2)))) + { let out = unsafe { $intr(i1, i2, i3) }; let i1 = i1.to_bits(); @@ -266,10 +303,10 @@ macro_rules! f32i32_f32 { $(fn $intr(_: f32, _: i32) -> f32;)* } + let mut rng2 = rng.clone(); $( let mut cases = String::new(); - for _ in 0..NTESTS { - let i1 = f32(rng); + for i1 in EDGE_CASES32.iter().cloned().chain((0..NTESTS).map(|_| f32(&mut rng2))) { let i2 = rng.gen_range(i16::MIN, i16::MAX); let out = unsafe { $intr(i1, i2 as i32) }; @@ -342,8 +379,7 @@ macro_rules! f64_f64 { $( let mut cases = String::new(); - for _ in 0..NTESTS { - let inp = f64(rng); + for inp in EDGE_CASES64.iter().cloned().chain((0..NTESTS).map(|_| f64(rng))) { let out = unsafe { $intr(inp) }; let inp = inp.to_bits(); @@ -412,11 +448,17 @@ macro_rules! f64f64_f64 { $(fn $intr(_: f64, _: f64) -> f64;)* } + let mut rng2 = rng.clone(); + let mut rng3 = rng.clone(); $( let mut cases = String::new(); - for _ in 0..NTESTS { - let i1 = f64(rng); - let i2 = f64(rng); + for (i1, i2) in iproduct!( + EDGE_CASES64.iter().cloned(), + EDGE_CASES64.iter().cloned() + ).chain(EDGE_CASES64.iter().map(|i1| (*i1, f64(rng)))) + .chain(EDGE_CASES64.iter().map(|i2| (f64(&mut rng2), *i2))) + .chain((0..NTESTS).map(|_| (f64(&mut rng3), f64(&mut rng3)))) + { let out = unsafe { $intr(i1, i2) }; let i1 = i1.to_bits(); @@ -485,12 +527,16 @@ macro_rules! f64f64f64_f64 { $(fn $intr(_: f64, _: f64, _: f64) -> f64;)* } + let mut rng2 = rng.clone(); $( let mut cases = String::new(); - for _ in 0..NTESTS { - let i1 = f64(rng); - let i2 = f64(rng); - let i3 = f64(rng); + for (i1, i2, i3) in iproduct!( + EDGE_CASES64.iter().cloned(), + EDGE_CASES64.iter().cloned(), + EDGE_CASES64.iter().cloned() + ).chain(EDGE_CASES64.iter().map(|i1| (*i1, f64(rng), f64(rng)))) + .chain((0..NTESTS).map(|_| (f64(&mut rng2), f64(&mut rng2), f64(&mut rng2)))) + { let out = unsafe { $intr(i1, i2, i3) }; let i1 = i1.to_bits(); @@ -565,10 +611,10 @@ macro_rules! f64i32_f64 { $(fn $intr(_: f64, _: i32) -> f64;)* } + let mut rng2 = rng.clone(); $( let mut cases = String::new(); - for _ in 0..NTESTS { - let i1 = f64(rng); + for i1 in EDGE_CASES64.iter().cloned().chain((0..NTESTS).map(|_| f64(&mut rng2))) { let i2 = rng.gen_range(i16::MIN, i16::MAX); let out = unsafe { $intr(i1, i2 as i32) }; From e6f9e770064d7c86d80c9bb311726085dae91aaa Mon Sep 17 00:00:00 2001 From: Richard Dodd Date: Mon, 16 Jul 2018 17:56:14 +0100 Subject: [PATCH 0569/4206] Implement atan --- library/compiler-builtins/libm/src/lib.rs | 2 - .../compiler-builtins/libm/src/math/atan.rs | 170 ++++++++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 2 + .../libm/test-generator/src/main.rs | 2 +- 4 files changed, 173 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/atan.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 38ebeac413b37..0e1ed61d2776d 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -374,7 +374,6 @@ pub trait F64Ext: private::Sealed + Sized { fn acos(self) -> Self; - #[cfg(todo)] fn atan(self) -> Self; #[cfg(todo)] @@ -541,7 +540,6 @@ impl F64Ext for f64 { acos(self) } - #[cfg(todo)] #[inline] fn atan(self) -> Self { atan(self) diff --git a/library/compiler-builtins/libm/src/math/atan.rs b/library/compiler-builtins/libm/src/math/atan.rs new file mode 100644 index 0000000000000..d057af6d66333 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/atan.rs @@ -0,0 +1,170 @@ +/* atan(x) + * Method + * 1. Reduce x to positive by atan(x) = -atan(-x). + * 2. According to the integer k=4t+0.25 chopped, t=x, the argument + * is further reduced to one of the following intervals and the + * arctangent of t is evaluated by the corresponding formula: + * + * [0,7/16] atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...) + * [7/16,11/16] atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) ) + * [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) ) + * [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) ) + * [39/16,INF] atan(x) = atan(INF) + atan( -1/t ) + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +use super::fabs; +use core::f64; + +const ATANHI: [f64; 4] = [ + 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */ + 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */ + 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */ + 1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */ +]; + +const ATANLO: [f64; 4] = [ + 2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */ + 3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */ + 1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */ + 6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */ +]; + +const AT: [f64; 11] = [ + 3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */ + -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */ + 1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */ + -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */ + 9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */ + -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */ + 6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */ + -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */ + 4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */ + -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */ + 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */ +]; + +#[inline] +pub fn atan(x: f64) -> f64 { + let mut x = x; + let mut ix = (x.to_bits() >> 32) as u32; + let sign = ix >> 31; + ix &= 0x7fff_ffff; + if ix >= 0x4410_0000 { + if x.is_nan() { + return x; + } + + let z = ATANHI[3] + f64::from_bits(0x0380_0000); // 0x1p-120f + return if sign != 0 { -z } else { z }; + } + + let id = if ix < 0x3fdc_0000 { + /* |x| < 0.4375 */ + if ix < 0x3e40_0000 { + /* |x| < 2^-27 */ + if ix < 0x0010_0000 { + /* raise underflow for subnormal x */ + force_eval!(x as f32); + } + + return x; + } + + -1 + } else { + x = fabs(x); + if ix < 0x3ff30000 { + /* |x| < 1.1875 */ + if ix < 0x3fe60000 { + /* 7/16 <= |x| < 11/16 */ + x = (2. * x - 1.) / (2. + x); + 0 + } else { + /* 11/16 <= |x| < 19/16 */ + x = (x - 1.) / (x + 1.); + 1 + } + } else { + if ix < 0x40038000 { + /* |x| < 2.4375 */ + x = (x - 1.5) / (1. + 1.5 * x); + 2 + } else { + /* 2.4375 <= |x| < 2^66 */ + x = -1. / x; + 3 + } + } + }; + + let z = x * x; + let w = z * z; + /* break sum from i=0 to 10 AT[i]z**(i+1) into odd and even poly */ + let s1 = z * (AT[0] + w * (AT[2] + w * (AT[4] + w * (AT[6] + w * (AT[8] + w * AT[10]))))); + let s2 = w * (AT[1] + w * (AT[3] + w * (AT[5] + w * (AT[7] + w * AT[9])))); + + if id < 0 { + return x - x * (s1 + s2); + } + + let z = ATANHI[id as usize] - (x * (s1 + s2) - ATANLO[id as usize] - x); + + if sign != 0 { + -z + } else { + z + } +} + +#[cfg(test)] +mod tests { + use super::atan; + use core::f64; + + #[test] + fn sanity_check() { + for (input, answer) in [ + (3.0_f64.sqrt() / 3.0, f64::consts::FRAC_PI_6), + (1.0, f64::consts::FRAC_PI_4), + (3.0_f64.sqrt(), f64::consts::FRAC_PI_3), + (-3.0_f64.sqrt() / 3.0, -f64::consts::FRAC_PI_6), + (-1.0, -f64::consts::FRAC_PI_4), + (-3.0_f64.sqrt(), -f64::consts::FRAC_PI_3), + ].iter() + { + assert!( + (atan(*input) - answer) / answer < 1e-5, + "\natan({:.4}/16) = {:.4}, actual: {}", + input * 16.0, + answer, + atan(*input) + ); + } + } + + #[test] + fn zero() { + assert_eq!(atan(0.0), 0.0); + } + + #[test] + fn infinity() { + assert_eq!(atan(f64::INFINITY), f64::consts::FRAC_PI_2); + } + + #[test] + fn minus_infinity() { + assert_eq!(atan(f64::NEG_INFINITY), -f64::consts::FRAC_PI_2); + } + + #[test] + fn nan() { + assert!(atan(f64::NAN).is_nan()); + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 352e1d37b6c59..64ab3faa703c5 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -11,6 +11,7 @@ mod acos; mod acosf; mod asin; mod asinf; +mod atan; mod atan2f; mod atanf; mod cbrt; @@ -70,6 +71,7 @@ pub use self::acos::acos; pub use self::acosf::acosf; pub use self::asin::asin; pub use self::asinf::asinf; +pub use self::atan::atan; pub use self::atan2f::atan2f; pub use self::atanf::atanf; pub use self::cbrt::cbrt; diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index e22e2018640d1..a3efd076962ec 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -745,7 +745,7 @@ f32i32_f32! { f64_f64! { acos, asin, - // atan, + atan, cbrt, ceil, cos, From 33086672fa30ef627cbb69896b79ad6c936c2f2f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 16 Jul 2018 16:37:35 -0700 Subject: [PATCH 0570/4206] Don't build multc3 on AArch64 MSVC Apparently it doesn't compile due to an odd compiler error! This intrinsic has to do with complex arithmetic anyway and we shouldn't need it. --- library/compiler-builtins/build.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index a7091d541f4c9..cdcbfe24cd73c 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -415,11 +415,14 @@ mod c { "floatsitf.c", "floatunditf.c", "floatunsitf.c", - "multc3.c", "trunctfdf2.c", "trunctfsf2.c", ], ); + + if target_os != "windows" { + sources.extend(&["multc3.c"]); + } } // Remove the assembly implementations that won't compile for the target From 579a0ad4fd1dab5ac84aecaf711a79b51f3ed2c6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 16 Jul 2018 18:46:59 -0500 Subject: [PATCH 0571/4206] fix rebase error --- library/compiler-builtins/libm/src/math/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 3f6fa3211493a..f3f533ddd218d 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -10,6 +10,7 @@ macro_rules! force_eval { mod acos; mod acosf; mod asin; +mod asinf; mod atan2; mod atan2f; mod atanf; From addfefd63f24c4caeed01326b4f91e029d450b97 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 16 Jul 2018 18:54:19 -0500 Subject: [PATCH 0572/4206] fix another rebase error --- library/compiler-builtins/libm/src/math/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index f3f533ddd218d..49f5059dcb0c6 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -11,6 +11,7 @@ mod acos; mod acosf; mod asin; mod asinf; +mod atan; mod atan2; mod atan2f; mod atanf; From 29c1188f1f7626d0552b781fc97a62d11f2e6a03 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 16 Jul 2018 20:03:30 -0500 Subject: [PATCH 0573/4206] cargo fmt --- library/compiler-builtins/libm/src/math/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 49f5059dcb0c6..754efa9f6dac3 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -72,8 +72,8 @@ pub use self::acos::acos; pub use self::acosf::acosf; pub use self::asin::asin; pub use self::asinf::asinf; -pub use self::atan2::atan2; pub use self::atan::atan; +pub use self::atan2::atan2; pub use self::atan2f::atan2f; pub use self::atanf::atanf; pub use self::cbrt::cbrt; From fe84c2050e917466b67866b76b7155f383524cf4 Mon Sep 17 00:00:00 2001 From: Joseph Ryan Date: Mon, 16 Jul 2018 21:18:38 -0500 Subject: [PATCH 0574/4206] Add unit tests for atan2 --- library/compiler-builtins/libm/src/math/atan2.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs index 324b1e937f94f..1816bca5c50b6 100644 --- a/library/compiler-builtins/libm/src/math/atan2.rs +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -70,3 +70,14 @@ pub fn atan2(y: f64, x: f64) -> f64 { _ => (z - PI_LO) - PI, /* atan(-,-) */ } } + +#[test] +fn sanity_check() { + assert_eq!(atan2(0.0, 1.0), 0.0); + assert_eq!(atan2(0.0, -1.0), PI); + assert_eq!(atan2(-0.0, -1.0), -PI); + assert_eq!(atan2(3.0, 2.0), atan(3.0/2.0)); + assert_eq!(atan2(2.0, -1.0), atan(2.0/-1.0) + PI); + assert_eq!(atan2(-2.0, -1.0), atan(-2.0/-1.0) - PI); +} + From 203a8aea86c1e20af051d63d64f375364671f4ed Mon Sep 17 00:00:00 2001 From: Joseph Ryan Date: Mon, 16 Jul 2018 21:22:35 -0500 Subject: [PATCH 0575/4206] rustfmt --- library/compiler-builtins/libm/src/math/atan2.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs index 1816bca5c50b6..a719b6d632ce0 100644 --- a/library/compiler-builtins/libm/src/math/atan2.rs +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -76,8 +76,7 @@ fn sanity_check() { assert_eq!(atan2(0.0, 1.0), 0.0); assert_eq!(atan2(0.0, -1.0), PI); assert_eq!(atan2(-0.0, -1.0), -PI); - assert_eq!(atan2(3.0, 2.0), atan(3.0/2.0)); - assert_eq!(atan2(2.0, -1.0), atan(2.0/-1.0) + PI); - assert_eq!(atan2(-2.0, -1.0), atan(-2.0/-1.0) - PI); + assert_eq!(atan2(3.0, 2.0), atan(3.0 / 2.0)); + assert_eq!(atan2(2.0, -1.0), atan(2.0 / -1.0) + PI); + assert_eq!(atan2(-2.0, -1.0), atan(-2.0 / -1.0) - PI); } - From f12ba75f67ede8582bfdf20e75eafbf423112e50 Mon Sep 17 00:00:00 2001 From: Rahul Butani Date: Tue, 17 Jul 2018 14:56:11 -0500 Subject: [PATCH 0576/4206] pow! --- .../compiler-builtins/libm/src/math/pow.rs | 395 ++++++++++++++++++ 1 file changed, 395 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/pow.rs diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs new file mode 100644 index 0000000000000..3d0769b344035 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -0,0 +1,395 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_pow.c */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* pow(x,y) return x**y + * + * n + * Method: Let x = 2 * (1+f) + * 1. Compute and return log2(x) in two pieces: + * log2(x) = w1 + w2, + * where w1 has 53-24 = 29 bit trailing zeros. + * 2. Perform y*log2(x) = n+y' by simulating muti-precision + * arithmetic, where |y'|<=0.5. + * 3. Return x**y = 2**n*exp(y'*log2) + * + * Special cases: + * 1. (anything) ** 0 is 1 + * 2. 1 ** (anything) is 1 + * 3. (anything except 1) ** NAN is NAN + * 4. NAN ** (anything except 0) is NAN + * 5. +-(|x| > 1) ** +INF is +INF + * 6. +-(|x| > 1) ** -INF is +0 + * 7. +-(|x| < 1) ** +INF is +0 + * 8. +-(|x| < 1) ** -INF is +INF + * 9. -1 ** +-INF is 1 + * 10. +0 ** (+anything except 0, NAN) is +0 + * 11. -0 ** (+anything except 0, NAN, odd integer) is +0 + * 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero + * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero + * 14. -0 ** (+odd integer) is -0 + * 15. -0 ** (-odd integer) is -INF, raise divbyzero + * 16. +INF ** (+anything except 0,NAN) is +INF + * 17. +INF ** (-anything except 0,NAN) is +0 + * 18. -INF ** (+odd integer) is -INF + * 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) + * 20. (anything) ** 1 is (anything) + * 21. (anything) ** -1 is 1/(anything) + * 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) + * 23. (-anything except 0 and inf) ** (non-integer) is NAN + * + * Accuracy: + * pow(x,y) returns x**y nearly rounded. In particular + * pow(integer,integer) + * always returns the correct integer provided it is + * representable. + * + * Constants : + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +// #include "libm.h" + +/* Concerns: + * - Some constants are shared; DRY? + * - FLT_EVAL_METHOD: the others sidestep this (epsilon or just always true in the case of hypot (#71)) + */ + +use super::{fabs, scalbn, sqrt, with_set_low_word, with_set_high_word, get_high_word}; + +const BP: [f64; 2] = [1.0, 1.5]; +const DP_H: [f64; 2] = [0.0, 5.84962487220764160156e-01]; /* 0x3fe2b803_40000000 */ +const DP_L: [f64; 2] = [0.0, 1.35003920212974897128e-08]; /* 0x3E4CFDEB, 0x43CFD006 */ +const TWO53: f64 = 9007199254740992.0; /* 0x43400000_00000000 */ +const HUGE: f64 = 1.0e300; +const TINY: f64 = 1.0e-300; + +// poly coefs for (3/2)*(log(x)-2s-2/3*s**3: +const L1: f64 = 5.99999999999994648725e-01; /* 0x3fe33333_33333303 */ +const L2: f64 = 4.28571428578550184252e-01; /* 0x3fdb6db6_db6fabff */ +const L3: f64 = 3.33333329818377432918e-01; /* 0x3fd55555_518f264d */ +const L4: f64 = 2.72728123808534006489e-01; /* 0x3fd17460_a91d4101 */ +const L5: f64 = 2.30660745775561754067e-01; /* 0x3fcd864a_93c9db65 */ +const L6: f64 = 2.06975017800338417784e-01; /* 0x3fca7e28_4a454eef */ +const P1: f64 = 1.66666666666666019037e-01; /* 0x3fc55555_5555553e */ +const P2: f64 = -2.77777777770155933842e-03; /* 0xbf66c16c_16bebd93 */ +const P3: f64 = 6.61375632143793436117e-05; /* 0x3f11566a_af25de2c */ +const P4: f64 = -1.65339022054652515390e-06; /* 0xbebbbd41_c5d26bf1 */ +const P5: f64 = 4.13813679705723846039e-08; /* 0x3e663769_72bea4d0 */ +const LG2: f64 = 6.93147180559945286227e-01; /* 0x3fe62e42_fefa39ef */ +const LG2_H: f64 = 6.93147182464599609375e-01; /* 0x3fe62e43_00000000 */ +const LG2_L: f64 = -1.90465429995776804525e-09; /* 0xbe205c61_0ca86c39 */ +const OVT: f64 = 8.0085662595372944372e-017; /* -(1024-log2(ovfl+.5ulp)) */ +const CP: f64 = 9.61796693925975554329e-01; /* 0x3feec709_dc3a03fd =2/(3ln2) */ +const CP_H: f64 = 9.61796700954437255859e-01; /* 0x3feec709_e0000000 =(float)cp */ +const CP_L: f64 = -7.02846165095275826516e-09; /* 0xbe3e2fe0_145b01f5 =tail of cp_h*/ +const IVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547_652b82fe =1/ln2 */ +const IVLN2_H: f64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/ln2*/ +const IVLN2_L: f64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ + +#[inline] +pub fn pow(x: f64, y: f64) -> f64 { + let t1: f64; + let t2: f64; + + let (hx, lx): (i32, u32) = ((x.to_bits() >> 32) as i32, x.to_bits() as u32); + let (hy, ly): (i32, u32) = ((y.to_bits() >> 32) as i32, y.to_bits() as u32); + + let mut ix: i32 = (hx & 0x7fffffff) as i32; + let iy: i32 = (hy & 0x7fffffff) as i32; + + /* x**0 = 1, even if x is NaN */ + if ((iy as u32) | ly) == 0 { + return 1.0; + } + + /* 1**y = 1, even if y is NaN */ + if hx == 0x3ff00000 && lx == 0 { + return 1.0; + } + + /* NaN if either arg is NaN */ + if ix > 0x7ff00000 || (ix == 0x7ff00000 && lx != 0) || + iy > 0x7ff00000 || (iy == 0x7ff00000 && ly != 0) { + return x + y; + } + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + let mut yisint: i32 = 0; + let mut k: i32; + let mut j: i32; + if hx < 0 { + if iy >= 0x43400000 { + yisint = 2; /* even integer y */ + } else if iy >= 0x3ff00000 { + k = (iy >> 20) - 0x3ff; /* exponent */ + + if k > 20 { + j = (ly >> (52 - k)) as i32; + + if (j << (52 - k)) == (ly as i32) { + yisint = 2 - (j & 1); + } + } else if ly == 0 { + j = iy >> (20 - k); + + if (j << (20 - k)) == iy { + yisint = 2 - (j & 1); + } + } + } + } + + if ly == 0 { + /* special value of y */ + if iy == 0x7ff00000 { + /* y is +-inf */ + return if ((ix - 0x3ff00000) | (lx as i32)) == 0 { + /* (-1)**+-inf is 1 */ + 1.0 + } else if ix >= 0x3ff00000 { + /* (|x|>1)**+-inf = inf,0 */ + if hy >= 0 { y } else { 0.0 } + } else { + /* (|x|<1)**+-inf = 0,inf */ + if hy >= 0 { 0.0 } else { -y } + }; + } + + if iy == 0x3ff00000 { + /* y is +-1 */ + return if hy >= 0 { x } else { 1.0 / x }; + } + + if hy == 0x40000000 { + /* y is 2 */ + return x * x; + } + + if hy == 0x3fe00000 { + /* y is 0.5 */ + if hx >= 0 { + /* x >= +0 */ + return sqrt(x); + } + } + } + + let mut ax: f64 = fabs(x); + if lx == 0 { + /* special value of x */ + if ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000 { + /* x is +-0,+-inf,+-1 */ + let mut z: f64 = ax; + + if hy < 0 { + /* z = (1/|x|) */ + z = 1.0 / z; + } + + if hx < 0 { + if ((ix-0x3ff00000)|yisint) == 0 { + z = (z - z) / (z - z); /* (-1)**non-int is NaN */ + } else if yisint == 1 { + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + } + + return z; + } + } + + let mut s: f64 = 1.0; /* sign of result */ + if hx < 0 { + if yisint == 0 { + /* (x<0)**(non-int) is NaN */ + return (x - x) / (x - x); + } + + if yisint == 1 { + /* (x<0)**(odd int) */ + s = -1.0; + } + } + + /* |y| is HUGE */ + if iy > 0x41e00000 { + /* if |y| > 2**31 */ + if iy > 0x43f00000 { + /* if |y| > 2**64, must o/uflow */ + if ix <= 0x3fefffff { + return if hy < 0 { HUGE * HUGE } else { TINY * TINY }; + } + + if ix >= 0x3ff00000 { + return if hy > 0 { HUGE * HUGE } else { TINY * TINY }; + } + } + + /* over/underflow if x is not close to one */ + if ix < 0x3fefffff { + return if hy < 0 { s * HUGE * HUGE } else { s * TINY * TINY }; + } + if ix > 0x3ff00000 { + return if hy > 0 { s * HUGE * HUGE } else { s * TINY * TINY }; + } + + /* now |1-x| is TINY <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + let t: f64 = ax - 1.0; /* t has 20 trailing zeros */ + let w: f64 = (t * t) * (0.5 - t * (0.3333333333333333333333 - t * 0.25)); + let u: f64 = IVLN2_H * t; /* ivln2_h has 21 sig. bits */ + let v: f64 = t * IVLN2_L - w * IVLN2; + t1 = with_set_low_word(u + v, 0); + t2 = v - (t1 - u); + } else { + // double ss,s2,s_h,s_l,t_h,t_l; + let mut n: i32 = 0; + + if ix < 0x00100000 { + /* take care subnormal number */ + ax *= TWO53; + n -= 53; + ix = get_high_word(ax) as i32; + } + + n += (ix >> 20) - 0x3ff; + j = ix & 0x000fffff; + + /* determine interval */ + let k: i32; + ix = j | 0x3ff00000; /* normalize ix */ + if j <= 0x3988E { + /* |x|> 1) | 0x20000000) + 0x00080000 + ((k as u32) << 18)); + let t_l: f64 = ax - (t_h - BP[k as usize]); + let s_l: f64 = v * ((u - s_h * t_h) - s_h * t_l); + + /* compute log(ax) */ + let s2: f64 = ss * ss; + let mut r: f64 = s2 * s2 * (L1 + s2 * (L2 + s2 *(L3 + s2 *(L4 + s2 *(L5 + s2 * L6))))); + r += s_l * (s_h + ss); + let s2: f64 = s_h * s_h; + let t_h: f64 = with_set_low_word(3.0 + s2 + r, 0); + let t_l: f64 = r - ((t_h - 3.0) - s2); + + /* u+v = ss*(1+...) */ + let u: f64 = s_h * t_h; + let v: f64 = s_l * t_h + t_l * ss; + + /* 2/(3log2)*(ss+...) */ + let p_h: f64 = with_set_low_word(u + v, 0); + let p_l = v - (p_h-u); + let z_h: f64 = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ + let z_l: f64 = CP_L * p_h + p_l * CP + DP_L[k as usize]; + + /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + let t: f64 = n as f64; + t1 = with_set_low_word(((z_h + z_l) + DP_H[k as usize]) + t, 0); + t2 = z_l - (((t1 - t) - DP_H[k as usize]) - z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + let y1: f64 = with_set_low_word(y, 0); + let p_l: f64 = (y - y1) * t1 + y * t2; + let mut p_h: f64 = y1 * t1; + let z: f64 = p_l + p_h; + let mut j: i32 = (z.to_bits() >> 32) as i32; + let i: i32 = z.to_bits() as i32; + // let (j, i): (i32, i32) = ((z.to_bits() >> 32) as i32, z.to_bits() as i32); + + if j >= 0x40900000 { + /* z >= 1024 */ + if (j - 0x40900000) | i != 0 { + /* if z > 1024 */ + return s * HUGE * HUGE; /* overflow */ + } + + if p_l + OVT > z - p_h { + return s * HUGE * HUGE; /* overflow */ + } + } else if (j & 0x7fffffff) >= 0x4090cc00 { + /* z <= -1075 */ + // FIXME: instead of abs(j) use unsigned j + + if (((j as u32) - 0xc090cc00) | (i as u32)) != 0 { + /* z < -1075 */ + return s * TINY * TINY; /* underflow */ + } + + if p_l <= z - p_h { + return s * TINY * TINY; /* underflow */ + } + } + + /* compute 2**(p_h+p_l) */ + let i: i32 = j & (0x7fffffff as i32); + k = (i >> 20) - 0x3ff; + let mut n: i32 = 0; + + if i > 0x3fe00000 { + /* if |z| > 0.5, set n = [z+0.5] */ + n = j + (0x00100000 >> (k + 1)); + k = ((n&0x7fffffff) >> 20) - 0x3ff; /* new k for n */ + let t: f64 = with_set_high_word(0.0, (n & !(0x000fffff >> k)) as u32); + n = ((n & 0x000fffff) | 0x00100000) >> (20 - k); + if j < 0 { + n = -n; + } + p_h -= t; + } + + let t: f64 = with_set_low_word(p_l + p_h, 0); + let u: f64 = t * LG2_H; + let v: f64 = (p_l - (t - p_h)) * LG2 + t * LG2_L; + let mut z: f64 = u + v; + let w: f64 = v - (z - u); + let t: f64 = z * z; + let t1: f64 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); + let r: f64 = (z * t1) / (t1 - 2.0) - (w + z*w); + z = 1.0 - (r - z); + j = get_high_word(z) as i32; + j += n << 20; + + if (j >> 20) <= 0 { + /* subnormal output */ + z = scalbn(z,n); + } else { + z = with_set_high_word(z, j as u32); + } + + return s*z; +} From 440e835967dd4bac67a7b20ea8b063dfa347891e Mon Sep 17 00:00:00 2001 From: Rahul Butani Date: Tue, 17 Jul 2018 15:03:39 -0500 Subject: [PATCH 0577/4206] Enable tests and expose --- library/compiler-builtins/libm/src/lib.rs | 2 -- library/compiler-builtins/libm/src/math/mod.rs | 3 ++- library/compiler-builtins/libm/test-generator/src/main.rs | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 1837b9c1f9ed1..06991effe1d78 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -343,7 +343,6 @@ pub trait F64Ext: private::Sealed + Sized { // NOTE depends on unstable intrinsics::powif64 // fn powi(self, n: i32) -> Self; - #[cfg(todo)] fn powf(self, n: Self) -> Self; fn sqrt(self) -> Self; @@ -463,7 +462,6 @@ impl F64Ext for f64 { } } - #[cfg(todo)] #[inline] fn powf(self, n: Self) -> Self { pow(self, n) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 754efa9f6dac3..6dd362d009456 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -50,6 +50,7 @@ mod log2; mod log2f; mod logf; mod powf; +mod pow; mod round; mod roundf; mod scalbn; @@ -111,6 +112,7 @@ pub use self::log2::log2; pub use self::log2f::log2f; pub use self::logf::logf; pub use self::powf::powf; +pub use self::pow::pow; pub use self::round::round; pub use self::roundf::roundf; pub use self::scalbn::scalbn; @@ -167,7 +169,6 @@ fn get_low_word(x: f64) -> u32 { x.to_bits() as u32 } -#[allow(dead_code)] #[inline] fn with_set_high_word(f: f64, hi: u32) -> f64 { let mut tmp = f.to_bits(); diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 09a9cb8f58870..4c4e420a28528 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -774,7 +774,7 @@ f64f64_f64! { fdim, fmod, hypot, - // pow, + pow, } // With signature `fn(f64, f64, f64) -> f64` From 1c555103ae48c2c452739d9b9b77e4267738965f Mon Sep 17 00:00:00 2001 From: Rahul Butani Date: Tue, 17 Jul 2018 15:06:50 -0500 Subject: [PATCH 0578/4206] rustfmt'ed + some clean up --- .../compiler-builtins/libm/src/math/mod.rs | 4 +- .../compiler-builtins/libm/src/math/pow.rs | 239 ++++++++++-------- 2 files changed, 129 insertions(+), 114 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 6dd362d009456..752a5991aeab2 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -49,8 +49,8 @@ mod log1pf; mod log2; mod log2f; mod logf; -mod powf; mod pow; +mod powf; mod round; mod roundf; mod scalbn; @@ -111,8 +111,8 @@ pub use self::log1pf::log1pf; pub use self::log2::log2; pub use self::log2f::log2f; pub use self::logf::logf; -pub use self::powf::powf; pub use self::pow::pow; +pub use self::powf::powf; pub use self::round::round; pub use self::roundf::roundf; pub use self::scalbn::scalbn; diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 3d0769b344035..69c086b0f242a 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -8,93 +8,87 @@ * is preserved. * ==================================================== */ -/* pow(x,y) return x**y - * - * n - * Method: Let x = 2 * (1+f) - * 1. Compute and return log2(x) in two pieces: - * log2(x) = w1 + w2, - * where w1 has 53-24 = 29 bit trailing zeros. - * 2. Perform y*log2(x) = n+y' by simulating muti-precision - * arithmetic, where |y'|<=0.5. - * 3. Return x**y = 2**n*exp(y'*log2) - * - * Special cases: - * 1. (anything) ** 0 is 1 - * 2. 1 ** (anything) is 1 - * 3. (anything except 1) ** NAN is NAN - * 4. NAN ** (anything except 0) is NAN - * 5. +-(|x| > 1) ** +INF is +INF - * 6. +-(|x| > 1) ** -INF is +0 - * 7. +-(|x| < 1) ** +INF is +0 - * 8. +-(|x| < 1) ** -INF is +INF - * 9. -1 ** +-INF is 1 - * 10. +0 ** (+anything except 0, NAN) is +0 - * 11. -0 ** (+anything except 0, NAN, odd integer) is +0 - * 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero - * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero - * 14. -0 ** (+odd integer) is -0 - * 15. -0 ** (-odd integer) is -INF, raise divbyzero - * 16. +INF ** (+anything except 0,NAN) is +INF - * 17. +INF ** (-anything except 0,NAN) is +0 - * 18. -INF ** (+odd integer) is -INF - * 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) - * 20. (anything) ** 1 is (anything) - * 21. (anything) ** -1 is 1/(anything) - * 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) - * 23. (-anything except 0 and inf) ** (non-integer) is NAN - * - * Accuracy: - * pow(x,y) returns x**y nearly rounded. In particular - * pow(integer,integer) - * always returns the correct integer provided it is - * representable. - * - * Constants : - * The hexadecimal values are the intended ones for the following - * constants. The decimal values may be used, provided that the - * compiler will convert from decimal to binary accurately enough - * to produce the hexadecimal values shown. - */ - -// #include "libm.h" -/* Concerns: - * - Some constants are shared; DRY? - * - FLT_EVAL_METHOD: the others sidestep this (epsilon or just always true in the case of hypot (#71)) - */ - -use super::{fabs, scalbn, sqrt, with_set_low_word, with_set_high_word, get_high_word}; - -const BP: [f64; 2] = [1.0, 1.5]; +/// pow(x,y) return x**y +/// +/// n +/// Method: Let x = 2 * (1+f) +/// 1. Compute and return log2(x) in two pieces: +/// log2(x) = w1 + w2, +/// where w1 has 53-24 = 29 bit trailing zeros. +/// 2. Perform y*log2(x) = n+y' by simulating muti-precision +/// arithmetic, where |y'|<=0.5. +/// 3. Return x**y = 2**n*exp(y'*log2) +/// +/// Special cases: +/// 1. (anything) ** 0 is 1 +/// 2. 1 ** (anything) is 1 +/// 3. (anything except 1) ** NAN is NAN +/// 4. NAN ** (anything except 0) is NAN +/// 5. +-(|x| > 1) ** +INF is +INF +/// 6. +-(|x| > 1) ** -INF is +0 +/// 7. +-(|x| < 1) ** +INF is +0 +/// 8. +-(|x| < 1) ** -INF is +INF +/// 9. -1 ** +-INF is 1 +/// 10. +0 ** (+anything except 0, NAN) is +0 +/// 11. -0 ** (+anything except 0, NAN, odd integer) is +0 +/// 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero +/// 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero +/// 14. -0 ** (+odd integer) is -0 +/// 15. -0 ** (-odd integer) is -INF, raise divbyzero +/// 16. +INF ** (+anything except 0,NAN) is +INF +/// 17. +INF ** (-anything except 0,NAN) is +0 +/// 18. -INF ** (+odd integer) is -INF +/// 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) +/// 20. (anything) ** 1 is (anything) +/// 21. (anything) ** -1 is 1/(anything) +/// 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) +/// 23. (-anything except 0 and inf) ** (non-integer) is NAN +/// +/// Accuracy: +/// pow(x,y) returns x**y nearly rounded. In particular +/// pow(integer,integer) +/// always returns the correct integer provided it is +/// representable. +/// +/// Constants : +/// The hexadecimal values are the intended ones for the following +/// constants. The decimal values may be used, provided that the +/// compiler will convert from decimal to binary accurately enough +/// to produce the hexadecimal values shown. +/// + +use super::{fabs, get_high_word, scalbn, sqrt, with_set_high_word, with_set_low_word}; + +const BP: [f64; 2] = [1.0, 1.5]; const DP_H: [f64; 2] = [0.0, 5.84962487220764160156e-01]; /* 0x3fe2b803_40000000 */ const DP_L: [f64; 2] = [0.0, 1.35003920212974897128e-08]; /* 0x3E4CFDEB, 0x43CFD006 */ -const TWO53: f64 = 9007199254740992.0; /* 0x43400000_00000000 */ -const HUGE: f64 = 1.0e300; -const TINY: f64 = 1.0e-300; +const TWO53: f64 = 9007199254740992.0; /* 0x43400000_00000000 */ +const HUGE: f64 = 1.0e300; +const TINY: f64 = 1.0e-300; // poly coefs for (3/2)*(log(x)-2s-2/3*s**3: -const L1: f64 = 5.99999999999994648725e-01; /* 0x3fe33333_33333303 */ -const L2: f64 = 4.28571428578550184252e-01; /* 0x3fdb6db6_db6fabff */ -const L3: f64 = 3.33333329818377432918e-01; /* 0x3fd55555_518f264d */ -const L4: f64 = 2.72728123808534006489e-01; /* 0x3fd17460_a91d4101 */ -const L5: f64 = 2.30660745775561754067e-01; /* 0x3fcd864a_93c9db65 */ -const L6: f64 = 2.06975017800338417784e-01; /* 0x3fca7e28_4a454eef */ -const P1: f64 = 1.66666666666666019037e-01; /* 0x3fc55555_5555553e */ +const L1: f64 = 5.99999999999994648725e-01; /* 0x3fe33333_33333303 */ +const L2: f64 = 4.28571428578550184252e-01; /* 0x3fdb6db6_db6fabff */ +const L3: f64 = 3.33333329818377432918e-01; /* 0x3fd55555_518f264d */ +const L4: f64 = 2.72728123808534006489e-01; /* 0x3fd17460_a91d4101 */ +const L5: f64 = 2.30660745775561754067e-01; /* 0x3fcd864a_93c9db65 */ +const L6: f64 = 2.06975017800338417784e-01; /* 0x3fca7e28_4a454eef */ +const P1: f64 = 1.66666666666666019037e-01; /* 0x3fc55555_5555553e */ const P2: f64 = -2.77777777770155933842e-03; /* 0xbf66c16c_16bebd93 */ -const P3: f64 = 6.61375632143793436117e-05; /* 0x3f11566a_af25de2c */ +const P3: f64 = 6.61375632143793436117e-05; /* 0x3f11566a_af25de2c */ const P4: f64 = -1.65339022054652515390e-06; /* 0xbebbbd41_c5d26bf1 */ -const P5: f64 = 4.13813679705723846039e-08; /* 0x3e663769_72bea4d0 */ -const LG2: f64 = 6.93147180559945286227e-01; /* 0x3fe62e42_fefa39ef */ -const LG2_H: f64 = 6.93147182464599609375e-01; /* 0x3fe62e43_00000000 */ -const LG2_L: f64 = -1.90465429995776804525e-09; /* 0xbe205c61_0ca86c39 */ -const OVT: f64 = 8.0085662595372944372e-017; /* -(1024-log2(ovfl+.5ulp)) */ -const CP: f64 = 9.61796693925975554329e-01; /* 0x3feec709_dc3a03fd =2/(3ln2) */ -const CP_H: f64 = 9.61796700954437255859e-01; /* 0x3feec709_e0000000 =(float)cp */ -const CP_L: f64 = -7.02846165095275826516e-09; /* 0xbe3e2fe0_145b01f5 =tail of cp_h*/ -const IVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547_652b82fe =1/ln2 */ -const IVLN2_H: f64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/ln2*/ -const IVLN2_L: f64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ +const P5: f64 = 4.13813679705723846039e-08; /* 0x3e663769_72bea4d0 */ +const LG2: f64 = 6.93147180559945286227e-01; /* 0x3fe62e42_fefa39ef */ +const LG2_H: f64 = 6.93147182464599609375e-01; /* 0x3fe62e43_00000000 */ +const LG2_L: f64 = -1.90465429995776804525e-09; /* 0xbe205c61_0ca86c39 */ +const OVT: f64 = 8.0085662595372944372e-017; /* -(1024-log2(ovfl+.5ulp)) */ +const CP: f64 = 9.61796693925975554329e-01; /* 0x3feec709_dc3a03fd =2/(3ln2) */ +const CP_H: f64 = 9.61796700954437255859e-01; /* 0x3feec709_e0000000 =(float)cp */ +const CP_L: f64 = -7.02846165095275826516e-09; /* 0xbe3e2fe0_145b01f5 =tail of cp_h*/ +const IVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547_652b82fe =1/ln2 */ +const IVLN2_H: f64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/ln2*/ +const IVLN2_L: f64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ #[inline] pub fn pow(x: f64, y: f64) -> f64 { @@ -103,7 +97,7 @@ pub fn pow(x: f64, y: f64) -> f64 { let (hx, lx): (i32, u32) = ((x.to_bits() >> 32) as i32, x.to_bits() as u32); let (hy, ly): (i32, u32) = ((y.to_bits() >> 32) as i32, y.to_bits() as u32); - + let mut ix: i32 = (hx & 0x7fffffff) as i32; let iy: i32 = (hy & 0x7fffffff) as i32; @@ -118,9 +112,12 @@ pub fn pow(x: f64, y: f64) -> f64 { } /* NaN if either arg is NaN */ - if ix > 0x7ff00000 || (ix == 0x7ff00000 && lx != 0) || - iy > 0x7ff00000 || (iy == 0x7ff00000 && ly != 0) { - return x + y; + if ix > 0x7ff00000 + || (ix == 0x7ff00000 && lx != 0) + || iy > 0x7ff00000 + || (iy == 0x7ff00000 && ly != 0) + { + return x + y; } /* determine if y is an odd int when x < 0 @@ -136,16 +133,16 @@ pub fn pow(x: f64, y: f64) -> f64 { yisint = 2; /* even integer y */ } else if iy >= 0x3ff00000 { k = (iy >> 20) - 0x3ff; /* exponent */ - + if k > 20 { j = (ly >> (52 - k)) as i32; - + if (j << (52 - k)) == (ly as i32) { yisint = 2 - (j & 1); } } else if ly == 0 { j = iy >> (20 - k); - + if (j << (20 - k)) == iy { yisint = 2 - (j & 1); } @@ -156,16 +153,25 @@ pub fn pow(x: f64, y: f64) -> f64 { if ly == 0 { /* special value of y */ if iy == 0x7ff00000 { - /* y is +-inf */ + /* y is +-inf */ + return if ((ix - 0x3ff00000) | (lx as i32)) == 0 { /* (-1)**+-inf is 1 */ 1.0 } else if ix >= 0x3ff00000 { /* (|x|>1)**+-inf = inf,0 */ - if hy >= 0 { y } else { 0.0 } + if hy >= 0 { + y + } else { + 0.0 + } } else { /* (|x|<1)**+-inf = 0,inf */ - if hy >= 0 { 0.0 } else { -y } + if hy >= 0 { + 0.0 + } else { + -y + } }; } @@ -194,14 +200,14 @@ pub fn pow(x: f64, y: f64) -> f64 { if ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000 { /* x is +-0,+-inf,+-1 */ let mut z: f64 = ax; - + if hy < 0 { /* z = (1/|x|) */ z = 1.0 / z; } if hx < 0 { - if ((ix-0x3ff00000)|yisint) == 0 { + if ((ix - 0x3ff00000) | yisint) == 0 { z = (z - z) / (z - z); /* (-1)**non-int is NaN */ } else if yisint == 1 { z = -z; /* (x<0)**odd = -(|x|**odd) */ @@ -241,17 +247,25 @@ pub fn pow(x: f64, y: f64) -> f64 { /* over/underflow if x is not close to one */ if ix < 0x3fefffff { - return if hy < 0 { s * HUGE * HUGE } else { s * TINY * TINY }; + return if hy < 0 { + s * HUGE * HUGE + } else { + s * TINY * TINY + }; } if ix > 0x3ff00000 { - return if hy > 0 { s * HUGE * HUGE } else { s * TINY * TINY }; + return if hy > 0 { + s * HUGE * HUGE + } else { + s * TINY * TINY + }; } /* now |1-x| is TINY <= 2**-20, suffice to compute log(x) by x-x^2/2+x^3/3-x^4/4 */ - let t: f64 = ax - 1.0; /* t has 20 trailing zeros */ + let t: f64 = ax - 1.0; /* t has 20 trailing zeros */ let w: f64 = (t * t) * (0.5 - t * (0.3333333333333333333333 - t * 0.25)); - let u: f64 = IVLN2_H * t; /* ivln2_h has 21 sig. bits */ + let u: f64 = IVLN2_H * t; /* ivln2_h has 21 sig. bits */ let v: f64 = t * IVLN2_L - w * IVLN2; t1 = with_set_low_word(u + v, 0); t2 = v - (t1 - u); @@ -262,8 +276,8 @@ pub fn pow(x: f64, y: f64) -> f64 { if ix < 0x00100000 { /* take care subnormal number */ ax *= TWO53; - n -= 53; - ix = get_high_word(ax) as i32; + n -= 53; + ix = get_high_word(ax) as i32; } n += (ix >> 20) - 0x3ff; @@ -271,12 +285,11 @@ pub fn pow(x: f64, y: f64) -> f64 { /* determine interval */ let k: i32; - ix = j | 0x3ff00000; /* normalize ix */ + ix = j | 0x3ff00000; /* normalize ix */ if j <= 0x3988E { /* |x| f64 { /* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */ let u: f64 = ax - BP[k as usize]; /* bp[0]=1.0, bp[1]=1.5 */ let v: f64 = 1.0 / (ax + BP[k as usize]); - let ss: f64 = u * v; + let ss: f64 = u * v; let s_h = with_set_low_word(ss, 0); /* t_h=ax+bp[k] High */ - let t_h: f64 = with_set_high_word(0.0, - ((ix as u32 >> 1) | 0x20000000) + 0x00080000 + ((k as u32) << 18)); + let t_h: f64 = with_set_high_word( + 0.0, + ((ix as u32 >> 1) | 0x20000000) + 0x00080000 + ((k as u32) << 18), + ); let t_l: f64 = ax - (t_h - BP[k as usize]); let s_l: f64 = v * ((u - s_h * t_h) - s_h * t_l); /* compute log(ax) */ let s2: f64 = ss * ss; - let mut r: f64 = s2 * s2 * (L1 + s2 * (L2 + s2 *(L3 + s2 *(L4 + s2 *(L5 + s2 * L6))))); + let mut r: f64 = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); r += s_l * (s_h + ss); let s2: f64 = s_h * s_h; let t_h: f64 = with_set_low_word(3.0 + s2 + r, 0); @@ -312,7 +327,7 @@ pub fn pow(x: f64, y: f64) -> f64 { /* 2/(3log2)*(ss+...) */ let p_h: f64 = with_set_low_word(u + v, 0); - let p_l = v - (p_h-u); + let p_l = v - (p_h - u); let z_h: f64 = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ let z_l: f64 = CP_L * p_h + p_l * CP + DP_L[k as usize]; @@ -323,10 +338,10 @@ pub fn pow(x: f64, y: f64) -> f64 { } /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ - let y1: f64 = with_set_low_word(y, 0); + let y1: f64 = with_set_low_word(y, 0); let p_l: f64 = (y - y1) * t1 + y * t2; let mut p_h: f64 = y1 * t1; - let z: f64 = p_l + p_h; + let z: f64 = p_l + p_h; let mut j: i32 = (z.to_bits() >> 32) as i32; let i: i32 = z.to_bits() as i32; // let (j, i): (i32, i32) = ((z.to_bits() >> 32) as i32, z.to_bits() as i32); @@ -363,7 +378,7 @@ pub fn pow(x: f64, y: f64) -> f64 { if i > 0x3fe00000 { /* if |z| > 0.5, set n = [z+0.5] */ n = j + (0x00100000 >> (k + 1)); - k = ((n&0x7fffffff) >> 20) - 0x3ff; /* new k for n */ + k = ((n & 0x7fffffff) >> 20) - 0x3ff; /* new k for n */ let t: f64 = with_set_high_word(0.0, (n & !(0x000fffff >> k)) as u32); n = ((n & 0x000fffff) | 0x00100000) >> (20 - k); if j < 0 { @@ -379,17 +394,17 @@ pub fn pow(x: f64, y: f64) -> f64 { let w: f64 = v - (z - u); let t: f64 = z * z; let t1: f64 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); - let r: f64 = (z * t1) / (t1 - 2.0) - (w + z*w); + let r: f64 = (z * t1) / (t1 - 2.0) - (w + z * w); z = 1.0 - (r - z); j = get_high_word(z) as i32; j += n << 20; if (j >> 20) <= 0 { /* subnormal output */ - z = scalbn(z,n); + z = scalbn(z, n); } else { z = with_set_high_word(z, j as u32); } - return s*z; + return s * z; } From 9f920e739a0765f31b77223186dfd16c48b45936 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 17 Jul 2018 19:46:12 -0500 Subject: [PATCH 0579/4206] cargo fmt --- .../compiler-builtins/libm/src/math/pow.rs | 97 +++++++++---------- 1 file changed, 48 insertions(+), 49 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 69c086b0f242a..329b3955d8837 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -9,55 +9,54 @@ * ==================================================== */ -/// pow(x,y) return x**y -/// -/// n -/// Method: Let x = 2 * (1+f) -/// 1. Compute and return log2(x) in two pieces: -/// log2(x) = w1 + w2, -/// where w1 has 53-24 = 29 bit trailing zeros. -/// 2. Perform y*log2(x) = n+y' by simulating muti-precision -/// arithmetic, where |y'|<=0.5. -/// 3. Return x**y = 2**n*exp(y'*log2) -/// -/// Special cases: -/// 1. (anything) ** 0 is 1 -/// 2. 1 ** (anything) is 1 -/// 3. (anything except 1) ** NAN is NAN -/// 4. NAN ** (anything except 0) is NAN -/// 5. +-(|x| > 1) ** +INF is +INF -/// 6. +-(|x| > 1) ** -INF is +0 -/// 7. +-(|x| < 1) ** +INF is +0 -/// 8. +-(|x| < 1) ** -INF is +INF -/// 9. -1 ** +-INF is 1 -/// 10. +0 ** (+anything except 0, NAN) is +0 -/// 11. -0 ** (+anything except 0, NAN, odd integer) is +0 -/// 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero -/// 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero -/// 14. -0 ** (+odd integer) is -0 -/// 15. -0 ** (-odd integer) is -INF, raise divbyzero -/// 16. +INF ** (+anything except 0,NAN) is +INF -/// 17. +INF ** (-anything except 0,NAN) is +0 -/// 18. -INF ** (+odd integer) is -INF -/// 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) -/// 20. (anything) ** 1 is (anything) -/// 21. (anything) ** -1 is 1/(anything) -/// 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) -/// 23. (-anything except 0 and inf) ** (non-integer) is NAN -/// -/// Accuracy: -/// pow(x,y) returns x**y nearly rounded. In particular -/// pow(integer,integer) -/// always returns the correct integer provided it is -/// representable. -/// -/// Constants : -/// The hexadecimal values are the intended ones for the following -/// constants. The decimal values may be used, provided that the -/// compiler will convert from decimal to binary accurately enough -/// to produce the hexadecimal values shown. -/// - +// pow(x,y) return x**y +// +// n +// Method: Let x = 2 * (1+f) +// 1. Compute and return log2(x) in two pieces: +// log2(x) = w1 + w2, +// where w1 has 53-24 = 29 bit trailing zeros. +// 2. Perform y*log2(x) = n+y' by simulating muti-precision +// arithmetic, where |y'|<=0.5. +// 3. Return x**y = 2**n*exp(y'*log2) +// +// Special cases: +// 1. (anything) ** 0 is 1 +// 2. 1 ** (anything) is 1 +// 3. (anything except 1) ** NAN is NAN +// 4. NAN ** (anything except 0) is NAN +// 5. +-(|x| > 1) ** +INF is +INF +// 6. +-(|x| > 1) ** -INF is +0 +// 7. +-(|x| < 1) ** +INF is +0 +// 8. +-(|x| < 1) ** -INF is +INF +// 9. -1 ** +-INF is 1 +// 10. +0 ** (+anything except 0, NAN) is +0 +// 11. -0 ** (+anything except 0, NAN, odd integer) is +0 +// 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero +// 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero +// 14. -0 ** (+odd integer) is -0 +// 15. -0 ** (-odd integer) is -INF, raise divbyzero +// 16. +INF ** (+anything except 0,NAN) is +INF +// 17. +INF ** (-anything except 0,NAN) is +0 +// 18. -INF ** (+odd integer) is -INF +// 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) +// 20. (anything) ** 1 is (anything) +// 21. (anything) ** -1 is 1/(anything) +// 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) +// 23. (-anything except 0 and inf) ** (non-integer) is NAN +// +// Accuracy: +// pow(x,y) returns x**y nearly rounded. In particular +// pow(integer,integer) +// always returns the correct integer provided it is +// representable. +// +// Constants : +// The hexadecimal values are the intended ones for the following +// constants. The decimal values may be used, provided that the +// compiler will convert from decimal to binary accurately enough +// to produce the hexadecimal values shown. +// use super::{fabs, get_high_word, scalbn, sqrt, with_set_high_word, with_set_low_word}; const BP: [f64; 2] = [1.0, 1.5]; From a8cce5bda19ea62439fd167370dcd15c8abecb73 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 17 Jul 2018 20:04:33 -0500 Subject: [PATCH 0580/4206] update changelog; add more copyright notices --- library/compiler-builtins/libm/CHANGELOG.md | 15 +++++++ .../compiler-builtins/libm/src/math/atan.rs | 11 ++++++ .../compiler-builtins/libm/src/math/atan2.rs | 39 +++++++++++++++++++ .../compiler-builtins/libm/src/math/atan2f.rs | 15 +++++++ 4 files changed, 80 insertions(+) diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index 107813b081364..d37468685a98d 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -7,14 +7,29 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added +- acosf +- asin +- asinf +- atan +- atan2 - atan2f +- atanf - cos +- cosf +- cosh - coshf +- exp2 +- expm1 +- expm1f +- expo2 - fmaf +- pow - sin +- sinf - sinh - sinhf - tan +- tanf - tanh - tanhf diff --git a/library/compiler-builtins/libm/src/math/atan.rs b/library/compiler-builtins/libm/src/math/atan.rs index d057af6d66333..47a2951c6f405 100644 --- a/library/compiler-builtins/libm/src/math/atan.rs +++ b/library/compiler-builtins/libm/src/math/atan.rs @@ -1,3 +1,14 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_atan.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. + * ==================================================== + */ /* atan(x) * Method * 1. Reduce x to positive by atan(x) = -atan(-x). diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs index a719b6d632ce0..a91ddd84d0d72 100644 --- a/library/compiler-builtins/libm/src/math/atan2.rs +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -1,3 +1,42 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* atan2(y,x) + * Method : + * 1. Reduce y to positive by atan2(y,x)=-atan2(-y,x). + * 2. Reduce x to positive by (if x and y are unexceptional): + * ARG (x+iy) = arctan(y/x) ... if x > 0, + * ARG (x+iy) = pi - arctan[y/(-x)] ... if x < 0, + * + * Special cases: + * + * ATAN2((anything), NaN ) is NaN; + * ATAN2(NAN , (anything) ) is NaN; + * ATAN2(+-0, +(anything but NaN)) is +-0 ; + * ATAN2(+-0, -(anything but NaN)) is +-pi ; + * ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2; + * ATAN2(+-(anything but INF and NaN), +INF) is +-0 ; + * ATAN2(+-(anything but INF and NaN), -INF) is +-pi; + * ATAN2(+-INF,+INF ) is +-pi/4 ; + * ATAN2(+-INF,-INF ) is +-3pi/4; + * ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2; + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + use super::atan; use super::fabs; diff --git a/library/compiler-builtins/libm/src/math/atan2f.rs b/library/compiler-builtins/libm/src/math/atan2f.rs index a232ffdd61dc9..211a992a06562 100644 --- a/library/compiler-builtins/libm/src/math/atan2f.rs +++ b/library/compiler-builtins/libm/src/math/atan2f.rs @@ -1,3 +1,18 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + use super::atanf; use super::fabsf; From 1dbcef117c2c16a4cafbb0160e3383db64bd1d91 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 12 Jul 2018 20:40:30 -0500 Subject: [PATCH 0581/4206] expose math symbol on wasm32-unknown-unknown --- library/compiler-builtins/.gitmodules | 3 ++ library/compiler-builtins/.travis.yml | 3 ++ library/compiler-builtins/libm | 1 + library/compiler-builtins/src/lib.rs | 3 ++ library/compiler-builtins/src/math.rs | 51 +++++++++++++++++++++++++++ 5 files changed, 61 insertions(+) create mode 160000 library/compiler-builtins/libm create mode 100644 library/compiler-builtins/src/math.rs diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index 3ff1154f3e795..7162b2c4d5b2b 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -1,3 +1,6 @@ [submodule "compiler-rt"] path = compiler-rt url = https://github.com/rust-lang/compiler-rt +[submodule "libm"] + path = libm + url = https://github.com/japaric/libm diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index efd0b1738e3e5..7b7ed7e6bca5a 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -25,6 +25,9 @@ matrix: - env: TARGET=thumbv7em-linux-eabi - env: TARGET=thumbv7em-linux-eabihf - env: TARGET=thumbv7m-linux-eabi + - env: TARGET=wasm32-unknown-unknown + install: rustup target add $TARGET + script: cargo build --target $TARGET - env: TARGET=x86_64-apple-darwin os: osx - env: TARGET=x86_64-unknown-linux-gnu diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm new file mode 160000 index 0000000000000..d65f60f24289b --- /dev/null +++ b/library/compiler-builtins/libm @@ -0,0 +1 @@ +Subproject commit d65f60f24289ba212f5d47792f7236857efb2339 diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 619b6ac7afbdb..3e665a88d49dc 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -48,6 +48,9 @@ pub mod int; pub mod float; pub mod mem; +// only for the wasm32-unknown-unknown target +#[cfg(all(target_arch = "wasm32", target_os = "unknown"))] +pub mod math; #[cfg(target_arch = "arm")] pub mod arm; diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs new file mode 100644 index 0000000000000..f9ee36f0e72ec --- /dev/null +++ b/library/compiler-builtins/src/math.rs @@ -0,0 +1,51 @@ +#[allow(dead_code)] +#[path = "../../libm/src/math/mod.rs"] +mod libm; + +macro_rules! no_mangle { + ($(fn $fun:ident($($iid:ident : $ity:ty),+) -> $oty:ty;)+) => { + $( + #[no_mangle] + pub fn $fun($($iid: $ity),+) -> $oty { + self::libm::$fun($($iid),+) + } + )+ + } +} + +no_mangle! { + fn acos(x: f64) -> f64; + fn asin(x: f64) -> f64; + fn atan(x: f64) -> f64; + fn atan2(x: f64, y: f64) -> f64; + fn cbrt(x: f64) -> f64; + fn cosh(x: f64) -> f64; + fn expm1(x: f64) -> f64; + fn hypot(x: f64, y: f64) -> f64; + fn log1p(x: f64) -> f64; + fn sinh(x: f64) -> f64; + fn tan(x: f64) -> f64; + fn tanh(x: f64) -> f64; + fn cos(x: f64) -> f64; + fn cosf(x: f32) -> f32; + fn exp(x: f64) -> f64; + fn expf(x: f32) -> f32; + fn log2(x: f64) -> f64; + fn log2f(x: f32) -> f32; + fn log10(x: f64) -> f64; + fn log10f(x: f32) -> f32; + fn log(x: f64) -> f64; + fn logf(x: f32) -> f32; + fn round(x: f64) -> f64; + fn roundf(x: f32) -> f32; + fn sin(x: f64) -> f64; + fn sinf(x: f32) -> f32; + fn pow(x: f64, y: f64) -> f64; + fn powf(x: f32, y: f32) -> f32; + fn exp2(x: f64) -> f64; + fn exp2f(x: f32) -> f32; + fn fmod(x: f64, y: f64) -> f64; + fn fmodf(x: f32, y: f32) -> f32; + fn fma(x: f64, y: f64, z: f64) -> f64; + fn fmaf(x: f32, y: f32, z: f32) -> f32; +} From f43deaa6a483cb8fadc87c61eaa765fe9f781cf7 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 18 Jul 2018 11:36:24 -0500 Subject: [PATCH 0582/4206] fix path --- library/compiler-builtins/src/math.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index f9ee36f0e72ec..76bb72679936b 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -1,5 +1,5 @@ #[allow(dead_code)] -#[path = "../../libm/src/math/mod.rs"] +#[path = "../libm/src/math/mod.rs"] mod libm; macro_rules! no_mangle { From ddd9a3c5ba32460e3b506f10a780076bfade39f7 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 18 Jul 2018 11:48:47 -0500 Subject: [PATCH 0583/4206] v0.1.2 --- library/compiler-builtins/libm/CHANGELOG.md | 5 ++++- library/compiler-builtins/libm/Cargo.toml | 2 +- library/compiler-builtins/libm/src/lib.rs | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index d37468685a98d..1cc396455f391 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -5,6 +5,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.1.2] - 2018-07-18 + ### Added - acosf @@ -72,5 +74,6 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Initial release -[Unreleased]: https://github.com/japaric/libm/compare/v0.1.1...HEAD +[Unreleased]: https://github.com/japaric/libm/compare/v0.1.2...HEAD +[v0.1.2]: https://github.com/japaric/libm/compare/v0.1.1...v0.1.2 [v0.1.1]: https://github.com/japaric/libm/compare/v0.1.0...v0.1.1 diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index a82fc99a7e7ab..11c59a2dbdb9a 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -7,7 +7,7 @@ keywords = ["libm", "math"] license = "MIT OR Apache-2.0" name = "libm" repository = "https://github.com/japaric/libm" -version = "0.1.1" +version = "0.1.2" [workspace] members = ["cb", "test-generator"] \ No newline at end of file diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 06991effe1d78..5121cbfbacf35 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -1,4 +1,4 @@ -//! Port of MUSL's libm to Rust +//! libm in pure Rust //! //! # Usage //! From bb88e27e3c6658273d634aeaf95bb172adfb748e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 18 Jul 2018 10:04:33 -0700 Subject: [PATCH 0584/4206] Use `intrinsics!` macro for math intrinsics Make sure they respect the `mangled-names` feature as well as have the `"C"` ABI. --- library/compiler-builtins/src/math.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 76bb72679936b..f1eaaa5fa414d 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -4,12 +4,13 @@ mod libm; macro_rules! no_mangle { ($(fn $fun:ident($($iid:ident : $ity:ty),+) -> $oty:ty;)+) => { - $( - #[no_mangle] - pub fn $fun($($iid: $ity),+) -> $oty { - self::libm::$fun($($iid),+) - } - )+ + intrinsics! { + $( + pub extern "C" fn $fun($($iid: $ity),+) -> $oty { + self::libm::$fun($($iid),+) + } + )+ + } } } From 7774eac9625362e9433209dc22b356058d5b63a0 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 21 Jul 2018 12:01:49 -0500 Subject: [PATCH 0585/4206] README: all the math functions we needed are now supported --- library/compiler-builtins/libm/README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 02de9765a50b2..24b816c351b8a 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -33,10 +33,7 @@ fn foo(x: f32) { } ``` -Not all the math functions are available at the moment. Check the [API docs] to learn what's -currently supported. - -[API docs]: https://docs.rs/libm +The API documentation can be found [here](https://docs.rs/libm). ## Contributing From 8b1e42bf2ae50dab91837e5d6d8da386b945c460 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 24 Jul 2018 13:26:50 -0500 Subject: [PATCH 0586/4206] expose fmod{,f} symbols on thumb these symbols are required for the built-in operation `f32 % f32` --- library/compiler-builtins/src/lib.rs | 4 +--- library/compiler-builtins/src/math.rs | 11 +++++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 3e665a88d49dc..5c87e90a5acc6 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -47,10 +47,8 @@ mod macros; pub mod int; pub mod float; -pub mod mem; -// only for the wasm32-unknown-unknown target -#[cfg(all(target_arch = "wasm32", target_os = "unknown"))] pub mod math; +pub mod mem; #[cfg(target_arch = "arm")] pub mod arm; diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index f1eaaa5fa414d..6eddc3d78abb6 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -14,6 +14,8 @@ macro_rules! no_mangle { } } +// only for the wasm32-unknown-unknown target +#[cfg(all(target_arch = "wasm32", target_os = "unknown"))] no_mangle! { fn acos(x: f64) -> f64; fn asin(x: f64) -> f64; @@ -50,3 +52,12 @@ no_mangle! { fn fma(x: f64, y: f64, z: f64) -> f64; fn fmaf(x: f32, y: f32, z: f32) -> f32; } + +// only for the thumb*-none-eabi* targets +#[cfg(all(target_arch = "arm", target_os = "none"))] +no_mangle! { + // `f64 % f64` + fn fmod(x: f64, y: f64) -> f64; + // `f32 % f32` + fn fmodf(x: f32, y: f32) -> f32; +} From cfa1690e6918de6ee8bbe92e2cfb69817b26d636 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 24 Jul 2018 16:57:22 -0500 Subject: [PATCH 0587/4206] fix warnings --- library/compiler-builtins/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 5c87e90a5acc6..02b6c7db953ad 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -47,6 +47,8 @@ mod macros; pub mod int; pub mod float; +#[cfg(any(all(target_arch = "wasm32", target_os = "unknown"), + all(target_arch = "arm", target_os = "none")))] pub mod math; pub mod mem; From 645468713446cabed74c9de55cf8df98e13ebe49 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 25 Jul 2018 13:16:10 -0500 Subject: [PATCH 0588/4206] omit bounds check in release mode this eliminates panicking branches in the optimized version of the functions. We keep the bounds checks when running the test suite to check that we never do an out of bounds access. This commit also adds a "must link" test that ensures that future changes in our implementation won't add panicking branches. closes rust-lang/libm#129 --- library/compiler-builtins/libm/Cargo.toml | 4 + library/compiler-builtins/libm/ci/script.sh | 14 ++- .../libm/examples/no-panic.rs | 115 ++++++++++++++++++ .../compiler-builtins/libm/src/math/atan.rs | 2 +- .../compiler-builtins/libm/src/math/mod.rs | 44 +++++++ .../libm/src/math/rem_pio2.rs | 2 +- .../libm/src/math/rem_pio2_large.rs | 104 ++++++++-------- 7 files changed, 233 insertions(+), 52 deletions(-) create mode 100644 library/compiler-builtins/libm/examples/no-panic.rs diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 11c59a2dbdb9a..8a2ba7447ab62 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -9,5 +9,9 @@ name = "libm" repository = "https://github.com/japaric/libm" version = "0.1.2" +[features] +# only used to run our test suite +checked = [] + [workspace] members = ["cb", "test-generator"] \ No newline at end of file diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh index cf37ac1ca64ba..71d9e088212e0 100644 --- a/library/compiler-builtins/libm/ci/script.sh +++ b/library/compiler-builtins/libm/ci/script.sh @@ -12,11 +12,21 @@ main() { # check that we can source import libm into compiler-builtins cargo check --package cb + # test that the functions don't contain invocations of `panic!` + case $TARGET in + armv7-unknown-linux-gnueabihf) + cross build --release --target $TARGET --example no-panic + ;; + esac + + # run unit tests + cross test --lib --features checked --target $TARGET --release + # generate tests cargo run --package test-generator --target x86_64-unknown-linux-musl - # run tests - cross test --target $TARGET --release + # run generated tests + cross test --tests --features checked --target $TARGET --release # TODO need to fix overflow issues (cf. issue #4) # cross test --target $TARGET diff --git a/library/compiler-builtins/libm/examples/no-panic.rs b/library/compiler-builtins/libm/examples/no-panic.rs new file mode 100644 index 0000000000000..fb79f99afa122 --- /dev/null +++ b/library/compiler-builtins/libm/examples/no-panic.rs @@ -0,0 +1,115 @@ +#![feature(lang_items)] +#![feature(panic_implementation)] +#![no_main] +#![no_std] + +extern crate libm; + +use core::panic::PanicInfo; +use core::ptr; + +macro_rules! force_eval { + ($e:expr) => { + unsafe { + core::ptr::read_volatile(&$e); + } + }; +} + +#[no_mangle] +pub fn main() { + force_eval!(libm::acos(random())); + force_eval!(libm::acosf(random())); + force_eval!(libm::asin(random())); + force_eval!(libm::asinf(random())); + force_eval!(libm::atan(random())); + force_eval!(libm::atan2(random(), random())); + force_eval!(libm::atan2f(random(), random())); + force_eval!(libm::atanf(random())); + force_eval!(libm::cbrt(random())); + force_eval!(libm::cbrtf(random())); + force_eval!(libm::ceil(random())); + force_eval!(libm::ceilf(random())); + force_eval!(libm::cos(random())); + force_eval!(libm::cosf(random())); + force_eval!(libm::cosh(random())); + force_eval!(libm::coshf(random())); + force_eval!(libm::exp(random())); + force_eval!(libm::exp2(random())); + force_eval!(libm::exp2f(random())); + force_eval!(libm::expf(random())); + force_eval!(libm::expm1(random())); + force_eval!(libm::expm1f(random())); + force_eval!(libm::fabs(random())); + force_eval!(libm::fabsf(random())); + force_eval!(libm::fdim(random(), random())); + force_eval!(libm::fdimf(random(), random())); + force_eval!(libm::floor(random())); + force_eval!(libm::floorf(random())); + force_eval!(libm::fma(random(), random(), random())); + force_eval!(libm::fmaf(random(), random(), random())); + force_eval!(libm::fmod(random(), random())); + force_eval!(libm::fmodf(random(), random())); + force_eval!(libm::hypot(random(), random())); + force_eval!(libm::hypotf(random(), random())); + force_eval!(libm::log(random())); + force_eval!(libm::log2(random())); + force_eval!(libm::log10(random())); + force_eval!(libm::log10f(random())); + force_eval!(libm::log1p(random())); + force_eval!(libm::log1pf(random())); + force_eval!(libm::log2f(random())); + force_eval!(libm::logf(random())); + force_eval!(libm::pow(random(), random())); + force_eval!(libm::powf(random(), random())); + force_eval!(libm::round(random())); + force_eval!(libm::roundf(random())); + force_eval!(libm::scalbn(random(), random())); + force_eval!(libm::scalbnf(random(), random())); + force_eval!(libm::sin(random())); + force_eval!(libm::sinf(random())); + force_eval!(libm::sinh(random())); + force_eval!(libm::sinhf(random())); + force_eval!(libm::sqrt(random())); + force_eval!(libm::sqrtf(random())); + force_eval!(libm::tan(random())); + force_eval!(libm::tanf(random())); + force_eval!(libm::tanh(random())); + force_eval!(libm::tanhf(random())); + force_eval!(libm::trunc(random())); + force_eval!(libm::truncf(random())); +} + +fn random() -> T +where + T: Copy, +{ + unsafe { + static mut X: usize = 0; + X += 8; + ptr::read_volatile(X as *const T) + } +} + +#[panic_implementation] +#[no_mangle] +pub fn panic(_info: &PanicInfo) -> ! { + // loop {} + extern "C" { + fn thou_shalt_not_panic() -> !; + } + + unsafe { thou_shalt_not_panic() } +} + +#[link(name = "c")] +extern "C" {} + +#[lang = "eh_personality"] +fn eh() {} + +#[no_mangle] +pub extern "C" fn __aeabi_unwind_cpp_pr0() {} + +#[no_mangle] +pub extern "C" fn __aeabi_unwind_cpp_pr1() {} diff --git a/library/compiler-builtins/libm/src/math/atan.rs b/library/compiler-builtins/libm/src/math/atan.rs index 47a2951c6f405..cf6a62a545917 100644 --- a/library/compiler-builtins/libm/src/math/atan.rs +++ b/library/compiler-builtins/libm/src/math/atan.rs @@ -124,7 +124,7 @@ pub fn atan(x: f64) -> f64 { return x - x * (s1 + s2); } - let z = ATANHI[id as usize] - (x * (s1 + s2) - ATANLO[id as usize] - x); + let z = i!(ATANHI, id as usize) - (x * (s1 + s2) - i!(ATANLO, id as usize) - x); if sign != 0 { -z diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 752a5991aeab2..f663ae674f91f 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -6,6 +6,50 @@ macro_rules! force_eval { }; } +#[cfg(not(feature = "checked"))] +macro_rules! i { + ($array:expr, $index:expr) => { + unsafe { *$array.get_unchecked($index) } + }; + ($array:expr, $index:expr, =, $rhs:expr) => { + unsafe { *$array.get_unchecked_mut($index) = $rhs; } + }; + ($array:expr, $index:expr, +=, $rhs:expr) => { + unsafe { *$array.get_unchecked_mut($index) += $rhs; } + }; + ($array:expr, $index:expr, -=, $rhs:expr) => { + unsafe { *$array.get_unchecked_mut($index) -= $rhs; } + }; + ($array:expr, $index:expr, &=, $rhs:expr) => { + unsafe { *$array.get_unchecked_mut($index) &= $rhs; } + }; + ($array:expr, $index:expr, ==, $rhs:expr) => { + unsafe { *$array.get_unchecked_mut($index) == $rhs } + }; +} + +#[cfg(feature = "checked")] +macro_rules! i { + ($array:expr, $index:expr) => { + *$array.get($index).unwrap() + }; + ($array:expr, $index:expr, =, $rhs:expr) => { + *$array.get_mut($index).unwrap() = $rhs; + }; + ($array:expr, $index:expr, -=, $rhs:expr) => { + *$array.get_mut($index).unwrap() -= $rhs; + }; + ($array:expr, $index:expr, +=, $rhs:expr) => { + *$array.get_mut($index).unwrap() += $rhs; + }; + ($array:expr, $index:expr, &=, $rhs:expr) => { + *$array.get_mut($index).unwrap() &= $rhs; + }; + ($array:expr, $index:expr, ==, $rhs:expr) => { + *$array.get_mut($index).unwrap() == $rhs + }; +} + // Public modules mod acos; mod acosf; diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 6e655e7d41929..5c1685877b67d 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -177,7 +177,7 @@ pub fn rem_pio2(x: f64) -> (i32, f64, f64) { tx[2] = z; /* skip zero terms, first term is non-zero */ let mut i = 2; - while tx[i] == 0.0 { + while i != 0 && tx[i] == 0.0 { i -= 1; } let mut ty = [0.0; 3]; 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 745b700a5eb2f..f44520931f8c5 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -1,3 +1,4 @@ +#![allow(unused_unsafe)] /* origin: FreeBSD /usr/src/lib/msun/src/k_rem_pio2.c */ /* * ==================================================== @@ -257,17 +258,21 @@ pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { let mut j = (jv - jx) as i32; let m = jx + jk; for i in 0..=m { - f[i] = if j < 0 { 0. } else { IPIO2[j as usize] as f64 }; - j += 1 + i!(f, i, =, if j < 0 { + 0. + } else { + i!(IPIO2, j as usize) as f64 + }); + j += 1; } /* compute q[0],q[1],...q[jk] */ for i in 0..=jk { fw = 0f64; for j in 0..=jx { - fw += x[j] * f[jx + i - j]; + fw += i!(x, j) * i!(f, jx + i - j); } - q[i] = fw; + i!(q, i, =, fw); } let mut jz = jk; @@ -275,11 +280,11 @@ pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { 'recompute: loop { /* distill q[] into iq[] reversingly */ let mut i = 0i32; - z = q[jz]; + z = i!(q, jz); for j in (1..=jz).rev() { fw = (x1p_24 * z) as i32 as f64; - iq[i as usize] = (z - x1p24 * fw) as i32; - z = q[j - 1] + fw; + i!(iq, i as usize, =, (z - x1p24 * fw) as i32); + z = i!(q, j - 1) + fw; i += 1; } @@ -291,12 +296,12 @@ pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { ih = 0; if q0 > 0 { /* need iq[jz-1] to determine n */ - i = iq[jz - 1] >> (24 - q0); + i = i!(iq, jz - 1) >> (24 - q0); n += i; - iq[jz - 1] -= i << (24 - q0); - ih = iq[jz - 1] >> (23 - q0); + i!(iq, jz - 1, -=, i << (24 - q0)); + ih = i!(iq, jz - 1) >> (23 - q0); } else if q0 == 0 { - ih = iq[jz - 1] >> 23; + ih = i!(iq, jz - 1) >> 23; } else if z >= 0.5 { ih = 2; } @@ -307,24 +312,24 @@ pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { let mut carry = 0i32; for i in 0..jz { /* compute 1-q */ - let j = iq[i]; + let j = i!(iq, i); if carry == 0 { if j != 0 { carry = 1; - iq[i] = 0x1000000 - j; + i!(iq, i, =, 0x1000000 - j); } } else { - iq[i] = 0xffffff - j; + i!(iq, i, =, 0xffffff - j); } } if q0 > 0 { /* rare case: chance is 1 in 12 */ match q0 { 1 => { - iq[jz - 1] &= 0x7fffff; + i!(iq, jz - 1, &=, 0x7fffff); } 2 => { - iq[jz - 1] &= 0x3fffff; + i!(iq, jz - 1, &=, 0x3fffff); } _ => {} } @@ -341,23 +346,23 @@ pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { if z == 0. { let mut j = 0; for i in (jk..=jz - 1).rev() { - j |= iq[i]; + j |= i!(iq, i); } if j == 0 { /* need recomputation */ let mut k = 1; - while iq[jk - k] == 0 { + while i!(iq, jk - k, ==, 0) { k += 1; /* k = no. of terms needed */ } for i in (jz + 1)..=(jz + k) { /* add q[jz+1] to q[jz+k] */ - f[jx + i] = IPIO2[jv + i] as f64; + i!(f, jx + i, =, i!(IPIO2, jv + i) as f64); fw = 0f64; for j in 0..=jx { - fw += x[j] * f[jx + i - j]; + fw += i!(x, j) * i!(f, jx + i - j); } - q[i] = fw; + i!(q, i, =, fw); } jz += k; continue 'recompute; @@ -371,7 +376,7 @@ pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { if z == 0. { jz -= 1; q0 -= 24; - while iq[jz] == 0 { + while i!(iq, jz) == 0 { jz -= 1; q0 -= 24; } @@ -380,19 +385,19 @@ pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { z = scalbn(z, -q0); if z >= x1p24 { fw = (x1p_24 * z) as i32 as f64; - iq[jz] = (z - x1p24 * fw) as i32; + i!(iq, jz, =, (z - x1p24 * fw) as i32); jz += 1; q0 += 24; - iq[jz] = fw as i32; + i!(iq, jz, =, fw as i32); } else { - iq[jz] = z as i32; + i!(iq, jz, =, z as i32); } } /* convert integer "bit" chunk to floating-point value */ fw = scalbn(1., q0); for i in (0..=jz).rev() { - q[i] = fw * (iq[i] as f64); + i!(q, i, =, fw * (i!(iq, i) as f64)); fw *= x1p_24; } @@ -401,10 +406,10 @@ pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { fw = 0f64; let mut k = 0; while (k <= jp) && (k <= jz - i) { - fw += PIO2[k] * q[i + k]; + fw += i!(PIO2, k) * i!(q, i + k); k += 1; } - fq[jz - i] = fw; + i!(fq, jz - i, =, fw); } /* compress fq[] into y[] */ @@ -412,51 +417,54 @@ pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { 0 => { fw = 0f64; for i in (0..=jz).rev() { - fw += fq[i]; + fw += i!(fq, i); } - y[0] = if ih == 0 { fw } else { -fw }; + i!(y, 0, =, if ih == 0 { fw } else { -fw }); } 1 | 2 => { fw = 0f64; for i in (0..=jz).rev() { - fw += fq[i]; + fw += i!(fq, i); } // TODO: drop excess precision here once double_t is used fw = fw as f64; - y[0] = if ih == 0 { fw } else { -fw }; - fw = fq[0] - fw; + i!(y, 0, =, if ih == 0 { fw } else { -fw }); + fw = i!(fq, 0) - fw; for i in 1..=jz { - fw += fq[i]; + fw += i!(fq, i); } - y[1] = if ih == 0 { fw } else { -fw }; + i!(y, 1, =, if ih == 0 { fw } else { -fw }); } 3 => { /* painful */ for i in (1..=jz).rev() { - fw = fq[i - 1] + fq[i]; - fq[i] += fq[i - 1] - fw; - fq[i - 1] = fw; + fw = i!(fq, i - 1) + i!(fq, i); + i!(fq, i, +=, i!(fq, i - 1) - fw); + i!(fq, i - 1, =, fw); } for i in (2..=jz).rev() { - fw = fq[i - 1] + fq[i]; - fq[i] += fq[i - 1] - fw; - fq[i - 1] = fw; + fw = i!(fq, i - 1) + i!(fq, i); + i!(fq, i, +=, i!(fq, i - 1) - fw); + i!(fq, i - 1, =, fw); } fw = 0f64; for i in (2..=jz).rev() { - fw += fq[i]; + fw += i!(fq, i); } if ih == 0 { - y[0] = fq[0]; - y[1] = fq[1]; - y[2] = fw; + i!(y, 0, =, i!(fq, 0)); + i!(y, 1, =, i!(fq, 1)); + i!(y, 2, =, fw); } else { - y[0] = -fq[0]; - y[1] = -fq[1]; - y[2] = -fw; + i!(y, 0, =, -i!(fq, 0)); + i!(y, 1, =, -i!(fq, 1)); + i!(y, 2, =, -fw); } } + #[cfg(feature = "checked")] _ => unreachable!(), + #[cfg(not(feature = "checked"))] + _ => {}, } n & 7 } From 657906b30c5fcf3810f31a3e5967112b917750df Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 25 Jul 2018 14:48:49 -0500 Subject: [PATCH 0589/4206] ci: add nightly build job to rnu the no-panic test --- library/compiler-builtins/libm/.travis.yml | 3 +++ library/compiler-builtins/libm/ci/script.sh | 13 ++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/libm/.travis.yml b/library/compiler-builtins/libm/.travis.yml index 223b586ea6daf..922273e0936ba 100644 --- a/library/compiler-builtins/libm/.travis.yml +++ b/library/compiler-builtins/libm/.travis.yml @@ -17,6 +17,9 @@ matrix: - env: TARGET=x86_64-unknown-linux-gnu - env: TARGET=cargo-fmt rust: beta + # no-panic link test + - env: TARGET=armv7-unknown-linux-gnueabihf + rust: nightly before_install: set -e diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh index 71d9e088212e0..5156047df5829 100644 --- a/library/compiler-builtins/libm/ci/script.sh +++ b/library/compiler-builtins/libm/ci/script.sh @@ -6,19 +6,18 @@ main() { return fi + # test that the functions don't contain invocations of `panic!` + if [ $TRAVIS_RUST_VERSION ]; then + cross build --release --target $TARGET --example no-panic + return + fi + # quick check cargo check # check that we can source import libm into compiler-builtins cargo check --package cb - # test that the functions don't contain invocations of `panic!` - case $TARGET in - armv7-unknown-linux-gnueabihf) - cross build --release --target $TARGET --example no-panic - ;; - esac - # run unit tests cross test --lib --features checked --target $TARGET --release From a4197d1cdefcf87463c5a6be4163fa8ab5e390d1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 25 Jul 2018 14:49:14 -0500 Subject: [PATCH 0590/4206] cargo fmt --- .../compiler-builtins/libm/src/math/mod.rs | 36 +++++++++++-------- .../libm/src/math/rem_pio2_large.rs | 2 +- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index f663ae674f91f..da34fb4cecd1d 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -11,19 +11,27 @@ macro_rules! i { ($array:expr, $index:expr) => { unsafe { *$array.get_unchecked($index) } }; - ($array:expr, $index:expr, =, $rhs:expr) => { - unsafe { *$array.get_unchecked_mut($index) = $rhs; } + ($array:expr, $index:expr, = , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) = $rhs; + } }; - ($array:expr, $index:expr, +=, $rhs:expr) => { - unsafe { *$array.get_unchecked_mut($index) += $rhs; } + ($array:expr, $index:expr, += , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) += $rhs; + } }; - ($array:expr, $index:expr, -=, $rhs:expr) => { - unsafe { *$array.get_unchecked_mut($index) -= $rhs; } + ($array:expr, $index:expr, -= , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) -= $rhs; + } }; - ($array:expr, $index:expr, &=, $rhs:expr) => { - unsafe { *$array.get_unchecked_mut($index) &= $rhs; } + ($array:expr, $index:expr, &= , $rhs:expr) => { + unsafe { + *$array.get_unchecked_mut($index) &= $rhs; + } }; - ($array:expr, $index:expr, ==, $rhs:expr) => { + ($array:expr, $index:expr, == , $rhs:expr) => { unsafe { *$array.get_unchecked_mut($index) == $rhs } }; } @@ -33,19 +41,19 @@ macro_rules! i { ($array:expr, $index:expr) => { *$array.get($index).unwrap() }; - ($array:expr, $index:expr, =, $rhs:expr) => { + ($array:expr, $index:expr, = , $rhs:expr) => { *$array.get_mut($index).unwrap() = $rhs; }; - ($array:expr, $index:expr, -=, $rhs:expr) => { + ($array:expr, $index:expr, -= , $rhs:expr) => { *$array.get_mut($index).unwrap() -= $rhs; }; - ($array:expr, $index:expr, +=, $rhs:expr) => { + ($array:expr, $index:expr, += , $rhs:expr) => { *$array.get_mut($index).unwrap() += $rhs; }; - ($array:expr, $index:expr, &=, $rhs:expr) => { + ($array:expr, $index:expr, &= , $rhs:expr) => { *$array.get_mut($index).unwrap() &= $rhs; }; - ($array:expr, $index:expr, ==, $rhs:expr) => { + ($array:expr, $index:expr, == , $rhs:expr) => { *$array.get_mut($index).unwrap() == $rhs }; } 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 f44520931f8c5..4d9146af9d627 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -464,7 +464,7 @@ pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { #[cfg(feature = "checked")] _ => unreachable!(), #[cfg(not(feature = "checked"))] - _ => {}, + _ => {} } n & 7 } From 47e65384f254e5d0328fee59f40acddc000a4b7c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 25 Jul 2018 15:02:10 -0500 Subject: [PATCH 0591/4206] ci: fix if condition --- library/compiler-builtins/libm/ci/script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh index 5156047df5829..bb19e23d84e07 100644 --- a/library/compiler-builtins/libm/ci/script.sh +++ b/library/compiler-builtins/libm/ci/script.sh @@ -7,7 +7,7 @@ main() { fi # test that the functions don't contain invocations of `panic!` - if [ $TRAVIS_RUST_VERSION ]; then + if [ $TRAVIS_RUST_VERSION = nightly ]; then cross build --release --target $TARGET --example no-panic return fi From be2f980cf6ae19da23a1ac8684f0b426be5ee6ff Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 25 Jul 2018 18:11:47 -0700 Subject: [PATCH 0592/4206] Update libm to elide bounds checks --- library/compiler-builtins/libm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index d65f60f24289b..96e36ea2620f9 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit d65f60f24289ba212f5d47792f7236857efb2339 +Subproject commit 96e36ea2620f9fbbaa46a01694a2fa3ef6c2fb7e From c626608e414820d87a2c81f0701ded45b1fb4597 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 27 Jul 2018 00:11:06 -0500 Subject: [PATCH 0593/4206] add newlib support to the test generator --- library/compiler-builtins/libm/.gitignore | 3 + library/compiler-builtins/libm/.travis.yml | 35 +- library/compiler-builtins/libm/Cargo.toml | 11 +- library/compiler-builtins/libm/ci/install.sh | 3 + library/compiler-builtins/libm/ci/script.sh | 17 +- .../Cargo.toml | 6 +- .../libm/input-generator/src/main.rs | 189 +++++ .../compiler-builtins/libm/math/.cargo/config | 11 + .../compiler-builtins/libm/math/Cargo.toml | 8 + .../compiler-builtins/libm/math/Cross.toml | 2 + .../libm/musl-generator/Cargo.toml | 9 + .../libm/musl-generator/src/macros.rs | 191 +++++ .../libm/musl-generator/src/main.rs | 97 +++ .../libm/newlib-generator/Cargo.toml | 7 + .../libm/newlib-generator/src/macros.rs | 245 ++++++ .../libm/newlib-generator/src/main.rs | 32 + .../compiler-builtins/libm/shared/Cargo.toml | 7 + .../compiler-builtins/libm/shared/src/lib.rs | 471 +++++++++++ library/compiler-builtins/libm/src/lib.rs | 28 +- .../libm/test-generator/README.md | 8 - .../libm/test-generator/src/main.rs | 788 ------------------ 21 files changed, 1343 insertions(+), 825 deletions(-) rename library/compiler-builtins/libm/{test-generator => input-generator}/Cargo.toml (55%) create mode 100644 library/compiler-builtins/libm/input-generator/src/main.rs create mode 100644 library/compiler-builtins/libm/math/.cargo/config create mode 100644 library/compiler-builtins/libm/math/Cargo.toml create mode 100644 library/compiler-builtins/libm/math/Cross.toml create mode 100644 library/compiler-builtins/libm/musl-generator/Cargo.toml create mode 100644 library/compiler-builtins/libm/musl-generator/src/macros.rs create mode 100644 library/compiler-builtins/libm/musl-generator/src/main.rs create mode 100644 library/compiler-builtins/libm/newlib-generator/Cargo.toml create mode 100644 library/compiler-builtins/libm/newlib-generator/src/macros.rs create mode 100644 library/compiler-builtins/libm/newlib-generator/src/main.rs create mode 100644 library/compiler-builtins/libm/shared/Cargo.toml create mode 100644 library/compiler-builtins/libm/shared/src/lib.rs delete mode 100644 library/compiler-builtins/libm/test-generator/README.md delete mode 100644 library/compiler-builtins/libm/test-generator/src/main.rs diff --git a/library/compiler-builtins/libm/.gitignore b/library/compiler-builtins/libm/.gitignore index 6db0ab6effc41..39950911a6249 100644 --- a/library/compiler-builtins/libm/.gitignore +++ b/library/compiler-builtins/libm/.gitignore @@ -1,5 +1,8 @@ **/*.rs.bk .#* +/bin +/math/src +/math/target /target /tests Cargo.lock diff --git a/library/compiler-builtins/libm/.travis.yml b/library/compiler-builtins/libm/.travis.yml index 922273e0936ba..b3beecb092049 100644 --- a/library/compiler-builtins/libm/.travis.yml +++ b/library/compiler-builtins/libm/.travis.yml @@ -5,21 +5,29 @@ sudo: required matrix: include: - env: TARGET=aarch64-unknown-linux-gnu - - env: TARGET=armv7-unknown-linux-gnueabihf - - env: TARGET=i686-unknown-linux-gnu - - env: TARGET=mips-unknown-linux-gnu - - env: TARGET=mips64-unknown-linux-gnuabi64 - - env: TARGET=mips64el-unknown-linux-gnuabi64 - - env: TARGET=mipsel-unknown-linux-gnu - - env: TARGET=powerpc-unknown-linux-gnu - - env: TARGET=powerpc64-unknown-linux-gnu - - env: TARGET=powerpc64le-unknown-linux-gnu + rust: nightly + # - env: TARGET=armv7-unknown-linux-gnueabihf + # rust: nightly + # - env: TARGET=i686-unknown-linux-gnu + # rust: nightly + # - env: TARGET=mips-unknown-linux-gnu + # rust: nightly + # - env: TARGET=mips64-unknown-linux-gnuabi64 + # rust: nightly + # - env: TARGET=mips64el-unknown-linux-gnuabi64 + # rust: nightly + # - env: TARGET=mipsel-unknown-linux-gnu + # rust: nightly + # - env: TARGET=powerpc-unknown-linux-gnu + # rust: nightly + # - env: TARGET=powerpc64-unknown-linux-gnu + # rust: nightly + # - env: TARGET=powerpc64le-unknown-linux-gnu + # rust: nightly - env: TARGET=x86_64-unknown-linux-gnu - - env: TARGET=cargo-fmt - rust: beta - # no-panic link test - - env: TARGET=armv7-unknown-linux-gnueabihf rust: nightly + # - env: TARGET=cargo-fmt + # rust: beta before_install: set -e @@ -27,6 +35,7 @@ install: - bash ci/install.sh script: + - export PATH=$HOME/.local/bin:$PATH - bash ci/script.sh after_script: set +e diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 8a2ba7447ab62..cedf8d267db8a 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -14,4 +14,13 @@ version = "0.1.2" checked = [] [workspace] -members = ["cb", "test-generator"] \ No newline at end of file +members = [ + "cb", + "input-generator", + "musl-generator", + "newlib-generator", + "shared", +] + +[dev-dependencies] +shared = { path = "shared" } diff --git a/library/compiler-builtins/libm/ci/install.sh b/library/compiler-builtins/libm/ci/install.sh index 4d9552d231bc0..7f73c5feaf369 100644 --- a/library/compiler-builtins/libm/ci/install.sh +++ b/library/compiler-builtins/libm/ci/install.sh @@ -15,6 +15,9 @@ main() { if [ $TARGET != x86_64-unknown-linux-gnu ]; then rustup target add $TARGET fi + + mkdir -p ~/.local/bin + curl -L https://github.com/japaric/qemu-bin/raw/master/14.04/qemu-arm-2.12.0 > ~/.local/bin/qemu-arm } main diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh index bb19e23d84e07..59e5a5f37de95 100644 --- a/library/compiler-builtins/libm/ci/script.sh +++ b/library/compiler-builtins/libm/ci/script.sh @@ -7,10 +7,11 @@ main() { fi # test that the functions don't contain invocations of `panic!` - if [ $TRAVIS_RUST_VERSION = nightly ]; then - cross build --release --target $TARGET --example no-panic - return - fi + case $TARGET in + armv7-unknown-linux-gnueabihf) + cross build --release --target $TARGET --example no-panic + ;; + esac # quick check cargo check @@ -18,12 +19,14 @@ main() { # check that we can source import libm into compiler-builtins cargo check --package cb + # generate tests + cargo run -p input-generator --target x86_64-unknown-linux-musl + cargo run -p musl-generator --target x86_64-unknown-linux-musl + cargo run -p newlib-generator + # run unit tests cross test --lib --features checked --target $TARGET --release - # generate tests - cargo run --package test-generator --target x86_64-unknown-linux-musl - # run generated tests cross test --tests --features checked --target $TARGET --release diff --git a/library/compiler-builtins/libm/test-generator/Cargo.toml b/library/compiler-builtins/libm/input-generator/Cargo.toml similarity index 55% rename from library/compiler-builtins/libm/test-generator/Cargo.toml rename to library/compiler-builtins/libm/input-generator/Cargo.toml index b810d9daf6305..fef2558a8b09f 100644 --- a/library/compiler-builtins/libm/test-generator/Cargo.toml +++ b/library/compiler-builtins/libm/input-generator/Cargo.toml @@ -1,9 +1,7 @@ [package] -name = "test-generator" +name = "input-generator" version = "0.1.0" authors = ["Jorge Aparicio "] -publish = false [dependencies] -rand = "0.5.3" -itertools = "0.7.8" +rand = "0.5.4" diff --git a/library/compiler-builtins/libm/input-generator/src/main.rs b/library/compiler-builtins/libm/input-generator/src/main.rs new file mode 100644 index 0000000000000..b4a6ad142258c --- /dev/null +++ b/library/compiler-builtins/libm/input-generator/src/main.rs @@ -0,0 +1,189 @@ +extern crate rand; + +use std::collections::BTreeSet; +use std::error::Error; +use std::fs::{self, File}; +use std::io::Write; + +use rand::{RngCore, SeedableRng, XorShiftRng}; + +const NTESTS: usize = 10_000; + +fn main() -> Result<(), Box> { + let mut rng = XorShiftRng::from_rng(&mut rand::thread_rng())?; + + fs::remove_dir_all("bin").ok(); + fs::create_dir_all("bin/input")?; + fs::create_dir_all("bin/output")?; + + f32(&mut rng)?; + f32f32(&mut rng)?; + f32f32f32(&mut rng)?; + f32i16(&mut rng)?; + f64(&mut rng)?; + f64f64(&mut rng)?; + f64f64f64(&mut rng)?; + f64i16(&mut rng)?; + + Ok(()) +} + +fn f32(rng: &mut XorShiftRng) -> Result<(), Box> { + let mut set = BTreeSet::new(); + + while set.len() < NTESTS { + let f = f32::from_bits(rng.next_u32()); + + if f.is_nan() { + continue; + } + + set.insert(f.to_bits()); + } + + let mut f = File::create("bin/input/f32")?; + for i in set { + f.write_all(&i.to_bytes())?; + } + + Ok(()) +} + +fn f32f32(rng: &mut XorShiftRng) -> Result<(), Box> { + let mut f = File::create("bin/input/f32f32")?; + let mut i = 0; + while i < NTESTS { + let x0 = f32::from_bits(rng.next_u32()); + let x1 = f32::from_bits(rng.next_u32()); + + if x0.is_nan() || x1.is_nan() { + continue; + } + + i += 1; + f.write_all(&x0.to_bits().to_bytes())?; + f.write_all(&x1.to_bits().to_bytes())?; + } + + Ok(()) +} + +fn f32i16(rng: &mut XorShiftRng) -> Result<(), Box> { + let mut f = File::create("bin/input/f32i16")?; + let mut i = 0; + while i < NTESTS { + let x0 = f32::from_bits(rng.next_u32()); + let x1 = rng.next_u32() as i16; + + if x0.is_nan() { + continue; + } + + i += 1; + f.write_all(&x0.to_bits().to_bytes())?; + f.write_all(&x1.to_bytes())?; + } + + Ok(()) +} + +fn f32f32f32(rng: &mut XorShiftRng) -> Result<(), Box> { + let mut f = File::create("bin/input/f32f32f32")?; + let mut i = 0; + while i < NTESTS { + let x0 = f32::from_bits(rng.next_u32()); + let x1 = f32::from_bits(rng.next_u32()); + let x2 = f32::from_bits(rng.next_u32()); + + if x0.is_nan() || x1.is_nan() || x2.is_nan() { + continue; + } + + i += 1; + f.write_all(&x0.to_bits().to_bytes())?; + f.write_all(&x1.to_bits().to_bytes())?; + f.write_all(&x2.to_bits().to_bytes())?; + } + + Ok(()) +} + +fn f64(rng: &mut XorShiftRng) -> Result<(), Box> { + let mut set = BTreeSet::new(); + + while set.len() < NTESTS { + let f = f64::from_bits(rng.next_u64()); + + if f.is_nan() { + continue; + } + + set.insert(f.to_bits()); + } + + let mut f = File::create("bin/input/f64")?; + for i in set { + f.write_all(&i.to_bytes())?; + } + + Ok(()) +} + +fn f64f64(rng: &mut XorShiftRng) -> Result<(), Box> { + let mut f = File::create("bin/input/f64f64")?; + let mut i = 0; + while i < NTESTS { + let x0 = f64::from_bits(rng.next_u64()); + let x1 = f64::from_bits(rng.next_u64()); + + if x0.is_nan() || x1.is_nan() { + continue; + } + + i += 1; + f.write_all(&x0.to_bits().to_bytes())?; + f.write_all(&x1.to_bits().to_bytes())?; + } + + Ok(()) +} + +fn f64f64f64(rng: &mut XorShiftRng) -> Result<(), Box> { + let mut f = File::create("bin/input/f64f64f64")?; + let mut i = 0; + while i < NTESTS { + let x0 = f64::from_bits(rng.next_u64()); + let x1 = f64::from_bits(rng.next_u64()); + let x2 = f64::from_bits(rng.next_u64()); + + if x0.is_nan() || x1.is_nan() || x2.is_nan() { + continue; + } + + i += 1; + f.write_all(&x0.to_bits().to_bytes())?; + f.write_all(&x1.to_bits().to_bytes())?; + f.write_all(&x2.to_bits().to_bytes())?; + } + + Ok(()) +} + +fn f64i16(rng: &mut XorShiftRng) -> Result<(), Box> { + let mut f = File::create("bin/input/f64i16")?; + let mut i = 0; + while i < NTESTS { + let x0 = f64::from_bits(rng.next_u64()); + let x1 = rng.next_u32() as i16; + + if x0.is_nan() { + continue; + } + + i += 1; + f.write_all(&x0.to_bits().to_bytes())?; + f.write_all(&x1.to_bytes())?; + } + + Ok(()) +} diff --git a/library/compiler-builtins/libm/math/.cargo/config b/library/compiler-builtins/libm/math/.cargo/config new file mode 100644 index 0000000000000..be79c453ad697 --- /dev/null +++ b/library/compiler-builtins/libm/math/.cargo/config @@ -0,0 +1,11 @@ +[target.thumbv7em-none-eabi] +rustflags = [ + "-C", "link-arg=-Wl,-Tlink.x", + "-C", "link-arg=-nostartfiles", + "-C", "link-arg=-mthumb", + "-C", "link-arg=-march=armv7e-m", + "-C", "link-arg=-mfloat-abi=soft", +] + +[build] +target = "thumbv7em-none-eabi" \ No newline at end of file diff --git a/library/compiler-builtins/libm/math/Cargo.toml b/library/compiler-builtins/libm/math/Cargo.toml new file mode 100644 index 0000000000000..5bca038a9c3ce --- /dev/null +++ b/library/compiler-builtins/libm/math/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "math" +version = "0.0.0" + +[dependencies] +qemu-arm-rt = { git = "https://github.com/japaric/qemu-arm-rt" } + +[workspace] \ No newline at end of file diff --git a/library/compiler-builtins/libm/math/Cross.toml b/library/compiler-builtins/libm/math/Cross.toml new file mode 100644 index 0000000000000..471770b528b45 --- /dev/null +++ b/library/compiler-builtins/libm/math/Cross.toml @@ -0,0 +1,2 @@ +[target.thumbv7em-none-eabi] +xargo = false \ No newline at end of file diff --git a/library/compiler-builtins/libm/musl-generator/Cargo.toml b/library/compiler-builtins/libm/musl-generator/Cargo.toml new file mode 100644 index 0000000000000..0564f35361167 --- /dev/null +++ b/library/compiler-builtins/libm/musl-generator/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "musl-generator" +version = "0.1.0" +authors = ["Jorge Aparicio "] + +[dependencies] +lazy_static = "1.0.2" +shared = { path = "../shared" } +libm = { path = ".." } diff --git a/library/compiler-builtins/libm/musl-generator/src/macros.rs b/library/compiler-builtins/libm/musl-generator/src/macros.rs new file mode 100644 index 0000000000000..16ba99d640c65 --- /dev/null +++ b/library/compiler-builtins/libm/musl-generator/src/macros.rs @@ -0,0 +1,191 @@ +macro_rules! f32 { + ($($fun:ident,)+) => {{ + $( + // check type signature + let _: fn(f32) -> f32 = libm::$fun; + let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; + )+ + + for x in shared::F32.iter() { + $( + let y = unsafe { + extern "C" { + fn $fun(_: f32) -> f32; + } + + $fun(*x) + }; + + $fun.write_all(&y.to_bits().to_bytes())?; + )+ + } + }}; +} + +macro_rules! f32f32 { + ($($fun:ident,)+) => {{ + $( + // check type signature + let _: fn(f32, f32) -> f32 = libm::$fun; + let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; + )+ + + for (x0, x1) in shared::F32F32.iter() { + $( + let y = unsafe { + extern "C" { + fn $fun(_: f32, _: f32) -> f32; + } + + $fun(*x0, *x1) + }; + + $fun.write_all(&y.to_bits().to_bytes())?; + )+ + } + }}; +} + +macro_rules! f32f32f32 { + ($($fun:ident,)+) => {{ + $( + // check type signature + let _: fn(f32, f32, f32) -> f32 = libm::$fun; + let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; + )+ + + for (x0, x1, x2) in shared::F32F32F32.iter() { + $( + let y = unsafe { + extern "C" { + fn $fun(_: f32, _: f32, _: f32) -> f32; + } + + $fun(*x0, *x1, *x2) + }; + + $fun.write_all(&y.to_bits().to_bytes())?; + )+ + } + }}; +} + +macro_rules! f32i32 { + ($($fun:ident,)+) => {{ + $( + // check type signature + let _: fn(f32, i32) -> f32 = libm::$fun; + let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; + )+ + + for (x0, x1) in shared::F32I32.iter() { + $( + let y = unsafe { + extern "C" { + fn $fun(_: f32, _: i32) -> f32; + } + + $fun(*x0, *x1 as i32) + }; + + $fun.write_all(&y.to_bits().to_bytes())?; + )+ + } + }}; +} + +macro_rules! f64 { + ($($fun:ident,)+) => {{ + $( + // check type signature + let _: fn(f64) -> f64 = libm::$fun; + let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; + )+ + + for x in shared::F64.iter() { + $( + let y = unsafe { + extern "C" { + fn $fun(_: f64) -> f64; + } + + $fun(*x) + }; + + $fun.write_all(&y.to_bits().to_bytes())?; + )+ + } + }}; +} + +macro_rules! f64f64 { + ($($fun:ident,)+) => {{ + $( + // check type signature + let _: fn(f64, f64) -> f64 = libm::$fun; + let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; + )+ + + for (x0, x1) in shared::F64F64.iter() { + $( + let y = unsafe { + extern "C" { + fn $fun(_: f64, _: f64) -> f64; + } + + $fun(*x0, *x1) + }; + + $fun.write_all(&y.to_bits().to_bytes())?; + )+ + } + }}; +} + +macro_rules! f64f64f64 { + ($($fun:ident,)+) => {{ + $( + // check type signature + let _: fn(f64, f64, f64) -> f64 = libm::$fun; + let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; + )+ + + for (x0, x1, x2) in shared::F64F64F64.iter() { + $( + let y = unsafe { + extern "C" { + fn $fun(_: f64, _: f64, _: f64) -> f64; + } + + $fun(*x0, *x1, *x2) + }; + + $fun.write_all(&y.to_bits().to_bytes())?; + )+ + } + }}; +} + +macro_rules! f64i32 { + ($($fun:ident,)+) => {{ + $( + // check type signature + let _: fn(f64, i32) -> f64 = libm::$fun; + let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; + )+ + + for (x0, x1) in shared::F64I32.iter() { + $( + let y = unsafe { + extern "C" { + fn $fun(_: f64, _: i32) -> f64; + } + + $fun(*x0, *x1 as i32) + }; + + $fun.write_all(&y.to_bits().to_bytes())?; + )+ + } + }}; +} diff --git a/library/compiler-builtins/libm/musl-generator/src/main.rs b/library/compiler-builtins/libm/musl-generator/src/main.rs new file mode 100644 index 0000000000000..6e57e856dc644 --- /dev/null +++ b/library/compiler-builtins/libm/musl-generator/src/main.rs @@ -0,0 +1,97 @@ +extern crate libm; +extern crate shared; + +use std::error::Error; +use std::fs::File; +use std::io::Write; + +#[macro_use] +mod macros; + +fn main() -> Result<(), Box> { + f32! { + acosf, + asinf, + atanf, + cbrtf, + ceilf, + cosf, + coshf, + exp2f, + expf, + expm1f, + fabsf, + floorf, + log10f, + log1pf, + log2f, + logf, + roundf, + sinf, + sinhf, + sqrtf, + tanf, + tanhf, + truncf, + } + + f32f32! { + atan2f, + fdimf, + fmodf, + hypotf, + powf, + } + + f32i32! { + scalbnf, + } + + f32f32f32! { + fmaf, + } + + f64! { + acos, + asin, + atan, + cbrt, + ceil, + cos, + cosh, + exp, + exp2, + expm1, + fabs, + floor, + log, + log10, + log1p, + log2, + round, + sin, + sinh, + sqrt, + tan, + tanh, + trunc, + } + + f64f64! { + atan2, + fdim, + fmod, + hypot, + pow, + } + + f64i32! { + scalbn, + } + + f64f64f64! { + fma, + } + + Ok(()) +} diff --git a/library/compiler-builtins/libm/newlib-generator/Cargo.toml b/library/compiler-builtins/libm/newlib-generator/Cargo.toml new file mode 100644 index 0000000000000..5766cb4b7a059 --- /dev/null +++ b/library/compiler-builtins/libm/newlib-generator/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "newlib-generator" +version = "0.1.0" +authors = ["Jorge Aparicio "] + +[dependencies] +shared = { path = "../shared" } diff --git a/library/compiler-builtins/libm/newlib-generator/src/macros.rs b/library/compiler-builtins/libm/newlib-generator/src/macros.rs new file mode 100644 index 0000000000000..84315a777bdef --- /dev/null +++ b/library/compiler-builtins/libm/newlib-generator/src/macros.rs @@ -0,0 +1,245 @@ +macro_rules! f32 { + ($($fun:ident,)+) => { + $( + let fun = stringify!($fun); + + fs::create_dir_all("math/src")?; + + let main = format!(" +#![no_main] +#![no_std] + +#[macro_use] +extern crate qemu_arm_rt as rt; + +use core::u32; + +use rt::{{io, process}}; + +entry!(main); + +fn main() {{ + run().unwrap_or_else(|e| {{ + eprintln!(\"error: {{}}\", e); + process::exit(1); + }}) +}} + +fn run() -> Result<(), usize> {{ + #[link(name = \"m\")] + extern \"C\" {{ + fn {0}(_: f32) -> f32; + }} + + let mut buf = [0; 4]; + while let Ok(()) = io::Stdin.read_exact(&mut buf) {{ + let x = f32::from_bits(u32::from_bytes(buf)); + let y = unsafe {{ {0}(x) }}; + + io::Stdout.write_all(&y.to_bits().to_bytes())?; + }} + + Ok(()) +}} + +#[no_mangle] +pub fn __errno() -> *mut i32 {{ + static mut ERRNO: i32 = 0; + unsafe {{ &mut ERRNO }} +}} +", fun); + + File::create("math/src/main.rs")?.write_all(main.as_bytes())?; + + assert!( + Command::new("cross") + .args(&["build", "--target", "thumbv7em-none-eabi", "--release"]) + .current_dir("math") + .status()? + .success() + ); + + let mut qemu = Command::new("qemu-arm") + .arg("math/target/thumbv7em-none-eabi/release/math") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn()?; + + qemu.stdin.as_mut().take().unwrap().write_all(F32)?; + + let output = qemu.wait_with_output()?; + + File::create(concat!("bin/output/newlib.", stringify!($fun)))? + .write_all(&output.stdout)?; + )+ + } +} + +macro_rules! f32f32 { + ($($fun:ident,)+) => { + $( + let fun = stringify!($fun); + + fs::create_dir_all("math/src")?; + + let main = format!(" +#![no_main] +#![no_std] + +#[macro_use] +extern crate qemu_arm_rt as rt; + +use core::u32; + +use rt::{{io, process}}; + +entry!(main); + +fn main() {{ + run().unwrap_or_else(|e| {{ + eprintln!(\"error: {{}}\", e); + process::exit(1); + }}) +}} + +fn run() -> Result<(), usize> {{ + #[link(name = \"m\")] + extern \"C\" {{ + fn {0}(_: f32, _: f32) -> f32; + }} + + let mut chunk = [0; 8]; + while let Ok(()) = io::Stdin.read_exact(&mut chunk) {{ + let mut buf = [0; 4]; + buf.copy_from_slice(&chunk[..4]); + let x0 = f32::from_bits(u32::from_bytes(buf)); + + buf.copy_from_slice(&chunk[4..]); + let x1 = f32::from_bits(u32::from_bytes(buf)); + + let y = unsafe {{ {0}(x0, x1) }}; + + io::Stdout.write_all(&y.to_bits().to_bytes())?; + }} + + Ok(()) +}} + +#[no_mangle] +pub fn __errno() -> *mut i32 {{ + static mut ERRNO: i32 = 0; + unsafe {{ &mut ERRNO }} +}} +", fun); + + File::create("math/src/main.rs")?.write_all(main.as_bytes())?; + + assert!( + Command::new("cross") + .args(&["build", "--target", "thumbv7em-none-eabi", "--release"]) + .current_dir("math") + .status()? + .success() + ); + + let mut qemu = Command::new("qemu-arm") + .arg("math/target/thumbv7em-none-eabi/release/math") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn()?; + + qemu.stdin.as_mut().take().unwrap().write_all(F32)?; + + let output = qemu.wait_with_output()?; + + File::create(concat!("bin/output/newlib.", stringify!($fun)))? + .write_all(&output.stdout)?; + )+ + } +} + +macro_rules! f32f32f32 { + ($($fun:ident,)+) => { + $( + let fun = stringify!($fun); + + fs::create_dir_all("math/src")?; + + let main = format!(" +#![no_main] +#![no_std] + +#[macro_use] +extern crate qemu_arm_rt as rt; + +use core::u32; + +use rt::{{io, process}}; + +entry!(main); + +fn main() {{ + run().unwrap_or_else(|e| {{ + eprintln!(\"error: {{}}\", e); + process::exit(1); + }}) +}} + +fn run() -> Result<(), usize> {{ + #[link(name = \"m\")] + extern \"C\" {{ + fn {0}(_: f32, _: f32, _: f32) -> f32; + }} + + let mut chunk = [0; 12]; + while let Ok(()) = io::Stdin.read_exact(&mut chunk) {{ + let mut buf = [0; 4]; + buf.copy_from_slice(&chunk[..4]); + let x0 = f32::from_bits(u32::from_bytes(buf)); + + buf.copy_from_slice(&chunk[4..8]); + let x1 = f32::from_bits(u32::from_bytes(buf)); + + buf.copy_from_slice(&chunk[8..]); + let x2 = f32::from_bits(u32::from_bytes(buf)); + + let y = unsafe {{ {0}(x0, x1, x2) }}; + + io::Stdout.write_all(&y.to_bits().to_bytes())?; + }} + + Ok(()) +}} + +#[no_mangle] +pub fn __errno() -> *mut i32 {{ + static mut ERRNO: i32 = 0; + unsafe {{ &mut ERRNO }} +}} +", fun); + + File::create("math/src/main.rs")?.write_all(main.as_bytes())?; + + assert!( + Command::new("cross") + .args(&["build", "--target", "thumbv7em-none-eabi", "--release"]) + .current_dir("math") + .status()? + .success() + ); + + let mut qemu = Command::new("qemu-arm") + .arg("math/target/thumbv7em-none-eabi/release/math") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn()?; + + qemu.stdin.as_mut().take().unwrap().write_all(F32)?; + + let output = qemu.wait_with_output()?; + + File::create(concat!("bin/output/newlib.", stringify!($fun)))? + .write_all(&output.stdout)?; + )+ + } +} diff --git a/library/compiler-builtins/libm/newlib-generator/src/main.rs b/library/compiler-builtins/libm/newlib-generator/src/main.rs new file mode 100644 index 0000000000000..52a97cabbfd4e --- /dev/null +++ b/library/compiler-builtins/libm/newlib-generator/src/main.rs @@ -0,0 +1,32 @@ +extern crate shared; + +use std::error::Error; +use std::fs::{self, File}; +use std::io::Write; +use std::process::{Command, Stdio}; + +#[macro_use] +mod macros; + +fn main() -> Result<(), Box> { + const F32: &[u8] = include_bytes!("../../bin/input/f32"); + + f32! { + asinf, + cbrtf, + cosf, + exp2f, + sinf, + tanf, + } + + f32f32! { + hypotf, + } + + f32f32f32! { + fmaf, + } + + Ok(()) +} diff --git a/library/compiler-builtins/libm/shared/Cargo.toml b/library/compiler-builtins/libm/shared/Cargo.toml new file mode 100644 index 0000000000000..d77823781016d --- /dev/null +++ b/library/compiler-builtins/libm/shared/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "shared" +version = "0.1.0" +authors = ["Jorge Aparicio "] + +[dependencies] +lazy_static = "1.0.2" diff --git a/library/compiler-builtins/libm/shared/src/lib.rs b/library/compiler-builtins/libm/shared/src/lib.rs new file mode 100644 index 0000000000000..84676f94f747d --- /dev/null +++ b/library/compiler-builtins/libm/shared/src/lib.rs @@ -0,0 +1,471 @@ +#![feature(exact_chunks)] + +#[macro_use] +extern crate lazy_static; + +lazy_static! { + pub static ref F32: Vec = { + let bytes = include_bytes!("../../bin/input/f32"); + + bytes + .exact_chunks(4) + .map(|chunk| { + let mut buf = [0; 4]; + buf.copy_from_slice(chunk); + f32::from_bits(u32::from_le(u32::from_bytes(buf))) + }) + .collect() + }; + pub static ref F32F32: Vec<(f32, f32)> = { + let bytes = include_bytes!("../../bin/input/f32f32"); + + bytes + .exact_chunks(8) + .map(|chunk| { + let mut x0 = [0; 4]; + let mut x1 = [0; 4]; + x0.copy_from_slice(&chunk[..4]); + x1.copy_from_slice(&chunk[4..]); + + ( + f32::from_bits(u32::from_le(u32::from_bytes(x0))), + f32::from_bits(u32::from_le(u32::from_bytes(x1))), + ) + }) + .collect() + }; + pub static ref F32F32F32: Vec<(f32, f32, f32)> = { + let bytes = include_bytes!("../../bin/input/f32f32f32"); + + bytes + .exact_chunks(12) + .map(|chunk| { + let mut x0 = [0; 4]; + let mut x1 = [0; 4]; + let mut x2 = [0; 4]; + x0.copy_from_slice(&chunk[..4]); + x1.copy_from_slice(&chunk[4..8]); + x2.copy_from_slice(&chunk[8..]); + + ( + f32::from_bits(u32::from_le(u32::from_bytes(x0))), + f32::from_bits(u32::from_le(u32::from_bytes(x1))), + f32::from_bits(u32::from_le(u32::from_bytes(x2))), + ) + }) + .collect() + }; + pub static ref F32I32: Vec<(f32, i32)> = { + let bytes = include_bytes!("../../bin/input/f32i16"); + + bytes + .exact_chunks(6) + .map(|chunk| { + let mut x0 = [0; 4]; + let mut x1 = [0; 2]; + x0.copy_from_slice(&chunk[..4]); + x1.copy_from_slice(&chunk[4..]); + + ( + f32::from_bits(u32::from_le(u32::from_bytes(x0))), + i16::from_le(i16::from_bytes(x1)) as i32, + ) + }) + .collect() + }; + pub static ref F64: Vec = { + let bytes = include_bytes!("../../bin/input/f64"); + + bytes + .exact_chunks(8) + .map(|chunk| { + let mut buf = [0; 8]; + buf.copy_from_slice(chunk); + f64::from_bits(u64::from_le(u64::from_bytes(buf))) + }) + .collect() + }; + pub static ref F64F64: Vec<(f64, f64)> = { + let bytes = include_bytes!("../../bin/input/f64f64"); + + bytes + .exact_chunks(16) + .map(|chunk| { + let mut x0 = [0; 8]; + let mut x1 = [0; 8]; + x0.copy_from_slice(&chunk[..8]); + x1.copy_from_slice(&chunk[8..]); + + ( + f64::from_bits(u64::from_le(u64::from_bytes(x0))), + f64::from_bits(u64::from_le(u64::from_bytes(x1))), + ) + }) + .collect() + }; + pub static ref F64F64F64: Vec<(f64, f64, f64)> = { + let bytes = include_bytes!("../../bin/input/f64f64f64"); + + bytes + .exact_chunks(24) + .map(|chunk| { + let mut x0 = [0; 8]; + let mut x1 = [0; 8]; + let mut x2 = [0; 8]; + x0.copy_from_slice(&chunk[..8]); + x1.copy_from_slice(&chunk[8..16]); + x2.copy_from_slice(&chunk[16..]); + + ( + f64::from_bits(u64::from_le(u64::from_bytes(x0))), + f64::from_bits(u64::from_le(u64::from_bytes(x1))), + f64::from_bits(u64::from_le(u64::from_bytes(x2))), + ) + }) + .collect() + }; + pub static ref F64I32: Vec<(f64, i32)> = { + let bytes = include_bytes!("../../bin/input/f64i16"); + + bytes + .exact_chunks(10) + .map(|chunk| { + let mut x0 = [0; 8]; + let mut x1 = [0; 2]; + x0.copy_from_slice(&chunk[..8]); + x1.copy_from_slice(&chunk[8..]); + + ( + f64::from_bits(u64::from_le(u64::from_bytes(x0))), + i16::from_le(i16::from_bytes(x1)) as i32, + ) + }) + .collect() + }; +} + +#[macro_export] +macro_rules! f32 { + ($lib:expr, $($fun:ident),+) => { + $( + #[test] + fn $fun() { + let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) + .exact_chunks(4) + .map(|chunk| { + let mut buf = [0; 4]; + buf.copy_from_slice(chunk); + f32::from_bits(u32::from_le(u32::from_bytes(buf))) + }) + .collect::>(); + + for (input, expected) in $crate::F32.iter().zip(&expected) { + if let Ok(output) = panic::catch_unwind(|| libm::$fun(*input)) { + if let Err(error) = libm::_eqf(output, *expected) { + panic!( + "INPUT: {:#x}, OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", + input.to_bits(), + output.to_bits(), + expected.to_bits(), + error + ); + } + } else { + panic!( + "INPUT: {:#x}, OUTPUT: PANIC!, EXPECTED: {:#x}", + input.to_bits(), + expected.to_bits() + ); + } + } + } + )+ + } +} + +#[macro_export] +macro_rules! f32f32 { + ($lib:expr, $($fun:ident),+) => { + $( + #[test] + fn $fun() { + let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) + .exact_chunks(4) + .map(|chunk| { + let mut buf = [0; 4]; + buf.copy_from_slice(chunk); + f32::from_bits(u32::from_le(u32::from_bytes(buf))) + }) + .collect::>(); + + for ((i0, i1), expected) in $crate::F32F32.iter().zip(&expected) { + if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) { + if let Err(error) = libm::_eqf(output, *expected) { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", + i0.to_bits(), + i1.to_bits(), + output.to_bits(), + expected.to_bits(), + error + ); + } + } else { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", + i0.to_bits(), + i1.to_bits(), + expected.to_bits() + ); + } + } + } + )+ + } +} + +#[macro_export] +macro_rules! f32f32f32 { + ($lib:expr, $($fun:ident),+) => { + $( + #[test] + fn $fun() { + let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) + .exact_chunks(4) + .map(|chunk| { + let mut buf = [0; 4]; + buf.copy_from_slice(chunk); + f32::from_bits(u32::from_le(u32::from_bytes(buf))) + }) + .collect::>(); + + for ((i0, i1, i2), expected) in $crate::F32F32F32.iter().zip(&expected) { + if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1, *i2)) { + if let Err(error) = libm::_eqf(output, *expected) { + panic!( + "INPUT: ({:#x}, {:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", + i0.to_bits(), + i1.to_bits(), + i2.to_bits(), + output.to_bits(), + expected.to_bits(), + error + ); + } + } else { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", + i0.to_bits(), + i1.to_bits(), + expected.to_bits() + ); + } + } + } + )+ + } +} + +#[macro_export] +macro_rules! f32i32 { + ($lib:expr, $($fun:ident),+) => { + $( + #[test] + fn $fun() { + let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) + .exact_chunks(4) + .map(|chunk| { + let mut buf = [0; 4]; + buf.copy_from_slice(chunk); + f32::from_bits(u32::from_le(u32::from_bytes(buf))) + }) + .collect::>(); + + for ((i0, i1), expected) in $crate::F32I32.iter().zip(&expected) { + if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) { + if let Err(error) = libm::_eqf(output, *expected) { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", + i0.to_bits(), + i1, + output.to_bits(), + expected.to_bits(), + error + ); + } + } else { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", + i0.to_bits(), + i1, + expected.to_bits() + ); + } + } + } + )+ + } +} + +#[macro_export] +macro_rules! f64 { + ($lib:expr, $($fun:ident),+) => { + $( + #[test] + fn $fun() { + let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) + .exact_chunks(8) + .map(|chunk| { + let mut buf = [0; 8]; + buf.copy_from_slice(chunk); + f64::from_bits(u64::from_le(u64::from_bytes(buf))) + }) + .collect::>(); + + for (input, expected) in shared::F64.iter().zip(&expected) { + if let Ok(output) = panic::catch_unwind(|| libm::$fun(*input)) { + if let Err(error) = libm::_eq(output, *expected) { + panic!( + "INPUT: {:#x}, OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", + input.to_bits(), + output.to_bits(), + expected.to_bits(), + error + ); + } + } else { + panic!( + "INPUT: {:#x}, OUTPUT: PANIC!, EXPECTED: {:#x}", + input.to_bits(), + expected.to_bits() + ); + } + } + } + )+ + } +} + +#[macro_export] +macro_rules! f64f64 { + ($lib:expr, $($fun:ident),+) => { + $( + #[test] + fn $fun() { + let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) + .exact_chunks(8) + .map(|chunk| { + let mut buf = [0; 8]; + buf.copy_from_slice(chunk); + f64::from_bits(u64::from_le(u64::from_bytes(buf))) + }) + .collect::>(); + + for ((i0, i1), expected) in shared::F64F64.iter().zip(&expected) { + if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) { + if let Err(error) = libm::_eq(output, *expected) { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", + i0.to_bits(), + i1.to_bits(), + output.to_bits(), + expected.to_bits(), + error + ); + } + } else { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", + i0.to_bits(), + i1.to_bits(), + expected.to_bits() + ); + } + } + } + )+ + } +} + +#[macro_export] +macro_rules! f64f64f64 { + ($lib:expr, $($fun:ident),+) => { + $( + #[test] + fn $fun() { + let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) + .exact_chunks(8) + .map(|chunk| { + let mut buf = [0; 8]; + buf.copy_from_slice(chunk); + f64::from_bits(u64::from_le(u64::from_bytes(buf))) + }) + .collect::>(); + + for ((i0, i1, i2), expected) in shared::F64F64F64.iter().zip(&expected) { + if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1, *i2)) { + if let Err(error) = libm::_eq(output, *expected) { + panic!( + "INPUT: ({:#x}, {:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", + i0.to_bits(), + i1.to_bits(), + i2.to_bits(), + output.to_bits(), + expected.to_bits(), + error + ); + } + } else { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", + i0.to_bits(), + i1.to_bits(), + expected.to_bits() + ); + } + } + } + )+ + } +} + +#[macro_export] +macro_rules! f64i32 { + ($lib:expr, $($fun:ident),+) => { + $( + #[test] + fn $fun() { + let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) + .exact_chunks(8) + .map(|chunk| { + let mut buf = [0; 8]; + buf.copy_from_slice(chunk); + f64::from_bits(u64::from_le(u64::from_bytes(buf))) + }) + .collect::>(); + + for ((i0, i1), expected) in shared::F64I32.iter().zip(&expected) { + if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) { + if let Err(error) = libm::_eq(output, *expected) { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", + i0.to_bits(), + i1, + output.to_bits(), + expected.to_bits(), + error + ); + } + } else { + panic!( + "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", + i0.to_bits(), + i1, + expected.to_bits() + ); + } + } + } + )+ + } +} diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 5121cbfbacf35..627c6443e3dca 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -21,14 +21,34 @@ pub use math::*; /// Approximate equality with 1 ULP of tolerance #[doc(hidden)] #[inline] -pub fn _eqf(a: u32, b: u32) -> bool { - (a as i32).wrapping_sub(b as i32).abs() <= 1 +pub fn _eqf(a: f32, b: f32) -> Result<(), u32> { + if a.is_nan() && b.is_nan() { + Ok(()) + } else { + let err = (a.to_bits() as i32).wrapping_sub(b.to_bits() as i32).abs(); + + if err <= 1 { + Ok(()) + } else { + Err(err as u32) + } + } } #[doc(hidden)] #[inline] -pub fn _eq(a: u64, b: u64) -> bool { - (a as i64).wrapping_sub(b as i64).abs() <= 1 +pub fn _eq(a: f64, b: f64) -> Result<(), u64> { + if a.is_nan() && b.is_nan() { + Ok(()) + } else { + let err = (a.to_bits() as i64).wrapping_sub(b.to_bits() as i64).abs(); + + if err <= 1 { + Ok(()) + } else { + Err(err as u64) + } + } } /// Math support for `f32` diff --git a/library/compiler-builtins/libm/test-generator/README.md b/library/compiler-builtins/libm/test-generator/README.md deleted file mode 100644 index cbacd88f14d2a..0000000000000 --- a/library/compiler-builtins/libm/test-generator/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# `test-generator` - -This is a tool to generate test cases for the `libm` crate. - -The generator randomly creates inputs for each math function, then proceeds to compute the -expected output for the given function by running the MUSL *C implementation* of the function and -finally it packs the test cases as a Cargo test file. For this reason, this generator **must** -always be compiled for the `x86_64-unknown-linux-musl` target. diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs deleted file mode 100644 index 4c4e420a28528..0000000000000 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ /dev/null @@ -1,788 +0,0 @@ -// NOTE we intentionally avoid using the `quote` crate here because it doesn't work with the -// `x86_64-unknown-linux-musl` target. - -// NOTE usually the only thing you need to do to test a new math function is to add it to one of the -// macro invocations found in the bottom of this file. - -#[macro_use] -extern crate itertools; -extern crate rand; - -use std::error::Error; -use std::fmt::Write as _0; -use std::fs::{self, File}; -use std::io::Write as _1; -use std::{f32, f64, i16, u16, u32, u64, u8}; - -use rand::{Rng, SeedableRng, XorShiftRng}; - -// Number of test cases to generate -const NTESTS: usize = 10_000; - -// TODO tweak these functions to generate edge cases (zero, infinity, NaN) more often -fn f32(rng: &mut XorShiftRng) -> f32 { - let sign = if rng.gen_bool(0.5) { 1 << 31 } else { 0 }; - let exponent = (rng.gen_range(0, u8::MAX) as u32) << 23; - let mantissa = rng.gen_range(0, u32::MAX) & ((1 << 23) - 1); - - f32::from_bits(sign + exponent + mantissa) -} - -fn f64(rng: &mut XorShiftRng) -> f64 { - let sign = if rng.gen_bool(0.5) { 1 << 63 } else { 0 }; - let exponent = (rng.gen_range(0, u16::MAX) as u64 & ((1 << 11) - 1)) << 52; - let mantissa = rng.gen_range(0, u64::MAX) & ((1 << 52) - 1); - - f64::from_bits(sign + exponent + mantissa) -} - -const EDGE_CASES32: &[f32] = &[ - -0., - 0., - f32::EPSILON, - f32::INFINITY, - f32::MAX, - f32::MIN, - f32::MIN_POSITIVE, - f32::NAN, - f32::NEG_INFINITY, -]; - -const EDGE_CASES64: &[f64] = &[ - -0., - 0., - f64::EPSILON, - f64::INFINITY, - f64::MAX, - f64::MIN, - f64::MIN_POSITIVE, - f64::NAN, - f64::NEG_INFINITY, -]; - -// fn(f32) -> f32 -macro_rules! f32_f32 { - ($($intr:ident,)*) => { - fn f32_f32(rng: &mut XorShiftRng) -> Result<(), Box> { - // MUSL C implementation of the function to test - extern "C" { - $(fn $intr(_: f32) -> f32;)* - } - - $( - let mut cases = String::new(); - - // random inputs - for inp in EDGE_CASES32.iter().cloned().chain((0..NTESTS).map(|_| f32(rng))) { - let out = unsafe { $intr(inp) }; - - let inp = inp.to_bits(); - let out = out.to_bits(); - - write!(cases, "({}, {})", inp, out).unwrap(); - cases.push(','); - } - - let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; - write!(f, " - #![deny(warnings)] - - extern crate libm; - - use std::panic; - - #[test] - fn {0}() {{ - const CASES: &[(u32, u32)] = &[ - {1} - ]; - - for case in CASES {{ - let (inp, expected) = *case; - - if let Ok(outf) = - panic::catch_unwind(|| libm::{0}(f32::from_bits(inp))) - {{ - let outi = outf.to_bits(); - - if !((outf.is_nan() && f32::from_bits(expected).is_nan()) - || libm::_eqf(outi, expected)) - {{ - panic!( - \"input: {{}}, output: {{}}, expected: {{}}\", - inp, outi, expected, - ); - }} - }} else {{ - panic!( - \"input: {{}}, output: PANIC, expected: {{}}\", - inp, expected, - ); - }} - }} - }} -", - stringify!($intr), - cases)?; - )* - - Ok(()) - } - } -} - -// fn(f32, f32) -> f32 -macro_rules! f32f32_f32 { - ($($intr:ident,)*) => { - fn f32f32_f32(rng: &mut XorShiftRng) -> Result<(), Box> { - extern "C" { - $(fn $intr(_: f32, _: f32) -> f32;)* - } - - let mut rng2 = rng.clone(); - let mut rng3 = rng.clone(); - $( - let mut cases = String::new(); - for (i1, i2) in iproduct!( - EDGE_CASES32.iter().cloned(), - EDGE_CASES32.iter().cloned() - ).chain(EDGE_CASES32.iter().map(|i1| (*i1, f32(rng)))) - .chain(EDGE_CASES32.iter().map(|i2| (f32(&mut rng2), *i2))) - .chain((0..NTESTS).map(|_| (f32(&mut rng3), f32(&mut rng3)))) - { - let out = unsafe { $intr(i1, i2) }; - - let i1 = i1.to_bits(); - let i2 = i2.to_bits(); - let out = out.to_bits(); - - write!(cases, "(({}, {}), {})", i1, i2, out).unwrap(); - cases.push(','); - } - - let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; - write!(f, " - #![deny(warnings)] - - extern crate libm; - - use std::panic; - - #[test] - fn {0}() {{ - const CASES: &[((u32, u32), u32)] = &[ - {1} - ]; - - for case in CASES {{ - let ((i1, i2), expected) = *case; - - if let Ok(outf) = panic::catch_unwind(|| {{ - libm::{0}(f32::from_bits(i1), f32::from_bits(i2)) - }}) {{ - let outi = outf.to_bits(); - - if !((outf.is_nan() && f32::from_bits(expected).is_nan()) - || libm::_eqf(outi, expected)) - {{ - panic!( - \"input: {{:?}}, output: {{}}, expected: {{}}\", - (i1, i2), - outi, - expected, - ); - }} - }} else {{ - panic!( - \"input: {{:?}}, output: PANIC, expected: {{}}\", - (i1, i2), - expected, - ); - }} - }} - }} -", - stringify!($intr), - cases)?; - )* - - Ok(()) - } - }; -} - -// fn(f32, f32, f32) -> f32 -macro_rules! f32f32f32_f32 { - ($($intr:ident,)*) => { - fn f32f32f32_f32(rng: &mut XorShiftRng) -> Result<(), Box> { - extern "C" { - $(fn $intr(_: f32, _: f32, _: f32) -> f32;)* - } - - let mut rng2 = rng.clone(); - $( - let mut cases = String::new(); - for (i1, i2, i3) in iproduct!( - EDGE_CASES32.iter().cloned(), - EDGE_CASES32.iter().cloned(), - EDGE_CASES32.iter().cloned() - ).chain(EDGE_CASES32.iter().map(|i1| (*i1, f32(rng), f32(rng)))) - .chain((0..NTESTS).map(|_| (f32(&mut rng2), f32(&mut rng2), f32(&mut rng2)))) - { - let out = unsafe { $intr(i1, i2, i3) }; - - let i1 = i1.to_bits(); - let i2 = i2.to_bits(); - let i3 = i3.to_bits(); - let out = out.to_bits(); - - write!(cases, "(({}, {}, {}), {})", i1, i2, i3, out).unwrap(); - cases.push(','); - } - - let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; - write!(f, " - #![deny(warnings)] - - extern crate libm; - - use std::panic; - - #[test] - fn {0}() {{ - const CASES: &[((u32, u32, u32), u32)] = &[ - {1} - ]; - - for case in CASES {{ - let ((i1, i2, i3), expected) = *case; - - if let Ok(outf) = panic::catch_unwind(|| {{ - libm::{0}( - f32::from_bits(i1), - f32::from_bits(i2), - f32::from_bits(i3), - ) - }}) {{ - let outi = outf.to_bits(); - - if !((outf.is_nan() && f32::from_bits(expected).is_nan()) - || libm::_eqf(outi, expected)) - {{ - panic!( - \"input: {{:?}}, output: {{}}, expected: {{}}\", - (i1, i2, i3), - outi, - expected, - ); - }} - }} else {{ - panic!( - \"input: {{:?}}, output: PANIC, expected: {{}}\", - (i1, i2, i3), - expected, - ); - }} - }} - }} -", - stringify!($intr), - cases)?; - )* - - Ok(()) - } - }; -} - -// fn(f32, i32) -> f32 -macro_rules! f32i32_f32 { - ($($intr:ident,)*) => { - fn f32i32_f32(rng: &mut XorShiftRng) -> Result<(), Box> { - extern "C" { - $(fn $intr(_: f32, _: i32) -> f32;)* - } - - let mut rng2 = rng.clone(); - $( - let mut cases = String::new(); - for i1 in EDGE_CASES32.iter().cloned().chain((0..NTESTS).map(|_| f32(&mut rng2))) { - let i2 = rng.gen_range(i16::MIN, i16::MAX); - let out = unsafe { $intr(i1, i2 as i32) }; - - let i1 = i1.to_bits(); - let out = out.to_bits(); - - write!(cases, "(({}, {}), {})", i1, i2, out).unwrap(); - cases.push(','); - } - - let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; - write!(f, " - #![deny(warnings)] - - extern crate libm; - - use std::panic; - - #[test] - fn {0}() {{ - const CASES: &[((u32, i16), u32)] = &[ - {1} - ]; - - for case in CASES {{ - let ((i1, i2), expected) = *case; - - if let Ok(outf) = panic::catch_unwind(|| {{ - libm::{0}(f32::from_bits(i1), i2 as i32) - }}) {{ - let outi = outf.to_bits(); - - if !((outf.is_nan() && f32::from_bits(expected).is_nan()) - || libm::_eqf(outi, expected)) - {{ - panic!( - \"input: {{:?}}, output: {{}}, expected: {{}}\", - (i1, i2), - outi, - expected, - ); - }} - }} else {{ - panic!( - \"input: {{:?}}, output: PANIC, expected: {{}}\", - (i1, i2), - expected, - ); - }} - }} - }} -", - stringify!($intr), - cases)?; - )* - - Ok(()) - } - }; -} - -// fn(f64) -> f64 -macro_rules! f64_f64 { - ($($intr:ident,)*) => { - fn f64_f64(rng: &mut XorShiftRng) -> Result<(), Box> { - // MUSL C implementation of the function to test - extern "C" { - $(fn $intr(_: f64) -> f64;)* - } - - $( - let mut cases = String::new(); - for inp in EDGE_CASES64.iter().cloned().chain((0..NTESTS).map(|_| f64(rng))) { - let out = unsafe { $intr(inp) }; - - let inp = inp.to_bits(); - let out = out.to_bits(); - - write!(cases, "({}, {})", inp, out).unwrap(); - cases.push(','); - } - - let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; - write!(f, " - #![deny(warnings)] - - extern crate libm; - - use std::panic; - - #[test] - fn {0}() {{ - const CASES: &[(u64, u64)] = &[ - {1} - ]; - - for case in CASES {{ - let (inp, expected) = *case; - - if let Ok(outf) = panic::catch_unwind(|| {{ - libm::{0}(f64::from_bits(inp)) - }}) {{ - let outi = outf.to_bits(); - - if !((outf.is_nan() && f64::from_bits(expected).is_nan()) - || libm::_eq(outi, expected)) - {{ - panic!( - \"input: {{}}, output: {{}}, expected: {{}}\", - inp, - outi, - expected, - ); - }} - }} else {{ - panic!( - \"input: {{}}, output: PANIC, expected: {{}}\", - inp, - expected, - ); - }} - }} - }} -", - stringify!($intr), - cases)?; - )* - - Ok(()) - } - } -} - -// fn(f64, f64) -> f64 -macro_rules! f64f64_f64 { - ($($intr:ident,)*) => { - fn f64f64_f64(rng: &mut XorShiftRng) -> Result<(), Box> { - extern "C" { - $(fn $intr(_: f64, _: f64) -> f64;)* - } - - let mut rng2 = rng.clone(); - let mut rng3 = rng.clone(); - $( - let mut cases = String::new(); - for (i1, i2) in iproduct!( - EDGE_CASES64.iter().cloned(), - EDGE_CASES64.iter().cloned() - ).chain(EDGE_CASES64.iter().map(|i1| (*i1, f64(rng)))) - .chain(EDGE_CASES64.iter().map(|i2| (f64(&mut rng2), *i2))) - .chain((0..NTESTS).map(|_| (f64(&mut rng3), f64(&mut rng3)))) - { - let out = unsafe { $intr(i1, i2) }; - - let i1 = i1.to_bits(); - let i2 = i2.to_bits(); - let out = out.to_bits(); - - write!(cases, "(({}, {}), {})", i1, i2, out).unwrap(); - cases.push(','); - } - - let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; - write!(f, " - #![deny(warnings)] - - extern crate libm; - - use std::panic; - - #[test] - fn {0}() {{ - const CASES: &[((u64, u64), u64)] = &[ - {1} - ]; - - for case in CASES {{ - let ((i1, i2), expected) = *case; - - if let Ok(outf) = panic::catch_unwind(|| {{ - libm::{0}(f64::from_bits(i1), f64::from_bits(i2)) - }}) {{ - let outi = outf.to_bits(); - - if !((outf.is_nan() && f64::from_bits(expected).is_nan()) || - libm::_eq(outi, expected)) {{ - panic!( - \"input: {{:?}}, output: {{}}, expected: {{}}\", - (i1, i2), - outi, - expected, - ); - }} - }} else {{ - panic!( - \"input: {{:?}}, output: PANIC, expected: {{}}\", - (i1, i2), - expected, - ); - }} - }} - }} -", - stringify!($intr), - cases)?; - )* - - Ok(()) - } - }; -} - -// fn(f64, f64, f64) -> f64 -macro_rules! f64f64f64_f64 { - ($($intr:ident,)*) => { - fn f64f64f64_f64(rng: &mut XorShiftRng) -> Result<(), Box> { - extern "C" { - $(fn $intr(_: f64, _: f64, _: f64) -> f64;)* - } - - let mut rng2 = rng.clone(); - $( - let mut cases = String::new(); - for (i1, i2, i3) in iproduct!( - EDGE_CASES64.iter().cloned(), - EDGE_CASES64.iter().cloned(), - EDGE_CASES64.iter().cloned() - ).chain(EDGE_CASES64.iter().map(|i1| (*i1, f64(rng), f64(rng)))) - .chain((0..NTESTS).map(|_| (f64(&mut rng2), f64(&mut rng2), f64(&mut rng2)))) - { - let out = unsafe { $intr(i1, i2, i3) }; - - let i1 = i1.to_bits(); - let i2 = i2.to_bits(); - let i3 = i3.to_bits(); - let out = out.to_bits(); - - write!(cases, "(({}, {}, {}), {})", i1, i2, i3, out).unwrap(); - cases.push(','); - } - - let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; - write!(f, " - #![deny(warnings)] - - extern crate libm; - - use std::panic; - - #[test] - fn {0}() {{ - const CASES: &[((u64, u64, u64), u64)] = &[ - {1} - ]; - - for case in CASES {{ - let ((i1, i2, i3), expected) = *case; - - if let Ok(outf) = panic::catch_unwind(|| {{ - libm::{0}( - f64::from_bits(i1), - f64::from_bits(i2), - f64::from_bits(i3), - ) - }}) {{ - let outi = outf.to_bits(); - - if !((outf.is_nan() && f64::from_bits(expected).is_nan()) - || libm::_eq(outi, expected)) - {{ - panic!( - \"input: {{:?}}, output: {{}}, expected: {{}}\", - (i1, i2, i3), - outi, - expected, - ); - }} - }} else {{ - panic!( - \"input: {{:?}}, output: PANIC, expected: {{}}\", - (i1, i2, i3), - expected, - ); - }} - }} - }} -", - stringify!($intr), - cases)?; - )* - - Ok(()) - } - }; -} - -// fn(f64, i32) -> f64 -macro_rules! f64i32_f64 { - ($($intr:ident,)*) => { - fn f64i32_f64(rng: &mut XorShiftRng) -> Result<(), Box> { - extern "C" { - $(fn $intr(_: f64, _: i32) -> f64;)* - } - - let mut rng2 = rng.clone(); - $( - let mut cases = String::new(); - for i1 in EDGE_CASES64.iter().cloned().chain((0..NTESTS).map(|_| f64(&mut rng2))) { - let i2 = rng.gen_range(i16::MIN, i16::MAX); - let out = unsafe { $intr(i1, i2 as i32) }; - - let i1 = i1.to_bits(); - let out = out.to_bits(); - - write!(cases, "(({}, {}), {})", i1, i2, out).unwrap(); - cases.push(','); - } - - let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?; - write!(f, " - #![deny(warnings)] - - extern crate libm; - - use std::panic; - - #[test] - fn {0}() {{ - const CASES: &[((u64, i16), u64)] = &[ - {1} - ]; - - for case in CASES {{ - let ((i1, i2), expected) = *case; - - if let Ok(outf) = panic::catch_unwind(|| {{ - libm::{0}(f64::from_bits(i1), i2 as i32) - }}) {{ - let outi = outf.to_bits(); - - if !((outf.is_nan() && f64::from_bits(expected).is_nan()) || - libm::_eq(outi, expected)) {{ - panic!( - \"input: {{:?}}, output: {{}}, expected: {{}}\", - (i1, i2), - outi, - expected, - ); - }} - }} else {{ - panic!( - \"input: {{:?}}, output: PANIC, expected: {{}}\", - (i1, i2), - expected, - ); - }} - }} - }} -", - stringify!($intr), - cases)?; - )* - - Ok(()) - } - }; -} - -fn main() -> Result<(), Box> { - fs::remove_dir_all("tests").ok(); - fs::create_dir("tests")?; - - let mut rng = XorShiftRng::from_rng(&mut rand::thread_rng())?; - - f32_f32(&mut rng)?; - f32f32_f32(&mut rng)?; - f32f32f32_f32(&mut rng)?; - f32i32_f32(&mut rng)?; - f64_f64(&mut rng)?; - f64f64_f64(&mut rng)?; - f64f64f64_f64(&mut rng)?; - f64i32_f64(&mut rng)?; - - Ok(()) -} - -/* Functions to test */ - -// With signature `fn(f32) -> f32` -f32_f32! { - acosf, - floorf, - truncf, - asinf, - atanf, - cbrtf, - cosf, - ceilf, - coshf, - exp2f, - expf, - expm1f, - log10f, - log1pf, - log2f, - logf, - roundf, - sinf, - sinhf, - tanf, - tanhf, - fabsf, - sqrtf, -} - -// With signature `fn(f32, f32) -> f32` -f32f32_f32! { - atan2f, - fdimf, - hypotf, - fmodf, - powf, -} - -// With signature `fn(f32, f32, f32) -> f32` -f32f32f32_f32! { - fmaf, -} - -// With signature `fn(f32, i32) -> f32` -f32i32_f32! { - scalbnf, -} - -// With signature `fn(f64) -> f64` -f64_f64! { - acos, - asin, - atan, - cbrt, - ceil, - cos, - cosh, - exp, - exp2, - expm1, - floor, - log, - log10, - log1p, - log2, - round, - sin, - sinh, - sqrt, - tan, - tanh, - trunc, - fabs, -} - -// With signature `fn(f64, f64) -> f64` -f64f64_f64! { - atan2, - fdim, - fmod, - hypot, - pow, -} - -// With signature `fn(f64, f64, f64) -> f64` -f64f64f64_f64! { - fma, -} - -// With signature `fn(f64, i32) -> f64` -f64i32_f64! { - scalbn, -} From 99da9ff292e475172c42d5cea073354af47972fa Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 27 Jul 2018 00:21:54 -0500 Subject: [PATCH 0594/4206] make qemu-arm executable --- library/compiler-builtins/libm/ci/install.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/libm/ci/install.sh b/library/compiler-builtins/libm/ci/install.sh index 7f73c5feaf369..af26e2d4c30e4 100644 --- a/library/compiler-builtins/libm/ci/install.sh +++ b/library/compiler-builtins/libm/ci/install.sh @@ -18,6 +18,8 @@ main() { mkdir -p ~/.local/bin curl -L https://github.com/japaric/qemu-bin/raw/master/14.04/qemu-arm-2.12.0 > ~/.local/bin/qemu-arm + chmod +x ~/.local/bin/qemu-arm + qemu-arm --version } main From 28b3fff3c5ec7aafe467ce2b0e34d1678f8fdc5a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 27 Jul 2018 00:27:25 -0500 Subject: [PATCH 0595/4206] uncomment the other build jobs --- library/compiler-builtins/libm/.travis.yml | 40 +++++++++++----------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/library/compiler-builtins/libm/.travis.yml b/library/compiler-builtins/libm/.travis.yml index b3beecb092049..47f2b2f205df6 100644 --- a/library/compiler-builtins/libm/.travis.yml +++ b/library/compiler-builtins/libm/.travis.yml @@ -6,28 +6,28 @@ matrix: include: - env: TARGET=aarch64-unknown-linux-gnu rust: nightly - # - env: TARGET=armv7-unknown-linux-gnueabihf - # rust: nightly - # - env: TARGET=i686-unknown-linux-gnu - # rust: nightly - # - env: TARGET=mips-unknown-linux-gnu - # rust: nightly - # - env: TARGET=mips64-unknown-linux-gnuabi64 - # rust: nightly - # - env: TARGET=mips64el-unknown-linux-gnuabi64 - # rust: nightly - # - env: TARGET=mipsel-unknown-linux-gnu - # rust: nightly - # - env: TARGET=powerpc-unknown-linux-gnu - # rust: nightly - # - env: TARGET=powerpc64-unknown-linux-gnu - # rust: nightly - # - env: TARGET=powerpc64le-unknown-linux-gnu - # rust: nightly + - env: TARGET=armv7-unknown-linux-gnueabihf + rust: nightly + - env: TARGET=i686-unknown-linux-gnu + rust: nightly + - env: TARGET=mips-unknown-linux-gnu + rust: nightly + - env: TARGET=mips64-unknown-linux-gnuabi64 + rust: nightly + - env: TARGET=mips64el-unknown-linux-gnuabi64 + rust: nightly + - env: TARGET=mipsel-unknown-linux-gnu + rust: nightly + - env: TARGET=powerpc-unknown-linux-gnu + rust: nightly + - env: TARGET=powerpc64-unknown-linux-gnu + rust: nightly + - env: TARGET=powerpc64le-unknown-linux-gnu + rust: nightly - env: TARGET=x86_64-unknown-linux-gnu rust: nightly - # - env: TARGET=cargo-fmt - # rust: beta + - env: TARGET=cargo-fmt + rust: beta before_install: set -e From 527eefef9c11396cff6bc9cb0b939c053ebf8b95 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 27 Jul 2018 00:38:56 -0500 Subject: [PATCH 0596/4206] tweak the order of the tests --- library/compiler-builtins/libm/ci/script.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh index 59e5a5f37de95..c3b6faa6cac67 100644 --- a/library/compiler-builtins/libm/ci/script.sh +++ b/library/compiler-builtins/libm/ci/script.sh @@ -6,13 +6,6 @@ main() { return fi - # test that the functions don't contain invocations of `panic!` - case $TARGET in - armv7-unknown-linux-gnueabihf) - cross build --release --target $TARGET --example no-panic - ;; - esac - # quick check cargo check @@ -24,6 +17,13 @@ main() { cargo run -p musl-generator --target x86_64-unknown-linux-musl cargo run -p newlib-generator + # test that the functions don't contain invocations of `panic!` + case $TARGET in + armv7-unknown-linux-gnueabihf) + cross build --release --target $TARGET --example no-panic + ;; + esac + # run unit tests cross test --lib --features checked --target $TARGET --release From 831af41ae4ea718e255b7f857df7a49e4fb2eb06 Mon Sep 17 00:00:00 2001 From: David Craven Date: Thu, 26 Jul 2018 19:30:26 +0200 Subject: [PATCH 0597/4206] Implement __mulsi3. --- library/compiler-builtins/src/lib.rs | 3 +++ library/compiler-builtins/src/riscv32.rs | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 library/compiler-builtins/src/riscv32.rs diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 02b6c7db953ad..9f1dd15120c07 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -58,6 +58,9 @@ pub mod arm; #[cfg(all(kernel_user_helpers, target_os = "linux", target_arch = "arm"))] pub mod arm_linux; +#[cfg(any(target_arch = "riscv32"))] +pub mod riscv32; + #[cfg(target_arch = "x86")] pub mod x86; diff --git a/library/compiler-builtins/src/riscv32.rs b/library/compiler-builtins/src/riscv32.rs new file mode 100644 index 0000000000000..ebaa354a4b30f --- /dev/null +++ b/library/compiler-builtins/src/riscv32.rs @@ -0,0 +1,17 @@ +intrinsics! { + // Implementation from gcc + // https://raw.githubusercontent.com/gcc-mirror/gcc/master/libgcc/config/epiphany/mulsi3.c + pub extern "C" fn __mulsi3(mut a: u32, mut b: u32) -> u32 { + let mut r: usize = 0; + + while a > 0 { + if a & 1 > 0 { + r += b; + } + a >>= 1; + b <<= 1; + } + + r + } +} From b0b04fc04394d0c6b47a688e29f9df717899d3bb Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 Aug 2018 07:07:43 -0700 Subject: [PATCH 0598/4206] Upgrade to LLVM 7 branch point --- library/compiler-builtins/compiler-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-rt b/library/compiler-builtins/compiler-rt index 40151c4c1cf77..8964c7a0c4d1d 160000 --- a/library/compiler-builtins/compiler-rt +++ b/library/compiler-builtins/compiler-rt @@ -1 +1 @@ -Subproject commit 40151c4c1cf77e593e3654e66e25ea423116aaae +Subproject commit 8964c7a0c4d1dc8c45b5adee6fe5ae3db057ab98 From e3ac57b2343b56389d6f6eb8be1767f30b883f03 Mon Sep 17 00:00:00 2001 From: Yu Ding Date: Mon, 6 Aug 2018 20:54:48 -0700 Subject: [PATCH 0599/4206] Fix symbol collision caused by floatdisf [PR #234](https://github.com/rust-lang-nursery/compiler-builtins/pull/234) added floatdisf implementation in rust and removed floatdisf.c from build.rs. However the removal is in-complete. In x86_64+!msvc environment, the symbol floatdisf would be generated twice. Bugs found in Redox OS issue [#1195](https://gitlab.redox-os.org/redox-os/redox/issues/1195) and Mesalink travis [log](https://travis-ci.org/mesalock-linux/mesalink/jobs/412928048) at line 738. This patch fixes it by removing floatdisf.c from this environment. Signed-off-by: Yu Ding --- library/compiler-builtins/build.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index cdcbfe24cd73c..d06c1191f3edc 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -267,7 +267,6 @@ mod c { if target_arch == "x86_64" { sources.extend( &[ - "x86_64/floatdisf.c", "x86_64/floatdixf.c", "x86_64/floatundidf.S", "x86_64/floatundisf.S", From 0e67871a430062619951e72c92b9d2735c3449cc Mon Sep 17 00:00:00 2001 From: Yu Ding Date: Mon, 6 Aug 2018 23:03:37 -0700 Subject: [PATCH 0600/4206] Follow up on PR #252 --- library/compiler-builtins/build.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index d06c1191f3edc..fba4091124a98 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -269,7 +269,6 @@ mod c { &[ "x86_64/floatdixf.c", "x86_64/floatundidf.S", - "x86_64/floatundisf.S", "x86_64/floatundixf.S", ], ); From 2095fdab378c80ba64bd1aeacd01f772743f21f0 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 17 Aug 2018 11:21:08 -0700 Subject: [PATCH 0601/4206] Remove unused features --- library/compiler-builtins/examples/intrinsics.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index c165fcccaff91..7f502bba34b70 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -6,10 +6,8 @@ #![allow(unused_features)] #![cfg_attr(thumb, no_main)] #![deny(dead_code)] -#![feature(alloc_system)] #![feature(asm)] #![feature(compiler_builtins_lib)] -#![feature(core_float)] #![feature(lang_items)] #![feature(start)] #![feature(allocator_api)] From c9b4a8423c388246fb29c49cda44717cb671bdd6 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 18 Aug 2018 12:29:01 +0300 Subject: [PATCH 0602/4206] Fix __sync_fetch_and_nand_* for pre-v6 ARM gcc changed semantics for __sync_fetch_and_nand_* in gcc 4.4, and this was implementing the old semantics: https://gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc/_005f_005fsync-Builtins.html --- library/compiler-builtins/src/arm_linux.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/arm_linux.rs b/library/compiler-builtins/src/arm_linux.rs index 2291edf9f1462..5ed379fa1e253 100644 --- a/library/compiler-builtins/src/arm_linux.rs +++ b/library/compiler-builtins/src/arm_linux.rs @@ -125,9 +125,9 @@ atomic_rmw!(__sync_fetch_and_xor_1, u8, |a: u8, b: u8| a ^ b); atomic_rmw!(__sync_fetch_and_xor_2, u16, |a: u16, b: u16| a ^ b); atomic_rmw!(__sync_fetch_and_xor_4, u32, |a: u32, b: u32| a ^ b); -atomic_rmw!(__sync_fetch_and_nand_1, u8, |a: u8, b: u8| !a & b); -atomic_rmw!(__sync_fetch_and_nand_2, u16, |a: u16, b: u16| !a & b); -atomic_rmw!(__sync_fetch_and_nand_4, u32, |a: u32, b: u32| !a & b); +atomic_rmw!(__sync_fetch_and_nand_1, u8, |a: u8, b: u8| !(a & b)); +atomic_rmw!(__sync_fetch_and_nand_2, u16, |a: u16, b: u16| !(a & b)); +atomic_rmw!(__sync_fetch_and_nand_4, u32, |a: u32, b: u32| !(a & b)); atomic_rmw!(__sync_fetch_and_max_1, i8, |a: i8, b: i8| if a > b { a } else { b }); atomic_rmw!(__sync_fetch_and_max_2, i16, |a: i16, b: i16| if a > b { a } else { b }); From ff82848c8e07b85bb1717bd5f657132dd3cdadfe Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 22 Aug 2018 11:19:18 -0700 Subject: [PATCH 0603/4206] Update LLVM's compiler-rt submodule --- library/compiler-builtins/compiler-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-rt b/library/compiler-builtins/compiler-rt index 8964c7a0c4d1d..7e387f0f90b49 160000 --- a/library/compiler-builtins/compiler-rt +++ b/library/compiler-builtins/compiler-rt @@ -1 +1 @@ -Subproject commit 8964c7a0c4d1dc8c45b5adee6fe5ae3db057ab98 +Subproject commit 7e387f0f90b493ae72930c787c381a80055a7ec9 From 4f1f71a8d623a9189ce979614f7f72d4629c35ec Mon Sep 17 00:00:00 2001 From: Igor null Date: Sun, 26 Aug 2018 16:36:59 +0300 Subject: [PATCH 0604/4206] Ported several remaining math functions from musl Please note that these aren't tested yet. --- .../compiler-builtins/libm/src/math/acosh.rs | 22 + .../compiler-builtins/libm/src/math/acoshf.rs | 21 + .../compiler-builtins/libm/src/math/asinef.rs | 95 +++++ .../compiler-builtins/libm/src/math/asinh.rs | 35 ++ .../compiler-builtins/libm/src/math/asinhf.rs | 34 ++ .../compiler-builtins/libm/src/math/atanh.rs | 33 ++ .../compiler-builtins/libm/src/math/atanhf.rs | 32 ++ .../libm/src/math/copysign.rs | 7 + .../libm/src/math/copysignf.rs | 7 + .../compiler-builtins/libm/src/math/erf.rs | 297 +++++++++++++ .../compiler-builtins/libm/src/math/erff.rs | 210 ++++++++++ .../compiler-builtins/libm/src/math/exp10.rs | 24 ++ .../compiler-builtins/libm/src/math/exp10f.rs | 22 + .../compiler-builtins/libm/src/math/frexp.rs | 20 + .../compiler-builtins/libm/src/math/frexpf.rs | 21 + .../compiler-builtins/libm/src/math/ilogb.rs | 31 ++ .../compiler-builtins/libm/src/math/ilogbf.rs | 31 ++ library/compiler-builtins/libm/src/math/j0.rs | 392 ++++++++++++++++++ .../compiler-builtins/libm/src/math/j0f.rs | 330 +++++++++++++++ library/compiler-builtins/libm/src/math/j1.rs | 387 +++++++++++++++++ .../compiler-builtins/libm/src/math/j1f.rs | 331 +++++++++++++++ library/compiler-builtins/libm/src/math/jn.rs | 338 +++++++++++++++ .../compiler-builtins/libm/src/math/jnf.rs | 255 ++++++++++++ .../compiler-builtins/libm/src/math/lgamma.rs | 309 ++++++++++++++ .../libm/src/math/lgammaf.rs | 244 +++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 74 ++++ .../compiler-builtins/libm/src/math/modf.rs | 33 ++ .../compiler-builtins/libm/src/math/modff.rs | 32 ++ .../compiler-builtins/libm/src/math/remquo.rs | 98 +++++ .../libm/src/math/remquof.rs | 97 +++++ .../compiler-builtins/libm/src/math/sincos.rs | 60 +++ .../libm/src/math/sincosf.rs | 122 ++++++ .../compiler-builtins/libm/src/math/tgamma.rs | 179 ++++++++ .../libm/src/math/tgammaf.rs | 5 + 34 files changed, 4228 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/acosh.rs create mode 100644 library/compiler-builtins/libm/src/math/acoshf.rs create mode 100644 library/compiler-builtins/libm/src/math/asinef.rs create mode 100644 library/compiler-builtins/libm/src/math/asinh.rs create mode 100644 library/compiler-builtins/libm/src/math/asinhf.rs create mode 100644 library/compiler-builtins/libm/src/math/atanh.rs create mode 100644 library/compiler-builtins/libm/src/math/atanhf.rs create mode 100644 library/compiler-builtins/libm/src/math/copysign.rs create mode 100644 library/compiler-builtins/libm/src/math/copysignf.rs create mode 100644 library/compiler-builtins/libm/src/math/erf.rs create mode 100644 library/compiler-builtins/libm/src/math/erff.rs create mode 100644 library/compiler-builtins/libm/src/math/exp10.rs create mode 100644 library/compiler-builtins/libm/src/math/exp10f.rs create mode 100644 library/compiler-builtins/libm/src/math/frexp.rs create mode 100644 library/compiler-builtins/libm/src/math/frexpf.rs create mode 100644 library/compiler-builtins/libm/src/math/ilogb.rs create mode 100644 library/compiler-builtins/libm/src/math/ilogbf.rs create mode 100644 library/compiler-builtins/libm/src/math/j0.rs create mode 100644 library/compiler-builtins/libm/src/math/j0f.rs create mode 100644 library/compiler-builtins/libm/src/math/j1.rs create mode 100644 library/compiler-builtins/libm/src/math/j1f.rs create mode 100644 library/compiler-builtins/libm/src/math/jn.rs create mode 100644 library/compiler-builtins/libm/src/math/jnf.rs create mode 100644 library/compiler-builtins/libm/src/math/lgamma.rs create mode 100644 library/compiler-builtins/libm/src/math/lgammaf.rs create mode 100644 library/compiler-builtins/libm/src/math/modf.rs create mode 100644 library/compiler-builtins/libm/src/math/modff.rs create mode 100644 library/compiler-builtins/libm/src/math/remquo.rs create mode 100644 library/compiler-builtins/libm/src/math/remquof.rs create mode 100644 library/compiler-builtins/libm/src/math/sincos.rs create mode 100644 library/compiler-builtins/libm/src/math/sincosf.rs create mode 100644 library/compiler-builtins/libm/src/math/tgamma.rs create mode 100644 library/compiler-builtins/libm/src/math/tgammaf.rs diff --git a/library/compiler-builtins/libm/src/math/acosh.rs b/library/compiler-builtins/libm/src/math/acosh.rs new file mode 100644 index 0000000000000..3494e3405e762 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/acosh.rs @@ -0,0 +1,22 @@ +use super::{log, log1p, sqrt}; + +const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ + +/* acosh(x) = log(x + sqrt(x*x-1)) */ +pub fn acosh(x: f64) -> f64 { + let u = x.to_bits(); + let e = ((u >> 52) as usize) & 0x7ff; + + /* x < 1 domain error is handled in the called functions */ + + if e < 0x3ff + 1 { + /* |x| < 2, up to 2ulp error in [1,1.125] */ + return log1p(x-1.0+sqrt((x-1.0)*(x-1.0)+2.0*(x-1.0))); + } + if e < 0x3ff + 26 { + /* |x| < 0x1p26 */ + return log(2.0*x-1.0/(x+sqrt(x*x-1.0))); + } + /* |x| >= 0x1p26 or nan */ + return log(x) + LN2; +} diff --git a/library/compiler-builtins/libm/src/math/acoshf.rs b/library/compiler-builtins/libm/src/math/acoshf.rs new file mode 100644 index 0000000000000..1e298a9b3d5d6 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/acoshf.rs @@ -0,0 +1,21 @@ +use super::{log1pf, logf, sqrtf}; + +const LN2: f32 = 0.693147180559945309417232121458176568; + +/* acosh(x) = log(x + sqrt(x*x-1)) */ +pub fn acoshf(x: f32) -> f32 { + let u = x.to_bits(); + let a = u & 0x7fffffff; + + if a < 0x3f800000+(1<<23) { + /* |x| < 2, invalid if x < 1 or nan */ + /* up to 2ulp error in [1,1.125] */ + return log1pf(x-1.0 + sqrtf((x-1.0)*(x-1.0)+2.0*(x-1.0))); + } + if a < 0x3f800000+(12<<23) { + /* |x| < 0x1p12 */ + return logf(2.0*x - 1.0/(x+sqrtf(x*x-1.0))); + } + /* x >= 0x1p12 */ + return logf(x) + LN2; +} diff --git a/library/compiler-builtins/libm/src/math/asinef.rs b/library/compiler-builtins/libm/src/math/asinef.rs new file mode 100644 index 0000000000000..d2cd826999d0c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/asinef.rs @@ -0,0 +1,95 @@ +/* @(#)z_asinef.c 1.0 98/08/13 */ +/****************************************************************** + * The following routines are coded directly from the algorithms + * and coefficients given in "Software Manual for the Elementary + * Functions" by William J. Cody, Jr. and William Waite, Prentice + * Hall, 1980. + ******************************************************************/ +/****************************************************************** + * Arcsine + * + * Input: + * x - floating point value + * acosine - indicates acos calculation + * + * Output: + * Arcsine of x. + * + * Description: + * This routine calculates arcsine / arccosine. + * + *****************************************************************/ + +use super::{fabsf, sqrtf}; + +const P: [f32; 2] = [ 0.933935835, -0.504400557 ]; +const Q: [f32; 2] = [ 0.560363004e+1, -0.554846723e+1 ]; +const A: [f32; 2] = [ 0.0, 0.785398163 ]; +const B: [f32; 2] = [ 1.570796326, 0.785398163 ]; +const Z_ROOTEPS_F: f32 = 1.7263349182589107e-4; + +pub fn asinef(x: f32, acosine: usize) -> f32 +{ + let flag: usize; + let i: usize; + let mut branch: bool = false; + let g: f32; + let mut res: f32 = 0.0; + let mut y: f32; + + /* Check for special values. */ + //i = numtestf (x); + if x.is_nan() || x.is_infinite() { + force_eval!(x); + return x; + } + + y = fabsf(x); + flag = acosine; + + if y > 0.5 { + i = 1 - flag; + + /* Check for range error. */ + if y > 1.0 { + return 0.0 / 0.0; + } + + g = (1.0 - y) / 2.0; + y = -2.0 * sqrtf(g); + branch = true; + } else { + i = flag; + if y < Z_ROOTEPS_F { + res = y; + g = 0.0; // pleasing the uninitialized variable + } else { + g = y * y; + } + } + + if y >= Z_ROOTEPS_F || branch { + /* Calculate the Taylor series. */ + let p = (P[1] * g + P[0]) * g; + let q = (g + Q[1]) * g + Q[0]; + let r = p / q; + + res = y + y * r; + } + + /* Calculate asine or acose. */ + if flag == 0 { + res = (A[i] + res) + A[i]; + if x < 0.0 { + res = -res; + } + } else { + if x < 0.0 { + res = (B[i] + res) + B[i]; + } else { + res = (A[i] - res) + A[i]; + } + } + + return res; +} diff --git a/library/compiler-builtins/libm/src/math/asinh.rs b/library/compiler-builtins/libm/src/math/asinh.rs new file mode 100644 index 0000000000000..09e894551f6c0 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/asinh.rs @@ -0,0 +1,35 @@ +use super::{log, log1p, sqrt}; + +const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +pub fn asinh(mut x: f64) -> f64 { + let mut u = x.to_bits(); + let e = ((u >> 52) as usize) & 0x7ff; + let sign = (u >> 63) != 0; + + /* |x| */ + u &= (!0) >> 1; + x = f64::from_bits(u); + + if e >= 0x3ff + 26 { + /* |x| >= 0x1p26 or inf or nan */ + x = log(x) + LN2; + } else if e >= 0x3ff + 1 { + /* |x| >= 2 */ + x = log(2.0*x + 1.0/(sqrt(x*x+1.0)+x)); + } else if e >= 0x3ff - 26 { + /* |x| >= 0x1p-26, up to 1.6ulp error in [0.125,0.5] */ + x = log1p(x + x*x/(sqrt(x*x+1.0)+1.0)); + } else { + /* |x| < 0x1p-26, raise inexact if x != 0 */ + let x1p120 = f64::from_bits(0x4770000000000000); + force_eval!(x + x1p120); + } + + if sign { + -x + } else { + x + } +} diff --git a/library/compiler-builtins/libm/src/math/asinhf.rs b/library/compiler-builtins/libm/src/math/asinhf.rs new file mode 100644 index 0000000000000..236916d83e872 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/asinhf.rs @@ -0,0 +1,34 @@ +use super::{logf, log1pf, sqrtf}; + +const LN2: f32 = 0.693147180559945309417232121458176568; + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +pub fn asinhf(mut x: f32) -> f32 { + let u = x.to_bits(); + let i = u & 0x7fffffff; + let sign = (u >> 31) != 0; + + /* |x| */ + x = f32::from_bits(i); + + if i >= 0x3f800000 + (12<<23) { + /* |x| >= 0x1p12 or inf or nan */ + x = logf(x) + LN2; + } else if i >= 0x3f800000 + (1<<23) { + /* |x| >= 2 */ + x = logf(2.0*x + 1.0/(sqrtf(x*x+1.0)+x)); + } else if i >= 0x3f800000 - (12<<23) { + /* |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5] */ + x = log1pf(x + x*x/(sqrtf(x*x+1.0)+1.0)); + } else { + /* |x| < 0x1p-12, raise inexact if x!=0 */ + let x1p120 = f32::from_bits(0x7b800000); + force_eval!(x + x1p120); + } + + if sign { + -x + } else { + x + } +} diff --git a/library/compiler-builtins/libm/src/math/atanh.rs b/library/compiler-builtins/libm/src/math/atanh.rs new file mode 100644 index 0000000000000..ea444809c7d17 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/atanh.rs @@ -0,0 +1,33 @@ +use super::{log1p}; + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +pub fn atanh(mut x: f64) -> f64 { + let mut u = x.to_bits(); + let e = ((u >> 52) as usize) & 0x7ff; + let sign = (u >> 63) != 0; + + /* |x| */ + u &= 0x7fffffff; + x = f64::from_bits(u); + + if e < 0x3ff - 1 { + if e < 0x3ff - 32 { + /* handle underflow */ + if e == 0 { + force_eval!(x as f32); + } + } else { + /* |x| < 0.5, up to 1.7ulp error */ + x = 0.5*log1p(2.0*x + 2.0*x*x/(1.0-x)); + } + } else { + /* avoid overflow */ + x = 0.5*log1p(2.0*(x/(1.0-x))); + } + + if sign { + -x + } else { + x + } +} diff --git a/library/compiler-builtins/libm/src/math/atanhf.rs b/library/compiler-builtins/libm/src/math/atanhf.rs new file mode 100644 index 0000000000000..77d451bf27e42 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/atanhf.rs @@ -0,0 +1,32 @@ +use super::{log1pf}; + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +pub fn atanhf(mut x: f32) -> f32 { + let mut u = x.to_bits(); + let sign = (u >> 31) != 0; + + /* |x| */ + u &= 0x7fffffff; + x = f32::from_bits(u); + + if u < 0x3f800000 - (1<<23) { + if u < 0x3f800000 - (32<<23) { + /* handle underflow */ + if u < (1<<23) { + force_eval!((x*x) as f32); + } + } else { + /* |x| < 0.5, up to 1.7ulp error */ + x = 0.5*log1pf(2.0*x + 2.0*x*x/(1.0-x)); + } + } else { + /* avoid overflow */ + x = 0.5*log1pf(2.0*(x/(1.0-x))); + } + + if sign { + -x + } else { + x + } +} diff --git a/library/compiler-builtins/libm/src/math/copysign.rs b/library/compiler-builtins/libm/src/math/copysign.rs new file mode 100644 index 0000000000000..74b761e7468b8 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/copysign.rs @@ -0,0 +1,7 @@ +pub fn copysign(x: f64, y: f64) -> f64 { + let mut ux = x.to_bits(); + let uy = y.to_bits(); + ux &= (!0) >> 1; + ux |= uy & (1<<63); + f64::from_bits(ux) +} diff --git a/library/compiler-builtins/libm/src/math/copysignf.rs b/library/compiler-builtins/libm/src/math/copysignf.rs new file mode 100644 index 0000000000000..a0a814bf6a10f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/copysignf.rs @@ -0,0 +1,7 @@ +pub fn copysignf(x: f32, y: f32) -> f32 { + let mut ux = x.to_bits(); + let uy = y.to_bits(); + ux &= 0x7fffffff; + ux |= uy & 0x80000000; + f32::from_bits(ux) +} diff --git a/library/compiler-builtins/libm/src/math/erf.rs b/library/compiler-builtins/libm/src/math/erf.rs new file mode 100644 index 0000000000000..b3ad2ce058f28 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/erf.rs @@ -0,0 +1,297 @@ +use super::{exp, fabs, get_high_word, with_set_low_word}; +/* origin: FreeBSD /usr/src/lib/msun/src/s_erf.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. + * ==================================================== + */ +/* double erf(double x) + * double erfc(double x) + * x + * 2 |\ + * erf(x) = --------- | exp(-t*t)dt + * sqrt(pi) \| + * 0 + * + * erfc(x) = 1-erf(x) + * Note that + * erf(-x) = -erf(x) + * erfc(-x) = 2 - erfc(x) + * + * Method: + * 1. For |x| in [0, 0.84375] + * erf(x) = x + x*R(x^2) + * erfc(x) = 1 - erf(x) if x in [-.84375,0.25] + * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] + * where R = P/Q where P is an odd poly of degree 8 and + * Q is an odd poly of degree 10. + * -57.90 + * | R - (erf(x)-x)/x | <= 2 + * + * + * Remark. The formula is derived by noting + * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) + * and that + * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 + * is close to one. The interval is chosen because the fix + * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is + * near 0.6174), and by some experiment, 0.84375 is chosen to + * guarantee the error is less than one ulp for erf. + * + * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and + * c = 0.84506291151 rounded to single (24 bits) + * erf(x) = sign(x) * (c + P1(s)/Q1(s)) + * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 + * 1+(c+P1(s)/Q1(s)) if x < 0 + * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06 + * Remark: here we use the taylor series expansion at x=1. + * erf(1+s) = erf(1) + s*Poly(s) + * = 0.845.. + P1(s)/Q1(s) + * That is, we use rational approximation to approximate + * erf(1+s) - (c = (single)0.84506291151) + * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] + * where + * P1(s) = degree 6 poly in s + * Q1(s) = degree 6 poly in s + * + * 3. For x in [1.25,1/0.35(~2.857143)], + * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1) + * erf(x) = 1 - erfc(x) + * where + * R1(z) = degree 7 poly in z, (z=1/x^2) + * S1(z) = degree 8 poly in z + * + * 4. For x in [1/0.35,28] + * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 + * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6 x >= 28 + * erf(x) = sign(x) *(1 - tiny) (raise inexact) + * erfc(x) = tiny*tiny (raise underflow) if x > 0 + * = 2 - tiny if x<0 + * + * 7. Special case: + * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, + * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, + * erfc/erf(NaN) is NaN + */ + +const ERX: f64 = 8.45062911510467529297e-01; /* 0x3FEB0AC1, 0x60000000 */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +const EFX8: f64 = 1.02703333676410069053e+00; /* 0x3FF06EBA, 0x8214DB69 */ +const PP0: f64 = 1.28379167095512558561e-01; /* 0x3FC06EBA, 0x8214DB68 */ +const PP1: f64 = -3.25042107247001499370e-01; /* 0xBFD4CD7D, 0x691CB913 */ +const PP2: f64 = -2.84817495755985104766e-02; /* 0xBF9D2A51, 0xDBD7194F */ +const PP3: f64 = -5.77027029648944159157e-03; /* 0xBF77A291, 0x236668E4 */ +const PP4: f64 = -2.37630166566501626084e-05; /* 0xBEF8EAD6, 0x120016AC */ +const QQ1: f64 = 3.97917223959155352819e-01; /* 0x3FD97779, 0xCDDADC09 */ +const QQ2: f64 = 6.50222499887672944485e-02; /* 0x3FB0A54C, 0x5536CEBA */ +const QQ3: f64 = 5.08130628187576562776e-03; /* 0x3F74D022, 0xC4D36B0F */ +const QQ4: f64 = 1.32494738004321644526e-04; /* 0x3F215DC9, 0x221C1A10 */ +const QQ5: f64 = -3.96022827877536812320e-06; /* 0xBED09C43, 0x42A26120 */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +const PA0: f64 = -2.36211856075265944077e-03; /* 0xBF6359B8, 0xBEF77538 */ +const PA1: f64 = 4.14856118683748331666e-01; /* 0x3FDA8D00, 0xAD92B34D */ +const PA2: f64 = -3.72207876035701323847e-01; /* 0xBFD7D240, 0xFBB8C3F1 */ +const PA3: f64 = 3.18346619901161753674e-01; /* 0x3FD45FCA, 0x805120E4 */ +const PA4: f64 = -1.10894694282396677476e-01; /* 0xBFBC6398, 0x3D3E28EC */ +const PA5: f64 = 3.54783043256182359371e-02; /* 0x3FA22A36, 0x599795EB */ +const PA6: f64 = -2.16637559486879084300e-03; /* 0xBF61BF38, 0x0A96073F */ +const QA1: f64 = 1.06420880400844228286e-01; /* 0x3FBB3E66, 0x18EEE323 */ +const QA2: f64 = 5.40397917702171048937e-01; /* 0x3FE14AF0, 0x92EB6F33 */ +const QA3: f64 = 7.18286544141962662868e-02; /* 0x3FB2635C, 0xD99FE9A7 */ +const QA4: f64 = 1.26171219808761642112e-01; /* 0x3FC02660, 0xE763351F */ +const QA5: f64 = 1.36370839120290507362e-02; /* 0x3F8BEDC2, 0x6B51DD1C */ +const QA6: f64 = 1.19844998467991074170e-02; /* 0x3F888B54, 0x5735151D */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +const RA0: f64 = -9.86494403484714822705e-03; /* 0xBF843412, 0x600D6435 */ +const RA1: f64 = -6.93858572707181764372e-01; /* 0xBFE63416, 0xE4BA7360 */ +const RA2: f64 = -1.05586262253232909814e+01; /* 0xC0251E04, 0x41B0E726 */ +const RA3: f64 = -6.23753324503260060396e+01; /* 0xC04F300A, 0xE4CBA38D */ +const RA4: f64 = -1.62396669462573470355e+02; /* 0xC0644CB1, 0x84282266 */ +const RA5: f64 = -1.84605092906711035994e+02; /* 0xC067135C, 0xEBCCABB2 */ +const RA6: f64 = -8.12874355063065934246e+01; /* 0xC0545265, 0x57E4D2F2 */ +const RA7: f64 = -9.81432934416914548592e+00; /* 0xC023A0EF, 0xC69AC25C */ +const SA1: f64 = 1.96512716674392571292e+01; /* 0x4033A6B9, 0xBD707687 */ +const SA2: f64 = 1.37657754143519042600e+02; /* 0x4061350C, 0x526AE721 */ +const SA3: f64 = 4.34565877475229228821e+02; /* 0x407B290D, 0xD58A1A71 */ +const SA4: f64 = 6.45387271733267880336e+02; /* 0x40842B19, 0x21EC2868 */ +const SA5: f64 = 4.29008140027567833386e+02; /* 0x407AD021, 0x57700314 */ +const SA6: f64 = 1.08635005541779435134e+02; /* 0x405B28A3, 0xEE48AE2C */ +const SA7: f64 = 6.57024977031928170135e+00; /* 0x401A47EF, 0x8E484A93 */ +const SA8: f64 = -6.04244152148580987438e-02; /* 0xBFAEEFF2, 0xEE749A62 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +const RB0: f64 = -9.86494292470009928597e-03; /* 0xBF843412, 0x39E86F4A */ +const RB1: f64 = -7.99283237680523006574e-01; /* 0xBFE993BA, 0x70C285DE */ +const RB2: f64 = -1.77579549177547519889e+01; /* 0xC031C209, 0x555F995A */ +const RB3: f64 = -1.60636384855821916062e+02; /* 0xC064145D, 0x43C5ED98 */ +const RB4: f64 = -6.37566443368389627722e+02; /* 0xC083EC88, 0x1375F228 */ +const RB5: f64 = -1.02509513161107724954e+03; /* 0xC0900461, 0x6A2E5992 */ +const RB6: f64 = -4.83519191608651397019e+02; /* 0xC07E384E, 0x9BDC383F */ +const SB1: f64 = 3.03380607434824582924e+01; /* 0x403E568B, 0x261D5190 */ +const SB2: f64 = 3.25792512996573918826e+02; /* 0x40745CAE, 0x221B9F0A */ +const SB3: f64 = 1.53672958608443695994e+03; /* 0x409802EB, 0x189D5118 */ +const SB4: f64 = 3.19985821950859553908e+03; /* 0x40A8FFB7, 0x688C246A */ +const SB5: f64 = 2.55305040643316442583e+03; /* 0x40A3F219, 0xCEDF3BE6 */ +const SB6: f64 = 4.74528541206955367215e+02; /* 0x407DA874, 0xE79FE763 */ +const SB7: f64 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */ + +fn erfc1(x: f64) -> f64 { + let s: f64; + let p: f64; + let q: f64; + + s = fabs(x) - 1.0; + p = PA0+s*(PA1+s*(PA2+s*(PA3+s*(PA4+s*(PA5+s*PA6))))); + q = 1.0+s*(QA1+s*(QA2+s*(QA3+s*(QA4+s*(QA5+s*QA6))))); + + 1.0 - ERX - p/q +} + +fn erfc2(ix: u32, mut x: f64) -> f64 { + let s: f64; + let r: f64; + let big_s: f64; + let z: f64; + + if ix < 0x3ff40000 { /* |x| < 1.25 */ + return erfc1(x); + } + + x = fabs(x); + s = 1.0/(x*x); + if ix < 0x4006db6d { /* |x| < 1/.35 ~ 2.85714 */ + r = RA0+s*(RA1+s*(RA2+s*(RA3+s*(RA4+s*( + RA5+s*(RA6+s*RA7)))))); + big_s = 1.0+s*(SA1+s*(SA2+s*(SA3+s*(SA4+s*( + SA5+s*(SA6+s*(SA7+s*SA8))))))); + } else { /* |x| > 1/.35 */ + r = RB0+s*(RB1+s*(RB2+s*(RB3+s*(RB4+s*( + RB5+s*RB6))))); + big_s = 1.0+s*(SB1+s*(SB2+s*(SB3+s*(SB4+s*( + SB5+s*(SB6+s*SB7)))))); + } + z = with_set_low_word(x, 0); + + exp(-z*z-0.5625)*exp((z-x)*(z+x)+r/big_s)/x +} + +pub fn erf(x: f64) -> f64 { + let r: f64; + let s: f64; + let z: f64; + let y: f64; + let mut ix: u32; + let sign: usize; + + ix = get_high_word(x); + sign = (ix>>31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7ff00000 { + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1.0-2.0*(sign as f64) + 1.0/x; + } + if ix < 0x3feb0000 { /* |x| < 0.84375 */ + if ix < 0x3e300000 { /* |x| < 2**-28 */ + /* avoid underflow */ + return 0.125*(8.0*x + EFX8*x); + } + z = x*x; + r = PP0+z*(PP1+z*(PP2+z*(PP3+z*PP4))); + s = 1.0+z*(QQ1+z*(QQ2+z*(QQ3+z*(QQ4+z*QQ5)))); + y = r/s; + return x + x*y; + } + if ix < 0x40180000 { /* 0.84375 <= |x| < 6 */ + y = 1.0 - erfc2(ix,x); + } else { + let x1p_1022 = f64::from_bits(0x0010000000000000); + y = 1.0 - x1p_1022; + } + + if sign != 0 { + -y + } else { + y + } +} + +pub fn erfc(x: f64) -> f64 { + let r: f64; + let s: f64; + let z: f64; + let y: f64; + let mut ix: u32; + let sign: usize; + + ix = get_high_word(x); + sign = (ix>>31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7ff00000 { + /* erfc(nan)=nan, erfc(+-inf)=0,2 */ + return 2.0*(sign as f64) + 1.0/x; + } + if ix < 0x3feb0000 { /* |x| < 0.84375 */ + if ix < 0x3c700000 { /* |x| < 2**-56 */ + return 1.0 - x; + } + z = x*x; + r = PP0+z*(PP1+z*(PP2+z*(PP3+z*PP4))); + s = 1.0+z*(QQ1+z*(QQ2+z*(QQ3+z*(QQ4+z*QQ5)))); + y = r/s; + if sign != 0 || ix < 0x3fd00000 { /* x < 1/4 */ + return 1.0 - (x+x*y); + } + return 0.5 - (x - 0.5 + x*y); + } + if ix < 0x403c0000 { /* 0.84375 <= |x| < 28 */ + if sign != 0 { + return 2.0 - erfc2(ix,x); + } else { + return erfc2(ix,x); + } + } + + let x1p_1022 = f64::from_bits(0x0010000000000000); + if sign != 0 { + 2.0 - x1p_1022 + } else { + x1p_1022*x1p_1022 + } +} diff --git a/library/compiler-builtins/libm/src/math/erff.rs b/library/compiler-builtins/libm/src/math/erff.rs new file mode 100644 index 0000000000000..0aaa89767aba5 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/erff.rs @@ -0,0 +1,210 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_erff.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + +use super::{expf, fabsf}; + +const ERX: f32 = 8.4506291151e-01; /* 0x3f58560b */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +const EFX8: f32 = 1.0270333290e+00; /* 0x3f8375d4 */ +const PP0: f32 = 1.2837916613e-01; /* 0x3e0375d4 */ +const PP1: f32 = -3.2504209876e-01; /* 0xbea66beb */ +const PP2: f32 = -2.8481749818e-02; /* 0xbce9528f */ +const PP3: f32 = -5.7702702470e-03; /* 0xbbbd1489 */ +const PP4: f32 = -2.3763017452e-05; /* 0xb7c756b1 */ +const QQ1: f32 = 3.9791721106e-01; /* 0x3ecbbbce */ +const QQ2: f32 = 6.5022252500e-02; /* 0x3d852a63 */ +const QQ3: f32 = 5.0813062117e-03; /* 0x3ba68116 */ +const QQ4: f32 = 1.3249473704e-04; /* 0x390aee49 */ +const QQ5: f32 = -3.9602282413e-06; /* 0xb684e21a */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +const PA0: f32 = -2.3621185683e-03; /* 0xbb1acdc6 */ +const PA1: f32 = 4.1485610604e-01; /* 0x3ed46805 */ +const PA2: f32 = -3.7220788002e-01; /* 0xbebe9208 */ +const PA3: f32 = 3.1834661961e-01; /* 0x3ea2fe54 */ +const PA4: f32 = -1.1089469492e-01; /* 0xbde31cc2 */ +const PA5: f32 = 3.5478305072e-02; /* 0x3d1151b3 */ +const PA6: f32 = -2.1663755178e-03; /* 0xbb0df9c0 */ +const QA1: f32 = 1.0642088205e-01; /* 0x3dd9f331 */ +const QA2: f32 = 5.4039794207e-01; /* 0x3f0a5785 */ +const QA3: f32 = 7.1828655899e-02; /* 0x3d931ae7 */ +const QA4: f32 = 1.2617121637e-01; /* 0x3e013307 */ +const QA5: f32 = 1.3637083583e-02; /* 0x3c5f6e13 */ +const QA6: f32 = 1.1984500103e-02; /* 0x3c445aa3 */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +const RA0: f32 = -9.8649440333e-03; /* 0xbc21a093 */ +const RA1: f32 = -6.9385856390e-01; /* 0xbf31a0b7 */ +const RA2: f32 = -1.0558626175e+01; /* 0xc128f022 */ +const RA3: f32 = -6.2375331879e+01; /* 0xc2798057 */ +const RA4: f32 = -1.6239666748e+02; /* 0xc322658c */ +const RA5: f32 = -1.8460508728e+02; /* 0xc3389ae7 */ +const RA6: f32 = -8.1287437439e+01; /* 0xc2a2932b */ +const RA7: f32 = -9.8143291473e+00; /* 0xc11d077e */ +const SA1: f32 = 1.9651271820e+01; /* 0x419d35ce */ +const SA2: f32 = 1.3765776062e+02; /* 0x4309a863 */ +const SA3: f32 = 4.3456588745e+02; /* 0x43d9486f */ +const SA4: f32 = 6.4538726807e+02; /* 0x442158c9 */ +const SA5: f32 = 4.2900814819e+02; /* 0x43d6810b */ +const SA6: f32 = 1.0863500214e+02; /* 0x42d9451f */ +const SA7: f32 = 6.5702495575e+00; /* 0x40d23f7c */ +const SA8: f32 = -6.0424413532e-02; /* 0xbd777f97 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +const RB0: f32 = -9.8649431020e-03; /* 0xbc21a092 */ +const RB1: f32 = -7.9928326607e-01; /* 0xbf4c9dd4 */ +const RB2: f32 = -1.7757955551e+01; /* 0xc18e104b */ +const RB3: f32 = -1.6063638306e+02; /* 0xc320a2ea */ +const RB4: f32 = -6.3756646729e+02; /* 0xc41f6441 */ +const RB5: f32 = -1.0250950928e+03; /* 0xc480230b */ +const RB6: f32 = -4.8351919556e+02; /* 0xc3f1c275 */ +const SB1: f32 = 3.0338060379e+01; /* 0x41f2b459 */ +const SB2: f32 = 3.2579251099e+02; /* 0x43a2e571 */ +const SB3: f32 = 1.5367296143e+03; /* 0x44c01759 */ +const SB4: f32 = 3.1998581543e+03; /* 0x4547fdbb */ +const SB5: f32 = 2.5530502930e+03; /* 0x451f90ce */ +const SB6: f32 = 4.7452853394e+02; /* 0x43ed43a7 */ +const SB7: f32 = -2.2440952301e+01; /* 0xc1b38712 */ + +fn erfc1(x: f32) -> f32 { + let s: f32; + let p: f32; + let q: f32; + + s = fabsf(x) - 1.0; + p = PA0+s*(PA1+s*(PA2+s*(PA3+s*(PA4+s*(PA5+s*PA6))))); + q = 1.0+s*(QA1+s*(QA2+s*(QA3+s*(QA4+s*(QA5+s*QA6))))); + return 1.0 - ERX - p/q; +} + +fn erfc2(mut ix: u32, mut x: f32) -> f32 { + let s: f32; + let r: f32; + let big_s: f32; + let z: f32; + + if ix < 0x3fa00000 { /* |x| < 1.25 */ + return erfc1(x); + } + + x = fabsf(x); + s = 1.0/(x*x); + if ix < 0x4036db6d { /* |x| < 1/0.35 */ + r = RA0+s*(RA1+s*(RA2+s*(RA3+s*(RA4+s*( + RA5+s*(RA6+s*RA7)))))); + big_s = 1.0+s*(SA1+s*(SA2+s*(SA3+s*(SA4+s*( + SA5+s*(SA6+s*(SA7+s*SA8))))))); + } else { /* |x| >= 1/0.35 */ + r = RB0+s*(RB1+s*(RB2+s*(RB3+s*(RB4+s*( + RB5+s*RB6))))); + big_s = 1.0+s*(SB1+s*(SB2+s*(SB3+s*(SB4+s*( + SB5+s*(SB6+s*SB7)))))); + } + ix = x.to_bits(); + z = f32::from_bits(ix&0xffffe000); + + expf(-z*z - 0.5625) * expf((z-x)*(z+x) + r/big_s)/x +} + +pub fn erff(x: f32) -> f32 +{ + let r: f32; + let s: f32; + let z: f32; + let y: f32; + let mut ix: u32; + let sign: usize; + + ix = x.to_bits(); + sign = (ix>>31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1.0-2.0*(sign as f32) + 1.0/x; + } + if ix < 0x3f580000 { /* |x| < 0.84375 */ + if ix < 0x31800000 { /* |x| < 2**-28 */ + /*avoid underflow */ + return 0.125*(8.0*x + EFX8*x); + } + z = x*x; + r = PP0+z*(PP1+z*(PP2+z*(PP3+z*PP4))); + s = 1.0+z*(QQ1+z*(QQ2+z*(QQ3+z*(QQ4+z*QQ5)))); + y = r/s; + return x + x*y; + } + if ix < 0x40c00000 { /* |x| < 6 */ + y = 1.0 - erfc2(ix,x); + } else { + let x1p_120 = f32::from_bits(0x03800000); + y = 1.0 - x1p_120; + } + + if sign != 0 { + -y + } else { + y + } +} + +pub fn erfcf(x: f32) -> f32 { + let r: f32; + let s: f32; + let z: f32; + let y: f32; + let mut ix: u32; + let sign: usize; + + ix = x.to_bits(); + sign = (ix>>31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + /* erfc(nan)=nan, erfc(+-inf)=0,2 */ + return 2.0*(sign as f32) + 1.0/x; + } + + if ix < 0x3f580000 { /* |x| < 0.84375 */ + if ix < 0x23800000 { /* |x| < 2**-56 */ + return 1.0 - x; + } + z = x*x; + r = PP0+z*(PP1+z*(PP2+z*(PP3+z*PP4))); + s = 1.0+z*(QQ1+z*(QQ2+z*(QQ3+z*(QQ4+z*QQ5)))); + y = r/s; + if sign != 0 || ix < 0x3e800000 { /* x < 1/4 */ + return 1.0 - (x+x*y); + } + return 0.5 - (x - 0.5 + x*y); + } + if ix < 0x41e00000 { /* |x| < 28 */ + if sign != 0 { + return 2.0 - erfc2(ix, x); + } else { + return erfc2(ix, x); + } + } + + let x1p_120 = f32::from_bits(0x03800000); + if sign != 0 { + 2.0 - x1p_120 + } else { + x1p_120*x1p_120 + } +} diff --git a/library/compiler-builtins/libm/src/math/exp10.rs b/library/compiler-builtins/libm/src/math/exp10.rs new file mode 100644 index 0000000000000..d12fa0be31e1c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/exp10.rs @@ -0,0 +1,24 @@ +use super::{exp2, modf, pow}; + +const LN10: f64 = 3.32192809488736234787031942948939; +const P10: &[f64] = &[ + 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, + 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15 +]; + +pub fn exp10(x: f64) -> f64 +{ + let (mut y, n) = modf(x); + let u: u64 = n.to_bits(); + /* fabs(n) < 16 without raising invalid on nan */ + if (u>>52 & 0x7ff) < 0x3ff+4 { + if y == 0.0 { + return P10[((n as isize) + 15) as usize]; + } + y = exp2(LN10 * y); + return y * P10[((n as isize) + 15) as usize]; + } + return pow(10.0, x); +} diff --git a/library/compiler-builtins/libm/src/math/exp10f.rs b/library/compiler-builtins/libm/src/math/exp10f.rs new file mode 100644 index 0000000000000..8fb88a52c017f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/exp10f.rs @@ -0,0 +1,22 @@ +use super::{exp2, exp2f, modff}; + +const LN10_F32: f32 = 3.32192809488736234787031942948939; +const LN10_F64: f64 = 3.32192809488736234787031942948939; +const P10: &[f32] = &[ + 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7 +]; + +pub fn exp10f(x: f32) -> f32 { + let (mut y, n) = modff(x); + let u = n.to_bits(); + /* fabsf(n) < 8 without raising invalid on nan */ + if (u>>23 & 0xff) < 0x7f+3 { + if y == 0.0 { + return P10[((n as isize) + 7) as usize] + } + y = exp2f(LN10_F32 * y); + return y * P10[((n as isize) + 7) as usize]; + } + return exp2(LN10_F64 * (x as f64)) as f32; +} diff --git a/library/compiler-builtins/libm/src/math/frexp.rs b/library/compiler-builtins/libm/src/math/frexp.rs new file mode 100644 index 0000000000000..45733a3aaa323 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/frexp.rs @@ -0,0 +1,20 @@ +pub fn frexp(x: f64) -> (f64, isize) { + let mut y = x.to_bits(); + let ee = ((y>>52) & 0x7ff) as isize; + + if ee == 0 { + if x != 0.0 { + let x1p64 = f64::from_bits(0x43f0000000000000); + let (x, e) = frexp(x*x1p64); + return (x, e - 64); + } + return (x, 0); + } else if ee == 0x7ff { + return (x, 0); + } + + let e = ee - 0x3fe; + y &= 0x800fffffffffffff; + y |= 0x3fe0000000000000; + return (f64::from_bits(y), e); +} diff --git a/library/compiler-builtins/libm/src/math/frexpf.rs b/library/compiler-builtins/libm/src/math/frexpf.rs new file mode 100644 index 0000000000000..1c9dae0bb9836 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/frexpf.rs @@ -0,0 +1,21 @@ +pub fn frexpf(x: f32) -> (f32, isize) { + let mut y = x.to_bits(); + let ee: isize = ((y>>23) & 0xff) as isize; + + if ee == 0 { + if x != 0.0 { + let x1p64 = f32::from_bits(0x5f800000); + let (x, e) = frexpf(x*x1p64); + return (x, e - 64); + } else { + return (x, 0); + } + } else if ee == 0xff { + return (x, 0); + } + + let e = ee - 0x7e; + y &= 0x807fffff; + y |= 0x3f000000; + return (f32::from_bits(y), e); +} diff --git a/library/compiler-builtins/libm/src/math/ilogb.rs b/library/compiler-builtins/libm/src/math/ilogb.rs new file mode 100644 index 0000000000000..78fe030a1cc23 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ilogb.rs @@ -0,0 +1,31 @@ +const FP_ILOGBNAN: isize = -1 - (((!0) >> 1)); +const FP_ILOGB0: isize = FP_ILOGBNAN; + +pub fn ilogb(x: f64) -> isize { + let mut i: u64 = x.to_bits(); + let e = ((i>>52) & 0x7ff) as isize; + + if e == 0 { + i <<= 12; + if i == 0 { + force_eval!(0.0/0.0); + return FP_ILOGB0; + } + /* subnormal x */ + let mut e = -0x3ff; + while (i>>63) == 0 { + e -= 1; + i <<= 1; + } + return e; + } + if e == 0x7ff { + force_eval!(0.0/0.0); + if (i<<12) != 0 { + return FP_ILOGBNAN; + } else { + return isize::max_value(); + } + } + return e - 0x3ff; +} diff --git a/library/compiler-builtins/libm/src/math/ilogbf.rs b/library/compiler-builtins/libm/src/math/ilogbf.rs new file mode 100644 index 0000000000000..9ca1c360665f0 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ilogbf.rs @@ -0,0 +1,31 @@ +const FP_ILOGBNAN: isize = -1 - (((!0) >> 1)); +const FP_ILOGB0: isize = FP_ILOGBNAN; + +pub fn ilogbf(x: f32) -> isize { + let mut i = x.to_bits(); + let e = ((i>>23) & 0xff) as isize; + + if e == 0 { + i <<= 9; + if i == 0 { + force_eval!(0.0/0.0); + return FP_ILOGB0; + } + /* subnormal x */ + let mut e = -0x7f; + while (i>>31) == 0 { + e -= 1; + i <<= 1; + } + return e; + } + if e == 0xff { + force_eval!(0.0/0.0); + if (i<<9) != 0 { + return FP_ILOGBNAN; + } else { + return isize::max_value(); + } + } + return e - 0x7f; +} diff --git a/library/compiler-builtins/libm/src/math/j0.rs b/library/compiler-builtins/libm/src/math/j0.rs new file mode 100644 index 0000000000000..02625b086db49 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/j0.rs @@ -0,0 +1,392 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j0.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* j0(x), y0(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j0(x): + * 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ... + * 2. Reduce x to |x| since j0(x)=j0(-x), and + * for x in (0,2) + * j0(x) = 1-z/4+ z^2*R0/S0, where z = x*x; + * (precision: |j0-1+z/4-z^2R0/S0 |<2**-63.67 ) + * for x in (2,inf) + * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * as follow: + * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4) + * = 1/sqrt(2) * (cos(x) + sin(x)) + * sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j0(nan)= nan + * j0(0) = 1 + * j0(inf) = 0 + * + * Method -- y0(x): + * 1. For x<2. + * Since + * y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...) + * therefore y0(x)-2/pi*j0(x)*ln(x) is an even function. + * We use the following function to approximate y0, + * y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2 + * where + * U(z) = u00 + u01*z + ... + u06*z^6 + * V(z) = 1 + v01*z + ... + v04*z^4 + * with absolute approximation error bounded by 2**-72. + * Note: For tiny x, U/V = u0 and j0(x)~1, hence + * y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27) + * 2. For x>=2. + * y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * by the method mentioned above. + * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0. + */ + +use super::{cos, get_low_word, get_high_word, fabs, log, sin, sqrt}; +const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ +const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ + +/* common method when |x|>=2 */ +fn common(ix: u32, x: f64, y0: bool) -> f64 { + let s: f64; + let mut c: f64; + let mut ss: f64; + let mut cc: f64; + let z: f64; + + /* + * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x-pi/4)-q0(x)*sin(x-pi/4)) + * y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x-pi/4)+q0(x)*cos(x-pi/4)) + * + * sin(x-pi/4) = (sin(x) - cos(x))/sqrt(2) + * cos(x-pi/4) = (sin(x) + cos(x))/sqrt(2) + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + */ + s = sin(x); + c = cos(x); + if y0 { + c = -c; + } + cc = s+c; + /* avoid overflow in 2*x, big ulp error when x>=0x1p1023 */ + if ix < 0x7fe00000 { + ss = s-c; + z = -cos(2.0*x); + if s*c < 0.0 { + cc = z/ss; + } else { + ss = z/cc; + } + if ix < 0x48000000 { + if y0 { + ss = -ss; + } + cc = pzero(x)*cc-qzero(x)*ss; + } + } + return INVSQRTPI*cc/sqrt(x); +} + +/* R0/S0 on [0, 2.00] */ +const R02: f64 = 1.56249999999999947958e-02; /* 0x3F8FFFFF, 0xFFFFFFFD */ +const R03: f64 = -1.89979294238854721751e-04; /* 0xBF28E6A5, 0xB61AC6E9 */ +const R04: f64 = 1.82954049532700665670e-06; /* 0x3EBEB1D1, 0x0C503919 */ +const R05: f64 = -4.61832688532103189199e-09; /* 0xBE33D5E7, 0x73D63FCE */ +const S01: f64 = 1.56191029464890010492e-02; /* 0x3F8FFCE8, 0x82C8C2A4 */ +const S02: f64 = 1.16926784663337450260e-04; /* 0x3F1EA6D2, 0xDD57DBF4 */ +const S03: f64 = 5.13546550207318111446e-07; /* 0x3EA13B54, 0xCE84D5A9 */ +const S04: f64 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ + +pub fn j0(mut x: f64) -> f64 +{ + let z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + + /* j0(+-inf)=0, j0(nan)=nan */ + if ix >= 0x7ff00000 { + return 1.0/(x*x); + } + x = fabs(x); + + if ix >= 0x40000000 { /* |x| >= 2 */ + /* large ulp error near zeros: 2.4, 5.52, 8.6537,.. */ + return common(ix,x,false); + } + + /* 1 - x*x/4 + x*x*R(x^2)/S(x^2) */ + if ix >= 0x3f200000 { /* |x| >= 2**-13 */ + /* up to 4ulp error close to 2 */ + z = x*x; + r = z*(R02+z*(R03+z*(R04+z*R05))); + s = 1.0+z*(S01+z*(S02+z*(S03+z*S04))); + return (1.0+x/2.0)*(1.0-x/2.0) + z*(r/s); + } + + /* 1 - x*x/4 */ + /* prevent underflow */ + /* inexact should be raised when x!=0, this is not done correctly */ + if ix >= 0x38000000 { /* |x| >= 2**-127 */ + x = 0.25*x*x; + } + return 1.0 - x; +} + +const U00: f64 = -7.38042951086872317523e-02; /* 0xBFB2E4D6, 0x99CBD01F */ +const U01: f64 = 1.76666452509181115538e-01; /* 0x3FC69D01, 0x9DE9E3FC */ +const U02: f64 = -1.38185671945596898896e-02; /* 0xBF8C4CE8, 0xB16CFA97 */ +const U03: f64 = 3.47453432093683650238e-04; /* 0x3F36C54D, 0x20B29B6B */ +const U04: f64 = -3.81407053724364161125e-06; /* 0xBECFFEA7, 0x73D25CAD */ +const U05: f64 = 1.95590137035022920206e-08; /* 0x3E550057, 0x3B4EABD4 */ +const U06: f64 = -3.98205194132103398453e-11; /* 0xBDC5E43D, 0x693FB3C8 */ +const V01: f64 = 1.27304834834123699328e-02; /* 0x3F8A1270, 0x91C9C71A */ +const V02: f64 = 7.60068627350353253702e-05; /* 0x3F13ECBB, 0xF578C6C1 */ +const V03: f64 = 2.59150851840457805467e-07; /* 0x3E91642D, 0x7FF202FD */ +const V04: f64 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ + +pub fn y0(x: f64) -> f64 +{ + let z: f64; + let u: f64; + let v: f64; + let ix: u32; + let lx: u32; + + ix = get_high_word(x); + lx = get_low_word(x); + + /* y0(nan)=nan, y0(<0)=nan, y0(0)=-inf, y0(inf)=0 */ + if ((ix<<1) | lx) == 0 { + return -1.0/0.0; + } + if (ix>>31) != 0 { + return 0.0/0.0; + } + if ix >= 0x7ff00000 { + return 1.0/x; + } + + if ix >= 0x40000000 { /* x >= 2 */ + /* large ulp errors near zeros: 3.958, 7.086,.. */ + return common(ix,x,true); + } + + /* U(x^2)/V(x^2) + (2/pi)*j0(x)*log(x) */ + if ix >= 0x3e400000 { /* x >= 2**-27 */ + /* large ulp error near the first zero, x ~= 0.89 */ + z = x*x; + u = U00+z*(U01+z*(U02+z*(U03+z*(U04+z*(U05+z*U06))))); + v = 1.0+z*(V01+z*(V02+z*(V03+z*V04))); + return u/v + TPI*(j0(x)*log(x)); + } + return U00 + TPI*log(x); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +const PR8: [f64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */ + -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */ + -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */ + -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */ + -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */ +]; +const PS8: [f64; 5] = [ + 1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */ + 3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */ + 4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */ + 1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */ + 4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */ +]; + +const PR5: [f64; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */ + -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */ + -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */ + -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */ + -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */ + -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */ +]; +const PS5: [f64; 5] = [ + 6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */ + 1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */ + 5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */ + 9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */ + 2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */ +]; + +const PR3: [f64; 6] = [/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */ + -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */ + -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */ + -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */ + -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */ + -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */ +]; +const PS3: [f64; 5] = [ + 3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */ + 3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */ + 1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */ + 1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */ + 1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */ +]; + +const PR2: [f64; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */ + -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */ + -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */ + -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */ + -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */ + -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */ +]; +const PS2: [f64; 5] = [ + 2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */ + 1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */ + 2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */ + 1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */ + 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */ +]; + +fn pzero(x: f64) -> f64 +{ + let p: &[f64; 6]; + let q: &[f64; 5]; + let z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 {p = &PR8; q = &PS8;} + else if ix >= 0x40122E8B {p = &PR5; q = &PS5;} + else if ix >= 0x4006DB6D {p = &PR3; q = &PS3;} + else /*ix >= 0x40000000*/{p = &PR2; q = &PS2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return 1.0 + r/s; +} + + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +const QR8: [f64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */ + 1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */ + 5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */ + 8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */ + 3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */ +]; +const QS8: [f64; 6] = [ + 1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */ + 8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */ + 1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */ + 8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */ + 8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */ + -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */ +]; + +const QR5: [f64; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */ + 7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */ + 5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */ + 1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */ + 1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */ + 1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */ +]; +const QS5: [f64; 6] = [ + 8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */ + 2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */ + 1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */ + 5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */ + 3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */ + -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */ +]; + +const QR3: [f64; 6] = [/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */ + 7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */ + 3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */ + 4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */ + 1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */ + 1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */ +]; +const QS3: [f64; 6] = [ + 4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */ + 7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */ + 3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */ + 6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */ + 2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */ + -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */ +]; + +const QR2: [f64; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */ + 7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */ + 1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */ + 1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */ + 3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */ + 1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */ +]; +const QS2: [f64; 6] = [ + 3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */ + 2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */ + 8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */ + 8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */ + 2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */ + -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */ +]; + +fn qzero(x: f64) -> f64 +{ + let p: &[f64; 6]; + let q: &[f64; 6]; + let s: f64; + let r: f64; + let z: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 {p = &QR8; q = &QS8;} + else if ix >= 0x40122E8B {p = &QR5; q = &QS5;} + else if ix >= 0x4006DB6D {p = &QR3; q = &QS3;} + else /*ix >= 0x40000000*/{p = &QR2; q = &QS2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (-0.125 + r/s)/x; +} diff --git a/library/compiler-builtins/libm/src/math/j0f.rs b/library/compiler-builtins/libm/src/math/j0f.rs new file mode 100644 index 0000000000000..e2faed0b256fe --- /dev/null +++ b/library/compiler-builtins/libm/src/math/j0f.rs @@ -0,0 +1,330 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j0f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + +use super::{cosf, fabsf, logf, sinf, sqrtf}; + +const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ +const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ + +fn common(ix: u32, x: f32, y0: bool) -> f32 +{ + let z: f32; + let s: f32; + let mut c: f32; + let mut ss: f32; + let mut cc: f32; + /* + * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) + * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) + */ + s = sinf(x); + c = cosf(x); + if y0 { + c = -c; + } + cc = s+c; + if ix < 0x7f000000 { + ss = s-c; + z = -cosf(2.0*x); + if s*c < 0.0 { + cc = z/ss; + } else { + ss = z/cc; + } + if ix < 0x58800000 { + if y0 { + ss = -ss; + } + cc = pzerof(x)*cc-qzerof(x)*ss; + } + } + return INVSQRTPI*cc/sqrtf(x); +} + +/* R0/S0 on [0, 2.00] */ +const R02: f32 = 1.5625000000e-02; /* 0x3c800000 */ +const R03: f32 = -1.8997929874e-04; /* 0xb947352e */ +const R04: f32 = 1.8295404516e-06; /* 0x35f58e88 */ +const R05: f32 = -4.6183270541e-09; /* 0xb19eaf3c */ +const S01: f32 = 1.5619102865e-02; /* 0x3c7fe744 */ +const S02: f32 = 1.1692678527e-04; /* 0x38f53697 */ +const S03: f32 = 5.1354652442e-07; /* 0x3509daa6 */ +const S04: f32 = 1.1661400734e-09; /* 0x30a045e8 */ + +pub fn j0f(mut x: f32) -> f32 +{ + let z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + return 1.0/(x*x); + } + x = fabsf(x); + + if ix >= 0x40000000 { /* |x| >= 2 */ + /* large ulp error near zeros */ + return common(ix, x, false); + } + if ix >= 0x3a000000 { /* |x| >= 2**-11 */ + /* up to 4ulp error near 2 */ + z = x*x; + r = z*(R02+z*(R03+z*(R04+z*R05))); + s = 1.0+z*(S01+z*(S02+z*(S03+z*S04))); + return (1.0+x/2.0)*(1.0-x/2.0) + z*(r/s); + } + if ix >= 0x21800000 { /* |x| >= 2**-60 */ + x = 0.25*x*x; + } + return 1.0 - x; +} + +const U00: f32 = -7.3804296553e-02; /* 0xbd9726b5 */ +const U01: f32 = 1.7666645348e-01; /* 0x3e34e80d */ +const U02: f32 = -1.3818567619e-02; /* 0xbc626746 */ +const U03: f32 = 3.4745343146e-04; /* 0x39b62a69 */ +const U04: f32 = -3.8140706238e-06; /* 0xb67ff53c */ +const U05: f32 = 1.9559013964e-08; /* 0x32a802ba */ +const U06: f32 = -3.9820518410e-11; /* 0xae2f21eb */ +const V01: f32 = 1.2730483897e-02; /* 0x3c509385 */ +const V02: f32 = 7.6006865129e-05; /* 0x389f65e0 */ +const V03: f32 = 2.5915085189e-07; /* 0x348b216c */ +const V04: f32 = 4.4111031494e-10; /* 0x2ff280c2 */ + +pub fn y0f(x: f32) -> f32 +{ + let z: f32; + let u: f32; + let v: f32; + let ix: u32; + + ix = x.to_bits(); + if (ix & 0x7fffffff) == 0 { + return -1.0/0.0; + } + if (ix>>31) !=0 { + return 0.0/0.0; + } + if ix >= 0x7f800000 { + return 1.0/x; + } + if ix >= 0x40000000 { /* |x| >= 2.0 */ + /* large ulp error near zeros */ + return common(ix,x,true); + } + if ix >= 0x39000000 { /* x >= 2**-13 */ + /* large ulp error at x ~= 0.89 */ + z = x*x; + u = U00+z*(U01+z*(U02+z*(U03+z*(U04+z*(U05+z*U06))))); + v = 1.0+z*(V01+z*(V02+z*(V03+z*V04))); + return u/v + TPI*(j0f(x)*logf(x)); + } + return U00 + TPI*logf(x); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +const PR8: [f32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -7.0312500000e-02, /* 0xbd900000 */ + -8.0816707611e+00, /* 0xc1014e86 */ + -2.5706311035e+02, /* 0xc3808814 */ + -2.4852163086e+03, /* 0xc51b5376 */ + -5.2530439453e+03, /* 0xc5a4285a */ +]; +const PS8: [f32; 5] = [ + 1.1653436279e+02, /* 0x42e91198 */ + 3.8337448730e+03, /* 0x456f9beb */ + 4.0597855469e+04, /* 0x471e95db */ + 1.1675296875e+05, /* 0x47e4087c */ + 4.7627726562e+04, /* 0x473a0bba */ +]; +const PR5: [f32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.1412546255e-11, /* 0xad48c58a */ + -7.0312492549e-02, /* 0xbd8fffff */ + -4.1596107483e+00, /* 0xc0851b88 */ + -6.7674766541e+01, /* 0xc287597b */ + -3.3123129272e+02, /* 0xc3a59d9b */ + -3.4643338013e+02, /* 0xc3ad3779 */ +]; +const PS5: [f32; 5] = [ + 6.0753936768e+01, /* 0x42730408 */ + 1.0512523193e+03, /* 0x44836813 */ + 5.9789707031e+03, /* 0x45bad7c4 */ + 9.6254453125e+03, /* 0x461665c8 */ + 2.4060581055e+03, /* 0x451660ee */ +]; + +const PR3: [f32; 6] = [/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.5470459075e-09, /* 0xb12f081b */ + -7.0311963558e-02, /* 0xbd8fffb8 */ + -2.4090321064e+00, /* 0xc01a2d95 */ + -2.1965976715e+01, /* 0xc1afba52 */ + -5.8079170227e+01, /* 0xc2685112 */ + -3.1447946548e+01, /* 0xc1fb9565 */ +]; +const PS3: [f32; 5] = [ + 3.5856033325e+01, /* 0x420f6c94 */ + 3.6151397705e+02, /* 0x43b4c1ca */ + 1.1936077881e+03, /* 0x44953373 */ + 1.1279968262e+03, /* 0x448cffe6 */ + 1.7358093262e+02, /* 0x432d94b8 */ +]; + +const PR2: [f32; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.8753431271e-08, /* 0xb3be98b7 */ + -7.0303097367e-02, /* 0xbd8ffb12 */ + -1.4507384300e+00, /* 0xbfb9b1cc */ + -7.6356959343e+00, /* 0xc0f4579f */ + -1.1193166733e+01, /* 0xc1331736 */ + -3.2336456776e+00, /* 0xc04ef40d */ +]; +const PS2: [f32; 5] = [ + 2.2220300674e+01, /* 0x41b1c32d */ + 1.3620678711e+02, /* 0x430834f0 */ + 2.7047027588e+02, /* 0x43873c32 */ + 1.5387539673e+02, /* 0x4319e01a */ + 1.4657617569e+01, /* 0x416a859a */ +]; + +fn pzerof(x: f32) -> f32 +{ + let p: &[f32; 6]; + let q: &[f32; 5]; + let z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 {p = &PR8; q = &PS8;} + else if ix >= 0x409173eb {p = &PR5; q = &PS5;} + else if ix >= 0x4036d917 {p = &PR3; q = &PS3;} + else /*ix >= 0x40000000*/{p = &PR2; q = &PS2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return 1.0 + r/s; +} + + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +const QR8: [f32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 7.3242187500e-02, /* 0x3d960000 */ + 1.1768206596e+01, /* 0x413c4a93 */ + 5.5767340088e+02, /* 0x440b6b19 */ + 8.8591972656e+03, /* 0x460a6cca */ + 3.7014625000e+04, /* 0x471096a0 */ +]; +const QS8: [f32; 6] = [ + 1.6377603149e+02, /* 0x4323c6aa */ + 8.0983447266e+03, /* 0x45fd12c2 */ + 1.4253829688e+05, /* 0x480b3293 */ + 8.0330925000e+05, /* 0x49441ed4 */ + 8.4050156250e+05, /* 0x494d3359 */ + -3.4389928125e+05, /* 0xc8a7eb69 */ +]; + +const QR5: [f32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.8408595828e-11, /* 0x2da1ec79 */ + 7.3242180049e-02, /* 0x3d95ffff */ + 5.8356351852e+00, /* 0x40babd86 */ + 1.3511157227e+02, /* 0x43071c90 */ + 1.0272437744e+03, /* 0x448067cd */ + 1.9899779053e+03, /* 0x44f8bf4b */ +]; +const QS5: [f32; 6] = [ + 8.2776611328e+01, /* 0x42a58da0 */ + 2.0778142090e+03, /* 0x4501dd07 */ + 1.8847289062e+04, /* 0x46933e94 */ + 5.6751113281e+04, /* 0x475daf1d */ + 3.5976753906e+04, /* 0x470c88c1 */ + -5.3543427734e+03, /* 0xc5a752be */ +]; + +const QR3: [f32; 6] = [/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.3774099900e-09, /* 0x3196681b */ + 7.3241114616e-02, /* 0x3d95ff70 */ + 3.3442313671e+00, /* 0x405607e3 */ + 4.2621845245e+01, /* 0x422a7cc5 */ + 1.7080809021e+02, /* 0x432acedf */ + 1.6673394775e+02, /* 0x4326bbe4 */ +]; +const QS3: [f32; 6] = [ + 4.8758872986e+01, /* 0x42430916 */ + 7.0968920898e+02, /* 0x44316c1c */ + 3.7041481934e+03, /* 0x4567825f */ + 6.4604252930e+03, /* 0x45c9e367 */ + 2.5163337402e+03, /* 0x451d4557 */ + -1.4924745178e+02, /* 0xc3153f59 */ +]; + +const QR2: [f32; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.5044444979e-07, /* 0x342189db */ + 7.3223426938e-02, /* 0x3d95f62a */ + 1.9981917143e+00, /* 0x3fffc4bf */ + 1.4495602608e+01, /* 0x4167edfd */ + 3.1666231155e+01, /* 0x41fd5471 */ + 1.6252708435e+01, /* 0x4182058c */ +]; +const QS2: [f32; 6] = [ + 3.0365585327e+01, /* 0x41f2ecb8 */ + 2.6934811401e+02, /* 0x4386ac8f */ + 8.4478375244e+02, /* 0x44533229 */ + 8.8293585205e+02, /* 0x445cbbe5 */ + 2.1266638184e+02, /* 0x4354aa98 */ + -5.3109550476e+00, /* 0xc0a9f358 */ +]; + +fn qzerof(x: f32) -> f32 +{ + let p: &[f32; 6]; + let q: &[f32; 6]; + let s: f32; + let r: f32; + let z: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 {p = &QR8; q = &QS8;} + else if ix >= 0x409173eb {p = &QR5; q = &QS5;} + else if ix >= 0x4036d917 {p = &QR3; q = &QS3;} + else /*ix >= 0x40000000*/{p = &QR2; q = &QS2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (-0.125 + r/s)/x; +} diff --git a/library/compiler-builtins/libm/src/math/j1.rs b/library/compiler-builtins/libm/src/math/j1.rs new file mode 100644 index 0000000000000..92289a613200b --- /dev/null +++ b/library/compiler-builtins/libm/src/math/j1.rs @@ -0,0 +1,387 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j1.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* j1(x), y1(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j1(x): + * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ... + * 2. Reduce x to |x| since j1(x)=-j1(-x), and + * for x in (0,2) + * j1(x) = x/2 + x*z*R0/S0, where z = x*x; + * (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 ) + * for x in (2,inf) + * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1)) + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * as follow: + * cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) + * = -1/sqrt(2) * (sin(x) + cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j1(nan)= nan + * j1(0) = 0 + * j1(inf) = 0 + * + * Method -- y1(x): + * 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN + * 2. For x<2. + * Since + * y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...) + * therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function. + * We use the following function to approximate y1, + * y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2 + * where for x in [0,2] (abs err less than 2**-65.89) + * U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4 + * V(z) = 1 + v0[0]*z + ... + v0[4]*z^5 + * Note: For tiny x, 1/x dominate y1 and hence + * y1(tiny) = -2/pi/tiny, (choose tiny<2**-54) + * 3. For x>=2. + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * by method mentioned above. + */ + +use super::{cos, get_high_word, get_low_word, fabs, log, sin, sqrt}; + +const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ +const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ + +fn common(ix: u32, x: f64, y1: bool, sign: bool) -> f64 +{ + let z: f64; + let mut s: f64; + let c: f64; + let mut ss: f64; + let mut cc: f64; + + /* + * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x-3pi/4)-q1(x)*sin(x-3pi/4)) + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x-3pi/4)+q1(x)*cos(x-3pi/4)) + * + * sin(x-3pi/4) = -(sin(x) + cos(x))/sqrt(2) + * cos(x-3pi/4) = (sin(x) - cos(x))/sqrt(2) + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + */ + s = sin(x); + if y1 { + s = -s; + } + c = cos(x); + cc = s-c; + if ix < 0x7fe00000 { + /* avoid overflow in 2*x */ + ss = -s-c; + z = cos(2.0*x); + if s*c > 0.0 { + cc = z/ss; + } else { + ss = z/cc; + } + if ix < 0x48000000 { + if y1 { + ss = -ss; + } + cc = pone(x)*cc-qone(x)*ss; + } + } + if sign { + cc = -cc; + } + return INVSQRTPI*cc/sqrt(x); +} + +/* R0/S0 on [0,2] */ +const R00: f64 = -6.25000000000000000000e-02; /* 0xBFB00000, 0x00000000 */ +const R01: f64 = 1.40705666955189706048e-03; /* 0x3F570D9F, 0x98472C61 */ +const R02: f64 = -1.59955631084035597520e-05; /* 0xBEF0C5C6, 0xBA169668 */ +const R03: f64 = 4.96727999609584448412e-08; /* 0x3E6AAAFA, 0x46CA0BD9 */ +const S01: f64 = 1.91537599538363460805e-02; /* 0x3F939D0B, 0x12637E53 */ +const S02: f64 = 1.85946785588630915560e-04; /* 0x3F285F56, 0xB9CDF664 */ +const S03: f64 = 1.17718464042623683263e-06; /* 0x3EB3BFF8, 0x333F8498 */ +const S04: f64 = 5.04636257076217042715e-09; /* 0x3E35AC88, 0xC97DFF2C */ +const S05: f64 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ + +pub fn j1(x: f64) -> f64 +{ + let mut z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + let sign: bool; + + ix = get_high_word(x); + sign = (ix>>31) != 0; + ix &= 0x7fffffff; + if ix >= 0x7ff00000 { + return 1.0/(x*x); + } + if ix >= 0x40000000 { /* |x| >= 2 */ + return common(ix, fabs(x), false, sign); + } + if ix >= 0x38000000 { /* |x| >= 2**-127 */ + z = x*x; + r = z*(R00+z*(R01+z*(R02+z*R03))); + s = 1.0+z*(S01+z*(S02+z*(S03+z*(S04+z*S05)))); + z = r/s; + } else { + /* avoid underflow, raise inexact if x!=0 */ + z = x; + } + return (0.5 + z)*x; +} + +const U0: [f64; 5] = [ + -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */ + 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */ + -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */ + 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */ + -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */ +]; +const V0: [f64; 5] = [ + 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */ + 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */ + 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */ + 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */ + 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ +]; + +pub fn y1(x: f64) -> f64 +{ + let z: f64; + let u: f64; + let v: f64; + let ix: u32; + let lx: u32; + + ix = get_high_word(x); + lx = get_low_word(x); + + /* y1(nan)=nan, y1(<0)=nan, y1(0)=-inf, y1(inf)=0 */ + if (ix<<1 | lx) == 0 { + return -1.0/0.0; + } + if (ix>>31) != 0 { + return 0.0/0.0; + } + if ix >= 0x7ff00000 { + return 1.0/x; + } + + if ix >= 0x40000000 { /* x >= 2 */ + return common(ix, x, true, false); + } + if ix < 0x3c900000 { /* x < 2**-54 */ + return -TPI/x; + } + z = x*x; + u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4]))); + v = 1.0+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4])))); + return x*(u/v) + TPI*(j1(x)*log(x)-1.0/x); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +const PR8: [f64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */ + 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */ + 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */ + 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */ + 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */ +]; +const PS8: [f64; 5] = [ + 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */ + 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */ + 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */ + 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */ + 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */ +]; + +const PR5: [f64; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */ + 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */ + 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */ + 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */ + 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */ + 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */ +]; +const PS5: [f64; 5] = [ + 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */ + 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */ + 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */ + 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */ + 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */ +]; + +const PR3: [f64; 6] = [ + 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */ + 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */ + 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */ + 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */ + 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */ + 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */ +]; +const PS3: [f64; 5] = [ + 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */ + 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */ + 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */ + 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */ + 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */ +]; + +const PR2: [f64; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */ + 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */ + 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */ + 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */ + 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */ + 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */ +]; +const PS2: [f64; 5] = [ + 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */ + 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */ + 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */ + 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */ + 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */ +]; + +fn pone(x: f64) -> f64 +{ + let p: &[f64; 6]; + let q: &[f64; 5]; + let z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 {p = &PR8; q = &PS8;} + else if ix >= 0x40122E8B {p = &PR5; q = &PS5;} + else if ix >= 0x4006DB6D {p = &PR3; q = &PS3;} + else /*ix >= 0x40000000*/{p = &PR2; q = &PS2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return 1.0+ r/s; +} + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +const QR8: [f64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */ + -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */ + -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */ + -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */ + -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */ +]; +const QS8: [f64; 6] = [ + 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */ + 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */ + 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */ + 7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */ + 6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */ + -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */ +]; + +const QR5: [f64; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */ + -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */ + -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */ + -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */ + -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */ + -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */ +]; +const QS5: [f64; 6] = [ + 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */ + 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */ + 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */ + 4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */ + 2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */ + -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */ +]; + +const QR3: [f64; 6] = [ + -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */ + -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */ + -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */ + -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */ + -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */ + -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */ +]; +const QS3: [f64; 6] = [ + 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */ + 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */ + 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */ + 5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */ + 1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */ + -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */ +]; + +const QR2: [f64; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */ + -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */ + -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */ + -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */ + -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */ + -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */ +]; +const QS2: [f64; 6] = [ + 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */ + 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */ + 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */ + 7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */ + 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */ + -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */ +]; + +fn qone(x: f64) -> f64 +{ + let p: &[f64; 6]; + let q: &[f64; 6]; + let s: f64; + let r: f64; + let z: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 {p = &QR8; q = &QS8;} + else if ix >= 0x40122E8B {p = &QR5; q = &QS5;} + else if ix >= 0x4006DB6D {p = &QR3; q = &QS3;} + else /*ix >= 0x40000000*/{p = &QR2; q = &QS2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (0.375 + r/s)/x; +} diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs new file mode 100644 index 0000000000000..7cf9c45b98e97 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/j1f.rs @@ -0,0 +1,331 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j1f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + +use super::{cosf, fabsf, logf, sinf, sqrtf}; + +const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ +const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ + +fn common(ix: u32, x: f32, y1: bool, sign: bool) -> f32 +{ + let z: f64; + let mut s: f64; + let c: f64; + let mut ss: f64; + let mut cc: f64; + + s = sinf(x) as f64; + if y1 { + s = -s; + } + c = cosf(x) as f64; + cc = s-c; + if ix < 0x7f000000 { + ss = -s-c; + z = cosf(2.0*x) as f64; + if s*c > 0.0 { + cc = z/ss; + } else { + ss = z/cc; + } + if ix < 0x58800000 { + if y1 { + ss = -ss; + } + cc = (ponef(x) as f64)*cc-(qonef(x) as f64)*ss; + } + } + if sign { + cc = -cc; + } + return INVSQRTPI*(cc as f32)/sqrtf(x); +} + +/* R0/S0 on [0,2] */ +const R00: f32 = -6.2500000000e-02; /* 0xbd800000 */ +const R01: f32 = 1.4070566976e-03; /* 0x3ab86cfd */ +const R02: f32 = -1.5995563444e-05; /* 0xb7862e36 */ +const R03: f32 = 4.9672799207e-08; /* 0x335557d2 */ +const S01: f32 = 1.9153760746e-02; /* 0x3c9ce859 */ +const S02: f32 = 1.8594678841e-04; /* 0x3942fab6 */ +const S03: f32 = 1.1771846857e-06; /* 0x359dffc2 */ +const S04: f32 = 5.0463624390e-09; /* 0x31ad6446 */ +const S05: f32 = 1.2354227016e-11; /* 0x2d59567e */ + +pub fn j1f(x: f32) -> f32 +{ + let mut z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + let sign: bool; + + ix = x.to_bits(); + sign = (ix>>31) != 0; + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + return 1.0/(x*x); + } + if ix >= 0x40000000 { /* |x| >= 2 */ + return common(ix, fabsf(x), false, sign); + } + if ix >= 0x39000000 { /* |x| >= 2**-13 */ + z = x*x; + r = z*(R00+z*(R01+z*(R02+z*R03))); + s = 1.0+z*(S01+z*(S02+z*(S03+z*(S04+z*S05)))); + z = 0.5 + r/s; + } else { + z = 0.5; + } + return z*x; +} + +const U0: [f32; 5] = [ + -1.9605709612e-01, /* 0xbe48c331 */ + 5.0443872809e-02, /* 0x3d4e9e3c */ + -1.9125689287e-03, /* 0xbafaaf2a */ + 2.3525259166e-05, /* 0x37c5581c */ + -9.1909917899e-08, /* 0xb3c56003 */ +]; +const V0: [f32; 5] = [ + 1.9916731864e-02, /* 0x3ca3286a */ + 2.0255257550e-04, /* 0x3954644b */ + 1.3560879779e-06, /* 0x35b602d4 */ + 6.2274145840e-09, /* 0x31d5f8eb */ + 1.6655924903e-11, /* 0x2d9281cf */ +]; + +pub fn y1f(x: f32) -> f32 +{ + let z: f32; + let u: f32; + let v: f32; + let ix: u32; + + ix = x.to_bits(); + if (ix & 0x7fffffff) == 0 { + return -1.0/0.0; + } + if (ix>>31) != 0{ + return 0.0/0.0; + } + if ix >= 0x7f800000 { + return 1.0/x; + } + if ix >= 0x40000000 { /* |x| >= 2.0 */ + return common(ix,x,true,false); + } + if ix < 0x33000000 { /* x < 2**-25 */ + return -TPI/x; + } + z = x*x; + u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4]))); + v = 1.0+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4])))); + return x*(u/v) + TPI*(j1f(x)*logf(x)-1.0/x); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +const PR8: [f32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 1.1718750000e-01, /* 0x3df00000 */ + 1.3239480972e+01, /* 0x4153d4ea */ + 4.1205184937e+02, /* 0x43ce06a3 */ + 3.8747453613e+03, /* 0x45722bed */ + 7.9144794922e+03, /* 0x45f753d6 */ +]; +const PS8: [f32; 5] = [ + 1.1420736694e+02, /* 0x42e46a2c */ + 3.6509309082e+03, /* 0x45642ee5 */ + 3.6956207031e+04, /* 0x47105c35 */ + 9.7602796875e+04, /* 0x47bea166 */ + 3.0804271484e+04, /* 0x46f0a88b */ +]; + +const PR5: [f32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.3199052094e-11, /* 0x2d68333f */ + 1.1718749255e-01, /* 0x3defffff */ + 6.8027510643e+00, /* 0x40d9b023 */ + 1.0830818176e+02, /* 0x42d89dca */ + 5.1763616943e+02, /* 0x440168b7 */ + 5.2871520996e+02, /* 0x44042dc6 */ +]; +const PS5: [f32; 5] = [ + 5.9280597687e+01, /* 0x426d1f55 */ + 9.9140142822e+02, /* 0x4477d9b1 */ + 5.3532670898e+03, /* 0x45a74a23 */ + 7.8446904297e+03, /* 0x45f52586 */ + 1.5040468750e+03, /* 0x44bc0180 */ +]; + +const PR3: [f32; 6] = [ + 3.0250391081e-09, /* 0x314fe10d */ + 1.1718686670e-01, /* 0x3defffab */ + 3.9329774380e+00, /* 0x407bb5e7 */ + 3.5119403839e+01, /* 0x420c7a45 */ + 9.1055007935e+01, /* 0x42b61c2a */ + 4.8559066772e+01, /* 0x42423c7c */ +]; +const PS3: [f32; 5] = [ + 3.4791309357e+01, /* 0x420b2a4d */ + 3.3676245117e+02, /* 0x43a86198 */ + 1.0468714600e+03, /* 0x4482dbe3 */ + 8.9081134033e+02, /* 0x445eb3ed */ + 1.0378793335e+02, /* 0x42cf936c */ +]; + +const PR2: [f32; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.0771083225e-07, /* 0x33e74ea8 */ + 1.1717621982e-01, /* 0x3deffa16 */ + 2.3685150146e+00, /* 0x401795c0 */ + 1.2242610931e+01, /* 0x4143e1bc */ + 1.7693971634e+01, /* 0x418d8d41 */ + 5.0735230446e+00, /* 0x40a25a4d */ +]; +const PS2: [f32; 5] = [ + 2.1436485291e+01, /* 0x41ab7dec */ + 1.2529022980e+02, /* 0x42fa9499 */ + 2.3227647400e+02, /* 0x436846c7 */ + 1.1767937469e+02, /* 0x42eb5bd7 */ + 8.3646392822e+00, /* 0x4105d590 */ +]; + +fn ponef(x: f32) -> f32 +{ + let p: &[f32; 6]; + let q: &[f32; 5]; + let z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 {p = &PR8; q = &PS8;} + else if ix >= 0x409173eb {p = &PR5; q = &PS5;} + else if ix >= 0x4036d917 {p = &PR3; q = &PS3;} + else /*ix >= 0x40000000*/{p = &PR2; q = &PS2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return 1.0 + r/s; +} + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +const QR8: [f32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -1.0253906250e-01, /* 0xbdd20000 */ + -1.6271753311e+01, /* 0xc1822c8d */ + -7.5960174561e+02, /* 0xc43de683 */ + -1.1849806641e+04, /* 0xc639273a */ + -4.8438511719e+04, /* 0xc73d3683 */ +]; +const QS8: [f32; 6] = [ + 1.6139537048e+02, /* 0x43216537 */ + 7.8253862305e+03, /* 0x45f48b17 */ + 1.3387534375e+05, /* 0x4802bcd6 */ + 7.1965775000e+05, /* 0x492fb29c */ + 6.6660125000e+05, /* 0x4922be94 */ + -2.9449025000e+05, /* 0xc88fcb48 */ +]; + +const QR5: [f32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.0897993405e-11, /* 0xadb7d219 */ + -1.0253904760e-01, /* 0xbdd1fffe */ + -8.0564479828e+00, /* 0xc100e736 */ + -1.8366960144e+02, /* 0xc337ab6b */ + -1.3731937256e+03, /* 0xc4aba633 */ + -2.6124443359e+03, /* 0xc523471c */ +]; +const QS5: [f32; 6] = [ + 8.1276550293e+01, /* 0x42a28d98 */ + 1.9917987061e+03, /* 0x44f8f98f */ + 1.7468484375e+04, /* 0x468878f8 */ + 4.9851425781e+04, /* 0x4742bb6d */ + 2.7948074219e+04, /* 0x46da5826 */ + -4.7191835938e+03, /* 0xc5937978 */ +]; + +const QR3: [f32; 6] = [ + -5.0783124372e-09, /* 0xb1ae7d4f */ + -1.0253783315e-01, /* 0xbdd1ff5b */ + -4.6101160049e+00, /* 0xc0938612 */ + -5.7847221375e+01, /* 0xc267638e */ + -2.2824453735e+02, /* 0xc3643e9a */ + -2.1921012878e+02, /* 0xc35b35cb */ +]; +const QS3: [f32; 6] = [ + 4.7665153503e+01, /* 0x423ea91e */ + 6.7386511230e+02, /* 0x4428775e */ + 3.3801528320e+03, /* 0x45534272 */ + 5.5477290039e+03, /* 0x45ad5dd5 */ + 1.9031191406e+03, /* 0x44ede3d0 */ + -1.3520118713e+02, /* 0xc3073381 */ +]; + +const QR2: [f32; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.7838172539e-07, /* 0xb43f8932 */ + -1.0251704603e-01, /* 0xbdd1f475 */ + -2.7522056103e+00, /* 0xc0302423 */ + -1.9663616180e+01, /* 0xc19d4f16 */ + -4.2325313568e+01, /* 0xc2294d1f */ + -2.1371921539e+01, /* 0xc1aaf9b2 */ +]; +const QS2: [f32; 6] = [ + 2.9533363342e+01, /* 0x41ec4454 */ + 2.5298155212e+02, /* 0x437cfb47 */ + 7.5750280762e+02, /* 0x443d602e */ + 7.3939318848e+02, /* 0x4438d92a */ + 1.5594900513e+02, /* 0x431bf2f2 */ + -4.9594988823e+00, /* 0xc09eb437 */ +]; + +fn qonef(x: f32) -> f32 +{ + let p: &[f32; 6]; + let q: &[f32; 6]; + let s: f32; + let r: f32; + let z: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 {p = &QR8; q = &QS8;} + else if ix >= 0x409173eb {p = &QR5; q = &QS5;} + else if ix >= 0x4036d917 {p = &QR3; q = &QS3;} + else /*ix >= 0x40000000*/{p = &QR2; q = &QS2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (0.375 + r/s)/x; +} diff --git a/library/compiler-builtins/libm/src/math/jn.rs b/library/compiler-builtins/libm/src/math/jn.rs new file mode 100644 index 0000000000000..7f7c06feed261 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/jn.rs @@ -0,0 +1,338 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_jn.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * jn(n, x), yn(n, x) + * floating point Bessel's function of the 1st and 2nd kind + * of order n + * + * Special cases: + * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal; + * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal. + * Note 2. About jn(n,x), yn(n,x) + * For n=0, j0(x) is called, + * for n=1, j1(x) is called, + * for n<=x, forward recursion is used starting + * from values of j0(x) and j1(x). + * for n>x, a continued fraction approximation to + * j(n,x)/j(n-1,x) is evaluated and then backward + * recursion is used starting from a supposed value + * for j(n,x). The resulting value of j(0,x) is + * compared with the actual value to correct the + * supposed value of j(n,x). + * + * yn(n,x) is similar in all respects, except + * that forward recursion is used for all + * values of n>1. + */ + +use super::{cos, fabs, get_high_word, get_low_word, log, j0, j1, sin, sqrt, y0, y1}; + +const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ + +pub fn jn(n: isize, mut x: f64) -> f64 +{ + let mut ix: u32; + let lx: u32; + let nm1: isize; + let mut i: isize; + let mut sign: bool; + let mut a: f64; + let mut b: f64; + let mut temp: f64; + + ix = get_high_word(x); + lx = get_low_word(x); + sign = (ix>>31) != 0; + ix &= 0x7fffffff; + + // -lx == !lx + 1 + if (ix | (lx|(!lx+1))>>31) > 0x7ff00000 { /* nan */ + return x; + } + + /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x) + * Thus, J(-n,x) = J(n,-x) + */ + /* nm1 = |n|-1 is used instead of |n| to handle n==INT_MIN */ + if n == 0 { + return j0(x); + } + if n < 0 { + nm1 = -(n+1); + x = -x; + sign = !sign; + } else { + nm1 = n-1; + } + if nm1 == 0 { + return j1(x); + } + + sign &= (n & 1) != 0; /* even n: 0, odd n: signbit(x) */ + x = fabs(x); + if (ix|lx) == 0 || ix == 0x7ff00000 { /* if x is 0 or inf */ + b = 0.0; + } else if (nm1 as f64) < x { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + if ix >= 0x52d00000 { /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + temp = match nm1&3 { + 0 => -cos(x)+sin(x), + 1 => -cos(x)-sin(x), + 2 => cos(x)-sin(x), + 3 | _ => cos(x)+sin(x), + }; + b = INVSQRTPI*temp/sqrt(x); + } else { + a = j0(x); + b = j1(x); + i = 0; + while i < nm1 { + i += 1; + temp = b; + b = b*(2.0*(i as f64)/x) - a; /* avoid underflow */ + a = temp; + } + } + } else { + if ix < 0x3e100000 { /* x < 2**-29 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if nm1 > 32 { /* underflow */ + b = 0.0; + } else { + temp = x*0.5; + b = temp; + a = 1.0; + i = 2; + while i <= nm1 + 1 { + a *= i as f64; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + i += 1; + } + b = b/a; + } + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + let mut t: f64; + let mut q0: f64; + let mut q1: f64; + let mut w: f64; + let h: f64; + let mut z: f64; + let mut tmp: f64; + let nf: f64; + + let mut k: isize; + + nf = (nm1 as f64) + 1.0; + w = 2.0*nf/x; + h = 2.0/x; + z = w+h; + q0 = w; + q1 = w*z - 1.0; + k = 1; + while q1 < 1.0e9 { + k += 1; + z += h; + tmp = z*q1 - q0; + q0 = q1; + q1 = tmp; + } + t = 0.0; + i = k; + while i >= 0 { + t = 1.0/(2.0*((i as f64)+nf)/x - t); + i -= 1; + } + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf*log(fabs(w)); + if tmp < 7.09782712893383973096e+02 { + i = nm1; + while i > 0 { + temp = b; + b = b*(2.0*(i as f64))/x - a; + a = temp; + i -= 1; + } + } else { + i = nm1; + while i > 0 { + temp = b; + b = b*(2.0*(i as f64))/x - a; + a = temp; + /* scale b to avoid spurious overflow */ + let x1p500 = f64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 + if b > x1p500 { + a /= b; + t /= b; + b = 1.0; + } + i -= 1; + } + } + z = j0(x); + w = j1(x); + if fabs(z) >= fabs(w) { + b = t*z/b; + } else { + b = t*w/a; + } + } + } + + if sign { + -b + } else { + b + } +} + + +pub fn yn(n: isize, x: f64) -> f64 +{ + let mut ix: u32; + let lx: u32; + let mut ib: u32; + let nm1: isize; + let mut sign: bool; + let mut i: isize; + let mut a: f64; + let mut b: f64; + let mut temp: f64; + + ix = get_high_word(x); + lx = get_low_word(x); + sign = (ix>>31) != 0; + ix &= 0x7fffffff; + + // -lx == !lx + 1 + if (ix | (lx|(!lx+1))>>31) > 0x7ff00000 { /* nan */ + return x; + } + if sign && (ix|lx) != 0 { /* x < 0 */ + return 0.0/0.0; + } + if ix == 0x7ff00000 { + return 0.0; + } + + if n == 0 { + return y0(x); + } + if n < 0 { + nm1 = -(n+1); + sign = (n&1) != 0; + } else { + nm1 = n-1; + sign = false; + } + if nm1 == 0 { + if sign { + return -y1(x); + } else { + return y1(x); + } + } + + if ix >= 0x52d00000 { /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + temp = match nm1&3 { + 0 => -sin(x)-cos(x), + 1 => -sin(x)+cos(x), + 2 => sin(x)+cos(x), + 3 | _ => sin(x)-cos(x), + }; + b = INVSQRTPI*temp/sqrt(x); + } else { + a = y0(x); + b = y1(x); + /* quit if b is -inf */ + ib = get_high_word(b); + i = 0; + while i < nm1 && ib != 0xfff00000 { + i += 1; + temp = b; + b = (2.0*(i as f64)/x)*b - a; + ib = get_high_word(b); + a = temp; + } + } + + if sign { + -b + } else { + b + } +} diff --git a/library/compiler-builtins/libm/src/math/jnf.rs b/library/compiler-builtins/libm/src/math/jnf.rs new file mode 100644 index 0000000000000..4cd848a03b078 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/jnf.rs @@ -0,0 +1,255 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_jnf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + +use super::{fabsf, j0f, j1f, logf, y0f, y1f}; + +pub fn jnf(n: isize, mut x: f32) -> f32 +{ + let mut ix: u32; + let mut nm1: isize; + let mut sign: bool; + let mut i: isize; + let mut a: f32; + let mut b: f32; + let mut temp: f32; + + ix = x.to_bits(); + sign = (ix>>31) != 0; + ix &= 0x7fffffff; + if ix > 0x7f800000 { /* nan */ + return x; + } + + /* J(-n,x) = J(n,-x), use |n|-1 to avoid overflow in -n */ + if n == 0 { + return j0f(x); + } + if n < 0 { + nm1 = -(n+1); + x = -x; + sign = !sign; + } else { + nm1 = n-1; + } + if nm1 == 0 { + return j1f(x); + } + + sign &= (n&1) != 0; /* even n: 0, odd n: signbit(x) */ + x = fabsf(x); + if ix == 0 || ix == 0x7f800000 { /* if x is 0 or inf */ + b = 0.0; + } else if (nm1 as f32) < x { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + a = j0f(x); + b = j1f(x); + i = 0; + while i < nm1 { + i += 1; + temp = b; + b = b*(2.0*(i as f32)/x) - a; + a = temp; + } + } else { + if ix < 0x35800000 { /* x < 2**-20 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if nm1 > 8 { /* underflow */ + nm1 = 8; + } + temp = 0.5 * x; + b = temp; + a = 1.0; + i = 2; + while i <= nm1 + 1 { + a *= i as f32; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + i += 1; + } + b = b/a; + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + let mut t: f32; + let mut q0: f32; + let mut q1: f32; + let mut w: f32; + let h: f32; + let mut z: f32; + let mut tmp: f32; + let nf: f32; + let mut k: isize; + + nf = (nm1 as f32)+1.0; + w = 2.0*(nf as f32)/x; + h = 2.0/x; + z = w+h; + q0 = w; + q1 = w*z - 1.0; + k = 1; + while q1 < 1.0e4 { + k += 1; + z += h; + tmp = z*q1 - q0; + q0 = q1; + q1 = tmp; + } + t = 0.0; + i = k; + while i >= 0 { + t = 1.0/(2.0*((i as f32)+nf)/x-t); + i -= 1; + } + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf*logf(fabsf(w)); + if tmp < 88.721679688 { + i = nm1; + while i > 0 { + temp = b; + b = 2.0*(i as f32)*b/x - a; + a = temp; + i -= 1; + } + } else { + i = nm1; + while i > 0 { + temp = b; + b = 2.0*(i as f32)*b/x - a; + a = temp; + /* scale b to avoid spurious overflow */ + let x1p60 = f32::from_bits(0x5d800000); // 0x1p60 == 2^60 + if b > x1p60 { + a /= b; + t /= b; + b = 1.0; + } + i -= 1; + } + } + z = j0f(x); + w = j1f(x); + if fabsf(z) >= fabsf(w) { + b = t*z/b; + } else { + b = t*w/a; + } + } + } + + if sign { + -b + } else { + b + } +} + +pub fn ynf(n: isize, x: f32) -> f32 +{ + let mut ix: u32; + let mut ib: u32; + let nm1: isize; + let mut sign: bool; + let mut i: isize; + let mut a: f32; + let mut b: f32; + let mut temp: f32; + + ix = x.to_bits(); + sign = (ix>>31) != 0; + ix &= 0x7fffffff; + if ix > 0x7f800000 { /* nan */ + return x; + } + if sign && ix != 0 { /* x < 0 */ + return 0.0/0.0; + } + if ix == 0x7f800000 { + return 0.0; + } + + if n == 0 { + return y0f(x); + } + if n < 0 { + nm1 = -(n+1); + sign = (n&1) != 0; + } else { + nm1 = n-1; + sign = false; + } + if nm1 == 0 { + if sign { + return -y1f(x); + } else { + return y1f(x); + } + } + + a = y0f(x); + b = y1f(x); + /* quit if b is -inf */ + ib = b.to_bits(); + i = 0; + while i < nm1 && ib != 0xff800000 { + i += 1; + temp = b; + b = (2.0*(i as f32)/x)*b - a; + ib = b.to_bits(); + a = temp; + } + + if sign { + -b + } else { + b + } +} diff --git a/library/compiler-builtins/libm/src/math/lgamma.rs b/library/compiler-builtins/libm/src/math/lgamma.rs new file mode 100644 index 0000000000000..35b25265214f5 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/lgamma.rs @@ -0,0 +1,309 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* lgamma_r(x, signgamp) + * Reentrant version of the logarithm of the Gamma function + * with user provide pointer for the sign of Gamma(x). + * + * Method: + * 1. Argument Reduction for 0 < x <= 8 + * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may + * reduce x to a number in [1.5,2.5] by + * lgamma(1+s) = log(s) + lgamma(s) + * for example, + * lgamma(7.3) = log(6.3) + lgamma(6.3) + * = log(6.3*5.3) + lgamma(5.3) + * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) + * 2. Polynomial approximation of lgamma around its + * minimun ymin=1.461632144968362245 to maintain monotonicity. + * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use + * Let z = x-ymin; + * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) + * where + * poly(z) is a 14 degree polynomial. + * 2. Rational approximation in the primary interval [2,3] + * We use the following approximation: + * s = x-2.0; + * lgamma(x) = 0.5*s + s*P(s)/Q(s) + * with accuracy + * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 + * Our algorithms are based on the following observation + * + * zeta(2)-1 2 zeta(3)-1 3 + * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... + * 2 3 + * + * where Euler = 0.5771... is the Euler constant, which is very + * close to 0.5. + * + * 3. For x>=8, we have + * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... + * (better formula: + * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) + * Let z = 1/x, then we approximation + * f(z) = lgamma(x) - (x-0.5)(log(x)-1) + * by + * 3 5 11 + * w = w0 + w1*z + w2*z + w3*z + ... + w6*z + * where + * |w - f(z)| < 2**-58.74 + * + * 4. For negative x, since (G is gamma function) + * -x*G(-x)*G(x) = PI/sin(PI*x), + * we have + * G(x) = PI/(sin(PI*x)*(-x)*G(-x)) + * since G(-x) is positive, sign(G(x)) = sign(sin(PI*x)) for x<0 + * Hence, for x<0, signgam = sign(sin(PI*x)) and + * lgamma(x) = log(|Gamma(x)|) + * = log(PI/(|x*sin(PI*x)|)) - lgamma(-x); + * Note: one should avoid compute PI*(-x) directly in the + * computation of sin(PI*(-x)). + * + * 5. Special Cases + * lgamma(2+s) ~ s*(1-Euler) for tiny s + * lgamma(1) = lgamma(2) = 0 + * lgamma(x) ~ -log(|x|) for tiny x + * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero + * lgamma(inf) = inf + * lgamma(-inf) = inf (bug for bug compatible with C99!?) + * + */ + +use super::{floor, k_cos, k_sin, log}; + +const PI: f64 = 3.14159265358979311600e+00; /* 0x400921FB, 0x54442D18 */ +const A0: f64 = 7.72156649015328655494e-02; /* 0x3FB3C467, 0xE37DB0C8 */ +const A1: f64 = 3.22467033424113591611e-01; /* 0x3FD4A34C, 0xC4A60FAD */ +const A2: f64 = 6.73523010531292681824e-02; /* 0x3FB13E00, 0x1A5562A7 */ +const A3: f64 = 2.05808084325167332806e-02; /* 0x3F951322, 0xAC92547B */ +const A4: f64 = 7.38555086081402883957e-03; /* 0x3F7E404F, 0xB68FEFE8 */ +const A5: f64 = 2.89051383673415629091e-03; /* 0x3F67ADD8, 0xCCB7926B */ +const A6: f64 = 1.19270763183362067845e-03; /* 0x3F538A94, 0x116F3F5D */ +const A7: f64 = 5.10069792153511336608e-04; /* 0x3F40B6C6, 0x89B99C00 */ +const A8: f64 = 2.20862790713908385557e-04; /* 0x3F2CF2EC, 0xED10E54D */ +const A9: f64 = 1.08011567247583939954e-04; /* 0x3F1C5088, 0x987DFB07 */ +const A10: f64 = 2.52144565451257326939e-05; /* 0x3EFA7074, 0x428CFA52 */ +const A11: f64 = 4.48640949618915160150e-05; /* 0x3F07858E, 0x90A45837 */ +const TC: f64 = 1.46163214496836224576e+00; /* 0x3FF762D8, 0x6356BE3F */ +const TF: f64 = -1.21486290535849611461e-01; /* 0xBFBF19B9, 0xBCC38A42 */ +/* tt = -(tail of TF) */ +const TT: f64 = -3.63867699703950536541e-18; /* 0xBC50C7CA, 0xA48A971F */ +const T0: f64 = 4.83836122723810047042e-01; /* 0x3FDEF72B, 0xC8EE38A2 */ +const T1: f64 = -1.47587722994593911752e-01; /* 0xBFC2E427, 0x8DC6C509 */ +const T2: f64 = 6.46249402391333854778e-02; /* 0x3FB08B42, 0x94D5419B */ +const T3: f64 = -3.27885410759859649565e-02; /* 0xBFA0C9A8, 0xDF35B713 */ +const T4: f64 = 1.79706750811820387126e-02; /* 0x3F9266E7, 0x970AF9EC */ +const T5: f64 = -1.03142241298341437450e-02; /* 0xBF851F9F, 0xBA91EC6A */ +const T6: f64 = 6.10053870246291332635e-03; /* 0x3F78FCE0, 0xE370E344 */ +const T7: f64 = -3.68452016781138256760e-03; /* 0xBF6E2EFF, 0xB3E914D7 */ +const T8: f64 = 2.25964780900612472250e-03; /* 0x3F6282D3, 0x2E15C915 */ +const T9: f64 = -1.40346469989232843813e-03; /* 0xBF56FE8E, 0xBF2D1AF1 */ +const T10: f64 = 8.81081882437654011382e-04; /* 0x3F4CDF0C, 0xEF61A8E9 */ +const T11: f64 = -5.38595305356740546715e-04; /* 0xBF41A610, 0x9C73E0EC */ +const T12: f64 = 3.15632070903625950361e-04; /* 0x3F34AF6D, 0x6C0EBBF7 */ +const T13: f64 = -3.12754168375120860518e-04; /* 0xBF347F24, 0xECC38C38 */ +const T14: f64 = 3.35529192635519073543e-04; /* 0x3F35FD3E, 0xE8C2D3F4 */ +const U0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ +const U1: f64 = 6.32827064025093366517e-01; /* 0x3FE4401E, 0x8B005DFF */ +const U2: f64 = 1.45492250137234768737e+00; /* 0x3FF7475C, 0xD119BD6F */ +const U3: f64 = 9.77717527963372745603e-01; /* 0x3FEF4976, 0x44EA8450 */ +const U4: f64 = 2.28963728064692451092e-01; /* 0x3FCD4EAE, 0xF6010924 */ +const U5: f64 = 1.33810918536787660377e-02; /* 0x3F8B678B, 0xBF2BAB09 */ +const V1: f64 = 2.45597793713041134822e+00; /* 0x4003A5D7, 0xC2BD619C */ +const V2: f64 = 2.12848976379893395361e+00; /* 0x40010725, 0xA42B18F5 */ +const V3: f64 = 7.69285150456672783825e-01; /* 0x3FE89DFB, 0xE45050AF */ +const V4: f64 = 1.04222645593369134254e-01; /* 0x3FBAAE55, 0xD6537C88 */ +const V5: f64 = 3.21709242282423911810e-03; /* 0x3F6A5ABB, 0x57D0CF61 */ +const S0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ +const S1: f64 = 2.14982415960608852501e-01; /* 0x3FCB848B, 0x36E20878 */ +const S2: f64 = 3.25778796408930981787e-01; /* 0x3FD4D98F, 0x4F139F59 */ +const S3: f64 = 1.46350472652464452805e-01; /* 0x3FC2BB9C, 0xBEE5F2F7 */ +const S4: f64 = 2.66422703033638609560e-02; /* 0x3F9B481C, 0x7E939961 */ +const S5: f64 = 1.84028451407337715652e-03; /* 0x3F5E26B6, 0x7368F239 */ +const S6: f64 = 3.19475326584100867617e-05; /* 0x3F00BFEC, 0xDD17E945 */ +const R1: f64 = 1.39200533467621045958e+00; /* 0x3FF645A7, 0x62C4AB74 */ +const R2: f64 = 7.21935547567138069525e-01; /* 0x3FE71A18, 0x93D3DCDC */ +const R3: f64 = 1.71933865632803078993e-01; /* 0x3FC601ED, 0xCCFBDF27 */ +const R4: f64 = 1.86459191715652901344e-02; /* 0x3F9317EA, 0x742ED475 */ +const R5: f64 = 7.77942496381893596434e-04; /* 0x3F497DDA, 0xCA41A95B */ +const R6: f64 = 7.32668430744625636189e-06; /* 0x3EDEBAF7, 0xA5B38140 */ +const W0: f64 = 4.18938533204672725052e-01; /* 0x3FDACFE3, 0x90C97D69 */ +const W1: f64 = 8.33333333333329678849e-02; /* 0x3FB55555, 0x5555553B */ +const W2: f64 = -2.77777777728775536470e-03; /* 0xBF66C16C, 0x16B02E5C */ +const W3: f64 = 7.93650558643019558500e-04; /* 0x3F4A019F, 0x98CF38B6 */ +const W4: f64 = -5.95187557450339963135e-04; /* 0xBF4380CB, 0x8C0FE741 */ +const W5: f64 = 8.36339918996282139126e-04; /* 0x3F4B67BA, 0x4CDAD5D1 */ +const W6: f64 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ + +/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ +fn sin_pi(mut x: f64) -> f64 +{ + let mut n: isize; + + /* spurious inexact if odd int */ + x = 2.0*(x*0.5 - floor(x*0.5)); /* x mod 2.0 */ + + n = (x*4.0) as isize; + n = (n+1)/2; + x -= (n as f64)*0.5; + x *= PI; + + match n { + 1 => k_cos(x, 0.0), + 2 => k_sin(-x, 0.0, 0), + 3 => -k_cos(x, 0.0), + 0|_ => k_sin(x, 0.0, 0), + } +} + +pub fn lgamma(x: f64) -> f64 { + lgamma_r(x).0 +} + +pub fn lgamma_r(mut x: f64) -> (f64, isize) +{ + let u: u64 = x.to_bits(); + let mut t: f64; + let y: f64; + let mut z: f64; + let nadj: f64; + let p: f64; + let p1: f64; + let p2: f64; + let p3: f64; + let q: f64; + let mut r: f64; + let w: f64; + let ix: u32; + let sign: bool; + let i: isize; + let mut signgam: isize; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + signgam = 1; + sign = (u>>63) != 0; + ix = ((u>>32) as u32) & 0x7fffffff; + if ix >= 0x7ff00000 { + return (x*x, signgam); + } + if ix < (0x3ff-70)<<20 { /* |x|<2**-70, return -log(|x|) */ + if sign { + x = -x; + signgam = -1; + } + return (-log(x), signgam); + } + if sign { + x = -x; + t = sin_pi(x); + if t == 0.0 { /* -integer */ + return (1.0/(x-x), signgam); + } + if t > 0.0 { + signgam = -1; + } else { + t = -t; + } + nadj = log(PI/(t*x)); + } else { + nadj = 0.0; + } + + /* purge off 1 and 2 */ + if (ix == 0x3ff00000 || ix == 0x40000000) && (u & 0xffffffff) == 0 { + r = 0.0; + } + /* for x < 2.0 */ + else if ix < 0x40000000 { + if ix <= 0x3feccccc { /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -log(x); + if ix >= 0x3FE76944 { + y = 1.0 - x; + i = 0; + } else if ix >= 0x3FCDA661 { + y = x - (TC-1.0); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0; + if ix >= 0x3FFBB4C3 { /* [1.7316,2] */ + y = 2.0 - x; + i = 0; + } else if ix >= 0x3FF3B4C4 { /* [1.23,1.73] */ + y = x - TC; + i = 1; + } else { + y = x - 1.0; + i = 2; + } + } + match i { + 0 => { + z = y*y; + p1 = A0+z*(A2+z*(A4+z*(A6+z*(A8+z*A10)))); + p2 = z*(A1+z*(A3+z*(A5+z*(A7+z*(A9+z*A11))))); + p = y*p1+p2; + r += p-0.5*y; + } + 1 => { + z = y*y; + w = z*y; + p1 = T0+w*(T3+w*(T6+w*(T9 +w*T12))); /* parallel comp */ + p2 = T1+w*(T4+w*(T7+w*(T10+w*T13))); + p3 = T2+w*(T5+w*(T8+w*(T11+w*T14))); + p = z*p1-(TT-w*(p2+y*p3)); + r += TF + p; + } + 2 => { + p1 = y*(U0+y*(U1+y*(U2+y*(U3+y*(U4+y*U5))))); + p2 = 1.0+y*(V1+y*(V2+y*(V3+y*(V4+y*V5)))); + r += -0.5*y + p1/p2; + } + #[cfg(feature = "checked")] + _ => unreachable!(), + #[cfg(not(feature = "checked"))] + _ => {} + } + } else if ix < 0x40200000 { /* x < 8.0 */ + i = x as isize; + y = x - (i as f64); + p = y*(S0+y*(S1+y*(S2+y*(S3+y*(S4+y*(S5+y*S6)))))); + q = 1.0+y*(R1+y*(R2+y*(R3+y*(R4+y*(R5+y*R6))))); + r = 0.5*y+p/q; + z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ + // TODO: In C, this was implemented using switch jumps with fallthrough. + // Does this implementation have performance problems? + if i >= 7 { z *= y + 6.0; } + if i >= 6 { z *= y + 5.0; } + if i >= 5 { z *= y + 4.0; } + if i >= 4 { z *= y + 3.0; } + if i >= 3 { + z *= y + 2.0; + r += log(z); + } + } else if ix < 0x43900000 { /* 8.0 <= x < 2**58 */ + t = log(x); + z = 1.0/x; + y = z*z; + w = W0+z*(W1+y*(W2+y*(W3+y*(W4+y*(W5+y*W6))))); + r = (x-0.5)*(t-1.0)+w; + } else { /* 2**58 <= x <= inf */ + r = x*(log(x)-1.0); + } + if sign { + r = nadj - r; + } + return (r, signgam); +} diff --git a/library/compiler-builtins/libm/src/math/lgammaf.rs b/library/compiler-builtins/libm/src/math/lgammaf.rs new file mode 100644 index 0000000000000..60effa316740c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/lgammaf.rs @@ -0,0 +1,244 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + +use super::{floorf, k_cosf, k_sinf, logf}; + +const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ +const A0: f32 = 7.7215664089e-02; /* 0x3d9e233f */ +const A1: f32 = 3.2246702909e-01; /* 0x3ea51a66 */ +const A2: f32 = 6.7352302372e-02; /* 0x3d89f001 */ +const A3: f32 = 2.0580807701e-02; /* 0x3ca89915 */ +const A4: f32 = 7.3855509982e-03; /* 0x3bf2027e */ +const A5: f32 = 2.8905137442e-03; /* 0x3b3d6ec6 */ +const A6: f32 = 1.1927076848e-03; /* 0x3a9c54a1 */ +const A7: f32 = 5.1006977446e-04; /* 0x3a05b634 */ +const A8: f32 = 2.2086278477e-04; /* 0x39679767 */ +const A9: f32 = 1.0801156895e-04; /* 0x38e28445 */ +const A10: f32 = 2.5214456400e-05; /* 0x37d383a2 */ +const A11: f32 = 4.4864096708e-05; /* 0x383c2c75 */ +const TC: f32 = 1.4616321325e+00; /* 0x3fbb16c3 */ +const TF: f32 = -1.2148628384e-01; /* 0xbdf8cdcd */ +/* TT = -(tail of TF) */ +const TT: f32 = 6.6971006518e-09; /* 0x31e61c52 */ +const T0: f32 = 4.8383611441e-01; /* 0x3ef7b95e */ +const T1: f32 = -1.4758771658e-01; /* 0xbe17213c */ +const T2: f32 = 6.4624942839e-02; /* 0x3d845a15 */ +const T3: f32 = -3.2788541168e-02; /* 0xbd064d47 */ +const T4: f32 = 1.7970675603e-02; /* 0x3c93373d */ +const T5: f32 = -1.0314224288e-02; /* 0xbc28fcfe */ +const T6: f32 = 6.1005386524e-03; /* 0x3bc7e707 */ +const T7: f32 = -3.6845202558e-03; /* 0xbb7177fe */ +const T8: f32 = 2.2596477065e-03; /* 0x3b141699 */ +const T9: f32 = -1.4034647029e-03; /* 0xbab7f476 */ +const T10: f32 = 8.8108185446e-04; /* 0x3a66f867 */ +const T11: f32 = -5.3859531181e-04; /* 0xba0d3085 */ +const T12: f32 = 3.1563205994e-04; /* 0x39a57b6b */ +const T13: f32 = -3.1275415677e-04; /* 0xb9a3f927 */ +const T14: f32 = 3.3552918467e-04; /* 0x39afe9f7 */ +const U0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ +const U1: f32 = 6.3282704353e-01; /* 0x3f2200f4 */ +const U2: f32 = 1.4549225569e+00; /* 0x3fba3ae7 */ +const U3: f32 = 9.7771751881e-01; /* 0x3f7a4bb2 */ +const U4: f32 = 2.2896373272e-01; /* 0x3e6a7578 */ +const U5: f32 = 1.3381091878e-02; /* 0x3c5b3c5e */ +const V1: f32 = 2.4559779167e+00; /* 0x401d2ebe */ +const V2: f32 = 2.1284897327e+00; /* 0x4008392d */ +const V3: f32 = 7.6928514242e-01; /* 0x3f44efdf */ +const V4: f32 = 1.0422264785e-01; /* 0x3dd572af */ +const V5: f32 = 3.2170924824e-03; /* 0x3b52d5db */ +const S0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ +const S1: f32 = 2.1498242021e-01; /* 0x3e5c245a */ +const S2: f32 = 3.2577878237e-01; /* 0x3ea6cc7a */ +const S3: f32 = 1.4635047317e-01; /* 0x3e15dce6 */ +const S4: f32 = 2.6642270386e-02; /* 0x3cda40e4 */ +const S5: f32 = 1.8402845599e-03; /* 0x3af135b4 */ +const S6: f32 = 3.1947532989e-05; /* 0x3805ff67 */ +const R1: f32 = 1.3920053244e+00; /* 0x3fb22d3b */ +const R2: f32 = 7.2193557024e-01; /* 0x3f38d0c5 */ +const R3: f32 = 1.7193385959e-01; /* 0x3e300f6e */ +const R4: f32 = 1.8645919859e-02; /* 0x3c98bf54 */ +const R5: f32 = 7.7794247773e-04; /* 0x3a4beed6 */ +const R6: f32 = 7.3266842264e-06; /* 0x36f5d7bd */ +const W0: f32 = 4.1893854737e-01; /* 0x3ed67f1d */ +const W1: f32 = 8.3333335817e-02; /* 0x3daaaaab */ +const W2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ +const W3: f32 = 7.9365057172e-04; /* 0x3a500cfd */ +const W4: f32 = -5.9518753551e-04; /* 0xba1c065c */ +const W5: f32 = 8.3633989561e-04; /* 0x3a5b3dd2 */ +const W6: f32 = -1.6309292987e-03; /* 0xbad5c4e8 */ + +/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ +fn sin_pi(mut x: f32) -> f32 +{ + let mut y: f64; + let mut n: isize; + + /* spurious inexact if odd int */ + x = 2.0*(x*0.5 - floorf(x*0.5)); /* x mod 2.0 */ + + n = (x*4.0) as isize; + n = (n+1)/2; + y = (x as f64) - (n as f64)*0.5; + y *= 3.14159265358979323846; + match n { + 1 => k_cosf(y), + 2 => k_sinf(-y), + 3 => -k_cosf(y), + 0|_ => k_sinf(y), + } +} + +pub fn lgammaf(x: f32) -> f32 { + lgammaf_r(x).0 +} + +pub fn lgammaf_r(mut x: f32) -> (f32, isize) +{ + let u = x.to_bits(); + let mut t: f32; + let y: f32; + let mut z: f32; + let nadj: f32; + let p: f32; + let p1: f32; + let p2: f32; + let p3: f32; + let q: f32; + let mut r: f32; + let w: f32; + let ix: u32; + let i: isize; + let sign: bool; + let mut signgam: isize; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + signgam = 1; + sign = (u>>31) != 0; + ix = u & 0x7fffffff; + if ix >= 0x7f800000 { + return (x*x, signgam); + } + if ix < 0x35000000 { /* |x| < 2**-21, return -log(|x|) */ + if sign { + signgam = -1; + x = -x; + } + return (-logf(x), signgam); + } + if sign { + x = -x; + t = sin_pi(x); + if t == 0.0 { /* -integer */ + return (1.0/(x-x), signgam); + } + if t > 0.0 { + signgam = -1; + } else { + t = -t; + } + nadj = logf(PI/(t*x)); + } else { + nadj = 0.0; + } + + /* purge off 1 and 2 */ + if ix == 0x3f800000 || ix == 0x40000000 { + r = 0.0; + } + /* for x < 2.0 */ + else if ix < 0x40000000 { + if ix <= 0x3f666666 { /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -logf(x); + if ix >= 0x3f3b4a20 { + y = 1.0 - x; + i = 0; + } else if ix >= 0x3e6d3308 { + y = x - (TC-1.0); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0; + if ix >= 0x3fdda618 { /* [1.7316,2] */ + y = 2.0 - x; + i = 0; + } else if ix >= 0x3F9da620 { /* [1.23,1.73] */ + y = x - TC; + i = 1; + } else { + y = x - 1.0; + i = 2; + } + } + match i { + 0 => { + z = y*y; + p1 = A0+z*(A2+z*(A4+z*(A6+z*(A8+z*A10)))); + p2 = z*(A1+z*(A3+z*(A5+z*(A7+z*(A9+z*A11))))); + p = y*p1+p2; + r += p - 0.5*y; + } + 1 => { + z = y*y; + w = z*y; + p1 = T0+w*(T3+w*(T6+w*(T9 +w*T12))); /* parallel comp */ + p2 = T1+w*(T4+w*(T7+w*(T10+w*T13))); + p3 = T2+w*(T5+w*(T8+w*(T11+w*T14))); + p = z*p1-(TT-w*(p2+y*p3)); + r += TF + p; + } + 2 => { + p1 = y*(U0+y*(U1+y*(U2+y*(U3+y*(U4+y*U5))))); + p2 = 1.0+y*(V1+y*(V2+y*(V3+y*(V4+y*V5)))); + r += -0.5*y + p1/p2; + } + #[cfg(feature = "checked")] + _ => unreachable!(), + #[cfg(not(feature = "checked"))] + _ => {} + } + } else if ix < 0x41000000 { /* x < 8.0 */ + i = x as isize; + y = x - (i as f32); + p = y*(S0+y*(S1+y*(S2+y*(S3+y*(S4+y*(S5+y*S6)))))); + q = 1.0+y*(R1+y*(R2+y*(R3+y*(R4+y*(R5+y*R6))))); + r = 0.5*y+p/q; + z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ + // TODO: In C, this was implemented using switch jumps with fallthrough. + // Does this implementation have performance problems? + if i >= 7 { z *= y + 6.0; } + if i >= 6 { z *= y + 5.0; } + if i >= 5 { z *= y + 4.0; } + if i >= 4 { z *= y + 3.0; } + if i >= 3 { + z *= y + 2.0; + r += logf(z); + } + } else if ix < 0x5c800000 { /* 8.0 <= x < 2**58 */ + t = logf(x); + z = 1.0/x; + y = z*z; + w = W0+z*(W1+y*(W2+y*(W3+y*(W4+y*(W5+y*W6))))); + r = (x-0.5)*(t-1.0)+w; + } else { /* 2**58 <= x <= inf */ + r = x*(logf(x)-1.0); + } + if sign { + r = nadj - r; + } + return (r, signgam); +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index da34fb4cecd1d..53842b38e99a2 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -61,21 +61,33 @@ macro_rules! i { // Public modules mod acos; mod acosf; +mod acosh; +mod acoshf; mod asin; mod asinf; +mod asinh; +mod asinhf; mod atan; mod atan2; mod atan2f; mod atanf; +mod atanh; +mod atanhf; mod cbrt; mod cbrtf; mod ceil; mod ceilf; +mod copysign; +mod copysignf; mod cos; mod cosf; mod cosh; mod coshf; +mod erf; +mod erff; mod exp; +mod exp10; +mod exp10f; mod exp2; mod exp2f; mod expf; @@ -91,8 +103,20 @@ mod fma; mod fmaf; mod fmod; mod fmodf; +mod frexp; +mod frexpf; mod hypot; mod hypotf; +mod ilogb; +mod ilogbf; +mod j0; +mod j0f; +mod j1; +mod j1f; +mod jn; +mod jnf; +mod lgamma; +mod lgammaf; mod log; mod log10; mod log10f; @@ -101,13 +125,19 @@ mod log1pf; mod log2; mod log2f; mod logf; +mod modf; +mod modff; mod pow; mod powf; +mod remquo; +mod remquof; mod round; mod roundf; mod scalbn; mod scalbnf; mod sin; +mod sincos; +mod sincosf; mod sinf; mod sinh; mod sinhf; @@ -117,27 +147,43 @@ mod tan; mod tanf; mod tanh; mod tanhf; +mod tgamma; +mod tgammaf; mod trunc; mod truncf; // Use separated imports instead of {}-grouped imports for easier merging. pub use self::acos::acos; pub use self::acosf::acosf; +pub use self::acosh::acosh; +pub use self::acoshf::acoshf; pub use self::asin::asin; pub use self::asinf::asinf; +pub use self::asinh::asinh; +pub use self::asinhf::asinhf; pub use self::atan::atan; pub use self::atan2::atan2; pub use self::atan2f::atan2f; pub use self::atanf::atanf; +pub use self::atanh::atanh; +pub use self::atanhf::atanhf; pub use self::cbrt::cbrt; pub use self::cbrtf::cbrtf; pub use self::ceil::ceil; pub use self::ceilf::ceilf; +pub use self::copysign::copysign; +pub use self::copysignf::copysignf; pub use self::cos::cos; pub use self::cosf::cosf; pub use self::cosh::cosh; pub use self::coshf::coshf; +pub use self::erf::erf; +pub use self::erf::erfc; +pub use self::erff::erff; +pub use self::erff::erfcf; pub use self::exp::exp; +pub use self::exp10::exp10; +pub use self::exp10f::exp10f; pub use self::exp2::exp2; pub use self::exp2f::exp2f; pub use self::expf::expf; @@ -153,8 +199,28 @@ pub use self::fma::fma; pub use self::fmaf::fmaf; pub use self::fmod::fmod; pub use self::fmodf::fmodf; +pub use self::frexp::frexp; +pub use self::frexpf::frexpf; pub use self::hypot::hypot; pub use self::hypotf::hypotf; +pub use self::ilogb::ilogb; +pub use self::ilogbf::ilogbf; +pub use self::j0::j0; +pub use self::j0::y0; +pub use self::j0f::j0f; +pub use self::j0f::y0f; +pub use self::j1::j1; +pub use self::j1::y1; +pub use self::j1f::j1f; +pub use self::j1f::y1f; +pub use self::jn::jn; +pub use self::jn::yn; +pub use self::jnf::jnf; +pub use self::jnf::ynf; +pub use self::lgamma::lgamma; +pub use self::lgamma::lgamma_r; +pub use self::lgammaf::lgammaf; +pub use self::lgammaf::lgammaf_r; pub use self::log::log; pub use self::log10::log10; pub use self::log10f::log10f; @@ -163,13 +229,19 @@ pub use self::log1pf::log1pf; pub use self::log2::log2; pub use self::log2f::log2f; pub use self::logf::logf; +pub use self::modf::modf; +pub use self::modff::modff; pub use self::pow::pow; pub use self::powf::powf; +pub use self::remquo::remquo; +pub use self::remquof::remquof; pub use self::round::round; pub use self::roundf::roundf; pub use self::scalbn::scalbn; pub use self::scalbnf::scalbnf; pub use self::sin::sin; +pub use self::sincos::sincos; +pub use self::sincosf::sincosf; pub use self::sinf::sinf; pub use self::sinh::sinh; pub use self::sinhf::sinhf; @@ -179,6 +251,8 @@ pub use self::tan::tan; pub use self::tanf::tanf; pub use self::tanh::tanh; pub use self::tanhf::tanhf; +pub use self::tgamma::tgamma; +pub use self::tgammaf::tgammaf; pub use self::trunc::trunc; pub use self::truncf::truncf; diff --git a/library/compiler-builtins/libm/src/math/modf.rs b/library/compiler-builtins/libm/src/math/modf.rs new file mode 100644 index 0000000000000..1ff8ee116d0c7 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/modf.rs @@ -0,0 +1,33 @@ +pub fn modf(x: f64) -> (f64, f64) { + let rv2: f64; + let mut u = x.to_bits(); + let mask: u64; + let e = ((u>>52 & 0x7ff) as isize) - 0x3ff; + + /* no fractional part */ + if e >= 52 { + rv2 = x; + if e == 0x400 && (u<<12) != 0 { /* nan */ + return (x, rv2); + } + u &= 1<<63; + return (f64::from_bits(u), rv2); + } + + /* no integral part*/ + if e < 0 { + u &= 1<<63; + rv2 = f64::from_bits(u); + return (x, rv2); + } + + mask = ((!0)>>12)>>e; + if (u & mask) == 0 { + rv2 = x; + u &= 1<<63; + return (f64::from_bits(u), rv2); + } + u &= !mask; + rv2 = f64::from_bits(u); + return (x - rv2, rv2); +} diff --git a/library/compiler-builtins/libm/src/math/modff.rs b/library/compiler-builtins/libm/src/math/modff.rs new file mode 100644 index 0000000000000..5250e8d380104 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/modff.rs @@ -0,0 +1,32 @@ +pub fn modff(x: f32) -> (f32, f32) { + let rv2: f32; + let mut u: u32 = x.to_bits(); + let mask: u32; + let e = ((u>>23 & 0xff) as isize) - 0x7f; + + /* no fractional part */ + if e >= 23 { + rv2 = x; + if e == 0x80 && (u<<9) != 0 { /* nan */ + return (x, rv2); + } + u &= 0x80000000; + return (f32::from_bits(u), rv2); + } + /* no integral part */ + if e < 0 { + u &= 0x80000000; + rv2 = f32::from_bits(u); + return (x, rv2); + } + + mask = 0x007fffff>>e; + if (u & mask) == 0 { + rv2 = x; + u &= 0x80000000; + return (f32::from_bits(u), rv2); + } + u &= !mask; + rv2 = f32::from_bits(u); + return (x - rv2, rv2); +} diff --git a/library/compiler-builtins/libm/src/math/remquo.rs b/library/compiler-builtins/libm/src/math/remquo.rs new file mode 100644 index 0000000000000..98f4b38581a5a --- /dev/null +++ b/library/compiler-builtins/libm/src/math/remquo.rs @@ -0,0 +1,98 @@ +pub fn remquo(mut x: f64, mut y: f64) -> (f64, isize) +{ + let ux: u64 = x.to_bits(); + let mut uy: u64 = y.to_bits(); + let mut ex = ((ux>>52) & 0x7ff) as isize; + let mut ey = ((uy>>52) & 0x7ff) as isize; + let sx = (ux>>63) != 0; + let sy = (uy>>63) != 0; + let mut q: u32; + let mut i: u64; + let mut uxi: u64 = ux; + + if (uy<<1) == 0 || y.is_nan() || ex == 0x7ff { + return ((x*y)/(x*y), 0); + } + if (ux<<1) == 0 { + return (x, 0); + } + + /* normalize x and y */ + if ex == 0 { + i = uxi << 12; + while (i>>63) == 0 { + ex -= 1; + i <<= 1; + } + uxi <<= -ex + 1; + } else { + uxi &= (!0) >> 12; + uxi |= 1 << 52; + } + if ey == 0 { + i = uy<<12; + while (i>>63) == 0 { + ey -= 1; + i <<= 1; + } + uy <<= -ey + 1; + } else { + uy &= (!0) >> 12; + uy |= 1 << 52; + } + + q = 0; + + if ex+1 != ey { + if ex < ey { + return (x, 0); + } + /* x mod y */ + while ex > ey { + i = uxi - uy; + if (i>>63) == 0 { + uxi = i; + q += 1; + } + uxi <<= 1; + q <<= 1; + ex -= 1; + } + i = uxi - uy; + if (i>>63) == 0 { + uxi = i; + q += 1; + } + if uxi == 0 { + ex = -60; + } else { + while (uxi>>52) == 0 { + uxi <<= 1; + ex -= 1; + } + } + } + + /* scale result and decide between |x| and |x|-|y| */ + if ex > 0 { + uxi -= 1 << 52; + uxi |= (ex as u64) << 52; + } else { + uxi >>= -ex + 1; + } + x = f64::from_bits(uxi); + if sy { + y = -y; + } + if ex == ey || (ex+1 == ey && (2.0*x > y || (2.0*x == y && (q%2) != 0))) { + x -= y; + q += 1; + } + q &= 0x7fffffff; + let quo = if sx ^ sy { -(q as isize) } else { q as isize }; + if sx { + (-x, quo) + } else { + (x, quo) + } +} diff --git a/library/compiler-builtins/libm/src/math/remquof.rs b/library/compiler-builtins/libm/src/math/remquof.rs new file mode 100644 index 0000000000000..4307e19066521 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/remquof.rs @@ -0,0 +1,97 @@ +pub fn remquof(mut x: f32, mut y: f32) -> (f32, isize) +{ + let ux: u32 = x.to_bits(); + let mut uy: u32 = y.to_bits(); + let mut ex = ((ux>>23) & 0xff) as isize; + let mut ey = ((uy>>23) & 0xff) as isize; + let sx = (ux>>31) != 0; + let sy = (uy>>31) != 0; + let mut q: u32; + let mut i: u32; + let mut uxi: u32 = ux; + + if (uy<<1) == 0 || y.is_nan() || ex == 0xff { + return ((x*y)/(x*y), 0); + } + if (ux<<1) == 0 { + return (x, 0); + } + + /* normalize x and y */ + if ex == 0 { + i = uxi<<9; + while (i>>31) == 0 { + ex -= 1; + i <<= 1; + } + uxi <<= -ex + 1; + } else { + uxi &= (!0) >> 9; + uxi |= 1 << 23; + } + if ey == 0 { + i = uy<<9; + while (i>>31) == 0 { + ey -= 1; + i <<= 1; + } + uy <<= -ey + 1; + } else { + uy &= (!0) >> 9; + uy |= 1 << 23; + } + + q = 0; + if ex+1 != ey { + if ex < ey { + return (x, 0); + } + /* x mod y */ + while ex > ey { + i = uxi - uy; + if (i>>31) == 0 { + uxi = i; + q += 1; + } + uxi <<= 1; + q <<= 1; + ex -= 1; + } + i = uxi - uy; + if (i>>31) == 0 { + uxi = i; + q += 1; + } + if uxi == 0 { + ex = -30; + } else { + while (uxi>>23) == 0 { + uxi <<= 1; + ex -= 1; + } + } + } + + /* scale result and decide between |x| and |x|-|y| */ + if ex > 0 { + uxi -= 1 << 23; + uxi |= (ex as u32) << 23; + } else { + uxi >>= -ex + 1; + } + x = f32::from_bits(uxi); + if sy { + y = -y; + } + if ex == ey || (ex+1 == ey && (2.0*x > y || (2.0*x == y && (q%2) != 0))) { + x -= y; + q += 1; + } + q &= 0x7fffffff; + let quo = if sx^sy { -(q as isize) } else { q as isize }; + if sx { + (-x, quo) + } else { + (x, quo) + } +} diff --git a/library/compiler-builtins/libm/src/math/sincos.rs b/library/compiler-builtins/libm/src/math/sincos.rs new file mode 100644 index 0000000000000..c15ee4661f646 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sincos.rs @@ -0,0 +1,60 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.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. + * ==================================================== + */ + +use super::{get_high_word, k_cos, k_sin, rem_pio2}; + +pub fn sincos(x: f64) -> (f64, f64) +{ + let s: f64; + let c: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + + /* |x| ~< pi/4 */ + if ix <= 0x3fe921fb { + /* if |x| < 2**-27 * sqrt(2) */ + if ix < 0x3e46a09e { + /* raise inexact if x!=0 and underflow if subnormal */ + let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120 == 2^120 + if ix < 0x00100000 { + force_eval!(x/x1p120); + } else { + force_eval!(x+x1p120); + } + return (x, 1.0); + } + return (k_sin(x, 0.0, 0), k_cos(x, 0.0)); + } + + /* sincos(Inf or NaN) is NaN */ + if ix >= 0x7ff00000 { + let rv = x - x; + return (rv, rv); + } + + /* argument reduction needed */ + let (n, y0, y1) = rem_pio2(x); + s = k_sin(y0, y1, 1); + c = k_cos(y0, y1); + match n&3 { + 0 => (s, c), + 1 => (c, -s), + 2 => (-s, -c), + 3 => (-c, s), + #[cfg(feature = "checked")] + _ => unreachable!(), + #[cfg(not(feature = "checked"))] + _ => (0.0, 1.0), + } +} diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs new file mode 100644 index 0000000000000..911421d63d4b0 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sincosf.rs @@ -0,0 +1,122 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + +use super::{k_cosf, k_sinf, rem_pio2f}; + +/* Small multiples of pi/2 rounded to double precision. */ +const PI_2: f32 = 0.5 * 3.1415926535897931160E+00; +const S1PIO2: f32 = 1.0*PI_2; /* 0x3FF921FB, 0x54442D18 */ +const S2PIO2: f32 = 2.0*PI_2; /* 0x400921FB, 0x54442D18 */ +const S3PIO2: f32 = 3.0*PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const S4PIO2: f32 = 4.0*PI_2; /* 0x401921FB, 0x54442D18 */ + +pub fn sincosf(x: f32) -> (f32, f32) +{ + let s: f32; + let c: f32; + let mut ix: u32; + let sign: bool; + + ix = x.to_bits(); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + /* |x| ~<= pi/4 */ + if ix <= 0x3f490fda { + /* |x| < 2**-12 */ + if ix < 0x39800000 { + /* raise inexact if x!=0 and underflow if subnormal */ + + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120 == 2^120 + if ix < 0x00100000 { + force_eval!(x/x1p120); + } else { + force_eval!(x+x1p120); + } + return (x, 1.0); + } + return (k_sinf(x as f64), k_cosf(x as f64)); + } + + /* |x| ~<= 5*pi/4 */ + if ix <= 0x407b53d1 { + if ix <= 0x4016cbe3 { /* |x| ~<= 3pi/4 */ + if sign { + s = -k_cosf((x + S1PIO2) as f64); + c = k_sinf((x + S1PIO2) as f64); + } else { + s = k_cosf((S1PIO2 - x) as f64); + c = k_sinf((S1PIO2 - x) as f64); + } + } + /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ + else { + if sign { + s = k_sinf((x + S2PIO2) as f64); + c = k_cosf((x + S2PIO2) as f64); + } else { + s = k_sinf((x - S2PIO2) as f64); + c = k_cosf((x - S2PIO2) as f64); + } + } + + return (s, c); + } + + /* |x| ~<= 9*pi/4 */ + if ix <= 0x40e231d5 { + if ix <= 0x40afeddf { /* |x| ~<= 7*pi/4 */ + if sign { + s = k_cosf((x + S3PIO2) as f64); + c = -k_sinf((x + S3PIO2) as f64); + } else { + s = -k_cosf((x - S3PIO2) as f64); + c = k_sinf((x - S3PIO2) as f64); + } + } else { + if sign { + s = k_cosf((x + S4PIO2) as f64); + c = k_sinf((x + S4PIO2) as f64); + } else { + s = k_cosf((x - S4PIO2) as f64); + c = k_sinf((x - S4PIO2) as f64); + } + } + + return (s, c); + } + + /* sin(Inf or NaN) is NaN */ + if ix >= 0x7f800000 { + let rv = x - x; + return (rv, rv); + } + + /* general argument reduction needed */ + let (n, y) = rem_pio2f(x); + s = k_sinf(y); + c = k_cosf(y); + match n&3 { + 0 => (s, c), + 1 => (c, -s), + 2 => (-s, -c), + 3 => (-c, s), + #[cfg(feature = "checked")] + _ => unreachable!(), + #[cfg(not(feature = "checked"))] + _ => (0.0, 1.0), + } +} diff --git a/library/compiler-builtins/libm/src/math/tgamma.rs b/library/compiler-builtins/libm/src/math/tgamma.rs new file mode 100644 index 0000000000000..598f46f1c3e1f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/tgamma.rs @@ -0,0 +1,179 @@ +/* +"A Precision Approximation of the Gamma Function" - Cornelius Lanczos (1964) +"Lanczos Implementation of the Gamma Function" - Paul Godfrey (2001) +"An Analysis of the Lanczos Gamma Approximation" - Glendon Ralph Pugh (2004) + +approximation method: + + (x - 0.5) S(x) +Gamma(x) = (x + g - 0.5) * ---------------- + exp(x + g - 0.5) + +with + a1 a2 a3 aN +S(x) ~= [ a0 + ----- + ----- + ----- + ... + ----- ] + x + 1 x + 2 x + 3 x + N + +with a0, a1, a2, a3,.. aN constants which depend on g. + +for x < 0 the following reflection formula is used: + +Gamma(x)*Gamma(-x) = -pi/(x sin(pi x)) + +most ideas and constants are from boost and python +*/ +extern crate core; +use super::{exp, floor, k_cos, k_sin, pow}; + +const PI: f64 = 3.141592653589793238462643383279502884; + +/* sin(pi x) with x > 0x1p-100, if sin(pi*x)==0 the sign is arbitrary */ +fn sinpi(mut x: f64) -> f64 +{ + let mut n: isize; + + /* argument reduction: x = |x| mod 2 */ + /* spurious inexact when x is odd int */ + x = x * 0.5; + x = 2.0 * (x - floor(x)); + + /* reduce x into [-.25,.25] */ + n = (4.0 * x) as isize; + n = (n+1)/2; + x -= (n as f64) * 0.5; + + x *= PI; + match n { + 1 => k_cos(x, 0.0), + 2 => k_sin(-x, 0.0, 0), + 3 => -k_cos(x, 0.0), + 0|_ => k_sin(x, 0.0, 0), + } +} + +const N: usize = 12; +//static const double g = 6.024680040776729583740234375; +const GMHALF: f64 = 5.524680040776729583740234375; +const SNUM: [f64; N+1] = [ + 23531376880.410759688572007674451636754734846804940, + 42919803642.649098768957899047001988850926355848959, + 35711959237.355668049440185451547166705960488635843, + 17921034426.037209699919755754458931112671403265390, + 6039542586.3520280050642916443072979210699388420708, + 1439720407.3117216736632230727949123939715485786772, + 248874557.86205415651146038641322942321632125127801, + 31426415.585400194380614231628318205362874684987640, + 2876370.6289353724412254090516208496135991145378768, + 186056.26539522349504029498971604569928220784236328, + 8071.6720023658162106380029022722506138218516325024, + 210.82427775157934587250973392071336271166969580291, + 2.5066282746310002701649081771338373386264310793408, +]; +const SDEN: [f64; N+1] = [ + 0.0, 39916800.0, 120543840.0, 150917976.0, 105258076.0, + 45995730.0, 13339535.0, 2637558.0, 357423.0, 32670.0, 1925.0, 66.0, 1.0, +]; +/* n! for small integer n */ +const FACT: [f64; 23] = [ + 1.0, 1.0, 2.0, 6.0, 24.0, 120.0, 720.0, 5040.0, 40320.0, 362880.0, 3628800.0, + 39916800.0, 479001600.0, 6227020800.0, 87178291200.0, 1307674368000.0, + 20922789888000.0, 355687428096000.0, 6402373705728000.0, 121645100408832000.0, + 2432902008176640000.0, 51090942171709440000.0, 1124000727777607680000.0, +]; + +/* S(x) rational function for positive x */ +fn s(x: f64) -> f64 +{ + let mut num: f64 = 0.0; + let mut den: f64 = 0.0; + + /* to avoid overflow handle large x differently */ + if x < 8.0 { + for i in (0..=N).rev() { + num = num * x + SNUM[i]; + den = den * x + SDEN[i]; + } + } else { + for i in 0..=N { + num = num / x + SNUM[i]; + den = den / x + SDEN[i]; + } + } + return num/den; +} + +pub fn tgamma(mut x: f64) -> f64 +{ + let u: u64 = x.to_bits(); + let absx: f64; + let mut y: f64; + let mut dy: f64; + let mut z: f64; + let mut r: f64; + let ix: u32 = ((u >> 32) as u32) & 0x7fffffff; + let sign: bool = (u>>64) != 0; + + /* special cases */ + if ix >= 0x7ff00000 { + /* tgamma(nan)=nan, tgamma(inf)=inf, tgamma(-inf)=nan with invalid */ + return x + core::f64::INFINITY; + } + if ix < ((0x3ff-54)<<20) { + /* |x| < 2^-54: tgamma(x) ~ 1/x, +-0 raises div-by-zero */ + return 1.0/x; + } + + /* integer arguments */ + /* raise inexact when non-integer */ + if x == floor(x) { + if sign { + return 0.0/0.0; + } + if x <= FACT.len() as f64 { + return FACT[(x as usize) - 1]; + } + } + + /* x >= 172: tgamma(x)=inf with overflow */ + /* x =< -184: tgamma(x)=+-0 with underflow */ + if ix >= 0x40670000 { /* |x| >= 184 */ + if sign { + let x1p_126 = f64::from_bits(0x3810000000000000); // 0x1p-126 == 2^-126 + force_eval!((x1p_126/x) as f32); + if floor(x) * 0.5 == floor(x * 0.5) { + return 0.0; + } else { + return -0.0; + } + } + let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 == 2^1023 + x *= x1p1023; + return x; + } + + absx = if sign { -x } else { x }; + + /* handle the error of x + g - 0.5 */ + y = absx + GMHALF; + if absx > GMHALF { + dy = y - absx; + dy -= GMHALF; + } else { + dy = y - GMHALF; + dy -= absx; + } + + z = absx - 0.5; + r = s(absx) * exp(-y); + if x < 0.0 { + /* reflection formula for negative x */ + /* sinpi(absx) is not 0, integers are already handled */ + r = -PI / (sinpi(absx) * absx * r); + dy = -dy; + z = -z; + } + r += dy * (GMHALF+0.5) * r / y; + z = pow(y, 0.5*z); + y = r * z * z; + return y; +} diff --git a/library/compiler-builtins/libm/src/math/tgammaf.rs b/library/compiler-builtins/libm/src/math/tgammaf.rs new file mode 100644 index 0000000000000..b9c799ce76cd6 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/tgammaf.rs @@ -0,0 +1,5 @@ +use super::{tgamma}; + +pub fn tgammaf(x: f32) -> f32 { + tgamma(x as f64) as f32 +} From cbff8302355717eb3f73457f19538972443e36af Mon Sep 17 00:00:00 2001 From: Charles Samborski Date: Tue, 28 Aug 2018 15:48:58 +0200 Subject: [PATCH 0605/4206] Fix link in README.md (Rust operator precedence) --- library/compiler-builtins/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index d10b44f8f7822..cae885279ad1d 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -69,13 +69,13 @@ features = ["c"] ### Porting Reminders -1. [Rust][4] and [C][5] have slightly different operator precedence. C evaluates comparisons (`== !=`) before bitwise operations (`& | ^`), while Rust evaluates the other way. +1. [Rust][5a] and [C][5b] have slightly different operator precedence. C evaluates comparisons (`== !=`) before bitwise operations (`& | ^`), while Rust evaluates the other way. 2. C assumes wrapping operations everywhere. Rust panics on overflow when in debug mode. Consider using the [Wrapping][6] type or the explicit [wrapping_*][7] functions where applicable. 3. Note [C implicit casts][8], especially integer promotion. Rust is much more explicit about casting, so be sure that any cast which affects the output is ported to the Rust implementation. 4. Rust has [many functions][9] for integer or floating point manipulation in the standard library. Consider using one of these functions rather than porting a new one. -[4]: https://doc.rust-lang.org/reference.html#operator-precedence -[5]: http://en.cppreference.com/w/c/language/operator_precedence +[5a]: https://doc.rust-lang.org/reference/expressions.html#expression-precedence +[5b]: http://en.cppreference.com/w/c/language/operator_precedence [6]: https://doc.rust-lang.org/core/num/struct.Wrapping.html [7]: https://doc.rust-lang.org/std/primitive.i32.html#method.wrapping_add [8]: http://en.cppreference.com/w/cpp/language/implicit_conversion From 1b4201f90d4c796c5776c1fb7ef077fb73af7f43 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 30 Aug 2018 14:13:15 -0700 Subject: [PATCH 0606/4206] Fix compilation on riscv32 --- library/compiler-builtins/src/riscv32.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/riscv32.rs b/library/compiler-builtins/src/riscv32.rs index ebaa354a4b30f..9161a11ccecc0 100644 --- a/library/compiler-builtins/src/riscv32.rs +++ b/library/compiler-builtins/src/riscv32.rs @@ -1,7 +1,8 @@ intrinsics! { // Implementation from gcc // https://raw.githubusercontent.com/gcc-mirror/gcc/master/libgcc/config/epiphany/mulsi3.c - pub extern "C" fn __mulsi3(mut a: u32, mut b: u32) -> u32 { + pub extern "C" fn __mulsi3(a: u32, b: u32) -> u32 { + let (mut a, mut b) = (a, b); let mut r: usize = 0; while a > 0 { From 091b21da578911d46e1c95b2e37413737473e374 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 31 Aug 2018 16:00:12 -0700 Subject: [PATCH 0607/4206] Fix compile on riscv again --- library/compiler-builtins/src/riscv32.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/riscv32.rs b/library/compiler-builtins/src/riscv32.rs index 9161a11ccecc0..9a3c1714c1f09 100644 --- a/library/compiler-builtins/src/riscv32.rs +++ b/library/compiler-builtins/src/riscv32.rs @@ -3,7 +3,7 @@ intrinsics! { // https://raw.githubusercontent.com/gcc-mirror/gcc/master/libgcc/config/epiphany/mulsi3.c pub extern "C" fn __mulsi3(a: u32, b: u32) -> u32 { let (mut a, mut b) = (a, b); - let mut r: usize = 0; + let mut r = 0; while a > 0 { if a & 1 > 0 { From 8a4148f60b5b27e35df5c5ed9dd42cb537b86a55 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sat, 1 Sep 2018 20:12:41 +0200 Subject: [PATCH 0608/4206] Rename panic_implementation -> panic_handler panic_implementation has been deprecated/renamed. New name is panic_handler --- library/compiler-builtins/Cargo.toml | 2 +- .../crates/{panic-implementation => panic-handler}/Cargo.toml | 2 +- .../crates/{panic-implementation => panic-handler}/src/lib.rs | 4 ++-- library/compiler-builtins/examples/intrinsics.rs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) rename library/compiler-builtins/crates/{panic-implementation => panic-handler}/Cargo.toml (76%) rename library/compiler-builtins/crates/{panic-implementation => panic-handler}/src/lib.rs (68%) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 311266269199c..7eae2dc1f2889 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -10,7 +10,7 @@ test = false cc = { optional = true, version = "1.0" } [dev-dependencies] -panic-implementation = { path = 'crates/panic-implementation' } +panic-handler = { path = 'crates/panic-handler' } [features] default = ["compiler-builtins"] diff --git a/library/compiler-builtins/crates/panic-implementation/Cargo.toml b/library/compiler-builtins/crates/panic-handler/Cargo.toml similarity index 76% rename from library/compiler-builtins/crates/panic-implementation/Cargo.toml rename to library/compiler-builtins/crates/panic-handler/Cargo.toml index a076cbc3cb8eb..1dea613d192f7 100644 --- a/library/compiler-builtins/crates/panic-implementation/Cargo.toml +++ b/library/compiler-builtins/crates/panic-handler/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "panic-implementation" +name = "panic-handler" version = "0.1.0" authors = ["Alex Crichton "] diff --git a/library/compiler-builtins/crates/panic-implementation/src/lib.rs b/library/compiler-builtins/crates/panic-handler/src/lib.rs similarity index 68% rename from library/compiler-builtins/crates/panic-implementation/src/lib.rs rename to library/compiler-builtins/crates/panic-handler/src/lib.rs index 1bb23970f7d3c..e9706108737ee 100644 --- a/library/compiler-builtins/crates/panic-implementation/src/lib.rs +++ b/library/compiler-builtins/crates/panic-handler/src/lib.rs @@ -1,11 +1,11 @@ // Hack of a crate until rust-lang/rust#51647 is fixed -#![feature(no_core, panic_implementation)] +#![feature(no_core, panic_handler)] #![no_core] extern crate core; -#[panic_implementation] +#[panic_handler] fn panic(_: &core::panic::PanicInfo) -> ! { loop {} } diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 7f502bba34b70..a5be5739443a7 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -11,11 +11,11 @@ #![feature(lang_items)] #![feature(start)] #![feature(allocator_api)] -#![feature(panic_implementation)] +#![feature(panic_handler)] #![cfg_attr(windows, feature(panic_unwind))] #![no_std] -extern crate panic_implementation; +extern crate panic_handler; #[cfg(not(thumb))] #[link(name = "c")] From 38d5777d984c1e4eb35bbaf3e932c2b90a038dc9 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 4 Sep 2018 10:19:55 -0700 Subject: [PATCH 0609/4206] Fix some `use_c_shim_if` directives This was an accidental regression introduced in #252 by removing compilation of C files without adjusting the `#[use_c_shim_if]` directives. This restores the compilation of the assembly files and updates the `#[use_c_shim_if]` directives. --- library/compiler-builtins/build.rs | 2 ++ library/compiler-builtins/src/float/conv.rs | 19 ++++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index fba4091124a98..cdcbfe24cd73c 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -267,8 +267,10 @@ mod c { if target_arch == "x86_64" { sources.extend( &[ + "x86_64/floatdisf.c", "x86_64/floatdixf.c", "x86_64/floatundidf.S", + "x86_64/floatundisf.S", "x86_64/floatundixf.S", ], ); diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 53844c17b49df..3171e45096cc2 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -80,7 +80,10 @@ intrinsics! { int_to_float!(i, i32, f64) } - #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[use_c_shim_if(any( + all(target_arch = "x86", not(target_env = "msvc")), + all(target_arch = "x86_64", not(windows)), + ))] #[arm_aeabi_alias = __aeabi_l2f] pub extern "C" fn __floatdisf(i: i64) -> f32 { // On x86_64 LLVM will use native instructions for this conversion, we @@ -124,17 +127,19 @@ intrinsics! { int_to_float!(i, u32, f64) } - #[use_c_shim_if(all(not(target_env = "msvc"), - any(target_arch = "x86", - all(not(windows), target_arch = "x86_64"))))] + #[use_c_shim_if(any( + all(target_arch = "x86", not(target_env = "msvc")), + all(target_arch = "x86_64", not(windows)), + ))] #[arm_aeabi_alias = __aeabi_ul2f] pub extern "C" fn __floatundisf(i: u64) -> f32 { int_to_float!(i, u64, f32) } - #[use_c_shim_if(all(not(target_env = "msvc"), - any(target_arch = "x86", - all(not(windows), target_arch = "x86_64"))))] + #[use_c_shim_if(any( + all(target_arch = "x86", not(target_env = "msvc")), + all(target_arch = "x86_64", not(windows)), + ))] #[arm_aeabi_alias = __aeabi_ul2d] pub extern "C" fn __floatundidf(i: u64) -> f64 { int_to_float!(i, u64, f64) From 6310b74d854eb354b344afbde6ea62be7fead78d Mon Sep 17 00:00:00 2001 From: Jordan Rhee Date: Thu, 5 Jul 2018 11:20:34 -0700 Subject: [PATCH 0610/4206] Support windows/arm target --- library/compiler-builtins/build.rs | 4 ++-- library/compiler-builtins/src/arm.rs | 2 +- library/compiler-builtins/src/int/sdiv.rs | 5 +++-- library/compiler-builtins/src/int/udiv.rs | 2 ++ 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index fba4091124a98..111a38b5e6bf2 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -297,7 +297,7 @@ mod c { } } - if target_arch == "arm" && target_os != "ios" { + if target_arch == "arm" && target_os != "ios" && target_env != "msvc" { sources.extend( &[ "arm/aeabi_div0.c", @@ -348,7 +348,7 @@ mod c { } } - if llvm_target[0] == "armv7" { + if llvm_target[0] == "armv7" && target_env != "msvc" { sources.extend( &[ "arm/sync_fetch_and_add_4.S", diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index dbd6f87ca522c..9e43aec7d345a 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -4,7 +4,7 @@ use core::intrinsics; // calling convention which can't be implemented using a normal Rust function. // NOTE The only difference between the iOS and non-iOS versions of those functions is that the iOS // versions use 3 leading underscores in the names of called functions instead of 2. -#[cfg(not(target_os = "ios"))] +#[cfg(not(any(target_os = "ios", target_env = "msvc")))] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_uidivmod() { diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 2de73b0eab7cc..89bb51a47b347 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -73,7 +73,8 @@ intrinsics! { } #[use_c_shim_if(all(target_arch = "arm", - not(target_os = "ios")), + not(target_os = "ios"), + not(target_env = "msvc")), not(thumbv6m))] pub extern "C" fn __modsi3(a: i32, b: i32) -> i32 { a.mod_(b) @@ -89,7 +90,7 @@ intrinsics! { a.mod_(b) } - #[use_c_shim_if(all(target_arch = "arm", + #[use_c_shim_if(all(target_arch = "arm", not(target_env = "msvc"), not(target_os = "ios"), not(thumbv6m)))] pub extern "C" fn __divmodsi4(a: i32, b: i32, rem: &mut i32) -> i32 { a.divmod(b, rem, |a, b| __divsi3(a, b)) diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 4382460e78285..a2572227f9702 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -211,6 +211,7 @@ intrinsics! { #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), + not(target_env = "msvc"), not(thumbv6m)))] /// Returns `n % d` pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { @@ -220,6 +221,7 @@ intrinsics! { #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), + not(target_env = "msvc"), not(thumbv6m)))] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { From 19a7eedbf3143f77a67e177ff9e2c7670f3e9bf5 Mon Sep 17 00:00:00 2001 From: Jordan Rhee Date: Thu, 6 Sep 2018 09:24:52 -0700 Subject: [PATCH 0611/4206] Try undoing unnecessary change --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 111a38b5e6bf2..45060a4e6e344 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -348,7 +348,7 @@ mod c { } } - if llvm_target[0] == "armv7" && target_env != "msvc" { + if llvm_target[0] == "armv7" /* XXX && target_env != "msvc" */ { sources.extend( &[ "arm/sync_fetch_and_add_4.S", From 71c5701c58f8744699690b450ca62ad53f1fc8ad Mon Sep 17 00:00:00 2001 From: Jordan Rhee Date: Fri, 7 Sep 2018 08:27:38 -0700 Subject: [PATCH 0612/4206] Remove unnecessary check --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 45060a4e6e344..87b5e049063f6 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -348,7 +348,7 @@ mod c { } } - if llvm_target[0] == "armv7" /* XXX && target_env != "msvc" */ { + if llvm_target[0] == "armv7" { sources.extend( &[ "arm/sync_fetch_and_add_4.S", From 66d52cf01d671ad1616f067702a585d2fa9e5f1a Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sat, 8 Sep 2018 17:41:26 +0200 Subject: [PATCH 0613/4206] Remove superfluous cc flags Latest `cc-rs` already manage all arm/thumb flags, so We can safely remove this piece of code. --- library/compiler-builtins/build.rs | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index fba4091124a98..48d11db7ccefe 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -141,29 +141,6 @@ mod c { cfg.define("VISIBILITY_HIDDEN", None); } - // NOTE Most of the ARM intrinsics are written in assembly. Tell gcc which arch we are going - // to target to make sure that the assembly implementations really work for the target. If - // the implementation is not valid for the arch, then gcc will error when compiling it. - if llvm_target[0].starts_with("thumb") { - cfg.flag("-mthumb"); - } - - if target_arch_arm && llvm_target.last() == Some(&"eabihf") { - cfg.flag("-mfloat-abi=hard"); - } - - if llvm_target[0] == "thumbv6m" { - cfg.flag("-march=armv6-m"); - } - - if llvm_target[0] == "thumbv7m" { - cfg.flag("-march=armv7-m"); - } - - if llvm_target[0] == "thumbv7em" { - cfg.flag("-march=armv7e-m"); - } - let mut sources = Sources::new(); sources.extend( &[ From 296f04fe6342430ff44207e149ac32e93b1f62d4 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Sat, 8 Sep 2018 19:04:09 +0200 Subject: [PATCH 0614/4206] Remove unused variable target_arch_arm Previous commit makes this variable unused --- library/compiler-builtins/build.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 48d11db7ccefe..1ace622bef429 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -110,9 +110,6 @@ mod c { let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap(); let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap(); - let target_arch_arm = - target_arch.contains("arm") || - target_arch.contains("thumb"); let cfg = &mut cc::Build::new(); cfg.warnings(false); From c03769a47e91aadf34d616d68f8a3ddfcf983d93 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Thu, 13 Sep 2018 10:10:52 +0200 Subject: [PATCH 0615/4206] `panic_handler` is now stable Fixes the following warning: "warning: the feature `panic_handler` has been stable since 1.30.0 and no longer requires an attribute to enable" --- library/compiler-builtins/crates/panic-handler/src/lib.rs | 2 +- library/compiler-builtins/examples/intrinsics.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/library/compiler-builtins/crates/panic-handler/src/lib.rs b/library/compiler-builtins/crates/panic-handler/src/lib.rs index e9706108737ee..a75999a4b605e 100644 --- a/library/compiler-builtins/crates/panic-handler/src/lib.rs +++ b/library/compiler-builtins/crates/panic-handler/src/lib.rs @@ -1,6 +1,6 @@ // Hack of a crate until rust-lang/rust#51647 is fixed -#![feature(no_core, panic_handler)] +#![feature(no_core)] #![no_core] extern crate core; diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index a5be5739443a7..1c498176c1303 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -11,7 +11,6 @@ #![feature(lang_items)] #![feature(start)] #![feature(allocator_api)] -#![feature(panic_handler)] #![cfg_attr(windows, feature(panic_unwind))] #![no_std] From 620a8d4272dbb511dcbc75eeffaefaae4700a253 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Thu, 13 Sep 2018 10:31:36 +0200 Subject: [PATCH 0616/4206] Apple-darwin: set DEBUG_LTO_BUILD_DOESNT_WORK Temporary workaround for the well known "undefined references problem for debug-assertions+lto" (#79) --- library/compiler-builtins/.travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml index 7b7ed7e6bca5a..9b4c28419f8c7 100644 --- a/library/compiler-builtins/.travis.yml +++ b/library/compiler-builtins/.travis.yml @@ -11,7 +11,7 @@ matrix: - env: TARGET=arm-unknown-linux-gnueabihf - env: TARGET=armv7-unknown-linux-gnueabihf - env: TARGET=i586-unknown-linux-gnu - - env: TARGET=i686-apple-darwin + - env: TARGET=i686-apple-darwin DEBUG_LTO_BUILD_DOESNT_WORK=1 os: osx - env: TARGET=i686-unknown-linux-gnu - env: TARGET=mips-unknown-linux-gnu @@ -28,7 +28,7 @@ matrix: - env: TARGET=wasm32-unknown-unknown install: rustup target add $TARGET script: cargo build --target $TARGET - - env: TARGET=x86_64-apple-darwin + - env: TARGET=x86_64-apple-darwin DEBUG_LTO_BUILD_DOESNT_WORK=1 os: osx - env: TARGET=x86_64-unknown-linux-gnu allow_failures: From 45a42b5b890f2c894bff2980e1bbb03522267c23 Mon Sep 17 00:00:00 2001 From: Paolo Teti Date: Mon, 17 Sep 2018 19:37:18 +0200 Subject: [PATCH 0617/4206] Conversion from a wider to a narrower IEEE-754 floating-point type Adds generic conversion from a wider to a narrower IEEE-754 floating-point type. Implement `__truncdfsf2` and `__truncdfsf2vfp` and associated test-cases. --- library/compiler-builtins/README.md | 4 +- library/compiler-builtins/build.rs | 1 - library/compiler-builtins/src/float/mod.rs | 1 + .../compiler-builtins/src/float/truncate.rs | 116 ++++++++++++++++++ library/compiler-builtins/testcrate/build.rs | 18 +++ 5 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/src/float/truncate.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index cae885279ad1d..fceaa631d5523 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -129,7 +129,7 @@ features = ["c"] - [x] arm/softfloat-alias.list - [x] arm/subdf3vfp.S - [x] arm/subsf3vfp.S -- [ ] arm/truncdfsf2vfp.S +- [x] arm/truncdfsf2vfp.S - [ ] arm/udivmodsi4.S (generic version is done) - [ ] arm/udivsi3.S (generic version is done) - [ ] arm/umodsi3.S (generic version is done) @@ -186,7 +186,7 @@ features = ["c"] - [x] subdf3.c - [x] subsf3.c - [ ] truncdfhf2.c -- [ ] truncdfsf2.c +- [x] truncdfsf2.c - [ ] truncsfhf2.c - [x] udivdi3.c - [x] udivmoddi4.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 6f2cc76a96175..917dd963d0f86 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -174,7 +174,6 @@ mod c { "subvdi3.c", "subvsi3.c", "truncdfhf2.c", - "truncdfsf2.c", "truncsfhf2.c", "ucmpdi2.c", ], diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 3bb13abbc5c61..2b8ddb94132ad 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -11,6 +11,7 @@ pub mod sub; pub mod mul; pub mod div; pub mod extend; +pub mod truncate; /// Trait for some basic operations on floats pub trait Float: diff --git a/library/compiler-builtins/src/float/truncate.rs b/library/compiler-builtins/src/float/truncate.rs new file mode 100644 index 0000000000000..99d4807da8ae8 --- /dev/null +++ b/library/compiler-builtins/src/float/truncate.rs @@ -0,0 +1,116 @@ +use float::Float; +use int::{CastInto, Int}; + +/// Generic conversion from a wider to a narrower IEEE-754 floating-point type +fn truncate(a: F) -> R +where + F::Int: CastInto, + u64: CastInto, + F::Int: CastInto, + u32: CastInto, + u32: CastInto, + R::Int: CastInto, + F::Int: CastInto, +{ + let src_one = F::Int::ONE; + let src_bits = F::BITS; + let src_sign_bits = F::SIGNIFICAND_BITS; + let src_exp_bias = F::EXPONENT_BIAS; + let src_min_normal = F::IMPLICIT_BIT; + let src_infinity = F::EXPONENT_MASK; + let src_sign_mask = F::SIGN_MASK as F::Int; + let src_abs_mask = src_sign_mask - src_one; + let src_qnan = F::SIGNIFICAND_MASK; + let src_nan_code = src_qnan - src_one; + + let dst_bits = R::BITS; + let dst_sign_bits = R::SIGNIFICAND_BITS; + let dst_inf_exp = R::EXPONENT_MAX; + let dst_exp_bias = R::EXPONENT_BIAS; + + let dst_zero = R::Int::ZERO; + let dst_one = R::Int::ONE; + let dst_qnan = R::SIGNIFICAND_MASK; + let dst_nan_code = dst_qnan - dst_one; + + let round_mask = (src_one << src_sign_bits - dst_sign_bits) - src_one; + let half = src_one << src_sign_bits - dst_sign_bits - 1; + let underflow_exp = src_exp_bias + 1 - dst_exp_bias; + let overflow_exp = src_exp_bias + dst_inf_exp - dst_exp_bias; + let underflow: F::Int = underflow_exp.cast(); // << src_sign_bits; + let overflow: F::Int = overflow_exp.cast(); //<< src_sign_bits; + + let a_abs = a.repr() & src_abs_mask; + let sign = a.repr() & src_sign_mask; + let mut abs_result: R::Int; + + let src_underflow = underflow << src_sign_bits; + let src_overflow = overflow << src_sign_bits; + + if a_abs.wrapping_sub(src_underflow) < a_abs.wrapping_sub(src_overflow) { + // The exponent of a is within the range of normal numbers + let bias_delta: R::Int = (src_exp_bias - dst_exp_bias).cast(); + abs_result = a_abs.cast(); + abs_result = abs_result >> src_sign_bits - dst_sign_bits; + abs_result = abs_result - bias_delta.wrapping_shl(dst_sign_bits); + let round_bits: F::Int = a_abs & round_mask; + abs_result += if round_bits > half { + dst_one + } else { + abs_result & dst_one + }; + } else if a_abs > src_infinity { + // a is NaN. + // Conjure the result by beginning with infinity, setting the qNaN + // bit and inserting the (truncated) trailing NaN field + let nan_result: R::Int = (a_abs & src_nan_code).cast(); + abs_result = dst_inf_exp.cast(); + abs_result = abs_result.wrapping_shl(dst_sign_bits); + abs_result |= dst_qnan; + abs_result |= (nan_result >> (src_sign_bits - dst_sign_bits)) & dst_nan_code; + } else if a_abs >= src_overflow { + // a overflows to infinity. + abs_result = dst_inf_exp.cast(); + abs_result = abs_result.wrapping_shl(dst_sign_bits); + } else { + // a underflows on conversion to the destination type or is an exact + // zero. The result may be a denormal or zero. Extract the exponent + // to get the shift amount for the denormalization. + let a_exp = a_abs >> src_sign_bits; + let mut shift: u32 = a_exp.cast(); + shift = src_exp_bias - dst_exp_bias - shift + 1; + + let significand = (a.repr() & src_sign_mask) | src_min_normal; + if shift > src_sign_bits { + abs_result = dst_zero; + } else { + let sticky = significand << src_bits - shift; + let mut denormalized_significand: R::Int = significand.cast(); + let sticky_shift: u32 = sticky.cast(); + denormalized_significand = denormalized_significand >> (shift | sticky_shift); + abs_result = denormalized_significand >> src_sign_bits - dst_sign_bits; + let round_bits = denormalized_significand & round_mask.cast(); + if round_bits > half.cast() { + abs_result += dst_one; // Round to nearest + } else if round_bits == half.cast() { + abs_result += abs_result & dst_one; // Ties to even + } + } + } + // Finally apply the sign bit + let s = sign >> src_bits - dst_bits; + R::from_repr(abs_result | s.cast()) +} + +intrinsics! { + #[aapcs_on_arm] + #[arm_aeabi_alias = __aeabi_d2f] + pub extern "C" fn __truncdfsf2(a: f64) -> f32 { + truncate(a) + } + + #[cfg(target_arch = "arm")] + pub extern "C" fn __truncdfsf2vfp(a: f64) -> f32 { + a as f32 + } +} diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index d862e0d0ffbf9..f02a67cc32a88 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -348,6 +348,24 @@ fn main() { "builtins::float::extend::__extendsfdf2vfp(a)"); } + // float/truncate.rs + gen(|a: MyF64| { + if a.0.is_nan() { + return None; + } + Some(a.0 as f32) + }, + "builtins::float::truncate::__truncdfsf2(a)"); + if target_arch_arm { + gen(|a: LargeF64| { + if a.0.is_nan() { + return None; + } + Some(a.0 as f32) + }, + "builtins::float::truncate::__truncdfsf2vfp(a)"); + } + // float/conv.rs gen(|a: MyF64| i64(a.0).ok(), "builtins::float::conv::__fixdfdi(a)"); From 9b03920fe17ddb1e61a179a7a83fcb00ce740e98 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 11 Oct 2018 14:43:19 -0700 Subject: [PATCH 0618/4206] Optimize intrinsics on wasm32 Profiling a recent demo I was playing with on `wasm32-unknown-unknown` pointed me to the surprising result that 15% of the execution time was in the `sqrt` intrinsic (there's a lot of math here). Upon investigation I remembered that wasm (unconditionally) has a native `f32.sqrt` instruction! I was then subsequently confused that a simple `f.sqrt()` actually codegens to use `f32.sqrt` in Rust, but I later realized that the implementations of intrinsics in this library often use other intrinsics to implement them. That means that the real intrinsic here, `acos`, internally called `sqrt` at some point but wasn't using the optimized implementation! To help fix this situation this PR is intended on providing the infrastructure for optimized implementations (via code generation) to be used for each intrinsic. I've gone thorugh the various math instructions that wasm has available and updated each of the intrinsic implementations in this crate to optionally use the LLVM intrinsic versions, which are known to unconditionally compile down to a single instruction (unlike the arbitrary platform, where we don't know what it will compile down to!). To do this I created a new macro to wrap the invocation of LLVM intrinsics. Invoking LLVM intrinsics is turned off by default (through a new and on-by-default feature, `stable`). When the `stable` feature is disabled, however, then the wasm-target specifically will enable usage of the LLVM intrinsics. I've additionally added a CI builder which should verify that these continue to build on Travis. After this I intended to update the submodule in the `compiler-builtins` repository so we can pull in the optimized implementation there, and `compiler-builtins` naturally won't set `feature = "stable"` when compiling so all the intrinsics should get compiled in by default. After a further update of `the libcompiler_builtins` submodule in rust-lang/rust we should be good to go! --- library/compiler-builtins/libm/.travis.yml | 7 +++++++ library/compiler-builtins/libm/Cargo.toml | 4 ++++ library/compiler-builtins/libm/src/lib.rs | 4 ++++ library/compiler-builtins/libm/src/math/ceil.rs | 8 ++++++++ library/compiler-builtins/libm/src/math/ceilf.rs | 8 ++++++++ library/compiler-builtins/libm/src/math/fabs.rs | 8 ++++++++ library/compiler-builtins/libm/src/math/fabsf.rs | 8 ++++++++ library/compiler-builtins/libm/src/math/floor.rs | 8 ++++++++ library/compiler-builtins/libm/src/math/floorf.rs | 8 ++++++++ library/compiler-builtins/libm/src/math/mod.rs | 11 +++++++++++ library/compiler-builtins/libm/src/math/sqrt.rs | 12 ++++++++++++ library/compiler-builtins/libm/src/math/sqrtf.rs | 12 ++++++++++++ library/compiler-builtins/libm/src/math/trunc.rs | 8 ++++++++ library/compiler-builtins/libm/src/math/truncf.rs | 8 ++++++++ 14 files changed, 114 insertions(+) diff --git a/library/compiler-builtins/libm/.travis.yml b/library/compiler-builtins/libm/.travis.yml index 47f2b2f205df6..7583161781963 100644 --- a/library/compiler-builtins/libm/.travis.yml +++ b/library/compiler-builtins/libm/.travis.yml @@ -29,6 +29,13 @@ matrix: - env: TARGET=cargo-fmt rust: beta + - env: TARGET=wasm32-unknown-unknown + rust: nightly + install: rustup target add $TARGET + script: + - cargo build --target $TARGET + - cargo build --no-default-features --target $TARGET + before_install: set -e install: diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index cedf8d267db8a..f7a528334241a 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -24,3 +24,7 @@ members = [ [dev-dependencies] shared = { path = "shared" } + +[features] +default = ['stable'] +stable = [] diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 627c6443e3dca..6be458728197f 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -11,6 +11,10 @@ #![deny(warnings)] #![no_std] +#![cfg_attr( + all(target_arch = "wasm32", not(feature = "stable")), + feature(core_intrinsics) +)] mod math; diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index 4db2ca8403682..5dbfa6a2c0ad4 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -4,6 +4,14 @@ const TOINT: f64 = 1. / f64::EPSILON; #[inline] pub fn ceil(x: f64) -> f64 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f64.ceil` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return unsafe { ::core::intrinsics::ceilf64(x) } + } + } let u: u64 = x.to_bits(); let e: i64 = (u >> 52 & 0x7ff) as i64; let y: f64; diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index 16bffb3002e59..c8cd4b5aa5b5c 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -2,6 +2,14 @@ use core::f32; #[inline] pub fn ceilf(x: f32) -> f32 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f32.ceil` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return unsafe { ::core::intrinsics::ceilf32(x) } + } + } let mut ui = x.to_bits(); let e = (((ui >> 23) & 0xff) - 0x7f) as i32; diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index 9e081f3f9f69f..7c804653c9968 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -2,5 +2,13 @@ use core::u64; #[inline] pub fn fabs(x: f64) -> f64 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f64.abs` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return unsafe { ::core::intrinsics::fabsf64(x) } + } + } f64::from_bits(x.to_bits() & (u64::MAX / 2)) } diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index 4cc9411169ab2..884c20f6c4103 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -1,4 +1,12 @@ #[inline] pub fn fabsf(x: f32) -> f32 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f32.abs` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return unsafe { ::core::intrinsics::fabsf32(x) } + } + } f32::from_bits(x.to_bits() & 0x7fffffff) } diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index 997865d39e93c..b14a48d55bc7f 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -4,6 +4,14 @@ const TOINT: f64 = 1. / f64::EPSILON; #[inline] pub fn floor(x: f64) -> f64 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f64.floor` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return unsafe { ::core::intrinsics::floorf64(x) } + } + } let ui = x.to_bits(); let e = ((ui >> 52) & 0x7ff) as i32; diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index 9c263b51828bf..71b5953df3e26 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -2,6 +2,14 @@ use core::f32; #[inline] pub fn floorf(x: f32) -> f32 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f32.floor` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return unsafe { ::core::intrinsics::floorf32(x) } + } + } let mut ui = x.to_bits(); let e = (((ui >> 23) & 0xff) - 0x7f) as i32; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index da34fb4cecd1d..e51b1511dfcbe 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -58,6 +58,17 @@ macro_rules! i { }; } +macro_rules! llvm_intrinsically_optimized { + (#[cfg($($clause:tt)*)] $e:expr) => { + #[cfg(all(not(feature = "stable"), $($clause)*))] + { + if true { // thwart the dead code lint + $e + } + } + }; +} + // Public modules mod acos; mod acosf; diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index cbadb49bba03b..b2387a26e750c 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -82,6 +82,18 @@ const TINY: f64 = 1.0e-300; #[inline] pub fn sqrt(x: f64) -> f64 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f64.sqrt` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return if x < 0.0 { + f64::NAN + } else { + unsafe { ::core::intrinsics::sqrtf64(x) } + } + } + } let mut z: f64; let sign: u32 = 0x80000000; let mut ix0: i32; diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 49984689efc28..33cafbcbda36c 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -17,6 +17,18 @@ const TINY: f32 = 1.0e-30; #[inline] pub fn sqrtf(x: f32) -> f32 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f32.sqrt` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return if x < 0.0 { + ::core::f32::NAN + } else { + unsafe { ::core::intrinsics::sqrtf32(x) } + } + } + } let mut z: f32; let sign: i32 = 0x80000000u32 as i32; let mut ix: i32; diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs index 6bea67cbc1654..8eecfcf538e5e 100644 --- a/library/compiler-builtins/libm/src/math/trunc.rs +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -2,6 +2,14 @@ use core::f64; #[inline] pub fn trunc(x: f64) -> f64 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f64.trunc` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return unsafe { ::core::intrinsics::truncf64(x) } + } + } let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 let mut i: u64 = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs index 9d42620d96663..0d74fea9c9ee9 100644 --- a/library/compiler-builtins/libm/src/math/truncf.rs +++ b/library/compiler-builtins/libm/src/math/truncf.rs @@ -2,6 +2,14 @@ use core::f32; #[inline] pub fn truncf(x: f32) -> f32 { + // On wasm32 we know that LLVM's intrinsic will compile to an optimized + // `f32.trunc` native instruction, so we can leverage this for both code size + // and speed. + llvm_intrinsically_optimized! { + #[cfg(target_arch = "wasm32")] { + return unsafe { ::core::intrinsics::truncf32(x) } + } + } let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 let mut i: u32 = x.to_bits(); From 5c6fd41b3deab08ab7cbbfec15bc8ce5af593a1c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 24 Oct 2018 00:18:30 +0200 Subject: [PATCH 0619/4206] merge [features] tables --- library/compiler-builtins/libm/Cargo.toml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index f7a528334241a..f28024d041c53 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -12,6 +12,8 @@ version = "0.1.2" [features] # only used to run our test suite checked = [] +default = ['stable'] +stable = [] [workspace] members = [ @@ -24,7 +26,3 @@ members = [ [dev-dependencies] shared = { path = "shared" } - -[features] -default = ['stable'] -stable = [] From b387ac07b1bc26f829bb686868e2cce4d2cd9751 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 24 Oct 2018 01:01:14 -0700 Subject: [PATCH 0620/4206] Update libm submodule --- library/compiler-builtins/.gitmodules | 2 +- library/compiler-builtins/libm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index 7162b2c4d5b2b..50ed51e937b9d 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -3,4 +3,4 @@ url = https://github.com/rust-lang/compiler-rt [submodule "libm"] path = libm - url = https://github.com/japaric/libm + url = https://github.com/rust-lang-nursery/libm diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 96e36ea2620f9..3559e703795d3 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 96e36ea2620f9fbbaa46a01694a2fa3ef6c2fb7e +Subproject commit 3559e703795d33e84a91da2a35f2f3baac47e872 From dbdcd66e3579a187dba001dca5102ea0a7996a81 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 30 Oct 2018 10:51:11 -0700 Subject: [PATCH 0621/4206] Revert "Conversion from a wider to a narrower IEEE-754 floating-point type" This reverts commit baab4fd89cdd945e46fed31166e5dcad7224ed87. --- library/compiler-builtins/README.md | 4 +- library/compiler-builtins/build.rs | 1 + library/compiler-builtins/src/float/mod.rs | 1 - .../compiler-builtins/src/float/truncate.rs | 116 ------------------ library/compiler-builtins/testcrate/build.rs | 18 --- 5 files changed, 3 insertions(+), 137 deletions(-) delete mode 100644 library/compiler-builtins/src/float/truncate.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index fceaa631d5523..cae885279ad1d 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -129,7 +129,7 @@ features = ["c"] - [x] arm/softfloat-alias.list - [x] arm/subdf3vfp.S - [x] arm/subsf3vfp.S -- [x] arm/truncdfsf2vfp.S +- [ ] arm/truncdfsf2vfp.S - [ ] arm/udivmodsi4.S (generic version is done) - [ ] arm/udivsi3.S (generic version is done) - [ ] arm/umodsi3.S (generic version is done) @@ -186,7 +186,7 @@ features = ["c"] - [x] subdf3.c - [x] subsf3.c - [ ] truncdfhf2.c -- [x] truncdfsf2.c +- [ ] truncdfsf2.c - [ ] truncsfhf2.c - [x] udivdi3.c - [x] udivmoddi4.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 917dd963d0f86..6f2cc76a96175 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -174,6 +174,7 @@ mod c { "subvdi3.c", "subvsi3.c", "truncdfhf2.c", + "truncdfsf2.c", "truncsfhf2.c", "ucmpdi2.c", ], diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 2b8ddb94132ad..3bb13abbc5c61 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -11,7 +11,6 @@ pub mod sub; pub mod mul; pub mod div; pub mod extend; -pub mod truncate; /// Trait for some basic operations on floats pub trait Float: diff --git a/library/compiler-builtins/src/float/truncate.rs b/library/compiler-builtins/src/float/truncate.rs deleted file mode 100644 index 99d4807da8ae8..0000000000000 --- a/library/compiler-builtins/src/float/truncate.rs +++ /dev/null @@ -1,116 +0,0 @@ -use float::Float; -use int::{CastInto, Int}; - -/// Generic conversion from a wider to a narrower IEEE-754 floating-point type -fn truncate(a: F) -> R -where - F::Int: CastInto, - u64: CastInto, - F::Int: CastInto, - u32: CastInto, - u32: CastInto, - R::Int: CastInto, - F::Int: CastInto, -{ - let src_one = F::Int::ONE; - let src_bits = F::BITS; - let src_sign_bits = F::SIGNIFICAND_BITS; - let src_exp_bias = F::EXPONENT_BIAS; - let src_min_normal = F::IMPLICIT_BIT; - let src_infinity = F::EXPONENT_MASK; - let src_sign_mask = F::SIGN_MASK as F::Int; - let src_abs_mask = src_sign_mask - src_one; - let src_qnan = F::SIGNIFICAND_MASK; - let src_nan_code = src_qnan - src_one; - - let dst_bits = R::BITS; - let dst_sign_bits = R::SIGNIFICAND_BITS; - let dst_inf_exp = R::EXPONENT_MAX; - let dst_exp_bias = R::EXPONENT_BIAS; - - let dst_zero = R::Int::ZERO; - let dst_one = R::Int::ONE; - let dst_qnan = R::SIGNIFICAND_MASK; - let dst_nan_code = dst_qnan - dst_one; - - let round_mask = (src_one << src_sign_bits - dst_sign_bits) - src_one; - let half = src_one << src_sign_bits - dst_sign_bits - 1; - let underflow_exp = src_exp_bias + 1 - dst_exp_bias; - let overflow_exp = src_exp_bias + dst_inf_exp - dst_exp_bias; - let underflow: F::Int = underflow_exp.cast(); // << src_sign_bits; - let overflow: F::Int = overflow_exp.cast(); //<< src_sign_bits; - - let a_abs = a.repr() & src_abs_mask; - let sign = a.repr() & src_sign_mask; - let mut abs_result: R::Int; - - let src_underflow = underflow << src_sign_bits; - let src_overflow = overflow << src_sign_bits; - - if a_abs.wrapping_sub(src_underflow) < a_abs.wrapping_sub(src_overflow) { - // The exponent of a is within the range of normal numbers - let bias_delta: R::Int = (src_exp_bias - dst_exp_bias).cast(); - abs_result = a_abs.cast(); - abs_result = abs_result >> src_sign_bits - dst_sign_bits; - abs_result = abs_result - bias_delta.wrapping_shl(dst_sign_bits); - let round_bits: F::Int = a_abs & round_mask; - abs_result += if round_bits > half { - dst_one - } else { - abs_result & dst_one - }; - } else if a_abs > src_infinity { - // a is NaN. - // Conjure the result by beginning with infinity, setting the qNaN - // bit and inserting the (truncated) trailing NaN field - let nan_result: R::Int = (a_abs & src_nan_code).cast(); - abs_result = dst_inf_exp.cast(); - abs_result = abs_result.wrapping_shl(dst_sign_bits); - abs_result |= dst_qnan; - abs_result |= (nan_result >> (src_sign_bits - dst_sign_bits)) & dst_nan_code; - } else if a_abs >= src_overflow { - // a overflows to infinity. - abs_result = dst_inf_exp.cast(); - abs_result = abs_result.wrapping_shl(dst_sign_bits); - } else { - // a underflows on conversion to the destination type or is an exact - // zero. The result may be a denormal or zero. Extract the exponent - // to get the shift amount for the denormalization. - let a_exp = a_abs >> src_sign_bits; - let mut shift: u32 = a_exp.cast(); - shift = src_exp_bias - dst_exp_bias - shift + 1; - - let significand = (a.repr() & src_sign_mask) | src_min_normal; - if shift > src_sign_bits { - abs_result = dst_zero; - } else { - let sticky = significand << src_bits - shift; - let mut denormalized_significand: R::Int = significand.cast(); - let sticky_shift: u32 = sticky.cast(); - denormalized_significand = denormalized_significand >> (shift | sticky_shift); - abs_result = denormalized_significand >> src_sign_bits - dst_sign_bits; - let round_bits = denormalized_significand & round_mask.cast(); - if round_bits > half.cast() { - abs_result += dst_one; // Round to nearest - } else if round_bits == half.cast() { - abs_result += abs_result & dst_one; // Ties to even - } - } - } - // Finally apply the sign bit - let s = sign >> src_bits - dst_bits; - R::from_repr(abs_result | s.cast()) -} - -intrinsics! { - #[aapcs_on_arm] - #[arm_aeabi_alias = __aeabi_d2f] - pub extern "C" fn __truncdfsf2(a: f64) -> f32 { - truncate(a) - } - - #[cfg(target_arch = "arm")] - pub extern "C" fn __truncdfsf2vfp(a: f64) -> f32 { - a as f32 - } -} diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index f02a67cc32a88..d862e0d0ffbf9 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -348,24 +348,6 @@ fn main() { "builtins::float::extend::__extendsfdf2vfp(a)"); } - // float/truncate.rs - gen(|a: MyF64| { - if a.0.is_nan() { - return None; - } - Some(a.0 as f32) - }, - "builtins::float::truncate::__truncdfsf2(a)"); - if target_arch_arm { - gen(|a: LargeF64| { - if a.0.is_nan() { - return None; - } - Some(a.0 as f32) - }, - "builtins::float::truncate::__truncdfsf2vfp(a)"); - } - // float/conv.rs gen(|a: MyF64| i64(a.0).ok(), "builtins::float::conv::__fixdfdi(a)"); From 330bb3a744de533597d18cded2373c71bd781c41 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 9 Nov 2018 12:52:21 -0800 Subject: [PATCH 0622/4206] Update for next LLVM 8 version --- library/compiler-builtins/compiler-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-rt b/library/compiler-builtins/compiler-rt index 7e387f0f90b49..84c0bd0158c3f 160000 --- a/library/compiler-builtins/compiler-rt +++ b/library/compiler-builtins/compiler-rt @@ -1 +1 @@ -Subproject commit 7e387f0f90b493ae72930c787c381a80055a7ec9 +Subproject commit 84c0bd0158c3ff86052be1b07a3ddc3c4f5ba52a From 6582b145b8404d4b61ff60123014e9158931c344 Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Wed, 21 Nov 2018 14:07:03 +0530 Subject: [PATCH 0623/4206] Add f32 versions of WebAssembly math functions --- library/compiler-builtins/src/math.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 6eddc3d78abb6..9db7a0aa3d6bb 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -51,6 +51,19 @@ no_mangle! { fn fmodf(x: f32, y: f32) -> f32; fn fma(x: f64, y: f64, z: f64) -> f64; fn fmaf(x: f32, y: f32, z: f32) -> f32; + fn acosf(n: f32) -> f32; + fn asinf(n: f32) -> f32; + fn atan2f(a: f32, b: f32) -> f32; + fn atanf(n: f32) -> f32; + fn cbrtf(n: f32) -> f32; + fn coshf(n: f32) -> f32; + fn expm1f(n: f32) -> f32; + fn fdimf(a: f32, b: f32) -> f32; + fn hypotf(x: f32, y: f32) -> f32; + fn log1pf(n: f32) -> f32; + fn sinhf(n: f32) -> f32; + fn tanf(n: f32) -> f32; + fn tanhf(n: f32) -> f32; } // only for the thumb*-none-eabi* targets From 3880e404a8b53ed9312a4272bc2ae7653e05dc23 Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Wed, 21 Nov 2018 14:07:57 +0530 Subject: [PATCH 0624/4206] Add SGX target --- library/compiler-builtins/build.rs | 4 ++-- library/compiler-builtins/src/lib.rs | 3 ++- library/compiler-builtins/src/math.rs | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 6f2cc76a96175..f5ada024f41ef 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -17,9 +17,9 @@ fn main() { return; } - // Forcibly enable memory intrinsics on wasm32 as we don't have a libc to + // Forcibly enable memory intrinsics on wasm32 & SGX as we don't have a libc to // provide them. - if target.contains("wasm32") { + if target.contains("wasm32") || target.contains("sgx") { println!("cargo:rustc-cfg=feature=\"mem\""); } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 9f1dd15120c07..9bb38f39aa2fc 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -48,7 +48,8 @@ pub mod int; pub mod float; #[cfg(any(all(target_arch = "wasm32", target_os = "unknown"), - all(target_arch = "arm", target_os = "none")))] + all(target_arch = "arm", target_os = "none"), + target_env = "sgx"))] pub mod math; pub mod mem; diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 9db7a0aa3d6bb..c37243504b1b8 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -15,7 +15,7 @@ macro_rules! no_mangle { } // only for the wasm32-unknown-unknown target -#[cfg(all(target_arch = "wasm32", target_os = "unknown"))] +#[cfg(any(all(target_arch = "wasm32", target_os = "unknown"), target_env = "sgx"))] no_mangle! { fn acos(x: f64) -> f64; fn asin(x: f64) -> f64; From 59fb3fd69c2e0b97890fa4a707bd57bd267ba5f8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 19 Nov 2018 22:02:13 -0800 Subject: [PATCH 0625/4206] Prepare for publication to crates.io This commit prepares to publish the compiler-builtins crate to crates.io in order for the standard library to directly depend on it from crates.io in rust-lang/rust#56092 --- library/compiler-builtins/Cargo.toml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 7eae2dc1f2889..0bbd22e463ac3 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -6,6 +6,11 @@ version = "0.1.0" [lib] test = false +[dependencies] +# For more information on this dependency see rust-lang/rust's +# `src/tools/rustc-std-workspace` folder +core = { version = "1.0.0", optional = true, package = 'rustc-std-workspace-core' } + [build-dependencies] cc = { optional = true, version = "1.0" } @@ -32,6 +37,9 @@ mangled-names = [] # Don't generate lang items for i128 intrisnics and such no-lang-items = [] +# Only used in the compiler's build system +rustc-dep-of-std = ['c', 'compiler-builtins', 'core'] + [[example]] name = "intrinsics" required-features = ["c", "compiler-builtins"] From 9fdc957019b94922c303071945fac62c4ee50079 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 21 Nov 2018 10:19:31 -0800 Subject: [PATCH 0626/4206] Use panic=abort for tests Try to fix issues with undefined `rust_eh_personality` symbols --- library/compiler-builtins/Cargo.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 0bbd22e463ac3..a7f34c007a6cc 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -46,3 +46,9 @@ required-features = ["c", "compiler-builtins"] [workspace] members = ["testcrate"] + +[profile.release] +panic = 'abort' + +[profile.dev] +panic = 'abort' From 1af471e00b32a849703b366962a594faf5e5d2b1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 21 Nov 2018 10:48:58 -0800 Subject: [PATCH 0627/4206] Use `nm` on OSX Looks like it may be fixed now? --- library/compiler-builtins/ci/run.sh | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 8c85038f97a7d..b77752288d9c6 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -64,18 +64,7 @@ case $1 in ;; esac -case "$TRAVIS_OS_NAME" in - osx) - # NOTE OSx's nm doesn't accept the `--defined-only` or provide an equivalent. - # Use GNU nm instead - NM=gnm - brew update - brew install binutils - ;; - *) - NM=nm - ;; -esac +NM=nm if [ -d /target ]; then path=/target/${1}/debug/deps/libcompiler_builtins-*.rlib From e367858b0e627ff824428c906094b47cc9dfbfee Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 21 Nov 2018 11:07:07 -0800 Subject: [PATCH 0628/4206] Remove unknown feature --- library/compiler-builtins/examples/intrinsics.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 1c498176c1303..c1a781415edf1 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -11,7 +11,6 @@ #![feature(lang_items)] #![feature(start)] #![feature(allocator_api)] -#![cfg_attr(windows, feature(panic_unwind))] #![no_std] extern crate panic_handler; From d90aa8c244a9de892d93735f1123cab2e3bb5640 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 21 Nov 2018 11:09:24 -0800 Subject: [PATCH 0629/4206] Add some crate metadata --- library/compiler-builtins/Cargo.toml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index a7f34c007a6cc..97cad699cb999 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -2,6 +2,15 @@ authors = ["Jorge Aparicio "] name = "compiler_builtins" version = "0.1.0" +license = "MIT/Apache-2.0" +readme = "README.md" +repository = "https://github.com/rust-lang-nursery/compiler-builtins" +homepage = "https://github.com/rust-lang-nursery/compiler-builtins" +documentation = "https://docs.rs/compiler_builtins" +description = """ +Compiler intrinsics used by the Rust compiler. Also available for other targets +if necessary! +""" [lib] test = false From 9690d3a17ecfd0548b60157a83d5c29352a483da Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 21 Nov 2018 11:56:04 -0800 Subject: [PATCH 0630/4206] Try to fix Windows build issue --- library/compiler-builtins/examples/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index c1a781415edf1..c52b4f0d76873 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -15,7 +15,7 @@ extern crate panic_handler; -#[cfg(not(thumb))] +#[cfg(all(not(thumb), not(windows)))] #[link(name = "c")] extern {} From 08db8f31d38ce77e0562cf2a9a07ba6cf4949408 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 21 Nov 2018 12:55:06 -0800 Subject: [PATCH 0631/4206] Add metadata for where compiler-rt is located Compiler crates will need to use this! --- library/compiler-builtins/Cargo.toml | 1 + library/compiler-builtins/build.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 97cad699cb999..5b9469b3d2bcd 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -11,6 +11,7 @@ description = """ Compiler intrinsics used by the Rust compiler. Also available for other targets if necessary! """ +links = 'compiler-rt' [lib] test = false diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index f5ada024f41ef..752bba1343f6f 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -4,6 +4,9 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); let target = env::var("TARGET").unwrap(); + let cwd = env::current_dir().unwrap(); + + println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display()); // Emscripten's runtime includes all the builtins if target.contains("emscripten") { From 018fa133fd41781426a7f096e9766ec7a97ac124 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 21 Nov 2018 12:57:14 -0800 Subject: [PATCH 0632/4206] Add a whitelist of included files in packaging --- library/compiler-builtins/Cargo.toml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 5b9469b3d2bcd..13d0b18e35b18 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -11,6 +11,16 @@ description = """ Compiler intrinsics used by the Rust compiler. Also available for other targets if necessary! """ +include = [ + '/Cargo.toml', + '/build.rs', + '/src/*', + '/examples/*', + '/LICENSE.txt', + '/README.md', + '/compiler-rt/*', + '/libm/src/math/*', +] links = 'compiler-rt' [lib] From 693a2636607c8fce4d6a7922722d092aaed58621 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 21 Nov 2018 12:57:54 -0800 Subject: [PATCH 0633/4206] Bump to 0.1.1 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 13d0b18e35b18..cf996ef2f4478 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.0" +version = "0.1.1" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" From b29ccbb6e9e25565b18be8716de504b128c43fdd Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 26 Nov 2018 12:09:10 -0800 Subject: [PATCH 0634/4206] Bump to 0.1.2 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index cf996ef2f4478..07afd3046866b 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.1" +version = "0.1.2" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" From 1a1dd89a320a55e1f0927088aa8fb194feef3118 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 20 Dec 2018 17:47:57 -0700 Subject: [PATCH 0635/4206] start of __clzsi2 --- library/compiler-builtins/src/arm.rs | 58 ++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 9e43aec7d345a..111e6974f34a7 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -233,3 +233,61 @@ pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); } + +#[no_mangle] +#[cfg(any(target_pointer_width = "16", target_pointer_width = "32", target_pointer_width = "64"))] +pub extern "C" fn __clzsi2(mut x: usize) -> usize { + // TODO: const this? Requires const if + let mut y: usize; + let mut n: usize = { + #[cfg(target_pointer_width = "64")] + { + 64 + } + #[cfg(target_pointer_width = "32")] + { + 32 + } + #[cfg(target_pointer_width = "16")] + { + 16 + } + }; + #[cfg(target_pointer_width = "64")] + { + y = x >> 32; + if y != 0 { + n -= 32; + x = y; + } + } + #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] + { + y = x >> 16; + if y != 0 { + n -= 16; + x = y; + } + } + y = x >> 8; + if y != 0 { + n -= 8; + x = y; + } + y = x >> 4; + if y != 0 { + n -= 4; + x = y; + } + y = x >> 2; + if y != 0 { + n -= 2; + x = y; + } + y = x >> 1; + if y != 0 { + n - 2 + } else { + n - x + } +} From 9e1de34b4e36078c0f12c1e11c6981c5aadf7f7d Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 20 Dec 2018 17:53:10 -0700 Subject: [PATCH 0636/4206] modify to fit into standard rustfmt output --- library/compiler-builtins/src/arm.rs | 92 +++++++++++++++------------- 1 file changed, 48 insertions(+), 44 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 111e6974f34a7..009b1ff69f57c 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -235,59 +235,63 @@ pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { } #[no_mangle] -#[cfg(any(target_pointer_width = "16", target_pointer_width = "32", target_pointer_width = "64"))] +#[cfg(any( + target_pointer_width = "16", + target_pointer_width = "32", + target_pointer_width = "64" +))] pub extern "C" fn __clzsi2(mut x: usize) -> usize { - // TODO: const this? Requires const if - let mut y: usize; - let mut n: usize = { + // TODO: const this? Requires const if + let mut y: usize; + let mut n: usize = { + #[cfg(target_pointer_width = "64")] + { + 64 + } + #[cfg(target_pointer_width = "32")] + { + 32 + } + #[cfg(target_pointer_width = "16")] + { + 16 + } + }; #[cfg(target_pointer_width = "64")] { - 64 + y = x >> 32; + if y != 0 { + n -= 32; + x = y; + } } - #[cfg(target_pointer_width = "32")] + #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] { - 32 + y = x >> 16; + if y != 0 { + n -= 16; + x = y; + } } - #[cfg(target_pointer_width = "16")] - { - 16 + y = x >> 8; + if y != 0 { + n -= 8; + x = y; + } + y = x >> 4; + if y != 0 { + n -= 4; + x = y; } - }; - #[cfg(target_pointer_width = "64")] - { - y = x >> 32; + y = x >> 2; if y != 0 { - n -= 32; - x = y; + n -= 2; + x = y; } - } - #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] - { - y = x >> 16; + y = x >> 1; if y != 0 { - n -= 16; - x = y; + n - 2 + } else { + n - x } - } - y = x >> 8; - if y != 0 { - n -= 8; - x = y; - } - y = x >> 4; - if y != 0 { - n -= 4; - x = y; - } - y = x >> 2; - if y != 0 { - n -= 2; - x = y; - } - y = x >> 1; - if y != 0 { - n - 2 - } else { - n - x - } } From 86de7413562fffb54e69a1d6c855b6d9f336d5c2 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 21 Dec 2018 18:02:12 -0700 Subject: [PATCH 0637/4206] Move clzi2 into the int module --- library/compiler-builtins/src/arm.rs | 62 ------------------------ library/compiler-builtins/src/int/mod.rs | 62 ++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 62 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 009b1ff69f57c..9e43aec7d345a 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -233,65 +233,3 @@ pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); } - -#[no_mangle] -#[cfg(any( - target_pointer_width = "16", - target_pointer_width = "32", - target_pointer_width = "64" -))] -pub extern "C" fn __clzsi2(mut x: usize) -> usize { - // TODO: const this? Requires const if - let mut y: usize; - let mut n: usize = { - #[cfg(target_pointer_width = "64")] - { - 64 - } - #[cfg(target_pointer_width = "32")] - { - 32 - } - #[cfg(target_pointer_width = "16")] - { - 16 - } - }; - #[cfg(target_pointer_width = "64")] - { - y = x >> 32; - if y != 0 { - n -= 32; - x = y; - } - } - #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] - { - y = x >> 16; - if y != 0 { - n -= 16; - x = y; - } - } - y = x >> 8; - if y != 0 { - n -= 8; - x = y; - } - y = x >> 4; - if y != 0 { - n -= 4; - x = y; - } - y = x >> 2; - if y != 0 { - n -= 2; - x = y; - } - y = x >> 1; - if y != 0 { - n - 2 - } else { - n - x - } -} diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index b645b21454004..11fd49bbc886d 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -300,3 +300,65 @@ macro_rules! impl_wide_int { impl_wide_int!(u32, u64, 32); impl_wide_int!(u64, u128, 64); + +#[no_mangle] +#[cfg(any( + target_pointer_width = "16", + target_pointer_width = "32", + target_pointer_width = "64" +))] +pub extern "C" fn __clzsi2(mut x: usize) -> usize { + // TODO: const this? Would require const-if + let mut y: usize; + let mut n: usize = { + #[cfg(target_pointer_width = "64")] + { + 64 + } + #[cfg(target_pointer_width = "32")] + { + 32 + } + #[cfg(target_pointer_width = "16")] + { + 16 + } + }; + #[cfg(target_pointer_width = "64")] + { + y = x >> 32; + if y != 0 { + n -= 32; + x = y; + } + } + #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] + { + y = x >> 16; + if y != 0 { + n -= 16; + x = y; + } + } + y = x >> 8; + if y != 0 { + n -= 8; + x = y; + } + y = x >> 4; + if y != 0 { + n -= 4; + x = y; + } + y = x >> 2; + if y != 0 { + n -= 2; + x = y; + } + y = x >> 1; + if y != 0 { + n - 2 + } else { + n - x + } +} From a57c899eb118da796e045f6ea43d7c941081760e Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 21 Dec 2018 18:10:45 -0700 Subject: [PATCH 0638/4206] trying a test case for clzsi2 --- library/compiler-builtins/testcrate/build.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index d862e0d0ffbf9..08c14fda5334c 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -775,6 +775,12 @@ fn main() { (builtins::int::udiv::__udivmodti4(a, b, Some(&mut r)), r) }"); } + + // count leading zeros + gen(|(a): (usize)| { + Some(a.leading_zeros()) + }, + "builtins::int::__clzsi2(a)"); } macro_rules! gen_float { From 734b5c261ac295a266bcdd8424a2a3072f2aeef5 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 21 Dec 2018 18:20:59 -0700 Subject: [PATCH 0639/4206] We can't accept usize directly, i guess accept `MyU64`? --- library/compiler-builtins/testcrate/build.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 08c14fda5334c..0fa2f5631b9ad 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -777,10 +777,12 @@ fn main() { } // count leading zeros - gen(|(a): (usize)| { - Some(a.leading_zeros()) + gen(|a: MyU128| { + Some((a as usize).leading_zeros()) }, - "builtins::int::__clzsi2(a)"); + "{ + builtins::int::__clzsi2(a as usize) + }"); } macro_rules! gen_float { From e495054f893683f3a2f48dbd2d65ba8a7eaf1733 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 21 Dec 2018 18:21:47 -0700 Subject: [PATCH 0640/4206] 64, not 128! --- library/compiler-builtins/testcrate/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 0fa2f5631b9ad..292d36a77ac8e 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -777,7 +777,7 @@ fn main() { } // count leading zeros - gen(|a: MyU128| { + gen(|a: MyU64| { Some((a as usize).leading_zeros()) }, "{ From e5123b4625094408749422dfc262a0a32bdaa348 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 21 Dec 2018 18:36:26 -0700 Subject: [PATCH 0641/4206] forgot the little `.0` part --- library/compiler-builtins/testcrate/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 292d36a77ac8e..1a5105407e4b6 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -778,7 +778,7 @@ fn main() { // count leading zeros gen(|a: MyU64| { - Some((a as usize).leading_zeros()) + Some((a.0 as usize).leading_zeros()) }, "{ builtins::int::__clzsi2(a as usize) From fe9b17acec9b1e0d2028ab997ca5768708bd2867 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 21 Dec 2018 18:47:03 -0700 Subject: [PATCH 0642/4206] Rust and LLVM don't spec the same output types --- library/compiler-builtins/testcrate/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 1a5105407e4b6..4f10adcf029b3 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -778,7 +778,7 @@ fn main() { // count leading zeros gen(|a: MyU64| { - Some((a.0 as usize).leading_zeros()) + Some((a.0 as usize).leading_zeros() as usize) }, "{ builtins::int::__clzsi2(a as usize) From d422c9a587d1ebd051f45dd1b6fd6d003ee0856c Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 21 Dec 2018 18:55:01 -0700 Subject: [PATCH 0643/4206] Okay we'll process outputs as all u32 --- library/compiler-builtins/testcrate/build.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 4f10adcf029b3..c18daca2458ee 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -778,10 +778,10 @@ fn main() { // count leading zeros gen(|a: MyU64| { - Some((a.0 as usize).leading_zeros() as usize) + Some((a.0 as usize).leading_zeros()) }, "{ - builtins::int::__clzsi2(a as usize) + builtins::int::__clzsi2(a as usize) as u32 }"); } From f1971b5b710a35c758e5662af904b4e28f7426ff Mon Sep 17 00:00:00 2001 From: akashfortanix Date: Thu, 27 Dec 2018 19:13:50 +0530 Subject: [PATCH 0644/4206] expose ceil, floor and trunc on sgx-target --- library/compiler-builtins/src/math.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index c37243504b1b8..e2b15c6a7b594 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -66,6 +66,16 @@ no_mangle! { fn tanhf(n: f32) -> f32; } +#[cfg(target_env = "sgx")] +no_mangle! { + fn ceil(x: f64) -> f64; + fn ceilf(x: f32) -> f32; + fn floor(x: f64) -> f64; + fn floorf(x: f32) -> f32; + fn trunc(x: f64) -> f64; + fn truncf(x: f32) -> f32; +} + // only for the thumb*-none-eabi* targets #[cfg(all(target_arch = "arm", target_os = "none"))] no_mangle! { From b549e21009f1341fee325938a2a1f7df66b5671c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 2 Jan 2019 10:21:41 -0800 Subject: [PATCH 0645/4206] Bump to 0.1.3 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 07afd3046866b..32cc2681d7a86 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.2" +version = "0.1.3" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" From a68950646f9ff08e7dce7e5b110a2a3d2f7fc01f Mon Sep 17 00:00:00 2001 From: Lokathor Date: Wed, 2 Jan 2019 18:50:11 -0700 Subject: [PATCH 0646/4206] Move the test to be a standard test. --- library/compiler-builtins/testcrate/build.rs | 8 ------ .../testcrate/tests/count_leading_zeros.rs | 25 +++++++++++++++++++ 2 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 library/compiler-builtins/testcrate/tests/count_leading_zeros.rs diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index c18daca2458ee..d862e0d0ffbf9 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -775,14 +775,6 @@ fn main() { (builtins::int::udiv::__udivmodti4(a, b, Some(&mut r)), r) }"); } - - // count leading zeros - gen(|a: MyU64| { - Some((a.0 as usize).leading_zeros()) - }, - "{ - builtins::int::__clzsi2(a as usize) as u32 - }"); } macro_rules! gen_float { diff --git a/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs b/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs new file mode 100644 index 0000000000000..559650174542a --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs @@ -0,0 +1,25 @@ +#![feature(compiler_builtins_lib)] + +extern crate compiler_builtins; + +use compiler_builtins::int::__clzsi2; + +#[test] +fn __clzsi2_test() { + let mut i: usize = core::usize::MAX; + // Check all values above 0 + while i > 0 { + assert_eq!(__clzsi2(i) as u32, i.leading_zeros()); + i >>= 1; + } + // check 0 also + i = 0; + assert_eq!(__clzsi2(i) as u32, i.leading_zeros()); + // double check for bit patterns that aren't just solid 1s + i = 1; + for _ in 0..63 { + assert_eq!(__clzsi2(i) as u32, i.leading_zeros()); + i <<= 2; + i += 1; + } +} From c5dc23d75d36f414a47034d9510fec56d84ae2b0 Mon Sep 17 00:00:00 2001 From: Yu Ding Date: Thu, 3 Jan 2019 12:53:08 -0800 Subject: [PATCH 0647/4206] Fix SGX target_env collision Signed-off-by: Yu Ding --- library/compiler-builtins/build.rs | 2 +- library/compiler-builtins/src/lib.rs | 3 ++- library/compiler-builtins/src/math.rs | 5 +++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 752bba1343f6f..78a4ce2fb110d 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -22,7 +22,7 @@ fn main() { // Forcibly enable memory intrinsics on wasm32 & SGX as we don't have a libc to // provide them. - if target.contains("wasm32") || target.contains("sgx") { + if target.contains("wasm32") || (target.contains("sgx") && target.contains("fortanix")) { println!("cargo:rustc-cfg=feature=\"mem\""); } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 9bb38f39aa2fc..0acb00698d2a5 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -16,6 +16,7 @@ #![feature(abi_unadjusted)] #![feature(linkage)] #![feature(lang_items)] +#![feature(cfg_target_vendor)] #![allow(unused_features)] #![no_builtins] #![cfg_attr(feature = "compiler-builtins", feature(staged_api))] @@ -49,7 +50,7 @@ pub mod float; #[cfg(any(all(target_arch = "wasm32", target_os = "unknown"), all(target_arch = "arm", target_os = "none"), - target_env = "sgx"))] + all(target_vendor = "fortanix", target_env = "sgx")))] pub mod math; pub mod mem; diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index e2b15c6a7b594..18def0e86c70b 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -15,7 +15,8 @@ macro_rules! no_mangle { } // only for the wasm32-unknown-unknown target -#[cfg(any(all(target_arch = "wasm32", target_os = "unknown"), target_env = "sgx"))] +#[cfg(any(all(target_arch = "wasm32", target_os = "unknown"), + all(target_vendor = "fortanix", target_env = "sgx")))] no_mangle! { fn acos(x: f64) -> f64; fn asin(x: f64) -> f64; @@ -66,7 +67,7 @@ no_mangle! { fn tanhf(n: f32) -> f32; } -#[cfg(target_env = "sgx")] +#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] no_mangle! { fn ceil(x: f64) -> f64; fn ceilf(x: f32) -> f32; From 905869e4d5b229a12d43f706e59efc300ba7aa1b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 3 Jan 2019 13:55:02 -0800 Subject: [PATCH 0648/4206] Bump to 0.1.4 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 32cc2681d7a86..7dce4b07b02f3 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.3" +version = "0.1.4" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" From 8b002dcd525fbda817d802f2e8f624dde3ae4ee8 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 4 Jan 2019 19:17:02 -0700 Subject: [PATCH 0649/4206] Attempt to use `intrinsics!` --- library/compiler-builtins/src/int/mod.rs | 97 ++++++++++++------------ 1 file changed, 50 insertions(+), 47 deletions(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 11fd49bbc886d..52a4227a09b6b 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -301,64 +301,67 @@ macro_rules! impl_wide_int { impl_wide_int!(u32, u64, 32); impl_wide_int!(u64, u128, 64); -#[no_mangle] -#[cfg(any( - target_pointer_width = "16", - target_pointer_width = "32", - target_pointer_width = "64" -))] -pub extern "C" fn __clzsi2(mut x: usize) -> usize { - // TODO: const this? Would require const-if - let mut y: usize; - let mut n: usize = { +intrinsics! { + #[cfg(any( + target_pointer_width = "16", + target_pointer_width = "32", + target_pointer_width = "64" + ))] + pub extern "C" fn __clzsi2(x: usize) -> usize { + // TODO: const this? Would require const-if + // Note(Lokathor): the `intrinsics!` macro can't process mut inputs + let mut x = x; + let mut y: usize; + let mut n: usize = { + #[cfg(target_pointer_width = "64")] + { + 64 + } + #[cfg(target_pointer_width = "32")] + { + 32 + } + #[cfg(target_pointer_width = "16")] + { + 16 + } + }; #[cfg(target_pointer_width = "64")] { - 64 + y = x >> 32; + if y != 0 { + n -= 32; + x = y; + } } - #[cfg(target_pointer_width = "32")] + #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] { - 32 + y = x >> 16; + if y != 0 { + n -= 16; + x = y; + } } - #[cfg(target_pointer_width = "16")] - { - 16 + y = x >> 8; + if y != 0 { + n -= 8; + x = y; } - }; - #[cfg(target_pointer_width = "64")] - { - y = x >> 32; + y = x >> 4; if y != 0 { - n -= 32; + n -= 4; x = y; } - } - #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] - { - y = x >> 16; + y = x >> 2; if y != 0 { - n -= 16; + n -= 2; x = y; } - } - y = x >> 8; - if y != 0 { - n -= 8; - x = y; - } - y = x >> 4; - if y != 0 { - n -= 4; - x = y; - } - y = x >> 2; - if y != 0 { - n -= 2; - x = y; - } - y = x >> 1; - if y != 0 { - n - 2 - } else { - n - x + y = x >> 1; + if y != 0 { + n - 2 + } else { + n - x + } } } From deb1cb51d13642a1c6390f2b593ddba74c88dd38 Mon Sep 17 00:00:00 2001 From: Denys Zariaiev Date: Sun, 6 Jan 2019 16:28:46 +0100 Subject: [PATCH 0650/4206] Don't build compiler-rt for NVPTX --- library/compiler-builtins/build.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 752bba1343f6f..b094734539e33 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -36,8 +36,8 @@ fn main() { // build anything and we rely on the upstream implementation of compiler-rt // functions if !cfg!(feature = "mangled-names") && cfg!(feature = "c") { - // no C compiler for wasm - if !target.contains("wasm32") { + // Don't use C compiler for bitcode-only wasm and nvptx + if !target.contains("wasm32") && !target.contains("nvptx") { #[cfg(feature = "c")] c::compile(&llvm_target); println!("cargo:rustc-cfg=use_c"); From 5b18b6471dab40d72a2cfc405972e1b7a50f664f Mon Sep 17 00:00:00 2001 From: Lokathor Date: Mon, 7 Jan 2019 11:52:30 -0700 Subject: [PATCH 0651/4206] Version Bump for count leading zeros --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 07afd3046866b..32cc2681d7a86 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.2" +version = "0.1.3" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" From c48d0c3d999aebba85af9dd59d97f3e2a76b3898 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Mon, 7 Jan 2019 12:08:18 -0700 Subject: [PATCH 0652/4206] Perform the correct version bump --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 7dce4b07b02f3..de2996b215d30 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.4" +version = "0.1.5" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" From 2b8e3f6029a4710f30d023808285b8ebbd1ebd26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cyryl=20P=C5=82otnicki?= Date: Sun, 20 Jan 2019 09:33:55 +0000 Subject: [PATCH 0653/4206] Fix compilation on new nightly. Compilation on rustc 1.33.0-nightly (c76f3c374 2019-01-18) failed with ``` error: the feature `cfg_target_vendor` has been stable since 1.33.0 and no longer requires an attribute to enable --> src/lib.rs:19:12 | 19 | #![feature(cfg_target_vendor)] | ^^^^^^^^^^^^^^^^^ | ``` Removed the attribute to make it compile. --- library/compiler-builtins/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 0acb00698d2a5..fddfa67aa8ea1 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -16,7 +16,6 @@ #![feature(abi_unadjusted)] #![feature(linkage)] #![feature(lang_items)] -#![feature(cfg_target_vendor)] #![allow(unused_features)] #![no_builtins] #![cfg_attr(feature = "compiler-builtins", feature(staged_api))] From 55f0ab112a4cec08681aae2b0ab4d0a39bdba8a8 Mon Sep 17 00:00:00 2001 From: MikaelUrankar Date: Sat, 2 Feb 2019 19:52:41 +0100 Subject: [PATCH 0654/4206] FreeBSD arm needs clear_cache.c --- library/compiler-builtins/build.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 057f5d9d82e52..9a7c05eb0a78e 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -311,6 +311,10 @@ mod c { ], ); + if target_os == "freebsd" { + sources.extend(&["clear_cache.c"]); + } + // First of all aeabi_cdcmp and aeabi_cfcmp are never called by LLVM. // Second are little-endian only, so build fail on big-endian targets. // Temporally workaround: exclude these files for big-endian targets. From cab813bf74205cbe49431f98e49fc6427a14ca87 Mon Sep 17 00:00:00 2001 From: Jordan Rhee Date: Wed, 27 Feb 2019 11:39:49 -0800 Subject: [PATCH 0655/4206] Fix undefined symbol errors on windows/arm Fix undefined symbol linker errors when building rust for windows/arm by excluding unneeded symbols. The errors are: = note: lib.def : error LNK2001: unresolved external symbol __aeabi_memclr4 lib.def : error LNK2001: unresolved external symbol __aeabi_memclr8 lib.def : error LNK2001: unresolved external symbol __aeabi_memmove4 lib.def : error LNK2001: unresolved external symbol __aeabi_memmove8 --- library/compiler-builtins/src/arm.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 9e43aec7d345a..9bfffb74fc95f 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -164,14 +164,14 @@ pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: u ::mem::memmove(dest, src, n); } -#[cfg(not(target_os = "ios"))] +#[cfg(not(any(target_os = "ios", target_env = "msvc")))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memmove(dest, src, n); } -#[cfg(not(target_os = "ios"))] +#[cfg(not(any(target_os = "ios", target_env = "msvc")))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { @@ -220,14 +220,14 @@ pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { __aeabi_memset(dest, n, 0); } -#[cfg(not(target_os = "ios"))] +#[cfg(not(any(target_os = "ios", target_env = "msvc")))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); } -#[cfg(not(target_os = "ios"))] +#[cfg(not(any(target_os = "ios", target_env = "msvc")))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { From 648db7498b471619870e295f8f8e3eab55be50fe Mon Sep 17 00:00:00 2001 From: Jordan Rhee Date: Wed, 27 Feb 2019 11:45:14 -0800 Subject: [PATCH 0656/4206] Bump version to 0.1.6 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index de2996b215d30..44dabada166ef 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.5" +version = "0.1.6" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" From b94478025096c875b396ba98de745b8655fe8035 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 27 Feb 2019 12:39:34 -0800 Subject: [PATCH 0657/4206] Bump to 0.1.7 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 44dabada166ef..62900bff6e63f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.6" +version = "0.1.7" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" From 8d0fdce9ca55b5d8f7732a35a452e0dcfbb364c2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 13 Mar 2019 08:19:30 -0700 Subject: [PATCH 0658/4206] Don't compile memory intrinsics on wasi --- library/compiler-builtins/build.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 9a7c05eb0a78e..5d555d6082869 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -22,7 +22,8 @@ fn main() { // Forcibly enable memory intrinsics on wasm32 & SGX as we don't have a libc to // provide them. - if target.contains("wasm32") || (target.contains("sgx") && target.contains("fortanix")) { + if (target.contains("wasm32") && !target.contains("wasi")) || + (target.contains("sgx") && target.contains("fortanix")) { println!("cargo:rustc-cfg=feature=\"mem\""); } @@ -314,7 +315,7 @@ mod c { if target_os == "freebsd" { sources.extend(&["clear_cache.c"]); } - + // First of all aeabi_cdcmp and aeabi_cfcmp are never called by LLVM. // Second are little-endian only, so build fail on big-endian targets. // Temporally workaround: exclude these files for big-endian targets. From e7c41f4a8418b27525ebbb989c78a8fc74d999aa Mon Sep 17 00:00:00 2001 From: Hugues de Valon Date: Thu, 7 Mar 2019 19:24:15 +0000 Subject: [PATCH 0659/4206] Fix Armv8-M Baseline compilation Armv8-M Baseline, ie thumbv8m.base-none-eabi, is a superset of the Armv6-M architecture profile. As it shares almost the same instruction set, this commit copies the configuration for thumbv6m-none-eabi to enable it. --- library/compiler-builtins/build.rs | 11 ++++++----- library/compiler-builtins/src/int/sdiv.rs | 6 +++--- library/compiler-builtins/src/int/udiv.rs | 4 ++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 9a7c05eb0a78e..6cef4be394073 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -49,10 +49,11 @@ fn main() { println!("cargo:rustc-cfg=thumb") } - // compiler-rt `cfg`s away some intrinsics for thumbv6m because that target doesn't have full - // THUMBv2 support. We have to cfg our code accordingly. - if llvm_target[0] == "thumbv6m" { - println!("cargo:rustc-cfg=thumbv6m") + // 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. + if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" { + println!("cargo:rustc-cfg=thumb_1") } // Only emit the ARM Linux atomic emulation on pre-ARMv6 architectures. @@ -407,7 +408,7 @@ mod c { } // Remove the assembly implementations that won't compile for the target - if llvm_target[0] == "thumbv6m" { + if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" { sources.remove( &[ "clzdi2", diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 89bb51a47b347..a2e8aa96f9038 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -74,8 +74,8 @@ intrinsics! { #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), - not(target_env = "msvc")), - not(thumbv6m))] + not(target_env = "msvc"), + not(thumb_1)))] pub extern "C" fn __modsi3(a: i32, b: i32) -> i32 { a.mod_(b) } @@ -91,7 +91,7 @@ intrinsics! { } #[use_c_shim_if(all(target_arch = "arm", not(target_env = "msvc"), - not(target_os = "ios"), not(thumbv6m)))] + not(target_os = "ios"), not(thumb_1)))] pub extern "C" fn __divmodsi4(a: i32, b: i32, rem: &mut i32) -> i32 { a.divmod(b, rem, |a, b| __divsi3(a, b)) } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index a2572227f9702..d873559bdd899 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -212,7 +212,7 @@ intrinsics! { #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), not(target_env = "msvc"), - not(thumbv6m)))] + not(thumb_1)))] /// Returns `n % d` pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { let q = __udivsi3(n, d); @@ -222,7 +222,7 @@ intrinsics! { #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), not(target_env = "msvc"), - not(thumbv6m)))] + not(thumb_1)))] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { let q = __udivsi3(n, d); From ae7b057cdb913b64a08498b816c30e2691a74118 Mon Sep 17 00:00:00 2001 From: Hugues de Valon Date: Thu, 7 Mar 2019 19:30:39 +0000 Subject: [PATCH 0660/4206] Fix compilation for thumbv8m.main-none-eabihf Some files were not assembling for the Armv8-M Mainline architecture profile with FPU extension. Reason being the same as for Armv7-M: the conversion intrinsics including double precision floating point variables do not work with single precision FPUs. Also removes from exclusion files that are assembling without errors for Armv7-M and Armv8-M Mainline. --- library/compiler-builtins/build.rs | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 6cef4be394073..ccd908caa36ec 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -360,24 +360,36 @@ mod c { } if llvm_target.last().unwrap().ends_with("eabihf") { - if !llvm_target[0].starts_with("thumbv7em") { + if !llvm_target[0].starts_with("thumbv7em") && + !llvm_target[0].starts_with("thumbv8m.main") { + // The FPU option chosen for these architectures in cc-rs, ie: + // -mfpu=fpv4-sp-d16 for thumbv7em + // -mfpu=fpv5-sp-d16 for thumbv8m.main + // do not support double precision floating points conversions so the files + // that include such instructions are not included for these targets. sources.extend( &[ "arm/fixdfsivfp.S", - "arm/fixsfsivfp.S", "arm/fixunsdfsivfp.S", - "arm/fixunssfsivfp.S", "arm/floatsidfvfp.S", - "arm/floatsisfvfp.S", "arm/floatunssidfvfp.S", - "arm/floatunssisfvfp.S", - "arm/restore_vfp_d8_d15_regs.S", - "arm/save_vfp_d8_d15_regs.S", ], ); } - sources.extend(&["arm/negdf2vfp.S", "arm/negsf2vfp.S"]); + sources.extend( + &[ + "arm/fixsfsivfp.S", + "arm/fixunssfsivfp.S", + "arm/floatsisfvfp.S", + "arm/floatunssisfvfp.S", + "arm/floatunssisfvfp.S", + "arm/restore_vfp_d8_d15_regs.S", + "arm/save_vfp_d8_d15_regs.S", + "arm/negdf2vfp.S", + "arm/negsf2vfp.S", + ] + ); } From b8413ddc326efe629f6fd307f113fa0fc46cdd77 Mon Sep 17 00:00:00 2001 From: Hugues de Valon Date: Thu, 7 Mar 2019 19:34:53 +0000 Subject: [PATCH 0661/4206] Remove thumbv6m configuration of intrinsic example It seems that the intrinsics that were generated for the functions in example/intrinsics.rs where different implementations were given for thumb6m-none-eabi target, have now been implemented in Rust so configuration is not needed anymore. --- .../compiler-builtins/examples/intrinsics.rs | 63 ------------------- 1 file changed, 63 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index c52b4f0d76873..89c2c23dbfc71 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -19,9 +19,6 @@ extern crate panic_handler; #[link(name = "c")] extern {} -// NOTE cfg(not(thumbv6m)) means that the operation is not supported on ARMv6-M at all. Not even -// compiler-rt provides a C/assembly implementation. - // Every function in this module maps will be lowered to an intrinsic by LLVM, if the platform // doesn't have native support for the operation used in the function. ARM has a naming convention // convention for its intrinsics that's different from other architectures; that's why some function @@ -39,70 +36,40 @@ mod intrinsics { } // fixdfdi - #[cfg(not(thumbv6m))] pub fn aeabi_d2l(x: f64) -> i64 { x as i64 } - #[cfg(thumbv6m)] - pub fn aeabi_d2l(_: f64) -> i64 { - 0 - } - // fixunsdfsi pub fn aeabi_d2uiz(x: f64) -> u32 { x as u32 } // fixunsdfdi - #[cfg(not(thumbv6m))] pub fn aeabi_d2ulz(x: f64) -> u64 { x as u64 } - #[cfg(thumbv6m)] - pub fn aeabi_d2ulz(_: f64) -> u64 { - 0 - } - // adddf3 pub fn aeabi_dadd(a: f64, b: f64) -> f64 { a + b } // eqdf2 - #[cfg(not(thumbv6m))] pub fn aeabi_dcmpeq(a: f64, b: f64) -> bool { a == b } - #[cfg(thumbv6m)] - pub fn aeabi_dcmpeq(_: f64, _: f64) -> bool { - true - } - // gtdf2 - #[cfg(not(thumbv6m))] pub fn aeabi_dcmpgt(a: f64, b: f64) -> bool { a > b } - #[cfg(thumbv6m)] - pub fn aeabi_dcmpgt(_: f64, _: f64) -> bool { - true - } - // ltdf2 - #[cfg(not(thumbv6m))] pub fn aeabi_dcmplt(a: f64, b: f64) -> bool { a < b } - #[cfg(thumbv6m)] - pub fn aeabi_dcmplt(_: f64, _: f64) -> bool { - true - } - // divdf3 pub fn aeabi_ddiv(a: f64, b: f64) -> f64 { a / b @@ -129,70 +96,40 @@ mod intrinsics { } // fixsfdi - #[cfg(not(thumbv6m))] pub fn aeabi_f2lz(x: f32) -> i64 { x as i64 } - #[cfg(thumbv6m)] - pub fn aeabi_f2lz(_: f32) -> i64 { - 0 - } - // fixunssfsi pub fn aeabi_f2uiz(x: f32) -> u32 { x as u32 } // fixunssfdi - #[cfg(not(thumbv6m))] pub fn aeabi_f2ulz(x: f32) -> u64 { x as u64 } - #[cfg(thumbv6m)] - pub fn aeabi_f2ulz(_: f32) -> u64 { - 0 - } - // addsf3 pub fn aeabi_fadd(a: f32, b: f32) -> f32 { a + b } // eqsf2 - #[cfg(not(thumbv6m))] pub fn aeabi_fcmpeq(a: f32, b: f32) -> bool { a == b } - #[cfg(thumbv6m)] - pub fn aeabi_fcmpeq(_: f32, _: f32) -> bool { - true - } - // gtsf2 - #[cfg(not(thumbv6m))] pub fn aeabi_fcmpgt(a: f32, b: f32) -> bool { a > b } - #[cfg(thumbv6m)] - pub fn aeabi_fcmpgt(_: f32, _: f32) -> bool { - true - } - // ltsf2 - #[cfg(not(thumbv6m))] pub fn aeabi_fcmplt(a: f32, b: f32) -> bool { a < b } - #[cfg(thumbv6m)] - pub fn aeabi_fcmplt(_: f32, _: f32) -> bool { - true - } - // divsf3 pub fn aeabi_fdiv(a: f32, b: f32) -> f32 { a / b From a634eff2801f0ddaf22ce36e9010f5e5f6b59f60 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 21 Mar 2019 07:52:59 -0700 Subject: [PATCH 0662/4206] Bump to 0.1.8 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 62900bff6e63f..d30af40511da3 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.7" +version = "0.1.8" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" From a806c53b2cfb1d17c6825691cf1f1a5731755df3 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 07:46:06 -0700 Subject: [PATCH 0663/4206] Don't compile math symbols on wasm32-unknown-wasi These are already provided by the C sysroot, so no need for us to duplicate them! --- library/compiler-builtins/src/math.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 18def0e86c70b..dfdd99cdf9311 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -14,9 +14,14 @@ macro_rules! no_mangle { } } -// only for the wasm32-unknown-unknown target -#[cfg(any(all(target_arch = "wasm32", target_os = "unknown"), - all(target_vendor = "fortanix", target_env = "sgx")))] +#[cfg(any( + all( + target_arch = "wasm32", + target_os = "unknown", + not(target_env = "wasi") + ), + all(target_vendor = "fortanix", target_env = "sgx") +))] no_mangle! { fn acos(x: f64) -> f64; fn asin(x: f64) -> f64; From d3d3cc21260527eb24b46bbf64eb96de7ea7650e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 07:57:02 -0700 Subject: [PATCH 0664/4206] Add sample azure pipelines configuration --- library/compiler-builtins/azure-pipelines.yml | 33 +++++++++++++++++++ .../ci/azure-install-rust.yml | 25 ++++++++++++++ library/compiler-builtins/ci/azure-steps.yml | 10 ++++++ 3 files changed, 68 insertions(+) create mode 100644 library/compiler-builtins/azure-pipelines.yml create mode 100644 library/compiler-builtins/ci/azure-install-rust.yml create mode 100644 library/compiler-builtins/ci/azure-steps.yml diff --git a/library/compiler-builtins/azure-pipelines.yml b/library/compiler-builtins/azure-pipelines.yml new file mode 100644 index 0000000000000..f7a25ae00aa62 --- /dev/null +++ b/library/compiler-builtins/azure-pipelines.yml @@ -0,0 +1,33 @@ +trigger: + - master + +jobs: + - job: Linux + pool: + vmImage: ubuntu-16.04 + steps: + - template: ci/azure-steps.yml + strategy: + matrix: + aarch64-unknown-linux-gnu: + TARGET: aarch64-unknown-linux-gnu + + - job: macOS + pool: + vmImage: macos-10.13 + steps: + - template: ci/azure-steps.yml + strategy: + matrix: + x86_64-apple-darwin: + TARGET: x86_64-apple-darwin + + - job: Windows + pool: + vmImage: 'vs2017-win2016' + steps: + - template: ci/azure-steps.yml + strategy: + matrix: + i686-pc-windows-msvc: + TARGET: i686-pc-windows-msvc diff --git a/library/compiler-builtins/ci/azure-install-rust.yml b/library/compiler-builtins/ci/azure-install-rust.yml new file mode 100644 index 0000000000000..25e48f99157ac --- /dev/null +++ b/library/compiler-builtins/ci/azure-install-rust.yml @@ -0,0 +1,25 @@ +parameters: + toolchain: 'nightly' + +steps: + - bash: | + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $TOOLCHAIN + echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin" + displayName: Install rust + condition: ne( variables['Agent.OS'], 'Windows_NT' ) + env: + TOOLCHAIN: ${{ parameters.toolchain }} + + - script: | + curl -sSf -o rustup-init.exe https://win.rustup.rs + rustup-init.exe -y --default-toolchain %TOOLCHAIN% + echo "##vso[task.setvariable variable=PATH;]%PATH%;%USERPROFILE%\.cargo\bin" + displayName: Install rust + condition: eq( variables['Agent.OS'], 'Windows_NT' ) + env: + TOOLCHAIN: ${{ parameters.toolchain }} + + - script: | + rustc -Vv + cargo -V + displayName: Query rust and cargo versions diff --git a/library/compiler-builtins/ci/azure-steps.yml b/library/compiler-builtins/ci/azure-steps.yml new file mode 100644 index 0000000000000..a6acba4806995 --- /dev/null +++ b/library/compiler-builtins/ci/azure-steps.yml @@ -0,0 +1,10 @@ +steps: + - template: azure-install-rust.yml + + - bash: ./ci/run.sh $TARGET + condition: ne( variables['Agent.OS'], 'Linux' ) + displayName: Run test script + + - bash: ./ci/run-docker.sh $TARGET + condition: eq( variables['Agent.OS'], 'Linux' ) + displayName: Run docker test script From b51f3d18a32e443bd254df81ac4df17be941c03c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 07:58:12 -0700 Subject: [PATCH 0665/4206] Configure Azure Pipelines --- library/compiler-builtins/.travis.yml | 63 ------------------- library/compiler-builtins/README.md | 5 +- library/compiler-builtins/appveyor.yml | 45 ------------- library/compiler-builtins/azure-pipelines.yml | 3 +- .../ci/azure-install-rust.yml | 5 +- library/compiler-builtins/ci/azure-steps.yml | 2 + 6 files changed, 9 insertions(+), 114 deletions(-) delete mode 100644 library/compiler-builtins/.travis.yml delete mode 100644 library/compiler-builtins/appveyor.yml diff --git a/library/compiler-builtins/.travis.yml b/library/compiler-builtins/.travis.yml deleted file mode 100644 index 9b4c28419f8c7..0000000000000 --- a/library/compiler-builtins/.travis.yml +++ /dev/null @@ -1,63 +0,0 @@ -dist: trusty -language: rust -rust: nightly -services: docker -sudo: required - -matrix: - include: - - env: TARGET=aarch64-unknown-linux-gnu - - env: TARGET=arm-unknown-linux-gnueabi - - env: TARGET=arm-unknown-linux-gnueabihf - - env: TARGET=armv7-unknown-linux-gnueabihf - - env: TARGET=i586-unknown-linux-gnu - - env: TARGET=i686-apple-darwin DEBUG_LTO_BUILD_DOESNT_WORK=1 - os: osx - - env: TARGET=i686-unknown-linux-gnu - - env: TARGET=mips-unknown-linux-gnu - - env: TARGET=mips64-unknown-linux-gnuabi64 - - env: TARGET=mips64el-unknown-linux-gnuabi64 - - env: TARGET=mipsel-unknown-linux-gnu - - env: TARGET=powerpc-unknown-linux-gnu - - env: TARGET=powerpc64-unknown-linux-gnu - - env: TARGET=powerpc64le-unknown-linux-gnu - - env: TARGET=thumbv6m-linux-eabi - - env: TARGET=thumbv7em-linux-eabi - - env: TARGET=thumbv7em-linux-eabihf - - env: TARGET=thumbv7m-linux-eabi - - env: TARGET=wasm32-unknown-unknown - install: rustup target add $TARGET - script: cargo build --target $TARGET - - env: TARGET=x86_64-apple-darwin DEBUG_LTO_BUILD_DOESNT_WORK=1 - os: osx - - env: TARGET=x86_64-unknown-linux-gnu - allow_failures: - - env: TARGET=thumbv6m-linux-eabi - - env: TARGET=thumbv7em-linux-eabi - - env: TARGET=thumbv7em-linux-eabihf - - env: TARGET=thumbv7m-linux-eabi - -install: - - case $TARGET in - x86_64-apple-darwin | x86_64-unknown-linux-gnu) ;; - thumbv*eabi*) rustup component add rust-src ;; - *) rustup target add $TARGET;; - esac - -script: - # work around rust-lang/cargo#3340 - - test "$TRAVIS_OS_NAME" = "osx" || - export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt - - cargo generate-lockfile - - if [[ $TRAVIS_OS_NAME = "linux" ]]; then - sudo apt-get remove -y qemu-user-static && - sudo apt-get install -y qemu-user-static && - sh ci/run-docker.sh $TARGET; - else - sh ci/run.sh $TARGET; - fi - -notifications: - email: - on_success: never - webhooks: https://buildbot.rust-lang.org/homu/travis diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index cae885279ad1d..b290cbff88964 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -1,9 +1,8 @@ # `compiler-builtins` -[![Build status](https://ci.appveyor.com/api/projects/status/eusnjps5ui3d305p?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/compiler-builtins) -[![Build Status](https://travis-ci.org/rust-lang-nursery/compiler-builtins.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/compiler-builtins) +[![Build Status](https://dev.azure.com/rust-lang/compiler-builtins/_apis/build/status/compiler-builtins-CI?branchName=master)](https://dev.azure.com/rust-lang/compiler-builtins/_build/latest?definitionId=2&branchName=master) -> [WIP] Porting `compiler-rt` intrinsics to Rust +> Porting `compiler-rt` intrinsics to Rust See [rust-lang/rust#35437][0]. diff --git a/library/compiler-builtins/appveyor.yml b/library/compiler-builtins/appveyor.yml deleted file mode 100644 index bb78ad36a2a8e..0000000000000 --- a/library/compiler-builtins/appveyor.yml +++ /dev/null @@ -1,45 +0,0 @@ -environment: - # It's... a little unclear why the memcpy symbols clash on linux but not on - # other platforms. Would be great to not differ on this though! - INTRINSICS_FAILS_WITH_MEM_FEATURE: 1 - - matrix: - - TARGET: i686-pc-windows-msvc - - TARGET: x86_64-pc-windows-msvc - - # Ensure MinGW works, but we need to download the 32-bit MinGW compiler from a - # custom location. - # - # Note that the MinGW builds have tons of references to - # `rust_eh_unwind_resume` in the debug LTO builds that aren't optimized out, - # so we skip that test for now. Would be great to not skip it! - - TARGET: i686-pc-windows-gnu - MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror - MINGW_ARCHIVE: i686-6.3.0-release-win32-dwarf-rt_v5-rev1.7z - MINGW_DIR: mingw32 - DEBUG_LTO_BUILD_DOESNT_WORK: 1 - - TARGET: x86_64-pc-windows-gnu - DEBUG_LTO_BUILD_DOESNT_WORK: 1 - -install: - - git submodule update --init - - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - - rustup-init.exe --default-host x86_64-pc-windows-msvc --default-toolchain nightly -y - - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - - if NOT "%TARGET%" == "x86_64-pc-windows-msvc" rustup target add %TARGET% - - # Use the system msys - - set PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH% - - # download a custom compiler otherwise - - if defined MINGW_URL appveyor DownloadFile %MINGW_URL%/%MINGW_ARCHIVE% - - if defined MINGW_URL 7z x -y %MINGW_ARCHIVE% > nul - - if defined MINGW_URL set PATH=C:\Python27;%CD%\%MINGW_DIR%\bin;C:\msys64\usr\bin;%PATH% - - - rustc -Vv - - cargo -V - -build: false - -test_script: - - sh ci/run.sh %TARGET% diff --git a/library/compiler-builtins/azure-pipelines.yml b/library/compiler-builtins/azure-pipelines.yml index f7a25ae00aa62..b4b7ef81cafb1 100644 --- a/library/compiler-builtins/azure-pipelines.yml +++ b/library/compiler-builtins/azure-pipelines.yml @@ -1,6 +1,7 @@ trigger: - master - +pr: + - master jobs: - job: Linux pool: diff --git a/library/compiler-builtins/ci/azure-install-rust.yml b/library/compiler-builtins/ci/azure-install-rust.yml index 25e48f99157ac..d74946e3dfd9c 100644 --- a/library/compiler-builtins/ci/azure-install-rust.yml +++ b/library/compiler-builtins/ci/azure-install-rust.yml @@ -3,8 +3,9 @@ parameters: steps: - bash: | + set -e curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $TOOLCHAIN - echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin" + echo "##vso[task.prependpath]$HOME/.cargo/bin" displayName: Install rust condition: ne( variables['Agent.OS'], 'Windows_NT' ) env: @@ -13,7 +14,7 @@ steps: - script: | curl -sSf -o rustup-init.exe https://win.rustup.rs rustup-init.exe -y --default-toolchain %TOOLCHAIN% - echo "##vso[task.setvariable variable=PATH;]%PATH%;%USERPROFILE%\.cargo\bin" + echo ##vso[task.prependpath]%USERPROFILE%\.cargo\bin displayName: Install rust condition: eq( variables['Agent.OS'], 'Windows_NT' ) env: diff --git a/library/compiler-builtins/ci/azure-steps.yml b/library/compiler-builtins/ci/azure-steps.yml index a6acba4806995..c769941d4c626 100644 --- a/library/compiler-builtins/ci/azure-steps.yml +++ b/library/compiler-builtins/ci/azure-steps.yml @@ -1,4 +1,6 @@ steps: + - checkout: self + submodules: true - template: azure-install-rust.yml - bash: ./ci/run.sh $TARGET From cede5bc161d1cef9f13c707d1545765d7760a9f8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 08:27:38 -0700 Subject: [PATCH 0666/4206] Expand Azure Pipelines configuration --- library/compiler-builtins/azure-pipelines.yml | 51 +++++++++++++++++-- library/compiler-builtins/ci/azure-steps.yml | 4 ++ library/compiler-builtins/ci/run-docker.sh | 0 3 files changed, 50 insertions(+), 5 deletions(-) mode change 100644 => 100755 library/compiler-builtins/ci/run-docker.sh diff --git a/library/compiler-builtins/azure-pipelines.yml b/library/compiler-builtins/azure-pipelines.yml index b4b7ef81cafb1..c32262b1c7e87 100644 --- a/library/compiler-builtins/azure-pipelines.yml +++ b/library/compiler-builtins/azure-pipelines.yml @@ -1,7 +1,6 @@ trigger: - master -pr: - - master + jobs: - job: Linux pool: @@ -10,8 +9,42 @@ jobs: - template: ci/azure-steps.yml strategy: matrix: - aarch64-unknown-linux-gnu: + aarch64: TARGET: aarch64-unknown-linux-gnu + arm: + TARGET: arm-unknown-linux-gnueabi + armhf: + TARGET: arm-unknown-linux-gnueabihf + i586: + TARGET: i586-unknown-linux-gnu + i686: + TARGET: i686-unknown-linux-gnu + mips: + TARGET: mips-unknown-linux-gnu + mips64: + TARGET: mips64-unknown-linux-gnuabi64 + mips64el: + TARGET: mips64el-unknown-linux-gnuabi64 + mipsel: + TARGET: mipsel-unknown-linux-gnu + powerpc: + TARGET: powerpc-unknown-linux-gnu + powerpc64: + TARGET: powerpc64-unknown-linux-gnu + powerpc64le: + TARGET: powerpc64le-unknown-linux-gnu + thumbv6m: + TARGET: thumbv6m-linux-eabi + thumbv7em: + TARGET: thumbv7em-linux-eabi + thumbv7emhf: + TARGET: thumbv7em-linux-eabihf + thumbv7m: + TARGET: thumbv7m-linux-eabi + wasm32: + TARGET: wasm32-unknown-unknown + x86_64: + TARGET: x86_64-unknown-linux-gnu - job: macOS pool: @@ -20,8 +53,10 @@ jobs: - template: ci/azure-steps.yml strategy: matrix: - x86_64-apple-darwin: + x86_64: TARGET: x86_64-apple-darwin + i686: + TARGET: i686-apple-darwin - job: Windows pool: @@ -30,5 +65,11 @@ jobs: - template: ci/azure-steps.yml strategy: matrix: - i686-pc-windows-msvc: + i686-msvc: TARGET: i686-pc-windows-msvc + x86_64-msvc: + TARGET: x86_64-pc-windows-msvc + i686-gnu: + TARGET: i686-pc-windows-gnu + x86_64-gnu: + TARGET: x86_64-pc-windows-gnu diff --git a/library/compiler-builtins/ci/azure-steps.yml b/library/compiler-builtins/ci/azure-steps.yml index c769941d4c626..251b2d5844385 100644 --- a/library/compiler-builtins/ci/azure-steps.yml +++ b/library/compiler-builtins/ci/azure-steps.yml @@ -1,8 +1,12 @@ steps: - checkout: self submodules: true + - template: azure-install-rust.yml + - bash: rustup target add $TARGET + displayName: Install compilation target + - bash: ./ci/run.sh $TARGET condition: ne( variables['Agent.OS'], 'Linux' ) displayName: Run test script diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh old mode 100644 new mode 100755 From 95f4f0cd4eb1eee145a4d56344c314e57d8cfc4b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 08:39:19 -0700 Subject: [PATCH 0667/4206] Upgrade all docker containers to 18.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/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 +- .../compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile | 2 +- .../compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile | 2 +- .../ci/docker/thumbv7em-linux-eabihf/Dockerfile | 2 +- .../compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile | 2 +- .../ci/docker/x86_64-unknown-linux-gnu/Dockerfile | 2 +- 18 files changed, 18 insertions(+), 18 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 3f6a63fcb0d45..9e2559f4ab3a2 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 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ 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 1c31b00b4eaac..afab874bc2817 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 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ 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 c305b1ba54698..3ed3602b0dc97 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 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ 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 76f367f142ae6..6617af1558c9a 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 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ 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 fb32306090bd4..5783e28e12200 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 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc-multilib libc6-dev ca-certificates 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 fb32306090bd4..5783e28e12200 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 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc-multilib libc6-dev ca-certificates 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 71a9e8032f893..f47e8f5227b49 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 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ 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 22239e46d8aa3..8fa77c7bd0737 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 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates \ 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 77f1fd58c473a..c6611d9ac899c 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 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates \ 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 98257e768061f..0bc695624620e 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 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ 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 b6bee385ec48f..2d39fef6142bb 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 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ 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 26dc1dc27261e..653cd351156e1 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 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ 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 3b280c0bdc657..63ea9af9d2023 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 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile index ecf90087e1e97..789bdf4e46cc9 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static diff --git a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile index 029a55d29a015..c6ce273c875d3 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static diff --git a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile index 5bf0c76e5be24..c7518aaca8489 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static diff --git a/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile index 1ffac1f3345e1..c907109413914 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static 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 efc7b26c609eb..98000f4eb81a7 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 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates From 7567d9ceb4d79e2ac500620316e02718a5560504 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 09:35:47 -0700 Subject: [PATCH 0668/4206] Don't pass `-it` to docker --- library/compiler-builtins/ci/run-docker.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 5608cedc4677e..6b3066e53e66c 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -23,7 +23,7 @@ run() { -v `pwd`:/checkout:ro \ -v `rustc --print sysroot`:/rust:ro \ -w /checkout \ - -it $target \ + $target \ sh -c "HOME=/tmp PATH=\$PATH:/rust/bin ci/run.sh $target" } From a2b87a1a7fdba9c76f4c4d1b6ee273fb1b1ecfe4 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 09:53:05 -0700 Subject: [PATCH 0669/4206] Generate a lock file before using Docker Can't do it in the readonly filesystem inside! --- library/compiler-builtins/ci/azure-steps.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/azure-steps.yml b/library/compiler-builtins/ci/azure-steps.yml index 251b2d5844385..19972a7c0a356 100644 --- a/library/compiler-builtins/ci/azure-steps.yml +++ b/library/compiler-builtins/ci/azure-steps.yml @@ -11,6 +11,6 @@ steps: condition: ne( variables['Agent.OS'], 'Linux' ) displayName: Run test script - - bash: ./ci/run-docker.sh $TARGET + - bash: cargo generate-lockfile && ./ci/run-docker.sh $TARGET condition: eq( variables['Agent.OS'], 'Linux' ) displayName: Run docker test script From 742b0330c55f70ba4bc5075a656f62ca881b4898 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 11:44:28 -0700 Subject: [PATCH 0670/4206] Try to handle thumb targets and xargo --- library/compiler-builtins/azure-pipelines.yml | 61 +++++++++-------- library/compiler-builtins/ci/azure-steps.yml | 14 +++- library/compiler-builtins/ci/run-docker.sh | 1 + library/compiler-builtins/ci/run.sh | 65 +++++++++---------- 4 files changed, 75 insertions(+), 66 deletions(-) diff --git a/library/compiler-builtins/azure-pipelines.yml b/library/compiler-builtins/azure-pipelines.yml index c32262b1c7e87..ca02a515399e2 100644 --- a/library/compiler-builtins/azure-pipelines.yml +++ b/library/compiler-builtins/azure-pipelines.yml @@ -11,38 +11,43 @@ jobs: matrix: aarch64: TARGET: aarch64-unknown-linux-gnu - arm: - TARGET: arm-unknown-linux-gnueabi - armhf: - TARGET: arm-unknown-linux-gnueabihf - i586: - TARGET: i586-unknown-linux-gnu - i686: - TARGET: i686-unknown-linux-gnu - mips: - TARGET: mips-unknown-linux-gnu - mips64: - TARGET: mips64-unknown-linux-gnuabi64 - mips64el: - TARGET: mips64el-unknown-linux-gnuabi64 - mipsel: - TARGET: mipsel-unknown-linux-gnu - powerpc: - TARGET: powerpc-unknown-linux-gnu - powerpc64: - TARGET: powerpc64-unknown-linux-gnu - powerpc64le: - TARGET: powerpc64le-unknown-linux-gnu + # arm: + # TARGET: arm-unknown-linux-gnueabi + # armhf: + # TARGET: arm-unknown-linux-gnueabihf + # i586: + # TARGET: i586-unknown-linux-gnu + # i686: + # TARGET: i686-unknown-linux-gnu + # mips: + # TARGET: mips-unknown-linux-gnu + # mips64: + # TARGET: mips64-unknown-linux-gnuabi64 + # mips64el: + # TARGET: mips64el-unknown-linux-gnuabi64 + # mipsel: + # TARGET: mipsel-unknown-linux-gnu + # powerpc: + # TARGET: powerpc-unknown-linux-gnu + # powerpc64: + # TARGET: powerpc64-unknown-linux-gnu + # powerpc64le: + # TARGET: powerpc64le-unknown-linux-gnu thumbv6m: TARGET: thumbv6m-linux-eabi + XARGO: 1 thumbv7em: TARGET: thumbv7em-linux-eabi + XARGO: 1 thumbv7emhf: TARGET: thumbv7em-linux-eabihf + XARGO: 1 thumbv7m: TARGET: thumbv7m-linux-eabi + XARGO: 1 wasm32: TARGET: wasm32-unknown-unknown + ONLY_BUILD: 1 x86_64: TARGET: x86_64-unknown-linux-gnu @@ -55,8 +60,8 @@ jobs: matrix: x86_64: TARGET: x86_64-apple-darwin - i686: - TARGET: i686-apple-darwin + # i686: + # TARGET: i686-apple-darwin - job: Windows pool: @@ -67,9 +72,9 @@ jobs: matrix: i686-msvc: TARGET: i686-pc-windows-msvc - x86_64-msvc: - TARGET: x86_64-pc-windows-msvc - i686-gnu: - TARGET: i686-pc-windows-gnu + # x86_64-msvc: + # TARGET: x86_64-pc-windows-msvc + # i686-gnu: + # TARGET: i686-pc-windows-gnu x86_64-gnu: TARGET: x86_64-pc-windows-gnu diff --git a/library/compiler-builtins/ci/azure-steps.yml b/library/compiler-builtins/ci/azure-steps.yml index 19972a7c0a356..c8a954024daca 100644 --- a/library/compiler-builtins/ci/azure-steps.yml +++ b/library/compiler-builtins/ci/azure-steps.yml @@ -4,13 +4,23 @@ steps: - template: azure-install-rust.yml + - script: rustup component add rust-src + displayName: Install Rust sources + condition: eq( variables['XARGO'], '1' ) + - bash: rustup target add $TARGET - displayName: Install compilation target + displayName: Install Rust target + condition: ne( variables['XARGO'], '1' ) - bash: ./ci/run.sh $TARGET condition: ne( variables['Agent.OS'], 'Linux' ) displayName: Run test script - - bash: cargo generate-lockfile && ./ci/run-docker.sh $TARGET + - bash: | + if [ "$ONLY_BUILD" = "1" ]; then + cargo build --target $TARGET + else + cargo generate-lockfile && ./ci/run-docker.sh $TARGET + fi condition: eq( variables['Agent.OS'], 'Linux' ) displayName: Run docker test script diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 6b3066e53e66c..5c2e065ccef97 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -18,6 +18,7 @@ run() { --user $(id -u):$(id -g) \ -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ + -e XARGO \ -v $HOME/.cargo:/cargo \ -v `pwd`/target:/target \ -v `pwd`:/checkout:ro \ diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index b77752288d9c6..589553adbf227 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -3,14 +3,10 @@ set -ex # FIXME(japarix/xargo#186) this shouldn't be necessary export RUST_TARGET_PATH=`pwd` -case $1 in - thumb*) - cargo=xargo - ;; - *) - cargo=cargo - ;; -esac +cargo=cargo +if [ "$XARGO" = "1" ]; then + cargo=xargo +fi INTRINSICS_FEATURES="c" @@ -22,34 +18,31 @@ if [ -z "$INTRINSICS_FAILS_WITH_MEM_FEATURE" ]; then fi # Test our implementation -case $1 in - thumb*) - run="xargo test --manifest-path testcrate/Cargo.toml --target $1" - for t in $(ls testcrate/tests); do - t=${t%.rs} - - RUSTFLAGS="-C debug-assertions=no -C lto" \ - CARGO_INCREMENTAL=0 \ - $run --test $t --no-default-features --features 'mem c' --no-run - qemu-arm-static target/${1}/debug/$t-* - done - - for t in $(ls testcrate/tests); do - t=${t%.rs} - RUSTFLAGS="-C lto" \ - CARGO_INCREMENTAL=0 \ - $run --test $t --no-default-features --features 'mem c' --no-run --release - qemu-arm-static target/${1}/release/$t-* - done - ;; - *) - run="cargo test --manifest-path testcrate/Cargo.toml --target $1" - $run - $run --release - $run --features c - $run --features c --release - ;; -esac +if [ "$XARGO" = "1" ]; then + run="xargo test --manifest-path testcrate/Cargo.toml --target $1" + for t in $(ls testcrate/tests); do + t=${t%.rs} + + RUSTFLAGS="-C debug-assertions=no -C lto" \ + CARGO_INCREMENTAL=0 \ + $run --test $t --no-default-features --features 'mem c' --no-run + qemu-arm-static target/${1}/debug/$t-* + done + + for t in $(ls testcrate/tests); do + t=${t%.rs} + RUSTFLAGS="-C lto" \ + CARGO_INCREMENTAL=0 \ + $run --test $t --no-default-features --features 'mem c' --no-run --release + qemu-arm-static target/${1}/release/$t-* + done +else + run="cargo test --manifest-path testcrate/Cargo.toml --target $1" + $run + $run --release + $run --features c + $run --features c --release +fi PREFIX=$(echo $1 | sed -e 's/unknown-//')- case $1 in From b73fa4b764991ea7f87827cdd5e8a850bacab269 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 12:12:19 -0700 Subject: [PATCH 0671/4206] Try to fix Windows --- library/compiler-builtins/azure-pipelines.yml | 130 +++++++++--------- .../ci/azure-install-rust.yml | 2 +- 2 files changed, 66 insertions(+), 66 deletions(-) diff --git a/library/compiler-builtins/azure-pipelines.yml b/library/compiler-builtins/azure-pipelines.yml index ca02a515399e2..36732f1320d3a 100644 --- a/library/compiler-builtins/azure-pipelines.yml +++ b/library/compiler-builtins/azure-pipelines.yml @@ -2,67 +2,67 @@ trigger: - master jobs: - - job: Linux - pool: - vmImage: ubuntu-16.04 - steps: - - template: ci/azure-steps.yml - strategy: - matrix: - aarch64: - TARGET: aarch64-unknown-linux-gnu - # arm: - # TARGET: arm-unknown-linux-gnueabi - # armhf: - # TARGET: arm-unknown-linux-gnueabihf - # i586: - # TARGET: i586-unknown-linux-gnu - # i686: - # TARGET: i686-unknown-linux-gnu - # mips: - # TARGET: mips-unknown-linux-gnu - # mips64: - # TARGET: mips64-unknown-linux-gnuabi64 - # mips64el: - # TARGET: mips64el-unknown-linux-gnuabi64 - # mipsel: - # TARGET: mipsel-unknown-linux-gnu - # powerpc: - # TARGET: powerpc-unknown-linux-gnu - # powerpc64: - # TARGET: powerpc64-unknown-linux-gnu - # powerpc64le: - # TARGET: powerpc64le-unknown-linux-gnu - thumbv6m: - TARGET: thumbv6m-linux-eabi - XARGO: 1 - thumbv7em: - TARGET: thumbv7em-linux-eabi - XARGO: 1 - thumbv7emhf: - TARGET: thumbv7em-linux-eabihf - XARGO: 1 - thumbv7m: - TARGET: thumbv7m-linux-eabi - XARGO: 1 - wasm32: - TARGET: wasm32-unknown-unknown - ONLY_BUILD: 1 - x86_64: - TARGET: x86_64-unknown-linux-gnu - - - job: macOS - pool: - vmImage: macos-10.13 - steps: - - template: ci/azure-steps.yml - strategy: - matrix: - x86_64: - TARGET: x86_64-apple-darwin - # i686: - # TARGET: i686-apple-darwin - + # - job: Linux + # pool: + # vmImage: ubuntu-16.04 + # steps: + # - template: ci/azure-steps.yml + # strategy: + # matrix: + # aarch64: + # TARGET: aarch64-unknown-linux-gnu + # arm: + # TARGET: arm-unknown-linux-gnueabi + # armhf: + # TARGET: arm-unknown-linux-gnueabihf + # i586: + # TARGET: i586-unknown-linux-gnu + # i686: + # TARGET: i686-unknown-linux-gnu + # mips: + # TARGET: mips-unknown-linux-gnu + # mips64: + # TARGET: mips64-unknown-linux-gnuabi64 + # mips64el: + # TARGET: mips64el-unknown-linux-gnuabi64 + # mipsel: + # TARGET: mipsel-unknown-linux-gnu + # powerpc: + # TARGET: powerpc-unknown-linux-gnu + # powerpc64: + # TARGET: powerpc64-unknown-linux-gnu + # powerpc64le: + # TARGET: powerpc64le-unknown-linux-gnu + # thumbv6m: + # TARGET: thumbv6m-linux-eabi + # XARGO: 1 + # thumbv7em: + # TARGET: thumbv7em-linux-eabi + # XARGO: 1 + # thumbv7emhf: + # TARGET: thumbv7em-linux-eabihf + # XARGO: 1 + # thumbv7m: + # TARGET: thumbv7m-linux-eabi + # XARGO: 1 + # wasm32: + # TARGET: wasm32-unknown-unknown + # ONLY_BUILD: 1 + # x86_64: + # TARGET: x86_64-unknown-linux-gnu + # + # - job: macOS + # pool: + # vmImage: macos-10.13 + # steps: + # - template: ci/azure-steps.yml + # strategy: + # matrix: + # x86_64: + # TARGET: x86_64-apple-darwin + # i686: + # TARGET: i686-apple-darwin + # - job: Windows pool: vmImage: 'vs2017-win2016' @@ -72,9 +72,9 @@ jobs: matrix: i686-msvc: TARGET: i686-pc-windows-msvc - # x86_64-msvc: - # TARGET: x86_64-pc-windows-msvc - # i686-gnu: - # TARGET: i686-pc-windows-gnu + x86_64-msvc: + TARGET: x86_64-pc-windows-msvc + i686-gnu: + TARGET: i686-pc-windows-gnu x86_64-gnu: TARGET: x86_64-pc-windows-gnu diff --git a/library/compiler-builtins/ci/azure-install-rust.yml b/library/compiler-builtins/ci/azure-install-rust.yml index d74946e3dfd9c..f44f8c59dc6f4 100644 --- a/library/compiler-builtins/ci/azure-install-rust.yml +++ b/library/compiler-builtins/ci/azure-install-rust.yml @@ -13,7 +13,7 @@ steps: - script: | curl -sSf -o rustup-init.exe https://win.rustup.rs - rustup-init.exe -y --default-toolchain %TOOLCHAIN% + rustup-init.exe -y --default-toolchain %TOOLCHAIN%-%TARGET% echo ##vso[task.prependpath]%USERPROFILE%\.cargo\bin displayName: Install rust condition: eq( variables['Agent.OS'], 'Windows_NT' ) From 9772acb3cd954061c01e5bc6f5a5b7f9ba0bc8ff Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 12:16:59 -0700 Subject: [PATCH 0672/4206] Re-enable all targets --- library/compiler-builtins/azure-pipelines.yml | 122 +++++++++--------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/library/compiler-builtins/azure-pipelines.yml b/library/compiler-builtins/azure-pipelines.yml index 36732f1320d3a..8df6e64c5e206 100644 --- a/library/compiler-builtins/azure-pipelines.yml +++ b/library/compiler-builtins/azure-pipelines.yml @@ -2,67 +2,67 @@ trigger: - master jobs: - # - job: Linux - # pool: - # vmImage: ubuntu-16.04 - # steps: - # - template: ci/azure-steps.yml - # strategy: - # matrix: - # aarch64: - # TARGET: aarch64-unknown-linux-gnu - # arm: - # TARGET: arm-unknown-linux-gnueabi - # armhf: - # TARGET: arm-unknown-linux-gnueabihf - # i586: - # TARGET: i586-unknown-linux-gnu - # i686: - # TARGET: i686-unknown-linux-gnu - # mips: - # TARGET: mips-unknown-linux-gnu - # mips64: - # TARGET: mips64-unknown-linux-gnuabi64 - # mips64el: - # TARGET: mips64el-unknown-linux-gnuabi64 - # mipsel: - # TARGET: mipsel-unknown-linux-gnu - # powerpc: - # TARGET: powerpc-unknown-linux-gnu - # powerpc64: - # TARGET: powerpc64-unknown-linux-gnu - # powerpc64le: - # TARGET: powerpc64le-unknown-linux-gnu - # thumbv6m: - # TARGET: thumbv6m-linux-eabi - # XARGO: 1 - # thumbv7em: - # TARGET: thumbv7em-linux-eabi - # XARGO: 1 - # thumbv7emhf: - # TARGET: thumbv7em-linux-eabihf - # XARGO: 1 - # thumbv7m: - # TARGET: thumbv7m-linux-eabi - # XARGO: 1 - # wasm32: - # TARGET: wasm32-unknown-unknown - # ONLY_BUILD: 1 - # x86_64: - # TARGET: x86_64-unknown-linux-gnu - # - # - job: macOS - # pool: - # vmImage: macos-10.13 - # steps: - # - template: ci/azure-steps.yml - # strategy: - # matrix: - # x86_64: - # TARGET: x86_64-apple-darwin - # i686: - # TARGET: i686-apple-darwin - # + - job: Linux + pool: + vmImage: ubuntu-16.04 + steps: + - template: ci/azure-steps.yml + strategy: + matrix: + aarch64: + TARGET: aarch64-unknown-linux-gnu + arm: + TARGET: arm-unknown-linux-gnueabi + armhf: + TARGET: arm-unknown-linux-gnueabihf + i586: + TARGET: i586-unknown-linux-gnu + i686: + TARGET: i686-unknown-linux-gnu + mips: + TARGET: mips-unknown-linux-gnu + mips64: + TARGET: mips64-unknown-linux-gnuabi64 + mips64el: + TARGET: mips64el-unknown-linux-gnuabi64 + mipsel: + TARGET: mipsel-unknown-linux-gnu + powerpc: + TARGET: powerpc-unknown-linux-gnu + powerpc64: + TARGET: powerpc64-unknown-linux-gnu + powerpc64le: + TARGET: powerpc64le-unknown-linux-gnu + # thumbv6m: + # TARGET: thumbv6m-linux-eabi + # XARGO: 1 + # thumbv7em: + # TARGET: thumbv7em-linux-eabi + # XARGO: 1 + # thumbv7emhf: + # TARGET: thumbv7em-linux-eabihf + # XARGO: 1 + # thumbv7m: + # TARGET: thumbv7m-linux-eabi + # XARGO: 1 + wasm32: + TARGET: wasm32-unknown-unknown + ONLY_BUILD: 1 + x86_64: + TARGET: x86_64-unknown-linux-gnu + + - job: macOS + pool: + vmImage: macos-10.13 + steps: + - template: ci/azure-steps.yml + strategy: + matrix: + x86_64: + TARGET: x86_64-apple-darwin + i686: + TARGET: i686-apple-darwin + - job: Windows pool: vmImage: 'vs2017-win2016' From 44181b42f4dba4062bb6d974f62d3223d84a4d23 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 12:51:36 -0700 Subject: [PATCH 0673/4206] Attempt to fix MinGW targets --- library/compiler-builtins/azure-pipelines.yml | 4 ++++ library/compiler-builtins/examples/intrinsics.rs | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/library/compiler-builtins/azure-pipelines.yml b/library/compiler-builtins/azure-pipelines.yml index 8df6e64c5e206..da3a1bb1d39f9 100644 --- a/library/compiler-builtins/azure-pipelines.yml +++ b/library/compiler-builtins/azure-pipelines.yml @@ -76,5 +76,9 @@ jobs: TARGET: x86_64-pc-windows-msvc i686-gnu: TARGET: i686-pc-windows-gnu + INTRINSICS_FAILS_WITH_MEM_FEATURE: 1 + DEBUG_LTO_BUILD_DOESNT_WORK: 1 x86_64-gnu: TARGET: x86_64-pc-windows-gnu + INTRINSICS_FAILS_WITH_MEM_FEATURE: 1 + DEBUG_LTO_BUILD_DOESNT_WORK: 1 diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 89c2c23dbfc71..7766687c8b5e2 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -383,3 +383,11 @@ pub fn _Unwind_Resume() {} #[lang = "eh_personality"] #[no_mangle] pub extern "C" fn eh_personality() {} + +#[cfg(all(windows, target_env = "gnu"))] +mod mingw_unwidning { + #[no_mangle] + pub fn rust_eh_personality() {} + #[no_mangle] + pub fn rust_eh_unwind_resume() {} +} From a6034d0b7be09158e287df7e49460cf7dc845296 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 13:02:22 -0700 Subject: [PATCH 0674/4206] More fixes for i686-mingw --- library/compiler-builtins/examples/intrinsics.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 7766687c8b5e2..ccd701569d902 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -390,4 +390,8 @@ mod mingw_unwidning { pub fn rust_eh_personality() {} #[no_mangle] pub fn rust_eh_unwind_resume() {} + #[no_mangle] + pub fn rust_eh_register_frames() {} + #[no_mangle] + pub fn rust_eh_unregister_frames() {} } From 26a01f97a8bbe482599e98d3aa852c7513ff8b60 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 13:05:56 -0700 Subject: [PATCH 0675/4206] Bump to 0.1.9 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index d30af40511da3..7c0cf0d74bcee 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.8" +version = "0.1.9" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" From 78d40ed30c560a2deda73c34637a09f3ee285c9f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 15:41:20 -0500 Subject: [PATCH 0676/4206] Update azure pipelines badge --- library/compiler-builtins/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index b290cbff88964..f0724bffe1d0a 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -1,6 +1,6 @@ # `compiler-builtins` -[![Build Status](https://dev.azure.com/rust-lang/compiler-builtins/_apis/build/status/compiler-builtins-CI?branchName=master)](https://dev.azure.com/rust-lang/compiler-builtins/_build/latest?definitionId=2&branchName=master) +[![Build Status](https://dev.azure.com/rust-lang/compiler-builtins/_apis/build/status/rust-lang-nursery.compiler-builtins?branchName=master)](https://dev.azure.com/rust-lang/compiler-builtins/_build/latest?definitionId=6&branchName=master) > Porting `compiler-rt` intrinsics to Rust From 36e4db03641d734815d799731c8016a0f7f68749 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 8 Apr 2019 16:30:33 +0200 Subject: [PATCH 0677/4206] Update submodule for VS 2019 support --- library/compiler-builtins/compiler-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-rt b/library/compiler-builtins/compiler-rt index 84c0bd0158c3f..03fc28f9273ee 160000 --- a/library/compiler-builtins/compiler-rt +++ b/library/compiler-builtins/compiler-rt @@ -1 +1 @@ -Subproject commit 84c0bd0158c3ff86052be1b07a3ddc3c4f5ba52a +Subproject commit 03fc28f9273eeab16f1005f982dfde5900bddb29 From c2e263422329e2daeb81d82f3a3bd98e66be844c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 8 Apr 2019 07:52:05 -0700 Subject: [PATCH 0678/4206] Bump to 0.1.10 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 7c0cf0d74bcee..1dfe6c73f162a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.9" +version = "0.1.10" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" From 76184c21e0791c99855ac30ea0e1d5f15766a796 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 8 Apr 2019 07:55:09 -0700 Subject: [PATCH 0679/4206] Add instructions for publishing --- library/compiler-builtins/PUBLISHING.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 library/compiler-builtins/PUBLISHING.md diff --git a/library/compiler-builtins/PUBLISHING.md b/library/compiler-builtins/PUBLISHING.md new file mode 100644 index 0000000000000..ad100dee08fbe --- /dev/null +++ b/library/compiler-builtins/PUBLISHING.md @@ -0,0 +1,17 @@ +# Publishing to crates.io + +Publishing `compiler-builtins` to crates.io takes a few steps unfortunately. +It's not great, but it works for now. PRs to improve this process would be +greatly appreciated! + +1. Make sure you've got a clean working tree and it's updated with the latest + changes on `master` +2. Edit `Cargo.toml` to bump the version number +3. Commit this change +4. Run `git tag` to create a tag for this version +5. Delete the `libm/Cargo.toml` file +6. Comment out the `[dev-dependencies]` section of `Cargo.toml` +7. Run `cargo +nightly publish --allow-dirty` +8. Push the tag +9. Push the commit +10. Undo changes to `Cargo.toml` and the `libm` submodule From 63c0bd2522d7f1cc897c3467346f713eaad7fda5 Mon Sep 17 00:00:00 2001 From: Goirad Date: Mon, 29 Apr 2019 14:42:14 -0700 Subject: [PATCH 0680/4206] Added missing fdim signature --- library/compiler-builtins/src/math.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index dfdd99cdf9311..b6195553916db 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -64,6 +64,7 @@ no_mangle! { fn cbrtf(n: f32) -> f32; fn coshf(n: f32) -> f32; fn expm1f(n: f32) -> f32; + fn fdim(a: f64, b: f64) -> f64; fn fdimf(a: f32, b: f32) -> f32; fn hypotf(x: f32, y: f32) -> f32; fn log1pf(n: f32) -> f32; From 3789bb1a981a7f2dc8e9374d87961633078f59a8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 30 Apr 2019 10:08:23 -0700 Subject: [PATCH 0681/4206] Bump to 0.1.11 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 1dfe6c73f162a..fdca20143b91f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.10" +version = "0.1.11" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" From fa6d92bb415938c532e60dc3536e27b4b7146c24 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 09:15:01 -0500 Subject: [PATCH 0682/4206] Set up CI with Azure Pipelines [skip ci] --- .../libm/azure-pipelines.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 library/compiler-builtins/libm/azure-pipelines.yml diff --git a/library/compiler-builtins/libm/azure-pipelines.yml b/library/compiler-builtins/libm/azure-pipelines.yml new file mode 100644 index 0000000000000..c23ced43ca07e --- /dev/null +++ b/library/compiler-builtins/libm/azure-pipelines.yml @@ -0,0 +1,19 @@ +# Starter pipeline +# Start with a minimal pipeline that you can customize to build and deploy your code. +# Add steps that build, run tests, deploy, and more: +# https://aka.ms/yaml + +trigger: +- master + +pool: + vmImage: 'Ubuntu-16.04' + +steps: +- script: echo Hello, world! + displayName: 'Run a one-line script' + +- script: | + echo Add other tasks to build, test, and deploy your project. + echo See https://aka.ms/yaml + displayName: 'Run a multi-line script' From ae69253dc7b6f33de149fa5b09679bc2c603a702 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 08:12:00 -0700 Subject: [PATCH 0683/4206] Move crates to `crates` folder --- library/compiler-builtins/libm/Cargo.toml | 10 +- .../libm/azure-pipelines.yml | 156 ++++++++++++++++-- .../libm/ci/azure-install-rust.yml | 23 +++ .../libm/ci/azure-test-all.yml | 41 +++++ .../compiler-builtins-smoke-test}/Cargo.toml | 0 .../compiler-builtins-smoke-test}/src/lib.rs | 2 +- .../{ => crates}/input-generator/Cargo.toml | 0 .../{ => crates}/input-generator/src/main.rs | 32 ++-- .../{ => crates}/musl-generator/Cargo.toml | 0 .../{ => crates}/musl-generator/src/macros.rs | 16 +- .../{ => crates}/musl-generator/src/main.rs | 0 .../{ => crates}/newlib-generator/Cargo.toml | 0 .../newlib-generator/src/macros.rs | 0 .../{ => crates}/newlib-generator/src/main.rs | 0 .../libm/{ => crates}/shared/Cargo.toml | 0 .../libm/{ => crates}/shared/src/lib.rs | 82 +++++---- .../compiler-builtins/libm/math/.cargo/config | 11 -- .../compiler-builtins/libm/math/Cargo.toml | 8 - .../compiler-builtins/libm/math/Cross.toml | 2 - .../compiler-builtins/libm/src/math/acosf.rs | 14 ++ 20 files changed, 288 insertions(+), 109 deletions(-) create mode 100644 library/compiler-builtins/libm/ci/azure-install-rust.yml create mode 100644 library/compiler-builtins/libm/ci/azure-test-all.yml rename library/compiler-builtins/libm/{cb => crates/compiler-builtins-smoke-test}/Cargo.toml (100%) rename library/compiler-builtins/libm/{cb => crates/compiler-builtins-smoke-test}/src/lib.rs (82%) rename library/compiler-builtins/libm/{ => crates}/input-generator/Cargo.toml (100%) rename library/compiler-builtins/libm/{ => crates}/input-generator/src/main.rs (82%) rename library/compiler-builtins/libm/{ => crates}/musl-generator/Cargo.toml (100%) rename library/compiler-builtins/libm/{ => crates}/musl-generator/src/macros.rs (90%) rename library/compiler-builtins/libm/{ => crates}/musl-generator/src/main.rs (100%) rename library/compiler-builtins/libm/{ => crates}/newlib-generator/Cargo.toml (100%) rename library/compiler-builtins/libm/{ => crates}/newlib-generator/src/macros.rs (100%) rename library/compiler-builtins/libm/{ => crates}/newlib-generator/src/main.rs (100%) rename library/compiler-builtins/libm/{ => crates}/shared/Cargo.toml (100%) rename library/compiler-builtins/libm/{ => crates}/shared/src/lib.rs (86%) delete mode 100644 library/compiler-builtins/libm/math/.cargo/config delete mode 100644 library/compiler-builtins/libm/math/Cargo.toml delete mode 100644 library/compiler-builtins/libm/math/Cross.toml diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index f28024d041c53..b4f07eeeed236 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -17,11 +17,11 @@ stable = [] [workspace] members = [ - "cb", - "input-generator", - "musl-generator", - "newlib-generator", - "shared", + "crates/compiler-builtins-smoke-test", + "crates/input-generator", + "crates/musl-generator", + "crates/newlib-generator", + "crates/shared", ] [dev-dependencies] diff --git a/library/compiler-builtins/libm/azure-pipelines.yml b/library/compiler-builtins/libm/azure-pipelines.yml index c23ced43ca07e..36271ec1bea3e 100644 --- a/library/compiler-builtins/libm/azure-pipelines.yml +++ b/library/compiler-builtins/libm/azure-pipelines.yml @@ -1,19 +1,143 @@ -# Starter pipeline -# Start with a minimal pipeline that you can customize to build and deploy your code. -# Add steps that build, run tests, deploy, and more: -# https://aka.ms/yaml - trigger: -- master - -pool: - vmImage: 'Ubuntu-16.04' + - master -steps: -- script: echo Hello, world! - displayName: 'Run a one-line script' +jobs: + - job: Docker + pool: + vmImage: ubuntu-16.04 + steps: + - template: ci/azure-install-rust.yml + env: + TOOLCHAIN: nightly + - bash: rustup target add $TARGET + displayName: "Install rust cross target" + - bash: | + set -e + mkdir cross + curl -L https://github.com/rust-embedded/cross/releases/download/v0.1.14/cross-v0.1.14-x86_64-unknown-linux-musl.tar.gz | tar xzf - -C $HOME/.cargo/bin + displayName: "Install cross" + - bash: cross test --lib --features checked --target $TARGET --release + displayName: "Run lib tests" + - bash: cross test --tests --features checked --target $TARGET --release + displayName: "Run integration tests" + strategy: + matrix: + aarch64: + TARGET: aarch64-unknown-linux-gnu + armhv: + TARGET: arm-unknown-linux-gnueabihf + armv7: + TARGET: armv7-unknown-linux-gnueabihf + i586: + TARGET: i586-unknown-linux-gnu + i686: + TARGET: i686-unknown-linux-gnu + mips: + TARGET: mips-unknown-linux-gnu + mips64: + TARGET: mips64-unknown-linux-gnuabi64 + mips64el: + TARGET: mips64el-unknown-linux-gnuabi64 + powerpc: + TARGET: powerpc-unknown-linux-gnu + powerpc64: + TARGET: powerpc64-unknown-linux-gnu + powerpc64le: + TARGET: powerpc64le-unknown-linux-gnu + x86_64: + TARGET: x86_64-unknown-linux-gnu -- script: | - echo Add other tasks to build, test, and deploy your project. - echo See https://aka.ms/yaml - displayName: 'Run a multi-line script' + # - job: Linux + # pool: + # vmImage: ubuntu-16.04 + # steps: + # - template: ci/azure-test-all.yml + # strategy: + # matrix: + # stable: + # TOOLCHAIN: stable + # beta: + # TOOLCHAIN: beta + # nightly: + # TOOLCHAIN: nightly + # + # - job: macOS + # pool: + # vmImage: macos-10.13 + # steps: + # - template: ci/azure-test-all.yml + # strategy: + # matrix: + # x86_64: + # TARGET: x86_64-apple-darwin + # + # - job: iOS + # pool: + # vmImage: macos-10.13 + # steps: + # - checkout: self + # submodules: true + # - template: ci/azure-install-rust.yml + # - script: rustup target add $TARGET + # displayName: "Install rust cross target" + # - bash: | + # set -e + # export SDK_PATH=`xcrun --show-sdk-path --sdk $SDK` + # export RUSTFLAGS="-C link-arg=-isysroot -C link-arg=$SDK_PATH" + # cargo test --no-run --target $TARGET + # displayName: "Build for iOS" + # strategy: + # matrix: + # aarch64: + # TARGET: aarch64-apple-ios + # SDK: iphoneos + # armv7: + # TARGET: armv7-apple-ios + # SDK: iphoneos + # armv7s: + # TARGET: armv7s-apple-ios + # SDK: iphoneos + # i386: + # TARGET: i386-apple-ios + # SDK: iphonesimulator + # x86_64: + # TARGET: x86_64-apple-ios + # SDK: iphonesimulator + # + # - job: wasm + # pool: + # vmImage: ubuntu-16.04 + # steps: + # - checkout: self + # submodules: true + # - template: ci/azure-install-rust.yml + # - script: rustup target add wasm32-unknown-unknown + # displayName: "Install rust cross target" + # - script: cargo build --target wasm32-unknown-unknown + # displayName: "Build for wasm" + # + # - job: Windows + # pool: + # vmImage: vs2017-win2016 + # steps: + # - template: ci/azure-test-all.yml + # strategy: + # matrix: + # x86_64-msvc: + # TARGET: x86_64-pc-windows-msvc + # i686-msvc: + # TARGET: i686-pc-windows-msvc + # x86_64-gnu: + # TARGET: x86_64-pc-windows-gnu + # i686-gnu: + # TARGET: i686-pc-windows-gnu + # + # - job: Windows_arm64 + # pool: + # vmImage: windows-2019 + # steps: + # - template: ci/azure-install-rust.yml + # - script: rustup target add aarch64-pc-windows-msvc + # displayName: "Install rust cross target" + # - script: cargo test --no-run --target aarch64-pc-windows-msvc + # displayName: "Build for arm64" diff --git a/library/compiler-builtins/libm/ci/azure-install-rust.yml b/library/compiler-builtins/libm/ci/azure-install-rust.yml new file mode 100644 index 0000000000000..fa7eae459b796 --- /dev/null +++ b/library/compiler-builtins/libm/ci/azure-install-rust.yml @@ -0,0 +1,23 @@ +steps: + - bash: | + set -e + toolchain=$TOOLCHAIN + if [ "$toolchain" = "" ]; then + toolchain=stable + fi + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $toolchain + echo "##vso[task.prependpath]$HOME/.cargo/bin" + displayName: Install rust (unix) + condition: ne( variables['Agent.OS'], 'Windows_NT' ) + + - script: | + curl -sSf -o rustup-init.exe https://win.rustup.rs + rustup-init.exe -y --default-toolchain stable-%TARGET% + echo ##vso[task.prependpath]%USERPROFILE%\.cargo\bin + displayName: Install rust (windows) + condition: eq( variables['Agent.OS'], 'Windows_NT' ) + + - script: | + rustc -Vv + cargo -V + displayName: Query rust and cargo versions diff --git a/library/compiler-builtins/libm/ci/azure-test-all.yml b/library/compiler-builtins/libm/ci/azure-test-all.yml new file mode 100644 index 0000000000000..b2b7124d3ff3e --- /dev/null +++ b/library/compiler-builtins/libm/ci/azure-test-all.yml @@ -0,0 +1,41 @@ +steps: + - checkout: self + submodules: true + - template: azure-install-rust.yml + + - bash: cargo build --manifest-path backtrace-sys/Cargo.toml + displayName: "Build backtrace-sys" + - bash: cargo build + displayName: "Build backtrace" + - bash: cargo test + displayName: "Test backtrace" + - bash: cargo test --no-default-features + displayName: "Test backtrace (-default)" + - bash: cargo test --no-default-features --features 'std' + displayName: "Test backtrace (-default + std)" + - bash: cargo test --no-default-features --features 'libunwind std' + displayName: "Test backtrace (-default + libunwind)" + - bash: cargo test --no-default-features --features 'libunwind dladdr std' + displayName: "Test backtrace (-default + libunwind + dladdr)" + - bash: cargo test --no-default-features --features 'libunwind libbacktrace std' + displayName: "Test backtrace (-default + libunwind + libbacktrace)" + - bash: cargo test --no-default-features --features 'unix-backtrace std' + displayName: "Test backtrace (-default + unix-backtrace)" + - bash: cargo test --no-default-features --features 'unix-backtrace dladdr std' + displayName: "Test backtrace (-default + unix-backtrace + dladdr)" + - bash: cargo test --no-default-features --features 'unix-backtrace libbacktrace std' + displayName: "Test backtrace (-default + unix-backtrace + libbacktrace)" + - bash: cargo test --no-default-features --features 'serialize-serde std' + displayName: "Test backtrace (-default + serialize-serde + std)" + - bash: cargo test --no-default-features --features 'serialize-rustc std' + displayName: "Test backtrace (-default + serialize-rustc + std)" + - bash: cargo test --no-default-features --features 'serialize-rustc serialize-serde std' + displayName: "Test backtrace (-default + serialize-rustc + serialize-serde + std)" + - bash: cargo test --no-default-features --features 'cpp_demangle std' + displayName: "Test backtrace (-default + cpp_demangle + std)" + - bash: cargo test --no-default-features --features 'gimli-symbolize std' + displayName: "Test backtrace (-default + gimli-symbolize + std)" + - bash: cargo test --no-default-features --features 'dbghelp std' + displayName: "Test backtrace (-default + dbghelp + std)" + - bash: cd ./cpp_smoke_test && cargo test + displayName: "Test cpp_smoke_test" diff --git a/library/compiler-builtins/libm/cb/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml similarity index 100% rename from library/compiler-builtins/libm/cb/Cargo.toml rename to library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml diff --git a/library/compiler-builtins/libm/cb/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs similarity index 82% rename from library/compiler-builtins/libm/cb/src/lib.rs rename to library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index 439ba7dc4e63f..7fad301b98349 100644 --- a/library/compiler-builtins/libm/cb/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -5,5 +5,5 @@ #![allow(dead_code)] #![no_std] -#[path = "../../src/math/mod.rs"] +#[path = "../../../src/math/mod.rs"] mod libm; diff --git a/library/compiler-builtins/libm/input-generator/Cargo.toml b/library/compiler-builtins/libm/crates/input-generator/Cargo.toml similarity index 100% rename from library/compiler-builtins/libm/input-generator/Cargo.toml rename to library/compiler-builtins/libm/crates/input-generator/Cargo.toml diff --git a/library/compiler-builtins/libm/input-generator/src/main.rs b/library/compiler-builtins/libm/crates/input-generator/src/main.rs similarity index 82% rename from library/compiler-builtins/libm/input-generator/src/main.rs rename to library/compiler-builtins/libm/crates/input-generator/src/main.rs index b4a6ad142258c..0746ea477e838 100644 --- a/library/compiler-builtins/libm/input-generator/src/main.rs +++ b/library/compiler-builtins/libm/crates/input-generator/src/main.rs @@ -43,7 +43,7 @@ fn f32(rng: &mut XorShiftRng) -> Result<(), Box> { let mut f = File::create("bin/input/f32")?; for i in set { - f.write_all(&i.to_bytes())?; + f.write_all(&i.to_le_bytes())?; } Ok(()) @@ -61,8 +61,8 @@ fn f32f32(rng: &mut XorShiftRng) -> Result<(), Box> { } i += 1; - f.write_all(&x0.to_bits().to_bytes())?; - f.write_all(&x1.to_bits().to_bytes())?; + f.write_all(&x0.to_bits().to_le_bytes())?; + f.write_all(&x1.to_bits().to_le_bytes())?; } Ok(()) @@ -80,8 +80,8 @@ fn f32i16(rng: &mut XorShiftRng) -> Result<(), Box> { } i += 1; - f.write_all(&x0.to_bits().to_bytes())?; - f.write_all(&x1.to_bytes())?; + f.write_all(&x0.to_bits().to_le_bytes())?; + f.write_all(&x1.to_le_bytes())?; } Ok(()) @@ -100,9 +100,9 @@ fn f32f32f32(rng: &mut XorShiftRng) -> Result<(), Box> { } i += 1; - f.write_all(&x0.to_bits().to_bytes())?; - f.write_all(&x1.to_bits().to_bytes())?; - f.write_all(&x2.to_bits().to_bytes())?; + f.write_all(&x0.to_bits().to_le_bytes())?; + f.write_all(&x1.to_bits().to_le_bytes())?; + f.write_all(&x2.to_bits().to_le_bytes())?; } Ok(()) @@ -123,7 +123,7 @@ fn f64(rng: &mut XorShiftRng) -> Result<(), Box> { let mut f = File::create("bin/input/f64")?; for i in set { - f.write_all(&i.to_bytes())?; + f.write_all(&i.to_le_bytes())?; } Ok(()) @@ -141,8 +141,8 @@ fn f64f64(rng: &mut XorShiftRng) -> Result<(), Box> { } i += 1; - f.write_all(&x0.to_bits().to_bytes())?; - f.write_all(&x1.to_bits().to_bytes())?; + f.write_all(&x0.to_bits().to_le_bytes())?; + f.write_all(&x1.to_bits().to_le_bytes())?; } Ok(()) @@ -161,9 +161,9 @@ fn f64f64f64(rng: &mut XorShiftRng) -> Result<(), Box> { } i += 1; - f.write_all(&x0.to_bits().to_bytes())?; - f.write_all(&x1.to_bits().to_bytes())?; - f.write_all(&x2.to_bits().to_bytes())?; + f.write_all(&x0.to_bits().to_le_bytes())?; + f.write_all(&x1.to_bits().to_le_bytes())?; + f.write_all(&x2.to_bits().to_le_bytes())?; } Ok(()) @@ -181,8 +181,8 @@ fn f64i16(rng: &mut XorShiftRng) -> Result<(), Box> { } i += 1; - f.write_all(&x0.to_bits().to_bytes())?; - f.write_all(&x1.to_bytes())?; + f.write_all(&x0.to_bits().to_le_bytes())?; + f.write_all(&x1.to_le_bytes())?; } Ok(()) diff --git a/library/compiler-builtins/libm/musl-generator/Cargo.toml b/library/compiler-builtins/libm/crates/musl-generator/Cargo.toml similarity index 100% rename from library/compiler-builtins/libm/musl-generator/Cargo.toml rename to library/compiler-builtins/libm/crates/musl-generator/Cargo.toml diff --git a/library/compiler-builtins/libm/musl-generator/src/macros.rs b/library/compiler-builtins/libm/crates/musl-generator/src/macros.rs similarity index 90% rename from library/compiler-builtins/libm/musl-generator/src/macros.rs rename to library/compiler-builtins/libm/crates/musl-generator/src/macros.rs index 16ba99d640c65..e47c0ab6f96d1 100644 --- a/library/compiler-builtins/libm/musl-generator/src/macros.rs +++ b/library/compiler-builtins/libm/crates/musl-generator/src/macros.rs @@ -16,7 +16,7 @@ macro_rules! f32 { $fun(*x) }; - $fun.write_all(&y.to_bits().to_bytes())?; + $fun.write_all(&y.to_bits().to_le_bytes())?; )+ } }}; @@ -40,7 +40,7 @@ macro_rules! f32f32 { $fun(*x0, *x1) }; - $fun.write_all(&y.to_bits().to_bytes())?; + $fun.write_all(&y.to_bits().to_le_bytes())?; )+ } }}; @@ -64,7 +64,7 @@ macro_rules! f32f32f32 { $fun(*x0, *x1, *x2) }; - $fun.write_all(&y.to_bits().to_bytes())?; + $fun.write_all(&y.to_bits().to_le_bytes())?; )+ } }}; @@ -88,7 +88,7 @@ macro_rules! f32i32 { $fun(*x0, *x1 as i32) }; - $fun.write_all(&y.to_bits().to_bytes())?; + $fun.write_all(&y.to_bits().to_le_bytes())?; )+ } }}; @@ -112,7 +112,7 @@ macro_rules! f64 { $fun(*x) }; - $fun.write_all(&y.to_bits().to_bytes())?; + $fun.write_all(&y.to_bits().to_le_bytes())?; )+ } }}; @@ -136,7 +136,7 @@ macro_rules! f64f64 { $fun(*x0, *x1) }; - $fun.write_all(&y.to_bits().to_bytes())?; + $fun.write_all(&y.to_bits().to_le_bytes())?; )+ } }}; @@ -160,7 +160,7 @@ macro_rules! f64f64f64 { $fun(*x0, *x1, *x2) }; - $fun.write_all(&y.to_bits().to_bytes())?; + $fun.write_all(&y.to_bits().to_le_bytes())?; )+ } }}; @@ -184,7 +184,7 @@ macro_rules! f64i32 { $fun(*x0, *x1 as i32) }; - $fun.write_all(&y.to_bits().to_bytes())?; + $fun.write_all(&y.to_bits().to_le_bytes())?; )+ } }}; diff --git a/library/compiler-builtins/libm/musl-generator/src/main.rs b/library/compiler-builtins/libm/crates/musl-generator/src/main.rs similarity index 100% rename from library/compiler-builtins/libm/musl-generator/src/main.rs rename to library/compiler-builtins/libm/crates/musl-generator/src/main.rs diff --git a/library/compiler-builtins/libm/newlib-generator/Cargo.toml b/library/compiler-builtins/libm/crates/newlib-generator/Cargo.toml similarity index 100% rename from library/compiler-builtins/libm/newlib-generator/Cargo.toml rename to library/compiler-builtins/libm/crates/newlib-generator/Cargo.toml diff --git a/library/compiler-builtins/libm/newlib-generator/src/macros.rs b/library/compiler-builtins/libm/crates/newlib-generator/src/macros.rs similarity index 100% rename from library/compiler-builtins/libm/newlib-generator/src/macros.rs rename to library/compiler-builtins/libm/crates/newlib-generator/src/macros.rs diff --git a/library/compiler-builtins/libm/newlib-generator/src/main.rs b/library/compiler-builtins/libm/crates/newlib-generator/src/main.rs similarity index 100% rename from library/compiler-builtins/libm/newlib-generator/src/main.rs rename to library/compiler-builtins/libm/crates/newlib-generator/src/main.rs diff --git a/library/compiler-builtins/libm/shared/Cargo.toml b/library/compiler-builtins/libm/crates/shared/Cargo.toml similarity index 100% rename from library/compiler-builtins/libm/shared/Cargo.toml rename to library/compiler-builtins/libm/crates/shared/Cargo.toml diff --git a/library/compiler-builtins/libm/shared/src/lib.rs b/library/compiler-builtins/libm/crates/shared/src/lib.rs similarity index 86% rename from library/compiler-builtins/libm/shared/src/lib.rs rename to library/compiler-builtins/libm/crates/shared/src/lib.rs index 84676f94f747d..17c20a332e5b4 100644 --- a/library/compiler-builtins/libm/shared/src/lib.rs +++ b/library/compiler-builtins/libm/crates/shared/src/lib.rs @@ -1,5 +1,3 @@ -#![feature(exact_chunks)] - #[macro_use] extern crate lazy_static; @@ -8,11 +6,11 @@ lazy_static! { let bytes = include_bytes!("../../bin/input/f32"); bytes - .exact_chunks(4) + .chunks_exact(4) .map(|chunk| { let mut buf = [0; 4]; buf.copy_from_slice(chunk); - f32::from_bits(u32::from_le(u32::from_bytes(buf))) + f32::from_bits(u32::from_le(u32::from_le_bytes(buf))) }) .collect() }; @@ -20,7 +18,7 @@ lazy_static! { let bytes = include_bytes!("../../bin/input/f32f32"); bytes - .exact_chunks(8) + .chunks_exact(8) .map(|chunk| { let mut x0 = [0; 4]; let mut x1 = [0; 4]; @@ -28,8 +26,8 @@ lazy_static! { x1.copy_from_slice(&chunk[4..]); ( - f32::from_bits(u32::from_le(u32::from_bytes(x0))), - f32::from_bits(u32::from_le(u32::from_bytes(x1))), + f32::from_bits(u32::from_le(u32::from_le_bytes(x0))), + f32::from_bits(u32::from_le(u32::from_le_bytes(x1))), ) }) .collect() @@ -38,7 +36,7 @@ lazy_static! { let bytes = include_bytes!("../../bin/input/f32f32f32"); bytes - .exact_chunks(12) + .chunks_exact(12) .map(|chunk| { let mut x0 = [0; 4]; let mut x1 = [0; 4]; @@ -48,9 +46,9 @@ lazy_static! { x2.copy_from_slice(&chunk[8..]); ( - f32::from_bits(u32::from_le(u32::from_bytes(x0))), - f32::from_bits(u32::from_le(u32::from_bytes(x1))), - f32::from_bits(u32::from_le(u32::from_bytes(x2))), + f32::from_bits(u32::from_le(u32::from_le_bytes(x0))), + f32::from_bits(u32::from_le(u32::from_le_bytes(x1))), + f32::from_bits(u32::from_le(u32::from_le_bytes(x2))), ) }) .collect() @@ -59,7 +57,7 @@ lazy_static! { let bytes = include_bytes!("../../bin/input/f32i16"); bytes - .exact_chunks(6) + .chunks_exact(6) .map(|chunk| { let mut x0 = [0; 4]; let mut x1 = [0; 2]; @@ -67,8 +65,8 @@ lazy_static! { x1.copy_from_slice(&chunk[4..]); ( - f32::from_bits(u32::from_le(u32::from_bytes(x0))), - i16::from_le(i16::from_bytes(x1)) as i32, + f32::from_bits(u32::from_le(u32::from_le_bytes(x0))), + i16::from_le(i16::from_le_bytes(x1)) as i32, ) }) .collect() @@ -77,11 +75,11 @@ lazy_static! { let bytes = include_bytes!("../../bin/input/f64"); bytes - .exact_chunks(8) + .chunks_exact(8) .map(|chunk| { let mut buf = [0; 8]; buf.copy_from_slice(chunk); - f64::from_bits(u64::from_le(u64::from_bytes(buf))) + f64::from_bits(u64::from_le(u64::from_le_bytes(buf))) }) .collect() }; @@ -89,7 +87,7 @@ lazy_static! { let bytes = include_bytes!("../../bin/input/f64f64"); bytes - .exact_chunks(16) + .chunks_exact(16) .map(|chunk| { let mut x0 = [0; 8]; let mut x1 = [0; 8]; @@ -97,8 +95,8 @@ lazy_static! { x1.copy_from_slice(&chunk[8..]); ( - f64::from_bits(u64::from_le(u64::from_bytes(x0))), - f64::from_bits(u64::from_le(u64::from_bytes(x1))), + f64::from_bits(u64::from_le(u64::from_le_bytes(x0))), + f64::from_bits(u64::from_le(u64::from_le_bytes(x1))), ) }) .collect() @@ -107,7 +105,7 @@ lazy_static! { let bytes = include_bytes!("../../bin/input/f64f64f64"); bytes - .exact_chunks(24) + .chunks_exact(24) .map(|chunk| { let mut x0 = [0; 8]; let mut x1 = [0; 8]; @@ -117,9 +115,9 @@ lazy_static! { x2.copy_from_slice(&chunk[16..]); ( - f64::from_bits(u64::from_le(u64::from_bytes(x0))), - f64::from_bits(u64::from_le(u64::from_bytes(x1))), - f64::from_bits(u64::from_le(u64::from_bytes(x2))), + f64::from_bits(u64::from_le(u64::from_le_bytes(x0))), + f64::from_bits(u64::from_le(u64::from_le_bytes(x1))), + f64::from_bits(u64::from_le(u64::from_le_bytes(x2))), ) }) .collect() @@ -128,7 +126,7 @@ lazy_static! { let bytes = include_bytes!("../../bin/input/f64i16"); bytes - .exact_chunks(10) + .chunks_exact(10) .map(|chunk| { let mut x0 = [0; 8]; let mut x1 = [0; 2]; @@ -136,8 +134,8 @@ lazy_static! { x1.copy_from_slice(&chunk[8..]); ( - f64::from_bits(u64::from_le(u64::from_bytes(x0))), - i16::from_le(i16::from_bytes(x1)) as i32, + f64::from_bits(u64::from_le(u64::from_le_bytes(x0))), + i16::from_le(i16::from_le_bytes(x1)) as i32, ) }) .collect() @@ -151,11 +149,11 @@ macro_rules! f32 { #[test] fn $fun() { let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .exact_chunks(4) + .chunks_exact(4) .map(|chunk| { let mut buf = [0; 4]; buf.copy_from_slice(chunk); - f32::from_bits(u32::from_le(u32::from_bytes(buf))) + f32::from_bits(u32::from_le(u32::from_le_bytes(buf))) }) .collect::>(); @@ -190,11 +188,11 @@ macro_rules! f32f32 { #[test] fn $fun() { let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .exact_chunks(4) + .chunks_exact(4) .map(|chunk| { let mut buf = [0; 4]; buf.copy_from_slice(chunk); - f32::from_bits(u32::from_le(u32::from_bytes(buf))) + f32::from_bits(u32::from_le(u32::from_le_bytes(buf))) }) .collect::>(); @@ -231,11 +229,11 @@ macro_rules! f32f32f32 { #[test] fn $fun() { let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .exact_chunks(4) + .chunks_exact(4) .map(|chunk| { let mut buf = [0; 4]; buf.copy_from_slice(chunk); - f32::from_bits(u32::from_le(u32::from_bytes(buf))) + f32::from_bits(u32::from_le(u32::from_le_bytes(buf))) }) .collect::>(); @@ -273,11 +271,11 @@ macro_rules! f32i32 { #[test] fn $fun() { let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .exact_chunks(4) + .chunks_exact(4) .map(|chunk| { let mut buf = [0; 4]; buf.copy_from_slice(chunk); - f32::from_bits(u32::from_le(u32::from_bytes(buf))) + f32::from_bits(u32::from_le(u32::from_le_bytes(buf))) }) .collect::>(); @@ -314,11 +312,11 @@ macro_rules! f64 { #[test] fn $fun() { let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .exact_chunks(8) + .chunks_exact(8) .map(|chunk| { let mut buf = [0; 8]; buf.copy_from_slice(chunk); - f64::from_bits(u64::from_le(u64::from_bytes(buf))) + f64::from_bits(u64::from_le(u64::from_le_bytes(buf))) }) .collect::>(); @@ -353,11 +351,11 @@ macro_rules! f64f64 { #[test] fn $fun() { let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .exact_chunks(8) + .chunks_exact(8) .map(|chunk| { let mut buf = [0; 8]; buf.copy_from_slice(chunk); - f64::from_bits(u64::from_le(u64::from_bytes(buf))) + f64::from_bits(u64::from_le(u64::from_le_bytes(buf))) }) .collect::>(); @@ -394,11 +392,11 @@ macro_rules! f64f64f64 { #[test] fn $fun() { let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .exact_chunks(8) + .chunks_exact(8) .map(|chunk| { let mut buf = [0; 8]; buf.copy_from_slice(chunk); - f64::from_bits(u64::from_le(u64::from_bytes(buf))) + f64::from_bits(u64::from_le(u64::from_le_bytes(buf))) }) .collect::>(); @@ -436,11 +434,11 @@ macro_rules! f64i32 { #[test] fn $fun() { let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .exact_chunks(8) + .chunks_exact(8) .map(|chunk| { let mut buf = [0; 8]; buf.copy_from_slice(chunk); - f64::from_bits(u64::from_le(u64::from_bytes(buf))) + f64::from_bits(u64::from_le(u64::from_le_bytes(buf))) }) .collect::>(); diff --git a/library/compiler-builtins/libm/math/.cargo/config b/library/compiler-builtins/libm/math/.cargo/config deleted file mode 100644 index be79c453ad697..0000000000000 --- a/library/compiler-builtins/libm/math/.cargo/config +++ /dev/null @@ -1,11 +0,0 @@ -[target.thumbv7em-none-eabi] -rustflags = [ - "-C", "link-arg=-Wl,-Tlink.x", - "-C", "link-arg=-nostartfiles", - "-C", "link-arg=-mthumb", - "-C", "link-arg=-march=armv7e-m", - "-C", "link-arg=-mfloat-abi=soft", -] - -[build] -target = "thumbv7em-none-eabi" \ No newline at end of file diff --git a/library/compiler-builtins/libm/math/Cargo.toml b/library/compiler-builtins/libm/math/Cargo.toml deleted file mode 100644 index 5bca038a9c3ce..0000000000000 --- a/library/compiler-builtins/libm/math/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "math" -version = "0.0.0" - -[dependencies] -qemu-arm-rt = { git = "https://github.com/japaric/qemu-arm-rt" } - -[workspace] \ No newline at end of file diff --git a/library/compiler-builtins/libm/math/Cross.toml b/library/compiler-builtins/libm/math/Cross.toml deleted file mode 100644 index 471770b528b45..0000000000000 --- a/library/compiler-builtins/libm/math/Cross.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.thumbv7em-none-eabi] -xargo = false \ No newline at end of file diff --git a/library/compiler-builtins/libm/src/math/acosf.rs b/library/compiler-builtins/libm/src/math/acosf.rs index 469601caba4d7..b12ed531ae218 100644 --- a/library/compiler-builtins/libm/src/math/acosf.rs +++ b/library/compiler-builtins/libm/src/math/acosf.rs @@ -73,3 +73,17 @@ pub fn acosf(x: f32) -> f32 { w = r(z) * s + c; 2. * (df + w) } + +#[cfg(test)] +mod tests { + #[test] + fn acosf() { + extern { + fn acosf(x: f32) -> f32; + } + unsafe { + crate::_eqf(super::acosf(1.0), acosf(1.0)).unwrap(); + } + } + // shared::f32!("musl", acosf); +} From 8560077059df4b5ecfebead0fb3667253b0592c2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 08:12:23 -0700 Subject: [PATCH 0684/4206] Remove newlib generator It's broken and we can try to add it back later if necessary --- library/compiler-builtins/libm/Cargo.toml | 1 - .../libm/crates/newlib-generator/Cargo.toml | 7 - .../crates/newlib-generator/src/macros.rs | 245 ------------------ .../libm/crates/newlib-generator/src/main.rs | 32 --- 4 files changed, 285 deletions(-) delete mode 100644 library/compiler-builtins/libm/crates/newlib-generator/Cargo.toml delete mode 100644 library/compiler-builtins/libm/crates/newlib-generator/src/macros.rs delete mode 100644 library/compiler-builtins/libm/crates/newlib-generator/src/main.rs diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index b4f07eeeed236..c2ac902d9910a 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -20,7 +20,6 @@ members = [ "crates/compiler-builtins-smoke-test", "crates/input-generator", "crates/musl-generator", - "crates/newlib-generator", "crates/shared", ] diff --git a/library/compiler-builtins/libm/crates/newlib-generator/Cargo.toml b/library/compiler-builtins/libm/crates/newlib-generator/Cargo.toml deleted file mode 100644 index 5766cb4b7a059..0000000000000 --- a/library/compiler-builtins/libm/crates/newlib-generator/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "newlib-generator" -version = "0.1.0" -authors = ["Jorge Aparicio "] - -[dependencies] -shared = { path = "../shared" } diff --git a/library/compiler-builtins/libm/crates/newlib-generator/src/macros.rs b/library/compiler-builtins/libm/crates/newlib-generator/src/macros.rs deleted file mode 100644 index 84315a777bdef..0000000000000 --- a/library/compiler-builtins/libm/crates/newlib-generator/src/macros.rs +++ /dev/null @@ -1,245 +0,0 @@ -macro_rules! f32 { - ($($fun:ident,)+) => { - $( - let fun = stringify!($fun); - - fs::create_dir_all("math/src")?; - - let main = format!(" -#![no_main] -#![no_std] - -#[macro_use] -extern crate qemu_arm_rt as rt; - -use core::u32; - -use rt::{{io, process}}; - -entry!(main); - -fn main() {{ - run().unwrap_or_else(|e| {{ - eprintln!(\"error: {{}}\", e); - process::exit(1); - }}) -}} - -fn run() -> Result<(), usize> {{ - #[link(name = \"m\")] - extern \"C\" {{ - fn {0}(_: f32) -> f32; - }} - - let mut buf = [0; 4]; - while let Ok(()) = io::Stdin.read_exact(&mut buf) {{ - let x = f32::from_bits(u32::from_bytes(buf)); - let y = unsafe {{ {0}(x) }}; - - io::Stdout.write_all(&y.to_bits().to_bytes())?; - }} - - Ok(()) -}} - -#[no_mangle] -pub fn __errno() -> *mut i32 {{ - static mut ERRNO: i32 = 0; - unsafe {{ &mut ERRNO }} -}} -", fun); - - File::create("math/src/main.rs")?.write_all(main.as_bytes())?; - - assert!( - Command::new("cross") - .args(&["build", "--target", "thumbv7em-none-eabi", "--release"]) - .current_dir("math") - .status()? - .success() - ); - - let mut qemu = Command::new("qemu-arm") - .arg("math/target/thumbv7em-none-eabi/release/math") - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn()?; - - qemu.stdin.as_mut().take().unwrap().write_all(F32)?; - - let output = qemu.wait_with_output()?; - - File::create(concat!("bin/output/newlib.", stringify!($fun)))? - .write_all(&output.stdout)?; - )+ - } -} - -macro_rules! f32f32 { - ($($fun:ident,)+) => { - $( - let fun = stringify!($fun); - - fs::create_dir_all("math/src")?; - - let main = format!(" -#![no_main] -#![no_std] - -#[macro_use] -extern crate qemu_arm_rt as rt; - -use core::u32; - -use rt::{{io, process}}; - -entry!(main); - -fn main() {{ - run().unwrap_or_else(|e| {{ - eprintln!(\"error: {{}}\", e); - process::exit(1); - }}) -}} - -fn run() -> Result<(), usize> {{ - #[link(name = \"m\")] - extern \"C\" {{ - fn {0}(_: f32, _: f32) -> f32; - }} - - let mut chunk = [0; 8]; - while let Ok(()) = io::Stdin.read_exact(&mut chunk) {{ - let mut buf = [0; 4]; - buf.copy_from_slice(&chunk[..4]); - let x0 = f32::from_bits(u32::from_bytes(buf)); - - buf.copy_from_slice(&chunk[4..]); - let x1 = f32::from_bits(u32::from_bytes(buf)); - - let y = unsafe {{ {0}(x0, x1) }}; - - io::Stdout.write_all(&y.to_bits().to_bytes())?; - }} - - Ok(()) -}} - -#[no_mangle] -pub fn __errno() -> *mut i32 {{ - static mut ERRNO: i32 = 0; - unsafe {{ &mut ERRNO }} -}} -", fun); - - File::create("math/src/main.rs")?.write_all(main.as_bytes())?; - - assert!( - Command::new("cross") - .args(&["build", "--target", "thumbv7em-none-eabi", "--release"]) - .current_dir("math") - .status()? - .success() - ); - - let mut qemu = Command::new("qemu-arm") - .arg("math/target/thumbv7em-none-eabi/release/math") - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn()?; - - qemu.stdin.as_mut().take().unwrap().write_all(F32)?; - - let output = qemu.wait_with_output()?; - - File::create(concat!("bin/output/newlib.", stringify!($fun)))? - .write_all(&output.stdout)?; - )+ - } -} - -macro_rules! f32f32f32 { - ($($fun:ident,)+) => { - $( - let fun = stringify!($fun); - - fs::create_dir_all("math/src")?; - - let main = format!(" -#![no_main] -#![no_std] - -#[macro_use] -extern crate qemu_arm_rt as rt; - -use core::u32; - -use rt::{{io, process}}; - -entry!(main); - -fn main() {{ - run().unwrap_or_else(|e| {{ - eprintln!(\"error: {{}}\", e); - process::exit(1); - }}) -}} - -fn run() -> Result<(), usize> {{ - #[link(name = \"m\")] - extern \"C\" {{ - fn {0}(_: f32, _: f32, _: f32) -> f32; - }} - - let mut chunk = [0; 12]; - while let Ok(()) = io::Stdin.read_exact(&mut chunk) {{ - let mut buf = [0; 4]; - buf.copy_from_slice(&chunk[..4]); - let x0 = f32::from_bits(u32::from_bytes(buf)); - - buf.copy_from_slice(&chunk[4..8]); - let x1 = f32::from_bits(u32::from_bytes(buf)); - - buf.copy_from_slice(&chunk[8..]); - let x2 = f32::from_bits(u32::from_bytes(buf)); - - let y = unsafe {{ {0}(x0, x1, x2) }}; - - io::Stdout.write_all(&y.to_bits().to_bytes())?; - }} - - Ok(()) -}} - -#[no_mangle] -pub fn __errno() -> *mut i32 {{ - static mut ERRNO: i32 = 0; - unsafe {{ &mut ERRNO }} -}} -", fun); - - File::create("math/src/main.rs")?.write_all(main.as_bytes())?; - - assert!( - Command::new("cross") - .args(&["build", "--target", "thumbv7em-none-eabi", "--release"]) - .current_dir("math") - .status()? - .success() - ); - - let mut qemu = Command::new("qemu-arm") - .arg("math/target/thumbv7em-none-eabi/release/math") - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn()?; - - qemu.stdin.as_mut().take().unwrap().write_all(F32)?; - - let output = qemu.wait_with_output()?; - - File::create(concat!("bin/output/newlib.", stringify!($fun)))? - .write_all(&output.stdout)?; - )+ - } -} diff --git a/library/compiler-builtins/libm/crates/newlib-generator/src/main.rs b/library/compiler-builtins/libm/crates/newlib-generator/src/main.rs deleted file mode 100644 index 52a97cabbfd4e..0000000000000 --- a/library/compiler-builtins/libm/crates/newlib-generator/src/main.rs +++ /dev/null @@ -1,32 +0,0 @@ -extern crate shared; - -use std::error::Error; -use std::fs::{self, File}; -use std::io::Write; -use std::process::{Command, Stdio}; - -#[macro_use] -mod macros; - -fn main() -> Result<(), Box> { - const F32: &[u8] = include_bytes!("../../bin/input/f32"); - - f32! { - asinf, - cbrtf, - cosf, - exp2f, - sinf, - tanf, - } - - f32f32! { - hypotf, - } - - f32f32f32! { - fmaf, - } - - Ok(()) -} From 7cb4a204a2d6019a14430ad67fd060f59f2d5934 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 10:48:55 -0700 Subject: [PATCH 0685/4206] Rework how testing is done Use a build script to generate musl reference outputs and then ensure that everything gets hooked up to actually run reference tests. --- library/compiler-builtins/libm/Cargo.toml | 9 +- library/compiler-builtins/libm/build.rs | 344 +++++++++++++ .../libm/crates/input-generator/Cargo.toml | 7 - .../libm/crates/input-generator/src/main.rs | 189 ------- .../libm/crates/musl-generator/Cargo.toml | 9 - .../libm/crates/musl-generator/src/macros.rs | 191 ------- .../libm/crates/musl-generator/src/main.rs | 97 ---- .../libm/crates/shared/Cargo.toml | 7 - .../libm/crates/shared/src/lib.rs | 469 ------------------ library/compiler-builtins/libm/src/lib.rs | 3 + 10 files changed, 351 insertions(+), 974 deletions(-) create mode 100644 library/compiler-builtins/libm/build.rs delete mode 100644 library/compiler-builtins/libm/crates/input-generator/Cargo.toml delete mode 100644 library/compiler-builtins/libm/crates/input-generator/src/main.rs delete mode 100644 library/compiler-builtins/libm/crates/musl-generator/Cargo.toml delete mode 100644 library/compiler-builtins/libm/crates/musl-generator/src/macros.rs delete mode 100644 library/compiler-builtins/libm/crates/musl-generator/src/main.rs delete mode 100644 library/compiler-builtins/libm/crates/shared/Cargo.toml delete mode 100644 library/compiler-builtins/libm/crates/shared/src/lib.rs diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index c2ac902d9910a..7d9890e3e300a 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,20 +8,19 @@ license = "MIT OR Apache-2.0" name = "libm" repository = "https://github.com/japaric/libm" version = "0.1.2" +edition = "2018" [features] # only used to run our test suite checked = [] default = ['stable'] stable = [] +musl-reference-tests = ['rand'] [workspace] members = [ "crates/compiler-builtins-smoke-test", - "crates/input-generator", - "crates/musl-generator", - "crates/shared", ] -[dev-dependencies] -shared = { path = "shared" } +[build-dependencies] +rand = { version = "0.6.5", optional = true } diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs new file mode 100644 index 0000000000000..31b1bbea9473b --- /dev/null +++ b/library/compiler-builtins/libm/build.rs @@ -0,0 +1,344 @@ +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + + #[cfg(feature = "musl-reference-tests")] + musl_reference_tests::generate(); +} + +#[cfg(feature = "musl-reference-tests")] +mod musl_reference_tests { + use rand::seq::SliceRandom; + use rand::Rng; + use std::fs; + use std::process::Command; + + // Number of tests to generate for each function + const NTESTS: usize = 500; + + // These files are all internal functions or otherwise miscellaneous, not + // defining a function we want to test. + const IGNORED_FILES: &[&str] = &[ + "expo2.rs", + "fenv.rs", + "k_cos.rs", + "k_cosf.rs", + "k_expo2.rs", + "k_expo2f.rs", + "k_sin.rs", + "k_sinf.rs", + "k_tan.rs", + "k_tanf.rs", + "mod.rs", + "rem_pio2.rs", + "rem_pio2_large.rs", + "rem_pio2f.rs", + ]; + + struct Function { + name: String, + args: Vec, + ret: Ty, + tests: Vec, + } + + enum Ty { + F32, + F64, + I32, + Bool, + } + + struct Test { + inputs: Vec, + output: i64, + } + + pub fn generate() { + let files = fs::read_dir("src/math") + .unwrap() + .map(|f| f.unwrap().path()) + .collect::>(); + + let mut math = Vec::new(); + for file in files { + if IGNORED_FILES.iter().any(|f| file.ends_with(f)) { + continue; + } + + println!("generating musl reference tests in {:?}", file); + + let contents = fs::read_to_string(file).unwrap(); + let mut functions = contents.lines().filter(|f| f.starts_with("pub fn")); + let function_to_test = functions.next().unwrap(); + if functions.next().is_some() { + panic!("more than one function in"); + } + + math.push(parse(function_to_test)); + } + + // Generate a bunch of random inputs for each function. This will + // attempt to generate a good set of uniform test cases for exercising + // all the various functionality. + generate_random_tests(&mut math, &mut rand::thread_rng()); + + // After we have all our inputs, use the x86_64-unknown-linux-musl + // target to generate the expected output. + generate_test_outputs(&mut math); + + // ... and now that we have both inputs and expected outputs, do a bunch + // of codegen to create the unit tests which we'll actually execute. + generate_unit_tests(&math); + } + + /// A "poor man's" parser for the signature of a function + fn parse(s: &str) -> Function { + let s = eat(s, "pub fn "); + let pos = s.find('(').unwrap(); + let name = &s[..pos]; + let s = &s[pos + 1..]; + let end = s.find(')').unwrap(); + let args = s[..end] + .split(',') + .map(|arg| { + let colon = arg.find(':').unwrap(); + parse_ty(arg[colon + 1..].trim()) + }) + .collect::>(); + let tail = &s[end + 1..]; + let tail = eat(tail, " -> "); + let ret = parse_ty(tail.trim().split(' ').next().unwrap()); + + return Function { + name: name.to_string(), + args, + ret, + tests: Vec::new(), + }; + + fn parse_ty(s: &str) -> Ty { + match s { + "f32" => Ty::F32, + "f64" => Ty::F64, + "i32" => Ty::I32, + "bool" => Ty::Bool, + other => panic!("unknown type `{}`", other), + } + } + + fn eat<'a>(s: &'a str, prefix: &str) -> &'a str { + if s.starts_with(prefix) { + &s[prefix.len()..] + } else { + panic!("{:?} didn't start with {:?}", s, prefix) + } + } + } + + fn generate_random_tests(functions: &mut [Function], rng: &mut R) { + for function in functions { + for _ in 0..NTESTS { + function.tests.push(generate_test(&function.args, rng)); + } + } + + fn generate_test(args: &[Ty], rng: &mut R) -> Test { + let inputs = args.iter().map(|ty| ty.gen_i64(rng)).collect(); + // zero output for now since we'll generate it later + Test { inputs, output: 0 } + } + } + + impl Ty { + fn gen_i64(&self, r: &mut R) -> i64 { + match self { + Ty::F32 => r.gen::().to_bits().into(), + Ty::F64 => r.gen::().to_bits() as i64, + Ty::I32 => { + if r.gen_range(0, 10) < 1 { + let i = *[i32::max_value(), 0, i32::min_value()].choose(r).unwrap(); + i.into() + } else { + r.gen::().into() + } + } + Ty::Bool => r.gen::() as i64, + } + } + + fn libc_ty(&self) -> &'static str { + match self { + Ty::F32 => "f32", + Ty::F64 => "f64", + Ty::I32 => "i32", + Ty::Bool => "i32", + } + } + } + + fn generate_test_outputs(functions: &mut [Function]) { + let mut src = String::new(); + let dst = std::env::var("OUT_DIR").unwrap(); + + // Generate a program which will run all tests with all inputs in + // `functions`. This program will write all outputs to stdout (in a + // binary format). + src.push_str("use std::io::Write;"); + src.push_str("fn main() {"); + src.push_str("let mut result = Vec::new();"); + for function in functions.iter_mut() { + src.push_str("unsafe {"); + src.push_str("extern { fn "); + src.push_str(&function.name); + src.push_str("("); + for (i, arg) in function.args.iter().enumerate() { + src.push_str(&format!("arg{}: {},", i, arg.libc_ty())); + } + src.push_str(") -> "); + src.push_str(function.ret.libc_ty()); + src.push_str("; }"); + + src.push_str(&format!("static TESTS: &[[i64; {}]]", function.args.len())); + src.push_str(" = &["); + for test in function.tests.iter() { + src.push_str("["); + for val in test.inputs.iter() { + src.push_str(&val.to_string()); + src.push_str(","); + } + src.push_str("],"); + } + src.push_str("];"); + + src.push_str("for test in TESTS {"); + src.push_str("let output = "); + src.push_str(&function.name); + src.push_str("("); + for (i, arg) in function.args.iter().enumerate() { + src.push_str(&match arg { + Ty::F32 => format!("f32::from_bits(test[{}] as u32)", i), + Ty::F64 => format!("f64::from_bits(test[{}] as u64)", i), + Ty::I32 => format!("test[{}] as i32", i), + Ty::Bool => format!("test[{}] as i32", i), + }); + src.push_str(","); + } + src.push_str(");"); + src.push_str("let output = "); + src.push_str(match function.ret { + Ty::F32 => "output.to_bits() as i64", + Ty::F64 => "output.to_bits() as i64", + Ty::I32 => "output as i64", + Ty::Bool => "output as i64", + }); + src.push_str(";"); + src.push_str("result.extend_from_slice(&output.to_le_bytes());"); + + src.push_str("}"); + + src.push_str("}"); + } + + src.push_str("std::io::stdout().write_all(&result).unwrap();"); + + src.push_str("}"); + + let path = format!("{}/gen.rs", dst); + fs::write(&path, src).unwrap(); + + // Make it somewhat pretty if something goes wrong + drop(Command::new("rustfmt").arg(&path).status()); + + // Compile and execute this tests for the musl target, assuming we're an + // x86_64 host effectively. + let status = Command::new("rustc") + .current_dir(&dst) + .arg(&path) + .arg("--target=x86_64-unknown-linux-musl") + .status() + .unwrap(); + assert!(status.success()); + let output = Command::new("./gen") + .current_dir(&dst) + .output() + .unwrap(); + assert!(output.status.success()); + assert!(output.stderr.is_empty()); + + // Map all the output bytes back to an `i64` and then shove it all into + // the expected results. + let mut results = + output.stdout.chunks_exact(8) + .map(|buf| { + let mut exact = [0; 8]; + exact.copy_from_slice(buf); + i64::from_le_bytes(exact) + }); + + for test in functions.iter_mut().flat_map(|f| f.tests.iter_mut()) { + test.output = results.next().unwrap(); + } + assert!(results.next().is_none()); + } + + /// Codegens a file which has a ton of `#[test]` annotations for all the + /// tests that we generated above. + fn generate_unit_tests(functions: &[Function]) { + let mut src = String::new(); + let dst = std::env::var("OUT_DIR").unwrap(); + + for function in functions { + src.push_str("#[test]"); + src.push_str("fn "); + src.push_str(&function.name); + src.push_str("_matches_musl() {"); + src.push_str(&format!("static TESTS: &[([i64; {}], i64)]", function.args.len())); + src.push_str(" = &["); + for test in function.tests.iter() { + src.push_str("(["); + for val in test.inputs.iter() { + src.push_str(&val.to_string()); + src.push_str(","); + } + src.push_str("],"); + src.push_str(&test.output.to_string()); + src.push_str("),"); + } + src.push_str("];"); + + src.push_str("for (test, expected) in TESTS {"); + src.push_str("let output = "); + src.push_str(&function.name); + src.push_str("("); + for (i, arg) in function.args.iter().enumerate() { + src.push_str(&match arg { + Ty::F32 => format!("f32::from_bits(test[{}] as u32)", i), + Ty::F64 => format!("f64::from_bits(test[{}] as u64)", i), + Ty::I32 => format!("test[{}] as i32", i), + Ty::Bool => format!("test[{}] as i32", i), + }); + src.push_str(","); + } + src.push_str(");"); + src.push_str(match function.ret { + Ty::F32 => "if _eqf(output, f32::from_bits(*expected as u32)).is_ok() { continue }", + Ty::F64 => "if _eq(output, f64::from_bits(*expected as u64)).is_ok() { continue }", + Ty::I32 => "if output as i64 == expected { continue }", + Ty::Bool => unreachable!(), + }); + + src.push_str(r#" + panic!("INPUT: {:?} EXPECTED: {:?} ACTUAL {:?}", test, expected, output); + "#); + src.push_str("}"); + + src.push_str("}"); + } + + let path = format!("{}/tests.rs", dst); + fs::write(&path, src).unwrap(); + + // Try to make it somewhat pretty + drop(Command::new("rustfmt").arg(&path).status()); + } +} diff --git a/library/compiler-builtins/libm/crates/input-generator/Cargo.toml b/library/compiler-builtins/libm/crates/input-generator/Cargo.toml deleted file mode 100644 index fef2558a8b09f..0000000000000 --- a/library/compiler-builtins/libm/crates/input-generator/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "input-generator" -version = "0.1.0" -authors = ["Jorge Aparicio "] - -[dependencies] -rand = "0.5.4" diff --git a/library/compiler-builtins/libm/crates/input-generator/src/main.rs b/library/compiler-builtins/libm/crates/input-generator/src/main.rs deleted file mode 100644 index 0746ea477e838..0000000000000 --- a/library/compiler-builtins/libm/crates/input-generator/src/main.rs +++ /dev/null @@ -1,189 +0,0 @@ -extern crate rand; - -use std::collections::BTreeSet; -use std::error::Error; -use std::fs::{self, File}; -use std::io::Write; - -use rand::{RngCore, SeedableRng, XorShiftRng}; - -const NTESTS: usize = 10_000; - -fn main() -> Result<(), Box> { - let mut rng = XorShiftRng::from_rng(&mut rand::thread_rng())?; - - fs::remove_dir_all("bin").ok(); - fs::create_dir_all("bin/input")?; - fs::create_dir_all("bin/output")?; - - f32(&mut rng)?; - f32f32(&mut rng)?; - f32f32f32(&mut rng)?; - f32i16(&mut rng)?; - f64(&mut rng)?; - f64f64(&mut rng)?; - f64f64f64(&mut rng)?; - f64i16(&mut rng)?; - - Ok(()) -} - -fn f32(rng: &mut XorShiftRng) -> Result<(), Box> { - let mut set = BTreeSet::new(); - - while set.len() < NTESTS { - let f = f32::from_bits(rng.next_u32()); - - if f.is_nan() { - continue; - } - - set.insert(f.to_bits()); - } - - let mut f = File::create("bin/input/f32")?; - for i in set { - f.write_all(&i.to_le_bytes())?; - } - - Ok(()) -} - -fn f32f32(rng: &mut XorShiftRng) -> Result<(), Box> { - let mut f = File::create("bin/input/f32f32")?; - let mut i = 0; - while i < NTESTS { - let x0 = f32::from_bits(rng.next_u32()); - let x1 = f32::from_bits(rng.next_u32()); - - if x0.is_nan() || x1.is_nan() { - continue; - } - - i += 1; - f.write_all(&x0.to_bits().to_le_bytes())?; - f.write_all(&x1.to_bits().to_le_bytes())?; - } - - Ok(()) -} - -fn f32i16(rng: &mut XorShiftRng) -> Result<(), Box> { - let mut f = File::create("bin/input/f32i16")?; - let mut i = 0; - while i < NTESTS { - let x0 = f32::from_bits(rng.next_u32()); - let x1 = rng.next_u32() as i16; - - if x0.is_nan() { - continue; - } - - i += 1; - f.write_all(&x0.to_bits().to_le_bytes())?; - f.write_all(&x1.to_le_bytes())?; - } - - Ok(()) -} - -fn f32f32f32(rng: &mut XorShiftRng) -> Result<(), Box> { - let mut f = File::create("bin/input/f32f32f32")?; - let mut i = 0; - while i < NTESTS { - let x0 = f32::from_bits(rng.next_u32()); - let x1 = f32::from_bits(rng.next_u32()); - let x2 = f32::from_bits(rng.next_u32()); - - if x0.is_nan() || x1.is_nan() || x2.is_nan() { - continue; - } - - i += 1; - f.write_all(&x0.to_bits().to_le_bytes())?; - f.write_all(&x1.to_bits().to_le_bytes())?; - f.write_all(&x2.to_bits().to_le_bytes())?; - } - - Ok(()) -} - -fn f64(rng: &mut XorShiftRng) -> Result<(), Box> { - let mut set = BTreeSet::new(); - - while set.len() < NTESTS { - let f = f64::from_bits(rng.next_u64()); - - if f.is_nan() { - continue; - } - - set.insert(f.to_bits()); - } - - let mut f = File::create("bin/input/f64")?; - for i in set { - f.write_all(&i.to_le_bytes())?; - } - - Ok(()) -} - -fn f64f64(rng: &mut XorShiftRng) -> Result<(), Box> { - let mut f = File::create("bin/input/f64f64")?; - let mut i = 0; - while i < NTESTS { - let x0 = f64::from_bits(rng.next_u64()); - let x1 = f64::from_bits(rng.next_u64()); - - if x0.is_nan() || x1.is_nan() { - continue; - } - - i += 1; - f.write_all(&x0.to_bits().to_le_bytes())?; - f.write_all(&x1.to_bits().to_le_bytes())?; - } - - Ok(()) -} - -fn f64f64f64(rng: &mut XorShiftRng) -> Result<(), Box> { - let mut f = File::create("bin/input/f64f64f64")?; - let mut i = 0; - while i < NTESTS { - let x0 = f64::from_bits(rng.next_u64()); - let x1 = f64::from_bits(rng.next_u64()); - let x2 = f64::from_bits(rng.next_u64()); - - if x0.is_nan() || x1.is_nan() || x2.is_nan() { - continue; - } - - i += 1; - f.write_all(&x0.to_bits().to_le_bytes())?; - f.write_all(&x1.to_bits().to_le_bytes())?; - f.write_all(&x2.to_bits().to_le_bytes())?; - } - - Ok(()) -} - -fn f64i16(rng: &mut XorShiftRng) -> Result<(), Box> { - let mut f = File::create("bin/input/f64i16")?; - let mut i = 0; - while i < NTESTS { - let x0 = f64::from_bits(rng.next_u64()); - let x1 = rng.next_u32() as i16; - - if x0.is_nan() { - continue; - } - - i += 1; - f.write_all(&x0.to_bits().to_le_bytes())?; - f.write_all(&x1.to_le_bytes())?; - } - - Ok(()) -} diff --git a/library/compiler-builtins/libm/crates/musl-generator/Cargo.toml b/library/compiler-builtins/libm/crates/musl-generator/Cargo.toml deleted file mode 100644 index 0564f35361167..0000000000000 --- a/library/compiler-builtins/libm/crates/musl-generator/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "musl-generator" -version = "0.1.0" -authors = ["Jorge Aparicio "] - -[dependencies] -lazy_static = "1.0.2" -shared = { path = "../shared" } -libm = { path = ".." } diff --git a/library/compiler-builtins/libm/crates/musl-generator/src/macros.rs b/library/compiler-builtins/libm/crates/musl-generator/src/macros.rs deleted file mode 100644 index e47c0ab6f96d1..0000000000000 --- a/library/compiler-builtins/libm/crates/musl-generator/src/macros.rs +++ /dev/null @@ -1,191 +0,0 @@ -macro_rules! f32 { - ($($fun:ident,)+) => {{ - $( - // check type signature - let _: fn(f32) -> f32 = libm::$fun; - let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; - )+ - - for x in shared::F32.iter() { - $( - let y = unsafe { - extern "C" { - fn $fun(_: f32) -> f32; - } - - $fun(*x) - }; - - $fun.write_all(&y.to_bits().to_le_bytes())?; - )+ - } - }}; -} - -macro_rules! f32f32 { - ($($fun:ident,)+) => {{ - $( - // check type signature - let _: fn(f32, f32) -> f32 = libm::$fun; - let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; - )+ - - for (x0, x1) in shared::F32F32.iter() { - $( - let y = unsafe { - extern "C" { - fn $fun(_: f32, _: f32) -> f32; - } - - $fun(*x0, *x1) - }; - - $fun.write_all(&y.to_bits().to_le_bytes())?; - )+ - } - }}; -} - -macro_rules! f32f32f32 { - ($($fun:ident,)+) => {{ - $( - // check type signature - let _: fn(f32, f32, f32) -> f32 = libm::$fun; - let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; - )+ - - for (x0, x1, x2) in shared::F32F32F32.iter() { - $( - let y = unsafe { - extern "C" { - fn $fun(_: f32, _: f32, _: f32) -> f32; - } - - $fun(*x0, *x1, *x2) - }; - - $fun.write_all(&y.to_bits().to_le_bytes())?; - )+ - } - }}; -} - -macro_rules! f32i32 { - ($($fun:ident,)+) => {{ - $( - // check type signature - let _: fn(f32, i32) -> f32 = libm::$fun; - let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; - )+ - - for (x0, x1) in shared::F32I32.iter() { - $( - let y = unsafe { - extern "C" { - fn $fun(_: f32, _: i32) -> f32; - } - - $fun(*x0, *x1 as i32) - }; - - $fun.write_all(&y.to_bits().to_le_bytes())?; - )+ - } - }}; -} - -macro_rules! f64 { - ($($fun:ident,)+) => {{ - $( - // check type signature - let _: fn(f64) -> f64 = libm::$fun; - let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; - )+ - - for x in shared::F64.iter() { - $( - let y = unsafe { - extern "C" { - fn $fun(_: f64) -> f64; - } - - $fun(*x) - }; - - $fun.write_all(&y.to_bits().to_le_bytes())?; - )+ - } - }}; -} - -macro_rules! f64f64 { - ($($fun:ident,)+) => {{ - $( - // check type signature - let _: fn(f64, f64) -> f64 = libm::$fun; - let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; - )+ - - for (x0, x1) in shared::F64F64.iter() { - $( - let y = unsafe { - extern "C" { - fn $fun(_: f64, _: f64) -> f64; - } - - $fun(*x0, *x1) - }; - - $fun.write_all(&y.to_bits().to_le_bytes())?; - )+ - } - }}; -} - -macro_rules! f64f64f64 { - ($($fun:ident,)+) => {{ - $( - // check type signature - let _: fn(f64, f64, f64) -> f64 = libm::$fun; - let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; - )+ - - for (x0, x1, x2) in shared::F64F64F64.iter() { - $( - let y = unsafe { - extern "C" { - fn $fun(_: f64, _: f64, _: f64) -> f64; - } - - $fun(*x0, *x1, *x2) - }; - - $fun.write_all(&y.to_bits().to_le_bytes())?; - )+ - } - }}; -} - -macro_rules! f64i32 { - ($($fun:ident,)+) => {{ - $( - // check type signature - let _: fn(f64, i32) -> f64 = libm::$fun; - let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?; - )+ - - for (x0, x1) in shared::F64I32.iter() { - $( - let y = unsafe { - extern "C" { - fn $fun(_: f64, _: i32) -> f64; - } - - $fun(*x0, *x1 as i32) - }; - - $fun.write_all(&y.to_bits().to_le_bytes())?; - )+ - } - }}; -} diff --git a/library/compiler-builtins/libm/crates/musl-generator/src/main.rs b/library/compiler-builtins/libm/crates/musl-generator/src/main.rs deleted file mode 100644 index 6e57e856dc644..0000000000000 --- a/library/compiler-builtins/libm/crates/musl-generator/src/main.rs +++ /dev/null @@ -1,97 +0,0 @@ -extern crate libm; -extern crate shared; - -use std::error::Error; -use std::fs::File; -use std::io::Write; - -#[macro_use] -mod macros; - -fn main() -> Result<(), Box> { - f32! { - acosf, - asinf, - atanf, - cbrtf, - ceilf, - cosf, - coshf, - exp2f, - expf, - expm1f, - fabsf, - floorf, - log10f, - log1pf, - log2f, - logf, - roundf, - sinf, - sinhf, - sqrtf, - tanf, - tanhf, - truncf, - } - - f32f32! { - atan2f, - fdimf, - fmodf, - hypotf, - powf, - } - - f32i32! { - scalbnf, - } - - f32f32f32! { - fmaf, - } - - f64! { - acos, - asin, - atan, - cbrt, - ceil, - cos, - cosh, - exp, - exp2, - expm1, - fabs, - floor, - log, - log10, - log1p, - log2, - round, - sin, - sinh, - sqrt, - tan, - tanh, - trunc, - } - - f64f64! { - atan2, - fdim, - fmod, - hypot, - pow, - } - - f64i32! { - scalbn, - } - - f64f64f64! { - fma, - } - - Ok(()) -} diff --git a/library/compiler-builtins/libm/crates/shared/Cargo.toml b/library/compiler-builtins/libm/crates/shared/Cargo.toml deleted file mode 100644 index d77823781016d..0000000000000 --- a/library/compiler-builtins/libm/crates/shared/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "shared" -version = "0.1.0" -authors = ["Jorge Aparicio "] - -[dependencies] -lazy_static = "1.0.2" diff --git a/library/compiler-builtins/libm/crates/shared/src/lib.rs b/library/compiler-builtins/libm/crates/shared/src/lib.rs deleted file mode 100644 index 17c20a332e5b4..0000000000000 --- a/library/compiler-builtins/libm/crates/shared/src/lib.rs +++ /dev/null @@ -1,469 +0,0 @@ -#[macro_use] -extern crate lazy_static; - -lazy_static! { - pub static ref F32: Vec = { - let bytes = include_bytes!("../../bin/input/f32"); - - bytes - .chunks_exact(4) - .map(|chunk| { - let mut buf = [0; 4]; - buf.copy_from_slice(chunk); - f32::from_bits(u32::from_le(u32::from_le_bytes(buf))) - }) - .collect() - }; - pub static ref F32F32: Vec<(f32, f32)> = { - let bytes = include_bytes!("../../bin/input/f32f32"); - - bytes - .chunks_exact(8) - .map(|chunk| { - let mut x0 = [0; 4]; - let mut x1 = [0; 4]; - x0.copy_from_slice(&chunk[..4]); - x1.copy_from_slice(&chunk[4..]); - - ( - f32::from_bits(u32::from_le(u32::from_le_bytes(x0))), - f32::from_bits(u32::from_le(u32::from_le_bytes(x1))), - ) - }) - .collect() - }; - pub static ref F32F32F32: Vec<(f32, f32, f32)> = { - let bytes = include_bytes!("../../bin/input/f32f32f32"); - - bytes - .chunks_exact(12) - .map(|chunk| { - let mut x0 = [0; 4]; - let mut x1 = [0; 4]; - let mut x2 = [0; 4]; - x0.copy_from_slice(&chunk[..4]); - x1.copy_from_slice(&chunk[4..8]); - x2.copy_from_slice(&chunk[8..]); - - ( - f32::from_bits(u32::from_le(u32::from_le_bytes(x0))), - f32::from_bits(u32::from_le(u32::from_le_bytes(x1))), - f32::from_bits(u32::from_le(u32::from_le_bytes(x2))), - ) - }) - .collect() - }; - pub static ref F32I32: Vec<(f32, i32)> = { - let bytes = include_bytes!("../../bin/input/f32i16"); - - bytes - .chunks_exact(6) - .map(|chunk| { - let mut x0 = [0; 4]; - let mut x1 = [0; 2]; - x0.copy_from_slice(&chunk[..4]); - x1.copy_from_slice(&chunk[4..]); - - ( - f32::from_bits(u32::from_le(u32::from_le_bytes(x0))), - i16::from_le(i16::from_le_bytes(x1)) as i32, - ) - }) - .collect() - }; - pub static ref F64: Vec = { - let bytes = include_bytes!("../../bin/input/f64"); - - bytes - .chunks_exact(8) - .map(|chunk| { - let mut buf = [0; 8]; - buf.copy_from_slice(chunk); - f64::from_bits(u64::from_le(u64::from_le_bytes(buf))) - }) - .collect() - }; - pub static ref F64F64: Vec<(f64, f64)> = { - let bytes = include_bytes!("../../bin/input/f64f64"); - - bytes - .chunks_exact(16) - .map(|chunk| { - let mut x0 = [0; 8]; - let mut x1 = [0; 8]; - x0.copy_from_slice(&chunk[..8]); - x1.copy_from_slice(&chunk[8..]); - - ( - f64::from_bits(u64::from_le(u64::from_le_bytes(x0))), - f64::from_bits(u64::from_le(u64::from_le_bytes(x1))), - ) - }) - .collect() - }; - pub static ref F64F64F64: Vec<(f64, f64, f64)> = { - let bytes = include_bytes!("../../bin/input/f64f64f64"); - - bytes - .chunks_exact(24) - .map(|chunk| { - let mut x0 = [0; 8]; - let mut x1 = [0; 8]; - let mut x2 = [0; 8]; - x0.copy_from_slice(&chunk[..8]); - x1.copy_from_slice(&chunk[8..16]); - x2.copy_from_slice(&chunk[16..]); - - ( - f64::from_bits(u64::from_le(u64::from_le_bytes(x0))), - f64::from_bits(u64::from_le(u64::from_le_bytes(x1))), - f64::from_bits(u64::from_le(u64::from_le_bytes(x2))), - ) - }) - .collect() - }; - pub static ref F64I32: Vec<(f64, i32)> = { - let bytes = include_bytes!("../../bin/input/f64i16"); - - bytes - .chunks_exact(10) - .map(|chunk| { - let mut x0 = [0; 8]; - let mut x1 = [0; 2]; - x0.copy_from_slice(&chunk[..8]); - x1.copy_from_slice(&chunk[8..]); - - ( - f64::from_bits(u64::from_le(u64::from_le_bytes(x0))), - i16::from_le(i16::from_le_bytes(x1)) as i32, - ) - }) - .collect() - }; -} - -#[macro_export] -macro_rules! f32 { - ($lib:expr, $($fun:ident),+) => { - $( - #[test] - fn $fun() { - let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .chunks_exact(4) - .map(|chunk| { - let mut buf = [0; 4]; - buf.copy_from_slice(chunk); - f32::from_bits(u32::from_le(u32::from_le_bytes(buf))) - }) - .collect::>(); - - for (input, expected) in $crate::F32.iter().zip(&expected) { - if let Ok(output) = panic::catch_unwind(|| libm::$fun(*input)) { - if let Err(error) = libm::_eqf(output, *expected) { - panic!( - "INPUT: {:#x}, OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", - input.to_bits(), - output.to_bits(), - expected.to_bits(), - error - ); - } - } else { - panic!( - "INPUT: {:#x}, OUTPUT: PANIC!, EXPECTED: {:#x}", - input.to_bits(), - expected.to_bits() - ); - } - } - } - )+ - } -} - -#[macro_export] -macro_rules! f32f32 { - ($lib:expr, $($fun:ident),+) => { - $( - #[test] - fn $fun() { - let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .chunks_exact(4) - .map(|chunk| { - let mut buf = [0; 4]; - buf.copy_from_slice(chunk); - f32::from_bits(u32::from_le(u32::from_le_bytes(buf))) - }) - .collect::>(); - - for ((i0, i1), expected) in $crate::F32F32.iter().zip(&expected) { - if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) { - if let Err(error) = libm::_eqf(output, *expected) { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", - i0.to_bits(), - i1.to_bits(), - output.to_bits(), - expected.to_bits(), - error - ); - } - } else { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", - i0.to_bits(), - i1.to_bits(), - expected.to_bits() - ); - } - } - } - )+ - } -} - -#[macro_export] -macro_rules! f32f32f32 { - ($lib:expr, $($fun:ident),+) => { - $( - #[test] - fn $fun() { - let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .chunks_exact(4) - .map(|chunk| { - let mut buf = [0; 4]; - buf.copy_from_slice(chunk); - f32::from_bits(u32::from_le(u32::from_le_bytes(buf))) - }) - .collect::>(); - - for ((i0, i1, i2), expected) in $crate::F32F32F32.iter().zip(&expected) { - if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1, *i2)) { - if let Err(error) = libm::_eqf(output, *expected) { - panic!( - "INPUT: ({:#x}, {:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", - i0.to_bits(), - i1.to_bits(), - i2.to_bits(), - output.to_bits(), - expected.to_bits(), - error - ); - } - } else { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", - i0.to_bits(), - i1.to_bits(), - expected.to_bits() - ); - } - } - } - )+ - } -} - -#[macro_export] -macro_rules! f32i32 { - ($lib:expr, $($fun:ident),+) => { - $( - #[test] - fn $fun() { - let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .chunks_exact(4) - .map(|chunk| { - let mut buf = [0; 4]; - buf.copy_from_slice(chunk); - f32::from_bits(u32::from_le(u32::from_le_bytes(buf))) - }) - .collect::>(); - - for ((i0, i1), expected) in $crate::F32I32.iter().zip(&expected) { - if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) { - if let Err(error) = libm::_eqf(output, *expected) { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", - i0.to_bits(), - i1, - output.to_bits(), - expected.to_bits(), - error - ); - } - } else { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", - i0.to_bits(), - i1, - expected.to_bits() - ); - } - } - } - )+ - } -} - -#[macro_export] -macro_rules! f64 { - ($lib:expr, $($fun:ident),+) => { - $( - #[test] - fn $fun() { - let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .chunks_exact(8) - .map(|chunk| { - let mut buf = [0; 8]; - buf.copy_from_slice(chunk); - f64::from_bits(u64::from_le(u64::from_le_bytes(buf))) - }) - .collect::>(); - - for (input, expected) in shared::F64.iter().zip(&expected) { - if let Ok(output) = panic::catch_unwind(|| libm::$fun(*input)) { - if let Err(error) = libm::_eq(output, *expected) { - panic!( - "INPUT: {:#x}, OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", - input.to_bits(), - output.to_bits(), - expected.to_bits(), - error - ); - } - } else { - panic!( - "INPUT: {:#x}, OUTPUT: PANIC!, EXPECTED: {:#x}", - input.to_bits(), - expected.to_bits() - ); - } - } - } - )+ - } -} - -#[macro_export] -macro_rules! f64f64 { - ($lib:expr, $($fun:ident),+) => { - $( - #[test] - fn $fun() { - let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .chunks_exact(8) - .map(|chunk| { - let mut buf = [0; 8]; - buf.copy_from_slice(chunk); - f64::from_bits(u64::from_le(u64::from_le_bytes(buf))) - }) - .collect::>(); - - for ((i0, i1), expected) in shared::F64F64.iter().zip(&expected) { - if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) { - if let Err(error) = libm::_eq(output, *expected) { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", - i0.to_bits(), - i1.to_bits(), - output.to_bits(), - expected.to_bits(), - error - ); - } - } else { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", - i0.to_bits(), - i1.to_bits(), - expected.to_bits() - ); - } - } - } - )+ - } -} - -#[macro_export] -macro_rules! f64f64f64 { - ($lib:expr, $($fun:ident),+) => { - $( - #[test] - fn $fun() { - let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .chunks_exact(8) - .map(|chunk| { - let mut buf = [0; 8]; - buf.copy_from_slice(chunk); - f64::from_bits(u64::from_le(u64::from_le_bytes(buf))) - }) - .collect::>(); - - for ((i0, i1, i2), expected) in shared::F64F64F64.iter().zip(&expected) { - if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1, *i2)) { - if let Err(error) = libm::_eq(output, *expected) { - panic!( - "INPUT: ({:#x}, {:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", - i0.to_bits(), - i1.to_bits(), - i2.to_bits(), - output.to_bits(), - expected.to_bits(), - error - ); - } - } else { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", - i0.to_bits(), - i1.to_bits(), - expected.to_bits() - ); - } - } - } - )+ - } -} - -#[macro_export] -macro_rules! f64i32 { - ($lib:expr, $($fun:ident),+) => { - $( - #[test] - fn $fun() { - let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun))) - .chunks_exact(8) - .map(|chunk| { - let mut buf = [0; 8]; - buf.copy_from_slice(chunk); - f64::from_bits(u64::from_le(u64::from_le_bytes(buf))) - }) - .collect::>(); - - for ((i0, i1), expected) in shared::F64I32.iter().zip(&expected) { - if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) { - if let Err(error) = libm::_eq(output, *expected) { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}", - i0.to_bits(), - i1, - output.to_bits(), - expected.to_bits(), - error - ); - } - } else { - panic!( - "INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}", - i0.to_bits(), - i1, - expected.to_bits() - ); - } - } - } - )+ - } -} diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 6be458728197f..e705dde0f917b 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -625,3 +625,6 @@ mod private { impl Sealed for f32 {} impl Sealed for f64 {} } + +#[cfg(test)] +include!(concat!(env!("OUT_DIR"), "/tests.rs")); From 8d79795d70f7dd30d26720462c39ca0990c8a777 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 11:37:21 -0700 Subject: [PATCH 0686/4206] Overhaul tests * Move everything to azure pipelines * Inline docker configuration in this repo (no `cross`) * Delete `no-panic` example, use `#[no_panic]` instead. --- library/compiler-builtins/libm/.travis.yml | 58 -------- library/compiler-builtins/libm/Cargo.toml | 13 +- .../libm/azure-pipelines.yml | 140 +++++------------- library/compiler-builtins/libm/build.rs | 11 +- .../libm/ci/azure-test-all.yml | 39 +---- .../aarch64-unknown-linux-gnu/Dockerfile | 10 ++ .../arm-unknown-linux-gnueabi/Dockerfile | 9 ++ .../arm-unknown-linux-gnueabihf/Dockerfile | 9 ++ .../armv7-unknown-linux-gnueabihf/Dockerfile | 9 ++ .../docker/i686-unknown-linux-gnu/Dockerfile | 4 + .../docker/mips-unknown-linux-gnu/Dockerfile | 12 ++ .../mips64-unknown-linux-gnuabi64/Dockerfile | 15 ++ .../Dockerfile | 14 ++ .../mipsel-unknown-linux-gnu/Dockerfile | 12 ++ .../powerpc-unknown-linux-gnu/Dockerfile | 12 ++ .../powerpc64-unknown-linux-gnu/Dockerfile | 13 ++ .../powerpc64le-unknown-linux-gnu/Dockerfile | 13 ++ .../x86_64-unknown-linux-gnu/Dockerfile | 4 + library/compiler-builtins/libm/ci/install.sh | 25 ---- .../compiler-builtins/libm/ci/run-docker.sh | 36 +++++ library/compiler-builtins/libm/ci/run.sh | 12 ++ library/compiler-builtins/libm/ci/script.sh | 37 ----- .../libm/examples/no-panic.rs | 115 -------------- library/compiler-builtins/libm/src/lib.rs | 4 +- .../compiler-builtins/libm/src/math/acos.rs | 1 + .../compiler-builtins/libm/src/math/acosf.rs | 1 + .../compiler-builtins/libm/src/math/asin.rs | 1 + .../compiler-builtins/libm/src/math/asinf.rs | 1 + .../compiler-builtins/libm/src/math/atan.rs | 1 + .../compiler-builtins/libm/src/math/atan2.rs | 1 + .../compiler-builtins/libm/src/math/atan2f.rs | 1 + .../compiler-builtins/libm/src/math/atanf.rs | 1 + .../compiler-builtins/libm/src/math/cbrt.rs | 1 + .../compiler-builtins/libm/src/math/cbrtf.rs | 1 + .../compiler-builtins/libm/src/math/ceil.rs | 1 + .../compiler-builtins/libm/src/math/ceilf.rs | 1 + .../compiler-builtins/libm/src/math/cos.rs | 1 + .../compiler-builtins/libm/src/math/cosf.rs | 1 + .../compiler-builtins/libm/src/math/cosh.rs | 1 + .../compiler-builtins/libm/src/math/coshf.rs | 1 + .../compiler-builtins/libm/src/math/exp.rs | 1 + .../compiler-builtins/libm/src/math/exp2.rs | 1 + .../compiler-builtins/libm/src/math/exp2f.rs | 1 + .../compiler-builtins/libm/src/math/expf.rs | 1 + .../compiler-builtins/libm/src/math/expm1.rs | 1 + .../compiler-builtins/libm/src/math/expm1f.rs | 1 + .../compiler-builtins/libm/src/math/expo2.rs | 1 + .../compiler-builtins/libm/src/math/fabs.rs | 1 + .../compiler-builtins/libm/src/math/fabsf.rs | 1 + .../compiler-builtins/libm/src/math/fdim.rs | 1 + .../compiler-builtins/libm/src/math/fdimf.rs | 1 + .../compiler-builtins/libm/src/math/floor.rs | 1 + .../compiler-builtins/libm/src/math/floorf.rs | 1 + .../compiler-builtins/libm/src/math/fma.rs | 1 + .../compiler-builtins/libm/src/math/fmaf.rs | 1 + .../compiler-builtins/libm/src/math/fmod.rs | 1 + .../compiler-builtins/libm/src/math/fmodf.rs | 1 + .../compiler-builtins/libm/src/math/hypot.rs | 1 + .../compiler-builtins/libm/src/math/hypotf.rs | 1 + .../compiler-builtins/libm/src/math/k_cos.rs | 1 + .../compiler-builtins/libm/src/math/k_cosf.rs | 1 + .../libm/src/math/k_expo2.rs | 1 + .../libm/src/math/k_expo2f.rs | 1 + .../compiler-builtins/libm/src/math/k_sin.rs | 1 + .../compiler-builtins/libm/src/math/k_sinf.rs | 1 + .../compiler-builtins/libm/src/math/k_tan.rs | 1 + .../compiler-builtins/libm/src/math/k_tanf.rs | 1 + .../compiler-builtins/libm/src/math/log.rs | 1 + .../compiler-builtins/libm/src/math/log10.rs | 1 + .../compiler-builtins/libm/src/math/log10f.rs | 1 + .../compiler-builtins/libm/src/math/log1p.rs | 1 + .../compiler-builtins/libm/src/math/log1pf.rs | 1 + .../compiler-builtins/libm/src/math/log2.rs | 1 + .../compiler-builtins/libm/src/math/log2f.rs | 1 + .../compiler-builtins/libm/src/math/logf.rs | 1 + .../compiler-builtins/libm/src/math/pow.rs | 1 + .../compiler-builtins/libm/src/math/powf.rs | 1 + .../libm/src/math/rem_pio2.rs | 1 + .../libm/src/math/rem_pio2_large.rs | 1 + .../libm/src/math/rem_pio2f.rs | 1 + .../compiler-builtins/libm/src/math/round.rs | 1 + .../compiler-builtins/libm/src/math/roundf.rs | 1 + .../compiler-builtins/libm/src/math/scalbn.rs | 1 + .../libm/src/math/scalbnf.rs | 1 + .../compiler-builtins/libm/src/math/sin.rs | 1 + .../compiler-builtins/libm/src/math/sinf.rs | 1 + .../compiler-builtins/libm/src/math/sinh.rs | 1 + .../compiler-builtins/libm/src/math/sinhf.rs | 1 + .../compiler-builtins/libm/src/math/sqrt.rs | 1 + .../compiler-builtins/libm/src/math/sqrtf.rs | 1 + .../compiler-builtins/libm/src/math/tan.rs | 1 + .../compiler-builtins/libm/src/math/tanf.rs | 1 + .../compiler-builtins/libm/src/math/tanh.rs | 1 + .../compiler-builtins/libm/src/math/tanhf.rs | 1 + .../compiler-builtins/libm/src/math/trunc.rs | 1 + .../compiler-builtins/libm/src/math/truncf.rs | 1 + 96 files changed, 313 insertions(+), 385 deletions(-) delete mode 100644 library/compiler-builtins/libm/.travis.yml create mode 100644 library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/libm/ci/install.sh create mode 100755 library/compiler-builtins/libm/ci/run-docker.sh create mode 100755 library/compiler-builtins/libm/ci/run.sh delete mode 100644 library/compiler-builtins/libm/ci/script.sh delete mode 100644 library/compiler-builtins/libm/examples/no-panic.rs diff --git a/library/compiler-builtins/libm/.travis.yml b/library/compiler-builtins/libm/.travis.yml deleted file mode 100644 index 7583161781963..0000000000000 --- a/library/compiler-builtins/libm/.travis.yml +++ /dev/null @@ -1,58 +0,0 @@ -language: rust -services: docker -sudo: required - -matrix: - include: - - env: TARGET=aarch64-unknown-linux-gnu - rust: nightly - - env: TARGET=armv7-unknown-linux-gnueabihf - rust: nightly - - env: TARGET=i686-unknown-linux-gnu - rust: nightly - - env: TARGET=mips-unknown-linux-gnu - rust: nightly - - env: TARGET=mips64-unknown-linux-gnuabi64 - rust: nightly - - env: TARGET=mips64el-unknown-linux-gnuabi64 - rust: nightly - - env: TARGET=mipsel-unknown-linux-gnu - rust: nightly - - env: TARGET=powerpc-unknown-linux-gnu - rust: nightly - - env: TARGET=powerpc64-unknown-linux-gnu - rust: nightly - - env: TARGET=powerpc64le-unknown-linux-gnu - rust: nightly - - env: TARGET=x86_64-unknown-linux-gnu - rust: nightly - - env: TARGET=cargo-fmt - rust: beta - - - env: TARGET=wasm32-unknown-unknown - rust: nightly - install: rustup target add $TARGET - script: - - cargo build --target $TARGET - - cargo build --no-default-features --target $TARGET - -before_install: set -e - -install: - - bash ci/install.sh - -script: - - export PATH=$HOME/.local/bin:$PATH - - bash ci/script.sh - -after_script: set +e - -cache: cargo - -before_cache: - - chmod -R a+r $HOME/.cargo; - -branches: - only: - - staging - - trying diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 7d9890e3e300a..45fad8230a062 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -6,21 +6,30 @@ documentation = "https://docs.rs/libm" keywords = ["libm", "math"] license = "MIT OR Apache-2.0" name = "libm" -repository = "https://github.com/japaric/libm" +repository = "https://github.com/rust-lang-nursery/libm" version = "0.1.2" edition = "2018" [features] # only used to run our test suite -checked = [] default = ['stable'] stable = [] + +# Generate tests which are random inputs and the outputs are calculated with +# musl libc. musl-reference-tests = ['rand'] +# Used checked array indexing instead of unchecked array indexing in this +# library. +checked = [] + [workspace] members = [ "crates/compiler-builtins-smoke-test", ] +[dev-dependencies] +no-panic = "0.1.8" + [build-dependencies] rand = { version = "0.6.5", optional = true } diff --git a/library/compiler-builtins/libm/azure-pipelines.yml b/library/compiler-builtins/libm/azure-pipelines.yml index 36271ec1bea3e..82a74452a0f4c 100644 --- a/library/compiler-builtins/libm/azure-pipelines.yml +++ b/library/compiler-builtins/libm/azure-pipelines.yml @@ -10,26 +10,18 @@ jobs: env: TOOLCHAIN: nightly - bash: rustup target add $TARGET - displayName: "Install rust cross target" - - bash: | - set -e - mkdir cross - curl -L https://github.com/rust-embedded/cross/releases/download/v0.1.14/cross-v0.1.14-x86_64-unknown-linux-musl.tar.gz | tar xzf - -C $HOME/.cargo/bin - displayName: "Install cross" - - bash: cross test --lib --features checked --target $TARGET --release - displayName: "Run lib tests" - - bash: cross test --tests --features checked --target $TARGET --release - displayName: "Run integration tests" + - template: ci/azure-install-rust.yml + - bash: cargo generate-lockfile && ./ci/run-docker.sh $TARGET strategy: matrix: aarch64: TARGET: aarch64-unknown-linux-gnu - armhv: + arm: + TARGET: arm-unknown-linux-gnueabi + armhf: TARGET: arm-unknown-linux-gnueabihf armv7: TARGET: armv7-unknown-linux-gnueabihf - i586: - TARGET: i586-unknown-linux-gnu i686: TARGET: i686-unknown-linux-gnu mips: @@ -47,97 +39,31 @@ jobs: x86_64: TARGET: x86_64-unknown-linux-gnu - # - job: Linux - # pool: - # vmImage: ubuntu-16.04 - # steps: - # - template: ci/azure-test-all.yml - # strategy: - # matrix: - # stable: - # TOOLCHAIN: stable - # beta: - # TOOLCHAIN: beta - # nightly: - # TOOLCHAIN: nightly - # - # - job: macOS - # pool: - # vmImage: macos-10.13 - # steps: - # - template: ci/azure-test-all.yml - # strategy: - # matrix: - # x86_64: - # TARGET: x86_64-apple-darwin - # - # - job: iOS - # pool: - # vmImage: macos-10.13 - # steps: - # - checkout: self - # submodules: true - # - template: ci/azure-install-rust.yml - # - script: rustup target add $TARGET - # displayName: "Install rust cross target" - # - bash: | - # set -e - # export SDK_PATH=`xcrun --show-sdk-path --sdk $SDK` - # export RUSTFLAGS="-C link-arg=-isysroot -C link-arg=$SDK_PATH" - # cargo test --no-run --target $TARGET - # displayName: "Build for iOS" - # strategy: - # matrix: - # aarch64: - # TARGET: aarch64-apple-ios - # SDK: iphoneos - # armv7: - # TARGET: armv7-apple-ios - # SDK: iphoneos - # armv7s: - # TARGET: armv7s-apple-ios - # SDK: iphoneos - # i386: - # TARGET: i386-apple-ios - # SDK: iphonesimulator - # x86_64: - # TARGET: x86_64-apple-ios - # SDK: iphonesimulator - # - # - job: wasm - # pool: - # vmImage: ubuntu-16.04 - # steps: - # - checkout: self - # submodules: true - # - template: ci/azure-install-rust.yml - # - script: rustup target add wasm32-unknown-unknown - # displayName: "Install rust cross target" - # - script: cargo build --target wasm32-unknown-unknown - # displayName: "Build for wasm" - # - # - job: Windows - # pool: - # vmImage: vs2017-win2016 - # steps: - # - template: ci/azure-test-all.yml - # strategy: - # matrix: - # x86_64-msvc: - # TARGET: x86_64-pc-windows-msvc - # i686-msvc: - # TARGET: i686-pc-windows-msvc - # x86_64-gnu: - # TARGET: x86_64-pc-windows-gnu - # i686-gnu: - # TARGET: i686-pc-windows-gnu - # - # - job: Windows_arm64 - # pool: - # vmImage: windows-2019 - # steps: - # - template: ci/azure-install-rust.yml - # - script: rustup target add aarch64-pc-windows-msvc - # displayName: "Install rust cross target" - # - script: cargo test --no-run --target aarch64-pc-windows-msvc - # displayName: "Build for arm64" + - job: wasm + pool: + vmImage: ubuntu-16.04 + steps: + - template: ci/azure-install-rust.yml + env: + TOOLCHAIN: nightly + - script: rustup target add wasm32-unknown-unknown + displayName: "Install rust wasm target" + - script: cargo build --target wasm32-unknown-unknown + displayName: "Build for wasm" + - script: cargo build --target wasm32-unknown-unknown --no-default-features + displayName: "Build for wasm (no default features)" + + - job: rustfmt + pool: + vmImage: ubuntu-16.04 + steps: + - template: ci/azure-install-rust.yml + - bash: rustup component add rustfmt + - bash: cargo fmt --all -- --check + + - job: compiler_builtins_works + pool: + vmImage: ubuntu-16.04 + steps: + - template: ci/azure-install-rust.yml + - bash: cargo build -p cb diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 31b1bbea9473b..41dc920e9f7d6 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -1,8 +1,17 @@ +use std::env; + fn main() { println!("cargo:rerun-if-changed=build.rs"); #[cfg(feature = "musl-reference-tests")] musl_reference_tests::generate(); + + if !cfg!(feature = "checked") { + let lvl = env::var("OPT_LEVEL").unwrap(); + if lvl != "0" { + println!("cargo:rustc-cfg=assert_no_panic"); + } + } } #[cfg(feature = "musl-reference-tests")] @@ -335,7 +344,7 @@ mod musl_reference_tests { src.push_str("}"); } - let path = format!("{}/tests.rs", dst); + let path = format!("{}/musl-tests.rs", dst); fs::write(&path, src).unwrap(); // Try to make it somewhat pretty diff --git a/library/compiler-builtins/libm/ci/azure-test-all.yml b/library/compiler-builtins/libm/ci/azure-test-all.yml index b2b7124d3ff3e..36831bd540182 100644 --- a/library/compiler-builtins/libm/ci/azure-test-all.yml +++ b/library/compiler-builtins/libm/ci/azure-test-all.yml @@ -1,41 +1,4 @@ steps: - - checkout: self - submodules: true - template: azure-install-rust.yml - - bash: cargo build --manifest-path backtrace-sys/Cargo.toml - displayName: "Build backtrace-sys" - - bash: cargo build - displayName: "Build backtrace" - - bash: cargo test - displayName: "Test backtrace" - - bash: cargo test --no-default-features - displayName: "Test backtrace (-default)" - - bash: cargo test --no-default-features --features 'std' - displayName: "Test backtrace (-default + std)" - - bash: cargo test --no-default-features --features 'libunwind std' - displayName: "Test backtrace (-default + libunwind)" - - bash: cargo test --no-default-features --features 'libunwind dladdr std' - displayName: "Test backtrace (-default + libunwind + dladdr)" - - bash: cargo test --no-default-features --features 'libunwind libbacktrace std' - displayName: "Test backtrace (-default + libunwind + libbacktrace)" - - bash: cargo test --no-default-features --features 'unix-backtrace std' - displayName: "Test backtrace (-default + unix-backtrace)" - - bash: cargo test --no-default-features --features 'unix-backtrace dladdr std' - displayName: "Test backtrace (-default + unix-backtrace + dladdr)" - - bash: cargo test --no-default-features --features 'unix-backtrace libbacktrace std' - displayName: "Test backtrace (-default + unix-backtrace + libbacktrace)" - - bash: cargo test --no-default-features --features 'serialize-serde std' - displayName: "Test backtrace (-default + serialize-serde + std)" - - bash: cargo test --no-default-features --features 'serialize-rustc std' - displayName: "Test backtrace (-default + serialize-rustc + std)" - - bash: cargo test --no-default-features --features 'serialize-rustc serialize-serde std' - displayName: "Test backtrace (-default + serialize-rustc + serialize-serde + std)" - - bash: cargo test --no-default-features --features 'cpp_demangle std' - displayName: "Test backtrace (-default + cpp_demangle + std)" - - bash: cargo test --no-default-features --features 'gimli-symbolize std' - displayName: "Test backtrace (-default + gimli-symbolize + std)" - - bash: cargo test --no-default-features --features 'dbghelp std' - displayName: "Test backtrace (-default + dbghelp + std)" - - bash: cd ./cpp_smoke_test && cargo test - displayName: "Test cpp_smoke_test" + - bash: cargo generate-lockfile && ./ci/run-docker.sh $TARGET diff --git a/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile new file mode 100644 index 0000000000000..9e2559f4ab3a2 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,10 @@ +FROM ubuntu:18.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-aarch64-linux-gnu libc6-dev-arm64-cross \ + qemu-user-static +ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ + CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER=qemu-aarch64-static \ + QEMU_LD_PREFIX=/usr/aarch64-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile new file mode 100644 index 0000000000000..afab874bc2817 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile @@ -0,0 +1,9 @@ +FROM ubuntu:18.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-linux-gnueabi libc6-dev-armel-cross qemu-user-static +ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER=arm-linux-gnueabi-gcc \ + CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_RUNNER=qemu-arm-static \ + QEMU_LD_PREFIX=/usr/arm-linux-gnueabi \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile new file mode 100644 index 0000000000000..3ed3602b0dc97 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile @@ -0,0 +1,9 @@ +FROM ubuntu:18.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static +ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \ + QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile new file mode 100644 index 0000000000000..6617af1558c9a --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile @@ -0,0 +1,9 @@ +FROM ubuntu:18.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static +ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \ + QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile new file mode 100644 index 0000000000000..5783e28e12200 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile @@ -0,0 +1,4 @@ +FROM ubuntu:18.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc-multilib libc6-dev ca-certificates diff --git a/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile new file mode 100644 index 0000000000000..f47e8f5227b49 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile @@ -0,0 +1,12 @@ +FROM ubuntu:18.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-mips-linux-gnu libc6-dev-mips-cross \ + binfmt-support qemu-user-static qemu-system-mips + +ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER=mips-linux-gnu-gcc \ + CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_RUNNER=qemu-mips-static \ + QEMU_LD_PREFIX=/usr/mips-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile new file mode 100644 index 0000000000000..8fa77c7bd0737 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile @@ -0,0 +1,15 @@ +FROM ubuntu:18.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + ca-certificates \ + gcc \ + gcc-mips64-linux-gnuabi64 \ + libc6-dev \ + libc6-dev-mips64-cross \ + qemu-user-static \ + qemu-system-mips +ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER=mips64-linux-gnuabi64-gcc \ + CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64-static \ + CC_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-gcc \ + QEMU_LD_PREFIX=/usr/mips64-linux-gnuabi64 \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile new file mode 100644 index 0000000000000..c6611d9ac899c --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile @@ -0,0 +1,14 @@ +FROM ubuntu:18.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + ca-certificates \ + gcc \ + gcc-mips64el-linux-gnuabi64 \ + libc6-dev \ + libc6-dev-mips64el-cross \ + qemu-user-static +ENV CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_LINKER=mips64el-linux-gnuabi64-gcc \ + CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64el-static \ + CC_mips64el_unknown_linux_gnuabi64=mips64el-linux-gnuabi64-gcc \ + QEMU_LD_PREFIX=/usr/mips64el-linux-gnuabi64 \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile new file mode 100644 index 0000000000000..0bc695624620e --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile @@ -0,0 +1,12 @@ +FROM ubuntu:18.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-mipsel-linux-gnu libc6-dev-mipsel-cross \ + binfmt-support qemu-user-static + +ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER=mipsel-linux-gnu-gcc \ + CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_RUNNER=qemu-mipsel-static \ + QEMU_LD_PREFIX=/usr/mipsel-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile new file mode 100644 index 0000000000000..2d39fef6142bb --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile @@ -0,0 +1,12 @@ +FROM ubuntu:18.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user-static ca-certificates \ + gcc-powerpc-linux-gnu libc6-dev-powerpc-cross \ + qemu-system-ppc + +ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER=powerpc-linux-gnu-gcc \ + CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc-static \ + QEMU_LD_PREFIX=/usr/powerpc-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile new file mode 100644 index 0000000000000..653cd351156e1 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,13 @@ +FROM ubuntu:18.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross \ + binfmt-support qemu-user-static qemu-system-ppc + +ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER=powerpc64-linux-gnu-gcc \ + CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64-static \ + CC_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-gcc \ + QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile new file mode 100644 index 0000000000000..63ea9af9d2023 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile @@ -0,0 +1,13 @@ +FROM ubuntu:18.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user-static ca-certificates \ + gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross \ + qemu-system-ppc + +ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER=powerpc64le-linux-gnu-gcc \ + CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64le-static \ + QEMU_CPU=POWER8 \ + QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile new file mode 100644 index 0000000000000..98000f4eb81a7 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,4 @@ +FROM ubuntu:18.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates diff --git a/library/compiler-builtins/libm/ci/install.sh b/library/compiler-builtins/libm/ci/install.sh deleted file mode 100644 index af26e2d4c30e4..0000000000000 --- a/library/compiler-builtins/libm/ci/install.sh +++ /dev/null @@ -1,25 +0,0 @@ -set -euxo pipefail - -main() { - if [ $TARGET = cargo-fmt ]; then - rustup component add rustfmt-preview - return - fi - - if ! hash cross >/dev/null 2>&1; then - cargo install cross - fi - - rustup target add x86_64-unknown-linux-musl - - if [ $TARGET != x86_64-unknown-linux-gnu ]; then - rustup target add $TARGET - fi - - mkdir -p ~/.local/bin - curl -L https://github.com/japaric/qemu-bin/raw/master/14.04/qemu-arm-2.12.0 > ~/.local/bin/qemu-arm - chmod +x ~/.local/bin/qemu-arm - qemu-arm --version -} - -main diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh new file mode 100755 index 0000000000000..6b3066e53e66c --- /dev/null +++ b/library/compiler-builtins/libm/ci/run-docker.sh @@ -0,0 +1,36 @@ +# Small script to run tests for a target (or all targets) inside all the +# respective docker images. + +set -ex + +run() { + local target=$1 + + echo $target + + # This directory needs to exist before calling docker, otherwise docker will create it but it + # will be owned by root + mkdir -p target + + docker build -t $target ci/docker/$target + docker run \ + --rm \ + --user $(id -u):$(id -g) \ + -e CARGO_HOME=/cargo \ + -e CARGO_TARGET_DIR=/target \ + -v $HOME/.cargo:/cargo \ + -v `pwd`/target:/target \ + -v `pwd`:/checkout:ro \ + -v `rustc --print sysroot`:/rust:ro \ + -w /checkout \ + $target \ + sh -c "HOME=/tmp PATH=\$PATH:/rust/bin ci/run.sh $target" +} + +if [ -z "$1" ]; then + for d in `ls ci/docker/`; do + run $d + done +else + run $1 +fi diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh new file mode 100755 index 0000000000000..fabfd0ecb9693 --- /dev/null +++ b/library/compiler-builtins/libm/ci/run.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +set -ex +TARGET=$1 + +cargo build --target $TARGET +cargo test --target $TARGET +cargo build --target $TARGET --release +cargo test --target $TARGET --release + +cargo test --features 'checked musl-reference-tests' --target $TARGET +cargo test --features 'checked musl-reference-tests' --target $TARGET --release diff --git a/library/compiler-builtins/libm/ci/script.sh b/library/compiler-builtins/libm/ci/script.sh deleted file mode 100644 index c3b6faa6cac67..0000000000000 --- a/library/compiler-builtins/libm/ci/script.sh +++ /dev/null @@ -1,37 +0,0 @@ -set -euxo pipefail - -main() { - if [ $TARGET = cargo-fmt ]; then - cargo fmt -- --check - return - fi - - # quick check - cargo check - - # check that we can source import libm into compiler-builtins - cargo check --package cb - - # generate tests - cargo run -p input-generator --target x86_64-unknown-linux-musl - cargo run -p musl-generator --target x86_64-unknown-linux-musl - cargo run -p newlib-generator - - # test that the functions don't contain invocations of `panic!` - case $TARGET in - armv7-unknown-linux-gnueabihf) - cross build --release --target $TARGET --example no-panic - ;; - esac - - # run unit tests - cross test --lib --features checked --target $TARGET --release - - # run generated tests - cross test --tests --features checked --target $TARGET --release - - # TODO need to fix overflow issues (cf. issue #4) - # cross test --target $TARGET -} - -main diff --git a/library/compiler-builtins/libm/examples/no-panic.rs b/library/compiler-builtins/libm/examples/no-panic.rs deleted file mode 100644 index fb79f99afa122..0000000000000 --- a/library/compiler-builtins/libm/examples/no-panic.rs +++ /dev/null @@ -1,115 +0,0 @@ -#![feature(lang_items)] -#![feature(panic_implementation)] -#![no_main] -#![no_std] - -extern crate libm; - -use core::panic::PanicInfo; -use core::ptr; - -macro_rules! force_eval { - ($e:expr) => { - unsafe { - core::ptr::read_volatile(&$e); - } - }; -} - -#[no_mangle] -pub fn main() { - force_eval!(libm::acos(random())); - force_eval!(libm::acosf(random())); - force_eval!(libm::asin(random())); - force_eval!(libm::asinf(random())); - force_eval!(libm::atan(random())); - force_eval!(libm::atan2(random(), random())); - force_eval!(libm::atan2f(random(), random())); - force_eval!(libm::atanf(random())); - force_eval!(libm::cbrt(random())); - force_eval!(libm::cbrtf(random())); - force_eval!(libm::ceil(random())); - force_eval!(libm::ceilf(random())); - force_eval!(libm::cos(random())); - force_eval!(libm::cosf(random())); - force_eval!(libm::cosh(random())); - force_eval!(libm::coshf(random())); - force_eval!(libm::exp(random())); - force_eval!(libm::exp2(random())); - force_eval!(libm::exp2f(random())); - force_eval!(libm::expf(random())); - force_eval!(libm::expm1(random())); - force_eval!(libm::expm1f(random())); - force_eval!(libm::fabs(random())); - force_eval!(libm::fabsf(random())); - force_eval!(libm::fdim(random(), random())); - force_eval!(libm::fdimf(random(), random())); - force_eval!(libm::floor(random())); - force_eval!(libm::floorf(random())); - force_eval!(libm::fma(random(), random(), random())); - force_eval!(libm::fmaf(random(), random(), random())); - force_eval!(libm::fmod(random(), random())); - force_eval!(libm::fmodf(random(), random())); - force_eval!(libm::hypot(random(), random())); - force_eval!(libm::hypotf(random(), random())); - force_eval!(libm::log(random())); - force_eval!(libm::log2(random())); - force_eval!(libm::log10(random())); - force_eval!(libm::log10f(random())); - force_eval!(libm::log1p(random())); - force_eval!(libm::log1pf(random())); - force_eval!(libm::log2f(random())); - force_eval!(libm::logf(random())); - force_eval!(libm::pow(random(), random())); - force_eval!(libm::powf(random(), random())); - force_eval!(libm::round(random())); - force_eval!(libm::roundf(random())); - force_eval!(libm::scalbn(random(), random())); - force_eval!(libm::scalbnf(random(), random())); - force_eval!(libm::sin(random())); - force_eval!(libm::sinf(random())); - force_eval!(libm::sinh(random())); - force_eval!(libm::sinhf(random())); - force_eval!(libm::sqrt(random())); - force_eval!(libm::sqrtf(random())); - force_eval!(libm::tan(random())); - force_eval!(libm::tanf(random())); - force_eval!(libm::tanh(random())); - force_eval!(libm::tanhf(random())); - force_eval!(libm::trunc(random())); - force_eval!(libm::truncf(random())); -} - -fn random() -> T -where - T: Copy, -{ - unsafe { - static mut X: usize = 0; - X += 8; - ptr::read_volatile(X as *const T) - } -} - -#[panic_implementation] -#[no_mangle] -pub fn panic(_info: &PanicInfo) -> ! { - // loop {} - extern "C" { - fn thou_shalt_not_panic() -> !; - } - - unsafe { thou_shalt_not_panic() } -} - -#[link(name = "c")] -extern "C" {} - -#[lang = "eh_personality"] -fn eh() {} - -#[no_mangle] -pub extern "C" fn __aeabi_unwind_cpp_pr0() {} - -#[no_mangle] -pub extern "C" fn __aeabi_unwind_cpp_pr1() {} diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index e705dde0f917b..5e94541ab1a3c 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -626,5 +626,5 @@ mod private { impl Sealed for f64 {} } -#[cfg(test)] -include!(concat!(env!("OUT_DIR"), "/tests.rs")); +#[cfg(all(test, feature = "musl-reference-tests"))] +include!(concat!(env!("OUT_DIR"), "/musl-tests.rs")); diff --git a/library/compiler-builtins/libm/src/math/acos.rs b/library/compiler-builtins/libm/src/math/acos.rs index 276e361f3d5c2..a0d1450e3a859 100644 --- a/library/compiler-builtins/libm/src/math/acos.rs +++ b/library/compiler-builtins/libm/src/math/acos.rs @@ -56,6 +56,7 @@ fn r(z: f64) -> f64 { } #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn acos(x: f64) -> f64 { let x1p_120f = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ -120 let z: f64; diff --git a/library/compiler-builtins/libm/src/math/acosf.rs b/library/compiler-builtins/libm/src/math/acosf.rs index b12ed531ae218..d635ee8a6c027 100644 --- a/library/compiler-builtins/libm/src/math/acosf.rs +++ b/library/compiler-builtins/libm/src/math/acosf.rs @@ -30,6 +30,7 @@ fn r(z: f32) -> f32 { } #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn acosf(x: f32) -> f32 { let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) diff --git a/library/compiler-builtins/libm/src/math/asin.rs b/library/compiler-builtins/libm/src/math/asin.rs index a0bb4918c5a4c..8553008372663 100644 --- a/library/compiler-builtins/libm/src/math/asin.rs +++ b/library/compiler-builtins/libm/src/math/asin.rs @@ -63,6 +63,7 @@ fn comp_r(z: f64) -> f64 { } #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn asin(mut x: f64) -> f64 { let z: f64; let r: f64; diff --git a/library/compiler-builtins/libm/src/math/asinf.rs b/library/compiler-builtins/libm/src/math/asinf.rs index 79c85d81d0068..979f1a6548fab 100644 --- a/library/compiler-builtins/libm/src/math/asinf.rs +++ b/library/compiler-builtins/libm/src/math/asinf.rs @@ -32,6 +32,7 @@ fn r(z: f32) -> f32 { } #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn asinf(mut x: f32) -> f32 { let x1p_120 = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ (-120) diff --git a/library/compiler-builtins/libm/src/math/atan.rs b/library/compiler-builtins/libm/src/math/atan.rs index cf6a62a545917..a9cdc29333d09 100644 --- a/library/compiler-builtins/libm/src/math/atan.rs +++ b/library/compiler-builtins/libm/src/math/atan.rs @@ -61,6 +61,7 @@ const AT: [f64; 11] = [ ]; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atan(x: f64) -> f64 { let mut x = x; let mut ix = (x.to_bits() >> 32) as u32; diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs index a91ddd84d0d72..a702ec39fe693 100644 --- a/library/compiler-builtins/libm/src/math/atan2.rs +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -44,6 +44,7 @@ const PI: f64 = 3.1415926535897931160E+00; /* 0x400921FB, 0x54442D18 */ const PI_LO: f64 = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atan2(y: f64, x: f64) -> f64 { if x.is_nan() || y.is_nan() { return x + y; diff --git a/library/compiler-builtins/libm/src/math/atan2f.rs b/library/compiler-builtins/libm/src/math/atan2f.rs index 211a992a06562..94e3c77186769 100644 --- a/library/compiler-builtins/libm/src/math/atan2f.rs +++ b/library/compiler-builtins/libm/src/math/atan2f.rs @@ -20,6 +20,7 @@ const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ const PI_LO: f32 = -8.7422776573e-08; /* 0xb3bbbd2e */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atan2f(y: f32, x: f32) -> f32 { if x.is_nan() || y.is_nan() { return x + y; diff --git a/library/compiler-builtins/libm/src/math/atanf.rs b/library/compiler-builtins/libm/src/math/atanf.rs index b05152e2bc3e7..5d9024022b98d 100644 --- a/library/compiler-builtins/libm/src/math/atanf.rs +++ b/library/compiler-builtins/libm/src/math/atanf.rs @@ -38,6 +38,7 @@ const A_T: [f32; 5] = [ ]; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atanf(mut x: f32) -> f32 { let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) diff --git a/library/compiler-builtins/libm/src/math/cbrt.rs b/library/compiler-builtins/libm/src/math/cbrt.rs index 8c37f0b266b8c..ab11c497e12d9 100644 --- a/library/compiler-builtins/libm/src/math/cbrt.rs +++ b/library/compiler-builtins/libm/src/math/cbrt.rs @@ -28,6 +28,7 @@ const P3: f64 = -0.758397934778766047437; /* 0xbfe844cb, 0xbee751d9 */ const P4: f64 = 0.145996192886612446982; /* 0x3fc2b000, 0xd4e4edd7 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cbrt(x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 diff --git a/library/compiler-builtins/libm/src/math/cbrtf.rs b/library/compiler-builtins/libm/src/math/cbrtf.rs index 878372eefbf83..19215b8587bdd 100644 --- a/library/compiler-builtins/libm/src/math/cbrtf.rs +++ b/library/compiler-builtins/libm/src/math/cbrtf.rs @@ -23,6 +23,7 @@ const B1: u32 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */ const B2: u32 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cbrtf(x: f32) -> f32 { let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index 5dbfa6a2c0ad4..c2b11e4e74dc1 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -3,6 +3,7 @@ use core::f64; const TOINT: f64 = 1. / f64::EPSILON; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ceil(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f64.ceil` native instruction, so we can leverage this for both code size diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index c8cd4b5aa5b5c..5eb6a35a6ec63 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -1,6 +1,7 @@ use core::f32; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ceilf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f32.ceil` native instruction, so we can leverage this for both code size diff --git a/library/compiler-builtins/libm/src/math/cos.rs b/library/compiler-builtins/libm/src/math/cos.rs index df16b5c36a840..fe5a89919b2bb 100644 --- a/library/compiler-builtins/libm/src/math/cos.rs +++ b/library/compiler-builtins/libm/src/math/cos.rs @@ -42,6 +42,7 @@ use super::{k_cos, k_sin, rem_pio2}; // TRIG(x) returns trig(x) nearly rounded // #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cos(x: f64) -> f64 { let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; diff --git a/library/compiler-builtins/libm/src/math/cosf.rs b/library/compiler-builtins/libm/src/math/cosf.rs index 23faacdc26cf7..615746a31f7f3 100644 --- a/library/compiler-builtins/libm/src/math/cosf.rs +++ b/library/compiler-builtins/libm/src/math/cosf.rs @@ -25,6 +25,7 @@ const C3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ const C4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cosf(x: f32) -> f32 { let x64 = x as f64; diff --git a/library/compiler-builtins/libm/src/math/cosh.rs b/library/compiler-builtins/libm/src/math/cosh.rs index f3f7fbfbeb16f..b6ba338b55f2e 100644 --- a/library/compiler-builtins/libm/src/math/cosh.rs +++ b/library/compiler-builtins/libm/src/math/cosh.rs @@ -3,6 +3,7 @@ use super::expm1; use super::k_expo2; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cosh(mut x: f64) -> f64 { /* |x| */ let mut ix = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/coshf.rs b/library/compiler-builtins/libm/src/math/coshf.rs index bd468f5da712c..b37ee1f3271b5 100644 --- a/library/compiler-builtins/libm/src/math/coshf.rs +++ b/library/compiler-builtins/libm/src/math/coshf.rs @@ -3,6 +3,7 @@ use super::expm1f; use super::k_expo2f; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn coshf(mut x: f32) -> f32 { let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 diff --git a/library/compiler-builtins/libm/src/math/exp.rs b/library/compiler-builtins/libm/src/math/exp.rs index cd63b8fb3f159..c327731867965 100644 --- a/library/compiler-builtins/libm/src/math/exp.rs +++ b/library/compiler-builtins/libm/src/math/exp.rs @@ -78,6 +78,7 @@ const P4: f64 = -1.65339022054652515390e-06; /* 0xBEBBBD41, 0xC5D26BF1 */ const P5: f64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp(mut x: f64) -> f64 { let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 let x1p_149 = f64::from_bits(0x36a0000000000000); // 0x1p-149 === 2 ^ -149 diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs index 3952e93007e13..be6a003c6eeb6 100644 --- a/library/compiler-builtins/libm/src/math/exp2.rs +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -319,6 +319,7 @@ static TBL: [u64; TBLSIZE * 2] = [ // Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library // for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp2(mut x: f64) -> f64 { let redux = f64::from_bits(0x4338000000000000) / TBLSIZE as f64; let p1 = f64::from_bits(0x3fe62e42fefa39ef); diff --git a/library/compiler-builtins/libm/src/math/exp2f.rs b/library/compiler-builtins/libm/src/math/exp2f.rs index a3f6db8c5b365..32816104b5c61 100644 --- a/library/compiler-builtins/libm/src/math/exp2f.rs +++ b/library/compiler-builtins/libm/src/math/exp2f.rs @@ -70,6 +70,7 @@ static EXP2FT: [u64; TBLSIZE] = [ // Tang, P. Table-driven Implementation of the Exponential Function // in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989). #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp2f(mut x: f32) -> f32 { let redux = f32::from_bits(0x4b400000) / TBLSIZE as f32; let p1 = f32::from_bits(0x3f317218); diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs index 8ecc3b6abd61c..e33425665eb98 100644 --- a/library/compiler-builtins/libm/src/math/expf.rs +++ b/library/compiler-builtins/libm/src/math/expf.rs @@ -27,6 +27,7 @@ const P1: f32 = 1.6666625440e-1; /* 0xaaaa8f.0p-26 */ const P2: f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn expf(mut x: f32) -> f32 { let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */ diff --git a/library/compiler-builtins/libm/src/math/expm1.rs b/library/compiler-builtins/libm/src/math/expm1.rs index 9da064ee77362..42616399066c0 100644 --- a/library/compiler-builtins/libm/src/math/expm1.rs +++ b/library/compiler-builtins/libm/src/math/expm1.rs @@ -24,6 +24,7 @@ const Q4: f64 = 4.00821782732936239552e-06; /* 3ED0CFCA 86E65239 */ const Q5: f64 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn expm1(mut x: f64) -> f64 { let hi: f64; let lo: f64; diff --git a/library/compiler-builtins/libm/src/math/expm1f.rs b/library/compiler-builtins/libm/src/math/expm1f.rs index 8f581733acd69..4daa83c856543 100644 --- a/library/compiler-builtins/libm/src/math/expm1f.rs +++ b/library/compiler-builtins/libm/src/math/expm1f.rs @@ -26,6 +26,7 @@ const Q1: f32 = -3.3333212137e-2; /* -0x888868.0p-28 */ const Q2: f32 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn expm1f(mut x: f32) -> f32 { let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 diff --git a/library/compiler-builtins/libm/src/math/expo2.rs b/library/compiler-builtins/libm/src/math/expo2.rs index 39f9815c40471..b5369fbbe56e2 100644 --- a/library/compiler-builtins/libm/src/math/expo2.rs +++ b/library/compiler-builtins/libm/src/math/expo2.rs @@ -2,6 +2,7 @@ use super::{combine_words, exp}; /* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn expo2(x: f64) -> f64 { /* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */ const K: i32 = 2043; diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index 7c804653c9968..0824bd593586a 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -1,6 +1,7 @@ use core::u64; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fabs(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f64.abs` native instruction, so we can leverage this for both code size diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index 884c20f6c4103..859508f9b539f 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -1,4 +1,5 @@ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fabsf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f32.abs` native instruction, so we can leverage this for both code size diff --git a/library/compiler-builtins/libm/src/math/fdim.rs b/library/compiler-builtins/libm/src/math/fdim.rs index 1daae4ebc227d..32ae306e2efb2 100644 --- a/library/compiler-builtins/libm/src/math/fdim.rs +++ b/library/compiler-builtins/libm/src/math/fdim.rs @@ -1,6 +1,7 @@ use core::f64; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fdim(x: f64, y: f64) -> f64 { if x.is_nan() { x diff --git a/library/compiler-builtins/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/src/math/fdimf.rs index 953e0c8dfafcc..7db01932626fb 100644 --- a/library/compiler-builtins/libm/src/math/fdimf.rs +++ b/library/compiler-builtins/libm/src/math/fdimf.rs @@ -1,6 +1,7 @@ use core::f32; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fdimf(x: f32, y: f32) -> f32 { if x.is_nan() { x diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index b14a48d55bc7f..f5ac8006f0eb5 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -3,6 +3,7 @@ use core::f64; const TOINT: f64 = 1. / f64::EPSILON; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn floor(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f64.floor` native instruction, so we can leverage this for both code size diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index 71b5953df3e26..8699be0602693 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -1,6 +1,7 @@ use core::f32; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn floorf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f32.floor` native instruction, so we can leverage this for both code size diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 99a27164a81ec..38468ae755f61 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -49,6 +49,7 @@ fn mul(x: u64, y: u64) -> (u64, u64) { } #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fma(x: f64, y: f64, z: f64) -> f64 { let x1p63: f64 = f64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63 let x0_ffffff8p_63 = f64::from_bits(0x3bfffffff0000000); // 0x0.ffffff8p-63 diff --git a/library/compiler-builtins/libm/src/math/fmaf.rs b/library/compiler-builtins/libm/src/math/fmaf.rs index 25b04fc239667..9e5a55f44b648 100644 --- a/library/compiler-builtins/libm/src/math/fmaf.rs +++ b/library/compiler-builtins/libm/src/math/fmaf.rs @@ -41,6 +41,7 @@ use super::fenv::{ * rounding occurs. */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { let xy: f64; let mut result: f64; diff --git a/library/compiler-builtins/libm/src/math/fmod.rs b/library/compiler-builtins/libm/src/math/fmod.rs index 23f0c4846c4b3..ecc9b39a5c1ec 100644 --- a/library/compiler-builtins/libm/src/math/fmod.rs +++ b/library/compiler-builtins/libm/src/math/fmod.rs @@ -1,6 +1,7 @@ use core::u64; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmod(x: f64, y: f64) -> f64 { let mut uxi = x.to_bits(); let mut uyi = y.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs index d84cfeb01b831..98f51f455b882 100644 --- a/library/compiler-builtins/libm/src/math/fmodf.rs +++ b/library/compiler-builtins/libm/src/math/fmodf.rs @@ -2,6 +2,7 @@ use core::f32; use core::u32; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmodf(x: f32, y: f32) -> f32 { let mut uxi = x.to_bits(); let mut uyi = y.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/hypot.rs b/library/compiler-builtins/libm/src/math/hypot.rs index f011415fdc64f..dee9bbf424028 100644 --- a/library/compiler-builtins/libm/src/math/hypot.rs +++ b/library/compiler-builtins/libm/src/math/hypot.rs @@ -19,6 +19,7 @@ fn sq(x: f64) -> (f64, f64) { } #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn hypot(mut x: f64, mut y: f64) -> f64 { let x1p700 = f64::from_bits(0x6bb0000000000000); // 0x1p700 === 2 ^ 700 let x1p_700 = f64::from_bits(0x1430000000000000); // 0x1p-700 === 2 ^ -700 diff --git a/library/compiler-builtins/libm/src/math/hypotf.rs b/library/compiler-builtins/libm/src/math/hypotf.rs index d59710ada3956..4636b8f1d8b77 100644 --- a/library/compiler-builtins/libm/src/math/hypotf.rs +++ b/library/compiler-builtins/libm/src/math/hypotf.rs @@ -3,6 +3,7 @@ use core::f32; use super::sqrtf; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn hypotf(mut x: f32, mut y: f32) -> f32 { let x1p90 = f32::from_bits(0x6c800000); // 0x1p90f === 2 ^ 90 let x1p_90 = f32::from_bits(0x12800000); // 0x1p-90f === 2 ^ -90 diff --git a/library/compiler-builtins/libm/src/math/k_cos.rs b/library/compiler-builtins/libm/src/math/k_cos.rs index 693950d1d418e..8876fac2143cc 100644 --- a/library/compiler-builtins/libm/src/math/k_cos.rs +++ b/library/compiler-builtins/libm/src/math/k_cos.rs @@ -52,6 +52,7 @@ const C6: f64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ // under FreeBSD, so don't pessimize things by forcibly clipping // any extra precision in w. #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn k_cos(x: f64, y: f64) -> f64 { let z = x * x; let w = z * z; diff --git a/library/compiler-builtins/libm/src/math/k_cosf.rs b/library/compiler-builtins/libm/src/math/k_cosf.rs index 4aa10c0f08945..9b48e190ddd5a 100644 --- a/library/compiler-builtins/libm/src/math/k_cosf.rs +++ b/library/compiler-builtins/libm/src/math/k_cosf.rs @@ -21,6 +21,7 @@ const C2: f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ const C3: f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn k_cosf(x: f64) -> f32 { let z = x * x; let w = z * z; diff --git a/library/compiler-builtins/libm/src/math/k_expo2.rs b/library/compiler-builtins/libm/src/math/k_expo2.rs index e295c7a534629..0a9562eaeaad7 100644 --- a/library/compiler-builtins/libm/src/math/k_expo2.rs +++ b/library/compiler-builtins/libm/src/math/k_expo2.rs @@ -5,6 +5,7 @@ const K: i32 = 2043; /* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_expo2(x: f64) -> f64 { let k_ln2 = f64::from_bits(0x40962066151add8b); /* note that k is odd and scale*scale overflows */ diff --git a/library/compiler-builtins/libm/src/math/k_expo2f.rs b/library/compiler-builtins/libm/src/math/k_expo2f.rs index ec2a2c5e2b8ad..68a7a50325c1e 100644 --- a/library/compiler-builtins/libm/src/math/k_expo2f.rs +++ b/library/compiler-builtins/libm/src/math/k_expo2f.rs @@ -5,6 +5,7 @@ const K: i32 = 235; /* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn k_expo2f(x: f32) -> f32 { let k_ln2 = f32::from_bits(0x4322e3bc); /* note that k is odd and scale*scale overflows */ diff --git a/library/compiler-builtins/libm/src/math/k_sin.rs b/library/compiler-builtins/libm/src/math/k_sin.rs index 3e07c3594475e..15718c4c92650 100644 --- a/library/compiler-builtins/libm/src/math/k_sin.rs +++ b/library/compiler-builtins/libm/src/math/k_sin.rs @@ -44,6 +44,7 @@ const S6: f64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ // then 3 2 // sin(x) = x + (S1*x + (x *(r-y/2)+y)) #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn k_sin(x: f64, y: f64, iy: i32) -> f64 { let z = x * x; let w = z * z; diff --git a/library/compiler-builtins/libm/src/math/k_sinf.rs b/library/compiler-builtins/libm/src/math/k_sinf.rs index 1c5f5f98a48f6..157fc104cc750 100644 --- a/library/compiler-builtins/libm/src/math/k_sinf.rs +++ b/library/compiler-builtins/libm/src/math/k_sinf.rs @@ -21,6 +21,7 @@ const S3: f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ const S4: f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn k_sinf(x: f64) -> f32 { let z = x * x; let w = z * z; diff --git a/library/compiler-builtins/libm/src/math/k_tan.rs b/library/compiler-builtins/libm/src/math/k_tan.rs index e9ba21499d015..684e937b93ca5 100644 --- a/library/compiler-builtins/libm/src/math/k_tan.rs +++ b/library/compiler-builtins/libm/src/math/k_tan.rs @@ -59,6 +59,7 @@ const PIO4: f64 = 7.85398163397448278999e-01; /* 3FE921FB, 54442D18 */ const PIO4_LO: f64 = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { let hx = (f64::to_bits(x) >> 32) as u32; let big = (hx & 0x7fffffff) >= 0x3FE59428; /* |x| >= 0.6744 */ diff --git a/library/compiler-builtins/libm/src/math/k_tanf.rs b/library/compiler-builtins/libm/src/math/k_tanf.rs index b9ccf2570f35b..96a591007083d 100644 --- a/library/compiler-builtins/libm/src/math/k_tanf.rs +++ b/library/compiler-builtins/libm/src/math/k_tanf.rs @@ -20,6 +20,7 @@ const T: [f64; 6] = [ ]; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn k_tanf(x: f64, odd: bool) -> f32 { let z = x * x; /* diff --git a/library/compiler-builtins/libm/src/math/log.rs b/library/compiler-builtins/libm/src/math/log.rs index 48e9fa79a46fd..948065abf3b8a 100644 --- a/library/compiler-builtins/libm/src/math/log.rs +++ b/library/compiler-builtins/libm/src/math/log.rs @@ -71,6 +71,7 @@ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log(mut x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 diff --git a/library/compiler-builtins/libm/src/math/log10.rs b/library/compiler-builtins/libm/src/math/log10.rs index 7c7afefa34562..100618a0281df 100644 --- a/library/compiler-builtins/libm/src/math/log10.rs +++ b/library/compiler-builtins/libm/src/math/log10.rs @@ -32,6 +32,7 @@ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log10(mut x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 diff --git a/library/compiler-builtins/libm/src/math/log10f.rs b/library/compiler-builtins/libm/src/math/log10f.rs index 82b87c044b255..9cf89deb9576b 100644 --- a/library/compiler-builtins/libm/src/math/log10f.rs +++ b/library/compiler-builtins/libm/src/math/log10f.rs @@ -26,6 +26,7 @@ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log10f(mut x: f32) -> f32 { let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 diff --git a/library/compiler-builtins/libm/src/math/log1p.rs b/library/compiler-builtins/libm/src/math/log1p.rs index f42669deeaee7..fb35e90db14cf 100644 --- a/library/compiler-builtins/libm/src/math/log1p.rs +++ b/library/compiler-builtins/libm/src/math/log1p.rs @@ -66,6 +66,7 @@ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log1p(x: f64) -> f64 { let mut ui: u64 = x.to_bits(); let hfsq: f64; diff --git a/library/compiler-builtins/libm/src/math/log1pf.rs b/library/compiler-builtins/libm/src/math/log1pf.rs index e6e1c14c8c5f5..9fc399d956ee6 100644 --- a/library/compiler-builtins/libm/src/math/log1pf.rs +++ b/library/compiler-builtins/libm/src/math/log1pf.rs @@ -21,6 +21,7 @@ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log1pf(x: f32) -> f32 { let mut ui: u32 = x.to_bits(); let hfsq: f32; diff --git a/library/compiler-builtins/libm/src/math/log2.rs b/library/compiler-builtins/libm/src/math/log2.rs index 35eb9bf72b274..b513928ccb120 100644 --- a/library/compiler-builtins/libm/src/math/log2.rs +++ b/library/compiler-builtins/libm/src/math/log2.rs @@ -30,6 +30,7 @@ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log2(mut x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 diff --git a/library/compiler-builtins/libm/src/math/log2f.rs b/library/compiler-builtins/libm/src/math/log2f.rs index 8684b142f8be2..07a00dc3dae96 100644 --- a/library/compiler-builtins/libm/src/math/log2f.rs +++ b/library/compiler-builtins/libm/src/math/log2f.rs @@ -24,6 +24,7 @@ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log2f(mut x: f32) -> f32 { let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 diff --git a/library/compiler-builtins/libm/src/math/logf.rs b/library/compiler-builtins/libm/src/math/logf.rs index 09519104174b5..95195601c2d7c 100644 --- a/library/compiler-builtins/libm/src/math/logf.rs +++ b/library/compiler-builtins/libm/src/math/logf.rs @@ -22,6 +22,7 @@ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn logf(mut x: f32) -> f32 { let x1p25 = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 329b3955d8837..3b789dd9fb308 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -90,6 +90,7 @@ const IVLN2_H: f64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/l const IVLN2_L: f64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn pow(x: f64, y: f64) -> f64 { let t1: f64; let t2: f64; diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs index 8d0afe6693cff..5bc5c08e972ba 100644 --- a/library/compiler-builtins/libm/src/math/powf.rs +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -44,6 +44,7 @@ const IVLN2_H: f32 = 1.4426879883e+00; const IVLN2_L: f32 = 7.0526075433e-06; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn powf(x: f32, y: f32) -> f32 { let mut z: f32; let mut ax: f32; diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 5c1685877b67d..98d6b37beb5d9 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -43,6 +43,7 @@ const PIO2_3T: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ // // caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn rem_pio2(x: f64) -> (i32, f64, f64) { let x1p24 = f64::from_bits(0x4170000000000000); 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 4d9146af9d627..8bab485695efc 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -223,6 +223,7 @@ const PIO2: [f64; 8] = [ /// more accurately, = 0 mod 8 ). Thus the number of operations are /// independent of the exponent of the input. #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs index 5e7a7d43904d4..054c311841f23 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2f.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2f.rs @@ -32,6 +32,7 @@ const PIO2_1T: f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ /// use double precision for everything except passing x /// use __rem_pio2_large() for large x #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn rem_pio2f(x: f32) -> (i32, f64) { let x64 = x as f64; diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs index 1a6e754489c1c..9a9723cfbb658 100644 --- a/library/compiler-builtins/libm/src/math/round.rs +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -3,6 +3,7 @@ use core::f64; const TOINT: f64 = 1.0 / f64::EPSILON; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn round(mut x: f64) -> f64 { let (f, i) = (x, x.to_bits()); let e: u64 = i >> 52 & 0x7ff; diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs index 7dd79557a9d3b..839d9469a49ef 100644 --- a/library/compiler-builtins/libm/src/math/roundf.rs +++ b/library/compiler-builtins/libm/src/math/roundf.rs @@ -3,6 +3,7 @@ use core::f32; const TOINT: f32 = 1.0 / f32::EPSILON; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn roundf(mut x: f32) -> f32 { let i = x.to_bits(); let e: u32 = i >> 23 & 0xff; diff --git a/library/compiler-builtins/libm/src/math/scalbn.rs b/library/compiler-builtins/libm/src/math/scalbn.rs index ad81072ddc98c..2c4ab36608483 100644 --- a/library/compiler-builtins/libm/src/math/scalbn.rs +++ b/library/compiler-builtins/libm/src/math/scalbn.rs @@ -1,4 +1,5 @@ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn scalbn(x: f64, mut n: i32) -> f64 { let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 let x1p53 = f64::from_bits(0x4340000000000000); // 0x1p53 === 2 ^ 53 diff --git a/library/compiler-builtins/libm/src/math/scalbnf.rs b/library/compiler-builtins/libm/src/math/scalbnf.rs index 901497e5e51d7..4e9771175d29b 100644 --- a/library/compiler-builtins/libm/src/math/scalbnf.rs +++ b/library/compiler-builtins/libm/src/math/scalbnf.rs @@ -1,4 +1,5 @@ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn scalbnf(mut x: f32, mut n: i32) -> f32 { let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 diff --git a/library/compiler-builtins/libm/src/math/sin.rs b/library/compiler-builtins/libm/src/math/sin.rs index e749094e6681d..b7307441646fb 100644 --- a/library/compiler-builtins/libm/src/math/sin.rs +++ b/library/compiler-builtins/libm/src/math/sin.rs @@ -41,6 +41,7 @@ use super::{k_cos, k_sin, rem_pio2}; // Accuracy: // TRIG(x) returns trig(x) nearly rounded #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sin(x: f64) -> f64 { let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 diff --git a/library/compiler-builtins/libm/src/math/sinf.rs b/library/compiler-builtins/libm/src/math/sinf.rs index c9b02bcdc5138..b8fc8d6f4bec4 100644 --- a/library/compiler-builtins/libm/src/math/sinf.rs +++ b/library/compiler-builtins/libm/src/math/sinf.rs @@ -25,6 +25,7 @@ const S3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ const S4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sinf(x: f32) -> f32 { let x64 = x as f64; diff --git a/library/compiler-builtins/libm/src/math/sinh.rs b/library/compiler-builtins/libm/src/math/sinh.rs index 684e8e30984a1..25ff3daaccbb6 100644 --- a/library/compiler-builtins/libm/src/math/sinh.rs +++ b/library/compiler-builtins/libm/src/math/sinh.rs @@ -5,6 +5,7 @@ use super::{expm1, expo2}; // = x + x^3/6 + o(x^5) // #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sinh(x: f64) -> f64 { // union {double f; uint64_t i;} u = {.f = x}; // uint32_t w; diff --git a/library/compiler-builtins/libm/src/math/sinhf.rs b/library/compiler-builtins/libm/src/math/sinhf.rs index 90c4b9312819f..fd0b2bfc8943e 100644 --- a/library/compiler-builtins/libm/src/math/sinhf.rs +++ b/library/compiler-builtins/libm/src/math/sinhf.rs @@ -2,6 +2,7 @@ use super::expm1f; use super::k_expo2f; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sinhf(x: f32) -> f32 { let mut h = 0.5f32; let mut ix = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index b2387a26e750c..a05a521fb4b7b 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -81,6 +81,7 @@ use core::f64; const TINY: f64 = 1.0e-300; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrt(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f64.sqrt` native instruction, so we can leverage this for both code size diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 33cafbcbda36c..b9365c6171615 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -16,6 +16,7 @@ const TINY: f32 = 1.0e-30; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrtf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f32.sqrt` native instruction, so we can leverage this for both code size diff --git a/library/compiler-builtins/libm/src/math/tan.rs b/library/compiler-builtins/libm/src/math/tan.rs index 5a5f178a51ccd..e5c94cbb1565d 100644 --- a/library/compiler-builtins/libm/src/math/tan.rs +++ b/library/compiler-builtins/libm/src/math/tan.rs @@ -40,6 +40,7 @@ use super::{k_tan, rem_pio2}; // Accuracy: // TRIG(x) returns trig(x) nearly rounded #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tan(x: f64) -> f64 { let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 diff --git a/library/compiler-builtins/libm/src/math/tanf.rs b/library/compiler-builtins/libm/src/math/tanf.rs index 15a462d4e19f9..c286cdeb419ec 100644 --- a/library/compiler-builtins/libm/src/math/tanf.rs +++ b/library/compiler-builtins/libm/src/math/tanf.rs @@ -25,6 +25,7 @@ const T3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ const T4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tanf(x: f32) -> f32 { let x64 = x as f64; diff --git a/library/compiler-builtins/libm/src/math/tanh.rs b/library/compiler-builtins/libm/src/math/tanh.rs index 1c3dd0be438ef..75d695cf7e9d5 100644 --- a/library/compiler-builtins/libm/src/math/tanh.rs +++ b/library/compiler-builtins/libm/src/math/tanh.rs @@ -5,6 +5,7 @@ use super::expm1; * = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2) */ #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tanh(mut x: f64) -> f64 { let mut uf: f64 = x; let mut ui: u64 = f64::to_bits(uf); diff --git a/library/compiler-builtins/libm/src/math/tanhf.rs b/library/compiler-builtins/libm/src/math/tanhf.rs index 98a1b60c29be2..ac4657b5abdbc 100644 --- a/library/compiler-builtins/libm/src/math/tanhf.rs +++ b/library/compiler-builtins/libm/src/math/tanhf.rs @@ -1,6 +1,7 @@ use super::expm1f; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tanhf(mut x: f32) -> f32 { /* x = |x| */ let mut ix = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs index 8eecfcf538e5e..1ee46fc7dae61 100644 --- a/library/compiler-builtins/libm/src/math/trunc.rs +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -1,6 +1,7 @@ use core::f64; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn trunc(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f64.trunc` native instruction, so we can leverage this for both code size diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs index 0d74fea9c9ee9..f93383269057d 100644 --- a/library/compiler-builtins/libm/src/math/truncf.rs +++ b/library/compiler-builtins/libm/src/math/truncf.rs @@ -1,6 +1,7 @@ use core::f32; #[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn truncf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f32.trunc` native instruction, so we can leverage this for both code size From 0656dec45610f13c8b56c30f89f0987a1954622c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 11:38:26 -0700 Subject: [PATCH 0687/4206] Delete stray test --- library/compiler-builtins/libm/src/math/acosf.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/acosf.rs b/library/compiler-builtins/libm/src/math/acosf.rs index d635ee8a6c027..a6061ae8027b4 100644 --- a/library/compiler-builtins/libm/src/math/acosf.rs +++ b/library/compiler-builtins/libm/src/math/acosf.rs @@ -74,17 +74,3 @@ pub fn acosf(x: f32) -> f32 { w = r(z) * s + c; 2. * (df + w) } - -#[cfg(test)] -mod tests { - #[test] - fn acosf() { - extern { - fn acosf(x: f32) -> f32; - } - unsafe { - crate::_eqf(super::acosf(1.0), acosf(1.0)).unwrap(); - } - } - // shared::f32!("musl", acosf); -} From 9cf8475f2f5970f21086b40116d266b746f11c8b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 11:40:01 -0700 Subject: [PATCH 0688/4206] Fix azure config --- library/compiler-builtins/libm/azure-pipelines.yml | 5 ----- library/compiler-builtins/libm/ci/azure-test-all.yml | 4 ---- 2 files changed, 9 deletions(-) delete mode 100644 library/compiler-builtins/libm/ci/azure-test-all.yml diff --git a/library/compiler-builtins/libm/azure-pipelines.yml b/library/compiler-builtins/libm/azure-pipelines.yml index 82a74452a0f4c..9f4e3672d2850 100644 --- a/library/compiler-builtins/libm/azure-pipelines.yml +++ b/library/compiler-builtins/libm/azure-pipelines.yml @@ -7,10 +7,7 @@ jobs: vmImage: ubuntu-16.04 steps: - template: ci/azure-install-rust.yml - env: - TOOLCHAIN: nightly - bash: rustup target add $TARGET - - template: ci/azure-install-rust.yml - bash: cargo generate-lockfile && ./ci/run-docker.sh $TARGET strategy: matrix: @@ -44,8 +41,6 @@ jobs: vmImage: ubuntu-16.04 steps: - template: ci/azure-install-rust.yml - env: - TOOLCHAIN: nightly - script: rustup target add wasm32-unknown-unknown displayName: "Install rust wasm target" - script: cargo build --target wasm32-unknown-unknown diff --git a/library/compiler-builtins/libm/ci/azure-test-all.yml b/library/compiler-builtins/libm/ci/azure-test-all.yml deleted file mode 100644 index 36831bd540182..0000000000000 --- a/library/compiler-builtins/libm/ci/azure-test-all.yml +++ /dev/null @@ -1,4 +0,0 @@ -steps: - - template: azure-install-rust.yml - - - bash: cargo generate-lockfile && ./ci/run-docker.sh $TARGET From 47a543171c1ed4c55b6744cff9a65bbcdcf19d95 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 11:44:58 -0700 Subject: [PATCH 0689/4206] Run rustfmt --- library/compiler-builtins/libm/build.rs | 28 +++++++++---------- .../compiler-builtins/libm/src/math/atan.rs | 3 +- .../compiler-builtins/libm/src/math/expf.rs | 1 - .../compiler-builtins/libm/src/math/fma.rs | 8 +++--- .../compiler-builtins/libm/src/math/pow.rs | 2 +- .../compiler-builtins/libm/src/math/powf.rs | 2 +- .../libm/src/math/rem_pio2.rs | 1 - .../compiler-builtins/libm/src/math/scalbn.rs | 2 +- 8 files changed, 23 insertions(+), 24 deletions(-) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 41dc920e9f7d6..23e1178e36075 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -267,22 +267,17 @@ mod musl_reference_tests { .status() .unwrap(); assert!(status.success()); - let output = Command::new("./gen") - .current_dir(&dst) - .output() - .unwrap(); + let output = Command::new("./gen").current_dir(&dst).output().unwrap(); assert!(output.status.success()); assert!(output.stderr.is_empty()); // Map all the output bytes back to an `i64` and then shove it all into // the expected results. - let mut results = - output.stdout.chunks_exact(8) - .map(|buf| { - let mut exact = [0; 8]; - exact.copy_from_slice(buf); - i64::from_le_bytes(exact) - }); + let mut results = output.stdout.chunks_exact(8).map(|buf| { + let mut exact = [0; 8]; + exact.copy_from_slice(buf); + i64::from_le_bytes(exact) + }); for test in functions.iter_mut().flat_map(|f| f.tests.iter_mut()) { test.output = results.next().unwrap(); @@ -301,7 +296,10 @@ mod musl_reference_tests { src.push_str("fn "); src.push_str(&function.name); src.push_str("_matches_musl() {"); - src.push_str(&format!("static TESTS: &[([i64; {}], i64)]", function.args.len())); + src.push_str(&format!( + "static TESTS: &[([i64; {}], i64)]", + function.args.len() + )); src.push_str(" = &["); for test in function.tests.iter() { src.push_str("(["); @@ -336,9 +334,11 @@ mod musl_reference_tests { Ty::Bool => unreachable!(), }); - src.push_str(r#" + src.push_str( + r#" panic!("INPUT: {:?} EXPECTED: {:?} ACTUAL {:?}", test, expected, output); - "#); + "#, + ); src.push_str("}"); src.push_str("}"); diff --git a/library/compiler-builtins/libm/src/math/atan.rs b/library/compiler-builtins/libm/src/math/atan.rs index a9cdc29333d09..ad1d57c1fe79e 100644 --- a/library/compiler-builtins/libm/src/math/atan.rs +++ b/library/compiler-builtins/libm/src/math/atan.rs @@ -148,7 +148,8 @@ mod tests { (-3.0_f64.sqrt() / 3.0, -f64::consts::FRAC_PI_6), (-1.0, -f64::consts::FRAC_PI_4), (-3.0_f64.sqrt(), -f64::consts::FRAC_PI_3), - ].iter() + ] + .iter() { assert!( (atan(*input) - answer) / answer < 1e-5, diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs index e33425665eb98..baade2552e12a 100644 --- a/library/compiler-builtins/libm/src/math/expf.rs +++ b/library/compiler-builtins/libm/src/math/expf.rs @@ -31,7 +31,6 @@ const P2: f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ pub fn expf(mut x: f32) -> f32 { let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */ - let mut hx = x.to_bits(); let sign = (hx >> 31) as i32; /* sign bit of x */ let signb: bool = sign != 0; diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 38468ae755f61..acf99a5d4e233 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -166,13 +166,13 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { } if r == c { /* min normal after rounding, underflow depends - on arch behaviour which can be imitated by - a double to float conversion */ + on arch behaviour which can be imitated by + a double to float conversion */ let fltmin: f32 = (x0_ffffff8p_63 * f32::MIN_POSITIVE as f64 * r) as f32; return f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * fltmin as f64; } /* one bit is lost when scaled, add another top bit to - only round once at conversion if it is inexact */ + only round once at conversion if it is inexact */ if (rhi << 53) != 0 { i = (rhi >> 1 | (rhi & 1) | 1 << 62) as i64; if sign != 0 { @@ -182,7 +182,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { r = 2. * r - c; /* remove top bit */ /* raise underflow portably, such that it - cannot be optimized away */ + cannot be optimized away */ { let tiny: f64 = f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * r; r += (tiny * tiny) * (r - r); diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 3b789dd9fb308..b5b0407efa19a 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -262,7 +262,7 @@ pub fn pow(x: f64, y: f64) -> f64 { } /* now |1-x| is TINY <= 2**-20, suffice to compute - log(x) by x-x^2/2+x^3/3-x^4/4 */ + log(x) by x-x^2/2+x^3/3-x^4/4 */ let t: f64 = ax - 1.0; /* t has 20 trailing zeros */ let w: f64 = (t * t) * (0.5 - t * (0.3333333333333333333333 - t * 0.25)); let u: f64 = IVLN2_H * t; /* ivln2_h has 21 sig. bits */ diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs index 5bc5c08e972ba..0a26573a3d10f 100644 --- a/library/compiler-builtins/libm/src/math/powf.rs +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -198,7 +198,7 @@ pub fn powf(x: f32, y: f32) -> f32 { } /* now |1-x| is TINY <= 2**-20, suffice to compute - log(x) by x-x^2/2+x^3/3-x^4/4 */ + log(x) by x-x^2/2+x^3/3-x^4/4 */ t = ax - 1.; /* t has 20 trailing zeros */ w = (t * t) * (0.5 - t * (0.333333333333 - t * 0.25)); u = IVLN2_H * t; /* IVLN2_H has 16 sig. bits */ diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 98d6b37beb5d9..82faf5da97a66 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -10,7 +10,6 @@ // ==================================================== // // Optimized by Bruce D. Evans. */ - use super::rem_pio2_large; // #if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 diff --git a/library/compiler-builtins/libm/src/math/scalbn.rs b/library/compiler-builtins/libm/src/math/scalbn.rs index 2c4ab36608483..d8c8409ac10c6 100644 --- a/library/compiler-builtins/libm/src/math/scalbn.rs +++ b/library/compiler-builtins/libm/src/math/scalbn.rs @@ -19,7 +19,7 @@ pub fn scalbn(x: f64, mut n: i32) -> f64 { } } else if n < -1022 { /* make sure final n < -53 to avoid double - rounding in the subnormal range */ + rounding in the subnormal range */ y *= x1p_1022 * x1p53; n += 1022 - 53; if n < -1022 { From c4468281d48438de363314270f023d7d34e52421 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 11:47:46 -0700 Subject: [PATCH 0690/4206] More azure config fixes --- library/compiler-builtins/libm/README.md | 2 ++ library/compiler-builtins/libm/azure-pipelines.yml | 9 +++++++++ library/compiler-builtins/libm/ci/run-docker.sh | 3 ++- library/compiler-builtins/libm/ci/run.sh | 6 +++--- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 24b816c351b8a..568a049f0c58b 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -1,5 +1,7 @@ # `libm` +[![Build Status](https://dev.azure.com/rust-lang/libm/_apis/build/status/rust-lang-nursery.libm?branchName=master)](https://dev.azure.com/rust-lang/libm/_build/latest?definitionId=7&branchName=master) + A port of [MUSL]'s libm to Rust. [MUSL]: https://www.musl-libc.org/ diff --git a/library/compiler-builtins/libm/azure-pipelines.yml b/library/compiler-builtins/libm/azure-pipelines.yml index 9f4e3672d2850..d8068e023b4ca 100644 --- a/library/compiler-builtins/libm/azure-pipelines.yml +++ b/library/compiler-builtins/libm/azure-pipelines.yml @@ -8,7 +8,11 @@ jobs: steps: - template: ci/azure-install-rust.yml - bash: rustup target add $TARGET + displayName: "add cross target" + - bash: rustup target add x86_64-unknown-linux-musl + displayName: "add musl target" - bash: cargo generate-lockfile && ./ci/run-docker.sh $TARGET + displayName: "run tests" strategy: matrix: aarch64: @@ -47,6 +51,8 @@ jobs: displayName: "Build for wasm" - script: cargo build --target wasm32-unknown-unknown --no-default-features displayName: "Build for wasm (no default features)" + variables: + TOOLCHAIN: nightly - job: rustfmt pool: @@ -54,7 +60,9 @@ jobs: steps: - template: ci/azure-install-rust.yml - bash: rustup component add rustfmt + displayName: "install rustfmt" - bash: cargo fmt --all -- --check + displayName: "check formatting" - job: compiler_builtins_works pool: @@ -62,3 +70,4 @@ jobs: steps: - template: ci/azure-install-rust.yml - bash: cargo build -p cb + displayName: "Check compiler-builtins still probably builds" diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh index 6b3066e53e66c..95bd3db4836ec 100755 --- a/library/compiler-builtins/libm/ci/run-docker.sh +++ b/library/compiler-builtins/libm/ci/run-docker.sh @@ -22,9 +22,10 @@ run() { -v `pwd`/target:/target \ -v `pwd`:/checkout:ro \ -v `rustc --print sysroot`:/rust:ro \ + --init \ -w /checkout \ $target \ - sh -c "HOME=/tmp PATH=\$PATH:/rust/bin ci/run.sh $target" + sh -c "HOME=/tmp PATH=\$PATH:/rust/bin exec ci/run.sh $target" } if [ -z "$1" ]; then diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index fabfd0ecb9693..d288113003993 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -3,10 +3,10 @@ set -ex TARGET=$1 -cargo build --target $TARGET cargo test --target $TARGET -cargo build --target $TARGET --release cargo test --target $TARGET --release -cargo test --features 'checked musl-reference-tests' --target $TARGET +# FIXME(#4) overflow checks in non-release currently cause issues +#cargo test --features 'checked musl-reference-tests' --target $TARGET + cargo test --features 'checked musl-reference-tests' --target $TARGET --release From 272f92def5be4051303711684599800b9466e462 Mon Sep 17 00:00:00 2001 From: Rahul Butani Date: Mon, 23 Jul 2018 01:13:23 -0500 Subject: [PATCH 0691/4206] Add some tests for pow These probably aren't comprehensive but they cover all the edge cases identified in the original musl source. --- .../compiler-builtins/libm/src/math/pow.rs | 189 ++++++++++++++++++ 1 file changed, 189 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index b5b0407efa19a..288e403c688b9 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -408,3 +408,192 @@ pub fn pow(x: f64, y: f64) -> f64 { return s * z; } + +/// Special cases: + +/// 20. (anything) ** 1 is (anything) +/// 21. (anything) ** -1 is 1/(anything) +/// 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) +/// 23. (-anything except 0 and inf) ** (non-integer) is NAN + +#[cfg(test)] +mod tests { + // #[macro_use] + extern crate std; + + use self::std::f64::consts::{E, PI}; + use self::std::f64::{EPSILON, INFINITY, MAX, MIN, MIN_POSITIVE, NAN, NEG_INFINITY}; + use super::pow; + + // const TESTCASES: &[f64] = &[1.0, 0.0, PI, -PI, E, -E, MIN, MAX, MIN_POSITIVE, NAN, INFINITY, NEG_INFINITY]; + + const POS_ZERO: &[f64] = &[0.0]; + const NEG_ZERO: &[f64] = &[-0.0]; + const POS_ONE: &[f64] = &[1.0]; + const NEG_ONE: &[f64] = &[-1.0]; + const POS_FLOATS: &[f64] = &[E, PI, MAX]; + const NEG_FLOATS: &[f64] = &[-E, -PI, MIN]; + const POS_SMALL_FLOATS: &[f64] = &[(1.0 / 2.0), MIN_POSITIVE, EPSILON]; + const NEG_SMALL_FLOATS: &[f64] = &[-(1.0 / 2.0), -MIN_POSITIVE, -EPSILON]; + const POS_EVENS: &[f64] = &[2.0, 6.0, 8.0, 10.0, 22.0, 100.0]; + const NEG_EVENS: &[f64] = &[-8.0, -2.0]; + const POS_ODDS: &[f64] = &[3.0, 7.0]; + const NEG_ODDS: &[f64] = &[-7.0, -3.0]; + const NANS: &[f64] = &[NAN]; + // const EDGES: &[f64] = &[MIN, MAX, MIN_POSITIVE, EPSILON]; + const POS_INF: &[f64] = &[INFINITY]; + const NEG_INF: &[f64] = &[NEG_INFINITY]; + + const ALL: &[&[f64]] = &[ + POS_ZERO, NEG_ZERO, NANS, NEG_SMALL_FLOATS, POS_SMALL_FLOATS, NEG_FLOATS, POS_FLOATS, NEG_EVENS, POS_EVENS, NEG_ODDS, POS_ODDS, + NEG_INF, POS_INF, NEG_ONE, POS_ONE, + ]; + const POS: &[&[f64]] = &[POS_ZERO, POS_ODDS, POS_ONE, POS_FLOATS, POS_EVENS, POS_INF]; + const NEG: &[&[f64]] = &[NEG_ZERO, NEG_ODDS, NEG_ONE, NEG_FLOATS, NEG_EVENS, NEG_INF]; + + fn pow_test(base: f64, exponent: f64, expected: f64) { + let res = pow(base, exponent); + assert!(if expected.is_nan() {res.is_nan()} else {pow(base, exponent) == expected}, + "{} ** {} was {} instead of {}", base, exponent, res, expected); + } + + fn test_sets_as_base(sets: &[&[f64]], exponent: f64, expected: f64) { + sets.iter() + .for_each(|s| s.iter().for_each(|val| pow_test(*val, exponent, expected))); + } + + fn test_sets_as_exponent(base: f64, sets: &[&[f64]], expected: f64) { + sets.iter() + .for_each(|s| s.iter().for_each(|val| pow_test(base, *val, expected))); + } + + fn test_sets(sets: &[&[f64]], computed: &Fn(f64) -> f64, expected: &Fn(f64) -> f64) { + sets.iter() + .for_each(|s| s.iter().for_each(|val| { + let exp = expected(*val); + let res = computed(*val); + + assert!(if exp.is_nan() {res.is_nan()} else {exp == res}, + "test for {} was {} instead of {}", val, res, exp); + })); + } + + /// 1. (anything) ** 0 is 1 + #[test] + fn zero_as_exponent() { + test_sets_as_base(ALL, 0.0, 1.0); + test_sets_as_base(ALL, -0.0, 1.0); + } + + /// 2. 1 ** (anything) is 1 + #[test] + fn one_as_base() { + test_sets_as_exponent(1.0, ALL, 1.0); + } + + /// 3. (anything except 1) ** NAN is NAN + /// 4. NAN ** (anything except 0) is NAN + #[test] + fn nan_inputs() { + // NAN as the base: + // (NAN ^ anything *but 0* should be NAN) + test_sets_as_exponent(NAN, &ALL[2..], NAN); + + // NAN as the exponent: + // (anything *but 1* ^ NAN should be NAN) + test_sets_as_base(&ALL[..(ALL.len() - 2)], NAN, NAN); + } + + /// 16. +INF ** (+anything except 0,NAN) is +INF + /// 17. +INF ** (-anything except 0,NAN) is +0 + /// 18. -INF ** (+odd integer) is -INF + /// 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) + #[test] + fn infinity_as_base() { + // Positive Infinity as the base: + // (+Infinity ^ positive anything but 0 and NAN should be +Infinity) + test_sets_as_exponent(INFINITY, &POS[1..], INFINITY); + + // (+Infinity ^ negative anything except 0 and NAN should be 0.0) + test_sets_as_exponent(INFINITY, &NEG[1..], 0.0); + + // Negative Infinity as the base: + // (-Infinity ^ positive odd ints should be -Infinity) + test_sets_as_exponent(NEG_INFINITY, &[POS_ODDS], NEG_INFINITY); + + // (-Infinity ^ anything but odd ints should be == -0 ^ (-anything)) + // We can lump in pos/neg odd ints here because they don't seem to + // cause panics (div by zero) in release mode (I think). + test_sets(ALL, &|v: f64| pow(NEG_INFINITY, v), &|v: f64| pow(-0.0, -v)); + } + + /// 5. +-(|x| > 1) ** +INF is +INF + /// 6. +-(|x| > 1) ** -INF is +0 + /// 7. +-(|x| < 1) ** +INF is +0 + /// 8. +-(|x| < 1) ** -INF is +INF + /// 9. -1 ** +-INF is 1 + #[test] + fn infinity_as_exponent() { + // Positive/Negative base greater than 1: + // (pos/neg > 1 ^ Infinity should be Infinity - note this excludes NAN as the base) + test_sets_as_base(&ALL[5..(ALL.len() - 2)], INFINITY, INFINITY); + + // (pos/neg > 1 ^ -Infinity should be 0.0) + test_sets_as_base(&ALL[5..(ALL.len() - 2)], NEG_INFINITY, 0.0); + + // Positive/Negative base less than 1: + let base_below_one = &[POS_ZERO, NEG_ZERO, NEG_SMALL_FLOATS, POS_SMALL_FLOATS]; + + // (pos/neg < 1 ^ Infinity should be 0.0 - this also excludes NAN as the base) + test_sets_as_base(base_below_one, INFINITY, 0.0); + + // (pos/neg < 1 ^ -Infinity should be Infinity) + test_sets_as_base(base_below_one, NEG_INFINITY, INFINITY); + + // Positive/Negative 1 as the base: + // (pos/neg 1 ^ Infinity should be 1) + test_sets_as_base(&[NEG_ONE, POS_ONE], INFINITY, 1.0); + + // (pos/neg 1 ^ -Infinity should be 1) + test_sets_as_base(&[NEG_ONE, POS_ONE], NEG_INFINITY, 1.0); + } + + /// 10. +0 ** (+anything except 0, NAN) is +0 + /// 11. -0 ** (+anything except 0, NAN, odd integer) is +0 + /// 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero + /// 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero + /// 14. -0 ** (+odd integer) is -0 + /// 15. -0 ** (-odd integer) is -INF, raise divbyzero + #[test] + fn zero_as_base() { + // Positive Zero as the base: + // (+0 ^ anything positive but 0 and NAN should be +0) + test_sets_as_exponent(0.0, &POS[1..], 0.0); + + // (+0 ^ anything negative but 0 and NAN should be Infinity) + // (this should panic because we're dividing by zero but won't because release mode, I think) + test_sets_as_exponent(0.0, &NEG[1..], INFINITY); + + // Negative Zero as the base: + // (-0 ^ anything positive but 0, NAN, and odd ints should be +0) + test_sets_as_exponent(-0.0, &POS[3..], 0.0); + + // (-0 ^ anything negative but 0, NAN, and odd ints should be Infinity) + // (should panic because of divide by zero) + test_sets_as_exponent(-0.0, &NEG[3..], INFINITY); + + // (-0 ^ positive odd ints should be -0) + test_sets_as_exponent(-0.0, &[POS_ODDS], -0.0); + + // (-0 ^ negative odd ints should be -Infinity) + // (should panic because of divide by zero) + test_sets_as_exponent(-0.0, &[NEG_ODDS], NEG_INFINITY); + } + + #[test] + fn normal_cases() { + assert_eq!(pow(2.0, 20.0), (1 << 20) as f64); + assert_eq!(pow(-1.0, 9.0), -1.0); + assert!(pow(-1.0, 2.2).is_nan()); + } +} From 399b9acdd2ba0cc55955c3efba35ca50f9b59181 Mon Sep 17 00:00:00 2001 From: Rahul Butani Date: Mon, 23 Jul 2018 02:54:53 -0500 Subject: [PATCH 0692/4206] Cleaned up + rustfmt'ed --- .../compiler-builtins/libm/src/math/pow.rs | 85 ++++++++++--------- 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 288e403c688b9..47505dc9a0c25 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -409,24 +409,14 @@ pub fn pow(x: f64, y: f64) -> f64 { return s * z; } -/// Special cases: - -/// 20. (anything) ** 1 is (anything) -/// 21. (anything) ** -1 is 1/(anything) -/// 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) -/// 23. (-anything except 0 and inf) ** (non-integer) is NAN - #[cfg(test)] mod tests { - // #[macro_use] extern crate std; use self::std::f64::consts::{E, PI}; use self::std::f64::{EPSILON, INFINITY, MAX, MIN, MIN_POSITIVE, NAN, NEG_INFINITY}; use super::pow; - // const TESTCASES: &[f64] = &[1.0, 0.0, PI, -PI, E, -E, MIN, MAX, MIN_POSITIVE, NAN, INFINITY, NEG_INFINITY]; - const POS_ZERO: &[f64] = &[0.0]; const NEG_ZERO: &[f64] = &[-0.0]; const POS_ONE: &[f64] = &[1.0]; @@ -440,21 +430,43 @@ mod tests { const POS_ODDS: &[f64] = &[3.0, 7.0]; const NEG_ODDS: &[f64] = &[-7.0, -3.0]; const NANS: &[f64] = &[NAN]; - // const EDGES: &[f64] = &[MIN, MAX, MIN_POSITIVE, EPSILON]; const POS_INF: &[f64] = &[INFINITY]; const NEG_INF: &[f64] = &[NEG_INFINITY]; const ALL: &[&[f64]] = &[ - POS_ZERO, NEG_ZERO, NANS, NEG_SMALL_FLOATS, POS_SMALL_FLOATS, NEG_FLOATS, POS_FLOATS, NEG_EVENS, POS_EVENS, NEG_ODDS, POS_ODDS, - NEG_INF, POS_INF, NEG_ONE, POS_ONE, + POS_ZERO, + NEG_ZERO, + NANS, + NEG_SMALL_FLOATS, + POS_SMALL_FLOATS, + NEG_FLOATS, + POS_FLOATS, + NEG_EVENS, + POS_EVENS, + NEG_ODDS, + POS_ODDS, + NEG_INF, + POS_INF, + NEG_ONE, + POS_ONE, ]; const POS: &[&[f64]] = &[POS_ZERO, POS_ODDS, POS_ONE, POS_FLOATS, POS_EVENS, POS_INF]; const NEG: &[&[f64]] = &[NEG_ZERO, NEG_ODDS, NEG_ONE, NEG_FLOATS, NEG_EVENS, NEG_INF]; fn pow_test(base: f64, exponent: f64, expected: f64) { let res = pow(base, exponent); - assert!(if expected.is_nan() {res.is_nan()} else {pow(base, exponent) == expected}, - "{} ** {} was {} instead of {}", base, exponent, res, expected); + assert!( + if expected.is_nan() { + res.is_nan() + } else { + pow(base, exponent) == expected + }, + "{} ** {} was {} instead of {}", + base, + exponent, + res, + expected + ); } fn test_sets_as_base(sets: &[&[f64]], exponent: f64, expected: f64) { @@ -468,31 +480,37 @@ mod tests { } fn test_sets(sets: &[&[f64]], computed: &Fn(f64) -> f64, expected: &Fn(f64) -> f64) { - sets.iter() - .for_each(|s| s.iter().for_each(|val| { + sets.iter().for_each(|s| { + s.iter().for_each(|val| { let exp = expected(*val); let res = computed(*val); - assert!(if exp.is_nan() {res.is_nan()} else {exp == res}, - "test for {} was {} instead of {}", val, res, exp); - })); + assert!( + if exp.is_nan() { + res.is_nan() + } else { + exp == res + }, + "test for {} was {} instead of {}", + val, + res, + exp + ); + }) + }); } - /// 1. (anything) ** 0 is 1 #[test] fn zero_as_exponent() { test_sets_as_base(ALL, 0.0, 1.0); test_sets_as_base(ALL, -0.0, 1.0); } - /// 2. 1 ** (anything) is 1 #[test] fn one_as_base() { test_sets_as_exponent(1.0, ALL, 1.0); } - /// 3. (anything except 1) ** NAN is NAN - /// 4. NAN ** (anything except 0) is NAN #[test] fn nan_inputs() { // NAN as the base: @@ -504,10 +522,6 @@ mod tests { test_sets_as_base(&ALL[..(ALL.len() - 2)], NAN, NAN); } - /// 16. +INF ** (+anything except 0,NAN) is +INF - /// 17. +INF ** (-anything except 0,NAN) is +0 - /// 18. -INF ** (+odd integer) is -INF - /// 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) #[test] fn infinity_as_base() { // Positive Infinity as the base: @@ -527,11 +541,6 @@ mod tests { test_sets(ALL, &|v: f64| pow(NEG_INFINITY, v), &|v: f64| pow(-0.0, -v)); } - /// 5. +-(|x| > 1) ** +INF is +INF - /// 6. +-(|x| > 1) ** -INF is +0 - /// 7. +-(|x| < 1) ** +INF is +0 - /// 8. +-(|x| < 1) ** -INF is +INF - /// 9. -1 ** +-INF is 1 #[test] fn infinity_as_exponent() { // Positive/Negative base greater than 1: @@ -539,7 +548,7 @@ mod tests { test_sets_as_base(&ALL[5..(ALL.len() - 2)], INFINITY, INFINITY); // (pos/neg > 1 ^ -Infinity should be 0.0) - test_sets_as_base(&ALL[5..(ALL.len() - 2)], NEG_INFINITY, 0.0); + test_sets_as_base(&ALL[5..ALL.len() - 2], NEG_INFINITY, 0.0); // Positive/Negative base less than 1: let base_below_one = &[POS_ZERO, NEG_ZERO, NEG_SMALL_FLOATS, POS_SMALL_FLOATS]; @@ -558,12 +567,6 @@ mod tests { test_sets_as_base(&[NEG_ONE, POS_ONE], NEG_INFINITY, 1.0); } - /// 10. +0 ** (+anything except 0, NAN) is +0 - /// 11. -0 ** (+anything except 0, NAN, odd integer) is +0 - /// 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero - /// 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero - /// 14. -0 ** (+odd integer) is -0 - /// 15. -0 ** (-odd integer) is -INF, raise divbyzero #[test] fn zero_as_base() { // Positive Zero as the base: @@ -576,7 +579,7 @@ mod tests { // Negative Zero as the base: // (-0 ^ anything positive but 0, NAN, and odd ints should be +0) - test_sets_as_exponent(-0.0, &POS[3..], 0.0); + test_sets_as_exponent(-0.0, &POS[3..], 0.0); // (-0 ^ anything negative but 0, NAN, and odd ints should be Infinity) // (should panic because of divide by zero) From 770e0edb7087f346554392545feef3bfbec77041 Mon Sep 17 00:00:00 2001 From: Rahul Butani Date: Mon, 23 Jul 2018 09:45:22 -0500 Subject: [PATCH 0693/4206] Some additional tests --- .../compiler-builtins/libm/src/math/pow.rs | 39 ++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 47505dc9a0c25..c908c8461f2be 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -421,12 +421,12 @@ mod tests { const NEG_ZERO: &[f64] = &[-0.0]; const POS_ONE: &[f64] = &[1.0]; const NEG_ONE: &[f64] = &[-1.0]; - const POS_FLOATS: &[f64] = &[E, PI, MAX]; - const NEG_FLOATS: &[f64] = &[-E, -PI, MIN]; + const POS_FLOATS: &[f64] = &[99.0 / 70.0, E, PI]; + const NEG_FLOATS: &[f64] = &[-99.0 / 70.0, -E, -PI]; const POS_SMALL_FLOATS: &[f64] = &[(1.0 / 2.0), MIN_POSITIVE, EPSILON]; const NEG_SMALL_FLOATS: &[f64] = &[-(1.0 / 2.0), -MIN_POSITIVE, -EPSILON]; - const POS_EVENS: &[f64] = &[2.0, 6.0, 8.0, 10.0, 22.0, 100.0]; - const NEG_EVENS: &[f64] = &[-8.0, -2.0]; + const POS_EVENS: &[f64] = &[2.0, 6.0, 8.0, 10.0, 22.0, 100.0, MAX]; + const NEG_EVENS: &[f64] = &[MIN, -100.0, -22.0, -10.0, -8.0, -6.0, -2.0]; const POS_ODDS: &[f64] = &[3.0, 7.0]; const NEG_ODDS: &[f64] = &[-7.0, -3.0]; const NANS: &[f64] = &[NAN]; @@ -574,7 +574,7 @@ mod tests { test_sets_as_exponent(0.0, &POS[1..], 0.0); // (+0 ^ anything negative but 0 and NAN should be Infinity) - // (this should panic because we're dividing by zero but won't because release mode, I think) + // (this should panic because we're dividing by zero) test_sets_as_exponent(0.0, &NEG[1..], INFINITY); // Negative Zero as the base: @@ -593,10 +593,39 @@ mod tests { test_sets_as_exponent(-0.0, &[NEG_ODDS], NEG_INFINITY); } + #[test] + fn special_cases() { + // / 20. (anything) ** 1 is (anything) + // One as the exponent: + // (anything ^ 1 should be anything - i.e. the base) + test_sets(ALL, &|v: f64| pow(v, 1.0), &|v: f64| v); + + // / 21. (anything) ** -1 is 1/(anything) + // Negative One as the exponent: + // (anything ^ -1 should be 1/anything) + test_sets(ALL, &|v: f64| pow(v, -1.0), &|v: f64| 1.0 / v); + + // / 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) + // Factoring -1 out: + // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer)) + &[POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS].iter().for_each(|int_set| int_set.iter().for_each(|int| { + test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| pow(-1.0, *int) * pow(v, *int)); + })); + + // / 23. (-anything except 0 and inf) ** (non-integer) is NAN + // Negative base (imaginary results): + // (-anything except 0 and Infinity ^ non-integer should be NAN) + &NEG[1..(NEG.len()-1)].iter().for_each(|set| set.iter().for_each(|val| { + test_sets(&ALL[3..7], &|v: f64| pow(*val, v), &|_| NAN); + })); + + } + #[test] fn normal_cases() { assert_eq!(pow(2.0, 20.0), (1 << 20) as f64); assert_eq!(pow(-1.0, 9.0), -1.0); assert!(pow(-1.0, 2.2).is_nan()); + assert!(pow(-1.0, -1.14).is_nan()); } } From f52b7ea8f5dc173766c8435f482cde0e85c981b1 Mon Sep 17 00:00:00 2001 From: Rahul Butani Date: Mon, 23 Jul 2018 09:48:47 -0500 Subject: [PATCH 0694/4206] rustfmt'ed --- .../compiler-builtins/libm/src/math/pow.rs | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index c908c8461f2be..7aaec7874013b 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -595,30 +595,33 @@ mod tests { #[test] fn special_cases() { - // / 20. (anything) ** 1 is (anything) // One as the exponent: // (anything ^ 1 should be anything - i.e. the base) test_sets(ALL, &|v: f64| pow(v, 1.0), &|v: f64| v); - // / 21. (anything) ** -1 is 1/(anything) // Negative One as the exponent: // (anything ^ -1 should be 1/anything) test_sets(ALL, &|v: f64| pow(v, -1.0), &|v: f64| 1.0 / v); - // / 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) // Factoring -1 out: // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer)) - &[POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS].iter().for_each(|int_set| int_set.iter().for_each(|int| { - test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| pow(-1.0, *int) * pow(v, *int)); - })); + &[POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS] + .iter() + .for_each(|int_set| { + int_set.iter().for_each(|int| { + test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| { + pow(-1.0, *int) * pow(v, *int) + }); + }) + }); - // / 23. (-anything except 0 and inf) ** (non-integer) is NAN // Negative base (imaginary results): // (-anything except 0 and Infinity ^ non-integer should be NAN) - &NEG[1..(NEG.len()-1)].iter().for_each(|set| set.iter().for_each(|val| { - test_sets(&ALL[3..7], &|v: f64| pow(*val, v), &|_| NAN); - })); - + &NEG[1..(NEG.len() - 1)].iter().for_each(|set| { + set.iter().for_each(|val| { + test_sets(&ALL[3..7], &|v: f64| pow(*val, v), &|_| NAN); + }) + }); } #[test] From 7f76eda7b51fe698a04c7dfda1bf49507a887ac0 Mon Sep 17 00:00:00 2001 From: Rahul Butani Date: Mon, 23 Jul 2018 11:14:41 -0500 Subject: [PATCH 0695/4206] Use core for constants instead of std (thanks @vks) --- library/compiler-builtins/libm/src/math/pow.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 7aaec7874013b..a1889bb6bb68e 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -411,10 +411,10 @@ pub fn pow(x: f64, y: f64) -> f64 { #[cfg(test)] mod tests { - extern crate std; + extern crate core; - use self::std::f64::consts::{E, PI}; - use self::std::f64::{EPSILON, INFINITY, MAX, MIN, MIN_POSITIVE, NAN, NEG_INFINITY}; + use self::core::f64::consts::{E, PI}; + use self::core::f64::{EPSILON, INFINITY, MAX, MIN, MIN_POSITIVE, NAN, NEG_INFINITY}; use super::pow; const POS_ZERO: &[f64] = &[0.0]; From d8cc6337f6e7606a54bd1b70cb9778555829753b Mon Sep 17 00:00:00 2001 From: Mark Barbone Date: Tue, 31 Jul 2018 20:56:46 -0400 Subject: [PATCH 0696/4206] Change sqrt to use wrapping operations --- .../compiler-builtins/libm/src/math/sqrt.rs | 63 ++++++++++--------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index a05a521fb4b7b..14404d4eb18b9 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -77,6 +77,7 @@ */ use core::f64; +use core::num::Wrapping; const TINY: f64 = 1.0e-300; @@ -96,21 +97,21 @@ pub fn sqrt(x: f64) -> f64 { } } let mut z: f64; - let sign: u32 = 0x80000000; + let sign: Wrapping = Wrapping(0x80000000); let mut ix0: i32; let mut s0: i32; let mut q: i32; let mut m: i32; let mut t: i32; let mut i: i32; - let mut r: u32; - let mut t1: u32; - let mut s1: u32; - let mut ix1: u32; - let mut q1: u32; + let mut r: Wrapping; + let mut t1: Wrapping; + let mut s1: Wrapping; + let mut ix1: Wrapping; + let mut q1: Wrapping; ix0 = (x.to_bits() >> 32) as i32; - ix1 = x.to_bits() as u32; + ix1 = Wrapping(x.to_bits() as u32); /* take care of Inf and NaN */ if (ix0 & 0x7ff00000) == 0x7ff00000 { @@ -118,7 +119,7 @@ pub fn sqrt(x: f64) -> f64 { } /* take care of zero */ if ix0 <= 0 { - if ((ix0 & !(sign as i32)) | ix1 as i32) == 0 { + if ((ix0 & !(sign.0 as i32)) | ix1.0 as i32) == 0 { return x; /* sqrt(+-0) = +-0 */ } if ix0 < 0 { @@ -131,7 +132,7 @@ pub fn sqrt(x: f64) -> f64 { /* subnormal x */ while ix0 == 0 { m -= 21; - ix0 |= (ix1 >> 11) as i32; + ix0 |= (ix1 >> 11).0 as i32; ix1 <<= 21; } i = 0; @@ -140,46 +141,46 @@ pub fn sqrt(x: f64) -> f64 { ix0 <<= 1; } m -= i - 1; - ix0 |= (ix1 >> (32 - i)) as i32; - ix1 <<= i; + ix0 |= (ix1 >> (32 - i) as usize).0 as i32; + ix1 = ix1 << i as usize; } m -= 1023; /* unbias exponent */ ix0 = (ix0 & 0x000fffff) | 0x00100000; if (m & 1) == 1 { /* odd m, double x to make it even */ - ix0 += ix0 + ((ix1 & sign) >> 31) as i32; + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; ix1 += ix1; } m >>= 1; /* m = [m/2] */ /* generate sqrt(x) bit by bit */ - ix0 += ix0 + ((ix1 & sign) >> 31) as i32; + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; ix1 += ix1; q = 0; /* [q,q1] = sqrt(x) */ - q1 = 0; + q1 = Wrapping(0); s0 = 0; - s1 = 0; - r = 0x00200000; /* r = moving bit from right to left */ + s1 = Wrapping(0); + r = Wrapping(0x00200000); /* r = moving bit from right to left */ - while r != 0 { - t = s0 + r as i32; + while r != Wrapping(0) { + t = s0 + r.0 as i32; if t <= ix0 { - s0 = t + r as i32; + s0 = t + r.0 as i32; ix0 -= t; - q += r as i32; + q += r.0 as i32; } - ix0 += ix0 + ((ix1 & sign) >> 31) as i32; + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; ix1 += ix1; r >>= 1; } r = sign; - while r != 0 { + while r != Wrapping(0) { t1 = s1 + r; t = s0; if t < ix0 || (t == ix0 && t1 <= ix1) { s1 = t1 + r; - if (t1 & sign) == sign && (s1 & sign) == 0 { + if (t1 & sign) == sign && (s1 & sign) == Wrapping(0) { s0 += 1; } ix0 -= t; @@ -189,26 +190,26 @@ pub fn sqrt(x: f64) -> f64 { ix1 -= t1; q1 += r; } - ix0 += ix0 + ((ix1 & sign) >> 31) as i32; + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; ix1 += ix1; r >>= 1; } /* use floating add to find out rounding direction */ - if (ix0 as u32 | ix1) != 0 { + if (ix0 as u32 | ix1.0) != 0 { z = 1.0 - TINY; /* raise inexact flag */ if z >= 1.0 { z = 1.0 + TINY; - if q1 == 0xffffffff { - q1 = 0; + if q1.0 == 0xffffffff { + q1 = Wrapping(0); q += 1; } else if z > 1.0 { - if q1 == 0xfffffffe { + if q1.0 == 0xfffffffe { q += 1; } - q1 += 2; + q1 += Wrapping(2); } else { - q1 += q1 & 1; + q1 += q1 & Wrapping(1); } } } @@ -218,5 +219,5 @@ pub fn sqrt(x: f64) -> f64 { ix1 |= sign; } ix0 += m << 20; - f64::from_bits((ix0 as u64) << 32 | ix1 as u64) + f64::from_bits((ix0 as u64) << 32 | ix1.0 as u64) } From 1cbbb87c89c91f5b6cb3acb694c405cd6f83fb32 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 12:12:47 -0700 Subject: [PATCH 0697/4206] Update contributing docs --- .../compiler-builtins/libm/CONTRIBUTING.md | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md index 680c40e80e7d8..a7e817e13ed23 100644 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -2,25 +2,25 @@ - Pick your favorite math function from the [issue tracker]. - Look for the C implementation of the function in the [MUSL source code][src]. -- Copy paste the C code into a Rust file in the `src/math` directory and adjust `src/math/mod.rs` - accordingly. Also, uncomment the corresponding trait method in `src/lib.rs`. -- Run `cargo watch check` and fix the compiler errors. -- Tweak the bottom of `test-generator/src/main.rs` to add your function to the test suite. -- If you can, run the full test suite locally (see the [testing](#testing) section below). If you - can't, no problem! Your PR will be fully tested automatically. Though you may still want to add - and run some unit tests. See the bottom of [`src/math/truncf.rs`] for an example of such tests; - you can run unit tests with the `cargo test --lib` command. -- Send us a pull request! Make sure to run `cargo fmt` on your code before sending the PR. Also - include "closes #42" in the PR description to close the corresponding issue. +- Copy paste the C code into a Rust file in the `src/math` directory and adjust + `src/math/mod.rs` accordingly. Also, uncomment the corresponding trait method + in `src/lib.rs`. +- Write some simple tests in your module (using `#[test]`) +- Run `cargo test` to make sure it works +- Run `cargo test --features musl-reference-tests` to compare your + implementation against musl's +- Send us a pull request! Make sure to run `cargo fmt` on your code before + sending the PR. Also include "closes #42" in the PR description to close the + corresponding issue. - :tada: -[issue tracker]: https://github.com/japaric/libm/issues +[issue tracker]: https://github.com/rust-lang-nursery/libm/issues [src]: https://git.musl-libc.org/cgit/musl/tree/src/math -[`src/math/truncf.rs`]: https://github.com/japaric/libm/blob/master/src/math/truncf.rs +[`src/math/truncf.rs`]: https://github.com/rust-lang-nursery/libm/blob/master/src/math/truncf.rs Check [PR #65] for an example. -[PR #65]: https://github.com/japaric/libm/pull/65 +[PR #65]: https://github.com/rust-lang-nursery/libm/pull/65 ## Tips and tricks @@ -78,18 +78,18 @@ let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 12 ## Testing -The test suite of this crate can only be run on x86_64 Linux systems using the following commands: +Normal tests can be executed with: -``` console -$ # The test suite depends on the `cross` tool so install it if you don't have it -$ cargo install cross - -$ # and the `cross` tool requires docker to be running -$ systemctl start docker +``` +cargo test +``` -$ # execute the test suite for the x86_64 target -$ TARGET=x86_64-unknown-linux-gnu bash ci/script.sh +If you'd like to run tests with randomized inputs that get compared against musl +itself, you'll need to be on a Linux system and then you can execute: -$ # execute the test suite for the ARMv7 target -$ TARGET=armv7-unknown-linux-gnueabihf bash ci/script.sh ``` +cargo test --features musl-reference-tests +``` + +Note that you may need to pass `--release` to Cargo if there are errors related +to integer overflow. From c981490c7565102a52a580cd20535c311cac7a85 Mon Sep 17 00:00:00 2001 From: Mark Barbone Date: Wed, 1 Aug 2018 12:59:20 -0400 Subject: [PATCH 0698/4206] Modify atan2 to use `wrapping_` ops --- library/compiler-builtins/libm/src/math/atan2.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs index a702ec39fe693..37dad35e1a447 100644 --- a/library/compiler-builtins/libm/src/math/atan2.rs +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -92,12 +92,12 @@ pub fn atan2(y: f64, x: f64) -> f64 { } } /* |y/x| > 0x1p64 */ - if ix + (64 << 20) < iy || iy == 0x7ff00000 { + if ix.wrapping_add(64 << 20) < iy || iy == 0x7ff00000 { return if m & 1 != 0 { -PI / 2.0 } else { PI / 2.0 }; } /* z = atan(|y/x|) without spurious underflow */ - let z = if (m & 2 != 0) && iy + (64 << 20) < ix { + let z = if (m & 2 != 0) && iy.wrapping_add(64 << 20) < ix { /* |y/x| < 0x1p-64, x<0 */ 0.0 } else { From f4c572727a3c4ac47709a25c5aef53832e06850a Mon Sep 17 00:00:00 2001 From: Igor null Date: Tue, 16 Oct 2018 10:26:39 +0300 Subject: [PATCH 0699/4206] fixed uint underflow in floorf for negative exponents --- library/compiler-builtins/libm/src/math/floorf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index 8699be0602693..7d631df02b3d8 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -12,7 +12,7 @@ pub fn floorf(x: f32) -> f32 { } } let mut ui = x.to_bits(); - let e = (((ui >> 23) & 0xff) - 0x7f) as i32; + let e = (((ui >> 23) as i32) & 0xff) - 0x7f; if e >= 23 { return x; From 6ab6ca024e37b5f2dc446c78834d84e2b05732d4 Mon Sep 17 00:00:00 2001 From: Anna Bogus Date: Fri, 5 Oct 2018 07:37:23 +0200 Subject: [PATCH 0700/4206] fixed some clippy warnings --- .../compiler-builtins/libm/src/math/acos.rs | 6 ++--- .../compiler-builtins/libm/src/math/asin.rs | 8 +++---- .../compiler-builtins/libm/src/math/atan.rs | 16 ++++++------- .../compiler-builtins/libm/src/math/atan2.rs | 2 +- .../compiler-builtins/libm/src/math/atanf.rs | 16 ++++++------- .../compiler-builtins/libm/src/math/ceil.rs | 2 +- .../compiler-builtins/libm/src/math/ceilf.rs | 2 +- .../compiler-builtins/libm/src/math/cosf.rs | 16 +++++-------- .../compiler-builtins/libm/src/math/expo2.rs | 2 +- .../compiler-builtins/libm/src/math/fdim.rs | 8 +++---- .../compiler-builtins/libm/src/math/fdimf.rs | 8 +++---- .../compiler-builtins/libm/src/math/floor.rs | 2 +- .../compiler-builtins/libm/src/math/floorf.rs | 2 +- .../compiler-builtins/libm/src/math/fma.rs | 10 ++++---- .../compiler-builtins/libm/src/math/hypot.rs | 2 +- .../compiler-builtins/libm/src/math/log.rs | 2 +- .../compiler-builtins/libm/src/math/log10.rs | 2 +- .../compiler-builtins/libm/src/math/log10f.rs | 2 +- .../compiler-builtins/libm/src/math/log1p.rs | 2 +- .../compiler-builtins/libm/src/math/log1pf.rs | 2 +- .../compiler-builtins/libm/src/math/log2.rs | 2 +- .../compiler-builtins/libm/src/math/log2f.rs | 2 +- .../compiler-builtins/libm/src/math/pow.rs | 2 +- .../compiler-builtins/libm/src/math/powf.rs | 22 ++++++++--------- .../libm/src/math/rem_pio2.rs | 24 +++++++++---------- .../compiler-builtins/libm/src/math/sinf.rs | 2 +- .../compiler-builtins/libm/src/math/sinh.rs | 2 +- 27 files changed, 76 insertions(+), 92 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/acos.rs b/library/compiler-builtins/libm/src/math/acos.rs index a0d1450e3a859..055888ffa61d5 100644 --- a/library/compiler-builtins/libm/src/math/acos.rs +++ b/library/compiler-builtins/libm/src/math/acos.rs @@ -52,7 +52,7 @@ const QS4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ fn r(z: f64) -> f64 { let p: f64 = z * (PS0 + z * (PS1 + z * (PS2 + z * (PS3 + z * (PS4 + z * PS5))))); let q: f64 = 1.0 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4))); - return p / q; + p / q } #[inline] @@ -73,7 +73,7 @@ pub fn acos(x: f64) -> f64 { if ix >= 0x3ff00000 { let lx: u32 = x.to_bits() as u32; - if (ix - 0x3ff00000 | lx) == 0 { + if ((ix - 0x3ff00000) | lx) == 0 { /* acos(1)=0, acos(-1)=pi */ if (hx >> 31) != 0 { return 2. * PIO2_HI + x1p_120f; @@ -105,5 +105,5 @@ pub fn acos(x: f64) -> f64 { c = (z - df * df) / (s + df); w = r(z) * s + c; - return 2. * (df + w); + 2. * (df + w) } diff --git a/library/compiler-builtins/libm/src/math/asin.rs b/library/compiler-builtins/libm/src/math/asin.rs index 8553008372663..2aee72b286174 100644 --- a/library/compiler-builtins/libm/src/math/asin.rs +++ b/library/compiler-builtins/libm/src/math/asin.rs @@ -59,7 +59,7 @@ const Q_S4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ fn comp_r(z: f64) -> f64 { let p = z * (P_S0 + z * (P_S1 + z * (P_S2 + z * (P_S3 + z * (P_S4 + z * P_S5))))); let q = 1.0 + z * (Q_S1 + z * (Q_S2 + z * (Q_S3 + z * Q_S4))); - return p / q; + p / q } #[inline] @@ -77,7 +77,7 @@ pub fn asin(mut x: f64) -> f64 { if ix >= 0x3ff00000 { let lx: u32; lx = get_low_word(x); - if (ix - 0x3ff00000 | lx) == 0 { + if ((ix - 0x3ff00000) | lx) == 0 { /* asin(1) = +-pi/2 with inexact */ return x * PIO2_HI + f64::from_bits(0x3870000000000000); } else { @@ -109,8 +109,8 @@ pub fn asin(mut x: f64) -> f64 { x = 0.5 * PIO2_HI - (2.0 * s * r - (PIO2_LO - 2.0 * c) - (0.5 * PIO2_HI - 2.0 * f)); } if hx >> 31 != 0 { - return -x; + -x } else { - return x; + x } } diff --git a/library/compiler-builtins/libm/src/math/atan.rs b/library/compiler-builtins/libm/src/math/atan.rs index ad1d57c1fe79e..94594080cb83f 100644 --- a/library/compiler-builtins/libm/src/math/atan.rs +++ b/library/compiler-builtins/libm/src/math/atan.rs @@ -102,16 +102,14 @@ pub fn atan(x: f64) -> f64 { x = (x - 1.) / (x + 1.); 1 } + } else if ix < 0x40038000 { + /* |x| < 2.4375 */ + x = (x - 1.5) / (1. + 1.5 * x); + 2 } else { - if ix < 0x40038000 { - /* |x| < 2.4375 */ - x = (x - 1.5) / (1. + 1.5 * x); - 2 - } else { - /* 2.4375 <= |x| < 2^66 */ - x = -1. / x; - 3 - } + /* 2.4375 <= |x| < 2^66 */ + x = -1. / x; + 3 } }; diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs index a702ec39fe693..5dc38099de540 100644 --- a/library/compiler-builtins/libm/src/math/atan2.rs +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -53,7 +53,7 @@ pub fn atan2(y: f64, x: f64) -> f64 { let lx = x.to_bits() as u32; let mut iy = (y.to_bits() >> 32) as u32; let ly = y.to_bits() as u32; - if (ix - 0x3ff00000 | lx) == 0 { + if ((ix - 0x3ff00000) | lx) == 0 { /* x = 1.0 */ return atan(y); } diff --git a/library/compiler-builtins/libm/src/math/atanf.rs b/library/compiler-builtins/libm/src/math/atanf.rs index 5d9024022b98d..89b0afd6fb0be 100644 --- a/library/compiler-builtins/libm/src/math/atanf.rs +++ b/library/compiler-builtins/libm/src/math/atanf.rs @@ -80,16 +80,14 @@ pub fn atanf(mut x: f32) -> f32 { x = (x - 1.) / (x + 1.); 1 } + } else if ix < 0x401c0000 { + /* |x| < 2.4375 */ + x = (x - 1.5) / (1. + 1.5 * x); + 2 } else { - if ix < 0x401c0000 { - /* |x| < 2.4375 */ - x = (x - 1.5) / (1. + 1.5 * x); - 2 - } else { - /* 2.4375 <= |x| < 2**26 */ - x = -1. / x; - 3 - } + /* 2.4375 <= |x| < 2**26 */ + x = -1. / x; + 3 } }; /* end of argument reduction */ diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index c2b11e4e74dc1..d337db200bfe7 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -27,7 +27,7 @@ pub fn ceil(x: f64) -> f64 { x + TOINT - TOINT - x }; // special case because of non-nearest rounding modes - if e <= 0x3ff - 1 { + if e < 0x3ff { force_eval!(y); return if (u >> 63) != 0 { -0. } else { 1. }; } diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index 5eb6a35a6ec63..88f9ecc443418 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -35,5 +35,5 @@ pub fn ceilf(x: f32) -> f32 { return 1.0; } } - return f32::from_bits(ui); + f32::from_bits(ui) } diff --git a/library/compiler-builtins/libm/src/math/cosf.rs b/library/compiler-builtins/libm/src/math/cosf.rs index 615746a31f7f3..48d76c8ee0d7d 100644 --- a/library/compiler-builtins/libm/src/math/cosf.rs +++ b/library/compiler-builtins/libm/src/math/cosf.rs @@ -50,12 +50,10 @@ pub fn cosf(x: f32) -> f32 { if ix > 0x4016cbe3 { /* |x| ~> 3*pi/4 */ return -k_cosf(if sign { x64 + C2_PIO2 } else { x64 - C2_PIO2 }); + } else if sign { + return k_sinf(x64 + C1_PIO2); } else { - if sign { - return k_sinf(x64 + C1_PIO2); - } else { - return k_sinf(C1_PIO2 - x64); - } + return k_sinf(C1_PIO2 - x64); } } if ix <= 0x40e231d5 { @@ -63,12 +61,10 @@ pub fn cosf(x: f32) -> f32 { if ix > 0x40afeddf { /* |x| ~> 7*pi/4 */ return k_cosf(if sign { x64 + C4_PIO2 } else { x64 - C4_PIO2 }); + } else if sign { + return k_sinf(-x64 - C3_PIO2); } else { - if sign { - return k_sinf(-x64 - C3_PIO2); - } else { - return k_sinf(x64 - C3_PIO2); - } + return k_sinf(x64 - C3_PIO2); } } diff --git a/library/compiler-builtins/libm/src/math/expo2.rs b/library/compiler-builtins/libm/src/math/expo2.rs index b5369fbbe56e2..9e60ca99422ec 100644 --- a/library/compiler-builtins/libm/src/math/expo2.rs +++ b/library/compiler-builtins/libm/src/math/expo2.rs @@ -11,5 +11,5 @@ pub fn expo2(x: f64) -> f64 { /* note that k is odd and scale*scale overflows */ let scale = combine_words(((0x3ff + K / 2) as u32) << 20, 0); /* exp(x - k ln2) * 2**(k-1) */ - return exp(x - kln2) * scale * scale; + exp(x - kln2) * scale * scale } diff --git a/library/compiler-builtins/libm/src/math/fdim.rs b/library/compiler-builtins/libm/src/math/fdim.rs index 32ae306e2efb2..d9aca86115815 100644 --- a/library/compiler-builtins/libm/src/math/fdim.rs +++ b/library/compiler-builtins/libm/src/math/fdim.rs @@ -7,11 +7,9 @@ pub fn fdim(x: f64, y: f64) -> f64 { x } else if y.is_nan() { y + } else if x > y { + x - y } else { - if x > y { - x - y - } else { - 0.0 - } + 0.0 } } diff --git a/library/compiler-builtins/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/src/math/fdimf.rs index 7db01932626fb..bcda8ee94f9bd 100644 --- a/library/compiler-builtins/libm/src/math/fdimf.rs +++ b/library/compiler-builtins/libm/src/math/fdimf.rs @@ -7,11 +7,9 @@ pub fn fdimf(x: f32, y: f32) -> f32 { x } else if y.is_nan() { y + } else if x > y { + x - y } else { - if x > y { - x - y - } else { - 0.0 - } + 0.0 } } diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index f5ac8006f0eb5..c705ae501a9ba 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -26,7 +26,7 @@ pub fn floor(x: f64) -> f64 { x + TOINT - TOINT - x }; /* special case because of non-nearest rounding modes */ - if e <= 0x3ff - 1 { + if e < 0x3ff { force_eval!(y); return if (ui >> 63) != 0 { -1. } else { 0. }; } diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index 8699be0602693..b02bae5962b47 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -35,5 +35,5 @@ pub fn floorf(x: f32) -> f32 { return -1.0; } } - return f32::from_bits(ui); + f32::from_bits(ui) } diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index acf99a5d4e233..21c854cd00f11 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -83,7 +83,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { if d > 0 { if d < 64 { zlo = nz.m << d; - zhi = nz.m >> 64 - d; + zhi = nz.m >> (64 - d); } else { zlo = 0; zhi = nz.m; @@ -91,7 +91,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { d -= 64; if d == 0 { } else if d < 64 { - rlo = rhi << 64 - d | rlo >> d | ((rlo << 64 - d) != 0) as u64; + rlo = rhi << (64 - d) | rlo >> d | ((rlo << (64 - d)) != 0) as u64; rhi = rhi >> d; } else { rlo = 1; @@ -104,7 +104,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { if d == 0 { zlo = nz.m; } else if d < 64 { - zlo = nz.m >> d | ((nz.m << 64 - d) != 0) as u64; + zlo = nz.m >> d | ((nz.m << (64 - d)) != 0) as u64; } else { zlo = 1; } @@ -136,7 +136,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { e += 64; d = rhi.leading_zeros() as i32 - 1; /* note: d > 0 */ - rhi = rhi << d | rlo >> 64 - d | ((rlo << d) != 0) as u64; + rhi = rhi << d | rlo >> (64 - d) | ((rlo << d) != 0) as u64; } else if rlo != 0 { d = rlo.leading_zeros() as i32 - 1; if d < 0 { @@ -191,7 +191,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { } else { /* only round once when scaled */ d = 10; - i = ((rhi >> d | ((rhi << 64 - d) != 0) as u64) << d) as i64; + i = ((rhi >> d | ((rhi << (64 - d)) != 0) as u64) << d) as i64; if sign != 0 { i = -i; } diff --git a/library/compiler-builtins/libm/src/math/hypot.rs b/library/compiler-builtins/libm/src/math/hypot.rs index dee9bbf424028..e53baf5399421 100644 --- a/library/compiler-builtins/libm/src/math/hypot.rs +++ b/library/compiler-builtins/libm/src/math/hypot.rs @@ -72,5 +72,5 @@ pub fn hypot(mut x: f64, mut y: f64) -> f64 { } let (hx, lx) = sq(x); let (hy, ly) = sq(y); - return z * sqrt(ly + lx + hy + hx); + z * sqrt(ly + lx + hy + hx) } diff --git a/library/compiler-builtins/libm/src/math/log.rs b/library/compiler-builtins/libm/src/math/log.rs index 948065abf3b8a..4126e413b77d6 100644 --- a/library/compiler-builtins/libm/src/math/log.rs +++ b/library/compiler-builtins/libm/src/math/log.rs @@ -114,5 +114,5 @@ pub fn log(mut x: f64) -> f64 { let t2: f64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); let r: f64 = t2 + t1; let dk: f64 = k as f64; - return s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI; + s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI } diff --git a/library/compiler-builtins/libm/src/math/log10.rs b/library/compiler-builtins/libm/src/math/log10.rs index 100618a0281df..c99696040ab47 100644 --- a/library/compiler-builtins/libm/src/math/log10.rs +++ b/library/compiler-builtins/libm/src/math/log10.rs @@ -114,5 +114,5 @@ pub fn log10(mut x: f64) -> f64 { val_lo += (y - w) + val_hi; val_hi = w; - return val_lo + val_hi; + val_lo + val_hi } diff --git a/library/compiler-builtins/libm/src/math/log10f.rs b/library/compiler-builtins/libm/src/math/log10f.rs index 9cf89deb9576b..9845cda5d950f 100644 --- a/library/compiler-builtins/libm/src/math/log10f.rs +++ b/library/compiler-builtins/libm/src/math/log10f.rs @@ -88,5 +88,5 @@ pub fn log10f(mut x: f32) -> f32 { hi = f32::from_bits(ui); lo = f - hi - hfsq + s * (hfsq + r); dk = k as f32; - return dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI + hi * IVLN10HI + dk * LOG10_2HI; + dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI + hi * IVLN10HI + dk * LOG10_2HI } diff --git a/library/compiler-builtins/libm/src/math/log1p.rs b/library/compiler-builtins/libm/src/math/log1p.rs index fb35e90db14cf..cd7045ac97ed4 100644 --- a/library/compiler-builtins/libm/src/math/log1p.rs +++ b/library/compiler-builtins/libm/src/math/log1p.rs @@ -140,5 +140,5 @@ pub fn log1p(x: f64) -> f64 { t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); r = t2 + t1; dk = k as f64; - return s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI; + s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI } diff --git a/library/compiler-builtins/libm/src/math/log1pf.rs b/library/compiler-builtins/libm/src/math/log1pf.rs index 9fc399d956ee6..8e9651357d103 100644 --- a/library/compiler-builtins/libm/src/math/log1pf.rs +++ b/library/compiler-builtins/libm/src/math/log1pf.rs @@ -95,5 +95,5 @@ pub fn log1pf(x: f32) -> f32 { r = t2 + t1; hfsq = 0.5 * f * f; dk = k as f32; - return s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI; + s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI } diff --git a/library/compiler-builtins/libm/src/math/log2.rs b/library/compiler-builtins/libm/src/math/log2.rs index b513928ccb120..a3d43e55c2b77 100644 --- a/library/compiler-builtins/libm/src/math/log2.rs +++ b/library/compiler-builtins/libm/src/math/log2.rs @@ -103,5 +103,5 @@ pub fn log2(mut x: f64) -> f64 { val_lo += (y - w) + val_hi; val_hi = w; - return val_lo + val_hi; + val_lo + val_hi } diff --git a/library/compiler-builtins/libm/src/math/log2f.rs b/library/compiler-builtins/libm/src/math/log2f.rs index 07a00dc3dae96..53a37e5033749 100644 --- a/library/compiler-builtins/libm/src/math/log2f.rs +++ b/library/compiler-builtins/libm/src/math/log2f.rs @@ -84,5 +84,5 @@ pub fn log2f(mut x: f32) -> f32 { ui &= 0xfffff000; hi = f32::from_bits(ui); lo = f - hi - hfsq + s * (hfsq + r); - return (lo + hi) * IVLN2LO + lo * IVLN2HI + hi * IVLN2HI + k as f32; + (lo + hi) * IVLN2LO + lo * IVLN2HI + hi * IVLN2HI + k as f32 } diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index b5b0407efa19a..dca70f99b619e 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -406,5 +406,5 @@ pub fn pow(x: f64, y: f64) -> f64 { z = with_set_high_word(z, j as u32); } - return s * z; + s * z } diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs index 0a26573a3d10f..befbf44db770f 100644 --- a/library/compiler-builtins/libm/src/math/powf.rs +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -136,12 +136,11 @@ pub fn powf(x: f32, y: f32) -> f32 { return x * x; } - if hy == 0x3f000000 { - /* y is 0.5 */ - if hx >= 0 { - /* x >= +0 */ - return sqrtf(x); - } + if hy == 0x3f000000 + /* y is 0.5 */ + && hx >= 0 { + /* x >= +0 */ + return sqrtf(x); } ax = fabsf(x); @@ -296,11 +295,10 @@ pub fn powf(x: f32, y: f32) -> f32 { /* z < -150 */ // FIXME: check should be (uint32_t)j > 0xc3160000 return sn * TINY * TINY; /* underflow */ - } else if j as u32 == 0xc3160000 { - /* z == -150 */ - if p_l <= z - p_h { - return sn * TINY * TINY; /* underflow */ - } + } else if j as u32 == 0xc3160000 + /* z == -150 */ + && p_l <= z - p_h { + return sn * TINY * TINY; /* underflow */ } /* @@ -339,5 +337,5 @@ pub fn powf(x: f32, y: f32) -> f32 { } else { z = f32::from_bits(j as u32); } - return sn * z; + sn * z } diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 82faf5da97a66..951dd08b429e5 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -78,7 +78,7 @@ pub fn rem_pio2(x: f64) -> (i32, f64, f64) { } } let y1 = (r - y0) - w; - return (n, y0, y1); + (n, y0, y1) } if ix <= 0x400f6a7a { @@ -100,18 +100,16 @@ pub fn rem_pio2(x: f64) -> (i32, f64, f64) { let y1 = (z - y0) + PIO2_1T; return (-1, y0, y1); } + } else if sign == 0 { + let z = x - 2.0 * PIO2_1; + let y0 = z - 2.0 * PIO2_1T; + let y1 = (z - y0) - 2.0 * PIO2_1T; + return (2, y0, y1); } else { - if sign == 0 { - let z = x - 2.0 * PIO2_1; - let y0 = z - 2.0 * PIO2_1T; - let y1 = (z - y0) - 2.0 * PIO2_1T; - return (2, y0, y1); - } else { - let z = x + 2.0 * PIO2_1; - let y0 = z + 2.0 * PIO2_1T; - let y1 = (z - y0) + 2.0 * PIO2_1T; - return (-2, y0, y1); - } + let z = x + 2.0 * PIO2_1; + let y0 = z + 2.0 * PIO2_1T; + let y1 = (z - y0) + 2.0 * PIO2_1T; + return (-2, y0, y1); } } if ix <= 0x401c463b { @@ -185,5 +183,5 @@ pub fn rem_pio2(x: f64) -> (i32, f64, f64) { if sign != 0 { return (-n, -ty[0], -ty[1]); } - return (n, ty[0], ty[1]); + (n, ty[0], ty[1]) } diff --git a/library/compiler-builtins/libm/src/math/sinf.rs b/library/compiler-builtins/libm/src/math/sinf.rs index b8fc8d6f4bec4..0c31099edd215 100644 --- a/library/compiler-builtins/libm/src/math/sinf.rs +++ b/library/compiler-builtins/libm/src/math/sinf.rs @@ -88,7 +88,7 @@ pub fn sinf(x: f32) -> f32 { match n & 3 { 0 => k_sinf(y), 1 => k_cosf(y), - 2 => return k_sinf(-y), + 2 => k_sinf(-y), _ => -k_cosf(y), } } diff --git a/library/compiler-builtins/libm/src/math/sinh.rs b/library/compiler-builtins/libm/src/math/sinh.rs index 25ff3daaccbb6..d36de66c1c0a9 100644 --- a/library/compiler-builtins/libm/src/math/sinh.rs +++ b/library/compiler-builtins/libm/src/math/sinh.rs @@ -46,5 +46,5 @@ pub fn sinh(x: f64) -> f64 { /* |x| > log(DBL_MAX) or nan */ /* note: the result is stored to handle overflow */ t = 2.0 * h * expo2(absx); - return t; + t } From a7ca98487e32cc83fb78baed6539475a3a0379a6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 12:21:55 -0700 Subject: [PATCH 0701/4206] Add bindings for ldexp/ldexpf Should help in fixing wasmerio/wasmer#407 --- library/compiler-builtins/libm/src/math/ldexp.rs | 5 +++++ library/compiler-builtins/libm/src/math/ldexpf.rs | 5 +++++ library/compiler-builtins/libm/src/math/mod.rs | 4 ++++ 3 files changed, 14 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/ldexp.rs create mode 100644 library/compiler-builtins/libm/src/math/ldexpf.rs diff --git a/library/compiler-builtins/libm/src/math/ldexp.rs b/library/compiler-builtins/libm/src/math/ldexp.rs new file mode 100644 index 0000000000000..780ddfc11659f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ldexp.rs @@ -0,0 +1,5 @@ +#[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexp(x: f64, n: i32) -> f64 { + super::scalbn(x, n) +} diff --git a/library/compiler-builtins/libm/src/math/ldexpf.rs b/library/compiler-builtins/libm/src/math/ldexpf.rs new file mode 100644 index 0000000000000..70935a0024e8b --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ldexpf.rs @@ -0,0 +1,5 @@ +#[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf(x: f32, n: i32) -> f32 { + super::scalbnf(x, n) +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index e51b1511dfcbe..be0918ffdfa40 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -104,6 +104,8 @@ mod fmod; mod fmodf; mod hypot; mod hypotf; +mod ldexp; +mod ldexpf; mod log; mod log10; mod log10f; @@ -166,6 +168,8 @@ pub use self::fmod::fmod; pub use self::fmodf::fmodf; pub use self::hypot::hypot; pub use self::hypotf::hypotf; +pub use self::ldexp::ldexp; +pub use self::ldexpf::ldexpf; pub use self::log::log; pub use self::log10::log10; pub use self::log10f::log10f; From ef597e0e8f999f278ae939368bb8e7dc91da3f0d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 12:27:57 -0700 Subject: [PATCH 0702/4206] Update some URLs --- library/compiler-builtins/libm/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 568a049f0c58b..3df5b65ea383f 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -12,9 +12,9 @@ The short term goal of this library is to [enable math support (e.g. `sin`, `ata `wasm32-unknown-unknown` target][wasm] (cf. [rust-lang-nursery/compiler-builtins][pr]). The longer term goal is to enable [math support in the `core` crate][core]. -[wasm]: https://github.com/japaric/libm/milestone/1 +[wasm]: https://github.com/rust-lang-nursery/libm/milestone/1 [pr]: https://github.com/rust-lang-nursery/compiler-builtins/pull/248 -[core]: https://github.com/japaric/libm/milestone/2 +[core]: https://github.com/rust-lang-nursery/libm/milestone/2 ## Already usable From dc3eebd0b7e04a73d7f255db7daa1918d717c249 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 12:34:05 -0700 Subject: [PATCH 0703/4206] Add a test that overflow does not happen --- library/compiler-builtins/libm/src/math/floorf.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index 7d631df02b3d8..8a63874ebd112 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -37,3 +37,11 @@ pub fn floorf(x: f32) -> f32 { } return f32::from_bits(ui); } + +#[cfg(test)] +mod tests { + #[test] + fn no_overflow() { + assert_eq!(super::floorf(0.5), 0.0); + } +} From 01d0e3eed8caadef805fd15d9dceb0d44039b712 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 12:36:37 -0700 Subject: [PATCH 0704/4206] Run `cargo fmt` --- library/compiler-builtins/libm/src/math/powf.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs index befbf44db770f..015bade86c97d 100644 --- a/library/compiler-builtins/libm/src/math/powf.rs +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -136,9 +136,10 @@ pub fn powf(x: f32, y: f32) -> f32 { return x * x; } - if hy == 0x3f000000 + if hy == 0x3f000000 /* y is 0.5 */ - && hx >= 0 { + && hx >= 0 + { /* x >= +0 */ return sqrtf(x); } @@ -295,9 +296,10 @@ pub fn powf(x: f32, y: f32) -> f32 { /* z < -150 */ // FIXME: check should be (uint32_t)j > 0xc3160000 return sn * TINY * TINY; /* underflow */ - } else if j as u32 == 0xc3160000 + } else if j as u32 == 0xc3160000 /* z == -150 */ - && p_l <= z - p_h { + && p_l <= z - p_h + { return sn * TINY * TINY; /* underflow */ } From 1701e71ed63312e72f15c04b42b152b242b0d1e6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 12:40:39 -0700 Subject: [PATCH 0705/4206] Include `ldexp*` intrinsics on the wasm target Looks like LLVM optimizes programs like: fn foo(a: u8) -> f32 { 2.0f32.powf(a as f32) } to actually invoking `ldexpf`, so let's be sure to include bindings so there's not undefined symbols. --- library/compiler-builtins/libm | 2 +- library/compiler-builtins/src/math.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 3559e703795d3..0ae442888c7af 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 3559e703795d33e84a91da2a35f2f3baac47e872 +Subproject commit 0ae442888c7af72c0a335edd43dbbd74c751f119 diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index b6195553916db..1893f1c166bac 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -71,6 +71,8 @@ no_mangle! { fn sinhf(n: f32) -> f32; fn tanf(n: f32) -> f32; fn tanhf(n: f32) -> f32; + fn ldexp(f: f64, n: i32) -> f64; + fn ldexpf(f: f32, n: i32) -> f32; } #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] From 98f4618c9ad71df908472b2f34fa567ef17353da Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 12:47:51 -0700 Subject: [PATCH 0706/4206] Revert "Use the Rust implementation of udivsi3 on ARM" This reverts commit 681aaa914dea7cae8252c33023604ce6c91808bd. --- library/compiler-builtins/build.rs | 17 ++++------------- library/compiler-builtins/ci/run-docker.sh | 1 + library/compiler-builtins/src/int/sdiv.rs | 1 + library/compiler-builtins/src/int/udiv.rs | 3 +++ 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 835b423cd7957..27dac6026478d 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -289,6 +289,7 @@ mod c { "arm/clzdi2.S", "arm/clzsi2.S", "arm/divmodsi4.S", + "arm/divsi3.S", "arm/modsi3.S", "arm/switch16.S", "arm/switch32.S", @@ -296,20 +297,8 @@ mod c { "arm/switchu8.S", "arm/sync_synchronize.S", "arm/udivmodsi4.S", + "arm/udivsi3.S", "arm/umodsi3.S", - - // Exclude these two files for now even though we haven't - // translated their implementation into Rust yet (#173). - // They appear... buggy? The `udivsi3` implementation was - // the one that seemed buggy, but the `divsi3` file - // references a symbol from `udivsi3` so we compile them - // both with the Rust versions. - // - // Note that if these are added back they should be removed - // from thumbv6m below. - // - // "arm/divsi3.S", - // "arm/udivsi3.S", ], ); @@ -427,12 +416,14 @@ mod c { "clzdi2", "clzsi2", "divmodsi4", + "divsi3", "modsi3", "switch16", "switch32", "switch8", "switchu8", "udivmodsi4", + "udivsi3", "umodsi3", ], ); diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 5c2e065ccef97..bed84ed81f6fc 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -24,6 +24,7 @@ run() { -v `pwd`:/checkout:ro \ -v `rustc --print sysroot`:/rust:ro \ -w /checkout \ + --init \ $target \ sh -c "HOME=/tmp PATH=\$PATH:/rust/bin ci/run.sh $target" } diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index a2e8aa96f9038..d7ae71ab29390 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -57,6 +57,7 @@ impl Divmod for i32 {} impl Divmod for i64 {} intrinsics! { + #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), not(thumbv6m)))] #[arm_aeabi_alias = __aeabi_idiv] pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 { a.div(b) diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index d873559bdd899..7b7f5b44dfaab 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -152,6 +152,9 @@ macro_rules! udivmod_inner { } intrinsics! { + #[use_c_shim_if(all(target_arch = "arm", + not(target_os = "ios"), + not(thumbv6m)))] #[arm_aeabi_alias = __aeabi_uidiv] /// Returns `n / d` pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { From 0899a164edf8aa04295c9c6002bdf9e394c4e412 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 13:35:50 -0700 Subject: [PATCH 0707/4206] Fix duplicate symbol __clzsi2 Looks like our tests weren't quite testing compiler-builtins when it was compiled with unmangled symbols, so update the tests to catch this and then fix the compilation of the `__clzsi2` intrinsic to use the C version if it's compiled. --- library/compiler-builtins/ci/run.sh | 9 +++++++++ library/compiler-builtins/src/int/mod.rs | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 589553adbf227..27e2de22f70f3 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -42,6 +42,10 @@ else $run --release $run --features c $run --features c --release + cargo build --target $1 + cargo build --target $1 --release + cargo build --target $1 --features c + cargo build --target $1 --release --features c fi PREFIX=$(echo $1 | sed -e 's/unknown-//')- @@ -68,6 +72,10 @@ fi # Look out for duplicated symbols when we include the compiler-rt (C) implementation for rlib in $(echo $path); do set +x + echo "================================================================" + echo checking $rlib for duplicate symbols + echo "================================================================" + stdout=$($PREFIX$NM -g --defined-only $rlib 2>&1) # NOTE On i586, It's normal that the get_pc_thunk symbol appears several @@ -86,6 +94,7 @@ for rlib in $(echo $path); do if test $? = 0; then exit 1 fi + set -ex done diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 52a4227a09b6b..07f72f84e7159 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -302,6 +302,7 @@ impl_wide_int!(u32, u64, 32); impl_wide_int!(u64, u128, 64); intrinsics! { + #[use_c_shim_if(/* always if C compilation is enabled */)] #[cfg(any( target_pointer_width = "16", target_pointer_width = "32", @@ -310,7 +311,7 @@ intrinsics! { pub extern "C" fn __clzsi2(x: usize) -> usize { // TODO: const this? Would require const-if // Note(Lokathor): the `intrinsics!` macro can't process mut inputs - let mut x = x; + let mut x = x; let mut y: usize; let mut n: usize = { #[cfg(target_pointer_width = "64")] From 21513cdcc238f6e66cc83606057116dbcbc61a46 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 13:44:20 -0700 Subject: [PATCH 0708/4206] Enable historically segfaulting tests on MIPS They seem to be passing locally so let's see what CI has to say. Closes #137 --- library/compiler-builtins/testcrate/build.rs | 104 +++++++++---------- 1 file changed, 49 insertions(+), 55 deletions(-) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index d862e0d0ffbf9..17ae3ef1819e3 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -594,14 +594,12 @@ fn main() { }"); gen(|(a, b): (MyI128, MyI128)| Some(a.0.wrapping_mul(b.0)), "builtins::int::mul::__multi3(a, b)"); - if !target_arch_mips { // FIXME(#137) - gen(|(a, b): (MyI128, MyI128)| Some(a.0.overflowing_mul(b.0)), - "{ - let mut o = 2; - let c = builtins::int::mul::__muloti4(a, b, &mut o); - (c, match o { 0 => false, 1 => true, _ => panic!() }) - }"); - } + gen(|(a, b): (MyI128, MyI128)| Some(a.0.overflowing_mul(b.0)), + "{ + let mut o = 2; + let c = builtins::int::mul::__muloti4(a, b, &mut o); + (c, match o { 0 => false, 1 => true, _ => panic!() }) + }"); // int/sdiv.rs gen(|(a, b): (MyI64, MyI64)| { @@ -658,24 +656,22 @@ fn main() { } }, "builtins::int::sdiv::__moddi3(a, b)"); - if !target_arch_mips { // FIXME(#137) - gen(|(a, b): (MyI128, MyI128)| { - if b.0 == 0 { - None - } else { - Some(a.0 / b.0) - } - }, - "builtins::int::sdiv::__divti3(a, b)"); - gen(|(a, b): (MyI128, MyI128)| { - if b.0 == 0 { - None - } else { - Some(a.0 % b.0) - } - }, - "builtins::int::sdiv::__modti3(a, b)"); - } + gen(|(a, b): (MyI128, MyI128)| { + if b.0 == 0 { + None + } else { + Some(a.0 / b.0) + } + }, + "builtins::int::sdiv::__divti3(a, b)"); + gen(|(a, b): (MyI128, MyI128)| { + if b.0 == 0 { + None + } else { + Some(a.0 % b.0) + } + }, + "builtins::int::sdiv::__modti3(a, b)"); // int/shift.rs gen(|(a, b): (MyU64, MyU32)| Some(a.0 << (b.0 % 64)), @@ -746,35 +742,33 @@ fn main() { } }, "builtins::int::udiv::__umoddi3(a, b)"); - if !target_arch_mips { // FIXME(#137) - gen(|(a, b): (MyU128, MyU128)| { - if b.0 == 0 { - None - } else { - Some(a.0 / b.0) - } - }, - "builtins::int::udiv::__udivti3(a, b)"); - gen(|(a, b): (MyU128, MyU128)| { - if b.0 == 0 { - None - } else { - Some(a.0 % b.0) - } - }, - "builtins::int::udiv::__umodti3(a, b)"); - gen(|(a, b): (MyU128, MyU128)| { - if b.0 == 0 { - None - } else { - Some((a.0 / b.0, a.0 % b.0)) - } - }, - "{ - let mut r = 0; - (builtins::int::udiv::__udivmodti4(a, b, Some(&mut r)), r) - }"); - } + gen(|(a, b): (MyU128, MyU128)| { + if b.0 == 0 { + None + } else { + Some(a.0 / b.0) + } + }, + "builtins::int::udiv::__udivti3(a, b)"); + gen(|(a, b): (MyU128, MyU128)| { + if b.0 == 0 { + None + } else { + Some(a.0 % b.0) + } + }, + "builtins::int::udiv::__umodti3(a, b)"); + gen(|(a, b): (MyU128, MyU128)| { + if b.0 == 0 { + None + } else { + Some((a.0 / b.0, a.0 % b.0)) + } + }, + "{ + let mut r = 0; + (builtins::int::udiv::__udivmodti4(a, b, Some(&mut r)), r) + }"); } macro_rules! gen_float { From de566fec8cdd22d9ab8c0c36e26bd31d6c8fd146 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 14:22:19 -0700 Subject: [PATCH 0709/4206] Fix duplicate floatdisf symbol on Windows MSVC --- library/compiler-builtins/src/float/conv.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 3171e45096cc2..8d3e5fc6de22c 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -83,6 +83,7 @@ intrinsics! { #[use_c_shim_if(any( all(target_arch = "x86", not(target_env = "msvc")), all(target_arch = "x86_64", not(windows)), + all(target_arch = "x86_64", target_env = "msvc"), ))] #[arm_aeabi_alias = __aeabi_l2f] pub extern "C" fn __floatdisf(i: i64) -> f32 { From 3a8b5e0244d71bf80da2f824b0ab4349fb232d2e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 May 2019 15:18:37 -0700 Subject: [PATCH 0710/4206] Bump to 0.1.12 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index fdca20143b91f..a05825a6122b8 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.11" +version = "0.1.12" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" From fcdb5a8c13ffd7ca19953ca0de0816d90db27510 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Tue, 7 May 2019 07:16:24 +0300 Subject: [PATCH 0711/4206] tests, fixes, format --- library/compiler-builtins/libm/build.rs | 22 +- .../compiler-builtins/libm/ci/run-docker.sh | 0 library/compiler-builtins/libm/ci/run.sh | 0 .../compiler-builtins/libm/src/math/acosh.rs | 44 +- .../compiler-builtins/libm/src/math/acoshf.rs | 42 +- .../compiler-builtins/libm/src/math/asinef.rs | 188 ++-- .../compiler-builtins/libm/src/math/asinh.rs | 70 +- .../compiler-builtins/libm/src/math/asinhf.rs | 68 +- .../compiler-builtins/libm/src/math/atan2.rs | 2 +- .../compiler-builtins/libm/src/math/atanh.rs | 65 +- .../compiler-builtins/libm/src/math/atanhf.rs | 64 +- .../compiler-builtins/libm/src/math/ceilf.rs | 2 +- .../libm/src/math/copysign.rs | 14 +- .../libm/src/math/copysignf.rs | 14 +- .../compiler-builtins/libm/src/math/erf.rs | 603 ++++++------- .../compiler-builtins/libm/src/math/erff.rs | 428 ++++----- .../compiler-builtins/libm/src/math/exp10.rs | 45 +- .../compiler-builtins/libm/src/math/exp10f.rs | 43 +- .../compiler-builtins/libm/src/math/fma.rs | 4 +- .../compiler-builtins/libm/src/math/fmod.rs | 4 +- .../compiler-builtins/libm/src/math/fmodf.rs | 4 +- .../compiler-builtins/libm/src/math/frexp.rs | 40 +- .../compiler-builtins/libm/src/math/frexpf.rs | 42 +- .../compiler-builtins/libm/src/math/ilogb.rs | 62 +- .../compiler-builtins/libm/src/math/ilogbf.rs | 62 +- library/compiler-builtins/libm/src/math/j0.rs | 814 +++++++++--------- .../compiler-builtins/libm/src/math/j0f.rs | 689 ++++++++------- library/compiler-builtins/libm/src/math/j1.rs | 801 ++++++++--------- .../compiler-builtins/libm/src/math/j1f.rs | 689 ++++++++------- library/compiler-builtins/libm/src/math/jn.rs | 681 +++++++-------- .../compiler-builtins/libm/src/math/jnf.rs | 514 +++++------ .../compiler-builtins/libm/src/math/lgamma.rs | 632 +++++++------- .../libm/src/math/lgammaf.rs | 502 +++++------ .../compiler-builtins/libm/src/math/mod.rs | 10 +- .../compiler-builtins/libm/src/math/modf.rs | 67 +- .../compiler-builtins/libm/src/math/modff.rs | 65 +- .../compiler-builtins/libm/src/math/remquo.rs | 195 +++-- .../libm/src/math/remquof.rs | 193 +++-- .../compiler-builtins/libm/src/math/sincos.rs | 119 ++- .../libm/src/math/sincosf.rs | 245 +++--- .../compiler-builtins/libm/src/math/tgamma.rs | 386 +++++---- .../libm/src/math/tgammaf.rs | 10 +- 42 files changed, 4371 insertions(+), 4173 deletions(-) mode change 100755 => 100644 library/compiler-builtins/libm/ci/run-docker.sh mode change 100755 => 100644 library/compiler-builtins/libm/ci/run.sh diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 23e1178e36075..29521ab193c22 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -41,6 +41,19 @@ mod musl_reference_tests { "rem_pio2.rs", "rem_pio2_large.rs", "rem_pio2f.rs", + "remquo.rs", + "remquof.rs", + "lgamma.rs", // lgamma passed, lgamma_r has more than 1 result + "lgammaf.rs", // lgammaf passed, lgammaf_r has more than 1 result + "frexp.rs", // more than 1 result + "frexpf.rs", // more than 1 result + "sincos.rs", // more than 1 result + "sincosf.rs", // more than 1 result + "modf.rs", // more than 1 result + "modff.rs", // more than 1 result + "asinef.rs", // not exists + "jn.rs", // passed, but very slow + "jnf.rs", // passed, but very slow ]; struct Function { @@ -78,12 +91,9 @@ mod musl_reference_tests { let contents = fs::read_to_string(file).unwrap(); let mut functions = contents.lines().filter(|f| f.starts_with("pub fn")); - let function_to_test = functions.next().unwrap(); - if functions.next().is_some() { - panic!("more than one function in"); + while let Some(function_to_test) = functions.next() { + math.push(parse(function_to_test)); } - - math.push(parse(function_to_test)); } // Generate a bunch of random inputs for each function. This will @@ -330,7 +340,7 @@ mod musl_reference_tests { src.push_str(match function.ret { Ty::F32 => "if _eqf(output, f32::from_bits(*expected as u32)).is_ok() { continue }", Ty::F64 => "if _eq(output, f64::from_bits(*expected as u64)).is_ok() { continue }", - Ty::I32 => "if output as i64 == expected { continue }", + Ty::I32 => "if output as i64 == *expected { continue }", Ty::Bool => unreachable!(), }); diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh old mode 100755 new mode 100644 diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh old mode 100755 new mode 100644 diff --git a/library/compiler-builtins/libm/src/math/acosh.rs b/library/compiler-builtins/libm/src/math/acosh.rs index 3494e3405e762..95dc57d811c9d 100644 --- a/library/compiler-builtins/libm/src/math/acosh.rs +++ b/library/compiler-builtins/libm/src/math/acosh.rs @@ -1,22 +1,22 @@ -use super::{log, log1p, sqrt}; - -const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ - -/* acosh(x) = log(x + sqrt(x*x-1)) */ -pub fn acosh(x: f64) -> f64 { - let u = x.to_bits(); - let e = ((u >> 52) as usize) & 0x7ff; - - /* x < 1 domain error is handled in the called functions */ - - if e < 0x3ff + 1 { - /* |x| < 2, up to 2ulp error in [1,1.125] */ - return log1p(x-1.0+sqrt((x-1.0)*(x-1.0)+2.0*(x-1.0))); - } - if e < 0x3ff + 26 { - /* |x| < 0x1p26 */ - return log(2.0*x-1.0/(x+sqrt(x*x-1.0))); - } - /* |x| >= 0x1p26 or nan */ - return log(x) + LN2; -} +use super::{log, log1p, sqrt}; + +const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ + +/* acosh(x) = log(x + sqrt(x*x-1)) */ +pub fn acosh(x: f64) -> f64 { + let u = x.to_bits(); + let e = ((u >> 52) as usize) & 0x7ff; + + /* x < 1 domain error is handled in the called functions */ + + if e < 0x3ff + 1 { + /* |x| < 2, up to 2ulp error in [1,1.125] */ + return log1p(x - 1.0 + sqrt((x - 1.0) * (x - 1.0) + 2.0 * (x - 1.0))); + } + if e < 0x3ff + 26 { + /* |x| < 0x1p26 */ + return log(2.0 * x - 1.0 / (x + sqrt(x * x - 1.0))); + } + /* |x| >= 0x1p26 or nan */ + return log(x) + LN2; +} diff --git a/library/compiler-builtins/libm/src/math/acoshf.rs b/library/compiler-builtins/libm/src/math/acoshf.rs index 1e298a9b3d5d6..f50a00324b198 100644 --- a/library/compiler-builtins/libm/src/math/acoshf.rs +++ b/library/compiler-builtins/libm/src/math/acoshf.rs @@ -1,21 +1,21 @@ -use super::{log1pf, logf, sqrtf}; - -const LN2: f32 = 0.693147180559945309417232121458176568; - -/* acosh(x) = log(x + sqrt(x*x-1)) */ -pub fn acoshf(x: f32) -> f32 { - let u = x.to_bits(); - let a = u & 0x7fffffff; - - if a < 0x3f800000+(1<<23) { - /* |x| < 2, invalid if x < 1 or nan */ - /* up to 2ulp error in [1,1.125] */ - return log1pf(x-1.0 + sqrtf((x-1.0)*(x-1.0)+2.0*(x-1.0))); - } - if a < 0x3f800000+(12<<23) { - /* |x| < 0x1p12 */ - return logf(2.0*x - 1.0/(x+sqrtf(x*x-1.0))); - } - /* x >= 0x1p12 */ - return logf(x) + LN2; -} +use super::{log1pf, logf, sqrtf}; + +const LN2: f32 = 0.693147180559945309417232121458176568; + +/* acosh(x) = log(x + sqrt(x*x-1)) */ +pub fn acoshf(x: f32) -> f32 { + let u = x.to_bits(); + let a = u & 0x7fffffff; + + if a < 0x3f800000 + (1 << 23) { + /* |x| < 2, invalid if x < 1 or nan */ + /* up to 2ulp error in [1,1.125] */ + return log1pf(x - 1.0 + sqrtf((x - 1.0) * (x - 1.0) + 2.0 * (x - 1.0))); + } + if a < 0x3f800000 + (12 << 23) { + /* |x| < 0x1p12 */ + return logf(2.0 * x - 1.0 / (x + sqrtf(x * x - 1.0))); + } + /* x >= 0x1p12 */ + return logf(x) + LN2; +} diff --git a/library/compiler-builtins/libm/src/math/asinef.rs b/library/compiler-builtins/libm/src/math/asinef.rs index d2cd826999d0c..cd1428bc23292 100644 --- a/library/compiler-builtins/libm/src/math/asinef.rs +++ b/library/compiler-builtins/libm/src/math/asinef.rs @@ -1,95 +1,93 @@ -/* @(#)z_asinef.c 1.0 98/08/13 */ -/****************************************************************** - * The following routines are coded directly from the algorithms - * and coefficients given in "Software Manual for the Elementary - * Functions" by William J. Cody, Jr. and William Waite, Prentice - * Hall, 1980. - ******************************************************************/ -/****************************************************************** - * Arcsine - * - * Input: - * x - floating point value - * acosine - indicates acos calculation - * - * Output: - * Arcsine of x. - * - * Description: - * This routine calculates arcsine / arccosine. - * - *****************************************************************/ - -use super::{fabsf, sqrtf}; - -const P: [f32; 2] = [ 0.933935835, -0.504400557 ]; -const Q: [f32; 2] = [ 0.560363004e+1, -0.554846723e+1 ]; -const A: [f32; 2] = [ 0.0, 0.785398163 ]; -const B: [f32; 2] = [ 1.570796326, 0.785398163 ]; -const Z_ROOTEPS_F: f32 = 1.7263349182589107e-4; - -pub fn asinef(x: f32, acosine: usize) -> f32 -{ - let flag: usize; - let i: usize; - let mut branch: bool = false; - let g: f32; - let mut res: f32 = 0.0; - let mut y: f32; - - /* Check for special values. */ - //i = numtestf (x); - if x.is_nan() || x.is_infinite() { - force_eval!(x); - return x; - } - - y = fabsf(x); - flag = acosine; - - if y > 0.5 { - i = 1 - flag; - - /* Check for range error. */ - if y > 1.0 { - return 0.0 / 0.0; - } - - g = (1.0 - y) / 2.0; - y = -2.0 * sqrtf(g); - branch = true; - } else { - i = flag; - if y < Z_ROOTEPS_F { - res = y; - g = 0.0; // pleasing the uninitialized variable - } else { - g = y * y; - } - } - - if y >= Z_ROOTEPS_F || branch { - /* Calculate the Taylor series. */ - let p = (P[1] * g + P[0]) * g; - let q = (g + Q[1]) * g + Q[0]; - let r = p / q; - - res = y + y * r; - } - - /* Calculate asine or acose. */ - if flag == 0 { - res = (A[i] + res) + A[i]; - if x < 0.0 { - res = -res; - } - } else { - if x < 0.0 { - res = (B[i] + res) + B[i]; - } else { - res = (A[i] - res) + A[i]; - } - } - - return res; -} +/* @(#)z_asinef.c 1.0 98/08/13 */ +/****************************************************************** + * The following routines are coded directly from the algorithms + * and coefficients given in "Software Manual for the Elementary + * Functions" by William J. Cody, Jr. and William Waite, Prentice + * Hall, 1980. + ******************************************************************/ +/****************************************************************** + * Arcsine + * + * Input: + * x - floating point value + * acosine - indicates acos calculation + * + * Output: + * Arcsine of x. + * + * Description: + * This routine calculates arcsine / arccosine. + * + *****************************************************************/ + +use super::{fabsf, sqrtf}; + +const P: [f32; 2] = [ 0.933935835, -0.504400557 ]; +const Q: [f32; 2] = [ 0.560363004e+1, -0.554846723e+1 ]; +const A: [f32; 2] = [ 0.0, 0.785398163 ]; +const B: [f32; 2] = [ 1.570796326, 0.785398163 ]; +const Z_ROOTEPS_F: f32 = 1.7263349182589107e-4; + +pub fn asinef(x: f32, acosine: bool) -> f32 { + let i: usize; + let mut branch: bool = false; + let g: f32; + let mut res: f32 = 0.0; + let mut y: f32; + + /* Check for special values. */ + //i = numtestf (x); + if x.is_nan() || x.is_infinite() { + force_eval!(x); + return x; + } + + y = fabsf(x); + let flag = acosine; + + if y > 0.5 { + i = (!flag) as usize; + + /* Check for range error. */ + if y > 1.0 { + return 0.0 / 0.0; + } + + g = (1.0 - y) / 2.0; + y = -2.0 * sqrtf(g); + branch = true; + } else { + i = flag; + if y < Z_ROOTEPS_F { + res = y; + g = 0.0; // pleasing the uninitialized variable + } else { + g = y * y; + } + } + + if y >= Z_ROOTEPS_F || branch { + /* Calculate the Taylor series. */ + let p = (P[1] * g + P[0]) * g; + let q = (g + Q[1]) * g + Q[0]; + let r = p / q; + + res = y + y * r; + } + + /* Calculate asine or acose. */ + if flag == 0 { + res = (A[i] + res) + A[i]; + if x < 0.0 { + res = -res; + } + } else { + if x < 0.0 { + res = (B[i] + res) + B[i]; + } else { + res = (A[i] - res) + A[i]; + } + } + + return res; +} diff --git a/library/compiler-builtins/libm/src/math/asinh.rs b/library/compiler-builtins/libm/src/math/asinh.rs index 09e894551f6c0..b29093b23472a 100644 --- a/library/compiler-builtins/libm/src/math/asinh.rs +++ b/library/compiler-builtins/libm/src/math/asinh.rs @@ -1,35 +1,35 @@ -use super::{log, log1p, sqrt}; - -const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ - -/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ -pub fn asinh(mut x: f64) -> f64 { - let mut u = x.to_bits(); - let e = ((u >> 52) as usize) & 0x7ff; - let sign = (u >> 63) != 0; - - /* |x| */ - u &= (!0) >> 1; - x = f64::from_bits(u); - - if e >= 0x3ff + 26 { - /* |x| >= 0x1p26 or inf or nan */ - x = log(x) + LN2; - } else if e >= 0x3ff + 1 { - /* |x| >= 2 */ - x = log(2.0*x + 1.0/(sqrt(x*x+1.0)+x)); - } else if e >= 0x3ff - 26 { - /* |x| >= 0x1p-26, up to 1.6ulp error in [0.125,0.5] */ - x = log1p(x + x*x/(sqrt(x*x+1.0)+1.0)); - } else { - /* |x| < 0x1p-26, raise inexact if x != 0 */ - let x1p120 = f64::from_bits(0x4770000000000000); - force_eval!(x + x1p120); - } - - if sign { - -x - } else { - x - } -} +use super::{log, log1p, sqrt}; + +const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +pub fn asinh(mut x: f64) -> f64 { + let mut u = x.to_bits(); + let e = ((u >> 52) as usize) & 0x7ff; + let sign = (u >> 63) != 0; + + /* |x| */ + u &= (!0) >> 1; + x = f64::from_bits(u); + + if e >= 0x3ff + 26 { + /* |x| >= 0x1p26 or inf or nan */ + x = log(x) + LN2; + } else if e >= 0x3ff + 1 { + /* |x| >= 2 */ + x = log(2.0 * x + 1.0 / (sqrt(x * x + 1.0) + x)); + } else if e >= 0x3ff - 26 { + /* |x| >= 0x1p-26, up to 1.6ulp error in [0.125,0.5] */ + x = log1p(x + x * x / (sqrt(x * x + 1.0) + 1.0)); + } else { + /* |x| < 0x1p-26, raise inexact if x != 0 */ + let x1p120 = f64::from_bits(0x4770000000000000); + force_eval!(x + x1p120); + } + + if sign { + -x + } else { + x + } +} diff --git a/library/compiler-builtins/libm/src/math/asinhf.rs b/library/compiler-builtins/libm/src/math/asinhf.rs index 236916d83e872..9812433032b6a 100644 --- a/library/compiler-builtins/libm/src/math/asinhf.rs +++ b/library/compiler-builtins/libm/src/math/asinhf.rs @@ -1,34 +1,34 @@ -use super::{logf, log1pf, sqrtf}; - -const LN2: f32 = 0.693147180559945309417232121458176568; - -/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ -pub fn asinhf(mut x: f32) -> f32 { - let u = x.to_bits(); - let i = u & 0x7fffffff; - let sign = (u >> 31) != 0; - - /* |x| */ - x = f32::from_bits(i); - - if i >= 0x3f800000 + (12<<23) { - /* |x| >= 0x1p12 or inf or nan */ - x = logf(x) + LN2; - } else if i >= 0x3f800000 + (1<<23) { - /* |x| >= 2 */ - x = logf(2.0*x + 1.0/(sqrtf(x*x+1.0)+x)); - } else if i >= 0x3f800000 - (12<<23) { - /* |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5] */ - x = log1pf(x + x*x/(sqrtf(x*x+1.0)+1.0)); - } else { - /* |x| < 0x1p-12, raise inexact if x!=0 */ - let x1p120 = f32::from_bits(0x7b800000); - force_eval!(x + x1p120); - } - - if sign { - -x - } else { - x - } -} +use super::{log1pf, logf, sqrtf}; + +const LN2: f32 = 0.693147180559945309417232121458176568; + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +pub fn asinhf(mut x: f32) -> f32 { + let u = x.to_bits(); + let i = u & 0x7fffffff; + let sign = (u >> 31) != 0; + + /* |x| */ + x = f32::from_bits(i); + + if i >= 0x3f800000 + (12 << 23) { + /* |x| >= 0x1p12 or inf or nan */ + x = logf(x) + LN2; + } else if i >= 0x3f800000 + (1 << 23) { + /* |x| >= 2 */ + x = logf(2.0 * x + 1.0 / (sqrtf(x * x + 1.0) + x)); + } else if i >= 0x3f800000 - (12 << 23) { + /* |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5] */ + x = log1pf(x + x * x / (sqrtf(x * x + 1.0) + 1.0)); + } else { + /* |x| < 0x1p-12, raise inexact if x!=0 */ + let x1p120 = f32::from_bits(0x7b800000); + force_eval!(x + x1p120); + } + + if sign { + -x + } else { + x + } +} diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs index 7ab636050f9b0..313bec4b907b6 100644 --- a/library/compiler-builtins/libm/src/math/atan2.rs +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -53,7 +53,7 @@ pub fn atan2(y: f64, x: f64) -> f64 { let lx = x.to_bits() as u32; let mut iy = (y.to_bits() >> 32) as u32; let ly = y.to_bits() as u32; - if ((ix - 0x3ff00000) | lx) == 0 { + if ((ix.wrapping_sub(0x3ff00000)) | lx) == 0 { /* x = 1.0 */ return atan(y); } diff --git a/library/compiler-builtins/libm/src/math/atanh.rs b/library/compiler-builtins/libm/src/math/atanh.rs index ea444809c7d17..2833715ab92cd 100644 --- a/library/compiler-builtins/libm/src/math/atanh.rs +++ b/library/compiler-builtins/libm/src/math/atanh.rs @@ -1,33 +1,32 @@ -use super::{log1p}; - -/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ -pub fn atanh(mut x: f64) -> f64 { - let mut u = x.to_bits(); - let e = ((u >> 52) as usize) & 0x7ff; - let sign = (u >> 63) != 0; - - /* |x| */ - u &= 0x7fffffff; - x = f64::from_bits(u); - - if e < 0x3ff - 1 { - if e < 0x3ff - 32 { - /* handle underflow */ - if e == 0 { - force_eval!(x as f32); - } - } else { - /* |x| < 0.5, up to 1.7ulp error */ - x = 0.5*log1p(2.0*x + 2.0*x*x/(1.0-x)); - } - } else { - /* avoid overflow */ - x = 0.5*log1p(2.0*(x/(1.0-x))); - } - - if sign { - -x - } else { - x - } -} +use super::log1p; + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +pub fn atanh(x: f64) -> f64 { + let u = x.to_bits(); + let e = ((u >> 52) as usize) & 0x7ff; + let sign = (u >> 63) != 0; + + /* |x| */ + let mut y = f64::from_bits(u & 0x7fff_ffff_ffff_ffff); + + if e < 0x3ff - 1 { + if e < 0x3ff - 32 { + /* handle underflow */ + if e == 0 { + force_eval!(y as f32); + } + } else { + /* |x| < 0.5, up to 1.7ulp error */ + y = 0.5 * log1p(2.0 * y + 2.0 * y * y / (1.0 - y)); + } + } else { + /* avoid overflow */ + y = 0.5 * log1p(2.0 * (y / (1.0 - y))); + } + + if sign { + -y + } else { + y + } +} diff --git a/library/compiler-builtins/libm/src/math/atanhf.rs b/library/compiler-builtins/libm/src/math/atanhf.rs index 77d451bf27e42..709a955518228 100644 --- a/library/compiler-builtins/libm/src/math/atanhf.rs +++ b/library/compiler-builtins/libm/src/math/atanhf.rs @@ -1,32 +1,32 @@ -use super::{log1pf}; - -/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ -pub fn atanhf(mut x: f32) -> f32 { - let mut u = x.to_bits(); - let sign = (u >> 31) != 0; - - /* |x| */ - u &= 0x7fffffff; - x = f32::from_bits(u); - - if u < 0x3f800000 - (1<<23) { - if u < 0x3f800000 - (32<<23) { - /* handle underflow */ - if u < (1<<23) { - force_eval!((x*x) as f32); - } - } else { - /* |x| < 0.5, up to 1.7ulp error */ - x = 0.5*log1pf(2.0*x + 2.0*x*x/(1.0-x)); - } - } else { - /* avoid overflow */ - x = 0.5*log1pf(2.0*(x/(1.0-x))); - } - - if sign { - -x - } else { - x - } -} +use super::log1pf; + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +pub fn atanhf(mut x: f32) -> f32 { + let mut u = x.to_bits(); + let sign = (u >> 31) != 0; + + /* |x| */ + u &= 0x7fffffff; + x = f32::from_bits(u); + + if u < 0x3f800000 - (1 << 23) { + if u < 0x3f800000 - (32 << 23) { + /* handle underflow */ + if u < (1 << 23) { + force_eval!((x * x) as f32); + } + } else { + /* |x| < 0.5, up to 1.7ulp error */ + x = 0.5 * log1pf(2.0 * x + 2.0 * x * x / (1.0 - x)); + } + } else { + /* avoid overflow */ + x = 0.5 * log1pf(2.0 * (x / (1.0 - x))); + } + + if sign { + -x + } else { + x + } +} diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index 88f9ecc443418..0be53c5cf3c8a 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -12,7 +12,7 @@ pub fn ceilf(x: f32) -> f32 { } } let mut ui = x.to_bits(); - let e = (((ui >> 23) & 0xff) - 0x7f) as i32; + let e = (((ui >> 23) & 0xff).wrapping_sub(0x7f)) as i32; if e >= 23 { return x; diff --git a/library/compiler-builtins/libm/src/math/copysign.rs b/library/compiler-builtins/libm/src/math/copysign.rs index 74b761e7468b8..9c5362a5a4772 100644 --- a/library/compiler-builtins/libm/src/math/copysign.rs +++ b/library/compiler-builtins/libm/src/math/copysign.rs @@ -1,7 +1,7 @@ -pub fn copysign(x: f64, y: f64) -> f64 { - let mut ux = x.to_bits(); - let uy = y.to_bits(); - ux &= (!0) >> 1; - ux |= uy & (1<<63); - f64::from_bits(ux) -} +pub fn copysign(x: f64, y: f64) -> f64 { + let mut ux = x.to_bits(); + let uy = y.to_bits(); + ux &= (!0) >> 1; + ux |= uy & (1 << 63); + f64::from_bits(ux) +} diff --git a/library/compiler-builtins/libm/src/math/copysignf.rs b/library/compiler-builtins/libm/src/math/copysignf.rs index a0a814bf6a10f..b42fd39ad558e 100644 --- a/library/compiler-builtins/libm/src/math/copysignf.rs +++ b/library/compiler-builtins/libm/src/math/copysignf.rs @@ -1,7 +1,7 @@ -pub fn copysignf(x: f32, y: f32) -> f32 { - let mut ux = x.to_bits(); - let uy = y.to_bits(); - ux &= 0x7fffffff; - ux |= uy & 0x80000000; - f32::from_bits(ux) -} +pub fn copysignf(x: f32, y: f32) -> f32 { + let mut ux = x.to_bits(); + let uy = y.to_bits(); + ux &= 0x7fffffff; + ux |= uy & 0x80000000; + f32::from_bits(ux) +} diff --git a/library/compiler-builtins/libm/src/math/erf.rs b/library/compiler-builtins/libm/src/math/erf.rs index b3ad2ce058f28..d53a4c83cd5be 100644 --- a/library/compiler-builtins/libm/src/math/erf.rs +++ b/library/compiler-builtins/libm/src/math/erf.rs @@ -1,297 +1,306 @@ -use super::{exp, fabs, get_high_word, with_set_low_word}; -/* origin: FreeBSD /usr/src/lib/msun/src/s_erf.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. - * ==================================================== - */ -/* double erf(double x) - * double erfc(double x) - * x - * 2 |\ - * erf(x) = --------- | exp(-t*t)dt - * sqrt(pi) \| - * 0 - * - * erfc(x) = 1-erf(x) - * Note that - * erf(-x) = -erf(x) - * erfc(-x) = 2 - erfc(x) - * - * Method: - * 1. For |x| in [0, 0.84375] - * erf(x) = x + x*R(x^2) - * erfc(x) = 1 - erf(x) if x in [-.84375,0.25] - * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] - * where R = P/Q where P is an odd poly of degree 8 and - * Q is an odd poly of degree 10. - * -57.90 - * | R - (erf(x)-x)/x | <= 2 - * - * - * Remark. The formula is derived by noting - * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) - * and that - * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 - * is close to one. The interval is chosen because the fix - * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is - * near 0.6174), and by some experiment, 0.84375 is chosen to - * guarantee the error is less than one ulp for erf. - * - * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and - * c = 0.84506291151 rounded to single (24 bits) - * erf(x) = sign(x) * (c + P1(s)/Q1(s)) - * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 - * 1+(c+P1(s)/Q1(s)) if x < 0 - * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06 - * Remark: here we use the taylor series expansion at x=1. - * erf(1+s) = erf(1) + s*Poly(s) - * = 0.845.. + P1(s)/Q1(s) - * That is, we use rational approximation to approximate - * erf(1+s) - (c = (single)0.84506291151) - * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] - * where - * P1(s) = degree 6 poly in s - * Q1(s) = degree 6 poly in s - * - * 3. For x in [1.25,1/0.35(~2.857143)], - * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1) - * erf(x) = 1 - erfc(x) - * where - * R1(z) = degree 7 poly in z, (z=1/x^2) - * S1(z) = degree 8 poly in z - * - * 4. For x in [1/0.35,28] - * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 - * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6 x >= 28 - * erf(x) = sign(x) *(1 - tiny) (raise inexact) - * erfc(x) = tiny*tiny (raise underflow) if x > 0 - * = 2 - tiny if x<0 - * - * 7. Special case: - * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, - * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, - * erfc/erf(NaN) is NaN - */ - -const ERX: f64 = 8.45062911510467529297e-01; /* 0x3FEB0AC1, 0x60000000 */ -/* - * Coefficients for approximation to erf on [0,0.84375] - */ -const EFX8: f64 = 1.02703333676410069053e+00; /* 0x3FF06EBA, 0x8214DB69 */ -const PP0: f64 = 1.28379167095512558561e-01; /* 0x3FC06EBA, 0x8214DB68 */ -const PP1: f64 = -3.25042107247001499370e-01; /* 0xBFD4CD7D, 0x691CB913 */ -const PP2: f64 = -2.84817495755985104766e-02; /* 0xBF9D2A51, 0xDBD7194F */ -const PP3: f64 = -5.77027029648944159157e-03; /* 0xBF77A291, 0x236668E4 */ -const PP4: f64 = -2.37630166566501626084e-05; /* 0xBEF8EAD6, 0x120016AC */ -const QQ1: f64 = 3.97917223959155352819e-01; /* 0x3FD97779, 0xCDDADC09 */ -const QQ2: f64 = 6.50222499887672944485e-02; /* 0x3FB0A54C, 0x5536CEBA */ -const QQ3: f64 = 5.08130628187576562776e-03; /* 0x3F74D022, 0xC4D36B0F */ -const QQ4: f64 = 1.32494738004321644526e-04; /* 0x3F215DC9, 0x221C1A10 */ -const QQ5: f64 = -3.96022827877536812320e-06; /* 0xBED09C43, 0x42A26120 */ -/* - * Coefficients for approximation to erf in [0.84375,1.25] - */ -const PA0: f64 = -2.36211856075265944077e-03; /* 0xBF6359B8, 0xBEF77538 */ -const PA1: f64 = 4.14856118683748331666e-01; /* 0x3FDA8D00, 0xAD92B34D */ -const PA2: f64 = -3.72207876035701323847e-01; /* 0xBFD7D240, 0xFBB8C3F1 */ -const PA3: f64 = 3.18346619901161753674e-01; /* 0x3FD45FCA, 0x805120E4 */ -const PA4: f64 = -1.10894694282396677476e-01; /* 0xBFBC6398, 0x3D3E28EC */ -const PA5: f64 = 3.54783043256182359371e-02; /* 0x3FA22A36, 0x599795EB */ -const PA6: f64 = -2.16637559486879084300e-03; /* 0xBF61BF38, 0x0A96073F */ -const QA1: f64 = 1.06420880400844228286e-01; /* 0x3FBB3E66, 0x18EEE323 */ -const QA2: f64 = 5.40397917702171048937e-01; /* 0x3FE14AF0, 0x92EB6F33 */ -const QA3: f64 = 7.18286544141962662868e-02; /* 0x3FB2635C, 0xD99FE9A7 */ -const QA4: f64 = 1.26171219808761642112e-01; /* 0x3FC02660, 0xE763351F */ -const QA5: f64 = 1.36370839120290507362e-02; /* 0x3F8BEDC2, 0x6B51DD1C */ -const QA6: f64 = 1.19844998467991074170e-02; /* 0x3F888B54, 0x5735151D */ -/* - * Coefficients for approximation to erfc in [1.25,1/0.35] - */ -const RA0: f64 = -9.86494403484714822705e-03; /* 0xBF843412, 0x600D6435 */ -const RA1: f64 = -6.93858572707181764372e-01; /* 0xBFE63416, 0xE4BA7360 */ -const RA2: f64 = -1.05586262253232909814e+01; /* 0xC0251E04, 0x41B0E726 */ -const RA3: f64 = -6.23753324503260060396e+01; /* 0xC04F300A, 0xE4CBA38D */ -const RA4: f64 = -1.62396669462573470355e+02; /* 0xC0644CB1, 0x84282266 */ -const RA5: f64 = -1.84605092906711035994e+02; /* 0xC067135C, 0xEBCCABB2 */ -const RA6: f64 = -8.12874355063065934246e+01; /* 0xC0545265, 0x57E4D2F2 */ -const RA7: f64 = -9.81432934416914548592e+00; /* 0xC023A0EF, 0xC69AC25C */ -const SA1: f64 = 1.96512716674392571292e+01; /* 0x4033A6B9, 0xBD707687 */ -const SA2: f64 = 1.37657754143519042600e+02; /* 0x4061350C, 0x526AE721 */ -const SA3: f64 = 4.34565877475229228821e+02; /* 0x407B290D, 0xD58A1A71 */ -const SA4: f64 = 6.45387271733267880336e+02; /* 0x40842B19, 0x21EC2868 */ -const SA5: f64 = 4.29008140027567833386e+02; /* 0x407AD021, 0x57700314 */ -const SA6: f64 = 1.08635005541779435134e+02; /* 0x405B28A3, 0xEE48AE2C */ -const SA7: f64 = 6.57024977031928170135e+00; /* 0x401A47EF, 0x8E484A93 */ -const SA8: f64 = -6.04244152148580987438e-02; /* 0xBFAEEFF2, 0xEE749A62 */ -/* - * Coefficients for approximation to erfc in [1/.35,28] - */ -const RB0: f64 = -9.86494292470009928597e-03; /* 0xBF843412, 0x39E86F4A */ -const RB1: f64 = -7.99283237680523006574e-01; /* 0xBFE993BA, 0x70C285DE */ -const RB2: f64 = -1.77579549177547519889e+01; /* 0xC031C209, 0x555F995A */ -const RB3: f64 = -1.60636384855821916062e+02; /* 0xC064145D, 0x43C5ED98 */ -const RB4: f64 = -6.37566443368389627722e+02; /* 0xC083EC88, 0x1375F228 */ -const RB5: f64 = -1.02509513161107724954e+03; /* 0xC0900461, 0x6A2E5992 */ -const RB6: f64 = -4.83519191608651397019e+02; /* 0xC07E384E, 0x9BDC383F */ -const SB1: f64 = 3.03380607434824582924e+01; /* 0x403E568B, 0x261D5190 */ -const SB2: f64 = 3.25792512996573918826e+02; /* 0x40745CAE, 0x221B9F0A */ -const SB3: f64 = 1.53672958608443695994e+03; /* 0x409802EB, 0x189D5118 */ -const SB4: f64 = 3.19985821950859553908e+03; /* 0x40A8FFB7, 0x688C246A */ -const SB5: f64 = 2.55305040643316442583e+03; /* 0x40A3F219, 0xCEDF3BE6 */ -const SB6: f64 = 4.74528541206955367215e+02; /* 0x407DA874, 0xE79FE763 */ -const SB7: f64 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */ - -fn erfc1(x: f64) -> f64 { - let s: f64; - let p: f64; - let q: f64; - - s = fabs(x) - 1.0; - p = PA0+s*(PA1+s*(PA2+s*(PA3+s*(PA4+s*(PA5+s*PA6))))); - q = 1.0+s*(QA1+s*(QA2+s*(QA3+s*(QA4+s*(QA5+s*QA6))))); - - 1.0 - ERX - p/q -} - -fn erfc2(ix: u32, mut x: f64) -> f64 { - let s: f64; - let r: f64; - let big_s: f64; - let z: f64; - - if ix < 0x3ff40000 { /* |x| < 1.25 */ - return erfc1(x); - } - - x = fabs(x); - s = 1.0/(x*x); - if ix < 0x4006db6d { /* |x| < 1/.35 ~ 2.85714 */ - r = RA0+s*(RA1+s*(RA2+s*(RA3+s*(RA4+s*( - RA5+s*(RA6+s*RA7)))))); - big_s = 1.0+s*(SA1+s*(SA2+s*(SA3+s*(SA4+s*( - SA5+s*(SA6+s*(SA7+s*SA8))))))); - } else { /* |x| > 1/.35 */ - r = RB0+s*(RB1+s*(RB2+s*(RB3+s*(RB4+s*( - RB5+s*RB6))))); - big_s = 1.0+s*(SB1+s*(SB2+s*(SB3+s*(SB4+s*( - SB5+s*(SB6+s*SB7)))))); - } - z = with_set_low_word(x, 0); - - exp(-z*z-0.5625)*exp((z-x)*(z+x)+r/big_s)/x -} - -pub fn erf(x: f64) -> f64 { - let r: f64; - let s: f64; - let z: f64; - let y: f64; - let mut ix: u32; - let sign: usize; - - ix = get_high_word(x); - sign = (ix>>31) as usize; - ix &= 0x7fffffff; - if ix >= 0x7ff00000 { - /* erf(nan)=nan, erf(+-inf)=+-1 */ - return 1.0-2.0*(sign as f64) + 1.0/x; - } - if ix < 0x3feb0000 { /* |x| < 0.84375 */ - if ix < 0x3e300000 { /* |x| < 2**-28 */ - /* avoid underflow */ - return 0.125*(8.0*x + EFX8*x); - } - z = x*x; - r = PP0+z*(PP1+z*(PP2+z*(PP3+z*PP4))); - s = 1.0+z*(QQ1+z*(QQ2+z*(QQ3+z*(QQ4+z*QQ5)))); - y = r/s; - return x + x*y; - } - if ix < 0x40180000 { /* 0.84375 <= |x| < 6 */ - y = 1.0 - erfc2(ix,x); - } else { - let x1p_1022 = f64::from_bits(0x0010000000000000); - y = 1.0 - x1p_1022; - } - - if sign != 0 { - -y - } else { - y - } -} - -pub fn erfc(x: f64) -> f64 { - let r: f64; - let s: f64; - let z: f64; - let y: f64; - let mut ix: u32; - let sign: usize; - - ix = get_high_word(x); - sign = (ix>>31) as usize; - ix &= 0x7fffffff; - if ix >= 0x7ff00000 { - /* erfc(nan)=nan, erfc(+-inf)=0,2 */ - return 2.0*(sign as f64) + 1.0/x; - } - if ix < 0x3feb0000 { /* |x| < 0.84375 */ - if ix < 0x3c700000 { /* |x| < 2**-56 */ - return 1.0 - x; - } - z = x*x; - r = PP0+z*(PP1+z*(PP2+z*(PP3+z*PP4))); - s = 1.0+z*(QQ1+z*(QQ2+z*(QQ3+z*(QQ4+z*QQ5)))); - y = r/s; - if sign != 0 || ix < 0x3fd00000 { /* x < 1/4 */ - return 1.0 - (x+x*y); - } - return 0.5 - (x - 0.5 + x*y); - } - if ix < 0x403c0000 { /* 0.84375 <= |x| < 28 */ - if sign != 0 { - return 2.0 - erfc2(ix,x); - } else { - return erfc2(ix,x); - } - } - - let x1p_1022 = f64::from_bits(0x0010000000000000); - if sign != 0 { - 2.0 - x1p_1022 - } else { - x1p_1022*x1p_1022 - } -} +use super::{exp, fabs, get_high_word, with_set_low_word}; +/* origin: FreeBSD /usr/src/lib/msun/src/s_erf.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. + * ==================================================== + */ +/* double erf(double x) + * double erfc(double x) + * x + * 2 |\ + * erf(x) = --------- | exp(-t*t)dt + * sqrt(pi) \| + * 0 + * + * erfc(x) = 1-erf(x) + * Note that + * erf(-x) = -erf(x) + * erfc(-x) = 2 - erfc(x) + * + * Method: + * 1. For |x| in [0, 0.84375] + * erf(x) = x + x*R(x^2) + * erfc(x) = 1 - erf(x) if x in [-.84375,0.25] + * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] + * where R = P/Q where P is an odd poly of degree 8 and + * Q is an odd poly of degree 10. + * -57.90 + * | R - (erf(x)-x)/x | <= 2 + * + * + * Remark. The formula is derived by noting + * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) + * and that + * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 + * is close to one. The interval is chosen because the fix + * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is + * near 0.6174), and by some experiment, 0.84375 is chosen to + * guarantee the error is less than one ulp for erf. + * + * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and + * c = 0.84506291151 rounded to single (24 bits) + * erf(x) = sign(x) * (c + P1(s)/Q1(s)) + * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 + * 1+(c+P1(s)/Q1(s)) if x < 0 + * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06 + * Remark: here we use the taylor series expansion at x=1. + * erf(1+s) = erf(1) + s*Poly(s) + * = 0.845.. + P1(s)/Q1(s) + * That is, we use rational approximation to approximate + * erf(1+s) - (c = (single)0.84506291151) + * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] + * where + * P1(s) = degree 6 poly in s + * Q1(s) = degree 6 poly in s + * + * 3. For x in [1.25,1/0.35(~2.857143)], + * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1) + * erf(x) = 1 - erfc(x) + * where + * R1(z) = degree 7 poly in z, (z=1/x^2) + * S1(z) = degree 8 poly in z + * + * 4. For x in [1/0.35,28] + * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 + * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6 x >= 28 + * erf(x) = sign(x) *(1 - tiny) (raise inexact) + * erfc(x) = tiny*tiny (raise underflow) if x > 0 + * = 2 - tiny if x<0 + * + * 7. Special case: + * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, + * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, + * erfc/erf(NaN) is NaN + */ + +const ERX: f64 = 8.45062911510467529297e-01; /* 0x3FEB0AC1, 0x60000000 */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +const EFX8: f64 = 1.02703333676410069053e+00; /* 0x3FF06EBA, 0x8214DB69 */ +const PP0: f64 = 1.28379167095512558561e-01; /* 0x3FC06EBA, 0x8214DB68 */ +const PP1: f64 = -3.25042107247001499370e-01; /* 0xBFD4CD7D, 0x691CB913 */ +const PP2: f64 = -2.84817495755985104766e-02; /* 0xBF9D2A51, 0xDBD7194F */ +const PP3: f64 = -5.77027029648944159157e-03; /* 0xBF77A291, 0x236668E4 */ +const PP4: f64 = -2.37630166566501626084e-05; /* 0xBEF8EAD6, 0x120016AC */ +const QQ1: f64 = 3.97917223959155352819e-01; /* 0x3FD97779, 0xCDDADC09 */ +const QQ2: f64 = 6.50222499887672944485e-02; /* 0x3FB0A54C, 0x5536CEBA */ +const QQ3: f64 = 5.08130628187576562776e-03; /* 0x3F74D022, 0xC4D36B0F */ +const QQ4: f64 = 1.32494738004321644526e-04; /* 0x3F215DC9, 0x221C1A10 */ +const QQ5: f64 = -3.96022827877536812320e-06; /* 0xBED09C43, 0x42A26120 */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +const PA0: f64 = -2.36211856075265944077e-03; /* 0xBF6359B8, 0xBEF77538 */ +const PA1: f64 = 4.14856118683748331666e-01; /* 0x3FDA8D00, 0xAD92B34D */ +const PA2: f64 = -3.72207876035701323847e-01; /* 0xBFD7D240, 0xFBB8C3F1 */ +const PA3: f64 = 3.18346619901161753674e-01; /* 0x3FD45FCA, 0x805120E4 */ +const PA4: f64 = -1.10894694282396677476e-01; /* 0xBFBC6398, 0x3D3E28EC */ +const PA5: f64 = 3.54783043256182359371e-02; /* 0x3FA22A36, 0x599795EB */ +const PA6: f64 = -2.16637559486879084300e-03; /* 0xBF61BF38, 0x0A96073F */ +const QA1: f64 = 1.06420880400844228286e-01; /* 0x3FBB3E66, 0x18EEE323 */ +const QA2: f64 = 5.40397917702171048937e-01; /* 0x3FE14AF0, 0x92EB6F33 */ +const QA3: f64 = 7.18286544141962662868e-02; /* 0x3FB2635C, 0xD99FE9A7 */ +const QA4: f64 = 1.26171219808761642112e-01; /* 0x3FC02660, 0xE763351F */ +const QA5: f64 = 1.36370839120290507362e-02; /* 0x3F8BEDC2, 0x6B51DD1C */ +const QA6: f64 = 1.19844998467991074170e-02; /* 0x3F888B54, 0x5735151D */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +const RA0: f64 = -9.86494403484714822705e-03; /* 0xBF843412, 0x600D6435 */ +const RA1: f64 = -6.93858572707181764372e-01; /* 0xBFE63416, 0xE4BA7360 */ +const RA2: f64 = -1.05586262253232909814e+01; /* 0xC0251E04, 0x41B0E726 */ +const RA3: f64 = -6.23753324503260060396e+01; /* 0xC04F300A, 0xE4CBA38D */ +const RA4: f64 = -1.62396669462573470355e+02; /* 0xC0644CB1, 0x84282266 */ +const RA5: f64 = -1.84605092906711035994e+02; /* 0xC067135C, 0xEBCCABB2 */ +const RA6: f64 = -8.12874355063065934246e+01; /* 0xC0545265, 0x57E4D2F2 */ +const RA7: f64 = -9.81432934416914548592e+00; /* 0xC023A0EF, 0xC69AC25C */ +const SA1: f64 = 1.96512716674392571292e+01; /* 0x4033A6B9, 0xBD707687 */ +const SA2: f64 = 1.37657754143519042600e+02; /* 0x4061350C, 0x526AE721 */ +const SA3: f64 = 4.34565877475229228821e+02; /* 0x407B290D, 0xD58A1A71 */ +const SA4: f64 = 6.45387271733267880336e+02; /* 0x40842B19, 0x21EC2868 */ +const SA5: f64 = 4.29008140027567833386e+02; /* 0x407AD021, 0x57700314 */ +const SA6: f64 = 1.08635005541779435134e+02; /* 0x405B28A3, 0xEE48AE2C */ +const SA7: f64 = 6.57024977031928170135e+00; /* 0x401A47EF, 0x8E484A93 */ +const SA8: f64 = -6.04244152148580987438e-02; /* 0xBFAEEFF2, 0xEE749A62 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +const RB0: f64 = -9.86494292470009928597e-03; /* 0xBF843412, 0x39E86F4A */ +const RB1: f64 = -7.99283237680523006574e-01; /* 0xBFE993BA, 0x70C285DE */ +const RB2: f64 = -1.77579549177547519889e+01; /* 0xC031C209, 0x555F995A */ +const RB3: f64 = -1.60636384855821916062e+02; /* 0xC064145D, 0x43C5ED98 */ +const RB4: f64 = -6.37566443368389627722e+02; /* 0xC083EC88, 0x1375F228 */ +const RB5: f64 = -1.02509513161107724954e+03; /* 0xC0900461, 0x6A2E5992 */ +const RB6: f64 = -4.83519191608651397019e+02; /* 0xC07E384E, 0x9BDC383F */ +const SB1: f64 = 3.03380607434824582924e+01; /* 0x403E568B, 0x261D5190 */ +const SB2: f64 = 3.25792512996573918826e+02; /* 0x40745CAE, 0x221B9F0A */ +const SB3: f64 = 1.53672958608443695994e+03; /* 0x409802EB, 0x189D5118 */ +const SB4: f64 = 3.19985821950859553908e+03; /* 0x40A8FFB7, 0x688C246A */ +const SB5: f64 = 2.55305040643316442583e+03; /* 0x40A3F219, 0xCEDF3BE6 */ +const SB6: f64 = 4.74528541206955367215e+02; /* 0x407DA874, 0xE79FE763 */ +const SB7: f64 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */ + +fn erfc1(x: f64) -> f64 { + let s: f64; + let p: f64; + let q: f64; + + s = fabs(x) - 1.0; + p = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6))))); + q = 1.0 + s * (QA1 + s * (QA2 + s * (QA3 + s * (QA4 + s * (QA5 + s * QA6))))); + + 1.0 - ERX - p / q +} + +fn erfc2(ix: u32, mut x: f64) -> f64 { + let s: f64; + let r: f64; + let big_s: f64; + let z: f64; + + if ix < 0x3ff40000 { + /* |x| < 1.25 */ + return erfc1(x); + } + + x = fabs(x); + s = 1.0 / (x * x); + if ix < 0x4006db6d { + /* |x| < 1/.35 ~ 2.85714 */ + r = RA0 + s * (RA1 + s * (RA2 + s * (RA3 + s * (RA4 + s * (RA5 + s * (RA6 + s * RA7)))))); + big_s = 1.0 + + s * (SA1 + + s * (SA2 + s * (SA3 + s * (SA4 + s * (SA5 + s * (SA6 + s * (SA7 + s * SA8))))))); + } else { + /* |x| > 1/.35 */ + r = RB0 + s * (RB1 + s * (RB2 + s * (RB3 + s * (RB4 + s * (RB5 + s * RB6))))); + big_s = + 1.0 + s * (SB1 + s * (SB2 + s * (SB3 + s * (SB4 + s * (SB5 + s * (SB6 + s * SB7)))))); + } + z = with_set_low_word(x, 0); + + exp(-z * z - 0.5625) * exp((z - x) * (z + x) + r / big_s) / x +} + +pub fn erf(x: f64) -> f64 { + let r: f64; + let s: f64; + let z: f64; + let y: f64; + let mut ix: u32; + let sign: usize; + + ix = get_high_word(x); + sign = (ix >> 31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7ff00000 { + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1.0 - 2.0 * (sign as f64) + 1.0 / x; + } + if ix < 0x3feb0000 { + /* |x| < 0.84375 */ + if ix < 0x3e300000 { + /* |x| < 2**-28 */ + /* avoid underflow */ + return 0.125 * (8.0 * x + EFX8 * x); + } + z = x * x; + r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); + s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); + y = r / s; + return x + x * y; + } + if ix < 0x40180000 { + /* 0.84375 <= |x| < 6 */ + y = 1.0 - erfc2(ix, x); + } else { + let x1p_1022 = f64::from_bits(0x0010000000000000); + y = 1.0 - x1p_1022; + } + + if sign != 0 { + -y + } else { + y + } +} + +pub fn erfc(x: f64) -> f64 { + let r: f64; + let s: f64; + let z: f64; + let y: f64; + let mut ix: u32; + let sign: usize; + + ix = get_high_word(x); + sign = (ix >> 31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7ff00000 { + /* erfc(nan)=nan, erfc(+-inf)=0,2 */ + return 2.0 * (sign as f64) + 1.0 / x; + } + if ix < 0x3feb0000 { + /* |x| < 0.84375 */ + if ix < 0x3c700000 { + /* |x| < 2**-56 */ + return 1.0 - x; + } + z = x * x; + r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); + s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); + y = r / s; + if sign != 0 || ix < 0x3fd00000 { + /* x < 1/4 */ + return 1.0 - (x + x * y); + } + return 0.5 - (x - 0.5 + x * y); + } + if ix < 0x403c0000 { + /* 0.84375 <= |x| < 28 */ + if sign != 0 { + return 2.0 - erfc2(ix, x); + } else { + return erfc2(ix, x); + } + } + + let x1p_1022 = f64::from_bits(0x0010000000000000); + if sign != 0 { + 2.0 - x1p_1022 + } else { + x1p_1022 * x1p_1022 + } +} diff --git a/library/compiler-builtins/libm/src/math/erff.rs b/library/compiler-builtins/libm/src/math/erff.rs index 0aaa89767aba5..ef67c335b0c7b 100644 --- a/library/compiler-builtins/libm/src/math/erff.rs +++ b/library/compiler-builtins/libm/src/math/erff.rs @@ -1,210 +1,218 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_erff.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * 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. - * ==================================================== - */ - -use super::{expf, fabsf}; - -const ERX: f32 = 8.4506291151e-01; /* 0x3f58560b */ -/* - * Coefficients for approximation to erf on [0,0.84375] - */ -const EFX8: f32 = 1.0270333290e+00; /* 0x3f8375d4 */ -const PP0: f32 = 1.2837916613e-01; /* 0x3e0375d4 */ -const PP1: f32 = -3.2504209876e-01; /* 0xbea66beb */ -const PP2: f32 = -2.8481749818e-02; /* 0xbce9528f */ -const PP3: f32 = -5.7702702470e-03; /* 0xbbbd1489 */ -const PP4: f32 = -2.3763017452e-05; /* 0xb7c756b1 */ -const QQ1: f32 = 3.9791721106e-01; /* 0x3ecbbbce */ -const QQ2: f32 = 6.5022252500e-02; /* 0x3d852a63 */ -const QQ3: f32 = 5.0813062117e-03; /* 0x3ba68116 */ -const QQ4: f32 = 1.3249473704e-04; /* 0x390aee49 */ -const QQ5: f32 = -3.9602282413e-06; /* 0xb684e21a */ -/* - * Coefficients for approximation to erf in [0.84375,1.25] - */ -const PA0: f32 = -2.3621185683e-03; /* 0xbb1acdc6 */ -const PA1: f32 = 4.1485610604e-01; /* 0x3ed46805 */ -const PA2: f32 = -3.7220788002e-01; /* 0xbebe9208 */ -const PA3: f32 = 3.1834661961e-01; /* 0x3ea2fe54 */ -const PA4: f32 = -1.1089469492e-01; /* 0xbde31cc2 */ -const PA5: f32 = 3.5478305072e-02; /* 0x3d1151b3 */ -const PA6: f32 = -2.1663755178e-03; /* 0xbb0df9c0 */ -const QA1: f32 = 1.0642088205e-01; /* 0x3dd9f331 */ -const QA2: f32 = 5.4039794207e-01; /* 0x3f0a5785 */ -const QA3: f32 = 7.1828655899e-02; /* 0x3d931ae7 */ -const QA4: f32 = 1.2617121637e-01; /* 0x3e013307 */ -const QA5: f32 = 1.3637083583e-02; /* 0x3c5f6e13 */ -const QA6: f32 = 1.1984500103e-02; /* 0x3c445aa3 */ -/* - * Coefficients for approximation to erfc in [1.25,1/0.35] - */ -const RA0: f32 = -9.8649440333e-03; /* 0xbc21a093 */ -const RA1: f32 = -6.9385856390e-01; /* 0xbf31a0b7 */ -const RA2: f32 = -1.0558626175e+01; /* 0xc128f022 */ -const RA3: f32 = -6.2375331879e+01; /* 0xc2798057 */ -const RA4: f32 = -1.6239666748e+02; /* 0xc322658c */ -const RA5: f32 = -1.8460508728e+02; /* 0xc3389ae7 */ -const RA6: f32 = -8.1287437439e+01; /* 0xc2a2932b */ -const RA7: f32 = -9.8143291473e+00; /* 0xc11d077e */ -const SA1: f32 = 1.9651271820e+01; /* 0x419d35ce */ -const SA2: f32 = 1.3765776062e+02; /* 0x4309a863 */ -const SA3: f32 = 4.3456588745e+02; /* 0x43d9486f */ -const SA4: f32 = 6.4538726807e+02; /* 0x442158c9 */ -const SA5: f32 = 4.2900814819e+02; /* 0x43d6810b */ -const SA6: f32 = 1.0863500214e+02; /* 0x42d9451f */ -const SA7: f32 = 6.5702495575e+00; /* 0x40d23f7c */ -const SA8: f32 = -6.0424413532e-02; /* 0xbd777f97 */ -/* - * Coefficients for approximation to erfc in [1/.35,28] - */ -const RB0: f32 = -9.8649431020e-03; /* 0xbc21a092 */ -const RB1: f32 = -7.9928326607e-01; /* 0xbf4c9dd4 */ -const RB2: f32 = -1.7757955551e+01; /* 0xc18e104b */ -const RB3: f32 = -1.6063638306e+02; /* 0xc320a2ea */ -const RB4: f32 = -6.3756646729e+02; /* 0xc41f6441 */ -const RB5: f32 = -1.0250950928e+03; /* 0xc480230b */ -const RB6: f32 = -4.8351919556e+02; /* 0xc3f1c275 */ -const SB1: f32 = 3.0338060379e+01; /* 0x41f2b459 */ -const SB2: f32 = 3.2579251099e+02; /* 0x43a2e571 */ -const SB3: f32 = 1.5367296143e+03; /* 0x44c01759 */ -const SB4: f32 = 3.1998581543e+03; /* 0x4547fdbb */ -const SB5: f32 = 2.5530502930e+03; /* 0x451f90ce */ -const SB6: f32 = 4.7452853394e+02; /* 0x43ed43a7 */ -const SB7: f32 = -2.2440952301e+01; /* 0xc1b38712 */ - -fn erfc1(x: f32) -> f32 { - let s: f32; - let p: f32; - let q: f32; - - s = fabsf(x) - 1.0; - p = PA0+s*(PA1+s*(PA2+s*(PA3+s*(PA4+s*(PA5+s*PA6))))); - q = 1.0+s*(QA1+s*(QA2+s*(QA3+s*(QA4+s*(QA5+s*QA6))))); - return 1.0 - ERX - p/q; -} - -fn erfc2(mut ix: u32, mut x: f32) -> f32 { - let s: f32; - let r: f32; - let big_s: f32; - let z: f32; - - if ix < 0x3fa00000 { /* |x| < 1.25 */ - return erfc1(x); - } - - x = fabsf(x); - s = 1.0/(x*x); - if ix < 0x4036db6d { /* |x| < 1/0.35 */ - r = RA0+s*(RA1+s*(RA2+s*(RA3+s*(RA4+s*( - RA5+s*(RA6+s*RA7)))))); - big_s = 1.0+s*(SA1+s*(SA2+s*(SA3+s*(SA4+s*( - SA5+s*(SA6+s*(SA7+s*SA8))))))); - } else { /* |x| >= 1/0.35 */ - r = RB0+s*(RB1+s*(RB2+s*(RB3+s*(RB4+s*( - RB5+s*RB6))))); - big_s = 1.0+s*(SB1+s*(SB2+s*(SB3+s*(SB4+s*( - SB5+s*(SB6+s*SB7)))))); - } - ix = x.to_bits(); - z = f32::from_bits(ix&0xffffe000); - - expf(-z*z - 0.5625) * expf((z-x)*(z+x) + r/big_s)/x -} - -pub fn erff(x: f32) -> f32 -{ - let r: f32; - let s: f32; - let z: f32; - let y: f32; - let mut ix: u32; - let sign: usize; - - ix = x.to_bits(); - sign = (ix>>31) as usize; - ix &= 0x7fffffff; - if ix >= 0x7f800000 { - /* erf(nan)=nan, erf(+-inf)=+-1 */ - return 1.0-2.0*(sign as f32) + 1.0/x; - } - if ix < 0x3f580000 { /* |x| < 0.84375 */ - if ix < 0x31800000 { /* |x| < 2**-28 */ - /*avoid underflow */ - return 0.125*(8.0*x + EFX8*x); - } - z = x*x; - r = PP0+z*(PP1+z*(PP2+z*(PP3+z*PP4))); - s = 1.0+z*(QQ1+z*(QQ2+z*(QQ3+z*(QQ4+z*QQ5)))); - y = r/s; - return x + x*y; - } - if ix < 0x40c00000 { /* |x| < 6 */ - y = 1.0 - erfc2(ix,x); - } else { - let x1p_120 = f32::from_bits(0x03800000); - y = 1.0 - x1p_120; - } - - if sign != 0 { - -y - } else { - y - } -} - -pub fn erfcf(x: f32) -> f32 { - let r: f32; - let s: f32; - let z: f32; - let y: f32; - let mut ix: u32; - let sign: usize; - - ix = x.to_bits(); - sign = (ix>>31) as usize; - ix &= 0x7fffffff; - if ix >= 0x7f800000 { - /* erfc(nan)=nan, erfc(+-inf)=0,2 */ - return 2.0*(sign as f32) + 1.0/x; - } - - if ix < 0x3f580000 { /* |x| < 0.84375 */ - if ix < 0x23800000 { /* |x| < 2**-56 */ - return 1.0 - x; - } - z = x*x; - r = PP0+z*(PP1+z*(PP2+z*(PP3+z*PP4))); - s = 1.0+z*(QQ1+z*(QQ2+z*(QQ3+z*(QQ4+z*QQ5)))); - y = r/s; - if sign != 0 || ix < 0x3e800000 { /* x < 1/4 */ - return 1.0 - (x+x*y); - } - return 0.5 - (x - 0.5 + x*y); - } - if ix < 0x41e00000 { /* |x| < 28 */ - if sign != 0 { - return 2.0 - erfc2(ix, x); - } else { - return erfc2(ix, x); - } - } - - let x1p_120 = f32::from_bits(0x03800000); - if sign != 0 { - 2.0 - x1p_120 - } else { - x1p_120*x1p_120 - } -} +/* origin: FreeBSD /usr/src/lib/msun/src/s_erff.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + +use super::{expf, fabsf}; + +const ERX: f32 = 8.4506291151e-01; /* 0x3f58560b */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +const EFX8: f32 = 1.0270333290e+00; /* 0x3f8375d4 */ +const PP0: f32 = 1.2837916613e-01; /* 0x3e0375d4 */ +const PP1: f32 = -3.2504209876e-01; /* 0xbea66beb */ +const PP2: f32 = -2.8481749818e-02; /* 0xbce9528f */ +const PP3: f32 = -5.7702702470e-03; /* 0xbbbd1489 */ +const PP4: f32 = -2.3763017452e-05; /* 0xb7c756b1 */ +const QQ1: f32 = 3.9791721106e-01; /* 0x3ecbbbce */ +const QQ2: f32 = 6.5022252500e-02; /* 0x3d852a63 */ +const QQ3: f32 = 5.0813062117e-03; /* 0x3ba68116 */ +const QQ4: f32 = 1.3249473704e-04; /* 0x390aee49 */ +const QQ5: f32 = -3.9602282413e-06; /* 0xb684e21a */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +const PA0: f32 = -2.3621185683e-03; /* 0xbb1acdc6 */ +const PA1: f32 = 4.1485610604e-01; /* 0x3ed46805 */ +const PA2: f32 = -3.7220788002e-01; /* 0xbebe9208 */ +const PA3: f32 = 3.1834661961e-01; /* 0x3ea2fe54 */ +const PA4: f32 = -1.1089469492e-01; /* 0xbde31cc2 */ +const PA5: f32 = 3.5478305072e-02; /* 0x3d1151b3 */ +const PA6: f32 = -2.1663755178e-03; /* 0xbb0df9c0 */ +const QA1: f32 = 1.0642088205e-01; /* 0x3dd9f331 */ +const QA2: f32 = 5.4039794207e-01; /* 0x3f0a5785 */ +const QA3: f32 = 7.1828655899e-02; /* 0x3d931ae7 */ +const QA4: f32 = 1.2617121637e-01; /* 0x3e013307 */ +const QA5: f32 = 1.3637083583e-02; /* 0x3c5f6e13 */ +const QA6: f32 = 1.1984500103e-02; /* 0x3c445aa3 */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +const RA0: f32 = -9.8649440333e-03; /* 0xbc21a093 */ +const RA1: f32 = -6.9385856390e-01; /* 0xbf31a0b7 */ +const RA2: f32 = -1.0558626175e+01; /* 0xc128f022 */ +const RA3: f32 = -6.2375331879e+01; /* 0xc2798057 */ +const RA4: f32 = -1.6239666748e+02; /* 0xc322658c */ +const RA5: f32 = -1.8460508728e+02; /* 0xc3389ae7 */ +const RA6: f32 = -8.1287437439e+01; /* 0xc2a2932b */ +const RA7: f32 = -9.8143291473e+00; /* 0xc11d077e */ +const SA1: f32 = 1.9651271820e+01; /* 0x419d35ce */ +const SA2: f32 = 1.3765776062e+02; /* 0x4309a863 */ +const SA3: f32 = 4.3456588745e+02; /* 0x43d9486f */ +const SA4: f32 = 6.4538726807e+02; /* 0x442158c9 */ +const SA5: f32 = 4.2900814819e+02; /* 0x43d6810b */ +const SA6: f32 = 1.0863500214e+02; /* 0x42d9451f */ +const SA7: f32 = 6.5702495575e+00; /* 0x40d23f7c */ +const SA8: f32 = -6.0424413532e-02; /* 0xbd777f97 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +const RB0: f32 = -9.8649431020e-03; /* 0xbc21a092 */ +const RB1: f32 = -7.9928326607e-01; /* 0xbf4c9dd4 */ +const RB2: f32 = -1.7757955551e+01; /* 0xc18e104b */ +const RB3: f32 = -1.6063638306e+02; /* 0xc320a2ea */ +const RB4: f32 = -6.3756646729e+02; /* 0xc41f6441 */ +const RB5: f32 = -1.0250950928e+03; /* 0xc480230b */ +const RB6: f32 = -4.8351919556e+02; /* 0xc3f1c275 */ +const SB1: f32 = 3.0338060379e+01; /* 0x41f2b459 */ +const SB2: f32 = 3.2579251099e+02; /* 0x43a2e571 */ +const SB3: f32 = 1.5367296143e+03; /* 0x44c01759 */ +const SB4: f32 = 3.1998581543e+03; /* 0x4547fdbb */ +const SB5: f32 = 2.5530502930e+03; /* 0x451f90ce */ +const SB6: f32 = 4.7452853394e+02; /* 0x43ed43a7 */ +const SB7: f32 = -2.2440952301e+01; /* 0xc1b38712 */ + +fn erfc1(x: f32) -> f32 { + let s: f32; + let p: f32; + let q: f32; + + s = fabsf(x) - 1.0; + p = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6))))); + q = 1.0 + s * (QA1 + s * (QA2 + s * (QA3 + s * (QA4 + s * (QA5 + s * QA6))))); + return 1.0 - ERX - p / q; +} + +fn erfc2(mut ix: u32, mut x: f32) -> f32 { + let s: f32; + let r: f32; + let big_s: f32; + let z: f32; + + if ix < 0x3fa00000 { + /* |x| < 1.25 */ + return erfc1(x); + } + + x = fabsf(x); + s = 1.0 / (x * x); + if ix < 0x4036db6d { + /* |x| < 1/0.35 */ + r = RA0 + s * (RA1 + s * (RA2 + s * (RA3 + s * (RA4 + s * (RA5 + s * (RA6 + s * RA7)))))); + big_s = 1.0 + + s * (SA1 + + s * (SA2 + s * (SA3 + s * (SA4 + s * (SA5 + s * (SA6 + s * (SA7 + s * SA8))))))); + } else { + /* |x| >= 1/0.35 */ + r = RB0 + s * (RB1 + s * (RB2 + s * (RB3 + s * (RB4 + s * (RB5 + s * RB6))))); + big_s = + 1.0 + s * (SB1 + s * (SB2 + s * (SB3 + s * (SB4 + s * (SB5 + s * (SB6 + s * SB7)))))); + } + ix = x.to_bits(); + z = f32::from_bits(ix & 0xffffe000); + + expf(-z * z - 0.5625) * expf((z - x) * (z + x) + r / big_s) / x +} + +pub fn erff(x: f32) -> f32 { + let r: f32; + let s: f32; + let z: f32; + let y: f32; + let mut ix: u32; + let sign: usize; + + ix = x.to_bits(); + sign = (ix >> 31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1.0 - 2.0 * (sign as f32) + 1.0 / x; + } + if ix < 0x3f580000 { + /* |x| < 0.84375 */ + if ix < 0x31800000 { + /* |x| < 2**-28 */ + /*avoid underflow */ + return 0.125 * (8.0 * x + EFX8 * x); + } + z = x * x; + r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); + s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); + y = r / s; + return x + x * y; + } + if ix < 0x40c00000 { + /* |x| < 6 */ + y = 1.0 - erfc2(ix, x); + } else { + let x1p_120 = f32::from_bits(0x03800000); + y = 1.0 - x1p_120; + } + + if sign != 0 { + -y + } else { + y + } +} + +pub fn erfcf(x: f32) -> f32 { + let r: f32; + let s: f32; + let z: f32; + let y: f32; + let mut ix: u32; + let sign: usize; + + ix = x.to_bits(); + sign = (ix >> 31) as usize; + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + /* erfc(nan)=nan, erfc(+-inf)=0,2 */ + return 2.0 * (sign as f32) + 1.0 / x; + } + + if ix < 0x3f580000 { + /* |x| < 0.84375 */ + if ix < 0x23800000 { + /* |x| < 2**-56 */ + return 1.0 - x; + } + z = x * x; + r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); + s = 1.0 + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); + y = r / s; + if sign != 0 || ix < 0x3e800000 { + /* x < 1/4 */ + return 1.0 - (x + x * y); + } + return 0.5 - (x - 0.5 + x * y); + } + if ix < 0x41e00000 { + /* |x| < 28 */ + if sign != 0 { + return 2.0 - erfc2(ix, x); + } else { + return erfc2(ix, x); + } + } + + let x1p_120 = f32::from_bits(0x03800000); + if sign != 0 { + 2.0 - x1p_120 + } else { + x1p_120 * x1p_120 + } +} diff --git a/library/compiler-builtins/libm/src/math/exp10.rs b/library/compiler-builtins/libm/src/math/exp10.rs index d12fa0be31e1c..9537f76f13618 100644 --- a/library/compiler-builtins/libm/src/math/exp10.rs +++ b/library/compiler-builtins/libm/src/math/exp10.rs @@ -1,24 +1,21 @@ -use super::{exp2, modf, pow}; - -const LN10: f64 = 3.32192809488736234787031942948939; -const P10: &[f64] = &[ - 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, - 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, - 1e10, 1e11, 1e12, 1e13, 1e14, 1e15 -]; - -pub fn exp10(x: f64) -> f64 -{ - let (mut y, n) = modf(x); - let u: u64 = n.to_bits(); - /* fabs(n) < 16 without raising invalid on nan */ - if (u>>52 & 0x7ff) < 0x3ff+4 { - if y == 0.0 { - return P10[((n as isize) + 15) as usize]; - } - y = exp2(LN10 * y); - return y * P10[((n as isize) + 15) as usize]; - } - return pow(10.0, x); -} +use super::{exp2, modf, pow}; + +const LN10: f64 = 3.32192809488736234787031942948939; +const P10: &[f64] = &[ + 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, +]; + +pub fn exp10(x: f64) -> f64 { + let (mut y, n) = modf(x); + let u: u64 = n.to_bits(); + /* fabs(n) < 16 without raising invalid on nan */ + if (u >> 52 & 0x7ff) < 0x3ff + 4 { + if y == 0.0 { + return P10[((n as isize) + 15) as usize]; + } + y = exp2(LN10 * y); + return y * P10[((n as isize) + 15) as usize]; + } + return pow(10.0, x); +} diff --git a/library/compiler-builtins/libm/src/math/exp10f.rs b/library/compiler-builtins/libm/src/math/exp10f.rs index 8fb88a52c017f..d45fff36ea3de 100644 --- a/library/compiler-builtins/libm/src/math/exp10f.rs +++ b/library/compiler-builtins/libm/src/math/exp10f.rs @@ -1,22 +1,21 @@ -use super::{exp2, exp2f, modff}; - -const LN10_F32: f32 = 3.32192809488736234787031942948939; -const LN10_F64: f64 = 3.32192809488736234787031942948939; -const P10: &[f32] = &[ - 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7 -]; - -pub fn exp10f(x: f32) -> f32 { - let (mut y, n) = modff(x); - let u = n.to_bits(); - /* fabsf(n) < 8 without raising invalid on nan */ - if (u>>23 & 0xff) < 0x7f+3 { - if y == 0.0 { - return P10[((n as isize) + 7) as usize] - } - y = exp2f(LN10_F32 * y); - return y * P10[((n as isize) + 7) as usize]; - } - return exp2(LN10_F64 * (x as f64)) as f32; -} +use super::{exp2, exp2f, modff}; + +const LN10_F32: f32 = 3.32192809488736234787031942948939; +const LN10_F64: f64 = 3.32192809488736234787031942948939; +const P10: &[f32] = &[ + 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, +]; + +pub fn exp10f(x: f32) -> f32 { + let (mut y, n) = modff(x); + let u = n.to_bits(); + /* fabsf(n) < 8 without raising invalid on nan */ + if (u >> 23 & 0xff) < 0x7f + 3 { + if y == 0.0 { + return P10[((n as isize) + 7) as usize]; + } + y = exp2f(LN10_F32 * y); + return y * P10[((n as isize) + 7) as usize]; + } + return exp2(LN10_F64 * (x as f64)) as f32; +} diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 21c854cd00f11..6b062481dcafb 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -43,7 +43,7 @@ fn mul(x: u64, y: u64) -> (u64, u64) { t1 = xlo * ylo; t2 = xlo * yhi + xhi * ylo; t3 = xhi * yhi; - let lo = t1 + (t2 << 32); + let lo = t1.wrapping_add(t2 << 32); let hi = t3 + (t2 >> 32) + (t1 > lo) as u64; (hi, lo) } @@ -116,7 +116,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { let mut nonzero: i32 = 1; if samesign { /* r += z */ - rlo += zlo; + rlo = rlo.wrapping_add(zlo); rhi += zhi + (rlo < zlo) as u64; } else { /* r -= z */ diff --git a/library/compiler-builtins/libm/src/math/fmod.rs b/library/compiler-builtins/libm/src/math/fmod.rs index ecc9b39a5c1ec..2cdd8a9ba3fde 100644 --- a/library/compiler-builtins/libm/src/math/fmod.rs +++ b/library/compiler-builtins/libm/src/math/fmod.rs @@ -46,7 +46,7 @@ pub fn fmod(x: f64, y: f64) -> f64 { /* x mod y */ while ex > ey { - i = uxi - uyi; + i = uxi.wrapping_sub(uyi); if i >> 63 == 0 { if i == 0 { return 0.0 * x; @@ -56,7 +56,7 @@ pub fn fmod(x: f64, y: f64) -> f64 { uxi <<= 1; ex -= 1; } - i = uxi - uyi; + i = uxi.wrapping_sub(uyi); if i >> 63 == 0 { if i == 0 { return 0.0 * x; diff --git a/library/compiler-builtins/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs index 98f51f455b882..3e6779a9304fb 100644 --- a/library/compiler-builtins/libm/src/math/fmodf.rs +++ b/library/compiler-builtins/libm/src/math/fmodf.rs @@ -52,7 +52,7 @@ pub fn fmodf(x: f32, y: f32) -> f32 { /* x mod y */ while ex > ey { - i = uxi - uyi; + i = uxi.wrapping_sub(uyi); if i >> 31 == 0 { if i == 0 { return 0.0 * x; @@ -64,7 +64,7 @@ pub fn fmodf(x: f32, y: f32) -> f32 { ex -= 1; } - i = uxi - uyi; + i = uxi.wrapping_sub(uyi); if i >> 31 == 0 { if i == 0 { return 0.0 * x; diff --git a/library/compiler-builtins/libm/src/math/frexp.rs b/library/compiler-builtins/libm/src/math/frexp.rs index 45733a3aaa323..badad786aa318 100644 --- a/library/compiler-builtins/libm/src/math/frexp.rs +++ b/library/compiler-builtins/libm/src/math/frexp.rs @@ -1,20 +1,20 @@ -pub fn frexp(x: f64) -> (f64, isize) { - let mut y = x.to_bits(); - let ee = ((y>>52) & 0x7ff) as isize; - - if ee == 0 { - if x != 0.0 { - let x1p64 = f64::from_bits(0x43f0000000000000); - let (x, e) = frexp(x*x1p64); - return (x, e - 64); - } - return (x, 0); - } else if ee == 0x7ff { - return (x, 0); - } - - let e = ee - 0x3fe; - y &= 0x800fffffffffffff; - y |= 0x3fe0000000000000; - return (f64::from_bits(y), e); -} +pub fn frexp(x: f64) -> (f64, i32) { + let mut y = x.to_bits(); + let ee = ((y >> 52) & 0x7ff) as i32; + + if ee == 0 { + if x != 0.0 { + let x1p64 = f64::from_bits(0x43f0000000000000); + let (x, e) = frexp(x * x1p64); + return (x, e - 64); + } + return (x, 0); + } else if ee == 0x7ff { + return (x, 0); + } + + let e = ee - 0x3fe; + y &= 0x800fffffffffffff; + y |= 0x3fe0000000000000; + return (f64::from_bits(y), e); +} diff --git a/library/compiler-builtins/libm/src/math/frexpf.rs b/library/compiler-builtins/libm/src/math/frexpf.rs index 1c9dae0bb9836..2919c0ab02279 100644 --- a/library/compiler-builtins/libm/src/math/frexpf.rs +++ b/library/compiler-builtins/libm/src/math/frexpf.rs @@ -1,21 +1,21 @@ -pub fn frexpf(x: f32) -> (f32, isize) { - let mut y = x.to_bits(); - let ee: isize = ((y>>23) & 0xff) as isize; - - if ee == 0 { - if x != 0.0 { - let x1p64 = f32::from_bits(0x5f800000); - let (x, e) = frexpf(x*x1p64); - return (x, e - 64); - } else { - return (x, 0); - } - } else if ee == 0xff { - return (x, 0); - } - - let e = ee - 0x7e; - y &= 0x807fffff; - y |= 0x3f000000; - return (f32::from_bits(y), e); -} +pub fn frexpf(x: f32) -> (f32, i32) { + let mut y = x.to_bits(); + let ee: i32 = ((y >> 23) & 0xff) as i32; + + if ee == 0 { + if x != 0.0 { + let x1p64 = f32::from_bits(0x5f800000); + let (x, e) = frexpf(x * x1p64); + return (x, e - 64); + } else { + return (x, 0); + } + } else if ee == 0xff { + return (x, 0); + } + + let e = ee - 0x7e; + y &= 0x807fffff; + y |= 0x3f000000; + (f32::from_bits(y), e) +} diff --git a/library/compiler-builtins/libm/src/math/ilogb.rs b/library/compiler-builtins/libm/src/math/ilogb.rs index 78fe030a1cc23..8a1289ca444d8 100644 --- a/library/compiler-builtins/libm/src/math/ilogb.rs +++ b/library/compiler-builtins/libm/src/math/ilogb.rs @@ -1,31 +1,31 @@ -const FP_ILOGBNAN: isize = -1 - (((!0) >> 1)); -const FP_ILOGB0: isize = FP_ILOGBNAN; - -pub fn ilogb(x: f64) -> isize { - let mut i: u64 = x.to_bits(); - let e = ((i>>52) & 0x7ff) as isize; - - if e == 0 { - i <<= 12; - if i == 0 { - force_eval!(0.0/0.0); - return FP_ILOGB0; - } - /* subnormal x */ - let mut e = -0x3ff; - while (i>>63) == 0 { - e -= 1; - i <<= 1; - } - return e; - } - if e == 0x7ff { - force_eval!(0.0/0.0); - if (i<<12) != 0 { - return FP_ILOGBNAN; - } else { - return isize::max_value(); - } - } - return e - 0x3ff; -} +const FP_ILOGBNAN: i32 = -1 - ((!0) >> 1); +const FP_ILOGB0: i32 = FP_ILOGBNAN; + +pub fn ilogb(x: f64) -> i32 { + let mut i: u64 = x.to_bits(); + let e = ((i >> 52) & 0x7ff) as i32; + + if e == 0 { + i <<= 12; + if i == 0 { + force_eval!(0.0 / 0.0); + return FP_ILOGB0; + } + /* subnormal x */ + let mut e = -0x3ff; + while (i >> 63) == 0 { + e -= 1; + i <<= 1; + } + return e; + } + if e == 0x7ff { + force_eval!(0.0 / 0.0); + if (i << 12) != 0 { + return FP_ILOGBNAN; + } else { + return i32::max_value(); + } + } + return e - 0x3ff; +} diff --git a/library/compiler-builtins/libm/src/math/ilogbf.rs b/library/compiler-builtins/libm/src/math/ilogbf.rs index 9ca1c360665f0..1bf4670a8129f 100644 --- a/library/compiler-builtins/libm/src/math/ilogbf.rs +++ b/library/compiler-builtins/libm/src/math/ilogbf.rs @@ -1,31 +1,31 @@ -const FP_ILOGBNAN: isize = -1 - (((!0) >> 1)); -const FP_ILOGB0: isize = FP_ILOGBNAN; - -pub fn ilogbf(x: f32) -> isize { - let mut i = x.to_bits(); - let e = ((i>>23) & 0xff) as isize; - - if e == 0 { - i <<= 9; - if i == 0 { - force_eval!(0.0/0.0); - return FP_ILOGB0; - } - /* subnormal x */ - let mut e = -0x7f; - while (i>>31) == 0 { - e -= 1; - i <<= 1; - } - return e; - } - if e == 0xff { - force_eval!(0.0/0.0); - if (i<<9) != 0 { - return FP_ILOGBNAN; - } else { - return isize::max_value(); - } - } - return e - 0x7f; -} +const FP_ILOGBNAN: i32 = -1 - ((!0) >> 1); +const FP_ILOGB0: i32 = FP_ILOGBNAN; + +pub fn ilogbf(x: f32) -> i32 { + let mut i = x.to_bits(); + let e = ((i >> 23) & 0xff) as i32; + + if e == 0 { + i <<= 9; + if i == 0 { + force_eval!(0.0 / 0.0); + return FP_ILOGB0; + } + /* subnormal x */ + let mut e = -0x7f; + while (i >> 31) == 0 { + e -= 1; + i <<= 1; + } + return e; + } + if e == 0xff { + force_eval!(0.0 / 0.0); + if (i << 9) != 0 { + return FP_ILOGBNAN; + } else { + return i32::max_value(); + } + } + return e - 0x7f; +} diff --git a/library/compiler-builtins/libm/src/math/j0.rs b/library/compiler-builtins/libm/src/math/j0.rs index 02625b086db49..c4258ccca162d 100644 --- a/library/compiler-builtins/libm/src/math/j0.rs +++ b/library/compiler-builtins/libm/src/math/j0.rs @@ -1,392 +1,422 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_j0.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* j0(x), y0(x) - * Bessel function of the first and second kinds of order zero. - * Method -- j0(x): - * 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ... - * 2. Reduce x to |x| since j0(x)=j0(-x), and - * for x in (0,2) - * j0(x) = 1-z/4+ z^2*R0/S0, where z = x*x; - * (precision: |j0-1+z/4-z^2R0/S0 |<2**-63.67 ) - * for x in (2,inf) - * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0)) - * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) - * as follow: - * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4) - * = 1/sqrt(2) * (cos(x) + sin(x)) - * sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4) - * = 1/sqrt(2) * (sin(x) - cos(x)) - * (To avoid cancellation, use - * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) - * to compute the worse one.) - * - * 3 Special cases - * j0(nan)= nan - * j0(0) = 1 - * j0(inf) = 0 - * - * Method -- y0(x): - * 1. For x<2. - * Since - * y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...) - * therefore y0(x)-2/pi*j0(x)*ln(x) is an even function. - * We use the following function to approximate y0, - * y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2 - * where - * U(z) = u00 + u01*z + ... + u06*z^6 - * V(z) = 1 + v01*z + ... + v04*z^4 - * with absolute approximation error bounded by 2**-72. - * Note: For tiny x, U/V = u0 and j0(x)~1, hence - * y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27) - * 2. For x>=2. - * y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0)) - * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) - * by the method mentioned above. - * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0. - */ - -use super::{cos, get_low_word, get_high_word, fabs, log, sin, sqrt}; -const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ -const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ - -/* common method when |x|>=2 */ -fn common(ix: u32, x: f64, y0: bool) -> f64 { - let s: f64; - let mut c: f64; - let mut ss: f64; - let mut cc: f64; - let z: f64; - - /* - * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x-pi/4)-q0(x)*sin(x-pi/4)) - * y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x-pi/4)+q0(x)*cos(x-pi/4)) - * - * sin(x-pi/4) = (sin(x) - cos(x))/sqrt(2) - * cos(x-pi/4) = (sin(x) + cos(x))/sqrt(2) - * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) - */ - s = sin(x); - c = cos(x); - if y0 { - c = -c; - } - cc = s+c; - /* avoid overflow in 2*x, big ulp error when x>=0x1p1023 */ - if ix < 0x7fe00000 { - ss = s-c; - z = -cos(2.0*x); - if s*c < 0.0 { - cc = z/ss; - } else { - ss = z/cc; - } - if ix < 0x48000000 { - if y0 { - ss = -ss; - } - cc = pzero(x)*cc-qzero(x)*ss; - } - } - return INVSQRTPI*cc/sqrt(x); -} - -/* R0/S0 on [0, 2.00] */ -const R02: f64 = 1.56249999999999947958e-02; /* 0x3F8FFFFF, 0xFFFFFFFD */ -const R03: f64 = -1.89979294238854721751e-04; /* 0xBF28E6A5, 0xB61AC6E9 */ -const R04: f64 = 1.82954049532700665670e-06; /* 0x3EBEB1D1, 0x0C503919 */ -const R05: f64 = -4.61832688532103189199e-09; /* 0xBE33D5E7, 0x73D63FCE */ -const S01: f64 = 1.56191029464890010492e-02; /* 0x3F8FFCE8, 0x82C8C2A4 */ -const S02: f64 = 1.16926784663337450260e-04; /* 0x3F1EA6D2, 0xDD57DBF4 */ -const S03: f64 = 5.13546550207318111446e-07; /* 0x3EA13B54, 0xCE84D5A9 */ -const S04: f64 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ - -pub fn j0(mut x: f64) -> f64 -{ - let z: f64; - let r: f64; - let s: f64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - - /* j0(+-inf)=0, j0(nan)=nan */ - if ix >= 0x7ff00000 { - return 1.0/(x*x); - } - x = fabs(x); - - if ix >= 0x40000000 { /* |x| >= 2 */ - /* large ulp error near zeros: 2.4, 5.52, 8.6537,.. */ - return common(ix,x,false); - } - - /* 1 - x*x/4 + x*x*R(x^2)/S(x^2) */ - if ix >= 0x3f200000 { /* |x| >= 2**-13 */ - /* up to 4ulp error close to 2 */ - z = x*x; - r = z*(R02+z*(R03+z*(R04+z*R05))); - s = 1.0+z*(S01+z*(S02+z*(S03+z*S04))); - return (1.0+x/2.0)*(1.0-x/2.0) + z*(r/s); - } - - /* 1 - x*x/4 */ - /* prevent underflow */ - /* inexact should be raised when x!=0, this is not done correctly */ - if ix >= 0x38000000 { /* |x| >= 2**-127 */ - x = 0.25*x*x; - } - return 1.0 - x; -} - -const U00: f64 = -7.38042951086872317523e-02; /* 0xBFB2E4D6, 0x99CBD01F */ -const U01: f64 = 1.76666452509181115538e-01; /* 0x3FC69D01, 0x9DE9E3FC */ -const U02: f64 = -1.38185671945596898896e-02; /* 0xBF8C4CE8, 0xB16CFA97 */ -const U03: f64 = 3.47453432093683650238e-04; /* 0x3F36C54D, 0x20B29B6B */ -const U04: f64 = -3.81407053724364161125e-06; /* 0xBECFFEA7, 0x73D25CAD */ -const U05: f64 = 1.95590137035022920206e-08; /* 0x3E550057, 0x3B4EABD4 */ -const U06: f64 = -3.98205194132103398453e-11; /* 0xBDC5E43D, 0x693FB3C8 */ -const V01: f64 = 1.27304834834123699328e-02; /* 0x3F8A1270, 0x91C9C71A */ -const V02: f64 = 7.60068627350353253702e-05; /* 0x3F13ECBB, 0xF578C6C1 */ -const V03: f64 = 2.59150851840457805467e-07; /* 0x3E91642D, 0x7FF202FD */ -const V04: f64 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ - -pub fn y0(x: f64) -> f64 -{ - let z: f64; - let u: f64; - let v: f64; - let ix: u32; - let lx: u32; - - ix = get_high_word(x); - lx = get_low_word(x); - - /* y0(nan)=nan, y0(<0)=nan, y0(0)=-inf, y0(inf)=0 */ - if ((ix<<1) | lx) == 0 { - return -1.0/0.0; - } - if (ix>>31) != 0 { - return 0.0/0.0; - } - if ix >= 0x7ff00000 { - return 1.0/x; - } - - if ix >= 0x40000000 { /* x >= 2 */ - /* large ulp errors near zeros: 3.958, 7.086,.. */ - return common(ix,x,true); - } - - /* U(x^2)/V(x^2) + (2/pi)*j0(x)*log(x) */ - if ix >= 0x3e400000 { /* x >= 2**-27 */ - /* large ulp error near the first zero, x ~= 0.89 */ - z = x*x; - u = U00+z*(U01+z*(U02+z*(U03+z*(U04+z*(U05+z*U06))))); - v = 1.0+z*(V01+z*(V02+z*(V03+z*V04))); - return u/v + TPI*(j0(x)*log(x)); - } - return U00 + TPI*log(x); -} - -/* The asymptotic expansions of pzero is - * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. - * For x >= 2, We approximate pzero by - * pzero(x) = 1 + (R/S) - * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 - * S = 1 + pS0*s^2 + ... + pS4*s^10 - * and - * | pzero(x)-1-R/S | <= 2 ** ( -60.26) - */ -const PR8: [f64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ - 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ - -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */ - -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */ - -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */ - -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */ - -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */ -]; -const PS8: [f64; 5] = [ - 1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */ - 3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */ - 4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */ - 1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */ - 4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */ -]; - -const PR5: [f64; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ - -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */ - -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */ - -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */ - -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */ - -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */ - -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */ -]; -const PS5: [f64; 5] = [ - 6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */ - 1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */ - 5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */ - 9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */ - 2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */ -]; - -const PR3: [f64; 6] = [/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ - -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */ - -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */ - -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */ - -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */ - -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */ - -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */ -]; -const PS3: [f64; 5] = [ - 3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */ - 3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */ - 1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */ - 1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */ - 1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */ -]; - -const PR2: [f64; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ - -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */ - -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */ - -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */ - -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */ - -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */ - -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */ -]; -const PS2: [f64; 5] = [ - 2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */ - 1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */ - 2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */ - 1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */ - 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */ -]; - -fn pzero(x: f64) -> f64 -{ - let p: &[f64; 6]; - let q: &[f64; 5]; - let z: f64; - let r: f64; - let s: f64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - if ix >= 0x40200000 {p = &PR8; q = &PS8;} - else if ix >= 0x40122E8B {p = &PR5; q = &PS5;} - else if ix >= 0x4006DB6D {p = &PR3; q = &PS3;} - else /*ix >= 0x40000000*/{p = &PR2; q = &PS2;} - z = 1.0/(x*x); - r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); - s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); - return 1.0 + r/s; -} - - -/* For x >= 8, the asymptotic expansions of qzero is - * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. - * We approximate pzero by - * qzero(x) = s*(-1.25 + (R/S)) - * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 - * S = 1 + qS0*s^2 + ... + qS5*s^12 - * and - * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) - */ -const QR8: [f64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ - 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ - 7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */ - 1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */ - 5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */ - 8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */ - 3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */ -]; -const QS8: [f64; 6] = [ - 1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */ - 8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */ - 1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */ - 8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */ - 8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */ - -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */ -]; - -const QR5: [f64; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */ - 7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */ - 5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */ - 1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */ - 1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */ - 1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */ -]; -const QS5: [f64; 6] = [ - 8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */ - 2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */ - 1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */ - 5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */ - 3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */ - -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */ -]; - -const QR3: [f64; 6] = [/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ - 4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */ - 7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */ - 3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */ - 4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */ - 1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */ - 1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */ -]; -const QS3: [f64; 6] = [ - 4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */ - 7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */ - 3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */ - 6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */ - 2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */ - -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */ -]; - -const QR2: [f64; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */ - 7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */ - 1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */ - 1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */ - 3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */ - 1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */ -]; -const QS2: [f64; 6] = [ - 3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */ - 2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */ - 8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */ - 8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */ - 2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */ - -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */ -]; - -fn qzero(x: f64) -> f64 -{ - let p: &[f64; 6]; - let q: &[f64; 6]; - let s: f64; - let r: f64; - let z: f64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - if ix >= 0x40200000 {p = &QR8; q = &QS8;} - else if ix >= 0x40122E8B {p = &QR5; q = &QS5;} - else if ix >= 0x4006DB6D {p = &QR3; q = &QS3;} - else /*ix >= 0x40000000*/{p = &QR2; q = &QS2;} - z = 1.0/(x*x); - r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); - s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); - return (-0.125 + r/s)/x; -} +/* origin: FreeBSD /usr/src/lib/msun/src/e_j0.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* j0(x), y0(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j0(x): + * 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ... + * 2. Reduce x to |x| since j0(x)=j0(-x), and + * for x in (0,2) + * j0(x) = 1-z/4+ z^2*R0/S0, where z = x*x; + * (precision: |j0-1+z/4-z^2R0/S0 |<2**-63.67 ) + * for x in (2,inf) + * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * as follow: + * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4) + * = 1/sqrt(2) * (cos(x) + sin(x)) + * sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j0(nan)= nan + * j0(0) = 1 + * j0(inf) = 0 + * + * Method -- y0(x): + * 1. For x<2. + * Since + * y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...) + * therefore y0(x)-2/pi*j0(x)*ln(x) is an even function. + * We use the following function to approximate y0, + * y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2 + * where + * U(z) = u00 + u01*z + ... + u06*z^6 + * V(z) = 1 + v01*z + ... + v04*z^4 + * with absolute approximation error bounded by 2**-72. + * Note: For tiny x, U/V = u0 and j0(x)~1, hence + * y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27) + * 2. For x>=2. + * y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * by the method mentioned above. + * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0. + */ + +use super::{cos, fabs, get_high_word, get_low_word, log, sin, sqrt}; +const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ +const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ + +/* common method when |x|>=2 */ +fn common(ix: u32, x: f64, y0: bool) -> f64 { + let s: f64; + let mut c: f64; + let mut ss: f64; + let mut cc: f64; + let z: f64; + + /* + * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x-pi/4)-q0(x)*sin(x-pi/4)) + * y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x-pi/4)+q0(x)*cos(x-pi/4)) + * + * sin(x-pi/4) = (sin(x) - cos(x))/sqrt(2) + * cos(x-pi/4) = (sin(x) + cos(x))/sqrt(2) + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + */ + s = sin(x); + c = cos(x); + if y0 { + c = -c; + } + cc = s + c; + /* avoid overflow in 2*x, big ulp error when x>=0x1p1023 */ + if ix < 0x7fe00000 { + ss = s - c; + z = -cos(2.0 * x); + if s * c < 0.0 { + cc = z / ss; + } else { + ss = z / cc; + } + if ix < 0x48000000 { + if y0 { + ss = -ss; + } + cc = pzero(x) * cc - qzero(x) * ss; + } + } + return INVSQRTPI * cc / sqrt(x); +} + +/* R0/S0 on [0, 2.00] */ +const R02: f64 = 1.56249999999999947958e-02; /* 0x3F8FFFFF, 0xFFFFFFFD */ +const R03: f64 = -1.89979294238854721751e-04; /* 0xBF28E6A5, 0xB61AC6E9 */ +const R04: f64 = 1.82954049532700665670e-06; /* 0x3EBEB1D1, 0x0C503919 */ +const R05: f64 = -4.61832688532103189199e-09; /* 0xBE33D5E7, 0x73D63FCE */ +const S01: f64 = 1.56191029464890010492e-02; /* 0x3F8FFCE8, 0x82C8C2A4 */ +const S02: f64 = 1.16926784663337450260e-04; /* 0x3F1EA6D2, 0xDD57DBF4 */ +const S03: f64 = 5.13546550207318111446e-07; /* 0x3EA13B54, 0xCE84D5A9 */ +const S04: f64 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ + +pub fn j0(mut x: f64) -> f64 { + let z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + + /* j0(+-inf)=0, j0(nan)=nan */ + if ix >= 0x7ff00000 { + return 1.0 / (x * x); + } + x = fabs(x); + + if ix >= 0x40000000 { + /* |x| >= 2 */ + /* large ulp error near zeros: 2.4, 5.52, 8.6537,.. */ + return common(ix, x, false); + } + + /* 1 - x*x/4 + x*x*R(x^2)/S(x^2) */ + if ix >= 0x3f200000 { + /* |x| >= 2**-13 */ + /* up to 4ulp error close to 2 */ + z = x * x; + r = z * (R02 + z * (R03 + z * (R04 + z * R05))); + s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * S04))); + return (1.0 + x / 2.0) * (1.0 - x / 2.0) + z * (r / s); + } + + /* 1 - x*x/4 */ + /* prevent underflow */ + /* inexact should be raised when x!=0, this is not done correctly */ + if ix >= 0x38000000 { + /* |x| >= 2**-127 */ + x = 0.25 * x * x; + } + return 1.0 - x; +} + +const U00: f64 = -7.38042951086872317523e-02; /* 0xBFB2E4D6, 0x99CBD01F */ +const U01: f64 = 1.76666452509181115538e-01; /* 0x3FC69D01, 0x9DE9E3FC */ +const U02: f64 = -1.38185671945596898896e-02; /* 0xBF8C4CE8, 0xB16CFA97 */ +const U03: f64 = 3.47453432093683650238e-04; /* 0x3F36C54D, 0x20B29B6B */ +const U04: f64 = -3.81407053724364161125e-06; /* 0xBECFFEA7, 0x73D25CAD */ +const U05: f64 = 1.95590137035022920206e-08; /* 0x3E550057, 0x3B4EABD4 */ +const U06: f64 = -3.98205194132103398453e-11; /* 0xBDC5E43D, 0x693FB3C8 */ +const V01: f64 = 1.27304834834123699328e-02; /* 0x3F8A1270, 0x91C9C71A */ +const V02: f64 = 7.60068627350353253702e-05; /* 0x3F13ECBB, 0xF578C6C1 */ +const V03: f64 = 2.59150851840457805467e-07; /* 0x3E91642D, 0x7FF202FD */ +const V04: f64 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ + +pub fn y0(x: f64) -> f64 { + let z: f64; + let u: f64; + let v: f64; + let ix: u32; + let lx: u32; + + ix = get_high_word(x); + lx = get_low_word(x); + + /* y0(nan)=nan, y0(<0)=nan, y0(0)=-inf, y0(inf)=0 */ + if ((ix << 1) | lx) == 0 { + return -1.0 / 0.0; + } + if (ix >> 31) != 0 { + return 0.0 / 0.0; + } + if ix >= 0x7ff00000 { + return 1.0 / x; + } + + if ix >= 0x40000000 { + /* x >= 2 */ + /* large ulp errors near zeros: 3.958, 7.086,.. */ + return common(ix, x, true); + } + + /* U(x^2)/V(x^2) + (2/pi)*j0(x)*log(x) */ + if ix >= 0x3e400000 { + /* x >= 2**-27 */ + /* large ulp error near the first zero, x ~= 0.89 */ + z = x * x; + u = U00 + z * (U01 + z * (U02 + z * (U03 + z * (U04 + z * (U05 + z * U06))))); + v = 1.0 + z * (V01 + z * (V02 + z * (V03 + z * V04))); + return u / v + TPI * (j0(x) * log(x)); + } + return U00 + TPI * log(x); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +const PR8: [f64; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */ + -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */ + -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */ + -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */ + -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */ +]; +const PS8: [f64; 5] = [ + 1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */ + 3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */ + 4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */ + 1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */ + 4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */ +]; + +const PR5: [f64; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */ + -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */ + -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */ + -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */ + -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */ + -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */ +]; +const PS5: [f64; 5] = [ + 6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */ + 1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */ + 5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */ + 9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */ + 2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */ +]; + +const PR3: [f64; 6] = [ + /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */ + -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */ + -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */ + -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */ + -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */ + -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */ +]; +const PS3: [f64; 5] = [ + 3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */ + 3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */ + 1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */ + 1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */ + 1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */ +]; + +const PR2: [f64; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */ + -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */ + -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */ + -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */ + -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */ + -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */ +]; +const PS2: [f64; 5] = [ + 2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */ + 1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */ + 2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */ + 1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */ + 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */ +]; + +fn pzero(x: f64) -> f64 { + let p: &[f64; 6]; + let q: &[f64; 5]; + let z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 { + p = &PR8; + q = &PS8; + } else if ix >= 0x40122E8B { + p = &PR5; + q = &PS5; + } else if ix >= 0x4006DB6D { + p = &PR3; + q = &PS3; + } else + /*ix >= 0x40000000*/ + { + p = &PR2; + q = &PS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + return 1.0 + r / s; +} + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +const QR8: [f64; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */ + 1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */ + 5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */ + 8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */ + 3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */ +]; +const QS8: [f64; 6] = [ + 1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */ + 8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */ + 1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */ + 8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */ + 8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */ + -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */ +]; + +const QR5: [f64; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */ + 7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */ + 5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */ + 1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */ + 1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */ + 1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */ +]; +const QS5: [f64; 6] = [ + 8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */ + 2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */ + 1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */ + 5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */ + 3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */ + -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */ +]; + +const QR3: [f64; 6] = [ + /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */ + 7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */ + 3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */ + 4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */ + 1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */ + 1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */ +]; +const QS3: [f64; 6] = [ + 4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */ + 7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */ + 3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */ + 6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */ + 2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */ + -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */ +]; + +const QR2: [f64; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */ + 7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */ + 1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */ + 1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */ + 3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */ + 1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */ +]; +const QS2: [f64; 6] = [ + 3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */ + 2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */ + 8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */ + 8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */ + 2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */ + -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */ +]; + +fn qzero(x: f64) -> f64 { + let p: &[f64; 6]; + let q: &[f64; 6]; + let s: f64; + let r: f64; + let z: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 { + p = &QR8; + q = &QS8; + } else if ix >= 0x40122E8B { + p = &QR5; + q = &QS5; + } else if ix >= 0x4006DB6D { + p = &QR3; + q = &QS3; + } else + /*ix >= 0x40000000*/ + { + p = &QR2; + q = &QS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + return (-0.125 + r / s) / x; +} diff --git a/library/compiler-builtins/libm/src/math/j0f.rs b/library/compiler-builtins/libm/src/math/j0f.rs index e2faed0b256fe..91c03dbbcdd28 100644 --- a/library/compiler-builtins/libm/src/math/j0f.rs +++ b/library/compiler-builtins/libm/src/math/j0f.rs @@ -1,330 +1,359 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_j0f.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * 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. - * ==================================================== - */ - -use super::{cosf, fabsf, logf, sinf, sqrtf}; - -const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ -const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ - -fn common(ix: u32, x: f32, y0: bool) -> f32 -{ - let z: f32; - let s: f32; - let mut c: f32; - let mut ss: f32; - let mut cc: f32; - /* - * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) - * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) - */ - s = sinf(x); - c = cosf(x); - if y0 { - c = -c; - } - cc = s+c; - if ix < 0x7f000000 { - ss = s-c; - z = -cosf(2.0*x); - if s*c < 0.0 { - cc = z/ss; - } else { - ss = z/cc; - } - if ix < 0x58800000 { - if y0 { - ss = -ss; - } - cc = pzerof(x)*cc-qzerof(x)*ss; - } - } - return INVSQRTPI*cc/sqrtf(x); -} - -/* R0/S0 on [0, 2.00] */ -const R02: f32 = 1.5625000000e-02; /* 0x3c800000 */ -const R03: f32 = -1.8997929874e-04; /* 0xb947352e */ -const R04: f32 = 1.8295404516e-06; /* 0x35f58e88 */ -const R05: f32 = -4.6183270541e-09; /* 0xb19eaf3c */ -const S01: f32 = 1.5619102865e-02; /* 0x3c7fe744 */ -const S02: f32 = 1.1692678527e-04; /* 0x38f53697 */ -const S03: f32 = 5.1354652442e-07; /* 0x3509daa6 */ -const S04: f32 = 1.1661400734e-09; /* 0x30a045e8 */ - -pub fn j0f(mut x: f32) -> f32 -{ - let z: f32; - let r: f32; - let s: f32; - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; - if ix >= 0x7f800000 { - return 1.0/(x*x); - } - x = fabsf(x); - - if ix >= 0x40000000 { /* |x| >= 2 */ - /* large ulp error near zeros */ - return common(ix, x, false); - } - if ix >= 0x3a000000 { /* |x| >= 2**-11 */ - /* up to 4ulp error near 2 */ - z = x*x; - r = z*(R02+z*(R03+z*(R04+z*R05))); - s = 1.0+z*(S01+z*(S02+z*(S03+z*S04))); - return (1.0+x/2.0)*(1.0-x/2.0) + z*(r/s); - } - if ix >= 0x21800000 { /* |x| >= 2**-60 */ - x = 0.25*x*x; - } - return 1.0 - x; -} - -const U00: f32 = -7.3804296553e-02; /* 0xbd9726b5 */ -const U01: f32 = 1.7666645348e-01; /* 0x3e34e80d */ -const U02: f32 = -1.3818567619e-02; /* 0xbc626746 */ -const U03: f32 = 3.4745343146e-04; /* 0x39b62a69 */ -const U04: f32 = -3.8140706238e-06; /* 0xb67ff53c */ -const U05: f32 = 1.9559013964e-08; /* 0x32a802ba */ -const U06: f32 = -3.9820518410e-11; /* 0xae2f21eb */ -const V01: f32 = 1.2730483897e-02; /* 0x3c509385 */ -const V02: f32 = 7.6006865129e-05; /* 0x389f65e0 */ -const V03: f32 = 2.5915085189e-07; /* 0x348b216c */ -const V04: f32 = 4.4111031494e-10; /* 0x2ff280c2 */ - -pub fn y0f(x: f32) -> f32 -{ - let z: f32; - let u: f32; - let v: f32; - let ix: u32; - - ix = x.to_bits(); - if (ix & 0x7fffffff) == 0 { - return -1.0/0.0; - } - if (ix>>31) !=0 { - return 0.0/0.0; - } - if ix >= 0x7f800000 { - return 1.0/x; - } - if ix >= 0x40000000 { /* |x| >= 2.0 */ - /* large ulp error near zeros */ - return common(ix,x,true); - } - if ix >= 0x39000000 { /* x >= 2**-13 */ - /* large ulp error at x ~= 0.89 */ - z = x*x; - u = U00+z*(U01+z*(U02+z*(U03+z*(U04+z*(U05+z*U06))))); - v = 1.0+z*(V01+z*(V02+z*(V03+z*V04))); - return u/v + TPI*(j0f(x)*logf(x)); - } - return U00 + TPI*logf(x); -} - -/* The asymptotic expansions of pzero is - * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. - * For x >= 2, We approximate pzero by - * pzero(x) = 1 + (R/S) - * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 - * S = 1 + pS0*s^2 + ... + pS4*s^10 - * and - * | pzero(x)-1-R/S | <= 2 ** ( -60.26) - */ -const PR8: [f32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ - 0.0000000000e+00, /* 0x00000000 */ - -7.0312500000e-02, /* 0xbd900000 */ - -8.0816707611e+00, /* 0xc1014e86 */ - -2.5706311035e+02, /* 0xc3808814 */ - -2.4852163086e+03, /* 0xc51b5376 */ - -5.2530439453e+03, /* 0xc5a4285a */ -]; -const PS8: [f32; 5] = [ - 1.1653436279e+02, /* 0x42e91198 */ - 3.8337448730e+03, /* 0x456f9beb */ - 4.0597855469e+04, /* 0x471e95db */ - 1.1675296875e+05, /* 0x47e4087c */ - 4.7627726562e+04, /* 0x473a0bba */ -]; -const PR5: [f32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ - -1.1412546255e-11, /* 0xad48c58a */ - -7.0312492549e-02, /* 0xbd8fffff */ - -4.1596107483e+00, /* 0xc0851b88 */ - -6.7674766541e+01, /* 0xc287597b */ - -3.3123129272e+02, /* 0xc3a59d9b */ - -3.4643338013e+02, /* 0xc3ad3779 */ -]; -const PS5: [f32; 5] = [ - 6.0753936768e+01, /* 0x42730408 */ - 1.0512523193e+03, /* 0x44836813 */ - 5.9789707031e+03, /* 0x45bad7c4 */ - 9.6254453125e+03, /* 0x461665c8 */ - 2.4060581055e+03, /* 0x451660ee */ -]; - -const PR3: [f32; 6] = [/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ - -2.5470459075e-09, /* 0xb12f081b */ - -7.0311963558e-02, /* 0xbd8fffb8 */ - -2.4090321064e+00, /* 0xc01a2d95 */ - -2.1965976715e+01, /* 0xc1afba52 */ - -5.8079170227e+01, /* 0xc2685112 */ - -3.1447946548e+01, /* 0xc1fb9565 */ -]; -const PS3: [f32; 5] = [ - 3.5856033325e+01, /* 0x420f6c94 */ - 3.6151397705e+02, /* 0x43b4c1ca */ - 1.1936077881e+03, /* 0x44953373 */ - 1.1279968262e+03, /* 0x448cffe6 */ - 1.7358093262e+02, /* 0x432d94b8 */ -]; - -const PR2: [f32; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ - -8.8753431271e-08, /* 0xb3be98b7 */ - -7.0303097367e-02, /* 0xbd8ffb12 */ - -1.4507384300e+00, /* 0xbfb9b1cc */ - -7.6356959343e+00, /* 0xc0f4579f */ - -1.1193166733e+01, /* 0xc1331736 */ - -3.2336456776e+00, /* 0xc04ef40d */ -]; -const PS2: [f32; 5] = [ - 2.2220300674e+01, /* 0x41b1c32d */ - 1.3620678711e+02, /* 0x430834f0 */ - 2.7047027588e+02, /* 0x43873c32 */ - 1.5387539673e+02, /* 0x4319e01a */ - 1.4657617569e+01, /* 0x416a859a */ -]; - -fn pzerof(x: f32) -> f32 -{ - let p: &[f32; 6]; - let q: &[f32; 5]; - let z: f32; - let r: f32; - let s: f32; - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; - if ix >= 0x41000000 {p = &PR8; q = &PS8;} - else if ix >= 0x409173eb {p = &PR5; q = &PS5;} - else if ix >= 0x4036d917 {p = &PR3; q = &PS3;} - else /*ix >= 0x40000000*/{p = &PR2; q = &PS2;} - z = 1.0/(x*x); - r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); - s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); - return 1.0 + r/s; -} - - -/* For x >= 8, the asymptotic expansions of qzero is - * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. - * We approximate pzero by - * qzero(x) = s*(-1.25 + (R/S)) - * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 - * S = 1 + qS0*s^2 + ... + qS5*s^12 - * and - * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) - */ -const QR8: [f32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ - 0.0000000000e+00, /* 0x00000000 */ - 7.3242187500e-02, /* 0x3d960000 */ - 1.1768206596e+01, /* 0x413c4a93 */ - 5.5767340088e+02, /* 0x440b6b19 */ - 8.8591972656e+03, /* 0x460a6cca */ - 3.7014625000e+04, /* 0x471096a0 */ -]; -const QS8: [f32; 6] = [ - 1.6377603149e+02, /* 0x4323c6aa */ - 8.0983447266e+03, /* 0x45fd12c2 */ - 1.4253829688e+05, /* 0x480b3293 */ - 8.0330925000e+05, /* 0x49441ed4 */ - 8.4050156250e+05, /* 0x494d3359 */ - -3.4389928125e+05, /* 0xc8a7eb69 */ -]; - -const QR5: [f32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.8408595828e-11, /* 0x2da1ec79 */ - 7.3242180049e-02, /* 0x3d95ffff */ - 5.8356351852e+00, /* 0x40babd86 */ - 1.3511157227e+02, /* 0x43071c90 */ - 1.0272437744e+03, /* 0x448067cd */ - 1.9899779053e+03, /* 0x44f8bf4b */ -]; -const QS5: [f32; 6] = [ - 8.2776611328e+01, /* 0x42a58da0 */ - 2.0778142090e+03, /* 0x4501dd07 */ - 1.8847289062e+04, /* 0x46933e94 */ - 5.6751113281e+04, /* 0x475daf1d */ - 3.5976753906e+04, /* 0x470c88c1 */ - -5.3543427734e+03, /* 0xc5a752be */ -]; - -const QR3: [f32; 6] = [/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ - 4.3774099900e-09, /* 0x3196681b */ - 7.3241114616e-02, /* 0x3d95ff70 */ - 3.3442313671e+00, /* 0x405607e3 */ - 4.2621845245e+01, /* 0x422a7cc5 */ - 1.7080809021e+02, /* 0x432acedf */ - 1.6673394775e+02, /* 0x4326bbe4 */ -]; -const QS3: [f32; 6] = [ - 4.8758872986e+01, /* 0x42430916 */ - 7.0968920898e+02, /* 0x44316c1c */ - 3.7041481934e+03, /* 0x4567825f */ - 6.4604252930e+03, /* 0x45c9e367 */ - 2.5163337402e+03, /* 0x451d4557 */ - -1.4924745178e+02, /* 0xc3153f59 */ -]; - -const QR2: [f32; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.5044444979e-07, /* 0x342189db */ - 7.3223426938e-02, /* 0x3d95f62a */ - 1.9981917143e+00, /* 0x3fffc4bf */ - 1.4495602608e+01, /* 0x4167edfd */ - 3.1666231155e+01, /* 0x41fd5471 */ - 1.6252708435e+01, /* 0x4182058c */ -]; -const QS2: [f32; 6] = [ - 3.0365585327e+01, /* 0x41f2ecb8 */ - 2.6934811401e+02, /* 0x4386ac8f */ - 8.4478375244e+02, /* 0x44533229 */ - 8.8293585205e+02, /* 0x445cbbe5 */ - 2.1266638184e+02, /* 0x4354aa98 */ - -5.3109550476e+00, /* 0xc0a9f358 */ -]; - -fn qzerof(x: f32) -> f32 -{ - let p: &[f32; 6]; - let q: &[f32; 6]; - let s: f32; - let r: f32; - let z: f32; - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; - if ix >= 0x41000000 {p = &QR8; q = &QS8;} - else if ix >= 0x409173eb {p = &QR5; q = &QS5;} - else if ix >= 0x4036d917 {p = &QR3; q = &QS3;} - else /*ix >= 0x40000000*/{p = &QR2; q = &QS2;} - z = 1.0/(x*x); - r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); - s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); - return (-0.125 + r/s)/x; -} +/* origin: FreeBSD /usr/src/lib/msun/src/e_j0f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + +use super::{cosf, fabsf, logf, sinf, sqrtf}; + +const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ +const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ + +fn common(ix: u32, x: f32, y0: bool) -> f32 { + let z: f32; + let s: f32; + let mut c: f32; + let mut ss: f32; + let mut cc: f32; + /* + * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) + * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) + */ + s = sinf(x); + c = cosf(x); + if y0 { + c = -c; + } + cc = s + c; + if ix < 0x7f000000 { + ss = s - c; + z = -cosf(2.0 * x); + if s * c < 0.0 { + cc = z / ss; + } else { + ss = z / cc; + } + if ix < 0x58800000 { + if y0 { + ss = -ss; + } + cc = pzerof(x) * cc - qzerof(x) * ss; + } + } + return INVSQRTPI * cc / sqrtf(x); +} + +/* R0/S0 on [0, 2.00] */ +const R02: f32 = 1.5625000000e-02; /* 0x3c800000 */ +const R03: f32 = -1.8997929874e-04; /* 0xb947352e */ +const R04: f32 = 1.8295404516e-06; /* 0x35f58e88 */ +const R05: f32 = -4.6183270541e-09; /* 0xb19eaf3c */ +const S01: f32 = 1.5619102865e-02; /* 0x3c7fe744 */ +const S02: f32 = 1.1692678527e-04; /* 0x38f53697 */ +const S03: f32 = 5.1354652442e-07; /* 0x3509daa6 */ +const S04: f32 = 1.1661400734e-09; /* 0x30a045e8 */ + +pub fn j0f(mut x: f32) -> f32 { + let z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + return 1.0 / (x * x); + } + x = fabsf(x); + + if ix >= 0x40000000 { + /* |x| >= 2 */ + /* large ulp error near zeros */ + return common(ix, x, false); + } + if ix >= 0x3a000000 { + /* |x| >= 2**-11 */ + /* up to 4ulp error near 2 */ + z = x * x; + r = z * (R02 + z * (R03 + z * (R04 + z * R05))); + s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * S04))); + return (1.0 + x / 2.0) * (1.0 - x / 2.0) + z * (r / s); + } + if ix >= 0x21800000 { + /* |x| >= 2**-60 */ + x = 0.25 * x * x; + } + return 1.0 - x; +} + +const U00: f32 = -7.3804296553e-02; /* 0xbd9726b5 */ +const U01: f32 = 1.7666645348e-01; /* 0x3e34e80d */ +const U02: f32 = -1.3818567619e-02; /* 0xbc626746 */ +const U03: f32 = 3.4745343146e-04; /* 0x39b62a69 */ +const U04: f32 = -3.8140706238e-06; /* 0xb67ff53c */ +const U05: f32 = 1.9559013964e-08; /* 0x32a802ba */ +const U06: f32 = -3.9820518410e-11; /* 0xae2f21eb */ +const V01: f32 = 1.2730483897e-02; /* 0x3c509385 */ +const V02: f32 = 7.6006865129e-05; /* 0x389f65e0 */ +const V03: f32 = 2.5915085189e-07; /* 0x348b216c */ +const V04: f32 = 4.4111031494e-10; /* 0x2ff280c2 */ + +pub fn y0f(x: f32) -> f32 { + let z: f32; + let u: f32; + let v: f32; + let ix: u32; + + ix = x.to_bits(); + if (ix & 0x7fffffff) == 0 { + return -1.0 / 0.0; + } + if (ix >> 31) != 0 { + return 0.0 / 0.0; + } + if ix >= 0x7f800000 { + return 1.0 / x; + } + if ix >= 0x40000000 { + /* |x| >= 2.0 */ + /* large ulp error near zeros */ + return common(ix, x, true); + } + if ix >= 0x39000000 { + /* x >= 2**-13 */ + /* large ulp error at x ~= 0.89 */ + z = x * x; + u = U00 + z * (U01 + z * (U02 + z * (U03 + z * (U04 + z * (U05 + z * U06))))); + v = 1.0 + z * (V01 + z * (V02 + z * (V03 + z * V04))); + return u / v + TPI * (j0f(x) * logf(x)); + } + return U00 + TPI * logf(x); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +const PR8: [f32; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -7.0312500000e-02, /* 0xbd900000 */ + -8.0816707611e+00, /* 0xc1014e86 */ + -2.5706311035e+02, /* 0xc3808814 */ + -2.4852163086e+03, /* 0xc51b5376 */ + -5.2530439453e+03, /* 0xc5a4285a */ +]; +const PS8: [f32; 5] = [ + 1.1653436279e+02, /* 0x42e91198 */ + 3.8337448730e+03, /* 0x456f9beb */ + 4.0597855469e+04, /* 0x471e95db */ + 1.1675296875e+05, /* 0x47e4087c */ + 4.7627726562e+04, /* 0x473a0bba */ +]; +const PR5: [f32; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.1412546255e-11, /* 0xad48c58a */ + -7.0312492549e-02, /* 0xbd8fffff */ + -4.1596107483e+00, /* 0xc0851b88 */ + -6.7674766541e+01, /* 0xc287597b */ + -3.3123129272e+02, /* 0xc3a59d9b */ + -3.4643338013e+02, /* 0xc3ad3779 */ +]; +const PS5: [f32; 5] = [ + 6.0753936768e+01, /* 0x42730408 */ + 1.0512523193e+03, /* 0x44836813 */ + 5.9789707031e+03, /* 0x45bad7c4 */ + 9.6254453125e+03, /* 0x461665c8 */ + 2.4060581055e+03, /* 0x451660ee */ +]; + +const PR3: [f32; 6] = [ + /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.5470459075e-09, /* 0xb12f081b */ + -7.0311963558e-02, /* 0xbd8fffb8 */ + -2.4090321064e+00, /* 0xc01a2d95 */ + -2.1965976715e+01, /* 0xc1afba52 */ + -5.8079170227e+01, /* 0xc2685112 */ + -3.1447946548e+01, /* 0xc1fb9565 */ +]; +const PS3: [f32; 5] = [ + 3.5856033325e+01, /* 0x420f6c94 */ + 3.6151397705e+02, /* 0x43b4c1ca */ + 1.1936077881e+03, /* 0x44953373 */ + 1.1279968262e+03, /* 0x448cffe6 */ + 1.7358093262e+02, /* 0x432d94b8 */ +]; + +const PR2: [f32; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.8753431271e-08, /* 0xb3be98b7 */ + -7.0303097367e-02, /* 0xbd8ffb12 */ + -1.4507384300e+00, /* 0xbfb9b1cc */ + -7.6356959343e+00, /* 0xc0f4579f */ + -1.1193166733e+01, /* 0xc1331736 */ + -3.2336456776e+00, /* 0xc04ef40d */ +]; +const PS2: [f32; 5] = [ + 2.2220300674e+01, /* 0x41b1c32d */ + 1.3620678711e+02, /* 0x430834f0 */ + 2.7047027588e+02, /* 0x43873c32 */ + 1.5387539673e+02, /* 0x4319e01a */ + 1.4657617569e+01, /* 0x416a859a */ +]; + +fn pzerof(x: f32) -> f32 { + let p: &[f32; 6]; + let q: &[f32; 5]; + let z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 { + p = &PR8; + q = &PS8; + } else if ix >= 0x409173eb { + p = &PR5; + q = &PS5; + } else if ix >= 0x4036d917 { + p = &PR3; + q = &PS3; + } else + /*ix >= 0x40000000*/ + { + p = &PR2; + q = &PS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + return 1.0 + r / s; +} + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +const QR8: [f32; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 7.3242187500e-02, /* 0x3d960000 */ + 1.1768206596e+01, /* 0x413c4a93 */ + 5.5767340088e+02, /* 0x440b6b19 */ + 8.8591972656e+03, /* 0x460a6cca */ + 3.7014625000e+04, /* 0x471096a0 */ +]; +const QS8: [f32; 6] = [ + 1.6377603149e+02, /* 0x4323c6aa */ + 8.0983447266e+03, /* 0x45fd12c2 */ + 1.4253829688e+05, /* 0x480b3293 */ + 8.0330925000e+05, /* 0x49441ed4 */ + 8.4050156250e+05, /* 0x494d3359 */ + -3.4389928125e+05, /* 0xc8a7eb69 */ +]; + +const QR5: [f32; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.8408595828e-11, /* 0x2da1ec79 */ + 7.3242180049e-02, /* 0x3d95ffff */ + 5.8356351852e+00, /* 0x40babd86 */ + 1.3511157227e+02, /* 0x43071c90 */ + 1.0272437744e+03, /* 0x448067cd */ + 1.9899779053e+03, /* 0x44f8bf4b */ +]; +const QS5: [f32; 6] = [ + 8.2776611328e+01, /* 0x42a58da0 */ + 2.0778142090e+03, /* 0x4501dd07 */ + 1.8847289062e+04, /* 0x46933e94 */ + 5.6751113281e+04, /* 0x475daf1d */ + 3.5976753906e+04, /* 0x470c88c1 */ + -5.3543427734e+03, /* 0xc5a752be */ +]; + +const QR3: [f32; 6] = [ + /* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.3774099900e-09, /* 0x3196681b */ + 7.3241114616e-02, /* 0x3d95ff70 */ + 3.3442313671e+00, /* 0x405607e3 */ + 4.2621845245e+01, /* 0x422a7cc5 */ + 1.7080809021e+02, /* 0x432acedf */ + 1.6673394775e+02, /* 0x4326bbe4 */ +]; +const QS3: [f32; 6] = [ + 4.8758872986e+01, /* 0x42430916 */ + 7.0968920898e+02, /* 0x44316c1c */ + 3.7041481934e+03, /* 0x4567825f */ + 6.4604252930e+03, /* 0x45c9e367 */ + 2.5163337402e+03, /* 0x451d4557 */ + -1.4924745178e+02, /* 0xc3153f59 */ +]; + +const QR2: [f32; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.5044444979e-07, /* 0x342189db */ + 7.3223426938e-02, /* 0x3d95f62a */ + 1.9981917143e+00, /* 0x3fffc4bf */ + 1.4495602608e+01, /* 0x4167edfd */ + 3.1666231155e+01, /* 0x41fd5471 */ + 1.6252708435e+01, /* 0x4182058c */ +]; +const QS2: [f32; 6] = [ + 3.0365585327e+01, /* 0x41f2ecb8 */ + 2.6934811401e+02, /* 0x4386ac8f */ + 8.4478375244e+02, /* 0x44533229 */ + 8.8293585205e+02, /* 0x445cbbe5 */ + 2.1266638184e+02, /* 0x4354aa98 */ + -5.3109550476e+00, /* 0xc0a9f358 */ +]; + +fn qzerof(x: f32) -> f32 { + let p: &[f32; 6]; + let q: &[f32; 6]; + let s: f32; + let r: f32; + let z: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 { + p = &QR8; + q = &QS8; + } else if ix >= 0x409173eb { + p = &QR5; + q = &QS5; + } else if ix >= 0x4036d917 { + p = &QR3; + q = &QS3; + } else + /*ix >= 0x40000000*/ + { + p = &QR2; + q = &QS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + return (-0.125 + r / s) / x; +} diff --git a/library/compiler-builtins/libm/src/math/j1.rs b/library/compiler-builtins/libm/src/math/j1.rs index 92289a613200b..02a65ca5a2916 100644 --- a/library/compiler-builtins/libm/src/math/j1.rs +++ b/library/compiler-builtins/libm/src/math/j1.rs @@ -1,387 +1,414 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_j1.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* j1(x), y1(x) - * Bessel function of the first and second kinds of order zero. - * Method -- j1(x): - * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ... - * 2. Reduce x to |x| since j1(x)=-j1(-x), and - * for x in (0,2) - * j1(x) = x/2 + x*z*R0/S0, where z = x*x; - * (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 ) - * for x in (2,inf) - * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1)) - * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) - * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) - * as follow: - * cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) - * = 1/sqrt(2) * (sin(x) - cos(x)) - * sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) - * = -1/sqrt(2) * (sin(x) + cos(x)) - * (To avoid cancellation, use - * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) - * to compute the worse one.) - * - * 3 Special cases - * j1(nan)= nan - * j1(0) = 0 - * j1(inf) = 0 - * - * Method -- y1(x): - * 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN - * 2. For x<2. - * Since - * y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...) - * therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function. - * We use the following function to approximate y1, - * y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2 - * where for x in [0,2] (abs err less than 2**-65.89) - * U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4 - * V(z) = 1 + v0[0]*z + ... + v0[4]*z^5 - * Note: For tiny x, 1/x dominate y1 and hence - * y1(tiny) = -2/pi/tiny, (choose tiny<2**-54) - * 3. For x>=2. - * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) - * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) - * by method mentioned above. - */ - -use super::{cos, get_high_word, get_low_word, fabs, log, sin, sqrt}; - -const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ -const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ - -fn common(ix: u32, x: f64, y1: bool, sign: bool) -> f64 -{ - let z: f64; - let mut s: f64; - let c: f64; - let mut ss: f64; - let mut cc: f64; - - /* - * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x-3pi/4)-q1(x)*sin(x-3pi/4)) - * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x-3pi/4)+q1(x)*cos(x-3pi/4)) - * - * sin(x-3pi/4) = -(sin(x) + cos(x))/sqrt(2) - * cos(x-3pi/4) = (sin(x) - cos(x))/sqrt(2) - * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) - */ - s = sin(x); - if y1 { - s = -s; - } - c = cos(x); - cc = s-c; - if ix < 0x7fe00000 { - /* avoid overflow in 2*x */ - ss = -s-c; - z = cos(2.0*x); - if s*c > 0.0 { - cc = z/ss; - } else { - ss = z/cc; - } - if ix < 0x48000000 { - if y1 { - ss = -ss; - } - cc = pone(x)*cc-qone(x)*ss; - } - } - if sign { - cc = -cc; - } - return INVSQRTPI*cc/sqrt(x); -} - -/* R0/S0 on [0,2] */ -const R00: f64 = -6.25000000000000000000e-02; /* 0xBFB00000, 0x00000000 */ -const R01: f64 = 1.40705666955189706048e-03; /* 0x3F570D9F, 0x98472C61 */ -const R02: f64 = -1.59955631084035597520e-05; /* 0xBEF0C5C6, 0xBA169668 */ -const R03: f64 = 4.96727999609584448412e-08; /* 0x3E6AAAFA, 0x46CA0BD9 */ -const S01: f64 = 1.91537599538363460805e-02; /* 0x3F939D0B, 0x12637E53 */ -const S02: f64 = 1.85946785588630915560e-04; /* 0x3F285F56, 0xB9CDF664 */ -const S03: f64 = 1.17718464042623683263e-06; /* 0x3EB3BFF8, 0x333F8498 */ -const S04: f64 = 5.04636257076217042715e-09; /* 0x3E35AC88, 0xC97DFF2C */ -const S05: f64 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ - -pub fn j1(x: f64) -> f64 -{ - let mut z: f64; - let r: f64; - let s: f64; - let mut ix: u32; - let sign: bool; - - ix = get_high_word(x); - sign = (ix>>31) != 0; - ix &= 0x7fffffff; - if ix >= 0x7ff00000 { - return 1.0/(x*x); - } - if ix >= 0x40000000 { /* |x| >= 2 */ - return common(ix, fabs(x), false, sign); - } - if ix >= 0x38000000 { /* |x| >= 2**-127 */ - z = x*x; - r = z*(R00+z*(R01+z*(R02+z*R03))); - s = 1.0+z*(S01+z*(S02+z*(S03+z*(S04+z*S05)))); - z = r/s; - } else { - /* avoid underflow, raise inexact if x!=0 */ - z = x; - } - return (0.5 + z)*x; -} - -const U0: [f64; 5] = [ - -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */ - 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */ - -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */ - 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */ - -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */ -]; -const V0: [f64; 5] = [ - 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */ - 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */ - 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */ - 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */ - 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ -]; - -pub fn y1(x: f64) -> f64 -{ - let z: f64; - let u: f64; - let v: f64; - let ix: u32; - let lx: u32; - - ix = get_high_word(x); - lx = get_low_word(x); - - /* y1(nan)=nan, y1(<0)=nan, y1(0)=-inf, y1(inf)=0 */ - if (ix<<1 | lx) == 0 { - return -1.0/0.0; - } - if (ix>>31) != 0 { - return 0.0/0.0; - } - if ix >= 0x7ff00000 { - return 1.0/x; - } - - if ix >= 0x40000000 { /* x >= 2 */ - return common(ix, x, true, false); - } - if ix < 0x3c900000 { /* x < 2**-54 */ - return -TPI/x; - } - z = x*x; - u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4]))); - v = 1.0+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4])))); - return x*(u/v) + TPI*(j1(x)*log(x)-1.0/x); -} - -/* For x >= 8, the asymptotic expansions of pone is - * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. - * We approximate pone by - * pone(x) = 1 + (R/S) - * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 - * S = 1 + ps0*s^2 + ... + ps4*s^10 - * and - * | pone(x)-1-R/S | <= 2 ** ( -60.06) - */ - -const PR8: [f64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ - 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ - 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */ - 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */ - 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */ - 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */ - 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */ -]; -const PS8: [f64; 5] = [ - 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */ - 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */ - 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */ - 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */ - 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */ -]; - -const PR5: [f64; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */ - 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */ - 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */ - 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */ - 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */ - 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */ -]; -const PS5: [f64; 5] = [ - 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */ - 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */ - 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */ - 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */ - 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */ -]; - -const PR3: [f64; 6] = [ - 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */ - 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */ - 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */ - 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */ - 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */ - 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */ -]; -const PS3: [f64; 5] = [ - 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */ - 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */ - 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */ - 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */ - 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */ -]; - -const PR2: [f64; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */ - 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */ - 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */ - 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */ - 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */ - 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */ -]; -const PS2: [f64; 5] = [ - 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */ - 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */ - 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */ - 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */ - 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */ -]; - -fn pone(x: f64) -> f64 -{ - let p: &[f64; 6]; - let q: &[f64; 5]; - let z: f64; - let r: f64; - let s: f64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - if ix >= 0x40200000 {p = &PR8; q = &PS8;} - else if ix >= 0x40122E8B {p = &PR5; q = &PS5;} - else if ix >= 0x4006DB6D {p = &PR3; q = &PS3;} - else /*ix >= 0x40000000*/{p = &PR2; q = &PS2;} - z = 1.0/(x*x); - r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); - s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); - return 1.0+ r/s; -} - -/* For x >= 8, the asymptotic expansions of qone is - * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. - * We approximate pone by - * qone(x) = s*(0.375 + (R/S)) - * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 - * S = 1 + qs1*s^2 + ... + qs6*s^12 - * and - * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) - */ - -const QR8: [f64; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ - 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ - -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */ - -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */ - -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */ - -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */ - -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */ -]; -const QS8: [f64; 6] = [ - 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */ - 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */ - 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */ - 7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */ - 6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */ - -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */ -]; - -const QR5: [f64; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ - -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */ - -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */ - -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */ - -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */ - -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */ - -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */ -]; -const QS5: [f64; 6] = [ - 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */ - 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */ - 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */ - 4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */ - 2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */ - -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */ -]; - -const QR3: [f64; 6] = [ - -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */ - -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */ - -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */ - -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */ - -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */ - -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */ -]; -const QS3: [f64; 6] = [ - 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */ - 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */ - 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */ - 5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */ - 1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */ - -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */ -]; - -const QR2: [f64; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ - -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */ - -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */ - -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */ - -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */ - -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */ - -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */ -]; -const QS2: [f64; 6] = [ - 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */ - 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */ - 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */ - 7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */ - 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */ - -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */ -]; - -fn qone(x: f64) -> f64 -{ - let p: &[f64; 6]; - let q: &[f64; 6]; - let s: f64; - let r: f64; - let z: f64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - if ix >= 0x40200000 {p = &QR8; q = &QS8;} - else if ix >= 0x40122E8B {p = &QR5; q = &QS5;} - else if ix >= 0x4006DB6D {p = &QR3; q = &QS3;} - else /*ix >= 0x40000000*/{p = &QR2; q = &QS2;} - z = 1.0/(x*x); - r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); - s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); - return (0.375 + r/s)/x; -} +/* origin: FreeBSD /usr/src/lib/msun/src/e_j1.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* j1(x), y1(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j1(x): + * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ... + * 2. Reduce x to |x| since j1(x)=-j1(-x), and + * for x in (0,2) + * j1(x) = x/2 + x*z*R0/S0, where z = x*x; + * (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 ) + * for x in (2,inf) + * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1)) + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * as follow: + * cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) + * = -1/sqrt(2) * (sin(x) + cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j1(nan)= nan + * j1(0) = 0 + * j1(inf) = 0 + * + * Method -- y1(x): + * 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN + * 2. For x<2. + * Since + * y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...) + * therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function. + * We use the following function to approximate y1, + * y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2 + * where for x in [0,2] (abs err less than 2**-65.89) + * U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4 + * V(z) = 1 + v0[0]*z + ... + v0[4]*z^5 + * Note: For tiny x, 1/x dominate y1 and hence + * y1(tiny) = -2/pi/tiny, (choose tiny<2**-54) + * 3. For x>=2. + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * by method mentioned above. + */ + +use super::{cos, fabs, get_high_word, get_low_word, log, sin, sqrt}; + +const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ +const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ + +fn common(ix: u32, x: f64, y1: bool, sign: bool) -> f64 { + let z: f64; + let mut s: f64; + let c: f64; + let mut ss: f64; + let mut cc: f64; + + /* + * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x-3pi/4)-q1(x)*sin(x-3pi/4)) + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x-3pi/4)+q1(x)*cos(x-3pi/4)) + * + * sin(x-3pi/4) = -(sin(x) + cos(x))/sqrt(2) + * cos(x-3pi/4) = (sin(x) - cos(x))/sqrt(2) + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + */ + s = sin(x); + if y1 { + s = -s; + } + c = cos(x); + cc = s - c; + if ix < 0x7fe00000 { + /* avoid overflow in 2*x */ + ss = -s - c; + z = cos(2.0 * x); + if s * c > 0.0 { + cc = z / ss; + } else { + ss = z / cc; + } + if ix < 0x48000000 { + if y1 { + ss = -ss; + } + cc = pone(x) * cc - qone(x) * ss; + } + } + if sign { + cc = -cc; + } + return INVSQRTPI * cc / sqrt(x); +} + +/* R0/S0 on [0,2] */ +const R00: f64 = -6.25000000000000000000e-02; /* 0xBFB00000, 0x00000000 */ +const R01: f64 = 1.40705666955189706048e-03; /* 0x3F570D9F, 0x98472C61 */ +const R02: f64 = -1.59955631084035597520e-05; /* 0xBEF0C5C6, 0xBA169668 */ +const R03: f64 = 4.96727999609584448412e-08; /* 0x3E6AAAFA, 0x46CA0BD9 */ +const S01: f64 = 1.91537599538363460805e-02; /* 0x3F939D0B, 0x12637E53 */ +const S02: f64 = 1.85946785588630915560e-04; /* 0x3F285F56, 0xB9CDF664 */ +const S03: f64 = 1.17718464042623683263e-06; /* 0x3EB3BFF8, 0x333F8498 */ +const S04: f64 = 5.04636257076217042715e-09; /* 0x3E35AC88, 0xC97DFF2C */ +const S05: f64 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ + +pub fn j1(x: f64) -> f64 { + let mut z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + let sign: bool; + + ix = get_high_word(x); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + if ix >= 0x7ff00000 { + return 1.0 / (x * x); + } + if ix >= 0x40000000 { + /* |x| >= 2 */ + return common(ix, fabs(x), false, sign); + } + if ix >= 0x38000000 { + /* |x| >= 2**-127 */ + z = x * x; + r = z * (R00 + z * (R01 + z * (R02 + z * R03))); + s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * (S04 + z * S05)))); + z = r / s; + } else { + /* avoid underflow, raise inexact if x!=0 */ + z = x; + } + return (0.5 + z) * x; +} + +const U0: [f64; 5] = [ + -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */ + 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */ + -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */ + 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */ + -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */ +]; +const V0: [f64; 5] = [ + 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */ + 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */ + 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */ + 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */ + 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ +]; + +pub fn y1(x: f64) -> f64 { + let z: f64; + let u: f64; + let v: f64; + let ix: u32; + let lx: u32; + + ix = get_high_word(x); + lx = get_low_word(x); + + /* y1(nan)=nan, y1(<0)=nan, y1(0)=-inf, y1(inf)=0 */ + if (ix << 1 | lx) == 0 { + return -1.0 / 0.0; + } + if (ix >> 31) != 0 { + return 0.0 / 0.0; + } + if ix >= 0x7ff00000 { + return 1.0 / x; + } + + if ix >= 0x40000000 { + /* x >= 2 */ + return common(ix, x, true, false); + } + if ix < 0x3c900000 { + /* x < 2**-54 */ + return -TPI / x; + } + z = x * x; + u = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); + v = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); + return x * (u / v) + TPI * (j1(x) * log(x) - 1.0 / x); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +const PR8: [f64; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */ + 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */ + 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */ + 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */ + 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */ +]; +const PS8: [f64; 5] = [ + 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */ + 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */ + 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */ + 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */ + 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */ +]; + +const PR5: [f64; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */ + 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */ + 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */ + 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */ + 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */ + 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */ +]; +const PS5: [f64; 5] = [ + 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */ + 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */ + 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */ + 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */ + 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */ +]; + +const PR3: [f64; 6] = [ + 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */ + 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */ + 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */ + 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */ + 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */ + 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */ +]; +const PS3: [f64; 5] = [ + 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */ + 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */ + 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */ + 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */ + 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */ +]; + +const PR2: [f64; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */ + 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */ + 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */ + 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */ + 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */ + 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */ +]; +const PS2: [f64; 5] = [ + 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */ + 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */ + 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */ + 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */ + 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */ +]; + +fn pone(x: f64) -> f64 { + let p: &[f64; 6]; + let q: &[f64; 5]; + let z: f64; + let r: f64; + let s: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 { + p = &PR8; + q = &PS8; + } else if ix >= 0x40122E8B { + p = &PR5; + q = &PS5; + } else if ix >= 0x4006DB6D { + p = &PR3; + q = &PS3; + } else + /*ix >= 0x40000000*/ + { + p = &PR2; + q = &PS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + return 1.0 + r / s; +} + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +const QR8: [f64; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */ + -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */ + -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */ + -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */ + -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */ +]; +const QS8: [f64; 6] = [ + 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */ + 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */ + 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */ + 7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */ + 6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */ + -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */ +]; + +const QR5: [f64; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */ + -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */ + -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */ + -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */ + -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */ + -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */ +]; +const QS5: [f64; 6] = [ + 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */ + 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */ + 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */ + 4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */ + 2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */ + -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */ +]; + +const QR3: [f64; 6] = [ + -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */ + -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */ + -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */ + -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */ + -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */ + -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */ +]; +const QS3: [f64; 6] = [ + 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */ + 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */ + 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */ + 5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */ + 1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */ + -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */ +]; + +const QR2: [f64; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */ + -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */ + -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */ + -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */ + -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */ + -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */ +]; +const QS2: [f64; 6] = [ + 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */ + 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */ + 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */ + 7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */ + 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */ + -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */ +]; + +fn qone(x: f64) -> f64 { + let p: &[f64; 6]; + let q: &[f64; 6]; + let s: f64; + let r: f64; + let z: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + if ix >= 0x40200000 { + p = &QR8; + q = &QS8; + } else if ix >= 0x40122E8B { + p = &QR5; + q = &QS5; + } else if ix >= 0x4006DB6D { + p = &QR3; + q = &QS3; + } else + /*ix >= 0x40000000*/ + { + p = &QR2; + q = &QS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + return (0.375 + r / s) / x; +} diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs index 7cf9c45b98e97..83ac1acffdc43 100644 --- a/library/compiler-builtins/libm/src/math/j1f.rs +++ b/library/compiler-builtins/libm/src/math/j1f.rs @@ -1,331 +1,358 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_j1f.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * 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. - * ==================================================== - */ - -use super::{cosf, fabsf, logf, sinf, sqrtf}; - -const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ -const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ - -fn common(ix: u32, x: f32, y1: bool, sign: bool) -> f32 -{ - let z: f64; - let mut s: f64; - let c: f64; - let mut ss: f64; - let mut cc: f64; - - s = sinf(x) as f64; - if y1 { - s = -s; - } - c = cosf(x) as f64; - cc = s-c; - if ix < 0x7f000000 { - ss = -s-c; - z = cosf(2.0*x) as f64; - if s*c > 0.0 { - cc = z/ss; - } else { - ss = z/cc; - } - if ix < 0x58800000 { - if y1 { - ss = -ss; - } - cc = (ponef(x) as f64)*cc-(qonef(x) as f64)*ss; - } - } - if sign { - cc = -cc; - } - return INVSQRTPI*(cc as f32)/sqrtf(x); -} - -/* R0/S0 on [0,2] */ -const R00: f32 = -6.2500000000e-02; /* 0xbd800000 */ -const R01: f32 = 1.4070566976e-03; /* 0x3ab86cfd */ -const R02: f32 = -1.5995563444e-05; /* 0xb7862e36 */ -const R03: f32 = 4.9672799207e-08; /* 0x335557d2 */ -const S01: f32 = 1.9153760746e-02; /* 0x3c9ce859 */ -const S02: f32 = 1.8594678841e-04; /* 0x3942fab6 */ -const S03: f32 = 1.1771846857e-06; /* 0x359dffc2 */ -const S04: f32 = 5.0463624390e-09; /* 0x31ad6446 */ -const S05: f32 = 1.2354227016e-11; /* 0x2d59567e */ - -pub fn j1f(x: f32) -> f32 -{ - let mut z: f32; - let r: f32; - let s: f32; - let mut ix: u32; - let sign: bool; - - ix = x.to_bits(); - sign = (ix>>31) != 0; - ix &= 0x7fffffff; - if ix >= 0x7f800000 { - return 1.0/(x*x); - } - if ix >= 0x40000000 { /* |x| >= 2 */ - return common(ix, fabsf(x), false, sign); - } - if ix >= 0x39000000 { /* |x| >= 2**-13 */ - z = x*x; - r = z*(R00+z*(R01+z*(R02+z*R03))); - s = 1.0+z*(S01+z*(S02+z*(S03+z*(S04+z*S05)))); - z = 0.5 + r/s; - } else { - z = 0.5; - } - return z*x; -} - -const U0: [f32; 5] = [ - -1.9605709612e-01, /* 0xbe48c331 */ - 5.0443872809e-02, /* 0x3d4e9e3c */ - -1.9125689287e-03, /* 0xbafaaf2a */ - 2.3525259166e-05, /* 0x37c5581c */ - -9.1909917899e-08, /* 0xb3c56003 */ -]; -const V0: [f32; 5] = [ - 1.9916731864e-02, /* 0x3ca3286a */ - 2.0255257550e-04, /* 0x3954644b */ - 1.3560879779e-06, /* 0x35b602d4 */ - 6.2274145840e-09, /* 0x31d5f8eb */ - 1.6655924903e-11, /* 0x2d9281cf */ -]; - -pub fn y1f(x: f32) -> f32 -{ - let z: f32; - let u: f32; - let v: f32; - let ix: u32; - - ix = x.to_bits(); - if (ix & 0x7fffffff) == 0 { - return -1.0/0.0; - } - if (ix>>31) != 0{ - return 0.0/0.0; - } - if ix >= 0x7f800000 { - return 1.0/x; - } - if ix >= 0x40000000 { /* |x| >= 2.0 */ - return common(ix,x,true,false); - } - if ix < 0x33000000 { /* x < 2**-25 */ - return -TPI/x; - } - z = x*x; - u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4]))); - v = 1.0+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4])))); - return x*(u/v) + TPI*(j1f(x)*logf(x)-1.0/x); -} - -/* For x >= 8, the asymptotic expansions of pone is - * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. - * We approximate pone by - * pone(x) = 1 + (R/S) - * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 - * S = 1 + ps0*s^2 + ... + ps4*s^10 - * and - * | pone(x)-1-R/S | <= 2 ** ( -60.06) - */ - -const PR8: [f32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ - 0.0000000000e+00, /* 0x00000000 */ - 1.1718750000e-01, /* 0x3df00000 */ - 1.3239480972e+01, /* 0x4153d4ea */ - 4.1205184937e+02, /* 0x43ce06a3 */ - 3.8747453613e+03, /* 0x45722bed */ - 7.9144794922e+03, /* 0x45f753d6 */ -]; -const PS8: [f32; 5] = [ - 1.1420736694e+02, /* 0x42e46a2c */ - 3.6509309082e+03, /* 0x45642ee5 */ - 3.6956207031e+04, /* 0x47105c35 */ - 9.7602796875e+04, /* 0x47bea166 */ - 3.0804271484e+04, /* 0x46f0a88b */ -]; - -const PR5: [f32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ - 1.3199052094e-11, /* 0x2d68333f */ - 1.1718749255e-01, /* 0x3defffff */ - 6.8027510643e+00, /* 0x40d9b023 */ - 1.0830818176e+02, /* 0x42d89dca */ - 5.1763616943e+02, /* 0x440168b7 */ - 5.2871520996e+02, /* 0x44042dc6 */ -]; -const PS5: [f32; 5] = [ - 5.9280597687e+01, /* 0x426d1f55 */ - 9.9140142822e+02, /* 0x4477d9b1 */ - 5.3532670898e+03, /* 0x45a74a23 */ - 7.8446904297e+03, /* 0x45f52586 */ - 1.5040468750e+03, /* 0x44bc0180 */ -]; - -const PR3: [f32; 6] = [ - 3.0250391081e-09, /* 0x314fe10d */ - 1.1718686670e-01, /* 0x3defffab */ - 3.9329774380e+00, /* 0x407bb5e7 */ - 3.5119403839e+01, /* 0x420c7a45 */ - 9.1055007935e+01, /* 0x42b61c2a */ - 4.8559066772e+01, /* 0x42423c7c */ -]; -const PS3: [f32; 5] = [ - 3.4791309357e+01, /* 0x420b2a4d */ - 3.3676245117e+02, /* 0x43a86198 */ - 1.0468714600e+03, /* 0x4482dbe3 */ - 8.9081134033e+02, /* 0x445eb3ed */ - 1.0378793335e+02, /* 0x42cf936c */ -]; - -const PR2: [f32; 6] = [/* for x in [2.8570,2]=1/[0.3499,0.5] */ - 1.0771083225e-07, /* 0x33e74ea8 */ - 1.1717621982e-01, /* 0x3deffa16 */ - 2.3685150146e+00, /* 0x401795c0 */ - 1.2242610931e+01, /* 0x4143e1bc */ - 1.7693971634e+01, /* 0x418d8d41 */ - 5.0735230446e+00, /* 0x40a25a4d */ -]; -const PS2: [f32; 5] = [ - 2.1436485291e+01, /* 0x41ab7dec */ - 1.2529022980e+02, /* 0x42fa9499 */ - 2.3227647400e+02, /* 0x436846c7 */ - 1.1767937469e+02, /* 0x42eb5bd7 */ - 8.3646392822e+00, /* 0x4105d590 */ -]; - -fn ponef(x: f32) -> f32 -{ - let p: &[f32; 6]; - let q: &[f32; 5]; - let z: f32; - let r: f32; - let s: f32; - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; - if ix >= 0x41000000 {p = &PR8; q = &PS8;} - else if ix >= 0x409173eb {p = &PR5; q = &PS5;} - else if ix >= 0x4036d917 {p = &PR3; q = &PS3;} - else /*ix >= 0x40000000*/{p = &PR2; q = &PS2;} - z = 1.0/(x*x); - r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); - s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); - return 1.0 + r/s; -} - -/* For x >= 8, the asymptotic expansions of qone is - * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. - * We approximate pone by - * qone(x) = s*(0.375 + (R/S)) - * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 - * S = 1 + qs1*s^2 + ... + qs6*s^12 - * and - * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) - */ - -const QR8: [f32; 6] = [ /* for x in [inf, 8]=1/[0,0.125] */ - 0.0000000000e+00, /* 0x00000000 */ - -1.0253906250e-01, /* 0xbdd20000 */ - -1.6271753311e+01, /* 0xc1822c8d */ - -7.5960174561e+02, /* 0xc43de683 */ - -1.1849806641e+04, /* 0xc639273a */ - -4.8438511719e+04, /* 0xc73d3683 */ -]; -const QS8: [f32; 6] = [ - 1.6139537048e+02, /* 0x43216537 */ - 7.8253862305e+03, /* 0x45f48b17 */ - 1.3387534375e+05, /* 0x4802bcd6 */ - 7.1965775000e+05, /* 0x492fb29c */ - 6.6660125000e+05, /* 0x4922be94 */ - -2.9449025000e+05, /* 0xc88fcb48 */ -]; - -const QR5: [f32; 6] = [ /* for x in [8,4.5454]=1/[0.125,0.22001] */ - -2.0897993405e-11, /* 0xadb7d219 */ - -1.0253904760e-01, /* 0xbdd1fffe */ - -8.0564479828e+00, /* 0xc100e736 */ - -1.8366960144e+02, /* 0xc337ab6b */ - -1.3731937256e+03, /* 0xc4aba633 */ - -2.6124443359e+03, /* 0xc523471c */ -]; -const QS5: [f32; 6] = [ - 8.1276550293e+01, /* 0x42a28d98 */ - 1.9917987061e+03, /* 0x44f8f98f */ - 1.7468484375e+04, /* 0x468878f8 */ - 4.9851425781e+04, /* 0x4742bb6d */ - 2.7948074219e+04, /* 0x46da5826 */ - -4.7191835938e+03, /* 0xc5937978 */ -]; - -const QR3: [f32; 6] = [ - -5.0783124372e-09, /* 0xb1ae7d4f */ - -1.0253783315e-01, /* 0xbdd1ff5b */ - -4.6101160049e+00, /* 0xc0938612 */ - -5.7847221375e+01, /* 0xc267638e */ - -2.2824453735e+02, /* 0xc3643e9a */ - -2.1921012878e+02, /* 0xc35b35cb */ -]; -const QS3: [f32; 6] = [ - 4.7665153503e+01, /* 0x423ea91e */ - 6.7386511230e+02, /* 0x4428775e */ - 3.3801528320e+03, /* 0x45534272 */ - 5.5477290039e+03, /* 0x45ad5dd5 */ - 1.9031191406e+03, /* 0x44ede3d0 */ - -1.3520118713e+02, /* 0xc3073381 */ -]; - -const QR2: [f32; 6] = [ /* for x in [2.8570,2]=1/[0.3499,0.5] */ - -1.7838172539e-07, /* 0xb43f8932 */ - -1.0251704603e-01, /* 0xbdd1f475 */ - -2.7522056103e+00, /* 0xc0302423 */ - -1.9663616180e+01, /* 0xc19d4f16 */ - -4.2325313568e+01, /* 0xc2294d1f */ - -2.1371921539e+01, /* 0xc1aaf9b2 */ -]; -const QS2: [f32; 6] = [ - 2.9533363342e+01, /* 0x41ec4454 */ - 2.5298155212e+02, /* 0x437cfb47 */ - 7.5750280762e+02, /* 0x443d602e */ - 7.3939318848e+02, /* 0x4438d92a */ - 1.5594900513e+02, /* 0x431bf2f2 */ - -4.9594988823e+00, /* 0xc09eb437 */ -]; - -fn qonef(x: f32) -> f32 -{ - let p: &[f32; 6]; - let q: &[f32; 6]; - let s: f32; - let r: f32; - let z: f32; - let mut ix: u32; - - ix = x.to_bits(); - ix &= 0x7fffffff; - if ix >= 0x41000000 {p = &QR8; q = &QS8;} - else if ix >= 0x409173eb {p = &QR5; q = &QS5;} - else if ix >= 0x4036d917 {p = &QR3; q = &QS3;} - else /*ix >= 0x40000000*/{p = &QR2; q = &QS2;} - z = 1.0/(x*x); - r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); - s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); - return (0.375 + r/s)/x; -} +/* origin: FreeBSD /usr/src/lib/msun/src/e_j1f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + +use super::{cosf, fabsf, logf, sinf, sqrtf}; + +const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ +const TPI: f32 = 6.3661974669e-01; /* 0x3f22f983 */ + +fn common(ix: u32, x: f32, y1: bool, sign: bool) -> f32 { + let z: f64; + let mut s: f64; + let c: f64; + let mut ss: f64; + let mut cc: f64; + + s = sinf(x) as f64; + if y1 { + s = -s; + } + c = cosf(x) as f64; + cc = s - c; + if ix < 0x7f000000 { + ss = -s - c; + z = cosf(2.0 * x) as f64; + if s * c > 0.0 { + cc = z / ss; + } else { + ss = z / cc; + } + if ix < 0x58800000 { + if y1 { + ss = -ss; + } + cc = (ponef(x) as f64) * cc - (qonef(x) as f64) * ss; + } + } + if sign { + cc = -cc; + } + return INVSQRTPI * (cc as f32) / sqrtf(x); +} + +/* R0/S0 on [0,2] */ +const R00: f32 = -6.2500000000e-02; /* 0xbd800000 */ +const R01: f32 = 1.4070566976e-03; /* 0x3ab86cfd */ +const R02: f32 = -1.5995563444e-05; /* 0xb7862e36 */ +const R03: f32 = 4.9672799207e-08; /* 0x335557d2 */ +const S01: f32 = 1.9153760746e-02; /* 0x3c9ce859 */ +const S02: f32 = 1.8594678841e-04; /* 0x3942fab6 */ +const S03: f32 = 1.1771846857e-06; /* 0x359dffc2 */ +const S04: f32 = 5.0463624390e-09; /* 0x31ad6446 */ +const S05: f32 = 1.2354227016e-11; /* 0x2d59567e */ + +pub fn j1f(x: f32) -> f32 { + let mut z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + let sign: bool; + + ix = x.to_bits(); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + if ix >= 0x7f800000 { + return 1.0 / (x * x); + } + if ix >= 0x40000000 { + /* |x| >= 2 */ + return common(ix, fabsf(x), false, sign); + } + if ix >= 0x39000000 { + /* |x| >= 2**-13 */ + z = x * x; + r = z * (R00 + z * (R01 + z * (R02 + z * R03))); + s = 1.0 + z * (S01 + z * (S02 + z * (S03 + z * (S04 + z * S05)))); + z = 0.5 + r / s; + } else { + z = 0.5; + } + return z * x; +} + +const U0: [f32; 5] = [ + -1.9605709612e-01, /* 0xbe48c331 */ + 5.0443872809e-02, /* 0x3d4e9e3c */ + -1.9125689287e-03, /* 0xbafaaf2a */ + 2.3525259166e-05, /* 0x37c5581c */ + -9.1909917899e-08, /* 0xb3c56003 */ +]; +const V0: [f32; 5] = [ + 1.9916731864e-02, /* 0x3ca3286a */ + 2.0255257550e-04, /* 0x3954644b */ + 1.3560879779e-06, /* 0x35b602d4 */ + 6.2274145840e-09, /* 0x31d5f8eb */ + 1.6655924903e-11, /* 0x2d9281cf */ +]; + +pub fn y1f(x: f32) -> f32 { + let z: f32; + let u: f32; + let v: f32; + let ix: u32; + + ix = x.to_bits(); + if (ix & 0x7fffffff) == 0 { + return -1.0 / 0.0; + } + if (ix >> 31) != 0 { + return 0.0 / 0.0; + } + if ix >= 0x7f800000 { + return 1.0 / x; + } + if ix >= 0x40000000 { + /* |x| >= 2.0 */ + return common(ix, x, true, false); + } + if ix < 0x33000000 { + /* x < 2**-25 */ + return -TPI / x; + } + z = x * x; + u = U0[0] + z * (U0[1] + z * (U0[2] + z * (U0[3] + z * U0[4]))); + v = 1.0 + z * (V0[0] + z * (V0[1] + z * (V0[2] + z * (V0[3] + z * V0[4])))); + return x * (u / v) + TPI * (j1f(x) * logf(x) - 1.0 / x); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +const PR8: [f32; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 1.1718750000e-01, /* 0x3df00000 */ + 1.3239480972e+01, /* 0x4153d4ea */ + 4.1205184937e+02, /* 0x43ce06a3 */ + 3.8747453613e+03, /* 0x45722bed */ + 7.9144794922e+03, /* 0x45f753d6 */ +]; +const PS8: [f32; 5] = [ + 1.1420736694e+02, /* 0x42e46a2c */ + 3.6509309082e+03, /* 0x45642ee5 */ + 3.6956207031e+04, /* 0x47105c35 */ + 9.7602796875e+04, /* 0x47bea166 */ + 3.0804271484e+04, /* 0x46f0a88b */ +]; + +const PR5: [f32; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.3199052094e-11, /* 0x2d68333f */ + 1.1718749255e-01, /* 0x3defffff */ + 6.8027510643e+00, /* 0x40d9b023 */ + 1.0830818176e+02, /* 0x42d89dca */ + 5.1763616943e+02, /* 0x440168b7 */ + 5.2871520996e+02, /* 0x44042dc6 */ +]; +const PS5: [f32; 5] = [ + 5.9280597687e+01, /* 0x426d1f55 */ + 9.9140142822e+02, /* 0x4477d9b1 */ + 5.3532670898e+03, /* 0x45a74a23 */ + 7.8446904297e+03, /* 0x45f52586 */ + 1.5040468750e+03, /* 0x44bc0180 */ +]; + +const PR3: [f32; 6] = [ + 3.0250391081e-09, /* 0x314fe10d */ + 1.1718686670e-01, /* 0x3defffab */ + 3.9329774380e+00, /* 0x407bb5e7 */ + 3.5119403839e+01, /* 0x420c7a45 */ + 9.1055007935e+01, /* 0x42b61c2a */ + 4.8559066772e+01, /* 0x42423c7c */ +]; +const PS3: [f32; 5] = [ + 3.4791309357e+01, /* 0x420b2a4d */ + 3.3676245117e+02, /* 0x43a86198 */ + 1.0468714600e+03, /* 0x4482dbe3 */ + 8.9081134033e+02, /* 0x445eb3ed */ + 1.0378793335e+02, /* 0x42cf936c */ +]; + +const PR2: [f32; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.0771083225e-07, /* 0x33e74ea8 */ + 1.1717621982e-01, /* 0x3deffa16 */ + 2.3685150146e+00, /* 0x401795c0 */ + 1.2242610931e+01, /* 0x4143e1bc */ + 1.7693971634e+01, /* 0x418d8d41 */ + 5.0735230446e+00, /* 0x40a25a4d */ +]; +const PS2: [f32; 5] = [ + 2.1436485291e+01, /* 0x41ab7dec */ + 1.2529022980e+02, /* 0x42fa9499 */ + 2.3227647400e+02, /* 0x436846c7 */ + 1.1767937469e+02, /* 0x42eb5bd7 */ + 8.3646392822e+00, /* 0x4105d590 */ +]; + +fn ponef(x: f32) -> f32 { + let p: &[f32; 6]; + let q: &[f32; 5]; + let z: f32; + let r: f32; + let s: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 { + p = &PR8; + q = &PS8; + } else if ix >= 0x409173eb { + p = &PR5; + q = &PS5; + } else if ix >= 0x4036d917 { + p = &PR3; + q = &PS3; + } else + /*ix >= 0x40000000*/ + { + p = &PR2; + q = &PS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * q[4])))); + return 1.0 + r / s; +} + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +const QR8: [f32; 6] = [ + /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -1.0253906250e-01, /* 0xbdd20000 */ + -1.6271753311e+01, /* 0xc1822c8d */ + -7.5960174561e+02, /* 0xc43de683 */ + -1.1849806641e+04, /* 0xc639273a */ + -4.8438511719e+04, /* 0xc73d3683 */ +]; +const QS8: [f32; 6] = [ + 1.6139537048e+02, /* 0x43216537 */ + 7.8253862305e+03, /* 0x45f48b17 */ + 1.3387534375e+05, /* 0x4802bcd6 */ + 7.1965775000e+05, /* 0x492fb29c */ + 6.6660125000e+05, /* 0x4922be94 */ + -2.9449025000e+05, /* 0xc88fcb48 */ +]; + +const QR5: [f32; 6] = [ + /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.0897993405e-11, /* 0xadb7d219 */ + -1.0253904760e-01, /* 0xbdd1fffe */ + -8.0564479828e+00, /* 0xc100e736 */ + -1.8366960144e+02, /* 0xc337ab6b */ + -1.3731937256e+03, /* 0xc4aba633 */ + -2.6124443359e+03, /* 0xc523471c */ +]; +const QS5: [f32; 6] = [ + 8.1276550293e+01, /* 0x42a28d98 */ + 1.9917987061e+03, /* 0x44f8f98f */ + 1.7468484375e+04, /* 0x468878f8 */ + 4.9851425781e+04, /* 0x4742bb6d */ + 2.7948074219e+04, /* 0x46da5826 */ + -4.7191835938e+03, /* 0xc5937978 */ +]; + +const QR3: [f32; 6] = [ + -5.0783124372e-09, /* 0xb1ae7d4f */ + -1.0253783315e-01, /* 0xbdd1ff5b */ + -4.6101160049e+00, /* 0xc0938612 */ + -5.7847221375e+01, /* 0xc267638e */ + -2.2824453735e+02, /* 0xc3643e9a */ + -2.1921012878e+02, /* 0xc35b35cb */ +]; +const QS3: [f32; 6] = [ + 4.7665153503e+01, /* 0x423ea91e */ + 6.7386511230e+02, /* 0x4428775e */ + 3.3801528320e+03, /* 0x45534272 */ + 5.5477290039e+03, /* 0x45ad5dd5 */ + 1.9031191406e+03, /* 0x44ede3d0 */ + -1.3520118713e+02, /* 0xc3073381 */ +]; + +const QR2: [f32; 6] = [ + /* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.7838172539e-07, /* 0xb43f8932 */ + -1.0251704603e-01, /* 0xbdd1f475 */ + -2.7522056103e+00, /* 0xc0302423 */ + -1.9663616180e+01, /* 0xc19d4f16 */ + -4.2325313568e+01, /* 0xc2294d1f */ + -2.1371921539e+01, /* 0xc1aaf9b2 */ +]; +const QS2: [f32; 6] = [ + 2.9533363342e+01, /* 0x41ec4454 */ + 2.5298155212e+02, /* 0x437cfb47 */ + 7.5750280762e+02, /* 0x443d602e */ + 7.3939318848e+02, /* 0x4438d92a */ + 1.5594900513e+02, /* 0x431bf2f2 */ + -4.9594988823e+00, /* 0xc09eb437 */ +]; + +fn qonef(x: f32) -> f32 { + let p: &[f32; 6]; + let q: &[f32; 6]; + let s: f32; + let r: f32; + let z: f32; + let mut ix: u32; + + ix = x.to_bits(); + ix &= 0x7fffffff; + if ix >= 0x41000000 { + p = &QR8; + q = &QS8; + } else if ix >= 0x409173eb { + p = &QR5; + q = &QS5; + } else if ix >= 0x4036d917 { + p = &QR3; + q = &QS3; + } else + /*ix >= 0x40000000*/ + { + p = &QR2; + q = &QS2; + } + z = 1.0 / (x * x); + r = p[0] + z * (p[1] + z * (p[2] + z * (p[3] + z * (p[4] + z * p[5])))); + s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); + return (0.375 + r / s) / x; +} diff --git a/library/compiler-builtins/libm/src/math/jn.rs b/library/compiler-builtins/libm/src/math/jn.rs index 7f7c06feed261..70c98026685df 100644 --- a/library/compiler-builtins/libm/src/math/jn.rs +++ b/library/compiler-builtins/libm/src/math/jn.rs @@ -1,338 +1,343 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_jn.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* - * jn(n, x), yn(n, x) - * floating point Bessel's function of the 1st and 2nd kind - * of order n - * - * Special cases: - * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal; - * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal. - * Note 2. About jn(n,x), yn(n,x) - * For n=0, j0(x) is called, - * for n=1, j1(x) is called, - * for n<=x, forward recursion is used starting - * from values of j0(x) and j1(x). - * for n>x, a continued fraction approximation to - * j(n,x)/j(n-1,x) is evaluated and then backward - * recursion is used starting from a supposed value - * for j(n,x). The resulting value of j(0,x) is - * compared with the actual value to correct the - * supposed value of j(n,x). - * - * yn(n,x) is similar in all respects, except - * that forward recursion is used for all - * values of n>1. - */ - -use super::{cos, fabs, get_high_word, get_low_word, log, j0, j1, sin, sqrt, y0, y1}; - -const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ - -pub fn jn(n: isize, mut x: f64) -> f64 -{ - let mut ix: u32; - let lx: u32; - let nm1: isize; - let mut i: isize; - let mut sign: bool; - let mut a: f64; - let mut b: f64; - let mut temp: f64; - - ix = get_high_word(x); - lx = get_low_word(x); - sign = (ix>>31) != 0; - ix &= 0x7fffffff; - - // -lx == !lx + 1 - if (ix | (lx|(!lx+1))>>31) > 0x7ff00000 { /* nan */ - return x; - } - - /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x) - * Thus, J(-n,x) = J(n,-x) - */ - /* nm1 = |n|-1 is used instead of |n| to handle n==INT_MIN */ - if n == 0 { - return j0(x); - } - if n < 0 { - nm1 = -(n+1); - x = -x; - sign = !sign; - } else { - nm1 = n-1; - } - if nm1 == 0 { - return j1(x); - } - - sign &= (n & 1) != 0; /* even n: 0, odd n: signbit(x) */ - x = fabs(x); - if (ix|lx) == 0 || ix == 0x7ff00000 { /* if x is 0 or inf */ - b = 0.0; - } else if (nm1 as f64) < x { - /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ - if ix >= 0x52d00000 { /* x > 2**302 */ - /* (x >> n**2) - * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) - * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) - * Let s=sin(x), c=cos(x), - * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then - * - * n sin(xn)*sqt2 cos(xn)*sqt2 - * ---------------------------------- - * 0 s-c c+s - * 1 -s-c -c+s - * 2 -s+c -c-s - * 3 s+c c-s - */ - temp = match nm1&3 { - 0 => -cos(x)+sin(x), - 1 => -cos(x)-sin(x), - 2 => cos(x)-sin(x), - 3 | _ => cos(x)+sin(x), - }; - b = INVSQRTPI*temp/sqrt(x); - } else { - a = j0(x); - b = j1(x); - i = 0; - while i < nm1 { - i += 1; - temp = b; - b = b*(2.0*(i as f64)/x) - a; /* avoid underflow */ - a = temp; - } - } - } else { - if ix < 0x3e100000 { /* x < 2**-29 */ - /* x is tiny, return the first Taylor expansion of J(n,x) - * J(n,x) = 1/n!*(x/2)^n - ... - */ - if nm1 > 32 { /* underflow */ - b = 0.0; - } else { - temp = x*0.5; - b = temp; - a = 1.0; - i = 2; - while i <= nm1 + 1 { - a *= i as f64; /* a = n! */ - b *= temp; /* b = (x/2)^n */ - i += 1; - } - b = b/a; - } - } else { - /* use backward recurrence */ - /* x x^2 x^2 - * J(n,x)/J(n-1,x) = ---- ------ ------ ..... - * 2n - 2(n+1) - 2(n+2) - * - * 1 1 1 - * (for large x) = ---- ------ ------ ..... - * 2n 2(n+1) 2(n+2) - * -- - ------ - ------ - - * x x x - * - * Let w = 2n/x and h=2/x, then the above quotient - * is equal to the continued fraction: - * 1 - * = ----------------------- - * 1 - * w - ----------------- - * 1 - * w+h - --------- - * w+2h - ... - * - * To determine how many terms needed, let - * Q(0) = w, Q(1) = w(w+h) - 1, - * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), - * When Q(k) > 1e4 good for single - * When Q(k) > 1e9 good for double - * When Q(k) > 1e17 good for quadruple - */ - /* determine k */ - let mut t: f64; - let mut q0: f64; - let mut q1: f64; - let mut w: f64; - let h: f64; - let mut z: f64; - let mut tmp: f64; - let nf: f64; - - let mut k: isize; - - nf = (nm1 as f64) + 1.0; - w = 2.0*nf/x; - h = 2.0/x; - z = w+h; - q0 = w; - q1 = w*z - 1.0; - k = 1; - while q1 < 1.0e9 { - k += 1; - z += h; - tmp = z*q1 - q0; - q0 = q1; - q1 = tmp; - } - t = 0.0; - i = k; - while i >= 0 { - t = 1.0/(2.0*((i as f64)+nf)/x - t); - i -= 1; - } - a = t; - b = 1.0; - /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) - * Hence, if n*(log(2n/x)) > ... - * single 8.8722839355e+01 - * double 7.09782712893383973096e+02 - * long double 1.1356523406294143949491931077970765006170e+04 - * then recurrent value may overflow and the result is - * likely underflow to zero - */ - tmp = nf*log(fabs(w)); - if tmp < 7.09782712893383973096e+02 { - i = nm1; - while i > 0 { - temp = b; - b = b*(2.0*(i as f64))/x - a; - a = temp; - i -= 1; - } - } else { - i = nm1; - while i > 0 { - temp = b; - b = b*(2.0*(i as f64))/x - a; - a = temp; - /* scale b to avoid spurious overflow */ - let x1p500 = f64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 - if b > x1p500 { - a /= b; - t /= b; - b = 1.0; - } - i -= 1; - } - } - z = j0(x); - w = j1(x); - if fabs(z) >= fabs(w) { - b = t*z/b; - } else { - b = t*w/a; - } - } - } - - if sign { - -b - } else { - b - } -} - - -pub fn yn(n: isize, x: f64) -> f64 -{ - let mut ix: u32; - let lx: u32; - let mut ib: u32; - let nm1: isize; - let mut sign: bool; - let mut i: isize; - let mut a: f64; - let mut b: f64; - let mut temp: f64; - - ix = get_high_word(x); - lx = get_low_word(x); - sign = (ix>>31) != 0; - ix &= 0x7fffffff; - - // -lx == !lx + 1 - if (ix | (lx|(!lx+1))>>31) > 0x7ff00000 { /* nan */ - return x; - } - if sign && (ix|lx) != 0 { /* x < 0 */ - return 0.0/0.0; - } - if ix == 0x7ff00000 { - return 0.0; - } - - if n == 0 { - return y0(x); - } - if n < 0 { - nm1 = -(n+1); - sign = (n&1) != 0; - } else { - nm1 = n-1; - sign = false; - } - if nm1 == 0 { - if sign { - return -y1(x); - } else { - return y1(x); - } - } - - if ix >= 0x52d00000 { /* x > 2**302 */ - /* (x >> n**2) - * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) - * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) - * Let s=sin(x), c=cos(x), - * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then - * - * n sin(xn)*sqt2 cos(xn)*sqt2 - * ---------------------------------- - * 0 s-c c+s - * 1 -s-c -c+s - * 2 -s+c -c-s - * 3 s+c c-s - */ - temp = match nm1&3 { - 0 => -sin(x)-cos(x), - 1 => -sin(x)+cos(x), - 2 => sin(x)+cos(x), - 3 | _ => sin(x)-cos(x), - }; - b = INVSQRTPI*temp/sqrt(x); - } else { - a = y0(x); - b = y1(x); - /* quit if b is -inf */ - ib = get_high_word(b); - i = 0; - while i < nm1 && ib != 0xfff00000 { - i += 1; - temp = b; - b = (2.0*(i as f64)/x)*b - a; - ib = get_high_word(b); - a = temp; - } - } - - if sign { - -b - } else { - b - } -} +/* origin: FreeBSD /usr/src/lib/msun/src/e_jn.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * jn(n, x), yn(n, x) + * floating point Bessel's function of the 1st and 2nd kind + * of order n + * + * Special cases: + * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal; + * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal. + * Note 2. About jn(n,x), yn(n,x) + * For n=0, j0(x) is called, + * for n=1, j1(x) is called, + * for n<=x, forward recursion is used starting + * from values of j0(x) and j1(x). + * for n>x, a continued fraction approximation to + * j(n,x)/j(n-1,x) is evaluated and then backward + * recursion is used starting from a supposed value + * for j(n,x). The resulting value of j(0,x) is + * compared with the actual value to correct the + * supposed value of j(n,x). + * + * yn(n,x) is similar in all respects, except + * that forward recursion is used for all + * values of n>1. + */ + +use super::{cos, fabs, get_high_word, get_low_word, j0, j1, log, sin, sqrt, y0, y1}; + +const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ + +pub fn jn(n: i32, mut x: f64) -> f64 { + let mut ix: u32; + let lx: u32; + let nm1: i32; + let mut i: i32; + let mut sign: bool; + let mut a: f64; + let mut b: f64; + let mut temp: f64; + + ix = get_high_word(x); + lx = get_low_word(x); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + // -lx == !lx + 1 + if (ix | (lx | (!lx + 1)) >> 31) > 0x7ff00000 { + /* nan */ + return x; + } + + /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x) + * Thus, J(-n,x) = J(n,-x) + */ + /* nm1 = |n|-1 is used instead of |n| to handle n==INT_MIN */ + if n == 0 { + return j0(x); + } + if n < 0 { + nm1 = -(n + 1); + x = -x; + sign = !sign; + } else { + nm1 = n - 1; + } + if nm1 == 0 { + return j1(x); + } + + sign &= (n & 1) != 0; /* even n: 0, odd n: signbit(x) */ + x = fabs(x); + if (ix | lx) == 0 || ix == 0x7ff00000 { + /* if x is 0 or inf */ + b = 0.0; + } else if (nm1 as f64) < x { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + if ix >= 0x52d00000 { + /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + temp = match nm1 & 3 { + 0 => -cos(x) + sin(x), + 1 => -cos(x) - sin(x), + 2 => cos(x) - sin(x), + 3 | _ => cos(x) + sin(x), + }; + b = INVSQRTPI * temp / sqrt(x); + } else { + a = j0(x); + b = j1(x); + i = 0; + while i < nm1 { + i += 1; + temp = b; + b = b * (2.0 * (i as f64) / x) - a; /* avoid underflow */ + a = temp; + } + } + } else { + if ix < 0x3e100000 { + /* x < 2**-29 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if nm1 > 32 { + /* underflow */ + b = 0.0; + } else { + temp = x * 0.5; + b = temp; + a = 1.0; + i = 2; + while i <= nm1 + 1 { + a *= i as f64; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + i += 1; + } + b = b / a; + } + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + let mut t: f64; + let mut q0: f64; + let mut q1: f64; + let mut w: f64; + let h: f64; + let mut z: f64; + let mut tmp: f64; + let nf: f64; + + let mut k: i32; + + nf = (nm1 as f64) + 1.0; + w = 2.0 * nf / x; + h = 2.0 / x; + z = w + h; + q0 = w; + q1 = w * z - 1.0; + k = 1; + while q1 < 1.0e9 { + k += 1; + z += h; + tmp = z * q1 - q0; + q0 = q1; + q1 = tmp; + } + t = 0.0; + i = k; + while i >= 0 { + t = 1.0 / (2.0 * ((i as f64) + nf) / x - t); + i -= 1; + } + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf * log(fabs(w)); + if tmp < 7.09782712893383973096e+02 { + i = nm1; + while i > 0 { + temp = b; + b = b * (2.0 * (i as f64)) / x - a; + a = temp; + i -= 1; + } + } else { + i = nm1; + while i > 0 { + temp = b; + b = b * (2.0 * (i as f64)) / x - a; + a = temp; + /* scale b to avoid spurious overflow */ + let x1p500 = f64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 + if b > x1p500 { + a /= b; + t /= b; + b = 1.0; + } + i -= 1; + } + } + z = j0(x); + w = j1(x); + if fabs(z) >= fabs(w) { + b = t * z / b; + } else { + b = t * w / a; + } + } + } + + if sign { + -b + } else { + b + } +} + +pub fn yn(n: i32, x: f64) -> f64 { + let mut ix: u32; + let lx: u32; + let mut ib: u32; + let nm1: i32; + let mut sign: bool; + let mut i: i32; + let mut a: f64; + let mut b: f64; + let mut temp: f64; + + ix = get_high_word(x); + lx = get_low_word(x); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + // -lx == !lx + 1 + if (ix | (lx | (!lx + 1)) >> 31) > 0x7ff00000 { + /* nan */ + return x; + } + if sign && (ix | lx) != 0 { + /* x < 0 */ + return 0.0 / 0.0; + } + if ix == 0x7ff00000 { + return 0.0; + } + + if n == 0 { + return y0(x); + } + if n < 0 { + nm1 = -(n + 1); + sign = (n & 1) != 0; + } else { + nm1 = n - 1; + sign = false; + } + if nm1 == 0 { + if sign { + return -y1(x); + } else { + return y1(x); + } + } + + if ix >= 0x52d00000 { + /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + temp = match nm1 & 3 { + 0 => -sin(x) - cos(x), + 1 => -sin(x) + cos(x), + 2 => sin(x) + cos(x), + 3 | _ => sin(x) - cos(x), + }; + b = INVSQRTPI * temp / sqrt(x); + } else { + a = y0(x); + b = y1(x); + /* quit if b is -inf */ + ib = get_high_word(b); + i = 0; + while i < nm1 && ib != 0xfff00000 { + i += 1; + temp = b; + b = (2.0 * (i as f64) / x) * b - a; + ib = get_high_word(b); + a = temp; + } + } + + if sign { + -b + } else { + b + } +} diff --git a/library/compiler-builtins/libm/src/math/jnf.rs b/library/compiler-builtins/libm/src/math/jnf.rs index 4cd848a03b078..360f62e201d46 100644 --- a/library/compiler-builtins/libm/src/math/jnf.rs +++ b/library/compiler-builtins/libm/src/math/jnf.rs @@ -1,255 +1,259 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_jnf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * 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. - * ==================================================== - */ - -use super::{fabsf, j0f, j1f, logf, y0f, y1f}; - -pub fn jnf(n: isize, mut x: f32) -> f32 -{ - let mut ix: u32; - let mut nm1: isize; - let mut sign: bool; - let mut i: isize; - let mut a: f32; - let mut b: f32; - let mut temp: f32; - - ix = x.to_bits(); - sign = (ix>>31) != 0; - ix &= 0x7fffffff; - if ix > 0x7f800000 { /* nan */ - return x; - } - - /* J(-n,x) = J(n,-x), use |n|-1 to avoid overflow in -n */ - if n == 0 { - return j0f(x); - } - if n < 0 { - nm1 = -(n+1); - x = -x; - sign = !sign; - } else { - nm1 = n-1; - } - if nm1 == 0 { - return j1f(x); - } - - sign &= (n&1) != 0; /* even n: 0, odd n: signbit(x) */ - x = fabsf(x); - if ix == 0 || ix == 0x7f800000 { /* if x is 0 or inf */ - b = 0.0; - } else if (nm1 as f32) < x { - /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ - a = j0f(x); - b = j1f(x); - i = 0; - while i < nm1 { - i += 1; - temp = b; - b = b*(2.0*(i as f32)/x) - a; - a = temp; - } - } else { - if ix < 0x35800000 { /* x < 2**-20 */ - /* x is tiny, return the first Taylor expansion of J(n,x) - * J(n,x) = 1/n!*(x/2)^n - ... - */ - if nm1 > 8 { /* underflow */ - nm1 = 8; - } - temp = 0.5 * x; - b = temp; - a = 1.0; - i = 2; - while i <= nm1 + 1 { - a *= i as f32; /* a = n! */ - b *= temp; /* b = (x/2)^n */ - i += 1; - } - b = b/a; - } else { - /* use backward recurrence */ - /* x x^2 x^2 - * J(n,x)/J(n-1,x) = ---- ------ ------ ..... - * 2n - 2(n+1) - 2(n+2) - * - * 1 1 1 - * (for large x) = ---- ------ ------ ..... - * 2n 2(n+1) 2(n+2) - * -- - ------ - ------ - - * x x x - * - * Let w = 2n/x and h=2/x, then the above quotient - * is equal to the continued fraction: - * 1 - * = ----------------------- - * 1 - * w - ----------------- - * 1 - * w+h - --------- - * w+2h - ... - * - * To determine how many terms needed, let - * Q(0) = w, Q(1) = w(w+h) - 1, - * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), - * When Q(k) > 1e4 good for single - * When Q(k) > 1e9 good for double - * When Q(k) > 1e17 good for quadruple - */ - /* determine k */ - let mut t: f32; - let mut q0: f32; - let mut q1: f32; - let mut w: f32; - let h: f32; - let mut z: f32; - let mut tmp: f32; - let nf: f32; - let mut k: isize; - - nf = (nm1 as f32)+1.0; - w = 2.0*(nf as f32)/x; - h = 2.0/x; - z = w+h; - q0 = w; - q1 = w*z - 1.0; - k = 1; - while q1 < 1.0e4 { - k += 1; - z += h; - tmp = z*q1 - q0; - q0 = q1; - q1 = tmp; - } - t = 0.0; - i = k; - while i >= 0 { - t = 1.0/(2.0*((i as f32)+nf)/x-t); - i -= 1; - } - a = t; - b = 1.0; - /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) - * Hence, if n*(log(2n/x)) > ... - * single 8.8722839355e+01 - * double 7.09782712893383973096e+02 - * long double 1.1356523406294143949491931077970765006170e+04 - * then recurrent value may overflow and the result is - * likely underflow to zero - */ - tmp = nf*logf(fabsf(w)); - if tmp < 88.721679688 { - i = nm1; - while i > 0 { - temp = b; - b = 2.0*(i as f32)*b/x - a; - a = temp; - i -= 1; - } - } else { - i = nm1; - while i > 0 { - temp = b; - b = 2.0*(i as f32)*b/x - a; - a = temp; - /* scale b to avoid spurious overflow */ - let x1p60 = f32::from_bits(0x5d800000); // 0x1p60 == 2^60 - if b > x1p60 { - a /= b; - t /= b; - b = 1.0; - } - i -= 1; - } - } - z = j0f(x); - w = j1f(x); - if fabsf(z) >= fabsf(w) { - b = t*z/b; - } else { - b = t*w/a; - } - } - } - - if sign { - -b - } else { - b - } -} - -pub fn ynf(n: isize, x: f32) -> f32 -{ - let mut ix: u32; - let mut ib: u32; - let nm1: isize; - let mut sign: bool; - let mut i: isize; - let mut a: f32; - let mut b: f32; - let mut temp: f32; - - ix = x.to_bits(); - sign = (ix>>31) != 0; - ix &= 0x7fffffff; - if ix > 0x7f800000 { /* nan */ - return x; - } - if sign && ix != 0 { /* x < 0 */ - return 0.0/0.0; - } - if ix == 0x7f800000 { - return 0.0; - } - - if n == 0 { - return y0f(x); - } - if n < 0 { - nm1 = -(n+1); - sign = (n&1) != 0; - } else { - nm1 = n-1; - sign = false; - } - if nm1 == 0 { - if sign { - return -y1f(x); - } else { - return y1f(x); - } - } - - a = y0f(x); - b = y1f(x); - /* quit if b is -inf */ - ib = b.to_bits(); - i = 0; - while i < nm1 && ib != 0xff800000 { - i += 1; - temp = b; - b = (2.0*(i as f32)/x)*b - a; - ib = b.to_bits(); - a = temp; - } - - if sign { - -b - } else { - b - } -} +/* origin: FreeBSD /usr/src/lib/msun/src/e_jnf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + +use super::{fabsf, j0f, j1f, logf, y0f, y1f}; + +pub fn jnf(n: i32, mut x: f32) -> f32 { + let mut ix: u32; + let mut nm1: i32; + let mut sign: bool; + let mut i: i32; + let mut a: f32; + let mut b: f32; + let mut temp: f32; + + ix = x.to_bits(); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + if ix > 0x7f800000 { + /* nan */ + return x; + } + + /* J(-n,x) = J(n,-x), use |n|-1 to avoid overflow in -n */ + if n == 0 { + return j0f(x); + } + if n < 0 { + nm1 = -(n + 1); + x = -x; + sign = !sign; + } else { + nm1 = n - 1; + } + if nm1 == 0 { + return j1f(x); + } + + sign &= (n & 1) != 0; /* even n: 0, odd n: signbit(x) */ + x = fabsf(x); + if ix == 0 || ix == 0x7f800000 { + /* if x is 0 or inf */ + b = 0.0; + } else if (nm1 as f32) < x { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + a = j0f(x); + b = j1f(x); + i = 0; + while i < nm1 { + i += 1; + temp = b; + b = b * (2.0 * (i as f32) / x) - a; + a = temp; + } + } else { + if ix < 0x35800000 { + /* x < 2**-20 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if nm1 > 8 { + /* underflow */ + nm1 = 8; + } + temp = 0.5 * x; + b = temp; + a = 1.0; + i = 2; + while i <= nm1 + 1 { + a *= i as f32; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + i += 1; + } + b = b / a; + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + let mut t: f32; + let mut q0: f32; + let mut q1: f32; + let mut w: f32; + let h: f32; + let mut z: f32; + let mut tmp: f32; + let nf: f32; + let mut k: i32; + + nf = (nm1 as f32) + 1.0; + w = 2.0 * (nf as f32) / x; + h = 2.0 / x; + z = w + h; + q0 = w; + q1 = w * z - 1.0; + k = 1; + while q1 < 1.0e4 { + k += 1; + z += h; + tmp = z * q1 - q0; + q0 = q1; + q1 = tmp; + } + t = 0.0; + i = k; + while i >= 0 { + t = 1.0 / (2.0 * ((i as f32) + nf) / x - t); + i -= 1; + } + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf * logf(fabsf(w)); + if tmp < 88.721679688 { + i = nm1; + while i > 0 { + temp = b; + b = 2.0 * (i as f32) * b / x - a; + a = temp; + i -= 1; + } + } else { + i = nm1; + while i > 0 { + temp = b; + b = 2.0 * (i as f32) * b / x - a; + a = temp; + /* scale b to avoid spurious overflow */ + let x1p60 = f32::from_bits(0x5d800000); // 0x1p60 == 2^60 + if b > x1p60 { + a /= b; + t /= b; + b = 1.0; + } + i -= 1; + } + } + z = j0f(x); + w = j1f(x); + if fabsf(z) >= fabsf(w) { + b = t * z / b; + } else { + b = t * w / a; + } + } + } + + if sign { + -b + } else { + b + } +} + +pub fn ynf(n: i32, x: f32) -> f32 { + let mut ix: u32; + let mut ib: u32; + let nm1: i32; + let mut sign: bool; + let mut i: i32; + let mut a: f32; + let mut b: f32; + let mut temp: f32; + + ix = x.to_bits(); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + if ix > 0x7f800000 { + /* nan */ + return x; + } + if sign && ix != 0 { + /* x < 0 */ + return 0.0 / 0.0; + } + if ix == 0x7f800000 { + return 0.0; + } + + if n == 0 { + return y0f(x); + } + if n < 0 { + nm1 = -(n + 1); + sign = (n & 1) != 0; + } else { + nm1 = n - 1; + sign = false; + } + if nm1 == 0 { + if sign { + return -y1f(x); + } else { + return y1f(x); + } + } + + a = y0f(x); + b = y1f(x); + /* quit if b is -inf */ + ib = b.to_bits(); + i = 0; + while i < nm1 && ib != 0xff800000 { + i += 1; + temp = b; + b = (2.0 * (i as f32) / x) * b - a; + ib = b.to_bits(); + a = temp; + } + + if sign { + -b + } else { + b + } +} diff --git a/library/compiler-builtins/libm/src/math/lgamma.rs b/library/compiler-builtins/libm/src/math/lgamma.rs index 35b25265214f5..b1a321e308c45 100644 --- a/library/compiler-builtins/libm/src/math/lgamma.rs +++ b/library/compiler-builtins/libm/src/math/lgamma.rs @@ -1,309 +1,323 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - * - */ -/* lgamma_r(x, signgamp) - * Reentrant version of the logarithm of the Gamma function - * with user provide pointer for the sign of Gamma(x). - * - * Method: - * 1. Argument Reduction for 0 < x <= 8 - * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may - * reduce x to a number in [1.5,2.5] by - * lgamma(1+s) = log(s) + lgamma(s) - * for example, - * lgamma(7.3) = log(6.3) + lgamma(6.3) - * = log(6.3*5.3) + lgamma(5.3) - * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) - * 2. Polynomial approximation of lgamma around its - * minimun ymin=1.461632144968362245 to maintain monotonicity. - * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use - * Let z = x-ymin; - * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) - * where - * poly(z) is a 14 degree polynomial. - * 2. Rational approximation in the primary interval [2,3] - * We use the following approximation: - * s = x-2.0; - * lgamma(x) = 0.5*s + s*P(s)/Q(s) - * with accuracy - * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 - * Our algorithms are based on the following observation - * - * zeta(2)-1 2 zeta(3)-1 3 - * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... - * 2 3 - * - * where Euler = 0.5771... is the Euler constant, which is very - * close to 0.5. - * - * 3. For x>=8, we have - * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... - * (better formula: - * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) - * Let z = 1/x, then we approximation - * f(z) = lgamma(x) - (x-0.5)(log(x)-1) - * by - * 3 5 11 - * w = w0 + w1*z + w2*z + w3*z + ... + w6*z - * where - * |w - f(z)| < 2**-58.74 - * - * 4. For negative x, since (G is gamma function) - * -x*G(-x)*G(x) = PI/sin(PI*x), - * we have - * G(x) = PI/(sin(PI*x)*(-x)*G(-x)) - * since G(-x) is positive, sign(G(x)) = sign(sin(PI*x)) for x<0 - * Hence, for x<0, signgam = sign(sin(PI*x)) and - * lgamma(x) = log(|Gamma(x)|) - * = log(PI/(|x*sin(PI*x)|)) - lgamma(-x); - * Note: one should avoid compute PI*(-x) directly in the - * computation of sin(PI*(-x)). - * - * 5. Special Cases - * lgamma(2+s) ~ s*(1-Euler) for tiny s - * lgamma(1) = lgamma(2) = 0 - * lgamma(x) ~ -log(|x|) for tiny x - * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero - * lgamma(inf) = inf - * lgamma(-inf) = inf (bug for bug compatible with C99!?) - * - */ - -use super::{floor, k_cos, k_sin, log}; - -const PI: f64 = 3.14159265358979311600e+00; /* 0x400921FB, 0x54442D18 */ -const A0: f64 = 7.72156649015328655494e-02; /* 0x3FB3C467, 0xE37DB0C8 */ -const A1: f64 = 3.22467033424113591611e-01; /* 0x3FD4A34C, 0xC4A60FAD */ -const A2: f64 = 6.73523010531292681824e-02; /* 0x3FB13E00, 0x1A5562A7 */ -const A3: f64 = 2.05808084325167332806e-02; /* 0x3F951322, 0xAC92547B */ -const A4: f64 = 7.38555086081402883957e-03; /* 0x3F7E404F, 0xB68FEFE8 */ -const A5: f64 = 2.89051383673415629091e-03; /* 0x3F67ADD8, 0xCCB7926B */ -const A6: f64 = 1.19270763183362067845e-03; /* 0x3F538A94, 0x116F3F5D */ -const A7: f64 = 5.10069792153511336608e-04; /* 0x3F40B6C6, 0x89B99C00 */ -const A8: f64 = 2.20862790713908385557e-04; /* 0x3F2CF2EC, 0xED10E54D */ -const A9: f64 = 1.08011567247583939954e-04; /* 0x3F1C5088, 0x987DFB07 */ -const A10: f64 = 2.52144565451257326939e-05; /* 0x3EFA7074, 0x428CFA52 */ -const A11: f64 = 4.48640949618915160150e-05; /* 0x3F07858E, 0x90A45837 */ -const TC: f64 = 1.46163214496836224576e+00; /* 0x3FF762D8, 0x6356BE3F */ -const TF: f64 = -1.21486290535849611461e-01; /* 0xBFBF19B9, 0xBCC38A42 */ -/* tt = -(tail of TF) */ -const TT: f64 = -3.63867699703950536541e-18; /* 0xBC50C7CA, 0xA48A971F */ -const T0: f64 = 4.83836122723810047042e-01; /* 0x3FDEF72B, 0xC8EE38A2 */ -const T1: f64 = -1.47587722994593911752e-01; /* 0xBFC2E427, 0x8DC6C509 */ -const T2: f64 = 6.46249402391333854778e-02; /* 0x3FB08B42, 0x94D5419B */ -const T3: f64 = -3.27885410759859649565e-02; /* 0xBFA0C9A8, 0xDF35B713 */ -const T4: f64 = 1.79706750811820387126e-02; /* 0x3F9266E7, 0x970AF9EC */ -const T5: f64 = -1.03142241298341437450e-02; /* 0xBF851F9F, 0xBA91EC6A */ -const T6: f64 = 6.10053870246291332635e-03; /* 0x3F78FCE0, 0xE370E344 */ -const T7: f64 = -3.68452016781138256760e-03; /* 0xBF6E2EFF, 0xB3E914D7 */ -const T8: f64 = 2.25964780900612472250e-03; /* 0x3F6282D3, 0x2E15C915 */ -const T9: f64 = -1.40346469989232843813e-03; /* 0xBF56FE8E, 0xBF2D1AF1 */ -const T10: f64 = 8.81081882437654011382e-04; /* 0x3F4CDF0C, 0xEF61A8E9 */ -const T11: f64 = -5.38595305356740546715e-04; /* 0xBF41A610, 0x9C73E0EC */ -const T12: f64 = 3.15632070903625950361e-04; /* 0x3F34AF6D, 0x6C0EBBF7 */ -const T13: f64 = -3.12754168375120860518e-04; /* 0xBF347F24, 0xECC38C38 */ -const T14: f64 = 3.35529192635519073543e-04; /* 0x3F35FD3E, 0xE8C2D3F4 */ -const U0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ -const U1: f64 = 6.32827064025093366517e-01; /* 0x3FE4401E, 0x8B005DFF */ -const U2: f64 = 1.45492250137234768737e+00; /* 0x3FF7475C, 0xD119BD6F */ -const U3: f64 = 9.77717527963372745603e-01; /* 0x3FEF4976, 0x44EA8450 */ -const U4: f64 = 2.28963728064692451092e-01; /* 0x3FCD4EAE, 0xF6010924 */ -const U5: f64 = 1.33810918536787660377e-02; /* 0x3F8B678B, 0xBF2BAB09 */ -const V1: f64 = 2.45597793713041134822e+00; /* 0x4003A5D7, 0xC2BD619C */ -const V2: f64 = 2.12848976379893395361e+00; /* 0x40010725, 0xA42B18F5 */ -const V3: f64 = 7.69285150456672783825e-01; /* 0x3FE89DFB, 0xE45050AF */ -const V4: f64 = 1.04222645593369134254e-01; /* 0x3FBAAE55, 0xD6537C88 */ -const V5: f64 = 3.21709242282423911810e-03; /* 0x3F6A5ABB, 0x57D0CF61 */ -const S0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ -const S1: f64 = 2.14982415960608852501e-01; /* 0x3FCB848B, 0x36E20878 */ -const S2: f64 = 3.25778796408930981787e-01; /* 0x3FD4D98F, 0x4F139F59 */ -const S3: f64 = 1.46350472652464452805e-01; /* 0x3FC2BB9C, 0xBEE5F2F7 */ -const S4: f64 = 2.66422703033638609560e-02; /* 0x3F9B481C, 0x7E939961 */ -const S5: f64 = 1.84028451407337715652e-03; /* 0x3F5E26B6, 0x7368F239 */ -const S6: f64 = 3.19475326584100867617e-05; /* 0x3F00BFEC, 0xDD17E945 */ -const R1: f64 = 1.39200533467621045958e+00; /* 0x3FF645A7, 0x62C4AB74 */ -const R2: f64 = 7.21935547567138069525e-01; /* 0x3FE71A18, 0x93D3DCDC */ -const R3: f64 = 1.71933865632803078993e-01; /* 0x3FC601ED, 0xCCFBDF27 */ -const R4: f64 = 1.86459191715652901344e-02; /* 0x3F9317EA, 0x742ED475 */ -const R5: f64 = 7.77942496381893596434e-04; /* 0x3F497DDA, 0xCA41A95B */ -const R6: f64 = 7.32668430744625636189e-06; /* 0x3EDEBAF7, 0xA5B38140 */ -const W0: f64 = 4.18938533204672725052e-01; /* 0x3FDACFE3, 0x90C97D69 */ -const W1: f64 = 8.33333333333329678849e-02; /* 0x3FB55555, 0x5555553B */ -const W2: f64 = -2.77777777728775536470e-03; /* 0xBF66C16C, 0x16B02E5C */ -const W3: f64 = 7.93650558643019558500e-04; /* 0x3F4A019F, 0x98CF38B6 */ -const W4: f64 = -5.95187557450339963135e-04; /* 0xBF4380CB, 0x8C0FE741 */ -const W5: f64 = 8.36339918996282139126e-04; /* 0x3F4B67BA, 0x4CDAD5D1 */ -const W6: f64 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ - -/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ -fn sin_pi(mut x: f64) -> f64 -{ - let mut n: isize; - - /* spurious inexact if odd int */ - x = 2.0*(x*0.5 - floor(x*0.5)); /* x mod 2.0 */ - - n = (x*4.0) as isize; - n = (n+1)/2; - x -= (n as f64)*0.5; - x *= PI; - - match n { - 1 => k_cos(x, 0.0), - 2 => k_sin(-x, 0.0, 0), - 3 => -k_cos(x, 0.0), - 0|_ => k_sin(x, 0.0, 0), - } -} - -pub fn lgamma(x: f64) -> f64 { - lgamma_r(x).0 -} - -pub fn lgamma_r(mut x: f64) -> (f64, isize) -{ - let u: u64 = x.to_bits(); - let mut t: f64; - let y: f64; - let mut z: f64; - let nadj: f64; - let p: f64; - let p1: f64; - let p2: f64; - let p3: f64; - let q: f64; - let mut r: f64; - let w: f64; - let ix: u32; - let sign: bool; - let i: isize; - let mut signgam: isize; - - /* purge off +-inf, NaN, +-0, tiny and negative arguments */ - signgam = 1; - sign = (u>>63) != 0; - ix = ((u>>32) as u32) & 0x7fffffff; - if ix >= 0x7ff00000 { - return (x*x, signgam); - } - if ix < (0x3ff-70)<<20 { /* |x|<2**-70, return -log(|x|) */ - if sign { - x = -x; - signgam = -1; - } - return (-log(x), signgam); - } - if sign { - x = -x; - t = sin_pi(x); - if t == 0.0 { /* -integer */ - return (1.0/(x-x), signgam); - } - if t > 0.0 { - signgam = -1; - } else { - t = -t; - } - nadj = log(PI/(t*x)); - } else { - nadj = 0.0; - } - - /* purge off 1 and 2 */ - if (ix == 0x3ff00000 || ix == 0x40000000) && (u & 0xffffffff) == 0 { - r = 0.0; - } - /* for x < 2.0 */ - else if ix < 0x40000000 { - if ix <= 0x3feccccc { /* lgamma(x) = lgamma(x+1)-log(x) */ - r = -log(x); - if ix >= 0x3FE76944 { - y = 1.0 - x; - i = 0; - } else if ix >= 0x3FCDA661 { - y = x - (TC-1.0); - i = 1; - } else { - y = x; - i = 2; - } - } else { - r = 0.0; - if ix >= 0x3FFBB4C3 { /* [1.7316,2] */ - y = 2.0 - x; - i = 0; - } else if ix >= 0x3FF3B4C4 { /* [1.23,1.73] */ - y = x - TC; - i = 1; - } else { - y = x - 1.0; - i = 2; - } - } - match i { - 0 => { - z = y*y; - p1 = A0+z*(A2+z*(A4+z*(A6+z*(A8+z*A10)))); - p2 = z*(A1+z*(A3+z*(A5+z*(A7+z*(A9+z*A11))))); - p = y*p1+p2; - r += p-0.5*y; - } - 1 => { - z = y*y; - w = z*y; - p1 = T0+w*(T3+w*(T6+w*(T9 +w*T12))); /* parallel comp */ - p2 = T1+w*(T4+w*(T7+w*(T10+w*T13))); - p3 = T2+w*(T5+w*(T8+w*(T11+w*T14))); - p = z*p1-(TT-w*(p2+y*p3)); - r += TF + p; - } - 2 => { - p1 = y*(U0+y*(U1+y*(U2+y*(U3+y*(U4+y*U5))))); - p2 = 1.0+y*(V1+y*(V2+y*(V3+y*(V4+y*V5)))); - r += -0.5*y + p1/p2; - } - #[cfg(feature = "checked")] - _ => unreachable!(), - #[cfg(not(feature = "checked"))] - _ => {} - } - } else if ix < 0x40200000 { /* x < 8.0 */ - i = x as isize; - y = x - (i as f64); - p = y*(S0+y*(S1+y*(S2+y*(S3+y*(S4+y*(S5+y*S6)))))); - q = 1.0+y*(R1+y*(R2+y*(R3+y*(R4+y*(R5+y*R6))))); - r = 0.5*y+p/q; - z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ - // TODO: In C, this was implemented using switch jumps with fallthrough. - // Does this implementation have performance problems? - if i >= 7 { z *= y + 6.0; } - if i >= 6 { z *= y + 5.0; } - if i >= 5 { z *= y + 4.0; } - if i >= 4 { z *= y + 3.0; } - if i >= 3 { - z *= y + 2.0; - r += log(z); - } - } else if ix < 0x43900000 { /* 8.0 <= x < 2**58 */ - t = log(x); - z = 1.0/x; - y = z*z; - w = W0+z*(W1+y*(W2+y*(W3+y*(W4+y*(W5+y*W6))))); - r = (x-0.5)*(t-1.0)+w; - } else { /* 2**58 <= x <= inf */ - r = x*(log(x)-1.0); - } - if sign { - r = nadj - r; - } - return (r, signgam); -} +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* lgamma_r(x, signgamp) + * Reentrant version of the logarithm of the Gamma function + * with user provide pointer for the sign of Gamma(x). + * + * Method: + * 1. Argument Reduction for 0 < x <= 8 + * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may + * reduce x to a number in [1.5,2.5] by + * lgamma(1+s) = log(s) + lgamma(s) + * for example, + * lgamma(7.3) = log(6.3) + lgamma(6.3) + * = log(6.3*5.3) + lgamma(5.3) + * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) + * 2. Polynomial approximation of lgamma around its + * minimun ymin=1.461632144968362245 to maintain monotonicity. + * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use + * Let z = x-ymin; + * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) + * where + * poly(z) is a 14 degree polynomial. + * 2. Rational approximation in the primary interval [2,3] + * We use the following approximation: + * s = x-2.0; + * lgamma(x) = 0.5*s + s*P(s)/Q(s) + * with accuracy + * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 + * Our algorithms are based on the following observation + * + * zeta(2)-1 2 zeta(3)-1 3 + * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... + * 2 3 + * + * where Euler = 0.5771... is the Euler constant, which is very + * close to 0.5. + * + * 3. For x>=8, we have + * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... + * (better formula: + * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) + * Let z = 1/x, then we approximation + * f(z) = lgamma(x) - (x-0.5)(log(x)-1) + * by + * 3 5 11 + * w = w0 + w1*z + w2*z + w3*z + ... + w6*z + * where + * |w - f(z)| < 2**-58.74 + * + * 4. For negative x, since (G is gamma function) + * -x*G(-x)*G(x) = PI/sin(PI*x), + * we have + * G(x) = PI/(sin(PI*x)*(-x)*G(-x)) + * since G(-x) is positive, sign(G(x)) = sign(sin(PI*x)) for x<0 + * Hence, for x<0, signgam = sign(sin(PI*x)) and + * lgamma(x) = log(|Gamma(x)|) + * = log(PI/(|x*sin(PI*x)|)) - lgamma(-x); + * Note: one should avoid compute PI*(-x) directly in the + * computation of sin(PI*(-x)). + * + * 5. Special Cases + * lgamma(2+s) ~ s*(1-Euler) for tiny s + * lgamma(1) = lgamma(2) = 0 + * lgamma(x) ~ -log(|x|) for tiny x + * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero + * lgamma(inf) = inf + * lgamma(-inf) = inf (bug for bug compatible with C99!?) + * + */ + +use super::{floor, k_cos, k_sin, log}; + +const PI: f64 = 3.14159265358979311600e+00; /* 0x400921FB, 0x54442D18 */ +const A0: f64 = 7.72156649015328655494e-02; /* 0x3FB3C467, 0xE37DB0C8 */ +const A1: f64 = 3.22467033424113591611e-01; /* 0x3FD4A34C, 0xC4A60FAD */ +const A2: f64 = 6.73523010531292681824e-02; /* 0x3FB13E00, 0x1A5562A7 */ +const A3: f64 = 2.05808084325167332806e-02; /* 0x3F951322, 0xAC92547B */ +const A4: f64 = 7.38555086081402883957e-03; /* 0x3F7E404F, 0xB68FEFE8 */ +const A5: f64 = 2.89051383673415629091e-03; /* 0x3F67ADD8, 0xCCB7926B */ +const A6: f64 = 1.19270763183362067845e-03; /* 0x3F538A94, 0x116F3F5D */ +const A7: f64 = 5.10069792153511336608e-04; /* 0x3F40B6C6, 0x89B99C00 */ +const A8: f64 = 2.20862790713908385557e-04; /* 0x3F2CF2EC, 0xED10E54D */ +const A9: f64 = 1.08011567247583939954e-04; /* 0x3F1C5088, 0x987DFB07 */ +const A10: f64 = 2.52144565451257326939e-05; /* 0x3EFA7074, 0x428CFA52 */ +const A11: f64 = 4.48640949618915160150e-05; /* 0x3F07858E, 0x90A45837 */ +const TC: f64 = 1.46163214496836224576e+00; /* 0x3FF762D8, 0x6356BE3F */ +const TF: f64 = -1.21486290535849611461e-01; /* 0xBFBF19B9, 0xBCC38A42 */ +/* tt = -(tail of TF) */ +const TT: f64 = -3.63867699703950536541e-18; /* 0xBC50C7CA, 0xA48A971F */ +const T0: f64 = 4.83836122723810047042e-01; /* 0x3FDEF72B, 0xC8EE38A2 */ +const T1: f64 = -1.47587722994593911752e-01; /* 0xBFC2E427, 0x8DC6C509 */ +const T2: f64 = 6.46249402391333854778e-02; /* 0x3FB08B42, 0x94D5419B */ +const T3: f64 = -3.27885410759859649565e-02; /* 0xBFA0C9A8, 0xDF35B713 */ +const T4: f64 = 1.79706750811820387126e-02; /* 0x3F9266E7, 0x970AF9EC */ +const T5: f64 = -1.03142241298341437450e-02; /* 0xBF851F9F, 0xBA91EC6A */ +const T6: f64 = 6.10053870246291332635e-03; /* 0x3F78FCE0, 0xE370E344 */ +const T7: f64 = -3.68452016781138256760e-03; /* 0xBF6E2EFF, 0xB3E914D7 */ +const T8: f64 = 2.25964780900612472250e-03; /* 0x3F6282D3, 0x2E15C915 */ +const T9: f64 = -1.40346469989232843813e-03; /* 0xBF56FE8E, 0xBF2D1AF1 */ +const T10: f64 = 8.81081882437654011382e-04; /* 0x3F4CDF0C, 0xEF61A8E9 */ +const T11: f64 = -5.38595305356740546715e-04; /* 0xBF41A610, 0x9C73E0EC */ +const T12: f64 = 3.15632070903625950361e-04; /* 0x3F34AF6D, 0x6C0EBBF7 */ +const T13: f64 = -3.12754168375120860518e-04; /* 0xBF347F24, 0xECC38C38 */ +const T14: f64 = 3.35529192635519073543e-04; /* 0x3F35FD3E, 0xE8C2D3F4 */ +const U0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ +const U1: f64 = 6.32827064025093366517e-01; /* 0x3FE4401E, 0x8B005DFF */ +const U2: f64 = 1.45492250137234768737e+00; /* 0x3FF7475C, 0xD119BD6F */ +const U3: f64 = 9.77717527963372745603e-01; /* 0x3FEF4976, 0x44EA8450 */ +const U4: f64 = 2.28963728064692451092e-01; /* 0x3FCD4EAE, 0xF6010924 */ +const U5: f64 = 1.33810918536787660377e-02; /* 0x3F8B678B, 0xBF2BAB09 */ +const V1: f64 = 2.45597793713041134822e+00; /* 0x4003A5D7, 0xC2BD619C */ +const V2: f64 = 2.12848976379893395361e+00; /* 0x40010725, 0xA42B18F5 */ +const V3: f64 = 7.69285150456672783825e-01; /* 0x3FE89DFB, 0xE45050AF */ +const V4: f64 = 1.04222645593369134254e-01; /* 0x3FBAAE55, 0xD6537C88 */ +const V5: f64 = 3.21709242282423911810e-03; /* 0x3F6A5ABB, 0x57D0CF61 */ +const S0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ +const S1: f64 = 2.14982415960608852501e-01; /* 0x3FCB848B, 0x36E20878 */ +const S2: f64 = 3.25778796408930981787e-01; /* 0x3FD4D98F, 0x4F139F59 */ +const S3: f64 = 1.46350472652464452805e-01; /* 0x3FC2BB9C, 0xBEE5F2F7 */ +const S4: f64 = 2.66422703033638609560e-02; /* 0x3F9B481C, 0x7E939961 */ +const S5: f64 = 1.84028451407337715652e-03; /* 0x3F5E26B6, 0x7368F239 */ +const S6: f64 = 3.19475326584100867617e-05; /* 0x3F00BFEC, 0xDD17E945 */ +const R1: f64 = 1.39200533467621045958e+00; /* 0x3FF645A7, 0x62C4AB74 */ +const R2: f64 = 7.21935547567138069525e-01; /* 0x3FE71A18, 0x93D3DCDC */ +const R3: f64 = 1.71933865632803078993e-01; /* 0x3FC601ED, 0xCCFBDF27 */ +const R4: f64 = 1.86459191715652901344e-02; /* 0x3F9317EA, 0x742ED475 */ +const R5: f64 = 7.77942496381893596434e-04; /* 0x3F497DDA, 0xCA41A95B */ +const R6: f64 = 7.32668430744625636189e-06; /* 0x3EDEBAF7, 0xA5B38140 */ +const W0: f64 = 4.18938533204672725052e-01; /* 0x3FDACFE3, 0x90C97D69 */ +const W1: f64 = 8.33333333333329678849e-02; /* 0x3FB55555, 0x5555553B */ +const W2: f64 = -2.77777777728775536470e-03; /* 0xBF66C16C, 0x16B02E5C */ +const W3: f64 = 7.93650558643019558500e-04; /* 0x3F4A019F, 0x98CF38B6 */ +const W4: f64 = -5.95187557450339963135e-04; /* 0xBF4380CB, 0x8C0FE741 */ +const W5: f64 = 8.36339918996282139126e-04; /* 0x3F4B67BA, 0x4CDAD5D1 */ +const W6: f64 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ + +/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ +fn sin_pi(mut x: f64) -> f64 { + let mut n: i32; + + /* spurious inexact if odd int */ + x = 2.0 * (x * 0.5 - floor(x * 0.5)); /* x mod 2.0 */ + + n = (x * 4.0) as i32; + n = (n + 1) / 2; + x -= (n as f64) * 0.5; + x *= PI; + + match n { + 1 => k_cos(x, 0.0), + 2 => k_sin(-x, 0.0, 0), + 3 => -k_cos(x, 0.0), + 0 | _ => k_sin(x, 0.0, 0), + } +} + +pub fn lgamma(x: f64) -> f64 { + lgamma_r(x).0 +} + +pub fn lgamma_r(mut x: f64) -> (f64, i32) { + let u: u64 = x.to_bits(); + let mut t: f64; + let y: f64; + let mut z: f64; + let nadj: f64; + let p: f64; + let p1: f64; + let p2: f64; + let p3: f64; + let q: f64; + let mut r: f64; + let w: f64; + let ix: u32; + let sign: bool; + let i: i32; + let mut signgam: i32; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + signgam = 1; + sign = (u >> 63) != 0; + ix = ((u >> 32) as u32) & 0x7fffffff; + if ix >= 0x7ff00000 { + return (x * x, signgam); + } + if ix < (0x3ff - 70) << 20 { + /* |x|<2**-70, return -log(|x|) */ + if sign { + x = -x; + signgam = -1; + } + return (-log(x), signgam); + } + if sign { + x = -x; + t = sin_pi(x); + if t == 0.0 { + /* -integer */ + return (1.0 / (x - x), signgam); + } + if t > 0.0 { + signgam = -1; + } else { + t = -t; + } + nadj = log(PI / (t * x)); + } else { + nadj = 0.0; + } + + /* purge off 1 and 2 */ + if (ix == 0x3ff00000 || ix == 0x40000000) && (u & 0xffffffff) == 0 { + r = 0.0; + } + /* for x < 2.0 */ + else if ix < 0x40000000 { + if ix <= 0x3feccccc { + /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -log(x); + if ix >= 0x3FE76944 { + y = 1.0 - x; + i = 0; + } else if ix >= 0x3FCDA661 { + y = x - (TC - 1.0); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0; + if ix >= 0x3FFBB4C3 { + /* [1.7316,2] */ + y = 2.0 - x; + i = 0; + } else if ix >= 0x3FF3B4C4 { + /* [1.23,1.73] */ + y = x - TC; + i = 1; + } else { + y = x - 1.0; + i = 2; + } + } + match i { + 0 => { + z = y * y; + p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); + p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); + p = y * p1 + p2; + r += p - 0.5 * y; + } + 1 => { + z = y * y; + w = z * y; + p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ + p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); + p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); + p = z * p1 - (TT - w * (p2 + y * p3)); + r += TF + p; + } + 2 => { + p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); + p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); + r += -0.5 * y + p1 / p2; + } + #[cfg(feature = "checked")] + _ => unreachable!(), + #[cfg(not(feature = "checked"))] + _ => {} + } + } else if ix < 0x40200000 { + /* x < 8.0 */ + i = x as i32; + y = x - (i as f64); + p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); + q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); + r = 0.5 * y + p / q; + z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ + // TODO: In C, this was implemented using switch jumps with fallthrough. + // Does this implementation have performance problems? + if i >= 7 { + z *= y + 6.0; + } + if i >= 6 { + z *= y + 5.0; + } + if i >= 5 { + z *= y + 4.0; + } + if i >= 4 { + z *= y + 3.0; + } + if i >= 3 { + z *= y + 2.0; + r += log(z); + } + } else if ix < 0x43900000 { + /* 8.0 <= x < 2**58 */ + t = log(x); + z = 1.0 / x; + y = z * z; + w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); + r = (x - 0.5) * (t - 1.0) + w; + } else { + /* 2**58 <= x <= inf */ + r = x * (log(x) - 1.0); + } + if sign { + r = nadj - r; + } + return (r, signgam); +} diff --git a/library/compiler-builtins/libm/src/math/lgammaf.rs b/library/compiler-builtins/libm/src/math/lgammaf.rs index 60effa316740c..8fe8060b5ece7 100644 --- a/library/compiler-builtins/libm/src/math/lgammaf.rs +++ b/library/compiler-builtins/libm/src/math/lgammaf.rs @@ -1,244 +1,258 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * 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. - * ==================================================== - */ - -use super::{floorf, k_cosf, k_sinf, logf}; - -const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ -const A0: f32 = 7.7215664089e-02; /* 0x3d9e233f */ -const A1: f32 = 3.2246702909e-01; /* 0x3ea51a66 */ -const A2: f32 = 6.7352302372e-02; /* 0x3d89f001 */ -const A3: f32 = 2.0580807701e-02; /* 0x3ca89915 */ -const A4: f32 = 7.3855509982e-03; /* 0x3bf2027e */ -const A5: f32 = 2.8905137442e-03; /* 0x3b3d6ec6 */ -const A6: f32 = 1.1927076848e-03; /* 0x3a9c54a1 */ -const A7: f32 = 5.1006977446e-04; /* 0x3a05b634 */ -const A8: f32 = 2.2086278477e-04; /* 0x39679767 */ -const A9: f32 = 1.0801156895e-04; /* 0x38e28445 */ -const A10: f32 = 2.5214456400e-05; /* 0x37d383a2 */ -const A11: f32 = 4.4864096708e-05; /* 0x383c2c75 */ -const TC: f32 = 1.4616321325e+00; /* 0x3fbb16c3 */ -const TF: f32 = -1.2148628384e-01; /* 0xbdf8cdcd */ -/* TT = -(tail of TF) */ -const TT: f32 = 6.6971006518e-09; /* 0x31e61c52 */ -const T0: f32 = 4.8383611441e-01; /* 0x3ef7b95e */ -const T1: f32 = -1.4758771658e-01; /* 0xbe17213c */ -const T2: f32 = 6.4624942839e-02; /* 0x3d845a15 */ -const T3: f32 = -3.2788541168e-02; /* 0xbd064d47 */ -const T4: f32 = 1.7970675603e-02; /* 0x3c93373d */ -const T5: f32 = -1.0314224288e-02; /* 0xbc28fcfe */ -const T6: f32 = 6.1005386524e-03; /* 0x3bc7e707 */ -const T7: f32 = -3.6845202558e-03; /* 0xbb7177fe */ -const T8: f32 = 2.2596477065e-03; /* 0x3b141699 */ -const T9: f32 = -1.4034647029e-03; /* 0xbab7f476 */ -const T10: f32 = 8.8108185446e-04; /* 0x3a66f867 */ -const T11: f32 = -5.3859531181e-04; /* 0xba0d3085 */ -const T12: f32 = 3.1563205994e-04; /* 0x39a57b6b */ -const T13: f32 = -3.1275415677e-04; /* 0xb9a3f927 */ -const T14: f32 = 3.3552918467e-04; /* 0x39afe9f7 */ -const U0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ -const U1: f32 = 6.3282704353e-01; /* 0x3f2200f4 */ -const U2: f32 = 1.4549225569e+00; /* 0x3fba3ae7 */ -const U3: f32 = 9.7771751881e-01; /* 0x3f7a4bb2 */ -const U4: f32 = 2.2896373272e-01; /* 0x3e6a7578 */ -const U5: f32 = 1.3381091878e-02; /* 0x3c5b3c5e */ -const V1: f32 = 2.4559779167e+00; /* 0x401d2ebe */ -const V2: f32 = 2.1284897327e+00; /* 0x4008392d */ -const V3: f32 = 7.6928514242e-01; /* 0x3f44efdf */ -const V4: f32 = 1.0422264785e-01; /* 0x3dd572af */ -const V5: f32 = 3.2170924824e-03; /* 0x3b52d5db */ -const S0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ -const S1: f32 = 2.1498242021e-01; /* 0x3e5c245a */ -const S2: f32 = 3.2577878237e-01; /* 0x3ea6cc7a */ -const S3: f32 = 1.4635047317e-01; /* 0x3e15dce6 */ -const S4: f32 = 2.6642270386e-02; /* 0x3cda40e4 */ -const S5: f32 = 1.8402845599e-03; /* 0x3af135b4 */ -const S6: f32 = 3.1947532989e-05; /* 0x3805ff67 */ -const R1: f32 = 1.3920053244e+00; /* 0x3fb22d3b */ -const R2: f32 = 7.2193557024e-01; /* 0x3f38d0c5 */ -const R3: f32 = 1.7193385959e-01; /* 0x3e300f6e */ -const R4: f32 = 1.8645919859e-02; /* 0x3c98bf54 */ -const R5: f32 = 7.7794247773e-04; /* 0x3a4beed6 */ -const R6: f32 = 7.3266842264e-06; /* 0x36f5d7bd */ -const W0: f32 = 4.1893854737e-01; /* 0x3ed67f1d */ -const W1: f32 = 8.3333335817e-02; /* 0x3daaaaab */ -const W2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ -const W3: f32 = 7.9365057172e-04; /* 0x3a500cfd */ -const W4: f32 = -5.9518753551e-04; /* 0xba1c065c */ -const W5: f32 = 8.3633989561e-04; /* 0x3a5b3dd2 */ -const W6: f32 = -1.6309292987e-03; /* 0xbad5c4e8 */ - -/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ -fn sin_pi(mut x: f32) -> f32 -{ - let mut y: f64; - let mut n: isize; - - /* spurious inexact if odd int */ - x = 2.0*(x*0.5 - floorf(x*0.5)); /* x mod 2.0 */ - - n = (x*4.0) as isize; - n = (n+1)/2; - y = (x as f64) - (n as f64)*0.5; - y *= 3.14159265358979323846; - match n { - 1 => k_cosf(y), - 2 => k_sinf(-y), - 3 => -k_cosf(y), - 0|_ => k_sinf(y), - } -} - -pub fn lgammaf(x: f32) -> f32 { - lgammaf_r(x).0 -} - -pub fn lgammaf_r(mut x: f32) -> (f32, isize) -{ - let u = x.to_bits(); - let mut t: f32; - let y: f32; - let mut z: f32; - let nadj: f32; - let p: f32; - let p1: f32; - let p2: f32; - let p3: f32; - let q: f32; - let mut r: f32; - let w: f32; - let ix: u32; - let i: isize; - let sign: bool; - let mut signgam: isize; - - /* purge off +-inf, NaN, +-0, tiny and negative arguments */ - signgam = 1; - sign = (u>>31) != 0; - ix = u & 0x7fffffff; - if ix >= 0x7f800000 { - return (x*x, signgam); - } - if ix < 0x35000000 { /* |x| < 2**-21, return -log(|x|) */ - if sign { - signgam = -1; - x = -x; - } - return (-logf(x), signgam); - } - if sign { - x = -x; - t = sin_pi(x); - if t == 0.0 { /* -integer */ - return (1.0/(x-x), signgam); - } - if t > 0.0 { - signgam = -1; - } else { - t = -t; - } - nadj = logf(PI/(t*x)); - } else { - nadj = 0.0; - } - - /* purge off 1 and 2 */ - if ix == 0x3f800000 || ix == 0x40000000 { - r = 0.0; - } - /* for x < 2.0 */ - else if ix < 0x40000000 { - if ix <= 0x3f666666 { /* lgamma(x) = lgamma(x+1)-log(x) */ - r = -logf(x); - if ix >= 0x3f3b4a20 { - y = 1.0 - x; - i = 0; - } else if ix >= 0x3e6d3308 { - y = x - (TC-1.0); - i = 1; - } else { - y = x; - i = 2; - } - } else { - r = 0.0; - if ix >= 0x3fdda618 { /* [1.7316,2] */ - y = 2.0 - x; - i = 0; - } else if ix >= 0x3F9da620 { /* [1.23,1.73] */ - y = x - TC; - i = 1; - } else { - y = x - 1.0; - i = 2; - } - } - match i { - 0 => { - z = y*y; - p1 = A0+z*(A2+z*(A4+z*(A6+z*(A8+z*A10)))); - p2 = z*(A1+z*(A3+z*(A5+z*(A7+z*(A9+z*A11))))); - p = y*p1+p2; - r += p - 0.5*y; - } - 1 => { - z = y*y; - w = z*y; - p1 = T0+w*(T3+w*(T6+w*(T9 +w*T12))); /* parallel comp */ - p2 = T1+w*(T4+w*(T7+w*(T10+w*T13))); - p3 = T2+w*(T5+w*(T8+w*(T11+w*T14))); - p = z*p1-(TT-w*(p2+y*p3)); - r += TF + p; - } - 2 => { - p1 = y*(U0+y*(U1+y*(U2+y*(U3+y*(U4+y*U5))))); - p2 = 1.0+y*(V1+y*(V2+y*(V3+y*(V4+y*V5)))); - r += -0.5*y + p1/p2; - } - #[cfg(feature = "checked")] - _ => unreachable!(), - #[cfg(not(feature = "checked"))] - _ => {} - } - } else if ix < 0x41000000 { /* x < 8.0 */ - i = x as isize; - y = x - (i as f32); - p = y*(S0+y*(S1+y*(S2+y*(S3+y*(S4+y*(S5+y*S6)))))); - q = 1.0+y*(R1+y*(R2+y*(R3+y*(R4+y*(R5+y*R6))))); - r = 0.5*y+p/q; - z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ - // TODO: In C, this was implemented using switch jumps with fallthrough. - // Does this implementation have performance problems? - if i >= 7 { z *= y + 6.0; } - if i >= 6 { z *= y + 5.0; } - if i >= 5 { z *= y + 4.0; } - if i >= 4 { z *= y + 3.0; } - if i >= 3 { - z *= y + 2.0; - r += logf(z); - } - } else if ix < 0x5c800000 { /* 8.0 <= x < 2**58 */ - t = logf(x); - z = 1.0/x; - y = z*z; - w = W0+z*(W1+y*(W2+y*(W3+y*(W4+y*(W5+y*W6))))); - r = (x-0.5)*(t-1.0)+w; - } else { /* 2**58 <= x <= inf */ - r = x*(logf(x)-1.0); - } - if sign { - r = nadj - r; - } - return (r, signgam); -} +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + +use super::{floorf, k_cosf, k_sinf, logf}; + +const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ +const A0: f32 = 7.7215664089e-02; /* 0x3d9e233f */ +const A1: f32 = 3.2246702909e-01; /* 0x3ea51a66 */ +const A2: f32 = 6.7352302372e-02; /* 0x3d89f001 */ +const A3: f32 = 2.0580807701e-02; /* 0x3ca89915 */ +const A4: f32 = 7.3855509982e-03; /* 0x3bf2027e */ +const A5: f32 = 2.8905137442e-03; /* 0x3b3d6ec6 */ +const A6: f32 = 1.1927076848e-03; /* 0x3a9c54a1 */ +const A7: f32 = 5.1006977446e-04; /* 0x3a05b634 */ +const A8: f32 = 2.2086278477e-04; /* 0x39679767 */ +const A9: f32 = 1.0801156895e-04; /* 0x38e28445 */ +const A10: f32 = 2.5214456400e-05; /* 0x37d383a2 */ +const A11: f32 = 4.4864096708e-05; /* 0x383c2c75 */ +const TC: f32 = 1.4616321325e+00; /* 0x3fbb16c3 */ +const TF: f32 = -1.2148628384e-01; /* 0xbdf8cdcd */ +/* TT = -(tail of TF) */ +const TT: f32 = 6.6971006518e-09; /* 0x31e61c52 */ +const T0: f32 = 4.8383611441e-01; /* 0x3ef7b95e */ +const T1: f32 = -1.4758771658e-01; /* 0xbe17213c */ +const T2: f32 = 6.4624942839e-02; /* 0x3d845a15 */ +const T3: f32 = -3.2788541168e-02; /* 0xbd064d47 */ +const T4: f32 = 1.7970675603e-02; /* 0x3c93373d */ +const T5: f32 = -1.0314224288e-02; /* 0xbc28fcfe */ +const T6: f32 = 6.1005386524e-03; /* 0x3bc7e707 */ +const T7: f32 = -3.6845202558e-03; /* 0xbb7177fe */ +const T8: f32 = 2.2596477065e-03; /* 0x3b141699 */ +const T9: f32 = -1.4034647029e-03; /* 0xbab7f476 */ +const T10: f32 = 8.8108185446e-04; /* 0x3a66f867 */ +const T11: f32 = -5.3859531181e-04; /* 0xba0d3085 */ +const T12: f32 = 3.1563205994e-04; /* 0x39a57b6b */ +const T13: f32 = -3.1275415677e-04; /* 0xb9a3f927 */ +const T14: f32 = 3.3552918467e-04; /* 0x39afe9f7 */ +const U0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ +const U1: f32 = 6.3282704353e-01; /* 0x3f2200f4 */ +const U2: f32 = 1.4549225569e+00; /* 0x3fba3ae7 */ +const U3: f32 = 9.7771751881e-01; /* 0x3f7a4bb2 */ +const U4: f32 = 2.2896373272e-01; /* 0x3e6a7578 */ +const U5: f32 = 1.3381091878e-02; /* 0x3c5b3c5e */ +const V1: f32 = 2.4559779167e+00; /* 0x401d2ebe */ +const V2: f32 = 2.1284897327e+00; /* 0x4008392d */ +const V3: f32 = 7.6928514242e-01; /* 0x3f44efdf */ +const V4: f32 = 1.0422264785e-01; /* 0x3dd572af */ +const V5: f32 = 3.2170924824e-03; /* 0x3b52d5db */ +const S0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ +const S1: f32 = 2.1498242021e-01; /* 0x3e5c245a */ +const S2: f32 = 3.2577878237e-01; /* 0x3ea6cc7a */ +const S3: f32 = 1.4635047317e-01; /* 0x3e15dce6 */ +const S4: f32 = 2.6642270386e-02; /* 0x3cda40e4 */ +const S5: f32 = 1.8402845599e-03; /* 0x3af135b4 */ +const S6: f32 = 3.1947532989e-05; /* 0x3805ff67 */ +const R1: f32 = 1.3920053244e+00; /* 0x3fb22d3b */ +const R2: f32 = 7.2193557024e-01; /* 0x3f38d0c5 */ +const R3: f32 = 1.7193385959e-01; /* 0x3e300f6e */ +const R4: f32 = 1.8645919859e-02; /* 0x3c98bf54 */ +const R5: f32 = 7.7794247773e-04; /* 0x3a4beed6 */ +const R6: f32 = 7.3266842264e-06; /* 0x36f5d7bd */ +const W0: f32 = 4.1893854737e-01; /* 0x3ed67f1d */ +const W1: f32 = 8.3333335817e-02; /* 0x3daaaaab */ +const W2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ +const W3: f32 = 7.9365057172e-04; /* 0x3a500cfd */ +const W4: f32 = -5.9518753551e-04; /* 0xba1c065c */ +const W5: f32 = 8.3633989561e-04; /* 0x3a5b3dd2 */ +const W6: f32 = -1.6309292987e-03; /* 0xbad5c4e8 */ + +/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ +fn sin_pi(mut x: f32) -> f32 { + let mut y: f64; + let mut n: isize; + + /* spurious inexact if odd int */ + x = 2.0 * (x * 0.5 - floorf(x * 0.5)); /* x mod 2.0 */ + + n = (x * 4.0) as isize; + n = (n + 1) / 2; + y = (x as f64) - (n as f64) * 0.5; + y *= 3.14159265358979323846; + match n { + 1 => k_cosf(y), + 2 => k_sinf(-y), + 3 => -k_cosf(y), + 0 | _ => k_sinf(y), + } +} + +pub fn lgammaf(x: f32) -> f32 { + lgammaf_r(x).0 +} + +pub fn lgammaf_r(mut x: f32) -> (f32, isize) { + let u = x.to_bits(); + let mut t: f32; + let y: f32; + let mut z: f32; + let nadj: f32; + let p: f32; + let p1: f32; + let p2: f32; + let p3: f32; + let q: f32; + let mut r: f32; + let w: f32; + let ix: u32; + let i: isize; + let sign: bool; + let mut signgam: isize; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + signgam = 1; + sign = (u >> 31) != 0; + ix = u & 0x7fffffff; + if ix >= 0x7f800000 { + return (x * x, signgam); + } + if ix < 0x35000000 { + /* |x| < 2**-21, return -log(|x|) */ + if sign { + signgam = -1; + x = -x; + } + return (-logf(x), signgam); + } + if sign { + x = -x; + t = sin_pi(x); + if t == 0.0 { + /* -integer */ + return (1.0 / (x - x), signgam); + } + if t > 0.0 { + signgam = -1; + } else { + t = -t; + } + nadj = logf(PI / (t * x)); + } else { + nadj = 0.0; + } + + /* purge off 1 and 2 */ + if ix == 0x3f800000 || ix == 0x40000000 { + r = 0.0; + } + /* for x < 2.0 */ + else if ix < 0x40000000 { + if ix <= 0x3f666666 { + /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -logf(x); + if ix >= 0x3f3b4a20 { + y = 1.0 - x; + i = 0; + } else if ix >= 0x3e6d3308 { + y = x - (TC - 1.0); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0; + if ix >= 0x3fdda618 { + /* [1.7316,2] */ + y = 2.0 - x; + i = 0; + } else if ix >= 0x3F9da620 { + /* [1.23,1.73] */ + y = x - TC; + i = 1; + } else { + y = x - 1.0; + i = 2; + } + } + match i { + 0 => { + z = y * y; + p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); + p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); + p = y * p1 + p2; + r += p - 0.5 * y; + } + 1 => { + z = y * y; + w = z * y; + p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ + p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); + p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); + p = z * p1 - (TT - w * (p2 + y * p3)); + r += TF + p; + } + 2 => { + p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); + p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); + r += -0.5 * y + p1 / p2; + } + #[cfg(feature = "checked")] + _ => unreachable!(), + #[cfg(not(feature = "checked"))] + _ => {} + } + } else if ix < 0x41000000 { + /* x < 8.0 */ + i = x as isize; + y = x - (i as f32); + p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); + q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); + r = 0.5 * y + p / q; + z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ + // TODO: In C, this was implemented using switch jumps with fallthrough. + // Does this implementation have performance problems? + if i >= 7 { + z *= y + 6.0; + } + if i >= 6 { + z *= y + 5.0; + } + if i >= 5 { + z *= y + 4.0; + } + if i >= 4 { + z *= y + 3.0; + } + if i >= 3 { + z *= y + 2.0; + r += logf(z); + } + } else if ix < 0x5c800000 { + /* 8.0 <= x < 2**58 */ + t = logf(x); + z = 1.0 / x; + y = z * z; + w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); + r = (x - 0.5) * (t - 1.0) + w; + } else { + /* 2**58 <= x <= inf */ + r = x * (logf(x) - 1.0); + } + if sign { + r = nadj - r; + } + return (r, signgam); +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 6e53b020c4bb9..b70b0cd6b3289 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -118,8 +118,6 @@ mod frexp; mod frexpf; mod hypot; mod hypotf; -mod ldexp; -mod ldexpf; mod ilogb; mod ilogbf; mod j0; @@ -128,6 +126,8 @@ mod j1; mod j1f; mod jn; mod jnf; +mod ldexp; +mod ldexpf; mod lgamma; mod lgammaf; mod log; @@ -192,8 +192,8 @@ pub use self::cosh::cosh; pub use self::coshf::coshf; pub use self::erf::erf; pub use self::erf::erfc; -pub use self::erff::erff; pub use self::erff::erfcf; +pub use self::erff::erff; pub use self::exp::exp; pub use self::exp10::exp10; pub use self::exp10f::exp10f; @@ -216,8 +216,6 @@ pub use self::frexp::frexp; pub use self::frexpf::frexpf; pub use self::hypot::hypot; pub use self::hypotf::hypotf; -pub use self::ldexp::ldexp; -pub use self::ldexpf::ldexpf; pub use self::ilogb::ilogb; pub use self::ilogbf::ilogbf; pub use self::j0::j0; @@ -232,6 +230,8 @@ pub use self::jn::jn; pub use self::jn::yn; pub use self::jnf::jnf; pub use self::jnf::ynf; +pub use self::ldexp::ldexp; +pub use self::ldexpf::ldexpf; pub use self::lgamma::lgamma; pub use self::lgamma::lgamma_r; pub use self::lgammaf::lgammaf; diff --git a/library/compiler-builtins/libm/src/math/modf.rs b/library/compiler-builtins/libm/src/math/modf.rs index 1ff8ee116d0c7..a37f8b918a37d 100644 --- a/library/compiler-builtins/libm/src/math/modf.rs +++ b/library/compiler-builtins/libm/src/math/modf.rs @@ -1,33 +1,34 @@ -pub fn modf(x: f64) -> (f64, f64) { - let rv2: f64; - let mut u = x.to_bits(); - let mask: u64; - let e = ((u>>52 & 0x7ff) as isize) - 0x3ff; - - /* no fractional part */ - if e >= 52 { - rv2 = x; - if e == 0x400 && (u<<12) != 0 { /* nan */ - return (x, rv2); - } - u &= 1<<63; - return (f64::from_bits(u), rv2); - } - - /* no integral part*/ - if e < 0 { - u &= 1<<63; - rv2 = f64::from_bits(u); - return (x, rv2); - } - - mask = ((!0)>>12)>>e; - if (u & mask) == 0 { - rv2 = x; - u &= 1<<63; - return (f64::from_bits(u), rv2); - } - u &= !mask; - rv2 = f64::from_bits(u); - return (x - rv2, rv2); -} +pub fn modf(x: f64) -> (f64, f64) { + let rv2: f64; + let mut u = x.to_bits(); + let mask: u64; + let e = ((u >> 52 & 0x7ff) as isize) - 0x3ff; + + /* no fractional part */ + if e >= 52 { + rv2 = x; + if e == 0x400 && (u << 12) != 0 { + /* nan */ + return (x, rv2); + } + u &= 1 << 63; + return (f64::from_bits(u), rv2); + } + + /* no integral part*/ + if e < 0 { + u &= 1 << 63; + rv2 = f64::from_bits(u); + return (x, rv2); + } + + mask = ((!0) >> 12) >> e; + if (u & mask) == 0 { + rv2 = x; + u &= 1 << 63; + return (f64::from_bits(u), rv2); + } + u &= !mask; + rv2 = f64::from_bits(u); + return (x - rv2, rv2); +} diff --git a/library/compiler-builtins/libm/src/math/modff.rs b/library/compiler-builtins/libm/src/math/modff.rs index 5250e8d380104..4ce9052e7eaca 100644 --- a/library/compiler-builtins/libm/src/math/modff.rs +++ b/library/compiler-builtins/libm/src/math/modff.rs @@ -1,32 +1,33 @@ -pub fn modff(x: f32) -> (f32, f32) { - let rv2: f32; - let mut u: u32 = x.to_bits(); - let mask: u32; - let e = ((u>>23 & 0xff) as isize) - 0x7f; - - /* no fractional part */ - if e >= 23 { - rv2 = x; - if e == 0x80 && (u<<9) != 0 { /* nan */ - return (x, rv2); - } - u &= 0x80000000; - return (f32::from_bits(u), rv2); - } - /* no integral part */ - if e < 0 { - u &= 0x80000000; - rv2 = f32::from_bits(u); - return (x, rv2); - } - - mask = 0x007fffff>>e; - if (u & mask) == 0 { - rv2 = x; - u &= 0x80000000; - return (f32::from_bits(u), rv2); - } - u &= !mask; - rv2 = f32::from_bits(u); - return (x - rv2, rv2); -} +pub fn modff(x: f32) -> (f32, f32) { + let rv2: f32; + let mut u: u32 = x.to_bits(); + let mask: u32; + let e = ((u >> 23 & 0xff) as isize) - 0x7f; + + /* no fractional part */ + if e >= 23 { + rv2 = x; + if e == 0x80 && (u << 9) != 0 { + /* nan */ + return (x, rv2); + } + u &= 0x80000000; + return (f32::from_bits(u), rv2); + } + /* no integral part */ + if e < 0 { + u &= 0x80000000; + rv2 = f32::from_bits(u); + return (x, rv2); + } + + mask = 0x007fffff >> e; + if (u & mask) == 0 { + rv2 = x; + u &= 0x80000000; + return (f32::from_bits(u), rv2); + } + u &= !mask; + rv2 = f32::from_bits(u); + return (x - rv2, rv2); +} diff --git a/library/compiler-builtins/libm/src/math/remquo.rs b/library/compiler-builtins/libm/src/math/remquo.rs index 98f4b38581a5a..3681b947cc243 100644 --- a/library/compiler-builtins/libm/src/math/remquo.rs +++ b/library/compiler-builtins/libm/src/math/remquo.rs @@ -1,98 +1,97 @@ -pub fn remquo(mut x: f64, mut y: f64) -> (f64, isize) -{ - let ux: u64 = x.to_bits(); - let mut uy: u64 = y.to_bits(); - let mut ex = ((ux>>52) & 0x7ff) as isize; - let mut ey = ((uy>>52) & 0x7ff) as isize; - let sx = (ux>>63) != 0; - let sy = (uy>>63) != 0; - let mut q: u32; - let mut i: u64; - let mut uxi: u64 = ux; - - if (uy<<1) == 0 || y.is_nan() || ex == 0x7ff { - return ((x*y)/(x*y), 0); - } - if (ux<<1) == 0 { - return (x, 0); - } - - /* normalize x and y */ - if ex == 0 { - i = uxi << 12; - while (i>>63) == 0 { - ex -= 1; - i <<= 1; - } - uxi <<= -ex + 1; - } else { - uxi &= (!0) >> 12; - uxi |= 1 << 52; - } - if ey == 0 { - i = uy<<12; - while (i>>63) == 0 { - ey -= 1; - i <<= 1; - } - uy <<= -ey + 1; - } else { - uy &= (!0) >> 12; - uy |= 1 << 52; - } - - q = 0; - - if ex+1 != ey { - if ex < ey { - return (x, 0); - } - /* x mod y */ - while ex > ey { - i = uxi - uy; - if (i>>63) == 0 { - uxi = i; - q += 1; - } - uxi <<= 1; - q <<= 1; - ex -= 1; - } - i = uxi - uy; - if (i>>63) == 0 { - uxi = i; - q += 1; - } - if uxi == 0 { - ex = -60; - } else { - while (uxi>>52) == 0 { - uxi <<= 1; - ex -= 1; - } - } - } - - /* scale result and decide between |x| and |x|-|y| */ - if ex > 0 { - uxi -= 1 << 52; - uxi |= (ex as u64) << 52; - } else { - uxi >>= -ex + 1; - } - x = f64::from_bits(uxi); - if sy { - y = -y; - } - if ex == ey || (ex+1 == ey && (2.0*x > y || (2.0*x == y && (q%2) != 0))) { - x -= y; - q += 1; - } - q &= 0x7fffffff; - let quo = if sx ^ sy { -(q as isize) } else { q as isize }; - if sx { - (-x, quo) - } else { - (x, quo) - } -} +pub fn remquo(mut x: f64, mut y: f64) -> (f64, isize) { + let ux: u64 = x.to_bits(); + let mut uy: u64 = y.to_bits(); + let mut ex = ((ux >> 52) & 0x7ff) as isize; + let mut ey = ((uy >> 52) & 0x7ff) as isize; + let sx = (ux >> 63) != 0; + let sy = (uy >> 63) != 0; + let mut q: u32; + let mut i: u64; + let mut uxi: u64 = ux; + + if (uy << 1) == 0 || y.is_nan() || ex == 0x7ff { + return ((x * y) / (x * y), 0); + } + if (ux << 1) == 0 { + return (x, 0); + } + + /* normalize x and y */ + if ex == 0 { + i = uxi << 12; + while (i >> 63) == 0 { + ex -= 1; + i <<= 1; + } + uxi <<= -ex + 1; + } else { + uxi &= (!0) >> 12; + uxi |= 1 << 52; + } + if ey == 0 { + i = uy << 12; + while (i >> 63) == 0 { + ey -= 1; + i <<= 1; + } + uy <<= -ey + 1; + } else { + uy &= (!0) >> 12; + uy |= 1 << 52; + } + + q = 0; + + if ex + 1 != ey { + if ex < ey { + return (x, 0); + } + /* x mod y */ + while ex > ey { + i = uxi - uy; + if (i >> 63) == 0 { + uxi = i; + q += 1; + } + uxi <<= 1; + q <<= 1; + ex -= 1; + } + i = uxi - uy; + if (i >> 63) == 0 { + uxi = i; + q += 1; + } + if uxi == 0 { + ex = -60; + } else { + while (uxi >> 52) == 0 { + uxi <<= 1; + ex -= 1; + } + } + } + + /* scale result and decide between |x| and |x|-|y| */ + if ex > 0 { + uxi -= 1 << 52; + uxi |= (ex as u64) << 52; + } else { + uxi >>= -ex + 1; + } + x = f64::from_bits(uxi); + if sy { + y = -y; + } + if ex == ey || (ex + 1 == ey && (2.0 * x > y || (2.0 * x == y && (q % 2) != 0))) { + x -= y; + q += 1; + } + q &= 0x7fffffff; + let quo = if sx ^ sy { -(q as isize) } else { q as isize }; + if sx { + (-x, quo) + } else { + (x, quo) + } +} diff --git a/library/compiler-builtins/libm/src/math/remquof.rs b/library/compiler-builtins/libm/src/math/remquof.rs index 4307e19066521..40ded5d69768f 100644 --- a/library/compiler-builtins/libm/src/math/remquof.rs +++ b/library/compiler-builtins/libm/src/math/remquof.rs @@ -1,97 +1,96 @@ -pub fn remquof(mut x: f32, mut y: f32) -> (f32, isize) -{ - let ux: u32 = x.to_bits(); - let mut uy: u32 = y.to_bits(); - let mut ex = ((ux>>23) & 0xff) as isize; - let mut ey = ((uy>>23) & 0xff) as isize; - let sx = (ux>>31) != 0; - let sy = (uy>>31) != 0; - let mut q: u32; - let mut i: u32; - let mut uxi: u32 = ux; - - if (uy<<1) == 0 || y.is_nan() || ex == 0xff { - return ((x*y)/(x*y), 0); - } - if (ux<<1) == 0 { - return (x, 0); - } - - /* normalize x and y */ - if ex == 0 { - i = uxi<<9; - while (i>>31) == 0 { - ex -= 1; - i <<= 1; - } - uxi <<= -ex + 1; - } else { - uxi &= (!0) >> 9; - uxi |= 1 << 23; - } - if ey == 0 { - i = uy<<9; - while (i>>31) == 0 { - ey -= 1; - i <<= 1; - } - uy <<= -ey + 1; - } else { - uy &= (!0) >> 9; - uy |= 1 << 23; - } - - q = 0; - if ex+1 != ey { - if ex < ey { - return (x, 0); - } - /* x mod y */ - while ex > ey { - i = uxi - uy; - if (i>>31) == 0 { - uxi = i; - q += 1; - } - uxi <<= 1; - q <<= 1; - ex -= 1; - } - i = uxi - uy; - if (i>>31) == 0 { - uxi = i; - q += 1; - } - if uxi == 0 { - ex = -30; - } else { - while (uxi>>23) == 0 { - uxi <<= 1; - ex -= 1; - } - } - } - - /* scale result and decide between |x| and |x|-|y| */ - if ex > 0 { - uxi -= 1 << 23; - uxi |= (ex as u32) << 23; - } else { - uxi >>= -ex + 1; - } - x = f32::from_bits(uxi); - if sy { - y = -y; - } - if ex == ey || (ex+1 == ey && (2.0*x > y || (2.0*x == y && (q%2) != 0))) { - x -= y; - q += 1; - } - q &= 0x7fffffff; - let quo = if sx^sy { -(q as isize) } else { q as isize }; - if sx { - (-x, quo) - } else { - (x, quo) - } -} +pub fn remquof(mut x: f32, mut y: f32) -> (f32, isize) { + let ux: u32 = x.to_bits(); + let mut uy: u32 = y.to_bits(); + let mut ex = ((ux >> 23) & 0xff) as isize; + let mut ey = ((uy >> 23) & 0xff) as isize; + let sx = (ux >> 31) != 0; + let sy = (uy >> 31) != 0; + let mut q: u32; + let mut i: u32; + let mut uxi: u32 = ux; + + if (uy << 1) == 0 || y.is_nan() || ex == 0xff { + return ((x * y) / (x * y), 0); + } + if (ux << 1) == 0 { + return (x, 0); + } + + /* normalize x and y */ + if ex == 0 { + i = uxi << 9; + while (i >> 31) == 0 { + ex -= 1; + i <<= 1; + } + uxi <<= -ex + 1; + } else { + uxi &= (!0) >> 9; + uxi |= 1 << 23; + } + if ey == 0 { + i = uy << 9; + while (i >> 31) == 0 { + ey -= 1; + i <<= 1; + } + uy <<= -ey + 1; + } else { + uy &= (!0) >> 9; + uy |= 1 << 23; + } + + q = 0; + if ex + 1 != ey { + if ex < ey { + return (x, 0); + } + /* x mod y */ + while ex > ey { + i = uxi - uy; + if (i >> 31) == 0 { + uxi = i; + q += 1; + } + uxi <<= 1; + q <<= 1; + ex -= 1; + } + i = uxi - uy; + if (i >> 31) == 0 { + uxi = i; + q += 1; + } + if uxi == 0 { + ex = -30; + } else { + while (uxi >> 23) == 0 { + uxi <<= 1; + ex -= 1; + } + } + } + + /* scale result and decide between |x| and |x|-|y| */ + if ex > 0 { + uxi -= 1 << 23; + uxi |= (ex as u32) << 23; + } else { + uxi >>= -ex + 1; + } + x = f32::from_bits(uxi); + if sy { + y = -y; + } + if ex == ey || (ex + 1 == ey && (2.0 * x > y || (2.0 * x == y && (q % 2) != 0))) { + x -= y; + q += 1; + } + q &= 0x7fffffff; + let quo = if sx ^ sy { -(q as isize) } else { q as isize }; + if sx { + (-x, quo) + } else { + (x, quo) + } +} diff --git a/library/compiler-builtins/libm/src/math/sincos.rs b/library/compiler-builtins/libm/src/math/sincos.rs index c15ee4661f646..750908df4f7e9 100644 --- a/library/compiler-builtins/libm/src/math/sincos.rs +++ b/library/compiler-builtins/libm/src/math/sincos.rs @@ -1,60 +1,59 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.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. - * ==================================================== - */ - -use super::{get_high_word, k_cos, k_sin, rem_pio2}; - -pub fn sincos(x: f64) -> (f64, f64) -{ - let s: f64; - let c: f64; - let mut ix: u32; - - ix = get_high_word(x); - ix &= 0x7fffffff; - - /* |x| ~< pi/4 */ - if ix <= 0x3fe921fb { - /* if |x| < 2**-27 * sqrt(2) */ - if ix < 0x3e46a09e { - /* raise inexact if x!=0 and underflow if subnormal */ - let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120 == 2^120 - if ix < 0x00100000 { - force_eval!(x/x1p120); - } else { - force_eval!(x+x1p120); - } - return (x, 1.0); - } - return (k_sin(x, 0.0, 0), k_cos(x, 0.0)); - } - - /* sincos(Inf or NaN) is NaN */ - if ix >= 0x7ff00000 { - let rv = x - x; - return (rv, rv); - } - - /* argument reduction needed */ - let (n, y0, y1) = rem_pio2(x); - s = k_sin(y0, y1, 1); - c = k_cos(y0, y1); - match n&3 { - 0 => (s, c), - 1 => (c, -s), - 2 => (-s, -c), - 3 => (-c, s), - #[cfg(feature = "checked")] - _ => unreachable!(), - #[cfg(not(feature = "checked"))] - _ => (0.0, 1.0), - } -} +/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.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. + * ==================================================== + */ + +use super::{get_high_word, k_cos, k_sin, rem_pio2}; + +pub fn sincos(x: f64) -> (f64, f64) { + let s: f64; + let c: f64; + let mut ix: u32; + + ix = get_high_word(x); + ix &= 0x7fffffff; + + /* |x| ~< pi/4 */ + if ix <= 0x3fe921fb { + /* if |x| < 2**-27 * sqrt(2) */ + if ix < 0x3e46a09e { + /* raise inexact if x!=0 and underflow if subnormal */ + let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120 == 2^120 + if ix < 0x00100000 { + force_eval!(x / x1p120); + } else { + force_eval!(x + x1p120); + } + return (x, 1.0); + } + return (k_sin(x, 0.0, 0), k_cos(x, 0.0)); + } + + /* sincos(Inf or NaN) is NaN */ + if ix >= 0x7ff00000 { + let rv = x - x; + return (rv, rv); + } + + /* argument reduction needed */ + let (n, y0, y1) = rem_pio2(x); + s = k_sin(y0, y1, 1); + c = k_cos(y0, y1); + match n & 3 { + 0 => (s, c), + 1 => (c, -s), + 2 => (-s, -c), + 3 => (-c, s), + #[cfg(feature = "checked")] + _ => unreachable!(), + #[cfg(not(feature = "checked"))] + _ => (0.0, 1.0), + } +} diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs index 911421d63d4b0..bb9a003920174 100644 --- a/library/compiler-builtins/libm/src/math/sincosf.rs +++ b/library/compiler-builtins/libm/src/math/sincosf.rs @@ -1,122 +1,123 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Optimized by Bruce D. Evans. - */ -/* - * ==================================================== - * 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. - * ==================================================== - */ - -use super::{k_cosf, k_sinf, rem_pio2f}; - -/* Small multiples of pi/2 rounded to double precision. */ -const PI_2: f32 = 0.5 * 3.1415926535897931160E+00; -const S1PIO2: f32 = 1.0*PI_2; /* 0x3FF921FB, 0x54442D18 */ -const S2PIO2: f32 = 2.0*PI_2; /* 0x400921FB, 0x54442D18 */ -const S3PIO2: f32 = 3.0*PI_2; /* 0x4012D97C, 0x7F3321D2 */ -const S4PIO2: f32 = 4.0*PI_2; /* 0x401921FB, 0x54442D18 */ - -pub fn sincosf(x: f32) -> (f32, f32) -{ - let s: f32; - let c: f32; - let mut ix: u32; - let sign: bool; - - ix = x.to_bits(); - sign = (ix >> 31) != 0; - ix &= 0x7fffffff; - - /* |x| ~<= pi/4 */ - if ix <= 0x3f490fda { - /* |x| < 2**-12 */ - if ix < 0x39800000 { - /* raise inexact if x!=0 and underflow if subnormal */ - - let x1p120 = f32::from_bits(0x7b800000); // 0x1p120 == 2^120 - if ix < 0x00100000 { - force_eval!(x/x1p120); - } else { - force_eval!(x+x1p120); - } - return (x, 1.0); - } - return (k_sinf(x as f64), k_cosf(x as f64)); - } - - /* |x| ~<= 5*pi/4 */ - if ix <= 0x407b53d1 { - if ix <= 0x4016cbe3 { /* |x| ~<= 3pi/4 */ - if sign { - s = -k_cosf((x + S1PIO2) as f64); - c = k_sinf((x + S1PIO2) as f64); - } else { - s = k_cosf((S1PIO2 - x) as f64); - c = k_sinf((S1PIO2 - x) as f64); - } - } - /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ - else { - if sign { - s = k_sinf((x + S2PIO2) as f64); - c = k_cosf((x + S2PIO2) as f64); - } else { - s = k_sinf((x - S2PIO2) as f64); - c = k_cosf((x - S2PIO2) as f64); - } - } - - return (s, c); - } - - /* |x| ~<= 9*pi/4 */ - if ix <= 0x40e231d5 { - if ix <= 0x40afeddf { /* |x| ~<= 7*pi/4 */ - if sign { - s = k_cosf((x + S3PIO2) as f64); - c = -k_sinf((x + S3PIO2) as f64); - } else { - s = -k_cosf((x - S3PIO2) as f64); - c = k_sinf((x - S3PIO2) as f64); - } - } else { - if sign { - s = k_cosf((x + S4PIO2) as f64); - c = k_sinf((x + S4PIO2) as f64); - } else { - s = k_cosf((x - S4PIO2) as f64); - c = k_sinf((x - S4PIO2) as f64); - } - } - - return (s, c); - } - - /* sin(Inf or NaN) is NaN */ - if ix >= 0x7f800000 { - let rv = x - x; - return (rv, rv); - } - - /* general argument reduction needed */ - let (n, y) = rem_pio2f(x); - s = k_sinf(y); - c = k_cosf(y); - match n&3 { - 0 => (s, c), - 1 => (c, -s), - 2 => (-s, -c), - 3 => (-c, s), - #[cfg(feature = "checked")] - _ => unreachable!(), - #[cfg(not(feature = "checked"))] - _ => (0.0, 1.0), - } -} +/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + +use super::{k_cosf, k_sinf, rem_pio2f}; + +/* Small multiples of pi/2 rounded to double precision. */ +const PI_2: f32 = 0.5 * 3.1415926535897931160E+00; +const S1PIO2: f32 = 1.0 * PI_2; /* 0x3FF921FB, 0x54442D18 */ +const S2PIO2: f32 = 2.0 * PI_2; /* 0x400921FB, 0x54442D18 */ +const S3PIO2: f32 = 3.0 * PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const S4PIO2: f32 = 4.0 * PI_2; /* 0x401921FB, 0x54442D18 */ + +pub fn sincosf(x: f32) -> (f32, f32) { + let s: f32; + let c: f32; + let mut ix: u32; + let sign: bool; + + ix = x.to_bits(); + sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + + /* |x| ~<= pi/4 */ + if ix <= 0x3f490fda { + /* |x| < 2**-12 */ + if ix < 0x39800000 { + /* raise inexact if x!=0 and underflow if subnormal */ + + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120 == 2^120 + if ix < 0x00100000 { + force_eval!(x / x1p120); + } else { + force_eval!(x + x1p120); + } + return (x, 1.0); + } + return (k_sinf(x as f64), k_cosf(x as f64)); + } + + /* |x| ~<= 5*pi/4 */ + if ix <= 0x407b53d1 { + if ix <= 0x4016cbe3 { + /* |x| ~<= 3pi/4 */ + if sign { + s = -k_cosf((x + S1PIO2) as f64); + c = k_sinf((x + S1PIO2) as f64); + } else { + s = k_cosf((S1PIO2 - x) as f64); + c = k_sinf((S1PIO2 - x) as f64); + } + } + /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ + else { + if sign { + s = k_sinf((x + S2PIO2) as f64); + c = k_cosf((x + S2PIO2) as f64); + } else { + s = k_sinf((x - S2PIO2) as f64); + c = k_cosf((x - S2PIO2) as f64); + } + } + + return (s, c); + } + + /* |x| ~<= 9*pi/4 */ + if ix <= 0x40e231d5 { + if ix <= 0x40afeddf { + /* |x| ~<= 7*pi/4 */ + if sign { + s = k_cosf((x + S3PIO2) as f64); + c = -k_sinf((x + S3PIO2) as f64); + } else { + s = -k_cosf((x - S3PIO2) as f64); + c = k_sinf((x - S3PIO2) as f64); + } + } else { + if sign { + s = k_cosf((x + S4PIO2) as f64); + c = k_sinf((x + S4PIO2) as f64); + } else { + s = k_cosf((x - S4PIO2) as f64); + c = k_sinf((x - S4PIO2) as f64); + } + } + + return (s, c); + } + + /* sin(Inf or NaN) is NaN */ + if ix >= 0x7f800000 { + let rv = x - x; + return (rv, rv); + } + + /* general argument reduction needed */ + let (n, y) = rem_pio2f(x); + s = k_sinf(y); + c = k_cosf(y); + match n & 3 { + 0 => (s, c), + 1 => (c, -s), + 2 => (-s, -c), + 3 => (-c, s), + #[cfg(feature = "checked")] + _ => unreachable!(), + #[cfg(not(feature = "checked"))] + _ => (0.0, 1.0), + } +} diff --git a/library/compiler-builtins/libm/src/math/tgamma.rs b/library/compiler-builtins/libm/src/math/tgamma.rs index 598f46f1c3e1f..f8ccf669a2513 100644 --- a/library/compiler-builtins/libm/src/math/tgamma.rs +++ b/library/compiler-builtins/libm/src/math/tgamma.rs @@ -1,179 +1,207 @@ -/* -"A Precision Approximation of the Gamma Function" - Cornelius Lanczos (1964) -"Lanczos Implementation of the Gamma Function" - Paul Godfrey (2001) -"An Analysis of the Lanczos Gamma Approximation" - Glendon Ralph Pugh (2004) - -approximation method: - - (x - 0.5) S(x) -Gamma(x) = (x + g - 0.5) * ---------------- - exp(x + g - 0.5) - -with - a1 a2 a3 aN -S(x) ~= [ a0 + ----- + ----- + ----- + ... + ----- ] - x + 1 x + 2 x + 3 x + N - -with a0, a1, a2, a3,.. aN constants which depend on g. - -for x < 0 the following reflection formula is used: - -Gamma(x)*Gamma(-x) = -pi/(x sin(pi x)) - -most ideas and constants are from boost and python -*/ -extern crate core; -use super::{exp, floor, k_cos, k_sin, pow}; - -const PI: f64 = 3.141592653589793238462643383279502884; - -/* sin(pi x) with x > 0x1p-100, if sin(pi*x)==0 the sign is arbitrary */ -fn sinpi(mut x: f64) -> f64 -{ - let mut n: isize; - - /* argument reduction: x = |x| mod 2 */ - /* spurious inexact when x is odd int */ - x = x * 0.5; - x = 2.0 * (x - floor(x)); - - /* reduce x into [-.25,.25] */ - n = (4.0 * x) as isize; - n = (n+1)/2; - x -= (n as f64) * 0.5; - - x *= PI; - match n { - 1 => k_cos(x, 0.0), - 2 => k_sin(-x, 0.0, 0), - 3 => -k_cos(x, 0.0), - 0|_ => k_sin(x, 0.0, 0), - } -} - -const N: usize = 12; -//static const double g = 6.024680040776729583740234375; -const GMHALF: f64 = 5.524680040776729583740234375; -const SNUM: [f64; N+1] = [ - 23531376880.410759688572007674451636754734846804940, - 42919803642.649098768957899047001988850926355848959, - 35711959237.355668049440185451547166705960488635843, - 17921034426.037209699919755754458931112671403265390, - 6039542586.3520280050642916443072979210699388420708, - 1439720407.3117216736632230727949123939715485786772, - 248874557.86205415651146038641322942321632125127801, - 31426415.585400194380614231628318205362874684987640, - 2876370.6289353724412254090516208496135991145378768, - 186056.26539522349504029498971604569928220784236328, - 8071.6720023658162106380029022722506138218516325024, - 210.82427775157934587250973392071336271166969580291, - 2.5066282746310002701649081771338373386264310793408, -]; -const SDEN: [f64; N+1] = [ - 0.0, 39916800.0, 120543840.0, 150917976.0, 105258076.0, - 45995730.0, 13339535.0, 2637558.0, 357423.0, 32670.0, 1925.0, 66.0, 1.0, -]; -/* n! for small integer n */ -const FACT: [f64; 23] = [ - 1.0, 1.0, 2.0, 6.0, 24.0, 120.0, 720.0, 5040.0, 40320.0, 362880.0, 3628800.0, - 39916800.0, 479001600.0, 6227020800.0, 87178291200.0, 1307674368000.0, - 20922789888000.0, 355687428096000.0, 6402373705728000.0, 121645100408832000.0, - 2432902008176640000.0, 51090942171709440000.0, 1124000727777607680000.0, -]; - -/* S(x) rational function for positive x */ -fn s(x: f64) -> f64 -{ - let mut num: f64 = 0.0; - let mut den: f64 = 0.0; - - /* to avoid overflow handle large x differently */ - if x < 8.0 { - for i in (0..=N).rev() { - num = num * x + SNUM[i]; - den = den * x + SDEN[i]; - } - } else { - for i in 0..=N { - num = num / x + SNUM[i]; - den = den / x + SDEN[i]; - } - } - return num/den; -} - -pub fn tgamma(mut x: f64) -> f64 -{ - let u: u64 = x.to_bits(); - let absx: f64; - let mut y: f64; - let mut dy: f64; - let mut z: f64; - let mut r: f64; - let ix: u32 = ((u >> 32) as u32) & 0x7fffffff; - let sign: bool = (u>>64) != 0; - - /* special cases */ - if ix >= 0x7ff00000 { - /* tgamma(nan)=nan, tgamma(inf)=inf, tgamma(-inf)=nan with invalid */ - return x + core::f64::INFINITY; - } - if ix < ((0x3ff-54)<<20) { - /* |x| < 2^-54: tgamma(x) ~ 1/x, +-0 raises div-by-zero */ - return 1.0/x; - } - - /* integer arguments */ - /* raise inexact when non-integer */ - if x == floor(x) { - if sign { - return 0.0/0.0; - } - if x <= FACT.len() as f64 { - return FACT[(x as usize) - 1]; - } - } - - /* x >= 172: tgamma(x)=inf with overflow */ - /* x =< -184: tgamma(x)=+-0 with underflow */ - if ix >= 0x40670000 { /* |x| >= 184 */ - if sign { - let x1p_126 = f64::from_bits(0x3810000000000000); // 0x1p-126 == 2^-126 - force_eval!((x1p_126/x) as f32); - if floor(x) * 0.5 == floor(x * 0.5) { - return 0.0; - } else { - return -0.0; - } - } - let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 == 2^1023 - x *= x1p1023; - return x; - } - - absx = if sign { -x } else { x }; - - /* handle the error of x + g - 0.5 */ - y = absx + GMHALF; - if absx > GMHALF { - dy = y - absx; - dy -= GMHALF; - } else { - dy = y - GMHALF; - dy -= absx; - } - - z = absx - 0.5; - r = s(absx) * exp(-y); - if x < 0.0 { - /* reflection formula for negative x */ - /* sinpi(absx) is not 0, integers are already handled */ - r = -PI / (sinpi(absx) * absx * r); - dy = -dy; - z = -z; - } - r += dy * (GMHALF+0.5) * r / y; - z = pow(y, 0.5*z); - y = r * z * z; - return y; -} +/* +"A Precision Approximation of the Gamma Function" - Cornelius Lanczos (1964) +"Lanczos Implementation of the Gamma Function" - Paul Godfrey (2001) +"An Analysis of the Lanczos Gamma Approximation" - Glendon Ralph Pugh (2004) + +approximation method: + + (x - 0.5) S(x) +Gamma(x) = (x + g - 0.5) * ---------------- + exp(x + g - 0.5) + +with + a1 a2 a3 aN +S(x) ~= [ a0 + ----- + ----- + ----- + ... + ----- ] + x + 1 x + 2 x + 3 x + N + +with a0, a1, a2, a3,.. aN constants which depend on g. + +for x < 0 the following reflection formula is used: + +Gamma(x)*Gamma(-x) = -pi/(x sin(pi x)) + +most ideas and constants are from boost and python +*/ +extern crate core; +use super::{exp, floor, k_cos, k_sin, pow}; + +const PI: f64 = 3.141592653589793238462643383279502884; + +/* sin(pi x) with x > 0x1p-100, if sin(pi*x)==0 the sign is arbitrary */ +fn sinpi(mut x: f64) -> f64 { + let mut n: isize; + + /* argument reduction: x = |x| mod 2 */ + /* spurious inexact when x is odd int */ + x = x * 0.5; + x = 2.0 * (x - floor(x)); + + /* reduce x into [-.25,.25] */ + n = (4.0 * x) as isize; + n = (n + 1) / 2; + x -= (n as f64) * 0.5; + + x *= PI; + match n { + 1 => k_cos(x, 0.0), + 2 => k_sin(-x, 0.0, 0), + 3 => -k_cos(x, 0.0), + 0 | _ => k_sin(x, 0.0, 0), + } +} + +const N: usize = 12; +//static const double g = 6.024680040776729583740234375; +const GMHALF: f64 = 5.524680040776729583740234375; +const SNUM: [f64; N + 1] = [ + 23531376880.410759688572007674451636754734846804940, + 42919803642.649098768957899047001988850926355848959, + 35711959237.355668049440185451547166705960488635843, + 17921034426.037209699919755754458931112671403265390, + 6039542586.3520280050642916443072979210699388420708, + 1439720407.3117216736632230727949123939715485786772, + 248874557.86205415651146038641322942321632125127801, + 31426415.585400194380614231628318205362874684987640, + 2876370.6289353724412254090516208496135991145378768, + 186056.26539522349504029498971604569928220784236328, + 8071.6720023658162106380029022722506138218516325024, + 210.82427775157934587250973392071336271166969580291, + 2.5066282746310002701649081771338373386264310793408, +]; +const SDEN: [f64; N + 1] = [ + 0.0, + 39916800.0, + 120543840.0, + 150917976.0, + 105258076.0, + 45995730.0, + 13339535.0, + 2637558.0, + 357423.0, + 32670.0, + 1925.0, + 66.0, + 1.0, +]; +/* n! for small integer n */ +const FACT: [f64; 23] = [ + 1.0, + 1.0, + 2.0, + 6.0, + 24.0, + 120.0, + 720.0, + 5040.0, + 40320.0, + 362880.0, + 3628800.0, + 39916800.0, + 479001600.0, + 6227020800.0, + 87178291200.0, + 1307674368000.0, + 20922789888000.0, + 355687428096000.0, + 6402373705728000.0, + 121645100408832000.0, + 2432902008176640000.0, + 51090942171709440000.0, + 1124000727777607680000.0, +]; + +/* S(x) rational function for positive x */ +fn s(x: f64) -> f64 { + let mut num: f64 = 0.0; + let mut den: f64 = 0.0; + + /* to avoid overflow handle large x differently */ + if x < 8.0 { + for i in (0..=N).rev() { + num = num * x + SNUM[i]; + den = den * x + SDEN[i]; + } + } else { + for i in 0..=N { + num = num / x + SNUM[i]; + den = den / x + SDEN[i]; + } + } + return num / den; +} + +pub fn tgamma(mut x: f64) -> f64 { + let u: u64 = x.to_bits(); + let absx: f64; + let mut y: f64; + let mut dy: f64; + let mut z: f64; + let mut r: f64; + let ix: u32 = ((u >> 32) as u32) & 0x7fffffff; + let sign: bool = (u >> 63) != 0; + + /* special cases */ + if ix >= 0x7ff00000 { + /* tgamma(nan)=nan, tgamma(inf)=inf, tgamma(-inf)=nan with invalid */ + return x + core::f64::INFINITY; + } + if ix < ((0x3ff - 54) << 20) { + /* |x| < 2^-54: tgamma(x) ~ 1/x, +-0 raises div-by-zero */ + return 1.0 / x; + } + + /* integer arguments */ + /* raise inexact when non-integer */ + if x == floor(x) { + if sign { + return 0.0 / 0.0; + } + if x <= FACT.len() as f64 { + return FACT[(x as usize) - 1]; + } + } + + /* x >= 172: tgamma(x)=inf with overflow */ + /* x =< -184: tgamma(x)=+-0 with underflow */ + if ix >= 0x40670000 { + /* |x| >= 184 */ + if sign { + let x1p_126 = f64::from_bits(0x3810000000000000); // 0x1p-126 == 2^-126 + force_eval!((x1p_126 / x) as f32); + if floor(x) * 0.5 == floor(x * 0.5) { + return 0.0; + } else { + return -0.0; + } + } + let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 == 2^1023 + x *= x1p1023; + return x; + } + + absx = if sign { -x } else { x }; + + /* handle the error of x + g - 0.5 */ + y = absx + GMHALF; + if absx > GMHALF { + dy = y - absx; + dy -= GMHALF; + } else { + dy = y - GMHALF; + dy -= absx; + } + + z = absx - 0.5; + r = s(absx) * exp(-y); + if x < 0.0 { + /* reflection formula for negative x */ + /* sinpi(absx) is not 0, integers are already handled */ + r = -PI / (sinpi(absx) * absx * r); + dy = -dy; + z = -z; + } + r += dy * (GMHALF + 0.5) * r / y; + z = pow(y, 0.5 * z); + y = r * z * z; + return y; +} diff --git a/library/compiler-builtins/libm/src/math/tgammaf.rs b/library/compiler-builtins/libm/src/math/tgammaf.rs index b9c799ce76cd6..a8f161f0c1c95 100644 --- a/library/compiler-builtins/libm/src/math/tgammaf.rs +++ b/library/compiler-builtins/libm/src/math/tgammaf.rs @@ -1,5 +1,5 @@ -use super::{tgamma}; - -pub fn tgammaf(x: f32) -> f32 { - tgamma(x as f64) as f32 -} +use super::tgamma; + +pub fn tgammaf(x: f32) -> f32 { + tgamma(x as f64) as f32 +} From 92db6e9c1bfae23b91be38ff05c9f0cc212881bb Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Tue, 7 May 2019 09:07:26 +0300 Subject: [PATCH 0712/4206] sh +x --- library/compiler-builtins/libm/ci/run-docker.sh | 0 library/compiler-builtins/libm/ci/run.sh | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 library/compiler-builtins/libm/ci/run-docker.sh mode change 100644 => 100755 library/compiler-builtins/libm/ci/run.sh diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh old mode 100644 new mode 100755 diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh old mode 100644 new mode 100755 From 5c5ba6fe82e415b949671e66239d8067e6f5cfca Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Thu, 9 May 2019 06:58:58 +0300 Subject: [PATCH 0713/4206] rm asine, mv lgamma --- library/compiler-builtins/libm/build.rs | 9 +- .../compiler-builtins/libm/src/math/asinef.rs | 93 ----- .../compiler-builtins/libm/src/math/lgamma.rs | 320 +----------------- .../libm/src/math/lgamma_r.rs | 319 +++++++++++++++++ .../libm/src/math/lgammaf.rs | 255 +------------- .../libm/src/math/lgammaf_r.rs | 254 ++++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 6 +- .../compiler-builtins/libm/src/math/modf.rs | 2 +- .../compiler-builtins/libm/src/math/modff.rs | 2 +- .../compiler-builtins/libm/src/math/remquo.rs | 8 +- .../libm/src/math/remquof.rs | 8 +- 11 files changed, 593 insertions(+), 683 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/asinef.rs create mode 100644 library/compiler-builtins/libm/src/math/lgamma_r.rs create mode 100644 library/compiler-builtins/libm/src/math/lgammaf_r.rs diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 29521ab193c22..4d739a121120d 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -41,17 +41,16 @@ mod musl_reference_tests { "rem_pio2.rs", "rem_pio2_large.rs", "rem_pio2f.rs", - "remquo.rs", - "remquof.rs", - "lgamma.rs", // lgamma passed, lgamma_r has more than 1 result - "lgammaf.rs", // lgammaf passed, lgammaf_r has more than 1 result + "remquo.rs", // more than 1 result + "remquof.rs", // more than 1 result + "lgamma_r.rs", // more than 1 result + "lgammaf_r.rs", // more than 1 result "frexp.rs", // more than 1 result "frexpf.rs", // more than 1 result "sincos.rs", // more than 1 result "sincosf.rs", // more than 1 result "modf.rs", // more than 1 result "modff.rs", // more than 1 result - "asinef.rs", // not exists "jn.rs", // passed, but very slow "jnf.rs", // passed, but very slow ]; diff --git a/library/compiler-builtins/libm/src/math/asinef.rs b/library/compiler-builtins/libm/src/math/asinef.rs deleted file mode 100644 index cd1428bc23292..0000000000000 --- a/library/compiler-builtins/libm/src/math/asinef.rs +++ /dev/null @@ -1,93 +0,0 @@ -/* @(#)z_asinef.c 1.0 98/08/13 */ -/****************************************************************** - * The following routines are coded directly from the algorithms - * and coefficients given in "Software Manual for the Elementary - * Functions" by William J. Cody, Jr. and William Waite, Prentice - * Hall, 1980. - ******************************************************************/ -/****************************************************************** - * Arcsine - * - * Input: - * x - floating point value - * acosine - indicates acos calculation - * - * Output: - * Arcsine of x. - * - * Description: - * This routine calculates arcsine / arccosine. - * - *****************************************************************/ - -use super::{fabsf, sqrtf}; - -const P: [f32; 2] = [ 0.933935835, -0.504400557 ]; -const Q: [f32; 2] = [ 0.560363004e+1, -0.554846723e+1 ]; -const A: [f32; 2] = [ 0.0, 0.785398163 ]; -const B: [f32; 2] = [ 1.570796326, 0.785398163 ]; -const Z_ROOTEPS_F: f32 = 1.7263349182589107e-4; - -pub fn asinef(x: f32, acosine: bool) -> f32 { - let i: usize; - let mut branch: bool = false; - let g: f32; - let mut res: f32 = 0.0; - let mut y: f32; - - /* Check for special values. */ - //i = numtestf (x); - if x.is_nan() || x.is_infinite() { - force_eval!(x); - return x; - } - - y = fabsf(x); - let flag = acosine; - - if y > 0.5 { - i = (!flag) as usize; - - /* Check for range error. */ - if y > 1.0 { - return 0.0 / 0.0; - } - - g = (1.0 - y) / 2.0; - y = -2.0 * sqrtf(g); - branch = true; - } else { - i = flag; - if y < Z_ROOTEPS_F { - res = y; - g = 0.0; // pleasing the uninitialized variable - } else { - g = y * y; - } - } - - if y >= Z_ROOTEPS_F || branch { - /* Calculate the Taylor series. */ - let p = (P[1] * g + P[0]) * g; - let q = (g + Q[1]) * g + Q[0]; - let r = p / q; - - res = y + y * r; - } - - /* Calculate asine or acose. */ - if flag == 0 { - res = (A[i] + res) + A[i]; - if x < 0.0 { - res = -res; - } - } else { - if x < 0.0 { - res = (B[i] + res) + B[i]; - } else { - res = (A[i] - res) + A[i]; - } - } - - return res; -} diff --git a/library/compiler-builtins/libm/src/math/lgamma.rs b/library/compiler-builtins/libm/src/math/lgamma.rs index b1a321e308c45..5bc87e85e8c33 100644 --- a/library/compiler-builtins/libm/src/math/lgamma.rs +++ b/library/compiler-builtins/libm/src/math/lgamma.rs @@ -1,323 +1,5 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - * - */ -/* lgamma_r(x, signgamp) - * Reentrant version of the logarithm of the Gamma function - * with user provide pointer for the sign of Gamma(x). - * - * Method: - * 1. Argument Reduction for 0 < x <= 8 - * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may - * reduce x to a number in [1.5,2.5] by - * lgamma(1+s) = log(s) + lgamma(s) - * for example, - * lgamma(7.3) = log(6.3) + lgamma(6.3) - * = log(6.3*5.3) + lgamma(5.3) - * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) - * 2. Polynomial approximation of lgamma around its - * minimun ymin=1.461632144968362245 to maintain monotonicity. - * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use - * Let z = x-ymin; - * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) - * where - * poly(z) is a 14 degree polynomial. - * 2. Rational approximation in the primary interval [2,3] - * We use the following approximation: - * s = x-2.0; - * lgamma(x) = 0.5*s + s*P(s)/Q(s) - * with accuracy - * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 - * Our algorithms are based on the following observation - * - * zeta(2)-1 2 zeta(3)-1 3 - * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... - * 2 3 - * - * where Euler = 0.5771... is the Euler constant, which is very - * close to 0.5. - * - * 3. For x>=8, we have - * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... - * (better formula: - * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) - * Let z = 1/x, then we approximation - * f(z) = lgamma(x) - (x-0.5)(log(x)-1) - * by - * 3 5 11 - * w = w0 + w1*z + w2*z + w3*z + ... + w6*z - * where - * |w - f(z)| < 2**-58.74 - * - * 4. For negative x, since (G is gamma function) - * -x*G(-x)*G(x) = PI/sin(PI*x), - * we have - * G(x) = PI/(sin(PI*x)*(-x)*G(-x)) - * since G(-x) is positive, sign(G(x)) = sign(sin(PI*x)) for x<0 - * Hence, for x<0, signgam = sign(sin(PI*x)) and - * lgamma(x) = log(|Gamma(x)|) - * = log(PI/(|x*sin(PI*x)|)) - lgamma(-x); - * Note: one should avoid compute PI*(-x) directly in the - * computation of sin(PI*(-x)). - * - * 5. Special Cases - * lgamma(2+s) ~ s*(1-Euler) for tiny s - * lgamma(1) = lgamma(2) = 0 - * lgamma(x) ~ -log(|x|) for tiny x - * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero - * lgamma(inf) = inf - * lgamma(-inf) = inf (bug for bug compatible with C99!?) - * - */ - -use super::{floor, k_cos, k_sin, log}; - -const PI: f64 = 3.14159265358979311600e+00; /* 0x400921FB, 0x54442D18 */ -const A0: f64 = 7.72156649015328655494e-02; /* 0x3FB3C467, 0xE37DB0C8 */ -const A1: f64 = 3.22467033424113591611e-01; /* 0x3FD4A34C, 0xC4A60FAD */ -const A2: f64 = 6.73523010531292681824e-02; /* 0x3FB13E00, 0x1A5562A7 */ -const A3: f64 = 2.05808084325167332806e-02; /* 0x3F951322, 0xAC92547B */ -const A4: f64 = 7.38555086081402883957e-03; /* 0x3F7E404F, 0xB68FEFE8 */ -const A5: f64 = 2.89051383673415629091e-03; /* 0x3F67ADD8, 0xCCB7926B */ -const A6: f64 = 1.19270763183362067845e-03; /* 0x3F538A94, 0x116F3F5D */ -const A7: f64 = 5.10069792153511336608e-04; /* 0x3F40B6C6, 0x89B99C00 */ -const A8: f64 = 2.20862790713908385557e-04; /* 0x3F2CF2EC, 0xED10E54D */ -const A9: f64 = 1.08011567247583939954e-04; /* 0x3F1C5088, 0x987DFB07 */ -const A10: f64 = 2.52144565451257326939e-05; /* 0x3EFA7074, 0x428CFA52 */ -const A11: f64 = 4.48640949618915160150e-05; /* 0x3F07858E, 0x90A45837 */ -const TC: f64 = 1.46163214496836224576e+00; /* 0x3FF762D8, 0x6356BE3F */ -const TF: f64 = -1.21486290535849611461e-01; /* 0xBFBF19B9, 0xBCC38A42 */ -/* tt = -(tail of TF) */ -const TT: f64 = -3.63867699703950536541e-18; /* 0xBC50C7CA, 0xA48A971F */ -const T0: f64 = 4.83836122723810047042e-01; /* 0x3FDEF72B, 0xC8EE38A2 */ -const T1: f64 = -1.47587722994593911752e-01; /* 0xBFC2E427, 0x8DC6C509 */ -const T2: f64 = 6.46249402391333854778e-02; /* 0x3FB08B42, 0x94D5419B */ -const T3: f64 = -3.27885410759859649565e-02; /* 0xBFA0C9A8, 0xDF35B713 */ -const T4: f64 = 1.79706750811820387126e-02; /* 0x3F9266E7, 0x970AF9EC */ -const T5: f64 = -1.03142241298341437450e-02; /* 0xBF851F9F, 0xBA91EC6A */ -const T6: f64 = 6.10053870246291332635e-03; /* 0x3F78FCE0, 0xE370E344 */ -const T7: f64 = -3.68452016781138256760e-03; /* 0xBF6E2EFF, 0xB3E914D7 */ -const T8: f64 = 2.25964780900612472250e-03; /* 0x3F6282D3, 0x2E15C915 */ -const T9: f64 = -1.40346469989232843813e-03; /* 0xBF56FE8E, 0xBF2D1AF1 */ -const T10: f64 = 8.81081882437654011382e-04; /* 0x3F4CDF0C, 0xEF61A8E9 */ -const T11: f64 = -5.38595305356740546715e-04; /* 0xBF41A610, 0x9C73E0EC */ -const T12: f64 = 3.15632070903625950361e-04; /* 0x3F34AF6D, 0x6C0EBBF7 */ -const T13: f64 = -3.12754168375120860518e-04; /* 0xBF347F24, 0xECC38C38 */ -const T14: f64 = 3.35529192635519073543e-04; /* 0x3F35FD3E, 0xE8C2D3F4 */ -const U0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ -const U1: f64 = 6.32827064025093366517e-01; /* 0x3FE4401E, 0x8B005DFF */ -const U2: f64 = 1.45492250137234768737e+00; /* 0x3FF7475C, 0xD119BD6F */ -const U3: f64 = 9.77717527963372745603e-01; /* 0x3FEF4976, 0x44EA8450 */ -const U4: f64 = 2.28963728064692451092e-01; /* 0x3FCD4EAE, 0xF6010924 */ -const U5: f64 = 1.33810918536787660377e-02; /* 0x3F8B678B, 0xBF2BAB09 */ -const V1: f64 = 2.45597793713041134822e+00; /* 0x4003A5D7, 0xC2BD619C */ -const V2: f64 = 2.12848976379893395361e+00; /* 0x40010725, 0xA42B18F5 */ -const V3: f64 = 7.69285150456672783825e-01; /* 0x3FE89DFB, 0xE45050AF */ -const V4: f64 = 1.04222645593369134254e-01; /* 0x3FBAAE55, 0xD6537C88 */ -const V5: f64 = 3.21709242282423911810e-03; /* 0x3F6A5ABB, 0x57D0CF61 */ -const S0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ -const S1: f64 = 2.14982415960608852501e-01; /* 0x3FCB848B, 0x36E20878 */ -const S2: f64 = 3.25778796408930981787e-01; /* 0x3FD4D98F, 0x4F139F59 */ -const S3: f64 = 1.46350472652464452805e-01; /* 0x3FC2BB9C, 0xBEE5F2F7 */ -const S4: f64 = 2.66422703033638609560e-02; /* 0x3F9B481C, 0x7E939961 */ -const S5: f64 = 1.84028451407337715652e-03; /* 0x3F5E26B6, 0x7368F239 */ -const S6: f64 = 3.19475326584100867617e-05; /* 0x3F00BFEC, 0xDD17E945 */ -const R1: f64 = 1.39200533467621045958e+00; /* 0x3FF645A7, 0x62C4AB74 */ -const R2: f64 = 7.21935547567138069525e-01; /* 0x3FE71A18, 0x93D3DCDC */ -const R3: f64 = 1.71933865632803078993e-01; /* 0x3FC601ED, 0xCCFBDF27 */ -const R4: f64 = 1.86459191715652901344e-02; /* 0x3F9317EA, 0x742ED475 */ -const R5: f64 = 7.77942496381893596434e-04; /* 0x3F497DDA, 0xCA41A95B */ -const R6: f64 = 7.32668430744625636189e-06; /* 0x3EDEBAF7, 0xA5B38140 */ -const W0: f64 = 4.18938533204672725052e-01; /* 0x3FDACFE3, 0x90C97D69 */ -const W1: f64 = 8.33333333333329678849e-02; /* 0x3FB55555, 0x5555553B */ -const W2: f64 = -2.77777777728775536470e-03; /* 0xBF66C16C, 0x16B02E5C */ -const W3: f64 = 7.93650558643019558500e-04; /* 0x3F4A019F, 0x98CF38B6 */ -const W4: f64 = -5.95187557450339963135e-04; /* 0xBF4380CB, 0x8C0FE741 */ -const W5: f64 = 8.36339918996282139126e-04; /* 0x3F4B67BA, 0x4CDAD5D1 */ -const W6: f64 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ - -/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ -fn sin_pi(mut x: f64) -> f64 { - let mut n: i32; - - /* spurious inexact if odd int */ - x = 2.0 * (x * 0.5 - floor(x * 0.5)); /* x mod 2.0 */ - - n = (x * 4.0) as i32; - n = (n + 1) / 2; - x -= (n as f64) * 0.5; - x *= PI; - - match n { - 1 => k_cos(x, 0.0), - 2 => k_sin(-x, 0.0, 0), - 3 => -k_cos(x, 0.0), - 0 | _ => k_sin(x, 0.0, 0), - } -} +use super::lgamma_r; pub fn lgamma(x: f64) -> f64 { lgamma_r(x).0 } - -pub fn lgamma_r(mut x: f64) -> (f64, i32) { - let u: u64 = x.to_bits(); - let mut t: f64; - let y: f64; - let mut z: f64; - let nadj: f64; - let p: f64; - let p1: f64; - let p2: f64; - let p3: f64; - let q: f64; - let mut r: f64; - let w: f64; - let ix: u32; - let sign: bool; - let i: i32; - let mut signgam: i32; - - /* purge off +-inf, NaN, +-0, tiny and negative arguments */ - signgam = 1; - sign = (u >> 63) != 0; - ix = ((u >> 32) as u32) & 0x7fffffff; - if ix >= 0x7ff00000 { - return (x * x, signgam); - } - if ix < (0x3ff - 70) << 20 { - /* |x|<2**-70, return -log(|x|) */ - if sign { - x = -x; - signgam = -1; - } - return (-log(x), signgam); - } - if sign { - x = -x; - t = sin_pi(x); - if t == 0.0 { - /* -integer */ - return (1.0 / (x - x), signgam); - } - if t > 0.0 { - signgam = -1; - } else { - t = -t; - } - nadj = log(PI / (t * x)); - } else { - nadj = 0.0; - } - - /* purge off 1 and 2 */ - if (ix == 0x3ff00000 || ix == 0x40000000) && (u & 0xffffffff) == 0 { - r = 0.0; - } - /* for x < 2.0 */ - else if ix < 0x40000000 { - if ix <= 0x3feccccc { - /* lgamma(x) = lgamma(x+1)-log(x) */ - r = -log(x); - if ix >= 0x3FE76944 { - y = 1.0 - x; - i = 0; - } else if ix >= 0x3FCDA661 { - y = x - (TC - 1.0); - i = 1; - } else { - y = x; - i = 2; - } - } else { - r = 0.0; - if ix >= 0x3FFBB4C3 { - /* [1.7316,2] */ - y = 2.0 - x; - i = 0; - } else if ix >= 0x3FF3B4C4 { - /* [1.23,1.73] */ - y = x - TC; - i = 1; - } else { - y = x - 1.0; - i = 2; - } - } - match i { - 0 => { - z = y * y; - p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); - p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); - p = y * p1 + p2; - r += p - 0.5 * y; - } - 1 => { - z = y * y; - w = z * y; - p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ - p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); - p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); - p = z * p1 - (TT - w * (p2 + y * p3)); - r += TF + p; - } - 2 => { - p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); - p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); - r += -0.5 * y + p1 / p2; - } - #[cfg(feature = "checked")] - _ => unreachable!(), - #[cfg(not(feature = "checked"))] - _ => {} - } - } else if ix < 0x40200000 { - /* x < 8.0 */ - i = x as i32; - y = x - (i as f64); - p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); - q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); - r = 0.5 * y + p / q; - z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ - // TODO: In C, this was implemented using switch jumps with fallthrough. - // Does this implementation have performance problems? - if i >= 7 { - z *= y + 6.0; - } - if i >= 6 { - z *= y + 5.0; - } - if i >= 5 { - z *= y + 4.0; - } - if i >= 4 { - z *= y + 3.0; - } - if i >= 3 { - z *= y + 2.0; - r += log(z); - } - } else if ix < 0x43900000 { - /* 8.0 <= x < 2**58 */ - t = log(x); - z = 1.0 / x; - y = z * z; - w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); - r = (x - 0.5) * (t - 1.0) + w; - } else { - /* 2**58 <= x <= inf */ - r = x * (log(x) - 1.0); - } - if sign { - r = nadj - r; - } - return (r, signgam); -} diff --git a/library/compiler-builtins/libm/src/math/lgamma_r.rs b/library/compiler-builtins/libm/src/math/lgamma_r.rs new file mode 100644 index 0000000000000..382a501fc3dcf --- /dev/null +++ b/library/compiler-builtins/libm/src/math/lgamma_r.rs @@ -0,0 +1,319 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* lgamma_r(x, signgamp) + * Reentrant version of the logarithm of the Gamma function + * with user provide pointer for the sign of Gamma(x). + * + * Method: + * 1. Argument Reduction for 0 < x <= 8 + * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may + * reduce x to a number in [1.5,2.5] by + * lgamma(1+s) = log(s) + lgamma(s) + * for example, + * lgamma(7.3) = log(6.3) + lgamma(6.3) + * = log(6.3*5.3) + lgamma(5.3) + * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) + * 2. Polynomial approximation of lgamma around its + * minimun ymin=1.461632144968362245 to maintain monotonicity. + * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use + * Let z = x-ymin; + * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) + * where + * poly(z) is a 14 degree polynomial. + * 2. Rational approximation in the primary interval [2,3] + * We use the following approximation: + * s = x-2.0; + * lgamma(x) = 0.5*s + s*P(s)/Q(s) + * with accuracy + * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 + * Our algorithms are based on the following observation + * + * zeta(2)-1 2 zeta(3)-1 3 + * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... + * 2 3 + * + * where Euler = 0.5771... is the Euler constant, which is very + * close to 0.5. + * + * 3. For x>=8, we have + * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... + * (better formula: + * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) + * Let z = 1/x, then we approximation + * f(z) = lgamma(x) - (x-0.5)(log(x)-1) + * by + * 3 5 11 + * w = w0 + w1*z + w2*z + w3*z + ... + w6*z + * where + * |w - f(z)| < 2**-58.74 + * + * 4. For negative x, since (G is gamma function) + * -x*G(-x)*G(x) = PI/sin(PI*x), + * we have + * G(x) = PI/(sin(PI*x)*(-x)*G(-x)) + * since G(-x) is positive, sign(G(x)) = sign(sin(PI*x)) for x<0 + * Hence, for x<0, signgam = sign(sin(PI*x)) and + * lgamma(x) = log(|Gamma(x)|) + * = log(PI/(|x*sin(PI*x)|)) - lgamma(-x); + * Note: one should avoid compute PI*(-x) directly in the + * computation of sin(PI*(-x)). + * + * 5. Special Cases + * lgamma(2+s) ~ s*(1-Euler) for tiny s + * lgamma(1) = lgamma(2) = 0 + * lgamma(x) ~ -log(|x|) for tiny x + * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero + * lgamma(inf) = inf + * lgamma(-inf) = inf (bug for bug compatible with C99!?) + * + */ + +use super::{floor, k_cos, k_sin, log}; + +const PI: f64 = 3.14159265358979311600e+00; /* 0x400921FB, 0x54442D18 */ +const A0: f64 = 7.72156649015328655494e-02; /* 0x3FB3C467, 0xE37DB0C8 */ +const A1: f64 = 3.22467033424113591611e-01; /* 0x3FD4A34C, 0xC4A60FAD */ +const A2: f64 = 6.73523010531292681824e-02; /* 0x3FB13E00, 0x1A5562A7 */ +const A3: f64 = 2.05808084325167332806e-02; /* 0x3F951322, 0xAC92547B */ +const A4: f64 = 7.38555086081402883957e-03; /* 0x3F7E404F, 0xB68FEFE8 */ +const A5: f64 = 2.89051383673415629091e-03; /* 0x3F67ADD8, 0xCCB7926B */ +const A6: f64 = 1.19270763183362067845e-03; /* 0x3F538A94, 0x116F3F5D */ +const A7: f64 = 5.10069792153511336608e-04; /* 0x3F40B6C6, 0x89B99C00 */ +const A8: f64 = 2.20862790713908385557e-04; /* 0x3F2CF2EC, 0xED10E54D */ +const A9: f64 = 1.08011567247583939954e-04; /* 0x3F1C5088, 0x987DFB07 */ +const A10: f64 = 2.52144565451257326939e-05; /* 0x3EFA7074, 0x428CFA52 */ +const A11: f64 = 4.48640949618915160150e-05; /* 0x3F07858E, 0x90A45837 */ +const TC: f64 = 1.46163214496836224576e+00; /* 0x3FF762D8, 0x6356BE3F */ +const TF: f64 = -1.21486290535849611461e-01; /* 0xBFBF19B9, 0xBCC38A42 */ +/* tt = -(tail of TF) */ +const TT: f64 = -3.63867699703950536541e-18; /* 0xBC50C7CA, 0xA48A971F */ +const T0: f64 = 4.83836122723810047042e-01; /* 0x3FDEF72B, 0xC8EE38A2 */ +const T1: f64 = -1.47587722994593911752e-01; /* 0xBFC2E427, 0x8DC6C509 */ +const T2: f64 = 6.46249402391333854778e-02; /* 0x3FB08B42, 0x94D5419B */ +const T3: f64 = -3.27885410759859649565e-02; /* 0xBFA0C9A8, 0xDF35B713 */ +const T4: f64 = 1.79706750811820387126e-02; /* 0x3F9266E7, 0x970AF9EC */ +const T5: f64 = -1.03142241298341437450e-02; /* 0xBF851F9F, 0xBA91EC6A */ +const T6: f64 = 6.10053870246291332635e-03; /* 0x3F78FCE0, 0xE370E344 */ +const T7: f64 = -3.68452016781138256760e-03; /* 0xBF6E2EFF, 0xB3E914D7 */ +const T8: f64 = 2.25964780900612472250e-03; /* 0x3F6282D3, 0x2E15C915 */ +const T9: f64 = -1.40346469989232843813e-03; /* 0xBF56FE8E, 0xBF2D1AF1 */ +const T10: f64 = 8.81081882437654011382e-04; /* 0x3F4CDF0C, 0xEF61A8E9 */ +const T11: f64 = -5.38595305356740546715e-04; /* 0xBF41A610, 0x9C73E0EC */ +const T12: f64 = 3.15632070903625950361e-04; /* 0x3F34AF6D, 0x6C0EBBF7 */ +const T13: f64 = -3.12754168375120860518e-04; /* 0xBF347F24, 0xECC38C38 */ +const T14: f64 = 3.35529192635519073543e-04; /* 0x3F35FD3E, 0xE8C2D3F4 */ +const U0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ +const U1: f64 = 6.32827064025093366517e-01; /* 0x3FE4401E, 0x8B005DFF */ +const U2: f64 = 1.45492250137234768737e+00; /* 0x3FF7475C, 0xD119BD6F */ +const U3: f64 = 9.77717527963372745603e-01; /* 0x3FEF4976, 0x44EA8450 */ +const U4: f64 = 2.28963728064692451092e-01; /* 0x3FCD4EAE, 0xF6010924 */ +const U5: f64 = 1.33810918536787660377e-02; /* 0x3F8B678B, 0xBF2BAB09 */ +const V1: f64 = 2.45597793713041134822e+00; /* 0x4003A5D7, 0xC2BD619C */ +const V2: f64 = 2.12848976379893395361e+00; /* 0x40010725, 0xA42B18F5 */ +const V3: f64 = 7.69285150456672783825e-01; /* 0x3FE89DFB, 0xE45050AF */ +const V4: f64 = 1.04222645593369134254e-01; /* 0x3FBAAE55, 0xD6537C88 */ +const V5: f64 = 3.21709242282423911810e-03; /* 0x3F6A5ABB, 0x57D0CF61 */ +const S0: f64 = -7.72156649015328655494e-02; /* 0xBFB3C467, 0xE37DB0C8 */ +const S1: f64 = 2.14982415960608852501e-01; /* 0x3FCB848B, 0x36E20878 */ +const S2: f64 = 3.25778796408930981787e-01; /* 0x3FD4D98F, 0x4F139F59 */ +const S3: f64 = 1.46350472652464452805e-01; /* 0x3FC2BB9C, 0xBEE5F2F7 */ +const S4: f64 = 2.66422703033638609560e-02; /* 0x3F9B481C, 0x7E939961 */ +const S5: f64 = 1.84028451407337715652e-03; /* 0x3F5E26B6, 0x7368F239 */ +const S6: f64 = 3.19475326584100867617e-05; /* 0x3F00BFEC, 0xDD17E945 */ +const R1: f64 = 1.39200533467621045958e+00; /* 0x3FF645A7, 0x62C4AB74 */ +const R2: f64 = 7.21935547567138069525e-01; /* 0x3FE71A18, 0x93D3DCDC */ +const R3: f64 = 1.71933865632803078993e-01; /* 0x3FC601ED, 0xCCFBDF27 */ +const R4: f64 = 1.86459191715652901344e-02; /* 0x3F9317EA, 0x742ED475 */ +const R5: f64 = 7.77942496381893596434e-04; /* 0x3F497DDA, 0xCA41A95B */ +const R6: f64 = 7.32668430744625636189e-06; /* 0x3EDEBAF7, 0xA5B38140 */ +const W0: f64 = 4.18938533204672725052e-01; /* 0x3FDACFE3, 0x90C97D69 */ +const W1: f64 = 8.33333333333329678849e-02; /* 0x3FB55555, 0x5555553B */ +const W2: f64 = -2.77777777728775536470e-03; /* 0xBF66C16C, 0x16B02E5C */ +const W3: f64 = 7.93650558643019558500e-04; /* 0x3F4A019F, 0x98CF38B6 */ +const W4: f64 = -5.95187557450339963135e-04; /* 0xBF4380CB, 0x8C0FE741 */ +const W5: f64 = 8.36339918996282139126e-04; /* 0x3F4B67BA, 0x4CDAD5D1 */ +const W6: f64 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ + +/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ +fn sin_pi(mut x: f64) -> f64 { + let mut n: i32; + + /* spurious inexact if odd int */ + x = 2.0 * (x * 0.5 - floor(x * 0.5)); /* x mod 2.0 */ + + n = (x * 4.0) as i32; + n = (n + 1) / 2; + x -= (n as f64) * 0.5; + x *= PI; + + match n { + 1 => k_cos(x, 0.0), + 2 => k_sin(-x, 0.0, 0), + 3 => -k_cos(x, 0.0), + 0 | _ => k_sin(x, 0.0, 0), + } +} + +pub fn lgamma_r(mut x: f64) -> (f64, i32) { + let u: u64 = x.to_bits(); + let mut t: f64; + let y: f64; + let mut z: f64; + let nadj: f64; + let p: f64; + let p1: f64; + let p2: f64; + let p3: f64; + let q: f64; + let mut r: f64; + let w: f64; + let ix: u32; + let sign: bool; + let i: i32; + let mut signgam: i32; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + signgam = 1; + sign = (u >> 63) != 0; + ix = ((u >> 32) as u32) & 0x7fffffff; + if ix >= 0x7ff00000 { + return (x * x, signgam); + } + if ix < (0x3ff - 70) << 20 { + /* |x|<2**-70, return -log(|x|) */ + if sign { + x = -x; + signgam = -1; + } + return (-log(x), signgam); + } + if sign { + x = -x; + t = sin_pi(x); + if t == 0.0 { + /* -integer */ + return (1.0 / (x - x), signgam); + } + if t > 0.0 { + signgam = -1; + } else { + t = -t; + } + nadj = log(PI / (t * x)); + } else { + nadj = 0.0; + } + + /* purge off 1 and 2 */ + if (ix == 0x3ff00000 || ix == 0x40000000) && (u & 0xffffffff) == 0 { + r = 0.0; + } + /* for x < 2.0 */ + else if ix < 0x40000000 { + if ix <= 0x3feccccc { + /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -log(x); + if ix >= 0x3FE76944 { + y = 1.0 - x; + i = 0; + } else if ix >= 0x3FCDA661 { + y = x - (TC - 1.0); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0; + if ix >= 0x3FFBB4C3 { + /* [1.7316,2] */ + y = 2.0 - x; + i = 0; + } else if ix >= 0x3FF3B4C4 { + /* [1.23,1.73] */ + y = x - TC; + i = 1; + } else { + y = x - 1.0; + i = 2; + } + } + match i { + 0 => { + z = y * y; + p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); + p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); + p = y * p1 + p2; + r += p - 0.5 * y; + } + 1 => { + z = y * y; + w = z * y; + p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ + p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); + p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); + p = z * p1 - (TT - w * (p2 + y * p3)); + r += TF + p; + } + 2 => { + p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); + p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); + r += -0.5 * y + p1 / p2; + } + #[cfg(feature = "checked")] + _ => unreachable!(), + #[cfg(not(feature = "checked"))] + _ => {} + } + } else if ix < 0x40200000 { + /* x < 8.0 */ + i = x as i32; + y = x - (i as f64); + p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); + q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); + r = 0.5 * y + p / q; + z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ + // TODO: In C, this was implemented using switch jumps with fallthrough. + // Does this implementation have performance problems? + if i >= 7 { + z *= y + 6.0; + } + if i >= 6 { + z *= y + 5.0; + } + if i >= 5 { + z *= y + 4.0; + } + if i >= 4 { + z *= y + 3.0; + } + if i >= 3 { + z *= y + 2.0; + r += log(z); + } + } else if ix < 0x43900000 { + /* 8.0 <= x < 2**58 */ + t = log(x); + z = 1.0 / x; + y = z * z; + w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); + r = (x - 0.5) * (t - 1.0) + w; + } else { + /* 2**58 <= x <= inf */ + r = x * (log(x) - 1.0); + } + if sign { + r = nadj - r; + } + return (r, signgam); +} diff --git a/library/compiler-builtins/libm/src/math/lgammaf.rs b/library/compiler-builtins/libm/src/math/lgammaf.rs index 8fe8060b5ece7..dfdc87f9622c6 100644 --- a/library/compiler-builtins/libm/src/math/lgammaf.rs +++ b/library/compiler-builtins/libm/src/math/lgammaf.rs @@ -1,258 +1,5 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * 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. - * ==================================================== - */ - -use super::{floorf, k_cosf, k_sinf, logf}; - -const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ -const A0: f32 = 7.7215664089e-02; /* 0x3d9e233f */ -const A1: f32 = 3.2246702909e-01; /* 0x3ea51a66 */ -const A2: f32 = 6.7352302372e-02; /* 0x3d89f001 */ -const A3: f32 = 2.0580807701e-02; /* 0x3ca89915 */ -const A4: f32 = 7.3855509982e-03; /* 0x3bf2027e */ -const A5: f32 = 2.8905137442e-03; /* 0x3b3d6ec6 */ -const A6: f32 = 1.1927076848e-03; /* 0x3a9c54a1 */ -const A7: f32 = 5.1006977446e-04; /* 0x3a05b634 */ -const A8: f32 = 2.2086278477e-04; /* 0x39679767 */ -const A9: f32 = 1.0801156895e-04; /* 0x38e28445 */ -const A10: f32 = 2.5214456400e-05; /* 0x37d383a2 */ -const A11: f32 = 4.4864096708e-05; /* 0x383c2c75 */ -const TC: f32 = 1.4616321325e+00; /* 0x3fbb16c3 */ -const TF: f32 = -1.2148628384e-01; /* 0xbdf8cdcd */ -/* TT = -(tail of TF) */ -const TT: f32 = 6.6971006518e-09; /* 0x31e61c52 */ -const T0: f32 = 4.8383611441e-01; /* 0x3ef7b95e */ -const T1: f32 = -1.4758771658e-01; /* 0xbe17213c */ -const T2: f32 = 6.4624942839e-02; /* 0x3d845a15 */ -const T3: f32 = -3.2788541168e-02; /* 0xbd064d47 */ -const T4: f32 = 1.7970675603e-02; /* 0x3c93373d */ -const T5: f32 = -1.0314224288e-02; /* 0xbc28fcfe */ -const T6: f32 = 6.1005386524e-03; /* 0x3bc7e707 */ -const T7: f32 = -3.6845202558e-03; /* 0xbb7177fe */ -const T8: f32 = 2.2596477065e-03; /* 0x3b141699 */ -const T9: f32 = -1.4034647029e-03; /* 0xbab7f476 */ -const T10: f32 = 8.8108185446e-04; /* 0x3a66f867 */ -const T11: f32 = -5.3859531181e-04; /* 0xba0d3085 */ -const T12: f32 = 3.1563205994e-04; /* 0x39a57b6b */ -const T13: f32 = -3.1275415677e-04; /* 0xb9a3f927 */ -const T14: f32 = 3.3552918467e-04; /* 0x39afe9f7 */ -const U0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ -const U1: f32 = 6.3282704353e-01; /* 0x3f2200f4 */ -const U2: f32 = 1.4549225569e+00; /* 0x3fba3ae7 */ -const U3: f32 = 9.7771751881e-01; /* 0x3f7a4bb2 */ -const U4: f32 = 2.2896373272e-01; /* 0x3e6a7578 */ -const U5: f32 = 1.3381091878e-02; /* 0x3c5b3c5e */ -const V1: f32 = 2.4559779167e+00; /* 0x401d2ebe */ -const V2: f32 = 2.1284897327e+00; /* 0x4008392d */ -const V3: f32 = 7.6928514242e-01; /* 0x3f44efdf */ -const V4: f32 = 1.0422264785e-01; /* 0x3dd572af */ -const V5: f32 = 3.2170924824e-03; /* 0x3b52d5db */ -const S0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ -const S1: f32 = 2.1498242021e-01; /* 0x3e5c245a */ -const S2: f32 = 3.2577878237e-01; /* 0x3ea6cc7a */ -const S3: f32 = 1.4635047317e-01; /* 0x3e15dce6 */ -const S4: f32 = 2.6642270386e-02; /* 0x3cda40e4 */ -const S5: f32 = 1.8402845599e-03; /* 0x3af135b4 */ -const S6: f32 = 3.1947532989e-05; /* 0x3805ff67 */ -const R1: f32 = 1.3920053244e+00; /* 0x3fb22d3b */ -const R2: f32 = 7.2193557024e-01; /* 0x3f38d0c5 */ -const R3: f32 = 1.7193385959e-01; /* 0x3e300f6e */ -const R4: f32 = 1.8645919859e-02; /* 0x3c98bf54 */ -const R5: f32 = 7.7794247773e-04; /* 0x3a4beed6 */ -const R6: f32 = 7.3266842264e-06; /* 0x36f5d7bd */ -const W0: f32 = 4.1893854737e-01; /* 0x3ed67f1d */ -const W1: f32 = 8.3333335817e-02; /* 0x3daaaaab */ -const W2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ -const W3: f32 = 7.9365057172e-04; /* 0x3a500cfd */ -const W4: f32 = -5.9518753551e-04; /* 0xba1c065c */ -const W5: f32 = 8.3633989561e-04; /* 0x3a5b3dd2 */ -const W6: f32 = -1.6309292987e-03; /* 0xbad5c4e8 */ - -/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ -fn sin_pi(mut x: f32) -> f32 { - let mut y: f64; - let mut n: isize; - - /* spurious inexact if odd int */ - x = 2.0 * (x * 0.5 - floorf(x * 0.5)); /* x mod 2.0 */ - - n = (x * 4.0) as isize; - n = (n + 1) / 2; - y = (x as f64) - (n as f64) * 0.5; - y *= 3.14159265358979323846; - match n { - 1 => k_cosf(y), - 2 => k_sinf(-y), - 3 => -k_cosf(y), - 0 | _ => k_sinf(y), - } -} +use super::lgammaf_r; pub fn lgammaf(x: f32) -> f32 { lgammaf_r(x).0 } - -pub fn lgammaf_r(mut x: f32) -> (f32, isize) { - let u = x.to_bits(); - let mut t: f32; - let y: f32; - let mut z: f32; - let nadj: f32; - let p: f32; - let p1: f32; - let p2: f32; - let p3: f32; - let q: f32; - let mut r: f32; - let w: f32; - let ix: u32; - let i: isize; - let sign: bool; - let mut signgam: isize; - - /* purge off +-inf, NaN, +-0, tiny and negative arguments */ - signgam = 1; - sign = (u >> 31) != 0; - ix = u & 0x7fffffff; - if ix >= 0x7f800000 { - return (x * x, signgam); - } - if ix < 0x35000000 { - /* |x| < 2**-21, return -log(|x|) */ - if sign { - signgam = -1; - x = -x; - } - return (-logf(x), signgam); - } - if sign { - x = -x; - t = sin_pi(x); - if t == 0.0 { - /* -integer */ - return (1.0 / (x - x), signgam); - } - if t > 0.0 { - signgam = -1; - } else { - t = -t; - } - nadj = logf(PI / (t * x)); - } else { - nadj = 0.0; - } - - /* purge off 1 and 2 */ - if ix == 0x3f800000 || ix == 0x40000000 { - r = 0.0; - } - /* for x < 2.0 */ - else if ix < 0x40000000 { - if ix <= 0x3f666666 { - /* lgamma(x) = lgamma(x+1)-log(x) */ - r = -logf(x); - if ix >= 0x3f3b4a20 { - y = 1.0 - x; - i = 0; - } else if ix >= 0x3e6d3308 { - y = x - (TC - 1.0); - i = 1; - } else { - y = x; - i = 2; - } - } else { - r = 0.0; - if ix >= 0x3fdda618 { - /* [1.7316,2] */ - y = 2.0 - x; - i = 0; - } else if ix >= 0x3F9da620 { - /* [1.23,1.73] */ - y = x - TC; - i = 1; - } else { - y = x - 1.0; - i = 2; - } - } - match i { - 0 => { - z = y * y; - p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); - p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); - p = y * p1 + p2; - r += p - 0.5 * y; - } - 1 => { - z = y * y; - w = z * y; - p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ - p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); - p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); - p = z * p1 - (TT - w * (p2 + y * p3)); - r += TF + p; - } - 2 => { - p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); - p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); - r += -0.5 * y + p1 / p2; - } - #[cfg(feature = "checked")] - _ => unreachable!(), - #[cfg(not(feature = "checked"))] - _ => {} - } - } else if ix < 0x41000000 { - /* x < 8.0 */ - i = x as isize; - y = x - (i as f32); - p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); - q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); - r = 0.5 * y + p / q; - z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ - // TODO: In C, this was implemented using switch jumps with fallthrough. - // Does this implementation have performance problems? - if i >= 7 { - z *= y + 6.0; - } - if i >= 6 { - z *= y + 5.0; - } - if i >= 5 { - z *= y + 4.0; - } - if i >= 4 { - z *= y + 3.0; - } - if i >= 3 { - z *= y + 2.0; - r += logf(z); - } - } else if ix < 0x5c800000 { - /* 8.0 <= x < 2**58 */ - t = logf(x); - z = 1.0 / x; - y = z * z; - w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); - r = (x - 0.5) * (t - 1.0) + w; - } else { - /* 2**58 <= x <= inf */ - r = x * (logf(x) - 1.0); - } - if sign { - r = nadj - r; - } - return (r, signgam); -} diff --git a/library/compiler-builtins/libm/src/math/lgammaf_r.rs b/library/compiler-builtins/libm/src/math/lgammaf_r.rs new file mode 100644 index 0000000000000..0745359a257d1 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/lgammaf_r.rs @@ -0,0 +1,254 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * 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. + * ==================================================== + */ + +use super::{floorf, k_cosf, k_sinf, logf}; + +const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ +const A0: f32 = 7.7215664089e-02; /* 0x3d9e233f */ +const A1: f32 = 3.2246702909e-01; /* 0x3ea51a66 */ +const A2: f32 = 6.7352302372e-02; /* 0x3d89f001 */ +const A3: f32 = 2.0580807701e-02; /* 0x3ca89915 */ +const A4: f32 = 7.3855509982e-03; /* 0x3bf2027e */ +const A5: f32 = 2.8905137442e-03; /* 0x3b3d6ec6 */ +const A6: f32 = 1.1927076848e-03; /* 0x3a9c54a1 */ +const A7: f32 = 5.1006977446e-04; /* 0x3a05b634 */ +const A8: f32 = 2.2086278477e-04; /* 0x39679767 */ +const A9: f32 = 1.0801156895e-04; /* 0x38e28445 */ +const A10: f32 = 2.5214456400e-05; /* 0x37d383a2 */ +const A11: f32 = 4.4864096708e-05; /* 0x383c2c75 */ +const TC: f32 = 1.4616321325e+00; /* 0x3fbb16c3 */ +const TF: f32 = -1.2148628384e-01; /* 0xbdf8cdcd */ +/* TT = -(tail of TF) */ +const TT: f32 = 6.6971006518e-09; /* 0x31e61c52 */ +const T0: f32 = 4.8383611441e-01; /* 0x3ef7b95e */ +const T1: f32 = -1.4758771658e-01; /* 0xbe17213c */ +const T2: f32 = 6.4624942839e-02; /* 0x3d845a15 */ +const T3: f32 = -3.2788541168e-02; /* 0xbd064d47 */ +const T4: f32 = 1.7970675603e-02; /* 0x3c93373d */ +const T5: f32 = -1.0314224288e-02; /* 0xbc28fcfe */ +const T6: f32 = 6.1005386524e-03; /* 0x3bc7e707 */ +const T7: f32 = -3.6845202558e-03; /* 0xbb7177fe */ +const T8: f32 = 2.2596477065e-03; /* 0x3b141699 */ +const T9: f32 = -1.4034647029e-03; /* 0xbab7f476 */ +const T10: f32 = 8.8108185446e-04; /* 0x3a66f867 */ +const T11: f32 = -5.3859531181e-04; /* 0xba0d3085 */ +const T12: f32 = 3.1563205994e-04; /* 0x39a57b6b */ +const T13: f32 = -3.1275415677e-04; /* 0xb9a3f927 */ +const T14: f32 = 3.3552918467e-04; /* 0x39afe9f7 */ +const U0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ +const U1: f32 = 6.3282704353e-01; /* 0x3f2200f4 */ +const U2: f32 = 1.4549225569e+00; /* 0x3fba3ae7 */ +const U3: f32 = 9.7771751881e-01; /* 0x3f7a4bb2 */ +const U4: f32 = 2.2896373272e-01; /* 0x3e6a7578 */ +const U5: f32 = 1.3381091878e-02; /* 0x3c5b3c5e */ +const V1: f32 = 2.4559779167e+00; /* 0x401d2ebe */ +const V2: f32 = 2.1284897327e+00; /* 0x4008392d */ +const V3: f32 = 7.6928514242e-01; /* 0x3f44efdf */ +const V4: f32 = 1.0422264785e-01; /* 0x3dd572af */ +const V5: f32 = 3.2170924824e-03; /* 0x3b52d5db */ +const S0: f32 = -7.7215664089e-02; /* 0xbd9e233f */ +const S1: f32 = 2.1498242021e-01; /* 0x3e5c245a */ +const S2: f32 = 3.2577878237e-01; /* 0x3ea6cc7a */ +const S3: f32 = 1.4635047317e-01; /* 0x3e15dce6 */ +const S4: f32 = 2.6642270386e-02; /* 0x3cda40e4 */ +const S5: f32 = 1.8402845599e-03; /* 0x3af135b4 */ +const S6: f32 = 3.1947532989e-05; /* 0x3805ff67 */ +const R1: f32 = 1.3920053244e+00; /* 0x3fb22d3b */ +const R2: f32 = 7.2193557024e-01; /* 0x3f38d0c5 */ +const R3: f32 = 1.7193385959e-01; /* 0x3e300f6e */ +const R4: f32 = 1.8645919859e-02; /* 0x3c98bf54 */ +const R5: f32 = 7.7794247773e-04; /* 0x3a4beed6 */ +const R6: f32 = 7.3266842264e-06; /* 0x36f5d7bd */ +const W0: f32 = 4.1893854737e-01; /* 0x3ed67f1d */ +const W1: f32 = 8.3333335817e-02; /* 0x3daaaaab */ +const W2: f32 = -2.7777778450e-03; /* 0xbb360b61 */ +const W3: f32 = 7.9365057172e-04; /* 0x3a500cfd */ +const W4: f32 = -5.9518753551e-04; /* 0xba1c065c */ +const W5: f32 = 8.3633989561e-04; /* 0x3a5b3dd2 */ +const W6: f32 = -1.6309292987e-03; /* 0xbad5c4e8 */ + +/* sin(PI*x) assuming x > 2^-100, if sin(PI*x)==0 the sign is arbitrary */ +fn sin_pi(mut x: f32) -> f32 { + let mut y: f64; + let mut n: isize; + + /* spurious inexact if odd int */ + x = 2.0 * (x * 0.5 - floorf(x * 0.5)); /* x mod 2.0 */ + + n = (x * 4.0) as isize; + n = (n + 1) / 2; + y = (x as f64) - (n as f64) * 0.5; + y *= 3.14159265358979323846; + match n { + 1 => k_cosf(y), + 2 => k_sinf(-y), + 3 => -k_cosf(y), + 0 | _ => k_sinf(y), + } +} + +pub fn lgammaf_r(mut x: f32) -> (f32, i32) { + let u = x.to_bits(); + let mut t: f32; + let y: f32; + let mut z: f32; + let nadj: f32; + let p: f32; + let p1: f32; + let p2: f32; + let p3: f32; + let q: f32; + let mut r: f32; + let w: f32; + let ix: u32; + let i: i32; + let sign: bool; + let mut signgam: i32; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + signgam = 1; + sign = (u >> 31) != 0; + ix = u & 0x7fffffff; + if ix >= 0x7f800000 { + return (x * x, signgam); + } + if ix < 0x35000000 { + /* |x| < 2**-21, return -log(|x|) */ + if sign { + signgam = -1; + x = -x; + } + return (-logf(x), signgam); + } + if sign { + x = -x; + t = sin_pi(x); + if t == 0.0 { + /* -integer */ + return (1.0 / (x - x), signgam); + } + if t > 0.0 { + signgam = -1; + } else { + t = -t; + } + nadj = logf(PI / (t * x)); + } else { + nadj = 0.0; + } + + /* purge off 1 and 2 */ + if ix == 0x3f800000 || ix == 0x40000000 { + r = 0.0; + } + /* for x < 2.0 */ + else if ix < 0x40000000 { + if ix <= 0x3f666666 { + /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -logf(x); + if ix >= 0x3f3b4a20 { + y = 1.0 - x; + i = 0; + } else if ix >= 0x3e6d3308 { + y = x - (TC - 1.0); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0; + if ix >= 0x3fdda618 { + /* [1.7316,2] */ + y = 2.0 - x; + i = 0; + } else if ix >= 0x3F9da620 { + /* [1.23,1.73] */ + y = x - TC; + i = 1; + } else { + y = x - 1.0; + i = 2; + } + } + match i { + 0 => { + z = y * y; + p1 = A0 + z * (A2 + z * (A4 + z * (A6 + z * (A8 + z * A10)))); + p2 = z * (A1 + z * (A3 + z * (A5 + z * (A7 + z * (A9 + z * A11))))); + p = y * p1 + p2; + r += p - 0.5 * y; + } + 1 => { + z = y * y; + w = z * y; + p1 = T0 + w * (T3 + w * (T6 + w * (T9 + w * T12))); /* parallel comp */ + p2 = T1 + w * (T4 + w * (T7 + w * (T10 + w * T13))); + p3 = T2 + w * (T5 + w * (T8 + w * (T11 + w * T14))); + p = z * p1 - (TT - w * (p2 + y * p3)); + r += TF + p; + } + 2 => { + p1 = y * (U0 + y * (U1 + y * (U2 + y * (U3 + y * (U4 + y * U5))))); + p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); + r += -0.5 * y + p1 / p2; + } + #[cfg(feature = "checked")] + _ => unreachable!(), + #[cfg(not(feature = "checked"))] + _ => {} + } + } else if ix < 0x41000000 { + /* x < 8.0 */ + i = x as i32; + y = x - (i as f32); + p = y * (S0 + y * (S1 + y * (S2 + y * (S3 + y * (S4 + y * (S5 + y * S6)))))); + q = 1.0 + y * (R1 + y * (R2 + y * (R3 + y * (R4 + y * (R5 + y * R6))))); + r = 0.5 * y + p / q; + z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ + // TODO: In C, this was implemented using switch jumps with fallthrough. + // Does this implementation have performance problems? + if i >= 7 { + z *= y + 6.0; + } + if i >= 6 { + z *= y + 5.0; + } + if i >= 5 { + z *= y + 4.0; + } + if i >= 4 { + z *= y + 3.0; + } + if i >= 3 { + z *= y + 2.0; + r += logf(z); + } + } else if ix < 0x5c800000 { + /* 8.0 <= x < 2**58 */ + t = logf(x); + z = 1.0 / x; + y = z * z; + w = W0 + z * (W1 + y * (W2 + y * (W3 + y * (W4 + y * (W5 + y * W6))))); + r = (x - 0.5) * (t - 1.0) + w; + } else { + /* 2**58 <= x <= inf */ + r = x * (logf(x) - 1.0); + } + if sign { + r = nadj - r; + } + return (r, signgam); +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index b70b0cd6b3289..c4d247414690e 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -129,7 +129,9 @@ mod jnf; mod ldexp; mod ldexpf; mod lgamma; +mod lgamma_r; mod lgammaf; +mod lgammaf_r; mod log; mod log10; mod log10f; @@ -233,9 +235,9 @@ pub use self::jnf::ynf; pub use self::ldexp::ldexp; pub use self::ldexpf::ldexpf; pub use self::lgamma::lgamma; -pub use self::lgamma::lgamma_r; +pub use self::lgamma_r::lgamma_r; pub use self::lgammaf::lgammaf; -pub use self::lgammaf::lgammaf_r; +pub use self::lgammaf_r::lgammaf_r; pub use self::log::log; pub use self::log10::log10; pub use self::log10f::log10f; diff --git a/library/compiler-builtins/libm/src/math/modf.rs b/library/compiler-builtins/libm/src/math/modf.rs index a37f8b918a37d..bcab33a810d66 100644 --- a/library/compiler-builtins/libm/src/math/modf.rs +++ b/library/compiler-builtins/libm/src/math/modf.rs @@ -2,7 +2,7 @@ pub fn modf(x: f64) -> (f64, f64) { let rv2: f64; let mut u = x.to_bits(); let mask: u64; - let e = ((u >> 52 & 0x7ff) as isize) - 0x3ff; + let e = ((u >> 52 & 0x7ff) as i32) - 0x3ff; /* no fractional part */ if e >= 52 { diff --git a/library/compiler-builtins/libm/src/math/modff.rs b/library/compiler-builtins/libm/src/math/modff.rs index 4ce9052e7eaca..56ece12e3c0de 100644 --- a/library/compiler-builtins/libm/src/math/modff.rs +++ b/library/compiler-builtins/libm/src/math/modff.rs @@ -2,7 +2,7 @@ pub fn modff(x: f32) -> (f32, f32) { let rv2: f32; let mut u: u32 = x.to_bits(); let mask: u32; - let e = ((u >> 23 & 0xff) as isize) - 0x7f; + let e = ((u >> 23 & 0xff) as i32) - 0x7f; /* no fractional part */ if e >= 23 { diff --git a/library/compiler-builtins/libm/src/math/remquo.rs b/library/compiler-builtins/libm/src/math/remquo.rs index 3681b947cc243..507f8db347a3d 100644 --- a/library/compiler-builtins/libm/src/math/remquo.rs +++ b/library/compiler-builtins/libm/src/math/remquo.rs @@ -1,8 +1,8 @@ -pub fn remquo(mut x: f64, mut y: f64) -> (f64, isize) { +pub fn remquo(mut x: f64, mut y: f64) -> (f64, i32) { let ux: u64 = x.to_bits(); let mut uy: u64 = y.to_bits(); - let mut ex = ((ux >> 52) & 0x7ff) as isize; - let mut ey = ((uy >> 52) & 0x7ff) as isize; + let mut ex = ((ux >> 52) & 0x7ff) as i32; + let mut ey = ((uy >> 52) & 0x7ff) as i32; let sx = (ux >> 63) != 0; let sy = (uy >> 63) != 0; let mut q: u32; @@ -88,7 +88,7 @@ pub fn remquo(mut x: f64, mut y: f64) -> (f64, isize) { q += 1; } q &= 0x7fffffff; - let quo = if sx ^ sy { -(q as isize) } else { q as isize }; + let quo = if sx ^ sy { -(q as i32) } else { q as i32 }; if sx { (-x, quo) } else { diff --git a/library/compiler-builtins/libm/src/math/remquof.rs b/library/compiler-builtins/libm/src/math/remquof.rs index 40ded5d69768f..6aa4974ed3eee 100644 --- a/library/compiler-builtins/libm/src/math/remquof.rs +++ b/library/compiler-builtins/libm/src/math/remquof.rs @@ -1,8 +1,8 @@ -pub fn remquof(mut x: f32, mut y: f32) -> (f32, isize) { +pub fn remquof(mut x: f32, mut y: f32) -> (f32, i32) { let ux: u32 = x.to_bits(); let mut uy: u32 = y.to_bits(); - let mut ex = ((ux >> 23) & 0xff) as isize; - let mut ey = ((uy >> 23) & 0xff) as isize; + let mut ex = ((ux >> 23) & 0xff) as i32; + let mut ey = ((uy >> 23) & 0xff) as i32; let sx = (ux >> 31) != 0; let sy = (uy >> 31) != 0; let mut q: u32; @@ -87,7 +87,7 @@ pub fn remquof(mut x: f32, mut y: f32) -> (f32, isize) { q += 1; } q &= 0x7fffffff; - let quo = if sx ^ sy { -(q as isize) } else { q as isize }; + let quo = if sx ^ sy { -(q as i32) } else { q as i32 }; if sx { (-x, quo) } else { From 7c1e4dbf117e761c567b8ecdfb62053dc54b3712 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Thu, 9 May 2019 07:36:52 +0300 Subject: [PATCH 0714/4206] fix traits --- library/compiler-builtins/libm/build.rs | 20 ++++----- library/compiler-builtins/libm/src/lib.rs | 52 ++++++++--------------- 2 files changed, 28 insertions(+), 44 deletions(-) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 4d739a121120d..4da50a885d915 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -41,18 +41,18 @@ mod musl_reference_tests { "rem_pio2.rs", "rem_pio2_large.rs", "rem_pio2f.rs", - "remquo.rs", // more than 1 result - "remquof.rs", // more than 1 result + "remquo.rs", // more than 1 result + "remquof.rs", // more than 1 result "lgamma_r.rs", // more than 1 result "lgammaf_r.rs", // more than 1 result - "frexp.rs", // more than 1 result - "frexpf.rs", // more than 1 result - "sincos.rs", // more than 1 result - "sincosf.rs", // more than 1 result - "modf.rs", // more than 1 result - "modff.rs", // more than 1 result - "jn.rs", // passed, but very slow - "jnf.rs", // passed, but very slow + "frexp.rs", // more than 1 result + "frexpf.rs", // more than 1 result + "sincos.rs", // more than 1 result + "sincosf.rs", // more than 1 result + "modf.rs", // more than 1 result + "modff.rs", // more than 1 result + "jn.rs", // passed, but very slow + "jnf.rs", // passed, but very slow ]; struct Function { diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 5e94541ab1a3c..0d0f6155abe88 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -119,13 +119,7 @@ pub trait F32Ext: private::Sealed + Sized { fn atan2(self, other: Self) -> Self; - #[inline] - fn sin_cos(self) -> (Self, Self) - where - Self: Copy, - { - (self.sin(), self.cos()) - } + fn sin_cos(self) -> (Self, Self); fn exp_m1(self) -> Self; @@ -289,6 +283,11 @@ impl F32Ext for f32 { atan2f(self, other) } + #[inline] + fn sin_cos(self) -> (Self, Self) { + sincosf(self) + } + #[inline] fn exp_m1(self) -> Self { expm1f(self) @@ -316,24 +315,17 @@ impl F32Ext for f32 { #[inline] fn asinh(self) -> Self { - if self == f32::NEG_INFINITY { - f32::NEG_INFINITY - } else { - (self + ((self * self) + 1.0).sqrt()).ln() - } + asinhf(self) } #[inline] fn acosh(self) -> Self { - match self { - x if x < 1.0 => f32::NAN, - x => (x + ((x * x) - 1.0).sqrt()).ln(), - } + acoshf(self) } #[inline] fn atanh(self) -> Self { - 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() + atanhf(self) } } @@ -401,13 +393,7 @@ pub trait F64Ext: private::Sealed + Sized { fn atan2(self, other: Self) -> Self; - #[inline] - fn sin_cos(self) -> (Self, Self) - where - Self: Copy, - { - (self.sin(), self.cos()) - } + fn sin_cos(self) -> (Self, Self); fn exp_m1(self) -> Self; @@ -571,6 +557,11 @@ impl F64Ext for f64 { atan2(self, other) } + #[inline] + fn sin_cos(self) -> (Self, Self) { + sincos(self) + } + #[inline] fn exp_m1(self) -> Self { expm1(self) @@ -598,24 +589,17 @@ impl F64Ext for f64 { #[inline] fn asinh(self) -> Self { - if self == f64::NEG_INFINITY { - f64::NEG_INFINITY - } else { - (self + ((self * self) + 1.0).sqrt()).ln() - } + asinh(self) } #[inline] fn acosh(self) -> Self { - match self { - x if x < 1.0 => f64::NAN, - x => (x + ((x * x) - 1.0).sqrt()).ln(), - } + acosh(self) } #[inline] fn atanh(self) -> Self { - 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() + atanh(self) } } From bb88bad22298777c908ea6fdc91049c0e9bb942c Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Thu, 9 May 2019 12:10:11 +0300 Subject: [PATCH 0715/4206] test several outputs --- library/compiler-builtins/libm/build.rs | 170 +++++++++++++----- .../compiler-builtins/libm/src/math/remquo.rs | 4 +- .../libm/src/math/remquof.rs | 4 +- 3 files changed, 125 insertions(+), 53 deletions(-) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 4da50a885d915..642e929ce5dba 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -27,38 +27,30 @@ mod musl_reference_tests { // These files are all internal functions or otherwise miscellaneous, not // defining a function we want to test. const IGNORED_FILES: &[&str] = &[ - "expo2.rs", + "expo2.rs", // kernel, private "fenv.rs", - "k_cos.rs", - "k_cosf.rs", - "k_expo2.rs", - "k_expo2f.rs", - "k_sin.rs", - "k_sinf.rs", - "k_tan.rs", - "k_tanf.rs", + "k_cos.rs", // kernel, private + "k_cosf.rs", // kernel, private + "k_expo2.rs", // kernel, private + "k_expo2f.rs", // kernel, private + "k_sin.rs", // kernel, private + "k_sinf.rs", // kernel, private + "k_tan.rs", // kernel, private + "k_tanf.rs", // kernel, private "mod.rs", - "rem_pio2.rs", - "rem_pio2_large.rs", - "rem_pio2f.rs", - "remquo.rs", // more than 1 result - "remquof.rs", // more than 1 result - "lgamma_r.rs", // more than 1 result - "lgammaf_r.rs", // more than 1 result - "frexp.rs", // more than 1 result - "frexpf.rs", // more than 1 result - "sincos.rs", // more than 1 result - "sincosf.rs", // more than 1 result - "modf.rs", // more than 1 result - "modff.rs", // more than 1 result - "jn.rs", // passed, but very slow - "jnf.rs", // passed, but very slow + "rem_pio2.rs", // kernel, private + "rem_pio2_large.rs", // kernel, private + "rem_pio2f.rs", // kernel, private + "sincos.rs", // more than 1 result + "sincosf.rs", // more than 1 result + "jn.rs", // passed, but very slow + "jnf.rs", // passed, but very slow ]; struct Function { name: String, args: Vec, - ret: Ty, + ret: Vec, tests: Vec, } @@ -71,7 +63,7 @@ mod musl_reference_tests { struct Test { inputs: Vec, - output: i64, + outputs: Vec, } pub fn generate() { @@ -103,7 +95,7 @@ mod musl_reference_tests { // After we have all our inputs, use the x86_64-unknown-linux-musl // target to generate the expected output. generate_test_outputs(&mut math); - + //panic!("Boo"); // ... and now that we have both inputs and expected outputs, do a bunch // of codegen to create the unit tests which we'll actually execute. generate_unit_tests(&math); @@ -125,7 +117,7 @@ mod musl_reference_tests { .collect::>(); let tail = &s[end + 1..]; let tail = eat(tail, " -> "); - let ret = parse_ty(tail.trim().split(' ').next().unwrap()); + let ret = parse_retty(tail.replace("{", "").trim()); return Function { name: name.to_string(), @@ -144,6 +136,16 @@ mod musl_reference_tests { } } + fn parse_retty(s: &str) -> Vec { + match s { + "(f32, f32)" => vec![Ty::F32, Ty::F32], + "(f32, i32)" => vec![Ty::F32, Ty::I32], + "(f64, f64)" => vec![Ty::F64, Ty::F64], + "(f64, i32)" => vec![Ty::F64, Ty::I32], + other => vec![parse_ty(other)], + } + } + fn eat<'a>(s: &'a str, prefix: &str) -> &'a str { if s.starts_with(prefix) { &s[prefix.len()..] @@ -163,7 +165,10 @@ mod musl_reference_tests { fn generate_test(args: &[Ty], rng: &mut R) -> Test { let inputs = args.iter().map(|ty| ty.gen_i64(rng)).collect(); // zero output for now since we'll generate it later - Test { inputs, output: 0 } + Test { + inputs, + outputs: vec![], + } } } @@ -192,6 +197,33 @@ mod musl_reference_tests { Ty::Bool => "i32", } } + + fn libc_pty(&self) -> &'static str { + match self { + Ty::F32 => "*mut f32", + Ty::F64 => "*mut f64", + Ty::I32 => "*mut i32", + Ty::Bool => "*mut i32", + } + } + + fn default(&self) -> &'static str { + match self { + Ty::F32 => "0_f32", + Ty::F64 => "0_f64", + Ty::I32 => "0_i32", + Ty::Bool => "false", + } + } + + fn to_i64(&self) -> &'static str { + match self { + Ty::F32 => ".to_bits() as i64", + Ty::F64 => ".to_bits() as i64", + Ty::I32 => " as i64", + Ty::Bool => " as i64", + } + } } fn generate_test_outputs(functions: &mut [Function]) { @@ -212,8 +244,11 @@ mod musl_reference_tests { for (i, arg) in function.args.iter().enumerate() { src.push_str(&format!("arg{}: {},", i, arg.libc_ty())); } + for (i, ret) in function.ret.iter().skip(1).enumerate() { + src.push_str(&format!("argret{}: {},", i, ret.libc_pty())); + } src.push_str(") -> "); - src.push_str(function.ret.libc_ty()); + src.push_str(function.ret[0].libc_ty()); src.push_str("; }"); src.push_str(&format!("static TESTS: &[[i64; {}]]", function.args.len())); @@ -229,6 +264,14 @@ mod musl_reference_tests { src.push_str("];"); src.push_str("for test in TESTS {"); + for (i, arg) in function.ret.iter().skip(1).enumerate() { + src.push_str(&format!("let mut argret{} = {};", i, arg.default())); + src.push_str(&format!( + "let argret_ptr{0} = &mut argret{0} as *mut {1};", + i, + arg.libc_ty() + )); + } src.push_str("let output = "); src.push_str(&function.name); src.push_str("("); @@ -241,17 +284,20 @@ mod musl_reference_tests { }); src.push_str(","); } + for (i, _) in function.ret.iter().skip(1).enumerate() { + src.push_str(&format!("argret_ptr{},", i)); + } src.push_str(");"); - src.push_str("let output = "); - src.push_str(match function.ret { - Ty::F32 => "output.to_bits() as i64", - Ty::F64 => "output.to_bits() as i64", - Ty::I32 => "output as i64", - Ty::Bool => "output as i64", - }); - src.push_str(";"); + src.push_str(&format!("let output = output{};", function.ret[0].to_i64())); src.push_str("result.extend_from_slice(&output.to_le_bytes());"); + for (i, ret) in function.ret.iter().skip(1).enumerate() { + src.push_str(&format!("let output{0} = argret{0}{1};", i, ret.to_i64())); + src.push_str(&format!( + "result.extend_from_slice(&output{}.to_le_bytes());", + i + )); + } src.push_str("}"); src.push_str("}"); @@ -288,8 +334,13 @@ mod musl_reference_tests { i64::from_le_bytes(exact) }); - for test in functions.iter_mut().flat_map(|f| f.tests.iter_mut()) { - test.output = results.next().unwrap(); + for f in functions.iter_mut() { + for test in f.tests.iter_mut() { + test.outputs = vec![results.next().unwrap()]; + for _ in f.ret.iter().skip(1) { + test.outputs.push(results.next().unwrap()); + } + } } assert!(results.next().is_none()); } @@ -306,8 +357,9 @@ mod musl_reference_tests { src.push_str(&function.name); src.push_str("_matches_musl() {"); src.push_str(&format!( - "static TESTS: &[([i64; {}], i64)]", - function.args.len() + "static TESTS: &[([i64; {}], [i64; {}])]", + function.args.len(), + function.ret.len(), )); src.push_str(" = &["); for test in function.tests.iter() { @@ -317,7 +369,12 @@ mod musl_reference_tests { src.push_str(","); } src.push_str("],"); - src.push_str(&test.output.to_string()); + src.push_str("["); + for val in test.outputs.iter() { + src.push_str(&val.to_string()); + src.push_str(","); + } + src.push_str("],"); src.push_str("),"); } src.push_str("];"); @@ -336,12 +393,27 @@ mod musl_reference_tests { src.push_str(","); } src.push_str(");"); - src.push_str(match function.ret { - Ty::F32 => "if _eqf(output, f32::from_bits(*expected as u32)).is_ok() { continue }", - Ty::F64 => "if _eq(output, f64::from_bits(*expected as u64)).is_ok() { continue }", - Ty::I32 => "if output as i64 == *expected { continue }", - Ty::Bool => unreachable!(), - }); + if function.ret.len() > 1 { + for (i, ret) in function.ret.iter().enumerate() { + src.push_str(&(match ret { + Ty::F32 => format!("if _eqf(output.{0}, f32::from_bits(expected[{0}] as u32)).is_ok() {{ continue }}", i), + Ty::F64 => format!("if _eq(output.{0}, f64::from_bits(expected[{0}] as u64)).is_ok() {{ continue }}", i), + Ty::I32 => format!("if output.{0} as i64 == expected[{0}] {{ continue }}", i), + Ty::Bool => unreachable!(), + })); + } + } else { + src.push_str(match function.ret[0] { + Ty::F32 => { + "if _eqf(output, f32::from_bits(expected[0] as u32)).is_ok() { continue }" + } + Ty::F64 => { + "if _eq(output, f64::from_bits(expected[0] as u64)).is_ok() { continue }" + } + Ty::I32 => "if output as i64 == expected[0] { continue }", + Ty::Bool => unreachable!(), + }); + } src.push_str( r#" diff --git a/library/compiler-builtins/libm/src/math/remquo.rs b/library/compiler-builtins/libm/src/math/remquo.rs index 507f8db347a3d..1c2ba8918cba4 100644 --- a/library/compiler-builtins/libm/src/math/remquo.rs +++ b/library/compiler-builtins/libm/src/math/remquo.rs @@ -48,7 +48,7 @@ pub fn remquo(mut x: f64, mut y: f64) -> (f64, i32) { } /* x mod y */ while ex > ey { - i = uxi - uy; + i = uxi.wrapping_sub(uy); if (i >> 63) == 0 { uxi = i; q += 1; @@ -57,7 +57,7 @@ pub fn remquo(mut x: f64, mut y: f64) -> (f64, i32) { q <<= 1; ex -= 1; } - i = uxi - uy; + i = uxi.wrapping_sub(uy); if (i >> 63) == 0 { uxi = i; q += 1; diff --git a/library/compiler-builtins/libm/src/math/remquof.rs b/library/compiler-builtins/libm/src/math/remquof.rs index 6aa4974ed3eee..871d0c7d6967d 100644 --- a/library/compiler-builtins/libm/src/math/remquof.rs +++ b/library/compiler-builtins/libm/src/math/remquof.rs @@ -47,7 +47,7 @@ pub fn remquof(mut x: f32, mut y: f32) -> (f32, i32) { } /* x mod y */ while ex > ey { - i = uxi - uy; + i = uxi.wrapping_sub(uy); if (i >> 31) == 0 { uxi = i; q += 1; @@ -56,7 +56,7 @@ pub fn remquof(mut x: f32, mut y: f32) -> (f32, i32) { q <<= 1; ex -= 1; } - i = uxi - uy; + i = uxi.wrapping_sub(uy); if (i >> 31) == 0 { uxi = i; q += 1; From 13981db1e106deb18a1a8ad5dafd47e56b471b2c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 9 May 2019 07:27:10 -0700 Subject: [PATCH 0716/4206] Move non-public functions to `pub(crate)` Remove exceptions from the test list after doing so --- library/compiler-builtins/libm/build.rs | 13 ------------- library/compiler-builtins/libm/src/math/expo2.rs | 2 +- library/compiler-builtins/libm/src/math/k_cos.rs | 2 +- library/compiler-builtins/libm/src/math/k_cosf.rs | 2 +- library/compiler-builtins/libm/src/math/k_expo2f.rs | 2 +- library/compiler-builtins/libm/src/math/k_sin.rs | 2 +- library/compiler-builtins/libm/src/math/k_sinf.rs | 2 +- library/compiler-builtins/libm/src/math/k_tan.rs | 2 +- library/compiler-builtins/libm/src/math/k_tanf.rs | 2 +- library/compiler-builtins/libm/src/math/rem_pio2.rs | 2 +- .../libm/src/math/rem_pio2_large.rs | 4 ++-- .../compiler-builtins/libm/src/math/rem_pio2f.rs | 2 +- 12 files changed, 12 insertions(+), 25 deletions(-) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 642e929ce5dba..896b41326a344 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -27,20 +27,7 @@ mod musl_reference_tests { // These files are all internal functions or otherwise miscellaneous, not // defining a function we want to test. const IGNORED_FILES: &[&str] = &[ - "expo2.rs", // kernel, private "fenv.rs", - "k_cos.rs", // kernel, private - "k_cosf.rs", // kernel, private - "k_expo2.rs", // kernel, private - "k_expo2f.rs", // kernel, private - "k_sin.rs", // kernel, private - "k_sinf.rs", // kernel, private - "k_tan.rs", // kernel, private - "k_tanf.rs", // kernel, private - "mod.rs", - "rem_pio2.rs", // kernel, private - "rem_pio2_large.rs", // kernel, private - "rem_pio2f.rs", // kernel, private "sincos.rs", // more than 1 result "sincosf.rs", // more than 1 result "jn.rs", // passed, but very slow diff --git a/library/compiler-builtins/libm/src/math/expo2.rs b/library/compiler-builtins/libm/src/math/expo2.rs index 9e60ca99422ec..ae6cc8121e000 100644 --- a/library/compiler-builtins/libm/src/math/expo2.rs +++ b/library/compiler-builtins/libm/src/math/expo2.rs @@ -3,7 +3,7 @@ use super::{combine_words, exp}; /* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */ #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn expo2(x: f64) -> f64 { +pub(crate) fn expo2(x: f64) -> f64 { /* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */ const K: i32 = 2043; let kln2 = f64::from_bits(0x40962066151add8b); diff --git a/library/compiler-builtins/libm/src/math/k_cos.rs b/library/compiler-builtins/libm/src/math/k_cos.rs index 8876fac2143cc..4687b369a6117 100644 --- a/library/compiler-builtins/libm/src/math/k_cos.rs +++ b/library/compiler-builtins/libm/src/math/k_cos.rs @@ -53,7 +53,7 @@ const C6: f64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ // any extra precision in w. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn k_cos(x: f64, y: f64) -> f64 { +pub(crate) fn k_cos(x: f64, y: f64) -> f64 { let z = x * x; let w = z * z; let r = z * (C1 + z * (C2 + z * C3)) + w * w * (C4 + z * (C5 + z * C6)); diff --git a/library/compiler-builtins/libm/src/math/k_cosf.rs b/library/compiler-builtins/libm/src/math/k_cosf.rs index 9b48e190ddd5a..79d0f238fced2 100644 --- a/library/compiler-builtins/libm/src/math/k_cosf.rs +++ b/library/compiler-builtins/libm/src/math/k_cosf.rs @@ -22,7 +22,7 @@ const C3: f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn k_cosf(x: f64) -> f32 { +pub(crate) fn k_cosf(x: f64) -> f32 { let z = x * x; let w = z * z; let r = C2 + z * C3; diff --git a/library/compiler-builtins/libm/src/math/k_expo2f.rs b/library/compiler-builtins/libm/src/math/k_expo2f.rs index 68a7a50325c1e..de850777259b3 100644 --- a/library/compiler-builtins/libm/src/math/k_expo2f.rs +++ b/library/compiler-builtins/libm/src/math/k_expo2f.rs @@ -6,7 +6,7 @@ const K: i32 = 235; /* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn k_expo2f(x: f32) -> f32 { +pub(crate) fn k_expo2f(x: f32) -> f32 { let k_ln2 = f32::from_bits(0x4322e3bc); /* note that k is odd and scale*scale overflows */ let scale = f32::from_bits(((0x7f + K / 2) as u32) << 23); diff --git a/library/compiler-builtins/libm/src/math/k_sin.rs b/library/compiler-builtins/libm/src/math/k_sin.rs index 15718c4c92650..5d2bd68aa9555 100644 --- a/library/compiler-builtins/libm/src/math/k_sin.rs +++ b/library/compiler-builtins/libm/src/math/k_sin.rs @@ -45,7 +45,7 @@ const S6: f64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ // sin(x) = x + (S1*x + (x *(r-y/2)+y)) #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn k_sin(x: f64, y: f64, iy: i32) -> f64 { +pub(crate) fn k_sin(x: f64, y: f64, iy: i32) -> f64 { let z = x * x; let w = z * z; let r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6); diff --git a/library/compiler-builtins/libm/src/math/k_sinf.rs b/library/compiler-builtins/libm/src/math/k_sinf.rs index 157fc104cc750..68fe926c21785 100644 --- a/library/compiler-builtins/libm/src/math/k_sinf.rs +++ b/library/compiler-builtins/libm/src/math/k_sinf.rs @@ -22,7 +22,7 @@ const S4: f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn k_sinf(x: f64) -> f32 { +pub(crate) fn k_sinf(x: f64) -> f32 { let z = x * x; let w = z * z; let r = S3 + z * S4; diff --git a/library/compiler-builtins/libm/src/math/k_tan.rs b/library/compiler-builtins/libm/src/math/k_tan.rs index 684e937b93ca5..ea3c386b00238 100644 --- a/library/compiler-builtins/libm/src/math/k_tan.rs +++ b/library/compiler-builtins/libm/src/math/k_tan.rs @@ -60,7 +60,7 @@ const PIO4_LO: f64 = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { +pub(crate) fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { let hx = (f64::to_bits(x) >> 32) as u32; let big = (hx & 0x7fffffff) >= 0x3FE59428; /* |x| >= 0.6744 */ if big { diff --git a/library/compiler-builtins/libm/src/math/k_tanf.rs b/library/compiler-builtins/libm/src/math/k_tanf.rs index 96a591007083d..52651378db522 100644 --- a/library/compiler-builtins/libm/src/math/k_tanf.rs +++ b/library/compiler-builtins/libm/src/math/k_tanf.rs @@ -21,7 +21,7 @@ const T: [f64; 6] = [ #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn k_tanf(x: f64, odd: bool) -> f32 { +pub(crate) fn k_tanf(x: f64, odd: bool) -> f32 { let z = x * x; /* * Split up the polynomial into small independent terms to give diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 951dd08b429e5..285663ea2c09b 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -43,7 +43,7 @@ const PIO2_3T: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ // caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn rem_pio2(x: f64) -> (i32, f64, f64) { +pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { let x1p24 = f64::from_bits(0x4170000000000000); let sign = (f64::to_bits(x) >> 63) as i32; 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 8bab485695efc..006d3e153db97 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -224,11 +224,11 @@ const PIO2: [f64; 8] = [ /// independent of the exponent of the input. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { +pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) - #[cfg(target_pointer_width = "64")] + #[cfg(all(target_pointer_width = "64", feature = "checked"))] assert!(e0 <= 16360); let nx = x.len(); diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs index 054c311841f23..af2745d1be94d 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2f.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2f.rs @@ -33,7 +33,7 @@ const PIO2_1T: f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ /// use __rem_pio2_large() for large x #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn rem_pio2f(x: f32) -> (i32, f64) { +pub(crate) fn rem_pio2f(x: f32) -> (i32, f64) { let x64 = x as f64; let mut tx: [f64; 1] = [0.]; From f3e2ed67f917820906e5b1438b1e8ce9b7a706ae Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 9 May 2019 07:52:52 -0700 Subject: [PATCH 0717/4206] Test sincos and sincosf --- library/compiler-builtins/libm/build.rs | 81 +++++++++++-------------- 1 file changed, 37 insertions(+), 44 deletions(-) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 896b41326a344..b913a3e31053c 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -28,10 +28,8 @@ mod musl_reference_tests { // defining a function we want to test. const IGNORED_FILES: &[&str] = &[ "fenv.rs", - "sincos.rs", // more than 1 result - "sincosf.rs", // more than 1 result - "jn.rs", // passed, but very slow - "jnf.rs", // passed, but very slow + "jn.rs", // passed, but very slow + "jnf.rs", // passed, but very slow ]; struct Function { @@ -228,14 +226,22 @@ mod musl_reference_tests { src.push_str("extern { fn "); src.push_str(&function.name); src.push_str("("); + + let (ret, retptr) = match function.name.as_str() { + "sincos" | "sincosf" => (None, &function.ret[..]), + _ => (Some(&function.ret[0]), &function.ret[1..]), + }; for (i, arg) in function.args.iter().enumerate() { src.push_str(&format!("arg{}: {},", i, arg.libc_ty())); } - for (i, ret) in function.ret.iter().skip(1).enumerate() { + for (i, ret) in retptr.iter().enumerate() { src.push_str(&format!("argret{}: {},", i, ret.libc_pty())); } - src.push_str(") -> "); - src.push_str(function.ret[0].libc_ty()); + src.push_str(")"); + if let Some(ty) = ret { + src.push_str(" -> "); + src.push_str(ty.libc_ty()); + } src.push_str("; }"); src.push_str(&format!("static TESTS: &[[i64; {}]]", function.args.len())); @@ -251,13 +257,8 @@ mod musl_reference_tests { src.push_str("];"); src.push_str("for test in TESTS {"); - for (i, arg) in function.ret.iter().skip(1).enumerate() { + for (i, arg) in retptr.iter().enumerate() { src.push_str(&format!("let mut argret{} = {};", i, arg.default())); - src.push_str(&format!( - "let argret_ptr{0} = &mut argret{0} as *mut {1};", - i, - arg.libc_ty() - )); } src.push_str("let output = "); src.push_str(&function.name); @@ -271,18 +272,20 @@ mod musl_reference_tests { }); src.push_str(","); } - for (i, _) in function.ret.iter().skip(1).enumerate() { - src.push_str(&format!("argret_ptr{},", i)); + for (i, _) in retptr.iter().enumerate() { + src.push_str(&format!("&mut argret{},", i)); } src.push_str(");"); - src.push_str(&format!("let output = output{};", function.ret[0].to_i64())); - src.push_str("result.extend_from_slice(&output.to_le_bytes());"); + if let Some(ty) = &ret { + src.push_str(&format!("let output = output{};", ty.to_i64())); + src.push_str("result.extend_from_slice(&output.to_le_bytes());"); + } - for (i, ret) in function.ret.iter().skip(1).enumerate() { - src.push_str(&format!("let output{0} = argret{0}{1};", i, ret.to_i64())); + for (i, ret) in retptr.iter().enumerate() { src.push_str(&format!( - "result.extend_from_slice(&output{}.to_le_bytes());", - i + "result.extend_from_slice(&(argret{}{}).to_le_bytes());", + i, + ret.to_i64(), )); } src.push_str("}"); @@ -323,10 +326,7 @@ mod musl_reference_tests { for f in functions.iter_mut() { for test in f.tests.iter_mut() { - test.outputs = vec![results.next().unwrap()]; - for _ in f.ret.iter().skip(1) { - test.outputs.push(results.next().unwrap()); - } + test.outputs = (0..f.ret.len()).map(|_| results.next().unwrap()).collect(); } } assert!(results.next().is_none()); @@ -380,26 +380,19 @@ mod musl_reference_tests { src.push_str(","); } src.push_str(");"); - if function.ret.len() > 1 { - for (i, ret) in function.ret.iter().enumerate() { - src.push_str(&(match ret { - Ty::F32 => format!("if _eqf(output.{0}, f32::from_bits(expected[{0}] as u32)).is_ok() {{ continue }}", i), - Ty::F64 => format!("if _eq(output.{0}, f64::from_bits(expected[{0}] as u64)).is_ok() {{ continue }}", i), - Ty::I32 => format!("if output.{0} as i64 == expected[{0}] {{ continue }}", i), - Ty::Bool => unreachable!(), - })); - } - } else { - src.push_str(match function.ret[0] { - Ty::F32 => { - "if _eqf(output, f32::from_bits(expected[0] as u32)).is_ok() { continue }" - } - Ty::F64 => { - "if _eq(output, f64::from_bits(expected[0] as u64)).is_ok() { continue }" - } - Ty::I32 => "if output as i64 == expected[0] { continue }", + + for (i, ret) in function.ret.iter().enumerate() { + let get = if function.ret.len() == 1 { + String::new() + } else { + format!(".{}", i) + }; + src.push_str(&(match ret { + Ty::F32 => format!("if _eqf(output{}, f32::from_bits(expected[{}] as u32)).is_ok() {{ continue }}", get, i), + Ty::F64 => format!("if _eq(output{}, f64::from_bits(expected[{}] as u64)).is_ok() {{ continue }}", get, i), + Ty::I32 => format!("if output{} as i64 == expected[{}] {{ continue }}", get, i), Ty::Bool => unreachable!(), - }); + })); } src.push_str( From fba10c51e62555d58857f15f96c2a96aa5c0d299 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 9 May 2019 07:53:21 -0700 Subject: [PATCH 0718/4206] Generate NaN and Infinity more often Make sure they come up in RNG generation of floats --- library/compiler-builtins/libm/build.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index b913a3e31053c..decb91692be37 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -159,9 +159,26 @@ mod musl_reference_tests { impl Ty { fn gen_i64(&self, r: &mut R) -> i64 { - match self { - Ty::F32 => r.gen::().to_bits().into(), - Ty::F64 => r.gen::().to_bits() as i64, + use std::f32; + use std::f64; + + return match self { + Ty::F32 => { + if r.gen_range(0, 20) < 1 { + let i = *[f32::NAN, f32::INFINITY, f32::NEG_INFINITY].choose(r).unwrap(); + i.to_bits().into() + } else { + r.gen::().to_bits().into() + } + } + Ty::F64 => { + if r.gen_range(0, 20) < 1 { + let i = *[f64::NAN, f64::INFINITY, f64::NEG_INFINITY].choose(r).unwrap(); + i.to_bits() as i64 + } else { + r.gen::().to_bits() as i64 + } + } Ty::I32 => { if r.gen_range(0, 10) < 1 { let i = *[i32::max_value(), 0, i32::min_value()].choose(r).unwrap(); @@ -171,7 +188,7 @@ mod musl_reference_tests { } } Ty::Bool => r.gen::() as i64, - } + }; } fn libc_ty(&self) -> &'static str { From 8a74ccde217846a56b8c17419e92767730ca0631 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 9 May 2019 07:58:57 -0700 Subject: [PATCH 0719/4206] Test jn and jnf --- library/compiler-builtins/libm/build.rs | 31 ++++++++++++++++++------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index decb91692be37..bf28fe23c1f31 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -28,8 +28,6 @@ mod musl_reference_tests { // defining a function we want to test. const IGNORED_FILES: &[&str] = &[ "fenv.rs", - "jn.rs", // passed, but very slow - "jnf.rs", // passed, but very slow ]; struct Function { @@ -143,15 +141,28 @@ mod musl_reference_tests { fn generate_random_tests(functions: &mut [Function], rng: &mut R) { for function in functions { for _ in 0..NTESTS { - function.tests.push(generate_test(&function.args, rng)); + function.tests.push(generate_test(function, rng)); } } - fn generate_test(args: &[Ty], rng: &mut R) -> Test { - let inputs = args.iter().map(|ty| ty.gen_i64(rng)).collect(); - // zero output for now since we'll generate it later + fn generate_test(function: &Function, rng: &mut R) -> Test { + let mut inputs = function + .args + .iter() + .map(|ty| ty.gen_i64(rng)) + .collect::>(); + + // First argument to this function appears to be a number of + // iterations, so passing in massive random numbers causes it to + // take forever to execute, so make sure we're not running random + // math code until the heat death of the universe. + if function.name == "jn" || function.name == "jnf" { + inputs[0] &= 0xffff; + } + Test { inputs, + // zero output for now since we'll generate it later outputs: vec![], } } @@ -165,7 +176,9 @@ mod musl_reference_tests { return match self { Ty::F32 => { if r.gen_range(0, 20) < 1 { - let i = *[f32::NAN, f32::INFINITY, f32::NEG_INFINITY].choose(r).unwrap(); + let i = *[f32::NAN, f32::INFINITY, f32::NEG_INFINITY] + .choose(r) + .unwrap(); i.to_bits().into() } else { r.gen::().to_bits().into() @@ -173,7 +186,9 @@ mod musl_reference_tests { } Ty::F64 => { if r.gen_range(0, 20) < 1 { - let i = *[f64::NAN, f64::INFINITY, f64::NEG_INFINITY].choose(r).unwrap(); + let i = *[f64::NAN, f64::INFINITY, f64::NEG_INFINITY] + .choose(r) + .unwrap(); i.to_bits() as i64 } else { r.gen::().to_bits() as i64 From 0dff1621e025503ad5b7c3f01472f10c68efb98a Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Thu, 9 May 2019 18:40:19 +0300 Subject: [PATCH 0720/4206] fix jn, ilogb --- library/compiler-builtins/libm/build.rs | 4 +--- library/compiler-builtins/libm/src/math/ilogb.rs | 14 +++++++------- library/compiler-builtins/libm/src/math/ilogbf.rs | 14 +++++++------- library/compiler-builtins/libm/src/math/jn.rs | 4 ++-- 4 files changed, 17 insertions(+), 19 deletions(-) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index bf28fe23c1f31..9af6dec938b17 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -26,9 +26,7 @@ mod musl_reference_tests { // These files are all internal functions or otherwise miscellaneous, not // defining a function we want to test. - const IGNORED_FILES: &[&str] = &[ - "fenv.rs", - ]; + const IGNORED_FILES: &[&str] = &["fenv.rs"]; struct Function { name: String, diff --git a/library/compiler-builtins/libm/src/math/ilogb.rs b/library/compiler-builtins/libm/src/math/ilogb.rs index 8a1289ca444d8..0a380b7efd352 100644 --- a/library/compiler-builtins/libm/src/math/ilogb.rs +++ b/library/compiler-builtins/libm/src/math/ilogb.rs @@ -1,4 +1,4 @@ -const FP_ILOGBNAN: i32 = -1 - ((!0) >> 1); +const FP_ILOGBNAN: i32 = -1 - 0x7fffffff; const FP_ILOGB0: i32 = FP_ILOGBNAN; pub fn ilogb(x: f64) -> i32 { @@ -17,15 +17,15 @@ pub fn ilogb(x: f64) -> i32 { e -= 1; i <<= 1; } - return e; - } - if e == 0x7ff { + e + } else if e == 0x7ff { force_eval!(0.0 / 0.0); if (i << 12) != 0 { - return FP_ILOGBNAN; + FP_ILOGBNAN } else { - return i32::max_value(); + i32::max_value() } + } else { + e - 0x3ff } - return e - 0x3ff; } diff --git a/library/compiler-builtins/libm/src/math/ilogbf.rs b/library/compiler-builtins/libm/src/math/ilogbf.rs index 1bf4670a8129f..b384fa4b20d36 100644 --- a/library/compiler-builtins/libm/src/math/ilogbf.rs +++ b/library/compiler-builtins/libm/src/math/ilogbf.rs @@ -1,4 +1,4 @@ -const FP_ILOGBNAN: i32 = -1 - ((!0) >> 1); +const FP_ILOGBNAN: i32 = -1 - 0x7fffffff; const FP_ILOGB0: i32 = FP_ILOGBNAN; pub fn ilogbf(x: f32) -> i32 { @@ -17,15 +17,15 @@ pub fn ilogbf(x: f32) -> i32 { e -= 1; i <<= 1; } - return e; - } - if e == 0xff { + e + } else if e == 0xff { force_eval!(0.0 / 0.0); if (i << 9) != 0 { - return FP_ILOGBNAN; + FP_ILOGBNAN } else { - return i32::max_value(); + i32::max_value() } + } else { + e - 0x7f } - return e - 0x7f; } diff --git a/library/compiler-builtins/libm/src/math/jn.rs b/library/compiler-builtins/libm/src/math/jn.rs index 70c98026685df..1be167f8461aa 100644 --- a/library/compiler-builtins/libm/src/math/jn.rs +++ b/library/compiler-builtins/libm/src/math/jn.rs @@ -54,7 +54,7 @@ pub fn jn(n: i32, mut x: f64) -> f64 { ix &= 0x7fffffff; // -lx == !lx + 1 - if (ix | (lx | (!lx + 1)) >> 31) > 0x7ff00000 { + if (ix | (lx | ((!lx).wrapping_add(1))) >> 31) > 0x7ff00000 { /* nan */ return x; } @@ -268,7 +268,7 @@ pub fn yn(n: i32, x: f64) -> f64 { ix &= 0x7fffffff; // -lx == !lx + 1 - if (ix | (lx | (!lx + 1)) >> 31) > 0x7ff00000 { + if (ix | (lx | ((!lx).wrapping_add(1))) >> 31) > 0x7ff00000 { /* nan */ return x; } From f8e5ff50c53f3bb15fb3ea4d1e8e8ecc21436b48 Mon Sep 17 00:00:00 2001 From: Igor null Date: Mon, 13 May 2019 12:14:03 +0300 Subject: [PATCH 0721/4206] rem_pio2: actually return medium value for x ~<= 5pi/4 --- library/compiler-builtins/libm/src/math/rem_pio2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 285663ea2c09b..186333e570da3 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -85,7 +85,7 @@ pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { /* |x| ~<= 5pi/4 */ if (ix & 0xfffff) == 0x921fb { /* |x| ~= pi/2 or 2pi/2 */ - medium(x, ix); /* cancellation -- use medium case */ + return medium(x, ix); /* cancellation -- use medium case */ } if ix <= 0x4002d97c { /* |x| ~<= 3pi/4 */ From d58376453078ccb67e602a69eaa33724bcd9b434 Mon Sep 17 00:00:00 2001 From: Igor null Date: Mon, 13 May 2019 17:42:18 +0300 Subject: [PATCH 0722/4206] added tests near pi for rem_pio2 --- library/compiler-builtins/libm/src/math/rem_pio2.rs | 8 ++++++++ library/compiler-builtins/libm/src/math/sin.rs | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 186333e570da3..e46e6623e44f6 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -185,3 +185,11 @@ pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { } (n, ty[0], ty[1]) } + +#[test] +fn test_near_pi() { + assert_eq!(rem_pio2(3.141592025756836), (2, -6.278329573009626e-7, -2.1125998133974653e-23)); + assert_eq!(rem_pio2(3.141592033207416), (2, -6.20382377148128e-7, -2.1125998133974653e-23)); + assert_eq!(rem_pio2(3.141592144966125), (2, -5.086236681942706e-7, -2.1125998133974653e-23)); + assert_eq!(rem_pio2(3.141592979431152), (2, 3.2584135866119817e-7, -2.1125998133974653e-23)); +} diff --git a/library/compiler-builtins/libm/src/math/sin.rs b/library/compiler-builtins/libm/src/math/sin.rs index b7307441646fb..51aed88a8dbbc 100644 --- a/library/compiler-builtins/libm/src/math/sin.rs +++ b/library/compiler-builtins/libm/src/math/sin.rs @@ -77,3 +77,10 @@ pub fn sin(x: f64) -> f64 { _ => -k_cos(y0, y1), } } + +#[test] +fn test_near_pi() { + let x = f64::from_bits(0x400921fb000FD5DD); // 3.141592026217707 + let sx = f64::from_bits(0x3ea50d15ced1a4a2); // 6.273720864039205e-7 + assert_eq!(sin(x), sx); +} From 03f6b3194e50104a6bb4a50de16dd9e21d86dc99 Mon Sep 17 00:00:00 2001 From: Igor null Date: Mon, 13 May 2019 18:05:38 +0300 Subject: [PATCH 0723/4206] formatted rem_pio2 tests --- .../libm/src/math/rem_pio2.rs | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index e46e6623e44f6..536dfac3c42ce 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -188,8 +188,20 @@ pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { #[test] fn test_near_pi() { - assert_eq!(rem_pio2(3.141592025756836), (2, -6.278329573009626e-7, -2.1125998133974653e-23)); - assert_eq!(rem_pio2(3.141592033207416), (2, -6.20382377148128e-7, -2.1125998133974653e-23)); - assert_eq!(rem_pio2(3.141592144966125), (2, -5.086236681942706e-7, -2.1125998133974653e-23)); - assert_eq!(rem_pio2(3.141592979431152), (2, 3.2584135866119817e-7, -2.1125998133974653e-23)); + assert_eq!( + rem_pio2(3.141592025756836), + (2, -6.278329573009626e-7, -2.1125998133974653e-23) + ); + assert_eq!( + rem_pio2(3.141592033207416), + (2, -6.20382377148128e-7, -2.1125998133974653e-23) + ); + assert_eq!( + rem_pio2(3.141592144966125), + (2, -5.086236681942706e-7, -2.1125998133974653e-23) + ); + assert_eq!( + rem_pio2(3.141592979431152), + (2, 3.2584135866119817e-7, -2.1125998133974653e-23) + ); } From 546492b69a3e6c8302b51cdc30724a1632396dcf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 May 2019 17:57:42 +0200 Subject: [PATCH 0724/4206] don't force-on c feature when working in rustc workspace --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index a05825a6122b8..ec9fc13f20385 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -58,7 +58,7 @@ mangled-names = [] no-lang-items = [] # Only used in the compiler's build system -rustc-dep-of-std = ['c', 'compiler-builtins', 'core'] +rustc-dep-of-std = ['compiler-builtins', 'core'] [[example]] name = "intrinsics" From 7448d0fac3b7cbc208192222524936c7a1fec8dc Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 14 May 2019 09:06:43 -0700 Subject: [PATCH 0725/4206] Bump to 0.1.3 --- library/compiler-builtins/libm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 45fad8230a062..a61db5ebaf897 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -7,7 +7,7 @@ keywords = ["libm", "math"] license = "MIT OR Apache-2.0" name = "libm" repository = "https://github.com/rust-lang-nursery/libm" -version = "0.1.2" +version = "0.1.3" edition = "2018" [features] From 6ddcff1475851b9f5adbfc91709937fe4b7cc8cf Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 14 May 2019 12:26:09 -0700 Subject: [PATCH 0726/4206] Fix __divsi3 and __udivsi3 on thumbv6m targets This commit fixes a bug accidentally introduced in #285 where some lingering references remained to `#[cfg(thumbv6m)]` but this, since the historical revert, was renamed to `#[cfg(thumb_1)]`. This caused on the thumbv6m platform for the intrinsics to be accidentally omitted because the build script didn't actually compile them but the Rust code thought the C code was in use. After correcting the `#[cfg]` statements the CI configuration for the `thumb*` family of targets was all updated. The support for xargo testing was removed from `run.sh` since it had long since bitrotted, and the script was updated to simply build the intrinsics example to attempt to link for each of these targets. This in turn exposed the bug locally and allowed to confirm a fix once the `#[cfg]` statements were corrected. cc rust-lang/rust#60782 --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/azure-pipelines.yml | 20 +++----- .../ci/docker/thumbv6m-linux-eabi/Dockerfile | 10 ---- .../ci/docker/thumbv6m-none-eabi/Dockerfile | 7 +++ .../ci/docker/thumbv7em-linux-eabi/Dockerfile | 10 ---- .../docker/thumbv7em-linux-eabihf/Dockerfile | 10 ---- .../ci/docker/thumbv7em-none-eabi/Dockerfile | 7 +++ .../docker/thumbv7em-none-eabihf/Dockerfile | 7 +++ .../ci/docker/thumbv7m-linux-eabi/Dockerfile | 10 ---- .../ci/docker/thumbv7m-none-eabi/Dockerfile | 7 +++ library/compiler-builtins/ci/run-docker.sh | 1 - library/compiler-builtins/ci/run.sh | 50 +++++-------------- .../compiler-builtins/examples/intrinsics.rs | 14 +++++- library/compiler-builtins/src/int/sdiv.rs | 2 +- library/compiler-builtins/src/int/udiv.rs | 2 +- 15 files changed, 64 insertions(+), 95 deletions(-) delete mode 100644 library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile delete mode 100644 library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile delete mode 100644 library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile delete mode 100644 library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile create mode 100644 library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index a05825a6122b8..e7995915bd47c 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -62,7 +62,7 @@ rustc-dep-of-std = ['c', 'compiler-builtins', 'core'] [[example]] name = "intrinsics" -required-features = ["c", "compiler-builtins"] +required-features = ["compiler-builtins"] [workspace] members = ["testcrate"] diff --git a/library/compiler-builtins/azure-pipelines.yml b/library/compiler-builtins/azure-pipelines.yml index da3a1bb1d39f9..eac3fb5e486bb 100644 --- a/library/compiler-builtins/azure-pipelines.yml +++ b/library/compiler-builtins/azure-pipelines.yml @@ -33,18 +33,14 @@ jobs: TARGET: powerpc64-unknown-linux-gnu powerpc64le: TARGET: powerpc64le-unknown-linux-gnu - # thumbv6m: - # TARGET: thumbv6m-linux-eabi - # XARGO: 1 - # thumbv7em: - # TARGET: thumbv7em-linux-eabi - # XARGO: 1 - # thumbv7emhf: - # TARGET: thumbv7em-linux-eabihf - # XARGO: 1 - # thumbv7m: - # TARGET: thumbv7m-linux-eabi - # XARGO: 1 + thumbv6m: + TARGET: thumbv6m-none-eabi + thumbv7em: + TARGET: thumbv7em-none-eabi + thumbv7emhf: + TARGET: thumbv7em-none-eabihf + thumbv7m: + TARGET: thumbv7m-none-eabi wasm32: TARGET: wasm32-unknown-unknown ONLY_BUILD: 1 diff --git a/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile deleted file mode 100644 index 789bdf4e46cc9..0000000000000 --- a/library/compiler-builtins/ci/docker/thumbv6m-linux-eabi/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM ubuntu:18.04 -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static -RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ - sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin -ENV AR_thumbv6m_linux_eabi=arm-none-eabi-ar \ - CARGO_TARGET_THUMBV6M_LINUX_EABI_LINKER=arm-none-eabi-gcc \ - CARGO_TARGET_THUMBV6M_LINUX_EABI_RUNNER=qemu-arm-static \ - CC_thumbv6m_linux_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile new file mode 100644 index 0000000000000..04d4f4429051b --- /dev/null +++ b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -0,0 +1,7 @@ +FROM ubuntu:18.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-none-eabi \ + libnewlib-arm-none-eabi +ENV XARGO=1 diff --git a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile deleted file mode 100644 index c6ce273c875d3..0000000000000 --- a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabi/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM ubuntu:18.04 -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static -RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ - sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin -ENV AR_thumbv7em_linux_eabi=arm-none-eabi-ar \ - CARGO_TARGET_THUMBV7EM_LINUX_EABI_LINKER=arm-none-eabi-gcc \ - CARGO_TARGET_THUMBV7EM_LINUX_EABI_RUNNER=qemu-arm-static \ - CC_thumbv7em_linux_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile deleted file mode 100644 index c7518aaca8489..0000000000000 --- a/library/compiler-builtins/ci/docker/thumbv7em-linux-eabihf/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM ubuntu:18.04 -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static -RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ - sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin -ENV AR_thumbv7em_linux_eabihf=arm-none-eabi-ar \ - CARGO_TARGET_THUMBV7EM_LINUX_EABIHF_LINKER=arm-none-eabi-gcc \ - CARGO_TARGET_THUMBV7EM_LINUX_EABIHF_RUNNER=qemu-arm-static \ - CC_thumbv7em_linux_eabihf=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile new file mode 100644 index 0000000000000..04d4f4429051b --- /dev/null +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -0,0 +1,7 @@ +FROM ubuntu:18.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-none-eabi \ + libnewlib-arm-none-eabi +ENV XARGO=1 diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile new file mode 100644 index 0000000000000..04d4f4429051b --- /dev/null +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -0,0 +1,7 @@ +FROM ubuntu:18.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-none-eabi \ + libnewlib-arm-none-eabi +ENV XARGO=1 diff --git a/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile deleted file mode 100644 index c907109413914..0000000000000 --- a/library/compiler-builtins/ci/docker/thumbv7m-linux-eabi/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM ubuntu:18.04 -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static -RUN curl -LSfs https://japaric.github.io/trust/install.sh | \ - sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin -ENV AR_thumbv7m_linux_eabi=arm-none-eabi-ar \ - CARGO_TARGET_THUMBV7M_LINUX_EABI_LINKER=arm-none-eabi-gcc \ - CARGO_TARGET_THUMBV7M_LINUX_EABI_RUNNER=qemu-arm-static \ - CC_thumbv7m_linux_eabi=arm-none-eabi-gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile new file mode 100644 index 0000000000000..04d4f4429051b --- /dev/null +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -0,0 +1,7 @@ +FROM ubuntu:18.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-none-eabi \ + libnewlib-arm-none-eabi +ENV XARGO=1 diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index bed84ed81f6fc..ddb970c1b4a69 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -18,7 +18,6 @@ run() { --user $(id -u):$(id -g) \ -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ - -e XARGO \ -v $HOME/.cargo:/cargo \ -v `pwd`/target:/target \ -v `pwd`:/checkout:ro \ diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 27e2de22f70f3..ae32806ece8ea 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -1,53 +1,24 @@ set -ex -# FIXME(japarix/xargo#186) this shouldn't be necessary -export RUST_TARGET_PATH=`pwd` - cargo=cargo -if [ "$XARGO" = "1" ]; then - cargo=xargo -fi - -INTRINSICS_FEATURES="c" - -# Some architectures like ARM apparently seem to require the `mem` feature -# enabled to successfully compile the `intrinsics` example, and... we're not -# sure why! -if [ -z "$INTRINSICS_FAILS_WITH_MEM_FEATURE" ]; then - INTRINSICS_FEATURES="$INTRINSICS_FEATURES mem" -fi # Test our implementation if [ "$XARGO" = "1" ]; then - run="xargo test --manifest-path testcrate/Cargo.toml --target $1" - for t in $(ls testcrate/tests); do - t=${t%.rs} - - RUSTFLAGS="-C debug-assertions=no -C lto" \ - CARGO_INCREMENTAL=0 \ - $run --test $t --no-default-features --features 'mem c' --no-run - qemu-arm-static target/${1}/debug/$t-* - done - - for t in $(ls testcrate/tests); do - t=${t%.rs} - RUSTFLAGS="-C lto" \ - CARGO_INCREMENTAL=0 \ - $run --test $t --no-default-features --features 'mem c' --no-run --release - qemu-arm-static target/${1}/release/$t-* - done + # FIXME: currently these tests don't work... + echo nothing to do else run="cargo test --manifest-path testcrate/Cargo.toml --target $1" $run $run --release $run --features c $run --features c --release - cargo build --target $1 - cargo build --target $1 --release - cargo build --target $1 --features c - cargo build --target $1 --release --features c fi +cargo build --target $1 +cargo build --target $1 --release +cargo build --target $1 --features c +cargo build --target $1 --release --features c + PREFIX=$(echo $1 | sed -e 's/unknown-//')- case $1 in armv7-*) @@ -101,8 +72,11 @@ done rm -f $path # Verify that we haven't drop any intrinsic/symbol -RUSTFLAGS="-C debug-assertions=no" \ - $cargo build --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics -v +build_intrinsics="$cargo build --target $1 -v --example intrinsics" +RUSTFLAGS="-C debug-assertions=no" $build_intrinsics +RUSTFLAGS="-C debug-assertions=no" $build_intrinsics --release +RUSTFLAGS="-C debug-assertions=no" $build_intrinsics --features c +RUSTFLAGS="-C debug-assertions=no" $build_intrinsics --features c --release # Verify that there are no undefined symbols to `panic` within our # implementations diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index ccd701569d902..8de108d99b456 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -27,7 +27,14 @@ extern {} mod intrinsics { // trunccdfsf2 pub fn aeabi_d2f(x: f64) -> f32 { - x as f32 + // This is only implemented in C currently, so only test it there. + #[cfg(feature = "c")] + return x as f32; + #[cfg(not(feature = "c"))] + { + drop(x); + 0.0 + } } // fixdfsi @@ -263,6 +270,10 @@ mod intrinsics { pub fn modti3(a: i128, b: i128) -> i128 { a % b } + + pub fn udivsi3(a: u32, b: u32) -> u32 { + a / b + } } fn run() { @@ -325,6 +336,7 @@ fn run() { bb(umodti3(bb(2), bb(2))); bb(divti3(bb(2), bb(2))); bb(modti3(bb(2), bb(2))); + bb(udivsi3(bb(2), bb(2))); something_with_a_dtor(&|| assert_eq!(bb(1), 1)); diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index d7ae71ab29390..82262a4412de8 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -57,7 +57,7 @@ impl Divmod for i32 {} impl Divmod for i64 {} intrinsics! { - #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), not(thumbv6m)))] + #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), not(thumb_1)))] #[arm_aeabi_alias = __aeabi_idiv] pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 { a.div(b) diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 7b7f5b44dfaab..8837126deef8b 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -154,7 +154,7 @@ macro_rules! udivmod_inner { intrinsics! { #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), - not(thumbv6m)))] + not(thumb_1)))] #[arm_aeabi_alias = __aeabi_uidiv] /// Returns `n / d` pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { From 9886a163b3d49e5523eed904d6803465ad3fecc1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 14 May 2019 14:29:29 -0700 Subject: [PATCH 0727/4206] Don't compile C code on riscv targets This fixes a longstanding bug in compiler-builtins where C code was compiled for the riscv targets but when distributed in rust-lang/rust all the C code was actually compiled for x86_64 since there is no configured C compiler for riscv. This was exposed by #286 by accident but the underlying cause was somewhat unrelated. For now we forcibly disable C code for riscv targets, and when the C compiler story is sorted out in rust-lang/rust and with `cc-rs` we can reenable. For now just use all the Rust definitions. cc rust-lang/rust#60747 --- library/compiler-builtins/build.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 27dac6026478d..4fc0adbeda615 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -37,8 +37,15 @@ fn main() { // build anything and we rely on the upstream implementation of compiler-rt // functions if !cfg!(feature = "mangled-names") && cfg!(feature = "c") { - // Don't use C compiler for bitcode-only wasm and nvptx - if !target.contains("wasm32") && !target.contains("nvptx") { + // Don't use a C compiler for these targets: + // + // * wasm32 - clang 8 for wasm is somewhat hard to come by and it's + // unlikely that the C is really that much better than our own Rust. + // * nvptx - everything is bitcode, not compatible with mixed C/Rust + // * riscv - the rust-lang/rust distribution container doesn't have a C + // compiler nor is cc-rs ready for compilation to riscv (at this + // time). This can probably be removed in the future + if !target.contains("wasm32") && !target.contains("nvptx") && !target.starts_with("riscv") { #[cfg(feature = "c")] c::compile(&llvm_target); println!("cargo:rustc-cfg=use_c"); From b2cfc3a4f111d3b944e9c1884d7324bef3607e6b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 14 May 2019 14:33:08 -0700 Subject: [PATCH 0728/4206] Run rustfmt over everything --- library/compiler-builtins/build.rs | 413 +++++---- .../compiler-builtins/examples/intrinsics.rs | 10 +- library/compiler-builtins/src/arm_linux.rs | 98 ++- library/compiler-builtins/src/float/add.rs | 50 +- library/compiler-builtins/src/float/cmp.rs | 67 +- library/compiler-builtins/src/float/conv.rs | 74 +- library/compiler-builtins/src/float/div.rs | 6 +- library/compiler-builtins/src/float/extend.rs | 7 +- library/compiler-builtins/src/float/mod.rs | 46 +- library/compiler-builtins/src/float/mul.rs | 2 +- library/compiler-builtins/src/float/pow.rs | 2 +- library/compiler-builtins/src/float/sub.rs | 4 +- library/compiler-builtins/src/int/addsub.rs | 23 +- library/compiler-builtins/src/int/mod.rs | 50 +- library/compiler-builtins/src/int/mul.rs | 9 +- library/compiler-builtins/src/int/sdiv.rs | 3 +- library/compiler-builtins/src/int/shift.rs | 35 +- library/compiler-builtins/src/lib.rs | 34 +- library/compiler-builtins/src/macros.rs | 2 +- library/compiler-builtins/src/mem.rs | 10 +- library/compiler-builtins/src/probestack.rs | 4 +- library/compiler-builtins/testcrate/build.rs | 814 +++++++++++------- .../compiler-builtins/testcrate/src/lib.rs | 2 +- .../testcrate/tests/aeabi_memclr.rs | 10 +- .../testcrate/tests/aeabi_memcpy.rs | 10 +- .../testcrate/tests/aeabi_memset.rs | 82 +- .../testcrate/tests/count_leading_zeros.rs | 30 +- .../testcrate/tests/generated.rs | 30 +- 28 files changed, 1105 insertions(+), 822 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 4fc0adbeda615..a8301afa95fcb 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -22,8 +22,9 @@ fn main() { // Forcibly enable memory intrinsics on wasm32 & SGX as we don't have a libc to // provide them. - if (target.contains("wasm32") && !target.contains("wasi")) || - (target.contains("sgx") && target.contains("fortanix")) { + if (target.contains("wasm32") && !target.contains("wasi")) + || (target.contains("sgx") && target.contains("fortanix")) + { println!("cargo:rustc-cfg=feature=\"mem\""); } @@ -85,7 +86,9 @@ mod c { impl Sources { fn new() -> Sources { - Sources { map: BTreeMap::new() } + Sources { + map: BTreeMap::new(), + } } fn extend(&mut self, sources: &[&'static str]) { @@ -151,163 +154,144 @@ mod c { } let mut sources = Sources::new(); - sources.extend( - &[ - "absvdi2.c", - "absvsi2.c", - "addvdi3.c", - "addvsi3.c", - "apple_versioning.c", - "clzdi2.c", - "clzsi2.c", - "cmpdi2.c", - "ctzdi2.c", - "ctzsi2.c", - "divdc3.c", - "divsc3.c", - "divxc3.c", - "extendhfsf2.c", - "int_util.c", - "muldc3.c", - "mulsc3.c", - "mulvdi3.c", - "mulvsi3.c", - "mulxc3.c", - "negdf2.c", - "negdi2.c", - "negsf2.c", - "negvdi2.c", - "negvsi2.c", - "paritydi2.c", - "paritysi2.c", - "popcountdi2.c", - "popcountsi2.c", - "powixf2.c", - "subvdi3.c", - "subvsi3.c", - "truncdfhf2.c", - "truncdfsf2.c", - "truncsfhf2.c", - "ucmpdi2.c", - ], - ); + sources.extend(&[ + "absvdi2.c", + "absvsi2.c", + "addvdi3.c", + "addvsi3.c", + "apple_versioning.c", + "clzdi2.c", + "clzsi2.c", + "cmpdi2.c", + "ctzdi2.c", + "ctzsi2.c", + "divdc3.c", + "divsc3.c", + "divxc3.c", + "extendhfsf2.c", + "int_util.c", + "muldc3.c", + "mulsc3.c", + "mulvdi3.c", + "mulvsi3.c", + "mulxc3.c", + "negdf2.c", + "negdi2.c", + "negsf2.c", + "negvdi2.c", + "negvsi2.c", + "paritydi2.c", + "paritysi2.c", + "popcountdi2.c", + "popcountsi2.c", + "powixf2.c", + "subvdi3.c", + "subvsi3.c", + "truncdfhf2.c", + "truncdfsf2.c", + "truncsfhf2.c", + "ucmpdi2.c", + ]); // When compiling in rustbuild (the rust-lang/rust repo) this library // also needs to satisfy intrinsics that jemalloc or C in general may // need, so include a few more that aren't typically needed by // LLVM/Rust. if cfg!(feature = "rustbuild") { - sources.extend(&[ - "ffsdi2.c", - ]); + sources.extend(&["ffsdi2.c"]); } // On iOS and 32-bit OSX these are all just empty intrinsics, no need to // include them. if target_os != "ios" && (target_vendor != "apple" || target_arch != "x86") { - sources.extend( - &[ - "absvti2.c", - "addvti3.c", - "clzti2.c", - "cmpti2.c", - "ctzti2.c", - "ffsti2.c", - "mulvti3.c", - "negti2.c", - "negvti2.c", - "parityti2.c", - "popcountti2.c", - "subvti3.c", - "ucmpti2.c", - ], - ); + sources.extend(&[ + "absvti2.c", + "addvti3.c", + "clzti2.c", + "cmpti2.c", + "ctzti2.c", + "ffsti2.c", + "mulvti3.c", + "negti2.c", + "negvti2.c", + "parityti2.c", + "popcountti2.c", + "subvti3.c", + "ucmpti2.c", + ]); } if target_vendor == "apple" { - sources.extend( - &[ - "atomic_flag_clear.c", - "atomic_flag_clear_explicit.c", - "atomic_flag_test_and_set.c", - "atomic_flag_test_and_set_explicit.c", - "atomic_signal_fence.c", - "atomic_thread_fence.c", - ], - ); + sources.extend(&[ + "atomic_flag_clear.c", + "atomic_flag_clear_explicit.c", + "atomic_flag_test_and_set.c", + "atomic_flag_test_and_set_explicit.c", + "atomic_signal_fence.c", + "atomic_thread_fence.c", + ]); } if target_env == "msvc" { if target_arch == "x86_64" { - sources.extend( - &[ - "x86_64/floatdisf.c", - "x86_64/floatdixf.c", - ], - ); + sources.extend(&["x86_64/floatdisf.c", "x86_64/floatdixf.c"]); } } else { // None of these seem to be used on x86_64 windows, and they've all // got the wrong ABI anyway, so we want to avoid them. if target_os != "windows" { if target_arch == "x86_64" { - sources.extend( - &[ - "x86_64/floatdisf.c", - "x86_64/floatdixf.c", - "x86_64/floatundidf.S", - "x86_64/floatundisf.S", - "x86_64/floatundixf.S", - ], - ); + sources.extend(&[ + "x86_64/floatdisf.c", + "x86_64/floatdixf.c", + "x86_64/floatundidf.S", + "x86_64/floatundisf.S", + "x86_64/floatundixf.S", + ]); } } if target_arch == "x86" { - sources.extend( - &[ - "i386/ashldi3.S", - "i386/ashrdi3.S", - "i386/divdi3.S", - "i386/floatdidf.S", - "i386/floatdisf.S", - "i386/floatdixf.S", - "i386/floatundidf.S", - "i386/floatundisf.S", - "i386/floatundixf.S", - "i386/lshrdi3.S", - "i386/moddi3.S", - "i386/muldi3.S", - "i386/udivdi3.S", - "i386/umoddi3.S", - ], - ); + sources.extend(&[ + "i386/ashldi3.S", + "i386/ashrdi3.S", + "i386/divdi3.S", + "i386/floatdidf.S", + "i386/floatdisf.S", + "i386/floatdixf.S", + "i386/floatundidf.S", + "i386/floatundisf.S", + "i386/floatundixf.S", + "i386/lshrdi3.S", + "i386/moddi3.S", + "i386/muldi3.S", + "i386/udivdi3.S", + "i386/umoddi3.S", + ]); } } if target_arch == "arm" && target_os != "ios" && target_env != "msvc" { - sources.extend( - &[ - "arm/aeabi_div0.c", - "arm/aeabi_drsub.c", - "arm/aeabi_frsub.c", - "arm/bswapdi2.S", - "arm/bswapsi2.S", - "arm/clzdi2.S", - "arm/clzsi2.S", - "arm/divmodsi4.S", - "arm/divsi3.S", - "arm/modsi3.S", - "arm/switch16.S", - "arm/switch32.S", - "arm/switch8.S", - "arm/switchu8.S", - "arm/sync_synchronize.S", - "arm/udivmodsi4.S", - "arm/udivsi3.S", - "arm/umodsi3.S", - ], - ); + sources.extend(&[ + "arm/aeabi_div0.c", + "arm/aeabi_drsub.c", + "arm/aeabi_frsub.c", + "arm/bswapdi2.S", + "arm/bswapsi2.S", + "arm/clzdi2.S", + "arm/clzsi2.S", + "arm/divmodsi4.S", + "arm/divsi3.S", + "arm/modsi3.S", + "arm/switch16.S", + "arm/switch32.S", + "arm/switch8.S", + "arm/switchu8.S", + "arm/sync_synchronize.S", + "arm/udivmodsi4.S", + "arm/udivsi3.S", + "arm/umodsi3.S", + ]); if target_os == "freebsd" { sources.extend(&["clear_cache.c"]); @@ -316,100 +300,89 @@ mod c { // First of all aeabi_cdcmp and aeabi_cfcmp are never called by LLVM. // Second are little-endian only, so build fail on big-endian targets. // Temporally workaround: exclude these files for big-endian targets. - if !llvm_target[0].starts_with("thumbeb") && - !llvm_target[0].starts_with("armeb") { - sources.extend( - &[ - "arm/aeabi_cdcmp.S", - "arm/aeabi_cdcmpeq_check_nan.c", - "arm/aeabi_cfcmp.S", - "arm/aeabi_cfcmpeq_check_nan.c", - ], - ); + if !llvm_target[0].starts_with("thumbeb") && !llvm_target[0].starts_with("armeb") { + sources.extend(&[ + "arm/aeabi_cdcmp.S", + "arm/aeabi_cdcmpeq_check_nan.c", + "arm/aeabi_cfcmp.S", + "arm/aeabi_cfcmpeq_check_nan.c", + ]); } } if llvm_target[0] == "armv7" { - sources.extend( - &[ - "arm/sync_fetch_and_add_4.S", - "arm/sync_fetch_and_add_8.S", - "arm/sync_fetch_and_and_4.S", - "arm/sync_fetch_and_and_8.S", - "arm/sync_fetch_and_max_4.S", - "arm/sync_fetch_and_max_8.S", - "arm/sync_fetch_and_min_4.S", - "arm/sync_fetch_and_min_8.S", - "arm/sync_fetch_and_nand_4.S", - "arm/sync_fetch_and_nand_8.S", - "arm/sync_fetch_and_or_4.S", - "arm/sync_fetch_and_or_8.S", - "arm/sync_fetch_and_sub_4.S", - "arm/sync_fetch_and_sub_8.S", - "arm/sync_fetch_and_umax_4.S", - "arm/sync_fetch_and_umax_8.S", - "arm/sync_fetch_and_umin_4.S", - "arm/sync_fetch_and_umin_8.S", - "arm/sync_fetch_and_xor_4.S", - "arm/sync_fetch_and_xor_8.S", - ], - ); + sources.extend(&[ + "arm/sync_fetch_and_add_4.S", + "arm/sync_fetch_and_add_8.S", + "arm/sync_fetch_and_and_4.S", + "arm/sync_fetch_and_and_8.S", + "arm/sync_fetch_and_max_4.S", + "arm/sync_fetch_and_max_8.S", + "arm/sync_fetch_and_min_4.S", + "arm/sync_fetch_and_min_8.S", + "arm/sync_fetch_and_nand_4.S", + "arm/sync_fetch_and_nand_8.S", + "arm/sync_fetch_and_or_4.S", + "arm/sync_fetch_and_or_8.S", + "arm/sync_fetch_and_sub_4.S", + "arm/sync_fetch_and_sub_8.S", + "arm/sync_fetch_and_umax_4.S", + "arm/sync_fetch_and_umax_8.S", + "arm/sync_fetch_and_umin_4.S", + "arm/sync_fetch_and_umin_8.S", + "arm/sync_fetch_and_xor_4.S", + "arm/sync_fetch_and_xor_8.S", + ]); } if llvm_target.last().unwrap().ends_with("eabihf") { - if !llvm_target[0].starts_with("thumbv7em") && - !llvm_target[0].starts_with("thumbv8m.main") { + if !llvm_target[0].starts_with("thumbv7em") + && !llvm_target[0].starts_with("thumbv8m.main") + { // The FPU option chosen for these architectures in cc-rs, ie: // -mfpu=fpv4-sp-d16 for thumbv7em // -mfpu=fpv5-sp-d16 for thumbv8m.main // do not support double precision floating points conversions so the files // that include such instructions are not included for these targets. - sources.extend( - &[ - "arm/fixdfsivfp.S", - "arm/fixunsdfsivfp.S", - "arm/floatsidfvfp.S", - "arm/floatunssidfvfp.S", - ], - ); + sources.extend(&[ + "arm/fixdfsivfp.S", + "arm/fixunsdfsivfp.S", + "arm/floatsidfvfp.S", + "arm/floatunssidfvfp.S", + ]); } - sources.extend( - &[ - "arm/fixsfsivfp.S", - "arm/fixunssfsivfp.S", - "arm/floatsisfvfp.S", - "arm/floatunssisfvfp.S", - "arm/floatunssisfvfp.S", - "arm/restore_vfp_d8_d15_regs.S", - "arm/save_vfp_d8_d15_regs.S", - "arm/negdf2vfp.S", - "arm/negsf2vfp.S", - ] - ); - + sources.extend(&[ + "arm/fixsfsivfp.S", + "arm/fixunssfsivfp.S", + "arm/floatsisfvfp.S", + "arm/floatunssisfvfp.S", + "arm/floatunssisfvfp.S", + "arm/restore_vfp_d8_d15_regs.S", + "arm/save_vfp_d8_d15_regs.S", + "arm/negdf2vfp.S", + "arm/negsf2vfp.S", + ]); } if target_arch == "aarch64" { - sources.extend( - &[ - "comparetf2.c", - "extenddftf2.c", - "extendsftf2.c", - "fixtfdi.c", - "fixtfsi.c", - "fixtfti.c", - "fixunstfdi.c", - "fixunstfsi.c", - "fixunstfti.c", - "floatditf.c", - "floatsitf.c", - "floatunditf.c", - "floatunsitf.c", - "trunctfdf2.c", - "trunctfsf2.c", - ], - ); + sources.extend(&[ + "comparetf2.c", + "extenddftf2.c", + "extendsftf2.c", + "fixtfdi.c", + "fixtfsi.c", + "fixtfti.c", + "fixunstfdi.c", + "fixunstfsi.c", + "fixunstfti.c", + "floatditf.c", + "floatsitf.c", + "floatunditf.c", + "floatunsitf.c", + "trunctfdf2.c", + "trunctfsf2.c", + ]); if target_os != "windows" { sources.extend(&["multc3.c"]); @@ -418,22 +391,20 @@ mod c { // Remove the assembly implementations that won't compile for the target if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" { - sources.remove( - &[ - "clzdi2", - "clzsi2", - "divmodsi4", - "divsi3", - "modsi3", - "switch16", - "switch32", - "switch8", - "switchu8", - "udivmodsi4", - "udivsi3", - "umodsi3", - ], - ); + sources.remove(&[ + "clzdi2", + "clzsi2", + "divmodsi4", + "divsi3", + "modsi3", + "switch16", + "switch32", + "switch8", + "switchu8", + "udivmodsi4", + "udivsi3", + "umodsi3", + ]); // But use some generic implementations where possible sources.extend(&["clzdi2.c", "clzsi2.c"]) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 8de108d99b456..3debffa450a38 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -17,7 +17,7 @@ extern crate panic_handler; #[cfg(all(not(thumb), not(windows)))] #[link(name = "c")] -extern {} +extern "C" {} // Every function in this module maps will be lowered to an intrinsic by LLVM, if the platform // doesn't have native support for the operation used in the function. ARM has a naming convention @@ -340,11 +340,13 @@ fn run() { something_with_a_dtor(&|| assert_eq!(bb(1), 1)); - extern { + extern "C" { fn rust_begin_unwind(); } // if bb(false) { - unsafe { rust_begin_unwind(); } + unsafe { + rust_begin_unwind(); + } // } } @@ -377,7 +379,7 @@ pub fn _start() -> ! { #[cfg(windows)] #[link(name = "kernel32")] #[link(name = "msvcrt")] -extern {} +extern "C" {} // ARM targets need these symbols #[no_mangle] diff --git a/library/compiler-builtins/src/arm_linux.rs b/library/compiler-builtins/src/arm_linux.rs index 5ed379fa1e253..e710c1ab98a59 100644 --- a/library/compiler-builtins/src/arm_linux.rs +++ b/library/compiler-builtins/src/arm_linux.rs @@ -4,11 +4,11 @@ use core::mem; // Kernel-provided user-mode helper functions: // https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt unsafe fn __kuser_cmpxchg(oldval: u32, newval: u32, ptr: *mut u32) -> bool { - let f: extern "C" fn (u32, u32, *mut u32) -> u32 = mem::transmute(0xffff0fc0u32); + let f: extern "C" fn(u32, u32, *mut u32) -> u32 = mem::transmute(0xffff0fc0u32); f(oldval, newval, ptr) == 0 } unsafe fn __kuser_memory_barrier() { - let f: extern "C" fn () = mem::transmute(0xffff0fa0u32); + let f: extern "C" fn() = mem::transmute(0xffff0fa0u32); f(); } @@ -94,7 +94,7 @@ macro_rules! atomic_rmw { pub unsafe extern "C" fn $name(ptr: *mut $ty, val: $ty) -> $ty { atomic_rmw(ptr, |x| $op(x as $ty, val) as u32) as $ty } - } + }; } macro_rules! atomic_cmpxchg { ($name:ident, $ty:ty) => { @@ -102,16 +102,20 @@ macro_rules! atomic_cmpxchg { pub unsafe extern "C" fn $name(ptr: *mut $ty, oldval: $ty, newval: $ty) -> $ty { atomic_cmpxchg(ptr, oldval as u32, newval as u32) as $ty } - } + }; } atomic_rmw!(__sync_fetch_and_add_1, u8, |a: u8, b: u8| a.wrapping_add(b)); -atomic_rmw!(__sync_fetch_and_add_2, u16, |a: u16, b: u16| a.wrapping_add(b)); -atomic_rmw!(__sync_fetch_and_add_4, u32, |a: u32, b: u32| a.wrapping_add(b)); +atomic_rmw!(__sync_fetch_and_add_2, u16, |a: u16, b: u16| a + .wrapping_add(b)); +atomic_rmw!(__sync_fetch_and_add_4, u32, |a: u32, b: u32| a + .wrapping_add(b)); atomic_rmw!(__sync_fetch_and_sub_1, u8, |a: u8, b: u8| a.wrapping_sub(b)); -atomic_rmw!(__sync_fetch_and_sub_2, u16, |a: u16, b: u16| a.wrapping_sub(b)); -atomic_rmw!(__sync_fetch_and_sub_4, u32, |a: u32, b: u32| a.wrapping_sub(b)); +atomic_rmw!(__sync_fetch_and_sub_2, u16, |a: u16, b: u16| a + .wrapping_sub(b)); +atomic_rmw!(__sync_fetch_and_sub_4, u32, |a: u32, b: u32| a + .wrapping_sub(b)); atomic_rmw!(__sync_fetch_and_and_1, u8, |a: u8, b: u8| a & b); atomic_rmw!(__sync_fetch_and_and_2, u16, |a: u16, b: u16| a & b); @@ -129,21 +133,69 @@ atomic_rmw!(__sync_fetch_and_nand_1, u8, |a: u8, b: u8| !(a & b)); atomic_rmw!(__sync_fetch_and_nand_2, u16, |a: u16, b: u16| !(a & b)); atomic_rmw!(__sync_fetch_and_nand_4, u32, |a: u32, b: u32| !(a & b)); -atomic_rmw!(__sync_fetch_and_max_1, i8, |a: i8, b: i8| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_max_2, i16, |a: i16, b: i16| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_max_4, i32, |a: i32, b: i32| if a > b { a } else { b }); - -atomic_rmw!(__sync_fetch_and_umax_1, u8, |a: u8, b: u8| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umax_2, u16, |a: u16, b: u16| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umax_4, u32, |a: u32, b: u32| if a > b { a } else { b }); - -atomic_rmw!(__sync_fetch_and_min_1, i8, |a: i8, b: i8| if a < b { a } else { b }); -atomic_rmw!(__sync_fetch_and_min_2, i16, |a: i16, b: i16| if a < b { a } else { b }); -atomic_rmw!(__sync_fetch_and_min_4, i32, |a: i32, b: i32| if a < b { a } else { b }); - -atomic_rmw!(__sync_fetch_and_umin_1, u8, |a: u8, b: u8| if a < b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umin_2, u16, |a: u16, b: u16| if a < b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umin_4, u32, |a: u32, b: u32| if a < b { a } else { b }); +atomic_rmw!(__sync_fetch_and_max_1, i8, |a: i8, b: i8| if a > b { + a +} else { + b +}); +atomic_rmw!(__sync_fetch_and_max_2, i16, |a: i16, b: i16| if a > b { + a +} else { + b +}); +atomic_rmw!(__sync_fetch_and_max_4, i32, |a: i32, b: i32| if a > b { + a +} else { + b +}); + +atomic_rmw!(__sync_fetch_and_umax_1, u8, |a: u8, b: u8| if a > b { + a +} else { + b +}); +atomic_rmw!(__sync_fetch_and_umax_2, u16, |a: u16, b: u16| if a > b { + a +} else { + b +}); +atomic_rmw!(__sync_fetch_and_umax_4, u32, |a: u32, b: u32| if a > b { + a +} else { + b +}); + +atomic_rmw!(__sync_fetch_and_min_1, i8, |a: i8, b: i8| if a < b { + a +} else { + b +}); +atomic_rmw!(__sync_fetch_and_min_2, i16, |a: i16, b: i16| if a < b { + a +} else { + b +}); +atomic_rmw!(__sync_fetch_and_min_4, i32, |a: i32, b: i32| if a < b { + a +} else { + b +}); + +atomic_rmw!(__sync_fetch_and_umin_1, u8, |a: u8, b: u8| if a < b { + a +} else { + b +}); +atomic_rmw!(__sync_fetch_and_umin_2, u16, |a: u16, b: u16| if a < b { + a +} else { + b +}); +atomic_rmw!(__sync_fetch_and_umin_4, u32, |a: u32, b: u32| if a < b { + a +} else { + b +}); atomic_rmw!(__sync_lock_test_and_set_1, u8, |_: u8, b: u8| b); atomic_rmw!(__sync_lock_test_and_set_2, u16, |_: u16, b: u16| b); diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 2b6ada81ddc79..e8b9f9e774272 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -1,8 +1,9 @@ -use int::{Int, CastInto}; use float::Float; +use int::{CastInto, Int}; /// Returns `a + b` -fn add(a: F, b: F) -> F where +fn add(a: F, b: F) -> F +where u32: CastInto, F::Int: CastInto, i32: CastInto, @@ -11,18 +12,18 @@ fn add(a: F, b: F) -> F where let one = F::Int::ONE; let zero = F::Int::ZERO; - let bits = F::BITS.cast(); + let bits = F::BITS.cast(); let significand_bits = F::SIGNIFICAND_BITS; - let max_exponent = F::EXPONENT_MAX; + let max_exponent = F::EXPONENT_MAX; - let implicit_bit = F::IMPLICIT_BIT; + let implicit_bit = F::IMPLICIT_BIT; let significand_mask = F::SIGNIFICAND_MASK; - let sign_bit = F::SIGN_MASK as F::Int; - let abs_mask = sign_bit - one; - let exponent_mask = F::EXPONENT_MASK; - let inf_rep = exponent_mask; - let quiet_bit = implicit_bit >> 1; - let qnan_rep = exponent_mask | quiet_bit; + let sign_bit = F::SIGN_MASK as F::Int; + let abs_mask = sign_bit - one; + let exponent_mask = F::EXPONENT_MASK; + let inf_rep = exponent_mask; + let quiet_bit = implicit_bit >> 1; + let qnan_rep = exponent_mask | quiet_bit; let mut a_rep = a.repr(); let mut b_rep = b.repr(); @@ -30,8 +31,7 @@ fn add(a: F, b: F) -> F where let b_abs = b_rep & abs_mask; // Detect if a or b is zero, infinity, or NaN. - if a_abs.wrapping_sub(one) >= inf_rep - one || - b_abs.wrapping_sub(one) >= inf_rep - one { + if a_abs.wrapping_sub(one) >= inf_rep - one || b_abs.wrapping_sub(one) >= inf_rep - one { // NaN + anything = qNaN if a_abs > inf_rep { return F::from_repr(a_abs | quiet_bit); @@ -68,7 +68,7 @@ fn add(a: F, b: F) -> F where // anything + zero = anything if b_abs == Int::ZERO { - return a; + return a; } } @@ -115,7 +115,8 @@ fn add(a: F, b: F) -> F where let align = a_exponent.wrapping_sub(b_exponent).cast(); if align != Int::ZERO { if align < bits { - let sticky = F::Int::from_bool(b_significand << bits.wrapping_sub(align).cast() != Int::ZERO); + let sticky = + F::Int::from_bool(b_significand << bits.wrapping_sub(align).cast() != Int::ZERO); b_significand = (b_significand >> align.cast()) | sticky; } else { b_significand = one; // sticky; b is known to be non-zero. @@ -131,12 +132,14 @@ fn add(a: F, b: F) -> F where // If partial cancellation occured, we need to left-shift the result // and adjust the exponent: if a_significand < implicit_bit << 3 { - let shift = a_significand.leading_zeros() as i32 - - (implicit_bit << 3).leading_zeros() as i32; + let shift = + a_significand.leading_zeros() as i32 - (implicit_bit << 3).leading_zeros() as i32; a_significand <<= shift; a_exponent -= shift; } - } else /* addition */ { + } else + /* addition */ + { a_significand += b_significand; // If the addition carried up, we need to right-shift the result and @@ -157,7 +160,8 @@ fn add(a: F, b: F) -> F where // Result is denormal before rounding; the exponent is zero and we // need to shift the significand. let shift = (1 - a_exponent).cast(); - let sticky = F::Int::from_bool((a_significand << bits.wrapping_sub(shift).cast()) != Int::ZERO); + let sticky = + F::Int::from_bool((a_significand << bits.wrapping_sub(shift).cast()) != Int::ZERO); a_significand = a_significand >> shift.cast() | sticky; a_exponent = 0; } @@ -175,8 +179,12 @@ fn add(a: F, b: F) -> F where // Final rounding. The result may overflow to infinity, but that is the // correct result in that case. - if round_guard_sticky > 0x4 { result += one; } - if round_guard_sticky == 0x4 { result += result & one; } + if round_guard_sticky > 0x4 { + result += one; + } + if round_guard_sticky == 0x4 { + result += result & one; + } F::from_repr(result) } diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 01dd890550bc7..20ab92e4b9adc 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -1,64 +1,65 @@ #![allow(unreachable_code)] -use int::{Int, CastInto}; use float::Float; +use int::{CastInto, Int}; #[derive(Clone, Copy)] enum Result { Less, Equal, Greater, - Unordered + Unordered, } impl Result { fn to_le_abi(self) -> i32 { match self { - Result::Less => -1, - Result::Equal => 0, - Result::Greater => 1, - Result::Unordered => 1 + Result::Less => -1, + Result::Equal => 0, + Result::Greater => 1, + Result::Unordered => 1, } } fn to_ge_abi(self) -> i32 { match self { - Result::Less => -1, - Result::Equal => 0, - Result::Greater => 1, - Result::Unordered => -1 + Result::Less => -1, + Result::Equal => 0, + Result::Greater => 1, + Result::Unordered => -1, } } } -fn cmp(a: F, b: F) -> Result where +fn cmp(a: F, b: F) -> Result +where u32: CastInto, F::Int: CastInto, i32: CastInto, F::Int: CastInto, { - let one = F::Int::ONE; - let zero = F::Int::ZERO; + let one = F::Int::ONE; + let zero = F::Int::ZERO; let szero = F::SignedInt::ZERO; - let sign_bit = F::SIGN_MASK as F::Int; - let abs_mask = sign_bit - one; + let sign_bit = F::SIGN_MASK as F::Int; + let abs_mask = sign_bit - one; let exponent_mask = F::EXPONENT_MASK; - let inf_rep = exponent_mask; + let inf_rep = exponent_mask; - let a_rep = a.repr(); - let b_rep = b.repr(); - let a_abs = a_rep & abs_mask; - let b_abs = b_rep & abs_mask; + let a_rep = a.repr(); + let b_rep = b.repr(); + let a_abs = a_rep & abs_mask; + let b_abs = b_rep & abs_mask; // If either a or b is NaN, they are unordered. if a_abs > inf_rep || b_abs > inf_rep { - return Result::Unordered + return Result::Unordered; } // If a and b are both zeros, they are equal. if a_abs | b_abs == zero { - return Result::Equal + return Result::Equal; } let a_srep = a.signed_repr(); @@ -68,29 +69,29 @@ fn cmp(a: F, b: F) -> Result where // a and b as signed integers as we would with a fp_ting-point compare. if a_srep & b_srep >= szero { if a_srep < b_srep { - return Result::Less + return Result::Less; } else if a_srep == b_srep { - return Result::Equal + return Result::Equal; } else { - return Result::Greater + return Result::Greater; } } - // Otherwise, both are negative, so we need to flip the sense of the // comparison to get the correct result. (This assumes a twos- or ones- // complement integer representation; if integers are represented in a // sign-magnitude representation, then this flip is incorrect). else { if a_srep > b_srep { - return Result::Less + return Result::Less; } else if a_srep == b_srep { - return Result::Equal + return Result::Equal; } else { - return Result::Greater + return Result::Greater; } } } -fn unord(a: F, b: F) -> bool where +fn unord(a: F, b: F) -> bool +where u32: CastInto, F::Int: CastInto, i32: CastInto, @@ -98,10 +99,10 @@ fn unord(a: F, b: F) -> bool where { let one = F::Int::ONE; - let sign_bit = F::SIGN_MASK as F::Int; - let abs_mask = sign_bit - one; + let sign_bit = F::SIGN_MASK as F::Int; + let abs_mask = sign_bit - one; let exponent_mask = F::EXPONENT_MASK; - let inf_rep = exponent_mask; + let inf_rep = exponent_mask; let a_rep = a.repr(); let b_rep = b.repr(); diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 8d3e5fc6de22c..21aac15c167ef 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -2,10 +2,10 @@ use float::Float; use int::Int; macro_rules! int_to_float { - ($i:expr, $ity:ty, $fty:ty) => ({ + ($i:expr, $ity:ty, $fty:ty) => {{ let i = $i; if i == 0 { - return 0.0 + return 0.0; } let mant_dig = <$fty>::SIGNIFICAND_BITS + 1; @@ -22,20 +22,22 @@ macro_rules! int_to_float { let mut e = sd - 1; if <$ity>::BITS < mant_dig { - return <$fty>::from_parts(s, + return <$fty>::from_parts( + s, (e + exponent_bias) as <$fty as Float>::Int, - (a as <$fty as Float>::Int) << (mant_dig - e - 1)) + (a as <$fty as Float>::Int) << (mant_dig - e - 1), + ); } a = if sd > mant_dig { /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx - * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR - * 12345678901234567890123456 - * 1 = msb 1 bit - * P = bit MANT_DIG-1 bits to the right of 1 - * Q = bit MANT_DIG bits to the right of 1 - * R = "or" of all bits to the right of Q - */ + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit MANT_DIG-1 bits to the right of 1 + * Q = bit MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ let mant_dig_plus_one = mant_dig + 1; let mant_dig_plus_two = mant_dig + 2; a = if sd == mant_dig_plus_one { @@ -43,8 +45,10 @@ macro_rules! int_to_float { } else if sd == mant_dig_plus_two { a } else { - (a >> (sd - mant_dig_plus_two)) as <$ity as Int>::UnsignedInt | - ((a & <$ity as Int>::UnsignedInt::max_value()).wrapping_shl((n + mant_dig_plus_two) - sd) != 0) as <$ity as Int>::UnsignedInt + (a >> (sd - mant_dig_plus_two)) as <$ity as Int>::UnsignedInt + | ((a & <$ity as Int>::UnsignedInt::max_value()) + .wrapping_shl((n + mant_dig_plus_two) - sd) + != 0) as <$ity as Int>::UnsignedInt }; /* finish: */ @@ -54,19 +58,22 @@ macro_rules! int_to_float { /* a is now rounded to mant_dig or mant_dig+1 bits */ if (a & (1 << mant_dig)) != 0 { - a >>= 1; e += 1; + a >>= 1; + e += 1; } a - /* a is now rounded to mant_dig bits */ + /* a is now rounded to mant_dig bits */ } else { a.wrapping_shl(mant_dig - sd) /* a is now rounded to mant_dig bits */ }; - <$fty>::from_parts(s, + <$fty>::from_parts( + s, (e + exponent_bias) as <$fty as Float>::Int, - a as <$fty as Float>::Int) - }) + a as <$fty as Float>::Int, + ) + }}; } intrinsics! { @@ -160,11 +167,11 @@ intrinsics! { #[derive(PartialEq)] enum Sign { Positive, - Negative + Negative, } macro_rules! float_to_int { - ($f:expr, $fty:ty, $ity:ty) => ({ + ($f:expr, $fty:ty, $ity:ty) => {{ let f = $f; let fixint_min = <$ity>::min_value(); let fixint_max = <$ity>::max_value(); @@ -181,21 +188,34 @@ macro_rules! float_to_int { let a_abs = a_rep & !sign_bit; // this is used to work around -1 not being available for unsigned - let sign = if (a_rep & sign_bit) == 0 { Sign::Positive } else { Sign::Negative }; + let sign = if (a_rep & sign_bit) == 0 { + Sign::Positive + } else { + Sign::Negative + }; let mut exponent = (a_abs >> significand_bits) as usize; let significand = (a_abs & <$fty>::SIGNIFICAND_MASK) | <$fty>::IMPLICIT_BIT; // if < 1 or unsigned & negative - if exponent < exponent_bias || - fixint_unsigned && sign == Sign::Negative { - return 0 + if exponent < exponent_bias || fixint_unsigned && sign == Sign::Negative { + return 0; } exponent -= exponent_bias; // If the value is infinity, saturate. // If the value is too large for the integer type, 0. - if exponent >= (if fixint_unsigned {fixint_bits} else {fixint_bits -1}) { - return if sign == Sign::Positive {fixint_max} else {fixint_min} + if exponent + >= (if fixint_unsigned { + fixint_bits + } else { + fixint_bits - 1 + }) + { + return if sign == Sign::Positive { + fixint_max + } else { + fixint_min + }; } // If 0 <= exponent < significand_bits, right shift to get the result. // Otherwise, shift left. @@ -211,7 +231,7 @@ macro_rules! float_to_int { } else { r } - }) + }}; } intrinsics! { diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index ae12bb3214065..7c582a4408d75 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -1,7 +1,5 @@ -use int::{CastInto, Int, WideInt}; use float::Float; - - +use int::{CastInto, Int, WideInt}; fn div32(a: F, b: F) -> F where @@ -398,7 +396,6 @@ where // operation in C, so we need to be a little bit fussy. let (mut quotient, _) = ::wide_mul(a_significand << 2, reciprocal.cast()); - // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0). // In either case, we are going to compute a residual of the form // @@ -442,7 +439,6 @@ where } } - intrinsics! { #[arm_aeabi_alias = __aeabi_fdiv] pub extern "C" fn __divsf3(a: f32, b: f32) -> f32 { diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index 0ca9cf57a58d3..39633773b2578 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -1,8 +1,9 @@ -use int::{CastInto, Int}; use float::Float; +use int::{CastInto, Int}; /// Generic conversion from a narrower to a wider IEEE-754 floating-point type -fn extend(a: F) -> R where +fn extend(a: F) -> R +where F::Int: CastInto, u64: CastInto, u32: CastInto, @@ -79,4 +80,4 @@ intrinsics! { pub extern "C" fn __extendsfdf2vfp(a: f32) -> f64 { a as f64 // LLVM generate 'fcvtds' } -} \ No newline at end of file +} diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 3bb13abbc5c61..8b8039452a74c 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -3,26 +3,26 @@ use core::ops; use super::int::Int; -pub mod conv; -pub mod cmp; pub mod add; -pub mod pow; -pub mod sub; -pub mod mul; +pub mod cmp; +pub mod conv; pub mod div; pub mod extend; +pub mod mul; +pub mod pow; +pub mod sub; /// Trait for some basic operations on floats pub trait Float: - Copy + - PartialEq + - PartialOrd + - ops::AddAssign + - ops::MulAssign + - ops::Add + - ops::Sub + - ops::Div + - ops::Rem + + Copy + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::MulAssign + + ops::Add + + ops::Sub + + ops::Div + + ops::Rem { /// A uint of the same with as the float type Int: Int; @@ -118,17 +118,23 @@ macro_rules! float_impl { unsafe { mem::transmute(a) } } fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_repr(((sign as Self::Int) << (Self::BITS - 1)) | - ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) | - (significand & Self::SIGNIFICAND_MASK)) + Self::from_repr( + ((sign as Self::Int) << (Self::BITS - 1)) + | ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) + | (significand & Self::SIGNIFICAND_MASK), + ) } fn normalize(significand: Self::Int) -> (i32, Self::Int) { - let shift = significand.leading_zeros() + let shift = significand + .leading_zeros() .wrapping_sub((Self::Int::ONE << Self::SIGNIFICAND_BITS).leading_zeros()); - (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) + ( + 1i32.wrapping_sub(shift as i32), + significand << shift as Self::Int, + ) } } - } + }; } float_impl!(f32, u32, i32, 32, 23); diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index d014bbc90c047..7b28793c8e700 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -1,5 +1,5 @@ -use int::{CastInto, Int, WideInt}; use float::Float; +use int::{CastInto, Int, WideInt}; fn mul(a: F, b: F) -> F where diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index f879c1a1f8106..2eedf67584e67 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -1,5 +1,5 @@ -use int::Int; use float::Float; +use int::Int; trait Pow: Float { /// Returns `a` raised to the power `b` diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index 2afb1409b3220..8d300e9d248be 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -1,6 +1,6 @@ -use float::Float; -use float::add::__addsf3; use float::add::__adddf3; +use float::add::__addsf3; +use float::Float; intrinsics! { #[arm_aeabi_alias = __aeabi_fsub] diff --git a/library/compiler-builtins/src/int/addsub.rs b/library/compiler-builtins/src/int/addsub.rs index 50b5d10d2593b..e2d5bcbd4354a 100644 --- a/library/compiler-builtins/src/int/addsub.rs +++ b/library/compiler-builtins/src/int/addsub.rs @@ -1,16 +1,24 @@ -use int::LargeInt; use int::Int; +use int::LargeInt; trait UAddSub: LargeInt { fn uadd(self, other: Self) -> Self { let (low, carry) = self.low().overflowing_add(other.low()); let high = self.high().wrapping_add(other.high()); - let carry = if carry { Self::HighHalf::ONE } else { Self::HighHalf::ZERO }; + let carry = if carry { + Self::HighHalf::ONE + } else { + Self::HighHalf::ZERO + }; Self::from_parts(low, high.wrapping_add(carry)) } fn uadd_one(self) -> Self { let (low, carry) = self.low().overflowing_add(Self::LowHalf::ONE); - let carry = if carry { Self::HighHalf::ONE } else { Self::HighHalf::ZERO }; + let carry = if carry { + Self::HighHalf::ONE + } else { + Self::HighHalf::ZERO + }; Self::from_parts(low, self.high().wrapping_add(carry)) } fn usub(self, other: Self) -> Self { @@ -22,7 +30,8 @@ trait UAddSub: LargeInt { impl UAddSub for u128 {} trait AddSub: Int - where ::UnsignedInt: UAddSub +where + ::UnsignedInt: UAddSub, { fn add(self, other: Self) -> Self { Self::from_unsigned(self.unsigned().uadd(other.unsigned())) @@ -36,7 +45,8 @@ impl AddSub for u128 {} impl AddSub for i128 {} trait Addo: AddSub - where ::UnsignedInt: UAddSub +where + ::UnsignedInt: UAddSub, { fn addo(self, other: Self, overflow: &mut i32) -> Self { *overflow = 0; @@ -58,7 +68,8 @@ impl Addo for i128 {} impl Addo for u128 {} trait Subo: AddSub - where ::UnsignedInt: UAddSub +where + ::UnsignedInt: UAddSub, { fn subo(self, other: Self, overflow: &mut i32) -> Self { *overflow = 0; diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 07f72f84e7159..fd1f0c3c88138 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -3,13 +3,13 @@ use core::ops; macro_rules! hty { ($ty:ty) => { <$ty as LargeInt>::HighHalf - } + }; } macro_rules! os_ty { ($ty:ty) => { <$ty as Int>::OtherSign - } + }; } pub mod addsub; @@ -20,23 +20,23 @@ pub mod udiv; /// Trait for some basic operations on integers pub trait Int: - Copy + - PartialEq + - PartialOrd + - ops::AddAssign + - ops::BitAndAssign + - ops::BitOrAssign + - ops::ShlAssign + - ops::ShrAssign + - ops::Add + - ops::Sub + - ops::Div + - ops::Shl + - ops::Shr + - ops::BitOr + - ops::BitXor + - ops::BitAnd + - ops::Not + + Copy + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::BitAndAssign + + ops::BitOrAssign + + ops::ShlAssign + + ops::ShrAssign + + ops::Add + + ops::Sub + + ops::Div + + ops::Shl + + ops::Shr + + ops::BitOr + + ops::BitXor + + ops::BitAnd + + ops::Not { /// Type with the same width but other signedness type OtherSign: Int; @@ -182,7 +182,7 @@ macro_rules! int_impl { int_impl_common!($ity, $bits); } - } + }; } int_impl!(i32, u32, 32); @@ -223,7 +223,7 @@ macro_rules! large_int { low as $ty | ((high as $ty) << $halfbits) } } - } + }; } large_int!(u64, u32, u32, 32); @@ -284,9 +284,9 @@ macro_rules! impl_wide_int { let sticky = *low << ($bits - count); *low = *self << ($bits - count) | *low >> count | sticky; *self = *self >> count; - } else if count < 2*$bits { - let sticky = *self << (2*$bits - count) | *low; - *low = *self >> (count - $bits ) | sticky; + } else if count < 2 * $bits { + let sticky = *self << (2 * $bits - count) | *low; + *low = *self >> (count - $bits) | sticky; *self = 0; } else { let sticky = *self | *low; @@ -295,7 +295,7 @@ macro_rules! impl_wide_int { } } } - } + }; } impl_wide_int!(u32, u64, 32); diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 58ca461b085f1..376395ac04c85 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -1,7 +1,7 @@ use core::ops; -use int::LargeInt; use int::Int; +use int::LargeInt; trait Mul: LargeInt { fn mul(self, other: Self) -> Self { @@ -19,8 +19,9 @@ trait Mul: LargeInt { low += (t & lower_mask) << half_bits; high += Self::low_as_high(t >> half_bits); high += Self::low_as_high((self.low() >> half_bits).wrapping_mul(other.low() >> half_bits)); - high = high.wrapping_add(self.high().wrapping_mul(Self::low_as_high(other.low()))) - .wrapping_add(Self::low_as_high(self.low()).wrapping_mul(other.high())); + high = high + .wrapping_add(self.high().wrapping_mul(Self::low_as_high(other.low()))) + .wrapping_add(Self::low_as_high(self.low()).wrapping_mul(other.high())); Self::from_parts(low, high) } } @@ -70,7 +71,7 @@ impl Mulo for i32 {} impl Mulo for i64 {} impl Mulo for i128 {} -trait UMulo : Int { +trait UMulo: Int { fn mulo(self, other: Self, overflow: &mut i32) -> Self { *overflow = 0; let result = self.wrapping_mul(other); diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 82262a4412de8..4b63697b425dc 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -43,7 +43,8 @@ impl Mod for i128 {} trait Divmod: Int { /// Returns `a / b` and sets `*rem = n % d` fn divmod(self, other: Self, rem: &mut Self, div: F) -> Self - where F: Fn(Self, Self) -> Self, + where + F: Fn(Self, Self) -> Self, { let r = div(self, other); // NOTE won't overflow because it's using the result from the diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 959fcb0880fbe..4be588f161ddd 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -3,7 +3,8 @@ use int::{Int, LargeInt}; trait Ashl: Int + LargeInt { /// Returns `a << b`, requires `b < Self::BITS` fn ashl(self, offset: u32) -> Self - where Self: LargeInt::LowHalf>, + where + Self: LargeInt::LowHalf>, { let half_bits = Self::BITS / 2; if offset & half_bits != 0 { @@ -11,9 +12,10 @@ trait Ashl: Int + LargeInt { } else if offset == 0 { self } else { - Self::from_parts(self.low() << offset, - (self.high() << offset) | - (self.low() >> (half_bits - offset))) + Self::from_parts( + self.low() << offset, + (self.high() << offset) | (self.low() >> (half_bits - offset)), + ) } } } @@ -24,18 +26,23 @@ impl Ashl for u128 {} trait Ashr: Int + LargeInt { /// Returns arithmetic `a >> b`, requires `b < Self::BITS` fn ashr(self, offset: u32) -> Self - where Self: LargeInt::HighHalf as Int>::UnsignedInt>, + where + Self: LargeInt::HighHalf as Int>::UnsignedInt>, { let half_bits = Self::BITS / 2; if offset & half_bits != 0 { - Self::from_parts((self.high() >> (offset - half_bits)).unsigned(), - self.high() >> (half_bits - 1)) + Self::from_parts( + (self.high() >> (offset - half_bits)).unsigned(), + self.high() >> (half_bits - 1), + ) } else if offset == 0 { self } else { let high_unsigned = self.high().unsigned(); - Self::from_parts((high_unsigned << (half_bits - offset)) | (self.low() >> offset), - self.high() >> offset) + Self::from_parts( + (high_unsigned << (half_bits - offset)) | (self.low() >> offset), + self.high() >> offset, + ) } } } @@ -46,7 +53,8 @@ impl Ashr for i128 {} trait Lshr: Int + LargeInt { /// Returns logical `a >> b`, requires `b < Self::BITS` fn lshr(self, offset: u32) -> Self - where Self: LargeInt::LowHalf>, + where + Self: LargeInt::LowHalf>, { let half_bits = Self::BITS / 2; if offset & half_bits != 0 { @@ -54,9 +62,10 @@ trait Lshr: Int + LargeInt { } else if offset == 0 { self } else { - Self::from_parts((self.high() << (half_bits - offset)) | - (self.low() >> offset), - self.high() >> offset) + Self::from_parts( + (self.high() << (half_bits - offset)) | (self.low() >> offset), + self.high() >> offset, + ) } } } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index fddfa67aa8ea1..ef5353a7040ef 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -3,11 +3,13 @@ #![cfg_attr(feature = "compiler-builtins", compiler_builtins)] #![crate_name = "compiler_builtins"] #![crate_type = "rlib"] -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/", - html_playground_url = "https://play.rust-lang.org/", - test(attr(deny(warnings))))] +#![doc( + html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://doc.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/nightly/", + html_playground_url = "https://play.rust-lang.org/", + test(attr(deny(warnings))) +)] #![feature(asm)] #![feature(compiler_builtins)] #![feature(core_intrinsics)] @@ -19,10 +21,14 @@ #![allow(unused_features)] #![no_builtins] #![cfg_attr(feature = "compiler-builtins", feature(staged_api))] -#![cfg_attr(feature = "compiler-builtins", - unstable(feature = "compiler_builtins_lib", - reason = "Compiler builtins. Will never become stable.", - issue = "0"))] +#![cfg_attr( + feature = "compiler-builtins", + unstable( + feature = "compiler_builtins_lib", + reason = "Compiler builtins. Will never become stable.", + issue = "0" + ) +)] // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. @@ -44,12 +50,14 @@ fn abort() -> ! { #[macro_use] mod macros; -pub mod int; pub mod float; +pub mod int; -#[cfg(any(all(target_arch = "wasm32", target_os = "unknown"), - all(target_arch = "arm", target_os = "none"), - all(target_vendor = "fortanix", target_env = "sgx")))] +#[cfg(any( + all(target_arch = "wasm32", target_os = "unknown"), + all(target_arch = "arm", target_os = "none"), + all(target_vendor = "fortanix", target_env = "sgx") +))] pub mod math; pub mod mem; diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 5f1ab469a0214..e84338fae3974 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -261,7 +261,7 @@ macro_rules! intrinsics { // Hack for LLVM expectations for ABI on windows. This is used by the // `#[win64_128bit_abi_hack]` attribute recognized above -#[cfg(all(windows, target_pointer_width="64"))] +#[cfg(all(windows, target_pointer_width = "64"))] pub mod win64_128bit_abi_hack { #[repr(simd)] pub struct U64x2(u64, u64); diff --git a/library/compiler-builtins/src/mem.rs b/library/compiler-builtins/src/mem.rs index c56391c4d3d49..c863bb7294118 100644 --- a/library/compiler-builtins/src/mem.rs +++ b/library/compiler-builtins/src/mem.rs @@ -6,10 +6,7 @@ type c_int = i16; type c_int = i32; #[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -pub unsafe extern "C" fn memcpy(dest: *mut u8, - src: *const u8, - n: usize) - -> *mut u8 { +pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { let mut i = 0; while i < n { *dest.offset(i as isize) = *src.offset(i as isize); @@ -19,10 +16,7 @@ pub unsafe extern "C" fn memcpy(dest: *mut u8, } #[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -pub unsafe extern "C" fn memmove(dest: *mut u8, - src: *const u8, - n: usize) - -> *mut u8 { +pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { if src < dest as *const u8 { // copy from end let mut i = n; diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 52a0414a18fb2..f9284e8140515 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -46,7 +46,7 @@ #[naked] #[no_mangle] #[cfg(all(target_arch = "x86_64", not(feature = "mangled-names")))] -pub unsafe extern fn __rust_probestack() { +pub unsafe extern "C" fn __rust_probestack() { // Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax, // ensuring that if any pages are unmapped we'll make a page fault. // @@ -97,7 +97,7 @@ pub unsafe extern fn __rust_probestack() { #[naked] #[no_mangle] #[cfg(all(target_arch = "x86", not(feature = "mangled-names")))] -pub unsafe extern fn __rust_probestack() { +pub unsafe extern "C" fn __rust_probestack() { // This is the same as x86_64 above, only translated for 32-bit sizes. Note // that on Unix we're expected to restore everything as it was, this // function basically can't tamper with anything. diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 17ae3ef1819e3..e43fdb77b88a8 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -2,15 +2,15 @@ extern crate cast; extern crate rand; use std::collections::HashMap; +use std::fmt; use std::fmt::Write as FmtWrite; use std::fs::{self, OpenOptions}; -use std::io::Write; use std::hash::{Hash, Hasher}; +use std::io::Write; use std::path::PathBuf; use std::{env, mem}; -use std::fmt; -use self::cast::{f32, f64, u32, u64, u128, i32, i64, i128}; +use self::cast::{f32, f64, i128, i32, i64, u128, u32, u64}; use self::rand::Rng; const NTESTS: usize = 1_000; @@ -21,16 +21,15 @@ fn main() { drop(fs::remove_file(&out_file)); let target = env::var("TARGET").unwrap(); - let target_arch_arm = - target.contains("arm") || - target.contains("thumb"); + let target_arch_arm = target.contains("arm") || target.contains("thumb"); let target_arch_mips = target.contains("mips"); // TODO accept NaNs. We don't do that right now because we can't check // for NaN-ness on the thumb targets (due to missing intrinsics) // float/add.rs - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { let c = a.0 + b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { None @@ -38,8 +37,10 @@ fn main() { Some(c) } }, - "builtins::float::add::__adddf3(a, b)"); - gen(|(a, b): (MyF32, MyF32)| { + "builtins::float::add::__adddf3(a, b)", + ); + gen( + |(a, b): (MyF32, MyF32)| { let c = a.0 + b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { None @@ -47,10 +48,12 @@ fn main() { Some(c) } }, - "builtins::float::add::__addsf3(a, b)"); + "builtins::float::add::__addsf3(a, b)", + ); if target_arch_arm { - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { let c = a.0 + b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { None @@ -58,8 +61,10 @@ fn main() { Some(c) } }, - "builtins::float::add::__adddf3vfp(a, b)"); - gen(|(a, b): (LargeF32, LargeF32)| { + "builtins::float::add::__adddf3vfp(a, b)", + ); + gen( + |(a, b): (LargeF32, LargeF32)| { let c = a.0 + b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { None @@ -67,12 +72,13 @@ fn main() { Some(c) } }, - "builtins::float::add::__addsf3vfp(a, b)"); + "builtins::float::add::__addsf3vfp(a, b)", + ); } - // float/cmp.rs - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { let (a, b) = (a.0, b.0); if a.is_nan() || b.is_nan() { return None; @@ -88,8 +94,10 @@ fn main() { Some(0) } }, - "builtins::float::cmp::__gedf2(a, b)"); - gen(|(a, b): (MyF32, MyF32)| { + "builtins::float::cmp::__gedf2(a, b)", + ); + gen( + |(a, b): (MyF32, MyF32)| { let (a, b) = (a.0, b.0); if a.is_nan() || b.is_nan() { return None; @@ -105,8 +113,10 @@ fn main() { Some(0) } }, - "builtins::float::cmp::__gesf2(a, b)"); - gen(|(a, b): (MyF64, MyF64)| { + "builtins::float::cmp::__gesf2(a, b)", + ); + gen( + |(a, b): (MyF64, MyF64)| { let (a, b) = (a.0, b.0); if a.is_nan() || b.is_nan() { return None; @@ -122,8 +132,10 @@ fn main() { Some(0) } }, - "builtins::float::cmp::__ledf2(a, b)"); - gen(|(a, b): (MyF32, MyF32)| { + "builtins::float::cmp::__ledf2(a, b)", + ); + gen( + |(a, b): (MyF32, MyF32)| { let (a, b) = (a.0, b.0); if a.is_nan() || b.is_nan() { return None; @@ -139,285 +151,387 @@ fn main() { Some(0) } }, - "builtins::float::cmp::__lesf2(a, b)"); + "builtins::float::cmp::__lesf2(a, b)", + ); - gen(|(a, b): (MyF32, MyF32)| { + gen( + |(a, b): (MyF32, MyF32)| { let c = a.0.is_nan() || b.0.is_nan(); Some(c as i32) }, - "builtins::float::cmp::__unordsf2(a, b)"); + "builtins::float::cmp::__unordsf2(a, b)", + ); - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { let c = a.0.is_nan() || b.0.is_nan(); Some(c as i32) }, - "builtins::float::cmp::__unorddf2(a, b)"); + "builtins::float::cmp::__unorddf2(a, b)", + ); if target_arch_arm { - gen(|(a, b): (MyF32, MyF32)| { + gen( + |(a, b): (MyF32, MyF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } let c = (a.0 <= b.0) as i32; Some(c) }, - "builtins::float::cmp::__aeabi_fcmple(a, b)"); + "builtins::float::cmp::__aeabi_fcmple(a, b)", + ); - gen(|(a, b): (MyF32, MyF32)| { + gen( + |(a, b): (MyF32, MyF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } let c = (a.0 >= b.0) as i32; Some(c) }, - "builtins::float::cmp::__aeabi_fcmpge(a, b)"); + "builtins::float::cmp::__aeabi_fcmpge(a, b)", + ); - gen(|(a, b): (MyF32, MyF32)| { + gen( + |(a, b): (MyF32, MyF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } let c = (a.0 == b.0) as i32; Some(c) }, - "builtins::float::cmp::__aeabi_fcmpeq(a, b)"); + "builtins::float::cmp::__aeabi_fcmpeq(a, b)", + ); - gen(|(a, b): (MyF32, MyF32)| { + gen( + |(a, b): (MyF32, MyF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } let c = (a.0 < b.0) as i32; Some(c) }, - "builtins::float::cmp::__aeabi_fcmplt(a, b)"); + "builtins::float::cmp::__aeabi_fcmplt(a, b)", + ); - gen(|(a, b): (MyF32, MyF32)| { + gen( + |(a, b): (MyF32, MyF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } let c = (a.0 > b.0) as i32; Some(c) }, - "builtins::float::cmp::__aeabi_fcmpgt(a, b)"); + "builtins::float::cmp::__aeabi_fcmpgt(a, b)", + ); - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } let c = (a.0 <= b.0) as i32; Some(c) }, - "builtins::float::cmp::__aeabi_dcmple(a, b)"); + "builtins::float::cmp::__aeabi_dcmple(a, b)", + ); - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } let c = (a.0 >= b.0) as i32; Some(c) }, - "builtins::float::cmp::__aeabi_dcmpge(a, b)"); + "builtins::float::cmp::__aeabi_dcmpge(a, b)", + ); - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } let c = (a.0 == b.0) as i32; Some(c) }, - "builtins::float::cmp::__aeabi_dcmpeq(a, b)"); + "builtins::float::cmp::__aeabi_dcmpeq(a, b)", + ); - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } let c = (a.0 < b.0) as i32; Some(c) }, - "builtins::float::cmp::__aeabi_dcmplt(a, b)"); + "builtins::float::cmp::__aeabi_dcmplt(a, b)", + ); - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } let c = (a.0 > b.0) as i32; Some(c) }, - "builtins::float::cmp::__aeabi_dcmpgt(a, b)"); + "builtins::float::cmp::__aeabi_dcmpgt(a, b)", + ); - gen(|(a, b): (LargeF32, LargeF32)| { + gen( + |(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 >= b.0) as i32) }, - "builtins::float::cmp::__gesf2vfp(a, b)"); - gen(|(a, b): (MyF64, MyF64)| { + "builtins::float::cmp::__gesf2vfp(a, b)", + ); + gen( + |(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 >= b.0) as i32) }, - "builtins::float::cmp::__gedf2vfp(a, b)"); - gen(|(a, b): (LargeF32, LargeF32)| { + "builtins::float::cmp::__gedf2vfp(a, b)", + ); + gen( + |(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 > b.0) as i32) }, - "builtins::float::cmp::__gtsf2vfp(a, b)"); - gen(|(a, b): (MyF64, MyF64)| { + "builtins::float::cmp::__gtsf2vfp(a, b)", + ); + gen( + |(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 > b.0) as i32) }, - "builtins::float::cmp::__gtdf2vfp(a, b)"); - gen(|(a, b): (LargeF32, LargeF32)| { + "builtins::float::cmp::__gtdf2vfp(a, b)", + ); + gen( + |(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 < b.0) as i32) }, - "builtins::float::cmp::__ltsf2vfp(a, b)"); - gen(|(a, b): (MyF64, MyF64)| { + "builtins::float::cmp::__ltsf2vfp(a, b)", + ); + gen( + |(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 < b.0) as i32) }, - "builtins::float::cmp::__ltdf2vfp(a, b)"); - gen(|(a, b): (LargeF32, LargeF32)| { + "builtins::float::cmp::__ltdf2vfp(a, b)", + ); + gen( + |(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 <= b.0) as i32) }, - "builtins::float::cmp::__lesf2vfp(a, b)"); - gen(|(a, b): (MyF64, MyF64)| { + "builtins::float::cmp::__lesf2vfp(a, b)", + ); + gen( + |(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 <= b.0) as i32) }, - "builtins::float::cmp::__ledf2vfp(a, b)"); - gen(|(a, b): (LargeF32, LargeF32)| { + "builtins::float::cmp::__ledf2vfp(a, b)", + ); + gen( + |(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 != b.0) as i32) }, - "builtins::float::cmp::__nesf2vfp(a, b)"); - gen(|(a, b): (MyF64, MyF64)| { + "builtins::float::cmp::__nesf2vfp(a, b)", + ); + gen( + |(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 != b.0) as i32) }, - "builtins::float::cmp::__nedf2vfp(a, b)"); - gen(|(a, b): (LargeF32, LargeF32)| { + "builtins::float::cmp::__nedf2vfp(a, b)", + ); + gen( + |(a, b): (LargeF32, LargeF32)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 == b.0) as i32) }, - "builtins::float::cmp::__eqsf2vfp(a, b)"); - gen(|(a, b): (MyF64, MyF64)| { + "builtins::float::cmp::__eqsf2vfp(a, b)", + ); + gen( + |(a, b): (MyF64, MyF64)| { if a.0.is_nan() || b.0.is_nan() { return None; } Some((a.0 == b.0) as i32) }, - "builtins::float::cmp::__eqdf2vfp(a, b)"); + "builtins::float::cmp::__eqdf2vfp(a, b)", + ); } // float/extend.rs - gen(|a: MyF32| { + gen( + |a: MyF32| { if a.0.is_nan() { return None; } Some(f64(a.0)) }, - "builtins::float::extend::__extendsfdf2(a)"); + "builtins::float::extend::__extendsfdf2(a)", + ); if target_arch_arm { - gen(|a: LargeF32| { - if a.0.is_nan() { - return None; - } - Some(f64(a.0)) - }, - "builtins::float::extend::__extendsfdf2vfp(a)"); + gen( + |a: LargeF32| { + if a.0.is_nan() { + return None; + } + Some(f64(a.0)) + }, + "builtins::float::extend::__extendsfdf2vfp(a)", + ); } // float/conv.rs - gen(|a: MyF64| i64(a.0).ok(), - "builtins::float::conv::__fixdfdi(a)"); - gen(|a: MyF64| i32(a.0).ok(), - "builtins::float::conv::__fixdfsi(a)"); - gen(|a: MyF32| i64(a.0).ok(), - "builtins::float::conv::__fixsfdi(a)"); - gen(|a: MyF32| i32(a.0).ok(), - "builtins::float::conv::__fixsfsi(a)"); - gen(|a: MyF32| i128(a.0).ok(), - "builtins::float::conv::__fixsfti(a)"); - gen(|a: MyF64| i128(a.0).ok(), - "builtins::float::conv::__fixdfti(a)"); - gen(|a: MyF64| u64(a.0).ok(), - "builtins::float::conv::__fixunsdfdi(a)"); - gen(|a: MyF64| u32(a.0).ok(), - "builtins::float::conv::__fixunsdfsi(a)"); - gen(|a: MyF32| u64(a.0).ok(), - "builtins::float::conv::__fixunssfdi(a)"); - gen(|a: MyF32| u32(a.0).ok(), - "builtins::float::conv::__fixunssfsi(a)"); - gen(|a: MyF32| u128(a.0).ok(), - "builtins::float::conv::__fixunssfti(a)"); - gen(|a: MyF64| u128(a.0).ok(), - "builtins::float::conv::__fixunsdfti(a)"); - gen(|a: MyI64| Some(f64(a.0)), - "builtins::float::conv::__floatdidf(a)"); - gen(|a: MyI32| Some(f64(a.0)), - "builtins::float::conv::__floatsidf(a)"); - gen(|a: MyI32| Some(f32(a.0)), - "builtins::float::conv::__floatsisf(a)"); - gen(|a: MyU64| Some(f64(a.0)), - "builtins::float::conv::__floatundidf(a)"); - gen(|a: MyU32| Some(f64(a.0)), - "builtins::float::conv::__floatunsidf(a)"); - gen(|a: MyU32| Some(f32(a.0)), - "builtins::float::conv::__floatunsisf(a)"); - gen(|a: MyU128| f32(a.0).ok(), - "builtins::float::conv::__floatuntisf(a)"); + gen( + |a: MyF64| i64(a.0).ok(), + "builtins::float::conv::__fixdfdi(a)", + ); + gen( + |a: MyF64| i32(a.0).ok(), + "builtins::float::conv::__fixdfsi(a)", + ); + gen( + |a: MyF32| i64(a.0).ok(), + "builtins::float::conv::__fixsfdi(a)", + ); + gen( + |a: MyF32| i32(a.0).ok(), + "builtins::float::conv::__fixsfsi(a)", + ); + gen( + |a: MyF32| i128(a.0).ok(), + "builtins::float::conv::__fixsfti(a)", + ); + gen( + |a: MyF64| i128(a.0).ok(), + "builtins::float::conv::__fixdfti(a)", + ); + gen( + |a: MyF64| u64(a.0).ok(), + "builtins::float::conv::__fixunsdfdi(a)", + ); + gen( + |a: MyF64| u32(a.0).ok(), + "builtins::float::conv::__fixunsdfsi(a)", + ); + gen( + |a: MyF32| u64(a.0).ok(), + "builtins::float::conv::__fixunssfdi(a)", + ); + gen( + |a: MyF32| u32(a.0).ok(), + "builtins::float::conv::__fixunssfsi(a)", + ); + gen( + |a: MyF32| u128(a.0).ok(), + "builtins::float::conv::__fixunssfti(a)", + ); + gen( + |a: MyF64| u128(a.0).ok(), + "builtins::float::conv::__fixunsdfti(a)", + ); + gen( + |a: MyI64| Some(f64(a.0)), + "builtins::float::conv::__floatdidf(a)", + ); + gen( + |a: MyI32| Some(f64(a.0)), + "builtins::float::conv::__floatsidf(a)", + ); + gen( + |a: MyI32| Some(f32(a.0)), + "builtins::float::conv::__floatsisf(a)", + ); + gen( + |a: MyU64| Some(f64(a.0)), + "builtins::float::conv::__floatundidf(a)", + ); + gen( + |a: MyU32| Some(f64(a.0)), + "builtins::float::conv::__floatunsidf(a)", + ); + gen( + |a: MyU32| Some(f32(a.0)), + "builtins::float::conv::__floatunsisf(a)", + ); + gen( + |a: MyU128| f32(a.0).ok(), + "builtins::float::conv::__floatuntisf(a)", + ); if !target_arch_mips { - gen(|a: MyI128| Some(f32(a.0)), - "builtins::float::conv::__floattisf(a)"); - gen(|a: MyI128| Some(f64(a.0)), - "builtins::float::conv::__floattidf(a)"); - gen(|a: MyU128| Some(f64(a.0)), - "builtins::float::conv::__floatuntidf(a)"); + gen( + |a: MyI128| Some(f32(a.0)), + "builtins::float::conv::__floattisf(a)", + ); + gen( + |a: MyI128| Some(f64(a.0)), + "builtins::float::conv::__floattidf(a)", + ); + gen( + |a: MyU128| Some(f64(a.0)), + "builtins::float::conv::__floatuntidf(a)", + ); } // float/pow.rs - gen(|(a, b): (MyF64, MyI32)| { - let c = a.0.powi(b.0); - if a.0.is_nan() || c.is_nan() { - None - } else { + gen( + |(a, b): (MyF64, MyI32)| { + let c = a.0.powi(b.0); + if a.0.is_nan() || c.is_nan() { + None + } else { Some(c) } }, - "builtins::float::pow::__powidf2(a, b)"); - gen(|(a, b): (MyF32, MyI32)| { - let c = a.0.powi(b.0); - if a.0.is_nan() || c.is_nan() { - None - } else { + "builtins::float::pow::__powidf2(a, b)", + ); + gen( + |(a, b): (MyF32, MyI32)| { + let c = a.0.powi(b.0); + if a.0.is_nan() || c.is_nan() { + None + } else { Some(c) } }, - "builtins::float::pow::__powisf2(a, b)"); + "builtins::float::pow::__powisf2(a, b)", + ); // float/sub.rs - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { let c = a.0 - b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { None @@ -425,8 +539,10 @@ fn main() { Some(c) } }, - "builtins::float::sub::__subdf3(a, b)"); - gen(|(a, b): (MyF32, MyF32)| { + "builtins::float::sub::__subdf3(a, b)", + ); + gen( + |(a, b): (MyF32, MyF32)| { let c = a.0 - b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { None @@ -434,10 +550,12 @@ fn main() { Some(c) } }, - "builtins::float::sub::__subsf3(a, b)"); + "builtins::float::sub::__subsf3(a, b)", + ); if target_arch_arm { - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { let c = a.0 - b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { None @@ -445,8 +563,10 @@ fn main() { Some(c) } }, - "builtins::float::sub::__subdf3vfp(a, b)"); - gen(|(a, b): (LargeF32, LargeF32)| { + "builtins::float::sub::__subdf3vfp(a, b)", + ); + gen( + |(a, b): (LargeF32, LargeF32)| { let c = a.0 - b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { None @@ -454,11 +574,13 @@ fn main() { Some(c) } }, - "builtins::float::sub::__subsf3vfp(a, b)"); + "builtins::float::sub::__subsf3vfp(a, b)", + ); } // float/mul.rs - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { let c = a.0 * b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { None @@ -466,8 +588,10 @@ fn main() { Some(c) } }, - "builtins::float::mul::__muldf3(a, b)"); - gen(|(a, b): (LargeF32, LargeF32)| { + "builtins::float::mul::__muldf3(a, b)", + ); + gen( + |(a, b): (LargeF32, LargeF32)| { let c = a.0 * b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { None @@ -475,10 +599,12 @@ fn main() { Some(c) } }, - "builtins::float::mul::__mulsf3(a, b)"); + "builtins::float::mul::__mulsf3(a, b)", + ); if target_arch_arm { - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { let c = a.0 * b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { None @@ -486,8 +612,10 @@ fn main() { Some(c) } }, - "builtins::float::mul::__muldf3vfp(a, b)"); - gen(|(a, b): (LargeF32, LargeF32)| { + "builtins::float::mul::__muldf3vfp(a, b)", + ); + gen( + |(a, b): (LargeF32, LargeF32)| { let c = a.0 * b.0; if a.0.is_nan() || b.0.is_nan() || c.is_nan() { None @@ -495,122 +623,168 @@ fn main() { Some(c) } }, - "builtins::float::mul::__mulsf3vfp(a, b)"); + "builtins::float::mul::__mulsf3vfp(a, b)", + ); } // float/div.rs - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { if b.0 == 0.0 { - return None + return None; } let c = a.0 / b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() || - c.abs() <= unsafe { mem::transmute(4503599627370495u64) } + if a.0.is_nan() + || b.0.is_nan() + || c.is_nan() + || c.abs() <= unsafe { mem::transmute(4503599627370495u64) } { None } else { Some(c) } }, - "builtins::float::div::__divdf3(a, b)"); - gen(|(a, b): (LargeF32, LargeF32)| { + "builtins::float::div::__divdf3(a, b)", + ); + gen( + |(a, b): (LargeF32, LargeF32)| { if b.0 == 0.0 { - return None + return None; } let c = a.0 / b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() || - c.abs() <= unsafe { mem::transmute(16777215u32) } + if a.0.is_nan() + || b.0.is_nan() + || c.is_nan() + || c.abs() <= unsafe { mem::transmute(16777215u32) } { None } else { Some(c) } }, - "builtins::float::div::__divsf3(a, b)"); + "builtins::float::div::__divsf3(a, b)", + ); if target_arch_arm { - gen(|(a, b): (MyF64, MyF64)| { + gen( + |(a, b): (MyF64, MyF64)| { if b.0 == 0.0 { - return None + return None; } let c = a.0 / b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() || - c.abs() <= unsafe { mem::transmute(4503599627370495u64) } + if a.0.is_nan() + || b.0.is_nan() + || c.is_nan() + || c.abs() <= unsafe { mem::transmute(4503599627370495u64) } { None } else { Some(c) } }, - "builtins::float::div::__divdf3vfp(a, b)"); - gen(|(a, b): (LargeF32, LargeF32)| { + "builtins::float::div::__divdf3vfp(a, b)", + ); + gen( + |(a, b): (LargeF32, LargeF32)| { if b.0 == 0.0 { - return None + return None; } let c = a.0 / b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() || - c.abs() <= unsafe { mem::transmute(16777215u32) } + if a.0.is_nan() + || b.0.is_nan() + || c.is_nan() + || c.abs() <= unsafe { mem::transmute(16777215u32) } { None } else { Some(c) } }, - "builtins::float::div::__divsf3vfp(a, b)"); + "builtins::float::div::__divsf3vfp(a, b)", + ); } // int/addsub.rs - gen(|(a, b): (MyU128, MyU128)| Some(a.0.wrapping_add(b.0)), - "builtins::int::addsub::rust_u128_add(a, b)"); - gen(|(a, b): (MyI128, MyI128)| Some(a.0.wrapping_add(b.0)), - "builtins::int::addsub::rust_i128_add(a, b)"); - gen(|(a, b): (MyU128, MyU128)| Some(a.0.overflowing_add(b.0)), - "builtins::int::addsub::rust_u128_addo(a, b)"); - gen(|(a, b): (MyI128, MyI128)| Some(a.0.overflowing_add(b.0)), - "builtins::int::addsub::rust_i128_addo(a, b)"); - gen(|(a, b): (MyU128, MyU128)| Some(a.0.wrapping_sub(b.0)), - "builtins::int::addsub::rust_u128_sub(a, b)"); - gen(|(a, b): (MyI128, MyI128)| Some(a.0.wrapping_sub(b.0)), - "builtins::int::addsub::rust_i128_sub(a, b)"); - gen(|(a, b): (MyU128, MyU128)| Some(a.0.overflowing_sub(b.0)), - "builtins::int::addsub::rust_u128_subo(a, b)"); - gen(|(a, b): (MyI128, MyI128)| Some(a.0.overflowing_sub(b.0)), - "builtins::int::addsub::rust_i128_subo(a, b)"); + gen( + |(a, b): (MyU128, MyU128)| Some(a.0.wrapping_add(b.0)), + "builtins::int::addsub::rust_u128_add(a, b)", + ); + gen( + |(a, b): (MyI128, MyI128)| Some(a.0.wrapping_add(b.0)), + "builtins::int::addsub::rust_i128_add(a, b)", + ); + gen( + |(a, b): (MyU128, MyU128)| Some(a.0.overflowing_add(b.0)), + "builtins::int::addsub::rust_u128_addo(a, b)", + ); + gen( + |(a, b): (MyI128, MyI128)| Some(a.0.overflowing_add(b.0)), + "builtins::int::addsub::rust_i128_addo(a, b)", + ); + gen( + |(a, b): (MyU128, MyU128)| Some(a.0.wrapping_sub(b.0)), + "builtins::int::addsub::rust_u128_sub(a, b)", + ); + gen( + |(a, b): (MyI128, MyI128)| Some(a.0.wrapping_sub(b.0)), + "builtins::int::addsub::rust_i128_sub(a, b)", + ); + gen( + |(a, b): (MyU128, MyU128)| Some(a.0.overflowing_sub(b.0)), + "builtins::int::addsub::rust_u128_subo(a, b)", + ); + gen( + |(a, b): (MyI128, MyI128)| Some(a.0.overflowing_sub(b.0)), + "builtins::int::addsub::rust_i128_subo(a, b)", + ); // int/mul.rs - gen(|(a, b): (MyU64, MyU64)| Some(a.0.wrapping_mul(b.0)), - "builtins::int::mul::__muldi3(a, b)"); - gen(|(a, b): (MyI64, MyI64)| Some(a.0.overflowing_mul(b.0)), + gen( + |(a, b): (MyU64, MyU64)| Some(a.0.wrapping_mul(b.0)), + "builtins::int::mul::__muldi3(a, b)", + ); + gen( + |(a, b): (MyI64, MyI64)| Some(a.0.overflowing_mul(b.0)), "{ let mut o = 2; let c = builtins::int::mul::__mulodi4(a, b, &mut o); (c, match o { 0 => false, 1 => true, _ => panic!() }) - }"); - gen(|(a, b): (MyI32, MyI32)| Some(a.0.overflowing_mul(b.0)), + }", + ); + gen( + |(a, b): (MyI32, MyI32)| Some(a.0.overflowing_mul(b.0)), "{ let mut o = 2; let c = builtins::int::mul::__mulosi4(a, b, &mut o); (c, match o { 0 => false, 1 => true, _ => panic!() }) - }"); - gen(|(a, b): (MyI128, MyI128)| Some(a.0.wrapping_mul(b.0)), - "builtins::int::mul::__multi3(a, b)"); - gen(|(a, b): (MyI128, MyI128)| Some(a.0.overflowing_mul(b.0)), + }", + ); + gen( + |(a, b): (MyI128, MyI128)| Some(a.0.wrapping_mul(b.0)), + "builtins::int::mul::__multi3(a, b)", + ); + gen( + |(a, b): (MyI128, MyI128)| Some(a.0.overflowing_mul(b.0)), "{ let mut o = 2; let c = builtins::int::mul::__muloti4(a, b, &mut o); (c, match o { 0 => false, 1 => true, _ => panic!() }) - }"); + }", + ); // int/sdiv.rs - gen(|(a, b): (MyI64, MyI64)| { + gen( + |(a, b): (MyI64, MyI64)| { if b.0 == 0 { None } else { Some(a.0 / b.0) } }, - "builtins::int::sdiv::__divdi3(a, b)"); - gen(|(a, b): (MyI64, MyI64)| { + "builtins::int::sdiv::__divdi3(a, b)", + ); + gen( + |(a, b): (MyI64, MyI64)| { if b.0 == 0 { None } else { @@ -620,8 +794,10 @@ fn main() { "{ let mut r = 0; (builtins::int::sdiv::__divmoddi4(a, b, &mut r), r) - }"); - gen(|(a, b): (MyI32, MyI32)| { + }", + ); + gen( + |(a, b): (MyI32, MyI32)| { if b.0 == 0 { None } else { @@ -631,72 +807,98 @@ fn main() { "{ let mut r = 0; (builtins::int::sdiv::__divmodsi4(a, b, &mut r), r) - }"); - gen(|(a, b): (MyI32, MyI32)| { + }", + ); + gen( + |(a, b): (MyI32, MyI32)| { if b.0 == 0 { None } else { Some(a.0 / b.0) } }, - "builtins::int::sdiv::__divsi3(a, b)"); - gen(|(a, b): (MyI32, MyI32)| { + "builtins::int::sdiv::__divsi3(a, b)", + ); + gen( + |(a, b): (MyI32, MyI32)| { if b.0 == 0 { None } else { Some(a.0 % b.0) } }, - "builtins::int::sdiv::__modsi3(a, b)"); - gen(|(a, b): (MyI64, MyI64)| { + "builtins::int::sdiv::__modsi3(a, b)", + ); + gen( + |(a, b): (MyI64, MyI64)| { if b.0 == 0 { None } else { Some(a.0 % b.0) } }, - "builtins::int::sdiv::__moddi3(a, b)"); - gen(|(a, b): (MyI128, MyI128)| { + "builtins::int::sdiv::__moddi3(a, b)", + ); + gen( + |(a, b): (MyI128, MyI128)| { if b.0 == 0 { None } else { Some(a.0 / b.0) } }, - "builtins::int::sdiv::__divti3(a, b)"); - gen(|(a, b): (MyI128, MyI128)| { + "builtins::int::sdiv::__divti3(a, b)", + ); + gen( + |(a, b): (MyI128, MyI128)| { if b.0 == 0 { None } else { Some(a.0 % b.0) } }, - "builtins::int::sdiv::__modti3(a, b)"); + "builtins::int::sdiv::__modti3(a, b)", + ); // int/shift.rs - gen(|(a, b): (MyU64, MyU32)| Some(a.0 << (b.0 % 64)), - "builtins::int::shift::__ashldi3(a, b % 64)"); - gen(|(a, b): (MyU128, MyU32)| Some(a.0 << (b.0 % 128)), - "builtins::int::shift::__ashlti3(a, b % 128)"); - gen(|(a, b): (MyI64, MyU32)| Some(a.0 >> (b.0 % 64)), - "builtins::int::shift::__ashrdi3(a, b % 64)"); - gen(|(a, b): (MyI128, MyU32)| Some(a.0 >> (b.0 % 128)), - "builtins::int::shift::__ashrti3(a, b % 128)"); - gen(|(a, b): (MyU64, MyU32)| Some(a.0 >> (b.0 % 64)), - "builtins::int::shift::__lshrdi3(a, b % 64)"); - gen(|(a, b): (MyU128, MyU32)| Some(a.0 >> (b.0 % 128)), - "builtins::int::shift::__lshrti3(a, b % 128)"); + gen( + |(a, b): (MyU64, MyU32)| Some(a.0 << (b.0 % 64)), + "builtins::int::shift::__ashldi3(a, b % 64)", + ); + gen( + |(a, b): (MyU128, MyU32)| Some(a.0 << (b.0 % 128)), + "builtins::int::shift::__ashlti3(a, b % 128)", + ); + gen( + |(a, b): (MyI64, MyU32)| Some(a.0 >> (b.0 % 64)), + "builtins::int::shift::__ashrdi3(a, b % 64)", + ); + gen( + |(a, b): (MyI128, MyU32)| Some(a.0 >> (b.0 % 128)), + "builtins::int::shift::__ashrti3(a, b % 128)", + ); + gen( + |(a, b): (MyU64, MyU32)| Some(a.0 >> (b.0 % 64)), + "builtins::int::shift::__lshrdi3(a, b % 64)", + ); + gen( + |(a, b): (MyU128, MyU32)| Some(a.0 >> (b.0 % 128)), + "builtins::int::shift::__lshrti3(a, b % 128)", + ); // int/udiv.rs - gen(|(a, b): (MyU64, MyU64)| { + gen( + |(a, b): (MyU64, MyU64)| { if b.0 == 0 { None } else { Some(a.0 / b.0) } }, - "builtins::int::udiv::__udivdi3(a, b)"); - gen(|(a, b): (MyU64, MyU64)| { + "builtins::int::udiv::__udivdi3(a, b)", + ); + gen( + |(a, b): (MyU64, MyU64)| { if b.0 == 0 { None } else { @@ -706,8 +908,10 @@ fn main() { "{ let mut r = 0; (builtins::int::udiv::__udivmoddi4(a, b, Some(&mut r)), r) - }"); - gen(|(a, b): (MyU32, MyU32)| { + }", + ); + gen( + |(a, b): (MyU32, MyU32)| { if b.0 == 0 { None } else { @@ -717,48 +921,60 @@ fn main() { "{ let mut r = 0; (builtins::int::udiv::__udivmodsi4(a, b, Some(&mut r)), r) - }"); - gen(|(a, b): (MyU32, MyU32)| { + }", + ); + gen( + |(a, b): (MyU32, MyU32)| { if b.0 == 0 { None } else { Some(a.0 / b.0) } }, - "builtins::int::udiv::__udivsi3(a, b)"); - gen(|(a, b): (MyU32, MyU32)| { + "builtins::int::udiv::__udivsi3(a, b)", + ); + gen( + |(a, b): (MyU32, MyU32)| { if b.0 == 0 { None } else { Some(a.0 % b.0) } }, - "builtins::int::udiv::__umodsi3(a, b)"); - gen(|(a, b): (MyU64, MyU64)| { + "builtins::int::udiv::__umodsi3(a, b)", + ); + gen( + |(a, b): (MyU64, MyU64)| { if b.0 == 0 { None } else { Some(a.0 % b.0) } }, - "builtins::int::udiv::__umoddi3(a, b)"); - gen(|(a, b): (MyU128, MyU128)| { + "builtins::int::udiv::__umoddi3(a, b)", + ); + gen( + |(a, b): (MyU128, MyU128)| { if b.0 == 0 { None } else { Some(a.0 / b.0) } }, - "builtins::int::udiv::__udivti3(a, b)"); - gen(|(a, b): (MyU128, MyU128)| { + "builtins::int::udiv::__udivti3(a, b)", + ); + gen( + |(a, b): (MyU128, MyU128)| { if b.0 == 0 { None } else { Some(a.0 % b.0) } }, - "builtins::int::udiv::__umodti3(a, b)"); - gen(|(a, b): (MyU128, MyU128)| { + "builtins::int::udiv::__umodti3(a, b)", + ); + gen( + |(a, b): (MyU128, MyU128)| { if b.0 == 0 { None } else { @@ -768,7 +984,8 @@ fn main() { "{ let mut r = 0; (builtins::int::udiv::__udivmodti4(a, b, Some(&mut r)), r) - }"); + }", + ); } macro_rules! gen_float { @@ -790,24 +1007,27 @@ macro_rules! gen_float { fn mk_f32(sign: bool, exponent: $uty, significand: $uty) -> $fty { unsafe { - mem::transmute(((sign as $uty) << (BITS - 1)) | - ((exponent & EXPONENT_MASK) << - SIGNIFICAND_BITS) | - (significand & SIGNIFICAND_MASK)) + mem::transmute( + ((sign as $uty) << (BITS - 1)) + | ((exponent & EXPONENT_MASK) << SIGNIFICAND_BITS) + | (significand & SIGNIFICAND_MASK), + ) } } if rng.gen_weighted_bool(10) { // Special values - *rng.choose(&[-0.0, - 0.0, - ::std::$fty::MIN, - ::std::$fty::MIN_POSITIVE, - ::std::$fty::MAX, - ::std::$fty::NAN, - ::std::$fty::INFINITY, - -::std::$fty::INFINITY]) - .unwrap() + *rng.choose(&[ + -0.0, + 0.0, + ::std::$fty::MIN, + ::std::$fty::MIN_POSITIVE, + ::std::$fty::MAX, + ::std::$fty::NAN, + ::std::$fty::INFINITY, + -::std::$fty::INFINITY, + ]) + .unwrap() } else if rng.gen_weighted_bool(10) { // NaN patterns mk_f32(rng.gen(), rng.gen(), 0) @@ -819,7 +1039,7 @@ macro_rules! gen_float { mk_f32(rng.gen(), rng.gen(), rng.gen()) } } - } + }; } gen_float!(gen_f32, f32, u32, 32, 23); @@ -844,24 +1064,27 @@ macro_rules! gen_large_float { fn mk_f32(sign: bool, exponent: $uty, significand: $uty) -> $fty { unsafe { - mem::transmute(((sign as $uty) << (BITS - 1)) | - ((exponent & EXPONENT_MASK) << - SIGNIFICAND_BITS) | - (significand & SIGNIFICAND_MASK)) + mem::transmute( + ((sign as $uty) << (BITS - 1)) + | ((exponent & EXPONENT_MASK) << SIGNIFICAND_BITS) + | (significand & SIGNIFICAND_MASK), + ) } } if rng.gen_weighted_bool(10) { // Special values - *rng.choose(&[-0.0, - 0.0, - ::std::$fty::MIN, - ::std::$fty::MIN_POSITIVE, - ::std::$fty::MAX, - ::std::$fty::NAN, - ::std::$fty::INFINITY, - -::std::$fty::INFINITY]) - .unwrap() + *rng.choose(&[ + -0.0, + 0.0, + ::std::$fty::MIN, + ::std::$fty::MIN_POSITIVE, + ::std::$fty::MAX, + ::std::$fty::NAN, + ::std::$fty::INFINITY, + -::std::$fty::INFINITY, + ]) + .unwrap() } else if rng.gen_weighted_bool(10) { // NaN patterns mk_f32(rng.gen(), rng.gen(), 0) @@ -873,7 +1096,7 @@ macro_rules! gen_large_float { rng.gen::<$fty>() } } - } + }; } gen_large_float!(gen_large_f32, f32, u32, 32, 23); @@ -892,17 +1115,13 @@ trait TestOutput { } fn gen(mut generate: F, test: &str) - where F: FnMut(A) -> Option, - A: TestInput + Copy, - R: TestOutput, +where + F: FnMut(A) -> Option, + A: TestInput + Copy, + R: TestOutput, { let rng = &mut rand::thread_rng(); - let testname = test.split("::") - .last() - .unwrap() - .split("(") - .next() - .unwrap(); + let testname = test.split("::").last().unwrap().split("(").next().unwrap(); let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); let out_file = out_dir.join("generated.rs"); @@ -911,7 +1130,7 @@ fn gen(mut generate: F, test: &str) while n > 0 { let input: A = rng.gen(); if testcases.contains_key(&input) { - continue + continue; } let output = match generate(input) { Some(o) => o, @@ -925,10 +1144,12 @@ fn gen(mut generate: F, test: &str) contents.push_str(&format!("mod {} {{\nuse super::*;\n", testname)); contents.push_str("#[test]\n"); contents.push_str("fn test() {\n"); - contents.push_str(&format!("static TESTS: [({}, {}); {}] = [\n", - A::ty_name(), - R::ty_name(), - NTESTS)); + contents.push_str(&format!( + "static TESTS: [({}, {}); {}] = [\n", + A::ty_name(), + R::ty_name(), + NTESTS + )); for (input, output) in testcases { contents.push_str(" ("); input.generate_static(&mut contents); @@ -938,7 +1159,8 @@ fn gen(mut generate: F, test: &str) } contents.push_str("];\n"); - contents.push_str(&format!(r#" + contents.push_str(&format!( + r#" for &(inputs, output) in TESTS.iter() {{ {} assert_eq!({}, {}, "inputs {{:?}}", inputs) @@ -1070,17 +1292,20 @@ my_integer! { } impl TestInput for (A, B) - where A: TestInput, - B: TestInput, +where + A: TestInput, + B: TestInput, { fn ty_name() -> String { format!("({}, {})", A::ty_name(), B::ty_name()) } fn generate_lets(container: &str, cnt: &mut u8) -> String { - format!("{}{}", - A::generate_lets(&format!("{}.0", container), cnt), - B::generate_lets(&format!("{}.1", container), cnt)) + format!( + "{}{}", + A::generate_lets(&format!("{}.0", container), cnt), + B::generate_lets(&format!("{}.1", container), cnt) + ) } fn generate_static(&self, dst: &mut String) { @@ -1141,8 +1366,9 @@ macro_rules! plain_test_output { plain_test_output!(i32 i64 i128 u32 u64 u128 bool); impl TestOutput for (A, B) - where A: TestOutput, - B: TestOutput, +where + A: TestOutput, + B: TestOutput, { fn ty_name() -> String { format!("({}, {})", A::ty_name(), B::ty_name()) diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index 2e7f0d4d752b9..0c9ac1ac8e4bd 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -1 +1 @@ -#![no_std] \ No newline at end of file +#![no_std] diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs b/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs index 08fbd4fa9f245..326435c298d6e 100644 --- a/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs +++ b/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs @@ -1,7 +1,9 @@ -#![cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - feature = "mem"))] +#![cfg(all( + target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + feature = "mem" +))] #![feature(compiler_builtins_lib)] #![feature(lang_items)] #![no_std] diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs b/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs index 76dad899263a5..2d72dfbbaa6e0 100644 --- a/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs +++ b/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs @@ -1,7 +1,9 @@ -#![cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - feature = "mem"))] +#![cfg(all( + target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + feature = "mem" +))] #![feature(compiler_builtins_lib)] #![feature(lang_items)] #![no_std] diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memset.rs b/library/compiler-builtins/testcrate/tests/aeabi_memset.rs index 71fe37e3582e7..3cfbfe5b011ec 100644 --- a/library/compiler-builtins/testcrate/tests/aeabi_memset.rs +++ b/library/compiler-builtins/testcrate/tests/aeabi_memset.rs @@ -1,7 +1,9 @@ -#![cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - feature = "mem"))] +#![cfg(all( + target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + feature = "mem" +))] #![feature(compiler_builtins_lib)] #![feature(lang_items)] #![no_std] @@ -48,9 +50,7 @@ fn zero() { let xs = &mut aligned.array; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), 0, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), 0, c) } assert_eq!(*xs, [0; 8]); @@ -59,9 +59,7 @@ fn zero() { let xs = &mut aligned.array; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), 0, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), 0, c) } assert_eq!(*xs, [1; 8]); } @@ -74,9 +72,7 @@ fn one() { let n = 1; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0, 0, 0, 0, 0, 0, 0]); @@ -85,9 +81,7 @@ fn one() { let xs = &mut aligned.array; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 1, 1, 1, 1, 1, 1, 1]); } @@ -100,9 +94,7 @@ fn two() { let n = 2; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0, 0, 0, 0, 0, 0]); @@ -111,9 +103,7 @@ fn two() { let xs = &mut aligned.array; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 1, 1, 1, 1, 1, 1]); } @@ -126,9 +116,7 @@ fn three() { let n = 3; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0xef, 0, 0, 0, 0, 0]); @@ -137,9 +125,7 @@ fn three() { let xs = &mut aligned.array; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0xef, 1, 1, 1, 1, 1]); } @@ -152,9 +138,7 @@ fn four() { let n = 4; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0, 0, 0, 0]); @@ -163,9 +147,7 @@ fn four() { let xs = &mut aligned.array; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 1, 1, 1, 1]); } @@ -178,9 +160,7 @@ fn five() { let n = 5; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0, 0, 0]); @@ -189,9 +169,7 @@ fn five() { let xs = &mut aligned.array; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 1, 1, 1]); } @@ -204,9 +182,7 @@ fn six() { let n = 6; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0, 0]); @@ -215,9 +191,7 @@ fn six() { let xs = &mut aligned.array; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 1, 1]); } @@ -230,9 +204,7 @@ fn seven() { let n = 7; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0]); @@ -241,9 +213,7 @@ fn seven() { let xs = &mut aligned.array; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 1]); } @@ -256,9 +226,7 @@ fn eight() { let n = 8; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef]); @@ -267,9 +235,7 @@ fn eight() { let xs = &mut aligned.array; let c = 0xdeadbeef; - unsafe { - __aeabi_memset4(xs.as_mut_ptr(), n, c) - } + unsafe { __aeabi_memset4(xs.as_mut_ptr(), n, c) } assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef]); } diff --git a/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs b/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs index 559650174542a..b50a7ce843075 100644 --- a/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs +++ b/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs @@ -6,20 +6,20 @@ use compiler_builtins::int::__clzsi2; #[test] fn __clzsi2_test() { - let mut i: usize = core::usize::MAX; - // Check all values above 0 - while i > 0 { + let mut i: usize = core::usize::MAX; + // Check all values above 0 + while i > 0 { + assert_eq!(__clzsi2(i) as u32, i.leading_zeros()); + i >>= 1; + } + // check 0 also + i = 0; assert_eq!(__clzsi2(i) as u32, i.leading_zeros()); - i >>= 1; - } - // check 0 also - i = 0; - assert_eq!(__clzsi2(i) as u32, i.leading_zeros()); - // double check for bit patterns that aren't just solid 1s - i = 1; - for _ in 0..63 { - assert_eq!(__clzsi2(i) as u32, i.leading_zeros()); - i <<= 2; - i += 1; - } + // double check for bit patterns that aren't just solid 1s + i = 1; + for _ in 0..63 { + assert_eq!(__clzsi2(i) as u32, i.leading_zeros()); + i <<= 2; + i += 1; + } } diff --git a/library/compiler-builtins/testcrate/tests/generated.rs b/library/compiler-builtins/testcrate/tests/generated.rs index 28fe4be59e35f..ee575cba87e0a 100644 --- a/library/compiler-builtins/testcrate/tests/generated.rs +++ b/library/compiler-builtins/testcrate/tests/generated.rs @@ -6,23 +6,29 @@ extern crate compiler_builtins as builtins; -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] +#[cfg(all( + target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test +))] extern crate utest_cortex_m_qemu; -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] +#[cfg(all( + target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test +))] #[macro_use] extern crate utest_macros; -#[cfg(all(target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test))] +#[cfg(all( + target_arch = "arm", + not(any(target_env = "gnu", target_env = "musl")), + target_os = "linux", + test +))] macro_rules! panic { // overrides `panic!` ($($tt:tt)*) => { upanic!($($tt)*); From 02aaab7026122b28b4d4dcca833a7e99c91b55a0 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 14 May 2019 14:41:07 -0700 Subject: [PATCH 0729/4206] Bump to 0.1.13 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 4d0350de5ddad..f08037432841b 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.12" +version = "0.1.13" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" From f567dbb36ba82779e2aab06d12b68930c3db277f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 15 May 2019 12:57:36 -0700 Subject: [PATCH 0730/4206] Remove the need for #[cfg] in #[use_c_shim_if] This commit tweaks the implementation of the synthetic `#[use_c_shim_if]` attribute, renaming it to `#[maybe_use_optimized_c_shim]` in the process. This no longer requires specifying a `#[cfg]` clause indicating when the optimized intrinsic should be used, but rather this is inferred and printed from the build script. The build script will now print out appropriate `#[cfg]` directives for rustc to indicate what intrinsics it's compiling. This should remove the need for us to keep the build script and the source in sync, but rather the build script can simply take care of everything. --- library/compiler-builtins/build.rs | 336 ++++++++++---------- library/compiler-builtins/ci/run.sh | 1 + library/compiler-builtins/src/float/conv.rs | 18 +- library/compiler-builtins/src/int/mod.rs | 2 +- library/compiler-builtins/src/int/mul.rs | 2 +- library/compiler-builtins/src/int/sdiv.rs | 14 +- library/compiler-builtins/src/int/shift.rs | 6 +- library/compiler-builtins/src/int/udiv.rs | 18 +- library/compiler-builtins/src/macros.rs | 23 +- 9 files changed, 198 insertions(+), 222 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index a8301afa95fcb..be5d42bb76db2 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -49,7 +49,6 @@ fn main() { if !target.contains("wasm32") && !target.contains("nvptx") && !target.starts_with("riscv") { #[cfg(feature = "c")] c::compile(&llvm_target); - println!("cargo:rustc-cfg=use_c"); } } @@ -91,15 +90,14 @@ mod c { } } - fn extend(&mut self, sources: &[&'static str]) { + fn extend(&mut self, sources: &[(&'static str, &'static str)]) { // NOTE Some intrinsics have both a generic implementation (e.g. // `floatdidf.c`) and an arch optimized implementation // (`x86_64/floatdidf.c`). In those cases, we keep the arch optimized // implementation and discard the generic implementation. If we don't // and keep both implementations, the linker will yell at us about // duplicate symbols! - for &src in sources { - let symbol = Path::new(src).file_stem().unwrap().to_str().unwrap(); + for (symbol, src) in sources { if src.contains("/") { // Arch-optimized implementation (preferred) self.map.insert(symbol, src); @@ -155,42 +153,42 @@ mod c { let mut sources = Sources::new(); sources.extend(&[ - "absvdi2.c", - "absvsi2.c", - "addvdi3.c", - "addvsi3.c", - "apple_versioning.c", - "clzdi2.c", - "clzsi2.c", - "cmpdi2.c", - "ctzdi2.c", - "ctzsi2.c", - "divdc3.c", - "divsc3.c", - "divxc3.c", - "extendhfsf2.c", - "int_util.c", - "muldc3.c", - "mulsc3.c", - "mulvdi3.c", - "mulvsi3.c", - "mulxc3.c", - "negdf2.c", - "negdi2.c", - "negsf2.c", - "negvdi2.c", - "negvsi2.c", - "paritydi2.c", - "paritysi2.c", - "popcountdi2.c", - "popcountsi2.c", - "powixf2.c", - "subvdi3.c", - "subvsi3.c", - "truncdfhf2.c", - "truncdfsf2.c", - "truncsfhf2.c", - "ucmpdi2.c", + ("__absvdi2", "absvdi2.c"), + ("__absvsi2", "absvsi2.c"), + ("__addvdi3", "addvdi3.c"), + ("__addvsi3", "addvsi3.c"), + ("apple_versioning", "apple_versioning.c"), + ("__clzdi2", "clzdi2.c"), + ("__clzsi2", "clzsi2.c"), + ("__cmpdi2", "cmpdi2.c"), + ("__ctzdi2", "ctzdi2.c"), + ("__ctzsi2", "ctzsi2.c"), + ("__divdc3", "divdc3.c"), + ("__divsc3", "divsc3.c"), + ("__divxc3", "divxc3.c"), + ("__extendhfsf2", "extendhfsf2.c"), + ("__int_util", "int_util.c"), + ("__muldc3", "muldc3.c"), + ("__mulsc3", "mulsc3.c"), + ("__mulvdi3", "mulvdi3.c"), + ("__mulvsi3", "mulvsi3.c"), + ("__mulxc3", "mulxc3.c"), + ("__negdf2", "negdf2.c"), + ("__negdi2", "negdi2.c"), + ("__negsf2", "negsf2.c"), + ("__negvdi2", "negvdi2.c"), + ("__negvsi2", "negvsi2.c"), + ("__paritydi2", "paritydi2.c"), + ("__paritysi2", "paritysi2.c"), + ("__popcountdi2", "popcountdi2.c"), + ("__popcountsi2", "popcountsi2.c"), + ("__powixf2", "powixf2.c"), + ("__subvdi3", "subvdi3.c"), + ("__subvsi3", "subvsi3.c"), + ("__truncdfhf2", "truncdfhf2.c"), + ("__truncdfsf2", "truncdfsf2.c"), + ("__truncsfhf2", "truncsfhf2.c"), + ("__ucmpdi2", "ucmpdi2.c"), ]); // When compiling in rustbuild (the rust-lang/rust repo) this library @@ -198,43 +196,49 @@ mod c { // need, so include a few more that aren't typically needed by // LLVM/Rust. if cfg!(feature = "rustbuild") { - sources.extend(&["ffsdi2.c"]); + sources.extend(&[("__ffsdi2", "ffsdi2.c")]); } // On iOS and 32-bit OSX these are all just empty intrinsics, no need to // include them. if target_os != "ios" && (target_vendor != "apple" || target_arch != "x86") { sources.extend(&[ - "absvti2.c", - "addvti3.c", - "clzti2.c", - "cmpti2.c", - "ctzti2.c", - "ffsti2.c", - "mulvti3.c", - "negti2.c", - "negvti2.c", - "parityti2.c", - "popcountti2.c", - "subvti3.c", - "ucmpti2.c", + ("__absvti2", "absvti2.c"), + ("__addvti3", "addvti3.c"), + ("__clzti2", "clzti2.c"), + ("__cmpti2", "cmpti2.c"), + ("__ctzti2", "ctzti2.c"), + ("__ffsti2", "ffsti2.c"), + ("__mulvti3", "mulvti3.c"), + ("__negti2", "negti2.c"), + ("__negvti2", "negvti2.c"), + ("__parityti2", "parityti2.c"), + ("__popcountti2", "popcountti2.c"), + ("__subvti3", "subvti3.c"), + ("__ucmpti2", "ucmpti2.c"), ]); } if target_vendor == "apple" { sources.extend(&[ - "atomic_flag_clear.c", - "atomic_flag_clear_explicit.c", - "atomic_flag_test_and_set.c", - "atomic_flag_test_and_set_explicit.c", - "atomic_signal_fence.c", - "atomic_thread_fence.c", + ("atomic_flag_clear", "atomic_flag_clear.c"), + ("atomic_flag_clear_explicit", "atomic_flag_clear_explicit.c"), + ("atomic_flag_test_and_set", "atomic_flag_test_and_set.c"), + ( + "atomic_flag_test_and_set_explicit", + "atomic_flag_test_and_set_explicit.c", + ), + ("atomic_signal_fence", "atomic_signal_fence.c"), + ("atomic_thread_fence", "atomic_thread_fence.c"), ]); } if target_env == "msvc" { if target_arch == "x86_64" { - sources.extend(&["x86_64/floatdisf.c", "x86_64/floatdixf.c"]); + sources.extend(&[ + ("__floatdisf", "x86_64/floatdisf.c"), + ("__floatdixf", "x86_64/floatdixf.c"), + ]); } } else { // None of these seem to be used on x86_64 windows, and they've all @@ -242,59 +246,59 @@ mod c { if target_os != "windows" { if target_arch == "x86_64" { sources.extend(&[ - "x86_64/floatdisf.c", - "x86_64/floatdixf.c", - "x86_64/floatundidf.S", - "x86_64/floatundisf.S", - "x86_64/floatundixf.S", + ("__floatdisf", "x86_64/floatdisf.c"), + ("__floatdixf", "x86_64/floatdixf.c"), + ("__floatundidf", "x86_64/floatundidf.S"), + ("__floatundisf", "x86_64/floatundisf.S"), + ("__floatundixf", "x86_64/floatundixf.S"), ]); } } if target_arch == "x86" { sources.extend(&[ - "i386/ashldi3.S", - "i386/ashrdi3.S", - "i386/divdi3.S", - "i386/floatdidf.S", - "i386/floatdisf.S", - "i386/floatdixf.S", - "i386/floatundidf.S", - "i386/floatundisf.S", - "i386/floatundixf.S", - "i386/lshrdi3.S", - "i386/moddi3.S", - "i386/muldi3.S", - "i386/udivdi3.S", - "i386/umoddi3.S", + ("__ashldi3", "i386/ashldi3.S"), + ("__ashrdi3", "i386/ashrdi3.S"), + ("__divdi3", "i386/divdi3.S"), + ("__floatdidf", "i386/floatdidf.S"), + ("__floatdisf", "i386/floatdisf.S"), + ("__floatdixf", "i386/floatdixf.S"), + ("__floatundidf", "i386/floatundidf.S"), + ("__floatundisf", "i386/floatundisf.S"), + ("__floatundixf", "i386/floatundixf.S"), + ("__lshrdi3", "i386/lshrdi3.S"), + ("__moddi3", "i386/moddi3.S"), + ("__muldi3", "i386/muldi3.S"), + ("__udivdi3", "i386/udivdi3.S"), + ("__umoddi3", "i386/umoddi3.S"), ]); } } if target_arch == "arm" && target_os != "ios" && target_env != "msvc" { sources.extend(&[ - "arm/aeabi_div0.c", - "arm/aeabi_drsub.c", - "arm/aeabi_frsub.c", - "arm/bswapdi2.S", - "arm/bswapsi2.S", - "arm/clzdi2.S", - "arm/clzsi2.S", - "arm/divmodsi4.S", - "arm/divsi3.S", - "arm/modsi3.S", - "arm/switch16.S", - "arm/switch32.S", - "arm/switch8.S", - "arm/switchu8.S", - "arm/sync_synchronize.S", - "arm/udivmodsi4.S", - "arm/udivsi3.S", - "arm/umodsi3.S", + ("__aeabi_div0", "arm/aeabi_div0.c"), + ("__aeabi_drsub", "arm/aeabi_drsub.c"), + ("__aeabi_frsub", "arm/aeabi_frsub.c"), + ("__bswapdi2", "arm/bswapdi2.S"), + ("__bswapsi2", "arm/bswapsi2.S"), + ("__clzdi2", "arm/clzdi2.S"), + ("__clzsi2", "arm/clzsi2.S"), + ("__divmodsi4", "arm/divmodsi4.S"), + ("__divsi3", "arm/divsi3.S"), + ("__modsi3", "arm/modsi3.S"), + ("__switch16", "arm/switch16.S"), + ("__switch32", "arm/switch32.S"), + ("__switch8", "arm/switch8.S"), + ("__switchu8", "arm/switchu8.S"), + ("__sync_synchronize", "arm/sync_synchronize.S"), + ("__udivmodsi4", "arm/udivmodsi4.S"), + ("__udivsi3", "arm/udivsi3.S"), + ("__umodsi3", "arm/umodsi3.S"), ]); if target_os == "freebsd" { - sources.extend(&["clear_cache.c"]); + sources.extend(&[("__clear_cache", "clear_cache.c")]); } // First of all aeabi_cdcmp and aeabi_cfcmp are never called by LLVM. @@ -302,36 +306,36 @@ mod c { // Temporally workaround: exclude these files for big-endian targets. if !llvm_target[0].starts_with("thumbeb") && !llvm_target[0].starts_with("armeb") { sources.extend(&[ - "arm/aeabi_cdcmp.S", - "arm/aeabi_cdcmpeq_check_nan.c", - "arm/aeabi_cfcmp.S", - "arm/aeabi_cfcmpeq_check_nan.c", + ("__aeabi_cdcmp", "arm/aeabi_cdcmp.S"), + ("__aeabi_cdcmpeq_check_nan", "arm/aeabi_cdcmpeq_check_nan.c"), + ("__aeabi_cfcmp", "arm/aeabi_cfcmp.S"), + ("__aeabi_cfcmpeq_check_nan", "arm/aeabi_cfcmpeq_check_nan.c"), ]); } } if llvm_target[0] == "armv7" { sources.extend(&[ - "arm/sync_fetch_and_add_4.S", - "arm/sync_fetch_and_add_8.S", - "arm/sync_fetch_and_and_4.S", - "arm/sync_fetch_and_and_8.S", - "arm/sync_fetch_and_max_4.S", - "arm/sync_fetch_and_max_8.S", - "arm/sync_fetch_and_min_4.S", - "arm/sync_fetch_and_min_8.S", - "arm/sync_fetch_and_nand_4.S", - "arm/sync_fetch_and_nand_8.S", - "arm/sync_fetch_and_or_4.S", - "arm/sync_fetch_and_or_8.S", - "arm/sync_fetch_and_sub_4.S", - "arm/sync_fetch_and_sub_8.S", - "arm/sync_fetch_and_umax_4.S", - "arm/sync_fetch_and_umax_8.S", - "arm/sync_fetch_and_umin_4.S", - "arm/sync_fetch_and_umin_8.S", - "arm/sync_fetch_and_xor_4.S", - "arm/sync_fetch_and_xor_8.S", + ("__sync_fetch_and_add_4", "arm/sync_fetch_and_add_4.S"), + ("__sync_fetch_and_add_8", "arm/sync_fetch_and_add_8.S"), + ("__sync_fetch_and_and_4", "arm/sync_fetch_and_and_4.S"), + ("__sync_fetch_and_and_8", "arm/sync_fetch_and_and_8.S"), + ("__sync_fetch_and_max_4", "arm/sync_fetch_and_max_4.S"), + ("__sync_fetch_and_max_8", "arm/sync_fetch_and_max_8.S"), + ("__sync_fetch_and_min_4", "arm/sync_fetch_and_min_4.S"), + ("__sync_fetch_and_min_8", "arm/sync_fetch_and_min_8.S"), + ("__sync_fetch_and_nand_4", "arm/sync_fetch_and_nand_4.S"), + ("__sync_fetch_and_nand_8", "arm/sync_fetch_and_nand_8.S"), + ("__sync_fetch_and_or_4", "arm/sync_fetch_and_or_4.S"), + ("__sync_fetch_and_or_8", "arm/sync_fetch_and_or_8.S"), + ("__sync_fetch_and_sub_4", "arm/sync_fetch_and_sub_4.S"), + ("__sync_fetch_and_sub_8", "arm/sync_fetch_and_sub_8.S"), + ("__sync_fetch_and_umax_4", "arm/sync_fetch_and_umax_4.S"), + ("__sync_fetch_and_umax_8", "arm/sync_fetch_and_umax_8.S"), + ("__sync_fetch_and_umin_4", "arm/sync_fetch_and_umin_4.S"), + ("__sync_fetch_and_umin_8", "arm/sync_fetch_and_umin_8.S"), + ("__sync_fetch_and_xor_4", "arm/sync_fetch_and_xor_4.S"), + ("__sync_fetch_and_xor_8", "arm/sync_fetch_and_xor_8.S"), ]); } @@ -345,73 +349,66 @@ mod c { // do not support double precision floating points conversions so the files // that include such instructions are not included for these targets. sources.extend(&[ - "arm/fixdfsivfp.S", - "arm/fixunsdfsivfp.S", - "arm/floatsidfvfp.S", - "arm/floatunssidfvfp.S", + ("__fixdfsivfp", "arm/fixdfsivfp.S"), + ("__fixunsdfsivfp", "arm/fixunsdfsivfp.S"), + ("__floatsidfvfp", "arm/floatsidfvfp.S"), + ("__floatunssidfvfp", "arm/floatunssidfvfp.S"), ]); } sources.extend(&[ - "arm/fixsfsivfp.S", - "arm/fixunssfsivfp.S", - "arm/floatsisfvfp.S", - "arm/floatunssisfvfp.S", - "arm/floatunssisfvfp.S", - "arm/restore_vfp_d8_d15_regs.S", - "arm/save_vfp_d8_d15_regs.S", - "arm/negdf2vfp.S", - "arm/negsf2vfp.S", + ("__fixsfsivfp", "arm/fixsfsivfp.S"), + ("__fixunssfsivfp", "arm/fixunssfsivfp.S"), + ("__floatsisfvfp", "arm/floatsisfvfp.S"), + ("__floatunssisfvfp", "arm/floatunssisfvfp.S"), + ("__floatunssisfvfp", "arm/floatunssisfvfp.S"), + ("__restore_vfp_d8_d15_regs", "arm/restore_vfp_d8_d15_regs.S"), + ("__save_vfp_d8_d15_regs", "arm/save_vfp_d8_d15_regs.S"), + ("__negdf2vfp", "arm/negdf2vfp.S"), + ("__negsf2vfp", "arm/negsf2vfp.S"), ]); } if target_arch == "aarch64" { sources.extend(&[ - "comparetf2.c", - "extenddftf2.c", - "extendsftf2.c", - "fixtfdi.c", - "fixtfsi.c", - "fixtfti.c", - "fixunstfdi.c", - "fixunstfsi.c", - "fixunstfti.c", - "floatditf.c", - "floatsitf.c", - "floatunditf.c", - "floatunsitf.c", - "trunctfdf2.c", - "trunctfsf2.c", + ("__comparetf2", "comparetf2.c"), + ("__extenddftf2", "extenddftf2.c"), + ("__extendsftf2", "extendsftf2.c"), + ("__fixtfdi", "fixtfdi.c"), + ("__fixtfsi", "fixtfsi.c"), + ("__fixtfti", "fixtfti.c"), + ("__fixunstfdi", "fixunstfdi.c"), + ("__fixunstfsi", "fixunstfsi.c"), + ("__fixunstfti", "fixunstfti.c"), + ("__floatditf", "floatditf.c"), + ("__floatsitf", "floatsitf.c"), + ("__floatunditf", "floatunditf.c"), + ("__floatunsitf", "floatunsitf.c"), + ("__trunctfdf2", "trunctfdf2.c"), + ("__trunctfsf2", "trunctfsf2.c"), ]); if target_os != "windows" { - sources.extend(&["multc3.c"]); + sources.extend(&[("__multc3", "multc3.c")]); } } // Remove the assembly implementations that won't compile for the target if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" { - sources.remove(&[ - "clzdi2", - "clzsi2", - "divmodsi4", - "divsi3", - "modsi3", - "switch16", - "switch32", - "switch8", - "switchu8", - "udivmodsi4", - "udivsi3", - "umodsi3", - ]); + let mut to_remove = Vec::new(); + for (k, v) in sources.map.iter() { + if v.ends_with(".S") { + to_remove.push(*k); + } + } + sources.remove(&to_remove); // But use some generic implementations where possible - sources.extend(&["clzdi2.c", "clzsi2.c"]) + sources.extend(&[("__clzdi2", "clzdi2.c"), ("__clzsi2", "clzsi2.c")]) } if llvm_target[0] == "thumbv7m" || llvm_target[0] == "thumbv7em" { - sources.remove(&["aeabi_cdcmp", "aeabi_cfcmp"]); + sources.remove(&["__aeabi_cdcmp", "__aeabi_cfcmp"]); } // When compiling in rustbuild (the rust-lang/rust repo) this build @@ -423,10 +420,11 @@ mod c { }; let src_dir = root.join("compiler-rt/lib/builtins"); - for src in sources.map.values() { + for (sym, src) in sources.map.iter() { let src = src_dir.join(src); cfg.file(&src); println!("cargo:rerun-if-changed={}", src.display()); + println!("cargo:rustc-cfg={}=\"optimized-c\"", sym); } cfg.compile("libcompiler-rt.a"); diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index ae32806ece8ea..4d6d6c68f1f6d 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -1,5 +1,6 @@ set -ex +export CARGO_INCREMENTAL=0 cargo=cargo # Test our implementation diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 21aac15c167ef..8a0fc6cb42479 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -87,11 +87,7 @@ intrinsics! { int_to_float!(i, i32, f64) } - #[use_c_shim_if(any( - all(target_arch = "x86", not(target_env = "msvc")), - all(target_arch = "x86_64", not(windows)), - all(target_arch = "x86_64", target_env = "msvc"), - ))] + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_l2f] pub extern "C" fn __floatdisf(i: i64) -> f32 { // On x86_64 LLVM will use native instructions for this conversion, we @@ -103,7 +99,7 @@ intrinsics! { } } - #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_l2d] pub extern "C" fn __floatdidf(i: i64) -> f64 { // On x86_64 LLVM will use native instructions for this conversion, we @@ -135,19 +131,13 @@ intrinsics! { int_to_float!(i, u32, f64) } - #[use_c_shim_if(any( - all(target_arch = "x86", not(target_env = "msvc")), - all(target_arch = "x86_64", not(windows)), - ))] + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_ul2f] pub extern "C" fn __floatundisf(i: u64) -> f32 { int_to_float!(i, u64, f32) } - #[use_c_shim_if(any( - all(target_arch = "x86", not(target_env = "msvc")), - all(target_arch = "x86_64", not(windows)), - ))] + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_ul2d] pub extern "C" fn __floatundidf(i: u64) -> f64 { int_to_float!(i, u64, f64) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index fd1f0c3c88138..7587bc69e7612 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -302,7 +302,7 @@ impl_wide_int!(u32, u64, 32); impl_wide_int!(u64, u128, 64); intrinsics! { - #[use_c_shim_if(/* always if C compilation is enabled */)] + #[maybe_use_optimized_c_shim] #[cfg(any( target_pointer_width = "16", target_pointer_width = "32", diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 376395ac04c85..8df58a27b6a5f 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -84,7 +84,7 @@ trait UMulo: Int { impl UMulo for u128 {} intrinsics! { - #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_lmul] pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 { a.mul(b) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 4b63697b425dc..ad7f67b1b4c9e 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -58,13 +58,13 @@ impl Divmod for i32 {} impl Divmod for i64 {} intrinsics! { - #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios"), not(thumb_1)))] + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_idiv] pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 { a.div(b) } - #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[maybe_use_optimized_c_shim] pub extern "C" fn __divdi3(a: i64, b: i64) -> i64 { a.div(b) } @@ -74,15 +74,12 @@ intrinsics! { a.div(b) } - #[use_c_shim_if(all(target_arch = "arm", - not(target_os = "ios"), - not(target_env = "msvc"), - not(thumb_1)))] + #[maybe_use_optimized_c_shim] pub extern "C" fn __modsi3(a: i32, b: i32) -> i32 { a.mod_(b) } - #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[maybe_use_optimized_c_shim] pub extern "C" fn __moddi3(a: i64, b: i64) -> i64 { a.mod_(b) } @@ -92,8 +89,7 @@ intrinsics! { a.mod_(b) } - #[use_c_shim_if(all(target_arch = "arm", not(target_env = "msvc"), - not(target_os = "ios"), not(thumb_1)))] + #[maybe_use_optimized_c_shim] pub extern "C" fn __divmodsi4(a: i32, b: i32, rem: &mut i32) -> i32 { a.divmod(b, rem, |a, b| __divsi3(a, b)) } diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 4be588f161ddd..d98622279e706 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -74,7 +74,7 @@ impl Lshr for u64 {} impl Lshr for u128 {} intrinsics! { - #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_llsl] pub extern "C" fn __ashldi3(a: u64, b: u32) -> u64 { a.ashl(b) @@ -84,7 +84,7 @@ intrinsics! { a.ashl(b) } - #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_lasr] pub extern "C" fn __ashrdi3(a: i64, b: u32) -> i64 { a.ashr(b) @@ -94,7 +94,7 @@ intrinsics! { a.ashr(b) } - #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_llsr] pub extern "C" fn __lshrdi3(a: u64, b: u32) -> u64 { a.lshr(b) diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 8837126deef8b..cdec11d2f16a3 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -152,9 +152,7 @@ macro_rules! udivmod_inner { } intrinsics! { - #[use_c_shim_if(all(target_arch = "arm", - not(target_os = "ios"), - not(thumb_1)))] + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_uidiv] /// Returns `n / d` pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { @@ -212,20 +210,14 @@ intrinsics! { (q << 1) | carry } - #[use_c_shim_if(all(target_arch = "arm", - not(target_os = "ios"), - not(target_env = "msvc"), - not(thumb_1)))] + #[maybe_use_optimized_c_shim] /// Returns `n % d` pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { let q = __udivsi3(n, d); n - q * d } - #[use_c_shim_if(all(target_arch = "arm", - not(target_os = "ios"), - not(target_env = "msvc"), - not(thumb_1)))] + #[maybe_use_optimized_c_shim] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { let q = __udivsi3(n, d); @@ -235,13 +227,13 @@ intrinsics! { q } - #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[maybe_use_optimized_c_shim] /// Returns `n / d` pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { __udivmoddi4(n, d, None) } - #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] + #[maybe_use_optimized_c_shim] /// Returns `n % d` pub extern "C" fn __umoddi3(n: u64, d: u64) -> u64 { let mut rem = 0; diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index e84338fae3974..4abdae6eee0cf 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -30,8 +30,8 @@ /// /// A quick overview of attributes supported right now are: /// -/// * `use_c_shim_if` - takes a #[cfg] directive and falls back to the -/// C-compiled version if `use_c` is specified. +/// * `maybe_use_optimized_c_shim` - indicates that the Rust implementation is +/// ignored if an optimized C version was compiled. /// * `aapcs_on_arm` - forces the ABI of the function to be `"aapcs"` on ARM and /// the specified ABI everywhere else. /// * `unadjusted_on_win64` - like `aapcs_on_arm` this switches to the @@ -51,15 +51,14 @@ macro_rules! intrinsics { // to the architecture-specific versions which should be more optimized. The // purpose of this macro is to easily allow specifying this. // - // The argument to `use_c_shim_if` is a `#[cfg]` directive which, when true, - // will cause this crate's exported version of `$name` to just redirect to - // the C implementation. No symbol named `$name` will be in the object file - // for this crate itself. - // - // When the `#[cfg]` directive is false, or when the `c` feature is - // disabled, the provided implementation is used instead. + // The `#[maybe_use_optimized_c_shim]` attribute indicates that this + // intrinsic may have an optimized C version. In these situations the build + // script, if the C code is enabled and compiled, will emit a cfg directive + // to get passed to rustc for our compilation. If that cfg is set we skip + // the Rust implementation, but if the attribute is not enabled then we + // compile in the Rust implementation. ( - #[use_c_shim_if($($cfg_clause:tt)*)] + #[maybe_use_optimized_c_shim] $(#[$($attr:tt)*])* pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { $($body:tt)* @@ -68,7 +67,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( - #[cfg(all(use_c, $($cfg_clause)*))] + #[cfg($name = "optimized-c")] pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { extern $abi { fn $name($($argname: $ty),*) -> $ret; @@ -78,7 +77,7 @@ macro_rules! intrinsics { } } - #[cfg(not(all(use_c, $($cfg_clause)*)))] + #[cfg(not($name = "optimized-c"))] intrinsics! { $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { From e6503aeea766eb94d603bd9f1360f570a833510c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 15 May 2019 14:47:58 -0700 Subject: [PATCH 0731/4206] Bump to 0.1.14 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index f08037432841b..5cea06e35eae4 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.13" +version = "0.1.14" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" From b84b7143e8523e9c3285ee91639b24a0b34bfd17 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 16 May 2019 07:30:36 -0700 Subject: [PATCH 0732/4206] Remove `compiler-rt` submodule from this repository This commit removes the `compiler-rt` submodule from this repository. The goal here is to align the `compiler-rt` used for compiling C intrinsics with the upstream rust-lang/rust's usage of `llvm-project`. Currently we have both an `llvm-project` repository as well as `compiler-rt`, but they can naturally get out of sync and it's just one more submodule to manage. The thinking here is that the feature `c` for this crate, when activated, will require the user to configure where the source code for `compiler-rt` is present. This places the onus on the builder of `compiler-builtins` to check-out and arrange for the appropriate `compiler-rt` source code to be placed somewhere. For rust-lang/rust this is already done with the `llvm-project` submodule, and we can arrange for it to happen on this crate's CI anyway. For users of this crate this is a bit of a bummer, but `c` is disabled by default anyway and it seems unlikely that `c` is explicitly opted in to all that much. (given the purpose of this crate) This should allow us to archive the `compiler-rt` repository and simply use `llvm-project` in the rust-lang/rust repository. --- library/compiler-builtins/.gitmodules | 3 --- library/compiler-builtins/build.rs | 20 ++++++++++++-------- library/compiler-builtins/ci/azure-steps.yml | 12 +++++++----- library/compiler-builtins/ci/run-docker.sh | 1 + library/compiler-builtins/ci/run.sh | 1 - library/compiler-builtins/compiler-rt | 1 - 6 files changed, 20 insertions(+), 18 deletions(-) delete mode 160000 library/compiler-builtins/compiler-rt diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index 50ed51e937b9d..a71118ff93e7f 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -1,6 +1,3 @@ -[submodule "compiler-rt"] - path = compiler-rt - url = https://github.com/rust-lang/compiler-rt [submodule "libm"] path = libm url = https://github.com/rust-lang-nursery/libm diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index be5d42bb76db2..c714bc15de308 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -76,7 +76,7 @@ mod c { use std::collections::BTreeMap; use std::env; - use std::path::Path; + use std::path::PathBuf; struct Sources { // SYMBOL -> PATH TO SOURCE @@ -411,15 +411,19 @@ mod c { sources.remove(&["__aeabi_cdcmp", "__aeabi_cfcmp"]); } - // When compiling in rustbuild (the rust-lang/rust repo) this build - // script runs from a directory other than this root directory. - let root = if cfg!(feature = "rustbuild") { - Path::new("../../libcompiler_builtins") - } else { - Path::new(".") + // When compiling the C code we require the user to tell us where the + // source code is, and this is largely done so when we're compiling as + // part of rust-lang/rust we can use the same llvm-project repository as + // rust-lang/rust. + let root = match env::var_os("RUST_COMPILER_RT_ROOT") { + Some(s) => PathBuf::from(s), + None => panic!("RUST_COMPILER_RT_ROOT is not set"), }; + if !root.exists() { + panic!("RUST_COMPILER_RT_ROOT={} does not exist", root.display()); + } - let src_dir = root.join("compiler-rt/lib/builtins"); + let src_dir = root.join("lib/builtins"); for (sym, src) in sources.map.iter() { let src = src_dir.join(src); cfg.file(&src); diff --git a/library/compiler-builtins/ci/azure-steps.yml b/library/compiler-builtins/ci/azure-steps.yml index c8a954024daca..f08beca05bfaf 100644 --- a/library/compiler-builtins/ci/azure-steps.yml +++ b/library/compiler-builtins/ci/azure-steps.yml @@ -4,13 +4,15 @@ steps: - template: azure-install-rust.yml - - script: rustup component add rust-src - displayName: Install Rust sources - condition: eq( variables['XARGO'], '1' ) - - bash: rustup target add $TARGET displayName: Install Rust target - condition: ne( variables['XARGO'], '1' ) + + - bash: | + set -e + curl -L https://github.com/rust-lang/llvm-project/archive/rustc/8.0-2019-03-18.tar.gz | \ + tar xzf - --strip-components 1 llvm-project-rustc-8.0-2019-03-18/compiler-rt + echo '##vso[task.setvariable variable=RUST_COMPILER_RT_ROOT]./compiler-rt' + displayName: "Download compiler-rt reference sources" - bash: ./ci/run.sh $TARGET condition: ne( variables['Agent.OS'], 'Linux' ) diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index ddb970c1b4a69..dbc86ca54d789 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -18,6 +18,7 @@ run() { --user $(id -u):$(id -g) \ -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ + -e RUST_COMPILER_RT_ROOT \ -v $HOME/.cargo:/cargo \ -v `pwd`/target:/target \ -v `pwd`:/checkout:ro \ diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 4d6d6c68f1f6d..ae32806ece8ea 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -1,6 +1,5 @@ set -ex -export CARGO_INCREMENTAL=0 cargo=cargo # Test our implementation diff --git a/library/compiler-builtins/compiler-rt b/library/compiler-builtins/compiler-rt deleted file mode 160000 index 03fc28f9273ee..0000000000000 --- a/library/compiler-builtins/compiler-rt +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 03fc28f9273eeab16f1005f982dfde5900bddb29 From 9c469738d6ad916f627a29e028f0fc37ff777206 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 16 May 2019 08:12:14 -0700 Subject: [PATCH 0733/4206] Bump to 0.1.15 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 5cea06e35eae4..755dcf5e35341 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.14" +version = "0.1.15" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" From c6b403f5a9db23cae323aa40358d2099de7d0dd1 Mon Sep 17 00:00:00 2001 From: Benjamin Schultzer Date: Thu, 16 May 2019 17:09:33 -0700 Subject: [PATCH 0734/4206] Run musl test in debug mode --- library/compiler-builtins/libm/ci/run.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index d288113003993..42c2416455d9d 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -6,7 +6,6 @@ TARGET=$1 cargo test --target $TARGET cargo test --target $TARGET --release -# FIXME(#4) overflow checks in non-release currently cause issues -#cargo test --features 'checked musl-reference-tests' --target $TARGET +cargo test --features 'checked musl-reference-tests' --target $TARGET cargo test --features 'checked musl-reference-tests' --target $TARGET --release From 332d8fd21c071529c89d953511488136ebb93113 Mon Sep 17 00:00:00 2001 From: Benjamin Schultzer Date: Thu, 16 May 2019 23:06:43 -0700 Subject: [PATCH 0735/4206] Add docs --- library/compiler-builtins/libm/src/math/acos.rs | 5 +++++ library/compiler-builtins/libm/src/math/acosf.rs | 5 +++++ library/compiler-builtins/libm/src/math/acosh.rs | 6 +++++- library/compiler-builtins/libm/src/math/acoshf.rs | 6 +++++- library/compiler-builtins/libm/src/math/asin.rs | 5 +++++ library/compiler-builtins/libm/src/math/asinf.rs | 5 +++++ library/compiler-builtins/libm/src/math/asinh.rs | 4 ++++ library/compiler-builtins/libm/src/math/asinhf.rs | 4 ++++ library/compiler-builtins/libm/src/math/atan.rs | 4 ++++ library/compiler-builtins/libm/src/math/atan2.rs | 5 +++++ library/compiler-builtins/libm/src/math/atan2f.rs | 5 +++++ library/compiler-builtins/libm/src/math/atanf.rs | 4 ++++ library/compiler-builtins/libm/src/math/atanh.rs | 4 ++++ library/compiler-builtins/libm/src/math/atanhf.rs | 4 ++++ library/compiler-builtins/libm/src/math/cbrt.rs | 3 +++ library/compiler-builtins/libm/src/math/cbrtf.rs | 3 +++ library/compiler-builtins/libm/src/math/ceil.rs | 3 +++ library/compiler-builtins/libm/src/math/ceilf.rs | 3 +++ library/compiler-builtins/libm/src/math/copysign.rs | 4 ++++ library/compiler-builtins/libm/src/math/copysignf.rs | 4 ++++ library/compiler-builtins/libm/src/math/cosh.rs | 5 +++++ library/compiler-builtins/libm/src/math/coshf.rs | 5 +++++ library/compiler-builtins/libm/src/math/erf.rs | 11 +++++++++++ library/compiler-builtins/libm/src/math/erff.rs | 11 +++++++++++ library/compiler-builtins/libm/src/math/exp.rs | 4 ++++ library/compiler-builtins/libm/src/math/exp2.rs | 4 ++++ library/compiler-builtins/libm/src/math/exp2f.rs | 4 ++++ library/compiler-builtins/libm/src/math/expf.rs | 4 ++++ library/compiler-builtins/libm/src/math/expm1.rs | 7 +++++++ library/compiler-builtins/libm/src/math/expm1f.rs | 7 +++++++ library/compiler-builtins/libm/src/math/fabs.rs | 3 +++ library/compiler-builtins/libm/src/math/fabsf.rs | 3 +++ library/compiler-builtins/libm/src/math/fdim.rs | 8 ++++++++ library/compiler-builtins/libm/src/math/fdimf.rs | 8 ++++++++ library/compiler-builtins/libm/src/math/floor.rs | 3 +++ library/compiler-builtins/libm/src/math/floorf.rs | 3 +++ library/compiler-builtins/libm/src/math/fma.rs | 5 +++++ library/compiler-builtins/libm/src/math/fmaf.rs | 6 ++++++ 38 files changed, 185 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/acos.rs b/library/compiler-builtins/libm/src/math/acos.rs index 055888ffa61d5..d5e1f6865adea 100644 --- a/library/compiler-builtins/libm/src/math/acos.rs +++ b/library/compiler-builtins/libm/src/math/acos.rs @@ -55,6 +55,11 @@ fn r(z: f64) -> f64 { p / q } +/// Arccosine (f64) +/// +/// Computes the inverse cosine (arc cosine) of the input value. +/// Arguments must be in the range -1 to 1. +/// Returns values in radians, in the range of 0 to pi. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn acos(x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/acosf.rs b/library/compiler-builtins/libm/src/math/acosf.rs index a6061ae8027b4..d0598e8119009 100644 --- a/library/compiler-builtins/libm/src/math/acosf.rs +++ b/library/compiler-builtins/libm/src/math/acosf.rs @@ -29,6 +29,11 @@ fn r(z: f32) -> f32 { p / q } +/// Arccosine (f32) +/// +/// Computes the inverse cosine (arc cosine) of the input value. +/// Arguments must be in the range -1 to 1. +/// Returns values in radians, in the range of 0 to pi. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn acosf(x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/acosh.rs b/library/compiler-builtins/libm/src/math/acosh.rs index 95dc57d811c9d..ac7a5f1c623b8 100644 --- a/library/compiler-builtins/libm/src/math/acosh.rs +++ b/library/compiler-builtins/libm/src/math/acosh.rs @@ -2,7 +2,11 @@ use super::{log, log1p, sqrt}; const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ -/* acosh(x) = log(x + sqrt(x*x-1)) */ +/// Inverse hyperbolic cosine (f64) +/// +/// Calculates the inverse hyperbolic cosine of `x`. +/// Is defined as `log(x + sqrt(x*x-1))`. +/// `x` must be a number greater than or equal to 1. pub fn acosh(x: f64) -> f64 { let u = x.to_bits(); let e = ((u >> 52) as usize) & 0x7ff; diff --git a/library/compiler-builtins/libm/src/math/acoshf.rs b/library/compiler-builtins/libm/src/math/acoshf.rs index f50a00324b198..0879e1edb0a50 100644 --- a/library/compiler-builtins/libm/src/math/acoshf.rs +++ b/library/compiler-builtins/libm/src/math/acoshf.rs @@ -2,7 +2,11 @@ use super::{log1pf, logf, sqrtf}; const LN2: f32 = 0.693147180559945309417232121458176568; -/* acosh(x) = log(x + sqrt(x*x-1)) */ +/// Inverse hyperbolic cosine (f32) +/// +/// Calculates the inverse hyperbolic cosine of `x`. +/// Is defined as `log(x + sqrt(x*x-1))`. +/// `x` must be a number greater than or equal to 1. pub fn acoshf(x: f32) -> f32 { let u = x.to_bits(); let a = u & 0x7fffffff; diff --git a/library/compiler-builtins/libm/src/math/asin.rs b/library/compiler-builtins/libm/src/math/asin.rs index 2aee72b286174..774475e519562 100644 --- a/library/compiler-builtins/libm/src/math/asin.rs +++ b/library/compiler-builtins/libm/src/math/asin.rs @@ -62,6 +62,11 @@ fn comp_r(z: f64) -> f64 { p / q } +/// Arcsine (f64) +/// +/// Computes the inverse sine (arc sine) of the argument `x`. +/// Arguments to asin must be in the range -1 to 1. +/// Returns values in radians, in the range of -pi/2 to pi/2. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn asin(mut x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/asinf.rs b/library/compiler-builtins/libm/src/math/asinf.rs index 979f1a6548fab..ce0f4a997e778 100644 --- a/library/compiler-builtins/libm/src/math/asinf.rs +++ b/library/compiler-builtins/libm/src/math/asinf.rs @@ -31,6 +31,11 @@ fn r(z: f32) -> f32 { p / q } +/// Arcsine (f32) +/// +/// Computes the inverse sine (arc sine) of the argument `x`. +/// Arguments to asin must be in the range -1 to 1. +/// Returns values in radians, in the range of -pi/2 to pi/2. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn asinf(mut x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/asinh.rs b/library/compiler-builtins/libm/src/math/asinh.rs index b29093b23472a..14295357a55e4 100644 --- a/library/compiler-builtins/libm/src/math/asinh.rs +++ b/library/compiler-builtins/libm/src/math/asinh.rs @@ -3,6 +3,10 @@ use super::{log, log1p, sqrt}; const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa39ef*/ /* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +/// Inverse hyperbolic sine (f64) +/// +/// Calculates the inverse hyperbolic sine of `x`. +/// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`. pub fn asinh(mut x: f64) -> f64 { let mut u = x.to_bits(); let e = ((u >> 52) as usize) & 0x7ff; diff --git a/library/compiler-builtins/libm/src/math/asinhf.rs b/library/compiler-builtins/libm/src/math/asinhf.rs index 9812433032b6a..e22a291323f6a 100644 --- a/library/compiler-builtins/libm/src/math/asinhf.rs +++ b/library/compiler-builtins/libm/src/math/asinhf.rs @@ -3,6 +3,10 @@ use super::{log1pf, logf, sqrtf}; const LN2: f32 = 0.693147180559945309417232121458176568; /* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +/// Inverse hyperbolic sine (f32) +/// +/// Calculates the inverse hyperbolic sine of `x`. +/// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`. pub fn asinhf(mut x: f32) -> f32 { let u = x.to_bits(); let i = u & 0x7fffffff; diff --git a/library/compiler-builtins/libm/src/math/atan.rs b/library/compiler-builtins/libm/src/math/atan.rs index 94594080cb83f..d2684ece8e936 100644 --- a/library/compiler-builtins/libm/src/math/atan.rs +++ b/library/compiler-builtins/libm/src/math/atan.rs @@ -60,6 +60,10 @@ const AT: [f64; 11] = [ 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */ ]; +/// Arctangent (f64) +/// +/// Computes the inverse tangent (arc tangent) of the input value. +/// Returns a value in radians, in the range of -pi/2 to pi/2. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atan(x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs index 313bec4b907b6..08385cd100e08 100644 --- a/library/compiler-builtins/libm/src/math/atan2.rs +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -43,6 +43,11 @@ use super::fabs; const PI: f64 = 3.1415926535897931160E+00; /* 0x400921FB, 0x54442D18 */ const PI_LO: f64 = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ +/// Arctangent of y/x (f64) +/// +/// Computes the inverse tangent (arc tangent) of `y/x`. +/// Produces the correct result even for angles near pi/2 or -pi/2 (that is, when `x` is near 0). +/// Returns a value in radians, in the range of -pi to pi. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atan2(y: f64, x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/atan2f.rs b/library/compiler-builtins/libm/src/math/atan2f.rs index 94e3c77186769..7bbe5f1d47a4c 100644 --- a/library/compiler-builtins/libm/src/math/atan2f.rs +++ b/library/compiler-builtins/libm/src/math/atan2f.rs @@ -19,6 +19,11 @@ use super::fabsf; const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ const PI_LO: f32 = -8.7422776573e-08; /* 0xb3bbbd2e */ +/// Arctangent of y/x (f32) +/// +/// Computes the inverse tangent (arc tangent) of `y/x`. +/// Produces the correct result even for angles near pi/2 or -pi/2 (that is, when `x` is near 0). +/// Returns a value in radians, in the range of -pi to pi. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atan2f(y: f32, x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/atanf.rs b/library/compiler-builtins/libm/src/math/atanf.rs index 89b0afd6fb0be..363e11d647dbb 100644 --- a/library/compiler-builtins/libm/src/math/atanf.rs +++ b/library/compiler-builtins/libm/src/math/atanf.rs @@ -37,6 +37,10 @@ const A_T: [f32; 5] = [ 6.1687607318e-02, ]; +/// Arctangent (f32) +/// +/// Computes the inverse tangent (arc tangent) of the input value. +/// Returns a value in radians, in the range of -pi/2 to pi/2. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atanf(mut x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/atanh.rs b/library/compiler-builtins/libm/src/math/atanh.rs index 2833715ab92cd..79a989c42d1c4 100644 --- a/library/compiler-builtins/libm/src/math/atanh.rs +++ b/library/compiler-builtins/libm/src/math/atanh.rs @@ -1,6 +1,10 @@ use super::log1p; /* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +/// Inverse hyperbolic tangent (f64) +/// +/// Calculates the inverse hyperbolic tangent of `x`. +/// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`. pub fn atanh(x: f64) -> f64 { let u = x.to_bits(); let e = ((u >> 52) as usize) & 0x7ff; diff --git a/library/compiler-builtins/libm/src/math/atanhf.rs b/library/compiler-builtins/libm/src/math/atanhf.rs index 709a955518228..7b2f34d97d4a2 100644 --- a/library/compiler-builtins/libm/src/math/atanhf.rs +++ b/library/compiler-builtins/libm/src/math/atanhf.rs @@ -1,6 +1,10 @@ use super::log1pf; /* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +/// Inverse hyperbolic tangent (f32) +/// +/// Calculates the inverse hyperbolic tangent of `x`. +/// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`. pub fn atanhf(mut x: f32) -> f32 { let mut u = x.to_bits(); let sign = (u >> 31) != 0; diff --git a/library/compiler-builtins/libm/src/math/cbrt.rs b/library/compiler-builtins/libm/src/math/cbrt.rs index ab11c497e12d9..04469b1598fce 100644 --- a/library/compiler-builtins/libm/src/math/cbrt.rs +++ b/library/compiler-builtins/libm/src/math/cbrt.rs @@ -27,6 +27,9 @@ 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. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cbrt(x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/cbrtf.rs b/library/compiler-builtins/libm/src/math/cbrtf.rs index 19215b8587bdd..6e589c0994da5 100644 --- a/library/compiler-builtins/libm/src/math/cbrtf.rs +++ b/library/compiler-builtins/libm/src/math/cbrtf.rs @@ -22,6 +22,9 @@ use core::f32; const B1: u32 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */ const B2: u32 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */ +/// Cube root (f32) +/// +/// Computes the cube root of the argument. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cbrtf(x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index d337db200bfe7..59883a8a7b988 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -2,6 +2,9 @@ use core::f64; const TOINT: f64 = 1. / f64::EPSILON; +/// Ceil (f64) +/// +/// Finds the nearest integer greater than or equal to `x`. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ceil(x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index 0be53c5cf3c8a..151a4f210420a 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -1,5 +1,8 @@ use core::f32; +/// Ceil (f32) +/// +/// Finds the nearest integer greater than or equal to `x`. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ceilf(x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/copysign.rs b/library/compiler-builtins/libm/src/math/copysign.rs index 9c5362a5a4772..1527fb6ea8b41 100644 --- a/library/compiler-builtins/libm/src/math/copysign.rs +++ b/library/compiler-builtins/libm/src/math/copysign.rs @@ -1,3 +1,7 @@ +/// Sign of Y, magnitude of X (f64) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. pub fn copysign(x: f64, y: f64) -> f64 { let mut ux = x.to_bits(); let uy = y.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/copysignf.rs b/library/compiler-builtins/libm/src/math/copysignf.rs index b42fd39ad558e..35148561a86d1 100644 --- a/library/compiler-builtins/libm/src/math/copysignf.rs +++ b/library/compiler-builtins/libm/src/math/copysignf.rs @@ -1,3 +1,7 @@ +/// Sign of Y, magnitude of X (f32) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. pub fn copysignf(x: f32, y: f32) -> f32 { let mut ux = x.to_bits(); let uy = y.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/cosh.rs b/library/compiler-builtins/libm/src/math/cosh.rs index b6ba338b55f2e..bac875566855d 100644 --- a/library/compiler-builtins/libm/src/math/cosh.rs +++ b/library/compiler-builtins/libm/src/math/cosh.rs @@ -2,6 +2,11 @@ use super::exp; use super::expm1; use super::k_expo2; +/// Hyperbolic cosine (f64) +/// +/// Computes the hyperbolic cosine of the argument x. +/// Is defined as `(exp(x) + exp(-x))/2` +/// Angles are specified in radians. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cosh(mut x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/coshf.rs b/library/compiler-builtins/libm/src/math/coshf.rs index b37ee1f3271b5..bf99e42f09b0c 100644 --- a/library/compiler-builtins/libm/src/math/coshf.rs +++ b/library/compiler-builtins/libm/src/math/coshf.rs @@ -2,6 +2,11 @@ use super::expf; use super::expm1f; use super::k_expo2f; +/// Hyperbolic cosine (f64) +/// +/// Computes the hyperbolic cosine of the argument x. +/// Is defined as `(exp(x) + exp(-x))/2` +/// Angles are specified in radians. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn coshf(mut x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/erf.rs b/library/compiler-builtins/libm/src/math/erf.rs index d53a4c83cd5be..a2c617d341da5 100644 --- a/library/compiler-builtins/libm/src/math/erf.rs +++ b/library/compiler-builtins/libm/src/math/erf.rs @@ -214,6 +214,11 @@ fn erfc2(ix: u32, mut x: f64) -> f64 { exp(-z * z - 0.5625) * exp((z - x) * (z + x) + r / big_s) / x } +/// Error function (f64) +/// +/// Calculates an approximation to the “error function”, which estimates +/// the probability that an observation will fall within x standard +/// deviations of the mean (assuming a normal distribution). pub fn erf(x: f64) -> f64 { let r: f64; let s: f64; @@ -257,6 +262,12 @@ pub fn erf(x: f64) -> f64 { } } +/// Error function (f64) +/// +/// Calculates the complementary probability. +/// Is `1 - erf(x)`. Is computed directly, so that you can use it to avoid +/// the loss of precision that would result from subtracting +/// large probabilities (on large `x`) from 1. pub fn erfc(x: f64) -> f64 { let r: f64; let s: f64; diff --git a/library/compiler-builtins/libm/src/math/erff.rs b/library/compiler-builtins/libm/src/math/erff.rs index ef67c335b0c7b..384052293fe15 100644 --- a/library/compiler-builtins/libm/src/math/erff.rs +++ b/library/compiler-builtins/libm/src/math/erff.rs @@ -125,6 +125,11 @@ fn erfc2(mut ix: u32, mut x: f32) -> f32 { expf(-z * z - 0.5625) * expf((z - x) * (z + x) + r / big_s) / x } +/// Error function (f32) +/// +/// Calculates an approximation to the “error function”, which estimates +/// the probability that an observation will fall within x standard +/// deviations of the mean (assuming a normal distribution). pub fn erff(x: f32) -> f32 { let r: f32; let s: f32; @@ -168,6 +173,12 @@ pub fn erff(x: f32) -> f32 { } } +/// Error function (f32) +/// +/// Calculates the complementary probability. +/// Is `1 - erf(x)`. Is computed directly, so that you can use it to avoid +/// the loss of precision that would result from subtracting +/// large probabilities (on large `x`) from 1. pub fn erfcf(x: f32) -> f32 { let r: f32; let s: f32; diff --git a/library/compiler-builtins/libm/src/math/exp.rs b/library/compiler-builtins/libm/src/math/exp.rs index c327731867965..5465b569346ff 100644 --- a/library/compiler-builtins/libm/src/math/exp.rs +++ b/library/compiler-builtins/libm/src/math/exp.rs @@ -77,6 +77,10 @@ const P3: f64 = 6.61375632143793436117e-05; /* 0x3F11566A, 0xAF25DE2C */ const P4: f64 = -1.65339022054652515390e-06; /* 0xBEBBBD41, 0xC5D26BF1 */ const P5: f64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ +/// Exponential, base *e* (f64) +/// +/// Calculate the exponential of `x`, that is, *e* raised to the power `x` +/// (where *e* is the base of the natural system of logarithms, approximately 2.71828). #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp(mut x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs index be6a003c6eeb6..570ca315b094e 100644 --- a/library/compiler-builtins/libm/src/math/exp2.rs +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -318,6 +318,10 @@ static TBL: [u64; TBLSIZE * 2] = [ // // Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library // for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). + +/// Exponential, base 2 (f64) +/// +/// Calculate `2^x`, that is, 2 raised to the power `x`. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp2(mut x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/exp2f.rs b/library/compiler-builtins/libm/src/math/exp2f.rs index 32816104b5c61..12c9e76a4c7a5 100644 --- a/library/compiler-builtins/libm/src/math/exp2f.rs +++ b/library/compiler-builtins/libm/src/math/exp2f.rs @@ -69,6 +69,10 @@ static EXP2FT: [u64; TBLSIZE] = [ // // Tang, P. Table-driven Implementation of the Exponential Function // in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989). + +/// Exponential, base 2 (f32) +/// +/// Calculate `2^x`, that is, 2 raised to the power `x`. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp2f(mut x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs index baade2552e12a..09323ec8de284 100644 --- a/library/compiler-builtins/libm/src/math/expf.rs +++ b/library/compiler-builtins/libm/src/math/expf.rs @@ -26,6 +26,10 @@ const INV_LN2: f32 = 1.4426950216e+00; /* 0x3fb8aa3b */ const P1: f32 = 1.6666625440e-1; /* 0xaaaa8f.0p-26 */ const P2: f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ +/// Exponential, base *e* (f32) +/// +/// Calculate the exponential of `x`, that is, *e* raised to the power `x` +/// (where *e* is the base of the natural system of logarithms, approximately 2.71828). #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn expf(mut x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/expm1.rs b/library/compiler-builtins/libm/src/math/expm1.rs index 42616399066c0..0d43b4e103d7a 100644 --- a/library/compiler-builtins/libm/src/math/expm1.rs +++ b/library/compiler-builtins/libm/src/math/expm1.rs @@ -23,6 +23,13 @@ const Q3: f64 = -7.93650757867487942473e-05; /* BF14CE19 9EAADBB7 */ const Q4: f64 = 4.00821782732936239552e-06; /* 3ED0CFCA 86E65239 */ const Q5: f64 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ +/// Exponential, base *e*, of x-1 (f64) +/// +/// Calculates the exponential of `x` and subtract 1, that is, *e* raised +/// to the power `x` minus 1 (where *e* is the base of the natural +/// system of logarithms, approximately 2.71828). +/// The result is accurate even for small values of `x`, +/// where using `exp(x)-1` would lose many significant digits. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn expm1(mut x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/expm1f.rs b/library/compiler-builtins/libm/src/math/expm1f.rs index 4daa83c856543..9bb22344889e9 100644 --- a/library/compiler-builtins/libm/src/math/expm1f.rs +++ b/library/compiler-builtins/libm/src/math/expm1f.rs @@ -25,6 +25,13 @@ const INV_LN2: f32 = 1.4426950216e+00; /* 0x3fb8aa3b */ const Q1: f32 = -3.3333212137e-2; /* -0x888868.0p-28 */ const Q2: f32 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ +/// Exponential, base *e*, of x-1 (f32) +/// +/// Calculates the exponential of `x` and subtract 1, that is, *e* raised +/// to the power `x` minus 1 (where *e* is the base of the natural +/// system of logarithms, approximately 2.71828). +/// The result is accurate even for small values of `x`, +/// where using `exp(x)-1` would lose many significant digits. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn expm1f(mut x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index 0824bd593586a..52a9adcbff1b0 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -1,5 +1,8 @@ use core::u64; +/// Absolute value (magnitude) (f64) +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fabs(x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index 859508f9b539f..5942d983a4b04 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -1,3 +1,6 @@ +/// Absolute value (magnitude) (f32) +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fabsf(x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/fdim.rs b/library/compiler-builtins/libm/src/math/fdim.rs index d9aca86115815..06edc99603551 100644 --- a/library/compiler-builtins/libm/src/math/fdim.rs +++ b/library/compiler-builtins/libm/src/math/fdim.rs @@ -1,5 +1,13 @@ use core::f64; +/// Positive difference (f64) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fdim(x: f64, y: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/src/math/fdimf.rs index bcda8ee94f9bd..f1ad5896bf993 100644 --- a/library/compiler-builtins/libm/src/math/fdimf.rs +++ b/library/compiler-builtins/libm/src/math/fdimf.rs @@ -1,5 +1,13 @@ use core::f32; +/// Positive difference (f32) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fdimf(x: f32, y: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index c705ae501a9ba..f6068c697ac05 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -2,6 +2,9 @@ use core::f64; const TOINT: f64 = 1. / f64::EPSILON; +/// Floor (f64) +/// +/// Finds the nearest integer less than or equal to `x`. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn floor(x: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index 899dcf5a51268..ae605e1918f68 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -1,5 +1,8 @@ use core::f32; +/// Floor (f64) +/// +/// Finds the nearest integer less than or equal to `x`. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn floorf(x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 6b062481dcafb..07d90f8b727d2 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -48,6 +48,11 @@ fn mul(x: u64, y: u64) -> (u64, u64) { (hi, lo) } +/// Floating multiply add (f64) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation: +/// Computes the value (as if) to infinite precision and rounds once to the result format, +/// according to the rounding mode characterized by the value of FLT_ROUNDS. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fma(x: f64, y: f64, z: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/fmaf.rs b/library/compiler-builtins/libm/src/math/fmaf.rs index 9e5a55f44b648..e77e0fa4a2535 100644 --- a/library/compiler-builtins/libm/src/math/fmaf.rs +++ b/library/compiler-builtins/libm/src/math/fmaf.rs @@ -40,6 +40,12 @@ use super::fenv::{ * direct double-precision arithmetic suffices, except where double * rounding occurs. */ + +/// Floating multiply add (f32) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation: +/// Computes the value (as if) to infinite precision and rounds once to the result format, +/// according to the rounding mode characterized by the value of FLT_ROUNDS. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { From 3b18638b987b82221c5c6d6a466caa09883aefd1 Mon Sep 17 00:00:00 2001 From: Sean Leather Date: Tue, 21 May 2019 08:43:50 +0200 Subject: [PATCH 0736/4206] Fix typo: mingw_unwinding --- library/compiler-builtins/examples/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 3debffa450a38..f6980fcb56649 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -399,7 +399,7 @@ pub fn _Unwind_Resume() {} pub extern "C" fn eh_personality() {} #[cfg(all(windows, target_env = "gnu"))] -mod mingw_unwidning { +mod mingw_unwinding { #[no_mangle] pub fn rust_eh_personality() {} #[no_mangle] From 5c48fccd6c2533772c88fb33564aebc6df35031e Mon Sep 17 00:00:00 2001 From: Igor null Date: Mon, 3 Jun 2019 13:16:03 +0300 Subject: [PATCH 0737/4206] fixed add overflow in exp2 --- library/compiler-builtins/libm/src/math/exp2.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs index 570ca315b094e..c2192fde5a088 100644 --- a/library/compiler-builtins/libm/src/math/exp2.rs +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -373,7 +373,7 @@ pub fn exp2(mut x: f64) -> f64 { /* Reduce x, computing z, i0, and k. */ let ui = f64::to_bits(x + redux); let mut i0 = ui as u32; - i0 += TBLSIZE as u32 / 2; + i0 = i0.wrapping_add(TBLSIZE as u32 / 2); let ku = i0 / TBLSIZE as u32 * TBLSIZE as u32; let ki = ku as i32 / TBLSIZE as i32; i0 %= TBLSIZE as u32; @@ -387,3 +387,9 @@ pub fn exp2(mut x: f64) -> f64 { scalbn(r, ki) } + +#[test] +fn i0_wrap_test() { + let x = -3.0 / 256.0; + assert_eq!(exp2(x), f64::from_bits(0x3fefbdba3692d514)); +} From 13a350ca5df471f717107a0fe500ea547a471636 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 5 Jun 2019 12:14:53 -0700 Subject: [PATCH 0738/4206] Attempt to fix CI --- .../libm/ci/azure-install-rust.yml | 14 ++++++++------ library/compiler-builtins/libm/ci/run-docker.sh | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/libm/ci/azure-install-rust.yml b/library/compiler-builtins/libm/ci/azure-install-rust.yml index fa7eae459b796..c5a53122f8eba 100644 --- a/library/compiler-builtins/libm/ci/azure-install-rust.yml +++ b/library/compiler-builtins/libm/ci/azure-install-rust.yml @@ -5,15 +5,17 @@ steps: if [ "$toolchain" = "" ]; then toolchain=stable fi - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $toolchain - echo "##vso[task.prependpath]$HOME/.cargo/bin" + if command -v rustup; then + rustup update $toolchain + rustup default $toolchain + else + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $toolchain + echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin" + fi displayName: Install rust (unix) condition: ne( variables['Agent.OS'], 'Windows_NT' ) - - script: | - curl -sSf -o rustup-init.exe https://win.rustup.rs - rustup-init.exe -y --default-toolchain stable-%TARGET% - echo ##vso[task.prependpath]%USERPROFILE%\.cargo\bin + - bash: rustup update stable-$TOOLCHAIN && rustup default stable-$TOOLCHAIN displayName: Install rust (windows) condition: eq( variables['Agent.OS'], 'Windows_NT' ) diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh index 95bd3db4836ec..e7b80c719e5ca 100755 --- a/library/compiler-builtins/libm/ci/run-docker.sh +++ b/library/compiler-builtins/libm/ci/run-docker.sh @@ -18,7 +18,7 @@ run() { --user $(id -u):$(id -g) \ -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ - -v $HOME/.cargo:/cargo \ + -v $(dirname $(dirname `which cargo`)):/cargo \ -v `pwd`/target:/target \ -v `pwd`:/checkout:ro \ -v `rustc --print sysroot`:/rust:ro \ From f1c957e83237864e1f9c21c9fbebedd24ad54845 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 5 Jun 2019 17:43:46 +0100 Subject: [PATCH 0739/4206] Add minf --- library/compiler-builtins/libm/CHANGELOG.md | 4 ++++ library/compiler-builtins/libm/src/lib.rs | 7 +++++++ library/compiler-builtins/libm/src/math/minf.rs | 13 +++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 2 ++ 4 files changed, 26 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/minf.rs diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index 1cc396455f391..f8d4e98f043de 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -5,6 +5,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Added + +- minf + ## [v0.1.2] - 2018-07-18 ### Added diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 0d0f6155abe88..763920cc5437d 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -136,6 +136,8 @@ pub trait F32Ext: private::Sealed + Sized { fn acosh(self) -> Self; fn atanh(self) -> Self; + + fn min(self, other: Self) -> Self; } impl F32Ext for f32 { @@ -327,6 +329,11 @@ impl F32Ext for f32 { fn atanh(self) -> Self { atanhf(self) } + + #[inline] + fn min(self, other: Self) -> Self { + minf(self, other) + } } /// Math support for `f64` diff --git a/library/compiler-builtins/libm/src/math/minf.rs b/library/compiler-builtins/libm/src/math/minf.rs new file mode 100644 index 0000000000000..2098a2d75c0c8 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/minf.rs @@ -0,0 +1,13 @@ +#[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn minf(x: f32, y: f32) -> f32 { + // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if y.is_nan() || x < y { x } else { y }) * 1.0 +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index c4d247414690e..90c5fd311a791 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -166,6 +166,7 @@ mod tgamma; mod tgammaf; mod trunc; mod truncf; +mod minf; // Use separated imports instead of {}-grouped imports for easier merging. pub use self::acos::acos; @@ -272,6 +273,7 @@ pub use self::tgamma::tgamma; pub use self::tgammaf::tgammaf; pub use self::trunc::trunc; pub use self::truncf::truncf; +pub use self::minf::minf; // Private modules mod expo2; From 193e7960f9fc9c76690fe0cb536fe67758e48e67 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 5 Jun 2019 17:44:06 +0100 Subject: [PATCH 0740/4206] Add min --- library/compiler-builtins/libm/CHANGELOG.md | 1 + library/compiler-builtins/libm/src/lib.rs | 7 +++++++ library/compiler-builtins/libm/src/math/min.rs | 13 +++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 2 ++ 4 files changed, 23 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/min.rs diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index f8d4e98f043de..4ecd8c8ab763d 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -8,6 +8,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added - minf +- min ## [v0.1.2] - 2018-07-18 diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 763920cc5437d..b72b58c1f44df 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -417,6 +417,8 @@ pub trait F64Ext: private::Sealed + Sized { fn acosh(self) -> Self; fn atanh(self) -> Self; + + fn min(self, other: Self) -> Self; } impl F64Ext for f64 { @@ -608,6 +610,11 @@ impl F64Ext for f64 { fn atanh(self) -> Self { atanh(self) } + + #[inline] + fn min(self, other: Self) -> Self { + min(self, other) + } } mod private { diff --git a/library/compiler-builtins/libm/src/math/min.rs b/library/compiler-builtins/libm/src/math/min.rs new file mode 100644 index 0000000000000..d0345cf8d4d2e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/min.rs @@ -0,0 +1,13 @@ +#[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn min(x: f64, y: f64) -> f64 { + // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if y.is_nan() || x < y { x } else { y }) * 1.0 +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 90c5fd311a791..e2d706201d972 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -166,6 +166,7 @@ mod tgamma; mod tgammaf; mod trunc; mod truncf; +mod min; mod minf; // Use separated imports instead of {}-grouped imports for easier merging. @@ -273,6 +274,7 @@ pub use self::tgamma::tgamma; pub use self::tgammaf::tgammaf; pub use self::trunc::trunc; pub use self::truncf::truncf; +pub use self::min::min; pub use self::minf::minf; // Private modules From a3c8111c5f895f8dc09884edaea915430792a346 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 5 Jun 2019 17:44:20 +0100 Subject: [PATCH 0741/4206] Add maxf --- library/compiler-builtins/libm/CHANGELOG.md | 1 + library/compiler-builtins/libm/src/lib.rs | 7 +++++++ library/compiler-builtins/libm/src/math/maxf.rs | 13 +++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 2 ++ 4 files changed, 23 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/maxf.rs diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index 4ecd8c8ab763d..7fb17cc9fbf80 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -9,6 +9,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - minf - min +- maxf ## [v0.1.2] - 2018-07-18 diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index b72b58c1f44df..368e25c8cfa32 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -138,6 +138,8 @@ pub trait F32Ext: private::Sealed + Sized { fn atanh(self) -> Self; fn min(self, other: Self) -> Self; + + fn max(self, other: Self) -> Self; } impl F32Ext for f32 { @@ -334,6 +336,11 @@ impl F32Ext for f32 { fn min(self, other: Self) -> Self { minf(self, other) } + + #[inline] + fn max(self, other: Self) -> Self { + maxf(self, other) + } } /// Math support for `f64` diff --git a/library/compiler-builtins/libm/src/math/maxf.rs b/library/compiler-builtins/libm/src/math/maxf.rs new file mode 100644 index 0000000000000..ac0d22aa5f903 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/maxf.rs @@ -0,0 +1,13 @@ +#[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn maxf(x: f32, y: f32) -> f32 { + // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if x.is_nan() || x < y { y } else { x }) * 1.0 +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index e2d706201d972..9feadce7d1a6a 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -168,6 +168,7 @@ mod trunc; mod truncf; mod min; mod minf; +mod maxf; // Use separated imports instead of {}-grouped imports for easier merging. pub use self::acos::acos; @@ -276,6 +277,7 @@ pub use self::trunc::trunc; pub use self::truncf::truncf; pub use self::min::min; pub use self::minf::minf; +pub use self::maxf::maxf; // Private modules mod expo2; From 2db94e02d8571adb956af807e4eae2e6b54f0963 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 5 Jun 2019 17:44:24 +0100 Subject: [PATCH 0742/4206] Add max --- library/compiler-builtins/libm/CHANGELOG.md | 1 + library/compiler-builtins/libm/src/lib.rs | 7 +++++++ library/compiler-builtins/libm/src/math/max.rs | 13 +++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 2 ++ 4 files changed, 23 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/max.rs diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index 7fb17cc9fbf80..d7667c0a11622 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - minf - min - maxf +- max ## [v0.1.2] - 2018-07-18 diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 368e25c8cfa32..f77cda94bdf00 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -426,6 +426,8 @@ pub trait F64Ext: private::Sealed + Sized { fn atanh(self) -> Self; fn min(self, other: Self) -> Self; + + fn max(self, other: Self) -> Self; } impl F64Ext for f64 { @@ -622,6 +624,11 @@ impl F64Ext for f64 { fn min(self, other: Self) -> Self { min(self, other) } + + #[inline] + fn max(self, other: Self) -> Self { + max(self, other) + } } mod private { diff --git a/library/compiler-builtins/libm/src/math/max.rs b/library/compiler-builtins/libm/src/math/max.rs new file mode 100644 index 0000000000000..3fbb480249a7c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/max.rs @@ -0,0 +1,13 @@ +#[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn max(x: f64, y: f64) -> f64 { + // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if x.is_nan() || x < y { y } else { x }) * 1.0 +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 9feadce7d1a6a..c2bc9a4750f6d 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -168,6 +168,7 @@ mod trunc; mod truncf; mod min; mod minf; +mod max; mod maxf; // Use separated imports instead of {}-grouped imports for easier merging. @@ -277,6 +278,7 @@ pub use self::trunc::trunc; pub use self::truncf::truncf; pub use self::min::min; pub use self::minf::minf; +pub use self::max::max; pub use self::maxf::maxf; // Private modules From 1613fbc4121bd4a19914089f779010e0795917bf Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 5 Jun 2019 20:59:05 +0100 Subject: [PATCH 0743/4206] Alphabetise --- library/compiler-builtins/libm/src/math/mod.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index c2bc9a4750f6d..bedc3a69e5bd1 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -140,6 +140,10 @@ mod log1pf; mod log2; mod log2f; mod logf; +mod max; +mod maxf; +mod min; +mod minf; mod modf; mod modff; mod pow; @@ -166,10 +170,6 @@ mod tgamma; mod tgammaf; mod trunc; mod truncf; -mod min; -mod minf; -mod max; -mod maxf; // Use separated imports instead of {}-grouped imports for easier merging. pub use self::acos::acos; @@ -250,6 +250,10 @@ pub use self::log1pf::log1pf; pub use self::log2::log2; pub use self::log2f::log2f; pub use self::logf::logf; +pub use self::max::max; +pub use self::maxf::maxf; +pub use self::min::min; +pub use self::minf::minf; pub use self::modf::modf; pub use self::modff::modff; pub use self::pow::pow; @@ -276,10 +280,6 @@ pub use self::tgamma::tgamma; pub use self::tgammaf::tgammaf; pub use self::trunc::trunc; pub use self::truncf::truncf; -pub use self::min::min; -pub use self::minf::minf; -pub use self::max::max; -pub use self::maxf::maxf; // Private modules mod expo2; From 727722531e56206b1804937480bef563482d6c55 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 5 Jun 2019 21:13:25 +0100 Subject: [PATCH 0744/4206] Correct libm names --- library/compiler-builtins/libm/CHANGELOG.md | 6 +++--- library/compiler-builtins/libm/src/lib.rs | 8 ++++---- .../libm/src/math/{max.rs => fmax.rs} | 2 +- .../libm/src/math/{maxf.rs => fmaxf.rs} | 2 +- .../libm/src/math/{min.rs => fmin.rs} | 2 +- .../libm/src/math/{minf.rs => fminf.rs} | 2 +- library/compiler-builtins/libm/src/math/mod.rs | 16 ++++++++-------- 7 files changed, 19 insertions(+), 19 deletions(-) rename library/compiler-builtins/libm/src/math/{max.rs => fmax.rs} (95%) rename library/compiler-builtins/libm/src/math/{maxf.rs => fmaxf.rs} (95%) rename library/compiler-builtins/libm/src/math/{min.rs => fmin.rs} (95%) rename library/compiler-builtins/libm/src/math/{minf.rs => fminf.rs} (95%) diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index d7667c0a11622..62bfd0d5b9437 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -8,9 +8,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added - minf -- min -- maxf -- max +- fmin +- fmaxf +- fmax ## [v0.1.2] - 2018-07-18 diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index f77cda94bdf00..df3c8cf601ae8 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -334,12 +334,12 @@ impl F32Ext for f32 { #[inline] fn min(self, other: Self) -> Self { - minf(self, other) + fminf(self, other) } #[inline] fn max(self, other: Self) -> Self { - maxf(self, other) + fmaxf(self, other) } } @@ -622,12 +622,12 @@ impl F64Ext for f64 { #[inline] fn min(self, other: Self) -> Self { - min(self, other) + fmin(self, other) } #[inline] fn max(self, other: Self) -> Self { - max(self, other) + fmax(self, other) } } diff --git a/library/compiler-builtins/libm/src/math/max.rs b/library/compiler-builtins/libm/src/math/fmax.rs similarity index 95% rename from library/compiler-builtins/libm/src/math/max.rs rename to library/compiler-builtins/libm/src/math/fmax.rs index 3fbb480249a7c..22016d11cc668 100644 --- a/library/compiler-builtins/libm/src/math/max.rs +++ b/library/compiler-builtins/libm/src/math/fmax.rs @@ -1,6 +1,6 @@ #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn max(x: f64, y: f64) -> f64 { +pub fn fmax(x: f64, y: f64) -> f64 { // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it // is either x or y, canonicalized (this means results might differ among implementations). diff --git a/library/compiler-builtins/libm/src/math/maxf.rs b/library/compiler-builtins/libm/src/math/fmaxf.rs similarity index 95% rename from library/compiler-builtins/libm/src/math/maxf.rs rename to library/compiler-builtins/libm/src/math/fmaxf.rs index ac0d22aa5f903..a883fdaef5bc0 100644 --- a/library/compiler-builtins/libm/src/math/maxf.rs +++ b/library/compiler-builtins/libm/src/math/fmaxf.rs @@ -1,6 +1,6 @@ #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn maxf(x: f32, y: f32) -> f32 { +pub fn fmaxf(x: f32, y: f32) -> f32 { // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it // is either x or y, canonicalized (this means results might differ among implementations). diff --git a/library/compiler-builtins/libm/src/math/min.rs b/library/compiler-builtins/libm/src/math/fmin.rs similarity index 95% rename from library/compiler-builtins/libm/src/math/min.rs rename to library/compiler-builtins/libm/src/math/fmin.rs index d0345cf8d4d2e..d1ccc3a468088 100644 --- a/library/compiler-builtins/libm/src/math/min.rs +++ b/library/compiler-builtins/libm/src/math/fmin.rs @@ -1,6 +1,6 @@ #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn min(x: f64, y: f64) -> f64 { +pub fn fmin(x: f64, y: f64) -> f64 { // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it // is either x or y, canonicalized (this means results might differ among implementations). diff --git a/library/compiler-builtins/libm/src/math/minf.rs b/library/compiler-builtins/libm/src/math/fminf.rs similarity index 95% rename from library/compiler-builtins/libm/src/math/minf.rs rename to library/compiler-builtins/libm/src/math/fminf.rs index 2098a2d75c0c8..43ec97cb5b57e 100644 --- a/library/compiler-builtins/libm/src/math/minf.rs +++ b/library/compiler-builtins/libm/src/math/fminf.rs @@ -1,6 +1,6 @@ #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn minf(x: f32, y: f32) -> f32 { +pub fn fminf(x: f32, y: f32) -> f32 { // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it // is either x or y, canonicalized (this means results might differ among implementations). diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index bedc3a69e5bd1..35ffe1a2cb242 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -112,6 +112,10 @@ mod floor; mod floorf; mod fma; mod fmaf; +mod fmax; +mod fmaxf; +mod fmin; +mod fminf; mod fmod; mod fmodf; mod frexp; @@ -140,10 +144,6 @@ mod log1pf; mod log2; mod log2f; mod logf; -mod max; -mod maxf; -mod min; -mod minf; mod modf; mod modff; mod pow; @@ -216,6 +216,10 @@ pub use self::floor::floor; pub use self::floorf::floorf; pub use self::fma::fma; pub use self::fmaf::fmaf; +pub use self::fmax::fmax; +pub use self::fmaxf::fmaxf; +pub use self::fmin::fmin; +pub use self::fminf::fminf; pub use self::fmod::fmod; pub use self::fmodf::fmodf; pub use self::frexp::frexp; @@ -250,10 +254,6 @@ pub use self::log1pf::log1pf; pub use self::log2::log2; pub use self::log2f::log2f; pub use self::logf::logf; -pub use self::max::max; -pub use self::maxf::maxf; -pub use self::min::min; -pub use self::minf::minf; pub use self::modf::modf; pub use self::modff::modff; pub use self::pow::pow; From 3fe09ab411fafd90ef5b2e1504c4bf33742d7874 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 5 Jun 2019 21:32:31 +0100 Subject: [PATCH 0745/4206] Update libm for fmin/fmax/fminf/fmaxf --- library/compiler-builtins/libm | 2 +- library/compiler-builtins/src/math.rs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 0ae442888c7af..01bee72a93eba 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 0ae442888c7af72c0a335edd43dbbd74c751f119 +Subproject commit 01bee72a93ebaeea2883d0f963174c2b00d4fe68 diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 1893f1c166bac..4b27cb80f6834 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -45,6 +45,10 @@ no_mangle! { fn log10f(x: f32) -> f32; fn log(x: f64) -> f64; fn logf(x: f32) -> f32; + fn fmin(x: f64, y: f64) -> f64; + fn fminf(x: f32, y: f32) -> f32; + fn fmax(x: f64, y: f64) -> f64; + fn fmaxf(x: f32, y: f32) -> f32; fn round(x: f64) -> f64; fn roundf(x: f32) -> f32; fn sin(x: f64) -> f64; From 0d83008f7ac55d854d9ff2fac8a03c7bd42915d0 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 5 Jun 2019 16:09:27 -0700 Subject: [PATCH 0746/4206] Attempt to fix CI --- .../compiler-builtins/ci/azure-install-rust.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/ci/azure-install-rust.yml b/library/compiler-builtins/ci/azure-install-rust.yml index f44f8c59dc6f4..d0255f85b2798 100644 --- a/library/compiler-builtins/ci/azure-install-rust.yml +++ b/library/compiler-builtins/ci/azure-install-rust.yml @@ -4,17 +4,21 @@ parameters: steps: - bash: | set -e - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $TOOLCHAIN - echo "##vso[task.prependpath]$HOME/.cargo/bin" + if command -v rustup; then + rustup update $TOOLCHAIN + rustup default $TOOLCHAIN + else + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $TOOLCHAIN + echo "##vso[task.prependpath]$HOME/.cargo/bin" + fi displayName: Install rust condition: ne( variables['Agent.OS'], 'Windows_NT' ) env: TOOLCHAIN: ${{ parameters.toolchain }} - script: | - curl -sSf -o rustup-init.exe https://win.rustup.rs - rustup-init.exe -y --default-toolchain %TOOLCHAIN%-%TARGET% - echo ##vso[task.prependpath]%USERPROFILE%\.cargo\bin + rustup update --no-self-update %TOOLCHAIN%-%TARGET% + rustup default %TOOLCHAIN%-%TARGET% displayName: Install rust condition: eq( variables['Agent.OS'], 'Windows_NT' ) env: From 22030968eb31afd7acf0a3916d38e66b73577420 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 5 Jun 2019 16:19:26 -0700 Subject: [PATCH 0747/4206] More fixes for CI --- library/compiler-builtins/ci/run-docker.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index dbc86ca54d789..4bb2a78d9342b 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -19,7 +19,7 @@ run() { -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ -e RUST_COMPILER_RT_ROOT \ - -v $HOME/.cargo:/cargo \ + -v $(dirname $(dirname `which cargo`)):/cargo \ -v `pwd`/target:/target \ -v `pwd`:/checkout:ro \ -v `rustc --print sysroot`:/rust:ro \ From 319ae3ab428c0e6920ecd45315450385354ba549 Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 6 Jun 2019 01:09:47 +0100 Subject: [PATCH 0748/4206] Bump to 0.1.16 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 755dcf5e35341..e0bb22d218af7 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.15" +version = "0.1.16" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" From c955dbe5d03779eddaa127a3d64d123587957d01 Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Fri, 7 Jun 2019 18:23:43 +0200 Subject: [PATCH 0749/4206] Make module path compatible with Rust 1.31.0 --- library/compiler-builtins/libm/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index df3c8cf601ae8..a47883d81bb2d 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -20,7 +20,7 @@ mod math; use core::{f32, f64}; -pub use math::*; +pub use self::math::*; /// Approximate equality with 1 ULP of tolerance #[doc(hidden)] From 9df2e2151ce8c956109d4a8bd54891bbe245bf7d Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Wed, 12 Jun 2019 18:43:12 +0200 Subject: [PATCH 0750/4206] Add 0.1.3 changelog entry --- library/compiler-builtins/libm/CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index 62bfd0d5b9437..aef65cfb3c858 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -5,6 +5,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +... + +## [v0.1.3] - 2019-05-14 + ### Added - minf @@ -81,6 +85,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Initial release -[Unreleased]: https://github.com/japaric/libm/compare/v0.1.2...HEAD +[Unreleased]: https://github.com/japaric/libm/compare/0.1.3...HEAD +[v0.1.3]: https://github.com/japaric/libm/compare/v0.1.2...0.1.3 [v0.1.2]: https://github.com/japaric/libm/compare/v0.1.1...v0.1.2 [v0.1.1]: https://github.com/japaric/libm/compare/v0.1.0...v0.1.1 From 1319dfac2cae4b4ae7de4b681faa7b1b8d5e0786 Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Wed, 12 Jun 2019 18:45:42 +0200 Subject: [PATCH 0751/4206] Add changelog entry for v0.1.4 release --- library/compiler-builtins/libm/CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index aef65cfb3c858..28e27055dfd3e 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -7,6 +7,11 @@ This project adheres to [Semantic Versioning](http://semver.org/). ... +## [v0.1.4] - 2019-06-12 + +### Fixed +- Restored compatibility with Rust 1.31.0 + ## [v0.1.3] - 2019-05-14 ### Added @@ -85,7 +90,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Initial release -[Unreleased]: https://github.com/japaric/libm/compare/0.1.3...HEAD +[Unreleased]: https://github.com/japaric/libm/compare/v0.1.4...HEAD +[v0.1.4]: https://github.com/japaric/libm/compare/0.1.3...v0.1.4 [v0.1.3]: https://github.com/japaric/libm/compare/v0.1.2...0.1.3 [v0.1.2]: https://github.com/japaric/libm/compare/v0.1.1...v0.1.2 [v0.1.1]: https://github.com/japaric/libm/compare/v0.1.0...v0.1.1 From e19b1f013d7913359b3d4b72b9f4e83553b06c4e Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Wed, 12 Jun 2019 18:46:01 +0200 Subject: [PATCH 0752/4206] Bump version --- library/compiler-builtins/libm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index a61db5ebaf897..8b272d29479c5 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -7,7 +7,7 @@ keywords = ["libm", "math"] license = "MIT OR Apache-2.0" name = "libm" repository = "https://github.com/rust-lang-nursery/libm" -version = "0.1.3" +version = "0.1.4" edition = "2018" [features] From f9b32471651d42dd9529b8a7e55164e23c488975 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 13 Jun 2019 09:21:50 -0700 Subject: [PATCH 0753/4206] Update Rust install task --- library/compiler-builtins/libm/ci/azure-install-rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/ci/azure-install-rust.yml b/library/compiler-builtins/libm/ci/azure-install-rust.yml index c5a53122f8eba..f1cd87bcc5c7b 100644 --- a/library/compiler-builtins/libm/ci/azure-install-rust.yml +++ b/library/compiler-builtins/libm/ci/azure-install-rust.yml @@ -10,7 +10,7 @@ steps: rustup default $toolchain else curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $toolchain - echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin" + echo "##vso[task.prependpath]$HOME/.cargo/bin" fi displayName: Install rust (unix) condition: ne( variables['Agent.OS'], 'Windows_NT' ) From b31fdb1a70d1cc0da89e8fa6e5e66f60a71a3e38 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 25 Jun 2019 20:39:09 +0200 Subject: [PATCH 0754/4206] Fix doc for floorf --- library/compiler-builtins/libm/src/math/floorf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index ae605e1918f68..c04f18aeeea0d 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -1,6 +1,6 @@ use core::f32; -/// Floor (f64) +/// Floor (f32) /// /// Finds the nearest integer less than or equal to `x`. #[inline] From 1011d29c556d8abc41748c66f19ce8b22be7a6ca Mon Sep 17 00:00:00 2001 From: Igor null Date: Mon, 1 Jul 2019 17:05:46 +0300 Subject: [PATCH 0755/4206] Fixed rounding to negative zero --- library/compiler-builtins/libm/src/math/round.rs | 15 ++++++++++----- library/compiler-builtins/libm/src/math/roundf.rs | 11 ++++++++--- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs index 9a9723cfbb658..efbe68ae4b999 100644 --- a/library/compiler-builtins/libm/src/math/round.rs +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -5,20 +5,20 @@ const TOINT: f64 = 1.0 / f64::EPSILON; #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn round(mut x: f64) -> f64 { - let (f, i) = (x, x.to_bits()); + let i = x.to_bits(); let e: u64 = i >> 52 & 0x7ff; let mut y: f64; if e >= 0x3ff + 52 { return x; } - if i >> 63 != 0 { - x = -x; - } if e < 0x3ff - 1 { // raise inexact if x!=0 force_eval!(x + TOINT); - return 0.0 * f; + return 0.0 * x; + } + if i >> 63 != 0 { + x = -x; } y = x + TOINT - TOINT - x; if y > 0.5 { @@ -35,3 +35,8 @@ pub fn round(mut x: f64) -> f64 { y } } + +#[test] +fn negative_zero() { + assert_eq!(round(-0.0_f64).to_bits(), (-0.0_f64).to_bits()); +} diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs index 839d9469a49ef..559d3a9268093 100644 --- a/library/compiler-builtins/libm/src/math/roundf.rs +++ b/library/compiler-builtins/libm/src/math/roundf.rs @@ -12,13 +12,13 @@ pub fn roundf(mut x: f32) -> f32 { if e >= 0x7f + 23 { return x; } - if i >> 31 != 0 { - x = -x; - } if e < 0x7f - 1 { force_eval!(x + TOINT); return 0.0 * x; } + if i >> 31 != 0 { + x = -x; + } y = x + TOINT - TOINT - x; if y > 0.5f32 { y = y + x - 1.0; @@ -33,3 +33,8 @@ pub fn roundf(mut x: f32) -> f32 { y } } + +#[test] +fn negative_zero() { + assert_eq!(roundf(-0.0_f32).to_bits(), (-0.0_f32).to_bits()); +} From a1286b4f24db30531c46faa542ea3f8e1f9b09c8 Mon Sep 17 00:00:00 2001 From: Igor null Date: Mon, 1 Jul 2019 17:10:44 +0300 Subject: [PATCH 0756/4206] Fix incorrect f32<->f64 casting in j1f/y1f --- library/compiler-builtins/libm/src/math/j1f.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs index 83ac1acffdc43..14e4ef5bf5bd1 100644 --- a/library/compiler-builtins/libm/src/math/j1f.rs +++ b/library/compiler-builtins/libm/src/math/j1f.rs @@ -49,7 +49,7 @@ fn common(ix: u32, x: f32, y1: bool, sign: bool) -> f32 { if sign { cc = -cc; } - return INVSQRTPI * (cc as f32) / sqrtf(x); + return (((INVSQRTPI as f64) * cc) / (sqrtf(x) as f64)) as f32; } /* R0/S0 on [0,2] */ @@ -356,3 +356,17 @@ fn qonef(x: f32) -> f32 { s = 1.0 + z * (q[0] + z * (q[1] + z * (q[2] + z * (q[3] + z * (q[4] + z * q[5]))))); return (0.375 + r / s) / x; } + +#[test] +fn test_j1f_2488() { + // 0x401F3E49 + assert_eq!( + j1f(2.4881766_f32), + 0.49999475_f32); +} +#[test] +fn test_y1f_2002() { + assert_eq!( + y1f(2.0000002_f32), + -0.10703229_f32); +} From 217b9a34f8339b72838a97aaf7ad24a92ecad89d Mon Sep 17 00:00:00 2001 From: Igor null Date: Mon, 1 Jul 2019 17:18:59 +0300 Subject: [PATCH 0757/4206] fixed formatting in tests --- library/compiler-builtins/libm/src/math/j1f.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs index 14e4ef5bf5bd1..d165ce3698526 100644 --- a/library/compiler-builtins/libm/src/math/j1f.rs +++ b/library/compiler-builtins/libm/src/math/j1f.rs @@ -360,13 +360,9 @@ fn qonef(x: f32) -> f32 { #[test] fn test_j1f_2488() { // 0x401F3E49 - assert_eq!( - j1f(2.4881766_f32), - 0.49999475_f32); + assert_eq!(j1f(2.4881766_f32), 0.49999475_f32); } #[test] fn test_y1f_2002() { - assert_eq!( - y1f(2.0000002_f32), - -0.10703229_f32); + assert_eq!(y1f(2.0000002_f32), -0.10703229_f32); } From 2c05001264d5b57a193776e7e31259e5f6114f8d Mon Sep 17 00:00:00 2001 From: Igor null Date: Mon, 1 Jul 2019 17:21:43 +0300 Subject: [PATCH 0758/4206] separate tests into #[cfg(test)] mod --- .../compiler-builtins/libm/src/math/j1f.rs | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs index d165ce3698526..5095894d7a1d3 100644 --- a/library/compiler-builtins/libm/src/math/j1f.rs +++ b/library/compiler-builtins/libm/src/math/j1f.rs @@ -357,12 +357,16 @@ fn qonef(x: f32) -> f32 { return (0.375 + r / s) / x; } -#[test] -fn test_j1f_2488() { - // 0x401F3E49 - assert_eq!(j1f(2.4881766_f32), 0.49999475_f32); -} -#[test] -fn test_y1f_2002() { - assert_eq!(y1f(2.0000002_f32), -0.10703229_f32); +#[cfg(test)] +mod tests { + use super::{j1f, y1f}; + #[test] + fn test_j1f_2488() { + // 0x401F3E49 + assert_eq!(j1f(2.4881766_f32), 0.49999475_f32); + } + #[test] + fn test_y1f_2002() { + assert_eq!(y1f(2.0000002_f32), -0.10703229_f32); + } } From b0c846bfd1b15c55e99bad8fdc5c45e626f00db2 Mon Sep 17 00:00:00 2001 From: Igor null Date: Mon, 1 Jul 2019 17:23:52 +0300 Subject: [PATCH 0759/4206] move tests to separate #[cfg(test)] mod --- library/compiler-builtins/libm/src/math/round.rs | 11 ++++++++--- library/compiler-builtins/libm/src/math/roundf.rs | 11 ++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs index efbe68ae4b999..67590d2c19b92 100644 --- a/library/compiler-builtins/libm/src/math/round.rs +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -36,7 +36,12 @@ pub fn round(mut x: f64) -> f64 { } } -#[test] -fn negative_zero() { - assert_eq!(round(-0.0_f64).to_bits(), (-0.0_f64).to_bits()); +#[cfg(test)] +mod tests { + use super::round; + + #[test] + fn negative_zero() { + assert_eq!(round(-0.0_f64).to_bits(), (-0.0_f64).to_bits()); + } } diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs index 559d3a9268093..85114be4ba119 100644 --- a/library/compiler-builtins/libm/src/math/roundf.rs +++ b/library/compiler-builtins/libm/src/math/roundf.rs @@ -34,7 +34,12 @@ pub fn roundf(mut x: f32) -> f32 { } } -#[test] -fn negative_zero() { - assert_eq!(roundf(-0.0_f32).to_bits(), (-0.0_f32).to_bits()); +#[cfg(test)] +mod tests { + use super::roundf; + + #[test] + fn negative_zero() { + assert_eq!(roundf(-0.0_f32).to_bits(), (-0.0_f32).to_bits()); + } } From 2cd88e96b1f87ffcd73e2df62d42f53d1f2ebb63 Mon Sep 17 00:00:00 2001 From: Benjamin Schultzer Date: Tue, 18 Jun 2019 17:56:58 -0700 Subject: [PATCH 0760/4206] Add benchmark suite Signed-off-by: Benjamin Schultzer --- library/compiler-builtins/libm/Cargo.toml | 2 + library/compiler-builtins/libm/README.md | 6 + .../libm/azure-pipelines.yml | 11 ++ .../compiler-builtins/libm/benches/bench.rs | 118 ++++++++++++++++++ .../compiler-builtins/libm/src/math/pow.rs | 2 +- 5 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/libm/benches/bench.rs diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 8b272d29479c5..2f68ecc011b70 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -30,6 +30,8 @@ members = [ [dev-dependencies] no-panic = "0.1.8" +rand = "0.6.5" +paste = "0.1.5" [build-dependencies] rand = { version = "0.6.5", optional = true } diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 3df5b65ea383f..edd54d4187413 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -37,6 +37,12 @@ fn foo(x: f32) { The API documentation can be found [here](https://docs.rs/libm). +## Benchmark +[benchmark]: #benchmark +Run `cargo +nightly bench` + +NOTE: remember to have nightly installed `rustup install nightly` + ## Contributing Please check [CONTRIBUTING.md](CONTRIBUTING.md) diff --git a/library/compiler-builtins/libm/azure-pipelines.yml b/library/compiler-builtins/libm/azure-pipelines.yml index d8068e023b4ca..e9cb916dbed70 100644 --- a/library/compiler-builtins/libm/azure-pipelines.yml +++ b/library/compiler-builtins/libm/azure-pipelines.yml @@ -71,3 +71,14 @@ jobs: - template: ci/azure-install-rust.yml - bash: cargo build -p cb displayName: "Check compiler-builtins still probably builds" + + - job: benchmarks + pool: + vmImage: ubuntu-16.04 + steps: + - template: ci/azure-install-rust.yml + - bash: cargo bench + displayName: "Benchmarks" + variables: + TOOLCHAIN: nightly + diff --git a/library/compiler-builtins/libm/benches/bench.rs b/library/compiler-builtins/libm/benches/bench.rs new file mode 100644 index 0000000000000..522ac4e3bf3ed --- /dev/null +++ b/library/compiler-builtins/libm/benches/bench.rs @@ -0,0 +1,118 @@ +#![feature(test)] + +extern crate paste; +extern crate rand; +extern crate test; + +use rand::Rng; +use test::Bencher; + +macro_rules! unary { + ($($func:ident),*) => ($( + paste::item! { + #[bench] + pub fn [<$func>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let x = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func>](x))) + } + #[bench] + pub fn [<$func f>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let x = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func f>](x))) + } + } + )*); +} +macro_rules! binary { + ($($func:ident),*) => ($( + paste::item! { + #[bench] + pub fn [<$func>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let x = rng.gen::(); + let y = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func>](x, y))) + } + #[bench] + pub fn [<$func f>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let x = rng.gen::(); + let y = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func f>](x, y))) + } + } + )*); + ($($func:ident);*) => ($( + paste::item! { + #[bench] + pub fn [<$func>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let x = rng.gen::(); + let n = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func>](x, n))) + } + #[bench] + pub fn [<$func f>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let x = rng.gen::(); + let n = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func f>](x, n))) + } + } + )*); +} +macro_rules! trinary { + ($($func:ident),*) => ($( + paste::item! { + #[bench] + pub fn [<$func>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let x = rng.gen::(); + let y = rng.gen::(); + let z = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func>](x, y, z))) + } + #[bench] + pub fn [<$func f>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let x = rng.gen::(); + let y = rng.gen::(); + let z = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func f>](x, y, z))) + } + } + )*); +} +macro_rules! bessel { + ($($func:ident),*) => ($( + paste::item! { + #[bench] + pub fn [<$func>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let mut n = rng.gen::(); + n &= 0xffff; + let x = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func>](n, x))) + } + #[bench] + pub fn [<$func f>](bh: &mut Bencher) { + let mut rng = rand::thread_rng(); + let mut n = rng.gen::(); + n &= 0xffff; + let x = rng.gen::(); + bh.iter(|| test::black_box(libm::[<$func f>](n, x))) + } + } + )*); +} + +unary!( + acos, acosh, asin, atan, cbrt, ceil, cos, cosh, erf, exp, exp2, exp10, expm1, fabs, floor, j0, + j1, lgamma, log, log1p, log2, log10, round, sin, sinh, sqrt, tan, tanh, tgamma, trunc, y0, y1 +); +binary!(atan2, copysign, fdim, fmax, fmin, fmod, hypot, pow); +trinary!(fma); +bessel!(jn, yn); +binary!(ldexp; scalbn); diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 111d712ffc8e6..068a4ec47d4ab 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -479,7 +479,7 @@ mod tests { .for_each(|s| s.iter().for_each(|val| pow_test(base, *val, expected))); } - fn test_sets(sets: &[&[f64]], computed: &Fn(f64) -> f64, expected: &Fn(f64) -> f64) { + fn test_sets(sets: &[&[f64]], computed: &dyn Fn(f64) -> f64, expected: &dyn Fn(f64) -> f64) { sets.iter().for_each(|s| { s.iter().for_each(|val| { let exp = expected(*val); From 53c6687ef53383c6c6b387908c1a1f9893e371dc Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Tue, 2 Jul 2019 08:22:03 +0200 Subject: [PATCH 0761/4206] Move benchmarks into its own crate --- library/compiler-builtins/libm/Cargo.toml | 3 +-- library/compiler-builtins/libm/README.md | 6 ++++-- library/compiler-builtins/libm/ci/run.sh | 14 +++++++++----- .../libm/crates/libm-bench/Cargo.toml | 11 +++++++++++ .../libm/{ => crates/libm-bench}/benches/bench.rs | 3 --- 5 files changed, 25 insertions(+), 12 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-bench/Cargo.toml rename library/compiler-builtins/libm/{ => crates/libm-bench}/benches/bench.rs (98%) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 2f68ecc011b70..bd1bb80ce4578 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -26,12 +26,11 @@ checked = [] [workspace] members = [ "crates/compiler-builtins-smoke-test", + "crates/libm-bench", ] [dev-dependencies] no-panic = "0.1.8" -rand = "0.6.5" -paste = "0.1.5" [build-dependencies] rand = { version = "0.6.5", optional = true } diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index edd54d4187413..8b93f260373df 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -39,9 +39,11 @@ The API documentation can be found [here](https://docs.rs/libm). ## Benchmark [benchmark]: #benchmark -Run `cargo +nightly bench` -NOTE: remember to have nightly installed `rustup install nightly` +The benchmarks are located in `crates/libm-bench` and require a nightly Rust toolchain. +To run all benchmarks: + +> cargo +nightly bench --all ## Contributing diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 42c2416455d9d..37ffb8793cc83 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -1,11 +1,15 @@ -#!/bin/sh +#!/usr/bin/env sh set -ex TARGET=$1 -cargo test --target $TARGET -cargo test --target $TARGET --release +CMD="cargo test --all --no-default-features --target $TARGET" -cargo test --features 'checked musl-reference-tests' --target $TARGET +$CMD +$CMD --release -cargo test --features 'checked musl-reference-tests' --target $TARGET --release +$CMD --features 'stable' +$CMD --release --features 'stable' + +$CMD --features 'stable checked musl-reference-tests' +$CMD --release --features 'stable checked musl-reference-tests' diff --git a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml new file mode 100644 index 0000000000000..8e06e0fb5c829 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "libm-bench" +version = "0.1.0" +authors = ["Gonzalo Brito Gadeschi "] +edition = "2018" +license = "MIT OR Apache-2.0" + +[dependencies] +libm = { path = "../.." } +rand = "0.6.5" +paste = "0.1.5" diff --git a/library/compiler-builtins/libm/benches/bench.rs b/library/compiler-builtins/libm/crates/libm-bench/benches/bench.rs similarity index 98% rename from library/compiler-builtins/libm/benches/bench.rs rename to library/compiler-builtins/libm/crates/libm-bench/benches/bench.rs index 522ac4e3bf3ed..b6d8741531f3f 100644 --- a/library/compiler-builtins/libm/benches/bench.rs +++ b/library/compiler-builtins/libm/crates/libm-bench/benches/bench.rs @@ -1,7 +1,4 @@ #![feature(test)] - -extern crate paste; -extern crate rand; extern crate test; use rand::Rng; From cc1671fc576eb3ca390e3f9979bac4afae063193 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Tue, 2 Jul 2019 08:32:31 +0200 Subject: [PATCH 0762/4206] Do not enable default features in benchmarks --- library/compiler-builtins/libm/crates/libm-bench/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml index 8e06e0fb5c829..d28dd861fe4dd 100644 --- a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml @@ -6,6 +6,6 @@ edition = "2018" license = "MIT OR Apache-2.0" [dependencies] -libm = { path = "../.." } +libm = { path = "../..", default-features = false } rand = "0.6.5" paste = "0.1.5" From f6e48dd17d39fc95bec7a98f638378b68165a6a1 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Tue, 2 Jul 2019 08:33:11 +0200 Subject: [PATCH 0763/4206] Re-export the stable libm feature --- library/compiler-builtins/libm/crates/libm-bench/Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml index d28dd861fe4dd..ba65dbd5fe692 100644 --- a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml @@ -9,3 +9,7 @@ license = "MIT OR Apache-2.0" libm = { path = "../..", default-features = false } rand = "0.6.5" paste = "0.1.5" + +[features] +default = [] +stable = [ "libm/stable" ] From eb08eb0d433cfb38f7ba857b7496b69e68aa8d8c Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Tue, 2 Jul 2019 09:07:10 +0200 Subject: [PATCH 0764/4206] Run benchmarks on CI --- library/compiler-builtins/libm/azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/azure-pipelines.yml b/library/compiler-builtins/libm/azure-pipelines.yml index e9cb916dbed70..c89346c73d80f 100644 --- a/library/compiler-builtins/libm/azure-pipelines.yml +++ b/library/compiler-builtins/libm/azure-pipelines.yml @@ -77,7 +77,7 @@ jobs: vmImage: ubuntu-16.04 steps: - template: ci/azure-install-rust.yml - - bash: cargo bench + - bash: cargo bench --all displayName: "Benchmarks" variables: TOOLCHAIN: nightly From 5e711e630e77c5c9c111f2833b778bff99f22af6 Mon Sep 17 00:00:00 2001 From: Igor null Date: Tue, 2 Jul 2019 16:48:59 +0300 Subject: [PATCH 0765/4206] Fixed a few int overflows rem_pio2 had incorrect u32/i32 operations remquo has a straight int overflow --- .../libm/src/math/rem_pio2.rs | 53 ++++++++++++------- .../libm/src/math/rem_pio2_large.rs | 2 +- .../compiler-builtins/libm/src/math/remquo.rs | 14 ++++- 3 files changed, 48 insertions(+), 21 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 536dfac3c42ce..dc6b3297d93ca 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -179,29 +179,44 @@ pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { i -= 1; } let mut ty = [0.0; 3]; - let n = rem_pio2_large(&tx[..=i], &mut ty, ((ix >> 20) - (0x3ff + 23)) as i32, 1); + let n = rem_pio2_large(&tx[..=i], &mut ty, ((ix as i32) >> 20) - (0x3ff + 23), 1); if sign != 0 { return (-n, -ty[0], -ty[1]); } (n, ty[0], ty[1]) } -#[test] -fn test_near_pi() { - assert_eq!( - rem_pio2(3.141592025756836), - (2, -6.278329573009626e-7, -2.1125998133974653e-23) - ); - assert_eq!( - rem_pio2(3.141592033207416), - (2, -6.20382377148128e-7, -2.1125998133974653e-23) - ); - assert_eq!( - rem_pio2(3.141592144966125), - (2, -5.086236681942706e-7, -2.1125998133974653e-23) - ); - assert_eq!( - rem_pio2(3.141592979431152), - (2, 3.2584135866119817e-7, -2.1125998133974653e-23) - ); +#[cfg(test)] +mod tests { + use super::rem_pio2; + + #[test] + fn test_near_pi() { + assert_eq!( + rem_pio2(3.141592025756836), + (2, -6.278329573009626e-7, -2.1125998133974653e-23) + ); + assert_eq!( + rem_pio2(3.141592033207416), + (2, -6.20382377148128e-7, -2.1125998133974653e-23) + ); + assert_eq!( + rem_pio2(3.141592144966125), + (2, -5.086236681942706e-7, -2.1125998133974653e-23) + ); + assert_eq!( + rem_pio2(3.141592979431152), + (2, 3.2584135866119817e-7, -2.1125998133974653e-23) + ); + } + + #[test] + fn test_overflow_b9b847() { + let _ = rem_pio2(-3054214.5490637687); + } + + #[test] + fn test_overflow_4747b9() { + let _ = rem_pio2(917340800458.2274); + } } 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 006d3e153db97..5336a97671935 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -256,7 +256,7 @@ pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> let jv = jv as usize; /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ - let mut j = (jv - jx) as i32; + let mut j = (jv as i32) - (jx as i32); let m = jx + jk; for i in 0..=m { i!(f, i, =, if j < 0 { diff --git a/library/compiler-builtins/libm/src/math/remquo.rs b/library/compiler-builtins/libm/src/math/remquo.rs index 1c2ba8918cba4..c72c8f1878e19 100644 --- a/library/compiler-builtins/libm/src/math/remquo.rs +++ b/library/compiler-builtins/libm/src/math/remquo.rs @@ -85,7 +85,8 @@ pub fn remquo(mut x: f64, mut y: f64) -> (f64, i32) { } if ex == ey || (ex + 1 == ey && (2.0 * x > y || (2.0 * x == y && (q % 2) != 0))) { x -= y; - q += 1; + // TODO: this matches musl behavior, but it is incorrect + q = q.wrapping_add(1); } q &= 0x7fffffff; let quo = if sx ^ sy { -(q as i32) } else { q as i32 }; @@ -95,3 +96,14 @@ pub fn remquo(mut x: f64, mut y: f64) -> (f64, i32) { (x, quo) } } + +#[cfg(test)] +mod tests { + use super::remquo; + + #[test] + fn test_q_overflow() { + // 0xc000000000000001, 0x04c0000000000004 + let _ = remquo(-2.0000000000000004, 8.406091369059082e-286); + } +} From 4f5e28166f8794cc8a1847fa7bf948aab98ced62 Mon Sep 17 00:00:00 2001 From: Benjamin Schultzer Date: Tue, 2 Jul 2019 11:56:38 -0700 Subject: [PATCH 0766/4206] Add signum Signed-off-by: Benjamin Schultzer --- library/compiler-builtins/libm/src/lib.rs | 24 +++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index a47883d81bb2d..81b76f87b44e8 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -73,8 +73,7 @@ pub trait F32Ext: private::Sealed + Sized { fn abs(self) -> Self; - // NOTE depends on unstable intrinsics::copysignf32 - // fn signum(self) -> Self; + fn signum(self) -> Self; fn mul_add(self, a: Self, b: Self) -> Self; @@ -178,6 +177,15 @@ impl F32Ext for f32 { fabsf(self) } + #[inline] + fn signum(self) -> Self { + if self.is_nan() { + f32::NAN + } else { + copysignf(1., self) + } + } + #[inline] fn mul_add(self, a: Self, b: Self) -> Self { fmaf(self, a, b) @@ -361,8 +369,7 @@ pub trait F64Ext: private::Sealed + Sized { fn abs(self) -> Self; - // NOTE depends on unstable intrinsics::copysignf64 - // fn signum(self) -> Self; + fn signum(self) -> Self; fn mul_add(self, a: Self, b: Self) -> Self; @@ -466,6 +473,15 @@ impl F64Ext for f64 { fabs(self) } + #[inline] + fn signum(self) -> Self { + if self.is_nan() { + f64::NAN + } else { + copysign(1., self) + } + } + #[inline] fn mul_add(self, a: Self, b: Self) -> Self { fma(self, a, b) From 1d159b527896d7776a0a7982e45324145452f85b Mon Sep 17 00:00:00 2001 From: Benjamin Schultzer Date: Wed, 3 Jul 2019 11:57:54 -0700 Subject: [PATCH 0767/4206] Add remainder This PR adds the missing `remainder` and `remainderf` found in musl libm respectly https://git.musl-libc.org/cgit/musl/tree/src/math/remainder.c and https://git.musl-libc.org/cgit/musl/tree/src/math/remainderf.c Signed-off-by: Benjamin Schultzer --- library/compiler-builtins/libm/src/math/mod.rs | 4 ++++ library/compiler-builtins/libm/src/math/remainder.rs | 5 +++++ library/compiler-builtins/libm/src/math/remainderf.rs | 5 +++++ 3 files changed, 14 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/remainder.rs create mode 100644 library/compiler-builtins/libm/src/math/remainderf.rs diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 35ffe1a2cb242..48b400a92079d 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -148,6 +148,8 @@ mod modf; mod modff; mod pow; mod powf; +mod remainder; +mod remainderf; mod remquo; mod remquof; mod round; @@ -258,6 +260,8 @@ pub use self::modf::modf; pub use self::modff::modff; pub use self::pow::pow; pub use self::powf::powf; +pub use self::remainder::remainder; +pub use self::remainderf::remainderf; pub use self::remquo::remquo; pub use self::remquof::remquof; pub use self::round::round; diff --git a/library/compiler-builtins/libm/src/math/remainder.rs b/library/compiler-builtins/libm/src/math/remainder.rs new file mode 100644 index 0000000000000..e0f56da201428 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/remainder.rs @@ -0,0 +1,5 @@ +#[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn remainder(x: f64, y: f64) -> (f64, i32) { + super::remquo(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/remainderf.rs b/library/compiler-builtins/libm/src/math/remainderf.rs new file mode 100644 index 0000000000000..72fd0e2058786 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/remainderf.rs @@ -0,0 +1,5 @@ +#[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn remainderf(x: f32, y: f32) -> (f32, i32) { + super::remquof(x, y) +} From 05762eb876f40c192a3c497b8634b668d280b033 Mon Sep 17 00:00:00 2001 From: Benjamin Schultzer Date: Wed, 3 Jul 2019 14:15:29 -0700 Subject: [PATCH 0768/4206] Only return the fp value. Signed-off-by: Benjamin Schultzer --- library/compiler-builtins/libm/src/math/remainder.rs | 5 +++-- library/compiler-builtins/libm/src/math/remainderf.rs | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/remainder.rs b/library/compiler-builtins/libm/src/math/remainder.rs index e0f56da201428..7ce895004b897 100644 --- a/library/compiler-builtins/libm/src/math/remainder.rs +++ b/library/compiler-builtins/libm/src/math/remainder.rs @@ -1,5 +1,6 @@ #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn remainder(x: f64, y: f64) -> (f64, i32) { - super::remquo(x, y) +pub fn remainder(x: f64, y: f64) -> f64 { + let (result, _) = super::remquo(x, y); + result } diff --git a/library/compiler-builtins/libm/src/math/remainderf.rs b/library/compiler-builtins/libm/src/math/remainderf.rs index 72fd0e2058786..8b2aa5aabbc95 100644 --- a/library/compiler-builtins/libm/src/math/remainderf.rs +++ b/library/compiler-builtins/libm/src/math/remainderf.rs @@ -1,5 +1,6 @@ #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn remainderf(x: f32, y: f32) -> (f32, i32) { - super::remquof(x, y) +pub fn remainderf(x: f32, y: f32) -> f32 { + let (result, _) = super::remquof(x, y); + result } From 0e871e58b4b024b0d2eb0456f2c2aaab5d3a299b Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 3 Jul 2019 23:35:07 +0200 Subject: [PATCH 0769/4206] Remove F32Ext and F64Ext --- library/compiler-builtins/libm/src/lib.rs | 599 ---------------------- 1 file changed, 599 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 81b76f87b44e8..b37248ffba438 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -55,604 +55,5 @@ pub fn _eq(a: f64, b: f64) -> Result<(), u64> { } } -/// Math support for `f32` -/// -/// This trait is sealed and cannot be implemented outside of `libm`. -pub trait F32Ext: private::Sealed + Sized { - fn floor(self) -> Self; - - fn ceil(self) -> Self; - - fn round(self) -> Self; - - fn trunc(self) -> Self; - - fn fdim(self, rhs: Self) -> Self; - - fn fract(self) -> Self; - - fn abs(self) -> Self; - - fn signum(self) -> Self; - - fn mul_add(self, a: Self, b: Self) -> Self; - - fn div_euc(self, rhs: Self) -> Self; - - fn mod_euc(self, rhs: Self) -> Self; - - // NOTE depends on unstable intrinsics::powif32 - // fn powi(self, n: i32) -> Self; - - fn powf(self, n: Self) -> Self; - - fn sqrt(self) -> Self; - - fn exp(self) -> Self; - - fn exp2(self) -> Self; - - fn ln(self) -> Self; - - fn log(self, base: Self) -> Self; - - fn log2(self) -> Self; - - fn log10(self) -> Self; - - fn cbrt(self) -> Self; - - fn hypot(self, other: Self) -> Self; - - fn sin(self) -> Self; - - fn cos(self) -> Self; - - fn tan(self) -> Self; - - fn asin(self) -> Self; - - fn acos(self) -> Self; - - fn atan(self) -> Self; - - fn atan2(self, other: Self) -> Self; - - fn sin_cos(self) -> (Self, Self); - - fn exp_m1(self) -> Self; - - fn ln_1p(self) -> Self; - - fn sinh(self) -> Self; - - fn cosh(self) -> Self; - - fn tanh(self) -> Self; - - fn asinh(self) -> Self; - - fn acosh(self) -> Self; - - fn atanh(self) -> Self; - - fn min(self, other: Self) -> Self; - - fn max(self, other: Self) -> Self; -} - -impl F32Ext for f32 { - #[inline] - fn floor(self) -> Self { - floorf(self) - } - - #[inline] - fn ceil(self) -> Self { - ceilf(self) - } - - #[inline] - fn round(self) -> Self { - roundf(self) - } - - #[inline] - fn trunc(self) -> Self { - truncf(self) - } - - #[inline] - fn fdim(self, rhs: Self) -> Self { - fdimf(self, rhs) - } - - #[inline] - fn fract(self) -> Self { - self - self.trunc() - } - - #[inline] - fn abs(self) -> Self { - fabsf(self) - } - - #[inline] - fn signum(self) -> Self { - if self.is_nan() { - f32::NAN - } else { - copysignf(1., self) - } - } - - #[inline] - fn mul_add(self, a: Self, b: Self) -> Self { - fmaf(self, a, b) - } - - #[inline] - fn div_euc(self, rhs: Self) -> Self { - let q = (self / rhs).trunc(); - if self % rhs < 0.0 { - return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; - } - q - } - - #[inline] - fn mod_euc(self, rhs: f32) -> f32 { - let r = self % rhs; - if r < 0.0 { - r + rhs.abs() - } else { - r - } - } - - #[inline] - fn powf(self, n: Self) -> Self { - powf(self, n) - } - - #[inline] - fn sqrt(self) -> Self { - sqrtf(self) - } - - #[inline] - fn exp(self) -> Self { - expf(self) - } - - #[inline] - fn exp2(self) -> Self { - exp2f(self) - } - - #[inline] - fn ln(self) -> Self { - logf(self) - } - - #[inline] - fn log(self, base: Self) -> Self { - self.ln() / base.ln() - } - - #[inline] - fn log2(self) -> Self { - log2f(self) - } - - #[inline] - fn log10(self) -> Self { - log10f(self) - } - - #[inline] - fn cbrt(self) -> Self { - cbrtf(self) - } - - #[inline] - fn hypot(self, other: Self) -> Self { - hypotf(self, other) - } - - #[inline] - fn sin(self) -> Self { - sinf(self) - } - - #[inline] - fn cos(self) -> Self { - cosf(self) - } - - #[inline] - fn tan(self) -> Self { - tanf(self) - } - - #[inline] - fn asin(self) -> Self { - asinf(self) - } - - #[inline] - fn acos(self) -> Self { - acosf(self) - } - - #[inline] - fn atan(self) -> Self { - atanf(self) - } - - #[inline] - fn atan2(self, other: Self) -> Self { - atan2f(self, other) - } - - #[inline] - fn sin_cos(self) -> (Self, Self) { - sincosf(self) - } - - #[inline] - fn exp_m1(self) -> Self { - expm1f(self) - } - - #[inline] - fn ln_1p(self) -> Self { - log1pf(self) - } - - #[inline] - fn sinh(self) -> Self { - sinhf(self) - } - - #[inline] - fn cosh(self) -> Self { - coshf(self) - } - - #[inline] - fn tanh(self) -> Self { - tanhf(self) - } - - #[inline] - fn asinh(self) -> Self { - asinhf(self) - } - - #[inline] - fn acosh(self) -> Self { - acoshf(self) - } - - #[inline] - fn atanh(self) -> Self { - atanhf(self) - } - - #[inline] - fn min(self, other: Self) -> Self { - fminf(self, other) - } - - #[inline] - fn max(self, other: Self) -> Self { - fmaxf(self, other) - } -} - -/// Math support for `f64` -/// -/// This trait is sealed and cannot be implemented outside of `libm`. -pub trait F64Ext: private::Sealed + Sized { - fn floor(self) -> Self; - - fn ceil(self) -> Self; - - fn round(self) -> Self; - - fn trunc(self) -> Self; - - fn fdim(self, rhs: Self) -> Self; - - fn fract(self) -> Self; - - fn abs(self) -> Self; - - fn signum(self) -> Self; - - fn mul_add(self, a: Self, b: Self) -> Self; - - fn div_euc(self, rhs: Self) -> Self; - - fn mod_euc(self, rhs: Self) -> Self; - - // NOTE depends on unstable intrinsics::powif64 - // fn powi(self, n: i32) -> Self; - - fn powf(self, n: Self) -> Self; - - fn sqrt(self) -> Self; - - fn exp(self) -> Self; - - fn exp2(self) -> Self; - - fn ln(self) -> Self; - - fn log(self, base: Self) -> Self; - - fn log2(self) -> Self; - - fn log10(self) -> Self; - - fn cbrt(self) -> Self; - - fn hypot(self, other: Self) -> Self; - - fn sin(self) -> Self; - - fn cos(self) -> Self; - - fn tan(self) -> Self; - - fn asin(self) -> Self; - - fn acos(self) -> Self; - - fn atan(self) -> Self; - - fn atan2(self, other: Self) -> Self; - - fn sin_cos(self) -> (Self, Self); - - fn exp_m1(self) -> Self; - - fn ln_1p(self) -> Self; - - fn sinh(self) -> Self; - - fn cosh(self) -> Self; - - fn tanh(self) -> Self; - - fn asinh(self) -> Self; - - fn acosh(self) -> Self; - - fn atanh(self) -> Self; - - fn min(self, other: Self) -> Self; - - fn max(self, other: Self) -> Self; -} - -impl F64Ext for f64 { - #[inline] - fn floor(self) -> Self { - floor(self) - } - - #[inline] - fn ceil(self) -> Self { - ceil(self) - } - - #[inline] - fn round(self) -> Self { - round(self) - } - - #[inline] - fn trunc(self) -> Self { - trunc(self) - } - - #[inline] - fn fdim(self, rhs: Self) -> Self { - fdim(self, rhs) - } - - #[inline] - fn fract(self) -> Self { - self - self.trunc() - } - - #[inline] - fn abs(self) -> Self { - fabs(self) - } - - #[inline] - fn signum(self) -> Self { - if self.is_nan() { - f64::NAN - } else { - copysign(1., self) - } - } - - #[inline] - fn mul_add(self, a: Self, b: Self) -> Self { - fma(self, a, b) - } - - #[inline] - fn div_euc(self, rhs: Self) -> Self { - let q = (self / rhs).trunc(); - if self % rhs < 0.0 { - return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; - } - q - } - - #[inline] - fn mod_euc(self, rhs: f64) -> f64 { - let r = self % rhs; - if r < 0.0 { - r + rhs.abs() - } else { - r - } - } - - #[inline] - fn powf(self, n: Self) -> Self { - pow(self, n) - } - - #[inline] - fn sqrt(self) -> Self { - sqrt(self) - } - - #[inline] - fn exp(self) -> Self { - exp(self) - } - - #[inline] - fn exp2(self) -> Self { - exp2(self) - } - - #[inline] - fn ln(self) -> Self { - log(self) - } - - #[inline] - fn log(self, base: Self) -> Self { - self.ln() / base.ln() - } - - #[inline] - fn log2(self) -> Self { - log2(self) - } - - #[inline] - fn log10(self) -> Self { - log10(self) - } - - #[inline] - fn cbrt(self) -> Self { - cbrt(self) - } - - #[inline] - fn hypot(self, other: Self) -> Self { - hypot(self, other) - } - - #[inline] - fn sin(self) -> Self { - sin(self) - } - - #[inline] - fn cos(self) -> Self { - cos(self) - } - - #[inline] - fn tan(self) -> Self { - tan(self) - } - - #[inline] - fn asin(self) -> Self { - asin(self) - } - - #[inline] - fn acos(self) -> Self { - acos(self) - } - - #[inline] - fn atan(self) -> Self { - atan(self) - } - - #[inline] - fn atan2(self, other: Self) -> Self { - atan2(self, other) - } - - #[inline] - fn sin_cos(self) -> (Self, Self) { - sincos(self) - } - - #[inline] - fn exp_m1(self) -> Self { - expm1(self) - } - - #[inline] - fn ln_1p(self) -> Self { - log1p(self) - } - - #[inline] - fn sinh(self) -> Self { - sinh(self) - } - - #[inline] - fn cosh(self) -> Self { - cosh(self) - } - - #[inline] - fn tanh(self) -> Self { - tanh(self) - } - - #[inline] - fn asinh(self) -> Self { - asinh(self) - } - - #[inline] - fn acosh(self) -> Self { - acosh(self) - } - - #[inline] - fn atanh(self) -> Self { - atanh(self) - } - - #[inline] - fn min(self, other: Self) -> Self { - fmin(self, other) - } - - #[inline] - fn max(self, other: Self) -> Self { - fmax(self, other) - } -} - -mod private { - pub trait Sealed {} - - impl Sealed for f32 {} - impl Sealed for f64 {} -} - #[cfg(all(test, feature = "musl-reference-tests"))] include!(concat!(env!("OUT_DIR"), "/musl-tests.rs")); From dc9fa00222b4204545000f6404d87fef0cd1eb9c Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 3 Jul 2019 23:35:24 +0200 Subject: [PATCH 0770/4206] Bump minor version to 0.2.0 --- library/compiler-builtins/libm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index bd1bb80ce4578..3e6817851ba7f 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -7,7 +7,7 @@ keywords = ["libm", "math"] license = "MIT OR Apache-2.0" name = "libm" repository = "https://github.com/rust-lang-nursery/libm" -version = "0.1.4" +version = "0.2.0" edition = "2018" [features] From e8ad478f6fb33bb95fd7cc215323e0f2a4d7c778 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 3 Jul 2019 23:53:35 +0200 Subject: [PATCH 0771/4206] Remove traits from README --- library/compiler-builtins/libm/README.md | 17 +---------------- library/compiler-builtins/libm/src/lib.rs | 10 ---------- 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 8b93f260373df..e10904f8cf081 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -18,22 +18,7 @@ term goal is to enable [math support in the `core` crate][core]. ## Already usable -This crate is [on crates.io] and can be used today in stable `#![no_std]` programs like this: - -[on crates.io]: https://crates.io/crates/libm - -``` rust -#![no_std] - -extern crate libm; - -use libm::F32Ext; // adds methods to `f32` - -fn foo(x: f32) { - let y = x.sqrt(); - let z = libm::truncf(x); -} -``` +This crate is [on crates.io] and can be used today in stable `#![no_std]` programs. The API documentation can be found [here](https://docs.rs/libm). diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index b37248ffba438..b15857dbe6f6f 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -1,14 +1,4 @@ //! libm in pure Rust -//! -//! # Usage -//! -//! You can use this crate in two ways: -//! -//! - By directly using its free functions, e.g. `libm::powf`. -//! -//! - By importing the `F32Ext` and / or `F64Ext` extension traits to add methods like `powf` to the -//! `f32` and `f64` types. Then you'll be able to invoke math functions as methods, e.g. `x.sqrt()`. - #![deny(warnings)] #![no_std] #![cfg_attr( From 2da2f8dce485370556bec2d6851ec650ef3c79e2 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Tue, 9 Jul 2019 17:17:08 +0200 Subject: [PATCH 0772/4206] Add nextafter and nextafterf from musl --- .../compiler-builtins/libm/src/math/mod.rs | 4 ++ .../libm/src/math/nextafter.rs | 38 +++++++++++++++++++ .../libm/src/math/nextafterf.rs | 38 +++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/nextafter.rs create mode 100644 library/compiler-builtins/libm/src/math/nextafterf.rs diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 48b400a92079d..fcf4e649cdeda 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -146,6 +146,8 @@ mod log2f; mod logf; mod modf; mod modff; +mod nextafter; +mod nextafterf; mod pow; mod powf; mod remainder; @@ -258,6 +260,8 @@ pub use self::log2f::log2f; pub use self::logf::logf; pub use self::modf::modf; pub use self::modff::modff; +pub use self::nextafter::nextafter; +pub use self::nextafterf::nextafterf; pub use self::pow::pow; pub use self::powf::powf; pub use self::remainder::remainder; diff --git a/library/compiler-builtins/libm/src/math/nextafter.rs b/library/compiler-builtins/libm/src/math/nextafter.rs new file mode 100644 index 0000000000000..4c1257e002711 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/nextafter.rs @@ -0,0 +1,38 @@ +#[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn nextafter(x: f64, y: f64) -> f64 { + if x.is_nan() || y.is_nan() { + return x + y; + } + + let mut ux_i = x.to_bits(); + let uy_i = y.to_bits(); + if ux_i == uy_i { + return y; + } + + let ax = ux_i & !1_u64 / 2; + let ay = uy_i & !1_u64 / 2; + if ax == 0 { + if ay == 0 { + return y; + } + ux_i = (uy_i & 1_u64 << 63) | 1; + } else if ax > ay || ((ux_i ^ uy_i) & 1_u64 << 63) != 0 { + ux_i -= 1; + } else { + ux_i += 1; + } + + let e = ux_i.wrapping_shr(52 & 0x7ff); + // raise overflow if ux.f is infinite and x is finite + if e == 0x7ff { + force_eval!(x + x); + } + let ux_f = f64::from_bits(ux_i); + // raise underflow if ux.f is subnormal or zero + if e == 0 { + force_eval!(x * x + ux_f * ux_f); + } + ux_f +} diff --git a/library/compiler-builtins/libm/src/math/nextafterf.rs b/library/compiler-builtins/libm/src/math/nextafterf.rs new file mode 100644 index 0000000000000..a48bce9f742c2 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/nextafterf.rs @@ -0,0 +1,38 @@ +#[inline] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn nextafterf(x: f32, y: f32) -> f32 { + if x.is_nan() || y.is_nan() { + return x + y; + } + + let mut ux_i = x.to_bits(); + let uy_i = y.to_bits(); + if ux_i == uy_i { + return y; + } + + let ax = ux_i & 0x7fff_ffff_u32; + let ay = uy_i & 0x7fff_ffff_u32; + if ax == 0 { + if ay == 0 { + return y; + } + ux_i = (uy_i & 0x8000_0000_u32) | 1; + } else if ax > ay || ((ux_i ^ uy_i) & 0x8000_0000_u32) != 0 { + ux_i -= 1; + } else { + ux_i += 1; + } + + let e = ux_i.wrapping_shr(0x7f80_0000_u32); + // raise overflow if ux_f is infinite and x is finite + if e == 0x7f80_0000_u32 { + force_eval!(x + x); + } + let ux_f = f32::from_bits(ux_i); + // raise underflow if ux_f is subnormal or zero + if e == 0 { + force_eval!(x * x + ux_f * ux_f); + } + ux_f +} From e46b4a82995f7a01bbb12385ae27ed476aa89379 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Tue, 9 Jul 2019 17:33:01 +0200 Subject: [PATCH 0773/4206] Floating-point environment APIs are private --- .../compiler-builtins/libm/src/math/fenv.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/fenv.rs b/library/compiler-builtins/libm/src/math/fenv.rs index 63bb203682068..652e6032452b3 100644 --- a/library/compiler-builtins/libm/src/math/fenv.rs +++ b/library/compiler-builtins/libm/src/math/fenv.rs @@ -1,33 +1,33 @@ // src: musl/src/fenv/fenv.c /* Dummy functions for archs lacking fenv implementation */ -pub const FE_UNDERFLOW: i32 = 0; -pub const FE_INEXACT: i32 = 0; +pub(crate) const FE_UNDERFLOW: i32 = 0; +pub(crate) const FE_INEXACT: i32 = 0; -pub const FE_TONEAREST: i32 = 0; -pub const FE_TOWARDZERO: i32 = 0; +pub(crate) const FE_TONEAREST: i32 = 0; +pub(crate) const FE_TOWARDZERO: i32 = 0; #[inline] -pub fn feclearexcept(_mask: i32) -> i32 { +pub(crate) fn feclearexcept(_mask: i32) -> i32 { 0 } #[inline] -pub fn feraiseexcept(_mask: i32) -> i32 { +pub(crate) fn feraiseexcept(_mask: i32) -> i32 { 0 } #[inline] -pub fn fetestexcept(_mask: i32) -> i32 { +pub(crate) fn fetestexcept(_mask: i32) -> i32 { 0 } #[inline] -pub fn fegetround() -> i32 { +pub(crate) fn fegetround() -> i32 { FE_TONEAREST } #[inline] -pub fn fesetround(_r: i32) -> i32 { +pub(crate) fn fesetround(_r: i32) -> i32 { 0 } From 42e0c8c0a1cabb24b48f56470aea1656a47f9cc7 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 10 Jul 2019 12:59:36 +0200 Subject: [PATCH 0774/4206] Add FMA tests that cause it to segfault --- .../compiler-builtins/libm/src/math/fma.rs | 19 +++++++++++++++++++ library/compiler-builtins/libm/tests/unit.rs | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 library/compiler-builtins/libm/tests/unit.rs diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 07d90f8b727d2..6d4471a9a04fd 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -205,3 +205,22 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { } scalbn(r, e) } + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn fma_segfault() { + // These two inputs cause fma to segfault on release due to overflow: + assert_eq!( + fma( + -0.0000000000000002220446049250313, + -0.0000000000000002220446049250313, + -0.0000000000000002220446049250313 + ), + -0.00000000000000022204460492503126, + ); + + assert_eq!(fma(-0.992, -0.992, -0.992), -0.00793599999988632,); + } +} diff --git a/library/compiler-builtins/libm/tests/unit.rs b/library/compiler-builtins/libm/tests/unit.rs new file mode 100644 index 0000000000000..4e7002817a648 --- /dev/null +++ b/library/compiler-builtins/libm/tests/unit.rs @@ -0,0 +1,19 @@ +use libm::*; + +#[test] +fn fma_segfault() { + // These two inputs cause fma to segfault on release due to overflow: + assert_eq!( + fma( + -0.0000000000000002220446049250313, + -0.0000000000000002220446049250313, + -0.0000000000000002220446049250313 + ), + -0.00000000000000022204460492503126, + ); + + assert_eq!( + fma(-0.992, -0.992, -0.992), + -0.00793599999988632, + ); +} From f783ff454b69a50f37aa37f41a36b7e7b90d67c8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 10 Jul 2019 08:42:28 -0700 Subject: [PATCH 0775/4206] Remove most `#[inline]` annotations These annotations fall into a few categories * Some simply aren't needed since functions will always be in the same CGU anyway and are already candidates for inlining. * Many are on massive functions which shouldn't be inlined across crates due to code size concerns. * Others aren't necessary since calls to this crate are rarely inlined anyway (since it's lowered through LLVM). If this crate is called directly and inlining is needed then LTO can always be turned on, otherwise this will benefit downstream consumers by avoiding re-codegen'ing so many functions. --- library/compiler-builtins/libm/src/math/acos.rs | 2 -- library/compiler-builtins/libm/src/math/acosf.rs | 2 -- library/compiler-builtins/libm/src/math/asin.rs | 2 -- library/compiler-builtins/libm/src/math/asinf.rs | 2 -- library/compiler-builtins/libm/src/math/atan.rs | 1 - library/compiler-builtins/libm/src/math/atan2.rs | 1 - library/compiler-builtins/libm/src/math/atan2f.rs | 1 - library/compiler-builtins/libm/src/math/atanf.rs | 1 - library/compiler-builtins/libm/src/math/cbrt.rs | 1 - library/compiler-builtins/libm/src/math/cbrtf.rs | 1 - library/compiler-builtins/libm/src/math/ceil.rs | 1 - library/compiler-builtins/libm/src/math/ceilf.rs | 1 - library/compiler-builtins/libm/src/math/cos.rs | 1 - library/compiler-builtins/libm/src/math/cosf.rs | 1 - library/compiler-builtins/libm/src/math/cosh.rs | 1 - library/compiler-builtins/libm/src/math/coshf.rs | 1 - library/compiler-builtins/libm/src/math/exp.rs | 1 - library/compiler-builtins/libm/src/math/exp2.rs | 1 - library/compiler-builtins/libm/src/math/exp2f.rs | 1 - library/compiler-builtins/libm/src/math/expf.rs | 1 - library/compiler-builtins/libm/src/math/expm1.rs | 1 - library/compiler-builtins/libm/src/math/expm1f.rs | 1 - library/compiler-builtins/libm/src/math/expo2.rs | 1 - library/compiler-builtins/libm/src/math/fabs.rs | 1 - library/compiler-builtins/libm/src/math/fabsf.rs | 1 - library/compiler-builtins/libm/src/math/fdim.rs | 1 - library/compiler-builtins/libm/src/math/fdimf.rs | 1 - library/compiler-builtins/libm/src/math/floor.rs | 1 - library/compiler-builtins/libm/src/math/floorf.rs | 1 - library/compiler-builtins/libm/src/math/fma.rs | 3 --- library/compiler-builtins/libm/src/math/fmaf.rs | 1 - library/compiler-builtins/libm/src/math/fmax.rs | 1 - library/compiler-builtins/libm/src/math/fmaxf.rs | 1 - library/compiler-builtins/libm/src/math/fmin.rs | 1 - library/compiler-builtins/libm/src/math/fminf.rs | 1 - library/compiler-builtins/libm/src/math/fmod.rs | 1 - library/compiler-builtins/libm/src/math/fmodf.rs | 1 - library/compiler-builtins/libm/src/math/hypot.rs | 2 -- library/compiler-builtins/libm/src/math/hypotf.rs | 1 - library/compiler-builtins/libm/src/math/k_cos.rs | 1 - library/compiler-builtins/libm/src/math/k_cosf.rs | 1 - library/compiler-builtins/libm/src/math/k_expo2.rs | 1 - library/compiler-builtins/libm/src/math/k_expo2f.rs | 1 - library/compiler-builtins/libm/src/math/k_sin.rs | 1 - library/compiler-builtins/libm/src/math/k_sinf.rs | 1 - library/compiler-builtins/libm/src/math/k_tan.rs | 2 -- library/compiler-builtins/libm/src/math/k_tanf.rs | 1 - library/compiler-builtins/libm/src/math/ldexp.rs | 1 - library/compiler-builtins/libm/src/math/ldexpf.rs | 1 - library/compiler-builtins/libm/src/math/log.rs | 1 - library/compiler-builtins/libm/src/math/log10.rs | 1 - library/compiler-builtins/libm/src/math/log10f.rs | 1 - library/compiler-builtins/libm/src/math/log1p.rs | 1 - library/compiler-builtins/libm/src/math/log1pf.rs | 1 - library/compiler-builtins/libm/src/math/log2.rs | 1 - library/compiler-builtins/libm/src/math/log2f.rs | 1 - library/compiler-builtins/libm/src/math/logf.rs | 1 - library/compiler-builtins/libm/src/math/nextafter.rs | 1 - library/compiler-builtins/libm/src/math/nextafterf.rs | 1 - library/compiler-builtins/libm/src/math/pow.rs | 1 - library/compiler-builtins/libm/src/math/powf.rs | 1 - library/compiler-builtins/libm/src/math/rem_pio2.rs | 2 -- library/compiler-builtins/libm/src/math/rem_pio2_large.rs | 1 - library/compiler-builtins/libm/src/math/rem_pio2f.rs | 1 - library/compiler-builtins/libm/src/math/remainder.rs | 1 - library/compiler-builtins/libm/src/math/remainderf.rs | 1 - library/compiler-builtins/libm/src/math/remquo.rs | 1 + library/compiler-builtins/libm/src/math/remquof.rs | 1 + library/compiler-builtins/libm/src/math/round.rs | 1 - library/compiler-builtins/libm/src/math/roundf.rs | 1 - library/compiler-builtins/libm/src/math/scalbn.rs | 1 - library/compiler-builtins/libm/src/math/scalbnf.rs | 1 - library/compiler-builtins/libm/src/math/sin.rs | 1 - library/compiler-builtins/libm/src/math/sinf.rs | 1 - library/compiler-builtins/libm/src/math/sinh.rs | 1 - library/compiler-builtins/libm/src/math/sinhf.rs | 1 - library/compiler-builtins/libm/src/math/sqrt.rs | 1 - library/compiler-builtins/libm/src/math/sqrtf.rs | 1 - library/compiler-builtins/libm/src/math/tan.rs | 1 - library/compiler-builtins/libm/src/math/tanf.rs | 1 - library/compiler-builtins/libm/src/math/tanh.rs | 1 - library/compiler-builtins/libm/src/math/tanhf.rs | 1 - library/compiler-builtins/libm/src/math/trunc.rs | 1 - library/compiler-builtins/libm/src/math/truncf.rs | 1 - 84 files changed, 2 insertions(+), 91 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/acos.rs b/library/compiler-builtins/libm/src/math/acos.rs index d5e1f6865adea..23b13251ee231 100644 --- a/library/compiler-builtins/libm/src/math/acos.rs +++ b/library/compiler-builtins/libm/src/math/acos.rs @@ -48,7 +48,6 @@ const QS2: f64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ const QS3: f64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ const QS4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ -#[inline] fn r(z: f64) -> f64 { let p: f64 = z * (PS0 + z * (PS1 + z * (PS2 + z * (PS3 + z * (PS4 + z * PS5))))); let q: f64 = 1.0 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4))); @@ -60,7 +59,6 @@ fn r(z: f64) -> f64 { /// Computes the inverse cosine (arc cosine) of the input value. /// Arguments must be in the range -1 to 1. /// Returns values in radians, in the range of 0 to pi. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn acos(x: f64) -> f64 { let x1p_120f = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ -120 diff --git a/library/compiler-builtins/libm/src/math/acosf.rs b/library/compiler-builtins/libm/src/math/acosf.rs index d0598e8119009..1a60479e32a7f 100644 --- a/library/compiler-builtins/libm/src/math/acosf.rs +++ b/library/compiler-builtins/libm/src/math/acosf.rs @@ -22,7 +22,6 @@ const P_S1: f32 = -4.2743422091e-02; const P_S2: f32 = -8.6563630030e-03; const Q_S1: f32 = -7.0662963390e-01; -#[inline] fn r(z: f32) -> f32 { let p = z * (P_S0 + z * (P_S1 + z * P_S2)); let q = 1. + z * Q_S1; @@ -34,7 +33,6 @@ fn r(z: f32) -> f32 { /// Computes the inverse cosine (arc cosine) of the input value. /// Arguments must be in the range -1 to 1. /// Returns values in radians, in the range of 0 to pi. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn acosf(x: f32) -> f32 { let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) diff --git a/library/compiler-builtins/libm/src/math/asin.rs b/library/compiler-builtins/libm/src/math/asin.rs index 774475e519562..3e4b7c56ebae1 100644 --- a/library/compiler-builtins/libm/src/math/asin.rs +++ b/library/compiler-builtins/libm/src/math/asin.rs @@ -55,7 +55,6 @@ const Q_S2: f64 = 2.02094576023350569471e+00; /* 0x40002AE5, 0x9C598AC8 */ const Q_S3: f64 = -6.88283971605453293030e-01; /* 0xBFE6066C, 0x1B8D0159 */ const Q_S4: f64 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ -#[inline] fn comp_r(z: f64) -> f64 { let p = z * (P_S0 + z * (P_S1 + z * (P_S2 + z * (P_S3 + z * (P_S4 + z * P_S5))))); let q = 1.0 + z * (Q_S1 + z * (Q_S2 + z * (Q_S3 + z * Q_S4))); @@ -67,7 +66,6 @@ fn comp_r(z: f64) -> f64 { /// Computes the inverse sine (arc sine) of the argument `x`. /// Arguments to asin must be in the range -1 to 1. /// Returns values in radians, in the range of -pi/2 to pi/2. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn asin(mut x: f64) -> f64 { let z: f64; diff --git a/library/compiler-builtins/libm/src/math/asinf.rs b/library/compiler-builtins/libm/src/math/asinf.rs index ce0f4a997e778..6ec61b6297823 100644 --- a/library/compiler-builtins/libm/src/math/asinf.rs +++ b/library/compiler-builtins/libm/src/math/asinf.rs @@ -24,7 +24,6 @@ const P_S1: f32 = -4.2743422091e-02; const P_S2: f32 = -8.6563630030e-03; const Q_S1: f32 = -7.0662963390e-01; -#[inline] fn r(z: f32) -> f32 { let p = z * (P_S0 + z * (P_S1 + z * P_S2)); let q = 1. + z * Q_S1; @@ -36,7 +35,6 @@ fn r(z: f32) -> f32 { /// Computes the inverse sine (arc sine) of the argument `x`. /// Arguments to asin must be in the range -1 to 1. /// Returns values in radians, in the range of -pi/2 to pi/2. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn asinf(mut x: f32) -> f32 { let x1p_120 = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ (-120) diff --git a/library/compiler-builtins/libm/src/math/atan.rs b/library/compiler-builtins/libm/src/math/atan.rs index d2684ece8e936..4259dc71aaba5 100644 --- a/library/compiler-builtins/libm/src/math/atan.rs +++ b/library/compiler-builtins/libm/src/math/atan.rs @@ -64,7 +64,6 @@ const AT: [f64; 11] = [ /// /// Computes the inverse tangent (arc tangent) of the input value. /// Returns a value in radians, in the range of -pi/2 to pi/2. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atan(x: f64) -> f64 { let mut x = x; diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs index 08385cd100e08..fb2ea4edaf56d 100644 --- a/library/compiler-builtins/libm/src/math/atan2.rs +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -48,7 +48,6 @@ const PI_LO: f64 = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ /// Computes the inverse tangent (arc tangent) of `y/x`. /// Produces the correct result even for angles near pi/2 or -pi/2 (that is, when `x` is near 0). /// Returns a value in radians, in the range of -pi to pi. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atan2(y: f64, x: f64) -> f64 { if x.is_nan() || y.is_nan() { diff --git a/library/compiler-builtins/libm/src/math/atan2f.rs b/library/compiler-builtins/libm/src/math/atan2f.rs index 7bbe5f1d47a4c..eae3b002daeec 100644 --- a/library/compiler-builtins/libm/src/math/atan2f.rs +++ b/library/compiler-builtins/libm/src/math/atan2f.rs @@ -24,7 +24,6 @@ const PI_LO: f32 = -8.7422776573e-08; /* 0xb3bbbd2e */ /// Computes the inverse tangent (arc tangent) of `y/x`. /// Produces the correct result even for angles near pi/2 or -pi/2 (that is, when `x` is near 0). /// Returns a value in radians, in the range of -pi to pi. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atan2f(y: f32, x: f32) -> f32 { if x.is_nan() || y.is_nan() { diff --git a/library/compiler-builtins/libm/src/math/atanf.rs b/library/compiler-builtins/libm/src/math/atanf.rs index 363e11d647dbb..73f3352e9eccd 100644 --- a/library/compiler-builtins/libm/src/math/atanf.rs +++ b/library/compiler-builtins/libm/src/math/atanf.rs @@ -41,7 +41,6 @@ const A_T: [f32; 5] = [ /// /// Computes the inverse tangent (arc tangent) of the input value. /// Returns a value in radians, in the range of -pi/2 to pi/2. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atanf(mut x: f32) -> f32 { let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120) diff --git a/library/compiler-builtins/libm/src/math/cbrt.rs b/library/compiler-builtins/libm/src/math/cbrt.rs index 04469b1598fce..b4e77eaa27c82 100644 --- a/library/compiler-builtins/libm/src/math/cbrt.rs +++ b/library/compiler-builtins/libm/src/math/cbrt.rs @@ -30,7 +30,6 @@ const P4: f64 = 0.145996192886612446982; /* 0x3fc2b000, 0xd4e4edd7 */ // Cube root (f64) /// /// Computes the cube root of the argument. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cbrt(x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 diff --git a/library/compiler-builtins/libm/src/math/cbrtf.rs b/library/compiler-builtins/libm/src/math/cbrtf.rs index 6e589c0994da5..9d70305c64720 100644 --- a/library/compiler-builtins/libm/src/math/cbrtf.rs +++ b/library/compiler-builtins/libm/src/math/cbrtf.rs @@ -25,7 +25,6 @@ const B2: u32 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */ /// Cube root (f32) /// /// Computes the cube root of the argument. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cbrtf(x: f32) -> f32 { let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index 59883a8a7b988..63c1121c6d33f 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -5,7 +5,6 @@ const TOINT: f64 = 1. / f64::EPSILON; /// Ceil (f64) /// /// Finds the nearest integer greater than or equal to `x`. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ceil(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index 151a4f210420a..87d96982aab97 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -3,7 +3,6 @@ use core::f32; /// Ceil (f32) /// /// Finds the nearest integer greater than or equal to `x`. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ceilf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized diff --git a/library/compiler-builtins/libm/src/math/cos.rs b/library/compiler-builtins/libm/src/math/cos.rs index fe5a89919b2bb..db8bc49892610 100644 --- a/library/compiler-builtins/libm/src/math/cos.rs +++ b/library/compiler-builtins/libm/src/math/cos.rs @@ -41,7 +41,6 @@ use super::{k_cos, k_sin, rem_pio2}; // Accuracy: // TRIG(x) returns trig(x) nearly rounded // -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cos(x: f64) -> f64 { let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; diff --git a/library/compiler-builtins/libm/src/math/cosf.rs b/library/compiler-builtins/libm/src/math/cosf.rs index 48d76c8ee0d7d..424fa42eda612 100644 --- a/library/compiler-builtins/libm/src/math/cosf.rs +++ b/library/compiler-builtins/libm/src/math/cosf.rs @@ -24,7 +24,6 @@ const C2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ const C3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ const C4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cosf(x: f32) -> f32 { let x64 = x as f64; diff --git a/library/compiler-builtins/libm/src/math/cosh.rs b/library/compiler-builtins/libm/src/math/cosh.rs index bac875566855d..2fb568ab314c3 100644 --- a/library/compiler-builtins/libm/src/math/cosh.rs +++ b/library/compiler-builtins/libm/src/math/cosh.rs @@ -7,7 +7,6 @@ use super::k_expo2; /// Computes the hyperbolic cosine of the argument x. /// Is defined as `(exp(x) + exp(-x))/2` /// Angles are specified in radians. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cosh(mut x: f64) -> f64 { /* |x| */ diff --git a/library/compiler-builtins/libm/src/math/coshf.rs b/library/compiler-builtins/libm/src/math/coshf.rs index bf99e42f09b0c..e7b684587887e 100644 --- a/library/compiler-builtins/libm/src/math/coshf.rs +++ b/library/compiler-builtins/libm/src/math/coshf.rs @@ -7,7 +7,6 @@ use super::k_expo2f; /// Computes the hyperbolic cosine of the argument x. /// Is defined as `(exp(x) + exp(-x))/2` /// Angles are specified in radians. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn coshf(mut x: f32) -> f32 { let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 diff --git a/library/compiler-builtins/libm/src/math/exp.rs b/library/compiler-builtins/libm/src/math/exp.rs index 5465b569346ff..5b163f95427c3 100644 --- a/library/compiler-builtins/libm/src/math/exp.rs +++ b/library/compiler-builtins/libm/src/math/exp.rs @@ -81,7 +81,6 @@ const P5: f64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ /// /// Calculate the exponential of `x`, that is, *e* raised to the power `x` /// (where *e* is the base of the natural system of logarithms, approximately 2.71828). -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp(mut x: f64) -> f64 { let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs index c2192fde5a088..8ea434dcadbd3 100644 --- a/library/compiler-builtins/libm/src/math/exp2.rs +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -322,7 +322,6 @@ static TBL: [u64; TBLSIZE * 2] = [ /// Exponential, base 2 (f64) /// /// Calculate `2^x`, that is, 2 raised to the power `x`. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp2(mut x: f64) -> f64 { let redux = f64::from_bits(0x4338000000000000) / TBLSIZE as f64; diff --git a/library/compiler-builtins/libm/src/math/exp2f.rs b/library/compiler-builtins/libm/src/math/exp2f.rs index 12c9e76a4c7a5..8a890b832e92c 100644 --- a/library/compiler-builtins/libm/src/math/exp2f.rs +++ b/library/compiler-builtins/libm/src/math/exp2f.rs @@ -73,7 +73,6 @@ static EXP2FT: [u64; TBLSIZE] = [ /// Exponential, base 2 (f32) /// /// Calculate `2^x`, that is, 2 raised to the power `x`. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp2f(mut x: f32) -> f32 { let redux = f32::from_bits(0x4b400000) / TBLSIZE as f32; diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs index 09323ec8de284..47c1b2c467ec0 100644 --- a/library/compiler-builtins/libm/src/math/expf.rs +++ b/library/compiler-builtins/libm/src/math/expf.rs @@ -30,7 +30,6 @@ const P2: f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ /// /// Calculate the exponential of `x`, that is, *e* raised to the power `x` /// (where *e* is the base of the natural system of logarithms, approximately 2.71828). -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn expf(mut x: f32) -> f32 { let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 diff --git a/library/compiler-builtins/libm/src/math/expm1.rs b/library/compiler-builtins/libm/src/math/expm1.rs index 0d43b4e103d7a..42608509a402e 100644 --- a/library/compiler-builtins/libm/src/math/expm1.rs +++ b/library/compiler-builtins/libm/src/math/expm1.rs @@ -30,7 +30,6 @@ const Q5: f64 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ /// system of logarithms, approximately 2.71828). /// The result is accurate even for small values of `x`, /// where using `exp(x)-1` would lose many significant digits. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn expm1(mut x: f64) -> f64 { let hi: f64; diff --git a/library/compiler-builtins/libm/src/math/expm1f.rs b/library/compiler-builtins/libm/src/math/expm1f.rs index 9bb22344889e9..3fc2a247b5bee 100644 --- a/library/compiler-builtins/libm/src/math/expm1f.rs +++ b/library/compiler-builtins/libm/src/math/expm1f.rs @@ -32,7 +32,6 @@ const Q2: f32 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ /// system of logarithms, approximately 2.71828). /// The result is accurate even for small values of `x`, /// where using `exp(x)-1` would lose many significant digits. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn expm1f(mut x: f32) -> f32 { let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 diff --git a/library/compiler-builtins/libm/src/math/expo2.rs b/library/compiler-builtins/libm/src/math/expo2.rs index ae6cc8121e000..82e9b360a764f 100644 --- a/library/compiler-builtins/libm/src/math/expo2.rs +++ b/library/compiler-builtins/libm/src/math/expo2.rs @@ -1,7 +1,6 @@ use super::{combine_words, exp}; /* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn expo2(x: f64) -> f64 { /* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */ diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index 52a9adcbff1b0..5a7f795f6a34c 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -3,7 +3,6 @@ use core::u64; /// Absolute value (magnitude) (f64) /// Calculates the absolute value (magnitude) of the argument `x`, /// by direct manipulation of the bit representation of `x`. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fabs(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index 5942d983a4b04..495512584d229 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -1,7 +1,6 @@ /// Absolute value (magnitude) (f32) /// Calculates the absolute value (magnitude) of the argument `x`, /// by direct manipulation of the bit representation of `x`. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fabsf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized diff --git a/library/compiler-builtins/libm/src/math/fdim.rs b/library/compiler-builtins/libm/src/math/fdim.rs index 06edc99603551..014930097a02d 100644 --- a/library/compiler-builtins/libm/src/math/fdim.rs +++ b/library/compiler-builtins/libm/src/math/fdim.rs @@ -8,7 +8,6 @@ use core::f64; /// * NAN if either argument is NAN. /// /// A range error may occur. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fdim(x: f64, y: f64) -> f64 { if x.is_nan() { diff --git a/library/compiler-builtins/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/src/math/fdimf.rs index f1ad5896bf993..ea0b592d7ab97 100644 --- a/library/compiler-builtins/libm/src/math/fdimf.rs +++ b/library/compiler-builtins/libm/src/math/fdimf.rs @@ -8,7 +8,6 @@ use core::f32; /// * NAN if either argument is NAN. /// /// A range error may occur. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fdimf(x: f32, y: f32) -> f32 { if x.is_nan() { diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index f6068c697ac05..91825e3c88fd5 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -5,7 +5,6 @@ const TOINT: f64 = 1. / f64::EPSILON; /// Floor (f64) /// /// Finds the nearest integer less than or equal to `x`. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn floor(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index c04f18aeeea0d..6d751b077ef14 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -3,7 +3,6 @@ use core::f32; /// Floor (f32) /// /// Finds the nearest integer less than or equal to `x`. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn floorf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 07d90f8b727d2..5ea0d09ea9f09 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -10,7 +10,6 @@ struct Num { sign: i32, } -#[inline] fn normalize(x: f64) -> Num { let x1p63: f64 = f64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63 @@ -30,7 +29,6 @@ fn normalize(x: f64) -> Num { Num { m: ix, e, sign } } -#[inline] fn mul(x: u64, y: u64) -> (u64, u64) { let t1: u64; let t2: u64; @@ -53,7 +51,6 @@ fn mul(x: u64, y: u64) -> (u64, u64) { /// Computes `(x*y)+z`, rounded as one ternary operation: /// Computes the value (as if) to infinite precision and rounds once to the result format, /// according to the rounding mode characterized by the value of FLT_ROUNDS. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fma(x: f64, y: f64, z: f64) -> f64 { let x1p63: f64 = f64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63 diff --git a/library/compiler-builtins/libm/src/math/fmaf.rs b/library/compiler-builtins/libm/src/math/fmaf.rs index e77e0fa4a2535..03d371c55f202 100644 --- a/library/compiler-builtins/libm/src/math/fmaf.rs +++ b/library/compiler-builtins/libm/src/math/fmaf.rs @@ -46,7 +46,6 @@ use super::fenv::{ /// Computes `(x*y)+z`, rounded as one ternary operation: /// Computes the value (as if) to infinite precision and rounds once to the result format, /// according to the rounding mode characterized by the value of FLT_ROUNDS. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { let xy: f64; diff --git a/library/compiler-builtins/libm/src/math/fmax.rs b/library/compiler-builtins/libm/src/math/fmax.rs index 22016d11cc668..93c97bc611c7a 100644 --- a/library/compiler-builtins/libm/src/math/fmax.rs +++ b/library/compiler-builtins/libm/src/math/fmax.rs @@ -1,4 +1,3 @@ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmax(x: f64, y: f64) -> f64 { // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the diff --git a/library/compiler-builtins/libm/src/math/fmaxf.rs b/library/compiler-builtins/libm/src/math/fmaxf.rs index a883fdaef5bc0..60774664752d7 100644 --- a/library/compiler-builtins/libm/src/math/fmaxf.rs +++ b/library/compiler-builtins/libm/src/math/fmaxf.rs @@ -1,4 +1,3 @@ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmaxf(x: f32, y: f32) -> f32 { // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the diff --git a/library/compiler-builtins/libm/src/math/fmin.rs b/library/compiler-builtins/libm/src/math/fmin.rs index d1ccc3a468088..ab1509f34a652 100644 --- a/library/compiler-builtins/libm/src/math/fmin.rs +++ b/library/compiler-builtins/libm/src/math/fmin.rs @@ -1,4 +1,3 @@ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmin(x: f64, y: f64) -> f64 { // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the diff --git a/library/compiler-builtins/libm/src/math/fminf.rs b/library/compiler-builtins/libm/src/math/fminf.rs index 43ec97cb5b57e..0049e7117ae05 100644 --- a/library/compiler-builtins/libm/src/math/fminf.rs +++ b/library/compiler-builtins/libm/src/math/fminf.rs @@ -1,4 +1,3 @@ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fminf(x: f32, y: f32) -> f32 { // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the diff --git a/library/compiler-builtins/libm/src/math/fmod.rs b/library/compiler-builtins/libm/src/math/fmod.rs index 2cdd8a9ba3fde..d892ffd8b72a2 100644 --- a/library/compiler-builtins/libm/src/math/fmod.rs +++ b/library/compiler-builtins/libm/src/math/fmod.rs @@ -1,6 +1,5 @@ use core::u64; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmod(x: f64, y: f64) -> f64 { let mut uxi = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs index 3e6779a9304fb..c53dc186aebac 100644 --- a/library/compiler-builtins/libm/src/math/fmodf.rs +++ b/library/compiler-builtins/libm/src/math/fmodf.rs @@ -1,7 +1,6 @@ use core::f32; use core::u32; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmodf(x: f32, y: f32) -> f32 { let mut uxi = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/hypot.rs b/library/compiler-builtins/libm/src/math/hypot.rs index e53baf5399421..da458ea1d05f1 100644 --- a/library/compiler-builtins/libm/src/math/hypot.rs +++ b/library/compiler-builtins/libm/src/math/hypot.rs @@ -4,7 +4,6 @@ use super::sqrt; const SPLIT: f64 = 134217728. + 1.; // 0x1p27 + 1 === (2 ^ 27) + 1 -#[inline] fn sq(x: f64) -> (f64, f64) { let xh: f64; let xl: f64; @@ -18,7 +17,6 @@ fn sq(x: f64) -> (f64, f64) { (hi, lo) } -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn hypot(mut x: f64, mut y: f64) -> f64 { let x1p700 = f64::from_bits(0x6bb0000000000000); // 0x1p700 === 2 ^ 700 diff --git a/library/compiler-builtins/libm/src/math/hypotf.rs b/library/compiler-builtins/libm/src/math/hypotf.rs index 4636b8f1d8b77..576eebb334314 100644 --- a/library/compiler-builtins/libm/src/math/hypotf.rs +++ b/library/compiler-builtins/libm/src/math/hypotf.rs @@ -2,7 +2,6 @@ use core::f32; use super::sqrtf; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn hypotf(mut x: f32, mut y: f32) -> f32 { let x1p90 = f32::from_bits(0x6c800000); // 0x1p90f === 2 ^ 90 diff --git a/library/compiler-builtins/libm/src/math/k_cos.rs b/library/compiler-builtins/libm/src/math/k_cos.rs index 4687b369a6117..49b2fc64d8648 100644 --- a/library/compiler-builtins/libm/src/math/k_cos.rs +++ b/library/compiler-builtins/libm/src/math/k_cos.rs @@ -51,7 +51,6 @@ const C6: f64 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ // expression for cos(). Retention happens in all cases tested // under FreeBSD, so don't pessimize things by forcibly clipping // any extra precision in w. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_cos(x: f64, y: f64) -> f64 { let z = x * x; diff --git a/library/compiler-builtins/libm/src/math/k_cosf.rs b/library/compiler-builtins/libm/src/math/k_cosf.rs index 79d0f238fced2..e99f2348c00df 100644 --- a/library/compiler-builtins/libm/src/math/k_cosf.rs +++ b/library/compiler-builtins/libm/src/math/k_cosf.rs @@ -20,7 +20,6 @@ const C1: f64 = 0.0416666233237390631894; /* 0x155553e1053a42.0p-57 */ const C2: f64 = -0.00138867637746099294692; /* -0x16c087e80f1e27.0p-62 */ const C3: f64 = 0.0000243904487962774090654; /* 0x199342e0ee5069.0p-68 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_cosf(x: f64) -> f32 { let z = x * x; diff --git a/library/compiler-builtins/libm/src/math/k_expo2.rs b/library/compiler-builtins/libm/src/math/k_expo2.rs index 0a9562eaeaad7..7345075f37684 100644 --- a/library/compiler-builtins/libm/src/math/k_expo2.rs +++ b/library/compiler-builtins/libm/src/math/k_expo2.rs @@ -4,7 +4,6 @@ use super::exp; const K: i32 = 2043; /* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_expo2(x: f64) -> f64 { let k_ln2 = f64::from_bits(0x40962066151add8b); diff --git a/library/compiler-builtins/libm/src/math/k_expo2f.rs b/library/compiler-builtins/libm/src/math/k_expo2f.rs index de850777259b3..fbd7b27d5832f 100644 --- a/library/compiler-builtins/libm/src/math/k_expo2f.rs +++ b/library/compiler-builtins/libm/src/math/k_expo2f.rs @@ -4,7 +4,6 @@ use super::expf; const K: i32 = 235; /* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_expo2f(x: f32) -> f32 { let k_ln2 = f32::from_bits(0x4322e3bc); diff --git a/library/compiler-builtins/libm/src/math/k_sin.rs b/library/compiler-builtins/libm/src/math/k_sin.rs index 5d2bd68aa9555..9dd96c944744d 100644 --- a/library/compiler-builtins/libm/src/math/k_sin.rs +++ b/library/compiler-builtins/libm/src/math/k_sin.rs @@ -43,7 +43,6 @@ const S6: f64 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ // r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) // then 3 2 // sin(x) = x + (S1*x + (x *(r-y/2)+y)) -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_sin(x: f64, y: f64, iy: i32) -> f64 { let z = x * x; diff --git a/library/compiler-builtins/libm/src/math/k_sinf.rs b/library/compiler-builtins/libm/src/math/k_sinf.rs index 68fe926c21785..88d10cababc5d 100644 --- a/library/compiler-builtins/libm/src/math/k_sinf.rs +++ b/library/compiler-builtins/libm/src/math/k_sinf.rs @@ -20,7 +20,6 @@ const S2: f64 = 0.0083333293858894631756; /* 0x111110896efbb2.0p-59 */ const S3: f64 = -0.000198393348360966317347; /* -0x1a00f9e2cae774.0p-65 */ const S4: f64 = 0.0000027183114939898219064; /* 0x16cd878c3b46a7.0p-71 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_sinf(x: f64) -> f32 { let z = x * x; diff --git a/library/compiler-builtins/libm/src/math/k_tan.rs b/library/compiler-builtins/libm/src/math/k_tan.rs index ea3c386b00238..d177010bb0a0f 100644 --- a/library/compiler-builtins/libm/src/math/k_tan.rs +++ b/library/compiler-builtins/libm/src/math/k_tan.rs @@ -58,7 +58,6 @@ static T: [f64; 13] = [ const PIO4: f64 = 7.85398163397448278999e-01; /* 3FE921FB, 54442D18 */ const PIO4_LO: f64 = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { let hx = (f64::to_bits(x) >> 32) as u32; @@ -101,7 +100,6 @@ pub(crate) fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 { a0 + a * (1.0 + a0 * w0 + a0 * v) } -#[inline] fn zero_low_word(x: f64) -> f64 { f64::from_bits(f64::to_bits(x) & 0xFFFF_FFFF_0000_0000) } diff --git a/library/compiler-builtins/libm/src/math/k_tanf.rs b/library/compiler-builtins/libm/src/math/k_tanf.rs index 52651378db522..af8db539dad4a 100644 --- a/library/compiler-builtins/libm/src/math/k_tanf.rs +++ b/library/compiler-builtins/libm/src/math/k_tanf.rs @@ -19,7 +19,6 @@ const T: [f64; 6] = [ 0.00946564784943673166728, /* 0x1362b9bf971bcd.0p-59 */ ]; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn k_tanf(x: f64, odd: bool) -> f32 { let z = x * x; diff --git a/library/compiler-builtins/libm/src/math/ldexp.rs b/library/compiler-builtins/libm/src/math/ldexp.rs index 780ddfc11659f..e46242e55b254 100644 --- a/library/compiler-builtins/libm/src/math/ldexp.rs +++ b/library/compiler-builtins/libm/src/math/ldexp.rs @@ -1,4 +1,3 @@ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ldexp(x: f64, n: i32) -> f64 { super::scalbn(x, n) diff --git a/library/compiler-builtins/libm/src/math/ldexpf.rs b/library/compiler-builtins/libm/src/math/ldexpf.rs index 70935a0024e8b..95b27fc49d28e 100644 --- a/library/compiler-builtins/libm/src/math/ldexpf.rs +++ b/library/compiler-builtins/libm/src/math/ldexpf.rs @@ -1,4 +1,3 @@ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ldexpf(x: f32, n: i32) -> f32 { super::scalbnf(x, n) diff --git a/library/compiler-builtins/libm/src/math/log.rs b/library/compiler-builtins/libm/src/math/log.rs index 4126e413b77d6..27a26da60a987 100644 --- a/library/compiler-builtins/libm/src/math/log.rs +++ b/library/compiler-builtins/libm/src/math/log.rs @@ -70,7 +70,6 @@ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log(mut x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 diff --git a/library/compiler-builtins/libm/src/math/log10.rs b/library/compiler-builtins/libm/src/math/log10.rs index c99696040ab47..40dacf2c916bc 100644 --- a/library/compiler-builtins/libm/src/math/log10.rs +++ b/library/compiler-builtins/libm/src/math/log10.rs @@ -31,7 +31,6 @@ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log10(mut x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 diff --git a/library/compiler-builtins/libm/src/math/log10f.rs b/library/compiler-builtins/libm/src/math/log10f.rs index 9845cda5d950f..108dfa8b508ea 100644 --- a/library/compiler-builtins/libm/src/math/log10f.rs +++ b/library/compiler-builtins/libm/src/math/log10f.rs @@ -25,7 +25,6 @@ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log10f(mut x: f32) -> f32 { let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 diff --git a/library/compiler-builtins/libm/src/math/log1p.rs b/library/compiler-builtins/libm/src/math/log1p.rs index cd7045ac97ed4..4fd1c73eb81e5 100644 --- a/library/compiler-builtins/libm/src/math/log1p.rs +++ b/library/compiler-builtins/libm/src/math/log1p.rs @@ -65,7 +65,6 @@ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log1p(x: f64) -> f64 { let mut ui: u64 = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/log1pf.rs b/library/compiler-builtins/libm/src/math/log1pf.rs index 8e9651357d103..500e8eeaa85e9 100644 --- a/library/compiler-builtins/libm/src/math/log1pf.rs +++ b/library/compiler-builtins/libm/src/math/log1pf.rs @@ -20,7 +20,6 @@ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log1pf(x: f32) -> f32 { let mut ui: u32 = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/log2.rs b/library/compiler-builtins/libm/src/math/log2.rs index a3d43e55c2b77..83da3a19366f7 100644 --- a/library/compiler-builtins/libm/src/math/log2.rs +++ b/library/compiler-builtins/libm/src/math/log2.rs @@ -29,7 +29,6 @@ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log2(mut x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 diff --git a/library/compiler-builtins/libm/src/math/log2f.rs b/library/compiler-builtins/libm/src/math/log2f.rs index 53a37e5033749..3a20fb15bd699 100644 --- a/library/compiler-builtins/libm/src/math/log2f.rs +++ b/library/compiler-builtins/libm/src/math/log2f.rs @@ -23,7 +23,6 @@ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log2f(mut x: f32) -> f32 { let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 diff --git a/library/compiler-builtins/libm/src/math/logf.rs b/library/compiler-builtins/libm/src/math/logf.rs index 95195601c2d7c..2b57b934fb9f6 100644 --- a/library/compiler-builtins/libm/src/math/logf.rs +++ b/library/compiler-builtins/libm/src/math/logf.rs @@ -21,7 +21,6 @@ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn logf(mut x: f32) -> f32 { let x1p25 = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 diff --git a/library/compiler-builtins/libm/src/math/nextafter.rs b/library/compiler-builtins/libm/src/math/nextafter.rs index 4c1257e002711..13094a17c34b5 100644 --- a/library/compiler-builtins/libm/src/math/nextafter.rs +++ b/library/compiler-builtins/libm/src/math/nextafter.rs @@ -1,4 +1,3 @@ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn nextafter(x: f64, y: f64) -> f64 { if x.is_nan() || y.is_nan() { diff --git a/library/compiler-builtins/libm/src/math/nextafterf.rs b/library/compiler-builtins/libm/src/math/nextafterf.rs index a48bce9f742c2..df9b1082978a3 100644 --- a/library/compiler-builtins/libm/src/math/nextafterf.rs +++ b/library/compiler-builtins/libm/src/math/nextafterf.rs @@ -1,4 +1,3 @@ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn nextafterf(x: f32, y: f32) -> f32 { if x.is_nan() || y.is_nan() { diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 068a4ec47d4ab..ce8e83ee6f8e9 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -89,7 +89,6 @@ const IVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547_652b82fe =1/ln2 */ const IVLN2_H: f64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/ln2*/ const IVLN2_L: f64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn pow(x: f64, y: f64) -> f64 { let t1: f64; diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs index 015bade86c97d..f3cf76f9aa6ea 100644 --- a/library/compiler-builtins/libm/src/math/powf.rs +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -43,7 +43,6 @@ const IVLN2: f32 = 1.4426950216e+00; const IVLN2_H: f32 = 1.4426879883e+00; const IVLN2_L: f32 = 7.0526075433e-06; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn powf(x: f32, y: f32) -> f32 { let mut z: f32; diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index dc6b3297d93ca..6b7dbd348c6cd 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -41,7 +41,6 @@ const PIO2_3T: f64 = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ // use rem_pio2_large() for large x // // caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { let x1p24 = f64::from_bits(0x4170000000000000); @@ -49,7 +48,6 @@ pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { let sign = (f64::to_bits(x) >> 63) as i32; let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; - #[inline] fn medium(x: f64, ix: u32) -> (i32, f64, f64) { /* rint(x/(pi/2)), Assume round-to-nearest. */ let f_n = x as f64 * INV_PIO2 + TO_INT - TO_INT; 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 5336a97671935..8533dc28948d5 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -222,7 +222,6 @@ const PIO2: [f64; 8] = [ /// skip the part of the product that are known to be a huge integer ( /// more accurately, = 0 mod 8 ). Thus the number of operations are /// independent of the exponent of the input. -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 { let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs index af2745d1be94d..5d392ba2d7fe0 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2f.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2f.rs @@ -31,7 +31,6 @@ const PIO2_1T: f64 = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ /// /// use double precision for everything except passing x /// use __rem_pio2_large() for large x -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub(crate) fn rem_pio2f(x: f32) -> (i32, f64) { let x64 = x as f64; diff --git a/library/compiler-builtins/libm/src/math/remainder.rs b/library/compiler-builtins/libm/src/math/remainder.rs index 7ce895004b897..9e966c9ed7f4a 100644 --- a/library/compiler-builtins/libm/src/math/remainder.rs +++ b/library/compiler-builtins/libm/src/math/remainder.rs @@ -1,4 +1,3 @@ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn remainder(x: f64, y: f64) -> f64 { let (result, _) = super::remquo(x, y); diff --git a/library/compiler-builtins/libm/src/math/remainderf.rs b/library/compiler-builtins/libm/src/math/remainderf.rs index 8b2aa5aabbc95..b1407cf2ace36 100644 --- a/library/compiler-builtins/libm/src/math/remainderf.rs +++ b/library/compiler-builtins/libm/src/math/remainderf.rs @@ -1,4 +1,3 @@ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn remainderf(x: f32, y: f32) -> f32 { let (result, _) = super::remquof(x, y); diff --git a/library/compiler-builtins/libm/src/math/remquo.rs b/library/compiler-builtins/libm/src/math/remquo.rs index c72c8f1878e19..0afd1f7f5f2a3 100644 --- a/library/compiler-builtins/libm/src/math/remquo.rs +++ b/library/compiler-builtins/libm/src/math/remquo.rs @@ -1,3 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn remquo(mut x: f64, mut y: f64) -> (f64, i32) { let ux: u64 = x.to_bits(); let mut uy: u64 = y.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/remquof.rs b/library/compiler-builtins/libm/src/math/remquof.rs index 871d0c7d6967d..d71bd38e3ddca 100644 --- a/library/compiler-builtins/libm/src/math/remquof.rs +++ b/library/compiler-builtins/libm/src/math/remquof.rs @@ -1,3 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn remquof(mut x: f32, mut y: f32) -> (f32, i32) { let ux: u32 = x.to_bits(); let mut uy: u32 = y.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs index 67590d2c19b92..bf72f5b941dc7 100644 --- a/library/compiler-builtins/libm/src/math/round.rs +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -2,7 +2,6 @@ use core::f64; const TOINT: f64 = 1.0 / f64::EPSILON; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn round(mut x: f64) -> f64 { let i = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs index 85114be4ba119..497e88d6254a4 100644 --- a/library/compiler-builtins/libm/src/math/roundf.rs +++ b/library/compiler-builtins/libm/src/math/roundf.rs @@ -2,7 +2,6 @@ use core::f32; const TOINT: f32 = 1.0 / f32::EPSILON; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn roundf(mut x: f32) -> f32 { let i = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/scalbn.rs b/library/compiler-builtins/libm/src/math/scalbn.rs index d8c8409ac10c6..00c455a106531 100644 --- a/library/compiler-builtins/libm/src/math/scalbn.rs +++ b/library/compiler-builtins/libm/src/math/scalbn.rs @@ -1,4 +1,3 @@ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn scalbn(x: f64, mut n: i32) -> f64 { let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 diff --git a/library/compiler-builtins/libm/src/math/scalbnf.rs b/library/compiler-builtins/libm/src/math/scalbnf.rs index 4e9771175d29b..73f4bb57aaf2f 100644 --- a/library/compiler-builtins/libm/src/math/scalbnf.rs +++ b/library/compiler-builtins/libm/src/math/scalbnf.rs @@ -1,4 +1,3 @@ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn scalbnf(mut x: f32, mut n: i32) -> f32 { let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 diff --git a/library/compiler-builtins/libm/src/math/sin.rs b/library/compiler-builtins/libm/src/math/sin.rs index 51aed88a8dbbc..1329b41a9d602 100644 --- a/library/compiler-builtins/libm/src/math/sin.rs +++ b/library/compiler-builtins/libm/src/math/sin.rs @@ -40,7 +40,6 @@ use super::{k_cos, k_sin, rem_pio2}; // // Accuracy: // TRIG(x) returns trig(x) nearly rounded -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sin(x: f64) -> f64 { let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 diff --git a/library/compiler-builtins/libm/src/math/sinf.rs b/library/compiler-builtins/libm/src/math/sinf.rs index 0c31099edd215..6e20be2aeee38 100644 --- a/library/compiler-builtins/libm/src/math/sinf.rs +++ b/library/compiler-builtins/libm/src/math/sinf.rs @@ -24,7 +24,6 @@ const S2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ const S3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ const S4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sinf(x: f32) -> f32 { let x64 = x as f64; diff --git a/library/compiler-builtins/libm/src/math/sinh.rs b/library/compiler-builtins/libm/src/math/sinh.rs index d36de66c1c0a9..fd24fd20cf72b 100644 --- a/library/compiler-builtins/libm/src/math/sinh.rs +++ b/library/compiler-builtins/libm/src/math/sinh.rs @@ -4,7 +4,6 @@ use super::{expm1, expo2}; // = (exp(x)-1 + (exp(x)-1)/exp(x))/2 // = x + x^3/6 + o(x^5) // -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sinh(x: f64) -> f64 { // union {double f; uint64_t i;} u = {.f = x}; diff --git a/library/compiler-builtins/libm/src/math/sinhf.rs b/library/compiler-builtins/libm/src/math/sinhf.rs index fd0b2bfc8943e..24f863c4465e2 100644 --- a/library/compiler-builtins/libm/src/math/sinhf.rs +++ b/library/compiler-builtins/libm/src/math/sinhf.rs @@ -1,7 +1,6 @@ use super::expm1f; use super::k_expo2f; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sinhf(x: f32) -> f32 { let mut h = 0.5f32; diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 14404d4eb18b9..58cf00ed8888c 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -81,7 +81,6 @@ use core::num::Wrapping; const TINY: f64 = 1.0e-300; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrt(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index b9365c6171615..889b525812254 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -15,7 +15,6 @@ const TINY: f32 = 1.0e-30; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrtf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized diff --git a/library/compiler-builtins/libm/src/math/tan.rs b/library/compiler-builtins/libm/src/math/tan.rs index e5c94cbb1565d..5a72f68014abe 100644 --- a/library/compiler-builtins/libm/src/math/tan.rs +++ b/library/compiler-builtins/libm/src/math/tan.rs @@ -39,7 +39,6 @@ use super::{k_tan, rem_pio2}; // // Accuracy: // TRIG(x) returns trig(x) nearly rounded -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tan(x: f64) -> f64 { let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 diff --git a/library/compiler-builtins/libm/src/math/tanf.rs b/library/compiler-builtins/libm/src/math/tanf.rs index c286cdeb419ec..10de59c3917de 100644 --- a/library/compiler-builtins/libm/src/math/tanf.rs +++ b/library/compiler-builtins/libm/src/math/tanf.rs @@ -24,7 +24,6 @@ const T2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ const T3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ const T4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tanf(x: f32) -> f32 { let x64 = x as f64; diff --git a/library/compiler-builtins/libm/src/math/tanh.rs b/library/compiler-builtins/libm/src/math/tanh.rs index 75d695cf7e9d5..980c68554fd8b 100644 --- a/library/compiler-builtins/libm/src/math/tanh.rs +++ b/library/compiler-builtins/libm/src/math/tanh.rs @@ -4,7 +4,6 @@ use super::expm1; * = (exp(2*x) - 1)/(exp(2*x) - 1 + 2) * = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2) */ -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tanh(mut x: f64) -> f64 { let mut uf: f64 = x; diff --git a/library/compiler-builtins/libm/src/math/tanhf.rs b/library/compiler-builtins/libm/src/math/tanhf.rs index ac4657b5abdbc..fc94e3ddd5899 100644 --- a/library/compiler-builtins/libm/src/math/tanhf.rs +++ b/library/compiler-builtins/libm/src/math/tanhf.rs @@ -1,6 +1,5 @@ use super::expm1f; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tanhf(mut x: f32) -> f32 { /* x = |x| */ diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs index 1ee46fc7dae61..f7892a2c55367 100644 --- a/library/compiler-builtins/libm/src/math/trunc.rs +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -1,6 +1,5 @@ use core::f64; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn trunc(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs index f93383269057d..a4c001629a24a 100644 --- a/library/compiler-builtins/libm/src/math/truncf.rs +++ b/library/compiler-builtins/libm/src/math/truncf.rs @@ -1,6 +1,5 @@ use core::f32; -#[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn truncf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized From c2b0bbb814544d8c8ccc662b6294948629f0ceb6 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 10 Jul 2019 13:01:02 +0200 Subject: [PATCH 0776/4206] Fix overflow bug in fma --- .../compiler-builtins/libm/src/math/fma.rs | 4 ++-- library/compiler-builtins/libm/tests/unit.rs | 19 ------------------- 2 files changed, 2 insertions(+), 21 deletions(-) delete mode 100644 library/compiler-builtins/libm/tests/unit.rs diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 6d4471a9a04fd..99f77bc7967aa 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -126,8 +126,8 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { } else { /* r -= z */ let t = rlo; - rlo -= zlo; - rhi = rhi - zhi - (t < rlo) as u64; + rlo = rlo.wrapping_sub(zlo); + rhi = rhi.wrapping_sub(zhi.wrapping_sub((t < rlo) as u64)); if (rhi >> 63) != 0 { rlo = (-(rlo as i64)) as u64; rhi = (-(rhi as i64)) as u64 - (rlo != 0) as u64; diff --git a/library/compiler-builtins/libm/tests/unit.rs b/library/compiler-builtins/libm/tests/unit.rs deleted file mode 100644 index 4e7002817a648..0000000000000 --- a/library/compiler-builtins/libm/tests/unit.rs +++ /dev/null @@ -1,19 +0,0 @@ -use libm::*; - -#[test] -fn fma_segfault() { - // These two inputs cause fma to segfault on release due to overflow: - assert_eq!( - fma( - -0.0000000000000002220446049250313, - -0.0000000000000002220446049250313, - -0.0000000000000002220446049250313 - ), - -0.00000000000000022204460492503126, - ); - - assert_eq!( - fma(-0.992, -0.992, -0.992), - -0.00793599999988632, - ); -} From f4bc012b26ead3e50d25e1f878b7447a058d447c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Jul 2019 10:55:54 +0200 Subject: [PATCH 0777/4206] avoid ptr::write which might panic in debug mode --- library/compiler-builtins/src/arm.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 9bfffb74fc95f..ab35ec92b240a 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -137,11 +137,12 @@ pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: us pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, mut n: usize) { use core::ptr; + // We are guaranteed 4-alignment, so accessing at u32 is okay. let mut dest = dest as *mut u32; let mut src = src as *mut u32; while n >= 4 { - ptr::write(dest, ptr::read(src)); + *dest = *src; dest = dest.offset(1); src = src.offset(1); n -= 4; @@ -198,7 +199,7 @@ pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, mut n: usize, c: i32 let c = (byte << 24) | (byte << 16) | (byte << 8) | byte; while n >= 4 { - ptr::write(dest, c); + *dest = c; dest = dest.offset(1); n -= 4; } From 29ea38c623296267d568ad18a4818c6808dcd93c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Jul 2019 11:00:15 +0200 Subject: [PATCH 0778/4206] remove unused imports --- library/compiler-builtins/src/arm.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index ab35ec92b240a..4cf73ef37ac04 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -135,8 +135,6 @@ pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: us #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, mut n: usize) { - use core::ptr; - // We are guaranteed 4-alignment, so accessing at u32 is okay. let mut dest = dest as *mut u32; let mut src = src as *mut u32; @@ -191,8 +189,6 @@ pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(thumb, linkage = "weak")] pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, mut n: usize, c: i32) { - use core::ptr; - let mut dest = dest as *mut u32; let byte = (c as u32) & 0xff; From 8ae096b54455b84e6a36ecef05215163b5fd1f08 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Jul 2019 11:07:43 +0200 Subject: [PATCH 0779/4206] avoid bare trait objects --- library/compiler-builtins/examples/intrinsics.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index f6980fcb56649..8b0ffa3a8d6ae 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -350,8 +350,8 @@ fn run() { // } } -fn something_with_a_dtor(f: &Fn()) { - struct A<'a>(&'a (Fn() + 'a)); +fn something_with_a_dtor(f: &dyn Fn()) { + struct A<'a>(&'a (dyn Fn() + 'a)); impl<'a> Drop for A<'a> { fn drop(&mut self) { From 8bd3e4d5a18facf044f0c740db44605dd2bdc69f Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 13 Jul 2019 11:38:35 +0200 Subject: [PATCH 0780/4206] Replace {u,i}128_* lang items with __rust_{u,i}128_* unmangled functions The -Zlower-128bit-ops feature is completely broken, as libcore needs those lang items to compile with this feature, but they are only provided by compiler_builtins, which itself depends on libcore. According to rust-lang/rust#58969 the feature never got finished. This commit removes the associated lang items and replaces them with normal unmangled functions, when there is no existing intrinsic. This makes it easier for alternative codegen backends to implement 128bit integer support. --- library/compiler-builtins/src/int/addsub.rs | 37 ++++++++++--------- library/compiler-builtins/src/int/mul.rs | 17 ++------- library/compiler-builtins/src/int/sdiv.rs | 11 ------ library/compiler-builtins/src/int/shift.rs | 40 ++++++--------------- library/compiler-builtins/src/int/udiv.rs | 11 ------ library/compiler-builtins/src/macros.rs | 14 -------- 6 files changed, 31 insertions(+), 99 deletions(-) diff --git a/library/compiler-builtins/src/int/addsub.rs b/library/compiler-builtins/src/int/addsub.rs index e2d5bcbd4354a..0a88e2fc8f13c 100644 --- a/library/compiler-builtins/src/int/addsub.rs +++ b/library/compiler-builtins/src/int/addsub.rs @@ -90,44 +90,43 @@ where impl Subo for i128 {} impl Subo for u128 {} -u128_lang_items! { - #[lang = "i128_add"] - pub fn rust_i128_add(a: i128, b: i128) -> i128 { - rust_u128_add(a as _, b as _) as _ +intrinsics! { + pub extern "C" fn __rust_i128_add(a: i128, b: i128) -> i128 { + __rust_u128_add(a as _, b as _) as _ } - #[lang = "i128_addo"] - pub fn rust_i128_addo(a: i128, b: i128) -> (i128, bool) { + + pub extern "C" fn __rust_i128_addo(a: i128, b: i128) -> (i128, bool) { let mut oflow = 0; let r = a.addo(b, &mut oflow); (r, oflow != 0) } - #[lang = "u128_add"] - pub fn rust_u128_add(a: u128, b: u128) -> u128 { + + pub extern "C" fn __rust_u128_add(a: u128, b: u128) -> u128 { a.add(b) } - #[lang = "u128_addo"] - pub fn rust_u128_addo(a: u128, b: u128) -> (u128, bool) { + + pub extern "C" fn __rust_u128_addo(a: u128, b: u128) -> (u128, bool) { let mut oflow = 0; let r = a.addo(b, &mut oflow); (r, oflow != 0) } - #[lang = "i128_sub"] - pub fn rust_i128_sub(a: i128, b: i128) -> i128 { - rust_u128_sub(a as _, b as _) as _ + + pub extern "C" fn __rust_i128_sub(a: i128, b: i128) -> i128 { + __rust_u128_sub(a as _, b as _) as _ } - #[lang = "i128_subo"] - pub fn rust_i128_subo(a: i128, b: i128) -> (i128, bool) { + + pub extern "C" fn __rust_i128_subo(a: i128, b: i128) -> (i128, bool) { let mut oflow = 0; let r = a.subo(b, &mut oflow); (r, oflow != 0) } - #[lang = "u128_sub"] - pub fn rust_u128_sub(a: u128, b: u128) -> u128 { + + pub extern "C" fn __rust_u128_sub(a: u128, b: u128) -> u128 { a.sub(b) } - #[lang = "u128_subo"] - pub fn rust_u128_subo(a: u128, b: u128) -> (u128, bool) { + + pub extern "C" fn __rust_u128_subo(a: u128, b: u128) -> (u128, bool) { let mut oflow = 0; let r = a.subo(b, &mut oflow); (r, oflow != 0) diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 8df58a27b6a5f..42f13913e3e7e 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -107,25 +107,14 @@ intrinsics! { pub extern "C" fn __muloti4(a: i128, b: i128, oflow: &mut i32) -> i128 { a.mulo(b, oflow) } -} -u128_lang_items! { - #[lang = "i128_mul"] - pub fn rust_i128_mul(a: i128, b: i128) -> i128 { - __multi3(a, b) - } - #[lang = "i128_mulo"] - pub fn rust_i128_mulo(a: i128, b: i128) -> (i128, bool) { + pub extern "C" fn __rust_i128_mulo(a: i128, b: i128) -> (i128, bool) { let mut oflow = 0; let r = __muloti4(a, b, &mut oflow); (r, oflow != 0) } - #[lang = "u128_mul"] - pub fn rust_u128_mul(a: u128, b: u128) -> u128 { - __multi3(a as _, b as _) as _ - } - #[lang = "u128_mulo"] - pub fn rust_u128_mulo(a: u128, b: u128) -> (u128, bool) { + + pub extern "C" fn __rust_u128_mulo(a: u128, b: u128) -> (u128, bool) { let mut oflow = 0; let r = a.mulo(b, &mut oflow); (r, oflow != 0) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index ad7f67b1b4c9e..c9e252cc3b0e5 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -99,14 +99,3 @@ intrinsics! { a.divmod(b, rem, |a, b| __divdi3(a, b)) } } - -u128_lang_items! { - #[lang = "i128_div"] - pub fn rust_i128_div(a: i128, b: i128) -> i128 { - __divti3(a, b) - } - #[lang = "i128_rem"] - pub fn rust_i128_rem(a: i128, b: i128) -> i128 { - __modti3(a, b) - } -} diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index d98622279e706..408f8f3ccbb77 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -103,40 +103,20 @@ intrinsics! { pub extern "C" fn __lshrti3(a: u128, b: u32) -> u128 { a.lshr(b) } -} -u128_lang_items! { - #[lang = "i128_shl"] - pub fn rust_i128_shl(a: i128, b: u32) -> i128 { - __ashlti3(a as _, b) as _ - } - #[lang = "i128_shlo"] - pub fn rust_i128_shlo(a: i128, b: u128) -> (i128, bool) { - (rust_i128_shl(a, b as _), b >= 128) - } - #[lang = "u128_shl"] - pub fn rust_u128_shl(a: u128, b: u32) -> u128 { - __ashlti3(a, b) - } - #[lang = "u128_shlo"] - pub fn rust_u128_shlo(a: u128, b: u128) -> (u128, bool) { - (rust_u128_shl(a, b as _), b >= 128) + pub extern "C" fn __rust_i128_shlo(a: i128, b: u128) -> (i128, bool) { + (__ashlti3(a as _, b as _) as _, b >= 128) } - #[lang = "i128_shr"] - pub fn rust_i128_shr(a: i128, b: u32) -> i128 { - __ashrti3(a, b) + pub extern "C" fn __rust_u128_shlo(a: u128, b: u128) -> (u128, bool) { + (__ashlti3(a, b as _), b >= 128) } - #[lang = "i128_shro"] - pub fn rust_i128_shro(a: i128, b: u128) -> (i128, bool) { - (rust_i128_shr(a, b as _), b >= 128) - } - #[lang = "u128_shr"] - pub fn rust_u128_shr(a: u128, b: u32) -> u128 { - __lshrti3(a, b) + + pub extern "C" fn __rust_i128_shro(a: i128, b: u128) -> (i128, bool) { + (__ashrti3(a, b as _), b >= 128) } - #[lang = "u128_shro"] - pub fn rust_u128_shro(a: u128, b: u128) -> (u128, bool) { - (rust_u128_shr(a, b as _), b >= 128) + + pub extern "C" fn __rust_u128_shro(a: u128, b: u128) -> (u128, bool) { + (__lshrti3(a, b as _), b >= 128) } } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index cdec11d2f16a3..b393ac6db1282 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -268,14 +268,3 @@ intrinsics! { udivmod_inner!(n, d, rem, u128) } } - -u128_lang_items! { - #[lang = "u128_div"] - pub fn rust_u128_div(a: u128, b: u128) -> u128 { - __udivti3(a, b) - } - #[lang = "u128_rem"] - pub fn rust_u128_rem(a: u128, b: u128) -> u128 { - __umodti3(a, b) - } -} diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 4abdae6eee0cf..2d11ba622b817 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -280,17 +280,3 @@ pub mod win64_128bit_abi_hack { } } } - -macro_rules! u128_lang_items { - ($( - #[lang = $lang:tt] - pub fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { - $($body:tt)* - } - )*) => ($( - #[cfg_attr(not(any(stage0, feature = "no-lang-items")), lang = $lang)] - pub fn $name( $($argname: $ty),* ) -> $ret { - $($body)* - } - )*) -} From 4ca09454a8603715d51a4ff4c3ea40e020a9949d Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 13 Jul 2019 12:27:58 +0200 Subject: [PATCH 0781/4206] Fix tests --- library/compiler-builtins/testcrate/build.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index e43fdb77b88a8..4bd4005b705f4 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -707,35 +707,35 @@ fn main() { // int/addsub.rs gen( |(a, b): (MyU128, MyU128)| Some(a.0.wrapping_add(b.0)), - "builtins::int::addsub::rust_u128_add(a, b)", + "builtins::int::addsub::__rust_u128_add(a, b)", ); gen( |(a, b): (MyI128, MyI128)| Some(a.0.wrapping_add(b.0)), - "builtins::int::addsub::rust_i128_add(a, b)", + "builtins::int::addsub::__rust_i128_add(a, b)", ); gen( |(a, b): (MyU128, MyU128)| Some(a.0.overflowing_add(b.0)), - "builtins::int::addsub::rust_u128_addo(a, b)", + "builtins::int::addsub::__rust_u128_addo(a, b)", ); gen( |(a, b): (MyI128, MyI128)| Some(a.0.overflowing_add(b.0)), - "builtins::int::addsub::rust_i128_addo(a, b)", + "builtins::int::addsub::__rust_i128_addo(a, b)", ); gen( |(a, b): (MyU128, MyU128)| Some(a.0.wrapping_sub(b.0)), - "builtins::int::addsub::rust_u128_sub(a, b)", + "builtins::int::addsub::__rust_u128_sub(a, b)", ); gen( |(a, b): (MyI128, MyI128)| Some(a.0.wrapping_sub(b.0)), - "builtins::int::addsub::rust_i128_sub(a, b)", + "builtins::int::addsub::__rust_i128_sub(a, b)", ); gen( |(a, b): (MyU128, MyU128)| Some(a.0.overflowing_sub(b.0)), - "builtins::int::addsub::rust_u128_subo(a, b)", + "builtins::int::addsub::__rust_u128_subo(a, b)", ); gen( |(a, b): (MyI128, MyI128)| Some(a.0.overflowing_sub(b.0)), - "builtins::int::addsub::rust_i128_subo(a, b)", + "builtins::int::addsub::__rust_i128_subo(a, b)", ); // int/mul.rs From 7773dafe014c407b6e01fb342e2af282ddaf9422 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 15 Jul 2019 07:26:49 -0700 Subject: [PATCH 0782/4206] Bump to 0.1.17 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index e0bb22d218af7..fed7beead7f90 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.16" +version = "0.1.17" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" From fb3519099873118e14312d8fb469c464e10558fc Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 19 Jul 2019 07:44:17 -0700 Subject: [PATCH 0783/4206] Bump to 0.1.18 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index fed7beead7f90..1436d9b4def90 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.17" +version = "0.1.18" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" From 84e8cc74c57190a1c4321a3db7b6a9a5c9a626a1 Mon Sep 17 00:00:00 2001 From: Dan Aloni Date: Wed, 24 Jul 2019 08:59:54 +0300 Subject: [PATCH 0784/4206] probestack: add frame pointers for easier traceback This turns the following backtrace, ``` >> bt #0 0x0000555555576f73 in __rust_probestack () at /cargo/registry/src/github.com-1ecc6299db9ec823/compiler_builtins-0.1.14/src/probestack.rs:55 Backtrace stopped: Cannot access memory at address 0x7fffff7fedf0 ``` To this: ``` >>> bt #0 0x0000555555574e47 in __rust_probestack () #1 0x00005555555595ba in test::main () #2 0x00005555555594f3 in std::rt::lang_start::{{closure}} () #3 0x0000555555561ae3 in std::panicking::try::do_call () #4 0x000055555556595a in __rust_maybe_catch_panic () #5 0x000055555555af9b in std::rt::lang_start_internal () #6 0x00005555555594d5 in std::rt::lang_start () #7 0x000055555555977b in main () ``` --- library/compiler-builtins/src/probestack.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index f9284e8140515..9bcaf4fd13dcb 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -53,6 +53,9 @@ pub unsafe extern "C" fn __rust_probestack() { // The ABI here is that the stack frame size is located in `%eax`. Upon // return we're not supposed to modify `%esp` or `%eax`. asm!(" + pushq %rbp + movq %rsp, %rbp + mov %rax,%r11 // duplicate %rax as we're clobbering %r11 // Main loop, taken in one page increments. We're decrementing rsp by @@ -89,6 +92,7 @@ pub unsafe extern "C" fn __rust_probestack() { // return. add %rax,%rsp + leave ret " ::: "memory" : "volatile"); ::core::intrinsics::unreachable(); @@ -104,6 +108,8 @@ pub unsafe extern "C" fn __rust_probestack() { // // The ABI here is the same as x86_64, except everything is 32-bits large. asm!(" + push %ebp + mov %esp, %ebp push %ecx mov %eax,%ecx @@ -122,6 +128,7 @@ pub unsafe extern "C" fn __rust_probestack() { add %eax,%esp pop %ecx + leave ret " ::: "memory" : "volatile"); ::core::intrinsics::unreachable(); From 8b76d4463610c07f2018fc8c22ef4be29df678d5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 24 Jul 2019 07:05:29 -0700 Subject: [PATCH 0785/4206] Bump to 0.1.19 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 1436d9b4def90..0705dbd9c32b3 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.18" +version = "0.1.19" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang-nursery/compiler-builtins" From d19e47014ac1aa1e6f0d1b60753caef7dfd8db3c Mon Sep 17 00:00:00 2001 From: Lokathor Date: Wed, 7 Aug 2019 14:06:12 -0600 Subject: [PATCH 0786/4206] Improve sqrt/sqrtf if stable intrinsics allow --- .../compiler-builtins/libm/src/math/sqrt.rs | 252 ++++++++++-------- .../compiler-builtins/libm/src/math/sqrtf.rs | 160 ++++++----- 2 files changed, 224 insertions(+), 188 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 58cf00ed8888c..f01267da7274d 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -95,128 +95,146 @@ pub fn sqrt(x: f64) -> f64 { } } } - let mut z: f64; - let sign: Wrapping = Wrapping(0x80000000); - let mut ix0: i32; - let mut s0: i32; - let mut q: i32; - let mut m: i32; - let mut t: i32; - let mut i: i32; - let mut r: Wrapping; - let mut t1: Wrapping; - let mut s1: Wrapping; - let mut ix1: Wrapping; - let mut q1: Wrapping; + #[cfg(target_feature="sse2")] + { + // Note(Lokathor): If compile time settings allow, we just use SSE2, since + // the sqrt in `std` on these platforms also compiles down to an SSE2 + // instruction. + #[cfg(target_arch="x86")] + use core::arch::x86::*; + #[cfg(target_arch="x86_64")] + use core::arch::x86_64::*; + unsafe { + let m = _mm_set_sd(x); + let m_sqrt = _mm_sqrt_pd(m); + _mm_cvtsd_f64(m_sqrt) + } + } + #[cfg(not(target_feature="sse2"))] + { + let mut z: f64; + let sign: Wrapping = Wrapping(0x80000000); + let mut ix0: i32; + let mut s0: i32; + let mut q: i32; + let mut m: i32; + let mut t: i32; + let mut i: i32; + let mut r: Wrapping; + let mut t1: Wrapping; + let mut s1: Wrapping; + let mut ix1: Wrapping; + let mut q1: Wrapping; - ix0 = (x.to_bits() >> 32) as i32; - ix1 = Wrapping(x.to_bits() as u32); + ix0 = (x.to_bits() >> 32) as i32; + ix1 = Wrapping(x.to_bits() as u32); - /* take care of Inf and NaN */ - if (ix0 & 0x7ff00000) == 0x7ff00000 { - return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ - } - /* take care of zero */ - if ix0 <= 0 { - if ((ix0 & !(sign.0 as i32)) | ix1.0 as i32) == 0 { - return x; /* sqrt(+-0) = +-0 */ - } - if ix0 < 0 { - return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ - } - } - /* normalize x */ - m = ix0 >> 20; - if m == 0 { - /* subnormal x */ - while ix0 == 0 { - m -= 21; - ix0 |= (ix1 >> 11).0 as i32; - ix1 <<= 21; - } - i = 0; - while (ix0 & 0x00100000) == 0 { - i += 1; - ix0 <<= 1; - } - m -= i - 1; - ix0 |= (ix1 >> (32 - i) as usize).0 as i32; - ix1 = ix1 << i as usize; - } - m -= 1023; /* unbias exponent */ - ix0 = (ix0 & 0x000fffff) | 0x00100000; - if (m & 1) == 1 { - /* odd m, double x to make it even */ - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - } - m >>= 1; /* m = [m/2] */ + /* take care of Inf and NaN */ + if (ix0 & 0x7ff00000) == 0x7ff00000 { + return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + } + /* take care of zero */ + if ix0 <= 0 { + if ((ix0 & !(sign.0 as i32)) | ix1.0 as i32) == 0 { + return x; /* sqrt(+-0) = +-0 */ + } + if ix0 < 0 { + return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ + } + } + /* normalize x */ + m = ix0 >> 20; + if m == 0 { + /* subnormal x */ + while ix0 == 0 { + m -= 21; + ix0 |= (ix1 >> 11).0 as i32; + ix1 <<= 21; + } + i = 0; + while (ix0 & 0x00100000) == 0 { + i += 1; + ix0 <<= 1; + } + m -= i - 1; + ix0 |= (ix1 >> (32 - i) as usize).0 as i32; + ix1 = ix1 << i as usize; + } + m -= 1023; /* unbias exponent */ + ix0 = (ix0 & 0x000fffff) | 0x00100000; + if (m & 1) == 1 { + /* odd m, double x to make it even */ + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + } + m >>= 1; /* m = [m/2] */ - /* generate sqrt(x) bit by bit */ - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - q = 0; /* [q,q1] = sqrt(x) */ - q1 = Wrapping(0); - s0 = 0; - s1 = Wrapping(0); - r = Wrapping(0x00200000); /* r = moving bit from right to left */ + /* generate sqrt(x) bit by bit */ + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + q = 0; /* [q,q1] = sqrt(x) */ + q1 = Wrapping(0); + s0 = 0; + s1 = Wrapping(0); + r = Wrapping(0x00200000); /* r = moving bit from right to left */ - while r != Wrapping(0) { - t = s0 + r.0 as i32; - if t <= ix0 { - s0 = t + r.0 as i32; - ix0 -= t; - q += r.0 as i32; - } - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - r >>= 1; - } + while r != Wrapping(0) { + t = s0 + r.0 as i32; + if t <= ix0 { + s0 = t + r.0 as i32; + ix0 -= t; + q += r.0 as i32; + } + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + r >>= 1; + } - r = sign; - while r != Wrapping(0) { - t1 = s1 + r; - t = s0; - if t < ix0 || (t == ix0 && t1 <= ix1) { - s1 = t1 + r; - if (t1 & sign) == sign && (s1 & sign) == Wrapping(0) { - s0 += 1; - } - ix0 -= t; - if ix1 < t1 { - ix0 -= 1; - } - ix1 -= t1; - q1 += r; - } - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - r >>= 1; - } + r = sign; + while r != Wrapping(0) { + t1 = s1 + r; + t = s0; + if t < ix0 || (t == ix0 && t1 <= ix1) { + s1 = t1 + r; + if (t1 & sign) == sign && (s1 & sign) == Wrapping(0) { + s0 += 1; + } + ix0 -= t; + if ix1 < t1 { + ix0 -= 1; + } + ix1 -= t1; + q1 += r; + } + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + r >>= 1; + } - /* use floating add to find out rounding direction */ - if (ix0 as u32 | ix1.0) != 0 { - z = 1.0 - TINY; /* raise inexact flag */ - if z >= 1.0 { - z = 1.0 + TINY; - if q1.0 == 0xffffffff { - q1 = Wrapping(0); - q += 1; - } else if z > 1.0 { - if q1.0 == 0xfffffffe { - q += 1; - } - q1 += Wrapping(2); - } else { - q1 += q1 & Wrapping(1); - } - } - } - ix0 = (q >> 1) + 0x3fe00000; - ix1 = q1 >> 1; - if (q & 1) == 1 { - ix1 |= sign; + /* use floating add to find out rounding direction */ + if (ix0 as u32 | ix1.0) != 0 { + z = 1.0 - TINY; /* raise inexact flag */ + if z >= 1.0 { + z = 1.0 + TINY; + if q1.0 == 0xffffffff { + q1 = Wrapping(0); + q += 1; + } else if z > 1.0 { + if q1.0 == 0xfffffffe { + q += 1; + } + q1 += Wrapping(2); + } else { + q1 += q1 & Wrapping(1); + } + } + } + ix0 = (q >> 1) + 0x3fe00000; + ix1 = q1 >> 1; + if (q & 1) == 1 { + ix1 |= sign; + } + ix0 += m << 20; + f64::from_bits((ix0 as u64) << 32 | ix1.0 as u64) } - ix0 += m << 20; - f64::from_bits((ix0 as u64) << 32 | ix1.0 as u64) } diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 889b525812254..a4d9ab53deb5c 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -29,83 +29,101 @@ pub fn sqrtf(x: f32) -> f32 { } } } - let mut z: f32; - let sign: i32 = 0x80000000u32 as i32; - let mut ix: i32; - let mut s: i32; - let mut q: i32; - let mut m: i32; - let mut t: i32; - let mut i: i32; - let mut r: u32; + #[cfg(target_feature="sse")] + { + // Note(Lokathor): If compile time settings allow, we just use SSE, since + // the sqrt in `std` on these platforms also compiles down to an SSE + // instruction. + #[cfg(target_arch="x86")] + use core::arch::x86::*; + #[cfg(target_arch="x86_64")] + use core::arch::x86_64::*; + unsafe { + let m = _mm_set_ss(x); + let m_sqrt = _mm_sqrt_ss(m); + _mm_cvtss_f32(m_sqrt) + } + } + #[cfg(not(target_feature="sse"))] + { + let mut z: f32; + let sign: i32 = 0x80000000u32 as i32; + let mut ix: i32; + let mut s: i32; + let mut q: i32; + let mut m: i32; + let mut t: i32; + let mut i: i32; + let mut r: u32; - ix = x.to_bits() as i32; + ix = x.to_bits() as i32; - /* take care of Inf and NaN */ - if (ix as u32 & 0x7f800000) == 0x7f800000 { - return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ - } + /* take care of Inf and NaN */ + if (ix as u32 & 0x7f800000) == 0x7f800000 { + return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + } - /* take care of zero */ - if ix <= 0 { - if (ix & !sign) == 0 { - return x; /* sqrt(+-0) = +-0 */ - } - if ix < 0 { - return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ - } - } + /* take care of zero */ + if ix <= 0 { + if (ix & !sign) == 0 { + return x; /* sqrt(+-0) = +-0 */ + } + if ix < 0 { + return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ + } + } - /* normalize x */ - m = ix >> 23; - if m == 0 { - /* subnormal x */ - i = 0; - while ix & 0x00800000 == 0 { - ix <<= 1; - i = i + 1; - } - m -= i - 1; - } - m -= 127; /* unbias exponent */ - ix = (ix & 0x007fffff) | 0x00800000; - if m & 1 == 1 { - /* odd m, double x to make it even */ - ix += ix; - } - m >>= 1; /* m = [m/2] */ + /* normalize x */ + m = ix >> 23; + if m == 0 { + /* subnormal x */ + i = 0; + while ix & 0x00800000 == 0 { + ix <<= 1; + i = i + 1; + } + m -= i - 1; + } + m -= 127; /* unbias exponent */ + ix = (ix & 0x007fffff) | 0x00800000; + if m & 1 == 1 { + /* odd m, double x to make it even */ + ix += ix; + } + m >>= 1; /* m = [m/2] */ - /* generate sqrt(x) bit by bit */ - ix += ix; - q = 0; - s = 0; - r = 0x01000000; /* r = moving bit from right to left */ + /* generate sqrt(x) bit by bit */ + ix += ix; + q = 0; + s = 0; + r = 0x01000000; /* r = moving bit from right to left */ - while r != 0 { - t = s + r as i32; - if t <= ix { - s = t + r as i32; - ix -= t; - q += r as i32; - } - ix += ix; - r >>= 1; - } + while r != 0 { + t = s + r as i32; + if t <= ix { + s = t + r as i32; + ix -= t; + q += r as i32; + } + ix += ix; + r >>= 1; + } - /* use floating add to find out rounding direction */ - if ix != 0 { - z = 1.0 - TINY; /* raise inexact flag */ - if z >= 1.0 { - z = 1.0 + TINY; - if z > 1.0 { - q += 2; - } else { - q += q & 1; - } - } - } + /* use floating add to find out rounding direction */ + if ix != 0 { + z = 1.0 - TINY; /* raise inexact flag */ + if z >= 1.0 { + z = 1.0 + TINY; + if z > 1.0 { + q += 2; + } else { + q += q & 1; + } + } + } - ix = (q >> 1) + 0x3f000000; - ix += m << 23; - f32::from_bits(ix as u32) + ix = (q >> 1) + 0x3f000000; + ix += m << 23; + f32::from_bits(ix as u32) + } } From 47d6a214d44591208201bb5cd8e3f458ef00c695 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Wed, 7 Aug 2019 14:10:34 -0600 Subject: [PATCH 0787/4206] apply rustfmt --- .../compiler-builtins/libm/src/math/sqrt.rs | 264 +++++++++--------- .../compiler-builtins/libm/src/math/sqrtf.rs | 170 +++++------ 2 files changed, 217 insertions(+), 217 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index f01267da7274d..2fb1b24b7da99 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -95,146 +95,146 @@ pub fn sqrt(x: f64) -> f64 { } } } - #[cfg(target_feature="sse2")] + #[cfg(target_feature = "sse2")] { - // Note(Lokathor): If compile time settings allow, we just use SSE2, since - // the sqrt in `std` on these platforms also compiles down to an SSE2 - // instruction. - #[cfg(target_arch="x86")] - use core::arch::x86::*; - #[cfg(target_arch="x86_64")] - use core::arch::x86_64::*; - unsafe { - let m = _mm_set_sd(x); - let m_sqrt = _mm_sqrt_pd(m); - _mm_cvtsd_f64(m_sqrt) - } + // Note(Lokathor): If compile time settings allow, we just use SSE2, since + // the sqrt in `std` on these platforms also compiles down to an SSE2 + // instruction. + #[cfg(target_arch = "x86")] + use core::arch::x86::*; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64::*; + unsafe { + let m = _mm_set_sd(x); + let m_sqrt = _mm_sqrt_pd(m); + _mm_cvtsd_f64(m_sqrt) + } } - #[cfg(not(target_feature="sse2"))] + #[cfg(not(target_feature = "sse2"))] { - let mut z: f64; - let sign: Wrapping = Wrapping(0x80000000); - let mut ix0: i32; - let mut s0: i32; - let mut q: i32; - let mut m: i32; - let mut t: i32; - let mut i: i32; - let mut r: Wrapping; - let mut t1: Wrapping; - let mut s1: Wrapping; - let mut ix1: Wrapping; - let mut q1: Wrapping; + let mut z: f64; + let sign: Wrapping = Wrapping(0x80000000); + let mut ix0: i32; + let mut s0: i32; + let mut q: i32; + let mut m: i32; + let mut t: i32; + let mut i: i32; + let mut r: Wrapping; + let mut t1: Wrapping; + let mut s1: Wrapping; + let mut ix1: Wrapping; + let mut q1: Wrapping; - ix0 = (x.to_bits() >> 32) as i32; - ix1 = Wrapping(x.to_bits() as u32); + ix0 = (x.to_bits() >> 32) as i32; + ix1 = Wrapping(x.to_bits() as u32); - /* take care of Inf and NaN */ - if (ix0 & 0x7ff00000) == 0x7ff00000 { - return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ - } - /* take care of zero */ - if ix0 <= 0 { - if ((ix0 & !(sign.0 as i32)) | ix1.0 as i32) == 0 { - return x; /* sqrt(+-0) = +-0 */ - } - if ix0 < 0 { - return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ - } - } - /* normalize x */ - m = ix0 >> 20; - if m == 0 { - /* subnormal x */ - while ix0 == 0 { - m -= 21; - ix0 |= (ix1 >> 11).0 as i32; - ix1 <<= 21; - } - i = 0; - while (ix0 & 0x00100000) == 0 { - i += 1; - ix0 <<= 1; - } - m -= i - 1; - ix0 |= (ix1 >> (32 - i) as usize).0 as i32; - ix1 = ix1 << i as usize; - } - m -= 1023; /* unbias exponent */ - ix0 = (ix0 & 0x000fffff) | 0x00100000; - if (m & 1) == 1 { - /* odd m, double x to make it even */ - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - } - m >>= 1; /* m = [m/2] */ + /* take care of Inf and NaN */ + if (ix0 & 0x7ff00000) == 0x7ff00000 { + return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + } + /* take care of zero */ + if ix0 <= 0 { + if ((ix0 & !(sign.0 as i32)) | ix1.0 as i32) == 0 { + return x; /* sqrt(+-0) = +-0 */ + } + if ix0 < 0 { + return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ + } + } + /* normalize x */ + m = ix0 >> 20; + if m == 0 { + /* subnormal x */ + while ix0 == 0 { + m -= 21; + ix0 |= (ix1 >> 11).0 as i32; + ix1 <<= 21; + } + i = 0; + while (ix0 & 0x00100000) == 0 { + i += 1; + ix0 <<= 1; + } + m -= i - 1; + ix0 |= (ix1 >> (32 - i) as usize).0 as i32; + ix1 = ix1 << i as usize; + } + m -= 1023; /* unbias exponent */ + ix0 = (ix0 & 0x000fffff) | 0x00100000; + if (m & 1) == 1 { + /* odd m, double x to make it even */ + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + } + m >>= 1; /* m = [m/2] */ - /* generate sqrt(x) bit by bit */ - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - q = 0; /* [q,q1] = sqrt(x) */ - q1 = Wrapping(0); - s0 = 0; - s1 = Wrapping(0); - r = Wrapping(0x00200000); /* r = moving bit from right to left */ + /* generate sqrt(x) bit by bit */ + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + q = 0; /* [q,q1] = sqrt(x) */ + q1 = Wrapping(0); + s0 = 0; + s1 = Wrapping(0); + r = Wrapping(0x00200000); /* r = moving bit from right to left */ - while r != Wrapping(0) { - t = s0 + r.0 as i32; - if t <= ix0 { - s0 = t + r.0 as i32; - ix0 -= t; - q += r.0 as i32; - } - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - r >>= 1; - } + while r != Wrapping(0) { + t = s0 + r.0 as i32; + if t <= ix0 { + s0 = t + r.0 as i32; + ix0 -= t; + q += r.0 as i32; + } + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + r >>= 1; + } - r = sign; - while r != Wrapping(0) { - t1 = s1 + r; - t = s0; - if t < ix0 || (t == ix0 && t1 <= ix1) { - s1 = t1 + r; - if (t1 & sign) == sign && (s1 & sign) == Wrapping(0) { - s0 += 1; - } - ix0 -= t; - if ix1 < t1 { - ix0 -= 1; - } - ix1 -= t1; - q1 += r; - } - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - r >>= 1; - } + r = sign; + while r != Wrapping(0) { + t1 = s1 + r; + t = s0; + if t < ix0 || (t == ix0 && t1 <= ix1) { + s1 = t1 + r; + if (t1 & sign) == sign && (s1 & sign) == Wrapping(0) { + s0 += 1; + } + ix0 -= t; + if ix1 < t1 { + ix0 -= 1; + } + ix1 -= t1; + q1 += r; + } + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + r >>= 1; + } - /* use floating add to find out rounding direction */ - if (ix0 as u32 | ix1.0) != 0 { - z = 1.0 - TINY; /* raise inexact flag */ - if z >= 1.0 { - z = 1.0 + TINY; - if q1.0 == 0xffffffff { - q1 = Wrapping(0); - q += 1; - } else if z > 1.0 { - if q1.0 == 0xfffffffe { - q += 1; - } - q1 += Wrapping(2); - } else { - q1 += q1 & Wrapping(1); - } - } - } - ix0 = (q >> 1) + 0x3fe00000; - ix1 = q1 >> 1; - if (q & 1) == 1 { - ix1 |= sign; - } - ix0 += m << 20; - f64::from_bits((ix0 as u64) << 32 | ix1.0 as u64) + /* use floating add to find out rounding direction */ + if (ix0 as u32 | ix1.0) != 0 { + z = 1.0 - TINY; /* raise inexact flag */ + if z >= 1.0 { + z = 1.0 + TINY; + if q1.0 == 0xffffffff { + q1 = Wrapping(0); + q += 1; + } else if z > 1.0 { + if q1.0 == 0xfffffffe { + q += 1; + } + q1 += Wrapping(2); + } else { + q1 += q1 & Wrapping(1); + } + } + } + ix0 = (q >> 1) + 0x3fe00000; + ix1 = q1 >> 1; + if (q & 1) == 1 { + ix1 |= sign; + } + ix0 += m << 20; + f64::from_bits((ix0 as u64) << 32 | ix1.0 as u64) } } diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index a4d9ab53deb5c..5fe0a7744919d 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -29,101 +29,101 @@ pub fn sqrtf(x: f32) -> f32 { } } } - #[cfg(target_feature="sse")] + #[cfg(target_feature = "sse")] { - // Note(Lokathor): If compile time settings allow, we just use SSE, since - // the sqrt in `std` on these platforms also compiles down to an SSE - // instruction. - #[cfg(target_arch="x86")] - use core::arch::x86::*; - #[cfg(target_arch="x86_64")] - use core::arch::x86_64::*; - unsafe { - let m = _mm_set_ss(x); - let m_sqrt = _mm_sqrt_ss(m); - _mm_cvtss_f32(m_sqrt) - } + // Note(Lokathor): If compile time settings allow, we just use SSE, since + // the sqrt in `std` on these platforms also compiles down to an SSE + // instruction. + #[cfg(target_arch = "x86")] + use core::arch::x86::*; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64::*; + unsafe { + let m = _mm_set_ss(x); + let m_sqrt = _mm_sqrt_ss(m); + _mm_cvtss_f32(m_sqrt) + } } - #[cfg(not(target_feature="sse"))] + #[cfg(not(target_feature = "sse"))] { - let mut z: f32; - let sign: i32 = 0x80000000u32 as i32; - let mut ix: i32; - let mut s: i32; - let mut q: i32; - let mut m: i32; - let mut t: i32; - let mut i: i32; - let mut r: u32; + let mut z: f32; + let sign: i32 = 0x80000000u32 as i32; + let mut ix: i32; + let mut s: i32; + let mut q: i32; + let mut m: i32; + let mut t: i32; + let mut i: i32; + let mut r: u32; - ix = x.to_bits() as i32; + ix = x.to_bits() as i32; - /* take care of Inf and NaN */ - if (ix as u32 & 0x7f800000) == 0x7f800000 { - return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ - } + /* take care of Inf and NaN */ + if (ix as u32 & 0x7f800000) == 0x7f800000 { + return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + } - /* take care of zero */ - if ix <= 0 { - if (ix & !sign) == 0 { - return x; /* sqrt(+-0) = +-0 */ - } - if ix < 0 { - return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ - } - } + /* take care of zero */ + if ix <= 0 { + if (ix & !sign) == 0 { + return x; /* sqrt(+-0) = +-0 */ + } + if ix < 0 { + return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ + } + } - /* normalize x */ - m = ix >> 23; - if m == 0 { - /* subnormal x */ - i = 0; - while ix & 0x00800000 == 0 { - ix <<= 1; - i = i + 1; - } - m -= i - 1; - } - m -= 127; /* unbias exponent */ - ix = (ix & 0x007fffff) | 0x00800000; - if m & 1 == 1 { - /* odd m, double x to make it even */ - ix += ix; - } - m >>= 1; /* m = [m/2] */ + /* normalize x */ + m = ix >> 23; + if m == 0 { + /* subnormal x */ + i = 0; + while ix & 0x00800000 == 0 { + ix <<= 1; + i = i + 1; + } + m -= i - 1; + } + m -= 127; /* unbias exponent */ + ix = (ix & 0x007fffff) | 0x00800000; + if m & 1 == 1 { + /* odd m, double x to make it even */ + ix += ix; + } + m >>= 1; /* m = [m/2] */ - /* generate sqrt(x) bit by bit */ - ix += ix; - q = 0; - s = 0; - r = 0x01000000; /* r = moving bit from right to left */ + /* generate sqrt(x) bit by bit */ + ix += ix; + q = 0; + s = 0; + r = 0x01000000; /* r = moving bit from right to left */ - while r != 0 { - t = s + r as i32; - if t <= ix { - s = t + r as i32; - ix -= t; - q += r as i32; - } - ix += ix; - r >>= 1; - } + while r != 0 { + t = s + r as i32; + if t <= ix { + s = t + r as i32; + ix -= t; + q += r as i32; + } + ix += ix; + r >>= 1; + } - /* use floating add to find out rounding direction */ - if ix != 0 { - z = 1.0 - TINY; /* raise inexact flag */ - if z >= 1.0 { - z = 1.0 + TINY; - if z > 1.0 { - q += 2; - } else { - q += q & 1; - } - } - } + /* use floating add to find out rounding direction */ + if ix != 0 { + z = 1.0 - TINY; /* raise inexact flag */ + if z >= 1.0 { + z = 1.0 + TINY; + if z > 1.0 { + q += 2; + } else { + q += q & 1; + } + } + } - ix = (q >> 1) + 0x3f000000; - ix += m << 23; - f32::from_bits(ix as u32) + ix = (q >> 1) + 0x3f000000; + ix += m << 23; + f32::from_bits(ix as u32) } } From 887fca89c259844a50d5e7cca60cbf186f36ef33 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Wed, 7 Aug 2019 14:16:10 -0600 Subject: [PATCH 0788/4206] move use/const statements to a limited scope --- library/compiler-builtins/libm/src/math/sqrt.rs | 7 ++++--- library/compiler-builtins/libm/src/math/sqrtf.rs | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 2fb1b24b7da99..8a67cb18b7ce2 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -77,9 +77,6 @@ */ use core::f64; -use core::num::Wrapping; - -const TINY: f64 = 1.0e-300; #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrt(x: f64) -> f64 { @@ -112,6 +109,10 @@ pub fn sqrt(x: f64) -> f64 { } #[cfg(not(target_feature = "sse2"))] { + use core::num::Wrapping; + + const TINY: f64 = 1.0e-300; + let mut z: f64; let sign: Wrapping = Wrapping(0x80000000); let mut ix0: i32; diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 5fe0a7744919d..cb3c1672e929a 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -13,8 +13,6 @@ * ==================================================== */ -const TINY: f32 = 1.0e-30; - #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrtf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized @@ -46,6 +44,8 @@ pub fn sqrtf(x: f32) -> f32 { } #[cfg(not(target_feature = "sse"))] { + const TINY: f32 = 1.0e-30; + let mut z: f32; let sign: i32 = 0x80000000u32 as i32; let mut ix: i32; From e247c599cc53c52eb9cec8a7a3648d0c5858d27c Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 8 Aug 2019 18:21:10 -0600 Subject: [PATCH 0789/4206] update comments --- library/compiler-builtins/libm/src/math/sqrtf.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index cb3c1672e929a..1d5b78e84c6e1 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -29,9 +29,9 @@ pub fn sqrtf(x: f32) -> f32 { } #[cfg(target_feature = "sse")] { - // Note(Lokathor): If compile time settings allow, we just use SSE, since - // the sqrt in `std` on these platforms also compiles down to an SSE - // instruction. + // Note: This path is unlikely since LLVM will usually have already + // optimized sqrt calls into hardware instructions if sse is available, + // but if someone does end up here they'll apprected the speed increase. #[cfg(target_arch = "x86")] use core::arch::x86::*; #[cfg(target_arch = "x86_64")] From 0b8c514c8f6ca18025872868af2c6e3e335fc6d9 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 8 Aug 2019 18:21:18 -0600 Subject: [PATCH 0790/4206] update comments --- library/compiler-builtins/libm/src/math/sqrt.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 8a67cb18b7ce2..31afe33566b3e 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -94,9 +94,9 @@ pub fn sqrt(x: f64) -> f64 { } #[cfg(target_feature = "sse2")] { - // Note(Lokathor): If compile time settings allow, we just use SSE2, since - // the sqrt in `std` on these platforms also compiles down to an SSE2 - // instruction. + // Note: This path is unlikely since LLVM will usually have already + // optimized sqrt calls into hardware instructions if sse2 is available, + // but if someone does end up here they'll apprected the speed increase. #[cfg(target_arch = "x86")] use core::arch::x86::*; #[cfg(target_arch = "x86_64")] From f004acd69119d43426d93b8d0db5d2efe562b07e Mon Sep 17 00:00:00 2001 From: Roman Proskuryakov Date: Sat, 10 Aug 2019 15:30:43 +0300 Subject: [PATCH 0791/4206] Fix broken link in README --- library/compiler-builtins/libm/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index e10904f8cf081..e90b42d740c22 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -22,6 +22,8 @@ This crate is [on crates.io] and can be used today in stable `#![no_std]` progra The API documentation can be found [here](https://docs.rs/libm). +[on crates.io]: https://crates.io/crates/libm + ## Benchmark [benchmark]: #benchmark From ff3dd206d1eaf63ca3c7bb627ecdbceac827f8a7 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Tue, 13 Aug 2019 23:40:54 -0600 Subject: [PATCH 0792/4206] slightly improve spec and sanity check coverage --- .../compiler-builtins/libm/src/math/ceil.rs | 17 +++++++++++-- .../compiler-builtins/libm/src/math/ceilf.rs | 22 ++++++++++++++++ .../compiler-builtins/libm/src/math/fabs.rs | 24 ++++++++++++++++++ .../compiler-builtins/libm/src/math/fabsf.rs | 24 ++++++++++++++++++ .../compiler-builtins/libm/src/math/floor.rs | 22 ++++++++++++++++ .../compiler-builtins/libm/src/math/floorf.rs | 19 ++++++++++++-- .../compiler-builtins/libm/src/math/sqrt.rs | 25 ++++++++++++++++++- .../compiler-builtins/libm/src/math/sqrtf.rs | 23 +++++++++++++++++ 8 files changed, 171 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index 63c1121c6d33f..eda28b9a0f2b9 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -42,9 +42,22 @@ pub fn ceil(x: f64) -> f64 { #[cfg(test)] mod tests { + use super::*; + use core::f64::*; + #[test] fn sanity_check() { - assert_eq!(super::ceil(1.1), 2.0); - assert_eq!(super::ceil(2.9), 3.0); + assert_eq!(ceil(1.1), 2.0); + assert_eq!(ceil(2.9), 3.0); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/ceil + #[test] + fn spec_tests() { + // Not Asserted: that the current rounding mode has no effect. + assert!(ceil(NAN).is_nan()); + for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { + assert_eq!(ceil(f), f); + } } } diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index 87d96982aab97..f1edbd061bf7e 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -39,3 +39,25 @@ pub fn ceilf(x: f32) -> f32 { } f32::from_bits(ui) } + +#[cfg(test)] +mod tests { + use super::*; + use core::f32::*; + + #[test] + fn sanity_check() { + assert_eq!(ceilf(1.1), 2.0); + assert_eq!(ceilf(2.9), 3.0); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/ceil + #[test] + fn spec_tests() { + // Not Asserted: that the current rounding mode has no effect. + assert!(ceilf(NAN).is_nan()); + for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { + assert_eq!(ceilf(f), f); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index 5a7f795f6a34c..4b292acc6cdee 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -15,3 +15,27 @@ pub fn fabs(x: f64) -> f64 { } f64::from_bits(x.to_bits() & (u64::MAX / 2)) } + +#[cfg(test)] +mod tests { + use super::*; + use core::f64::*; + + #[test] + fn sanity_check() { + assert_eq!(fabs(-1.0), 1.0); + assert_eq!(fabs(2.8), 2.8); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs + #[test] + fn spec_tests() { + assert!(fabs(NAN).is_nan()); + for f in [0.0, -0.0].iter().copied() { + assert_eq!(fabs(f), 0.0); + } + for f in [INFINITY, NEG_INFINITY].iter().copied() { + assert_eq!(fabs(f), INFINITY); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index 495512584d229..21dda8d6a3cb6 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -13,3 +13,27 @@ pub fn fabsf(x: f32) -> f32 { } f32::from_bits(x.to_bits() & 0x7fffffff) } + +#[cfg(test)] +mod tests { + use super::*; + use core::f32::*; + + #[test] + fn sanity_check() { + assert_eq!(fabsf(-1.0), 1.0); + assert_eq!(fabsf(2.8), 2.8); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs + #[test] + fn spec_tests() { + assert!(fabsf(NAN).is_nan()); + for f in [0.0, -0.0].iter().copied() { + assert_eq!(fabsf(f), 0.0); + } + for f in [INFINITY, NEG_INFINITY].iter().copied() { + assert_eq!(fabsf(f), INFINITY); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index 91825e3c88fd5..b2b760570dee2 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -38,3 +38,25 @@ pub fn floor(x: f64) -> f64 { x + y } } + +#[cfg(test)] +mod tests { + use super::*; + use core::f64::*; + + #[test] + fn sanity_check() { + assert_eq!(floor(1.1), 1.0); + assert_eq!(floor(2.9), 2.0); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/floor + #[test] + fn spec_tests() { + // Not Asserted: that the current rounding mode has no effect. + assert!(floor(NAN).is_nan()); + for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { + assert_eq!(floor(f), f); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index 6d751b077ef14..287f08642778d 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -42,8 +42,23 @@ pub fn floorf(x: f32) -> f32 { #[cfg(test)] mod tests { + use super::*; + use core::f32::*; + #[test] - fn no_overflow() { - assert_eq!(super::floorf(0.5), 0.0); + fn sanity_check() { + assert_eq!(floorf(0.5), 0.0); + assert_eq!(floorf(1.1), 1.0); + assert_eq!(floorf(2.9), 2.0); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/floor + #[test] + fn spec_tests() { + // Not Asserted: that the current rounding mode has no effect. + assert!(floorf(NAN).is_nan()); + for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { + assert_eq!(floorf(f), f); + } } } diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 31afe33566b3e..addecba2352d1 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -37,7 +37,7 @@ * If (2) is false, then q = q ; otherwise q = q + 2 . * i+1 i i+1 i * - * With some algebric manipulation, it is not difficult to see + * With some algebraic manipulation, it is not difficult to see * that (2) is equivalent to * -(i+1) * s + 2 <= y (3) @@ -239,3 +239,26 @@ pub fn sqrt(x: f64) -> f64 { f64::from_bits((ix0 as u64) << 32 | ix1.0 as u64) } } + +#[cfg(test)] +mod tests { + use super::*; + use core::f64::*; + + #[test] + fn sanity_check() { + assert_eq!(sqrt(100.0), 10.0); + assert_eq!(sqrt(4.0), 2.0); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/sqrt + #[test] + fn spec_tests() { + // Not Asserted: FE_INVALID exception is raised if argument is negative. + assert!(sqrt(-1.0).is_nan()); + assert!(sqrt(NAN).is_nan()); + for f in [0.0, -0.0, INFINITY].iter().copied() { + assert_eq!(sqrt(f), f); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 1d5b78e84c6e1..0bee0286990a1 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -127,3 +127,26 @@ pub fn sqrtf(x: f32) -> f32 { f32::from_bits(ix as u32) } } + +#[cfg(test)] +mod tests { + use super::*; + use core::f32::*; + + #[test] + fn sanity_check() { + assert_eq!(sqrtf(100.0), 10.0); + assert_eq!(sqrtf(4.0), 2.0); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/sqrt + #[test] + fn spec_tests() { + // Not Asserted: FE_INVALID exception is raised if argument is negative. + assert!(sqrtf(-1.0).is_nan()); + assert!(sqrtf(NAN).is_nan()); + for f in [0.0, -0.0, INFINITY].iter().copied() { + assert_eq!(sqrtf(f), f); + } + } +} From 3dd4991eab8456dee638bcc9fb935c4d6978eea9 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Tue, 13 Aug 2019 23:45:50 -0600 Subject: [PATCH 0793/4206] rustfmt fixes --- library/compiler-builtins/libm/src/math/fabs.rs | 4 ++-- library/compiler-builtins/libm/src/math/fabsf.rs | 4 ++-- library/compiler-builtins/libm/src/math/sqrt.rs | 4 ++-- library/compiler-builtins/libm/src/math/sqrtf.rs | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index 4b292acc6cdee..b2255ad32cf32 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -23,8 +23,8 @@ mod tests { #[test] fn sanity_check() { - assert_eq!(fabs(-1.0), 1.0); - assert_eq!(fabs(2.8), 2.8); + assert_eq!(fabs(-1.0), 1.0); + assert_eq!(fabs(2.8), 2.8); } /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index 21dda8d6a3cb6..6655c4c3ccc71 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -21,8 +21,8 @@ mod tests { #[test] fn sanity_check() { - assert_eq!(fabsf(-1.0), 1.0); - assert_eq!(fabsf(2.8), 2.8); + assert_eq!(fabsf(-1.0), 1.0); + assert_eq!(fabsf(2.8), 2.8); } /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index addecba2352d1..f06b209a49f2f 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -247,8 +247,8 @@ mod tests { #[test] fn sanity_check() { - assert_eq!(sqrt(100.0), 10.0); - assert_eq!(sqrt(4.0), 2.0); + assert_eq!(sqrt(100.0), 10.0); + assert_eq!(sqrt(4.0), 2.0); } /// The spec: https://en.cppreference.com/w/cpp/numeric/math/sqrt diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 0bee0286990a1..ee868c8c8111e 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -135,8 +135,8 @@ mod tests { #[test] fn sanity_check() { - assert_eq!(sqrtf(100.0), 10.0); - assert_eq!(sqrtf(4.0), 2.0); + assert_eq!(sqrtf(100.0), 10.0); + assert_eq!(sqrtf(4.0), 2.0); } /// The spec: https://en.cppreference.com/w/cpp/numeric/math/sqrt From cefd832d8957ad369bfb3923e4ebfd7a4c985973 Mon Sep 17 00:00:00 2001 From: Joel Galenson Date: Mon, 19 Aug 2019 09:30:45 -0700 Subject: [PATCH 0794/4206] Support deterministic builds by remapping the __FILE__ prefix if the compiler supports it. --- library/compiler-builtins/build.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index c714bc15de308..feb7fc6ecdab0 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -423,6 +423,10 @@ mod c { panic!("RUST_COMPILER_RT_ROOT={} does not exist", root.display()); } + // Support deterministic builds by remapping the __FILE__ prefix if the + // compiler supports it. + cfg.flag_if_supported(&format!("-ffile-prefix-map={}=.", root.display())); + let src_dir = root.join("lib/builtins"); for (sym, src) in sources.map.iter() { let src = src_dir.join(src); From a292bd9cb52cc1c6c26d20e1226d4b94ef7866d5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 19 Aug 2019 14:02:08 -0700 Subject: [PATCH 0795/4206] Modernize the `testcrate` slighty * Update `rand` dependency * Drop `cast` in favor of explicit casting or crate-defined * Move build script to 2018 edition --- .../compiler-builtins/testcrate/Cargo.toml | 4 +- library/compiler-builtins/testcrate/build.rs | 130 +++++++++++------- 2 files changed, 83 insertions(+), 51 deletions(-) diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 2a102660b2f75..3b99b574ef20c 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -2,14 +2,14 @@ name = "testcrate" version = "0.1.0" authors = ["Alex Crichton "] +edition = "2018" [lib] test = false doctest = false [build-dependencies] -cast = { version = "0.2.2", features = ["x128"] } -rand = { version = "0.4", features = ["i128_support"] } +rand = "0.7" [dependencies.compiler_builtins] path = ".." diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 4bd4005b705f4..e1d4cf9e818c3 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -1,6 +1,5 @@ -extern crate cast; -extern crate rand; - +use rand::seq::SliceRandom; +use rand::Rng; use std::collections::HashMap; use std::fmt; use std::fmt::Write as FmtWrite; @@ -10,9 +9,6 @@ use std::io::Write; use std::path::PathBuf; use std::{env, mem}; -use self::cast::{f32, f64, i128, i32, i64, u128, u32, u64}; -use self::rand::Rng; - const NTESTS: usize = 1_000; fn main() { @@ -397,7 +393,7 @@ fn main() { if a.0.is_nan() { return None; } - Some(f64(a.0)) + Some(f64::from(a.0)) }, "builtins::float::extend::__extendsfdf2(a)", ); @@ -407,7 +403,7 @@ fn main() { if a.0.is_nan() { return None; } - Some(f64(a.0)) + Some(f64::from(a.0)) }, "builtins::float::extend::__extendsfdf2vfp(a)", ); @@ -415,92 +411,92 @@ fn main() { // float/conv.rs gen( - |a: MyF64| i64(a.0).ok(), + |a: MyF64| i64::cast(a.0), "builtins::float::conv::__fixdfdi(a)", ); gen( - |a: MyF64| i32(a.0).ok(), + |a: MyF64| i32::cast(a.0), "builtins::float::conv::__fixdfsi(a)", ); gen( - |a: MyF32| i64(a.0).ok(), + |a: MyF32| i64::cast(a.0), "builtins::float::conv::__fixsfdi(a)", ); gen( - |a: MyF32| i32(a.0).ok(), + |a: MyF32| i32::cast(a.0), "builtins::float::conv::__fixsfsi(a)", ); gen( - |a: MyF32| i128(a.0).ok(), + |a: MyF32| i128::cast(a.0), "builtins::float::conv::__fixsfti(a)", ); gen( - |a: MyF64| i128(a.0).ok(), + |a: MyF64| i128::cast(a.0), "builtins::float::conv::__fixdfti(a)", ); gen( - |a: MyF64| u64(a.0).ok(), + |a: MyF64| u64::cast(a.0), "builtins::float::conv::__fixunsdfdi(a)", ); gen( - |a: MyF64| u32(a.0).ok(), + |a: MyF64| u32::cast(a.0), "builtins::float::conv::__fixunsdfsi(a)", ); gen( - |a: MyF32| u64(a.0).ok(), + |a: MyF32| u64::cast(a.0), "builtins::float::conv::__fixunssfdi(a)", ); gen( - |a: MyF32| u32(a.0).ok(), + |a: MyF32| u32::cast(a.0), "builtins::float::conv::__fixunssfsi(a)", ); gen( - |a: MyF32| u128(a.0).ok(), + |a: MyF32| u128::cast(a.0), "builtins::float::conv::__fixunssfti(a)", ); gen( - |a: MyF64| u128(a.0).ok(), + |a: MyF64| u128::cast(a.0), "builtins::float::conv::__fixunsdfti(a)", ); gen( - |a: MyI64| Some(f64(a.0)), + |a: MyI64| Some(a.0 as f64), "builtins::float::conv::__floatdidf(a)", ); gen( - |a: MyI32| Some(f64(a.0)), + |a: MyI32| Some(a.0 as f64), "builtins::float::conv::__floatsidf(a)", ); gen( - |a: MyI32| Some(f32(a.0)), + |a: MyI32| Some(a.0 as f32), "builtins::float::conv::__floatsisf(a)", ); gen( - |a: MyU64| Some(f64(a.0)), + |a: MyU64| Some(a.0 as f64), "builtins::float::conv::__floatundidf(a)", ); gen( - |a: MyU32| Some(f64(a.0)), + |a: MyU32| Some(a.0 as f64), "builtins::float::conv::__floatunsidf(a)", ); gen( - |a: MyU32| Some(f32(a.0)), + |a: MyU32| Some(a.0 as f32), "builtins::float::conv::__floatunsisf(a)", ); gen( - |a: MyU128| f32(a.0).ok(), + |a: MyU128| Some(a.0 as f32), "builtins::float::conv::__floatuntisf(a)", ); if !target_arch_mips { gen( - |a: MyI128| Some(f32(a.0)), + |a: MyI128| Some(a.0 as f32), "builtins::float::conv::__floattisf(a)", ); gen( - |a: MyI128| Some(f64(a.0)), + |a: MyI128| Some(a.0 as f64), "builtins::float::conv::__floattidf(a)", ); gen( - |a: MyU128| Some(f64(a.0)), + |a: MyU128| Some(a.0 as f64), "builtins::float::conv::__floatuntidf(a)", ); } @@ -996,7 +992,7 @@ macro_rules! gen_float { $significand_bits:expr) => { pub fn $name(rng: &mut R) -> $fty where - R: Rng, + R: Rng + ?Sized, { const BITS: u8 = $bits; const SIGNIFICAND_BITS: u8 = $significand_bits; @@ -1015,9 +1011,9 @@ macro_rules! gen_float { } } - if rng.gen_weighted_bool(10) { + if rng.gen_range(0, 10) == 1 { // Special values - *rng.choose(&[ + *[ -0.0, 0.0, ::std::$fty::MIN, @@ -1026,9 +1022,10 @@ macro_rules! gen_float { ::std::$fty::NAN, ::std::$fty::INFINITY, -::std::$fty::INFINITY, - ]) + ] + .choose(rng) .unwrap() - } else if rng.gen_weighted_bool(10) { + } else if rng.gen_range(0, 10) == 1 { // NaN patterns mk_f32(rng.gen(), rng.gen(), 0) } else if rng.gen() { @@ -1053,7 +1050,7 @@ macro_rules! gen_large_float { $significand_bits:expr) => { pub fn $name(rng: &mut R) -> $fty where - R: Rng, + R: Rng + ?Sized, { const BITS: u8 = $bits; const SIGNIFICAND_BITS: u8 = $significand_bits; @@ -1072,9 +1069,9 @@ macro_rules! gen_large_float { } } - if rng.gen_weighted_bool(10) { + if rng.gen_range(0, 10) == 1 { // Special values - *rng.choose(&[ + *[ -0.0, 0.0, ::std::$fty::MIN, @@ -1083,9 +1080,10 @@ macro_rules! gen_large_float { ::std::$fty::NAN, ::std::$fty::INFINITY, -::std::$fty::INFINITY, - ]) + ] + .choose(rng) .unwrap() - } else if rng.gen_weighted_bool(10) { + } else if rng.gen_range(0, 10) == 1 { // NaN patterns mk_f32(rng.gen(), rng.gen(), 0) } else if rng.gen() { @@ -1102,7 +1100,7 @@ macro_rules! gen_large_float { gen_large_float!(gen_large_f32, f32, u32, 32, 23); gen_large_float!(gen_large_f64, f64, u64, 64, 52); -trait TestInput: rand::Rand + Hash + Eq + fmt::Debug { +trait TestInput: Hash + Eq + fmt::Debug { fn ty_name() -> String; fn generate_lets(container: &str, cnt: &mut u8) -> String; fn generate_static(&self, dst: &mut String); @@ -1119,6 +1117,7 @@ where F: FnMut(A) -> Option, A: TestInput + Copy, R: TestOutput, + rand::distributions::Standard: rand::distributions::Distribution, { let rng = &mut rand::thread_rng(); let testname = test.split("::").last().unwrap().split("(").next().unwrap(); @@ -1207,8 +1206,8 @@ macro_rules! my_float { } } - impl rand::Rand for $name { - fn rand(r: &mut R) -> $name { + impl rand::distributions::Distribution<$name> for rand::distributions::Standard { + fn sample(&self, r: &mut R) -> $name { $name($gen(r)) } } @@ -1260,18 +1259,18 @@ macro_rules! my_integer { } } - impl rand::Rand for $name { - fn rand(rng: &mut R) -> $name { + impl rand::distributions::Distribution<$name> for rand::distributions::Standard { + fn sample(&self, r: &mut R) -> $name { let bits = (0 as $inner).count_zeros(); let mut mk = || { - if rng.gen_weighted_bool(10) { - *rng.choose(&[ + if r.gen_range(0, 10) == 1 { + *[ ::std::$inner::MAX >> (bits / 2), 0, ::std::$inner::MIN >> (bits / 2), - ]).unwrap() + ].choose(r).unwrap() } else { - rng.gen::<$inner>() + r.gen::<$inner>() } }; let a = mk(); @@ -1386,3 +1385,36 @@ where container.to_string() } } + +trait FromFloat: Sized { + fn cast(src: T) -> Option; +} + +macro_rules! from_float { + ($($src:ident => $($dst:ident),+);+;) => { + $( + $( + impl FromFloat<$src> for $dst { + fn cast(src: $src) -> Option<$dst> { + use std::{$dst, $src}; + + if src.is_nan() || + src.is_infinite() || + src < std::$dst::MIN as $src || + src > std::$dst::MAX as $src + { + None + } else { + Some(src as $dst) + } + } + } + )+ + )+ + } +} + +from_float! { + f32 => i32, i64, i128, u32, u64, u128; + f64 => i32, i64, i128, u32, u64, u128; +} From a80233948f6321a6fa5995e7c2590e4596ed6a1f Mon Sep 17 00:00:00 2001 From: Joel Galenson Date: Mon, 19 Aug 2019 15:12:07 -0700 Subject: [PATCH 0796/4206] Update comment to mention where the __FILE__ macro is used. --- library/compiler-builtins/build.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index feb7fc6ecdab0..490b6391d08e4 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -424,7 +424,8 @@ mod c { } // Support deterministic builds by remapping the __FILE__ prefix if the - // compiler supports it. + // 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())); let src_dir = root.join("lib/builtins"); From 1cc3d328747b1a15913d50644213fd6924b03888 Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Tue, 20 Aug 2019 14:10:38 -0700 Subject: [PATCH 0797/4206] Implement LLVM's elementwise unordered atomic memory intrinsics Allows uses of intrinsics of the form llvm.(memcpy|memmove|memset).element.unordered.atomic.* to be linked. --- library/compiler-builtins/src/mem.rs | 106 +++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/library/compiler-builtins/src/mem.rs b/library/compiler-builtins/src/mem.rs index c863bb7294118..be7849ff39d6b 100644 --- a/library/compiler-builtins/src/mem.rs +++ b/library/compiler-builtins/src/mem.rs @@ -5,6 +5,10 @@ type c_int = i16; #[cfg(not(target_pointer_width = "16"))] type c_int = i32; +use core::intrinsics::{atomic_load_unordered, atomic_store_unordered, unchecked_div}; +use core::mem; +use core::ops::{BitOr, Shl}; + #[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { let mut i = 0; @@ -58,3 +62,105 @@ pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { } 0 } + +fn memcpy_element_unordered_atomic(dest: *mut T, src: *const T, bytes: usize) { + unsafe { + let n = unchecked_div(bytes, mem::size_of::()); + let mut i = 0; + while i < n { + atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i))); + i += 1; + } + } +} + +fn memmove_element_unordered_atomic(dest: *mut T, src: *const T, bytes: usize) { + unsafe { + let n = unchecked_div(bytes, mem::size_of::()); + if src < dest as *const T { + // copy from end + let mut i = n; + while i != 0 { + i -= 1; + atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i))); + } + } else { + // copy from beginning + let mut i = 0; + while i < n { + atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i))); + i += 1; + } + } + } +} + +fn memset_element_unordered_atomic(s: *mut T, c: u8, bytes: usize) +where + T: Copy + From + Shl + BitOr, +{ + unsafe { + let n = unchecked_div(bytes, mem::size_of::()); + let mut x = T::from(c); + let mut i = 1; + while i < mem::size_of::() { + x = x << 8 | T::from(c); + i += 1; + } + let mut i = 0; + while i < n { + atomic_store_unordered(s.add(i), x); + i += 1; + } + } +} + +intrinsics! { + pub extern "C" fn __llvm_memcpy_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () { + memcpy_element_unordered_atomic(dest, src, bytes); + } + pub extern "C" fn __llvm_memcpy_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () { + memcpy_element_unordered_atomic(dest, src, bytes); + } + pub extern "C" fn __llvm_memcpy_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () { + memcpy_element_unordered_atomic(dest, src, bytes); + } + pub extern "C" fn __llvm_memcpy_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () { + memcpy_element_unordered_atomic(dest, src, bytes); + } + pub extern "C" fn __llvm_memcpy_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () { + memcpy_element_unordered_atomic(dest, src, bytes); + } + + pub extern "C" fn __llvm_memmove_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () { + memmove_element_unordered_atomic(dest, src, bytes); + } + pub extern "C" fn __llvm_memmove_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () { + memmove_element_unordered_atomic(dest, src, bytes); + } + pub extern "C" fn __llvm_memmove_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () { + memmove_element_unordered_atomic(dest, src, bytes); + } + pub extern "C" fn __llvm_memmove_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () { + memmove_element_unordered_atomic(dest, src, bytes); + } + pub extern "C" fn __llvm_memmove_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () { + memmove_element_unordered_atomic(dest, src, bytes); + } + + pub extern "C" fn __llvm_memset_element_unordered_atomic_1(s: *mut u8, c: u8, bytes: usize) -> () { + memset_element_unordered_atomic(s, c, bytes); + } + pub extern "C" fn __llvm_memset_element_unordered_atomic_2(s: *mut u16, c: u8, bytes: usize) -> () { + memset_element_unordered_atomic(s, c, bytes); + } + pub extern "C" fn __llvm_memset_element_unordered_atomic_4(s: *mut u32, c: u8, bytes: usize) -> () { + memset_element_unordered_atomic(s, c, bytes); + } + pub extern "C" fn __llvm_memset_element_unordered_atomic_8(s: *mut u64, c: u8, bytes: usize) -> () { + memset_element_unordered_atomic(s, c, bytes); + } + pub extern "C" fn __llvm_memset_element_unordered_atomic_16(s: *mut u128, c: u8, bytes: usize) -> () { + memset_element_unordered_atomic(s, c, bytes); + } +} From 01a0524d8c3d5c81adc49934474b00b06d193054 Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Fri, 23 Aug 2019 10:18:36 -0700 Subject: [PATCH 0798/4206] Tidy up unordered elementwise atomic memory intrinsics --- library/compiler-builtins/src/mem.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/mem.rs b/library/compiler-builtins/src/mem.rs index be7849ff39d6b..76372d9bc81c8 100644 --- a/library/compiler-builtins/src/mem.rs +++ b/library/compiler-builtins/src/mem.rs @@ -5,7 +5,7 @@ type c_int = i16; #[cfg(not(target_pointer_width = "16"))] type c_int = i32; -use core::intrinsics::{atomic_load_unordered, atomic_store_unordered, unchecked_div}; +use core::intrinsics::{atomic_load_unordered, atomic_store_unordered, exact_div}; use core::mem; use core::ops::{BitOr, Shl}; @@ -63,9 +63,10 @@ pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { 0 } +// `bytes` must be a multiple of `mem::size_of::()` fn memcpy_element_unordered_atomic(dest: *mut T, src: *const T, bytes: usize) { unsafe { - let n = unchecked_div(bytes, mem::size_of::()); + let n = exact_div(bytes, mem::size_of::()); let mut i = 0; while i < n { atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i))); @@ -74,9 +75,10 @@ fn memcpy_element_unordered_atomic(dest: *mut T, src: *const T, bytes: } } +// `bytes` must be a multiple of `mem::size_of::()` fn memmove_element_unordered_atomic(dest: *mut T, src: *const T, bytes: usize) { unsafe { - let n = unchecked_div(bytes, mem::size_of::()); + let n = exact_div(bytes, mem::size_of::()); if src < dest as *const T { // copy from end let mut i = n; @@ -95,18 +97,24 @@ fn memmove_element_unordered_atomic(dest: *mut T, src: *const T, bytes: } } +// `T` must be a primitive integer type, and `bytes` must be a multiple of `mem::size_of::()` fn memset_element_unordered_atomic(s: *mut T, c: u8, bytes: usize) where T: Copy + From + Shl + BitOr, { unsafe { - let n = unchecked_div(bytes, mem::size_of::()); + let n = exact_div(bytes, mem::size_of::()); + + // Construct a value of type `T` consisting of repeated `c` + // bytes, to let us ensure we write each `T` atomically. let mut x = T::from(c); let mut i = 1; while i < mem::size_of::() { x = x << 8 | T::from(c); i += 1; } + + // Write it to `s` let mut i = 0; while i < n { atomic_store_unordered(s.add(i), x); From 2e3ba17f9d32d68a8c01c36f748487aa0730ac82 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 5 Sep 2019 08:32:05 -0600 Subject: [PATCH 0799/4206] there are no longer any default features --- library/compiler-builtins/libm/azure-pipelines.yml | 2 -- library/compiler-builtins/libm/ci/run.sh | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/azure-pipelines.yml b/library/compiler-builtins/libm/azure-pipelines.yml index c89346c73d80f..0d723c56dd251 100644 --- a/library/compiler-builtins/libm/azure-pipelines.yml +++ b/library/compiler-builtins/libm/azure-pipelines.yml @@ -49,8 +49,6 @@ jobs: displayName: "Install rust wasm target" - script: cargo build --target wasm32-unknown-unknown displayName: "Build for wasm" - - script: cargo build --target wasm32-unknown-unknown --no-default-features - displayName: "Build for wasm (no default features)" variables: TOOLCHAIN: nightly diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 37ffb8793cc83..59930b238790c 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -3,7 +3,7 @@ set -ex TARGET=$1 -CMD="cargo test --all --no-default-features --target $TARGET" +CMD="cargo test --all --target $TARGET" $CMD $CMD --release From de80131c2672868fb24761b2f7e6778940d70ebb Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 5 Sep 2019 08:32:26 -0600 Subject: [PATCH 0800/4206] swap stable to be unstable, checked is now debug_assertions --- library/compiler-builtins/libm/Cargo.toml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 3e6817851ba7f..37aff9a765bbd 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -11,18 +11,16 @@ version = "0.2.0" edition = "2018" [features] -# only used to run our test suite -default = ['stable'] -stable = [] +default = [] + +# This tells the compiler to assume that a Nightly toolchain is being used and +# that it should activate any useful Nightly things accordingly. +unstable = [] # Generate tests which are random inputs and the outputs are calculated with # musl libc. musl-reference-tests = ['rand'] -# Used checked array indexing instead of unchecked array indexing in this -# library. -checked = [] - [workspace] members = [ "crates/compiler-builtins-smoke-test", From 9811b57af2d08308187de34b00d9051e3de4e923 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 5 Sep 2019 08:32:38 -0600 Subject: [PATCH 0801/4206] swap stable to be unstable --- library/compiler-builtins/libm/crates/libm-bench/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml index ba65dbd5fe692..b09db339b5b27 100644 --- a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml @@ -12,4 +12,4 @@ paste = "0.1.5" [features] default = [] -stable = [ "libm/stable" ] +unstable = [ "libm/unstable" ] From c6fbe72886291c8201334adcbfc8c0f6cf58dac2 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 5 Sep 2019 08:33:03 -0600 Subject: [PATCH 0802/4206] swap stable to be unstable --- library/compiler-builtins/libm/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index b15857dbe6f6f..e9def49405118 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -2,7 +2,7 @@ #![deny(warnings)] #![no_std] #![cfg_attr( - all(target_arch = "wasm32", not(feature = "stable")), + all(target_arch = "wasm32", feature = "unstable"), feature(core_intrinsics) )] From c847d46c6409d9986d5964f093f3821838ce990d Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 5 Sep 2019 08:33:23 -0600 Subject: [PATCH 0803/4206] swap stable to be unstable, use debug_assertions --- library/compiler-builtins/libm/src/math/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index fcf4e649cdeda..c8d7bd8194df6 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -6,7 +6,7 @@ macro_rules! force_eval { }; } -#[cfg(not(feature = "checked"))] +#[cfg(not(debug_assertions))] macro_rules! i { ($array:expr, $index:expr) => { unsafe { *$array.get_unchecked($index) } @@ -36,7 +36,7 @@ macro_rules! i { }; } -#[cfg(feature = "checked")] +#[cfg(debug_assertions)] macro_rules! i { ($array:expr, $index:expr) => { *$array.get($index).unwrap() @@ -60,7 +60,7 @@ macro_rules! i { macro_rules! llvm_intrinsically_optimized { (#[cfg($($clause:tt)*)] $e:expr) => { - #[cfg(all(not(feature = "stable"), $($clause)*))] + #[cfg(all(feature = "unstable", $($clause)*))] { if true { // thwart the dead code lint $e From 06184b8d1052f716b9f46a86ed5bac5a942cc160 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 5 Sep 2019 08:33:34 -0600 Subject: [PATCH 0804/4206] use sebug_assertions --- library/compiler-builtins/libm/src/math/lgamma_r.rs | 4 ++-- library/compiler-builtins/libm/src/math/lgammaf_r.rs | 4 ++-- library/compiler-builtins/libm/src/math/rem_pio2_large.rs | 4 ++-- library/compiler-builtins/libm/src/math/sincos.rs | 4 ++-- library/compiler-builtins/libm/src/math/sincosf.rs | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/lgamma_r.rs b/library/compiler-builtins/libm/src/math/lgamma_r.rs index 382a501fc3dcf..9533e882cc998 100644 --- a/library/compiler-builtins/libm/src/math/lgamma_r.rs +++ b/library/compiler-builtins/libm/src/math/lgamma_r.rs @@ -270,9 +270,9 @@ pub fn lgamma_r(mut x: f64) -> (f64, i32) { p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); r += -0.5 * y + p1 / p2; } - #[cfg(feature = "checked")] + #[cfg(debug_assertions)] _ => unreachable!(), - #[cfg(not(feature = "checked"))] + #[cfg(not(debug_assertions))] _ => {} } } else if ix < 0x40200000 { diff --git a/library/compiler-builtins/libm/src/math/lgammaf_r.rs b/library/compiler-builtins/libm/src/math/lgammaf_r.rs index 0745359a257d1..c5e559f465282 100644 --- a/library/compiler-builtins/libm/src/math/lgammaf_r.rs +++ b/library/compiler-builtins/libm/src/math/lgammaf_r.rs @@ -205,9 +205,9 @@ pub fn lgammaf_r(mut x: f32) -> (f32, i32) { p2 = 1.0 + y * (V1 + y * (V2 + y * (V3 + y * (V4 + y * V5)))); r += -0.5 * y + p1 / p2; } - #[cfg(feature = "checked")] + #[cfg(debug_assertions)] _ => unreachable!(), - #[cfg(not(feature = "checked"))] + #[cfg(not(debug_assertions))] _ => {} } } else if ix < 0x41000000 { 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 8533dc28948d5..002ce2e211f2c 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -461,9 +461,9 @@ pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i!(y, 2, =, -fw); } } - #[cfg(feature = "checked")] + #[cfg(debug_assertions)] _ => unreachable!(), - #[cfg(not(feature = "checked"))] + #[cfg(not(debug_assertions))] _ => {} } n & 7 diff --git a/library/compiler-builtins/libm/src/math/sincos.rs b/library/compiler-builtins/libm/src/math/sincos.rs index 750908df4f7e9..d49f65c970795 100644 --- a/library/compiler-builtins/libm/src/math/sincos.rs +++ b/library/compiler-builtins/libm/src/math/sincos.rs @@ -51,9 +51,9 @@ pub fn sincos(x: f64) -> (f64, f64) { 1 => (c, -s), 2 => (-s, -c), 3 => (-c, s), - #[cfg(feature = "checked")] + #[cfg(debug_assertions)] _ => unreachable!(), - #[cfg(not(feature = "checked"))] + #[cfg(not(debug_assertions))] _ => (0.0, 1.0), } } diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs index bb9a003920174..d4e0772d5b105 100644 --- a/library/compiler-builtins/libm/src/math/sincosf.rs +++ b/library/compiler-builtins/libm/src/math/sincosf.rs @@ -115,9 +115,9 @@ pub fn sincosf(x: f32) -> (f32, f32) { 1 => (c, -s), 2 => (-s, -c), 3 => (-c, s), - #[cfg(feature = "checked")] + #[cfg(debug_assertions)] _ => unreachable!(), - #[cfg(not(feature = "checked"))] + #[cfg(not(debug_assertions))] _ => (0.0, 1.0), } } From de3480c3c29126e36d23a535299e1069979f0c4a Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 5 Sep 2019 08:36:08 -0600 Subject: [PATCH 0805/4206] Update run.sh --- library/compiler-builtins/libm/ci/run.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 59930b238790c..ed253ab0d10ab 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -5,11 +5,14 @@ TARGET=$1 CMD="cargo test --all --target $TARGET" +# stable by default $CMD $CMD --release -$CMD --features 'stable' -$CMD --release --features 'stable' +# unstable with a feature +$CMD --features 'unstable' +$CMD --release --features 'unstable' -$CMD --features 'stable checked musl-reference-tests' -$CMD --release --features 'stable checked musl-reference-tests' +# also run the reference tests +$CMD --features 'unstable musl-reference-tests' +$CMD --release --features 'unstable musl-reference-tests' From 0960b00b10f231a317e125cf454a54a5758670e3 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 5 Sep 2019 08:57:15 -0600 Subject: [PATCH 0806/4206] suppress useless clippy warnings --- library/compiler-builtins/libm/src/lib.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index e9def49405118..e228af9b3333d 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -5,6 +5,15 @@ all(target_arch = "wasm32", feature = "unstable"), feature(core_intrinsics) )] +#![allow(clippy::unreadable_literal)] +#![allow(clippy::many_single_char_names)] +#![allow(clippy::needless_return)] +#![allow(clippy::int_plus_one)] +#![allow(clippy::deprecated_cfg_attr)] +#![allow(clippy::mixed_case_hex_literals)] +#![allow(clippy::float_cmp)] +#![allow(clippy::eq_op)] +#![allow(clippy::assign_op_pattern)] mod math; From e9a2b2ca11b57e7a051087c5c14b3d89cb942e1e Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 6 Sep 2019 11:37:00 -0600 Subject: [PATCH 0807/4206] i was told to change this path to my repo and reset things --- library/compiler-builtins/.gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index a71118ff93e7f..23d29e11b4da2 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -1,3 +1,3 @@ [submodule "libm"] path = libm - url = https://github.com/rust-lang-nursery/libm + url = https://github.com/Lokathor/libm From 3ab350613b44869e1f3e5c7a594609f9fb7e1f1b Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 6 Sep 2019 13:48:15 -0600 Subject: [PATCH 0808/4206] Update the libm submodule --- library/compiler-builtins/libm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 01bee72a93eba..52983bee338ac 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 01bee72a93ebaeea2883d0f963174c2b00d4fe68 +Subproject commit 52983bee338ac439bc0f1146d6053955e3b4c33a From e079f2d70d5813775bff2e23ed942f76474c1e0e Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 6 Sep 2019 15:20:05 -0600 Subject: [PATCH 0809/4206] Update build.rs --- library/compiler-builtins/build.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 490b6391d08e4..5cdabf95987ee 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -8,6 +8,9 @@ fn main() { println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display()); + // Activate libm's unstable features to make full use of Nightly. + println!("rustc-cfg=libm/unstable"); + // Emscripten's runtime includes all the builtins if target.contains("emscripten") { return; From e796054f9ee7722a9b473de8de737a443bbd1112 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 6 Sep 2019 18:02:11 -0600 Subject: [PATCH 0810/4206] Update build.rs --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 5cdabf95987ee..b520b62477ed7 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -9,7 +9,7 @@ fn main() { println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display()); // Activate libm's unstable features to make full use of Nightly. - println!("rustc-cfg=libm/unstable"); + println!("cargo:rustc-cfg=feature=\"unstable\""); // Emscripten's runtime includes all the builtins if target.contains("emscripten") { From b86b2d59bc2f9141bbb71ec029677c5f9af321e0 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Mon, 9 Sep 2019 19:43:37 -0600 Subject: [PATCH 0811/4206] update the libm submodule, again --- library/compiler-builtins/.gitmodules | 2 +- library/compiler-builtins/libm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index 23d29e11b4da2..a71118ff93e7f 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -1,3 +1,3 @@ [submodule "libm"] path = libm - url = https://github.com/Lokathor/libm + url = https://github.com/rust-lang-nursery/libm diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 52983bee338ac..8eedc2470531f 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 52983bee338ac439bc0f1146d6053955e3b4c33a +Subproject commit 8eedc2470531f51b978e4c873ee78a33c90e0fbd From fda4a8992f627723a7ffc7f2c801aa4c8148944e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 10 Sep 2019 10:07:17 -0500 Subject: [PATCH 0812/4206] Migrate from azure pipelines to Github actions (#226) Should make user management easier and also helps follow the repository when it's renamed. --- .../libm/.github/workflows/main.yml | 67 +++++++++++++++ library/compiler-builtins/libm/README.md | 4 +- .../libm/azure-pipelines.yml | 82 ------------------- .../libm/ci/azure-install-rust.yml | 25 ------ 4 files changed, 68 insertions(+), 110 deletions(-) create mode 100644 library/compiler-builtins/libm/.github/workflows/main.yml delete mode 100644 library/compiler-builtins/libm/azure-pipelines.yml delete mode 100644 library/compiler-builtins/libm/ci/azure-install-rust.yml diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml new file mode 100644 index 0000000000000..80ce4ebd5a69c --- /dev/null +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -0,0 +1,67 @@ +name: CI +on: [push, pull_request] + +jobs: + docker: + name: Docker + runs-on: ubuntu-latest + strategy: + matrix: + target: + - aarch64-unknown-linux-gnu + - arm-unknown-linux-gnueabi + - arm-unknown-linux-gnueabihf + - armv7-unknown-linux-gnueabihf + - i686-unknown-linux-gnu + - mips-unknown-linux-gnu + - mips64-unknown-linux-gnuabi64 + - mips64el-unknown-linux-gnuabi64 + - powerpc-unknown-linux-gnu + - powerpc64-unknown-linux-gnu + - powerpc64le-unknown-linux-gnu + - x86_64-unknown-linux-gnu + steps: + - uses: actions/checkout@master + - name: Install Rust + run: rustup update nightly && rustup default nightly + - run: rustup target add ${{ matrix.target }} + - run: rustup target add x86_64-unknown-linux-musl + - run: cargo generate-lockfile + - run: ./ci/run-docker.sh ${{ matrix.target }} + + rustfmt: + name: Rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Install Rust + run: rustup update stable && rustup default stable && rustup component add rustfmt + - run: cargo fmt -- --check + + wasm: + name: WebAssembly + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Install Rust + run: rustup update nightly && rustup default nightly + - run: rustup target add wasm32-unknown-unknown + - run: cargo build --target wasm32-unknown-unknown + + cb: + name: "The compiler-builtins crate works" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Install Rust + run: rustup update nightly && rustup default nightly + - run: cargo build -p cb + + benchmarks: + name: Benchmarks + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Install Rust + run: rustup update nightly && rustup default nightly + - run: cargo bench --all diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index e90b42d740c22..61a6ebfb38263 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -1,7 +1,5 @@ # `libm` -[![Build Status](https://dev.azure.com/rust-lang/libm/_apis/build/status/rust-lang-nursery.libm?branchName=master)](https://dev.azure.com/rust-lang/libm/_build/latest?definitionId=7&branchName=master) - A port of [MUSL]'s libm to Rust. [MUSL]: https://www.musl-libc.org/ @@ -27,7 +25,7 @@ The API documentation can be found [here](https://docs.rs/libm). ## Benchmark [benchmark]: #benchmark -The benchmarks are located in `crates/libm-bench` and require a nightly Rust toolchain. +The benchmarks are located in `crates/libm-bench` and require a nightly Rust toolchain. To run all benchmarks: > cargo +nightly bench --all diff --git a/library/compiler-builtins/libm/azure-pipelines.yml b/library/compiler-builtins/libm/azure-pipelines.yml deleted file mode 100644 index 0d723c56dd251..0000000000000 --- a/library/compiler-builtins/libm/azure-pipelines.yml +++ /dev/null @@ -1,82 +0,0 @@ -trigger: - - master - -jobs: - - job: Docker - pool: - vmImage: ubuntu-16.04 - steps: - - template: ci/azure-install-rust.yml - - bash: rustup target add $TARGET - displayName: "add cross target" - - bash: rustup target add x86_64-unknown-linux-musl - displayName: "add musl target" - - bash: cargo generate-lockfile && ./ci/run-docker.sh $TARGET - displayName: "run tests" - strategy: - matrix: - aarch64: - TARGET: aarch64-unknown-linux-gnu - arm: - TARGET: arm-unknown-linux-gnueabi - armhf: - TARGET: arm-unknown-linux-gnueabihf - armv7: - TARGET: armv7-unknown-linux-gnueabihf - i686: - TARGET: i686-unknown-linux-gnu - mips: - TARGET: mips-unknown-linux-gnu - mips64: - TARGET: mips64-unknown-linux-gnuabi64 - mips64el: - TARGET: mips64el-unknown-linux-gnuabi64 - powerpc: - TARGET: powerpc-unknown-linux-gnu - powerpc64: - TARGET: powerpc64-unknown-linux-gnu - powerpc64le: - TARGET: powerpc64le-unknown-linux-gnu - x86_64: - TARGET: x86_64-unknown-linux-gnu - - - job: wasm - pool: - vmImage: ubuntu-16.04 - steps: - - template: ci/azure-install-rust.yml - - script: rustup target add wasm32-unknown-unknown - displayName: "Install rust wasm target" - - script: cargo build --target wasm32-unknown-unknown - displayName: "Build for wasm" - variables: - TOOLCHAIN: nightly - - - job: rustfmt - pool: - vmImage: ubuntu-16.04 - steps: - - template: ci/azure-install-rust.yml - - bash: rustup component add rustfmt - displayName: "install rustfmt" - - bash: cargo fmt --all -- --check - displayName: "check formatting" - - - job: compiler_builtins_works - pool: - vmImage: ubuntu-16.04 - steps: - - template: ci/azure-install-rust.yml - - bash: cargo build -p cb - displayName: "Check compiler-builtins still probably builds" - - - job: benchmarks - pool: - vmImage: ubuntu-16.04 - steps: - - template: ci/azure-install-rust.yml - - bash: cargo bench --all - displayName: "Benchmarks" - variables: - TOOLCHAIN: nightly - diff --git a/library/compiler-builtins/libm/ci/azure-install-rust.yml b/library/compiler-builtins/libm/ci/azure-install-rust.yml deleted file mode 100644 index f1cd87bcc5c7b..0000000000000 --- a/library/compiler-builtins/libm/ci/azure-install-rust.yml +++ /dev/null @@ -1,25 +0,0 @@ -steps: - - bash: | - set -e - toolchain=$TOOLCHAIN - if [ "$toolchain" = "" ]; then - toolchain=stable - fi - if command -v rustup; then - rustup update $toolchain - rustup default $toolchain - else - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $toolchain - echo "##vso[task.prependpath]$HOME/.cargo/bin" - fi - displayName: Install rust (unix) - condition: ne( variables['Agent.OS'], 'Windows_NT' ) - - - bash: rustup update stable-$TOOLCHAIN && rustup default stable-$TOOLCHAIN - displayName: Install rust (windows) - condition: eq( variables['Agent.OS'], 'Windows_NT' ) - - - script: | - rustc -Vv - cargo -V - displayName: Query rust and cargo versions From 0198311a4b56a1fac90cdbd8dccaa587d4bd35be Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 10 Sep 2019 18:16:26 -0700 Subject: [PATCH 0813/4206] Migrate to github actions from Azure Pipelines Less need to manage users, more concurrency, and interface is all in one! --- .../.github/workflows/main.yml | 146 ++++++++++++++++++ library/compiler-builtins/README.md | 2 - library/compiler-builtins/azure-pipelines.yml | 80 ---------- .../ci/azure-install-rust.yml | 30 ---- library/compiler-builtins/ci/azure-steps.yml | 28 ---- 5 files changed, 146 insertions(+), 140 deletions(-) create mode 100644 library/compiler-builtins/.github/workflows/main.yml delete mode 100644 library/compiler-builtins/azure-pipelines.yml delete mode 100644 library/compiler-builtins/ci/azure-install-rust.yml delete mode 100644 library/compiler-builtins/ci/azure-steps.yml diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml new file mode 100644 index 0000000000000..f9fb844a98e81 --- /dev/null +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -0,0 +1,146 @@ +name: CI +on: [push, pull_request] + +jobs: + test: + name: Test + runs-on: ${{ matrix.os }} + strategy: + matrix: + target: + - aarch64-unknown-linux-gnu + - arm-unknown-linux-gnueabi + - arm-unknown-linux-gnueabihf + - i586-unknown-linux-gnu + - i686-unknown-linux-gnu + - mips-unknown-linux-gnu + - mips64-unknown-linux-gnuabi64 + - mips64el-unknown-linux-gnuabi64 + - mipsel-unknown-linux-gnu + - powerpc-unknown-linux-gnu + - powerpc64-unknown-linux-gnu + - powerpc64le-unknown-linux-gnu + - thumbv6m-none-eabi + - thumbv7em-none-eabi + - thumbv7em-none-eabihf + - thumbv7m-none-eabi + - wasm32-unknown-unknown + - x86_64-unknown-linux-gnu + - x86_64-apple-darwin + - i686-pc-windows-msvc + - x86_64-pc-windows-msvc + - i686-pc-windows-gnu + - x86_64-pc-windows-gnu + include: + - target: aarch64-unknown-linux-gnu + os: ubuntu-latest + rust: nightly + - target: arm-unknown-linux-gnueabi + os: ubuntu-latest + rust: nightly + - target: arm-unknown-linux-gnueabihf + os: ubuntu-latest + rust: nightly + - target: i586-unknown-linux-gnu + os: ubuntu-latest + rust: nightly + - target: i686-unknown-linux-gnu + os: ubuntu-latest + rust: nightly + - target: mips-unknown-linux-gnu + os: ubuntu-latest + rust: nightly + - target: mips64-unknown-linux-gnuabi64 + os: ubuntu-latest + rust: nightly + - target: mips64el-unknown-linux-gnuabi64 + os: ubuntu-latest + rust: nightly + - target: mipsel-unknown-linux-gnu + os: ubuntu-latest + rust: nightly + - target: powerpc-unknown-linux-gnu + os: ubuntu-latest + rust: nightly + - target: powerpc64-unknown-linux-gnu + os: ubuntu-latest + rust: nightly + - target: powerpc64le-unknown-linux-gnu + os: ubuntu-latest + rust: nightly + - target: thumbv6m-none-eabi + os: ubuntu-latest + rust: nightly + - target: thumbv7em-none-eabi + os: ubuntu-latest + rust: nightly + - target: thumbv7em-none-eabihf + os: ubuntu-latest + rust: nightly + - target: thumbv7m-none-eabi + os: ubuntu-latest + rust: nightly + - target: wasm32-unknown-unknown + os: ubuntu-latest + rust: nightly + - target: x86_64-unknown-linux-gnu + os: ubuntu-latest + rust: nightly + - target: x86_64-apple-darwin + os: macos-latest + rust: nightly + - target: i686-pc-windows-msvc + os: windows-latest + rust: nightly + - target: x86_64-pc-windows-msvc + os: windows-latest + rust: nightly + - target: i686-pc-windows-gnu + os: windows-latest + rust: nightly-i686-gnu + - target: x86_64-pc-windows-gnu + os: windows-latest + rust: nightly-x86_64-gnu + steps: + - uses: actions/checkout@master + with: + submodules: true + - name: Install Rust (rustup) + run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }} + if: matrix.os != 'macos-latest' + - name: Install Rust (macos) + run: | + curl https://sh.rustup.rs | sh -s -- -y --default-toolchain nightly + echo "##[add-path]$HOME/.cargo/bin" + if: matrix.os == 'macos-latest' + - run: rustup target add ${{ matrix.target }} + - name: Download compiler-rt reference sources + run: | + curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/8.0-2019-03-18.tar.gz + tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-8.0-2019-03-18/compiler-rt + echo "##[set-env name=RUST_COMPILER_RT_ROOT]./compiler-rt" + shell: bash + + # Non-linux tests just use our raw script + - run: ./ci/run.sh ${{ matrix.target }} + if: matrix.os != 'ubuntu-latest' + shell: bash + + # Wasm is special and is just build as a smoke test + - run: cargo build --target ${{ matrix.target }} + if: matrix.target == 'wasm32-unknown-unknown' + + # Otherwise we use our docker containers to run builds + - run: cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} + if: matrix.target != 'wasm32-unknown-unknown' && matrix.os == 'ubuntu-latest' + + rustfmt: + name: Rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + with: + submodules: true + - name: Install Rust + run: rustup update stable && rustup default stable && rustup component add rustfmt + - run: cargo fmt -- --check diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index f0724bffe1d0a..262e9843d7711 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -1,7 +1,5 @@ # `compiler-builtins` -[![Build Status](https://dev.azure.com/rust-lang/compiler-builtins/_apis/build/status/rust-lang-nursery.compiler-builtins?branchName=master)](https://dev.azure.com/rust-lang/compiler-builtins/_build/latest?definitionId=6&branchName=master) - > Porting `compiler-rt` intrinsics to Rust See [rust-lang/rust#35437][0]. diff --git a/library/compiler-builtins/azure-pipelines.yml b/library/compiler-builtins/azure-pipelines.yml deleted file mode 100644 index eac3fb5e486bb..0000000000000 --- a/library/compiler-builtins/azure-pipelines.yml +++ /dev/null @@ -1,80 +0,0 @@ -trigger: - - master - -jobs: - - job: Linux - pool: - vmImage: ubuntu-16.04 - steps: - - template: ci/azure-steps.yml - strategy: - matrix: - aarch64: - TARGET: aarch64-unknown-linux-gnu - arm: - TARGET: arm-unknown-linux-gnueabi - armhf: - TARGET: arm-unknown-linux-gnueabihf - i586: - TARGET: i586-unknown-linux-gnu - i686: - TARGET: i686-unknown-linux-gnu - mips: - TARGET: mips-unknown-linux-gnu - mips64: - TARGET: mips64-unknown-linux-gnuabi64 - mips64el: - TARGET: mips64el-unknown-linux-gnuabi64 - mipsel: - TARGET: mipsel-unknown-linux-gnu - powerpc: - TARGET: powerpc-unknown-linux-gnu - powerpc64: - TARGET: powerpc64-unknown-linux-gnu - powerpc64le: - TARGET: powerpc64le-unknown-linux-gnu - thumbv6m: - TARGET: thumbv6m-none-eabi - thumbv7em: - TARGET: thumbv7em-none-eabi - thumbv7emhf: - TARGET: thumbv7em-none-eabihf - thumbv7m: - TARGET: thumbv7m-none-eabi - wasm32: - TARGET: wasm32-unknown-unknown - ONLY_BUILD: 1 - x86_64: - TARGET: x86_64-unknown-linux-gnu - - - job: macOS - pool: - vmImage: macos-10.13 - steps: - - template: ci/azure-steps.yml - strategy: - matrix: - x86_64: - TARGET: x86_64-apple-darwin - i686: - TARGET: i686-apple-darwin - - - job: Windows - pool: - vmImage: 'vs2017-win2016' - steps: - - template: ci/azure-steps.yml - strategy: - matrix: - i686-msvc: - TARGET: i686-pc-windows-msvc - x86_64-msvc: - TARGET: x86_64-pc-windows-msvc - i686-gnu: - TARGET: i686-pc-windows-gnu - INTRINSICS_FAILS_WITH_MEM_FEATURE: 1 - DEBUG_LTO_BUILD_DOESNT_WORK: 1 - x86_64-gnu: - TARGET: x86_64-pc-windows-gnu - INTRINSICS_FAILS_WITH_MEM_FEATURE: 1 - DEBUG_LTO_BUILD_DOESNT_WORK: 1 diff --git a/library/compiler-builtins/ci/azure-install-rust.yml b/library/compiler-builtins/ci/azure-install-rust.yml deleted file mode 100644 index d0255f85b2798..0000000000000 --- a/library/compiler-builtins/ci/azure-install-rust.yml +++ /dev/null @@ -1,30 +0,0 @@ -parameters: - toolchain: 'nightly' - -steps: - - bash: | - set -e - if command -v rustup; then - rustup update $TOOLCHAIN - rustup default $TOOLCHAIN - else - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $TOOLCHAIN - echo "##vso[task.prependpath]$HOME/.cargo/bin" - fi - displayName: Install rust - condition: ne( variables['Agent.OS'], 'Windows_NT' ) - env: - TOOLCHAIN: ${{ parameters.toolchain }} - - - script: | - rustup update --no-self-update %TOOLCHAIN%-%TARGET% - rustup default %TOOLCHAIN%-%TARGET% - displayName: Install rust - condition: eq( variables['Agent.OS'], 'Windows_NT' ) - env: - TOOLCHAIN: ${{ parameters.toolchain }} - - - script: | - rustc -Vv - cargo -V - displayName: Query rust and cargo versions diff --git a/library/compiler-builtins/ci/azure-steps.yml b/library/compiler-builtins/ci/azure-steps.yml deleted file mode 100644 index f08beca05bfaf..0000000000000 --- a/library/compiler-builtins/ci/azure-steps.yml +++ /dev/null @@ -1,28 +0,0 @@ -steps: - - checkout: self - submodules: true - - - template: azure-install-rust.yml - - - bash: rustup target add $TARGET - displayName: Install Rust target - - - bash: | - set -e - curl -L https://github.com/rust-lang/llvm-project/archive/rustc/8.0-2019-03-18.tar.gz | \ - tar xzf - --strip-components 1 llvm-project-rustc-8.0-2019-03-18/compiler-rt - echo '##vso[task.setvariable variable=RUST_COMPILER_RT_ROOT]./compiler-rt' - displayName: "Download compiler-rt reference sources" - - - bash: ./ci/run.sh $TARGET - condition: ne( variables['Agent.OS'], 'Linux' ) - displayName: Run test script - - - bash: | - if [ "$ONLY_BUILD" = "1" ]; then - cargo build --target $TARGET - else - cargo generate-lockfile && ./ci/run-docker.sh $TARGET - fi - condition: eq( variables['Agent.OS'], 'Linux' ) - displayName: Run docker test script From d7adb275eb03ead501e772795049d7e8dd321ad1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 25 Sep 2019 11:19:35 -0700 Subject: [PATCH 0814/4206] Update the gitmodule url for `libm` --- library/compiler-builtins/.gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index a71118ff93e7f..726b1c5c67c99 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -1,3 +1,3 @@ [submodule "libm"] path = libm - url = https://github.com/rust-lang-nursery/libm + url = https://github.com/rust-lang/libm.git From 30bf61039f4777bfd927c3fec8b8a7cc0f8ae5eb Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 25 Sep 2019 11:20:14 -0700 Subject: [PATCH 0815/4206] Remove `-nursery` from urls --- library/compiler-builtins/Cargo.toml | 4 ++-- library/compiler-builtins/README.md | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 0705dbd9c32b3..2e3c7038e6643 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -4,8 +4,8 @@ name = "compiler_builtins" version = "0.1.19" license = "MIT/Apache-2.0" readme = "README.md" -repository = "https://github.com/rust-lang-nursery/compiler-builtins" -homepage = "https://github.com/rust-lang-nursery/compiler-builtins" +repository = "https://github.com/rust-lang/compiler-builtins" +homepage = "https://github.com/rust-lang/compiler-builtins" documentation = "https://docs.rs/compiler_builtins" description = """ Compiler intrinsics used by the Rust compiler. Also available for other targets diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 262e9843d7711..a20d038f8e9ac 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -19,7 +19,7 @@ building: ``` toml # Cargo.toml [dependencies] -compiler_builtins = { git = "https://github.com/rust-lang-nursery/compiler-builtins" } +compiler_builtins = { git = "https://github.com/rust-lang/compiler-builtins" } ``` ``` rust @@ -40,11 +40,11 @@ implementation as well for unimplemented intrinsics: ```toml [dependencies.compiler_builtins] -git = "https://github.com/rust-lang-nursery/compiler-builtins" +git = "https://github.com/rust-lang/compiler-builtins" features = ["c"] ``` -[an issue]: https://github.com/rust-lang-nursery/compiler-builtins/issues +[an issue]: https://github.com/rust-lang/compiler-builtins/issues ## Contributing @@ -61,8 +61,8 @@ features = ["c"] [1]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/test/builtins/Unit [2]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/lib/builtins -[3]: https://github.com/rust-lang-nursery/compiler-builtins/blob/0ba07e49264a54cb5bbd4856fcea083bb3fbec15/build.rs#L180-L265 -[4]: https://travis-ci.org/rust-lang-nursery/compiler-builtins +[3]: https://github.com/rust-lang/compiler-builtins/blob/0ba07e49264a54cb5bbd4856fcea083bb3fbec15/build.rs#L180-L265 +[4]: https://travis-ci.org/rust-lang/compiler-builtins ### Porting Reminders From 52ecbdd9c011e8c472de0f25feb968896f6a355f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 25 Sep 2019 11:20:49 -0700 Subject: [PATCH 0816/4206] Remove `-nursery` from urls --- library/compiler-builtins/libm/CONTRIBUTING.md | 6 +++--- library/compiler-builtins/libm/Cargo.toml | 2 +- library/compiler-builtins/libm/README.md | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md index a7e817e13ed23..59c37a6f95926 100644 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -14,13 +14,13 @@ corresponding issue. - :tada: -[issue tracker]: https://github.com/rust-lang-nursery/libm/issues +[issue tracker]: https://github.com/rust-lang/libm/issues [src]: https://git.musl-libc.org/cgit/musl/tree/src/math -[`src/math/truncf.rs`]: https://github.com/rust-lang-nursery/libm/blob/master/src/math/truncf.rs +[`src/math/truncf.rs`]: https://github.com/rust-lang/libm/blob/master/src/math/truncf.rs Check [PR #65] for an example. -[PR #65]: https://github.com/rust-lang-nursery/libm/pull/65 +[PR #65]: https://github.com/rust-lang/libm/pull/65 ## Tips and tricks diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 37aff9a765bbd..1d7d971466278 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -6,7 +6,7 @@ documentation = "https://docs.rs/libm" keywords = ["libm", "math"] license = "MIT OR Apache-2.0" name = "libm" -repository = "https://github.com/rust-lang-nursery/libm" +repository = "https://github.com/rust-lang/libm" version = "0.2.0" edition = "2018" diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 61a6ebfb38263..5d9e9bddbf8fd 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -7,12 +7,12 @@ A port of [MUSL]'s libm to Rust. ## Goals The short term goal of this library is to [enable math support (e.g. `sin`, `atan2`) for the -`wasm32-unknown-unknown` target][wasm] (cf. [rust-lang-nursery/compiler-builtins][pr]). The longer +`wasm32-unknown-unknown` target][wasm] (cf. [rust-lang/compiler-builtins][pr]). The longer term goal is to enable [math support in the `core` crate][core]. -[wasm]: https://github.com/rust-lang-nursery/libm/milestone/1 -[pr]: https://github.com/rust-lang-nursery/compiler-builtins/pull/248 -[core]: https://github.com/rust-lang-nursery/libm/milestone/2 +[wasm]: https://github.com/rust-lang/libm/milestone/1 +[pr]: https://github.com/rust-lang/compiler-builtins/pull/248 +[core]: https://github.com/rust-lang/libm/milestone/2 ## Already usable From af3d2e0a3c8d2992b458b84c209036d2d0317b6c Mon Sep 17 00:00:00 2001 From: Ian Kronquist Date: Mon, 30 Sep 2019 09:02:47 -0700 Subject: [PATCH 0817/4206] Implement bcmp (#315) As of LLVM 9.0, certain calls to memcmp may be converted to bcmp, which I guess could save a single subtraction on some architectures. [1] bcmp is just like memcmp except instead of returning the difference between the two differing bytes, it returns non-zero instead. As such, memcmp is a valid implementation of bcmp. If we care about size, bcmp should just call memcmp. If we care about speed, we can change bcmp to look like this instead: ```rust pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { let mut i = 0; while i < n { let a = *s1.offset(i as isize); let b = *s2.offset(i as isize); if a != b { return 1; } i += 1; } 0 } ``` In this PR I do not address any changes which may or may not be needed for arm aebi as I lack proper test hardware. [1]: https://releases.llvm.org/9.0.0/docs/ReleaseNotes.html#noteworthy-optimizations --- library/compiler-builtins/src/mem.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/src/mem.rs b/library/compiler-builtins/src/mem.rs index 76372d9bc81c8..7b8a37fde7ba7 100644 --- a/library/compiler-builtins/src/mem.rs +++ b/library/compiler-builtins/src/mem.rs @@ -63,6 +63,11 @@ pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { 0 } +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { + memcmp(s1, s2, n) +} + // `bytes` must be a multiple of `mem::size_of::()` fn memcpy_element_unordered_atomic(dest: *mut T, src: *const T, bytes: usize) { unsafe { From 3b3f3e977cdbdf57a70fb3565dc59806df75f81b Mon Sep 17 00:00:00 2001 From: Christopher Serr Date: Fri, 18 Oct 2019 15:23:57 +0200 Subject: [PATCH 0818/4206] Fix sincosf(PI) (#229) Looks like the implementation was not ported correctly. Some negations were forgotten in a certain branch. Here is the original code in musl that has the negations: https://github.com/bpowers/musl/blob/94cb2ec2a0ffcb47d24dbf7a30e462505396cf54/src/math/sincosf.c#L66-L67 Resolves rust-lang/libm#228 --- .../libm/src/math/sincosf.rs | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs index d4e0772d5b105..df644f3b5e3c5 100644 --- a/library/compiler-builtins/libm/src/math/sincosf.rs +++ b/library/compiler-builtins/libm/src/math/sincosf.rs @@ -65,11 +65,11 @@ pub fn sincosf(x: f32) -> (f32, f32) { /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ else { if sign { - s = k_sinf((x + S2PIO2) as f64); - c = k_cosf((x + S2PIO2) as f64); + s = -k_sinf((x + S2PIO2) as f64); + c = -k_cosf((x + S2PIO2) as f64); } else { - s = k_sinf((x - S2PIO2) as f64); - c = k_cosf((x - S2PIO2) as f64); + s = -k_sinf((x - S2PIO2) as f64); + c = -k_cosf((x - S2PIO2) as f64); } } @@ -121,3 +121,16 @@ pub fn sincosf(x: f32) -> (f32, f32) { _ => (0.0, 1.0), } } + +#[cfg(test)] +mod tests { + use super::sincosf; + use crate::_eqf; + + #[test] + fn with_pi() { + let (s, c) = sincosf(core::f32::consts::PI); + _eqf(s.abs(), 0.0).unwrap(); + _eqf(c, -1.0).unwrap(); + } +} From 12283c7acad3dbf62556f8a72d5eedeeba4fbe2e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 28 Oct 2019 07:39:04 -0700 Subject: [PATCH 0819/4206] Fix Github Actions for recent system changes --- library/compiler-builtins/.github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index f9fb844a98e81..92ce9ca21743b 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -108,6 +108,7 @@ jobs: - name: Install Rust (rustup) run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }} if: matrix.os != 'macos-latest' + shell: bash - name: Install Rust (macos) run: | curl https://sh.rustup.rs | sh -s -- -y --default-toolchain nightly From bff186bef3532240249f4b637966a17db2379c96 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 7 Nov 2019 20:04:11 +0100 Subject: [PATCH 0820/4206] Emit `_fltused` on `uefi` targets as a short-term workaround (#317) * Emit `_fltused` on `uefi` targets as a short-term workaround * Remove stray docker container --- library/compiler-builtins/src/x86_64.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 2360ab8a6fa6e..6940f8d9d2910 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -73,3 +73,10 @@ pub unsafe fn ___chkstk() { ); intrinsics::unreachable(); } + +// HACK(https://github.com/rust-lang/rust/issues/62785): x86_64-unknown-uefi needs special LLVM +// support unless we emit the _fltused +#[no_mangle] +#[used] +#[cfg(target_os = "uefi")] +static _fltused: i32 = 0; From 5067dce07477fbf264c1ec4f09a17e22a0e1d8e2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 7 Nov 2019 11:04:36 -0800 Subject: [PATCH 0821/4206] Bump to 0.1.20 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 2e3c7038e6643..b667894abdc84 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.19" +version = "0.1.20" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 3f473cd3f38eba3aa275a5ffb8991314baa49a87 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 11 Nov 2019 12:19:10 -0600 Subject: [PATCH 0822/4206] Allow FFI-unsafe warnings for u128/i128 (#323) * Allow FFI-unsafe warnings for u128/i128 Handle new warnings on nightly, and we shouldn't need to worry about these with compiler-builtins since this is tied to a particular compiler. * Clean up crate attributes * No need for stability marker * Rustdoc docs not used for this crate * Remove old build-system related cruft from rustc itself. * Run `cargo fmt` --- .../compiler-builtins/examples/intrinsics.rs | 1 - library/compiler-builtins/src/lib.rs | 33 +++++------------ .../testcrate/tests/aeabi_memclr.rs | 2 +- .../testcrate/tests/aeabi_memset.rs | 36 +++++++++---------- 4 files changed, 28 insertions(+), 44 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 8b0ffa3a8d6ae..5ceebe13216a9 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -7,7 +7,6 @@ #![cfg_attr(thumb, no_main)] #![deny(dead_code)] #![feature(asm)] -#![feature(compiler_builtins_lib)] #![feature(lang_items)] #![feature(start)] #![feature(allocator_api)] diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index ef5353a7040ef..d90927aae1fd4 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,34 +1,19 @@ -#![cfg_attr(not(stage0), deny(warnings))] -#![cfg_attr(not(test), no_std)] #![cfg_attr(feature = "compiler-builtins", compiler_builtins)] -#![crate_name = "compiler_builtins"] -#![crate_type = "rlib"] -#![doc( - html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/", - html_playground_url = "https://play.rust-lang.org/", - test(attr(deny(warnings))) -)] +#![feature(abi_unadjusted)] #![feature(asm)] #![feature(compiler_builtins)] #![feature(core_intrinsics)] +#![feature(lang_items)] +#![feature(linkage)] #![feature(naked_functions)] #![feature(repr_simd)] -#![feature(abi_unadjusted)] -#![feature(linkage)] -#![feature(lang_items)] -#![allow(unused_features)] #![no_builtins] -#![cfg_attr(feature = "compiler-builtins", feature(staged_api))] -#![cfg_attr( - feature = "compiler-builtins", - unstable( - feature = "compiler_builtins_lib", - reason = "Compiler builtins. Will never become stable.", - issue = "0" - ) -)] +#![no_std] +#![allow(unused_features)] +// We use `u128` in a whole bunch of places which we currently agree with the +// compiler on ABIs and such, so we should be "good enough" for now and changes +// to the `u128` ABI will be reflected here. +#![allow(improper_ctypes)] // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs b/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs index 326435c298d6e..59507693988c4 100644 --- a/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs +++ b/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs @@ -46,7 +46,7 @@ impl Aligned { #[test] fn memclr4() { - let mut aligned = Aligned::new();; + let mut aligned = Aligned::new(); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memset.rs b/library/compiler-builtins/testcrate/tests/aeabi_memset.rs index 3cfbfe5b011ec..f03729bed35ad 100644 --- a/library/compiler-builtins/testcrate/tests/aeabi_memset.rs +++ b/library/compiler-builtins/testcrate/tests/aeabi_memset.rs @@ -45,7 +45,7 @@ impl Aligned { #[test] fn zero() { - let mut aligned = Aligned::new([0u8; 8]);; + let mut aligned = Aligned::new([0u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let c = 0xdeadbeef; @@ -54,7 +54,7 @@ fn zero() { assert_eq!(*xs, [0; 8]); - let mut aligned = Aligned::new([1u8; 8]);; + let mut aligned = Aligned::new([1u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let c = 0xdeadbeef; @@ -66,7 +66,7 @@ fn zero() { #[test] fn one() { - let mut aligned = Aligned::new([0u8; 8]);; + let mut aligned = Aligned::new([0u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let n = 1; @@ -76,7 +76,7 @@ fn one() { assert_eq!(*xs, [0xef, 0, 0, 0, 0, 0, 0, 0]); - let mut aligned = Aligned::new([1u8; 8]);; + let mut aligned = Aligned::new([1u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let c = 0xdeadbeef; @@ -88,7 +88,7 @@ fn one() { #[test] fn two() { - let mut aligned = Aligned::new([0u8; 8]);; + let mut aligned = Aligned::new([0u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let n = 2; @@ -98,7 +98,7 @@ fn two() { assert_eq!(*xs, [0xef, 0xef, 0, 0, 0, 0, 0, 0]); - let mut aligned = Aligned::new([1u8; 8]);; + let mut aligned = Aligned::new([1u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let c = 0xdeadbeef; @@ -110,7 +110,7 @@ fn two() { #[test] fn three() { - let mut aligned = Aligned::new([0u8; 8]);; + let mut aligned = Aligned::new([0u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let n = 3; @@ -120,7 +120,7 @@ fn three() { assert_eq!(*xs, [0xef, 0xef, 0xef, 0, 0, 0, 0, 0]); - let mut aligned = Aligned::new([1u8; 8]);; + let mut aligned = Aligned::new([1u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let c = 0xdeadbeef; @@ -132,7 +132,7 @@ fn three() { #[test] fn four() { - let mut aligned = Aligned::new([0u8; 8]);; + let mut aligned = Aligned::new([0u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let n = 4; @@ -142,7 +142,7 @@ fn four() { assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0, 0, 0, 0]); - let mut aligned = Aligned::new([1u8; 8]);; + let mut aligned = Aligned::new([1u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let c = 0xdeadbeef; @@ -154,7 +154,7 @@ fn four() { #[test] fn five() { - let mut aligned = Aligned::new([0u8; 8]);; + let mut aligned = Aligned::new([0u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let n = 5; @@ -164,7 +164,7 @@ fn five() { assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0, 0, 0]); - let mut aligned = Aligned::new([1u8; 8]);; + let mut aligned = Aligned::new([1u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let c = 0xdeadbeef; @@ -176,7 +176,7 @@ fn five() { #[test] fn six() { - let mut aligned = Aligned::new([0u8; 8]);; + let mut aligned = Aligned::new([0u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let n = 6; @@ -186,7 +186,7 @@ fn six() { assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0, 0]); - let mut aligned = Aligned::new([1u8; 8]);; + let mut aligned = Aligned::new([1u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let c = 0xdeadbeef; @@ -198,7 +198,7 @@ fn six() { #[test] fn seven() { - let mut aligned = Aligned::new([0u8; 8]);; + let mut aligned = Aligned::new([0u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let n = 7; @@ -208,7 +208,7 @@ fn seven() { assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0]); - let mut aligned = Aligned::new([1u8; 8]);; + let mut aligned = Aligned::new([1u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let c = 0xdeadbeef; @@ -220,7 +220,7 @@ fn seven() { #[test] fn eight() { - let mut aligned = Aligned::new([0u8; 8]);; + let mut aligned = Aligned::new([0u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let n = 8; @@ -230,7 +230,7 @@ fn eight() { assert_eq!(*xs, [0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef]); - let mut aligned = Aligned::new([1u8; 8]);; + let mut aligned = Aligned::new([1u8; 8]); assert_eq!(mem::align_of_val(&aligned), 4); let xs = &mut aligned.array; let c = 0xdeadbeef; From eb58e12abf74654faaa04e5e36d270fff8943fae Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 11 Nov 2019 12:38:50 -0600 Subject: [PATCH 0823/4206] Gate atomic intrinsics on presence of instructions (#324) Don't emit the intrinsics for platforms which don't actually have the instructions to do atomic loads/stores. Closes #322 --- library/compiler-builtins/src/lib.rs | 1 + library/compiler-builtins/src/mem.rs | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index d90927aae1fd4..0e1a435370fb9 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,6 +1,7 @@ #![cfg_attr(feature = "compiler-builtins", compiler_builtins)] #![feature(abi_unadjusted)] #![feature(asm)] +#![feature(cfg_target_has_atomic)] #![feature(compiler_builtins)] #![feature(core_intrinsics)] #![feature(lang_items)] diff --git a/library/compiler-builtins/src/mem.rs b/library/compiler-builtins/src/mem.rs index 7b8a37fde7ba7..24552ed851089 100644 --- a/library/compiler-builtins/src/mem.rs +++ b/library/compiler-builtins/src/mem.rs @@ -129,50 +129,65 @@ where } intrinsics! { + #[cfg(target_has_atomic_load_store = "8")] pub extern "C" fn __llvm_memcpy_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () { memcpy_element_unordered_atomic(dest, src, bytes); } + #[cfg(target_has_atomic_load_store = "16")] pub extern "C" fn __llvm_memcpy_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () { memcpy_element_unordered_atomic(dest, src, bytes); } + #[cfg(target_has_atomic_load_store = "32")] pub extern "C" fn __llvm_memcpy_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () { memcpy_element_unordered_atomic(dest, src, bytes); } + #[cfg(target_has_atomic_load_store = "64")] pub extern "C" fn __llvm_memcpy_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () { memcpy_element_unordered_atomic(dest, src, bytes); } + #[cfg(target_has_atomic_load_store = "128")] pub extern "C" fn __llvm_memcpy_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () { memcpy_element_unordered_atomic(dest, src, bytes); } + #[cfg(target_has_atomic_load_store = "8")] pub extern "C" fn __llvm_memmove_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () { memmove_element_unordered_atomic(dest, src, bytes); } + #[cfg(target_has_atomic_load_store = "16")] pub extern "C" fn __llvm_memmove_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () { memmove_element_unordered_atomic(dest, src, bytes); } + #[cfg(target_has_atomic_load_store = "32")] pub extern "C" fn __llvm_memmove_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () { memmove_element_unordered_atomic(dest, src, bytes); } + #[cfg(target_has_atomic_load_store = "64")] pub extern "C" fn __llvm_memmove_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () { memmove_element_unordered_atomic(dest, src, bytes); } + #[cfg(target_has_atomic_load_store = "128")] pub extern "C" fn __llvm_memmove_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () { memmove_element_unordered_atomic(dest, src, bytes); } + #[cfg(target_has_atomic_load_store = "8")] pub extern "C" fn __llvm_memset_element_unordered_atomic_1(s: *mut u8, c: u8, bytes: usize) -> () { memset_element_unordered_atomic(s, c, bytes); } + #[cfg(target_has_atomic_load_store = "16")] pub extern "C" fn __llvm_memset_element_unordered_atomic_2(s: *mut u16, c: u8, bytes: usize) -> () { memset_element_unordered_atomic(s, c, bytes); } + #[cfg(target_has_atomic_load_store = "32")] pub extern "C" fn __llvm_memset_element_unordered_atomic_4(s: *mut u32, c: u8, bytes: usize) -> () { memset_element_unordered_atomic(s, c, bytes); } + #[cfg(target_has_atomic_load_store = "64")] pub extern "C" fn __llvm_memset_element_unordered_atomic_8(s: *mut u64, c: u8, bytes: usize) -> () { memset_element_unordered_atomic(s, c, bytes); } + #[cfg(target_has_atomic_load_store = "128")] pub extern "C" fn __llvm_memset_element_unordered_atomic_16(s: *mut u128, c: u8, bytes: usize) -> () { memset_element_unordered_atomic(s, c, bytes); } From 4729d8bf39f2edc599ba11c22ab2dfb329d75ba6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 11 Nov 2019 10:39:08 -0800 Subject: [PATCH 0824/4206] Bump to 0.1.21 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index b667894abdc84..200c41bf83f14 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.20" +version = "0.1.21" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 62c025e9a85a65f5e8b88a1232720d464d80eb1f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 11 Nov 2019 10:40:09 -0800 Subject: [PATCH 0825/4206] Update publishing instructions --- library/compiler-builtins/PUBLISHING.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/PUBLISHING.md b/library/compiler-builtins/PUBLISHING.md index ad100dee08fbe..3df682ab04a4b 100644 --- a/library/compiler-builtins/PUBLISHING.md +++ b/library/compiler-builtins/PUBLISHING.md @@ -10,8 +10,7 @@ greatly appreciated! 3. Commit this change 4. Run `git tag` to create a tag for this version 5. Delete the `libm/Cargo.toml` file -6. Comment out the `[dev-dependencies]` section of `Cargo.toml` -7. Run `cargo +nightly publish --allow-dirty` -8. Push the tag -9. Push the commit -10. Undo changes to `Cargo.toml` and the `libm` submodule +6. Run `cargo +nightly publish` +7. Push the tag +8. Push the commit +9. Undo changes to `Cargo.toml` and the `libm` submodule From a8d9eb7521122bf58cbe1bd8d313b37aede07bdb Mon Sep 17 00:00:00 2001 From: AJ Frantz Date: Fri, 22 Nov 2019 14:16:00 -0500 Subject: [PATCH 0826/4206] Fix sincosf for interval (7*pi/4, 9*pi/4) (#233) A mistake was made in porting musl's implementation which caused the sin and cos components to be reversed. closes rust-lang/libm#232 --- .../libm/src/math/sincosf.rs | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs index df644f3b5e3c5..2725caad63c7c 100644 --- a/library/compiler-builtins/libm/src/math/sincosf.rs +++ b/library/compiler-builtins/libm/src/math/sincosf.rs @@ -89,11 +89,11 @@ pub fn sincosf(x: f32) -> (f32, f32) { } } else { if sign { - s = k_cosf((x + S4PIO2) as f64); - c = k_sinf((x + S4PIO2) as f64); + s = k_sinf((x + S4PIO2) as f64); + c = k_cosf((x + S4PIO2) as f64); } else { - s = k_cosf((x - S4PIO2) as f64); - c = k_sinf((x - S4PIO2) as f64); + s = k_sinf((x - S4PIO2) as f64); + c = k_cosf((x - S4PIO2) as f64); } } @@ -133,4 +133,22 @@ mod tests { _eqf(s.abs(), 0.0).unwrap(); _eqf(c, -1.0).unwrap(); } + + #[test] + fn rotational_symmetry() { + use core::f32::consts::PI; + const N: usize = 24; + for n in 0..N { + let theta = 2. * PI * (n as f32) / (N as f32); + let (s, c) = sincosf(theta); + let (s_plus, c_plus) = sincosf(theta + 2. * PI); + let (s_minus, c_minus) = sincosf(theta - 2. * PI); + + const TOLERANCE: f32 = 1e-6; + assert!((s - s_plus).abs() < TOLERANCE); + assert!((s - s_minus).abs() < TOLERANCE); + assert!((c - c_plus).abs() < TOLERANCE); + assert!((c - c_minus).abs() < TOLERANCE); + } + } } From d6d215b97c6300ce15a8a0338520b82ac53b4fa4 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 22 Nov 2019 11:16:36 -0800 Subject: [PATCH 0827/4206] Bump to 0.2.1 --- library/compiler-builtins/libm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 1d7d971466278..d9d6680409e14 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -7,7 +7,7 @@ keywords = ["libm", "math"] license = "MIT OR Apache-2.0" name = "libm" repository = "https://github.com/rust-lang/libm" -version = "0.2.0" +version = "0.2.1" edition = "2018" [features] From ca69fcbf1277d31dbcfd2136a460a8209d4ef129 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 3 Dec 2019 09:11:29 -0800 Subject: [PATCH 0828/4206] Update checkout action reference --- library/compiler-builtins/.github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 92ce9ca21743b..1e1666ab50db5 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -102,7 +102,7 @@ jobs: os: windows-latest rust: nightly-x86_64-gnu steps: - - uses: actions/checkout@master + - uses: actions/checkout@v1 with: submodules: true - name: Install Rust (rustup) @@ -139,7 +139,7 @@ jobs: name: Rustfmt runs-on: ubuntu-latest steps: - - uses: actions/checkout@master + - uses: actions/checkout@v1 with: submodules: true - name: Install Rust From d511d48b973cc5f8015ab2e1fbbb2b66d2eefab3 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Fri, 6 Dec 2019 06:51:42 -0800 Subject: [PATCH 0829/4206] Add control flow information to __rust_probestack (#328) --- library/compiler-builtins/src/lib.rs | 1 + library/compiler-builtins/src/probestack.rs | 232 ++++++++++++-------- 2 files changed, 144 insertions(+), 89 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 0e1a435370fb9..e57a5ef3f8748 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,6 +1,7 @@ #![cfg_attr(feature = "compiler-builtins", compiler_builtins)] #![feature(abi_unadjusted)] #![feature(asm)] +#![feature(global_asm)] #![feature(cfg_target_has_atomic)] #![feature(compiler_builtins)] #![feature(core_intrinsics)] diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 9bcaf4fd13dcb..933a60dd9850c 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -41,95 +41,149 @@ //! 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(windows))] // Windows already has builtins to do this - -#[naked] -#[no_mangle] -#[cfg(all(target_arch = "x86_64", not(feature = "mangled-names")))] -pub unsafe extern "C" fn __rust_probestack() { - // Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax, - // ensuring that if any pages are unmapped we'll make a page fault. - // - // The ABI here is that the stack frame size is located in `%eax`. Upon - // return we're not supposed to modify `%esp` or `%eax`. - asm!(" - pushq %rbp - movq %rsp, %rbp - - mov %rax,%r11 // duplicate %rax as we're clobbering %r11 - - // Main loop, taken in one page increments. We're decrementing rsp by - // a page each time until there's less than a page remaining. We're - // guaranteed that this function isn't called unless there's more than a - // page needed. - // - // Note that we're also testing against `8(%rsp)` to account for the 8 - // bytes pushed on the stack orginally with our return address. Using - // `8(%rsp)` simulates us testing the stack pointer in the caller's - // context. - - // It's usually called when %rax >= 0x1000, but that's not always true. - // Dynamic stack allocation, which is needed to implement unsized - // rvalues, triggers stackprobe even if %rax < 0x1000. - // Thus we have to check %r11 first to avoid segfault. - cmp $$0x1000,%r11 - jna 3f - 2: - sub $$0x1000,%rsp - test %rsp,8(%rsp) - sub $$0x1000,%r11 - cmp $$0x1000,%r11 - ja 2b - - 3: - // Finish up the last remaining stack space requested, getting the last - // bits out of r11 - sub %r11,%rsp - test %rsp,8(%rsp) - - // Restore the stack pointer to what it previously was when entering - // this function. The caller will readjust the stack pointer after we - // return. - add %rax,%rsp - - leave - ret - " ::: "memory" : "volatile"); - ::core::intrinsics::unreachable(); +#![cfg(not(feature = "mangled-names"))] +// Windows already has builtins to do this. +#![cfg(not(windows))] +// We only define stack probing for these architectures today. +#![cfg(any(target_arch = "x86_64", target_arch = "x86"))] + +extern "C" { + pub fn __rust_probestack(); } -#[naked] -#[no_mangle] -#[cfg(all(target_arch = "x86", not(feature = "mangled-names")))] -pub unsafe extern "C" fn __rust_probestack() { - // This is the same as x86_64 above, only translated for 32-bit sizes. Note - // that on Unix we're expected to restore everything as it was, this - // function basically can't tamper with anything. - // - // The ABI here is the same as x86_64, except everything is 32-bits large. - asm!(" - push %ebp - mov %esp, %ebp - push %ecx - mov %eax,%ecx - - cmp $$0x1000,%ecx - jna 3f - 2: - sub $$0x1000,%esp - test %esp,8(%esp) - sub $$0x1000,%ecx - cmp $$0x1000,%ecx - ja 2b - - 3: - sub %ecx,%esp - test %esp,8(%esp) - - add %eax,%esp - pop %ecx - leave - ret - " ::: "memory" : "volatile"); - ::core::intrinsics::unreachable(); +// A wrapper for our implementation of __rust_probestack, which allows us to +// keep the assembly inline while controlling all CFI directives in the assembly +// emitted for the function. +// +// This is the ELF version. +#[cfg(not(target_vendor = "apple"))] +macro_rules! define_rust_probestack { + ($body: expr) => { + concat!( + " + .pushsection .text.__rust_probestack + .globl __rust_probestack + .type __rust_probestack, @function + __rust_probestack: + ", + $body, + " + .size __rust_probestack, . - __rust_probestack + .popsection + " + ) + }; +} + +// Same as above, but for Mach-O. +#[cfg(target_vendor = "apple")] +macro_rules! define_rust_probestack { + ($body: expr) => { + concat!( + " + .globl ___rust_probestack + ___rust_probestack: + ", + $body + ) + }; } + +// Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax, +// ensuring that if any pages are unmapped we'll make a page fault. +// +// The ABI here is that the stack frame size is located in `%rax`. Upon +// return we're not supposed to modify `%rsp` or `%rax`. +#[cfg(target_arch = "x86_64")] +global_asm!(define_rust_probestack!( + " + .cfi_startproc + pushq %rbp + .cfi_adjust_cfa_offset 8 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + + mov %rax,%r11 // duplicate %rax as we're clobbering %r11 + + // Main loop, taken in one page increments. We're decrementing rsp by + // a page each time until there's less than a page remaining. We're + // guaranteed that this function isn't called unless there's more than a + // page needed. + // + // Note that we're also testing against `8(%rsp)` to account for the 8 + // bytes pushed on the stack orginally with our return address. Using + // `8(%rsp)` simulates us testing the stack pointer in the caller's + // context. + + // It's usually called when %rax >= 0x1000, but that's not always true. + // Dynamic stack allocation, which is needed to implement unsized + // rvalues, triggers stackprobe even if %rax < 0x1000. + // Thus we have to check %r11 first to avoid segfault. + cmp $0x1000,%r11 + jna 3f +2: + sub $0x1000,%rsp + test %rsp,8(%rsp) + sub $0x1000,%r11 + cmp $0x1000,%r11 + ja 2b + +3: + // Finish up the last remaining stack space requested, getting the last + // bits out of r11 + sub %r11,%rsp + test %rsp,8(%rsp) + + // Restore the stack pointer to what it previously was when entering + // this function. The caller will readjust the stack pointer after we + // return. + add %rax,%rsp + + leave + .cfi_def_cfa_register %rsp + .cfi_adjust_cfa_offset -8 + ret + .cfi_endproc + " +)); + +#[cfg(target_arch = "x86")] +// This is the same as x86_64 above, only translated for 32-bit sizes. Note +// that on Unix we're expected to restore everything as it was, this +// function basically can't tamper with anything. +// +// The ABI here is the same as x86_64, except everything is 32-bits large. +global_asm!(define_rust_probestack!( + " + .cfi_startproc + push %ebp + .cfi_adjust_cfa_offset 4 + .cfi_offset %ebp, -8 + mov %esp, %ebp + .cfi_def_cfa_register %ebp + push %ecx + mov %eax,%ecx + + cmp $0x1000,%ecx + jna 3f +2: + sub $0x1000,%esp + test %esp,8(%esp) + sub $0x1000,%ecx + cmp $0x1000,%ecx + ja 2b + +3: + sub %ecx,%esp + test %esp,8(%esp) + + add %eax,%esp + pop %ecx + leave + .cfi_def_cfa_register %esp + .cfi_adjust_cfa_offset -4 + ret + .cfi_endproc + " +)); From c056e295e23c17d89a27eb62b165a03ab5c46696 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 6 Dec 2019 06:54:50 -0800 Subject: [PATCH 0830/4206] Bump to 1.0.22 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 200c41bf83f14..4d5ffa712a73b 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.21" +version = "0.1.22" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 304028b2ed215dddbd141cfcd2ab37f9da479914 Mon Sep 17 00:00:00 2001 From: Runji Wang Date: Wed, 11 Dec 2019 01:02:14 +0800 Subject: [PATCH 0831/4206] Fix compile error on x86_64-unknown-uefi target (#331) * fix compile error on x86_64-unknown-uefi target * Fix tests on nightly --- library/compiler-builtins/src/probestack.rs | 4 ++-- .../compiler-builtins/testcrate/tests/count_leading_zeros.rs | 2 -- library/compiler-builtins/testcrate/tests/generated.rs | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 933a60dd9850c..70b33b8be2d2d 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -56,7 +56,7 @@ extern "C" { // emitted for the function. // // This is the ELF version. -#[cfg(not(target_vendor = "apple"))] +#[cfg(not(any(target_vendor = "apple", target_os = "uefi")))] macro_rules! define_rust_probestack { ($body: expr) => { concat!( @@ -76,7 +76,7 @@ macro_rules! define_rust_probestack { } // Same as above, but for Mach-O. -#[cfg(target_vendor = "apple")] +#[cfg(any(target_vendor = "apple", target_os = "uefi"))] macro_rules! define_rust_probestack { ($body: expr) => { concat!( diff --git a/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs b/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs index b50a7ce843075..022b2d8529367 100644 --- a/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs +++ b/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs @@ -1,5 +1,3 @@ -#![feature(compiler_builtins_lib)] - extern crate compiler_builtins; use compiler_builtins::int::__clzsi2; diff --git a/library/compiler-builtins/testcrate/tests/generated.rs b/library/compiler-builtins/testcrate/tests/generated.rs index ee575cba87e0a..a296db22da689 100644 --- a/library/compiler-builtins/testcrate/tests/generated.rs +++ b/library/compiler-builtins/testcrate/tests/generated.rs @@ -1,4 +1,3 @@ -#![feature(compiler_builtins_lib)] #![feature(lang_items)] #![allow(bad_style)] #![allow(unused_imports)] From 643306f30836e0d0de45e6f4d6d858a427c642ee Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 10 Dec 2019 09:02:40 -0800 Subject: [PATCH 0832/4206] Bump to 0.1.23 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 4d5ffa712a73b..39c4553fe1e98 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.22" +version = "0.1.23" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 328332003d2399c179a4488c393fb8d77ddd6a78 Mon Sep 17 00:00:00 2001 From: Adam Schwalm Date: Mon, 6 Jan 2020 10:22:30 -0600 Subject: [PATCH 0833/4206] Add separate rust_probestack definition for uefi (#335) This is necessary because the Mach-O definition must have the triple underscore, but the UEFI one must not. --- library/compiler-builtins/src/probestack.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 70b33b8be2d2d..3797df0d56b66 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -75,8 +75,22 @@ macro_rules! define_rust_probestack { }; } -// Same as above, but for Mach-O. -#[cfg(any(target_vendor = "apple", target_os = "uefi"))] +#[cfg(target_os = "uefi")] +macro_rules! define_rust_probestack { + ($body: expr) => { + concat!( + " + .globl __rust_probestack + __rust_probestack: + ", + $body + ) + }; +} + +// Same as above, but for Mach-O. Note that the triple underscore +// is deliberate +#[cfg(target_vendor = "apple")] macro_rules! define_rust_probestack { ($body: expr) => { concat!( From 8647190d6c57211c6ddec677e9a0821cea30a4e6 Mon Sep 17 00:00:00 2001 From: Daniel Frampton Date: Tue, 14 Jan 2020 13:28:10 -0800 Subject: [PATCH 0834/4206] Don't modify the intrinsic abi for aarch64 windows (#337) --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/src/macros.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 39c4553fe1e98..3203f1c6c026a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.23" +version = "0.1.24" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 2d11ba622b817..a86794072c257 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -165,13 +165,13 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( - #[cfg(all(windows, target_pointer_width = "64"))] + #[cfg(all(windows, target_arch = "x86_64"))] $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } - #[cfg(all(windows, target_pointer_width = "64"))] + #[cfg(all(windows, target_arch = "x86_64"))] pub mod $name { intrinsics! { @@ -184,7 +184,7 @@ macro_rules! intrinsics { } } - #[cfg(not(all(windows, target_pointer_width = "64")))] + #[cfg(not(all(windows, target_arch = "x86_64")))] intrinsics! { $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { From b2227dc5594895d8ee410b03b1aa4d64eab60c54 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 28 Jan 2020 00:39:52 -0800 Subject: [PATCH 0835/4206] Update CI installation of Rust on macos --- library/compiler-builtins/.github/workflows/main.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 1e1666ab50db5..4691549976487 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -107,13 +107,7 @@ jobs: submodules: true - name: Install Rust (rustup) run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }} - if: matrix.os != 'macos-latest' shell: bash - - name: Install Rust (macos) - run: | - curl https://sh.rustup.rs | sh -s -- -y --default-toolchain nightly - echo "##[add-path]$HOME/.cargo/bin" - if: matrix.os == 'macos-latest' - run: rustup target add ${{ matrix.target }} - name: Download compiler-rt reference sources run: | From 6677b55fcbbe11b8a9387144e4a0cd17dc15cc6c Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Tue, 11 Feb 2020 22:21:12 -0800 Subject: [PATCH 0836/4206] Set probestack visibility to hidden on ELF targets (#340) --- library/compiler-builtins/src/probestack.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 3797df0d56b66..19307df4e936b 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -64,6 +64,7 @@ macro_rules! define_rust_probestack { .pushsection .text.__rust_probestack .globl __rust_probestack .type __rust_probestack, @function + .hidden __rust_probestack __rust_probestack: ", $body, From 8e87d8a3b50479b9b04b74aba3d6604d41756ebd Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 11 Feb 2020 22:21:38 -0800 Subject: [PATCH 0837/4206] Bump to 0.1.25 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 3203f1c6c026a..d751897099727 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.24" +version = "0.1.25" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From d370d2728bfbf5ea1fcc1437b32a48eb4f0d2855 Mon Sep 17 00:00:00 2001 From: Yuxiang Zhu Date: Wed, 12 Feb 2020 10:44:10 +0800 Subject: [PATCH 0838/4206] add mips/mips64 compiler-rt fallbacks so that libgcc is not required This adds compiler-rt fallbacks for mips and mips64 arches. Solves linking issues like https://github.com/rust-lang/rust/issues/57820. Signed-off-by: Yuxiang Zhu --- .../.github/workflows/main.yml | 4 ++-- library/compiler-builtins/build.rs | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 4691549976487..750f288cf40ec 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -111,8 +111,8 @@ jobs: - run: rustup target add ${{ matrix.target }} - name: Download compiler-rt reference sources run: | - curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/8.0-2019-03-18.tar.gz - tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-8.0-2019-03-18/compiler-rt + curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/10.0-2020-02-05.tar.gz + tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-10.0-2020-02-05/compiler-rt echo "##[set-env name=RUST_COMPILER_RT_ROOT]./compiler-rt" shell: bash diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index b520b62477ed7..b3c65d5b9c6ba 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -396,6 +396,25 @@ mod c { } } + if target_arch == "mips" { + sources.extend(&[("__bswapsi2", "bswapsi2.c")]); + } + + if target_arch == "mips64" { + sources.extend(&[ + ("__extenddftf2", "extenddftf2.c"), + ("__netf2", "comparetf2.c"), + ("__addtf3", "addtf3.c"), + ("__multf3", "multf3.c"), + ("__subtf3", "subtf3.c"), + ("__fixtfsi", "fixtfsi.c"), + ("__floatsitf", "floatsitf.c"), + ("__fixunstfsi", "fixunstfsi.c"), + ("__floatunsitf", "floatunsitf.c"), + ("__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" { let mut to_remove = Vec::new(); From c82ad6a29419c9178410d9f51d565725998f11cd Mon Sep 17 00:00:00 2001 From: Wolfgang Silbermayr Date: Fri, 21 Feb 2020 11:01:50 +0100 Subject: [PATCH 0839/4206] Use lower-case file extension for LICENSE.txt The `LICENSE.txt` file should be distributed to crates.io, but it wasn't due to the `Cargo.toml` entry in the `includes` field being `LICENSE.txt` with lower-case file extension while the file itself had an upper-case extension. --- library/compiler-builtins/{LICENSE.TXT => LICENSE.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename library/compiler-builtins/{LICENSE.TXT => LICENSE.txt} (100%) diff --git a/library/compiler-builtins/LICENSE.TXT b/library/compiler-builtins/LICENSE.txt similarity index 100% rename from library/compiler-builtins/LICENSE.TXT rename to library/compiler-builtins/LICENSE.txt From 569b87d602110e3f620cbeed053cb537420049e6 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Fri, 28 Feb 2020 20:01:22 +0100 Subject: [PATCH 0840/4206] aarch64: Exclude FP intrinsics on +nofp or +nosimd (#344) `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. This patch prepares https://github.com/rust-lang/rust/pull/68334 --- library/compiler-builtins/build.rs | 57 +++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index b520b62477ed7..c4a80223b4745 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -51,7 +51,7 @@ fn main() { // time). This can probably be removed in the future if !target.contains("wasm32") && !target.contains("nvptx") && !target.starts_with("riscv") { #[cfg(feature = "c")] - c::compile(&llvm_target); + c::compile(&llvm_target, &target); } } @@ -121,13 +121,28 @@ mod c { } /// Compile intrinsics from the compiler-rt C source code - pub fn compile(llvm_target: &[&str]) { + pub fn compile(llvm_target: &[&str], target: &String) { let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap(); let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap(); + let mut consider_float_intrinsics = true; let cfg = &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.to_owned().replace("-", "_")); + if let Ok(cflags_value) = env::var(cflags_key) { + if cflags_value.contains("+nofp") || cflags_value.contains("+nosimd") { + consider_float_intrinsics = false; + } + } + } + cfg.warnings(false); if target_env == "msvc" { @@ -166,34 +181,39 @@ mod c { ("__cmpdi2", "cmpdi2.c"), ("__ctzdi2", "ctzdi2.c"), ("__ctzsi2", "ctzsi2.c"), - ("__divdc3", "divdc3.c"), - ("__divsc3", "divsc3.c"), - ("__divxc3", "divxc3.c"), - ("__extendhfsf2", "extendhfsf2.c"), ("__int_util", "int_util.c"), - ("__muldc3", "muldc3.c"), - ("__mulsc3", "mulsc3.c"), ("__mulvdi3", "mulvdi3.c"), ("__mulvsi3", "mulvsi3.c"), - ("__mulxc3", "mulxc3.c"), - ("__negdf2", "negdf2.c"), ("__negdi2", "negdi2.c"), - ("__negsf2", "negsf2.c"), ("__negvdi2", "negvdi2.c"), ("__negvsi2", "negvsi2.c"), ("__paritydi2", "paritydi2.c"), ("__paritysi2", "paritysi2.c"), ("__popcountdi2", "popcountdi2.c"), ("__popcountsi2", "popcountsi2.c"), - ("__powixf2", "powixf2.c"), ("__subvdi3", "subvdi3.c"), ("__subvsi3", "subvsi3.c"), - ("__truncdfhf2", "truncdfhf2.c"), - ("__truncdfsf2", "truncdfsf2.c"), - ("__truncsfhf2", "truncsfhf2.c"), ("__ucmpdi2", "ucmpdi2.c"), ]); + if consider_float_intrinsics { + sources.extend(&[ + ("__divdc3", "divdc3.c"), + ("__divsc3", "divsc3.c"), + ("__divxc3", "divxc3.c"), + ("__extendhfsf2", "extendhfsf2.c"), + ("__muldc3", "muldc3.c"), + ("__mulsc3", "mulsc3.c"), + ("__mulxc3", "mulxc3.c"), + ("__negdf2", "negdf2.c"), + ("__negsf2", "negsf2.c"), + ("__powixf2", "powixf2.c"), + ("__truncdfhf2", "truncdfhf2.c"), + ("__truncdfsf2", "truncdfsf2.c"), + ("__truncsfhf2", "truncsfhf2.c"), + ]); + } + // When compiling in rustbuild (the rust-lang/rust repo) this library // also needs to satisfy intrinsics that jemalloc or C in general may // need, so include a few more that aren't typically needed by @@ -214,12 +234,15 @@ mod c { ("__ffsti2", "ffsti2.c"), ("__mulvti3", "mulvti3.c"), ("__negti2", "negti2.c"), - ("__negvti2", "negvti2.c"), ("__parityti2", "parityti2.c"), ("__popcountti2", "popcountti2.c"), ("__subvti3", "subvti3.c"), ("__ucmpti2", "ucmpti2.c"), ]); + + if consider_float_intrinsics { + sources.extend(&[("__negvti2", "negvti2.c")]); + } } if target_vendor == "apple" { @@ -372,7 +395,7 @@ mod c { ]); } - if target_arch == "aarch64" { + if target_arch == "aarch64" && consider_float_intrinsics { sources.extend(&[ ("__comparetf2", "comparetf2.c"), ("__extenddftf2", "extenddftf2.c"), From fd781d567f9168c2ca2e3c131b4fe446b7a4f31b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 28 Feb 2020 11:01:42 -0800 Subject: [PATCH 0841/4206] Bump to 0.1.26 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index d751897099727..f24093fdfaa66 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.25" +version = "0.1.26" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From ef99c37aae973bbd7d554429ff55552aa69f3d17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sat, 11 Apr 2020 00:00:50 +0200 Subject: [PATCH 0842/4206] Place intrinsics in individual object files (#349) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tomasz Miąsko --- library/compiler-builtins/src/macros.rs | 49 +++++++++++++++++-------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index a86794072c257..b02f3ea5cedbe 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -173,14 +173,12 @@ macro_rules! intrinsics { #[cfg(all(windows, target_arch = "x86_64"))] pub mod $name { - - intrinsics! { - pub extern $abi fn $name( $($argname: $ty),* ) - -> ::macros::win64_128bit_abi_hack::U64x2 - { - let e: $ret = super::$name($($argname),*); - ::macros::win64_128bit_abi_hack::U64x2::from(e) - } + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + pub extern $abi fn $name( $($argname: $ty),* ) + -> ::macros::win64_128bit_abi_hack::U64x2 + { + let e: $ret = super::$name($($argname),*); + ::macros::win64_128bit_abi_hack::U64x2::from(e) } } @@ -209,17 +207,23 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( #[cfg(target_arch = "arm")] - #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } #[cfg(target_arch = "arm")] pub mod $name { - intrinsics! { - pub extern "aapcs" fn $alias( $($argname: $ty),* ) -> $ret { - super::$name($($argname),*) - } + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + super::$name($($argname),*) + } + } + + #[cfg(target_arch = "arm")] + pub mod $alias { + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + pub extern "aapcs" fn $alias( $($argname: $ty),* ) -> $ret { + super::$name($($argname),*) } } @@ -234,9 +238,15 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); - // This is the final catch-all rule. At this point we just generate an + // This is the final catch-all rule. At this point we generate an // intrinsic with a conditional `#[no_mangle]` directive to avoid - // interfereing with duplicate symbols and whatnot during testing. + // interfering with duplicate symbols and whatnot during testing. + // + // The implementation is placed in a separate module, to take advantage + // of the fact that rustc partitions functions into code generation + // units based on module they are defined in. As a result we will have + // a separate object file for each intrinsic. For further details see + // corresponding PR in rustc https://github.com/rust-lang/rust/pull/70846 // // After the intrinsic is defined we just continue with the rest of the // input we were given. @@ -249,11 +259,18 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( $(#[$($attr)*])* - #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { $($body)* } + pub mod $name { + $(#[$($attr)*])* + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + super::$name($($argname),*) + } + } + intrinsics!($($rest)*); ); } From 67ec7e4ccf5b3d04d31a01a95f8e4ca9c5f87733 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 13 Apr 2020 07:17:28 -0700 Subject: [PATCH 0843/4206] Bump to 0.1.27 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index f24093fdfaa66..41b33bf477556 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.26" +version = "0.1.27" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 0e69cc88170728c053a9845730eec6eaaf89531d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 29 Apr 2020 15:30:10 -0500 Subject: [PATCH 0844/4206] Switch to using `llvm_asm!` instead of `asm!` (#351) * Switch to using `llvm_asm!` instead of `asm!` * Run rustfmt * Fix how LTO is specified on nightly --- library/compiler-builtins/ci/run.sh | 6 +- .../compiler-builtins/examples/intrinsics.rs | 4 +- library/compiler-builtins/src/arm.rs | 140 ++++++++++-------- library/compiler-builtins/src/int/mod.rs | 74 ++++----- library/compiler-builtins/src/lib.rs | 2 +- library/compiler-builtins/src/x86.rs | 6 +- library/compiler-builtins/src/x86_64.rs | 6 +- 7 files changed, 128 insertions(+), 110 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index ae32806ece8ea..c4cc6813d599f 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -85,9 +85,11 @@ RUSTFLAGS="-C debug-assertions=no" $build_intrinsics --features c --release if [ -z "$DEBUG_LTO_BUILD_DOESNT_WORK" ]; then RUSTFLAGS="-C debug-assertions=no" \ CARGO_INCREMENTAL=0 \ - $cargo rustc --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics -- -C lto + CARGO_PROFILE_DEV_LTO=true \ + $cargo rustc --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics fi -$cargo rustc --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics --release -- -C lto +CARGO_PROFILE_RELEASE_LTO=true \ + $cargo rustc --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics --release # Ensure no references to a panicking function for rlib in $(echo $path); do diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 5ceebe13216a9..82762e076b1b5 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -6,7 +6,7 @@ #![allow(unused_features)] #![cfg_attr(thumb, no_main)] #![deny(dead_code)] -#![feature(asm)] +#![feature(llvm_asm)] #![feature(lang_items)] #![feature(start)] #![feature(allocator_api)] @@ -280,7 +280,7 @@ fn run() { // A copy of "test::black_box". Used to prevent LLVM from optimizing away the intrinsics during LTO fn bb(dummy: T) -> T { - unsafe { asm!("" : : "r"(&dummy)) } + unsafe { llvm_asm!("" : : "r"(&dummy)) } dummy } diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 4cf73ef37ac04..190bba7262027 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -8,13 +8,15 @@ use core::intrinsics; #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_uidivmod() { - asm!("push {lr} - sub sp, sp, #4 - mov r2, sp - bl __udivmodsi4 - ldr r1, [sp] - add sp, sp, #4 - pop {pc}" ::: "memory" : "volatile"); + llvm_asm!(" + push {lr} + sub sp, sp, #4 + mov r2, sp + bl __udivmodsi4 + ldr r1, [sp] + add sp, sp, #4 + pop {pc} + " ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -22,13 +24,15 @@ pub unsafe fn __aeabi_uidivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_uidivmod() { - asm!("push {lr} - sub sp, sp, #4 - mov r2, sp - bl ___udivmodsi4 - ldr r1, [sp] - add sp, sp, #4 - pop {pc}" ::: "memory" : "volatile"); + llvm_asm!(" + push {lr} + sub sp, sp, #4 + mov r2, sp + bl ___udivmodsi4 + ldr r1, [sp] + add sp, sp, #4 + pop {pc} + " ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -36,15 +40,17 @@ pub unsafe fn __aeabi_uidivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_uldivmod() { - asm!("push {r4, lr} - sub sp, sp, #16 - add r4, sp, #8 - str r4, [sp] - bl __udivmoddi4 - ldr r2, [sp, #8] - ldr r3, [sp, #12] - add sp, sp, #16 - pop {r4, pc}" ::: "memory" : "volatile"); + llvm_asm!(" + push {r4, lr} + sub sp, sp, #16 + add r4, sp, #8 + str r4, [sp] + bl __udivmoddi4 + ldr r2, [sp, #8] + ldr r3, [sp, #12] + add sp, sp, #16 + pop {r4, pc} + " ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -52,15 +58,17 @@ pub unsafe fn __aeabi_uldivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_uldivmod() { - asm!("push {r4, lr} - sub sp, sp, #16 - add r4, sp, #8 - str r4, [sp] - bl ___udivmoddi4 - ldr r2, [sp, #8] - ldr r3, [sp, #12] - add sp, sp, #16 - pop {r4, pc}" ::: "memory" : "volatile"); + llvm_asm!(" + push {r4, lr} + sub sp, sp, #16 + add r4, sp, #8 + str r4, [sp] + bl ___udivmoddi4 + ldr r2, [sp, #8] + ldr r3, [sp, #12] + add sp, sp, #16 + pop {r4, pc} + " ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -68,12 +76,14 @@ pub unsafe fn __aeabi_uldivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_idivmod() { - asm!("push {r0, r1, r4, lr} - bl __aeabi_idiv - pop {r1, r2} - muls r2, r2, r0 - subs r1, r1, r2 - pop {r4, pc}" ::: "memory" : "volatile"); + llvm_asm!(" + push {r0, r1, r4, lr} + bl __aeabi_idiv + pop {r1, r2} + muls r2, r2, r0 + subs r1, r1, r2 + pop {r4, pc} + " ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -81,12 +91,14 @@ pub unsafe fn __aeabi_idivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_idivmod() { - asm!("push {r0, r1, r4, lr} - bl ___aeabi_idiv - pop {r1, r2} - muls r2, r2, r0 - subs r1, r1, r2 - pop {r4, pc}" ::: "memory" : "volatile"); + llvm_asm!(" + push {r0, r1, r4, lr} + bl ___aeabi_idiv + pop {r1, r2} + muls r2, r2, r0 + subs r1, r1, r2 + pop {r4, pc} + " ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -94,15 +106,17 @@ pub unsafe fn __aeabi_idivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_ldivmod() { - asm!("push {r4, lr} - sub sp, sp, #16 - add r4, sp, #8 - str r4, [sp] - bl __divmoddi4 - ldr r2, [sp, #8] - ldr r3, [sp, #12] - add sp, sp, #16 - pop {r4, pc}" ::: "memory" : "volatile"); + llvm_asm!(" + push {r4, lr} + sub sp, sp, #16 + add r4, sp, #8 + str r4, [sp] + bl __divmoddi4 + ldr r2, [sp, #8] + ldr r3, [sp, #12] + add sp, sp, #16 + pop {r4, pc} + " ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -110,15 +124,17 @@ pub unsafe fn __aeabi_ldivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe fn __aeabi_ldivmod() { - asm!("push {r4, lr} - sub sp, sp, #16 - add r4, sp, #8 - str r4, [sp] - bl ___divmoddi4 - ldr r2, [sp, #8] - ldr r3, [sp, #12] - add sp, sp, #16 - pop {r4, pc}" ::: "memory" : "volatile"); + llvm_asm!(" + push {r4, lr} + sub sp, sp, #16 + add r4, sp, #8 + str r4, [sp] + bl ___divmoddi4 + ldr r2, [sp, #8] + ldr r3, [sp, #12] + add sp, sp, #16 + pop {r4, pc} + " ::: "memory" : "volatile"); intrinsics::unreachable(); } diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 7587bc69e7612..80ac4f9faaea8 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -88,55 +88,55 @@ fn unwrap(t: Option) -> T { macro_rules! int_impl_common { ($ty:ty, $bits:expr) => { - const BITS: u32 = $bits; + const BITS: u32 = $bits; - const ZERO: Self = 0; - const ONE: Self = 1; + const ZERO: Self = 0; + const ONE: Self = 1; - fn from_bool(b: bool) -> Self { - b as $ty - } + fn from_bool(b: bool) -> Self { + b as $ty + } - fn max_value() -> Self { - ::max_value() - } + fn max_value() -> Self { + ::max_value() + } - fn min_value() -> Self { - ::min_value() - } + fn min_value() -> Self { + ::min_value() + } - fn wrapping_add(self, other: Self) -> Self { - ::wrapping_add(self, other) - } + fn wrapping_add(self, other: Self) -> Self { + ::wrapping_add(self, other) + } - fn wrapping_mul(self, other: Self) -> Self { - ::wrapping_mul(self, other) - } + fn wrapping_mul(self, other: Self) -> Self { + ::wrapping_mul(self, other) + } - fn wrapping_sub(self, other: Self) -> Self { - ::wrapping_sub(self, other) - } + fn wrapping_sub(self, other: Self) -> Self { + ::wrapping_sub(self, other) + } - fn wrapping_shl(self, other: u32) -> Self { - ::wrapping_shl(self, other) - } + fn wrapping_shl(self, other: u32) -> Self { + ::wrapping_shl(self, other) + } - fn overflowing_add(self, other: Self) -> (Self, bool) { - ::overflowing_add(self, other) - } + fn overflowing_add(self, other: Self) -> (Self, bool) { + ::overflowing_add(self, other) + } - fn aborting_div(self, other: Self) -> Self { - unwrap(::checked_div(self, other)) - } + fn aborting_div(self, other: Self) -> Self { + unwrap(::checked_div(self, other)) + } - fn aborting_rem(self, other: Self) -> Self { - unwrap(::checked_rem(self, other)) - } + fn aborting_rem(self, other: Self) -> Self { + unwrap(::checked_rem(self, other)) + } - fn leading_zeros(self) -> u32 { - ::leading_zeros(self) - } - } + fn leading_zeros(self) -> u32 { + ::leading_zeros(self) + } + }; } macro_rules! int_impl { diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index e57a5ef3f8748..0ca770b1e78cb 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,6 +1,6 @@ #![cfg_attr(feature = "compiler-builtins", compiler_builtins)] #![feature(abi_unadjusted)] -#![feature(asm)] +#![feature(llvm_asm)] #![feature(global_asm)] #![feature(cfg_target_has_atomic)] #![feature(compiler_builtins)] diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs index 035c0a31c4167..5511c4572e528 100644 --- a/library/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/src/x86.rs @@ -12,7 +12,7 @@ use core::intrinsics; #[naked] #[no_mangle] pub unsafe fn ___chkstk_ms() { - asm!(" + llvm_asm!(" push %ecx push %eax cmp $$0x1000,%eax @@ -38,7 +38,7 @@ pub unsafe fn ___chkstk_ms() { #[naked] #[no_mangle] pub unsafe fn __alloca() { - asm!("jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable" + llvm_asm!("jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable" ::: "memory" : "volatile"); intrinsics::unreachable(); } @@ -47,7 +47,7 @@ pub unsafe fn __alloca() { #[naked] #[no_mangle] pub unsafe fn ___chkstk() { - asm!(" + llvm_asm!(" push %ecx cmp $$0x1000,%eax lea 8(%esp),%ecx // esp before calling this routine -> ecx diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 6940f8d9d2910..6a0cd56687348 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -12,7 +12,7 @@ use core::intrinsics; #[naked] #[no_mangle] pub unsafe fn ___chkstk_ms() { - asm!(" + llvm_asm!(" push %rcx push %rax cmp $$0x1000,%rax @@ -37,7 +37,7 @@ pub unsafe fn ___chkstk_ms() { #[naked] #[no_mangle] pub unsafe fn __alloca() { - asm!("mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx + llvm_asm!("mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable" ::: "memory" : "volatile"); intrinsics::unreachable(); @@ -47,7 +47,7 @@ pub unsafe fn __alloca() { #[naked] #[no_mangle] pub unsafe fn ___chkstk() { - asm!( + llvm_asm!( " push %rcx cmp $$0x1000,%rax From 5c41a11e62acf7b1687f8d237546c7e0a0bee3bf Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 11 May 2020 22:29:49 -0700 Subject: [PATCH 0845/4206] Bump to 0.1.28 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 41b33bf477556..75a7e1e93ae27 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.27" +version = "0.1.28" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From a2840567da837b1a9ff24befa13cf33f8d31fc85 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 22 May 2020 14:12:06 -0700 Subject: [PATCH 0846/4206] Add more targets to automatically select `mem` feature. (#357) --- library/compiler-builtins/build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index c4a80223b4745..abeac9bf1ecd5 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -27,6 +27,8 @@ fn main() { // provide them. if (target.contains("wasm32") && !target.contains("wasi")) || (target.contains("sgx") && target.contains("fortanix")) + || target.contains("-none") + || target.contains("nvptx") { println!("cargo:rustc-cfg=feature=\"mem\""); } From ca827eb2348cb83ccb26fa9403a6f11cb3d668ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Tue, 26 May 2020 22:12:10 +0200 Subject: [PATCH 0847/4206] Use crate visibility for traits (#358) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tomasz Miąsko --- library/compiler-builtins/src/float/mod.rs | 2 +- library/compiler-builtins/src/int/mod.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 8b8039452a74c..06e9aad4b4263 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -13,7 +13,7 @@ pub mod pow; pub mod sub; /// Trait for some basic operations on floats -pub trait Float: +pub(crate) trait Float: Copy + PartialEq + PartialOrd diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 80ac4f9faaea8..d73bf6db995c7 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -19,7 +19,7 @@ pub mod shift; pub mod udiv; /// Trait for some basic operations on integers -pub trait Int: +pub(crate) trait Int: Copy + PartialEq + PartialOrd @@ -190,7 +190,7 @@ int_impl!(i64, u64, 64); int_impl!(i128, u128, 128); /// Trait to convert an integer to/from smaller parts -pub trait LargeInt: Int { +pub(crate) trait LargeInt: Int { type LowHalf: Int; type HighHalf: Int; @@ -232,7 +232,7 @@ large_int!(u128, u64, u64, 64); large_int!(i128, u64, i64, 64); /// Trait to express (possibly lossy) casting of integers -pub trait CastInto: Copy { +pub(crate) trait CastInto: Copy { fn cast(self) -> T; } @@ -256,7 +256,7 @@ cast_into!(i64); cast_into!(u128); cast_into!(i128); -pub trait WideInt: Int { +pub(crate) trait WideInt: Int { type Output: Int; fn wide_mul(self, other: Self) -> (Self, Self); From a0f9847f1d202313068846c68936c772bbfd74c4 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 26 May 2020 13:12:24 -0700 Subject: [PATCH 0848/4206] Bump to 0.1.29 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 75a7e1e93ae27..7c6f4bdb7040a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.28" +version = "0.1.29" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 72b440075ea3abee81d2ce0682386e65ab98a6bd Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 29 May 2020 14:16:51 -0500 Subject: [PATCH 0849/4206] Use macros for more division/array checks (#244) * Use macros for more division/array checks This commit moves over more array accesses to the `i!` macro to avoid bounds checks when debug assertions are disabled. This is surfaced from rust-lang/compiler-builtins#360 where recent changes in codegen units has caused some bounds checks to not get elided in release mode. This also adds a `div!` macro to work around rust-lang/rust#72751. * Don't test/bench our shim crate It's not intended to run all our tests --- .../compiler-builtins-smoke-test/Cargo.toml | 5 ++++- library/compiler-builtins/libm/src/lib.rs | 5 +---- .../compiler-builtins/libm/src/math/atanf.rs | 8 ++++---- library/compiler-builtins/libm/src/math/exp.rs | 2 +- .../compiler-builtins/libm/src/math/exp2.rs | 6 +++--- .../compiler-builtins/libm/src/math/exp2f.rs | 2 +- .../compiler-builtins/libm/src/math/expf.rs | 2 +- library/compiler-builtins/libm/src/math/mod.rs | 18 ++++++++++++++++++ library/compiler-builtins/libm/src/math/pow.rs | 12 ++++++------ .../compiler-builtins/libm/src/math/powf.rs | 12 ++++++------ .../libm/src/math/rem_pio2.rs | 12 ++++++------ .../libm/src/math/rem_pio2_large.rs | 4 ++-- 12 files changed, 53 insertions(+), 35 deletions(-) diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index 40e75dd22fd19..ac192a9132f71 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -3,4 +3,7 @@ name = "cb" version = "0.1.0" authors = ["Jorge Aparicio "] -[dependencies] +[lib] +test = false +bench = false + diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index e228af9b3333d..bbc79ecad56f7 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -1,10 +1,7 @@ //! libm in pure Rust #![deny(warnings)] #![no_std] -#![cfg_attr( - all(target_arch = "wasm32", feature = "unstable"), - feature(core_intrinsics) -)] +#![cfg_attr(all(feature = "unstable"), feature(core_intrinsics))] #![allow(clippy::unreadable_literal)] #![allow(clippy::many_single_char_names)] #![allow(clippy::needless_return)] diff --git a/library/compiler-builtins/libm/src/math/atanf.rs b/library/compiler-builtins/libm/src/math/atanf.rs index 73f3352e9eccd..d042b3bc0fd91 100644 --- a/library/compiler-builtins/libm/src/math/atanf.rs +++ b/library/compiler-builtins/libm/src/math/atanf.rs @@ -56,7 +56,7 @@ pub fn atanf(mut x: f32) -> f32 { if x.is_nan() { return x; } - z = ATAN_HI[3] + x1p_120; + z = i!(ATAN_HI, 3) + x1p_120; return if sign { -z } else { z }; } let id = if ix < 0x3ee00000 { @@ -97,13 +97,13 @@ pub fn atanf(mut x: f32) -> f32 { z = x * x; let w = z * z; /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ - let s1 = z * (A_T[0] + w * (A_T[2] + w * A_T[4])); - let s2 = w * (A_T[1] + w * A_T[3]); + let s1 = z * (i!(A_T, 0) + w * (i!(A_T, 2) + w * i!(A_T, 4))); + let s2 = w * (i!(A_T, 1) + w * i!(A_T, 3)); if id < 0 { return x - x * (s1 + s2); } let id = id as usize; - let z = ATAN_HI[id] - ((x * (s1 + s2) - ATAN_LO[id]) - x); + let z = i!(ATAN_HI, id) - ((x * (s1 + s2) - i!(ATAN_LO, id)) - x); if sign { -z } else { diff --git a/library/compiler-builtins/libm/src/math/exp.rs b/library/compiler-builtins/libm/src/math/exp.rs index 5b163f95427c3..d4994277f8954 100644 --- a/library/compiler-builtins/libm/src/math/exp.rs +++ b/library/compiler-builtins/libm/src/math/exp.rs @@ -124,7 +124,7 @@ pub fn exp(mut x: f64) -> f64 { /* if |x| > 0.5 ln2 */ if hx >= 0x3ff0a2b2 { /* if |x| >= 1.5 ln2 */ - k = (INVLN2 * x + HALF[sign as usize]) as i32; + k = (INVLN2 * x + i!(HALF, sign as usize)) as i32; } else { k = 1 - sign - sign; } diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs index 8ea434dcadbd3..e0e385df2e702 100644 --- a/library/compiler-builtins/libm/src/math/exp2.rs +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -374,14 +374,14 @@ pub fn exp2(mut x: f64) -> f64 { let mut i0 = ui as u32; i0 = i0.wrapping_add(TBLSIZE as u32 / 2); let ku = i0 / TBLSIZE as u32 * TBLSIZE as u32; - let ki = ku as i32 / TBLSIZE as i32; + let ki = div!(ku as i32, TBLSIZE as i32); i0 %= TBLSIZE as u32; let uf = f64::from_bits(ui) - redux; let mut z = x - uf; /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ - let t = f64::from_bits(TBL[2 * i0 as usize]); /* exp2t[i0] */ - z -= f64::from_bits(TBL[2 * i0 as usize + 1]); /* eps[i0] */ + let t = f64::from_bits(i!(TBL, 2 * i0 as usize)); /* exp2t[i0] */ + z -= f64::from_bits(i!(TBL, 2 * i0 as usize + 1)); /* eps[i0] */ let r = t + t * z * (p1 + z * (p2 + z * (p3 + z * (p4 + z * p5)))); scalbn(r, ki) diff --git a/library/compiler-builtins/libm/src/math/exp2f.rs b/library/compiler-builtins/libm/src/math/exp2f.rs index 8a890b832e92c..f4867b80eedb5 100644 --- a/library/compiler-builtins/libm/src/math/exp2f.rs +++ b/library/compiler-builtins/libm/src/math/exp2f.rs @@ -126,7 +126,7 @@ pub fn exp2f(mut x: f32) -> f32 { uf -= redux; let z: f64 = (x - uf) as f64; /* Compute r = exp2(y) = exp2ft[i0] * p(z). */ - let r: f64 = f64::from_bits(EXP2FT[i0 as usize]); + let r: f64 = f64::from_bits(i!(EXP2FT, i0 as usize)); let t: f64 = r as f64 * z; let r: f64 = r + t * (p1 as f64 + z * p2 as f64) + t * (z * z) * (p3 as f64 + z * p4 as f64); diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs index 47c1b2c467ec0..a53aa90a646a9 100644 --- a/library/compiler-builtins/libm/src/math/expf.rs +++ b/library/compiler-builtins/libm/src/math/expf.rs @@ -70,7 +70,7 @@ pub fn expf(mut x: f32) -> f32 { /* if |x| > 0.5 ln2 */ if hx > 0x3f851592 { /* if |x| > 1.5 ln2 */ - k = (INV_LN2 * x + HALF[sign as usize]) as i32; + k = (INV_LN2 * x + i!(HALF, sign as usize)) as i32; } else { k = 1 - sign - sign; } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index c8d7bd8194df6..ceeee0b31fb15 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -58,6 +58,24 @@ macro_rules! i { }; } +// Temporary macro to avoid panic codegen for division (in debug mode too). At +// the time of this writing this is only used in a few places, and once +// rust-lang/rust#72751 is fixed then this macro will no longer be necessary and +// the native `/` operator can be used and panics won't be codegen'd. +#[cfg(any(debug_assertions, not(feature = "unstable")))] +macro_rules! div { + ($a:expr, $b:expr) => { + $a / $b + }; +} + +#[cfg(all(not(debug_assertions), feature = "unstable"))] +macro_rules! div { + ($a:expr, $b:expr) => { + unsafe { core::intrinsics::unchecked_div($a, $b) } + }; +} + macro_rules! llvm_intrinsically_optimized { (#[cfg($($clause:tt)*)] $e:expr) => { #[cfg(all(feature = "unstable", $($clause)*))] diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index ce8e83ee6f8e9..c7fd0dfa11760 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -299,8 +299,8 @@ pub fn pow(x: f64, y: f64) -> f64 { ax = with_set_high_word(ax, ix as u32); /* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */ - let u: f64 = ax - BP[k as usize]; /* bp[0]=1.0, bp[1]=1.5 */ - let v: f64 = 1.0 / (ax + BP[k as usize]); + let u: f64 = ax - i!(BP, k as usize); /* bp[0]=1.0, bp[1]=1.5 */ + let v: f64 = 1.0 / (ax + i!(BP, k as usize)); let ss: f64 = u * v; let s_h = with_set_low_word(ss, 0); @@ -309,7 +309,7 @@ pub fn pow(x: f64, y: f64) -> f64 { 0.0, ((ix as u32 >> 1) | 0x20000000) + 0x00080000 + ((k as u32) << 18), ); - let t_l: f64 = ax - (t_h - BP[k as usize]); + let t_l: f64 = ax - (t_h - i!(BP, k as usize)); let s_l: f64 = v * ((u - s_h * t_h) - s_h * t_l); /* compute log(ax) */ @@ -328,12 +328,12 @@ pub fn pow(x: f64, y: f64) -> f64 { let p_h: f64 = with_set_low_word(u + v, 0); let p_l = v - (p_h - u); let z_h: f64 = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ - let z_l: f64 = CP_L * p_h + p_l * CP + DP_L[k as usize]; + let z_l: f64 = CP_L * p_h + p_l * CP + i!(DP_L, k as usize); /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ let t: f64 = n as f64; - t1 = with_set_low_word(((z_h + z_l) + DP_H[k as usize]) + t, 0); - t2 = z_l - (((t1 - t) - DP_H[k as usize]) - z_h); + t1 = with_set_low_word(((z_h + z_l) + i!(DP_H, k as usize)) + t, 0); + t2 = z_l - (((t1 - t) - i!(DP_H, k as usize)) - z_h); } /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs index f3cf76f9aa6ea..68d2083bbdd79 100644 --- a/library/compiler-builtins/libm/src/math/powf.rs +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -238,8 +238,8 @@ pub fn powf(x: f32, y: f32) -> f32 { ax = f32::from_bits(ix as u32); /* compute s = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */ - u = ax - BP[k as usize]; /* bp[0]=1.0, bp[1]=1.5 */ - v = 1.0 / (ax + BP[k as usize]); + u = ax - i!(BP, k as usize); /* bp[0]=1.0, bp[1]=1.5 */ + v = 1.0 / (ax + i!(BP, k as usize)); s = u * v; s_h = s; is = s_h.to_bits() as i32; @@ -247,7 +247,7 @@ pub fn powf(x: f32, y: f32) -> f32 { /* t_h=ax+bp[k] High */ is = (((ix as u32 >> 1) & 0xfffff000) | 0x20000000) as i32; t_h = f32::from_bits(is as u32 + 0x00400000 + ((k as u32) << 21)); - t_l = ax - (t_h - BP[k as usize]); + t_l = ax - (t_h - i!(BP, k as usize)); s_l = v * ((u - s_h * t_h) - s_h * t_l); /* compute log(ax) */ s2 = s * s; @@ -267,13 +267,13 @@ pub fn powf(x: f32, y: f32) -> f32 { p_h = f32::from_bits(is as u32 & 0xfffff000); p_l = v - (p_h - u); z_h = CP_H * p_h; /* cp_h+cp_l = 2/(3*log2) */ - z_l = CP_L * p_h + p_l * CP + DP_L[k as usize]; + z_l = CP_L * p_h + p_l * CP + i!(DP_L, k as usize); /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ t = n as f32; - t1 = ((z_h + z_l) + DP_H[k as usize]) + t; + t1 = ((z_h + z_l) + i!(DP_H, k as usize)) + t; is = t1.to_bits() as i32; t1 = f32::from_bits(is as u32 & 0xfffff000); - t2 = z_l - (((t1 - t) - DP_H[k as usize]) - z_h); + t2 = z_l - (((t1 - t) - i!(DP_H, k as usize)) - z_h); }; /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 6b7dbd348c6cd..46f7c38ffedab 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -167,21 +167,21 @@ pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { let mut z = f64::from_bits(ui); let mut tx = [0.0; 3]; for i in 0..2 { - tx[i] = z as i32 as f64; - z = (z - tx[i]) * x1p24; + i!(tx,i, =, z as i32 as f64); + z = (z - i!(tx, i)) * x1p24; } - tx[2] = z; + i!(tx,2, =, z); /* skip zero terms, first term is non-zero */ let mut i = 2; - while i != 0 && tx[i] == 0.0 { + while i != 0 && i!(tx, i) == 0.0 { i -= 1; } let mut ty = [0.0; 3]; let n = rem_pio2_large(&tx[..=i], &mut ty, ((ix as i32) >> 20) - (0x3ff + 23), 1); if sign != 0 { - return (-n, -ty[0], -ty[1]); + return (-n, -i!(ty, 0), -i!(ty, 1)); } - (n, ty[0], ty[1]) + (n, i!(ty, 0), i!(ty, 1)) } #[cfg(test)] 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 002ce2e211f2c..65473f0abdadd 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -242,12 +242,12 @@ pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> let mut iq: [i32; 20] = [0; 20]; /* initialize jk*/ - let jk = INIT_JK[prec]; + let jk = i!(INIT_JK, prec); let jp = jk; /* determine jx,jv,q0, note that 3>q0 */ let jx = nx - 1; - let mut jv = (e0 - 3) / 24; + let mut jv = div!(e0 - 3, 24); if jv < 0 { jv = 0; } From 63982a3b9e3d8844d98447a474ca94eb1d9f0b0f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 29 May 2020 14:38:29 -0500 Subject: [PATCH 0850/4206] Expand wasm32 testing on CI (#360) * Expand wasm32 testing on CI Run the full `run.sh` test script to get full assertions, including that nothing in the wasm compiler-builtins is panicking. Unfortunately it's currently panicking, so this is good to weed out! * Update libm --- .../.github/workflows/main.yml | 31 ++----------------- .../docker/wasm32-unknown-unknown/Dockerfile | 6 ++++ library/compiler-builtins/ci/run.sh | 10 +++--- .../compiler-builtins/examples/intrinsics.rs | 6 ++-- library/compiler-builtins/libm | 2 +- library/compiler-builtins/src/lib.rs | 2 +- 6 files changed, 19 insertions(+), 38 deletions(-) create mode 100644 library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 4691549976487..25ab1b30a7ef3 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -7,30 +7,6 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - target: - - aarch64-unknown-linux-gnu - - arm-unknown-linux-gnueabi - - arm-unknown-linux-gnueabihf - - i586-unknown-linux-gnu - - i686-unknown-linux-gnu - - mips-unknown-linux-gnu - - mips64-unknown-linux-gnuabi64 - - mips64el-unknown-linux-gnuabi64 - - mipsel-unknown-linux-gnu - - powerpc-unknown-linux-gnu - - powerpc64-unknown-linux-gnu - - powerpc64le-unknown-linux-gnu - - thumbv6m-none-eabi - - thumbv7em-none-eabi - - thumbv7em-none-eabihf - - thumbv7m-none-eabi - - wasm32-unknown-unknown - - x86_64-unknown-linux-gnu - - x86_64-apple-darwin - - i686-pc-windows-msvc - - x86_64-pc-windows-msvc - - i686-pc-windows-gnu - - x86_64-pc-windows-gnu include: - target: aarch64-unknown-linux-gnu os: ubuntu-latest @@ -109,6 +85,7 @@ jobs: run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }} shell: bash - run: rustup target add ${{ matrix.target }} + - run: rustup component add llvm-tools-preview - name: Download compiler-rt reference sources run: | curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/8.0-2019-03-18.tar.gz @@ -121,13 +98,9 @@ jobs: if: matrix.os != 'ubuntu-latest' shell: bash - # Wasm is special and is just build as a smoke test - - run: cargo build --target ${{ matrix.target }} - if: matrix.target == 'wasm32-unknown-unknown' - # Otherwise we use our docker containers to run builds - run: cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} - if: matrix.target != 'wasm32-unknown-unknown' && matrix.os == 'ubuntu-latest' + if: matrix.os == 'ubuntu-latest' rustfmt: name: Rustfmt diff --git a/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile b/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile new file mode 100644 index 0000000000000..758d94d5013be --- /dev/null +++ b/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile @@ -0,0 +1,6 @@ +FROM ubuntu:20.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates + +ENV CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER=true diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index c4cc6813d599f..3c9dc0247e69a 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -32,7 +32,10 @@ case $1 in ;; esac -NM=nm +NM=$(find $(rustc --print sysroot) -name llvm-nm) +if [ "$NM" = "" ]; then + NM=${PREFIX}nm +fi if [ -d /target ]; then path=/target/${1}/debug/deps/libcompiler_builtins-*.rlib @@ -47,8 +50,7 @@ for rlib in $(echo $path); do echo checking $rlib for duplicate symbols echo "================================================================" - stdout=$($PREFIX$NM -g --defined-only $rlib 2>&1) - + stdout=$($NM -g --defined-only $rlib 2>&1) # NOTE On i586, It's normal that the get_pc_thunk symbol appears several # times so ignore it # @@ -94,7 +96,7 @@ CARGO_PROFILE_RELEASE_LTO=true \ # Ensure no references to a panicking function for rlib in $(echo $path); do set +ex - $PREFIX$NM -u $rlib 2>&1 | grep panicking + $NM -u $rlib 2>&1 | grep panicking if test $? = 0; then exit 1 diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 82762e076b1b5..519cea2ae0ee2 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -14,7 +14,7 @@ extern crate panic_handler; -#[cfg(all(not(thumb), not(windows)))] +#[cfg(all(not(thumb), not(windows), not(target_arch = "wasm32")))] #[link(name = "c")] extern "C" {} @@ -340,11 +340,11 @@ fn run() { something_with_a_dtor(&|| assert_eq!(bb(1), 1)); extern "C" { - fn rust_begin_unwind(); + fn rust_begin_unwind(x: usize); } // if bb(false) { unsafe { - rust_begin_unwind(); + rust_begin_unwind(0); } // } } diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 8eedc2470531f..fe396e00b7e47 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 8eedc2470531f51b978e4c873ee78a33c90e0fbd +Subproject commit fe396e00b7e47821a81c4c87a481ddc6af1d2cdf diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 0ca770b1e78cb..564988654f7e7 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -31,7 +31,7 @@ extern crate core; fn abort() -> ! { - unsafe { core::intrinsics::abort() } + core::intrinsics::abort() } #[macro_use] From 843c2261a9f918e59b5e14874a62a89473534cc1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 29 May 2020 13:41:09 -0700 Subject: [PATCH 0851/4206] Bump to 0.1.30 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 7c6f4bdb7040a..0e9778e40909e 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.29" +version = "0.1.30" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From e4293adbe151dad5264844c9cc3ef1c808e0c5ce Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 29 May 2020 13:43:21 -0700 Subject: [PATCH 0852/4206] Add back in unsafe for bootstrapping And add an `#[allow]` for now to appease stage0 --- library/compiler-builtins/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 564988654f7e7..db05af5de340a 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -30,8 +30,9 @@ #[cfg(test)] extern crate core; +#[allow(unused_unsafe)] fn abort() -> ! { - core::intrinsics::abort() + unsafe { core::intrinsics::abort() } } #[macro_use] From d1e1f04686c88ce03d0ed297d5ed6bca4f2f6a6a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 29 May 2020 13:43:57 -0700 Subject: [PATCH 0853/4206] Bump to 0.1.31 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 0e9778e40909e..9a5f9984d4e40 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.30" +version = "0.1.31" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 96e3a08719d3da905aa4307b09b9cd82910b7a3a Mon Sep 17 00:00:00 2001 From: jethrogb Date: Mon, 1 Jun 2020 17:55:42 +0200 Subject: [PATCH 0854/4206] Manually patch ret instruction for LVI (#359) Co-authored-by: Jethro Beekman --- library/compiler-builtins/src/probestack.rs | 70 ++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 19307df4e936b..9c78faa1d238c 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -109,7 +109,12 @@ macro_rules! define_rust_probestack { // // The ABI here is that the stack frame size is located in `%rax`. Upon // return we're not supposed to modify `%rsp` or `%rax`. -#[cfg(target_arch = "x86_64")] +// +// Any changes to this function should be replicated to the SGX version below. +#[cfg(all( + target_arch = "x86_64", + not(all(target_env = "sgx", target_vendor = "fortanix")) +))] global_asm!(define_rust_probestack!( " .cfi_startproc @@ -163,6 +168,69 @@ global_asm!(define_rust_probestack!( " )); +// This function is the same as above, except that some instructions are +// [manually patched for LVI]. +// +// [manually patched for LVI]: https://software.intel.com/security-software-guidance/insights/deep-dive-load-value-injection#specialinstructions +#[cfg(all( + target_arch = "x86_64", + all(target_env = "sgx", target_vendor = "fortanix") +))] +global_asm!(define_rust_probestack!( + " + .cfi_startproc + pushq %rbp + .cfi_adjust_cfa_offset 8 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + + mov %rax,%r11 // duplicate %rax as we're clobbering %r11 + + // Main loop, taken in one page increments. We're decrementing rsp by + // a page each time until there's less than a page remaining. We're + // guaranteed that this function isn't called unless there's more than a + // page needed. + // + // Note that we're also testing against `8(%rsp)` to account for the 8 + // bytes pushed on the stack orginally with our return address. Using + // `8(%rsp)` simulates us testing the stack pointer in the caller's + // context. + + // It's usually called when %rax >= 0x1000, but that's not always true. + // Dynamic stack allocation, which is needed to implement unsized + // rvalues, triggers stackprobe even if %rax < 0x1000. + // Thus we have to check %r11 first to avoid segfault. + cmp $0x1000,%r11 + jna 3f +2: + sub $0x1000,%rsp + test %rsp,8(%rsp) + sub $0x1000,%r11 + cmp $0x1000,%r11 + ja 2b + +3: + // Finish up the last remaining stack space requested, getting the last + // bits out of r11 + sub %r11,%rsp + test %rsp,8(%rsp) + + // Restore the stack pointer to what it previously was when entering + // this function. The caller will readjust the stack pointer after we + // return. + add %rax,%rsp + + leave + .cfi_def_cfa_register %rsp + .cfi_adjust_cfa_offset -8 + pop %r11 + lfence + jmp *%r11 + .cfi_endproc + " +)); + #[cfg(target_arch = "x86")] // This is the same as x86_64 above, only translated for 32-bit sizes. Note // that on Unix we're expected to restore everything as it was, this From 4e71b65530f084cc5041b16fdb6f03e863444bbf Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 1 Jun 2020 08:56:11 -0700 Subject: [PATCH 0855/4206] Bump to 0.1.32 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 9a5f9984d4e40..d4d1ad67d3840 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.31" +version = "0.1.32" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 2b0d14c89ef923287e900843746c9f5f3242e4bf Mon Sep 17 00:00:00 2001 From: kellda <59569234+kellda@users.noreply.github.com> Date: Mon, 8 Jun 2020 16:11:11 +0200 Subject: [PATCH 0856/4206] Update CHANGELOG.md (#245) --- library/compiler-builtins/libm/CHANGELOG.md | 28 ++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index 28e27055dfd3e..e8e9acf9b5c09 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -7,6 +7,30 @@ This project adheres to [Semantic Versioning](http://semver.org/). ... +## [v0.2.1] - 2019-11-22 + +### Fixed +- sincosf + +## [v0.2.0] - 2019-10-18 + +### Added +- Benchmarks +- signum +- remainder +- remainderf +- nextafter +- nextafterf + +### Fixed +- Rounding to negative zero +- Overflows in rem_pio2 and remquo +- Overflows in fma +- sincosf + +### Removed +- F32Ext and F64Ext traits + ## [v0.1.4] - 2019-06-12 ### Fixed @@ -90,7 +114,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Initial release -[Unreleased]: https://github.com/japaric/libm/compare/v0.1.4...HEAD +[Unreleased]: https://github.com/japaric/libm/compare/v0.2.1...HEAD +[v0.2.1]: https://github.com/japaric/libm/compare/0.2.0...v0.2.1 +[v0.2.0]: https://github.com/japaric/libm/compare/0.1.4...v0.2.0 [v0.1.4]: https://github.com/japaric/libm/compare/0.1.3...v0.1.4 [v0.1.3]: https://github.com/japaric/libm/compare/v0.1.2...0.1.3 [v0.1.2]: https://github.com/japaric/libm/compare/v0.1.1...v0.1.2 From d59b2875b57f406c3152b45c6f0abb3c794f0949 Mon Sep 17 00:00:00 2001 From: Joseph Richey Date: Wed, 8 Jul 2020 07:07:19 -0700 Subject: [PATCH 0857/4206] lint: Allow improper_ctypes_definitions (#364) https://github.com/rust-lang/rust/pull/72700 caused the existing `allow(improper_ctypes)` guard to stop working, we now need `allow(improper_ctypes_definitions)` instead. We keep the old one to avoid any issues with older nightlies. Signed-off-by: Joe Richey --- library/compiler-builtins/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index db05af5de340a..34397e0d2564e 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -15,7 +15,7 @@ // We use `u128` in a whole bunch of places which we currently agree with the // compiler on ABIs and such, so we should be "good enough" for now and changes // to the `u128` ABI will be reflected here. -#![allow(improper_ctypes)] +#![allow(improper_ctypes, improper_ctypes_definitions)] // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. From 7652f288d3a14ca5f5f4940387b48fb802dd614e Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Tue, 28 Jul 2020 13:09:18 -0500 Subject: [PATCH 0858/4206] Improve `__clzsi2` performance (#366) --- .../src/int/leading_zeros.rs | 143 ++++++++++++++++++ library/compiler-builtins/src/int/mod.rs | 69 +-------- .../compiler-builtins/testcrate/Cargo.toml | 6 + .../testcrate/tests/count_leading_zeros.rs | 23 --- .../testcrate/tests/leading_zeros.rs | 54 +++++++ 5 files changed, 206 insertions(+), 89 deletions(-) create mode 100644 library/compiler-builtins/src/int/leading_zeros.rs delete mode 100644 library/compiler-builtins/testcrate/tests/count_leading_zeros.rs create mode 100644 library/compiler-builtins/testcrate/tests/leading_zeros.rs diff --git a/library/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/src/int/leading_zeros.rs new file mode 100644 index 0000000000000..78556f0bcf639 --- /dev/null +++ b/library/compiler-builtins/src/int/leading_zeros.rs @@ -0,0 +1,143 @@ +// Note: these functions happen to produce the correct `usize::leading_zeros(0)` value +// without a explicit zero check. Zero is probably common enough that it could warrant +// adding a zero check at the beginning, but `__clzsi2` has a precondition that `x != 0`. +// Compilers will insert the check for zero in cases where it is needed. + +/// Returns the number of leading binary zeros in `x`. +pub fn usize_leading_zeros_default(x: usize) -> usize { + // The basic idea is to test if the higher bits of `x` are zero and bisect the number + // of leading zeros. It is possible for all branches of the bisection to use the same + // code path by conditionally shifting the higher parts down to let the next bisection + // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` + // and adding to the number of zeros, it is slightly faster to start with + // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, + // because it simplifies the final bisection step. + let mut x = x; + // the number of potential leading zeros + let mut z = usize::MAX.count_ones() as usize; + // a temporary + let mut t: usize; + #[cfg(target_pointer_width = "64")] + { + t = x >> 32; + if t != 0 { + z -= 32; + x = t; + } + } + #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] + { + t = x >> 16; + if t != 0 { + z -= 16; + x = t; + } + } + t = x >> 8; + if t != 0 { + z -= 8; + x = t; + } + t = x >> 4; + if t != 0 { + z -= 4; + x = t; + } + t = x >> 2; + if t != 0 { + z -= 2; + x = t; + } + // the last two bisections are combined into one conditional + t = x >> 1; + if t != 0 { + z - 2 + } else { + z - x + } + + // We could potentially save a few cycles by using the LUT trick from + // "https://embeddedgurus.com/state-space/2014/09/+%20%20%20%20//%20fast-deterministic-and-portable-counting-leading-zeros/". + // However, 256 bytes for a LUT is too large for embedded use cases. We could remove + // the last 3 bisections and use this 16 byte LUT for the rest of the work: + //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; + //z -= LUT[x] as usize; + //z + // However, it ends up generating about the same number of instructions. When benchmarked + // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO + // execution effects. Changing to using a LUT and branching is risky for smaller cores. +} + +// The above method does not compile well on RISC-V (because of the lack of predicated +// instructions), producing code with many branches or using an excessively long +// branchless solution. This method takes advantage of the set-if-less-than instruction on +// RISC-V that allows `(x >= power-of-two) as usize` to be branchless. + +/// Returns the number of leading binary zeros in `x`. +pub fn usize_leading_zeros_riscv(x: usize) -> usize { + let mut x = x; + // the number of potential leading zeros + let mut z = usize::MAX.count_ones() as usize; + // a temporary + let mut t: usize; + + // RISC-V does not have a set-if-greater-than-or-equal instruction and + // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is + // still the most optimal method. A conditional set can only be turned into a single + // immediate instruction if `x` is compared with an immediate `imm` (that can fit into + // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the + // right). If we try to save an instruction by using `x < imm` for each bisection, we + // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, + // but the immediate will never fit into 12 bits and never save an instruction. + #[cfg(target_pointer_width = "64")] + { + // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise + // `t` is set to 0. + t = ((x >= (1 << 32)) as usize) << 5; + // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the + // next step to process. + x >>= t; + // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential + // leading zeros + z -= t; + } + #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] + { + t = ((x >= (1 << 16)) as usize) << 4; + x >>= t; + z -= t; + } + t = ((x >= (1 << 8)) as usize) << 3; + x >>= t; + z -= t; + t = ((x >= (1 << 4)) as usize) << 2; + x >>= t; + z -= t; + t = ((x >= (1 << 2)) as usize) << 1; + x >>= t; + z -= t; + t = (x >= (1 << 1)) as usize; + x >>= t; + z -= t; + // All bits except the LSB are guaranteed to be zero for this final bisection step. + // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. + z - x +} + +intrinsics! { + #[maybe_use_optimized_c_shim] + #[cfg(any( + target_pointer_width = "16", + target_pointer_width = "32", + target_pointer_width = "64" + ))] + /// Returns the number of leading binary zeros in `x`. + pub extern "C" fn __clzsi2(x: usize) -> usize { + if cfg!(any(target_arch = "riscv32", target_arch = "riscv64")) { + usize_leading_zeros_riscv(x) + } else { + usize_leading_zeros_default(x) + } + } +} diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index d73bf6db995c7..8a469d901472b 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -13,11 +13,14 @@ macro_rules! os_ty { } pub mod addsub; +pub mod leading_zeros; pub mod mul; pub mod sdiv; pub mod shift; pub mod udiv; +pub use self::leading_zeros::__clzsi2; + /// Trait for some basic operations on integers pub(crate) trait Int: Copy @@ -300,69 +303,3 @@ macro_rules! impl_wide_int { impl_wide_int!(u32, u64, 32); impl_wide_int!(u64, u128, 64); - -intrinsics! { - #[maybe_use_optimized_c_shim] - #[cfg(any( - target_pointer_width = "16", - target_pointer_width = "32", - target_pointer_width = "64" - ))] - pub extern "C" fn __clzsi2(x: usize) -> usize { - // TODO: const this? Would require const-if - // Note(Lokathor): the `intrinsics!` macro can't process mut inputs - let mut x = x; - let mut y: usize; - let mut n: usize = { - #[cfg(target_pointer_width = "64")] - { - 64 - } - #[cfg(target_pointer_width = "32")] - { - 32 - } - #[cfg(target_pointer_width = "16")] - { - 16 - } - }; - #[cfg(target_pointer_width = "64")] - { - y = x >> 32; - if y != 0 { - n -= 32; - x = y; - } - } - #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] - { - y = x >> 16; - if y != 0 { - n -= 16; - x = y; - } - } - y = x >> 8; - if y != 0 { - n -= 8; - x = y; - } - y = x >> 4; - if y != 0 { - n -= 4; - x = y; - } - y = x >> 2; - if y != 0 { - n -= 2; - x = y; - } - y = x >> 1; - if y != 0 { - n - 2 - } else { - n - x - } - } -} diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 3b99b574ef20c..61282af0bf500 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -11,6 +11,12 @@ doctest = false [build-dependencies] rand = "0.7" +[dev-dependencies] +# 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. +# `xoshiro128**` is used for its quality, size, and speed at generating `u32` shift amounts. +rand_xoshiro = "0.4" + [dependencies.compiler_builtins] path = ".." default-features = false diff --git a/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs b/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs deleted file mode 100644 index 022b2d8529367..0000000000000 --- a/library/compiler-builtins/testcrate/tests/count_leading_zeros.rs +++ /dev/null @@ -1,23 +0,0 @@ -extern crate compiler_builtins; - -use compiler_builtins::int::__clzsi2; - -#[test] -fn __clzsi2_test() { - let mut i: usize = core::usize::MAX; - // Check all values above 0 - while i > 0 { - assert_eq!(__clzsi2(i) as u32, i.leading_zeros()); - i >>= 1; - } - // check 0 also - i = 0; - assert_eq!(__clzsi2(i) as u32, i.leading_zeros()); - // double check for bit patterns that aren't just solid 1s - i = 1; - for _ in 0..63 { - assert_eq!(__clzsi2(i) as u32, i.leading_zeros()); - i <<= 2; - i += 1; - } -} diff --git a/library/compiler-builtins/testcrate/tests/leading_zeros.rs b/library/compiler-builtins/testcrate/tests/leading_zeros.rs new file mode 100644 index 0000000000000..b857d9e0c31b1 --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/leading_zeros.rs @@ -0,0 +1,54 @@ +use rand_xoshiro::rand_core::{RngCore, SeedableRng}; +use rand_xoshiro::Xoshiro128StarStar; + +use compiler_builtins::int::__clzsi2; +use compiler_builtins::int::leading_zeros::{ + usize_leading_zeros_default, usize_leading_zeros_riscv, +}; + +#[test] +fn __clzsi2_test() { + // Binary fuzzer. We cannot just send a random number directly to `__clzsi2()`, because we need + // large sequences of zeros to test. This XORs, ANDs, and ORs random length strings of 1s to + // `x`. ORs insure sequences of ones, ANDs insures sequences of zeros, and XORs are not often + // destructive but add entropy. + let mut rng = Xoshiro128StarStar::seed_from_u64(0); + let mut x = 0usize; + // creates a mask for indexing the bits of the type + let bit_indexing_mask = usize::MAX.count_ones() - 1; + // 10000 iterations is enough to make sure edge cases like single set bits are tested and to go + // through many paths. + for _ in 0..10_000 { + let r0 = bit_indexing_mask & rng.next_u32(); + // random length of ones + let ones: usize = !0 >> r0; + let r1 = bit_indexing_mask & rng.next_u32(); + // random circular shift + let mask = ones.rotate_left(r1); + match rng.next_u32() % 4 { + 0 => x |= mask, + 1 => x &= mask, + // both 2 and 3 to make XORs as common as ORs and ANDs combined + _ => x ^= mask, + } + let lz = x.leading_zeros() as usize; + let lz0 = __clzsi2(x); + let lz1 = usize_leading_zeros_default(x); + let lz2 = usize_leading_zeros_riscv(x); + if lz0 != lz { + panic!("__clzsi2({}): expected: {}, found: {}", x, lz, lz0); + } + if lz1 != lz { + panic!( + "usize_leading_zeros_default({}): expected: {}, found: {}", + x, lz, lz1 + ); + } + if lz2 != lz { + panic!( + "usize_leading_zeros_riscv({}): expected: {}, found: {}", + x, lz, lz2 + ); + } + } +} From 981e803acd1ef2f54bdc0e431e47f9b5f4b66cd1 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Sun, 3 May 2020 22:38:04 -0500 Subject: [PATCH 0859/4206] regularize the location and documentation of division functions --- library/compiler-builtins/src/int/sdiv.rs | 44 ++++++++++++++--------- library/compiler-builtins/src/int/udiv.rs | 14 ++++---- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index c9e252cc3b0e5..854ea00bbd813 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -60,42 +60,52 @@ impl Divmod for i64 {} intrinsics! { #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_idiv] + /// Returns `n / d` pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 { a.div(b) } #[maybe_use_optimized_c_shim] - pub extern "C" fn __divdi3(a: i64, b: i64) -> i64 { - a.div(b) + /// Returns `n % d` + pub extern "C" fn __modsi3(a: i32, b: i32) -> i32 { + a.mod_(b) } - - #[win64_128bit_abi_hack] - pub extern "C" fn __divti3(a: i128, b: i128) -> i128 { - a.div(b) + + #[maybe_use_optimized_c_shim] + /// Returns `n / d` and sets `*rem = n % d` + pub extern "C" fn __divmodsi4(a: i32, b: i32, rem: &mut i32) -> i32 { + a.divmod(b, rem, |a, b| __divsi3(a, b)) } #[maybe_use_optimized_c_shim] - pub extern "C" fn __modsi3(a: i32, b: i32) -> i32 { - a.mod_(b) + /// Returns `n / d` + pub extern "C" fn __divdi3(a: i64, b: i64) -> i64 { + a.div(b) } #[maybe_use_optimized_c_shim] + /// Returns `n % d` pub extern "C" fn __moddi3(a: i64, b: i64) -> i64 { a.mod_(b) } - #[win64_128bit_abi_hack] - pub extern "C" fn __modti3(a: i128, b: i128) -> i128 { - a.mod_(b) + #[aapcs_on_arm] + /// Returns `n / d` and sets `*rem = n % d` + pub extern "C" fn __divmoddi4(a: i64, b: i64, rem: &mut i64) -> i64 { + a.divmod(b, rem, |a, b| __divdi3(a, b)) } - #[maybe_use_optimized_c_shim] - pub extern "C" fn __divmodsi4(a: i32, b: i32, rem: &mut i32) -> i32 { - a.divmod(b, rem, |a, b| __divsi3(a, b)) + #[win64_128bit_abi_hack] + /// Returns `n / d` + pub extern "C" fn __divti3(a: i128, b: i128) -> i128 { + a.div(b) } - #[aapcs_on_arm] - pub extern "C" fn __divmoddi4(a: i64, b: i64, rem: &mut i64) -> i64 { - a.divmod(b, rem, |a, b| __divdi3(a, b)) + #[win64_128bit_abi_hack] + /// Returns `n % d` + pub extern "C" fn __modti3(a: i128, b: i128) -> i128 { + a.mod_(b) } + + // LLVM does not currently have a `__divmodti4` function } diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index b393ac6db1282..1ee670c72abd1 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -241,6 +241,11 @@ intrinsics! { rem } + /// Returns `n / d` and sets `*rem = n % d` + pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { + udivmod_inner!(n, d, rem, u64) + } + #[win64_128bit_abi_hack] /// Returns `n / d` pub extern "C" fn __udivti3(n: u128, d: u128) -> u128 { @@ -255,16 +260,9 @@ intrinsics! { rem } - /// Returns `n / d` and sets `*rem = n % d` - pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { - udivmod_inner!(n, d, rem, u64) - } - #[win64_128bit_abi_hack] /// Returns `n / d` and sets `*rem = n % d` - pub extern "C" fn __udivmodti4(n: u128, - d: u128, - rem: Option<&mut u128>) -> u128 { + pub extern "C" fn __udivmodti4(n: u128, d: u128, rem: Option<&mut u128>) -> u128 { udivmod_inner!(n, d, rem, u128) } } From 3fda53a90d048fe9b2220817e502f2ccb02b5d98 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Sun, 3 May 2020 22:40:54 -0500 Subject: [PATCH 0860/4206] replace old soft division code with new functions --- library/compiler-builtins/src/int/sdiv.rs | 23 +++--- library/compiler-builtins/src/int/udiv.rs | 86 +++++------------------ 2 files changed, 33 insertions(+), 76 deletions(-) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 854ea00bbd813..983c34cf36d36 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -57,54 +57,59 @@ trait Divmod: Int { impl Divmod for i32 {} impl Divmod for i64 {} + intrinsics! { #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_idiv] /// Returns `n / d` pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 { - a.div(b) + i32_div_rem(a, b).0 } #[maybe_use_optimized_c_shim] /// Returns `n % d` pub extern "C" fn __modsi3(a: i32, b: i32) -> i32 { - a.mod_(b) + i32_div_rem(a, b).1 } - + #[maybe_use_optimized_c_shim] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __divmodsi4(a: i32, b: i32, rem: &mut i32) -> i32 { - a.divmod(b, rem, |a, b| __divsi3(a, b)) + let quo_rem = i32_div_rem(a, b); + *rem = quo_rem.1; + quo_rem.0 } #[maybe_use_optimized_c_shim] /// Returns `n / d` pub extern "C" fn __divdi3(a: i64, b: i64) -> i64 { - a.div(b) + i64_div_rem(a, b).0 } #[maybe_use_optimized_c_shim] /// Returns `n % d` pub extern "C" fn __moddi3(a: i64, b: i64) -> i64 { - a.mod_(b) + i64_div_rem(a, b).1 } #[aapcs_on_arm] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __divmoddi4(a: i64, b: i64, rem: &mut i64) -> i64 { - a.divmod(b, rem, |a, b| __divdi3(a, b)) + let quo_rem = i64_div_rem(a, b); + *rem = quo_rem.1; + quo_rem.0 } #[win64_128bit_abi_hack] /// Returns `n / d` pub extern "C" fn __divti3(a: i128, b: i128) -> i128 { - a.div(b) + i128_div_rem(a, b).0 } #[win64_128bit_abi_hack] /// Returns `n % d` pub extern "C" fn __modti3(a: i128, b: i128) -> i128 { - a.mod_(b) + i128_div_rem(a, b).1 } // LLVM does not currently have a `__divmodti4` function diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 1ee670c72abd1..b312ca48b049f 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -156,113 +156,65 @@ intrinsics! { #[arm_aeabi_alias = __aeabi_uidiv] /// Returns `n / d` pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 { - // Special cases - if d == 0 { - // NOTE This should be unreachable in safe Rust because the program will panic before - // this intrinsic is called - ::abort(); - } - - if n == 0 { - return 0; - } - - let mut sr = d.leading_zeros().wrapping_sub(n.leading_zeros()); - - // d > n - if sr > u32::BITS - 1 { - return 0; - } - - // d == 1 - if sr == u32::BITS - 1 { - return n; - } - - sr += 1; - - // 1 <= sr <= u32::BITS - 1 - let mut q = n << (u32::BITS - sr); - let mut r = n >> sr; - - let mut carry = 0; - - // Don't use a range because they may generate references to memcpy in unoptimized code - let mut i = 0; - while i < sr { - i += 1; - - // r:q = ((r:q) << 1) | carry - r = (r << 1) | (q >> (u32::BITS - 1)); - q = (q << 1) | carry; - - // carry = 0; - // if r > d { - // r -= d; - // carry = 1; - // } - - let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32::BITS - 1); - carry = (s & 1) as u32; - r -= d & s as u32; - } - - (q << 1) | carry + u32_div_rem(n, d).0 } #[maybe_use_optimized_c_shim] /// Returns `n % d` pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { - let q = __udivsi3(n, d); - n - q * d + u32_div_rem(n, d).1 } #[maybe_use_optimized_c_shim] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { - let q = __udivsi3(n, d); + let quo_rem = u32_div_rem(n, d); if let Some(rem) = rem { - *rem = n - (q * d); + *rem = quo_rem.1; } - q + quo_rem.0 } #[maybe_use_optimized_c_shim] /// Returns `n / d` pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { - __udivmoddi4(n, d, None) + u64_div_rem(n, d).0 } #[maybe_use_optimized_c_shim] /// Returns `n % d` pub extern "C" fn __umoddi3(n: u64, d: u64) -> u64 { - let mut rem = 0; - __udivmoddi4(n, d, Some(&mut rem)); - rem + u64_div_rem(n, d).1 } /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { - udivmod_inner!(n, d, rem, u64) + let quo_rem = u64_div_rem(n, d); + if let Some(rem) = rem { + *rem = quo_rem.1; + } + quo_rem.0 } #[win64_128bit_abi_hack] /// Returns `n / d` pub extern "C" fn __udivti3(n: u128, d: u128) -> u128 { - __udivmodti4(n, d, None) + u128_div_rem(n, d).0 } #[win64_128bit_abi_hack] /// Returns `n % d` pub extern "C" fn __umodti3(n: u128, d: u128) -> u128 { - let mut rem = 0; - __udivmodti4(n, d, Some(&mut rem)); - rem + u128_div_rem(n, d).1 } #[win64_128bit_abi_hack] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmodti4(n: u128, d: u128, rem: Option<&mut u128>) -> u128 { - udivmod_inner!(n, d, rem, u128) + let quo_rem = u128_div_rem(n, d); + if let Some(rem) = rem { + *rem = quo_rem.1; + } + quo_rem.0 } } From adbc0b24c55f75c53289ebc6b2fe641f28b2b202 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Sun, 19 Jul 2020 17:15:50 -0500 Subject: [PATCH 0861/4206] Remove erroneous `aapcs_on_arm` and add `maybe_use_optimized_c_shim` --- library/compiler-builtins/src/int/sdiv.rs | 2 +- library/compiler-builtins/src/int/udiv.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 983c34cf36d36..682ebeda21cfc 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -92,7 +92,7 @@ intrinsics! { i64_div_rem(a, b).1 } - #[aapcs_on_arm] + #[maybe_use_optimized_c_shim] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __divmoddi4(a: i64, b: i64, rem: &mut i64) -> i64 { let quo_rem = i64_div_rem(a, b); diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index b312ca48b049f..e517ca862d0fd 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -187,6 +187,7 @@ intrinsics! { u64_div_rem(n, d).1 } + #[maybe_use_optimized_c_shim] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { let quo_rem = u64_div_rem(n, d); From 5386117b974ccd468aa13b87acea7b6a0f2b9c46 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Fri, 17 Jul 2020 15:17:40 -0500 Subject: [PATCH 0862/4206] Remove unused code --- library/compiler-builtins/src/int/mod.rs | 12 -- library/compiler-builtins/src/int/sdiv.rs | 58 --------- library/compiler-builtins/src/int/udiv.rs | 151 ---------------------- 3 files changed, 221 deletions(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 8a469d901472b..7bafb82f88416 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -1,17 +1,5 @@ use core::ops; -macro_rules! hty { - ($ty:ty) => { - <$ty as LargeInt>::HighHalf - }; -} - -macro_rules! os_ty { - ($ty:ty) => { - <$ty as Int>::OtherSign - }; -} - pub mod addsub; pub mod leading_zeros; pub mod mul; diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 682ebeda21cfc..d8bb9c0939cde 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -1,63 +1,5 @@ use int::Int; -trait Div: Int { - /// Returns `a / b` - fn div(self, other: Self) -> Self { - let s_a = self >> (Self::BITS - 1); - let s_b = other >> (Self::BITS - 1); - // NOTE it's OK to overflow here because of the `.unsigned()` below. - // This whole operation is computing the absolute value of the inputs - // So some overflow will happen when dealing with e.g. `i64::MIN` - // where the absolute value is `(-i64::MIN) as u64` - let a = (self ^ s_a).wrapping_sub(s_a); - let b = (other ^ s_b).wrapping_sub(s_b); - let s = s_a ^ s_b; - - let r = a.unsigned().aborting_div(b.unsigned()); - (Self::from_unsigned(r) ^ s) - s - } -} - -impl Div for i32 {} -impl Div for i64 {} -impl Div for i128 {} - -trait Mod: Int { - /// Returns `a % b` - fn mod_(self, other: Self) -> Self { - let s = other >> (Self::BITS - 1); - // NOTE(wrapping_sub) see comment in the `div` - let b = (other ^ s).wrapping_sub(s); - let s = self >> (Self::BITS - 1); - let a = (self ^ s).wrapping_sub(s); - - let r = a.unsigned().aborting_rem(b.unsigned()); - (Self::from_unsigned(r) ^ s) - s - } -} - -impl Mod for i32 {} -impl Mod for i64 {} -impl Mod for i128 {} - -trait Divmod: Int { - /// Returns `a / b` and sets `*rem = n % d` - fn divmod(self, other: Self, rem: &mut Self, div: F) -> Self - where - F: Fn(Self, Self) -> Self, - { - let r = div(self, other); - // NOTE won't overflow because it's using the result from the - // previous division - *rem = self - r.wrapping_mul(other); - r - } -} - -impl Divmod for i32 {} -impl Divmod for i64 {} - - intrinsics! { #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_idiv] diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index e517ca862d0fd..49151594964e1 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -1,156 +1,5 @@ use int::{Int, LargeInt}; -macro_rules! udivmod_inner { - ($n:expr, $d:expr, $rem:expr, $ty:ty) => {{ - let (n, d, rem) = ($n, $d, $rem); - // NOTE X is unknown, K != 0 - if n.high() == 0 { - if d.high() == 0 { - // 0 X - // --- - // 0 X - - if let Some(rem) = rem { - *rem = <$ty>::from(n.low().aborting_rem(d.low())); - } - return <$ty>::from(n.low().aborting_div(d.low())) - } else { - // 0 X - // --- - // K X - if let Some(rem) = rem { - *rem = n; - } - return 0; - }; - } - - let mut sr; - let mut q; - let mut r; - - if d.low() == 0 { - if d.high() == 0 { - // K X - // --- - // 0 0 - // NOTE This should be unreachable in safe Rust because the program will panic before - // this intrinsic is called - ::abort(); - } - - if n.low() == 0 { - // K 0 - // --- - // K 0 - if let Some(rem) = rem { - *rem = <$ty>::from_parts(0, n.high().aborting_rem(d.high())); - } - return <$ty>::from(n.high().aborting_div(d.high())) - } - - // K K - // --- - // K 0 - - if d.high().is_power_of_two() { - if let Some(rem) = rem { - *rem = <$ty>::from_parts(n.low(), n.high() & (d.high() - 1)); - } - return <$ty>::from(n.high() >> d.high().trailing_zeros()); - } - - sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); - - // D > N - if sr > ::BITS - 2 { - if let Some(rem) = rem { - *rem = n; - } - return 0; - } - - sr += 1; - - // 1 <= sr <= ::BITS - 1 - q = n << (<$ty>::BITS - sr); - r = n >> sr; - } else if d.high() == 0 { - // K X - // --- - // 0 K - if d.low().is_power_of_two() { - if let Some(rem) = rem { - *rem = <$ty>::from(n.low() & (d.low() - 1)); - } - - if d.low() == 1 { - return n; - } else { - let sr = d.low().trailing_zeros(); - return n >> sr; - }; - } - - sr = 1 + ::BITS + d.low().leading_zeros() - n.high().leading_zeros(); - - // 2 <= sr <= u64::BITS - 1 - q = n << (<$ty>::BITS - sr); - r = n >> sr; - } else { - // K X - // --- - // K K - sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); - - // D > N - if sr > ::BITS - 1 { - if let Some(rem) = rem { - *rem = n; - } - return 0; - } - - sr += 1; - - // 1 <= sr <= ::BITS - q = n << (<$ty>::BITS - sr); - r = n >> sr; - } - - // Not a special case - // q and r are initialized with - // q = n << (u64::BITS - sr) - // r = n >> sr - // 1 <= sr <= u64::BITS - 1 - let mut carry = 0; - - // Don't use a range because they may generate references to memcpy in unoptimized code - let mut i = 0; - while i < sr { - i += 1; - - // r:q = ((r:q) << 1) | carry - r = (r << 1) | (q >> (<$ty>::BITS - 1)); - q = (q << 1) | carry as $ty; - - // carry = 0 - // if r >= d { - // r -= d; - // carry = 1; - // } - let s = (d.wrapping_sub(r).wrapping_sub(1)) as os_ty!($ty) >> (<$ty>::BITS - 1); - carry = (s & 1) as hty!($ty); - r -= d & s as $ty; - } - - if let Some(rem) = rem { - *rem = r; - } - (q << 1) | carry as $ty - }} -} - intrinsics! { #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_uidiv] From 66f5688d608274e5ea266c754ef4c660974498ad Mon Sep 17 00:00:00 2001 From: Max Audron Date: Thu, 13 Aug 2020 12:46:28 +0200 Subject: [PATCH 0863/4206] add 32 bit shift instructions * add 32 bit shift instructions to src/int/shift.rs __ashlsi3 __ashrsi3 __lshrsi3 * add int_impl! for 16 bit numbers and large_int! for i32 and u32 * add tests in testcrate/build.rs --- library/compiler-builtins/src/int/mod.rs | 3 +++ library/compiler-builtins/src/int/shift.rs | 18 ++++++++++++++++++ library/compiler-builtins/testcrate/build.rs | 13 +++++++++++++ 3 files changed, 34 insertions(+) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 8a469d901472b..128fdfdc563aa 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -188,6 +188,7 @@ macro_rules! int_impl { }; } +int_impl!(i16, u16, 16); int_impl!(i32, u32, 32); int_impl!(i64, u64, 64); int_impl!(i128, u128, 128); @@ -229,6 +230,8 @@ macro_rules! large_int { }; } +large_int!(u32, u16, u16, 16); +large_int!(i32, u16, i16, 16); large_int!(u64, u32, u32, 32); large_int!(i64, u32, i32, 32); large_int!(u128, u64, u64, 64); diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 408f8f3ccbb77..674c3ee8ca7d2 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -20,6 +20,7 @@ trait Ashl: Int + LargeInt { } } +impl Ashl for u32 {} impl Ashl for u64 {} impl Ashl for u128 {} @@ -47,6 +48,7 @@ trait Ashr: Int + LargeInt { } } +impl Ashr for i32 {} impl Ashr for i64 {} impl Ashr for i128 {} @@ -70,10 +72,16 @@ trait Lshr: Int + LargeInt { } } +impl Lshr for u32 {} impl Lshr for u64 {} impl Lshr for u128 {} intrinsics! { + #[maybe_use_optimized_c_shim] + pub extern "C" fn __ashlsi3(a: u32, b: u32) -> u32 { + a.ashl(b) + } + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_llsl] pub extern "C" fn __ashldi3(a: u64, b: u32) -> u64 { @@ -84,6 +92,11 @@ intrinsics! { a.ashl(b) } + #[maybe_use_optimized_c_shim] + pub extern "C" fn __ashrsi3(a: i32, b: u32) -> i32 { + a.ashr(b) + } + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_lasr] pub extern "C" fn __ashrdi3(a: i64, b: u32) -> i64 { @@ -94,6 +107,11 @@ intrinsics! { a.ashr(b) } + #[maybe_use_optimized_c_shim] + pub extern "C" fn __lshrsi3(a: u32, b: u32) -> u32 { + a.lshr(b) + } + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_llsr] pub extern "C" fn __lshrdi3(a: u64, b: u32) -> u64 { diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index e1d4cf9e818c3..5a91a120ab81c 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -857,6 +857,10 @@ fn main() { ); // int/shift.rs + gen( + |(a, b): (MyU32, MyU32)| Some(a.0 << (b.0 % 32)), + "builtins::int::shift::__ashlsi3(a, b % 32)", + ); gen( |(a, b): (MyU64, MyU32)| Some(a.0 << (b.0 % 64)), "builtins::int::shift::__ashldi3(a, b % 64)", @@ -865,6 +869,10 @@ fn main() { |(a, b): (MyU128, MyU32)| Some(a.0 << (b.0 % 128)), "builtins::int::shift::__ashlti3(a, b % 128)", ); + gen( + |(a, b): (MyI32, MyU32)| Some(a.0 >> (b.0 % 32)), + "builtins::int::shift::__ashrsi3(a, b % 32)", + ); gen( |(a, b): (MyI64, MyU32)| Some(a.0 >> (b.0 % 64)), "builtins::int::shift::__ashrdi3(a, b % 64)", @@ -873,6 +881,10 @@ fn main() { |(a, b): (MyI128, MyU32)| Some(a.0 >> (b.0 % 128)), "builtins::int::shift::__ashrti3(a, b % 128)", ); + gen( + |(a, b): (MyU32, MyU32)| Some(a.0 >> (b.0 % 32)), + "builtins::int::shift::__lshrsi3(a, b % 32)", + ); gen( |(a, b): (MyU64, MyU32)| Some(a.0 >> (b.0 % 64)), "builtins::int::shift::__lshrdi3(a, b % 64)", @@ -1285,6 +1297,7 @@ my_integer! { struct MyI32(i32); struct MyI64(i64); struct MyI128(i128); + struct MyU16(u16); struct MyU32(u32); struct MyU64(u64); struct MyU128(u128); From 0a957ae73a50eeb135688d0574b064d6f5abf883 Mon Sep 17 00:00:00 2001 From: Xiaoyu Lu Date: Fri, 14 Aug 2020 10:28:15 +0800 Subject: [PATCH 0864/4206] Add uefi arch x86 probestack support 1. In UEFI x86 arch, probestack need triple underscore. 2. In UEFI, probestack function do things like _chkstk(in MSVC). MSVC x32's _chkstk and cygwin/mingw's _alloca adjust %esp themselves MSVC x64's __chkstk and cygwin/mingw's ___chkstk_ms do not adjust %rsp themselves. But current probestack doesn't adjust esp. And LLVM doesn't generate sub %eax, %esp after probestack. So we adjust esp in probestack like MSVC x32's _chkstk. --- library/compiler-builtins/src/probestack.rs | 68 ++++++++++++++++++++- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 9c78faa1d238c..2f37a104ecee8 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -76,7 +76,7 @@ macro_rules! define_rust_probestack { }; } -#[cfg(target_os = "uefi")] +#[cfg(all(target_os = "uefi", target_arch = "x86_64"))] macro_rules! define_rust_probestack { ($body: expr) => { concat!( @@ -104,6 +104,20 @@ macro_rules! define_rust_probestack { }; } +// In UEFI x86 arch, triple underscore is deliberate. +#[cfg(all(target_os = "uefi", target_arch = "x86"))] +macro_rules! define_rust_probestack { + ($body: expr) => { + concat!( + " + .globl ___rust_probestack + ___rust_probestack: + ", + $body + ) + }; +} + // Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax, // ensuring that if any pages are unmapped we'll make a page fault. // @@ -231,7 +245,7 @@ global_asm!(define_rust_probestack!( " )); -#[cfg(target_arch = "x86")] +#[cfg(all(target_arch = "x86", not(target_os = "uefi")))] // This is the same as x86_64 above, only translated for 32-bit sizes. Note // that on Unix we're expected to restore everything as it was, this // function basically can't tamper with anything. @@ -270,3 +284,53 @@ global_asm!(define_rust_probestack!( .cfi_endproc " )); + +#[cfg(all(target_arch = "x86", target_os = "uefi"))] +// UEFI target is windows like target. LLVM will do _chkstk things like windows. +// probestack function will also do things like _chkstk in MSVC. +// So we need to sub %ax %sp in probestack when arch is x86. +// +// REF: Rust commit(74e80468347) +// rust\src\llvm-project\llvm\lib\Target\X86\X86FrameLowering.cpp: 805 +// Comments in LLVM: +// MSVC x32's _chkstk and cygwin/mingw's _alloca adjust %esp themselves. +// MSVC x64's __chkstk and cygwin/mingw's ___chkstk_ms do not adjust %rsp +// themselves. +global_asm!(define_rust_probestack!( + " + .cfi_startproc + push %ebp + .cfi_adjust_cfa_offset 4 + .cfi_offset %ebp, -8 + mov %esp, %ebp + .cfi_def_cfa_register %ebp + push %ecx + push %edx + mov %eax,%ecx + + cmp $0x1000,%ecx + jna 3f +2: + sub $0x1000,%esp + test %esp,8(%esp) + sub $0x1000,%ecx + cmp $0x1000,%ecx + ja 2b + +3: + sub %ecx,%esp + test %esp,8(%esp) + mov 4(%ebp),%edx + mov %edx, 12(%esp) + add %eax,%esp + pop %edx + pop %ecx + leave + + sub %eax, %esp + .cfi_def_cfa_register %esp + .cfi_adjust_cfa_offset -4 + ret + .cfi_endproc + " +)); From d1c867333293af83237afd547bde2ead334cb5e0 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Sat, 11 Jul 2020 12:15:10 -0500 Subject: [PATCH 0865/4206] Use `specialized-div-rem` 1.0.0 for division algorithms --- library/compiler-builtins/Cargo.toml | 4 + library/compiler-builtins/src/int/mod.rs | 2 + library/compiler-builtins/src/int/sdiv.rs | 2 +- .../src/int/specialized_div_rem/asymmetric.rs | 169 +++++ .../int/specialized_div_rem/binary_long.rs | 596 ++++++++++++++++++ .../src/int/specialized_div_rem/delegate.rs | 226 +++++++ .../src/int/specialized_div_rem/mod.rs | 295 +++++++++ .../src/int/specialized_div_rem/norm_shift.rs | 106 ++++ .../src/int/specialized_div_rem/trifecta.rs | 441 +++++++++++++ library/compiler-builtins/src/int/udiv.rs | 2 +- library/compiler-builtins/src/lib.rs | 1 + .../compiler-builtins/testcrate/Cargo.toml | 3 +- .../testcrate/tests/div_rem.rs | 143 +++++ 13 files changed, 1987 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs create mode 100644 library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs create mode 100644 library/compiler-builtins/src/int/specialized_div_rem/delegate.rs create mode 100644 library/compiler-builtins/src/int/specialized_div_rem/mod.rs create mode 100644 library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs create mode 100644 library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs create mode 100644 library/compiler-builtins/testcrate/tests/div_rem.rs diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index d4d1ad67d3840..353d9a73755ce 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -40,6 +40,10 @@ panic-handler = { path = 'crates/panic-handler' } [features] default = ["compiler-builtins"] +# Some algorithms benefit from inline assembly, but some compiler backends do +# not support it, so inline assembly is only enabled when this flag is set. +asm = [] + # Enable compilation of C code in compiler-rt, filling in some more optimized # implementations and also filling in unimplemented intrinsics c = ["cc"] diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 7bafb82f88416..5cfad1d6ccc31 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -1,5 +1,7 @@ use core::ops; +mod specialized_div_rem; + pub mod addsub; pub mod leading_zeros; pub mod mul; diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index d8bb9c0939cde..57ef03cdaa502 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -1,4 +1,4 @@ -use int::Int; +use int::specialized_div_rem::*; intrinsics! { #[maybe_use_optimized_c_shim] diff --git a/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs b/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs new file mode 100644 index 0000000000000..861e917426732 --- /dev/null +++ b/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs @@ -0,0 +1,169 @@ +/// Creates unsigned and signed division functions optimized for dividing integers with the same +/// bitwidth as the largest operand in an asymmetrically sized division. For example, x86-64 has an +/// assembly instruction that can divide a 128 bit integer by a 64 bit integer if the quotient fits +/// in 64 bits. The 128 bit version of this algorithm would use that fast hardware division to +/// construct a full 128 bit by 128 bit division. +#[macro_export] +macro_rules! impl_asymmetric { + ( + $unsigned_name:ident, // name of the unsigned division function + $signed_name:ident, // name of the signed division function + $zero_div_fn:ident, // function called when division by zero is attempted + $half_division:ident, // function for division of a $uX by a $uX + $asymmetric_division:ident, // function for division of a $uD by a $uX + $n_h:expr, // the number of bits in a $iH or $uH + $uH:ident, // unsigned integer with half the bit width of $uX + $uX:ident, // unsigned integer with half the bit width of $uD + $uD:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` + $iD:ident, // signed integer type for the inputs and outputs of `$signed_name` + $($unsigned_attr:meta),*; // attributes for the unsigned function + $($signed_attr:meta),* // attributes for the signed function + ) => { + /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a + /// tuple. + $( + #[$unsigned_attr] + )* + pub fn $unsigned_name(duo: $uD, div: $uD) -> ($uD,$uD) { + fn carrying_mul(lhs: $uX, rhs: $uX) -> ($uX, $uX) { + let tmp = (lhs as $uD).wrapping_mul(rhs as $uD); + (tmp as $uX, (tmp >> ($n_h * 2)) as $uX) + } + fn carrying_mul_add(lhs: $uX, mul: $uX, add: $uX) -> ($uX, $uX) { + let tmp = (lhs as $uD).wrapping_mul(mul as $uD).wrapping_add(add as $uD); + (tmp as $uX, (tmp >> ($n_h * 2)) as $uX) + } + + let n: u32 = $n_h * 2; + + // Many of these subalgorithms are taken from trifecta.rs, see that for better + // documentation. + + let duo_lo = duo as $uX; + let duo_hi = (duo >> n) as $uX; + let div_lo = div as $uX; + let div_hi = (div >> n) as $uX; + if div_hi == 0 { + if div_lo == 0 { + $zero_div_fn() + } + if duo_hi < div_lo { + // `$uD` by `$uX` division with a quotient that will fit into a `$uX` + let (quo, rem) = unsafe { $asymmetric_division(duo, div_lo) }; + return (quo as $uD, rem as $uD) + } else if (div_lo >> $n_h) == 0 { + // Short division of $uD by a $uH. + + // Some x86_64 CPUs have bad division implementations that make specializing + // this case faster. + let div_0 = div_lo as $uH as $uX; + let (quo_hi, rem_3) = $half_division(duo_hi, div_0); + + let duo_mid = + ((duo >> $n_h) as $uH as $uX) + | (rem_3 << $n_h); + let (quo_1, rem_2) = $half_division(duo_mid, div_0); + + let duo_lo = + (duo as $uH as $uX) + | (rem_2 << $n_h); + let (quo_0, rem_1) = $half_division(duo_lo, div_0); + + return ( + (quo_0 as $uD) + | ((quo_1 as $uD) << $n_h) + | ((quo_hi as $uD) << n), + rem_1 as $uD + ) + } else { + // Short division using the $uD by $uX division + let (quo_hi, rem_hi) = $half_division(duo_hi, div_lo); + let tmp = unsafe { + $asymmetric_division((duo_lo as $uD) | ((rem_hi as $uD) << n), div_lo) + }; + return ((tmp.0 as $uD) | ((quo_hi as $uD) << n), tmp.1 as $uD) + } + } + + let duo_lz = duo_hi.leading_zeros(); + let div_lz = div_hi.leading_zeros(); + let rel_leading_sb = div_lz.wrapping_sub(duo_lz); + if rel_leading_sb < $n_h { + // Some x86_64 CPUs have bad hardware division implementations that make putting + // a two possibility algorithm here beneficial. We also avoid a full `$uD` + // multiplication. + let shift = n - duo_lz; + let duo_sig_n = (duo >> shift) as $uX; + let div_sig_n = (div >> shift) as $uX; + let quo = $half_division(duo_sig_n, div_sig_n).0; + let div_lo = div as $uX; + let div_hi = (div >> n) as $uX; + let (tmp_lo, carry) = carrying_mul(quo, div_lo); + let (tmp_hi, overflow) = carrying_mul_add(quo, div_hi, carry); + let tmp = (tmp_lo as $uD) | ((tmp_hi as $uD) << n); + if (overflow != 0) || (duo < tmp) { + return ( + (quo - 1) as $uD, + duo.wrapping_add(div).wrapping_sub(tmp) + ) + } else { + return ( + quo as $uD, + duo - tmp + ) + } + } else { + // This has been adapted from + // https://www.codeproject.com/tips/785014/uint-division-modulus which was in turn + // adapted from Hacker's Delight. This is similar to the two possibility algorithm + // in that it uses only more significant parts of `duo` and `div` to divide a large + // integer with a smaller division instruction. + + let div_extra = n - div_lz; + let div_sig_n = (div >> div_extra) as $uX; + let tmp = unsafe { + $asymmetric_division(duo >> 1, div_sig_n) + }; + + let mut quo = tmp.0 >> ((n - 1) - div_lz); + if quo != 0 { + quo -= 1; + } + + // Note that this is a full `$uD` multiplication being used here + let mut rem = duo - (quo as $uD).wrapping_mul(div); + if div <= rem { + quo += 1; + rem -= div; + } + return (quo as $uD, rem) + } + } + + /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a + /// tuple. + $( + #[$signed_attr] + )* + pub fn $signed_name(duo: $iD, div: $iD) -> ($iD, $iD) { + match (duo < 0, div < 0) { + (false, false) => { + let t = $unsigned_name(duo as $uD, div as $uD); + (t.0 as $iD, t.1 as $iD) + }, + (true, false) => { + let t = $unsigned_name(duo.wrapping_neg() as $uD, div as $uD); + ((t.0 as $iD).wrapping_neg(), (t.1 as $iD).wrapping_neg()) + }, + (false, true) => { + let t = $unsigned_name(duo as $uD, div.wrapping_neg() as $uD); + ((t.0 as $iD).wrapping_neg(), t.1 as $iD) + }, + (true, true) => { + let t = $unsigned_name(duo.wrapping_neg() as $uD, div.wrapping_neg() as $uD); + (t.0 as $iD, (t.1 as $iD).wrapping_neg()) + }, + } + } + } +} diff --git a/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs b/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs new file mode 100644 index 0000000000000..4c63396a0889f --- /dev/null +++ b/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs @@ -0,0 +1,596 @@ +/// Creates unsigned and signed division functions that use binary long division, designed for +/// computer architectures without division instructions. These functions have good performance for +/// microarchitectures with large branch miss penalties and architectures without the ability to +/// predicate instructions. For architectures with predicated instructions, one of the algorithms +/// described in the documentation of these functions probably has higher performance, and a custom +/// assembly routine should be used instead. +#[macro_export] +macro_rules! impl_binary_long { + ( + $unsigned_name:ident, // name of the unsigned division function + $signed_name:ident, // name of the signed division function + $zero_div_fn:ident, // function called when division by zero is attempted + $normalization_shift:ident, // function for finding the normalization shift + $n:tt, // the number of bits in a $iX or $uX + $uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` + $iX:ident, // signed integer type for the inputs and outputs of `$signed_name` + $($unsigned_attr:meta),*; // attributes for the unsigned function + $($signed_attr:meta),* // attributes for the signed function + ) => { + /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a + /// tuple. + $( + #[$unsigned_attr] + )* + pub fn $unsigned_name(duo: $uX, div: $uX) -> ($uX, $uX) { + let mut duo = duo; + // handle edge cases before calling `$normalization_shift` + if div == 0 { + $zero_div_fn() + } + if duo < div { + return (0, duo) + } + + // There are many variations of binary division algorithm that could be used. This + // documentation gives a tour of different methods so that future readers wanting to + // optimize further do not have to painstakingly derive them. The SWAR variation is + // especially hard to understand without reading the less convoluted methods first. + + // You may notice that a `duo < div_original` check is included in many these + // algorithms. A critical optimization that many algorithms miss is handling of + // quotients that will turn out to have many trailing zeros or many leading zeros. This + // happens in cases of exact or close-to-exact divisions, divisions by power of two, and + // in cases where the quotient is small. The `duo < div_original` check handles these + // cases of early returns and ends up replacing other kinds of mundane checks that + // normally terminate a binary division algorithm. + // + // Something you may see in other algorithms that is not special-cased here is checks + // for division by powers of two. The `duo < div_original` check handles this case and + // more, however it can be checked up front before the bisection using the + // `((div > 0) && ((div & (div - 1)) == 0))` trick. This is not special-cased because + // compilers should handle most cases where divisions by power of two occur, and we do + // not want to add on a few cycles for every division operation just to save a few + // cycles rarely. + + // The following example is the most straightforward translation from the way binary + // long division is typically visualized: + // Dividing 178u8 (0b10110010) by 6u8 (0b110). `div` is shifted left by 5, according to + // the result from `$normalization_shift(duo, div, false)`. + // + // Step 0: `sub` is negative, so there is not full normalization, so no `quo` bit is set + // and `duo` is kept unchanged. + // duo:10110010, div_shifted:11000000, sub:11110010, quo:00000000, shl:5 + // + // Step 1: `sub` is positive, set a `quo` bit and update `duo` for next step. + // duo:10110010, div_shifted:01100000, sub:01010010, quo:00010000, shl:4 + // + // Step 2: Continue based on `sub`. The `quo` bits start accumulating. + // duo:01010010, div_shifted:00110000, sub:00100010, quo:00011000, shl:3 + // duo:00100010, div_shifted:00011000, sub:00001010, quo:00011100, shl:2 + // duo:00001010, div_shifted:00001100, sub:11111110, quo:00011100, shl:1 + // duo:00001010, div_shifted:00000110, sub:00000100, quo:00011100, shl:0 + // The `duo < div_original` check terminates the algorithm with the correct quotient of + // 29u8 and remainder of 4u8 + /* + let div_original = div; + let mut shl = $normalization_shift(duo, div, false); + let mut quo = 0; + loop { + let div_shifted = div << shl; + let sub = duo.wrapping_sub(div_shifted); + // it is recommended to use `println!`s like this if functionality is unclear + /* + println!("duo:{:08b}, div_shifted:{:08b}, sub:{:08b}, quo:{:08b}, shl:{}", + duo, + div_shifted, + sub, + quo, + shl + ); + */ + if 0 <= (sub as $iX) { + duo = sub; + quo += 1 << shl; + if duo < div_original { + // this branch is optional + return (quo, duo) + } + } + if shl == 0 { + return (quo, duo) + } + shl -= 1; + } + */ + + // This restoring binary long division algorithm reduces the number of operations + // overall via: + // - `pow` can be shifted right instead of recalculating from `shl` + // - starting `div` shifted left and shifting it right for each step instead of + // recalculating from `shl` + // - The `duo < div_original` branch is used to terminate the algorithm instead of the + // `shl == 0` branch. This check is strong enough to prevent set bits of `pow` and + // `div` from being shifted off the end. This check also only occurs on half of steps + // on average, since it is behind the `(sub as $iX) >= 0` branch. + // - `shl` is now not needed by any aspect of of the loop and thus only 3 variables are + // being updated between steps + // + // There are many variations of this algorithm, but this encompases the largest number + // of architectures and does not rely on carry flags, add-with-carry, or SWAR + // complications to be decently fast. + /* + let div_original = div; + let shl = $normalization_shift(duo, div, false); + let mut div: $uX = div << shl; + let mut pow: $uX = 1 << shl; + let mut quo: $uX = 0; + loop { + let sub = duo.wrapping_sub(div); + if 0 <= (sub as $iX) { + duo = sub; + quo |= pow; + if duo < div_original { + return (quo, duo) + } + } + div >>= 1; + pow >>= 1; + } + */ + + // If the architecture has flags and predicated arithmetic instructions, it is possible + // to do binary long division without branching and in only 3 or 4 instructions. This is + // a variation of a 3 instruction central loop from + // http://www.chiark.greenend.org.uk/~theom/riscos/docs/ultimate/a252div.txt. + // + // What allows doing division in only 3 instructions is realizing that instead of + // keeping `duo` in place and shifting `div` right to align bits, `div` can be kept in + // place and `duo` can be shifted left. This means `div` does not have to be updated, + // but causes edge case problems and makes `duo < div_original` tests harder. Some + // architectures have an option to shift an argument in an arithmetic operation, which + // means `duo` can be shifted left and subtracted from in one instruction. The other two + // instructions are updating `quo` and undoing the subtraction if it turns out things + // were not normalized. + + /* + // Perform one binary long division step on the already normalized arguments, because + // the main. Note that this does a full normalization since the central loop needs + // `duo.leading_zeros()` to be at least 1 more than `div.leading_zeros()`. The original + // variation only did normalization to the nearest 4 steps, but this makes handling edge + // cases much harder. We do a full normalization and perform a binary long division + // step. In the edge case where the msbs of `duo` and `div` are set, it clears the msb + // of `duo`, then the edge case handler shifts `div` right and does another long + // division step to always insure `duo.leading_zeros() + 1 >= div.leading_zeros()`. + let div_original = div; + let mut shl = $normalization_shift(duo, div, true); + let mut div: $uX = (div << shl); + let mut quo: $uX = 1; + duo = duo.wrapping_sub(div); + if duo < div_original { + return (1 << shl, duo); + } + let div_neg: $uX; + if (div as $iX) < 0 { + // A very ugly edge case where the most significant bit of `div` is set (after + // shifting to match `duo` when its most significant bit is at the sign bit), which + // leads to the sign bit of `div_neg` being cut off and carries not happening when + // they should. This branch performs a long division step that keeps `duo` in place + // and shifts `div` down. + div >>= 1; + div_neg = div.wrapping_neg(); + let (sub, carry) = duo.overflowing_add(div_neg); + duo = sub; + quo = quo.wrapping_add(quo).wrapping_add(carry as $uX); + if !carry { + duo = duo.wrapping_add(div); + } + shl -= 1; + } else { + div_neg = div.wrapping_neg(); + } + // The add-with-carry that updates `quo` needs to have the carry set when a normalized + // subtract happens. Using `duo.wrapping_shl(1).overflowing_sub(div)` to do the + // subtraction generates a carry when an unnormalized subtract happens, which is the + // opposite of what we want. Instead, we use + // `duo.wrapping_shl(1).overflowing_add(div_neg)`, where `div_neg` is negative `div`. + let mut i = shl; + loop { + if i == 0 { + break; + } + i -= 1; + // `ADDS duo, div, duo, LSL #1` + // (add `div` to `duo << 1` and set flags) + let (sub, carry) = duo.wrapping_shl(1).overflowing_add(div_neg); + duo = sub; + // `ADC quo, quo, quo` + // (add with carry). Effectively shifts `quo` left by 1 and sets the least + // significant bit to the carry. + quo = quo.wrapping_add(quo).wrapping_add(carry as $uX); + // `ADDCC duo, duo, div` + // (add if carry clear). Undoes the subtraction if no carry was generated. + if !carry { + duo = duo.wrapping_add(div); + } + } + return (quo, duo >> shl); + */ + + // This is the SWAR (SIMD within in a register) restoring division algorithm. + // This combines several ideas of the above algorithms: + // - If `duo` is shifted left instead of shifting `div` right like in the 3 instruction + // restoring division algorithm, some architectures can do the shifting and + // subtraction step in one instruction. + // - `quo` can be constructed by adding powers-of-two to it or shifting it left by one + // and adding one. + // - Every time `duo` is shifted left, there is another unused 0 bit shifted into the + // LSB, so what if we use those bits to store `quo`? + // Through a complex setup, it is possible to manage `duo` and `quo` in the same + // register, and perform one step with 2 or 3 instructions. The only major downsides are + // that there is significant setup (it is only saves instructions if `shl` is + // approximately more than 4), `duo < div_original` checks are impractical once SWAR is + // initiated, and the number of division steps taken has to be exact (we cannot do more + // division steps than `shl`, because it introduces edge cases where quotient bits in + // `duo` start to collide with the real part of `div`. + /* + // first step. The quotient bit is stored in `quo` for now + let div_original = div; + let mut shl = $normalization_shift(duo, div, true); + let mut div: $uX = (div << shl); + duo = duo.wrapping_sub(div); + let mut quo: $uX = 1 << shl; + if duo < div_original { + return (quo, duo); + } + + let mask: $uX; + if (div as $iX) < 0 { + // deal with same edge case as the 3 instruction restoring division algorithm, but + // the quotient bit from this step also has to be stored in `quo` + div >>= 1; + shl -= 1; + let tmp = 1 << shl; + mask = tmp - 1; + let sub = duo.wrapping_sub(div); + if (sub as $iX) >= 0 { + // restore + duo = sub; + quo |= tmp; + } + if duo < div_original { + return (quo, duo); + } + } else { + mask = quo - 1; + } + // There is now room for quotient bits in `duo`. + + // Note that `div` is already shifted left and has `shl` unset bits. We subtract 1 from + // `div` and end up with the subset of `shl` bits being all being set. This subset acts + // just like a two's complement negative one. The subset of `div` containing the divisor + // had 1 subtracted from it, but a carry will always be generated from the `shl` subset + // as long as the quotient stays positive. + // + // When the modified `div` is subtracted from `duo.wrapping_shl(1)`, the `shl` subset + // adds a quotient bit to the least significant bit. + // For example, 89 (0b01011001) divided by 3 (0b11): + // + // shl:4, div:0b00110000 + // first step: + // duo:0b01011001 + // + div_neg:0b11010000 + // ____________________ + // 0b00101001 + // quo is set to 0b00010000 and mask is set to 0b00001111 for later + // + // 1 is subtracted from `div`. I will differentiate the `shl` part of `div` and the + // quotient part of `duo` with `^`s. + // chars. + // div:0b00110000 + // ^^^^ + // + 0b11111111 + // ________________ + // 0b00101111 + // ^^^^ + // div_neg:0b11010001 + // + // first SWAR step: + // duo_shl1:0b01010010 + // ^ + // + div_neg:0b11010001 + // ____________________ + // 0b00100011 + // ^ + // second: + // duo_shl1:0b01000110 + // ^^ + // + div_neg:0b11010001 + // ____________________ + // 0b00010111 + // ^^ + // third: + // duo_shl1:0b00101110 + // ^^^ + // + div_neg:0b11010001 + // ____________________ + // 0b11111111 + // ^^^ + // 3 steps resulted in the quotient with 3 set bits as expected, but currently the real + // part of `duo` is negative and the third step was an unnormalized step. The restore + // branch then restores `duo`. Note that the restore branch does not shift `duo` left. + // + // duo:0b11111111 + // ^^^ + // + div:0b00101111 + // ^^^^ + // ________________ + // 0b00101110 + // ^^^ + // `duo` is now back in the `duo_shl1` state it was at in the the third step, with an + // unset quotient bit. + // + // final step (`shl` was 4, so exactly 4 steps must be taken) + // duo_shl1:0b01011100 + // ^^^^ + // + div_neg:0b11010001 + // ____________________ + // 0b00101101 + // ^^^^ + // The quotient includes the `^` bits added with the `quo` bits from the beginning that + // contained the first step and potential edge case step, + // `quo:0b00010000 + (duo:0b00101101 & mask:0b00001111) == 0b00011101 == 29u8`. + // The remainder is the bits remaining in `duo` that are not part of the quotient bits, + // `duo:0b00101101 >> shl == 0b0010 == 2u8`. + let div: $uX = div.wrapping_sub(1); + let mut i = shl; + loop { + if i == 0 { + break; + } + i -= 1; + duo = duo.wrapping_shl(1).wrapping_sub(div); + if (duo as $iX) < 0 { + // restore + duo = duo.wrapping_add(div); + } + } + // unpack the results of SWAR + return ((duo & mask) | quo, duo >> shl); + */ + + // The problem with the conditional restoring SWAR algorithm above is that, in practice, + // it requires assembly code to bring out its full unrolled potential (It seems that + // LLVM can't use unrolled conditionals optimally and ends up erasing all the benefit + // that my algorithm intends. On architectures without predicated instructions, the code + // gen is especially bad. We need a default software division algorithm that is + // guaranteed to get decent code gen for the central loop. + + // For non-SWAR algorithms, there is a way to do binary long division without + // predication or even branching. This involves creating a mask from the sign bit and + // performing different kinds of steps using that. + /* + let shl = $normalization_shift(duo, div, true); + let mut div: $uX = div << shl; + let mut pow: $uX = 1 << shl; + let mut quo: $uX = 0; + loop { + let sub = duo.wrapping_sub(div); + let sign_mask = !((sub as $iX).wrapping_shr($n - 1) as $uX); + duo -= div & sign_mask; + quo |= pow & sign_mask; + div >>= 1; + pow >>= 1; + if pow == 0 { + break; + } + } + return (quo, duo); + */ + // However, it requires about 4 extra operations (smearing the sign bit, negating the + // mask, and applying the mask twice) on top of the operations done by the actual + // algorithm. With SWAR however, just 2 extra operations are needed, making it + // practical and even the most optimal algorithm for some architectures. + + // What we do is use custom assembly for predicated architectures that need software + // division, and for the default algorithm use a mask based restoring SWAR algorithm + // without conditionals or branches. On almost all architectures, this Rust code is + // guaranteed to compile down to 5 assembly instructions or less for each step, and LLVM + // will unroll it in a decent way. + + // standard opening for SWAR algorithm with first step and edge case handling + let div_original = div; + let mut shl = $normalization_shift(duo, div, true); + let mut div: $uX = (div << shl); + duo = duo.wrapping_sub(div); + let mut quo: $uX = 1 << shl; + if duo < div_original { + return (quo, duo); + } + let mask: $uX; + if (div as $iX) < 0 { + div >>= 1; + shl -= 1; + let tmp = 1 << shl; + mask = tmp - 1; + let sub = duo.wrapping_sub(div); + if (sub as $iX) >= 0 { + duo = sub; + quo |= tmp; + } + if duo < div_original { + return (quo, duo); + } + } else { + mask = quo - 1; + } + + // central loop + div = div.wrapping_sub(1); + let mut i = shl; + loop { + if i == 0 { + break + } + i -= 1; + // shift left 1 and subtract + duo = duo.wrapping_shl(1).wrapping_sub(div); + // create mask + let mask = (duo as $iX).wrapping_shr($n - 1) as $uX; + // restore + duo = duo.wrapping_add(div & mask); + } + // unpack + return ((duo & mask) | quo, duo >> shl); + + // miscellanious binary long division algorithms that might be better for specific + // architectures + + // Another kind of long division uses an interesting fact that `div` and `pow` can be + // negated when `duo` is negative to perform a "negated" division step that works in + // place of any normalization mechanism. This is a non-restoring division algorithm that + // is very similar to the non-restoring division algorithms that can be found on the + // internet, except there is only one test for `duo < 0`. The subtraction from `quo` can + // be viewed as shifting the least significant set bit right (e.x. if we enter a series + // of negated binary long division steps starting with `quo == 0b1011_0000` and + // `pow == 0b0000_1000`, `quo` will progress like this: 0b1010_1000, 0b1010_0100, + // 0b1010_0010, 0b1010_0001). + /* + let div_original = div; + let shl = $normalization_shift(duo, div, true); + let mut div: $uX = (div << shl); + let mut pow: $uX = 1 << shl; + let mut quo: $uX = pow; + duo = duo.wrapping_sub(div); + if duo < div_original { + return (quo, duo); + } + div >>= 1; + pow >>= 1; + loop { + if (duo as $iX) < 0 { + // Negated binary long division step. + duo = duo.wrapping_add(div); + quo = quo.wrapping_sub(pow); + } else { + // Normal long division step. + if duo < div_original { + return (quo, duo) + } + duo = duo.wrapping_sub(div); + quo = quo.wrapping_add(pow); + } + pow >>= 1; + div >>= 1; + } + */ + + // This is the Nonrestoring SWAR algorithm, combining the nonrestoring algorithm with + // SWAR techniques that makes the only difference between steps be negation of `div`. + // If there was an architecture with an instruction that negated inputs to an adder + // based on conditionals, and in place shifting (or a three input addition operation + // that can have `duo` as two of the inputs to effectively shift it left by 1), then a + // single instruction central loop is possible. Microarchitectures often have inputs to + // their ALU that can invert the arguments and carry in of adders, but the architectures + // unfortunately do not have an instruction to dynamically invert this input based on + // conditionals. + /* + // SWAR opening + let div_original = div; + let mut shl = $normalization_shift(duo, div, true); + let mut div: $uX = (div << shl); + duo = duo.wrapping_sub(div); + let mut quo: $uX = 1 << shl; + if duo < div_original { + return (quo, duo); + } + let mask: $uX; + if (div as $iX) < 0 { + div >>= 1; + shl -= 1; + let tmp = 1 << shl; + let sub = duo.wrapping_sub(div); + if (sub as $iX) >= 0 { + // restore + duo = sub; + quo |= tmp; + } + if duo < div_original { + return (quo, duo); + } + mask = tmp - 1; + } else { + mask = quo - 1; + } + + // central loop + let div: $uX = div.wrapping_sub(1); + let mut i = shl; + loop { + if i == 0 { + break; + } + i -= 1; + // note: the `wrapping_shl(1)` can be factored out, but would require another + // restoring division step to prevent `(duo as $iX)` from overflowing + if (duo as $iX) < 0 { + // Negated binary long division step. + duo = duo.wrapping_shl(1).wrapping_add(div); + } else { + // Normal long division step. + duo = duo.wrapping_shl(1).wrapping_sub(div); + } + } + if (duo as $iX) < 0 { + // Restore. This was not needed in the original nonrestoring algorithm because of + // the `duo < div_original` checks. + duo = duo.wrapping_add(div); + } + // unpack + return ((duo & mask) | quo, duo >> shl); + */ + } + + /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a + /// tuple. + $( + #[$signed_attr] + )* + pub fn $signed_name(duo: $iX, div: $iX) -> ($iX, $iX) { + // There is a way of doing this without any branches, but requires too many extra + // operations to be faster. + /* + let duo_s = duo >> ($n - 1); + let div_s = div >> ($n - 1); + let duo = (duo ^ duo_s).wrapping_sub(duo_s); + let div = (div ^ div_s).wrapping_sub(div_s); + let quo_s = duo_s ^ div_s; + let rem_s = duo_s; + let tmp = $unsigned_name(duo as $uX, div as $uX); + ( + ((tmp.0 as $iX) ^ quo_s).wrapping_sub(quo_s), + ((tmp.1 as $iX) ^ rem_s).wrapping_sub(rem_s), + ) + */ + + match (duo < 0, div < 0) { + (false, false) => { + let t = $unsigned_name(duo as $uX, div as $uX); + (t.0 as $iX, t.1 as $iX) + }, + (true, false) => { + let t = $unsigned_name(duo.wrapping_neg() as $uX, div as $uX); + ((t.0 as $iX).wrapping_neg(), (t.1 as $iX).wrapping_neg()) + }, + (false, true) => { + let t = $unsigned_name(duo as $uX, div.wrapping_neg() as $uX); + ((t.0 as $iX).wrapping_neg(), t.1 as $iX) + }, + (true, true) => { + let t = $unsigned_name(duo.wrapping_neg() as $uX, div.wrapping_neg() as $uX); + (t.0 as $iX, (t.1 as $iX).wrapping_neg()) + }, + } + } + } +} diff --git a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs new file mode 100644 index 0000000000000..1ba72431d61a7 --- /dev/null +++ b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs @@ -0,0 +1,226 @@ +/// Creates unsigned and signed division functions that use a combination of hardware division and +/// binary long division to divide integers larger than what hardware division by itself can do. This +/// function is intended for microarchitectures that have division hardware, but not fast enough +/// multiplication hardware for `impl_trifecta` to be faster. +#[macro_export] +macro_rules! impl_delegate { + ( + $unsigned_name:ident, // name of the unsigned division function + $signed_name:ident, // name of the signed division function + $zero_div_fn:ident, // function called when division by zero is attempted + $half_normalization_shift:ident, // function for finding the normalization shift of $uX + $half_division:ident, // function for division of a $uX by a $uX + $n_h:expr, // the number of bits in $iH or $uH + $uH:ident, // unsigned integer with half the bit width of $uX + $uX:ident, // unsigned integer with half the bit width of $uD. + $uD:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` + $iD:ident, // signed integer type for the inputs and outputs of `$signed_name` + $($unsigned_attr:meta),*; // attributes for the unsigned function + $($signed_attr:meta),* // attributes for the signed function + ) => { + /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a + /// tuple. + $( + #[$unsigned_attr] + )* + pub fn $unsigned_name(duo: $uD, div: $uD) -> ($uD, $uD) { + // The two possibility algorithm, undersubtracting long division algorithm, or any kind + // of reciprocal based algorithm will not be fastest, because they involve large + // multiplications that we assume to not be fast enough relative to the divisions to + // outweigh setup times. + + // the number of bits in a $uX + let n = $n_h * 2; + + let duo_lo = duo as $uX; + let duo_hi = (duo >> n) as $uX; + let div_lo = div as $uX; + let div_hi = (div >> n) as $uX; + + match (div_lo == 0, div_hi == 0, duo_hi == 0) { + (true, true, _) => { + $zero_div_fn() + } + (_, false, true) => { + // `duo` < `div` + return (0, duo) + } + (false, true, true) => { + // delegate to smaller division + let tmp = $half_division(duo_lo, div_lo); + return (tmp.0 as $uD, tmp.1 as $uD) + } + (false, true, false) => { + if duo_hi < div_lo { + // `quo_hi` will always be 0. This performs a binary long division algorithm + // to zero `duo_hi` followed by a half division. + + // We can calculate the normalization shift using only `$uX` size functions. + // If we calculated the normalization shift using + // `$half_normalization_shift(duo_hi, div_lo false)`, it would break the + // assumption the function has that the first argument is more than the + // second argument. If the arguments are switched, the assumption holds true + // since `duo_hi < div_lo`. + let norm_shift = $half_normalization_shift(div_lo, duo_hi, false); + let shl = if norm_shift == 0 { + // Consider what happens if the msbs of `duo_hi` and `div_lo` align with + // no shifting. The normalization shift will always return + // `norm_shift == 0` regardless of whether it is fully normalized, + // because `duo_hi < div_lo`. In that edge case, `n - norm_shift` would + // result in shift overflow down the line. For the edge case, because + // both `duo_hi < div_lo` and we are comparing all the significant bits + // of `duo_hi` and `div`, we can make `shl = n - 1`. + n - 1 + } else { + // We also cannot just use `shl = n - norm_shift - 1` in the general + // case, because when we are not in the edge case comparing all the + // significant bits, then the full `duo < div` may not be true and thus + // breaks the division algorithm. + n - norm_shift + }; + + // The 3 variable restoring division algorithm (see binary_long.rs) is ideal + // for this task, since `pow` and `quo` can be `$uX` and the delegation + // check is simple. + let mut div: $uD = div << shl; + let mut pow_lo: $uX = 1 << shl; + let mut quo_lo: $uX = 0; + let mut duo = duo; + loop { + let sub = duo.wrapping_sub(div); + if 0 <= (sub as $iD) { + duo = sub; + quo_lo |= pow_lo; + let duo_hi = (duo >> n) as $uX; + if duo_hi == 0 { + // Delegate to get the rest of the quotient. Note that the + // `div_lo` here is the original unshifted `div`. + let tmp = $half_division(duo as $uX, div_lo); + return ((quo_lo | tmp.0) as $uD, tmp.1 as $uD) + } + } + div >>= 1; + pow_lo >>= 1; + } + } else if duo_hi == div_lo { + // `quo_hi == 1`. This branch is cheap and helps with edge cases. + let tmp = $half_division(duo as $uX, div as $uX); + return ((1 << n) | (tmp.0 as $uD), tmp.1 as $uD) + } else { + // `div_lo < duo_hi` + // `rem_hi == 0` + if (div_lo >> $n_h) == 0 { + // Short division of $uD by a $uH, using $uX by $uX division + let div_0 = div_lo as $uH as $uX; + let (quo_hi, rem_3) = $half_division(duo_hi, div_0); + + let duo_mid = + ((duo >> $n_h) as $uH as $uX) + | (rem_3 << $n_h); + let (quo_1, rem_2) = $half_division(duo_mid, div_0); + + let duo_lo = + (duo as $uH as $uX) + | (rem_2 << $n_h); + let (quo_0, rem_1) = $half_division(duo_lo, div_0); + + return ( + (quo_0 as $uD) + | ((quo_1 as $uD) << $n_h) + | ((quo_hi as $uD) << n), + rem_1 as $uD + ) + } + + // This is basically a short division composed of a half division for the hi + // part, specialized 3 variable binary long division in the middle, and + // another half division for the lo part. + let duo_lo = duo as $uX; + let tmp = $half_division(duo_hi, div_lo); + let quo_hi = tmp.0; + let mut duo = (duo_lo as $uD) | ((tmp.1 as $uD) << n); + // This check is required to avoid breaking the long division below. + if duo < div { + return ((quo_hi as $uD) << n, duo); + } + + // The half division handled all shift alignments down to `n`, so this + // division can continue with a shift of `n - 1`. + let mut div: $uD = div << (n - 1); + let mut pow_lo: $uX = 1 << (n - 1); + let mut quo_lo: $uX = 0; + loop { + let sub = duo.wrapping_sub(div); + if 0 <= (sub as $iD) { + duo = sub; + quo_lo |= pow_lo; + let duo_hi = (duo >> n) as $uX; + if duo_hi == 0 { + // Delegate to get the rest of the quotient. Note that the + // `div_lo` here is the original unshifted `div`. + let tmp = $half_division(duo as $uX, div_lo); + return ( + (tmp.0) as $uD | (quo_lo as $uD) | ((quo_hi as $uD) << n), + tmp.1 as $uD + ); + } + } + div >>= 1; + pow_lo >>= 1; + } + } + } + (_, false, false) => { + // Full $uD by $uD binary long division. `quo_hi` will always be 0. + if duo < div { + return (0, duo); + } + let div_original = div; + let shl = $half_normalization_shift(duo_hi, div_hi, false); + let mut duo = duo; + let mut div: $uD = div << shl; + let mut pow_lo: $uX = 1 << shl; + let mut quo_lo: $uX = 0; + loop { + let sub = duo.wrapping_sub(div); + if 0 <= (sub as $iD) { + duo = sub; + quo_lo |= pow_lo; + if duo < div_original { + return (quo_lo as $uD, duo) + } + } + div >>= 1; + pow_lo >>= 1; + } + } + } + } + + /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a + /// tuple. + $( + #[$signed_attr] + )* + pub fn $signed_name(duo: $iD, div: $iD) -> ($iD, $iD) { + match (duo < 0, div < 0) { + (false, false) => { + let t = $unsigned_name(duo as $uD, div as $uD); + (t.0 as $iD, t.1 as $iD) + }, + (true, false) => { + let t = $unsigned_name(duo.wrapping_neg() as $uD, div as $uD); + ((t.0 as $iD).wrapping_neg(), (t.1 as $iD).wrapping_neg()) + }, + (false, true) => { + let t = $unsigned_name(duo as $uD, div.wrapping_neg() as $uD); + ((t.0 as $iD).wrapping_neg(), t.1 as $iD) + }, + (true, true) => { + let t = $unsigned_name(duo.wrapping_neg() as $uD, div.wrapping_neg() as $uD); + (t.0 as $iD, (t.1 as $iD).wrapping_neg()) + }, + } + } + } +} diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs new file mode 100644 index 0000000000000..5a034dcf10b09 --- /dev/null +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -0,0 +1,295 @@ +// TODO: when `unsafe_block_in_unsafe_fn` is stabilized, remove this +#![allow(unused_unsafe)] + +//! This `specialized_div_rem` module is originally from version 1.0.0 of the +//! `specialized-div-rem` crate. Note that `for` loops with ranges are not used in this +//! module, since unoptimized compilation may generate references to `memcpy`. +//! +//! The purpose of these macros is to easily change the both the division algorithm used +//! for a given integer size and the half division used by that algorithm. The way +//! functions call each other is also constructed such that linkers will find the chain of +//! software and hardware divisions needed for every size of signed and unsigned division. +//! For example, most target compilations do the following: +//! +//! - Many 128 bit division functions like `u128::wrapping_div` use +//! `std::intrinsics::unchecked_div`, which gets replaced by `__udivti3` because there +//! is not a 128 bit by 128 bit hardware division function in most architectures. +//! `__udivti3` uses `u128_div_rem` (this extra level of function calls exists because +//! `__umodti3` and `__udivmodti4` also exist, and `specialized_div_rem` supplies just +//! one function to calculate both the quotient and remainder. If configuration flags +//! enable it, `impl_trifecta!` defines `u128_div_rem` to use the trifecta algorithm, +//! which requires the half sized division `u64_by_u64_div_rem`. If the architecture +//! supplies a 64 bit hardware division instruction, `u64_by_u64_div_rem` will be +//! reduced to those instructions. Note that we do not specify the half size division +//! directly to be `__udivdi3`, because hardware division would never be introduced. +//! - If the architecture does not supply a 64 bit hardware division instruction, u64 +//! divisions will use functions such as `__udivdi3`. This will call `u64_div_rem` +//! which is defined by `impl_delegate!`. The half division for this algorithm is +//! `u32_by_u32_div_rem` which in turn becomes hardware division instructions or more +//! software division algorithms. +//! - If the architecture does not supply a 32 bit hardware instruction, linkers will +//! look for `__udivsi3`. `impl_binary_long!` is used, but this algorithm uses no half +//! division, so the chain of calls ends here. +//! +//! On some architectures like x86_64, an asymmetrically sized division is supplied, in +//! which 128 bit numbers can be divided by 64 bit numbers. `impl_asymmetric!` is used to +//! extend the 128 by 64 bit division to a full 128 by 128 bit division. + +// `allow(dead_code)` is used in various places, because the configuration code would otherwise be +// ridiculously complex + +#[macro_use] +mod norm_shift; + +#[macro_use] +mod binary_long; + +#[macro_use] +mod delegate; + +#[macro_use] +mod trifecta; + +#[macro_use] +mod asymmetric; + +/// The behavior of all divisions by zero is controlled by this function. This function should be +/// impossible to reach by Rust users, unless `compiler-builtins` public division functions or +/// `core/std::unchecked_div/rem` are directly used without a zero check in front. +fn zero_div_fn() -> ! { + // TODO: change this once the algorithms are verified + //unsafe {core::hint::unreachable_unchecked()} + ::abort() +} + +// The `B` extension on RISC-V determines if a CLZ assembly instruction exists +#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] +const USE_LZ: bool = cfg!(target_feature = "b"); + +#[cfg(target_arch = "arm")] +const USE_LZ: bool = if cfg!(target_feature = "thumb-mode") { + // ARM thumb targets have CLZ instructions if the instruction set of ARMv6T2 is supported. This + // is needed to successfully differentiate between targets like `thumbv8.base` and + // `thumbv8.main`. + cfg!(target_feature = "v6t2") +} else { + // Regular ARM targets have CLZ instructions if the ARMv5TE instruction set is supported. + // Technically, ARMv5T was the first to have CLZ, but the "v5t" target feature does not seem to + // work. + cfg!(target_feature = "v5te") +}; + +// All other targets Rust supports have CLZ instructions +#[cfg(not(any(target_arch = "arm", target_arch = "riscv32", target_arch = "riscv64")))] +const USE_LZ: bool = true; + +impl_normalization_shift!( + u32_normalization_shift, + USE_LZ, + 32, + u32, + i32, + allow(dead_code) +); +impl_normalization_shift!( + u64_normalization_shift, + USE_LZ, + 64, + u64, + i64, + allow(dead_code) +); + +/// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. +/// `checked_div` and `checked_rem` are used to avoid bringing in panic function +/// dependencies. +#[inline] +fn u64_by_u64_div_rem(duo: u64, div: u64) -> (u64, u64) { + if let Some(quo) = duo.checked_div(div) { + if let Some(rem) = duo.checked_rem(div) { + return (quo, rem); + } + } + zero_div_fn() +} + +// Whether `trifecta` or `delegate` is faster for 128 bit division depends on the speed at which a +// microarchitecture can multiply and divide. We decide to be optimistic and assume `trifecta` is +// faster if the target pointer width is at least 64. +#[cfg(all( + not(all(feature = "asm", target_arch = "x86_64")), + not(any(target_pointer_width = "16", target_pointer_width = "32")) +))] +impl_trifecta!( + u128_div_rem, + i128_div_rem, + zero_div_fn, + u64_by_u64_div_rem, + 32, + u32, + u64, + u128, + i128,; +); + +// If the pointer width less than 64, then the target architecture almost certainly does not have +// the fast 64 to 128 bit widening multiplication needed for `trifecta` to be faster. +#[cfg(all( + not(all(feature = "asm", target_arch = "x86_64")), + any(target_pointer_width = "16", target_pointer_width = "32") +))] +impl_delegate!( + u128_div_rem, + i128_div_rem, + zero_div_fn, + u64_normalization_shift, + u64_by_u64_div_rem, + 32, + u32, + u64, + u128, + i128,; +); + +/// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. +/// +/// # Safety +/// +/// 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(feature = "asm", target_arch = "x86_64"))] +#[inline] +unsafe fn u128_by_u64_div_rem(duo: u128, div: u64) -> (u64, u64) { + let duo_lo = duo as u64; + let duo_hi = (duo >> 64) as u64; + let quo: u64; + let rem: u64; + unsafe { + // divides the combined registers rdx:rax (`duo` is split into two 64 bit parts to do this) + // by `div`. The quotient is stored in rax and the remainder in rdx. + asm!( + "div {0}", + in(reg) div, + inlateout("rax") duo_lo => quo, + inlateout("rdx") duo_hi => rem, + options(pure, nomem, nostack) + ); + } + (quo, rem) +} + +// use `asymmetric` instead of `trifecta` on x86_64 +#[cfg(all(feature = "asm", target_arch = "x86_64"))] +impl_asymmetric!( + u128_div_rem, + i128_div_rem, + zero_div_fn, + u64_by_u64_div_rem, + u128_by_u64_div_rem, + 32, + u32, + u64, + u128, + i128,; +); + +/// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. +/// `checked_div` and `checked_rem` are used to avoid bringing in panic function +/// dependencies. +#[inline] +#[allow(dead_code)] +fn u32_by_u32_div_rem(duo: u32, div: u32) -> (u32, u32) { + if let Some(quo) = duo.checked_div(div) { + if let Some(rem) = duo.checked_rem(div) { + return (quo, rem); + } + } + zero_div_fn() +} + +// 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(feature = "asm", target_arch = "x86")), + not(target_pointer_width = "64") +))] +impl_delegate!( + u64_div_rem, + i64_div_rem, + zero_div_fn, + u32_normalization_shift, + u32_by_u32_div_rem, + 16, + u16, + u32, + u64, + i64,; +); + +// When not on x86 and the pointer width is 64, use `binary_long`. +#[cfg(all( + not(all(feature = "asm", target_arch = "x86")), + target_pointer_width = "64" +))] +impl_binary_long!( + u64_div_rem, + i64_div_rem, + zero_div_fn, + u64_normalization_shift, + 64, + u64, + i64,; +); + +/// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. +/// +/// # Safety +/// +/// 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(feature = "asm", target_arch = "x86"))] +#[inline] +unsafe fn u64_by_u32_div_rem(duo: u64, div: u32) -> (u32, u32) { + let duo_lo = duo as u32; + let duo_hi = (duo >> 32) as u32; + let quo: u32; + let rem: u32; + unsafe { + // divides the combined registers rdx:rax (`duo` is split into two 32 bit parts to do this) + // by `div`. The quotient is stored in rax and the remainder in rdx. + asm!( + "div {0}", + in(reg) div, + inlateout("rax") duo_lo => quo, + inlateout("rdx") duo_hi => rem, + options(pure, nomem, nostack) + ); + } + (quo, rem) +} + +// use `asymmetric` instead of `delegate` on x86 +#[cfg(all(feature = "asm", target_arch = "x86"))] +impl_asymmetric!( + u64_div_rem, + i64_div_rem, + zero_div_fn, + u32_by_u32_div_rem, + u64_by_u32_div_rem, + 16, + u16, + u32, + u64, + i64,; +); + +// 32 bits is the smallest division used by `compiler-builtins`, so we end with binary long division +impl_binary_long!( + u32_div_rem, + i32_div_rem, + zero_div_fn, + u32_normalization_shift, + 32, + u32, + i32,; +); diff --git a/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs b/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs new file mode 100644 index 0000000000000..33348b373610a --- /dev/null +++ b/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs @@ -0,0 +1,106 @@ +/// Creates a function used by some division algorithms to compute the "normalization shift". +#[macro_export] +macro_rules! impl_normalization_shift { + ( + $name:ident, // name of the normalization shift function + // boolean for if `$uX::leading_zeros` should be used (if an architecture does not have a + // hardware instruction for `usize::leading_zeros`, then this should be `true`) + $use_lz:ident, + $n:tt, // the number of bits in a $iX or $uX + $uX:ident, // unsigned integer type for the inputs of `$name` + $iX:ident, // signed integer type for the inputs of `$name` + $($unsigned_attr:meta),* // attributes for the function + ) => { + /// Finds the shift left that the divisor `div` would need to be normalized for a binary + /// long division step with the dividend `duo`. NOTE: This function assumes that these edge + /// cases have been handled before reaching it: + /// ` + /// if div == 0 { + /// panic!("attempt to divide by zero") + /// } + /// if duo < div { + /// return (0, duo) + /// } + /// ` + /// + /// Normalization is defined as (where `shl` is the output of this function): + /// ` + /// if duo.leading_zeros() != (div << shl).leading_zeros() { + /// // If the most significant bits of `duo` and `div << shl` are not in the same place, + /// // then `div << shl` has one more leading zero than `duo`. + /// assert_eq!(duo.leading_zeros() + 1, (div << shl).leading_zeros()); + /// // Also, `2*(div << shl)` is not more than `duo` (otherwise the first division step + /// // would not be able to clear the msb of `duo`) + /// assert!(duo < (div << (shl + 1))); + /// } + /// if full_normalization { + /// // Some algorithms do not need "full" normalization, which means that `duo` is + /// // larger than `div << shl` when the most significant bits are aligned. + /// assert!((div << shl) <= duo); + /// } + /// ` + /// + /// Note: If the software bisection algorithm is being used in this function, it happens + /// that full normalization always occurs, so be careful that new algorithms are not + /// invisibly depending on this invariant when `full_normalization` is set to `false`. + $( + #[$unsigned_attr] + )* + fn $name(duo: $uX, div: $uX, full_normalization: bool) -> usize { + // We have to find the leading zeros of `div` to know where its msb (most significant + // set bit) is to even begin binary long division. It is also good to know where the msb + // of `duo` is so that useful work can be started instead of shifting `div` for all + // possible quotients (many division steps are wasted if `duo.leading_zeros()` is large + // and `div` starts out being shifted all the way to the msb). Aligning the msbs of + // `div` and `duo` could be done by shifting `div` left by + // `div.leading_zeros() - duo.leading_zeros()`, but some CPUs without division hardware + // also do not have single instructions for calculating `leading_zeros`. Instead of + // software doing two bisections to find the two `leading_zeros`, we do one bisection to + // find `div.leading_zeros() - duo.leading_zeros()` without actually knowing either of + // the leading zeros values. + + let mut shl: usize; + if $use_lz { + shl = (div.leading_zeros() - duo.leading_zeros()) as usize; + if full_normalization { + if duo < (div << shl) { + // when the msb of `duo` and `div` are aligned, the resulting `div` may be + // larger than `duo`, so we decrease the shift by 1. + shl -= 1; + } + } + } else { + let mut test = duo; + shl = 0usize; + let mut lvl = $n >> 1; + loop { + let tmp = test >> lvl; + // It happens that a final `duo < (div << shl)` check is not needed, because the + // `div <= tmp` check insures that the msb of `test` never passes the msb of + // `div`, and any set bits shifted off the end of `test` would still keep + // `div <= tmp` true. + if div <= tmp { + test = tmp; + shl += lvl; + } + // narrow down bisection + lvl >>= 1; + if lvl == 0 { + break + } + } + } + // tests the invariants that should hold before beginning binary long division + /* + if full_normalization { + assert!((div << shl) <= duo); + } + if duo.leading_zeros() != (div << shl).leading_zeros() { + assert_eq!(duo.leading_zeros() + 1, (div << shl).leading_zeros()); + assert!(duo < (div << (shl + 1))); + } + */ + shl + } + } +} diff --git a/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs b/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs new file mode 100644 index 0000000000000..e76516f349093 --- /dev/null +++ b/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs @@ -0,0 +1,441 @@ +/// Creates unsigned and signed division functions optimized for division of integers with bitwidths +/// larger than the largest hardware integer division supported. These functions use large radix +/// division algorithms that require both fast division and very fast widening multiplication on the +/// target microarchitecture. Otherwise, `impl_delegate` should be used instead. +#[macro_export] +macro_rules! impl_trifecta { + ( + $unsigned_name:ident, // name of the unsigned division function + $signed_name:ident, // name of the signed division function + $zero_div_fn:ident, // function called when division by zero is attempted + $half_division:ident, // function for division of a $uX by a $uX + $n_h:expr, // the number of bits in $iH or $uH + $uH:ident, // unsigned integer with half the bit width of $uX + $uX:ident, // unsigned integer with half the bit width of $uD + $uD:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` + $iD:ident, // signed integer type for the inputs and outputs of `$signed_name` + $($unsigned_attr:meta),*; // attributes for the unsigned function + $($signed_attr:meta),* // attributes for the signed function + ) => { + /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a + /// tuple. + $( + #[$unsigned_attr] + )* + pub fn $unsigned_name(duo: $uD, div: $uD) -> ($uD, $uD) { + // This is called the trifecta algorithm because it uses three main algorithms: short + // division for small divisors, the two possibility algorithm for large divisors, and an + // undersubtracting long division algorithm for intermediate cases. + + // This replicates `carrying_mul` (rust-lang rfc #2417). LLVM correctly optimizes this + // to use a widening multiply to 128 bits on the relevant architectures. + fn carrying_mul(lhs: $uX, rhs: $uX) -> ($uX, $uX) { + let tmp = (lhs as $uD).wrapping_mul(rhs as $uD); + (tmp as $uX, (tmp >> ($n_h * 2)) as $uX) + } + fn carrying_mul_add(lhs: $uX, mul: $uX, add: $uX) -> ($uX, $uX) { + let tmp = (lhs as $uD).wrapping_mul(mul as $uD).wrapping_add(add as $uD); + (tmp as $uX, (tmp >> ($n_h * 2)) as $uX) + } + + // the number of bits in a $uX + let n = $n_h * 2; + + if div == 0 { + $zero_div_fn() + } + + // Trying to use a normalization shift function will cause inelegancies in the code and + // inefficiencies for architectures with a native count leading zeros instruction. The + // undersubtracting algorithm needs both values (keeping the original `div_lz` but + // updating `duo_lz` multiple times), so we assume hardware support for fast + // `leading_zeros` calculation. + let div_lz = div.leading_zeros(); + let mut duo_lz = duo.leading_zeros(); + + // the possible ranges of `duo` and `div` at this point: + // `0 <= duo < 2^n_d` + // `1 <= div < 2^n_d` + + // quotient is 0 or 1 branch + if div_lz <= duo_lz { + // The quotient cannot be more than 1. The highest set bit of `duo` needs to be at + // least one place higher than `div` for the quotient to be more than 1. + if duo >= div { + return (1, duo - div) + } else { + return (0, duo) + } + } + + // `_sb` is the number of significant bits (from the ones place to the highest set bit) + // `{2, 2^div_sb} <= duo < 2^n_d` + // `1 <= div < {2^duo_sb, 2^(n_d - 1)}` + // smaller division branch + if duo_lz >= n { + // `duo < 2^n` so it will fit in a $uX. `div` will also fit in a $uX (because of the + // `div_lz <= duo_lz` branch) so no numerical error. + let (quo, rem) = $half_division(duo as $uX, div as $uX); + return ( + quo as $uD, + rem as $uD + ) + } + + // `{2^n, 2^div_sb} <= duo < 2^n_d` + // `1 <= div < {2^duo_sb, 2^(n_d - 1)}` + // short division branch + if div_lz >= (n + $n_h) { + // `1 <= div < {2^duo_sb, 2^n_h}` + + // It is barely possible to improve the performance of this by calculating the + // reciprocal and removing one `$half_division`, but only if the CPU can do fast + // multiplications in parallel. Other reciprocal based methods can remove two + // `$half_division`s, but have multiplications that cannot be done in parallel and + // reduce performance. I have decided to use this trivial short division method and + // rely on the CPU having quick divisions. + + let duo_hi = (duo >> n) as $uX; + let div_0 = div as $uH as $uX; + let (quo_hi, rem_3) = $half_division(duo_hi, div_0); + + let duo_mid = + ((duo >> $n_h) as $uH as $uX) + | (rem_3 << $n_h); + let (quo_1, rem_2) = $half_division(duo_mid, div_0); + + let duo_lo = + (duo as $uH as $uX) + | (rem_2 << $n_h); + let (quo_0, rem_1) = $half_division(duo_lo, div_0); + + return ( + (quo_0 as $uD) + | ((quo_1 as $uD) << $n_h) + | ((quo_hi as $uD) << n), + rem_1 as $uD + ) + } + + // relative leading significant bits, cannot overflow because of above branches + let lz_diff = div_lz - duo_lz; + + // `{2^n, 2^div_sb} <= duo < 2^n_d` + // `2^n_h <= div < {2^duo_sb, 2^(n_d - 1)}` + // `mul` or `mul - 1` branch + if lz_diff < $n_h { + // Two possibility division algorithm + + // The most significant bits of `duo` and `div` are within `$n_h` bits of each + // other. If we take the `n` most significant bits of `duo` and divide them by the + // corresponding bits in `div`, it produces a quotient value `quo`. It happens that + // `quo` or `quo - 1` will always be the correct quotient for the whole number. In + // other words, the bits less significant than the `n` most significant bits of + // `duo` and `div` can only influence the quotient to be one of two values. + // Because there are only two possibilities, there only needs to be one `$uH` sized + // division, a `$uH` by `$uD` multiplication, and only one branch with a few simple + // operations. + // + // Proof that the true quotient can only be `quo` or `quo - 1`. + // All `/` operators here are floored divisions. + // + // `shift` is the number of bits not in the higher `n` significant bits of `duo`. + // (definitions) + // 0. shift = n - duo_lz + // 1. duo_sig_n == duo / 2^shift + // 2. div_sig_n == div / 2^shift + // 3. quo == duo_sig_n / div_sig_n + // + // + // We are trying to find the true quotient, `true_quo`. + // 4. true_quo = duo / div. (definition) + // + // This is true because of the bits that are cut off during the bit shift. + // 5. duo_sig_n * 2^shift <= duo < (duo_sig_n + 1) * 2^shift. + // 6. div_sig_n * 2^shift <= div < (div_sig_n + 1) * 2^shift. + // + // Dividing each bound of (5) by each bound of (6) gives 4 possibilities for what + // `true_quo == duo / div` is bounded by: + // (duo_sig_n * 2^shift) / (div_sig_n * 2^shift) + // (duo_sig_n * 2^shift) / ((div_sig_n + 1) * 2^shift) + // ((duo_sig_n + 1) * 2^shift) / (div_sig_n * 2^shift) + // ((duo_sig_n + 1) * 2^shift) / ((div_sig_n + 1) * 2^shift) + // + // Simplifying each of these four: + // duo_sig_n / div_sig_n + // duo_sig_n / (div_sig_n + 1) + // (duo_sig_n + 1) / div_sig_n + // (duo_sig_n + 1) / (div_sig_n + 1) + // + // Taking the smallest and the largest of these as the low and high bounds + // and replacing `duo / div` with `true_quo`: + // 7. duo_sig_n / (div_sig_n + 1) <= true_quo < (duo_sig_n + 1) / div_sig_n + // + // The `lz_diff < n_h` conditional on this branch makes sure that `div_sig_n` is at + // least `2^n_h`, and the `div_lz <= duo_lz` branch makes sure that the highest bit + // of `div_sig_n` is not the `2^(n - 1)` bit. + // 8. `2^(n - 1) <= duo_sig_n < 2^n` + // 9. `2^n_h <= div_sig_n < 2^(n - 1)` + // + // We want to prove that either + // `(duo_sig_n + 1) / div_sig_n == duo_sig_n / (div_sig_n + 1)` or that + // `(duo_sig_n + 1) / div_sig_n == duo_sig_n / (div_sig_n + 1) + 1`. + // + // We also want to prove that `quo` is one of these: + // `duo_sig_n / div_sig_n == duo_sig_n / (div_sig_n + 1)` or + // `duo_sig_n / div_sig_n == (duo_sig_n + 1) / div_sig_n`. + // + // When 1 is added to the numerator of `duo_sig_n / div_sig_n` to produce + // `(duo_sig_n + 1) / div_sig_n`, it is not possible that the value increases by + // more than 1 with floored integer arithmetic and `div_sig_n != 0`. Consider + // `x/y + 1 < (x + 1)/y` <=> `x/y + 1 < x/y + 1/y` <=> `1 < 1/y` <=> `y < 1`. + // `div_sig_n` is a nonzero integer. Thus, + // 10. `duo_sig_n / div_sig_n == (duo_sig_n + 1) / div_sig_n` or + // `(duo_sig_n / div_sig_n) + 1 == (duo_sig_n + 1) / div_sig_n. + // + // When 1 is added to the denominator of `duo_sig_n / div_sig_n` to produce + // `duo_sig_n / (div_sig_n + 1)`, it is not possible that the value decreases by + // more than 1 with the bounds (8) and (9). Consider `x/y - 1 <= x/(y + 1)` <=> + // `(x - y)/y < x/(y + 1)` <=> `(y + 1)*(x - y) < x*y` <=> `x*y - y*y + x - y < x*y` + // <=> `x < y*y + y`. The smallest value of `div_sig_n` is `2^n_h` and the largest + // value of `duo_sig_n` is `2^n - 1`. Substituting reveals `2^n - 1 < 2^n + 2^n_h`. + // Thus, + // 11. `duo_sig_n / div_sig_n == duo_sig_n / (div_sig_n + 1)` or + // `(duo_sig_n / div_sig_n) - 1` == duo_sig_n / (div_sig_n + 1)` + // + // Combining both (10) and (11), we know that + // `quo - 1 <= duo_sig_n / (div_sig_n + 1) <= true_quo + // < (duo_sig_n + 1) / div_sig_n <= quo + 1` and therefore: + // 12. quo - 1 <= true_quo < quo + 1 + // + // In a lot of division algorithms using smaller divisions to construct a larger + // division, we often encounter a situation where the approximate `quo` value + // calculated from a smaller division is multiple increments away from the true + // `quo` value. In those algorithms, multiple correction steps have to be applied. + // Those correction steps may need more multiplications to test `duo - (quo*div)` + // again. Because of the fact that our `quo` can only be one of two values, we can + // see if `duo - (quo*div)` overflows. If it did overflow, then we know that we have + // the larger of the two values (since the true quotient is unique, and any larger + // quotient will cause `duo - (quo*div)` to be negative). Also because there is only + // one correction needed, we can calculate the remainder `duo - (true_quo*div) == + // duo - ((quo - 1)*div) == duo - (quo*div - div) == duo + div - quo*div`. + // If `duo - (quo*div)` did not overflow, then we have the correct answer. + let shift = n - duo_lz; + let duo_sig_n = (duo >> shift) as $uX; + let div_sig_n = (div >> shift) as $uX; + let quo = $half_division(duo_sig_n, div_sig_n).0; + + // The larger `quo` value can overflow `$uD` in the right circumstances. This is a + // manual `carrying_mul_add` with overflow checking. + let div_lo = div as $uX; + let div_hi = (div >> n) as $uX; + let (tmp_lo, carry) = carrying_mul(quo, div_lo); + let (tmp_hi, overflow) = carrying_mul_add(quo, div_hi, carry); + let tmp = (tmp_lo as $uD) | ((tmp_hi as $uD) << n); + if (overflow != 0) || (duo < tmp) { + return ( + (quo - 1) as $uD, + // Both the addition and subtraction can overflow, but when combined end up + // as a correct positive number. + duo.wrapping_add(div).wrapping_sub(tmp) + ) + } else { + return ( + quo as $uD, + duo - tmp + ) + } + } + + // Undersubtracting long division algorithm. + // Instead of clearing a minimum of 1 bit from `duo` per iteration via binary long + // division, `n_h - 1` bits are cleared per iteration with this algorithm. It is a more + // complicated version of regular long division. Most integer division algorithms tend + // to guess a part of the quotient, and may have a larger quotient than the true + // quotient (which when multiplied by `div` will "oversubtract" the original dividend). + // They then check if the quotient was in fact too large and then have to correct it. + // This long division algorithm has been carefully constructed to always underguess the + // quotient by slim margins. This allows different subalgorithms to be blindly jumped to + // without needing an extra correction step. + // + // The only problem is that this subalgorithm will not work for many ranges of `duo` and + // `div`. Fortunately, the short division, two possibility algorithm, and other simple + // cases happen to exactly fill these gaps. + // + // For an example, consider the division of 76543210 by 213 and assume that `n_h` is + // equal to two decimal digits (note: we are working with base 10 here for readability). + // The first `sig_n_h` part of the divisor (21) is taken and is incremented by 1 to + // prevent oversubtraction. We also record the number of extra places not a part of + // the `sig_n` or `sig_n_h` parts. + // + // sig_n_h == 2 digits, sig_n == 4 digits + // + // vvvv <- `duo_sig_n` + // 76543210 + // ^^^^ <- extra places in duo, `duo_extra == 4` + // + // vv <- `div_sig_n_h` + // 213 + // ^ <- extra places in div, `div_extra == 1` + // + // The difference in extra places, `duo_extra - div_extra == extra_shl == 3`, is used + // for shifting partial sums in the long division. + // + // In the first step, the first `sig_n` part of duo (7654) is divided by + // `div_sig_n_h_add_1` (22), which results in a partial quotient of 347. This is + // multiplied by the whole divisor to make 73911, which is shifted left by `extra_shl` + // and subtracted from duo. The partial quotient is also shifted left by `extra_shl` to + // be added to `quo`. + // + // 347 + // ________ + // |76543210 + // -73911 + // 2632210 + // + // Variables dependent on duo have to be updated: + // + // vvvv <- `duo_sig_n == 2632` + // 2632210 + // ^^^ <- `duo_extra == 3` + // + // `extra_shl == 2` + // + // Two more steps are taken after this and then duo fits into `n` bits, and then a final + // normal long division step is made. The partial quotients are all progressively added + // to each other in the actual algorithm, but here I have left them all in a tower that + // can be added together to produce the quotient, 359357. + // + // 14 + // 443 + // 119 + // 347 + // ________ + // |76543210 + // -73911 + // 2632210 + // -25347 + // 97510 + // -94359 + // 3151 + // -2982 + // 169 <- the remainder + + let mut duo = duo; + let mut quo: $uD = 0; + + // The number of lesser significant bits not a part of `div_sig_n_h` + let div_extra = (n + $n_h) - div_lz; + + // The most significant `n_h` bits of div + let div_sig_n_h = (div >> div_extra) as $uH; + + // This needs to be a `$uX` in case of overflow from the increment + let div_sig_n_h_add1 = (div_sig_n_h as $uX) + 1; + + // `{2^n, 2^(div_sb + n_h)} <= duo < 2^n_d` + // `2^n_h <= div < {2^(duo_sb - n_h), 2^n}` + loop { + // The number of lesser significant bits not a part of `duo_sig_n` + let duo_extra = n - duo_lz; + + // The most significant `n` bits of `duo` + let duo_sig_n = (duo >> duo_extra) as $uX; + + // the two possibility algorithm requires that the difference between msbs is less + // than `n_h`, so the comparison is `<=` here. + if div_extra <= duo_extra { + // Undersubtracting long division step + let quo_part = $half_division(duo_sig_n, div_sig_n_h_add1).0 as $uD; + let extra_shl = duo_extra - div_extra; + + // Addition to the quotient. + quo += (quo_part << extra_shl); + + // Subtraction from `duo`. At least `n_h - 1` bits are cleared from `duo` here. + duo -= (div.wrapping_mul(quo_part) << extra_shl); + } else { + // Two possibility algorithm + let shift = n - duo_lz; + let duo_sig_n = (duo >> shift) as $uX; + let div_sig_n = (div >> shift) as $uX; + let quo_part = $half_division(duo_sig_n, div_sig_n).0; + let div_lo = div as $uX; + let div_hi = (div >> n) as $uX; + + let (tmp_lo, carry) = carrying_mul(quo_part, div_lo); + // The undersubtracting long division algorithm has already run once, so + // overflow beyond `$uD` bits is not possible here + let (tmp_hi, _) = carrying_mul_add(quo_part, div_hi, carry); + let tmp = (tmp_lo as $uD) | ((tmp_hi as $uD) << n); + + if duo < tmp { + return ( + quo + ((quo_part - 1) as $uD), + duo.wrapping_add(div).wrapping_sub(tmp) + ) + } else { + return ( + quo + (quo_part as $uD), + duo - tmp + ) + } + } + + duo_lz = duo.leading_zeros(); + + if div_lz <= duo_lz { + // quotient can have 0 or 1 added to it + if div <= duo { + return ( + quo + 1, + duo - div + ) + } else { + return ( + quo, + duo + ) + } + } + + // This can only happen if `div_sd < n` (because of previous "quo = 0 or 1" + // branches), but it is not worth it to unroll further. + if n <= duo_lz { + // simple division and addition + let tmp = $half_division(duo as $uX, div as $uX); + return ( + quo + (tmp.0 as $uD), + tmp.1 as $uD + ) + } + } + } + + /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a + /// tuple. + $( + #[$signed_attr] + )* + pub fn $signed_name(duo: $iD, div: $iD) -> ($iD, $iD) { + match (duo < 0, div < 0) { + (false, false) => { + let t = $unsigned_name(duo as $uD, div as $uD); + (t.0 as $iD, t.1 as $iD) + }, + (true, false) => { + let t = $unsigned_name(duo.wrapping_neg() as $uD, div as $uD); + ((t.0 as $iD).wrapping_neg(), (t.1 as $iD).wrapping_neg()) + }, + (false, true) => { + let t = $unsigned_name(duo as $uD, div.wrapping_neg() as $uD); + ((t.0 as $iD).wrapping_neg(), t.1 as $iD) + }, + (true, true) => { + let t = $unsigned_name(duo.wrapping_neg() as $uD, div.wrapping_neg() as $uD); + (t.0 as $iD, (t.1 as $iD).wrapping_neg()) + }, + } + } + } +} diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 49151594964e1..3cd9be93cb1b1 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -1,4 +1,4 @@ -use int::{Int, LargeInt}; +use int::specialized_div_rem::*; intrinsics! { #[maybe_use_optimized_c_shim] diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 34397e0d2564e..cbd23850b3f95 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,4 +1,5 @@ #![cfg_attr(feature = "compiler-builtins", compiler_builtins)] +#![cfg_attr(feature = "asm", feature(asm))] #![feature(abi_unadjusted)] #![feature(llvm_asm)] #![feature(global_asm)] diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 61282af0bf500..5c3df79619e2e 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -28,7 +28,8 @@ utest-cortex-m-qemu = { default-features = false, git = "https://github.com/japa%20utest-macros%20=%20%7B%20git%20="https://github.com/japaric/utest" } [features] +default = ["asm", "mangled-names"] +asm = ["compiler_builtins/asm"] c = ["compiler_builtins/c"] mem = ["compiler_builtins/mem"] mangled-names = ["compiler_builtins/mangled-names"] -default = ["mangled-names"] diff --git a/library/compiler-builtins/testcrate/tests/div_rem.rs b/library/compiler-builtins/testcrate/tests/div_rem.rs new file mode 100644 index 0000000000000..2a154f5eb7e58 --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/div_rem.rs @@ -0,0 +1,143 @@ +use rand_xoshiro::rand_core::{RngCore, SeedableRng}; +use rand_xoshiro::Xoshiro128StarStar; + +use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divti3, __modti3}; +use compiler_builtins::int::udiv::{__udivmoddi4, __udivmodsi4, __udivmodti4}; + +// because `__divmodti4` does not exist, we synthesize it +fn __divmodti4(a: i128, b: i128, rem: &mut i128) -> i128 { + *rem = __modti3(a, b); + __divti3(a, b) +} + +/// Creates intensive test functions for division functions of a certain size +macro_rules! test { + ( + $n:expr, // the number of bits in a $iX or $uX + $uX:ident, // unsigned integer that will be shifted + $iX:ident, // signed version of $uX + $test_name:ident, // name of the test function + $unsigned_name:ident, // unsigned division function + $signed_name:ident // signed division function + ) => { + #[test] + fn $test_name() { + fn assert_invariants(lhs: $uX, rhs: $uX) { + let rem: &mut $uX = &mut 0; + let quo: $uX = $unsigned_name(lhs, rhs, Some(rem)); + let rem = *rem; + if rhs <= rem || (lhs != rhs.wrapping_mul(quo).wrapping_add(rem)) { + panic!( + "unsigned division function failed with lhs:{} rhs:{} \ + expected:({}, {}) found:({}, {})", + lhs, + rhs, + lhs.wrapping_div(rhs), + lhs.wrapping_rem(rhs), + quo, + rem + ); + } + + // test the signed division function also + let lhs = lhs as $iX; + let rhs = rhs as $iX; + let mut rem: $iX = 0; + let quo: $iX = $signed_name(lhs, rhs, &mut rem); + // We cannot just test that + // `lhs == rhs.wrapping_mul(quo).wrapping_add(rem)`, but also + // need to make sure the remainder isn't larger than the divisor + // and has the correct sign. + let incorrect_rem = if rem == 0 { + false + } else if rhs == $iX::MIN { + // `rhs.wrapping_abs()` would overflow, so handle this case + // separately. + (lhs.is_negative() != rem.is_negative()) || (rem == $iX::MIN) + } else { + (lhs.is_negative() != rem.is_negative()) + || (rhs.wrapping_abs() <= rem.wrapping_abs()) + }; + if incorrect_rem || lhs != rhs.wrapping_mul(quo).wrapping_add(rem) { + panic!( + "signed division function failed with lhs:{} rhs:{} \ + expected:({}, {}) found:({}, {})", + lhs, + rhs, + lhs.wrapping_div(rhs), + lhs.wrapping_rem(rhs), + quo, + rem + ); + } + } + + // Specially designed random fuzzer + let mut rng = Xoshiro128StarStar::seed_from_u64(0); + let mut lhs: $uX = 0; + let mut rhs: $uX = 0; + // all ones constant + let ones: $uX = !0; + // Alternating ones and zeros (e.x. 0b1010101010101010). This catches second-order + // problems that might occur for algorithms with two modes of operation (potentially + // there is some invariant that can be broken for large `duo` and maintained via + // alternating between modes, breaking the algorithm when it reaches the end). + let mut alt_ones: $uX = 1; + for _ in 0..($n / 2) { + alt_ones <<= 2; + alt_ones |= 1; + } + // creates a mask for indexing the bits of the type + let bit_indexing_mask = $n - 1; + for _ in 0..1_000_000 { + // Randomly OR, AND, and XOR randomly sized and shifted continuous strings of + // ones with `lhs` and `rhs`. This results in excellent fuzzing entropy such as: + // lhs:10101010111101000000000100101010 rhs: 1010101010000000000000001000001 + // lhs:10101010111101000000000101001010 rhs: 1010101010101010101010100010100 + // lhs:10101010111101000000000101001010 rhs:11101010110101010101010100001110 + // lhs:10101010000000000000000001001010 rhs:10100010100000000000000000001010 + // lhs:10101010000000000000000001001010 rhs: 10101010101010101000 + // lhs:10101010000000000000000001100000 rhs:11111111111101010101010101001111 + // lhs:10101010000000101010101011000000 rhs:11111111111101010101010100000111 + // lhs:10101010101010101010101011101010 rhs: 1010100000000000000 + // lhs:11111111110101101010101011010111 rhs: 1010100000000000000 + // The msb is set half of the time by the fuzzer, but `assert_invariants` tests + // both the signed and unsigned functions. + let r0: u32 = bit_indexing_mask & rng.next_u32(); + let r1: u32 = bit_indexing_mask & rng.next_u32(); + let mask = ones.wrapping_shr(r0).rotate_left(r1); + match rng.next_u32() % 8 { + 0 => lhs |= mask, + 1 => lhs &= mask, + // both 2 and 3 to make XORs as common as ORs and ANDs combined, otherwise + // the entropy gets destroyed too often + 2 | 3 => lhs ^= mask, + 4 => rhs |= mask, + 5 => rhs &= mask, + _ => rhs ^= mask, + } + // do the same for alternating ones and zeros + let r0: u32 = bit_indexing_mask & rng.next_u32(); + let r1: u32 = bit_indexing_mask & rng.next_u32(); + let mask = alt_ones.wrapping_shr(r0).rotate_left(r1); + match rng.next_u32() % 8 { + 0 => lhs |= mask, + 1 => lhs &= mask, + // both 2 and 3 to make XORs as common as ORs and ANDs combined, otherwise + // the entropy gets destroyed too often + 2 | 3 => lhs ^= mask, + 4 => rhs |= mask, + 5 => rhs &= mask, + _ => rhs ^= mask, + } + if rhs != 0 { + assert_invariants(lhs, rhs); + } + } + } + }; +} + +test!(32, u32, i32, div_rem_si4, __udivmodsi4, __divmodsi4); +test!(64, u64, i64, div_rem_di4, __udivmoddi4, __divmoddi4); +test!(128, u128, i128, div_rem_ti4, __udivmodti4, __divmodti4); From 11ae780481cd42edd7d3b9189536b724b4cac8c8 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Tue, 21 Jul 2020 23:16:52 -0500 Subject: [PATCH 0866/4206] Change inlining to favor three underlying division functions --- .../src/int/specialized_div_rem/mod.rs | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index 5a034dcf10b09..0304aa2e7daea 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -113,6 +113,13 @@ fn u64_by_u64_div_rem(duo: u64, div: u64) -> (u64, u64) { zero_div_fn() } +// `inline(never)` is placed on unsigned division functions so that there are just three division +// functions (`u32_div_rem`, `u64_div_rem`, and `u128_div_rem`) backing all `compiler-builtins` +// division functions. The signed functions like `i32_div_rem` will get inlined into the +// `compiler-builtins` signed division functions, so that they directly call the three division +// functions. Otherwise, LLVM may try to inline the unsigned division functions 4 times into the +// signed division functions, which results in an explosion in code size. + // Whether `trifecta` or `delegate` is faster for 128 bit division depends on the speed at which a // microarchitecture can multiply and divide. We decide to be optimistic and assume `trifecta` is // faster if the target pointer width is at least 64. @@ -129,7 +136,9 @@ impl_trifecta!( u32, u64, u128, - i128,; + i128, + inline(never); + inline ); // If the pointer width less than 64, then the target architecture almost certainly does not have @@ -148,7 +157,9 @@ impl_delegate!( u32, u64, u128, - i128,; + i128, + inline(never); + inline ); /// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. @@ -190,7 +201,9 @@ impl_asymmetric!( u32, u64, u128, - i128,; + i128, + inline(never); + inline ); /// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. @@ -223,7 +236,9 @@ impl_delegate!( u16, u32, u64, - i64,; + i64, + inline(never); + inline ); // When not on x86 and the pointer width is 64, use `binary_long`. @@ -238,7 +253,9 @@ impl_binary_long!( u64_normalization_shift, 64, u64, - i64,; + i64, + inline(never); + inline ); /// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. @@ -280,7 +297,9 @@ impl_asymmetric!( u16, u32, u64, - i64,; + i64, + inline(never); + inline ); // 32 bits is the smallest division used by `compiler-builtins`, so we end with binary long division @@ -291,5 +310,7 @@ impl_binary_long!( u32_normalization_shift, 32, u32, - i32,; + i32, + inline(never); + inline ); From ffb386369b280fe3e19ae2f004ebb71e7d72f801 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Fri, 14 Aug 2020 15:28:48 -0500 Subject: [PATCH 0867/4206] Use unreachable_unchecked --- library/compiler-builtins/src/int/specialized_div_rem/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index 0304aa2e7daea..f7dc044fa278f 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -57,9 +57,7 @@ mod asymmetric; /// impossible to reach by Rust users, unless `compiler-builtins` public division functions or /// `core/std::unchecked_div/rem` are directly used without a zero check in front. fn zero_div_fn() -> ! { - // TODO: change this once the algorithms are verified - //unsafe {core::hint::unreachable_unchecked()} - ::abort() + unsafe { core::hint::unreachable_unchecked() } } // The `B` extension on RISC-V determines if a CLZ assembly instruction exists From 51e969665e94ca3dd5af04026ea110059e9633d0 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 23 Aug 2020 23:31:51 +0100 Subject: [PATCH 0868/4206] Fix CI url for compiler-rt source --- library/compiler-builtins/.github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 1237bc032670a..e4bcc9c10529f 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -88,8 +88,8 @@ jobs: - run: rustup component add llvm-tools-preview - name: Download compiler-rt reference sources run: | - curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/10.0-2020-02-05.tar.gz - tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-10.0-2020-02-05/compiler-rt + curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/10.0-2020-05-05.tar.gz + tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-10.0-2020-05-05/compiler-rt echo "##[set-env name=RUST_COMPILER_RT_ROOT]./compiler-rt" shell: bash From 29791313f5a81f0d933c3a3a1be836e7b4922ca9 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Thu, 6 Aug 2020 10:59:15 +0200 Subject: [PATCH 0869/4206] add compiler-rt fallbacks on aarch64-musl --- library/compiler-builtins/build.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index a3b722ab7766d..f948edba9eb2f 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -419,6 +419,18 @@ mod c { if target_os != "windows" { sources.extend(&[("__multc3", "multc3.c")]); } + + if target_env == "musl" { + sources.extend(&[ + ("__addtf3", "addtf3.c"), + ("__multf3", "multf3.c"), + ("__subtf3", "subtf3.c"), + ("__divtf3", "divtf3.c"), + ("__powitf2", "powitf2.c"), + ("__fe_getround", "fp_mode.c"), + ("__fe_raise_inexact", "fp_mode.c"), + ]); + } } if target_arch == "mips" { From 9daf318bef7ff97a970ebc26613e6a29c8f748a9 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 24 Aug 2020 12:45:58 +0100 Subject: [PATCH 0870/4206] Bump to 0.1.33 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index d4d1ad67d3840..957fd7bebfc81 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.32" +version = "0.1.33" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 29cfa6fba9b1b98868b6dd640b8d16fc8886a6cc Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 27 Aug 2020 17:49:46 +0100 Subject: [PATCH 0871/4206] Bump to 0.1.34 0.1.33 was published without the libm submodule --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 957fd7bebfc81..60429681dbd7f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.33" +version = "0.1.34" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From c9c145c6d732c1bd0632b29d327f5068c3c6d760 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 28 Aug 2020 01:35:29 +0100 Subject: [PATCH 0872/4206] Bump to 0.1.35 This time using the proper procedure for including libm. --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 60429681dbd7f..b4fbb0b1e9336 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.34" +version = "0.1.35" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 92f068074323bf09c2bce05edab034de11fa1d76 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Sat, 29 Aug 2020 18:02:57 -0500 Subject: [PATCH 0873/4206] Add `__divmodti4` --- library/compiler-builtins/src/int/sdiv.rs | 9 ++++++++- library/compiler-builtins/testcrate/build.rs | 13 +++++++++++++ .../compiler-builtins/testcrate/tests/div_rem.rs | 8 +------- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 57ef03cdaa502..3d0c3afc11def 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -54,5 +54,12 @@ intrinsics! { i128_div_rem(a, b).1 } - // LLVM does not currently have a `__divmodti4` function + // LLVM does not currently have a `__divmodti4` function, but GCC does + #[maybe_use_optimized_c_shim] + /// Returns `n / d` and sets `*rem = n % d` + pub extern "C" fn __divmodti4(a: i128, b: i128, rem: &mut i128) -> i128 { + let quo_rem = i128_div_rem(a, b); + *rem = quo_rem.1; + quo_rem.0 + } } diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index e1d4cf9e818c3..656fd2d20b716 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -805,6 +805,19 @@ fn main() { (builtins::int::sdiv::__divmodsi4(a, b, &mut r), r) }", ); + gen( + |(a, b): (MyI128, MyI128)| { + if b.0 == 0 { + None + } else { + Some((a.0 / b.0, a.0 % b.0)) + } + }, + "{ + let mut r = 0; + (builtins::int::sdiv::__divmodti4(a, b, &mut r), r) + }", + ); gen( |(a, b): (MyI32, MyI32)| { if b.0 == 0 { diff --git a/library/compiler-builtins/testcrate/tests/div_rem.rs b/library/compiler-builtins/testcrate/tests/div_rem.rs index 2a154f5eb7e58..199fa9db71c20 100644 --- a/library/compiler-builtins/testcrate/tests/div_rem.rs +++ b/library/compiler-builtins/testcrate/tests/div_rem.rs @@ -1,15 +1,9 @@ use rand_xoshiro::rand_core::{RngCore, SeedableRng}; use rand_xoshiro::Xoshiro128StarStar; -use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divti3, __modti3}; +use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divmodti4}; use compiler_builtins::int::udiv::{__udivmoddi4, __udivmodsi4, __udivmodti4}; -// because `__divmodti4` does not exist, we synthesize it -fn __divmodti4(a: i128, b: i128, rem: &mut i128) -> i128 { - *rem = __modti3(a, b); - __divti3(a, b) -} - /// Creates intensive test functions for division functions of a certain size macro_rules! test { ( From 53b15eaba20b9fb573d343938c4547e5815b6d81 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 13 Sep 2020 20:47:25 +0100 Subject: [PATCH 0874/4206] Bump to 0.1.36 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 4ee76946592ad..9262bb6d64f13 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.35" +version = "0.1.36" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 1dfa14595ef13349d31891c805b9bca505a8d09d Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Fri, 2 Oct 2020 16:35:55 -0500 Subject: [PATCH 0875/4206] Remove unneeded code from asymmetric.rs Rebenchmarking this showed that perf changed for the worse only on really low end CPUs --- .../src/int/specialized_div_rem/asymmetric.rs | 105 ++++-------------- 1 file changed, 20 insertions(+), 85 deletions(-) diff --git a/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs b/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs index 861e917426732..16ab2baadeaba 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs @@ -25,20 +25,8 @@ macro_rules! impl_asymmetric { #[$unsigned_attr] )* pub fn $unsigned_name(duo: $uD, div: $uD) -> ($uD,$uD) { - fn carrying_mul(lhs: $uX, rhs: $uX) -> ($uX, $uX) { - let tmp = (lhs as $uD).wrapping_mul(rhs as $uD); - (tmp as $uX, (tmp >> ($n_h * 2)) as $uX) - } - fn carrying_mul_add(lhs: $uX, mul: $uX, add: $uX) -> ($uX, $uX) { - let tmp = (lhs as $uD).wrapping_mul(mul as $uD).wrapping_add(add as $uD); - (tmp as $uX, (tmp >> ($n_h * 2)) as $uX) - } - let n: u32 = $n_h * 2; - // Many of these subalgorithms are taken from trifecta.rs, see that for better - // documentation. - let duo_lo = duo as $uX; let duo_hi = (duo >> n) as $uX; let div_lo = div as $uX; @@ -51,30 +39,6 @@ macro_rules! impl_asymmetric { // `$uD` by `$uX` division with a quotient that will fit into a `$uX` let (quo, rem) = unsafe { $asymmetric_division(duo, div_lo) }; return (quo as $uD, rem as $uD) - } else if (div_lo >> $n_h) == 0 { - // Short division of $uD by a $uH. - - // Some x86_64 CPUs have bad division implementations that make specializing - // this case faster. - let div_0 = div_lo as $uH as $uX; - let (quo_hi, rem_3) = $half_division(duo_hi, div_0); - - let duo_mid = - ((duo >> $n_h) as $uH as $uX) - | (rem_3 << $n_h); - let (quo_1, rem_2) = $half_division(duo_mid, div_0); - - let duo_lo = - (duo as $uH as $uX) - | (rem_2 << $n_h); - let (quo_0, rem_1) = $half_division(duo_lo, div_0); - - return ( - (quo_0 as $uD) - | ((quo_1 as $uD) << $n_h) - | ((quo_hi as $uD) << n), - rem_1 as $uD - ) } else { // Short division using the $uD by $uX division let (quo_hi, rem_hi) = $half_division(duo_hi, div_lo); @@ -85,59 +49,30 @@ macro_rules! impl_asymmetric { } } - let duo_lz = duo_hi.leading_zeros(); + // This has been adapted from + // https://www.codeproject.com/tips/785014/uint-division-modulus which was in turn + // adapted from Hacker's Delight. This is similar to the two possibility algorithm + // in that it uses only more significant parts of `duo` and `div` to divide a large + // integer with a smaller division instruction. let div_lz = div_hi.leading_zeros(); - let rel_leading_sb = div_lz.wrapping_sub(duo_lz); - if rel_leading_sb < $n_h { - // Some x86_64 CPUs have bad hardware division implementations that make putting - // a two possibility algorithm here beneficial. We also avoid a full `$uD` - // multiplication. - let shift = n - duo_lz; - let duo_sig_n = (duo >> shift) as $uX; - let div_sig_n = (div >> shift) as $uX; - let quo = $half_division(duo_sig_n, div_sig_n).0; - let div_lo = div as $uX; - let div_hi = (div >> n) as $uX; - let (tmp_lo, carry) = carrying_mul(quo, div_lo); - let (tmp_hi, overflow) = carrying_mul_add(quo, div_hi, carry); - let tmp = (tmp_lo as $uD) | ((tmp_hi as $uD) << n); - if (overflow != 0) || (duo < tmp) { - return ( - (quo - 1) as $uD, - duo.wrapping_add(div).wrapping_sub(tmp) - ) - } else { - return ( - quo as $uD, - duo - tmp - ) - } - } else { - // This has been adapted from - // https://www.codeproject.com/tips/785014/uint-division-modulus which was in turn - // adapted from Hacker's Delight. This is similar to the two possibility algorithm - // in that it uses only more significant parts of `duo` and `div` to divide a large - // integer with a smaller division instruction. - - let div_extra = n - div_lz; - let div_sig_n = (div >> div_extra) as $uX; - let tmp = unsafe { - $asymmetric_division(duo >> 1, div_sig_n) - }; + let div_extra = n - div_lz; + let div_sig_n = (div >> div_extra) as $uX; + let tmp = unsafe { + $asymmetric_division(duo >> 1, div_sig_n) + }; - let mut quo = tmp.0 >> ((n - 1) - div_lz); - if quo != 0 { - quo -= 1; - } + let mut quo = tmp.0 >> ((n - 1) - div_lz); + if quo != 0 { + quo -= 1; + } - // Note that this is a full `$uD` multiplication being used here - let mut rem = duo - (quo as $uD).wrapping_mul(div); - if div <= rem { - quo += 1; - rem -= div; - } - return (quo as $uD, rem) + // Note that this is a full `$uD` multiplication being used here + let mut rem = duo - (quo as $uD).wrapping_mul(div); + if div <= rem { + quo += 1; + rem -= div; } + return (quo as $uD, rem) } /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a From 756a9dea00035d81b44956e552df978b307dbc97 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Fri, 2 Oct 2020 22:04:05 -0500 Subject: [PATCH 0876/4206] Construct signed division functions differently --- library/compiler-builtins/src/int/sdiv.rs | 207 +++++++++++++----- .../src/int/specialized_div_rem/asymmetric.rs | 53 +---- .../int/specialized_div_rem/binary_long.rs | 64 +----- .../src/int/specialized_div_rem/delegate.rs | 76 ++----- .../src/int/specialized_div_rem/mod.rs | 45 +--- .../src/int/specialized_div_rem/trifecta.rs | 105 +++------ 6 files changed, 221 insertions(+), 329 deletions(-) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 3d0c3afc11def..e1e3f33bbd00f 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -1,65 +1,166 @@ -use int::specialized_div_rem::*; +use int::udiv::*; -intrinsics! { - #[maybe_use_optimized_c_shim] - #[arm_aeabi_alias = __aeabi_idiv] - /// Returns `n / d` - pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 { - i32_div_rem(a, b).0 - } - - #[maybe_use_optimized_c_shim] - /// Returns `n % d` - pub extern "C" fn __modsi3(a: i32, b: i32) -> i32 { - i32_div_rem(a, b).1 - } - - #[maybe_use_optimized_c_shim] - /// Returns `n / d` and sets `*rem = n % d` - pub extern "C" fn __divmodsi4(a: i32, b: i32, rem: &mut i32) -> i32 { - let quo_rem = i32_div_rem(a, b); - *rem = quo_rem.1; - quo_rem.0 +macro_rules! sdivmod { + ( + $unsigned_fn:ident, // name of the unsigned division function + $signed_fn:ident, // name of the signed division function + $uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` + $iX:ident, // signed integer type for the inputs and outputs of `$signed_name` + $($attr:tt),* // attributes + ) => { + intrinsics! { + $( + #[$attr] + )* + /// Returns `n / d` and sets `*rem = n % d` + pub extern "C" fn $signed_fn(a: $iX, b: $iX, rem: &mut $iX) -> $iX { + let a_neg = a < 0; + let b_neg = b < 0; + let mut a = a; + let mut b = b; + if a_neg { + a = a.wrapping_neg(); + } + if b_neg { + b = b.wrapping_neg(); + } + let mut r = *rem as $uX; + let t = $unsigned_fn(a as $uX, b as $uX, Some(&mut r)) as $iX; + let mut r = r as $iX; + if a_neg { + r = r.wrapping_neg(); + } + *rem = r; + if a_neg != b_neg { + t.wrapping_neg() + } else { + t + } + } + } } +} - #[maybe_use_optimized_c_shim] - /// Returns `n / d` - pub extern "C" fn __divdi3(a: i64, b: i64) -> i64 { - i64_div_rem(a, b).0 +macro_rules! sdiv { + ( + $unsigned_fn:ident, // name of the unsigned division function + $signed_fn:ident, // name of the signed division function + $uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` + $iX:ident, // signed integer type for the inputs and outputs of `$signed_name` + $($attr:tt),* // attributes + ) => { + intrinsics! { + $( + #[$attr] + )* + /// Returns `n / d` + pub extern "C" fn $signed_fn(a: $iX, b: $iX) -> $iX { + let a_neg = a < 0; + let b_neg = b < 0; + let mut a = a; + let mut b = b; + if a_neg { + a = a.wrapping_neg(); + } + if b_neg { + b = b.wrapping_neg(); + } + let t = $unsigned_fn(a as $uX, b as $uX) as $iX; + if a_neg != b_neg { + t.wrapping_neg() + } else { + t + } + } + } } +} - #[maybe_use_optimized_c_shim] - /// Returns `n % d` - pub extern "C" fn __moddi3(a: i64, b: i64) -> i64 { - i64_div_rem(a, b).1 +macro_rules! smod { + ( + $unsigned_fn:ident, // name of the unsigned division function + $signed_fn:ident, // name of the signed division function + $uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` + $iX:ident, // signed integer type for the inputs and outputs of `$signed_name` + $($attr:tt),* // attributes + ) => { + intrinsics! { + $( + #[$attr] + )* + /// Returns `n % d` + pub extern "C" fn $signed_fn(a: $iX, b: $iX) -> $iX { + let a_neg = a < 0; + let b_neg = b < 0; + let mut a = a; + let mut b = b; + if a_neg { + a = a.wrapping_neg(); + } + if b_neg { + b = b.wrapping_neg(); + } + let r = $unsigned_fn(a as $uX, b as $uX) as $iX; + if a_neg { + r.wrapping_neg() + } else { + r + } + } + } } +} +sdivmod!( + __udivmodsi4, + __divmodsi4, + u32, + i32, + maybe_use_optimized_c_shim +); +// The `#[arm_aeabi_alias = __aeabi_idiv]` attribute cannot be made to work with `intrinsics!` in macros +intrinsics! { #[maybe_use_optimized_c_shim] - /// Returns `n / d` and sets `*rem = n % d` - pub extern "C" fn __divmoddi4(a: i64, b: i64, rem: &mut i64) -> i64 { - let quo_rem = i64_div_rem(a, b); - *rem = quo_rem.1; - quo_rem.0 - } - - #[win64_128bit_abi_hack] + #[arm_aeabi_alias = __aeabi_idiv] /// Returns `n / d` - pub extern "C" fn __divti3(a: i128, b: i128) -> i128 { - i128_div_rem(a, b).0 + pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 { + let a_neg = a < 0; + let b_neg = b < 0; + let mut a = a; + let mut b = b; + if a_neg { + a = a.wrapping_neg(); + } + if b_neg { + b = b.wrapping_neg(); + } + let t = __udivsi3(a as u32, b as u32) as i32; + if a_neg != b_neg { + t.wrapping_neg() + } else { + t + } } +} +smod!(__umodsi3, __modsi3, u32, i32, maybe_use_optimized_c_shim); - #[win64_128bit_abi_hack] - /// Returns `n % d` - pub extern "C" fn __modti3(a: i128, b: i128) -> i128 { - i128_div_rem(a, b).1 - } +sdivmod!( + __udivmoddi4, + __divmoddi4, + u64, + i64, + maybe_use_optimized_c_shim +); +sdiv!(__udivdi3, __divdi3, u64, i64, maybe_use_optimized_c_shim); +smod!(__umoddi3, __moddi3, u64, i64, maybe_use_optimized_c_shim); - // LLVM does not currently have a `__divmodti4` function, but GCC does - #[maybe_use_optimized_c_shim] - /// Returns `n / d` and sets `*rem = n % d` - pub extern "C" fn __divmodti4(a: i128, b: i128, rem: &mut i128) -> i128 { - let quo_rem = i128_div_rem(a, b); - *rem = quo_rem.1; - quo_rem.0 - } -} +// LLVM does not currently have a `__divmodti4` function, but GCC does +sdivmod!( + __udivmodti4, + __divmodti4, + u128, + i128, + maybe_use_optimized_c_shim +); +sdiv!(__udivti3, __divti3, u128, i128, win64_128bit_abi_hack); +smod!(__umodti3, __modti3, u128, i128, win64_128bit_abi_hack); diff --git a/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs b/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs index 16ab2baadeaba..bbb77722dc98b 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs @@ -1,4 +1,4 @@ -/// Creates unsigned and signed division functions optimized for dividing integers with the same +/// Creates an unsigned division function optimized for dividing integers with the same /// bitwidth as the largest operand in an asymmetrically sized division. For example, x86-64 has an /// assembly instruction that can divide a 128 bit integer by a 64 bit integer if the quotient fits /// in 64 bits. The 128 bit version of this algorithm would use that fast hardware division to @@ -6,25 +6,18 @@ #[macro_export] macro_rules! impl_asymmetric { ( - $unsigned_name:ident, // name of the unsigned division function - $signed_name:ident, // name of the signed division function + $fn:ident, // name of the unsigned division function $zero_div_fn:ident, // function called when division by zero is attempted $half_division:ident, // function for division of a $uX by a $uX $asymmetric_division:ident, // function for division of a $uD by a $uX $n_h:expr, // the number of bits in a $iH or $uH $uH:ident, // unsigned integer with half the bit width of $uX $uX:ident, // unsigned integer with half the bit width of $uD - $uD:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` - $iD:ident, // signed integer type for the inputs and outputs of `$signed_name` - $($unsigned_attr:meta),*; // attributes for the unsigned function - $($signed_attr:meta),* // attributes for the signed function + $uD:ident // unsigned integer type for the inputs and outputs of `$fn` ) => { /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a /// tuple. - $( - #[$unsigned_attr] - )* - pub fn $unsigned_name(duo: $uD, div: $uD) -> ($uD,$uD) { + pub fn $fn(duo: $uD, div: $uD) -> ($uD, $uD) { let n: u32 = $n_h * 2; let duo_lo = duo as $uX; @@ -38,14 +31,14 @@ macro_rules! impl_asymmetric { if duo_hi < div_lo { // `$uD` by `$uX` division with a quotient that will fit into a `$uX` let (quo, rem) = unsafe { $asymmetric_division(duo, div_lo) }; - return (quo as $uD, rem as $uD) + return (quo as $uD, rem as $uD); } else { // Short division using the $uD by $uX division let (quo_hi, rem_hi) = $half_division(duo_hi, div_lo); let tmp = unsafe { $asymmetric_division((duo_lo as $uD) | ((rem_hi as $uD) << n), div_lo) }; - return ((tmp.0 as $uD) | ((quo_hi as $uD) << n), tmp.1 as $uD) + return ((tmp.0 as $uD) | ((quo_hi as $uD) << n), tmp.1 as $uD); } } @@ -57,9 +50,7 @@ macro_rules! impl_asymmetric { let div_lz = div_hi.leading_zeros(); let div_extra = n - div_lz; let div_sig_n = (div >> div_extra) as $uX; - let tmp = unsafe { - $asymmetric_division(duo >> 1, div_sig_n) - }; + let tmp = unsafe { $asymmetric_division(duo >> 1, div_sig_n) }; let mut quo = tmp.0 >> ((n - 1) - div_lz); if quo != 0 { @@ -72,33 +63,7 @@ macro_rules! impl_asymmetric { quo += 1; rem -= div; } - return (quo as $uD, rem) + return (quo as $uD, rem); } - - /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a - /// tuple. - $( - #[$signed_attr] - )* - pub fn $signed_name(duo: $iD, div: $iD) -> ($iD, $iD) { - match (duo < 0, div < 0) { - (false, false) => { - let t = $unsigned_name(duo as $uD, div as $uD); - (t.0 as $iD, t.1 as $iD) - }, - (true, false) => { - let t = $unsigned_name(duo.wrapping_neg() as $uD, div as $uD); - ((t.0 as $iD).wrapping_neg(), (t.1 as $iD).wrapping_neg()) - }, - (false, true) => { - let t = $unsigned_name(duo as $uD, div.wrapping_neg() as $uD); - ((t.0 as $iD).wrapping_neg(), t.1 as $iD) - }, - (true, true) => { - let t = $unsigned_name(duo.wrapping_neg() as $uD, div.wrapping_neg() as $uD); - (t.0 as $iD, (t.1 as $iD).wrapping_neg()) - }, - } - } - } + }; } diff --git a/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs b/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs index 4c63396a0889f..0f5e870b0eeb4 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs @@ -1,4 +1,4 @@ -/// Creates unsigned and signed division functions that use binary long division, designed for +/// Creates an unsigned division function that uses binary long division, designed for /// computer architectures without division instructions. These functions have good performance for /// microarchitectures with large branch miss penalties and architectures without the ability to /// predicate instructions. For architectures with predicated instructions, one of the algorithms @@ -7,29 +7,23 @@ #[macro_export] macro_rules! impl_binary_long { ( - $unsigned_name:ident, // name of the unsigned division function - $signed_name:ident, // name of the signed division function + $fn:ident, // name of the unsigned division function $zero_div_fn:ident, // function called when division by zero is attempted $normalization_shift:ident, // function for finding the normalization shift $n:tt, // the number of bits in a $iX or $uX - $uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` - $iX:ident, // signed integer type for the inputs and outputs of `$signed_name` - $($unsigned_attr:meta),*; // attributes for the unsigned function - $($signed_attr:meta),* // attributes for the signed function + $uX:ident, // unsigned integer type for the inputs and outputs of `$fn` + $iX:ident // signed integer type with same bitwidth as `$uX` ) => { /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a /// tuple. - $( - #[$unsigned_attr] - )* - pub fn $unsigned_name(duo: $uX, div: $uX) -> ($uX, $uX) { + pub fn $fn(duo: $uX, div: $uX) -> ($uX, $uX) { let mut duo = duo; // handle edge cases before calling `$normalization_shift` if div == 0 { $zero_div_fn() } if duo < div { - return (0, duo) + return (0, duo); } // There are many variations of binary division algorithm that could be used. This @@ -430,7 +424,7 @@ macro_rules! impl_binary_long { let mut i = shl; loop { if i == 0 { - break + break; } i -= 1; // shift left 1 and subtract @@ -550,47 +544,5 @@ macro_rules! impl_binary_long { return ((duo & mask) | quo, duo >> shl); */ } - - /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a - /// tuple. - $( - #[$signed_attr] - )* - pub fn $signed_name(duo: $iX, div: $iX) -> ($iX, $iX) { - // There is a way of doing this without any branches, but requires too many extra - // operations to be faster. - /* - let duo_s = duo >> ($n - 1); - let div_s = div >> ($n - 1); - let duo = (duo ^ duo_s).wrapping_sub(duo_s); - let div = (div ^ div_s).wrapping_sub(div_s); - let quo_s = duo_s ^ div_s; - let rem_s = duo_s; - let tmp = $unsigned_name(duo as $uX, div as $uX); - ( - ((tmp.0 as $iX) ^ quo_s).wrapping_sub(quo_s), - ((tmp.1 as $iX) ^ rem_s).wrapping_sub(rem_s), - ) - */ - - match (duo < 0, div < 0) { - (false, false) => { - let t = $unsigned_name(duo as $uX, div as $uX); - (t.0 as $iX, t.1 as $iX) - }, - (true, false) => { - let t = $unsigned_name(duo.wrapping_neg() as $uX, div as $uX); - ((t.0 as $iX).wrapping_neg(), (t.1 as $iX).wrapping_neg()) - }, - (false, true) => { - let t = $unsigned_name(duo as $uX, div.wrapping_neg() as $uX); - ((t.0 as $iX).wrapping_neg(), t.1 as $iX) - }, - (true, true) => { - let t = $unsigned_name(duo.wrapping_neg() as $uX, div.wrapping_neg() as $uX); - (t.0 as $iX, (t.1 as $iX).wrapping_neg()) - }, - } - } - } + }; } diff --git a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs index 1ba72431d61a7..a74bdac02d415 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs @@ -1,29 +1,23 @@ -/// Creates unsigned and signed division functions that use a combination of hardware division and +/// Creates an unsigned division function that uses a combination of hardware division and /// binary long division to divide integers larger than what hardware division by itself can do. This /// function is intended for microarchitectures that have division hardware, but not fast enough /// multiplication hardware for `impl_trifecta` to be faster. #[macro_export] macro_rules! impl_delegate { ( - $unsigned_name:ident, // name of the unsigned division function - $signed_name:ident, // name of the signed division function + $fn:ident, // name of the unsigned division function $zero_div_fn:ident, // function called when division by zero is attempted $half_normalization_shift:ident, // function for finding the normalization shift of $uX $half_division:ident, // function for division of a $uX by a $uX $n_h:expr, // the number of bits in $iH or $uH $uH:ident, // unsigned integer with half the bit width of $uX $uX:ident, // unsigned integer with half the bit width of $uD. - $uD:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` - $iD:ident, // signed integer type for the inputs and outputs of `$signed_name` - $($unsigned_attr:meta),*; // attributes for the unsigned function - $($signed_attr:meta),* // attributes for the signed function + $uD:ident, // unsigned integer type for the inputs and outputs of `$fn` + $iD:ident // signed integer type with the same bitwidth as `$uD` ) => { /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a /// tuple. - $( - #[$unsigned_attr] - )* - pub fn $unsigned_name(duo: $uD, div: $uD) -> ($uD, $uD) { + pub fn $fn(duo: $uD, div: $uD) -> ($uD, $uD) { // The two possibility algorithm, undersubtracting long division algorithm, or any kind // of reciprocal based algorithm will not be fastest, because they involve large // multiplications that we assume to not be fast enough relative to the divisions to @@ -38,17 +32,15 @@ macro_rules! impl_delegate { let div_hi = (div >> n) as $uX; match (div_lo == 0, div_hi == 0, duo_hi == 0) { - (true, true, _) => { - $zero_div_fn() - } + (true, true, _) => $zero_div_fn(), (_, false, true) => { // `duo` < `div` - return (0, duo) + return (0, duo); } (false, true, true) => { // delegate to smaller division let tmp = $half_division(duo_lo, div_lo); - return (tmp.0 as $uD, tmp.1 as $uD) + return (tmp.0 as $uD, tmp.1 as $uD); } (false, true, false) => { if duo_hi < div_lo { @@ -96,7 +88,7 @@ macro_rules! impl_delegate { // Delegate to get the rest of the quotient. Note that the // `div_lo` here is the original unshifted `div`. let tmp = $half_division(duo as $uX, div_lo); - return ((quo_lo | tmp.0) as $uD, tmp.1 as $uD) + return ((quo_lo | tmp.0) as $uD, tmp.1 as $uD); } } div >>= 1; @@ -105,7 +97,7 @@ macro_rules! impl_delegate { } else if duo_hi == div_lo { // `quo_hi == 1`. This branch is cheap and helps with edge cases. let tmp = $half_division(duo as $uX, div as $uX); - return ((1 << n) | (tmp.0 as $uD), tmp.1 as $uD) + return ((1 << n) | (tmp.0 as $uD), tmp.1 as $uD); } else { // `div_lo < duo_hi` // `rem_hi == 0` @@ -114,22 +106,16 @@ macro_rules! impl_delegate { let div_0 = div_lo as $uH as $uX; let (quo_hi, rem_3) = $half_division(duo_hi, div_0); - let duo_mid = - ((duo >> $n_h) as $uH as $uX) - | (rem_3 << $n_h); + let duo_mid = ((duo >> $n_h) as $uH as $uX) | (rem_3 << $n_h); let (quo_1, rem_2) = $half_division(duo_mid, div_0); - let duo_lo = - (duo as $uH as $uX) - | (rem_2 << $n_h); + let duo_lo = (duo as $uH as $uX) | (rem_2 << $n_h); let (quo_0, rem_1) = $half_division(duo_lo, div_0); return ( - (quo_0 as $uD) - | ((quo_1 as $uD) << $n_h) - | ((quo_hi as $uD) << n), - rem_1 as $uD - ) + (quo_0 as $uD) | ((quo_1 as $uD) << $n_h) | ((quo_hi as $uD) << n), + rem_1 as $uD, + ); } // This is basically a short division composed of a half division for the hi @@ -161,7 +147,7 @@ macro_rules! impl_delegate { let tmp = $half_division(duo as $uX, div_lo); return ( (tmp.0) as $uD | (quo_lo as $uD) | ((quo_hi as $uD) << n), - tmp.1 as $uD + tmp.1 as $uD, ); } } @@ -187,7 +173,7 @@ macro_rules! impl_delegate { duo = sub; quo_lo |= pow_lo; if duo < div_original { - return (quo_lo as $uD, duo) + return (quo_lo as $uD, duo); } } div >>= 1; @@ -196,31 +182,5 @@ macro_rules! impl_delegate { } } } - - /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a - /// tuple. - $( - #[$signed_attr] - )* - pub fn $signed_name(duo: $iD, div: $iD) -> ($iD, $iD) { - match (duo < 0, div < 0) { - (false, false) => { - let t = $unsigned_name(duo as $uD, div as $uD); - (t.0 as $iD, t.1 as $iD) - }, - (true, false) => { - let t = $unsigned_name(duo.wrapping_neg() as $uD, div as $uD); - ((t.0 as $iD).wrapping_neg(), (t.1 as $iD).wrapping_neg()) - }, - (false, true) => { - let t = $unsigned_name(duo as $uD, div.wrapping_neg() as $uD); - ((t.0 as $iD).wrapping_neg(), t.1 as $iD) - }, - (true, true) => { - let t = $unsigned_name(duo.wrapping_neg() as $uD, div.wrapping_neg() as $uD); - (t.0 as $iD, (t.1 as $iD).wrapping_neg()) - }, - } - } - } + }; } diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index f7dc044fa278f..3ac341b6f35d4 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -111,13 +111,6 @@ fn u64_by_u64_div_rem(duo: u64, div: u64) -> (u64, u64) { zero_div_fn() } -// `inline(never)` is placed on unsigned division functions so that there are just three division -// functions (`u32_div_rem`, `u64_div_rem`, and `u128_div_rem`) backing all `compiler-builtins` -// division functions. The signed functions like `i32_div_rem` will get inlined into the -// `compiler-builtins` signed division functions, so that they directly call the three division -// functions. Otherwise, LLVM may try to inline the unsigned division functions 4 times into the -// signed division functions, which results in an explosion in code size. - // Whether `trifecta` or `delegate` is faster for 128 bit division depends on the speed at which a // microarchitecture can multiply and divide. We decide to be optimistic and assume `trifecta` is // faster if the target pointer width is at least 64. @@ -127,16 +120,12 @@ fn u64_by_u64_div_rem(duo: u64, div: u64) -> (u64, u64) { ))] impl_trifecta!( u128_div_rem, - i128_div_rem, zero_div_fn, u64_by_u64_div_rem, 32, u32, u64, - u128, - i128, - inline(never); - inline + u128 ); // If the pointer width less than 64, then the target architecture almost certainly does not have @@ -147,7 +136,6 @@ impl_trifecta!( ))] impl_delegate!( u128_div_rem, - i128_div_rem, zero_div_fn, u64_normalization_shift, u64_by_u64_div_rem, @@ -155,9 +143,7 @@ impl_delegate!( u32, u64, u128, - i128, - inline(never); - inline + i128 ); /// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. @@ -191,17 +177,13 @@ unsafe fn u128_by_u64_div_rem(duo: u128, div: u64) -> (u64, u64) { #[cfg(all(feature = "asm", target_arch = "x86_64"))] impl_asymmetric!( u128_div_rem, - i128_div_rem, zero_div_fn, u64_by_u64_div_rem, u128_by_u64_div_rem, 32, u32, u64, - u128, - i128, - inline(never); - inline + u128 ); /// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. @@ -226,7 +208,6 @@ fn u32_by_u32_div_rem(duo: u32, div: u32) -> (u32, u32) { ))] impl_delegate!( u64_div_rem, - i64_div_rem, zero_div_fn, u32_normalization_shift, u32_by_u32_div_rem, @@ -234,9 +215,7 @@ impl_delegate!( u16, u32, u64, - i64, - inline(never); - inline + i64 ); // When not on x86 and the pointer width is 64, use `binary_long`. @@ -246,14 +225,11 @@ impl_delegate!( ))] impl_binary_long!( u64_div_rem, - i64_div_rem, zero_div_fn, u64_normalization_shift, 64, u64, - i64, - inline(never); - inline + i64 ); /// Divides `duo` by `div` and returns a tuple of the quotient and the remainder. @@ -287,28 +263,21 @@ unsafe fn u64_by_u32_div_rem(duo: u64, div: u32) -> (u32, u32) { #[cfg(all(feature = "asm", target_arch = "x86"))] impl_asymmetric!( u64_div_rem, - i64_div_rem, zero_div_fn, u32_by_u32_div_rem, u64_by_u32_div_rem, 16, u16, u32, - u64, - i64, - inline(never); - inline + u64 ); // 32 bits is the smallest division used by `compiler-builtins`, so we end with binary long division impl_binary_long!( u32_div_rem, - i32_div_rem, zero_div_fn, u32_normalization_shift, 32, u32, - i32, - inline(never); - inline + i32 ); diff --git a/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs b/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs index e76516f349093..65ce1c3f0724c 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs @@ -1,28 +1,21 @@ -/// Creates unsigned and signed division functions optimized for division of integers with bitwidths +/// Creates an unsigned division function optimized for division of integers with bitwidths /// larger than the largest hardware integer division supported. These functions use large radix /// division algorithms that require both fast division and very fast widening multiplication on the /// target microarchitecture. Otherwise, `impl_delegate` should be used instead. #[macro_export] macro_rules! impl_trifecta { ( - $unsigned_name:ident, // name of the unsigned division function - $signed_name:ident, // name of the signed division function + $fn:ident, // name of the unsigned division function $zero_div_fn:ident, // function called when division by zero is attempted $half_division:ident, // function for division of a $uX by a $uX $n_h:expr, // the number of bits in $iH or $uH $uH:ident, // unsigned integer with half the bit width of $uX $uX:ident, // unsigned integer with half the bit width of $uD - $uD:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name` - $iD:ident, // signed integer type for the inputs and outputs of `$signed_name` - $($unsigned_attr:meta),*; // attributes for the unsigned function - $($signed_attr:meta),* // attributes for the signed function + $uD:ident // unsigned integer type for the inputs and outputs of `$unsigned_name` ) => { /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a /// tuple. - $( - #[$unsigned_attr] - )* - pub fn $unsigned_name(duo: $uD, div: $uD) -> ($uD, $uD) { + pub fn $fn(duo: $uD, div: $uD) -> ($uD, $uD) { // This is called the trifecta algorithm because it uses three main algorithms: short // division for small divisors, the two possibility algorithm for large divisors, and an // undersubtracting long division algorithm for intermediate cases. @@ -34,7 +27,9 @@ macro_rules! impl_trifecta { (tmp as $uX, (tmp >> ($n_h * 2)) as $uX) } fn carrying_mul_add(lhs: $uX, mul: $uX, add: $uX) -> ($uX, $uX) { - let tmp = (lhs as $uD).wrapping_mul(mul as $uD).wrapping_add(add as $uD); + let tmp = (lhs as $uD) + .wrapping_mul(mul as $uD) + .wrapping_add(add as $uD); (tmp as $uX, (tmp >> ($n_h * 2)) as $uX) } @@ -62,9 +57,9 @@ macro_rules! impl_trifecta { // The quotient cannot be more than 1. The highest set bit of `duo` needs to be at // least one place higher than `div` for the quotient to be more than 1. if duo >= div { - return (1, duo - div) + return (1, duo - div); } else { - return (0, duo) + return (0, duo); } } @@ -76,10 +71,7 @@ macro_rules! impl_trifecta { // `duo < 2^n` so it will fit in a $uX. `div` will also fit in a $uX (because of the // `div_lz <= duo_lz` branch) so no numerical error. let (quo, rem) = $half_division(duo as $uX, div as $uX); - return ( - quo as $uD, - rem as $uD - ) + return (quo as $uD, rem as $uD); } // `{2^n, 2^div_sb} <= duo < 2^n_d` @@ -99,22 +91,16 @@ macro_rules! impl_trifecta { let div_0 = div as $uH as $uX; let (quo_hi, rem_3) = $half_division(duo_hi, div_0); - let duo_mid = - ((duo >> $n_h) as $uH as $uX) - | (rem_3 << $n_h); + let duo_mid = ((duo >> $n_h) as $uH as $uX) | (rem_3 << $n_h); let (quo_1, rem_2) = $half_division(duo_mid, div_0); - let duo_lo = - (duo as $uH as $uX) - | (rem_2 << $n_h); + let duo_lo = (duo as $uH as $uX) | (rem_2 << $n_h); let (quo_0, rem_1) = $half_division(duo_lo, div_0); return ( - (quo_0 as $uD) - | ((quo_1 as $uD) << $n_h) - | ((quo_hi as $uD) << n), - rem_1 as $uD - ) + (quo_0 as $uD) | ((quo_1 as $uD) << $n_h) | ((quo_hi as $uD) << n), + rem_1 as $uD, + ); } // relative leading significant bits, cannot overflow because of above branches @@ -237,13 +223,10 @@ macro_rules! impl_trifecta { (quo - 1) as $uD, // Both the addition and subtraction can overflow, but when combined end up // as a correct positive number. - duo.wrapping_add(div).wrapping_sub(tmp) - ) + duo.wrapping_add(div).wrapping_sub(tmp), + ); } else { - return ( - quo as $uD, - duo - tmp - ) + return (quo as $uD, duo - tmp); } } @@ -372,13 +355,10 @@ macro_rules! impl_trifecta { if duo < tmp { return ( quo + ((quo_part - 1) as $uD), - duo.wrapping_add(div).wrapping_sub(tmp) - ) + duo.wrapping_add(div).wrapping_sub(tmp), + ); } else { - return ( - quo + (quo_part as $uD), - duo - tmp - ) + return (quo + (quo_part as $uD), duo - tmp); } } @@ -387,15 +367,9 @@ macro_rules! impl_trifecta { if div_lz <= duo_lz { // quotient can have 0 or 1 added to it if div <= duo { - return ( - quo + 1, - duo - div - ) + return (quo + 1, duo - div); } else { - return ( - quo, - duo - ) + return (quo, duo); } } @@ -404,38 +378,9 @@ macro_rules! impl_trifecta { if n <= duo_lz { // simple division and addition let tmp = $half_division(duo as $uX, div as $uX); - return ( - quo + (tmp.0 as $uD), - tmp.1 as $uD - ) + return (quo + (tmp.0 as $uD), tmp.1 as $uD); } } } - - /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a - /// tuple. - $( - #[$signed_attr] - )* - pub fn $signed_name(duo: $iD, div: $iD) -> ($iD, $iD) { - match (duo < 0, div < 0) { - (false, false) => { - let t = $unsigned_name(duo as $uD, div as $uD); - (t.0 as $iD, t.1 as $iD) - }, - (true, false) => { - let t = $unsigned_name(duo.wrapping_neg() as $uD, div as $uD); - ((t.0 as $iD).wrapping_neg(), (t.1 as $iD).wrapping_neg()) - }, - (false, true) => { - let t = $unsigned_name(duo as $uD, div.wrapping_neg() as $uD); - ((t.0 as $iD).wrapping_neg(), t.1 as $iD) - }, - (true, true) => { - let t = $unsigned_name(duo.wrapping_neg() as $uD, div.wrapping_neg() as $uD); - (t.0 as $iD, (t.1 as $iD).wrapping_neg()) - }, - } - } - } + }; } From d2a252503504adbc84de2c838f873eacfc04b829 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Fri, 2 Oct 2020 23:26:12 -0500 Subject: [PATCH 0877/4206] Hide macros and functions These macros and functions are only in the public interface for testing purposes or because of `#[macro_export]` pollution --- library/compiler-builtins/src/int/leading_zeros.rs | 2 ++ .../compiler-builtins/src/int/specialized_div_rem/asymmetric.rs | 1 + .../src/int/specialized_div_rem/binary_long.rs | 1 + .../compiler-builtins/src/int/specialized_div_rem/delegate.rs | 1 + .../compiler-builtins/src/int/specialized_div_rem/norm_shift.rs | 1 + .../compiler-builtins/src/int/specialized_div_rem/trifecta.rs | 1 + 6 files changed, 7 insertions(+) diff --git a/library/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/src/int/leading_zeros.rs index 78556f0bcf639..e4a9e5eb2b497 100644 --- a/library/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/src/int/leading_zeros.rs @@ -4,6 +4,7 @@ // Compilers will insert the check for zero in cases where it is needed. /// Returns the number of leading binary zeros in `x`. +#[doc(hidden)] pub fn usize_leading_zeros_default(x: usize) -> usize { // The basic idea is to test if the higher bits of `x` are zero and bisect the number // of leading zeros. It is possible for all branches of the bisection to use the same @@ -75,6 +76,7 @@ pub fn usize_leading_zeros_default(x: usize) -> usize { // RISC-V that allows `(x >= power-of-two) as usize` to be branchless. /// Returns the number of leading binary zeros in `x`. +#[doc(hidden)] pub fn usize_leading_zeros_riscv(x: usize) -> usize { let mut x = x; // the number of potential leading zeros diff --git a/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs b/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs index bbb77722dc98b..45da657e9c974 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs @@ -3,6 +3,7 @@ /// assembly instruction that can divide a 128 bit integer by a 64 bit integer if the quotient fits /// in 64 bits. The 128 bit version of this algorithm would use that fast hardware division to /// construct a full 128 bit by 128 bit division. +#[doc(hidden)] #[macro_export] macro_rules! impl_asymmetric { ( diff --git a/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs b/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs index 0f5e870b0eeb4..7de10e8527691 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs @@ -4,6 +4,7 @@ /// predicate instructions. For architectures with predicated instructions, one of the algorithms /// described in the documentation of these functions probably has higher performance, and a custom /// assembly routine should be used instead. +#[doc(hidden)] #[macro_export] macro_rules! impl_binary_long { ( diff --git a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs index a74bdac02d415..8310c142956fc 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs @@ -2,6 +2,7 @@ /// binary long division to divide integers larger than what hardware division by itself can do. This /// function is intended for microarchitectures that have division hardware, but not fast enough /// multiplication hardware for `impl_trifecta` to be faster. +#[doc(hidden)] #[macro_export] macro_rules! impl_delegate { ( diff --git a/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs b/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs index 33348b373610a..be95d1b927ee1 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs @@ -1,4 +1,5 @@ /// Creates a function used by some division algorithms to compute the "normalization shift". +#[doc(hidden)] #[macro_export] macro_rules! impl_normalization_shift { ( diff --git a/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs b/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs index 65ce1c3f0724c..a9ea603019d82 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs @@ -2,6 +2,7 @@ /// larger than the largest hardware integer division supported. These functions use large radix /// division algorithms that require both fast division and very fast widening multiplication on the /// target microarchitecture. Otherwise, `impl_delegate` should be used instead. +#[doc(hidden)] #[macro_export] macro_rules! impl_trifecta { ( From f9bf5fee785fb58292d409e74e620a64ed456c89 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 15 Oct 2020 00:10:38 +0800 Subject: [PATCH 0878/4206] Use weak linkage for aeabi memory functions (#385) --- library/compiler-builtins/src/arm.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 190bba7262027..3a25060919702 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -138,18 +138,20 @@ pub unsafe fn __aeabi_ldivmod() { intrinsics::unreachable(); } +// The following functions use weak linkage to allow users to override +// with custom implementation. // FIXME: The `*4` and `*8` variants should be defined as aliases. #[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg_attr(thumb, linkage = "weak")] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { ::mem::memcpy(dest, src, n); } #[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg_attr(thumb, linkage = "weak")] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, mut n: usize) { // We are guaranteed 4-alignment, so accessing at u32 is okay. let mut dest = dest as *mut u32; @@ -167,35 +169,35 @@ pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, mut #[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg_attr(thumb, linkage = "weak")] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memcpy4(dest, src, n); } #[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg_attr(thumb, linkage = "weak")] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { ::mem::memmove(dest, src, n); } #[cfg(not(any(target_os = "ios", target_env = "msvc")))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg_attr(thumb, linkage = "weak")] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memmove(dest, src, n); } #[cfg(not(any(target_os = "ios", target_env = "msvc")))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg_attr(thumb, linkage = "weak")] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memmove(dest, src, n); } #[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg_attr(thumb, linkage = "weak")] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { // Note the different argument order ::mem::memset(dest, c, n); @@ -203,7 +205,7 @@ pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { #[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg_attr(thumb, linkage = "weak")] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, mut n: usize, c: i32) { let mut dest = dest as *mut u32; @@ -221,28 +223,28 @@ pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, mut n: usize, c: i32 #[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg_attr(thumb, linkage = "weak")] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { __aeabi_memset4(dest, n, c); } #[cfg(not(target_os = "ios"))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg_attr(thumb, linkage = "weak")] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { __aeabi_memset(dest, n, 0); } #[cfg(not(any(target_os = "ios", target_env = "msvc")))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg_attr(thumb, linkage = "weak")] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); } #[cfg(not(any(target_os = "ios", target_env = "msvc")))] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[cfg_attr(thumb, linkage = "weak")] +#[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); } From 34e35d74b66f9473c29e75548196d6f4d53609fa Mon Sep 17 00:00:00 2001 From: Joseph Richey Date: Sat, 24 Oct 2020 08:58:04 -0700 Subject: [PATCH 0879/4206] Use REP MOVSQ/STOSQ on x86_64 (#365) * mem: Move mem* functions to separate directory Signed-off-by: Joe Richey * memcpy: Create separate memcpy.rs file Signed-off-by: Joe Richey * benches: Add benchmarks for mem* functions This allows comparing the "normal" implementations to the implementations provided by this crate. Signed-off-by: Joe Richey * mem: Add REP MOVSB/STOSB implementations The assembly generated seems correct: https://rust.godbolt.org/z/GGnec8 Signed-off-by: Joe Richey * mem: Add documentations for REP string insturctions Signed-off-by: Joe Richey * Use quad-word rep string instructions Signed-off-by: Joe Richey * Prevent panic when compiled in debug mode Signed-off-by: Joe Richey * Add tests for mem* functions Signed-off-by: Joe Richey * Add build/test with the "asm" feature Signed-off-by: Joe Richey * Add byte length to Bencher Signed-off-by: Joe Richey --- library/compiler-builtins/ci/run.sh | 4 + library/compiler-builtins/src/mem/memcpy.rs | 41 +++++ .../src/{mem.rs => mem/mod.rs} | 43 +---- library/compiler-builtins/src/mem/x86_64.rs | 79 +++++++++ .../testcrate/benches/mem.rs | 162 ++++++++++++++++++ .../compiler-builtins/testcrate/tests/mem.rs | 133 ++++++++++++++ 6 files changed, 423 insertions(+), 39 deletions(-) create mode 100644 library/compiler-builtins/src/mem/memcpy.rs rename library/compiler-builtins/src/{mem.rs => mem/mod.rs} (84%) create mode 100644 library/compiler-builtins/src/mem/x86_64.rs create mode 100644 library/compiler-builtins/testcrate/benches/mem.rs create mode 100644 library/compiler-builtins/testcrate/tests/mem.rs diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 3c9dc0247e69a..9d163233355e5 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -12,12 +12,16 @@ else $run --release $run --features c $run --features c --release + $run --features asm + $run --features asm --release fi cargo build --target $1 cargo build --target $1 --release cargo build --target $1 --features c cargo build --target $1 --release --features c +cargo build --target $1 --features asm +cargo build --target $1 --release --features asm PREFIX=$(echo $1 | sed -e 's/unknown-//')- case $1 in diff --git a/library/compiler-builtins/src/mem/memcpy.rs b/library/compiler-builtins/src/mem/memcpy.rs new file mode 100644 index 0000000000000..8fada9bca091b --- /dev/null +++ b/library/compiler-builtins/src/mem/memcpy.rs @@ -0,0 +1,41 @@ +use super::c_int; + +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { + let mut i = 0; + while i < n { + *dest.offset(i as isize) = *src.offset(i as isize); + i += 1; + } + dest +} + +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { + if src < dest as *const u8 { + // copy from end + let mut i = n; + while i != 0 { + i -= 1; + *dest.offset(i as isize) = *src.offset(i as isize); + } + } else { + // copy from beginning + let mut i = 0; + while i < n { + *dest.offset(i as isize) = *src.offset(i as isize); + i += 1; + } + } + dest +} + +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { + let mut i = 0; + while i < n { + *s.offset(i as isize) = c as u8; + i += 1; + } + s +} diff --git a/library/compiler-builtins/src/mem.rs b/library/compiler-builtins/src/mem/mod.rs similarity index 84% rename from library/compiler-builtins/src/mem.rs rename to library/compiler-builtins/src/mem/mod.rs index 24552ed851089..aa9d4b61deb57 100644 --- a/library/compiler-builtins/src/mem.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -9,45 +9,10 @@ use core::intrinsics::{atomic_load_unordered, atomic_store_unordered, exact_div} use core::mem; use core::ops::{BitOr, Shl}; -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { - let mut i = 0; - while i < n { - *dest.offset(i as isize) = *src.offset(i as isize); - i += 1; - } - dest -} - -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { - if src < dest as *const u8 { - // copy from end - let mut i = n; - while i != 0 { - i -= 1; - *dest.offset(i as isize) = *src.offset(i as isize); - } - } else { - // copy from beginning - let mut i = 0; - while i < n { - *dest.offset(i as isize) = *src.offset(i as isize); - i += 1; - } - } - dest -} - -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { - let mut i = 0; - while i < n { - *s.offset(i as isize) = c as u8; - i += 1; - } - s -} +// memcpy/memmove/memset have optimized implementations on some architectures +#[cfg_attr(all(feature = "asm", target_arch = "x86_64"), path = "x86_64.rs")] +mod memcpy; +pub use self::memcpy::*; #[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs new file mode 100644 index 0000000000000..1ecffce45f286 --- /dev/null +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -0,0 +1,79 @@ +use super::c_int; + +// On most modern Intel and AMD processors, "rep movsq" and "rep stosq" have +// been enhanced to perform better than an simple qword loop, making them ideal +// for implementing memcpy/memset. Note that "rep cmps" has received no such +// enhancement, so it is not used to implement memcmp. +// +// On certain recent Intel processors, "rep movsb" and "rep stosb" have been +// further enhanced to automatically select the best microarchitectural +// implementation based on length and alignment. See the following features from +// the "Intel® 64 and IA-32 Architectures Optimization Reference Manual": +// - ERMSB - Enhanced REP MOVSB and STOSB (Ivy Bridge and later) +// - FSRM - Fast Short REP MOV (Ice Lake and later) +// - Fast Zero-Length MOVSB (On no current hardware) +// - Fast Short STOSB (On no current hardware) +// However, to avoid run-time feature detection, we don't use these byte-based +// instructions for most of the copying, preferring the qword variants. + +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, count: usize) -> *mut u8 { + let qword_count = count >> 3; + let byte_count = count & 0b111; + asm!( + "rep movsq [rdi], [rsi]", + "mov ecx, {byte_count:e}", + "rep movsb [rdi], [rsi]", + byte_count = in(reg) byte_count, + inout("rcx") qword_count => _, + inout("rdi") dest => _, + inout("rsi") src => _, + options(nostack, preserves_flags) + ); + dest +} + +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, count: usize) -> *mut u8 { + let delta = (dest as usize).wrapping_sub(src as usize); + if delta >= count { + // We can copy forwards because either dest is far enough ahead of src, + // or src is ahead of dest (and delta overflowed). + return self::memcpy(dest, src, count); + } + // copy backwards + let qword_count = count >> 3; + let byte_count = count & 0b111; + asm!( + "std", + "rep movsq [rdi], [rsi]", + "mov ecx, {byte_count:e}", + "add rdi, 7", + "add rsi, 7", + "rep movsb [rdi], [rsi]", + "cld", + byte_count = in(reg) byte_count, + inout("rcx") qword_count => _, + inout("rdi") dest.offset(count as isize).wrapping_sub(8) => _, + inout("rsi") src.offset(count as isize).wrapping_sub(8) => _, + options(nostack) + ); + dest +} + +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +pub unsafe extern "C" fn memset(dest: *mut u8, c: c_int, count: usize) -> *mut u8 { + let qword_count = count >> 3; + let byte_count = count & 0b111; + asm!( + "rep stosq [rdi], rax", + "mov ecx, {byte_count:e}", + "rep stosb [rdi], al", + byte_count = in(reg) byte_count, + inout("rcx") qword_count => _, + inout("rdi") dest => _, + in("rax") (c as u8 as u64) * 0x0101010101010101, + options(nostack, preserves_flags) + ); + dest +} diff --git a/library/compiler-builtins/testcrate/benches/mem.rs b/library/compiler-builtins/testcrate/benches/mem.rs new file mode 100644 index 0000000000000..57d5750861347 --- /dev/null +++ b/library/compiler-builtins/testcrate/benches/mem.rs @@ -0,0 +1,162 @@ +#![feature(test)] + +extern crate test; +use test::{black_box, Bencher}; + +extern crate compiler_builtins; +use compiler_builtins::mem::{memcmp, memcpy, memmove, memset}; + +fn memcpy_builtin(b: &mut Bencher, n: usize) { + let v1 = vec![1u8; n]; + let mut v2 = vec![0u8; n]; + b.bytes = n as u64; + b.iter(|| { + let src: &[u8] = black_box(&v1); + let dst: &mut [u8] = black_box(&mut v2); + dst.copy_from_slice(src); + }) +} + +fn memcpy_rust(b: &mut Bencher, n: usize) { + let v1 = vec![1u8; n]; + let mut v2 = vec![0u8; n]; + b.bytes = n as u64; + b.iter(|| { + let src: &[u8] = black_box(&v1); + let dst: &mut [u8] = black_box(&mut v2); + unsafe { memcpy(dst.as_mut_ptr(), src.as_ptr(), n) } + }) +} + +fn memset_builtin(b: &mut Bencher, n: usize) { + let mut v1 = vec![0u8; n]; + b.bytes = n as u64; + b.iter(|| { + let dst: &mut [u8] = black_box(&mut v1); + let val: u8 = black_box(27); + for b in dst { + *b = val; + } + }) +} + +fn memset_rust(b: &mut Bencher, n: usize) { + let mut v1 = vec![0u8; n]; + b.bytes = n as u64; + b.iter(|| { + let dst: &mut [u8] = black_box(&mut v1); + let val = black_box(27); + unsafe { memset(dst.as_mut_ptr(), val, n) } + }) +} + +fn memcmp_builtin(b: &mut Bencher, n: usize) { + let v1 = vec![0u8; n]; + let mut v2 = vec![0u8; n]; + v2[n - 1] = 1; + b.bytes = n as u64; + b.iter(|| { + let s1: &[u8] = black_box(&v1); + let s2: &[u8] = black_box(&v2); + s1.cmp(s2) + }) +} + +fn memcmp_rust(b: &mut Bencher, n: usize) { + let v1 = vec![0u8; n]; + let mut v2 = vec![0u8; n]; + v2[n - 1] = 1; + b.bytes = n as u64; + b.iter(|| { + let s1: &[u8] = black_box(&v1); + let s2: &[u8] = black_box(&v2); + unsafe { memcmp(s1.as_ptr(), s2.as_ptr(), n) } + }) +} + +fn memmove_builtin(b: &mut Bencher, n: usize) { + let mut v = vec![0u8; n + n / 2]; + b.bytes = n as u64; + b.iter(|| { + let s: &mut [u8] = black_box(&mut v); + s.copy_within(0..n, n / 2); + }) +} + +fn memmove_rust(b: &mut Bencher, n: usize) { + let mut v = vec![0u8; n + n / 2]; + b.bytes = n as u64; + b.iter(|| { + let dst: *mut u8 = black_box(&mut v[n / 2..]).as_mut_ptr(); + let src: *const u8 = black_box(&v).as_ptr(); + unsafe { memmove(dst, src, n) }; + }) +} + +#[bench] +fn memcpy_builtin_4096(b: &mut Bencher) { + memcpy_builtin(b, 4096) +} +#[bench] +fn memcpy_rust_4096(b: &mut Bencher) { + memcpy_rust(b, 4096) +} +#[bench] +fn memcpy_builtin_1048576(b: &mut Bencher) { + memcpy_builtin(b, 1048576) +} +#[bench] +fn memcpy_rust_1048576(b: &mut Bencher) { + memcpy_rust(b, 1048576) +} + +#[bench] +fn memset_builtin_4096(b: &mut Bencher) { + memset_builtin(b, 4096) +} +#[bench] +fn memset_rust_4096(b: &mut Bencher) { + memset_rust(b, 4096) +} +#[bench] +fn memset_builtin_1048576(b: &mut Bencher) { + memset_builtin(b, 1048576) +} +#[bench] +fn memset_rust_1048576(b: &mut Bencher) { + memset_rust(b, 1048576) +} + +#[bench] +fn memcmp_builtin_4096(b: &mut Bencher) { + memcmp_builtin(b, 4096) +} +#[bench] +fn memcmp_rust_4096(b: &mut Bencher) { + memcmp_rust(b, 4096) +} +#[bench] +fn memcmp_builtin_1048576(b: &mut Bencher) { + memcmp_builtin(b, 1048576) +} +#[bench] +fn memcmp_rust_1048576(b: &mut Bencher) { + memcmp_rust(b, 1048576) +} + +#[bench] +fn memmove_builtin_4096(b: &mut Bencher) { + memmove_builtin(b, 4096) +} +#[bench] +fn memmove_rust_4096(b: &mut Bencher) { + memmove_rust(b, 4096) +} +#[bench] +fn memmove_builtin_1048576(b: &mut Bencher) { + memmove_builtin(b, 1048576) +} +#[bench] +fn memmove_rust_1048576(b: &mut Bencher) { + memmove_rust(b, 1048576) +} diff --git a/library/compiler-builtins/testcrate/tests/mem.rs b/library/compiler-builtins/testcrate/tests/mem.rs new file mode 100644 index 0000000000000..a5596b2811dad --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/mem.rs @@ -0,0 +1,133 @@ +extern crate compiler_builtins; +use compiler_builtins::mem::{memcmp, memcpy, memmove, memset}; + +#[test] +fn memcpy_3() { + let mut arr: [u8; 12] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; + unsafe { + let src = arr.as_ptr().offset(9); + let dst = arr.as_mut_ptr().offset(1); + assert_eq!(memcpy(dst, src, 3), dst); + assert_eq!(arr, [0, 9, 10, 11, 4, 5, 6, 7, 8, 9, 10, 11]); + } + arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; + unsafe { + let src = arr.as_ptr().offset(1); + let dst = arr.as_mut_ptr().offset(9); + assert_eq!(memcpy(dst, src, 3), dst); + assert_eq!(arr, [0, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3]); + } +} + +#[test] +fn memcpy_10() { + let arr: [u8; 18] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]; + let mut dst: [u8; 12] = [0; 12]; + unsafe { + let src = arr.as_ptr().offset(1); + assert_eq!(memcpy(dst.as_mut_ptr(), src, 10), dst.as_mut_ptr()); + assert_eq!(dst, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0]); + } + unsafe { + let src = arr.as_ptr().offset(8); + assert_eq!(memcpy(dst.as_mut_ptr(), src, 10), dst.as_mut_ptr()); + assert_eq!(dst, [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 0, 0]); + } +} + +#[test] +fn memcpy_big() { + // Make the arrays cross 3 pages + const SIZE: usize = 8193; + let src: [u8; SIZE] = [22; SIZE]; + struct Dst { + start: usize, + buf: [u8; SIZE], + end: usize, + } + + let mut dst = Dst { + start: 0, + buf: [0; SIZE], + end: 0, + }; + unsafe { + assert_eq!( + memcpy(dst.buf.as_mut_ptr(), src.as_ptr(), SIZE), + dst.buf.as_mut_ptr() + ); + assert_eq!(dst.start, 0); + assert_eq!(dst.buf, [22; SIZE]); + assert_eq!(dst.end, 0); + } +} + +#[test] +fn memmove_forward() { + let mut arr: [u8; 12] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; + unsafe { + let src = arr.as_ptr().offset(6); + let dst = arr.as_mut_ptr().offset(3); + assert_eq!(memmove(dst, src, 5), dst); + assert_eq!(arr, [0, 1, 2, 6, 7, 8, 9, 10, 8, 9, 10, 11]); + } +} + +#[test] +fn memmove_backward() { + let mut arr: [u8; 12] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; + unsafe { + let src = arr.as_ptr().offset(3); + let dst = arr.as_mut_ptr().offset(6); + assert_eq!(memmove(dst, src, 5), dst); + assert_eq!(arr, [0, 1, 2, 3, 4, 5, 3, 4, 5, 6, 7, 11]); + } +} + +#[test] +fn memset_zero() { + let mut arr: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; + unsafe { + let ptr = arr.as_mut_ptr().offset(5); + assert_eq!(memset(ptr, 0, 2), ptr); + assert_eq!(arr, [0, 1, 2, 3, 4, 0, 0, 7]); + + // Only the LSB matters for a memset + assert_eq!(memset(arr.as_mut_ptr(), 0x2000, 8), arr.as_mut_ptr()); + assert_eq!(arr, [0, 0, 0, 0, 0, 0, 0, 0]); + } +} + +#[test] +fn memset_nonzero() { + let mut arr: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; + unsafe { + let ptr = arr.as_mut_ptr().offset(2); + assert_eq!(memset(ptr, 22, 3), ptr); + assert_eq!(arr, [0, 1, 22, 22, 22, 5, 6, 7]); + + // Only the LSB matters for a memset + assert_eq!(memset(arr.as_mut_ptr(), 0x2009, 8), arr.as_mut_ptr()); + assert_eq!(arr, [9, 9, 9, 9, 9, 9, 9, 9]); + } +} + +#[test] +fn memcmp_eq() { + let arr1: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; + let arr2: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; + unsafe { + assert_eq!(memcmp(arr1.as_ptr(), arr2.as_ptr(), 8), 0); + assert_eq!(memcmp(arr1.as_ptr(), arr2.as_ptr(), 3), 0); + } +} + +#[test] +fn memcmp_ne() { + let arr1: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; + let arr2: [u8; 8] = [0, 1, 2, 3, 4, 5, 7, 7]; + unsafe { + assert!(memcmp(arr1.as_ptr(), arr2.as_ptr(), 8) < 0); + assert!(memcmp(arr2.as_ptr(), arr1.as_ptr(), 8) > 0); + } +} From a97fe5f1d3d959bb8d555fcc8eeca9e82f8e12d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 26 Oct 2020 17:37:02 +0100 Subject: [PATCH 0880/4206] math: add {fmin,fmax}{f,} for thumb*-none-eabi* (#389) These are exposed in core::f32 close #354 c.f. rust-lang/rust#62729 Patch from @whitequark (https://paste.debian.net/1168430/) --- library/compiler-builtins/src/math.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 4b27cb80f6834..94f91124bf0f6 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -92,6 +92,10 @@ no_mangle! { // only for the thumb*-none-eabi* targets #[cfg(all(target_arch = "arm", target_os = "none"))] no_mangle! { + fn fmin(x: f64, y: f64) -> f64; + fn fminf(x: f32, y: f32) -> f32; + fn fmax(x: f64, y: f64) -> f64; + fn fmaxf(x: f32, y: f32) -> f32; // `f64 % f64` fn fmod(x: f64, y: f64) -> f64; // `f32 % f32` From 53daa3c593a915b57ad79b138deda1d8945b6f4a Mon Sep 17 00:00:00 2001 From: Joseph Richey Date: Tue, 3 Nov 2020 06:57:08 -0800 Subject: [PATCH 0881/4206] Use REP MOVSB/STOSB when the ERMSB feature is present (#392) * Reorganize mem functions This reduces the amount of platform-specific code Signed-off-by: Joe Richey * Use ERMSB implementations if the feature is set Signed-off-by: Joe Richey * Add non-aligned benchmarks Signed-off-by: Joe Richey --- library/compiler-builtins/src/mem/impls.rs | 29 +++++++ library/compiler-builtins/src/mem/memcpy.rs | 41 ---------- library/compiler-builtins/src/mem/mod.rs | 28 ++++++- library/compiler-builtins/src/mem/x86_64.rs | 58 +++++++++----- .../testcrate/benches/mem.rs | 80 +++++++++++++------ 5 files changed, 148 insertions(+), 88 deletions(-) create mode 100644 library/compiler-builtins/src/mem/impls.rs delete mode 100644 library/compiler-builtins/src/mem/memcpy.rs diff --git a/library/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/src/mem/impls.rs new file mode 100644 index 0000000000000..6bd1a7ba1db2a --- /dev/null +++ b/library/compiler-builtins/src/mem/impls.rs @@ -0,0 +1,29 @@ +use super::c_int; + +#[inline(always)] +pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, n: usize) { + let mut i = 0; + while i < n { + *dest.offset(i as isize) = *src.offset(i as isize); + i += 1; + } +} + +#[inline(always)] +pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, n: usize) { + // copy from end + let mut i = n; + while i != 0 { + i -= 1; + *dest.offset(i as isize) = *src.offset(i as isize); + } +} + +#[inline(always)] +pub unsafe fn set_bytes(s: *mut u8, c: u8, n: usize) { + let mut i = 0; + while i < n { + *s.offset(i as isize) = c; + i += 1; + } +} diff --git a/library/compiler-builtins/src/mem/memcpy.rs b/library/compiler-builtins/src/mem/memcpy.rs deleted file mode 100644 index 8fada9bca091b..0000000000000 --- a/library/compiler-builtins/src/mem/memcpy.rs +++ /dev/null @@ -1,41 +0,0 @@ -use super::c_int; - -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { - let mut i = 0; - while i < n { - *dest.offset(i as isize) = *src.offset(i as isize); - i += 1; - } - dest -} - -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { - if src < dest as *const u8 { - // copy from end - let mut i = n; - while i != 0 { - i -= 1; - *dest.offset(i as isize) = *src.offset(i as isize); - } - } else { - // copy from beginning - let mut i = 0; - while i < n { - *dest.offset(i as isize) = *src.offset(i as isize); - i += 1; - } - } - dest -} - -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { - let mut i = 0; - while i < n { - *s.offset(i as isize) = c as u8; - i += 1; - } - s -} diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index aa9d4b61deb57..6bc76337c0be0 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -11,8 +11,32 @@ use core::ops::{BitOr, Shl}; // memcpy/memmove/memset have optimized implementations on some architectures #[cfg_attr(all(feature = "asm", target_arch = "x86_64"), path = "x86_64.rs")] -mod memcpy; -pub use self::memcpy::*; +mod impls; + +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { + impls::copy_forward(dest, src, n); + dest +} + +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { + let delta = (dest as usize).wrapping_sub(src as usize); + if delta >= n { + // We can copy forwards because either dest is far enough ahead of src, + // or src is ahead of dest (and delta overflowed). + impls::copy_forward(dest, src, n); + } else { + impls::copy_backward(dest, src, n); + } + dest +} + +#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { + impls::set_bytes(s, c as u8, n); + s +} #[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 1ecffce45f286..7eefd8099b957 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -1,5 +1,3 @@ -use super::c_int; - // On most modern Intel and AMD processors, "rep movsq" and "rep stosq" have // been enhanced to perform better than an simple qword loop, making them ideal // for implementing memcpy/memset. Note that "rep cmps" has received no such @@ -13,11 +11,26 @@ use super::c_int; // - FSRM - Fast Short REP MOV (Ice Lake and later) // - Fast Zero-Length MOVSB (On no current hardware) // - Fast Short STOSB (On no current hardware) -// However, to avoid run-time feature detection, we don't use these byte-based -// instructions for most of the copying, preferring the qword variants. +// +// To simplify things, we switch to using the byte-based variants if the "ermsb" +// feature is present at compile-time. We don't bother detecting other features. +// Note that ERMSB does not enhance the backwards (DF=1) "rep movsb". + +#[inline(always)] +#[cfg(target_feature = "ermsb")] +pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { + asm!( + "rep movsb [rdi], [rsi]", + inout("rcx") count => _, + inout("rdi") dest => _, + inout("rsi") src => _, + options(nostack, preserves_flags) + ); +} -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, count: usize) -> *mut u8 { +#[inline(always)] +#[cfg(not(target_feature = "ermsb"))] +pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { let qword_count = count >> 3; let byte_count = count & 0b111; asm!( @@ -30,18 +43,10 @@ pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, count: usize) -> inout("rsi") src => _, options(nostack, preserves_flags) ); - dest } -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, count: usize) -> *mut u8 { - let delta = (dest as usize).wrapping_sub(src as usize); - if delta >= count { - // We can copy forwards because either dest is far enough ahead of src, - // or src is ahead of dest (and delta overflowed). - return self::memcpy(dest, src, count); - } - // copy backwards +#[inline(always)] +pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { let qword_count = count >> 3; let byte_count = count & 0b111; asm!( @@ -58,11 +63,23 @@ pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, count: usize) -> inout("rsi") src.offset(count as isize).wrapping_sub(8) => _, options(nostack) ); - dest } -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -pub unsafe extern "C" fn memset(dest: *mut u8, c: c_int, count: usize) -> *mut u8 { +#[inline(always)] +#[cfg(target_feature = "ermsb")] +pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { + asm!( + "rep stosb [rdi], al", + inout("rcx") count => _, + inout("rdi") dest => _, + inout("al") c => _, + options(nostack, preserves_flags) + ) +} + +#[inline(always)] +#[cfg(not(target_feature = "ermsb"))] +pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { let qword_count = count >> 3; let byte_count = count & 0b111; asm!( @@ -72,8 +89,7 @@ pub unsafe extern "C" fn memset(dest: *mut u8, c: c_int, count: usize) -> *mut u byte_count = in(reg) byte_count, inout("rcx") qword_count => _, inout("rdi") dest => _, - in("rax") (c as u8 as u64) * 0x0101010101010101, + in("rax") (c as u64) * 0x0101010101010101, options(nostack, preserves_flags) ); - dest } diff --git a/library/compiler-builtins/testcrate/benches/mem.rs b/library/compiler-builtins/testcrate/benches/mem.rs index 57d5750861347..cee64ae4d51d5 100644 --- a/library/compiler-builtins/testcrate/benches/mem.rs +++ b/library/compiler-builtins/testcrate/benches/mem.rs @@ -6,33 +6,33 @@ use test::{black_box, Bencher}; extern crate compiler_builtins; use compiler_builtins::mem::{memcmp, memcpy, memmove, memset}; -fn memcpy_builtin(b: &mut Bencher, n: usize) { - let v1 = vec![1u8; n]; - let mut v2 = vec![0u8; n]; +fn memcpy_builtin(b: &mut Bencher, n: usize, offset: usize) { + let v1 = vec![1u8; n + offset]; + let mut v2 = vec![0u8; n + offset]; b.bytes = n as u64; b.iter(|| { - let src: &[u8] = black_box(&v1); - let dst: &mut [u8] = black_box(&mut v2); + let src: &[u8] = black_box(&v1[offset..]); + let dst: &mut [u8] = black_box(&mut v2[offset..]); dst.copy_from_slice(src); }) } -fn memcpy_rust(b: &mut Bencher, n: usize) { - let v1 = vec![1u8; n]; - let mut v2 = vec![0u8; n]; +fn memcpy_rust(b: &mut Bencher, n: usize, offset: usize) { + let v1 = vec![1u8; n + offset]; + let mut v2 = vec![0u8; n + offset]; b.bytes = n as u64; b.iter(|| { - let src: &[u8] = black_box(&v1); - let dst: &mut [u8] = black_box(&mut v2); + let src: &[u8] = black_box(&v1[offset..]); + let dst: &mut [u8] = black_box(&mut v2[offset..]); unsafe { memcpy(dst.as_mut_ptr(), src.as_ptr(), n) } }) } -fn memset_builtin(b: &mut Bencher, n: usize) { - let mut v1 = vec![0u8; n]; +fn memset_builtin(b: &mut Bencher, n: usize, offset: usize) { + let mut v1 = vec![0u8; n + offset]; b.bytes = n as u64; b.iter(|| { - let dst: &mut [u8] = black_box(&mut v1); + let dst: &mut [u8] = black_box(&mut v1[offset..]); let val: u8 = black_box(27); for b in dst { *b = val; @@ -40,11 +40,11 @@ fn memset_builtin(b: &mut Bencher, n: usize) { }) } -fn memset_rust(b: &mut Bencher, n: usize) { - let mut v1 = vec![0u8; n]; +fn memset_rust(b: &mut Bencher, n: usize, offset: usize) { + let mut v1 = vec![0u8; n + offset]; b.bytes = n as u64; b.iter(|| { - let dst: &mut [u8] = black_box(&mut v1); + let dst: &mut [u8] = black_box(&mut v1[offset..]); let val = black_box(27); unsafe { memset(dst.as_mut_ptr(), val, n) } }) @@ -95,36 +95,68 @@ fn memmove_rust(b: &mut Bencher, n: usize) { #[bench] fn memcpy_builtin_4096(b: &mut Bencher) { - memcpy_builtin(b, 4096) + memcpy_builtin(b, 4096, 0) } #[bench] fn memcpy_rust_4096(b: &mut Bencher) { - memcpy_rust(b, 4096) + memcpy_rust(b, 4096, 0) } #[bench] fn memcpy_builtin_1048576(b: &mut Bencher) { - memcpy_builtin(b, 1048576) + memcpy_builtin(b, 1048576, 0) } #[bench] fn memcpy_rust_1048576(b: &mut Bencher) { - memcpy_rust(b, 1048576) + memcpy_rust(b, 1048576, 0) +} +#[bench] +fn memcpy_builtin_4096_offset(b: &mut Bencher) { + memcpy_builtin(b, 4096, 65) +} +#[bench] +fn memcpy_rust_4096_offset(b: &mut Bencher) { + memcpy_rust(b, 4096, 65) +} +#[bench] +fn memcpy_builtin_1048576_offset(b: &mut Bencher) { + memcpy_builtin(b, 1048576, 65) +} +#[bench] +fn memcpy_rust_1048576_offset(b: &mut Bencher) { + memcpy_rust(b, 1048576, 65) } #[bench] fn memset_builtin_4096(b: &mut Bencher) { - memset_builtin(b, 4096) + memset_builtin(b, 4096, 0) } #[bench] fn memset_rust_4096(b: &mut Bencher) { - memset_rust(b, 4096) + memset_rust(b, 4096, 0) } #[bench] fn memset_builtin_1048576(b: &mut Bencher) { - memset_builtin(b, 1048576) + memset_builtin(b, 1048576, 0) } #[bench] fn memset_rust_1048576(b: &mut Bencher) { - memset_rust(b, 1048576) + memset_rust(b, 1048576, 0) +} +#[bench] +fn memset_builtin_4096_offset(b: &mut Bencher) { + memset_builtin(b, 4096, 65) +} +#[bench] +fn memset_rust_4096_offset(b: &mut Bencher) { + memset_rust(b, 4096, 65) +} +#[bench] +fn memset_builtin_1048576_offset(b: &mut Bencher) { + memset_builtin(b, 1048576, 65) +} +#[bench] +fn memset_rust_1048576_offset(b: &mut Bencher) { + memset_rust(b, 1048576, 65) } #[bench] From 5c294cedc0daba4a6f8cb99aa2de9cf58a8a2e4f Mon Sep 17 00:00:00 2001 From: Joseph Richey Date: Mon, 9 Nov 2020 07:24:25 -0800 Subject: [PATCH 0882/4206] Move from an "asm" flag to a "no-asm" feature flag (#386) * Use a no-asm feature instead of an asm feature This works better as core/alloc/std have trouble supporting default featues in this crate. Signed-off-by: Joe Richey * Have no-asm disable arm assembly intrinsics Signed-off-by: Joe Richey --- library/compiler-builtins/Cargo.toml | 8 +++---- library/compiler-builtins/ci/run.sh | 8 +++---- library/compiler-builtins/src/arm.rs | 2 ++ .../src/int/specialized_div_rem/mod.rs | 16 +++++++------- library/compiler-builtins/src/lib.rs | 6 +++--- library/compiler-builtins/src/mem/mod.rs | 5 ++++- library/compiler-builtins/src/probestack.rs | 2 ++ library/compiler-builtins/src/x86.rs | 21 ++++++++++++++++--- library/compiler-builtins/src/x86_64.rs | 21 ++++++++++++++++--- .../compiler-builtins/testcrate/Cargo.toml | 4 ++-- 10 files changed, 65 insertions(+), 28 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 9262bb6d64f13..0c5fd15315e4c 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -40,14 +40,14 @@ panic-handler = { path = 'crates/panic-handler' } [features] default = ["compiler-builtins"] -# Some algorithms benefit from inline assembly, but some compiler backends do -# not support it, so inline assembly is only enabled when this flag is set. -asm = [] - # Enable compilation of C code in compiler-rt, filling in some more optimized # implementations and also filling in unimplemented intrinsics c = ["cc"] +# Workaround for the Cranelift codegen backend. Disables any implementations +# which use inline assembly and fall back to pure Rust versions (if avalible). +no-asm = [] + # Flag this library as the unstable compiler-builtins lib compiler-builtins = [] diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 9d163233355e5..44ec30fb79871 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -12,16 +12,16 @@ else $run --release $run --features c $run --features c --release - $run --features asm - $run --features asm --release + $run --features no-asm + $run --features no-asm --release fi cargo build --target $1 cargo build --target $1 --release cargo build --target $1 --features c cargo build --target $1 --release --features c -cargo build --target $1 --features asm -cargo build --target $1 --release --features asm +cargo build --target $1 --features no-asm +cargo build --target $1 --release --features no-asm PREFIX=$(echo $1 | sed -e 's/unknown-//')- case $1 in diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 3a25060919702..2b17b4f9613ef 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,3 +1,5 @@ +#![cfg(not(feature = "no-asm"))] + use core::intrinsics; // NOTE This function and the ones below are implemented using assembly because they using a custom diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index 3ac341b6f35d4..7f37f62202b6f 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -115,7 +115,7 @@ fn u64_by_u64_div_rem(duo: u64, div: u64) -> (u64, u64) { // microarchitecture can multiply and divide. We decide to be optimistic and assume `trifecta` is // faster if the target pointer width is at least 64. #[cfg(all( - not(all(feature = "asm", target_arch = "x86_64")), + not(all(not(feature = "no-asm"), target_arch = "x86_64")), not(any(target_pointer_width = "16", target_pointer_width = "32")) ))] impl_trifecta!( @@ -131,7 +131,7 @@ impl_trifecta!( // If the pointer width less than 64, then the target architecture almost certainly does not have // the fast 64 to 128 bit widening multiplication needed for `trifecta` to be faster. #[cfg(all( - not(all(feature = "asm", target_arch = "x86_64")), + not(all(not(feature = "no-asm"), target_arch = "x86_64")), any(target_pointer_width = "16", target_pointer_width = "32") ))] impl_delegate!( @@ -152,7 +152,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(feature = "asm", target_arch = "x86_64"))] +#[cfg(all(not(feature = "no-asm"), target_arch = "x86_64"))] #[inline] unsafe fn u128_by_u64_div_rem(duo: u128, div: u64) -> (u64, u64) { let duo_lo = duo as u64; @@ -174,7 +174,7 @@ unsafe fn u128_by_u64_div_rem(duo: u128, div: u64) -> (u64, u64) { } // use `asymmetric` instead of `trifecta` on x86_64 -#[cfg(all(feature = "asm", target_arch = "x86_64"))] +#[cfg(all(not(feature = "no-asm"), target_arch = "x86_64"))] impl_asymmetric!( u128_div_rem, zero_div_fn, @@ -203,7 +203,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(feature = "asm", target_arch = "x86")), + not(all(not(feature = "no-asm"), target_arch = "x86")), not(target_pointer_width = "64") ))] impl_delegate!( @@ -220,7 +220,7 @@ impl_delegate!( // When not on x86 and the pointer width is 64, use `binary_long`. #[cfg(all( - not(all(feature = "asm", target_arch = "x86")), + not(all(not(feature = "no-asm"), target_arch = "x86")), target_pointer_width = "64" ))] impl_binary_long!( @@ -238,7 +238,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(feature = "asm", target_arch = "x86"))] +#[cfg(all(not(feature = "no-asm"), target_arch = "x86"))] #[inline] unsafe fn u64_by_u32_div_rem(duo: u64, div: u32) -> (u32, u32) { let duo_lo = duo as u32; @@ -260,7 +260,7 @@ unsafe fn u64_by_u32_div_rem(duo: u64, div: u32) -> (u32, u32) { } // use `asymmetric` instead of `delegate` on x86 -#[cfg(all(feature = "asm", target_arch = "x86"))] +#[cfg(all(not(feature = "no-asm"), target_arch = "x86"))] impl_asymmetric!( u64_div_rem, zero_div_fn, diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index cbd23850b3f95..4a7c746a2ff54 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,8 +1,8 @@ #![cfg_attr(feature = "compiler-builtins", compiler_builtins)] -#![cfg_attr(feature = "asm", feature(asm))] +#![cfg_attr(not(feature = "no-asm"), feature(asm))] #![feature(abi_unadjusted)] -#![feature(llvm_asm)] -#![feature(global_asm)] +#![cfg_attr(not(feature = "no-asm"), feature(llvm_asm))] +#![cfg_attr(not(feature = "no-asm"), feature(global_asm))] #![feature(cfg_target_has_atomic)] #![feature(compiler_builtins)] #![feature(core_intrinsics)] diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index 6bc76337c0be0..adb7c2c64c9ab 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -10,7 +10,10 @@ use core::mem; use core::ops::{BitOr, Shl}; // memcpy/memmove/memset have optimized implementations on some architectures -#[cfg_attr(all(feature = "asm", target_arch = "x86_64"), path = "x86_64.rs")] +#[cfg_attr( + all(not(feature = "no-asm"), target_arch = "x86_64"), + path = "x86_64.rs" +)] mod impls; #[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 2f37a104ecee8..ac3ae1ebbc4af 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -44,6 +44,8 @@ #![cfg(not(feature = "mangled-names"))] // Windows already has builtins to do this. #![cfg(not(windows))] +// All these builtins require assembly +#![cfg(not(feature = "no-asm"))] // We only define stack probing for these architectures today. #![cfg(any(target_arch = "x86_64", target_arch = "x86"))] diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs index 5511c4572e528..e038231bb0e9b 100644 --- a/library/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/src/x86.rs @@ -8,7 +8,12 @@ use core::intrinsics; // NOTE These functions are never mangled as they are not tested against compiler-rt // and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca -#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] +#[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm"), + not(feature = "mangled-names") +))] #[naked] #[no_mangle] pub unsafe fn ___chkstk_ms() { @@ -34,7 +39,12 @@ pub unsafe fn ___chkstk_ms() { } // FIXME: __alloca should be an alias to __chkstk -#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] +#[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm"), + not(feature = "mangled-names") +))] #[naked] #[no_mangle] pub unsafe fn __alloca() { @@ -43,7 +53,12 @@ pub unsafe fn __alloca() { intrinsics::unreachable(); } -#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] +#[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm"), + not(feature = "mangled-names") +))] #[naked] #[no_mangle] pub unsafe fn ___chkstk() { diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 6a0cd56687348..91c0f24fca6d9 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -8,7 +8,12 @@ use core::intrinsics; // NOTE These functions are never mangled as they are not tested against compiler-rt // and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca -#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] +#[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm"), + not(feature = "mangled-names") +))] #[naked] #[no_mangle] pub unsafe fn ___chkstk_ms() { @@ -33,7 +38,12 @@ pub unsafe fn ___chkstk_ms() { intrinsics::unreachable(); } -#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] +#[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm"), + not(feature = "mangled-names") +))] #[naked] #[no_mangle] pub unsafe fn __alloca() { @@ -43,7 +53,12 @@ pub unsafe fn __alloca() { intrinsics::unreachable(); } -#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] +#[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm"), + not(feature = "mangled-names") +))] #[naked] #[no_mangle] pub unsafe fn ___chkstk() { diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 5c3df79619e2e..ce8df2d12c529 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -28,8 +28,8 @@ utest-cortex-m-qemu = { default-features = false, git = "https://github.com/japa%20utest-macros%20=%20%7B%20git%20="https://github.com/japaric/utest" } [features] -default = ["asm", "mangled-names"] -asm = ["compiler_builtins/asm"] +default = ["mangled-names"] c = ["compiler_builtins/c"] +no-asm = ["compiler_builtins/no-asm"] mem = ["compiler_builtins/mem"] mangled-names = ["compiler_builtins/mangled-names"] From 82bee10b5bfcdd165ffefbbb69dc6d4e3d56aa43 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 20 Nov 2020 10:29:35 -0600 Subject: [PATCH 0883/4206] Update CI to fix on GitHub Actions (#394) Should hopefully fix the master branch... --- library/compiler-builtins/.github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index e4bcc9c10529f..01dffb8451ef5 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -90,7 +90,7 @@ jobs: run: | curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/10.0-2020-05-05.tar.gz tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-10.0-2020-05-05/compiler-rt - echo "##[set-env name=RUST_COMPILER_RT_ROOT]./compiler-rt" + echo RUST_COMPILER_RT_ROOT=./compiler-rt >> $GITHUB_ENV shell: bash # Non-linux tests just use our raw script From a7548bea0d32e11c4e16f5260485366ad28a34cd Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Mon, 23 Nov 2020 09:05:02 -0600 Subject: [PATCH 0884/4206] fix division on SPARC (#393) --- .../src/int/specialized_div_rem/delegate.rs | 130 ++++++++++++++++++ .../src/int/specialized_div_rem/mod.rs | 49 ++++--- library/compiler-builtins/src/int/udiv.rs | 38 ++++- 3 files changed, 190 insertions(+), 27 deletions(-) diff --git a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs index 8310c142956fc..135d3402a3af7 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs @@ -185,3 +185,133 @@ macro_rules! impl_delegate { } }; } + +/// Returns `n / d` and sets `*rem = n % d`. +/// +/// This specialization exists because: +/// - The LLVM backend for 32-bit SPARC cannot compile functions that return `(u128, u128)`, +/// so we have to use an old fashioned `&mut u128` argument to return the remainder. +/// - 64-bit SPARC does not have u64 * u64 => u128 widening multiplication, which makes the +/// delegate algorithm strategy the only reasonably fast way to perform `u128` division. +#[doc(hidden)] +pub fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { + use super::*; + let duo_lo = duo as u64; + let duo_hi = (duo >> 64) as u64; + let div_lo = div as u64; + let div_hi = (div >> 64) as u64; + + match (div_lo == 0, div_hi == 0, duo_hi == 0) { + (true, true, _) => zero_div_fn(), + (_, false, true) => { + *rem = duo; + return 0; + } + (false, true, true) => { + let tmp = u64_by_u64_div_rem(duo_lo, div_lo); + *rem = tmp.1 as u128; + return tmp.0 as u128; + } + (false, true, false) => { + if duo_hi < div_lo { + let norm_shift = u64_normalization_shift(div_lo, duo_hi, false); + let shl = if norm_shift == 0 { + 64 - 1 + } else { + 64 - norm_shift + }; + + let mut div: u128 = div << shl; + let mut pow_lo: u64 = 1 << shl; + let mut quo_lo: u64 = 0; + let mut duo = duo; + loop { + let sub = duo.wrapping_sub(div); + if 0 <= (sub as i128) { + duo = sub; + quo_lo |= pow_lo; + let duo_hi = (duo >> 64) as u64; + if duo_hi == 0 { + let tmp = u64_by_u64_div_rem(duo as u64, div_lo); + *rem = tmp.1 as u128; + return (quo_lo | tmp.0) as u128; + } + } + div >>= 1; + pow_lo >>= 1; + } + } else if duo_hi == div_lo { + let tmp = u64_by_u64_div_rem(duo as u64, div as u64); + *rem = tmp.1 as u128; + return (1 << 64) | (tmp.0 as u128); + } else { + if (div_lo >> 32) == 0 { + let div_0 = div_lo as u32 as u64; + let (quo_hi, rem_3) = u64_by_u64_div_rem(duo_hi, div_0); + + let duo_mid = ((duo >> 32) as u32 as u64) | (rem_3 << 32); + let (quo_1, rem_2) = u64_by_u64_div_rem(duo_mid, div_0); + + let duo_lo = (duo as u32 as u64) | (rem_2 << 32); + let (quo_0, rem_1) = u64_by_u64_div_rem(duo_lo, div_0); + + *rem = rem_1 as u128; + return (quo_0 as u128) | ((quo_1 as u128) << 32) | ((quo_hi as u128) << 64); + } + + let duo_lo = duo as u64; + let tmp = u64_by_u64_div_rem(duo_hi, div_lo); + let quo_hi = tmp.0; + let mut duo = (duo_lo as u128) | ((tmp.1 as u128) << 64); + if duo < div { + *rem = duo; + return (quo_hi as u128) << 64; + } + + let mut div: u128 = div << (64 - 1); + let mut pow_lo: u64 = 1 << (64 - 1); + let mut quo_lo: u64 = 0; + loop { + let sub = duo.wrapping_sub(div); + if 0 <= (sub as i128) { + duo = sub; + quo_lo |= pow_lo; + let duo_hi = (duo >> 64) as u64; + if duo_hi == 0 { + let tmp = u64_by_u64_div_rem(duo as u64, div_lo); + *rem = tmp.1 as u128; + return (tmp.0) as u128 | (quo_lo as u128) | ((quo_hi as u128) << 64); + } + } + div >>= 1; + pow_lo >>= 1; + } + } + } + (_, false, false) => { + if duo < div { + *rem = duo; + return 0; + } + let div_original = div; + let shl = u64_normalization_shift(duo_hi, div_hi, false); + let mut duo = duo; + let mut div: u128 = div << shl; + let mut pow_lo: u64 = 1 << shl; + let mut quo_lo: u64 = 0; + loop { + let sub = duo.wrapping_sub(div); + if 0 <= (sub as i128) { + duo = sub; + quo_lo |= pow_lo; + if duo < div_original { + *rem = duo; + return quo_lo as u128; + } + } + div >>= 1; + pow_lo >>= 1; + } + } + } +} diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index 7f37f62202b6f..eaeb030e389d1 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -46,6 +46,7 @@ mod binary_long; #[macro_use] mod delegate; +pub use self::delegate::u128_divide_sparc; #[macro_use] mod trifecta; @@ -60,27 +61,31 @@ fn zero_div_fn() -> ! { unsafe { core::hint::unreachable_unchecked() } } -// The `B` extension on RISC-V determines if a CLZ assembly instruction exists -#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] -const USE_LZ: bool = cfg!(target_feature = "b"); - -#[cfg(target_arch = "arm")] -const USE_LZ: bool = if cfg!(target_feature = "thumb-mode") { - // ARM thumb targets have CLZ instructions if the instruction set of ARMv6T2 is supported. This - // is needed to successfully differentiate between targets like `thumbv8.base` and - // `thumbv8.main`. - cfg!(target_feature = "v6t2") -} else { - // Regular ARM targets have CLZ instructions if the ARMv5TE instruction set is supported. - // Technically, ARMv5T was the first to have CLZ, but the "v5t" target feature does not seem to - // work. - cfg!(target_feature = "v5te") +const USE_LZ: bool = { + if cfg!(target_arch = "arm") { + if cfg!(target_feature = "thumb-mode") { + // ARM thumb targets have CLZ instructions if the instruction set of ARMv6T2 is + // supported. This is needed to successfully differentiate between targets like + // `thumbv8.base` and `thumbv8.main`. + cfg!(target_feature = "v6t2") + } else { + // Regular ARM targets have CLZ instructions if the ARMv5TE instruction set is + // supported. Technically, ARMv5T was the first to have CLZ, but the "v5t" target + // feature does not seem to work. + cfg!(target_feature = "v5te") + } + } else if cfg!(any(target_arch = "sparc", target_arch = "sparc64")) { + // LZD or LZCNT on SPARC only exists for the VIS 3 extension and later. + cfg!(target_feature = "vis3") + } else if cfg!(any(target_arch = "riscv32", target_arch = "riscv64")) { + // The `B` extension on RISC-V determines if a CLZ assembly instruction exists + cfg!(target_feature = "b") + } else { + // All other common targets Rust supports should have CLZ instructions + true + } }; -// All other targets Rust supports have CLZ instructions -#[cfg(not(any(target_arch = "arm", target_arch = "riscv32", target_arch = "riscv64")))] -const USE_LZ: bool = true; - impl_normalization_shift!( u32_normalization_shift, USE_LZ, @@ -115,8 +120,9 @@ fn u64_by_u64_div_rem(duo: u64, div: u64) -> (u64, u64) { // microarchitecture can multiply and divide. We decide to be optimistic and assume `trifecta` is // faster if the target pointer width is at least 64. #[cfg(all( + not(any(target_pointer_width = "16", target_pointer_width = "32")), not(all(not(feature = "no-asm"), target_arch = "x86_64")), - not(any(target_pointer_width = "16", target_pointer_width = "32")) + not(any(target_arch = "sparc", target_arch = "sparc64")) ))] impl_trifecta!( u128_div_rem, @@ -131,8 +137,9 @@ impl_trifecta!( // If the pointer width less than 64, then the target architecture almost certainly does not have // the fast 64 to 128 bit widening multiplication needed for `trifecta` to be faster. #[cfg(all( + any(target_pointer_width = "16", target_pointer_width = "32"), not(all(not(feature = "no-asm"), target_arch = "x86_64")), - any(target_pointer_width = "16", target_pointer_width = "32") + not(any(target_arch = "sparc", target_arch = "sparc64")) ))] impl_delegate!( u128_div_rem, diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 3cd9be93cb1b1..d971780784999 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -1,3 +1,4 @@ +pub use int::specialized_div_rem::u128_divide_sparc; use int::specialized_div_rem::*; intrinsics! { @@ -46,25 +47,50 @@ intrinsics! { quo_rem.0 } + // Note: we use block configuration and not `if cfg!(...)`, because we need to entirely disable + // the existence of `u128_div_rem` to get 32-bit SPARC to compile, see `u128_divide_sparc` docs. + #[win64_128bit_abi_hack] /// Returns `n / d` pub extern "C" fn __udivti3(n: u128, d: u128) -> u128 { - u128_div_rem(n, d).0 + #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] { + u128_div_rem(n, d).0 + } + #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] { + u128_divide_sparc(n, d, &mut 0) + } } #[win64_128bit_abi_hack] /// Returns `n % d` pub extern "C" fn __umodti3(n: u128, d: u128) -> u128 { - u128_div_rem(n, d).1 + #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] { + u128_div_rem(n, d).1 + } + #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] { + let mut rem = 0; + u128_divide_sparc(n, d, &mut rem); + rem + } } #[win64_128bit_abi_hack] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmodti4(n: u128, d: u128, rem: Option<&mut u128>) -> u128 { - let quo_rem = u128_div_rem(n, d); - if let Some(rem) = rem { - *rem = quo_rem.1; + #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] { + let quo_rem = u128_div_rem(n, d); + if let Some(rem) = rem { + *rem = quo_rem.1; + } + quo_rem.0 + } + #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] { + let mut tmp = 0; + let quo = u128_divide_sparc(n, d, &mut tmp); + if let Some(rem) = rem { + *rem = tmp; + } + quo } - quo_rem.0 } } From ea7feb2e0fd9dca228ec5f5b1094956b1339b657 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Tue, 13 Oct 2020 00:06:27 -0500 Subject: [PATCH 0885/4206] Remove `aapcs_on_arm` mistake --- library/compiler-builtins/src/int/mul.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 42f13913e3e7e..1e32560c2aeea 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -90,7 +90,6 @@ intrinsics! { a.mul(b) } - #[aapcs_on_arm] pub extern "C" fn __multi3(a: i128, b: i128) -> i128 { a.mul(b) } From e049a3096478ef8fdbc82131a5a26f7e57863ca1 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Mon, 12 Oct 2020 17:58:02 -0500 Subject: [PATCH 0886/4206] Introduce the `DInt` and `HInt` traits and add various methods that will be used for improved fuzzing --- library/compiler-builtins/src/int/mod.rs | 203 ++++++++++++++++++++++- 1 file changed, 202 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 5e695d5f7e0b6..da2263f6ef804 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -12,13 +12,15 @@ pub mod udiv; pub use self::leading_zeros::__clzsi2; /// Trait for some basic operations on integers -pub(crate) trait Int: +#[doc(hidden)] +pub trait Int: Copy + PartialEq + PartialOrd + ops::AddAssign + ops::BitAndAssign + ops::BitOrAssign + + ops::BitXorAssign + ops::ShlAssign + ops::ShrAssign + ops::Add @@ -41,6 +43,14 @@ pub(crate) trait Int: const ZERO: Self; const ONE: Self; + const MIN: Self; + + /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing + /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, + /// 112,119,120,125,126,127]. + const FUZZ_LENGTHS: [u8; 20]; + /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. + const FUZZ_NUM: usize; /// Extracts the sign from self and returns a tuple. /// @@ -59,17 +69,25 @@ pub(crate) trait Int: fn from_bool(b: bool) -> Self; + /// Prevents the need for excessive conversions between signed and unsigned + fn logical_shr(self, other: u32) -> Self; + // copied from primitive integers, but put in a trait + fn is_zero(self) -> bool; fn max_value() -> Self; fn min_value() -> Self; + fn wrapping_neg(self) -> Self; fn wrapping_add(self, other: Self) -> Self; fn wrapping_mul(self, other: Self) -> Self; fn wrapping_sub(self, other: Self) -> Self; fn wrapping_shl(self, other: u32) -> Self; + fn wrapping_shr(self, other: u32) -> Self; + fn rotate_left(self, other: u32) -> Self; fn overflowing_add(self, other: Self) -> (Self, bool); fn aborting_div(self, other: Self) -> Self; fn aborting_rem(self, other: Self) -> Self; fn leading_zeros(self) -> u32; + fn count_ones(self) -> u32; } fn unwrap(t: Option) -> T { @@ -85,11 +103,78 @@ macro_rules! int_impl_common { const ZERO: Self = 0; const ONE: Self = 1; + const MIN: Self = ::MIN; + + const FUZZ_LENGTHS: [u8; 20] = { + let bits = ::BITS; + let mut v = [0u8; 20]; + v[0] = 0; + v[1] = 1; + v[2] = 2; // important for parity and the iX::MIN case when reversed + let mut i = 3; + // No need for any more until the byte boundary, because there should be no algorithms + // that are sensitive to anything not next to byte boundaries after 2. We also scale + // in powers of two, which is important to prevent u128 corner tests from getting too + // big. + let mut l = 8; + loop { + if l >= ((bits / 2) as u8) { + break; + } + // get both sides of the byte boundary + v[i] = l - 1; + i += 1; + v[i] = l; + i += 1; + l *= 2; + } + + if bits != 8 { + // add the lower side of the middle boundary + v[i] = ((bits / 2) - 1) as u8; + i += 1; + } + + // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS + // boundary because of algorithms that split the high part up. We reverse the scaling + // as we go to Self::BITS. + let mid = i; + let mut j = 1; + loop { + v[i] = (bits as u8) - (v[mid - j]) - 1; + if j == mid { + break; + } + i += 1; + j += 1; + } + v + }; + + const FUZZ_NUM: usize = { + let log2 = (::BITS - 1).count_ones() as usize; + if log2 == 3 { + // case for u8 + 6 + } else { + // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate + // boundaries. + 8 + (4 * (log2 - 4)) + } + }; fn from_bool(b: bool) -> Self { b as $ty } + fn logical_shr(self, other: u32) -> Self { + Self::from_unsigned(self.unsigned().wrapping_shr(other)) + } + + fn is_zero(self) -> bool { + self == Self::ZERO + } + fn max_value() -> Self { ::max_value() } @@ -98,6 +183,10 @@ macro_rules! int_impl_common { ::min_value() } + fn wrapping_neg(self) -> Self { + ::wrapping_neg(self) + } + fn wrapping_add(self, other: Self) -> Self { ::wrapping_add(self, other) } @@ -114,6 +203,14 @@ macro_rules! int_impl_common { ::wrapping_shl(self, other) } + fn wrapping_shr(self, other: u32) -> Self { + ::wrapping_shr(self, other) + } + + fn rotate_left(self, other: u32) -> Self { + ::rotate_left(self, other) + } + fn overflowing_add(self, other: Self) -> (Self, bool) { ::overflowing_add(self, other) } @@ -129,6 +226,10 @@ macro_rules! int_impl_common { fn leading_zeros(self) -> u32 { ::leading_zeros(self) } + + fn count_ones(self) -> u32 { + ::count_ones(self) + } }; } @@ -178,11 +279,111 @@ macro_rules! int_impl { }; } +int_impl!(isize, usize, usize::MAX.count_ones()); +int_impl!(i8, u8, 8); int_impl!(i16, u16, 16); int_impl!(i32, u32, 32); int_impl!(i64, u64, 64); int_impl!(i128, u128, 128); +/// 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. +#[doc(hidden)] +pub trait DInt: Int { + /// Integer that is half the bit width of the integer this trait is implemented for + type H: HInt + Int; + + /// 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); + /// Constructs an integer using lower and higher half parts + fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self; +} + +/// 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. +#[doc(hidden)] +pub trait HInt: Int { + /// Integer that is double the bit width of the integer this trait is implemented for + type D: DInt + Int; + + /// 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 Int>::BITS) as $X + } + fn lo_hi(self) -> (Self::H, Self::H) { + (self.lo(), self.hi()) + } + fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { + lo.zero_widen() | hi.widen_hi() + } + } + )* + }; +} + +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 widen_hi(self) -> Self::D { + (self as $X) << <$H as Int>::BITS + } + 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()) + } + } + )* + }; +} + +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 +); + /// Trait to convert an integer to/from smaller parts pub(crate) trait LargeInt: Int { type LowHalf: Int; From d5b7e2b6d3a16c3b08b710ca1412aa10ee35bafc Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Mon, 12 Oct 2020 17:59:34 -0500 Subject: [PATCH 0887/4206] Overhaul overflowing multiplication impls --- library/compiler-builtins/src/float/conv.rs | 6 +- library/compiler-builtins/src/int/mul.rs | 123 +++++++++++--------- 2 files changed, 71 insertions(+), 58 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 8a0fc6cb42479..e9ca0f138ca2e 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -11,7 +11,7 @@ macro_rules! int_to_float { let mant_dig = <$fty>::SIGNIFICAND_BITS + 1; let exponent_bias = <$fty>::EXPONENT_BIAS; - let n = <$ity>::BITS; + let n = <$ity as Int>::BITS; let (s, a) = i.extract_sign(); let mut a = a; @@ -21,7 +21,7 @@ macro_rules! int_to_float { // exponent let mut e = sd - 1; - if <$ity>::BITS < mant_dig { + if <$ity as Int>::BITS < mant_dig { return <$fty>::from_parts( s, (e + exponent_bias) as <$fty as Float>::Int, @@ -165,7 +165,7 @@ macro_rules! float_to_int { let f = $f; let fixint_min = <$ity>::min_value(); let fixint_max = <$ity>::max_value(); - let fixint_bits = <$ity>::BITS as usize; + let fixint_bits = <$ity as Int>::BITS as usize; let fixint_unsigned = fixint_min == 0; let sign_bit = <$fty>::SIGN_MASK; diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 1e32560c2aeea..e5c0afc1eb009 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -1,7 +1,5 @@ -use core::ops; - -use int::Int; use int::LargeInt; +use int::{DInt, HInt, Int}; trait Mul: LargeInt { fn mul(self, other: Self) -> Self { @@ -29,59 +27,72 @@ trait Mul: LargeInt { impl Mul for u64 {} impl Mul for i128 {} -trait Mulo: Int + ops::Neg { - fn mulo(self, other: Self, overflow: &mut i32) -> Self { - *overflow = 0; - let result = self.wrapping_mul(other); - if self == Self::min_value() { - if other != Self::ZERO && other != Self::ONE { - *overflow = 1; +pub(crate) trait UMulo: Int + DInt { + fn mulo(self, rhs: Self) -> (Self, bool) { + match (self.hi().is_zero(), rhs.hi().is_zero()) { + // overflow is guaranteed + (false, false) => (self.wrapping_mul(rhs), true), + (true, false) => { + let mul_lo = self.lo().widen_mul(rhs.lo()); + let mul_hi = self.lo().widen_mul(rhs.hi()); + let (mul, o) = mul_lo.overflowing_add(mul_hi.lo().widen_hi()); + (mul, o || !mul_hi.hi().is_zero()) } - return result; - } - if other == Self::min_value() { - if self != Self::ZERO && self != Self::ONE { - *overflow = 1; + (false, true) => { + let mul_lo = rhs.lo().widen_mul(self.lo()); + let mul_hi = rhs.lo().widen_mul(self.hi()); + let (mul, o) = mul_lo.overflowing_add(mul_hi.lo().widen_hi()); + (mul, o || !mul_hi.hi().is_zero()) } - return result; + // overflow is guaranteed to not happen, and use a smaller widening multiplication + (true, true) => (self.lo().widen_mul(rhs.lo()), false), } + } +} - let sa = self >> (Self::BITS - 1); - let abs_a = (self ^ sa) - sa; - let sb = other >> (Self::BITS - 1); - let abs_b = (other ^ sb) - sb; - let two = Self::ONE + Self::ONE; - if abs_a < two || abs_b < two { - return result; - } - if sa == sb { - if abs_a > Self::max_value().aborting_div(abs_b) { - *overflow = 1; +impl UMulo for u32 {} +impl UMulo for u64 {} +impl UMulo for u128 {} + +macro_rules! impl_signed_mulo { + ($fn:ident, $iD:ident, $uD:ident) => { + fn $fn(lhs: $iD, rhs: $iD) -> ($iD, bool) { + let mut lhs = lhs; + let mut rhs = rhs; + // the test against `mul_neg` below fails without this early return + if lhs == 0 || rhs == 0 { + return (0, false); } - } else { - if abs_a > Self::min_value().aborting_div(-abs_b) { - *overflow = 1; + + let lhs_neg = lhs < 0; + let rhs_neg = rhs < 0; + if lhs_neg { + lhs = lhs.wrapping_neg(); } - } - result - } -} + if rhs_neg { + rhs = rhs.wrapping_neg(); + } + let mul_neg = lhs_neg != rhs_neg; -impl Mulo for i32 {} -impl Mulo for i64 {} -impl Mulo for i128 {} + let (mul, o) = (lhs as $uD).mulo(rhs as $uD); + let mut mul = mul as $iD; -trait UMulo: Int { - fn mulo(self, other: Self, overflow: &mut i32) -> Self { - *overflow = 0; - let result = self.wrapping_mul(other); - if self > Self::max_value().aborting_div(other) { - *overflow = 1; + if mul_neg { + mul = mul.wrapping_neg(); + } + if (mul < 0) != mul_neg { + // this one check happens to catch all edge cases related to `$iD::MIN` + (mul, true) + } else { + (mul, o) + } } - result - } + }; } -impl UMulo for u128 {} + +impl_signed_mulo!(i32_overflowing_mul, i32, u32); +impl_signed_mulo!(i64_overflowing_mul, i64, u64); +impl_signed_mulo!(i128_overflowing_mul, i128, u128); intrinsics! { #[maybe_use_optimized_c_shim] @@ -95,27 +106,29 @@ intrinsics! { } pub extern "C" fn __mulosi4(a: i32, b: i32, oflow: &mut i32) -> i32 { - a.mulo(b, oflow) + let (mul, o) = i32_overflowing_mul(a, b); + *oflow = o as i32; + mul } pub extern "C" fn __mulodi4(a: i64, b: i64, oflow: &mut i32) -> i64 { - a.mulo(b, oflow) + let (mul, o) = i64_overflowing_mul(a, b); + *oflow = o as i32; + mul } #[unadjusted_on_win64] pub extern "C" fn __muloti4(a: i128, b: i128, oflow: &mut i32) -> i128 { - a.mulo(b, oflow) + let (mul, o) = i128_overflowing_mul(a, b); + *oflow = o as i32; + mul } pub extern "C" fn __rust_i128_mulo(a: i128, b: i128) -> (i128, bool) { - let mut oflow = 0; - let r = __muloti4(a, b, &mut oflow); - (r, oflow != 0) + i128_overflowing_mul(a, b) } pub extern "C" fn __rust_u128_mulo(a: u128, b: u128) -> (u128, bool) { - let mut oflow = 0; - let r = a.mulo(b, &mut oflow); - (r, oflow != 0) + a.mulo(b) } } From fac884b0c47d6b5f7dfc23f8732b0b2ede315c99 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Mon, 12 Oct 2020 23:58:55 -0500 Subject: [PATCH 0888/4206] Completely replace `LargeInt` --- library/compiler-builtins/src/int/addsub.rs | 84 ++++++--------------- library/compiler-builtins/src/int/mod.rs | 44 ----------- library/compiler-builtins/src/int/mul.rs | 45 +++++------ library/compiler-builtins/src/int/shift.rs | 72 ++++++++---------- library/compiler-builtins/src/macros.rs | 8 +- 5 files changed, 83 insertions(+), 170 deletions(-) diff --git a/library/compiler-builtins/src/int/addsub.rs b/library/compiler-builtins/src/int/addsub.rs index 0a88e2fc8f13c..f4841e90f632e 100644 --- a/library/compiler-builtins/src/int/addsub.rs +++ b/library/compiler-builtins/src/int/addsub.rs @@ -1,25 +1,16 @@ -use int::Int; -use int::LargeInt; +use int::{DInt, Int}; -trait UAddSub: LargeInt { +trait UAddSub: DInt { fn uadd(self, other: Self) -> Self { - let (low, carry) = self.low().overflowing_add(other.low()); - let high = self.high().wrapping_add(other.high()); - let carry = if carry { - Self::HighHalf::ONE - } else { - Self::HighHalf::ZERO - }; - Self::from_parts(low, high.wrapping_add(carry)) + let (lo, carry) = self.lo().overflowing_add(other.lo()); + let hi = self.hi().wrapping_add(other.hi()); + let carry = if carry { Self::H::ONE } else { Self::H::ZERO }; + Self::from_lo_hi(lo, hi.wrapping_add(carry)) } fn uadd_one(self) -> Self { - let (low, carry) = self.low().overflowing_add(Self::LowHalf::ONE); - let carry = if carry { - Self::HighHalf::ONE - } else { - Self::HighHalf::ZERO - }; - Self::from_parts(low, self.high().wrapping_add(carry)) + let (lo, carry) = self.lo().overflowing_add(Self::H::ONE); + let carry = if carry { Self::H::ONE } else { Self::H::ZERO }; + Self::from_lo_hi(lo, self.hi().wrapping_add(carry)) } fn usub(self, other: Self) -> Self { let uneg = (!other).uadd_one(); @@ -48,19 +39,9 @@ trait Addo: AddSub where ::UnsignedInt: UAddSub, { - fn addo(self, other: Self, overflow: &mut i32) -> Self { - *overflow = 0; - let result = AddSub::add(self, other); - if other >= Self::ZERO { - if result < self { - *overflow = 1; - } - } else { - if result >= self { - *overflow = 1; - } - } - result + fn addo(self, other: Self) -> (Self, bool) { + let sum = AddSub::add(self, other); + (sum, (other < Self::ZERO) != (sum < self)) } } @@ -71,19 +52,9 @@ trait Subo: AddSub where ::UnsignedInt: UAddSub, { - fn subo(self, other: Self, overflow: &mut i32) -> Self { - *overflow = 0; - let result = AddSub::sub(self, other); - if other >= Self::ZERO { - if result > self { - *overflow = 1; - } - } else { - if result <= self { - *overflow = 1; - } - } - result + fn subo(self, other: Self) -> (Self, bool) { + let sum = AddSub::sub(self, other); + (sum, (other < Self::ZERO) != (self < sum)) } } @@ -92,43 +63,34 @@ impl Subo for u128 {} intrinsics! { pub extern "C" fn __rust_i128_add(a: i128, b: i128) -> i128 { - __rust_u128_add(a as _, b as _) as _ + AddSub::add(a,b) } pub extern "C" fn __rust_i128_addo(a: i128, b: i128) -> (i128, bool) { - let mut oflow = 0; - let r = a.addo(b, &mut oflow); - (r, oflow != 0) + a.addo(b) } pub extern "C" fn __rust_u128_add(a: u128, b: u128) -> u128 { - a.add(b) + AddSub::add(a,b) } pub extern "C" fn __rust_u128_addo(a: u128, b: u128) -> (u128, bool) { - let mut oflow = 0; - let r = a.addo(b, &mut oflow); - (r, oflow != 0) + a.addo(b) } - pub extern "C" fn __rust_i128_sub(a: i128, b: i128) -> i128 { - __rust_u128_sub(a as _, b as _) as _ + AddSub::sub(a,b) } pub extern "C" fn __rust_i128_subo(a: i128, b: i128) -> (i128, bool) { - let mut oflow = 0; - let r = a.subo(b, &mut oflow); - (r, oflow != 0) + a.subo(b) } pub extern "C" fn __rust_u128_sub(a: u128, b: u128) -> u128 { - a.sub(b) + AddSub::sub(a,b) } pub extern "C" fn __rust_u128_subo(a: u128, b: u128) -> (u128, bool) { - let mut oflow = 0; - let r = a.subo(b, &mut oflow); - (r, oflow != 0) + a.subo(b) } } diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index da2263f6ef804..1ce3d92da38a0 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -384,50 +384,6 @@ impl_h_int!( i64 u64 i128 ); -/// Trait to convert an integer to/from smaller parts -pub(crate) trait LargeInt: Int { - type LowHalf: Int; - type HighHalf: Int; - - fn low(self) -> Self::LowHalf; - fn low_as_high(low: Self::LowHalf) -> Self::HighHalf; - fn high(self) -> Self::HighHalf; - fn high_as_low(low: Self::HighHalf) -> Self::LowHalf; - fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self; -} - -macro_rules! large_int { - ($ty:ty, $tylow:ty, $tyhigh:ty, $halfbits:expr) => { - impl LargeInt for $ty { - type LowHalf = $tylow; - type HighHalf = $tyhigh; - - fn low(self) -> $tylow { - self as $tylow - } - fn low_as_high(low: $tylow) -> $tyhigh { - low as $tyhigh - } - fn high(self) -> $tyhigh { - (self >> $halfbits) as $tyhigh - } - fn high_as_low(high: $tyhigh) -> $tylow { - high as $tylow - } - fn from_parts(low: $tylow, high: $tyhigh) -> $ty { - low as $ty | ((high as $ty) << $halfbits) - } - } - }; -} - -large_int!(u32, u16, u16, 16); -large_int!(i32, u16, i16, 16); -large_int!(u64, u32, u32, 32); -large_int!(i64, u32, i32, 32); -large_int!(u128, u64, u64, 64); -large_int!(i128, u64, i64, 64); - /// Trait to express (possibly lossy) casting of integers pub(crate) trait CastInto: Copy { fn cast(self) -> T; diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index e5c0afc1eb009..a5238eeac70e3 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -1,26 +1,29 @@ -use int::LargeInt; use int::{DInt, HInt, Int}; -trait Mul: LargeInt { - fn mul(self, other: Self) -> Self { - let half_bits = Self::BITS / 4; - let lower_mask = !<::LowHalf>::ZERO >> half_bits; - let mut low = (self.low() & lower_mask).wrapping_mul(other.low() & lower_mask); - let mut t = low >> half_bits; - low &= lower_mask; - t += (self.low() >> half_bits).wrapping_mul(other.low() & lower_mask); - low += (t & lower_mask) << half_bits; - let mut high = Self::low_as_high(t >> half_bits); - t = low >> half_bits; - low &= lower_mask; - t += (other.low() >> half_bits).wrapping_mul(self.low() & lower_mask); - low += (t & lower_mask) << half_bits; - high += Self::low_as_high(t >> half_bits); - high += Self::low_as_high((self.low() >> half_bits).wrapping_mul(other.low() >> half_bits)); - high = high - .wrapping_add(self.high().wrapping_mul(Self::low_as_high(other.low()))) - .wrapping_add(Self::low_as_high(self.low()).wrapping_mul(other.high())); - Self::from_parts(low, high) +trait Mul: DInt +where + Self::H: DInt, +{ + fn mul(self, rhs: Self) -> Self { + // In order to prevent infinite recursion, we cannot use the `widen_mul` in this: + //self.lo().widen_mul(rhs.lo()) + // .wrapping_add(self.lo().wrapping_mul(rhs.hi()).widen_hi()) + // .wrapping_add(self.hi().wrapping_mul(rhs.lo()).widen_hi()) + + let lhs_lo = self.lo(); + let rhs_lo = rhs.lo(); + // construct the widening multiplication using only `Self::H` sized multiplications + let tmp_0 = lhs_lo.lo().zero_widen_mul(rhs_lo.lo()); + let tmp_1 = lhs_lo.lo().zero_widen_mul(rhs_lo.hi()); + let tmp_2 = lhs_lo.hi().zero_widen_mul(rhs_lo.lo()); + let tmp_3 = lhs_lo.hi().zero_widen_mul(rhs_lo.hi()); + // sum up all widening partials + let mul = Self::from_lo_hi(tmp_0, tmp_3) + .wrapping_add(tmp_1.zero_widen() << (Self::BITS / 4)) + .wrapping_add(tmp_2.zero_widen() << (Self::BITS / 4)); + // add the higher partials + mul.wrapping_add(lhs_lo.wrapping_mul(rhs.hi()).widen_hi()) + .wrapping_add(self.hi().wrapping_mul(rhs_lo).widen_hi()) } } diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 674c3ee8ca7d2..20561786b2f05 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -1,20 +1,18 @@ -use int::{Int, LargeInt}; +use int::{DInt, HInt, Int}; -trait Ashl: Int + LargeInt { +trait Ashl: DInt { /// Returns `a << b`, requires `b < Self::BITS` - fn ashl(self, offset: u32) -> Self - where - Self: LargeInt::LowHalf>, - { - let half_bits = Self::BITS / 2; - if offset & half_bits != 0 { - Self::from_parts(Int::ZERO, self.low() << (offset - half_bits)) - } else if offset == 0 { + fn ashl(self, shl: u32) -> Self { + let n_h = Self::H::BITS; + if shl & n_h != 0 { + // we only need `self.lo()` because `self.hi()` will be shifted out entirely + (self.lo() << (shl - n_h)).widen_hi() + } else if shl == 0 { self } else { - Self::from_parts( - self.low() << offset, - (self.high() << offset) | (self.low() >> (half_bits - offset)), + Self::from_lo_hi( + self.lo() << shl, + self.lo().logical_shr(n_h - shl) | (self.hi() << shl), ) } } @@ -24,25 +22,22 @@ impl Ashl for u32 {} impl Ashl for u64 {} impl Ashl for u128 {} -trait Ashr: Int + LargeInt { +trait Ashr: DInt { /// Returns arithmetic `a >> b`, requires `b < Self::BITS` - fn ashr(self, offset: u32) -> Self - where - Self: LargeInt::HighHalf as Int>::UnsignedInt>, - { - let half_bits = Self::BITS / 2; - if offset & half_bits != 0 { - Self::from_parts( - (self.high() >> (offset - half_bits)).unsigned(), - self.high() >> (half_bits - 1), + fn ashr(self, shr: u32) -> Self { + let n_h = Self::H::BITS; + if shr & n_h != 0 { + Self::from_lo_hi( + self.hi() >> (shr - n_h), + // smear the sign bit + self.hi() >> (n_h - 1), ) - } else if offset == 0 { + } else if shr == 0 { self } else { - let high_unsigned = self.high().unsigned(); - Self::from_parts( - (high_unsigned << (half_bits - offset)) | (self.low() >> offset), - self.high() >> offset, + Self::from_lo_hi( + self.lo().logical_shr(shr) | (self.hi() << (n_h - shr)), + self.hi() >> shr, ) } } @@ -52,21 +47,18 @@ impl Ashr for i32 {} impl Ashr for i64 {} impl Ashr for i128 {} -trait Lshr: Int + LargeInt { +trait Lshr: DInt { /// Returns logical `a >> b`, requires `b < Self::BITS` - fn lshr(self, offset: u32) -> Self - where - Self: LargeInt::LowHalf>, - { - let half_bits = Self::BITS / 2; - if offset & half_bits != 0 { - Self::from_parts(self.high() >> (offset - half_bits), Int::ZERO) - } else if offset == 0 { + fn lshr(self, shr: u32) -> Self { + let n_h = Self::H::BITS; + if shr & n_h != 0 { + self.hi().logical_shr(shr - n_h).zero_widen() + } else if shr == 0 { self } else { - Self::from_parts( - (self.high() << (half_bits - offset)) | (self.low() >> offset), - self.high() >> offset, + Self::from_lo_hi( + self.lo().logical_shr(shr) | (self.hi() << (n_h - shr)), + self.hi().logical_shr(shr), ) } } diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index b02f3ea5cedbe..56f27164a9399 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -284,16 +284,16 @@ pub mod win64_128bit_abi_hack { impl From for U64x2 { fn from(i: i128) -> U64x2 { - use int::LargeInt; + use int::DInt; let j = i as u128; - U64x2(j.low(), j.high()) + U64x2(j.lo(), j.hi()) } } impl From for U64x2 { fn from(i: u128) -> U64x2 { - use int::LargeInt; - U64x2(i.low(), i.high()) + use int::DInt; + U64x2(i.lo(), i.hi()) } } } From cb4e9755b8620c59407080fc9d2c6cf14f46947a Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Tue, 1 Dec 2020 23:16:26 -0600 Subject: [PATCH 0889/4206] Remove `WideInt` --- library/compiler-builtins/src/float/cmp.rs | 19 ++------- library/compiler-builtins/src/float/div.rs | 10 ++--- library/compiler-builtins/src/float/mod.rs | 11 ++++-- library/compiler-builtins/src/float/mul.rs | 30 +++++++++------ library/compiler-builtins/src/int/mod.rs | 45 ---------------------- 5 files changed, 36 insertions(+), 79 deletions(-) diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 20ab92e4b9adc..79c26b09921fc 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -1,7 +1,7 @@ #![allow(unreachable_code)] use float::Float; -use int::{CastInto, Int}; +use int::Int; #[derive(Clone, Copy)] enum Result { @@ -31,13 +31,7 @@ impl Result { } } -fn cmp(a: F, b: F) -> Result -where - u32: CastInto, - F::Int: CastInto, - i32: CastInto, - F::Int: CastInto, -{ +fn cmp(a: F, b: F) -> Result { let one = F::Int::ONE; let zero = F::Int::ZERO; let szero = F::SignedInt::ZERO; @@ -90,13 +84,8 @@ where } } } -fn unord(a: F, b: F) -> bool -where - u32: CastInto, - F::Int: CastInto, - i32: CastInto, - F::Int: CastInto, -{ + +fn unord(a: F, b: F) -> bool { let one = F::Int::ONE; let sign_bit = F::SIGN_MASK as F::Int; diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index 7c582a4408d75..dd6467f88fb7e 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -1,5 +1,5 @@ use float::Float; -use int::{CastInto, Int, WideInt}; +use int::{CastInto, DInt, HInt, Int}; fn div32(a: F, b: F) -> F where @@ -7,7 +7,7 @@ where F::Int: CastInto, i32: CastInto, F::Int: CastInto, - F::Int: WideInt, + F::Int: HInt, { let one = F::Int::ONE; let zero = F::Int::ZERO; @@ -156,7 +156,7 @@ where // is the error in the reciprocal of b scaled by the maximum // possible value of a. As a consequence of this error bound, // either q or nextafter(q) is the correctly rounded - let (mut quotient, _) = ::wide_mul(a_significand << 1, reciprocal.cast()); + let mut quotient = (a_significand << 1).widen_mul(reciprocal.cast()).hi(); // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0). // In either case, we are going to compute a residual of the form @@ -211,7 +211,7 @@ where F::Int: CastInto, i64: CastInto, F::Int: CastInto, - F::Int: WideInt, + F::Int: HInt, { let one = F::Int::ONE; let zero = F::Int::ZERO; @@ -394,7 +394,7 @@ where // We need a 64 x 64 multiply high to compute q, which isn't a basic // operation in C, so we need to be a little bit fussy. - let (mut quotient, _) = ::wide_mul(a_significand << 2, reciprocal.cast()); + let mut quotient = (a_significand << 2).widen_mul(reciprocal.cast()).hi(); // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0). // In either case, we are going to compute a residual of the form diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 06e9aad4b4263..34b3c6ac1e88e 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -13,7 +13,8 @@ pub mod pow; pub mod sub; /// Trait for some basic operations on floats -pub(crate) trait Float: +#[doc(hidden)] +pub trait Float: Copy + PartialEq + PartialOrd @@ -66,7 +67,6 @@ pub(crate) trait Float: /// Returns `self` transmuted to `Self::SignedInt` fn signed_repr(self) -> Self::SignedInt; - #[cfg(test)] /// 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. @@ -80,6 +80,9 @@ pub(crate) trait Float: /// Returns (normalized exponent, normalized significand) fn normalize(significand: Self::Int) -> (i32, Self::Int); + + /// Returns if `self` is subnormal + fn is_subnormal(&self) -> bool; } // FIXME: Some of this can be removed if RFC Issue #1424 is resolved @@ -106,7 +109,6 @@ macro_rules! float_impl { fn signed_repr(self) -> Self::SignedInt { unsafe { mem::transmute(self) } } - #[cfg(test)] fn eq_repr(self, rhs: Self) -> bool { if self.is_nan() && rhs.is_nan() { true @@ -133,6 +135,9 @@ macro_rules! float_impl { significand << shift as Self::Int, ) } + fn is_subnormal(&self) -> bool { + (self.repr() & Self::EXPONENT_MASK) == Self::Int::ZERO + } } }; } diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index 7b28793c8e700..540e7bdcfe301 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -1,5 +1,5 @@ use float::Float; -use int::{CastInto, Int, WideInt}; +use int::{CastInto, DInt, HInt, Int}; fn mul(a: F, b: F) -> F where @@ -7,7 +7,7 @@ where F::Int: CastInto, i32: CastInto, F::Int: CastInto, - F::Int: WideInt, + F::Int: HInt, { let one = F::Int::ONE; let zero = F::Int::ZERO; @@ -112,8 +112,9 @@ where // have (exponentBits + 2) integral digits, all but two of which must be // zero. Normalizing this result is just a conditional left-shift by one // and bumping the exponent accordingly. - let (mut product_high, mut product_low) = - ::wide_mul(a_significand, b_significand << exponent_bits); + let (mut product_low, mut product_high) = a_significand + .widen_mul(b_significand << exponent_bits) + .lo_hi(); let a_exponent_i32: i32 = a_exponent.cast(); let b_exponent_i32: i32 = b_exponent.cast(); @@ -126,7 +127,8 @@ where if (product_high & implicit_bit) != zero { product_exponent = product_exponent.wrapping_add(1); } else { - ::wide_shift_left(&mut product_high, &mut product_low, 1); + product_high = (product_high << 1) | (product_low >> (bits - 1)); + product_low <<= 1; } // If we have overflowed the type, return +/- infinity. @@ -142,17 +144,23 @@ where // handle this case separately, but we make it a special case to // simplify the shift logic. let shift = one.wrapping_sub(product_exponent.cast()).cast(); - if shift >= bits as i32 { + if shift >= bits { return F::from_repr(product_sign); } // Otherwise, shift the significand of the result so that the round // bit is the high bit of productLo. - ::wide_shift_right_with_sticky( - &mut product_high, - &mut product_low, - shift, - ) + if shift < bits { + let sticky = product_low << (bits - shift); + product_low = product_high << (bits - shift) | product_low >> shift | sticky; + product_high >>= shift; + } else if shift < (2 * bits) { + let sticky = product_high << (2 * bits - shift) | product_low; + product_low = product_high >> (shift - bits) | sticky; + product_high = zero; + } else { + product_high = zero; + } } else { // Result is normal before rounding; insert the exponent. product_high &= significand_mask; diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 1ce3d92da38a0..d23028263d88f 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -408,48 +408,3 @@ cast_into!(u64); cast_into!(i64); cast_into!(u128); cast_into!(i128); - -pub(crate) trait WideInt: Int { - type Output: Int; - - fn wide_mul(self, other: Self) -> (Self, Self); - fn wide_shift_left(&mut self, low: &mut Self, count: i32); - fn wide_shift_right_with_sticky(&mut self, low: &mut Self, count: i32); -} - -macro_rules! impl_wide_int { - ($ty:ty, $tywide:ty, $bits:expr) => { - impl WideInt for $ty { - type Output = $ty; - - fn wide_mul(self, other: Self) -> (Self, Self) { - let product = (self as $tywide).wrapping_mul(other as $tywide); - ((product >> ($bits as $ty)) as $ty, product as $ty) - } - - fn wide_shift_left(&mut self, low: &mut Self, count: i32) { - *self = (*self << count) | (*low >> ($bits - count)); - *low = *low << count; - } - - fn wide_shift_right_with_sticky(&mut self, low: &mut Self, count: i32) { - if count < $bits { - let sticky = *low << ($bits - count); - *low = *self << ($bits - count) | *low >> count | sticky; - *self = *self >> count; - } else if count < 2 * $bits { - let sticky = *self << (2 * $bits - count) | *low; - *low = *self >> (count - $bits) | sticky; - *self = 0; - } else { - let sticky = *self | *low; - *self = sticky; - *self = 0; - } - } - } - }; -} - -impl_wide_int!(u32, u64, 32); -impl_wide_int!(u64, u128, 64); From 26681724f35c6d941abbdcffc426255bc4a4adb2 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Tue, 1 Dec 2020 23:09:57 -0600 Subject: [PATCH 0890/4206] replace some transmutes --- library/compiler-builtins/src/float/mod.rs | 9 +++------ library/compiler-builtins/testcrate/build.rs | 8 ++++---- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 34b3c6ac1e88e..c4b6901613fbd 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,4 +1,3 @@ -use core::mem; use core::ops; use super::int::Int; @@ -85,8 +84,6 @@ pub trait Float: fn is_subnormal(&self) -> bool; } -// FIXME: Some of this can be removed if RFC Issue #1424 is resolved -// https://github.com/rust-lang/rfcs/issues/1424 macro_rules! float_impl { ($ty:ident, $ity:ident, $sity:ident, $bits:expr, $significand_bits:expr) => { impl Float for $ty { @@ -104,10 +101,10 @@ macro_rules! float_impl { const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); fn repr(self) -> Self::Int { - unsafe { mem::transmute(self) } + self.to_bits() } fn signed_repr(self) -> Self::SignedInt { - unsafe { mem::transmute(self) } + self.to_bits() as Self::SignedInt } fn eq_repr(self, rhs: Self) -> bool { if self.is_nan() && rhs.is_nan() { @@ -117,7 +114,7 @@ macro_rules! float_impl { } } fn from_repr(a: Self::Int) -> Self { - unsafe { mem::transmute(a) } + Self::from_bits(a) } fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { Self::from_repr( diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 1baa6a9660755..1ecd0179e8854 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -633,7 +633,7 @@ fn main() { if a.0.is_nan() || b.0.is_nan() || c.is_nan() - || c.abs() <= unsafe { mem::transmute(4503599627370495u64) } + || c.abs() <= f64::from_bits(4503599627370495u64) { None } else { @@ -651,7 +651,7 @@ fn main() { if a.0.is_nan() || b.0.is_nan() || c.is_nan() - || c.abs() <= unsafe { mem::transmute(16777215u32) } + || c.abs() <= f32::from_bits(16777215u32) { None } else { @@ -671,7 +671,7 @@ fn main() { if a.0.is_nan() || b.0.is_nan() || c.is_nan() - || c.abs() <= unsafe { mem::transmute(4503599627370495u64) } + || c.abs() <= f64::from_bits(4503599627370495u64) { None } else { @@ -689,7 +689,7 @@ fn main() { if a.0.is_nan() || b.0.is_nan() || c.is_nan() - || c.abs() <= unsafe { mem::transmute(16777215u32) } + || c.abs() <= f32::from_bits(16777215u32) { None } else { From f61c411e2b51ad1d8af1d6e8bdb46ece7b669ff1 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Sat, 7 Nov 2020 13:09:51 -0600 Subject: [PATCH 0891/4206] fix some clippy warnings --- library/compiler-builtins/src/mem/impls.rs | 8 +++----- library/compiler-builtins/src/mem/mod.rs | 4 ++-- library/compiler-builtins/src/mem/x86_64.rs | 4 ++-- library/compiler-builtins/testcrate/build.rs | 5 +---- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/library/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/src/mem/impls.rs index 6bd1a7ba1db2a..b3eef9901dd55 100644 --- a/library/compiler-builtins/src/mem/impls.rs +++ b/library/compiler-builtins/src/mem/impls.rs @@ -1,10 +1,8 @@ -use super::c_int; - #[inline(always)] pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, n: usize) { let mut i = 0; while i < n { - *dest.offset(i as isize) = *src.offset(i as isize); + *dest.add(i) = *src.add(i); i += 1; } } @@ -15,7 +13,7 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, n: usize) { let mut i = n; while i != 0 { i -= 1; - *dest.offset(i as isize) = *src.offset(i as isize); + *dest.add(i) = *src.add(i); } } @@ -23,7 +21,7 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, n: usize) { pub unsafe fn set_bytes(s: *mut u8, c: u8, n: usize) { let mut i = 0; while i < n { - *s.offset(i as isize) = c; + *s.add(i) = c; i += 1; } } diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index adb7c2c64c9ab..107762c43a6d9 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -45,8 +45,8 @@ pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { let mut i = 0; while i < n { - let a = *s1.offset(i as isize); - let b = *s2.offset(i as isize); + let a = *s1.add(i); + let b = *s2.add(i); if a != b { return a as i32 - b as i32; } diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 7eefd8099b957..8cbbdf779a6a0 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -59,8 +59,8 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { "cld", byte_count = in(reg) byte_count, inout("rcx") qword_count => _, - inout("rdi") dest.offset(count as isize).wrapping_sub(8) => _, - inout("rsi") src.offset(count as isize).wrapping_sub(8) => _, + inout("rdi") dest.add(count).wrapping_sub(8) => _, + inout("rsi") src.add(count).wrapping_sub(8) => _, options(nostack) ); } diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 1ecd0179e8854..39c2486c692e8 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -648,10 +648,7 @@ fn main() { return None; } let c = a.0 / b.0; - if a.0.is_nan() - || b.0.is_nan() - || c.is_nan() - || c.abs() <= f32::from_bits(16777215u32) + if a.0.is_nan() || b.0.is_nan() || c.is_nan() || c.abs() <= f32::from_bits(16777215u32) { None } else { From 69a3c571f7f8273d21d1a6a35f8d536142ab1270 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Mon, 7 Dec 2020 23:25:42 -0600 Subject: [PATCH 0892/4206] Completely overhaul fuzz testing adds testing for almost every numerical intrinsic --- library/compiler-builtins/src/int/mod.rs | 11 + .../compiler-builtins/testcrate/Cargo.toml | 2 +- .../compiler-builtins/testcrate/src/lib.rs | 258 ++++++++++++++++++ .../testcrate/tests/addsub.rs | 109 ++++++++ .../compiler-builtins/testcrate/tests/cmp.rs | 52 ++++ .../compiler-builtins/testcrate/tests/conv.rs | 125 +++++++++ .../testcrate/tests/div_rem.rs | 147 +++++----- .../testcrate/tests/leading_zeros.rs | 54 ---- .../compiler-builtins/testcrate/tests/misc.rs | 134 +++++++++ .../compiler-builtins/testcrate/tests/mul.rs | 114 ++++++++ .../testcrate/tests/shift.rs | 60 ++++ 11 files changed, 937 insertions(+), 129 deletions(-) create mode 100644 library/compiler-builtins/testcrate/tests/addsub.rs create mode 100644 library/compiler-builtins/testcrate/tests/cmp.rs create mode 100644 library/compiler-builtins/testcrate/tests/conv.rs delete mode 100644 library/compiler-builtins/testcrate/tests/leading_zeros.rs create mode 100644 library/compiler-builtins/testcrate/tests/misc.rs create mode 100644 library/compiler-builtins/testcrate/tests/mul.rs create mode 100644 library/compiler-builtins/testcrate/tests/shift.rs diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index d23028263d88f..cb94803a47035 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -72,6 +72,9 @@ pub trait Int: /// Prevents the need for excessive conversions between signed and unsigned fn logical_shr(self, other: u32) -> Self; + /// Absolute difference between two integers. + fn abs_diff(self, other: Self) -> Self::UnsignedInt; + // copied from primitive integers, but put in a trait fn is_zero(self) -> bool; fn max_value() -> Self; @@ -251,6 +254,10 @@ macro_rules! int_impl { me } + fn abs_diff(self, other: Self) -> Self { + (self.wrapping_sub(other) as $ity).wrapping_abs() as $uty + } + int_impl_common!($uty, $bits); } @@ -274,6 +281,10 @@ macro_rules! int_impl { me as $ity } + fn abs_diff(self, other: Self) -> $uty { + self.wrapping_sub(other).wrapping_abs() as $uty + } + int_impl_common!($ity, $bits); } }; diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index ce8df2d12c529..ff9a6a453bba4 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -11,7 +11,7 @@ doctest = false [build-dependencies] rand = "0.7" -[dev-dependencies] +[dependencies] # 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. # `xoshiro128**` is used for its quality, size, and speed at generating `u32` shift amounts. diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index 0c9ac1ac8e4bd..9bd155f6f1048 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -1 +1,259 @@ +//! This crate is for integration testing and fuzz testing of functions in `compiler-builtins`. This +//! includes publicly documented intrinsics and some internal alternative implementation functions +//! such as `usize_leading_zeros_riscv` (which are tested because they are configured for +//! architectures not tested by the CI). +//! +//! The general idea is to use a combination of edge case testing and randomized fuzz testing. The +//! edge case testing is crucial for checking cases like where both inputs are equal or equal to +//! special values such as `i128::MIN`, which is unlikely for the random fuzzer by itself to +//! encounter. The randomized fuzz testing is specially designed to cover wide swaths of search +//! space in as few iterations as possible. See `fuzz_values` in `testcrate/tests/misc.rs` for an +//! example. +//! +//! Some floating point tests are disabled for specific architectures, because they do not have +//! correct rounding. #![no_std] + +use compiler_builtins::float::Float; +use compiler_builtins::int::Int; + +use rand_xoshiro::rand_core::{RngCore, SeedableRng}; +use rand_xoshiro::Xoshiro128StarStar; + +/// Sets the number of fuzz iterations run for most tests. In practice, the vast majority of bugs +/// are caught by the edge case testers. Most of the remaining bugs triggered by more complex +/// sequences are caught well within 10_000 fuzz iterations. For classes of algorithms like division +/// that are vulnerable to rare edge cases, we want 1_000_000 iterations to be more confident. In +/// practical CI, however, we only want to run the more strenuous test once to catch algorithmic +/// level bugs, and run the 10_000 iteration test on most targets. Target-dependent bugs are likely +/// to involve miscompilation and misconfiguration that is likely to break algorithms in quickly +/// caught ways. We choose to configure `N = 1_000_000` iterations for `x86_64` targets (and if +/// debug assertions are disabled. Tests without `--release` would take too long) which are likely +/// to have fast hardware, and run `N = 10_000` for all other targets. +pub const N: u32 = if cfg!(target_arch = "x86_64") && !cfg!(debug_assertions) { + 1_000_000 +} else { + 10_000 +}; + +/// Random fuzzing step. When run several times, it results in excellent fuzzing entropy such as: +/// 11110101010101011110111110011111 +/// 10110101010100001011101011001010 +/// 1000000000000000 +/// 10000000000000110111110000001010 +/// 1111011111111101010101111110101 +/// 101111111110100000000101000000 +/// 10000000110100000000100010101 +/// 1010101010101000 +fn fuzz_step(rng: &mut Xoshiro128StarStar, x: &mut I) { + let ones = !I::ZERO; + let bit_indexing_mask: u32 = I::BITS - 1; + // It happens that all the RNG we need can come from one call. 7 bits are needed to index a + // worst case 128 bit integer, and there are 4 indexes that need to be made plus 4 bits for + // selecting operations + let rng32 = rng.next_u32(); + + // Randomly OR, AND, and XOR randomly sized and shifted continuous strings of + // ones with `lhs` and `rhs`. + let r0 = bit_indexing_mask & rng32; + let r1 = bit_indexing_mask & (rng32 >> 7); + let mask = ones.wrapping_shl(r0).rotate_left(r1); + match (rng32 >> 14) % 4 { + 0 => *x |= mask, + 1 => *x &= mask, + // both 2 and 3 to make XORs as common as ORs and ANDs combined + _ => *x ^= mask, + } + + // Alternating ones and zeros (e.x. 0b1010101010101010). This catches second-order + // problems that might occur for algorithms with two modes of operation (potentially + // there is some invariant that can be broken and maintained via alternating between modes, + // breaking the algorithm when it reaches the end). + let mut alt_ones = I::ONE; + for _ in 0..(I::BITS / 2) { + alt_ones <<= 2; + alt_ones |= I::ONE; + } + let r0 = bit_indexing_mask & (rng32 >> 16); + let r1 = bit_indexing_mask & (rng32 >> 23); + let mask = alt_ones.wrapping_shl(r0).rotate_left(r1); + match rng32 >> 30 { + 0 => *x |= mask, + 1 => *x &= mask, + _ => *x ^= mask, + } +} + +// We need macros like this, because `#![no_std]` prevents us from using iterators +macro_rules! edge_cases { + ($I:ident, $case:ident, $inner:block) => { + for i0 in 0..$I::FUZZ_NUM { + let mask_lo = (!$I::UnsignedInt::ZERO).wrapping_shr($I::FUZZ_LENGTHS[i0] as u32); + for i1 in i0..I::FUZZ_NUM { + let mask_hi = + (!$I::UnsignedInt::ZERO).wrapping_shl($I::FUZZ_LENGTHS[i1 - i0] as u32); + let $case = I::from_unsigned(mask_lo & mask_hi); + $inner + } + } + }; +} + +/// Feeds a series of fuzzing inputs to `f`. The fuzzer first uses an algorithm designed to find +/// edge cases, followed by a more random fuzzer that runs `n` times. +pub fn fuzz(n: u32, mut f: F) { + // edge case tester. Calls `f` 210 times for u128. + // zero gets skipped by the loop + f(I::ZERO); + edge_cases!(I, case, { + f(case); + }); + + // random fuzzer + let mut rng = Xoshiro128StarStar::seed_from_u64(0); + let mut x: I = Int::ZERO; + for _ in 0..n { + fuzz_step(&mut rng, &mut x); + f(x) + } +} + +/// The same as `fuzz`, except `f` has two inputs. +pub fn fuzz_2(n: u32, f: F) { + // Check cases where the first and second inputs are zero. Both call `f` 210 times for `u128`. + edge_cases!(I, case, { + f(I::ZERO, case); + }); + edge_cases!(I, case, { + f(case, I::ZERO); + }); + // Nested edge tester. Calls `f` 44100 times for `u128`. + edge_cases!(I, case0, { + edge_cases!(I, case1, { + f(case0, case1); + }) + }); + + // random fuzzer + let mut rng = Xoshiro128StarStar::seed_from_u64(0); + let mut x: I = I::ZERO; + let mut y: I = I::ZERO; + for _ in 0..n { + fuzz_step(&mut rng, &mut x); + fuzz_step(&mut rng, &mut y); + f(x, y) + } +} + +/// Tester for shift functions +pub fn fuzz_shift(f: F) { + // Shift functions are very simple and do not need anything other than shifting a small + // set of random patterns for every fuzz length. + let mut rng = Xoshiro128StarStar::seed_from_u64(0); + let mut x: I = Int::ZERO; + for i in 0..I::FUZZ_NUM { + fuzz_step(&mut rng, &mut x); + f(x, Int::ZERO); + f(x, I::FUZZ_LENGTHS[i] as u32); + } +} + +fn fuzz_float_step(rng: &mut Xoshiro128StarStar, f: &mut F) { + let rng32 = rng.next_u32(); + // we need to fuzz the different parts of the float separately, because the masking on larger + // significands will tend to set the exponent to all ones or all zeros frequently + + // sign bit fuzzing + let sign = (rng32 & 1) != 0; + + // exponent fuzzing. Only 4 bits for the selector needed. + let ones = (F::Int::ONE << F::EXPONENT_BITS) - F::Int::ONE; + let r0 = (rng32 >> 1) % F::EXPONENT_BITS; + let r1 = (rng32 >> 5) % F::EXPONENT_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) + } else { + let tmp = ones.wrapping_shr(r0); + (tmp.wrapping_shl(r1) | tmp.wrapping_shr(F::EXPONENT_BITS - r1)) & ones + }; + let mut exp = (f.repr() & F::EXPONENT_MASK) >> F::SIGNIFICAND_BITS; + match (rng32 >> 9) % 4 { + 0 => exp |= mask, + 1 => exp &= mask, + _ => exp ^= mask, + } + + // significand fuzzing + let mut sig = f.repr() & F::SIGNIFICAND_MASK; + fuzz_step(rng, &mut sig); + sig &= F::SIGNIFICAND_MASK; + + *f = F::from_parts(sign, exp, sig); +} + +macro_rules! float_edge_cases { + ($F:ident, $case:ident, $inner:block) => { + for exponent in [ + F::Int::ZERO, + F::Int::ONE, + F::Int::ONE << (F::EXPONENT_BITS / 2), + (F::Int::ONE << (F::EXPONENT_BITS - 1)) - F::Int::ONE, + F::Int::ONE << (F::EXPONENT_BITS - 1), + (F::Int::ONE << (F::EXPONENT_BITS - 1)) + F::Int::ONE, + (F::Int::ONE << F::EXPONENT_BITS) - F::Int::ONE, + ] + .iter() + { + for significand in [ + F::Int::ZERO, + F::Int::ONE, + F::Int::ONE << (F::SIGNIFICAND_BITS / 2), + (F::Int::ONE << (F::SIGNIFICAND_BITS - 1)) - F::Int::ONE, + F::Int::ONE << (F::SIGNIFICAND_BITS - 1), + (F::Int::ONE << (F::SIGNIFICAND_BITS - 1)) + F::Int::ONE, + (F::Int::ONE << F::SIGNIFICAND_BITS) - F::Int::ONE, + ] + .iter() + { + for sign in [false, true].iter() { + let $case = F::from_parts(*sign, *exponent, *significand); + $inner + } + } + } + }; +} + +pub fn fuzz_float(n: u32, f: E) { + float_edge_cases!(F, case, { + f(case); + }); + + // random fuzzer + let mut rng = Xoshiro128StarStar::seed_from_u64(0); + let mut x = F::ZERO; + for _ in 0..n { + fuzz_float_step(&mut rng, &mut x); + f(x); + } +} + +pub fn fuzz_float_2(n: u32, f: E) { + float_edge_cases!(F, case0, { + float_edge_cases!(F, case1, { + f(case0, case1); + }); + }); + + // random fuzzer + let mut rng = Xoshiro128StarStar::seed_from_u64(0); + let mut x = F::ZERO; + let mut y = F::ZERO; + for _ in 0..n { + fuzz_float_step(&mut rng, &mut x); + fuzz_float_step(&mut rng, &mut y); + f(x, y) + } +} diff --git a/library/compiler-builtins/testcrate/tests/addsub.rs b/library/compiler-builtins/testcrate/tests/addsub.rs new file mode 100644 index 0000000000000..ff56668b78b8f --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/addsub.rs @@ -0,0 +1,109 @@ +use testcrate::*; + +macro_rules! sum { + ($($i:ty, $fn_add:ident, $fn_sub:ident);*;) => { + $( + fuzz_2(N, |x: $i, y: $i| { + let add0 = x.wrapping_add(y); + let sub0 = x.wrapping_sub(y); + let add1: $i = $fn_add(x, y); + let sub1: $i = $fn_sub(x, y); + if add0 != add1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn_add), x, y, add0, add1 + ); + } + if sub0 != sub1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn_sub), x, y, sub0, sub1 + ); + } + }); + )* + }; +} + +macro_rules! overflowing_sum { + ($($i:ty, $fn_add:ident, $fn_sub:ident);*;) => { + $( + fuzz_2(N, |x: $i, y: $i| { + let add0 = x.overflowing_add(y); + let sub0 = x.overflowing_sub(y); + let add1: ($i, bool) = $fn_add(x, y); + let sub1: ($i, bool) = $fn_sub(x, y); + if add0.0 != add1.0 || add0.1 != add1.1 { + panic!( + "{}({}, {}): std: {:?}, builtins: {:?}", + stringify!($fn_add), x, y, add0, add1 + ); + } + if sub0.0 != sub1.0 || sub0.1 != sub1.1 { + panic!( + "{}({}, {}): std: {:?}, builtins: {:?}", + stringify!($fn_sub), x, y, sub0, sub1 + ); + } + }); + )* + }; +} + +#[test] +fn addsub() { + use compiler_builtins::int::addsub::{ + __rust_i128_add, __rust_i128_addo, __rust_i128_sub, __rust_i128_subo, __rust_u128_add, + __rust_u128_addo, __rust_u128_sub, __rust_u128_subo, + }; + + // Integer addition and subtraction is very simple, so 100 fuzzing passes should be plenty. + sum!( + u128, __rust_u128_add, __rust_u128_sub; + i128, __rust_i128_add, __rust_i128_sub; + ); + overflowing_sum!( + u128, __rust_u128_addo, __rust_u128_subo; + i128, __rust_i128_addo, __rust_i128_subo; + ); +} + +macro_rules! float_sum { + ($($f:ty, $fn_add:ident, $fn_sub:ident);*;) => { + $( + fuzz_float_2(N, |x: $f, y: $f| { + let add0 = x + y; + let sub0 = x - y; + let add1: $f = $fn_add(x, y); + let sub1: $f = $fn_sub(x, y); + if !Float::eq_repr(add0, add1) { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn_add), x, y, add0, add1 + ); + } + if !Float::eq_repr(sub0, sub1) { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn_sub), x, y, sub0, sub1 + ); + } + }); + )* + }; +} + +#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] +#[test] +fn float_addsub() { + use compiler_builtins::float::{ + add::{__adddf3, __addsf3}, + sub::{__subdf3, __subsf3}, + Float, + }; + + float_sum!( + f32, __addsf3, __subsf3; + f64, __adddf3, __subdf3; + ); +} diff --git a/library/compiler-builtins/testcrate/tests/cmp.rs b/library/compiler-builtins/testcrate/tests/cmp.rs new file mode 100644 index 0000000000000..d359b65d7e431 --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/cmp.rs @@ -0,0 +1,52 @@ +use testcrate::*; + +macro_rules! cmp { + ($x:ident, $y:ident, $($unordered_val:expr, $fn:ident);*;) => { + $( + let cmp0 = if $x.is_nan() || $y.is_nan() { + $unordered_val + } else if $x < $y { + -1 + } else if $x == $y { + 0 + } else { + 1 + }; + let cmp1 = $fn($x, $y); + if cmp0 != cmp1 { + panic!("{}({}, {}): std: {}, builtins: {}", stringify!($fn_builtins), $x, $y, cmp0, cmp1); + } + )* + }; +} + +#[test] +fn float_comparisons() { + use compiler_builtins::float::cmp::{ + __eqdf2, __eqsf2, __gedf2, __gesf2, __gtdf2, __gtsf2, __ledf2, __lesf2, __ltdf2, __ltsf2, + __nedf2, __nesf2, __unorddf2, __unordsf2, + }; + + fuzz_float_2(N, |x: f32, y: f32| { + assert_eq!(__unordsf2(x, y) != 0, x.is_nan() || y.is_nan()); + cmp!(x, y, + 1, __ltsf2; + 1, __lesf2; + 1, __eqsf2; + -1, __gesf2; + -1, __gtsf2; + 1, __nesf2; + ); + }); + fuzz_float_2(N, |x: f64, y: f64| { + assert_eq!(__unorddf2(x, y) != 0, x.is_nan() || y.is_nan()); + cmp!(x, y, + 1, __ltdf2; + 1, __ledf2; + 1, __eqdf2; + -1, __gedf2; + -1, __gtdf2; + 1, __nedf2; + ); + }); +} diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs new file mode 100644 index 0000000000000..7cdbf9fbb69e0 --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -0,0 +1,125 @@ +use testcrate::*; + +macro_rules! i_to_f { + ($($from:ty, $into:ty, $fn:ident);*;) => { + $( + fuzz(N, |x: $from| { + let f0 = x as $into; + let f1: $into = $fn(x); + // This makes sure that the conversion produced the best rounding possible, and does + // this independent of `x as $into` rounding correctly. + // This assumes that float to integer conversion is correct. + let y_minus_ulp = <$into>::from_bits(f1.to_bits().wrapping_sub(1)) as $from; + let y = f1 as $from; + let y_plus_ulp = <$into>::from_bits(f1.to_bits().wrapping_add(1)) as $from; + let error_minus = <$from as Int>::abs_diff(y_minus_ulp, x); + let error = <$from as Int>::abs_diff(y, x); + let error_plus = <$from as Int>::abs_diff(y_plus_ulp, x); + // The first two conditions check that none of the two closest float values are + // strictly closer in representation to `x`. The second makes sure that rounding is + // towards even significand if two float values are equally close to the integer. + if error_minus < error + || error_plus < error + || ((error_minus == error || error_plus == error) + && ((f0.to_bits() & 1) != 0)) + { + panic!( + "incorrect rounding by {}({}): {}, ({}, {}, {}), errors ({}, {}, {})", + stringify!($fn), + x, + f1.to_bits(), + y_minus_ulp, + y, + y_plus_ulp, + error_minus, + error, + error_plus, + ); + } + // Test against native conversion. We disable testing on all `x86` because of + // rounding bugs with `i686`. `powerpc` also has the same rounding bug. + if f0 != f1 && !cfg!(any( + target_arch = "x86", + target_arch = "powerpc", + target_arch = "powerpc64" + )) { + panic!( + "{}({}): std: {}, builtins: {}", + stringify!($fn), + x, + f0, + f1, + ); + } + }); + )* + }; +} + +#[test] +fn int_to_float() { + use compiler_builtins::float::conv::{ + __floatdidf, __floatdisf, __floatsidf, __floatsisf, __floattidf, __floattisf, + __floatundidf, __floatundisf, __floatunsidf, __floatunsisf, __floatuntidf, __floatuntisf, + }; + use compiler_builtins::int::Int; + + i_to_f!( + u32, f32, __floatunsisf; + u32, f64, __floatunsidf; + i32, f32, __floatsisf; + i32, f64, __floatsidf; + u64, f32, __floatundisf; + u64, f64, __floatundidf; + i64, f32, __floatdisf; + i64, f64, __floatdidf; + u128, f32, __floatuntisf; + u128, f64, __floatuntidf; + i128, f32, __floattisf; + i128, f64, __floattidf; + ); +} + +macro_rules! f_to_i { + ($x:ident, $($f:ty, $fn:ident);*;) => { + $( + // it is undefined behavior in the first place to do conversions with NaNs + if !$x.is_nan() { + let conv0 = $x as $f; + let conv1: $f = $fn($x); + if conv0 != conv1 { + panic!("{}({}): std: {}, builtins: {}", stringify!($fn), $x, conv0, conv1); + } + } + )* + }; +} + +#[test] +fn float_to_int() { + use compiler_builtins::float::conv::{ + __fixdfdi, __fixdfsi, __fixdfti, __fixsfdi, __fixsfsi, __fixsfti, __fixunsdfdi, + __fixunsdfsi, __fixunsdfti, __fixunssfdi, __fixunssfsi, __fixunssfti, + }; + + fuzz_float(N, |x: f32| { + f_to_i!(x, + u32, __fixunssfsi; + u64, __fixunssfdi; + u128, __fixunssfti; + i32, __fixsfsi; + i64, __fixsfdi; + i128, __fixsfti; + ); + }); + fuzz_float(N, |x: f64| { + f_to_i!(x, + u32, __fixunsdfsi; + u64, __fixunsdfdi; + u128, __fixunsdfti; + i32, __fixdfsi; + i64, __fixdfdi; + i128, __fixdfti; + ); + }); +} diff --git a/library/compiler-builtins/testcrate/tests/div_rem.rs b/library/compiler-builtins/testcrate/tests/div_rem.rs index 199fa9db71c20..0007c15aee5ea 100644 --- a/library/compiler-builtins/testcrate/tests/div_rem.rs +++ b/library/compiler-builtins/testcrate/tests/div_rem.rs @@ -1,8 +1,9 @@ -use rand_xoshiro::rand_core::{RngCore, SeedableRng}; -use rand_xoshiro::Xoshiro128StarStar; - use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divmodti4}; -use compiler_builtins::int::udiv::{__udivmoddi4, __udivmodsi4, __udivmodti4}; +use compiler_builtins::int::udiv::{__udivmoddi4, __udivmodsi4, __udivmodti4, u128_divide_sparc}; +use testcrate::*; + +// Division algorithms have by far the nastiest and largest number of edge cases, and experience shows +// that sometimes 100_000 iterations of the random fuzzer is needed. /// Creates intensive test functions for division functions of a certain size macro_rules! test { @@ -16,14 +17,17 @@ macro_rules! test { ) => { #[test] fn $test_name() { - fn assert_invariants(lhs: $uX, rhs: $uX) { - let rem: &mut $uX = &mut 0; - let quo: $uX = $unsigned_name(lhs, rhs, Some(rem)); - let rem = *rem; + fuzz_2(N, |lhs, rhs| { + if rhs == 0 { + return; + } + + let mut rem: $uX = 0; + let quo: $uX = $unsigned_name(lhs, rhs, Some(&mut rem)); if rhs <= rem || (lhs != rhs.wrapping_mul(quo).wrapping_add(rem)) { panic!( "unsigned division function failed with lhs:{} rhs:{} \ - expected:({}, {}) found:({}, {})", + std:({}, {}) builtins:({}, {})", lhs, rhs, lhs.wrapping_div(rhs), @@ -55,7 +59,7 @@ macro_rules! test { if incorrect_rem || lhs != rhs.wrapping_mul(quo).wrapping_add(rem) { panic!( "signed division function failed with lhs:{} rhs:{} \ - expected:({}, {}) found:({}, {})", + std:({}, {}) builtins:({}, {})", lhs, rhs, lhs.wrapping_div(rhs), @@ -64,70 +68,7 @@ macro_rules! test { rem ); } - } - - // Specially designed random fuzzer - let mut rng = Xoshiro128StarStar::seed_from_u64(0); - let mut lhs: $uX = 0; - let mut rhs: $uX = 0; - // all ones constant - let ones: $uX = !0; - // Alternating ones and zeros (e.x. 0b1010101010101010). This catches second-order - // problems that might occur for algorithms with two modes of operation (potentially - // there is some invariant that can be broken for large `duo` and maintained via - // alternating between modes, breaking the algorithm when it reaches the end). - let mut alt_ones: $uX = 1; - for _ in 0..($n / 2) { - alt_ones <<= 2; - alt_ones |= 1; - } - // creates a mask for indexing the bits of the type - let bit_indexing_mask = $n - 1; - for _ in 0..1_000_000 { - // Randomly OR, AND, and XOR randomly sized and shifted continuous strings of - // ones with `lhs` and `rhs`. This results in excellent fuzzing entropy such as: - // lhs:10101010111101000000000100101010 rhs: 1010101010000000000000001000001 - // lhs:10101010111101000000000101001010 rhs: 1010101010101010101010100010100 - // lhs:10101010111101000000000101001010 rhs:11101010110101010101010100001110 - // lhs:10101010000000000000000001001010 rhs:10100010100000000000000000001010 - // lhs:10101010000000000000000001001010 rhs: 10101010101010101000 - // lhs:10101010000000000000000001100000 rhs:11111111111101010101010101001111 - // lhs:10101010000000101010101011000000 rhs:11111111111101010101010100000111 - // lhs:10101010101010101010101011101010 rhs: 1010100000000000000 - // lhs:11111111110101101010101011010111 rhs: 1010100000000000000 - // The msb is set half of the time by the fuzzer, but `assert_invariants` tests - // both the signed and unsigned functions. - let r0: u32 = bit_indexing_mask & rng.next_u32(); - let r1: u32 = bit_indexing_mask & rng.next_u32(); - let mask = ones.wrapping_shr(r0).rotate_left(r1); - match rng.next_u32() % 8 { - 0 => lhs |= mask, - 1 => lhs &= mask, - // both 2 and 3 to make XORs as common as ORs and ANDs combined, otherwise - // the entropy gets destroyed too often - 2 | 3 => lhs ^= mask, - 4 => rhs |= mask, - 5 => rhs &= mask, - _ => rhs ^= mask, - } - // do the same for alternating ones and zeros - let r0: u32 = bit_indexing_mask & rng.next_u32(); - let r1: u32 = bit_indexing_mask & rng.next_u32(); - let mask = alt_ones.wrapping_shr(r0).rotate_left(r1); - match rng.next_u32() % 8 { - 0 => lhs |= mask, - 1 => lhs &= mask, - // both 2 and 3 to make XORs as common as ORs and ANDs combined, otherwise - // the entropy gets destroyed too often - 2 | 3 => lhs ^= mask, - 4 => rhs |= mask, - 5 => rhs &= mask, - _ => rhs ^= mask, - } - if rhs != 0 { - assert_invariants(lhs, rhs); - } - } + }); } }; } @@ -135,3 +76,61 @@ macro_rules! test { test!(32, u32, i32, div_rem_si4, __udivmodsi4, __divmodsi4); test!(64, u64, i64, div_rem_di4, __udivmoddi4, __divmoddi4); test!(128, u128, i128, div_rem_ti4, __udivmodti4, __divmodti4); + +#[test] +fn divide_sparc() { + fuzz_2(N, |lhs, rhs| { + if rhs == 0 { + return; + } + + let mut rem: u128 = 0; + let quo: u128 = u128_divide_sparc(lhs, rhs, &mut rem); + if rhs <= rem || (lhs != rhs.wrapping_mul(quo).wrapping_add(rem)) { + panic!( + "u128_divide_sparc({}, {}): \ + std:({}, {}), builtins:({}, {})", + lhs, + rhs, + lhs.wrapping_div(rhs), + lhs.wrapping_rem(rhs), + quo, + rem + ); + } + }); +} + +macro_rules! float { + ($($i:ty, $fn:ident);*;) => { + $( + fuzz_float_2(N, |x: $i, y: $i| { + let quo0 = x / y; + let quo1: $i = $fn(x, y); + // division of subnormals is not currently handled + if !(Float::is_subnormal(&quo0) || Float::is_subnormal(&quo1)) { + if !Float::eq_repr(quo0, quo1) { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn), x, y, quo0, quo1 + ); + } + } + }); + )* + }; +} + +#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] +#[test] +fn float_div() { + use compiler_builtins::float::{ + div::{__divdf3, __divsf3}, + Float, + }; + + float!( + f32, __divsf3; + f64, __divdf3; + ); +} diff --git a/library/compiler-builtins/testcrate/tests/leading_zeros.rs b/library/compiler-builtins/testcrate/tests/leading_zeros.rs deleted file mode 100644 index b857d9e0c31b1..0000000000000 --- a/library/compiler-builtins/testcrate/tests/leading_zeros.rs +++ /dev/null @@ -1,54 +0,0 @@ -use rand_xoshiro::rand_core::{RngCore, SeedableRng}; -use rand_xoshiro::Xoshiro128StarStar; - -use compiler_builtins::int::__clzsi2; -use compiler_builtins::int::leading_zeros::{ - usize_leading_zeros_default, usize_leading_zeros_riscv, -}; - -#[test] -fn __clzsi2_test() { - // Binary fuzzer. We cannot just send a random number directly to `__clzsi2()`, because we need - // large sequences of zeros to test. This XORs, ANDs, and ORs random length strings of 1s to - // `x`. ORs insure sequences of ones, ANDs insures sequences of zeros, and XORs are not often - // destructive but add entropy. - let mut rng = Xoshiro128StarStar::seed_from_u64(0); - let mut x = 0usize; - // creates a mask for indexing the bits of the type - let bit_indexing_mask = usize::MAX.count_ones() - 1; - // 10000 iterations is enough to make sure edge cases like single set bits are tested and to go - // through many paths. - for _ in 0..10_000 { - let r0 = bit_indexing_mask & rng.next_u32(); - // random length of ones - let ones: usize = !0 >> r0; - let r1 = bit_indexing_mask & rng.next_u32(); - // random circular shift - let mask = ones.rotate_left(r1); - match rng.next_u32() % 4 { - 0 => x |= mask, - 1 => x &= mask, - // both 2 and 3 to make XORs as common as ORs and ANDs combined - _ => x ^= mask, - } - let lz = x.leading_zeros() as usize; - let lz0 = __clzsi2(x); - let lz1 = usize_leading_zeros_default(x); - let lz2 = usize_leading_zeros_riscv(x); - if lz0 != lz { - panic!("__clzsi2({}): expected: {}, found: {}", x, lz, lz0); - } - if lz1 != lz { - panic!( - "usize_leading_zeros_default({}): expected: {}, found: {}", - x, lz, lz1 - ); - } - if lz2 != lz { - panic!( - "usize_leading_zeros_riscv({}): expected: {}, found: {}", - x, lz, lz2 - ); - } - } -} diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs new file mode 100644 index 0000000000000..d31e3e6b6a7cc --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -0,0 +1,134 @@ +use testcrate::*; + +/// Make sure that the the edge case tester and randomized tester don't break, and list examples of +/// fuzz values for documentation purposes. +#[test] +fn fuzz_values() { + const VALS: [u16; 47] = [ + 0b0, // edge cases + 0b1111111111111111, + 0b1111111111111110, + 0b1111111111111100, + 0b1111111110000000, + 0b1111111100000000, + 0b1110000000000000, + 0b1100000000000000, + 0b1000000000000000, + 0b111111111111111, + 0b111111111111110, + 0b111111111111100, + 0b111111110000000, + 0b111111100000000, + 0b110000000000000, + 0b100000000000000, + 0b11111111111111, + 0b11111111111110, + 0b11111111111100, + 0b11111110000000, + 0b11111100000000, + 0b10000000000000, + 0b111111111, + 0b111111110, + 0b111111100, + 0b110000000, + 0b100000000, + 0b11111111, + 0b11111110, + 0b11111100, + 0b10000000, + 0b111, + 0b110, + 0b100, + 0b11, + 0b10, + 0b1, + 0b1010110100000, // beginning of random fuzzing + 0b1100011001011010, + 0b1001100101001111, + 0b1101010100011010, + 0b100010001, + 0b1000000000000000, + 0b1100000000000101, + 0b1100111101010101, + 0b1100010111111111, + 0b1111110101111111, + ]; + let mut i = 0; + fuzz(10, |x: u16| { + assert_eq!(x, VALS[i]); + i += 1; + }); +} + +#[test] +fn leading_zeros() { + use compiler_builtins::int::__clzsi2; + use compiler_builtins::int::leading_zeros::{ + usize_leading_zeros_default, usize_leading_zeros_riscv, + }; + fuzz(N, |x: usize| { + let lz = x.leading_zeros() as usize; + let lz0 = __clzsi2(x); + let lz1 = usize_leading_zeros_default(x); + let lz2 = usize_leading_zeros_riscv(x); + if lz0 != lz { + panic!("__clzsi2({}): std: {}, builtins: {}", x, lz, lz0); + } + if lz1 != lz { + panic!( + "usize_leading_zeros_default({}): std: {}, builtins: {}", + x, lz, lz1 + ); + } + if lz2 != lz { + panic!( + "usize_leading_zeros_riscv({}): std: {}, builtins: {}", + x, lz, lz2 + ); + } + }) +} + +#[test] +fn float_extend() { + fuzz_float(N, |x: f32| { + let tmp0 = x as f64; + let tmp1: f64 = compiler_builtins::float::extend::__extendsfdf2(x); + if !compiler_builtins::float::Float::eq_repr(tmp0, tmp1) { + panic!("__extendsfdf2({}): std: {}, builtins: {}", x, tmp0, tmp1); + } + }); +} + +// This doesn't quite work because of issues related to +// https://github.com/rust-lang/rust/issues/73920. +// TODO how do we resolve this? +/* +macro_rules! pow { + ($($f:ty, $fn:ident);*;) => { + $( + fuzz_float_2(N, |x: $f, y: $f| { + let n = y as i32; + let tmp0: $f = x.powi(n); + let tmp1: $f = $fn(x, n); + if tmp0 != tmp1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn), x, y, tmp0, tmp1 + ); + } + }); + )* + }; +} + +#[test] +fn float_pow() { + use compiler_builtins::float::pow::{__powidf2, __powisf2}; + + pow!( + f32, __powisf2; + f64, __powidf2; + ); +} +*/ diff --git a/library/compiler-builtins/testcrate/tests/mul.rs b/library/compiler-builtins/testcrate/tests/mul.rs new file mode 100644 index 0000000000000..8b97ea46c3594 --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/mul.rs @@ -0,0 +1,114 @@ +use testcrate::*; + +macro_rules! mul { + ($($i:ty, $fn:ident);*;) => { + $( + fuzz_2(N, |x: $i, y: $i| { + let mul0 = x.wrapping_mul(y); + let mul1: $i = $fn(x, y); + if mul0 != mul1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn), x, y, mul0, mul1 + ); + } + }); + )* + }; +} + +#[test] +fn mul() { + use compiler_builtins::int::mul::{__muldi3, __multi3}; + + mul!( + u64, __muldi3; + i128, __multi3; + ); +} + +macro_rules! overflowing_mul { + ($($i:ty, $fn:ident);*;) => { + $( + fuzz_2(N, |x: $i, y: $i| { + let (mul0, o0) = x.overflowing_mul(y); + let mut o1 = 0i32; + let mul1: $i = $fn(x, y, &mut o1); + let o1 = o1 != 0; + if mul0 != mul1 || o0 != o1 { + panic!( + "{}({}, {}): std: ({}, {}), builtins: ({}, {})", + stringify!($fn), x, y, mul0, o0, mul1, o1 + ); + } + }); + )* + }; +} + +#[test] +fn overflowing_mul() { + use compiler_builtins::int::mul::{ + __mulodi4, __mulosi4, __muloti4, __rust_i128_mulo, __rust_u128_mulo, + }; + + overflowing_mul!( + i32, __mulosi4; + i64, __mulodi4; + i128, __muloti4; + ); + fuzz_2(N, |x: u128, y: u128| { + let (mul0, o0) = x.overflowing_mul(y); + let (mul1, o1) = __rust_u128_mulo(x, y); + if mul0 != mul1 || o0 != o1 { + panic!( + "__rust_u128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})", + x, y, mul0, o0, mul1, o1 + ); + } + let x = x as i128; + let y = y as i128; + let (mul0, o0) = x.overflowing_mul(y); + let (mul1, o1) = __rust_i128_mulo(x, y); + if mul0 != mul1 || o0 != o1 { + panic!( + "__rust_i128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})", + x, y, mul0, o0, mul1, o1 + ); + } + }); +} + +macro_rules! float_mul { + ($($f:ty, $fn:ident);*;) => { + $( + fuzz_float_2(N, |x: $f, y: $f| { + let mul0 = x * y; + let mul1: $f = $fn(x, y); + // multiplication of subnormals is not currently handled + if !(Float::is_subnormal(&mul0) || Float::is_subnormal(&mul1)) { + if !Float::eq_repr(mul0, mul1) { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn), x, y, mul0, mul1 + ); + } + } + }); + )* + }; +} + +#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] +#[test] +fn float_mul() { + use compiler_builtins::float::{ + mul::{__muldf3, __mulsf3}, + Float, + }; + + float_mul!( + f32, __mulsf3; + f64, __muldf3; + ); +} diff --git a/library/compiler-builtins/testcrate/tests/shift.rs b/library/compiler-builtins/testcrate/tests/shift.rs new file mode 100644 index 0000000000000..ecb13a133e172 --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/shift.rs @@ -0,0 +1,60 @@ +use testcrate::*; + +macro_rules! shift { + ($($i:ty, $fn_std:ident, $fn_builtins:ident);*;) => { + $( + fuzz_shift(|x: $i, s: u32| { + let tmp0: $i = x.$fn_std(s); + let tmp1: $i = $fn_builtins(x, s); + if tmp0 != tmp1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn_builtins), x, s, tmp0, tmp1 + ); + } + }); + )* + }; +} + +macro_rules! overflowing_shift { + ($($i:ty, $fn_std:ident, $fn_builtins:ident);*;) => { + $( + fuzz_shift(|x: $i, s: u32| { + let tmp0: $i = x.$fn_std(s); + let (tmp1, o1): ($i, bool) = $fn_builtins(x, s.into()); + if tmp0 != tmp1 || o1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn_builtins), x, s, tmp0, tmp1 + ); + } + }); + )* + }; +} + +#[test] +fn shift() { + use compiler_builtins::int::shift::{ + __ashldi3, __ashlsi3, __ashlti3, __ashrdi3, __ashrsi3, __ashrti3, __lshrdi3, __lshrsi3, + __lshrti3, __rust_i128_shlo, __rust_i128_shro, __rust_u128_shlo, __rust_u128_shro, + }; + shift!( + u32, wrapping_shl, __ashlsi3; + u64, wrapping_shl, __ashldi3; + u128, wrapping_shl, __ashlti3; + i32, wrapping_shr, __ashrsi3; + i64, wrapping_shr, __ashrdi3; + i128, wrapping_shr, __ashrti3; + u32, wrapping_shr, __lshrsi3; + u64, wrapping_shr, __lshrdi3; + u128, wrapping_shr, __lshrti3; + ); + overflowing_shift!( + u128, wrapping_shl, __rust_u128_shlo; + i128, wrapping_shl, __rust_i128_shlo; + u128, wrapping_shr, __rust_u128_shro; + i128, wrapping_shr, __rust_i128_shro; + ); +} From 176ae46ff852517fcf3670053db26ad67b309d62 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 9 Dec 2020 12:17:29 +0000 Subject: [PATCH 0893/4206] Bump to 0.1.37 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 0c5fd15315e4c..c9ac6d0a761af 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.36" +version = "0.1.37" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 7645c0b869292a07e287cc6862971016f72ed34b Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Fri, 11 Dec 2020 21:56:10 +0900 Subject: [PATCH 0894/4206] Use the AT&T syntax to support old LLVM on rust-lang/rust --- .../src/int/specialized_div_rem/mod.rs | 6 ++- library/compiler-builtins/src/mem/x86_64.rs | 41 +++++++++++-------- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index eaeb030e389d1..14e758fc5a8ff 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -169,12 +169,13 @@ unsafe fn u128_by_u64_div_rem(duo: u128, div: u64) -> (u64, u64) { unsafe { // divides the combined registers rdx:rax (`duo` is split into two 64 bit parts to do this) // by `div`. The quotient is stored in rax and the remainder in rdx. + // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. asm!( "div {0}", in(reg) div, inlateout("rax") duo_lo => quo, inlateout("rdx") duo_hi => rem, - options(pure, nomem, nostack) + options(att_syntax, pure, nomem, nostack) ); } (quo, rem) @@ -255,12 +256,13 @@ unsafe fn u64_by_u32_div_rem(duo: u64, div: u32) -> (u32, u32) { unsafe { // divides the combined registers rdx:rax (`duo` is split into two 32 bit parts to do this) // by `div`. The quotient is stored in rax and the remainder in rdx. + // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. asm!( "div {0}", in(reg) div, inlateout("rax") duo_lo => quo, inlateout("rdx") duo_hi => rem, - options(pure, nomem, nostack) + options(att_syntax, pure, nomem, nostack) ); } (quo, rem) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 8cbbdf779a6a0..abdb8eb67e002 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -19,12 +19,13 @@ #[inline(always)] #[cfg(target_feature = "ermsb")] pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { + // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. asm!( - "rep movsb [rdi], [rsi]", + "repe movsb (%rsi), (%rdi)", inout("rcx") count => _, inout("rdi") dest => _, inout("rsi") src => _, - options(nostack, preserves_flags) + options(att_syntax, nostack, preserves_flags) ); } @@ -33,15 +34,16 @@ pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { let qword_count = count >> 3; let byte_count = count & 0b111; + // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. asm!( - "rep movsq [rdi], [rsi]", - "mov ecx, {byte_count:e}", - "rep movsb [rdi], [rsi]", + "repe movsq (%rsi), (%rdi)", + "mov {byte_count:e}, %ecx", + "repe movsb (%rsi), (%rdi)", byte_count = in(reg) byte_count, inout("rcx") qword_count => _, inout("rdi") dest => _, inout("rsi") src => _, - options(nostack, preserves_flags) + options(att_syntax, nostack, preserves_flags) ); } @@ -49,31 +51,33 @@ pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { let qword_count = count >> 3; let byte_count = count & 0b111; + // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. asm!( "std", - "rep movsq [rdi], [rsi]", - "mov ecx, {byte_count:e}", - "add rdi, 7", - "add rsi, 7", - "rep movsb [rdi], [rsi]", + "repe movsq (%rsi), (%rdi)", + "movl {byte_count:e}, %ecx", + "addq $7, %rdi", + "addq $7, %rsi", + "repe movsb (%rsi), (%rdi)", "cld", byte_count = in(reg) byte_count, inout("rcx") qword_count => _, inout("rdi") dest.add(count).wrapping_sub(8) => _, inout("rsi") src.add(count).wrapping_sub(8) => _, - options(nostack) + options(att_syntax, nostack) ); } #[inline(always)] #[cfg(target_feature = "ermsb")] pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { + // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. asm!( - "rep stosb [rdi], al", + "repe stosb %al, (%rdi)", inout("rcx") count => _, inout("rdi") dest => _, inout("al") c => _, - options(nostack, preserves_flags) + options(att_syntax, nostack, preserves_flags) ) } @@ -82,14 +86,15 @@ pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { let qword_count = count >> 3; let byte_count = count & 0b111; + // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. asm!( - "rep stosq [rdi], rax", - "mov ecx, {byte_count:e}", - "rep stosb [rdi], al", + "repe stosq %rax, (%rdi)", + "mov {byte_count:e}, %ecx", + "repe stosb %al, (%rdi)", byte_count = in(reg) byte_count, inout("rcx") qword_count => _, inout("rdi") dest => _, in("rax") (c as u64) * 0x0101010101010101, - options(nostack, preserves_flags) + options(att_syntax, nostack, preserves_flags) ); } From f0a9f9e3e1905b220d086fdb6453ecade95c50c2 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 12 Dec 2020 12:11:21 +0000 Subject: [PATCH 0895/4206] Bump to 0.1.38 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index c9ac6d0a761af..901b33c3f7fcf 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.37" +version = "0.1.38" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From e5b667554e81efe2129f412a6eea5d8739c5f990 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Mon, 4 Jan 2021 09:17:44 -0600 Subject: [PATCH 0896/4206] Remove `count_ones` (#399) --- library/compiler-builtins/src/int/mod.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index cb94803a47035..06054c84af6d3 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -90,7 +90,6 @@ pub trait Int: fn aborting_div(self, other: Self) -> Self; fn aborting_rem(self, other: Self) -> Self; fn leading_zeros(self) -> u32; - fn count_ones(self) -> u32; } fn unwrap(t: Option) -> T { @@ -229,10 +228,6 @@ macro_rules! int_impl_common { fn leading_zeros(self) -> u32 { ::leading_zeros(self) } - - fn count_ones(self) -> u32 { - ::count_ones(self) - } }; } From 80fb6752fad5ea4963b0cd5630e1767971e8f765 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 6 Jan 2021 23:39:48 +0000 Subject: [PATCH 0897/4206] Bump to 0.1.39 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 901b33c3f7fcf..f1052d59d6784 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.38" +version = "0.1.39" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 57205c0b8654a121a07c70e63abfd5cf761f5eaa Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 5 Feb 2021 23:40:17 +0100 Subject: [PATCH 0898/4206] Use the newly stabilized BITS constant on the integer types --- library/compiler-builtins/src/int/mod.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 06054c84af6d3..e50b2e608383d 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -100,8 +100,8 @@ fn unwrap(t: Option) -> T { } macro_rules! int_impl_common { - ($ty:ty, $bits:expr) => { - const BITS: u32 = $bits; + ($ty:ty) => { + const BITS: u32 = ::BITS; const ZERO: Self = 0; const ONE: Self = 1; @@ -232,7 +232,7 @@ macro_rules! int_impl_common { } macro_rules! int_impl { - ($ity:ty, $uty:ty, $bits:expr) => { + ($ity:ty, $uty:ty) => { impl Int for $uty { type OtherSign = $ity; type UnsignedInt = $uty; @@ -253,7 +253,7 @@ macro_rules! int_impl { (self.wrapping_sub(other) as $ity).wrapping_abs() as $uty } - int_impl_common!($uty, $bits); + int_impl_common!($uty); } impl Int for $ity { @@ -280,17 +280,17 @@ macro_rules! int_impl { self.wrapping_sub(other).wrapping_abs() as $uty } - int_impl_common!($ity, $bits); + int_impl_common!($ity); } }; } -int_impl!(isize, usize, usize::MAX.count_ones()); -int_impl!(i8, u8, 8); -int_impl!(i16, u16, 16); -int_impl!(i32, u32, 32); -int_impl!(i64, u64, 64); -int_impl!(i128, u128, 128); +int_impl!(isize, usize); +int_impl!(i8, u8); +int_impl!(i16, u16); +int_impl!(i32, u32); +int_impl!(i64, u64); +int_impl!(i128, u128); /// 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. From c75621f12c8844a353226914b94259db2cf23c44 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 21 Feb 2021 11:36:47 +0100 Subject: [PATCH 0899/4206] Remove unused __rust_* shift intrinsics They are rust specific and used by neither cg_llvm nor cg_clif --- library/compiler-builtins/src/int/shift.rs | 16 ------------ .../testcrate/tests/shift.rs | 25 +------------------ 2 files changed, 1 insertion(+), 40 deletions(-) diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 20561786b2f05..59909929e58c2 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -113,20 +113,4 @@ intrinsics! { pub extern "C" fn __lshrti3(a: u128, b: u32) -> u128 { a.lshr(b) } - - pub extern "C" fn __rust_i128_shlo(a: i128, b: u128) -> (i128, bool) { - (__ashlti3(a as _, b as _) as _, b >= 128) - } - - pub extern "C" fn __rust_u128_shlo(a: u128, b: u128) -> (u128, bool) { - (__ashlti3(a, b as _), b >= 128) - } - - pub extern "C" fn __rust_i128_shro(a: i128, b: u128) -> (i128, bool) { - (__ashrti3(a, b as _), b >= 128) - } - - pub extern "C" fn __rust_u128_shro(a: u128, b: u128) -> (u128, bool) { - (__lshrti3(a, b as _), b >= 128) - } } diff --git a/library/compiler-builtins/testcrate/tests/shift.rs b/library/compiler-builtins/testcrate/tests/shift.rs index ecb13a133e172..7a76b164685bf 100644 --- a/library/compiler-builtins/testcrate/tests/shift.rs +++ b/library/compiler-builtins/testcrate/tests/shift.rs @@ -17,28 +17,11 @@ macro_rules! shift { }; } -macro_rules! overflowing_shift { - ($($i:ty, $fn_std:ident, $fn_builtins:ident);*;) => { - $( - fuzz_shift(|x: $i, s: u32| { - let tmp0: $i = x.$fn_std(s); - let (tmp1, o1): ($i, bool) = $fn_builtins(x, s.into()); - if tmp0 != tmp1 || o1 { - panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn_builtins), x, s, tmp0, tmp1 - ); - } - }); - )* - }; -} - #[test] fn shift() { use compiler_builtins::int::shift::{ __ashldi3, __ashlsi3, __ashlti3, __ashrdi3, __ashrsi3, __ashrti3, __lshrdi3, __lshrsi3, - __lshrti3, __rust_i128_shlo, __rust_i128_shro, __rust_u128_shlo, __rust_u128_shro, + __lshrti3, }; shift!( u32, wrapping_shl, __ashlsi3; @@ -51,10 +34,4 @@ fn shift() { u64, wrapping_shr, __lshrdi3; u128, wrapping_shr, __lshrti3; ); - overflowing_shift!( - u128, wrapping_shl, __rust_u128_shlo; - i128, wrapping_shl, __rust_i128_shlo; - u128, wrapping_shr, __rust_u128_shro; - i128, wrapping_shr, __rust_i128_shro; - ); } From 9ba75196bda13e70473ceb12f998f7a324577279 Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Sun, 28 Mar 2021 12:24:08 +0200 Subject: [PATCH 0900/4206] add "readme"-key to Cargo.toml in order for this crate to have a preview on crates.io --- library/compiler-builtins/libm/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index d9d6680409e14..106de51dfb61e 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -6,6 +6,7 @@ documentation = "https://docs.rs/libm" keywords = ["libm", "math"] license = "MIT OR Apache-2.0" name = "libm" +readme = "README.md" repository = "https://github.com/rust-lang/libm" version = "0.2.1" edition = "2018" From 880ec8bb83fc367907942a36e0ccadda877e16cf Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 2 Apr 2021 12:36:57 +0100 Subject: [PATCH 0901/4206] Disable AArch64 FP-to-int tests This is a temporary workaround for https://github.com/rust-lang/rust/issues/83467 --- library/compiler-builtins/testcrate/tests/conv.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 7cdbf9fbb69e0..17c31a8a00e5b 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -95,6 +95,8 @@ macro_rules! f_to_i { }; } +// AArch64 tests are currently broken due to https://github.com/rust-lang/rust/issues/83467 +#[cfg(not(target_arch = "aarch64"))] #[test] fn float_to_int() { use compiler_builtins::float::conv::{ From 0ce47b3c1f200f59e5459eb50fb6c2715c3b2259 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Thu, 10 Dec 2020 17:00:45 -0600 Subject: [PATCH 0902/4206] fix abs_diff bug --- library/compiler-builtins/src/int/mod.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index e50b2e608383d..a186a95aa6668 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -250,7 +250,11 @@ macro_rules! int_impl { } fn abs_diff(self, other: Self) -> Self { - (self.wrapping_sub(other) as $ity).wrapping_abs() as $uty + if self < other { + other.wrapping_sub(self) + } else { + self.wrapping_sub(other) + } } int_impl_common!($uty); From ec4fc5dab5718fa0ef048d9aec88784e4d2fe5fd Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Tue, 8 Dec 2020 19:28:05 -0600 Subject: [PATCH 0903/4206] refactor float conversion --- library/compiler-builtins/src/float/conv.rs | 299 +++++++++--------- library/compiler-builtins/src/float/mod.rs | 39 ++- library/compiler-builtins/src/float/pow.rs | 3 +- library/compiler-builtins/src/int/mod.rs | 70 +--- library/compiler-builtins/src/lib.rs | 5 - .../testcrate/tests/div_rem.rs | 2 +- .../compiler-builtins/testcrate/tests/mul.rs | 2 +- 7 files changed, 198 insertions(+), 222 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index e9ca0f138ca2e..8c46e4d2e7a28 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -1,90 +1,88 @@ use float::Float; -use int::Int; - -macro_rules! int_to_float { - ($i:expr, $ity:ty, $fty:ty) => {{ - let i = $i; - if i == 0 { - return 0.0; - } - - let mant_dig = <$fty>::SIGNIFICAND_BITS + 1; - let exponent_bias = <$fty>::EXPONENT_BIAS; - - let n = <$ity as Int>::BITS; - let (s, a) = i.extract_sign(); - let mut a = a; - - // number of significant digits - let sd = n - a.leading_zeros(); - - // exponent - let mut e = sd - 1; +use int::{CastInto, Int}; + +fn int_to_float(i: I) -> F +where + F::Int: CastInto, + F::Int: CastInto, + I::UnsignedInt: CastInto, + u32: CastInto, +{ + if i == I::ZERO { + return F::ZERO; + } - if <$ity as Int>::BITS < mant_dig { - return <$fty>::from_parts( - s, - (e + exponent_bias) as <$fty as Float>::Int, - (a as <$fty as Float>::Int) << (mant_dig - e - 1), - ); - } + let two = I::UnsignedInt::ONE + I::UnsignedInt::ONE; + let four = two + two; + let sign = i < I::ZERO; + let mut x = Int::abs_diff(i, I::ZERO); + + // number of significant digits in the integer + let i_sd = I::BITS - x.leading_zeros(); + // significant digits for the float, including implicit bit + let f_sd = F::SIGNIFICAND_BITS + 1; + + // exponent + let mut exp = i_sd - 1; + + if I::BITS < f_sd { + return F::from_parts( + sign, + (exp + F::EXPONENT_BIAS).cast(), + x.cast() << (f_sd - exp - 1), + ); + } - a = if sd > mant_dig { - /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx - * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR - * 12345678901234567890123456 - * 1 = msb 1 bit - * P = bit MANT_DIG-1 bits to the right of 1 - * Q = bit MANT_DIG bits to the right of 1 - * R = "or" of all bits to the right of Q - */ - let mant_dig_plus_one = mant_dig + 1; - let mant_dig_plus_two = mant_dig + 2; - a = if sd == mant_dig_plus_one { - a << 1 - } else if sd == mant_dig_plus_two { - a - } else { - (a >> (sd - mant_dig_plus_two)) as <$ity as Int>::UnsignedInt - | ((a & <$ity as Int>::UnsignedInt::max_value()) - .wrapping_shl((n + mant_dig_plus_two) - sd) - != 0) as <$ity as Int>::UnsignedInt - }; - - /* finish: */ - a |= ((a & 4) != 0) as <$ity as Int>::UnsignedInt; /* Or P into R */ - a += 1; /* round - this step may add a significant bit */ - a >>= 2; /* dump Q and R */ - - /* a is now rounded to mant_dig or mant_dig+1 bits */ - if (a & (1 << mant_dig)) != 0 { - a >>= 1; - e += 1; - } - a - /* a is now rounded to mant_dig bits */ + x = if i_sd > f_sd { + // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + // 12345678901234567890123456 + // 1 = the implicit bit + // P = bit f_sd-1 bits to the right of 1 + // Q = bit f_sd bits to the right of 1 + // R = "or" of all bits to the right of Q + let f_sd_add2 = f_sd + 2; + x = if i_sd == (f_sd + 1) { + x << 1 + } else if i_sd == f_sd_add2 { + x } else { - a.wrapping_shl(mant_dig - sd) - /* a is now rounded to mant_dig bits */ + (x >> (i_sd - f_sd_add2)) + | Int::from_bool( + (x & I::UnsignedInt::MAX).wrapping_shl((I::BITS + f_sd_add2) - i_sd) + != Int::ZERO, + ) }; - <$fty>::from_parts( - s, - (e + exponent_bias) as <$fty as Float>::Int, - a as <$fty as Float>::Int, - ) - }}; + // R |= P + x |= Int::from_bool((x & four) != I::UnsignedInt::ZERO); + // round - this step may add a significant bit + x += Int::ONE; + // dump Q and R + x >>= 2; + + // a is now rounded to f_sd or f_sd+1 bits + if (x & (I::UnsignedInt::ONE << f_sd)) != Int::ZERO { + x >>= 1; + exp += 1; + } + x + } else { + x.wrapping_shl(f_sd - i_sd) + }; + + F::from_parts(sign, (exp + F::EXPONENT_BIAS).cast(), x.cast()) } intrinsics! { #[arm_aeabi_alias = __aeabi_i2f] pub extern "C" fn __floatsisf(i: i32) -> f32 { - int_to_float!(i, i32, f32) + int_to_float(i) } #[arm_aeabi_alias = __aeabi_i2d] pub extern "C" fn __floatsidf(i: i32) -> f64 { - int_to_float!(i, i32, f64) + int_to_float(i) } #[maybe_use_optimized_c_shim] @@ -95,7 +93,7 @@ intrinsics! { if cfg!(target_arch = "x86_64") { i as f32 } else { - int_to_float!(i, i64, f32) + int_to_float(i) } } @@ -107,181 +105,172 @@ intrinsics! { if cfg!(target_arch = "x86_64") { i as f64 } else { - int_to_float!(i, i64, f64) + int_to_float(i) } } #[unadjusted_on_win64] pub extern "C" fn __floattisf(i: i128) -> f32 { - int_to_float!(i, i128, f32) + int_to_float(i) } #[unadjusted_on_win64] pub extern "C" fn __floattidf(i: i128) -> f64 { - int_to_float!(i, i128, f64) + int_to_float(i) } #[arm_aeabi_alias = __aeabi_ui2f] pub extern "C" fn __floatunsisf(i: u32) -> f32 { - int_to_float!(i, u32, f32) + int_to_float(i) } #[arm_aeabi_alias = __aeabi_ui2d] pub extern "C" fn __floatunsidf(i: u32) -> f64 { - int_to_float!(i, u32, f64) + int_to_float(i) } #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_ul2f] pub extern "C" fn __floatundisf(i: u64) -> f32 { - int_to_float!(i, u64, f32) + int_to_float(i) } #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_ul2d] pub extern "C" fn __floatundidf(i: u64) -> f64 { - int_to_float!(i, u64, f64) + int_to_float(i) } #[unadjusted_on_win64] pub extern "C" fn __floatuntisf(i: u128) -> f32 { - int_to_float!(i, u128, f32) + int_to_float(i) } #[unadjusted_on_win64] pub extern "C" fn __floatuntidf(i: u128) -> f64 { - int_to_float!(i, u128, f64) + int_to_float(i) } } -#[derive(PartialEq)] -enum Sign { - Positive, - Negative, -} +fn float_to_int(f: F) -> I +where + F::ExpInt: CastInto, + u32: CastInto, + F::Int: CastInto, +{ + // converting NaNs is UB, so we don't consider them + + let sign = f.sign(); + let mut exp = f.exp(); -macro_rules! float_to_int { - ($f:expr, $fty:ty, $ity:ty) => {{ - let f = $f; - let fixint_min = <$ity>::min_value(); - let fixint_max = <$ity>::max_value(); - let fixint_bits = <$ity as Int>::BITS as usize; - let fixint_unsigned = fixint_min == 0; - - let sign_bit = <$fty>::SIGN_MASK; - let significand_bits = <$fty>::SIGNIFICAND_BITS as usize; - let exponent_bias = <$fty>::EXPONENT_BIAS as usize; - //let exponent_max = <$fty>::exponent_max() as usize; - - // Break a into sign, exponent, significand - let a_rep = <$fty>::repr(f); - let a_abs = a_rep & !sign_bit; - - // this is used to work around -1 not being available for unsigned - let sign = if (a_rep & sign_bit) == 0 { - Sign::Positive + // if less than one or unsigned & negative + if (exp < F::EXPONENT_BIAS.cast()) || (!I::SIGNED && sign) { + return I::ZERO; + } + exp -= F::EXPONENT_BIAS.cast(); + + // If the value is too large for `I`, saturate. + let bits: F::ExpInt = I::BITS.cast(); + let max = if I::SIGNED { + bits - F::ExpInt::ONE + } else { + bits + }; + if max <= exp { + return if sign { + // It happens that I::MIN is handled correctly + I::MIN } else { - Sign::Negative + I::MAX }; - let mut exponent = (a_abs >> significand_bits) as usize; - let significand = (a_abs & <$fty>::SIGNIFICAND_MASK) | <$fty>::IMPLICIT_BIT; + }; - // if < 1 or unsigned & negative - if exponent < exponent_bias || fixint_unsigned && sign == Sign::Negative { - return 0; - } - exponent -= exponent_bias; - - // If the value is infinity, saturate. - // If the value is too large for the integer type, 0. - if exponent - >= (if fixint_unsigned { - fixint_bits - } else { - fixint_bits - 1 - }) - { - return if sign == Sign::Positive { - fixint_max - } else { - fixint_min - }; - } - // If 0 <= exponent < significand_bits, right shift to get the result. - // Otherwise, shift left. - // (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned - let r = if exponent < significand_bits { - (significand >> (significand_bits - exponent)) as $ity + // `0 <= exp < max` + + // If 0 <= exponent < F::SIGNIFICAND_BITS, right shift to get the result. Otherwise, shift left. + let sig_bits: F::ExpInt = F::SIGNIFICAND_BITS.cast(); + // The larger integer has to be casted into, or else the shift overflows + let r: I = if F::Int::BITS < I::BITS { + let tmp: I = if exp < sig_bits { + f.imp_frac().cast() >> (sig_bits - exp).cast() } else { - (significand as $ity) << (exponent - significand_bits) + f.imp_frac().cast() << (exp - sig_bits).cast() }; - - if sign == Sign::Negative { - (!r).wrapping_add(1) + tmp + } else { + let tmp: F::Int = if exp < sig_bits { + f.imp_frac() >> (sig_bits - exp).cast() } else { - r - } - }}; + f.imp_frac() << (exp - sig_bits).cast() + }; + tmp.cast() + }; + + if sign { + r.wrapping_neg() + } else { + r + } } intrinsics! { #[arm_aeabi_alias = __aeabi_f2iz] pub extern "C" fn __fixsfsi(f: f32) -> i32 { - float_to_int!(f, f32, i32) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_f2lz] pub extern "C" fn __fixsfdi(f: f32) -> i64 { - float_to_int!(f, f32, i64) + float_to_int(f) } #[unadjusted_on_win64] pub extern "C" fn __fixsfti(f: f32) -> i128 { - float_to_int!(f, f32, i128) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_d2iz] pub extern "C" fn __fixdfsi(f: f64) -> i32 { - float_to_int!(f, f64, i32) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_d2lz] pub extern "C" fn __fixdfdi(f: f64) -> i64 { - float_to_int!(f, f64, i64) + float_to_int(f) } #[unadjusted_on_win64] pub extern "C" fn __fixdfti(f: f64) -> i128 { - float_to_int!(f, f64, i128) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_f2uiz] pub extern "C" fn __fixunssfsi(f: f32) -> u32 { - float_to_int!(f, f32, u32) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_f2ulz] pub extern "C" fn __fixunssfdi(f: f32) -> u64 { - float_to_int!(f, f32, u64) + float_to_int(f) } #[unadjusted_on_win64] pub extern "C" fn __fixunssfti(f: f32) -> u128 { - float_to_int!(f, f32, u128) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_d2uiz] pub extern "C" fn __fixunsdfsi(f: f64) -> u32 { - float_to_int!(f, f64, u32) + float_to_int(f) } #[arm_aeabi_alias = __aeabi_d2ulz] pub extern "C" fn __fixunsdfdi(f: f64) -> u64 { - float_to_int!(f, f64, u64) + float_to_int(f) } #[unadjusted_on_win64] pub extern "C" fn __fixunsdfti(f: f64) -> u128 { - float_to_int!(f, f64, u128) + float_to_int(f) } } diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index c4b6901613fbd..5a0d37a7deb0c 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -30,6 +30,9 @@ pub trait Float: /// A int of the same with as the float type SignedInt: Int; + /// An int capable of containing the exponent bits plus a sign bit. This is signed. + type ExpInt: Int; + const ZERO: Self; const ONE: Self; @@ -71,6 +74,18 @@ pub trait Float: /// compared. fn eq_repr(self, rhs: Self) -> bool; + /// Returns the sign bit + fn sign(self) -> bool; + + /// Returns the exponent with 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_repr(a: Self::Int) -> Self; @@ -81,14 +96,16 @@ pub trait Float: fn normalize(significand: Self::Int) -> (i32, Self::Int); /// Returns if `self` is subnormal - fn is_subnormal(&self) -> bool; + fn is_subnormal(self) -> bool; } macro_rules! float_impl { - ($ty:ident, $ity:ident, $sity:ident, $bits:expr, $significand_bits:expr) => { + ($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; @@ -113,6 +130,18 @@ macro_rules! float_impl { self.repr() == rhs.repr() } } + fn sign(self) -> bool { + self.signed_repr() < Self::SignedInt::ZERO + } + fn exp(self) -> Self::ExpInt { + ((self.to_bits() & Self::EXPONENT_MASK) >> Self::SIGNIFICAND_BITS) as Self::ExpInt + } + fn frac(self) -> Self::Int { + self.to_bits() & Self::SIGNIFICAND_MASK + } + fn imp_frac(self) -> Self::Int { + self.frac() | Self::IMPLICIT_BIT + } fn from_repr(a: Self::Int) -> Self { Self::from_bits(a) } @@ -132,12 +161,12 @@ macro_rules! float_impl { significand << shift as Self::Int, ) } - fn is_subnormal(&self) -> bool { + fn is_subnormal(self) -> bool { (self.repr() & Self::EXPONENT_MASK) == Self::Int::ZERO } } }; } -float_impl!(f32, u32, i32, 32, 23); -float_impl!(f64, u64, i64, 64, 52); +float_impl!(f32, u32, i32, i16, 32, 23); +float_impl!(f64, u64, i64, i16, 64, 52); diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index 2eedf67584e67..7d7f75972c712 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -1,5 +1,4 @@ use float::Float; -use int::Int; trait Pow: Float { /// Returns `a` raised to the power `b` @@ -11,7 +10,7 @@ trait Pow: Float { if (b & 1) != 0 { r *= a; } - b = b.aborting_div(2); + b = ((b as u32) >> 1) as i32; if b == 0 { break; } diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index a186a95aa6668..d8524a58a5e8c 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -15,9 +15,11 @@ pub use self::leading_zeros::__clzsi2; #[doc(hidden)] pub trait Int: Copy + + core::fmt::Debug + PartialEq + PartialOrd + ops::AddAssign + + ops::SubAssign + ops::BitAndAssign + ops::BitOrAssign + ops::BitXorAssign @@ -38,12 +40,16 @@ pub trait Int: /// Unsigned version of Self type UnsignedInt: Int; + /// If `Self` is a signed integer + const SIGNED: bool; + /// The bitwidth of the int type const BITS: u32; const ZERO: Self; const ONE: Self; const MIN: Self; + const MAX: Self; /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, @@ -52,18 +58,6 @@ pub trait Int: /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. const FUZZ_NUM: usize; - /// Extracts the sign from self and returns a tuple. - /// - /// # Examples - /// - /// ```rust,ignore - /// let i = -25_i32; - /// let (sign, u) = i.extract_sign(); - /// assert_eq!(sign, true); - /// assert_eq!(u, 25_u32); - /// ``` - fn extract_sign(self) -> (bool, Self::UnsignedInt); - fn unsigned(self) -> Self::UnsignedInt; fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; @@ -77,8 +71,6 @@ pub trait Int: // copied from primitive integers, but put in a trait fn is_zero(self) -> bool; - fn max_value() -> Self; - fn min_value() -> Self; fn wrapping_neg(self) -> Self; fn wrapping_add(self, other: Self) -> Self; fn wrapping_mul(self, other: Self) -> Self; @@ -87,25 +79,18 @@ pub trait Int: fn wrapping_shr(self, other: u32) -> Self; fn rotate_left(self, other: u32) -> Self; fn overflowing_add(self, other: Self) -> (Self, bool); - fn aborting_div(self, other: Self) -> Self; - fn aborting_rem(self, other: Self) -> Self; fn leading_zeros(self) -> u32; } -fn unwrap(t: Option) -> T { - match t { - Some(t) => t, - None => ::abort(), - } -} - macro_rules! int_impl_common { ($ty:ty) => { const BITS: u32 = ::BITS; + const SIGNED: bool = Self::MIN != Self::ZERO; const ZERO: Self = 0; const ONE: Self = 1; const MIN: Self = ::MIN; + const MAX: Self = ::MAX; const FUZZ_LENGTHS: [u8; 20] = { let bits = ::BITS; @@ -177,14 +162,6 @@ macro_rules! int_impl_common { self == Self::ZERO } - fn max_value() -> Self { - ::max_value() - } - - fn min_value() -> Self { - ::min_value() - } - fn wrapping_neg(self) -> Self { ::wrapping_neg(self) } @@ -217,14 +194,6 @@ macro_rules! int_impl_common { ::overflowing_add(self, other) } - fn aborting_div(self, other: Self) -> Self { - unwrap(::checked_div(self, other)) - } - - fn aborting_rem(self, other: Self) -> Self { - unwrap(::checked_rem(self, other)) - } - fn leading_zeros(self) -> u32 { ::leading_zeros(self) } @@ -237,10 +206,6 @@ macro_rules! int_impl { type OtherSign = $ity; type UnsignedInt = $uty; - fn extract_sign(self) -> (bool, $uty) { - (false, self) - } - fn unsigned(self) -> $uty { self } @@ -264,14 +229,6 @@ macro_rules! int_impl { type OtherSign = $uty; type UnsignedInt = $uty; - fn extract_sign(self) -> (bool, $uty) { - if self < 0 { - (true, (!(self as $uty)).wrapping_add(1)) - } else { - (false, self as $uty) - } - } - fn unsigned(self) -> $uty { self as $uty } @@ -395,13 +352,14 @@ impl_h_int!( ); /// Trait to express (possibly lossy) casting of integers -pub(crate) trait CastInto: Copy { +#[doc(hidden)] +pub trait CastInto: Copy { fn cast(self) -> T; } macro_rules! cast_into { ($ty:ty) => { - cast_into!($ty; usize, isize, u32, i32, u64, i64, u128, i128); + cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); }; ($ty:ty; $($into:ty),*) => {$( impl CastInto<$into> for $ty { @@ -412,6 +370,12 @@ macro_rules! cast_into { )*}; } +cast_into!(usize); +cast_into!(isize); +cast_into!(u8); +cast_into!(i8); +cast_into!(u16); +cast_into!(i16); cast_into!(u32); cast_into!(i32); cast_into!(u64); diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 4a7c746a2ff54..9190c4251e548 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -31,11 +31,6 @@ #[cfg(test)] extern crate core; -#[allow(unused_unsafe)] -fn abort() -> ! { - unsafe { core::intrinsics::abort() } -} - #[macro_use] mod macros; diff --git a/library/compiler-builtins/testcrate/tests/div_rem.rs b/library/compiler-builtins/testcrate/tests/div_rem.rs index 0007c15aee5ea..bb4a08e42ae59 100644 --- a/library/compiler-builtins/testcrate/tests/div_rem.rs +++ b/library/compiler-builtins/testcrate/tests/div_rem.rs @@ -108,7 +108,7 @@ macro_rules! float { let quo0 = x / y; let quo1: $i = $fn(x, y); // division of subnormals is not currently handled - if !(Float::is_subnormal(&quo0) || Float::is_subnormal(&quo1)) { + if !(Float::is_subnormal(quo0) || Float::is_subnormal(quo1)) { if !Float::eq_repr(quo0, quo1) { panic!( "{}({}, {}): std: {}, builtins: {}", diff --git a/library/compiler-builtins/testcrate/tests/mul.rs b/library/compiler-builtins/testcrate/tests/mul.rs index 8b97ea46c3594..272bfa068815f 100644 --- a/library/compiler-builtins/testcrate/tests/mul.rs +++ b/library/compiler-builtins/testcrate/tests/mul.rs @@ -86,7 +86,7 @@ macro_rules! float_mul { let mul0 = x * y; let mul1: $f = $fn(x, y); // multiplication of subnormals is not currently handled - if !(Float::is_subnormal(&mul0) || Float::is_subnormal(&mul1)) { + if !(Float::is_subnormal(mul0) || Float::is_subnormal(mul1)) { if !Float::eq_repr(mul0, mul1) { panic!( "{}({}, {}): std: {}, builtins: {}", From 96a6110d69358304f6dbff1503de2cd6243dc231 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Thu, 10 Dec 2020 19:56:36 -0600 Subject: [PATCH 0904/4206] add remaining floating point tests --- .../testcrate/tests/addsub.rs | 17 +++++ .../compiler-builtins/testcrate/tests/cmp.rs | 60 +++++++++++++++++ .../testcrate/tests/div_rem.rs | 16 +++++ .../compiler-builtins/testcrate/tests/misc.rs | 66 ++++++++++++++----- .../compiler-builtins/testcrate/tests/mul.rs | 16 +++++ 5 files changed, 160 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/testcrate/tests/addsub.rs b/library/compiler-builtins/testcrate/tests/addsub.rs index ff56668b78b8f..da7684ec90126 100644 --- a/library/compiler-builtins/testcrate/tests/addsub.rs +++ b/library/compiler-builtins/testcrate/tests/addsub.rs @@ -1,3 +1,5 @@ +#![allow(unused_macros)] + use testcrate::*; macro_rules! sum { @@ -107,3 +109,18 @@ fn float_addsub() { f64, __adddf3, __subdf3; ); } + +#[cfg(target_arch = "arm")] +#[test] +fn float_addsub_arm() { + use compiler_builtins::float::{ + add::{__adddf3vfp, __addsf3vfp}, + sub::{__subdf3vfp, __subsf3vfp}, + Float, + }; + + float_sum!( + f32, __addsf3vfp, __subsf3vfp; + f64, __adddf3vfp, __subdf3vfp; + ); +} diff --git a/library/compiler-builtins/testcrate/tests/cmp.rs b/library/compiler-builtins/testcrate/tests/cmp.rs index d359b65d7e431..a49779ad0e48a 100644 --- a/library/compiler-builtins/testcrate/tests/cmp.rs +++ b/library/compiler-builtins/testcrate/tests/cmp.rs @@ -1,3 +1,5 @@ +#![allow(unused_macros)] + use testcrate::*; macro_rules! cmp { @@ -50,3 +52,61 @@ fn float_comparisons() { ); }); } + +macro_rules! cmp2 { + ($x:ident, $y:ident, $($unordered_val:expr, $fn_std:expr, $fn_builtins:ident);*;) => { + $( + let cmp0: i32 = if $x.is_nan() || $y.is_nan() { + $unordered_val + } else { + $fn_std as i32 + }; + let cmp1: i32 = $fn_builtins($x, $y); + if cmp0 != cmp1 { + panic!("{}({}, {}): std: {}, builtins: {}", stringify!($fn_builtins), $x, $y, cmp0, cmp1); + } + )* + }; +} + +#[cfg(target_arch = "arm")] +#[test] +fn float_comparisons_arm() { + use compiler_builtins::float::cmp::{ + __aeabi_dcmpeq, __aeabi_dcmpge, __aeabi_dcmpgt, __aeabi_dcmple, __aeabi_dcmplt, + __aeabi_fcmpeq, __aeabi_fcmpge, __aeabi_fcmpgt, __aeabi_fcmple, __aeabi_fcmplt, __eqdf2vfp, + __eqsf2vfp, __gedf2vfp, __gesf2vfp, __gtdf2vfp, __gtsf2vfp, __ledf2vfp, __lesf2vfp, + __ltdf2vfp, __ltsf2vfp, __nedf2vfp, __nesf2vfp, + }; + + fuzz_float_2(N, |x: f32, y: f32| { + cmp2!(x, y, + 0, x < y, __aeabi_fcmplt; + 0, x <= y, __aeabi_fcmple; + 0, x == y, __aeabi_fcmpeq; + 0, x >= y, __aeabi_fcmpge; + 0, x > y, __aeabi_fcmpgt; + 0, x < y, __ltsf2vfp; + 0, x <= y, __lesf2vfp; + 0, x == y, __eqsf2vfp; + 0, x >= y, __gesf2vfp; + 0, x > y, __gtsf2vfp; + 1, x != y, __nesf2vfp; + ); + }); + fuzz_float_2(N, |x: f64, y: f64| { + cmp2!(x, y, + 0, x < y, __aeabi_dcmplt; + 0, x <= y, __aeabi_dcmple; + 0, x == y, __aeabi_dcmpeq; + 0, x >= y, __aeabi_dcmpge; + 0, x > y, __aeabi_dcmpgt; + 0, x < y, __ltdf2vfp; + 0, x <= y, __ledf2vfp; + 0, x == y, __eqdf2vfp; + 0, x >= y, __gedf2vfp; + 0, x > y, __gtdf2vfp; + 1, x != y, __nedf2vfp; + ); + }); +} diff --git a/library/compiler-builtins/testcrate/tests/div_rem.rs b/library/compiler-builtins/testcrate/tests/div_rem.rs index bb4a08e42ae59..c3f0676400ed8 100644 --- a/library/compiler-builtins/testcrate/tests/div_rem.rs +++ b/library/compiler-builtins/testcrate/tests/div_rem.rs @@ -1,3 +1,5 @@ +#![allow(unused_macros)] + use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divmodti4}; use compiler_builtins::int::udiv::{__udivmoddi4, __udivmodsi4, __udivmodti4, u128_divide_sparc}; use testcrate::*; @@ -134,3 +136,17 @@ fn float_div() { f64, __divdf3; ); } + +#[cfg(target_arch = "arm")] +#[test] +fn float_div_arm() { + use compiler_builtins::float::{ + div::{__divdf3vfp, __divsf3vfp}, + Float, + }; + + float!( + f32, __divsf3vfp; + f64, __divdf3vfp; + ); +} diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index d31e3e6b6a7cc..ec3e9d96d45a6 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -1,3 +1,7 @@ +// makes configuration easier +#![allow(unused_macros)] + +use compiler_builtins::float::Float; use testcrate::*; /// Make sure that the the edge case tester and randomized tester don't break, and list examples of @@ -89,15 +93,37 @@ fn leading_zeros() { }) } +macro_rules! extend { + ($fX:ident, $fD:ident, $fn:ident) => { + fuzz_float(N, |x: $fX| { + let tmp0 = x as $fD; + let tmp1: $fD = $fn(x); + if !Float::eq_repr(tmp0, tmp1) { + panic!( + "{}({}): std: {}, builtins: {}", + stringify!($fn), + x, + tmp0, + tmp1 + ); + } + }); + }; +} + #[test] fn float_extend() { - fuzz_float(N, |x: f32| { - let tmp0 = x as f64; - let tmp1: f64 = compiler_builtins::float::extend::__extendsfdf2(x); - if !compiler_builtins::float::Float::eq_repr(tmp0, tmp1) { - panic!("__extendsfdf2({}): std: {}, builtins: {}", x, tmp0, tmp1); - } - }); + use compiler_builtins::float::extend::__extendsfdf2; + + extend!(f32, f64, __extendsfdf2); +} + +#[cfg(target_arch = "arm")] +#[test] +fn float_extend_arm() { + use compiler_builtins::float::extend::__extendsfdf2vfp; + + extend!(f32, f64, __extendsfdf2vfp); } // This doesn't quite work because of issues related to @@ -108,14 +134,16 @@ macro_rules! pow { ($($f:ty, $fn:ident);*;) => { $( fuzz_float_2(N, |x: $f, y: $f| { - let n = y as i32; - let tmp0: $f = x.powi(n); - let tmp1: $f = $fn(x, n); - if tmp0 != tmp1 { - panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn), x, y, tmp0, tmp1 - ); + if !(Float::is_subnormal(x) || Float::is_subnormal(y) || x < 0. || y < 0.) { + let n = y as i32; + let tmp0: $f = x.powi(n); + let tmp1: $f = $fn(x, n); + if tmp0 != tmp1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn), x, y, tmp0, tmp1 + ); + } } }); )* @@ -132,3 +160,11 @@ fn float_pow() { ); } */ + +// placeholder test to make sure basic functionality works +#[test] +fn float_pow() { + use compiler_builtins::float::pow::{__powidf2, __powisf2}; + assert_eq!(__powisf2(-3.0, 3), -27.0); + assert_eq!(__powidf2(-3.0, 3), -27.0); +} diff --git a/library/compiler-builtins/testcrate/tests/mul.rs b/library/compiler-builtins/testcrate/tests/mul.rs index 272bfa068815f..819f06ca9ef7d 100644 --- a/library/compiler-builtins/testcrate/tests/mul.rs +++ b/library/compiler-builtins/testcrate/tests/mul.rs @@ -1,3 +1,5 @@ +#![allow(unused_macros)] + use testcrate::*; macro_rules! mul { @@ -112,3 +114,17 @@ fn float_mul() { f64, __muldf3; ); } + +#[cfg(target_arch = "arm")] +#[test] +fn float_mul_arm() { + use compiler_builtins::float::{ + mul::{__muldf3vfp, __mulsf3vfp}, + Float, + }; + + float_mul!( + f32, __mulsf3vfp; + f64, __muldf3vfp; + ); +} From 3871282eee1de561eb90f47ea7cee4a70b272dd1 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Thu, 10 Dec 2020 20:30:48 -0600 Subject: [PATCH 0905/4206] fix `powi` --- library/compiler-builtins/src/float/mod.rs | 1 + library/compiler-builtins/src/float/pow.rs | 47 +++++++++---------- .../compiler-builtins/testcrate/tests/misc.rs | 47 +++++++++++-------- 3 files changed, 51 insertions(+), 44 deletions(-) diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 5a0d37a7deb0c..69e4dc6351711 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -15,6 +15,7 @@ pub mod sub; #[doc(hidden)] pub trait Float: Copy + + core::fmt::Debug + PartialEq + PartialOrd + ops::AddAssign diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index 7d7f75972c712..5ab5e4201c29d 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -1,39 +1,36 @@ use float::Float; +use int::Int; -trait Pow: Float { - /// Returns `a` raised to the power `b` - fn pow(self, mut b: i32) -> Self { - let mut a = self; - let recip = b < 0; - let mut r = Self::ONE; - loop { - if (b & 1) != 0 { - r *= a; - } - b = ((b as u32) >> 1) as i32; - if b == 0 { - break; - } - a *= a; +/// Returns `a` raised to the power `b` +fn pow(a: F, b: i32) -> F { + let mut a = a; + let recip = b < 0; + let mut pow = i32::abs_diff(b, 0); + let mut mul = F::ONE; + loop { + if (pow & 1) != 0 { + mul *= a; } - - if recip { - Self::ONE / r - } else { - r + pow >>= 1; + if pow == 0 { + break; } + a *= a; } -} -impl Pow for f32 {} -impl Pow for f64 {} + if recip { + F::ONE / mul + } else { + mul + } +} intrinsics! { pub extern "C" fn __powisf2(a: f32, b: i32) -> f32 { - a.pow(b) + pow(a, b) } pub extern "C" fn __powidf2(a: f64, b: i32) -> f64 { - a.pow(b) + pow(a, b) } } diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index ec3e9d96d45a6..82a1ea27b47e0 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -126,22 +126,39 @@ fn float_extend_arm() { extend!(f32, f64, __extendsfdf2vfp); } -// This doesn't quite work because of issues related to +// This is approximate because of issues related to // https://github.com/rust-lang/rust/issues/73920. -// TODO how do we resolve this? -/* +// TODO how do we resolve this indeterminacy? macro_rules! pow { - ($($f:ty, $fn:ident);*;) => { + ($($f:ty, $tolerance:expr, $fn:ident);*;) => { $( fuzz_float_2(N, |x: $f, y: $f| { - if !(Float::is_subnormal(x) || Float::is_subnormal(y) || x < 0. || y < 0.) { - let n = y as i32; + if !(Float::is_subnormal(x) || Float::is_subnormal(y) || x.is_nan()) { + let n = y.to_bits() & !<$f as Float>::SIGNIFICAND_MASK; + let n = (n as <$f as Float>::SignedInt) >> <$f as Float>::SIGNIFICAND_BITS; + let n = n as i32; let tmp0: $f = x.powi(n); let tmp1: $f = $fn(x, n); - if tmp0 != tmp1 { + let (a, b) = if tmp0 < tmp1 { + (tmp0, tmp1) + } else { + (tmp1, tmp0) + }; + let good = { + if a == b { + // handles infinity equality + true + } else if a < $tolerance { + b < $tolerance + } else { + let quo = b / a; + (quo < (1. + $tolerance)) && (quo > (1. - $tolerance)) + } + }; + if !good { panic!( "{}({}, {}): std: {}, builtins: {}", - stringify!($fn), x, y, tmp0, tmp1 + stringify!($fn), x, n, tmp0, tmp1 ); } } @@ -150,21 +167,13 @@ macro_rules! pow { }; } +#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] #[test] fn float_pow() { use compiler_builtins::float::pow::{__powidf2, __powisf2}; pow!( - f32, __powisf2; - f64, __powidf2; + f32, 1e-4, __powisf2; + f64, 1e-12, __powidf2; ); } -*/ - -// placeholder test to make sure basic functionality works -#[test] -fn float_pow() { - use compiler_builtins::float::pow::{__powidf2, __powisf2}; - assert_eq!(__powisf2(-3.0, 3), -27.0); - assert_eq!(__powidf2(-3.0, 3), -27.0); -} From 94af8a82683fa4984881305893eea3a120efc651 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Fri, 11 Dec 2020 13:26:41 -0600 Subject: [PATCH 0906/4206] Delete redundant tests The old tests were hacky and did not cover nearly as many cases as the new tests do. --- library/compiler-builtins/testcrate/build.rs | 1443 ----------------- .../testcrate/tests/generated.rs | 37 - 2 files changed, 1480 deletions(-) delete mode 100644 library/compiler-builtins/testcrate/build.rs delete mode 100644 library/compiler-builtins/testcrate/tests/generated.rs diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs deleted file mode 100644 index 39c2486c692e8..0000000000000 --- a/library/compiler-builtins/testcrate/build.rs +++ /dev/null @@ -1,1443 +0,0 @@ -use rand::seq::SliceRandom; -use rand::Rng; -use std::collections::HashMap; -use std::fmt; -use std::fmt::Write as FmtWrite; -use std::fs::{self, OpenOptions}; -use std::hash::{Hash, Hasher}; -use std::io::Write; -use std::path::PathBuf; -use std::{env, mem}; - -const NTESTS: usize = 1_000; - -fn main() { - let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); - let out_file = out_dir.join("generated.rs"); - drop(fs::remove_file(&out_file)); - - let target = env::var("TARGET").unwrap(); - let target_arch_arm = target.contains("arm") || target.contains("thumb"); - let target_arch_mips = target.contains("mips"); - - // TODO accept NaNs. We don't do that right now because we can't check - // for NaN-ness on the thumb targets (due to missing intrinsics) - - // float/add.rs - gen( - |(a, b): (MyF64, MyF64)| { - let c = a.0 + b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::add::__adddf3(a, b)", - ); - gen( - |(a, b): (MyF32, MyF32)| { - let c = a.0 + b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::add::__addsf3(a, b)", - ); - - if target_arch_arm { - gen( - |(a, b): (MyF64, MyF64)| { - let c = a.0 + b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::add::__adddf3vfp(a, b)", - ); - gen( - |(a, b): (LargeF32, LargeF32)| { - let c = a.0 + b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::add::__addsf3vfp(a, b)", - ); - } - - // float/cmp.rs - gen( - |(a, b): (MyF64, MyF64)| { - let (a, b) = (a.0, b.0); - if a.is_nan() || b.is_nan() { - return None; - } - - if a.is_nan() || b.is_nan() { - Some(-1) - } else if a < b { - Some(-1) - } else if a > b { - Some(1) - } else { - Some(0) - } - }, - "builtins::float::cmp::__gedf2(a, b)", - ); - gen( - |(a, b): (MyF32, MyF32)| { - let (a, b) = (a.0, b.0); - if a.is_nan() || b.is_nan() { - return None; - } - - if a.is_nan() || b.is_nan() { - Some(-1) - } else if a < b { - Some(-1) - } else if a > b { - Some(1) - } else { - Some(0) - } - }, - "builtins::float::cmp::__gesf2(a, b)", - ); - gen( - |(a, b): (MyF64, MyF64)| { - let (a, b) = (a.0, b.0); - if a.is_nan() || b.is_nan() { - return None; - } - - if a.is_nan() || b.is_nan() { - Some(1) - } else if a < b { - Some(-1) - } else if a > b { - Some(1) - } else { - Some(0) - } - }, - "builtins::float::cmp::__ledf2(a, b)", - ); - gen( - |(a, b): (MyF32, MyF32)| { - let (a, b) = (a.0, b.0); - if a.is_nan() || b.is_nan() { - return None; - } - - if a.is_nan() || b.is_nan() { - Some(1) - } else if a < b { - Some(-1) - } else if a > b { - Some(1) - } else { - Some(0) - } - }, - "builtins::float::cmp::__lesf2(a, b)", - ); - - gen( - |(a, b): (MyF32, MyF32)| { - let c = a.0.is_nan() || b.0.is_nan(); - Some(c as i32) - }, - "builtins::float::cmp::__unordsf2(a, b)", - ); - - gen( - |(a, b): (MyF64, MyF64)| { - let c = a.0.is_nan() || b.0.is_nan(); - Some(c as i32) - }, - "builtins::float::cmp::__unorddf2(a, b)", - ); - - if target_arch_arm { - gen( - |(a, b): (MyF32, MyF32)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - let c = (a.0 <= b.0) as i32; - Some(c) - }, - "builtins::float::cmp::__aeabi_fcmple(a, b)", - ); - - gen( - |(a, b): (MyF32, MyF32)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - let c = (a.0 >= b.0) as i32; - Some(c) - }, - "builtins::float::cmp::__aeabi_fcmpge(a, b)", - ); - - gen( - |(a, b): (MyF32, MyF32)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - let c = (a.0 == b.0) as i32; - Some(c) - }, - "builtins::float::cmp::__aeabi_fcmpeq(a, b)", - ); - - gen( - |(a, b): (MyF32, MyF32)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - let c = (a.0 < b.0) as i32; - Some(c) - }, - "builtins::float::cmp::__aeabi_fcmplt(a, b)", - ); - - gen( - |(a, b): (MyF32, MyF32)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - let c = (a.0 > b.0) as i32; - Some(c) - }, - "builtins::float::cmp::__aeabi_fcmpgt(a, b)", - ); - - gen( - |(a, b): (MyF64, MyF64)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - let c = (a.0 <= b.0) as i32; - Some(c) - }, - "builtins::float::cmp::__aeabi_dcmple(a, b)", - ); - - gen( - |(a, b): (MyF64, MyF64)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - let c = (a.0 >= b.0) as i32; - Some(c) - }, - "builtins::float::cmp::__aeabi_dcmpge(a, b)", - ); - - gen( - |(a, b): (MyF64, MyF64)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - let c = (a.0 == b.0) as i32; - Some(c) - }, - "builtins::float::cmp::__aeabi_dcmpeq(a, b)", - ); - - gen( - |(a, b): (MyF64, MyF64)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - let c = (a.0 < b.0) as i32; - Some(c) - }, - "builtins::float::cmp::__aeabi_dcmplt(a, b)", - ); - - gen( - |(a, b): (MyF64, MyF64)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - let c = (a.0 > b.0) as i32; - Some(c) - }, - "builtins::float::cmp::__aeabi_dcmpgt(a, b)", - ); - - gen( - |(a, b): (LargeF32, LargeF32)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - Some((a.0 >= b.0) as i32) - }, - "builtins::float::cmp::__gesf2vfp(a, b)", - ); - gen( - |(a, b): (MyF64, MyF64)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - Some((a.0 >= b.0) as i32) - }, - "builtins::float::cmp::__gedf2vfp(a, b)", - ); - gen( - |(a, b): (LargeF32, LargeF32)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - Some((a.0 > b.0) as i32) - }, - "builtins::float::cmp::__gtsf2vfp(a, b)", - ); - gen( - |(a, b): (MyF64, MyF64)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - Some((a.0 > b.0) as i32) - }, - "builtins::float::cmp::__gtdf2vfp(a, b)", - ); - gen( - |(a, b): (LargeF32, LargeF32)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - Some((a.0 < b.0) as i32) - }, - "builtins::float::cmp::__ltsf2vfp(a, b)", - ); - gen( - |(a, b): (MyF64, MyF64)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - Some((a.0 < b.0) as i32) - }, - "builtins::float::cmp::__ltdf2vfp(a, b)", - ); - gen( - |(a, b): (LargeF32, LargeF32)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - Some((a.0 <= b.0) as i32) - }, - "builtins::float::cmp::__lesf2vfp(a, b)", - ); - gen( - |(a, b): (MyF64, MyF64)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - Some((a.0 <= b.0) as i32) - }, - "builtins::float::cmp::__ledf2vfp(a, b)", - ); - gen( - |(a, b): (LargeF32, LargeF32)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - Some((a.0 != b.0) as i32) - }, - "builtins::float::cmp::__nesf2vfp(a, b)", - ); - gen( - |(a, b): (MyF64, MyF64)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - Some((a.0 != b.0) as i32) - }, - "builtins::float::cmp::__nedf2vfp(a, b)", - ); - gen( - |(a, b): (LargeF32, LargeF32)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - Some((a.0 == b.0) as i32) - }, - "builtins::float::cmp::__eqsf2vfp(a, b)", - ); - gen( - |(a, b): (MyF64, MyF64)| { - if a.0.is_nan() || b.0.is_nan() { - return None; - } - Some((a.0 == b.0) as i32) - }, - "builtins::float::cmp::__eqdf2vfp(a, b)", - ); - } - - // float/extend.rs - gen( - |a: MyF32| { - if a.0.is_nan() { - return None; - } - Some(f64::from(a.0)) - }, - "builtins::float::extend::__extendsfdf2(a)", - ); - if target_arch_arm { - gen( - |a: LargeF32| { - if a.0.is_nan() { - return None; - } - Some(f64::from(a.0)) - }, - "builtins::float::extend::__extendsfdf2vfp(a)", - ); - } - - // float/conv.rs - gen( - |a: MyF64| i64::cast(a.0), - "builtins::float::conv::__fixdfdi(a)", - ); - gen( - |a: MyF64| i32::cast(a.0), - "builtins::float::conv::__fixdfsi(a)", - ); - gen( - |a: MyF32| i64::cast(a.0), - "builtins::float::conv::__fixsfdi(a)", - ); - gen( - |a: MyF32| i32::cast(a.0), - "builtins::float::conv::__fixsfsi(a)", - ); - gen( - |a: MyF32| i128::cast(a.0), - "builtins::float::conv::__fixsfti(a)", - ); - gen( - |a: MyF64| i128::cast(a.0), - "builtins::float::conv::__fixdfti(a)", - ); - gen( - |a: MyF64| u64::cast(a.0), - "builtins::float::conv::__fixunsdfdi(a)", - ); - gen( - |a: MyF64| u32::cast(a.0), - "builtins::float::conv::__fixunsdfsi(a)", - ); - gen( - |a: MyF32| u64::cast(a.0), - "builtins::float::conv::__fixunssfdi(a)", - ); - gen( - |a: MyF32| u32::cast(a.0), - "builtins::float::conv::__fixunssfsi(a)", - ); - gen( - |a: MyF32| u128::cast(a.0), - "builtins::float::conv::__fixunssfti(a)", - ); - gen( - |a: MyF64| u128::cast(a.0), - "builtins::float::conv::__fixunsdfti(a)", - ); - gen( - |a: MyI64| Some(a.0 as f64), - "builtins::float::conv::__floatdidf(a)", - ); - gen( - |a: MyI32| Some(a.0 as f64), - "builtins::float::conv::__floatsidf(a)", - ); - gen( - |a: MyI32| Some(a.0 as f32), - "builtins::float::conv::__floatsisf(a)", - ); - gen( - |a: MyU64| Some(a.0 as f64), - "builtins::float::conv::__floatundidf(a)", - ); - gen( - |a: MyU32| Some(a.0 as f64), - "builtins::float::conv::__floatunsidf(a)", - ); - gen( - |a: MyU32| Some(a.0 as f32), - "builtins::float::conv::__floatunsisf(a)", - ); - gen( - |a: MyU128| Some(a.0 as f32), - "builtins::float::conv::__floatuntisf(a)", - ); - if !target_arch_mips { - gen( - |a: MyI128| Some(a.0 as f32), - "builtins::float::conv::__floattisf(a)", - ); - gen( - |a: MyI128| Some(a.0 as f64), - "builtins::float::conv::__floattidf(a)", - ); - gen( - |a: MyU128| Some(a.0 as f64), - "builtins::float::conv::__floatuntidf(a)", - ); - } - - // float/pow.rs - gen( - |(a, b): (MyF64, MyI32)| { - let c = a.0.powi(b.0); - if a.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::pow::__powidf2(a, b)", - ); - gen( - |(a, b): (MyF32, MyI32)| { - let c = a.0.powi(b.0); - if a.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::pow::__powisf2(a, b)", - ); - - // float/sub.rs - gen( - |(a, b): (MyF64, MyF64)| { - let c = a.0 - b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::sub::__subdf3(a, b)", - ); - gen( - |(a, b): (MyF32, MyF32)| { - let c = a.0 - b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::sub::__subsf3(a, b)", - ); - - if target_arch_arm { - gen( - |(a, b): (MyF64, MyF64)| { - let c = a.0 - b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::sub::__subdf3vfp(a, b)", - ); - gen( - |(a, b): (LargeF32, LargeF32)| { - let c = a.0 - b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::sub::__subsf3vfp(a, b)", - ); - } - - // float/mul.rs - gen( - |(a, b): (MyF64, MyF64)| { - let c = a.0 * b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::mul::__muldf3(a, b)", - ); - gen( - |(a, b): (LargeF32, LargeF32)| { - let c = a.0 * b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::mul::__mulsf3(a, b)", - ); - - if target_arch_arm { - gen( - |(a, b): (MyF64, MyF64)| { - let c = a.0 * b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::mul::__muldf3vfp(a, b)", - ); - gen( - |(a, b): (LargeF32, LargeF32)| { - let c = a.0 * b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() { - None - } else { - Some(c) - } - }, - "builtins::float::mul::__mulsf3vfp(a, b)", - ); - } - - // float/div.rs - gen( - |(a, b): (MyF64, MyF64)| { - if b.0 == 0.0 { - return None; - } - let c = a.0 / b.0; - if a.0.is_nan() - || b.0.is_nan() - || c.is_nan() - || c.abs() <= f64::from_bits(4503599627370495u64) - { - None - } else { - Some(c) - } - }, - "builtins::float::div::__divdf3(a, b)", - ); - gen( - |(a, b): (LargeF32, LargeF32)| { - if b.0 == 0.0 { - return None; - } - let c = a.0 / b.0; - if a.0.is_nan() || b.0.is_nan() || c.is_nan() || c.abs() <= f32::from_bits(16777215u32) - { - None - } else { - Some(c) - } - }, - "builtins::float::div::__divsf3(a, b)", - ); - - if target_arch_arm { - gen( - |(a, b): (MyF64, MyF64)| { - if b.0 == 0.0 { - return None; - } - let c = a.0 / b.0; - if a.0.is_nan() - || b.0.is_nan() - || c.is_nan() - || c.abs() <= f64::from_bits(4503599627370495u64) - { - None - } else { - Some(c) - } - }, - "builtins::float::div::__divdf3vfp(a, b)", - ); - gen( - |(a, b): (LargeF32, LargeF32)| { - if b.0 == 0.0 { - return None; - } - let c = a.0 / b.0; - if a.0.is_nan() - || b.0.is_nan() - || c.is_nan() - || c.abs() <= f32::from_bits(16777215u32) - { - None - } else { - Some(c) - } - }, - "builtins::float::div::__divsf3vfp(a, b)", - ); - } - - // int/addsub.rs - gen( - |(a, b): (MyU128, MyU128)| Some(a.0.wrapping_add(b.0)), - "builtins::int::addsub::__rust_u128_add(a, b)", - ); - gen( - |(a, b): (MyI128, MyI128)| Some(a.0.wrapping_add(b.0)), - "builtins::int::addsub::__rust_i128_add(a, b)", - ); - gen( - |(a, b): (MyU128, MyU128)| Some(a.0.overflowing_add(b.0)), - "builtins::int::addsub::__rust_u128_addo(a, b)", - ); - gen( - |(a, b): (MyI128, MyI128)| Some(a.0.overflowing_add(b.0)), - "builtins::int::addsub::__rust_i128_addo(a, b)", - ); - gen( - |(a, b): (MyU128, MyU128)| Some(a.0.wrapping_sub(b.0)), - "builtins::int::addsub::__rust_u128_sub(a, b)", - ); - gen( - |(a, b): (MyI128, MyI128)| Some(a.0.wrapping_sub(b.0)), - "builtins::int::addsub::__rust_i128_sub(a, b)", - ); - gen( - |(a, b): (MyU128, MyU128)| Some(a.0.overflowing_sub(b.0)), - "builtins::int::addsub::__rust_u128_subo(a, b)", - ); - gen( - |(a, b): (MyI128, MyI128)| Some(a.0.overflowing_sub(b.0)), - "builtins::int::addsub::__rust_i128_subo(a, b)", - ); - - // int/mul.rs - gen( - |(a, b): (MyU64, MyU64)| Some(a.0.wrapping_mul(b.0)), - "builtins::int::mul::__muldi3(a, b)", - ); - gen( - |(a, b): (MyI64, MyI64)| Some(a.0.overflowing_mul(b.0)), - "{ - let mut o = 2; - let c = builtins::int::mul::__mulodi4(a, b, &mut o); - (c, match o { 0 => false, 1 => true, _ => panic!() }) - }", - ); - gen( - |(a, b): (MyI32, MyI32)| Some(a.0.overflowing_mul(b.0)), - "{ - let mut o = 2; - let c = builtins::int::mul::__mulosi4(a, b, &mut o); - (c, match o { 0 => false, 1 => true, _ => panic!() }) - }", - ); - gen( - |(a, b): (MyI128, MyI128)| Some(a.0.wrapping_mul(b.0)), - "builtins::int::mul::__multi3(a, b)", - ); - gen( - |(a, b): (MyI128, MyI128)| Some(a.0.overflowing_mul(b.0)), - "{ - let mut o = 2; - let c = builtins::int::mul::__muloti4(a, b, &mut o); - (c, match o { 0 => false, 1 => true, _ => panic!() }) - }", - ); - - // int/sdiv.rs - gen( - |(a, b): (MyI64, MyI64)| { - if b.0 == 0 { - None - } else { - Some(a.0 / b.0) - } - }, - "builtins::int::sdiv::__divdi3(a, b)", - ); - gen( - |(a, b): (MyI64, MyI64)| { - if b.0 == 0 { - None - } else { - Some((a.0 / b.0, a.0 % b.0)) - } - }, - "{ - let mut r = 0; - (builtins::int::sdiv::__divmoddi4(a, b, &mut r), r) - }", - ); - gen( - |(a, b): (MyI32, MyI32)| { - if b.0 == 0 { - None - } else { - Some((a.0 / b.0, a.0 % b.0)) - } - }, - "{ - let mut r = 0; - (builtins::int::sdiv::__divmodsi4(a, b, &mut r), r) - }", - ); - gen( - |(a, b): (MyI128, MyI128)| { - if b.0 == 0 { - None - } else { - Some((a.0 / b.0, a.0 % b.0)) - } - }, - "{ - let mut r = 0; - (builtins::int::sdiv::__divmodti4(a, b, &mut r), r) - }", - ); - gen( - |(a, b): (MyI32, MyI32)| { - if b.0 == 0 { - None - } else { - Some(a.0 / b.0) - } - }, - "builtins::int::sdiv::__divsi3(a, b)", - ); - gen( - |(a, b): (MyI32, MyI32)| { - if b.0 == 0 { - None - } else { - Some(a.0 % b.0) - } - }, - "builtins::int::sdiv::__modsi3(a, b)", - ); - gen( - |(a, b): (MyI64, MyI64)| { - if b.0 == 0 { - None - } else { - Some(a.0 % b.0) - } - }, - "builtins::int::sdiv::__moddi3(a, b)", - ); - gen( - |(a, b): (MyI128, MyI128)| { - if b.0 == 0 { - None - } else { - Some(a.0 / b.0) - } - }, - "builtins::int::sdiv::__divti3(a, b)", - ); - gen( - |(a, b): (MyI128, MyI128)| { - if b.0 == 0 { - None - } else { - Some(a.0 % b.0) - } - }, - "builtins::int::sdiv::__modti3(a, b)", - ); - - // int/shift.rs - gen( - |(a, b): (MyU32, MyU32)| Some(a.0 << (b.0 % 32)), - "builtins::int::shift::__ashlsi3(a, b % 32)", - ); - gen( - |(a, b): (MyU64, MyU32)| Some(a.0 << (b.0 % 64)), - "builtins::int::shift::__ashldi3(a, b % 64)", - ); - gen( - |(a, b): (MyU128, MyU32)| Some(a.0 << (b.0 % 128)), - "builtins::int::shift::__ashlti3(a, b % 128)", - ); - gen( - |(a, b): (MyI32, MyU32)| Some(a.0 >> (b.0 % 32)), - "builtins::int::shift::__ashrsi3(a, b % 32)", - ); - gen( - |(a, b): (MyI64, MyU32)| Some(a.0 >> (b.0 % 64)), - "builtins::int::shift::__ashrdi3(a, b % 64)", - ); - gen( - |(a, b): (MyI128, MyU32)| Some(a.0 >> (b.0 % 128)), - "builtins::int::shift::__ashrti3(a, b % 128)", - ); - gen( - |(a, b): (MyU32, MyU32)| Some(a.0 >> (b.0 % 32)), - "builtins::int::shift::__lshrsi3(a, b % 32)", - ); - gen( - |(a, b): (MyU64, MyU32)| Some(a.0 >> (b.0 % 64)), - "builtins::int::shift::__lshrdi3(a, b % 64)", - ); - gen( - |(a, b): (MyU128, MyU32)| Some(a.0 >> (b.0 % 128)), - "builtins::int::shift::__lshrti3(a, b % 128)", - ); - - // int/udiv.rs - gen( - |(a, b): (MyU64, MyU64)| { - if b.0 == 0 { - None - } else { - Some(a.0 / b.0) - } - }, - "builtins::int::udiv::__udivdi3(a, b)", - ); - gen( - |(a, b): (MyU64, MyU64)| { - if b.0 == 0 { - None - } else { - Some((a.0 / b.0, a.0 % b.0)) - } - }, - "{ - let mut r = 0; - (builtins::int::udiv::__udivmoddi4(a, b, Some(&mut r)), r) - }", - ); - gen( - |(a, b): (MyU32, MyU32)| { - if b.0 == 0 { - None - } else { - Some((a.0 / b.0, a.0 % b.0)) - } - }, - "{ - let mut r = 0; - (builtins::int::udiv::__udivmodsi4(a, b, Some(&mut r)), r) - }", - ); - gen( - |(a, b): (MyU32, MyU32)| { - if b.0 == 0 { - None - } else { - Some(a.0 / b.0) - } - }, - "builtins::int::udiv::__udivsi3(a, b)", - ); - gen( - |(a, b): (MyU32, MyU32)| { - if b.0 == 0 { - None - } else { - Some(a.0 % b.0) - } - }, - "builtins::int::udiv::__umodsi3(a, b)", - ); - gen( - |(a, b): (MyU64, MyU64)| { - if b.0 == 0 { - None - } else { - Some(a.0 % b.0) - } - }, - "builtins::int::udiv::__umoddi3(a, b)", - ); - gen( - |(a, b): (MyU128, MyU128)| { - if b.0 == 0 { - None - } else { - Some(a.0 / b.0) - } - }, - "builtins::int::udiv::__udivti3(a, b)", - ); - gen( - |(a, b): (MyU128, MyU128)| { - if b.0 == 0 { - None - } else { - Some(a.0 % b.0) - } - }, - "builtins::int::udiv::__umodti3(a, b)", - ); - gen( - |(a, b): (MyU128, MyU128)| { - if b.0 == 0 { - None - } else { - Some((a.0 / b.0, a.0 % b.0)) - } - }, - "{ - let mut r = 0; - (builtins::int::udiv::__udivmodti4(a, b, Some(&mut r)), r) - }", - ); -} - -macro_rules! gen_float { - ($name:ident, - $fty:ident, - $uty:ident, - $bits:expr, - $significand_bits:expr) => { - pub fn $name(rng: &mut R) -> $fty - where - R: Rng + ?Sized, - { - const BITS: u8 = $bits; - const SIGNIFICAND_BITS: u8 = $significand_bits; - - const SIGNIFICAND_MASK: $uty = (1 << SIGNIFICAND_BITS) - 1; - const SIGN_MASK: $uty = (1 << (BITS - 1)); - const EXPONENT_MASK: $uty = !(SIGN_MASK | SIGNIFICAND_MASK); - - fn mk_f32(sign: bool, exponent: $uty, significand: $uty) -> $fty { - unsafe { - mem::transmute( - ((sign as $uty) << (BITS - 1)) - | ((exponent & EXPONENT_MASK) << SIGNIFICAND_BITS) - | (significand & SIGNIFICAND_MASK), - ) - } - } - - if rng.gen_range(0, 10) == 1 { - // Special values - *[ - -0.0, - 0.0, - ::std::$fty::MIN, - ::std::$fty::MIN_POSITIVE, - ::std::$fty::MAX, - ::std::$fty::NAN, - ::std::$fty::INFINITY, - -::std::$fty::INFINITY, - ] - .choose(rng) - .unwrap() - } else if rng.gen_range(0, 10) == 1 { - // NaN patterns - mk_f32(rng.gen(), rng.gen(), 0) - } else if rng.gen() { - // Denormalized - mk_f32(rng.gen(), 0, rng.gen()) - } else { - // Random anything - mk_f32(rng.gen(), rng.gen(), rng.gen()) - } - } - }; -} - -gen_float!(gen_f32, f32, u32, 32, 23); -gen_float!(gen_f64, f64, u64, 64, 52); - -macro_rules! gen_large_float { - ($name:ident, - $fty:ident, - $uty:ident, - $bits:expr, - $significand_bits:expr) => { - pub fn $name(rng: &mut R) -> $fty - where - R: Rng + ?Sized, - { - const BITS: u8 = $bits; - const SIGNIFICAND_BITS: u8 = $significand_bits; - - const SIGNIFICAND_MASK: $uty = (1 << SIGNIFICAND_BITS) - 1; - const SIGN_MASK: $uty = (1 << (BITS - 1)); - const EXPONENT_MASK: $uty = !(SIGN_MASK | SIGNIFICAND_MASK); - - fn mk_f32(sign: bool, exponent: $uty, significand: $uty) -> $fty { - unsafe { - mem::transmute( - ((sign as $uty) << (BITS - 1)) - | ((exponent & EXPONENT_MASK) << SIGNIFICAND_BITS) - | (significand & SIGNIFICAND_MASK), - ) - } - } - - if rng.gen_range(0, 10) == 1 { - // Special values - *[ - -0.0, - 0.0, - ::std::$fty::MIN, - ::std::$fty::MIN_POSITIVE, - ::std::$fty::MAX, - ::std::$fty::NAN, - ::std::$fty::INFINITY, - -::std::$fty::INFINITY, - ] - .choose(rng) - .unwrap() - } else if rng.gen_range(0, 10) == 1 { - // NaN patterns - mk_f32(rng.gen(), rng.gen(), 0) - } else if rng.gen() { - // Denormalized - mk_f32(rng.gen(), 0, rng.gen()) - } else { - // Random anything - rng.gen::<$fty>() - } - } - }; -} - -gen_large_float!(gen_large_f32, f32, u32, 32, 23); -gen_large_float!(gen_large_f64, f64, u64, 64, 52); - -trait TestInput: Hash + Eq + fmt::Debug { - fn ty_name() -> String; - fn generate_lets(container: &str, cnt: &mut u8) -> String; - fn generate_static(&self, dst: &mut String); -} - -trait TestOutput { - fn ty_name() -> String; - fn generate_static(&self, dst: &mut String); - fn generate_expr(container: &str) -> String; -} - -fn gen(mut generate: F, test: &str) -where - F: FnMut(A) -> Option, - A: TestInput + Copy, - R: TestOutput, - rand::distributions::Standard: rand::distributions::Distribution, -{ - let rng = &mut rand::thread_rng(); - let testname = test.split("::").last().unwrap().split("(").next().unwrap(); - let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); - let out_file = out_dir.join("generated.rs"); - - let mut testcases = HashMap::new(); - let mut n = NTESTS; - while n > 0 { - let input: A = rng.gen(); - if testcases.contains_key(&input) { - continue; - } - let output = match generate(input) { - Some(o) => o, - None => continue, - }; - testcases.insert(input, output); - n -= 1; - } - - let mut contents = String::new(); - contents.push_str(&format!("mod {} {{\nuse super::*;\n", testname)); - contents.push_str("#[test]\n"); - contents.push_str("fn test() {\n"); - contents.push_str(&format!( - "static TESTS: [({}, {}); {}] = [\n", - A::ty_name(), - R::ty_name(), - NTESTS - )); - for (input, output) in testcases { - contents.push_str(" ("); - input.generate_static(&mut contents); - contents.push_str(", "); - output.generate_static(&mut contents); - contents.push_str("),\n"); - } - contents.push_str("];\n"); - - contents.push_str(&format!( - r#" - for &(inputs, output) in TESTS.iter() {{ - {} - assert_eq!({}, {}, "inputs {{:?}}", inputs) - }} - "#, - A::generate_lets("inputs", &mut 0), - R::generate_expr("output"), - test, - )); - contents.push_str("\n}\n"); - contents.push_str("\n}\n"); - - OpenOptions::new() - .write(true) - .append(true) - .create(true) - .open(out_file) - .unwrap() - .write_all(contents.as_bytes()) - .unwrap(); -} - -macro_rules! my_float { - ($(struct $name:ident($inner:ident) = $gen:ident;)*) => ($( - #[derive(Debug, Clone, Copy)] - struct $name($inner); - - impl TestInput for $name { - fn ty_name() -> String { - format!("u{}", &stringify!($inner)[1..]) - } - - fn generate_lets(container: &str, cnt: &mut u8) -> String { - let me = *cnt; - *cnt += 1; - format!("let {} = {}::from_bits({});\n", - (b'a' + me) as char, - stringify!($inner), - container) - } - - fn generate_static(&self, dst: &mut String) { - write!(dst, "{}", self.0.to_bits()).unwrap(); - } - } - - impl rand::distributions::Distribution<$name> for rand::distributions::Standard { - fn sample(&self, r: &mut R) -> $name { - $name($gen(r)) - } - } - - impl Hash for $name { - fn hash(&self, h: &mut H) { - self.0.to_bits().hash(h) - } - } - - impl PartialEq for $name { - fn eq(&self, other: &$name) -> bool { - self.0.to_bits() == other.0.to_bits() - } - } - - impl Eq for $name {} - - )*) -} - -my_float! { - struct MyF64(f64) = gen_f64; - struct LargeF64(f64) = gen_large_f64; - struct MyF32(f32) = gen_f32; - struct LargeF32(f32) = gen_large_f32; -} - -macro_rules! my_integer { - ($(struct $name:ident($inner:ident);)*) => ($( - #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] - struct $name($inner); - - impl TestInput for $name { - fn ty_name() -> String { - stringify!($inner).to_string() - } - - fn generate_lets(container: &str, cnt: &mut u8) -> String { - let me = *cnt; - *cnt += 1; - format!("let {} = {};\n", - (b'a' + me) as char, - container) - } - - fn generate_static(&self, dst: &mut String) { - write!(dst, "{}", self.0).unwrap(); - } - } - - impl rand::distributions::Distribution<$name> for rand::distributions::Standard { - fn sample(&self, r: &mut R) -> $name { - let bits = (0 as $inner).count_zeros(); - let mut mk = || { - if r.gen_range(0, 10) == 1 { - *[ - ::std::$inner::MAX >> (bits / 2), - 0, - ::std::$inner::MIN >> (bits / 2), - ].choose(r).unwrap() - } else { - r.gen::<$inner>() - } - }; - let a = mk(); - let b = mk(); - $name((a << (bits / 2)) | (b & (!0 << (bits / 2)))) - } - } - )*) -} - -my_integer! { - struct MyI32(i32); - struct MyI64(i64); - struct MyI128(i128); - struct MyU16(u16); - struct MyU32(u32); - struct MyU64(u64); - struct MyU128(u128); -} - -impl TestInput for (A, B) -where - A: TestInput, - B: TestInput, -{ - fn ty_name() -> String { - format!("({}, {})", A::ty_name(), B::ty_name()) - } - - fn generate_lets(container: &str, cnt: &mut u8) -> String { - format!( - "{}{}", - A::generate_lets(&format!("{}.0", container), cnt), - B::generate_lets(&format!("{}.1", container), cnt) - ) - } - - fn generate_static(&self, dst: &mut String) { - dst.push_str("("); - self.0.generate_static(dst); - dst.push_str(", "); - self.1.generate_static(dst); - dst.push_str(")"); - } -} - -impl TestOutput for f64 { - fn ty_name() -> String { - "u64".to_string() - } - - fn generate_static(&self, dst: &mut String) { - write!(dst, "{}", self.to_bits()).unwrap(); - } - - fn generate_expr(container: &str) -> String { - format!("f64::from_bits({})", container) - } -} - -impl TestOutput for f32 { - fn ty_name() -> String { - "u32".to_string() - } - - fn generate_static(&self, dst: &mut String) { - write!(dst, "{}", self.to_bits()).unwrap(); - } - - fn generate_expr(container: &str) -> String { - format!("f32::from_bits({})", container) - } -} - -macro_rules! plain_test_output { - ($($i:tt)*) => ($( - impl TestOutput for $i { - fn ty_name() -> String { - stringify!($i).to_string() - } - - fn generate_static(&self, dst: &mut String) { - write!(dst, "{}", self).unwrap(); - } - - fn generate_expr(container: &str) -> String { - container.to_string() - } - } - )*) -} - -plain_test_output!(i32 i64 i128 u32 u64 u128 bool); - -impl TestOutput for (A, B) -where - A: TestOutput, - B: TestOutput, -{ - fn ty_name() -> String { - format!("({}, {})", A::ty_name(), B::ty_name()) - } - - fn generate_static(&self, dst: &mut String) { - dst.push_str("("); - self.0.generate_static(dst); - dst.push_str(", "); - self.1.generate_static(dst); - dst.push_str(")"); - } - - fn generate_expr(container: &str) -> String { - container.to_string() - } -} - -trait FromFloat: Sized { - fn cast(src: T) -> Option; -} - -macro_rules! from_float { - ($($src:ident => $($dst:ident),+);+;) => { - $( - $( - impl FromFloat<$src> for $dst { - fn cast(src: $src) -> Option<$dst> { - use std::{$dst, $src}; - - if src.is_nan() || - src.is_infinite() || - src < std::$dst::MIN as $src || - src > std::$dst::MAX as $src - { - None - } else { - Some(src as $dst) - } - } - } - )+ - )+ - } -} - -from_float! { - f32 => i32, i64, i128, u32, u64, u128; - f64 => i32, i64, i128, u32, u64, u128; -} diff --git a/library/compiler-builtins/testcrate/tests/generated.rs b/library/compiler-builtins/testcrate/tests/generated.rs deleted file mode 100644 index a296db22da689..0000000000000 --- a/library/compiler-builtins/testcrate/tests/generated.rs +++ /dev/null @@ -1,37 +0,0 @@ -#![feature(lang_items)] -#![allow(bad_style)] -#![allow(unused_imports)] -#![no_std] - -extern crate compiler_builtins as builtins; - -#[cfg(all( - target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test -))] -extern crate utest_cortex_m_qemu; - -#[cfg(all( - target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test -))] -#[macro_use] -extern crate utest_macros; - -#[cfg(all( - target_arch = "arm", - not(any(target_env = "gnu", target_env = "musl")), - target_os = "linux", - test -))] -macro_rules! panic { // overrides `panic!` - ($($tt:tt)*) => { - upanic!($($tt)*); - }; -} - -include!(concat!(env!("OUT_DIR"), "/generated.rs")); From 1d9d761e9fe941b014c698cc8d686824924da6d9 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Fri, 11 Dec 2020 14:20:51 -0600 Subject: [PATCH 0907/4206] Fix panic-handler documentation rust-lang/rust#51647 is fixed but panic-handler is still needed --- library/compiler-builtins/crates/panic-handler/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/crates/panic-handler/src/lib.rs b/library/compiler-builtins/crates/panic-handler/src/lib.rs index a75999a4b605e..673e005224bd0 100644 --- a/library/compiler-builtins/crates/panic-handler/src/lib.rs +++ b/library/compiler-builtins/crates/panic-handler/src/lib.rs @@ -1,4 +1,4 @@ -// Hack of a crate until rust-lang/rust#51647 is fixed +//! This is needed for tests on targets that require a `#[panic_handler]` function #![feature(no_core)] #![no_core] From 1cf47804df8d69192b60cafcf11b9d4d88e223da Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Fri, 11 Dec 2020 14:45:35 -0600 Subject: [PATCH 0908/4206] Fix all clippy warnings --- library/compiler-builtins/src/float/add.rs | 5 ++--- library/compiler-builtins/src/float/cmp.rs | 21 ++++++++----------- library/compiler-builtins/src/float/div.rs | 4 ++++ library/compiler-builtins/src/float/mul.rs | 2 +- .../src/int/specialized_div_rem/mod.rs | 7 +++++++ library/compiler-builtins/src/lib.rs | 2 ++ library/compiler-builtins/src/mem/mod.rs | 3 +++ 7 files changed, 28 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index e8b9f9e774272..67f6c2c1489fa 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -137,9 +137,8 @@ where a_significand <<= shift; a_exponent -= shift; } - } else - /* addition */ - { + } else { + // addition a_significand += b_significand; // If the addition carried up, we need to right-shift the result and diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 79c26b09921fc..1d4e384335bd7 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -63,25 +63,22 @@ fn cmp(a: F, b: F) -> Result { // a and b as signed integers as we would with a fp_ting-point compare. if a_srep & b_srep >= szero { if a_srep < b_srep { - return Result::Less; + Result::Less } else if a_srep == b_srep { - return Result::Equal; + Result::Equal } else { - return Result::Greater; + Result::Greater } - } // Otherwise, both are negative, so we need to flip the sense of the // comparison to get the correct result. (This assumes a twos- or ones- // complement integer representation; if integers are represented in a // sign-magnitude representation, then this flip is incorrect). - else { - if a_srep > b_srep { - return Result::Less; - } else if a_srep == b_srep { - return Result::Equal; - } else { - return Result::Greater; - } + } else if a_srep > b_srep { + Result::Less + } else if a_srep == b_srep { + Result::Equal + } else { + Result::Greater } } diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index dd6467f88fb7e..9ac1e87b4e2d9 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -1,3 +1,7 @@ +// The functions are complex with many branches, and explicit +// `return`s makes it clear where function exit points are +#![allow(clippy::needless_return)] + use float::Float; use int::{CastInto, DInt, HInt, Int}; diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index 540e7bdcfe301..c89f22756af70 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -181,7 +181,7 @@ where product_high += product_high & one; } - return F::from_repr(product_high); + F::from_repr(product_high) } intrinsics! { diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index 14e758fc5a8ff..391db765da471 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -1,5 +1,12 @@ // TODO: when `unsafe_block_in_unsafe_fn` is stabilized, remove this #![allow(unused_unsafe)] +// The functions are complex with many branches, and explicit +// `return`s makes it clear where function exit points are +#![allow(clippy::needless_return)] +#![allow(clippy::comparison_chain)] +// Clippy is confused by the complex configuration +#![allow(clippy::if_same_then_else)] +#![allow(clippy::needless_bool)] //! This `specialized_div_rem` module is originally from version 1.0.0 of the //! `specialized-div-rem` crate. Note that `for` loops with ranges are not used in this diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 9190c4251e548..efd63ff779520 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -17,6 +17,8 @@ // compiler on ABIs and such, so we should be "good enough" for now and changes // to the `u128` ABI will be reflected here. #![allow(improper_ctypes, improper_ctypes_definitions)] +// `mem::swap` cannot be used because it may generate references to memcpy in unoptimized code. +#![allow(clippy::manual_swap)] // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index 107762c43a6d9..03dc965ca4ac6 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -1,3 +1,6 @@ +// Trying to satisfy clippy here is hopeless +#![allow(clippy::style)] + #[allow(warnings)] #[cfg(target_pointer_width = "16")] type c_int = i16; From 9ae3728e5e85638453ebf81f3e08c5fd7a793be5 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Fri, 2 Apr 2021 09:24:00 -0500 Subject: [PATCH 0909/4206] fix CTFE cycle --- library/compiler-builtins/src/int/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index d8524a58a5e8c..2190a69b9d3de 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -84,7 +84,7 @@ pub trait Int: macro_rules! int_impl_common { ($ty:ty) => { - const BITS: u32 = ::BITS; + const BITS: u32 = ::ZERO.count_zeros(); const SIGNED: bool = Self::MIN != Self::ZERO; const ZERO: Self = 0; From 5221cef1fcd001128ced1900bef46c6a55f838e7 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Fri, 2 Apr 2021 09:35:01 -0500 Subject: [PATCH 0910/4206] Remove `rand` dependency, update `rand_xoshiro` --- library/compiler-builtins/testcrate/Cargo.toml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index ff9a6a453bba4..a066a11345aa8 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -8,14 +8,11 @@ edition = "2018" test = false doctest = false -[build-dependencies] -rand = "0.7" - [dependencies] # 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. # `xoshiro128**` is used for its quality, size, and speed at generating `u32` shift amounts. -rand_xoshiro = "0.4" +rand_xoshiro = "0.6" [dependencies.compiler_builtins] path = ".." From 2608f8392c0b36ccf6e61edcbc57e3e989875ccf Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 2 Apr 2021 20:31:08 +0100 Subject: [PATCH 0911/4206] Replace llvm_asm! with asm! --- .../compiler-builtins/examples/intrinsics.rs | 9 +- library/compiler-builtins/src/arm.rs | 188 +++++++++--------- library/compiler-builtins/src/lib.rs | 1 - library/compiler-builtins/src/x86.rs | 96 ++++----- library/compiler-builtins/src/x86_64.rs | 99 +++++---- 5 files changed, 194 insertions(+), 199 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 519cea2ae0ee2..ddbb976a252fd 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -6,7 +6,7 @@ #![allow(unused_features)] #![cfg_attr(thumb, no_main)] #![deny(dead_code)] -#![feature(llvm_asm)] +#![feature(test)] #![feature(lang_items)] #![feature(start)] #![feature(allocator_api)] @@ -276,14 +276,9 @@ mod intrinsics { } fn run() { + use core::hint::black_box as bb; use intrinsics::*; - // A copy of "test::black_box". Used to prevent LLVM from optimizing away the intrinsics during LTO - fn bb(dummy: T) -> T { - unsafe { llvm_asm!("" : : "r"(&dummy)) } - dummy - } - bb(aeabi_d2f(bb(2.))); bb(aeabi_d2i(bb(2.))); bb(aeabi_d2l(bb(2.))); diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 2b17b4f9613ef..545d6a17a45c5 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -9,135 +9,135 @@ use core::intrinsics; #[cfg(not(any(target_os = "ios", target_env = "msvc")))] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe fn __aeabi_uidivmod() { - llvm_asm!(" - push {lr} - sub sp, sp, #4 - mov r2, sp - bl __udivmodsi4 - ldr r1, [sp] - add sp, sp, #4 - pop {pc} - " ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn __aeabi_uidivmod() { + asm!( + "push {{lr}}", + "sub sp, sp, #4", + "mov r2, sp", + "bl __udivmodsi4", + "ldr r1, [sp]", + "add sp, sp, #4", + "pop {{pc}}", + options(noreturn) + ); } #[cfg(target_os = "ios")] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe fn __aeabi_uidivmod() { - llvm_asm!(" - push {lr} - sub sp, sp, #4 - mov r2, sp - bl ___udivmodsi4 - ldr r1, [sp] - add sp, sp, #4 - pop {pc} - " ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn __aeabi_uidivmod() { + asm!( + "push {{lr}}", + "sub sp, sp, #4", + "mov r2, sp", + "bl ___udivmodsi4", + "ldr r1, [sp]", + "add sp, sp, #4", + "pop {{pc}}", + options(noreturn) + ); } #[cfg(not(target_os = "ios"))] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe fn __aeabi_uldivmod() { - llvm_asm!(" - push {r4, lr} - sub sp, sp, #16 - add r4, sp, #8 - str r4, [sp] - bl __udivmoddi4 - ldr r2, [sp, #8] - ldr r3, [sp, #12] - add sp, sp, #16 - pop {r4, pc} - " ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn __aeabi_uldivmod() { + asm!( + "push {{r4, lr}}", + "sub sp, sp, #16", + "add r4, sp, #8", + "str r4, [sp]", + "bl __udivmoddi4", + "ldr r2, [sp, #8]", + "ldr r3, [sp, #12]", + "add sp, sp, #16", + "pop {{r4, pc}}", + options(noreturn) + ); } #[cfg(target_os = "ios")] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe fn __aeabi_uldivmod() { - llvm_asm!(" - push {r4, lr} - sub sp, sp, #16 - add r4, sp, #8 - str r4, [sp] - bl ___udivmoddi4 - ldr r2, [sp, #8] - ldr r3, [sp, #12] - add sp, sp, #16 - pop {r4, pc} - " ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn __aeabi_uldivmod() { + asm!( + "push {{r4, lr}}", + "sub sp, sp, #16", + "add r4, sp, #8", + "str r4, [sp]", + "bl ___udivmoddi4", + "ldr r2, [sp, #8]", + "ldr r3, [sp, #12]", + "add sp, sp, #16", + "pop {{r4, pc}}", + options(noreturn) + ); } #[cfg(not(target_os = "ios"))] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe fn __aeabi_idivmod() { - llvm_asm!(" - push {r0, r1, r4, lr} - bl __aeabi_idiv - pop {r1, r2} - muls r2, r2, r0 - subs r1, r1, r2 - pop {r4, pc} - " ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn __aeabi_idivmod() { + asm!( + "push {{r0, r1, r4, lr}}", + "bl __aeabi_idiv", + "pop {{r1, r2}}", + "muls r2, r2, r0", + "subs r1, r1, r2", + "pop {{r4, pc}}", + options(noreturn) + ); } #[cfg(target_os = "ios")] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe fn __aeabi_idivmod() { - llvm_asm!(" - push {r0, r1, r4, lr} - bl ___aeabi_idiv - pop {r1, r2} - muls r2, r2, r0 - subs r1, r1, r2 - pop {r4, pc} - " ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn __aeabi_idivmod() { + asm!( + "push {{r0, r1, r4, lr}}", + "bl ___aeabi_idiv", + "pop {{r1, r2}}", + "muls r2, r2, r0", + "subs r1, r1, r2", + "pop {{r4, pc}}", + options(noreturn) + ); } #[cfg(not(target_os = "ios"))] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe fn __aeabi_ldivmod() { - llvm_asm!(" - push {r4, lr} - sub sp, sp, #16 - add r4, sp, #8 - str r4, [sp] - bl __divmoddi4 - ldr r2, [sp, #8] - ldr r3, [sp, #12] - add sp, sp, #16 - pop {r4, pc} - " ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn __aeabi_ldivmod() { + asm!( + "push {{r4, lr}}", + "sub sp, sp, #16", + "add r4, sp, #8", + "str r4, [sp]", + "bl __divmoddi4", + "ldr r2, [sp, #8]", + "ldr r3, [sp, #12]", + "add sp, sp, #16", + "pop {{r4, pc}}", + options(noreturn) + ); } #[cfg(target_os = "ios")] #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe fn __aeabi_ldivmod() { - llvm_asm!(" - push {r4, lr} - sub sp, sp, #16 - add r4, sp, #8 - str r4, [sp] - bl ___divmoddi4 - ldr r2, [sp, #8] - ldr r3, [sp, #12] - add sp, sp, #16 - pop {r4, pc} - " ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn __aeabi_ldivmod() { + asm!( + "push {{r4, lr}}", + "sub sp, sp, #16", + "add r4, sp, #8", + "str r4, [sp]", + "bl ___divmoddi4", + "ldr r2, [sp, #8]", + "ldr r3, [sp, #12]", + "add sp, sp, #16", + "pop {{r4, pc}}", + options(noreturn) + ); } // The following functions use weak linkage to allow users to override diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 4a7c746a2ff54..1f93042e46190 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,7 +1,6 @@ #![cfg_attr(feature = "compiler-builtins", compiler_builtins)] #![cfg_attr(not(feature = "no-asm"), feature(asm))] #![feature(abi_unadjusted)] -#![cfg_attr(not(feature = "no-asm"), feature(llvm_asm))] #![cfg_attr(not(feature = "no-asm"), feature(global_asm))] #![feature(cfg_target_has_atomic)] #![feature(compiler_builtins)] diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs index e038231bb0e9b..4992de9da04bf 100644 --- a/library/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/src/x86.rs @@ -16,26 +16,27 @@ use core::intrinsics; ))] #[naked] #[no_mangle] -pub unsafe fn ___chkstk_ms() { - llvm_asm!(" - push %ecx - push %eax - cmp $$0x1000,%eax - lea 12(%esp),%ecx - jb 1f - 2: - sub $$0x1000,%ecx - test %ecx,(%ecx) - sub $$0x1000,%eax - cmp $$0x1000,%eax - ja 2b - 1: - sub %eax,%ecx - test %ecx,(%ecx) - pop %eax - pop %ecx - ret" ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn ___chkstk_ms() { + asm!( + "push %ecx", + "push %eax", + "cmp $0x1000,%eax", + "lea 12(%esp),%ecx", + "jb 1f", + "2:", + "sub $0x1000,%ecx", + "test %ecx,(%ecx)", + "sub $0x1000,%eax", + "cmp $0x1000,%eax", + "ja 2b", + "1:", + "sub %eax,%ecx", + "test %ecx,(%ecx)", + "pop %eax", + "pop %ecx", + "ret", + options(noreturn, att_syntax) + ); } // FIXME: __alloca should be an alias to __chkstk @@ -47,10 +48,11 @@ pub unsafe fn ___chkstk_ms() { ))] #[naked] #[no_mangle] -pub unsafe fn __alloca() { - llvm_asm!("jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable" - ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn __alloca() { + asm!( + "jmp ___chkstk", // Jump to ___chkstk since fallthrough may be unreliable" + options(noreturn, att_syntax) + ); } #[cfg(all( @@ -61,27 +63,27 @@ pub unsafe fn __alloca() { ))] #[naked] #[no_mangle] -pub unsafe fn ___chkstk() { - llvm_asm!(" - push %ecx - cmp $$0x1000,%eax - lea 8(%esp),%ecx // esp before calling this routine -> ecx - jb 1f - 2: - sub $$0x1000,%ecx - test %ecx,(%ecx) - sub $$0x1000,%eax - cmp $$0x1000,%eax - ja 2b - 1: - sub %eax,%ecx - test %ecx,(%ecx) - - lea 4(%esp),%eax // load pointer to the return address into eax - mov %ecx,%esp // install the new top of stack pointer into esp - mov -4(%eax),%ecx // restore ecx - push (%eax) // push return address onto the stack - sub %esp,%eax // restore the original value in eax - ret" ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn ___chkstk() { + asm!( + "push %ecx", + "cmp $0x1000,%eax", + "lea 8(%esp),%ecx", // esp before calling this routine -> ecx + "jb 1f", + "2:", + "sub $0x1000,%ecx", + "test %ecx,(%ecx)", + "sub $0x1000,%eax", + "cmp $0x1000,%eax", + "ja 2b", + "1:", + "sub %eax,%ecx", + "test %ecx,(%ecx)", + "lea 4(%esp),%eax", // load pointer to the return address into eax + "mov %ecx,%esp", // install the new top of stack pointer into esp + "mov -4(%eax),%ecx", // restore ecx + "push (%eax)", // push return address onto the stack + "sub %esp,%eax", // restore the original value in eax + "ret", + options(noreturn, att_syntax) + ); } diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 91c0f24fca6d9..b382b886c5532 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -16,26 +16,27 @@ use core::intrinsics; ))] #[naked] #[no_mangle] -pub unsafe fn ___chkstk_ms() { - llvm_asm!(" - push %rcx - push %rax - cmp $$0x1000,%rax - lea 24(%rsp),%rcx - jb 1f - 2: - sub $$0x1000,%rcx - test %rcx,(%rcx) - sub $$0x1000,%rax - cmp $$0x1000,%rax - ja 2b - 1: - sub %rax,%rcx - test %rcx,(%rcx) - pop %rax - pop %rcx - ret" ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn ___chkstk_ms() { + asm!( + "push %rcx", + "push %rax", + "cmp $0x1000,%rax", + "lea 24(%rsp),%rcx", + "jb 1f", + "2:", + "sub $0x1000,%rcx", + "test %rcx,(%rcx)", + "sub $0x1000,%rax", + "cmp $0x1000,%rax", + "ja 2b", + "1:", + "sub %rax,%rcx", + "test %rcx,(%rcx)", + "pop %rax", + "pop %rcx", + "ret", + options(noreturn, att_syntax) + ); } #[cfg(all( @@ -46,11 +47,12 @@ pub unsafe fn ___chkstk_ms() { ))] #[naked] #[no_mangle] -pub unsafe fn __alloca() { - llvm_asm!("mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx - jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable" - ::: "memory" : "volatile"); - intrinsics::unreachable(); +pub unsafe extern "C" fn __alloca() { + asm!( + "mov %rcx,%rax", // x64 _alloca is a normal function with parameter in rcx + "jmp ___chkstk", // Jump to ___chkstk since fallthrough may be unreliable" + options(noreturn, att_syntax) + ); } #[cfg(all( @@ -61,32 +63,29 @@ pub unsafe fn __alloca() { ))] #[naked] #[no_mangle] -pub unsafe fn ___chkstk() { - llvm_asm!( - " - push %rcx - cmp $$0x1000,%rax - lea 16(%rsp),%rcx // rsp before calling this routine -> rcx - jb 1f - 2: - sub $$0x1000,%rcx - test %rcx,(%rcx) - sub $$0x1000,%rax - cmp $$0x1000,%rax - ja 2b - 1: - sub %rax,%rcx - test %rcx,(%rcx) - - lea 8(%rsp),%rax // load pointer to the return address into rax - mov %rcx,%rsp // install the new top of stack pointer into rsp - mov -8(%rax),%rcx // restore rcx - push (%rax) // push return address onto the stack - sub %rsp,%rax // restore the original value in rax - ret" - ::: "memory" : "volatile" +pub unsafe extern "C" fn ___chkstk() { + asm!( + "push %rcx", + "cmp $0x1000,%rax", + "lea 16(%rsp),%rcx", // rsp before calling this routine -> rcx + "jb 1f", + "2:", + "sub $0x1000,%rcx", + "test %rcx,(%rcx)", + "sub $0x1000,%rax", + "cmp $0x1000,%rax", + "ja 2b", + "1:", + "sub %rax,%rcx", + "test %rcx,(%rcx)", + "lea 8(%rsp),%rax", // load pointer to the return address into rax + "mov %rcx,%rsp", // install the new top of stack pointer into rsp + "mov -8(%rax),%rcx", // restore rcx + "push (%rax)", // push return address onto the stack + "sub %rsp,%rax", // restore the original value in rax + "ret", + options(noreturn, att_syntax) ); - intrinsics::unreachable(); } // HACK(https://github.com/rust-lang/rust/issues/62785): x86_64-unknown-uefi needs special LLVM From 500c8e0b2c055d20b8d43f6778e7f86398a9071e Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Fri, 2 Apr 2021 09:44:10 -0500 Subject: [PATCH 0912/4206] add clippy to CI --- .../.github/workflows/main.yml | 18 ++++++++++++++++-- library/compiler-builtins/src/int/mod.rs | 2 ++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 01dffb8451ef5..6e2d83879a266 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -109,6 +109,20 @@ jobs: - uses: actions/checkout@v1 with: submodules: true - - name: Install Rust - run: rustup update stable && rustup default stable && rustup component add rustfmt + - name: Install stable `rustfmt` + run: rustup set profile minimal && rustup default stable && rustup component add rustfmt - run: cargo fmt -- --check + + clippy: + name: Clippy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + with: + submodules: true + # Unlike rustfmt, stable clippy does not work on code with nightly features. + # This acquires the most recent nightly with a clippy component. + - name: Install nightly `clippy` + run: | + rustup set profile minimal && rustup default "nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/clippy)" && rustup component add clippy + - run: cargo clippy -- -D clippy::all diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 2190a69b9d3de..080a415de34d9 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -210,6 +210,8 @@ macro_rules! int_impl { self } + // It makes writing macros easier if this is implemented for both signed and unsigned + #[allow(clippy::wrong_self_convention)] fn from_unsigned(me: $uty) -> Self { me } From 6cd2f3ae40c60bb7bbd546d2470a10c97b4b8b34 Mon Sep 17 00:00:00 2001 From: messense Date: Wed, 24 Mar 2021 13:49:12 +0800 Subject: [PATCH 0913/4206] Add compiler-rt fallbacks on mips64-musl --- library/compiler-builtins/build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index f948edba9eb2f..701c4d4950b06 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -449,6 +449,8 @@ mod c { ("__fixunstfsi", "fixunstfsi.c"), ("__floatunsitf", "floatunsitf.c"), ("__fe_getround", "fp_mode.c"), + ("__divtf3", "divtf3.c"), + ("__trunctfdf2", "trunctfdf2.c"), ]); } From 8c4127d044a78179f24f92b80133694b5c3a2a47 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Sat, 3 Apr 2021 18:57:16 +0100 Subject: [PATCH 0914/4206] Add `#[linkage = "weak"]` attribute to all `mem` instrinics. --- library/compiler-builtins/src/mem/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index 03dc965ca4ac6..3d7372c8273c4 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -20,12 +20,14 @@ use core::ops::{BitOr, Shl}; mod impls; #[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +#[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { impls::copy_forward(dest, src, n); dest } #[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +#[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { let delta = (dest as usize).wrapping_sub(src as usize); if delta >= n { @@ -39,12 +41,14 @@ pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mu } #[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +#[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { impls::set_bytes(s, c as u8, n); s } #[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +#[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { let mut i = 0; while i < n { @@ -59,6 +63,7 @@ pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { } #[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] +#[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { memcmp(s1, s2, n) } From 5dd043525adbd1db4519874afa800a62f1fc31d2 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 10 Apr 2021 16:03:19 +0200 Subject: [PATCH 0915/4206] Fix typo --- library/compiler-builtins/src/arm.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 545d6a17a45c5..82c41fc5a1067 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -2,8 +2,8 @@ use core::intrinsics; -// NOTE This function and the ones below are implemented using assembly because they using a custom -// calling convention which can't be implemented using a normal Rust function. +// NOTE This function and the ones below are implemented using assembly because they are using a +// custom calling convention which can't be implemented using a normal Rust function. // NOTE The only difference between the iOS and non-iOS versions of those functions is that the iOS // versions use 3 leading underscores in the names of called functions instead of 2. #[cfg(not(any(target_os = "ios", target_env = "msvc")))] From 68df0eb8178799c4b032d3c375528918412cd4e5 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 10 Apr 2021 19:13:02 +0100 Subject: [PATCH 0916/4206] Mark global_asm! code with .att_syntax global_asm! will soon change to use Intel syntax by default. --- library/compiler-builtins/src/probestack.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index ac3ae1ebbc4af..6892ab2d3eaa2 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -48,6 +48,8 @@ #![cfg(not(feature = "no-asm"))] // We only define stack probing for these architectures today. #![cfg(any(target_arch = "x86_64", target_arch = "x86"))] +// We need to add .att_syntax for bootstraping the new global_asm! +#![allow(unknown_lints, bad_asm_style)] extern "C" { pub fn __rust_probestack(); @@ -63,6 +65,7 @@ macro_rules! define_rust_probestack { ($body: expr) => { concat!( " + .att_syntax .pushsection .text.__rust_probestack .globl __rust_probestack .type __rust_probestack, @function From 79916f0ac8155d9a0174490d3df690427fe4be52 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 11 Apr 2021 20:56:38 +0100 Subject: [PATCH 0917/4206] Bump to 0.1.40 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index f1052d59d6784..8d0c05084aaea 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.39" +version = "0.1.40" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 189b987a250b05dd1628c5cf8703bc88223e3ada Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 23 Apr 2021 18:54:12 +0100 Subject: [PATCH 0918/4206] Revert "Disable AArch64 FP-to-int tests" This reverts commit 9e76b9115fa9571501d378b6329ce557266908b7. --- library/compiler-builtins/testcrate/tests/conv.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 17c31a8a00e5b..7cdbf9fbb69e0 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -95,8 +95,6 @@ macro_rules! f_to_i { }; } -// AArch64 tests are currently broken due to https://github.com/rust-lang/rust/issues/83467 -#[cfg(not(target_arch = "aarch64"))] #[test] fn float_to_int() { use compiler_builtins::float::conv::{ From 61b2242af9c7cd48e65cacd781afdcff29297349 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 30 Apr 2021 19:15:53 +0100 Subject: [PATCH 0919/4206] Fix CI on latest nightly --- library/compiler-builtins/examples/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index ddbb976a252fd..dfa46b1b8fed4 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -6,7 +6,7 @@ #![allow(unused_features)] #![cfg_attr(thumb, no_main)] #![deny(dead_code)] -#![feature(test)] +#![feature(bench_black_box)] #![feature(lang_items)] #![feature(start)] #![feature(allocator_api)] From 5edaec6c970c92f5613021032790ea65037014ca Mon Sep 17 00:00:00 2001 From: George Burgess IV Date: Tue, 2 Mar 2021 15:50:09 -0800 Subject: [PATCH 0920/4206] add support for building outlined aarch64 intrinsics llvm/llvm-project@a4ac434c47434d80bca54bab96f295ed4e972cc6 saw the addition of out-of-line aarch64 atomic intrinsics. LLVM will sometimes emit these, so we need to ensure they're included in Rust's compiler-rt. --- library/compiler-builtins/build.rs | 71 +++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 701c4d4950b06..2ff6443d7deac 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -81,7 +81,7 @@ mod c { use std::collections::BTreeMap; use std::env; - use std::path::PathBuf; + use std::path::{Path, PathBuf}; struct Sources { // SYMBOL -> PATH TO SOURCE @@ -489,7 +489,20 @@ mod c { // use of that macro in lib/builtins/int_util.h in compiler-rt. cfg.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. let src_dir = root.join("lib/builtins"); + if target_arch == "aarch64" { + let atomics_libs = build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg); + if !atomics_libs.is_empty() { + for library in atomics_libs { + cfg.object(library); + } + // Some run-time CPU feature detection is necessary, as well. + sources.extend(&[("__aarch64_have_lse_atomics", "cpu_model.c")]); + } + } + for (sym, src) in sources.map.iter() { let src = src_dir.join(src); cfg.file(&src); @@ -499,4 +512,60 @@ mod c { cfg.compile("libcompiler-rt.a"); } + + fn build_aarch64_out_of_line_atomics_libraries( + builtins_dir: &Path, + cfg: &cc::Build, + ) -> Vec { + // NOTE: because we're recompiling the same source file in N different ways, building + // serially is necessary. If we want to lift this restriction, we can either: + // - create symlinks to lse.S and build those_(though we'd still need to pass special + // #define-like flags to each of these), or + // - synthesizing tiny .S files in out/ with the proper #defines, which ultimately #include + // lse.S. + // That said, it's unclear how useful this added complexity will be, so just do the simple + // thing for now. + let outlined_atomics_file = builtins_dir.join("aarch64/lse.S"); + + // A stable release hasn't been made with lse.S yet. Until we pick that up, do nothing. + if !outlined_atomics_file.exists() { + return vec![]; + } + + println!("cargo:rerun-if-changed={}", outlined_atomics_file.display()); + let out_dir: PathBuf = env::var("OUT_DIR").unwrap().into(); + + // Ideally, this would be a Vec of object files, but cc doesn't make it *entirely* + // trivial to build an individual object. + let mut atomics_libraries = Vec::new(); + for instruction_type in &["cas", "cwp", "ldadd", "ldclr", "ldeor", "ldset"] { + for size in &[1, 2, 4, 8, 16] { + if *size == 16 && *instruction_type != "cas" { + continue; + } + + for (model_number, model_name) in + &[(1, "relax"), (2, "acq"), (3, "rel"), (4, "acq_rel")] + { + let library_name = format!( + "liboutline_atomic_helper_{}_{}_{}.a", + instruction_type, size, model_name + ); + let sym = format!("__aarch64_{}{}_{}", instruction_type, size, model_name); + let mut cfg = cfg.clone(); + + cfg.include(&builtins_dir) + .define(&format!("L_{}", instruction_type), None) + .define("SIZE", size.to_string().as_str()) + .define("MODEL", model_number.to_string().as_str()) + .file(&outlined_atomics_file); + cfg.compile(&library_name); + + atomics_libraries.push(out_dir.join(library_name)); + println!("cargo:rustc-cfg={}=\"optimized-c\"", sym); + } + } + } + atomics_libraries + } } From b9da06f662b5fe013b2601550b81ba9ad22e87b1 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 30 Apr 2021 02:38:39 -0700 Subject: [PATCH 0921/4206] Fix typo in instruction name: s/cwp/swp/ --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 2ff6443d7deac..26296db0c84b2 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -538,7 +538,7 @@ mod c { // Ideally, this would be a Vec of object files, but cc doesn't make it *entirely* // trivial to build an individual object. let mut atomics_libraries = Vec::new(); - for instruction_type in &["cas", "cwp", "ldadd", "ldclr", "ldeor", "ldset"] { + for instruction_type in &["cas", "swp", "ldadd", "ldclr", "ldeor", "ldset"] { for size in &[1, 2, 4, 8, 16] { if *size == 16 && *instruction_type != "cas" { continue; From df8e6f179a7f9045464617a8ce7d23bc7c90bfe1 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 30 Apr 2021 02:39:07 -0700 Subject: [PATCH 0922/4206] Require lse.S (now available in current LLVM) --- library/compiler-builtins/build.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 26296db0c84b2..2178dc9353c1a 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -526,13 +526,8 @@ mod c { // That said, it's unclear how useful this added complexity will be, so just do the simple // thing for now. let outlined_atomics_file = builtins_dir.join("aarch64/lse.S"); - - // A stable release hasn't been made with lse.S yet. Until we pick that up, do nothing. - if !outlined_atomics_file.exists() { - return vec![]; - } - println!("cargo:rerun-if-changed={}", outlined_atomics_file.display()); + let out_dir: PathBuf = env::var("OUT_DIR").unwrap().into(); // Ideally, this would be a Vec of object files, but cc doesn't make it *entirely* From 79c1e33364b002391584a35281d2862c1209efec Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 30 Apr 2021 02:41:44 -0700 Subject: [PATCH 0923/4206] Make the name of the intermediate library more closely match the intrinsic --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 2178dc9353c1a..3ba6d5883f25a 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -543,7 +543,7 @@ mod c { &[(1, "relax"), (2, "acq"), (3, "rel"), (4, "acq_rel")] { let library_name = format!( - "liboutline_atomic_helper_{}_{}_{}.a", + "liboutline_atomic_helper_{}{}_{}.a", instruction_type, size, model_name ); let sym = format!("__aarch64_{}{}_{}", instruction_type, size, model_name); From fee637a7b6366200952775abe399eafb404a8a7b Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 30 Apr 2021 12:24:12 -0700 Subject: [PATCH 0924/4206] Update the version of compiler-rt in CI --- library/compiler-builtins/.github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 6e2d83879a266..3d63bc070cda5 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -88,8 +88,8 @@ jobs: - run: rustup component add llvm-tools-preview - name: Download compiler-rt reference sources run: | - curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/10.0-2020-05-05.tar.gz - tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-10.0-2020-05-05/compiler-rt + curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/12.0-2021-04-15.tar.gz + tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-12.0-2021-04-15/compiler-rt echo RUST_COMPILER_RT_ROOT=./compiler-rt >> $GITHUB_ENV shell: bash From a77e15f562fca6e2646e44726e32ec5703fef75b Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 30 Apr 2021 21:03:06 +0100 Subject: [PATCH 0925/4206] Bump to 0.1.41 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 8d0c05084aaea..c59f787288252 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.40" +version = "0.1.41" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From fdbeb187ec5239d73798ddb87f17b506c3816757 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 2 May 2021 21:29:00 +0100 Subject: [PATCH 0926/4206] Add missing .att_syntax from #414 --- library/compiler-builtins/src/probestack.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 6892ab2d3eaa2..4d6cd694943a4 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -86,6 +86,7 @@ macro_rules! define_rust_probestack { ($body: expr) => { concat!( " + .att_syntax .globl __rust_probestack __rust_probestack: ", @@ -101,6 +102,7 @@ macro_rules! define_rust_probestack { ($body: expr) => { concat!( " + .att_syntax .globl ___rust_probestack ___rust_probestack: ", @@ -115,6 +117,7 @@ macro_rules! define_rust_probestack { ($body: expr) => { concat!( " + .att_syntax .globl ___rust_probestack ___rust_probestack: ", From fcf675bf4a6d80500525655ad0a567f44fd0d84d Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 2 May 2021 22:12:49 +0100 Subject: [PATCH 0927/4206] Bump to 0.1.42 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index c59f787288252..0f5faebac4475 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.41" +version = "0.1.42" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 1630c86e0761d9c9772cdc9dda28ad7a0e06581b Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 13 May 2021 21:35:34 +0100 Subject: [PATCH 0928/4206] Don't embed lse_*.a inside another static library --- library/compiler-builtins/build.rs | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 3ba6d5883f25a..297a0adff05fe 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -493,14 +493,11 @@ mod c { // sets of flags to the same source file. let src_dir = root.join("lib/builtins"); if target_arch == "aarch64" { - let atomics_libs = build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg); - if !atomics_libs.is_empty() { - for library in atomics_libs { - cfg.object(library); - } - // Some run-time CPU feature detection is necessary, as well. - sources.extend(&[("__aarch64_have_lse_atomics", "cpu_model.c")]); - } + // See below for why we're building these as separate libraries. + build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg); + + // Some run-time CPU feature detection is necessary, as well. + sources.extend(&[("__aarch64_have_lse_atomics", "cpu_model.c")]); } for (sym, src) in sources.map.iter() { @@ -513,10 +510,7 @@ mod c { cfg.compile("libcompiler-rt.a"); } - fn build_aarch64_out_of_line_atomics_libraries( - builtins_dir: &Path, - cfg: &cc::Build, - ) -> Vec { + fn build_aarch64_out_of_line_atomics_libraries(builtins_dir: &Path, cfg: &cc::Build) { // NOTE: because we're recompiling the same source file in N different ways, building // serially is necessary. If we want to lift this restriction, we can either: // - create symlinks to lse.S and build those_(though we'd still need to pass special @@ -528,11 +522,8 @@ mod c { let outlined_atomics_file = builtins_dir.join("aarch64/lse.S"); println!("cargo:rerun-if-changed={}", outlined_atomics_file.display()); - let out_dir: PathBuf = env::var("OUT_DIR").unwrap().into(); - // Ideally, this would be a Vec of object files, but cc doesn't make it *entirely* // trivial to build an individual object. - let mut atomics_libraries = Vec::new(); for instruction_type in &["cas", "swp", "ldadd", "ldclr", "ldeor", "ldset"] { for size in &[1, 2, 4, 8, 16] { if *size == 16 && *instruction_type != "cas" { @@ -556,11 +547,9 @@ mod c { .file(&outlined_atomics_file); cfg.compile(&library_name); - atomics_libraries.push(out_dir.join(library_name)); println!("cargo:rustc-cfg={}=\"optimized-c\"", sym); } } } - atomics_libraries } } From 924d71851160705925f23e3398f2f327f4043efc Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 13 May 2021 21:41:46 +0100 Subject: [PATCH 0929/4206] Bump to 0.1.43 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 0f5faebac4475..f5ba632a031fb 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.42" +version = "0.1.43" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From c041104afd529680657fb10734062579b4c4c71f Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 26 May 2021 12:22:52 +0900 Subject: [PATCH 0930/4206] Suppress some warnings --- library/compiler-builtins/src/arm.rs | 1 + library/compiler-builtins/src/mem/mod.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 82c41fc5a1067..7203d91e4a9d3 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -1,4 +1,5 @@ #![cfg(not(feature = "no-asm"))] +#![allow(unused_imports)] use core::intrinsics; diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index 3d7372c8273c4..2f9a9fd945eac 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -69,6 +69,7 @@ pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { } // `bytes` must be a multiple of `mem::size_of::()` +#[cfg_attr(not(target_has_atomic_load_store = "8"), allow(dead_code))] fn memcpy_element_unordered_atomic(dest: *mut T, src: *const T, bytes: usize) { unsafe { let n = exact_div(bytes, mem::size_of::()); @@ -81,6 +82,7 @@ fn memcpy_element_unordered_atomic(dest: *mut T, src: *const T, bytes: } // `bytes` must be a multiple of `mem::size_of::()` +#[cfg_attr(not(target_has_atomic_load_store = "8"), allow(dead_code))] fn memmove_element_unordered_atomic(dest: *mut T, src: *const T, bytes: usize) { unsafe { let n = exact_div(bytes, mem::size_of::()); @@ -103,6 +105,7 @@ fn memmove_element_unordered_atomic(dest: *mut T, src: *const T, bytes: } // `T` must be a primitive integer type, and `bytes` must be a multiple of `mem::size_of::()` +#[cfg_attr(not(target_has_atomic_load_store = "8"), allow(dead_code))] fn memset_element_unordered_atomic(s: *mut T, c: u8, bytes: usize) where T: Copy + From + Shl + BitOr, From 31e3ae708c51e42f3e13043fa11c2ec13ce9df8b Mon Sep 17 00:00:00 2001 From: Tilmann Meyer Date: Mon, 31 May 2021 16:32:46 +0200 Subject: [PATCH 0931/4206] Include Linux atomic emulation on androideabi The old androideabi uses armv5 and thus also needs the atomic emulation and because Android is basically Linux it can use the same implementation. --- library/compiler-builtins/build.rs | 7 +++++-- library/compiler-builtins/src/lib.rs | 6 +++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 297a0adff05fe..0fb1e17bebcba 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -69,8 +69,11 @@ fn main() { println!("cargo:rustc-cfg=thumb_1") } - // Only emit the ARM Linux atomic emulation on pre-ARMv6 architectures. - if llvm_target[0] == "armv4t" || llvm_target[0] == "armv5te" { + // 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" || llvm_target[0] == "armv5te" || llvm_target[2] == "androideabi" + { println!("cargo:rustc-cfg=kernel_user_helpers") } } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index facdf946f6b2e..21796ca55411f 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -49,7 +49,11 @@ pub mod mem; #[cfg(target_arch = "arm")] pub mod arm; -#[cfg(all(kernel_user_helpers, target_os = "linux", target_arch = "arm"))] +#[cfg(all( + kernel_user_helpers, + any(target_os = "linux", target_os = "android"), + target_arch = "arm" +))] pub mod arm_linux; #[cfg(any(target_arch = "riscv32"))] From bc956a76952d4e2418b30e0e8da18e1c36999d91 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 1 Jun 2021 19:08:32 +0100 Subject: [PATCH 0932/4206] Bump to 0.1.44 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index f5ba632a031fb..5c917fc6838fc 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.43" +version = "0.1.44" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From fdcc30c3a386a5753cbbf898c9d6a68d10421c64 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Wed, 2 Jun 2021 13:11:28 -0500 Subject: [PATCH 0933/4206] Add public-test-deps feature for better visibility control --- library/compiler-builtins/Cargo.toml | 4 ++++ library/compiler-builtins/src/float/mod.rs | 5 +++-- .../src/int/leading_zeros.rs | 10 ++++++---- library/compiler-builtins/src/int/mod.rs | 20 +++++++++++-------- .../src/int/specialized_div_rem/asymmetric.rs | 3 +-- .../int/specialized_div_rem/binary_long.rs | 3 +-- .../src/int/specialized_div_rem/delegate.rs | 10 ++++++---- .../src/int/specialized_div_rem/mod.rs | 7 +++++++ .../src/int/specialized_div_rem/norm_shift.rs | 3 +-- .../src/int/specialized_div_rem/trifecta.rs | 3 +-- library/compiler-builtins/src/int/udiv.rs | 7 +++++-- library/compiler-builtins/src/macros.rs | 16 +++++++++++++++ .../compiler-builtins/testcrate/Cargo.toml | 2 +- 13 files changed, 64 insertions(+), 29 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index f5ba632a031fb..e1f5cbf8fea32 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -64,6 +64,10 @@ no-lang-items = [] # Only used in the compiler's build system rustc-dep-of-std = ['compiler-builtins', 'core'] +# This makes certain traits and function specializations public that +# are not normally public but are required by the `testcrate` +public-test-deps = [] + [[example]] name = "intrinsics" required-features = ["compiler-builtins"] diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 69e4dc6351711..11680e7a9fa3f 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -11,9 +11,9 @@ pub mod mul; pub mod pow; pub mod sub; +public_test_dep! { /// Trait for some basic operations on floats -#[doc(hidden)] -pub trait Float: +pub(crate) trait Float: Copy + core::fmt::Debug + PartialEq @@ -99,6 +99,7 @@ pub trait Float: /// 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) => { diff --git a/library/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/src/int/leading_zeros.rs index e4a9e5eb2b497..0265b9a9d021b 100644 --- a/library/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/src/int/leading_zeros.rs @@ -3,9 +3,9 @@ // adding a zero check at the beginning, but `__clzsi2` has a precondition that `x != 0`. // Compilers will insert the check for zero in cases where it is needed. +public_test_dep! { /// Returns the number of leading binary zeros in `x`. -#[doc(hidden)] -pub fn usize_leading_zeros_default(x: usize) -> usize { +pub(crate) fn usize_leading_zeros_default(x: usize) -> usize { // The basic idea is to test if the higher bits of `x` are zero and bisect the number // of leading zeros. It is possible for all branches of the bisection to use the same // code path by conditionally shifting the higher parts down to let the next bisection @@ -69,15 +69,16 @@ pub fn usize_leading_zeros_default(x: usize) -> usize { // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO // execution effects. Changing to using a LUT and branching is risky for smaller cores. } +} // The above method does not compile well on RISC-V (because of the lack of predicated // instructions), producing code with many branches or using an excessively long // branchless solution. This method takes advantage of the set-if-less-than instruction on // RISC-V that allows `(x >= power-of-two) as usize` to be branchless. +public_test_dep! { /// Returns the number of leading binary zeros in `x`. -#[doc(hidden)] -pub fn usize_leading_zeros_riscv(x: usize) -> usize { +pub(crate) fn usize_leading_zeros_riscv(x: usize) -> usize { let mut x = x; // the number of potential leading zeros let mut z = usize::MAX.count_ones() as usize; @@ -126,6 +127,7 @@ pub fn usize_leading_zeros_riscv(x: usize) -> usize { // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. z - x } +} intrinsics! { #[maybe_use_optimized_c_shim] diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 080a415de34d9..509f9fdae395a 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -11,9 +11,9 @@ pub mod udiv; pub use self::leading_zeros::__clzsi2; +public_test_dep! { /// Trait for some basic operations on integers -#[doc(hidden)] -pub trait Int: +pub(crate) trait Int: Copy + core::fmt::Debug + PartialEq @@ -81,6 +81,7 @@ pub trait Int: fn overflowing_add(self, other: Self) -> (Self, bool); fn leading_zeros(self) -> u32; } +} macro_rules! int_impl_common { ($ty:ty) => { @@ -255,10 +256,10 @@ int_impl!(i32, u32); int_impl!(i64, u64); int_impl!(i128, u128); +public_test_dep! { /// 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. -#[doc(hidden)] -pub trait DInt: Int { +pub(crate) trait DInt: Int { /// Integer that is half the bit width of the integer this trait is implemented for type H: HInt + Int; @@ -271,11 +272,12 @@ pub trait DInt: Int { /// Constructs an integer using lower and higher half parts fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self; } +} +public_test_dep! { /// 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. -#[doc(hidden)] -pub trait HInt: Int { +pub(crate) trait HInt: Int { /// Integer that is double the bit width of the integer this trait is implemented for type D: DInt + Int; @@ -291,6 +293,7 @@ pub trait HInt: Int { /// Widening multiplication. This cannot overflow. fn widen_mul(self, rhs: Self) -> Self::D; } +} macro_rules! impl_d_int { ($($X:ident $D:ident),*) => { @@ -353,11 +356,12 @@ impl_h_int!( i64 u64 i128 ); +public_test_dep! { /// Trait to express (possibly lossy) casting of integers -#[doc(hidden)] -pub trait CastInto: Copy { +pub(crate) trait CastInto: Copy { fn cast(self) -> T; } +} macro_rules! cast_into { ($ty:ty) => { diff --git a/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs b/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs index 45da657e9c974..56ce188a37378 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs @@ -3,8 +3,7 @@ /// assembly instruction that can divide a 128 bit integer by a 64 bit integer if the quotient fits /// in 64 bits. The 128 bit version of this algorithm would use that fast hardware division to /// construct a full 128 bit by 128 bit division. -#[doc(hidden)] -#[macro_export] +#[allow(unused_macros)] macro_rules! impl_asymmetric { ( $fn:ident, // name of the unsigned division function diff --git a/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs b/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs index 7de10e8527691..0d7822882b060 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs @@ -4,8 +4,7 @@ /// predicate instructions. For architectures with predicated instructions, one of the algorithms /// described in the documentation of these functions probably has higher performance, and a custom /// assembly routine should be used instead. -#[doc(hidden)] -#[macro_export] +#[allow(unused_macros)] macro_rules! impl_binary_long { ( $fn:ident, // name of the unsigned division function diff --git a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs index 135d3402a3af7..330c6e4f80bb7 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs @@ -2,8 +2,7 @@ /// binary long division to divide integers larger than what hardware division by itself can do. This /// function is intended for microarchitectures that have division hardware, but not fast enough /// multiplication hardware for `impl_trifecta` to be faster. -#[doc(hidden)] -#[macro_export] +#[allow(unused_macros)] macro_rules! impl_delegate { ( $fn:ident, // name of the unsigned division function @@ -186,6 +185,7 @@ macro_rules! impl_delegate { }; } +public_test_dep! { /// Returns `n / d` and sets `*rem = n % d`. /// /// This specialization exists because: @@ -193,8 +193,9 @@ macro_rules! impl_delegate { /// so we have to use an old fashioned `&mut u128` argument to return the remainder. /// - 64-bit SPARC does not have u64 * u64 => u128 widening multiplication, which makes the /// delegate algorithm strategy the only reasonably fast way to perform `u128` division. -#[doc(hidden)] -pub fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { +// used on SPARC +#[allow(dead_code)] +pub(crate) fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { use super::*; let duo_lo = duo as u64; let duo_hi = (duo >> 64) as u64; @@ -315,3 +316,4 @@ pub fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { } } } +} diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index 391db765da471..f5b2af235bd26 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -53,6 +53,13 @@ mod binary_long; #[macro_use] mod delegate; + +// used on SPARC +#[allow(unused_imports)] +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use self::delegate::u128_divide_sparc; + +#[cfg(feature = "public-test-deps")] pub use self::delegate::u128_divide_sparc; #[macro_use] diff --git a/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs b/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs index be95d1b927ee1..61b67b6bc3dc1 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs @@ -1,6 +1,5 @@ /// Creates a function used by some division algorithms to compute the "normalization shift". -#[doc(hidden)] -#[macro_export] +#[allow(unused_macros)] macro_rules! impl_normalization_shift { ( $name:ident, // name of the normalization shift function diff --git a/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs b/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs index a9ea603019d82..7e104053b8b9e 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs @@ -2,8 +2,7 @@ /// larger than the largest hardware integer division supported. These functions use large radix /// division algorithms that require both fast division and very fast widening multiplication on the /// target microarchitecture. Otherwise, `impl_delegate` should be used instead. -#[doc(hidden)] -#[macro_export] +#[allow(unused_macros)] macro_rules! impl_trifecta { ( $fn:ident, // name of the unsigned division function diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index d971780784999..2f236346d3dd7 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -1,5 +1,8 @@ -pub use int::specialized_div_rem::u128_divide_sparc; -use int::specialized_div_rem::*; +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use int::specialized_div_rem::*; + +#[cfg(feature = "public-test-deps")] +pub use int::specialized_div_rem::*; intrinsics! { #[maybe_use_optimized_c_shim] diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 56f27164a9399..214f0795fc543 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -1,5 +1,21 @@ //! Macros shared throughout the compiler-builtins implementation +/// Changes the visibility to `pub` if feature "public-test-deps" is set +#[cfg(not(feature = "public-test-deps"))] +macro_rules! public_test_dep { + ($(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*) => { + $(#[$($meta)*])* pub(crate) $ident $($tokens)* + }; +} + +/// Changes the visibility to `pub` if feature "public-test-deps" is set +#[cfg(feature = "public-test-deps")] +macro_rules! public_test_dep { + {$(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*} => { + $(#[$($meta)*])* pub $ident $($tokens)* + }; +} + /// The "main macro" used for defining intrinsics. /// /// The compiler-builtins library is super platform-specific with tons of crazy diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index a066a11345aa8..1f77b255491a4 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -17,7 +17,7 @@ rand_xoshiro = "0.6" [dependencies.compiler_builtins] path = ".." default-features = false -features = ["no-lang-items"] +features = ["no-lang-items", "public-test-deps"] [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" } From 77d9a28bbb6df8449a926b748044ee923b6aa75c Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 3 Jun 2021 22:59:34 +0100 Subject: [PATCH 0934/4206] Fix build on targets with fewer than 3 components in their name --- library/compiler-builtins/build.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 0fb1e17bebcba..f0617b6e92a10 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -72,7 +72,9 @@ 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" || llvm_target[0] == "armv5te" || llvm_target[2] == "androideabi" + if llvm_target[0] == "armv4t" + || llvm_target[0] == "armv5te" + || llvm_target.get(2) == Some(&"androideabi") { println!("cargo:rustc-cfg=kernel_user_helpers") } From bca8bedb939369b7a462ea83067920fc75510d5c Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 4 Jun 2021 00:20:57 +0100 Subject: [PATCH 0935/4206] Bump to 0.1.45 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index f5d450938a62e..2dd5a61ebf221 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.44" +version = "0.1.45" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From a9c912c42f92679abde009987552dadb9dc29725 Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Thu, 24 Jun 2021 15:58:36 +0200 Subject: [PATCH 0936/4206] Fix build failure with latest nightly --- library/compiler-builtins/libm/src/math/pow.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index c7fd0dfa11760..f79680a05d015 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -604,7 +604,7 @@ mod tests { // Factoring -1 out: // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer)) - &[POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS] + (&[POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS]) .iter() .for_each(|int_set| { int_set.iter().for_each(|int| { @@ -616,7 +616,7 @@ mod tests { // Negative base (imaginary results): // (-anything except 0 and Infinity ^ non-integer should be NAN) - &NEG[1..(NEG.len() - 1)].iter().for_each(|set| { + (&NEG[1..(NEG.len() - 1)]).iter().for_each(|set| { set.iter().for_each(|val| { test_sets(&ALL[3..7], &|v: f64| pow(*val, v), &|_| NAN); }) From eedfb239a35e1b2e0cf30c96776f3fe7b9f9d8c7 Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Tue, 22 Jun 2021 18:06:17 +0200 Subject: [PATCH 0937/4206] Fix substract with borrow in FMA Fixes rust-lang/libm#242 --- library/compiler-builtins/libm/src/math/fma.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 3219dbcce1fbe..85d842119cb3b 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -122,9 +122,9 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { rhi += zhi + (rlo < zlo) as u64; } else { /* r -= z */ - let t = rlo; - rlo = rlo.wrapping_sub(zlo); - rhi = rhi.wrapping_sub(zhi.wrapping_sub((t < rlo) as u64)); + let (res, borrow) = rlo.overflowing_sub(zlo); + rlo = res; + rhi = rhi.wrapping_sub(zhi.wrapping_add(borrow as u64)); if (rhi >> 63) != 0 { rlo = (-(rlo as i64)) as u64; rhi = (-(rhi as i64)) as u64 - (rlo != 0) as u64; @@ -218,6 +218,14 @@ mod tests { -0.00000000000000022204460492503126, ); - assert_eq!(fma(-0.992, -0.992, -0.992), -0.00793599999988632,); + assert_eq!(fma(-0.992, -0.992, -0.992), -0.007936000000000007,); + } + + #[test] + fn fma_sbb() { + assert_eq!( + fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), + -3991680619069439e277 + ); } } From 0534e104f312cea63f6eff57d3dc997040a13c55 Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Fri, 25 Jun 2021 11:52:14 +0200 Subject: [PATCH 0938/4206] Update libm --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/libm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 2dd5a61ebf221..6f579f57b1c4b 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.45" +version = "0.1.46" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index fe396e00b7e47..c2d22bf95e2f0 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit fe396e00b7e47821a81c4c87a481ddc6af1d2cdf +Subproject commit c2d22bf95e2f032ae6b237e8e4c336bc795a151c From 5f23bf3c9bc4cf1681586003c3dca877ad0760a6 Mon Sep 17 00:00:00 2001 From: Brian Vincent Date: Wed, 30 Jun 2021 22:35:47 -0500 Subject: [PATCH 0939/4206] Optimize round and roundf --- .../compiler-builtins/libm/src/math/round.rs | 46 ++++++------------- .../compiler-builtins/libm/src/math/roundf.rs | 44 ++++++------------ 2 files changed, 28 insertions(+), 62 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs index bf72f5b941dc7..46fabc90ff534 100644 --- a/library/compiler-builtins/libm/src/math/round.rs +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -1,38 +1,10 @@ +use super::copysign; +use super::trunc; use core::f64; -const TOINT: f64 = 1.0 / f64::EPSILON; - #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn round(mut x: f64) -> f64 { - let i = x.to_bits(); - let e: u64 = i >> 52 & 0x7ff; - let mut y: f64; - - if e >= 0x3ff + 52 { - return x; - } - if e < 0x3ff - 1 { - // raise inexact if x!=0 - force_eval!(x + TOINT); - return 0.0 * x; - } - if i >> 63 != 0 { - x = -x; - } - y = x + TOINT - TOINT - x; - if y > 0.5 { - y = y + x - 1.0; - } else if y <= -0.5 { - y = y + x + 1.0; - } else { - y = y + x; - } - - if i >> 63 != 0 { - -y - } else { - y - } +pub fn round(x: f64) -> f64 { + trunc(x + copysign(0.5 - 0.25 * f64::EPSILON, x)) } #[cfg(test)] @@ -43,4 +15,14 @@ mod tests { fn negative_zero() { assert_eq!(round(-0.0_f64).to_bits(), (-0.0_f64).to_bits()); } + + #[test] + fn sanity_check() { + assert_eq!(round(-1.0), -1.0); + assert_eq!(round(2.8), 3.0); + assert_eq!(round(-0.5), -1.0); + assert_eq!(round(0.5), 1.0); + assert_eq!(round(-1.5), -2.0); + assert_eq!(round(1.5), 2.0); + } } diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs index 497e88d6254a4..c0872a7829d55 100644 --- a/library/compiler-builtins/libm/src/math/roundf.rs +++ b/library/compiler-builtins/libm/src/math/roundf.rs @@ -1,36 +1,10 @@ +use super::copysignf; +use super::truncf; use core::f32; -const TOINT: f32 = 1.0 / f32::EPSILON; - #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundf(mut x: f32) -> f32 { - let i = x.to_bits(); - let e: u32 = i >> 23 & 0xff; - let mut y: f32; - - if e >= 0x7f + 23 { - return x; - } - if e < 0x7f - 1 { - force_eval!(x + TOINT); - return 0.0 * x; - } - if i >> 31 != 0 { - x = -x; - } - y = x + TOINT - TOINT - x; - if y > 0.5f32 { - y = y + x - 1.0; - } else if y <= -0.5f32 { - y = y + x + 1.0; - } else { - y = y + x; - } - if i >> 31 != 0 { - -y - } else { - y - } +pub fn roundf(x: f32) -> f32 { + truncf(x + copysignf(0.5 - 0.25 * f32::EPSILON, x)) } #[cfg(test)] @@ -41,4 +15,14 @@ mod tests { fn negative_zero() { assert_eq!(roundf(-0.0_f32).to_bits(), (-0.0_f32).to_bits()); } + + #[test] + fn sanity_check() { + assert_eq!(roundf(-1.0), -1.0); + assert_eq!(roundf(2.8), 3.0); + assert_eq!(roundf(-0.5), -1.0); + assert_eq!(roundf(0.5), 1.0); + assert_eq!(roundf(-1.5), -2.0); + assert_eq!(roundf(1.5), 2.0); + } } From 5428334eaac521c8c3a9ec65f1221e0082311b15 Mon Sep 17 00:00:00 2001 From: SuKiN-a Date: Fri, 9 Jul 2021 09:52:08 +0530 Subject: [PATCH 0940/4206] updated link to musl website --- library/compiler-builtins/libm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 5d9e9bddbf8fd..b864b5df8e79c 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -2,7 +2,7 @@ A port of [MUSL]'s libm to Rust. -[MUSL]: https://www.musl-libc.org/ +[MUSL]: https://musl.libc.org/ ## Goals From 6ff825785857197058b56d938a19403edded9839 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Tue, 13 Jul 2021 21:11:12 -0700 Subject: [PATCH 0941/4206] Support `long double` intrinsics in any aarch64 linux Expands the support added in #377 from just musl to any linux. Also checks for and avoids adding duplicate sources. Fixes #428 --- library/compiler-builtins/build.rs | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index f0617b6e92a10..730ea61dfc6e2 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -84,7 +84,7 @@ fn main() { mod c { extern crate cc; - use std::collections::BTreeMap; + use std::collections::{BTreeMap, HashSet}; use std::env; use std::path::{Path, PathBuf}; @@ -419,23 +419,18 @@ mod c { ("__floatunsitf", "floatunsitf.c"), ("__trunctfdf2", "trunctfdf2.c"), ("__trunctfsf2", "trunctfsf2.c"), + ("__addtf3", "addtf3.c"), + ("__multf3", "multf3.c"), + ("__subtf3", "subtf3.c"), + ("__divtf3", "divtf3.c"), + ("__powitf2", "powitf2.c"), + ("__fe_getround", "fp_mode.c"), + ("__fe_raise_inexact", "fp_mode.c"), ]); if target_os != "windows" { sources.extend(&[("__multc3", "multc3.c")]); } - - if target_env == "musl" { - sources.extend(&[ - ("__addtf3", "addtf3.c"), - ("__multf3", "multf3.c"), - ("__subtf3", "subtf3.c"), - ("__divtf3", "divtf3.c"), - ("__powitf2", "powitf2.c"), - ("__fe_getround", "fp_mode.c"), - ("__fe_raise_inexact", "fp_mode.c"), - ]); - } } if target_arch == "mips" { @@ -505,10 +500,13 @@ mod c { sources.extend(&[("__aarch64_have_lse_atomics", "cpu_model.c")]); } + let mut added_sources = HashSet::new(); for (sym, src) in sources.map.iter() { let src = src_dir.join(src); - cfg.file(&src); - println!("cargo:rerun-if-changed={}", src.display()); + if added_sources.insert(src.clone()) { + cfg.file(&src); + println!("cargo:rerun-if-changed={}", src.display()); + } println!("cargo:rustc-cfg={}=\"optimized-c\"", sym); } From b1440f2b0a903e886355148868d7ed2bbd3857fb Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 14 Jul 2021 21:40:46 +0200 Subject: [PATCH 0942/4206] Bump to 0.1.47 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 6f579f57b1c4b..604e54d300136 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.46" +version = "0.1.47" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From ba100707db3a07d2b9561d78d93a93acc4c1fd0f Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Wed, 28 Jul 2021 13:44:49 -0400 Subject: [PATCH 0943/4206] Don't try to build out-of-line aarch64 atomics with the msvc toolchain The msvc toolchain does not support building `.s` files, clang only supports generating out-of-line atomics on Linux and gcc does not support aarch64 for Windows at all. Therefore, we don't need to compile `lse.s` on `aarch64-pc-windows-msvc`. --- library/compiler-builtins/build.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 730ea61dfc6e2..d4cfe0e1c2b3a 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -491,8 +491,9 @@ mod c { // 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). let src_dir = root.join("lib/builtins"); - if target_arch == "aarch64" { + if target_arch == "aarch64" && target_env != "msvc" { // See below for why we're building these as separate libraries. build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg); From 2e7151205ef4a6487b6745ee63ab06ce442ec13b Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 28 Jul 2021 22:30:59 +0200 Subject: [PATCH 0944/4206] Bump to 0.1.48 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 604e54d300136..b1dcd11c4f92e 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.47" +version = "0.1.48" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 502370f277ccf9abf48914a0d901615c861d3f01 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 30 Jul 2021 00:23:15 +0200 Subject: [PATCH 0945/4206] Don't panic if the shift intrinsics receive out-of-range shifts LLVM sometimes emits calls with out-of-range shifts but then discards the results. We should avoid panics in these cases. --- library/compiler-builtins/src/int/shift.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 59909929e58c2..908e619e1dd81 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -6,13 +6,13 @@ trait Ashl: DInt { let n_h = Self::H::BITS; if shl & n_h != 0 { // we only need `self.lo()` because `self.hi()` will be shifted out entirely - (self.lo() << (shl - n_h)).widen_hi() + self.lo().wrapping_shl(shl - n_h).widen_hi() } else if shl == 0 { self } else { Self::from_lo_hi( - self.lo() << shl, - self.lo().logical_shr(n_h - shl) | (self.hi() << shl), + self.lo().wrapping_shl(shl), + self.lo().logical_shr(n_h - shl) | self.hi().wrapping_shl(shl), ) } } @@ -28,16 +28,16 @@ trait Ashr: DInt { let n_h = Self::H::BITS; if shr & n_h != 0 { Self::from_lo_hi( - self.hi() >> (shr - n_h), + self.hi().wrapping_shr(shr - n_h), // smear the sign bit - self.hi() >> (n_h - 1), + self.hi().wrapping_shr(n_h - 1), ) } else if shr == 0 { self } else { Self::from_lo_hi( - self.lo().logical_shr(shr) | (self.hi() << (n_h - shr)), - self.hi() >> shr, + self.lo().logical_shr(shr) | self.hi().wrapping_shl(n_h - shr), + self.hi().wrapping_shr(shr), ) } } @@ -57,7 +57,7 @@ trait Lshr: DInt { self } else { Self::from_lo_hi( - self.lo().logical_shr(shr) | (self.hi() << (n_h - shr)), + self.lo().logical_shr(shr) | self.hi().wrapping_shl(n_h - shr), self.hi().logical_shr(shr), ) } From 4ffaedd2e3a017648d1d7c84916e937bcffab5d7 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 30 Jul 2021 18:49:46 +0200 Subject: [PATCH 0946/4206] Bump to 0.1.49 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index b1dcd11c4f92e..7979032d7944d 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.48" +version = "0.1.49" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From d282412f70c510185bcd34e29c99d177ea7078d3 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Tue, 9 Feb 2021 05:07:58 +0000 Subject: [PATCH 0947/4206] Add test cases for memcpy, memmove and memset for different alignment --- .../compiler-builtins/testcrate/tests/mem.rs | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/library/compiler-builtins/testcrate/tests/mem.rs b/library/compiler-builtins/testcrate/tests/mem.rs index a5596b2811dad..3f20e72a04c8d 100644 --- a/library/compiler-builtins/testcrate/tests/mem.rs +++ b/library/compiler-builtins/testcrate/tests/mem.rs @@ -1,6 +1,8 @@ extern crate compiler_builtins; use compiler_builtins::mem::{memcmp, memcpy, memmove, memset}; +const WORD_SIZE: usize = core::mem::size_of::(); + #[test] fn memcpy_3() { let mut arr: [u8; 12] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; @@ -131,3 +133,130 @@ fn memcmp_ne() { assert!(memcmp(arr2.as_ptr(), arr1.as_ptr(), 8) > 0); } } + +#[derive(Clone, Copy)] +struct AlignedStorage([u8; N], [usize; 0]); + +fn gen_arr() -> AlignedStorage { + let mut ret = AlignedStorage::([0; N], []); + for i in 0..N { + ret.0[i] = i as u8; + } + ret +} + +#[test] +fn memmove_forward_misaligned_nonaligned_start() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let src = arr.0.as_ptr().offset(6); + let dst = arr.0.as_mut_ptr().offset(3); + assert_eq!(memmove(dst, src, 17), dst); + reference.0.copy_within(6..6 + 17, 3); + assert_eq!(arr.0, reference.0); + } +} + +#[test] +fn memmove_forward_misaligned_aligned_start() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let src = arr.0.as_ptr().offset(6); + let dst = arr.0.as_mut_ptr().add(0); + assert_eq!(memmove(dst, src, 17), dst); + reference.0.copy_within(6..6 + 17, 0); + assert_eq!(arr.0, reference.0); + } +} + +#[test] +fn memmove_forward_aligned() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let src = arr.0.as_ptr().add(3 + WORD_SIZE); + let dst = arr.0.as_mut_ptr().add(3); + assert_eq!(memmove(dst, src, 17), dst); + reference + .0 + .copy_within(3 + WORD_SIZE..3 + WORD_SIZE + 17, 3); + assert_eq!(arr.0, reference.0); + } +} + +#[test] +fn memmove_backward_misaligned_nonaligned_start() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let src = arr.0.as_ptr().offset(3); + let dst = arr.0.as_mut_ptr().offset(6); + assert_eq!(memmove(dst, src, 17), dst); + reference.0.copy_within(3..3 + 17, 6); + assert_eq!(arr.0, reference.0); + } +} + +#[test] +fn memmove_backward_misaligned_aligned_start() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let src = arr.0.as_ptr().offset(3); + let dst = arr.0.as_mut_ptr().add(WORD_SIZE); + assert_eq!(memmove(dst, src, 17), dst); + reference.0.copy_within(3..3 + 17, WORD_SIZE); + assert_eq!(arr.0, reference.0); + } +} + +#[test] +fn memmove_backward_aligned() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let src = arr.0.as_ptr().add(3); + let dst = arr.0.as_mut_ptr().add(3 + WORD_SIZE); + assert_eq!(memmove(dst, src, 17), dst); + reference.0.copy_within(3..3 + 17, 3 + WORD_SIZE); + assert_eq!(arr.0, reference.0); + } +} + +#[test] +fn memset_backward_misaligned_nonaligned_start() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let ptr = arr.0.as_mut_ptr().offset(6); + assert_eq!(memset(ptr, 0xCC, 17), ptr); + core::ptr::write_bytes(reference.0.as_mut_ptr().add(6), 0xCC, 17); + assert_eq!(arr.0, reference.0); + } +} + +#[test] +fn memset_backward_misaligned_aligned_start() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let ptr = arr.0.as_mut_ptr().add(WORD_SIZE); + assert_eq!(memset(ptr, 0xCC, 17), ptr); + core::ptr::write_bytes(reference.0.as_mut_ptr().add(WORD_SIZE), 0xCC, 17); + assert_eq!(arr.0, reference.0); + } +} + +#[test] +fn memset_backward_aligned() { + let mut arr = gen_arr::<32>(); + let mut reference = arr; + unsafe { + let ptr = arr.0.as_mut_ptr().add(3 + WORD_SIZE); + assert_eq!(memset(ptr, 0xCC, 17), ptr); + core::ptr::write_bytes(reference.0.as_mut_ptr().add(3 + WORD_SIZE), 0xCC, 17); + assert_eq!(arr.0, reference.0); + } +} From 45715eb7f73a1aaee6e4619521f3e836293e535a Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Tue, 9 Feb 2021 05:10:39 +0000 Subject: [PATCH 0948/4206] Implement word-sized copy --- library/compiler-builtins/src/mem/impls.rs | 224 +++++++++++++++++++-- 1 file changed, 208 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/src/mem/impls.rs index b3eef9901dd55..e60b160fdfd69 100644 --- a/library/compiler-builtins/src/mem/impls.rs +++ b/library/compiler-builtins/src/mem/impls.rs @@ -1,27 +1,219 @@ +use core::intrinsics::likely; + +const WORD_SIZE: usize = core::mem::size_of::(); +const WORD_MASK: usize = WORD_SIZE - 1; + +// If the number of bytes involved exceed this threshold we will opt in word-wise copy. +// The value here selected is max(2 * WORD_SIZE, 16): +// * We need at least 2 * WORD_SIZE bytes to guarantee that at least 1 word will be copied through +// word-wise copy. +// * The word-wise copy logic needs to perform some checks so it has some small overhead. +// ensures that even on 32-bit platforms we have copied at least 8 bytes through +// word-wise copy so the saving of word-wise copy outweights the fixed overhead. +const WORD_COPY_THRESHOLD: usize = if 2 * WORD_SIZE > 16 { + 2 * WORD_SIZE +} else { + 16 +}; + #[inline(always)] -pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, n: usize) { - let mut i = 0; - while i < n { - *dest.add(i) = *src.add(i); - i += 1; +pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) { + #[inline(always)] + unsafe fn copy_forward_bytes(mut dest: *mut u8, mut src: *const u8, n: usize) { + let dest_end = dest.add(n); + while dest < dest_end { + *dest = *src; + dest = dest.add(1); + src = src.add(1); + } + } + + #[inline(always)] + unsafe fn copy_forward_aligned_words(dest: *mut u8, src: *const u8, n: usize) { + let mut dest_usize = dest as *mut usize; + let mut src_usize = src as *mut usize; + let dest_end = dest.add(n) as *mut usize; + + while dest_usize < dest_end { + *dest_usize = *src_usize; + dest_usize = dest_usize.add(1); + src_usize = src_usize.add(1); + } + } + + #[inline(always)] + unsafe fn copy_forward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { + let mut dest_usize = dest as *mut usize; + let dest_end = dest.add(n) as *mut usize; + + // Calculate the misalignment offset and shift needed to reassemble value. + let offset = src as usize & WORD_MASK; + let shift = offset * 8; + + // Realign src + let mut src_aligned = (src as usize & !WORD_MASK) as *mut usize; + // XXX: Could this possibly be UB? + let mut prev_word = *src_aligned; + + while dest_usize < dest_end { + src_aligned = src_aligned.add(1); + let cur_word = *src_aligned; + #[cfg(target_endian = "little")] + let resembled = prev_word >> shift | cur_word << (WORD_SIZE * 8 - shift); + #[cfg(target_endian = "big")] + let resembled = prev_word << shift | cur_word >> (WORD_SIZE * 8 - shift); + prev_word = cur_word; + + *dest_usize = resembled; + dest_usize = dest_usize.add(1); + } } + + if n >= WORD_COPY_THRESHOLD { + // Align dest + // Because of n >= 2 * WORD_SIZE, dst_misalignment < n + let dest_misalignment = (dest as usize).wrapping_neg() & WORD_MASK; + copy_forward_bytes(dest, src, dest_misalignment); + dest = dest.add(dest_misalignment); + src = src.add(dest_misalignment); + n -= dest_misalignment; + + let n_words = n & !WORD_MASK; + let src_misalignment = src as usize & WORD_MASK; + if likely(src_misalignment == 0) { + copy_forward_aligned_words(dest, src, n_words); + } else { + copy_forward_misaligned_words(dest, src, n_words); + } + dest = dest.add(n_words); + src = src.add(n_words); + n -= n_words; + } + copy_forward_bytes(dest, src, n); } #[inline(always)] -pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, n: usize) { - // copy from end - let mut i = n; - while i != 0 { - i -= 1; - *dest.add(i) = *src.add(i); +pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { + // The following backward copy helper functions uses the pointers past the end + // as their inputs instead of pointers to the start! + #[inline(always)] + unsafe fn copy_backward_bytes(mut dest: *mut u8, mut src: *const u8, n: usize) { + let dest_start = dest.sub(n); + while dest_start < dest { + dest = dest.sub(1); + src = src.sub(1); + *dest = *src; + } + } + + #[inline(always)] + unsafe fn copy_backward_aligned_words(dest: *mut u8, src: *const u8, n: usize) { + let mut dest_usize = dest as *mut usize; + let mut src_usize = src as *mut usize; + let dest_start = dest.sub(n) as *mut usize; + + while dest_start < dest_usize { + dest_usize = dest_usize.sub(1); + src_usize = src_usize.sub(1); + *dest_usize = *src_usize; + } } + + #[inline(always)] + unsafe fn copy_backward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { + let mut dest_usize = dest as *mut usize; + let dest_start = dest.sub(n) as *mut usize; + + // Calculate the misalignment offset and shift needed to reassemble value. + let offset = src as usize & WORD_MASK; + let shift = offset * 8; + + // Realign src_aligned + let mut src_aligned = (src as usize & !WORD_MASK) as *mut usize; + // XXX: Could this possibly be UB? + let mut prev_word = *src_aligned; + + while dest_start < dest_usize { + src_aligned = src_aligned.sub(1); + let cur_word = *src_aligned; + #[cfg(target_endian = "little")] + let resembled = prev_word << (WORD_SIZE * 8 - shift) | cur_word >> shift; + #[cfg(target_endian = "big")] + let resembled = prev_word >> (WORD_SIZE * 8 - shift) | cur_word << shift; + prev_word = cur_word; + + dest_usize = dest_usize.sub(1); + *dest_usize = resembled; + } + } + + let mut dest = dest.add(n); + let mut src = src.add(n); + + if n >= WORD_COPY_THRESHOLD { + // Align dest + // Because of n >= 2 * WORD_SIZE, dst_misalignment < n + let dest_misalignment = dest as usize & WORD_MASK; + copy_backward_bytes(dest, src, dest_misalignment); + dest = dest.sub(dest_misalignment); + src = src.sub(dest_misalignment); + n -= dest_misalignment; + + let n_words = n & !WORD_MASK; + let src_misalignment = src as usize & WORD_MASK; + if likely(src_misalignment == 0) { + copy_backward_aligned_words(dest, src, n_words); + } else { + copy_backward_misaligned_words(dest, src, n_words); + } + dest = dest.sub(n_words); + src = src.sub(n_words); + n -= n_words; + } + copy_backward_bytes(dest, src, n); } #[inline(always)] -pub unsafe fn set_bytes(s: *mut u8, c: u8, n: usize) { - let mut i = 0; - while i < n { - *s.add(i) = c; - i += 1; +pub unsafe fn set_bytes(mut s: *mut u8, c: u8, mut n: usize) { + #[inline(always)] + pub unsafe fn set_bytes_bytes(mut s: *mut u8, c: u8, n: usize) { + let end = s.add(n); + while s < end { + *s = c; + s = s.add(1); + } + } + + #[inline(always)] + pub unsafe fn set_bytes_words(s: *mut u8, c: u8, n: usize) { + let mut broadcast = c as usize; + let mut bits = 8; + while bits < WORD_SIZE * 8 { + broadcast |= broadcast << bits; + bits *= 2; + } + + let mut s_usize = s as *mut usize; + let end = s.add(n) as *mut usize; + + while s_usize < end { + *s_usize = broadcast; + s_usize = s_usize.add(1); + } + } + + if likely(n >= WORD_COPY_THRESHOLD) { + // Align s + // Because of n >= 2 * WORD_SIZE, dst_misalignment < n + let misalignment = (s as usize).wrapping_neg() & WORD_MASK; + set_bytes_bytes(s, c, misalignment); + s = s.add(misalignment); + n -= misalignment; + + let n_words = n & !WORD_MASK; + set_bytes_words(s, c, n_words); + s = s.add(n_words); + n -= n_words; } + set_bytes_bytes(s, c, n); } From 8535675a1706733a51288b3f0752554a3b065028 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 10 Feb 2021 23:35:54 +0000 Subject: [PATCH 0949/4206] Add misaligned benchmarks --- .../testcrate/benches/mem.rs | 134 +++++++++++++----- 1 file changed, 100 insertions(+), 34 deletions(-) diff --git a/library/compiler-builtins/testcrate/benches/mem.rs b/library/compiler-builtins/testcrate/benches/mem.rs index cee64ae4d51d5..b6883a93b2483 100644 --- a/library/compiler-builtins/testcrate/benches/mem.rs +++ b/library/compiler-builtins/testcrate/benches/mem.rs @@ -6,30 +6,64 @@ use test::{black_box, Bencher}; extern crate compiler_builtins; use compiler_builtins::mem::{memcmp, memcpy, memmove, memset}; -fn memcpy_builtin(b: &mut Bencher, n: usize, offset: usize) { - let v1 = vec![1u8; n + offset]; - let mut v2 = vec![0u8; n + offset]; +const WORD_SIZE: usize = core::mem::size_of::(); + +struct AlignedVec { + vec: Vec, + size: usize, +} + +impl AlignedVec { + fn new(fill: u8, size: usize) -> Self { + let mut broadcast = fill as usize; + let mut bits = 8; + while bits < WORD_SIZE * 8 { + broadcast |= broadcast << bits; + bits *= 2; + } + + let vec = vec![broadcast; (size + WORD_SIZE - 1) & !WORD_SIZE]; + AlignedVec { vec, size } + } +} + +impl core::ops::Deref for AlignedVec { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { core::slice::from_raw_parts(self.vec.as_ptr() as *const u8, self.size) } + } +} + +impl core::ops::DerefMut for AlignedVec { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { core::slice::from_raw_parts_mut(self.vec.as_mut_ptr() as *mut u8, self.size) } + } +} + +fn memcpy_builtin(b: &mut Bencher, n: usize, offset1: usize, offset2: usize) { + let v1 = AlignedVec::new(1, n + offset1); + let mut v2 = AlignedVec::new(0, n + offset2); b.bytes = n as u64; b.iter(|| { - let src: &[u8] = black_box(&v1[offset..]); - let dst: &mut [u8] = black_box(&mut v2[offset..]); + let src: &[u8] = black_box(&v1[offset1..]); + let dst: &mut [u8] = black_box(&mut v2[offset2..]); dst.copy_from_slice(src); }) } -fn memcpy_rust(b: &mut Bencher, n: usize, offset: usize) { - let v1 = vec![1u8; n + offset]; - let mut v2 = vec![0u8; n + offset]; +fn memcpy_rust(b: &mut Bencher, n: usize, offset1: usize, offset2: usize) { + let v1 = AlignedVec::new(1, n + offset1); + let mut v2 = AlignedVec::new(0, n + offset2); b.bytes = n as u64; b.iter(|| { - let src: &[u8] = black_box(&v1[offset..]); - let dst: &mut [u8] = black_box(&mut v2[offset..]); + let src: &[u8] = black_box(&v1[offset1..]); + let dst: &mut [u8] = black_box(&mut v2[offset2..]); unsafe { memcpy(dst.as_mut_ptr(), src.as_ptr(), n) } }) } fn memset_builtin(b: &mut Bencher, n: usize, offset: usize) { - let mut v1 = vec![0u8; n + offset]; + let mut v1 = AlignedVec::new(0, n + offset); b.bytes = n as u64; b.iter(|| { let dst: &mut [u8] = black_box(&mut v1[offset..]); @@ -41,7 +75,7 @@ fn memset_builtin(b: &mut Bencher, n: usize, offset: usize) { } fn memset_rust(b: &mut Bencher, n: usize, offset: usize) { - let mut v1 = vec![0u8; n + offset]; + let mut v1 = AlignedVec::new(0, n + offset); b.bytes = n as u64; b.iter(|| { let dst: &mut [u8] = black_box(&mut v1[offset..]); @@ -51,8 +85,8 @@ fn memset_rust(b: &mut Bencher, n: usize, offset: usize) { } fn memcmp_builtin(b: &mut Bencher, n: usize) { - let v1 = vec![0u8; n]; - let mut v2 = vec![0u8; n]; + let v1 = AlignedVec::new(0, n); + let mut v2 = AlignedVec::new(0, n); v2[n - 1] = 1; b.bytes = n as u64; b.iter(|| { @@ -63,8 +97,8 @@ fn memcmp_builtin(b: &mut Bencher, n: usize) { } fn memcmp_rust(b: &mut Bencher, n: usize) { - let v1 = vec![0u8; n]; - let mut v2 = vec![0u8; n]; + let v1 = AlignedVec::new(0, n); + let mut v2 = AlignedVec::new(0, n); v2[n - 1] = 1; b.bytes = n as u64; b.iter(|| { @@ -74,20 +108,20 @@ fn memcmp_rust(b: &mut Bencher, n: usize) { }) } -fn memmove_builtin(b: &mut Bencher, n: usize) { - let mut v = vec![0u8; n + n / 2]; +fn memmove_builtin(b: &mut Bencher, n: usize, offset: usize) { + let mut v = AlignedVec::new(0, n + n / 2 + offset); b.bytes = n as u64; b.iter(|| { let s: &mut [u8] = black_box(&mut v); - s.copy_within(0..n, n / 2); + s.copy_within(0..n, n / 2 + offset); }) } -fn memmove_rust(b: &mut Bencher, n: usize) { - let mut v = vec![0u8; n + n / 2]; +fn memmove_rust(b: &mut Bencher, n: usize, offset: usize) { + let mut v = AlignedVec::new(0, n + n / 2 + offset); b.bytes = n as u64; b.iter(|| { - let dst: *mut u8 = black_box(&mut v[n / 2..]).as_mut_ptr(); + let dst: *mut u8 = black_box(&mut v[n / 2 + offset..]).as_mut_ptr(); let src: *const u8 = black_box(&v).as_ptr(); unsafe { memmove(dst, src, n) }; }) @@ -95,35 +129,51 @@ fn memmove_rust(b: &mut Bencher, n: usize) { #[bench] fn memcpy_builtin_4096(b: &mut Bencher) { - memcpy_builtin(b, 4096, 0) + memcpy_builtin(b, 4096, 0, 0) } #[bench] fn memcpy_rust_4096(b: &mut Bencher) { - memcpy_rust(b, 4096, 0) + memcpy_rust(b, 4096, 0, 0) } #[bench] fn memcpy_builtin_1048576(b: &mut Bencher) { - memcpy_builtin(b, 1048576, 0) + memcpy_builtin(b, 1048576, 0, 0) } #[bench] fn memcpy_rust_1048576(b: &mut Bencher) { - memcpy_rust(b, 1048576, 0) + memcpy_rust(b, 1048576, 0, 0) } #[bench] fn memcpy_builtin_4096_offset(b: &mut Bencher) { - memcpy_builtin(b, 4096, 65) + memcpy_builtin(b, 4096, 65, 65) } #[bench] fn memcpy_rust_4096_offset(b: &mut Bencher) { - memcpy_rust(b, 4096, 65) + memcpy_rust(b, 4096, 65, 65) } #[bench] fn memcpy_builtin_1048576_offset(b: &mut Bencher) { - memcpy_builtin(b, 1048576, 65) + memcpy_builtin(b, 1048576, 65, 65) } #[bench] fn memcpy_rust_1048576_offset(b: &mut Bencher) { - memcpy_rust(b, 1048576, 65) + memcpy_rust(b, 1048576, 65, 65) +} +#[bench] +fn memcpy_builtin_4096_misalign(b: &mut Bencher) { + memcpy_builtin(b, 4096, 65, 66) +} +#[bench] +fn memcpy_rust_4096_misalign(b: &mut Bencher) { + memcpy_rust(b, 4096, 65, 66) +} +#[bench] +fn memcpy_builtin_1048576_misalign(b: &mut Bencher) { + memcpy_builtin(b, 1048576, 65, 66) +} +#[bench] +fn memcpy_rust_1048576_misalign(b: &mut Bencher) { + memcpy_rust(b, 1048576, 65, 66) } #[bench] @@ -178,17 +228,33 @@ fn memcmp_rust_1048576(b: &mut Bencher) { #[bench] fn memmove_builtin_4096(b: &mut Bencher) { - memmove_builtin(b, 4096) + memmove_builtin(b, 4096, 0) } #[bench] fn memmove_rust_4096(b: &mut Bencher) { - memmove_rust(b, 4096) + memmove_rust(b, 4096, 0) } #[bench] fn memmove_builtin_1048576(b: &mut Bencher) { - memmove_builtin(b, 1048576) + memmove_builtin(b, 1048576, 0) } #[bench] fn memmove_rust_1048576(b: &mut Bencher) { - memmove_rust(b, 1048576) + memmove_rust(b, 1048576, 0) +} +#[bench] +fn memmove_builtin_4096_misalign(b: &mut Bencher) { + memmove_builtin(b, 4096, 1) +} +#[bench] +fn memmove_rust_4096_misalign(b: &mut Bencher) { + memmove_rust(b, 4096, 1) +} +#[bench] +fn memmove_builtin_1048576_misalign(b: &mut Bencher) { + memmove_builtin(b, 1048576, 1) +} +#[bench] +fn memmove_rust_1048576_misalign(b: &mut Bencher) { + memmove_rust(b, 1048576, 1) } From 709bd6e11cc9b616fe9a36f3a4bc402eee73ddc9 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 21 Aug 2021 03:45:38 +0100 Subject: [PATCH 0950/4206] Add different misaligned path for archs with unaligned support --- library/compiler-builtins/build.rs | 5 +++ library/compiler-builtins/src/mem/impls.rs | 38 ++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index d4cfe0e1c2b3a..fb3dc373aa2c8 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -33,6 +33,11 @@ fn main() { println!("cargo:rustc-cfg=feature=\"mem\""); } + // These targets have hardware unaligned access support. + if target.contains("x86_64") || target.contains("i686") || target.contains("aarch64") { + println!("cargo:rustc-cfg=feature=\"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. diff --git a/library/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/src/mem/impls.rs index e60b160fdfd69..7022d62571167 100644 --- a/library/compiler-builtins/src/mem/impls.rs +++ b/library/compiler-builtins/src/mem/impls.rs @@ -16,6 +16,14 @@ const WORD_COPY_THRESHOLD: usize = if 2 * WORD_SIZE > 16 { 16 }; +#[cfg(feature = "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. + let x_read = (x as *const [u8; core::mem::size_of::()]).read(); + core::mem::transmute(x_read) +} + #[inline(always)] pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) { #[inline(always)] @@ -41,6 +49,7 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) } } + #[cfg(not(feature = "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; @@ -69,6 +78,20 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) } } + #[cfg(feature = "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; + let mut src_usize = src as *mut usize; + let dest_end = dest.add(n) as *mut usize; + + while dest_usize < dest_end { + *dest_usize = read_usize_unaligned(src_usize); + dest_usize = dest_usize.add(1); + src_usize = src_usize.add(1); + } + } + if n >= WORD_COPY_THRESHOLD { // Align dest // Because of n >= 2 * WORD_SIZE, dst_misalignment < n @@ -119,6 +142,7 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { } } + #[cfg(not(feature = "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; @@ -147,6 +171,20 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { } } + #[cfg(feature = "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; + let mut src_usize = src as *mut usize; + let dest_start = dest.sub(n) as *mut usize; + + while dest_start < dest_usize { + dest_usize = dest_usize.sub(1); + src_usize = src_usize.sub(1); + *dest_usize = read_usize_unaligned(src_usize); + } + } + let mut dest = dest.add(n); let mut src = src.add(n); From 1f0cbb29458fdd6d3a3656516d485a23a0aa18f3 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Tue, 31 Aug 2021 00:22:43 +0100 Subject: [PATCH 0951/4206] Use atomic_load_unordered for first word load in misaligned case --- library/compiler-builtins/src/mem/impls.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/src/mem/impls.rs index 7022d62571167..65887a3389299 100644 --- a/library/compiler-builtins/src/mem/impls.rs +++ b/library/compiler-builtins/src/mem/impls.rs @@ -61,8 +61,8 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) // Realign src let mut src_aligned = (src as usize & !WORD_MASK) as *mut usize; - // XXX: Could this possibly be UB? - let mut prev_word = *src_aligned; + // This will read (but won't use) bytes out of bound. + let mut prev_word = core::intrinsics::atomic_load_unordered(src_aligned); while dest_usize < dest_end { src_aligned = src_aligned.add(1); @@ -154,8 +154,8 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { // Realign src_aligned let mut src_aligned = (src as usize & !WORD_MASK) as *mut usize; - // XXX: Could this possibly be UB? - let mut prev_word = *src_aligned; + // This will read (but won't use) bytes out of bound. + let mut prev_word = core::intrinsics::atomic_load_unordered(src_aligned); while dest_start < dest_usize { src_aligned = src_aligned.sub(1); From abf75cc713538b590ee769e6957169e0a2f89288 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 1 Sep 2021 00:22:59 +0200 Subject: [PATCH 0952/4206] Bump to 0.1.50 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 7979032d7944d..8c06d9621a105 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.49" +version = "0.1.50" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From a71b0e449395f68833b97a2a47bf58c0b157a54a Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 15 Oct 2021 01:56:08 +0200 Subject: [PATCH 0953/4206] Disable broken powerpc64 test due to https://github.com/rust-lang/rust/issues/88520 --- library/compiler-builtins/testcrate/tests/cmp.rs | 2 ++ library/compiler-builtins/testcrate/tests/conv.rs | 2 ++ library/compiler-builtins/testcrate/tests/misc.rs | 2 ++ 3 files changed, 6 insertions(+) diff --git a/library/compiler-builtins/testcrate/tests/cmp.rs b/library/compiler-builtins/testcrate/tests/cmp.rs index a49779ad0e48a..5c10a5601138a 100644 --- a/library/compiler-builtins/testcrate/tests/cmp.rs +++ b/library/compiler-builtins/testcrate/tests/cmp.rs @@ -22,6 +22,8 @@ macro_rules! cmp { }; } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[test] fn float_comparisons() { use compiler_builtins::float::cmp::{ diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 7cdbf9fbb69e0..8c4b1946ce4db 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -95,6 +95,8 @@ macro_rules! f_to_i { }; } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[test] fn float_to_int() { use compiler_builtins::float::conv::{ diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index 82a1ea27b47e0..5f74e00638094 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -111,6 +111,8 @@ macro_rules! extend { }; } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[test] fn float_extend() { use compiler_builtins::float::extend::__extendsfdf2; From 29dd109959b067323e5d21a3534ab93edb5201ae Mon Sep 17 00:00:00 2001 From: Georgy Shepelev Date: Wed, 29 Sep 2021 16:02:46 +0400 Subject: [PATCH 0954/4206] expose some math to UEFI envs --- library/compiler-builtins/src/lib.rs | 1 + library/compiler-builtins/src/math.rs | 46 +++++++++++++++++---------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 21796ca55411f..2bf6e00a8d575 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -40,6 +40,7 @@ pub mod int; #[cfg(any( all(target_arch = "wasm32", target_os = "unknown"), + all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "arm", target_os = "none"), all(target_vendor = "fortanix", target_env = "sgx") ))] diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 94f91124bf0f6..6bc1e90763815 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -20,24 +20,17 @@ macro_rules! no_mangle { target_os = "unknown", not(target_env = "wasi") ), + all(target_arch = "x86_64", target_os = "uefi"), all(target_vendor = "fortanix", target_env = "sgx") ))] no_mangle! { fn acos(x: f64) -> f64; fn asin(x: f64) -> f64; - fn atan(x: f64) -> f64; - fn atan2(x: f64, y: f64) -> f64; fn cbrt(x: f64) -> f64; - fn cosh(x: f64) -> f64; fn expm1(x: f64) -> f64; fn hypot(x: f64, y: f64) -> f64; - fn log1p(x: f64) -> f64; - fn sinh(x: f64) -> f64; fn tan(x: f64) -> f64; - fn tanh(x: f64) -> f64; fn cos(x: f64) -> f64; - fn cosf(x: f32) -> f32; - fn exp(x: f64) -> f64; fn expf(x: f32) -> f32; fn log2(x: f64) -> f64; fn log2f(x: f32) -> f32; @@ -52,33 +45,52 @@ no_mangle! { fn round(x: f64) -> f64; fn roundf(x: f32) -> f32; fn sin(x: f64) -> f64; - fn sinf(x: f32) -> f32; fn pow(x: f64, y: f64) -> f64; fn powf(x: f32, y: f32) -> f32; - fn exp2(x: f64) -> f64; - fn exp2f(x: f32) -> f32; fn fmod(x: f64, y: f64) -> f64; fn fmodf(x: f32, y: f32) -> f32; - fn fma(x: f64, y: f64, z: f64) -> f64; - fn fmaf(x: f32, y: f32, z: f32) -> f32; fn acosf(n: f32) -> f32; - fn asinf(n: f32) -> f32; fn atan2f(a: f32, b: f32) -> f32; fn atanf(n: f32) -> f32; - fn cbrtf(n: f32) -> f32; fn coshf(n: f32) -> f32; fn expm1f(n: f32) -> f32; fn fdim(a: f64, b: f64) -> f64; fn fdimf(a: f32, b: f32) -> f32; - fn hypotf(x: f32, y: f32) -> f32; fn log1pf(n: f32) -> f32; fn sinhf(n: f32) -> f32; - fn tanf(n: f32) -> f32; fn tanhf(n: f32) -> f32; fn ldexp(f: f64, n: i32) -> f64; fn ldexpf(f: f32, n: i32) -> f32; } +#[cfg(any( + all( + target_arch = "wasm32", + target_os = "unknown", + not(target_env = "wasi") + ), + all(target_vendor = "fortanix", target_env = "sgx") +))] +no_mangle! { + fn atan(x: f64) -> f64; + fn atan2(x: f64, y: f64) -> f64; + fn cosh(x: f64) -> f64; + fn log1p(x: f64) -> f64; + fn sinh(x: f64) -> f64; + fn tanh(x: f64) -> f64; + fn cosf(x: f32) -> f32; + fn exp(x: f64) -> f64; + fn sinf(x: f32) -> f32; + fn exp2(x: f64) -> f64; + fn exp2f(x: f32) -> f32; + fn fma(x: f64, y: f64, z: f64) -> f64; + fn fmaf(x: f32, y: f32, z: f32) -> f32; + fn asinf(n: f32) -> f32; + fn cbrtf(n: f32) -> f32; + fn hypotf(x: f32, y: f32) -> f32; + fn tanf(n: f32) -> f32; +} + #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] no_mangle! { fn ceil(x: f64) -> f64; From 3b4d10f6bcaefa98002c287a4ec7bde71342b6a1 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Fri, 8 Oct 2021 13:36:30 +0100 Subject: [PATCH 0955/4206] Add xtensa to list of soft math targets. --- library/compiler-builtins/src/math.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 6bc1e90763815..6f024e7b38d3c 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -21,6 +21,7 @@ macro_rules! no_mangle { not(target_env = "wasi") ), all(target_arch = "x86_64", target_os = "uefi"), + all(target_arch = "xtensa", target_os = "none"), all(target_vendor = "fortanix", target_env = "sgx") ))] no_mangle! { @@ -69,6 +70,7 @@ no_mangle! { target_os = "unknown", not(target_env = "wasi") ), + all(target_arch = "xtensa", target_os = "none"), all(target_vendor = "fortanix", target_env = "sgx") ))] no_mangle! { From 2d12d7150aa396e8d79cc493c4edf0ab55cfe371 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 17 Oct 2021 01:41:40 +0200 Subject: [PATCH 0956/4206] Bump to 0.1.51 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 8c06d9621a105..7874b99fdac93 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.50" +version = "0.1.51" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From b7fb6c594a8267d5810b5319f2f3bf24b2ecb1de Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 28 Oct 2021 10:29:37 -0700 Subject: [PATCH 0957/4206] Adjust some build directives for wasm64 This is still an experimental target but this should get the wasm64 target to behave more like wasm32. --- library/compiler-builtins/build.rs | 8 ++++---- library/compiler-builtins/src/lib.rs | 1 + library/compiler-builtins/src/math.rs | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index fb3dc373aa2c8..60feb0619325d 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -23,9 +23,9 @@ fn main() { return; } - // Forcibly enable memory intrinsics on wasm32 & SGX as we don't have a libc to + // Forcibly enable memory intrinsics on wasm & SGX as we don't have a libc to // provide them. - if (target.contains("wasm32") && !target.contains("wasi")) + if (target.contains("wasm") && !target.contains("wasi")) || (target.contains("sgx") && target.contains("fortanix")) || target.contains("-none") || target.contains("nvptx") @@ -50,13 +50,13 @@ fn main() { if !cfg!(feature = "mangled-names") && cfg!(feature = "c") { // Don't use a C compiler for these targets: // - // * wasm32 - clang 8 for wasm is somewhat hard to come by and it's + // * wasm - clang for wasm is somewhat hard to come by and it's // unlikely that the C is really that much better than our own Rust. // * nvptx - everything is bitcode, not compatible with mixed C/Rust // * riscv - the rust-lang/rust distribution container doesn't have a C // compiler nor is cc-rs ready for compilation to riscv (at this // time). This can probably be removed in the future - if !target.contains("wasm32") && !target.contains("nvptx") && !target.starts_with("riscv") { + if !target.contains("wasm") && !target.contains("nvptx") && !target.starts_with("riscv") { #[cfg(feature = "c")] c::compile(&llvm_target, &target); } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 2bf6e00a8d575..b021a68641412 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -40,6 +40,7 @@ pub mod int; #[cfg(any( all(target_arch = "wasm32", target_os = "unknown"), + all(target_arch = "wasm64", target_os = "unknown"), all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "arm", target_os = "none"), all(target_vendor = "fortanix", target_env = "sgx") diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 6f024e7b38d3c..c6d47b8035194 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -16,7 +16,7 @@ macro_rules! no_mangle { #[cfg(any( all( - target_arch = "wasm32", + any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown", not(target_env = "wasi") ), @@ -66,7 +66,7 @@ no_mangle! { #[cfg(any( all( - target_arch = "wasm32", + any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown", not(target_env = "wasi") ), From 9a01750b1b85e5d9babd36930fab399101c3971c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 28 Oct 2021 16:32:30 -0700 Subject: [PATCH 0958/4206] Use more concise directives --- library/compiler-builtins/src/lib.rs | 3 +-- library/compiler-builtins/src/math.rs | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index b021a68641412..fcafb8978f107 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -39,8 +39,7 @@ pub mod float; pub mod int; #[cfg(any( - all(target_arch = "wasm32", target_os = "unknown"), - all(target_arch = "wasm64", target_os = "unknown"), + all(target_family = "wasm", target_os = "unknown"), all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "arm", target_os = "none"), all(target_vendor = "fortanix", target_env = "sgx") diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index c6d47b8035194..fa59753f8f6cd 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -16,7 +16,7 @@ macro_rules! no_mangle { #[cfg(any( all( - any(target_arch = "wasm32", target_arch = "wasm64"), + target_family = "wasm", target_os = "unknown", not(target_env = "wasi") ), @@ -66,7 +66,7 @@ no_mangle! { #[cfg(any( all( - any(target_arch = "wasm32", target_arch = "wasm64"), + target_family = "wasm", target_os = "unknown", not(target_env = "wasi") ), From 8e7401a1515a9e72be19cd23849526fb4cf58892 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 1 Nov 2021 23:02:56 +0000 Subject: [PATCH 0959/4206] Bump to 0.1.52 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 7874b99fdac93..2caf6fed47d55 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.51" +version = "0.1.52" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From d96a0a0877376a402332b4ba79467bc5b810e9ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=C2=A0Decina?= Date: Sun, 21 Nov 2021 06:54:00 +0000 Subject: [PATCH 0960/4206] Turn on the mem-unaligned feature for bpf targets Fixes the following LLVM segfault: Error: e: 05:02:06 [ERROR] fatal error: "Cannot select: 0x55e970a357d0: i64,ch = AtomicLoad<(load unordered (s64) from %ir.45)> 0x55e970410be8, 0x55e970a358a0\n 0x55e970a358a0: i64,ch = CopyFromReg 0x55e970410be8, Register:i64 %19\n 0x55e970a35490: i64 = Register %19\nIn function: memcpy" PLEASE submit a bug report to https://bugs.llvm.org/ and include the crash backtrace. Stack dump: 0. Running pass 'Function Pass Manager' on module 'unroll-loop'. 1. Running pass 'BPF DAG->DAG Pattern Instruction Selection' on function '@memcpy' --- library/compiler-builtins/build.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 60feb0619325d..b930f1d8d61da 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -34,7 +34,11 @@ fn main() { } // These targets have hardware unaligned access support. - if target.contains("x86_64") || target.contains("i686") || target.contains("aarch64") { + if target.contains("x86_64") + || target.contains("i686") + || target.contains("aarch64") + || target.contains("bpf") + { println!("cargo:rustc-cfg=feature=\"mem-unaligned\""); } From 54e028e964a4dabdffcdcf02c25718129b9a6584 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 25 Nov 2021 00:01:25 +0000 Subject: [PATCH 0961/4206] Bump to 0.1.53 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 2caf6fed47d55..d4348fb4f5902 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.52" +version = "0.1.53" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From e6d7983889c621e0afb551f6c754da4897ac1b92 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Wed, 24 Nov 2021 21:51:50 -0500 Subject: [PATCH 0962/4206] Do not use atomic reads on platforms without atomic support in LLVM. --- library/compiler-builtins/src/mem/impls.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/src/mem/impls.rs index 65887a3389299..8151324254a06 100644 --- a/library/compiler-builtins/src/mem/impls.rs +++ b/library/compiler-builtins/src/mem/impls.rs @@ -62,7 +62,12 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) // Realign src let mut src_aligned = (src as usize & !WORD_MASK) as *mut usize; // This will read (but won't use) bytes out of bound. + // cfg needed because not all targets will have atomic loads that can be lowered + // (e.g. BPF, MSP430), or provided by an external library (e.g. RV32I) + #[cfg(target_has_atomic_load_store = "ptr")] let mut prev_word = core::intrinsics::atomic_load_unordered(src_aligned); + #[cfg(not(target_has_atomic_load_store = "ptr"))] + let mut prev_word = core::ptr::read_volatile(src_aligned); while dest_usize < dest_end { src_aligned = src_aligned.add(1); @@ -155,7 +160,12 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { // Realign src_aligned let mut src_aligned = (src as usize & !WORD_MASK) as *mut usize; // This will read (but won't use) bytes out of bound. + // cfg needed because not all targets will have atomic loads that can be lowered + // (e.g. BPF, MSP430), or provided by an external library (e.g. RV32I) + #[cfg(target_has_atomic_load_store = "ptr")] let mut prev_word = core::intrinsics::atomic_load_unordered(src_aligned); + #[cfg(not(target_has_atomic_load_store = "ptr"))] + let mut prev_word = core::ptr::read_volatile(src_aligned); while dest_start < dest_usize { src_aligned = src_aligned.sub(1); From f275e26e3d1c48abf65401c7727b6de8584952b8 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 27 Nov 2021 19:38:43 -0500 Subject: [PATCH 0963/4206] Use fully-qualified syntax for abs_diff to avoid warning, which can trigger a compiler error. --- library/compiler-builtins/src/float/pow.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index 5ab5e4201c29d..a75340c3093a9 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -5,7 +5,7 @@ use int::Int; fn pow(a: F, b: i32) -> F { let mut a = a; let recip = b < 0; - let mut pow = i32::abs_diff(b, 0); + let mut pow = Int::abs_diff(b, 0); let mut mul = F::ONE; loop { if (pow & 1) != 0 { From a01a61bd36e31ae082ca1cbb83bea811ee840699 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 28 Nov 2021 11:19:54 +0000 Subject: [PATCH 0964/4206] Bump to 0.1.54 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index d4348fb4f5902..8beb767d44459 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.53" +version = "0.1.54" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From c7502772685dd31ed1c877cc7a1c2007fc4d82ee Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 28 Nov 2021 12:50:21 +0000 Subject: [PATCH 0965/4206] Ensure AArch64 LSE object files have distinct names in an archive This is needed by libtool which rejects archives that contain object files with the same name multiple times. Fixes #443 --- library/compiler-builtins/build.rs | 51 ++++++++++++++++-------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index b930f1d8d61da..90b8a04face73 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -95,6 +95,8 @@ mod c { use std::collections::{BTreeMap, HashSet}; use std::env; + use std::fs::File; + use std::io::Write; use std::path::{Path, PathBuf}; struct Sources { @@ -523,20 +525,13 @@ mod c { cfg.compile("libcompiler-rt.a"); } - fn build_aarch64_out_of_line_atomics_libraries(builtins_dir: &Path, cfg: &cc::Build) { - // NOTE: because we're recompiling the same source file in N different ways, building - // serially is necessary. If we want to lift this restriction, we can either: - // - create symlinks to lse.S and build those_(though we'd still need to pass special - // #define-like flags to each of these), or - // - synthesizing tiny .S files in out/ with the proper #defines, which ultimately #include - // lse.S. - // That said, it's unclear how useful this added complexity will be, so just do the simple - // thing for now. + fn build_aarch64_out_of_line_atomics_libraries(builtins_dir: &Path, cfg: &mut cc::Build) { + let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); let outlined_atomics_file = builtins_dir.join("aarch64/lse.S"); println!("cargo:rerun-if-changed={}", outlined_atomics_file.display()); - // Ideally, this would be a Vec of object files, but cc doesn't make it *entirely* - // trivial to build an individual object. + cfg.include(&builtins_dir); + for instruction_type in &["cas", "swp", "ldadd", "ldclr", "ldeor", "ldset"] { for size in &[1, 2, 4, 8, 16] { if *size == 16 && *instruction_type != "cas" { @@ -546,20 +541,30 @@ mod c { for (model_number, model_name) in &[(1, "relax"), (2, "acq"), (3, "rel"), (4, "acq_rel")] { - let library_name = format!( - "liboutline_atomic_helper_{}{}_{}.a", - instruction_type, size, model_name + // The original compiler-rt build system compiles the same + // source file multiple times with different compiler + // options. Here we do something slightly different: we + // create multiple .S files with the proper #defines and + // then include the original file. + // + // This is needed because the cc crate doesn't allow us to + // override the name of object files and libtool requires + // all objects in an archive to have unique names. + let path = + out_dir.join(format!("lse_{}{}_{}.S", instruction_type, size, model_name)); + let mut file = File::create(&path).unwrap(); + writeln!(file, "#define L_{}", instruction_type).unwrap(); + writeln!(file, "#define SIZE {}", size).unwrap(); + writeln!(file, "#define MODEL {}", model_number).unwrap(); + writeln!( + file, + "#include \"{}\"", + outlined_atomics_file.canonicalize().unwrap().display() ); - let sym = format!("__aarch64_{}{}_{}", instruction_type, size, model_name); - let mut cfg = cfg.clone(); - - cfg.include(&builtins_dir) - .define(&format!("L_{}", instruction_type), None) - .define("SIZE", size.to_string().as_str()) - .define("MODEL", model_number.to_string().as_str()) - .file(&outlined_atomics_file); - cfg.compile(&library_name); + drop(file); + cfg.file(path); + let sym = format!("__aarch64_{}{}_{}", instruction_type, size, model_name); println!("cargo:rustc-cfg={}=\"optimized-c\"", sym); } } From c17d0c2780b2127b825dc9c361ef34cd5d790da5 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 28 Nov 2021 15:30:04 +0000 Subject: [PATCH 0966/4206] Bump to 0.1.55 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 8beb767d44459..7a894b9584c86 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.54" +version = "0.1.55" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 4abfecabef8901cf29a415dd275bef76194a1687 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 9 Dec 2021 23:51:18 +0000 Subject: [PATCH 0967/4206] Import the asm! macro from core::arch It is going to be removed from the prelude due to the decision in https://github.com/rust-lang/rust/issues/87228 --- library/compiler-builtins/build.rs | 3 +- library/compiler-builtins/src/arm.rs | 16 +++---- .../src/int/leading_zeros.rs | 2 + .../src/int/specialized_div_rem/mod.rs | 4 +- library/compiler-builtins/src/lib.rs | 2 + library/compiler-builtins/src/mem/x86_64.rs | 10 ++--- library/compiler-builtins/src/probestack.rs | 42 +++++++++++-------- library/compiler-builtins/src/x86.rs | 6 +-- library/compiler-builtins/src/x86_64.rs | 6 +-- 9 files changed, 51 insertions(+), 40 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 90b8a04face73..922cd07a0af99 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -560,7 +560,8 @@ mod c { file, "#include \"{}\"", outlined_atomics_file.canonicalize().unwrap().display() - ); + ) + .unwrap(); drop(file); cfg.file(path); diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 7203d91e4a9d3..3660825aa73cf 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -11,7 +11,7 @@ use core::intrinsics; #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "C" fn __aeabi_uidivmod() { - asm!( + core::arch::asm!( "push {{lr}}", "sub sp, sp, #4", "mov r2, sp", @@ -27,7 +27,7 @@ pub unsafe extern "C" fn __aeabi_uidivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "C" fn __aeabi_uidivmod() { - asm!( + core::arch::asm!( "push {{lr}}", "sub sp, sp, #4", "mov r2, sp", @@ -43,7 +43,7 @@ pub unsafe extern "C" fn __aeabi_uidivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "C" fn __aeabi_uldivmod() { - asm!( + core::arch::asm!( "push {{r4, lr}}", "sub sp, sp, #16", "add r4, sp, #8", @@ -61,7 +61,7 @@ pub unsafe extern "C" fn __aeabi_uldivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "C" fn __aeabi_uldivmod() { - asm!( + core::arch::asm!( "push {{r4, lr}}", "sub sp, sp, #16", "add r4, sp, #8", @@ -79,7 +79,7 @@ pub unsafe extern "C" fn __aeabi_uldivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "C" fn __aeabi_idivmod() { - asm!( + core::arch::asm!( "push {{r0, r1, r4, lr}}", "bl __aeabi_idiv", "pop {{r1, r2}}", @@ -94,7 +94,7 @@ pub unsafe extern "C" fn __aeabi_idivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "C" fn __aeabi_idivmod() { - asm!( + core::arch::asm!( "push {{r0, r1, r4, lr}}", "bl ___aeabi_idiv", "pop {{r1, r2}}", @@ -109,7 +109,7 @@ pub unsafe extern "C" fn __aeabi_idivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "C" fn __aeabi_ldivmod() { - asm!( + core::arch::asm!( "push {{r4, lr}}", "sub sp, sp, #16", "add r4, sp, #8", @@ -127,7 +127,7 @@ pub unsafe extern "C" fn __aeabi_ldivmod() { #[naked] #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub unsafe extern "C" fn __aeabi_ldivmod() { - asm!( + core::arch::asm!( "push {{r4, lr}}", "sub sp, sp, #16", "add r4, sp, #8", diff --git a/library/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/src/int/leading_zeros.rs index 0265b9a9d021b..9e60ab0d74461 100644 --- a/library/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/src/int/leading_zeros.rs @@ -5,6 +5,7 @@ public_test_dep! { /// Returns the number of leading binary zeros in `x`. +#[allow(dead_code)] pub(crate) fn usize_leading_zeros_default(x: usize) -> usize { // The basic idea is to test if the higher bits of `x` are zero and bisect the number // of leading zeros. It is possible for all branches of the bisection to use the same @@ -78,6 +79,7 @@ pub(crate) fn usize_leading_zeros_default(x: usize) -> usize { public_test_dep! { /// Returns the number of leading binary zeros in `x`. +#[allow(dead_code)] pub(crate) fn usize_leading_zeros_riscv(x: usize) -> usize { let mut x = x; // the number of potential leading zeros diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index f5b2af235bd26..6ec4675df94f4 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -184,7 +184,7 @@ unsafe fn u128_by_u64_div_rem(duo: u128, div: u64) -> (u64, u64) { // divides the combined registers rdx:rax (`duo` is split into two 64 bit parts to do this) // by `div`. The quotient is stored in rax and the remainder in rdx. // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - asm!( + core::arch::asm!( "div {0}", in(reg) div, inlateout("rax") duo_lo => quo, @@ -271,7 +271,7 @@ unsafe fn u64_by_u32_div_rem(duo: u64, div: u32) -> (u32, u32) { // divides the combined registers rdx:rax (`duo` is split into two 32 bit parts to do this) // by `div`. The quotient is stored in rax and the remainder in rdx. // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - asm!( + core::arch::asm!( "div {0}", in(reg) div, inlateout("rax") duo_lo => quo, diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index fcafb8978f107..c3eefbc036228 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -18,6 +18,8 @@ #![allow(improper_ctypes, improper_ctypes_definitions)] // `mem::swap` cannot be used because it may generate references to memcpy in unoptimized code. #![allow(clippy::manual_swap)] +// Support compiling on both stage0 and stage1 which may differ in supported stable features. +#![allow(stable_features)] // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index abdb8eb67e002..a7ab6f605bdcf 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -20,7 +20,7 @@ #[cfg(target_feature = "ermsb")] pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - asm!( + core::arch::asm!( "repe movsb (%rsi), (%rdi)", inout("rcx") count => _, inout("rdi") dest => _, @@ -35,7 +35,7 @@ pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { let qword_count = count >> 3; let byte_count = count & 0b111; // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - asm!( + core::arch::asm!( "repe movsq (%rsi), (%rdi)", "mov {byte_count:e}, %ecx", "repe movsb (%rsi), (%rdi)", @@ -52,7 +52,7 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { let qword_count = count >> 3; let byte_count = count & 0b111; // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - asm!( + core::arch::asm!( "std", "repe movsq (%rsi), (%rdi)", "movl {byte_count:e}, %ecx", @@ -72,7 +72,7 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { #[cfg(target_feature = "ermsb")] pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - asm!( + core::arch::asm!( "repe stosb %al, (%rdi)", inout("rcx") count => _, inout("rdi") dest => _, @@ -87,7 +87,7 @@ pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { let qword_count = count >> 3; let byte_count = count & 0b111; // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - asm!( + core::arch::asm!( "repe stosq %rax, (%rdi)", "mov {byte_count:e}, %ecx", "repe stosb %al, (%rdi)", diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 4d6cd694943a4..0c30384db385a 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -48,8 +48,6 @@ #![cfg(not(feature = "no-asm"))] // We only define stack probing for these architectures today. #![cfg(any(target_arch = "x86_64", target_arch = "x86"))] -// We need to add .att_syntax for bootstraping the new global_asm! -#![allow(unknown_lints, bad_asm_style)] extern "C" { pub fn __rust_probestack(); @@ -65,7 +63,6 @@ macro_rules! define_rust_probestack { ($body: expr) => { concat!( " - .att_syntax .pushsection .text.__rust_probestack .globl __rust_probestack .type __rust_probestack, @function @@ -86,7 +83,6 @@ macro_rules! define_rust_probestack { ($body: expr) => { concat!( " - .att_syntax .globl __rust_probestack __rust_probestack: ", @@ -102,7 +98,6 @@ macro_rules! define_rust_probestack { ($body: expr) => { concat!( " - .att_syntax .globl ___rust_probestack ___rust_probestack: ", @@ -117,7 +112,6 @@ macro_rules! define_rust_probestack { ($body: expr) => { concat!( " - .att_syntax .globl ___rust_probestack ___rust_probestack: ", @@ -137,8 +131,9 @@ macro_rules! define_rust_probestack { target_arch = "x86_64", not(all(target_env = "sgx", target_vendor = "fortanix")) ))] -global_asm!(define_rust_probestack!( - " +core::arch::global_asm!( + define_rust_probestack!( + " .cfi_startproc pushq %rbp .cfi_adjust_cfa_offset 8 @@ -188,7 +183,9 @@ global_asm!(define_rust_probestack!( ret .cfi_endproc " -)); + ), + options(att_syntax) +); // This function is the same as above, except that some instructions are // [manually patched for LVI]. @@ -198,8 +195,9 @@ global_asm!(define_rust_probestack!( target_arch = "x86_64", all(target_env = "sgx", target_vendor = "fortanix") ))] -global_asm!(define_rust_probestack!( - " +core::arch::global_asm!( + define_rust_probestack!( + " .cfi_startproc pushq %rbp .cfi_adjust_cfa_offset 8 @@ -251,7 +249,9 @@ global_asm!(define_rust_probestack!( jmp *%r11 .cfi_endproc " -)); + ), + options(att_syntax) +); #[cfg(all(target_arch = "x86", not(target_os = "uefi")))] // This is the same as x86_64 above, only translated for 32-bit sizes. Note @@ -259,8 +259,9 @@ global_asm!(define_rust_probestack!( // function basically can't tamper with anything. // // The ABI here is the same as x86_64, except everything is 32-bits large. -global_asm!(define_rust_probestack!( - " +core::arch::global_asm!( + define_rust_probestack!( + " .cfi_startproc push %ebp .cfi_adjust_cfa_offset 4 @@ -291,7 +292,9 @@ global_asm!(define_rust_probestack!( ret .cfi_endproc " -)); + ), + options(att_syntax) +); #[cfg(all(target_arch = "x86", target_os = "uefi"))] // UEFI target is windows like target. LLVM will do _chkstk things like windows. @@ -304,8 +307,9 @@ global_asm!(define_rust_probestack!( // MSVC x32's _chkstk and cygwin/mingw's _alloca adjust %esp themselves. // MSVC x64's __chkstk and cygwin/mingw's ___chkstk_ms do not adjust %rsp // themselves. -global_asm!(define_rust_probestack!( - " +core::arch::global_asm!( + define_rust_probestack!( + " .cfi_startproc push %ebp .cfi_adjust_cfa_offset 4 @@ -341,4 +345,6 @@ global_asm!(define_rust_probestack!( ret .cfi_endproc " -)); + ), + options(att_syntax) +); diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs index 4992de9da04bf..abcc2bdb3d41e 100644 --- a/library/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/src/x86.rs @@ -17,7 +17,7 @@ use core::intrinsics; #[naked] #[no_mangle] pub unsafe extern "C" fn ___chkstk_ms() { - asm!( + core::arch::asm!( "push %ecx", "push %eax", "cmp $0x1000,%eax", @@ -49,7 +49,7 @@ pub unsafe extern "C" fn ___chkstk_ms() { #[naked] #[no_mangle] pub unsafe extern "C" fn __alloca() { - asm!( + core::arch::asm!( "jmp ___chkstk", // Jump to ___chkstk since fallthrough may be unreliable" options(noreturn, att_syntax) ); @@ -64,7 +64,7 @@ pub unsafe extern "C" fn __alloca() { #[naked] #[no_mangle] pub unsafe extern "C" fn ___chkstk() { - asm!( + core::arch::asm!( "push %ecx", "cmp $0x1000,%eax", "lea 8(%esp),%ecx", // esp before calling this routine -> ecx diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index b382b886c5532..ea3c99497909e 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -17,7 +17,7 @@ use core::intrinsics; #[naked] #[no_mangle] pub unsafe extern "C" fn ___chkstk_ms() { - asm!( + core::arch::asm!( "push %rcx", "push %rax", "cmp $0x1000,%rax", @@ -48,7 +48,7 @@ pub unsafe extern "C" fn ___chkstk_ms() { #[naked] #[no_mangle] pub unsafe extern "C" fn __alloca() { - asm!( + core::arch::asm!( "mov %rcx,%rax", // x64 _alloca is a normal function with parameter in rcx "jmp ___chkstk", // Jump to ___chkstk since fallthrough may be unreliable" options(noreturn, att_syntax) @@ -64,7 +64,7 @@ pub unsafe extern "C" fn __alloca() { #[naked] #[no_mangle] pub unsafe extern "C" fn ___chkstk() { - asm!( + core::arch::asm!( "push %rcx", "cmp $0x1000,%rax", "lea 16(%rsp),%rcx", // rsp before calling this routine -> rcx From 0928b32141c0a01b47e45670a223bc4d479bec55 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 10 Dec 2021 00:04:25 +0000 Subject: [PATCH 0968/4206] Fix clippy lints --- library/compiler-builtins/src/float/div.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index 9ac1e87b4e2d9..528a8368d9252 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -132,8 +132,9 @@ where // This doubles the number of correct binary digits in the approximation // with each iteration, so after three iterations, we have about 28 binary // digits of accuracy. - let mut correction: u32; - correction = negate_u32(((reciprocal as u64).wrapping_mul(q31b as u64) >> 32) as u32); + + let mut correction: u32 = + negate_u32(((reciprocal as u64).wrapping_mul(q31b as u64) >> 32) as u32); reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) as u64 >> 31) as u32; correction = negate_u32(((reciprocal as u64).wrapping_mul(q31b as u64) >> 32) as u32); reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) as u64 >> 31) as u32; @@ -342,8 +343,9 @@ where // This doubles the number of correct binary digits in the approximation // with each iteration, so after three iterations, we have about 28 binary // digits of accuracy. - let mut correction32: u32; - correction32 = negate_u32(((recip32 as u64).wrapping_mul(q31b as u64) >> 32) as u32); + + let mut correction32: u32 = + negate_u32(((recip32 as u64).wrapping_mul(q31b as u64) >> 32) as u32); recip32 = ((recip32 as u64).wrapping_mul(correction32 as u64) >> 31) as u32; correction32 = negate_u32(((recip32 as u64).wrapping_mul(q31b as u64) >> 32) as u32); recip32 = ((recip32 as u64).wrapping_mul(correction32 as u64) >> 31) as u32; @@ -359,16 +361,15 @@ where // We need to perform one more iteration to get us to 56 binary digits; // The last iteration needs to happen with extra precision. let q63blo = CastInto::::cast(b_significand << 11.cast()); - let correction: u64; - let mut reciprocal: u64; - correction = negate_u64( + + let correction: u64 = negate_u64( (recip32 as u64) .wrapping_mul(q31b as u64) .wrapping_add((recip32 as u64).wrapping_mul(q63blo as u64) >> 32), ); let c_hi = (correction >> 32) as u32; let c_lo = correction as u32; - reciprocal = (recip32 as u64) + let mut reciprocal: u64 = (recip32 as u64) .wrapping_mul(c_hi as u64) .wrapping_add((recip32 as u64).wrapping_mul(c_lo as u64) >> 32); From c7dc3215a1a1384c51727227d01259fc06f5c6f6 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 10 Dec 2021 00:11:25 +0000 Subject: [PATCH 0969/4206] Bump to 0.1.56 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 7a894b9584c86..4b2ed2de1d6ae 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.55" +version = "0.1.65" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 9e650601841ad7fa2e34e46523bbd5bffc658d61 Mon Sep 17 00:00:00 2001 From: Ayrton Date: Sat, 11 Dec 2021 23:03:01 -0500 Subject: [PATCH 0970/4206] Add `__truncdfsf2` intrinsic This adds the truncdfsf2 intrinsic and a corresponding fuzz test case. The implementation of trunc is generic to make it easy to add truncdfhs2 and truncsfhf2 if rust ever gets `f16` support. --- library/compiler-builtins/README.md | 2 +- library/compiler-builtins/src/float/mod.rs | 1 + library/compiler-builtins/src/float/trunc.rs | 118 ++++++++++++++++++ .../compiler-builtins/testcrate/tests/misc.rs | 25 ++++ 4 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/src/float/trunc.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index a20d038f8e9ac..108b2679ded36 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -183,7 +183,7 @@ features = ["c"] - [x] subdf3.c - [x] subsf3.c - [ ] truncdfhf2.c -- [ ] truncdfsf2.c +- [x] truncdfsf2.c - [ ] truncsfhf2.c - [x] udivdi3.c - [x] udivmoddi4.c diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 11680e7a9fa3f..01a5504d52c51 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -10,6 +10,7 @@ pub mod extend; pub mod mul; pub mod pow; pub mod sub; +pub mod trunc; public_test_dep! { /// Trait for some basic operations on floats diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs new file mode 100644 index 0000000000000..a00994c76e7b6 --- /dev/null +++ b/library/compiler-builtins/src/float/trunc.rs @@ -0,0 +1,118 @@ +use float::Float; +use int::{CastInto, Int}; + +fn trunc(a: F) -> R +where + F::Int: CastInto, + F::Int: CastInto, + u64: CastInto, + u32: CastInto, + + R::Int: CastInto, + u32: CastInto, + F::Int: CastInto, +{ + let src_zero = F::Int::ZERO; + let src_one = F::Int::ONE; + let src_bits = F::BITS; + let src_exp_bias = F::EXPONENT_BIAS; + + let src_min_normal = F::IMPLICIT_BIT; + let src_significand_mask = F::SIGNIFICAND_MASK; + let src_infinity = F::EXPONENT_MASK; + let src_sign_mask = F::SIGN_MASK; + let src_abs_mask = src_sign_mask - src_one; + let round_mask = (src_one << (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS)) - src_one; + let halfway = src_one << (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS - 1); + let src_qnan = src_one << (F::SIGNIFICAND_BITS - 1); + let src_nan_code = src_qnan - src_one; + + let dst_zero = R::Int::ZERO; + let dst_one = R::Int::ONE; + let dst_bits = R::BITS; + let dst_inf_exp = R::EXPONENT_MAX; + let dst_exp_bias = R::EXPONENT_BIAS; + + let underflow_exponent: F::Int = (src_exp_bias + 1 - dst_exp_bias).cast(); + let overflow_exponent: F::Int = (src_exp_bias + dst_inf_exp - dst_exp_bias).cast(); + let underflow: F::Int = underflow_exponent << F::SIGNIFICAND_BITS; + let overflow: F::Int = overflow_exponent << F::SIGNIFICAND_BITS; + + let dst_qnan = R::Int::ONE << (R::SIGNIFICAND_BITS - 1); + let dst_nan_code = dst_qnan - dst_one; + + let sign_bits_delta = F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS; + // Break a into a sign and representation of the absolute value. + let a_abs = a.repr() & src_abs_mask; + let sign = a.repr() & src_sign_mask; + let mut abs_result: R::Int; + + if a_abs.wrapping_sub(underflow) < a_abs.wrapping_sub(overflow) { + // The exponent of a is within the range of normal numbers in the + // destination format. We can convert by simply right-shifting with + // rounding and adjusting the exponent. + abs_result = (a_abs >> sign_bits_delta).cast(); + let tmp = src_exp_bias.wrapping_sub(dst_exp_bias) << R::SIGNIFICAND_BITS; + abs_result = abs_result.wrapping_sub(tmp.cast()); + + let round_bits = a_abs & round_mask; + if round_bits > halfway { + // Round to nearest. + abs_result += dst_one; + } else if round_bits == halfway { + // Tie to even. + abs_result += abs_result & dst_one; + }; + } else if a_abs > src_infinity { + // a is NaN. + // Conjure the result by beginning with infinity, setting the qNaN + // bit and inserting the (truncated) trailing NaN field. + abs_result = (dst_inf_exp << R::SIGNIFICAND_BITS).cast(); + abs_result |= dst_qnan; + abs_result |= dst_nan_code + & ((a_abs & src_nan_code) >> (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS)).cast(); + } else if a_abs >= overflow { + // a overflows to infinity. + abs_result = (dst_inf_exp << R::SIGNIFICAND_BITS).cast(); + } else { + // a underflows on conversion to the destination type or is an exact + // zero. The result may be a denormal or zero. Extract the exponent + // to get the shift amount for the denormalization. + let a_exp: u32 = (a_abs >> F::SIGNIFICAND_BITS).cast(); + let shift = src_exp_bias - dst_exp_bias - a_exp + 1; + + let significand = (a.repr() & src_significand_mask) | src_min_normal; + + // Right shift by the denormalization amount with sticky. + if shift > F::SIGNIFICAND_BITS { + abs_result = dst_zero; + } else { + let sticky = if (significand << (src_bits - shift)) != src_zero { + src_one + } else { + src_zero + }; + let denormalized_significand: F::Int = significand >> shift | sticky; + abs_result = + (denormalized_significand >> (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS)).cast(); + let round_bits = denormalized_significand & round_mask; + // Round to nearest + if round_bits > halfway { + abs_result += dst_one; + } + // Ties to even + else if round_bits == halfway { + abs_result += abs_result & dst_one; + }; + } + } + + // Apply the signbit to the absolute value. + R::from_repr(abs_result | sign.wrapping_shr(src_bits - dst_bits).cast()) +} + +intrinsics! { + pub extern "C" fn __truncdfsf2(a: f64) -> f32 { + trunc(a) + } +} diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index 5f74e00638094..773153c43b817 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -179,3 +179,28 @@ fn float_pow() { f64, 1e-12, __powidf2; ); } + +macro_rules! trunc { + ($fX:ident, $fD:ident, $fn:ident) => { + fuzz_float(N, |x: $fX| { + let tmp0 = x as $fD; + let tmp1: $fD = $fn(x); + if !Float::eq_repr(tmp0, tmp1) { + panic!( + "{}({}): std: {}, builtins: {}", + stringify!($fn), + x, + tmp0, + tmp1 + ); + } + }); + }; +} + +#[test] +fn float_trunc() { + use compiler_builtins::float::trunc::__truncdfsf2; + + trunc!(f64, f32, __truncdfsf2); +} From 39cd6082e46febeb6f04c856a910a1da15a900c3 Mon Sep 17 00:00:00 2001 From: Ayrton Date: Sun, 12 Dec 2021 15:19:05 -0500 Subject: [PATCH 0971/4206] Add attribute for ARM alias --- library/compiler-builtins/src/float/trunc.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index a00994c76e7b6..d3890e0401763 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -112,6 +112,7 @@ where } intrinsics! { + #[arm_aeabi_alias = __aeabi_d2f] pub extern "C" fn __truncdfsf2(a: f64) -> f32 { trunc(a) } From 03b4f6233719ec971eeaafd240b5db0f0b28634b Mon Sep 17 00:00:00 2001 From: Ayrton Date: Sun, 12 Dec 2021 15:36:09 -0500 Subject: [PATCH 0972/4206] Add `__truncdfsf2vfp` for ARM --- library/compiler-builtins/src/float/trunc.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index d3890e0401763..5f846c66941cc 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -116,4 +116,9 @@ intrinsics! { pub extern "C" fn __truncdfsf2(a: f64) -> f32 { trunc(a) } + + #[cfg(target_arch = "arm")] + pub extern "C" fn __truncdfsf2vfp(a: f64) -> f32 { + a as f32 + } } From 9124cdc7ec431805441cf6810ed55315803811c5 Mon Sep 17 00:00:00 2001 From: Ayrton Date: Sun, 12 Dec 2021 21:12:42 -0500 Subject: [PATCH 0973/4206] Remove truncdfsf2.c from sources in build.rs and add test for __truncdfsf2vfp Also fixed the calling convention for truncdfsf2 on ARM --- library/compiler-builtins/README.md | 2 +- library/compiler-builtins/build.rs | 1 - library/compiler-builtins/examples/intrinsics.rs | 11 ++--------- library/compiler-builtins/src/float/trunc.rs | 1 + library/compiler-builtins/testcrate/tests/misc.rs | 8 ++++++++ 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 108b2679ded36..8b25558a87e8e 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -126,7 +126,7 @@ features = ["c"] - [x] arm/softfloat-alias.list - [x] arm/subdf3vfp.S - [x] arm/subsf3vfp.S -- [ ] arm/truncdfsf2vfp.S +- [x] arm/truncdfsf2vfp.S - [ ] arm/udivmodsi4.S (generic version is done) - [ ] arm/udivsi3.S (generic version is done) - [ ] arm/umodsi3.S (generic version is done) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 922cd07a0af99..dc1cd1d23c71a 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -227,7 +227,6 @@ mod c { ("__negsf2", "negsf2.c"), ("__powixf2", "powixf2.c"), ("__truncdfhf2", "truncdfhf2.c"), - ("__truncdfsf2", "truncdfsf2.c"), ("__truncsfhf2", "truncsfhf2.c"), ]); } diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index dfa46b1b8fed4..0ca30c215b331 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -24,16 +24,9 @@ extern "C" {} // have an additional comment: the function name is the ARM name for the intrinsic and the comment // in the non-ARM name for the intrinsic. mod intrinsics { - // trunccdfsf2 + // truncdfsf2 pub fn aeabi_d2f(x: f64) -> f32 { - // This is only implemented in C currently, so only test it there. - #[cfg(feature = "c")] - return x as f32; - #[cfg(not(feature = "c"))] - { - drop(x); - 0.0 - } + x as f32 } // fixdfsi diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index 5f846c66941cc..d73713084d6c6 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -112,6 +112,7 @@ where } intrinsics! { + #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_d2f] pub extern "C" fn __truncdfsf2(a: f64) -> f32 { trunc(a) diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index 773153c43b817..537ba1e60c722 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -204,3 +204,11 @@ fn float_trunc() { trunc!(f64, f32, __truncdfsf2); } + +#[cfg(target_arch = "arm")] +#[test] +fn float_trunc_arm() { + use compiler_builtins::float::trunc::__truncdfsf2vfp; + + trunc!(f64, f32, __truncdfsf2vfp); +} From df4d9cd6cce2dabf36cb0f513b6ce48decd7b2ee Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 13 Dec 2021 02:25:49 +0000 Subject: [PATCH 0974/4206] Bump to 0.1.66 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 4b2ed2de1d6ae..3f4c96745efe8 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.65" +version = "0.1.66" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From e36ee3b4b78b449028874c4644d53d8b2f67d7f0 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 3 Jan 2022 19:00:31 +0100 Subject: [PATCH 0975/4206] Disable powerpc64 tests which were broken by the LLVM 13 upgrade --- library/compiler-builtins/libm/ci/run-docker.sh | 2 +- library/compiler-builtins/libm/src/math/ceilf.rs | 2 ++ library/compiler-builtins/libm/src/math/fabsf.rs | 2 ++ library/compiler-builtins/libm/src/math/floorf.rs | 2 ++ library/compiler-builtins/libm/src/math/j1f.rs | 2 ++ library/compiler-builtins/libm/src/math/roundf.rs | 2 ++ library/compiler-builtins/libm/src/math/sincosf.rs | 2 ++ library/compiler-builtins/libm/src/math/sqrtf.rs | 2 ++ library/compiler-builtins/libm/src/math/truncf.rs | 2 ++ 9 files changed, 17 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh index e7b80c719e5ca..c7ad60fd499d5 100755 --- a/library/compiler-builtins/libm/ci/run-docker.sh +++ b/library/compiler-builtins/libm/ci/run-docker.sh @@ -18,7 +18,7 @@ run() { --user $(id -u):$(id -g) \ -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ - -v $(dirname $(dirname `which cargo`)):/cargo \ + -v "${HOME}/.cargo":/cargo \ -v `pwd`/target:/target \ -v `pwd`:/checkout:ro \ -v `rustc --print sysroot`:/rust:ro \ diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index f1edbd061bf7e..7bcc647ca76a1 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -40,6 +40,8 @@ pub fn ceilf(x: f32) -> f32 { f32::from_bits(ui) } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { use super::*; diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index 6655c4c3ccc71..23f3646dc4a5a 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -14,6 +14,8 @@ pub fn fabsf(x: f32) -> f32 { f32::from_bits(x.to_bits() & 0x7fffffff) } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { use super::*; diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index 287f08642778d..dfdab91a0f695 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -40,6 +40,8 @@ pub fn floorf(x: f32) -> f32 { f32::from_bits(ui) } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { use super::*; diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs index 5095894d7a1d3..33694908ca23b 100644 --- a/library/compiler-builtins/libm/src/math/j1f.rs +++ b/library/compiler-builtins/libm/src/math/j1f.rs @@ -357,6 +357,8 @@ fn qonef(x: f32) -> f32 { return (0.375 + r / s) / x; } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { use super::{j1f, y1f}; diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs index c0872a7829d55..becdb5620a903 100644 --- a/library/compiler-builtins/libm/src/math/roundf.rs +++ b/library/compiler-builtins/libm/src/math/roundf.rs @@ -7,6 +7,8 @@ pub fn roundf(x: f32) -> f32 { truncf(x + copysignf(0.5 - 0.25 * f32::EPSILON, x)) } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { use super::roundf; diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs index 2725caad63c7c..83c9f40ee3a02 100644 --- a/library/compiler-builtins/libm/src/math/sincosf.rs +++ b/library/compiler-builtins/libm/src/math/sincosf.rs @@ -122,6 +122,8 @@ pub fn sincosf(x: f32) -> (f32, f32) { } } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { use super::sincosf; diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index ee868c8c8111e..00b20e578be91 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -128,6 +128,8 @@ pub fn sqrtf(x: f32) -> f32 { } } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { use super::*; diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs index a4c001629a24a..20d5b73bd675e 100644 --- a/library/compiler-builtins/libm/src/math/truncf.rs +++ b/library/compiler-builtins/libm/src/math/truncf.rs @@ -31,6 +31,8 @@ pub fn truncf(x: f32) -> f32 { f32::from_bits(i) } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { #[test] From 7a67cce08845f95c342de39442e41a713939113f Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 3 Jan 2022 19:06:54 +0100 Subject: [PATCH 0976/4206] Disable i686-unknown-linux-gnu tests for now --- library/compiler-builtins/libm/.github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 80ce4ebd5a69c..decd71f5c7a07 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -12,7 +12,7 @@ jobs: - arm-unknown-linux-gnueabi - arm-unknown-linux-gnueabihf - armv7-unknown-linux-gnueabihf - - i686-unknown-linux-gnu + # - i686-unknown-linux-gnu - mips-unknown-linux-gnu - mips64-unknown-linux-gnuabi64 - mips64el-unknown-linux-gnuabi64 From 54a57001f80274e2d8885b742aa9117061d5e93e Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 3 Jan 2022 19:52:31 +0100 Subject: [PATCH 0977/4206] Ignore some functions which don't match musl --- library/compiler-builtins/libm/build.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 9af6dec938b17..13c3fa1cca03e 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -26,7 +26,19 @@ mod musl_reference_tests { // These files are all internal functions or otherwise miscellaneous, not // defining a function we want to test. - const IGNORED_FILES: &[&str] = &["fenv.rs"]; + const IGNORED_FILES: &[&str] = &[ + "fenv.rs", + // These are giving slightly different results compared to musl + "lgamma.rs", + "lgammaf.rs", + "tgamma.rs", + "j0.rs", + "j0f.rs", + "jn.rs", + "jnf.rs", + "j1.rs", + "j1f.rs", + ]; struct Function { name: String, From 4f5d1524fd60c59a0e070facd1da8e2d15c23337 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 3 Jan 2022 21:32:08 +0100 Subject: [PATCH 0978/4206] Fix no-panic --- library/compiler-builtins/libm/Cargo.toml | 4 ++++ library/compiler-builtins/libm/ci/run.sh | 3 +++ 2 files changed, 7 insertions(+) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 106de51dfb61e..3a6c5851b718d 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -33,3 +33,7 @@ no-panic = "0.1.8" [build-dependencies] rand = { version = "0.6.5", optional = true } + +# This is needed for no-panic to correctly detect the lack of panics +[profile.release] +lto = "fat" diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index ed253ab0d10ab..d0cd42a8d0b84 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -5,6 +5,9 @@ TARGET=$1 CMD="cargo test --all --target $TARGET" +# Needed for no-panic to correct detect a lack of panics +export RUSTFLAGS="$RUSTFLAGS -Ccodegen-units=1" + # stable by default $CMD $CMD --release From eb26f75f637c7492e4ef204088e3b438b921afac Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 4 Jan 2022 00:09:07 +0100 Subject: [PATCH 0979/4206] Disable musl tests on powerpc64 --- library/compiler-builtins/libm/build.rs | 7 +++++++ library/compiler-builtins/libm/src/lib.rs | 2 ++ 2 files changed, 9 insertions(+) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 13c3fa1cca03e..80145a9ccac97 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -18,6 +18,7 @@ fn main() { mod musl_reference_tests { use rand::seq::SliceRandom; use rand::Rng; + use std::env; use std::fs; use std::process::Command; @@ -60,6 +61,12 @@ mod musl_reference_tests { } pub fn generate() { + // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + if target_arch == "powerpc64" { + return; + } + let files = fs::read_dir("src/math") .unwrap() .map(|f| f.unwrap().path()) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index bbc79ecad56f7..29742b4510c82 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -51,5 +51,7 @@ pub fn _eq(a: f64, b: f64) -> Result<(), u64> { } } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[cfg(all(test, feature = "musl-reference-tests"))] include!(concat!(env!("OUT_DIR"), "/musl-tests.rs")); From d3fb52a7af8ba99ba8e1861d3453499b7ef8faa4 Mon Sep 17 00:00:00 2001 From: Peter Michael Green Date: Wed, 22 Dec 2021 00:56:18 +0000 Subject: [PATCH 0980/4206] force test_near_pi in rem_pio2.rs to be evaluated at runtime not compiletime. --- .../compiler-builtins/libm/src/math/rem_pio2.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 46f7c38ffedab..f58fa359bab45 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -190,20 +190,28 @@ mod tests { #[test] fn test_near_pi() { + let arg = 3.141592025756836; + force_eval!(arg); assert_eq!( - rem_pio2(3.141592025756836), + rem_pio2(arg), (2, -6.278329573009626e-7, -2.1125998133974653e-23) ); + let arg = 3.141592033207416; + force_eval!(arg); assert_eq!( - rem_pio2(3.141592033207416), + rem_pio2(arg), (2, -6.20382377148128e-7, -2.1125998133974653e-23) ); + let arg = 3.141592144966125; + force_eval!(arg); assert_eq!( - rem_pio2(3.141592144966125), + rem_pio2(arg), (2, -5.086236681942706e-7, -2.1125998133974653e-23) ); + let arg = 3.141592979431152; + force_eval!(arg); assert_eq!( - rem_pio2(3.141592979431152), + rem_pio2(arg), (2, 3.2584135866119817e-7, -2.1125998133974653e-23) ); } From 17c907329893aca7c966aa6117f3e008315d5681 Mon Sep 17 00:00:00 2001 From: Peter Michael Green Date: Tue, 5 Jan 2021 17:32:30 +0000 Subject: [PATCH 0981/4206] Fix testcases on x87 --- .../compiler-builtins/libm/src/math/ceil.rs | 19 ++++++++++ .../compiler-builtins/libm/src/math/floor.rs | 19 ++++++++++ .../compiler-builtins/libm/src/math/j1f.rs | 6 +++- .../libm/src/math/rem_pio2f.rs | 4 ++- .../libm/src/math/sincosf.rs | 36 ++++++++++++++++--- 5 files changed, 78 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index eda28b9a0f2b9..22d89297138c9 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -1,3 +1,4 @@ +#![allow(unreachable_code)] use core::f64; const TOINT: f64 = 1. / f64::EPSILON; @@ -15,6 +16,24 @@ pub fn ceil(x: f64) -> f64 { return unsafe { ::core::intrinsics::ceilf64(x) } } } + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + { + //use an alternative implementation on x86, because the + //main implementation fails with the x87 FPU used by + //debian i386, probablly due to excess precision issues. + //basic implementation taken from https://github.com/rust-lang/libm/issues/219 + use super::fabs; + if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { + let truncated = x as i64 as f64; + if truncated < x { + return truncated + 1.0; + } else { + return truncated; + } + } else { + return x; + } + } let u: u64 = x.to_bits(); let e: i64 = (u >> 52 & 0x7ff) as i64; let y: f64; diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index b2b760570dee2..d09f9a1a1f81f 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -1,3 +1,4 @@ +#![allow(unreachable_code)] use core::f64; const TOINT: f64 = 1. / f64::EPSILON; @@ -15,6 +16,24 @@ pub fn floor(x: f64) -> f64 { return unsafe { ::core::intrinsics::floorf64(x) } } } + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + { + //use an alternative implementation on x86, because the + //main implementation fails with the x87 FPU used by + //debian i386, probablly due to excess precision issues. + //basic implementation taken from https://github.com/rust-lang/libm/issues/219 + use super::fabs; + if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { + let truncated = x as i64 as f64; + if truncated > x { + return truncated - 1.0; + } else { + return truncated; + } + } else { + return x; + } + } let ui = x.to_bits(); let e = ((ui >> 52) & 0x7ff) as i32; diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs index 33694908ca23b..225b719bf96cc 100644 --- a/library/compiler-builtins/libm/src/math/j1f.rs +++ b/library/compiler-builtins/libm/src/math/j1f.rs @@ -369,6 +369,10 @@ mod tests { } #[test] fn test_y1f_2002() { - assert_eq!(y1f(2.0000002_f32), -0.10703229_f32); + //allow slightly different result on x87 + let res = y1f(2.0000002_f32); + if res != -0.10703231_f32 { + assert_eq!(res, -0.10703229_f32); + } } } diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs index 5d392ba2d7fe0..4d4499b986ef4 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2f.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2f.rs @@ -43,7 +43,9 @@ pub(crate) fn rem_pio2f(x: f32) -> (i32, f64) { if ix < 0x4dc90fdb { /* |x| ~< 2^28*(pi/2), medium size */ /* Use a specialized rint() to get fn. Assume round-to-nearest. */ - let f_n = x64 * INV_PIO2 + TOINT - TOINT; + // use to_bits and from_bits to force rounding to storage format on + // x87. + let f_n = f64::from_bits((x64 * INV_PIO2 + TOINT).to_bits()) - TOINT; return (f_n as i32, x64 - f_n * PIO2_1 - f_n * PIO2_1T); } if ix >= 0x7f800000 { diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs index 83c9f40ee3a02..5304e8ca02768 100644 --- a/library/compiler-builtins/libm/src/math/sincosf.rs +++ b/library/compiler-builtins/libm/src/math/sincosf.rs @@ -147,10 +147,38 @@ mod tests { let (s_minus, c_minus) = sincosf(theta - 2. * PI); const TOLERANCE: f32 = 1e-6; - assert!((s - s_plus).abs() < TOLERANCE); - assert!((s - s_minus).abs() < TOLERANCE); - assert!((c - c_plus).abs() < TOLERANCE); - assert!((c - c_minus).abs() < TOLERANCE); + assert!( + (s - s_plus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + s_plus, + (s - s_plus).abs(), + TOLERANCE + ); + assert!( + (s - s_minus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + s_minus, + (s - s_minus).abs(), + TOLERANCE + ); + assert!( + (c - c_plus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + c, + c_plus, + (c - c_plus).abs(), + TOLERANCE + ); + assert!( + (c - c_minus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + c, + c_minus, + (c - c_minus).abs(), + TOLERANCE + ); } } } From 874209b56c5ab1ce15e6c499bc83bcdecf5f7c74 Mon Sep 17 00:00:00 2001 From: Peter Michael Green Date: Tue, 21 Dec 2021 22:41:29 +0000 Subject: [PATCH 0982/4206] Use force_eval instead of to_bits/from_bits combination, Using to_bits/from_bits to force conversion to storage format apparently doesn't work in release mode. Also add an architecture conditional to avoid pessimising other architectures. --- library/compiler-builtins/libm/src/math/rem_pio2f.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs index 4d4499b986ef4..3ce8f9ab1779a 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2f.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2f.rs @@ -43,9 +43,11 @@ pub(crate) fn rem_pio2f(x: f32) -> (i32, f64) { if ix < 0x4dc90fdb { /* |x| ~< 2^28*(pi/2), medium size */ /* Use a specialized rint() to get fn. Assume round-to-nearest. */ - // use to_bits and from_bits to force rounding to storage format on - // x87. - let f_n = f64::from_bits((x64 * INV_PIO2 + TOINT).to_bits()) - TOINT; + 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")))]force_eval!(tmp); + let f_n = tmp - TOINT; return (f_n as i32, x64 - f_n * PIO2_1 - f_n * PIO2_1T); } if ix >= 0x7f800000 { From e95ea2b11dcadd99fa9b0b0057b6cfe2d299ac11 Mon Sep 17 00:00:00 2001 From: Peter Michael Green Date: Tue, 21 Dec 2021 23:53:06 +0000 Subject: [PATCH 0983/4206] Add forced rounding to storage format for x87 to rem_pio2.rs as well. --- .../libm/src/math/rem_pio2.rs | 6 +- .../compiler-builtins/libm/src/math/sincos.rs | 74 +++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index f58fa359bab45..4ac9415b5f4d1 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -50,7 +50,11 @@ pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { fn medium(x: f64, ix: u32) -> (i32, f64, f64) { /* rint(x/(pi/2)), Assume round-to-nearest. */ - let f_n = x as f64 * INV_PIO2 + TO_INT - TO_INT; + let tmp = x as f64 * 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")))]force_eval!(tmp); + let f_n = tmp - TO_INT; let n = f_n as i32; let mut r = x - f_n * PIO2_1; let mut w = f_n * PIO2_1T; /* 1st round, good to 85 bits */ diff --git a/library/compiler-builtins/libm/src/math/sincos.rs b/library/compiler-builtins/libm/src/math/sincos.rs index d49f65c970795..bfc4561f8b2b7 100644 --- a/library/compiler-builtins/libm/src/math/sincos.rs +++ b/library/compiler-builtins/libm/src/math/sincos.rs @@ -57,3 +57,77 @@ pub fn sincos(x: f64) -> (f64, f64) { _ => (0.0, 1.0), } } + +// These tests are based on those from sincosf.rs +#[cfg(test)] +mod tests { + use super::sincos; + + const TOLERANCE: f64 = 1e-6; + + #[test] + fn with_pi() { + let (s, c) = sincos(core::f64::consts::PI); + assert!( + (s - 0.0).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + 0.0, + (s - 0.0).abs(), + TOLERANCE + ); + assert!( + (c + 1.0).abs() < TOLERANCE, + "|{} + {}| = {} >= {}", + c, + 1.0, + (s + 1.0).abs(), + TOLERANCE + ); + } + + #[test] + fn rotational_symmetry() { + use core::f64::consts::PI; + const N: usize = 24; + for n in 0..N { + let theta = 2. * PI * (n as f64) / (N as f64); + let (s, c) = sincos(theta); + let (s_plus, c_plus) = sincos(theta + 2. * PI); + let (s_minus, c_minus) = sincos(theta - 2. * PI); + + assert!( + (s - s_plus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + s_plus, + (s - s_plus).abs(), + TOLERANCE + ); + assert!( + (s - s_minus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + s_minus, + (s - s_minus).abs(), + TOLERANCE + ); + assert!( + (c - c_plus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + c, + c_plus, + (c - c_plus).abs(), + TOLERANCE + ); + assert!( + (c - c_minus).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + c, + c_minus, + (c - c_minus).abs(), + TOLERANCE + ); + } + } +} From e3c3304557ba9f3888215f995d1bbf58ee1037e9 Mon Sep 17 00:00:00 2001 From: Peter Michael Green Date: Wed, 22 Dec 2021 00:21:25 +0000 Subject: [PATCH 0984/4206] round to storage format in some tests before comparison to prevent spurious errors on x87. --- library/compiler-builtins/libm/src/math/fma.rs | 5 ++++- library/compiler-builtins/libm/src/math/pow.rs | 2 ++ library/compiler-builtins/libm/src/math/sin.rs | 4 +++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 85d842119cb3b..c20de94a57e06 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -218,7 +218,10 @@ mod tests { -0.00000000000000022204460492503126, ); - assert_eq!(fma(-0.992, -0.992, -0.992), -0.007936000000000007,); + 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")))]force_eval!(result); + assert_eq!(result, -0.007936000000000007,); } #[test] diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index f79680a05d015..3249e7eea0339 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -484,6 +484,8 @@ mod tests { let exp = expected(*val); let res = computed(*val); + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]force_eval!(exp); + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]force_eval!(res); assert!( if exp.is_nan() { res.is_nan() diff --git a/library/compiler-builtins/libm/src/math/sin.rs b/library/compiler-builtins/libm/src/math/sin.rs index 1329b41a9d602..a562aa6e4a07f 100644 --- a/library/compiler-builtins/libm/src/math/sin.rs +++ b/library/compiler-builtins/libm/src/math/sin.rs @@ -81,5 +81,7 @@ pub fn sin(x: f64) -> f64 { fn test_near_pi() { let x = f64::from_bits(0x400921fb000FD5DD); // 3.141592026217707 let sx = f64::from_bits(0x3ea50d15ced1a4a2); // 6.273720864039205e-7 - assert_eq!(sin(x), sx); + let result = sin(x); + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]force_eval!(result); + assert_eq!(result, sx); } From 94b416e4960830abe9afeb896df00b3931008089 Mon Sep 17 00:00:00 2001 From: Peter Michael Green Date: Tue, 4 Jan 2022 20:38:09 +0000 Subject: [PATCH 0985/4206] only allow x87-specific result in j1f.rs test on x87 --- library/compiler-builtins/libm/src/math/j1f.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs index 225b719bf96cc..775ff2b2ef1c1 100644 --- a/library/compiler-builtins/libm/src/math/j1f.rs +++ b/library/compiler-builtins/libm/src/math/j1f.rs @@ -371,8 +371,7 @@ mod tests { fn test_y1f_2002() { //allow slightly different result on x87 let res = y1f(2.0000002_f32); - if res != -0.10703231_f32 { - assert_eq!(res, -0.10703229_f32); - } + if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) && (res == -0.10703231_f32) { return }; + assert_eq!(res, -0.10703229_f32); } } From f8c8c8b2fe3610924ac062943bd210cb275196bb Mon Sep 17 00:00:00 2001 From: Peter Michael Green Date: Tue, 4 Jan 2022 20:51:40 +0000 Subject: [PATCH 0986/4206] allow force_eval! to produce a result and use that result to more explicitly force rounding on x87. --- library/compiler-builtins/libm/src/math/fma.rs | 3 ++- library/compiler-builtins/libm/src/math/mod.rs | 2 +- library/compiler-builtins/libm/src/math/pow.rs | 6 ++++-- library/compiler-builtins/libm/src/math/rem_pio2.rs | 11 ++++++----- library/compiler-builtins/libm/src/math/rem_pio2f.rs | 3 ++- library/compiler-builtins/libm/src/math/sin.rs | 3 ++- 6 files changed, 17 insertions(+), 11 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index c20de94a57e06..516f9ad3a77fe 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -220,7 +220,8 @@ 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")))]force_eval!(result); + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let result = force_eval!(result); assert_eq!(result, -0.007936000000000007,); } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index ceeee0b31fb15..7f4c8bcf4c07c 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -1,7 +1,7 @@ macro_rules! force_eval { ($e:expr) => { unsafe { - ::core::ptr::read_volatile(&$e); + ::core::ptr::read_volatile(&$e) } }; } diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 3249e7eea0339..6a19ae601116e 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -484,8 +484,10 @@ mod tests { let exp = expected(*val); let res = computed(*val); - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]force_eval!(exp); - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]force_eval!(res); + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let exp = force_eval!(exp); + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let res = force_eval!(res); assert!( if exp.is_nan() { res.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 4ac9415b5f4d1..644616f2df84d 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -53,7 +53,8 @@ pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { let tmp = x as f64 * 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")))]force_eval!(tmp); + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let tmp = force_eval!(tmp); let f_n = tmp - TO_INT; let n = f_n as i32; let mut r = x - f_n * PIO2_1; @@ -195,25 +196,25 @@ mod tests { #[test] fn test_near_pi() { let arg = 3.141592025756836; - force_eval!(arg); + let arg = force_eval!(arg); assert_eq!( rem_pio2(arg), (2, -6.278329573009626e-7, -2.1125998133974653e-23) ); let arg = 3.141592033207416; - force_eval!(arg); + let arg = force_eval!(arg); assert_eq!( rem_pio2(arg), (2, -6.20382377148128e-7, -2.1125998133974653e-23) ); let arg = 3.141592144966125; - force_eval!(arg); + let arg = force_eval!(arg); assert_eq!( rem_pio2(arg), (2, -5.086236681942706e-7, -2.1125998133974653e-23) ); let arg = 3.141592979431152; - force_eval!(arg); + let arg = force_eval!(arg); assert_eq!( rem_pio2(arg), (2, 3.2584135866119817e-7, -2.1125998133974653e-23) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs index 3ce8f9ab1779a..775f5d750fb11 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2f.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2f.rs @@ -46,7 +46,8 @@ 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")))]force_eval!(tmp); + #[cfg(all(target_arch = "x86", not(target_feature = "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); } diff --git a/library/compiler-builtins/libm/src/math/sin.rs b/library/compiler-builtins/libm/src/math/sin.rs index a562aa6e4a07f..a53843dcdaeb9 100644 --- a/library/compiler-builtins/libm/src/math/sin.rs +++ b/library/compiler-builtins/libm/src/math/sin.rs @@ -82,6 +82,7 @@ fn test_near_pi() { let x = f64::from_bits(0x400921fb000FD5DD); // 3.141592026217707 let sx = f64::from_bits(0x3ea50d15ced1a4a2); // 6.273720864039205e-7 let result = sin(x); - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]force_eval!(result); + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let result = force_eval!(result); assert_eq!(result, sx); } From 8d91281fcc05a0cabd8c606a8999bc0ecc775d53 Mon Sep 17 00:00:00 2001 From: Peter Michael Green Date: Wed, 22 Dec 2021 01:50:25 +0000 Subject: [PATCH 0987/4206] Apply formatting fixes from CI --- .../compiler-builtins/libm/src/math/j1f.rs | 5 +++- .../compiler-builtins/libm/src/math/mod.rs | 4 +-- .../compiler-builtins/libm/src/math/sincos.rs | 28 +++++++++---------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs index 775ff2b2ef1c1..c39f8ff7e9648 100644 --- a/library/compiler-builtins/libm/src/math/j1f.rs +++ b/library/compiler-builtins/libm/src/math/j1f.rs @@ -371,7 +371,10 @@ 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) { return }; + if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) && (res == -0.10703231_f32) + { + return; + } assert_eq!(res, -0.10703229_f32); } } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 7f4c8bcf4c07c..81bfc53ed854a 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -1,8 +1,6 @@ macro_rules! force_eval { ($e:expr) => { - unsafe { - ::core::ptr::read_volatile(&$e) - } + unsafe { ::core::ptr::read_volatile(&$e) } }; } diff --git a/library/compiler-builtins/libm/src/math/sincos.rs b/library/compiler-builtins/libm/src/math/sincos.rs index bfc4561f8b2b7..4ab588412a5e1 100644 --- a/library/compiler-builtins/libm/src/math/sincos.rs +++ b/library/compiler-builtins/libm/src/math/sincos.rs @@ -69,21 +69,21 @@ mod tests { fn with_pi() { let (s, c) = sincos(core::f64::consts::PI); assert!( - (s - 0.0).abs() < TOLERANCE, - "|{} - {}| = {} >= {}", - s, - 0.0, - (s - 0.0).abs(), - TOLERANCE - ); + (s - 0.0).abs() < TOLERANCE, + "|{} - {}| = {} >= {}", + s, + 0.0, + (s - 0.0).abs(), + TOLERANCE + ); assert!( - (c + 1.0).abs() < TOLERANCE, - "|{} + {}| = {} >= {}", - c, - 1.0, - (s + 1.0).abs(), - TOLERANCE - ); + (c + 1.0).abs() < TOLERANCE, + "|{} + {}| = {} >= {}", + c, + 1.0, + (s + 1.0).abs(), + TOLERANCE + ); } #[test] From 554fa533abb120fe78e2a9d2c5da3d67b70aa13c Mon Sep 17 00:00:00 2001 From: Daniel Sommermann Date: Thu, 27 Jan 2022 11:53:50 -0800 Subject: [PATCH 0988/4206] Stop emitting duplicate symbols for `armv7-linux-androideabi` The change in 186517b3266a7bb2b2310927f7342ea7f41790c3 was intended to affect only `arm-linux-androideabi` but also affected `armv7-linux-androideabi` which is not a pre-ARMv6 architecture. Fixes #449 --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index dc1cd1d23c71a..2b34540dc44e6 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -83,7 +83,7 @@ fn main() { // rustc target (arm-linux-androideabi). if llvm_target[0] == "armv4t" || llvm_target[0] == "armv5te" - || llvm_target.get(2) == Some(&"androideabi") + || target == "arm-linux-androideabi" { println!("cargo:rustc-cfg=kernel_user_helpers") } From f5fa287bc2ac15e5023db1c0ae8abdbeddacfdd3 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 28 Jan 2022 12:47:27 +0000 Subject: [PATCH 0989/4206] Bump to 0.1.67 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 3f4c96745efe8..a8278f0b81611 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.66" +version = "0.1.67" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From c51299d63abd66542afc51e34b03a27da6b48f06 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 6 Feb 2022 09:20:19 +0000 Subject: [PATCH 0990/4206] Fix run-docker.sh so it can be run locally --- library/compiler-builtins/ci/run-docker.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 4bb2a78d9342b..8c4af0eff20bb 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -19,7 +19,7 @@ run() { -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ -e RUST_COMPILER_RT_ROOT \ - -v $(dirname $(dirname `which cargo`)):/cargo \ + -v "${HOME}/.cargo":/cargo \ -v `pwd`/target:/target \ -v `pwd`:/checkout:ro \ -v `rustc --print sysroot`:/rust:ro \ From f03c7fd6afe41392479bb921e118abf6f2f5c136 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 6 Feb 2022 09:20:43 +0000 Subject: [PATCH 0991/4206] Wrap all intrinsics in the intrinsics! macro This ensures that each intrinsic ends up in a separate module, which in turn (because rustc treats compiler_builtins specially) will result in each intrinsic ending up in its own object file. This allows the linker to only pick up object files for intrinsics that are missing and avoids duplicate symbol definition errors. --- library/compiler-builtins/src/arm.rs | 376 +++++++++------------ library/compiler-builtins/src/arm_linux.rs | 21 +- library/compiler-builtins/src/macros.rs | 119 +++++-- library/compiler-builtins/src/mem/mod.rs | 112 +++--- library/compiler-builtins/src/x86.rs | 148 ++++---- library/compiler-builtins/src/x86_64.rs | 158 +++++---- 6 files changed, 469 insertions(+), 465 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 3660825aa73cf..95bde51166209 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -3,251 +3,181 @@ use core::intrinsics; -// NOTE This function and the ones below are implemented using assembly because they are using a -// custom calling convention which can't be implemented using a normal Rust function. -// NOTE The only difference between the iOS and non-iOS versions of those functions is that the iOS -// versions use 3 leading underscores in the names of called functions instead of 2. -#[cfg(not(any(target_os = "ios", target_env = "msvc")))] -#[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe extern "C" fn __aeabi_uidivmod() { - core::arch::asm!( - "push {{lr}}", - "sub sp, sp, #4", - "mov r2, sp", - "bl __udivmodsi4", - "ldr r1, [sp]", - "add sp, sp, #4", - "pop {{pc}}", - options(noreturn) - ); -} - +// iOS symbols have a leading underscore. #[cfg(target_os = "ios")] -#[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe extern "C" fn __aeabi_uidivmod() { - core::arch::asm!( - "push {{lr}}", - "sub sp, sp, #4", - "mov r2, sp", - "bl ___udivmodsi4", - "ldr r1, [sp]", - "add sp, sp, #4", - "pop {{pc}}", - options(noreturn) - ); +macro_rules! bl { + ($func:literal) => { + concat!("bl _", $func) + }; } - #[cfg(not(target_os = "ios"))] -#[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe extern "C" fn __aeabi_uldivmod() { - core::arch::asm!( - "push {{r4, lr}}", - "sub sp, sp, #16", - "add r4, sp, #8", - "str r4, [sp]", - "bl __udivmoddi4", - "ldr r2, [sp, #8]", - "ldr r3, [sp, #12]", - "add sp, sp, #16", - "pop {{r4, pc}}", - options(noreturn) - ); -} - -#[cfg(target_os = "ios")] -#[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe extern "C" fn __aeabi_uldivmod() { - core::arch::asm!( - "push {{r4, lr}}", - "sub sp, sp, #16", - "add r4, sp, #8", - "str r4, [sp]", - "bl ___udivmoddi4", - "ldr r2, [sp, #8]", - "ldr r3, [sp, #12]", - "add sp, sp, #16", - "pop {{r4, pc}}", - options(noreturn) - ); -} - -#[cfg(not(target_os = "ios"))] -#[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe extern "C" fn __aeabi_idivmod() { - core::arch::asm!( - "push {{r0, r1, r4, lr}}", - "bl __aeabi_idiv", - "pop {{r1, r2}}", - "muls r2, r2, r0", - "subs r1, r1, r2", - "pop {{r4, pc}}", - options(noreturn) - ); -} - -#[cfg(target_os = "ios")] -#[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe extern "C" fn __aeabi_idivmod() { - core::arch::asm!( - "push {{r0, r1, r4, lr}}", - "bl ___aeabi_idiv", - "pop {{r1, r2}}", - "muls r2, r2, r0", - "subs r1, r1, r2", - "pop {{r4, pc}}", - options(noreturn) - ); -} +macro_rules! bl { + ($func:literal) => { + concat!("bl ", $func) + }; +} + +intrinsics! { + // NOTE This function and the ones below are implemented using assembly because they are using a + // custom calling convention which can't be implemented using a normal Rust function. + #[naked] + #[cfg(not(target_env = "msvc"))] + pub unsafe extern "C" fn __aeabi_uidivmod() { + core::arch::asm!( + "push {{lr}}", + "sub sp, sp, #4", + "mov r2, sp", + bl!("__udivmodsi4"), + "ldr r1, [sp]", + "add sp, sp, #4", + "pop {{pc}}", + options(noreturn) + ); + } -#[cfg(not(target_os = "ios"))] -#[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe extern "C" fn __aeabi_ldivmod() { - core::arch::asm!( - "push {{r4, lr}}", - "sub sp, sp, #16", - "add r4, sp, #8", - "str r4, [sp]", - "bl __divmoddi4", - "ldr r2, [sp, #8]", - "ldr r3, [sp, #12]", - "add sp, sp, #16", - "pop {{r4, pc}}", - options(noreturn) - ); -} + #[naked] + pub unsafe extern "C" fn __aeabi_uldivmod() { + core::arch::asm!( + "push {{r4, lr}}", + "sub sp, sp, #16", + "add r4, sp, #8", + "str r4, [sp]", + bl!("__udivmodsi4"), + "ldr r2, [sp, #8]", + "ldr r3, [sp, #12]", + "add sp, sp, #16", + "pop {{r4, pc}}", + options(noreturn) + ); + } -#[cfg(target_os = "ios")] -#[naked] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe extern "C" fn __aeabi_ldivmod() { - core::arch::asm!( - "push {{r4, lr}}", - "sub sp, sp, #16", - "add r4, sp, #8", - "str r4, [sp]", - "bl ___divmoddi4", - "ldr r2, [sp, #8]", - "ldr r3, [sp, #12]", - "add sp, sp, #16", - "pop {{r4, pc}}", - options(noreturn) - ); -} + #[naked] + pub unsafe extern "C" fn __aeabi_idivmod() { + core::arch::asm!( + "push {{r0, r1, r4, lr}}", + bl!("__aeabi_idiv"), + "pop {{r1, r2}}", + "muls r2, r2, r0", + "subs r1, r1, r2", + "pop {{r4, pc}}", + options(noreturn) + ); + } -// The following functions use weak linkage to allow users to override -// with custom implementation. -// FIXME: The `*4` and `*8` variants should be defined as aliases. + #[naked] + pub unsafe extern "C" fn __aeabi_ldivmod() { + core::arch::asm!( + "push {{r4, lr}}", + "sub sp, sp, #16", + "add r4, sp, #8", + "str r4, [sp]", + bl!("__divmoddi4"), + "ldr r2, [sp, #8]", + "ldr r3, [sp, #12]", + "add sp, sp, #16", + "pop {{r4, pc}}", + options(noreturn) + ); + } -#[cfg(not(target_os = "ios"))] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] -pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { - ::mem::memcpy(dest, src, n); -} + // The following functions use weak linkage to allow users to override + // with custom implementation. + // FIXME: The `*4` and `*8` variants should be defined as aliases. -#[cfg(not(target_os = "ios"))] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] -pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, mut n: usize) { - // We are guaranteed 4-alignment, so accessing at u32 is okay. - let mut dest = dest as *mut u32; - let mut src = src as *mut u32; + #[cfg(not(target_os = "ios"))] + #[linkage = "weak"] + pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { + ::mem::memcpy(dest, src, n); + } - while n >= 4 { - *dest = *src; - dest = dest.offset(1); - src = src.offset(1); - n -= 4; + #[cfg(not(target_os = "ios"))] + #[linkage = "weak"] + pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { + // We are guaranteed 4-alignment, so accessing at u32 is okay. + let mut dest = dest as *mut u32; + let mut src = src as *mut u32; + let mut n = n; + + while n >= 4 { + *dest = *src; + dest = dest.offset(1); + src = src.offset(1); + n -= 4; + } + + __aeabi_memcpy(dest as *mut u8, src as *const u8, n); } - __aeabi_memcpy(dest as *mut u8, src as *const u8, n); -} + #[cfg(not(target_os = "ios"))] + #[linkage = "weak"] + pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { + __aeabi_memcpy4(dest, src, n); + } -#[cfg(not(target_os = "ios"))] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] -pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { - __aeabi_memcpy4(dest, src, n); -} + #[cfg(not(target_os = "ios"))] + #[linkage = "weak"] + pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { + ::mem::memmove(dest, src, n); + } -#[cfg(not(target_os = "ios"))] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] -pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { - ::mem::memmove(dest, src, n); -} + #[cfg(not(any(target_os = "ios", target_env = "msvc")))] + #[linkage = "weak"] + pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { + __aeabi_memmove(dest, src, n); + } -#[cfg(not(any(target_os = "ios", target_env = "msvc")))] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] -pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { - __aeabi_memmove(dest, src, n); -} + #[cfg(not(any(target_os = "ios", target_env = "msvc")))] + #[linkage = "weak"] + pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { + __aeabi_memmove(dest, src, n); + } -#[cfg(not(any(target_os = "ios", target_env = "msvc")))] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] -pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { - __aeabi_memmove(dest, src, n); -} + #[cfg(not(target_os = "ios"))] + #[linkage = "weak"] + pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { + // Note the different argument order + ::mem::memset(dest, c, n); + } -#[cfg(not(target_os = "ios"))] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] -pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { - // Note the different argument order - ::mem::memset(dest, c, n); -} + #[cfg(not(target_os = "ios"))] + #[linkage = "weak"] + pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { + let mut dest = dest as *mut u32; + let mut n = n; -#[cfg(not(target_os = "ios"))] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] -pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, mut n: usize, c: i32) { - let mut dest = dest as *mut u32; + let byte = (c as u32) & 0xff; + let c = (byte << 24) | (byte << 16) | (byte << 8) | byte; - let byte = (c as u32) & 0xff; - let c = (byte << 24) | (byte << 16) | (byte << 8) | byte; + while n >= 4 { + *dest = c; + dest = dest.offset(1); + n -= 4; + } - while n >= 4 { - *dest = c; - dest = dest.offset(1); - n -= 4; + __aeabi_memset(dest as *mut u8, n, byte as i32); } - __aeabi_memset(dest as *mut u8, n, byte as i32); -} - -#[cfg(not(target_os = "ios"))] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] -pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { - __aeabi_memset4(dest, n, c); -} + #[cfg(not(target_os = "ios"))] + #[linkage = "weak"] + pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { + __aeabi_memset4(dest, n, c); + } -#[cfg(not(target_os = "ios"))] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] -pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { - __aeabi_memset(dest, n, 0); -} + #[cfg(not(target_os = "ios"))] + #[linkage = "weak"] + pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { + __aeabi_memset(dest, n, 0); + } -#[cfg(not(any(target_os = "ios", target_env = "msvc")))] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] -pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { - __aeabi_memset4(dest, n, 0); -} + #[cfg(not(any(target_os = "ios", target_env = "msvc")))] + #[linkage = "weak"] + pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { + __aeabi_memset4(dest, n, 0); + } -#[cfg(not(any(target_os = "ios", target_env = "msvc")))] -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -#[linkage = "weak"] -pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { - __aeabi_memset4(dest, n, 0); + #[cfg(not(any(target_os = "ios", target_env = "msvc")))] + #[linkage = "weak"] + pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { + __aeabi_memset4(dest, n, 0); + } } diff --git a/library/compiler-builtins/src/arm_linux.rs b/library/compiler-builtins/src/arm_linux.rs index e710c1ab98a59..df1723d99c611 100644 --- a/library/compiler-builtins/src/arm_linux.rs +++ b/library/compiler-builtins/src/arm_linux.rs @@ -90,17 +90,19 @@ unsafe fn atomic_cmpxchg(ptr: *mut T, oldval: u32, newval: u32) -> u32 { macro_rules! atomic_rmw { ($name:ident, $ty:ty, $op:expr) => { - #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - pub unsafe extern "C" fn $name(ptr: *mut $ty, val: $ty) -> $ty { - atomic_rmw(ptr, |x| $op(x as $ty, val) as u32) as $ty + intrinsics! { + pub unsafe extern "C" fn $name(ptr: *mut $ty, val: $ty) -> $ty { + atomic_rmw(ptr, |x| $op(x as $ty, val) as u32) as $ty + } } }; } macro_rules! atomic_cmpxchg { ($name:ident, $ty:ty) => { - #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - pub unsafe extern "C" fn $name(ptr: *mut $ty, oldval: $ty, newval: $ty) -> $ty { - atomic_cmpxchg(ptr, oldval as u32, newval as u32) as $ty + intrinsics! { + pub unsafe extern "C" fn $name(ptr: *mut $ty, oldval: $ty, newval: $ty) -> $ty { + atomic_cmpxchg(ptr, oldval as u32, newval as u32) as $ty + } } }; } @@ -205,7 +207,8 @@ atomic_cmpxchg!(__sync_val_compare_and_swap_1, u8); atomic_cmpxchg!(__sync_val_compare_and_swap_2, u16); atomic_cmpxchg!(__sync_val_compare_and_swap_4, u32); -#[cfg_attr(not(feature = "mangled-names"), no_mangle)] -pub unsafe extern "C" fn __sync_synchronize() { - __kuser_memory_barrier(); +intrinsics! { + pub unsafe extern "C" fn __sync_synchronize() { + __kuser_memory_barrier(); + } } diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 214f0795fc543..6926feac055cb 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -76,7 +76,7 @@ macro_rules! intrinsics { ( #[maybe_use_optimized_c_shim] $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { $($body:tt)* } @@ -84,9 +84,9 @@ macro_rules! intrinsics { ) => ( #[cfg($name = "optimized-c")] - pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { extern $abi { - fn $name($($argname: $ty),*) -> $ret; + fn $name($($argname: $ty),*) $(-> $ret)?; } unsafe { $name($($argname),*) @@ -96,7 +96,7 @@ macro_rules! intrinsics { #[cfg(not($name = "optimized-c"))] intrinsics! { $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } } @@ -110,7 +110,7 @@ macro_rules! intrinsics { ( #[aapcs_on_arm] $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { $($body:tt)* } @@ -119,7 +119,7 @@ macro_rules! intrinsics { #[cfg(target_arch = "arm")] intrinsics! { $(#[$($attr)*])* - pub extern "aapcs" fn $name( $($argname: $ty),* ) -> $ret { + pub extern "aapcs" fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } } @@ -127,7 +127,7 @@ macro_rules! intrinsics { #[cfg(not(target_arch = "arm"))] intrinsics! { $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } } @@ -140,7 +140,7 @@ macro_rules! intrinsics { ( #[unadjusted_on_win64] $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { $($body:tt)* } @@ -149,7 +149,7 @@ macro_rules! intrinsics { #[cfg(all(windows, target_pointer_width = "64"))] intrinsics! { $(#[$($attr)*])* - pub extern "unadjusted" fn $name( $($argname: $ty),* ) -> $ret { + pub extern "unadjusted" fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } } @@ -157,7 +157,7 @@ macro_rules! intrinsics { #[cfg(not(all(windows, target_pointer_width = "64")))] intrinsics! { $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } } @@ -175,7 +175,7 @@ macro_rules! intrinsics { ( #[win64_128bit_abi_hack] $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { $($body:tt)* } @@ -183,7 +183,7 @@ macro_rules! intrinsics { ) => ( #[cfg(all(windows, target_arch = "x86_64"))] $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } @@ -193,7 +193,7 @@ macro_rules! intrinsics { pub extern $abi fn $name( $($argname: $ty),* ) -> ::macros::win64_128bit_abi_hack::U64x2 { - let e: $ret = super::$name($($argname),*); + let e: $($ret)? = super::$name($($argname),*); ::macros::win64_128bit_abi_hack::U64x2::from(e) } } @@ -201,7 +201,7 @@ macro_rules! intrinsics { #[cfg(not(all(windows, target_arch = "x86_64")))] intrinsics! { $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } } @@ -216,21 +216,21 @@ macro_rules! intrinsics { ( #[arm_aeabi_alias = $alias:ident] $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { $($body:tt)* } $($rest:tt)* ) => ( #[cfg(target_arch = "arm")] - pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } #[cfg(target_arch = "arm")] pub mod $name { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } } @@ -238,7 +238,7 @@ macro_rules! intrinsics { #[cfg(target_arch = "arm")] pub mod $alias { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - pub extern "aapcs" fn $alias( $($argname: $ty),* ) -> $ret { + pub extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } } @@ -246,7 +246,57 @@ macro_rules! intrinsics { #[cfg(not(target_arch = "arm"))] intrinsics! { $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + + // C mem* functions are only generated when the "mem" feature is enabled. + ( + #[mem_builtin] + $(#[$($attr:tt)*])* + pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + $(#[$($attr)*])* + pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + + #[cfg(feature = "mem")] + pub mod $name { + $(#[$($attr)*])* + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + super::$name($($argname),*) + } + } + + intrinsics!($($rest)*); + ); + + // Naked functions are special: we can't generate wrappers for them since + // they use a custom calling convention. + ( + #[naked] + $(#[$($attr:tt)*])* + pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + pub mod $name { + #[naked] + $(#[$($attr)*])* + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } } @@ -268,21 +318,46 @@ macro_rules! intrinsics { // input we were given. ( $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + + pub mod $name { + $(#[$($attr)*])* + #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + super::$name($($argname),*) + } + } + + intrinsics!($($rest)*); + ); + + // Same as the above for unsafe functions. + ( + $(#[$($attr:tt)*])* + pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { $($body:tt)* } $($rest:tt)* ) => ( $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } pub mod $name { $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } } diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index 2f9a9fd945eac..dce4d87e0a5c0 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -19,53 +19,55 @@ use core::ops::{BitOr, Shl}; )] mod impls; -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -#[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] -pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { - impls::copy_forward(dest, src, n); - dest -} - -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -#[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] -pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { - let delta = (dest as usize).wrapping_sub(src as usize); - if delta >= n { - // We can copy forwards because either dest is far enough ahead of src, - // or src is ahead of dest (and delta overflowed). +intrinsics! { + #[mem_builtin] + #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] + pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { impls::copy_forward(dest, src, n); - } else { - impls::copy_backward(dest, src, n); + dest } - dest -} -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -#[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] -pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { - impls::set_bytes(s, c as u8, n); - s -} + #[mem_builtin] + #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] + pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { + let delta = (dest as usize).wrapping_sub(src as usize); + if delta >= n { + // We can copy forwards because either dest is far enough ahead of src, + // or src is ahead of dest (and delta overflowed). + impls::copy_forward(dest, src, n); + } else { + impls::copy_backward(dest, src, n); + } + dest + } -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -#[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] -pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { - let mut i = 0; - while i < n { - let a = *s1.add(i); - let b = *s2.add(i); - if a != b { - return a as i32 - b as i32; + #[mem_builtin] + #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] + pub unsafe extern "C" fn memset(s: *mut u8, c: crate::mem::c_int, n: usize) -> *mut u8 { + impls::set_bytes(s, c as u8, n); + s + } + + #[mem_builtin] + #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] + pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { + let mut i = 0; + while i < n { + let a = *s1.add(i); + let b = *s2.add(i); + if a != b { + return a as i32 - b as i32; + } + i += 1; } - i += 1; + 0 } - 0 -} -#[cfg_attr(all(feature = "mem", not(feature = "mangled-names")), no_mangle)] -#[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] -pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { - memcmp(s1, s2, n) + #[mem_builtin] + #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] + pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { + memcmp(s1, s2, n) + } } // `bytes` must be a multiple of `mem::size_of::()` @@ -133,65 +135,65 @@ where intrinsics! { #[cfg(target_has_atomic_load_store = "8")] - pub extern "C" fn __llvm_memcpy_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memcpy_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () { memcpy_element_unordered_atomic(dest, src, bytes); } #[cfg(target_has_atomic_load_store = "16")] - pub extern "C" fn __llvm_memcpy_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memcpy_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () { memcpy_element_unordered_atomic(dest, src, bytes); } #[cfg(target_has_atomic_load_store = "32")] - pub extern "C" fn __llvm_memcpy_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memcpy_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () { memcpy_element_unordered_atomic(dest, src, bytes); } #[cfg(target_has_atomic_load_store = "64")] - pub extern "C" fn __llvm_memcpy_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memcpy_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () { memcpy_element_unordered_atomic(dest, src, bytes); } #[cfg(target_has_atomic_load_store = "128")] - pub extern "C" fn __llvm_memcpy_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memcpy_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () { memcpy_element_unordered_atomic(dest, src, bytes); } #[cfg(target_has_atomic_load_store = "8")] - pub extern "C" fn __llvm_memmove_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memmove_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () { memmove_element_unordered_atomic(dest, src, bytes); } #[cfg(target_has_atomic_load_store = "16")] - pub extern "C" fn __llvm_memmove_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memmove_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () { memmove_element_unordered_atomic(dest, src, bytes); } #[cfg(target_has_atomic_load_store = "32")] - pub extern "C" fn __llvm_memmove_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memmove_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () { memmove_element_unordered_atomic(dest, src, bytes); } #[cfg(target_has_atomic_load_store = "64")] - pub extern "C" fn __llvm_memmove_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memmove_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () { memmove_element_unordered_atomic(dest, src, bytes); } #[cfg(target_has_atomic_load_store = "128")] - pub extern "C" fn __llvm_memmove_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memmove_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () { memmove_element_unordered_atomic(dest, src, bytes); } #[cfg(target_has_atomic_load_store = "8")] - pub extern "C" fn __llvm_memset_element_unordered_atomic_1(s: *mut u8, c: u8, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memset_element_unordered_atomic_1(s: *mut u8, c: u8, bytes: usize) -> () { memset_element_unordered_atomic(s, c, bytes); } #[cfg(target_has_atomic_load_store = "16")] - pub extern "C" fn __llvm_memset_element_unordered_atomic_2(s: *mut u16, c: u8, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memset_element_unordered_atomic_2(s: *mut u16, c: u8, bytes: usize) -> () { memset_element_unordered_atomic(s, c, bytes); } #[cfg(target_has_atomic_load_store = "32")] - pub extern "C" fn __llvm_memset_element_unordered_atomic_4(s: *mut u32, c: u8, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memset_element_unordered_atomic_4(s: *mut u32, c: u8, bytes: usize) -> () { memset_element_unordered_atomic(s, c, bytes); } #[cfg(target_has_atomic_load_store = "64")] - pub extern "C" fn __llvm_memset_element_unordered_atomic_8(s: *mut u64, c: u8, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memset_element_unordered_atomic_8(s: *mut u64, c: u8, bytes: usize) -> () { memset_element_unordered_atomic(s, c, bytes); } #[cfg(target_has_atomic_load_store = "128")] - pub extern "C" fn __llvm_memset_element_unordered_atomic_16(s: *mut u128, c: u8, bytes: usize) -> () { + pub unsafe extern "C" fn __llvm_memset_element_unordered_atomic_16(s: *mut u128, c: u8, bytes: usize) -> () { memset_element_unordered_atomic(s, c, bytes); } } diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs index abcc2bdb3d41e..fd1f32e3a7d8b 100644 --- a/library/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/src/x86.rs @@ -8,82 +8,78 @@ use core::intrinsics; // NOTE These functions are never mangled as they are not tested against compiler-rt // and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca -#[cfg(all( - windows, - target_env = "gnu", - not(feature = "no-asm"), - not(feature = "mangled-names") -))] -#[naked] -#[no_mangle] -pub unsafe extern "C" fn ___chkstk_ms() { - core::arch::asm!( - "push %ecx", - "push %eax", - "cmp $0x1000,%eax", - "lea 12(%esp),%ecx", - "jb 1f", - "2:", - "sub $0x1000,%ecx", - "test %ecx,(%ecx)", - "sub $0x1000,%eax", - "cmp $0x1000,%eax", - "ja 2b", - "1:", - "sub %eax,%ecx", - "test %ecx,(%ecx)", - "pop %eax", - "pop %ecx", - "ret", - options(noreturn, att_syntax) - ); -} +intrinsics! { + #[naked] + #[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm") + ))] + pub unsafe extern "C" fn ___chkstk_ms() { + core::arch::asm!( + "push %ecx", + "push %eax", + "cmp $0x1000,%eax", + "lea 12(%esp),%ecx", + "jb 1f", + "2:", + "sub $0x1000,%ecx", + "test %ecx,(%ecx)", + "sub $0x1000,%eax", + "cmp $0x1000,%eax", + "ja 2b", + "1:", + "sub %eax,%ecx", + "test %ecx,(%ecx)", + "pop %eax", + "pop %ecx", + "ret", + options(noreturn, att_syntax) + ); + } -// FIXME: __alloca should be an alias to __chkstk -#[cfg(all( - windows, - target_env = "gnu", - not(feature = "no-asm"), - not(feature = "mangled-names") -))] -#[naked] -#[no_mangle] -pub unsafe extern "C" fn __alloca() { - core::arch::asm!( - "jmp ___chkstk", // Jump to ___chkstk since fallthrough may be unreliable" - options(noreturn, att_syntax) - ); -} + // FIXME: __alloca should be an alias to __chkstk + #[naked] + #[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm") + ))] + pub unsafe extern "C" fn __alloca() { + core::arch::asm!( + "jmp ___chkstk", // Jump to ___chkstk since fallthrough may be unreliable" + options(noreturn, att_syntax) + ); + } -#[cfg(all( - windows, - target_env = "gnu", - not(feature = "no-asm"), - not(feature = "mangled-names") -))] -#[naked] -#[no_mangle] -pub unsafe extern "C" fn ___chkstk() { - core::arch::asm!( - "push %ecx", - "cmp $0x1000,%eax", - "lea 8(%esp),%ecx", // esp before calling this routine -> ecx - "jb 1f", - "2:", - "sub $0x1000,%ecx", - "test %ecx,(%ecx)", - "sub $0x1000,%eax", - "cmp $0x1000,%eax", - "ja 2b", - "1:", - "sub %eax,%ecx", - "test %ecx,(%ecx)", - "lea 4(%esp),%eax", // load pointer to the return address into eax - "mov %ecx,%esp", // install the new top of stack pointer into esp - "mov -4(%eax),%ecx", // restore ecx - "push (%eax)", // push return address onto the stack - "sub %esp,%eax", // restore the original value in eax - "ret", - options(noreturn, att_syntax) - ); + #[naked] + #[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm") + ))] + pub unsafe extern "C" fn ___chkstk() { + core::arch::asm!( + "push %ecx", + "cmp $0x1000,%eax", + "lea 8(%esp),%ecx", // esp before calling this routine -> ecx + "jb 1f", + "2:", + "sub $0x1000,%ecx", + "test %ecx,(%ecx)", + "sub $0x1000,%eax", + "cmp $0x1000,%eax", + "ja 2b", + "1:", + "sub %eax,%ecx", + "test %ecx,(%ecx)", + "lea 4(%esp),%eax", // load pointer to the return address into eax + "mov %ecx,%esp", // install the new top of stack pointer into esp + "mov -4(%eax),%ecx", // restore ecx + "push (%eax)", // push return address onto the stack + "sub %esp,%eax", // restore the original value in eax + "ret", + options(noreturn, att_syntax) + ); + } } diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index ea3c99497909e..393eeddd877ad 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -8,89 +8,87 @@ use core::intrinsics; // NOTE These functions are never mangled as they are not tested against compiler-rt // and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca -#[cfg(all( - windows, - target_env = "gnu", - not(feature = "no-asm"), - not(feature = "mangled-names") -))] -#[naked] -#[no_mangle] -pub unsafe extern "C" fn ___chkstk_ms() { - core::arch::asm!( - "push %rcx", - "push %rax", - "cmp $0x1000,%rax", - "lea 24(%rsp),%rcx", - "jb 1f", - "2:", - "sub $0x1000,%rcx", - "test %rcx,(%rcx)", - "sub $0x1000,%rax", - "cmp $0x1000,%rax", - "ja 2b", - "1:", - "sub %rax,%rcx", - "test %rcx,(%rcx)", - "pop %rax", - "pop %rcx", - "ret", - options(noreturn, att_syntax) - ); -} +intrinsics! { + #[naked] + #[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm") + ))] + pub unsafe extern "C" fn ___chkstk_ms() { + core::arch::asm!( + "push %rcx", + "push %rax", + "cmp $0x1000,%rax", + "lea 24(%rsp),%rcx", + "jb 1f", + "2:", + "sub $0x1000,%rcx", + "test %rcx,(%rcx)", + "sub $0x1000,%rax", + "cmp $0x1000,%rax", + "ja 2b", + "1:", + "sub %rax,%rcx", + "test %rcx,(%rcx)", + "pop %rax", + "pop %rcx", + "ret", + options(noreturn, att_syntax) + ); + } -#[cfg(all( - windows, - target_env = "gnu", - not(feature = "no-asm"), - not(feature = "mangled-names") -))] -#[naked] -#[no_mangle] -pub unsafe extern "C" fn __alloca() { - core::arch::asm!( - "mov %rcx,%rax", // x64 _alloca is a normal function with parameter in rcx - "jmp ___chkstk", // Jump to ___chkstk since fallthrough may be unreliable" - options(noreturn, att_syntax) - ); -} + #[naked] + #[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm") + ))] + pub unsafe extern "C" fn __alloca() { + core::arch::asm!( + "mov %rcx,%rax", // x64 _alloca is a normal function with parameter in rcx + "jmp ___chkstk", // Jump to ___chkstk since fallthrough may be unreliable" + options(noreturn, att_syntax) + ); + } -#[cfg(all( - windows, - target_env = "gnu", - not(feature = "no-asm"), - not(feature = "mangled-names") -))] -#[naked] -#[no_mangle] -pub unsafe extern "C" fn ___chkstk() { - core::arch::asm!( - "push %rcx", - "cmp $0x1000,%rax", - "lea 16(%rsp),%rcx", // rsp before calling this routine -> rcx - "jb 1f", - "2:", - "sub $0x1000,%rcx", - "test %rcx,(%rcx)", - "sub $0x1000,%rax", - "cmp $0x1000,%rax", - "ja 2b", - "1:", - "sub %rax,%rcx", - "test %rcx,(%rcx)", - "lea 8(%rsp),%rax", // load pointer to the return address into rax - "mov %rcx,%rsp", // install the new top of stack pointer into rsp - "mov -8(%rax),%rcx", // restore rcx - "push (%rax)", // push return address onto the stack - "sub %rsp,%rax", // restore the original value in rax - "ret", - options(noreturn, att_syntax) - ); + #[naked] + #[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm") + ))] + pub unsafe extern "C" fn ___chkstk() { + core::arch::asm!( + "push %rcx", + "cmp $0x1000,%rax", + "lea 16(%rsp),%rcx", // rsp before calling this routine -> rcx + "jb 1f", + "2:", + "sub $0x1000,%rcx", + "test %rcx,(%rcx)", + "sub $0x1000,%rax", + "cmp $0x1000,%rax", + "ja 2b", + "1:", + "sub %rax,%rcx", + "test %rcx,(%rcx)", + "lea 8(%rsp),%rax", // load pointer to the return address into rax + "mov %rcx,%rsp", // install the new top of stack pointer into rsp + "mov -8(%rax),%rcx", // restore rcx + "push (%rax)", // push return address onto the stack + "sub %rsp,%rax", // restore the original value in rax + "ret", + options(noreturn, att_syntax) + ); + } } // HACK(https://github.com/rust-lang/rust/issues/62785): x86_64-unknown-uefi needs special LLVM // support unless we emit the _fltused -#[no_mangle] -#[used] -#[cfg(target_os = "uefi")] -static _fltused: i32 = 0; +mod _fltused { + #[no_mangle] + #[used] + #[cfg(target_os = "uefi")] + static _fltused: i32 = 0; +} From 76f02fa2db306804d6f4d0d5c5de3fbf089564b4 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 6 Feb 2022 09:52:15 +0000 Subject: [PATCH 0992/4206] Bump to 0.2.2 --- library/compiler-builtins/libm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 3a6c5851b718d..99055ad47b16b 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/libm" -version = "0.2.1" +version = "0.2.2" edition = "2018" [features] From f34d42cf4909a4dca8cd7875fd1fe3903cf7ba6f Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 6 Feb 2022 09:53:16 +0000 Subject: [PATCH 0993/4206] Update libm submodule to 0.2.2 --- library/compiler-builtins/libm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index c2d22bf95e2f0..1f7b8eb61cab5 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit c2d22bf95e2f032ae6b237e8e4c336bc795a151c +Subproject commit 1f7b8eb61cab5f62ec93d2343432bebd1ada30f2 From 2f988a88ffdbd03a8d4c2904e1e4cd3323d4acf0 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 6 Feb 2022 09:59:11 +0000 Subject: [PATCH 0994/4206] Bump to 0.1.68 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index a8278f0b81611..2ac4a6ba104fc 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.67" +version = "0.1.68" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 5bdeade2c4c4cea3d81ec219eaecf6e721e3b366 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 9 Feb 2022 20:54:39 +0000 Subject: [PATCH 0995/4206] Fix typo in __aeabi_uldivmod Accidentally introduced in #452 --- library/compiler-builtins/src/arm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 95bde51166209..9c1b6ad123ae5 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -42,7 +42,7 @@ intrinsics! { "sub sp, sp, #16", "add r4, sp, #8", "str r4, [sp]", - bl!("__udivmodsi4"), + bl!("__udivmoddi4"), "ldr r2, [sp, #8]", "ldr r3, [sp, #12]", "add sp, sp, #16", From e771805ee5a11e6e94d2463fa2e768069d2e258d Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 9 Feb 2022 21:02:02 +0000 Subject: [PATCH 0996/4206] Bump to 0.1.69 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 2ac4a6ba104fc..491cc5a82997a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.68" +version = "0.1.69" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 0575846f80e894ddddd048b0c19ab63d7af15b44 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sun, 13 Feb 2022 17:54:35 +0100 Subject: [PATCH 0997/4206] Handle Win64 builtins ABI change in LLVM 14 As of https://reviews.llvm.org/D110413, these no longer use the unadjusted ABI (and use normal C ABI instead, passing i128 indirectly and returning it as <2 x i64>). To support both LLVM 14 and older versions, rustc will expose a "llvm14-builtins-abi" target feature, based on which compiler-builtins can chose the appropriate ABI. This is needed for rust-lang/rust#93577. --- library/compiler-builtins/src/float/conv.rs | 116 ++++++++++++++------ 1 file changed, 81 insertions(+), 35 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 8c46e4d2e7a28..c0cee43732802 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -109,16 +109,6 @@ intrinsics! { } } - #[unadjusted_on_win64] - pub extern "C" fn __floattisf(i: i128) -> f32 { - int_to_float(i) - } - - #[unadjusted_on_win64] - pub extern "C" fn __floattidf(i: i128) -> f64 { - int_to_float(i) - } - #[arm_aeabi_alias = __aeabi_ui2f] pub extern "C" fn __floatunsisf(i: u32) -> f32 { int_to_float(i) @@ -140,16 +130,6 @@ intrinsics! { pub extern "C" fn __floatundidf(i: u64) -> f64 { int_to_float(i) } - - #[unadjusted_on_win64] - pub extern "C" fn __floatuntisf(i: u128) -> f32 { - int_to_float(i) - } - - #[unadjusted_on_win64] - pub extern "C" fn __floatuntidf(i: u128) -> f64 { - int_to_float(i) - } } fn float_to_int(f: F) -> I @@ -224,11 +204,6 @@ intrinsics! { float_to_int(f) } - #[unadjusted_on_win64] - pub extern "C" fn __fixsfti(f: f32) -> i128 { - float_to_int(f) - } - #[arm_aeabi_alias = __aeabi_d2iz] pub extern "C" fn __fixdfsi(f: f64) -> i32 { float_to_int(f) @@ -239,11 +214,6 @@ intrinsics! { float_to_int(f) } - #[unadjusted_on_win64] - pub extern "C" fn __fixdfti(f: f64) -> i128 { - float_to_int(f) - } - #[arm_aeabi_alias = __aeabi_f2uiz] pub extern "C" fn __fixunssfsi(f: f32) -> u32 { float_to_int(f) @@ -254,11 +224,6 @@ intrinsics! { float_to_int(f) } - #[unadjusted_on_win64] - pub extern "C" fn __fixunssfti(f: f32) -> u128 { - float_to_int(f) - } - #[arm_aeabi_alias = __aeabi_d2uiz] pub extern "C" fn __fixunsdfsi(f: f64) -> u32 { float_to_int(f) @@ -268,6 +233,87 @@ intrinsics! { pub extern "C" fn __fixunsdfdi(f: f64) -> u64 { float_to_int(f) } +} + +// The ABI for the following intrinsics changed in LLVM 14. On Win64, they now +// use Win64 ABI rather than unadjusted ABI. Pick the correct ABI based on the +// llvm14-builtins-abi target feature. + +#[cfg(target_feature = "llvm14-builtins-abi")] +intrinsics! { + pub extern "C" fn __floattisf(i: i128) -> f32 { + int_to_float(i) + } + + pub extern "C" fn __floattidf(i: i128) -> f64 { + int_to_float(i) + } + + pub extern "C" fn __floatuntisf(i: u128) -> f32 { + int_to_float(i) + } + + pub extern "C" fn __floatuntidf(i: u128) -> f64 { + int_to_float(i) + } + + #[win64_128bit_abi_hack] + pub extern "C" fn __fixsfti(f: f32) -> i128 { + float_to_int(f) + } + + #[win64_128bit_abi_hack] + pub extern "C" fn __fixdfti(f: f64) -> i128 { + float_to_int(f) + } + + #[win64_128bit_abi_hack] + pub extern "C" fn __fixunssfti(f: f32) -> u128 { + float_to_int(f) + } + + #[win64_128bit_abi_hack] + pub extern "C" fn __fixunsdfti(f: f64) -> u128 { + float_to_int(f) + } +} + +#[cfg(not(target_feature = "llvm14-builtins-abi"))] +intrinsics! { + #[unadjusted_on_win64] + pub extern "C" fn __floattisf(i: i128) -> f32 { + int_to_float(i) + } + + #[unadjusted_on_win64] + pub extern "C" fn __floattidf(i: i128) -> f64 { + int_to_float(i) + } + + #[unadjusted_on_win64] + pub extern "C" fn __floatuntisf(i: u128) -> f32 { + int_to_float(i) + } + + #[unadjusted_on_win64] + pub extern "C" fn __floatuntidf(i: u128) -> f64 { + int_to_float(i) + } + + #[unadjusted_on_win64] + pub extern "C" fn __fixsfti(f: f32) -> i128 { + float_to_int(f) + } + + #[unadjusted_on_win64] + pub extern "C" fn __fixdfti(f: f64) -> i128 { + float_to_int(f) + } + + #[unadjusted_on_win64] + pub extern "C" fn __fixunssfti(f: f32) -> u128 { + float_to_int(f) + } #[unadjusted_on_win64] pub extern "C" fn __fixunsdfti(f: f64) -> u128 { From 96339ec86d42f31388028c452b5cbb132534771f Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 16 Feb 2022 01:18:05 +0000 Subject: [PATCH 0998/4206] Bump to 0.1.70 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 491cc5a82997a..80e118a94788c 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.69" +version = "0.1.70" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 002fc52f002d7ef62665e756c741bb3feb9e808f Mon Sep 17 00:00:00 2001 From: Vladimir Michael Eatwell Date: Thu, 17 Jun 2021 17:40:45 +0100 Subject: [PATCH 0999/4206] [watch_os] add watchOS --- library/compiler-builtins/build.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 2b34540dc44e6..c8b7700111271 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -241,7 +241,7 @@ mod c { // On iOS and 32-bit OSX these are all just empty intrinsics, no need to // include them. - if target_os != "ios" && (target_vendor != "apple" || target_arch != "x86") { + if target_os != "ios" && target_os != "watchos" && (target_vendor != "apple" || target_arch != "x86") { sources.extend(&[ ("__absvti2", "absvti2.c"), ("__addvti3", "addvti3.c"), @@ -318,7 +318,7 @@ mod c { } } - if target_arch == "arm" && target_os != "ios" && target_env != "msvc" { + if target_arch == "arm" && target_os != "ios" && target_os != "watchos" && target_env != "msvc" { sources.extend(&[ ("__aeabi_div0", "arm/aeabi_div0.c"), ("__aeabi_drsub", "arm/aeabi_drsub.c"), From 50c5587f82f590553df41831629e4f494d016d16 Mon Sep 17 00:00:00 2001 From: Vladimir Michael Eatwell Date: Tue, 8 Mar 2022 10:18:07 +0000 Subject: [PATCH 1000/4206] [watch_os] Fix formatting --- library/compiler-builtins/build.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index c8b7700111271..d811fc5cb4589 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -241,7 +241,10 @@ mod c { // On iOS and 32-bit OSX these are all just empty intrinsics, no need to // include them. - if target_os != "ios" && target_os != "watchos" && (target_vendor != "apple" || target_arch != "x86") { + if target_os != "ios" + && target_os != "watchos" + && (target_vendor != "apple" || target_arch != "x86") + { sources.extend(&[ ("__absvti2", "absvti2.c"), ("__addvti3", "addvti3.c"), @@ -318,7 +321,11 @@ mod c { } } - if target_arch == "arm" && target_os != "ios" && target_os != "watchos" && target_env != "msvc" { + if target_arch == "arm" + && target_os != "ios" + && target_os != "watchos" + && target_env != "msvc" + { sources.extend(&[ ("__aeabi_div0", "arm/aeabi_div0.c"), ("__aeabi_drsub", "arm/aeabi_drsub.c"), From 7f535824f5ebeb0774d6c3185e89cf76a3a5d65e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 18 Mar 2022 18:18:28 +0300 Subject: [PATCH 1001/4206] Provide an implementation of `strlen` to be used as a fallback --- library/compiler-builtins/src/lib.rs | 1 + library/compiler-builtins/src/mem/mod.rs | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index c3eefbc036228..9ca72bc20f4e3 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -4,6 +4,7 @@ #![cfg_attr(not(feature = "no-asm"), feature(global_asm))] #![feature(cfg_target_has_atomic)] #![feature(compiler_builtins)] +#![feature(core_ffi_c)] #![feature(core_intrinsics)] #![feature(lang_items)] #![feature(linkage)] diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index dce4d87e0a5c0..a551138612bb6 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -68,6 +68,18 @@ intrinsics! { pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { memcmp(s1, s2, n) } + + #[mem_builtin] + #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] + pub unsafe extern "C" fn strlen(s: *const core::ffi::c_char) -> usize { + let mut n = 0; + let mut s = s; + while *s != 0 { + n += 1; + s = s.offset(1); + } + n + } } // `bytes` must be a multiple of `mem::size_of::()` From 8abefcd926c9d4e9261c286cac923c7deef30f5a Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 18 Mar 2022 20:12:07 +0000 Subject: [PATCH 1002/4206] Bump to 0.1.71 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 80e118a94788c..8c49b8c9e8f01 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.70" +version = "0.1.71" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From c491ca7ec58cab3e40e48f28d7dee651f5e3119f Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Tue, 22 Mar 2022 19:06:50 -0700 Subject: [PATCH 1003/4206] Build emutls.c on Android. Android uses emulated TLS so we need a runtime support function from this source file. --- library/compiler-builtins/build.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index d811fc5cb4589..e199124b26d7a 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -489,6 +489,16 @@ mod c { sources.remove(&["__aeabi_cdcmp", "__aeabi_cfcmp"]); } + // Android uses emulated TLS so we need a runtime support function. + if target_os == "android" { + 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. + cfg.define("LONG_BIT", "(8 * sizeof(long))"); + } + // When compiling the C code we require the user to tell us where the // source code is, and this is largely done so when we're compiling as // part of rust-lang/rust we can use the same llvm-project repository as From c307915e7850b82ac25b8a1f1598bf05d725b998 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 30 Mar 2022 19:39:47 +0100 Subject: [PATCH 1004/4206] Bump to 0.1.72 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 8c49b8c9e8f01..99f2947242d11 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.71" +version = "0.1.72" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 10971912e87e0ab10e1f7c6e9da8086f11ced68a Mon Sep 17 00:00:00 2001 From: Johannes Stoelp Date: Mon, 2 May 2022 23:00:12 +0200 Subject: [PATCH 1005/4206] rv64 implement muldi3 intrinsic Implement the __muldi3 intrinsic to prevent infinite recursion during multiplication on rv64 without the 'm' extension. --- library/compiler-builtins/src/int/mul.rs | 1 + library/compiler-builtins/src/lib.rs | 4 ++-- .../src/{riscv32.rs => riscv.rs} | 17 +++++++++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) rename library/compiler-builtins/src/{riscv32.rs => riscv.rs} (54%) diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index a5238eeac70e3..37eb03ec054f8 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -100,6 +100,7 @@ impl_signed_mulo!(i128_overflowing_mul, i128, u128); intrinsics! { #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_lmul] + #[cfg(not(target_arch = "riscv64"))] pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 { a.mul(b) } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 9ca72bc20f4e3..009923d27e5b4 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -60,8 +60,8 @@ pub mod arm; ))] pub mod arm_linux; -#[cfg(any(target_arch = "riscv32"))] -pub mod riscv32; +#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] +pub mod riscv; #[cfg(target_arch = "x86")] pub mod x86; diff --git a/library/compiler-builtins/src/riscv32.rs b/library/compiler-builtins/src/riscv.rs similarity index 54% rename from library/compiler-builtins/src/riscv32.rs rename to library/compiler-builtins/src/riscv.rs index 9a3c1714c1f09..d9a65e200745a 100644 --- a/library/compiler-builtins/src/riscv32.rs +++ b/library/compiler-builtins/src/riscv.rs @@ -1,6 +1,7 @@ intrinsics! { // Implementation from gcc // https://raw.githubusercontent.com/gcc-mirror/gcc/master/libgcc/config/epiphany/mulsi3.c + #[cfg(target_arch = "riscv32")] pub extern "C" fn __mulsi3(a: u32, b: u32) -> u32 { let (mut a, mut b) = (a, b); let mut r = 0; @@ -15,4 +16,20 @@ intrinsics! { r } + + #[cfg(target_arch = "riscv64")] + pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 { + let (mut a, mut b) = (a, b); + let mut r = 0; + + while a > 0 { + if a & 1 > 0 { + r += b; + } + a >>= 1; + b <<= 1; + } + + r + } } From 7d79662fd1d81932ffa6feffafbf384417a82189 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Mon, 2 May 2022 16:05:03 -0700 Subject: [PATCH 1006/4206] Remove apple_versioning.c inclusion According to the README this file isn't used by rust, but it's currently included which leads to these linker warnings in some cases: ``` ld: warning: linker symbol '$ld$hide$os10.5$___udivti3' hides a non-existent symbol '___udivti3' ld: warning: linker symbol '$ld$hide$os10.4$___umoddi3' hides a non-existent symbol '___umoddi3' ld: warning: linker symbol '$ld$hide$os10.5$___umoddi3' hides a non-existent symbol '___umoddi3' ld: warning: linker symbol '$ld$hide$os10.4$___umodti3' hides a non-existent symbol '___umodti3' ld: warning: linker symbol '$ld$hide$os10.5$___umodti3' hides a non-existent symbol '___umodti3' ``` This file exclusively contains macros which hides old symbols on Apple OS versions where they don't exist. https://github.com/rust-lang/llvm-project/blob/fc10370ef7d91babf512c10505f8f2176bc8519d/compiler-rt/lib/builtins/apple_versioning.c --- library/compiler-builtins/build.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index e199124b26d7a..a1bcf2ea1fc9b 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -193,7 +193,6 @@ mod c { ("__absvsi2", "absvsi2.c"), ("__addvdi3", "addvdi3.c"), ("__addvsi3", "addvsi3.c"), - ("apple_versioning", "apple_versioning.c"), ("__clzdi2", "clzdi2.c"), ("__clzsi2", "clzsi2.c"), ("__cmpdi2", "cmpdi2.c"), From 65ec71d38687ee2338129622e97f249fa2402196 Mon Sep 17 00:00:00 2001 From: Johannes Stoelp Date: Thu, 12 May 2022 00:34:49 +0200 Subject: [PATCH 1007/4206] rv32 rv64: adapt conditional compilation Adapt conditional compilation as: rv32i : riscv:__mulsi3, riscv:__muldi3 rv32im: riscv:__mulsi3, int/mul:__muldi3 rv64i : riscv:__mulsi3, riscv:__muldi3 rv64im: riscv:__mulsi3, int/mul:__muldi3 --- library/compiler-builtins/src/int/mul.rs | 2 +- library/compiler-builtins/src/riscv.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 37eb03ec054f8..07ce061c994f8 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -100,7 +100,7 @@ impl_signed_mulo!(i128_overflowing_mul, i128, u128); intrinsics! { #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_lmul] - #[cfg(not(target_arch = "riscv64"))] + #[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) } diff --git a/library/compiler-builtins/src/riscv.rs b/library/compiler-builtins/src/riscv.rs index d9a65e200745a..ee78b9dbacf48 100644 --- a/library/compiler-builtins/src/riscv.rs +++ b/library/compiler-builtins/src/riscv.rs @@ -1,7 +1,6 @@ intrinsics! { // Implementation from gcc // https://raw.githubusercontent.com/gcc-mirror/gcc/master/libgcc/config/epiphany/mulsi3.c - #[cfg(target_arch = "riscv32")] pub extern "C" fn __mulsi3(a: u32, b: u32) -> u32 { let (mut a, mut b) = (a, b); let mut r = 0; @@ -17,7 +16,7 @@ intrinsics! { r } - #[cfg(target_arch = "riscv64")] + #[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 = 0; From a695a800d542d7a0fac55ec8ee2eb5ea926389e2 Mon Sep 17 00:00:00 2001 From: Patryk Wychowaniec Date: Sun, 15 May 2022 12:58:38 +0200 Subject: [PATCH 1008/4206] Fix division on AVRs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For division and modulo, AVR uses a custom calling convention that does not match compiler_builtins' expectations, leading to non-working code¹. Ideally we'd just use hand-written naked functions (as, afair, ARM does), but that's a lot of code to port², so hopefully we'll be able to do it gradually later. For the time being, I'd suggest not compiling problematic functions for AVR target - this causes avr-gcc (which is a mandatory part of Rust+AVR toolchain anyway) to link hand-written assembly from libgcc, which is confirmed to work. I've tested the code locally on simavr and the patch seems to be working correctly :-) ¹ https://github.com/rust-lang/rust/issues/82242, https://github.com/rust-lang/rust/issues/83281 ² https://github.com/gcc-mirror/gcc/blob/31048012db98f5ec9c2ba537bfd850374bdd771f/libgcc/config/avr/lib1funcs.S Closes https://github.com/rust-lang/rust/issues/82242 Closes https://github.com/rust-lang/rust/issues/83281 --- library/compiler-builtins/src/int/sdiv.rs | 3 +++ library/compiler-builtins/src/int/udiv.rs | 5 ++++ library/compiler-builtins/src/macros.rs | 31 ++++++++++++++++++++++- 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index e1e3f33bbd00f..f1822f0f86e87 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -9,6 +9,7 @@ macro_rules! sdivmod { $($attr:tt),* // attributes ) => { intrinsics! { + #[avr_skip] $( #[$attr] )* @@ -50,6 +51,7 @@ macro_rules! sdiv { $($attr:tt),* // attributes ) => { intrinsics! { + #[avr_skip] $( #[$attr] )* @@ -85,6 +87,7 @@ macro_rules! smod { $($attr:tt),* // attributes ) => { intrinsics! { + #[avr_skip] $( #[$attr] )* diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index 2f236346d3dd7..c5ef4a6b19770 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -18,6 +18,7 @@ intrinsics! { u32_div_rem(n, d).1 } + #[avr_skip] #[maybe_use_optimized_c_shim] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { @@ -28,18 +29,21 @@ intrinsics! { quo_rem.0 } + #[avr_skip] #[maybe_use_optimized_c_shim] /// Returns `n / d` pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { u64_div_rem(n, d).0 } + #[avr_skip] #[maybe_use_optimized_c_shim] /// Returns `n % d` pub extern "C" fn __umoddi3(n: u64, d: u64) -> u64 { u64_div_rem(n, d).1 } + #[avr_skip] #[maybe_use_optimized_c_shim] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { @@ -77,6 +81,7 @@ intrinsics! { } } + #[avr_skip] #[win64_128bit_abi_hack] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmodti4(n: u128, d: u128, rem: Option<&mut u128>) -> u128 { diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 6926feac055cb..4c1d8af628119 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -82,7 +82,6 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( - #[cfg($name = "optimized-c")] pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { extern $abi { @@ -304,6 +303,36 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); + // For division and modulo, AVR uses a custom calling convention¹ that does + // not match our definitions here. Ideally we would just use hand-written + // naked functions, but that's quite a lot of code to port² - so for the + // time being we are just ignoring the problematic functions, letting + // avr-gcc (which is required to compile to AVR anyway) link them from + // libgcc. + // + // ¹ https://gcc.gnu.org/wiki/avr-gcc (see "Exceptions to the Calling + // Convention") + // ² https://github.com/gcc-mirror/gcc/blob/31048012db98f5ec9c2ba537bfd850374bdd771f/libgcc/config/avr/lib1funcs.S + ( + #[avr_skip] + $(#[$($attr:tt)*])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(not(target_arch = "avr"))] + intrinsics! { + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + // This is the final catch-all rule. At this point we generate an // intrinsic with a conditional `#[no_mangle]` directive to avoid // interfering with duplicate symbols and whatnot during testing. From 2063e07b353fe5d675a986351228278ec7244f14 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 20 May 2022 14:43:16 +0200 Subject: [PATCH 1009/4206] Support cfg_attr attributes in intrinsics!() macro. --- library/compiler-builtins/src/macros.rs | 29 +++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 6926feac055cb..22d82e3fab95b 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -61,6 +61,35 @@ macro_rules! public_test_dep { macro_rules! intrinsics { () => (); + // Support cfg_attr: + ( + #[cfg_attr($e:meta, $($attr:tt)*)] + $(#[$($attrs:tt)*])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + $($rest:tt)* + ) => ( + #[cfg($e)] + intrinsics! { + #[$($attr)*] + $(#[$($attrs)*])* + pub extern $abi fn $name($($argname: $ty),*) $(-> $ret)? { + $($body)* + } + } + + #[cfg(not($e))] + intrinsics! { + $(#[$($attrs)*])* + pub extern $abi fn $name($($argname: $ty),*) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + // Right now there's a bunch of architecture-optimized intrinsics in the // stock compiler-rt implementation. Not all of these have been ported over // to Rust yet so when the `c` feature of this crate is enabled we fall back From 7ed26a7e7a32f7124d2ccf9004ab820a0766c2a6 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 20 May 2022 14:43:34 +0200 Subject: [PATCH 1010/4206] De-duplicate 128 bit float conv intrinsics using cfg_attr. --- library/compiler-builtins/src/float/conv.rs | 60 +++++---------------- 1 file changed, 12 insertions(+), 48 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index c0cee43732802..0e21a1ed3bfbd 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -239,83 +239,47 @@ intrinsics! { // use Win64 ABI rather than unadjusted ABI. Pick the correct ABI based on the // llvm14-builtins-abi target feature. -#[cfg(target_feature = "llvm14-builtins-abi")] intrinsics! { + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] pub extern "C" fn __floattisf(i: i128) -> f32 { int_to_float(i) } + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] pub extern "C" fn __floattidf(i: i128) -> f64 { int_to_float(i) } + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] pub extern "C" fn __floatuntisf(i: u128) -> f32 { int_to_float(i) } + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] pub extern "C" fn __floatuntidf(i: u128) -> f64 { int_to_float(i) } - #[win64_128bit_abi_hack] + #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] pub extern "C" fn __fixsfti(f: f32) -> i128 { float_to_int(f) } - #[win64_128bit_abi_hack] + #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] pub extern "C" fn __fixdfti(f: f64) -> i128 { float_to_int(f) } - #[win64_128bit_abi_hack] + #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] pub extern "C" fn __fixunssfti(f: f32) -> u128 { float_to_int(f) } - #[win64_128bit_abi_hack] - pub extern "C" fn __fixunsdfti(f: f64) -> u128 { - float_to_int(f) - } -} - -#[cfg(not(target_feature = "llvm14-builtins-abi"))] -intrinsics! { - #[unadjusted_on_win64] - pub extern "C" fn __floattisf(i: i128) -> f32 { - int_to_float(i) - } - - #[unadjusted_on_win64] - pub extern "C" fn __floattidf(i: i128) -> f64 { - int_to_float(i) - } - - #[unadjusted_on_win64] - pub extern "C" fn __floatuntisf(i: u128) -> f32 { - int_to_float(i) - } - - #[unadjusted_on_win64] - pub extern "C" fn __floatuntidf(i: u128) -> f64 { - int_to_float(i) - } - - #[unadjusted_on_win64] - pub extern "C" fn __fixsfti(f: f32) -> i128 { - float_to_int(f) - } - - #[unadjusted_on_win64] - pub extern "C" fn __fixdfti(f: f64) -> i128 { - float_to_int(f) - } - - #[unadjusted_on_win64] - pub extern "C" fn __fixunssfti(f: f32) -> u128 { - float_to_int(f) - } - - #[unadjusted_on_win64] + #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] pub extern "C" fn __fixunsdfti(f: f64) -> u128 { float_to_int(f) } From 425c78ee7a71ebfa6a43eb7df2be58b656e7b7af Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 20 May 2022 16:25:18 +0200 Subject: [PATCH 1011/4206] Faster int<->float conversions. --- library/compiler-builtins/build.rs | 12 +- library/compiler-builtins/src/float/conv.rs | 481 +++++++++++--------- 2 files changed, 274 insertions(+), 219 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index e199124b26d7a..3868510bea55f 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -281,10 +281,7 @@ mod c { if target_env == "msvc" { if target_arch == "x86_64" { - sources.extend(&[ - ("__floatdisf", "x86_64/floatdisf.c"), - ("__floatdixf", "x86_64/floatdixf.c"), - ]); + sources.extend(&[("__floatdixf", "x86_64/floatdixf.c")]); } } else { // None of these seem to be used on x86_64 windows, and they've all @@ -292,10 +289,7 @@ mod c { if target_os != "windows" { if target_arch == "x86_64" { sources.extend(&[ - ("__floatdisf", "x86_64/floatdisf.c"), ("__floatdixf", "x86_64/floatdixf.c"), - ("__floatundidf", "x86_64/floatundidf.S"), - ("__floatundisf", "x86_64/floatundisf.S"), ("__floatundixf", "x86_64/floatundixf.S"), ]); } @@ -306,11 +300,7 @@ mod c { ("__ashldi3", "i386/ashldi3.S"), ("__ashrdi3", "i386/ashrdi3.S"), ("__divdi3", "i386/divdi3.S"), - ("__floatdidf", "i386/floatdidf.S"), - ("__floatdisf", "i386/floatdisf.S"), ("__floatdixf", "i386/floatdixf.S"), - ("__floatundidf", "i386/floatundidf.S"), - ("__floatundisf", "i386/floatundisf.S"), ("__floatundixf", "i386/floatundixf.S"), ("__lshrdi3", "i386/lshrdi3.S"), ("__moddi3", "i386/moddi3.S"), diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 0e21a1ed3bfbd..86847ed6c7933 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -1,286 +1,351 @@ -use float::Float; -use int::{CastInto, Int}; - -fn int_to_float(i: I) -> F -where - F::Int: CastInto, - F::Int: CastInto, - I::UnsignedInt: CastInto, - u32: CastInto, -{ - if i == I::ZERO { - return F::ZERO; - } - - let two = I::UnsignedInt::ONE + I::UnsignedInt::ONE; - let four = two + two; - let sign = i < I::ZERO; - let mut x = Int::abs_diff(i, I::ZERO); - - // number of significant digits in the integer - let i_sd = I::BITS - x.leading_zeros(); - // significant digits for the float, including implicit bit - let f_sd = F::SIGNIFICAND_BITS + 1; - - // exponent - let mut exp = i_sd - 1; - - if I::BITS < f_sd { - return F::from_parts( - sign, - (exp + F::EXPONENT_BIAS).cast(), - x.cast() << (f_sd - exp - 1), - ); +/// Conversions from integers to floats. +/// +/// These are hand-optimized bit twiddling code, +/// which unfortunately isn't the easiest kind of code to read. +/// +/// The algorithm is explained here: https://blog.m-ou.se/floats/ +mod int_to_float { + pub fn u32_to_f32_bits(i: u32) -> u32 { + if i == 0 { + return 0; + } + let n = i.leading_zeros(); + let a = i << n >> 8; // Significant bits, with bit 24 still in tact. + let b = i << n << 24; // Insignificant bits, only relevant for rounding. + let m = a + ((b - (b >> 31 & !a)) >> 31); // Add one when we need to round up. Break ties to even. + let e = 157 - n as u32; // Exponent plus 127, minus one. + (e << 23) + m // + not |, so the mantissa can overflow into the exponent. } - x = if i_sd > f_sd { - // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx - // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR - // 12345678901234567890123456 - // 1 = the implicit bit - // P = bit f_sd-1 bits to the right of 1 - // Q = bit f_sd bits to the right of 1 - // R = "or" of all bits to the right of Q - let f_sd_add2 = f_sd + 2; - x = if i_sd == (f_sd + 1) { - x << 1 - } else if i_sd == f_sd_add2 { - x - } else { - (x >> (i_sd - f_sd_add2)) - | Int::from_bool( - (x & I::UnsignedInt::MAX).wrapping_shl((I::BITS + f_sd_add2) - i_sd) - != Int::ZERO, - ) - }; - - // R |= P - x |= Int::from_bool((x & four) != I::UnsignedInt::ZERO); - // round - this step may add a significant bit - x += Int::ONE; - // dump Q and R - x >>= 2; - - // a is now rounded to f_sd or f_sd+1 bits - if (x & (I::UnsignedInt::ONE << f_sd)) != Int::ZERO { - x >>= 1; - exp += 1; + pub fn u32_to_f64_bits(i: u32) -> u64 { + if i == 0 { + return 0; } - x - } else { - x.wrapping_shl(f_sd - i_sd) - }; - - F::from_parts(sign, (exp + F::EXPONENT_BIAS).cast(), x.cast()) -} - -intrinsics! { - #[arm_aeabi_alias = __aeabi_i2f] - pub extern "C" fn __floatsisf(i: i32) -> f32 { - int_to_float(i) + let n = i.leading_zeros(); + let m = (i as u64) << (21 + n); // Significant bits, with bit 53 still in tact. + let e = 1053 - n as u64; // Exponent plus 1023, minus one. + (e << 52) + m // Bit 53 of m will overflow into e. } - #[arm_aeabi_alias = __aeabi_i2d] - pub extern "C" fn __floatsidf(i: i32) -> f64 { - int_to_float(i) + pub fn u64_to_f32_bits(i: u64) -> u32 { + let n = i.leading_zeros(); + let y = i.wrapping_shl(n); + let a = (y >> 40) as u32; // Significant bits, with bit 24 still in tact. + let b = (y >> 8 | y & 0xFFFF) as u32; // Insignificant bits, only relevant for rounding. + let m = a + ((b - (b >> 31 & !a)) >> 31); // Add one when we need to round up. Break ties to even. + let e = if i == 0 { 0 } else { 189 - n }; // Exponent plus 127, minus one, except for zero. + (e << 23) + m // + not |, so the mantissa can overflow into the exponent. } - #[maybe_use_optimized_c_shim] - #[arm_aeabi_alias = __aeabi_l2f] - pub extern "C" fn __floatdisf(i: i64) -> f32 { - // On x86_64 LLVM will use native instructions for this conversion, we - // can just do it directly - if cfg!(target_arch = "x86_64") { - i as f32 - } else { - int_to_float(i) + pub fn u64_to_f64_bits(i: u64) -> u64 { + if i == 0 { + return 0; } + let n = i.leading_zeros(); + let a = (i << n >> 11) as u64; // Significant bits, with bit 53 still in tact. + let b = (i << n << 53) as u64; // Insignificant bits, only relevant for rounding. + let m = a + ((b - (b >> 63 & !a)) >> 63); // Add one when we need to round up. Break ties to even. + let e = 1085 - n as u64; // Exponent plus 1023, minus one. + (e << 52) + m // + not |, so the mantissa can overflow into the exponent. } - #[maybe_use_optimized_c_shim] - #[arm_aeabi_alias = __aeabi_l2d] - pub extern "C" fn __floatdidf(i: i64) -> f64 { - // On x86_64 LLVM will use native instructions for this conversion, we - // can just do it directly - if cfg!(target_arch = "x86_64") { - i as f64 - } else { - int_to_float(i) - } + pub fn u128_to_f32_bits(i: u128) -> u32 { + let n = i.leading_zeros(); + let y = i.wrapping_shl(n); + let a = (y >> 104) as u32; // Significant bits, with bit 24 still in tact. + let b = (y >> 72) as u32 | (y << 32 >> 32 != 0) as u32; // Insignificant bits, only relevant for rounding. + let m = a + ((b - (b >> 31 & !a)) >> 31); // Add one when we need to round up. Break ties to even. + let e = if i == 0 { 0 } else { 253 - n }; // Exponent plus 127, minus one, except for zero. + (e << 23) + m // + not |, so the mantissa can overflow into the exponent. + } + + pub fn u128_to_f64_bits(i: u128) -> u64 { + let n = i.leading_zeros(); + let y = i.wrapping_shl(n); + let a = (y >> 75) as u64; // Significant bits, with bit 53 still in tact. + let b = (y >> 11 | y & 0xFFFF_FFFF) as u64; // Insignificant bits, only relevant for rounding. + let m = a + ((b - (b >> 63 & !a)) >> 63); // Add one when we need to round up. Break ties to even. + let e = if i == 0 { 0 } else { 1149 - n as u64 }; // Exponent plus 1023, minus one, except for zero. + (e << 52) + m // + not |, so the mantissa can overflow into the exponent. } +} +// Conversions from unsigned integers to floats. +intrinsics! { #[arm_aeabi_alias = __aeabi_ui2f] pub extern "C" fn __floatunsisf(i: u32) -> f32 { - int_to_float(i) + f32::from_bits(int_to_float::u32_to_f32_bits(i)) } #[arm_aeabi_alias = __aeabi_ui2d] pub extern "C" fn __floatunsidf(i: u32) -> f64 { - int_to_float(i) + f64::from_bits(int_to_float::u32_to_f64_bits(i)) } - #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_ul2f] pub extern "C" fn __floatundisf(i: u64) -> f32 { - int_to_float(i) + f32::from_bits(int_to_float::u64_to_f32_bits(i)) } - #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_ul2d] pub extern "C" fn __floatundidf(i: u64) -> f64 { - int_to_float(i) + f64::from_bits(int_to_float::u64_to_f64_bits(i)) } -} - -fn float_to_int(f: F) -> I -where - F::ExpInt: CastInto, - u32: CastInto, - F::Int: CastInto, -{ - // converting NaNs is UB, so we don't consider them - let sign = f.sign(); - let mut exp = f.exp(); - - // if less than one or unsigned & negative - if (exp < F::EXPONENT_BIAS.cast()) || (!I::SIGNED && sign) { - return I::ZERO; + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + pub extern "C" fn __floatuntisf(i: u128) -> f32 { + f32::from_bits(int_to_float::u128_to_f32_bits(i)) } - exp -= F::EXPONENT_BIAS.cast(); - - // If the value is too large for `I`, saturate. - let bits: F::ExpInt = I::BITS.cast(); - let max = if I::SIGNED { - bits - F::ExpInt::ONE - } else { - bits - }; - if max <= exp { - return if sign { - // It happens that I::MIN is handled correctly - I::MIN - } else { - I::MAX - }; - }; - // `0 <= exp < max` - - // If 0 <= exponent < F::SIGNIFICAND_BITS, right shift to get the result. Otherwise, shift left. - let sig_bits: F::ExpInt = F::SIGNIFICAND_BITS.cast(); - // The larger integer has to be casted into, or else the shift overflows - let r: I = if F::Int::BITS < I::BITS { - let tmp: I = if exp < sig_bits { - f.imp_frac().cast() >> (sig_bits - exp).cast() - } else { - f.imp_frac().cast() << (exp - sig_bits).cast() - }; - tmp - } else { - let tmp: F::Int = if exp < sig_bits { - f.imp_frac() >> (sig_bits - exp).cast() - } else { - f.imp_frac() << (exp - sig_bits).cast() - }; - tmp.cast() - }; - - if sign { - r.wrapping_neg() - } else { - r + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + pub extern "C" fn __floatuntidf(i: u128) -> f64 { + f64::from_bits(int_to_float::u128_to_f64_bits(i)) } } +// Conversions from signed integers to floats. intrinsics! { - #[arm_aeabi_alias = __aeabi_f2iz] - pub extern "C" fn __fixsfsi(f: f32) -> i32 { - float_to_int(f) + #[arm_aeabi_alias = __aeabi_i2f] + pub extern "C" fn __floatsisf(i: i32) -> f32 { + let sign_bit = ((i >> 31) as u32) << 31; + f32::from_bits(int_to_float::u32_to_f32_bits(i.unsigned_abs()) | sign_bit) } - #[arm_aeabi_alias = __aeabi_f2lz] - pub extern "C" fn __fixsfdi(f: f32) -> i64 { - float_to_int(f) + #[arm_aeabi_alias = __aeabi_i2d] + pub extern "C" fn __floatsidf(i: i32) -> f64 { + let sign_bit = ((i >> 31) as u64) << 63; + f64::from_bits(int_to_float::u32_to_f64_bits(i.unsigned_abs()) | sign_bit) } - #[arm_aeabi_alias = __aeabi_d2iz] - pub extern "C" fn __fixdfsi(f: f64) -> i32 { - float_to_int(f) + #[arm_aeabi_alias = __aeabi_l2f] + pub extern "C" fn __floatdisf(i: i64) -> f32 { + let sign_bit = ((i >> 63) as u32) << 31; + f32::from_bits(int_to_float::u64_to_f32_bits(i.unsigned_abs()) | sign_bit) } - #[arm_aeabi_alias = __aeabi_d2lz] - pub extern "C" fn __fixdfdi(f: f64) -> i64 { - float_to_int(f) + #[arm_aeabi_alias = __aeabi_l2d] + pub extern "C" fn __floatdidf(i: i64) -> f64 { + let sign_bit = ((i >> 63) as u64) << 63; + f64::from_bits(int_to_float::u64_to_f64_bits(i.unsigned_abs()) | sign_bit) + } + + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + pub extern "C" fn __floattisf(i: i128) -> f32 { + let sign_bit = ((i >> 127) as u32) << 31; + f32::from_bits(int_to_float::u128_to_f32_bits(i.unsigned_abs()) | sign_bit) } + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + pub extern "C" fn __floattidf(i: i128) -> f64 { + let sign_bit = ((i >> 127) as u64) << 63; + f64::from_bits(int_to_float::u128_to_f64_bits(i.unsigned_abs()) | sign_bit) + } +} + +// Conversions from floats to unsigned integers. +intrinsics! { #[arm_aeabi_alias = __aeabi_f2uiz] pub extern "C" fn __fixunssfsi(f: f32) -> u32 { - float_to_int(f) + let fbits = f.to_bits(); + if fbits < 127 << 23 { // >= 0, < 1 + 0 + } else if fbits < 159 << 23 { // >= 1, < max + let m = 1 << 31 | fbits << 8; // Mantissa and the implicit 1-bit. + let s = 158 - (fbits >> 23); // Shift based on the exponent and bias. + m >> s + } else if fbits <= 255 << 23 { // >= max (incl. inf) + u32::MAX + } else { // Negative or NaN + 0 + } } #[arm_aeabi_alias = __aeabi_f2ulz] pub extern "C" fn __fixunssfdi(f: f32) -> u64 { - float_to_int(f) + let fbits = f.to_bits(); + if fbits < 127 << 23 { // >= 0, < 1 + 0 + } else if fbits < 191 << 23 { // >= 1, < max + let m = 1 << 63 | (fbits as u64) << 40; // Mantissa and the implicit 1-bit. + let s = 190 - (fbits >> 23); // Shift based on the exponent and bias. + m >> s + } else if fbits <= 255 << 23 { // >= max (incl. inf) + u64::MAX + } else { // Negative or NaN + 0 + } + } + + #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] + #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + pub extern "C" fn __fixunssfti(f: f32) -> u128 { + let fbits = f.to_bits(); + if fbits < 127 << 23 { // >= 0, < 1 + 0 + } else if fbits < 255 << 23 { // >= 1, < inf + let m = 1 << 127 | (fbits as u128) << 104; // Mantissa and the implicit 1-bit. + let s = 254 - (fbits >> 23); // Shift based on the exponent and bias. + m >> s + } else if fbits == 255 << 23 { // == inf + u128::MAX + } else { // Negative or NaN + 0 + } } #[arm_aeabi_alias = __aeabi_d2uiz] pub extern "C" fn __fixunsdfsi(f: f64) -> u32 { - float_to_int(f) + let fbits = f.to_bits(); + if fbits < 1023 << 52 { // >= 0, < 1 + 0 + } else if fbits < 1055 << 52 { // >= 1, < max + let m = 1 << 31 | (fbits >> 21) as u32; // Mantissa and the implicit 1-bit. + let s = 1054 - (fbits >> 52); // Shift based on the exponent and bias. + m >> s + } else if fbits <= 2047 << 52 { // >= max (incl. inf) + u32::MAX + } else { // Negative or NaN + 0 + } } #[arm_aeabi_alias = __aeabi_d2ulz] pub extern "C" fn __fixunsdfdi(f: f64) -> u64 { - float_to_int(f) - } -} - -// The ABI for the following intrinsics changed in LLVM 14. On Win64, they now -// use Win64 ABI rather than unadjusted ABI. Pick the correct ABI based on the -// llvm14-builtins-abi target feature. - -intrinsics! { - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] - pub extern "C" fn __floattisf(i: i128) -> f32 { - int_to_float(i) + let fbits = f.to_bits(); + if fbits < 1023 << 52 { // >= 0, < 1 + 0 + } else if fbits < 1087 << 52 { // >= 1, < max + let m = 1 << 63 | fbits << 11; // Mantissa and the implicit 1-bit. + let s = 1086 - (fbits >> 52); // Shift based on the exponent and bias. + m >> s + } else if fbits <= 2047 << 52 { // >= max (incl. inf) + u64::MAX + } else { // Negative or NaN + 0 + } } + #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] - pub extern "C" fn __floattidf(i: i128) -> f64 { - int_to_float(i) + pub extern "C" fn __fixunsdfti(f: f64) -> u128 { + let fbits = f.to_bits(); + if fbits < 1023 << 52 { // >= 0, < 1 + 0 + } else if fbits < 1151 << 52 { // >= 1, < max + let m = 1 << 127 | (fbits as u128) << 75; // Mantissa and the implicit 1-bit. + let s = 1150 - (fbits >> 52); // Shift based on the exponent and bias. + m >> s + } else if fbits <= 2047 << 52 { // >= max (incl. inf) + u128::MAX + } else { // Negative or NaN + 0 + } } +} - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] - pub extern "C" fn __floatuntisf(i: u128) -> f32 { - int_to_float(i) +// Conversions from floats to signed integers. +intrinsics! { + #[arm_aeabi_alias = __aeabi_f2iz] + pub extern "C" fn __fixsfsi(f: f32) -> i32 { + let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. + if fbits < 127 << 23 { // >= 0, < 1 + 0 + } else if fbits < 158 << 23 { // >= 1, < max + let m = 1 << 31 | fbits << 8; // Mantissa and the implicit 1-bit. + let s = 158 - (fbits >> 23); // Shift based on the exponent and bias. + let u = (m >> s) as i32; // Unsigned result. + if f.is_sign_negative() { -u } else { u } + } else if fbits <= 255 << 23 { // >= max (incl. inf) + if f.is_sign_negative() { i32::MIN } else { i32::MAX } + } else { // NaN + 0 + } } - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] - pub extern "C" fn __floatuntidf(i: u128) -> f64 { - int_to_float(i) + #[arm_aeabi_alias = __aeabi_f2lz] + pub extern "C" fn __fixsfdi(f: f32) -> i64 { + let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. + if fbits < 127 << 23 { // >= 0, < 1 + 0 + } else if fbits < 190 << 23 { // >= 1, < max + let m = 1 << 63 | (fbits as u64) << 40; // Mantissa and the implicit 1-bit. + let s = 190 - (fbits >> 23); // Shift based on the exponent and bias. + let u = (m >> s) as i64; // Unsigned result. + if f.is_sign_negative() { -u } else { u } + } else if fbits <= 255 << 23 { // >= max (incl. inf) + if f.is_sign_negative() { i64::MIN } else { i64::MAX } + } else { // NaN + 0 + } } #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] pub extern "C" fn __fixsfti(f: f32) -> i128 { - float_to_int(f) + let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. + if fbits < 127 << 23 { // >= 0, < 1 + 0 + } else if fbits < 254 << 23 { // >= 1, < max + let m = 1 << 127 | (fbits as u128) << 104; // Mantissa and the implicit 1-bit. + let s = 254 - (fbits >> 23); // Shift based on the exponent and bias. + let u = (m >> s) as i128; // Unsigned result. + if f.is_sign_negative() { -u } else { u } + } else if fbits <= 255 << 23 { // >= max (incl. inf) + if f.is_sign_negative() { i128::MIN } else { i128::MAX } + } else { // NaN + 0 + } } - #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] - pub extern "C" fn __fixdfti(f: f64) -> i128 { - float_to_int(f) + #[arm_aeabi_alias = __aeabi_d2iz] + pub extern "C" fn __fixdfsi(f: f64) -> i32 { + let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. + if fbits < 1023 << 52 { // >= 0, < 1 + 0 + } else if fbits < 1054 << 52 { // >= 1, < max + let m = 1 << 31 | (fbits >> 21) as u32; // Mantissa and the implicit 1-bit. + let s = 1054 - (fbits >> 52); // Shift based on the exponent and bias. + let u = (m >> s) as i32; // Unsigned result. + if f.is_sign_negative() { -u } else { u } + } else if fbits <= 2047 << 52 { // >= max (incl. inf) + if f.is_sign_negative() { i32::MIN } else { i32::MAX } + } else { // NaN + 0 + } } - #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] - pub extern "C" fn __fixunssfti(f: f32) -> u128 { - float_to_int(f) + #[arm_aeabi_alias = __aeabi_d2lz] + pub extern "C" fn __fixdfdi(f: f64) -> i64 { + let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. + if fbits < 1023 << 52 { // >= 0, < 1 + 0 + } else if fbits < 1086 << 52 { // >= 1, < max + let m = 1 << 63 | fbits << 11; // Mantissa and the implicit 1-bit. + let s = 1086 - (fbits >> 52); // Shift based on the exponent and bias. + let u = (m >> s) as i64; // Unsigned result. + if f.is_sign_negative() { -u } else { u } + } else if fbits <= 2047 << 52 { // >= max (incl. inf) + if f.is_sign_negative() { i64::MIN } else { i64::MAX } + } else { // NaN + 0 + } } #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] - pub extern "C" fn __fixunsdfti(f: f64) -> u128 { - float_to_int(f) + pub extern "C" fn __fixdfti(f: f64) -> i128 { + let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. + if fbits < 1023 << 52 { // >= 0, < 1 + 0 + } else if fbits < 1150 << 52 { // >= 1, < max + let m = 1 << 127 | (fbits as u128) << 75; // Mantissa and the implicit 1-bit. + let s = 1150 - (fbits >> 52); // Shift based on the exponent and bias. + let u = (m >> s) as i128; // Unsigned result. + if f.is_sign_negative() { -u } else { u } + } else if fbits <= 2047 << 52 { // >= max (incl. inf) + if f.is_sign_negative() { i128::MIN } else { i128::MAX } + } else { // NaN + 0 + } } } From dcdd9bbc565ea30a07416b93fe043b95f2abb9c2 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Mon, 23 May 2022 23:34:10 -0700 Subject: [PATCH 1012/4206] Avoid int to ptr transmute by casting first --- library/compiler-builtins/src/arm_linux.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/arm_linux.rs b/library/compiler-builtins/src/arm_linux.rs index df1723d99c611..8fe09485bcf36 100644 --- a/library/compiler-builtins/src/arm_linux.rs +++ b/library/compiler-builtins/src/arm_linux.rs @@ -4,11 +4,11 @@ use core::mem; // Kernel-provided user-mode helper functions: // https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt unsafe fn __kuser_cmpxchg(oldval: u32, newval: u32, ptr: *mut u32) -> bool { - let f: extern "C" fn(u32, u32, *mut u32) -> u32 = mem::transmute(0xffff0fc0u32); + let f: extern "C" fn(u32, u32, *mut u32) -> u32 = mem::transmute(0xffff0fc0usize as *const ()); f(oldval, newval, ptr) == 0 } unsafe fn __kuser_memory_barrier() { - let f: extern "C" fn() = mem::transmute(0xffff0fa0u32); + let f: extern "C" fn() = mem::transmute(0xffff0fa0usize as *const ()); f(); } From ac47841ce294f13108fa619fd164b154c3ea7fb7 Mon Sep 17 00:00:00 2001 From: Patryk Wychowaniec Date: Tue, 24 May 2022 19:49:08 +0200 Subject: [PATCH 1013/4206] Add avr_skip for __udivti3 & __umodti3 --- library/compiler-builtins/src/int/udiv.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index c5ef4a6b19770..fb09f87d89cdf 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -57,6 +57,7 @@ intrinsics! { // Note: we use block configuration and not `if cfg!(...)`, because we need to entirely disable // the existence of `u128_div_rem` to get 32-bit SPARC to compile, see `u128_divide_sparc` docs. + #[avr_skip] #[win64_128bit_abi_hack] /// Returns `n / d` pub extern "C" fn __udivti3(n: u128, d: u128) -> u128 { @@ -68,6 +69,7 @@ intrinsics! { } } + #[avr_skip] #[win64_128bit_abi_hack] /// Returns `n % d` pub extern "C" fn __umodti3(n: u128, d: u128) -> u128 { From ca517a25e7c232c7d9a6a72ff4ab70917eb36683 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 26 May 2022 17:17:38 +0200 Subject: [PATCH 1014/4206] Explicitly use parentheses for associativity of shift operators. --- library/compiler-builtins/src/float/conv.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 86847ed6c7933..07b58f3d232e0 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -10,8 +10,8 @@ mod int_to_float { return 0; } let n = i.leading_zeros(); - let a = i << n >> 8; // Significant bits, with bit 24 still in tact. - let b = i << n << 24; // Insignificant bits, only relevant for rounding. + let a = (i << n) >> 8; // Significant bits, with bit 24 still in tact. + let b = (i << n) << 24; // Insignificant bits, only relevant for rounding. let m = a + ((b - (b >> 31 & !a)) >> 31); // Add one when we need to round up. Break ties to even. let e = 157 - n as u32; // Exponent plus 127, minus one. (e << 23) + m // + not |, so the mantissa can overflow into the exponent. @@ -42,8 +42,8 @@ mod int_to_float { return 0; } let n = i.leading_zeros(); - let a = (i << n >> 11) as u64; // Significant bits, with bit 53 still in tact. - let b = (i << n << 53) as u64; // Insignificant bits, only relevant for rounding. + let a = ((i << n) >> 11) as u64; // Significant bits, with bit 53 still in tact. + let b = ((i << n) << 53) as u64; // Insignificant bits, only relevant for rounding. let m = a + ((b - (b >> 63 & !a)) >> 63); // Add one when we need to round up. Break ties to even. let e = 1085 - n as u64; // Exponent plus 1023, minus one. (e << 52) + m // + not |, so the mantissa can overflow into the exponent. @@ -53,7 +53,7 @@ mod int_to_float { let n = i.leading_zeros(); let y = i.wrapping_shl(n); let a = (y >> 104) as u32; // Significant bits, with bit 24 still in tact. - let b = (y >> 72) as u32 | (y << 32 >> 32 != 0) as u32; // Insignificant bits, only relevant for rounding. + let b = (y >> 72) as u32 | ((y << 32) >> 32 != 0) as u32; // Insignificant bits, only relevant for rounding. let m = a + ((b - (b >> 31 & !a)) >> 31); // Add one when we need to round up. Break ties to even. let e = if i == 0 { 0 } else { 253 - n }; // Exponent plus 127, minus one, except for zero. (e << 23) + m // + not |, so the mantissa can overflow into the exponent. From 735ad075010c8462b203df4c10af6029e086dd38 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 26 May 2022 19:54:32 +0100 Subject: [PATCH 1015/4206] Bump to 0.1.73 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 99f2947242d11..ac1794b187a17 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.72" +version = "0.1.73" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 4dbd8387f9bc3e5c30e7c3060db0c1c25cd49f89 Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Tue, 1 Mar 2022 09:50:55 +0100 Subject: [PATCH 1016/4206] Implement faster memcmp for x86_64 x86_64 can load unaligned words in a single cache line as fast as aligned words. Even when crossing cache or page boundaries it is just as fast to do an unaligned word read instead of multiple byte reads. Also add a couple more tests & benchmarks. --- library/compiler-builtins/src/mem/impls.rs | 14 +++ library/compiler-builtins/src/mem/mod.rs | 11 +- library/compiler-builtins/src/mem/x86_64.rs | 41 +++++++ .../testcrate/benches/mem.rs | 104 ++++++++++++++++++ .../compiler-builtins/testcrate/tests/mem.rs | 38 ++++++- 5 files changed, 193 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/src/mem/impls.rs index 8151324254a06..f31366d765c1f 100644 --- a/library/compiler-builtins/src/mem/impls.rs +++ b/library/compiler-builtins/src/mem/impls.rs @@ -265,3 +265,17 @@ pub unsafe fn set_bytes(mut s: *mut u8, c: u8, mut n: usize) { } set_bytes_bytes(s, c, n); } + +#[inline(always)] +pub unsafe fn compare_bytes(s1: *const u8, s2: *const u8, n: usize) { + let mut i = 0; + while i < n { + let a = *s1.add(i); + let b = *s2.add(i); + if a != b { + return a as i32 - b as i32; + } + i += 1; + } + 0 +} diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index a551138612bb6..c5b0ddc16ec33 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -51,16 +51,7 @@ intrinsics! { #[mem_builtin] #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { - let mut i = 0; - while i < n { - let a = *s1.add(i); - let b = *s2.add(i); - if a != b { - return a as i32 - b as i32; - } - i += 1; - } - 0 + impls::compare_bytes(s1, s2, n) } #[mem_builtin] diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index a7ab6f605bdcf..0bfacf713c578 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -16,6 +16,8 @@ // feature is present at compile-time. We don't bother detecting other features. // Note that ERMSB does not enhance the backwards (DF=1) "rep movsb". +use core::mem; + #[inline(always)] #[cfg(target_feature = "ermsb")] pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { @@ -98,3 +100,42 @@ pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { options(att_syntax, nostack, preserves_flags) ); } + +#[inline(always)] +pub unsafe fn compare_bytes( + a: *const u8, + b: *const u8, + n: usize, +) -> i32 { + unsafe fn cmp(mut a: *const T, mut b: *const T, n: usize, f: F) -> i32 + where + T: Clone + Copy + Eq, + U: Clone + Copy + Eq, + F: FnOnce(*const U, *const U, usize) -> i32, + { + for _ in 0..n / mem::size_of::() { + if a.read_unaligned() != b.read_unaligned() { + return f(a.cast(), b.cast(), mem::size_of::()); + } + a = a.add(1); + b = b.add(1); + } + f(a.cast(), b.cast(), n % mem::size_of::()) + } + let c1 = |mut a: *const u8, mut b: *const u8, n| { + for _ in 0..n { + if a.read() != b.read() { + return i32::from(a.read()) - i32::from(b.read()); + } + a = a.add(1); + b = b.add(1); + } + 0 + }; + let c2 = |a: *const u16, b, n| cmp(a, b, n, c1); + let c4 = |a: *const u32, b, n| cmp(a, b, n, c2); + let c8 = |a: *const u64, b, n| cmp(a, b, n, c4); + let c16 = |a: *const u128, b, n| cmp(a, b, n, c8); + let c32 = |a: *const [u128; 2], b, n| cmp(a, b, n, c16); + c32(a.cast(), b.cast(), n) +} diff --git a/library/compiler-builtins/testcrate/benches/mem.rs b/library/compiler-builtins/testcrate/benches/mem.rs index b6883a93b2483..98a040958c4d6 100644 --- a/library/compiler-builtins/testcrate/benches/mem.rs +++ b/library/compiler-builtins/testcrate/benches/mem.rs @@ -96,6 +96,18 @@ fn memcmp_builtin(b: &mut Bencher, n: usize) { }) } +fn memcmp_builtin_unaligned(b: &mut Bencher, n: usize) { + let v1 = AlignedVec::new(0, n); + let mut v2 = AlignedVec::new(0, n); + v2[n - 1] = 1; + b.bytes = n as u64; + b.iter(|| { + let s1: &[u8] = black_box(&v1[0..]); + let s2: &[u8] = black_box(&v2[1..]); + s1.cmp(s2) + }) +} + fn memcmp_rust(b: &mut Bencher, n: usize) { let v1 = AlignedVec::new(0, n); let mut v2 = AlignedVec::new(0, n); @@ -108,6 +120,18 @@ fn memcmp_rust(b: &mut Bencher, n: usize) { }) } +fn memcmp_rust_unaligned(b: &mut Bencher, n: usize) { + let v1 = AlignedVec::new(0, n); + let mut v2 = AlignedVec::new(0, n); + v2[n - 1] = 1; + b.bytes = n as u64; + b.iter(|| { + let s1: &[u8] = black_box(&v1[0..]); + let s2: &[u8] = black_box(&v2[1..]); + unsafe { memcmp(s1.as_ptr(), s2.as_ptr(), n - 1) } + }) +} + fn memmove_builtin(b: &mut Bencher, n: usize, offset: usize) { let mut v = AlignedVec::new(0, n + n / 2 + offset); b.bytes = n as u64; @@ -209,6 +233,38 @@ fn memset_rust_1048576_offset(b: &mut Bencher) { memset_rust(b, 1048576, 65) } +#[bench] +fn memcmp_builtin_8(b: &mut Bencher) { + memcmp_builtin(b, 8) +} +#[bench] +fn memcmp_rust_8(b: &mut Bencher) { + memcmp_rust(b, 8) +} +#[bench] +fn memcmp_builtin_16(b: &mut Bencher) { + memcmp_builtin(b, 16) +} +#[bench] +fn memcmp_rust_16(b: &mut Bencher) { + memcmp_rust(b, 16) +} +#[bench] +fn memcmp_builtin_32(b: &mut Bencher) { + memcmp_builtin(b, 32) +} +#[bench] +fn memcmp_rust_32(b: &mut Bencher) { + memcmp_rust(b, 32) +} +#[bench] +fn memcmp_builtin_64(b: &mut Bencher) { + memcmp_builtin(b, 64) +} +#[bench] +fn memcmp_rust_64(b: &mut Bencher) { + memcmp_rust(b, 64) +} #[bench] fn memcmp_builtin_4096(b: &mut Bencher) { memcmp_builtin(b, 4096) @@ -225,6 +281,54 @@ fn memcmp_builtin_1048576(b: &mut Bencher) { fn memcmp_rust_1048576(b: &mut Bencher) { memcmp_rust(b, 1048576) } +#[bench] +fn memcmp_builtin_unaligned_7(b: &mut Bencher) { + memcmp_builtin_unaligned(b, 8) +} +#[bench] +fn memcmp_rust_unaligned_7(b: &mut Bencher) { + memcmp_rust_unaligned(b, 8) +} +#[bench] +fn memcmp_builtin_unaligned_15(b: &mut Bencher) { + memcmp_builtin_unaligned(b, 16) +} +#[bench] +fn memcmp_rust_unaligned_15(b: &mut Bencher) { + memcmp_rust_unaligned(b, 16) +} +#[bench] +fn memcmp_builtin_unaligned_31(b: &mut Bencher) { + memcmp_builtin_unaligned(b, 32) +} +#[bench] +fn memcmp_rust_unaligned_31(b: &mut Bencher) { + memcmp_rust_unaligned(b, 32) +} +#[bench] +fn memcmp_builtin_unaligned_63(b: &mut Bencher) { + memcmp_builtin_unaligned(b, 64) +} +#[bench] +fn memcmp_rust_unaligned_63(b: &mut Bencher) { + memcmp_rust_unaligned(b, 64) +} +#[bench] +fn memcmp_builtin_unaligned_4095(b: &mut Bencher) { + memcmp_builtin_unaligned(b, 4096) +} +#[bench] +fn memcmp_rust_unaligned_4095(b: &mut Bencher) { + memcmp_rust_unaligned(b, 4096) +} +#[bench] +fn memcmp_builtin_unaligned_1048575(b: &mut Bencher) { + memcmp_builtin_unaligned(b, 1048576) +} +#[bench] +fn memcmp_rust_unaligned_1048575(b: &mut Bencher) { + memcmp_rust_unaligned(b, 1048576) +} #[bench] fn memmove_builtin_4096(b: &mut Bencher) { diff --git a/library/compiler-builtins/testcrate/tests/mem.rs b/library/compiler-builtins/testcrate/tests/mem.rs index 3f20e72a04c8d..69a63e71df598 100644 --- a/library/compiler-builtins/testcrate/tests/mem.rs +++ b/library/compiler-builtins/testcrate/tests/mem.rs @@ -116,11 +116,13 @@ fn memset_nonzero() { #[test] fn memcmp_eq() { - let arr1: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; - let arr2: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; - unsafe { - assert_eq!(memcmp(arr1.as_ptr(), arr2.as_ptr(), 8), 0); - assert_eq!(memcmp(arr1.as_ptr(), arr2.as_ptr(), 3), 0); + let arr1: [u8; 32] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]; + let arr2: [u8; 32] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]; + for i in 0..32 { + unsafe { + assert_eq!(memcmp(arr1.as_ptr(), arr2.as_ptr(), i), 0); + assert_eq!(memcmp(arr2.as_ptr(), arr1.as_ptr(), i), 0); + } } } @@ -134,6 +136,32 @@ fn memcmp_ne() { } } +#[test] +fn memcmp_ne_16() { + let arr1: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + let arr2: [u8; 16] = [0, 1, 2, 3, 4, 5, 7, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + unsafe { + assert!(memcmp(arr1.as_ptr(), arr2.as_ptr(), 16) < 0); + assert!(memcmp(arr2.as_ptr(), arr1.as_ptr(), 16) > 0); + } +} + +#[test] +fn memcmp_ne_32() { + let arr1: [u8; 32] = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + ]; + let arr2: [u8; 32] = [ + 0, 1, 2, 3, 4, 5, 7, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + ]; + unsafe { + assert!(memcmp(arr1.as_ptr(), arr2.as_ptr(), 32) < 0); + assert!(memcmp(arr2.as_ptr(), arr1.as_ptr(), 32) > 0); + } +} + #[derive(Clone, Copy)] struct AlignedStorage([u8; N], [usize; 0]); From d6650678de2239397ae8ab1a6af443a2b2ecfcef Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Fri, 27 May 2022 22:37:54 +0200 Subject: [PATCH 1017/4206] Fix formatting --- library/compiler-builtins/testcrate/tests/mem.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/testcrate/tests/mem.rs b/library/compiler-builtins/testcrate/tests/mem.rs index 69a63e71df598..8385dfc2cec93 100644 --- a/library/compiler-builtins/testcrate/tests/mem.rs +++ b/library/compiler-builtins/testcrate/tests/mem.rs @@ -116,8 +116,14 @@ fn memset_nonzero() { #[test] fn memcmp_eq() { - let arr1: [u8; 32] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]; - let arr2: [u8; 32] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]; + let arr1: [u8; 32] = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, + ]; + let arr2: [u8; 32] = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, + ]; for i in 0..32 { unsafe { assert_eq!(memcmp(arr1.as_ptr(), arr2.as_ptr(), i), 0); From e7a8932e3b6173d98b0925ee5011d8601d023a3b Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Sat, 28 May 2022 00:09:02 +0200 Subject: [PATCH 1018/4206] Fix CI, better memcmp tests --- library/compiler-builtins/src/mem/impls.rs | 2 +- library/compiler-builtins/src/mem/x86_64.rs | 6 +- .../compiler-builtins/testcrate/tests/mem.rs | 55 +++++-------------- 3 files changed, 15 insertions(+), 48 deletions(-) diff --git a/library/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/src/mem/impls.rs index f31366d765c1f..72003a5c472b2 100644 --- a/library/compiler-builtins/src/mem/impls.rs +++ b/library/compiler-builtins/src/mem/impls.rs @@ -267,7 +267,7 @@ pub unsafe fn set_bytes(mut s: *mut u8, c: u8, mut n: usize) { } #[inline(always)] -pub unsafe fn compare_bytes(s1: *const u8, s2: *const u8, n: usize) { +pub unsafe fn compare_bytes(s1: *const u8, s2: *const u8, n: usize) -> i32 { let mut i = 0; while i < n { let a = *s1.add(i); diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 0bfacf713c578..fc89aa768d337 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -102,11 +102,7 @@ pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { } #[inline(always)] -pub unsafe fn compare_bytes( - a: *const u8, - b: *const u8, - n: usize, -) -> i32 { +pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { unsafe fn cmp(mut a: *const T, mut b: *const T, n: usize, f: F) -> i32 where T: Clone + Copy + Eq, diff --git a/library/compiler-builtins/testcrate/tests/mem.rs b/library/compiler-builtins/testcrate/tests/mem.rs index 8385dfc2cec93..48ac95adc17f4 100644 --- a/library/compiler-builtins/testcrate/tests/mem.rs +++ b/library/compiler-builtins/testcrate/tests/mem.rs @@ -116,55 +116,26 @@ fn memset_nonzero() { #[test] fn memcmp_eq() { - let arr1: [u8; 32] = [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, - ]; - let arr2: [u8; 32] = [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, - ]; - for i in 0..32 { + let arr1 @ arr2 = gen_arr::<256>(); + for i in 0..256 { unsafe { - assert_eq!(memcmp(arr1.as_ptr(), arr2.as_ptr(), i), 0); - assert_eq!(memcmp(arr2.as_ptr(), arr1.as_ptr(), i), 0); + assert_eq!(memcmp(arr1.0.as_ptr(), arr2.0.as_ptr(), i), 0); + assert_eq!(memcmp(arr2.0.as_ptr(), arr1.0.as_ptr(), i), 0); } } } #[test] fn memcmp_ne() { - let arr1: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; - let arr2: [u8; 8] = [0, 1, 2, 3, 4, 5, 7, 7]; - unsafe { - assert!(memcmp(arr1.as_ptr(), arr2.as_ptr(), 8) < 0); - assert!(memcmp(arr2.as_ptr(), arr1.as_ptr(), 8) > 0); - } -} - -#[test] -fn memcmp_ne_16() { - let arr1: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; - let arr2: [u8; 16] = [0, 1, 2, 3, 4, 5, 7, 7, 8, 9, 10, 11, 12, 13, 14, 15]; - unsafe { - assert!(memcmp(arr1.as_ptr(), arr2.as_ptr(), 16) < 0); - assert!(memcmp(arr2.as_ptr(), arr1.as_ptr(), 16) > 0); - } -} - -#[test] -fn memcmp_ne_32() { - let arr1: [u8; 32] = [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, - ]; - let arr2: [u8; 32] = [ - 0, 1, 2, 3, 4, 5, 7, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, - ]; - unsafe { - assert!(memcmp(arr1.as_ptr(), arr2.as_ptr(), 32) < 0); - assert!(memcmp(arr2.as_ptr(), arr1.as_ptr(), 32) > 0); + let arr1 @ arr2 = gen_arr::<256>(); + for i in 0..256 { + let mut diff_arr = arr1; + diff_arr.0[i] = 127; + let expect = diff_arr.0[i].cmp(&arr2.0[i]); + for k in i + 1..256 { + let result = unsafe { memcmp(diff_arr.0.as_ptr(), arr2.0.as_ptr(), k) }; + assert_eq!(expect, result.cmp(&0)); + } } } From 2071d05a19980737bbb15948c5d914cae7ba23de Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Sat, 28 May 2022 00:50:05 +0200 Subject: [PATCH 1019/4206] Always inline compare_bytes::cmp --- library/compiler-builtins/src/mem/x86_64.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index fc89aa768d337..65b61224dc22b 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -103,6 +103,7 @@ pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { #[inline(always)] pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { + #[inline(always)] unsafe fn cmp(mut a: *const T, mut b: *const T, n: usize, f: F) -> i32 where T: Clone + Copy + Eq, From 217748f91bbe20959262a46246edf2d0d3c9a7bd Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Sat, 28 May 2022 01:23:50 +0200 Subject: [PATCH 1020/4206] Fix panic not being optimized out. I don't know why it isn't being optimized out though, which worries me. --- library/compiler-builtins/src/lib.rs | 1 + library/compiler-builtins/src/mem/x86_64.rs | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 009923d27e5b4..acac040be3329 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -6,6 +6,7 @@ #![feature(compiler_builtins)] #![feature(core_ffi_c)] #![feature(core_intrinsics)] +#![feature(inline_const)] #![feature(lang_items)] #![feature(linkage)] #![feature(naked_functions)] diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 65b61224dc22b..6eecd5a515e67 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -110,14 +110,20 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { U: Clone + Copy + Eq, F: FnOnce(*const U, *const U, usize) -> i32, { - for _ in 0..n / mem::size_of::() { + // Just to be sure we're actually working with powers of two... + let _ = const { 1 - mem::size_of::().count_ones() }; // <= 1 + let _ = const { mem::size_of::().count_ones() - 1 }; // >= 1 + // This should be equivalent to division with power-of-two sizes, except the former + // somehow still leaves a call to panic because ?? + for _ in 0..n >> mem::size_of::().trailing_zeros() { if a.read_unaligned() != b.read_unaligned() { return f(a.cast(), b.cast(), mem::size_of::()); } a = a.add(1); b = b.add(1); } - f(a.cast(), b.cast(), n % mem::size_of::()) + // Ditto + f(a.cast(), b.cast(), n & (mem::size_of::() - 1)) } let c1 = |mut a: *const u8, mut b: *const u8, n| { for _ in 0..n { From 95d2cd550288c798e14be620229de936c54cc0c3 Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Sat, 28 May 2022 08:16:46 +0200 Subject: [PATCH 1021/4206] Fix rustfmt sillyness --- library/compiler-builtins/src/mem/x86_64.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 6eecd5a515e67..66b51fedf8a9f 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -113,6 +113,7 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { // Just to be sure we're actually working with powers of two... let _ = const { 1 - mem::size_of::().count_ones() }; // <= 1 let _ = const { mem::size_of::().count_ones() - 1 }; // >= 1 + // This should be equivalent to division with power-of-two sizes, except the former // somehow still leaves a call to panic because ?? for _ in 0..n >> mem::size_of::().trailing_zeros() { From b94e93ead806cc90f9831ca6a150318edcea35fe Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Sat, 28 May 2022 22:46:16 +0200 Subject: [PATCH 1022/4206] Slightly optimize main (32b) memcmp loop It only seems to save a single instruction at first sight yet the effects are significant. --- library/compiler-builtins/src/mem/x86_64.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 66b51fedf8a9f..2b4875697ae58 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -116,7 +116,8 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { // This should be equivalent to division with power-of-two sizes, except the former // somehow still leaves a call to panic because ?? - for _ in 0..n >> mem::size_of::().trailing_zeros() { + let end = a.add(n >> mem::size_of::().trailing_zeros()); + while a != end { if a.read_unaligned() != b.read_unaligned() { return f(a.cast(), b.cast(), mem::size_of::()); } From cb63d7d500f03b19618fd166e1cd9afd91612fa6 Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Tue, 31 May 2022 08:20:30 +0200 Subject: [PATCH 1023/4206] Use unchecked_div/rem --- library/compiler-builtins/src/mem/x86_64.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 2b4875697ae58..4d2f6e5ee3296 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -16,6 +16,7 @@ // feature is present at compile-time. We don't bother detecting other features. // Note that ERMSB does not enhance the backwards (DF=1) "rep movsb". +use core::intrinsics; use core::mem; #[inline(always)] @@ -110,13 +111,10 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { U: Clone + Copy + Eq, F: FnOnce(*const U, *const U, usize) -> i32, { - // Just to be sure we're actually working with powers of two... - let _ = const { 1 - mem::size_of::().count_ones() }; // <= 1 - let _ = const { mem::size_of::().count_ones() - 1 }; // >= 1 + // Ensure T is not a ZST. + const { assert!(mem::size_of::() != 0) }; - // This should be equivalent to division with power-of-two sizes, except the former - // somehow still leaves a call to panic because ?? - let end = a.add(n >> mem::size_of::().trailing_zeros()); + let end = a.add(intrinsics::unchecked_div(n, mem::size_of::())); while a != end { if a.read_unaligned() != b.read_unaligned() { return f(a.cast(), b.cast(), mem::size_of::()); @@ -124,8 +122,11 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { a = a.add(1); b = b.add(1); } - // Ditto - f(a.cast(), b.cast(), n & (mem::size_of::() - 1)) + f( + a.cast(), + b.cast(), + intrinsics::unchecked_rem(n, mem::size_of::()), + ) } let c1 = |mut a: *const u8, mut b: *const u8, n| { for _ in 0..n { From cfc0422a7e5427ca7571392f101f729abd495832 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 31 May 2022 17:19:27 +0100 Subject: [PATCH 1024/4206] Bump to 0.1.74 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index ac1794b187a17..31cf41265fb48 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.73" +version = "0.1.74" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From bb0b7d660f47e8c383267a9524ede705859b87d3 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Thu, 9 Jun 2022 08:40:15 +0800 Subject: [PATCH 1025/4206] build: compile C code for "xous" operating system The "xous" operating system is enturely Rust-based, meaning it has no libc. Therefore, it relies on `compiler-builtins` for all intrinsics. Unfortunately, there are not yet Rust equivalents for all C functions. For example, triganometric functions are still missing. In the meantime, enable C replacements for these functions so that Rust programs compiled for Xous can call these functions. Signed-off-by: Sean Cross --- library/compiler-builtins/build.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 11deffb9c926c..876224934211a 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -58,9 +58,11 @@ fn main() { // unlikely that the C is really that much better than our own Rust. // * nvptx - everything is bitcode, not compatible with mixed C/Rust // * riscv - the rust-lang/rust distribution container doesn't have a C - // compiler nor is cc-rs ready for compilation to riscv (at this - // time). This can probably be removed in the future - if !target.contains("wasm") && !target.contains("nvptx") && !target.starts_with("riscv") { + // compiler. + if !target.contains("wasm") + && !target.contains("nvptx") + && (!target.starts_with("riscv") || target.contains("xous")) + { #[cfg(feature = "c")] c::compile(&llvm_target, &target); } From 7cdad114a59af6b503f611e82ba3a5fd177c4c36 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Thu, 9 Sep 2021 11:21:33 +0800 Subject: [PATCH 1026/4206] math: compile math functions for Xous This adds support for Xous, enabling users to call math functions on primitives such as `cos()`. Signed-off-by: Sean Cross --- library/compiler-builtins/src/lib.rs | 1 + library/compiler-builtins/src/math.rs | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index acac040be3329..e7bc61e4c0f60 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -46,6 +46,7 @@ pub mod int; all(target_family = "wasm", target_os = "unknown"), all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "arm", target_os = "none"), + target_os = "xous", all(target_vendor = "fortanix", target_env = "sgx") ))] pub mod math; diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index fa59753f8f6cd..14a65395eb8e1 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -20,6 +20,7 @@ macro_rules! no_mangle { target_os = "unknown", not(target_env = "wasi") ), + target_os = "xous", all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "xtensa", target_os = "none"), all(target_vendor = "fortanix", target_env = "sgx") @@ -70,6 +71,7 @@ no_mangle! { target_os = "unknown", not(target_env = "wasi") ), + target_os = "xous", all(target_arch = "xtensa", target_os = "none"), all(target_vendor = "fortanix", target_env = "sgx") ))] @@ -93,7 +95,16 @@ no_mangle! { fn tanf(n: f32) -> f32; } -#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] +#[cfg(target_os = "xous")] +no_mangle! { + fn sqrtf(x: f32) -> f32; + fn sqrt(x: f64) -> f64; +} + +#[cfg(any( + all(target_vendor = "fortanix", target_env = "sgx"), + target_os = "xous" +))] no_mangle! { fn ceil(x: f64) -> f64; fn ceilf(x: f32) -> f32; From 08f4f4007d9aaaef367949c2d31c0882b4f1bc27 Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Sat, 11 Jun 2022 09:13:28 +0200 Subject: [PATCH 1027/4206] Fix infinite recursion in x86_64 memcmp if SSE2 is not present Fixes #470 --- library/compiler-builtins/src/mem/x86_64.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 4d2f6e5ee3296..3b372d10d1a99 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -143,5 +143,16 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { let c8 = |a: *const u64, b, n| cmp(a, b, n, c4); let c16 = |a: *const u128, b, n| cmp(a, b, n, c8); let c32 = |a: *const [u128; 2], b, n| cmp(a, b, n, c16); - c32(a.cast(), b.cast(), n) + // [u128; 2] internally uses raw_eq for comparisons, which may emit a call to memcmp + // above a certain size threshold. When SSE2 is enabled this threshold does not seem + // to be reached but without SSE2 a call is emitted, leading to infinite recursion. + // + // While replacing [u128; 2] with (u128, u128) fixes the issues it degrades performance + // severely. Likewise, removing c32() has a lesser but still significant impact. Instead the + // [u128; 2] case is only enabled when SSE2 is present. + if cfg!(target_feature = "sse2") { + c32(a.cast(), b.cast(), n) + } else { + c16(a.cast(), b.cast(), n) + } } From 4d44679eb5e5ce9fc10fa12ff31330f9a1b5ce57 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 12 Jun 2022 01:19:53 +0100 Subject: [PATCH 1028/4206] Bump to 0.1.75 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 31cf41265fb48..520a1f7dc98b9 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.74" +version = "0.1.75" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From f6ab9ca9a7c469af22deb9ae93d63c30efe95b6c Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Tue, 28 Jun 2022 20:16:07 +0530 Subject: [PATCH 1029/4206] Enable mem for UEFI Signed-off-by: Ayush Singh --- library/compiler-builtins/build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 11deffb9c926c..8d482fa21993f 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -29,6 +29,7 @@ fn main() { || (target.contains("sgx") && target.contains("fortanix")) || target.contains("-none") || target.contains("nvptx") + || target.contains("uefi") { println!("cargo:rustc-cfg=feature=\"mem\""); } From 5e484198368fe373ff6245d5cc5518f858a78c73 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 29 Jun 2022 01:08:54 +0100 Subject: [PATCH 1030/4206] Bump to 0.1.76 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 520a1f7dc98b9..22ce34d366a92 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.75" +version = "0.1.76" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 011f92c877db3cc595f0a8c1e6ad3649e5481dbc Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 22 Jul 2022 17:14:18 -0600 Subject: [PATCH 1031/4206] add weak linkage to the ARM AEABI division functions --- library/compiler-builtins/src/arm.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 9c1b6ad123ae5..f3b22544a8ce3 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -22,6 +22,7 @@ intrinsics! { // custom calling convention which can't be implemented using a normal Rust function. #[naked] #[cfg(not(target_env = "msvc"))] + #[linkage = "weak"] pub unsafe extern "C" fn __aeabi_uidivmod() { core::arch::asm!( "push {{lr}}", @@ -36,6 +37,7 @@ intrinsics! { } #[naked] + #[linkage = "weak"] pub unsafe extern "C" fn __aeabi_uldivmod() { core::arch::asm!( "push {{r4, lr}}", @@ -52,6 +54,7 @@ intrinsics! { } #[naked] + #[linkage = "weak"] pub unsafe extern "C" fn __aeabi_idivmod() { core::arch::asm!( "push {{r0, r1, r4, lr}}", @@ -65,6 +68,7 @@ intrinsics! { } #[naked] + #[linkage = "weak"] pub unsafe extern "C" fn __aeabi_ldivmod() { core::arch::asm!( "push {{r4, lr}}", From 6b6db5cc843e6790367a16d8c4238e0f9dd9e5bd Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 28 Jul 2022 16:02:04 +0100 Subject: [PATCH 1032/4206] Disable some PPC64 tests which are failing due to an LLVM(?) bug See https://github.com/rust-lang/rust/issues/99853 --- library/compiler-builtins/testcrate/tests/mem.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/compiler-builtins/testcrate/tests/mem.rs b/library/compiler-builtins/testcrate/tests/mem.rs index 48ac95adc17f4..5099d69ed6c3c 100644 --- a/library/compiler-builtins/testcrate/tests/mem.rs +++ b/library/compiler-builtins/testcrate/tests/mem.rs @@ -230,6 +230,8 @@ fn memmove_backward_aligned() { } } +// PowerPC tests are failing: https://github.com/rust-lang/rust/issues/99853 +#[cfg(not(target_arch = "powerpc64"))] #[test] fn memset_backward_misaligned_nonaligned_start() { let mut arr = gen_arr::<32>(); @@ -242,6 +244,8 @@ fn memset_backward_misaligned_nonaligned_start() { } } +// PowerPC tests are failing: https://github.com/rust-lang/rust/issues/99853 +#[cfg(not(target_arch = "powerpc64"))] #[test] fn memset_backward_misaligned_aligned_start() { let mut arr = gen_arr::<32>(); @@ -254,6 +258,8 @@ fn memset_backward_misaligned_aligned_start() { } } +// PowerPC tests are failing: https://github.com/rust-lang/rust/issues/99853 +#[cfg(not(target_arch = "powerpc64"))] #[test] fn memset_backward_aligned() { let mut arr = gen_arr::<32>(); From f2ac36348c9b8570732ed2153cf4ffd50bc8f172 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Thu, 28 Jul 2022 17:58:16 +0530 Subject: [PATCH 1033/4206] Use all of src/math for UEFI This is needed for libtest --- library/compiler-builtins/src/math.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 14a65395eb8e1..7337dabb93a70 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -72,6 +72,7 @@ no_mangle! { not(target_env = "wasi") ), target_os = "xous", + all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "xtensa", target_os = "none"), all(target_vendor = "fortanix", target_env = "sgx") ))] @@ -95,7 +96,7 @@ no_mangle! { fn tanf(n: f32) -> f32; } -#[cfg(target_os = "xous")] +#[cfg(any(target_os = "xous", target_os = "uefi"))] no_mangle! { fn sqrtf(x: f32) -> f32; fn sqrt(x: f64) -> f64; @@ -103,7 +104,8 @@ no_mangle! { #[cfg(any( all(target_vendor = "fortanix", target_env = "sgx"), - target_os = "xous" + target_os = "xous", + target_os = "uefi" ))] no_mangle! { fn ceil(x: f64) -> f64; From 8568a33255ab36b8be9a6b19c9fa2ee4628621ae Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 28 Jul 2022 09:42:18 -0600 Subject: [PATCH 1034/4206] restrict linkage to platforms using ELF binaries on windows and apple (which don't use ELF) we can't apply weak linkage --- library/compiler-builtins/src/arm.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index f3b22544a8ce3..e517a9ef34b8d 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -22,7 +22,7 @@ intrinsics! { // custom calling convention which can't be implemented using a normal Rust function. #[naked] #[cfg(not(target_env = "msvc"))] - #[linkage = "weak"] + #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] pub unsafe extern "C" fn __aeabi_uidivmod() { core::arch::asm!( "push {{lr}}", @@ -37,7 +37,7 @@ intrinsics! { } #[naked] - #[linkage = "weak"] + #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] pub unsafe extern "C" fn __aeabi_uldivmod() { core::arch::asm!( "push {{r4, lr}}", @@ -54,7 +54,7 @@ intrinsics! { } #[naked] - #[linkage = "weak"] + #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] pub unsafe extern "C" fn __aeabi_idivmod() { core::arch::asm!( "push {{r0, r1, r4, lr}}", @@ -68,7 +68,7 @@ intrinsics! { } #[naked] - #[linkage = "weak"] + #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] pub unsafe extern "C" fn __aeabi_ldivmod() { core::arch::asm!( "push {{r4, lr}}", From 586e2b38ef2f5dabad565dfa96bf1625aba134df Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 9 Jul 2022 22:41:14 -0400 Subject: [PATCH 1035/4206] Enable win64_128bit_abi_hack for x86_64-unknown-uefi The `x86_64-unknown-uefi` target is Windows-like [1], and requires the same altered ABI for some 128-bit integer intrinsics. See also https://github.com/rust-lang/rust/issues/86494. [1]: https://github.com/rust-lang/rust/blob/master/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs --- library/compiler-builtins/src/macros.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 518a18d4de8de..6acf1be969e87 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -209,13 +209,13 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( - #[cfg(all(windows, target_arch = "x86_64"))] + #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64"))] $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } - #[cfg(all(windows, target_arch = "x86_64"))] + #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64"))] pub mod $name { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] pub extern $abi fn $name( $($argname: $ty),* ) @@ -226,7 +226,7 @@ macro_rules! intrinsics { } } - #[cfg(not(all(windows, target_arch = "x86_64")))] + #[cfg(not(all(any(windows, target_os = "uefi"), target_arch = "x86_64")))] intrinsics! { $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { @@ -426,7 +426,7 @@ macro_rules! intrinsics { // Hack for LLVM expectations for ABI on windows. This is used by the // `#[win64_128bit_abi_hack]` attribute recognized above -#[cfg(all(windows, target_pointer_width = "64"))] +#[cfg(all(any(windows, target_os = "uefi"), target_pointer_width = "64"))] pub mod win64_128bit_abi_hack { #[repr(simd)] pub struct U64x2(u64, u64); From a977b01090ce83dd2cfc900b77ceaeb6eb61f795 Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Sat, 2 Jul 2022 23:54:30 +0200 Subject: [PATCH 1036/4206] Align destination in mem* instructions. While misaligned reads are generally fast, misaligned writes aren't and can have severe penalties. --- library/compiler-builtins/src/mem/x86_64.rs | 130 ++++++++++++++------ 1 file changed, 94 insertions(+), 36 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 3b372d10d1a99..68ef17f1e8671 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -16,6 +16,7 @@ // feature is present at compile-time. We don't bother detecting other features. // Note that ERMSB does not enhance the backwards (DF=1) "rep movsb". +use core::arch::asm; use core::intrinsics; use core::mem; @@ -34,40 +35,61 @@ pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { #[inline(always)] #[cfg(not(target_feature = "ermsb"))] -pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { - let qword_count = count >> 3; - let byte_count = count & 0b111; - // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - core::arch::asm!( - "repe movsq (%rsi), (%rdi)", - "mov {byte_count:e}, %ecx", - "repe movsb (%rsi), (%rdi)", - byte_count = in(reg) byte_count, +pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, count: usize) { + let (pre_byte_count, qword_count, byte_count) = rep_param(dest, count); + // Separating the blocks gives the compiler more freedom to reorder instructions. + // It also allows us to trivially skip the rep movsb, which is faster when memcpying + // aligned data. + if pre_byte_count > 0 { + asm!( + "rep movsb", + inout("ecx") pre_byte_count => _, + inout("rdi") dest => dest, + inout("rsi") src => src, + options(nostack, preserves_flags) + ); + } + asm!( + "rep movsq", inout("rcx") qword_count => _, - inout("rdi") dest => _, - inout("rsi") src => _, - options(att_syntax, nostack, preserves_flags) + inout("rdi") dest => dest, + inout("rsi") src => src, + options(nostack, preserves_flags) ); + if byte_count > 0 { + asm!( + "rep movsb", + inout("ecx") byte_count => _, + inout("rdi") dest => _, + inout("rsi") src => _, + options(nostack, preserves_flags) + ); + } } #[inline(always)] pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { - let qword_count = count >> 3; - let byte_count = count & 0b111; - // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - core::arch::asm!( + let (pre_byte_count, qword_count, byte_count) = rep_param_rev(dest, count); + // We can't separate this block due to std/cld + asm!( "std", - "repe movsq (%rsi), (%rdi)", - "movl {byte_count:e}, %ecx", - "addq $7, %rdi", - "addq $7, %rsi", - "repe movsb (%rsi), (%rdi)", + "rep movsb", + "sub rsi, 7", + "sub rdi, 7", + "mov rcx, {qword_count}", + "rep movsq", + "add rsi, 7", + "add rdi, 7", + "mov ecx, {byte_count:e}", + "rep movsb", "cld", byte_count = in(reg) byte_count, - inout("rcx") qword_count => _, - inout("rdi") dest.add(count).wrapping_sub(8) => _, - inout("rsi") src.add(count).wrapping_sub(8) => _, - options(att_syntax, nostack) + qword_count = in(reg) qword_count, + inout("ecx") pre_byte_count => _, + inout("rdi") dest.add(count - 1) => _, + inout("rsi") src.add(count - 1) => _, + // We modify flags, but we restore it afterwards + options(nostack, preserves_flags) ); } @@ -86,20 +108,36 @@ pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { #[inline(always)] #[cfg(not(target_feature = "ermsb"))] -pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { - let qword_count = count >> 3; - let byte_count = count & 0b111; - // FIXME: Use the Intel syntax once we drop LLVM 9 support on rust-lang/rust. - core::arch::asm!( - "repe stosq %rax, (%rdi)", - "mov {byte_count:e}, %ecx", - "repe stosb %al, (%rdi)", - byte_count = in(reg) byte_count, +pub unsafe fn set_bytes(mut dest: *mut u8, c: u8, count: usize) { + let (pre_byte_count, qword_count, byte_count) = rep_param(dest, count); + // Separating the blocks gives the compiler more freedom to reorder instructions. + // It also allows us to trivially skip the rep stosb, which is faster when memcpying + // aligned data. + if pre_byte_count > 0 { + asm!( + "rep stosb", + inout("ecx") pre_byte_count => _, + inout("rdi") dest => dest, + in("al") c, + options(nostack, preserves_flags) + ); + } + asm!( + "rep stosq", inout("rcx") qword_count => _, - inout("rdi") dest => _, + inout("rdi") dest => dest, in("rax") (c as u64) * 0x0101010101010101, - options(att_syntax, nostack, preserves_flags) + options(nostack, preserves_flags) ); + if byte_count > 0 { + asm!( + "rep stosb", + inout("ecx") byte_count => _, + inout("rdi") dest => _, + in("al") c, + options(nostack, preserves_flags) + ); + } } #[inline(always)] @@ -156,3 +194,23 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { c16(a.cast(), b.cast(), n) } } + +/// Determine optimal parameters for a `rep` instruction. +fn rep_param(dest: *mut u8, mut count: usize) -> (usize, usize, usize) { + // Unaligned writes are still slow on modern processors, so align the destination address. + let pre_byte_count = ((8 - (dest as usize & 0b111)) & 0b111).min(count); + count -= pre_byte_count; + let qword_count = count >> 3; + let byte_count = count & 0b111; + (pre_byte_count, qword_count, byte_count) +} + +/// Determine optimal parameters for a reverse `rep` instruction (i.e. direction bit is set). +fn rep_param_rev(dest: *mut u8, mut count: usize) -> (usize, usize, usize) { + // Unaligned writes are still slow on modern processors, so align the destination address. + let pre_byte_count = ((dest as usize + count) & 0b111).min(count); + count -= pre_byte_count; + let qword_count = count >> 3; + let byte_count = count & 0b111; + (pre_byte_count, qword_count, byte_count) +} From 45e2996c965162844433ac72702681c9cb571580 Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Thu, 7 Jul 2022 11:53:44 +0200 Subject: [PATCH 1037/4206] Fix suboptimal codegen in memset --- library/compiler-builtins/src/mem/x86_64.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 68ef17f1e8671..3cbbbba53e32c 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -109,6 +109,7 @@ pub unsafe fn set_bytes(dest: *mut u8, c: u8, count: usize) { #[inline(always)] #[cfg(not(target_feature = "ermsb"))] pub unsafe fn set_bytes(mut dest: *mut u8, c: u8, count: usize) { + let c = c as u64 * 0x0101_0101_0101_0101; let (pre_byte_count, qword_count, byte_count) = rep_param(dest, count); // Separating the blocks gives the compiler more freedom to reorder instructions. // It also allows us to trivially skip the rep stosb, which is faster when memcpying @@ -118,7 +119,7 @@ pub unsafe fn set_bytes(mut dest: *mut u8, c: u8, count: usize) { "rep stosb", inout("ecx") pre_byte_count => _, inout("rdi") dest => dest, - in("al") c, + in("rax") c, options(nostack, preserves_flags) ); } @@ -126,7 +127,7 @@ pub unsafe fn set_bytes(mut dest: *mut u8, c: u8, count: usize) { "rep stosq", inout("rcx") qword_count => _, inout("rdi") dest => dest, - in("rax") (c as u64) * 0x0101010101010101, + in("rax") c, options(nostack, preserves_flags) ); if byte_count > 0 { @@ -134,7 +135,7 @@ pub unsafe fn set_bytes(mut dest: *mut u8, c: u8, count: usize) { "rep stosb", inout("ecx") byte_count => _, inout("rdi") dest => _, - in("al") c, + in("rax") c, options(nostack, preserves_flags) ); } From 897a1338698a13b82bea082110aad71e4a952ae1 Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Thu, 7 Jul 2022 13:13:19 +0200 Subject: [PATCH 1038/4206] Remove rep_param_rev --- library/compiler-builtins/src/mem/x86_64.rs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 3cbbbba53e32c..483a3e31b79a8 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -69,7 +69,7 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, count: usize) #[inline(always)] pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { - let (pre_byte_count, qword_count, byte_count) = rep_param_rev(dest, count); + let (pre_byte_count, qword_count, byte_count) = rep_param(dest, count); // We can't separate this block due to std/cld asm!( "std", @@ -80,12 +80,12 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { "rep movsq", "add rsi, 7", "add rdi, 7", - "mov ecx, {byte_count:e}", + "mov ecx, {pre_byte_count:e}", "rep movsb", "cld", - byte_count = in(reg) byte_count, + pre_byte_count = in(reg) pre_byte_count, qword_count = in(reg) qword_count, - inout("ecx") pre_byte_count => _, + inout("ecx") byte_count => _, inout("rdi") dest.add(count - 1) => _, inout("rsi") src.add(count - 1) => _, // We modify flags, but we restore it afterwards @@ -205,13 +205,3 @@ fn rep_param(dest: *mut u8, mut count: usize) -> (usize, usize, usize) { let byte_count = count & 0b111; (pre_byte_count, qword_count, byte_count) } - -/// Determine optimal parameters for a reverse `rep` instruction (i.e. direction bit is set). -fn rep_param_rev(dest: *mut u8, mut count: usize) -> (usize, usize, usize) { - // Unaligned writes are still slow on modern processors, so align the destination address. - let pre_byte_count = ((dest as usize + count) & 0b111).min(count); - count -= pre_byte_count; - let qword_count = count >> 3; - let byte_count = count & 0b111; - (pre_byte_count, qword_count, byte_count) -} From 30e0c1f4c296bef105368c0a7025a0f9228a5188 Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Thu, 7 Jul 2022 13:19:06 +0200 Subject: [PATCH 1039/4206] Use att_syntax for now --- library/compiler-builtins/src/mem/x86_64.rs | 26 ++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 483a3e31b79a8..a1015f61282ae 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -46,7 +46,7 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, count: usize) inout("ecx") pre_byte_count => _, inout("rdi") dest => dest, inout("rsi") src => src, - options(nostack, preserves_flags) + options(att_syntax, nostack, preserves_flags) ); } asm!( @@ -54,7 +54,7 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, count: usize) inout("rcx") qword_count => _, inout("rdi") dest => dest, inout("rsi") src => src, - options(nostack, preserves_flags) + options(att_syntax, nostack, preserves_flags) ); if byte_count > 0 { asm!( @@ -62,7 +62,7 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, count: usize) inout("ecx") byte_count => _, inout("rdi") dest => _, inout("rsi") src => _, - options(nostack, preserves_flags) + options(att_syntax, nostack, preserves_flags) ); } } @@ -74,13 +74,13 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { asm!( "std", "rep movsb", - "sub rsi, 7", - "sub rdi, 7", - "mov rcx, {qword_count}", + "sub $7, %rsi", + "sub $7, %rdi", + "mov {qword_count}, %rcx", "rep movsq", - "add rsi, 7", - "add rdi, 7", - "mov ecx, {pre_byte_count:e}", + "add $7, %rsi", + "add $7, %rdi", + "mov {pre_byte_count:e}, %ecx", "rep movsb", "cld", pre_byte_count = in(reg) pre_byte_count, @@ -89,7 +89,7 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { inout("rdi") dest.add(count - 1) => _, inout("rsi") src.add(count - 1) => _, // We modify flags, but we restore it afterwards - options(nostack, preserves_flags) + options(att_syntax, nostack, preserves_flags) ); } @@ -120,7 +120,7 @@ pub unsafe fn set_bytes(mut dest: *mut u8, c: u8, count: usize) { inout("ecx") pre_byte_count => _, inout("rdi") dest => dest, in("rax") c, - options(nostack, preserves_flags) + options(att_syntax, nostack, preserves_flags) ); } asm!( @@ -128,7 +128,7 @@ pub unsafe fn set_bytes(mut dest: *mut u8, c: u8, count: usize) { inout("rcx") qword_count => _, inout("rdi") dest => dest, in("rax") c, - options(nostack, preserves_flags) + options(att_syntax, nostack, preserves_flags) ); if byte_count > 0 { asm!( @@ -136,7 +136,7 @@ pub unsafe fn set_bytes(mut dest: *mut u8, c: u8, count: usize) { inout("ecx") byte_count => _, inout("rdi") dest => _, in("rax") c, - options(nostack, preserves_flags) + options(att_syntax, nostack, preserves_flags) ); } } From 04c223f0df126df6c0e076caab33d04f9792c317 Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Thu, 7 Jul 2022 13:20:41 +0200 Subject: [PATCH 1040/4206] Skip rep movsb in copy_backward if possible There is currently no measureable performance difference in benchmarks but it likely will make a difference in real workloads. --- library/compiler-builtins/src/mem/x86_64.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index a1015f61282ae..e9c1c56d539be 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -73,15 +73,21 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { // We can't separate this block due to std/cld asm!( "std", + "test %ecx, %ecx", + "jz 1f", "rep movsb", + "1:", "sub $7, %rsi", "sub $7, %rdi", "mov {qword_count}, %rcx", "rep movsq", + "test {pre_byte_count:e}, {pre_byte_count:e}", + "jz 1f", "add $7, %rsi", "add $7, %rdi", "mov {pre_byte_count:e}, %ecx", "rep movsb", + "1:", "cld", pre_byte_count = in(reg) pre_byte_count, qword_count = in(reg) qword_count, From 66f22e0931e00d5c0beb2f6564ca0c45d3f80699 Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Thu, 28 Jul 2022 18:43:45 +0200 Subject: [PATCH 1041/4206] Remove branches around rep movsb/stosb While it is measurably faster for older CPUs, removing them keeps the code smaller and is likely more beneficial for newer CPUs. --- library/compiler-builtins/src/mem/x86_64.rs | 73 ++++++++------------- 1 file changed, 28 insertions(+), 45 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index e9c1c56d539be..dd98e37c5f0fa 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -38,17 +38,13 @@ pub unsafe fn copy_forward(dest: *mut u8, src: *const u8, count: usize) { pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, count: usize) { let (pre_byte_count, qword_count, byte_count) = rep_param(dest, count); // Separating the blocks gives the compiler more freedom to reorder instructions. - // It also allows us to trivially skip the rep movsb, which is faster when memcpying - // aligned data. - if pre_byte_count > 0 { - asm!( - "rep movsb", - inout("ecx") pre_byte_count => _, - inout("rdi") dest => dest, - inout("rsi") src => src, - options(att_syntax, nostack, preserves_flags) - ); - } + asm!( + "rep movsb", + inout("ecx") pre_byte_count => _, + inout("rdi") dest => dest, + inout("rsi") src => src, + options(att_syntax, nostack, preserves_flags) + ); asm!( "rep movsq", inout("rcx") qword_count => _, @@ -56,15 +52,13 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, count: usize) inout("rsi") src => src, options(att_syntax, nostack, preserves_flags) ); - if byte_count > 0 { - asm!( - "rep movsb", - inout("ecx") byte_count => _, - inout("rdi") dest => _, - inout("rsi") src => _, - options(att_syntax, nostack, preserves_flags) - ); - } + asm!( + "rep movsb", + inout("ecx") byte_count => _, + inout("rdi") dest => _, + inout("rsi") src => _, + options(att_syntax, nostack, preserves_flags) + ); } #[inline(always)] @@ -73,21 +67,16 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, count: usize) { // We can't separate this block due to std/cld asm!( "std", - "test %ecx, %ecx", - "jz 1f", "rep movsb", - "1:", "sub $7, %rsi", "sub $7, %rdi", "mov {qword_count}, %rcx", "rep movsq", "test {pre_byte_count:e}, {pre_byte_count:e}", - "jz 1f", "add $7, %rsi", "add $7, %rdi", "mov {pre_byte_count:e}, %ecx", "rep movsb", - "1:", "cld", pre_byte_count = in(reg) pre_byte_count, qword_count = in(reg) qword_count, @@ -118,17 +107,13 @@ pub unsafe fn set_bytes(mut dest: *mut u8, c: u8, count: usize) { let c = c as u64 * 0x0101_0101_0101_0101; let (pre_byte_count, qword_count, byte_count) = rep_param(dest, count); // Separating the blocks gives the compiler more freedom to reorder instructions. - // It also allows us to trivially skip the rep stosb, which is faster when memcpying - // aligned data. - if pre_byte_count > 0 { - asm!( - "rep stosb", - inout("ecx") pre_byte_count => _, - inout("rdi") dest => dest, - in("rax") c, - options(att_syntax, nostack, preserves_flags) - ); - } + asm!( + "rep stosb", + inout("ecx") pre_byte_count => _, + inout("rdi") dest => dest, + in("rax") c, + options(att_syntax, nostack, preserves_flags) + ); asm!( "rep stosq", inout("rcx") qword_count => _, @@ -136,15 +121,13 @@ pub unsafe fn set_bytes(mut dest: *mut u8, c: u8, count: usize) { in("rax") c, options(att_syntax, nostack, preserves_flags) ); - if byte_count > 0 { - asm!( - "rep stosb", - inout("ecx") byte_count => _, - inout("rdi") dest => _, - in("rax") c, - options(att_syntax, nostack, preserves_flags) - ); - } + asm!( + "rep stosb", + inout("ecx") byte_count => _, + inout("rdi") dest => _, + in("rax") c, + options(att_syntax, nostack, preserves_flags) + ); } #[inline(always)] From 1913181e243f312539336fec39d4c6d9efb9b59a Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 28 Jul 2022 20:58:02 +0100 Subject: [PATCH 1042/4206] Bump to 0.1.77 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 22ce34d366a92..cd4718830610f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.76" +version = "0.1.77" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 89df6f6bc0709f0dbdebe901a8996d484f9040bb Mon Sep 17 00:00:00 2001 From: Andrew Kane Date: Thu, 28 Jul 2022 16:21:37 -0700 Subject: [PATCH 1043/4206] Added tgamma and tgammaf --- library/compiler-builtins/src/math.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 14a65395eb8e1..c3b9788e1dc71 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -63,6 +63,8 @@ no_mangle! { fn tanhf(n: f32) -> f32; fn ldexp(f: f64, n: i32) -> f64; fn ldexpf(f: f32, n: i32) -> f32; + fn tgamma(x: f64) -> f64; + fn tgammaf(x: f32) -> f32; } #[cfg(any( From de09c87e0b9da96b53fc6d7d01e8eebb696672ca Mon Sep 17 00:00:00 2001 From: Alex Huszagh Date: Fri, 29 Jul 2022 15:52:23 -0500 Subject: [PATCH 1044/4206] Add compiler-rt fallback for __trunctfsf2 on mips64-musl. --- library/compiler-builtins/build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index befc5e2e3bb80..73952bb9f3ea9 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -460,6 +460,7 @@ mod c { ("__fe_getround", "fp_mode.c"), ("__divtf3", "divtf3.c"), ("__trunctfdf2", "trunctfdf2.c"), + ("__trunctfsf2", "trunctfsf2.c"), ]); } From 599dcc2c46d0c312629feb9fd419bc07a1c5a02e Mon Sep 17 00:00:00 2001 From: Alex Huszagh Date: Fri, 29 Jul 2022 16:58:05 -0500 Subject: [PATCH 1045/4206] Add compiler-rt fallbacks for sync builtins on armv5te-musl. --- library/compiler-builtins/src/arm_linux.rs | 110 ++++++++++++++------- 1 file changed, 73 insertions(+), 37 deletions(-) diff --git a/library/compiler-builtins/src/arm_linux.rs b/library/compiler-builtins/src/arm_linux.rs index 8fe09485bcf36..8f22eb6286600 100644 --- a/library/compiler-builtins/src/arm_linux.rs +++ b/library/compiler-builtins/src/arm_linux.rs @@ -55,7 +55,7 @@ fn insert_aligned(aligned: u32, val: u32, shift: u32, mask: u32) -> u32 { } // Generic atomic read-modify-write operation -unsafe fn atomic_rmw u32>(ptr: *mut T, f: F) -> u32 { +unsafe fn atomic_rmw u32, G: Fn(u32, u32) -> u32>(ptr: *mut T, f: F, g: G) -> u32 { let aligned_ptr = align_ptr(ptr); let (shift, mask) = get_shift_mask(ptr); @@ -65,7 +65,7 @@ unsafe fn atomic_rmw u32>(ptr: *mut T, f: F) -> u32 { let newval = f(curval); let newval_aligned = insert_aligned(curval_aligned, newval, shift, mask); if __kuser_cmpxchg(curval_aligned, newval_aligned, aligned_ptr) { - return curval; + return g(curval, newval); } } } @@ -89,13 +89,21 @@ unsafe fn atomic_cmpxchg(ptr: *mut T, oldval: u32, newval: u32) -> u32 { } macro_rules! atomic_rmw { - ($name:ident, $ty:ty, $op:expr) => { + ($name:ident, $ty:ty, $op:expr, $fetch:expr) => { intrinsics! { pub unsafe extern "C" fn $name(ptr: *mut $ty, val: $ty) -> $ty { - atomic_rmw(ptr, |x| $op(x as $ty, val) as u32) as $ty + atomic_rmw(ptr, |x| $op(x as $ty, val) as u32, |old, new| $fetch(old, new)) as $ty } } }; + + (@old $name:ident, $ty:ty, $op:expr) => { + atomic_rmw!($name, $ty, $op, |old, _| old); + }; + + (@new $name:ident, $ty:ty, $op:expr) => { + atomic_rmw!($name, $ty, $op, |_, new| new); + }; } macro_rules! atomic_cmpxchg { ($name:ident, $ty:ty) => { @@ -107,101 +115,129 @@ macro_rules! atomic_cmpxchg { }; } -atomic_rmw!(__sync_fetch_and_add_1, u8, |a: u8, b: u8| a.wrapping_add(b)); -atomic_rmw!(__sync_fetch_and_add_2, u16, |a: u16, b: u16| a +atomic_rmw!(@old __sync_fetch_and_add_1, u8, |a: u8, b: u8| a.wrapping_add(b)); +atomic_rmw!(@old __sync_fetch_and_add_2, u16, |a: u16, b: u16| a + .wrapping_add(b)); +atomic_rmw!(@old __sync_fetch_and_add_4, u32, |a: u32, b: u32| a + .wrapping_add(b)); + +atomic_rmw!(@new __sync_add_and_fetch_1, u8, |a: u8, b: u8| a.wrapping_add(b)); +atomic_rmw!(@new __sync_add_and_fetch_2, u16, |a: u16, b: u16| a .wrapping_add(b)); -atomic_rmw!(__sync_fetch_and_add_4, u32, |a: u32, b: u32| a +atomic_rmw!(@new __sync_add_and_fetch_4, u32, |a: u32, b: u32| a .wrapping_add(b)); -atomic_rmw!(__sync_fetch_and_sub_1, u8, |a: u8, b: u8| a.wrapping_sub(b)); -atomic_rmw!(__sync_fetch_and_sub_2, u16, |a: u16, b: u16| a +atomic_rmw!(@old __sync_fetch_and_sub_1, u8, |a: u8, b: u8| a.wrapping_sub(b)); +atomic_rmw!(@old __sync_fetch_and_sub_2, u16, |a: u16, b: u16| a .wrapping_sub(b)); -atomic_rmw!(__sync_fetch_and_sub_4, u32, |a: u32, b: u32| a +atomic_rmw!(@old __sync_fetch_and_sub_4, u32, |a: u32, b: u32| a .wrapping_sub(b)); -atomic_rmw!(__sync_fetch_and_and_1, u8, |a: u8, b: u8| a & b); -atomic_rmw!(__sync_fetch_and_and_2, u16, |a: u16, b: u16| a & b); -atomic_rmw!(__sync_fetch_and_and_4, u32, |a: u32, b: u32| a & b); +atomic_rmw!(@new __sync_sub_and_fetch_1, u8, |a: u8, b: u8| a.wrapping_sub(b)); +atomic_rmw!(@new __sync_sub_and_fetch_2, u16, |a: u16, b: u16| a + .wrapping_sub(b)); +atomic_rmw!(@new __sync_sub_and_fetch_4, u32, |a: u32, b: u32| a + .wrapping_sub(b)); + +atomic_rmw!(@old __sync_fetch_and_and_1, u8, |a: u8, b: u8| a & b); +atomic_rmw!(@old __sync_fetch_and_and_2, u16, |a: u16, b: u16| a & b); +atomic_rmw!(@old __sync_fetch_and_and_4, u32, |a: u32, b: u32| a & b); + +atomic_rmw!(@new __sync_and_and_fetch_1, u8, |a: u8, b: u8| a & b); +atomic_rmw!(@new __sync_and_and_fetch_2, u16, |a: u16, b: u16| a & b); +atomic_rmw!(@new __sync_and_and_fetch_4, u32, |a: u32, b: u32| a & b); + +atomic_rmw!(@old __sync_fetch_and_or_1, u8, |a: u8, b: u8| a | b); +atomic_rmw!(@old __sync_fetch_and_or_2, u16, |a: u16, b: u16| a | b); +atomic_rmw!(@old __sync_fetch_and_or_4, u32, |a: u32, b: u32| a | b); + +atomic_rmw!(@new __sync_or_and_fetch_1, u8, |a: u8, b: u8| a | b); +atomic_rmw!(@new __sync_or_and_fetch_2, u16, |a: u16, b: u16| a | b); +atomic_rmw!(@new __sync_or_and_fetch_4, u32, |a: u32, b: u32| a | b); + +atomic_rmw!(@old __sync_fetch_and_xor_1, u8, |a: u8, b: u8| a ^ b); +atomic_rmw!(@old __sync_fetch_and_xor_2, u16, |a: u16, b: u16| a ^ b); +atomic_rmw!(@old __sync_fetch_and_xor_4, u32, |a: u32, b: u32| a ^ b); -atomic_rmw!(__sync_fetch_and_or_1, u8, |a: u8, b: u8| a | b); -atomic_rmw!(__sync_fetch_and_or_2, u16, |a: u16, b: u16| a | b); -atomic_rmw!(__sync_fetch_and_or_4, u32, |a: u32, b: u32| a | b); +atomic_rmw!(@new __sync_xor_and_fetch_1, u8, |a: u8, b: u8| a ^ b); +atomic_rmw!(@new __sync_xor_and_fetch_2, u16, |a: u16, b: u16| a ^ b); +atomic_rmw!(@new __sync_xor_and_fetch_4, u32, |a: u32, b: u32| a ^ b); -atomic_rmw!(__sync_fetch_and_xor_1, u8, |a: u8, b: u8| a ^ b); -atomic_rmw!(__sync_fetch_and_xor_2, u16, |a: u16, b: u16| a ^ b); -atomic_rmw!(__sync_fetch_and_xor_4, u32, |a: u32, b: u32| a ^ b); +atomic_rmw!(@old __sync_fetch_and_nand_1, u8, |a: u8, b: u8| !(a & b)); +atomic_rmw!(@old __sync_fetch_and_nand_2, u16, |a: u16, b: u16| !(a & b)); +atomic_rmw!(@old __sync_fetch_and_nand_4, u32, |a: u32, b: u32| !(a & b)); -atomic_rmw!(__sync_fetch_and_nand_1, u8, |a: u8, b: u8| !(a & b)); -atomic_rmw!(__sync_fetch_and_nand_2, u16, |a: u16, b: u16| !(a & b)); -atomic_rmw!(__sync_fetch_and_nand_4, u32, |a: u32, b: u32| !(a & b)); +atomic_rmw!(@new __sync_nand_and_fetch_1, u8, |a: u8, b: u8| !(a & b)); +atomic_rmw!(@new __sync_nand_and_fetch_2, u16, |a: u16, b: u16| !(a & b)); +atomic_rmw!(@new __sync_nand_and_fetch_4, u32, |a: u32, b: u32| !(a & b)); -atomic_rmw!(__sync_fetch_and_max_1, i8, |a: i8, b: i8| if a > b { +atomic_rmw!(@old __sync_fetch_and_max_1, i8, |a: i8, b: i8| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_max_2, i16, |a: i16, b: i16| if a > b { +atomic_rmw!(@old __sync_fetch_and_max_2, i16, |a: i16, b: i16| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_max_4, i32, |a: i32, b: i32| if a > b { +atomic_rmw!(@old __sync_fetch_and_max_4, i32, |a: i32, b: i32| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umax_1, u8, |a: u8, b: u8| if a > b { +atomic_rmw!(@old __sync_fetch_and_umax_1, u8, |a: u8, b: u8| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umax_2, u16, |a: u16, b: u16| if a > b { +atomic_rmw!(@old __sync_fetch_and_umax_2, u16, |a: u16, b: u16| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umax_4, u32, |a: u32, b: u32| if a > b { +atomic_rmw!(@old __sync_fetch_and_umax_4, u32, |a: u32, b: u32| if a > b { a } else { b }); -atomic_rmw!(__sync_fetch_and_min_1, i8, |a: i8, b: i8| if a < b { +atomic_rmw!(@old __sync_fetch_and_min_1, i8, |a: i8, b: i8| if a < b { a } else { b }); -atomic_rmw!(__sync_fetch_and_min_2, i16, |a: i16, b: i16| if a < b { +atomic_rmw!(@old __sync_fetch_and_min_2, i16, |a: i16, b: i16| if a < b { a } else { b }); -atomic_rmw!(__sync_fetch_and_min_4, i32, |a: i32, b: i32| if a < b { +atomic_rmw!(@old __sync_fetch_and_min_4, i32, |a: i32, b: i32| if a < b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umin_1, u8, |a: u8, b: u8| if a < b { +atomic_rmw!(@old __sync_fetch_and_umin_1, u8, |a: u8, b: u8| if a < b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umin_2, u16, |a: u16, b: u16| if a < b { +atomic_rmw!(@old __sync_fetch_and_umin_2, u16, |a: u16, b: u16| if a < b { a } else { b }); -atomic_rmw!(__sync_fetch_and_umin_4, u32, |a: u32, b: u32| if a < b { +atomic_rmw!(@old __sync_fetch_and_umin_4, u32, |a: u32, b: u32| if a < b { a } else { b }); -atomic_rmw!(__sync_lock_test_and_set_1, u8, |_: u8, b: u8| b); -atomic_rmw!(__sync_lock_test_and_set_2, u16, |_: u16, b: u16| b); -atomic_rmw!(__sync_lock_test_and_set_4, u32, |_: u32, b: u32| b); +atomic_rmw!(@old __sync_lock_test_and_set_1, u8, |_: u8, b: u8| b); +atomic_rmw!(@old __sync_lock_test_and_set_2, u16, |_: u16, b: u16| b); +atomic_rmw!(@old __sync_lock_test_and_set_4, u32, |_: u32, b: u32| b); atomic_cmpxchg!(__sync_val_compare_and_swap_1, u8); atomic_cmpxchg!(__sync_val_compare_and_swap_2, u16); From 4d8d134d103af0e86316acddd4db8b2016376330 Mon Sep 17 00:00:00 2001 From: Andrew Kane Date: Fri, 29 Jul 2022 16:52:30 -0700 Subject: [PATCH 1046/4206] Remove panics from tgamma and tgammaf --- library/compiler-builtins/libm/src/math/tgamma.rs | 13 +++++++------ library/compiler-builtins/libm/src/math/tgammaf.rs | 1 + 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/tgamma.rs b/library/compiler-builtins/libm/src/math/tgamma.rs index f8ccf669a2513..e64eff61f0669 100644 --- a/library/compiler-builtins/libm/src/math/tgamma.rs +++ b/library/compiler-builtins/libm/src/math/tgamma.rs @@ -38,7 +38,7 @@ fn sinpi(mut x: f64) -> f64 { /* reduce x into [-.25,.25] */ n = (4.0 * x) as isize; - n = (n + 1) / 2; + n = div!(n + 1, 2); x -= (n as f64) * 0.5; x *= PI; @@ -118,18 +118,19 @@ fn s(x: f64) -> f64 { /* to avoid overflow handle large x differently */ if x < 8.0 { for i in (0..=N).rev() { - num = num * x + SNUM[i]; - den = den * x + SDEN[i]; + num = num * x + i!(SNUM, i); + den = den * x + i!(SDEN, i); } } else { for i in 0..=N { - num = num / x + SNUM[i]; - den = den / x + SDEN[i]; + num = num / x + i!(SNUM, i); + den = den / x + i!(SDEN, i); } } return num / den; } +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tgamma(mut x: f64) -> f64 { let u: u64 = x.to_bits(); let absx: f64; @@ -157,7 +158,7 @@ pub fn tgamma(mut x: f64) -> f64 { return 0.0 / 0.0; } if x <= FACT.len() as f64 { - return FACT[(x as usize) - 1]; + return i!(FACT, (x as usize) - 1); } } diff --git a/library/compiler-builtins/libm/src/math/tgammaf.rs b/library/compiler-builtins/libm/src/math/tgammaf.rs index a8f161f0c1c95..23e3814f99fd1 100644 --- a/library/compiler-builtins/libm/src/math/tgammaf.rs +++ b/library/compiler-builtins/libm/src/math/tgammaf.rs @@ -1,5 +1,6 @@ use super::tgamma; +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tgammaf(x: f32) -> f32 { tgamma(x as f64) as f32 } From d9cd50d32f209a34e26c9c7032c3724d3d171482 Mon Sep 17 00:00:00 2001 From: Andrew Kane Date: Fri, 29 Jul 2022 17:34:06 -0700 Subject: [PATCH 1047/4206] Update libm --- library/compiler-builtins/libm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 1f7b8eb61cab5..add735e30df2b 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 1f7b8eb61cab5f62ec93d2343432bebd1ada30f2 +Subproject commit add735e30df2ba780fb76187f43163dedcd96fa7 From 365558d74903e88447b40134e94dd0e79ba7d643 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 30 Jul 2022 01:43:36 +0100 Subject: [PATCH 1048/4206] Bump to 0.2.3 --- library/compiler-builtins/libm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 99055ad47b16b..a94a85a26ea05 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/libm" -version = "0.2.2" +version = "0.2.3" edition = "2018" [features] From 8a9e33297ab2bc21404d43066f3a63cd72c8c755 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 30 Jul 2022 01:45:31 +0100 Subject: [PATCH 1049/4206] Bump to 0.1.78 --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/libm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index cd4718830610f..826dee795b4ac 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.77" +version = "0.1.78" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index add735e30df2b..d6d8a1610c991 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit add735e30df2ba780fb76187f43163dedcd96fa7 +Subproject commit d6d8a1610c9912c84c4c1d12d994d0204dc702ef From ada0be15bf8858e313bb2dc0a5283a96c9a12842 Mon Sep 17 00:00:00 2001 From: Outurnate Date: Sun, 31 Jul 2022 14:37:57 -0400 Subject: [PATCH 1050/4206] Use smaller IPIO2 table for 16 and 32 bit architectures --- library/compiler-builtins/libm/src/math/rem_pio2_large.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 65473f0abdadd..db97a39d49021 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -27,7 +27,7 @@ const INIT_JK: [usize; 4] = [3, 4, 4, 6]; // // NB: This table must have at least (e0-3)/24 + jk terms. // For quad precision (e0 <= 16360, jk = 6), this is 686. -#[cfg(target_pointer_width = "32")] +#[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))] const IPIO2: [i32; 66] = [ 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, From fecd4045afc6cf00d70403e548348de973535699 Mon Sep 17 00:00:00 2001 From: Andrew Kane Date: Sun, 31 Jul 2022 13:57:20 -0700 Subject: [PATCH 1051/4206] Ensure more functions do not panic --- library/compiler-builtins/libm/src/math/acosh.rs | 1 + library/compiler-builtins/libm/src/math/acoshf.rs | 1 + library/compiler-builtins/libm/src/math/asinh.rs | 1 + library/compiler-builtins/libm/src/math/asinhf.rs | 1 + library/compiler-builtins/libm/src/math/atanh.rs | 1 + library/compiler-builtins/libm/src/math/atanhf.rs | 1 + library/compiler-builtins/libm/src/math/copysign.rs | 1 + library/compiler-builtins/libm/src/math/copysignf.rs | 1 + library/compiler-builtins/libm/src/math/erf.rs | 1 + library/compiler-builtins/libm/src/math/erff.rs | 1 + library/compiler-builtins/libm/src/math/exp10.rs | 5 +++-- library/compiler-builtins/libm/src/math/exp10f.rs | 5 +++-- library/compiler-builtins/libm/src/math/ilogb.rs | 1 + library/compiler-builtins/libm/src/math/ilogbf.rs | 1 + library/compiler-builtins/libm/src/math/lgamma.rs | 1 + library/compiler-builtins/libm/src/math/lgamma_r.rs | 3 ++- library/compiler-builtins/libm/src/math/lgammaf.rs | 1 + library/compiler-builtins/libm/src/math/lgammaf_r.rs | 3 ++- library/compiler-builtins/libm/src/math/sincos.rs | 1 + library/compiler-builtins/libm/src/math/sincosf.rs | 1 + 20 files changed, 26 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/acosh.rs b/library/compiler-builtins/libm/src/math/acosh.rs index ac7a5f1c623b8..d1f5b9fa9372c 100644 --- a/library/compiler-builtins/libm/src/math/acosh.rs +++ b/library/compiler-builtins/libm/src/math/acosh.rs @@ -7,6 +7,7 @@ const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa3 /// Calculates the inverse hyperbolic cosine of `x`. /// Is defined as `log(x + sqrt(x*x-1))`. /// `x` must be a number greater than or equal to 1. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn acosh(x: f64) -> f64 { let u = x.to_bits(); let e = ((u >> 52) as usize) & 0x7ff; diff --git a/library/compiler-builtins/libm/src/math/acoshf.rs b/library/compiler-builtins/libm/src/math/acoshf.rs index 0879e1edb0a50..ad3455fdd48cf 100644 --- a/library/compiler-builtins/libm/src/math/acoshf.rs +++ b/library/compiler-builtins/libm/src/math/acoshf.rs @@ -7,6 +7,7 @@ const LN2: f32 = 0.693147180559945309417232121458176568; /// Calculates the inverse hyperbolic cosine of `x`. /// Is defined as `log(x + sqrt(x*x-1))`. /// `x` must be a number greater than or equal to 1. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn acoshf(x: f32) -> f32 { let u = x.to_bits(); let a = u & 0x7fffffff; diff --git a/library/compiler-builtins/libm/src/math/asinh.rs b/library/compiler-builtins/libm/src/math/asinh.rs index 14295357a55e4..0abd80c2fd723 100644 --- a/library/compiler-builtins/libm/src/math/asinh.rs +++ b/library/compiler-builtins/libm/src/math/asinh.rs @@ -7,6 +7,7 @@ const LN2: f64 = 0.693147180559945309417232121458176568; /* 0x3fe62e42, 0xfefa3 /// /// Calculates the inverse hyperbolic sine of `x`. /// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn asinh(mut x: f64) -> f64 { let mut u = x.to_bits(); let e = ((u >> 52) as usize) & 0x7ff; diff --git a/library/compiler-builtins/libm/src/math/asinhf.rs b/library/compiler-builtins/libm/src/math/asinhf.rs index e22a291323f6a..09c77823e1050 100644 --- a/library/compiler-builtins/libm/src/math/asinhf.rs +++ b/library/compiler-builtins/libm/src/math/asinhf.rs @@ -7,6 +7,7 @@ const LN2: f32 = 0.693147180559945309417232121458176568; /// /// Calculates the inverse hyperbolic sine of `x`. /// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn asinhf(mut x: f32) -> f32 { let u = x.to_bits(); let i = u & 0x7fffffff; diff --git a/library/compiler-builtins/libm/src/math/atanh.rs b/library/compiler-builtins/libm/src/math/atanh.rs index 79a989c42d1c4..b984c4ac62820 100644 --- a/library/compiler-builtins/libm/src/math/atanh.rs +++ b/library/compiler-builtins/libm/src/math/atanh.rs @@ -5,6 +5,7 @@ use super::log1p; /// /// Calculates the inverse hyperbolic tangent of `x`. /// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atanh(x: f64) -> f64 { let u = x.to_bits(); let e = ((u >> 52) as usize) & 0x7ff; diff --git a/library/compiler-builtins/libm/src/math/atanhf.rs b/library/compiler-builtins/libm/src/math/atanhf.rs index 7b2f34d97d4a2..a1aa314a50f35 100644 --- a/library/compiler-builtins/libm/src/math/atanhf.rs +++ b/library/compiler-builtins/libm/src/math/atanhf.rs @@ -5,6 +5,7 @@ use super::log1pf; /// /// Calculates the inverse hyperbolic tangent of `x`. /// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn atanhf(mut x: f32) -> f32 { let mut u = x.to_bits(); let sign = (u >> 31) != 0; diff --git a/library/compiler-builtins/libm/src/math/copysign.rs b/library/compiler-builtins/libm/src/math/copysign.rs index 1527fb6ea8b41..1f4a35a331b9a 100644 --- a/library/compiler-builtins/libm/src/math/copysign.rs +++ b/library/compiler-builtins/libm/src/math/copysign.rs @@ -2,6 +2,7 @@ /// /// Constructs a number with the magnitude (absolute value) of its /// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn copysign(x: f64, y: f64) -> f64 { let mut ux = x.to_bits(); let uy = y.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/copysignf.rs b/library/compiler-builtins/libm/src/math/copysignf.rs index 35148561a86d1..6c346e3a52804 100644 --- a/library/compiler-builtins/libm/src/math/copysignf.rs +++ b/library/compiler-builtins/libm/src/math/copysignf.rs @@ -2,6 +2,7 @@ /// /// Constructs a number with the magnitude (absolute value) of its /// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn copysignf(x: f32, y: f32) -> f32 { let mut ux = x.to_bits(); let uy = y.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/erf.rs b/library/compiler-builtins/libm/src/math/erf.rs index a2c617d341da5..5e21ba578dfe3 100644 --- a/library/compiler-builtins/libm/src/math/erf.rs +++ b/library/compiler-builtins/libm/src/math/erf.rs @@ -219,6 +219,7 @@ fn erfc2(ix: u32, mut x: f64) -> f64 { /// Calculates an approximation to the “error function”, which estimates /// the probability that an observation will fall within x standard /// deviations of the mean (assuming a normal distribution). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn erf(x: f64) -> f64 { let r: f64; let s: f64; diff --git a/library/compiler-builtins/libm/src/math/erff.rs b/library/compiler-builtins/libm/src/math/erff.rs index 384052293fe15..f74d4b632491b 100644 --- a/library/compiler-builtins/libm/src/math/erff.rs +++ b/library/compiler-builtins/libm/src/math/erff.rs @@ -130,6 +130,7 @@ fn erfc2(mut ix: u32, mut x: f32) -> f32 { /// Calculates an approximation to the “error function”, which estimates /// the probability that an observation will fall within x standard /// deviations of the mean (assuming a normal distribution). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn erff(x: f32) -> f32 { let r: f32; let s: f32; diff --git a/library/compiler-builtins/libm/src/math/exp10.rs b/library/compiler-builtins/libm/src/math/exp10.rs index 9537f76f13618..559930e109fe6 100644 --- a/library/compiler-builtins/libm/src/math/exp10.rs +++ b/library/compiler-builtins/libm/src/math/exp10.rs @@ -6,16 +6,17 @@ const P10: &[f64] = &[ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, ]; +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp10(x: f64) -> f64 { let (mut y, n) = modf(x); let u: u64 = n.to_bits(); /* fabs(n) < 16 without raising invalid on nan */ if (u >> 52 & 0x7ff) < 0x3ff + 4 { if y == 0.0 { - return P10[((n as isize) + 15) as usize]; + return i!(P10, ((n as isize) + 15) as usize); } y = exp2(LN10 * y); - return y * P10[((n as isize) + 15) as usize]; + return y * i!(P10, ((n as isize) + 15) as usize); } return pow(10.0, x); } diff --git a/library/compiler-builtins/libm/src/math/exp10f.rs b/library/compiler-builtins/libm/src/math/exp10f.rs index d45fff36ea3de..1279bc6c566b9 100644 --- a/library/compiler-builtins/libm/src/math/exp10f.rs +++ b/library/compiler-builtins/libm/src/math/exp10f.rs @@ -6,16 +6,17 @@ const P10: &[f32] = &[ 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, ]; +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp10f(x: f32) -> f32 { let (mut y, n) = modff(x); let u = n.to_bits(); /* fabsf(n) < 8 without raising invalid on nan */ if (u >> 23 & 0xff) < 0x7f + 3 { if y == 0.0 { - return P10[((n as isize) + 7) as usize]; + return i!(P10, ((n as isize) + 7) as usize); } y = exp2f(LN10_F32 * y); - return y * P10[((n as isize) + 7) as usize]; + return y * i!(P10, ((n as isize) + 7) as usize); } return exp2(LN10_F64 * (x as f64)) as f32; } diff --git a/library/compiler-builtins/libm/src/math/ilogb.rs b/library/compiler-builtins/libm/src/math/ilogb.rs index 0a380b7efd352..7d74dcfb666d8 100644 --- a/library/compiler-builtins/libm/src/math/ilogb.rs +++ b/library/compiler-builtins/libm/src/math/ilogb.rs @@ -1,6 +1,7 @@ const FP_ILOGBNAN: i32 = -1 - 0x7fffffff; const FP_ILOGB0: i32 = FP_ILOGBNAN; +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ilogb(x: f64) -> i32 { let mut i: u64 = x.to_bits(); let e = ((i >> 52) & 0x7ff) as i32; diff --git a/library/compiler-builtins/libm/src/math/ilogbf.rs b/library/compiler-builtins/libm/src/math/ilogbf.rs index b384fa4b20d36..0fa58748c2f5e 100644 --- a/library/compiler-builtins/libm/src/math/ilogbf.rs +++ b/library/compiler-builtins/libm/src/math/ilogbf.rs @@ -1,6 +1,7 @@ const FP_ILOGBNAN: i32 = -1 - 0x7fffffff; const FP_ILOGB0: i32 = FP_ILOGBNAN; +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ilogbf(x: f32) -> i32 { let mut i = x.to_bits(); let e = ((i >> 23) & 0xff) as i32; diff --git a/library/compiler-builtins/libm/src/math/lgamma.rs b/library/compiler-builtins/libm/src/math/lgamma.rs index 5bc87e85e8c33..a08bc5b641e4f 100644 --- a/library/compiler-builtins/libm/src/math/lgamma.rs +++ b/library/compiler-builtins/libm/src/math/lgamma.rs @@ -1,5 +1,6 @@ use super::lgamma_r; +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn lgamma(x: f64) -> f64 { lgamma_r(x).0 } diff --git a/library/compiler-builtins/libm/src/math/lgamma_r.rs b/library/compiler-builtins/libm/src/math/lgamma_r.rs index 9533e882cc998..b26177e6ebf75 100644 --- a/library/compiler-builtins/libm/src/math/lgamma_r.rs +++ b/library/compiler-builtins/libm/src/math/lgamma_r.rs @@ -152,7 +152,7 @@ fn sin_pi(mut x: f64) -> f64 { x = 2.0 * (x * 0.5 - floor(x * 0.5)); /* x mod 2.0 */ n = (x * 4.0) as i32; - n = (n + 1) / 2; + n = div!(n + 1, 2); x -= (n as f64) * 0.5; x *= PI; @@ -164,6 +164,7 @@ fn sin_pi(mut x: f64) -> f64 { } } +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn lgamma_r(mut x: f64) -> (f64, i32) { let u: u64 = x.to_bits(); let mut t: f64; diff --git a/library/compiler-builtins/libm/src/math/lgammaf.rs b/library/compiler-builtins/libm/src/math/lgammaf.rs index dfdc87f9622c6..a9c2da75bd779 100644 --- a/library/compiler-builtins/libm/src/math/lgammaf.rs +++ b/library/compiler-builtins/libm/src/math/lgammaf.rs @@ -1,5 +1,6 @@ use super::lgammaf_r; +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn lgammaf(x: f32) -> f32 { lgammaf_r(x).0 } diff --git a/library/compiler-builtins/libm/src/math/lgammaf_r.rs b/library/compiler-builtins/libm/src/math/lgammaf_r.rs index c5e559f465282..723c90daf1ed1 100644 --- a/library/compiler-builtins/libm/src/math/lgammaf_r.rs +++ b/library/compiler-builtins/libm/src/math/lgammaf_r.rs @@ -88,7 +88,7 @@ fn sin_pi(mut x: f32) -> f32 { x = 2.0 * (x * 0.5 - floorf(x * 0.5)); /* x mod 2.0 */ n = (x * 4.0) as isize; - n = (n + 1) / 2; + n = div!(n + 1, 2); y = (x as f64) - (n as f64) * 0.5; y *= 3.14159265358979323846; match n { @@ -99,6 +99,7 @@ fn sin_pi(mut x: f32) -> f32 { } } +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn lgammaf_r(mut x: f32) -> (f32, i32) { let u = x.to_bits(); let mut t: f32; diff --git a/library/compiler-builtins/libm/src/math/sincos.rs b/library/compiler-builtins/libm/src/math/sincos.rs index 4ab588412a5e1..ff5d87a1c60ff 100644 --- a/library/compiler-builtins/libm/src/math/sincos.rs +++ b/library/compiler-builtins/libm/src/math/sincos.rs @@ -12,6 +12,7 @@ use super::{get_high_word, k_cos, k_sin, rem_pio2}; +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sincos(x: f64) -> (f64, f64) { let s: f64; let c: f64; diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs index 5304e8ca02768..9a4c36104e92c 100644 --- a/library/compiler-builtins/libm/src/math/sincosf.rs +++ b/library/compiler-builtins/libm/src/math/sincosf.rs @@ -23,6 +23,7 @@ const S2PIO2: f32 = 2.0 * PI_2; /* 0x400921FB, 0x54442D18 */ const S3PIO2: f32 = 3.0 * PI_2; /* 0x4012D97C, 0x7F3321D2 */ const S4PIO2: f32 = 4.0 * PI_2; /* 0x401921FB, 0x54442D18 */ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sincosf(x: f32) -> (f32, f32) { let s: f32; let c: f32; From abb6893a85b99defdbf6acd569d7f7151bfd67d8 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sun, 31 Jul 2022 11:07:33 -0400 Subject: [PATCH 1052/4206] Enable unadjusted_on_win64 for UEFI in some cases The conversion functions from i128/u128 to f32/f64 have the `unadjusted_on_win64` attribute, but it is disabled starting with LLVM14. This seems to be the correct thing to do for Win64, but for some reason x86_64-unknown-uefi is different, despite generally using the same ABI as Win64. --- library/compiler-builtins/src/float/conv.rs | 8 ++++---- library/compiler-builtins/src/macros.rs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 07b58f3d232e0..68ba63408e934 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -92,12 +92,12 @@ intrinsics! { f64::from_bits(int_to_float::u64_to_f64_bits(i)) } - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + #[cfg_attr(any(not(target_feature = "llvm14-builtins-abi"), target_os = "uefi"), unadjusted_on_win64)] pub extern "C" fn __floatuntisf(i: u128) -> f32 { f32::from_bits(int_to_float::u128_to_f32_bits(i)) } - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + #[cfg_attr(any(not(target_feature = "llvm14-builtins-abi"), target_os = "uefi"), unadjusted_on_win64)] pub extern "C" fn __floatuntidf(i: u128) -> f64 { f64::from_bits(int_to_float::u128_to_f64_bits(i)) } @@ -129,13 +129,13 @@ intrinsics! { f64::from_bits(int_to_float::u64_to_f64_bits(i.unsigned_abs()) | sign_bit) } - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + #[cfg_attr(any(not(target_feature = "llvm14-builtins-abi"), target_os = "uefi"), unadjusted_on_win64)] pub extern "C" fn __floattisf(i: i128) -> f32 { let sign_bit = ((i >> 127) as u32) << 31; f32::from_bits(int_to_float::u128_to_f32_bits(i.unsigned_abs()) | sign_bit) } - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + #[cfg_attr(any(not(target_feature = "llvm14-builtins-abi"), target_os = "uefi"), unadjusted_on_win64)] pub extern "C" fn __floattidf(i: i128) -> f64 { let sign_bit = ((i >> 127) as u64) << 63; f64::from_bits(int_to_float::u128_to_f64_bits(i.unsigned_abs()) | sign_bit) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 6acf1be969e87..7d90b7aadbe1c 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -174,7 +174,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( - #[cfg(all(windows, target_pointer_width = "64"))] + #[cfg(all(any(windows, all(target_os = "uefi", target_arch = "x86_64")), target_pointer_width = "64"))] intrinsics! { $(#[$($attr)*])* pub extern "unadjusted" fn $name( $($argname: $ty),* ) $(-> $ret)? { @@ -182,7 +182,7 @@ macro_rules! intrinsics { } } - #[cfg(not(all(windows, target_pointer_width = "64")))] + #[cfg(not(all(any(windows, all(target_os = "uefi", target_arch = "x86_64")), target_pointer_width = "64")))] intrinsics! { $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { From 142261c91cba56c32c1554d67de8561d71d48631 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 10 Aug 2022 01:11:33 +0100 Subject: [PATCH 1053/4206] Fix fmaf not to depend on FE_TOWARDZERO Ported from upstream musl commit 4f3d346bffdf9ed2b1803653643dc31242490944 Fixes rust-lang/libm#263 --- .../compiler-builtins/libm/src/math/fenv.rs | 6 ---- .../compiler-builtins/libm/src/math/fmaf.rs | 35 ++++++++++++------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/fenv.rs b/library/compiler-builtins/libm/src/math/fenv.rs index 652e6032452b3..c91272e826852 100644 --- a/library/compiler-builtins/libm/src/math/fenv.rs +++ b/library/compiler-builtins/libm/src/math/fenv.rs @@ -5,7 +5,6 @@ pub(crate) const FE_UNDERFLOW: i32 = 0; pub(crate) const FE_INEXACT: i32 = 0; pub(crate) const FE_TONEAREST: i32 = 0; -pub(crate) const FE_TOWARDZERO: i32 = 0; #[inline] pub(crate) fn feclearexcept(_mask: i32) -> i32 { @@ -26,8 +25,3 @@ pub(crate) fn fetestexcept(_mask: i32) -> i32 { pub(crate) fn fegetround() -> i32 { FE_TONEAREST } - -#[inline] -pub(crate) fn fesetround(_r: i32) -> i32 { - 0 -} diff --git a/library/compiler-builtins/libm/src/math/fmaf.rs b/library/compiler-builtins/libm/src/math/fmaf.rs index 03d371c55f202..2848f2aee0c37 100644 --- a/library/compiler-builtins/libm/src/math/fmaf.rs +++ b/library/compiler-builtins/libm/src/math/fmaf.rs @@ -29,8 +29,7 @@ use core::f32; use core::ptr::read_volatile; use super::fenv::{ - feclearexcept, fegetround, feraiseexcept, fesetround, fetestexcept, FE_INEXACT, FE_TONEAREST, - FE_TOWARDZERO, FE_UNDERFLOW, + feclearexcept, fegetround, feraiseexcept, fetestexcept, FE_INEXACT, FE_TONEAREST, FE_UNDERFLOW, }; /* @@ -91,16 +90,28 @@ pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { * If result is inexact, and exactly halfway between two float values, * we need to adjust the low-order bit in the direction of the error. */ - fesetround(FE_TOWARDZERO); - // prevent `vxy + z` from being CSE'd with `xy + z` above - let vxy: f64 = unsafe { read_volatile(&xy) }; - let mut adjusted_result: f64 = vxy + z as f64; - fesetround(FE_TONEAREST); - if result == adjusted_result { - ui = adjusted_result.to_bits(); + let neg = ui >> 63 != 0; + let err = if neg == (z as f64 > xy) { + xy - result + z as f64 + } else { + z as f64 - result + xy + }; + if neg == (err < 0.0) { ui += 1; - adjusted_result = f64::from_bits(ui); + } else { + ui -= 1; + } + f64::from_bits(ui) as f32 +} + +#[cfg(test)] +mod tests { + #[test] + fn issue_263() { + let a = f32::from_bits(1266679807); + let b = f32::from_bits(1300234242); + let c = f32::from_bits(1115553792); + let expected = f32::from_bits(1501560833); + assert_eq!(super::fmaf(a, b, c), expected); } - z = adjusted_result as f32; - z } From a695cf95cfd6a2067f1068384a9ee98c94a3a492 Mon Sep 17 00:00:00 2001 From: David Hoppenbrouwers Date: Wed, 10 Aug 2022 11:29:38 +0200 Subject: [PATCH 1054/4206] Remove c32() from x86_64 memcmp Fixes https://github.com/rust-lang/compiler-builtins/issues/487 --- library/compiler-builtins/src/mem/x86_64.rs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index dd98e37c5f0fa..17b461f791426 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -170,19 +170,7 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { let c4 = |a: *const u32, b, n| cmp(a, b, n, c2); let c8 = |a: *const u64, b, n| cmp(a, b, n, c4); let c16 = |a: *const u128, b, n| cmp(a, b, n, c8); - let c32 = |a: *const [u128; 2], b, n| cmp(a, b, n, c16); - // [u128; 2] internally uses raw_eq for comparisons, which may emit a call to memcmp - // above a certain size threshold. When SSE2 is enabled this threshold does not seem - // to be reached but without SSE2 a call is emitted, leading to infinite recursion. - // - // While replacing [u128; 2] with (u128, u128) fixes the issues it degrades performance - // severely. Likewise, removing c32() has a lesser but still significant impact. Instead the - // [u128; 2] case is only enabled when SSE2 is present. - if cfg!(target_feature = "sse2") { - c32(a.cast(), b.cast(), n) - } else { - c16(a.cast(), b.cast(), n) - } + c16(a.cast(), b.cast(), n) } /// Determine optimal parameters for a `rep` instruction. From 8b42fe77b7485de7a4215dba8b13402deaaacc65 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 10 Aug 2022 15:23:56 +0100 Subject: [PATCH 1055/4206] Bump to 0.2.5 --- library/compiler-builtins/libm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index a94a85a26ea05..527c383b99f14 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/libm" -version = "0.2.3" +version = "0.2.5" edition = "2018" [features] From 1eb4cc19776282cfee7be880749ff7cd6786371f Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 10 Aug 2022 15:19:30 +0100 Subject: [PATCH 1056/4206] Update libm submodule --- library/compiler-builtins/libm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index d6d8a1610c991..14a76eaf8dab4 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit d6d8a1610c9912c84c4c1d12d994d0204dc702ef +Subproject commit 14a76eaf8dab437e92c5fc505c48fb4ed0eb3483 From 83c4ff5f9672683bdcc45188f39d48c58d60c150 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 10 Aug 2022 15:28:39 +0100 Subject: [PATCH 1057/4206] Bump to 0.1.79 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 826dee795b4ac..26258dd4f94c2 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.78" +version = "0.1.79" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 1d5b9521002e6b8c6a3beba995d767f29ec82ff9 Mon Sep 17 00:00:00 2001 From: D1plo1d Date: Sat, 17 Sep 2022 11:47:21 -0400 Subject: [PATCH 1058/4206] math: Enabled floating point intrinsics for RISCV32 microcontrollers --- library/compiler-builtins/src/math.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index fa983618695c9..3fc33b1273829 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -118,8 +118,11 @@ no_mangle! { fn truncf(x: f32) -> f32; } -// only for the thumb*-none-eabi* targets -#[cfg(all(target_arch = "arm", target_os = "none"))] +// only for the thumb*-none-eabi* targets and riscv32*-none-elf targets that lack the floating point instruction set +#[cfg(any( + all(target_arch = "arm", target_os = "none"), + all(target_arch = "riscv32", not(target_feature = "f"), target_os = "none") +))] no_mangle! { fn fmin(x: f64, y: f64) -> f64; fn fminf(x: f32, y: f32) -> f32; From 4c8bb40c8df0313192982a7df6e19338c1a74c49 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 20 Sep 2022 16:20:52 +0800 Subject: [PATCH 1059/4206] Bump to 0.1.80 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 26258dd4f94c2..f44b8e1113c95 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.79" +version = "0.1.80" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From f6cd5cf8060b82911c3e549d468e919e86b2d64a Mon Sep 17 00:00:00 2001 From: Lokathor Date: Tue, 27 Sep 2022 13:22:45 -0600 Subject: [PATCH 1060/4206] Update macros.rs --- library/compiler-builtins/src/macros.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 7d90b7aadbe1c..477c256843198 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -266,6 +266,7 @@ macro_rules! intrinsics { #[cfg(target_arch = "arm")] pub mod $alias { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] pub extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } From 8bc227d1fe7cbffd1c742bbf93a02eb4597e25bd Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 29 Sep 2022 03:16:50 +0100 Subject: [PATCH 1061/4206] Bump to 0.1.81 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index f44b8e1113c95..5c8ea2597c9ae 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.80" +version = "0.1.81" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 98e9ab973a653aaa70d29dd7d5af759ae262d854 Mon Sep 17 00:00:00 2001 From: Andrew Tribick Date: Fri, 30 Sep 2022 14:11:15 +0200 Subject: [PATCH 1062/4206] Use wrapping_neg() to avoid fma errors on underflow --- library/compiler-builtins/libm/src/math/fma.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 516f9ad3a77fe..f9a86dc60633b 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -126,8 +126,8 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { rlo = res; rhi = rhi.wrapping_sub(zhi.wrapping_add(borrow as u64)); if (rhi >> 63) != 0 { - rlo = (-(rlo as i64)) as u64; - rhi = (-(rhi as i64)) as u64 - (rlo != 0) as u64; + rlo = (rlo as i64).wrapping_neg() as u64; + rhi = (rhi as i64).wrapping_neg() as u64 - (rlo != 0) as u64; sign = (sign == 0) as i32; } nonzero = (rhi != 0) as i32; @@ -232,4 +232,12 @@ mod tests { -3991680619069439e277 ); } + + #[test] + fn fma_underflow() { + assert_eq!( + fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), + 0.0, + ); + } } From 2e0590c997215db442213b19db6b0ff7e0605d7b Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 10 Oct 2022 17:40:16 +0100 Subject: [PATCH 1063/4206] Fix clippy lints --- library/compiler-builtins/src/float/conv.rs | 6 +++--- library/compiler-builtins/src/float/div.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 68ba63408e934..19fdc2fdc698d 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -13,7 +13,7 @@ mod int_to_float { let a = (i << n) >> 8; // Significant bits, with bit 24 still in tact. let b = (i << n) << 24; // Insignificant bits, only relevant for rounding. let m = a + ((b - (b >> 31 & !a)) >> 31); // Add one when we need to round up. Break ties to even. - let e = 157 - n as u32; // Exponent plus 127, minus one. + let e = 157 - n; // Exponent plus 127, minus one. (e << 23) + m // + not |, so the mantissa can overflow into the exponent. } @@ -42,8 +42,8 @@ mod int_to_float { return 0; } let n = i.leading_zeros(); - let a = ((i << n) >> 11) as u64; // Significant bits, with bit 53 still in tact. - let b = ((i << n) << 53) as u64; // Insignificant bits, only relevant for rounding. + let a = (i << n) >> 11; // Significant bits, with bit 53 still in tact. + let b = (i << n) << 53; // Insignificant bits, only relevant for rounding. let m = a + ((b - (b >> 63 & !a)) >> 63); // Add one when we need to round up. Break ties to even. let e = 1085 - n as u64; // Exponent plus 1023, minus one. (e << 52) + m // + not |, so the mantissa can overflow into the exponent. diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index 528a8368d9252..c2d6c07e73dbd 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -135,11 +135,11 @@ where let mut correction: u32 = negate_u32(((reciprocal as u64).wrapping_mul(q31b as u64) >> 32) as u32); - reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) as u64 >> 31) as u32; + reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) >> 31) as u32; correction = negate_u32(((reciprocal as u64).wrapping_mul(q31b as u64) >> 32) as u32); - reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) as u64 >> 31) as u32; + reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) >> 31) as u32; correction = negate_u32(((reciprocal as u64).wrapping_mul(q31b as u64) >> 32) as u32); - reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) as u64 >> 31) as u32; + reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) >> 31) as u32; // Exhaustive testing shows that the error in reciprocal after three steps // is in the interval [-0x1.f58108p-31, 0x1.d0e48cp-29], in line with our From 626754531561adee4f076916fc6cb029b5f59e27 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Oct 2022 14:58:18 +0200 Subject: [PATCH 1064/4206] invoke the unreachable intrinsic, not the stable wrapper --- library/compiler-builtins/src/int/specialized_div_rem/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index 6ec4675df94f4..77034eb5476e9 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -72,7 +72,10 @@ mod asymmetric; /// impossible to reach by Rust users, unless `compiler-builtins` public division functions or /// `core/std::unchecked_div/rem` are directly used without a zero check in front. fn zero_div_fn() -> ! { - unsafe { core::hint::unreachable_unchecked() } + // Calling the intrinsic directly, to avoid the `assert_unsafe_precondition` that cannot be used + // here because it involves non-`inline` functions + // (https://github.com/rust-lang/compiler-builtins/issues/491). + unsafe { core::intrinsics::unreachable() } } const USE_LZ: bool = { From 6f53a4f0749f19a0bc309daa5eb900563f296413 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 10 Oct 2022 19:04:06 +0100 Subject: [PATCH 1065/4206] Bump to 0.1.82 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 5c8ea2597c9ae..fb113b922beee 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.81" +version = "0.1.82" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 8266a1343b3ee164da223f9f034562ba1aa44d45 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 25 Oct 2022 11:25:14 -0400 Subject: [PATCH 1066/4206] Document origins of the multiplication method being used here. --- library/compiler-builtins/src/riscv.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/riscv.rs b/library/compiler-builtins/src/riscv.rs index ee78b9dbacf48..eff249692ce30 100644 --- a/library/compiler-builtins/src/riscv.rs +++ b/library/compiler-builtins/src/riscv.rs @@ -1,5 +1,18 @@ intrinsics! { - // Implementation from gcc + // 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 pub extern "C" fn __mulsi3(a: u32, b: u32) -> u32 { let (mut a, mut b) = (a, b); From 2faf57c08da1098b16591430940a07fa865b2e98 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 25 Oct 2022 12:32:41 -0400 Subject: [PATCH 1067/4206] might as well add the link to the LLVM assembly code as well. --- library/compiler-builtins/src/riscv.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/src/riscv.rs b/library/compiler-builtins/src/riscv.rs index eff249692ce30..ae361b33acfb8 100644 --- a/library/compiler-builtins/src/riscv.rs +++ b/library/compiler-builtins/src/riscv.rs @@ -14,6 +14,9 @@ intrinsics! { // // 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 = 0; From e3efddc2c25b36408fa5184b6bc8c7700d32b2a4 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 7 Nov 2022 12:34:47 -0500 Subject: [PATCH 1068/4206] Add `roundeven` and `roundevenf` --- library/compiler-builtins/libm/build.rs | 3 ++ .../compiler-builtins/libm/src/math/mod.rs | 4 ++ .../libm/src/math/roundeven.rs | 50 +++++++++++++++++++ .../libm/src/math/roundevenf.rs | 50 +++++++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/roundeven.rs create mode 100644 library/compiler-builtins/libm/src/math/roundevenf.rs diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 80145a9ccac97..403304a1383b3 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -39,6 +39,9 @@ mod musl_reference_tests { "jnf.rs", "j1.rs", "j1f.rs", + // musl doens't have these + "roundeven.rs", + "roundevenf.rs", ]; struct Function { diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 81bfc53ed854a..e710bd381bc11 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -171,6 +171,8 @@ mod remainderf; mod remquo; mod remquof; mod round; +mod roundeven; +mod roundevenf; mod roundf; mod scalbn; mod scalbnf; @@ -285,6 +287,8 @@ pub use self::remainderf::remainderf; pub use self::remquo::remquo; pub use self::remquof::remquof; pub use self::round::round; +pub use self::roundeven::roundeven; +pub use self::roundevenf::roundevenf; pub use self::roundf::roundf; pub use self::scalbn::scalbn; pub use self::scalbnf::scalbnf; diff --git a/library/compiler-builtins/libm/src/math/roundeven.rs b/library/compiler-builtins/libm/src/math/roundeven.rs new file mode 100644 index 0000000000000..5cc30c8af8287 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/roundeven.rs @@ -0,0 +1,50 @@ +// Source: musl libm rint +// (equivalent to roundeven when rounding mode is default, +// which Rust assumes) + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundeven(x: f64) -> f64 { + let one_over_e = 1.0 / f64::EPSILON; + let as_u64: u64 = x.to_bits(); + let exponent: u64 = as_u64 >> 52 & 0x7ff; + let is_positive = (as_u64 >> 63) == 0; + if exponent >= 0x3ff + 52 { + x + } else { + let ans = if is_positive { + x + one_over_e - one_over_e + } else { + x - one_over_e + one_over_e + }; + + if ans == 0.0 { + if is_positive { + 0.0 + } else { + -0.0 + } + } else { + ans + } + } +} + +#[cfg(test)] +mod tests { + use super::roundeven; + + #[test] + fn negative_zero() { + assert_eq!(roundeven(-0.0_f64).to_bits(), (-0.0_f64).to_bits()); + } + + #[test] + fn sanity_check() { + assert_eq!(roundeven(-1.0), -1.0); + assert_eq!(roundeven(2.8), 3.0); + assert_eq!(roundeven(-0.5), -0.0); + assert_eq!(roundeven(0.5), 0.0); + assert_eq!(roundeven(-1.5), -2.0); + assert_eq!(roundeven(1.5), 2.0); + } +} diff --git a/library/compiler-builtins/libm/src/math/roundevenf.rs b/library/compiler-builtins/libm/src/math/roundevenf.rs new file mode 100644 index 0000000000000..e720dcd947809 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/roundevenf.rs @@ -0,0 +1,50 @@ +// Source: musl libm rintf +// (equivalent to roundevenf when rounding mode is default, +// which Rust assumes) + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundevenf(x: f32) -> f32 { + let one_over_e = 1.0 / f32::EPSILON; + let as_u32: u32 = x.to_bits(); + let exponent: u32 = as_u32 >> 23 & 0xff; + let is_positive = (as_u32 >> 31) == 0; + if exponent >= 0x7f + 23 { + x + } else { + let ans = if is_positive { + x + one_over_e - one_over_e + } else { + x - one_over_e + one_over_e + }; + + if ans == 0.0 { + if is_positive { + 0.0 + } else { + -0.0 + } + } else { + ans + } + } +} + +#[cfg(test)] +mod tests { + use super::roundevenf; + + #[test] + fn negative_zero() { + assert_eq!(roundevenf(-0.0_f32).to_bits(), (-0.0_f32).to_bits()); + } + + #[test] + fn sanity_check() { + assert_eq!(roundevenf(-1.0), -1.0); + assert_eq!(roundevenf(2.8), 3.0); + assert_eq!(roundevenf(-0.5), -0.0); + assert_eq!(roundevenf(0.5), 0.0); + assert_eq!(roundevenf(-1.5), -2.0); + assert_eq!(roundevenf(1.5), 2.0); + } +} From 292221cf4c1055850c219f141525c7cfade0cab6 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 7 Nov 2022 12:53:26 -0500 Subject: [PATCH 1069/4206] `rint`/`rintf` instead of `roundeven`/`roundevenf` --- library/compiler-builtins/libm/build.rs | 3 --- .../compiler-builtins/libm/src/math/mod.rs | 8 +++---- .../libm/src/math/{roundeven.rs => rint.rs} | 22 ++++++++----------- .../libm/src/math/{roundevenf.rs => rintf.rs} | 22 ++++++++----------- 4 files changed, 22 insertions(+), 33 deletions(-) rename library/compiler-builtins/libm/src/math/{roundeven.rs => rint.rs} (59%) rename library/compiler-builtins/libm/src/math/{roundevenf.rs => rintf.rs} (58%) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 403304a1383b3..80145a9ccac97 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -39,9 +39,6 @@ mod musl_reference_tests { "jnf.rs", "j1.rs", "j1f.rs", - // musl doens't have these - "roundeven.rs", - "roundevenf.rs", ]; struct Function { diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index e710bd381bc11..05ebb708c9c5c 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -170,9 +170,9 @@ mod remainder; mod remainderf; mod remquo; mod remquof; +mod rint; +mod rintf; mod round; -mod roundeven; -mod roundevenf; mod roundf; mod scalbn; mod scalbnf; @@ -286,9 +286,9 @@ pub use self::remainder::remainder; pub use self::remainderf::remainderf; pub use self::remquo::remquo; pub use self::remquof::remquof; +pub use self::rint::rint; +pub use self::rintf::rintf; pub use self::round::round; -pub use self::roundeven::roundeven; -pub use self::roundevenf::roundevenf; pub use self::roundf::roundf; pub use self::scalbn::scalbn; pub use self::scalbnf::scalbnf; diff --git a/library/compiler-builtins/libm/src/math/roundeven.rs b/library/compiler-builtins/libm/src/math/rint.rs similarity index 59% rename from library/compiler-builtins/libm/src/math/roundeven.rs rename to library/compiler-builtins/libm/src/math/rint.rs index 5cc30c8af8287..97d167ab83586 100644 --- a/library/compiler-builtins/libm/src/math/roundeven.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -1,9 +1,5 @@ -// Source: musl libm rint -// (equivalent to roundeven when rounding mode is default, -// which Rust assumes) - #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundeven(x: f64) -> f64 { +pub fn rint(x: f64) -> f64 { let one_over_e = 1.0 / f64::EPSILON; let as_u64: u64 = x.to_bits(); let exponent: u64 = as_u64 >> 52 & 0x7ff; @@ -31,20 +27,20 @@ pub fn roundeven(x: f64) -> f64 { #[cfg(test)] mod tests { - use super::roundeven; + use super::rint; #[test] fn negative_zero() { - assert_eq!(roundeven(-0.0_f64).to_bits(), (-0.0_f64).to_bits()); + assert_eq!(rint(-0.0_f64).to_bits(), (-0.0_f64).to_bits()); } #[test] fn sanity_check() { - assert_eq!(roundeven(-1.0), -1.0); - assert_eq!(roundeven(2.8), 3.0); - assert_eq!(roundeven(-0.5), -0.0); - assert_eq!(roundeven(0.5), 0.0); - assert_eq!(roundeven(-1.5), -2.0); - assert_eq!(roundeven(1.5), 2.0); + assert_eq!(rint(-1.0), -1.0); + assert_eq!(rint(2.8), 3.0); + assert_eq!(rint(-0.5), -0.0); + assert_eq!(rint(0.5), 0.0); + assert_eq!(rint(-1.5), -2.0); + assert_eq!(rint(1.5), 2.0); } } diff --git a/library/compiler-builtins/libm/src/math/roundevenf.rs b/library/compiler-builtins/libm/src/math/rintf.rs similarity index 58% rename from library/compiler-builtins/libm/src/math/roundevenf.rs rename to library/compiler-builtins/libm/src/math/rintf.rs index e720dcd947809..7b87fafb3c58e 100644 --- a/library/compiler-builtins/libm/src/math/roundevenf.rs +++ b/library/compiler-builtins/libm/src/math/rintf.rs @@ -1,9 +1,5 @@ -// Source: musl libm rintf -// (equivalent to roundevenf when rounding mode is default, -// which Rust assumes) - #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundevenf(x: f32) -> f32 { +pub fn rintf(x: f32) -> f32 { let one_over_e = 1.0 / f32::EPSILON; let as_u32: u32 = x.to_bits(); let exponent: u32 = as_u32 >> 23 & 0xff; @@ -31,20 +27,20 @@ pub fn roundevenf(x: f32) -> f32 { #[cfg(test)] mod tests { - use super::roundevenf; + use super::rintf; #[test] fn negative_zero() { - assert_eq!(roundevenf(-0.0_f32).to_bits(), (-0.0_f32).to_bits()); + assert_eq!(rintf(-0.0_f32).to_bits(), (-0.0_f32).to_bits()); } #[test] fn sanity_check() { - assert_eq!(roundevenf(-1.0), -1.0); - assert_eq!(roundevenf(2.8), 3.0); - assert_eq!(roundevenf(-0.5), -0.0); - assert_eq!(roundevenf(0.5), 0.0); - assert_eq!(roundevenf(-1.5), -2.0); - assert_eq!(roundevenf(1.5), 2.0); + assert_eq!(rintf(-1.0), -1.0); + assert_eq!(rintf(2.8), 3.0); + assert_eq!(rintf(-0.5), -0.0); + assert_eq!(rintf(0.5), 0.0); + assert_eq!(rintf(-1.5), -2.0); + assert_eq!(rintf(1.5), 2.0); } } From 83524d4aa286c80207b4742cb49b96e3c452d521 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 7 Nov 2022 13:19:05 -0500 Subject: [PATCH 1070/4206] Disable tests on PowerPC --- library/compiler-builtins/libm/src/math/rint.rs | 2 ++ library/compiler-builtins/libm/src/math/rintf.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index 97d167ab83586..0c6025c1f73d4 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -25,6 +25,8 @@ pub fn rint(x: f64) -> f64 { } } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { use super::rint; diff --git a/library/compiler-builtins/libm/src/math/rintf.rs b/library/compiler-builtins/libm/src/math/rintf.rs index 7b87fafb3c58e..d427793f7fc61 100644 --- a/library/compiler-builtins/libm/src/math/rintf.rs +++ b/library/compiler-builtins/libm/src/math/rintf.rs @@ -25,6 +25,8 @@ pub fn rintf(x: f32) -> f32 { } } +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { use super::rintf; From 90128a1abb9b1a30c3b4dcc322ba408d6d5e24e6 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 7 Nov 2022 23:43:14 -0500 Subject: [PATCH 1071/4206] Add benchmarks --- .../compiler-builtins/libm/crates/libm-bench/benches/bench.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-bench/benches/bench.rs b/library/compiler-builtins/libm/crates/libm-bench/benches/bench.rs index b6d8741531f3f..ca999b90f27c4 100644 --- a/library/compiler-builtins/libm/crates/libm-bench/benches/bench.rs +++ b/library/compiler-builtins/libm/crates/libm-bench/benches/bench.rs @@ -107,7 +107,8 @@ macro_rules! bessel { unary!( acos, acosh, asin, atan, cbrt, ceil, cos, cosh, erf, exp, exp2, exp10, expm1, fabs, floor, j0, - j1, lgamma, log, log1p, log2, log10, round, sin, sinh, sqrt, tan, tanh, tgamma, trunc, y0, y1 + j1, lgamma, log, log1p, log2, log10, rint, round, sin, sinh, sqrt, tan, tanh, tgamma, trunc, + y0, y1 ); binary!(atan2, copysign, fdim, fmax, fmin, fmod, hypot, pow); trinary!(fma); From 53dec2fc63522c995dbdc82f3b8bedf6eedfe119 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 9 Nov 2022 01:30:02 +0000 Subject: [PATCH 1072/4206] Bump to 0.2.6 --- library/compiler-builtins/libm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 527c383b99f14..f942fdec3c922 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/libm" -version = "0.2.5" +version = "0.2.6" edition = "2018" [features] From af5664be846f41ebd0a48725936ac489f10d57c1 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Tue, 8 Nov 2022 21:02:21 -0500 Subject: [PATCH 1073/4206] Update `libm`, add `rint` and `rintf` --- library/compiler-builtins/libm | 2 +- library/compiler-builtins/src/math.rs | 16 ++-------------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 14a76eaf8dab4..4c8a973741c01 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 14a76eaf8dab437e92c5fc505c48fb4ed0eb3483 +Subproject commit 4c8a973741c014b11ce7f1477693a3e5d4ef9609 diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 3fc33b1273829..4ae174891c2f3 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -46,6 +46,8 @@ no_mangle! { fn fmaxf(x: f32, y: f32) -> f32; fn round(x: f64) -> f64; fn roundf(x: f32) -> f32; + fn rint(x: f64) -> f64; + fn rintf(x: f32) -> f32; fn sin(x: f64) -> f64; fn pow(x: f64, y: f64) -> f64; fn powf(x: f32, y: f32) -> f32; @@ -65,20 +67,6 @@ no_mangle! { fn ldexpf(f: f32, n: i32) -> f32; fn tgamma(x: f64) -> f64; fn tgammaf(x: f32) -> f32; -} - -#[cfg(any( - all( - target_family = "wasm", - target_os = "unknown", - not(target_env = "wasi") - ), - target_os = "xous", - all(target_arch = "x86_64", target_os = "uefi"), - all(target_arch = "xtensa", target_os = "none"), - all(target_vendor = "fortanix", target_env = "sgx") -))] -no_mangle! { fn atan(x: f64) -> f64; fn atan2(x: f64, y: f64) -> f64; fn cosh(x: f64) -> f64; From a996f56f5a4fbfe42ad34373d6b5ab28458321df Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 9 Nov 2022 04:12:51 +0000 Subject: [PATCH 1074/4206] Bump to 0.1.83 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index fb113b922beee..092460e425464 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.82" +version = "0.1.83" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 524ca7ceb6111681fae7ffa73491d477d008ea3c Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 12 Nov 2022 12:06:04 -0500 Subject: [PATCH 1075/4206] Remove unused `no-lang-items` feature --- library/compiler-builtins/Cargo.toml | 3 --- library/compiler-builtins/testcrate/Cargo.toml | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 092460e425464..36c1f8a08df4a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -58,9 +58,6 @@ mem = [] # compiler-rt implementations. Also used for testing mangled-names = [] -# Don't generate lang items for i128 intrisnics and such -no-lang-items = [] - # Only used in the compiler's build system rustc-dep-of-std = ['compiler-builtins', 'core'] diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 1f77b255491a4..762d3293b2b67 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -17,7 +17,7 @@ rand_xoshiro = "0.6" [dependencies.compiler_builtins] path = ".." default-features = false -features = ["no-lang-items", "public-test-deps"] +features = ["public-test-deps"] [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" } From 95c860d1bf676ec1652f069a30a060db0ded9355 Mon Sep 17 00:00:00 2001 From: Luc Date: Mon, 14 Nov 2022 16:49:43 +0100 Subject: [PATCH 1076/4206] Add Small Conformance tests to Sqrt(f) --- library/compiler-builtins/libm/src/math/sqrt.rs | 12 ++++++++++++ library/compiler-builtins/libm/src/math/sqrtf.rs | 11 +++++++++++ 2 files changed, 23 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index f06b209a49f2f..9a700d8ea0f20 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -261,4 +261,16 @@ mod tests { assert_eq!(sqrt(f), f); } } + + #[test] + fn conformance_tests() { + let values = [3.14159265359, 10000.0, -1.0, INFINITY]; + let results = [4610661241675116657u64, 4636737291354636288u64, + 18444492273895866368u64, 9218868437227405312u64]; + + for i in 0..values.len() { + let bits = f64::to_bits(sqrt(values[i])); + assert_eq!(results[i], bits); + } + } } diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 00b20e578be91..b1321137629ba 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -151,4 +151,15 @@ mod tests { assert_eq!(sqrtf(f), f); } } + + #[test] + fn conformance_tests() { + let values = [3.14159265359f32, 10000.0f32, -1.0f32, INFINITY]; + let results = [1071833029u32, 1120403456u32, 4290772992u32, 2139095040u32]; + + for i in 0..values.len() { + let bits = f32::to_bits(sqrtf(values[i])); + assert_eq!(results[i], bits); + } + } } From 294eab952066583556a05fe5c68e8bac0e5fe370 Mon Sep 17 00:00:00 2001 From: Luc Date: Wed, 16 Nov 2022 15:39:13 +0100 Subject: [PATCH 1077/4206] Remove negative numbers from test --- library/compiler-builtins/libm/src/math/sqrt.rs | 4 ++-- library/compiler-builtins/libm/src/math/sqrtf.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 9a700d8ea0f20..434d4d6d775fd 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -264,9 +264,9 @@ mod tests { #[test] fn conformance_tests() { - let values = [3.14159265359, 10000.0, -1.0, INFINITY]; + let values = [3.14159265359, 10000.0, f64::from_bits(0x0000000f), INFINITY]; let results = [4610661241675116657u64, 4636737291354636288u64, - 18444492273895866368u64, 9218868437227405312u64]; + 2197470602079456986u64, 9218868437227405312u64]; for i in 0..values.len() { let bits = f64::to_bits(sqrt(values[i])); diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index b1321137629ba..04301355e75e3 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -154,9 +154,9 @@ mod tests { #[test] fn conformance_tests() { - let values = [3.14159265359f32, 10000.0f32, -1.0f32, INFINITY]; - let results = [1071833029u32, 1120403456u32, 4290772992u32, 2139095040u32]; - + let values = [3.14159265359f32, 10000.0f32, f32::from_bits(0x0000000f), INFINITY]; + let results = [1071833029u32, 1120403456u32, 456082799u32, 2139095040u32]; + for i in 0..values.len() { let bits = f32::to_bits(sqrtf(values[i])); assert_eq!(results[i], bits); From b90b2f8547209a01362ed50b7aad80667e1190f5 Mon Sep 17 00:00:00 2001 From: Luc Date: Wed, 16 Nov 2022 15:44:43 +0100 Subject: [PATCH 1078/4206] Fix formatting Forgot to run cargo fmt last time... --- library/compiler-builtins/libm/src/math/sqrt.rs | 14 +++++++++----- library/compiler-builtins/libm/src/math/sqrtf.rs | 13 +++++++++---- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 434d4d6d775fd..3733ba0400f6c 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -261,16 +261,20 @@ mod tests { assert_eq!(sqrt(f), f); } } - + #[test] fn conformance_tests() { let values = [3.14159265359, 10000.0, f64::from_bits(0x0000000f), INFINITY]; - let results = [4610661241675116657u64, 4636737291354636288u64, - 2197470602079456986u64, 9218868437227405312u64]; - + let results = [ + 4610661241675116657u64, + 4636737291354636288u64, + 2197470602079456986u64, + 9218868437227405312u64, + ]; + for i in 0..values.len() { let bits = f64::to_bits(sqrt(values[i])); assert_eq!(results[i], bits); - } + } } } diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 04301355e75e3..8ec72fbf7fae3 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -151,15 +151,20 @@ mod tests { assert_eq!(sqrtf(f), f); } } - - #[test] + + #[test] fn conformance_tests() { - let values = [3.14159265359f32, 10000.0f32, f32::from_bits(0x0000000f), INFINITY]; + let values = [ + 3.14159265359f32, + 10000.0f32, + f32::from_bits(0x0000000f), + INFINITY, + ]; let results = [1071833029u32, 1120403456u32, 456082799u32, 2139095040u32]; for i in 0..values.len() { let bits = f32::to_bits(sqrtf(values[i])); assert_eq!(results[i], bits); - } + } } } From 98b3454d3db1110a26df7a8dde4efaf81bd278a0 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Tue, 15 Nov 2022 21:01:21 -0500 Subject: [PATCH 1079/4206] Skip assembly implementations on the UEFI targets The UEFI targets link with `/SAFESEH`. That requires that objects have a symbol called [`@feat.00`]. Clang adds that symbol for COFF targets if the input is a C file, but not if the input is an ASM file. That doesn't prevent compiler_builtins or rustc from building, but using the resulting rustc to compile something that references one of the objects lacking `@feat.00` will result in a linker error. Fix by removing all the `.S` implementations when `target_os == uefi`. [`@feat.00`]: https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#the-sxdata-section --- library/compiler-builtins/build.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 73952bb9f3ea9..8fde89d9101e2 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -465,7 +465,8 @@ mod c { } // Remove the assembly implementations that won't compile for the target - if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" { + if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" || target_os == "uefi" + { let mut to_remove = Vec::new(); for (k, v) in sources.map.iter() { if v.ends_with(".S") { From ebaca42a412c5650e04be953615e58a9b5fcf80a Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Wed, 16 Nov 2022 17:52:46 -0500 Subject: [PATCH 1080/4206] Use a stub stdlib.h when compiling for UEFI targets int_util.c includes stdlib.h if `_WIN32` is defined. When compiling the UEFI targets with clang they are treated as Windows targets (e.g. if the Rust target is x86_64-unknown-uefi, the clang target is x86_64-unknown-windows-gnu). So stdlib.h gets included, even though we are compilling with `-ffreestanding` and don't want stdlib.h to be used. That file may not be present, or an incompatible version might be installed leading to typedef redefinition errors. The contents of stdlib.h aren't actually needed for these targets anyway (due to `__STDC_HOSTED__` being 0), so create a minimal stdlib.h in `build.rs` when `target_os == uefi` and add it to the include path. --- library/compiler-builtins/build.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 8fde89d9101e2..3f5dbd3ab2748 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -98,7 +98,7 @@ mod c { use std::collections::{BTreeMap, HashSet}; use std::env; - use std::fs::File; + use std::fs::{self, File}; use std::io::Write; use std::path::{Path, PathBuf}; @@ -190,6 +190,21 @@ mod c { cfg.define("VISIBILITY_HIDDEN", None); } + // int_util.c tries to include stdlib.h if `_WIN32` is defined, + // which it is when compiling UEFI targets with clang. This is + // 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" { + 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())); + } + let mut sources = Sources::new(); sources.extend(&[ ("__absvdi2", "absvdi2.c"), From ad4ab99a2e0419b015a9a3f5f4c9cdd3f270c48a Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 18 Nov 2022 02:58:11 +0000 Subject: [PATCH 1081/4206] Bump to 0.1.84 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 36c1f8a08df4a..1b89d51e90469 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.83" +version = "0.1.84" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 80828bfb0b880822131243a016dbf38882a99dff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9rome=20Eertmans?= Date: Mon, 28 Nov 2022 10:53:42 +0100 Subject: [PATCH 1082/4206] fix(docs): typo in docstrings Hello, I think you misspelled `width` to `with`. --- library/compiler-builtins/src/float/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 01a5504d52c51..fdbe9dde35b19 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -26,10 +26,10 @@ pub(crate) trait Float: + ops::Div + ops::Rem { - /// A uint of the same with as the float + /// A uint of the same width as the float type Int: Int; - /// A int of the same with as the float + /// A int of the same width as the float type SignedInt: Int; /// An int capable of containing the exponent bits plus a sign bit. This is signed. From 620f50589e7e27d18121c52c4f82cb2c57173117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Wed, 7 Dec 2022 16:08:01 +0100 Subject: [PATCH 1083/4206] Expose minimal floating point symbols for x86_64-unknown-none --- library/compiler-builtins/src/lib.rs | 1 + library/compiler-builtins/src/math.rs | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index e7bc61e4c0f60..10b4aafec3123 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -44,6 +44,7 @@ pub mod int; #[cfg(any( all(target_family = "wasm", target_os = "unknown"), + all(target_arch = "x86_64", target_os = "none"), all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "arm", target_os = "none"), target_os = "xous", diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 4ae174891c2f3..c64984e9ee7b8 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -106,10 +106,11 @@ no_mangle! { fn truncf(x: f32) -> f32; } -// only for the thumb*-none-eabi* targets and riscv32*-none-elf targets that lack the floating point instruction set +// only for the thumb*-none-eabi*, riscv32*-none-elf and x86_64-unknown-none targets that lack the floating point instruction set #[cfg(any( all(target_arch = "arm", target_os = "none"), - all(target_arch = "riscv32", not(target_feature = "f"), target_os = "none") + all(target_arch = "riscv32", not(target_feature = "f"), target_os = "none"), + all(target_arch = "x86_64", target_os = "none") ))] no_mangle! { fn fmin(x: f64, y: f64) -> f64; From 62cd3780ae22bf341afaa2dfc1417f5e334efc73 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 8 Dec 2022 13:31:59 +0000 Subject: [PATCH 1084/4206] Bump to 0.1.85 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 1b89d51e90469..00998e40f803b 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.84" +version = "0.1.85" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From d20eea4d47593b37f6355d6fb364aa9826770fd8 Mon Sep 17 00:00:00 2001 From: Patryk Wychowaniec Date: Sun, 25 Dec 2022 11:46:30 +0100 Subject: [PATCH 1085/4206] fix: Add `#[avr_skip]` for bit shifts This commit follows the same logic as: - https://github.com/rust-lang/compiler-builtins/pull/462 - https://github.com/rust-lang/compiler-builtins/pull/466 I've tested the changes by preparing a simple program: ```rust fn calc() -> ... { let x = hint::black_box(4u...); // 4u8, 4u16, 4u32, 4u64, 4u128 + signed let y = hint::black_box(1u32); // x >> y // x << y } fn main() -> ! { let dp = arduino_hal::Peripherals::take().unwrap(); let pins = arduino_hal::pins!(dp); let mut serial = arduino_hal::default_serial!(dp, pins, 57600); for b in calc().to_le_bytes() { _ = ufmt::uwrite!(&mut serial, "{} ", b); } _ = ufmt::uwriteln!(&mut serial, ""); loop { // } } ``` ... switching types & operators in `calc()`, and observing the results; what I ended up with was: ``` u32 << u32 - ok u64 << u32 - ok u128 << u32 - error (undefined reference to `__ashlti3') i32 >> u32 - ok i64 >> u32 - ok i128 >> u32 - error (undefined reference to `__ashrti3') u32 >> u32 - ok u64 >> u32 - ok u128 >> u32 - error (undefined reference to `__lshrti3') (where "ok" = compiles and returns correct results) ``` As with multiplication and division, so do in here 128-bit operations not work, because avr-gcc's standard library doesn't provide them (at the same time, requiring that specific calling convention, making it pretty difficult for compiler-builtins to jump in). I think 128-bit operations non-working on an 8-bit controller is an acceptable trade-off - :innocent: - and so the entire fix in here is just about skipping those functions. --- library/compiler-builtins/src/int/shift.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 908e619e1dd81..2d2c081a680c9 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -69,47 +69,56 @@ impl Lshr for u64 {} impl Lshr for u128 {} intrinsics! { + #[avr_skip] #[maybe_use_optimized_c_shim] pub extern "C" fn __ashlsi3(a: u32, b: u32) -> u32 { a.ashl(b) } + #[avr_skip] #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_llsl] pub extern "C" fn __ashldi3(a: u64, b: u32) -> u64 { a.ashl(b) } + #[avr_skip] pub extern "C" fn __ashlti3(a: u128, b: u32) -> u128 { a.ashl(b) } + #[avr_skip] #[maybe_use_optimized_c_shim] pub extern "C" fn __ashrsi3(a: i32, b: u32) -> i32 { a.ashr(b) } + #[avr_skip] #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_lasr] pub extern "C" fn __ashrdi3(a: i64, b: u32) -> i64 { a.ashr(b) } + #[avr_skip] pub extern "C" fn __ashrti3(a: i128, b: u32) -> i128 { a.ashr(b) } + #[avr_skip] #[maybe_use_optimized_c_shim] pub extern "C" fn __lshrsi3(a: u32, b: u32) -> u32 { a.lshr(b) } + #[avr_skip] #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_llsr] pub extern "C" fn __lshrdi3(a: u64, b: u32) -> u64 { a.lshr(b) } + #[avr_skip] pub extern "C" fn __lshrti3(a: u128, b: u32) -> u128 { a.lshr(b) } From 7f39126ff9c97ad21d4c87ae8e12f2315681c0ed Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 29 Dec 2022 20:36:57 +0100 Subject: [PATCH 1086/4206] Bump to 0.1.86 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 00998e40f803b..f143c1033f07e 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.85" +version = "0.1.86" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 7777c60a0b574a0f0fcb7f5a423a03199a9a4060 Mon Sep 17 00:00:00 2001 From: Moritz Meier Date: Tue, 17 Jan 2023 20:41:24 +0100 Subject: [PATCH 1087/4206] add generic libm helper Add editorconfig + docs refactor --- library/compiler-builtins/libm/.editorconfig | 21 +++ library/compiler-builtins/libm/src/lib.rs | 2 + .../compiler-builtins/libm/src/libm_helper.rs | 171 ++++++++++++++++++ 3 files changed, 194 insertions(+) create mode 100644 library/compiler-builtins/libm/.editorconfig create mode 100644 library/compiler-builtins/libm/src/libm_helper.rs diff --git a/library/compiler-builtins/libm/.editorconfig b/library/compiler-builtins/libm/.editorconfig new file mode 100644 index 0000000000000..ec6e107d547f0 --- /dev/null +++ b/library/compiler-builtins/libm/.editorconfig @@ -0,0 +1,21 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + +[*] +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +indent_size = 4 + +[*.md] +# double whitespace at end of line +# denotes a line break in Markdown +trim_trailing_whitespace = false + +[*.yml] +indent_size = 2 diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 29742b4510c82..4a17d3a77a213 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -12,11 +12,13 @@ #![allow(clippy::eq_op)] #![allow(clippy::assign_op_pattern)] +mod libm_helper; mod math; use core::{f32, f64}; pub use self::math::*; +pub use libm_helper::*; /// Approximate equality with 1 ULP of tolerance #[doc(hidden)] diff --git a/library/compiler-builtins/libm/src/libm_helper.rs b/library/compiler-builtins/libm/src/libm_helper.rs new file mode 100644 index 0000000000000..52d0c4c2a11e4 --- /dev/null +++ b/library/compiler-builtins/libm/src/libm_helper.rs @@ -0,0 +1,171 @@ +use core::marker::PhantomData; + +use crate::*; + +/// Generic helper for libm functions, abstracting over f32 and f64.
+/// # Type Parameter: +/// - `T`: Either `f32` or `f64` +/// +/// # Examples +/// ```rust +/// use libm::{self, Libm}; +/// +/// const PI_F32: f32 = 3.1415927410e+00; +/// const PI_F64: f64 = 3.1415926535897931160e+00; +/// +/// assert!(Libm::::cos(0.0f32) == libm::cosf(0.0)); +/// assert!(Libm::::sin(PI_F32) == libm::sinf(PI_F32)); +/// +/// assert!(Libm::::cos(0.0f64) == libm::cos(0.0)); +/// assert!(Libm::::sin(PI_F64) == libm::sin(PI_F64)); +/// ``` +pub struct Libm(PhantomData); + +macro_rules! libm_helper { + ($t:ident, funcs: $funcs:tt) => { + impl Libm<$t> { + #![allow(unused_parens)] + + libm_helper! { $funcs } + } + }; + + ({$($func:tt);*}) => { + $( + libm_helper! { $func } + )* + }; + + ((fn $func:ident($($arg:ident: $arg_typ:ty),*) -> ($($ret_typ:ty),*); => $libm_fn:ident)) => { + #[inline(always)] + pub fn $func($($arg: $arg_typ),*) -> ($($ret_typ),*) { + $libm_fn($($arg),*) + } + }; +} + +libm_helper! { + f32, + funcs: { + (fn acos(x: f32) -> (f32); => acosf); + (fn acosh(x: f32) -> (f32); => acoshf); + (fn asin(x: f32) -> (f32); => asinf); + (fn asinh(x: f32) -> (f32); => asinhf); + (fn atan(x: f32) -> (f32); => atanf); + (fn atan2(y: f32, x: f32) -> (f32); => atan2f); + (fn atanh(x: f32) -> (f32); => atanhf); + (fn cbrt(x: f32) -> (f32); => cbrtf); + (fn ceil(x: f32) -> (f32); => ceilf); + (fn copysign(x: f32, y: f32) -> (f32); => copysignf); + (fn cos(x: f32) -> (f32); => cosf); + (fn cosh(x: f32) -> (f32); => coshf); + (fn erf(x: f32) -> (f32); => erff); + (fn erfc(x: f32) -> (f32); => erfcf); + (fn exp(x: f32) -> (f32); => expf); + (fn exp2(x: f32) -> (f32); => exp2f); + (fn exp10(x: f32) -> (f32); => exp10f); + (fn expm1(x: f32) -> (f32); => expm1f); + (fn fabs(x: f32) -> (f32); => fabsf); + (fn fdim(x: f32, y: f32) -> (f32); => fdimf); + (fn floor(x: f32) -> (f32); => floorf); + (fn fma(x: f32, y: f32, z: f32) -> (f32); => fmaf); + (fn fmax(x: f32, y: f32) -> (f32); => fmaxf); + (fn fmin(x: f32, y: f32) -> (f32); => fminf); + (fn fmod(x: f32, y: f32) -> (f32); => fmodf); + (fn frexp(x: f32) -> (f32, i32); => frexpf); + (fn hypot(x: f32, y: f32) -> (f32); => hypotf); + (fn ilogb(x: f32) -> (i32); => ilogbf); + (fn j0(x: f32) -> (f32); => j0f); + (fn j1(x: f32) -> (f32); => j1f); + (fn jn(n: i32, x: f32) -> (f32); => jnf); + (fn ldexp(x: f32, n: i32) -> (f32); => ldexpf); + (fn lgamma_r(x: f32) -> (f32, i32); => lgammaf_r); + (fn lgamma(x: f32) -> (f32); => lgammaf); + (fn log(x: f32) -> (f32); => logf); + (fn log1p(x: f32) -> (f32); => log1pf); + (fn log2(x: f32) -> (f32); => log2f); + (fn log10(x: f32) -> (f32); => log10f); + (fn modf(x: f32) -> (f32, f32); => modff); + (fn nextafter(x: f32, y: f32) -> (f32); => nextafterf); + (fn pow(x: f32, y: f32) -> (f32); => powf); + (fn remainder(x: f32, y: f32) -> (f32); => remainderf); + (fn remquo(x: f32, y: f32) -> (f32, i32); => remquof); + (fn rint(x: f32) -> (f32); => rintf); + (fn round(x: f32) -> (f32); => roundf); + (fn scalbn(x: f32, n: i32) -> (f32); => scalbnf); + (fn sin(x: f32) -> (f32); => sinf); + (fn sincos(x: f32) -> (f32, f32); => sincosf); + (fn sinh(x: f32) -> (f32); => sinhf); + (fn sqrt(x: f32) -> (f32); => sqrtf); + (fn tan(x: f32) -> (f32); => tanf); + (fn tanh(x: f32) -> (f32); => tanhf); + (fn tgamma(x: f32) -> (f32); => tgammaf); + (fn trunc(x: f32) -> (f32); => truncf); + (fn y0(x: f32) -> (f32); => y0f); + (fn y1(x: f32) -> (f32); => y1f); + (fn yn(n: i32, x: f32) -> (f32); => ynf) + } +} + +libm_helper! { + f64, + funcs: { + (fn acos(x: f64) -> (f64); => acos); + (fn acosh(x: f64) -> (f64); => acosh); + (fn asin(x: f64) -> (f64); => asin); + (fn asinh(x: f64) -> (f64); => asinh); + (fn atan(x: f64) -> (f64); => atan); + (fn atan2(y: f64, x: f64) -> (f64); => atan2); + (fn atanh(x: f64) -> (f64); => atanh); + (fn cbrt(x: f64) -> (f64); => cbrt); + (fn ceil(x: f64) -> (f64); => ceil); + (fn copysign(x: f64, y: f64) -> (f64); => copysign); + (fn cos(x: f64) -> (f64); => cos); + (fn cosh(x: f64) -> (f64); => cosh); + (fn erf(x: f64) -> (f64); => erf); + (fn erfc(x: f64) -> (f64); => erfc); + (fn exp(x: f64) -> (f64); => exp); + (fn exp2(x: f64) -> (f64); => exp2); + (fn exp10(x: f64) -> (f64); => exp10); + (fn expm1(x: f64) -> (f64); => expm1); + (fn fabs(x: f64) -> (f64); => fabs); + (fn fdim(x: f64, y: f64) -> (f64); => fdim); + (fn floor(x: f64) -> (f64); => floor); + (fn fma(x: f64, y: f64, z: f64) -> (f64); => fma); + (fn fmax(x: f64, y: f64) -> (f64); => fmax); + (fn fmin(x: f64, y: f64) -> (f64); => fmin); + (fn fmod(x: f64, y: f64) -> (f64); => fmod); + (fn frexp(x: f64) -> (f64, i32); => frexp); + (fn hypot(x: f64, y: f64) -> (f64); => hypot); + (fn ilogb(x: f64) -> (i32); => ilogb); + (fn j0(x: f64) -> (f64); => j0); + (fn j1(x: f64) -> (f64); => j1); + (fn jn(n: i32, x: f64) -> (f64); => jn); + (fn ldexp(x: f64, n: i32) -> (f64); => ldexp); + (fn lgamma_r(x: f64) -> (f64, i32); => lgamma_r); + (fn lgamma(x: f64) -> (f64); => lgamma); + (fn log(x: f64) -> (f64); => log); + (fn log1p(x: f64) -> (f64); => log1p); + (fn log2(x: f64) -> (f64); => log2); + (fn log10(x: f64) -> (f64); => log10); + (fn modf(x: f64) -> (f64, f64); => modf); + (fn nextafter(x: f64, y: f64) -> (f64); => nextafter); + (fn pow(x: f64, y: f64) -> (f64); => pow); + (fn remainder(x: f64, y: f64) -> (f64); => remainder); + (fn remquo(x: f64, y: f64) -> (f64, i32); => remquo); + (fn rint(x: f64) -> (f64); => rint); + (fn round(x: f64) -> (f64); => round); + (fn scalbn(x: f64, n: i32) -> (f64); => scalbn); + (fn sin(x: f64) -> (f64); => sin); + (fn sincos(x: f64) -> (f64, f64); => sincos); + (fn sinh(x: f64) -> (f64); => sinh); + (fn sqrt(x: f64) -> (f64); => sqrt); + (fn tan(x: f64) -> (f64); => tan); + (fn tanh(x: f64) -> (f64); => tanh); + (fn tgamma(x: f64) -> (f64); => tgamma); + (fn trunc(x: f64) -> (f64); => trunc); + (fn y0(x: f64) -> (f64); => y0); + (fn y1(x: f64) -> (f64); => y1); + (fn yn(n: i32, x: f64) -> (f64); => yn) + } +} From 929b5841db27b43934b1322c450327df27144e69 Mon Sep 17 00:00:00 2001 From: "James D. Turner" Date: Fri, 20 Jan 2023 13:39:41 -0500 Subject: [PATCH 1088/4206] Fix descriptions of erfc and erfcf As described in the second paragraph of the docs for these functions, they are the complementary error function, not the error function. --- library/compiler-builtins/libm/src/math/erf.rs | 2 +- library/compiler-builtins/libm/src/math/erff.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/erf.rs b/library/compiler-builtins/libm/src/math/erf.rs index 5e21ba578dfe3..55569affc9753 100644 --- a/library/compiler-builtins/libm/src/math/erf.rs +++ b/library/compiler-builtins/libm/src/math/erf.rs @@ -263,7 +263,7 @@ pub fn erf(x: f64) -> f64 { } } -/// Error function (f64) +/// Complementary error function (f64) /// /// Calculates the complementary probability. /// Is `1 - erf(x)`. Is computed directly, so that you can use it to avoid diff --git a/library/compiler-builtins/libm/src/math/erff.rs b/library/compiler-builtins/libm/src/math/erff.rs index f74d4b632491b..7b25474f6025e 100644 --- a/library/compiler-builtins/libm/src/math/erff.rs +++ b/library/compiler-builtins/libm/src/math/erff.rs @@ -174,7 +174,7 @@ pub fn erff(x: f32) -> f32 { } } -/// Error function (f32) +/// Complementary error function (f32) /// /// Calculates the complementary probability. /// Is `1 - erf(x)`. Is computed directly, so that you can use it to avoid From 8d4e9062066b10bf5914d94b68dfb6a190ea09ae Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 1 Feb 2023 14:52:18 -0800 Subject: [PATCH 1089/4206] Drop the llvm14-builtins-abi hack --- library/compiler-builtins/src/float/conv.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 19fdc2fdc698d..a27d542fae390 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -92,12 +92,12 @@ intrinsics! { f64::from_bits(int_to_float::u64_to_f64_bits(i)) } - #[cfg_attr(any(not(target_feature = "llvm14-builtins-abi"), target_os = "uefi"), unadjusted_on_win64)] + #[cfg_attr(target_os = "uefi", unadjusted_on_win64)] pub extern "C" fn __floatuntisf(i: u128) -> f32 { f32::from_bits(int_to_float::u128_to_f32_bits(i)) } - #[cfg_attr(any(not(target_feature = "llvm14-builtins-abi"), target_os = "uefi"), unadjusted_on_win64)] + #[cfg_attr(target_os = "uefi", unadjusted_on_win64)] pub extern "C" fn __floatuntidf(i: u128) -> f64 { f64::from_bits(int_to_float::u128_to_f64_bits(i)) } @@ -129,13 +129,13 @@ intrinsics! { f64::from_bits(int_to_float::u64_to_f64_bits(i.unsigned_abs()) | sign_bit) } - #[cfg_attr(any(not(target_feature = "llvm14-builtins-abi"), target_os = "uefi"), unadjusted_on_win64)] + #[cfg_attr(target_os = "uefi", unadjusted_on_win64)] pub extern "C" fn __floattisf(i: i128) -> f32 { let sign_bit = ((i >> 127) as u32) << 31; f32::from_bits(int_to_float::u128_to_f32_bits(i.unsigned_abs()) | sign_bit) } - #[cfg_attr(any(not(target_feature = "llvm14-builtins-abi"), target_os = "uefi"), unadjusted_on_win64)] + #[cfg_attr(target_os = "uefi", unadjusted_on_win64)] pub extern "C" fn __floattidf(i: i128) -> f64 { let sign_bit = ((i >> 127) as u64) << 63; f64::from_bits(int_to_float::u128_to_f64_bits(i.unsigned_abs()) | sign_bit) @@ -176,8 +176,7 @@ intrinsics! { } } - #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + #[win64_128bit_abi_hack] pub extern "C" fn __fixunssfti(f: f32) -> u128 { let fbits = f.to_bits(); if fbits < 127 << 23 { // >= 0, < 1 @@ -225,8 +224,7 @@ intrinsics! { } } - #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + #[win64_128bit_abi_hack] pub extern "C" fn __fixunsdfti(f: f64) -> u128 { let fbits = f.to_bits(); if fbits < 1023 << 52 { // >= 0, < 1 @@ -279,8 +277,7 @@ intrinsics! { } } - #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + #[win64_128bit_abi_hack] pub extern "C" fn __fixsfti(f: f32) -> i128 { let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. if fbits < 127 << 23 { // >= 0, < 1 @@ -331,8 +328,7 @@ intrinsics! { } } - #[cfg_attr(target_feature = "llvm14-builtins-abi", win64_128bit_abi_hack)] - #[cfg_attr(not(target_feature = "llvm14-builtins-abi"), unadjusted_on_win64)] + #[win64_128bit_abi_hack] pub extern "C" fn __fixdfti(f: f64) -> i128 { let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. if fbits < 1023 << 52 { // >= 0, < 1 From 2ca64c27984e30f812216908d248c3b28bd9dc63 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 3 Feb 2023 19:21:40 +0100 Subject: [PATCH 1090/4206] Bump to 0.1.87 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index f143c1033f07e..ca0d96aa6af18 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.86" +version = "0.1.87" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 8753da27ae52a7c76ffdbccf1fc681171e6aed9b Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Thu, 16 Feb 2023 18:22:17 +0100 Subject: [PATCH 1091/4206] Small tweak to `mul` in `fma.rs`. --- library/compiler-builtins/libm/src/math/fma.rs | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index f9a86dc60633b..940ee2db927bc 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -29,21 +29,10 @@ fn normalize(x: f64) -> Num { Num { m: ix, e, sign } } +#[inline] fn mul(x: u64, y: u64) -> (u64, u64) { - let t1: u64; - let t2: u64; - let t3: u64; - let xlo: u64 = x as u32 as u64; - let xhi: u64 = x >> 32; - let ylo: u64 = y as u32 as u64; - let yhi: u64 = y >> 32; - - t1 = xlo * ylo; - t2 = xlo * yhi + xhi * ylo; - t3 = xhi * yhi; - let lo = t1.wrapping_add(t2 << 32); - let hi = t3 + (t2 >> 32) + (t1 > lo) as u64; - (hi, lo) + let t = (x as u128).wrapping_mul(y as u128); + ((t >> 64) as u64, t as u64) } /// Floating multiply add (f64) From a11bd1cfdb3642bc137b2e2bda3254c2a6a827f4 Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Tue, 21 Feb 2023 23:13:02 +0100 Subject: [PATCH 1092/4206] Specialize `strlen` for `x86_64`. --- library/compiler-builtins/src/mem/impls.rs | 10 +++++++ library/compiler-builtins/src/mem/mod.rs | 8 +----- library/compiler-builtins/src/mem/x86_64.rs | 29 +++++++++++++++++++++ 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/src/mem/impls.rs index 72003a5c472b2..23c9d8d327536 100644 --- a/library/compiler-builtins/src/mem/impls.rs +++ b/library/compiler-builtins/src/mem/impls.rs @@ -279,3 +279,13 @@ pub unsafe fn compare_bytes(s1: *const u8, s2: *const u8, n: usize) -> i32 { } 0 } + +#[inline(always)] +pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize { + let mut n = 0; + while *s != 0 { + n += 1; + s = s.add(1); + } + n +} diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index c5b0ddc16ec33..be118778b1a46 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -63,13 +63,7 @@ intrinsics! { #[mem_builtin] #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn strlen(s: *const core::ffi::c_char) -> usize { - let mut n = 0; - let mut s = s; - while *s != 0 { - n += 1; - s = s.offset(1); - } - n + impls::c_string_length(s) } } diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 17b461f791426..ea8f6d819de52 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -173,6 +173,35 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { c16(a.cast(), b.cast(), n) } +#[inline(always)] +pub unsafe fn c_string_length(s: *const std::ffi::c_char) -> usize { + let mut n: usize; + + std::arch::asm!( + // search for a zero byte + "xor al, al", + + // unbounded memory region + "xor rcx, rcx", + "not rcx", + + // forward direction + "cld", + + // perform search + "repne scasb", + + // extract length + "not rcx", + "dec rcx", + inout("rdi") s => _, + out("rcx") n, + options(nostack), + ); + + n +} + /// Determine optimal parameters for a `rep` instruction. fn rep_param(dest: *mut u8, mut count: usize) -> (usize, usize, usize) { // Unaligned writes are still slow on modern processors, so align the destination address. From 990596fa283a6f35e27a089f0ebd8d7aad0e1bce Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Tue, 21 Feb 2023 23:32:39 +0100 Subject: [PATCH 1093/4206] Correct path. --- library/compiler-builtins/src/mem/x86_64.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index ea8f6d819de52..13e186e649b47 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -177,7 +177,7 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { pub unsafe fn c_string_length(s: *const std::ffi::c_char) -> usize { let mut n: usize; - std::arch::asm!( + asm!( // search for a zero byte "xor al, al", From 44d34e87fa462edb0b75732212595e3d2933eb45 Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Tue, 21 Feb 2023 23:36:47 +0100 Subject: [PATCH 1094/4206] Update path for argument. --- library/compiler-builtins/src/mem/x86_64.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 13e186e649b47..282074a6cbc44 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -174,7 +174,7 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { } #[inline(always)] -pub unsafe fn c_string_length(s: *const std::ffi::c_char) -> usize { +pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { let mut n: usize; asm!( From b53c1ae17ad396730c12bafdd745b04e2b170ed9 Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Wed, 22 Feb 2023 00:07:41 +0100 Subject: [PATCH 1095/4206] Improve assembly quality + AT&T syntax. --- library/compiler-builtins/src/mem/x86_64.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 282074a6cbc44..fe93ae7aed4e5 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -179,24 +179,25 @@ pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { asm!( // search for a zero byte - "xor al, al", + "xor %eax, %eax", // unbounded memory region - "xor rcx, rcx", - "not rcx", + "xor %ecx, %ecx", + "not %rcx", // forward direction - "cld", + // (already set thanks to abi) + //"cld", // perform search - "repne scasb", + "repne scasb (%rdi), %al", // extract length - "not rcx", - "dec rcx", + "not %rcx", + "dec %rcx", inout("rdi") s => _, out("rcx") n, - options(nostack), + options(att_syntax, nostack), ); n From e9e34801a69f2e29e5f93d5cf2916fb183e130ed Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Wed, 22 Feb 2023 00:10:46 +0100 Subject: [PATCH 1096/4206] Remove superfluous comment. --- library/compiler-builtins/src/mem/x86_64.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index fe93ae7aed4e5..5752005a478f1 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -185,10 +185,6 @@ pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { "xor %ecx, %ecx", "not %rcx", - // forward direction - // (already set thanks to abi) - //"cld", - // perform search "repne scasb (%rdi), %al", From 97402fc580b9fd9858b6c6e5db95b85f2464aeb3 Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Wed, 22 Feb 2023 21:54:33 +0100 Subject: [PATCH 1097/4206] Change implementation to SSE --- library/compiler-builtins/src/mem/x86_64.rs | 77 ++++++++++++++++++--- 1 file changed, 67 insertions(+), 10 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 5752005a478f1..daa92098e6bc6 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -178,21 +178,78 @@ pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { let mut n: usize; asm!( - // search for a zero byte + // For small sizes, we avoid invoking SSE instructions. + // make manual comparisons instead. "xor %eax, %eax", + "cmpb $0, (%rdi)", + "je 3f", + "mov $1, %eax", + "cmpb $0, 1(%rdi)", + "je 3f", + "mov $2, %eax", + "cmpb $0, 2(%rdi)", + "je 3f", + "mov $3, %eax", + "cmpb $0, 3(%rdi)", + "je 3f", - // unbounded memory region - "xor %ecx, %ecx", - "not %rcx", + // Adjust address + "add $4, %rdi", - // perform search - "repne scasb (%rdi), %al", + // Align the address to 16 bytes (xmm register size). + // This is important, since an n byte read + // with n byte alignment is guranteed to never cross + // a page boundary and thus will never try to access + // memory which may not be accessible. + "mov %edi, %ecx", + "and $15, %ecx", + "and $-16, %rdi", - // extract length - "not %rcx", - "dec %rcx", + // zero out an xmm register for comparisons with zero. + "pxor %xmm0, %xmm0", + + // One manual iteration of a zero byte search. + // Ensuring proper alignment may cause us to read + // memory _before_ the actual string start. + // Thus, one separate iteration is needed to handle this special case. + "movdqa (%rdi), %xmm1", + "pcmpeqb %xmm0, %xmm1", + "pmovmskb %xmm1, %eax", + // Shift out comparisons that don't belong to the actual string. + "shr %cl, %eax", + // Check if there was a zero + "test %eax, %eax", + "jz 1f", + + // A zero was found: calculate result and exit. + "bsf %eax, %eax", + "add $4, %eax", + "jmp 3f", + + // No zero was found: prepare main loop. + "1:", + "add $16, %rdi", + "neg %rcx", + "add $4, %rcx", + + // main loop + "2:", + "movdqa (%rdi), %xmm1", + "add $16, %rdi", + "add $16, %rcx", + "pcmpeqb %xmm0, %xmm1", + "pmovmskb %xmm1, %eax", + // Check if there was a zero + "test %eax, %eax", + "jz 2b", + + // A zero was found: calculate result and exit. + "bsf %eax, %eax", + "add %rcx, %rax", + "3:", inout("rdi") s => _, - out("rcx") n, + out("rax") n, + out("rcx") _, options(att_syntax, nostack), ); From 67ebc4ae1480c5d5a1a9be05213e5dc30466f3ab Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Wed, 22 Feb 2023 20:35:06 +0000 Subject: [PATCH 1098/4206] Extend the intrinsics exported for Xtensa no_std --- library/compiler-builtins/src/lib.rs | 1 + library/compiler-builtins/src/math.rs | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 10b4aafec3123..71f249c8eb34f 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -47,6 +47,7 @@ pub mod int; all(target_arch = "x86_64", target_os = "none"), all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "arm", target_os = "none"), + all(target_arch = "xtensa", target_os = "none"), target_os = "xous", all(target_vendor = "fortanix", target_env = "sgx") ))] diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index c64984e9ee7b8..982c9499a2113 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -86,7 +86,11 @@ no_mangle! { fn tanf(n: f32) -> f32; } -#[cfg(any(target_os = "xous", target_os = "uefi"))] +#[cfg(any( + target_os = "xous", + target_os = "uefi", + all(target_arch = "xtensa", target_os = "none"), +))] no_mangle! { fn sqrtf(x: f32) -> f32; fn sqrt(x: f64) -> f64; @@ -94,6 +98,7 @@ no_mangle! { #[cfg(any( all(target_vendor = "fortanix", target_env = "sgx"), + all(target_arch = "xtensa", target_os = "none"), target_os = "xous", target_os = "uefi" ))] From c7404df0694435bba4e1118ee5ca539a780bacbf Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Wed, 22 Feb 2023 22:16:29 +0100 Subject: [PATCH 1099/4206] Provide a non-sse version for x86_64. --- library/compiler-builtins/src/mem/x86_64.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index daa92098e6bc6..e9003310c202a 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -173,6 +173,7 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { c16(a.cast(), b.cast(), n) } +#[cfg(target_feature="sse2")] #[inline(always)] pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { let mut n: usize; @@ -256,6 +257,19 @@ pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { n } +// Provided for scenarios like kernel development, where SSE might not +// be available. +#[cfg(not(target_feature="sse2"))] +#[inline(always)] +pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize { + let mut n = 0; + while *s != 0 { + n += 1; + s = s.add(1); + } + n +} + /// Determine optimal parameters for a `rep` instruction. fn rep_param(dest: *mut u8, mut count: usize) -> (usize, usize, usize) { // Unaligned writes are still slow on modern processors, so align the destination address. From 04fe48216003d3bc92647946a36d7eaa23b5e54f Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Wed, 22 Feb 2023 22:19:10 +0100 Subject: [PATCH 1100/4206] Formatting --- library/compiler-builtins/src/mem/x86_64.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index e9003310c202a..321d592968775 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -173,7 +173,7 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { c16(a.cast(), b.cast(), n) } -#[cfg(target_feature="sse2")] +#[cfg(target_feature = "sse2")] #[inline(always)] pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { let mut n: usize; @@ -259,7 +259,7 @@ pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { // Provided for scenarios like kernel development, where SSE might not // be available. -#[cfg(not(target_feature="sse2"))] +#[cfg(not(target_feature = "sse2"))] #[inline(always)] pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize { let mut n = 0; From 3e59619de7fea763ca81e530b43aab313309ed4e Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 23 Feb 2023 18:19:41 +0000 Subject: [PATCH 1101/4206] Bump to 0.1.88 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index ca0d96aa6af18..8c0f6221c9139 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.87" +version = "0.1.88" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 59fb34e63ae41d3bd93bfe656882f37da7b31a83 Mon Sep 17 00:00:00 2001 From: Andrew Kane Date: Sun, 5 Mar 2023 12:17:21 -0800 Subject: [PATCH 1102/4206] Added lgamma_r and lgammaf_r --- library/compiler-builtins/src/math.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 982c9499a2113..498e4d85ff09e 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -86,6 +86,31 @@ no_mangle! { fn tanf(n: f32) -> f32; } +#[cfg(any( + all( + target_family = "wasm", + target_os = "unknown", + not(target_env = "wasi") + ), + target_os = "xous", + all(target_arch = "x86_64", target_os = "uefi"), + all(target_arch = "xtensa", target_os = "none"), + all(target_vendor = "fortanix", target_env = "sgx") +))] +intrinsics! { + pub extern "C" fn lgamma_r(x: f64, s: &mut i32) -> f64 { + let r = self::libm::lgamma_r(x); + *s = r.1; + r.0 + } + + pub extern "C" fn lgammaf_r(x: f32, s: &mut i32) -> f32 { + let r = self::libm::lgammaf_r(x); + *s = r.1; + r.0 + } +} + #[cfg(any( target_os = "xous", target_os = "uefi", From 215f63ad19405a06266c832f3c246b23a4f60cf1 Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Mon, 6 Mar 2023 19:20:30 +0100 Subject: [PATCH 1103/4206] Final version. --- library/compiler-builtins/src/mem/x86_64.rs | 181 ++++++++++++-------- 1 file changed, 108 insertions(+), 73 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 321d592968775..ad6ff9d172b79 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -173,88 +173,82 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { c16(a.cast(), b.cast(), n) } + +// In order to process more than on byte simultaneously when executing strlen, +// two things must be considered: +// * An n byte read with an n-byte aligned address will never cross +// a page boundary and will always succeed. Any smaller alignment +// may result in a read that will cross a page boundary, which may +// trigger an access violation. +// * Surface Rust considers any kind of out-of-bounds read as undefined +// behaviour. To dodge this, memory access operations are written +// using inline assembly. + #[cfg(target_feature = "sse2")] #[inline(always)] pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { - let mut n: usize; - - asm!( - // For small sizes, we avoid invoking SSE instructions. - // make manual comparisons instead. - "xor %eax, %eax", - "cmpb $0, (%rdi)", - "je 3f", - "mov $1, %eax", - "cmpb $0, 1(%rdi)", - "je 3f", - "mov $2, %eax", - "cmpb $0, 2(%rdi)", - "je 3f", - "mov $3, %eax", - "cmpb $0, 3(%rdi)", - "je 3f", - - // Adjust address - "add $4, %rdi", + use core::arch::x86_64::{__m128i, _mm_cmpeq_epi8, _mm_movemask_epi8, _mm_set1_epi8}; - // Align the address to 16 bytes (xmm register size). - // This is important, since an n byte read - // with n byte alignment is guranteed to never cross - // a page boundary and thus will never try to access - // memory which may not be accessible. - "mov %edi, %ecx", - "and $15, %ecx", - "and $-16, %rdi", + let mut n = 0; + + // The use of _mm_movemask_epi8 and company allow for speedups, + // but they aren't cheap by themselves. Thus, possibly small strings + // are handled in simple loops. - // zero out an xmm register for comparisons with zero. - "pxor %xmm0, %xmm0", + for _ in 0..4 { + if *s == 0 { + return n; + } - // One manual iteration of a zero byte search. - // Ensuring proper alignment may cause us to read - // memory _before_ the actual string start. - // Thus, one separate iteration is needed to handle this special case. - "movdqa (%rdi), %xmm1", - "pcmpeqb %xmm0, %xmm1", - "pmovmskb %xmm1, %eax", - // Shift out comparisons that don't belong to the actual string. - "shr %cl, %eax", - // Check if there was a zero - "test %eax, %eax", - "jz 1f", + n += 1; + s = s.add(1); + } + + // Shave of the least significand bits to align the address to a 16 + // byte boundary. The shaved of bits are used to correct the first iteration. - // A zero was found: calculate result and exit. - "bsf %eax, %eax", - "add $4, %eax", - "jmp 3f", + let align = s as usize & 15; + let mut s = ((s as usize) - align) as *const __m128i; + let zero = _mm_set1_epi8(0); - // No zero was found: prepare main loop. - "1:", - "add $16, %rdi", - "neg %rcx", - "add $4, %rcx", + let x = { + let r; + asm!( + "movdqa ({addr}), {dest}", + addr = in(reg) s, + dest = out(xmm_reg) r, + options(att_syntax, nostack), + ); + r + }; + let cmp = _mm_movemask_epi8(_mm_cmpeq_epi8(x, zero)) >> align; - // main loop - "2:", - "movdqa (%rdi), %xmm1", - "add $16, %rdi", - "add $16, %rcx", - "pcmpeqb %xmm0, %xmm1", - "pmovmskb %xmm1, %eax", - // Check if there was a zero - "test %eax, %eax", - "jz 2b", + if cmp != 0 { + return n + cmp.trailing_zeros() as usize; + } - // A zero was found: calculate result and exit. - "bsf %eax, %eax", - "add %rcx, %rax", - "3:", - inout("rdi") s => _, - out("rax") n, - out("rcx") _, - options(att_syntax, nostack), - ); + n += 16 - align; + s = s.add(1); - n + loop { + let x = { + let r; + asm!( + "movdqa ({addr}), {dest}", + addr = in(reg) s, + dest = out(xmm_reg) r, + options(att_syntax, nostack), + ); + r + }; + let cmp = _mm_movemask_epi8(_mm_cmpeq_epi8(x, zero)) as u32; + if cmp == 0 { + n += 16; + s = s.add(1); + } else { + return n + cmp.trailing_zeros() as usize; + } + } } // Provided for scenarios like kernel development, where SSE might not @@ -263,11 +257,52 @@ pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { #[inline(always)] pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize { let mut n = 0; - while *s != 0 { + + // Check bytes in steps of one until + // either a zero byte is discovered or + // pointer is aligned to an eight byte boundary. + + while s as usize & 7 != 0 { + if *s == 0 { + return n; + } + n += 1; s = s.add(1); } - n + + // Check bytes in steps of eight until a zero + // byte is discovered. + + let mut s = s as *const u64; + + loop { + let mut cs = { + let r: u64; + asm!( + "mov ({addr}), {dest}", + addr = in(reg) s, + dest = out(reg) r, + options(att_syntax, nostack), + ); + r + }; + // Detect if a word has a zero byte, taken from + // https://graphics.stanford.edu/~seander/bithacks.html + if (cs.wrapping_sub(0x0101010101010101) & !cs & 0x8080808080808080) != 0 { + loop { + if cs & 255 == 0 { + return n; + } else { + cs >>= 8; + n += 1; + } + } + } else { + n += 8; + s = s.add(1); + } + } } /// Determine optimal parameters for a `rep` instruction. From 73fa0deaa62f240b782523cfb5f45aa8e2f09791 Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Mon, 6 Mar 2023 19:24:02 +0100 Subject: [PATCH 1104/4206] formatting --- library/compiler-builtins/src/mem/x86_64.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index ad6ff9d172b79..5377f04236f0f 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -173,7 +173,6 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { c16(a.cast(), b.cast(), n) } - // In order to process more than on byte simultaneously when executing strlen, // two things must be considered: // * An n byte read with an n-byte aligned address will never cross @@ -190,7 +189,7 @@ pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { use core::arch::x86_64::{__m128i, _mm_cmpeq_epi8, _mm_movemask_epi8, _mm_set1_epi8}; let mut n = 0; - + // The use of _mm_movemask_epi8 and company allow for speedups, // but they aren't cheap by themselves. Thus, possibly small strings // are handled in simple loops. @@ -266,11 +265,10 @@ pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize { if *s == 0 { return n; } - n += 1; s = s.add(1); } - + // Check bytes in steps of eight until a zero // byte is discovered. From 59766673e76d056123933834ea89cb640a650bd1 Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Mon, 6 Mar 2023 19:28:49 +0100 Subject: [PATCH 1105/4206] more fixing --- library/compiler-builtins/src/mem/x86_64.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/src/mem/x86_64.rs index 5377f04236f0f..40b67093f51d5 100644 --- a/library/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/src/mem/x86_64.rs @@ -185,7 +185,7 @@ pub unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { #[cfg(target_feature = "sse2")] #[inline(always)] -pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { +pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize { use core::arch::x86_64::{__m128i, _mm_cmpeq_epi8, _mm_movemask_epi8, _mm_set1_epi8}; let mut n = 0; @@ -202,7 +202,7 @@ pub unsafe fn c_string_length(s: *const core::ffi::c_char) -> usize { n += 1; s = s.add(1); } - + // Shave of the least significand bits to align the address to a 16 // byte boundary. The shaved of bits are used to correct the first iteration. From 20fb963ab68e086d38a51f419ed41c83dfa39333 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 10 Mar 2023 19:59:23 +0000 Subject: [PATCH 1106/4206] Add emutls.c for OpenHarmony --- library/compiler-builtins/build.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 3f5dbd3ab2748..766dec05d9b3c 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -508,6 +508,11 @@ mod c { cfg.define("LONG_BIT", "(8 * sizeof(long))"); } + // OpenHarmony also uses emulated TLS. + if target_env == "ohos" { + sources.extend(&[("__emutls_get_address", "emutls.c")]); + } + // When compiling the C code we require the user to tell us where the // source code is, and this is largely done so when we're compiling as // part of rust-lang/rust we can use the same llvm-project repository as From 2f43b936033c5c83cc7c7bafe75c27e95e3f00f9 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Thu, 23 Mar 2023 22:00:22 +0900 Subject: [PATCH 1107/4206] Fix panic due to overflow in riscv.rs and int/shift.rs --- library/compiler-builtins/src/int/shift.rs | 6 +++--- library/compiler-builtins/src/riscv.rs | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 2d2c081a680c9..080de2a14eb49 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -12,7 +12,7 @@ trait Ashl: DInt { } else { Self::from_lo_hi( self.lo().wrapping_shl(shl), - self.lo().logical_shr(n_h - shl) | self.hi().wrapping_shl(shl), + self.lo().logical_shr(n_h.wrapping_sub(shl)) | self.hi().wrapping_shl(shl), ) } } @@ -36,7 +36,7 @@ trait Ashr: DInt { self } else { Self::from_lo_hi( - self.lo().logical_shr(shr) | self.hi().wrapping_shl(n_h - shr), + self.lo().logical_shr(shr) | self.hi().wrapping_shl(n_h.wrapping_sub(shr)), self.hi().wrapping_shr(shr), ) } @@ -57,7 +57,7 @@ trait Lshr: DInt { self } else { Self::from_lo_hi( - self.lo().logical_shr(shr) | self.hi().wrapping_shl(n_h - shr), + self.lo().logical_shr(shr) | self.hi().wrapping_shl(n_h.wrapping_sub(shr)), self.hi().logical_shr(shr), ) } diff --git a/library/compiler-builtins/src/riscv.rs b/library/compiler-builtins/src/riscv.rs index ae361b33acfb8..bf31255334193 100644 --- a/library/compiler-builtins/src/riscv.rs +++ b/library/compiler-builtins/src/riscv.rs @@ -19,11 +19,11 @@ intrinsics! { // 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 = 0; + let mut r: u32 = 0; while a > 0 { if a & 1 > 0 { - r += b; + r = r.wrapping_add(b); } a >>= 1; b <<= 1; @@ -35,11 +35,11 @@ intrinsics! { #[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 = 0; + let mut r: u64 = 0; while a > 0 { if a & 1 > 0 { - r += b; + r = r.wrapping_add(b); } a >>= 1; b <<= 1; From 26e2432c25dbed8712456ce5eb78b37004e3633b Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 25 Mar 2023 21:55:23 +0000 Subject: [PATCH 1108/4206] Bump to 0.1.90 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 8c0f6221c9139..2c1d03ba61ec4 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.88" +version = "0.1.90" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 7db8c0581d8e72d6561880f9906bd3837faa1689 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 29 Mar 2023 21:49:08 +0100 Subject: [PATCH 1109/4206] Disable another test on powerpc --- .../compiler-builtins/testcrate/tests/conv.rs | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 8c4b1946ce4db..2a70db17890b7 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -23,18 +23,23 @@ macro_rules! i_to_f { || ((error_minus == error || error_plus == error) && ((f0.to_bits() & 1) != 0)) { - panic!( - "incorrect rounding by {}({}): {}, ({}, {}, {}), errors ({}, {}, {})", - stringify!($fn), - x, - f1.to_bits(), - y_minus_ulp, - y, - y_plus_ulp, - error_minus, - error, - error_plus, - ); + if !cfg!(any( + target_arch = "powerpc", + target_arch = "powerpc64" + )) { + panic!( + "incorrect rounding by {}({}): {}, ({}, {}, {}), errors ({}, {}, {})", + stringify!($fn), + x, + f1.to_bits(), + y_minus_ulp, + y, + y_plus_ulp, + error_minus, + error, + error_plus, + ); + } } // Test against native conversion. We disable testing on all `x86` because of // rounding bugs with `i686`. `powerpc` also has the same rounding bug. From 5246405d61ca3d70e0e7409846cea18ef6c18ece Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sun, 26 Mar 2023 00:00:58 -0400 Subject: [PATCH 1110/4206] Ensure shift instrinsic arguments match width of compiler-rt's (int vs si_int). --- library/compiler-builtins/src/int/shift.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index 080de2a14eb49..c90cf1de3205e 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -78,8 +78,8 @@ intrinsics! { #[avr_skip] #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_llsl] - pub extern "C" fn __ashldi3(a: u64, b: u32) -> u64 { - a.ashl(b) + pub extern "C" fn __ashldi3(a: u64, b: core::ffi::c_uint) -> u64 { + a.ashl(b as u32) } #[avr_skip] @@ -96,8 +96,8 @@ intrinsics! { #[avr_skip] #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_lasr] - pub extern "C" fn __ashrdi3(a: i64, b: u32) -> i64 { - a.ashr(b) + pub extern "C" fn __ashrdi3(a: i64, b: core::ffi::c_uint) -> i64 { + a.ashr(b as u32) } #[avr_skip] @@ -114,8 +114,8 @@ intrinsics! { #[avr_skip] #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_llsr] - pub extern "C" fn __lshrdi3(a: u64, b: u32) -> u64 { - a.lshr(b) + pub extern "C" fn __lshrdi3(a: u64, b: core::ffi::c_uint) -> u64 { + a.lshr(b as u32) } #[avr_skip] From 7749ed65809779b193978797f4c453017d9e7bed Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 29 Mar 2023 23:55:20 +0100 Subject: [PATCH 1111/4206] Bump to 0.1.91 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 2c1d03ba61ec4..9b9812836b44e 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.90" +version = "0.1.91" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From eac491efc3e3862bf2453c6f4cb633b414d6a2f2 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sat, 13 May 2023 15:16:59 +0900 Subject: [PATCH 1112/4206] Prepare 0.2.7 release Signed-off-by: Yuki Okushi --- library/compiler-builtins/libm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index f942fdec3c922..393d95e4af266 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/libm" -version = "0.2.6" +version = "0.2.7" edition = "2018" [features] From fb77604e79c307900366e90b2de17bf8e2ccea1c Mon Sep 17 00:00:00 2001 From: danakj Date: Fri, 19 May 2023 15:47:57 -0400 Subject: [PATCH 1113/4206] Add the weak-intrinsics feature When enabled, the weak-intrinsics feature will cause all intrinsics functions to be marked with weak linkage (i.e. `#[linkage = "weak"]) so that they can be replaced at link time by a stronger symbol. This can be set to use C++ intrinsics from the compiler-rt library, as it will avoid Rust's implementation replacing the compiler-rt implementation as long as the compiler-rt symbols are linked as strong symbols. Typically this requires the compiler-rt library to be explicitly specified in the link command. Addresses https://github.com/rust-lang/compiler-builtins/issues/525. Without weak-intrinsics, from nm: ``` 00000000 W __aeabi_memclr8 // Is explicitly weak 00000000 T __udivsi3 // Is not. ``` With weak-intrinsics, from nm: ``` 00000000 W __aeabi_memclr8 // Is explicitly weak 00000000 W __udivsi3 // Is weak due to weak-intrinsics ``` --- library/compiler-builtins/Cargo.toml | 11 +++ library/compiler-builtins/src/arm.rs | 32 +++---- library/compiler-builtins/src/macros.rs | 110 ++++++++++++++++++++++- library/compiler-builtins/src/mem/mod.rs | 12 +-- 4 files changed, 141 insertions(+), 24 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 9b9812836b44e..57b8b34c75d51 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -65,6 +65,17 @@ rustc-dep-of-std = ['compiler-builtins', 'core'] # are not normally public but are required by the `testcrate` public-test-deps = [] +# Marks all intrinsics functions with weak linkage so that they can be +# replaced at link time by another implementation. This is particularly useful +# for mixed Rust/C++ binaries that want to use the C++ intrinsics, otherwise +# linking against the Rust stdlib will replace those from the compiler-rt +# library. +# +# Unlike the "c" feature, the intrinsics are still provided by the Rust +# implementations and each will be used unless a stronger symbol replaces +# it during linking. +weak-intrinsics = [] + [[example]] name = "intrinsics" required-features = ["compiler-builtins"] diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index e517a9ef34b8d..a062a54e008bc 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -20,9 +20,9 @@ macro_rules! bl { intrinsics! { // NOTE This function and the ones below are implemented using assembly because they are using a // custom calling convention which can't be implemented using a normal Rust function. + #[cfg_attr(all(not(windows), not(target_vendor="apple")), weak)] #[naked] #[cfg(not(target_env = "msvc"))] - #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] pub unsafe extern "C" fn __aeabi_uidivmod() { core::arch::asm!( "push {{lr}}", @@ -36,8 +36,8 @@ intrinsics! { ); } + #[cfg_attr(all(not(windows), not(target_vendor="apple")), weak)] #[naked] - #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] pub unsafe extern "C" fn __aeabi_uldivmod() { core::arch::asm!( "push {{r4, lr}}", @@ -53,8 +53,8 @@ intrinsics! { ); } + #[cfg_attr(all(not(windows), not(target_vendor="apple")), weak)] #[naked] - #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] pub unsafe extern "C" fn __aeabi_idivmod() { core::arch::asm!( "push {{r0, r1, r4, lr}}", @@ -67,8 +67,8 @@ intrinsics! { ); } + #[cfg_attr(all(not(windows), not(target_vendor="apple")), weak)] #[naked] - #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] pub unsafe extern "C" fn __aeabi_ldivmod() { core::arch::asm!( "push {{r4, lr}}", @@ -88,14 +88,14 @@ intrinsics! { // with custom implementation. // FIXME: The `*4` and `*8` variants should be defined as aliases. + #[weak] #[cfg(not(target_os = "ios"))] - #[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { ::mem::memcpy(dest, src, n); } + #[weak] #[cfg(not(target_os = "ios"))] - #[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { // We are guaranteed 4-alignment, so accessing at u32 is okay. let mut dest = dest as *mut u32; @@ -112,39 +112,39 @@ intrinsics! { __aeabi_memcpy(dest as *mut u8, src as *const u8, n); } + #[weak] #[cfg(not(target_os = "ios"))] - #[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memcpy4(dest, src, n); } + #[weak] #[cfg(not(target_os = "ios"))] - #[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { ::mem::memmove(dest, src, n); } + #[weak] #[cfg(not(any(target_os = "ios", target_env = "msvc")))] - #[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memmove(dest, src, n); } + #[weak] #[cfg(not(any(target_os = "ios", target_env = "msvc")))] - #[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memmove(dest, src, n); } + #[weak] #[cfg(not(target_os = "ios"))] - #[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { // Note the different argument order ::mem::memset(dest, c, n); } + #[weak] #[cfg(not(target_os = "ios"))] - #[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { let mut dest = dest as *mut u32; let mut n = n; @@ -161,26 +161,26 @@ intrinsics! { __aeabi_memset(dest as *mut u8, n, byte as i32); } + #[weak] #[cfg(not(target_os = "ios"))] - #[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { __aeabi_memset4(dest, n, c); } + #[weak] #[cfg(not(target_os = "ios"))] - #[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { __aeabi_memset(dest, n, 0); } + #[weak] #[cfg(not(any(target_os = "ios", target_env = "msvc")))] - #[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); } + #[weak] #[cfg(not(any(target_os = "ios", target_env = "msvc")))] - #[linkage = "weak"] pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); } diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 477c256843198..59f25317e6624 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -25,6 +25,12 @@ macro_rules! public_test_dep { /// platforms need and elsewhere in this library it just looks like normal Rust /// code. /// +/// When the weak-intrinsics feature is enabled, all intrinsics functions are +/// marked with #[linkage = "weak"] so that they can be replaced by another +/// implementation at link time. This is particularly useful for mixed Rust/C++ +/// binaries that want to use the C++ intrinsics, otherwise linking against the +/// Rust stdlib will replace those from the compiler-rt library. +/// /// This macro is structured to be invoked with a bunch of functions that looks /// like: /// @@ -46,6 +52,10 @@ macro_rules! public_test_dep { /// /// A quick overview of attributes supported right now are: /// +/// * `weak` - indicates that the function should always be given weak linkage. +/// This attribute must come before other attributes, as the other attributes +/// will generate the final output function and need to have `weak` modify +/// them. /// * `maybe_use_optimized_c_shim` - indicates that the Rust implementation is /// ignored if an optimized C version was compiled. /// * `aapcs_on_arm` - forces the ABI of the function to be `"aapcs"` on ARM and @@ -57,7 +67,6 @@ macro_rules! public_test_dep { /// it's a normal ABI elsewhere for returning a 128 bit integer. /// * `arm_aeabi_alias` - handles the "aliasing" of various intrinsics on ARM /// their otherwise typical names to other prefixed ones. -/// macro_rules! intrinsics { () => (); @@ -89,6 +98,95 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); + // Same as above but for unsafe. + ( + #[cfg_attr($e:meta, $($attr:tt)*)] + $(#[$($attrs:tt)*])* + pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + $($rest:tt)* + ) => ( + #[cfg($e)] + intrinsics! { + #[$($attr)*] + $(#[$($attrs)*])* + pub unsafe extern $abi fn $name($($argname: $ty),*) $(-> $ret)? { + $($body)* + } + } + + #[cfg(not($e))] + intrinsics! { + $(#[$($attrs)*])* + pub unsafe extern $abi fn $name($($argname: $ty),*) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + + // Explicit weak linkage gets dropped when weak-intrinsics is on since it + // will be added unconditionally to all intrinsics and would conflict + // otherwise. + ( + #[weak] + $(#[$($attr:tt)*])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(feature = "weak-intrinsics")] + intrinsics! { + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + #[cfg(not(feature = "weak-intrinsics"))] + intrinsics! { + $(#[$($attr)*])* + #[linkage = "weak"] + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + // Same as above but for unsafe. + ( + #[weak] + $(#[$($attr:tt)*])* + pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(feature = "weak-intrinsics")] + intrinsics! { + $(#[$($attr)*])* + pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + #[cfg(not(feature = "weak-intrinsics"))] + intrinsics! { + $(#[$($attr)*])* + #[linkage = "weak"] + pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); // Right now there's a bunch of architecture-optimized intrinsics in the // stock compiler-rt implementation. Not all of these have been ported over @@ -112,6 +210,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( #[cfg($name = "optimized-c")] + #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { extern $abi { fn $name($($argname: $ty),*) $(-> $ret)?; @@ -211,6 +310,7 @@ macro_rules! intrinsics { ) => ( #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64"))] $(#[$($attr)*])* + #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } @@ -218,6 +318,7 @@ macro_rules! intrinsics { #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64"))] pub mod $name { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] pub extern $abi fn $name( $($argname: $ty),* ) -> ::macros::win64_128bit_abi_hack::U64x2 { @@ -258,6 +359,7 @@ macro_rules! intrinsics { #[cfg(target_arch = "arm")] pub mod $name { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } @@ -266,7 +368,7 @@ macro_rules! intrinsics { #[cfg(target_arch = "arm")] pub mod $alias { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] + #[cfg_attr(any(all(not(windows), not(target_vendor="apple"), feature = "weak-intrinsics")), linkage = "weak")] pub extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } @@ -302,6 +404,7 @@ macro_rules! intrinsics { pub mod $name { $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } @@ -325,6 +428,7 @@ macro_rules! intrinsics { #[naked] $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } @@ -391,6 +495,7 @@ macro_rules! intrinsics { pub mod $name { $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } @@ -416,6 +521,7 @@ macro_rules! intrinsics { pub mod $name { $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index be118778b1a46..ccf191779f49a 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -20,15 +20,15 @@ use core::ops::{BitOr, Shl}; mod impls; intrinsics! { + #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), weak)] #[mem_builtin] - #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { impls::copy_forward(dest, src, n); dest } + #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), weak)] #[mem_builtin] - #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { let delta = (dest as usize).wrapping_sub(src as usize); if delta >= n { @@ -41,27 +41,27 @@ intrinsics! { dest } + #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), weak)] #[mem_builtin] - #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn memset(s: *mut u8, c: crate::mem::c_int, n: usize) -> *mut u8 { impls::set_bytes(s, c as u8, n); s } + #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), weak)] #[mem_builtin] - #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { impls::compare_bytes(s1, s2, n) } + #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), weak)] #[mem_builtin] - #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { memcmp(s1, s2, n) } + #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), weak)] #[mem_builtin] - #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), linkage = "weak")] pub unsafe extern "C" fn strlen(s: *const core::ffi::c_char) -> usize { impls::c_string_length(s) } From 2eb4f692bc0b3e375cd16edea7b75c3abfd02cff Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 20 May 2023 10:49:41 +0200 Subject: [PATCH 1114/4206] Upgrade libm to 0.2.7 --- library/compiler-builtins/libm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 4c8a973741c01..1dbb9d2d476d6 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 4c8a973741c014b11ce7f1477693a3e5d4ef9609 +Subproject commit 1dbb9d2d476d65d020feca17b11391652038e2e1 From 92d88fd7a4a556cb438fe583215061dc1dfded4d Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 20 May 2023 10:50:12 +0200 Subject: [PATCH 1115/4206] Bump to 0.1.92 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 57b8b34c75d51..0f30668cc6fde 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.91" +version = "0.1.92" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 73f57893aa93547d247efce0b7b513d837df2111 Mon Sep 17 00:00:00 2001 From: Patryk Wychowaniec Date: Mon, 12 Jun 2023 14:04:10 +0200 Subject: [PATCH 1116/4206] fix: Add `#[avr_skip]` for floats Same story as always, i.e. ABI mismatch: - https://github.com/rust-lang/compiler-builtins/pull/462 - https://github.com/rust-lang/compiler-builtins/pull/466 - https://github.com/rust-lang/compiler-builtins/pull/513 I've made sure the changes work by rendering a Mandelbrot fractal: ```rust #[arduino_hal::entry] fn main() -> ! { let dp = arduino_hal::Peripherals::take().unwrap(); let pins = arduino_hal::pins!(dp); let mut serial = arduino_hal::default_serial!(dp, pins, 57600); mandelbrot(&mut serial, 60, 40, -2.05, -1.12, 0.47, 1.12, 100); loop { // } } fn mandelbrot( output: &mut T, viewport_width: i64, viewport_height: i64, x1: f32, y1: f32, x2: f32, y2: f32, max_iterations: i64, ) where T: uWrite, { for viewport_y in 0..viewport_height { let y0 = y1 + (y2 - y1) * ((viewport_y as f32) / (viewport_height as f32)); for viewport_x in 0..viewport_width { let x0 = x1 + (x2 - x1) * ((viewport_x as f32) / (viewport_width as f32)); let mut x = 0.0; let mut y = 0.0; let mut iterations = max_iterations; while x * x + y * y <= 4.0 && iterations > 0 { let xtemp = x * x - y * y + x0; y = 2.0 * x * y + y0; x = xtemp; iterations -= 1; } let ch = "#%=-:,. " .chars() .nth((8.0 * ((iterations as f32) / (max_iterations as f32))) as _) .unwrap(); _ = ufmt::uwrite!(output, "{}", ch); } _ = ufmt::uwriteln!(output, ""); } } ``` ... where without avr_skips, the code printed an image full of only `#`. Note that because libgcc doesn't provide implementations for f64, using those (e.g. swapping f32 to f64 in the code above) will cause linking to fail: ``` undefined reference to `__divdf3' undefined reference to `__muldf3' undefined reference to `__gedf2' undefined reference to `__fixunsdfsi' undefined reference to `__gtdf2' ``` Ideally compiler-builtins could jump right in and provide those, but f64 also require a special calling convention which hasn't been yet exposed through LLVM. Note that because using 64-bit floats on an 8-bit target is a pretty niche thing to do, and because f64 floats don't work correctly anyway at the moment (due to this ABI mismatch), we're not actually breaking anything by skipping those functions, since any code that currently uses f64 on AVR works by accident. Closes https://github.com/rust-lang/rust/issues/108489. --- library/compiler-builtins/src/float/cmp.rs | 14 ++++++++++++++ library/compiler-builtins/src/macros.rs | 11 +++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 1d4e384335bd7..1bd7aa284d872 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -99,60 +99,74 @@ fn unord(a: F, b: F) -> bool { } intrinsics! { + #[avr_skip] pub extern "C" fn __lesf2(a: f32, b: f32) -> i32 { cmp(a, b).to_le_abi() } + #[avr_skip] pub extern "C" fn __gesf2(a: f32, b: f32) -> i32 { cmp(a, b).to_ge_abi() } + #[avr_skip] #[arm_aeabi_alias = __aeabi_fcmpun] pub extern "C" fn __unordsf2(a: f32, b: f32) -> i32 { unord(a, b) as i32 } + #[avr_skip] pub extern "C" fn __eqsf2(a: f32, b: f32) -> i32 { cmp(a, b).to_le_abi() } + #[avr_skip] pub extern "C" fn __ltsf2(a: f32, b: f32) -> i32 { cmp(a, b).to_le_abi() } + #[avr_skip] pub extern "C" fn __nesf2(a: f32, b: f32) -> i32 { cmp(a, b).to_le_abi() } + #[avr_skip] pub extern "C" fn __gtsf2(a: f32, b: f32) -> i32 { cmp(a, b).to_ge_abi() } + #[avr_skip] pub extern "C" fn __ledf2(a: f64, b: f64) -> i32 { cmp(a, b).to_le_abi() } + #[avr_skip] pub extern "C" fn __gedf2(a: f64, b: f64) -> i32 { cmp(a, b).to_ge_abi() } + #[avr_skip] #[arm_aeabi_alias = __aeabi_dcmpun] pub extern "C" fn __unorddf2(a: f64, b: f64) -> i32 { unord(a, b) as i32 } + #[avr_skip] pub extern "C" fn __eqdf2(a: f64, b: f64) -> i32 { cmp(a, b).to_le_abi() } + #[avr_skip] pub extern "C" fn __ltdf2(a: f64, b: f64) -> i32 { cmp(a, b).to_le_abi() } + #[avr_skip] pub extern "C" fn __nedf2(a: f64, b: f64) -> i32 { cmp(a, b).to_le_abi() } + #[avr_skip] pub extern "C" fn __gtdf2(a: f64, b: f64) -> i32 { cmp(a, b).to_ge_abi() } diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 59f25317e6624..f1e2c533a3f40 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -437,12 +437,11 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); - // For division and modulo, AVR uses a custom calling convention¹ that does - // not match our definitions here. Ideally we would just use hand-written - // naked functions, but that's quite a lot of code to port² - so for the - // time being we are just ignoring the problematic functions, letting - // avr-gcc (which is required to compile to AVR anyway) link them from - // libgcc. + // For some intrinsics, AVR uses a custom calling convention¹ that does not + // match our definitions here. Ideally we would just use hand-written naked + // functions, but that's quite a lot of code to port² - so for the time + // being we are just ignoring the problematic functions, letting avr-gcc + // (which is required to compile to AVR anyway) link them from libgcc. // // ¹ https://gcc.gnu.org/wiki/avr-gcc (see "Exceptions to the Calling // Convention") From 2eeedaf25aea1a466231d7f625a55b578683b920 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 12 Jun 2023 15:37:22 +0100 Subject: [PATCH 1117/4206] Bump to 0.1.93 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 0f30668cc6fde..6cfa2b99e38b3 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.92" +version = "0.1.93" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From d3951c082ef5265c39ec5718ad54da0db9356962 Mon Sep 17 00:00:00 2001 From: kirk Date: Sat, 17 Jun 2023 14:07:45 +0000 Subject: [PATCH 1118/4206] allow stable features lint, fix link formatting warning, add ignore block to intrinsics macro documentation --- library/compiler-builtins/examples/intrinsics.rs | 1 + library/compiler-builtins/src/float/conv.rs | 2 +- library/compiler-builtins/src/macros.rs | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 0ca30c215b331..19bb569b57dc4 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -4,6 +4,7 @@ // to link due to the missing intrinsic (symbol). #![allow(unused_features)] +#![allow(stable_features)] // bench_black_box feature is stable, leaving for backcompat #![cfg_attr(thumb, no_main)] #![deny(dead_code)] #![feature(bench_black_box)] diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index a27d542fae390..790c0ab9f351f 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -3,7 +3,7 @@ /// These are hand-optimized bit twiddling code, /// which unfortunately isn't the easiest kind of code to read. /// -/// The algorithm is explained here: https://blog.m-ou.se/floats/ +/// The algorithm is explained here: mod int_to_float { pub fn u32_to_f32_bits(i: u32) -> u32 { if i == 0 { diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index f1e2c533a3f40..b3becde7230cf 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -33,7 +33,7 @@ macro_rules! public_test_dep { /// /// This macro is structured to be invoked with a bunch of functions that looks /// like: -/// +/// ```ignore /// intrinsics! { /// pub extern "C" fn foo(a: i32) -> u32 { /// // ... @@ -44,6 +44,7 @@ macro_rules! public_test_dep { /// // ... /// } /// } +/// ``` /// /// Each function is defined in a manner that looks like a normal Rust function. /// The macro then accepts a few nonstandard attributes that can decorate From fad0b3a4316f5cb954af4513dd42f2e80b087ef4 Mon Sep 17 00:00:00 2001 From: kirk Date: Sat, 17 Jun 2023 14:35:00 +0000 Subject: [PATCH 1119/4206] change links in README to match reference code version used in CI --- library/compiler-builtins/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 8b25558a87e8e..da0adbce70c65 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -59,8 +59,8 @@ features = ["c"] 5. Once the PR passes our extensive [testing infrastructure][4], we'll merge it! 6. Celebrate :tada: -[1]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/test/builtins/Unit -[2]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/lib/builtins +[1]: https://github.com/rust-lang/llvm-project/tree/9e3de9490ff580cd484fbfa2908292b4838d56e7/compiler-rt/test/builtins/Unit +[2]: https://github.com/rust-lang/llvm-project/tree/9e3de9490ff580cd484fbfa2908292b4838d56e7/compiler-rt/lib/builtins [3]: https://github.com/rust-lang/compiler-builtins/blob/0ba07e49264a54cb5bbd4856fcea083bb3fbec15/build.rs#L180-L265 [4]: https://travis-ci.org/rust-lang/compiler-builtins From 21c821c6c973bbdffe558ede2dd7c483735b9f3f Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 25 Jun 2023 21:07:00 +0000 Subject: [PATCH 1120/4206] Port outline-atomics to rust This has a very long history, summarized in https://github.com/rust-lang/rust/issues/109064. This port is a very minimal subset of `aarch64/lse.S` from LLVM's compiler-rt. In particular, it is missing the following: 1. Any form of runtime dispatch between LL/SC and LSE. Determining which version of the intrinsics to use requires one of the following: i) `getauxval` from glibc. It's unclear whether `compiler_builtins` is allowed to depend on libc at all, and musl doesn't even support getauxval. Don't enshrine the requirement "de-facto" by making it required for outline-atomics. ii) kernel support. Linux and FreeBSD have limited support, but it requires an extremely recent kernel version and doesn't work at all under QEMU (https://github.com/rust-lang/rust/issues/109064#issuecomment-1494939904). Instead, we hard-code LL/SC intrinsics. Users who want LSE support should use the LLVM compiler-rt (if you're building from source in rust-lang/rust, make sure you have `src/llvm-project` checked out locally. the goal is to soon add a new `optimized-compiler-builtins` option so this is easier to discover). 2. The global `___aarch64_have_lse_atomics` CTOR, required to do runtime dispatch. Thom Chiviolani has this to say about global CTORs: > static ctors are problems because we are pretty eager about dead code elim > in general if you have a module that isnt directly reference we will probably not have its static ctors > also, while llvm has a super robust way to have a static ctor (theres s special "appending global" to use for c++), we dont use that and just have people make a #[used] static in a special section > 1. the robust way kinda requires rust knowing that the argument is a static ctor (maybe a #[rustc_static_ctor] attribute). it also would be... finnicky, since on windows we actually care beyond being a static ctor, that we run as part in a specific group of ctors, which means a very specific section (one for TLS and the other for, uh, i dont remember) > 2. we still actually have to codegen the cgu that isn't referenced. but maybe we could remember that it has that attribute and use that So while this is possible in theory, it's decidedly non-trivial, and needs invasive changes to rust itself. In any case, it doesn't matter until we decide the story around libc. 3. The 16-byte (i128) version of compare_and_swap. This wouldn't be *too* hard to add, but it would be hard to test. The way I tested the existing code was not just with unit tests but also by loading it as a path dependency and running `x test core` - the latter caught several bugs the unit tests didn't catch (because I originally wrote the tests wrong). So I am slightly nervous about adding a 16-byte version that is much more poorly tested than the other intrinsics. --- library/compiler-builtins/build.rs | 57 ++++- library/compiler-builtins/src/aarch64.rs | 221 ++++++++++++++++++ library/compiler-builtins/src/lib.rs | 3 + library/compiler-builtins/src/macros.rs | 2 +- .../compiler-builtins/testcrate/tests/lse.rs | 88 +++++++ 5 files changed, 369 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/src/aarch64.rs create mode 100644 library/compiler-builtins/testcrate/tests/lse.rs diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 766dec05d9b3c..266cc28bb2fe6 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1,4 +1,4 @@ -use std::env; +use std::{collections::HashMap, env, sync::atomic::Ordering}; fn main() { println!("cargo:rerun-if-changed=build.rs"); @@ -90,6 +90,61 @@ fn main() { { println!("cargo:rustc-cfg=kernel_user_helpers") } + + if llvm_target[0] == "aarch64" { + generate_aarch64_outlined_atomics(); + } +} + +fn aarch64_symbol(ordering: Ordering) -> &'static str { + match ordering { + Ordering::Relaxed => "relax", + Ordering::Acquire => "acq", + Ordering::Release => "rel", + Ordering::AcqRel => "acq_rel", + _ => panic!("unknown symbol for {:?}", ordering), + } +} + +/// The `concat_idents` macro is extremely annoying and doesn't allow us to define new items. +/// Define them from the build script instead. +/// Note that the majority of the code is still defined in `aarch64.rs` through inline macros. +fn generate_aarch64_outlined_atomics() { + use std::fmt::Write; + // #[macro_export] so that we can use this in tests + let gen_macro = + |name| format!("#[macro_export] macro_rules! foreach_{name} {{ ($macro:path) => {{\n"); + + // Generate different macros for add/clr/eor/set so that we can test them separately. + let sym_names = ["cas", "ldadd", "ldclr", "ldeor", "ldset", "swp"]; + let mut macros = HashMap::new(); + for sym in sym_names { + macros.insert(sym, gen_macro(sym)); + } + + for ordering in [ + Ordering::Relaxed, + Ordering::Acquire, + Ordering::Release, + Ordering::AcqRel, + ] { + let sym_ordering = aarch64_symbol(ordering); + // TODO: support CAS 16 + for size in [1, 2, 4, 8 /* , 16*/] { + for (sym, macro_) in &mut macros { + let name = format!("__aarch64_{sym}{size}_{sym_ordering}"); + writeln!(macro_, "$macro!( {ordering:?}, {size}, {name} );").unwrap(); + } + } + } + + let mut buf = String::new(); + for macro_def in macros.values() { + buf += macro_def; + buf += "}; }"; + } + let dst = std::env::var("OUT_DIR").unwrap() + "/outlined_atomics.rs"; + std::fs::write(dst, buf).unwrap(); } #[cfg(feature = "c")] diff --git a/library/compiler-builtins/src/aarch64.rs b/library/compiler-builtins/src/aarch64.rs new file mode 100644 index 0000000000000..018880650d38a --- /dev/null +++ b/library/compiler-builtins/src/aarch64.rs @@ -0,0 +1,221 @@ +//! Aarch64 targets have two possible implementations for atomics: +//! 1. Load-Locked, Store-Conditional (LL/SC), older and slower. +//! 2. Large System Extensions (LSE), newer and faster. +//! To avoid breaking backwards compat, C toolchains introduced a concept of "outlined atomics", +//! where atomic operations call into the compiler runtime to dispatch between two depending on +//! which is supported on the current CPU. +//! See https://community.arm.com/arm-community-blogs/b/tools-software-ides-blog/posts/making-the-most-of-the-arm-architecture-in-gcc-10#:~:text=out%20of%20line%20atomics for more discussion. +//! +//! Currently we only support LL/SC, because LSE requires `getauxval` from libc in order to do runtime detection. +//! Use the `compiler-rt` intrinsics if you want LSE support. +//! +//! Ported from `aarch64/lse.S` in LLVM's compiler-rt. +//! +//! Generate functions for each of the following symbols: +//! __aarch64_swpN_ORDER +//! __aarch64_ldaddN_ORDER +//! __aarch64_ldclrN_ORDER +//! __aarch64_ldeorN_ORDER +//! __aarch64_ldsetN_ORDER +//! for N = {1, 2, 4, 8}, M = {1, 2, 4, 8}, ORDER = { relax, acq, rel, acq_rel } +//! +//! TODO: M = 16 +//! +//! The original `lse.S` has some truly horrifying code that expects to be compiled multiple times with different constants. +//! We do something similar, but with macro arguments. + +/// We don't do runtime dispatch so we don't have to worry about the global ctor. +/// Apparently MacOS uses a different number of underscores in the symbol name (???) +// #[cfg(target_vendor = "apple")] +// macro_rules! have_lse { +// () => { ___aarch64_have_lse_atomics } +// } + +// #[cfg(not(target_vendor = "apple"))] +// macro_rules! have_lse { +// () => { __aarch64_have_lse_atomics } +// } + +/// Translate a byte size to a Rust type. +macro_rules! int_ty { + (1) => { i8 }; + (2) => { i16 }; + (4) => { i32 }; + (8) => { i64 }; + (16) => { i128 }; +} + +/// Given a byte size and a register number, return a register of the appropriate size. +/// +/// See . +macro_rules! reg { + (1, $num:literal) => { concat!("w", $num) }; + (2, $num:literal) => { concat!("w", $num) }; + (4, $num:literal) => { concat!("w", $num) }; + (8, $num:literal) => { concat!("x", $num) }; +} + +/// Given an atomic ordering, translate it to the acquire suffix for the lxdr aarch64 ASM instruction. +macro_rules! acquire { + (Relaxed) => { "" }; + (Acquire) => { "a" }; + (Release) => { "" }; + (AcqRel) => { "a" }; +} + +/// Given an atomic ordering, translate it to the release suffix for the stxr aarch64 ASM instruction. +macro_rules! release { + (Relaxed) => { "" }; + (Acquire) => { "" }; + (Release) => { "l" }; + (AcqRel) => { "l" }; +} + +/// Given a size in bytes, translate it to the byte suffix for an aarch64 ASM instruction. +macro_rules! size { + (1) => { "b" }; + (2) => { "h" }; + (4) => { "" }; + (8) => { "" }; + (16) => { "" }; +} + +/// Given a byte size, translate it to an Unsigned eXTend instruction +/// with the correct semantics. +/// +/// See +macro_rules! uxt { + (1) => { "uxtb" }; + (2) => { "uxth" }; + ($_:tt) => { "mov" }; +} + +/// Given an atomic ordering and byte size, translate it to a LoaD eXclusive Register instruction +/// with the correct semantics. +/// +/// See . +macro_rules! ldxr { + ($ordering:ident, $bytes:tt) => { concat!("ld", acquire!($ordering), "xr", size!($bytes)) } +} + +/// Given an atomic ordering and byte size, translate it to a STore eXclusive Register instruction +/// with the correct semantics. +/// +/// See . +macro_rules! stxr { + ($ordering:ident, $bytes:tt) => { concat!("st", release!($ordering), "xr", size!($bytes)) } +} + +/// See . +macro_rules! compare_and_swap { + ($ordering:ident, $bytes:tt, $name:ident) => { + intrinsics! { + #[maybe_use_optimized_c_shim] + #[naked] + pub extern "C" fn $name ( + expected: int_ty!($bytes), desired: int_ty!($bytes), ptr: *mut int_ty!($bytes) + ) -> int_ty!($bytes) { + // We can't use `AtomicI8::compare_and_swap`; we *are* compare_and_swap. + unsafe { core::arch::asm! { + // UXT s(tmp0), s(0) + concat!(uxt!($bytes), " ", reg!($bytes, 16), ", ", reg!($bytes, 0)), + "0:", + // LDXR s(0), [x2] + concat!(ldxr!($ordering, $bytes), " ", reg!($bytes, 0), ", [x2]"), + // cmp s(0), s(tmp0) + concat!("cmp ", reg!($bytes, 0), ", ", reg!($bytes, 16)), + "bne 1f", + // STXR w(tmp1), s(1), [x2] + concat!(stxr!($ordering, $bytes), " w17, ", reg!($bytes, 1), ", [x2]"), + "cbnz w17, 0b", + "1:", + "ret", + options(noreturn) + } } + } + } + } +} + + +/// See . +macro_rules! swap { + ($ordering:ident, $bytes:tt, $name:ident) => { + intrinsics! { + #[maybe_use_optimized_c_shim] + #[naked] + pub extern "C" fn $name ( + left: int_ty!($bytes), right_ptr: *mut int_ty!($bytes) + ) -> int_ty!($bytes) { + unsafe { core::arch::asm! { + // mov s(tmp0), s(0) + concat!("mov ", reg!($bytes, 16), ", ", reg!($bytes, 0)), + "0:", + // LDXR s(0), [x1] + concat!(ldxr!($ordering, $bytes), " ", reg!($bytes, 0), ", [x1]"), + // STXR w(tmp1), s(tmp0), [x1] + concat!(stxr!($ordering, $bytes), " w17, ", reg!($bytes, 16), ", [x1]"), + "cbnz w17, 0b", + "ret", + options(noreturn) + } } + } + } + } +} + +/// See (e.g.) . +macro_rules! fetch_op { + ($ordering:ident, $bytes:tt, $name:ident, $op:literal) => { + intrinsics! { + #[maybe_use_optimized_c_shim] + #[naked] + pub extern "C" fn $name ( + val: int_ty!($bytes), ptr: *mut int_ty!($bytes) + ) -> int_ty!($bytes) { + unsafe { core::arch::asm! { + // mov s(tmp0), s(0) + concat!("mov ", reg!($bytes, 16), ", ", reg!($bytes, 0)), + "0:", + // LDXR s(0), [x1] + concat!(ldxr!($ordering, $bytes), " ", reg!($bytes, 0), ", [x1]"), + // OP s(tmp1), s(0), s(tmp0) + concat!($op, " ", reg!($bytes, 17), ", ", reg!($bytes, 0), ", ", reg!($bytes, 16)), + // STXR w(tmp2), s(tmp1), [x1] + concat!(stxr!($ordering, $bytes), " w15, ", reg!($bytes, 17), ", [x1]"), + "cbnz w15, 0b", + "ret", + options(noreturn) + } } + } + } + } +} + +// We need a single macro to pass to `foreach_ldadd`. +macro_rules! add { + ($ordering:ident, $bytes:tt, $name:ident) => { fetch_op! { $ordering, $bytes, $name, "add" } } +} + +macro_rules! and { + ($ordering:ident, $bytes:tt, $name:ident) => { fetch_op! { $ordering, $bytes, $name, "bic" } } +} + +macro_rules! xor { + ($ordering:ident, $bytes:tt, $name:ident) => { fetch_op! { $ordering, $bytes, $name, "eor" } } +} + +macro_rules! or { + ($ordering:ident, $bytes:tt, $name:ident) => { fetch_op! { $ordering, $bytes, $name, "orr" } } +} + +// See `generate_aarch64_outlined_atomics` in build.rs. +include!(concat!(env!("OUT_DIR"), "/outlined_atomics.rs")); +foreach_cas!(compare_and_swap); +foreach_swp!(swap); +foreach_ldadd!(add); +foreach_ldclr!(and); +foreach_ldeor!(xor); +foreach_ldset!(or); + +// TODO: CAS 16 diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 71f249c8eb34f..90b21f1fc7fee 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -57,6 +57,9 @@ pub mod mem; #[cfg(target_arch = "arm")] pub mod arm; +#[cfg(target_arch = "aarch64")] +pub mod aarch64; + #[cfg(all( kernel_user_helpers, any(target_os = "linux", target_os = "android"), diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index b3becde7230cf..e3a381928c64f 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -419,7 +419,7 @@ macro_rules! intrinsics { ( #[naked] $(#[$($attr:tt)*])* - pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + pub $(unsafe)? extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { $($body:tt)* } diff --git a/library/compiler-builtins/testcrate/tests/lse.rs b/library/compiler-builtins/testcrate/tests/lse.rs new file mode 100644 index 0000000000000..49d73177e3bdc --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/lse.rs @@ -0,0 +1,88 @@ +#![cfg(target_arch = "aarch64")] +#![feature(decl_macro)] // so we can use pub(super) + +/// Translate a byte size to a Rust type. +macro int_ty { + (1) => { i8 }, + (2) => { i16 }, + (4) => { i32 }, + (8) => { i64 }, + (16) => { i128 } +} + +mod cas { + pub(super) macro test($_ordering:ident, $bytes:tt, $name:ident) { + #[test] + fn $name() { + testcrate::fuzz_2(10000, |expected: super::int_ty!($bytes), new| { + let mut target = expected.wrapping_add(10); + assert_eq!( + unsafe { compiler_builtins::aarch64::$name::$name(expected, new, &mut target) }, + expected.wrapping_add(10), + "return value should always be the previous value", + ); + assert_eq!( + target, + expected.wrapping_add(10), + "shouldn't have changed target" + ); + + target = expected; + assert_eq!( + unsafe { compiler_builtins::aarch64::$name::$name(expected, new, &mut target) }, + expected + ); + assert_eq!(target, new, "should have updated target"); + }); + } + } +} + +mod swap { + pub(super) macro test($_ordering:ident, $bytes:tt, $name:ident) { + #[test] + fn $name() { + testcrate::fuzz_2(10000, |left: super::int_ty!($bytes), mut right| { + let orig_right = right; + assert_eq!( + unsafe { compiler_builtins::aarch64::$name::$name(left, &mut right) }, + orig_right + ); + assert_eq!(left, right); + }); + } + } +} + +macro_rules! test_op { + ($mod:ident, $( $op:tt )* ) => { + mod $mod { + pub(super) macro test { + ($_ordering:ident, $bytes:tt, $name:ident) => { + #[test] + fn $name() { + testcrate::fuzz_2(10000, |old, val| { + let mut target = old; + let op: fn(super::int_ty!($bytes), super::int_ty!($bytes)) -> _ = $($op)*; + let expected = op(old, val); + assert_eq!(old, unsafe { compiler_builtins::aarch64::$name::$name(val, &mut target) }, "{} should return original value", stringify!($name)); + assert_eq!(expected, target, "{} should store to target", stringify!($name)); + }); + } + } + } + } + }; +} + +test_op!(add, |left, right| left.wrapping_add(right)); +test_op!(clr, |left, right| left & !right); +test_op!(xor, std::ops::BitXor::bitxor); +test_op!(or, std::ops::BitOr::bitor); + +compiler_builtins::foreach_cas!(cas::test); +compiler_builtins::foreach_swp!(swap::test); +compiler_builtins::foreach_ldadd!(add::test); +compiler_builtins::foreach_ldclr!(clr::test); +compiler_builtins::foreach_ldeor!(xor::test); +compiler_builtins::foreach_ldset!(or::test); From 6242fd629e7a680d090e5606954de85ccf5be187 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 26 Jun 2023 13:54:47 +0000 Subject: [PATCH 1121/4206] address review comments and fix CI - implement CAS 16 - remove useless commented out symbol name - support `feature("no-asm")` - fix warnings when `feature("c")` is enabled - rustfmt --- library/compiler-builtins/build.rs | 10 +- library/compiler-builtins/src/aarch64.rs | 103 ++++++++++++++---- library/compiler-builtins/src/lib.rs | 6 +- .../compiler-builtins/testcrate/tests/lse.rs | 7 +- 4 files changed, 97 insertions(+), 29 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 266cc28bb2fe6..4549d0b4f166c 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -122,6 +122,9 @@ fn generate_aarch64_outlined_atomics() { macros.insert(sym, gen_macro(sym)); } + // Only CAS supports 16 bytes, and it has a different implementation that uses a different macro. + let mut cas16 = gen_macro("cas16"); + for ordering in [ Ordering::Relaxed, Ordering::Acquire, @@ -129,17 +132,18 @@ fn generate_aarch64_outlined_atomics() { Ordering::AcqRel, ] { let sym_ordering = aarch64_symbol(ordering); - // TODO: support CAS 16 - for size in [1, 2, 4, 8 /* , 16*/] { + for size in [1, 2, 4, 8] { for (sym, macro_) in &mut macros { let name = format!("__aarch64_{sym}{size}_{sym_ordering}"); writeln!(macro_, "$macro!( {ordering:?}, {size}, {name} );").unwrap(); } } + let name = format!("__aarch64_cas16_{sym_ordering}"); + writeln!(cas16, "$macro!( {ordering:?}, {name} );").unwrap(); } let mut buf = String::new(); - for macro_def in macros.values() { + for macro_def in macros.values().chain(std::iter::once(&cas16)) { buf += macro_def; buf += "}; }"; } diff --git a/library/compiler-builtins/src/aarch64.rs b/library/compiler-builtins/src/aarch64.rs index 018880650d38a..1aaa1a69472bd 100644 --- a/library/compiler-builtins/src/aarch64.rs +++ b/library/compiler-builtins/src/aarch64.rs @@ -12,31 +12,21 @@ //! Ported from `aarch64/lse.S` in LLVM's compiler-rt. //! //! Generate functions for each of the following symbols: +//! __aarch64_casM_ORDER //! __aarch64_swpN_ORDER //! __aarch64_ldaddN_ORDER //! __aarch64_ldclrN_ORDER //! __aarch64_ldeorN_ORDER //! __aarch64_ldsetN_ORDER -//! for N = {1, 2, 4, 8}, M = {1, 2, 4, 8}, ORDER = { relax, acq, rel, acq_rel } -//! -//! TODO: M = 16 +//! for N = {1, 2, 4, 8}, M = {1, 2, 4, 8, 16}, ORDER = { relax, acq, rel, acq_rel } //! //! The original `lse.S` has some truly horrifying code that expects to be compiled multiple times with different constants. //! We do something similar, but with macro arguments. -/// We don't do runtime dispatch so we don't have to worry about the global ctor. -/// Apparently MacOS uses a different number of underscores in the symbol name (???) -// #[cfg(target_vendor = "apple")] -// macro_rules! have_lse { -// () => { ___aarch64_have_lse_atomics } -// } - -// #[cfg(not(target_vendor = "apple"))] -// macro_rules! have_lse { -// () => { __aarch64_have_lse_atomics } -// } +// We don't do runtime dispatch so we don't have to worry about the `__aarch64_have_lse_atomics` global ctor. /// Translate a byte size to a Rust type. +#[rustfmt::skip] macro_rules! int_ty { (1) => { i8 }; (2) => { i16 }; @@ -48,6 +38,7 @@ macro_rules! int_ty { /// Given a byte size and a register number, return a register of the appropriate size. /// /// See . +#[rustfmt::skip] macro_rules! reg { (1, $num:literal) => { concat!("w", $num) }; (2, $num:literal) => { concat!("w", $num) }; @@ -56,6 +47,7 @@ macro_rules! reg { } /// Given an atomic ordering, translate it to the acquire suffix for the lxdr aarch64 ASM instruction. +#[rustfmt::skip] macro_rules! acquire { (Relaxed) => { "" }; (Acquire) => { "a" }; @@ -64,6 +56,7 @@ macro_rules! acquire { } /// Given an atomic ordering, translate it to the release suffix for the stxr aarch64 ASM instruction. +#[rustfmt::skip] macro_rules! release { (Relaxed) => { "" }; (Acquire) => { "" }; @@ -72,6 +65,7 @@ macro_rules! release { } /// Given a size in bytes, translate it to the byte suffix for an aarch64 ASM instruction. +#[rustfmt::skip] macro_rules! size { (1) => { "b" }; (2) => { "h" }; @@ -84,6 +78,7 @@ macro_rules! size { /// with the correct semantics. /// /// See +#[rustfmt::skip] macro_rules! uxt { (1) => { "uxtb" }; (2) => { "uxth" }; @@ -95,7 +90,9 @@ macro_rules! uxt { /// /// See . macro_rules! ldxr { - ($ordering:ident, $bytes:tt) => { concat!("ld", acquire!($ordering), "xr", size!($bytes)) } + ($ordering:ident, $bytes:tt) => { + concat!("ld", acquire!($ordering), "xr", size!($bytes)) + }; } /// Given an atomic ordering and byte size, translate it to a STore eXclusive Register instruction @@ -103,7 +100,29 @@ macro_rules! ldxr { /// /// See . macro_rules! stxr { - ($ordering:ident, $bytes:tt) => { concat!("st", release!($ordering), "xr", size!($bytes)) } + ($ordering:ident, $bytes:tt) => { + concat!("st", release!($ordering), "xr", size!($bytes)) + }; +} + +/// Given an atomic ordering and byte size, translate it to a LoaD eXclusive Pair of registers instruction +/// with the correct semantics. +/// +/// See +macro_rules! ldxp { + ($ordering:ident) => { + concat!("ld", acquire!($ordering), "xp") + }; +} + +/// Given an atomic ordering and byte size, translate it to a STore eXclusive Pair of registers instruction +/// with the correct semantics. +/// +/// See . +macro_rules! stxp { + ($ordering:ident) => { + concat!("st", release!($ordering), "xp") + }; } /// See . @@ -134,9 +153,38 @@ macro_rules! compare_and_swap { } } } } - } + }; } +// i128 uses a completely different impl, so it has its own macro. +macro_rules! compare_and_swap_i128 { + ($ordering:ident, $name:ident) => { + intrinsics! { + #[maybe_use_optimized_c_shim] + #[naked] + pub extern "C" fn $name ( + expected: i128, desired: i128, ptr: *mut i128 + ) -> i128 { + unsafe { core::arch::asm! { + "mov x16, x0", + "mov x17, x1", + "0:", + // LDXP x0, x1, [x4] + concat!(ldxp!($ordering), " x0, x1, [x4]"), + "cmp x0, x16", + "ccmp x1, x17, #0, eq", + "bne 1f", + // STXP w(tmp2), x2, x3, [x4] + concat!(stxp!($ordering), " w15, x2, x3, [x4]"), + "cbnz w15, 0b", + "1:", + "ret", + options(noreturn) + } } + } + } + }; +} /// See . macro_rules! swap { @@ -161,7 +209,7 @@ macro_rules! swap { } } } } - } + }; } /// See (e.g.) . @@ -194,28 +242,35 @@ macro_rules! fetch_op { // We need a single macro to pass to `foreach_ldadd`. macro_rules! add { - ($ordering:ident, $bytes:tt, $name:ident) => { fetch_op! { $ordering, $bytes, $name, "add" } } + ($ordering:ident, $bytes:tt, $name:ident) => { + fetch_op! { $ordering, $bytes, $name, "add" } + }; } macro_rules! and { - ($ordering:ident, $bytes:tt, $name:ident) => { fetch_op! { $ordering, $bytes, $name, "bic" } } + ($ordering:ident, $bytes:tt, $name:ident) => { + fetch_op! { $ordering, $bytes, $name, "bic" } + }; } macro_rules! xor { - ($ordering:ident, $bytes:tt, $name:ident) => { fetch_op! { $ordering, $bytes, $name, "eor" } } + ($ordering:ident, $bytes:tt, $name:ident) => { + fetch_op! { $ordering, $bytes, $name, "eor" } + }; } macro_rules! or { - ($ordering:ident, $bytes:tt, $name:ident) => { fetch_op! { $ordering, $bytes, $name, "orr" } } + ($ordering:ident, $bytes:tt, $name:ident) => { + fetch_op! { $ordering, $bytes, $name, "orr" } + }; } // See `generate_aarch64_outlined_atomics` in build.rs. include!(concat!(env!("OUT_DIR"), "/outlined_atomics.rs")); foreach_cas!(compare_and_swap); +foreach_cas16!(compare_and_swap_i128); foreach_swp!(swap); foreach_ldadd!(add); foreach_ldclr!(and); foreach_ldeor!(xor); foreach_ldset!(or); - -// TODO: CAS 16 diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 90b21f1fc7fee..4b44adc266d88 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -57,7 +57,11 @@ pub mod mem; #[cfg(target_arch = "arm")] pub mod arm; -#[cfg(target_arch = "aarch64")] +#[cfg(all( + target_arch = "aarch64", + not(feature = "no-asm"), + not(feature = "optimized-c") +))] pub mod aarch64; #[cfg(all( diff --git a/library/compiler-builtins/testcrate/tests/lse.rs b/library/compiler-builtins/testcrate/tests/lse.rs index 49d73177e3bdc..7b54ab5d2865c 100644 --- a/library/compiler-builtins/testcrate/tests/lse.rs +++ b/library/compiler-builtins/testcrate/tests/lse.rs @@ -1,5 +1,5 @@ -#![cfg(target_arch = "aarch64")] #![feature(decl_macro)] // so we can use pub(super) +#![cfg(all(target_arch = "aarch64", not(feature = "no-asm")))] /// Translate a byte size to a Rust type. macro int_ty { @@ -38,6 +38,10 @@ mod cas { } } +macro test_cas16($_ordering:ident, $name:ident) { + cas::test!($_ordering, 16, $name); +} + mod swap { pub(super) macro test($_ordering:ident, $bytes:tt, $name:ident) { #[test] @@ -81,6 +85,7 @@ test_op!(xor, std::ops::BitXor::bitxor); test_op!(or, std::ops::BitOr::bitor); compiler_builtins::foreach_cas!(cas::test); +compiler_builtins::foreach_cas16!(test_cas16); compiler_builtins::foreach_swp!(swap::test); compiler_builtins::foreach_ldadd!(add::test); compiler_builtins::foreach_ldclr!(clr::test); From e7c4a453484da043e2affdd8320151beafec94b1 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 26 Jun 2023 16:27:16 +0000 Subject: [PATCH 1122/4206] require naked functions to be unsafe again they dereference raw pointers, so the caller needs to make sure the pointer is valid. note that this requires changing `maybe_use_optimized_c_shim` to support unsafe functions. --- library/compiler-builtins/src/aarch64.rs | 8 ++++---- library/compiler-builtins/src/macros.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/src/aarch64.rs b/library/compiler-builtins/src/aarch64.rs index 1aaa1a69472bd..ddbec6d327bd6 100644 --- a/library/compiler-builtins/src/aarch64.rs +++ b/library/compiler-builtins/src/aarch64.rs @@ -131,7 +131,7 @@ macro_rules! compare_and_swap { intrinsics! { #[maybe_use_optimized_c_shim] #[naked] - pub extern "C" fn $name ( + pub unsafe extern "C" fn $name ( expected: int_ty!($bytes), desired: int_ty!($bytes), ptr: *mut int_ty!($bytes) ) -> int_ty!($bytes) { // We can't use `AtomicI8::compare_and_swap`; we *are* compare_and_swap. @@ -162,7 +162,7 @@ macro_rules! compare_and_swap_i128 { intrinsics! { #[maybe_use_optimized_c_shim] #[naked] - pub extern "C" fn $name ( + pub unsafe extern "C" fn $name ( expected: i128, desired: i128, ptr: *mut i128 ) -> i128 { unsafe { core::arch::asm! { @@ -192,7 +192,7 @@ macro_rules! swap { intrinsics! { #[maybe_use_optimized_c_shim] #[naked] - pub extern "C" fn $name ( + pub unsafe extern "C" fn $name ( left: int_ty!($bytes), right_ptr: *mut int_ty!($bytes) ) -> int_ty!($bytes) { unsafe { core::arch::asm! { @@ -218,7 +218,7 @@ macro_rules! fetch_op { intrinsics! { #[maybe_use_optimized_c_shim] #[naked] - pub extern "C" fn $name ( + pub unsafe extern "C" fn $name ( val: int_ty!($bytes), ptr: *mut int_ty!($bytes) ) -> int_ty!($bytes) { unsafe { core::arch::asm! { diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index e3a381928c64f..b11114f123880 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -204,7 +204,7 @@ macro_rules! intrinsics { ( #[maybe_use_optimized_c_shim] $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + pub $(unsafe $(@ $empty:tt)? )? extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { $($body:tt)* } @@ -212,7 +212,7 @@ macro_rules! intrinsics { ) => ( #[cfg($name = "optimized-c")] #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + pub $(unsafe $($empty)? )? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { extern $abi { fn $name($($argname: $ty),*) $(-> $ret)?; } @@ -224,7 +224,7 @@ macro_rules! intrinsics { #[cfg(not($name = "optimized-c"))] intrinsics! { $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + pub $(unsafe $($empty)? )? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } } @@ -419,7 +419,7 @@ macro_rules! intrinsics { ( #[naked] $(#[$($attr:tt)*])* - pub $(unsafe)? extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { $($body:tt)* } From 379445f9a5514de341b0d2d731b8dfdcdcf20415 Mon Sep 17 00:00:00 2001 From: kirk Date: Sun, 25 Jun 2023 13:06:18 +0000 Subject: [PATCH 1123/4206] port updated version of llvm float div --- library/compiler-builtins/src/float/div.rs | 857 ++++++++++++++---- .../testcrate/tests/div_rem.rs | 11 +- 2 files changed, 667 insertions(+), 201 deletions(-) diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index c2d6c07e73dbd..c0aae34fb639d 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -12,11 +12,17 @@ where i32: CastInto, F::Int: CastInto, F::Int: HInt, + ::Int: core::ops::Mul, { + const NUMBER_OF_HALF_ITERATIONS: usize = 0; + const NUMBER_OF_FULL_ITERATIONS: usize = 3; + const USE_NATIVE_FULL_ITERATIONS: bool = true; + let one = F::Int::ONE; let zero = F::Int::ZERO; + let hw = F::BITS / 2; + let lo_mask = u32::MAX >> hw; - // let bits = F::BITS; let significand_bits = F::SIGNIFICAND_BITS; let max_exponent = F::EXPONENT_MAX; @@ -109,101 +115,341 @@ where } } - // Or in the implicit significand bit. (If we fell through from the + // Set the implicit significand bit. If we fell through from the // denormal path it was already set by normalize( ), but setting it twice - // won't hurt anything.) + // won't hurt anything. a_significand |= implicit_bit; b_significand |= implicit_bit; - let mut quotient_exponent: i32 = CastInto::::cast(a_exponent) - .wrapping_sub(CastInto::::cast(b_exponent)) - .wrapping_add(scale); - - // Align the significand of b as a Q31 fixed-point number in the range - // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax - // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This - // is accurate to about 3.5 binary digits. - let q31b = CastInto::::cast(b_significand << 8.cast()); - let mut reciprocal = (0x7504f333u32).wrapping_sub(q31b); - - // Now refine the reciprocal estimate using a Newton-Raphson iteration: - // - // x1 = x0 * (2 - x0 * b) - // - // This doubles the number of correct binary digits in the approximation - // with each iteration, so after three iterations, we have about 28 binary - // digits of accuracy. - - let mut correction: u32 = - negate_u32(((reciprocal as u64).wrapping_mul(q31b as u64) >> 32) as u32); - reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) >> 31) as u32; - correction = negate_u32(((reciprocal as u64).wrapping_mul(q31b as u64) >> 32) as u32); - reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) >> 31) as u32; - correction = negate_u32(((reciprocal as u64).wrapping_mul(q31b as u64) >> 32) as u32); - reciprocal = ((reciprocal as u64).wrapping_mul(correction as u64) >> 31) as u32; - - // Exhaustive testing shows that the error in reciprocal after three steps - // is in the interval [-0x1.f58108p-31, 0x1.d0e48cp-29], in line with our - // expectations. We bump the reciprocal by a tiny value to force the error - // to be strictly positive (in the range [0x1.4fdfp-37,0x1.287246p-29], to - // be specific). This also causes 1/1 to give a sensible approximation - // instead of zero (due to overflow). - reciprocal = reciprocal.wrapping_sub(2); - - // The numerical reciprocal is accurate to within 2^-28, lies in the - // interval [0x1.000000eep-1, 0x1.fffffffcp-1], and is strictly smaller - // than the true reciprocal of b. Multiplying a by this reciprocal thus - // gives a numerical q = a/b in Q24 with the following properties: - // - // 1. q < a/b - // 2. q is in the interval [0x1.000000eep-1, 0x1.fffffffcp0) - // 3. the error in q is at most 2^-24 + 2^-27 -- the 2^24 term comes - // from the fact that we truncate the product, and the 2^27 term - // is the error in the reciprocal of b scaled by the maximum - // possible value of a. As a consequence of this error bound, - // either q or nextafter(q) is the correctly rounded - let mut quotient = (a_significand << 1).widen_mul(reciprocal.cast()).hi(); - - // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0). - // In either case, we are going to compute a residual of the form - // - // r = a - q*b + + let written_exponent: i32 = CastInto::::cast( + a_exponent + .wrapping_sub(b_exponent) + .wrapping_add(scale.cast()), + ) + .wrapping_add(exponent_bias) as i32; + let b_uq1 = b_significand << (F::BITS - significand_bits - 1); + + // Align the significand of b as a UQ1.(n-1) fixed-point number in the range + // [1.0, 2.0) and get a UQ0.n approximate reciprocal using a small minimax + // polynomial approximation: x0 = 3/4 + 1/sqrt(2) - b/2. + // The max error for this approximation is achieved at endpoints, so + // abs(x0(b) - 1/b) <= abs(x0(1) - 1/1) = 3/4 - 1/sqrt(2) = 0.04289..., + // which is about 4.5 bits. + // The initial approximation is between x0(1.0) = 0.9571... and x0(2.0) = 0.4571... + + // Then, refine the reciprocal estimate using a quadratically converging + // Newton-Raphson iteration: + // x_{n+1} = x_n * (2 - x_n * b) // - // We know from the construction of q that r satisfies: + // Let b be the original divisor considered "in infinite precision" and + // obtained from IEEE754 representation of function argument (with the + // implicit bit set). Corresponds to rep_t-sized b_UQ1 represented in + // UQ1.(W-1). // - // 0 <= r < ulp(q)*b + // Let b_hw be an infinitely precise number obtained from the highest (HW-1) + // bits of divisor significand (with the implicit bit set). Corresponds to + // half_rep_t-sized b_UQ1_hw represented in UQ1.(HW-1) that is a **truncated** + // version of b_UQ1. // - // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we - // already have the correct result. The exact halfway case cannot occur. - // We also take this time to right shift quotient if it falls in the [1,2) - // range and adjust the exponent accordingly. - let residual = if quotient < (implicit_bit << 1) { - quotient_exponent = quotient_exponent.wrapping_sub(1); - (a_significand << (significand_bits + 1)).wrapping_sub(quotient.wrapping_mul(b_significand)) + // Let e_n := x_n - 1/b_hw + // E_n := x_n - 1/b + // abs(E_n) <= abs(e_n) + (1/b_hw - 1/b) + // = abs(e_n) + (b - b_hw) / (b*b_hw) + // <= abs(e_n) + 2 * 2^-HW + + // rep_t-sized iterations may be slower than the corresponding half-width + // variant depending on the handware and whether single/double/quad precision + // is selected. + // NB: Using half-width iterations increases computation errors due to + // rounding, so error estimations have to be computed taking the selected + // mode into account! + + #[allow(clippy::absurd_extreme_comparisons)] + let mut x_uq0 = if NUMBER_OF_HALF_ITERATIONS > 0 { + // Starting with (n-1) half-width iterations + let b_uq1_hw: u16 = + (CastInto::::cast(b_significand) >> (significand_bits + 1 - hw)) as u16; + + // C is (3/4 + 1/sqrt(2)) - 1 truncated to W0 fractional bits as UQ0.HW + // with W0 being either 16 or 32 and W0 <= HW. + // That is, C is the aforementioned 3/4 + 1/sqrt(2) constant (from which + // b/2 is subtracted to obtain x0) wrapped to [0, 1) range. + + // HW is at least 32. Shifting into the highest bits if needed. + let c_hw = (0x7504_u32 as u16).wrapping_shl(hw.wrapping_sub(32)); + + // b >= 1, thus an upper bound for 3/4 + 1/sqrt(2) - b/2 is about 0.9572, + // so x0 fits to UQ0.HW without wrapping. + let x_uq0_hw: u16 = { + let mut x_uq0_hw: u16 = c_hw.wrapping_sub(b_uq1_hw /* exact b_hw/2 as UQ0.HW */); + // An e_0 error is comprised of errors due to + // * x0 being an inherently imprecise first approximation of 1/b_hw + // * C_hw being some (irrational) number **truncated** to W0 bits + // Please note that e_0 is calculated against the infinitely precise + // reciprocal of b_hw (that is, **truncated** version of b). + // + // e_0 <= 3/4 - 1/sqrt(2) + 2^-W0 + + // By construction, 1 <= b < 2 + // f(x) = x * (2 - b*x) = 2*x - b*x^2 + // f'(x) = 2 * (1 - b*x) + // + // On the [0, 1] interval, f(0) = 0, + // then it increses until f(1/b) = 1 / b, maximum on (0, 1), + // then it decreses to f(1) = 2 - b + // + // Let g(x) = x - f(x) = b*x^2 - x. + // On (0, 1/b), g(x) < 0 <=> f(x) > x + // On (1/b, 1], g(x) > 0 <=> f(x) < x + // + // For half-width iterations, b_hw is used instead of b. + #[allow(clippy::reversed_empty_ranges)] + for _ in 0..NUMBER_OF_HALF_ITERATIONS { + // corr_UQ1_hw can be **larger** than 2 - b_hw*x by at most 1*Ulp + // of corr_UQ1_hw. + // "0.0 - (...)" is equivalent to "2.0 - (...)" in UQ1.(HW-1). + // On the other hand, corr_UQ1_hw should not overflow from 2.0 to 0.0 provided + // no overflow occurred earlier: ((rep_t)x_UQ0_hw * b_UQ1_hw >> HW) is + // expected to be strictly positive because b_UQ1_hw has its highest bit set + // and x_UQ0_hw should be rather large (it converges to 1/2 < 1/b_hw <= 1). + let corr_uq1_hw: u16 = + 0.wrapping_sub((x_uq0_hw as u32).wrapping_mul(b_uq1_hw.cast()) >> hw) as u16; + + // Now, we should multiply UQ0.HW and UQ1.(HW-1) numbers, naturally + // obtaining an UQ1.(HW-1) number and proving its highest bit could be + // considered to be 0 to be able to represent it in UQ0.HW. + // From the above analysis of f(x), if corr_UQ1_hw would be represented + // without any intermediate loss of precision (that is, in twice_rep_t) + // x_UQ0_hw could be at most [1.]000... if b_hw is exactly 1.0 and strictly + // less otherwise. On the other hand, to obtain [1.]000..., one have to pass + // 1/b_hw == 1.0 to f(x), so this cannot occur at all without overflow (due + // to 1.0 being not representable as UQ0.HW). + // The fact corr_UQ1_hw was virtually round up (due to result of + // multiplication being **first** truncated, then negated - to improve + // error estimations) can increase x_UQ0_hw by up to 2*Ulp of x_UQ0_hw. + x_uq0_hw = ((x_uq0_hw as u32).wrapping_mul(corr_uq1_hw as u32) >> (hw - 1)) as u16; + // Now, either no overflow occurred or x_UQ0_hw is 0 or 1 in its half_rep_t + // representation. In the latter case, x_UQ0_hw will be either 0 or 1 after + // any number of iterations, so just subtract 2 from the reciprocal + // approximation after last iteration. + + // In infinite precision, with 0 <= eps1, eps2 <= U = 2^-HW: + // corr_UQ1_hw = 2 - (1/b_hw + e_n) * b_hw + 2*eps1 + // = 1 - e_n * b_hw + 2*eps1 + // x_UQ0_hw = (1/b_hw + e_n) * (1 - e_n*b_hw + 2*eps1) - eps2 + // = 1/b_hw - e_n + 2*eps1/b_hw + e_n - e_n^2*b_hw + 2*e_n*eps1 - eps2 + // = 1/b_hw + 2*eps1/b_hw - e_n^2*b_hw + 2*e_n*eps1 - eps2 + // e_{n+1} = -e_n^2*b_hw + 2*eps1/b_hw + 2*e_n*eps1 - eps2 + // = 2*e_n*eps1 - (e_n^2*b_hw + eps2) + 2*eps1/b_hw + // \------ >0 -------/ \-- >0 ---/ + // abs(e_{n+1}) <= 2*abs(e_n)*U + max(2*e_n^2 + U, 2 * U) + } + // For initial half-width iterations, U = 2^-HW + // Let abs(e_n) <= u_n * U, + // then abs(e_{n+1}) <= 2 * u_n * U^2 + max(2 * u_n^2 * U^2 + U, 2 * U) + // u_{n+1} <= 2 * u_n * U + max(2 * u_n^2 * U + 1, 2) + + // Account for possible overflow (see above). For an overflow to occur for the + // first time, for "ideal" corr_UQ1_hw (that is, without intermediate + // truncation), the result of x_UQ0_hw * corr_UQ1_hw should be either maximum + // value representable in UQ0.HW or less by 1. This means that 1/b_hw have to + // be not below that value (see g(x) above), so it is safe to decrement just + // once after the final iteration. On the other hand, an effective value of + // divisor changes after this point (from b_hw to b), so adjust here. + x_uq0_hw.wrapping_sub(1_u16) + }; + + // Error estimations for full-precision iterations are calculated just + // as above, but with U := 2^-W and taking extra decrementing into account. + // We need at least one such iteration. + + // Simulating operations on a twice_rep_t to perform a single final full-width + // iteration. Using ad-hoc multiplication implementations to take advantage + // of particular structure of operands. + + let blo: u32 = (CastInto::::cast(b_uq1)) & lo_mask; + // x_UQ0 = x_UQ0_hw * 2^HW - 1 + // x_UQ0 * b_UQ1 = (x_UQ0_hw * 2^HW) * (b_UQ1_hw * 2^HW + blo) - b_UQ1 + // + // <--- higher half ---><--- lower half ---> + // [x_UQ0_hw * b_UQ1_hw] + // + [ x_UQ0_hw * blo ] + // - [ b_UQ1 ] + // = [ result ][.... discarded ...] + let corr_uq1 = negate_u32( + (x_uq0_hw as u32) * (b_uq1_hw as u32) + (((x_uq0_hw as u32) * (blo)) >> hw) - 1, + ); // account for *possible* carry + let lo_corr = corr_uq1 & lo_mask; + let hi_corr = corr_uq1 >> hw; + // x_UQ0 * corr_UQ1 = (x_UQ0_hw * 2^HW) * (hi_corr * 2^HW + lo_corr) - corr_UQ1 + let mut x_uq0: ::Int = ((((x_uq0_hw as u32) * hi_corr) << 1) + .wrapping_add(((x_uq0_hw as u32) * lo_corr) >> (hw - 1)) + .wrapping_sub(2)) + .cast(); // 1 to account for the highest bit of corr_UQ1 can be 1 + // 1 to account for possible carry + // Just like the case of half-width iterations but with possibility + // of overflowing by one extra Ulp of x_UQ0. + x_uq0 -= one; + // ... and then traditional fixup by 2 should work + + // On error estimation: + // abs(E_{N-1}) <= (u_{N-1} + 2 /* due to conversion e_n -> E_n */) * 2^-HW + // + (2^-HW + 2^-W)) + // abs(E_{N-1}) <= (u_{N-1} + 3.01) * 2^-HW + + // Then like for the half-width iterations: + // With 0 <= eps1, eps2 < 2^-W + // E_N = 4 * E_{N-1} * eps1 - (E_{N-1}^2 * b + 4 * eps2) + 4 * eps1 / b + // abs(E_N) <= 2^-W * [ 4 * abs(E_{N-1}) + max(2 * abs(E_{N-1})^2 * 2^W + 4, 8)) ] + // abs(E_N) <= 2^-W * [ 4 * (u_{N-1} + 3.01) * 2^-HW + max(4 + 2 * (u_{N-1} + 3.01)^2, 8) ] + x_uq0 } else { - quotient >>= 1; - (a_significand << significand_bits).wrapping_sub(quotient.wrapping_mul(b_significand)) + // C is (3/4 + 1/sqrt(2)) - 1 truncated to 32 fractional bits as UQ0.n + let c: ::Int = (0x7504F333 << (F::BITS - 32)).cast(); + let x_uq0: ::Int = c.wrapping_sub(b_uq1); + // E_0 <= 3/4 - 1/sqrt(2) + 2 * 2^-32 + x_uq0 + }; + + let mut x_uq0 = if USE_NATIVE_FULL_ITERATIONS { + for _ in 0..NUMBER_OF_FULL_ITERATIONS { + let corr_uq1: u32 = 0.wrapping_sub( + ((CastInto::::cast(x_uq0) as u64) * (CastInto::::cast(b_uq1) as u64)) + >> F::BITS, + ) as u32; + x_uq0 = ((((CastInto::::cast(x_uq0) as u64) * (corr_uq1 as u64)) >> (F::BITS - 1)) + as u32) + .cast(); + } + x_uq0 + } else { + // not using native full iterations + x_uq0 }; - let written_exponent = quotient_exponent.wrapping_add(exponent_bias as i32); + // Finally, account for possible overflow, as explained above. + x_uq0 = x_uq0.wrapping_sub(2.cast()); + + // u_n for different precisions (with N-1 half-width iterations): + // W0 is the precision of C + // u_0 = (3/4 - 1/sqrt(2) + 2^-W0) * 2^HW + + // Estimated with bc: + // define half1(un) { return 2.0 * (un + un^2) / 2.0^hw + 1.0; } + // define half2(un) { return 2.0 * un / 2.0^hw + 2.0; } + // define full1(un) { return 4.0 * (un + 3.01) / 2.0^hw + 2.0 * (un + 3.01)^2 + 4.0; } + // define full2(un) { return 4.0 * (un + 3.01) / 2.0^hw + 8.0; } + + // | f32 (0 + 3) | f32 (2 + 1) | f64 (3 + 1) | f128 (4 + 1) + // u_0 | < 184224974 | < 2812.1 | < 184224974 | < 791240234244348797 + // u_1 | < 15804007 | < 242.7 | < 15804007 | < 67877681371350440 + // u_2 | < 116308 | < 2.81 | < 116308 | < 499533100252317 + // u_3 | < 7.31 | | < 7.31 | < 27054456580 + // u_4 | | | | < 80.4 + // Final (U_N) | same as u_3 | < 72 | < 218 | < 13920 + + // Add 2 to U_N due to final decrement. + + let reciprocal_precision: ::Int = 10.cast(); + + // Suppose 1/b - P * 2^-W < x < 1/b + P * 2^-W + let x_uq0 = x_uq0 - reciprocal_precision; + // Now 1/b - (2*P) * 2^-W < x < 1/b + // FIXME Is x_UQ0 still >= 0.5? + + let mut quotient: ::Int = x_uq0.widen_mul(a_significand << 1).hi(); + // Now, a/b - 4*P * 2^-W < q < a/b for q= in UQ1.(SB+1+W). + + // quotient_UQ1 is in [0.5, 2.0) as UQ1.(SB+1), + // adjust it to be in [1.0, 2.0) as UQ1.SB. + let (mut residual, written_exponent) = if quotient < (implicit_bit << 1) { + // Highest bit is 0, so just reinterpret quotient_UQ1 as UQ1.SB, + // effectively doubling its value as well as its error estimation. + let residual_lo = (a_significand << (significand_bits + 1)).wrapping_sub( + (CastInto::::cast(quotient).wrapping_mul(CastInto::::cast(b_significand))) + .cast(), + ); + a_significand <<= 1; + (residual_lo, written_exponent.wrapping_sub(1)) + } else { + // Highest bit is 1 (the UQ1.(SB+1) value is in [1, 2)), convert it + // to UQ1.SB by right shifting by 1. Least significant bit is omitted. + quotient >>= 1; + let residual_lo = (a_significand << significand_bits).wrapping_sub( + (CastInto::::cast(quotient).wrapping_mul(CastInto::::cast(b_significand))) + .cast(), + ); + (residual_lo, written_exponent) + }; + //drop mutability + let quotient = quotient; + + // NB: residualLo is calculated above for the normal result case. + // It is re-computed on denormal path that is expected to be not so + // performance-sensitive. + + // Now, q cannot be greater than a/b and can differ by at most 8*P * 2^-W + 2^-SB + // Each NextAfter() increments the floating point value by at least 2^-SB + // (more, if exponent was incremented). + // Different cases (<---> is of 2^-SB length, * = a/b that is shown as a midpoint): + // q + // | | * | | | | | + // <---> 2^t + // | | | | | * | | + // q + // To require at most one NextAfter(), an error should be less than 1.5 * 2^-SB. + // (8*P) * 2^-W + 2^-SB < 1.5 * 2^-SB + // (8*P) * 2^-W < 0.5 * 2^-SB + // P < 2^(W-4-SB) + // Generally, for at most R NextAfter() to be enough, + // P < (2*R - 1) * 2^(W-4-SB) + // For f32 (0+3): 10 < 32 (OK) + // For f32 (2+1): 32 < 74 < 32 * 3, so two NextAfter() are required + // For f64: 220 < 256 (OK) + // For f128: 4096 * 3 < 13922 < 4096 * 5 (three NextAfter() are required) + + // If we have overflowed the exponent, return infinity if written_exponent >= max_exponent as i32 { - // If we have overflowed the exponent, return infinity. return F::from_repr(inf_rep | quotient_sign); - } else if written_exponent < 1 { - // Flush denormals to zero. In the future, it would be nice to add - // code to round them correctly. - return F::from_repr(quotient_sign); - } else { - let round = ((residual << 1) > b_significand) as u32; - // Clear the implicit bits - let mut abs_result = quotient & significand_mask; - // Insert the exponent - abs_result |= written_exponent.cast() << significand_bits; - // Round - abs_result = abs_result.wrapping_add(round.cast()); - // Insert the sign and return - return F::from_repr(abs_result | quotient_sign); } + + // Now, quotient <= the correctly-rounded result + // and may need taking NextAfter() up to 3 times (see error estimates above) + // r = a - b * q + let abs_result = if written_exponent > 0 { + let mut ret = quotient & significand_mask; + ret |= ((written_exponent as u32) << significand_bits).cast(); + residual <<= 1; + ret + } else { + if (significand_bits as i32 + written_exponent) < 0 { + return F::from_repr(quotient_sign); + } + let ret = quotient.wrapping_shr(negate_u32(CastInto::::cast(written_exponent)) + 1); + residual = (CastInto::::cast( + a_significand.wrapping_shl( + significand_bits.wrapping_add(CastInto::::cast(written_exponent)), + ), + ) + .wrapping_sub( + (CastInto::::cast(ret).wrapping_mul(CastInto::::cast(b_significand))) << 1, + )) + .cast(); + ret + }; + // Round + let abs_result = { + residual += abs_result & one; // tie to even + // The above line conditionally turns the below LT comparison into LTE + + if residual > b_significand { + abs_result + one + } else { + abs_result + } + }; + F::from_repr(abs_result | quotient_sign) } fn div64(a: F, b: F) -> F @@ -218,10 +464,15 @@ where F::Int: CastInto, F::Int: HInt, { + const NUMBER_OF_HALF_ITERATIONS: usize = 3; + const NUMBER_OF_FULL_ITERATIONS: usize = 1; + const USE_NATIVE_FULL_ITERATIONS: bool = false; + let one = F::Int::ONE; let zero = F::Int::ZERO; + let hw = F::BITS / 2; + let lo_mask = u64::MAX >> hw; - // let bits = F::BITS; let significand_bits = F::SIGNIFICAND_BITS; let max_exponent = F::EXPONENT_MAX; @@ -235,12 +486,6 @@ where let inf_rep = exponent_mask; let quiet_bit = implicit_bit >> 1; let qnan_rep = exponent_mask | quiet_bit; - // let exponent_bits = F::EXPONENT_BITS; - - #[inline(always)] - fn negate_u32(a: u32) -> u32 { - (::wrapping_neg(a as i32)) as u32 - } #[inline(always)] fn negate_u64(a: u64) -> u64 { @@ -320,128 +565,340 @@ where } } - // Or in the implicit significand bit. (If we fell through from the + // Set the implicit significand bit. If we fell through from the // denormal path it was already set by normalize( ), but setting it twice - // won't hurt anything.) + // won't hurt anything. a_significand |= implicit_bit; b_significand |= implicit_bit; - let mut quotient_exponent: i32 = CastInto::::cast(a_exponent) - .wrapping_sub(CastInto::::cast(b_exponent)) - .wrapping_add(scale); - - // Align the significand of b as a Q31 fixed-point number in the range - // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax - // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This - // is accurate to about 3.5 binary digits. - let q31b = CastInto::::cast(b_significand >> 21.cast()); - let mut recip32 = (0x7504f333u32).wrapping_sub(q31b); - - // Now refine the reciprocal estimate using a Newton-Raphson iteration: - // - // x1 = x0 * (2 - x0 * b) - // - // This doubles the number of correct binary digits in the approximation - // with each iteration, so after three iterations, we have about 28 binary - // digits of accuracy. - - let mut correction32: u32 = - negate_u32(((recip32 as u64).wrapping_mul(q31b as u64) >> 32) as u32); - recip32 = ((recip32 as u64).wrapping_mul(correction32 as u64) >> 31) as u32; - correction32 = negate_u32(((recip32 as u64).wrapping_mul(q31b as u64) >> 32) as u32); - recip32 = ((recip32 as u64).wrapping_mul(correction32 as u64) >> 31) as u32; - correction32 = negate_u32(((recip32 as u64).wrapping_mul(q31b as u64) >> 32) as u32); - recip32 = ((recip32 as u64).wrapping_mul(correction32 as u64) >> 31) as u32; - - // recip32 might have overflowed to exactly zero in the preceeding - // computation if the high word of b is exactly 1.0. This would sabotage - // the full-width final stage of the computation that follows, so we adjust - // recip32 downward by one bit. - recip32 = recip32.wrapping_sub(1); - - // We need to perform one more iteration to get us to 56 binary digits; - // The last iteration needs to happen with extra precision. - let q63blo = CastInto::::cast(b_significand << 11.cast()); - - let correction: u64 = negate_u64( - (recip32 as u64) - .wrapping_mul(q31b as u64) - .wrapping_add((recip32 as u64).wrapping_mul(q63blo as u64) >> 32), - ); - let c_hi = (correction >> 32) as u32; - let c_lo = correction as u32; - let mut reciprocal: u64 = (recip32 as u64) - .wrapping_mul(c_hi as u64) - .wrapping_add((recip32 as u64).wrapping_mul(c_lo as u64) >> 32); - - // We already adjusted the 32-bit estimate, now we need to adjust the final - // 64-bit reciprocal estimate downward to ensure that it is strictly smaller - // than the infinitely precise exact reciprocal. Because the computation - // of the Newton-Raphson step is truncating at every step, this adjustment - // is small; most of the work is already done. - reciprocal = reciprocal.wrapping_sub(2); - - // The numerical reciprocal is accurate to within 2^-56, lies in the - // interval [0.5, 1.0), and is strictly smaller than the true reciprocal - // of b. Multiplying a by this reciprocal thus gives a numerical q = a/b - // in Q53 with the following properties: - // - // 1. q < a/b - // 2. q is in the interval [0.5, 2.0) - // 3. the error in q is bounded away from 2^-53 (actually, we have a - // couple of bits to spare, but this is all we need). - - // We need a 64 x 64 multiply high to compute q, which isn't a basic - // operation in C, so we need to be a little bit fussy. - // let mut quotient: F::Int = ((((reciprocal as u64) - // .wrapping_mul(CastInto::::cast(a_significand << 1) as u64)) - // >> 32) as u32) - // .cast(); - - // We need a 64 x 64 multiply high to compute q, which isn't a basic - // operation in C, so we need to be a little bit fussy. - let mut quotient = (a_significand << 2).widen_mul(reciprocal.cast()).hi(); - - // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0). - // In either case, we are going to compute a residual of the form - // - // r = a - q*b + + let written_exponent: i64 = CastInto::::cast( + a_exponent + .wrapping_sub(b_exponent) + .wrapping_add(scale.cast()), + ) + .wrapping_add(exponent_bias as u64) as i64; + let b_uq1 = b_significand << (F::BITS - significand_bits - 1); + + // Align the significand of b as a UQ1.(n-1) fixed-point number in the range + // [1.0, 2.0) and get a UQ0.n approximate reciprocal using a small minimax + // polynomial approximation: x0 = 3/4 + 1/sqrt(2) - b/2. + // The max error for this approximation is achieved at endpoints, so + // abs(x0(b) - 1/b) <= abs(x0(1) - 1/1) = 3/4 - 1/sqrt(2) = 0.04289..., + // which is about 4.5 bits. + // The initial approximation is between x0(1.0) = 0.9571... and x0(2.0) = 0.4571... + + // Then, refine the reciprocal estimate using a quadratically converging + // Newton-Raphson iteration: + // x_{n+1} = x_n * (2 - x_n * b) // - // We know from the construction of q that r satisfies: + // Let b be the original divisor considered "in infinite precision" and + // obtained from IEEE754 representation of function argument (with the + // implicit bit set). Corresponds to rep_t-sized b_UQ1 represented in + // UQ1.(W-1). // - // 0 <= r < ulp(q)*b + // Let b_hw be an infinitely precise number obtained from the highest (HW-1) + // bits of divisor significand (with the implicit bit set). Corresponds to + // half_rep_t-sized b_UQ1_hw represented in UQ1.(HW-1) that is a **truncated** + // version of b_UQ1. // - // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we - // already have the correct result. The exact halfway case cannot occur. - // We also take this time to right shift quotient if it falls in the [1,2) - // range and adjust the exponent accordingly. - let residual = if quotient < (implicit_bit << 1) { - quotient_exponent = quotient_exponent.wrapping_sub(1); - (a_significand << (significand_bits + 1)).wrapping_sub(quotient.wrapping_mul(b_significand)) + // Let e_n := x_n - 1/b_hw + // E_n := x_n - 1/b + // abs(E_n) <= abs(e_n) + (1/b_hw - 1/b) + // = abs(e_n) + (b - b_hw) / (b*b_hw) + // <= abs(e_n) + 2 * 2^-HW + + // rep_t-sized iterations may be slower than the corresponding half-width + // variant depending on the handware and whether single/double/quad precision + // is selected. + // NB: Using half-width iterations increases computation errors due to + // rounding, so error estimations have to be computed taking the selected + // mode into account! + + let mut x_uq0 = if NUMBER_OF_HALF_ITERATIONS > 0 { + // Starting with (n-1) half-width iterations + let b_uq1_hw: u32 = + (CastInto::::cast(b_significand) >> (significand_bits + 1 - hw)) as u32; + + // C is (3/4 + 1/sqrt(2)) - 1 truncated to W0 fractional bits as UQ0.HW + // with W0 being either 16 or 32 and W0 <= HW. + // That is, C is the aforementioned 3/4 + 1/sqrt(2) constant (from which + // b/2 is subtracted to obtain x0) wrapped to [0, 1) range. + + // HW is at least 32. Shifting into the highest bits if needed. + let c_hw = (0x7504F333_u64 as u32).wrapping_shl(hw.wrapping_sub(32)); + + // b >= 1, thus an upper bound for 3/4 + 1/sqrt(2) - b/2 is about 0.9572, + // so x0 fits to UQ0.HW without wrapping. + let x_uq0_hw: u32 = { + let mut x_uq0_hw: u32 = c_hw.wrapping_sub(b_uq1_hw /* exact b_hw/2 as UQ0.HW */); + // dbg!(x_uq0_hw); + // An e_0 error is comprised of errors due to + // * x0 being an inherently imprecise first approximation of 1/b_hw + // * C_hw being some (irrational) number **truncated** to W0 bits + // Please note that e_0 is calculated against the infinitely precise + // reciprocal of b_hw (that is, **truncated** version of b). + // + // e_0 <= 3/4 - 1/sqrt(2) + 2^-W0 + + // By construction, 1 <= b < 2 + // f(x) = x * (2 - b*x) = 2*x - b*x^2 + // f'(x) = 2 * (1 - b*x) + // + // On the [0, 1] interval, f(0) = 0, + // then it increses until f(1/b) = 1 / b, maximum on (0, 1), + // then it decreses to f(1) = 2 - b + // + // Let g(x) = x - f(x) = b*x^2 - x. + // On (0, 1/b), g(x) < 0 <=> f(x) > x + // On (1/b, 1], g(x) > 0 <=> f(x) < x + // + // For half-width iterations, b_hw is used instead of b. + for _ in 0..NUMBER_OF_HALF_ITERATIONS { + // corr_UQ1_hw can be **larger** than 2 - b_hw*x by at most 1*Ulp + // of corr_UQ1_hw. + // "0.0 - (...)" is equivalent to "2.0 - (...)" in UQ1.(HW-1). + // On the other hand, corr_UQ1_hw should not overflow from 2.0 to 0.0 provided + // no overflow occurred earlier: ((rep_t)x_UQ0_hw * b_UQ1_hw >> HW) is + // expected to be strictly positive because b_UQ1_hw has its highest bit set + // and x_UQ0_hw should be rather large (it converges to 1/2 < 1/b_hw <= 1). + let corr_uq1_hw: u32 = + 0.wrapping_sub(((x_uq0_hw as u64).wrapping_mul(b_uq1_hw as u64)) >> hw) as u32; + // dbg!(corr_uq1_hw); + + // Now, we should multiply UQ0.HW and UQ1.(HW-1) numbers, naturally + // obtaining an UQ1.(HW-1) number and proving its highest bit could be + // considered to be 0 to be able to represent it in UQ0.HW. + // From the above analysis of f(x), if corr_UQ1_hw would be represented + // without any intermediate loss of precision (that is, in twice_rep_t) + // x_UQ0_hw could be at most [1.]000... if b_hw is exactly 1.0 and strictly + // less otherwise. On the other hand, to obtain [1.]000..., one have to pass + // 1/b_hw == 1.0 to f(x), so this cannot occur at all without overflow (due + // to 1.0 being not representable as UQ0.HW). + // The fact corr_UQ1_hw was virtually round up (due to result of + // multiplication being **first** truncated, then negated - to improve + // error estimations) can increase x_UQ0_hw by up to 2*Ulp of x_UQ0_hw. + x_uq0_hw = ((x_uq0_hw as u64).wrapping_mul(corr_uq1_hw as u64) >> (hw - 1)) as u32; + // dbg!(x_uq0_hw); + // Now, either no overflow occurred or x_UQ0_hw is 0 or 1 in its half_rep_t + // representation. In the latter case, x_UQ0_hw will be either 0 or 1 after + // any number of iterations, so just subtract 2 from the reciprocal + // approximation after last iteration. + + // In infinite precision, with 0 <= eps1, eps2 <= U = 2^-HW: + // corr_UQ1_hw = 2 - (1/b_hw + e_n) * b_hw + 2*eps1 + // = 1 - e_n * b_hw + 2*eps1 + // x_UQ0_hw = (1/b_hw + e_n) * (1 - e_n*b_hw + 2*eps1) - eps2 + // = 1/b_hw - e_n + 2*eps1/b_hw + e_n - e_n^2*b_hw + 2*e_n*eps1 - eps2 + // = 1/b_hw + 2*eps1/b_hw - e_n^2*b_hw + 2*e_n*eps1 - eps2 + // e_{n+1} = -e_n^2*b_hw + 2*eps1/b_hw + 2*e_n*eps1 - eps2 + // = 2*e_n*eps1 - (e_n^2*b_hw + eps2) + 2*eps1/b_hw + // \------ >0 -------/ \-- >0 ---/ + // abs(e_{n+1}) <= 2*abs(e_n)*U + max(2*e_n^2 + U, 2 * U) + } + // For initial half-width iterations, U = 2^-HW + // Let abs(e_n) <= u_n * U, + // then abs(e_{n+1}) <= 2 * u_n * U^2 + max(2 * u_n^2 * U^2 + U, 2 * U) + // u_{n+1} <= 2 * u_n * U + max(2 * u_n^2 * U + 1, 2) + + // Account for possible overflow (see above). For an overflow to occur for the + // first time, for "ideal" corr_UQ1_hw (that is, without intermediate + // truncation), the result of x_UQ0_hw * corr_UQ1_hw should be either maximum + // value representable in UQ0.HW or less by 1. This means that 1/b_hw have to + // be not below that value (see g(x) above), so it is safe to decrement just + // once after the final iteration. On the other hand, an effective value of + // divisor changes after this point (from b_hw to b), so adjust here. + x_uq0_hw.wrapping_sub(1_u32) + }; + + // Error estimations for full-precision iterations are calculated just + // as above, but with U := 2^-W and taking extra decrementing into account. + // We need at least one such iteration. + + // Simulating operations on a twice_rep_t to perform a single final full-width + // iteration. Using ad-hoc multiplication implementations to take advantage + // of particular structure of operands. + let blo: u64 = (CastInto::::cast(b_uq1)) & lo_mask; + // x_UQ0 = x_UQ0_hw * 2^HW - 1 + // x_UQ0 * b_UQ1 = (x_UQ0_hw * 2^HW) * (b_UQ1_hw * 2^HW + blo) - b_UQ1 + // + // <--- higher half ---><--- lower half ---> + // [x_UQ0_hw * b_UQ1_hw] + // + [ x_UQ0_hw * blo ] + // - [ b_UQ1 ] + // = [ result ][.... discarded ...] + let corr_uq1 = negate_u64( + (x_uq0_hw as u64) * (b_uq1_hw as u64) + (((x_uq0_hw as u64) * (blo)) >> hw) - 1, + ); // account for *possible* carry + let lo_corr = corr_uq1 & lo_mask; + let hi_corr = corr_uq1 >> hw; + // x_UQ0 * corr_UQ1 = (x_UQ0_hw * 2^HW) * (hi_corr * 2^HW + lo_corr) - corr_UQ1 + let mut x_uq0: ::Int = ((((x_uq0_hw as u64) * hi_corr) << 1) + .wrapping_add(((x_uq0_hw as u64) * lo_corr) >> (hw - 1)) + .wrapping_sub(2)) + .cast(); // 1 to account for the highest bit of corr_UQ1 can be 1 + // 1 to account for possible carry + // Just like the case of half-width iterations but with possibility + // of overflowing by one extra Ulp of x_UQ0. + x_uq0 -= one; + // ... and then traditional fixup by 2 should work + + // On error estimation: + // abs(E_{N-1}) <= (u_{N-1} + 2 /* due to conversion e_n -> E_n */) * 2^-HW + // + (2^-HW + 2^-W)) + // abs(E_{N-1}) <= (u_{N-1} + 3.01) * 2^-HW + + // Then like for the half-width iterations: + // With 0 <= eps1, eps2 < 2^-W + // E_N = 4 * E_{N-1} * eps1 - (E_{N-1}^2 * b + 4 * eps2) + 4 * eps1 / b + // abs(E_N) <= 2^-W * [ 4 * abs(E_{N-1}) + max(2 * abs(E_{N-1})^2 * 2^W + 4, 8)) ] + // abs(E_N) <= 2^-W * [ 4 * (u_{N-1} + 3.01) * 2^-HW + max(4 + 2 * (u_{N-1} + 3.01)^2, 8) ] + x_uq0 } else { - quotient >>= 1; - (a_significand << significand_bits).wrapping_sub(quotient.wrapping_mul(b_significand)) + // C is (3/4 + 1/sqrt(2)) - 1 truncated to 64 fractional bits as UQ0.n + let c: ::Int = (0x7504F333 << (F::BITS - 32)).cast(); + let x_uq0: ::Int = c.wrapping_sub(b_uq1); + // E_0 <= 3/4 - 1/sqrt(2) + 2 * 2^-64 + x_uq0 + }; + + let mut x_uq0 = if USE_NATIVE_FULL_ITERATIONS { + for _ in 0..NUMBER_OF_FULL_ITERATIONS { + let corr_uq1: u64 = 0.wrapping_sub( + (CastInto::::cast(x_uq0) * (CastInto::::cast(b_uq1))) >> F::BITS, + ); + x_uq0 = ((((CastInto::::cast(x_uq0) as u128) * (corr_uq1 as u128)) + >> (F::BITS - 1)) as u64) + .cast(); + } + x_uq0 + } else { + // not using native full iterations + x_uq0 }; - let written_exponent = quotient_exponent.wrapping_add(exponent_bias as i32); + // Finally, account for possible overflow, as explained above. + x_uq0 = x_uq0.wrapping_sub(2.cast()); + + // u_n for different precisions (with N-1 half-width iterations): + // W0 is the precision of C + // u_0 = (3/4 - 1/sqrt(2) + 2^-W0) * 2^HW + + // Estimated with bc: + // define half1(un) { return 2.0 * (un + un^2) / 2.0^hw + 1.0; } + // define half2(un) { return 2.0 * un / 2.0^hw + 2.0; } + // define full1(un) { return 4.0 * (un + 3.01) / 2.0^hw + 2.0 * (un + 3.01)^2 + 4.0; } + // define full2(un) { return 4.0 * (un + 3.01) / 2.0^hw + 8.0; } + + // | f32 (0 + 3) | f32 (2 + 1) | f64 (3 + 1) | f128 (4 + 1) + // u_0 | < 184224974 | < 2812.1 | < 184224974 | < 791240234244348797 + // u_1 | < 15804007 | < 242.7 | < 15804007 | < 67877681371350440 + // u_2 | < 116308 | < 2.81 | < 116308 | < 499533100252317 + // u_3 | < 7.31 | | < 7.31 | < 27054456580 + // u_4 | | | | < 80.4 + // Final (U_N) | same as u_3 | < 72 | < 218 | < 13920 + + // Add 2 to U_N due to final decrement. + + let reciprocal_precision: ::Int = 220.cast(); + + // Suppose 1/b - P * 2^-W < x < 1/b + P * 2^-W + let x_uq0 = x_uq0 - reciprocal_precision; + // Now 1/b - (2*P) * 2^-W < x < 1/b + // FIXME Is x_UQ0 still >= 0.5? + + let mut quotient: ::Int = x_uq0.widen_mul(a_significand << 1).hi(); + // Now, a/b - 4*P * 2^-W < q < a/b for q= in UQ1.(SB+1+W). + + // quotient_UQ1 is in [0.5, 2.0) as UQ1.(SB+1), + // adjust it to be in [1.0, 2.0) as UQ1.SB. + let (mut residual, written_exponent) = if quotient < (implicit_bit << 1) { + // Highest bit is 0, so just reinterpret quotient_UQ1 as UQ1.SB, + // effectively doubling its value as well as its error estimation. + let residual_lo = (a_significand << (significand_bits + 1)).wrapping_sub( + (CastInto::::cast(quotient).wrapping_mul(CastInto::::cast(b_significand))) + .cast(), + ); + a_significand <<= 1; + (residual_lo, written_exponent.wrapping_sub(1)) + } else { + // Highest bit is 1 (the UQ1.(SB+1) value is in [1, 2)), convert it + // to UQ1.SB by right shifting by 1. Least significant bit is omitted. + quotient >>= 1; + let residual_lo = (a_significand << significand_bits).wrapping_sub( + (CastInto::::cast(quotient).wrapping_mul(CastInto::::cast(b_significand))) + .cast(), + ); + (residual_lo, written_exponent) + }; - if written_exponent >= max_exponent as i32 { - // If we have overflowed the exponent, return infinity. + //drop mutability + let quotient = quotient; + + // NB: residualLo is calculated above for the normal result case. + // It is re-computed on denormal path that is expected to be not so + // performance-sensitive. + + // Now, q cannot be greater than a/b and can differ by at most 8*P * 2^-W + 2^-SB + // Each NextAfter() increments the floating point value by at least 2^-SB + // (more, if exponent was incremented). + // Different cases (<---> is of 2^-SB length, * = a/b that is shown as a midpoint): + // q + // | | * | | | | | + // <---> 2^t + // | | | | | * | | + // q + // To require at most one NextAfter(), an error should be less than 1.5 * 2^-SB. + // (8*P) * 2^-W + 2^-SB < 1.5 * 2^-SB + // (8*P) * 2^-W < 0.5 * 2^-SB + // P < 2^(W-4-SB) + // Generally, for at most R NextAfter() to be enough, + // P < (2*R - 1) * 2^(W-4-SB) + // For f32 (0+3): 10 < 32 (OK) + // For f32 (2+1): 32 < 74 < 32 * 3, so two NextAfter() are required + // For f64: 220 < 256 (OK) + // For f128: 4096 * 3 < 13922 < 4096 * 5 (three NextAfter() are required) + + // If we have overflowed the exponent, return infinity + if written_exponent >= max_exponent as i64 { return F::from_repr(inf_rep | quotient_sign); - } else if written_exponent < 1 { - // Flush denormals to zero. In the future, it would be nice to add - // code to round them correctly. - return F::from_repr(quotient_sign); - } else { - let round = ((residual << 1) > b_significand) as u32; - // Clear the implicit bits - let mut abs_result = quotient & significand_mask; - // Insert the exponent - abs_result |= written_exponent.cast() << significand_bits; - // Round - abs_result = abs_result.wrapping_add(round.cast()); - // Insert the sign and return - return F::from_repr(abs_result | quotient_sign); } + + // Now, quotient <= the correctly-rounded result + // and may need taking NextAfter() up to 3 times (see error estimates above) + // r = a - b * q + let abs_result = if written_exponent > 0 { + let mut ret = quotient & significand_mask; + ret |= ((written_exponent as u64) << significand_bits).cast(); + residual <<= 1; + ret + } else { + if (significand_bits as i64 + written_exponent) < 0 { + return F::from_repr(quotient_sign); + } + let ret = + quotient.wrapping_shr((negate_u64(CastInto::::cast(written_exponent)) + 1) as u32); + residual = (CastInto::::cast( + a_significand.wrapping_shl( + significand_bits.wrapping_add(CastInto::::cast(written_exponent)), + ), + ) + .wrapping_sub( + (CastInto::::cast(ret).wrapping_mul(CastInto::::cast(b_significand))) << 1, + )) + .cast(); + ret + }; + // Round + let abs_result = { + residual += abs_result & one; // tie to even + // conditionally turns the below LT comparison into LTE + if residual > b_significand { + abs_result + one + } else { + abs_result + } + }; + F::from_repr(abs_result | quotient_sign) } intrinsics! { diff --git a/library/compiler-builtins/testcrate/tests/div_rem.rs b/library/compiler-builtins/testcrate/tests/div_rem.rs index c3f0676400ed8..de3bd9bee8f1f 100644 --- a/library/compiler-builtins/testcrate/tests/div_rem.rs +++ b/library/compiler-builtins/testcrate/tests/div_rem.rs @@ -109,7 +109,16 @@ macro_rules! float { fuzz_float_2(N, |x: $i, y: $i| { let quo0 = x / y; let quo1: $i = $fn(x, y); - // division of subnormals is not currently handled + #[cfg(not(target_arch = "arm"))] + if !Float::eq_repr(quo0, quo1) { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn), x, y, quo0, quo1 + ); + } + + // ARM SIMD instructions always flush subnormals to zero + #[cfg(target_arch = "arm")] if !(Float::is_subnormal(quo0) || Float::is_subnormal(quo1)) { if !Float::eq_repr(quo0, quo1) { panic!( From 1a41e48d11a1d764d905047d38e80c591500d624 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 27 Jun 2023 02:31:42 +0000 Subject: [PATCH 1124/4206] fix tests to work with `--feature c` --- library/compiler-builtins/src/aarch64.rs | 1 + library/compiler-builtins/src/lib.rs | 6 +----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/src/aarch64.rs b/library/compiler-builtins/src/aarch64.rs index ddbec6d327bd6..62144e53199be 100644 --- a/library/compiler-builtins/src/aarch64.rs +++ b/library/compiler-builtins/src/aarch64.rs @@ -22,6 +22,7 @@ //! //! The original `lse.S` has some truly horrifying code that expects to be compiled multiple times with different constants. //! We do something similar, but with macro arguments. +#![cfg_attr(feature = "c", allow(unused_macros))] // avoid putting the macros into a submodule // We don't do runtime dispatch so we don't have to worry about the `__aarch64_have_lse_atomics` global ctor. diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 4b44adc266d88..2e5c587fb958c 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -57,11 +57,7 @@ pub mod mem; #[cfg(target_arch = "arm")] pub mod arm; -#[cfg(all( - target_arch = "aarch64", - not(feature = "no-asm"), - not(feature = "optimized-c") -))] +#[cfg(all(target_arch = "aarch64", not(feature = "no-asm"),))] pub mod aarch64; #[cfg(all( From c6fa74aacb1d516124c2914c429378ce32c6a414 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 28 Jun 2023 21:35:33 +0200 Subject: [PATCH 1125/4206] enable simple f32/f64 support needed by core library --- library/compiler-builtins/src/lib.rs | 1 + library/compiler-builtins/src/math.rs | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 71f249c8eb34f..729b1ec54bf35 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -48,6 +48,7 @@ pub mod int; all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "arm", target_os = "none"), all(target_arch = "xtensa", target_os = "none"), + all(target_arch = "mips", target_os = "none"), target_os = "xous", all(target_vendor = "fortanix", target_env = "sgx") ))] diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 498e4d85ff09e..b4e5fc1138b70 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -136,11 +136,12 @@ no_mangle! { fn truncf(x: f32) -> f32; } -// only for the thumb*-none-eabi*, riscv32*-none-elf and x86_64-unknown-none targets that lack the floating point instruction set +// only for the thumb*-none-eabi*, riscv32*-none-elf, x86_64-unknown-none and mips*-unknown-none targets that lack the floating point instruction set #[cfg(any( all(target_arch = "arm", target_os = "none"), all(target_arch = "riscv32", not(target_feature = "f"), target_os = "none"), - all(target_arch = "x86_64", target_os = "none") + all(target_arch = "x86_64", target_os = "none"), + all(target_arch = "mips", target_os = "none"), ))] no_mangle! { fn fmin(x: f64, y: f64) -> f64; From 9234bedeea54889aa7f5d9dc477b9c00af0c527c Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 28 Jun 2023 23:44:06 +0100 Subject: [PATCH 1126/4206] Bump to 0.1.94 --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/libm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 6cfa2b99e38b3..c468bdf758618 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.93" +version = "0.1.94" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 1dbb9d2d476d6..4c8a973741c01 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 1dbb9d2d476d65d020feca17b11391652038e2e1 +Subproject commit 4c8a973741c014b11ce7f1477693a3e5d4ef9609 From c4e9f479add8a54dce33069e43814426843099d9 Mon Sep 17 00:00:00 2001 From: jyn Date: Sun, 2 Jul 2023 14:43:25 -0500 Subject: [PATCH 1127/4206] Only compile outlined-atomics intrinsics on linux --- .../src/{aarch64.rs => aarch64_linux.rs} | 0 library/compiler-builtins/src/lib.rs | 4 ++-- library/compiler-builtins/testcrate/tests/lse.rs | 12 ++++++++---- 3 files changed, 10 insertions(+), 6 deletions(-) rename library/compiler-builtins/src/{aarch64.rs => aarch64_linux.rs} (100%) diff --git a/library/compiler-builtins/src/aarch64.rs b/library/compiler-builtins/src/aarch64_linux.rs similarity index 100% rename from library/compiler-builtins/src/aarch64.rs rename to library/compiler-builtins/src/aarch64_linux.rs diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 58603a57c002a..a6b61bdf5fcd7 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -58,8 +58,8 @@ pub mod mem; #[cfg(target_arch = "arm")] pub mod arm; -#[cfg(all(target_arch = "aarch64", not(feature = "no-asm"),))] -pub mod aarch64; +#[cfg(all(target_arch = "aarch64", target_os = "linux", not(feature = "no-asm"),))] +pub mod aarch64_linux; #[cfg(all( kernel_user_helpers, diff --git a/library/compiler-builtins/testcrate/tests/lse.rs b/library/compiler-builtins/testcrate/tests/lse.rs index 7b54ab5d2865c..5589f22f1e93e 100644 --- a/library/compiler-builtins/testcrate/tests/lse.rs +++ b/library/compiler-builtins/testcrate/tests/lse.rs @@ -17,7 +17,9 @@ mod cas { testcrate::fuzz_2(10000, |expected: super::int_ty!($bytes), new| { let mut target = expected.wrapping_add(10); assert_eq!( - unsafe { compiler_builtins::aarch64::$name::$name(expected, new, &mut target) }, + unsafe { + compiler_builtins::aarch64_linux::$name::$name(expected, new, &mut target) + }, expected.wrapping_add(10), "return value should always be the previous value", ); @@ -29,7 +31,9 @@ mod cas { target = expected; assert_eq!( - unsafe { compiler_builtins::aarch64::$name::$name(expected, new, &mut target) }, + unsafe { + compiler_builtins::aarch64_linux::$name::$name(expected, new, &mut target) + }, expected ); assert_eq!(target, new, "should have updated target"); @@ -49,7 +53,7 @@ mod swap { testcrate::fuzz_2(10000, |left: super::int_ty!($bytes), mut right| { let orig_right = right; assert_eq!( - unsafe { compiler_builtins::aarch64::$name::$name(left, &mut right) }, + unsafe { compiler_builtins::aarch64_linux::$name::$name(left, &mut right) }, orig_right ); assert_eq!(left, right); @@ -69,7 +73,7 @@ macro_rules! test_op { let mut target = old; let op: fn(super::int_ty!($bytes), super::int_ty!($bytes)) -> _ = $($op)*; let expected = op(old, val); - assert_eq!(old, unsafe { compiler_builtins::aarch64::$name::$name(val, &mut target) }, "{} should return original value", stringify!($name)); + assert_eq!(old, unsafe { compiler_builtins::aarch64_linux::$name::$name(val, &mut target) }, "{} should return original value", stringify!($name)); assert_eq!(expected, target, "{} should store to target", stringify!($name)); }); } From 8a3c3942a544313af237a739e3648581702dfa4c Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 3 Jul 2023 10:45:20 +0200 Subject: [PATCH 1128/4206] Bump to 0.1.95 --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/libm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index c468bdf758618..52c1ee39a822f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.94" +version = "0.1.95" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 4c8a973741c01..1dbb9d2d476d6 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 4c8a973741c014b11ce7f1477693a3e5d4ef9609 +Subproject commit 1dbb9d2d476d65d020feca17b11391652038e2e1 From 28f24376147d3fae9959d4d3143dccf21998cb06 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 6 Jul 2023 20:20:19 +0200 Subject: [PATCH 1129/4206] Disable MIPS in CI See https://github.com/rust-lang/compiler-team/issues/648 --- .../.github/workflows/main.yml | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 3d63bc070cda5..b69c48c16a955 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -23,18 +23,20 @@ jobs: - target: i686-unknown-linux-gnu os: ubuntu-latest rust: nightly - - target: mips-unknown-linux-gnu - os: ubuntu-latest - rust: nightly - - target: mips64-unknown-linux-gnuabi64 - os: ubuntu-latest - rust: nightly - - target: mips64el-unknown-linux-gnuabi64 - os: ubuntu-latest - rust: nightly - - target: mipsel-unknown-linux-gnu - os: ubuntu-latest - rust: nightly + # MIPS targets disabled since they are dropped to tier 3. + # See https://github.com/rust-lang/compiler-team/issues/648 + #- target: mips-unknown-linux-gnu + # os: ubuntu-latest + # rust: nightly + #- target: mips64-unknown-linux-gnuabi64 + # os: ubuntu-latest + # rust: nightly + #- target: mips64el-unknown-linux-gnuabi64 + # os: ubuntu-latest + # rust: nightly + #- target: mipsel-unknown-linux-gnu + # os: ubuntu-latest + # rust: nightly - target: powerpc-unknown-linux-gnu os: ubuntu-latest rust: nightly From 025076f763405d3d2a9e05716b9b055ee8b52155 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Thu, 6 Jul 2023 01:51:47 -0500 Subject: [PATCH 1130/4206] Use the target_feature "zbb" instead of "b" for RISC-V --- library/compiler-builtins/src/int/specialized_div_rem/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index 77034eb5476e9..1ff1d19dc8c2f 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -95,8 +95,9 @@ const USE_LZ: bool = { // LZD or LZCNT on SPARC only exists for the VIS 3 extension and later. cfg!(target_feature = "vis3") } else if cfg!(any(target_arch = "riscv32", target_arch = "riscv64")) { - // The `B` extension on RISC-V determines if a CLZ assembly instruction exists - cfg!(target_feature = "b") + // The 'Zbb' Basic Bit-Manipulation extension on RISC-V + // determines if a CLZ assembly instruction exists + cfg!(target_feature = "zbb") } else { // All other common targets Rust supports should have CLZ instructions true From e2f0b9cd3ade182c6b92782e781b31328b972cfb Mon Sep 17 00:00:00 2001 From: Andrew Kane Date: Fri, 7 Jul 2023 10:49:54 -0400 Subject: [PATCH 1131/4206] Add lgamma_r and lgammaf_r to MSVC --- library/compiler-builtins/src/math.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index b4e5fc1138b70..4e255ca1a34ca 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -95,7 +95,8 @@ no_mangle! { target_os = "xous", all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "xtensa", target_os = "none"), - all(target_vendor = "fortanix", target_env = "sgx") + all(target_vendor = "fortanix", target_env = "sgx"), + target_env = "msvc" ))] intrinsics! { pub extern "C" fn lgamma_r(x: f64, s: &mut i32) -> f64 { From 716d2064f0b144b6c704a5d689457a3af0ff1733 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sat, 8 Jul 2023 14:18:27 +0900 Subject: [PATCH 1132/4206] Fix build error on aarch64_be linux --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 4549d0b4f166c..26db6b4be9a3c 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -91,7 +91,7 @@ fn main() { println!("cargo:rustc-cfg=kernel_user_helpers") } - if llvm_target[0] == "aarch64" { + if llvm_target[0].starts_with("aarch64") { generate_aarch64_outlined_atomics(); } } From 5cc74482b40b4c88368114e4edfcb36f1335a857 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 17 Jul 2023 13:51:40 +0100 Subject: [PATCH 1133/4206] Bump to 0.1.96 --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/libm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 52c1ee39a822f..6c6c8d1365e70 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.95" +version = "0.1.96" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 1dbb9d2d476d6..4c8a973741c01 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 1dbb9d2d476d65d020feca17b11391652038e2e1 +Subproject commit 4c8a973741c014b11ce7f1477693a3e5d4ef9609 From 7eca0c2ba3f5e4d606aac99e7717ad98b3db2f91 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Tue, 18 Jul 2023 21:59:39 -0400 Subject: [PATCH 1134/4206] Enable chkstk/alloca intrinsics on x86_64-unknown-uefi --- library/compiler-builtins/src/x86_64.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 393eeddd877ad..7ad94115825a1 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -11,8 +11,7 @@ use core::intrinsics; intrinsics! { #[naked] #[cfg(all( - windows, - target_env = "gnu", + any(all(windows, target_env = "gnu"), target_os = "uefi"), not(feature = "no-asm") ))] pub unsafe extern "C" fn ___chkstk_ms() { @@ -40,8 +39,7 @@ intrinsics! { #[naked] #[cfg(all( - windows, - target_env = "gnu", + any(all(windows, target_env = "gnu"), target_os = "uefi"), not(feature = "no-asm") ))] pub unsafe extern "C" fn __alloca() { @@ -54,8 +52,7 @@ intrinsics! { #[naked] #[cfg(all( - windows, - target_env = "gnu", + any(all(windows, target_env = "gnu"), target_os = "uefi"), not(feature = "no-asm") ))] pub unsafe extern "C" fn ___chkstk() { From 2a14bca476c42884837051e6359302a7da08cf24 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 21 Jul 2023 14:29:00 +0100 Subject: [PATCH 1135/4206] Bump to 0.1.97 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 6c6c8d1365e70..d95a69530ad24 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.96" +version = "0.1.97" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 2b29ddcca785a937c5b02e61dd4170a9dc922ee0 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 21 Jul 2023 17:45:47 +0100 Subject: [PATCH 1136/4206] Upgrade to libm 0.2.7 --- library/compiler-builtins/libm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 4c8a973741c01..1dbb9d2d476d6 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 4c8a973741c014b11ce7f1477693a3e5d4ef9609 +Subproject commit 1dbb9d2d476d65d020feca17b11391652038e2e1 From 05ca9048adad29393892b6ef0728b8e80c625343 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 21 Jul 2023 17:46:23 +0100 Subject: [PATCH 1137/4206] Bump to 0.1.98 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index d95a69530ad24..d1072fe6dbdba 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.97" +version = "0.1.98" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From da052339350055721f0cd721042a5fa4a3766707 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 22 Jul 2023 15:05:30 -0400 Subject: [PATCH 1138/4206] Add __chkstk for aarch64-unknown-uefi This is based on compiler-rt/lib/builtins/aarch64/chkstk.S: https://github.com/llvm/llvm-project/commit/f8e19b37995751f7913692bf9eed8ebb14a95f2d --- library/compiler-builtins/src/aarch64.rs | 22 ++++++++++++++++++++++ library/compiler-builtins/src/lib.rs | 3 +++ 2 files changed, 25 insertions(+) create mode 100644 library/compiler-builtins/src/aarch64.rs diff --git a/library/compiler-builtins/src/aarch64.rs b/library/compiler-builtins/src/aarch64.rs new file mode 100644 index 0000000000000..e5747d5258f73 --- /dev/null +++ b/library/compiler-builtins/src/aarch64.rs @@ -0,0 +1,22 @@ +#![allow(unused_imports)] + +use core::intrinsics; + +intrinsics! { + #[naked] + #[cfg(all(target_os = "uefi", not(feature = "no-asm")))] + pub unsafe extern "C" fn __chkstk() { + core::arch::asm!( + ".p2align 2", + "lsl x16, x15, #4", + "mov x17, sp", + "1:", + "sub x17, x17, 4096", + "subs x16, x16, 4096", + "ldr xzr, [x17]", + "b.gt 1b", + "ret", + options(noreturn) + ); + } +} diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index a6b61bdf5fcd7..f77f08268cadd 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -58,6 +58,9 @@ pub mod mem; #[cfg(target_arch = "arm")] pub mod arm; +#[cfg(target_arch = "aarch64")] +pub mod aarch64; + #[cfg(all(target_arch = "aarch64", target_os = "linux", not(feature = "no-asm"),))] pub mod aarch64_linux; From d4477f8218d5521c0e3a3a72748ce846baa5dfdc Mon Sep 17 00:00:00 2001 From: Andrew Kane Date: Sun, 30 Jul 2023 10:45:26 -0700 Subject: [PATCH 1139/4206] Add lgamma_r and lgammaf_r to MSVC --- library/compiler-builtins/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index f77f08268cadd..73cb3d505d2c1 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -50,7 +50,8 @@ pub mod int; all(target_arch = "xtensa", target_os = "none"), all(target_arch = "mips", target_os = "none"), target_os = "xous", - all(target_vendor = "fortanix", target_env = "sgx") + all(target_vendor = "fortanix", target_env = "sgx"), + target_env = "msvc" ))] pub mod math; pub mod mem; From 0db7a3a020f9f0694c6411715ba17f5be0367bc1 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 30 Jul 2023 23:56:13 +0100 Subject: [PATCH 1140/4206] Bump to 0.1.99 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index d1072fe6dbdba..dde57030f116b 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.98" +version = "0.1.99" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 2a197cb5c9c46d2b389e6a46eb26c7321e81b114 Mon Sep 17 00:00:00 2001 From: Andrew Kane Date: Mon, 31 Jul 2023 15:08:37 -0700 Subject: [PATCH 1141/4206] Add lgamma_r and lgammaf_r to MinGW --- library/compiler-builtins/src/lib.rs | 2 +- library/compiler-builtins/src/math.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 73cb3d505d2c1..dd81608f2e06f 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -51,7 +51,7 @@ pub mod int; all(target_arch = "mips", target_os = "none"), target_os = "xous", all(target_vendor = "fortanix", target_env = "sgx"), - target_env = "msvc" + target_os = "windows" ))] pub mod math; pub mod mem; diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 4e255ca1a34ca..e0f7d8e8b6624 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -96,7 +96,7 @@ no_mangle! { all(target_arch = "x86_64", target_os = "uefi"), all(target_arch = "xtensa", target_os = "none"), all(target_vendor = "fortanix", target_env = "sgx"), - target_env = "msvc" + target_os = "windows" ))] intrinsics! { pub extern "C" fn lgamma_r(x: f64, s: &mut i32) -> f64 { From c52ae9d5974b08f6455c33c0a87c1e995184c4f5 Mon Sep 17 00:00:00 2001 From: mulhern Date: Wed, 2 Aug 2023 14:05:07 -0400 Subject: [PATCH 1142/4206] Exclude ci directory from packaged crate I do not think there is compelling reason to release the ci support as part of a Rust source code package. In addition, the crate, as it is released now, gets flagged in some security scans due to the presence of Dockerfiles which are considered to be following some unsafe practices. Most Linux distros package using the vendored appraoch and provide a vendor tarfile of an application's dependencies. Scanners will tend to expect that the contents of the vendor tarfile will be source code. These Dockerfiles are already being flagged by some scanners; other contents of the ci directory may be flagged in future. --- library/compiler-builtins/libm/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 393d95e4af266..50e6ed6e22254 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -10,6 +10,7 @@ readme = "README.md" repository = "https://github.com/rust-lang/libm" version = "0.2.7" edition = "2018" +exclude = ["/ci/"] [features] default = [] From 54577e0039af34884e9a8f98e7e9103efe173766 Mon Sep 17 00:00:00 2001 From: mulhern Date: Thu, 3 Aug 2023 15:05:28 -0400 Subject: [PATCH 1143/4206] Exclude GitHub Workflows files from packaged crate --- library/compiler-builtins/libm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 50e6ed6e22254..12126c6d085bb 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -10,7 +10,7 @@ readme = "README.md" repository = "https://github.com/rust-lang/libm" version = "0.2.7" edition = "2018" -exclude = ["/ci/"] +exclude = ["/ci/", "/.github/workflows/"] [features] default = [] From dd34581ec9062dd91bcc93e1934fe021fee9a328 Mon Sep 17 00:00:00 2001 From: klensy Date: Thu, 20 Jul 2023 17:23:56 +0300 Subject: [PATCH 1144/4206] edition 2018 --- library/compiler-builtins/Cargo.toml | 1 + library/compiler-builtins/src/arm.rs | 6 +++--- library/compiler-builtins/src/float/add.rs | 4 ++-- library/compiler-builtins/src/float/cmp.rs | 4 ++-- library/compiler-builtins/src/float/div.rs | 4 ++-- library/compiler-builtins/src/float/extend.rs | 4 ++-- library/compiler-builtins/src/float/mul.rs | 4 ++-- library/compiler-builtins/src/float/pow.rs | 4 ++-- library/compiler-builtins/src/float/sub.rs | 6 +++--- library/compiler-builtins/src/float/trunc.rs | 4 ++-- library/compiler-builtins/src/int/addsub.rs | 2 +- library/compiler-builtins/src/int/mul.rs | 2 +- library/compiler-builtins/src/int/sdiv.rs | 2 +- library/compiler-builtins/src/int/shift.rs | 2 +- library/compiler-builtins/src/int/udiv.rs | 4 ++-- library/compiler-builtins/src/macros.rs | 8 ++++---- library/compiler-builtins/src/math.rs | 1 + 17 files changed, 32 insertions(+), 30 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index dde57030f116b..bc8528087d1bc 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -7,6 +7,7 @@ readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" homepage = "https://github.com/rust-lang/compiler-builtins" documentation = "https://docs.rs/compiler_builtins" +edition = "2018" description = """ Compiler intrinsics used by the Rust compiler. Also available for other targets if necessary! diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index a062a54e008bc..cc67642e16bc3 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -91,7 +91,7 @@ intrinsics! { #[weak] #[cfg(not(target_os = "ios"))] pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { - ::mem::memcpy(dest, src, n); + crate::mem::memcpy(dest, src, n); } #[weak] @@ -121,7 +121,7 @@ intrinsics! { #[weak] #[cfg(not(target_os = "ios"))] pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { - ::mem::memmove(dest, src, n); + crate::mem::memmove(dest, src, n); } #[weak] @@ -140,7 +140,7 @@ intrinsics! { #[cfg(not(target_os = "ios"))] pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { // Note the different argument order - ::mem::memset(dest, c, n); + crate::mem::memset(dest, c, n); } #[weak] diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 67f6c2c1489fa..804f4b5100b7a 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -1,5 +1,5 @@ -use float::Float; -use int::{CastInto, Int}; +use crate::float::Float; +use crate::int::{CastInto, Int}; /// Returns `a + b` fn add(a: F, b: F) -> F diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 1bd7aa284d872..1c8917af8adff 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -1,7 +1,7 @@ #![allow(unreachable_code)] -use float::Float; -use int::Int; +use crate::float::Float; +use crate::int::Int; #[derive(Clone, Copy)] enum Result { diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index c0aae34fb639d..8c4cf55b8d334 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -2,8 +2,8 @@ // `return`s makes it clear where function exit points are #![allow(clippy::needless_return)] -use float::Float; -use int::{CastInto, DInt, HInt, Int}; +use crate::float::Float; +use crate::int::{CastInto, DInt, HInt, Int}; fn div32(a: F, b: F) -> F where diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index 39633773b2578..cffc57510e605 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -1,5 +1,5 @@ -use float::Float; -use int::{CastInto, Int}; +use crate::float::Float; +use crate::int::{CastInto, Int}; /// Generic conversion from a narrower to a wider IEEE-754 floating-point type fn extend(a: F) -> R diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index c89f22756af70..1b8c61203e632 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -1,5 +1,5 @@ -use float::Float; -use int::{CastInto, DInt, HInt, Int}; +use crate::float::Float; +use crate::int::{CastInto, DInt, HInt, Int}; fn mul(a: F, b: F) -> F where diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index a75340c3093a9..0232ef405d168 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -1,5 +1,5 @@ -use float::Float; -use int::Int; +use crate::float::Float; +use crate::int::Int; /// Returns `a` raised to the power `b` fn pow(a: F, b: i32) -> F { diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index 8d300e9d248be..0ea071b3ce969 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -1,6 +1,6 @@ -use float::add::__adddf3; -use float::add::__addsf3; -use float::Float; +use crate::float::add::__adddf3; +use crate::float::add::__addsf3; +use crate::float::Float; intrinsics! { #[arm_aeabi_alias = __aeabi_fsub] diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index d73713084d6c6..9bc4d6e57e1b1 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -1,5 +1,5 @@ -use float::Float; -use int::{CastInto, Int}; +use crate::float::Float; +use crate::int::{CastInto, Int}; fn trunc(a: F) -> R where diff --git a/library/compiler-builtins/src/int/addsub.rs b/library/compiler-builtins/src/int/addsub.rs index f4841e90f632e..f31eff4bd03ec 100644 --- a/library/compiler-builtins/src/int/addsub.rs +++ b/library/compiler-builtins/src/int/addsub.rs @@ -1,4 +1,4 @@ -use int::{DInt, Int}; +use crate::int::{DInt, Int}; trait UAddSub: DInt { fn uadd(self, other: Self) -> Self { diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 07ce061c994f8..2538e2f4181b2 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -1,4 +1,4 @@ -use int::{DInt, HInt, Int}; +use crate::int::{DInt, HInt, Int}; trait Mul: DInt where diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index f1822f0f86e87..9d316c76ecad3 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -1,4 +1,4 @@ -use int::udiv::*; +use crate::int::udiv::*; macro_rules! sdivmod { ( diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index c90cf1de3205e..dbd0401873201 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -1,4 +1,4 @@ -use int::{DInt, HInt, Int}; +use crate::int::{DInt, HInt, Int}; trait Ashl: DInt { /// Returns `a << b`, requires `b < Self::BITS` diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index fb09f87d89cdf..c891eede4b1aa 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -1,8 +1,8 @@ #[cfg(not(feature = "public-test-deps"))] -pub(crate) use int::specialized_div_rem::*; +pub(crate) use crate::int::specialized_div_rem::*; #[cfg(feature = "public-test-deps")] -pub use int::specialized_div_rem::*; +pub use crate::int::specialized_div_rem::*; intrinsics! { #[maybe_use_optimized_c_shim] diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index b11114f123880..d2b5734d5254a 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -321,10 +321,10 @@ macro_rules! intrinsics { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] pub extern $abi fn $name( $($argname: $ty),* ) - -> ::macros::win64_128bit_abi_hack::U64x2 + -> $crate::macros::win64_128bit_abi_hack::U64x2 { let e: $($ret)? = super::$name($($argname),*); - ::macros::win64_128bit_abi_hack::U64x2::from(e) + $crate::macros::win64_128bit_abi_hack::U64x2::from(e) } } @@ -540,7 +540,7 @@ pub mod win64_128bit_abi_hack { impl From for U64x2 { fn from(i: i128) -> U64x2 { - use int::DInt; + use crate::int::DInt; let j = i as u128; U64x2(j.lo(), j.hi()) } @@ -548,7 +548,7 @@ pub mod win64_128bit_abi_hack { impl From for U64x2 { fn from(i: u128) -> U64x2 { - use int::DInt; + use crate::int::DInt; U64x2(i.lo(), i.hi()) } } diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 4e255ca1a34ca..21d23ff978fe2 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -2,6 +2,7 @@ #[path = "../libm/src/math/mod.rs"] mod libm; +#[allow(unused_macros)] macro_rules! no_mangle { ($(fn $fun:ident($($iid:ident : $ity:ty),+) -> $oty:ty;)+) => { intrinsics! { From 10f6ee84e38143e2d54c03f6e70a918ad8edd8e4 Mon Sep 17 00:00:00 2001 From: klensy Date: Mon, 7 Aug 2023 17:52:27 +0300 Subject: [PATCH 1145/4206] allow internal_features, added in https://github.com/rust-lang/rust/pull/108955 --- library/compiler-builtins/examples/intrinsics.rs | 1 + library/compiler-builtins/src/lib.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 19bb569b57dc4..54b703dfbc72a 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -5,6 +5,7 @@ #![allow(unused_features)] #![allow(stable_features)] // bench_black_box feature is stable, leaving for backcompat +#![allow(internal_features)] #![cfg_attr(thumb, no_main)] #![deny(dead_code)] #![feature(bench_black_box)] diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 73cb3d505d2c1..2ef28fc63309b 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -14,6 +14,7 @@ #![no_builtins] #![no_std] #![allow(unused_features)] +#![allow(internal_features)] // We use `u128` in a whole bunch of places which we currently agree with the // compiler on ABIs and such, so we should be "good enough" for now and changes // to the `u128` ABI will be reflected here. From a15a3a5df00da818d5a39b63d79a318d034c5dc4 Mon Sep 17 00:00:00 2001 From: klensy Date: Mon, 7 Aug 2023 21:19:25 +0300 Subject: [PATCH 1146/4206] impl_binary_long allow to pass attribute --- .../src/int/specialized_div_rem/binary_long.rs | 4 ++++ library/compiler-builtins/src/int/specialized_div_rem/mod.rs | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs b/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs index 0d7822882b060..2c61a45e06e0a 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs @@ -13,9 +13,13 @@ macro_rules! impl_binary_long { $n:tt, // the number of bits in a $iX or $uX $uX:ident, // unsigned integer type for the inputs and outputs of `$fn` $iX:ident // signed integer type with same bitwidth as `$uX` + $(, $fun_attr:meta)* // attributes for the function ) => { /// Computes the quotient and remainder of `duo` divided by `div` and returns them as a /// tuple. + $( + #[$fun_attr] + )* pub fn $fn(duo: $uX, div: $uX) -> ($uX, $uX) { let mut duo = duo; // handle edge cases before calling `$normalization_shift` diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index 1ff1d19dc8c2f..760f5f5b7a326 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -306,5 +306,6 @@ impl_binary_long!( u32_normalization_shift, 32, u32, - i32 + i32, + allow(dead_code) ); From ceffc1c25fc59994d072404ba5b67341db012be8 Mon Sep 17 00:00:00 2001 From: klensy Date: Mon, 7 Aug 2023 21:51:34 +0300 Subject: [PATCH 1147/4206] fix ci, disable mips, mirrors https://github.com/rust-lang/compiler-builtins/pull/537 --- library/compiler-builtins/libm/.github/workflows/main.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index decd71f5c7a07..5408ac23fb494 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -13,9 +13,11 @@ jobs: - arm-unknown-linux-gnueabihf - armv7-unknown-linux-gnueabihf # - i686-unknown-linux-gnu - - mips-unknown-linux-gnu - - mips64-unknown-linux-gnuabi64 - - mips64el-unknown-linux-gnuabi64 + # MIPS targets disabled since they are dropped to tier 3. + # See https://github.com/rust-lang/compiler-team/issues/648 + #- mips-unknown-linux-gnu + #- mips64-unknown-linux-gnuabi64 + #- mips64el-unknown-linux-gnuabi64 - powerpc-unknown-linux-gnu - powerpc64-unknown-linux-gnu - powerpc64le-unknown-linux-gnu From 14f4e11a86c857426cba130bb333d9d2a193aad5 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 7 Aug 2023 23:37:59 +0100 Subject: [PATCH 1148/4206] Bump to 0.1.100 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index bc8528087d1bc..797857d76450b 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.99" +version = "0.1.100" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 10df3f61ad291eee4a3c8e6e1129601acf18b011 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Thu, 10 Aug 2023 13:50:04 +0800 Subject: [PATCH 1149/4206] build: compile memory intrinsics on xous Like SGX, Xous does not have any libc to link against. As a result, memory intrinsics need to be available as part of `compiler_builtins` Signed-off-by: Sean Cross --- library/compiler-builtins/build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 26db6b4be9a3c..10c7aaa63e013 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -30,6 +30,7 @@ fn main() { || target.contains("-none") || target.contains("nvptx") || target.contains("uefi") + || target.contains("xous") { println!("cargo:rustc-cfg=feature=\"mem\""); } From 5642f6ba4c4b0d4aaffa3499247ea1ae1f9faeb4 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 12 Aug 2023 10:28:45 +0200 Subject: [PATCH 1150/4206] Bump to 0.1.101 --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/libm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 797857d76450b..239191a9bce47 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.100" +version = "0.1.101" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 1dbb9d2d476d6..5bcbc3b636b79 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 1dbb9d2d476d65d020feca17b11391652038e2e1 +Subproject commit 5bcbc3b636b79da7a3061b1c257d4ae53f033018 From 6595f3631751b622ace9e83745edd9dbcca89c65 Mon Sep 17 00:00:00 2001 From: James Farrell Date: Mon, 28 Aug 2023 22:14:18 +0000 Subject: [PATCH 1151/4206] Generate outlined_atomics.rs in a deterministic order. Also add a missing newline. --- library/compiler-builtins/build.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 10c7aaa63e013..b60181062a783 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, env, sync::atomic::Ordering}; +use std::{collections::BTreeMap, env, sync::atomic::Ordering}; fn main() { println!("cargo:rerun-if-changed=build.rs"); @@ -118,7 +118,7 @@ fn generate_aarch64_outlined_atomics() { // Generate different macros for add/clr/eor/set so that we can test them separately. let sym_names = ["cas", "ldadd", "ldclr", "ldeor", "ldset", "swp"]; - let mut macros = HashMap::new(); + let mut macros = BTreeMap::new(); for sym in sym_names { macros.insert(sym, gen_macro(sym)); } @@ -146,7 +146,7 @@ fn generate_aarch64_outlined_atomics() { let mut buf = String::new(); for macro_def in macros.values().chain(std::iter::once(&cas16)) { buf += macro_def; - buf += "}; }"; + buf += "}; }\n"; } let dst = std::env::var("OUT_DIR").unwrap() + "/outlined_atomics.rs"; std::fs::write(dst, buf).unwrap(); From 36e334dfb02a0c072005e8836a9364137b517ee9 Mon Sep 17 00:00:00 2001 From: Peter Michael Green Date: Thu, 5 Oct 2023 17:38:44 +0000 Subject: [PATCH 1152/4206] Fix rint and rintf on x87. --- library/compiler-builtins/libm/src/math/rint.rs | 14 ++++++++++++-- library/compiler-builtins/libm/src/math/rintf.rs | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index 0c6025c1f73d4..8edbe34402232 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -8,9 +8,19 @@ pub fn rint(x: f64) -> f64 { x } else { let ans = if is_positive { - x + one_over_e - one_over_e + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let x = force_eval!(x); + let xplusoneovere = x + one_over_e; + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let xplusoneovere = force_eval!(xplusoneovere); + xplusoneovere - one_over_e } else { - x - one_over_e + one_over_e + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let x = force_eval!(x); + let xminusoneovere = x - one_over_e; + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let xminusoneovere = force_eval!(xminusoneovere); + xminusoneovere + one_over_e }; if ans == 0.0 { diff --git a/library/compiler-builtins/libm/src/math/rintf.rs b/library/compiler-builtins/libm/src/math/rintf.rs index d427793f7fc61..7a7da618ad8f6 100644 --- a/library/compiler-builtins/libm/src/math/rintf.rs +++ b/library/compiler-builtins/libm/src/math/rintf.rs @@ -8,9 +8,19 @@ pub fn rintf(x: f32) -> f32 { x } else { let ans = if is_positive { - x + one_over_e - one_over_e + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let x = force_eval!(x); + let xplusoneovere = x + one_over_e; + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let xplusoneovere = force_eval!(xplusoneovere); + xplusoneovere - one_over_e } else { - x - one_over_e + one_over_e + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let x = force_eval!(x); + let xminusoneovere = x - one_over_e; + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + let xminusoneovere = force_eval!(xminusoneovere); + xminusoneovere + one_over_e }; if ans == 0.0 { From 5531828bfceeb8d794e6445aa0a8c50adca9d331 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 6 Oct 2023 11:25:38 +0200 Subject: [PATCH 1153/4206] Release 0.2.8 --- library/compiler-builtins/libm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 12126c6d085bb..d33ca61cd4785 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/libm" -version = "0.2.7" +version = "0.2.8" edition = "2018" exclude = ["/ci/", "/.github/workflows/"] From 25fa91e1b249218b5df895c725273888b5e68147 Mon Sep 17 00:00:00 2001 From: Sebastian Imlay Date: Fri, 6 Oct 2023 17:35:20 -0400 Subject: [PATCH 1154/4206] Add tvOS to build script --- library/compiler-builtins/build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index b60181062a783..0486116778c0c 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -320,6 +320,7 @@ mod c { // include them. if target_os != "ios" && target_os != "watchos" + && target_os != "tvos" && (target_vendor != "apple" || target_arch != "x86") { sources.extend(&[ @@ -391,6 +392,7 @@ mod c { if target_arch == "arm" && target_os != "ios" && target_os != "watchos" + && target_os != "tvos" && target_env != "msvc" { sources.extend(&[ From de2da94c49d4ad76b29bb3ccb6b4966e2440522b Mon Sep 17 00:00:00 2001 From: Grant Elbert Date: Mon, 23 Oct 2023 15:54:05 -0500 Subject: [PATCH 1155/4206] intrinsics macro: fix non-weak aeabi generation Signed-off-by: Grant Elbert --- library/compiler-builtins/src/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index d2b5734d5254a..2aa9a742c57ca 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -369,7 +369,7 @@ macro_rules! intrinsics { #[cfg(target_arch = "arm")] pub mod $alias { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - #[cfg_attr(any(all(not(windows), not(target_vendor="apple"), feature = "weak-intrinsics")), linkage = "weak")] + #[cfg_attr(any(all(not(windows), not(target_vendor="apple")), feature = "weak-intrinsics"), linkage = "weak")] pub extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } From e8509dd054bf960bde4de66f76829a755a0c46a9 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Fri, 27 Oct 2023 20:19:55 +0000 Subject: [PATCH 1156/4206] Enable src/math for all UEFI targets This fixes various math operations on aarch64-unknown-uefi and i686-unknown-uefi. --- library/compiler-builtins/src/lib.rs | 2 +- library/compiler-builtins/src/math.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index d1195a4a83de3..e2e35fbd324a3 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -46,7 +46,7 @@ pub mod int; #[cfg(any( all(target_family = "wasm", target_os = "unknown"), all(target_arch = "x86_64", target_os = "none"), - all(target_arch = "x86_64", target_os = "uefi"), + target_os = "uefi", all(target_arch = "arm", target_os = "none"), all(target_arch = "xtensa", target_os = "none"), all(target_arch = "mips", target_os = "none"), diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index f8f9d225bea94..63d85833393e0 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -22,7 +22,7 @@ macro_rules! no_mangle { not(target_env = "wasi") ), target_os = "xous", - all(target_arch = "x86_64", target_os = "uefi"), + target_os = "uefi", all(target_arch = "xtensa", target_os = "none"), all(target_vendor = "fortanix", target_env = "sgx") ))] @@ -94,7 +94,7 @@ no_mangle! { not(target_env = "wasi") ), target_os = "xous", - all(target_arch = "x86_64", target_os = "uefi"), + target_os = "uefi", all(target_arch = "xtensa", target_os = "none"), all(target_vendor = "fortanix", target_env = "sgx"), target_os = "windows" From 8ec53915fefeed8fc1656573e1ffea859fefbdc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Chodzikiewicz?= Date: Tue, 31 Oct 2023 20:32:53 +0100 Subject: [PATCH 1157/4206] Enable math module for all "none" os targets This was initially a bugfix that fixed gating math module for riscv32, but conclusiion is it makes no sense to gate on target architecture. --- library/compiler-builtins/src/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index e2e35fbd324a3..3e54918782be6 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -45,11 +45,8 @@ pub mod int; #[cfg(any( all(target_family = "wasm", target_os = "unknown"), - all(target_arch = "x86_64", target_os = "none"), target_os = "uefi", - all(target_arch = "arm", target_os = "none"), - all(target_arch = "xtensa", target_os = "none"), - all(target_arch = "mips", target_os = "none"), + target_os = "none", target_os = "xous", all(target_vendor = "fortanix", target_env = "sgx"), target_os = "windows" From 7a32a99352cc6001c24c8bff0885c0d0cb937678 Mon Sep 17 00:00:00 2001 From: "Mark S. Baranowski" Date: Tue, 31 Oct 2023 15:59:56 -0600 Subject: [PATCH 1158/4206] This updates the exponent calculations done in the nextafter functions related to detecting underflow/overflow. The functions now match the behavior of the MUSL implementations these were based on. Fixes rust-lang/libm#286 --- library/compiler-builtins/libm/src/math/nextafter.rs | 2 +- library/compiler-builtins/libm/src/math/nextafterf.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/nextafter.rs b/library/compiler-builtins/libm/src/math/nextafter.rs index 13094a17c34b5..05762619109a2 100644 --- a/library/compiler-builtins/libm/src/math/nextafter.rs +++ b/library/compiler-builtins/libm/src/math/nextafter.rs @@ -23,7 +23,7 @@ pub fn nextafter(x: f64, y: f64) -> f64 { ux_i += 1; } - let e = ux_i.wrapping_shr(52 & 0x7ff); + let e = ux_i >> 52 & 0x7ff; // raise overflow if ux.f is infinite and x is finite if e == 0x7ff { force_eval!(x + x); diff --git a/library/compiler-builtins/libm/src/math/nextafterf.rs b/library/compiler-builtins/libm/src/math/nextafterf.rs index df9b1082978a3..8ba3833562fbe 100644 --- a/library/compiler-builtins/libm/src/math/nextafterf.rs +++ b/library/compiler-builtins/libm/src/math/nextafterf.rs @@ -23,7 +23,7 @@ pub fn nextafterf(x: f32, y: f32) -> f32 { ux_i += 1; } - let e = ux_i.wrapping_shr(0x7f80_0000_u32); + let e = ux_i & 0x7f80_0000_u32; // raise overflow if ux_f is infinite and x is finite if e == 0x7f80_0000_u32 { force_eval!(x + x); From 44d0e30db9aeb6eba2da5bf888f255b2d3b2ed5d Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 4 Nov 2023 00:28:36 +0000 Subject: [PATCH 1159/4206] Bump to 0.1.102 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 239191a9bce47..320a4c1fe3cb5 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.101" +version = "0.1.102" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 52959b58006bc4b746384a36e8ddea2ad4f1b630 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 4 Nov 2023 00:29:27 +0000 Subject: [PATCH 1160/4206] Bump to 0.1.103 There was a mistake in publishing the 0.1.102 release. --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 320a4c1fe3cb5..5a022cc4b84b5 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.102" +version = "0.1.103" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From c2c4c8e146ec7127d9fa0fc3f27da56dba9597ab Mon Sep 17 00:00:00 2001 From: Patryk Wychowaniec Date: Sun, 26 Nov 2023 16:17:00 +0100 Subject: [PATCH 1161/4206] fix: Add (even more) `#[avr_skip]` for floats Tale as old as the world - there's an ABI mismatch: https://github.com/rust-lang/compiler-builtins/pull/527 Fortunately, newest GCCs (from v11, it seems) actually provide most of those intrinsics (even for f64!), so that's pretty cool. (the only intrinsics not provided by GCC are `__powisf2` & `__powidf2`, but our codegen for AVR doesn't emit those anyway.) Fixes https://github.com/rust-lang/rust/issues/118079. --- library/compiler-builtins/src/float/div.rs | 2 ++ library/compiler-builtins/src/float/extend.rs | 1 + library/compiler-builtins/src/float/mul.rs | 2 ++ library/compiler-builtins/src/float/pow.rs | 2 ++ library/compiler-builtins/src/float/sub.rs | 2 ++ library/compiler-builtins/src/float/trunc.rs | 1 + 6 files changed, 10 insertions(+) diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index 8c4cf55b8d334..d587fe4f98f67 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -902,11 +902,13 @@ where } intrinsics! { + #[avr_skip] #[arm_aeabi_alias = __aeabi_fdiv] pub extern "C" fn __divsf3(a: f32, b: f32) -> f32 { div32(a, b) } + #[avr_skip] #[arm_aeabi_alias = __aeabi_ddiv] pub extern "C" fn __divdf3(a: f64, b: f64) -> f64 { div64(a, b) diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index cffc57510e605..0e6673b9c095d 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -70,6 +70,7 @@ where } intrinsics! { + #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_f2d] pub extern "C" fn __extendsfdf2(a: f32) -> f64 { diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index 1b8c61203e632..378fa970116fe 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -185,12 +185,14 @@ where } intrinsics! { + #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_fmul] pub extern "C" fn __mulsf3(a: f32, b: f32) -> f32 { mul(a, b) } + #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_dmul] pub extern "C" fn __muldf3(a: f64, b: f64) -> f64 { diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index 0232ef405d168..3103fe6f6972c 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -26,10 +26,12 @@ fn pow(a: F, b: i32) -> F { } intrinsics! { + #[avr_skip] pub extern "C" fn __powisf2(a: f32, b: i32) -> f32 { pow(a, b) } + #[avr_skip] pub extern "C" fn __powidf2(a: f64, b: i32) -> f64 { pow(a, b) } diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index 0ea071b3ce969..64653ee25ff19 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -3,11 +3,13 @@ use crate::float::add::__addsf3; use crate::float::Float; intrinsics! { + #[avr_skip] #[arm_aeabi_alias = __aeabi_fsub] pub extern "C" fn __subsf3(a: f32, b: f32) -> f32 { __addsf3(a, f32::from_repr(b.repr() ^ f32::SIGN_MASK)) } + #[avr_skip] #[arm_aeabi_alias = __aeabi_dsub] pub extern "C" fn __subdf3(a: f64, b: f64) -> f64 { __adddf3(a, f64::from_repr(b.repr() ^ f64::SIGN_MASK)) diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index 9bc4d6e57e1b1..0beeb9f98de1f 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -112,6 +112,7 @@ where } intrinsics! { + #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_d2f] pub extern "C" fn __truncdfsf2(a: f64) -> f32 { From d46758a18f9122956723b115b58f2cb4f30f4b6e Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 28 Nov 2023 08:02:43 +0000 Subject: [PATCH 1162/4206] Bump to 0.1.104 --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/libm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 5a022cc4b84b5..6ebabfdcbebaf 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.103" +version = "0.1.104" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 5bcbc3b636b79..721a5edc1be6b 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 5bcbc3b636b79da7a3061b1c257d4ae53f033018 +Subproject commit 721a5edc1be6b0412e4b1704590aed76f9a55899 From c4a7058a1193584f156f83f141e56c53e7720ab0 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sun, 5 Nov 2023 18:42:34 -0800 Subject: [PATCH 1163/4206] Add hexagon support Signed-off-by: Brian Cain --- library/compiler-builtins/src/hexagon.rs | 55 ++ .../compiler-builtins/src/hexagon/dfaddsub.s | 321 +++++++++++ library/compiler-builtins/src/hexagon/dfdiv.s | 372 ++++++++++++ library/compiler-builtins/src/hexagon/dffma.s | 536 ++++++++++++++++++ .../compiler-builtins/src/hexagon/dfminmax.s | 51 ++ library/compiler-builtins/src/hexagon/dfmul.s | 309 ++++++++++ .../compiler-builtins/src/hexagon/dfsqrt.s | 277 +++++++++ .../compiler-builtins/src/hexagon/divdi3.s | 64 +++ .../compiler-builtins/src/hexagon/divsi3.s | 53 ++ .../src/hexagon/fastmath2_dlib_asm.s | 266 +++++++++ .../src/hexagon/fastmath2_ldlib_asm.s | 187 ++++++ .../src/hexagon/func_macro.s | 12 + .../src/hexagon/memcpy_forward_vp4cp4n2.s | 91 +++ .../src/hexagon/memcpy_likely_aligned.s | 42 ++ .../compiler-builtins/src/hexagon/moddi3.s | 63 ++ .../compiler-builtins/src/hexagon/modsi3.s | 44 ++ .../compiler-builtins/src/hexagon/sfdiv_opt.s | 42 ++ .../src/hexagon/sfsqrt_opt.s | 49 ++ .../compiler-builtins/src/hexagon/udivdi3.s | 50 ++ .../src/hexagon/udivmoddi4.s | 50 ++ .../src/hexagon/udivmodsi4.s | 39 ++ .../compiler-builtins/src/hexagon/udivsi3.s | 36 ++ .../compiler-builtins/src/hexagon/umoddi3.s | 53 ++ .../compiler-builtins/src/hexagon/umodsi3.s | 34 ++ library/compiler-builtins/src/lib.rs | 4 + 25 files changed, 3100 insertions(+) create mode 100644 library/compiler-builtins/src/hexagon.rs create mode 100644 library/compiler-builtins/src/hexagon/dfaddsub.s create mode 100644 library/compiler-builtins/src/hexagon/dfdiv.s create mode 100644 library/compiler-builtins/src/hexagon/dffma.s create mode 100644 library/compiler-builtins/src/hexagon/dfminmax.s create mode 100644 library/compiler-builtins/src/hexagon/dfmul.s create mode 100644 library/compiler-builtins/src/hexagon/dfsqrt.s create mode 100644 library/compiler-builtins/src/hexagon/divdi3.s create mode 100644 library/compiler-builtins/src/hexagon/divsi3.s create mode 100644 library/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s create mode 100644 library/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s create mode 100644 library/compiler-builtins/src/hexagon/func_macro.s create mode 100644 library/compiler-builtins/src/hexagon/memcpy_forward_vp4cp4n2.s create mode 100644 library/compiler-builtins/src/hexagon/memcpy_likely_aligned.s create mode 100644 library/compiler-builtins/src/hexagon/moddi3.s create mode 100644 library/compiler-builtins/src/hexagon/modsi3.s create mode 100644 library/compiler-builtins/src/hexagon/sfdiv_opt.s create mode 100644 library/compiler-builtins/src/hexagon/sfsqrt_opt.s create mode 100644 library/compiler-builtins/src/hexagon/udivdi3.s create mode 100644 library/compiler-builtins/src/hexagon/udivmoddi4.s create mode 100644 library/compiler-builtins/src/hexagon/udivmodsi4.s create mode 100644 library/compiler-builtins/src/hexagon/udivsi3.s create mode 100644 library/compiler-builtins/src/hexagon/umoddi3.s create mode 100644 library/compiler-builtins/src/hexagon/umodsi3.s diff --git a/library/compiler-builtins/src/hexagon.rs b/library/compiler-builtins/src/hexagon.rs new file mode 100644 index 0000000000000..91cf91c314219 --- /dev/null +++ b/library/compiler-builtins/src/hexagon.rs @@ -0,0 +1,55 @@ +#![cfg(not(feature = "no-asm"))] + +use core::arch::global_asm; + +global_asm!(include_str!("hexagon/func_macro.s"), options(raw)); + +global_asm!(include_str!("hexagon/dfaddsub.s"), options(raw)); + +global_asm!(include_str!("hexagon/dfdiv.s"), options(raw)); + +global_asm!(include_str!("hexagon/dffma.s"), options(raw)); + +global_asm!(include_str!("hexagon/dfminmax.s"), options(raw)); + +global_asm!(include_str!("hexagon/dfmul.s"), options(raw)); + +global_asm!(include_str!("hexagon/dfsqrt.s"), options(raw)); + +global_asm!(include_str!("hexagon/divdi3.s"), options(raw)); + +global_asm!(include_str!("hexagon/divsi3.s"), options(raw)); + +global_asm!(include_str!("hexagon/fastmath2_dlib_asm.s"), options(raw)); + +global_asm!(include_str!("hexagon/fastmath2_ldlib_asm.s"), options(raw)); + +global_asm!( + include_str!("hexagon/memcpy_forward_vp4cp4n2.s"), + options(raw) +); + +global_asm!( + include_str!("hexagon/memcpy_likely_aligned.s"), + options(raw) +); + +global_asm!(include_str!("hexagon/moddi3.s"), options(raw)); + +global_asm!(include_str!("hexagon/modsi3.s"), options(raw)); + +global_asm!(include_str!("hexagon/sfdiv_opt.s"), options(raw)); + +global_asm!(include_str!("hexagon/sfsqrt_opt.s"), options(raw)); + +global_asm!(include_str!("hexagon/udivdi3.s"), options(raw)); + +global_asm!(include_str!("hexagon/udivmoddi4.s"), options(raw)); + +global_asm!(include_str!("hexagon/udivmodsi4.s"), options(raw)); + +global_asm!(include_str!("hexagon/udivsi3.s"), options(raw)); + +global_asm!(include_str!("hexagon/umoddi3.s"), options(raw)); + +global_asm!(include_str!("hexagon/umodsi3.s"), options(raw)); diff --git a/library/compiler-builtins/src/hexagon/dfaddsub.s b/library/compiler-builtins/src/hexagon/dfaddsub.s new file mode 100644 index 0000000000000..1f59e460be61c --- /dev/null +++ b/library/compiler-builtins/src/hexagon/dfaddsub.s @@ -0,0 +1,321 @@ + .text + .global __hexagon_adddf3 + .global __hexagon_subdf3 + .type __hexagon_adddf3, @function + .type __hexagon_subdf3, @function + +.global __qdsp_adddf3 ; .set __qdsp_adddf3, __hexagon_adddf3 +.global __hexagon_fast_adddf3 ; .set __hexagon_fast_adddf3, __hexagon_adddf3 +.global __hexagon_fast2_adddf3 ; .set __hexagon_fast2_adddf3, __hexagon_adddf3 +.global __qdsp_subdf3 ; .set __qdsp_subdf3, __hexagon_subdf3 +.global __hexagon_fast_subdf3 ; .set __hexagon_fast_subdf3, __hexagon_subdf3 +.global __hexagon_fast2_subdf3 ; .set __hexagon_fast2_subdf3, __hexagon_subdf3 + + .p2align 5 +__hexagon_adddf3: + { + r4 = extractu(r1,#11,#20) + r5 = extractu(r3,#11,#20) + r13:12 = combine(##0x20000000,#0) + } + { + p3 = dfclass(r1:0,#2) + p3 = dfclass(r3:2,#2) + r9:8 = r13:12 + p2 = cmp.gtu(r5,r4) + } + { + if (!p3) jump .Ladd_abnormal + if (p2) r1:0 = r3:2 + if (p2) r3:2 = r1:0 + if (p2) r5:4 = combine(r4,r5) + } + { + r13:12 = insert(r1:0,#52,#11 -2) + r9:8 = insert(r3:2,#52,#11 -2) + r15 = sub(r4,r5) + r7:6 = combine(#62,#1) + } + + + + + +.Ladd_continue: + { + r15 = min(r15,r7) + + r11:10 = neg(r13:12) + p2 = cmp.gt(r1,#-1) + r14 = #0 + } + { + if (!p2) r13:12 = r11:10 + r11:10 = extractu(r9:8,r15:14) + r9:8 = ASR(r9:8,r15) + + + + + r15:14 = #0 + } + { + p1 = cmp.eq(r11:10,r15:14) + if (!p1.new) r8 = or(r8,r6) + r5 = add(r4,#-1024 -60) + p3 = cmp.gt(r3,#-1) + } + { + r13:12 = add(r13:12,r9:8) + r11:10 = sub(r13:12,r9:8) + r7:6 = combine(#54,##2045) + } + { + p0 = cmp.gtu(r4,r7) + p0 = !cmp.gtu(r4,r6) + if (!p0.new) jump:nt .Ladd_ovf_unf + if (!p3) r13:12 = r11:10 + } + { + r1:0 = convert_d2df(r13:12) + p0 = cmp.eq(r13,#0) + p0 = cmp.eq(r12,#0) + if (p0.new) jump:nt .Ladd_zero + } + { + r1 += asl(r5,#20) + jumpr r31 + } + .falign +__hexagon_subdf3: + { + r3 = togglebit(r3,#31) + jump __qdsp_adddf3 + } + + + .falign +.Ladd_zero: + + + { + r28 = USR + r1:0 = #0 + r3 = #1 + } + { + r28 = extractu(r28,#2,#22) + r3 = asl(r3,#31) + } + { + p0 = cmp.eq(r28,#2) + if (p0.new) r1 = xor(r1,r3) + jumpr r31 + } + .falign +.Ladd_ovf_unf: + { + r1:0 = convert_d2df(r13:12) + p0 = cmp.eq(r13,#0) + p0 = cmp.eq(r12,#0) + if (p0.new) jump:nt .Ladd_zero + } + { + r28 = extractu(r1,#11,#20) + r1 += asl(r5,#20) + } + { + r5 = add(r5,r28) + r3:2 = combine(##0x00100000,#0) + } + { + p0 = cmp.gt(r5,##1024 +1024 -2) + if (p0.new) jump:nt .Ladd_ovf + } + { + p0 = cmp.gt(r5,#0) + if (p0.new) jumpr:t r31 + r28 = sub(#1,r5) + } + { + r3:2 = insert(r1:0,#52,#0) + r1:0 = r13:12 + } + { + r3:2 = lsr(r3:2,r28) + } + { + r1:0 = insert(r3:2,#63,#0) + jumpr r31 + } + .falign +.Ladd_ovf: + + { + r1:0 = r13:12 + r28 = USR + r13:12 = combine(##0x7fefffff,#-1) + } + { + r5 = extractu(r28,#2,#22) + r28 = or(r28,#0x28) + r9:8 = combine(##0x7ff00000,#0) + } + { + USR = r28 + r5 ^= lsr(r1,#31) + r28 = r5 + } + { + p0 = !cmp.eq(r28,#1) + p0 = !cmp.eq(r5,#2) + if (p0.new) r13:12 = r9:8 + } + { + r1:0 = insert(r13:12,#63,#0) + } + { + p0 = dfcmp.eq(r1:0,r1:0) + jumpr r31 + } + +.Ladd_abnormal: + { + r13:12 = extractu(r1:0,#63,#0) + r9:8 = extractu(r3:2,#63,#0) + } + { + p3 = cmp.gtu(r13:12,r9:8) + if (!p3.new) r1:0 = r3:2 + if (!p3.new) r3:2 = r1:0 + } + { + + p0 = dfclass(r1:0,#0x0f) + if (!p0.new) jump:nt .Linvalid_nan_add + if (!p3) r13:12 = r9:8 + if (!p3) r9:8 = r13:12 + } + { + + + p1 = dfclass(r1:0,#0x08) + if (p1.new) jump:nt .Linf_add + } + { + p2 = dfclass(r3:2,#0x01) + if (p2.new) jump:nt .LB_zero + r13:12 = #0 + } + + { + p0 = dfclass(r1:0,#4) + if (p0.new) jump:nt .Ladd_two_subnormal + r13:12 = combine(##0x20000000,#0) + } + { + r4 = extractu(r1,#11,#20) + r5 = #1 + + r9:8 = asl(r9:8,#11 -2) + } + + + + { + r13:12 = insert(r1:0,#52,#11 -2) + r15 = sub(r4,r5) + r7:6 = combine(#62,#1) + jump .Ladd_continue + } + +.Ladd_two_subnormal: + { + r13:12 = extractu(r1:0,#63,#0) + r9:8 = extractu(r3:2,#63,#0) + } + { + r13:12 = neg(r13:12) + r9:8 = neg(r9:8) + p0 = cmp.gt(r1,#-1) + p1 = cmp.gt(r3,#-1) + } + { + if (p0) r13:12 = r1:0 + if (p1) r9:8 = r3:2 + } + { + r13:12 = add(r13:12,r9:8) + } + { + r9:8 = neg(r13:12) + p0 = cmp.gt(r13,#-1) + r3:2 = #0 + } + { + if (!p0) r1:0 = r9:8 + if (p0) r1:0 = r13:12 + r3 = ##0x80000000 + } + { + if (!p0) r1 = or(r1,r3) + p0 = dfcmp.eq(r1:0,r3:2) + if (p0.new) jump:nt .Lzero_plus_zero + } + { + jumpr r31 + } + +.Linvalid_nan_add: + { + r28 = convert_df2sf(r1:0) + p0 = dfclass(r3:2,#0x0f) + if (p0.new) r3:2 = r1:0 + } + { + r2 = convert_df2sf(r3:2) + r1:0 = #-1 + jumpr r31 + } + .falign +.LB_zero: + { + p0 = dfcmp.eq(r13:12,r1:0) + if (!p0.new) jumpr:t r31 + } + + + + +.Lzero_plus_zero: + { + p0 = cmp.eq(r1:0,r3:2) + if (p0.new) jumpr:t r31 + } + { + r28 = USR + } + { + r28 = extractu(r28,#2,#22) + r1:0 = #0 + } + { + p0 = cmp.eq(r28,#2) + if (p0.new) r1 = ##0x80000000 + jumpr r31 + } +.Linf_add: + + { + p0 = !cmp.eq(r1,r3) + p0 = dfclass(r3:2,#8) + if (!p0.new) jumpr:t r31 + } + { + r2 = ##0x7f800001 + } + { + r1:0 = convert_sf2df(r2) + jumpr r31 + } +.size __hexagon_adddf3,.-__hexagon_adddf3 diff --git a/library/compiler-builtins/src/hexagon/dfdiv.s b/library/compiler-builtins/src/hexagon/dfdiv.s new file mode 100644 index 0000000000000..6d65dbfc4df1d --- /dev/null +++ b/library/compiler-builtins/src/hexagon/dfdiv.s @@ -0,0 +1,372 @@ + .text + .global __hexagon_divdf3 + .type __hexagon_divdf3,@function + .global __qdsp_divdf3 ; .set __qdsp_divdf3, __hexagon_divdf3 + .global __hexagon_fast_divdf3 ; .set __hexagon_fast_divdf3, __hexagon_divdf3 + .global __hexagon_fast2_divdf3 ; .set __hexagon_fast2_divdf3, __hexagon_divdf3 + .p2align 5 +__hexagon_divdf3: + { + p2 = dfclass(r1:0,#0x02) + p2 = dfclass(r3:2,#0x02) + r13:12 = combine(r3,r1) + r28 = xor(r1,r3) + } + { + if (!p2) jump .Ldiv_abnormal + r7:6 = extractu(r3:2,#23,#52 -23) + r8 = ##0x3f800001 + } + { + r9 = or(r8,r6) + r13 = extractu(r13,#11,#52 -32) + r12 = extractu(r12,#11,#52 -32) + p3 = cmp.gt(r28,#-1) + } + + +.Ldenorm_continue: + { + r11,p0 = sfrecipa(r8,r9) + r10 = and(r8,#-2) + r28 = #1 + r12 = sub(r12,r13) + } + + + { + r10 -= sfmpy(r11,r9):lib + r1 = insert(r28,#11 +1,#52 -32) + r13 = ##0x00800000 << 3 + } + { + r11 += sfmpy(r11,r10):lib + r3 = insert(r28,#11 +1,#52 -32) + r10 = and(r8,#-2) + } + { + r10 -= sfmpy(r11,r9):lib + r5 = #-0x3ff +1 + r4 = #0x3ff -1 + } + { + r11 += sfmpy(r11,r10):lib + p1 = cmp.gt(r12,r5) + p1 = !cmp.gt(r12,r4) + } + { + r13 = insert(r11,#23,#3) + r5:4 = #0 + r12 = add(r12,#-61) + } + + + + + { + r13 = add(r13,#((-3) << 3)) + } + { r7:6 = mpyu(r13,r1); r1:0 = asl(r1:0,# ( 15 )); }; { r6 = # 0; r1:0 -= mpyu(r7,r2); r15:14 = mpyu(r7,r3); }; { r5:4 += ASL(r7:6, # ( 14 )); r1:0 -= asl(r15:14, # 32); } + { r7:6 = mpyu(r13,r1); r1:0 = asl(r1:0,# ( 15 )); }; { r6 = # 0; r1:0 -= mpyu(r7,r2); r15:14 = mpyu(r7,r3); }; { r5:4 += ASR(r7:6, # ( 1 )); r1:0 -= asl(r15:14, # 32); } + { r7:6 = mpyu(r13,r1); r1:0 = asl(r1:0,# ( 15 )); }; { r6 = # 0; r1:0 -= mpyu(r7,r2); r15:14 = mpyu(r7,r3); }; { r5:4 += ASR(r7:6, # ( 16 )); r1:0 -= asl(r15:14, # 32); } + { r7:6 = mpyu(r13,r1); r1:0 = asl(r1:0,# ( 15 )); }; { r6 = # 0; r1:0 -= mpyu(r7,r2); r15:14 = mpyu(r7,r3); }; { r5:4 += ASR(r7:6, # ( 31 )); r1:0 -= asl(r15:14, # 32); r7:6=# ( 0 ); } + + + + + + + + { + + r15:14 = sub(r1:0,r3:2) + p0 = cmp.gtu(r3:2,r1:0) + + if (!p0.new) r6 = #2 + } + { + r5:4 = add(r5:4,r7:6) + if (!p0) r1:0 = r15:14 + r15:14 = #0 + } + { + p0 = cmp.eq(r1:0,r15:14) + if (!p0.new) r4 = or(r4,r28) + } + { + r7:6 = neg(r5:4) + } + { + if (!p3) r5:4 = r7:6 + } + { + r1:0 = convert_d2df(r5:4) + if (!p1) jump .Ldiv_ovf_unf + } + { + r1 += asl(r12,#52 -32) + jumpr r31 + } + +.Ldiv_ovf_unf: + { + r1 += asl(r12,#52 -32) + r13 = extractu(r1,#11,#52 -32) + } + { + r7:6 = abs(r5:4) + r12 = add(r12,r13) + } + { + p0 = cmp.gt(r12,##0x3ff +0x3ff) + if (p0.new) jump:nt .Ldiv_ovf + } + { + p0 = cmp.gt(r12,#0) + if (p0.new) jump:nt .Lpossible_unf2 + } + { + r13 = add(clb(r7:6),#-1) + r12 = sub(#7,r12) + r10 = USR + r11 = #63 + } + { + r13 = min(r12,r11) + r11 = or(r10,#0x030) + r7:6 = asl(r7:6,r13) + r12 = #0 + } + { + r15:14 = extractu(r7:6,r13:12) + r7:6 = lsr(r7:6,r13) + r3:2 = #1 + } + { + p0 = cmp.gtu(r3:2,r15:14) + if (!p0.new) r6 = or(r2,r6) + r7 = setbit(r7,#52 -32+4) + } + { + r5:4 = neg(r7:6) + p0 = bitsclr(r6,#(1<<4)-1) + if (!p0.new) r10 = r11 + } + { + USR = r10 + if (p3) r5:4 = r7:6 + r10 = #-0x3ff -(52 +4) + } + { + r1:0 = convert_d2df(r5:4) + } + { + r1 += asl(r10,#52 -32) + jumpr r31 + } + + +.Lpossible_unf2: + + + { + r3:2 = extractu(r1:0,#63,#0) + r15:14 = combine(##0x00100000,#0) + r10 = #0x7FFF + } + { + p0 = dfcmp.eq(r15:14,r3:2) + p0 = bitsset(r7,r10) + } + + + + + + + { + if (!p0) jumpr r31 + r10 = USR + } + + { + r10 = or(r10,#0x30) + } + { + USR = r10 + } + { + p0 = dfcmp.eq(r1:0,r1:0) + jumpr r31 + } + +.Ldiv_ovf: + + + + { + r10 = USR + r3:2 = combine(##0x7fefffff,#-1) + r1 = mux(p3,#0,#-1) + } + { + r7:6 = combine(##0x7ff00000,#0) + r5 = extractu(r10,#2,#22) + r10 = or(r10,#0x28) + } + { + USR = r10 + r5 ^= lsr(r1,#31) + r4 = r5 + } + { + p0 = !cmp.eq(r4,#1) + p0 = !cmp.eq(r5,#2) + if (p0.new) r3:2 = r7:6 + p0 = dfcmp.eq(r3:2,r3:2) + } + { + r1:0 = insert(r3:2,#63,#0) + jumpr r31 + } + + + + + + + +.Ldiv_abnormal: + { + p0 = dfclass(r1:0,#0x0F) + p0 = dfclass(r3:2,#0x0F) + p3 = cmp.gt(r28,#-1) + } + { + p1 = dfclass(r1:0,#0x08) + p1 = dfclass(r3:2,#0x08) + } + { + p2 = dfclass(r1:0,#0x01) + p2 = dfclass(r3:2,#0x01) + } + { + if (!p0) jump .Ldiv_nan + if (p1) jump .Ldiv_invalid + } + { + if (p2) jump .Ldiv_invalid + } + { + p2 = dfclass(r1:0,#(0x0F ^ 0x01)) + p2 = dfclass(r3:2,#(0x0F ^ 0x08)) + } + { + p1 = dfclass(r1:0,#(0x0F ^ 0x08)) + p1 = dfclass(r3:2,#(0x0F ^ 0x01)) + } + { + if (!p2) jump .Ldiv_zero_result + if (!p1) jump .Ldiv_inf_result + } + + + + + + { + p0 = dfclass(r1:0,#0x02) + p1 = dfclass(r3:2,#0x02) + r10 = ##0x00100000 + } + { + r13:12 = combine(r3,r1) + r1 = insert(r10,#11 +1,#52 -32) + r3 = insert(r10,#11 +1,#52 -32) + } + { + if (p0) r1 = or(r1,r10) + if (p1) r3 = or(r3,r10) + } + { + r5 = add(clb(r1:0),#-11) + r4 = add(clb(r3:2),#-11) + r10 = #1 + } + { + r12 = extractu(r12,#11,#52 -32) + r13 = extractu(r13,#11,#52 -32) + } + { + r1:0 = asl(r1:0,r5) + r3:2 = asl(r3:2,r4) + if (!p0) r12 = sub(r10,r5) + if (!p1) r13 = sub(r10,r4) + } + { + r7:6 = extractu(r3:2,#23,#52 -23) + } + { + r9 = or(r8,r6) + jump .Ldenorm_continue + } + +.Ldiv_zero_result: + { + r1 = xor(r1,r3) + r3:2 = #0 + } + { + r1:0 = insert(r3:2,#63,#0) + jumpr r31 + } +.Ldiv_inf_result: + { + p2 = dfclass(r3:2,#0x01) + p2 = dfclass(r1:0,#(0x0F ^ 0x08)) + } + { + r10 = USR + if (!p2) jump 1f + r1 = xor(r1,r3) + } + { + r10 = or(r10,#0x04) + } + { + USR = r10 + } +1: + { + r3:2 = combine(##0x7ff00000,#0) + p0 = dfcmp.uo(r3:2,r3:2) + } + { + r1:0 = insert(r3:2,#63,#0) + jumpr r31 + } +.Ldiv_nan: + { + p0 = dfclass(r1:0,#0x10) + p1 = dfclass(r3:2,#0x10) + if (!p0.new) r1:0 = r3:2 + if (!p1.new) r3:2 = r1:0 + } + { + r5 = convert_df2sf(r1:0) + r4 = convert_df2sf(r3:2) + } + { + r1:0 = #-1 + jumpr r31 + } + +.Ldiv_invalid: + { + r10 = ##0x7f800001 + } + { + r1:0 = convert_sf2df(r10) + jumpr r31 + } +.size __hexagon_divdf3,.-__hexagon_divdf3 diff --git a/library/compiler-builtins/src/hexagon/dffma.s b/library/compiler-builtins/src/hexagon/dffma.s new file mode 100644 index 0000000000000..043a1d294a343 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/dffma.s @@ -0,0 +1,536 @@ + .text + .global __hexagon_fmadf4 + .type __hexagon_fmadf4,@function + .global __hexagon_fmadf5 + .type __hexagon_fmadf5,@function + .global fma + .type fma,@function + .global __qdsp_fmadf5 ; .set __qdsp_fmadf5, __hexagon_fmadf5 + .p2align 5 +__hexagon_fmadf4: +__hexagon_fmadf5: +fma: + { + p0 = dfclass(r1:0,#2) + p0 = dfclass(r3:2,#2) + r13:12 = #0 + r15:14 = #0 + } + { + r13:12 = insert(r1:0,#52,#11 -3) + r15:14 = insert(r3:2,#52,#11 -3) + r7 = ##0x10000000 + allocframe(#32) + } + { + r9:8 = mpyu(r12,r14) + if (!p0) jump .Lfma_abnormal_ab + r13 = or(r13,r7) + r15 = or(r15,r7) + } + { + p0 = dfclass(r5:4,#2) + if (!p0.new) jump:nt .Lfma_abnormal_c + r11:10 = combine(r7,#0) + r7:6 = combine(#0,r9) + } +.Lfma_abnormal_c_restart: + { + r7:6 += mpyu(r14,r13) + r11:10 = insert(r5:4,#52,#11 -3) + memd(r29+#0) = r17:16 + memd(r29+#8) = r19:18 + } + { + r7:6 += mpyu(r12,r15) + r19:18 = neg(r11:10) + p0 = cmp.gt(r5,#-1) + r28 = xor(r1,r3) + } + { + r18 = extractu(r1,#11,#20) + r19 = extractu(r3,#11,#20) + r17:16 = combine(#0,r7) + if (!p0) r11:10 = r19:18 + } + { + r17:16 += mpyu(r13,r15) + r9:8 = combine(r6,r8) + r18 = add(r18,r19) + + + + + r19 = extractu(r5,#11,#20) + } + { + r18 = add(r18,#-1023 +(4)) + p3 = !cmp.gt(r28,#-1) + r7:6 = #0 + r15:14 = #0 + } + { + r7:6 = sub(r7:6,r9:8,p3):carry + p0 = !cmp.gt(r28,#-1) + p1 = cmp.gt(r19,r18) + if (p1.new) r19:18 = combine(r18,r19) + } + { + r15:14 = sub(r15:14,r17:16,p3):carry + if (p0) r9:8 = r7:6 + + + + + r7:6 = #0 + r19 = sub(r18,r19) + } + { + if (p0) r17:16 = r15:14 + p0 = cmp.gt(r19,#63) + if (p1) r9:8 = r7:6 + if (p1) r7:6 = r9:8 + } + + + + + + + + { + if (p1) r17:16 = r11:10 + if (p1) r11:10 = r17:16 + if (p0) r19 = add(r19,#-64) + r28 = #63 + } + { + + if (p0) r7:6 = r11:10 + r28 = asr(r11,#31) + r13 = min(r19,r28) + r12 = #0 + } + + + + + + + { + if (p0) r11:10 = combine(r28,r28) + r5:4 = extract(r7:6,r13:12) + r7:6 = lsr(r7:6,r13) + r12 = sub(#64,r13) + } + { + r15:14 = #0 + r28 = #-2 + r7:6 |= lsl(r11:10,r12) + r11:10 = asr(r11:10,r13) + } + { + p3 = cmp.gtu(r5:4,r15:14) + if (p3.new) r6 = and(r6,r28) + + + + r15:14 = #1 + r5:4 = #0 + } + { + r9:8 = add(r7:6,r9:8,p3):carry + } + { + r17:16 = add(r11:10,r17:16,p3):carry + r28 = #62 + } + + + + + + + + { + r12 = add(clb(r17:16),#-2) + if (!cmp.eq(r12.new,r28)) jump:t 1f + } + + { + r11:10 = extractu(r9:8,#62,#2) + r9:8 = asl(r9:8,#62) + r18 = add(r18,#-62) + } + { + r17:16 = insert(r11:10,#62,#0) + } + { + r12 = add(clb(r17:16),#-2) + } + .falign +1: + { + r11:10 = asl(r17:16,r12) + r5:4 |= asl(r9:8,r12) + r13 = sub(#64,r12) + r18 = sub(r18,r12) + } + { + r11:10 |= lsr(r9:8,r13) + p2 = cmp.gtu(r15:14,r5:4) + r28 = #1023 +1023 -2 + } + { + if (!p2) r10 = or(r10,r14) + + p0 = !cmp.gt(r18,r28) + p0 = cmp.gt(r18,#1) + if (!p0.new) jump:nt .Lfma_ovf_unf + } + { + + p0 = cmp.gtu(r15:14,r11:10) + r1:0 = convert_d2df(r11:10) + r18 = add(r18,#-1023 -60) + r17:16 = memd(r29+#0) + } + { + r1 += asl(r18,#20) + r19:18 = memd(r29+#8) + if (!p0) dealloc_return + } +.Ladd_yields_zero: + + { + r28 = USR + r1:0 = #0 + } + { + r28 = extractu(r28,#2,#22) + r17:16 = memd(r29+#0) + r19:18 = memd(r29+#8) + } + { + p0 = cmp.eq(r28,#2) + if (p0.new) r1 = ##0x80000000 + dealloc_return + } +.Lfma_ovf_unf: + { + p0 = cmp.gtu(r15:14,r11:10) + if (p0.new) jump:nt .Ladd_yields_zero + } + { + r1:0 = convert_d2df(r11:10) + r18 = add(r18,#-1023 -60) + r28 = r18 + } + + + { + r1 += asl(r18,#20) + r7 = extractu(r1,#11,#20) + } + { + r6 = add(r18,r7) + r17:16 = memd(r29+#0) + r19:18 = memd(r29+#8) + r9:8 = abs(r11:10) + } + { + p0 = cmp.gt(r6,##1023 +1023) + if (p0.new) jump:nt .Lfma_ovf + } + { + p0 = cmp.gt(r6,#0) + if (p0.new) jump:nt .Lpossible_unf0 + } + { + + + + r7 = add(clb(r9:8),#-2) + r6 = sub(#1+5,r28) + p3 = cmp.gt(r11,#-1) + } + + + + { + r6 = add(r6,r7) + r9:8 = asl(r9:8,r7) + r1 = USR + r28 = #63 + } + { + r7 = min(r6,r28) + r6 = #0 + r0 = #0x0030 + } + { + r3:2 = extractu(r9:8,r7:6) + r9:8 = asr(r9:8,r7) + } + { + p0 = cmp.gtu(r15:14,r3:2) + if (!p0.new) r8 = or(r8,r14) + r9 = setbit(r9,#20 +3) + } + { + r11:10 = neg(r9:8) + p1 = bitsclr(r8,#(1<<3)-1) + if (!p1.new) r1 = or(r1,r0) + r3:2 = #0 + } + { + if (p3) r11:10 = r9:8 + USR = r1 + r28 = #-1023 -(52 +3) + } + { + r1:0 = convert_d2df(r11:10) + } + { + r1 += asl(r28,#20) + dealloc_return + } +.Lpossible_unf0: + { + r28 = ##0x7fefffff + r9:8 = abs(r11:10) + } + { + p0 = cmp.eq(r0,#0) + p0 = bitsclr(r1,r28) + if (!p0.new) dealloc_return:t + r28 = #0x7fff + } + { + p0 = bitsset(r9,r28) + r3 = USR + r2 = #0x0030 + } + { + if (p0) r3 = or(r3,r2) + } + { + USR = r3 + } + { + p0 = dfcmp.eq(r1:0,r1:0) + dealloc_return + } +.Lfma_ovf: + { + r28 = USR + r11:10 = combine(##0x7fefffff,#-1) + r1:0 = r11:10 + } + { + r9:8 = combine(##0x7ff00000,#0) + r3 = extractu(r28,#2,#22) + r28 = or(r28,#0x28) + } + { + USR = r28 + r3 ^= lsr(r1,#31) + r2 = r3 + } + { + p0 = !cmp.eq(r2,#1) + p0 = !cmp.eq(r3,#2) + } + { + p0 = dfcmp.eq(r9:8,r9:8) + if (p0.new) r11:10 = r9:8 + } + { + r1:0 = insert(r11:10,#63,#0) + dealloc_return + } +.Lfma_abnormal_ab: + { + r9:8 = extractu(r1:0,#63,#0) + r11:10 = extractu(r3:2,#63,#0) + deallocframe + } + { + p3 = cmp.gtu(r9:8,r11:10) + if (!p3.new) r1:0 = r3:2 + if (!p3.new) r3:2 = r1:0 + } + { + p0 = dfclass(r1:0,#0x0f) + if (!p0.new) jump:nt .Lnan + if (!p3) r9:8 = r11:10 + if (!p3) r11:10 = r9:8 + } + { + p1 = dfclass(r1:0,#0x08) + p1 = dfclass(r3:2,#0x0e) + } + { + p0 = dfclass(r1:0,#0x08) + p0 = dfclass(r3:2,#0x01) + } + { + if (p1) jump .Lab_inf + p2 = dfclass(r3:2,#0x01) + } + { + if (p0) jump .Linvalid + if (p2) jump .Lab_true_zero + r28 = ##0x7c000000 + } + + + + + + { + p0 = bitsclr(r1,r28) + if (p0.new) jump:nt .Lfma_ab_tiny + } + { + r28 = add(clb(r11:10),#-11) + } + { + r11:10 = asl(r11:10,r28) + } + { + r3:2 = insert(r11:10,#63,#0) + r1 -= asl(r28,#20) + } + jump fma + +.Lfma_ab_tiny: + r9:8 = combine(##0x00100000,#0) + { + r1:0 = insert(r9:8,#63,#0) + r3:2 = insert(r9:8,#63,#0) + } + jump fma + +.Lab_inf: + { + r3:2 = lsr(r3:2,#63) + p0 = dfclass(r5:4,#0x10) + } + { + r1:0 ^= asl(r3:2,#63) + if (p0) jump .Lnan + } + { + p1 = dfclass(r5:4,#0x08) + if (p1.new) jump:nt .Lfma_inf_plus_inf + } + + { + jumpr r31 + } + .falign +.Lfma_inf_plus_inf: + { + p0 = dfcmp.eq(r1:0,r5:4) + if (!p0.new) jump:nt .Linvalid + } + { + jumpr r31 + } + +.Lnan: + { + p0 = dfclass(r3:2,#0x10) + p1 = dfclass(r5:4,#0x10) + if (!p0.new) r3:2 = r1:0 + if (!p1.new) r5:4 = r1:0 + } + { + r3 = convert_df2sf(r3:2) + r2 = convert_df2sf(r5:4) + } + { + r3 = convert_df2sf(r1:0) + r1:0 = #-1 + jumpr r31 + } + +.Linvalid: + { + r28 = ##0x7f800001 + } + { + r1:0 = convert_sf2df(r28) + jumpr r31 + } + +.Lab_true_zero: + + { + p0 = dfclass(r5:4,#0x10) + if (p0.new) jump:nt .Lnan + if (p0.new) r1:0 = r5:4 + } + { + p0 = dfcmp.eq(r3:2,r5:4) + r1 = lsr(r1,#31) + } + { + r3 ^= asl(r1,#31) + if (!p0) r1:0 = r5:4 + if (!p0) jumpr r31 + } + + { + p0 = cmp.eq(r3:2,r5:4) + if (p0.new) jumpr:t r31 + r1:0 = r3:2 + } + { + r28 = USR + } + { + r28 = extractu(r28,#2,#22) + r1:0 = #0 + } + { + p0 = cmp.eq(r28,#2) + if (p0.new) r1 = ##0x80000000 + jumpr r31 + } + + + + + .falign +.Lfma_abnormal_c: + + + { + p0 = dfclass(r5:4,#0x10) + if (p0.new) jump:nt .Lnan + if (p0.new) r1:0 = r5:4 + deallocframe + } + { + p0 = dfclass(r5:4,#0x08) + if (p0.new) r1:0 = r5:4 + if (p0.new) jumpr:nt r31 + } + + + { + p0 = dfclass(r5:4,#0x01) + if (p0.new) jump:nt __hexagon_muldf3 + r28 = #1 + } + + + { + allocframe(#32) + r11:10 = #0 + r5 = insert(r28,#11,#20) + jump .Lfma_abnormal_c_restart + } +.size fma,.-fma diff --git a/library/compiler-builtins/src/hexagon/dfminmax.s b/library/compiler-builtins/src/hexagon/dfminmax.s new file mode 100644 index 0000000000000..3337a3223ecd1 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/dfminmax.s @@ -0,0 +1,51 @@ + .text + .global __hexagon_mindf3 + .global __hexagon_maxdf3 + .global fmin + .type fmin,@function + .global fmax + .type fmax,@function + .type __hexagon_mindf3,@function + .type __hexagon_maxdf3,@function + .global __qdsp_mindf3 ; .set __qdsp_mindf3, __hexagon_mindf3 + .global __qdsp_maxdf3 ; .set __qdsp_maxdf3, __hexagon_maxdf3 + .p2align 5 +__hexagon_mindf3: +fmin: + { + p0 = dfclass(r1:0,#0x10) + p1 = dfcmp.gt(r1:0,r3:2) + r5:4 = r1:0 + } + { + if (p0) r1:0 = r3:2 + if (p1) r1:0 = r3:2 + p2 = dfcmp.eq(r1:0,r3:2) + if (!p2.new) jumpr:t r31 + } + + { + r1:0 = or(r5:4,r3:2) + jumpr r31 + } +.size __hexagon_mindf3,.-__hexagon_mindf3 + .falign +__hexagon_maxdf3: +fmax: + { + p0 = dfclass(r1:0,#0x10) + p1 = dfcmp.gt(r3:2,r1:0) + r5:4 = r1:0 + } + { + if (p0) r1:0 = r3:2 + if (p1) r1:0 = r3:2 + p2 = dfcmp.eq(r1:0,r3:2) + if (!p2.new) jumpr:t r31 + } + + { + r1:0 = and(r5:4,r3:2) + jumpr r31 + } +.size __hexagon_maxdf3,.-__hexagon_maxdf3 diff --git a/library/compiler-builtins/src/hexagon/dfmul.s b/library/compiler-builtins/src/hexagon/dfmul.s new file mode 100644 index 0000000000000..32fc674f975d1 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/dfmul.s @@ -0,0 +1,309 @@ + .text + .global __hexagon_muldf3 + .type __hexagon_muldf3,@function + .global __qdsp_muldf3 ; .set __qdsp_muldf3, __hexagon_muldf3 + .global __hexagon_fast_muldf3 ; .set __hexagon_fast_muldf3, __hexagon_muldf3 + .global __hexagon_fast2_muldf3 ; .set __hexagon_fast2_muldf3, __hexagon_muldf3 + .p2align 5 +__hexagon_muldf3: + { + p0 = dfclass(r1:0,#2) + p0 = dfclass(r3:2,#2) + r13:12 = combine(##0x40000000,#0) + } + { + r13:12 = insert(r1:0,#52,#11 -1) + r5:4 = asl(r3:2,#11 -1) + r28 = #-1024 + r9:8 = #1 + } + { + r7:6 = mpyu(r4,r13) + r5:4 = insert(r9:8,#2,#62) + } + + + + + { + r15:14 = mpyu(r12,r4) + r7:6 += mpyu(r12,r5) + } + { + r7:6 += lsr(r15:14,#32) + r11:10 = mpyu(r13,r5) + r5:4 = combine(##1024 +1024 -4,#0) + } + { + r11:10 += lsr(r7:6,#32) + if (!p0) jump .Lmul_abnormal + p1 = cmp.eq(r14,#0) + p1 = cmp.eq(r6,#0) + } + { + if (!p1) r10 = or(r10,r8) + r6 = extractu(r1,#11,#20) + r7 = extractu(r3,#11,#20) + } + { + r15:14 = neg(r11:10) + r6 += add(r28,r7) + r28 = xor(r1,r3) + } + { + if (!p2.new) r11:10 = r15:14 + p2 = cmp.gt(r28,#-1) + p0 = !cmp.gt(r6,r5) + p0 = cmp.gt(r6,r4) + if (!p0.new) jump:nt .Lmul_ovf_unf + } + { + r1:0 = convert_d2df(r11:10) + r6 = add(r6,#-1024 -58) + } + { + r1 += asl(r6,#20) + jumpr r31 + } + + .falign +.Lpossible_unf1: + { + p0 = cmp.eq(r0,#0) + p0 = bitsclr(r1,r4) + if (!p0.new) jumpr:t r31 + r5 = #0x7fff + } + { + p0 = bitsset(r13,r5) + r4 = USR + r5 = #0x030 + } + { + if (p0) r4 = or(r4,r5) + } + { + USR = r4 + } + { + p0 = dfcmp.eq(r1:0,r1:0) + jumpr r31 + } + .falign +.Lmul_ovf_unf: + { + r1:0 = convert_d2df(r11:10) + r13:12 = abs(r11:10) + r7 = add(r6,#-1024 -58) + } + { + r1 += asl(r7,#20) + r7 = extractu(r1,#11,#20) + r4 = ##0x7FEFFFFF + } + { + r7 += add(r6,##-1024 -58) + + r5 = #0 + } + { + p0 = cmp.gt(r7,##1024 +1024 -2) + if (p0.new) jump:nt .Lmul_ovf + } + { + p0 = cmp.gt(r7,#0) + if (p0.new) jump:nt .Lpossible_unf1 + r5 = sub(r6,r5) + r28 = #63 + } + { + r4 = #0 + r5 = sub(#5,r5) + } + { + p3 = cmp.gt(r11,#-1) + r5 = min(r5,r28) + r11:10 = r13:12 + } + { + r28 = USR + r15:14 = extractu(r11:10,r5:4) + } + { + r11:10 = asr(r11:10,r5) + r4 = #0x0030 + r1 = insert(r9,#11,#20) + } + { + p0 = cmp.gtu(r9:8,r15:14) + if (!p0.new) r10 = or(r10,r8) + r11 = setbit(r11,#20 +3) + } + { + r15:14 = neg(r11:10) + p1 = bitsclr(r10,#0x7) + if (!p1.new) r28 = or(r4,r28) + } + { + if (!p3) r11:10 = r15:14 + USR = r28 + } + { + r1:0 = convert_d2df(r11:10) + p0 = dfcmp.eq(r1:0,r1:0) + } + { + r1 = insert(r9,#11 -1,#20 +1) + jumpr r31 + } + .falign +.Lmul_ovf: + + { + r28 = USR + r13:12 = combine(##0x7fefffff,#-1) + r1:0 = r11:10 + } + { + r14 = extractu(r28,#2,#22) + r28 = or(r28,#0x28) + r5:4 = combine(##0x7ff00000,#0) + } + { + USR = r28 + r14 ^= lsr(r1,#31) + r28 = r14 + } + { + p0 = !cmp.eq(r28,#1) + p0 = !cmp.eq(r14,#2) + if (p0.new) r13:12 = r5:4 + p0 = dfcmp.eq(r1:0,r1:0) + } + { + r1:0 = insert(r13:12,#63,#0) + jumpr r31 + } + +.Lmul_abnormal: + { + r13:12 = extractu(r1:0,#63,#0) + r5:4 = extractu(r3:2,#63,#0) + } + { + p3 = cmp.gtu(r13:12,r5:4) + if (!p3.new) r1:0 = r3:2 + if (!p3.new) r3:2 = r1:0 + } + { + + p0 = dfclass(r1:0,#0x0f) + if (!p0.new) jump:nt .Linvalid_nan + if (!p3) r13:12 = r5:4 + if (!p3) r5:4 = r13:12 + } + { + + p1 = dfclass(r1:0,#0x08) + p1 = dfclass(r3:2,#0x0e) + } + { + + + p0 = dfclass(r1:0,#0x08) + p0 = dfclass(r3:2,#0x01) + } + { + if (p1) jump .Ltrue_inf + p2 = dfclass(r3:2,#0x01) + } + { + if (p0) jump .Linvalid_zeroinf + if (p2) jump .Ltrue_zero + r28 = ##0x7c000000 + } + + + + + + { + p0 = bitsclr(r1,r28) + if (p0.new) jump:nt .Lmul_tiny + } + { + r28 = cl0(r5:4) + } + { + r28 = add(r28,#-11) + } + { + r5:4 = asl(r5:4,r28) + } + { + r3:2 = insert(r5:4,#63,#0) + r1 -= asl(r28,#20) + } + jump __hexagon_muldf3 +.Lmul_tiny: + { + r28 = USR + r1:0 = xor(r1:0,r3:2) + } + { + r28 = or(r28,#0x30) + r1:0 = insert(r9:8,#63,#0) + r5 = extractu(r28,#2,#22) + } + { + USR = r28 + p0 = cmp.gt(r5,#1) + if (!p0.new) r0 = #0 + r5 ^= lsr(r1,#31) + } + { + p0 = cmp.eq(r5,#3) + if (!p0.new) r0 = #0 + jumpr r31 + } +.Linvalid_zeroinf: + { + r28 = USR + } + { + r1:0 = #-1 + r28 = or(r28,#2) + } + { + USR = r28 + } + { + p0 = dfcmp.uo(r1:0,r1:0) + jumpr r31 + } +.Linvalid_nan: + { + p0 = dfclass(r3:2,#0x0f) + r28 = convert_df2sf(r1:0) + if (p0.new) r3:2 = r1:0 + } + { + r2 = convert_df2sf(r3:2) + r1:0 = #-1 + jumpr r31 + } + .falign +.Ltrue_zero: + { + r1:0 = r3:2 + r3:2 = r1:0 + } +.Ltrue_inf: + { + r3 = extract(r3,#1,#31) + } + { + r1 ^= asl(r3,#31) + jumpr r31 + } +.size __hexagon_muldf3,.-__hexagon_muldf3 diff --git a/library/compiler-builtins/src/hexagon/dfsqrt.s b/library/compiler-builtins/src/hexagon/dfsqrt.s new file mode 100644 index 0000000000000..14f584a11339d --- /dev/null +++ b/library/compiler-builtins/src/hexagon/dfsqrt.s @@ -0,0 +1,277 @@ + .text + .global __hexagon_sqrtdf2 + .type __hexagon_sqrtdf2,@function + .global __hexagon_sqrt + .type __hexagon_sqrt,@function + .global __qdsp_sqrtdf2 ; .set __qdsp_sqrtdf2, __hexagon_sqrtdf2; .type __qdsp_sqrtdf2,@function + .global __qdsp_sqrt ; .set __qdsp_sqrt, __hexagon_sqrt; .type __qdsp_sqrt,@function + .global __hexagon_fast_sqrtdf2 ; .set __hexagon_fast_sqrtdf2, __hexagon_sqrtdf2; .type __hexagon_fast_sqrtdf2,@function + .global __hexagon_fast_sqrt ; .set __hexagon_fast_sqrt, __hexagon_sqrt; .type __hexagon_fast_sqrt,@function + .global __hexagon_fast2_sqrtdf2 ; .set __hexagon_fast2_sqrtdf2, __hexagon_sqrtdf2; .type __hexagon_fast2_sqrtdf2,@function + .global __hexagon_fast2_sqrt ; .set __hexagon_fast2_sqrt, __hexagon_sqrt; .type __hexagon_fast2_sqrt,@function + .type sqrt,@function + .p2align 5 +__hexagon_sqrtdf2: +__hexagon_sqrt: + { + r15:14 = extractu(r1:0,#23 +1,#52 -23) + r28 = extractu(r1,#11,#52 -32) + r5:4 = combine(##0x3f000004,#1) + } + { + p2 = dfclass(r1:0,#0x02) + p2 = cmp.gt(r1,#-1) + if (!p2.new) jump:nt .Lsqrt_abnormal + r9 = or(r5,r14) + } + +.Ldenormal_restart: + { + r11:10 = r1:0 + r7,p0 = sfinvsqrta(r9) + r5 = and(r5,#-16) + r3:2 = #0 + } + { + r3 += sfmpy(r7,r9):lib + r2 += sfmpy(r7,r5):lib + r6 = r5 + + + r9 = and(r28,#1) + } + { + r6 -= sfmpy(r3,r2):lib + r11 = insert(r4,#11 +1,#52 -32) + p1 = cmp.gtu(r9,#0) + } + { + r3 += sfmpy(r3,r6):lib + r2 += sfmpy(r2,r6):lib + r6 = r5 + r9 = mux(p1,#8,#9) + } + { + r6 -= sfmpy(r3,r2):lib + r11:10 = asl(r11:10,r9) + r9 = mux(p1,#3,#2) + } + { + r2 += sfmpy(r2,r6):lib + + r15:14 = asl(r11:10,r9) + } + { + r2 = and(r2,##0x007fffff) + } + { + r2 = add(r2,##0x00800000 - 3) + r9 = mux(p1,#7,#8) + } + { + r8 = asl(r2,r9) + r9 = mux(p1,#15-(1+1),#15-(1+0)) + } + { + r13:12 = mpyu(r8,r15) + } + { + r1:0 = asl(r11:10,#15) + r15:14 = mpyu(r13,r13) + p1 = cmp.eq(r0,r0) + } + { + r1:0 -= asl(r15:14,#15) + r15:14 = mpyu(r13,r12) + p2 = cmp.eq(r0,r0) + } + { + r1:0 -= lsr(r15:14,#16) + p3 = cmp.eq(r0,r0) + } + { + r1:0 = mpyu(r1,r8) + } + { + r13:12 += lsr(r1:0,r9) + r9 = add(r9,#16) + r1:0 = asl(r11:10,#31) + } + + { + r15:14 = mpyu(r13,r13) + r1:0 -= mpyu(r13,r12) + } + { + r1:0 -= asl(r15:14,#31) + r15:14 = mpyu(r12,r12) + } + { + r1:0 -= lsr(r15:14,#33) + } + { + r1:0 = mpyu(r1,r8) + } + { + r13:12 += lsr(r1:0,r9) + r9 = add(r9,#16) + r1:0 = asl(r11:10,#47) + } + + { + r15:14 = mpyu(r13,r13) + } + { + r1:0 -= asl(r15:14,#47) + r15:14 = mpyu(r13,r12) + } + { + r1:0 -= asl(r15:14,#16) + r15:14 = mpyu(r12,r12) + } + { + r1:0 -= lsr(r15:14,#17) + } + { + r1:0 = mpyu(r1,r8) + } + { + r13:12 += lsr(r1:0,r9) + } + { + r3:2 = mpyu(r13,r12) + r5:4 = mpyu(r12,r12) + r15:14 = #0 + r1:0 = #0 + } + { + r3:2 += lsr(r5:4,#33) + r5:4 += asl(r3:2,#33) + p1 = cmp.eq(r0,r0) + } + { + r7:6 = mpyu(r13,r13) + r1:0 = sub(r1:0,r5:4,p1):carry + r9:8 = #1 + } + { + r7:6 += lsr(r3:2,#31) + r9:8 += asl(r13:12,#1) + } + + + + + + { + r15:14 = sub(r11:10,r7:6,p1):carry + r5:4 = sub(r1:0,r9:8,p2):carry + + + + + r7:6 = #1 + r11:10 = #0 + } + { + r3:2 = sub(r15:14,r11:10,p2):carry + r7:6 = add(r13:12,r7:6) + r28 = add(r28,#-0x3ff) + } + { + + if (p2) r13:12 = r7:6 + if (p2) r1:0 = r5:4 + if (p2) r15:14 = r3:2 + } + { + r5:4 = sub(r1:0,r9:8,p3):carry + r7:6 = #1 + r28 = asr(r28,#1) + } + { + r3:2 = sub(r15:14,r11:10,p3):carry + r7:6 = add(r13:12,r7:6) + } + { + if (p3) r13:12 = r7:6 + if (p3) r1:0 = r5:4 + + + + + + r2 = #1 + } + { + p0 = cmp.eq(r1:0,r11:10) + if (!p0.new) r12 = or(r12,r2) + r3 = cl0(r13:12) + r28 = add(r28,#-63) + } + + + + { + r1:0 = convert_ud2df(r13:12) + r28 = add(r28,r3) + } + { + r1 += asl(r28,#52 -32) + jumpr r31 + } +.Lsqrt_abnormal: + { + p0 = dfclass(r1:0,#0x01) + if (p0.new) jumpr:t r31 + } + { + p0 = dfclass(r1:0,#0x10) + if (p0.new) jump:nt .Lsqrt_nan + } + { + p0 = cmp.gt(r1,#-1) + if (!p0.new) jump:nt .Lsqrt_invalid_neg + if (!p0.new) r28 = ##0x7F800001 + } + { + p0 = dfclass(r1:0,#0x08) + if (p0.new) jumpr:nt r31 + } + + + { + r1:0 = extractu(r1:0,#52,#0) + } + { + r28 = add(clb(r1:0),#-11) + } + { + r1:0 = asl(r1:0,r28) + r28 = sub(#1,r28) + } + { + r1 = insert(r28,#1,#52 -32) + } + { + r3:2 = extractu(r1:0,#23 +1,#52 -23) + r5 = ##0x3f000004 + } + { + r9 = or(r5,r2) + r5 = and(r5,#-16) + jump .Ldenormal_restart + } +.Lsqrt_nan: + { + r28 = convert_df2sf(r1:0) + r1:0 = #-1 + jumpr r31 + } +.Lsqrt_invalid_neg: + { + r1:0 = convert_sf2df(r28) + jumpr r31 + } +.size __hexagon_sqrt,.-__hexagon_sqrt +.size __hexagon_sqrtdf2,.-__hexagon_sqrtdf2 diff --git a/library/compiler-builtins/src/hexagon/divdi3.s b/library/compiler-builtins/src/hexagon/divdi3.s new file mode 100644 index 0000000000000..0fee6e70f0630 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/divdi3.s @@ -0,0 +1,64 @@ + +FUNCTION_BEGIN __hexagon_divdi3 + { + p2 = tstbit(r1,#31) + p3 = tstbit(r3,#31) + } + { + r1:0 = abs(r1:0) + r3:2 = abs(r3:2) + } + { + r6 = cl0(r1:0) + r7 = cl0(r3:2) + r5:4 = r3:2 + r3:2 = r1:0 + } + { + p3 = xor(p2,p3) + r10 = sub(r7,r6) + r1:0 = #0 + r15:14 = #1 + } + { + r11 = add(r10,#1) + r13:12 = lsl(r5:4,r10) + r15:14 = lsl(r15:14,r10) + } + { + p0 = cmp.gtu(r5:4,r3:2) + loop0(1f,r11) + } + { + if (p0) jump .hexagon_divdi3_return + } + .falign +1: + { + p0 = cmp.gtu(r13:12,r3:2) + } + { + r7:6 = sub(r3:2, r13:12) + r9:8 = add(r1:0, r15:14) + } + { + r1:0 = vmux(p0, r1:0, r9:8) + r3:2 = vmux(p0, r3:2, r7:6) + } + { + r15:14 = lsr(r15:14, #1) + r13:12 = lsr(r13:12, #1) + }:endloop0 + +.hexagon_divdi3_return: + { + r3:2 = neg(r1:0) + } + { + r1:0 = vmux(p3,r3:2,r1:0) + jumpr r31 + } +FUNCTION_END __hexagon_divdi3 + + .globl __qdsp_divdi3 + .set __qdsp_divdi3, __hexagon_divdi3 diff --git a/library/compiler-builtins/src/hexagon/divsi3.s b/library/compiler-builtins/src/hexagon/divsi3.s new file mode 100644 index 0000000000000..fc957a4314600 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/divsi3.s @@ -0,0 +1,53 @@ + +FUNCTION_BEGIN __hexagon_divsi3 + { + p0 = cmp.ge(r0,#0) + p1 = cmp.ge(r1,#0) + r1 = abs(r0) + r2 = abs(r1) + } + { + r3 = cl0(r1) + r4 = cl0(r2) + r5 = sub(r1,r2) + p2 = cmp.gtu(r2,r1) + } + { + r0 = #0 + p1 = xor(p0,p1) + p0 = cmp.gtu(r2,r5) + if (p2) jumpr r31 + } + + { + r0 = mux(p1,#-1,#1) + if (p0) jumpr r31 + r4 = sub(r4,r3) + r3 = #1 + } + { + r0 = #0 + r3:2 = vlslw(r3:2,r4) + loop0(1f,r4) + } + .falign +1: + { + p0 = cmp.gtu(r2,r1) + if (!p0.new) r1 = sub(r1,r2) + if (!p0.new) r0 = add(r0,r3) + r3:2 = vlsrw(r3:2,#1) + }:endloop0 + { + p0 = cmp.gtu(r2,r1) + if (!p0.new) r0 = add(r0,r3) + if (!p1) jumpr r31 + } + { + r0 = neg(r0) + jumpr r31 + } +FUNCTION_END __hexagon_divsi3 + + .globl __qdsp_divsi3 + .set __qdsp_divsi3, __hexagon_divsi3 diff --git a/library/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s b/library/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s new file mode 100644 index 0000000000000..15c387846facc --- /dev/null +++ b/library/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s @@ -0,0 +1,266 @@ + .text + .global fast2_dadd_asm + .type fast2_dadd_asm, @function +fast2_dadd_asm: + .falign + { + R7:6 = VABSDIFFH(R1:0, R3:2) + R9 = #62 + R4 = SXTH(R0) + R5 = SXTH(R2) + } { + R6 = SXTH(R6) + P0 = CMP.GT(R4, R5); + if ( P0.new) R8 = add(R4, #1) + if (!P0.new) R8 = add(R5, #1) + } { + if ( P0) R4 = #1 + if (!P0) R5 = #1 + R0.L = #0 + R6 = MIN(R6, R9) + } { + if (!P0) R4 = add(R6, #1) + if ( P0) R5 = add(R6, #1) + R2.L = #0 + R11:10 = #0 + } { + R1:0 = ASR(R1:0, R4) + R3:2 = ASR(R3:2, R5) + } { + R1:0 = add(R1:0, R3:2) + R10.L = #0x8001 + } { + R4 = clb(R1:0) + R9 = #58 + } { + R4 = add(R4, #-1) + p0 = cmp.gt(R4, R9) + } { + R1:0 = ASL(R1:0, R4) + R8 = SUB(R8, R4) + if(p0) jump .Ldenorma + } { + R0 = insert(R8, #16, #0) + jumpr r31 + } +.Ldenorma: + { + R1:0 = R11:10 + jumpr r31 + } + .text + .global fast2_dsub_asm + .type fast2_dsub_asm, @function +fast2_dsub_asm: + .falign + { + R7:6 = VABSDIFFH(R1:0, R3:2) + R9 = #62 + R4 = SXTH(R0) + R5 = SXTH(R2) + } { + R6 = SXTH(R6) + P0 = CMP.GT(R4, R5); + if ( P0.new) R8 = add(R4, #1) + if (!P0.new) R8 = add(R5, #1) + } { + if ( P0) R4 = #1 + if (!P0) R5 = #1 + R0.L = #0 + R6 = MIN(R6, R9) + } { + if (!P0) R4 = add(R6, #1) + if ( P0) R5 = add(R6, #1) + R2.L = #0 + R11:10 = #0 + } { + R1:0 = ASR(R1:0, R4) + R3:2 = ASR(R3:2, R5) + } { + R1:0 = sub(R1:0, R3:2) + R10.L = #0x8001 + } { + R4 = clb(R1:0) + R9 = #58 + } { + R4 = add(R4, #-1) + p0 = cmp.gt(R4, R9) + } { + R1:0 = ASL(R1:0, R4) + R8 = SUB(R8, R4) + if(p0) jump .Ldenorm + } { + R0 = insert(R8, #16, #0) + jumpr r31 + } +.Ldenorm: + { + R1:0 = R11:10 + jumpr r31 + } + .text + .global fast2_dmpy_asm + .type fast2_dmpy_asm, @function +fast2_dmpy_asm: + .falign + { + R13= lsr(R2, #16) + R5 = sxth(R2) + R4 = sxth(R0) + R12= lsr(R0, #16) + } + { + R11:10 = mpy(R1, R3) + R7:6 = mpy(R1, R13) + R0.L = #0x0 + R15:14 = #0 + } + { + R11:10 = add(R11:10, R11:10) + R7:6 += mpy(R3, R12) + R2.L = #0x0 + R15.H = #0x8000 + } + { + R7:6 = asr(R7:6, #15) + R12.L = #0x8001 + p1 = cmp.eq(R1:0, R3:2) + } + { + R7:6 = add(R7:6, R11:10) + R8 = add(R4, R5) + p2 = cmp.eq(R1:0, R15:14) + } + { + R9 = clb(R7:6) + R3:2 = abs(R7:6) + R11 = #58 + } + { + p1 = and(p1, p2) + R8 = sub(R8, R9) + R9 = add(R9, #-1) + p0 = cmp.gt(R9, R11) + } + { + R8 = add(R8, #1) + R1:0 = asl(R7:6, R9) + if(p1) jump .Lsat + } + { + R0 = insert(R8,#16, #0) + if(!p0) jumpr r31 + } + { + R0 = insert(R12,#16, #0) + jumpr r31 + } +.Lsat: + { + R1:0 = #-1 + } + { + R1:0 = lsr(R1:0, #1) + } + { + R0 = insert(R8,#16, #0) + jumpr r31 + } + .text + .global fast2_qd2f_asm + .type fast2_qd2f_asm, @function +fast2_qd2f_asm: + .falign + { + R3 = abs(R1):sat + R4 = sxth(R0) + R5 = #0x40 + R6.L = #0xffc0 + } + { + R0 = extractu(R3, #8, #0) + p2 = cmp.gt(R4, #126) + p3 = cmp.ge(R4, #-126) + R6.H = #0x7fff + } + { + p1 = cmp.eq(R0,#0x40) + if(p1.new) R5 = #0 + R4 = add(R4, #126) + if(!p3) jump .Lmin + } + { + p0 = bitsset(R3, R6) + R0.L = #0x0000 + R2 = add(R3, R5) + R7 = lsr(R6, #8) + } + { + if(p0) R4 = add(R4, #1) + if(p0) R3 = #0 + R2 = lsr(R2, #7) + R0.H = #0x8000 + } + { + R0 = and(R0, R1) + R6 &= asl(R4, #23) + if(!p0) R3 = and(R2, R7) + if(p2) jump .Lmax + } + { + R0 += add(R6, R3) + jumpr r31 + } +.Lmax: + { + R0.L = #0xffff; + } + { + R0.H = #0x7f7f; + jumpr r31 + } +.Lmin: + { + R0 = #0x0 + jumpr r31 + } + .text + .global fast2_f2qd_asm + .type fast2_f2qd_asm, @function +fast2_f2qd_asm: + + + + + + + + .falign + { + R1 = asl(R0, #7) + p0 = tstbit(R0, #31) + R5:4 = #0 + R3 = add(R0,R0) + } + { + R1 = setbit(R1, #30) + R0= extractu(R0,#8,#23) + R4.L = #0x8001 + p1 = cmp.eq(R3, #0) + } + { + R1= extractu(R1, #31, #0) + R0= add(R0, #-126) + R2 = #0 + if(p1) jump .Lminqd + } + { + R0 = zxth(R0) + if(p0) R1= sub(R2, R1) + jumpr r31 + } +.Lminqd: + { + R1:0 = R5:4 + jumpr r31 + } diff --git a/library/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s b/library/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s new file mode 100644 index 0000000000000..b72b7550afc4b --- /dev/null +++ b/library/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s @@ -0,0 +1,187 @@ + .text + .global fast2_ldadd_asm + .type fast2_ldadd_asm, @function +fast2_ldadd_asm: + .falign + { + R4 = memw(r29+#8) + R5 = memw(r29+#24) + r7 = r0 + } + { + R6 = sub(R4, R5):sat + P0 = CMP.GT(R4, R5); + if ( P0.new) R8 = add(R4, #1) + if (!P0.new) R8 = add(R5, #1) + } { + R6 = abs(R6):sat + if ( P0) R4 = #1 + if (!P0) R5 = #1 + R9 = #62 + } { + R6 = MIN(R6, R9) + R1:0 = memd(r29+#0) + R3:2 = memd(r29+#16) + } { + if (!P0) R4 = add(R6, #1) + if ( P0) R5 = add(R6, #1) + } { + R1:0 = ASR(R1:0, R4) + R3:2 = ASR(R3:2, R5) + } { + R1:0 = add(R1:0, R3:2) + R3:2 = #0 + } { + R4 = clb(R1:0) + R9.L =#0x0001 + } { + R8 -= add(R4, #-1) + R4 = add(R4, #-1) + p0 = cmp.gt(R4, #58) + R9.H =#0x8000 + } { + if(!p0)memw(r7+#8) = R8 + R1:0 = ASL(R1:0, R4) + if(p0) jump .Ldenorma1 + } { + memd(r7+#0) = R1:0 + jumpr r31 + } +.Ldenorma1: + memd(r7+#0) = R3:2 + { + memw(r7+#8) = R9 + jumpr r31 + } + .text + .global fast2_ldsub_asm + .type fast2_ldsub_asm, @function +fast2_ldsub_asm: + .falign + { + R4 = memw(r29+#8) + R5 = memw(r29+#24) + r7 = r0 + } + { + R6 = sub(R4, R5):sat + P0 = CMP.GT(R4, R5); + if ( P0.new) R8 = add(R4, #1) + if (!P0.new) R8 = add(R5, #1) + } { + R6 = abs(R6):sat + if ( P0) R4 = #1 + if (!P0) R5 = #1 + R9 = #62 + } { + R6 = min(R6, R9) + R1:0 = memd(r29+#0) + R3:2 = memd(r29+#16) + } { + if (!P0) R4 = add(R6, #1) + if ( P0) R5 = add(R6, #1) + } { + R1:0 = ASR(R1:0, R4) + R3:2 = ASR(R3:2, R5) + } { + R1:0 = sub(R1:0, R3:2) + R3:2 = #0 + } { + R4 = clb(R1:0) + R9.L =#0x0001 + } { + R8 -= add(R4, #-1) + R4 = add(R4, #-1) + p0 = cmp.gt(R4, #58) + R9.H =#0x8000 + } { + if(!p0)memw(r7+#8) = R8 + R1:0 = asl(R1:0, R4) + if(p0) jump .Ldenorma_s + } { + memd(r7+#0) = R1:0 + jumpr r31 + } +.Ldenorma_s: + memd(r7+#0) = R3:2 + { + memw(r7+#8) = R9 + jumpr r31 + } + .text + .global fast2_ldmpy_asm + .type fast2_ldmpy_asm, @function +fast2_ldmpy_asm: + .falign + { + R15:14 = memd(r29+#0) + R3:2 = memd(r29+#16) + R13:12 = #0 + } + { + R8= extractu(R2, #31, #1) + R9= extractu(R14, #31, #1) + R13.H = #0x8000 + } + { + R11:10 = mpy(R15, R3) + R7:6 = mpy(R15, R8) + R4 = memw(r29+#8) + R5 = memw(r29+#24) + } + { + R11:10 = add(R11:10, R11:10) + R7:6 += mpy(R3, R9) + } + { + R7:6 = asr(R7:6, #30) + R8.L = #0x0001 + p1 = cmp.eq(R15:14, R3:2) + } + { + R7:6 = add(R7:6, R11:10) + R4= add(R4, R5) + p2 = cmp.eq(R3:2, R13:12) + } + { + R9 = clb(R7:6) + R8.H = #0x8000 + p1 = and(p1, p2) + } + { + R4-= add(R9, #-1) + R9 = add(R9, #-1) + if(p1) jump .Lsat1 + } + { + R7:6 = asl(R7:6, R9) + memw(R0+#8) = R4 + p0 = cmp.gt(R9, #58) + if(p0.new) jump:NT .Ldenorm1 + } + { + memd(R0+#0) = R7:6 + jumpr r31 + } +.Lsat1: + { + R13:12 = #0 + R4+= add(R9, #1) + } + { + R13.H = #0x4000 + memw(R0+#8) = R4 + } + { + memd(R0+#0) = R13:12 + jumpr r31 + } +.Ldenorm1: + { + memw(R0+#8) = R8 + R15:14 = #0 + } + { + memd(R0+#0) = R15:14 + jumpr r31 + } diff --git a/library/compiler-builtins/src/hexagon/func_macro.s b/library/compiler-builtins/src/hexagon/func_macro.s new file mode 100644 index 0000000000000..9a1e11aebcb50 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/func_macro.s @@ -0,0 +1,12 @@ + .macro FUNCTION_BEGIN name + .text + .p2align 5 + .globl \name + .type \name, @function +\name: + .endm + + .macro FUNCTION_END name + .size \name, . - \name + .endm + diff --git a/library/compiler-builtins/src/hexagon/memcpy_forward_vp4cp4n2.s b/library/compiler-builtins/src/hexagon/memcpy_forward_vp4cp4n2.s new file mode 100644 index 0000000000000..89f69010aa43b --- /dev/null +++ b/library/compiler-builtins/src/hexagon/memcpy_forward_vp4cp4n2.s @@ -0,0 +1,91 @@ + .text + + + + + + + .globl hexagon_memcpy_forward_vp4cp4n2 + .balign 32 + .type hexagon_memcpy_forward_vp4cp4n2,@function +hexagon_memcpy_forward_vp4cp4n2: + + + + + { + r3 = sub(##4096, r1) + r5 = lsr(r2, #3) + } + { + + + r3 = extractu(r3, #10, #2) + r4 = extractu(r3, #7, #5) + } + { + r3 = minu(r2, r3) + r4 = minu(r5, r4) + } + { + r4 = or(r4, ##2105344) + p0 = cmp.eq(r3, #0) + if (p0.new) jump:nt .Lskipprolog + } + l2fetch(r1, r4) + { + loop0(.Lprolog, r3) + r2 = sub(r2, r3) + } + .falign +.Lprolog: + { + r4 = memw(r1++#4) + memw(r0++#4) = r4.new + } :endloop0 +.Lskipprolog: + { + + r3 = lsr(r2, #10) + if (cmp.eq(r3.new, #0)) jump:nt .Lskipmain + } + { + loop1(.Lout, r3) + r2 = extractu(r2, #10, #0) + r3 = ##2105472 + } + + .falign +.Lout: + + l2fetch(r1, r3) + loop0(.Lpage, #512) + .falign +.Lpage: + r5:4 = memd(r1++#8) + { + memw(r0++#8) = r4 + memw(r0+#4) = r5 + } :endloop0:endloop1 +.Lskipmain: + { + r3 = ##2105344 + r4 = lsr(r2, #3) + p0 = cmp.eq(r2, #0) + if (p0.new) jumpr:nt r31 + } + { + r3 = or(r3, r4) + loop0(.Lepilog, r2) + } + l2fetch(r1, r3) + .falign +.Lepilog: + { + r4 = memw(r1++#4) + memw(r0++#4) = r4.new + } :endloop0 + + jumpr r31 + +.size hexagon_memcpy_forward_vp4cp4n2, . - hexagon_memcpy_forward_vp4cp4n2 diff --git a/library/compiler-builtins/src/hexagon/memcpy_likely_aligned.s b/library/compiler-builtins/src/hexagon/memcpy_likely_aligned.s new file mode 100644 index 0000000000000..7e9b62f6a791c --- /dev/null +++ b/library/compiler-builtins/src/hexagon/memcpy_likely_aligned.s @@ -0,0 +1,42 @@ + +FUNCTION_BEGIN __hexagon_memcpy_likely_aligned_min32bytes_mult8bytes + { + p0 = bitsclr(r1,#7) + p0 = bitsclr(r0,#7) + if (p0.new) r5:4 = memd(r1) + r3 = #-3 + } + { + if (!p0) jump .Lmemcpy_call + if (p0) memd(r0++#8) = r5:4 + if (p0) 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_likely_aligned_min32bytes_mult8bytes + +.Lmemcpy_call: + + jump memcpy@PLT + + + + + .globl __qdsp_memcpy_likely_aligned_min32bytes_mult8bytes + .set __qdsp_memcpy_likely_aligned_min32bytes_mult8bytes, __hexagon_memcpy_likely_aligned_min32bytes_mult8bytes diff --git a/library/compiler-builtins/src/hexagon/moddi3.s b/library/compiler-builtins/src/hexagon/moddi3.s new file mode 100644 index 0000000000000..53ea6d52a58b4 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/moddi3.s @@ -0,0 +1,63 @@ + + +FUNCTION_BEGIN __hexagon_moddi3 + { + p3 = tstbit(r1,#31) + } + { + r1:0 = abs(r1:0) + r3:2 = abs(r3:2) + } + { + r6 = cl0(r1:0) + r7 = cl0(r3:2) + r5:4 = r3:2 + r3:2 = r1:0 + } + { + r10 = sub(r7,r6) + r1:0 = #0 + r15:14 = #1 + } + { + r11 = add(r10,#1) + r13:12 = lsl(r5:4,r10) + r15:14 = lsl(r15:14,r10) + } + { + p0 = cmp.gtu(r5:4,r3:2) + loop0(1f,r11) + } + { + if (p0) jump .hexagon_moddi3_return + } + .falign +1: + { + p0 = cmp.gtu(r13:12,r3:2) + } + { + r7:6 = sub(r3:2, r13:12) + r9:8 = add(r1:0, r15:14) + } + { + r1:0 = vmux(p0, r1:0, r9:8) + r3:2 = vmux(p0, r3:2, r7:6) + } + { + r15:14 = lsr(r15:14, #1) + r13:12 = lsr(r13:12, #1) + }:endloop0 + +.hexagon_moddi3_return: + { + r1:0 = neg(r3:2) + } + { + r1:0 = vmux(p3,r1:0,r3:2) + jumpr r31 + } +FUNCTION_END __hexagon_moddi3 + + .globl __qdsp_moddi3 + .set __qdsp_moddi3, __hexagon_moddi3 diff --git a/library/compiler-builtins/src/hexagon/modsi3.s b/library/compiler-builtins/src/hexagon/modsi3.s new file mode 100644 index 0000000000000..c4ae7e59edc9a --- /dev/null +++ b/library/compiler-builtins/src/hexagon/modsi3.s @@ -0,0 +1,44 @@ + + +FUNCTION_BEGIN __hexagon_modsi3 + { + p2 = cmp.ge(r0,#0) + r2 = abs(r0) + r1 = abs(r1) + } + { + r3 = cl0(r2) + r4 = cl0(r1) + p0 = cmp.gtu(r1,r2) + } + { + r3 = sub(r4,r3) + if (p0) jumpr r31 + } + { + p1 = cmp.eq(r3,#0) + loop0(1f,r3) + r0 = r2 + r2 = lsl(r1,r3) + } + .falign +1: + { + p0 = cmp.gtu(r2,r0) + if (!p0.new) r0 = sub(r0,r2) + r2 = lsr(r2,#1) + if (p1) r1 = #0 + }:endloop0 + { + p0 = cmp.gtu(r2,r0) + if (!p0.new) r0 = sub(r0,r1) + if (p2) jumpr r31 + } + { + r0 = neg(r0) + jumpr r31 + } +FUNCTION_END __hexagon_modsi3 + + .globl __qdsp_modsi3 + .set __qdsp_modsi3, __hexagon_modsi3 diff --git a/library/compiler-builtins/src/hexagon/sfdiv_opt.s b/library/compiler-builtins/src/hexagon/sfdiv_opt.s new file mode 100644 index 0000000000000..26c91f15cbb05 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/sfdiv_opt.s @@ -0,0 +1,42 @@ + +FUNCTION_BEGIN __hexagon_divsf3 + { + r2,p0 = sfrecipa(r0,r1) + r4 = sffixupd(r0,r1) + r3 = ##0x3f800000 + } + { + r5 = sffixupn(r0,r1) + r3 -= sfmpy(r4,r2):lib + r6 = ##0x80000000 + r7 = r3 + } + { + r2 += sfmpy(r3,r2):lib + r3 = r7 + r6 = r5 + r0 = and(r6,r5) + } + { + r3 -= sfmpy(r4,r2):lib + r0 += sfmpy(r5,r2):lib + } + { + r2 += sfmpy(r3,r2):lib + r6 -= sfmpy(r0,r4):lib + } + { + r0 += sfmpy(r6,r2):lib + } + { + r5 -= sfmpy(r0,r4):lib + } + { + r0 += sfmpy(r5,r2,p0):scale + jumpr r31 + } +FUNCTION_END __hexagon_divsf3 + +.global __qdsp_divsf3 ; .set __qdsp_divsf3, __hexagon_divsf3 +.global __hexagon_fast_divsf3 ; .set __hexagon_fast_divsf3, __hexagon_divsf3 +.global __hexagon_fast2_divsf3 ; .set __hexagon_fast2_divsf3, __hexagon_divsf3 diff --git a/library/compiler-builtins/src/hexagon/sfsqrt_opt.s b/library/compiler-builtins/src/hexagon/sfsqrt_opt.s new file mode 100644 index 0000000000000..c90af17975412 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/sfsqrt_opt.s @@ -0,0 +1,49 @@ +FUNCTION_BEGIN __hexagon_sqrtf + { + r3,p0 = sfinvsqrta(r0) + r5 = sffixupr(r0) + r4 = ##0x3f000000 + r1:0 = combine(#0,#0) + } + { + r0 += sfmpy(r3,r5):lib + r1 += sfmpy(r3,r4):lib + r2 = r4 + r3 = r5 + } + { + r2 -= sfmpy(r0,r1):lib + p1 = sfclass(r5,#1) + + } + { + r0 += sfmpy(r0,r2):lib + r1 += sfmpy(r1,r2):lib + r2 = r4 + r3 = r5 + } + { + r2 -= sfmpy(r0,r1):lib + r3 -= sfmpy(r0,r0):lib + } + { + r0 += sfmpy(r1,r3):lib + r1 += sfmpy(r1,r2):lib + r2 = r4 + r3 = r5 + } + { + + r3 -= sfmpy(r0,r0):lib + if (p1) r0 = or(r0,r5) + } + { + r0 += sfmpy(r1,r3,p0):scale + jumpr r31 + } + +FUNCTION_END __hexagon_sqrtf + +.global __qdsp_sqrtf ; .set __qdsp_sqrtf, __hexagon_sqrtf +.global __hexagon_fast_sqrtf ; .set __hexagon_fast_sqrtf, __hexagon_sqrtf +.global __hexagon_fast2_sqrtf ; .set __hexagon_fast2_sqrtf, __hexagon_sqrtf diff --git a/library/compiler-builtins/src/hexagon/udivdi3.s b/library/compiler-builtins/src/hexagon/udivdi3.s new file mode 100644 index 0000000000000..f0fffc23df006 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/udivdi3.s @@ -0,0 +1,50 @@ + + +FUNCTION_BEGIN __hexagon_udivdi3 + { + r6 = cl0(r1:0) + r7 = cl0(r3:2) + r5:4 = r3:2 + r3:2 = r1:0 + } + { + r10 = sub(r7,r6) + r1:0 = #0 + r15:14 = #1 + } + { + r11 = add(r10,#1) + r13:12 = lsl(r5:4,r10) + r15:14 = lsl(r15:14,r10) + } + { + p0 = cmp.gtu(r5:4,r3:2) + loop0(1f,r11) + } + { + if (p0) jumpr r31 + } + .falign +1: + { + p0 = cmp.gtu(r13:12,r3:2) + } + { + r7:6 = sub(r3:2, r13:12) + r9:8 = add(r1:0, r15:14) + } + { + r1:0 = vmux(p0, r1:0, r9:8) + r3:2 = vmux(p0, r3:2, r7:6) + } + { + r15:14 = lsr(r15:14, #1) + r13:12 = lsr(r13:12, #1) + }:endloop0 + { + jumpr r31 + } +FUNCTION_END __hexagon_udivdi3 + + .globl __qdsp_udivdi3 + .set __qdsp_udivdi3, __hexagon_udivdi3 diff --git a/library/compiler-builtins/src/hexagon/udivmoddi4.s b/library/compiler-builtins/src/hexagon/udivmoddi4.s new file mode 100644 index 0000000000000..cbfb3987dd2be --- /dev/null +++ b/library/compiler-builtins/src/hexagon/udivmoddi4.s @@ -0,0 +1,50 @@ + + +FUNCTION_BEGIN __hexagon_udivmoddi4 + { + r6 = cl0(r1:0) + r7 = cl0(r3:2) + r5:4 = r3:2 + r3:2 = r1:0 + } + { + r10 = sub(r7,r6) + r1:0 = #0 + r15:14 = #1 + } + { + r11 = add(r10,#1) + r13:12 = lsl(r5:4,r10) + r15:14 = lsl(r15:14,r10) + } + { + p0 = cmp.gtu(r5:4,r3:2) + loop0(1f,r11) + } + { + if (p0) jumpr r31 + } + .falign +1: + { + p0 = cmp.gtu(r13:12,r3:2) + } + { + r7:6 = sub(r3:2, r13:12) + r9:8 = add(r1:0, r15:14) + } + { + r1:0 = vmux(p0, r1:0, r9:8) + r3:2 = vmux(p0, r3:2, r7:6) + } + { + r15:14 = lsr(r15:14, #1) + r13:12 = lsr(r13:12, #1) + }:endloop0 + { + jumpr r31 + } +FUNCTION_END __hexagon_udivmoddi4 + + .globl __qdsp_udivmoddi4 + .set __qdsp_udivmoddi4, __hexagon_udivmoddi4 diff --git a/library/compiler-builtins/src/hexagon/udivmodsi4.s b/library/compiler-builtins/src/hexagon/udivmodsi4.s new file mode 100644 index 0000000000000..83489c5143151 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/udivmodsi4.s @@ -0,0 +1,39 @@ + + +FUNCTION_BEGIN __hexagon_udivmodsi4 + { + r2 = cl0(r0) + r3 = cl0(r1) + r5:4 = combine(#1,#0) + p0 = cmp.gtu(r1,r0) + } + { + r6 = sub(r3,r2) + r4 = r1 + r1:0 = combine(r0,r4) + if (p0) jumpr r31 + } + { + r3:2 = vlslw(r5:4,r6) + loop0(1f,r6) + p0 = cmp.eq(r6,#0) + if (p0.new) r4 = #0 + } + .falign +1: + { + p0 = cmp.gtu(r2,r1) + if (!p0.new) r1 = sub(r1,r2) + if (!p0.new) r0 = add(r0,r3) + r3:2 = vlsrw(r3:2,#1) + }:endloop0 + { + p0 = cmp.gtu(r2,r1) + if (!p0.new) r1 = sub(r1,r4) + if (!p0.new) r0 = add(r0,r3) + jumpr r31 + } +FUNCTION_END __hexagon_udivmodsi4 + + .globl __qdsp_udivmodsi4 + .set __qdsp_udivmodsi4, __hexagon_udivmodsi4 diff --git a/library/compiler-builtins/src/hexagon/udivsi3.s b/library/compiler-builtins/src/hexagon/udivsi3.s new file mode 100644 index 0000000000000..e0b94aa99826e --- /dev/null +++ b/library/compiler-builtins/src/hexagon/udivsi3.s @@ -0,0 +1,36 @@ + + +FUNCTION_BEGIN __hexagon_udivsi3 + { + r2 = cl0(r0) + r3 = cl0(r1) + r5:4 = combine(#1,#0) + p0 = cmp.gtu(r1,r0) + } + { + r6 = sub(r3,r2) + r4 = r1 + r1:0 = combine(r0,r4) + if (p0) jumpr r31 + } + { + r3:2 = vlslw(r5:4,r6) + loop0(1f,r6) + } + .falign +1: + { + p0 = cmp.gtu(r2,r1) + if (!p0.new) r1 = sub(r1,r2) + if (!p0.new) r0 = add(r0,r3) + r3:2 = vlsrw(r3:2,#1) + }:endloop0 + { + p0 = cmp.gtu(r2,r1) + if (!p0.new) r0 = add(r0,r3) + jumpr r31 + } +FUNCTION_END __hexagon_udivsi3 + + .globl __qdsp_udivsi3 + .set __qdsp_udivsi3, __hexagon_udivsi3 diff --git a/library/compiler-builtins/src/hexagon/umoddi3.s b/library/compiler-builtins/src/hexagon/umoddi3.s new file mode 100644 index 0000000000000..c76011c3e7aef --- /dev/null +++ b/library/compiler-builtins/src/hexagon/umoddi3.s @@ -0,0 +1,53 @@ + + +FUNCTION_BEGIN __hexagon_umoddi3 + { + r6 = cl0(r1:0) + r7 = cl0(r3:2) + r5:4 = r3:2 + r3:2 = r1:0 + } + { + r10 = sub(r7,r6) + r1:0 = #0 + r15:14 = #1 + } + { + r11 = add(r10,#1) + r13:12 = lsl(r5:4,r10) + r15:14 = lsl(r15:14,r10) + } + { + p0 = cmp.gtu(r5:4,r3:2) + loop0(1f,r11) + } + { + if (p0) jump .hexagon_umoddi3_return + } + .falign +1: + { + p0 = cmp.gtu(r13:12,r3:2) + } + { + r7:6 = sub(r3:2, r13:12) + r9:8 = add(r1:0, r15:14) + } + { + r1:0 = vmux(p0, r1:0, r9:8) + r3:2 = vmux(p0, r3:2, r7:6) + } + { + r15:14 = lsr(r15:14, #1) + r13:12 = lsr(r13:12, #1) + }:endloop0 + +.hexagon_umoddi3_return: + { + r1:0 = r3:2 + jumpr r31 + } +FUNCTION_END __hexagon_umoddi3 + + .globl __qdsp_umoddi3 + .set __qdsp_umoddi3, __hexagon_umoddi3 diff --git a/library/compiler-builtins/src/hexagon/umodsi3.s b/library/compiler-builtins/src/hexagon/umodsi3.s new file mode 100644 index 0000000000000..1b592a7c56184 --- /dev/null +++ b/library/compiler-builtins/src/hexagon/umodsi3.s @@ -0,0 +1,34 @@ + + +FUNCTION_BEGIN __hexagon_umodsi3 + { + r2 = cl0(r0) + r3 = cl0(r1) + p0 = cmp.gtu(r1,r0) + } + { + r2 = sub(r3,r2) + if (p0) jumpr r31 + } + { + loop0(1f,r2) + p1 = cmp.eq(r2,#0) + r2 = lsl(r1,r2) + } + .falign +1: + { + p0 = cmp.gtu(r2,r0) + if (!p0.new) r0 = sub(r0,r2) + r2 = lsr(r2,#1) + if (p1) r1 = #0 + }:endloop0 + { + p0 = cmp.gtu(r2,r0) + if (!p0.new) r0 = sub(r0,r1) + jumpr r31 + } +FUNCTION_END __hexagon_umodsi3 + + .globl __qdsp_umodsi3 + .set __qdsp_umodsi3, __hexagon_umodsi3 diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 3e54918782be6..47aef540e41c7 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,6 +1,7 @@ #![cfg_attr(feature = "compiler-builtins", compiler_builtins)] #![cfg_attr(not(feature = "no-asm"), feature(asm))] #![feature(abi_unadjusted)] +#![feature(asm_experimental_arch)] #![cfg_attr(not(feature = "no-asm"), feature(global_asm))] #![feature(cfg_target_has_atomic)] #![feature(compiler_builtins)] @@ -70,6 +71,9 @@ pub mod aarch64_linux; ))] pub mod arm_linux; +#[cfg(target_arch = "hexagon")] +pub mod hexagon; + #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] pub mod riscv; From 72dbe301ff7ebf19fc01dc790973bc24d8742347 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 14 Dec 2023 20:23:55 +0000 Subject: [PATCH 1164/4206] Bump to 0.1.105 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 6ebabfdcbebaf..1b8b426ce05e6 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.104" +version = "0.1.105" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From e898296fd9bc1937e4156cc44e30b7f92f90342f Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 20 Dec 2023 09:30:11 +1000 Subject: [PATCH 1165/4206] build: Allow building C compiler-rt fallbacks for RISC-V Now that https://github.com/rust-lang/rust/pull/117654 has been merged the rust-lang/rust distribution containers contain RISC-V C compilers. This means that we can now enable the "c" feature fallback. Resolves: https://github.com/rust-lang/compiler-builtins/issues/350 Signed-off-by: Alistair Francis --- library/compiler-builtins/build.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 0486116778c0c..d4b2a9b499e99 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -59,12 +59,7 @@ fn main() { // * wasm - clang for wasm is somewhat hard to come by and it's // unlikely that the C is really that much better than our own Rust. // * nvptx - everything is bitcode, not compatible with mixed C/Rust - // * riscv - the rust-lang/rust distribution container doesn't have a C - // compiler. - if !target.contains("wasm") - && !target.contains("nvptx") - && (!target.starts_with("riscv") || target.contains("xous")) - { + if !target.contains("wasm") && !target.contains("nvptx") { #[cfg(feature = "c")] c::compile(&llvm_target, &target); } @@ -519,7 +514,7 @@ mod c { } } - if target_arch == "mips" { + if target_arch == "mips" || target_arch == "riscv32" || target_arch == "riscv64" { sources.extend(&[("__bswapsi2", "bswapsi2.c")]); } From c464d5a38d5030ca413686b65b3389acea9e71b9 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Tue, 9 Jan 2024 00:07:27 +0900 Subject: [PATCH 1166/4206] Update actions/checkout action to v4 --- library/compiler-builtins/.github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index b69c48c16a955..360ed97391d6f 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -80,7 +80,7 @@ jobs: os: windows-latest rust: nightly-x86_64-gnu steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 with: submodules: true - name: Install Rust (rustup) @@ -108,7 +108,7 @@ jobs: name: Rustfmt runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 with: submodules: true - name: Install stable `rustfmt` @@ -119,7 +119,7 @@ jobs: name: Clippy runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 with: submodules: true # Unlike rustfmt, stable clippy does not work on code with nightly features. From 0808cdeb67fa5e0ec24c381e0164eee021b5b1b0 Mon Sep 17 00:00:00 2001 From: trevyn <230691+trevyn@users.noreply.github.com> Date: Tue, 9 Jan 2024 01:23:59 +0400 Subject: [PATCH 1167/4206] build: Allow building C compiler-rt fallbacks for wasm --- library/compiler-builtins/.github/workflows/main.yml | 4 ++-- library/compiler-builtins/build.rs | 7 +------ .../ci/docker/wasm32-unknown-unknown/Dockerfile | 2 +- library/compiler-builtins/ci/run.sh | 1 + 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index b69c48c16a955..8110e27f76e03 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -90,8 +90,8 @@ jobs: - run: rustup component add llvm-tools-preview - name: Download compiler-rt reference sources run: | - curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/12.0-2021-04-15.tar.gz - tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-12.0-2021-04-15/compiler-rt + curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/13.0-2021-08-08.tar.gz + tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-13.0-2021-08-08/compiler-rt echo RUST_COMPILER_RT_ROOT=./compiler-rt >> $GITHUB_ENV shell: bash diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 0486116778c0c..9bf6a25472419 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -56,15 +56,10 @@ fn main() { if !cfg!(feature = "mangled-names") && cfg!(feature = "c") { // Don't use a C compiler for these targets: // - // * wasm - clang for wasm is somewhat hard to come by and it's - // unlikely that the C is really that much better than our own Rust. // * nvptx - everything is bitcode, not compatible with mixed C/Rust // * riscv - the rust-lang/rust distribution container doesn't have a C // compiler. - if !target.contains("wasm") - && !target.contains("nvptx") - && (!target.starts_with("riscv") || target.contains("xous")) - { + if !target.contains("nvptx") && (!target.starts_with("riscv") || target.contains("xous")) { #[cfg(feature = "c")] c::compile(&llvm_target, &target); } diff --git a/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile b/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile index 758d94d5013be..85ead29aaee62 100644 --- a/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile +++ b/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:20.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates + gcc clang libc6-dev ca-certificates ENV CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER=true diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 44ec30fb79871..6376d2216d9e1 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -66,6 +66,7 @@ for rlib in $(echo $path); do grep -v __x86.get_pc_thunk | \ grep -v __builtin_cl | \ grep -v __builtin_ctz | \ + grep -v __builtin_sadd_overflow | \ grep 'T __' if test $? = 0; then From 0dc7f73408c4465f73d7b9cc14877fa6b12e4ac1 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 18 Jan 2024 01:27:08 +0000 Subject: [PATCH 1168/4206] Bump to 0.1.106 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 1b8b426ce05e6..e3540f4658eb1 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.105" +version = "0.1.106" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 105f0d834d67546166ec44be3d561a8b7739c98e Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 22 Jan 2024 12:55:25 +0100 Subject: [PATCH 1169/4206] Only add 80-bit long double source on x86 These no longer build on other architectures with LLVM 18. In previous versions they used an incorrect float layout. --- library/compiler-builtins/build.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index d4b2a9b499e99..690a4fc9b6878 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -290,17 +290,23 @@ mod c { sources.extend(&[ ("__divdc3", "divdc3.c"), ("__divsc3", "divsc3.c"), - ("__divxc3", "divxc3.c"), ("__extendhfsf2", "extendhfsf2.c"), ("__muldc3", "muldc3.c"), ("__mulsc3", "mulsc3.c"), - ("__mulxc3", "mulxc3.c"), ("__negdf2", "negdf2.c"), ("__negsf2", "negsf2.c"), - ("__powixf2", "powixf2.c"), ("__truncdfhf2", "truncdfhf2.c"), ("__truncsfhf2", "truncsfhf2.c"), ]); + + if target_arch == "x86" || target_arch == "x86_64" { + // Only add 80-bit long double sources on x86. + sources.extend(&[ + ("__divxc3", "divxc3.c"), + ("__mulxc3", "mulxc3.c"), + ("__powixf2", "powixf2.c"), + ]); + } } // When compiling in rustbuild (the rust-lang/rust repo) this library From 8ca492c7d7858ded13f2f83c560d8b467e700a54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 24 Jan 2024 19:38:55 +0100 Subject: [PATCH 1170/4206] CI: add a success conclusion job --- .../compiler-builtins/.github/workflows/main.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 360ed97391d6f..9f15cb9d831b2 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -128,3 +128,18 @@ jobs: run: | rustup set profile minimal && rustup default "nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/clippy)" && rustup component add clippy - run: cargo clippy -- -D clippy::all + + success: + needs: + - test + - rustfmt + - clippy + runs-on: ubuntu-latest + # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency + # 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" + 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) }}' From 845f4e75d12c43acbbc7a7347e6d07ee2094f21a Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Wed, 24 Jan 2024 13:57:31 -0500 Subject: [PATCH 1171/4206] fix: replace travis link with github actions link --- library/compiler-builtins/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index da0adbce70c65..adcdcacbac128 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -62,7 +62,7 @@ features = ["c"] [1]: https://github.com/rust-lang/llvm-project/tree/9e3de9490ff580cd484fbfa2908292b4838d56e7/compiler-rt/test/builtins/Unit [2]: https://github.com/rust-lang/llvm-project/tree/9e3de9490ff580cd484fbfa2908292b4838d56e7/compiler-rt/lib/builtins [3]: https://github.com/rust-lang/compiler-builtins/blob/0ba07e49264a54cb5bbd4856fcea083bb3fbec15/build.rs#L180-L265 -[4]: https://travis-ci.org/rust-lang/compiler-builtins +[4]: https://github.com/rust-lang/compiler-builtins/actions ### Porting Reminders From 45a113effb32fabd8d6098a412bca2a2cbb85f15 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Thu, 4 Jan 2024 18:43:58 -0800 Subject: [PATCH 1172/4206] Handle move of cpu_model.c This happened in https://github.com/llvm/llvm-project/pull/75635/files and shows up when building against a recent commit of LLVM. --- library/compiler-builtins/build.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 690a4fc9b6878..c133d5e7ced63 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -602,7 +602,12 @@ mod c { build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg); // Some run-time CPU feature detection is necessary, as well. - sources.extend(&[("__aarch64_have_lse_atomics", "cpu_model.c")]); + let cpu_model_src = if src_dir.join("cpu_model.c").exists() { + "cpu_model.c" + } else { + "cpu_model/aarch64.c" + }; + sources.extend(&[("__aarch64_have_lse_atomics", cpu_model_src)]); } let mut added_sources = HashSet::new(); From 1cd23fa8b0343828dd523009eebb20ff8e03d097 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 31 Jan 2024 08:36:00 +0000 Subject: [PATCH 1173/4206] Bump to 0.1.107 (#571) --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index e3540f4658eb1..b7e504ad5d719 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.106" +version = "0.1.107" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 2f8b08f9e34ce405befb67ff681595fb30add102 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Wed, 31 Jan 2024 17:37:26 +0100 Subject: [PATCH 1174/4206] Remove 80-bit builtins entirely It turns out that these also don't build on x86 + MSVC. Rather than fixing up the condition, I'm just deleting them entirely. As far as I know, Rust does not support 80-bit floats and has no plan to support them, so we shouldn't need them. --- library/compiler-builtins/build.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 6ad7f71538ef6..8082131ef8cbf 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -296,15 +296,6 @@ mod c { ("__truncdfhf2", "truncdfhf2.c"), ("__truncsfhf2", "truncsfhf2.c"), ]); - - if target_arch == "x86" || target_arch == "x86_64" { - // Only add 80-bit long double sources on x86. - sources.extend(&[ - ("__divxc3", "divxc3.c"), - ("__mulxc3", "mulxc3.c"), - ("__powixf2", "powixf2.c"), - ]); - } } // When compiling in rustbuild (the rust-lang/rust repo) this library From 168bc9ecd7214e33610d6a53212026d35b49c89d Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 2 Feb 2024 10:04:55 +0100 Subject: [PATCH 1175/4206] Also don't build floatdixf and floatundixf --- library/compiler-builtins/build.rs | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 8082131ef8cbf..6268fd2ff3419 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -347,29 +347,12 @@ mod c { ]); } - if target_env == "msvc" { - if target_arch == "x86_64" { - sources.extend(&[("__floatdixf", "x86_64/floatdixf.c")]); - } - } else { - // None of these seem to be used on x86_64 windows, and they've all - // got the wrong ABI anyway, so we want to avoid them. - if target_os != "windows" { - if target_arch == "x86_64" { - sources.extend(&[ - ("__floatdixf", "x86_64/floatdixf.c"), - ("__floatundixf", "x86_64/floatundixf.S"), - ]); - } - } - + if target_env != "msvc" { if target_arch == "x86" { sources.extend(&[ ("__ashldi3", "i386/ashldi3.S"), ("__ashrdi3", "i386/ashrdi3.S"), ("__divdi3", "i386/divdi3.S"), - ("__floatdixf", "i386/floatdixf.S"), - ("__floatundixf", "i386/floatundixf.S"), ("__lshrdi3", "i386/lshrdi3.S"), ("__moddi3", "i386/moddi3.S"), ("__muldi3", "i386/muldi3.S"), From 079d7d857ca878d13d3a5ceed917e7627735b8e8 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 4 Feb 2024 06:37:55 +0000 Subject: [PATCH 1176/4206] Release 0.1.108 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index b7e504ad5d719..e94c2f7625f78 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.107" +version = "0.1.108" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From cdf7ac490c22f055b83d1068bfc455f2b63fdd9f Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 21 Feb 2024 00:58:14 +0000 Subject: [PATCH 1177/4206] Allow internal_features lint when building with "unstable" --- library/compiler-builtins/libm/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 4a17d3a77a213..1f23ef8a80e17 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -1,7 +1,8 @@ //! libm in pure Rust #![deny(warnings)] #![no_std] -#![cfg_attr(all(feature = "unstable"), feature(core_intrinsics))] +#![cfg_attr(feature = "unstable", allow(internal_features))] +#![cfg_attr(feature = "unstable", feature(core_intrinsics))] #![allow(clippy::unreadable_literal)] #![allow(clippy::many_single_char_names)] #![allow(clippy::needless_return)] From d752cbfb0ebcad536011a6a03612775450d63c9a Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Sun, 11 Feb 2024 18:03:42 +0800 Subject: [PATCH 1178/4206] Remove unneeded `extern core` in `tgamma` --- library/compiler-builtins/libm/src/math/tgamma.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/tgamma.rs b/library/compiler-builtins/libm/src/math/tgamma.rs index e64eff61f0669..3f38c0b1d9fd7 100644 --- a/library/compiler-builtins/libm/src/math/tgamma.rs +++ b/library/compiler-builtins/libm/src/math/tgamma.rs @@ -22,7 +22,6 @@ Gamma(x)*Gamma(-x) = -pi/(x sin(pi x)) most ideas and constants are from boost and python */ -extern crate core; use super::{exp, floor, k_cos, k_sin, pow}; const PI: f64 = 3.141592653589793238462643383279502884; From 68b5a7a0ad1d516955c13a0dde3d1ec0c547472d Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 24 Mar 2024 20:27:38 +0000 Subject: [PATCH 1179/4206] Clean up and rework CI script --- .../.github/workflows/main.yml | 1 + .../ci/docker/thumbv6m-none-eabi/Dockerfile | 2 +- .../ci/docker/thumbv7em-none-eabi/Dockerfile | 2 +- .../docker/thumbv7em-none-eabihf/Dockerfile | 2 +- .../ci/docker/thumbv7m-none-eabi/Dockerfile | 2 +- library/compiler-builtins/ci/run.sh | 58 ++++++++++--------- 6 files changed, 37 insertions(+), 30 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 9071e4ff063df..f5600c1ed3208 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -6,6 +6,7 @@ jobs: name: Test runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: include: - target: aarch64-unknown-linux-gnu diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile index 04d4f4429051b..dc7dd431ba382 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -4,4 +4,4 @@ RUN apt-get update && \ gcc libc6-dev ca-certificates \ gcc-arm-none-eabi \ libnewlib-arm-none-eabi -ENV XARGO=1 +ENV NO_STD=1 diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile index 04d4f4429051b..dc7dd431ba382 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -4,4 +4,4 @@ RUN apt-get update && \ gcc libc6-dev ca-certificates \ gcc-arm-none-eabi \ libnewlib-arm-none-eabi -ENV XARGO=1 +ENV NO_STD=1 diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile index 04d4f4429051b..dc7dd431ba382 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -4,4 +4,4 @@ RUN apt-get update && \ gcc libc6-dev ca-certificates \ gcc-arm-none-eabi \ libnewlib-arm-none-eabi -ENV XARGO=1 +ENV NO_STD=1 diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile index 04d4f4429051b..dc7dd431ba382 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -4,4 +4,4 @@ RUN apt-get update && \ gcc libc6-dev ca-certificates \ gcc-arm-none-eabi \ libnewlib-arm-none-eabi -ENV XARGO=1 +ENV NO_STD=1 diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 6376d2216d9e1..b059d56605229 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -1,10 +1,7 @@ set -ex -cargo=cargo - # Test our implementation -if [ "$XARGO" = "1" ]; then - # FIXME: currently these tests don't work... +if [ "$NO_STD" = "1" ]; then echo nothing to do else run="cargo test --manifest-path testcrate/Cargo.toml --target $1" @@ -16,6 +13,15 @@ else $run --features no-asm --release fi +if [ -d /target ]; then + path=/target/${1}/debug/deps/libcompiler_builtins-*.rlib +else + path=target/${1}/debug/deps/libcompiler_builtins-*.rlib +fi + +# Remove any existing artifacts from previous tests that don't set #![compiler_builtins] +rm -f $path + cargo build --target $1 cargo build --target $1 --release cargo build --target $1 --features c @@ -36,15 +42,15 @@ case $1 in ;; esac -NM=$(find $(rustc --print sysroot) -name llvm-nm) +NM=$(find $(rustc --print sysroot) \( -name llvm-nm -o -name llvm-nm.exe \) ) if [ "$NM" = "" ]; then NM=${PREFIX}nm fi - -if [ -d /target ]; then - path=/target/${1}/debug/deps/libcompiler_builtins-*.rlib -else - path=target/${1}/debug/deps/libcompiler_builtins-*.rlib +# i686-pc-windows-gnu tools have a dependency on some DLLs, so run it with +# rustup run to ensure that those are in PATH. +TOOLCHAIN=$(rustup show active-toolchain | sed 's/ (default)//') +if [[ $TOOLCHAIN == *i686-pc-windows-gnu ]]; then + NM="rustup run $TOOLCHAIN $NM" fi # Look out for duplicated symbols when we include the compiler-rt (C) implementation @@ -79,29 +85,29 @@ done rm -f $path # Verify that we haven't drop any intrinsic/symbol -build_intrinsics="$cargo build --target $1 -v --example intrinsics" -RUSTFLAGS="-C debug-assertions=no" $build_intrinsics -RUSTFLAGS="-C debug-assertions=no" $build_intrinsics --release -RUSTFLAGS="-C debug-assertions=no" $build_intrinsics --features c -RUSTFLAGS="-C debug-assertions=no" $build_intrinsics --features c --release +build_intrinsics="cargo build --target $1 -v --example intrinsics" +$build_intrinsics +$build_intrinsics --release +$build_intrinsics --features c +$build_intrinsics --features c --release # Verify that there are no undefined symbols to `panic` within our # implementations -# -# TODO(#79) fix the undefined references problem for debug-assertions+lto -if [ -z "$DEBUG_LTO_BUILD_DOESNT_WORK" ]; then - RUSTFLAGS="-C debug-assertions=no" \ - CARGO_INCREMENTAL=0 \ - CARGO_PROFILE_DEV_LTO=true \ - $cargo rustc --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics -fi +CARGO_PROFILE_DEV_LTO=true \ + cargo build --target $1 --example intrinsics CARGO_PROFILE_RELEASE_LTO=true \ - $cargo rustc --features "$INTRINSICS_FEATURES" --target $1 --example intrinsics --release + cargo build --target $1 --example intrinsics --release -# Ensure no references to a panicking function +# Ensure no references to any symbols from core for rlib in $(echo $path); do set +ex - $NM -u $rlib 2>&1 | grep panicking + echo "================================================================" + echo checking $rlib for references to core + echo "================================================================" + + $NM --quiet -U $rlib | grep 'T _ZN4core' | awk '{print $3}' | sort | uniq > defined_symbols.txt + $NM --quiet -u $rlib | grep 'U _ZN4core' | awk '{print $2}' | sort | uniq > undefined_symbols.txt + grep -v -F -x -f defined_symbols.txt undefined_symbols.txt if test $? = 0; then exit 1 From ce85d06f3b4e76ac22ec6cc1dc40b9548fff6a5b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 27 Mar 2024 18:16:35 +0100 Subject: [PATCH 1180/4206] add c_unwind feature --- library/compiler-builtins/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 47aef540e41c7..66540bb9b6bd8 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -12,6 +12,7 @@ #![feature(linkage)] #![feature(naked_functions)] #![feature(repr_simd)] +#![feature(c_unwind)] #![no_builtins] #![no_std] #![allow(unused_features)] From 75624cc8aecd693871aa95d5126023f1eaa81ef9 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Tue, 14 Nov 2023 18:43:39 +0800 Subject: [PATCH 1181/4206] Add compiler-rt fallbacks on loongarch64-musl --- library/compiler-builtins/build.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 6268fd2ff3419..1b901b7e8fab5 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -514,6 +514,24 @@ mod c { ]); } + if target_arch == "loongarch64" { + sources.extend(&[ + ("__extenddftf2", "extenddftf2.c"), + ("__netf2", "comparetf2.c"), + ("__addtf3", "addtf3.c"), + ("__multf3", "multf3.c"), + ("__subtf3", "subtf3.c"), + ("__fixtfsi", "fixtfsi.c"), + ("__floatsitf", "floatsitf.c"), + ("__fixunstfsi", "fixunstfsi.c"), + ("__floatunsitf", "floatunsitf.c"), + ("__fe_getround", "fp_mode.c"), + ("__divtf3", "divtf3.c"), + ("__trunctfdf2", "trunctfdf2.c"), + ("__trunctfsf2", "trunctfsf2.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" { From dc1321a5ca88cb97aa845bd0221d5e3a26396777 Mon Sep 17 00:00:00 2001 From: trevyn <230691+trevyn@users.noreply.github.com> Date: Thu, 8 Feb 2024 07:34:09 -0800 Subject: [PATCH 1182/4206] Remove duplicate symbol workaround --- library/compiler-builtins/.github/workflows/main.yml | 4 ++-- library/compiler-builtins/ci/run.sh | 5 ----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index f5600c1ed3208..97d298cf09c19 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -91,8 +91,8 @@ jobs: - run: rustup component add llvm-tools-preview - name: Download compiler-rt reference sources run: | - curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/13.0-2021-08-08.tar.gz - tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-13.0-2021-08-08/compiler-rt + curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/18.0-2024-02-13.tar.gz + tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-18.0-2024-02-13/compiler-rt echo RUST_COMPILER_RT_ROOT=./compiler-rt >> $GITHUB_ENV shell: bash diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index b059d56605229..09728191a228a 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -63,16 +63,11 @@ for rlib in $(echo $path); do stdout=$($NM -g --defined-only $rlib 2>&1) # NOTE On i586, It's normal that the get_pc_thunk symbol appears several # times so ignore it - # - # FIXME(#167) - we shouldn't ignore `__builtin_cl` style symbols here. set +e echo "$stdout" | \ sort | \ uniq -d | \ grep -v __x86.get_pc_thunk | \ - grep -v __builtin_cl | \ - grep -v __builtin_ctz | \ - grep -v __builtin_sadd_overflow | \ grep 'T __' if test $? = 0; then From 30182128c970316f820d97ae4e889107bd0077be Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Fri, 23 Feb 2024 10:51:15 -0800 Subject: [PATCH 1183/4206] Add support for arm64ec --- library/compiler-builtins/build.rs | 2 +- library/compiler-builtins/src/lib.rs | 2 +- library/compiler-builtins/testcrate/tests/lse.rs | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 1b901b7e8fab5..44946c1240c9e 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -461,7 +461,7 @@ mod c { ]); } - if target_arch == "aarch64" && consider_float_intrinsics { + if (target_arch == "aarch64" || target_arch == "arm64ec") && consider_float_intrinsics { sources.extend(&[ ("__comparetf2", "comparetf2.c"), ("__extenddftf2", "extenddftf2.c"), diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 66540bb9b6bd8..a414efde0ce91 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -59,7 +59,7 @@ pub mod mem; #[cfg(target_arch = "arm")] pub mod arm; -#[cfg(target_arch = "aarch64")] +#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] pub mod aarch64; #[cfg(all(target_arch = "aarch64", target_os = "linux", not(feature = "no-asm"),))] diff --git a/library/compiler-builtins/testcrate/tests/lse.rs b/library/compiler-builtins/testcrate/tests/lse.rs index 5589f22f1e93e..63c98957cf4f6 100644 --- a/library/compiler-builtins/testcrate/tests/lse.rs +++ b/library/compiler-builtins/testcrate/tests/lse.rs @@ -1,5 +1,8 @@ #![feature(decl_macro)] // so we can use pub(super) -#![cfg(all(target_arch = "aarch64", not(feature = "no-asm")))] +#![cfg(all( + any(target_arch = "aarch64", target_arch = "arm64ec"), + not(feature = "no-asm") +))] /// Translate a byte size to a Rust type. macro int_ty { From f04f8a6a9dcf7d813fb23f6af03437fc3bf54bcd Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Sat, 10 Feb 2024 14:47:03 +0100 Subject: [PATCH 1184/4206] Sync x86 chkstk intrinsics with LLVM Incorporates the following commits: https://github.com/llvm/llvm-project/commit/885d7b759b5c166c07c07f4c58c6e0ba110fb0c2 https://github.com/llvm/llvm-project/commit/1f9eff100ce8faea1284d68b779d844c6e019b77 https://github.com/llvm/llvm-project/commit/7a5cba8bea8f774d48db1b0426bcc102edd2b69f --- library/compiler-builtins/README.md | 2 -- library/compiler-builtins/src/x86.rs | 47 ++----------------------- library/compiler-builtins/src/x86_64.rs | 44 ----------------------- 3 files changed, 2 insertions(+), 91 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index adcdcacbac128..ffef4e52c79f1 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -163,7 +163,6 @@ features = ["c"] - [ ] i386/ashldi3.S - [ ] i386/ashrdi3.S - [x] i386/chkstk.S -- [x] i386/chkstk2.S - [ ] i386/divdi3.S - [ ] i386/lshrdi3.S - [ ] i386/moddi3.S @@ -192,7 +191,6 @@ features = ["c"] - [x] umoddi3.c - [x] umodsi3.c - [x] x86_64/chkstk.S -- [x] x86_64/chkstk2.S These builtins are needed to support 128-bit integers, which are in the process of being added to Rust. diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs index fd1f32e3a7d8b..5016816eb36c3 100644 --- a/library/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/src/x86.rs @@ -6,7 +6,6 @@ use core::intrinsics; // calling convention which can't be implemented using a normal Rust function // NOTE These functions are never mangled as they are not tested against compiler-rt -// and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca intrinsics! { #[naked] @@ -15,50 +14,8 @@ intrinsics! { target_env = "gnu", not(feature = "no-asm") ))] - pub unsafe extern "C" fn ___chkstk_ms() { - core::arch::asm!( - "push %ecx", - "push %eax", - "cmp $0x1000,%eax", - "lea 12(%esp),%ecx", - "jb 1f", - "2:", - "sub $0x1000,%ecx", - "test %ecx,(%ecx)", - "sub $0x1000,%eax", - "cmp $0x1000,%eax", - "ja 2b", - "1:", - "sub %eax,%ecx", - "test %ecx,(%ecx)", - "pop %eax", - "pop %ecx", - "ret", - options(noreturn, att_syntax) - ); - } - - // FIXME: __alloca should be an alias to __chkstk - #[naked] - #[cfg(all( - windows, - target_env = "gnu", - not(feature = "no-asm") - ))] - pub unsafe extern "C" fn __alloca() { - core::arch::asm!( - "jmp ___chkstk", // Jump to ___chkstk since fallthrough may be unreliable" - options(noreturn, att_syntax) - ); - } - - #[naked] - #[cfg(all( - windows, - target_env = "gnu", - not(feature = "no-asm") - ))] - pub unsafe extern "C" fn ___chkstk() { + pub unsafe extern "C" fn _alloca() { + // _chkstk and _alloca are the same function core::arch::asm!( "push %ecx", "cmp $0x1000,%eax", diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 7ad94115825a1..8048f85c8ffaa 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -6,7 +6,6 @@ use core::intrinsics; // calling convention which can't be implemented using a normal Rust function // NOTE These functions are never mangled as they are not tested against compiler-rt -// and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca intrinsics! { #[naked] @@ -36,49 +35,6 @@ intrinsics! { options(noreturn, att_syntax) ); } - - #[naked] - #[cfg(all( - any(all(windows, target_env = "gnu"), target_os = "uefi"), - not(feature = "no-asm") - ))] - pub unsafe extern "C" fn __alloca() { - core::arch::asm!( - "mov %rcx,%rax", // x64 _alloca is a normal function with parameter in rcx - "jmp ___chkstk", // Jump to ___chkstk since fallthrough may be unreliable" - options(noreturn, att_syntax) - ); - } - - #[naked] - #[cfg(all( - any(all(windows, target_env = "gnu"), target_os = "uefi"), - not(feature = "no-asm") - ))] - pub unsafe extern "C" fn ___chkstk() { - core::arch::asm!( - "push %rcx", - "cmp $0x1000,%rax", - "lea 16(%rsp),%rcx", // rsp before calling this routine -> rcx - "jb 1f", - "2:", - "sub $0x1000,%rcx", - "test %rcx,(%rcx)", - "sub $0x1000,%rax", - "cmp $0x1000,%rax", - "ja 2b", - "1:", - "sub %rax,%rcx", - "test %rcx,(%rcx)", - "lea 8(%rsp),%rax", // load pointer to the return address into rax - "mov %rcx,%rsp", // install the new top of stack pointer into rsp - "mov -8(%rax),%rcx", // restore rcx - "push (%rax)", // push return address onto the stack - "sub %rsp,%rax", // restore the original value in rax - "ret", - options(noreturn, att_syntax) - ); - } } // HACK(https://github.com/rust-lang/rust/issues/62785): x86_64-unknown-uefi needs special LLVM From 9c0ab26d3be9f4543376457498d4dc6fa12fd539 Mon Sep 17 00:00:00 2001 From: Jeff Thuong Date: Tue, 2 Apr 2024 11:35:08 +0800 Subject: [PATCH 1185/4206] Corrected English typos --- library/compiler-builtins/libm/src/math/ceil.rs | 2 +- library/compiler-builtins/libm/src/math/floor.rs | 2 +- library/compiler-builtins/libm/src/math/pow.rs | 2 +- library/compiler-builtins/libm/src/math/sqrt.rs | 2 +- library/compiler-builtins/libm/src/math/sqrtf.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index 22d89297138c9..cde5a19d0c807 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -20,7 +20,7 @@ pub fn ceil(x: f64) -> f64 { { //use an alternative implementation on x86, because the //main implementation fails with the x87 FPU used by - //debian i386, probablly due to excess precision issues. + //debian i386, probably due to excess precision issues. //basic implementation taken from https://github.com/rust-lang/libm/issues/219 use super::fabs; if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index d09f9a1a1f81f..b7d1a04d2cd35 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -20,7 +20,7 @@ pub fn floor(x: f64) -> f64 { { //use an alternative implementation on x86, because the //main implementation fails with the x87 FPU used by - //debian i386, probablly due to excess precision issues. + //debian i386, probably due to excess precision issues. //basic implementation taken from https://github.com/rust-lang/libm/issues/219 use super::fabs; if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 6a19ae601116e..09d12c1851b48 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -16,7 +16,7 @@ // 1. Compute and return log2(x) in two pieces: // log2(x) = w1 + w2, // where w1 has 53-24 = 29 bit trailing zeros. -// 2. Perform y*log2(x) = n+y' by simulating muti-precision +// 2. Perform y*log2(x) = n+y' by simulating multi-precision // arithmetic, where |y'|<=0.5. // 3. Return x**y = 2**n*exp(y'*log2) // diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 3733ba0400f6c..baa0db9f8d14a 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -96,7 +96,7 @@ pub fn sqrt(x: f64) -> f64 { { // Note: This path is unlikely since LLVM will usually have already // optimized sqrt calls into hardware instructions if sse2 is available, - // but if someone does end up here they'll apprected the speed increase. + // but if someone does end up here they'll appreciate the speed increase. #[cfg(target_arch = "x86")] use core::arch::x86::*; #[cfg(target_arch = "x86_64")] diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 8ec72fbf7fae3..12bd60028eef7 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -31,7 +31,7 @@ pub fn sqrtf(x: f32) -> f32 { { // Note: This path is unlikely since LLVM will usually have already // optimized sqrt calls into hardware instructions if sse is available, - // but if someone does end up here they'll apprected the speed increase. + // but if someone does end up here they'll appreciate the speed increase. #[cfg(target_arch = "x86")] use core::arch::x86::*; #[cfg(target_arch = "x86_64")] From f23a83c53cca5a10153420178395e7c7b09a8d5c Mon Sep 17 00:00:00 2001 From: Jeremy Drake Date: Sun, 7 Apr 2024 09:32:17 -0700 Subject: [PATCH 1186/4206] Add __chkstk on i686-pc-windows-gnu. libLLVMSupport.a(DynamicLibrary.cpp.obj) references ___chkstk, which is an alias of __alloca in libgcc. This crate provided __alloca, but libgcc's implementation was also pulled in by the linker due to the reference to ___chkstk, causing a multiple definition linker error. Providing that symbol here prevents that. Fixes #585 --- library/compiler-builtins/src/x86.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs index 5016816eb36c3..c348d082d9e78 100644 --- a/library/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/src/x86.rs @@ -8,6 +8,19 @@ use core::intrinsics; // NOTE These functions are never mangled as they are not tested against compiler-rt intrinsics! { + #[naked] + #[cfg(all( + windows, + target_env = "gnu", + not(feature = "no-asm") + ))] + pub unsafe extern "C" fn __chkstk() { + core::arch::asm!( + "jmp __alloca", // Jump to __alloca since fallthrough may be unreliable" + options(noreturn, att_syntax) + ); + } + #[naked] #[cfg(all( windows, @@ -15,7 +28,7 @@ intrinsics! { not(feature = "no-asm") ))] pub unsafe extern "C" fn _alloca() { - // _chkstk and _alloca are the same function + // __chkstk and _alloca are the same function core::arch::asm!( "push %ecx", "cmp $0x1000,%eax", From bf0ce314e9471d95432168a5d812a76a0681d042 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Apr 2024 21:56:02 +0200 Subject: [PATCH 1187/4206] add lib.miri.rs file for miri-test-libstd --- library/compiler-builtins/src/lib.miri.rs | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 library/compiler-builtins/src/lib.miri.rs diff --git a/library/compiler-builtins/src/lib.miri.rs b/library/compiler-builtins/src/lib.miri.rs new file mode 100644 index 0000000000000..17288058e5e8d --- /dev/null +++ b/library/compiler-builtins/src/lib.miri.rs @@ -0,0 +1,5 @@ +//! Grep bootstrap for `MIRI_REPLACE_LIBRS_IF_NOT_TEST` to learn what this is about. +#![no_std] +#![feature(rustc_private)] +extern crate compiler_builtins as real; +pub use real::*; From 5416c204a9173afadc9c69c9ca14ffd71f9ce1e8 Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Mon, 19 Feb 2024 16:41:17 +0800 Subject: [PATCH 1188/4206] Always have math functions but with `weak` linking attribute if we can This is a replacement for https://github.com/rust-lang/libm/pull/290 This fixes crashes during compilations for targets that don't have math symbols by default. So, we will provide them libm symbols, but mark it as `weak` (if its supported), so that the linker will choose the system builtin functions, since those are sometimes more optimized. If the linker couldn't find those, it will go with `libm` implementation. --- library/compiler-builtins/src/math.rs | 84 ++++++--------------------- 1 file changed, 17 insertions(+), 67 deletions(-) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 63d85833393e0..b04b0b66a7573 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -7,6 +7,7 @@ macro_rules! no_mangle { ($(fn $fun:ident($($iid:ident : $ity:ty),+) -> $oty:ty;)+) => { intrinsics! { $( + #[cfg_attr(all(not(windows), not(target_vendor = "apple")), weak)] pub extern "C" fn $fun($($iid: $ity),+) -> $oty { self::libm::$fun($($iid),+) } @@ -15,17 +16,6 @@ macro_rules! no_mangle { } } -#[cfg(any( - all( - target_family = "wasm", - target_os = "unknown", - not(target_env = "wasi") - ), - target_os = "xous", - target_os = "uefi", - all(target_arch = "xtensa", target_os = "none"), - all(target_vendor = "fortanix", target_env = "sgx") -))] no_mangle! { fn acos(x: f64) -> f64; fn asin(x: f64) -> f64; @@ -41,10 +31,6 @@ no_mangle! { fn log10f(x: f32) -> f32; fn log(x: f64) -> f64; fn logf(x: f32) -> f32; - fn fmin(x: f64, y: f64) -> f64; - fn fminf(x: f32, y: f32) -> f32; - fn fmax(x: f64, y: f64) -> f64; - fn fmaxf(x: f32, y: f32) -> f32; fn round(x: f64) -> f64; fn roundf(x: f32) -> f32; fn rint(x: f64) -> f64; @@ -52,8 +38,6 @@ no_mangle! { fn sin(x: f64) -> f64; fn pow(x: f64, y: f64) -> f64; fn powf(x: f32, y: f32) -> f32; - fn fmod(x: f64, y: f64) -> f64; - fn fmodf(x: f32, y: f32) -> f32; fn acosf(n: f32) -> f32; fn atan2f(a: f32, b: f32) -> f32; fn atanf(n: f32) -> f32; @@ -85,67 +69,17 @@ no_mangle! { fn cbrtf(n: f32) -> f32; fn hypotf(x: f32, y: f32) -> f32; fn tanf(n: f32) -> f32; -} - -#[cfg(any( - all( - target_family = "wasm", - target_os = "unknown", - not(target_env = "wasi") - ), - target_os = "xous", - target_os = "uefi", - all(target_arch = "xtensa", target_os = "none"), - all(target_vendor = "fortanix", target_env = "sgx"), - target_os = "windows" -))] -intrinsics! { - pub extern "C" fn lgamma_r(x: f64, s: &mut i32) -> f64 { - let r = self::libm::lgamma_r(x); - *s = r.1; - r.0 - } - - pub extern "C" fn lgammaf_r(x: f32, s: &mut i32) -> f32 { - let r = self::libm::lgammaf_r(x); - *s = r.1; - r.0 - } -} -#[cfg(any( - target_os = "xous", - target_os = "uefi", - all(target_arch = "xtensa", target_os = "none"), -))] -no_mangle! { fn sqrtf(x: f32) -> f32; fn sqrt(x: f64) -> f64; -} -#[cfg(any( - all(target_vendor = "fortanix", target_env = "sgx"), - all(target_arch = "xtensa", target_os = "none"), - target_os = "xous", - target_os = "uefi" -))] -no_mangle! { fn ceil(x: f64) -> f64; fn ceilf(x: f32) -> f32; fn floor(x: f64) -> f64; fn floorf(x: f32) -> f32; fn trunc(x: f64) -> f64; fn truncf(x: f32) -> f32; -} -// only for the thumb*-none-eabi*, riscv32*-none-elf, x86_64-unknown-none and mips*-unknown-none targets that lack the floating point instruction set -#[cfg(any( - all(target_arch = "arm", target_os = "none"), - all(target_arch = "riscv32", not(target_feature = "f"), target_os = "none"), - all(target_arch = "x86_64", target_os = "none"), - all(target_arch = "mips", target_os = "none"), -))] -no_mangle! { fn fmin(x: f64, y: f64) -> f64; fn fminf(x: f32, y: f32) -> f32; fn fmax(x: f64, y: f64) -> f64; @@ -155,3 +89,19 @@ no_mangle! { // `f32 % f32` fn fmodf(x: f32, y: f32) -> f32; } + +intrinsics! { + #[cfg_attr(all(not(windows), not(target_vendor = "apple")), weak)] + pub extern "C" fn lgamma_r(x: f64, s: &mut i32) -> f64 { + let r = self::libm::lgamma_r(x); + *s = r.1; + r.0 + } + + #[cfg_attr(all(not(windows), not(target_vendor = "apple")), weak)] + pub extern "C" fn lgammaf_r(x: f32, s: &mut i32) -> f32 { + let r = self::libm::lgammaf_r(x); + *s = r.1; + r.0 + } +} From 6cf5c13e8762354e9d1334b546286857e1cc7a75 Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Sun, 31 Mar 2024 13:53:15 +0300 Subject: [PATCH 1189/4206] Do not include math intrinsics for windows and apple targets --- library/compiler-builtins/src/math.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index b04b0b66a7573..593a1a19c46be 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -16,6 +16,7 @@ macro_rules! no_mangle { } } +#[cfg(all(not(windows), not(target_vendor = "apple")))] no_mangle! { fn acos(x: f64) -> f64; fn asin(x: f64) -> f64; From bd48df66bd6d8976fae571cabab47e8840e84387 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 10 Apr 2024 13:16:43 +0100 Subject: [PATCH 1190/4206] Release 0.1.109 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index e94c2f7625f78..267f1b950b6b0 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.108" +version = "0.1.109" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 47f2241db97ab321d74dde297e3a2d9f6fd0215b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 13 Apr 2024 04:32:49 -0400 Subject: [PATCH 1191/4206] Change aarch64_linux module and lse tests to have the same gating Trying to run testcrate on non-linux aarch64 currently hits a compilation error. Make this test linux-only, to be consistent with the `aarch64_linux` module that it depends on. Additionally, enable the `aarch64_linux` module for `target_arch = "arm64ec"` to be the same as these tests. --- library/compiler-builtins/testcrate/tests/lse.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/library/compiler-builtins/testcrate/tests/lse.rs b/library/compiler-builtins/testcrate/tests/lse.rs index 63c98957cf4f6..cbecd6143e726 100644 --- a/library/compiler-builtins/testcrate/tests/lse.rs +++ b/library/compiler-builtins/testcrate/tests/lse.rs @@ -1,8 +1,5 @@ #![feature(decl_macro)] // so we can use pub(super) -#![cfg(all( - any(target_arch = "aarch64", target_arch = "arm64ec"), - not(feature = "no-asm") -))] +#![cfg(all(target_arch = "aarch64", target_os = "linux", not(feature = "no-asm")))] /// Translate a byte size to a Rust type. macro int_ty { From d5bc2de9ec39ff0814d162fb4c06de8bc415ae48 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 16 Apr 2024 03:04:37 -0400 Subject: [PATCH 1192/4206] Add CI testing for AArch64 Darwin The Apple ARM silicon has been around for a while now and hopefully will become Rust Tier 1 at some point. Add it to CI since it is distinct enough from aarch64-linux and x86_86-darwin that there may be differences. --- library/compiler-builtins/.github/workflows/main.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 97d298cf09c19..57497e0500160 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -9,6 +9,9 @@ jobs: fail-fast: false matrix: include: + - target: aarch64-apple-darwin + os: macos-14 + rust: nightly - target: aarch64-unknown-linux-gnu os: ubuntu-latest rust: nightly @@ -81,6 +84,8 @@ jobs: os: windows-latest rust: nightly-x86_64-gnu steps: + - name: Print runner information + run: uname -a - uses: actions/checkout@v4 with: submodules: true From a55604fd8c2830de66c241b297872c55ea3ab3c2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 13 Apr 2024 00:42:36 -0400 Subject: [PATCH 1193/4206] Add a way to run tests on non-linux machines Allow using the `rust-lang/rust:nightly` docker image to run tests in cases where the host rust and cargo cannot be used, such as non-linux hosts. --- library/compiler-builtins/.gitignore | 2 + library/compiler-builtins/README.md | 20 +++++ library/compiler-builtins/build.rs | 4 +- .../aarch64-unknown-linux-gnu/Dockerfile | 3 +- .../arm-unknown-linux-gnueabi/Dockerfile | 3 +- .../arm-unknown-linux-gnueabihf/Dockerfile | 3 +- .../armv7-unknown-linux-gnueabihf/Dockerfile | 3 +- .../docker/i586-unknown-linux-gnu/Dockerfile | 3 +- .../docker/i686-unknown-linux-gnu/Dockerfile | 3 +- .../docker/mips-unknown-linux-gnu/Dockerfile | 3 +- .../mips64-unknown-linux-gnuabi64/Dockerfile | 3 +- .../Dockerfile | 3 +- .../mipsel-unknown-linux-gnu/Dockerfile | 3 +- .../powerpc-unknown-linux-gnu/Dockerfile | 3 +- .../powerpc64-unknown-linux-gnu/Dockerfile | 3 +- .../powerpc64le-unknown-linux-gnu/Dockerfile | 3 +- .../ci/docker/thumbv6m-none-eabi/Dockerfile | 3 +- .../ci/docker/thumbv7em-none-eabi/Dockerfile | 3 +- .../docker/thumbv7em-none-eabihf/Dockerfile | 3 +- .../ci/docker/thumbv7m-none-eabi/Dockerfile | 3 +- .../docker/wasm32-unknown-unknown/Dockerfile | 3 +- .../x86_64-unknown-linux-gnu/Dockerfile | 3 +- library/compiler-builtins/ci/run-docker.sh | 73 +++++++++++---- library/compiler-builtins/ci/run.sh | 88 ++++++++++++------- 24 files changed, 176 insertions(+), 68 deletions(-) diff --git a/library/compiler-builtins/.gitignore b/library/compiler-builtins/.gitignore index b203ea61f2a48..97df30ffaa85e 100644 --- a/library/compiler-builtins/.gitignore +++ b/library/compiler-builtins/.gitignore @@ -1,3 +1,5 @@ *.rs.bk Cargo.lock target +compiler-rt +*.tar.gz diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index ffef4e52c79f1..5a364a23d1a57 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -78,6 +78,26 @@ features = ["c"] [8]: http://en.cppreference.com/w/cpp/language/implicit_conversion [9]: https://doc.rust-lang.org/std/primitive.i32.html +## Testing + +The easiest way to test locally is using Docker. This can be done by running +`./ci/run-docker.sh [target]`. If no target is specified, all targets will be +run. + +In order to run the full test suite, you will also need the C compiler runtime +to test against, located in a directory called `compiler-rt`. This can be +obtained with the following: + +```sh +curl -L -o rustc-llvm-18.0.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/18.0-2024-02-13.tar.gz +tar xzf rustc-llvm-18.0.tar.gz --strip-components 1 llvm-project-rustc-18.0-2024-02-13/compiler-rt +```` + +Local targets may also be tested with `./ci/run.sh [target]`. + +Note that testing may not work on all hosts, in which cases it is acceptable to +rely on CI. + ## Progress - [x] adddf3.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 44946c1240c9e..bb2dba97ae168 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -572,7 +572,9 @@ mod c { // rust-lang/rust. let root = match env::var_os("RUST_COMPILER_RT_ROOT") { Some(s) => PathBuf::from(s), - None => panic!("RUST_COMPILER_RT_ROOT is not set"), + None => { + panic!("RUST_COMPILER_RT_ROOT is not set. You may need to download compiler-rt.") + } }; if !root.exists() { panic!("RUST_COMPILER_RT_ROOT={} does not exist", root.display()); 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 9e2559f4ab3a2..5de76efc375f0 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,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ 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 afab874bc2817..dc95da0f3c5e6 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,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ 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 3ed3602b0dc97..55e5e3d5754cb 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,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ 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 6617af1558c9a..fd2ad18d1a350 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,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ 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 5783e28e12200..f161ec76725a3 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,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc-multilib libc6-dev ca-certificates 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 5783e28e12200..f161ec76725a3 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,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc-multilib libc6-dev ca-certificates 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 f47e8f5227b49..042dd4219de7c 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,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ 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 8fa77c7bd0737..45b3089c9ed37 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,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates \ 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 c6611d9ac899c..bda6be1d67448 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,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates \ 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 0bc695624620e..702a26ec1a5f0 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,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ 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 2d39fef6142bb..6bae7cb3b65bf 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,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ 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 653cd351156e1..2c315e509e32e 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,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ 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 63ea9af9d2023..da8f9db604bbd 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,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile index dc7dd431ba382..d7256a9c53301 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile index dc7dd431ba382..d7256a9c53301 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile index dc7dd431ba382..d7256a9c53301 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile index dc7dd431ba382..d7256a9c53301 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ diff --git a/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile b/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile index 85ead29aaee62..4d12b6ff4265b 100644 --- a/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile +++ b/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:20.04 +ARG IMAGE=ubuntu:20.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc clang libc6-dev ca-certificates 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 98000f4eb81a7..d495d5044adf5 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,5 @@ -FROM ubuntu:18.04 +ARG IMAGE=ubuntu:18.04 +FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 8c4af0eff20bb..81964303935f2 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -1,38 +1,77 @@ +#!/bin/bash + # Small script to run tests for a target (or all targets) inside all the # respective docker images. -set -ex +set -eux run() { - local target=$1 + local target="$1" - echo $target + echo "TESTING TARGET: $target" # This directory needs to exist before calling docker, otherwise docker will create it but it # will be owned by root mkdir -p target - docker build -t $target ci/docker/$target + if [ $(uname -s) = "Linux" ] && [ -z "${DOCKER_BASE_IMAGE:-}" ]; then + # Share the host rustc and target. Do this only on Linux and if the image + # isn't overridden + run_args=( + --user "$(id -u):$(id -g)" + -e "CARGO_HOME=/cargo" + -v "${HOME}/.cargo:/cargo" + -v "$(pwd)/target:/builtins-target" + -v "$(rustc --print sysroot):/rust:ro" + ) + run_cmd="HOME=/tmp PATH=\$PATH:/rust/bin ci/run.sh $target" + else + # Use rustc provided by a docker image + docker volume create compiler-builtins-cache + build_args=( + "--build-arg" "IMAGE=${DOCKER_BASE_IMAGE:-rustlang/rust:nightly}" + ) + run_args=( + -v "compiler-builtins-cache:/builtins-target" + ) + run_cmd="HOME=/tmp USING_CONTAINER_RUSTC=1 ci/run.sh $target" + fi + + if [ -d compiler-rt ]; then + export RUST_COMPILER_RT_ROOT=./compiler-rt + fi + + docker build \ + -t "builtins-$target" \ + ${build_args[@]:-} \ + "ci/docker/$target" docker run \ --rm \ - --user $(id -u):$(id -g) \ - -e CARGO_HOME=/cargo \ - -e CARGO_TARGET_DIR=/target \ -e RUST_COMPILER_RT_ROOT \ - -v "${HOME}/.cargo":/cargo \ - -v `pwd`/target:/target \ - -v `pwd`:/checkout:ro \ - -v `rustc --print sysroot`:/rust:ro \ + -e "CARGO_TARGET_DIR=/builtins-target" \ + -v "$(pwd):/checkout:ro" \ -w /checkout \ + ${run_args[@]:-} \ --init \ - $target \ - sh -c "HOME=/tmp PATH=\$PATH:/rust/bin ci/run.sh $target" + "builtins-$target" \ + sh -c "$run_cmd" } -if [ -z "$1" ]; then - for d in `ls ci/docker/`; do - run $d +if [ "${1:-}" = "--help" ] || [ "$#" -gt 1 ]; then + set +x + echo "\ + usage: ./ci/run-docker.sh [target] + + you can also set DOCKER_BASE_IMAGE to use something other than the default + ubuntu:18.04 (or rustlang/rust:nightly). + " + exit +fi + +if [ -z "${1:-}" ]; then + for d in ci/docker/*; do + run $(basename "$d") done else - run $1 + run "$1" fi diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 09728191a228a..d2ea797310ed4 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -1,10 +1,25 @@ -set -ex +set -eux + +target="${1:-}" + +if [ -z "${1:-}" ]; then + host_target=$(rustc -vV | awk '/^host/ { print $2 }') + echo "Defaulted to host target $host_target" + target="$host_target" +fi + +if [ "${USING_CONTAINER_RUSTC:-}" = 1 ]; then + # Install nonstandard components if we have control of the environment + rustup target list --installed | + grep -E "^$target\$" || + rustup target add "$target" +fi # Test our implementation -if [ "$NO_STD" = "1" ]; then - echo nothing to do +if [ "${NO_STD:-}" = "1" ]; then + echo "nothing to do for no_std" else - run="cargo test --manifest-path testcrate/Cargo.toml --target $1" + run="cargo test --manifest-path testcrate/Cargo.toml --target $target" $run $run --release $run --features c @@ -13,24 +28,24 @@ else $run --features no-asm --release fi -if [ -d /target ]; then - path=/target/${1}/debug/deps/libcompiler_builtins-*.rlib +if [ -d /builtins-target ]; then + path=/builtins-target/${target}/debug/deps/libcompiler_builtins-*.rlib else - path=target/${1}/debug/deps/libcompiler_builtins-*.rlib + path=target/${target}/debug/deps/libcompiler_builtins-*.rlib fi # Remove any existing artifacts from previous tests that don't set #![compiler_builtins] rm -f $path -cargo build --target $1 -cargo build --target $1 --release -cargo build --target $1 --features c -cargo build --target $1 --release --features c -cargo build --target $1 --features no-asm -cargo build --target $1 --release --features no-asm +cargo build --target "$target" +cargo build --target "$target" --release +cargo build --target "$target" --features c +cargo build --target "$target" --release --features c +cargo build --target "$target" --features no-asm +cargo build --target "$target" --release --features no-asm -PREFIX=$(echo $1 | sed -e 's/unknown-//')- -case $1 in +PREFIX=$(echo "$target" | sed -e 's/unknown-//')- +case "$target" in armv7-*) PREFIX=arm-linux-gnueabihf- ;; @@ -44,12 +59,12 @@ esac NM=$(find $(rustc --print sysroot) \( -name llvm-nm -o -name llvm-nm.exe \) ) if [ "$NM" = "" ]; then - NM=${PREFIX}nm + NM="${PREFIX}nm" fi # i686-pc-windows-gnu tools have a dependency on some DLLs, so run it with # rustup run to ensure that those are in PATH. -TOOLCHAIN=$(rustup show active-toolchain | sed 's/ (default)//') -if [[ $TOOLCHAIN == *i686-pc-windows-gnu ]]; then +TOOLCHAIN="$(rustup show active-toolchain | sed 's/ (default)//')" +if [[ "$TOOLCHAIN" == *i686-pc-windows-gnu ]]; then NM="rustup run $TOOLCHAIN $NM" fi @@ -57,7 +72,7 @@ fi for rlib in $(echo $path); do set +x echo "================================================================" - echo checking $rlib for duplicate symbols + echo "checking $rlib for duplicate symbols" echo "================================================================" stdout=$($NM -g --defined-only $rlib 2>&1) @@ -80,7 +95,7 @@ done rm -f $path # Verify that we haven't drop any intrinsic/symbol -build_intrinsics="cargo build --target $1 -v --example intrinsics" +build_intrinsics="cargo build --target "$target" -v --example intrinsics" $build_intrinsics $build_intrinsics --release $build_intrinsics --features c @@ -89,25 +104,36 @@ $build_intrinsics --features c --release # Verify that there are no undefined symbols to `panic` within our # implementations CARGO_PROFILE_DEV_LTO=true \ - cargo build --target $1 --example intrinsics + cargo build --target "$target" --example intrinsics CARGO_PROFILE_RELEASE_LTO=true \ - cargo build --target $1 --example intrinsics --release + cargo build --target "$target" --example intrinsics --release # Ensure no references to any symbols from core for rlib in $(echo $path); do - set +ex + set +x echo "================================================================" - echo checking $rlib for references to core + echo "checking $rlib for references to core" echo "================================================================" - - $NM --quiet -U $rlib | grep 'T _ZN4core' | awk '{print $3}' | sort | uniq > defined_symbols.txt - $NM --quiet -u $rlib | grep 'U _ZN4core' | awk '{print $2}' | sort | uniq > undefined_symbols.txt - grep -v -F -x -f defined_symbols.txt undefined_symbols.txt - - if test $? = 0; then + set -x + + tmpdir="${CARGO_TARGET_DIR:-target}/tmp" + test -d "$tmpdir" || mkdir "$tmpdir" + defined="$tmpdir/defined_symbols.txt" + undefined="$tmpdir/defined_symbols.txt" + + $NM --quiet -U $rlib | grep 'T _ZN4core' | awk '{print $3}' | sort | uniq > "$defined" + $NM --quiet -u $rlib | grep 'U _ZN4core' | awk '{print $2}' | sort | uniq > "$undefined" + grep_failed=0 + grep -v -F -x -f "$defined" "$undefined" && grep_failed=1 + + if [ "$target" = "powerpc64-unknown-linux-gnu" ]; then + echo "FIXME: powerpc64 fails these tests" + elif [ "$grep_failed" != 0 ]; then + echo "error: found unexpected references to core" exit 1 + else + echo "success; no references to core found" fi - set -ex done true From 1b679e5cee1ae035b531c4101f09b73b94ce209f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 15 Apr 2024 14:44:39 -0400 Subject: [PATCH 1194/4206] Apply some more fixes suggested by Shellcheck --- library/compiler-builtins/ci/run-docker.sh | 2 +- library/compiler-builtins/ci/run.sh | 64 ++++++++++++---------- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 81964303935f2..b85f64133a71b 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -3,7 +3,7 @@ # Small script to run tests for a target (or all targets) inside all the # respective docker images. -set -eux +set -euxo pipefail run() { local target="$1" diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index d2ea797310ed4..65fffec5fddf6 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -1,3 +1,5 @@ +#!/bin/bash + set -eux target="${1:-}" @@ -29,13 +31,13 @@ else fi if [ -d /builtins-target ]; then - path=/builtins-target/${target}/debug/deps/libcompiler_builtins-*.rlib + rlib_paths=/builtins-target/"${target}"/debug/deps/libcompiler_builtins-*.rlib else - path=target/${target}/debug/deps/libcompiler_builtins-*.rlib + rlib_paths=target/"${target}"/debug/deps/libcompiler_builtins-*.rlib fi # Remove any existing artifacts from previous tests that don't set #![compiler_builtins] -rm -f $path +rm -f $rlib_paths cargo build --target "$target" cargo build --target "$target" --release @@ -44,7 +46,7 @@ cargo build --target "$target" --release --features c cargo build --target "$target" --features no-asm cargo build --target "$target" --release --features no-asm -PREFIX=$(echo "$target" | sed -e 's/unknown-//')- +PREFIX=${target//unknown-/}- case "$target" in armv7-*) PREFIX=arm-linux-gnueabihf- @@ -57,7 +59,7 @@ case "$target" in ;; esac -NM=$(find $(rustc --print sysroot) \( -name llvm-nm -o -name llvm-nm.exe \) ) +NM=$(find "$(rustc --print sysroot)" \( -name llvm-nm -o -name llvm-nm.exe \) ) if [ "$NM" = "" ]; then NM="${PREFIX}nm" fi @@ -69,37 +71,41 @@ if [[ "$TOOLCHAIN" == *i686-pc-windows-gnu ]]; then fi # Look out for duplicated symbols when we include the compiler-rt (C) implementation -for rlib in $(echo $path); do +for rlib in $rlib_paths; do set +x echo "================================================================" echo "checking $rlib for duplicate symbols" echo "================================================================" + + duplicates_found=0 - stdout=$($NM -g --defined-only $rlib 2>&1) # NOTE On i586, It's normal that the get_pc_thunk symbol appears several # times so ignore it - set +e - echo "$stdout" | \ - sort | \ - uniq -d | \ - grep -v __x86.get_pc_thunk | \ - grep 'T __' - - if test $? = 0; then + $NM -g --defined-only "$rlib" 2>&1 | + sort | + uniq -d | + grep -v __x86.get_pc_thunk --quiet | + grep 'T __' && duplicates_found=1 + + if [ "$duplicates_found" != 0 ]; then + echo "error: found duplicate symbols" exit 1 + else + echo "success; no duplicate symbols found" fi - - set -ex done -rm -f $path +rm -f $rlib_paths + +build_intrinsics() { + cargo build --target "$target" -v --example intrinsics "$@" +} # Verify that we haven't drop any intrinsic/symbol -build_intrinsics="cargo build --target "$target" -v --example intrinsics" -$build_intrinsics -$build_intrinsics --release -$build_intrinsics --features c -$build_intrinsics --features c --release +build_intrinsics +build_intrinsics --release +build_intrinsics --features c +build_intrinsics --features c --release # Verify that there are no undefined symbols to `panic` within our # implementations @@ -109,7 +115,7 @@ CARGO_PROFILE_RELEASE_LTO=true \ cargo build --target "$target" --example intrinsics --release # Ensure no references to any symbols from core -for rlib in $(echo $path); do +for rlib in $(echo $rlib_paths); do set +x echo "================================================================" echo "checking $rlib for references to core" @@ -121,14 +127,14 @@ for rlib in $(echo $path); do defined="$tmpdir/defined_symbols.txt" undefined="$tmpdir/defined_symbols.txt" - $NM --quiet -U $rlib | grep 'T _ZN4core' | awk '{print $3}' | sort | uniq > "$defined" - $NM --quiet -u $rlib | grep 'U _ZN4core' | awk '{print $2}' | sort | uniq > "$undefined" - grep_failed=0 - grep -v -F -x -f "$defined" "$undefined" && grep_failed=1 + $NM --quiet -U "$rlib" | grep 'T _ZN4core' | awk '{print $3}' | sort | uniq > "$defined" + $NM --quiet -u "$rlib" | grep 'U _ZN4core' | awk '{print $2}' | sort | uniq > "$undefined" + grep_has_results=0 + grep -v -F -x -f "$defined" "$undefined" && grep_has_results=1 if [ "$target" = "powerpc64-unknown-linux-gnu" ]; then echo "FIXME: powerpc64 fails these tests" - elif [ "$grep_failed" != 0 ]; then + elif [ "$grep_has_results" != 0 ]; then echo "error: found unexpected references to core" exit 1 else From a2587f7b028b28f65879512e61a6b67acaad2384 Mon Sep 17 00:00:00 2001 From: beetrees Date: Sun, 28 Apr 2024 17:41:35 +0100 Subject: [PATCH 1195/4206] Update status of 128-bit integers in README.md --- library/compiler-builtins/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 5a364a23d1a57..0c97690ca82b2 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -212,7 +212,7 @@ rely on CI. - [x] umodsi3.c - [x] x86_64/chkstk.S -These builtins are needed to support 128-bit integers, which are in the process of being added to Rust. +These builtins are needed to support 128-bit integers. - [x] ashlti3.c - [x] ashrti3.c From 1b15dd5eb2a8a8acfbae2f08bf92a8aed3471395 Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Tue, 30 Apr 2024 12:14:55 +0800 Subject: [PATCH 1196/4206] Fix `clippy::deprecated_cfg_attr` on compiler_builtins --- library/compiler-builtins/libm/src/math/exp2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs index e0e385df2e702..dce2ab4df6ff6 100644 --- a/library/compiler-builtins/libm/src/math/exp2.rs +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -28,7 +28,7 @@ use super::scalbn; const TBLSIZE: usize = 256; -#[cfg_attr(rustfmt, rustfmt_skip)] +#[rustfmt::skip] static TBL: [u64; TBLSIZE * 2] = [ // exp2(z + eps) eps 0x3fe6a09e667f3d5d, 0x3d39880000000000, From 2ce9bc0cc107d2f7c07962ce55cf5ba6ccf58c18 Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Mon, 15 Apr 2024 19:14:41 +0800 Subject: [PATCH 1197/4206] Fix math libraries not being linked on some platforms This is a continuation/fix of 018616e. In that commit, we made it add the math functions to all platforms (except apple-targets and windows), and use `weak` linking, so that it can be used if the system doesn't have those functions. Didn't notice `mod math` was behind another set of `cfg`, so removed it as well here. --- library/compiler-builtins/src/lib.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index a414efde0ce91..da438de7778d1 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -45,14 +45,6 @@ mod macros; pub mod float; pub mod int; -#[cfg(any( - all(target_family = "wasm", target_os = "unknown"), - target_os = "uefi", - target_os = "none", - target_os = "xous", - all(target_vendor = "fortanix", target_env = "sgx"), - target_os = "windows" -))] pub mod math; pub mod mem; From f761f0382295a13c42bc5f96f9a0e1af6f4b5cd9 Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Mon, 15 Apr 2024 19:37:48 +0800 Subject: [PATCH 1198/4206] Fix clippy warnings in `math` The solution is not pretty, but not sure why we still get clippy warning from one of the files in `libm` even though we use `allow(clippy::all)` --- library/compiler-builtins/src/lib.rs | 3 +++ library/compiler-builtins/src/math.rs | 2 ++ 2 files changed, 5 insertions(+) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index da438de7778d1..e7975098c9fb1 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -45,6 +45,9 @@ mod macros; pub mod float; pub mod int; +// For some reason, we still get clippy error `clippy::deprecated_cfg_attr` even though, we have +// used `allow(clippy::all)` in the file. So, we are disabling the clippy check for this file. +#[cfg(not(clippy))] pub mod math; pub mod mem; diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 593a1a19c46be..e47b834e44656 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -1,4 +1,6 @@ #[allow(dead_code)] +#[allow(unused_imports)] +#[allow(clippy::all)] #[path = "../libm/src/math/mod.rs"] mod libm; From 656106f0506960732b8d3d9caf9259e37c6c8c4f Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Tue, 30 Apr 2024 18:40:45 +0800 Subject: [PATCH 1199/4206] Updated `libm` to fix `clippy` warning --- library/compiler-builtins/libm | 2 +- library/compiler-builtins/src/lib.rs | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 721a5edc1be6b..a1e8a5bf95e99 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 721a5edc1be6b0412e4b1704590aed76f9a55899 +Subproject commit a1e8a5bf95e99309760b764b2a332d0039d08350 diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index e7975098c9fb1..da438de7778d1 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -45,9 +45,6 @@ mod macros; pub mod float; pub mod int; -// For some reason, we still get clippy error `clippy::deprecated_cfg_attr` even though, we have -// used `allow(clippy::all)` in the file. So, we are disabling the clippy check for this file. -#[cfg(not(clippy))] pub mod math; pub mod mem; From 229babb1d078ecd44def70abdd50ee5bf7a35945 Mon Sep 17 00:00:00 2001 From: beetrees Date: Sun, 14 Apr 2024 08:05:18 +0100 Subject: [PATCH 1200/4206] Add builtins for `f16`/`f128` float conversions --- library/compiler-builtins/Cargo.toml | 4 + library/compiler-builtins/README.md | 61 +++++---- library/compiler-builtins/build.rs | 21 ++- library/compiler-builtins/ci/run.sh | 4 + library/compiler-builtins/src/float/extend.rs | 34 +++++ library/compiler-builtins/src/float/mod.rs | 19 ++- library/compiler-builtins/src/float/trunc.rs | 55 +++++++- library/compiler-builtins/src/lib.rs | 2 + .../compiler-builtins/testcrate/Cargo.toml | 5 +- .../compiler-builtins/testcrate/tests/conv.rs | 125 ++++++++++++++++++ .../compiler-builtins/testcrate/tests/misc.rs | 68 ---------- 11 files changed, 283 insertions(+), 115 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 267f1b950b6b0..96e85d7b5fbd0 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -49,6 +49,10 @@ c = ["cc"] # which use inline assembly and fall back to pure Rust versions (if avalible). no-asm = [] +# Workaround for codegen backends which haven't yet implemented `f16` and +# `f128` support. Disabled any intrinsics which use those types. +no-f16-f128 = [] + # Flag this library as the unstable compiler-builtins lib compiler-builtins = [] diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 0c97690ca82b2..00d547f1bdb20 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -162,7 +162,6 @@ rely on CI. - [x] divmodsi4.c - [x] divsf3.c - [x] divsi3.c -- [ ] extendhfsf2.c - [x] extendsfdf2.c - [x] fixdfdi.c - [x] fixdfsi.c @@ -201,9 +200,7 @@ rely on CI. - [x] powisf2.c - [x] subdf3.c - [x] subsf3.c -- [ ] truncdfhf2.c - [x] truncdfsf2.c -- [ ] truncsfhf2.c - [x] udivdi3.c - [x] udivmoddi4.c - [x] udivmodsi4.c @@ -233,60 +230,68 @@ These builtins are needed to support 128-bit integers. - [x] udivti3.c - [x] umodti3.c +These builtins are needed to support `f16` and `f128`, which are in the process of being added to Rust. + +- [ ] addtf3.c +- [ ] comparetf2.c +- [ ] divtf3.c +- [x] extenddftf2.c +- [x] extendhfsf2.c +- [x] extendhftf2.c +- [x] extendsftf2.c +- [ ] fixtfdi.c +- [ ] fixtfsi.c +- [ ] fixtfti.c +- [ ] fixunstfdi.c +- [ ] fixunstfsi.c +- [ ] fixunstfti.c +- [ ] floatditf.c +- [ ] floatsitf.c +- [ ] floatunditf.c +- [ ] floatunsitf.c +- [ ] multf3.c +- [ ] powitf2.c +- [ ] ppc/fixtfdi.c +- [ ] ppc/fixunstfdi.c +- [ ] ppc/floatditf.c +- [ ] ppc/floatunditf.c +- [ ] subtf3.c +- [x] truncdfhf2.c +- [x] truncsfhf2.c +- [x] trunctfdf2.c +- [x] trunctfhf2.c +- [x] trunctfsf2.c + ## Unimplemented functions -These builtins involve floating-point types ("`f128`", "`f80`" and complex numbers) that are not supported by Rust. +These builtins involve floating-point types ("`f80`" and complex numbers) that are not supported by Rust. -- ~~addtf3.c~~ -- ~~comparetf2.c~~ - ~~divdc3.c~~ - ~~divsc3.c~~ - ~~divtc3.c~~ -- ~~divtf3.c~~ - ~~divxc3.c~~ -- ~~extenddftf2.c~~ -- ~~extendsftf2.c~~ -- ~~fixtfdi.c~~ -- ~~fixtfsi.c~~ -- ~~fixtfti.c~~ -- ~~fixunstfdi.c~~ -- ~~fixunstfsi.c~~ -- ~~fixunstfti.c~~ - ~~fixunsxfdi.c~~ - ~~fixunsxfsi.c~~ - ~~fixunsxfti.c~~ - ~~fixxfdi.c~~ - ~~fixxfti.c~~ -- ~~floatditf.c~~ - ~~floatdixf.c~~ -- ~~floatsitf.c~~ - ~~floattixf.c~~ -- ~~floatunditf.c~~ - ~~floatundixf.c~~ -- ~~floatunsitf.c~~ - ~~floatuntixf.c~~ - ~~i386/floatdixf.S~~ - ~~i386/floatundixf.S~~ - ~~muldc3.c~~ - ~~mulsc3.c~~ - ~~multc3.c~~ -- ~~multf3.c~~ - ~~mulxc3.c~~ -- ~~powitf2.c~~ - ~~powixf2.c~~ - ~~ppc/divtc3.c~~ -- ~~ppc/fixtfdi.c~~ -- ~~ppc/fixunstfdi.c~~ -- ~~ppc/floatditf.c~~ -- ~~ppc/floatunditf.c~~ - ~~ppc/gcc_qadd.c~~ - ~~ppc/gcc_qdiv.c~~ - ~~ppc/gcc_qmul.c~~ - ~~ppc/gcc_qsub.c~~ - ~~ppc/multc3.c~~ -- ~~subtf3.c~~ -- ~~trunctfdf2.c~~ -- ~~trunctfsf2.c~~ - ~~x86_64/floatdixf.c~~ - ~~x86_64/floatundixf.S~~ diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index bb2dba97ae168..bafbf75d06814 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -217,6 +217,14 @@ mod c { } } + // `compiler-rt` requires `COMPILER_RT_HAS_FLOAT16` to be defined to make it use the + // `_Float16` type for `f16` intrinsics. This shouldn't matter as all existing `f16` + // intrinsics have been ported to Rust in `compiler-builtins` as C compilers don't + // 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); + cfg.warnings(false); if target_env == "msvc" { @@ -288,13 +296,10 @@ mod c { sources.extend(&[ ("__divdc3", "divdc3.c"), ("__divsc3", "divsc3.c"), - ("__extendhfsf2", "extendhfsf2.c"), ("__muldc3", "muldc3.c"), ("__mulsc3", "mulsc3.c"), ("__negdf2", "negdf2.c"), ("__negsf2", "negsf2.c"), - ("__truncdfhf2", "truncdfhf2.c"), - ("__truncsfhf2", "truncsfhf2.c"), ]); } @@ -464,8 +469,6 @@ mod c { if (target_arch == "aarch64" || target_arch == "arm64ec") && consider_float_intrinsics { sources.extend(&[ ("__comparetf2", "comparetf2.c"), - ("__extenddftf2", "extenddftf2.c"), - ("__extendsftf2", "extendsftf2.c"), ("__fixtfdi", "fixtfdi.c"), ("__fixtfsi", "fixtfsi.c"), ("__fixtfti", "fixtfti.c"), @@ -476,8 +479,6 @@ mod c { ("__floatsitf", "floatsitf.c"), ("__floatunditf", "floatunditf.c"), ("__floatunsitf", "floatunsitf.c"), - ("__trunctfdf2", "trunctfdf2.c"), - ("__trunctfsf2", "trunctfsf2.c"), ("__addtf3", "addtf3.c"), ("__multf3", "multf3.c"), ("__subtf3", "subtf3.c"), @@ -498,7 +499,6 @@ mod c { if target_arch == "mips64" { sources.extend(&[ - ("__extenddftf2", "extenddftf2.c"), ("__netf2", "comparetf2.c"), ("__addtf3", "addtf3.c"), ("__multf3", "multf3.c"), @@ -509,14 +509,11 @@ mod c { ("__floatunsitf", "floatunsitf.c"), ("__fe_getround", "fp_mode.c"), ("__divtf3", "divtf3.c"), - ("__trunctfdf2", "trunctfdf2.c"), - ("__trunctfsf2", "trunctfsf2.c"), ]); } if target_arch == "loongarch64" { sources.extend(&[ - ("__extenddftf2", "extenddftf2.c"), ("__netf2", "comparetf2.c"), ("__addtf3", "addtf3.c"), ("__multf3", "multf3.c"), @@ -527,8 +524,6 @@ mod c { ("__floatunsitf", "floatunsitf.c"), ("__fe_getround", "fp_mode.c"), ("__divtf3", "divtf3.c"), - ("__trunctfdf2", "trunctfdf2.c"), - ("__trunctfsf2", "trunctfsf2.c"), ]); } diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 65fffec5fddf6..1298093a65807 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -28,6 +28,8 @@ else $run --features c --release $run --features no-asm $run --features no-asm --release + $run --features no-f16-f128 + $run --features no-f16-f128 --release fi if [ -d /builtins-target ]; then @@ -45,6 +47,8 @@ cargo build --target "$target" --features c cargo build --target "$target" --release --features c cargo build --target "$target" --features no-asm cargo build --target "$target" --release --features no-asm +cargo build --target "$target" --features no-f16-f128 +cargo build --target "$target" --release --features no-f16-f128 PREFIX=${target//unknown-/}- case "$target" in diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index 0e6673b9c095d..7c2446603f2cf 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -82,3 +82,37 @@ intrinsics! { a as f64 // LLVM generate 'fcvtds' } } + +#[cfg(not(feature = "no-f16-f128"))] +intrinsics! { + #[avr_skip] + #[aapcs_on_arm] + #[arm_aeabi_alias = __aeabi_h2f] + pub extern "C" fn __extendhfsf2(a: f16) -> f32 { + extend(a) + } + + #[avr_skip] + #[aapcs_on_arm] + pub extern "C" fn __gnu_h2f_ieee(a: f16) -> f32 { + extend(a) + } + + #[avr_skip] + #[aapcs_on_arm] + pub extern "C" fn __extendhftf2(a: f16) -> f128 { + extend(a) + } + + #[avr_skip] + #[aapcs_on_arm] + pub extern "C" fn __extendsftf2(a: f32) -> f128 { + extend(a) + } + + #[avr_skip] + #[aapcs_on_arm] + pub extern "C" fn __extenddftf2(a: f64) -> f128 { + extend(a) + } +} diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index fdbe9dde35b19..a82dd7d2a3b08 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -127,7 +127,20 @@ macro_rules! float_impl { self.to_bits() as Self::SignedInt } fn eq_repr(self, rhs: Self) -> bool { - if self.is_nan() && rhs.is_nan() { + #[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.repr() & $ty::EXPONENT_MASK == $ty::EXPONENT_MASK + && x.repr() & $ty::SIGNIFICAND_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.repr() == rhs.repr() @@ -171,5 +184,9 @@ macro_rules! float_impl { }; } +#[cfg(not(feature = "no-f16-f128"))] +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(not(feature = "no-f16-f128"))] +float_impl!(f128, u128, i128, i16, 128, 112); diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index 0beeb9f98de1f..6de446c100685 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -52,8 +52,10 @@ where // destination format. We can convert by simply right-shifting with // rounding and adjusting the exponent. abs_result = (a_abs >> sign_bits_delta).cast(); - let tmp = src_exp_bias.wrapping_sub(dst_exp_bias) << R::SIGNIFICAND_BITS; - abs_result = abs_result.wrapping_sub(tmp.cast()); + // Cast before shifting to prevent overflow. + let bias_diff: R::Int = src_exp_bias.wrapping_sub(dst_exp_bias).cast(); + let tmp = bias_diff << R::SIGNIFICAND_BITS; + abs_result = abs_result.wrapping_sub(tmp); let round_bits = a_abs & round_mask; if round_bits > halfway { @@ -67,13 +69,17 @@ where // a is NaN. // Conjure the result by beginning with infinity, setting the qNaN // bit and inserting the (truncated) trailing NaN field. - abs_result = (dst_inf_exp << R::SIGNIFICAND_BITS).cast(); + // Cast before shifting to prevent overflow. + let dst_inf_exp: R::Int = dst_inf_exp.cast(); + abs_result = dst_inf_exp << R::SIGNIFICAND_BITS; abs_result |= dst_qnan; abs_result |= dst_nan_code & ((a_abs & src_nan_code) >> (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS)).cast(); } else if a_abs >= overflow { // a overflows to infinity. - abs_result = (dst_inf_exp << R::SIGNIFICAND_BITS).cast(); + // Cast before shifting to prevent overflow. + let dst_inf_exp: R::Int = dst_inf_exp.cast(); + abs_result = dst_inf_exp << R::SIGNIFICAND_BITS; } else { // a underflows on conversion to the destination type or is an exact // zero. The result may be a denormal or zero. Extract the exponent @@ -124,3 +130,44 @@ intrinsics! { a as f32 } } + +#[cfg(not(feature = "no-f16-f128"))] +intrinsics! { + #[avr_skip] + #[aapcs_on_arm] + #[arm_aeabi_alias = __aeabi_f2h] + pub extern "C" fn __truncsfhf2(a: f32) -> f16 { + trunc(a) + } + + #[avr_skip] + #[aapcs_on_arm] + pub extern "C" fn __gnu_f2h_ieee(a: f32) -> f16 { + trunc(a) + } + + #[avr_skip] + #[aapcs_on_arm] + #[arm_aeabi_alias = __aeabi_d2h] + pub extern "C" fn __truncdfhf2(a: f64) -> f16 { + trunc(a) + } + + #[avr_skip] + #[aapcs_on_arm] + pub extern "C" fn __trunctfhf2(a: f128) -> f16 { + trunc(a) + } + + #[avr_skip] + #[aapcs_on_arm] + pub extern "C" fn __trunctfsf2(a: f128) -> f32 { + trunc(a) + } + + #[avr_skip] + #[aapcs_on_arm] + pub extern "C" fn __trunctfdf2(a: f128) -> f64 { + trunc(a) + } +} diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index da438de7778d1..40564178a2498 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -13,6 +13,8 @@ #![feature(naked_functions)] #![feature(repr_simd)] #![feature(c_unwind)] +#![cfg_attr(not(feature = "no-f16-f128"), feature(f16))] +#![cfg_attr(not(feature = "no-f16-f128"), feature(f128))] #![no_builtins] #![no_std] #![allow(unused_features)] diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 762d3293b2b67..6ff3fde1705c2 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -2,7 +2,7 @@ name = "testcrate" version = "0.1.0" authors = ["Alex Crichton "] -edition = "2018" +edition = "2021" [lib] test = false @@ -13,6 +13,8 @@ doctest = false # problems with system RNGs on the variety of platforms this crate is tested on. # `xoshiro128**` is used for its quality, size, and speed at generating `u32` shift amounts. rand_xoshiro = "0.6" +# To compare float builtins against +rustc_apfloat = "0.2.0" [dependencies.compiler_builtins] path = ".." @@ -28,5 +30,6 @@ utest-macros = { git = "https://github.com/japaric/utest" } default = ["mangled-names"] c = ["compiler_builtins/c"] no-asm = ["compiler_builtins/no-asm"] +no-f16-f128 = ["compiler_builtins/no-f16-f128"] mem = ["compiler_builtins/mem"] mangled-names = ["compiler_builtins/mangled-names"] diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 2a70db17890b7..84828dbfa6c77 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -1,3 +1,13 @@ +#![cfg_attr(not(feature = "no-f16-f128"), feature(f16))] +#![cfg_attr(not(feature = "no-f16-f128"), feature(f128))] +// makes configuration easier +#![allow(unused_macros)] + +use compiler_builtins::float::Float; +use rustc_apfloat::ieee::{Double, Single}; +#[cfg(not(feature = "no-f16-f128"))] +use rustc_apfloat::ieee::{Half, Quad}; +use rustc_apfloat::{Float as _, FloatConvert as _}; use testcrate::*; macro_rules! i_to_f { @@ -130,3 +140,118 @@ fn float_to_int() { ); }); } + +macro_rules! conv { + ($fX:ident, $fD:ident, $fn:ident, $apfloatX:ident, $apfloatD:ident) => { + fuzz_float(N, |x: $fX| { + let tmp0: $apfloatD = $apfloatX::from_bits(x.to_bits().into()) + .convert(&mut false) + .value; + let tmp0 = $fD::from_bits(tmp0.to_bits().try_into().unwrap()); + let tmp1: $fD = $fn(x); + if !Float::eq_repr(tmp0, tmp1) { + panic!( + "{}({x:?}): apfloat: {tmp0:?}, builtins: {tmp1:?}", + stringify!($fn) + ); + } + }); + }; +} + +macro_rules! extend { + ($fX:ident, $fD:ident, $fn:ident) => { + fuzz_float(N, |x: $fX| { + let tmp0 = x as $fD; + let tmp1: $fD = $fn(x); + if !Float::eq_repr(tmp0, tmp1) { + panic!( + "{}({}): std: {}, builtins: {}", + stringify!($fn), + x, + tmp0, + tmp1 + ); + } + }); + }; +} + +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +#[test] +fn float_extend() { + use compiler_builtins::float::extend::__extendsfdf2; + + extend!(f32, f64, __extendsfdf2); + conv!(f32, f64, __extendsfdf2, Single, Double); + #[cfg(not(feature = "no-f16-f128"))] + { + use compiler_builtins::float::extend::{ + __extenddftf2, __extendhfsf2, __extendhftf2, __extendsftf2, __gnu_h2f_ieee, + }; + // FIXME(f16_f128): Also do extend!() for `f16` and `f128` when builtins are in nightly + conv!(f16, f32, __extendhfsf2, Half, Single); + conv!(f16, f32, __gnu_h2f_ieee, Half, Single); + conv!(f16, f128, __extendhftf2, Half, Quad); + conv!(f32, f128, __extendsftf2, Single, Quad); + conv!(f64, f128, __extenddftf2, Double, Quad); + } +} + +#[cfg(target_arch = "arm")] +#[test] +fn float_extend_arm() { + use compiler_builtins::float::extend::__extendsfdf2vfp; + + extend!(f32, f64, __extendsfdf2vfp); + conv!(f32, f64, __extendsfdf2vfp, Single, Double); +} + +macro_rules! trunc { + ($fX:ident, $fD:ident, $fn:ident) => { + fuzz_float(N, |x: $fX| { + let tmp0 = x as $fD; + let tmp1: $fD = $fn(x); + if !Float::eq_repr(tmp0, tmp1) { + panic!( + "{}({}): std: {}, builtins: {}", + stringify!($fn), + x, + tmp0, + tmp1 + ); + } + }); + }; +} + +#[test] +fn float_trunc() { + use compiler_builtins::float::trunc::__truncdfsf2; + + trunc!(f64, f32, __truncdfsf2); + conv!(f64, f32, __truncdfsf2, Double, Single); + #[cfg(not(feature = "no-f16-f128"))] + { + use compiler_builtins::float::trunc::{ + __gnu_f2h_ieee, __truncdfhf2, __truncsfhf2, __trunctfdf2, __trunctfhf2, __trunctfsf2, + }; + // FIXME(f16_f128): Also do trunc!() for `f16` and `f128` when builtins are in nightly + conv!(f32, f16, __truncsfhf2, Single, Half); + conv!(f32, f16, __gnu_f2h_ieee, Single, Half); + conv!(f64, f16, __truncdfhf2, Double, Half); + conv!(f128, f16, __trunctfhf2, Quad, Half); + conv!(f128, f32, __trunctfsf2, Quad, Single); + conv!(f128, f64, __trunctfdf2, Quad, Double); + } +} + +#[cfg(target_arch = "arm")] +#[test] +fn float_trunc_arm() { + use compiler_builtins::float::trunc::__truncdfsf2vfp; + + trunc!(f64, f32, __truncdfsf2vfp); + conv!(f64, f32, __truncdfsf2vfp, Double, Single) +} diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index 537ba1e60c722..402d202a82b27 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -93,41 +93,6 @@ fn leading_zeros() { }) } -macro_rules! extend { - ($fX:ident, $fD:ident, $fn:ident) => { - fuzz_float(N, |x: $fX| { - let tmp0 = x as $fD; - let tmp1: $fD = $fn(x); - if !Float::eq_repr(tmp0, tmp1) { - panic!( - "{}({}): std: {}, builtins: {}", - stringify!($fn), - x, - tmp0, - tmp1 - ); - } - }); - }; -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[test] -fn float_extend() { - use compiler_builtins::float::extend::__extendsfdf2; - - extend!(f32, f64, __extendsfdf2); -} - -#[cfg(target_arch = "arm")] -#[test] -fn float_extend_arm() { - use compiler_builtins::float::extend::__extendsfdf2vfp; - - extend!(f32, f64, __extendsfdf2vfp); -} - // This is approximate because of issues related to // https://github.com/rust-lang/rust/issues/73920. // TODO how do we resolve this indeterminacy? @@ -179,36 +144,3 @@ fn float_pow() { f64, 1e-12, __powidf2; ); } - -macro_rules! trunc { - ($fX:ident, $fD:ident, $fn:ident) => { - fuzz_float(N, |x: $fX| { - let tmp0 = x as $fD; - let tmp1: $fD = $fn(x); - if !Float::eq_repr(tmp0, tmp1) { - panic!( - "{}({}): std: {}, builtins: {}", - stringify!($fn), - x, - tmp0, - tmp1 - ); - } - }); - }; -} - -#[test] -fn float_trunc() { - use compiler_builtins::float::trunc::__truncdfsf2; - - trunc!(f64, f32, __truncdfsf2); -} - -#[cfg(target_arch = "arm")] -#[test] -fn float_trunc_arm() { - use compiler_builtins::float::trunc::__truncdfsf2vfp; - - trunc!(f64, f32, __truncdfsf2vfp); -} From 2e096145c3bfb175d4fea9e3a518f67aa4851875 Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Mon, 29 Apr 2024 22:05:30 +0800 Subject: [PATCH 1201/4206] Apply `weak` attributes to all intrinsics Removed the `weak-intrinsics` feature, so that all functions will have the `weak` linkage attribute. Also this fixed the bug in https://github.com/rust-lang/rust/issues/124042. Before this commit, generated code will be ```rust pub extern "C" fn (...) -> ... { // code... } pub mod { #[linkage = "weak"] #[no_mangle] pub extern "C" fn (...) -> ... { super::(...) } } ``` The issue is that there is 2 `weak` linkage, the first one is not required. Along refactoring `weak` attributes, this was fixed. --- library/compiler-builtins/Cargo.toml | 11 --- library/compiler-builtins/src/arm.rs | 18 ----- library/compiler-builtins/src/macros.rs | 93 ++++-------------------- library/compiler-builtins/src/math.rs | 3 - library/compiler-builtins/src/mem/mod.rs | 6 -- 5 files changed, 14 insertions(+), 117 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 96e85d7b5fbd0..c8f164c94d28e 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -70,17 +70,6 @@ rustc-dep-of-std = ['compiler-builtins', 'core'] # are not normally public but are required by the `testcrate` public-test-deps = [] -# Marks all intrinsics functions with weak linkage so that they can be -# replaced at link time by another implementation. This is particularly useful -# for mixed Rust/C++ binaries that want to use the C++ intrinsics, otherwise -# linking against the Rust stdlib will replace those from the compiler-rt -# library. -# -# Unlike the "c" feature, the intrinsics are still provided by the Rust -# implementations and each will be used unless a stronger symbol replaces -# it during linking. -weak-intrinsics = [] - [[example]] name = "intrinsics" required-features = ["compiler-builtins"] diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index cc67642e16bc3..dcae22b73fb7f 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -20,7 +20,6 @@ macro_rules! bl { intrinsics! { // NOTE This function and the ones below are implemented using assembly because they are using a // custom calling convention which can't be implemented using a normal Rust function. - #[cfg_attr(all(not(windows), not(target_vendor="apple")), weak)] #[naked] #[cfg(not(target_env = "msvc"))] pub unsafe extern "C" fn __aeabi_uidivmod() { @@ -36,7 +35,6 @@ intrinsics! { ); } - #[cfg_attr(all(not(windows), not(target_vendor="apple")), weak)] #[naked] pub unsafe extern "C" fn __aeabi_uldivmod() { core::arch::asm!( @@ -53,7 +51,6 @@ intrinsics! { ); } - #[cfg_attr(all(not(windows), not(target_vendor="apple")), weak)] #[naked] pub unsafe extern "C" fn __aeabi_idivmod() { core::arch::asm!( @@ -67,7 +64,6 @@ intrinsics! { ); } - #[cfg_attr(all(not(windows), not(target_vendor="apple")), weak)] #[naked] pub unsafe extern "C" fn __aeabi_ldivmod() { core::arch::asm!( @@ -84,17 +80,13 @@ intrinsics! { ); } - // The following functions use weak linkage to allow users to override - // with custom implementation. // FIXME: The `*4` and `*8` variants should be defined as aliases. - #[weak] #[cfg(not(target_os = "ios"))] pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { crate::mem::memcpy(dest, src, n); } - #[weak] #[cfg(not(target_os = "ios"))] pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { // We are guaranteed 4-alignment, so accessing at u32 is okay. @@ -112,38 +104,32 @@ intrinsics! { __aeabi_memcpy(dest as *mut u8, src as *const u8, n); } - #[weak] #[cfg(not(target_os = "ios"))] pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memcpy4(dest, src, n); } - #[weak] #[cfg(not(target_os = "ios"))] pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { crate::mem::memmove(dest, src, n); } - #[weak] #[cfg(not(any(target_os = "ios", target_env = "msvc")))] pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memmove(dest, src, n); } - #[weak] #[cfg(not(any(target_os = "ios", target_env = "msvc")))] pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memmove(dest, src, n); } - #[weak] #[cfg(not(target_os = "ios"))] pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { // Note the different argument order crate::mem::memset(dest, c, n); } - #[weak] #[cfg(not(target_os = "ios"))] pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { let mut dest = dest as *mut u32; @@ -161,25 +147,21 @@ intrinsics! { __aeabi_memset(dest as *mut u8, n, byte as i32); } - #[weak] #[cfg(not(target_os = "ios"))] pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { __aeabi_memset4(dest, n, c); } - #[weak] #[cfg(not(target_os = "ios"))] pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { __aeabi_memset(dest, n, 0); } - #[weak] #[cfg(not(any(target_os = "ios", target_env = "msvc")))] pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); } - #[weak] #[cfg(not(any(target_os = "ios", target_env = "msvc")))] pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 2aa9a742c57ca..32c615f010e45 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -25,11 +25,12 @@ macro_rules! public_test_dep { /// platforms need and elsewhere in this library it just looks like normal Rust /// code. /// -/// When the weak-intrinsics feature is enabled, all intrinsics functions are -/// marked with #[linkage = "weak"] so that they can be replaced by another -/// implementation at link time. This is particularly useful for mixed Rust/C++ -/// binaries that want to use the C++ intrinsics, otherwise linking against the -/// Rust stdlib will replace those from the compiler-rt library. +/// All intrinsics functions are marked with #[linkage = "weak"] when +/// `not(windows) and not(target_vendor = "apple")`. +/// `weak` linkage attribute is used so that these functions can be replaced +/// by another implementation at link time. This is particularly useful for mixed +/// Rust/C++ binaries that want to use the C++ intrinsics, otherwise linking against +/// the Rust stdlib will replace those from the compiler-rt library. /// /// This macro is structured to be invoked with a bunch of functions that looks /// like: @@ -53,10 +54,6 @@ macro_rules! public_test_dep { /// /// A quick overview of attributes supported right now are: /// -/// * `weak` - indicates that the function should always be given weak linkage. -/// This attribute must come before other attributes, as the other attributes -/// will generate the final output function and need to have `weak` modify -/// them. /// * `maybe_use_optimized_c_shim` - indicates that the Rust implementation is /// ignored if an optimized C version was compiled. /// * `aapcs_on_arm` - forces the ABI of the function to be `"aapcs"` on ARM and @@ -128,67 +125,6 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); - // Explicit weak linkage gets dropped when weak-intrinsics is on since it - // will be added unconditionally to all intrinsics and would conflict - // otherwise. - ( - #[weak] - $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { - $($body:tt)* - } - - $($rest:tt)* - ) => ( - #[cfg(feature = "weak-intrinsics")] - intrinsics! { - $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - } - - #[cfg(not(feature = "weak-intrinsics"))] - intrinsics! { - $(#[$($attr)*])* - #[linkage = "weak"] - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - } - - intrinsics!($($rest)*); - ); - // Same as above but for unsafe. - ( - #[weak] - $(#[$($attr:tt)*])* - pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { - $($body:tt)* - } - - $($rest:tt)* - ) => ( - #[cfg(feature = "weak-intrinsics")] - intrinsics! { - $(#[$($attr)*])* - pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - } - - #[cfg(not(feature = "weak-intrinsics"))] - intrinsics! { - $(#[$($attr)*])* - #[linkage = "weak"] - pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - } - - intrinsics!($($rest)*); - ); - // Right now there's a bunch of architecture-optimized intrinsics in the // stock compiler-rt implementation. Not all of these have been ported over // to Rust yet so when the `c` feature of this crate is enabled we fall back @@ -211,7 +147,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( #[cfg($name = "optimized-c")] - #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] + #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] pub $(unsafe $($empty)? )? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { extern $abi { fn $name($($argname: $ty),*) $(-> $ret)?; @@ -311,7 +247,6 @@ macro_rules! intrinsics { ) => ( #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64"))] $(#[$($attr)*])* - #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } @@ -319,7 +254,7 @@ macro_rules! intrinsics { #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64"))] pub mod $name { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] + #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] pub extern $abi fn $name( $($argname: $ty),* ) -> $crate::macros::win64_128bit_abi_hack::U64x2 { @@ -360,7 +295,7 @@ macro_rules! intrinsics { #[cfg(target_arch = "arm")] pub mod $name { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] + #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } @@ -369,7 +304,7 @@ macro_rules! intrinsics { #[cfg(target_arch = "arm")] pub mod $alias { #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - #[cfg_attr(any(all(not(windows), not(target_vendor="apple")), feature = "weak-intrinsics"), linkage = "weak")] + #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] pub extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } @@ -405,7 +340,7 @@ macro_rules! intrinsics { pub mod $name { $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] + #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } @@ -429,7 +364,7 @@ macro_rules! intrinsics { #[naked] $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] + #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } @@ -495,7 +430,7 @@ macro_rules! intrinsics { pub mod $name { $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] + #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } @@ -521,7 +456,7 @@ macro_rules! intrinsics { pub mod $name { $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - #[cfg_attr(feature = "weak-intrinsics", linkage = "weak")] + #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index e47b834e44656..7d4d1787678bc 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -9,7 +9,6 @@ macro_rules! no_mangle { ($(fn $fun:ident($($iid:ident : $ity:ty),+) -> $oty:ty;)+) => { intrinsics! { $( - #[cfg_attr(all(not(windows), not(target_vendor = "apple")), weak)] pub extern "C" fn $fun($($iid: $ity),+) -> $oty { self::libm::$fun($($iid),+) } @@ -94,14 +93,12 @@ no_mangle! { } intrinsics! { - #[cfg_attr(all(not(windows), not(target_vendor = "apple")), weak)] pub extern "C" fn lgamma_r(x: f64, s: &mut i32) -> f64 { let r = self::libm::lgamma_r(x); *s = r.1; r.0 } - #[cfg_attr(all(not(windows), not(target_vendor = "apple")), weak)] pub extern "C" fn lgammaf_r(x: f32, s: &mut i32) -> f32 { let r = self::libm::lgammaf_r(x); *s = r.1; diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index ccf191779f49a..d0ff501585b3a 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -20,14 +20,12 @@ use core::ops::{BitOr, Shl}; mod impls; intrinsics! { - #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), weak)] #[mem_builtin] pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { impls::copy_forward(dest, src, n); dest } - #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), weak)] #[mem_builtin] pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { let delta = (dest as usize).wrapping_sub(src as usize); @@ -41,26 +39,22 @@ intrinsics! { dest } - #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), weak)] #[mem_builtin] pub unsafe extern "C" fn memset(s: *mut u8, c: crate::mem::c_int, n: usize) -> *mut u8 { impls::set_bytes(s, c as u8, n); s } - #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), weak)] #[mem_builtin] pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { impls::compare_bytes(s1, s2, n) } - #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), weak)] #[mem_builtin] pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { memcmp(s1, s2, n) } - #[cfg_attr(not(all(target_os = "windows", target_env = "gnu")), weak)] #[mem_builtin] pub unsafe extern "C" fn strlen(s: *const core::ffi::c_char) -> usize { impls::c_string_length(s) From e232a7914666faa57bbaeff501fe89c7861b3115 Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Thu, 2 May 2024 21:50:00 +0800 Subject: [PATCH 1202/4206] Remove unneeded `weak` for `optimized-c` function `weak` is only used with `no_mangle` --- library/compiler-builtins/src/macros.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 32c615f010e45..89cd6468999be 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -147,7 +147,6 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( #[cfg($name = "optimized-c")] - #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] pub $(unsafe $($empty)? )? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { extern $abi { fn $name($($argname: $ty),*) $(-> $ret)?; From ce8a0c346d5ce003d1f82d11c3e7bc451b349325 Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Thu, 2 May 2024 22:00:29 +0800 Subject: [PATCH 1203/4206] Cleanup `manged-names` macro Don't generate the whole function if we are not going to use `no_mangle`, there is no point --- library/compiler-builtins/src/macros.rs | 47 +++++++++++++------------ 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 89cd6468999be..f762ef4da21d6 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -250,11 +250,11 @@ macro_rules! intrinsics { $($body)* } - #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64"))] - pub mod $name { - #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64", not(feature = "mangled-names")))] + mod $name { + #[no_mangle] #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] - pub extern $abi fn $name( $($argname: $ty),* ) + extern $abi fn $name( $($argname: $ty),* ) -> $crate::macros::win64_128bit_abi_hack::U64x2 { let e: $($ret)? = super::$name($($argname),*); @@ -291,20 +291,20 @@ macro_rules! intrinsics { $($body)* } - #[cfg(target_arch = "arm")] - pub mod $name { - #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[cfg(all(target_arch = "arm", not(feature = "mangled-names")))] + mod $name { + #[no_mangle] #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } } - #[cfg(target_arch = "arm")] - pub mod $alias { - #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[cfg(all(target_arch = "arm", not(feature = "mangled-names")))] + mod $alias { + #[no_mangle] #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] - pub extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? { + extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } } @@ -335,12 +335,12 @@ macro_rules! intrinsics { $($body)* } - #[cfg(feature = "mem")] - pub mod $name { + #[cfg(all(feature = "mem", not(feature = "mangled-names")))] + mod $name { $(#[$($attr)*])* - #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[no_mangle] #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] - pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } } @@ -359,6 +359,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( + // `#[naked]` definitions are referenced by other places, so we can't use `cfg` like the others pub mod $name { #[naked] $(#[$($attr)*])* @@ -426,11 +427,12 @@ macro_rules! intrinsics { $($body)* } - pub mod $name { + #[cfg(not(feature = "mangled-names"))] + mod $name { $(#[$($attr)*])* - #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[no_mangle] #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } } @@ -452,11 +454,12 @@ macro_rules! intrinsics { $($body)* } - pub mod $name { + #[cfg(not(feature = "mangled-names"))] + mod $name { $(#[$($attr)*])* - #[cfg_attr(not(feature = "mangled-names"), no_mangle)] + #[no_mangle] #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] - pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + unsafe fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } } From 8c0c504d4fe380dc0b6e233bbe474dbef2647e40 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 4 May 2024 14:56:01 +0200 Subject: [PATCH 1204/4206] Update reference to rustc-std-workspace-core --- library/compiler-builtins/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index c8f164c94d28e..6a3c53de805d4 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -28,8 +28,8 @@ links = 'compiler-rt' test = false [dependencies] -# For more information on this dependency see rust-lang/rust's -# `src/tools/rustc-std-workspace` folder +# For more information on this dependency see +# https://github.com/rust-lang/rust/tree/master/library/rustc-std-workspace-core core = { version = "1.0.0", optional = true, package = 'rustc-std-workspace-core' } [build-dependencies] From 060391b020cb694f29329da3a9ff9200c84918e7 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 4 May 2024 15:31:14 +0100 Subject: [PATCH 1205/4206] Release version 0.1.110 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 6a3c53de805d4..1f4d319298a2e 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.109" +version = "0.1.110" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 461682bd914ef9c5f112ea8d3e43fc150d221492 Mon Sep 17 00:00:00 2001 From: Patryk Wychowaniec Date: Sat, 4 May 2024 15:30:43 +0200 Subject: [PATCH 1206/4206] fix: Add `#[avr_skip]` for `__addsf3` & `__adddf3` It looks like I've forgotten about them [back in 2023](https://github.com/rust-lang/compiler-builtins/pull/527). --- library/compiler-builtins/src/float/add.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 804f4b5100b7a..97f73e2f44ca1 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -189,12 +189,14 @@ where } intrinsics! { + #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_fadd] pub extern "C" fn __addsf3(a: f32, b: f32) -> f32 { add(a, b) } + #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_dadd] pub extern "C" fn __adddf3(a: f64, b: f64) -> f64 { From 2faef31e960b88893dc8b9a6be0062546bfdad61 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 4 May 2024 19:57:27 +0100 Subject: [PATCH 1207/4206] Release version 0.1.111 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 1f4d319298a2e..0606ef1e7bc02 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.110" +version = "0.1.111" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From c7eadedd5f5da45bad10b761e507e09ecec47ce0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 May 2024 04:16:52 -0500 Subject: [PATCH 1208/4206] Deny warnings in CI The main crate already has `#![deny(warnings)]`. Set RUSTFLAGS in CI to enforce this for other crates in the workspace. --- library/compiler-builtins/libm/.github/workflows/main.yml | 4 ++++ library/compiler-builtins/libm/build.rs | 4 ++++ library/compiler-builtins/libm/ci/run-docker.sh | 1 + .../libm/crates/compiler-builtins-smoke-test/Cargo.toml | 3 +++ .../libm/crates/compiler-builtins-smoke-test/build.rs | 3 +++ .../libm/crates/compiler-builtins-smoke-test/src/lib.rs | 2 +- 6 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 5408ac23fb494..2f2e46822b9ef 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -1,6 +1,10 @@ name: CI on: [push, pull_request] +env: + RUSTDOCFLAGS: -Dwarnings + RUSTFLAGS: -Dwarnings + jobs: docker: name: Docker diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 80145a9ccac97..c9ae232607fb9 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -2,10 +2,14 @@ use std::env; fn main() { println!("cargo:rerun-if-changed=build.rs"); + println!("cargo::rustc-check-cfg=cfg(assert_no_panic)"); + println!("cargo::rustc-check-cfg=cfg(feature, values(\"unstable\"))"); #[cfg(feature = "musl-reference-tests")] musl_reference_tests::generate(); + println!("cargo::rustc-check-cfg=cfg(feature, values(\"checked\"))"); + #[allow(unexpected_cfgs)] if !cfg!(feature = "checked") { let lvl = env::var("OPT_LEVEL").unwrap(); if lvl != "0" { diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh index c7ad60fd499d5..8d323634a67ec 100755 --- a/library/compiler-builtins/libm/ci/run-docker.sh +++ b/library/compiler-builtins/libm/ci/run-docker.sh @@ -16,6 +16,7 @@ run() { docker run \ --rm \ --user $(id -u):$(id -g) \ + -e RUSTFLAGS \ -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ -v "${HOME}/.cargo":/cargo \ diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index ac192a9132f71..695b710ff30dd 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -7,3 +7,6 @@ authors = ["Jorge Aparicio "] test = false bench = false +[features] +unstable = [] +checked = [] diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs new file mode 100644 index 0000000000000..27d4a0e89d0ba --- /dev/null +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs @@ -0,0 +1,3 @@ +fn main() { + println!("cargo::rustc-check-cfg=cfg(assert_no_panic)"); +} diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index 7fad301b98349..ab744c45bcec7 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -6,4 +6,4 @@ #![no_std] #[path = "../../../src/math/mod.rs"] -mod libm; +pub mod libm; From e4e03883ed315dd21724b003ef1875309627505f Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Wed, 8 May 2024 21:45:13 -0400 Subject: [PATCH 1209/4206] Enable chkstk/alloca intrinsics on i686-unknown-uefi --- library/compiler-builtins/src/x86.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs index c348d082d9e78..ceec3912eabb1 100644 --- a/library/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/src/x86.rs @@ -10,8 +10,7 @@ use core::intrinsics; intrinsics! { #[naked] #[cfg(all( - windows, - target_env = "gnu", + any(all(windows, target_env = "gnu"), target_os = "uefi"), not(feature = "no-asm") ))] pub unsafe extern "C" fn __chkstk() { @@ -23,8 +22,7 @@ intrinsics! { #[naked] #[cfg(all( - windows, - target_env = "gnu", + any(all(windows, target_env = "gnu"), target_os = "uefi"), not(feature = "no-asm") ))] pub unsafe extern "C" fn _alloca() { From ccfe0e38081c45684c01e7c4dd3748a88526c613 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 May 2024 02:49:35 -0500 Subject: [PATCH 1210/4206] Deny warnings in CI There are currently a lot of warnings printed in CI, mostly dead code. Update CI to deny warnings. --- library/compiler-builtins/.github/workflows/main.yml | 4 ++++ library/compiler-builtins/ci/run-docker.sh | 1 + 2 files changed, 5 insertions(+) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 57497e0500160..970a32ae51811 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -1,6 +1,10 @@ name: CI on: [push, pull_request] +env: + RUSTDOCFLAGS: -Dwarnings + RUSTFLAGS: -Dwarnings + jobs: test: name: Test diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index b85f64133a71b..e5ff8a46b26c9 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -48,6 +48,7 @@ run() { docker run \ --rm \ -e RUST_COMPILER_RT_ROOT \ + -e RUSTFLAGS \ -e "CARGO_TARGET_DIR=/builtins-target" \ -v "$(pwd):/checkout:ro" \ -w /checkout \ From 286944e479693949e2da8fc105ff397bc1166ffc Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 May 2024 03:04:47 -0500 Subject: [PATCH 1211/4206] Emit directives for cargo-check-cfg --- library/compiler-builtins/build.rs | 73 ++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index bafbf75d06814..31e527a0b6a72 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -2,6 +2,7 @@ use std::{collections::BTreeMap, env, sync::atomic::Ordering}; fn main() { println!("cargo:rerun-if-changed=build.rs"); + configure_check_cfg(); let target = env::var("TARGET").unwrap(); let cwd = env::current_dir().unwrap(); @@ -9,6 +10,7 @@ fn main() { println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display()); // Activate libm's unstable features to make full use of Nightly. + println!("cargo::rustc-check-cfg=cfg(feature, values(\"unstable\"))"); println!("cargo:rustc-cfg=feature=\"unstable\""); // Emscripten's runtime includes all the builtins @@ -36,6 +38,7 @@ fn main() { } // These targets have hardware unaligned access support. + println!("cargo::rustc-check-cfg=cfg(feature, values(\"mem-unaligned\"))"); if target.contains("x86_64") || target.contains("i686") || target.contains("aarch64") @@ -64,6 +67,7 @@ fn main() { } // To compile intrinsics.rs for thumb targets, where there is no libc + println!("cargo::rustc-check-cfg=cfg(thumb)"); if llvm_target[0].starts_with("thumb") { println!("cargo:rustc-cfg=thumb") } @@ -71,6 +75,7 @@ fn main() { // 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 llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" { println!("cargo:rustc-cfg=thumb_1") } @@ -78,6 +83,7 @@ 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). + println!("cargo::rustc-check-cfg=cfg(kernel_user_helpers)"); if llvm_target[0] == "armv4t" || llvm_target[0] == "armv5te" || target == "arm-linux-androideabi" @@ -145,6 +151,72 @@ fn generate_aarch64_outlined_atomics() { std::fs::write(dst, buf).unwrap(); } +/// Emit directives for features we expect to support that aren't in `Cargo.toml`. +/// +/// These are mostly cfg elements emitted by this `build.rs`. +fn configure_check_cfg() { + // Functions where we can set the "optimized-c" flag + const HAS_OPTIMIZED_C: &[&str] = &[ + "__ashldi3", + "__ashlsi3", + "__ashrdi3", + "__ashrsi3", + "__clzsi2", + "__divdi3", + "__divsi3", + "__divmoddi4", + "__divmodsi4", + "__divmodsi4", + "__divmodti4", + "__lshrdi3", + "__lshrsi3", + "__moddi3", + "__modsi3", + "__muldi3", + "__udivdi3", + "__udivmoddi4", + "__udivmodsi4", + "__udivsi3", + "__umoddi3", + "__umodsi3", + ]; + + // Build a list of all aarch64 atomic operation functions + let mut aarch_atomic = Vec::new(); + for aarch_op in ["cas", "ldadd", "ldclr", "ldeor", "ldset", "swp"] { + let op_sizes = if aarch_op == "cas" { + [1, 2, 4, 8, 16].as_slice() + } else { + [1, 2, 4, 8].as_slice() + }; + + for op_size in op_sizes { + for ordering in ["relax", "acq", "rel", "acq_rel"] { + aarch_atomic.push(format!("__aarch64_{}{}_{}", aarch_op, op_size, ordering)); + } + } + } + + for fn_name in HAS_OPTIMIZED_C + .iter() + .copied() + .chain(aarch_atomic.iter().map(|s| s.as_str())) + { + println!( + "cargo::rustc-check-cfg=cfg({}, values(\"optimized-c\"))", + fn_name + ); + } + + // 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")] mod c { extern crate cc; @@ -307,6 +379,7 @@ mod c { // also needs to satisfy intrinsics that jemalloc or C in general may // need, so include a few more that aren't typically needed by // LLVM/Rust. + #[allow(unexpected_cfgs)] if cfg!(feature = "rustbuild") { sources.extend(&[("__ffsdi2", "ffsdi2.c")]); } From 54d96150b58a498165ea2f1ea4fdefbf774f3bbe Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 May 2024 03:23:36 -0500 Subject: [PATCH 1212/4206] Update `cfg` to fix warnings --- library/compiler-builtins/src/float/mod.rs | 1 + library/compiler-builtins/src/int/mod.rs | 1 + library/compiler-builtins/testcrate/tests/cmp.rs | 1 + library/compiler-builtins/testcrate/tests/conv.rs | 2 +- library/compiler-builtins/testcrate/tests/misc.rs | 2 +- 5 files changed, 5 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index a82dd7d2a3b08..b0fbe8affcf73 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -14,6 +14,7 @@ pub mod trunc; public_test_dep! { /// Trait for some basic operations on floats +#[allow(dead_code)] pub(crate) trait Float: Copy + core::fmt::Debug diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 509f9fdae395a..3ef71da8d5da0 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -13,6 +13,7 @@ pub use self::leading_zeros::__clzsi2; public_test_dep! { /// Trait for some basic operations on integers +#[allow(dead_code)] pub(crate) trait Int: Copy + core::fmt::Debug diff --git a/library/compiler-builtins/testcrate/tests/cmp.rs b/library/compiler-builtins/testcrate/tests/cmp.rs index 5c10a5601138a..14dd76b2d7a74 100644 --- a/library/compiler-builtins/testcrate/tests/cmp.rs +++ b/library/compiler-builtins/testcrate/tests/cmp.rs @@ -1,5 +1,6 @@ #![allow(unused_macros)] +#[cfg(not(target_arch = "powerpc64"))] use testcrate::*; macro_rules! cmp { diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 84828dbfa6c77..5cff01202a875 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -155,7 +155,7 @@ macro_rules! conv { stringify!($fn) ); } - }); + }) }; } diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index 402d202a82b27..cdc37e2a0d7e3 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -1,7 +1,6 @@ // makes configuration easier #![allow(unused_macros)] -use compiler_builtins::float::Float; use testcrate::*; /// Make sure that the the edge case tester and randomized tester don't break, and list examples of @@ -138,6 +137,7 @@ macro_rules! pow { #[test] fn float_pow() { use compiler_builtins::float::pow::{__powidf2, __powisf2}; + use compiler_builtins::float::Float; pow!( f32, 1e-4, __powisf2; From f52b4a268fda27b2e629fed7368f743db0dc9aad Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 May 2024 04:26:49 -0500 Subject: [PATCH 1213/4206] Remove the undocumented and unused `rustbuild` feature See --- library/compiler-builtins/build.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 31e527a0b6a72..47c8b4ffe56ae 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -375,15 +375,6 @@ mod c { ]); } - // When compiling in rustbuild (the rust-lang/rust repo) this library - // also needs to satisfy intrinsics that jemalloc or C in general may - // need, so include a few more that aren't typically needed by - // LLVM/Rust. - #[allow(unexpected_cfgs)] - if cfg!(feature = "rustbuild") { - sources.extend(&[("__ffsdi2", "ffsdi2.c")]); - } - // On iOS and 32-bit OSX these are all just empty intrinsics, no need to // include them. if target_os != "ios" From f16e62159b91919d602399b51efe4c1c80884580 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 11 May 2024 09:50:21 +0200 Subject: [PATCH 1214/4206] Release 0.1.112 --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/libm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 0606ef1e7bc02..4564ba9e54c12 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.111" +version = "0.1.112" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index a1e8a5bf95e99..279e5f6abe0a2 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit a1e8a5bf95e99309760b764b2a332d0039d08350 +Subproject commit 279e5f6abe0a2ca9066962d9ec894f0df1f417ac From a5779e5d37a9efce7b55914d9cc56e38bc260444 Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Mon, 13 May 2024 11:17:07 -0700 Subject: [PATCH 1215/4206] Fix paths for Windows arm64 build --- library/compiler-builtins/build.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index bafbf75d06814..c6af5a9e7b2f0 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1,4 +1,4 @@ -use std::{collections::BTreeMap, env, sync::atomic::Ordering}; +use std::{collections::BTreeMap, env, path::PathBuf, sync::atomic::Ordering}; fn main() { println!("cargo:rerun-if-changed=build.rs"); @@ -141,8 +141,8 @@ fn generate_aarch64_outlined_atomics() { buf += macro_def; buf += "}; }\n"; } - let dst = std::env::var("OUT_DIR").unwrap() + "/outlined_atomics.rs"; - std::fs::write(dst, buf).unwrap(); + let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); + std::fs::write(out_dir.join("outlined_atomics.rs"), buf).unwrap(); } #[cfg(feature = "c")] @@ -612,7 +612,7 @@ mod c { fn build_aarch64_out_of_line_atomics_libraries(builtins_dir: &Path, cfg: &mut cc::Build) { let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - let outlined_atomics_file = builtins_dir.join("aarch64/lse.S"); + let outlined_atomics_file = builtins_dir.join("aarch64").join("lse.S"); println!("cargo:rerun-if-changed={}", outlined_atomics_file.display()); cfg.include(&builtins_dir); From 4edceece666ff008a61bc645469ee792de087ecf Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Mon, 13 May 2024 11:29:55 -0700 Subject: [PATCH 1216/4206] Add aarch64 target --- library/compiler-builtins/.github/workflows/main.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 57497e0500160..f1c63e4f93f78 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -83,6 +83,9 @@ jobs: - target: x86_64-pc-windows-gnu os: windows-latest rust: nightly-x86_64-gnu + - target: aarch64-pc-windows-gnu + os: windows-latest + rust: nightly steps: - name: Print runner information run: uname -a From 6ef61fd85a795ba688a383b018765f730a995c37 Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Mon, 13 May 2024 11:31:23 -0700 Subject: [PATCH 1217/4206] Update target --- library/compiler-builtins/.github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index f1c63e4f93f78..7a799eaed5c81 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -83,7 +83,7 @@ jobs: - target: x86_64-pc-windows-gnu os: windows-latest rust: nightly-x86_64-gnu - - target: aarch64-pc-windows-gnu + - target: aarch64-pc-windows-msvc os: windows-latest rust: nightly steps: From 8c27bcb11acc4f505699521051111853354de5ed Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Mon, 13 May 2024 11:38:43 -0700 Subject: [PATCH 1218/4206] Maybe try arm64 --- library/compiler-builtins/.github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 7a799eaed5c81..ba555387978fc 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -15,6 +15,9 @@ jobs: - target: aarch64-unknown-linux-gnu os: ubuntu-latest rust: nightly + - target: aarch64-pc-windows-msvc + os: [windows-latest, arm64] + rust: nightly - target: arm-unknown-linux-gnueabi os: ubuntu-latest rust: nightly @@ -83,9 +86,6 @@ jobs: - target: x86_64-pc-windows-gnu os: windows-latest rust: nightly-x86_64-gnu - - target: aarch64-pc-windows-msvc - os: windows-latest - rust: nightly steps: - name: Print runner information run: uname -a From 4c35dc3b1e436750ad3a04c867bdb531db713193 Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Tue, 14 May 2024 15:47:07 -0700 Subject: [PATCH 1219/4206] Remove aarch64 CI --- library/compiler-builtins/.github/workflows/main.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index ba555387978fc..57497e0500160 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -15,9 +15,6 @@ jobs: - target: aarch64-unknown-linux-gnu os: ubuntu-latest rust: nightly - - target: aarch64-pc-windows-msvc - os: [windows-latest, arm64] - rust: nightly - target: arm-unknown-linux-gnueabi os: ubuntu-latest rust: nightly From 10689247bc50a2dff10b244c1a5434ad3c847b97 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 10 May 2024 18:38:09 -0500 Subject: [PATCH 1220/4206] Split `Int` into `Int` and `MinInt` `MinInt` contains the basic methods that are only needed by integers involved in widening operations, i.e. big integers. `Int` retains all other operations and convenience methods. --- library/compiler-builtins/src/float/add.rs | 22 +- library/compiler-builtins/src/float/cmp.rs | 2 +- library/compiler-builtins/src/float/div.rs | 79 +++--- library/compiler-builtins/src/float/extend.rs | 2 +- library/compiler-builtins/src/float/mod.rs | 7 +- library/compiler-builtins/src/float/mul.rs | 2 +- library/compiler-builtins/src/float/trunc.rs | 2 +- library/compiler-builtins/src/int/addsub.rs | 10 +- library/compiler-builtins/src/int/mod.rs | 232 ++++++++++-------- library/compiler-builtins/src/int/mul.rs | 4 +- library/compiler-builtins/src/int/shift.rs | 2 +- .../compiler-builtins/testcrate/src/lib.rs | 18 +- 12 files changed, 210 insertions(+), 172 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 97f73e2f44ca1..909948ad29c53 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -1,5 +1,5 @@ use crate::float::Float; -use crate::int::{CastInto, Int}; +use crate::int::{CastInto, Int, MinInt}; /// Returns `a + b` fn add(a: F, b: F) -> F @@ -57,9 +57,9 @@ where } // zero + anything = anything - if a_abs == Int::ZERO { + if a_abs == MinInt::ZERO { // but we need to get the sign right for zero + zero - if b_abs == Int::ZERO { + if b_abs == MinInt::ZERO { return F::from_repr(a.repr() & b.repr()); } else { return b; @@ -67,7 +67,7 @@ where } // anything + zero = anything - if b_abs == Int::ZERO { + if b_abs == MinInt::ZERO { return a; } } @@ -113,10 +113,10 @@ where // Shift the significand of b by the difference in exponents, with a sticky // bottom bit to get rounding correct. let align = a_exponent.wrapping_sub(b_exponent).cast(); - if align != Int::ZERO { + if align != MinInt::ZERO { if align < bits { let sticky = - F::Int::from_bool(b_significand << bits.wrapping_sub(align).cast() != Int::ZERO); + F::Int::from_bool(b_significand << bits.wrapping_sub(align).cast() != MinInt::ZERO); b_significand = (b_significand >> align.cast()) | sticky; } else { b_significand = one; // sticky; b is known to be non-zero. @@ -125,8 +125,8 @@ where if subtraction { a_significand = a_significand.wrapping_sub(b_significand); // If a == -b, return +zero. - if a_significand == Int::ZERO { - return F::from_repr(Int::ZERO); + if a_significand == MinInt::ZERO { + return F::from_repr(MinInt::ZERO); } // If partial cancellation occured, we need to left-shift the result @@ -143,8 +143,8 @@ where // If the addition carried up, we need to right-shift the result and // adjust the exponent: - if a_significand & implicit_bit << 4 != Int::ZERO { - let sticky = F::Int::from_bool(a_significand & one != Int::ZERO); + if a_significand & implicit_bit << 4 != MinInt::ZERO { + let sticky = F::Int::from_bool(a_significand & one != MinInt::ZERO); a_significand = a_significand >> 1 | sticky; a_exponent += 1; } @@ -160,7 +160,7 @@ where // need to shift the significand. let shift = (1 - a_exponent).cast(); let sticky = - F::Int::from_bool((a_significand << bits.wrapping_sub(shift).cast()) != Int::ZERO); + F::Int::from_bool((a_significand << bits.wrapping_sub(shift).cast()) != MinInt::ZERO); a_significand = a_significand >> shift.cast() | sticky; a_exponent = 0; } diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 1c8917af8adff..193c5df368c89 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -1,7 +1,7 @@ #![allow(unreachable_code)] use crate::float::Float; -use crate::int::Int; +use crate::int::MinInt; #[derive(Clone, Copy)] enum Result { diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index d587fe4f98f67..c0d780b66dda4 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -3,7 +3,9 @@ #![allow(clippy::needless_return)] use crate::float::Float; -use crate::int::{CastInto, DInt, HInt, Int}; +use crate::int::{CastInto, DInt, HInt, Int, MinInt}; + +use super::HalfRep; fn div32(a: F, b: F) -> F where @@ -454,15 +456,20 @@ where fn div64(a: F, b: F) -> F where - u32: CastInto, F::Int: CastInto, - i32: CastInto, F::Int: CastInto, - u64: CastInto, + F::Int: CastInto>, + F::Int: From>, + F::Int: From, F::Int: CastInto, - i64: CastInto, F::Int: CastInto, - F::Int: HInt, + F::Int: HInt + DInt, + u16: CastInto, + i32: CastInto, + i64: CastInto, + u32: CastInto, + u64: CastInto, + u64: CastInto>, { const NUMBER_OF_HALF_ITERATIONS: usize = 3; const NUMBER_OF_FULL_ITERATIONS: usize = 1; @@ -471,7 +478,7 @@ where let one = F::Int::ONE; let zero = F::Int::ZERO; let hw = F::BITS / 2; - let lo_mask = u64::MAX >> hw; + let lo_mask = F::Int::MAX >> hw; let significand_bits = F::SIGNIFICAND_BITS; let max_exponent = F::EXPONENT_MAX; @@ -616,8 +623,9 @@ where let mut x_uq0 = if NUMBER_OF_HALF_ITERATIONS > 0 { // Starting with (n-1) half-width iterations - let b_uq1_hw: u32 = - (CastInto::::cast(b_significand) >> (significand_bits + 1 - hw)) as u32; + let b_uq1_hw: HalfRep = CastInto::>::cast( + CastInto::::cast(b_significand) >> (significand_bits + 1 - hw), + ); // C is (3/4 + 1/sqrt(2)) - 1 truncated to W0 fractional bits as UQ0.HW // with W0 being either 16 or 32 and W0 <= HW. @@ -625,12 +633,13 @@ where // b/2 is subtracted to obtain x0) wrapped to [0, 1) range. // HW is at least 32. Shifting into the highest bits if needed. - let c_hw = (0x7504F333_u64 as u32).wrapping_shl(hw.wrapping_sub(32)); + let c_hw = (CastInto::>::cast(0x7504F333_u64)).wrapping_shl(hw.wrapping_sub(32)); // b >= 1, thus an upper bound for 3/4 + 1/sqrt(2) - b/2 is about 0.9572, // so x0 fits to UQ0.HW without wrapping. - let x_uq0_hw: u32 = { - let mut x_uq0_hw: u32 = c_hw.wrapping_sub(b_uq1_hw /* exact b_hw/2 as UQ0.HW */); + let x_uq0_hw: HalfRep = { + let mut x_uq0_hw: HalfRep = + c_hw.wrapping_sub(b_uq1_hw /* exact b_hw/2 as UQ0.HW */); // dbg!(x_uq0_hw); // An e_0 error is comprised of errors due to // * x0 being an inherently imprecise first approximation of 1/b_hw @@ -661,8 +670,9 @@ where // no overflow occurred earlier: ((rep_t)x_UQ0_hw * b_UQ1_hw >> HW) is // expected to be strictly positive because b_UQ1_hw has its highest bit set // and x_UQ0_hw should be rather large (it converges to 1/2 < 1/b_hw <= 1). - let corr_uq1_hw: u32 = - 0.wrapping_sub(((x_uq0_hw as u64).wrapping_mul(b_uq1_hw as u64)) >> hw) as u32; + let corr_uq1_hw: HalfRep = CastInto::>::cast(zero.wrapping_sub( + ((F::Int::from(x_uq0_hw)).wrapping_mul(F::Int::from(b_uq1_hw))) >> hw, + )); // dbg!(corr_uq1_hw); // Now, we should multiply UQ0.HW and UQ1.(HW-1) numbers, naturally @@ -677,7 +687,9 @@ where // The fact corr_UQ1_hw was virtually round up (due to result of // multiplication being **first** truncated, then negated - to improve // error estimations) can increase x_UQ0_hw by up to 2*Ulp of x_UQ0_hw. - x_uq0_hw = ((x_uq0_hw as u64).wrapping_mul(corr_uq1_hw as u64) >> (hw - 1)) as u32; + x_uq0_hw = ((F::Int::from(x_uq0_hw)).wrapping_mul(F::Int::from(corr_uq1_hw)) + >> (hw - 1)) + .cast(); // dbg!(x_uq0_hw); // Now, either no overflow occurred or x_UQ0_hw is 0 or 1 in its half_rep_t // representation. In the latter case, x_UQ0_hw will be either 0 or 1 after @@ -707,7 +719,7 @@ where // be not below that value (see g(x) above), so it is safe to decrement just // once after the final iteration. On the other hand, an effective value of // divisor changes after this point (from b_hw to b), so adjust here. - x_uq0_hw.wrapping_sub(1_u32) + x_uq0_hw.wrapping_sub(HalfRep::::ONE) }; // Error estimations for full-precision iterations are calculated just @@ -717,7 +729,7 @@ where // Simulating operations on a twice_rep_t to perform a single final full-width // iteration. Using ad-hoc multiplication implementations to take advantage // of particular structure of operands. - let blo: u64 = (CastInto::::cast(b_uq1)) & lo_mask; + let blo: F::Int = b_uq1 & lo_mask; // x_UQ0 = x_UQ0_hw * 2^HW - 1 // x_UQ0 * b_UQ1 = (x_UQ0_hw * 2^HW) * (b_UQ1_hw * 2^HW + blo) - b_UQ1 // @@ -726,19 +738,20 @@ where // + [ x_UQ0_hw * blo ] // - [ b_UQ1 ] // = [ result ][.... discarded ...] - let corr_uq1 = negate_u64( - (x_uq0_hw as u64) * (b_uq1_hw as u64) + (((x_uq0_hw as u64) * (blo)) >> hw) - 1, - ); // account for *possible* carry - let lo_corr = corr_uq1 & lo_mask; - let hi_corr = corr_uq1 >> hw; + let corr_uq1: F::Int = (F::Int::from(x_uq0_hw) * F::Int::from(b_uq1_hw) + + ((F::Int::from(x_uq0_hw) * blo) >> hw)) + .wrapping_sub(one) + .wrapping_neg(); // account for *possible* carry + let lo_corr: F::Int = corr_uq1 & lo_mask; + let hi_corr: F::Int = corr_uq1 >> hw; // x_UQ0 * corr_UQ1 = (x_UQ0_hw * 2^HW) * (hi_corr * 2^HW + lo_corr) - corr_UQ1 - let mut x_uq0: ::Int = ((((x_uq0_hw as u64) * hi_corr) << 1) - .wrapping_add(((x_uq0_hw as u64) * lo_corr) >> (hw - 1)) - .wrapping_sub(2)) - .cast(); // 1 to account for the highest bit of corr_UQ1 can be 1 - // 1 to account for possible carry - // Just like the case of half-width iterations but with possibility - // of overflowing by one extra Ulp of x_UQ0. + let mut x_uq0: F::Int = ((F::Int::from(x_uq0_hw) * hi_corr) << 1) + .wrapping_add((F::Int::from(x_uq0_hw) * lo_corr) >> (hw - 1)) + .wrapping_sub(F::Int::from(2u8)); + // 1 to account for the highest bit of corr_UQ1 can be 1 + // 1 to account for possible carry + // Just like the case of half-width iterations but with possibility + // of overflowing by one extra Ulp of x_UQ0. x_uq0 -= one; // ... and then traditional fixup by 2 should work @@ -755,8 +768,8 @@ where x_uq0 } else { // C is (3/4 + 1/sqrt(2)) - 1 truncated to 64 fractional bits as UQ0.n - let c: ::Int = (0x7504F333 << (F::BITS - 32)).cast(); - let x_uq0: ::Int = c.wrapping_sub(b_uq1); + let c: F::Int = (0x7504F333 << (F::BITS - 32)).cast(); + let x_uq0: F::Int = c.wrapping_sub(b_uq1); // E_0 <= 3/4 - 1/sqrt(2) + 2 * 2^-64 x_uq0 }; @@ -806,7 +819,7 @@ where // Now 1/b - (2*P) * 2^-W < x < 1/b // FIXME Is x_UQ0 still >= 0.5? - let mut quotient: ::Int = x_uq0.widen_mul(a_significand << 1).hi(); + let mut quotient: F::Int = x_uq0.widen_mul(a_significand << 1).hi(); // Now, a/b - 4*P * 2^-W < q < a/b for q= in UQ1.(SB+1+W). // quotient_UQ1 is in [0.5, 2.0) as UQ1.(SB+1), @@ -868,7 +881,7 @@ where // r = a - b * q let abs_result = if written_exponent > 0 { let mut ret = quotient & significand_mask; - ret |= ((written_exponent as u64) << significand_bits).cast(); + ret |= written_exponent.cast() << significand_bits; residual <<= 1; ret } else { diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index 7c2446603f2cf..5b0c0d9726844 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -1,5 +1,5 @@ use crate::float::Float; -use crate::int::{CastInto, Int}; +use crate::int::{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/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index b0fbe8affcf73..e62a3fe0fd53a 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,6 +1,6 @@ use core::ops; -use super::int::Int; +use crate::int::{DInt, Int, MinInt}; pub mod add; pub mod cmp; @@ -12,6 +12,9 @@ pub mod pow; pub mod sub; pub mod trunc; +/// Wrapper to extract the integer type half of the float's size +pub(crate) type HalfRep = <::Int as DInt>::H; + public_test_dep! { /// Trait for some basic operations on floats #[allow(dead_code)] @@ -60,7 +63,7 @@ pub(crate) trait Float: /// A mask for the significand const SIGNIFICAND_MASK: Self::Int; - // The implicit bit of the float format + /// The implicit bit of the float format const IMPLICIT_BIT: Self::Int; /// A mask for the exponent diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index 378fa970116fe..46c41d09f191d 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -1,5 +1,5 @@ use crate::float::Float; -use crate::int::{CastInto, DInt, HInt, Int}; +use crate::int::{CastInto, DInt, HInt, Int, MinInt}; fn mul(a: F, b: F) -> F where diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index 6de446c100685..b607a65498347 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -1,5 +1,5 @@ use crate::float::Float; -use crate::int::{CastInto, Int}; +use crate::int::{CastInto, Int, MinInt}; fn trunc(a: F) -> R where diff --git a/library/compiler-builtins/src/int/addsub.rs b/library/compiler-builtins/src/int/addsub.rs index f31eff4bd03ec..e95590d84dcb7 100644 --- a/library/compiler-builtins/src/int/addsub.rs +++ b/library/compiler-builtins/src/int/addsub.rs @@ -1,6 +1,6 @@ -use crate::int::{DInt, Int}; +use crate::int::{DInt, Int, MinInt}; -trait UAddSub: DInt { +trait UAddSub: DInt + Int { fn uadd(self, other: Self) -> Self { let (lo, carry) = self.lo().overflowing_add(other.lo()); let hi = self.hi().wrapping_add(other.hi()); @@ -22,7 +22,7 @@ impl UAddSub for u128 {} trait AddSub: Int where - ::UnsignedInt: UAddSub, + ::UnsignedInt: UAddSub, { fn add(self, other: Self) -> Self { Self::from_unsigned(self.unsigned().uadd(other.unsigned())) @@ -37,7 +37,7 @@ impl AddSub for i128 {} trait Addo: AddSub where - ::UnsignedInt: UAddSub, + ::UnsignedInt: UAddSub, { fn addo(self, other: Self) -> (Self, bool) { let sum = AddSub::add(self, other); @@ -50,7 +50,7 @@ impl Addo for u128 {} trait Subo: AddSub where - ::UnsignedInt: UAddSub, + ::UnsignedInt: UAddSub, { fn subo(self, other: Self) -> (Self, bool) { let sum = AddSub::sub(self, other); diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 3ef71da8d5da0..dd23da3b752bf 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -9,37 +9,22 @@ pub mod sdiv; pub mod shift; pub mod udiv; -pub use self::leading_zeros::__clzsi2; +pub use leading_zeros::__clzsi2; public_test_dep! { -/// Trait for some basic operations on integers +/// Minimal integer implementations needed on all integer types, including wide integers. #[allow(dead_code)] -pub(crate) trait Int: - Copy +pub(crate) trait MinInt: Copy + core::fmt::Debug - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::SubAssign - + ops::BitAndAssign - + ops::BitOrAssign - + ops::BitXorAssign - + ops::ShlAssign - + ops::ShrAssign - + ops::Add - + ops::Sub - + ops::Div - + ops::Shl - + ops::Shr + ops::BitOr - + ops::BitXor - + ops::BitAnd + ops::Not + + ops::Shl { + /// Type with the same width but other signedness - type OtherSign: Int; + type OtherSign: MinInt; /// Unsigned version of Self - type UnsignedInt: Int; + type UnsignedInt: MinInt; /// If `Self` is a signed integer const SIGNED: bool; @@ -51,13 +36,47 @@ pub(crate) trait Int: const ONE: Self; const MIN: Self; const MAX: Self; +} +} +public_test_dep! { +/// Trait for some basic operations on integers +#[allow(dead_code)] +pub(crate) trait Int: MinInt + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::SubAssign + + ops::BitAndAssign + + ops::BitOrAssign + + ops::BitXorAssign + + ops::ShlAssign + + ops::ShrAssign + + ops::Add + + ops::Sub + + ops::Mul + + ops::Div + + ops::Shr + + ops::BitXor + + ops::BitAnd +{ /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, /// 112,119,120,125,126,127]. - const FUZZ_LENGTHS: [u8; 20]; + const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); + /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. - const FUZZ_NUM: usize; + const FUZZ_NUM: usize = { + let log2 = (::BITS - 1).count_ones() as usize; + if log2 == 3 { + // case for u8 + 6 + } else { + // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate + // boundaries. + 8 + (4 * (log2 - 4)) + } + }; fn unsigned(self) -> Self::UnsignedInt; fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; @@ -84,74 +103,54 @@ pub(crate) trait Int: } } +pub(crate) const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { + let mut v = [0u8; 20]; + v[0] = 0; + v[1] = 1; + v[2] = 2; // important for parity and the iX::MIN case when reversed + let mut i = 3; + + // No need for any more until the byte boundary, because there should be no algorithms + // that are sensitive to anything not next to byte boundaries after 2. We also scale + // in powers of two, which is important to prevent u128 corner tests from getting too + // big. + let mut l = 8; + loop { + if l >= ((bits / 2) as u8) { + break; + } + // get both sides of the byte boundary + v[i] = l - 1; + i += 1; + v[i] = l; + i += 1; + l *= 2; + } + + if bits != 8 { + // add the lower side of the middle boundary + v[i] = ((bits / 2) - 1) as u8; + i += 1; + } + + // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS + // boundary because of algorithms that split the high part up. We reverse the scaling + // as we go to Self::BITS. + let mid = i; + let mut j = 1; + loop { + v[i] = (bits as u8) - (v[mid - j]) - 1; + if j == mid { + break; + } + i += 1; + j += 1; + } + v +} + macro_rules! int_impl_common { ($ty:ty) => { - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - - const FUZZ_LENGTHS: [u8; 20] = { - let bits = ::BITS; - let mut v = [0u8; 20]; - v[0] = 0; - v[1] = 1; - v[2] = 2; // important for parity and the iX::MIN case when reversed - let mut i = 3; - // No need for any more until the byte boundary, because there should be no algorithms - // that are sensitive to anything not next to byte boundaries after 2. We also scale - // in powers of two, which is important to prevent u128 corner tests from getting too - // big. - let mut l = 8; - loop { - if l >= ((bits / 2) as u8) { - break; - } - // get both sides of the byte boundary - v[i] = l - 1; - i += 1; - v[i] = l; - i += 1; - l *= 2; - } - - if bits != 8 { - // add the lower side of the middle boundary - v[i] = ((bits / 2) - 1) as u8; - i += 1; - } - - // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS - // boundary because of algorithms that split the high part up. We reverse the scaling - // as we go to Self::BITS. - let mid = i; - let mut j = 1; - loop { - v[i] = (bits as u8) - (v[mid - j]) - 1; - if j == mid { - break; - } - i += 1; - j += 1; - } - v - }; - - const FUZZ_NUM: usize = { - let log2 = (::BITS - 1).count_ones() as usize; - if log2 == 3 { - // case for u8 - 6 - } else { - // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate - // boundaries. - 8 + (4 * (log2 - 4)) - } - }; - fn from_bool(b: bool) -> Self { b as $ty } @@ -204,10 +203,20 @@ macro_rules! int_impl_common { macro_rules! int_impl { ($ity:ty, $uty:ty) => { - impl Int for $uty { + impl MinInt for $uty { type OtherSign = $ity; type UnsignedInt = $uty; + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $uty { fn unsigned(self) -> $uty { self } @@ -229,10 +238,20 @@ macro_rules! int_impl { int_impl_common!($uty); } - impl Int for $ity { + impl MinInt for $ity { type OtherSign = $uty; type UnsignedInt = $uty; + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $ity { fn unsigned(self) -> $uty { self as $uty } @@ -260,18 +279,22 @@ int_impl!(i128, u128); public_test_dep! { /// 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(crate) trait DInt: Int { +pub(crate) trait DInt: MinInt { /// Integer that is half the bit width of the integer this trait is implemented for - type H: HInt + Int; + 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); + 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; + fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { + lo.zero_widen() | hi.widen_hi() + } } } @@ -280,7 +303,7 @@ public_test_dep! { /// primitives except for `u128`, because it there is not a larger primitive. pub(crate) trait HInt: Int { /// Integer that is double the bit width of the integer this trait is implemented for - type D: DInt + Int; + type D: DInt + MinInt; /// Widens (using default extension) the integer to have double bit width fn widen(self) -> Self::D; @@ -288,7 +311,9 @@ pub(crate) trait HInt: Int { /// 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; + fn widen_hi(self) -> Self::D { + self.widen() << ::BITS + } /// Widening multiplication with zero widening. This cannot overflow. fn zero_widen_mul(self, rhs: Self) -> Self::D; /// Widening multiplication. This cannot overflow. @@ -306,13 +331,7 @@ macro_rules! impl_d_int { self as $X } fn hi(self) -> Self::H { - (self >> <$X as Int>::BITS) as $X - } - fn lo_hi(self) -> (Self::H, Self::H) { - (self.lo(), self.hi()) - } - fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { - lo.zero_widen() | hi.widen_hi() + (self >> <$X as MinInt>::BITS) as $X } } )* @@ -331,9 +350,6 @@ macro_rules! impl_h_int { fn zero_widen(self) -> Self::D { (self as $uH) as $X } - fn widen_hi(self) -> Self::D { - (self as $X) << <$H as Int>::BITS - } fn zero_widen_mul(self, rhs: Self) -> Self::D { self.zero_widen().wrapping_mul(rhs.zero_widen()) } diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index 2538e2f4181b2..e0093a725c2a5 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -1,6 +1,6 @@ use crate::int::{DInt, HInt, Int}; -trait Mul: DInt +trait Mul: DInt + Int where Self::H: DInt, { @@ -30,7 +30,7 @@ where impl Mul for u64 {} impl Mul for i128 {} -pub(crate) trait UMulo: Int + DInt { +pub(crate) trait UMulo: DInt + Int { fn mulo(self, rhs: Self) -> (Self, bool) { match (self.hi().is_zero(), rhs.hi().is_zero()) { // overflow is guaranteed diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/src/int/shift.rs index dbd0401873201..317272988ce6a 100644 --- a/library/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/src/int/shift.rs @@ -1,4 +1,4 @@ -use crate::int::{DInt, HInt, Int}; +use crate::int::{DInt, HInt, Int, MinInt}; trait Ashl: DInt { /// Returns `a << b`, requires `b < Self::BITS` diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index 9bd155f6f1048..13abf459eba1d 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -15,7 +15,7 @@ #![no_std] use compiler_builtins::float::Float; -use compiler_builtins::int::Int; +use compiler_builtins::int::{Int, MinInt}; use rand_xoshiro::rand_core::{RngCore, SeedableRng}; use rand_xoshiro::Xoshiro128StarStar; @@ -101,7 +101,10 @@ macro_rules! edge_cases { /// Feeds a series of fuzzing inputs to `f`. The fuzzer first uses an algorithm designed to find /// edge cases, followed by a more random fuzzer that runs `n` times. -pub fn fuzz(n: u32, mut f: F) { +pub fn fuzz(n: u32, mut f: F) +where + ::UnsignedInt: Int, +{ // edge case tester. Calls `f` 210 times for u128. // zero gets skipped by the loop f(I::ZERO); @@ -111,7 +114,7 @@ pub fn fuzz(n: u32, mut f: F) { // random fuzzer let mut rng = Xoshiro128StarStar::seed_from_u64(0); - let mut x: I = Int::ZERO; + let mut x: I = MinInt::ZERO; for _ in 0..n { fuzz_step(&mut rng, &mut x); f(x) @@ -119,7 +122,10 @@ pub fn fuzz(n: u32, mut f: F) { } /// The same as `fuzz`, except `f` has two inputs. -pub fn fuzz_2(n: u32, f: F) { +pub fn fuzz_2(n: u32, f: F) +where + ::UnsignedInt: Int, +{ // Check cases where the first and second inputs are zero. Both call `f` 210 times for `u128`. edge_cases!(I, case, { f(I::ZERO, case); @@ -150,10 +156,10 @@ pub fn fuzz_shift(f: F) { // Shift functions are very simple and do not need anything other than shifting a small // set of random patterns for every fuzz length. let mut rng = Xoshiro128StarStar::seed_from_u64(0); - let mut x: I = Int::ZERO; + let mut x: I = MinInt::ZERO; for i in 0..I::FUZZ_NUM { fuzz_step(&mut rng, &mut x); - f(x, Int::ZERO); + f(x, MinInt::ZERO); f(x, I::FUZZ_LENGTHS[i] as u32); } } From 23b91f2b58a08f7e6958f6dd1080f03bc87f9a04 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 10 May 2024 18:50:36 -0500 Subject: [PATCH 1221/4206] Add `i256` and `u256` bigint types --- library/compiler-builtins/src/int/big.rs | 251 ++++++++++++++++++ library/compiler-builtins/src/int/mod.rs | 2 + .../compiler-builtins/testcrate/tests/big.rs | 61 +++++ 3 files changed, 314 insertions(+) create mode 100644 library/compiler-builtins/src/int/big.rs create mode 100644 library/compiler-builtins/testcrate/tests/big.rs diff --git a/library/compiler-builtins/src/int/big.rs b/library/compiler-builtins/src/int/big.rs new file mode 100644 index 0000000000000..019dd728b5d95 --- /dev/null +++ b/library/compiler-builtins/src/int/big.rs @@ -0,0 +1,251 @@ +//! Integers used for wide operations, larger than `u128`. + +#![allow(unused)] + +use crate::int::{DInt, HInt, Int, MinInt}; +use core::{fmt, ops}; + +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 UnsignedInt = 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 UnsignedInt = 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 { + todo!() + } + } + }; +} + +impl_common!(i256); +impl_common!(u256); + +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) + } +} + +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") + } +} + +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/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index dd23da3b752bf..2b6d4b812ee05 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -3,12 +3,14 @@ use core::ops; mod specialized_div_rem; pub mod addsub; +mod big; pub mod leading_zeros; pub mod mul; pub mod sdiv; pub mod shift; pub mod udiv; +pub use big::{i256, u256}; pub use leading_zeros::__clzsi2; public_test_dep! { diff --git a/library/compiler-builtins/testcrate/tests/big.rs b/library/compiler-builtins/testcrate/tests/big.rs new file mode 100644 index 0000000000000..128b5ddfd6d59 --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/big.rs @@ -0,0 +1,61 @@ +use compiler_builtins::int::{i256, u256, HInt, MinInt}; + +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()); +} From 1be662630700d380dc57160f9faf33ae23001e3d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 10 May 2024 19:01:49 -0500 Subject: [PATCH 1222/4206] Refactor float test macros to have a fallback Change float test macros to fall back to testing against `rustc_apfloat` when system implementations are not available, rather than just skipping tests. This allows for easier debugging where operations may not be supported. --- .../compiler-builtins/testcrate/src/lib.rs | 52 +++++++++++++++++++ .../testcrate/tests/addsub.rs | 21 ++++---- .../compiler-builtins/testcrate/tests/cmp.rs | 39 +++++++++++--- .../testcrate/tests/div_rem.rs | 35 ++++++++----- .../compiler-builtins/testcrate/tests/mul.rs | 16 +++--- 5 files changed, 127 insertions(+), 36 deletions(-) diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index 13abf459eba1d..1f3a4b8262170 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -263,3 +263,55 @@ pub fn fuzz_float_2(n: u32, f: E) { f(x, y) } } + +/// Perform an operation using builtin types if available, falling back to apfloat if not. +#[macro_export] +macro_rules! apfloat_fallback { + ( + $float_ty:ty, + // Type name in `rustc_apfloat::ieee`. Not a full path, it automatically gets the prefix. + $apfloat_ty:ident, + // Cfg expression for when builtin system operations should be used + $sys_available:meta, + // The expression to run. This expression may use `FloatTy` for its signature. + // Optionally, the final conversion back to a float can be suppressed using + // `=> no_convert` (for e.g. operations that return a bool). + $op:expr $(=> $convert:ident)?, + // Arguments that get passed to `$op` after converting to a float + $($arg:expr),+ + $(,)? + ) => {{ + #[cfg($sys_available)] + let ret = { + type FloatTy = $float_ty; + $op( $($arg),+ ) + }; + + #[cfg(not($sys_available))] + let ret = { + use rustc_apfloat::Float; + type FloatTy = rustc_apfloat::ieee::$apfloat_ty; + + let op_res = $op( $(FloatTy::from_bits($arg.to_bits().into())),+ ); + + apfloat_fallback!(@convert $float_ty, op_res $(,$convert)?) + }; + + ret + }}; + + // Operations that do not need converting back to a float + (@convert $float_ty:ty, $val:expr, no_convert) => { + $val + }; + + // Some apfloat operations return a `StatusAnd` that we need to extract the value from. This + // is the default. + (@convert $float_ty:ty, $val:expr) => {{ + // ignore the status, just get the value + let unwrapped = $val.value; + + <$float_ty>::from_bits(FloatTy::to_bits(unwrapped).try_into().unwrap()) + }}; + +} diff --git a/library/compiler-builtins/testcrate/tests/addsub.rs b/library/compiler-builtins/testcrate/tests/addsub.rs index da7684ec90126..85250ac3d4896 100644 --- a/library/compiler-builtins/testcrate/tests/addsub.rs +++ b/library/compiler-builtins/testcrate/tests/addsub.rs @@ -1,5 +1,6 @@ #![allow(unused_macros)] +use core::ops::{Add, Sub}; use testcrate::*; macro_rules! sum { @@ -71,28 +72,28 @@ fn addsub() { } macro_rules! float_sum { - ($($f:ty, $fn_add:ident, $fn_sub:ident);*;) => { + ($($f:ty, $fn_add:ident, $fn_sub:ident, $apfloat_ty:ident, $sys_available:meta);*;) => { $( fuzz_float_2(N, |x: $f, y: $f| { - let add0 = x + y; - let sub0 = x - y; + let add0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Add::add, x, y); + let sub0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Sub::sub, x, y); let add1: $f = $fn_add(x, y); let sub1: $f = $fn_sub(x, y); if !Float::eq_repr(add0, add1) { panic!( - "{}({}, {}): std: {}, builtins: {}", + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", stringify!($fn_add), x, y, add0, add1 ); } if !Float::eq_repr(sub0, sub1) { panic!( - "{}({}, {}): std: {}, builtins: {}", + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", stringify!($fn_sub), x, y, sub0, sub1 ); } }); )* - }; + } } #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] @@ -105,8 +106,8 @@ fn float_addsub() { }; float_sum!( - f32, __addsf3, __subsf3; - f64, __adddf3, __subdf3; + f32, __addsf3, __subsf3, Single, all(); + f64, __adddf3, __subdf3, Double, all(); ); } @@ -120,7 +121,7 @@ fn float_addsub_arm() { }; float_sum!( - f32, __addsf3vfp, __subsf3vfp; - f64, __adddf3vfp, __subdf3vfp; + f32, __addsf3vfp, __subsf3vfp, Single, all(); + f64, __adddf3vfp, __subdf3vfp, Double, all(); ); } diff --git a/library/compiler-builtins/testcrate/tests/cmp.rs b/library/compiler-builtins/testcrate/tests/cmp.rs index 14dd76b2d7a74..20915b25d1200 100644 --- a/library/compiler-builtins/testcrate/tests/cmp.rs +++ b/library/compiler-builtins/testcrate/tests/cmp.rs @@ -1,23 +1,48 @@ #![allow(unused_macros)] +#![allow(unreachable_code)] #[cfg(not(target_arch = "powerpc64"))] use testcrate::*; macro_rules! cmp { - ($x:ident, $y:ident, $($unordered_val:expr, $fn:ident);*;) => { + ( + $f:ty, $x:ident, $y:ident, $apfloat_ty:ident, $sys_available:meta, + $($unordered_val:expr, $fn:ident);*; + ) => { $( - let cmp0 = if $x.is_nan() || $y.is_nan() { + let cmp0 = if apfloat_fallback!( + $f, $apfloat_ty, $sys_available, + |x: FloatTy| x.is_nan() => no_convert, + $x + ) || apfloat_fallback!( + $f, $apfloat_ty, $sys_available, + |y: FloatTy| y.is_nan() => no_convert, + $y + ) + { $unordered_val - } else if $x < $y { + } else if apfloat_fallback!( + $f, $apfloat_ty, $sys_available, + |x, y| x < y => no_convert, + $x, $y + ) { -1 - } else if $x == $y { + } else if apfloat_fallback!( + $f, $apfloat_ty, $sys_available, + |x, y| x == y => no_convert, + $x, $y + ) { 0 } else { 1 }; + let cmp1 = $fn($x, $y); if cmp0 != cmp1 { - panic!("{}({}, {}): std: {}, builtins: {}", stringify!($fn_builtins), $x, $y, cmp0, cmp1); + panic!( + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn), $x, $y, cmp0, cmp1 + ); } )* }; @@ -34,7 +59,7 @@ fn float_comparisons() { fuzz_float_2(N, |x: f32, y: f32| { assert_eq!(__unordsf2(x, y) != 0, x.is_nan() || y.is_nan()); - cmp!(x, y, + cmp!(f32, x, y, Single, all(), 1, __ltsf2; 1, __lesf2; 1, __eqsf2; @@ -45,7 +70,7 @@ fn float_comparisons() { }); fuzz_float_2(N, |x: f64, y: f64| { assert_eq!(__unorddf2(x, y) != 0, x.is_nan() || y.is_nan()); - cmp!(x, y, + cmp!(f64, x, y, Double, all(), 1, __ltdf2; 1, __ledf2; 1, __eqdf2; diff --git a/library/compiler-builtins/testcrate/tests/div_rem.rs b/library/compiler-builtins/testcrate/tests/div_rem.rs index de3bd9bee8f1f..461e084d068fa 100644 --- a/library/compiler-builtins/testcrate/tests/div_rem.rs +++ b/library/compiler-builtins/testcrate/tests/div_rem.rs @@ -2,6 +2,7 @@ use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divmodti4}; use compiler_builtins::int::udiv::{__udivmoddi4, __udivmodsi4, __udivmodti4, u128_divide_sparc}; + use testcrate::*; // Division algorithms have by far the nastiest and largest number of edge cases, and experience shows @@ -104,16 +105,20 @@ fn divide_sparc() { } macro_rules! float { - ($($i:ty, $fn:ident);*;) => { + ($($f:ty, $fn:ident, $apfloat_ty:ident, $sys_available:meta);*;) => { $( - fuzz_float_2(N, |x: $i, y: $i| { - let quo0 = x / y; - let quo1: $i = $fn(x, y); + fuzz_float_2(N, |x: $f, y: $f| { + let quo0: $f = apfloat_fallback!($f, $apfloat_ty, $sys_available, Div::div, x, y); + let quo1: $f = $fn(x, y); #[cfg(not(target_arch = "arm"))] if !Float::eq_repr(quo0, quo1) { panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn), x, y, quo0, quo1 + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn), + x, + y, + quo0, + quo1 ); } @@ -122,8 +127,12 @@ macro_rules! float { if !(Float::is_subnormal(quo0) || Float::is_subnormal(quo1)) { if !Float::eq_repr(quo0, quo1) { panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn), x, y, quo0, quo1 + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn), + x, + y, + quo0, + quo1 ); } } @@ -139,10 +148,11 @@ fn float_div() { div::{__divdf3, __divsf3}, Float, }; + use core::ops::Div; float!( - f32, __divsf3; - f64, __divdf3; + f32, __divsf3, Single, all(); + f64, __divdf3, Double, all(); ); } @@ -153,9 +163,10 @@ fn float_div_arm() { div::{__divdf3vfp, __divsf3vfp}, Float, }; + use core::ops::Div; float!( - f32, __divsf3vfp; - f64, __divdf3vfp; + f32, __divsf3vfp, Single, all(); + f64, __divdf3vfp, Double, all(); ); } diff --git a/library/compiler-builtins/testcrate/tests/mul.rs b/library/compiler-builtins/testcrate/tests/mul.rs index 819f06ca9ef7d..4fca2c13fa666 100644 --- a/library/compiler-builtins/testcrate/tests/mul.rs +++ b/library/compiler-builtins/testcrate/tests/mul.rs @@ -82,16 +82,16 @@ fn overflowing_mul() { } macro_rules! float_mul { - ($($f:ty, $fn:ident);*;) => { + ($($f:ty, $fn:ident, $apfloat_ty:ident, $sys_available:meta);*;) => { $( fuzz_float_2(N, |x: $f, y: $f| { - let mul0 = x * y; + let mul0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Mul::mul, x, y); let mul1: $f = $fn(x, y); // multiplication of subnormals is not currently handled if !(Float::is_subnormal(mul0) || Float::is_subnormal(mul1)) { if !Float::eq_repr(mul0, mul1) { panic!( - "{}({}, {}): std: {}, builtins: {}", + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", stringify!($fn), x, y, mul0, mul1 ); } @@ -108,10 +108,11 @@ fn float_mul() { mul::{__muldf3, __mulsf3}, Float, }; + use core::ops::Mul; float_mul!( - f32, __mulsf3; - f64, __muldf3; + f32, __mulsf3, Single, all(); + f64, __muldf3, Double, all(); ); } @@ -122,9 +123,10 @@ fn float_mul_arm() { mul::{__muldf3vfp, __mulsf3vfp}, Float, }; + use core::ops::Mul; float_mul!( - f32, __mulsf3vfp; - f64, __muldf3vfp; + f32, __mulsf3vfp, Single, all(); + f64, __muldf3vfp, Double, all(); ); } From 4509315d2fe3b3567c3e8457599ac50ff7c06d80 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 10 May 2024 19:36:35 -0500 Subject: [PATCH 1223/4206] Enable no-fail-fast for more usable test output --- 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 1298093a65807..847b52435a138 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -21,7 +21,7 @@ fi if [ "${NO_STD:-}" = "1" ]; then echo "nothing to do for no_std" else - run="cargo test --manifest-path testcrate/Cargo.toml --target $target" + run="cargo test --manifest-path testcrate/Cargo.toml --no-fail-fast --target $target" $run $run --release $run --features c From 2755f457f8bbdb5a5528e644c2c7d952f356221b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 10 May 2024 19:22:03 -0500 Subject: [PATCH 1224/4206] Implement `f128` addition and subtraction --- library/compiler-builtins/README.md | 4 +-- library/compiler-builtins/build.rs | 6 ----- library/compiler-builtins/src/float/add.rs | 10 +++++++ library/compiler-builtins/src/float/sub.rs | 12 +++++++++ .../compiler-builtins/testcrate/Cargo.toml | 2 ++ library/compiler-builtins/testcrate/build.rs | 27 +++++++++++++++++++ .../testcrate/tests/addsub.rs | 17 +++++++++++- 7 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 library/compiler-builtins/testcrate/build.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 00d547f1bdb20..c7241ec7c0fd0 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -232,7 +232,7 @@ These builtins are needed to support 128-bit integers. These builtins are needed to support `f16` and `f128`, which are in the process of being added to Rust. -- [ ] addtf3.c +- [x] addtf3.c - [ ] comparetf2.c - [ ] divtf3.c - [x] extenddftf2.c @@ -255,7 +255,7 @@ These builtins are needed to support `f16` and `f128`, which are in the process - [ ] ppc/fixunstfdi.c - [ ] ppc/floatditf.c - [ ] ppc/floatunditf.c -- [ ] subtf3.c +- [x] subtf3.c - [x] truncdfhf2.c - [x] truncsfhf2.c - [x] trunctfdf2.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index f9eba6ee29ba6..a570524294603 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -543,9 +543,7 @@ mod c { ("__floatsitf", "floatsitf.c"), ("__floatunditf", "floatunditf.c"), ("__floatunsitf", "floatunsitf.c"), - ("__addtf3", "addtf3.c"), ("__multf3", "multf3.c"), - ("__subtf3", "subtf3.c"), ("__divtf3", "divtf3.c"), ("__powitf2", "powitf2.c"), ("__fe_getround", "fp_mode.c"), @@ -564,9 +562,7 @@ mod c { if target_arch == "mips64" { sources.extend(&[ ("__netf2", "comparetf2.c"), - ("__addtf3", "addtf3.c"), ("__multf3", "multf3.c"), - ("__subtf3", "subtf3.c"), ("__fixtfsi", "fixtfsi.c"), ("__floatsitf", "floatsitf.c"), ("__fixunstfsi", "fixunstfsi.c"), @@ -579,9 +575,7 @@ mod c { if target_arch == "loongarch64" { sources.extend(&[ ("__netf2", "comparetf2.c"), - ("__addtf3", "addtf3.c"), ("__multf3", "multf3.c"), - ("__subtf3", "subtf3.c"), ("__fixtfsi", "fixtfsi.c"), ("__floatsitf", "floatsitf.c"), ("__fixunstfsi", "fixunstfsi.c"), diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 909948ad29c53..fd151f77d8a09 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -203,6 +203,16 @@ intrinsics! { add(a, b) } + #[cfg(not(any(feature = "no-f16-f128", target_arch = "powerpc", target_arch = "powerpc64")))] + pub extern "C" fn __addtf3(a: f128, b: f128) -> f128 { + add(a, b) + } + + #[cfg(all(not(feature = "no-f16-f128"), any(target_arch = "powerpc", target_arch = "powerpc64")))] + pub extern "C" fn __addkf3(a: f128, b: f128) -> f128 { + add(a, b) + } + #[cfg(target_arch = "arm")] pub extern "C" fn __addsf3vfp(a: f32, b: f32) -> f32 { a + b diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index 64653ee25ff19..de33259d6406a 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -15,6 +15,18 @@ intrinsics! { __adddf3(a, f64::from_repr(b.repr() ^ f64::SIGN_MASK)) } + #[cfg(not(any(feature = "no-f16-f128", target_arch = "powerpc", target_arch = "powerpc64")))] + pub extern "C" fn __subtf3(a: f128, b: f128) -> f128 { + use crate::float::add::__addtf3; + __addtf3(a, f128::from_repr(b.repr() ^ f128::SIGN_MASK)) + } + + #[cfg(all(not(feature = "no-f16-f128"), any(target_arch = "powerpc", target_arch = "powerpc64")))] + pub extern "C" fn __subkf3(a: f128, b: f128) -> f128 { + use crate::float::add::__addkf3; + __addkf3(a, f128::from_repr(b.repr() ^ f128::SIGN_MASK)) + } + #[cfg(target_arch = "arm")] pub extern "C" fn __subsf3vfp(a: f32, b: f32) -> f32 { a - b diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 6ff3fde1705c2..6f771181a05df 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -33,3 +33,5 @@ no-asm = ["compiler_builtins/no-asm"] no-f16-f128 = ["compiler_builtins/no-f16-f128"] 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 = [] diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs new file mode 100644 index 0000000000000..f24dae3c664d3 --- /dev/null +++ b/library/compiler-builtins/testcrate/build.rs @@ -0,0 +1,27 @@ +use std::env; + +fn main() { + let target = env::var("TARGET").unwrap(); + + // These platforms do not have f128 symbols available in their system libraries, so + // skip related tests. + if target.starts_with("arm-") + || target.contains("apple-darwin") + || target.contains("windows-msvc") + // GCC and LLVM disagree on the ABI of `f16` and `f128` with MinGW. See + // . + || target.contains("windows-gnu") + // FIXME(llvm): There is an ABI incompatibility between GCC and Clang on 32-bit x86. + // See . + || target.starts_with("i686") + // 32-bit PowerPC gets code generated that Qemu cannot handle. See + // . + || target.starts_with("powerpc-") + // FIXME: We get different results from the builtin functions. See + // . + || target.starts_with("powerpc64-") + { + println!("cargo:warning=using apfloat fallback for f128"); + println!("cargo:rustc-cfg=feature=\"no-sys-f128\""); + } +} diff --git a/library/compiler-builtins/testcrate/tests/addsub.rs b/library/compiler-builtins/testcrate/tests/addsub.rs index 85250ac3d4896..d3e96d57de37c 100644 --- a/library/compiler-builtins/testcrate/tests/addsub.rs +++ b/library/compiler-builtins/testcrate/tests/addsub.rs @@ -1,6 +1,7 @@ #![allow(unused_macros)] +#![feature(f128)] +#![feature(f16)] -use core::ops::{Add, Sub}; use testcrate::*; macro_rules! sum { @@ -104,11 +105,24 @@ fn float_addsub() { sub::{__subdf3, __subsf3}, Float, }; + use core::ops::{Add, Sub}; float_sum!( f32, __addsf3, __subsf3, Single, all(); f64, __adddf3, __subdf3, Double, all(); ); + + #[cfg(not(feature = "no-f16-f128"))] + { + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + use compiler_builtins::float::{add::__addkf3 as __addtf3, sub::__subkf3 as __subtf3}; + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + use compiler_builtins::float::{add::__addtf3, sub::__subtf3}; + + float_sum!( + f128, __addtf3, __subtf3, Quad, not(feature = "no-sys-f128"); + ); + } } #[cfg(target_arch = "arm")] @@ -119,6 +133,7 @@ fn float_addsub_arm() { sub::{__subdf3vfp, __subsf3vfp}, Float, }; + use core::ops::{Add, Sub}; float_sum!( f32, __addsf3vfp, __subsf3vfp, Single, all(); From 191c1b88cde9ff8c34ffd7027aad1d7ae1c54bcd Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 10 May 2024 19:46:50 -0500 Subject: [PATCH 1225/4206] Implement `f128` multiplication --- library/compiler-builtins/README.md | 2 +- library/compiler-builtins/build.rs | 5 ----- library/compiler-builtins/src/float/mul.rs | 11 +++++++++++ .../compiler-builtins/testcrate/tests/mul.rs | 17 +++++++++++++++++ 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index c7241ec7c0fd0..1986c21c66924 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -249,7 +249,7 @@ These builtins are needed to support `f16` and `f128`, which are in the process - [ ] floatsitf.c - [ ] floatunditf.c - [ ] floatunsitf.c -- [ ] multf3.c +- [x] multf3.c - [ ] powitf2.c - [ ] ppc/fixtfdi.c - [ ] ppc/fixunstfdi.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index a570524294603..ec830ecb34b20 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -543,7 +543,6 @@ mod c { ("__floatsitf", "floatsitf.c"), ("__floatunditf", "floatunditf.c"), ("__floatunsitf", "floatunsitf.c"), - ("__multf3", "multf3.c"), ("__divtf3", "divtf3.c"), ("__powitf2", "powitf2.c"), ("__fe_getround", "fp_mode.c"), @@ -562,26 +561,22 @@ mod c { if target_arch == "mips64" { sources.extend(&[ ("__netf2", "comparetf2.c"), - ("__multf3", "multf3.c"), ("__fixtfsi", "fixtfsi.c"), ("__floatsitf", "floatsitf.c"), ("__fixunstfsi", "fixunstfsi.c"), ("__floatunsitf", "floatunsitf.c"), ("__fe_getround", "fp_mode.c"), - ("__divtf3", "divtf3.c"), ]); } if target_arch == "loongarch64" { sources.extend(&[ ("__netf2", "comparetf2.c"), - ("__multf3", "multf3.c"), ("__fixtfsi", "fixtfsi.c"), ("__floatsitf", "floatsitf.c"), ("__fixunstfsi", "fixunstfsi.c"), ("__floatunsitf", "floatunsitf.c"), ("__fe_getround", "fp_mode.c"), - ("__divtf3", "divtf3.c"), ]); } diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index 46c41d09f191d..9866b62804da9 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -199,6 +199,17 @@ intrinsics! { mul(a, b) } + #[cfg(not(any(feature = "no-f16-f128", target_arch = "powerpc", target_arch = "powerpc64")))] + pub extern "C" fn __multf3(a: f128, b: f128) -> f128 { + mul(a, b) + } + + + #[cfg(all(not(feature = "no-f16-f128"), any(target_arch = "powerpc", target_arch = "powerpc64")))] + pub extern "C" fn __mulkf3(a: f128, b: f128) -> f128 { + mul(a, b) + } + #[cfg(target_arch = "arm")] pub extern "C" fn __mulsf3vfp(a: f32, b: f32) -> f32 { a * b diff --git a/library/compiler-builtins/testcrate/tests/mul.rs b/library/compiler-builtins/testcrate/tests/mul.rs index 4fca2c13fa666..ffbe638644d1d 100644 --- a/library/compiler-builtins/testcrate/tests/mul.rs +++ b/library/compiler-builtins/testcrate/tests/mul.rs @@ -1,4 +1,6 @@ #![allow(unused_macros)] +#![feature(f128)] +#![feature(f16)] use testcrate::*; @@ -114,6 +116,21 @@ fn float_mul() { f32, __mulsf3, Single, all(); f64, __muldf3, Double, all(); ); + + #[cfg(not(feature = "no-f16-f128"))] + { + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + use compiler_builtins::float::mul::__mulkf3 as __multf3; + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + use compiler_builtins::float::mul::__multf3; + + float_mul!( + 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"))); + ); + } } #[cfg(target_arch = "arm")] From aaa52607489e964eafb369904f23246edd1ec402 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 11 May 2024 01:18:38 -0500 Subject: [PATCH 1226/4206] Implement `f128` comparison --- library/compiler-builtins/README.md | 2 +- library/compiler-builtins/src/float/cmp.rs | 83 +++++++++++++++++++ .../compiler-builtins/testcrate/tests/cmp.rs | 40 +++++++++ 3 files changed, 124 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 1986c21c66924..37d7ab2e6718d 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -233,7 +233,7 @@ These builtins are needed to support 128-bit integers. These builtins are needed to support `f16` and `f128`, which are in the process of being added to Rust. - [x] addtf3.c -- [ ] comparetf2.c +- [x] comparetf2.c - [ ] divtf3.c - [x] extenddftf2.c - [x] extendhfsf2.c diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 193c5df368c89..44ebf6262ea48 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -172,6 +172,89 @@ intrinsics! { } } +#[cfg(not(any( + feature = "no-f16-f128", + target_arch = "powerpc", + target_arch = "powerpc64" +)))] +intrinsics! { + #[avr_skip] + pub extern "C" fn __letf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + pub extern "C" fn __getf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_ge_abi() + } + + #[avr_skip] + pub extern "C" fn __unordtf2(a: f128, b: f128) -> i32 { + unord(a, b) as i32 + } + + #[avr_skip] + pub extern "C" fn __eqtf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + pub extern "C" fn __lttf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + pub extern "C" fn __netf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + pub extern "C" fn __gttf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_ge_abi() + } +} + +#[cfg(all( + not(feature = "no-f16-f128"), + any(target_arch = "powerpc", target_arch = "powerpc64") +))] +intrinsics! { + #[avr_skip] + pub extern "C" fn __lekf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + pub extern "C" fn __gekf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_ge_abi() + } + + #[avr_skip] + pub extern "C" fn __unordkf2(a: f128, b: f128) -> i32 { + unord(a, b) as i32 + } + + #[avr_skip] + pub extern "C" fn __eqkf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + pub extern "C" fn __ltkf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + pub extern "C" fn __nekf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_le_abi() + } + + #[avr_skip] + pub extern "C" fn __gtkf2(a: f128, b: f128) -> i32 { + cmp(a, b).to_ge_abi() + } +} + #[cfg(target_arch = "arm")] intrinsics! { pub extern "aapcs" fn __aeabi_fcmple(a: f32, b: f32) -> i32 { diff --git a/library/compiler-builtins/testcrate/tests/cmp.rs b/library/compiler-builtins/testcrate/tests/cmp.rs index 20915b25d1200..0d15f5d421f02 100644 --- a/library/compiler-builtins/testcrate/tests/cmp.rs +++ b/library/compiler-builtins/testcrate/tests/cmp.rs @@ -1,5 +1,7 @@ #![allow(unused_macros)] #![allow(unreachable_code)] +#![feature(f128)] +#![feature(f16)] #[cfg(not(target_arch = "powerpc64"))] use testcrate::*; @@ -79,6 +81,44 @@ fn float_comparisons() { 1, __nedf2; ); }); + + #[cfg(not(feature = "no-f16-f128"))] + { + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + use compiler_builtins::float::cmp::{ + __eqkf2 as __eqtf2, __gekf2 as __getf2, __gtkf2 as __gttf2, __lekf2 as __letf2, + __ltkf2 as __lttf2, __nekf2 as __netf2, __unordkf2 as __unordtf2, + }; + + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + use compiler_builtins::float::cmp::{ + __eqtf2, __getf2, __gttf2, __letf2, __lttf2, __netf2, __unordtf2, + }; + + fuzz_float_2(N, |x: f128, y: f128| { + let x_is_nan = apfloat_fallback!( + f128, Quad, not(feature = "no-sys-f128"), + |x: FloatTy| x.is_nan() => no_convert, + x + ); + let y_is_nan = apfloat_fallback!( + f128, Quad, not(feature = "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"), + 1, __lttf2; + 1, __letf2; + 1, __eqtf2; + -1, __getf2; + -1, __gttf2; + 1, __netf2; + ); + }); + } } macro_rules! cmp2 { From a82491ed5401386defb3335fcc82bfb37fbd41aa Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 12 May 2024 17:17:46 -0500 Subject: [PATCH 1227/4206] Correct f128 extend and truncate symbol names on powerpc PowerPC uses `kf` instead of `tf`: --- library/compiler-builtins/src/float/extend.rs | 18 ++++++++++++++++++ library/compiler-builtins/src/float/trunc.rs | 18 ++++++++++++++++++ .../compiler-builtins/testcrate/tests/conv.rs | 16 ++++++++++++++-- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index 5b0c0d9726844..12e5fc9e10f92 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -100,19 +100,37 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] pub extern "C" fn __extendhftf2(a: f16) -> f128 { extend(a) } + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + pub extern "C" fn __extendhfkf2(a: f16) -> f128 { + extend(a) + } + #[avr_skip] #[aapcs_on_arm] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] pub extern "C" fn __extendsftf2(a: f32) -> f128 { extend(a) } + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + pub extern "C" fn __extendsfkf2(a: f32) -> f128 { + extend(a) + } + #[avr_skip] #[aapcs_on_arm] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] pub extern "C" fn __extenddftf2(a: f64) -> f128 { extend(a) } + + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + pub extern "C" fn __extenddfkf2(a: f64) -> f128 { + extend(a) + } } diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index b607a65498347..31351b5e96970 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -155,19 +155,37 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] pub extern "C" fn __trunctfhf2(a: f128) -> f16 { trunc(a) } + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + pub extern "C" fn __trunckfhf2(a: f128) -> f16 { + trunc(a) + } + #[avr_skip] #[aapcs_on_arm] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] pub extern "C" fn __trunctfsf2(a: f128) -> f32 { trunc(a) } + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + pub extern "C" fn __trunckfsf2(a: f128) -> f32 { + trunc(a) + } + #[avr_skip] #[aapcs_on_arm] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] pub extern "C" fn __trunctfdf2(a: f128) -> f64 { trunc(a) } + + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + pub extern "C" fn __trunckfdf2(a: f128) -> f64 { + trunc(a) + } } diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 5cff01202a875..f0ef9525563af 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -187,9 +187,15 @@ fn float_extend() { conv!(f32, f64, __extendsfdf2, Single, Double); #[cfg(not(feature = "no-f16-f128"))] { + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] use compiler_builtins::float::extend::{ - __extenddftf2, __extendhfsf2, __extendhftf2, __extendsftf2, __gnu_h2f_ieee, + __extenddfkf2 as __extenddftf2, __extendhfkf2 as __extendhftf2, + __extendsfkf2 as __extendsftf2, }; + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + use compiler_builtins::float::extend::{__extenddftf2, __extendhftf2, __extendsftf2}; + use compiler_builtins::float::extend::{__extendhfsf2, __gnu_h2f_ieee}; + // FIXME(f16_f128): Also do extend!() for `f16` and `f128` when builtins are in nightly conv!(f16, f32, __extendhfsf2, Half, Single); conv!(f16, f32, __gnu_h2f_ieee, Half, Single); @@ -234,9 +240,15 @@ fn float_trunc() { conv!(f64, f32, __truncdfsf2, Double, Single); #[cfg(not(feature = "no-f16-f128"))] { + use compiler_builtins::float::trunc::{__gnu_f2h_ieee, __truncdfhf2, __truncsfhf2}; + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] use compiler_builtins::float::trunc::{ - __gnu_f2h_ieee, __truncdfhf2, __truncsfhf2, __trunctfdf2, __trunctfhf2, __trunctfsf2, + __trunckfdf2 as __trunctfdf2, __trunckfhf2 as __trunctfhf2, + __trunckfsf2 as __trunctfsf2, }; + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + use compiler_builtins::float::trunc::{__trunctfdf2, __trunctfhf2, __trunctfsf2}; + // FIXME(f16_f128): Also do trunc!() for `f16` and `f128` when builtins are in nightly conv!(f32, f16, __truncsfhf2, Single, Half); conv!(f32, f16, __gnu_f2h_ieee, Single, Half); From f82e1f14fc6f61dfcba3dd67fcb6bd40e6a40cda Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 18 May 2024 04:07:37 -0400 Subject: [PATCH 1228/4206] Rework the test crate to separate individual tests Currently, tests of the same kind are grouped together across all types into a single function. This makes it difficult to understand exactly what failed in CI. Change test macros to create separate functions for separate types so failures are more fine grained. --- .../testcrate/tests/addsub.rs | 226 ++++----- .../compiler-builtins/testcrate/tests/cmp.rs | 279 +++++------ .../compiler-builtins/testcrate/tests/conv.rs | 435 +++++++++++------- .../testcrate/tests/div_rem.rs | 70 ++- .../compiler-builtins/testcrate/tests/misc.rs | 71 +-- .../compiler-builtins/testcrate/tests/mul.rs | 238 +++++----- .../testcrate/tests/shift.rs | 52 +-- 7 files changed, 756 insertions(+), 615 deletions(-) diff --git a/library/compiler-builtins/testcrate/tests/addsub.rs b/library/compiler-builtins/testcrate/tests/addsub.rs index d3e96d57de37c..f21f61ff679a1 100644 --- a/library/compiler-builtins/testcrate/tests/addsub.rs +++ b/library/compiler-builtins/testcrate/tests/addsub.rs @@ -4,139 +4,149 @@ use testcrate::*; -macro_rules! sum { - ($($i:ty, $fn_add:ident, $fn_sub:ident);*;) => { - $( - fuzz_2(N, |x: $i, y: $i| { - let add0 = x.wrapping_add(y); - let sub0 = x.wrapping_sub(y); - let add1: $i = $fn_add(x, y); - let sub1: $i = $fn_sub(x, y); - if add0 != add1 { - panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn_add), x, y, add0, add1 - ); - } - if sub0 != sub1 { - panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn_sub), x, y, sub0, sub1 - ); - } - }); - )* - }; -} +mod int_addsub { + use super::*; -macro_rules! overflowing_sum { - ($($i:ty, $fn_add:ident, $fn_sub:ident);*;) => { - $( - fuzz_2(N, |x: $i, y: $i| { - let add0 = x.overflowing_add(y); - let sub0 = x.overflowing_sub(y); - let add1: ($i, bool) = $fn_add(x, y); - let sub1: ($i, bool) = $fn_sub(x, y); - if add0.0 != add1.0 || add0.1 != add1.1 { - panic!( - "{}({}, {}): std: {:?}, builtins: {:?}", - stringify!($fn_add), x, y, add0, add1 - ); - } - if sub0.0 != sub1.0 || sub0.1 != sub1.1 { - panic!( - "{}({}, {}): std: {:?}, builtins: {:?}", - stringify!($fn_sub), x, y, sub0, sub1 - ); + macro_rules! sum { + ($($i:ty, $fn_add:ident, $fn_sub:ident);*;) => { + $( + #[test] + fn $fn_add() { + use compiler_builtins::int::addsub::{$fn_add, $fn_sub}; + + fuzz_2(N, |x: $i, y: $i| { + let add0 = x.wrapping_add(y); + let sub0 = x.wrapping_sub(y); + let add1: $i = $fn_add(x, y); + let sub1: $i = $fn_sub(x, y); + if add0 != add1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn_add), x, y, add0, add1 + ); + } + if sub0 != sub1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn_sub), x, y, sub0, sub1 + ); + } + }); } - }); - )* - }; -} + )* + }; + } + + macro_rules! overflowing_sum { + ($($i:ty, $fn_add:ident, $fn_sub:ident);*;) => { + $( + #[test] + fn $fn_add() { + use compiler_builtins::int::addsub::{$fn_add, $fn_sub}; -#[test] -fn addsub() { - use compiler_builtins::int::addsub::{ - __rust_i128_add, __rust_i128_addo, __rust_i128_sub, __rust_i128_subo, __rust_u128_add, - __rust_u128_addo, __rust_u128_sub, __rust_u128_subo, - }; + fuzz_2(N, |x: $i, y: $i| { + let add0 = x.overflowing_add(y); + let sub0 = x.overflowing_sub(y); + let add1: ($i, bool) = $fn_add(x, y); + let sub1: ($i, bool) = $fn_sub(x, y); + if add0.0 != add1.0 || add0.1 != add1.1 { + panic!( + "{}({}, {}): std: {:?}, builtins: {:?}", + stringify!($fn_add), x, y, add0, add1 + ); + } + if sub0.0 != sub1.0 || sub0.1 != sub1.1 { + panic!( + "{}({}, {}): std: {:?}, builtins: {:?}", + stringify!($fn_sub), x, y, sub0, sub1 + ); + } + }); + } + )* + }; + } // Integer addition and subtraction is very simple, so 100 fuzzing passes should be plenty. - sum!( + sum! { u128, __rust_u128_add, __rust_u128_sub; i128, __rust_i128_add, __rust_i128_sub; - ); - overflowing_sum!( + } + + overflowing_sum! { u128, __rust_u128_addo, __rust_u128_subo; i128, __rust_i128_addo, __rust_i128_subo; - ); + } } macro_rules! float_sum { ($($f:ty, $fn_add:ident, $fn_sub:ident, $apfloat_ty:ident, $sys_available:meta);*;) => { $( - fuzz_float_2(N, |x: $f, y: $f| { - let add0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Add::add, x, y); - let sub0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Sub::sub, x, y); - let add1: $f = $fn_add(x, y); - let sub1: $f = $fn_sub(x, y); - if !Float::eq_repr(add0, add1) { - panic!( - "{}({:?}, {:?}): std: {:?}, builtins: {:?}", - stringify!($fn_add), x, y, add0, add1 - ); - } - if !Float::eq_repr(sub0, sub1) { - panic!( - "{}({:?}, {:?}): std: {:?}, builtins: {:?}", - stringify!($fn_sub), x, y, sub0, sub1 - ); - } - }); + #[test] + fn $fn_add() { + use core::ops::{Add, Sub}; + use compiler_builtins::float::{{add::$fn_add, sub::$fn_sub}, Float}; + + fuzz_float_2(N, |x: $f, y: $f| { + let add0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Add::add, x, y); + let sub0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Sub::sub, x, y); + let add1: $f = $fn_add(x, y); + let sub1: $f = $fn_sub(x, y); + if !Float::eq_repr(add0, add1) { + panic!( + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn_add), x, y, add0, add1 + ); + } + if !Float::eq_repr(sub0, sub1) { + panic!( + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn_sub), x, y, sub0, sub1 + ); + } + }); + } )* } } #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] -#[test] -fn float_addsub() { - use compiler_builtins::float::{ - add::{__adddf3, __addsf3}, - sub::{__subdf3, __subsf3}, - Float, - }; - use core::ops::{Add, Sub}; - - float_sum!( +mod float_addsub { + use super::*; + + float_sum! { f32, __addsf3, __subsf3, Single, all(); f64, __adddf3, __subdf3, Double, all(); - ); - - #[cfg(not(feature = "no-f16-f128"))] - { - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - use compiler_builtins::float::{add::__addkf3 as __addtf3, sub::__subkf3 as __subtf3}; - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] - use compiler_builtins::float::{add::__addtf3, sub::__subtf3}; - - float_sum!( - f128, __addtf3, __subtf3, Quad, not(feature = "no-sys-f128"); - ); + } +} + +#[cfg(not(feature = "no-f16-f128"))] +#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] +#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] +mod float_addsub_f128 { + use super::*; + + float_sum! { + f128, __addtf3, __subtf3, Quad, not(feature = "no-sys-f128"); + } +} + +#[cfg(not(feature = "no-f16-f128"))] +#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +mod float_addsub_f128_ppc { + use super::*; + + float_sum! { + f128, __addkf3, __subkf3, Quad, not(feature = "no-sys-f128"); } } #[cfg(target_arch = "arm")] -#[test] -fn float_addsub_arm() { - use compiler_builtins::float::{ - add::{__adddf3vfp, __addsf3vfp}, - sub::{__subdf3vfp, __subsf3vfp}, - Float, - }; - use core::ops::{Add, Sub}; - - float_sum!( +mod float_addsub_arm { + use super::*; + + float_sum! { f32, __addsf3vfp, __subsf3vfp, Single, all(); f64, __adddf3vfp, __subdf3vfp, Double, all(); - ); + } } diff --git a/library/compiler-builtins/testcrate/tests/cmp.rs b/library/compiler-builtins/testcrate/tests/cmp.rs index 0d15f5d421f02..e8a0eb165c3fd 100644 --- a/library/compiler-builtins/testcrate/tests/cmp.rs +++ b/library/compiler-builtins/testcrate/tests/cmp.rs @@ -6,84 +6,96 @@ #[cfg(not(target_arch = "powerpc64"))] use testcrate::*; -macro_rules! cmp { - ( - $f:ty, $x:ident, $y:ident, $apfloat_ty:ident, $sys_available:meta, - $($unordered_val:expr, $fn:ident);*; - ) => { - $( - let cmp0 = if apfloat_fallback!( +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +mod float_comparisons { + use super::*; + + macro_rules! cmp { + ( + $f:ty, $x:ident, $y:ident, $apfloat_ty:ident, $sys_available:meta, + $($unordered_val:expr, $fn:ident);*; + ) => { + $( + let cmp0 = if apfloat_fallback!( + $f, $apfloat_ty, $sys_available, + |x: FloatTy| x.is_nan() => no_convert, + $x + ) || apfloat_fallback!( + $f, $apfloat_ty, $sys_available, + |y: FloatTy| y.is_nan() => no_convert, + $y + ) + { + $unordered_val + } else if apfloat_fallback!( $f, $apfloat_ty, $sys_available, - |x: FloatTy| x.is_nan() => no_convert, - $x - ) || apfloat_fallback!( + |x, y| x < y => no_convert, + $x, $y + ) { + -1 + } else if apfloat_fallback!( $f, $apfloat_ty, $sys_available, - |y: FloatTy| y.is_nan() => no_convert, - $y - ) - { - $unordered_val - } else if apfloat_fallback!( - $f, $apfloat_ty, $sys_available, - |x, y| x < y => no_convert, - $x, $y - ) { - -1 - } else if apfloat_fallback!( - $f, $apfloat_ty, $sys_available, - |x, y| x == y => no_convert, - $x, $y - ) { - 0 - } else { - 1 - }; - - let cmp1 = $fn($x, $y); - if cmp0 != cmp1 { - panic!( - "{}({:?}, {:?}): std: {:?}, builtins: {:?}", - stringify!($fn), $x, $y, cmp0, cmp1 - ); - } - )* - }; -} + |x, y| x == y => no_convert, + $x, $y + ) { + 0 + } else { + 1 + }; -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[test] -fn float_comparisons() { - use compiler_builtins::float::cmp::{ - __eqdf2, __eqsf2, __gedf2, __gesf2, __gtdf2, __gtsf2, __ledf2, __lesf2, __ltdf2, __ltsf2, - __nedf2, __nesf2, __unorddf2, __unordsf2, - }; - - fuzz_float_2(N, |x: f32, y: f32| { - assert_eq!(__unordsf2(x, y) != 0, x.is_nan() || y.is_nan()); - cmp!(f32, x, y, Single, all(), - 1, __ltsf2; - 1, __lesf2; - 1, __eqsf2; - -1, __gesf2; - -1, __gtsf2; - 1, __nesf2; - ); - }); - fuzz_float_2(N, |x: f64, y: f64| { - assert_eq!(__unorddf2(x, y) != 0, x.is_nan() || y.is_nan()); - cmp!(f64, x, y, Double, all(), - 1, __ltdf2; - 1, __ledf2; - 1, __eqdf2; - -1, __gedf2; - -1, __gtdf2; - 1, __nedf2; - ); - }); + let cmp1 = $fn($x, $y); + if cmp0 != cmp1 { + panic!( + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn), $x, $y, cmp0, cmp1 + ); + } + )* + }; + } + + #[test] + fn cmp_f32() { + use compiler_builtins::float::cmp::{ + __eqsf2, __gesf2, __gtsf2, __lesf2, __ltsf2, __nesf2, __unordsf2, + }; + fuzz_float_2(N, |x: f32, y: f32| { + assert_eq!(__unordsf2(x, y) != 0, x.is_nan() || y.is_nan()); + cmp!(f32, x, y, Single, all(), + 1, __ltsf2; + 1, __lesf2; + 1, __eqsf2; + -1, __gesf2; + -1, __gtsf2; + 1, __nesf2; + ); + }); + } + + #[test] + fn cmp_f64() { + use compiler_builtins::float::cmp::{ + __eqdf2, __gedf2, __gtdf2, __ledf2, __ltdf2, __nedf2, __unorddf2, + }; + + fuzz_float_2(N, |x: f64, y: f64| { + assert_eq!(__unorddf2(x, y) != 0, x.is_nan() || y.is_nan()); + cmp!(f64, x, y, Double, all(), + 1, __ltdf2; + 1, __ledf2; + 1, __eqdf2; + -1, __gedf2; + -1, __gtdf2; + 1, __nedf2; + ); + }); + } + + #[test] #[cfg(not(feature = "no-f16-f128"))] - { + fn cmp_f128() { #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] use compiler_builtins::float::cmp::{ __eqkf2 as __eqtf2, __gekf2 as __getf2, __gtkf2 as __gttf2, __lekf2 as __letf2, @@ -121,60 +133,71 @@ fn float_comparisons() { } } -macro_rules! cmp2 { - ($x:ident, $y:ident, $($unordered_val:expr, $fn_std:expr, $fn_builtins:ident);*;) => { - $( - let cmp0: i32 = if $x.is_nan() || $y.is_nan() { - $unordered_val - } else { - $fn_std as i32 - }; - let cmp1: i32 = $fn_builtins($x, $y); - if cmp0 != cmp1 { - panic!("{}({}, {}): std: {}, builtins: {}", stringify!($fn_builtins), $x, $y, cmp0, cmp1); - } - )* - }; -} - #[cfg(target_arch = "arm")] -#[test] -fn float_comparisons_arm() { - use compiler_builtins::float::cmp::{ - __aeabi_dcmpeq, __aeabi_dcmpge, __aeabi_dcmpgt, __aeabi_dcmple, __aeabi_dcmplt, - __aeabi_fcmpeq, __aeabi_fcmpge, __aeabi_fcmpgt, __aeabi_fcmple, __aeabi_fcmplt, __eqdf2vfp, - __eqsf2vfp, __gedf2vfp, __gesf2vfp, __gtdf2vfp, __gtsf2vfp, __ledf2vfp, __lesf2vfp, - __ltdf2vfp, __ltsf2vfp, __nedf2vfp, __nesf2vfp, - }; - - fuzz_float_2(N, |x: f32, y: f32| { - cmp2!(x, y, - 0, x < y, __aeabi_fcmplt; - 0, x <= y, __aeabi_fcmple; - 0, x == y, __aeabi_fcmpeq; - 0, x >= y, __aeabi_fcmpge; - 0, x > y, __aeabi_fcmpgt; - 0, x < y, __ltsf2vfp; - 0, x <= y, __lesf2vfp; - 0, x == y, __eqsf2vfp; - 0, x >= y, __gesf2vfp; - 0, x > y, __gtsf2vfp; - 1, x != y, __nesf2vfp; - ); - }); - fuzz_float_2(N, |x: f64, y: f64| { - cmp2!(x, y, - 0, x < y, __aeabi_dcmplt; - 0, x <= y, __aeabi_dcmple; - 0, x == y, __aeabi_dcmpeq; - 0, x >= y, __aeabi_dcmpge; - 0, x > y, __aeabi_dcmpgt; - 0, x < y, __ltdf2vfp; - 0, x <= y, __ledf2vfp; - 0, x == y, __eqdf2vfp; - 0, x >= y, __gedf2vfp; - 0, x > y, __gtdf2vfp; - 1, x != y, __nedf2vfp; - ); - }); +mod float_comparisons_arm { + use super::*; + + macro_rules! cmp2 { + ($x:ident, $y:ident, $($unordered_val:expr, $fn_std:expr, $fn_builtins:ident);*;) => { + $( + let cmp0: i32 = if $x.is_nan() || $y.is_nan() { + $unordered_val + } else { + $fn_std as i32 + }; + let cmp1: i32 = $fn_builtins($x, $y); + if cmp0 != cmp1 { + panic!("{}({}, {}): std: {}, builtins: {}", stringify!($fn_builtins), $x, $y, cmp0, cmp1); + } + )* + }; + } + + #[test] + fn cmp_f32() { + use compiler_builtins::float::cmp::{ + __aeabi_fcmpeq, __aeabi_fcmpge, __aeabi_fcmpgt, __aeabi_fcmple, __aeabi_fcmplt, + __eqsf2vfp, __gesf2vfp, __gtsf2vfp, __lesf2vfp, __ltsf2vfp, __nesf2vfp, + }; + + fuzz_float_2(N, |x: f32, y: f32| { + cmp2!(x, y, + 0, x < y, __aeabi_fcmplt; + 0, x <= y, __aeabi_fcmple; + 0, x == y, __aeabi_fcmpeq; + 0, x >= y, __aeabi_fcmpge; + 0, x > y, __aeabi_fcmpgt; + 0, x < y, __ltsf2vfp; + 0, x <= y, __lesf2vfp; + 0, x == y, __eqsf2vfp; + 0, x >= y, __gesf2vfp; + 0, x > y, __gtsf2vfp; + 1, x != y, __nesf2vfp; + ); + }); + } + + #[test] + fn cmp_f64() { + use compiler_builtins::float::cmp::{ + __aeabi_dcmpeq, __aeabi_dcmpge, __aeabi_dcmpgt, __aeabi_dcmple, __aeabi_dcmplt, + __eqdf2vfp, __gedf2vfp, __gtdf2vfp, __ledf2vfp, __ltdf2vfp, __nedf2vfp, + }; + + fuzz_float_2(N, |x: f64, y: f64| { + cmp2!(x, y, + 0, x < y, __aeabi_dcmplt; + 0, x <= y, __aeabi_dcmple; + 0, x == y, __aeabi_dcmpeq; + 0, x >= y, __aeabi_dcmpge; + 0, x > y, __aeabi_dcmpgt; + 0, x < y, __ltdf2vfp; + 0, x <= y, __ledf2vfp; + 0, x == y, __eqdf2vfp; + 0, x >= y, __gedf2vfp; + 0, x > y, __gtdf2vfp; + 1, x != y, __nedf2vfp; + ); + }); + } } diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index f0ef9525563af..7b672ac251e5d 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -2,84 +2,83 @@ #![cfg_attr(not(feature = "no-f16-f128"), feature(f128))] // makes configuration easier #![allow(unused_macros)] +#![allow(unused_imports)] use compiler_builtins::float::Float; -use rustc_apfloat::ieee::{Double, Single}; -#[cfg(not(feature = "no-f16-f128"))] -use rustc_apfloat::ieee::{Half, Quad}; use rustc_apfloat::{Float as _, FloatConvert as _}; use testcrate::*; -macro_rules! i_to_f { - ($($from:ty, $into:ty, $fn:ident);*;) => { - $( - fuzz(N, |x: $from| { - let f0 = x as $into; - let f1: $into = $fn(x); - // This makes sure that the conversion produced the best rounding possible, and does - // this independent of `x as $into` rounding correctly. - // This assumes that float to integer conversion is correct. - let y_minus_ulp = <$into>::from_bits(f1.to_bits().wrapping_sub(1)) as $from; - let y = f1 as $from; - let y_plus_ulp = <$into>::from_bits(f1.to_bits().wrapping_add(1)) as $from; - let error_minus = <$from as Int>::abs_diff(y_minus_ulp, x); - let error = <$from as Int>::abs_diff(y, x); - let error_plus = <$from as Int>::abs_diff(y_plus_ulp, x); - // The first two conditions check that none of the two closest float values are - // strictly closer in representation to `x`. The second makes sure that rounding is - // towards even significand if two float values are equally close to the integer. - if error_minus < error - || error_plus < error - || ((error_minus == error || error_plus == error) - && ((f0.to_bits() & 1) != 0)) - { - if !cfg!(any( - target_arch = "powerpc", - target_arch = "powerpc64" - )) { - panic!( - "incorrect rounding by {}({}): {}, ({}, {}, {}), errors ({}, {}, {})", - stringify!($fn), - x, - f1.to_bits(), - y_minus_ulp, - y, - y_plus_ulp, - error_minus, - error, - error_plus, - ); - } - } - // Test against native conversion. We disable testing on all `x86` because of - // rounding bugs with `i686`. `powerpc` also has the same rounding bug. - if f0 != f1 && !cfg!(any( - target_arch = "x86", - target_arch = "powerpc", - target_arch = "powerpc64" - )) { - panic!( - "{}({}): std: {}, builtins: {}", - stringify!($fn), - x, - f0, - f1, - ); - } - }); - )* - }; -} +mod int_to_float { + use super::*; -#[test] -fn int_to_float() { - use compiler_builtins::float::conv::{ - __floatdidf, __floatdisf, __floatsidf, __floatsisf, __floattidf, __floattisf, - __floatundidf, __floatundisf, __floatunsidf, __floatunsisf, __floatuntidf, __floatuntisf, - }; - use compiler_builtins::int::Int; + macro_rules! i_to_f { + ($($from:ty, $into:ty, $fn:ident);*;) => { + $( + #[test] + fn $fn() { + use compiler_builtins::float::conv::$fn; + use compiler_builtins::int::Int; - i_to_f!( + fuzz(N, |x: $from| { + let f0 = x as $into; + let f1: $into = $fn(x); + // This makes sure that the conversion produced the best rounding possible, and does + // this independent of `x as $into` rounding correctly. + // This assumes that float to integer conversion is correct. + let y_minus_ulp = <$into>::from_bits(f1.to_bits().wrapping_sub(1)) as $from; + let y = f1 as $from; + let y_plus_ulp = <$into>::from_bits(f1.to_bits().wrapping_add(1)) as $from; + let error_minus = <$from as Int>::abs_diff(y_minus_ulp, x); + let error = <$from as Int>::abs_diff(y, x); + let error_plus = <$from as Int>::abs_diff(y_plus_ulp, x); + // The first two conditions check that none of the two closest float values are + // strictly closer in representation to `x`. The second makes sure that rounding is + // towards even significand if two float values are equally close to the integer. + if error_minus < error + || error_plus < error + || ((error_minus == error || error_plus == error) + && ((f0.to_bits() & 1) != 0)) + { + if !cfg!(any( + target_arch = "powerpc", + target_arch = "powerpc64" + )) { + panic!( + "incorrect rounding by {}({}): {}, ({}, {}, {}), errors ({}, {}, {})", + stringify!($fn), + x, + f1.to_bits(), + y_minus_ulp, + y, + y_plus_ulp, + error_minus, + error, + error_plus, + ); + } + } + // Test against native conversion. We disable testing on all `x86` because of + // rounding bugs with `i686`. `powerpc` also has the same rounding bug. + if f0 != f1 && !cfg!(any( + target_arch = "x86", + target_arch = "powerpc", + target_arch = "powerpc64" + )) { + panic!( + "{}({}): std: {}, builtins: {}", + stringify!($fn), + x, + f0, + f1, + ); + } + }); + } + )* + }; + } + + i_to_f! { u32, f32, __floatunsisf; u32, f64, __floatunsidf; i32, f32, __floatsisf; @@ -92,53 +91,64 @@ fn int_to_float() { u128, f64, __floatuntidf; i128, f32, __floattisf; i128, f64, __floattidf; - ); -} - -macro_rules! f_to_i { - ($x:ident, $($f:ty, $fn:ident);*;) => { - $( - // it is undefined behavior in the first place to do conversions with NaNs - if !$x.is_nan() { - let conv0 = $x as $f; - let conv1: $f = $fn($x); - if conv0 != conv1 { - panic!("{}({}): std: {}, builtins: {}", stringify!($fn), $x, conv0, conv1); - } - } - )* - }; + } } // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 #[cfg(not(target_arch = "powerpc64"))] -#[test] -fn float_to_int() { - use compiler_builtins::float::conv::{ - __fixdfdi, __fixdfsi, __fixdfti, __fixsfdi, __fixsfsi, __fixsfti, __fixunsdfdi, - __fixunsdfsi, __fixunsdfti, __fixunssfdi, __fixunssfsi, __fixunssfti, - }; +mod f_to_i { + use super::*; + + macro_rules! f_to_i { + ($x:ident, $($f:ty, $fn:ident);*;) => { + $( + // it is undefined behavior in the first place to do conversions with NaNs + if !$x.is_nan() { + let conv0 = $x as $f; + let conv1: $f = $fn($x); + if conv0 != conv1 { + panic!("{}({}): std: {}, builtins: {}", stringify!($fn), $x, conv0, conv1); + } + } + )* + }; + } - fuzz_float(N, |x: f32| { - f_to_i!(x, - u32, __fixunssfsi; - u64, __fixunssfdi; - u128, __fixunssfti; - i32, __fixsfsi; - i64, __fixsfdi; - i128, __fixsfti; - ); - }); - fuzz_float(N, |x: f64| { - f_to_i!(x, - u32, __fixunsdfsi; - u64, __fixunsdfdi; - u128, __fixunsdfti; - i32, __fixdfsi; - i64, __fixdfdi; - i128, __fixdfti; - ); - }); + #[test] + fn f32_to_int() { + use compiler_builtins::float::conv::{ + __fixsfdi, __fixsfsi, __fixsfti, __fixunssfdi, __fixunssfsi, __fixunssfti, + }; + + fuzz_float(N, |x: f32| { + f_to_i!(x, + u32, __fixunssfsi; + u64, __fixunssfdi; + u128, __fixunssfti; + i32, __fixsfsi; + i64, __fixsfdi; + i128, __fixsfti; + ); + }); + } + + #[test] + fn f64_to_int() { + use compiler_builtins::float::conv::{ + __fixdfdi, __fixdfsi, __fixdfti, __fixunsdfdi, __fixunsdfsi, __fixunsdfti, + }; + + fuzz_float(N, |x: f64| { + f_to_i!(x, + u32, __fixunsdfsi; + u64, __fixunsdfdi; + u128, __fixunsdfti; + i32, __fixdfsi; + i64, __fixdfdi; + i128, __fixdfti; + ); + }); + } } macro_rules! conv { @@ -161,40 +171,54 @@ macro_rules! conv { macro_rules! extend { ($fX:ident, $fD:ident, $fn:ident) => { - fuzz_float(N, |x: $fX| { - let tmp0 = x as $fD; - let tmp1: $fD = $fn(x); - if !Float::eq_repr(tmp0, tmp1) { - panic!( - "{}({}): std: {}, builtins: {}", - stringify!($fn), - x, - tmp0, - tmp1 - ); - } - }); + #[test] + fn $fn() { + use compiler_builtins::float::extend::$fn; + + fuzz_float(N, |x: $fX| { + let tmp0 = x as $fD; + let tmp1: $fD = $fn(x); + if !Float::eq_repr(tmp0, tmp1) { + panic!( + "{}({}): std: {}, builtins: {}", + stringify!($fn), + x, + tmp0, + tmp1 + ); + } + }); + } }; } // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 #[cfg(not(target_arch = "powerpc64"))] -#[test] -fn float_extend() { - use compiler_builtins::float::extend::__extendsfdf2; +mod float_extend { + use super::*; extend!(f32, f64, __extendsfdf2); - conv!(f32, f64, __extendsfdf2, Single, Double); - #[cfg(not(feature = "no-f16-f128"))] - { - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + + #[test] + fn conv() { + use compiler_builtins::float::extend::__extendsfdf2; + use rustc_apfloat::ieee::{Double, Single}; + + conv!(f32, f64, __extendsfdf2, Single, Double); + } +} + +#[cfg(not(feature = "no-f16-f128"))] +#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] +mod float_extend_f128 { + use super::*; + + #[test] + fn conv() { use compiler_builtins::float::extend::{ - __extenddfkf2 as __extenddftf2, __extendhfkf2 as __extendhftf2, - __extendsfkf2 as __extendsftf2, + __extenddftf2, __extendhfsf2, __extendhftf2, __extendsftf2, __gnu_h2f_ieee, }; - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] - use compiler_builtins::float::extend::{__extenddftf2, __extendhftf2, __extendsftf2}; - use compiler_builtins::float::extend::{__extendhfsf2, __gnu_h2f_ieee}; + use rustc_apfloat::ieee::{Double, Half, Quad, Single}; // FIXME(f16_f128): Also do extend!() for `f16` and `f128` when builtins are in nightly conv!(f16, f32, __extendhfsf2, Half, Single); @@ -205,49 +229,91 @@ fn float_extend() { } } +#[cfg(not(feature = "no-f16-f128"))] +#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +mod float_extend_f128_ppc { + use super::*; + + #[test] + fn conv() { + use compiler_builtins::float::extend::{ + __extenddfkf2, __extendhfkf2, __extendhfsf2, __extendsfkf2, __gnu_h2f_ieee, + }; + use rustc_apfloat::ieee::{Double, Half, Quad, Single}; + + // FIXME(f16_f128): Also do extend!() for `f16` and `f128` when builtins are in nightly + conv!(f16, f32, __extendhfsf2, Half, Single); + conv!(f16, f32, __gnu_h2f_ieee, Half, Single); + conv!(f16, f128, __extendhfkf2, Half, Quad); + conv!(f32, f128, __extendsfkf2, Single, Quad); + conv!(f64, f128, __extenddfkf2, Double, Quad); + } +} + #[cfg(target_arch = "arm")] -#[test] -fn float_extend_arm() { - use compiler_builtins::float::extend::__extendsfdf2vfp; +mod float_extend_arm { + use super::*; extend!(f32, f64, __extendsfdf2vfp); - conv!(f32, f64, __extendsfdf2vfp, Single, Double); + + #[test] + fn conv() { + use compiler_builtins::float::extend::__extendsfdf2vfp; + use rustc_apfloat::ieee::{Double, Single}; + + conv!(f32, f64, __extendsfdf2vfp, Single, Double); + } } macro_rules! trunc { ($fX:ident, $fD:ident, $fn:ident) => { - fuzz_float(N, |x: $fX| { - let tmp0 = x as $fD; - let tmp1: $fD = $fn(x); - if !Float::eq_repr(tmp0, tmp1) { - panic!( - "{}({}): std: {}, builtins: {}", - stringify!($fn), - x, - tmp0, - tmp1 - ); - } - }); + #[test] + fn $fn() { + use compiler_builtins::float::trunc::$fn; + + fuzz_float(N, |x: $fX| { + let tmp0 = x as $fD; + let tmp1: $fD = $fn(x); + if !Float::eq_repr(tmp0, tmp1) { + panic!( + "{}({}): std: {}, builtins: {}", + stringify!($fn), + x, + tmp0, + tmp1 + ); + } + }); + } }; } -#[test] -fn float_trunc() { - use compiler_builtins::float::trunc::__truncdfsf2; +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +mod float_trunc { + use super::*; trunc!(f64, f32, __truncdfsf2); - conv!(f64, f32, __truncdfsf2, Double, Single); - #[cfg(not(feature = "no-f16-f128"))] - { + + #[test] + fn conv() { + use compiler_builtins::float::trunc::__truncdfsf2; + use rustc_apfloat::ieee::{Double, Single}; + + conv!(f64, f32, __truncdfsf2, Double, Single); + } +} + +#[cfg(not(feature = "no-f16-f128"))] +#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] +mod float_trunc_f128 { + use super::*; + + #[test] + fn conv() { use compiler_builtins::float::trunc::{__gnu_f2h_ieee, __truncdfhf2, __truncsfhf2}; - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - use compiler_builtins::float::trunc::{ - __trunckfdf2 as __trunctfdf2, __trunckfhf2 as __trunctfhf2, - __trunckfsf2 as __trunctfsf2, - }; - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] use compiler_builtins::float::trunc::{__trunctfdf2, __trunctfhf2, __trunctfsf2}; + use rustc_apfloat::ieee::{Double, Half, Quad, Single}; // FIXME(f16_f128): Also do trunc!() for `f16` and `f128` when builtins are in nightly conv!(f32, f16, __truncsfhf2, Single, Half); @@ -259,11 +325,38 @@ fn float_trunc() { } } +#[cfg(not(feature = "no-f16-f128"))] +#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +mod float_trunc_f128_ppc { + use super::*; + + #[test] + fn conv() { + use compiler_builtins::float::trunc::{__gnu_f2h_ieee, __truncdfhf2, __truncsfhf2}; + use compiler_builtins::float::trunc::{__trunckfdf2, __trunckfhf2, __trunckfsf2}; + use rustc_apfloat::ieee::{Double, Half, Quad, Single}; + + // FIXME(f16_f128): Also do trunc!() for `f16` and `f128` when builtins are in nightly + conv!(f32, f16, __truncsfhf2, Single, Half); + conv!(f32, f16, __gnu_f2h_ieee, Single, Half); + conv!(f64, f16, __truncdfhf2, Double, Half); + conv!(f128, f16, __trunckfhf2, Quad, Half); + conv!(f128, f32, __trunckfsf2, Quad, Single); + conv!(f128, f64, __trunckfdf2, Quad, Double); + } +} + #[cfg(target_arch = "arm")] -#[test] -fn float_trunc_arm() { - use compiler_builtins::float::trunc::__truncdfsf2vfp; +mod float_trunc_arm { + use super::*; trunc!(f64, f32, __truncdfsf2vfp); - conv!(f64, f32, __truncdfsf2vfp, Double, Single) + + #[test] + fn conv() { + use compiler_builtins::float::trunc::__truncdfsf2vfp; + use rustc_apfloat::ieee::{Double, Single}; + + conv!(f64, f32, __truncdfsf2vfp, Double, Single) + } } diff --git a/library/compiler-builtins/testcrate/tests/div_rem.rs b/library/compiler-builtins/testcrate/tests/div_rem.rs index 461e084d068fa..ff78b4f54d548 100644 --- a/library/compiler-builtins/testcrate/tests/div_rem.rs +++ b/library/compiler-builtins/testcrate/tests/div_rem.rs @@ -107,24 +107,15 @@ fn divide_sparc() { macro_rules! float { ($($f:ty, $fn:ident, $apfloat_ty:ident, $sys_available:meta);*;) => { $( - fuzz_float_2(N, |x: $f, y: $f| { - let quo0: $f = apfloat_fallback!($f, $apfloat_ty, $sys_available, Div::div, x, y); - let quo1: $f = $fn(x, y); - #[cfg(not(target_arch = "arm"))] - if !Float::eq_repr(quo0, quo1) { - panic!( - "{}({:?}, {:?}): std: {:?}, builtins: {:?}", - stringify!($fn), - x, - y, - quo0, - quo1 - ); - } + #[test] + fn $fn() { + use compiler_builtins::float::{div::$fn, Float}; + use core::ops::Div; - // ARM SIMD instructions always flush subnormals to zero - #[cfg(target_arch = "arm")] - if !(Float::is_subnormal(quo0) || Float::is_subnormal(quo1)) { + fuzz_float_2(N, |x: $f, y: $f| { + let quo0: $f = apfloat_fallback!($f, $apfloat_ty, $sys_available, Div::div, x, y); + let quo1: $f = $fn(x, y); + #[cfg(not(target_arch = "arm"))] if !Float::eq_repr(quo0, quo1) { panic!( "{}({:?}, {:?}): std: {:?}, builtins: {:?}", @@ -135,38 +126,43 @@ macro_rules! float { quo1 ); } - } - }); + + // ARM SIMD instructions always flush subnormals to zero + #[cfg(target_arch = "arm")] + if !(Float::is_subnormal(quo0) || Float::is_subnormal(quo1)) { + if !Float::eq_repr(quo0, quo1) { + panic!( + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn), + x, + y, + quo0, + quo1 + ); + } + } + }); + } )* }; } #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] -#[test] -fn float_div() { - use compiler_builtins::float::{ - div::{__divdf3, __divsf3}, - Float, - }; - use core::ops::Div; +mod float_div { + use super::*; - float!( + float! { f32, __divsf3, Single, all(); f64, __divdf3, Double, all(); - ); + } } #[cfg(target_arch = "arm")] -#[test] -fn float_div_arm() { - use compiler_builtins::float::{ - div::{__divdf3vfp, __divsf3vfp}, - Float, - }; - use core::ops::Div; +mod float_div_arm { + use super::*; - float!( + float! { f32, __divsf3vfp, Single, all(); f64, __divdf3vfp, Double, all(); - ); + } } diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index cdc37e2a0d7e3..e01223c74848b 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -98,49 +98,52 @@ fn leading_zeros() { macro_rules! pow { ($($f:ty, $tolerance:expr, $fn:ident);*;) => { $( - 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>::SIGNIFICAND_MASK; - let n = (n as <$f as Float>::SignedInt) >> <$f as Float>::SIGNIFICAND_BITS; - let n = n as i32; - let tmp0: $f = x.powi(n); - let tmp1: $f = $fn(x, n); - let (a, b) = if tmp0 < tmp1 { - (tmp0, tmp1) - } else { - (tmp1, tmp0) - }; - let good = { - if a == b { - // handles infinity equality - true - } else if a < $tolerance { - b < $tolerance + #[test] + fn $fn() { + use compiler_builtins::float::pow::$fn; + use compiler_builtins::float::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>::SIGNIFICAND_MASK; + let n = (n as <$f as Float>::SignedInt) >> <$f as Float>::SIGNIFICAND_BITS; + let n = n as i32; + let tmp0: $f = x.powi(n); + let tmp1: $f = $fn(x, n); + let (a, b) = if tmp0 < tmp1 { + (tmp0, tmp1) } else { - let quo = b / a; - (quo < (1. + $tolerance)) && (quo > (1. - $tolerance)) + (tmp1, tmp0) + }; + let good = { + if a == b { + // handles infinity equality + true + } else if a < $tolerance { + b < $tolerance + } else { + let quo = b / a; + (quo < (1. + $tolerance)) && (quo > (1. - $tolerance)) + } + }; + if !good { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn), x, n, tmp0, tmp1 + ); } - }; - if !good { - panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn), x, n, tmp0, tmp1 - ); } - } - }); + }); + } )* }; } #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] -#[test] -fn float_pow() { - use compiler_builtins::float::pow::{__powidf2, __powisf2}; - use compiler_builtins::float::Float; +mod float_pow { + use super::*; - pow!( + pow! { f32, 1e-4, __powisf2; f64, 1e-12, __powidf2; - ); + } } diff --git a/library/compiler-builtins/testcrate/tests/mul.rs b/library/compiler-builtins/testcrate/tests/mul.rs index ffbe638644d1d..5daeadeb22bd6 100644 --- a/library/compiler-builtins/testcrate/tests/mul.rs +++ b/library/compiler-builtins/testcrate/tests/mul.rs @@ -4,146 +4,164 @@ use testcrate::*; -macro_rules! mul { - ($($i:ty, $fn:ident);*;) => { - $( - fuzz_2(N, |x: $i, y: $i| { - let mul0 = x.wrapping_mul(y); - let mul1: $i = $fn(x, y); - if mul0 != mul1 { - panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn), x, y, mul0, mul1 - ); - } - }); - )* - }; -} +mod int_mul { + use super::*; -#[test] -fn mul() { - use compiler_builtins::int::mul::{__muldi3, __multi3}; + macro_rules! mul { + ($($i:ty, $fn:ident);*;) => { + $( + #[test] + fn $fn() { + use compiler_builtins::int::mul::$fn; - mul!( + fuzz_2(N, |x: $i, y: $i| { + let mul0 = x.wrapping_mul(y); + let mul1: $i = $fn(x, y); + if mul0 != mul1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn), x, y, mul0, mul1 + ); + } + }); + + } + )* + }; + } + + mul! { u64, __muldi3; i128, __multi3; - ); + } } -macro_rules! overflowing_mul { - ($($i:ty, $fn:ident);*;) => { - $( - fuzz_2(N, |x: $i, y: $i| { - let (mul0, o0) = x.overflowing_mul(y); - let mut o1 = 0i32; - let mul1: $i = $fn(x, y, &mut o1); - let o1 = o1 != 0; - if mul0 != mul1 || o0 != o1 { - panic!( - "{}({}, {}): std: ({}, {}), builtins: ({}, {})", - stringify!($fn), x, y, mul0, o0, mul1, o1 - ); - } - }); - )* - }; -} +mod int_overflowing_mul { + use super::*; -#[test] -fn overflowing_mul() { - use compiler_builtins::int::mul::{ - __mulodi4, __mulosi4, __muloti4, __rust_i128_mulo, __rust_u128_mulo, - }; + macro_rules! overflowing_mul { + ($($i:ty, $fn:ident);*;) => { + $( + #[test] + fn $fn() { + use compiler_builtins::int::mul::$fn; + + fuzz_2(N, |x: $i, y: $i| { + let (mul0, o0) = x.overflowing_mul(y); + let mut o1 = 0i32; + let mul1: $i = $fn(x, y, &mut o1); + let o1 = o1 != 0; + if mul0 != mul1 || o0 != o1 { + panic!( + "{}({}, {}): std: ({}, {}), builtins: ({}, {})", + stringify!($fn), x, y, mul0, o0, mul1, o1 + ); + } + }); + } + )* + }; + } - overflowing_mul!( + overflowing_mul! { i32, __mulosi4; i64, __mulodi4; i128, __muloti4; - ); - fuzz_2(N, |x: u128, y: u128| { - let (mul0, o0) = x.overflowing_mul(y); - let (mul1, o1) = __rust_u128_mulo(x, y); - if mul0 != mul1 || o0 != o1 { - panic!( - "__rust_u128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})", - x, y, mul0, o0, mul1, o1 - ); - } - let x = x as i128; - let y = y as i128; - let (mul0, o0) = x.overflowing_mul(y); - let (mul1, o1) = __rust_i128_mulo(x, y); - if mul0 != mul1 || o0 != o1 { - panic!( - "__rust_i128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})", - x, y, mul0, o0, mul1, o1 - ); - } - }); + } + + #[test] + fn overflowing_mul_u128() { + use compiler_builtins::int::mul::{__rust_i128_mulo, __rust_u128_mulo}; + + fuzz_2(N, |x: u128, y: u128| { + let (mul0, o0) = x.overflowing_mul(y); + let (mul1, o1) = __rust_u128_mulo(x, y); + if mul0 != mul1 || o0 != o1 { + panic!( + "__rust_u128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})", + x, y, mul0, o0, mul1, o1 + ); + } + let x = x as i128; + let y = y as i128; + let (mul0, o0) = x.overflowing_mul(y); + let (mul1, o1) = __rust_i128_mulo(x, y); + if mul0 != mul1 || o0 != o1 { + panic!( + "__rust_i128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})", + x, y, mul0, o0, mul1, o1 + ); + } + }); + } } macro_rules! float_mul { ($($f:ty, $fn:ident, $apfloat_ty:ident, $sys_available:meta);*;) => { $( - fuzz_float_2(N, |x: $f, y: $f| { - let mul0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Mul::mul, x, y); - let mul1: $f = $fn(x, y); - // multiplication of subnormals is not currently handled - if !(Float::is_subnormal(mul0) || Float::is_subnormal(mul1)) { - if !Float::eq_repr(mul0, mul1) { - panic!( - "{}({:?}, {:?}): std: {:?}, builtins: {:?}", - stringify!($fn), x, y, mul0, mul1 - ); + #[test] + fn $fn() { + use compiler_builtins::float::{mul::$fn, Float}; + use core::ops::Mul; + + fuzz_float_2(N, |x: $f, y: $f| { + let mul0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Mul::mul, x, y); + let mul1: $f = $fn(x, y); + // multiplication of subnormals is not currently handled + if !(Float::is_subnormal(mul0) || Float::is_subnormal(mul1)) { + if !Float::eq_repr(mul0, mul1) { + panic!( + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn), x, y, mul0, mul1 + ); + } } - } - }); + }); + } )* }; } #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] -#[test] -fn float_mul() { - use compiler_builtins::float::{ - mul::{__muldf3, __mulsf3}, - Float, - }; - use core::ops::Mul; +mod float_mul { + use super::*; - float_mul!( + float_mul! { f32, __mulsf3, Single, all(); f64, __muldf3, Double, all(); - ); - - #[cfg(not(feature = "no-f16-f128"))] - { - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - use compiler_builtins::float::mul::__mulkf3 as __multf3; - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] - use compiler_builtins::float::mul::__multf3; - - float_mul!( - 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"))); - ); + } +} + +#[cfg(not(feature = "no-f16-f128"))] +#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] +#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] +mod float_mul_f128 { + use super::*; + + float_mul! { + 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"))); + } +} + +#[cfg(not(feature = "no-f16-f128"))] +#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +mod float_mul_f128_ppc { + use super::*; + + float_mul! { + f128, __mulkf3, Quad, not(feature = "no-sys-f128"); } } #[cfg(target_arch = "arm")] -#[test] -fn float_mul_arm() { - use compiler_builtins::float::{ - mul::{__muldf3vfp, __mulsf3vfp}, - Float, - }; - use core::ops::Mul; +mod float_mul_arm { + use super::*; - float_mul!( + float_mul! { f32, __mulsf3vfp, Single, all(); f64, __muldf3vfp, Double, all(); - ); + } } diff --git a/library/compiler-builtins/testcrate/tests/shift.rs b/library/compiler-builtins/testcrate/tests/shift.rs index 7a76b164685bf..23e3395edc629 100644 --- a/library/compiler-builtins/testcrate/tests/shift.rs +++ b/library/compiler-builtins/testcrate/tests/shift.rs @@ -3,35 +3,33 @@ use testcrate::*; macro_rules! shift { ($($i:ty, $fn_std:ident, $fn_builtins:ident);*;) => { $( - fuzz_shift(|x: $i, s: u32| { - let tmp0: $i = x.$fn_std(s); - let tmp1: $i = $fn_builtins(x, s); - if tmp0 != tmp1 { - panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn_builtins), x, s, tmp0, tmp1 - ); - } - }); + #[test] + fn $fn_builtins() { + use compiler_builtins::int::shift::$fn_builtins; + + fuzz_shift(|x: $i, s: u32| { + let tmp0: $i = x.$fn_std(s); + let tmp1: $i = $fn_builtins(x, s); + if tmp0 != tmp1 { + panic!( + "{}({}, {}): std: {}, builtins: {}", + stringify!($fn_builtins), x, s, tmp0, tmp1 + ); + } + }); + } )* }; } -#[test] -fn shift() { - use compiler_builtins::int::shift::{ - __ashldi3, __ashlsi3, __ashlti3, __ashrdi3, __ashrsi3, __ashrti3, __lshrdi3, __lshrsi3, - __lshrti3, - }; - shift!( - u32, wrapping_shl, __ashlsi3; - u64, wrapping_shl, __ashldi3; - u128, wrapping_shl, __ashlti3; - i32, wrapping_shr, __ashrsi3; - i64, wrapping_shr, __ashrdi3; - i128, wrapping_shr, __ashrti3; - u32, wrapping_shr, __lshrsi3; - u64, wrapping_shr, __lshrdi3; - u128, wrapping_shr, __lshrti3; - ); +shift! { + u32, wrapping_shl, __ashlsi3; + u64, wrapping_shl, __ashldi3; + u128, wrapping_shl, __ashlti3; + i32, wrapping_shr, __ashrsi3; + i64, wrapping_shr, __ashrdi3; + i128, wrapping_shr, __ashrti3; + u32, wrapping_shr, __lshrsi3; + u64, wrapping_shr, __lshrdi3; + u128, wrapping_shr, __lshrti3; } From 3fdef93258ab56f7cd0a6912dd271566b1ab87a1 Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Wed, 15 May 2024 10:32:06 -0700 Subject: [PATCH 1229/4206] Add tests for UNC paths on windows builds --- library/compiler-builtins/.github/workflows/main.yml | 9 +++++++++ library/compiler-builtins/ci/run.sh | 12 ++++++++++++ 2 files changed, 21 insertions(+) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 970a32ae51811..01188636621fb 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -19,6 +19,11 @@ jobs: - target: aarch64-unknown-linux-gnu os: ubuntu-latest rust: nightly + - target: aarch64-pc-windows-msvc + os: windows-latest + rust: nightly + test_unc: 1 + no_std: 1 - target: arm-unknown-linux-gnueabi os: ubuntu-latest rust: nightly @@ -78,6 +83,7 @@ jobs: - target: i686-pc-windows-msvc os: windows-latest rust: nightly + test_unc: 1 - target: x86_64-pc-windows-msvc os: windows-latest rust: nightly @@ -109,6 +115,9 @@ jobs: - run: ./ci/run.sh ${{ matrix.target }} if: matrix.os != 'ubuntu-latest' shell: bash + env: + NO_STD: ${{ matrix.no_std }} + TEST_UNC: ${{ matrix.test_unc }} # Otherwise we use our docker containers to run builds - run: cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 847b52435a138..f05744e87200c 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -32,6 +32,18 @@ else $run --features no-f16-f128 --release fi +if [ "${TEST_UNC:-}" = "1" ]; then + run="cargo build --manifest-path testcrate/Cargo.toml --target $target --target-dir \"\\\\?\\$(pwd)\"" + $run + $run --release + $run --features c + $run --features c --release + $run --features no-asm + $run --features no-asm --release + $run --features no-f16-f128 + $run --features no-f16-f128 --release +fi + if [ -d /builtins-target ]; then rlib_paths=/builtins-target/"${target}"/debug/deps/libcompiler_builtins-*.rlib else From 24cb0c2bcc044d5d60830334e18eb403c4d9ac2d Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Wed, 15 May 2024 10:40:48 -0700 Subject: [PATCH 1230/4206] Fix CI --- library/compiler-builtins/.github/workflows/main.yml | 1 + library/compiler-builtins/ci/run.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 01188636621fb..6518a4dd68800 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -87,6 +87,7 @@ jobs: - target: x86_64-pc-windows-msvc os: windows-latest rust: nightly + test_unc: 1 - target: i686-pc-windows-gnu os: windows-latest rust: nightly-i686-gnu diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index f05744e87200c..b2728eacf352f 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -33,7 +33,7 @@ else fi if [ "${TEST_UNC:-}" = "1" ]; then - run="cargo build --manifest-path testcrate/Cargo.toml --target $target --target-dir \"\\\\?\\$(pwd)\"" + run="cargo build --manifest-path testcrate/Cargo.toml --target $target --target-dir \\\\?\\$TEMP\\test_unc" $run $run --release $run --features c From e246ba5a460e45aaf24aaa5a8d2ccbc04227544c Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Wed, 15 May 2024 10:44:58 -0700 Subject: [PATCH 1231/4206] Use cmd.exe --- .../.github/workflows/main.yml | 2 ++ library/compiler-builtins/ci/run.sh | 20 ++++++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 6518a4dd68800..531a4c308a469 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -91,9 +91,11 @@ jobs: - target: i686-pc-windows-gnu os: windows-latest rust: nightly-i686-gnu + test_unc: 1 - target: x86_64-pc-windows-gnu os: windows-latest rust: nightly-x86_64-gnu + test_unc: 1 steps: - name: Print runner information run: uname -a diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index b2728eacf352f..2620dfff8e649 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -33,15 +33,17 @@ else fi if [ "${TEST_UNC:-}" = "1" ]; then - run="cargo build --manifest-path testcrate/Cargo.toml --target $target --target-dir \\\\?\\$TEMP\\test_unc" - $run - $run --release - $run --features c - $run --features c --release - $run --features no-asm - $run --features no-asm --release - $run --features no-f16-f128 - $run --features no-f16-f128 --release + function run() { + cmd.exe /c cargo build --manifest-path testcrate/Cargo.toml --target $target --target-dir "\\\\?\\%TEMP%\\test_unc" "$@" + } + run + run --release + run --features c + run --features c --release + run --features no-asm + run --features no-asm --release + run --features no-f16-f128 + run --features no-f16-f128 --release fi if [ -d /builtins-target ]; then From 0000f98d7307ebc2ab0e81914b5a3e0fa60f4a3b Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Wed, 15 May 2024 10:47:07 -0700 Subject: [PATCH 1232/4206] Fix backslash --- 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 2620dfff8e649..d4f0b80fbf7f4 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -34,7 +34,7 @@ fi if [ "${TEST_UNC:-}" = "1" ]; then function run() { - cmd.exe /c cargo build --manifest-path testcrate/Cargo.toml --target $target --target-dir "\\\\?\\%TEMP%\\test_unc" "$@" + cmd.exe /c cargo build --manifest-path "testcrate\\Cargo.toml" --target $target --target-dir "\\\\?\\%TEMP%\\test_unc" "$@" } run run --release From e3d86a8350a7ced205f9129995a96e34cd5043b4 Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Wed, 15 May 2024 10:54:40 -0700 Subject: [PATCH 1233/4206] Instead have cmd.exe dump out path --- library/compiler-builtins/ci/run.sh | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index d4f0b80fbf7f4..b4bf18b10149f 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -33,17 +33,16 @@ else fi if [ "${TEST_UNC:-}" = "1" ]; then - function run() { - cmd.exe /c cargo build --manifest-path "testcrate\\Cargo.toml" --target $target --target-dir "\\\\?\\%TEMP%\\test_unc" "$@" - } - run - run --release - run --features c - run --features c --release - run --features no-asm - run --features no-asm --release - run --features no-f16-f128 - run --features no-f16-f128 --release + path=$(cmd.exe "/C echo \\\\?\\%cd%\\testcrate\\target_unc") + run="cargo test --manifest-path testcrate/Cargo.toml --target $target --target-dir $path" + $run + $run --release + $run --features c + $run --features c --release + $run --features no-asm + $run --features no-asm --release + $run --features no-f16-f128 + $run --features no-f16-f128 --release fi if [ -d /builtins-target ]; then From fd290b133955f59e8b73dfe4e3891d2c0dc12d8f Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Wed, 15 May 2024 11:05:20 -0700 Subject: [PATCH 1234/4206] Properly escape /C and fix naming --- library/compiler-builtins/.github/workflows/main.yml | 12 ++++++------ library/compiler-builtins/ci/run.sh | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 531a4c308a469..b27267ba66c4f 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -22,7 +22,7 @@ jobs: - target: aarch64-pc-windows-msvc os: windows-latest rust: nightly - test_unc: 1 + test_verbatim: 1 no_std: 1 - target: arm-unknown-linux-gnueabi os: ubuntu-latest @@ -83,19 +83,19 @@ jobs: - target: i686-pc-windows-msvc os: windows-latest rust: nightly - test_unc: 1 + test_verbatim: 1 - target: x86_64-pc-windows-msvc os: windows-latest rust: nightly - test_unc: 1 + test_verbatim: 1 - target: i686-pc-windows-gnu os: windows-latest rust: nightly-i686-gnu - test_unc: 1 + test_verbatim: 1 - target: x86_64-pc-windows-gnu os: windows-latest rust: nightly-x86_64-gnu - test_unc: 1 + test_verbatim: 1 steps: - name: Print runner information run: uname -a @@ -120,7 +120,7 @@ jobs: shell: bash env: NO_STD: ${{ matrix.no_std }} - TEST_UNC: ${{ matrix.test_unc }} + TEST_VERBATIM: ${{ matrix.test_verbatim }} # Otherwise we use our docker containers to run builds - run: cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index b4bf18b10149f..cc07090d4d15f 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -32,9 +32,9 @@ else $run --features no-f16-f128 --release fi -if [ "${TEST_UNC:-}" = "1" ]; then - path=$(cmd.exe "/C echo \\\\?\\%cd%\\testcrate\\target_unc") - run="cargo test --manifest-path testcrate/Cargo.toml --target $target --target-dir $path" +if [ "${TEST_VERBATIM:-}" = "1" ]; then + verb_path=$(cmd.exe //C echo \\\\?\\%cd%\\testcrate\\target2) + run="cargo test --manifest-path testcrate/Cargo.toml --target $target --target-dir $verb_path" $run $run --release $run --features c From 416be726df79f30cd6ebba972bd689fbd09b7821 Mon Sep 17 00:00:00 2001 From: theKidOfArcrania Date: Wed, 15 May 2024 11:07:06 -0700 Subject: [PATCH 1235/4206] verbatim tests only need to build --- 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 cc07090d4d15f..3c33bbf835f5e 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -34,7 +34,7 @@ fi if [ "${TEST_VERBATIM:-}" = "1" ]; then verb_path=$(cmd.exe //C echo \\\\?\\%cd%\\testcrate\\target2) - run="cargo test --manifest-path testcrate/Cargo.toml --target $target --target-dir $verb_path" + run="cargo build --manifest-path testcrate/Cargo.toml --target $target --target-dir $verb_path" $run $run --release $run --features c From 7d60c93165e80cefb4ab6fc8ada0405593c1fe58 Mon Sep 17 00:00:00 2001 From: Henry Wang Date: Fri, 17 May 2024 08:40:39 -0700 Subject: [PATCH 1236/4206] Only run `--features c` for verbatim test --- library/compiler-builtins/ci/run.sh | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 3c33bbf835f5e..2512dc633e530 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -34,15 +34,7 @@ fi if [ "${TEST_VERBATIM:-}" = "1" ]; then verb_path=$(cmd.exe //C echo \\\\?\\%cd%\\testcrate\\target2) - run="cargo build --manifest-path testcrate/Cargo.toml --target $target --target-dir $verb_path" - $run - $run --release - $run --features c - $run --features c --release - $run --features no-asm - $run --features no-asm --release - $run --features no-f16-f128 - $run --features no-f16-f128 --release + cargo build --manifest-path testcrate/Cargo.toml --target $target --target-dir $verb_path --features c fi if [ -d /builtins-target ]; then From 0722bc4275c2e6e0f5d6b8e1b3813b61cd6efff1 Mon Sep 17 00:00:00 2001 From: Henry Wang Date: Fri, 17 May 2024 08:41:59 -0700 Subject: [PATCH 1237/4206] Don't run verbatim test on windows-gnu --- library/compiler-builtins/.github/workflows/main.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index b27267ba66c4f..72d441c4e7da5 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -91,11 +91,9 @@ jobs: - target: i686-pc-windows-gnu os: windows-latest rust: nightly-i686-gnu - test_verbatim: 1 - target: x86_64-pc-windows-gnu os: windows-latest rust: nightly-x86_64-gnu - test_verbatim: 1 steps: - name: Print runner information run: uname -a From bac7b1e77718fea6649ce3f88dc1fd7e628508e9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 17 May 2024 22:02:37 -0500 Subject: [PATCH 1238/4206] Add `CastFrom` as a convenience form of `CastInto` --- library/compiler-builtins/src/int/mod.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 2b6d4b812ee05..0c67a4c165667 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -380,6 +380,16 @@ public_test_dep! { pub(crate) trait CastInto: Copy { fn cast(self) -> T; } + +pub(crate) trait CastFrom:Copy { + fn cast_from(value: T) -> Self; +} +} + +impl + Copy> CastFrom for T { + fn cast_from(value: U) -> Self { + value.cast() + } } macro_rules! cast_into { From fc53fb64fc06642417c35e9d544bf4b0b40beba9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 17 May 2024 22:04:03 -0500 Subject: [PATCH 1239/4206] Make float to integer conversions generic Deduplicate code used for float to integer conversions in order to make adding `f128` conversion functions easier. --- library/compiler-builtins/src/float/conv.rs | 250 ++++++++------------ library/compiler-builtins/src/float/mod.rs | 8 +- library/compiler-builtins/src/int/mod.rs | 5 + 3 files changed, 109 insertions(+), 154 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 790c0ab9f351f..931840f15965c 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -1,3 +1,9 @@ +use core::ops::Neg; + +use crate::int::{CastFrom, CastInto, Int, MinInt}; + +use super::Float; + /// Conversions from integers to floats. /// /// These are hand-optimized bit twiddling code, @@ -142,102 +148,118 @@ intrinsics! { } } +/// Generic float to unsigned int conversions. +fn float_to_unsigned_int(f: F) -> U +where + F: Float, + U: Int, + F::Int: CastInto, + F::Int: CastFrom, + F::Int: CastInto, + u32: CastFrom, +{ + float_to_int_inner::(f.repr(), |i: U| i, || U::MAX) +} + +/// Generic float to signed int conversions. +fn float_to_signed_int(f: F) -> I +where + F: Float, + I: Int + Neg, + I::UnsignedInt: Int, + F::Int: CastInto, + F::Int: CastFrom, + u32: CastFrom, +{ + float_to_int_inner::( + f.repr() & !F::SIGN_MASK, + |i: I| if f.is_sign_negative() { -i } else { i }, + || if f.is_sign_negative() { I::MIN } else { I::MAX }, + ) +} + +/// Float to int conversions, generic for both signed and unsigned. +/// +/// Parameters: +/// - `fbits`: `abg(f)` bitcasted to an integer. +/// - `map_inbounds`: apply this transformation to integers that are within range (add the sign +/// back). +/// - `out_of_bounds`: return value when out of range for `I`. +fn float_to_int_inner( + fbits: F::Int, + map_inbounds: FnFoo, + out_of_bounds: FnOob, +) -> I +where + F: Float, + I: Int, + FnFoo: FnOnce(I) -> I, + FnOob: FnOnce() -> I, + I::UnsignedInt: Int, + F::Int: CastInto, + F::Int: CastFrom, + u32: CastFrom, +{ + let int_max_exp = F::EXPONENT_BIAS + I::MAX.ilog2() + 1; + let foobar = F::EXPONENT_BIAS + I::UnsignedInt::BITS - 1; + + if fbits < F::ONE.repr() { + // < 0 gets rounded to 0 + I::ZERO + } else if fbits < F::Int::cast_from(int_max_exp) << F::SIGNIFICAND_BITS { + // >= 1, < integer max + let m_base = if I::UnsignedInt::BITS >= F::Int::BITS { + I::UnsignedInt::cast_from(fbits) << (I::BITS - F::SIGNIFICAND_BITS - 1) + } else { + I::UnsignedInt::cast_from(fbits >> (F::SIGNIFICAND_BITS - I::BITS + 1)) + }; + + // Set the implicit 1-bit. + let m: I::UnsignedInt = I::UnsignedInt::ONE << (I::BITS - 1) | m_base; + + // Shift based on the exponent and bias. + let s: u32 = (foobar) - u32::cast_from(fbits >> F::SIGNIFICAND_BITS); + + let unsigned = m >> s; + map_inbounds(I::from_unsigned(unsigned)) + } else if fbits <= F::EXPONENT_MASK { + // >= max (incl. inf) + out_of_bounds() + } else { + I::ZERO + } +} + // Conversions from floats to unsigned integers. intrinsics! { #[arm_aeabi_alias = __aeabi_f2uiz] pub extern "C" fn __fixunssfsi(f: f32) -> u32 { - let fbits = f.to_bits(); - if fbits < 127 << 23 { // >= 0, < 1 - 0 - } else if fbits < 159 << 23 { // >= 1, < max - let m = 1 << 31 | fbits << 8; // Mantissa and the implicit 1-bit. - let s = 158 - (fbits >> 23); // Shift based on the exponent and bias. - m >> s - } else if fbits <= 255 << 23 { // >= max (incl. inf) - u32::MAX - } else { // Negative or NaN - 0 - } + float_to_unsigned_int(f) } #[arm_aeabi_alias = __aeabi_f2ulz] pub extern "C" fn __fixunssfdi(f: f32) -> u64 { - let fbits = f.to_bits(); - if fbits < 127 << 23 { // >= 0, < 1 - 0 - } else if fbits < 191 << 23 { // >= 1, < max - let m = 1 << 63 | (fbits as u64) << 40; // Mantissa and the implicit 1-bit. - let s = 190 - (fbits >> 23); // Shift based on the exponent and bias. - m >> s - } else if fbits <= 255 << 23 { // >= max (incl. inf) - u64::MAX - } else { // Negative or NaN - 0 - } + float_to_unsigned_int(f) } #[win64_128bit_abi_hack] pub extern "C" fn __fixunssfti(f: f32) -> u128 { - let fbits = f.to_bits(); - if fbits < 127 << 23 { // >= 0, < 1 - 0 - } else if fbits < 255 << 23 { // >= 1, < inf - let m = 1 << 127 | (fbits as u128) << 104; // Mantissa and the implicit 1-bit. - let s = 254 - (fbits >> 23); // Shift based on the exponent and bias. - m >> s - } else if fbits == 255 << 23 { // == inf - u128::MAX - } else { // Negative or NaN - 0 - } + float_to_unsigned_int(f) } #[arm_aeabi_alias = __aeabi_d2uiz] pub extern "C" fn __fixunsdfsi(f: f64) -> u32 { - let fbits = f.to_bits(); - if fbits < 1023 << 52 { // >= 0, < 1 - 0 - } else if fbits < 1055 << 52 { // >= 1, < max - let m = 1 << 31 | (fbits >> 21) as u32; // Mantissa and the implicit 1-bit. - let s = 1054 - (fbits >> 52); // Shift based on the exponent and bias. - m >> s - } else if fbits <= 2047 << 52 { // >= max (incl. inf) - u32::MAX - } else { // Negative or NaN - 0 - } + float_to_unsigned_int(f) } #[arm_aeabi_alias = __aeabi_d2ulz] pub extern "C" fn __fixunsdfdi(f: f64) -> u64 { - let fbits = f.to_bits(); - if fbits < 1023 << 52 { // >= 0, < 1 - 0 - } else if fbits < 1087 << 52 { // >= 1, < max - let m = 1 << 63 | fbits << 11; // Mantissa and the implicit 1-bit. - let s = 1086 - (fbits >> 52); // Shift based on the exponent and bias. - m >> s - } else if fbits <= 2047 << 52 { // >= max (incl. inf) - u64::MAX - } else { // Negative or NaN - 0 - } + float_to_unsigned_int(f) } #[win64_128bit_abi_hack] pub extern "C" fn __fixunsdfti(f: f64) -> u128 { - let fbits = f.to_bits(); - if fbits < 1023 << 52 { // >= 0, < 1 - 0 - } else if fbits < 1151 << 52 { // >= 1, < max - let m = 1 << 127 | (fbits as u128) << 75; // Mantissa and the implicit 1-bit. - let s = 1150 - (fbits >> 52); // Shift based on the exponent and bias. - m >> s - } else if fbits <= 2047 << 52 { // >= max (incl. inf) - u128::MAX - } else { // Negative or NaN - 0 - } + float_to_unsigned_int(f) } } @@ -245,103 +267,31 @@ intrinsics! { intrinsics! { #[arm_aeabi_alias = __aeabi_f2iz] pub extern "C" fn __fixsfsi(f: f32) -> i32 { - let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. - if fbits < 127 << 23 { // >= 0, < 1 - 0 - } else if fbits < 158 << 23 { // >= 1, < max - let m = 1 << 31 | fbits << 8; // Mantissa and the implicit 1-bit. - let s = 158 - (fbits >> 23); // Shift based on the exponent and bias. - let u = (m >> s) as i32; // Unsigned result. - if f.is_sign_negative() { -u } else { u } - } else if fbits <= 255 << 23 { // >= max (incl. inf) - if f.is_sign_negative() { i32::MIN } else { i32::MAX } - } else { // NaN - 0 - } + float_to_signed_int(f) } #[arm_aeabi_alias = __aeabi_f2lz] pub extern "C" fn __fixsfdi(f: f32) -> i64 { - let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. - if fbits < 127 << 23 { // >= 0, < 1 - 0 - } else if fbits < 190 << 23 { // >= 1, < max - let m = 1 << 63 | (fbits as u64) << 40; // Mantissa and the implicit 1-bit. - let s = 190 - (fbits >> 23); // Shift based on the exponent and bias. - let u = (m >> s) as i64; // Unsigned result. - if f.is_sign_negative() { -u } else { u } - } else if fbits <= 255 << 23 { // >= max (incl. inf) - if f.is_sign_negative() { i64::MIN } else { i64::MAX } - } else { // NaN - 0 - } + float_to_signed_int(f) } #[win64_128bit_abi_hack] pub extern "C" fn __fixsfti(f: f32) -> i128 { - let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. - if fbits < 127 << 23 { // >= 0, < 1 - 0 - } else if fbits < 254 << 23 { // >= 1, < max - let m = 1 << 127 | (fbits as u128) << 104; // Mantissa and the implicit 1-bit. - let s = 254 - (fbits >> 23); // Shift based on the exponent and bias. - let u = (m >> s) as i128; // Unsigned result. - if f.is_sign_negative() { -u } else { u } - } else if fbits <= 255 << 23 { // >= max (incl. inf) - if f.is_sign_negative() { i128::MIN } else { i128::MAX } - } else { // NaN - 0 - } + float_to_signed_int(f) } #[arm_aeabi_alias = __aeabi_d2iz] pub extern "C" fn __fixdfsi(f: f64) -> i32 { - let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. - if fbits < 1023 << 52 { // >= 0, < 1 - 0 - } else if fbits < 1054 << 52 { // >= 1, < max - let m = 1 << 31 | (fbits >> 21) as u32; // Mantissa and the implicit 1-bit. - let s = 1054 - (fbits >> 52); // Shift based on the exponent and bias. - let u = (m >> s) as i32; // Unsigned result. - if f.is_sign_negative() { -u } else { u } - } else if fbits <= 2047 << 52 { // >= max (incl. inf) - if f.is_sign_negative() { i32::MIN } else { i32::MAX } - } else { // NaN - 0 - } + float_to_signed_int(f) } #[arm_aeabi_alias = __aeabi_d2lz] pub extern "C" fn __fixdfdi(f: f64) -> i64 { - let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. - if fbits < 1023 << 52 { // >= 0, < 1 - 0 - } else if fbits < 1086 << 52 { // >= 1, < max - let m = 1 << 63 | fbits << 11; // Mantissa and the implicit 1-bit. - let s = 1086 - (fbits >> 52); // Shift based on the exponent and bias. - let u = (m >> s) as i64; // Unsigned result. - if f.is_sign_negative() { -u } else { u } - } else if fbits <= 2047 << 52 { // >= max (incl. inf) - if f.is_sign_negative() { i64::MIN } else { i64::MAX } - } else { // NaN - 0 - } + float_to_signed_int(f) } #[win64_128bit_abi_hack] pub extern "C" fn __fixdfti(f: f64) -> i128 { - let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. - if fbits < 1023 << 52 { // >= 0, < 1 - 0 - } else if fbits < 1150 << 52 { // >= 1, < max - let m = 1 << 127 | (fbits as u128) << 75; // Mantissa and the implicit 1-bit. - let s = 1150 - (fbits >> 52); // Shift based on the exponent and bias. - let u = (m >> s) as i128; // Unsigned result. - if f.is_sign_negative() { -u } else { u } - } else if fbits <= 2047 << 52 { // >= max (incl. inf) - if f.is_sign_negative() { i128::MIN } else { i128::MAX } - } else { // NaN - 0 - } + float_to_signed_int(f) } } diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index e62a3fe0fd53a..5fef1df32a5be 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -80,8 +80,8 @@ pub(crate) trait Float: /// compared. fn eq_repr(self, rhs: Self) -> bool; - /// Returns the sign bit - fn sign(self) -> bool; + /// Returns true if the sign is negative + fn is_sign_negative(self) -> bool; /// Returns the exponent with bias fn exp(self) -> Self::ExpInt; @@ -150,8 +150,8 @@ macro_rules! float_impl { self.repr() == rhs.repr() } } - fn sign(self) -> bool { - self.signed_repr() < Self::SignedInt::ZERO + fn is_sign_negative(self) -> bool { + self.is_sign_negative() } fn exp(self) -> Self::ExpInt { ((self.to_bits() & Self::EXPONENT_MASK) >> Self::SIGNIFICAND_BITS) as Self::ExpInt diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 0c67a4c165667..45d3838803108 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -102,6 +102,7 @@ pub(crate) trait Int: MinInt fn rotate_left(self, other: u32) -> Self; fn overflowing_add(self, other: Self) -> (Self, bool); fn leading_zeros(self) -> u32; + fn ilog2(self) -> u32; } } @@ -200,6 +201,10 @@ macro_rules! int_impl_common { fn leading_zeros(self) -> u32 { ::leading_zeros(self) } + + fn ilog2(self) -> u32 { + ::ilog2(self) + } }; } From a3b1dfb8d51d8032ba8e4f7769863dc85b4142a2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 17 May 2024 22:04:49 -0500 Subject: [PATCH 1240/4206] Allow a specific fallback function in `apfloat_fallback` `as` casts are only allowed for primitives, doing the same operations with `rustc_apfloat` requires using functions. Add a way to specify these separately. --- .../compiler-builtins/testcrate/src/lib.rs | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index 1f3a4b8262170..5ee96ad275175 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -276,7 +276,7 @@ macro_rules! apfloat_fallback { // The expression to run. This expression may use `FloatTy` for its signature. // Optionally, the final conversion back to a float can be suppressed using // `=> no_convert` (for e.g. operations that return a bool). - $op:expr $(=> $convert:ident)?, + $op:expr $(=> $convert:ident)? $(; $apfloat_op:expr)?, // Arguments that get passed to `$op` after converting to a float $($arg:expr),+ $(,)? @@ -292,26 +292,40 @@ macro_rules! apfloat_fallback { use rustc_apfloat::Float; type FloatTy = rustc_apfloat::ieee::$apfloat_ty; - let op_res = $op( $(FloatTy::from_bits($arg.to_bits().into())),+ ); - - apfloat_fallback!(@convert $float_ty, op_res $(,$convert)?) + apfloat_fallback!(@inner + fty: $float_ty, + // Apply a conversion to `FloatTy` to each arg, then pass all args to `$op` + op_res: $op( $(FloatTy::from_bits($arg.to_bits().into())),+ ), + $(apfloat_op: $apfloat_op, )? + $(conv_opts: $convert,)? + args: $($arg),+ + ) }; ret }}; // Operations that do not need converting back to a float - (@convert $float_ty:ty, $val:expr, no_convert) => { + (@inner fty: $float_ty:ty, op_res: $val:expr, conv_opts: no_convert, args: $($_arg:expr),+) => { $val }; // Some apfloat operations return a `StatusAnd` that we need to extract the value from. This // is the default. - (@convert $float_ty:ty, $val:expr) => {{ + (@inner fty: $float_ty:ty, op_res: $val:expr, args: $($_arg:expr),+) => {{ // ignore the status, just get the value let unwrapped = $val.value; <$float_ty>::from_bits(FloatTy::to_bits(unwrapped).try_into().unwrap()) }}; + // This is the case where we can't use the same expression for the default builtin and + // nonstandard apfloat fallbac (e.g. `as` casts in std are normal functions in apfloat, so + // two separate expressions must be specified. + (@inner + fty: $float_ty:ty, op_res: $_val:expr, + apfloat_op: $apfloat_op:expr, args: $($arg:expr),+ + ) => {{ + $apfloat_op($($arg),+) + }}; } From aaaf62bd6b1b18f8f2b333785aaaedcc49caf2de Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 20 May 2024 20:00:02 -0400 Subject: [PATCH 1241/4206] Add an apfloat fallback for float to integer tests --- .../compiler-builtins/testcrate/tests/conv.rs | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 7b672ac251e5d..1e26950fe3526 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -100,14 +100,39 @@ mod f_to_i { use super::*; macro_rules! f_to_i { - ($x:ident, $($f:ty, $fn:ident);*;) => { + ($x:ident, $f_ty:ty, $apfloat_ty:ident, $sys_available:meta, $($i_ty:ty, $fn:ident);*;) => { $( // it is undefined behavior in the first place to do conversions with NaNs - if !$x.is_nan() { - let conv0 = $x as $f; - let conv1: $f = $fn($x); + if !apfloat_fallback!( + $f_ty, $apfloat_ty, $sys_available, |x: FloatTy| x.is_nan() => no_convert, $x + ) { + let conv0 = apfloat_fallback!( + $f_ty, $apfloat_ty, $sys_available, + // Use an `as` cast when the builtin is available on the system. + |x| x as $i_ty; + // 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; + + let apf = FloatTy::from_bits(x.to_bits().into()); + let bits: usize = <$i_ty>::BITS.try_into().unwrap(); + + let err_fn = || panic!( + "Unable to convert value {x:?} to type {}:", stringify!($i_ty) + ); + + if <$i_ty>::SIGNED { + <$i_ty>::try_from(apf.to_i128(bits).value).ok().unwrap_or_else(err_fn) + } else { + <$i_ty>::try_from(apf.to_u128(bits).value).ok().unwrap_or_else(err_fn) + } + }, + $x + ); + let conv1: $i_ty = $fn($x); if conv0 != conv1 { - panic!("{}({}): std: {}, builtins: {}", stringify!($fn), $x, conv0, conv1); + panic!("{}({:?}): std: {:?}, builtins: {:?}", stringify!($fn), $x, conv0, conv1); } } )* From ccd179b23144c703701cdc848935342c4325e1a7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 20 May 2024 20:00:11 -0400 Subject: [PATCH 1242/4206] Add `f128` float to integer conversion functions Add the following: - `__fixtfsi` - `__fixtfdi` - `__fixtfti` - `__fixunstfsi` - `__fixunstfdi` - `__fixunstfti` --- library/compiler-builtins/README.md | 12 +++---- library/compiler-builtins/build.rs | 10 ------ library/compiler-builtins/src/float/conv.rs | 30 ++++++++++++++++++ .../compiler-builtins/testcrate/Cargo.toml | 4 ++- library/compiler-builtins/testcrate/build.rs | 31 +++++++++++++++++-- .../compiler-builtins/testcrate/tests/conv.rs | 27 ++++++++++++++-- 6 files changed, 92 insertions(+), 22 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 37d7ab2e6718d..8233c669c6dec 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -239,12 +239,12 @@ These builtins are needed to support `f16` and `f128`, which are in the process - [x] extendhfsf2.c - [x] extendhftf2.c - [x] extendsftf2.c -- [ ] fixtfdi.c -- [ ] fixtfsi.c -- [ ] fixtfti.c -- [ ] fixunstfdi.c -- [ ] fixunstfsi.c -- [ ] fixunstfti.c +- [x] fixtfdi.c +- [x] fixtfsi.c +- [x] fixtfti.c +- [x] fixunstfdi.c +- [x] fixunstfsi.c +- [x] fixunstfti.c - [ ] floatditf.c - [ ] floatsitf.c - [ ] floatunditf.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index ec830ecb34b20..50415910d297c 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -533,12 +533,6 @@ mod c { if (target_arch == "aarch64" || target_arch == "arm64ec") && consider_float_intrinsics { sources.extend(&[ ("__comparetf2", "comparetf2.c"), - ("__fixtfdi", "fixtfdi.c"), - ("__fixtfsi", "fixtfsi.c"), - ("__fixtfti", "fixtfti.c"), - ("__fixunstfdi", "fixunstfdi.c"), - ("__fixunstfsi", "fixunstfsi.c"), - ("__fixunstfti", "fixunstfti.c"), ("__floatditf", "floatditf.c"), ("__floatsitf", "floatsitf.c"), ("__floatunditf", "floatunditf.c"), @@ -561,9 +555,7 @@ mod c { if target_arch == "mips64" { sources.extend(&[ ("__netf2", "comparetf2.c"), - ("__fixtfsi", "fixtfsi.c"), ("__floatsitf", "floatsitf.c"), - ("__fixunstfsi", "fixunstfsi.c"), ("__floatunsitf", "floatunsitf.c"), ("__fe_getround", "fp_mode.c"), ]); @@ -572,9 +564,7 @@ mod c { if target_arch == "loongarch64" { sources.extend(&[ ("__netf2", "comparetf2.c"), - ("__fixtfsi", "fixtfsi.c"), ("__floatsitf", "floatsitf.c"), - ("__fixunstfsi", "fixunstfsi.c"), ("__floatunsitf", "floatunsitf.c"), ("__fe_getround", "fp_mode.c"), ]); diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 931840f15965c..a37206cdce607 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -261,6 +261,21 @@ intrinsics! { pub extern "C" fn __fixunsdfti(f: f64) -> u128 { float_to_unsigned_int(f) } + + #[cfg(not(feature = "no-f16-f128"))] + pub extern "C" fn __fixunstfsi(f: f128) -> u32 { + float_to_unsigned_int(f) + } + + #[cfg(not(feature = "no-f16-f128"))] + pub extern "C" fn __fixunstfdi(f: f128) -> u64 { + float_to_unsigned_int(f) + } + + #[cfg(not(feature = "no-f16-f128"))] + pub extern "C" fn __fixunstfti(f: f128) -> u128 { + float_to_unsigned_int(f) + } } // Conversions from floats to signed integers. @@ -294,4 +309,19 @@ intrinsics! { pub extern "C" fn __fixdfti(f: f64) -> i128 { float_to_signed_int(f) } + + #[cfg(not(feature = "no-f16-f128"))] + pub extern "C" fn __fixtfsi(f: f128) -> i32 { + float_to_signed_int(f) + } + + #[cfg(not(feature = "no-f16-f128"))] + pub extern "C" fn __fixtfdi(f: f128) -> i64 { + float_to_signed_int(f) + } + + #[cfg(not(feature = "no-f16-f128"))] + pub extern "C" fn __fixtfti(f: f128) -> i128 { + float_to_signed_int(f) + } } diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 6f771181a05df..1de0c39761ed9 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -34,4 +34,6 @@ no-f16-f128 = ["compiler_builtins/no-f16-f128"] 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 = ["no-sys-f128-int-convert"] +# Some platforms have some f128 functions but everything except integer conversions +no-sys-f128-int-convert = [] diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index f24dae3c664d3..1dad6c5e64917 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -1,7 +1,15 @@ -use std::env; +use std::{collections::HashSet, env}; + +/// Features to enable +#[derive(Debug, PartialEq, Eq, Hash)] +enum Feature { + NoSysF128, + NoSysF128IntConvert, +} fn main() { let target = env::var("TARGET").unwrap(); + let mut features = HashSet::new(); // These platforms do not have f128 symbols available in their system libraries, so // skip related tests. @@ -21,7 +29,24 @@ fn main() { // . || target.starts_with("powerpc64-") { - println!("cargo:warning=using apfloat fallback for f128"); - println!("cargo:rustc-cfg=feature=\"no-sys-f128\""); + features.insert(Feature::NoSysF128); + features.insert(Feature::NoSysF128IntConvert); + } + + if target.starts_with("i586") || target.starts_with("i686") { + // 32-bit x86 seems to not have `__fixunstfti`, but does have everything else + features.insert(Feature::NoSysF128IntConvert); + } + + 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 to int conversions", + ), + }; + println!("cargo:warning={warning}"); + println!("cargo:rustc-cfg=feature=\"{name}\""); } } diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 1e26950fe3526..f73b809d04fd8 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -146,7 +146,7 @@ mod f_to_i { }; fuzz_float(N, |x: f32| { - f_to_i!(x, + f_to_i!(x, f32, Single, all(), u32, __fixunssfsi; u64, __fixunssfdi; u128, __fixunssfti; @@ -164,7 +164,7 @@ mod f_to_i { }; fuzz_float(N, |x: f64| { - f_to_i!(x, + f_to_i!(x, f64, Double, all(), u32, __fixunsdfsi; u64, __fixunsdfdi; u128, __fixunsdfti; @@ -174,6 +174,29 @@ mod f_to_i { ); }); } + + #[test] + #[cfg(not(feature = "no-f16-f128"))] + fn f128_to_int() { + use compiler_builtins::float::conv::{ + __fixtfdi, __fixtfsi, __fixtfti, __fixunstfdi, __fixunstfsi, __fixunstfti, + }; + + fuzz_float(N, |x: f128| { + f_to_i!( + x, + f128, + Quad, + not(feature = "no-sys-f128-int-convert"), + u32, __fixunstfsi; + u64, __fixunstfdi; + u128, __fixunstfti; + i32, __fixtfsi; + i64, __fixtfdi; + i128, __fixtfti; + ); + }); + } } macro_rules! conv { From c7bd2a565517664e1e7b67d2655e0381bc5d0f2b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 21 May 2024 03:41:06 -0400 Subject: [PATCH 1243/4206] Add `ppc_alias` to the `intrinsics!` macro PowerPC platforms use `kf` rather than `tf` for `f128`. Add a way to alias this in the macro to make the code cleaner. This also fixes the names of `fixunstf*` and `fixtf*` on Power PC (`fixunskf*` and `fixkf*` are correct). --- library/compiler-builtins/src/float/add.rs | 8 +-- library/compiler-builtins/src/float/cmp.rs | 54 +++---------------- library/compiler-builtins/src/float/conv.rs | 6 +++ library/compiler-builtins/src/float/extend.rs | 21 ++------ library/compiler-builtins/src/float/mul.rs | 9 +--- library/compiler-builtins/src/float/sub.rs | 13 +++-- library/compiler-builtins/src/float/trunc.rs | 21 ++------ library/compiler-builtins/src/macros.rs | 33 ++++++++++++ .../compiler-builtins/testcrate/tests/conv.rs | 7 +++ 9 files changed, 70 insertions(+), 102 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index fd151f77d8a09..7e8529f3e296f 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -203,16 +203,12 @@ intrinsics! { add(a, b) } - #[cfg(not(any(feature = "no-f16-f128", target_arch = "powerpc", target_arch = "powerpc64")))] + #[ppc_alias = __addkf3] + #[cfg(not(feature = "no-f16-f128"))] pub extern "C" fn __addtf3(a: f128, b: f128) -> f128 { add(a, b) } - #[cfg(all(not(feature = "no-f16-f128"), any(target_arch = "powerpc", target_arch = "powerpc64")))] - pub extern "C" fn __addkf3(a: f128, b: f128) -> f128 { - add(a, b) - } - #[cfg(target_arch = "arm")] pub extern "C" fn __addsf3vfp(a: f32, b: f32) -> f32 { a + b diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 44ebf6262ea48..5c431304c61e9 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -172,89 +172,51 @@ intrinsics! { } } -#[cfg(not(any( - feature = "no-f16-f128", - target_arch = "powerpc", - target_arch = "powerpc64" -)))] +#[cfg(not(feature = "no-f16-f128",))] intrinsics! { #[avr_skip] + #[ppc_alias = __lekf2] pub extern "C" fn __letf2(a: f128, b: f128) -> i32 { cmp(a, b).to_le_abi() } #[avr_skip] + #[ppc_alias = __gekf2] pub extern "C" fn __getf2(a: f128, b: f128) -> i32 { cmp(a, b).to_ge_abi() } #[avr_skip] + #[ppc_alias = __unordkf2] pub extern "C" fn __unordtf2(a: f128, b: f128) -> i32 { unord(a, b) as i32 } #[avr_skip] + #[ppc_alias = __eqkf2] pub extern "C" fn __eqtf2(a: f128, b: f128) -> i32 { cmp(a, b).to_le_abi() } #[avr_skip] + #[ppc_alias = __ltkf2] pub extern "C" fn __lttf2(a: f128, b: f128) -> i32 { cmp(a, b).to_le_abi() } #[avr_skip] + #[ppc_alias = __nekf2] pub extern "C" fn __netf2(a: f128, b: f128) -> i32 { cmp(a, b).to_le_abi() } #[avr_skip] + #[ppc_alias = __gtkf2] pub extern "C" fn __gttf2(a: f128, b: f128) -> i32 { cmp(a, b).to_ge_abi() } } -#[cfg(all( - not(feature = "no-f16-f128"), - any(target_arch = "powerpc", target_arch = "powerpc64") -))] -intrinsics! { - #[avr_skip] - pub extern "C" fn __lekf2(a: f128, b: f128) -> i32 { - cmp(a, b).to_le_abi() - } - - #[avr_skip] - pub extern "C" fn __gekf2(a: f128, b: f128) -> i32 { - cmp(a, b).to_ge_abi() - } - - #[avr_skip] - pub extern "C" fn __unordkf2(a: f128, b: f128) -> i32 { - unord(a, b) as i32 - } - - #[avr_skip] - pub extern "C" fn __eqkf2(a: f128, b: f128) -> i32 { - cmp(a, b).to_le_abi() - } - - #[avr_skip] - pub extern "C" fn __ltkf2(a: f128, b: f128) -> i32 { - cmp(a, b).to_le_abi() - } - - #[avr_skip] - pub extern "C" fn __nekf2(a: f128, b: f128) -> i32 { - cmp(a, b).to_le_abi() - } - - #[avr_skip] - pub extern "C" fn __gtkf2(a: f128, b: f128) -> i32 { - cmp(a, b).to_ge_abi() - } -} - #[cfg(target_arch = "arm")] intrinsics! { pub extern "aapcs" fn __aeabi_fcmple(a: f32, b: f32) -> i32 { diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index a37206cdce607..52119f3e8006e 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -262,16 +262,19 @@ intrinsics! { float_to_unsigned_int(f) } + #[ppc_alias = __fixunskfsi] #[cfg(not(feature = "no-f16-f128"))] pub extern "C" fn __fixunstfsi(f: f128) -> u32 { float_to_unsigned_int(f) } + #[ppc_alias = __fixunskfdi] #[cfg(not(feature = "no-f16-f128"))] pub extern "C" fn __fixunstfdi(f: f128) -> u64 { float_to_unsigned_int(f) } + #[ppc_alias = __fixunskfti] #[cfg(not(feature = "no-f16-f128"))] pub extern "C" fn __fixunstfti(f: f128) -> u128 { float_to_unsigned_int(f) @@ -310,16 +313,19 @@ intrinsics! { float_to_signed_int(f) } + #[ppc_alias = __fixkfsi] #[cfg(not(feature = "no-f16-f128"))] pub extern "C" fn __fixtfsi(f: f128) -> i32 { float_to_signed_int(f) } + #[ppc_alias = __fixkfdi] #[cfg(not(feature = "no-f16-f128"))] pub extern "C" fn __fixtfdi(f: f128) -> i64 { float_to_signed_int(f) } + #[ppc_alias = __fixkfti] #[cfg(not(feature = "no-f16-f128"))] pub extern "C" fn __fixtfti(f: f128) -> i128 { float_to_signed_int(f) diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index 12e5fc9e10f92..556048991334c 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -100,37 +100,22 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[ppc_alias = __extendhfkf2] pub extern "C" fn __extendhftf2(a: f16) -> f128 { extend(a) } - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - pub extern "C" fn __extendhfkf2(a: f16) -> f128 { - extend(a) - } - #[avr_skip] #[aapcs_on_arm] - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[ppc_alias = __extendsfkf2] pub extern "C" fn __extendsftf2(a: f32) -> f128 { extend(a) } - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - pub extern "C" fn __extendsfkf2(a: f32) -> f128 { - extend(a) - } - #[avr_skip] #[aapcs_on_arm] - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[ppc_alias = __extenddfkf2] pub extern "C" fn __extenddftf2(a: f64) -> f128 { extend(a) } - - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - pub extern "C" fn __extenddfkf2(a: f64) -> f128 { - extend(a) - } } diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index 9866b62804da9..007cc09a498a3 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -199,17 +199,12 @@ intrinsics! { mul(a, b) } - #[cfg(not(any(feature = "no-f16-f128", target_arch = "powerpc", target_arch = "powerpc64")))] + #[ppc_alias = __mulkf3] + #[cfg(not(feature = "no-f16-f128"))] pub extern "C" fn __multf3(a: f128, b: f128) -> f128 { mul(a, b) } - - #[cfg(all(not(feature = "no-f16-f128"), any(target_arch = "powerpc", target_arch = "powerpc64")))] - pub extern "C" fn __mulkf3(a: f128, b: f128) -> f128 { - mul(a, b) - } - #[cfg(target_arch = "arm")] pub extern "C" fn __mulsf3vfp(a: f32, b: f32) -> f32 { a * b diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index de33259d6406a..1492679f62309 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -15,16 +15,15 @@ intrinsics! { __adddf3(a, f64::from_repr(b.repr() ^ f64::SIGN_MASK)) } - #[cfg(not(any(feature = "no-f16-f128", target_arch = "powerpc", target_arch = "powerpc64")))] + #[ppc_alias = __subkf3] + #[cfg(not(feature = "no-f16-f128"))] pub extern "C" fn __subtf3(a: f128, b: f128) -> f128 { + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + use crate::float::add::__addkf3 as __addtf3; + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] use crate::float::add::__addtf3; - __addtf3(a, f128::from_repr(b.repr() ^ f128::SIGN_MASK)) - } - #[cfg(all(not(feature = "no-f16-f128"), any(target_arch = "powerpc", target_arch = "powerpc64")))] - pub extern "C" fn __subkf3(a: f128, b: f128) -> f128 { - use crate::float::add::__addkf3; - __addkf3(a, f128::from_repr(b.repr() ^ f128::SIGN_MASK)) + __addtf3(a, f128::from_repr(b.repr() ^ f128::SIGN_MASK)) } #[cfg(target_arch = "arm")] diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index 31351b5e96970..9aea6f91ebca5 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -155,37 +155,22 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[ppc_alias = __trunckfhf2] pub extern "C" fn __trunctfhf2(a: f128) -> f16 { trunc(a) } - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - pub extern "C" fn __trunckfhf2(a: f128) -> f16 { - trunc(a) - } - #[avr_skip] #[aapcs_on_arm] - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[ppc_alias = __trunckfsf2] pub extern "C" fn __trunctfsf2(a: f128) -> f32 { trunc(a) } - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - pub extern "C" fn __trunckfsf2(a: f128) -> f32 { - trunc(a) - } - #[avr_skip] #[aapcs_on_arm] - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[ppc_alias = __trunckfdf2] pub extern "C" fn __trunctfdf2(a: f128) -> f64 { trunc(a) } - - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - pub extern "C" fn __trunckfdf2(a: f128) -> f64 { - trunc(a) - } } diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index f762ef4da21d6..f537c1a968f0a 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -65,6 +65,9 @@ macro_rules! public_test_dep { /// it's a normal ABI elsewhere for returning a 128 bit integer. /// * `arm_aeabi_alias` - handles the "aliasing" of various intrinsics on ARM /// their otherwise typical names to other prefixed ones. +/// * `ppc_alias` - changes the name of the symbol on PowerPC platforms without +/// changing any other behavior. This is mostly for `f128`, which is `tf` on +/// most platforms but `kf` on PowerPC. macro_rules! intrinsics { () => (); @@ -320,6 +323,36 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); + // PowerPC usually uses `kf` rather than `tf` for `f128`. This is just an easy + // way to add an alias on those targets. + ( + #[ppc_alias = $alias:ident] + $(#[$($attr:tt)*])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + intrinsics! { + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + intrinsics! { + $(#[$($attr)*])* + pub extern $abi fn $alias( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + // C mem* functions are only generated when the "mem" feature is enabled. ( #[mem_builtin] diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index f73b809d04fd8..1425b49ce494a 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -178,6 +178,13 @@ mod f_to_i { #[test] #[cfg(not(feature = "no-f16-f128"))] fn f128_to_int() { + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + use compiler_builtins::float::conv::{ + __fixkfdi as __fixtfdi, __fixkfsi as __fixtfsi, __fixkfti as __fixtfti, + __fixunskfdi as __fixunstfdi, __fixunskfsi as __fixunstfsi, + __fixunskfti as __fixunstfti, + }; + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] use compiler_builtins::float::conv::{ __fixtfdi, __fixtfsi, __fixtfti, __fixunstfdi, __fixunstfsi, __fixunstfti, }; From d696144b878277236f2fae367d2fc7d41b5f13c1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 21 May 2024 01:45:17 -0400 Subject: [PATCH 1244/4206] Organize functions in intrinsics example --- .../compiler-builtins/examples/intrinsics.rs | 179 ++++++++++-------- 1 file changed, 96 insertions(+), 83 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 54b703dfbc72a..201c9a7e05395 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -8,10 +8,12 @@ #![allow(internal_features)] #![cfg_attr(thumb, no_main)] #![deny(dead_code)] +#![feature(allocator_api)] #![feature(bench_black_box)] +#![feature(f128)] +#![feature(f16)] #![feature(lang_items)] #![feature(start)] -#![feature(allocator_api)] #![no_std] extern crate panic_handler; @@ -26,126 +28,132 @@ extern "C" {} // have an additional comment: the function name is the ARM name for the intrinsic and the comment // in the non-ARM name for the intrinsic. mod intrinsics { - // truncdfsf2 - pub fn aeabi_d2f(x: f64) -> f32 { - x as f32 + /* f32 operations */ + + // extendsfdf2 + pub fn aeabi_f2d(x: f32) -> f64 { + x as f64 } - // fixdfsi - pub fn aeabi_d2i(x: f64) -> i32 { + // fixsfsi + pub fn aeabi_f2iz(x: f32) -> i32 { x as i32 } - // fixdfdi - pub fn aeabi_d2l(x: f64) -> i64 { + // fixsfdi + pub fn aeabi_f2lz(x: f32) -> i64 { x as i64 } - // fixunsdfsi - pub fn aeabi_d2uiz(x: f64) -> u32 { + // fixunssfsi + pub fn aeabi_f2uiz(x: f32) -> u32 { x as u32 } - // fixunsdfdi - pub fn aeabi_d2ulz(x: f64) -> u64 { + // fixunssfdi + pub fn aeabi_f2ulz(x: f32) -> u64 { x as u64 } - // adddf3 - pub fn aeabi_dadd(a: f64, b: f64) -> f64 { + // addsf3 + pub fn aeabi_fadd(a: f32, b: f32) -> f32 { a + b } - // eqdf2 - pub fn aeabi_dcmpeq(a: f64, b: f64) -> bool { + // eqsf2 + pub fn aeabi_fcmpeq(a: f32, b: f32) -> bool { a == b } - // gtdf2 - pub fn aeabi_dcmpgt(a: f64, b: f64) -> bool { + // gtsf2 + pub fn aeabi_fcmpgt(a: f32, b: f32) -> bool { a > b } - // ltdf2 - pub fn aeabi_dcmplt(a: f64, b: f64) -> bool { + // ltsf2 + pub fn aeabi_fcmplt(a: f32, b: f32) -> bool { a < b } - // divdf3 - pub fn aeabi_ddiv(a: f64, b: f64) -> f64 { + // divsf3 + pub fn aeabi_fdiv(a: f32, b: f32) -> f32 { a / b } - // muldf3 - pub fn aeabi_dmul(a: f64, b: f64) -> f64 { + // mulsf3 + pub fn aeabi_fmul(a: f32, b: f32) -> f32 { a * b } - // subdf3 - pub fn aeabi_dsub(a: f64, b: f64) -> f64 { + // subsf3 + pub fn aeabi_fsub(a: f32, b: f32) -> f32 { a - b } - // extendsfdf2 - pub fn aeabi_f2d(x: f32) -> f64 { - x as f64 + /* f64 operations */ + + // truncdfsf2 + pub fn aeabi_d2f(x: f64) -> f32 { + x as f32 } - // fixsfsi - pub fn aeabi_f2iz(x: f32) -> i32 { + // fixdfsi + pub fn aeabi_d2i(x: f64) -> i32 { x as i32 } - // fixsfdi - pub fn aeabi_f2lz(x: f32) -> i64 { + // fixdfdi + pub fn aeabi_d2l(x: f64) -> i64 { x as i64 } - // fixunssfsi - pub fn aeabi_f2uiz(x: f32) -> u32 { + // fixunsdfsi + pub fn aeabi_d2uiz(x: f64) -> u32 { x as u32 } - // fixunssfdi - pub fn aeabi_f2ulz(x: f32) -> u64 { + // fixunsdfdi + pub fn aeabi_d2ulz(x: f64) -> u64 { x as u64 } - // addsf3 - pub fn aeabi_fadd(a: f32, b: f32) -> f32 { + // adddf3 + pub fn aeabi_dadd(a: f64, b: f64) -> f64 { a + b } - // eqsf2 - pub fn aeabi_fcmpeq(a: f32, b: f32) -> bool { + // eqdf2 + pub fn aeabi_dcmpeq(a: f64, b: f64) -> bool { a == b } - // gtsf2 - pub fn aeabi_fcmpgt(a: f32, b: f32) -> bool { + // gtdf2 + pub fn aeabi_dcmpgt(a: f64, b: f64) -> bool { a > b } - // ltsf2 - pub fn aeabi_fcmplt(a: f32, b: f32) -> bool { + // ltdf2 + pub fn aeabi_dcmplt(a: f64, b: f64) -> bool { a < b } - // divsf3 - pub fn aeabi_fdiv(a: f32, b: f32) -> f32 { + // divdf3 + pub fn aeabi_ddiv(a: f64, b: f64) -> f64 { a / b } - // mulsf3 - pub fn aeabi_fmul(a: f32, b: f32) -> f32 { + // muldf3 + pub fn aeabi_dmul(a: f64, b: f64) -> f64 { a * b } - // subsf3 - pub fn aeabi_fsub(a: f32, b: f32) -> f32 { + // subdf3 + pub fn aeabi_dsub(a: f64, b: f64) -> f64 { a - b } + /* i32 operations */ + // floatsidf pub fn aeabi_i2d(x: i32) -> f64 { x as f64 @@ -164,14 +172,20 @@ mod intrinsics { a % b } + /* i64 operations */ + + // floatdisf + pub fn aeabi_l2f(x: i64) -> f32 { + x as f32 + } + // floatdidf pub fn aeabi_l2d(x: i64) -> f64 { x as f64 } - // floatdisf - pub fn aeabi_l2f(x: i64) -> f32 { - x as f32 + pub fn mulodi4(a: i64, b: i64) -> i64 { + a * b } // divdi3 @@ -179,11 +193,31 @@ mod intrinsics { a / b } + pub fn moddi3(a: i64, b: i64) -> i64 { + a % b + } + // muldi3 pub fn aeabi_lmul(a: i64, b: i64) -> i64 { a.wrapping_mul(b) } + /* i128 operations */ + + pub fn lshrti3(a: i128, b: usize) -> i128 { + a >> b + } + + pub fn divti3(a: i128, b: i128) -> i128 { + a / b + } + + pub fn modti3(a: i128, b: i128) -> i128 { + a % b + } + + /* u32 operations */ + // floatunsidf pub fn aeabi_ui2d(x: u32) -> f64 { x as f64 @@ -202,26 +236,20 @@ mod intrinsics { a % b } - // floatundidf - pub fn aeabi_ul2d(x: u64) -> f64 { - x as f64 - } + /* u64 operations */ // floatundisf pub fn aeabi_ul2f(x: u64) -> f32 { x as f32 } - // udivdi3 - pub fn aeabi_uldivmod(a: u64, b: u64) -> u64 { - a * b - } - - pub fn moddi3(a: i64, b: i64) -> i64 { - a % b + // floatundidf + pub fn aeabi_ul2d(x: u64) -> f64 { + x as f64 } - pub fn mulodi4(a: i64, b: i64) -> i64 { + // udivdi3 + pub fn aeabi_uldivmod(a: u64, b: u64) -> u64 { a * b } @@ -229,6 +257,8 @@ mod intrinsics { a % b } + /* u128 operations */ + pub fn muloti4(a: u128, b: u128) -> Option { a.checked_mul(b) } @@ -245,10 +275,6 @@ mod intrinsics { a << b } - pub fn lshrti3(a: i128, b: usize) -> i128 { - a >> b - } - pub fn udivti3(a: u128, b: u128) -> u128 { a / b } @@ -256,18 +282,6 @@ mod intrinsics { pub fn umodti3(a: u128, b: u128) -> u128 { a % b } - - pub fn divti3(a: i128, b: i128) -> i128 { - a / b - } - - pub fn modti3(a: i128, b: i128) -> i128 { - a % b - } - - pub fn udivsi3(a: u32, b: u32) -> u32 { - a / b - } } fn run() { @@ -325,7 +339,6 @@ fn run() { bb(umodti3(bb(2), bb(2))); bb(divti3(bb(2), bb(2))); bb(modti3(bb(2), bb(2))); - bb(udivsi3(bb(2), bb(2))); something_with_a_dtor(&|| assert_eq!(bb(1), 1)); From 324544fb6a1acb678cb4259d29173e17ed266958 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 21 May 2024 01:55:46 -0400 Subject: [PATCH 1245/4206] Add f16 and f128 intrinsics to the example test --- .../compiler-builtins/examples/intrinsics.rs | 134 +++++++++++++++++- 1 file changed, 128 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 201c9a7e05395..e4fcb3e35e368 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -28,13 +28,36 @@ extern "C" {} // have an additional comment: the function name is the ARM name for the intrinsic and the comment // in the non-ARM name for the intrinsic. mod intrinsics { + /* f16 operations */ + + pub fn extendhfsf(x: f16) -> f32 { + x as f32 + } + + pub fn extendhfdf(x: f16) -> f64 { + x as f64 + } + + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + pub fn extendhftf(x: f16) -> f128 { + x as f128 + } + /* f32 operations */ + pub fn truncsfhf(x: f32) -> f16 { + x as f16 + } + // extendsfdf2 pub fn aeabi_f2d(x: f32) -> f64 { x as f64 } + pub fn extendsftf(x: f32) -> f128 { + x as f128 + } + // fixsfsi pub fn aeabi_f2iz(x: f32) -> i32 { x as i32 @@ -152,6 +175,75 @@ mod intrinsics { a - b } + /* f128 operations */ + + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + pub fn trunctfhf(x: f128) -> f16 { + x as f16 + } + + pub fn trunctfsf(x: f128) -> f32 { + x as f32 + } + + pub fn trunctfdf(x: f128) -> f64 { + x as f64 + } + + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + pub fn fixtfsi(x: f128) -> i32 { + x as i32 + } + + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + pub fn fixtfdi(x: f128) -> i64 { + x as i64 + } + + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + pub fn fixtfti(x: f128) -> i128 { + x as i128 + } + + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + pub fn fixunstfsi(x: f128) -> u32 { + x as u32 + } + + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + pub fn fixunstfdi(x: f128) -> u64 { + x as u64 + } + + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + pub fn fixunstfti(x: f128) -> u128 { + x as u128 + } + + pub fn addtf(a: f128, b: f128) -> f128 { + a + b + } + + pub fn eqtf(a: f128, b: f128) -> bool { + a == b + } + + pub fn gttf(a: f128, b: f128) -> bool { + a > b + } + + pub fn lttf(a: f128, b: f128) -> bool { + a < b + } + + pub fn multf(a: f128, b: f128) -> f128 { + a * b + } + + pub fn subtf(a: f128, b: f128) -> f128 { + a - b + } + /* i32 operations */ // floatsidf @@ -288,6 +380,9 @@ fn run() { use core::hint::black_box as bb; use intrinsics::*; + // FIXME(f16_f128): some PPC f128 <-> int conversion functions have the wrong names + + bb(addtf(bb(2.), bb(2.))); bb(aeabi_d2f(bb(2.))); bb(aeabi_d2i(bb(2.))); bb(aeabi_d2l(bb(2.))); @@ -327,18 +422,45 @@ fn run() { bb(aeabi_ul2d(bb(2))); bb(aeabi_ul2f(bb(2))); bb(aeabi_uldivmod(bb(2), bb(3))); + bb(ashlti3(bb(2), bb(2))); + bb(ashrti3(bb(2), bb(2))); + bb(divti3(bb(2), bb(2))); + bb(eqtf(bb(2.), bb(2.))); + bb(extendhfdf(bb(2.))); + bb(extendhfsf(bb(2.))); + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + bb(extendhftf(bb(2.))); + bb(extendsftf(bb(2.))); + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + bb(fixtfdi(bb(2.))); + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + bb(fixtfsi(bb(2.))); + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + bb(fixtfti(bb(2.))); + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + bb(fixunstfdi(bb(2.))); + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + bb(fixunstfsi(bb(2.))); + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + bb(fixunstfti(bb(2.))); + bb(gttf(bb(2.), bb(2.))); + bb(lshrti3(bb(2), bb(2))); + bb(lttf(bb(2.), bb(2.))); bb(moddi3(bb(2), bb(3))); + bb(modti3(bb(2), bb(2))); bb(mulodi4(bb(2), bb(3))); - bb(umoddi3(bb(2), bb(3))); bb(muloti4(bb(2), bb(2))); + bb(multf(bb(2.), bb(2.))); bb(multi3(bb(2), bb(2))); - bb(ashlti3(bb(2), bb(2))); - bb(ashrti3(bb(2), bb(2))); - bb(lshrti3(bb(2), bb(2))); + bb(subtf(bb(2.), bb(2.))); + bb(truncsfhf(bb(2.))); + bb(trunctfdf(bb(2.))); + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + bb(trunctfhf(bb(2.))); + bb(trunctfsf(bb(2.))); bb(udivti3(bb(2), bb(2))); + bb(umoddi3(bb(2), bb(3))); bb(umodti3(bb(2), bb(2))); - bb(divti3(bb(2), bb(2))); - bb(modti3(bb(2), bb(2))); something_with_a_dtor(&|| assert_eq!(bb(1), 1)); From ec123994707db2421c41d7bda9fc38c5a9a31a07 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 21 May 2024 01:59:00 -0400 Subject: [PATCH 1246/4206] Update outdated contribution guidelines --- library/compiler-builtins/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 8233c669c6dec..9a847da3f69ad 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -52,17 +52,17 @@ features = ["c"] 2. Fork this repository. 3. Port the intrinsic(s) and their corresponding [unit tests][1] from their [C implementation][2] to Rust. -4. Implement a [test generator][3] to compare the behavior of the ported intrinsic(s) - with their implementation on the testing host. Note that randomized compiler-builtin tests - should be run using `cargo test --features gen-tests`. -4. Send a Pull Request (PR). -5. Once the PR passes our extensive [testing infrastructure][4], we'll merge it! -6. Celebrate :tada: +4. Add a test to compare the behavior of the ported intrinsic(s) with their + implementation on the testing host. +5. Add the intrinsic to `examples/intrinsics.rs` to verify it can be linked on + all targets. +6. Send a Pull Request (PR). +7. Once the PR passes our extensive [testing infrastructure][4], we'll merge it! +8. Celebrate :tada: [1]: https://github.com/rust-lang/llvm-project/tree/9e3de9490ff580cd484fbfa2908292b4838d56e7/compiler-rt/test/builtins/Unit [2]: https://github.com/rust-lang/llvm-project/tree/9e3de9490ff580cd484fbfa2908292b4838d56e7/compiler-rt/lib/builtins -[3]: https://github.com/rust-lang/compiler-builtins/blob/0ba07e49264a54cb5bbd4856fcea083bb3fbec15/build.rs#L180-L265 -[4]: https://github.com/rust-lang/compiler-builtins/actions +[3]: https://github.com/rust-lang/compiler-builtins/actions ### Porting Reminders From 81fbfedd9214ea9b488aac5cbf69e328799bd8a9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 21 May 2024 02:02:21 -0400 Subject: [PATCH 1247/4206] Add some missing functions to examples/intrinsics --- .../compiler-builtins/examples/intrinsics.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index e4fcb3e35e368..8bb70767376ec 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -68,6 +68,10 @@ mod intrinsics { x as i64 } + pub fn fixsfti(x: f32) -> i128 { + x as i128 + } + // fixunssfsi pub fn aeabi_f2uiz(x: f32) -> u32 { x as u32 @@ -78,6 +82,10 @@ mod intrinsics { x as u64 } + pub fn fixunssfti(x: f32) -> u128 { + x as u128 + } + // addsf3 pub fn aeabi_fadd(a: f32, b: f32) -> f32 { a + b @@ -130,6 +138,10 @@ mod intrinsics { x as i64 } + pub fn fixdfti(x: f64) -> i128 { + x as i128 + } + // fixunsdfsi pub fn aeabi_d2uiz(x: f64) -> u32 { x as u32 @@ -140,6 +152,10 @@ mod intrinsics { x as u64 } + pub fn fixunsdfti(x: f64) -> u128 { + x as u128 + } + // adddf3 pub fn aeabi_dadd(a: f64, b: f64) -> f64 { a + b @@ -431,12 +447,16 @@ fn run() { #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] bb(extendhftf(bb(2.))); bb(extendsftf(bb(2.))); + bb(fixdfti(bb(2.))); + bb(fixsfti(bb(2.))); #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] bb(fixtfdi(bb(2.))); #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] bb(fixtfsi(bb(2.))); #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] bb(fixtfti(bb(2.))); + bb(fixunsdfti(bb(2.))); + bb(fixunssfti(bb(2.))); #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] bb(fixunstfdi(bb(2.))); #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] From 2fa55c4ef5f70a7fee319d6da962b6ed4e441836 Mon Sep 17 00:00:00 2001 From: Quentin Perez Date: Wed, 22 May 2024 09:49:08 +0200 Subject: [PATCH 1248/4206] Add Apple visionOS support --- library/compiler-builtins/build.rs | 13 ++---------- library/compiler-builtins/src/arm.rs | 30 ++++++++++++++-------------- 2 files changed, 17 insertions(+), 26 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 50415910d297c..0ecd399118e80 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -377,11 +377,7 @@ mod c { // On iOS and 32-bit OSX these are all just empty intrinsics, no need to // include them. - if target_os != "ios" - && target_os != "watchos" - && target_os != "tvos" - && (target_vendor != "apple" || target_arch != "x86") - { + if target_vendor != "apple" || target_arch != "x86" { sources.extend(&[ ("__absvti2", "absvti2.c"), ("__addvti3", "addvti3.c"), @@ -431,12 +427,7 @@ mod c { } } - if target_arch == "arm" - && target_os != "ios" - && target_os != "watchos" - && target_os != "tvos" - && target_env != "msvc" - { + if target_arch == "arm" && target_vendor != "apple" && target_env != "msvc" { sources.extend(&[ ("__aeabi_div0", "arm/aeabi_div0.c"), ("__aeabi_drsub", "arm/aeabi_drsub.c"), diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index dcae22b73fb7f..55cdda1f3e0b1 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -3,14 +3,14 @@ use core::intrinsics; -// iOS symbols have a leading underscore. -#[cfg(target_os = "ios")] +// Apple symbols have a leading underscore. +#[cfg(target_vendor = "apple")] macro_rules! bl { ($func:literal) => { concat!("bl _", $func) }; } -#[cfg(not(target_os = "ios"))] +#[cfg(not(target_vendor = "apple"))] macro_rules! bl { ($func:literal) => { concat!("bl ", $func) @@ -82,12 +82,12 @@ intrinsics! { // FIXME: The `*4` and `*8` variants should be defined as aliases. - #[cfg(not(target_os = "ios"))] + #[cfg(not(target_vendor = "apple"))] pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { crate::mem::memcpy(dest, src, n); } - #[cfg(not(target_os = "ios"))] + #[cfg(not(target_vendor = "apple"))] pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { // We are guaranteed 4-alignment, so accessing at u32 is okay. let mut dest = dest as *mut u32; @@ -104,33 +104,33 @@ intrinsics! { __aeabi_memcpy(dest as *mut u8, src as *const u8, n); } - #[cfg(not(target_os = "ios"))] + #[cfg(not(target_vendor = "apple"))] pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memcpy4(dest, src, n); } - #[cfg(not(target_os = "ios"))] + #[cfg(not(target_vendor = "apple"))] pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { crate::mem::memmove(dest, src, n); } - #[cfg(not(any(target_os = "ios", target_env = "msvc")))] + #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memmove(dest, src, n); } - #[cfg(not(any(target_os = "ios", target_env = "msvc")))] + #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { __aeabi_memmove(dest, src, n); } - #[cfg(not(target_os = "ios"))] + #[cfg(not(target_vendor = "apple"))] pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { // Note the different argument order crate::mem::memset(dest, c, n); } - #[cfg(not(target_os = "ios"))] + #[cfg(not(target_vendor = "apple"))] pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { let mut dest = dest as *mut u32; let mut n = n; @@ -147,22 +147,22 @@ intrinsics! { __aeabi_memset(dest as *mut u8, n, byte as i32); } - #[cfg(not(target_os = "ios"))] + #[cfg(not(target_vendor = "apple"))] pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { __aeabi_memset4(dest, n, c); } - #[cfg(not(target_os = "ios"))] + #[cfg(not(target_vendor = "apple"))] pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { __aeabi_memset(dest, n, 0); } - #[cfg(not(any(target_os = "ios", target_env = "msvc")))] + #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); } - #[cfg(not(any(target_os = "ios", target_env = "msvc")))] + #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { __aeabi_memset4(dest, n, 0); } From 6cd17ff4d23977ea6df711f3197b191994a5513e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 19 May 2024 05:02:25 -0400 Subject: [PATCH 1249/4206] Add benchmarks for floating point math This adds comparisons among the compiler-builtins function, system functions if available, and optionally handwritten assembly. These also help us identify inconsistencies between this crate and system functions, which may otherwise go unnoticed if intrinsics get lowered to inline operations rather than library calls. --- library/compiler-builtins/ci/run.sh | 6 +- .../compiler-builtins/testcrate/Cargo.toml | 48 +- .../bench-175b45d1-aarch64-macos.txt | 500 +++++++++++++ .../bench-3cee6376-aarch64-macos.txt | 699 ++++++++++++++++++ .../testcrate/benches/float_add.rs | 81 ++ .../testcrate/benches/float_cmp.rs | 202 +++++ .../testcrate/benches/float_conv.rs | 547 ++++++++++++++ .../testcrate/benches/float_div.rs | 70 ++ .../testcrate/benches/float_extend.rs | 93 +++ .../testcrate/benches/float_mul.rs | 81 ++ .../testcrate/benches/float_pow.rs | 24 + .../testcrate/benches/float_sub.rs | 81 ++ .../testcrate/benches/float_trunc.rs | 127 ++++ library/compiler-builtins/testcrate/build.rs | 19 + .../compiler-builtins/testcrate/src/bench.rs | 348 +++++++++ .../compiler-builtins/testcrate/src/lib.rs | 6 + 16 files changed, 2930 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/testcrate/bench-175b45d1-aarch64-macos.txt create mode 100644 library/compiler-builtins/testcrate/bench-3cee6376-aarch64-macos.txt create mode 100644 library/compiler-builtins/testcrate/benches/float_add.rs create mode 100644 library/compiler-builtins/testcrate/benches/float_cmp.rs create mode 100644 library/compiler-builtins/testcrate/benches/float_conv.rs create mode 100644 library/compiler-builtins/testcrate/benches/float_div.rs create mode 100644 library/compiler-builtins/testcrate/benches/float_extend.rs create mode 100644 library/compiler-builtins/testcrate/benches/float_mul.rs create mode 100644 library/compiler-builtins/testcrate/benches/float_pow.rs create mode 100644 library/compiler-builtins/testcrate/benches/float_sub.rs create mode 100644 library/compiler-builtins/testcrate/benches/float_trunc.rs create mode 100644 library/compiler-builtins/testcrate/src/bench.rs diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 2512dc633e530..dcbe1caf4ef4d 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -4,7 +4,9 @@ set -eux target="${1:-}" -if [ -z "${1:-}" ]; then +export RUST_BACKTRACE="${RUST_BACKTRACE:-full}" + +if [ -z "$target" ]; then host_target=$(rustc -vV | awk '/^host/ { print $2 }') echo "Defaulted to host target $host_target" target="$host_target" @@ -30,6 +32,8 @@ else $run --features no-asm --release $run --features no-f16-f128 $run --features no-f16-f128 --release + $run --benches + $run --benches --release fi if [ "${TEST_VERBATIM:-}" = "1" ]; then diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 1de0c39761ed9..6b5c4cf48d2a5 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -21,6 +21,10 @@ path = ".." default-features = false features = ["public-test-deps"] +[dev-dependencies] +criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } +paste = "1.0.15" + [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" } @@ -34,6 +38,48 @@ no-f16-f128 = ["compiler_builtins/no-f16-f128"] 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-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 = [] +# Skip tests that rely on f16 symbols being available on the system +no-sys-f16 = [] + +# Enable report generation without bringing in more dependencies by default +benchmarking-reports = ["criterion/plotters", "criterion/html_reports"] + +[[bench]] +name = "float_add" +harness = false + +[[bench]] +name = "float_sub" +harness = false + +[[bench]] +name = "float_mul" +harness = false + +[[bench]] +name = "float_div" +harness = false + +[[bench]] +name = "float_cmp" +harness = false + +[[bench]] +name = "float_conv" +harness = false + +[[bench]] +name = "float_extend" +harness = false + +[[bench]] +name = "float_trunc" +harness = false + +[[bench]] +name = "float_pow" +harness = false diff --git a/library/compiler-builtins/testcrate/bench-175b45d1-aarch64-macos.txt b/library/compiler-builtins/testcrate/bench-175b45d1-aarch64-macos.txt new file mode 100644 index 0000000000000..e79bbe3687354 --- /dev/null +++ b/library/compiler-builtins/testcrate/bench-175b45d1-aarch64-macos.txt @@ -0,0 +1,500 @@ + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + +add_f32 compiler-builtins + time: [35.804 µs 35.863 µs 35.920 µs] +Found 5 outliers among 100 measurements (5.00%) + 2 (2.00%) high mild + 3 (3.00%) high severe + +add_f32 system time: [39.084 µs 39.127 µs 39.169 µs] +Found 11 outliers among 100 measurements (11.00%) + 7 (7.00%) high mild + 4 (4.00%) high severe + +add_f32 assembly (aarch64 unix) + time: [8.1034 µs 8.1441 µs 8.1866 µs] +Found 4 outliers among 100 measurements (4.00%) + 4 (4.00%) high mild + +add_f64 compiler-builtins + time: [35.647 µs 35.725 µs 35.799 µs] +Found 10 outliers among 100 measurements (10.00%) + 8 (8.00%) high mild + 2 (2.00%) high severe + +add_f64 system time: [39.308 µs 39.322 µs 39.336 µs] +Found 7 outliers among 100 measurements (7.00%) + 4 (4.00%) high mild + 3 (3.00%) high severe + +add_f64 assembly (aarch64 unix) + time: [8.0401 µs 8.0442 µs 8.0499 µs] +Found 11 outliers among 100 measurements (11.00%) + 2 (2.00%) high mild + 9 (9.00%) high severe + +add_f128 compiler-builtins + time: [41.801 µs 41.986 µs 42.201 µs] +Found 7 outliers among 100 measurements (7.00%) + 4 (4.00%) high mild + 3 (3.00%) high severe + +cmp_f32_gt compiler-builtins + time: [13.579 µs 13.675 µs 13.778 µs] +Found 16 outliers among 100 measurements (16.00%) + 6 (6.00%) high mild + 10 (10.00%) high severe + +cmp_f32_gt system time: [12.343 µs 12.348 µs 12.355 µs] +Found 13 outliers among 100 measurements (13.00%) + 1 (1.00%) low mild + 3 (3.00%) high mild + 9 (9.00%) high severe + +cmp_f32_gt assembly (aarch64 unix) + time: [8.2593 µs 8.3185 µs 8.3813 µs] +Found 1 outliers among 100 measurements (1.00%) + 1 (1.00%) high mild + +cmp_f32_unord compiler-builtins + time: [11.977 µs 12.042 µs 12.109 µs] +Found 13 outliers among 100 measurements (13.00%) + 5 (5.00%) low severe + 6 (6.00%) low mild + 2 (2.00%) high mild + +cmp_f32_unord system time: [8.1236 µs 8.1736 µs 8.2350 µs] +Found 18 outliers among 100 measurements (18.00%) + 5 (5.00%) high mild + 13 (13.00%) high severe + +cmp_f32_unord assembly (aarch64 unix) + time: [8.1446 µs 8.2080 µs 8.2762 µs] +Found 14 outliers among 100 measurements (14.00%) + 6 (6.00%) high mild + 8 (8.00%) high severe + +cmp_f64_gt compiler-builtins + time: [16.073 µs 16.077 µs 16.082 µs] +Found 17 outliers among 100 measurements (17.00%) + 2 (2.00%) low mild + 4 (4.00%) high mild + 11 (11.00%) high severe + +cmp_f64_gt system time: [12.456 µs 12.487 µs 12.522 µs] +Found 3 outliers among 100 measurements (3.00%) + 2 (2.00%) high mild + 1 (1.00%) high severe + +cmp_f64_gt assembly (aarch64 unix) + time: [8.0557 µs 8.0616 µs 8.0685 µs] +Found 3 outliers among 100 measurements (3.00%) + 1 (1.00%) high mild + 2 (2.00%) high severe + +cmp_f64_unord compiler-builtins + time: [10.715 µs 10.724 µs 10.737 µs] +Found 13 outliers among 100 measurements (13.00%) + 3 (3.00%) high mild + 10 (10.00%) high severe + +cmp_f64_unord system time: [8.0692 µs 8.0734 µs 8.0784 µs] +Found 3 outliers among 100 measurements (3.00%) + 1 (1.00%) high mild + 2 (2.00%) high severe + +cmp_f64_unord assembly (aarch64 unix) + time: [8.0569 µs 8.0677 µs 8.0818 µs] +Found 18 outliers among 100 measurements (18.00%) + 4 (4.00%) high mild + 14 (14.00%) high severe + +cmp_f128_gt compiler-builtins + time: [18.234 µs 18.401 µs 18.602 µs] + +cmp_f128_unord compiler-builtins + time: [13.410 µs 13.471 µs 13.542 µs] +Found 7 outliers among 100 measurements (7.00%) + 7 (7.00%) high mild + +conv_u32_f32 compiler-builtins + time: [774.58 ns 776.01 ns 777.59 ns] +Found 9 outliers among 100 measurements (9.00%) + 2 (2.00%) high mild + 7 (7.00%) high severe + +conv_u32_f32 system time: [622.68 ns 625.64 ns 629.26 ns] +Found 16 outliers among 100 measurements (16.00%) + 7 (7.00%) high mild + 9 (9.00%) high severe + +conv_u32_f32 assembly (aarch64 unix) + time: [468.05 ns 469.76 ns 471.46 ns] +Found 3 outliers among 100 measurements (3.00%) + 2 (2.00%) high mild + 1 (1.00%) high severe + +conv_u32_f64 compiler-builtins + time: [617.61 ns 618.00 ns 618.52 ns] +Found 13 outliers among 100 measurements (13.00%) + 4 (4.00%) high mild + 9 (9.00%) high severe + +conv_u32_f64 system time: [469.56 ns 471.03 ns 472.81 ns] +Found 11 outliers among 100 measurements (11.00%) + 7 (7.00%) high mild + 4 (4.00%) high severe + +conv_u32_f64 assembly (aarch64 unix) + time: [464.43 ns 465.01 ns 465.72 ns] +Found 13 outliers among 100 measurements (13.00%) + 5 (5.00%) high mild + 8 (8.00%) high severe + +conv_u64_f32 compiler-builtins + time: [847.95 ns 848.19 ns 848.46 ns] +Found 19 outliers among 100 measurements (19.00%) + 3 (3.00%) low mild + 9 (9.00%) high mild + 7 (7.00%) high severe + +conv_u64_f32 system time: [701.68 ns 701.95 ns 702.30 ns] +Found 10 outliers among 100 measurements (10.00%) + 4 (4.00%) high mild + 6 (6.00%) high severe + +conv_u64_f32 assembly (aarch64 unix) + time: [511.73 ns 512.43 ns 513.32 ns] +Found 6 outliers among 100 measurements (6.00%) + 6 (6.00%) high mild + +conv_u64_f64 compiler-builtins + time: [681.23 ns 682.55 ns 684.30 ns] +Found 18 outliers among 100 measurements (18.00%) + 1 (1.00%) high mild + 17 (17.00%) high severe + +conv_u64_f64 system time: [679.34 ns 679.57 ns 679.88 ns] +Found 18 outliers among 100 measurements (18.00%) + 1 (1.00%) low mild + 6 (6.00%) high mild + 11 (11.00%) high severe + +conv_u64_f64 assembly (aarch64 unix) + time: [509.90 ns 510.09 ns 510.30 ns] +Found 15 outliers among 100 measurements (15.00%) + 6 (6.00%) high mild + 9 (9.00%) high severe + +conv_u128_f32 compiler-builtins + time: [1.1368 µs 1.1372 µs 1.1377 µs] +Found 14 outliers among 100 measurements (14.00%) + 8 (8.00%) high mild + 6 (6.00%) high severe + +conv_u128_f32 system time: [1.4338 µs 1.4370 µs 1.4410 µs] +Found 7 outliers among 100 measurements (7.00%) + 2 (2.00%) high mild + 5 (5.00%) high severe + +conv_u128_f64 compiler-builtins + time: [1.0133 µs 1.0143 µs 1.0156 µs] +Found 16 outliers among 100 measurements (16.00%) + 2 (2.00%) high mild + 14 (14.00%) high severe + +conv_u128_f64 system time: [1.3473 µs 1.3530 µs 1.3600 µs] +Found 4 outliers among 100 measurements (4.00%) + 4 (4.00%) high mild + +conv_i32_f32 compiler-builtins + time: [906.53 ns 907.86 ns 909.23 ns] +Found 7 outliers among 100 measurements (7.00%) + 4 (4.00%) high mild + 3 (3.00%) high severe + +conv_i32_f32 system time: [914.53 ns 915.69 ns 917.01 ns] +Found 10 outliers among 100 measurements (10.00%) + 6 (6.00%) high mild + 4 (4.00%) high severe + +conv_i32_f32 assembly (aarch64 unix) + time: [464.55 ns 465.10 ns 465.83 ns] +Found 4 outliers among 100 measurements (4.00%) + 4 (4.00%) high mild + +conv_i32_f64 compiler-builtins + time: [617.63 ns 617.92 ns 618.27 ns] +Found 12 outliers among 100 measurements (12.00%) + 3 (3.00%) high mild + 9 (9.00%) high severe + +conv_i32_f64 system time: [622.83 ns 624.19 ns 625.61 ns] +Found 6 outliers among 100 measurements (6.00%) + 5 (5.00%) high mild + 1 (1.00%) high severe + +conv_i32_f64 assembly (aarch64 unix) + time: [465.24 ns 466.04 ns 466.95 ns] +Found 11 outliers among 100 measurements (11.00%) + 4 (4.00%) high mild + 7 (7.00%) high severe + +conv_i64_f32 compiler-builtins + time: [852.67 ns 853.92 ns 855.34 ns] +Found 11 outliers among 100 measurements (11.00%) + 3 (3.00%) high mild + 8 (8.00%) high severe + +conv_i64_f32 system time: [906.94 ns 908.04 ns 909.33 ns] +Found 15 outliers among 100 measurements (15.00%) + 2 (2.00%) high mild + 13 (13.00%) high severe + +conv_i64_f32 assembly (aarch64 unix) + time: [510.84 ns 511.27 ns 511.80 ns] +Found 8 outliers among 100 measurements (8.00%) + 3 (3.00%) high mild + 5 (5.00%) high severe + +conv_i64_f64 compiler-builtins + time: [932.35 ns 932.97 ns 933.76 ns] +Found 10 outliers among 100 measurements (10.00%) + 4 (4.00%) high mild + 6 (6.00%) high severe + +conv_i64_f64 system time: [955.91 ns 958.95 ns 962.05 ns] +Found 5 outliers among 100 measurements (5.00%) + 3 (3.00%) high mild + 2 (2.00%) high severe + +conv_i64_f64 assembly (aarch64 unix) + time: [510.19 ns 510.72 ns 511.44 ns] +Found 9 outliers among 100 measurements (9.00%) + 5 (5.00%) high mild + 4 (4.00%) high severe + +conv_i128_f32 compiler-builtins + time: [1.4248 µs 1.4285 µs 1.4323 µs] +Found 12 outliers among 100 measurements (12.00%) + 7 (7.00%) high mild + 5 (5.00%) high severe + +conv_i128_f32 system time: [1.6970 µs 1.7017 µs 1.7069 µs] +Found 5 outliers among 100 measurements (5.00%) + 3 (3.00%) high mild + 2 (2.00%) high severe + +conv_i128_f64 compiler-builtins + time: [1.3132 µs 1.3161 µs 1.3191 µs] +Found 2 outliers among 100 measurements (2.00%) + 1 (1.00%) high mild + 1 (1.00%) high severe + +conv_i128_f64 system time: [1.6071 µs 1.6100 µs 1.6133 µs] +Found 4 outliers among 100 measurements (4.00%) + 3 (3.00%) high mild + 1 (1.00%) high severe + +conv_f64_u32 compiler-builtins + time: [640.35 ns 641.00 ns 641.68 ns] +Found 6 outliers among 100 measurements (6.00%) + 4 (4.00%) high mild + 2 (2.00%) high severe + +conv_f64_u32 system time: [640.87 ns 641.63 ns 642.42 ns] +Found 3 outliers among 100 measurements (3.00%) + 1 (1.00%) high mild + 2 (2.00%) high severe + +conv_f64_u32 assembly (aarch64 unix) + time: [482.02 ns 482.67 ns 483.38 ns] +Found 1 outliers among 100 measurements (1.00%) + 1 (1.00%) high severe + +conv_f64_u64 compiler-builtins + time: [638.58 ns 638.98 ns 639.45 ns] +Found 15 outliers among 100 measurements (15.00%) + 1 (1.00%) high mild + 14 (14.00%) high severe + +conv_f64_u64 system time: [642.54 ns 644.07 ns 645.59 ns] +Found 4 outliers among 100 measurements (4.00%) + 3 (3.00%) high mild + 1 (1.00%) high severe + +conv_f64_u64 assembly (aarch64 unix) + time: [482.65 ns 483.70 ns 484.87 ns] +Found 1 outliers among 100 measurements (1.00%) + 1 (1.00%) high mild + +conv_f64_u128 compiler-builtins + time: [1.0631 µs 1.0652 µs 1.0674 µs] +Found 8 outliers among 100 measurements (8.00%) + 7 (7.00%) high mild + 1 (1.00%) high severe + +conv_f64_u128 system time: [821.41 ns 823.45 ns 825.74 ns] +Found 11 outliers among 100 measurements (11.00%) + 8 (8.00%) high mild + 3 (3.00%) high severe + +conv_f64_i32 compiler-builtins + time: [826.76 ns 845.08 ns 870.23 ns] +Found 4 outliers among 100 measurements (4.00%) + 4 (4.00%) high mild + +conv_f64_i32 system time: [764.12 ns 764.63 ns 765.26 ns] +Found 2 outliers among 100 measurements (2.00%) + 2 (2.00%) high severe + +conv_f64_i32 assembly (aarch64 unix) + time: [484.50 ns 485.98 ns 487.54 ns] +Found 3 outliers among 100 measurements (3.00%) + 1 (1.00%) high mild + 2 (2.00%) high severe + +conv_f64_i64 compiler-builtins + time: [797.27 ns 798.19 ns 799.84 ns] +Found 9 outliers among 100 measurements (9.00%) + 5 (5.00%) high mild + 4 (4.00%) high severe + +conv_f64_i64 system time: [768.74 ns 769.52 ns 770.23 ns] +Found 1 outliers among 100 measurements (1.00%) + 1 (1.00%) high severe + +conv_f64_i64 assembly (aarch64 unix) + time: [480.59 ns 481.03 ns 481.46 ns] +Found 3 outliers among 100 measurements (3.00%) + 2 (2.00%) high mild + 1 (1.00%) high severe + +conv_f64_i128 compiler-builtins + time: [1.0577 µs 1.0591 µs 1.0606 µs] +Found 2 outliers among 100 measurements (2.00%) + 1 (1.00%) high mild + 1 (1.00%) high severe + +conv_f64_i128 system time: [1.0181 µs 1.0195 µs 1.0211 µs] +Found 3 outliers among 100 measurements (3.00%) + 3 (3.00%) high mild + +conv_f32_u32 compiler-builtins + time: [800.40 ns 801.39 ns 802.35 ns] +Found 2 outliers among 100 measurements (2.00%) + 2 (2.00%) high mild + +conv_f32_u32 system time: [638.12 ns 638.34 ns 638.63 ns] +Found 11 outliers among 100 measurements (11.00%) + 4 (4.00%) high mild + 7 (7.00%) high severe + +conv_f32_u32 assembly (aarch64 unix) + time: [479.37 ns 480.97 ns 483.32 ns] +Found 13 outliers among 100 measurements (13.00%) + 6 (6.00%) high mild + 7 (7.00%) high severe + +conv_f32_u64 compiler-builtins + time: [801.95 ns 803.64 ns 805.75 ns] + +conv_f32_u64 system time: [638.20 ns 638.56 ns 639.07 ns] +Found 10 outliers among 100 measurements (10.00%) + 1 (1.00%) high mild + 9 (9.00%) high severe + +conv_f32_u64 assembly (aarch64 unix) + time: [480.07 ns 480.47 ns 480.86 ns] +Found 2 outliers among 100 measurements (2.00%) + 1 (1.00%) high mild + 1 (1.00%) high severe + +conv_f32_u128 compiler-builtins + time: [1.1579 µs 1.1623 µs 1.1657 µs] +Found 14 outliers among 100 measurements (14.00%) + 2 (2.00%) low severe + 7 (7.00%) high mild + 5 (5.00%) high severe + +conv_f32_u128 system time: [1.0344 µs 1.0394 µs 1.0450 µs] + +conv_f32_i32 compiler-builtins + time: [800.14 ns 801.52 ns 803.26 ns] +Found 10 outliers among 100 measurements (10.00%) + 8 (8.00%) high mild + 2 (2.00%) high severe + +conv_f32_i32 system time: [741.36 ns 741.74 ns 742.13 ns] +Found 4 outliers among 100 measurements (4.00%) + 2 (2.00%) high mild + 2 (2.00%) high severe + +conv_f32_i32 assembly (aarch64 unix) + time: [484.35 ns 486.08 ns 488.11 ns] +Found 17 outliers among 100 measurements (17.00%) + 9 (9.00%) high mild + 8 (8.00%) high severe + +conv_f32_i64 compiler-builtins + time: [800.94 ns 802.68 ns 804.74 ns] + +conv_f32_i64 system time: [748.60 ns 750.68 ns 753.16 ns] +Found 9 outliers among 100 measurements (9.00%) + 4 (4.00%) high mild + 5 (5.00%) high severe + +conv_f32_i64 assembly (aarch64 unix) + time: [480.70 ns 481.23 ns 481.82 ns] +Found 4 outliers among 100 measurements (4.00%) + 2 (2.00%) high mild + 2 (2.00%) high severe + +conv_f32_i128 compiler-builtins + time: [1.1774 µs 1.1829 µs 1.1887 µs] +Found 11 outliers among 100 measurements (11.00%) + 1 (1.00%) low severe + 7 (7.00%) low mild + 1 (1.00%) high mild + 2 (2.00%) high severe + +conv_f32_i128 system time: [1.1785 µs 1.1853 µs 1.1941 µs] +Found 7 outliers among 100 measurements (7.00%) + 2 (2.00%) high mild + 5 (5.00%) high severe + +div_f32 compiler-builtins + time: [38.852 µs 39.011 µs 39.178 µs] +Found 3 outliers among 100 measurements (3.00%) + 3 (3.00%) high mild + +div_f32 system time: [41.846 µs 41.920 µs 42.005 µs] +Found 3 outliers among 100 measurements (3.00%) + 1 (1.00%) high mild + 2 (2.00%) high severe + +div_f32 assembly (aarch64 unix) + time: [8.1309 µs 8.1627 µs 8.2005 µs] +Found 2 outliers among 100 measurements (2.00%) + 2 (2.00%) high mild + +div_f64 compiler-builtins + time: [50.369 µs 50.605 µs 50.857 µs] +Found 15 outliers among 100 measurements (15.00%) + 11 (11.00%) high mild + 4 (4.00%) high severe + +div_f64 system time: [53.506 µs 53.582 µs 53.676 µs] +Found 8 outliers among 100 measurements (8.00%) + 4 (4.00%) high mild + 4 (4.00%) high severe + +div_f64 assembly (aarch64 unix) + time: [8.0695 µs 8.0807 µs 8.0948 µs] +Found 4 outliers among 100 measurements (4.00%) + 2 (2.00%) high mild + 2 (2.00%) high severe + diff --git a/library/compiler-builtins/testcrate/bench-3cee6376-aarch64-macos.txt b/library/compiler-builtins/testcrate/bench-3cee6376-aarch64-macos.txt new file mode 100644 index 0000000000000..131e7a85a0b55 --- /dev/null +++ b/library/compiler-builtins/testcrate/bench-3cee6376-aarch64-macos.txt @@ -0,0 +1,699 @@ + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + +add_f32/compiler-builtins + time: [36.813 µs 37.048 µs 37.303 µs] +Found 5 outliers among 100 measurements (5.00%) + 5 (5.00%) high mild +add_f32/system time: [39.103 µs 39.142 µs 39.189 µs] +Found 8 outliers among 100 measurements (8.00%) + 2 (2.00%) high mild + 6 (6.00%) high severe +add_f32/assembly (aarch64 unix) + time: [8.3786 µs 8.4680 µs 8.5570 µs] + +add_f64/compiler-builtins + time: [35.784 µs 35.819 µs 35.863 µs] +Found 4 outliers among 100 measurements (4.00%) + 1 (1.00%) high mild + 3 (3.00%) high severe +add_f64/system time: [39.634 µs 39.689 µs 39.746 µs] +Found 16 outliers among 100 measurements (16.00%) + 4 (4.00%) high mild + 12 (12.00%) high severe +add_f64/assembly (aarch64 unix) + time: [8.0533 µs 8.0599 µs 8.0670 µs] +Found 14 outliers among 100 measurements (14.00%) + 6 (6.00%) high mild + 8 (8.00%) high severe + +add_f128/compiler-builtins + time: [41.830 µs 41.920 µs 42.005 µs] + +cmp_f32_gt/compiler-builtins + time: [13.405 µs 13.411 µs 13.418 µs] +Found 18 outliers among 100 measurements (18.00%) + 4 (4.00%) high mild + 14 (14.00%) high severe +cmp_f32_gt/system time: [12.348 µs 12.355 µs 12.363 µs] +Found 12 outliers among 100 measurements (12.00%) + 2 (2.00%) high mild + 10 (10.00%) high severe +cmp_f32_gt/assembly (aarch64 unix) + time: [8.1233 µs 8.1625 µs 8.2072 µs] +Found 12 outliers among 100 measurements (12.00%) + 7 (7.00%) high mild + 5 (5.00%) high severe + +cmp_f32_unord/compiler-builtins + time: [11.349 µs 11.467 µs 11.584 µs] +cmp_f32_unord/system time: [8.0714 µs 8.0792 µs 8.0890 µs] +Found 16 outliers among 100 measurements (16.00%) + 4 (4.00%) high mild + 12 (12.00%) high severe +cmp_f32_unord/assembly (aarch64 unix) + time: [8.1121 µs 8.1705 µs 8.2325 µs] +Found 20 outliers among 100 measurements (20.00%) + 3 (3.00%) high mild + 17 (17.00%) high severe + +cmp_f64_gt/compiler-builtins + time: [13.749 µs 13.837 µs 13.934 µs] +Found 20 outliers among 100 measurements (20.00%) + 9 (9.00%) low mild + 7 (7.00%) high mild + 4 (4.00%) high severe +cmp_f64_gt/system time: [12.475 µs 12.515 µs 12.565 µs] +Found 4 outliers among 100 measurements (4.00%) + 4 (4.00%) high mild +cmp_f64_gt/assembly (aarch64 unix) + time: [8.0456 µs 8.0540 µs 8.0653 µs] +Found 12 outliers among 100 measurements (12.00%) + 3 (3.00%) high mild + 9 (9.00%) high severe + +cmp_f64_unord/compiler-builtins + time: [10.723 µs 10.730 µs 10.739 µs] +Found 15 outliers among 100 measurements (15.00%) + 5 (5.00%) high mild + 10 (10.00%) high severe +cmp_f64_unord/system time: [8.0944 µs 8.1296 µs 8.1683 µs] +Found 17 outliers among 100 measurements (17.00%) + 4 (4.00%) high mild + 13 (13.00%) high severe +cmp_f64_unord/assembly (aarch64 unix) + time: [8.1042 µs 8.1337 µs 8.1662 µs] +Found 3 outliers among 100 measurements (3.00%) + 3 (3.00%) high mild + +cmp_f128_gt/compiler-builtins + time: [20.508 µs 20.558 µs 20.615 µs] +Found 8 outliers among 100 measurements (8.00%) + 2 (2.00%) high mild + 6 (6.00%) high severe + +cmp_f128_unord/compiler-builtins + time: [13.332 µs 13.346 µs 13.360 µs] +Found 4 outliers among 100 measurements (4.00%) + 2 (2.00%) high mild + 2 (2.00%) high severe + +conv_u32_f32/compiler-builtins + time: [621.20 ns 621.89 ns 622.65 ns] +Found 7 outliers among 100 measurements (7.00%) + 4 (4.00%) high mild + 3 (3.00%) high severe +conv_u32_f32/system time: [621.44 ns 622.08 ns 622.74 ns] +Found 4 outliers among 100 measurements (4.00%) + 3 (3.00%) high mild + 1 (1.00%) high severe +conv_u32_f32/assembly (aarch64 unix) + time: [465.96 ns 466.65 ns 467.45 ns] +Found 13 outliers among 100 measurements (13.00%) + 3 (3.00%) high mild + 10 (10.00%) high severe + +conv_u32_f64/compiler-builtins + time: [619.71 ns 620.51 ns 621.52 ns] +Found 5 outliers among 100 measurements (5.00%) + 4 (4.00%) high mild + 1 (1.00%) high severe +conv_u32_f64/system time: [466.60 ns 467.14 ns 467.77 ns] +Found 2 outliers among 100 measurements (2.00%) + 2 (2.00%) high mild +conv_u32_f64/assembly (aarch64 unix) + time: [464.02 ns 464.32 ns 464.69 ns] +Found 2 outliers among 100 measurements (2.00%) + 1 (1.00%) high mild + 1 (1.00%) high severe + +conv_u64_f32/compiler-builtins + time: [851.24 ns 852.98 ns 854.77 ns] +Found 5 outliers among 100 measurements (5.00%) + 5 (5.00%) high mild +conv_u64_f32/system time: [724.35 ns 729.43 ns 735.07 ns] +Found 4 outliers among 100 measurements (4.00%) + 4 (4.00%) high mild +conv_u64_f32/assembly (aarch64 unix) + time: [513.30 ns 514.64 ns 516.16 ns] +Found 8 outliers among 100 measurements (8.00%) + 8 (8.00%) high mild + +conv_u64_f64/compiler-builtins + time: [850.72 ns 853.26 ns 856.54 ns] +Found 15 outliers among 100 measurements (15.00%) + 2 (2.00%) high mild + 13 (13.00%) high severe +conv_u64_f64/system time: [681.43 ns 682.54 ns 683.79 ns] +Found 4 outliers among 100 measurements (4.00%) + 3 (3.00%) high mild + 1 (1.00%) high severe +conv_u64_f64/assembly (aarch64 unix) + time: [511.37 ns 511.71 ns 512.02 ns] +Found 1 outliers among 100 measurements (1.00%) + 1 (1.00%) high severe + +conv_u128_f32/compiler-builtins + time: [1.1395 µs 1.1409 µs 1.1424 µs] +Found 10 outliers among 100 measurements (10.00%) + 6 (6.00%) high mild + 4 (4.00%) high severe +conv_u128_f32/system time: [1.4348 µs 1.4369 µs 1.4390 µs] +Found 5 outliers among 100 measurements (5.00%) + 4 (4.00%) high mild + 1 (1.00%) high severe + +conv_u128_f64/compiler-builtins + time: [1.0148 µs 1.0157 µs 1.0167 µs] +Found 4 outliers among 100 measurements (4.00%) + 3 (3.00%) high mild + 1 (1.00%) high severe +conv_u128_f64/system time: [1.3404 µs 1.3423 µs 1.3442 µs] +Found 8 outliers among 100 measurements (8.00%) + 7 (7.00%) high mild + 1 (1.00%) high severe + +conv_i32_f32/compiler-builtins + time: [902.89 ns 903.81 ns 904.84 ns] +Found 7 outliers among 100 measurements (7.00%) + 4 (4.00%) high mild + 3 (3.00%) high severe +conv_i32_f32/system time: [942.62 ns 949.04 ns 955.77 ns] +Found 4 outliers among 100 measurements (4.00%) + 3 (3.00%) high mild + 1 (1.00%) high severe +conv_i32_f32/assembly (aarch64 unix) + time: [466.06 ns 466.60 ns 467.27 ns] +Found 1 outliers among 100 measurements (1.00%) + 1 (1.00%) high severe + +conv_i32_f64/compiler-builtins + time: [618.98 ns 619.24 ns 619.55 ns] +Found 17 outliers among 100 measurements (17.00%) + 1 (1.00%) low mild + 3 (3.00%) high mild + 13 (13.00%) high severe +conv_i32_f64/system time: [622.18 ns 623.41 ns 624.85 ns] +Found 8 outliers among 100 measurements (8.00%) + 5 (5.00%) high mild + 3 (3.00%) high severe +conv_i32_f64/assembly (aarch64 unix) + time: [466.26 ns 466.76 ns 467.35 ns] +Found 9 outliers among 100 measurements (9.00%) + 5 (5.00%) high mild + 4 (4.00%) high severe + +conv_i64_f32/compiler-builtins + time: [850.11 ns 850.45 ns 850.88 ns] +Found 15 outliers among 100 measurements (15.00%) + 1 (1.00%) low severe + 1 (1.00%) low mild + 3 (3.00%) high mild + 10 (10.00%) high severe +conv_i64_f32/system time: [908.36 ns 908.70 ns 909.10 ns] +Found 12 outliers among 100 measurements (12.00%) + 3 (3.00%) high mild + 9 (9.00%) high severe +conv_i64_f32/assembly (aarch64 unix) + time: [513.56 ns 514.44 ns 515.38 ns] +Found 8 outliers among 100 measurements (8.00%) + 8 (8.00%) high mild + +conv_i64_f64/compiler-builtins + time: [935.39 ns 935.78 ns 936.26 ns] +Found 13 outliers among 100 measurements (13.00%) + 5 (5.00%) high mild + 8 (8.00%) high severe +conv_i64_f64/system time: [946.56 ns 947.33 ns 948.20 ns] +Found 8 outliers among 100 measurements (8.00%) + 6 (6.00%) high mild + 2 (2.00%) high severe +conv_i64_f64/assembly (aarch64 unix) + time: [511.55 ns 512.03 ns 512.56 ns] +Found 21 outliers among 100 measurements (21.00%) + 4 (4.00%) high mild + 17 (17.00%) high severe + +conv_i128_f32/compiler-builtins + time: [1.4206 µs 1.4218 µs 1.4232 µs] +Found 10 outliers among 100 measurements (10.00%) + 5 (5.00%) high mild + 5 (5.00%) high severe +conv_i128_f32/system time: [1.6863 µs 1.6891 µs 1.6922 µs] +Found 10 outliers among 100 measurements (10.00%) + 9 (9.00%) high mild + 1 (1.00%) high severe + +conv_i128_f64/compiler-builtins + time: [1.3110 µs 1.3122 µs 1.3136 µs] +Found 4 outliers among 100 measurements (4.00%) + 2 (2.00%) high mild + 2 (2.00%) high severe +conv_i128_f64/system time: [1.6022 µs 1.6048 µs 1.6090 µs] +Found 5 outliers among 100 measurements (5.00%) + 3 (3.00%) high mild + 2 (2.00%) high severe + +conv_f64_u32/compiler-builtins + time: [798.65 ns 799.42 ns 800.39 ns] +Found 15 outliers among 100 measurements (15.00%) + 6 (6.00%) high mild + 9 (9.00%) high severe +conv_f64_u32/system time: [639.48 ns 639.88 ns 640.40 ns] +Found 16 outliers among 100 measurements (16.00%) + 1 (1.00%) low mild + 5 (5.00%) high mild + 10 (10.00%) high severe +conv_f64_u32/assembly (aarch64 unix) + time: [480.78 ns 481.35 ns 482.17 ns] +Found 7 outliers among 100 measurements (7.00%) + 5 (5.00%) high mild + 2 (2.00%) high severe + +conv_f64_u64/compiler-builtins + time: [799.56 ns 800.54 ns 801.89 ns] +Found 4 outliers among 100 measurements (4.00%) + 2 (2.00%) high mild + 2 (2.00%) high severe +conv_f64_u64/system time: [640.72 ns 641.24 ns 641.81 ns] +Found 5 outliers among 100 measurements (5.00%) + 3 (3.00%) high mild + 2 (2.00%) high severe +conv_f64_u64/assembly (aarch64 unix) + time: [481.54 ns 482.48 ns 483.53 ns] +Found 6 outliers among 100 measurements (6.00%) + 1 (1.00%) low severe + 1 (1.00%) low mild + 3 (3.00%) high mild + 1 (1.00%) high severe + +conv_f64_u128/compiler-builtins + time: [1.0510 µs 1.0515 µs 1.0520 µs] +Found 13 outliers among 100 measurements (13.00%) + 1 (1.00%) low mild + 2 (2.00%) high mild + 10 (10.00%) high severe +conv_f64_u128/system time: [818.45 ns 819.23 ns 820.15 ns] +Found 2 outliers among 100 measurements (2.00%) + 2 (2.00%) high mild + +conv_f64_i32/compiler-builtins + time: [800.56 ns 801.31 ns 802.21 ns] +Found 5 outliers among 100 measurements (5.00%) + 3 (3.00%) high mild + 2 (2.00%) high severe +conv_f64_i32/system time: [765.62 ns 766.15 ns 766.80 ns] +Found 3 outliers among 100 measurements (3.00%) + 2 (2.00%) high mild + 1 (1.00%) high severe +conv_f64_i32/assembly (aarch64 unix) + time: [471.65 ns 472.77 ns 473.89 ns] +Found 10 outliers among 100 measurements (10.00%) + 1 (1.00%) low mild + 8 (8.00%) high mild + 1 (1.00%) high severe + +conv_f64_i64/compiler-builtins + time: [801.00 ns 804.55 ns 808.72 ns] +Found 18 outliers among 100 measurements (18.00%) + 6 (6.00%) high mild + 12 (12.00%) high severe +conv_f64_i64/system time: [770.28 ns 772.47 ns 775.21 ns] +Found 2 outliers among 100 measurements (2.00%) + 2 (2.00%) high mild +conv_f64_i64/assembly (aarch64 unix) + time: [491.56 ns 494.96 ns 499.19 ns] +Found 3 outliers among 100 measurements (3.00%) + 2 (2.00%) high mild + 1 (1.00%) high severe + +conv_f64_i128/compiler-builtins + time: [1.0637 µs 1.0704 µs 1.0762 µs] +Found 5 outliers among 100 measurements (5.00%) + 5 (5.00%) high mild +conv_f64_i128/system time: [1.0022 µs 1.0027 µs 1.0033 µs] +Found 4 outliers among 100 measurements (4.00%) + 1 (1.00%) low severe + 3 (3.00%) high severe + +conv_f32_u32/compiler-builtins + time: [644.56 ns 647.01 ns 649.95 ns] +Found 15 outliers among 100 measurements (15.00%) + 13 (13.00%) high mild + 2 (2.00%) high severe +conv_f32_u32/system time: [648.12 ns 651.20 ns 654.54 ns] +Found 9 outliers among 100 measurements (9.00%) + 7 (7.00%) high mild + 2 (2.00%) high severe +conv_f32_u32/assembly (aarch64 unix) + time: [481.02 ns 482.71 ns 484.60 ns] +Found 12 outliers among 100 measurements (12.00%) + 1 (1.00%) low mild + 10 (10.00%) high mild + 1 (1.00%) high severe + +conv_f32_u64/compiler-builtins + time: [644.14 ns 646.61 ns 649.53 ns] +Found 11 outliers among 100 measurements (11.00%) + 6 (6.00%) high mild + 5 (5.00%) high severe +conv_f32_u64/system time: [646.21 ns 650.17 ns 654.55 ns] +Found 3 outliers among 100 measurements (3.00%) + 3 (3.00%) high mild +conv_f32_u64/assembly (aarch64 unix) + time: [473.36 ns 474.60 ns 476.00 ns] +Found 9 outliers among 100 measurements (9.00%) + 2 (2.00%) low mild + 5 (5.00%) high mild + 2 (2.00%) high severe + +conv_f32_u128/compiler-builtins + time: [1.0820 µs 1.0828 µs 1.0839 µs] +Found 2 outliers among 100 measurements (2.00%) + 1 (1.00%) high mild + 1 (1.00%) high severe +conv_f32_u128/system time: [1.0003 µs 1.0042 µs 1.0076 µs] +Found 21 outliers among 100 measurements (21.00%) + 1 (1.00%) low mild + 3 (3.00%) high mild + 17 (17.00%) high severe + +conv_f32_i32/compiler-builtins + time: [801.13 ns 801.82 ns 802.53 ns] +Found 2 outliers among 100 measurements (2.00%) + 2 (2.00%) high severe +conv_f32_i32/system time: [745.17 ns 745.97 ns 746.78 ns] +Found 2 outliers among 100 measurements (2.00%) + 2 (2.00%) high severe +conv_f32_i32/assembly (aarch64 unix) + time: [469.87 ns 470.65 ns 471.57 ns] +Found 1 outliers among 100 measurements (1.00%) + 1 (1.00%) high mild + +conv_f32_i64/compiler-builtins + time: [799.44 ns 799.94 ns 800.59 ns] +Found 4 outliers among 100 measurements (4.00%) + 1 (1.00%) high mild + 3 (3.00%) high severe +conv_f32_i64/system time: [744.81 ns 745.17 ns 745.62 ns] +Found 14 outliers among 100 measurements (14.00%) + 5 (5.00%) high mild + 9 (9.00%) high severe +conv_f32_i64/assembly (aarch64 unix) + time: [465.06 ns 466.01 ns 467.12 ns] +Found 13 outliers among 100 measurements (13.00%) + 2 (2.00%) low severe + 5 (5.00%) high mild + 6 (6.00%) high severe + +conv_f32_i128/compiler-builtins + time: [1.1390 µs 1.1515 µs 1.1637 µs] +conv_f32_i128/system time: [1.1315 µs 1.1330 µs 1.1347 µs] +Found 6 outliers among 100 measurements (6.00%) + 3 (3.00%) low mild + 2 (2.00%) high mild + 1 (1.00%) high severe + +div_f32/compiler-builtins + time: [39.408 µs 39.676 µs 39.969 µs] +Found 5 outliers among 100 measurements (5.00%) + 5 (5.00%) high mild +div_f32/system time: [42.108 µs 42.248 µs 42.528 µs] +Found 11 outliers among 100 measurements (11.00%) + 4 (4.00%) high mild + 7 (7.00%) high severe +div_f32/assembly (aarch64 unix) + time: [8.0724 µs 8.0794 µs 8.0870 µs] +Found 7 outliers among 100 measurements (7.00%) + 5 (5.00%) high mild + 2 (2.00%) high severe + +div_f64/compiler-builtins + time: [49.992 µs 50.014 µs 50.040 µs] +Found 5 outliers among 100 measurements (5.00%) + 5 (5.00%) high severe +div_f64/system time: [53.577 µs 53.651 µs 53.743 µs] +Found 6 outliers among 100 measurements (6.00%) + 4 (4.00%) high mild + 2 (2.00%) high severe +div_f64/assembly (aarch64 unix) + time: [8.0976 µs 8.1064 µs 8.1158 µs] +Found 6 outliers among 100 measurements (6.00%) + 3 (3.00%) high mild + 3 (3.00%) high severe + +extend_f16_f32/compiler-builtins + time: [804.09 ns 805.38 ns 807.09 ns] +Found 3 outliers among 100 measurements (3.00%) + 1 (1.00%) high mild + 2 (2.00%) high severe +extend_f16_f32/system time: [641.07 ns 641.76 ns 642.60 ns] +Found 12 outliers among 100 measurements (12.00%) + 6 (6.00%) high mild + 6 (6.00%) high severe +extend_f16_f32/assembly (aarch64 unix) + time: [456.69 ns 457.14 ns 457.68 ns] +Found 8 outliers among 100 measurements (8.00%) + 4 (4.00%) low mild + 2 (2.00%) high mild + 2 (2.00%) high severe + +extend_f16_f128/compiler-builtins + time: [1.1025 µs 1.1035 µs 1.1045 µs] +Found 2 outliers among 100 measurements (2.00%) + 1 (1.00%) high mild + 1 (1.00%) high severe + +extend_f32_f64/compiler-builtins + time: [799.30 ns 799.68 ns 800.16 ns] +Found 13 outliers among 100 measurements (13.00%) + 3 (3.00%) high mild + 10 (10.00%) high severe +extend_f32_f64/system time: [992.48 ns 993.27 ns 994.32 ns] +Found 15 outliers among 100 measurements (15.00%) + 3 (3.00%) high mild + 12 (12.00%) high severe +extend_f32_f64/assembly (aarch64 unix) + time: [457.65 ns 460.39 ns 463.78 ns] + +extend_f32_f128/compiler-builtins + time: [1.0295 µs 1.0311 µs 1.0327 µs] +Found 3 outliers among 100 measurements (3.00%) + 2 (2.00%) low mild + 1 (1.00%) high mild + +extend_f64_f128/compiler-builtins + time: [1.0400 µs 1.0412 µs 1.0426 µs] +Found 2 outliers among 100 measurements (2.00%) + 2 (2.00%) high mild + +mul_f32/compiler-builtins + time: [25.604 µs 25.705 µs 25.818 µs] +Found 23 outliers among 100 measurements (23.00%) + 17 (17.00%) low severe + 3 (3.00%) high mild + 3 (3.00%) high severe +mul_f32/system time: [29.914 µs 29.977 µs 30.043 µs] +Found 5 outliers among 100 measurements (5.00%) + 5 (5.00%) high mild +mul_f32/assembly (aarch64 unix) + time: [8.1384 µs 8.1964 µs 8.2603 µs] +Found 13 outliers among 100 measurements (13.00%) + 3 (3.00%) high mild + 10 (10.00%) high severe + +mul_f64/compiler-builtins + time: [25.596 µs 25.615 µs 25.637 µs] +Found 3 outliers among 100 measurements (3.00%) + 2 (2.00%) high mild + 1 (1.00%) high severe +mul_f64/system time: [30.931 µs 30.963 µs 31.002 µs] +Found 3 outliers among 100 measurements (3.00%) + 3 (3.00%) high mild +mul_f64/assembly (aarch64 unix) + time: [8.0589 µs 8.0638 µs 8.0695 µs] +Found 3 outliers among 100 measurements (3.00%) + 1 (1.00%) high mild + 2 (2.00%) high severe + +mul_f128/compiler-builtins + time: [54.242 µs 54.306 µs 54.374 µs] +Found 3 outliers among 100 measurements (3.00%) + 2 (2.00%) high mild + 1 (1.00%) high severe + +powi_f32/compiler-builtins + time: [129.91 µs 130.09 µs 130.24 µs] +powi_f32/system time: [126.97 µs 127.34 µs 127.82 µs] +Found 4 outliers among 100 measurements (4.00%) + 3 (3.00%) high mild + 1 (1.00%) high severe + +powi_f64/compiler-builtins + time: [130.08 µs 130.81 µs 131.46 µs] +Found 13 outliers among 100 measurements (13.00%) + 13 (13.00%) high mild +powi_f64/system time: [128.51 µs 128.68 µs 128.88 µs] +Found 21 outliers among 100 measurements (21.00%) + 4 (4.00%) high mild + 17 (17.00%) high severe + +sub_f32/compiler-builtins + time: [37.861 µs 38.012 µs 38.158 µs] +Found 26 outliers among 100 measurements (26.00%) + 18 (18.00%) low mild + 7 (7.00%) high mild + 1 (1.00%) high severe +sub_f32/system time: [39.586 µs 39.628 µs 39.673 µs] +Found 2 outliers among 100 measurements (2.00%) + 1 (1.00%) high mild + 1 (1.00%) high severe +sub_f32/assembly (aarch64 unix) + time: [8.0976 µs 8.1584 µs 8.2208 µs] +Found 6 outliers among 100 measurements (6.00%) + 6 (6.00%) high mild + +sub_f64/compiler-builtins + time: [37.755 µs 37.838 µs 37.921 µs] +Found 25 outliers among 100 measurements (25.00%) + 7 (7.00%) low severe + 3 (3.00%) low mild + 4 (4.00%) high mild + 11 (11.00%) high severe +sub_f64/system time: [39.979 µs 40.019 µs 40.064 µs] +Found 3 outliers among 100 measurements (3.00%) + 2 (2.00%) high mild + 1 (1.00%) high severe +sub_f64/assembly (aarch64 unix) + time: [8.0669 µs 8.0733 µs 8.0801 µs] +Found 7 outliers among 100 measurements (7.00%) + 3 (3.00%) high mild + 4 (4.00%) high severe + +sub_f128/compiler-builtins + time: [68.618 µs 68.899 µs 69.293 µs] +Found 11 outliers among 100 measurements (11.00%) + 2 (2.00%) high mild + 9 (9.00%) high severe + +trunc_f32_f16/compiler-builtins + time: [1.3343 µs 1.3468 µs 1.3608 µs] +Found 3 outliers among 100 measurements (3.00%) + 1 (1.00%) high mild + 2 (2.00%) high severe +trunc_f32_f16/system time: [1.2687 µs 1.2714 µs 1.2738 µs] +trunc_f32_f16/assembly (aarch64 unix) + time: [470.06 ns 472.96 ns 475.30 ns] + +trunc_f64_f16/compiler-builtins + time: [1.2729 µs 1.2738 µs 1.2749 µs] +Found 7 outliers among 100 measurements (7.00%) + 2 (2.00%) high mild + 5 (5.00%) high severe +trunc_f64_f16/assembly (aarch64 unix) + time: [455.91 ns 456.61 ns 457.33 ns] +Found 12 outliers among 100 measurements (12.00%) + 1 (1.00%) low severe + 2 (2.00%) low mild + 6 (6.00%) high mild + 3 (3.00%) high severe + +trunc_f64_f32/compiler-builtins + time: [1.2240 µs 1.2325 µs 1.2410 µs] +Found 17 outliers among 100 measurements (17.00%) + 4 (4.00%) low mild + 2 (2.00%) high mild + 11 (11.00%) high severe +trunc_f64_f32/system time: [1.2784 µs 1.2835 µs 1.2884 µs] +Found 10 outliers among 100 measurements (10.00%) + 6 (6.00%) low severe + 1 (1.00%) low mild + 2 (2.00%) high mild + 1 (1.00%) high severe +trunc_f64_f32/assembly (aarch64 unix) + time: [455.64 ns 456.08 ns 456.58 ns] +Found 18 outliers among 100 measurements (18.00%) + 3 (3.00%) low severe + 4 (4.00%) low mild + 8 (8.00%) high mild + 3 (3.00%) high severe + +trunc_f128_f16/compiler-builtins + time: [1.2563 µs 1.2666 µs 1.2776 µs] +Found 3 outliers among 100 measurements (3.00%) + 3 (3.00%) high mild + +trunc_f128_f32/compiler-builtins + time: [1.2459 µs 1.2482 µs 1.2507 µs] +Found 6 outliers among 100 measurements (6.00%) + 2 (2.00%) low mild + 2 (2.00%) high mild + 2 (2.00%) high severe + +trunc_f128_f64/compiler-builtins + time: [1.2821 µs 1.3047 µs 1.3452 µs] +Found 8 outliers among 100 measurements (8.00%) + 4 (4.00%) low severe + 1 (1.00%) low mild + 2 (2.00%) high mild + 1 (1.00%) high severe + + +running 52 tests +test memcmp_builtin_1048576 ... bench: 20,975.52 ns/iter (+/- 239.69) = 49991 MB/s +test memcmp_builtin_16 ... bench: 1.60 ns/iter (+/- 0.05) = 16000 MB/s +test memcmp_builtin_32 ... bench: 1.61 ns/iter (+/- 0.03) = 32000 MB/s +test memcmp_builtin_4096 ... bench: 95.84 ns/iter (+/- 2.82) = 43115 MB/s +test memcmp_builtin_64 ... bench: 2.39 ns/iter (+/- 0.09) = 32000 MB/s +test memcmp_builtin_8 ... bench: 1.60 ns/iter (+/- 0.04) = 8000 MB/s +test memcmp_builtin_unaligned_1048575 ... bench: 22,060.00 ns/iter (+/- 873.55) = 47532 MB/s +test memcmp_builtin_unaligned_15 ... bench: 3.19 ns/iter (+/- 0.02) = 5333 MB/s +test memcmp_builtin_unaligned_31 ... bench: 1.61 ns/iter (+/- 0.01) = 32000 MB/s +test memcmp_builtin_unaligned_4095 ... bench: 96.63 ns/iter (+/- 4.58) = 42666 MB/s +test memcmp_builtin_unaligned_63 ... bench: 2.40 ns/iter (+/- 0.11) = 32000 MB/s +test memcmp_builtin_unaligned_7 ... bench: 3.37 ns/iter (+/- 0.05) = 2666 MB/s +test memcmp_rust_1048576 ... bench: 309,647.23 ns/iter (+/- 6,077.35) = 3386 MB/s +test memcmp_rust_16 ... bench: 5.66 ns/iter (+/- 0.30) = 3200 MB/s +test memcmp_rust_32 ... bench: 10.47 ns/iter (+/- 0.14) = 3200 MB/s +test memcmp_rust_4096 ... bench: 1,124.34 ns/iter (+/- 36.92) = 3644 MB/s +test memcmp_rust_64 ... bench: 19.90 ns/iter (+/- 0.36) = 3368 MB/s +test memcmp_rust_8 ... bench: 3.46 ns/iter (+/- 0.11) = 2666 MB/s +test memcmp_rust_unaligned_1048575 ... bench: 308,613.87 ns/iter (+/- 6,613.18) = 3397 MB/s +test memcmp_rust_unaligned_15 ... bench: 5.35 ns/iter (+/- 0.05) = 3200 MB/s +test memcmp_rust_unaligned_31 ... bench: 9.94 ns/iter (+/- 0.06) = 3555 MB/s +test memcmp_rust_unaligned_4095 ... bench: 1,120.06 ns/iter (+/- 5.03) = 3657 MB/s +test memcmp_rust_unaligned_63 ... bench: 19.64 ns/iter (+/- 0.82) = 3368 MB/s +test memcmp_rust_unaligned_7 ... bench: 3.22 ns/iter (+/- 0.10) = 2666 MB/s +test memcpy_builtin_1048576 ... bench: 12,538.05 ns/iter (+/- 354.79) = 83631 MB/s +test memcpy_builtin_1048576_misalign ... bench: 30,092.56 ns/iter (+/- 8,064.04) = 34845 MB/s +test memcpy_builtin_1048576_offset ... bench: 12,538.36 ns/iter (+/- 359.04) = 83631 MB/s +test memcpy_builtin_4096 ... bench: 44.24 ns/iter (+/- 6.80) = 93090 MB/s +test memcpy_builtin_4096_misalign ... bench: 45.34 ns/iter (+/- 2.13) = 91022 MB/s +test memcpy_builtin_4096_offset ... bench: 44.71 ns/iter (+/- 0.61) = 93090 MB/s +test memcpy_rust_1048576 ... bench: 17,943.33 ns/iter (+/- 243.18) = 58439 MB/s +test memcpy_rust_1048576_misalign ... bench: 15,004.68 ns/iter (+/- 3,978.65) = 69886 MB/s +test memcpy_rust_1048576_offset ... bench: 14,722.06 ns/iter (+/- 479.54) = 71225 MB/s +test memcpy_rust_4096 ... bench: 44.91 ns/iter (+/- 4.62) = 93090 MB/s +test memcpy_rust_4096_misalign ... bench: 76.21 ns/iter (+/- 8.21) = 53894 MB/s +test memcpy_rust_4096_offset ... bench: 76.27 ns/iter (+/- 4.69) = 53894 MB/s +test memmove_builtin_1048576 ... bench: 18,644.50 ns/iter (+/- 379.84) = 56242 MB/s +test memmove_builtin_1048576_misalign ... bench: 18,947.70 ns/iter (+/- 1,226.26) = 55342 MB/s +test memmove_builtin_4096 ... bench: 44.21 ns/iter (+/- 0.79) = 93090 MB/s +test memmove_builtin_4096_misalign ... bench: 47.21 ns/iter (+/- 3.12) = 87148 MB/s +test memmove_rust_1048576 ... bench: 34,813.33 ns/iter (+/- 3,637.47) = 30120 MB/s +test memmove_rust_1048576_misalign ... bench: 35,067.19 ns/iter (+/- 1,699.63) = 29902 MB/s +test memmove_rust_4096 ... bench: 148.69 ns/iter (+/- 1.31) = 27675 MB/s +test memmove_rust_4096_misalign ... bench: 153.81 ns/iter (+/- 1.71) = 26771 MB/s +test memset_builtin_1048576 ... bench: 15,704.12 ns/iter (+/- 12,113.86) = 66771 MB/s +test memset_builtin_1048576_offset ... bench: 17,894.23 ns/iter (+/- 175.12) = 58599 MB/s +test memset_builtin_4096 ... bench: 39.95 ns/iter (+/- 0.19) = 105025 MB/s +test memset_builtin_4096_offset ... bench: 40.48 ns/iter (+/- 3.11) = 102400 MB/s +test memset_rust_1048576 ... bench: 10,600.66 ns/iter (+/- 1,559.93) = 98922 MB/s +test memset_rust_1048576_offset ... bench: 14,810.85 ns/iter (+/- 575.27) = 70801 MB/s +test memset_rust_4096 ... bench: 37.91 ns/iter (+/- 2.77) = 110702 MB/s +test memset_rust_4096_offset ... bench: 59.99 ns/iter (+/- 10.45) = 69423 MB/s + +test result: ok. 0 passed; 0 failed; 0 ignored; 52 measured; 0 filtered out; finished in 97.74s + diff --git a/library/compiler-builtins/testcrate/benches/float_add.rs b/library/compiler-builtins/testcrate/benches/float_add.rs new file mode 100644 index 0000000000000..eef1ecc57c16d --- /dev/null +++ b/library/compiler-builtins/testcrate/benches/float_add.rs @@ -0,0 +1,81 @@ +#![feature(f128)] + +use compiler_builtins::float::add; +use criterion::{criterion_group, criterion_main, Criterion}; +use testcrate::float_bench; + +float_bench! { + name: add_f32, + sig: (a: f32, b: f32) -> f32, + crate_fn: add::__addsf3, + sys_fn: __addsf3, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + asm!( + "addss {a}, {b}", + a = inout(xmm_reg) a, + b = in(xmm_reg) b, + options(nomem, nostack, pure) + ); + + a + }; + + #[cfg(target_arch = "aarch64")] { + asm!( + "fadd {a:s}, {a:s}, {b:s}", + a = inout(vreg) a, + b = in(vreg) b, + options(nomem, nostack, pure) + ); + + a + }; + ], +} + +float_bench! { + name: add_f64, + sig: (a: f64, b: f64) -> f64, + crate_fn: add::__adddf3, + sys_fn: __adddf3, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + asm!( + "addsd {a}, {b}", + a = inout(xmm_reg) a, + b = in(xmm_reg) b, + options(nomem, nostack, pure) + ); + + a + }; + + #[cfg(target_arch = "aarch64")] { + asm!( + "fadd {a:d}, {a:d}, {b:d}", + a = inout(vreg) a, + b = in(vreg) b, + options(nomem, nostack, pure) + ); + + a + }; + ], +} + +float_bench! { + name: add_f128, + sig: (a: f128, b: f128) -> f128, + crate_fn: add::__addtf3, + crate_fn_ppc: add::__addkf3, + sys_fn: __addtf3, + sys_fn_ppc: __addkf3, + sys_available: not(feature = "no-sys-f128"), + asm: [] +} + +criterion_group!(float_add, add_f32, add_f64, add_f128); +criterion_main!(float_add); diff --git a/library/compiler-builtins/testcrate/benches/float_cmp.rs b/library/compiler-builtins/testcrate/benches/float_cmp.rs new file mode 100644 index 0000000000000..641eb0ac5d444 --- /dev/null +++ b/library/compiler-builtins/testcrate/benches/float_cmp.rs @@ -0,0 +1,202 @@ +#![feature(f128)] + +use criterion::{criterion_group, criterion_main, Criterion}; +use testcrate::float_bench; + +use compiler_builtins::float::cmp; + +/// `gt` symbols are allowed to return differing results, they just get compared +/// to 0. +fn gt_res_eq(a: i32, b: i32) -> bool { + let a_lt_0 = a <= 0; + let b_lt_0 = b <= 0; + (a_lt_0 && b_lt_0) || (!a_lt_0 && !b_lt_0) +} + +float_bench! { + name: cmp_f32_gt, + sig: (a: f32, b: f32) -> i32, + crate_fn: cmp::__gtsf2, + sys_fn: __gtsf2, + sys_available: all(), + output_eq: gt_res_eq, + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: i32; + asm!( + "xor {ret:e}, {ret:e}", + "ucomiss {a}, {b}", + "seta {ret:l}", + a = in(xmm_reg) a, + b = in(xmm_reg) b, + ret = out(reg) ret, + options(nomem, nostack, pure) + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: i32; + asm!( + "fcmp {a:s}, {b:s}", + "cset {ret:w}, gt", + a = in(vreg) a, + b = in(vreg) b, + ret = out(reg) ret, + options(nomem,nostack), + ); + + ret + }; + ], +} + +float_bench! { + name: cmp_f32_unord, + sig: (a: f32, b: f32) -> i32, + crate_fn: cmp::__unordsf2, + sys_fn: __unordsf2, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: i32; + asm!( + "xor {ret:e}, {ret:e}", + "ucomiss {a}, {b}", + "setp {ret:l}", + a = in(xmm_reg) a, + b = in(xmm_reg) b, + ret = out(reg) ret, + options(nomem, nostack, pure) + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: i32; + asm!( + "fcmp {a:s}, {b:s}", + "cset {ret:w}, vs", + a = in(vreg) a, + b = in(vreg) b, + ret = out(reg) ret, + options(nomem, nostack, pure) + ); + + ret + }; + ], +} + +float_bench! { + name: cmp_f64_gt, + sig: (a: f64, b: f64) -> i32, + crate_fn: cmp::__gtdf2, + sys_fn: __gtdf2, + sys_available: all(), + output_eq: gt_res_eq, + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: i32; + asm!( + "xor {ret:e}, {ret:e}", + "ucomisd {a}, {b}", + "seta {ret:l}", + a = in(xmm_reg) a, + b = in(xmm_reg) b, + ret = out(reg) ret, + options(nomem, nostack, pure) + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: i32; + asm!( + "fcmp {a:d}, {b:d}", + "cset {ret:w}, gt", + a = in(vreg) a, + b = in(vreg) b, + ret = out(reg) ret, + options(nomem, nostack, pure) + ); + + ret + }; + ], +} + +float_bench! { + name: cmp_f64_unord, + sig: (a: f64, b: f64) -> i32, + crate_fn: cmp::__unorddf2, + sys_fn: __unorddf2, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: i32; + asm!( + "xor {ret:e}, {ret:e}", + "ucomisd {a}, {b}", + "setp {ret:l}", + a = in(xmm_reg) a, + b = in(xmm_reg) b, + ret = out(reg) ret, + options(nomem, nostack, pure) + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: i32; + asm!( + "fcmp {a:d}, {b:d}", + "cset {ret:w}, vs", + a = in(vreg) a, + b = in(vreg) b, + ret = out(reg) ret, + options(nomem, nostack, pure) + ); + + ret + }; + ], +} + +float_bench! { + name: cmp_f128_gt, + sig: (a: f128, b: f128) -> i32, + crate_fn: cmp::__gttf2, + crate_fn_ppc: cmp::__gtkf2, + sys_fn: __gttf2, + sys_fn_ppc: __gtkf2, + sys_available: not(feature = "no-sys-f128"), + output_eq: gt_res_eq, + asm: [] +} + +float_bench! { + name: cmp_f128_unord, + sig: (a: f128, b: f128) -> i32, + crate_fn: cmp::__unordtf2, + crate_fn_ppc: cmp::__unordkf2, + sys_fn: __unordtf2, + sys_fn_ppc: __unordkf2, + sys_available: not(feature = "no-sys-f128"), + asm: [] +} + +criterion_group!( + float_cmp, + cmp_f32_gt, + cmp_f32_unord, + cmp_f64_gt, + cmp_f64_unord, + cmp_f128_gt, + cmp_f128_unord +); +criterion_main!(float_cmp); diff --git a/library/compiler-builtins/testcrate/benches/float_conv.rs b/library/compiler-builtins/testcrate/benches/float_conv.rs new file mode 100644 index 0000000000000..bbd3a06851d46 --- /dev/null +++ b/library/compiler-builtins/testcrate/benches/float_conv.rs @@ -0,0 +1,547 @@ +#![feature(f128)] +#![allow(improper_ctypes)] + +use compiler_builtins::float::conv; +use criterion::{criterion_group, criterion_main, Criterion}; +use testcrate::float_bench; + +/* unsigned int -> float */ + +float_bench! { + name: conv_u32_f32, + sig: (a: u32) -> f32, + crate_fn: conv::__floatunsisf, + sys_fn: __floatunsisf, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: f32; + asm!( + "mov {tmp:e}, {a:e}", + "cvtsi2ss {ret}, {tmp}", + a = in(reg) a, + tmp = out(reg) _, + ret = lateout(xmm_reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: f32; + asm!( + "ucvtf {ret:s}, {a:w}", + a = in(reg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_u32_f64, + sig: (a: u32) -> f64, + crate_fn: conv::__floatunsidf, + sys_fn: __floatunsidf, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: f64; + asm!( + "mov {tmp:e}, {a:e}", + "cvtsi2sd {ret}, {tmp}", + a = in(reg) a, + tmp = out(reg) _, + ret = lateout(xmm_reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: f64; + asm!( + "ucvtf {ret:d}, {a:w}", + a = in(reg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_u64_f32, + sig: (a: u64) -> f32, + crate_fn: conv::__floatundisf, + sys_fn: __floatundisf, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: f32; + asm!( + "ucvtf {ret:s}, {a:x}", + a = in(reg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_u64_f64, + sig: (a: u64) -> f64, + crate_fn: conv::__floatundidf, + sys_fn: __floatundidf, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: f64; + asm!( + "ucvtf {ret:d}, {a:x}", + a = in(reg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_u128_f32, + sig: (a: u128) -> f32, + crate_fn: conv::__floatuntisf, + sys_fn: __floatuntisf, + sys_available: all(), + asm: [] +} + +float_bench! { + name: conv_u128_f64, + sig: (a: u128) -> f64, + crate_fn: conv::__floatuntidf, + sys_fn: __floatuntidf, + sys_available: all(), + asm: [] +} + +/* signed int -> float */ + +float_bench! { + name: conv_i32_f32, + sig: (a: i32) -> f32, + crate_fn: conv::__floatsisf, + sys_fn: __floatsisf, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: f32; + asm!( + "cvtsi2ss {ret}, {a:e}", + a = in(reg) a, + ret = lateout(xmm_reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: f32; + asm!( + "scvtf {ret:s}, {a:w}", + a = in(reg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_i32_f64, + sig: (a: i32) -> f64, + crate_fn: conv::__floatsidf, + sys_fn: __floatsidf, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: f64; + asm!( + "cvtsi2sd {ret}, {a:e}", + a = in(reg) a, + ret = lateout(xmm_reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + + + #[cfg(target_arch = "aarch64")] { + let ret: f64; + asm!( + "scvtf {ret:d}, {a:w}", + a = in(reg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_i64_f32, + sig: (a: i64) -> f32, + crate_fn: conv::__floatdisf, + sys_fn: __floatdisf, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: f32; + asm!( + "cvtsi2ss {ret}, {a:r}", + a = in(reg) a, + ret = lateout(xmm_reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: f32; + asm!( + "scvtf {ret:s}, {a:x}", + a = in(reg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_i64_f64, + sig: (a: i64) -> f64, + crate_fn: conv::__floatdidf, + sys_fn: __floatdidf, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: f64; + asm!( + "cvtsi2sd {ret}, {a:r}", + a = in(reg) a, + ret = lateout(xmm_reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + + + #[cfg(target_arch = "aarch64")] { + let ret: f64; + asm!( + "scvtf {ret:d}, {a:x}", + a = in(reg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_i128_f32, + sig: (a: i128) -> f32, + crate_fn: conv::__floattisf, + sys_fn: __floattisf, + sys_available: all(), + asm: [] +} + +float_bench! { + name: conv_i128_f64, + sig: (a: i128) -> f64, + crate_fn: conv::__floattidf, + sys_fn: __floattidf, + sys_available: all(), + asm: [] +} + +/* float -> unsigned int */ + +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +float_bench! { + name: conv_f32_u32, + sig: (a: f32) -> u32, + crate_fn: conv::__fixunssfsi, + sys_fn: __fixunssfsi, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: u32; + asm!( + "fcvtzu {ret:w}, {a:s}", + a = in(vreg) a, + ret = lateout(reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +float_bench! { + name: conv_f32_u64, + sig: (a: f32) -> u64, + crate_fn: conv::__fixunssfdi, + sys_fn: __fixunssfdi, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: u64; + asm!( + "fcvtzu {ret:x}, {a:s}", + a = in(vreg) a, + ret = lateout(reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +float_bench! { + name: conv_f32_u128, + sig: (a: f32) -> u128, + crate_fn: conv::__fixunssfti, + sys_fn: __fixunssfti, + sys_available: all(), + asm: [] +} + +float_bench! { + name: conv_f64_u32, + sig: (a: f64) -> u32, + crate_fn: conv::__fixunsdfsi, + sys_fn: __fixunsdfsi, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: u32; + asm!( + "fcvtzu {ret:w}, {a:d}", + a = in(vreg) a, + ret = lateout(reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_f64_u64, + sig: (a: f64) -> u64, + crate_fn: conv::__fixunsdfdi, + sys_fn: __fixunsdfdi, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: u64; + asm!( + "fcvtzu {ret:x}, {a:d}", + a = in(vreg) a, + ret = lateout(reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_f64_u128, + sig: (a: f64) -> u128, + crate_fn: conv::__fixunsdfti, + sys_fn: __fixunsdfti, + sys_available: all(), + asm: [] +} + +/* float -> signed int */ + +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +float_bench! { + name: conv_f32_i32, + sig: (a: f32) -> i32, + crate_fn: conv::__fixsfsi, + sys_fn: __fixsfsi, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: i32; + asm!( + "fcvtzs {ret:w}, {a:s}", + a = in(vreg) a, + ret = lateout(reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +float_bench! { + name: conv_f32_i64, + sig: (a: f32) -> i64, + crate_fn: conv::__fixsfdi, + sys_fn: __fixsfdi, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: i64; + asm!( + "fcvtzs {ret:x}, {a:s}", + a = in(vreg) a, + ret = lateout(reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +float_bench! { + name: conv_f32_i128, + sig: (a: f32) -> i128, + crate_fn: conv::__fixsfti, + sys_fn: __fixsfti, + sys_available: all(), + asm: [] +} + +float_bench! { + name: conv_f64_i32, + sig: (a: f64) -> i32, + crate_fn: conv::__fixdfsi, + sys_fn: __fixdfsi, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: i32; + asm!( + "fcvtzs {ret:w}, {a:d}", + a = in(vreg) a, + ret = lateout(reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_f64_i64, + sig: (a: f64) -> i64, + crate_fn: conv::__fixdfdi, + sys_fn: __fixdfdi, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: i64; + asm!( + "fcvtzs {ret:x}, {a:d}", + a = in(vreg) a, + ret = lateout(reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: conv_f64_i128, + sig: (a: f64) -> i128, + crate_fn: conv::__fixdfti, + sys_fn: __fixdfti, + sys_available: all(), + asm: [] +} + +criterion_group!( + float_conv, + conv_u32_f32, + conv_u32_f64, + conv_u64_f32, + conv_u64_f64, + conv_u128_f32, + conv_u128_f64, + conv_i32_f32, + conv_i32_f64, + conv_i64_f32, + conv_i64_f64, + conv_i128_f32, + conv_i128_f64, + conv_f64_u32, + conv_f64_u64, + conv_f64_u128, + conv_f64_i32, + conv_f64_i64, + conv_f64_i128, +); + +// FIXME: ppc64le has a sporadic overflow panic in the crate functions +// +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +criterion_group!( + float_conv_not_ppc64le, + conv_f32_u32, + conv_f32_u64, + conv_f32_u128, + conv_f32_i32, + conv_f32_i64, + conv_f32_i128, +); + +#[cfg(all(target_arch = "powerpc64", target_endian = "little"))] +criterion_main!(float_conv); + +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +criterion_main!(float_conv, float_conv_not_ppc64le); diff --git a/library/compiler-builtins/testcrate/benches/float_div.rs b/library/compiler-builtins/testcrate/benches/float_div.rs new file mode 100644 index 0000000000000..e679f8ccccbe3 --- /dev/null +++ b/library/compiler-builtins/testcrate/benches/float_div.rs @@ -0,0 +1,70 @@ +#![feature(f128)] + +use compiler_builtins::float::div; +use criterion::{criterion_group, criterion_main, Criterion}; +use testcrate::float_bench; + +float_bench! { + name: div_f32, + sig: (a: f32, b: f32) -> f32, + crate_fn: div::__divsf3, + sys_fn: __divsf3, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + asm!( + "divss {a}, {b}", + a = inout(xmm_reg) a, + b = in(xmm_reg) b, + options(nomem, nostack, pure) + ); + + a + }; + + #[cfg(target_arch = "aarch64")] { + asm!( + "fdiv {a:s}, {a:s}, {b:s}", + a = inout(vreg) a, + b = in(vreg) b, + options(nomem, nostack, pure) + ); + + a + }; + ], +} + +float_bench! { + name: div_f64, + sig: (a: f64, b: f64) -> f64, + crate_fn: div::__divdf3, + sys_fn: __divdf3, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + asm!( + "divsd {a}, {b}", + a = inout(xmm_reg) a, + b = in(xmm_reg) b, + options(nomem, nostack, pure) + ); + + a + }; + + #[cfg(target_arch = "aarch64")] { + asm!( + "fdiv {a:d}, {a:d}, {b:d}", + a = inout(vreg) a, + b = in(vreg) b, + options(nomem, nostack, pure) + ); + + a + }; + ], +} + +criterion_group!(float_div, div_f32, div_f64); +criterion_main!(float_div); diff --git a/library/compiler-builtins/testcrate/benches/float_extend.rs b/library/compiler-builtins/testcrate/benches/float_extend.rs new file mode 100644 index 0000000000000..9bd8009e93b93 --- /dev/null +++ b/library/compiler-builtins/testcrate/benches/float_extend.rs @@ -0,0 +1,93 @@ +#![allow(unused_variables)] // "unused" f16 registers +#![feature(f128)] +#![feature(f16)] + +use compiler_builtins::float::extend; +use criterion::{criterion_group, criterion_main, Criterion}; +use testcrate::float_bench; + +float_bench! { + name: extend_f16_f32, + sig: (a: f16) -> f32, + crate_fn: extend::__extendhfsf2, + sys_fn: __extendhfsf2, + sys_available: not(feature = "no-sys-f16"), + asm: [ + #[cfg(target_arch = "aarch64")] { + // FIXME(f16_f128): remove `to_bits()` after f16 asm support (rust-lang/rust/#116909) + let ret: f32; + asm!( + "fcvt {ret:s}, {a:h}", + a = in(vreg) a.to_bits(), + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: extend_f16_f128, + sig: (a: f16) -> f128, + crate_fn: extend::__extendhftf2, + crate_fn_ppc: extend::__extendhfkf2, + sys_fn: __extendhftf2, + sys_fn_ppc: __extendhfkf2, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [], +} + +float_bench! { + name: extend_f32_f64, + sig: (a: f32) -> f64, + crate_fn: extend::__extendsfdf2, + sys_fn: __extendsfdf2, + sys_available: all(), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: f64; + asm!( + "fcvt {ret:d}, {a:s}", + a = in(vreg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: extend_f32_f128, + sig: (a: f32) -> f128, + crate_fn: extend::__extendsftf2, + crate_fn_ppc: extend::__extendsfkf2, + sys_fn: __extendsftf2, + sys_fn_ppc: __extendsfkf2, + sys_available: not(feature = "no-sys-f128"), + asm: [], +} + +float_bench! { + name: extend_f64_f128, + sig: (a: f64) -> f128, + crate_fn: extend::__extenddftf2, + crate_fn_ppc: extend::__extenddfkf2, + sys_fn: __extenddftf2, + sys_fn_ppc: __extenddfkf2, + sys_available: not(feature = "no-sys-f128"), + asm: [], +} + +criterion_group!( + float_extend, + extend_f16_f32, + extend_f16_f128, + extend_f32_f64, + extend_f32_f128, + extend_f64_f128, +); +criterion_main!(float_extend); diff --git a/library/compiler-builtins/testcrate/benches/float_mul.rs b/library/compiler-builtins/testcrate/benches/float_mul.rs new file mode 100644 index 0000000000000..efa32b28563e5 --- /dev/null +++ b/library/compiler-builtins/testcrate/benches/float_mul.rs @@ -0,0 +1,81 @@ +#![feature(f128)] + +use compiler_builtins::float::mul; +use criterion::{criterion_group, criterion_main, Criterion}; +use testcrate::float_bench; + +float_bench! { + name: mul_f32, + sig: (a: f32, b: f32) -> f32, + crate_fn: mul::__mulsf3, + sys_fn: __mulsf3, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + asm!( + "mulss {a}, {b}", + a = inout(xmm_reg) a, + b = in(xmm_reg) b, + options(nomem, nostack, pure) + ); + + a + }; + + #[cfg(target_arch = "aarch64")] { + asm!( + "fmul {a:s}, {a:s}, {b:s}", + a = inout(vreg) a, + b = in(vreg) b, + options(nomem, nostack, pure) + ); + + a + }; + ], +} + +float_bench! { + name: mul_f64, + sig: (a: f64, b: f64) -> f64, + crate_fn: mul::__muldf3, + sys_fn: __muldf3, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + asm!( + "mulsd {a}, {b}", + a = inout(xmm_reg) a, + b = in(xmm_reg) b, + options(nomem, nostack, pure) + ); + + a + }; + + #[cfg(target_arch = "aarch64")] { + asm!( + "fmul {a:d}, {a:d}, {b:d}", + a = inout(vreg) a, + b = in(vreg) b, + options(nomem, nostack, pure) + ); + + a + }; + ], +} + +float_bench! { + name: mul_f128, + sig: (a: f128, b: f128) -> f128, + crate_fn: mul::__multf3, + crate_fn_ppc: mul::__mulkf3, + sys_fn: __multf3, + sys_fn_ppc: __mulkf3, + sys_available: not(feature = "no-sys-f128"), + asm: [] +} + +criterion_group!(float_mul, mul_f32, mul_f64, mul_f128); +criterion_main!(float_mul); diff --git a/library/compiler-builtins/testcrate/benches/float_pow.rs b/library/compiler-builtins/testcrate/benches/float_pow.rs new file mode 100644 index 0000000000000..252f740120db2 --- /dev/null +++ b/library/compiler-builtins/testcrate/benches/float_pow.rs @@ -0,0 +1,24 @@ +use compiler_builtins::float::pow; +use criterion::{criterion_group, criterion_main, Criterion}; +use testcrate::float_bench; + +float_bench! { + name: powi_f32, + sig: (a: f32, b: i32) -> f32, + crate_fn: pow::__powisf2, + sys_fn: __powisf2, + sys_available: all(), + asm: [], +} + +float_bench! { + name: powi_f64, + sig: (a: f64, b: i32) -> f64, + crate_fn: pow::__powidf2, + sys_fn: __powidf2, + sys_available: all(), + asm: [], +} + +criterion_group!(float_add, powi_f32, powi_f64); +criterion_main!(float_add); diff --git a/library/compiler-builtins/testcrate/benches/float_sub.rs b/library/compiler-builtins/testcrate/benches/float_sub.rs new file mode 100644 index 0000000000000..6d87604aac713 --- /dev/null +++ b/library/compiler-builtins/testcrate/benches/float_sub.rs @@ -0,0 +1,81 @@ +#![feature(f128)] + +use compiler_builtins::float::sub; +use criterion::{criterion_group, criterion_main, Criterion}; +use testcrate::float_bench; + +float_bench! { + name: sub_f32, + sig: (a: f32, b: f32) -> f32, + crate_fn: sub::__subsf3, + sys_fn: __subsf3, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + asm!( + "subss {a}, {b}", + a = inout(xmm_reg) a, + b = in(xmm_reg) b, + options(nomem, nostack, pure) + ); + + a + }; + + #[cfg(target_arch = "aarch64")] { + asm!( + "fsub {a:s}, {a:s}, {b:s}", + a = inout(vreg) a, + b = in(vreg) b, + options(nomem, nostack, pure) + ); + + a + }; + ], +} + +float_bench! { + name: sub_f64, + sig: (a: f64, b: f64) -> f64, + crate_fn: sub::__subdf3, + sys_fn: __subdf3, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + asm!( + "subsd {a}, {b}", + a = inout(xmm_reg) a, + b = in(xmm_reg) b, + options(nomem, nostack, pure) + ); + + a + }; + + #[cfg(target_arch = "aarch64")] { + asm!( + "fsub {a:d}, {a:d}, {b:d}", + a = inout(vreg) a, + b = in(vreg) b, + options(nomem, nostack, pure) + ); + + a + }; + ], +} + +float_bench! { + name: sub_f128, + sig: (a: f128, b: f128) -> f128, + crate_fn: sub::__subtf3, + crate_fn_ppc: sub::__subkf3, + sys_fn: __subtf3, + sys_fn_ppc: __subkf3, + sys_available: not(feature = "no-sys-f128"), + asm: [] +} + +criterion_group!(float_sub, sub_f32, sub_f64, sub_f128); +criterion_main!(float_sub); diff --git a/library/compiler-builtins/testcrate/benches/float_trunc.rs b/library/compiler-builtins/testcrate/benches/float_trunc.rs new file mode 100644 index 0000000000000..1553dacee0820 --- /dev/null +++ b/library/compiler-builtins/testcrate/benches/float_trunc.rs @@ -0,0 +1,127 @@ +#![feature(f128)] +#![feature(f16)] + +use compiler_builtins::float::trunc; +use criterion::{criterion_group, criterion_main, Criterion}; +use testcrate::float_bench; + +float_bench! { + name: trunc_f32_f16, + sig: (a: f32) -> f16, + crate_fn: trunc::__truncsfhf2, + sys_fn: __truncsfhf2, + sys_available: not(feature = "no-sys-f16"), + asm: [ + #[cfg(target_arch = "aarch64")] { + // FIXME(f16_f128): remove `from_bits()` after f16 asm support (rust-lang/rust/#116909) + let ret: u16; + asm!( + "fcvt {ret:h}, {a:s}", + a = in(vreg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + f16::from_bits(ret) + }; + ], +} + +float_bench! { + name: trunc_f64_f16, + sig: (a: f64) -> f16, + crate_fn: trunc::__truncdfhf2, + sys_fn: __truncdfhf2, + sys_available: not(feature = "no-sys-f128"), + asm: [ + #[cfg(target_arch = "aarch64")] { + // FIXME(f16_f128): remove `from_bits()` after f16 asm support (rust-lang/rust/#116909) + let ret: u16; + asm!( + "fcvt {ret:h}, {a:d}", + a = in(vreg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + f16::from_bits(ret) + }; + ], +} + +float_bench! { + name: trunc_f64_f32, + sig: (a: f64) -> f32, + crate_fn: trunc::__truncdfsf2, + sys_fn: __truncdfsf2, + sys_available: all(), + asm: [ + #[cfg(target_arch = "x86_64")] { + let ret: f32; + asm!( + "cvtsd2ss {ret}, {a}", + a = in(xmm_reg) a, + ret = lateout(xmm_reg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + + #[cfg(target_arch = "aarch64")] { + let ret: f32; + asm!( + "fcvt {ret:s}, {a:d}", + a = in(vreg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + +float_bench! { + name: trunc_f128_f16, + sig: (a: f128) -> f16, + crate_fn: trunc::__trunctfhf2, + crate_fn_ppc: trunc::__trunckfhf2, + sys_fn: __trunctfhf2, + sys_fn_ppc: __trunckfhf2, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [], +} + +float_bench! { + name: trunc_f128_f32, + sig: (a: f128) -> f32, + crate_fn: trunc::__trunctfsf2, + crate_fn_ppc: trunc::__trunckfsf2, + sys_fn: __trunctfsf2, + sys_fn_ppc: __trunckfsf2, + sys_available: not(feature = "no-sys-f128"), + asm: [], +} + +float_bench! { + name: trunc_f128_f64, + sig: (a: f128) -> f64, + crate_fn: trunc::__trunctfdf2, + crate_fn_ppc: trunc::__trunckfdf2, + sys_fn: __trunctfdf2, + sys_fn_ppc: __trunckfdf2, + sys_available: not(feature = "no-sys-f128"), + asm: [], +} + +criterion_group!( + float_trunc, + trunc_f32_f16, + trunc_f64_f16, + trunc_f64_f32, + trunc_f128_f16, + trunc_f128_f32, + trunc_f128_f64, +); +criterion_main!(float_trunc); diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 1dad6c5e64917..cae83e1fc0930 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -5,6 +5,8 @@ use std::{collections::HashSet, env}; enum Feature { NoSysF128, NoSysF128IntConvert, + NoSysF16, + NoSysF16F128Convert, } fn main() { @@ -31,6 +33,7 @@ fn main() { { features.insert(Feature::NoSysF128); features.insert(Feature::NoSysF128IntConvert); + features.insert(Feature::NoSysF16F128Convert); } if target.starts_with("i586") || target.starts_with("i686") { @@ -38,6 +41,17 @@ fn main() { features.insert(Feature::NoSysF128IntConvert); } + if target.contains("-unknown-linux-") { + // No `__extendhftf2` on x86, no `__trunctfhf2` on aarch64 + features.insert(Feature::NoSysF16F128Convert); + } + + if target.starts_with("wasm32-") { + // Linking says "error: function signature mismatch: __extendhfsf2" and seems to + // think the signature is either `(i32) -> f32` or `(f32) -> f32` + features.insert(Feature::NoSysF16); + } + for feature in features { let (name, warning) = match feature { Feature::NoSysF128 => ("no-sys-f128", "using apfloat fallback for f128"), @@ -45,6 +59,11 @@ fn main() { "no-sys-f128-int-convert", "using apfloat fallback for f128 to int conversions", ), + Feature::NoSysF16F128Convert => ( + "no-sys-f16-f128-convert", + "skipping 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}\""); diff --git a/library/compiler-builtins/testcrate/src/bench.rs b/library/compiler-builtins/testcrate/src/bench.rs new file mode 100644 index 0000000000000..1374d7b4f77ac --- /dev/null +++ b/library/compiler-builtins/testcrate/src/bench.rs @@ -0,0 +1,348 @@ +use core::cell::RefCell; + +use alloc::vec::Vec; +use compiler_builtins::float::Float; + +/// Fuzz with these many items to ensure equal functions +pub const CHECK_ITER_ITEMS: u32 = 10_000; +/// Benchmark with this many items to get a variety +pub const BENCH_ITER_ITEMS: u32 = 500; + +/// Still run benchmarks/tests but don't check correctness between compiler-builtins and +/// builtin system functions functions +pub fn skip_sys_checks(test_name: &str) -> bool { + const ALWAYS_SKIPPED: &[&str] = &[ + // FIXME(f16_f128): system symbols have incorrect results + // + "extend_f16_f32", + "trunc_f32_f16", + "trunc_f64_f16", + // FIXME(f16_f128): rounding error + // + "mul_f128", + ]; + + // FIXME(f16_f128): error on LE ppc64. There are more tests that are cfg-ed out completely + // in their benchmark modules due to runtime panics. + // + const PPC64LE_SKIPPED: &[&str] = &["extend_f32_f128"]; + + // FIXME(f16_f128): system symbols have incorrect results + // + const X86_NO_SSE_SKIPPED: &[&str] = &["add_f128", "sub_f128", "powi_f32", "powi_f64"]; + + // FIXME(llvm): system symbols have incorrect results on Windows + // + const WINDOWS_SKIPPED: &[&str] = &[ + "conv_f32_u128", + "conv_f32_i128", + "conv_f64_u128", + "conv_f64_i128", + ]; + + if cfg!(target_arch = "arm") { + // The Arm symbols need a different ABI that our macro doesn't handle, just skip it + return true; + } + + if ALWAYS_SKIPPED.contains(&test_name) { + return true; + } + + if cfg!(all(target_arch = "powerpc64", target_endian = "little")) + && PPC64LE_SKIPPED.contains(&test_name) + { + return true; + } + + if cfg!(all(target_arch = "x86", not(target_feature = "sse"))) + && X86_NO_SSE_SKIPPED.contains(&test_name) + { + return true; + } + + if cfg!(target_family = "windows") && WINDOWS_SKIPPED.contains(&test_name) { + return true; + } + + false +} + +/// Still run benchmarks/tests but don't check correctness between compiler-builtins and +/// assembly functions +pub fn skip_asm_checks(test_name: &str) -> bool { + // FIXME(f16_f128): rounding error + // + const SKIPPED: &[&str] = &["mul_f32", "mul_f64"]; + + SKIPPED.contains(&test_name) +} + +/// Create a comparison of the system symbol, compiler_builtins, and optionally handwritten +/// assembly. +#[macro_export] +macro_rules! float_bench { + ( + // Name of this benchmark + name: $name:ident, + // The function signature to be tested + sig: ($($arg:ident: $arg_ty:ty),*) -> $ret_ty:ty, + // Path to the crate in compiler_builtins + crate_fn: $crate_fn:path, + // Optional alias on ppc + $( crate_fn_ppc: $crate_fn_ppc:path, )? + // Name of the system symbol + sys_fn: $sys_fn:ident, + // Optional alias on ppc + $( sys_fn_ppc: $sys_fn_ppc:path, )? + // Meta saying whether the system symbol is available + sys_available: $sys_available:meta, + // An optional function to validate the results of two functions are equal, if not + // just `$ret_ty::check_eq` + $( output_eq: $output_eq:expr, )? + // Assembly implementations, if any. + asm: [ + $( + #[cfg($asm_meta:meta)] { + $($asm_tt:tt)* + } + );* + $(;)? + ] + $(,)? + ) => {paste::paste! { + #[cfg($sys_available)] + extern "C" { + /// Binding for the system function + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + fn $sys_fn($($arg: $arg_ty),*) -> $ret_ty; + + + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + float_bench! { @coalesce_fn $($sys_fn_ppc)? => + fn $sys_fn($($arg: $arg_ty),*) -> $ret_ty; + } + } + + fn $name(c: &mut Criterion) { + use core::hint::black_box; + use compiler_builtins::float::Float; + use $crate::bench::TestIO; + + #[inline(never)] // equalize with external calls + fn crate_fn($($arg: $arg_ty),*) -> $ret_ty { + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + let target_crate_fn = $crate_fn; + + // On PPC, use an alias if specified + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + let target_crate_fn = float_bench!(@coalesce $($crate_fn_ppc)?, $crate_fn); + + target_crate_fn( $($arg),* ) + } + + #[inline(always)] // already a branch + #[cfg($sys_available)] + fn sys_fn($($arg: $arg_ty),*) -> $ret_ty { + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + let target_sys_fn = $sys_fn; + + // On PPC, use an alias if specified + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + let target_sys_fn = float_bench!(@coalesce $($sys_fn_ppc)?, $sys_fn); + + unsafe { target_sys_fn( $($arg),* ) } + } + + #[inline(never)] // equalize with external calls + #[cfg(any( $($asm_meta),* ))] + fn asm_fn($(mut $arg: $arg_ty),*) -> $ret_ty { + use core::arch::asm; + $( + #[cfg($asm_meta)] + unsafe { $($asm_tt)* } + )* + } + + let testvec = <($($arg_ty),*)>::make_testvec($crate::bench::CHECK_ITER_ITEMS); + let benchvec = <($($arg_ty),*)>::make_testvec($crate::bench::BENCH_ITER_ITEMS); + let test_name = stringify!($name); + let check_eq = float_bench!(@coalesce $($output_eq)?, $ret_ty::check_eq); + + // Verify math lines up. We run the crate functions even if we don't validate the + // output here to make sure there are no panics or crashes. + + #[cfg($sys_available)] + for ($($arg),*) in testvec.iter().copied() { + let crate_res = crate_fn($($arg),*); + let sys_res = sys_fn($($arg),*); + + if $crate::bench::skip_sys_checks(test_name) { + continue; + } + + assert!( + check_eq(crate_res, sys_res), + "{test_name}{:?}: crate: {crate_res:?}, sys: {sys_res:?}", + ($($arg),* ,) + ); + } + + #[cfg(any( $($asm_meta),* ))] + { + for ($($arg),*) in testvec.iter().copied() { + let crate_res = crate_fn($($arg),*); + let asm_res = asm_fn($($arg),*); + + if $crate::bench::skip_asm_checks(test_name) { + continue; + } + + assert!( + check_eq(crate_res, asm_res), + "{test_name}{:?}: crate: {crate_res:?}, asm: {asm_res:?}", + ($($arg),* ,) + ); + } + } + + let mut group = c.benchmark_group(test_name); + group.bench_function("compiler-builtins", |b| b.iter(|| { + for ($($arg),*) in benchvec.iter().copied() { + black_box(crate_fn( $(black_box($arg)),* )); + } + })); + + #[cfg($sys_available)] + group.bench_function("system", |b| b.iter(|| { + for ($($arg),*) in benchvec.iter().copied() { + black_box(sys_fn( $(black_box($arg)),* )); + } + })); + + #[cfg(any( $($asm_meta),* ))] + group.bench_function(&format!( + "assembly ({} {})", std::env::consts::ARCH, std::env::consts::FAMILY + ), |b| b.iter(|| { + for ($($arg),*) in benchvec.iter().copied() { + black_box(asm_fn( $(black_box($arg)),* )); + } + })); + + group.finish(); + } + }}; + + // Allow overriding a default + (@coalesce $specified:expr, $default:expr) => { $specified }; + (@coalesce, $default:expr) => { $default }; + + // Allow overriding a function name + (@coalesce_fn $specified:ident => fn $default_name:ident $($tt:tt)+) => { + fn $specified $($tt)+ + }; + (@coalesce_fn => fn $default_name:ident $($tt:tt)+) => { + fn $default_name $($tt)+ + }; +} + +/// A type used as either an input or output to/from a benchmark function. +pub trait TestIO: Sized { + fn make_testvec(len: u32) -> Vec; + fn check_eq(a: Self, b: Self) -> bool; +} + +macro_rules! impl_testio { + (float $($f_ty:ty),+) => {$( + impl TestIO for $f_ty { + fn make_testvec(len: u32) -> Vec { + // refcell because fuzz_* takes a `Fn` + let ret = RefCell::new(Vec::new()); + crate::fuzz_float(len, |a| ret.borrow_mut().push(a)); + ret.into_inner() + } + + fn check_eq(a: Self, b: Self) -> bool { + Float::eq_repr(a, b) + } + } + + impl TestIO for ($f_ty, $f_ty) { + fn make_testvec(len: u32) -> Vec { + // refcell because fuzz_* takes a `Fn` + let ret = RefCell::new(Vec::new()); + crate::fuzz_float_2(len, |a, b| ret.borrow_mut().push((a, b))); + ret.into_inner() + } + + fn check_eq(_a: Self, _b: Self) -> bool { + unimplemented!() + } + } + )*}; + + (int $($i_ty:ty),+) => {$( + impl TestIO for $i_ty { + fn make_testvec(len: u32) -> Vec { + // refcell because fuzz_* takes a `Fn` + let ret = RefCell::new(Vec::new()); + crate::fuzz(len, |a| ret.borrow_mut().push(a)); + ret.into_inner() + } + + fn check_eq(a: Self, b: Self) -> bool { + a == b + } + } + + impl TestIO for ($i_ty, $i_ty) { + fn make_testvec(len: u32) -> Vec { + // refcell because fuzz_* takes a `Fn` + let ret = RefCell::new(Vec::new()); + crate::fuzz_2(len, |a, b| ret.borrow_mut().push((a, b))); + ret.into_inner() + } + + fn check_eq(_a: Self, _b: Self) -> bool { + unimplemented!() + } + } + )*}; + + ((float, int) ($f_ty:ty, $i_ty:ty)) => { + impl TestIO for ($f_ty, $i_ty) { + fn make_testvec(len: u32) -> Vec { + // refcell because fuzz_* takes a `Fn` + let ivec = RefCell::new(Vec::new()); + let fvec = RefCell::new(Vec::new()); + + crate::fuzz(len.isqrt(), |a| ivec.borrow_mut().push(a)); + crate::fuzz_float(len.isqrt(), |a| fvec.borrow_mut().push(a)); + + let mut ret = Vec::new(); + let ivec = ivec.into_inner(); + let fvec = fvec.into_inner(); + + for f in fvec { + for i in &ivec { + ret.push((f, *i)); + } + } + + ret + } + + fn check_eq(_a: Self, _b: Self) -> bool { + unimplemented!() + } + } + } +} + +#[cfg(not(feature = "no-f16-f128"))] +impl_testio!(float f16, f128); +impl_testio!(float f32, f64); +impl_testio!(int i16, i32, i64, i128); +impl_testio!(int u16, u32, u64, u128); +impl_testio!((float, int)(f32, i32)); +impl_testio!((float, int)(f64, i32)); diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index 5ee96ad275175..f9b052528f027 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -13,6 +13,12 @@ //! Some floating point tests are disabled for specific architectures, because they do not have //! correct rounding. #![no_std] +#![cfg_attr(not(feature = "no-f16-f128"), feature(f128))] +#![cfg_attr(not(feature = "no-f16-f128"), feature(f16))] +#![feature(isqrt)] + +pub mod bench; +extern crate alloc; use compiler_builtins::float::Float; use compiler_builtins::int::{Int, MinInt}; From d0fdc0044a61bec6c7c4f8db8d7f41ca71eb688c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 May 2024 05:06:36 -0400 Subject: [PATCH 1250/4206] Enable cache for Cargo components of the build --- library/compiler-builtins/.github/workflows/main.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 72d441c4e7da5..98d22c75af99b 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -105,6 +105,9 @@ jobs: shell: bash - run: rustup target add ${{ matrix.target }} - run: rustup component add llvm-tools-preview + - uses: Swatinem/rust-cache@v2 + with: + key: ${{ matrix.target }} - name: Download compiler-rt reference sources run: | curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/18.0-2024-02-13.tar.gz @@ -147,6 +150,7 @@ jobs: - name: Install nightly `clippy` run: | rustup set profile minimal && rustup default "nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/clippy)" && rustup component add clippy + - uses: Swatinem/rust-cache@v2 - run: cargo clippy -- -D clippy::all success: From 98ddf3c66dd6f25d426c504554276d21fcac1c33 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 May 2024 05:23:06 -0400 Subject: [PATCH 1251/4206] Enable cache for Docker images --- .../.github/workflows/main.yml | 21 +++++++++++++++++++ library/compiler-builtins/ci/run-docker.sh | 14 ++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 98d22c75af99b..9e89c3a98bde4 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -108,6 +108,14 @@ jobs: - uses: Swatinem/rust-cache@v2 with: key: ${{ matrix.target }} + - name: Cache Docker layers + uses: actions/cache@v2 + if: matrix.os == 'ubuntu-latest' + with: + path: /tmp/.buildx-cache + key: ${{ matrix.target }}-buildx-${{ github.sha }} + restore-keys: ${{ matrix.target }}-buildx- + - name: Download compiler-rt reference sources run: | curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/18.0-2024-02-13.tar.gz @@ -123,10 +131,23 @@ jobs: NO_STD: ${{ matrix.no_std }} TEST_VERBATIM: ${{ matrix.test_verbatim }} + # Configure buildx to use Docker layer caching + - uses: docker/setup-buildx-action@v3 + if: matrix.os == 'ubuntu-latest' + # Otherwise we use our docker containers to run builds - run: cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} if: matrix.os == 'ubuntu-latest' + # Workaround to keep Docker cache smaller + # https://github.com/docker/build-push-action/issues/252 + # https://github.com/moby/buildkit/issues/1896 + - name: Move Docker cache + if: matrix.os == 'ubuntu-latest' + run: | + rm -rf /tmp/.buildx-cache + mv /tmp/.buildx-cache-new /tmp/.buildx-cache + rustfmt: name: Rustfmt runs-on: ubuntu-latest diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index e5ff8a46b26c9..14b1a32d712d6 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -41,7 +41,19 @@ run() { export RUST_COMPILER_RT_ROOT=./compiler-rt fi - docker build \ + if [ "$GITHUB_ACTIONS" = "true" ]; then + # Enable Docker image caching on GHA + + buildx="buildx" + build_args=( + "--cache-from" "type=local,src=/tmp/.buildx-cache" + "--cache-to" "type=local,dest=/tmp/.buildx-cache-new" + "${build_args[@]:-}" + "--load" + ) + fi + + docker "${buildx:-}" build \ -t "builtins-$target" \ ${build_args[@]:-} \ "ci/docker/$target" From 84e87eb15b3307af12abea4316ac9650024d8a43 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 May 2024 15:20:31 -0400 Subject: [PATCH 1252/4206] Add caching for downloading compiler-rt --- .../compiler-builtins/.github/workflows/main.yml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 9e89c3a98bde4..38064543f3e24 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -4,6 +4,8 @@ on: [push, pull_request] env: RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings + RUST_LLVM_VERSION: 18.0-2024-02-13 + RUST_COMPILER_RT_ROOT: ./compiler-rt jobs: test: @@ -115,12 +117,18 @@ jobs: path: /tmp/.buildx-cache key: ${{ matrix.target }}-buildx-${{ github.sha }} restore-keys: ${{ matrix.target }}-buildx- - + + - name: Cache compiler-rt + id: cache-compiler-rt + uses: actions/cache@v4 + with: + path: compiler-rt + key: ${{ runner.os }}-compiler-rt-${{ env.RUST_LLVM_VERSION }} - name: Download compiler-rt reference sources + if: steps.cache-compiler-rt.outputs.cache-hit != 'true' run: | - curl -L -o code.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/18.0-2024-02-13.tar.gz - tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-18.0-2024-02-13/compiler-rt - echo RUST_COMPILER_RT_ROOT=./compiler-rt >> $GITHUB_ENV + curl -L -o code.tar.gz "https://github.com/rust-lang/llvm-project/archive/rustc/$%7BRUST_LLVM_VERSION%7D.tar.gz" + tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-${RUST_LLVM_VERSION}/compiler-rt shell: bash # Non-linux tests just use our raw script From e35091a2d0b5fda2045c27ee4facc33f6dd8d486 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 17 Jun 2024 19:38:55 -0500 Subject: [PATCH 1253/4206] Disable libm on x86 without sse2 In , symbols for the Rust port of libm were made always weakly available. This seems to be causing problems on platforms with ABI issues, as explained at . Disable Rust libm on x86 without sse2 to mitigate this. --- library/compiler-builtins/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 40564178a2498..0d207a914bffd 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -47,6 +47,9 @@ mod macros; pub mod float; pub mod int; +// Disabled on x86 without sse2 due to ABI issues +// +#[cfg(not(all(target_arch = "x86", not(target_feature = "sse2"))))] pub mod math; pub mod mem; From f2092967cb163255a1e5ea7d36c5eac07e467067 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 29 May 2024 03:38:57 -0500 Subject: [PATCH 1254/4206] Update the Ubuntu docker image to the latest version --- .../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/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 +- .../compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile | 2 +- .../compiler-builtins/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/x86_64-unknown-linux-gnu/Dockerfile | 2 +- library/compiler-builtins/ci/run-docker.sh | 2 +- 19 files changed, 19 insertions(+), 19 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 5de76efc375f0..1aef14a962d64 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:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ 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 dc95da0f3c5e6..fc9803777f823 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:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ 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 55e5e3d5754cb..a127f67cb7311 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:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ 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 fd2ad18d1a350..67a3e51a96457 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:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ 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 f161ec76725a3..15285d9bb060e 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:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ 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 f161ec76725a3..15285d9bb060e 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:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ 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 042dd4219de7c..a47dd9f193134 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:18.04 +ARG IMAGE=ubuntu:24.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 45b3089c9ed37..688aa1ab231a1 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:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ 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 bda6be1d67448..27d032a1441c1 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:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ 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 702a26ec1a5f0..4d18a6edbc9db 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:18.04 +ARG IMAGE=ubuntu:24.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 6bae7cb3b65bf..5225b833c0c07 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:18.04 +ARG IMAGE=ubuntu:24.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 2c315e509e32e..cbd78eac4217c 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:18.04 +ARG IMAGE=ubuntu:24.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 da8f9db604bbd..bad064297c394 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:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile index d7256a9c53301..f966b2b9f2a5f 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:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile index d7256a9c53301..f966b2b9f2a5f 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:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile index d7256a9c53301..f966b2b9f2a5f 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:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile index d7256a9c53301..f966b2b9f2a5f 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:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ 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 d495d5044adf5..670c2439764d6 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:18.04 +ARG IMAGE=ubuntu:24.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 14b1a32d712d6..aff3564732fc6 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -76,7 +76,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:18.04 (or rustlang/rust:nightly). + ubuntu:24.04 (or rustlang/rust:nightly). " exit fi From 21690f7320ad03cb33801239cf7f0bd99fae0c74 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 22 Jun 2024 06:05:25 -0400 Subject: [PATCH 1255/4206] Skip f128 tests on powerpc64le __addkf3 and __mulkf3 seem to hit a nondescript SIGILL. This is probably likely to just be another Qemu limitation. --- library/compiler-builtins/testcrate/build.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index cae83e1fc0930..f18bd90df16a0 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -24,9 +24,10 @@ fn main() { // FIXME(llvm): There is an ABI incompatibility between GCC and Clang on 32-bit x86. // See . || target.starts_with("i686") - // 32-bit PowerPC gets code generated that Qemu cannot handle. See + // 32-bit PowerPC and 64-bit LE gets code generated that Qemu cannot handle. See // . || target.starts_with("powerpc-") + || target.starts_with("powerpc64le-") // FIXME: We get different results from the builtin functions. See // . || target.starts_with("powerpc64-") From fdec3b65142a95a3d7020d0160d926243cf8e81c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 22 Jun 2024 04:20:48 -0500 Subject: [PATCH 1256/4206] Fix unset variables in the build script These were preventing building via Docker locally. --- library/compiler-builtins/ci/run-docker.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index aff3564732fc6..50ae9dc83a1f5 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -41,10 +41,10 @@ run() { export RUST_COMPILER_RT_ROOT=./compiler-rt fi - if [ "$GITHUB_ACTIONS" = "true" ]; then + if [ "${GITHUB_ACTIONS:-}" = "true" ]; then # Enable Docker image caching on GHA - buildx="buildx" + build_cmd=("buildx" "build") build_args=( "--cache-from" "type=local,src=/tmp/.buildx-cache" "--cache-to" "type=local,dest=/tmp/.buildx-cache-new" @@ -53,7 +53,7 @@ run() { ) fi - docker "${buildx:-}" build \ + docker ${build_cmd[@]:-build} \ -t "builtins-$target" \ ${build_args[@]:-} \ "ci/docker/$target" From bf503b5c9b1cefa2709f1b1b7fc5174485f43f50 Mon Sep 17 00:00:00 2001 From: beetrees Date: Sun, 23 Jun 2024 19:19:25 +0100 Subject: [PATCH 1257/4206] Fix building on AVR --- library/compiler-builtins/src/float/sub.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index 1492679f62309..3ab46495d4f8e 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -1,18 +1,16 @@ -use crate::float::add::__adddf3; -use crate::float::add::__addsf3; use crate::float::Float; intrinsics! { #[avr_skip] #[arm_aeabi_alias = __aeabi_fsub] pub extern "C" fn __subsf3(a: f32, b: f32) -> f32 { - __addsf3(a, f32::from_repr(b.repr() ^ f32::SIGN_MASK)) + crate::float::add::__addsf3(a, f32::from_repr(b.repr() ^ f32::SIGN_MASK)) } #[avr_skip] #[arm_aeabi_alias = __aeabi_dsub] pub extern "C" fn __subdf3(a: f64, b: f64) -> f64 { - __adddf3(a, f64::from_repr(b.repr() ^ f64::SIGN_MASK)) + crate::float::add::__adddf3(a, f64::from_repr(b.repr() ^ f64::SIGN_MASK)) } #[ppc_alias = __subkf3] From 1d7f2847e32d91aeae3ceb716589ba73361a66f2 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 25 Jun 2024 22:51:05 +0100 Subject: [PATCH 1258/4206] Release 0.1.113 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 4564ba9e54c12..ab43951593b31 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.112" +version = "0.1.113" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 55b3f8b13d2abdd93232f608e45f218e2ba0e8a6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 22 Jun 2024 13:47:33 -0500 Subject: [PATCH 1259/4206] Enable `f128 -> f16` tests on Linux Since updating the docker images in , it looks like `__extendhftf2` and `__trunctfhf2` are available on all 64-bit Linux platforms. --- library/compiler-builtins/testcrate/build.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index f18bd90df16a0..12c3e7d13655e 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -38,12 +38,9 @@ fn main() { } if target.starts_with("i586") || target.starts_with("i686") { - // 32-bit x86 seems to not have `__fixunstfti`, but does have everything else + // 32-bit x86 does not have `__fixunstfti`/`__fixtfti` but does have everything else features.insert(Feature::NoSysF128IntConvert); - } - - if target.contains("-unknown-linux-") { - // No `__extendhftf2` on x86, no `__trunctfhf2` on aarch64 + // FIXME: 32-bit x86 has a bug in `f128 -> f16` system libraries features.insert(Feature::NoSysF16F128Convert); } From ffb31aee1341454ea96daaeee67110aafaa5c4d3 Mon Sep 17 00:00:00 2001 From: beetrees Date: Sun, 30 Jun 2024 22:02:41 +0100 Subject: [PATCH 1260/4206] Fix incorrect rounding with subnormal/zero results of float multiplication --- library/compiler-builtins/src/float/mul.rs | 19 +++++++------------ .../compiler-builtins/testcrate/tests/mul.rs | 13 +++++-------- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index 007cc09a498a3..decf722e29ac1 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -149,18 +149,13 @@ where } // Otherwise, shift the significand of the result so that the round - // bit is the high bit of productLo. - if shift < bits { - let sticky = product_low << (bits - shift); - product_low = product_high << (bits - shift) | product_low >> shift | sticky; - product_high >>= shift; - } else if shift < (2 * bits) { - let sticky = product_high << (2 * bits - shift) | product_low; - product_low = product_high >> (shift - bits) | sticky; - product_high = zero; - } else { - product_high = zero; - } + // bit is the high bit of `product_low`. + // Ensure one of the non-highest bits in `product_low` is set if the shifted out bit are + // not all zero so that the result is correctly rounded below. + let sticky = product_low << (bits - shift) != zero; + product_low = + product_high << (bits - shift) | product_low >> shift | (sticky as u32).cast(); + product_high >>= shift; } else { // Result is normal before rounding; insert the exponent. product_high &= significand_mask; diff --git a/library/compiler-builtins/testcrate/tests/mul.rs b/library/compiler-builtins/testcrate/tests/mul.rs index 5daeadeb22bd6..818ca656a0d7d 100644 --- a/library/compiler-builtins/testcrate/tests/mul.rs +++ b/library/compiler-builtins/testcrate/tests/mul.rs @@ -107,14 +107,11 @@ macro_rules! float_mul { fuzz_float_2(N, |x: $f, y: $f| { let mul0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Mul::mul, x, y); let mul1: $f = $fn(x, y); - // multiplication of subnormals is not currently handled - if !(Float::is_subnormal(mul0) || Float::is_subnormal(mul1)) { - if !Float::eq_repr(mul0, mul1) { - panic!( - "{}({:?}, {:?}): std: {:?}, builtins: {:?}", - stringify!($fn), x, y, mul0, mul1 - ); - } + if !Float::eq_repr(mul0, mul1) { + panic!( + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn), x, y, mul0, mul1 + ); } }); } From c6bf88ab1cb5510971b51b4a16610db8eb792484 Mon Sep 17 00:00:00 2001 From: beetrees Date: Sun, 30 Jun 2024 22:40:57 +0100 Subject: [PATCH 1261/4206] Ignore broken nightly/system builtins --- .../compiler-builtins/testcrate/src/bench.rs | 17 ++++++++++++++--- .../compiler-builtins/testcrate/tests/mul.rs | 6 ++++-- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/testcrate/src/bench.rs b/library/compiler-builtins/testcrate/src/bench.rs index 1374d7b4f77ac..5ab9bac8715de 100644 --- a/library/compiler-builtins/testcrate/src/bench.rs +++ b/library/compiler-builtins/testcrate/src/bench.rs @@ -17,9 +17,10 @@ pub fn skip_sys_checks(test_name: &str) -> bool { "extend_f16_f32", "trunc_f32_f16", "trunc_f64_f16", - // FIXME(f16_f128): rounding error + // FIXME(#616): re-enable once fix is in nightly // - "mul_f128", + "mul_f32", + "mul_f64", ]; // FIXME(f16_f128): error on LE ppc64. There are more tests that are cfg-ed out completely @@ -29,7 +30,13 @@ pub fn skip_sys_checks(test_name: &str) -> bool { // FIXME(f16_f128): system symbols have incorrect results // - const X86_NO_SSE_SKIPPED: &[&str] = &["add_f128", "sub_f128", "powi_f32", "powi_f64"]; + const X86_NO_SSE_SKIPPED: &[&str] = + &["add_f128", "sub_f128", "mul_f128", "powi_f32", "powi_f64"]; + + // FIXME(f16_f128): Wide multiply carry bug in `compiler-rt`, re-enable when nightly no longer + // uses `compiler-rt` version. + // + const AARCH64_SKIPPED: &[&str] = &["mul_f128"]; // FIXME(llvm): system symbols have incorrect results on Windows // @@ -61,6 +68,10 @@ pub fn skip_sys_checks(test_name: &str) -> bool { return true; } + if cfg!(target_arch = "aarch64") && AARCH64_SKIPPED.contains(&test_name) { + return true; + } + if cfg!(target_family = "windows") && WINDOWS_SKIPPED.contains(&test_name) { return true; } diff --git a/library/compiler-builtins/testcrate/tests/mul.rs b/library/compiler-builtins/testcrate/tests/mul.rs index 818ca656a0d7d..90144bb06355d 100644 --- a/library/compiler-builtins/testcrate/tests/mul.rs +++ b/library/compiler-builtins/testcrate/tests/mul.rs @@ -123,9 +123,11 @@ macro_rules! float_mul { mod float_mul { use super::*; + // FIXME(#616): Stop ignoring arches that don't have native support once fix for builtins is in + // nightly. float_mul! { - f32, __mulsf3, Single, all(); - f64, __muldf3, Double, all(); + f32, __mulsf3, Single, not(target_arch = "arm"); + f64, __muldf3, Double, not(target_arch = "arm"); } } From 086a1c33eb4826d6159fcbee71857e54b7907427 Mon Sep 17 00:00:00 2001 From: beetrees Date: Sun, 30 Jun 2024 23:14:19 +0100 Subject: [PATCH 1262/4206] Temporarily `use define_rust_probestack;` --- library/compiler-builtins/src/probestack.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 0c30384db385a..46caf16768701 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -120,6 +120,10 @@ macro_rules! define_rust_probestack { }; } +// FIXME(rust-lang/rust#126984): Remove allow once lint is fixed +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +use define_rust_probestack; + // Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax, // ensuring that if any pages are unmapped we'll make a page fault. // From 32b12b647b97b1bf047c8a090e6686e3703b196f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 30 Jun 2024 23:03:44 -0400 Subject: [PATCH 1263/4206] Remove unnecessary benchmark files --- .../bench-175b45d1-aarch64-macos.txt | 500 ------------- .../bench-3cee6376-aarch64-macos.txt | 699 ------------------ 2 files changed, 1199 deletions(-) delete mode 100644 library/compiler-builtins/testcrate/bench-175b45d1-aarch64-macos.txt delete mode 100644 library/compiler-builtins/testcrate/bench-3cee6376-aarch64-macos.txt diff --git a/library/compiler-builtins/testcrate/bench-175b45d1-aarch64-macos.txt b/library/compiler-builtins/testcrate/bench-175b45d1-aarch64-macos.txt deleted file mode 100644 index e79bbe3687354..0000000000000 --- a/library/compiler-builtins/testcrate/bench-175b45d1-aarch64-macos.txt +++ /dev/null @@ -1,500 +0,0 @@ - -running 0 tests - -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s - -add_f32 compiler-builtins - time: [35.804 µs 35.863 µs 35.920 µs] -Found 5 outliers among 100 measurements (5.00%) - 2 (2.00%) high mild - 3 (3.00%) high severe - -add_f32 system time: [39.084 µs 39.127 µs 39.169 µs] -Found 11 outliers among 100 measurements (11.00%) - 7 (7.00%) high mild - 4 (4.00%) high severe - -add_f32 assembly (aarch64 unix) - time: [8.1034 µs 8.1441 µs 8.1866 µs] -Found 4 outliers among 100 measurements (4.00%) - 4 (4.00%) high mild - -add_f64 compiler-builtins - time: [35.647 µs 35.725 µs 35.799 µs] -Found 10 outliers among 100 measurements (10.00%) - 8 (8.00%) high mild - 2 (2.00%) high severe - -add_f64 system time: [39.308 µs 39.322 µs 39.336 µs] -Found 7 outliers among 100 measurements (7.00%) - 4 (4.00%) high mild - 3 (3.00%) high severe - -add_f64 assembly (aarch64 unix) - time: [8.0401 µs 8.0442 µs 8.0499 µs] -Found 11 outliers among 100 measurements (11.00%) - 2 (2.00%) high mild - 9 (9.00%) high severe - -add_f128 compiler-builtins - time: [41.801 µs 41.986 µs 42.201 µs] -Found 7 outliers among 100 measurements (7.00%) - 4 (4.00%) high mild - 3 (3.00%) high severe - -cmp_f32_gt compiler-builtins - time: [13.579 µs 13.675 µs 13.778 µs] -Found 16 outliers among 100 measurements (16.00%) - 6 (6.00%) high mild - 10 (10.00%) high severe - -cmp_f32_gt system time: [12.343 µs 12.348 µs 12.355 µs] -Found 13 outliers among 100 measurements (13.00%) - 1 (1.00%) low mild - 3 (3.00%) high mild - 9 (9.00%) high severe - -cmp_f32_gt assembly (aarch64 unix) - time: [8.2593 µs 8.3185 µs 8.3813 µs] -Found 1 outliers among 100 measurements (1.00%) - 1 (1.00%) high mild - -cmp_f32_unord compiler-builtins - time: [11.977 µs 12.042 µs 12.109 µs] -Found 13 outliers among 100 measurements (13.00%) - 5 (5.00%) low severe - 6 (6.00%) low mild - 2 (2.00%) high mild - -cmp_f32_unord system time: [8.1236 µs 8.1736 µs 8.2350 µs] -Found 18 outliers among 100 measurements (18.00%) - 5 (5.00%) high mild - 13 (13.00%) high severe - -cmp_f32_unord assembly (aarch64 unix) - time: [8.1446 µs 8.2080 µs 8.2762 µs] -Found 14 outliers among 100 measurements (14.00%) - 6 (6.00%) high mild - 8 (8.00%) high severe - -cmp_f64_gt compiler-builtins - time: [16.073 µs 16.077 µs 16.082 µs] -Found 17 outliers among 100 measurements (17.00%) - 2 (2.00%) low mild - 4 (4.00%) high mild - 11 (11.00%) high severe - -cmp_f64_gt system time: [12.456 µs 12.487 µs 12.522 µs] -Found 3 outliers among 100 measurements (3.00%) - 2 (2.00%) high mild - 1 (1.00%) high severe - -cmp_f64_gt assembly (aarch64 unix) - time: [8.0557 µs 8.0616 µs 8.0685 µs] -Found 3 outliers among 100 measurements (3.00%) - 1 (1.00%) high mild - 2 (2.00%) high severe - -cmp_f64_unord compiler-builtins - time: [10.715 µs 10.724 µs 10.737 µs] -Found 13 outliers among 100 measurements (13.00%) - 3 (3.00%) high mild - 10 (10.00%) high severe - -cmp_f64_unord system time: [8.0692 µs 8.0734 µs 8.0784 µs] -Found 3 outliers among 100 measurements (3.00%) - 1 (1.00%) high mild - 2 (2.00%) high severe - -cmp_f64_unord assembly (aarch64 unix) - time: [8.0569 µs 8.0677 µs 8.0818 µs] -Found 18 outliers among 100 measurements (18.00%) - 4 (4.00%) high mild - 14 (14.00%) high severe - -cmp_f128_gt compiler-builtins - time: [18.234 µs 18.401 µs 18.602 µs] - -cmp_f128_unord compiler-builtins - time: [13.410 µs 13.471 µs 13.542 µs] -Found 7 outliers among 100 measurements (7.00%) - 7 (7.00%) high mild - -conv_u32_f32 compiler-builtins - time: [774.58 ns 776.01 ns 777.59 ns] -Found 9 outliers among 100 measurements (9.00%) - 2 (2.00%) high mild - 7 (7.00%) high severe - -conv_u32_f32 system time: [622.68 ns 625.64 ns 629.26 ns] -Found 16 outliers among 100 measurements (16.00%) - 7 (7.00%) high mild - 9 (9.00%) high severe - -conv_u32_f32 assembly (aarch64 unix) - time: [468.05 ns 469.76 ns 471.46 ns] -Found 3 outliers among 100 measurements (3.00%) - 2 (2.00%) high mild - 1 (1.00%) high severe - -conv_u32_f64 compiler-builtins - time: [617.61 ns 618.00 ns 618.52 ns] -Found 13 outliers among 100 measurements (13.00%) - 4 (4.00%) high mild - 9 (9.00%) high severe - -conv_u32_f64 system time: [469.56 ns 471.03 ns 472.81 ns] -Found 11 outliers among 100 measurements (11.00%) - 7 (7.00%) high mild - 4 (4.00%) high severe - -conv_u32_f64 assembly (aarch64 unix) - time: [464.43 ns 465.01 ns 465.72 ns] -Found 13 outliers among 100 measurements (13.00%) - 5 (5.00%) high mild - 8 (8.00%) high severe - -conv_u64_f32 compiler-builtins - time: [847.95 ns 848.19 ns 848.46 ns] -Found 19 outliers among 100 measurements (19.00%) - 3 (3.00%) low mild - 9 (9.00%) high mild - 7 (7.00%) high severe - -conv_u64_f32 system time: [701.68 ns 701.95 ns 702.30 ns] -Found 10 outliers among 100 measurements (10.00%) - 4 (4.00%) high mild - 6 (6.00%) high severe - -conv_u64_f32 assembly (aarch64 unix) - time: [511.73 ns 512.43 ns 513.32 ns] -Found 6 outliers among 100 measurements (6.00%) - 6 (6.00%) high mild - -conv_u64_f64 compiler-builtins - time: [681.23 ns 682.55 ns 684.30 ns] -Found 18 outliers among 100 measurements (18.00%) - 1 (1.00%) high mild - 17 (17.00%) high severe - -conv_u64_f64 system time: [679.34 ns 679.57 ns 679.88 ns] -Found 18 outliers among 100 measurements (18.00%) - 1 (1.00%) low mild - 6 (6.00%) high mild - 11 (11.00%) high severe - -conv_u64_f64 assembly (aarch64 unix) - time: [509.90 ns 510.09 ns 510.30 ns] -Found 15 outliers among 100 measurements (15.00%) - 6 (6.00%) high mild - 9 (9.00%) high severe - -conv_u128_f32 compiler-builtins - time: [1.1368 µs 1.1372 µs 1.1377 µs] -Found 14 outliers among 100 measurements (14.00%) - 8 (8.00%) high mild - 6 (6.00%) high severe - -conv_u128_f32 system time: [1.4338 µs 1.4370 µs 1.4410 µs] -Found 7 outliers among 100 measurements (7.00%) - 2 (2.00%) high mild - 5 (5.00%) high severe - -conv_u128_f64 compiler-builtins - time: [1.0133 µs 1.0143 µs 1.0156 µs] -Found 16 outliers among 100 measurements (16.00%) - 2 (2.00%) high mild - 14 (14.00%) high severe - -conv_u128_f64 system time: [1.3473 µs 1.3530 µs 1.3600 µs] -Found 4 outliers among 100 measurements (4.00%) - 4 (4.00%) high mild - -conv_i32_f32 compiler-builtins - time: [906.53 ns 907.86 ns 909.23 ns] -Found 7 outliers among 100 measurements (7.00%) - 4 (4.00%) high mild - 3 (3.00%) high severe - -conv_i32_f32 system time: [914.53 ns 915.69 ns 917.01 ns] -Found 10 outliers among 100 measurements (10.00%) - 6 (6.00%) high mild - 4 (4.00%) high severe - -conv_i32_f32 assembly (aarch64 unix) - time: [464.55 ns 465.10 ns 465.83 ns] -Found 4 outliers among 100 measurements (4.00%) - 4 (4.00%) high mild - -conv_i32_f64 compiler-builtins - time: [617.63 ns 617.92 ns 618.27 ns] -Found 12 outliers among 100 measurements (12.00%) - 3 (3.00%) high mild - 9 (9.00%) high severe - -conv_i32_f64 system time: [622.83 ns 624.19 ns 625.61 ns] -Found 6 outliers among 100 measurements (6.00%) - 5 (5.00%) high mild - 1 (1.00%) high severe - -conv_i32_f64 assembly (aarch64 unix) - time: [465.24 ns 466.04 ns 466.95 ns] -Found 11 outliers among 100 measurements (11.00%) - 4 (4.00%) high mild - 7 (7.00%) high severe - -conv_i64_f32 compiler-builtins - time: [852.67 ns 853.92 ns 855.34 ns] -Found 11 outliers among 100 measurements (11.00%) - 3 (3.00%) high mild - 8 (8.00%) high severe - -conv_i64_f32 system time: [906.94 ns 908.04 ns 909.33 ns] -Found 15 outliers among 100 measurements (15.00%) - 2 (2.00%) high mild - 13 (13.00%) high severe - -conv_i64_f32 assembly (aarch64 unix) - time: [510.84 ns 511.27 ns 511.80 ns] -Found 8 outliers among 100 measurements (8.00%) - 3 (3.00%) high mild - 5 (5.00%) high severe - -conv_i64_f64 compiler-builtins - time: [932.35 ns 932.97 ns 933.76 ns] -Found 10 outliers among 100 measurements (10.00%) - 4 (4.00%) high mild - 6 (6.00%) high severe - -conv_i64_f64 system time: [955.91 ns 958.95 ns 962.05 ns] -Found 5 outliers among 100 measurements (5.00%) - 3 (3.00%) high mild - 2 (2.00%) high severe - -conv_i64_f64 assembly (aarch64 unix) - time: [510.19 ns 510.72 ns 511.44 ns] -Found 9 outliers among 100 measurements (9.00%) - 5 (5.00%) high mild - 4 (4.00%) high severe - -conv_i128_f32 compiler-builtins - time: [1.4248 µs 1.4285 µs 1.4323 µs] -Found 12 outliers among 100 measurements (12.00%) - 7 (7.00%) high mild - 5 (5.00%) high severe - -conv_i128_f32 system time: [1.6970 µs 1.7017 µs 1.7069 µs] -Found 5 outliers among 100 measurements (5.00%) - 3 (3.00%) high mild - 2 (2.00%) high severe - -conv_i128_f64 compiler-builtins - time: [1.3132 µs 1.3161 µs 1.3191 µs] -Found 2 outliers among 100 measurements (2.00%) - 1 (1.00%) high mild - 1 (1.00%) high severe - -conv_i128_f64 system time: [1.6071 µs 1.6100 µs 1.6133 µs] -Found 4 outliers among 100 measurements (4.00%) - 3 (3.00%) high mild - 1 (1.00%) high severe - -conv_f64_u32 compiler-builtins - time: [640.35 ns 641.00 ns 641.68 ns] -Found 6 outliers among 100 measurements (6.00%) - 4 (4.00%) high mild - 2 (2.00%) high severe - -conv_f64_u32 system time: [640.87 ns 641.63 ns 642.42 ns] -Found 3 outliers among 100 measurements (3.00%) - 1 (1.00%) high mild - 2 (2.00%) high severe - -conv_f64_u32 assembly (aarch64 unix) - time: [482.02 ns 482.67 ns 483.38 ns] -Found 1 outliers among 100 measurements (1.00%) - 1 (1.00%) high severe - -conv_f64_u64 compiler-builtins - time: [638.58 ns 638.98 ns 639.45 ns] -Found 15 outliers among 100 measurements (15.00%) - 1 (1.00%) high mild - 14 (14.00%) high severe - -conv_f64_u64 system time: [642.54 ns 644.07 ns 645.59 ns] -Found 4 outliers among 100 measurements (4.00%) - 3 (3.00%) high mild - 1 (1.00%) high severe - -conv_f64_u64 assembly (aarch64 unix) - time: [482.65 ns 483.70 ns 484.87 ns] -Found 1 outliers among 100 measurements (1.00%) - 1 (1.00%) high mild - -conv_f64_u128 compiler-builtins - time: [1.0631 µs 1.0652 µs 1.0674 µs] -Found 8 outliers among 100 measurements (8.00%) - 7 (7.00%) high mild - 1 (1.00%) high severe - -conv_f64_u128 system time: [821.41 ns 823.45 ns 825.74 ns] -Found 11 outliers among 100 measurements (11.00%) - 8 (8.00%) high mild - 3 (3.00%) high severe - -conv_f64_i32 compiler-builtins - time: [826.76 ns 845.08 ns 870.23 ns] -Found 4 outliers among 100 measurements (4.00%) - 4 (4.00%) high mild - -conv_f64_i32 system time: [764.12 ns 764.63 ns 765.26 ns] -Found 2 outliers among 100 measurements (2.00%) - 2 (2.00%) high severe - -conv_f64_i32 assembly (aarch64 unix) - time: [484.50 ns 485.98 ns 487.54 ns] -Found 3 outliers among 100 measurements (3.00%) - 1 (1.00%) high mild - 2 (2.00%) high severe - -conv_f64_i64 compiler-builtins - time: [797.27 ns 798.19 ns 799.84 ns] -Found 9 outliers among 100 measurements (9.00%) - 5 (5.00%) high mild - 4 (4.00%) high severe - -conv_f64_i64 system time: [768.74 ns 769.52 ns 770.23 ns] -Found 1 outliers among 100 measurements (1.00%) - 1 (1.00%) high severe - -conv_f64_i64 assembly (aarch64 unix) - time: [480.59 ns 481.03 ns 481.46 ns] -Found 3 outliers among 100 measurements (3.00%) - 2 (2.00%) high mild - 1 (1.00%) high severe - -conv_f64_i128 compiler-builtins - time: [1.0577 µs 1.0591 µs 1.0606 µs] -Found 2 outliers among 100 measurements (2.00%) - 1 (1.00%) high mild - 1 (1.00%) high severe - -conv_f64_i128 system time: [1.0181 µs 1.0195 µs 1.0211 µs] -Found 3 outliers among 100 measurements (3.00%) - 3 (3.00%) high mild - -conv_f32_u32 compiler-builtins - time: [800.40 ns 801.39 ns 802.35 ns] -Found 2 outliers among 100 measurements (2.00%) - 2 (2.00%) high mild - -conv_f32_u32 system time: [638.12 ns 638.34 ns 638.63 ns] -Found 11 outliers among 100 measurements (11.00%) - 4 (4.00%) high mild - 7 (7.00%) high severe - -conv_f32_u32 assembly (aarch64 unix) - time: [479.37 ns 480.97 ns 483.32 ns] -Found 13 outliers among 100 measurements (13.00%) - 6 (6.00%) high mild - 7 (7.00%) high severe - -conv_f32_u64 compiler-builtins - time: [801.95 ns 803.64 ns 805.75 ns] - -conv_f32_u64 system time: [638.20 ns 638.56 ns 639.07 ns] -Found 10 outliers among 100 measurements (10.00%) - 1 (1.00%) high mild - 9 (9.00%) high severe - -conv_f32_u64 assembly (aarch64 unix) - time: [480.07 ns 480.47 ns 480.86 ns] -Found 2 outliers among 100 measurements (2.00%) - 1 (1.00%) high mild - 1 (1.00%) high severe - -conv_f32_u128 compiler-builtins - time: [1.1579 µs 1.1623 µs 1.1657 µs] -Found 14 outliers among 100 measurements (14.00%) - 2 (2.00%) low severe - 7 (7.00%) high mild - 5 (5.00%) high severe - -conv_f32_u128 system time: [1.0344 µs 1.0394 µs 1.0450 µs] - -conv_f32_i32 compiler-builtins - time: [800.14 ns 801.52 ns 803.26 ns] -Found 10 outliers among 100 measurements (10.00%) - 8 (8.00%) high mild - 2 (2.00%) high severe - -conv_f32_i32 system time: [741.36 ns 741.74 ns 742.13 ns] -Found 4 outliers among 100 measurements (4.00%) - 2 (2.00%) high mild - 2 (2.00%) high severe - -conv_f32_i32 assembly (aarch64 unix) - time: [484.35 ns 486.08 ns 488.11 ns] -Found 17 outliers among 100 measurements (17.00%) - 9 (9.00%) high mild - 8 (8.00%) high severe - -conv_f32_i64 compiler-builtins - time: [800.94 ns 802.68 ns 804.74 ns] - -conv_f32_i64 system time: [748.60 ns 750.68 ns 753.16 ns] -Found 9 outliers among 100 measurements (9.00%) - 4 (4.00%) high mild - 5 (5.00%) high severe - -conv_f32_i64 assembly (aarch64 unix) - time: [480.70 ns 481.23 ns 481.82 ns] -Found 4 outliers among 100 measurements (4.00%) - 2 (2.00%) high mild - 2 (2.00%) high severe - -conv_f32_i128 compiler-builtins - time: [1.1774 µs 1.1829 µs 1.1887 µs] -Found 11 outliers among 100 measurements (11.00%) - 1 (1.00%) low severe - 7 (7.00%) low mild - 1 (1.00%) high mild - 2 (2.00%) high severe - -conv_f32_i128 system time: [1.1785 µs 1.1853 µs 1.1941 µs] -Found 7 outliers among 100 measurements (7.00%) - 2 (2.00%) high mild - 5 (5.00%) high severe - -div_f32 compiler-builtins - time: [38.852 µs 39.011 µs 39.178 µs] -Found 3 outliers among 100 measurements (3.00%) - 3 (3.00%) high mild - -div_f32 system time: [41.846 µs 41.920 µs 42.005 µs] -Found 3 outliers among 100 measurements (3.00%) - 1 (1.00%) high mild - 2 (2.00%) high severe - -div_f32 assembly (aarch64 unix) - time: [8.1309 µs 8.1627 µs 8.2005 µs] -Found 2 outliers among 100 measurements (2.00%) - 2 (2.00%) high mild - -div_f64 compiler-builtins - time: [50.369 µs 50.605 µs 50.857 µs] -Found 15 outliers among 100 measurements (15.00%) - 11 (11.00%) high mild - 4 (4.00%) high severe - -div_f64 system time: [53.506 µs 53.582 µs 53.676 µs] -Found 8 outliers among 100 measurements (8.00%) - 4 (4.00%) high mild - 4 (4.00%) high severe - -div_f64 assembly (aarch64 unix) - time: [8.0695 µs 8.0807 µs 8.0948 µs] -Found 4 outliers among 100 measurements (4.00%) - 2 (2.00%) high mild - 2 (2.00%) high severe - diff --git a/library/compiler-builtins/testcrate/bench-3cee6376-aarch64-macos.txt b/library/compiler-builtins/testcrate/bench-3cee6376-aarch64-macos.txt deleted file mode 100644 index 131e7a85a0b55..0000000000000 --- a/library/compiler-builtins/testcrate/bench-3cee6376-aarch64-macos.txt +++ /dev/null @@ -1,699 +0,0 @@ - -running 0 tests - -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s - -add_f32/compiler-builtins - time: [36.813 µs 37.048 µs 37.303 µs] -Found 5 outliers among 100 measurements (5.00%) - 5 (5.00%) high mild -add_f32/system time: [39.103 µs 39.142 µs 39.189 µs] -Found 8 outliers among 100 measurements (8.00%) - 2 (2.00%) high mild - 6 (6.00%) high severe -add_f32/assembly (aarch64 unix) - time: [8.3786 µs 8.4680 µs 8.5570 µs] - -add_f64/compiler-builtins - time: [35.784 µs 35.819 µs 35.863 µs] -Found 4 outliers among 100 measurements (4.00%) - 1 (1.00%) high mild - 3 (3.00%) high severe -add_f64/system time: [39.634 µs 39.689 µs 39.746 µs] -Found 16 outliers among 100 measurements (16.00%) - 4 (4.00%) high mild - 12 (12.00%) high severe -add_f64/assembly (aarch64 unix) - time: [8.0533 µs 8.0599 µs 8.0670 µs] -Found 14 outliers among 100 measurements (14.00%) - 6 (6.00%) high mild - 8 (8.00%) high severe - -add_f128/compiler-builtins - time: [41.830 µs 41.920 µs 42.005 µs] - -cmp_f32_gt/compiler-builtins - time: [13.405 µs 13.411 µs 13.418 µs] -Found 18 outliers among 100 measurements (18.00%) - 4 (4.00%) high mild - 14 (14.00%) high severe -cmp_f32_gt/system time: [12.348 µs 12.355 µs 12.363 µs] -Found 12 outliers among 100 measurements (12.00%) - 2 (2.00%) high mild - 10 (10.00%) high severe -cmp_f32_gt/assembly (aarch64 unix) - time: [8.1233 µs 8.1625 µs 8.2072 µs] -Found 12 outliers among 100 measurements (12.00%) - 7 (7.00%) high mild - 5 (5.00%) high severe - -cmp_f32_unord/compiler-builtins - time: [11.349 µs 11.467 µs 11.584 µs] -cmp_f32_unord/system time: [8.0714 µs 8.0792 µs 8.0890 µs] -Found 16 outliers among 100 measurements (16.00%) - 4 (4.00%) high mild - 12 (12.00%) high severe -cmp_f32_unord/assembly (aarch64 unix) - time: [8.1121 µs 8.1705 µs 8.2325 µs] -Found 20 outliers among 100 measurements (20.00%) - 3 (3.00%) high mild - 17 (17.00%) high severe - -cmp_f64_gt/compiler-builtins - time: [13.749 µs 13.837 µs 13.934 µs] -Found 20 outliers among 100 measurements (20.00%) - 9 (9.00%) low mild - 7 (7.00%) high mild - 4 (4.00%) high severe -cmp_f64_gt/system time: [12.475 µs 12.515 µs 12.565 µs] -Found 4 outliers among 100 measurements (4.00%) - 4 (4.00%) high mild -cmp_f64_gt/assembly (aarch64 unix) - time: [8.0456 µs 8.0540 µs 8.0653 µs] -Found 12 outliers among 100 measurements (12.00%) - 3 (3.00%) high mild - 9 (9.00%) high severe - -cmp_f64_unord/compiler-builtins - time: [10.723 µs 10.730 µs 10.739 µs] -Found 15 outliers among 100 measurements (15.00%) - 5 (5.00%) high mild - 10 (10.00%) high severe -cmp_f64_unord/system time: [8.0944 µs 8.1296 µs 8.1683 µs] -Found 17 outliers among 100 measurements (17.00%) - 4 (4.00%) high mild - 13 (13.00%) high severe -cmp_f64_unord/assembly (aarch64 unix) - time: [8.1042 µs 8.1337 µs 8.1662 µs] -Found 3 outliers among 100 measurements (3.00%) - 3 (3.00%) high mild - -cmp_f128_gt/compiler-builtins - time: [20.508 µs 20.558 µs 20.615 µs] -Found 8 outliers among 100 measurements (8.00%) - 2 (2.00%) high mild - 6 (6.00%) high severe - -cmp_f128_unord/compiler-builtins - time: [13.332 µs 13.346 µs 13.360 µs] -Found 4 outliers among 100 measurements (4.00%) - 2 (2.00%) high mild - 2 (2.00%) high severe - -conv_u32_f32/compiler-builtins - time: [621.20 ns 621.89 ns 622.65 ns] -Found 7 outliers among 100 measurements (7.00%) - 4 (4.00%) high mild - 3 (3.00%) high severe -conv_u32_f32/system time: [621.44 ns 622.08 ns 622.74 ns] -Found 4 outliers among 100 measurements (4.00%) - 3 (3.00%) high mild - 1 (1.00%) high severe -conv_u32_f32/assembly (aarch64 unix) - time: [465.96 ns 466.65 ns 467.45 ns] -Found 13 outliers among 100 measurements (13.00%) - 3 (3.00%) high mild - 10 (10.00%) high severe - -conv_u32_f64/compiler-builtins - time: [619.71 ns 620.51 ns 621.52 ns] -Found 5 outliers among 100 measurements (5.00%) - 4 (4.00%) high mild - 1 (1.00%) high severe -conv_u32_f64/system time: [466.60 ns 467.14 ns 467.77 ns] -Found 2 outliers among 100 measurements (2.00%) - 2 (2.00%) high mild -conv_u32_f64/assembly (aarch64 unix) - time: [464.02 ns 464.32 ns 464.69 ns] -Found 2 outliers among 100 measurements (2.00%) - 1 (1.00%) high mild - 1 (1.00%) high severe - -conv_u64_f32/compiler-builtins - time: [851.24 ns 852.98 ns 854.77 ns] -Found 5 outliers among 100 measurements (5.00%) - 5 (5.00%) high mild -conv_u64_f32/system time: [724.35 ns 729.43 ns 735.07 ns] -Found 4 outliers among 100 measurements (4.00%) - 4 (4.00%) high mild -conv_u64_f32/assembly (aarch64 unix) - time: [513.30 ns 514.64 ns 516.16 ns] -Found 8 outliers among 100 measurements (8.00%) - 8 (8.00%) high mild - -conv_u64_f64/compiler-builtins - time: [850.72 ns 853.26 ns 856.54 ns] -Found 15 outliers among 100 measurements (15.00%) - 2 (2.00%) high mild - 13 (13.00%) high severe -conv_u64_f64/system time: [681.43 ns 682.54 ns 683.79 ns] -Found 4 outliers among 100 measurements (4.00%) - 3 (3.00%) high mild - 1 (1.00%) high severe -conv_u64_f64/assembly (aarch64 unix) - time: [511.37 ns 511.71 ns 512.02 ns] -Found 1 outliers among 100 measurements (1.00%) - 1 (1.00%) high severe - -conv_u128_f32/compiler-builtins - time: [1.1395 µs 1.1409 µs 1.1424 µs] -Found 10 outliers among 100 measurements (10.00%) - 6 (6.00%) high mild - 4 (4.00%) high severe -conv_u128_f32/system time: [1.4348 µs 1.4369 µs 1.4390 µs] -Found 5 outliers among 100 measurements (5.00%) - 4 (4.00%) high mild - 1 (1.00%) high severe - -conv_u128_f64/compiler-builtins - time: [1.0148 µs 1.0157 µs 1.0167 µs] -Found 4 outliers among 100 measurements (4.00%) - 3 (3.00%) high mild - 1 (1.00%) high severe -conv_u128_f64/system time: [1.3404 µs 1.3423 µs 1.3442 µs] -Found 8 outliers among 100 measurements (8.00%) - 7 (7.00%) high mild - 1 (1.00%) high severe - -conv_i32_f32/compiler-builtins - time: [902.89 ns 903.81 ns 904.84 ns] -Found 7 outliers among 100 measurements (7.00%) - 4 (4.00%) high mild - 3 (3.00%) high severe -conv_i32_f32/system time: [942.62 ns 949.04 ns 955.77 ns] -Found 4 outliers among 100 measurements (4.00%) - 3 (3.00%) high mild - 1 (1.00%) high severe -conv_i32_f32/assembly (aarch64 unix) - time: [466.06 ns 466.60 ns 467.27 ns] -Found 1 outliers among 100 measurements (1.00%) - 1 (1.00%) high severe - -conv_i32_f64/compiler-builtins - time: [618.98 ns 619.24 ns 619.55 ns] -Found 17 outliers among 100 measurements (17.00%) - 1 (1.00%) low mild - 3 (3.00%) high mild - 13 (13.00%) high severe -conv_i32_f64/system time: [622.18 ns 623.41 ns 624.85 ns] -Found 8 outliers among 100 measurements (8.00%) - 5 (5.00%) high mild - 3 (3.00%) high severe -conv_i32_f64/assembly (aarch64 unix) - time: [466.26 ns 466.76 ns 467.35 ns] -Found 9 outliers among 100 measurements (9.00%) - 5 (5.00%) high mild - 4 (4.00%) high severe - -conv_i64_f32/compiler-builtins - time: [850.11 ns 850.45 ns 850.88 ns] -Found 15 outliers among 100 measurements (15.00%) - 1 (1.00%) low severe - 1 (1.00%) low mild - 3 (3.00%) high mild - 10 (10.00%) high severe -conv_i64_f32/system time: [908.36 ns 908.70 ns 909.10 ns] -Found 12 outliers among 100 measurements (12.00%) - 3 (3.00%) high mild - 9 (9.00%) high severe -conv_i64_f32/assembly (aarch64 unix) - time: [513.56 ns 514.44 ns 515.38 ns] -Found 8 outliers among 100 measurements (8.00%) - 8 (8.00%) high mild - -conv_i64_f64/compiler-builtins - time: [935.39 ns 935.78 ns 936.26 ns] -Found 13 outliers among 100 measurements (13.00%) - 5 (5.00%) high mild - 8 (8.00%) high severe -conv_i64_f64/system time: [946.56 ns 947.33 ns 948.20 ns] -Found 8 outliers among 100 measurements (8.00%) - 6 (6.00%) high mild - 2 (2.00%) high severe -conv_i64_f64/assembly (aarch64 unix) - time: [511.55 ns 512.03 ns 512.56 ns] -Found 21 outliers among 100 measurements (21.00%) - 4 (4.00%) high mild - 17 (17.00%) high severe - -conv_i128_f32/compiler-builtins - time: [1.4206 µs 1.4218 µs 1.4232 µs] -Found 10 outliers among 100 measurements (10.00%) - 5 (5.00%) high mild - 5 (5.00%) high severe -conv_i128_f32/system time: [1.6863 µs 1.6891 µs 1.6922 µs] -Found 10 outliers among 100 measurements (10.00%) - 9 (9.00%) high mild - 1 (1.00%) high severe - -conv_i128_f64/compiler-builtins - time: [1.3110 µs 1.3122 µs 1.3136 µs] -Found 4 outliers among 100 measurements (4.00%) - 2 (2.00%) high mild - 2 (2.00%) high severe -conv_i128_f64/system time: [1.6022 µs 1.6048 µs 1.6090 µs] -Found 5 outliers among 100 measurements (5.00%) - 3 (3.00%) high mild - 2 (2.00%) high severe - -conv_f64_u32/compiler-builtins - time: [798.65 ns 799.42 ns 800.39 ns] -Found 15 outliers among 100 measurements (15.00%) - 6 (6.00%) high mild - 9 (9.00%) high severe -conv_f64_u32/system time: [639.48 ns 639.88 ns 640.40 ns] -Found 16 outliers among 100 measurements (16.00%) - 1 (1.00%) low mild - 5 (5.00%) high mild - 10 (10.00%) high severe -conv_f64_u32/assembly (aarch64 unix) - time: [480.78 ns 481.35 ns 482.17 ns] -Found 7 outliers among 100 measurements (7.00%) - 5 (5.00%) high mild - 2 (2.00%) high severe - -conv_f64_u64/compiler-builtins - time: [799.56 ns 800.54 ns 801.89 ns] -Found 4 outliers among 100 measurements (4.00%) - 2 (2.00%) high mild - 2 (2.00%) high severe -conv_f64_u64/system time: [640.72 ns 641.24 ns 641.81 ns] -Found 5 outliers among 100 measurements (5.00%) - 3 (3.00%) high mild - 2 (2.00%) high severe -conv_f64_u64/assembly (aarch64 unix) - time: [481.54 ns 482.48 ns 483.53 ns] -Found 6 outliers among 100 measurements (6.00%) - 1 (1.00%) low severe - 1 (1.00%) low mild - 3 (3.00%) high mild - 1 (1.00%) high severe - -conv_f64_u128/compiler-builtins - time: [1.0510 µs 1.0515 µs 1.0520 µs] -Found 13 outliers among 100 measurements (13.00%) - 1 (1.00%) low mild - 2 (2.00%) high mild - 10 (10.00%) high severe -conv_f64_u128/system time: [818.45 ns 819.23 ns 820.15 ns] -Found 2 outliers among 100 measurements (2.00%) - 2 (2.00%) high mild - -conv_f64_i32/compiler-builtins - time: [800.56 ns 801.31 ns 802.21 ns] -Found 5 outliers among 100 measurements (5.00%) - 3 (3.00%) high mild - 2 (2.00%) high severe -conv_f64_i32/system time: [765.62 ns 766.15 ns 766.80 ns] -Found 3 outliers among 100 measurements (3.00%) - 2 (2.00%) high mild - 1 (1.00%) high severe -conv_f64_i32/assembly (aarch64 unix) - time: [471.65 ns 472.77 ns 473.89 ns] -Found 10 outliers among 100 measurements (10.00%) - 1 (1.00%) low mild - 8 (8.00%) high mild - 1 (1.00%) high severe - -conv_f64_i64/compiler-builtins - time: [801.00 ns 804.55 ns 808.72 ns] -Found 18 outliers among 100 measurements (18.00%) - 6 (6.00%) high mild - 12 (12.00%) high severe -conv_f64_i64/system time: [770.28 ns 772.47 ns 775.21 ns] -Found 2 outliers among 100 measurements (2.00%) - 2 (2.00%) high mild -conv_f64_i64/assembly (aarch64 unix) - time: [491.56 ns 494.96 ns 499.19 ns] -Found 3 outliers among 100 measurements (3.00%) - 2 (2.00%) high mild - 1 (1.00%) high severe - -conv_f64_i128/compiler-builtins - time: [1.0637 µs 1.0704 µs 1.0762 µs] -Found 5 outliers among 100 measurements (5.00%) - 5 (5.00%) high mild -conv_f64_i128/system time: [1.0022 µs 1.0027 µs 1.0033 µs] -Found 4 outliers among 100 measurements (4.00%) - 1 (1.00%) low severe - 3 (3.00%) high severe - -conv_f32_u32/compiler-builtins - time: [644.56 ns 647.01 ns 649.95 ns] -Found 15 outliers among 100 measurements (15.00%) - 13 (13.00%) high mild - 2 (2.00%) high severe -conv_f32_u32/system time: [648.12 ns 651.20 ns 654.54 ns] -Found 9 outliers among 100 measurements (9.00%) - 7 (7.00%) high mild - 2 (2.00%) high severe -conv_f32_u32/assembly (aarch64 unix) - time: [481.02 ns 482.71 ns 484.60 ns] -Found 12 outliers among 100 measurements (12.00%) - 1 (1.00%) low mild - 10 (10.00%) high mild - 1 (1.00%) high severe - -conv_f32_u64/compiler-builtins - time: [644.14 ns 646.61 ns 649.53 ns] -Found 11 outliers among 100 measurements (11.00%) - 6 (6.00%) high mild - 5 (5.00%) high severe -conv_f32_u64/system time: [646.21 ns 650.17 ns 654.55 ns] -Found 3 outliers among 100 measurements (3.00%) - 3 (3.00%) high mild -conv_f32_u64/assembly (aarch64 unix) - time: [473.36 ns 474.60 ns 476.00 ns] -Found 9 outliers among 100 measurements (9.00%) - 2 (2.00%) low mild - 5 (5.00%) high mild - 2 (2.00%) high severe - -conv_f32_u128/compiler-builtins - time: [1.0820 µs 1.0828 µs 1.0839 µs] -Found 2 outliers among 100 measurements (2.00%) - 1 (1.00%) high mild - 1 (1.00%) high severe -conv_f32_u128/system time: [1.0003 µs 1.0042 µs 1.0076 µs] -Found 21 outliers among 100 measurements (21.00%) - 1 (1.00%) low mild - 3 (3.00%) high mild - 17 (17.00%) high severe - -conv_f32_i32/compiler-builtins - time: [801.13 ns 801.82 ns 802.53 ns] -Found 2 outliers among 100 measurements (2.00%) - 2 (2.00%) high severe -conv_f32_i32/system time: [745.17 ns 745.97 ns 746.78 ns] -Found 2 outliers among 100 measurements (2.00%) - 2 (2.00%) high severe -conv_f32_i32/assembly (aarch64 unix) - time: [469.87 ns 470.65 ns 471.57 ns] -Found 1 outliers among 100 measurements (1.00%) - 1 (1.00%) high mild - -conv_f32_i64/compiler-builtins - time: [799.44 ns 799.94 ns 800.59 ns] -Found 4 outliers among 100 measurements (4.00%) - 1 (1.00%) high mild - 3 (3.00%) high severe -conv_f32_i64/system time: [744.81 ns 745.17 ns 745.62 ns] -Found 14 outliers among 100 measurements (14.00%) - 5 (5.00%) high mild - 9 (9.00%) high severe -conv_f32_i64/assembly (aarch64 unix) - time: [465.06 ns 466.01 ns 467.12 ns] -Found 13 outliers among 100 measurements (13.00%) - 2 (2.00%) low severe - 5 (5.00%) high mild - 6 (6.00%) high severe - -conv_f32_i128/compiler-builtins - time: [1.1390 µs 1.1515 µs 1.1637 µs] -conv_f32_i128/system time: [1.1315 µs 1.1330 µs 1.1347 µs] -Found 6 outliers among 100 measurements (6.00%) - 3 (3.00%) low mild - 2 (2.00%) high mild - 1 (1.00%) high severe - -div_f32/compiler-builtins - time: [39.408 µs 39.676 µs 39.969 µs] -Found 5 outliers among 100 measurements (5.00%) - 5 (5.00%) high mild -div_f32/system time: [42.108 µs 42.248 µs 42.528 µs] -Found 11 outliers among 100 measurements (11.00%) - 4 (4.00%) high mild - 7 (7.00%) high severe -div_f32/assembly (aarch64 unix) - time: [8.0724 µs 8.0794 µs 8.0870 µs] -Found 7 outliers among 100 measurements (7.00%) - 5 (5.00%) high mild - 2 (2.00%) high severe - -div_f64/compiler-builtins - time: [49.992 µs 50.014 µs 50.040 µs] -Found 5 outliers among 100 measurements (5.00%) - 5 (5.00%) high severe -div_f64/system time: [53.577 µs 53.651 µs 53.743 µs] -Found 6 outliers among 100 measurements (6.00%) - 4 (4.00%) high mild - 2 (2.00%) high severe -div_f64/assembly (aarch64 unix) - time: [8.0976 µs 8.1064 µs 8.1158 µs] -Found 6 outliers among 100 measurements (6.00%) - 3 (3.00%) high mild - 3 (3.00%) high severe - -extend_f16_f32/compiler-builtins - time: [804.09 ns 805.38 ns 807.09 ns] -Found 3 outliers among 100 measurements (3.00%) - 1 (1.00%) high mild - 2 (2.00%) high severe -extend_f16_f32/system time: [641.07 ns 641.76 ns 642.60 ns] -Found 12 outliers among 100 measurements (12.00%) - 6 (6.00%) high mild - 6 (6.00%) high severe -extend_f16_f32/assembly (aarch64 unix) - time: [456.69 ns 457.14 ns 457.68 ns] -Found 8 outliers among 100 measurements (8.00%) - 4 (4.00%) low mild - 2 (2.00%) high mild - 2 (2.00%) high severe - -extend_f16_f128/compiler-builtins - time: [1.1025 µs 1.1035 µs 1.1045 µs] -Found 2 outliers among 100 measurements (2.00%) - 1 (1.00%) high mild - 1 (1.00%) high severe - -extend_f32_f64/compiler-builtins - time: [799.30 ns 799.68 ns 800.16 ns] -Found 13 outliers among 100 measurements (13.00%) - 3 (3.00%) high mild - 10 (10.00%) high severe -extend_f32_f64/system time: [992.48 ns 993.27 ns 994.32 ns] -Found 15 outliers among 100 measurements (15.00%) - 3 (3.00%) high mild - 12 (12.00%) high severe -extend_f32_f64/assembly (aarch64 unix) - time: [457.65 ns 460.39 ns 463.78 ns] - -extend_f32_f128/compiler-builtins - time: [1.0295 µs 1.0311 µs 1.0327 µs] -Found 3 outliers among 100 measurements (3.00%) - 2 (2.00%) low mild - 1 (1.00%) high mild - -extend_f64_f128/compiler-builtins - time: [1.0400 µs 1.0412 µs 1.0426 µs] -Found 2 outliers among 100 measurements (2.00%) - 2 (2.00%) high mild - -mul_f32/compiler-builtins - time: [25.604 µs 25.705 µs 25.818 µs] -Found 23 outliers among 100 measurements (23.00%) - 17 (17.00%) low severe - 3 (3.00%) high mild - 3 (3.00%) high severe -mul_f32/system time: [29.914 µs 29.977 µs 30.043 µs] -Found 5 outliers among 100 measurements (5.00%) - 5 (5.00%) high mild -mul_f32/assembly (aarch64 unix) - time: [8.1384 µs 8.1964 µs 8.2603 µs] -Found 13 outliers among 100 measurements (13.00%) - 3 (3.00%) high mild - 10 (10.00%) high severe - -mul_f64/compiler-builtins - time: [25.596 µs 25.615 µs 25.637 µs] -Found 3 outliers among 100 measurements (3.00%) - 2 (2.00%) high mild - 1 (1.00%) high severe -mul_f64/system time: [30.931 µs 30.963 µs 31.002 µs] -Found 3 outliers among 100 measurements (3.00%) - 3 (3.00%) high mild -mul_f64/assembly (aarch64 unix) - time: [8.0589 µs 8.0638 µs 8.0695 µs] -Found 3 outliers among 100 measurements (3.00%) - 1 (1.00%) high mild - 2 (2.00%) high severe - -mul_f128/compiler-builtins - time: [54.242 µs 54.306 µs 54.374 µs] -Found 3 outliers among 100 measurements (3.00%) - 2 (2.00%) high mild - 1 (1.00%) high severe - -powi_f32/compiler-builtins - time: [129.91 µs 130.09 µs 130.24 µs] -powi_f32/system time: [126.97 µs 127.34 µs 127.82 µs] -Found 4 outliers among 100 measurements (4.00%) - 3 (3.00%) high mild - 1 (1.00%) high severe - -powi_f64/compiler-builtins - time: [130.08 µs 130.81 µs 131.46 µs] -Found 13 outliers among 100 measurements (13.00%) - 13 (13.00%) high mild -powi_f64/system time: [128.51 µs 128.68 µs 128.88 µs] -Found 21 outliers among 100 measurements (21.00%) - 4 (4.00%) high mild - 17 (17.00%) high severe - -sub_f32/compiler-builtins - time: [37.861 µs 38.012 µs 38.158 µs] -Found 26 outliers among 100 measurements (26.00%) - 18 (18.00%) low mild - 7 (7.00%) high mild - 1 (1.00%) high severe -sub_f32/system time: [39.586 µs 39.628 µs 39.673 µs] -Found 2 outliers among 100 measurements (2.00%) - 1 (1.00%) high mild - 1 (1.00%) high severe -sub_f32/assembly (aarch64 unix) - time: [8.0976 µs 8.1584 µs 8.2208 µs] -Found 6 outliers among 100 measurements (6.00%) - 6 (6.00%) high mild - -sub_f64/compiler-builtins - time: [37.755 µs 37.838 µs 37.921 µs] -Found 25 outliers among 100 measurements (25.00%) - 7 (7.00%) low severe - 3 (3.00%) low mild - 4 (4.00%) high mild - 11 (11.00%) high severe -sub_f64/system time: [39.979 µs 40.019 µs 40.064 µs] -Found 3 outliers among 100 measurements (3.00%) - 2 (2.00%) high mild - 1 (1.00%) high severe -sub_f64/assembly (aarch64 unix) - time: [8.0669 µs 8.0733 µs 8.0801 µs] -Found 7 outliers among 100 measurements (7.00%) - 3 (3.00%) high mild - 4 (4.00%) high severe - -sub_f128/compiler-builtins - time: [68.618 µs 68.899 µs 69.293 µs] -Found 11 outliers among 100 measurements (11.00%) - 2 (2.00%) high mild - 9 (9.00%) high severe - -trunc_f32_f16/compiler-builtins - time: [1.3343 µs 1.3468 µs 1.3608 µs] -Found 3 outliers among 100 measurements (3.00%) - 1 (1.00%) high mild - 2 (2.00%) high severe -trunc_f32_f16/system time: [1.2687 µs 1.2714 µs 1.2738 µs] -trunc_f32_f16/assembly (aarch64 unix) - time: [470.06 ns 472.96 ns 475.30 ns] - -trunc_f64_f16/compiler-builtins - time: [1.2729 µs 1.2738 µs 1.2749 µs] -Found 7 outliers among 100 measurements (7.00%) - 2 (2.00%) high mild - 5 (5.00%) high severe -trunc_f64_f16/assembly (aarch64 unix) - time: [455.91 ns 456.61 ns 457.33 ns] -Found 12 outliers among 100 measurements (12.00%) - 1 (1.00%) low severe - 2 (2.00%) low mild - 6 (6.00%) high mild - 3 (3.00%) high severe - -trunc_f64_f32/compiler-builtins - time: [1.2240 µs 1.2325 µs 1.2410 µs] -Found 17 outliers among 100 measurements (17.00%) - 4 (4.00%) low mild - 2 (2.00%) high mild - 11 (11.00%) high severe -trunc_f64_f32/system time: [1.2784 µs 1.2835 µs 1.2884 µs] -Found 10 outliers among 100 measurements (10.00%) - 6 (6.00%) low severe - 1 (1.00%) low mild - 2 (2.00%) high mild - 1 (1.00%) high severe -trunc_f64_f32/assembly (aarch64 unix) - time: [455.64 ns 456.08 ns 456.58 ns] -Found 18 outliers among 100 measurements (18.00%) - 3 (3.00%) low severe - 4 (4.00%) low mild - 8 (8.00%) high mild - 3 (3.00%) high severe - -trunc_f128_f16/compiler-builtins - time: [1.2563 µs 1.2666 µs 1.2776 µs] -Found 3 outliers among 100 measurements (3.00%) - 3 (3.00%) high mild - -trunc_f128_f32/compiler-builtins - time: [1.2459 µs 1.2482 µs 1.2507 µs] -Found 6 outliers among 100 measurements (6.00%) - 2 (2.00%) low mild - 2 (2.00%) high mild - 2 (2.00%) high severe - -trunc_f128_f64/compiler-builtins - time: [1.2821 µs 1.3047 µs 1.3452 µs] -Found 8 outliers among 100 measurements (8.00%) - 4 (4.00%) low severe - 1 (1.00%) low mild - 2 (2.00%) high mild - 1 (1.00%) high severe - - -running 52 tests -test memcmp_builtin_1048576 ... bench: 20,975.52 ns/iter (+/- 239.69) = 49991 MB/s -test memcmp_builtin_16 ... bench: 1.60 ns/iter (+/- 0.05) = 16000 MB/s -test memcmp_builtin_32 ... bench: 1.61 ns/iter (+/- 0.03) = 32000 MB/s -test memcmp_builtin_4096 ... bench: 95.84 ns/iter (+/- 2.82) = 43115 MB/s -test memcmp_builtin_64 ... bench: 2.39 ns/iter (+/- 0.09) = 32000 MB/s -test memcmp_builtin_8 ... bench: 1.60 ns/iter (+/- 0.04) = 8000 MB/s -test memcmp_builtin_unaligned_1048575 ... bench: 22,060.00 ns/iter (+/- 873.55) = 47532 MB/s -test memcmp_builtin_unaligned_15 ... bench: 3.19 ns/iter (+/- 0.02) = 5333 MB/s -test memcmp_builtin_unaligned_31 ... bench: 1.61 ns/iter (+/- 0.01) = 32000 MB/s -test memcmp_builtin_unaligned_4095 ... bench: 96.63 ns/iter (+/- 4.58) = 42666 MB/s -test memcmp_builtin_unaligned_63 ... bench: 2.40 ns/iter (+/- 0.11) = 32000 MB/s -test memcmp_builtin_unaligned_7 ... bench: 3.37 ns/iter (+/- 0.05) = 2666 MB/s -test memcmp_rust_1048576 ... bench: 309,647.23 ns/iter (+/- 6,077.35) = 3386 MB/s -test memcmp_rust_16 ... bench: 5.66 ns/iter (+/- 0.30) = 3200 MB/s -test memcmp_rust_32 ... bench: 10.47 ns/iter (+/- 0.14) = 3200 MB/s -test memcmp_rust_4096 ... bench: 1,124.34 ns/iter (+/- 36.92) = 3644 MB/s -test memcmp_rust_64 ... bench: 19.90 ns/iter (+/- 0.36) = 3368 MB/s -test memcmp_rust_8 ... bench: 3.46 ns/iter (+/- 0.11) = 2666 MB/s -test memcmp_rust_unaligned_1048575 ... bench: 308,613.87 ns/iter (+/- 6,613.18) = 3397 MB/s -test memcmp_rust_unaligned_15 ... bench: 5.35 ns/iter (+/- 0.05) = 3200 MB/s -test memcmp_rust_unaligned_31 ... bench: 9.94 ns/iter (+/- 0.06) = 3555 MB/s -test memcmp_rust_unaligned_4095 ... bench: 1,120.06 ns/iter (+/- 5.03) = 3657 MB/s -test memcmp_rust_unaligned_63 ... bench: 19.64 ns/iter (+/- 0.82) = 3368 MB/s -test memcmp_rust_unaligned_7 ... bench: 3.22 ns/iter (+/- 0.10) = 2666 MB/s -test memcpy_builtin_1048576 ... bench: 12,538.05 ns/iter (+/- 354.79) = 83631 MB/s -test memcpy_builtin_1048576_misalign ... bench: 30,092.56 ns/iter (+/- 8,064.04) = 34845 MB/s -test memcpy_builtin_1048576_offset ... bench: 12,538.36 ns/iter (+/- 359.04) = 83631 MB/s -test memcpy_builtin_4096 ... bench: 44.24 ns/iter (+/- 6.80) = 93090 MB/s -test memcpy_builtin_4096_misalign ... bench: 45.34 ns/iter (+/- 2.13) = 91022 MB/s -test memcpy_builtin_4096_offset ... bench: 44.71 ns/iter (+/- 0.61) = 93090 MB/s -test memcpy_rust_1048576 ... bench: 17,943.33 ns/iter (+/- 243.18) = 58439 MB/s -test memcpy_rust_1048576_misalign ... bench: 15,004.68 ns/iter (+/- 3,978.65) = 69886 MB/s -test memcpy_rust_1048576_offset ... bench: 14,722.06 ns/iter (+/- 479.54) = 71225 MB/s -test memcpy_rust_4096 ... bench: 44.91 ns/iter (+/- 4.62) = 93090 MB/s -test memcpy_rust_4096_misalign ... bench: 76.21 ns/iter (+/- 8.21) = 53894 MB/s -test memcpy_rust_4096_offset ... bench: 76.27 ns/iter (+/- 4.69) = 53894 MB/s -test memmove_builtin_1048576 ... bench: 18,644.50 ns/iter (+/- 379.84) = 56242 MB/s -test memmove_builtin_1048576_misalign ... bench: 18,947.70 ns/iter (+/- 1,226.26) = 55342 MB/s -test memmove_builtin_4096 ... bench: 44.21 ns/iter (+/- 0.79) = 93090 MB/s -test memmove_builtin_4096_misalign ... bench: 47.21 ns/iter (+/- 3.12) = 87148 MB/s -test memmove_rust_1048576 ... bench: 34,813.33 ns/iter (+/- 3,637.47) = 30120 MB/s -test memmove_rust_1048576_misalign ... bench: 35,067.19 ns/iter (+/- 1,699.63) = 29902 MB/s -test memmove_rust_4096 ... bench: 148.69 ns/iter (+/- 1.31) = 27675 MB/s -test memmove_rust_4096_misalign ... bench: 153.81 ns/iter (+/- 1.71) = 26771 MB/s -test memset_builtin_1048576 ... bench: 15,704.12 ns/iter (+/- 12,113.86) = 66771 MB/s -test memset_builtin_1048576_offset ... bench: 17,894.23 ns/iter (+/- 175.12) = 58599 MB/s -test memset_builtin_4096 ... bench: 39.95 ns/iter (+/- 0.19) = 105025 MB/s -test memset_builtin_4096_offset ... bench: 40.48 ns/iter (+/- 3.11) = 102400 MB/s -test memset_rust_1048576 ... bench: 10,600.66 ns/iter (+/- 1,559.93) = 98922 MB/s -test memset_rust_1048576_offset ... bench: 14,810.85 ns/iter (+/- 575.27) = 70801 MB/s -test memset_rust_4096 ... bench: 37.91 ns/iter (+/- 2.77) = 110702 MB/s -test memset_rust_4096_offset ... bench: 59.99 ns/iter (+/- 10.45) = 69423 MB/s - -test result: ok. 0 passed; 0 failed; 0 ignored; 52 measured; 0 filtered out; finished in 97.74s - From 98195c0348ebd5fdc90e45de3fd4d30a337ad2c8 Mon Sep 17 00:00:00 2001 From: Andrey Turkin Date: Tue, 25 Jun 2024 13:52:02 +0300 Subject: [PATCH 1264/4206] Get rid of a warning --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/build.rs | 2 -- library/compiler-builtins/crates/panic-handler/Cargo.toml | 1 + 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index ab43951593b31..c8d78ec3e264a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -7,7 +7,7 @@ readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" homepage = "https://github.com/rust-lang/compiler-builtins" documentation = "https://docs.rs/compiler_builtins" -edition = "2018" +edition = "2021" description = """ Compiler intrinsics used by the Rust compiler. Also available for other targets if necessary! diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 0ecd399118e80..d7e3be5940371 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -219,8 +219,6 @@ fn configure_check_cfg() { #[cfg(feature = "c")] mod c { - extern crate cc; - use std::collections::{BTreeMap, HashSet}; use std::env; use std::fs::{self, File}; diff --git a/library/compiler-builtins/crates/panic-handler/Cargo.toml b/library/compiler-builtins/crates/panic-handler/Cargo.toml index 1dea613d192f7..4fb81eb82a411 100644 --- a/library/compiler-builtins/crates/panic-handler/Cargo.toml +++ b/library/compiler-builtins/crates/panic-handler/Cargo.toml @@ -2,5 +2,6 @@ name = "panic-handler" version = "0.1.0" authors = ["Alex Crichton "] +edition = "2021" [dependencies] From 45465cc488c02030575ef939b026d2e11530845b Mon Sep 17 00:00:00 2001 From: Andrey Turkin Date: Sat, 22 Jun 2024 00:01:52 +0300 Subject: [PATCH 1265/4206] Implement __bswap[sdt]i2 intrinsics These can be emitted by gcc, at least if requested specifically via __builtin_bswap{32,64,128}. --- library/compiler-builtins/README.md | 3 ++ library/compiler-builtins/build.rs | 3 ++ library/compiler-builtins/src/int/bswap.rs | 22 ++++++++++++ library/compiler-builtins/src/int/mod.rs | 1 + .../compiler-builtins/testcrate/tests/misc.rs | 34 +++++++++++++++++++ 5 files changed, 63 insertions(+) create mode 100644 library/compiler-builtins/src/int/bswap.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 9a847da3f69ad..a24c127392d7e 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -154,6 +154,9 @@ rely on CI. - [ ] arm/unordsf2vfp.S - [x] ashldi3.c - [x] ashrdi3.c +- [x] bswapdi2.c +- [x] bswapsi2.c +- [x] bswapti2.c - [x] comparedf2.c - [x] comparesf2.c - [x] divdf3.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index d7e3be5940371..34467d8f54bcd 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -161,6 +161,9 @@ fn configure_check_cfg() { "__ashlsi3", "__ashrdi3", "__ashrsi3", + "__bswapsi2", + "__bswapdi2", + "__bswapti2", "__clzsi2", "__divdi3", "__divsi3", diff --git a/library/compiler-builtins/src/int/bswap.rs b/library/compiler-builtins/src/int/bswap.rs new file mode 100644 index 0000000000000..9df80204d0e6b --- /dev/null +++ b/library/compiler-builtins/src/int/bswap.rs @@ -0,0 +1,22 @@ +intrinsics! { + #[maybe_use_optimized_c_shim] + #[avr_skip] + /// Swaps bytes in 32-bit number + pub extern "C" fn __bswapsi2(x: u32) -> u32 { + x.swap_bytes() + } + + #[maybe_use_optimized_c_shim] + #[avr_skip] + /// Swaps bytes in 64-bit number + pub extern "C" fn __bswapdi2(x: u64) -> u64 { + x.swap_bytes() + } + + #[maybe_use_optimized_c_shim] + #[avr_skip] + /// Swaps bytes in 128-bit number + pub extern "C" fn __bswapti2(x: u128) -> u128 { + x.swap_bytes() + } +} diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 45d3838803108..ddbffd7404401 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -4,6 +4,7 @@ mod specialized_div_rem; pub mod addsub; mod big; +pub mod bswap; pub mod leading_zeros; pub mod mul; pub mod sdiv; diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index e01223c74848b..c19923b75c293 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -92,6 +92,40 @@ fn leading_zeros() { }) } +#[test] +#[cfg(not(target_arch = "avr"))] +fn bswap() { + use compiler_builtins::int::bswap::{__bswapdi2, __bswapsi2}; + fuzz(N, |x: u32| { + assert_eq!(x.swap_bytes(), __bswapsi2(x)); + }); + fuzz(N, |x: u64| { + assert_eq!(x.swap_bytes(), __bswapdi2(x)); + }); + + assert_eq!(__bswapsi2(0x12345678u32), 0x78563412u32); + assert_eq!(__bswapsi2(0x00000001u32), 0x01000000u32); + assert_eq!(__bswapdi2(0x123456789ABCDEF0u64), 0xF0DEBC9A78563412u64); + assert_eq!(__bswapdi2(0x0200000001000000u64), 0x0000000100000002u64); + + #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] + { + use compiler_builtins::int::bswap::__bswapti2; + fuzz(N, |x: u128| { + assert_eq!(x.swap_bytes(), __bswapti2(x)); + }); + + assert_eq!( + __bswapti2(0x123456789ABCDEF013579BDF02468ACEu128), + 0xCE8A4602DF9B5713F0DEBC9A78563412u128 + ); + assert_eq!( + __bswapti2(0x04000000030000000200000001000000u128), + 0x00000001000000020000000300000004u128 + ); + } +} + // This is approximate because of issues related to // https://github.com/rust-lang/rust/issues/73920. // TODO how do we resolve this indeterminacy? From ddd97dc19a62a3be9495aecc5cd93c94d89237fe Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 18 Jul 2024 03:25:03 -0500 Subject: [PATCH 1266/4206] Fix missing `extern "C"` for unsafe functions `unsafe` functions were being matched in a different block that did not include `extern $abi`. This means that some intrinsics were getting generated with the Rust ABI rather than C. Combine the last two blocks using an optional token matcher, which fixes this problem and is cleaner. --- library/compiler-builtins/src/macros.rs | 33 +++---------------------- 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index f537c1a968f0a..fb14660af9878 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -449,41 +449,14 @@ macro_rules! intrinsics { // input we were given. ( $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { - $($body:tt)* - } - - $($rest:tt)* - ) => ( - $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - - #[cfg(not(feature = "mangled-names"))] - mod $name { - $(#[$($attr)*])* - #[no_mangle] - #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] - extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - super::$name($($argname),*) - } - } - - intrinsics!($($rest)*); - ); - - // Same as the above for unsafe functions. - ( - $(#[$($attr:tt)*])* - pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + pub $(unsafe $(@ $empty:tt)?)? extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { $($body:tt)* } $($rest:tt)* ) => ( $(#[$($attr)*])* - pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + pub $(unsafe $($empty)?)? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } @@ -492,7 +465,7 @@ macro_rules! intrinsics { $(#[$($attr)*])* #[no_mangle] #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] - unsafe fn $name( $($argname: $ty),* ) $(-> $ret)? { + $(unsafe $($empty)?)? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } } From a5c7a17d5598fd3aaf4757b05aad9e9560832456 Mon Sep 17 00:00:00 2001 From: Andrey Turkin Date: Sat, 22 Jun 2024 00:01:52 +0300 Subject: [PATCH 1267/4206] Implement remaining __clz*i2 intrinsics --- library/compiler-builtins/README.md | 6 +- library/compiler-builtins/build.rs | 2 +- .../src/int/leading_zeros.rs | 92 +++++++++++-------- library/compiler-builtins/src/int/mod.rs | 1 - .../compiler-builtins/testcrate/tests/misc.rs | 89 +++++++++++++----- 5 files changed, 123 insertions(+), 67 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index a24c127392d7e..6ff0de1909fb0 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -157,6 +157,9 @@ rely on CI. - [x] bswapdi2.c - [x] bswapsi2.c - [x] bswapti2.c +- [x] clzdi2.c +- [x] clzsi2.c +- [x] clzti2.c - [x] comparedf2.c - [x] comparesf2.c - [x] divdf3.c @@ -325,9 +328,6 @@ These builtins are never called by LLVM. - ~~arm/switch32.S~~ - ~~arm/switch8.S~~ - ~~arm/switchu8.S~~ -- ~~clzdi2.c~~ -- ~~clzsi2.c~~ -- ~~clzti2.c~~ - ~~cmpdi2.c~~ - ~~cmpti2.c~~ - ~~ctzdi2.c~~ diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 34467d8f54bcd..79f994456aa3d 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -165,6 +165,7 @@ fn configure_check_cfg() { "__bswapdi2", "__bswapti2", "__clzsi2", + "__clzdi2", "__divdi3", "__divsi3", "__divmoddi4", @@ -382,7 +383,6 @@ mod c { sources.extend(&[ ("__absvti2", "absvti2.c"), ("__addvti3", "addvti3.c"), - ("__clzti2", "clzti2.c"), ("__cmpti2", "cmpti2.c"), ("__ctzti2", "ctzti2.c"), ("__ffsti2", "ffsti2.c"), diff --git a/library/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/src/int/leading_zeros.rs index 9e60ab0d74461..68ac55ac70c92 100644 --- a/library/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/src/int/leading_zeros.rs @@ -3,10 +3,12 @@ // adding a zero check at the beginning, but `__clzsi2` has a precondition that `x != 0`. // Compilers will insert the check for zero in cases where it is needed. +use crate::int::{CastInto, Int}; + public_test_dep! { /// Returns the number of leading binary zeros in `x`. #[allow(dead_code)] -pub(crate) fn usize_leading_zeros_default(x: usize) -> usize { +pub(crate) fn leading_zeros_default>(x: T) -> usize { // The basic idea is to test if the higher bits of `x` are zero and bisect the number // of leading zeros. It is possible for all branches of the bisection to use the same // code path by conditionally shifting the higher parts down to let the next bisection @@ -16,46 +18,47 @@ pub(crate) fn usize_leading_zeros_default(x: usize) -> usize { // because it simplifies the final bisection step. let mut x = x; // the number of potential leading zeros - let mut z = usize::MAX.count_ones() as usize; + let mut z = T::BITS as usize; // a temporary - let mut t: usize; - #[cfg(target_pointer_width = "64")] - { + let mut t: T; + + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { t = x >> 32; - if t != 0 { + if t != T::ZERO { z -= 32; x = t; } } - #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] - { + if T::BITS >= 32 { t = x >> 16; - if t != 0 { + if t != T::ZERO { z -= 16; x = t; } } + const { assert!(T::BITS >= 16) }; t = x >> 8; - if t != 0 { + if t != T::ZERO { z -= 8; x = t; } t = x >> 4; - if t != 0 { + if t != T::ZERO { z -= 4; x = t; } t = x >> 2; - if t != 0 { + if t != T::ZERO { z -= 2; x = t; } // the last two bisections are combined into one conditional t = x >> 1; - if t != 0 { + if t != T::ZERO { z - 2 } else { - z - x + z - x.cast() } // We could potentially save a few cycles by using the LUT trick from @@ -80,12 +83,12 @@ pub(crate) fn usize_leading_zeros_default(x: usize) -> usize { public_test_dep! { /// Returns the number of leading binary zeros in `x`. #[allow(dead_code)] -pub(crate) fn usize_leading_zeros_riscv(x: usize) -> usize { +pub(crate) fn leading_zeros_riscv>(x: T) -> usize { let mut x = x; // the number of potential leading zeros - let mut z = usize::MAX.count_ones() as usize; + let mut z = T::BITS; // a temporary - let mut t: usize; + let mut t: u32; // RISC-V does not have a set-if-greater-than-or-equal instruction and // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is @@ -95,11 +98,11 @@ pub(crate) fn usize_leading_zeros_riscv(x: usize) -> usize { // right). If we try to save an instruction by using `x < imm` for each bisection, we // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, // but the immediate will never fit into 12 bits and never save an instruction. - #[cfg(target_pointer_width = "64")] - { + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise // `t` is set to 0. - t = ((x >= (1 << 32)) as usize) << 5; + t = ((x >= (T::ONE << 32)) as u32) << 5; // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the // next step to process. x >>= t; @@ -107,43 +110,58 @@ pub(crate) fn usize_leading_zeros_riscv(x: usize) -> usize { // leading zeros z -= t; } - #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] - { - t = ((x >= (1 << 16)) as usize) << 4; + if T::BITS >= 32 { + t = ((x >= (T::ONE << 16)) as u32) << 4; x >>= t; z -= t; } - t = ((x >= (1 << 8)) as usize) << 3; + const { assert!(T::BITS >= 16) }; + t = ((x >= (T::ONE << 8)) as u32) << 3; x >>= t; z -= t; - t = ((x >= (1 << 4)) as usize) << 2; + t = ((x >= (T::ONE << 4)) as u32) << 2; x >>= t; z -= t; - t = ((x >= (1 << 2)) as usize) << 1; + t = ((x >= (T::ONE << 2)) as u32) << 1; x >>= t; z -= t; - t = (x >= (1 << 1)) as usize; + t = (x >= (T::ONE << 1)) as u32; x >>= t; z -= t; // All bits except the LSB are guaranteed to be zero for this final bisection step. // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. - z - x + z as usize - x.cast() } } intrinsics! { #[maybe_use_optimized_c_shim] - #[cfg(any( - target_pointer_width = "16", - target_pointer_width = "32", - target_pointer_width = "64" - ))] - /// Returns the number of leading binary zeros in `x`. - pub extern "C" fn __clzsi2(x: usize) -> usize { + /// Returns the number of leading binary zeros in `x` + pub extern "C" fn __clzsi2(x: u32) -> usize { + if cfg!(any(target_arch = "riscv32", target_arch = "riscv64")) { + leading_zeros_riscv(x) + } else { + leading_zeros_default(x) + } + } + + #[maybe_use_optimized_c_shim] + /// Returns the number of leading binary zeros in `x` + pub extern "C" fn __clzdi2(x: u64) -> usize { if cfg!(any(target_arch = "riscv32", target_arch = "riscv64")) { - usize_leading_zeros_riscv(x) + leading_zeros_riscv(x) + } else { + leading_zeros_default(x) + } + } + + /// Returns the number of leading binary zeros in `x` + pub extern "C" fn __clzti2(x: u128) -> usize { + let hi = (x >> 64) as u64; + if hi == 0 { + 64 + __clzdi2(x as u64) } else { - usize_leading_zeros_default(x) + __clzdi2(hi) } } } diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index ddbffd7404401..728ce1d571880 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -12,7 +12,6 @@ pub mod shift; pub mod udiv; pub use big::{i256, u256}; -pub use leading_zeros::__clzsi2; public_test_dep! { /// Minimal integer implementations needed on all integer types, including wide integers. diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index c19923b75c293..f830a54230e8e 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -65,31 +65,70 @@ fn fuzz_values() { #[test] fn leading_zeros() { - use compiler_builtins::int::__clzsi2; - use compiler_builtins::int::leading_zeros::{ - usize_leading_zeros_default, usize_leading_zeros_riscv, - }; - fuzz(N, |x: usize| { - let lz = x.leading_zeros() as usize; - let lz0 = __clzsi2(x); - let lz1 = usize_leading_zeros_default(x); - let lz2 = usize_leading_zeros_riscv(x); - if lz0 != lz { - panic!("__clzsi2({}): std: {}, builtins: {}", x, lz, lz0); - } - if lz1 != lz { - panic!( - "usize_leading_zeros_default({}): std: {}, builtins: {}", - x, lz, lz1 - ); - } - if lz2 != lz { - panic!( - "usize_leading_zeros_riscv({}): std: {}, builtins: {}", - x, lz, lz2 - ); - } - }) + use compiler_builtins::int::leading_zeros::{leading_zeros_default, leading_zeros_riscv}; + { + use compiler_builtins::int::leading_zeros::__clzsi2; + fuzz(N, |x: u32| { + if x == 0 { + return; // undefined value for an intrinsic + } + let lz = x.leading_zeros() as usize; + let lz0 = __clzsi2(x); + let lz1 = leading_zeros_default(x); + let lz2 = leading_zeros_riscv(x); + if lz0 != lz { + panic!("__clzsi2({}): std: {}, builtins: {}", x, lz, lz0); + } + if lz1 != lz { + panic!( + "leading_zeros_default({}): std: {}, builtins: {}", + x, lz, lz1 + ); + } + if lz2 != lz { + panic!("leading_zeros_riscv({}): std: {}, builtins: {}", x, lz, lz2); + } + }); + } + + { + use compiler_builtins::int::leading_zeros::__clzdi2; + fuzz(N, |x: u64| { + if x == 0 { + return; // undefined value for an intrinsic + } + let lz = x.leading_zeros() as usize; + let lz0 = __clzdi2(x); + let lz1 = leading_zeros_default(x); + let lz2 = leading_zeros_riscv(x); + if lz0 != lz { + panic!("__clzdi2({}): std: {}, builtins: {}", x, lz, lz0); + } + if lz1 != lz { + panic!( + "leading_zeros_default({}): std: {}, builtins: {}", + x, lz, lz1 + ); + } + if lz2 != lz { + panic!("leading_zeros_riscv({}): std: {}, builtins: {}", x, lz, lz2); + } + }); + } + + { + use compiler_builtins::int::leading_zeros::__clzti2; + fuzz(N, |x: u128| { + if x == 0 { + return; // undefined value for an intrinsic + } + let lz = x.leading_zeros() as usize; + let lz0 = __clzti2(x); + if lz0 != lz { + panic!("__clzti2({}): std: {}, builtins: {}", x, lz, lz0); + } + }); + } } #[test] From cc64c7978eb663cf0f6a5965dd136ef580004af4 Mon Sep 17 00:00:00 2001 From: Andrey Turkin Date: Tue, 16 Jul 2024 14:03:43 +0300 Subject: [PATCH 1268/4206] Never use C version of clz builtins --- library/compiler-builtins/build.rs | 9 --------- library/compiler-builtins/src/int/leading_zeros.rs | 2 -- 2 files changed, 11 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 79f994456aa3d..b8da7cc56c14e 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -164,8 +164,6 @@ fn configure_check_cfg() { "__bswapsi2", "__bswapdi2", "__bswapti2", - "__clzsi2", - "__clzdi2", "__divdi3", "__divsi3", "__divmoddi4", @@ -346,8 +344,6 @@ mod c { ("__absvsi2", "absvsi2.c"), ("__addvdi3", "addvdi3.c"), ("__addvsi3", "addvsi3.c"), - ("__clzdi2", "clzdi2.c"), - ("__clzsi2", "clzsi2.c"), ("__cmpdi2", "cmpdi2.c"), ("__ctzdi2", "ctzdi2.c"), ("__ctzsi2", "ctzsi2.c"), @@ -435,8 +431,6 @@ mod c { ("__aeabi_frsub", "arm/aeabi_frsub.c"), ("__bswapdi2", "arm/bswapdi2.S"), ("__bswapsi2", "arm/bswapsi2.S"), - ("__clzdi2", "arm/clzdi2.S"), - ("__clzsi2", "arm/clzsi2.S"), ("__divmodsi4", "arm/divmodsi4.S"), ("__divsi3", "arm/divsi3.S"), ("__modsi3", "arm/modsi3.S"), @@ -572,9 +566,6 @@ mod c { } } sources.remove(&to_remove); - - // But use some generic implementations where possible - sources.extend(&[("__clzdi2", "clzdi2.c"), ("__clzsi2", "clzsi2.c")]) } if llvm_target[0] == "thumbv7m" || llvm_target[0] == "thumbv7em" { diff --git a/library/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/src/int/leading_zeros.rs index 68ac55ac70c92..1fee9fcf5d8fd 100644 --- a/library/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/src/int/leading_zeros.rs @@ -135,7 +135,6 @@ pub(crate) fn leading_zeros_riscv>(x: T) -> usize { } intrinsics! { - #[maybe_use_optimized_c_shim] /// Returns the number of leading binary zeros in `x` pub extern "C" fn __clzsi2(x: u32) -> usize { if cfg!(any(target_arch = "riscv32", target_arch = "riscv64")) { @@ -145,7 +144,6 @@ intrinsics! { } } - #[maybe_use_optimized_c_shim] /// Returns the number of leading binary zeros in `x` pub extern "C" fn __clzdi2(x: u64) -> usize { if cfg!(any(target_arch = "riscv32", target_arch = "riscv64")) { From a96c82123e7b1ae1936340406efa7d79adb134b8 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 25 Jun 2024 02:34:17 -0400 Subject: [PATCH 1269/4206] Remove a broken link in README --- library/compiler-builtins/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 6ff0de1909fb0..b5f061706286f 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -57,7 +57,7 @@ features = ["c"] 5. Add the intrinsic to `examples/intrinsics.rs` to verify it can be linked on all targets. 6. Send a Pull Request (PR). -7. Once the PR passes our extensive [testing infrastructure][4], we'll merge it! +7. Once the PR passes our extensive testing infrastructure, we'll merge it! 8. Celebrate :tada: [1]: https://github.com/rust-lang/llvm-project/tree/9e3de9490ff580cd484fbfa2908292b4838d56e7/compiler-rt/test/builtins/Unit From fb27c7283c666442adb8ea6f973928cf5cde0d62 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 25 Jun 2024 02:51:45 -0400 Subject: [PATCH 1270/4206] Move IBM extended double to the unneeded section --- library/compiler-builtins/README.md | 41 ++++++++++++++++++----------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index b5f061706286f..b33a7d6f7f4e9 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -257,10 +257,6 @@ These builtins are needed to support `f16` and `f128`, which are in the process - [ ] floatunsitf.c - [x] multf3.c - [ ] powitf2.c -- [ ] ppc/fixtfdi.c -- [ ] ppc/fixunstfdi.c -- [ ] ppc/floatditf.c -- [ ] ppc/floatunditf.c - [x] subtf3.c - [x] truncdfhf2.c - [x] truncsfhf2.c @@ -270,12 +266,9 @@ These builtins are needed to support `f16` and `f128`, which are in the process ## Unimplemented functions -These builtins involve floating-point types ("`f80`" and complex numbers) that are not supported by Rust. +These builtins are for x87 `f80` floating-point numbers that are not supported +by Rust. -- ~~divdc3.c~~ -- ~~divsc3.c~~ -- ~~divtc3.c~~ -- ~~divxc3.c~~ - ~~fixunsxfdi.c~~ - ~~fixunsxfsi.c~~ - ~~fixunsxfti.c~~ @@ -287,19 +280,35 @@ These builtins involve floating-point types ("`f80`" and complex numbers) that a - ~~floatuntixf.c~~ - ~~i386/floatdixf.S~~ - ~~i386/floatundixf.S~~ -- ~~muldc3.c~~ -- ~~mulsc3.c~~ -- ~~multc3.c~~ -- ~~mulxc3.c~~ -- ~~powixf2.c~~ +- ~~x86_64/floatdixf.c~~ +- ~~x86_64/floatundixf.S~~ + +These builtins are for IBM "extended double" non-IEEE 128-bit floating-point +numbers. + - ~~ppc/divtc3.c~~ +- ~~ppc/fixtfdi.c~~ +- ~~ppc/fixunstfdi.c~~ +- ~~ppc/floatditf.c~~ +- ~~ppc/floatunditf.c~~ - ~~ppc/gcc_qadd.c~~ - ~~ppc/gcc_qdiv.c~~ - ~~ppc/gcc_qmul.c~~ - ~~ppc/gcc_qsub.c~~ - ~~ppc/multc3.c~~ -- ~~x86_64/floatdixf.c~~ -- ~~x86_64/floatundixf.S~~ + +These builtins involve complex floating-point types that are not supported by +Rust. + +- ~~divdc3.c~~ +- ~~divsc3.c~~ +- ~~divtc3.c~~ +- ~~divxc3.c~~ +- ~~muldc3.c~~ +- ~~mulsc3.c~~ +- ~~multc3.c~~ +- ~~mulxc3.c~~ +- ~~powixf2.c~~ These builtins are never called by LLVM. From 6ef2b95d46f233d3d53aad297867b7ab213d95af Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 25 Jun 2024 03:56:21 -0400 Subject: [PATCH 1271/4206] Add missing symbols from compiler-rt to the README --- library/compiler-builtins/README.md | 86 +++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index b33a7d6f7f4e9..2d7aa337841bb 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -16,13 +16,13 @@ you can use this crate to get those intrinsics and solve the linker errors. To do that, add this crate somewhere in the dependency graph of the crate you are building: -``` toml +```toml # Cargo.toml [dependencies] compiler_builtins = { git = "https://github.com/rust-lang/compiler-builtins" } ``` -``` rust +```rust extern crate compiler_builtins; // ... @@ -91,7 +91,7 @@ obtained with the following: ```sh curl -L -o rustc-llvm-18.0.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/18.0-2024-02-13.tar.gz tar xzf rustc-llvm-18.0.tar.gz --strip-components 1 llvm-project-rustc-18.0-2024-02-13/compiler-rt -```` +``` Local targets may also be tested with `./ci/run.sh [target]`. @@ -100,9 +100,11 @@ rely on CI. ## Progress +- [x] aarch64/chkstk.S - [x] adddf3.c - [x] addsf3.c - [x] arm/adddf3vfp.S +- [x] arm/addsf3.S - [x] arm/addsf3vfp.S - [x] arm/aeabi_dcmp.S - [x] arm/aeabi_fcmp.S @@ -113,6 +115,7 @@ rely on CI. - [x] arm/aeabi_memset.S - [x] arm/aeabi_uidivmod.S - [x] arm/aeabi_uldivmod.S +- [ ] arm/chkstk.S - [x] arm/divdf3vfp.S - [ ] arm/divmodsi4.S (generic version is done) - [x] arm/divsf3vfp.S @@ -154,6 +157,12 @@ rely on CI. - [ ] arm/unordsf2vfp.S - [x] ashldi3.c - [x] ashrdi3.c +- [ ] avr/divmodhi4.S +- [ ] avr/divmodqi4.S +- [ ] avr/mulhi3.S +- [ ] avr/mulqi3.S +- [ ] avr/udivmodhi4.S +- [ ] avr/udivmodqi4.S - [x] bswapdi2.c - [x] bswapsi2.c - [x] bswapti2.c @@ -166,6 +175,7 @@ rely on CI. - [x] divdi3.c - [x] divmoddi4.c - [x] divmodsi4.c +- [x] divmodti4.c - [x] divsf3.c - [x] divsi3.c - [x] extendsfdf2.c @@ -204,6 +214,8 @@ rely on CI. - [x] mulsf3.c - [x] powidf2.c - [x] powisf2.c +- [ ] riscv/muldi3.S +- [ ] riscv/mulsi3.S - [x] subdf3.c - [x] subsf3.c - [x] truncdfsf2.c @@ -236,7 +248,8 @@ These builtins are needed to support 128-bit integers. - [x] udivti3.c - [x] umodti3.c -These builtins are needed to support `f16` and `f128`, which are in the process of being added to Rust. +These builtins are needed to support `f16` and `f128`, which are in the process +of being added to Rust. - [x] addtf3.c - [x] comparetf2.c @@ -253,8 +266,10 @@ These builtins are needed to support `f16` and `f128`, which are in the process - [x] fixunstfti.c - [ ] floatditf.c - [ ] floatsitf.c +- [ ] floattitf.c - [ ] floatunditf.c - [ ] floatunsitf.c +- [ ] floatuntitf.c - [x] multf3.c - [ ] powitf2.c - [x] subtf3.c @@ -264,11 +279,42 @@ These builtins are needed to support `f16` and `f128`, which are in the process - [x] trunctfhf2.c - [x] trunctfsf2.c + +These builtins are used by the Hexagon DSP + +- [ ] hexagon/common_entry_exit_abi1.S +- [ ] hexagon/common_entry_exit_abi2.S +- [ ] hexagon/common_entry_exit_legacy.S +- [x] hexagon/dfaddsub.S~~ +- [x] hexagon/dfdiv.S~~ +- [x] hexagon/dffma.S~~ +- [x] hexagon/dfminmax.S~~ +- [x] hexagon/dfmul.S~~ +- [x] hexagon/dfsqrt.S~~ +- [x] hexagon/divdi3.S~~ +- [x] hexagon/divsi3.S~~ +- [x] hexagon/fastmath2_dlib_asm.S~~ +- [x] hexagon/fastmath2_ldlib_asm.S~~ +- [x] hexagon/fastmath_dlib_asm.S~~ +- [x] hexagon/memcpy_forward_vp4cp4n2.S~~ +- [x] hexagon/memcpy_likely_aligned.S~~ +- [x] hexagon/moddi3.S~~ +- [x] hexagon/modsi3.S~~ +- [x] hexagon/sfdiv_opt.S~~ +- [x] hexagon/sfsqrt_opt.S~~ +- [x] hexagon/udivdi3.S~~ +- [x] hexagon/udivmoddi4.S~~ +- [x] hexagon/udivmodsi4.S~~ +- [x] hexagon/udivsi3.S~~ +- [x] hexagon/umoddi3.S~~ +- [x] hexagon/umodsi3.S~~ + ## Unimplemented functions These builtins are for x87 `f80` floating-point numbers that are not supported by Rust. +- ~~extendxftf2.c~~ - ~~fixunsxfdi.c~~ - ~~fixunsxfsi.c~~ - ~~fixunsxfti.c~~ @@ -288,8 +334,11 @@ numbers. - ~~ppc/divtc3.c~~ - ~~ppc/fixtfdi.c~~ +- ~~ppc/fixtfti.c~~ - ~~ppc/fixunstfdi.c~~ +- ~~ppc/fixunstfti.c~~ - ~~ppc/floatditf.c~~ +- ~~ppc/floattitf.c~~ - ~~ppc/floatunditf.c~~ - ~~ppc/gcc_qadd.c~~ - ~~ppc/gcc_qdiv.c~~ @@ -297,6 +346,13 @@ numbers. - ~~ppc/gcc_qsub.c~~ - ~~ppc/multc3.c~~ +These builtins are for 16-bit brain floating-point numbers that are not +supported by Rust. + +- ~~truncdfbf2.c~~ +- ~~truncsfbf2.c~~ +- ~~trunctfxf2.c~~ + These builtins involve complex floating-point types that are not supported by Rust. @@ -342,6 +398,7 @@ These builtins are never called by LLVM. - ~~ctzdi2.c~~ - ~~ctzsi2.c~~ - ~~ctzti2.c~~ +- ~~ffssi2.c~~ - ~~ffsdi2.c~~ - this is [called by gcc][jemalloc-fail] though! - ~~ffsti2.c~~ - ~~mulvdi3.c~~ @@ -404,13 +461,34 @@ Rust only exposes atomic types on platforms that support them, and therefore doe Miscellaneous functionality that is not used by Rust. +- ~~aarch64/fp_mode.c~~ +- ~~aarch64/lse.S~~ (LSE atomics) +- ~~aarch64/sme-abi-init.c~~ (matrix extension) +- ~~aarch64/sme-abi.S~~ (matrix extension) +- ~~aarch64/sme-libc-routines.c~~ (matrix extension) - ~~apple_versioning.c~~ +- ~~arm/fp_mode.c~~ +- ~~avr/exit.S~~ - ~~clear_cache.c~~ +- ~~cpu_model/aarch64.c~~ +- ~~cpu_model/x86.c~~ +- ~~crtbegin.c~~ +- ~~crtend.c~~ - ~~emutls.c~~ - ~~enable_execute_stack.c~~ - ~~eprintf.c~~ +- ~~fp_mode.c~~ (float exception handling) - ~~gcc_personality_v0.c~~ +- ~~i386/fp_mode.c~~ +- ~~int_util.c~~ +- ~~loongarch/fp_mode.c~~ +- ~~os_version_check.c~~ +- ~~riscv/fp_mode.c~~ +- ~~riscv/restore.S~~ (callee-saved registers) +- ~~riscv/save.S~~ (callee-saved registers) - ~~trampoline_setup.c~~ +- ~~ve/grow_stack.S~~ +- ~~ve/grow_stack_align.S~~ Floating-point implementations of builtins that are only called from soft-float code. It would be better to simply use the generic soft-float versions in this case. From adabbe73d9234ae4f7b4ae0695e87e27accbd8e9 Mon Sep 17 00:00:00 2001 From: Andrey Turkin Date: Sat, 22 Jun 2024 00:01:52 +0300 Subject: [PATCH 1272/4206] Implement __ctz*i2 intrinsics --- library/compiler-builtins/README.md | 6 +- library/compiler-builtins/build.rs | 3 - library/compiler-builtins/src/int/mod.rs | 1 + .../src/int/trailing_zeros.rs | 64 +++++++++++++++++++ .../compiler-builtins/testcrate/tests/misc.rs | 43 +++++++++++++ 5 files changed, 111 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/src/int/trailing_zeros.rs diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 2d7aa337841bb..51bef5e2e7c29 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -171,6 +171,9 @@ rely on CI. - [x] clzti2.c - [x] comparedf2.c - [x] comparesf2.c +- [x] ctzdi2.c +- [x] ctzsi2.c +- [x] ctzti2.c - [x] divdf3.c - [x] divdi3.c - [x] divmoddi4.c @@ -395,9 +398,6 @@ These builtins are never called by LLVM. - ~~arm/switchu8.S~~ - ~~cmpdi2.c~~ - ~~cmpti2.c~~ -- ~~ctzdi2.c~~ -- ~~ctzsi2.c~~ -- ~~ctzti2.c~~ - ~~ffssi2.c~~ - ~~ffsdi2.c~~ - this is [called by gcc][jemalloc-fail] though! - ~~ffsti2.c~~ diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index b8da7cc56c14e..d267d3cc4a831 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -345,8 +345,6 @@ mod c { ("__addvdi3", "addvdi3.c"), ("__addvsi3", "addvsi3.c"), ("__cmpdi2", "cmpdi2.c"), - ("__ctzdi2", "ctzdi2.c"), - ("__ctzsi2", "ctzsi2.c"), ("__int_util", "int_util.c"), ("__mulvdi3", "mulvdi3.c"), ("__mulvsi3", "mulvsi3.c"), @@ -380,7 +378,6 @@ mod c { ("__absvti2", "absvti2.c"), ("__addvti3", "addvti3.c"), ("__cmpti2", "cmpti2.c"), - ("__ctzti2", "ctzti2.c"), ("__ffsti2", "ffsti2.c"), ("__mulvti3", "mulvti3.c"), ("__negti2", "negti2.c"), diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 728ce1d571880..5f56c6b6ee135 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -9,6 +9,7 @@ pub mod leading_zeros; pub mod mul; pub mod sdiv; pub mod shift; +pub mod trailing_zeros; pub mod udiv; pub use big::{i256, u256}; diff --git a/library/compiler-builtins/src/int/trailing_zeros.rs b/library/compiler-builtins/src/int/trailing_zeros.rs new file mode 100644 index 0000000000000..cea366b07549f --- /dev/null +++ b/library/compiler-builtins/src/int/trailing_zeros.rs @@ -0,0 +1,64 @@ +use crate::int::{CastInto, Int}; + +public_test_dep! { +/// Returns number of trailing binary zeros in `x`. +#[allow(dead_code)] +pub(crate) fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { + let mut x = x; + let mut r: u32 = 0; + let mut t: u32; + + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 + x >>= r; // remove 32 zero bits + } + + if T::BITS >= 32 { + t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 + r += t; + x >>= t; // x = [0 - 0xFFFF] + higher garbage bits + } + + const { assert!(T::BITS >= 16) }; + t = ((CastInto::::cast(x) == 0) as u32) << 3; + x >>= t; // x = [0 - 0xFF] + higher garbage bits + r += t; + + let mut x: u8 = x.cast(); + + t = (((x & 0x0F) == 0) as u32) << 2; + x >>= t; // x = [0 - 0xF] + higher garbage bits + r += t; + + t = (((x & 0x3) == 0) as u32) << 1; + x >>= t; // x = [0 - 0x3] + higher garbage bits + r += t; + + x &= 3; + + r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) +} +} + +intrinsics! { + /// Returns the number of trailing binary zeros in `x` (32 bit version). + pub extern "C" fn __ctzsi2(x: u32) -> usize { + trailing_zeros(x) + } + + /// Returns the number of trailing binary zeros in `x` (64 bit version). + pub extern "C" fn __ctzdi2(x: u64) -> usize { + trailing_zeros(x) + } + + /// Returns the number of trailing binary zeros in `x` (128 bit version). + pub extern "C" fn __ctzti2(x: u128) -> usize { + let lo = x as u64; + if lo == 0 { + 64 + __ctzdi2((x >> 64) as u64) + } else { + __ctzdi2(lo) + } + } +} diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index f830a54230e8e..f9431915b15d2 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -131,6 +131,49 @@ fn leading_zeros() { } } +#[test] +fn trailing_zeros() { + use compiler_builtins::int::trailing_zeros::{__ctzdi2, __ctzsi2, __ctzti2, trailing_zeros}; + fuzz(N, |x: u32| { + if x == 0 { + return; // undefined value for an intrinsic + } + let tz = x.trailing_zeros() as usize; + let tz0 = __ctzsi2(x); + let tz1 = trailing_zeros(x); + if tz0 != tz { + panic!("__ctzsi2({}): std: {}, builtins: {}", x, tz, tz0); + } + if tz1 != tz { + panic!("trailing_zeros({}): std: {}, builtins: {}", x, tz, tz1); + } + }); + fuzz(N, |x: u64| { + if x == 0 { + return; // undefined value for an intrinsic + } + let tz = x.trailing_zeros() as usize; + let tz0 = __ctzdi2(x); + let tz1 = trailing_zeros(x); + if tz0 != tz { + panic!("__ctzdi2({}): std: {}, builtins: {}", x, tz, tz0); + } + if tz1 != tz { + panic!("trailing_zeros({}): std: {}, builtins: {}", x, tz, tz1); + } + }); + fuzz(N, |x: u128| { + if x == 0 { + return; // undefined value for an intrinsic + } + let tz = x.trailing_zeros() as usize; + let tz0 = __ctzti2(x); + if tz0 != tz { + panic!("__ctzti2({}): std: {}, builtins: {}", x, tz, tz0); + } + }); +} + #[test] #[cfg(not(target_arch = "avr"))] fn bswap() { From 364dd5fd5b431323792a96103df302303ccde325 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 18 Jul 2024 00:29:04 -0500 Subject: [PATCH 1273/4206] Add `release-plz` for automatic releases. This is what `cc-rs` is using and should create a release PR whenever a change to `master` is made. If the branch is merged, it should publish the new version. Includes configuration to disable semver checks and not keep a changelog since this is an implementation detail. --- .../.github/workflows/publish.yml | 30 +++++++++++++++++++ library/compiler-builtins/.release-plz.toml | 3 ++ .../crates/panic-handler/Cargo.toml | 1 + .../compiler-builtins/testcrate/Cargo.toml | 1 + 4 files changed, 35 insertions(+) create mode 100644 library/compiler-builtins/.github/workflows/publish.yml create mode 100644 library/compiler-builtins/.release-plz.toml diff --git a/library/compiler-builtins/.github/workflows/publish.yml b/library/compiler-builtins/.github/workflows/publish.yml new file mode 100644 index 0000000000000..d568f37573870 --- /dev/null +++ b/library/compiler-builtins/.github/workflows/publish.yml @@ -0,0 +1,30 @@ +name: Release-plz + +permissions: + pull-requests: write + contents: write + +on: + push: + branches: + - master + +jobs: + release-plz: + name: Release-plz + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: true + - name: Install Rust (rustup) + run: rustup update nightly --no-self-update && rustup default nightly + - name: Publish `libm` as part of builtins, rather than its own crate + run: rm libm/Cargo.toml + - name: Run release-plz + uses: MarcoIeni/release-plz-action@v0.5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/library/compiler-builtins/.release-plz.toml b/library/compiler-builtins/.release-plz.toml new file mode 100644 index 0000000000000..affc102650f20 --- /dev/null +++ b/library/compiler-builtins/.release-plz.toml @@ -0,0 +1,3 @@ +[workspace] +changelog_update = false +semver_check = false diff --git a/library/compiler-builtins/crates/panic-handler/Cargo.toml b/library/compiler-builtins/crates/panic-handler/Cargo.toml index 4fb81eb82a411..2ad85840900d8 100644 --- a/library/compiler-builtins/crates/panic-handler/Cargo.toml +++ b/library/compiler-builtins/crates/panic-handler/Cargo.toml @@ -3,5 +3,6 @@ name = "panic-handler" version = "0.1.0" authors = ["Alex Crichton "] edition = "2021" +publish = false [dependencies] diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 6b5c4cf48d2a5..e39c35b6791c8 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -3,6 +3,7 @@ name = "testcrate" version = "0.1.0" authors = ["Alex Crichton "] edition = "2021" +publish = false [lib] test = false From 99456ad08e5b2bab7042771fabcbabec67f7e0d5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 28 Jul 2024 17:00:41 -0400 Subject: [PATCH 1274/4206] Set allow_dirty to release-plz This should resolve the issue in --- library/compiler-builtins/.release-plz.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/.release-plz.toml b/library/compiler-builtins/.release-plz.toml index affc102650f20..fce19d1575597 100644 --- a/library/compiler-builtins/.release-plz.toml +++ b/library/compiler-builtins/.release-plz.toml @@ -1,3 +1,8 @@ [workspace] changelog_update = false semver_check = false + +# As part of the release process, we delete `libm/Cargo.toml`. Since +# this is only run in CI, we shouldn't need to worry about it. +allow_dirty = true +publish_allow_dirty = true From 85d4ef72c8b839f819d978959c08676ca6693169 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 28 Jul 2024 21:08:01 +0000 Subject: [PATCH 1275/4206] chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index c8d78ec3e264a..706031bbf71db 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.113" +version = "0.1.114" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 22e4aa37da718b86332745bbc40375e096862664 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 2 Aug 2024 13:41:08 -0400 Subject: [PATCH 1276/4206] Switch to a target structure in build.rs --- library/compiler-builtins/build.rs | 118 +++++++++++++++++++---------- 1 file changed, 78 insertions(+), 40 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index d267d3cc4a831..80454815f2c14 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1,10 +1,50 @@ use std::{collections::BTreeMap, env, path::PathBuf, sync::atomic::Ordering}; +#[allow(dead_code)] +struct Target { + triple: String, + os: String, + arch: String, + vendor: String, + env: String, + pointer_width: u8, + little_endian: bool, + features: Vec, +} + +impl Target { + fn from_env() -> Self { + let little_endian = match env::var("CARGO_CFG_TARGET_ENDIAN").unwrap().as_str() { + "little" => true, + "big" => false, + x => panic!("unknown endian {x}"), + }; + + Self { + triple: env::var("TARGET").unwrap(), + os: env::var("CARGO_CFG_TARGET_OS").unwrap(), + 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") + .unwrap() + .parse() + .unwrap(), + little_endian, + features: env::var("CARGO_CFG_TARGET_FEATURE") + .unwrap_or_default() + .split(",") + .map(ToOwned::to_owned) + .collect(), + } + } +} + fn main() { println!("cargo:rerun-if-changed=build.rs"); configure_check_cfg(); - let target = env::var("TARGET").unwrap(); + let target = Target::from_env(); let cwd = env::current_dir().unwrap(); println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display()); @@ -14,12 +54,12 @@ fn main() { println!("cargo:rustc-cfg=feature=\"unstable\""); // Emscripten's runtime includes all the builtins - if target.contains("emscripten") { + if target.env == "emscripten" { return; } // OpenBSD provides compiler_rt by default, use it instead of rebuilding it from source - if target.contains("openbsd") { + if target.os == "openbsd" { println!("cargo:rustc-link-search=native=/usr/lib"); println!("cargo:rustc-link-lib=compiler_rt"); return; @@ -27,22 +67,22 @@ fn main() { // Forcibly enable memory intrinsics on wasm & SGX as we don't have a libc to // provide them. - if (target.contains("wasm") && !target.contains("wasi")) - || (target.contains("sgx") && target.contains("fortanix")) - || target.contains("-none") - || target.contains("nvptx") - || target.contains("uefi") - || target.contains("xous") + 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") { println!("cargo:rustc-cfg=feature=\"mem\""); } // These targets have hardware unaligned access support. println!("cargo::rustc-check-cfg=cfg(feature, values(\"mem-unaligned\"))"); - if target.contains("x86_64") - || target.contains("i686") - || target.contains("aarch64") - || target.contains("bpf") + if target.arch.contains("x86_64") + || target.arch.contains("i686") + || target.arch.contains("aarch64") + || target.arch.contains("bpf") { println!("cargo:rustc-cfg=feature=\"mem-unaligned\""); } @@ -50,7 +90,7 @@ fn main() { // 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.split('-').collect::>(); + let llvm_target = 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 @@ -60,7 +100,7 @@ fn main() { // Don't use a C compiler for these targets: // // * nvptx - everything is bitcode, not compatible with mixed C/Rust - if !target.contains("nvptx") { + if !target.arch.contains("nvptx") { #[cfg(feature = "c")] c::compile(&llvm_target, &target); } @@ -86,7 +126,7 @@ fn main() { println!("cargo::rustc-check-cfg=cfg(kernel_user_helpers)"); if llvm_target[0] == "armv4t" || llvm_target[0] == "armv5te" - || target == "arm-linux-androideabi" + || target.triple == "arm-linux-androideabi" { println!("cargo:rustc-cfg=kernel_user_helpers") } @@ -227,6 +267,8 @@ mod c { use std::io::Write; use std::path::{Path, PathBuf}; + use super::Target; + struct Sources { // SYMBOL -> PATH TO SOURCE map: BTreeMap<&'static str, &'static str>, @@ -267,11 +309,7 @@ mod c { } /// Compile intrinsics from the compiler-rt C source code - pub fn compile(llvm_target: &[&str], target: &String) { - let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); - let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap(); - let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); - let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap(); + pub fn compile(llvm_target: &[&str], target: &Target) { let mut consider_float_intrinsics = true; let cfg = &mut cc::Build::new(); @@ -280,8 +318,8 @@ mod c { // // 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.to_owned().replace("-", "_")); + if target.arch == "aarch64" { + let cflags_key = String::from("CFLAGS_") + &(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; @@ -299,7 +337,7 @@ mod c { cfg.warnings(false); - if target_env == "msvc" { + if target.env == "msvc" { // Don't pull in extra libraries on MSVC cfg.flag("/Zl"); @@ -328,7 +366,7 @@ 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 target.os == "uefi" { let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); let include_dir = out_dir.join("include"); if !include_dir.exists() { @@ -373,7 +411,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 target.vendor != "apple" || target.arch != "x86" { sources.extend(&[ ("__absvti2", "absvti2.c"), ("__addvti3", "addvti3.c"), @@ -392,7 +430,7 @@ mod c { } } - if target_vendor == "apple" { + if target.vendor == "apple" { sources.extend(&[ ("atomic_flag_clear", "atomic_flag_clear.c"), ("atomic_flag_clear_explicit", "atomic_flag_clear_explicit.c"), @@ -406,8 +444,8 @@ mod c { ]); } - if target_env != "msvc" { - if target_arch == "x86" { + if target.env != "msvc" { + if target.arch == "x86" { sources.extend(&[ ("__ashldi3", "i386/ashldi3.S"), ("__ashrdi3", "i386/ashrdi3.S"), @@ -421,7 +459,7 @@ mod c { } } - if target_arch == "arm" && target_vendor != "apple" && target_env != "msvc" { + if target.arch == "arm" && target.vendor != "apple" && target.env != "msvc" { sources.extend(&[ ("__aeabi_div0", "arm/aeabi_div0.c"), ("__aeabi_drsub", "arm/aeabi_drsub.c"), @@ -441,7 +479,7 @@ mod c { ("__umodsi3", "arm/umodsi3.S"), ]); - if target_os == "freebsd" { + if target.os == "freebsd" { sources.extend(&[("__clear_cache", "clear_cache.c")]); } @@ -513,7 +551,7 @@ mod c { ]); } - if (target_arch == "aarch64" || target_arch == "arm64ec") && consider_float_intrinsics { + if (target.arch == "aarch64" || target.arch == "arm64ec") && consider_float_intrinsics { sources.extend(&[ ("__comparetf2", "comparetf2.c"), ("__floatditf", "floatditf.c"), @@ -526,16 +564,16 @@ mod c { ("__fe_raise_inexact", "fp_mode.c"), ]); - if target_os != "windows" { + if target.os != "windows" { sources.extend(&[("__multc3", "multc3.c")]); } } - if target_arch == "mips" || target_arch == "riscv32" || target_arch == "riscv64" { + if target.arch == "mips" || target.arch == "riscv32" || target.arch == "riscv64" { sources.extend(&[("__bswapsi2", "bswapsi2.c")]); } - if target_arch == "mips64" { + if target.arch == "mips64" { sources.extend(&[ ("__netf2", "comparetf2.c"), ("__floatsitf", "floatsitf.c"), @@ -544,7 +582,7 @@ mod c { ]); } - if target_arch == "loongarch64" { + if target.arch == "loongarch64" { sources.extend(&[ ("__netf2", "comparetf2.c"), ("__floatsitf", "floatsitf.c"), @@ -554,7 +592,7 @@ mod 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" || target.os == "uefi" { let mut to_remove = Vec::new(); for (k, v) in sources.map.iter() { @@ -570,7 +608,7 @@ mod c { } // Android uses emulated TLS so we need a runtime support function. - if target_os == "android" { + if target.os == "android" { sources.extend(&[("__emutls_get_address", "emutls.c")]); // Work around a bug in the NDK headers (fixed in @@ -580,7 +618,7 @@ mod c { } // OpenHarmony also uses emulated TLS. - if target_env == "ohos" { + if target.env == "ohos" { sources.extend(&[("__emutls_get_address", "emutls.c")]); } @@ -607,7 +645,7 @@ mod c { // sets of flags to the same source file. // Note: Out-of-line aarch64 atomics are not supported by the msvc toolchain (#430). let src_dir = root.join("lib/builtins"); - if target_arch == "aarch64" && target_env != "msvc" { + if target.arch == "aarch64" && target.env != "msvc" { // See below for why we're building these as separate libraries. build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg); From b32758cdc2be7fbcb1e692738d821310ff866c0c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 2 Aug 2024 17:42:36 -0400 Subject: [PATCH 1277/4206] Add back remaining config on `arm_aeabi_alias` Intrinsics marked with `arm_aeabi_alias = ...` were having the rest of their attributes eaten. Add them back. --- library/compiler-builtins/src/macros.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index fb14660af9878..42c83ee55fb9f 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -290,6 +290,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( #[cfg(target_arch = "arm")] + $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } @@ -298,6 +299,7 @@ macro_rules! intrinsics { mod $name { #[no_mangle] #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] + $(#[$($attr)*])* extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } @@ -307,6 +309,7 @@ macro_rules! intrinsics { mod $alias { #[no_mangle] #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] + $(#[$($attr)*])* extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } From b168f56dd4cf5605df9f170daab0541ef16ff66a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 2 Aug 2024 13:48:13 -0400 Subject: [PATCH 1278/4206] Configure which platforms get `f16` and `f128` enabled by default By moving the logic for which platforms get symbols to `compiler_builtins` rather than rust-lang/rust, we can control where symbols get enabled without relying on Cargo features. Using Cargo features turned out to be a problem in [1]. This will help resolve errors like [2]. [1]: https://github.com/rust-lang/rust/issues/128358 [2]: https://github.com/rust-lang/rust/issues/128401 --- library/compiler-builtins/build.rs | 46 ++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 80454815f2c14..749a08a5ae202 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -42,11 +42,12 @@ impl Target { fn main() { println!("cargo:rerun-if-changed=build.rs"); - configure_check_cfg(); - let target = Target::from_env(); let cwd = env::current_dir().unwrap(); + configure_check_cfg(); + configure_f16_f128(&target); + println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display()); // Activate libm's unstable features to make full use of Nightly. @@ -259,6 +260,47 @@ fn configure_check_cfg() { println!("cargo::rustc-check-cfg=cfg(assert_no_panic)"); } +/// Configure whether or not `f16` and `f128` support should be enabled. +fn configure_f16_f128(target: &Target) { + // Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means + // that the backend will not crash when using these types. This does not mean that the + // backend does the right thing, or that the platform doesn't have ABI bugs. + // + // We do this here rather than in `rust-lang/rust` because configuring via cargo features is + // not straightforward. + // + // Original source of this list: + // + let (f16_ok, f128_ok) = match target.arch.as_str() { + // `f16` and `f128` both crash + "arm64ec" => (false, false), + // `f16` crashes + "s390x" => (false, true), + // `f128` crashes + "mips64" | "mips64r6" => (true, false), + // `f128` crashes + "powerpc64" if &target.os == "aix" => (true, false), + // `f128` crashes + "sparc" | "sparcv9" => (true, false), + // Most everything else works as of LLVM 19 + _ => (true, true), + }; + + // If the feature is set, disable these types. + let disable_both = env::var_os("CARGO_FEATURE_NO_F16_F128").is_some(); + + println!("cargo::rustc-check-cfg=cfg(f16_enabled)"); + println!("cargo::rustc-check-cfg=cfg(f128_enabled)"); + + if f16_ok && !disable_both { + println!("cargo::rustc-cfg=f16_enabled"); + } + + if f128_ok && !disable_both { + println!("cargo::rustc-cfg=f128_enabled"); + } +} + #[cfg(feature = "c")] mod c { use std::collections::{BTreeMap, HashSet}; From 8199433bb260b63a7a7398c2d52d752a2cdb040f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 2 Aug 2024 15:58:29 -0400 Subject: [PATCH 1279/4206] Make use of new `f16` and `f128` config options Change from `not(feature = "no-f16-f128")` to `f16_enabled` or `f128_disabled`, as applicable. --- library/compiler-builtins/src/float/add.rs | 2 +- library/compiler-builtins/src/float/cmp.rs | 2 +- library/compiler-builtins/src/float/conv.rs | 12 ++++++------ library/compiler-builtins/src/float/extend.rs | 6 +++++- library/compiler-builtins/src/float/mod.rs | 4 ++-- library/compiler-builtins/src/float/mul.rs | 2 +- library/compiler-builtins/src/float/sub.rs | 2 +- library/compiler-builtins/src/float/trunc.rs | 7 ++++++- library/compiler-builtins/src/lib.rs | 4 ++-- 9 files changed, 25 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 7e8529f3e296f..03ed131af2630 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -204,7 +204,7 @@ intrinsics! { } #[ppc_alias = __addkf3] - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] pub extern "C" fn __addtf3(a: f128, b: f128) -> f128 { add(a, b) } diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 5c431304c61e9..1901ca4b36207 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -172,7 +172,7 @@ intrinsics! { } } -#[cfg(not(feature = "no-f16-f128",))] +#[cfg(f128_enabled)] intrinsics! { #[avr_skip] #[ppc_alias = __lekf2] diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 52119f3e8006e..d275f982bb44d 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -263,19 +263,19 @@ intrinsics! { } #[ppc_alias = __fixunskfsi] - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] pub extern "C" fn __fixunstfsi(f: f128) -> u32 { float_to_unsigned_int(f) } #[ppc_alias = __fixunskfdi] - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] pub extern "C" fn __fixunstfdi(f: f128) -> u64 { float_to_unsigned_int(f) } #[ppc_alias = __fixunskfti] - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] pub extern "C" fn __fixunstfti(f: f128) -> u128 { float_to_unsigned_int(f) } @@ -314,19 +314,19 @@ intrinsics! { } #[ppc_alias = __fixkfsi] - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] pub extern "C" fn __fixtfsi(f: f128) -> i32 { float_to_signed_int(f) } #[ppc_alias = __fixkfdi] - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] pub extern "C" fn __fixtfdi(f: f128) -> i64 { float_to_signed_int(f) } #[ppc_alias = __fixkfti] - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] pub extern "C" fn __fixtfti(f: f128) -> i128 { float_to_signed_int(f) } diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index 556048991334c..2f392255fea7c 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -83,17 +83,18 @@ intrinsics! { } } -#[cfg(not(feature = "no-f16-f128"))] intrinsics! { #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_h2f] + #[cfg(f16_enabled)] pub extern "C" fn __extendhfsf2(a: f16) -> f32 { extend(a) } #[avr_skip] #[aapcs_on_arm] + #[cfg(f16_enabled)] pub extern "C" fn __gnu_h2f_ieee(a: f16) -> f32 { extend(a) } @@ -101,6 +102,7 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __extendhfkf2] + #[cfg(all(f16_enabled, f128_enabled))] pub extern "C" fn __extendhftf2(a: f16) -> f128 { extend(a) } @@ -108,6 +110,7 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __extendsfkf2] + #[cfg(f128_enabled)] pub extern "C" fn __extendsftf2(a: f32) -> f128 { extend(a) } @@ -115,6 +118,7 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __extenddfkf2] + #[cfg(f128_enabled)] pub extern "C" fn __extenddftf2(a: f64) -> f128 { extend(a) } diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 5fef1df32a5be..8473732057a7d 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -188,9 +188,9 @@ macro_rules! float_impl { }; } -#[cfg(not(feature = "no-f16-f128"))] +#[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(not(feature = "no-f16-f128"))] +#[cfg(f128_enabled)] float_impl!(f128, u128, i128, i16, 128, 112); diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index decf722e29ac1..cb0fcdfa853f3 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -195,7 +195,7 @@ intrinsics! { } #[ppc_alias = __mulkf3] - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] pub extern "C" fn __multf3(a: f128, b: f128) -> f128 { mul(a, b) } diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index 3ab46495d4f8e..d33016ead2e39 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -14,7 +14,7 @@ intrinsics! { } #[ppc_alias = __subkf3] - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] pub extern "C" fn __subtf3(a: f128, b: f128) -> f128 { #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] use crate::float::add::__addkf3 as __addtf3; diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index 9aea6f91ebca5..c54ff7805f520 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -131,17 +131,18 @@ intrinsics! { } } -#[cfg(not(feature = "no-f16-f128"))] intrinsics! { #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_f2h] + #[cfg(f16_enabled)] pub extern "C" fn __truncsfhf2(a: f32) -> f16 { trunc(a) } #[avr_skip] #[aapcs_on_arm] + #[cfg(f16_enabled)] pub extern "C" fn __gnu_f2h_ieee(a: f32) -> f16 { trunc(a) } @@ -149,6 +150,7 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_d2h] + #[cfg(f16_enabled)] pub extern "C" fn __truncdfhf2(a: f64) -> f16 { trunc(a) } @@ -156,6 +158,7 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __trunckfhf2] + #[cfg(all(f16_enabled, f128_enabled))] pub extern "C" fn __trunctfhf2(a: f128) -> f16 { trunc(a) } @@ -163,6 +166,7 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __trunckfsf2] + #[cfg(f128_enabled)] pub extern "C" fn __trunctfsf2(a: f128) -> f32 { trunc(a) } @@ -170,6 +174,7 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __trunckfdf2] + #[cfg(f128_enabled)] pub extern "C" fn __trunctfdf2(a: f128) -> f64 { trunc(a) } diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 0d207a914bffd..0d44fdf9654a9 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -13,8 +13,8 @@ #![feature(naked_functions)] #![feature(repr_simd)] #![feature(c_unwind)] -#![cfg_attr(not(feature = "no-f16-f128"), feature(f16))] -#![cfg_attr(not(feature = "no-f16-f128"), feature(f128))] +#![cfg_attr(f16_enabled, feature(f16))] +#![cfg_attr(f128_enabled, feature(f128))] #![no_builtins] #![no_std] #![allow(unused_features)] From db8daebd5bef86ee00887aaca082faa87c120ca0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 2 Aug 2024 19:20:26 -0400 Subject: [PATCH 1280/4206] Update which platforms have no `f16` symbols Previously we were building the C versions of these symbols. Since we added the Rust version and updated compiler builtins, these are no longer available by default. This is unintentional, but it gives a better indicator of which symbol versions are not actually provided by the system. Use the list of build failures to correct the list of platforms that do not have `f16` symbols. --- library/compiler-builtins/testcrate/build.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 12c3e7d13655e..fc01f3f8d029b 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -44,10 +44,20 @@ fn main() { features.insert(Feature::NoSysF16F128Convert); } - if target.starts_with("wasm32-") { + // 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.starts_with("aarch64-") && target.contains("linux")) + || target.starts_with("arm") + || target.starts_with("powerpc-") + || target.starts_with("powerpc64-") + || target.starts_with("powerpc64le-") + || target.contains("windows-") // Linking says "error: function signature mismatch: __extendhfsf2" and seems to // think the signature is either `(i32) -> f32` or `(f32) -> f32` + || target.starts_with("wasm32-") + { features.insert(Feature::NoSysF16); + features.insert(Feature::NoSysF16F128Convert); } for feature in features { From 1cdeaed9f9ef495b5cb5080ccc1d6b83c1a73eae Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 2 Aug 2024 19:29:37 -0400 Subject: [PATCH 1281/4206] Correct `sys_avialable` for `f64` -> `f16` truncation The `sys_available` gate was incorrect. Update it. --- library/compiler-builtins/testcrate/benches/float_trunc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/testcrate/benches/float_trunc.rs b/library/compiler-builtins/testcrate/benches/float_trunc.rs index 1553dacee0820..70869bcaf6279 100644 --- a/library/compiler-builtins/testcrate/benches/float_trunc.rs +++ b/library/compiler-builtins/testcrate/benches/float_trunc.rs @@ -32,7 +32,7 @@ float_bench! { sig: (a: f64) -> f16, crate_fn: trunc::__truncdfhf2, sys_fn: __truncdfhf2, - sys_available: not(feature = "no-sys-f128"), + sys_available: not(feature = "no-sys-f16"), asm: [ #[cfg(target_arch = "aarch64")] { // FIXME(f16_f128): remove `from_bits()` after f16 asm support (rust-lang/rust/#116909) From b6c2b6ebf7499d83f25b8c420e837cc1d24a2085 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 2 Aug 2024 21:44:36 -0400 Subject: [PATCH 1282/4206] Update to the latest `rustc_apfloat` The latest version has a convenient `.unwrap()`. Increase the version so we can use this. --- library/compiler-builtins/testcrate/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index e39c35b6791c8..21cec17010933 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -15,7 +15,7 @@ doctest = false # `xoshiro128**` is used for its quality, size, and speed at generating `u32` shift amounts. rand_xoshiro = "0.6" # To compare float builtins against -rustc_apfloat = "0.2.0" +rustc_apfloat = "0.2.1" [dependencies.compiler_builtins] path = ".." From e0e6243b219835bdfbde2d198f548175c4c1d16b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 2 Aug 2024 21:45:59 -0400 Subject: [PATCH 1283/4206] Update float conversion tests Since there are more platforms that do not have symbols present, we need to use `rustc_apfloat` for more conversion tests. Make use of the fallback like other tests, and refactor so each test gets its own function. Previously we were testing both apfloat and system conversion methods when possible. This changes to only test one or the other, depending on whether or not the system version is available. This seems reasonable because it is consistent with all other tests, but we should consider updating all tests to check both at some point. This also includes an adjustment of PowerPC configuration to account for the linking errors at [1]. [1]: https://github.com/rust-lang/compiler-builtins/issues/655 --- .../testcrate/benches/float_extend.rs | 11 + .../testcrate/benches/float_trunc.rs | 6 + library/compiler-builtins/testcrate/build.rs | 1 + .../compiler-builtins/testcrate/src/lib.rs | 6 +- .../compiler-builtins/testcrate/tests/conv.rs | 252 ++++++------------ 5 files changed, 100 insertions(+), 176 deletions(-) diff --git a/library/compiler-builtins/testcrate/benches/float_extend.rs b/library/compiler-builtins/testcrate/benches/float_extend.rs index 9bd8009e93b93..bf136f49a0bd7 100644 --- a/library/compiler-builtins/testcrate/benches/float_extend.rs +++ b/library/compiler-builtins/testcrate/benches/float_extend.rs @@ -82,6 +82,7 @@ float_bench! { asm: [], } +#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] criterion_group!( float_extend, extend_f16_f32, @@ -90,4 +91,14 @@ criterion_group!( extend_f32_f128, extend_f64_f128, ); + +// FIXME(#655): `f16` tests disabled until we can bootstrap symbols +#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +criterion_group!( + float_extend, + extend_f32_f64, + extend_f32_f128, + extend_f64_f128, +); + criterion_main!(float_extend); diff --git a/library/compiler-builtins/testcrate/benches/float_trunc.rs b/library/compiler-builtins/testcrate/benches/float_trunc.rs index 70869bcaf6279..74b43dfc833c2 100644 --- a/library/compiler-builtins/testcrate/benches/float_trunc.rs +++ b/library/compiler-builtins/testcrate/benches/float_trunc.rs @@ -115,6 +115,7 @@ float_bench! { asm: [], } +#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] criterion_group!( float_trunc, trunc_f32_f16, @@ -124,4 +125,9 @@ criterion_group!( trunc_f128_f32, trunc_f128_f64, ); + +// FIXME(#655): `f16` tests disabled until we can bootstrap symbols +#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +criterion_group!(float_trunc, trunc_f64_f32, trunc_f128_f32, trunc_f128_f64,); + criterion_main!(float_trunc); diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index fc01f3f8d029b..8c441de8a9586 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -51,6 +51,7 @@ fn main() { || target.starts_with("powerpc-") || target.starts_with("powerpc64-") || target.starts_with("powerpc64le-") + || target.starts_with("i586-") || target.contains("windows-") // Linking says "error: function signature mismatch: __extendhfsf2" and seems to // think the signature is either `(i32) -> f32` or `(f32) -> f32` diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index f9b052528f027..5458c9ab6d05b 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -282,6 +282,8 @@ macro_rules! apfloat_fallback { // The expression to run. This expression may use `FloatTy` for its signature. // Optionally, the final conversion back to a float can be suppressed using // `=> no_convert` (for e.g. operations that return a bool). + // + // If the apfloat needs a different operation, it can be provided here. $op:expr $(=> $convert:ident)? $(; $apfloat_op:expr)?, // Arguments that get passed to `$op` after converting to a float $($arg:expr),+ @@ -318,7 +320,7 @@ macro_rules! apfloat_fallback { // Some apfloat operations return a `StatusAnd` that we need to extract the value from. This // is the default. - (@inner fty: $float_ty:ty, op_res: $val:expr, args: $($_arg:expr),+) => {{ + (@inner fty: $float_ty:ty, op_res: $val:expr, args: $($_arg:expr),+) => {{ // ignore the status, just get the value let unwrapped = $val.value; @@ -326,7 +328,7 @@ macro_rules! apfloat_fallback { }}; // This is the case where we can't use the same expression for the default builtin and - // nonstandard apfloat fallbac (e.g. `as` casts in std are normal functions in apfloat, so + // nonstandard apfloat fallback (e.g. `as` casts in std are normal functions in apfloat, so // two separate expressions must be specified. (@inner fty: $float_ty:ty, op_res: $_val:expr, diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 1425b49ce494a..e394183cf57e0 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -206,212 +206,116 @@ mod f_to_i { } } -macro_rules! conv { - ($fX:ident, $fD:ident, $fn:ident, $apfloatX:ident, $apfloatD:ident) => { - fuzz_float(N, |x: $fX| { - let tmp0: $apfloatD = $apfloatX::from_bits(x.to_bits().into()) - .convert(&mut false) - .value; - let tmp0 = $fD::from_bits(tmp0.to_bits().try_into().unwrap()); - let tmp1: $fD = $fn(x); - if !Float::eq_repr(tmp0, tmp1) { - panic!( - "{}({x:?}): apfloat: {tmp0:?}, builtins: {tmp1:?}", - stringify!($fn) - ); - } - }) - }; -} - -macro_rules! extend { - ($fX:ident, $fD:ident, $fn:ident) => { +macro_rules! f_to_f { + ( + $mod:ident, + $( + $from_ty:ty => $to_ty:ty, + $from_ap_ty:ident => $to_ap_ty:ident, + $fn:ident, $sys_available:meta + );+; + ) => {$( #[test] fn $fn() { - use compiler_builtins::float::extend::$fn; + use compiler_builtins::float::{$mod::$fn, Float}; + use rustc_apfloat::ieee::{$from_ap_ty, $to_ap_ty}; + + fuzz_float(N, |x: $from_ty| { + let tmp0: $to_ty = apfloat_fallback!( + $from_ty, + $from_ap_ty, + $sys_available, + |x: $from_ty| x as $to_ty; + |x: $from_ty| { + let from_apf = FloatTy::from_bits(x.to_bits().into()); + // Get `value` directly to ignore INVALID_OP + let to_apf: $to_ap_ty = from_apf.convert(&mut false).value; + <$to_ty>::from_bits(to_apf.to_bits().try_into().unwrap()) + }, + x + ); + let tmp1: $to_ty = $fn(x); - fuzz_float(N, |x: $fX| { - let tmp0 = x as $fD; - let tmp1: $fD = $fn(x); if !Float::eq_repr(tmp0, tmp1) { panic!( - "{}({}): std: {}, builtins: {}", + "{}({:?}): std: {:?}, builtins: {:?}", stringify!($fn), x, tmp0, tmp1 ); } - }); + }) } - }; + )+}; } -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -mod float_extend { +mod extend { use super::*; - extend!(f32, f64, __extendsfdf2); - - #[test] - fn conv() { - use compiler_builtins::float::extend::__extendsfdf2; - use rustc_apfloat::ieee::{Double, Single}; - - conv!(f32, f64, __extendsfdf2, Single, Double); + f_to_f! { + extend, + f32 => f64, Single => Double, __extendsfdf2, all(); } -} - -#[cfg(not(feature = "no-f16-f128"))] -#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] -mod float_extend_f128 { - use super::*; - - #[test] - fn conv() { - use compiler_builtins::float::extend::{ - __extenddftf2, __extendhfsf2, __extendhftf2, __extendsftf2, __gnu_h2f_ieee, - }; - use rustc_apfloat::ieee::{Double, Half, Quad, Single}; - // FIXME(f16_f128): Also do extend!() for `f16` and `f128` when builtins are in nightly - conv!(f16, f32, __extendhfsf2, Half, Single); - conv!(f16, f32, __gnu_h2f_ieee, Half, Single); - conv!(f16, f128, __extendhftf2, Half, Quad); - conv!(f32, f128, __extendsftf2, Single, Quad); - conv!(f64, f128, __extenddftf2, Double, Quad); + #[cfg(target_arch = "arm")] + f_to_f! { + extend, + f32 => f64, Single => Double, __extendsfdf2vfp, all(); } -} -#[cfg(not(feature = "no-f16-f128"))] -#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] -mod float_extend_f128_ppc { - use super::*; - - #[test] - fn conv() { - use compiler_builtins::float::extend::{ - __extenddfkf2, __extendhfkf2, __extendhfsf2, __extendsfkf2, __gnu_h2f_ieee, - }; - use rustc_apfloat::ieee::{Double, Half, Quad, Single}; - - // FIXME(f16_f128): Also do extend!() for `f16` and `f128` when builtins are in nightly - conv!(f16, f32, __extendhfsf2, Half, Single); - conv!(f16, f32, __gnu_h2f_ieee, Half, Single); - conv!(f16, f128, __extendhfkf2, Half, Quad); - conv!(f32, f128, __extendsfkf2, Single, Quad); - conv!(f64, f128, __extenddfkf2, Double, Quad); + #[cfg(not(feature = "no-f16-f128"))] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + 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 => 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"); } -} - -#[cfg(target_arch = "arm")] -mod float_extend_arm { - use super::*; - extend!(f32, f64, __extendsfdf2vfp); - - #[test] - fn conv() { - use compiler_builtins::float::extend::__extendsfdf2vfp; - use rustc_apfloat::ieee::{Double, Single}; - - conv!(f32, f64, __extendsfdf2vfp, Single, Double); + #[cfg(not(feature = "no-f16-f128"))] + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + 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"); } } -macro_rules! trunc { - ($fX:ident, $fD:ident, $fn:ident) => { - #[test] - fn $fn() { - use compiler_builtins::float::trunc::$fn; - - fuzz_float(N, |x: $fX| { - let tmp0 = x as $fD; - let tmp1: $fD = $fn(x); - if !Float::eq_repr(tmp0, tmp1) { - panic!( - "{}({}): std: {}, builtins: {}", - stringify!($fn), - x, - tmp0, - tmp1 - ); - } - }); - } - }; -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -mod float_trunc { +mod trunc { use super::*; - trunc!(f64, f32, __truncdfsf2); - - #[test] - fn conv() { - use compiler_builtins::float::trunc::__truncdfsf2; - use rustc_apfloat::ieee::{Double, Single}; - - conv!(f64, f32, __truncdfsf2, Double, Single); + f_to_f! { + trunc, + f64 => f32, Double => Single, __truncdfsf2, all(); } -} -#[cfg(not(feature = "no-f16-f128"))] -#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] -mod float_trunc_f128 { - use super::*; - - #[test] - fn conv() { - use compiler_builtins::float::trunc::{__gnu_f2h_ieee, __truncdfhf2, __truncsfhf2}; - use compiler_builtins::float::trunc::{__trunctfdf2, __trunctfhf2, __trunctfsf2}; - use rustc_apfloat::ieee::{Double, Half, Quad, Single}; - - // FIXME(f16_f128): Also do trunc!() for `f16` and `f128` when builtins are in nightly - conv!(f32, f16, __truncsfhf2, Single, Half); - conv!(f32, f16, __gnu_f2h_ieee, Single, Half); - conv!(f64, f16, __truncdfhf2, Double, Half); - conv!(f128, f16, __trunctfhf2, Quad, Half); - conv!(f128, f32, __trunctfsf2, Quad, Single); - conv!(f128, f64, __trunctfdf2, Quad, Double); + #[cfg(target_arch = "arm")] + f_to_f! { + trunc, + f64 => f32, Double => Single, __truncdfsf2vfp, all(); } -} - -#[cfg(not(feature = "no-f16-f128"))] -#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] -mod float_trunc_f128_ppc { - use super::*; - - #[test] - fn conv() { - use compiler_builtins::float::trunc::{__gnu_f2h_ieee, __truncdfhf2, __truncsfhf2}; - use compiler_builtins::float::trunc::{__trunckfdf2, __trunckfhf2, __trunckfsf2}; - use rustc_apfloat::ieee::{Double, Half, Quad, Single}; - // FIXME(f16_f128): Also do trunc!() for `f16` and `f128` when builtins are in nightly - conv!(f32, f16, __truncsfhf2, Single, Half); - conv!(f32, f16, __gnu_f2h_ieee, Single, Half); - conv!(f64, f16, __truncdfhf2, Double, Half); - conv!(f128, f16, __trunckfhf2, Quad, Half); - conv!(f128, f32, __trunckfsf2, Quad, Single); - conv!(f128, f64, __trunckfdf2, Quad, Double); + #[cfg(not(feature = "no-f16-f128"))] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + 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"); + 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"); } -} - -#[cfg(target_arch = "arm")] -mod float_trunc_arm { - use super::*; - trunc!(f64, f32, __truncdfsf2vfp); - - #[test] - fn conv() { - use compiler_builtins::float::trunc::__truncdfsf2vfp; - use rustc_apfloat::ieee::{Double, Single}; - - conv!(f64, f32, __truncdfsf2vfp, Double, Single) + #[cfg(not(feature = "no-f16-f128"))] + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + 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"); } } From 72e745ff9c4713a6dbf5be82c84839ab09f196c7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 4 Aug 2024 23:17:25 +0000 Subject: [PATCH 1284/4206] chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 706031bbf71db..805b44cad0f94 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.114" +version = "0.1.115" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 5a4ccab86684a05075cf93ac0063d782bdc2ae42 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 5 Aug 2024 16:26:27 -0500 Subject: [PATCH 1285/4206] Fix emscripten as `os` rather than `env`. b7af6078 ("Switch to a target structure...") is checking whether the target environment is emscripten, but it seems emscripten is the OS. Fix this, which should resolve the issue in . --- library/compiler-builtins/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 749a08a5ae202..bbae9e2862f14 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -55,7 +55,7 @@ fn main() { println!("cargo:rustc-cfg=feature=\"unstable\""); // Emscripten's runtime includes all the builtins - if target.env == "emscripten" { + if target.os == "emscripten" { return; } From 976881c9c90536a62eea5e1754cc0e90ab6fece2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 3 Aug 2024 21:29:58 -0400 Subject: [PATCH 1286/4206] Eliminate the use of `public_test_dep!` Replace `public_test_dep!` by placing optionally public items into new modules, then controlling what is exported with the `public-test-deps` feature. This is nicer for automatic formatting and diagnostics. --- library/compiler-builtins/src/float/mod.rs | 190 +------- library/compiler-builtins/src/float/traits.rs | 184 ++++++++ .../src/int/leading_zeros.rs | 228 +++++----- library/compiler-builtins/src/int/mod.rs | 417 +----------------- .../src/int/specialized_div_rem/delegate.rs | 4 +- .../src/int/trailing_zeros.rs | 70 +-- library/compiler-builtins/src/int/traits.rs | 402 +++++++++++++++++ library/compiler-builtins/src/macros.rs | 16 - 8 files changed, 752 insertions(+), 759 deletions(-) create mode 100644 library/compiler-builtins/src/float/traits.rs create mode 100644 library/compiler-builtins/src/int/traits.rs diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 8473732057a7d..41b308626b392 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,7 +1,3 @@ -use core::ops; - -use crate::int::{DInt, Int, MinInt}; - pub mod add; pub mod cmp; pub mod conv; @@ -10,187 +6,11 @@ pub mod extend; pub mod mul; pub mod pow; pub mod sub; +pub(crate) mod traits; pub mod trunc; -/// Wrapper to extract the integer type half of the float's size -pub(crate) type HalfRep = <::Int as DInt>::H; - -public_test_dep! { -/// Trait for some basic operations on floats -#[allow(dead_code)] -pub(crate) 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; - - /// 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 SIGNIFICAND_BITS: u32; - - /// The bitwidth of the exponent - const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1; - - /// The maximum value of the exponent - const EXPONENT_MAX: u32 = (1 << Self::EXPONENT_BITS) - 1; - - /// The exponent bias value - const EXPONENT_BIAS: u32 = Self::EXPONENT_MAX >> 1; - - /// A mask for the sign bit - const SIGN_MASK: Self::Int; - - /// A mask for the significand - const SIGNIFICAND_MASK: Self::Int; - - /// The implicit bit of the float format - const IMPLICIT_BIT: Self::Int; - - /// A mask for the exponent - const EXPONENT_MASK: Self::Int; - - /// Returns `self` transmuted to `Self::Int` - fn repr(self) -> Self::Int; - - /// Returns `self` transmuted to `Self::SignedInt` - fn signed_repr(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 with 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_repr(a: Self::Int) -> Self; - - /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. - fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self; - - /// 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 SIGNIFICAND_BITS: u32 = $significand_bits; - - const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); - const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1; - const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; - const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); - - fn repr(self) -> Self::Int { - self.to_bits() - } - fn signed_repr(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.repr() & $ty::EXPONENT_MASK == $ty::EXPONENT_MASK - && x.repr() & $ty::SIGNIFICAND_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.repr() == rhs.repr() - } - } - fn is_sign_negative(self) -> bool { - self.is_sign_negative() - } - fn exp(self) -> Self::ExpInt { - ((self.to_bits() & Self::EXPONENT_MASK) >> Self::SIGNIFICAND_BITS) as Self::ExpInt - } - fn frac(self) -> Self::Int { - self.to_bits() & Self::SIGNIFICAND_MASK - } - fn imp_frac(self) -> Self::Int { - self.frac() | Self::IMPLICIT_BIT - } - fn from_repr(a: Self::Int) -> Self { - Self::from_bits(a) - } - fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_repr( - ((sign as Self::Int) << (Self::BITS - 1)) - | ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) - | (significand & Self::SIGNIFICAND_MASK), - ) - } - fn normalize(significand: Self::Int) -> (i32, Self::Int) { - let shift = significand - .leading_zeros() - .wrapping_sub((Self::Int::ONE << Self::SIGNIFICAND_BITS).leading_zeros()); - ( - 1i32.wrapping_sub(shift as i32), - significand << shift as Self::Int, - ) - } - fn is_subnormal(self) -> bool { - (self.repr() & Self::EXPONENT_MASK) == Self::Int::ZERO - } - } - }; -} +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use traits::{Float, HalfRep}; -#[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); +#[cfg(feature = "public-test-deps")] +pub use traits::{Float, HalfRep}; diff --git a/library/compiler-builtins/src/float/traits.rs b/library/compiler-builtins/src/float/traits.rs new file mode 100644 index 0000000000000..e57bd1b98259b --- /dev/null +++ b/library/compiler-builtins/src/float/traits.rs @@ -0,0 +1,184 @@ +use core::ops; + +use crate::int::{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; + + /// 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 SIGNIFICAND_BITS: u32; + + /// The bitwidth of the exponent + const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1; + + /// The maximum value of the exponent + const EXPONENT_MAX: u32 = (1 << Self::EXPONENT_BITS) - 1; + + /// The exponent bias value + const EXPONENT_BIAS: u32 = Self::EXPONENT_MAX >> 1; + + /// A mask for the sign bit + const SIGN_MASK: Self::Int; + + /// A mask for the significand + const SIGNIFICAND_MASK: Self::Int; + + /// The implicit bit of the float format + const IMPLICIT_BIT: Self::Int; + + /// A mask for the exponent + const EXPONENT_MASK: Self::Int; + + /// Returns `self` transmuted to `Self::Int` + fn repr(self) -> Self::Int; + + /// Returns `self` transmuted to `Self::SignedInt` + fn signed_repr(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 with 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_repr(a: Self::Int) -> Self; + + /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. + fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self; + + /// 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 SIGNIFICAND_BITS: u32 = $significand_bits; + + const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); + const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1; + const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; + const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); + + fn repr(self) -> Self::Int { + self.to_bits() + } + fn signed_repr(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.repr() & $ty::EXPONENT_MASK == $ty::EXPONENT_MASK + && x.repr() & $ty::SIGNIFICAND_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.repr() == rhs.repr() + } + } + fn is_sign_negative(self) -> bool { + self.is_sign_negative() + } + fn exp(self) -> Self::ExpInt { + ((self.to_bits() & Self::EXPONENT_MASK) >> Self::SIGNIFICAND_BITS) as Self::ExpInt + } + fn frac(self) -> Self::Int { + self.to_bits() & Self::SIGNIFICAND_MASK + } + fn imp_frac(self) -> Self::Int { + self.frac() | Self::IMPLICIT_BIT + } + fn from_repr(a: Self::Int) -> Self { + Self::from_bits(a) + } + fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { + Self::from_repr( + ((sign as Self::Int) << (Self::BITS - 1)) + | ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) + | (significand & Self::SIGNIFICAND_MASK), + ) + } + fn normalize(significand: Self::Int) -> (i32, Self::Int) { + let shift = significand + .leading_zeros() + .wrapping_sub((Self::Int::ONE << Self::SIGNIFICAND_BITS).leading_zeros()); + ( + 1i32.wrapping_sub(shift as i32), + significand << shift as Self::Int, + ) + } + fn is_subnormal(self) -> bool { + (self.repr() & Self::EXPONENT_MASK) == Self::Int::ZERO + } + } + }; +} + +#[cfg(not(feature = "no-f16-f128"))] +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(not(feature = "no-f16-f128"))] +float_impl!(f128, u128, i128, i16, 128, 112); diff --git a/library/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/src/int/leading_zeros.rs index 1fee9fcf5d8fd..eede1ebe61cd2 100644 --- a/library/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/src/int/leading_zeros.rs @@ -3,137 +3,141 @@ // adding a zero check at the beginning, but `__clzsi2` has a precondition that `x != 0`. // Compilers will insert the check for zero in cases where it is needed. -use crate::int::{CastInto, Int}; +mod implementation { + use crate::int::{CastInto, Int}; -public_test_dep! { -/// Returns the number of leading binary zeros in `x`. -#[allow(dead_code)] -pub(crate) fn leading_zeros_default>(x: T) -> usize { - // The basic idea is to test if the higher bits of `x` are zero and bisect the number - // of leading zeros. It is possible for all branches of the bisection to use the same - // code path by conditionally shifting the higher parts down to let the next bisection - // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` - // and adding to the number of zeros, it is slightly faster to start with - // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, - // because it simplifies the final bisection step. - let mut x = x; - // the number of potential leading zeros - let mut z = T::BITS as usize; - // a temporary - let mut t: T; + /// Returns the number of leading binary zeros in `x`. + #[allow(dead_code)] + pub fn leading_zeros_default>(x: T) -> usize { + // The basic idea is to test if the higher bits of `x` are zero and bisect the number + // of leading zeros. It is possible for all branches of the bisection to use the same + // code path by conditionally shifting the higher parts down to let the next bisection + // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` + // and adding to the number of zeros, it is slightly faster to start with + // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, + // because it simplifies the final bisection step. + let mut x = x; + // the number of potential leading zeros + let mut z = T::BITS as usize; + // a temporary + let mut t: T; - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - t = x >> 32; + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + t = x >> 32; + if t != T::ZERO { + z -= 32; + x = t; + } + } + if T::BITS >= 32 { + t = x >> 16; + if t != T::ZERO { + z -= 16; + x = t; + } + } + const { assert!(T::BITS >= 16) }; + t = x >> 8; if t != T::ZERO { - z -= 32; + z -= 8; x = t; } - } - if T::BITS >= 32 { - t = x >> 16; + t = x >> 4; if t != T::ZERO { - z -= 16; + z -= 4; x = t; } - } - const { assert!(T::BITS >= 16) }; - t = x >> 8; - if t != T::ZERO { - z -= 8; - x = t; - } - t = x >> 4; - if t != T::ZERO { - z -= 4; - x = t; - } - t = x >> 2; - if t != T::ZERO { - z -= 2; - x = t; - } - // the last two bisections are combined into one conditional - t = x >> 1; - if t != T::ZERO { - z - 2 - } else { - z - x.cast() - } + t = x >> 2; + if t != T::ZERO { + z -= 2; + x = t; + } + // the last two bisections are combined into one conditional + t = x >> 1; + if t != T::ZERO { + z - 2 + } else { + z - x.cast() + } - // We could potentially save a few cycles by using the LUT trick from - // "https://embeddedgurus.com/state-space/2014/09/-%20%20%20%20//%20fast-deterministic-and-portable-counting-leading-zeros/". - // However, 256 bytes for a LUT is too large for embedded use cases. We could remove - // the last 3 bisections and use this 16 byte LUT for the rest of the work: - //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; - //z -= LUT[x] as usize; - //z - // However, it ends up generating about the same number of instructions. When benchmarked - // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO - // execution effects. Changing to using a LUT and branching is risky for smaller cores. -} -} + // We could potentially save a few cycles by using the LUT trick from + // "https://embeddedgurus.com/state-space/2014/09/+%20%20%20%20%20%20%20%20//%20fast-deterministic-and-portable-counting-leading-zeros/". + // However, 256 bytes for a LUT is too large for embedded use cases. We could remove + // the last 3 bisections and use this 16 byte LUT for the rest of the work: + //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; + //z -= LUT[x] as usize; + //z + // However, it ends up generating about the same number of instructions. When benchmarked + // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO + // execution effects. Changing to using a LUT and branching is risky for smaller cores. + } -// The above method does not compile well on RISC-V (because of the lack of predicated -// instructions), producing code with many branches or using an excessively long -// branchless solution. This method takes advantage of the set-if-less-than instruction on -// RISC-V that allows `(x >= power-of-two) as usize` to be branchless. + // The above method does not compile well on RISC-V (because of the lack of predicated + // instructions), producing code with many branches or using an excessively long + // branchless solution. This method takes advantage of the set-if-less-than instruction on + // RISC-V that allows `(x >= power-of-two) as usize` to be branchless. -public_test_dep! { -/// Returns the number of leading binary zeros in `x`. -#[allow(dead_code)] -pub(crate) fn leading_zeros_riscv>(x: T) -> usize { - let mut x = x; - // the number of potential leading zeros - let mut z = T::BITS; - // a temporary - let mut t: u32; + /// Returns the number of leading binary zeros in `x`. + #[allow(dead_code)] + pub fn leading_zeros_riscv>(x: T) -> usize { + let mut x = x; + // the number of potential leading zeros + let mut z = T::BITS; + // a temporary + let mut t: u32; - // RISC-V does not have a set-if-greater-than-or-equal instruction and - // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is - // still the most optimal method. A conditional set can only be turned into a single - // immediate instruction if `x` is compared with an immediate `imm` (that can fit into - // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the - // right). If we try to save an instruction by using `x < imm` for each bisection, we - // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, - // but the immediate will never fit into 12 bits and never save an instruction. - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise - // `t` is set to 0. - t = ((x >= (T::ONE << 32)) as u32) << 5; - // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the - // next step to process. + // RISC-V does not have a set-if-greater-than-or-equal instruction and + // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is + // still the most optimal method. A conditional set can only be turned into a single + // immediate instruction if `x` is compared with an immediate `imm` (that can fit into + // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the + // right). If we try to save an instruction by using `x < imm` for each bisection, we + // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, + // but the immediate will never fit into 12 bits and never save an instruction. + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise + // `t` is set to 0. + t = ((x >= (T::ONE << 32)) as u32) << 5; + // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the + // next step to process. + x >>= t; + // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential + // leading zeros + z -= t; + } + if T::BITS >= 32 { + t = ((x >= (T::ONE << 16)) as u32) << 4; + x >>= t; + z -= t; + } + const { assert!(T::BITS >= 16) }; + t = ((x >= (T::ONE << 8)) as u32) << 3; x >>= t; - // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential - // leading zeros z -= t; - } - if T::BITS >= 32 { - t = ((x >= (T::ONE << 16)) as u32) << 4; + t = ((x >= (T::ONE << 4)) as u32) << 2; x >>= t; z -= t; + t = ((x >= (T::ONE << 2)) as u32) << 1; + x >>= t; + z -= t; + t = (x >= (T::ONE << 1)) as u32; + x >>= t; + z -= t; + // All bits except the LSB are guaranteed to be zero for this final bisection step. + // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. + z as usize - x.cast() } - const { assert!(T::BITS >= 16) }; - t = ((x >= (T::ONE << 8)) as u32) << 3; - x >>= t; - z -= t; - t = ((x >= (T::ONE << 4)) as u32) << 2; - x >>= t; - z -= t; - t = ((x >= (T::ONE << 2)) as u32) << 1; - x >>= t; - z -= t; - t = (x >= (T::ONE << 1)) as u32; - x >>= t; - z -= t; - // All bits except the LSB are guaranteed to be zero for this final bisection step. - // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. - z as usize - x.cast() -} } +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use implementation::*; + +#[cfg(feature = "public-test-deps")] +pub use implementation::*; + intrinsics! { /// Returns the number of leading binary zeros in `x` pub extern "C" fn __clzsi2(x: u32) -> usize { diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 5f56c6b6ee135..a0d992e136d02 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -1,6 +1,4 @@ -use core::ops; - -mod specialized_div_rem; +pub(crate) mod specialized_div_rem; pub mod addsub; mod big; @@ -10,416 +8,13 @@ pub mod mul; pub mod sdiv; pub mod shift; pub mod trailing_zeros; +mod traits; pub mod udiv; pub use big::{i256, u256}; -public_test_dep! { -/// Minimal integer implementations needed on all integer types, including wide integers. -#[allow(dead_code)] -pub(crate) trait MinInt: Copy - + core::fmt::Debug - + ops::BitOr - + ops::Not - + ops::Shl -{ - - /// Type with the same width but other signedness - type OtherSign: MinInt; - /// Unsigned version of Self - type UnsignedInt: MinInt; - - /// If `Self` is a signed integer - const SIGNED: bool; - - /// The bitwidth of the int type - const BITS: u32; - - const ZERO: Self; - const ONE: Self; - const MIN: Self; - const MAX: Self; -} -} - -public_test_dep! { -/// Trait for some basic operations on integers -#[allow(dead_code)] -pub(crate) trait Int: MinInt - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::SubAssign - + ops::BitAndAssign - + ops::BitOrAssign - + ops::BitXorAssign - + ops::ShlAssign - + ops::ShrAssign - + ops::Add - + ops::Sub - + ops::Mul - + ops::Div - + ops::Shr - + ops::BitXor - + ops::BitAnd -{ - /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing - /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, - /// 112,119,120,125,126,127]. - const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); - - /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. - const FUZZ_NUM: usize = { - let log2 = (::BITS - 1).count_ones() as usize; - if log2 == 3 { - // case for u8 - 6 - } else { - // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate - // boundaries. - 8 + (4 * (log2 - 4)) - } - }; - - fn unsigned(self) -> Self::UnsignedInt; - fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; - - fn from_bool(b: bool) -> Self; - - /// Prevents the need for excessive conversions between signed and unsigned - fn logical_shr(self, other: u32) -> Self; - - /// Absolute difference between two integers. - fn abs_diff(self, other: Self) -> Self::UnsignedInt; - - // copied from primitive integers, but put in a trait - fn is_zero(self) -> bool; - fn wrapping_neg(self) -> Self; - fn wrapping_add(self, other: Self) -> Self; - fn wrapping_mul(self, other: Self) -> Self; - fn wrapping_sub(self, other: Self) -> Self; - fn wrapping_shl(self, other: u32) -> Self; - fn wrapping_shr(self, other: u32) -> Self; - fn rotate_left(self, other: u32) -> Self; - fn overflowing_add(self, other: Self) -> (Self, bool); - fn leading_zeros(self) -> u32; - fn ilog2(self) -> u32; -} -} - -pub(crate) const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { - let mut v = [0u8; 20]; - v[0] = 0; - v[1] = 1; - v[2] = 2; // important for parity and the iX::MIN case when reversed - let mut i = 3; - - // No need for any more until the byte boundary, because there should be no algorithms - // that are sensitive to anything not next to byte boundaries after 2. We also scale - // in powers of two, which is important to prevent u128 corner tests from getting too - // big. - let mut l = 8; - loop { - if l >= ((bits / 2) as u8) { - break; - } - // get both sides of the byte boundary - v[i] = l - 1; - i += 1; - v[i] = l; - i += 1; - l *= 2; - } - - if bits != 8 { - // add the lower side of the middle boundary - v[i] = ((bits / 2) - 1) as u8; - i += 1; - } - - // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS - // boundary because of algorithms that split the high part up. We reverse the scaling - // as we go to Self::BITS. - let mid = i; - let mut j = 1; - loop { - v[i] = (bits as u8) - (v[mid - j]) - 1; - if j == mid { - break; - } - i += 1; - j += 1; - } - v -} - -macro_rules! int_impl_common { - ($ty:ty) => { - fn from_bool(b: bool) -> Self { - b as $ty - } - - fn logical_shr(self, other: u32) -> Self { - Self::from_unsigned(self.unsigned().wrapping_shr(other)) - } - - fn is_zero(self) -> bool { - self == Self::ZERO - } - - fn wrapping_neg(self) -> Self { - ::wrapping_neg(self) - } - - fn wrapping_add(self, other: Self) -> Self { - ::wrapping_add(self, other) - } - - fn wrapping_mul(self, other: Self) -> Self { - ::wrapping_mul(self, other) - } - - fn wrapping_sub(self, other: Self) -> Self { - ::wrapping_sub(self, other) - } - - fn wrapping_shl(self, other: u32) -> Self { - ::wrapping_shl(self, other) - } - - fn wrapping_shr(self, other: u32) -> Self { - ::wrapping_shr(self, other) - } - - fn rotate_left(self, other: u32) -> Self { - ::rotate_left(self, other) - } - - fn overflowing_add(self, other: Self) -> (Self, bool) { - ::overflowing_add(self, other) - } - - fn leading_zeros(self) -> u32 { - ::leading_zeros(self) - } - - fn ilog2(self) -> u32 { - ::ilog2(self) - } - }; -} - -macro_rules! int_impl { - ($ity:ty, $uty:ty) => { - impl MinInt for $uty { - type OtherSign = $ity; - type UnsignedInt = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $uty { - fn unsigned(self) -> $uty { - self - } - - // It makes writing macros easier if this is implemented for both signed and unsigned - #[allow(clippy::wrong_self_convention)] - fn from_unsigned(me: $uty) -> Self { - me - } - - fn abs_diff(self, other: Self) -> Self { - if self < other { - other.wrapping_sub(self) - } else { - self.wrapping_sub(other) - } - } - - int_impl_common!($uty); - } - - impl MinInt for $ity { - type OtherSign = $uty; - type UnsignedInt = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $ity { - fn unsigned(self) -> $uty { - self as $uty - } - - fn from_unsigned(me: $uty) -> Self { - me as $ity - } - - fn abs_diff(self, other: Self) -> $uty { - self.wrapping_sub(other).wrapping_abs() as $uty - } - - int_impl_common!($ity); - } - }; -} - -int_impl!(isize, usize); -int_impl!(i8, u8); -int_impl!(i16, u16); -int_impl!(i32, u32); -int_impl!(i64, u64); -int_impl!(i128, u128); - -public_test_dep! { -/// 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(crate) 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() - } -} -} - -public_test_dep! { -/// 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(crate) trait HInt: Int { - /// Integer that is double the bit width of the integer this trait is implemented for - type D: DInt + MinInt; - - /// 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 { - self.widen() << ::BITS - } - /// 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()) - } - } - )* - }; -} - -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 -); - -public_test_dep! { -/// Trait to express (possibly lossy) casting of integers -pub(crate) trait CastInto: Copy { - fn cast(self) -> T; -} - -pub(crate) trait CastFrom:Copy { - fn cast_from(value: T) -> Self; -} -} - -impl + Copy> CastFrom for T { - fn cast_from(value: U) -> Self { - value.cast() - } -} - -macro_rules! cast_into { - ($ty:ty) => { - cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); - }; - ($ty:ty; $($into:ty),*) => {$( - impl CastInto<$into> for $ty { - fn cast(self) -> $into { - self as $into - } - } - )*}; -} +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; -cast_into!(usize); -cast_into!(isize); -cast_into!(u8); -cast_into!(i8); -cast_into!(u16); -cast_into!(i16); -cast_into!(u32); -cast_into!(i32); -cast_into!(u64); -cast_into!(i64); -cast_into!(u128); -cast_into!(i128); +#[cfg(feature = "public-test-deps")] +pub use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; diff --git a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs index 330c6e4f80bb7..f5c6e50239a35 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs @@ -185,7 +185,6 @@ macro_rules! impl_delegate { }; } -public_test_dep! { /// Returns `n / d` and sets `*rem = n % d`. /// /// This specialization exists because: @@ -195,7 +194,7 @@ public_test_dep! { /// delegate algorithm strategy the only reasonably fast way to perform `u128` division. // used on SPARC #[allow(dead_code)] -pub(crate) fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { +pub fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { use super::*; let duo_lo = duo as u64; let duo_hi = (duo >> 64) as u64; @@ -316,4 +315,3 @@ pub(crate) fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { } } } -} diff --git a/library/compiler-builtins/src/int/trailing_zeros.rs b/library/compiler-builtins/src/int/trailing_zeros.rs index cea366b07549f..9878a16878e44 100644 --- a/library/compiler-builtins/src/int/trailing_zeros.rs +++ b/library/compiler-builtins/src/int/trailing_zeros.rs @@ -1,46 +1,52 @@ -use crate::int::{CastInto, Int}; +mod implementation { + use crate::int::{CastInto, Int}; -public_test_dep! { -/// Returns number of trailing binary zeros in `x`. -#[allow(dead_code)] -pub(crate) fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { - let mut x = x; - let mut r: u32 = 0; - let mut t: u32; + /// Returns number of trailing binary zeros in `x`. + #[allow(dead_code)] + pub fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { + let mut x = x; + let mut r: u32 = 0; + let mut t: u32; - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 - x >>= r; // remove 32 zero bits - } + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 + x >>= r; // remove 32 zero bits + } - if T::BITS >= 32 { - t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 - r += t; - x >>= t; // x = [0 - 0xFFFF] + higher garbage bits - } + if T::BITS >= 32 { + t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 + r += t; + x >>= t; // x = [0 - 0xFFFF] + higher garbage bits + } - const { assert!(T::BITS >= 16) }; - t = ((CastInto::::cast(x) == 0) as u32) << 3; - x >>= t; // x = [0 - 0xFF] + higher garbage bits - r += t; + const { assert!(T::BITS >= 16) }; + t = ((CastInto::::cast(x) == 0) as u32) << 3; + x >>= t; // x = [0 - 0xFF] + higher garbage bits + r += t; - let mut x: u8 = x.cast(); + let mut x: u8 = x.cast(); - t = (((x & 0x0F) == 0) as u32) << 2; - x >>= t; // x = [0 - 0xF] + higher garbage bits - r += t; + t = (((x & 0x0F) == 0) as u32) << 2; + x >>= t; // x = [0 - 0xF] + higher garbage bits + r += t; - t = (((x & 0x3) == 0) as u32) << 1; - x >>= t; // x = [0 - 0x3] + higher garbage bits - r += t; + t = (((x & 0x3) == 0) as u32) << 1; + x >>= t; // x = [0 - 0x3] + higher garbage bits + r += t; - x &= 3; + x &= 3; - r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) -} + r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) + } } +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use implementation::*; + +#[cfg(feature = "public-test-deps")] +pub use implementation::*; + intrinsics! { /// Returns the number of trailing binary zeros in `x` (32 bit version). pub extern "C" fn __ctzsi2(x: u32) -> usize { diff --git a/library/compiler-builtins/src/int/traits.rs b/library/compiler-builtins/src/int/traits.rs new file mode 100644 index 0000000000000..e9d8796273a61 --- /dev/null +++ b/library/compiler-builtins/src/int/traits.rs @@ -0,0 +1,402 @@ +use core::ops; + +/// Minimal integer implementations needed on all integer types, including wide integers. +#[allow(dead_code)] +pub trait MinInt: + Copy + + core::fmt::Debug + + ops::BitOr + + ops::Not + + ops::Shl +{ + /// Type with the same width but other signedness + type OtherSign: MinInt; + /// Unsigned version of Self + type UnsignedInt: MinInt; + + /// If `Self` is a signed integer + const SIGNED: bool; + + /// The bitwidth of the int type + const BITS: u32; + + const ZERO: Self; + const ONE: Self; + const MIN: Self; + const MAX: Self; +} + +/// Trait for some basic operations on integers +#[allow(dead_code)] +pub trait Int: + MinInt + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::SubAssign + + ops::BitAndAssign + + ops::BitOrAssign + + ops::BitXorAssign + + ops::ShlAssign + + ops::ShrAssign + + ops::Add + + ops::Sub + + ops::Mul + + ops::Div + + ops::Shr + + ops::BitXor + + ops::BitAnd +{ + /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing + /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, + /// 112,119,120,125,126,127]. + const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); + + /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. + const FUZZ_NUM: usize = { + let log2 = (::BITS - 1).count_ones() as usize; + if log2 == 3 { + // case for u8 + 6 + } else { + // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate + // boundaries. + 8 + (4 * (log2 - 4)) + } + }; + + fn unsigned(self) -> Self::UnsignedInt; + fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; + + fn from_bool(b: bool) -> Self; + + /// Prevents the need for excessive conversions between signed and unsigned + fn logical_shr(self, other: u32) -> Self; + + /// Absolute difference between two integers. + fn abs_diff(self, other: Self) -> Self::UnsignedInt; + + // copied from primitive integers, but put in a trait + fn is_zero(self) -> bool; + fn wrapping_neg(self) -> Self; + fn wrapping_add(self, other: Self) -> Self; + fn wrapping_mul(self, other: Self) -> Self; + fn wrapping_sub(self, other: Self) -> Self; + fn wrapping_shl(self, other: u32) -> Self; + fn wrapping_shr(self, other: u32) -> Self; + fn rotate_left(self, other: u32) -> Self; + fn overflowing_add(self, other: Self) -> (Self, bool); + fn leading_zeros(self) -> u32; + fn ilog2(self) -> u32; +} + +const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { + let mut v = [0u8; 20]; + v[0] = 0; + v[1] = 1; + v[2] = 2; // important for parity and the iX::MIN case when reversed + let mut i = 3; + + // No need for any more until the byte boundary, because there should be no algorithms + // that are sensitive to anything not next to byte boundaries after 2. We also scale + // in powers of two, which is important to prevent u128 corner tests from getting too + // big. + let mut l = 8; + loop { + if l >= ((bits / 2) as u8) { + break; + } + // get both sides of the byte boundary + v[i] = l - 1; + i += 1; + v[i] = l; + i += 1; + l *= 2; + } + + if bits != 8 { + // add the lower side of the middle boundary + v[i] = ((bits / 2) - 1) as u8; + i += 1; + } + + // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS + // boundary because of algorithms that split the high part up. We reverse the scaling + // as we go to Self::BITS. + let mid = i; + let mut j = 1; + loop { + v[i] = (bits as u8) - (v[mid - j]) - 1; + if j == mid { + break; + } + i += 1; + j += 1; + } + v +} + +macro_rules! int_impl_common { + ($ty:ty) => { + fn from_bool(b: bool) -> Self { + b as $ty + } + + fn logical_shr(self, other: u32) -> Self { + Self::from_unsigned(self.unsigned().wrapping_shr(other)) + } + + fn is_zero(self) -> bool { + self == Self::ZERO + } + + fn wrapping_neg(self) -> Self { + ::wrapping_neg(self) + } + + fn wrapping_add(self, other: Self) -> Self { + ::wrapping_add(self, other) + } + + fn wrapping_mul(self, other: Self) -> Self { + ::wrapping_mul(self, other) + } + + fn wrapping_sub(self, other: Self) -> Self { + ::wrapping_sub(self, other) + } + + fn wrapping_shl(self, other: u32) -> Self { + ::wrapping_shl(self, other) + } + + fn wrapping_shr(self, other: u32) -> Self { + ::wrapping_shr(self, other) + } + + fn rotate_left(self, other: u32) -> Self { + ::rotate_left(self, other) + } + + fn overflowing_add(self, other: Self) -> (Self, bool) { + ::overflowing_add(self, other) + } + + fn leading_zeros(self) -> u32 { + ::leading_zeros(self) + } + + fn ilog2(self) -> u32 { + ::ilog2(self) + } + }; +} + +macro_rules! int_impl { + ($ity:ty, $uty:ty) => { + impl MinInt for $uty { + type OtherSign = $ity; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $uty { + fn unsigned(self) -> $uty { + self + } + + // It makes writing macros easier if this is implemented for both signed and unsigned + #[allow(clippy::wrong_self_convention)] + fn from_unsigned(me: $uty) -> Self { + me + } + + fn abs_diff(self, other: Self) -> Self { + if self < other { + other.wrapping_sub(self) + } else { + self.wrapping_sub(other) + } + } + + int_impl_common!($uty); + } + + impl MinInt for $ity { + type OtherSign = $uty; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $ity { + fn unsigned(self) -> $uty { + self as $uty + } + + fn from_unsigned(me: $uty) -> Self { + me as $ity + } + + fn abs_diff(self, other: Self) -> $uty { + self.wrapping_sub(other).wrapping_abs() as $uty + } + + int_impl_common!($ity); + } + }; +} + +int_impl!(isize, usize); +int_impl!(i8, u8); +int_impl!(i16, u16); +int_impl!(i32, u32); +int_impl!(i64, u64); +int_impl!(i128, u128); + +/// 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; + + /// 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 { + self.widen() << ::BITS + } + /// 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()) + } + } + )* + }; +} + +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 +); + +/// Trait to express (possibly lossy) casting of integers +pub trait CastInto: Copy { + fn cast(self) -> T; +} + +pub trait CastFrom: Copy { + fn cast_from(value: T) -> Self; +} + +impl + Copy> CastFrom for T { + fn cast_from(value: U) -> Self { + value.cast() + } +} + +macro_rules! cast_into { + ($ty:ty) => { + cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); + }; + ($ty:ty; $($into:ty),*) => {$( + impl CastInto<$into> for $ty { + fn cast(self) -> $into { + self as $into + } + } + )*}; +} + +cast_into!(usize); +cast_into!(isize); +cast_into!(u8); +cast_into!(i8); +cast_into!(u16); +cast_into!(i16); +cast_into!(u32); +cast_into!(i32); +cast_into!(u64); +cast_into!(i64); +cast_into!(u128); +cast_into!(i128); diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 42c83ee55fb9f..9f951d5158509 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -1,21 +1,5 @@ //! Macros shared throughout the compiler-builtins implementation -/// Changes the visibility to `pub` if feature "public-test-deps" is set -#[cfg(not(feature = "public-test-deps"))] -macro_rules! public_test_dep { - ($(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*) => { - $(#[$($meta)*])* pub(crate) $ident $($tokens)* - }; -} - -/// Changes the visibility to `pub` if feature "public-test-deps" is set -#[cfg(feature = "public-test-deps")] -macro_rules! public_test_dep { - {$(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*} => { - $(#[$($meta)*])* pub $ident $($tokens)* - }; -} - /// The "main macro" used for defining intrinsics. /// /// The compiler-builtins library is super platform-specific with tons of crazy From c1a498db17b5eadc4f17048fb2f11aa8d578732f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 6 Aug 2024 17:16:03 +0200 Subject: [PATCH 1287/4206] Add `only-soft-floats` feature to prevent using any intrinsics or arch-specific code --- library/compiler-builtins/libm/Cargo.toml | 3 +++ .../libm/crates/compiler-builtins-smoke-test/Cargo.toml | 1 + library/compiler-builtins/libm/src/math/mod.rs | 2 +- library/compiler-builtins/libm/src/math/sqrt.rs | 4 ++-- library/compiler-builtins/libm/src/math/sqrtf.rs | 4 ++-- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index d33ca61cd4785..893a2e19d350d 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -23,6 +23,9 @@ unstable = [] # musl libc. musl-reference-tests = ['rand'] +# Used to prevent using any intrinsics or arch-specific code. +only-soft-floats = [] + [workspace] members = [ "crates/compiler-builtins-smoke-test", diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index 695b710ff30dd..ec48ca20601da 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -10,3 +10,4 @@ bench = false [features] unstable = [] checked = [] +only-soft-floats = [] diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 05ebb708c9c5c..04d3bbb620329 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -76,7 +76,7 @@ macro_rules! div { macro_rules! llvm_intrinsically_optimized { (#[cfg($($clause:tt)*)] $e:expr) => { - #[cfg(all(feature = "unstable", $($clause)*))] + #[cfg(all(feature = "unstable", not(feature = "only-soft-floats"), $($clause)*))] { if true { // thwart the dead code lint $e diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index baa0db9f8d14a..a0003cb05660c 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -92,7 +92,7 @@ pub fn sqrt(x: f64) -> f64 { } } } - #[cfg(target_feature = "sse2")] + #[cfg(all(target_feature = "sse2", not(feature = "only-soft-floats")))] { // Note: This path is unlikely since LLVM will usually have already // optimized sqrt calls into hardware instructions if sse2 is available, @@ -107,7 +107,7 @@ pub fn sqrt(x: f64) -> f64 { _mm_cvtsd_f64(m_sqrt) } } - #[cfg(not(target_feature = "sse2"))] + #[cfg(any(not(target_feature = "sse2"), feature = "only-soft-floats"))] { use core::num::Wrapping; diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 12bd60028eef7..0cef073ea3e21 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -27,7 +27,7 @@ pub fn sqrtf(x: f32) -> f32 { } } } - #[cfg(target_feature = "sse")] + #[cfg(all(target_feature = "sse", not(feature = "only-soft-floats")))] { // Note: This path is unlikely since LLVM will usually have already // optimized sqrt calls into hardware instructions if sse is available, @@ -42,7 +42,7 @@ pub fn sqrtf(x: f32) -> f32 { _mm_cvtss_f32(m_sqrt) } } - #[cfg(not(target_feature = "sse"))] + #[cfg(any(not(target_feature = "sse"), feature = "only-soft-floats"))] { const TINY: f32 = 1.0e-30; From 41df199623a12fbf79097e2d0aa5c7b1eeca2cb5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2024 21:48:51 +0000 Subject: [PATCH 1288/4206] chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 805b44cad0f94..6c07fd555ef9f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.115" +version = "0.1.116" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 14bd1e6ae194c6688b69184bde987dc31c3fe5aa Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 6 Aug 2024 22:11:19 -0400 Subject: [PATCH 1289/4206] Revert "Eliminate the use of `public_test_dep!`" --- library/compiler-builtins/src/float/mod.rs | 190 +++++++- library/compiler-builtins/src/float/traits.rs | 184 -------- .../src/int/leading_zeros.rs | 228 +++++----- library/compiler-builtins/src/int/mod.rs | 417 +++++++++++++++++- .../src/int/specialized_div_rem/delegate.rs | 4 +- .../src/int/trailing_zeros.rs | 70 ++- library/compiler-builtins/src/int/traits.rs | 402 ----------------- library/compiler-builtins/src/macros.rs | 16 + 8 files changed, 759 insertions(+), 752 deletions(-) delete mode 100644 library/compiler-builtins/src/float/traits.rs delete mode 100644 library/compiler-builtins/src/int/traits.rs diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 41b308626b392..8473732057a7d 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,3 +1,7 @@ +use core::ops; + +use crate::int::{DInt, Int, MinInt}; + pub mod add; pub mod cmp; pub mod conv; @@ -6,11 +10,187 @@ pub mod extend; pub mod mul; pub mod pow; pub mod sub; -pub(crate) mod traits; pub mod trunc; -#[cfg(not(feature = "public-test-deps"))] -pub(crate) use traits::{Float, HalfRep}; +/// Wrapper to extract the integer type half of the float's size +pub(crate) type HalfRep = <::Int as DInt>::H; + +public_test_dep! { +/// Trait for some basic operations on floats +#[allow(dead_code)] +pub(crate) 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; + + /// 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 SIGNIFICAND_BITS: u32; + + /// The bitwidth of the exponent + const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1; + + /// The maximum value of the exponent + const EXPONENT_MAX: u32 = (1 << Self::EXPONENT_BITS) - 1; + + /// The exponent bias value + const EXPONENT_BIAS: u32 = Self::EXPONENT_MAX >> 1; + + /// A mask for the sign bit + const SIGN_MASK: Self::Int; + + /// A mask for the significand + const SIGNIFICAND_MASK: Self::Int; + + /// The implicit bit of the float format + const IMPLICIT_BIT: Self::Int; + + /// A mask for the exponent + const EXPONENT_MASK: Self::Int; + + /// Returns `self` transmuted to `Self::Int` + fn repr(self) -> Self::Int; + + /// Returns `self` transmuted to `Self::SignedInt` + fn signed_repr(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 with 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_repr(a: Self::Int) -> Self; + + /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. + fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self; + + /// 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 SIGNIFICAND_BITS: u32 = $significand_bits; + + const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); + const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1; + const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; + const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); + + fn repr(self) -> Self::Int { + self.to_bits() + } + fn signed_repr(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.repr() & $ty::EXPONENT_MASK == $ty::EXPONENT_MASK + && x.repr() & $ty::SIGNIFICAND_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.repr() == rhs.repr() + } + } + fn is_sign_negative(self) -> bool { + self.is_sign_negative() + } + fn exp(self) -> Self::ExpInt { + ((self.to_bits() & Self::EXPONENT_MASK) >> Self::SIGNIFICAND_BITS) as Self::ExpInt + } + fn frac(self) -> Self::Int { + self.to_bits() & Self::SIGNIFICAND_MASK + } + fn imp_frac(self) -> Self::Int { + self.frac() | Self::IMPLICIT_BIT + } + fn from_repr(a: Self::Int) -> Self { + Self::from_bits(a) + } + fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { + Self::from_repr( + ((sign as Self::Int) << (Self::BITS - 1)) + | ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) + | (significand & Self::SIGNIFICAND_MASK), + ) + } + fn normalize(significand: Self::Int) -> (i32, Self::Int) { + let shift = significand + .leading_zeros() + .wrapping_sub((Self::Int::ONE << Self::SIGNIFICAND_BITS).leading_zeros()); + ( + 1i32.wrapping_sub(shift as i32), + significand << shift as Self::Int, + ) + } + fn is_subnormal(self) -> bool { + (self.repr() & Self::EXPONENT_MASK) == Self::Int::ZERO + } + } + }; +} -#[cfg(feature = "public-test-deps")] -pub use traits::{Float, HalfRep}; +#[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/src/float/traits.rs b/library/compiler-builtins/src/float/traits.rs deleted file mode 100644 index e57bd1b98259b..0000000000000 --- a/library/compiler-builtins/src/float/traits.rs +++ /dev/null @@ -1,184 +0,0 @@ -use core::ops; - -use crate::int::{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; - - /// 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 SIGNIFICAND_BITS: u32; - - /// The bitwidth of the exponent - const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1; - - /// The maximum value of the exponent - const EXPONENT_MAX: u32 = (1 << Self::EXPONENT_BITS) - 1; - - /// The exponent bias value - const EXPONENT_BIAS: u32 = Self::EXPONENT_MAX >> 1; - - /// A mask for the sign bit - const SIGN_MASK: Self::Int; - - /// A mask for the significand - const SIGNIFICAND_MASK: Self::Int; - - /// The implicit bit of the float format - const IMPLICIT_BIT: Self::Int; - - /// A mask for the exponent - const EXPONENT_MASK: Self::Int; - - /// Returns `self` transmuted to `Self::Int` - fn repr(self) -> Self::Int; - - /// Returns `self` transmuted to `Self::SignedInt` - fn signed_repr(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 with 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_repr(a: Self::Int) -> Self; - - /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. - fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self; - - /// 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 SIGNIFICAND_BITS: u32 = $significand_bits; - - const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); - const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1; - const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; - const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); - - fn repr(self) -> Self::Int { - self.to_bits() - } - fn signed_repr(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.repr() & $ty::EXPONENT_MASK == $ty::EXPONENT_MASK - && x.repr() & $ty::SIGNIFICAND_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.repr() == rhs.repr() - } - } - fn is_sign_negative(self) -> bool { - self.is_sign_negative() - } - fn exp(self) -> Self::ExpInt { - ((self.to_bits() & Self::EXPONENT_MASK) >> Self::SIGNIFICAND_BITS) as Self::ExpInt - } - fn frac(self) -> Self::Int { - self.to_bits() & Self::SIGNIFICAND_MASK - } - fn imp_frac(self) -> Self::Int { - self.frac() | Self::IMPLICIT_BIT - } - fn from_repr(a: Self::Int) -> Self { - Self::from_bits(a) - } - fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_repr( - ((sign as Self::Int) << (Self::BITS - 1)) - | ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) - | (significand & Self::SIGNIFICAND_MASK), - ) - } - fn normalize(significand: Self::Int) -> (i32, Self::Int) { - let shift = significand - .leading_zeros() - .wrapping_sub((Self::Int::ONE << Self::SIGNIFICAND_BITS).leading_zeros()); - ( - 1i32.wrapping_sub(shift as i32), - significand << shift as Self::Int, - ) - } - fn is_subnormal(self) -> bool { - (self.repr() & Self::EXPONENT_MASK) == Self::Int::ZERO - } - } - }; -} - -#[cfg(not(feature = "no-f16-f128"))] -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(not(feature = "no-f16-f128"))] -float_impl!(f128, u128, i128, i16, 128, 112); diff --git a/library/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/src/int/leading_zeros.rs index eede1ebe61cd2..1fee9fcf5d8fd 100644 --- a/library/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/src/int/leading_zeros.rs @@ -3,140 +3,136 @@ // adding a zero check at the beginning, but `__clzsi2` has a precondition that `x != 0`. // Compilers will insert the check for zero in cases where it is needed. -mod implementation { - use crate::int::{CastInto, Int}; +use crate::int::{CastInto, Int}; - /// Returns the number of leading binary zeros in `x`. - #[allow(dead_code)] - pub fn leading_zeros_default>(x: T) -> usize { - // The basic idea is to test if the higher bits of `x` are zero and bisect the number - // of leading zeros. It is possible for all branches of the bisection to use the same - // code path by conditionally shifting the higher parts down to let the next bisection - // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` - // and adding to the number of zeros, it is slightly faster to start with - // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, - // because it simplifies the final bisection step. - let mut x = x; - // the number of potential leading zeros - let mut z = T::BITS as usize; - // a temporary - let mut t: T; +public_test_dep! { +/// Returns the number of leading binary zeros in `x`. +#[allow(dead_code)] +pub(crate) fn leading_zeros_default>(x: T) -> usize { + // The basic idea is to test if the higher bits of `x` are zero and bisect the number + // of leading zeros. It is possible for all branches of the bisection to use the same + // code path by conditionally shifting the higher parts down to let the next bisection + // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` + // and adding to the number of zeros, it is slightly faster to start with + // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, + // because it simplifies the final bisection step. + let mut x = x; + // the number of potential leading zeros + let mut z = T::BITS as usize; + // a temporary + let mut t: T; - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - t = x >> 32; - if t != T::ZERO { - z -= 32; - x = t; - } - } - if T::BITS >= 32 { - t = x >> 16; - if t != T::ZERO { - z -= 16; - x = t; - } - } - const { assert!(T::BITS >= 16) }; - t = x >> 8; + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + t = x >> 32; if t != T::ZERO { - z -= 8; + z -= 32; x = t; } - t = x >> 4; - if t != T::ZERO { - z -= 4; - x = t; - } - t = x >> 2; + } + if T::BITS >= 32 { + t = x >> 16; if t != T::ZERO { - z -= 2; + z -= 16; x = t; } - // the last two bisections are combined into one conditional - t = x >> 1; - if t != T::ZERO { - z - 2 - } else { - z - x.cast() - } - - // We could potentially save a few cycles by using the LUT trick from - // "https://embeddedgurus.com/state-space/2014/09/-%20%20%20%20%20%20%20%20//%20fast-deterministic-and-portable-counting-leading-zeros/". - // However, 256 bytes for a LUT is too large for embedded use cases. We could remove - // the last 3 bisections and use this 16 byte LUT for the rest of the work: - //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; - //z -= LUT[x] as usize; - //z - // However, it ends up generating about the same number of instructions. When benchmarked - // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO - // execution effects. Changing to using a LUT and branching is risky for smaller cores. + } + const { assert!(T::BITS >= 16) }; + t = x >> 8; + if t != T::ZERO { + z -= 8; + x = t; + } + t = x >> 4; + if t != T::ZERO { + z -= 4; + x = t; + } + t = x >> 2; + if t != T::ZERO { + z -= 2; + x = t; + } + // the last two bisections are combined into one conditional + t = x >> 1; + if t != T::ZERO { + z - 2 + } else { + z - x.cast() } - // The above method does not compile well on RISC-V (because of the lack of predicated - // instructions), producing code with many branches or using an excessively long - // branchless solution. This method takes advantage of the set-if-less-than instruction on - // RISC-V that allows `(x >= power-of-two) as usize` to be branchless. + // We could potentially save a few cycles by using the LUT trick from + // "https://embeddedgurus.com/state-space/2014/09/+%20%20%20%20//%20fast-deterministic-and-portable-counting-leading-zeros/". + // However, 256 bytes for a LUT is too large for embedded use cases. We could remove + // the last 3 bisections and use this 16 byte LUT for the rest of the work: + //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; + //z -= LUT[x] as usize; + //z + // However, it ends up generating about the same number of instructions. When benchmarked + // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO + // execution effects. Changing to using a LUT and branching is risky for smaller cores. +} +} - /// Returns the number of leading binary zeros in `x`. - #[allow(dead_code)] - pub fn leading_zeros_riscv>(x: T) -> usize { - let mut x = x; - // the number of potential leading zeros - let mut z = T::BITS; - // a temporary - let mut t: u32; +// The above method does not compile well on RISC-V (because of the lack of predicated +// instructions), producing code with many branches or using an excessively long +// branchless solution. This method takes advantage of the set-if-less-than instruction on +// RISC-V that allows `(x >= power-of-two) as usize` to be branchless. - // RISC-V does not have a set-if-greater-than-or-equal instruction and - // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is - // still the most optimal method. A conditional set can only be turned into a single - // immediate instruction if `x` is compared with an immediate `imm` (that can fit into - // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the - // right). If we try to save an instruction by using `x < imm` for each bisection, we - // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, - // but the immediate will never fit into 12 bits and never save an instruction. - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise - // `t` is set to 0. - t = ((x >= (T::ONE << 32)) as u32) << 5; - // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the - // next step to process. - x >>= t; - // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential - // leading zeros - z -= t; - } - if T::BITS >= 32 { - t = ((x >= (T::ONE << 16)) as u32) << 4; - x >>= t; - z -= t; - } - const { assert!(T::BITS >= 16) }; - t = ((x >= (T::ONE << 8)) as u32) << 3; - x >>= t; - z -= t; - t = ((x >= (T::ONE << 4)) as u32) << 2; - x >>= t; - z -= t; - t = ((x >= (T::ONE << 2)) as u32) << 1; +public_test_dep! { +/// Returns the number of leading binary zeros in `x`. +#[allow(dead_code)] +pub(crate) fn leading_zeros_riscv>(x: T) -> usize { + let mut x = x; + // the number of potential leading zeros + let mut z = T::BITS; + // a temporary + let mut t: u32; + + // RISC-V does not have a set-if-greater-than-or-equal instruction and + // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is + // still the most optimal method. A conditional set can only be turned into a single + // immediate instruction if `x` is compared with an immediate `imm` (that can fit into + // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the + // right). If we try to save an instruction by using `x < imm` for each bisection, we + // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, + // but the immediate will never fit into 12 bits and never save an instruction. + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise + // `t` is set to 0. + t = ((x >= (T::ONE << 32)) as u32) << 5; + // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the + // next step to process. x >>= t; + // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential + // leading zeros z -= t; - t = (x >= (T::ONE << 1)) as u32; + } + if T::BITS >= 32 { + t = ((x >= (T::ONE << 16)) as u32) << 4; x >>= t; z -= t; - // All bits except the LSB are guaranteed to be zero for this final bisection step. - // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. - z as usize - x.cast() } + const { assert!(T::BITS >= 16) }; + t = ((x >= (T::ONE << 8)) as u32) << 3; + x >>= t; + z -= t; + t = ((x >= (T::ONE << 4)) as u32) << 2; + x >>= t; + z -= t; + t = ((x >= (T::ONE << 2)) as u32) << 1; + x >>= t; + z -= t; + t = (x >= (T::ONE << 1)) as u32; + x >>= t; + z -= t; + // All bits except the LSB are guaranteed to be zero for this final bisection step. + // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. + z as usize - x.cast() +} } - -#[cfg(not(feature = "public-test-deps"))] -pub(crate) use implementation::*; - -#[cfg(feature = "public-test-deps")] -pub use implementation::*; intrinsics! { /// Returns the number of leading binary zeros in `x` diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index a0d992e136d02..5f56c6b6ee135 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -1,4 +1,6 @@ -pub(crate) mod specialized_div_rem; +use core::ops; + +mod specialized_div_rem; pub mod addsub; mod big; @@ -8,13 +10,416 @@ 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 = "public-test-deps"))] -pub(crate) use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; +public_test_dep! { +/// Minimal integer implementations needed on all integer types, including wide integers. +#[allow(dead_code)] +pub(crate) trait MinInt: Copy + + core::fmt::Debug + + ops::BitOr + + ops::Not + + ops::Shl +{ + + /// Type with the same width but other signedness + type OtherSign: MinInt; + /// Unsigned version of Self + type UnsignedInt: MinInt; + + /// If `Self` is a signed integer + const SIGNED: bool; + + /// The bitwidth of the int type + const BITS: u32; + + const ZERO: Self; + const ONE: Self; + const MIN: Self; + const MAX: Self; +} +} + +public_test_dep! { +/// Trait for some basic operations on integers +#[allow(dead_code)] +pub(crate) trait Int: MinInt + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::SubAssign + + ops::BitAndAssign + + ops::BitOrAssign + + ops::BitXorAssign + + ops::ShlAssign + + ops::ShrAssign + + ops::Add + + ops::Sub + + ops::Mul + + ops::Div + + ops::Shr + + ops::BitXor + + ops::BitAnd +{ + /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing + /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, + /// 112,119,120,125,126,127]. + const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); + + /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. + const FUZZ_NUM: usize = { + let log2 = (::BITS - 1).count_ones() as usize; + if log2 == 3 { + // case for u8 + 6 + } else { + // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate + // boundaries. + 8 + (4 * (log2 - 4)) + } + }; + + fn unsigned(self) -> Self::UnsignedInt; + fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; + + fn from_bool(b: bool) -> Self; + + /// Prevents the need for excessive conversions between signed and unsigned + fn logical_shr(self, other: u32) -> Self; + + /// Absolute difference between two integers. + fn abs_diff(self, other: Self) -> Self::UnsignedInt; + + // copied from primitive integers, but put in a trait + fn is_zero(self) -> bool; + fn wrapping_neg(self) -> Self; + fn wrapping_add(self, other: Self) -> Self; + fn wrapping_mul(self, other: Self) -> Self; + fn wrapping_sub(self, other: Self) -> Self; + fn wrapping_shl(self, other: u32) -> Self; + fn wrapping_shr(self, other: u32) -> Self; + fn rotate_left(self, other: u32) -> Self; + fn overflowing_add(self, other: Self) -> (Self, bool); + fn leading_zeros(self) -> u32; + fn ilog2(self) -> u32; +} +} + +pub(crate) const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { + let mut v = [0u8; 20]; + v[0] = 0; + v[1] = 1; + v[2] = 2; // important for parity and the iX::MIN case when reversed + let mut i = 3; + + // No need for any more until the byte boundary, because there should be no algorithms + // that are sensitive to anything not next to byte boundaries after 2. We also scale + // in powers of two, which is important to prevent u128 corner tests from getting too + // big. + let mut l = 8; + loop { + if l >= ((bits / 2) as u8) { + break; + } + // get both sides of the byte boundary + v[i] = l - 1; + i += 1; + v[i] = l; + i += 1; + l *= 2; + } + + if bits != 8 { + // add the lower side of the middle boundary + v[i] = ((bits / 2) - 1) as u8; + i += 1; + } + + // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS + // boundary because of algorithms that split the high part up. We reverse the scaling + // as we go to Self::BITS. + let mid = i; + let mut j = 1; + loop { + v[i] = (bits as u8) - (v[mid - j]) - 1; + if j == mid { + break; + } + i += 1; + j += 1; + } + v +} + +macro_rules! int_impl_common { + ($ty:ty) => { + fn from_bool(b: bool) -> Self { + b as $ty + } + + fn logical_shr(self, other: u32) -> Self { + Self::from_unsigned(self.unsigned().wrapping_shr(other)) + } + + fn is_zero(self) -> bool { + self == Self::ZERO + } + + fn wrapping_neg(self) -> Self { + ::wrapping_neg(self) + } + + fn wrapping_add(self, other: Self) -> Self { + ::wrapping_add(self, other) + } + + fn wrapping_mul(self, other: Self) -> Self { + ::wrapping_mul(self, other) + } + + fn wrapping_sub(self, other: Self) -> Self { + ::wrapping_sub(self, other) + } + + fn wrapping_shl(self, other: u32) -> Self { + ::wrapping_shl(self, other) + } + + fn wrapping_shr(self, other: u32) -> Self { + ::wrapping_shr(self, other) + } + + fn rotate_left(self, other: u32) -> Self { + ::rotate_left(self, other) + } + + fn overflowing_add(self, other: Self) -> (Self, bool) { + ::overflowing_add(self, other) + } + + fn leading_zeros(self) -> u32 { + ::leading_zeros(self) + } + + fn ilog2(self) -> u32 { + ::ilog2(self) + } + }; +} + +macro_rules! int_impl { + ($ity:ty, $uty:ty) => { + impl MinInt for $uty { + type OtherSign = $ity; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $uty { + fn unsigned(self) -> $uty { + self + } + + // It makes writing macros easier if this is implemented for both signed and unsigned + #[allow(clippy::wrong_self_convention)] + fn from_unsigned(me: $uty) -> Self { + me + } + + fn abs_diff(self, other: Self) -> Self { + if self < other { + other.wrapping_sub(self) + } else { + self.wrapping_sub(other) + } + } + + int_impl_common!($uty); + } + + impl MinInt for $ity { + type OtherSign = $uty; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $ity { + fn unsigned(self) -> $uty { + self as $uty + } + + fn from_unsigned(me: $uty) -> Self { + me as $ity + } + + fn abs_diff(self, other: Self) -> $uty { + self.wrapping_sub(other).wrapping_abs() as $uty + } + + int_impl_common!($ity); + } + }; +} + +int_impl!(isize, usize); +int_impl!(i8, u8); +int_impl!(i16, u16); +int_impl!(i32, u32); +int_impl!(i64, u64); +int_impl!(i128, u128); + +public_test_dep! { +/// 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(crate) 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() + } +} +} + +public_test_dep! { +/// 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(crate) trait HInt: Int { + /// Integer that is double the bit width of the integer this trait is implemented for + type D: DInt + MinInt; + + /// 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 { + self.widen() << ::BITS + } + /// 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()) + } + } + )* + }; +} + +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 +); + +public_test_dep! { +/// Trait to express (possibly lossy) casting of integers +pub(crate) trait CastInto: Copy { + fn cast(self) -> T; +} + +pub(crate) trait CastFrom:Copy { + fn cast_from(value: T) -> Self; +} +} + +impl + Copy> CastFrom for T { + fn cast_from(value: U) -> Self { + value.cast() + } +} + +macro_rules! cast_into { + ($ty:ty) => { + cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); + }; + ($ty:ty; $($into:ty),*) => {$( + impl CastInto<$into> for $ty { + fn cast(self) -> $into { + self as $into + } + } + )*}; +} -#[cfg(feature = "public-test-deps")] -pub use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; +cast_into!(usize); +cast_into!(isize); +cast_into!(u8); +cast_into!(i8); +cast_into!(u16); +cast_into!(i16); +cast_into!(u32); +cast_into!(i32); +cast_into!(u64); +cast_into!(i64); +cast_into!(u128); +cast_into!(i128); diff --git a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs index f5c6e50239a35..330c6e4f80bb7 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs @@ -185,6 +185,7 @@ macro_rules! impl_delegate { }; } +public_test_dep! { /// Returns `n / d` and sets `*rem = n % d`. /// /// This specialization exists because: @@ -194,7 +195,7 @@ macro_rules! impl_delegate { /// delegate algorithm strategy the only reasonably fast way to perform `u128` division. // used on SPARC #[allow(dead_code)] -pub fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { +pub(crate) fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { use super::*; let duo_lo = duo as u64; let duo_hi = (duo >> 64) as u64; @@ -315,3 +316,4 @@ pub fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { } } } +} diff --git a/library/compiler-builtins/src/int/trailing_zeros.rs b/library/compiler-builtins/src/int/trailing_zeros.rs index 9878a16878e44..cea366b07549f 100644 --- a/library/compiler-builtins/src/int/trailing_zeros.rs +++ b/library/compiler-builtins/src/int/trailing_zeros.rs @@ -1,51 +1,45 @@ -mod implementation { - use crate::int::{CastInto, Int}; +use crate::int::{CastInto, Int}; - /// Returns number of trailing binary zeros in `x`. - #[allow(dead_code)] - pub fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { - let mut x = x; - let mut r: u32 = 0; - let mut t: u32; +public_test_dep! { +/// Returns number of trailing binary zeros in `x`. +#[allow(dead_code)] +pub(crate) fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { + let mut x = x; + let mut r: u32 = 0; + let mut t: u32; - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 - x >>= r; // remove 32 zero bits - } - - if T::BITS >= 32 { - t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 - r += t; - x >>= t; // x = [0 - 0xFFFF] + higher garbage bits - } + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 + x >>= r; // remove 32 zero bits + } - const { assert!(T::BITS >= 16) }; - t = ((CastInto::::cast(x) == 0) as u32) << 3; - x >>= t; // x = [0 - 0xFF] + higher garbage bits + if T::BITS >= 32 { + t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 r += t; + x >>= t; // x = [0 - 0xFFFF] + higher garbage bits + } - let mut x: u8 = x.cast(); - - t = (((x & 0x0F) == 0) as u32) << 2; - x >>= t; // x = [0 - 0xF] + higher garbage bits - r += t; + const { assert!(T::BITS >= 16) }; + t = ((CastInto::::cast(x) == 0) as u32) << 3; + x >>= t; // x = [0 - 0xFF] + higher garbage bits + r += t; - t = (((x & 0x3) == 0) as u32) << 1; - x >>= t; // x = [0 - 0x3] + higher garbage bits - r += t; + let mut x: u8 = x.cast(); - x &= 3; + t = (((x & 0x0F) == 0) as u32) << 2; + x >>= t; // x = [0 - 0xF] + higher garbage bits + r += t; - r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) - } -} + t = (((x & 0x3) == 0) as u32) << 1; + x >>= t; // x = [0 - 0x3] + higher garbage bits + r += t; -#[cfg(not(feature = "public-test-deps"))] -pub(crate) use implementation::*; + x &= 3; -#[cfg(feature = "public-test-deps")] -pub use implementation::*; + r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) +} +} intrinsics! { /// Returns the number of trailing binary zeros in `x` (32 bit version). diff --git a/library/compiler-builtins/src/int/traits.rs b/library/compiler-builtins/src/int/traits.rs deleted file mode 100644 index e9d8796273a61..0000000000000 --- a/library/compiler-builtins/src/int/traits.rs +++ /dev/null @@ -1,402 +0,0 @@ -use core::ops; - -/// Minimal integer implementations needed on all integer types, including wide integers. -#[allow(dead_code)] -pub trait MinInt: - Copy - + core::fmt::Debug - + ops::BitOr - + ops::Not - + ops::Shl -{ - /// Type with the same width but other signedness - type OtherSign: MinInt; - /// Unsigned version of Self - type UnsignedInt: MinInt; - - /// If `Self` is a signed integer - const SIGNED: bool; - - /// The bitwidth of the int type - const BITS: u32; - - const ZERO: Self; - const ONE: Self; - const MIN: Self; - const MAX: Self; -} - -/// Trait for some basic operations on integers -#[allow(dead_code)] -pub trait Int: - MinInt - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::SubAssign - + ops::BitAndAssign - + ops::BitOrAssign - + ops::BitXorAssign - + ops::ShlAssign - + ops::ShrAssign - + ops::Add - + ops::Sub - + ops::Mul - + ops::Div - + ops::Shr - + ops::BitXor - + ops::BitAnd -{ - /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing - /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, - /// 112,119,120,125,126,127]. - const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); - - /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. - const FUZZ_NUM: usize = { - let log2 = (::BITS - 1).count_ones() as usize; - if log2 == 3 { - // case for u8 - 6 - } else { - // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate - // boundaries. - 8 + (4 * (log2 - 4)) - } - }; - - fn unsigned(self) -> Self::UnsignedInt; - fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; - - fn from_bool(b: bool) -> Self; - - /// Prevents the need for excessive conversions between signed and unsigned - fn logical_shr(self, other: u32) -> Self; - - /// Absolute difference between two integers. - fn abs_diff(self, other: Self) -> Self::UnsignedInt; - - // copied from primitive integers, but put in a trait - fn is_zero(self) -> bool; - fn wrapping_neg(self) -> Self; - fn wrapping_add(self, other: Self) -> Self; - fn wrapping_mul(self, other: Self) -> Self; - fn wrapping_sub(self, other: Self) -> Self; - fn wrapping_shl(self, other: u32) -> Self; - fn wrapping_shr(self, other: u32) -> Self; - fn rotate_left(self, other: u32) -> Self; - fn overflowing_add(self, other: Self) -> (Self, bool); - fn leading_zeros(self) -> u32; - fn ilog2(self) -> u32; -} - -const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { - let mut v = [0u8; 20]; - v[0] = 0; - v[1] = 1; - v[2] = 2; // important for parity and the iX::MIN case when reversed - let mut i = 3; - - // No need for any more until the byte boundary, because there should be no algorithms - // that are sensitive to anything not next to byte boundaries after 2. We also scale - // in powers of two, which is important to prevent u128 corner tests from getting too - // big. - let mut l = 8; - loop { - if l >= ((bits / 2) as u8) { - break; - } - // get both sides of the byte boundary - v[i] = l - 1; - i += 1; - v[i] = l; - i += 1; - l *= 2; - } - - if bits != 8 { - // add the lower side of the middle boundary - v[i] = ((bits / 2) - 1) as u8; - i += 1; - } - - // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS - // boundary because of algorithms that split the high part up. We reverse the scaling - // as we go to Self::BITS. - let mid = i; - let mut j = 1; - loop { - v[i] = (bits as u8) - (v[mid - j]) - 1; - if j == mid { - break; - } - i += 1; - j += 1; - } - v -} - -macro_rules! int_impl_common { - ($ty:ty) => { - fn from_bool(b: bool) -> Self { - b as $ty - } - - fn logical_shr(self, other: u32) -> Self { - Self::from_unsigned(self.unsigned().wrapping_shr(other)) - } - - fn is_zero(self) -> bool { - self == Self::ZERO - } - - fn wrapping_neg(self) -> Self { - ::wrapping_neg(self) - } - - fn wrapping_add(self, other: Self) -> Self { - ::wrapping_add(self, other) - } - - fn wrapping_mul(self, other: Self) -> Self { - ::wrapping_mul(self, other) - } - - fn wrapping_sub(self, other: Self) -> Self { - ::wrapping_sub(self, other) - } - - fn wrapping_shl(self, other: u32) -> Self { - ::wrapping_shl(self, other) - } - - fn wrapping_shr(self, other: u32) -> Self { - ::wrapping_shr(self, other) - } - - fn rotate_left(self, other: u32) -> Self { - ::rotate_left(self, other) - } - - fn overflowing_add(self, other: Self) -> (Self, bool) { - ::overflowing_add(self, other) - } - - fn leading_zeros(self) -> u32 { - ::leading_zeros(self) - } - - fn ilog2(self) -> u32 { - ::ilog2(self) - } - }; -} - -macro_rules! int_impl { - ($ity:ty, $uty:ty) => { - impl MinInt for $uty { - type OtherSign = $ity; - type UnsignedInt = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $uty { - fn unsigned(self) -> $uty { - self - } - - // It makes writing macros easier if this is implemented for both signed and unsigned - #[allow(clippy::wrong_self_convention)] - fn from_unsigned(me: $uty) -> Self { - me - } - - fn abs_diff(self, other: Self) -> Self { - if self < other { - other.wrapping_sub(self) - } else { - self.wrapping_sub(other) - } - } - - int_impl_common!($uty); - } - - impl MinInt for $ity { - type OtherSign = $uty; - type UnsignedInt = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $ity { - fn unsigned(self) -> $uty { - self as $uty - } - - fn from_unsigned(me: $uty) -> Self { - me as $ity - } - - fn abs_diff(self, other: Self) -> $uty { - self.wrapping_sub(other).wrapping_abs() as $uty - } - - int_impl_common!($ity); - } - }; -} - -int_impl!(isize, usize); -int_impl!(i8, u8); -int_impl!(i16, u16); -int_impl!(i32, u32); -int_impl!(i64, u64); -int_impl!(i128, u128); - -/// 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; - - /// 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 { - self.widen() << ::BITS - } - /// 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()) - } - } - )* - }; -} - -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 -); - -/// Trait to express (possibly lossy) casting of integers -pub trait CastInto: Copy { - fn cast(self) -> T; -} - -pub trait CastFrom: Copy { - fn cast_from(value: T) -> Self; -} - -impl + Copy> CastFrom for T { - fn cast_from(value: U) -> Self { - value.cast() - } -} - -macro_rules! cast_into { - ($ty:ty) => { - cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); - }; - ($ty:ty; $($into:ty),*) => {$( - impl CastInto<$into> for $ty { - fn cast(self) -> $into { - self as $into - } - } - )*}; -} - -cast_into!(usize); -cast_into!(isize); -cast_into!(u8); -cast_into!(i8); -cast_into!(u16); -cast_into!(i16); -cast_into!(u32); -cast_into!(i32); -cast_into!(u64); -cast_into!(i64); -cast_into!(u128); -cast_into!(i128); diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 9f951d5158509..42c83ee55fb9f 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -1,5 +1,21 @@ //! Macros shared throughout the compiler-builtins implementation +/// Changes the visibility to `pub` if feature "public-test-deps" is set +#[cfg(not(feature = "public-test-deps"))] +macro_rules! public_test_dep { + ($(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*) => { + $(#[$($meta)*])* pub(crate) $ident $($tokens)* + }; +} + +/// Changes the visibility to `pub` if feature "public-test-deps" is set +#[cfg(feature = "public-test-deps")] +macro_rules! public_test_dep { + {$(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*} => { + $(#[$($meta)*])* pub $ident $($tokens)* + }; +} + /// The "main macro" used for defining intrinsics. /// /// The compiler-builtins library is super platform-specific with tons of crazy From 6565fbb704a65394a8515d98f52eed5e4bc12b5e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 7 Aug 2024 02:18:44 +0000 Subject: [PATCH 1290/4206] chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 6c07fd555ef9f..e0a4abc638f50 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.116" +version = "0.1.117" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 7bc2291ac555e8e635d8aeae3d09a0ae39a96542 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 7 Aug 2024 11:29:47 +0200 Subject: [PATCH 1291/4206] Rename `only-soft-floats` feature into `force-soft-floats` --- library/compiler-builtins/libm/Cargo.toml | 2 +- .../libm/crates/compiler-builtins-smoke-test/Cargo.toml | 2 +- library/compiler-builtins/libm/src/math/mod.rs | 2 +- library/compiler-builtins/libm/src/math/sqrt.rs | 4 ++-- library/compiler-builtins/libm/src/math/sqrtf.rs | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 893a2e19d350d..c2388083b611d 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -24,7 +24,7 @@ unstable = [] musl-reference-tests = ['rand'] # Used to prevent using any intrinsics or arch-specific code. -only-soft-floats = [] +force-soft-floats = [] [workspace] members = [ diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index ec48ca20601da..481d386a4b221 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -10,4 +10,4 @@ bench = false [features] unstable = [] checked = [] -only-soft-floats = [] +force-soft-floats = [] diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 04d3bbb620329..a56532dddc141 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -76,7 +76,7 @@ macro_rules! div { macro_rules! llvm_intrinsically_optimized { (#[cfg($($clause:tt)*)] $e:expr) => { - #[cfg(all(feature = "unstable", not(feature = "only-soft-floats"), $($clause)*))] + #[cfg(all(feature = "unstable", not(feature = "force-soft-floats"), $($clause)*))] { if true { // thwart the dead code lint $e diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index a0003cb05660c..66cb7659c2dbe 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -92,7 +92,7 @@ pub fn sqrt(x: f64) -> f64 { } } } - #[cfg(all(target_feature = "sse2", not(feature = "only-soft-floats")))] + #[cfg(all(target_feature = "sse2", not(feature = "force-soft-floats")))] { // Note: This path is unlikely since LLVM will usually have already // optimized sqrt calls into hardware instructions if sse2 is available, @@ -107,7 +107,7 @@ pub fn sqrt(x: f64) -> f64 { _mm_cvtsd_f64(m_sqrt) } } - #[cfg(any(not(target_feature = "sse2"), feature = "only-soft-floats"))] + #[cfg(any(not(target_feature = "sse2"), feature = "force-soft-floats"))] { use core::num::Wrapping; diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 0cef073ea3e21..16cbb2f977018 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -27,7 +27,7 @@ pub fn sqrtf(x: f32) -> f32 { } } } - #[cfg(all(target_feature = "sse", not(feature = "only-soft-floats")))] + #[cfg(all(target_feature = "sse", not(feature = "force-soft-floats")))] { // Note: This path is unlikely since LLVM will usually have already // optimized sqrt calls into hardware instructions if sse is available, @@ -42,7 +42,7 @@ pub fn sqrtf(x: f32) -> f32 { _mm_cvtss_f32(m_sqrt) } } - #[cfg(any(not(target_feature = "sse"), feature = "only-soft-floats"))] + #[cfg(any(not(target_feature = "sse"), feature = "force-soft-floats"))] { const TINY: f32 = 1.0e-30; From 281c14d4fc5a1a88511a521f69c0ce66e72c2589 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Aug 2024 14:00:59 +0200 Subject: [PATCH 1292/4206] Update `libm` submodule --- library/compiler-builtins/libm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 279e5f6abe0a2..300edb32520b1 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 279e5f6abe0a2ca9066962d9ec894f0df1f417ac +Subproject commit 300edb32520b1673e16d2411a0e2e6273959eb46 From 145143a0b7c03afbdeb02d7853bc8edd005c9213 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Aug 2024 14:09:07 +0200 Subject: [PATCH 1293/4206] Activate `force-soft-floats` feature in `build.rs` --- library/compiler-builtins/build.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index bbae9e2862f14..93e323e6b2362 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -51,8 +51,9 @@ fn main() { println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display()); // Activate libm's unstable features to make full use of Nightly. - println!("cargo::rustc-check-cfg=cfg(feature, values(\"unstable\"))"); + println!("cargo::rustc-check-cfg=cfg(feature, values(\"unstable\", \"force-soft-floats\"))"); println!("cargo:rustc-cfg=feature=\"unstable\""); + println!("cargo:rustc-cfg=feature=\"force-soft-floats\""); // Emscripten's runtime includes all the builtins if target.os == "emscripten" { From 4860f2246016d87d329fdf5a498a255712ff4cae Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 8 Aug 2024 12:17:09 +0000 Subject: [PATCH 1294/4206] chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index e0a4abc638f50..49b315779ec86 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.117" +version = "0.1.118" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 5dad727bdc9aa69145cd48c08c42b8e878a3c84b Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Sun, 11 Aug 2024 11:36:25 +0200 Subject: [PATCH 1295/4206] Configure `f16` and `f128` support for WebAssembly --- library/compiler-builtins/build.rs | 2 ++ library/compiler-builtins/testcrate/build.rs | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 93e323e6b2362..56716b906aba0 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -283,6 +283,8 @@ fn configure_f16_f128(target: &Target) { "powerpc64" if &target.os == "aix" => (true, false), // `f128` crashes "sparc" | "sparcv9" => (true, false), + // `f16` miscompiles + "wasm32" | "wasm64" => (false, true), // Most everything else works as of LLVM 19 _ => (true, true), }; diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 8c441de8a9586..74d74559ef67f 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -54,8 +54,9 @@ fn main() { || target.starts_with("i586-") || target.contains("windows-") // Linking says "error: function signature mismatch: __extendhfsf2" and seems to - // think the signature is either `(i32) -> f32` or `(f32) -> f32` - || target.starts_with("wasm32-") + // think the signature is either `(i32) -> f32` or `(f32) -> f32`. See + // . + || target.starts_with("wasm") { features.insert(Feature::NoSysF16); features.insert(Feature::NoSysF16F128Convert); From 13cc7daf05d75b9e54f32db649132da682cc7bbe Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Mon, 12 Aug 2024 08:08:41 +0200 Subject: [PATCH 1296/4206] Fix CI for targets that conditionally disable `f16` or `f128` support --- library/compiler-builtins/build.rs | 83 +----------------- library/compiler-builtins/configure.rs | 86 +++++++++++++++++++ .../testcrate/benches/float_add.rs | 18 +++- .../testcrate/benches/float_cmp.rs | 28 +++--- .../testcrate/benches/float_conv.rs | 1 - .../testcrate/benches/float_div.rs | 2 - .../testcrate/benches/float_extend.rs | 49 ++++++----- .../testcrate/benches/float_mul.rs | 18 +++- .../testcrate/benches/float_sub.rs | 18 +++- .../testcrate/benches/float_trunc.rs | 51 +++++++---- library/compiler-builtins/testcrate/build.rs | 45 ++++++---- .../compiler-builtins/testcrate/src/bench.rs | 6 +- .../compiler-builtins/testcrate/src/lib.rs | 4 +- .../testcrate/tests/addsub.rs | 7 +- .../compiler-builtins/testcrate/tests/cmp.rs | 5 +- .../compiler-builtins/testcrate/tests/conv.rs | 14 +-- .../compiler-builtins/testcrate/tests/mul.rs | 7 +- 17 files changed, 260 insertions(+), 182 deletions(-) create mode 100644 library/compiler-builtins/configure.rs diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 56716b906aba0..894508b54ab97 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -1,44 +1,8 @@ use std::{collections::BTreeMap, env, path::PathBuf, sync::atomic::Ordering}; -#[allow(dead_code)] -struct Target { - triple: String, - os: String, - arch: String, - vendor: String, - env: String, - pointer_width: u8, - little_endian: bool, - features: Vec, -} - -impl Target { - fn from_env() -> Self { - let little_endian = match env::var("CARGO_CFG_TARGET_ENDIAN").unwrap().as_str() { - "little" => true, - "big" => false, - x => panic!("unknown endian {x}"), - }; +mod configure; - Self { - triple: env::var("TARGET").unwrap(), - os: env::var("CARGO_CFG_TARGET_OS").unwrap(), - 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") - .unwrap() - .parse() - .unwrap(), - little_endian, - features: env::var("CARGO_CFG_TARGET_FEATURE") - .unwrap_or_default() - .split(",") - .map(ToOwned::to_owned) - .collect(), - } - } -} +use configure::{configure_f16_f128, Target}; fn main() { println!("cargo:rerun-if-changed=build.rs"); @@ -261,49 +225,6 @@ fn configure_check_cfg() { println!("cargo::rustc-check-cfg=cfg(assert_no_panic)"); } -/// Configure whether or not `f16` and `f128` support should be enabled. -fn configure_f16_f128(target: &Target) { - // Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means - // that the backend will not crash when using these types. This does not mean that the - // backend does the right thing, or that the platform doesn't have ABI bugs. - // - // We do this here rather than in `rust-lang/rust` because configuring via cargo features is - // not straightforward. - // - // Original source of this list: - // - let (f16_ok, f128_ok) = match target.arch.as_str() { - // `f16` and `f128` both crash - "arm64ec" => (false, false), - // `f16` crashes - "s390x" => (false, true), - // `f128` crashes - "mips64" | "mips64r6" => (true, false), - // `f128` crashes - "powerpc64" if &target.os == "aix" => (true, false), - // `f128` crashes - "sparc" | "sparcv9" => (true, false), - // `f16` miscompiles - "wasm32" | "wasm64" => (false, true), - // Most everything else works as of LLVM 19 - _ => (true, true), - }; - - // If the feature is set, disable these types. - let disable_both = env::var_os("CARGO_FEATURE_NO_F16_F128").is_some(); - - println!("cargo::rustc-check-cfg=cfg(f16_enabled)"); - println!("cargo::rustc-check-cfg=cfg(f128_enabled)"); - - if f16_ok && !disable_both { - println!("cargo::rustc-cfg=f16_enabled"); - } - - if f128_ok && !disable_both { - println!("cargo::rustc-cfg=f128_enabled"); - } -} - #[cfg(feature = "c")] mod c { use std::collections::{BTreeMap, HashSet}; diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs new file mode 100644 index 0000000000000..676c88f3a4f59 --- /dev/null +++ b/library/compiler-builtins/configure.rs @@ -0,0 +1,86 @@ +// Configuration that is shared between `compiler_builtins` and `testcrate`. + +use std::env; + +#[allow(dead_code)] +pub struct Target { + pub triple: String, + pub os: String, + pub arch: String, + pub vendor: String, + pub env: String, + pub pointer_width: u8, + pub little_endian: bool, + pub features: Vec, +} + +impl Target { + pub fn from_env() -> Self { + let little_endian = match env::var("CARGO_CFG_TARGET_ENDIAN").unwrap().as_str() { + "little" => true, + "big" => false, + x => panic!("unknown endian {x}"), + }; + + Self { + triple: env::var("TARGET").unwrap(), + os: env::var("CARGO_CFG_TARGET_OS").unwrap(), + 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") + .unwrap() + .parse() + .unwrap(), + little_endian, + features: env::var("CARGO_CFG_TARGET_FEATURE") + .unwrap_or_default() + .split(",") + .map(ToOwned::to_owned) + .collect(), + } + } +} + +/// Configure whether or not `f16` and `f128` support should be enabled. +pub fn configure_f16_f128(target: &Target) { + // Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means + // that the backend will not crash when using these types. This does not mean that the + // backend does the right thing, or that the platform doesn't have ABI bugs. + // + // We do this here rather than in `rust-lang/rust` because configuring via cargo features is + // not straightforward. + // + // Original source of this list: + // + let (f16_ok, f128_ok) = match target.arch.as_str() { + // `f16` and `f128` both crash + "arm64ec" => (false, false), + // `f16` crashes + "s390x" => (false, true), + // `f128` crashes + "mips64" | "mips64r6" => (true, false), + // `f128` crashes + "powerpc64" if &target.os == "aix" => (true, false), + // `f128` crashes + "sparc" | "sparcv9" => (true, false), + // `f16` miscompiles + "wasm32" | "wasm64" => (false, true), + // Most everything else works as of LLVM 19 + _ => (true, true), + }; + + // If the feature is set, disable these types. + let disable_both = env::var_os("CARGO_FEATURE_NO_F16_F128").is_some(); + + println!("cargo::rustc-check-cfg=cfg(f16_enabled)"); + println!("cargo::rustc-check-cfg=cfg(f128_enabled)"); + + if f16_ok && !disable_both { + println!("cargo::rustc-cfg=f16_enabled"); + } + + if f128_ok && !disable_both { + println!("cargo::rustc-cfg=f128_enabled"); + } +} diff --git a/library/compiler-builtins/testcrate/benches/float_add.rs b/library/compiler-builtins/testcrate/benches/float_add.rs index eef1ecc57c16d..3311e7b5b299d 100644 --- a/library/compiler-builtins/testcrate/benches/float_add.rs +++ b/library/compiler-builtins/testcrate/benches/float_add.rs @@ -1,7 +1,7 @@ -#![feature(f128)] +#![cfg_attr(f128_enabled, feature(f128))] use compiler_builtins::float::add; -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{criterion_main, Criterion}; use testcrate::float_bench; float_bench! { @@ -66,6 +66,7 @@ float_bench! { ], } +#[cfg(f128_enabled)] float_bench! { name: add_f128, sig: (a: f128, b: f128) -> f128, @@ -77,5 +78,16 @@ float_bench! { asm: [] } -criterion_group!(float_add, add_f32, add_f64, add_f128); +pub fn float_add() { + let mut criterion = Criterion::default().configure_from_args(); + + add_f32(&mut criterion); + add_f64(&mut criterion); + + #[cfg(f128_enabled)] + { + add_f128(&mut criterion); + } +} + criterion_main!(float_add); diff --git a/library/compiler-builtins/testcrate/benches/float_cmp.rs b/library/compiler-builtins/testcrate/benches/float_cmp.rs index 641eb0ac5d444..400c09b427a53 100644 --- a/library/compiler-builtins/testcrate/benches/float_cmp.rs +++ b/library/compiler-builtins/testcrate/benches/float_cmp.rs @@ -1,6 +1,6 @@ -#![feature(f128)] +#![cfg_attr(f128_enabled, feature(f128))] -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{criterion_main, Criterion}; use testcrate::float_bench; use compiler_builtins::float::cmp; @@ -190,13 +190,19 @@ float_bench! { asm: [] } -criterion_group!( - float_cmp, - cmp_f32_gt, - cmp_f32_unord, - cmp_f64_gt, - cmp_f64_unord, - cmp_f128_gt, - cmp_f128_unord -); +pub fn float_cmp() { + let mut criterion = Criterion::default().configure_from_args(); + + cmp_f32_gt(&mut criterion); + cmp_f32_unord(&mut criterion); + cmp_f64_gt(&mut criterion); + cmp_f64_unord(&mut criterion); + + #[cfg(f128_enabled)] + { + cmp_f128_gt(&mut criterion); + cmp_f128_unord(&mut criterion); + } +} + criterion_main!(float_cmp); diff --git a/library/compiler-builtins/testcrate/benches/float_conv.rs b/library/compiler-builtins/testcrate/benches/float_conv.rs index bbd3a06851d46..de2043b04f859 100644 --- a/library/compiler-builtins/testcrate/benches/float_conv.rs +++ b/library/compiler-builtins/testcrate/benches/float_conv.rs @@ -1,4 +1,3 @@ -#![feature(f128)] #![allow(improper_ctypes)] use compiler_builtins::float::conv; diff --git a/library/compiler-builtins/testcrate/benches/float_div.rs b/library/compiler-builtins/testcrate/benches/float_div.rs index e679f8ccccbe3..6ba439b042068 100644 --- a/library/compiler-builtins/testcrate/benches/float_div.rs +++ b/library/compiler-builtins/testcrate/benches/float_div.rs @@ -1,5 +1,3 @@ -#![feature(f128)] - use compiler_builtins::float::div; use criterion::{criterion_group, criterion_main, Criterion}; use testcrate::float_bench; diff --git a/library/compiler-builtins/testcrate/benches/float_extend.rs b/library/compiler-builtins/testcrate/benches/float_extend.rs index bf136f49a0bd7..a9563741a68e0 100644 --- a/library/compiler-builtins/testcrate/benches/float_extend.rs +++ b/library/compiler-builtins/testcrate/benches/float_extend.rs @@ -1,11 +1,12 @@ #![allow(unused_variables)] // "unused" f16 registers -#![feature(f128)] -#![feature(f16)] +#![cfg_attr(f128_enabled, feature(f128))] +#![cfg_attr(f16_enabled, feature(f16))] use compiler_builtins::float::extend; -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{criterion_main, Criterion}; use testcrate::float_bench; +#[cfg(f16_enabled)] float_bench! { name: extend_f16_f32, sig: (a: f16) -> f32, @@ -28,6 +29,7 @@ float_bench! { ], } +#[cfg(all(f16_enabled, f128_enabled))] float_bench! { name: extend_f16_f128, sig: (a: f16) -> f128, @@ -60,6 +62,7 @@ float_bench! { ], } +#[cfg(f128_enabled)] float_bench! { name: extend_f32_f128, sig: (a: f32) -> f128, @@ -71,6 +74,7 @@ float_bench! { asm: [], } +#[cfg(f128_enabled)] float_bench! { name: extend_f64_f128, sig: (a: f64) -> f128, @@ -82,23 +86,28 @@ float_bench! { asm: [], } -#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] -criterion_group!( - float_extend, - extend_f16_f32, - extend_f16_f128, - extend_f32_f64, - extend_f32_f128, - extend_f64_f128, -); +pub fn float_extend() { + let mut criterion = Criterion::default().configure_from_args(); -// FIXME(#655): `f16` tests disabled until we can bootstrap symbols -#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] -criterion_group!( - float_extend, - extend_f32_f64, - extend_f32_f128, - extend_f64_f128, -); + // FIXME(#655): `f16` tests disabled until we can bootstrap symbols + #[cfg(f16_enabled)] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + { + extend_f16_f32(&mut criterion); + + #[cfg(f128_enabled)] + { + extend_f16_f128(&mut criterion); + } + } + + extend_f32_f64(&mut criterion); + + #[cfg(f128_enabled)] + { + extend_f32_f128(&mut criterion); + extend_f64_f128(&mut criterion); + } +} criterion_main!(float_extend); diff --git a/library/compiler-builtins/testcrate/benches/float_mul.rs b/library/compiler-builtins/testcrate/benches/float_mul.rs index efa32b28563e5..6e30b7866c715 100644 --- a/library/compiler-builtins/testcrate/benches/float_mul.rs +++ b/library/compiler-builtins/testcrate/benches/float_mul.rs @@ -1,7 +1,7 @@ -#![feature(f128)] +#![cfg_attr(f128_enabled, feature(f128))] use compiler_builtins::float::mul; -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{criterion_main, Criterion}; use testcrate::float_bench; float_bench! { @@ -66,6 +66,7 @@ float_bench! { ], } +#[cfg(f128_enabled)] float_bench! { name: mul_f128, sig: (a: f128, b: f128) -> f128, @@ -77,5 +78,16 @@ float_bench! { asm: [] } -criterion_group!(float_mul, mul_f32, mul_f64, mul_f128); +pub fn float_mul() { + let mut criterion = Criterion::default().configure_from_args(); + + mul_f32(&mut criterion); + mul_f64(&mut criterion); + + #[cfg(f128_enabled)] + { + mul_f128(&mut criterion); + } +} + criterion_main!(float_mul); diff --git a/library/compiler-builtins/testcrate/benches/float_sub.rs b/library/compiler-builtins/testcrate/benches/float_sub.rs index 6d87604aac713..cdb678eef052f 100644 --- a/library/compiler-builtins/testcrate/benches/float_sub.rs +++ b/library/compiler-builtins/testcrate/benches/float_sub.rs @@ -1,7 +1,7 @@ -#![feature(f128)] +#![cfg_attr(f128_enabled, feature(f128))] use compiler_builtins::float::sub; -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{criterion_main, Criterion}; use testcrate::float_bench; float_bench! { @@ -66,6 +66,7 @@ float_bench! { ], } +#[cfg(f128_enabled)] float_bench! { name: sub_f128, sig: (a: f128, b: f128) -> f128, @@ -77,5 +78,16 @@ float_bench! { asm: [] } -criterion_group!(float_sub, sub_f32, sub_f64, sub_f128); +pub fn float_sub() { + let mut criterion = Criterion::default().configure_from_args(); + + sub_f32(&mut criterion); + sub_f64(&mut criterion); + + #[cfg(f128_enabled)] + { + sub_f128(&mut criterion); + } +} + criterion_main!(float_sub); diff --git a/library/compiler-builtins/testcrate/benches/float_trunc.rs b/library/compiler-builtins/testcrate/benches/float_trunc.rs index 74b43dfc833c2..8d874e4b2e0b3 100644 --- a/library/compiler-builtins/testcrate/benches/float_trunc.rs +++ b/library/compiler-builtins/testcrate/benches/float_trunc.rs @@ -1,10 +1,11 @@ -#![feature(f128)] -#![feature(f16)] +#![cfg_attr(f128_enabled, feature(f128))] +#![cfg_attr(f16_enabled, feature(f16))] use compiler_builtins::float::trunc; -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{criterion_main, Criterion}; use testcrate::float_bench; +#[cfg(f16_enabled)] float_bench! { name: trunc_f32_f16, sig: (a: f32) -> f16, @@ -27,6 +28,7 @@ float_bench! { ], } +#[cfg(f16_enabled)] float_bench! { name: trunc_f64_f16, sig: (a: f64) -> f16, @@ -82,6 +84,7 @@ float_bench! { ], } +#[cfg(all(f16_enabled, f128_enabled))] float_bench! { name: trunc_f128_f16, sig: (a: f128) -> f16, @@ -93,6 +96,7 @@ float_bench! { asm: [], } +#[cfg(f128_enabled)] float_bench! { name: trunc_f128_f32, sig: (a: f128) -> f32, @@ -104,6 +108,7 @@ float_bench! { asm: [], } +#[cfg(f128_enabled)] float_bench! { name: trunc_f128_f64, sig: (a: f128) -> f64, @@ -115,19 +120,31 @@ float_bench! { asm: [], } -#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] -criterion_group!( - float_trunc, - trunc_f32_f16, - trunc_f64_f16, - trunc_f64_f32, - trunc_f128_f16, - trunc_f128_f32, - trunc_f128_f64, -); - -// FIXME(#655): `f16` tests disabled until we can bootstrap symbols -#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] -criterion_group!(float_trunc, trunc_f64_f32, trunc_f128_f32, trunc_f128_f64,); +pub fn float_trunc() { + let mut criterion = Criterion::default().configure_from_args(); + + // FIXME(#655): `f16` tests disabled until we can bootstrap symbols + #[cfg(f16_enabled)] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + { + trunc_f32_f16(&mut criterion); + trunc_f64_f16(&mut criterion); + } + + trunc_f64_f32(&mut criterion); + + #[cfg(f128_enabled)] + { + // FIXME(#655): `f16` tests disabled until we can bootstrap symbols + #[cfg(f16_enabled)] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + { + trunc_f128_f16(&mut criterion); + } + + trunc_f128_f32(&mut criterion); + trunc_f128_f64(&mut criterion); + } +} criterion_main!(float_trunc); diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 74d74559ef67f..fde4e5b56f30d 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -1,4 +1,4 @@ -use std::{collections::HashSet, env}; +use std::collections::HashSet; /// Features to enable #[derive(Debug, PartialEq, Eq, Hash)] @@ -9,35 +9,39 @@ enum Feature { NoSysF16F128Convert, } +mod builtins_configure { + include!("../configure.rs"); +} + fn main() { - let target = env::var("TARGET").unwrap(); + let target = builtins_configure::Target::from_env(); let mut features = HashSet::new(); // These platforms do not have f128 symbols available in their system libraries, so // skip related tests. - if target.starts_with("arm-") - || target.contains("apple-darwin") - || target.contains("windows-msvc") + if target.arch == "arm" + || target.vendor == "apple" + || target.env == "msvc" // GCC and LLVM disagree on the ABI of `f16` and `f128` with MinGW. See // . - || target.contains("windows-gnu") + || (target.os == "windows" && target.env == "gnu") // FIXME(llvm): There is an ABI incompatibility between GCC and Clang on 32-bit x86. // See . - || target.starts_with("i686") + || target.arch == "i686" // 32-bit PowerPC and 64-bit LE gets code generated that Qemu cannot handle. See // . - || target.starts_with("powerpc-") - || target.starts_with("powerpc64le-") + || target.arch == "powerpc" + || target.arch == "powerpc64le" // FIXME: We get different results from the builtin functions. See // . - || target.starts_with("powerpc64-") + || target.arch == "powerpc64" { features.insert(Feature::NoSysF128); features.insert(Feature::NoSysF128IntConvert); features.insert(Feature::NoSysF16F128Convert); } - if target.starts_with("i586") || target.starts_with("i686") { + if target.arch == "i586" || target.arch == "i686" { // 32-bit x86 does not have `__fixunstfti`/`__fixtfti` but does have everything else features.insert(Feature::NoSysF128IntConvert); // FIXME: 32-bit x86 has a bug in `f128 -> f16` system libraries @@ -46,17 +50,18 @@ 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.starts_with("aarch64-") && target.contains("linux")) - || target.starts_with("arm") - || target.starts_with("powerpc-") - || target.starts_with("powerpc64-") - || target.starts_with("powerpc64le-") - || target.starts_with("i586-") - || target.contains("windows-") + if (target.arch == "aarch64" && target.os == "linux") + || target.arch.starts_with("arm") + || target.arch == "powerpc" + || target.arch == "powerpc64" + || target.arch == "powerpc64le" + || target.arch == "i586" + || 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.starts_with("wasm") + || target.arch == "wasm32" + || target.arch == "wasm64" { features.insert(Feature::NoSysF16); features.insert(Feature::NoSysF16F128Convert); @@ -78,4 +83,6 @@ fn main() { println!("cargo:warning={warning}"); println!("cargo:rustc-cfg=feature=\"{name}\""); } + + builtins_configure::configure_f16_f128(&target); } diff --git a/library/compiler-builtins/testcrate/src/bench.rs b/library/compiler-builtins/testcrate/src/bench.rs index 5ab9bac8715de..1d571a6cf3b5b 100644 --- a/library/compiler-builtins/testcrate/src/bench.rs +++ b/library/compiler-builtins/testcrate/src/bench.rs @@ -350,9 +350,11 @@ macro_rules! impl_testio { } } -#[cfg(not(feature = "no-f16-f128"))] -impl_testio!(float f16, f128); +#[cfg(f16_enabled)] +impl_testio!(float f16); impl_testio!(float f32, f64); +#[cfg(f128_enabled)] +impl_testio!(float f128); impl_testio!(int i16, i32, i64, i128); impl_testio!(int u16, u32, u64, u128); impl_testio!((float, int)(f32, i32)); diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index 5458c9ab6d05b..cc9e73938fbc2 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -13,8 +13,8 @@ //! Some floating point tests are disabled for specific architectures, because they do not have //! correct rounding. #![no_std] -#![cfg_attr(not(feature = "no-f16-f128"), feature(f128))] -#![cfg_attr(not(feature = "no-f16-f128"), feature(f16))] +#![cfg_attr(f128_enabled, feature(f128))] +#![cfg_attr(f16_enabled, feature(f16))] #![feature(isqrt)] pub mod bench; diff --git a/library/compiler-builtins/testcrate/tests/addsub.rs b/library/compiler-builtins/testcrate/tests/addsub.rs index f21f61ff679a1..1ba2df74191b8 100644 --- a/library/compiler-builtins/testcrate/tests/addsub.rs +++ b/library/compiler-builtins/testcrate/tests/addsub.rs @@ -1,6 +1,5 @@ #![allow(unused_macros)] -#![feature(f128)] -#![feature(f16)] +#![cfg_attr(f128_enabled, feature(f128))] use testcrate::*; @@ -120,7 +119,7 @@ mod float_addsub { } } -#[cfg(not(feature = "no-f16-f128"))] +#[cfg(f128_enabled)] #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] mod float_addsub_f128 { @@ -131,7 +130,7 @@ mod float_addsub_f128 { } } -#[cfg(not(feature = "no-f16-f128"))] +#[cfg(f128_enabled)] #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] mod float_addsub_f128_ppc { use super::*; diff --git a/library/compiler-builtins/testcrate/tests/cmp.rs b/library/compiler-builtins/testcrate/tests/cmp.rs index e8a0eb165c3fd..7e973e7e5ed42 100644 --- a/library/compiler-builtins/testcrate/tests/cmp.rs +++ b/library/compiler-builtins/testcrate/tests/cmp.rs @@ -1,7 +1,6 @@ #![allow(unused_macros)] #![allow(unreachable_code)] -#![feature(f128)] -#![feature(f16)] +#![cfg_attr(f128_enabled, feature(f128))] #[cfg(not(target_arch = "powerpc64"))] use testcrate::*; @@ -94,7 +93,7 @@ mod float_comparisons { } #[test] - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] fn cmp_f128() { #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] use compiler_builtins::float::cmp::{ diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index e394183cf57e0..ce1f64e67d103 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -1,5 +1,5 @@ -#![cfg_attr(not(feature = "no-f16-f128"), feature(f16))] -#![cfg_attr(not(feature = "no-f16-f128"), feature(f128))] +#![cfg_attr(f128_enabled, feature(f128))] +#![cfg_attr(f16_enabled, feature(f16))] // makes configuration easier #![allow(unused_macros)] #![allow(unused_imports)] @@ -176,7 +176,7 @@ mod f_to_i { } #[test] - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] fn f128_to_int() { #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] use compiler_builtins::float::conv::{ @@ -264,7 +264,7 @@ mod extend { f32 => f64, Single => Double, __extendsfdf2vfp, all(); } - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(all(f16_enabled, f128_enabled))] #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] f_to_f! { extend, @@ -275,7 +275,7 @@ mod extend { f64 => f128, Double => Quad, __extenddftf2, not(feature = "no-sys-f128"); } - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] f_to_f! { extend, @@ -299,7 +299,7 @@ mod trunc { f64 => f32, Double => Single, __truncdfsf2vfp, all(); } - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(all(f16_enabled, f128_enabled))] #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] f_to_f! { trunc, @@ -310,7 +310,7 @@ mod trunc { f128 => f64, Quad => Double, __trunctfdf2, not(feature = "no-sys-f128"); } - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] f_to_f! { trunc, diff --git a/library/compiler-builtins/testcrate/tests/mul.rs b/library/compiler-builtins/testcrate/tests/mul.rs index 90144bb06355d..867622fdf07a9 100644 --- a/library/compiler-builtins/testcrate/tests/mul.rs +++ b/library/compiler-builtins/testcrate/tests/mul.rs @@ -1,6 +1,5 @@ #![allow(unused_macros)] -#![feature(f128)] -#![feature(f16)] +#![cfg_attr(f128_enabled, feature(f128))] use testcrate::*; @@ -131,7 +130,7 @@ mod float_mul { } } -#[cfg(not(feature = "no-f16-f128"))] +#[cfg(f128_enabled)] #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] mod float_mul_f128 { @@ -145,7 +144,7 @@ mod float_mul_f128 { } } -#[cfg(not(feature = "no-f16-f128"))] +#[cfg(f128_enabled)] #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] mod float_mul_f128_ppc { use super::*; From 3869b3962c830aafa3f1ca39e46c685023dc7619 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 12 Aug 2024 16:42:17 +0000 Subject: [PATCH 1297/4206] chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 49b315779ec86..44cc3994bd3ef 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.118" +version = "0.1.119" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 18cbc52ee63946fb21b8c29fa64b6c17ecd61c30 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Mon, 12 Aug 2024 19:45:28 +0200 Subject: [PATCH 1298/4206] Add `configure.rs` to the `include` list --- library/compiler-builtins/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 44cc3994bd3ef..8f2d8a5698a43 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -15,6 +15,7 @@ if necessary! include = [ '/Cargo.toml', '/build.rs', + '/configure.rs', '/src/*', '/examples/*', '/LICENSE.txt', From 1666f8684d7cd274c24ef5dc3f09a3e192a463ba Mon Sep 17 00:00:00 2001 From: David Carlier Date: Thu, 15 Aug 2024 13:01:43 +0100 Subject: [PATCH 1299/4206] proposal to expand (a subset of) linux specific socket capabilities. to stabilise the quickack part for now, tcp_deferaccept had been added at a later stage. --- library/std/src/os/android/net.rs | 2 +- library/std/src/os/linux/net.rs | 2 +- library/std/src/os/net/linux_ext/mod.rs | 2 +- library/std/src/os/net/linux_ext/tcp.rs | 12 +++++------- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/library/std/src/os/android/net.rs b/library/std/src/os/android/net.rs index 960a304fd0c8d..3a459ed8aeea1 100644 --- a/library/std/src/os/android/net.rs +++ b/library/std/src/os/android/net.rs @@ -6,5 +6,5 @@ pub use crate::os::net::linux_ext::addr::SocketAddrExt; #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub use crate::os::net::linux_ext::socket::UnixSocketExt; -#[unstable(feature = "tcp_quickack", issue = "96256")] +#[stable(feature = "tcp_quickack", since = "CURRENT_RUSTC_VERSION")] pub use crate::os::net::linux_ext::tcp::TcpStreamExt; diff --git a/library/std/src/os/linux/net.rs b/library/std/src/os/linux/net.rs index 1de120c8fd366..c14aba13bd153 100644 --- a/library/std/src/os/linux/net.rs +++ b/library/std/src/os/linux/net.rs @@ -6,5 +6,5 @@ pub use crate::os::net::linux_ext::addr::SocketAddrExt; #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub use crate::os::net::linux_ext::socket::UnixSocketExt; -#[unstable(feature = "tcp_quickack", issue = "96256")] +#[stable(feature = "tcp_quickack", since = "CURRENT_RUSTC_VERSION")] pub use crate::os::net::linux_ext::tcp::TcpStreamExt; diff --git a/library/std/src/os/net/linux_ext/mod.rs b/library/std/src/os/net/linux_ext/mod.rs index d0979640c32ea..bb9dfae2623e1 100644 --- a/library/std/src/os/net/linux_ext/mod.rs +++ b/library/std/src/os/net/linux_ext/mod.rs @@ -8,7 +8,7 @@ pub(crate) mod addr; #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub(crate) mod socket; -#[unstable(feature = "tcp_quickack", issue = "96256")] +#[stable(feature = "tcp_quickack", since = "CURRENT_RUSTC_VERSION")] pub(crate) mod tcp; #[cfg(test)] diff --git a/library/std/src/os/net/linux_ext/tcp.rs b/library/std/src/os/net/linux_ext/tcp.rs index c8d012962d45a..7761b7a5b857f 100644 --- a/library/std/src/os/net/linux_ext/tcp.rs +++ b/library/std/src/os/net/linux_ext/tcp.rs @@ -9,7 +9,7 @@ use crate::{io, net}; /// Os-specific extensions for [`TcpStream`] /// /// [`TcpStream`]: net::TcpStream -#[unstable(feature = "tcp_quickack", issue = "96256")] +#[stable(feature = "tcp_quickack", since = "CURRENT_RUSTC_VERSION")] pub trait TcpStreamExt: Sealed { /// Enable or disable `TCP_QUICKACK`. /// @@ -23,7 +23,6 @@ pub trait TcpStreamExt: Sealed { /// # Examples /// /// ```no_run - /// #![feature(tcp_quickack)] /// use std::net::TcpStream; /// use std::os::linux::net::TcpStreamExt; /// @@ -31,7 +30,7 @@ pub trait TcpStreamExt: Sealed { /// .expect("Couldn't connect to the server..."); /// stream.set_quickack(true).expect("set_quickack call failed"); /// ``` - #[unstable(feature = "tcp_quickack", issue = "96256")] + #[stable(feature = "tcp_quickack", since = "CURRENT_RUSTC_VERSION")] fn set_quickack(&self, quickack: bool) -> io::Result<()>; /// Gets the value of the `TCP_QUICKACK` option on this socket. @@ -41,7 +40,6 @@ pub trait TcpStreamExt: Sealed { /// # Examples /// /// ```no_run - /// #![feature(tcp_quickack)] /// use std::net::TcpStream; /// use std::os::linux::net::TcpStreamExt; /// @@ -50,7 +48,7 @@ pub trait TcpStreamExt: Sealed { /// stream.set_quickack(true).expect("set_quickack call failed"); /// assert_eq!(stream.quickack().unwrap_or(false), true); /// ``` - #[unstable(feature = "tcp_quickack", issue = "96256")] + #[stable(feature = "tcp_quickack", since = "CURRENT_RUSTC_VERSION")] fn quickack(&self) -> io::Result; /// A socket listener will be awakened solely when data arrives. @@ -99,10 +97,10 @@ pub trait TcpStreamExt: Sealed { fn deferaccept(&self) -> io::Result; } -#[unstable(feature = "tcp_quickack", issue = "96256")] +#[stable(feature = "tcp_quickack", since = "CURRENT_RUSTC_VERSION")] impl Sealed for net::TcpStream {} -#[unstable(feature = "tcp_quickack", issue = "96256")] +#[stable(feature = "tcp_quickack", since = "CURRENT_RUSTC_VERSION")] impl TcpStreamExt for net::TcpStream { fn set_quickack(&self, quickack: bool) -> io::Result<()> { self.as_inner().as_inner().set_quickack(quickack) From db9debf096e31322eb7a03a8ea67229ea69eced1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 19 Aug 2024 07:04:07 -0500 Subject: [PATCH 1300/4206] Apply fixes to `build.rs` files Make the following changes: - Add `rerun-if-changed` to the new `configure.rs`, it seems this was causing incorrect caching. - Change from matching `i686` to `x86`. The target triple starts with `i686` so that is what we were checking before, but the architecture is `x86`. This change should have been made when we added `struct Target`, update it now instead. --- library/compiler-builtins/build.rs | 6 ++++-- library/compiler-builtins/configure.rs | 6 ++++++ library/compiler-builtins/testcrate/build.rs | 12 +++++++----- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 894508b54ab97..5ccff76e7c53c 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -5,7 +5,9 @@ mod configure; use configure::{configure_f16_f128, Target}; fn main() { - println!("cargo:rerun-if-changed=build.rs"); + println!("cargo::rerun-if-changed=build.rs"); + println!("cargo::rerun-if-changed=configure.rs"); + let target = Target::from_env(); let cwd = env::current_dir().unwrap(); @@ -46,7 +48,7 @@ fn main() { // These targets have hardware unaligned access support. println!("cargo::rustc-check-cfg=cfg(feature, values(\"mem-unaligned\"))"); if target.arch.contains("x86_64") - || target.arch.contains("i686") + || target.arch.contains("x86") || target.arch.contains("aarch64") || target.arch.contains("bpf") { diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs index 676c88f3a4f59..e23c0e839359a 100644 --- a/library/compiler-builtins/configure.rs +++ b/library/compiler-builtins/configure.rs @@ -2,6 +2,7 @@ use std::env; +#[derive(Debug)] #[allow(dead_code)] pub struct Target { pub triple: String, @@ -40,6 +41,11 @@ impl Target { .collect(), } } + + #[allow(dead_code)] + pub fn has_feature(&self, feature: &str) -> bool { + self.features.iter().any(|f| f == feature) + } } /// Configure whether or not `f16` and `f128` support should be enabled. diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index fde4e5b56f30d..6205c7ac6fecb 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -14,6 +14,8 @@ mod builtins_configure { } fn main() { + println!("cargo::rerun-if-changed=../configure.rs"); + let target = builtins_configure::Target::from_env(); let mut features = HashSet::new(); @@ -27,7 +29,7 @@ fn main() { || (target.os == "windows" && target.env == "gnu") // FIXME(llvm): There is an ABI incompatibility between GCC and Clang on 32-bit x86. // See . - || target.arch == "i686" + || target.arch == "x86" // 32-bit PowerPC and 64-bit LE gets code generated that Qemu cannot handle. See // . || target.arch == "powerpc" @@ -41,7 +43,7 @@ fn main() { features.insert(Feature::NoSysF16F128Convert); } - if target.arch == "i586" || target.arch == "i686" { + if target.arch == "x86" { // 32-bit x86 does not have `__fixunstfti`/`__fixtfti` but does have everything else features.insert(Feature::NoSysF128IntConvert); // FIXME: 32-bit x86 has a bug in `f128 -> f16` system libraries @@ -55,7 +57,7 @@ fn main() { || target.arch == "powerpc" || target.arch == "powerpc64" || target.arch == "powerpc64le" - || target.arch == "i586" + || (target.arch == "x86" && !target.has_feature("sse")) || target.os == "windows" // Linking says "error: function signature mismatch: __extendhfsf2" and seems to // think the signature is either `(i32) -> f32` or `(f32) -> f32`. See @@ -72,11 +74,11 @@ fn main() { Feature::NoSysF128 => ("no-sys-f128", "using apfloat fallback for f128"), Feature::NoSysF128IntConvert => ( "no-sys-f128-int-convert", - "using apfloat fallback for f128 to int conversions", + "using apfloat fallback for f128 <-> int conversions", ), Feature::NoSysF16F128Convert => ( "no-sys-f16-f128-convert", - "skipping using apfloat fallback for f16 <-> f128 conversions", + "using apfloat fallback for f16 <-> f128 conversions", ), Feature::NoSysF16 => ("no-sys-f16", "using apfloat fallback for f16"), }; From b71531e64eb1c3085d1570177c160ad35f86eae7 Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Thu, 22 Aug 2024 10:59:06 +0800 Subject: [PATCH 1301/4206] Fix weak linkage on windows and apple platforms There were some issues regarding windows and apple platform, we were exporting symbols that are already provided by the compiler but weren't marked as `weak` which resulted in conflicted symbols in the linking process. Initially, we didn't add `weak` because we thought it is not supported on windows and apple platforms, but it looks like its only not supported on windows-gnu platforms Signed-off-by: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> --- library/compiler-builtins/src/macros.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 42c83ee55fb9f..18535d633f780 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -256,7 +256,7 @@ macro_rules! intrinsics { #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64", not(feature = "mangled-names")))] mod $name { #[no_mangle] - #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] + #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] extern $abi fn $name( $($argname: $ty),* ) -> $crate::macros::win64_128bit_abi_hack::U64x2 { @@ -298,7 +298,7 @@ macro_rules! intrinsics { #[cfg(all(target_arch = "arm", not(feature = "mangled-names")))] mod $name { #[no_mangle] - #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] + #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] $(#[$($attr)*])* extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) @@ -308,7 +308,7 @@ macro_rules! intrinsics { #[cfg(all(target_arch = "arm", not(feature = "mangled-names")))] mod $alias { #[no_mangle] - #[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")] + #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] $(#[$($attr)*])* extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) @@ -375,7 +375,7 @@ macro_rules! intrinsics { mod $name { $(#[$($attr)*])* #[no_mangle] - #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] + #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } @@ -400,7 +400,7 @@ macro_rules! intrinsics { #[naked] $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] + #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } @@ -467,7 +467,7 @@ macro_rules! intrinsics { mod $name { $(#[$($attr)*])* #[no_mangle] - #[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")] + #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] $(unsafe $($empty)?)? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } From 7033f32bacbc07e34eae5048d6b1133590d2a34e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 06:03:55 +0000 Subject: [PATCH 1302/4206] chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 8f2d8a5698a43..37051218172bc 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.119" +version = "0.1.120" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 40d2a60c224239904cf8f366f8835b5b0050ae9b Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 22 Aug 2024 00:43:02 -0700 Subject: [PATCH 1303/4206] Use array simd in `U64x2` --- library/compiler-builtins/src/macros.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 18535d633f780..f7c6d0bfeeee4 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -482,20 +482,20 @@ macro_rules! intrinsics { #[cfg(all(any(windows, target_os = "uefi"), target_pointer_width = "64"))] pub mod win64_128bit_abi_hack { #[repr(simd)] - pub struct U64x2(u64, u64); + pub struct U64x2([u64; 2]); impl From for U64x2 { fn from(i: i128) -> U64x2 { use crate::int::DInt; let j = i as u128; - U64x2(j.lo(), j.hi()) + U64x2([j.lo(), j.hi()]) } } impl From for U64x2 { fn from(i: u128) -> U64x2 { use crate::int::DInt; - U64x2(i.lo(), i.hi()) + U64x2([i.lo(), i.hi()]) } } } From 25be87d8a80c4df9209dc02434afb2fed05defe1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 08:01:13 +0000 Subject: [PATCH 1304/4206] chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 37051218172bc..3f104b037a908 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.120" +version = "0.1.121" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From a1ba7445d4077d3a421ff2ff721b3e8ec3171e20 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 22 Aug 2024 03:43:13 -0500 Subject: [PATCH 1305/4206] Add a `success` job to CI This will allow us to enable auto merge once CI completes. --- .../libm/.github/workflows/main.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 2f2e46822b9ef..322043d85af3b 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -71,3 +71,20 @@ jobs: - name: Install Rust run: rustup update nightly && rustup default nightly - run: cargo bench --all + + success: + needs: + - docker + - rustfmt + - wasm + - cb + - benchmarks + runs-on: ubuntu-latest + # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency + # 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" + 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) }}' From d6588dff8f9075d8cd2b20eba02aaf934f6aa88a Mon Sep 17 00:00:00 2001 From: beetrees Date: Sat, 24 Aug 2024 11:24:45 +0100 Subject: [PATCH 1306/4206] Use `macos-latest` in CI for `aarch64-apple-darwin` --- library/compiler-builtins/.github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 38064543f3e24..affb3a8244511 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -16,7 +16,7 @@ jobs: matrix: include: - target: aarch64-apple-darwin - os: macos-14 + os: macos-latest rust: nightly - target: aarch64-unknown-linux-gnu os: ubuntu-latest From 09a1f57604462039a1bd09b537f6311985ab3a66 Mon Sep 17 00:00:00 2001 From: beetrees Date: Sat, 24 Aug 2024 11:52:41 +0100 Subject: [PATCH 1307/4206] Use `macos-13` in CI for `x86_64-apple-darwin` --- library/compiler-builtins/.github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index affb3a8244511..fddb5973eb51c 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -80,7 +80,7 @@ jobs: os: ubuntu-latest rust: nightly - target: x86_64-apple-darwin - os: macos-latest + os: macos-13 rust: nightly - target: i686-pc-windows-msvc os: windows-latest From a17a15b08ad237431eeead760d2aebf086d764ba Mon Sep 17 00:00:00 2001 From: beetrees Date: Fri, 23 Aug 2024 12:39:31 +0100 Subject: [PATCH 1308/4206] Fix ABI for `f16` builtins on Intel Apple targets --- library/compiler-builtins/src/float/extend.rs | 2 + library/compiler-builtins/src/float/trunc.rs | 3 + library/compiler-builtins/src/macros.rs | 100 ++++++++++++++++++ 3 files changed, 105 insertions(+) diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index 2f392255fea7c..9fabcde25a5c2 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -86,6 +86,7 @@ intrinsics! { intrinsics! { #[avr_skip] #[aapcs_on_arm] + #[apple_f16_arg_abi] #[arm_aeabi_alias = __aeabi_h2f] #[cfg(f16_enabled)] pub extern "C" fn __extendhfsf2(a: f16) -> f32 { @@ -94,6 +95,7 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] + #[apple_f16_arg_abi] #[cfg(f16_enabled)] pub extern "C" fn __gnu_h2f_ieee(a: f16) -> f32 { extend(a) diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index c54ff7805f520..5c17cd96acfe4 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -134,6 +134,7 @@ intrinsics! { intrinsics! { #[avr_skip] #[aapcs_on_arm] + #[apple_f16_ret_abi] #[arm_aeabi_alias = __aeabi_f2h] #[cfg(f16_enabled)] pub extern "C" fn __truncsfhf2(a: f32) -> f16 { @@ -142,6 +143,7 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] + #[apple_f16_ret_abi] #[cfg(f16_enabled)] pub extern "C" fn __gnu_f2h_ieee(a: f32) -> f16 { trunc(a) @@ -149,6 +151,7 @@ intrinsics! { #[avr_skip] #[aapcs_on_arm] + #[apple_f16_ret_abi] #[arm_aeabi_alias = __aeabi_d2h] #[cfg(f16_enabled)] pub extern "C" fn __truncdfhf2(a: f64) -> f16 { diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index f7c6d0bfeeee4..f51e49e987661 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -276,6 +276,106 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); + // `arm_aeabi_alias` would conflict with `f16_apple_{arg,ret}_abi` not handled here. Avoid macro ambiguity by combining in a + // single `#[]`. + ( + #[apple_f16_arg_abi] + #[arm_aeabi_alias = $alias:ident] + $($t:tt)* + ) => { + intrinsics! { + #[apple_f16_arg_abi, arm_aeabi_alias = $alias] + $($t)* + } + }; + ( + #[apple_f16_ret_abi] + #[arm_aeabi_alias = $alias:ident] + $($t:tt)* + ) => { + intrinsics! { + #[apple_f16_ret_abi, arm_aeabi_alias = $alias] + $($t)* + } + }; + + // On x86 (32-bit and 64-bit) Apple platforms, `f16` is passed and returned like a `u16` unless + // the builtin involves `f128`. + ( + // `arm_aeabi_alias` would conflict if not handled here. Avoid macro ambiguity by combining + // in a single `#[]`. + #[apple_f16_arg_abi $(, arm_aeabi_alias = $alias:ident)?] + $(#[$($attr:tt)*])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64")))] + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + + #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"), not(feature = "mangled-names")))] + mod $name { + #[no_mangle] + #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] + $(#[$($attr)*])* + extern $abi fn $name( $($argname: u16),* ) $(-> $ret)? { + super::$name($(f16::from_bits($argname)),*) + } + } + + #[cfg(not(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"))))] + intrinsics! { + $(#[arm_aeabi_alias = $alias])? + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + ( + #[apple_f16_ret_abi $(, arm_aeabi_alias = $alias:ident)?] + $(#[$($attr:tt)*])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64")))] + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + + #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"), not(feature = "mangled-names")))] + mod $name { + #[no_mangle] + #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] + $(#[$($attr)*])* + extern $abi fn $name( $($argname: $ty),* ) -> u16 { + super::$name($($argname),*).to_bits() + } + } + + #[cfg(not(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"))))] + intrinsics! { + $(#[arm_aeabi_alias = $alias])? + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + // A bunch of intrinsics on ARM are aliased in the standard compiler-rt // build under `__aeabi_*` aliases, and LLVM will call these instead of the // original function. The aliasing here is used to generate these symbols in From 18109c2d2d78dc77840e6708ebaf20b51cf2aef2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 25 Aug 2024 04:08:06 +0000 Subject: [PATCH 1309/4206] chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 3f104b037a908..b9de326d994b6 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.121" +version = "0.1.122" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 1652ba219c7b28be8e440ad1c129c659625aff9b Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Tue, 27 Aug 2024 12:55:05 +0800 Subject: [PATCH 1310/4206] Don't include `math` for `unix` and `wasi` targets This fixes such as (https://github.com/rust-lang/rust/issues/128386) where, our implementation is being used on systems where there is already `math` library and its more performant and accurate. So with this change, linux will go back to the previous behavior and not include these functions, windows and apple were generally not affected. Looking at the targets we have builtin now in rust, everything else is probably good to have the math symbols. > A note on the above, the `hermit` os uses `libm` directly for itself, > but I think its Ok to keep providing math in `compiler_builtin` for it, > its technically the same implementation either from `compiler_builtin` > or `hermit-builtins`. Signed-off-by: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> --- library/compiler-builtins/src/lib.rs | 13 ++++++++++--- library/compiler-builtins/src/math.rs | 3 ++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 0d44fdf9654a9..b85f789fdd032 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -47,9 +47,16 @@ mod macros; pub mod float; pub mod int; -// Disabled on x86 without sse2 due to ABI issues -// -#[cfg(not(all(target_arch = "x86", not(target_feature = "sse2"))))] +// Disable for any of the following: +// - x86 without sse2 due to ABI issues +// - +// - All unix targets (linux, macos, freebsd, android, etc) +// - wasm with known target_os +#[cfg(not(any( + all(target_arch = "x86", not(target_feature = "sse2")), + unix, + all(target_family = "wasm", not(target_os = "unknown")) +)))] pub mod math; pub mod mem; diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 7d4d1787678bc..477dfe3651614 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -17,7 +17,7 @@ macro_rules! no_mangle { } } -#[cfg(all(not(windows), not(target_vendor = "apple")))] +#[cfg(not(windows))] no_mangle! { fn acos(x: f64) -> f64; fn asin(x: f64) -> f64; @@ -92,6 +92,7 @@ no_mangle! { fn fmodf(x: f32, y: f32) -> f32; } +// allow for windows (and other targets) intrinsics! { pub extern "C" fn lgamma_r(x: f64, s: &mut i32) -> f64 { let r = self::libm::lgamma_r(x); From 5b227e47723b8c71ca30dd7b3023bee1fe4df11e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 16:15:09 +0000 Subject: [PATCH 1311/4206] chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index b9de326d994b6..525095b17f757 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.122" +version = "0.1.123" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From a3a5a00b9a13c0f9949449313a591390a0546db6 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sat, 31 Aug 2024 12:54:21 -0500 Subject: [PATCH 1312/4206] [hexagon] Remove aliases w/o leading __ These hexagon builtins incorrectly created aliases in the global namespace which can (and in at least one case, did) conflict with symbols defined by other programs. This should address the issue reported as https://github.com/rust-lang/rust/issues/129823: Compiling compiler_builtins v0.1.123 Compiling core v0.0.0 (/home/ben/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core) Compiling rustc-std-workspace-core v1.99.0 (/home/ben/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/rustc-std-workspace-core) Compiling byteorder v1.5.0 Compiling zerocopy v0.7.34 error: symbol 'fma' is already defined error: could not compile `compiler_builtins` (lib) due to 1 previous error Also: some of the symbols defined were not just aliases, so those are now qualified with `__hexagon_`. The compiler does not yet emit calls to these particular ones, but if/when it does, it can use the new names. --- library/compiler-builtins/src/hexagon/dffma.s | 2 -- .../compiler-builtins/src/hexagon/dfminmax.s | 6 ---- .../src/hexagon/fastmath2_dlib_asm.s | 30 +++++++++---------- .../src/hexagon/fastmath2_ldlib_asm.s | 18 +++++------ 4 files changed, 24 insertions(+), 32 deletions(-) diff --git a/library/compiler-builtins/src/hexagon/dffma.s b/library/compiler-builtins/src/hexagon/dffma.s index 043a1d294a343..97d05eb1839ee 100644 --- a/library/compiler-builtins/src/hexagon/dffma.s +++ b/library/compiler-builtins/src/hexagon/dffma.s @@ -3,8 +3,6 @@ .type __hexagon_fmadf4,@function .global __hexagon_fmadf5 .type __hexagon_fmadf5,@function - .global fma - .type fma,@function .global __qdsp_fmadf5 ; .set __qdsp_fmadf5, __hexagon_fmadf5 .p2align 5 __hexagon_fmadf4: diff --git a/library/compiler-builtins/src/hexagon/dfminmax.s b/library/compiler-builtins/src/hexagon/dfminmax.s index 3337a3223ecd1..953e773bf1946 100644 --- a/library/compiler-builtins/src/hexagon/dfminmax.s +++ b/library/compiler-builtins/src/hexagon/dfminmax.s @@ -1,17 +1,12 @@ .text .global __hexagon_mindf3 .global __hexagon_maxdf3 - .global fmin - .type fmin,@function - .global fmax - .type fmax,@function .type __hexagon_mindf3,@function .type __hexagon_maxdf3,@function .global __qdsp_mindf3 ; .set __qdsp_mindf3, __hexagon_mindf3 .global __qdsp_maxdf3 ; .set __qdsp_maxdf3, __hexagon_maxdf3 .p2align 5 __hexagon_mindf3: -fmin: { p0 = dfclass(r1:0,#0x10) p1 = dfcmp.gt(r1:0,r3:2) @@ -31,7 +26,6 @@ fmin: .size __hexagon_mindf3,.-__hexagon_mindf3 .falign __hexagon_maxdf3: -fmax: { p0 = dfclass(r1:0,#0x10) p1 = dfcmp.gt(r3:2,r1:0) diff --git a/library/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s b/library/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s index 15c387846facc..e77b7db033242 100644 --- a/library/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s +++ b/library/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s @@ -1,7 +1,7 @@ .text - .global fast2_dadd_asm - .type fast2_dadd_asm, @function -fast2_dadd_asm: + .global __hexagon_fast2_dadd_asm + .type __hexagon_fast2_dadd_asm, @function +__hexagon_fast2_dadd_asm: .falign { R7:6 = VABSDIFFH(R1:0, R3:2) @@ -49,9 +49,9 @@ fast2_dadd_asm: jumpr r31 } .text - .global fast2_dsub_asm - .type fast2_dsub_asm, @function -fast2_dsub_asm: + .global __hexagon_fast2_dsub_asm + .type __hexagon_fast2_dsub_asm, @function +__hexagon_fast2_dsub_asm: .falign { R7:6 = VABSDIFFH(R1:0, R3:2) @@ -99,9 +99,9 @@ fast2_dsub_asm: jumpr r31 } .text - .global fast2_dmpy_asm - .type fast2_dmpy_asm, @function -fast2_dmpy_asm: + .global __hexagon_fast2_dmpy_asm + .type __hexagon_fast2_dmpy_asm, @function +__hexagon_fast2_dmpy_asm: .falign { R13= lsr(R2, #16) @@ -167,9 +167,9 @@ fast2_dmpy_asm: jumpr r31 } .text - .global fast2_qd2f_asm - .type fast2_qd2f_asm, @function -fast2_qd2f_asm: + .global __hexagon_fast2_qd2f_asm + .type __hexagon_fast2_qd2f_asm, @function +__hexagon_fast2_qd2f_asm: .falign { R3 = abs(R1):sat @@ -225,9 +225,9 @@ fast2_qd2f_asm: jumpr r31 } .text - .global fast2_f2qd_asm - .type fast2_f2qd_asm, @function -fast2_f2qd_asm: + .global __hexagon_fast2_f2qd_asm + .type __hexagon_fast2_f2qd_asm, @function +__hexagon_fast2_f2qd_asm: diff --git a/library/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s b/library/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s index b72b7550afc4b..3251057d78c98 100644 --- a/library/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s +++ b/library/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s @@ -1,7 +1,7 @@ .text - .global fast2_ldadd_asm - .type fast2_ldadd_asm, @function -fast2_ldadd_asm: + .global __hexagon_fast2ldadd_asm + .type __hexagon_fast2ldadd_asm, @function +__hexagon_fast2ldadd_asm: .falign { R4 = memw(r29+#8) @@ -54,9 +54,9 @@ fast2_ldadd_asm: jumpr r31 } .text - .global fast2_ldsub_asm - .type fast2_ldsub_asm, @function -fast2_ldsub_asm: + .global __hexagon_fast2ldsub_asm + .type __hexagon_fast2ldsub_asm, @function +__hexagon_fast2ldsub_asm: .falign { R4 = memw(r29+#8) @@ -109,9 +109,9 @@ fast2_ldsub_asm: jumpr r31 } .text - .global fast2_ldmpy_asm - .type fast2_ldmpy_asm, @function -fast2_ldmpy_asm: + .global __hexagon_fast2ldmpy_asm + .type __hexagon_fast2ldmpy_asm, @function +__hexagon_fast2ldmpy_asm: .falign { R15:14 = memd(r29+#0) From 39920c73dd5fbfb1d8541daee35330133e114527 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 1 Sep 2024 03:20:30 +0000 Subject: [PATCH 1313/4206] chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 525095b17f757..f5a04747a728f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.123" +version = "0.1.124" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 69406c118a8d1f863bda99830d813489d9a7e063 Mon Sep 17 00:00:00 2001 From: Sbstn Bcht Date: Wed, 4 Sep 2024 04:55:44 +0200 Subject: [PATCH 1314/4206] Remove unsupported *vfp functions (#678) Remove all *vfp functions and related tests since LLVM no longer emits them. Link: https://github.com/rust-lang/compiler-builtins/pull/626 [ Reword commit message - Trevor ] --- library/compiler-builtins/README.md | 71 ++++++++++--------- library/compiler-builtins/src/float/add.rs | 10 --- library/compiler-builtins/src/float/cmp.rs | 51 ------------- library/compiler-builtins/src/float/div.rs | 10 --- library/compiler-builtins/src/float/extend.rs | 5 -- library/compiler-builtins/src/float/mul.rs | 10 --- library/compiler-builtins/src/float/sub.rs | 10 --- library/compiler-builtins/src/float/trunc.rs | 5 -- .../testcrate/tests/addsub.rs | 10 --- .../compiler-builtins/testcrate/tests/cmp.rs | 14 ---- .../compiler-builtins/testcrate/tests/conv.rs | 12 ---- .../testcrate/tests/div_rem.rs | 10 --- .../compiler-builtins/testcrate/tests/mul.rs | 10 --- 13 files changed, 37 insertions(+), 191 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 51bef5e2e7c29..46983a281eb08 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -103,9 +103,7 @@ rely on CI. - [x] aarch64/chkstk.S - [x] adddf3.c - [x] addsf3.c -- [x] arm/adddf3vfp.S - [x] arm/addsf3.S -- [x] arm/addsf3vfp.S - [x] arm/aeabi_dcmp.S - [x] arm/aeabi_fcmp.S - [x] arm/aeabi_idivmod.S @@ -116,45 +114,13 @@ rely on CI. - [x] arm/aeabi_uidivmod.S - [x] arm/aeabi_uldivmod.S - [ ] arm/chkstk.S -- [x] arm/divdf3vfp.S - [ ] arm/divmodsi4.S (generic version is done) -- [x] arm/divsf3vfp.S - [ ] arm/divsi3.S (generic version is done) -- [x] arm/eqdf2vfp.S -- [x] arm/eqsf2vfp.S -- [x] arm/extendsfdf2vfp.S -- [ ] arm/fixdfsivfp.S -- [ ] arm/fixsfsivfp.S -- [ ] arm/fixunsdfsivfp.S -- [ ] arm/fixunssfsivfp.S -- [ ] arm/floatsidfvfp.S -- [ ] arm/floatsisfvfp.S -- [ ] arm/floatunssidfvfp.S -- [ ] arm/floatunssisfvfp.S -- [x] arm/gedf2vfp.S -- [x] arm/gesf2vfp.S -- [x] arm/gtdf2vfp.S -- [x] arm/gtsf2vfp.S -- [x] arm/ledf2vfp.S -- [x] arm/lesf2vfp.S -- [x] arm/ltdf2vfp.S -- [x] arm/ltsf2vfp.S - [ ] arm/modsi3.S (generic version is done) -- [x] arm/muldf3vfp.S -- [x] arm/mulsf3vfp.S -- [x] arm/nedf2vfp.S -- [ ] arm/negdf2vfp.S -- [ ] arm/negsf2vfp.S -- [x] arm/nesf2vfp.S - [x] arm/softfloat-alias.list -- [x] arm/subdf3vfp.S -- [x] arm/subsf3vfp.S -- [x] arm/truncdfsf2vfp.S - [ ] arm/udivmodsi4.S (generic version is done) - [ ] arm/udivsi3.S (generic version is done) - [ ] arm/umodsi3.S (generic version is done) -- [ ] arm/unorddf2vfp.S -- [ ] arm/unordsf2vfp.S - [x] ashldi3.c - [x] ashrdi3.c - [ ] avr/divmodhi4.S @@ -501,6 +467,43 @@ Floating-point implementations of builtins that are only called from soft-float - ~~x86_64/floatdidf.c~~ - ~~x86_64/floatdisf.c~~ +Unsupported in any current target: used on old versions of 32-bit iOS with ARMv5. + +- ~~arm/adddf3vfp.S~~ +- ~~arm/addsf3vfp.S~~ +- ~~arm/divdf3vfp.S~~ +- ~~arm/divsf3vfp.S~~ +- ~~arm/eqdf2vfp.S~~ +- ~~arm/eqsf2vfp.S~~ +- ~~arm/extendsfdf2vfp.S~~ +- ~~arm/fixdfsivfp.S~~ +- ~~arm/fixsfsivfp.S~~ +- ~~arm/fixunsdfsivfp.S~~ +- ~~arm/fixunssfsivfp.S~~ +- ~~arm/floatsidfvfp.S~~ +- ~~arm/floatsisfvfp.S~~ +- ~~arm/floatunssidfvfp.S~~ +- ~~arm/floatunssisfvfp.S~~ +- ~~arm/gedf2vfp.S~~ +- ~~arm/gesf2vfp.S~~ +- ~~arm/gtdf2vfp.S~~ +- ~~arm/gtsf2vfp.S~~ +- ~~arm/ledf2vfp.S~~ +- ~~arm/lesf2vfp.S~~ +- ~~arm/ltdf2vfp.S~~ +- ~~arm/ltsf2vfp.S~~ +- ~~arm/muldf3vfp.S~~ +- ~~arm/mulsf3vfp.S~~ +- ~~arm/nedf2vfp.S~~ +- ~~arm/negdf2vfp.S~~ +- ~~arm/negsf2vfp.S~~ +- ~~arm/nesf2vfp.S~~ +- ~~arm/subdf3vfp.S~~ +- ~~arm/subsf3vfp.S~~ +- ~~arm/truncdfsf2vfp.S~~ +- ~~arm/unorddf2vfp.S~~ +- ~~arm/unordsf2vfp.S~~ + ## License The compiler-builtins crate is dual licensed under both the University of diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 03ed131af2630..bceef7b0ed996 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -208,14 +208,4 @@ intrinsics! { pub extern "C" fn __addtf3(a: f128, b: f128) -> f128 { add(a, b) } - - #[cfg(target_arch = "arm")] - pub extern "C" fn __addsf3vfp(a: f32, b: f32) -> f32 { - a + b - } - - #[cfg(target_arch = "arm")] - pub extern "C" fn __adddf3vfp(a: f64, b: f64) -> f64 { - a + b - } } diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 1901ca4b36207..bb7d4b498fe2c 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -258,55 +258,4 @@ intrinsics! { pub extern "aapcs" fn __aeabi_dcmpgt(a: f64, b: f64) -> i32 { (__gtdf2(a, b) > 0) as i32 } - - // On hard-float targets LLVM will use native instructions - // for all VFP intrinsics below - - pub extern "C" fn __gesf2vfp(a: f32, b: f32) -> i32 { - (a >= b) as i32 - } - - pub extern "C" fn __gedf2vfp(a: f64, b: f64) -> i32 { - (a >= b) as i32 - } - - pub extern "C" fn __gtsf2vfp(a: f32, b: f32) -> i32 { - (a > b) as i32 - } - - pub extern "C" fn __gtdf2vfp(a: f64, b: f64) -> i32 { - (a > b) as i32 - } - - pub extern "C" fn __ltsf2vfp(a: f32, b: f32) -> i32 { - (a < b) as i32 - } - - pub extern "C" fn __ltdf2vfp(a: f64, b: f64) -> i32 { - (a < b) as i32 - } - - pub extern "C" fn __lesf2vfp(a: f32, b: f32) -> i32 { - (a <= b) as i32 - } - - pub extern "C" fn __ledf2vfp(a: f64, b: f64) -> i32 { - (a <= b) as i32 - } - - pub extern "C" fn __nesf2vfp(a: f32, b: f32) -> i32 { - (a != b) as i32 - } - - pub extern "C" fn __nedf2vfp(a: f64, b: f64) -> i32 { - (a != b) as i32 - } - - pub extern "C" fn __eqsf2vfp(a: f32, b: f32) -> i32 { - (a == b) as i32 - } - - pub extern "C" fn __eqdf2vfp(a: f64, b: f64) -> i32 { - (a == b) as i32 - } } diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index c0d780b66dda4..2a57ee1a0bdff 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -926,14 +926,4 @@ intrinsics! { pub extern "C" fn __divdf3(a: f64, b: f64) -> f64 { div64(a, b) } - - #[cfg(target_arch = "arm")] - pub extern "C" fn __divsf3vfp(a: f32, b: f32) -> f32 { - a / b - } - - #[cfg(target_arch = "arm")] - pub extern "C" fn __divdf3vfp(a: f64, b: f64) -> f64 { - a / b - } } diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index 9fabcde25a5c2..997475c8e0482 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -76,11 +76,6 @@ intrinsics! { pub extern "C" fn __extendsfdf2(a: f32) -> f64 { extend(a) } - - #[cfg(target_arch = "arm")] - pub extern "C" fn __extendsfdf2vfp(a: f32) -> f64 { - a as f64 // LLVM generate 'fcvtds' - } } intrinsics! { diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index cb0fcdfa853f3..a4c69ea8707e4 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -199,14 +199,4 @@ intrinsics! { pub extern "C" fn __multf3(a: f128, b: f128) -> f128 { mul(a, b) } - - #[cfg(target_arch = "arm")] - pub extern "C" fn __mulsf3vfp(a: f32, b: f32) -> f32 { - a * b - } - - #[cfg(target_arch = "arm")] - pub extern "C" fn __muldf3vfp(a: f64, b: f64) -> f64 { - a * b - } } diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index d33016ead2e39..7e8a894584839 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -23,14 +23,4 @@ intrinsics! { __addtf3(a, f128::from_repr(b.repr() ^ f128::SIGN_MASK)) } - - #[cfg(target_arch = "arm")] - pub extern "C" fn __subsf3vfp(a: f32, b: f32) -> f32 { - a - b - } - - #[cfg(target_arch = "arm")] - pub extern "C" fn __subdf3vfp(a: f64, b: f64) -> f64 { - a - b - } } diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index 5c17cd96acfe4..a25b6eabc5e29 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -124,11 +124,6 @@ intrinsics! { pub extern "C" fn __truncdfsf2(a: f64) -> f32 { trunc(a) } - - #[cfg(target_arch = "arm")] - pub extern "C" fn __truncdfsf2vfp(a: f64) -> f32 { - a as f32 - } } intrinsics! { diff --git a/library/compiler-builtins/testcrate/tests/addsub.rs b/library/compiler-builtins/testcrate/tests/addsub.rs index 1ba2df74191b8..284a2bf5a1127 100644 --- a/library/compiler-builtins/testcrate/tests/addsub.rs +++ b/library/compiler-builtins/testcrate/tests/addsub.rs @@ -139,13 +139,3 @@ mod float_addsub_f128_ppc { f128, __addkf3, __subkf3, Quad, not(feature = "no-sys-f128"); } } - -#[cfg(target_arch = "arm")] -mod float_addsub_arm { - use super::*; - - float_sum! { - f32, __addsf3vfp, __subsf3vfp, Single, all(); - f64, __adddf3vfp, __subdf3vfp, Double, all(); - } -} diff --git a/library/compiler-builtins/testcrate/tests/cmp.rs b/library/compiler-builtins/testcrate/tests/cmp.rs index 7e973e7e5ed42..e3161f374290d 100644 --- a/library/compiler-builtins/testcrate/tests/cmp.rs +++ b/library/compiler-builtins/testcrate/tests/cmp.rs @@ -156,7 +156,6 @@ mod float_comparisons_arm { fn cmp_f32() { use compiler_builtins::float::cmp::{ __aeabi_fcmpeq, __aeabi_fcmpge, __aeabi_fcmpgt, __aeabi_fcmple, __aeabi_fcmplt, - __eqsf2vfp, __gesf2vfp, __gtsf2vfp, __lesf2vfp, __ltsf2vfp, __nesf2vfp, }; fuzz_float_2(N, |x: f32, y: f32| { @@ -166,12 +165,6 @@ mod float_comparisons_arm { 0, x == y, __aeabi_fcmpeq; 0, x >= y, __aeabi_fcmpge; 0, x > y, __aeabi_fcmpgt; - 0, x < y, __ltsf2vfp; - 0, x <= y, __lesf2vfp; - 0, x == y, __eqsf2vfp; - 0, x >= y, __gesf2vfp; - 0, x > y, __gtsf2vfp; - 1, x != y, __nesf2vfp; ); }); } @@ -180,7 +173,6 @@ mod float_comparisons_arm { fn cmp_f64() { use compiler_builtins::float::cmp::{ __aeabi_dcmpeq, __aeabi_dcmpge, __aeabi_dcmpgt, __aeabi_dcmple, __aeabi_dcmplt, - __eqdf2vfp, __gedf2vfp, __gtdf2vfp, __ledf2vfp, __ltdf2vfp, __nedf2vfp, }; fuzz_float_2(N, |x: f64, y: f64| { @@ -190,12 +182,6 @@ mod float_comparisons_arm { 0, x == y, __aeabi_dcmpeq; 0, x >= y, __aeabi_dcmpge; 0, x > y, __aeabi_dcmpgt; - 0, x < y, __ltdf2vfp; - 0, x <= y, __ledf2vfp; - 0, x == y, __eqdf2vfp; - 0, x >= y, __gedf2vfp; - 0, x > y, __gtdf2vfp; - 1, x != y, __nedf2vfp; ); }); } diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index ce1f64e67d103..24f3a04a4eedc 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -258,12 +258,6 @@ mod extend { f32 => f64, Single => Double, __extendsfdf2, all(); } - #[cfg(target_arch = "arm")] - f_to_f! { - extend, - f32 => f64, Single => Double, __extendsfdf2vfp, all(); - } - #[cfg(all(f16_enabled, f128_enabled))] #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] f_to_f! { @@ -293,12 +287,6 @@ mod trunc { f64 => f32, Double => Single, __truncdfsf2, all(); } - #[cfg(target_arch = "arm")] - f_to_f! { - trunc, - f64 => f32, Double => Single, __truncdfsf2vfp, all(); - } - #[cfg(all(f16_enabled, f128_enabled))] #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] f_to_f! { diff --git a/library/compiler-builtins/testcrate/tests/div_rem.rs b/library/compiler-builtins/testcrate/tests/div_rem.rs index ff78b4f54d548..418e9c18937d2 100644 --- a/library/compiler-builtins/testcrate/tests/div_rem.rs +++ b/library/compiler-builtins/testcrate/tests/div_rem.rs @@ -156,13 +156,3 @@ mod float_div { f64, __divdf3, Double, all(); } } - -#[cfg(target_arch = "arm")] -mod float_div_arm { - use super::*; - - float! { - f32, __divsf3vfp, Single, all(); - f64, __divdf3vfp, Double, all(); - } -} diff --git a/library/compiler-builtins/testcrate/tests/mul.rs b/library/compiler-builtins/testcrate/tests/mul.rs index 867622fdf07a9..449d194804aee 100644 --- a/library/compiler-builtins/testcrate/tests/mul.rs +++ b/library/compiler-builtins/testcrate/tests/mul.rs @@ -153,13 +153,3 @@ mod float_mul_f128_ppc { f128, __mulkf3, Quad, not(feature = "no-sys-f128"); } } - -#[cfg(target_arch = "arm")] -mod float_mul_arm { - use super::*; - - float_mul! { - f32, __mulsf3vfp, Single, all(); - f64, __muldf3vfp, Double, all(); - } -} From 625462202e58c0043156e5407b54e5eeb14b7ad7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 5 Sep 2024 09:03:28 -0700 Subject: [PATCH 1315/4206] Use the trifecta div algorithm for 128-bit div on wasm This commit updates the `#[cfg]` annotations used to select the implementation of 128-bit division in compiler-builtins on wasm targets. This is done with relation to https://github.com/WebAssembly/128-bit-arithmetic where performance of 128-bit operations is being investigated on WebAssembly. While I don't know much about the particulars of the two algorithms involved here the comments indicate that the "trifecta" variant is preferred if possible but it's not selected on 32-bit architectures. This rationale isn't as applicable to WebAssembly targets because despite the 32-bit pointer width there are often wider-than-pointer operations available as it's typically run on 64-bit machines. Locally in testing a benchmark that performs division with a Rust-based bignum libraries whent from 350% slower-than-native to 220% slower-than-native with this change, a nice increase in speed. While this was tested with Wasmtime other runtimes are likely to see an improvement as well. --- .../src/int/specialized_div_rem/mod.rs | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs index 760f5f5b7a326..a91fe6632eec3 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -136,9 +136,15 @@ fn u64_by_u64_div_rem(duo: u64, div: u64) -> (u64, u64) { // Whether `trifecta` or `delegate` is faster for 128 bit division depends on the speed at which a // microarchitecture can multiply and divide. We decide to be optimistic and assume `trifecta` is -// faster if the target pointer width is at least 64. +// faster if the target pointer width is at least 64. Note that this +// implementation is additionally included on WebAssembly despite the typical +// pointer width there being 32 because it's typically run on a 64-bit machine +// that has access to faster 64-bit operations. #[cfg(all( - not(any(target_pointer_width = "16", target_pointer_width = "32")), + any( + target_family = "wasm", + not(any(target_pointer_width = "16", target_pointer_width = "32")), + ), not(all(not(feature = "no-asm"), target_arch = "x86_64")), not(any(target_arch = "sparc", target_arch = "sparc64")) ))] @@ -152,10 +158,14 @@ impl_trifecta!( u128 ); -// If the pointer width less than 64, then the target architecture almost certainly does not have -// the fast 64 to 128 bit widening multiplication needed for `trifecta` to be faster. +// If the pointer width less than 64 and this isn't wasm, then the target +// architecture almost certainly does not have the fast 64 to 128 bit widening +// multiplication needed for `trifecta` to be faster. #[cfg(all( - any(target_pointer_width = "16", target_pointer_width = "32"), + not(any( + target_family = "wasm", + not(any(target_pointer_width = "16", target_pointer_width = "32")), + )), not(all(not(feature = "no-asm"), target_arch = "x86_64")), not(any(target_arch = "sparc", target_arch = "sparc64")) ))] From 07112912290385f038777a3b26b467fa7ff0ba52 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 5 Sep 2024 16:14:31 +0000 Subject: [PATCH 1316/4206] chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index f5a04747a728f..1c7bc5db0ee8b 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.124" +version = "0.1.125" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 1a343b61182ae1de868cdd00e54fce9231e9ae5c Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 9 Sep 2024 16:44:50 +0200 Subject: [PATCH 1317/4206] use `naked_asm!` in `#[naked]` functions --- library/compiler-builtins/src/aarch64.rs | 3 +-- library/compiler-builtins/src/aarch64_linux.rs | 12 ++++-------- library/compiler-builtins/src/arm.rs | 12 ++++-------- library/compiler-builtins/src/x86.rs | 8 ++++---- library/compiler-builtins/src/x86_64.rs | 4 ++-- 5 files changed, 15 insertions(+), 24 deletions(-) diff --git a/library/compiler-builtins/src/aarch64.rs b/library/compiler-builtins/src/aarch64.rs index e5747d5258f73..cce485c46823d 100644 --- a/library/compiler-builtins/src/aarch64.rs +++ b/library/compiler-builtins/src/aarch64.rs @@ -6,7 +6,7 @@ intrinsics! { #[naked] #[cfg(all(target_os = "uefi", not(feature = "no-asm")))] pub unsafe extern "C" fn __chkstk() { - core::arch::asm!( + core::arch::naked_asm!( ".p2align 2", "lsl x16, x15, #4", "mov x17, sp", @@ -16,7 +16,6 @@ intrinsics! { "ldr xzr, [x17]", "b.gt 1b", "ret", - options(noreturn) ); } } diff --git a/library/compiler-builtins/src/aarch64_linux.rs b/library/compiler-builtins/src/aarch64_linux.rs index 62144e53199be..caac3e6025dc6 100644 --- a/library/compiler-builtins/src/aarch64_linux.rs +++ b/library/compiler-builtins/src/aarch64_linux.rs @@ -136,7 +136,7 @@ macro_rules! compare_and_swap { expected: int_ty!($bytes), desired: int_ty!($bytes), ptr: *mut int_ty!($bytes) ) -> int_ty!($bytes) { // We can't use `AtomicI8::compare_and_swap`; we *are* compare_and_swap. - unsafe { core::arch::asm! { + unsafe { core::arch::naked_asm! { // UXT s(tmp0), s(0) concat!(uxt!($bytes), " ", reg!($bytes, 16), ", ", reg!($bytes, 0)), "0:", @@ -150,7 +150,6 @@ macro_rules! compare_and_swap { "cbnz w17, 0b", "1:", "ret", - options(noreturn) } } } } @@ -166,7 +165,7 @@ macro_rules! compare_and_swap_i128 { pub unsafe extern "C" fn $name ( expected: i128, desired: i128, ptr: *mut i128 ) -> i128 { - unsafe { core::arch::asm! { + unsafe { core::arch::naked_asm! { "mov x16, x0", "mov x17, x1", "0:", @@ -180,7 +179,6 @@ macro_rules! compare_and_swap_i128 { "cbnz w15, 0b", "1:", "ret", - options(noreturn) } } } } @@ -196,7 +194,7 @@ macro_rules! swap { pub unsafe extern "C" fn $name ( left: int_ty!($bytes), right_ptr: *mut int_ty!($bytes) ) -> int_ty!($bytes) { - unsafe { core::arch::asm! { + unsafe { core::arch::naked_asm! { // mov s(tmp0), s(0) concat!("mov ", reg!($bytes, 16), ", ", reg!($bytes, 0)), "0:", @@ -206,7 +204,6 @@ macro_rules! swap { concat!(stxr!($ordering, $bytes), " w17, ", reg!($bytes, 16), ", [x1]"), "cbnz w17, 0b", "ret", - options(noreturn) } } } } @@ -222,7 +219,7 @@ macro_rules! fetch_op { pub unsafe extern "C" fn $name ( val: int_ty!($bytes), ptr: *mut int_ty!($bytes) ) -> int_ty!($bytes) { - unsafe { core::arch::asm! { + unsafe { core::arch::naked_asm! { // mov s(tmp0), s(0) concat!("mov ", reg!($bytes, 16), ", ", reg!($bytes, 0)), "0:", @@ -234,7 +231,6 @@ macro_rules! fetch_op { concat!(stxr!($ordering, $bytes), " w15, ", reg!($bytes, 17), ", [x1]"), "cbnz w15, 0b", "ret", - options(noreturn) } } } } diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/src/arm.rs index 55cdda1f3e0b1..9e6608397a846 100644 --- a/library/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/src/arm.rs @@ -23,7 +23,7 @@ intrinsics! { #[naked] #[cfg(not(target_env = "msvc"))] pub unsafe extern "C" fn __aeabi_uidivmod() { - core::arch::asm!( + core::arch::naked_asm!( "push {{lr}}", "sub sp, sp, #4", "mov r2, sp", @@ -31,13 +31,12 @@ intrinsics! { "ldr r1, [sp]", "add sp, sp, #4", "pop {{pc}}", - options(noreturn) ); } #[naked] pub unsafe extern "C" fn __aeabi_uldivmod() { - core::arch::asm!( + core::arch::naked_asm!( "push {{r4, lr}}", "sub sp, sp, #16", "add r4, sp, #8", @@ -47,26 +46,24 @@ intrinsics! { "ldr r3, [sp, #12]", "add sp, sp, #16", "pop {{r4, pc}}", - options(noreturn) ); } #[naked] pub unsafe extern "C" fn __aeabi_idivmod() { - core::arch::asm!( + core::arch::naked_asm!( "push {{r0, r1, r4, lr}}", bl!("__aeabi_idiv"), "pop {{r1, r2}}", "muls r2, r2, r0", "subs r1, r1, r2", "pop {{r4, pc}}", - options(noreturn) ); } #[naked] pub unsafe extern "C" fn __aeabi_ldivmod() { - core::arch::asm!( + core::arch::naked_asm!( "push {{r4, lr}}", "sub sp, sp, #16", "add r4, sp, #8", @@ -76,7 +73,6 @@ intrinsics! { "ldr r3, [sp, #12]", "add sp, sp, #16", "pop {{r4, pc}}", - options(noreturn) ); } diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/src/x86.rs index ceec3912eabb1..ad04d2108eadd 100644 --- a/library/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/src/x86.rs @@ -14,9 +14,9 @@ intrinsics! { not(feature = "no-asm") ))] pub unsafe extern "C" fn __chkstk() { - core::arch::asm!( + core::arch::naked_asm!( "jmp __alloca", // Jump to __alloca since fallthrough may be unreliable" - options(noreturn, att_syntax) + options(att_syntax) ); } @@ -27,7 +27,7 @@ intrinsics! { ))] pub unsafe extern "C" fn _alloca() { // __chkstk and _alloca are the same function - core::arch::asm!( + core::arch::naked_asm!( "push %ecx", "cmp $0x1000,%eax", "lea 8(%esp),%ecx", // esp before calling this routine -> ecx @@ -47,7 +47,7 @@ intrinsics! { "push (%eax)", // push return address onto the stack "sub %esp,%eax", // restore the original value in eax "ret", - options(noreturn, att_syntax) + options(att_syntax) ); } } diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 8048f85c8ffaa..9c91a45561ee2 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -14,7 +14,7 @@ intrinsics! { not(feature = "no-asm") ))] pub unsafe extern "C" fn ___chkstk_ms() { - core::arch::asm!( + core::arch::naked_asm!( "push %rcx", "push %rax", "cmp $0x1000,%rax", @@ -32,7 +32,7 @@ intrinsics! { "pop %rax", "pop %rcx", "ret", - options(noreturn, att_syntax) + options(att_syntax) ); } } From 22ef22e30b151dbb4eeafa15aa3a54a009652d70 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 11 Sep 2024 17:09:04 +0000 Subject: [PATCH 1318/4206] chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 1c7bc5db0ee8b..1aa6e5668d9c8 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.125" +version = "0.1.126" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 44840a12bcdbdef7eabd82a6dd5b396fdf7d90ed Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 19 Aug 2024 15:33:05 -0500 Subject: [PATCH 1319/4206] Add `Shr` to `u256` Float division requires some shift operations on big integers; implement right shift here. --- library/compiler-builtins/src/int/big.rs | 37 +++++++++- .../compiler-builtins/testcrate/tests/big.rs | 73 +++++++++++++++++++ 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/int/big.rs b/library/compiler-builtins/src/int/big.rs index 019dd728b5d95..e565da8972034 100644 --- a/library/compiler-builtins/src/int/big.rs +++ b/library/compiler-builtins/src/int/big.rs @@ -93,7 +93,7 @@ macro_rules! impl_common { type Output = Self; fn shl(self, rhs: u32) -> Self::Output { - todo!() + unimplemented!("only used to meet trait bounds") } } }; @@ -102,6 +102,41 @@ macro_rules! impl_common { 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 diff --git a/library/compiler-builtins/testcrate/tests/big.rs b/library/compiler-builtins/testcrate/tests/big.rs index 128b5ddfd6d59..595f622560796 100644 --- a/library/compiler-builtins/testcrate/tests/big.rs +++ b/library/compiler-builtins/testcrate/tests/big.rs @@ -59,3 +59,76 @@ fn widen_mul_u128() { } 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()); +} From 23af8ca763ca8096a05569065485879fc8b6d84f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 19 Aug 2024 15:35:49 -0500 Subject: [PATCH 1320/4206] Update bounds and docs for the `Float` trait Add some bounds to integer types that allow our function trait bounds to be slightly less verbose. Also clarify documentation and remove a redundant operation. --- library/compiler-builtins/src/float/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 8473732057a7d..704bba0c025f7 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -31,10 +31,10 @@ pub(crate) trait Float: + ops::Rem { /// A uint of the same width as the float - type Int: Int; + type Int: Int; /// A int of the same width as the float - type SignedInt: Int; + type SignedInt: Int + MinInt; /// An int capable of containing the exponent bits plus a sign bit. This is signed. type ExpInt: Int; @@ -51,7 +51,7 @@ pub(crate) trait Float: /// The bitwidth of the exponent const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1; - /// The maximum value of the exponent + /// The saturated value of the exponent (infinite representation), in the rightmost postiion. const EXPONENT_MAX: u32 = (1 << Self::EXPONENT_BITS) - 1; /// The exponent bias value @@ -83,7 +83,7 @@ pub(crate) trait Float: /// Returns true if the sign is negative fn is_sign_negative(self) -> bool; - /// Returns the exponent with bias + /// Returns the exponent, not adjusting for bias. fn exp(self) -> Self::ExpInt; /// Returns the significand with no implicit bit (or the "fractional" part) @@ -175,7 +175,7 @@ macro_rules! float_impl { fn normalize(significand: Self::Int) -> (i32, Self::Int) { let shift = significand .leading_zeros() - .wrapping_sub((Self::Int::ONE << Self::SIGNIFICAND_BITS).leading_zeros()); + .wrapping_sub(Self::EXPONENT_BITS); ( 1i32.wrapping_sub(shift as i32), significand << shift as Self::Int, From 4f8afbabdc26f140e2800056440ed14876976b80 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 19 Aug 2024 15:40:43 -0500 Subject: [PATCH 1321/4206] Make float division generic Float division currently has a separate `div32` and `div64` for `f32` and `f64`, respectively. Combine these to make use of generics. This will make it easier to support `f128` division, and reduces a lot of redundant code. This includes a simplification of division tests. --- library/compiler-builtins/src/float/div.rs | 1027 ++++++----------- .../testcrate/tests/div_rem.rs | 23 +- 2 files changed, 366 insertions(+), 684 deletions(-) diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index 2a57ee1a0bdff..4aec3418f4bc3 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -1,518 +1,149 @@ -// The functions are complex with many branches, and explicit -// `return`s makes it clear where function exit points are -#![allow(clippy::needless_return)] - -use crate::float::Float; -use crate::int::{CastInto, DInt, HInt, Int, MinInt}; +//! Floating point division routines. +//! +//! This module documentation gives an overview of the method used. More documentation is inline. +//! +//! # Relevant notation +//! +//! - `m_a`: the mantissa of `a`, in base 2 +//! - `p_a`: the exponent of `a`, in base 2. I.e. `a = m_a * 2^p_a` +//! - `uqN` (e.g. `uq1`): this refers to Q notation for fixed-point numbers. UQ1.31 is an unsigned +//! fixed-point number with 1 integral bit, and 31 decimal bits. A `uqN` variable of type `uM` +//! will have N bits of integer and M-N bits of fraction. +//! - `hw`: half width, i.e. for `f64` this will be a `u32`. +//! - `x` is the best estimate of `1/m_b` +//! +//! # Method Overview +//! +//! Division routines must solve for `a / b`, which is `res = m_a*2^p_a / m_b*2^p_b`. The basic +//! process is as follows: +//! +//! - Rearange the exponent and significand to simplify the operations: +//! `res = (m_a / m_b) * 2^{p_a - p_b}`. +//! - Check for early exits (infinity, zero, etc). +//! - If `a` or `b` are subnormal, normalize by shifting the mantissa and adjusting the exponent. +//! - Set the implicit bit so math is correct. +//! - Shift mantissa significant digits (with implicit bit) fully left such that fixed-point UQ1 +//! or UQ0 numbers can be used for mantissa math. These will have greater precision than the +//! actual mantissa, which is important for correct rounding. +//! - Calculate the reciprocal of `m_b`, `x`. +//! - Use the reciprocal to multiply rather than divide: `res = m_a * x_b * 2^{p_a - p_b}`. +//! - Reapply rounding. +//! +//! # Reciprocal calculation +//! +//! Calculating the reciprocal is the most complicated part of this process. It uses the +//! [Newton-Raphson method], which picks an initial estimation (of the reciprocal) and performs +//! a number of iterations to increase its precision. +//! +//! In general, Newton's method takes the following form: +//! +//! ```text +//! `x_n` is a guess or the result of a previous iteration. Increasing `n` converges to the +//! desired result. +//! +//! The result approaches a zero of `f(x)` by applying a correction to the previous gues. +//! +//! x_{n+1} = x_n - f(x_n) / f'(x_n) +//! ``` +//! +//! Applying this to find the reciprocal: +//! +//! ```text +//! 1 / x = b +//! +//! Rearrange so we can solve by finding a zero +//! 0 = (1 / x) - b = f(x) +//! +//! f'(x) = -x^{-2} +//! +//! x_{n+1} = 2*x_n - b*x_n^2 +//! ``` +//! +//! This is a process that can be repeated to calculate the reciprocal with enough precision to +//! achieve a correctly rounded result for the overall division operation. The maximum required +//! number of iterations is known since precision doubles with each iteration. +//! +//! # Half-width operations +//! +//! Calculating the reciprocal requires widening multiplication and performing arithmetic on the +//! results, meaning that emulated integer arithmetic on `u128` (for `f64`) and `u256` (for `f128`) +//! gets used instead of native math. +//! +//! To make this more efficient, all but the final operation can be computed using half-width +//! integers. For example, rather than computing four iterations using 128-bit integers for `f64`, +//! we can instead perform three iterations using native 64-bit integers and only one final +//! iteration using the full 128 bits. +//! +//! This works because of precision doubling. Some leeway is allowed here because the fixed-point +//! number has more bits than the final mantissa will. +//! +//! [Newton-Raphson method]: https://en.wikipedia.org/wiki/Newton%27s_method use super::HalfRep; +use crate::float::Float; +use crate::int::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; +use core::mem::size_of; +use core::ops; -fn div32(a: F, b: F) -> F -where - u32: CastInto, - F::Int: CastInto, - i32: CastInto, - F::Int: CastInto, - F::Int: HInt, - ::Int: core::ops::Mul, -{ - const NUMBER_OF_HALF_ITERATIONS: usize = 0; - const NUMBER_OF_FULL_ITERATIONS: usize = 3; - const USE_NATIVE_FULL_ITERATIONS: bool = true; - - let one = F::Int::ONE; - let zero = F::Int::ZERO; - let hw = F::BITS / 2; - let lo_mask = u32::MAX >> hw; - - let significand_bits = F::SIGNIFICAND_BITS; - let max_exponent = F::EXPONENT_MAX; - - let exponent_bias = F::EXPONENT_BIAS; - - let implicit_bit = F::IMPLICIT_BIT; - let significand_mask = F::SIGNIFICAND_MASK; - let sign_bit = F::SIGN_MASK as F::Int; - let abs_mask = sign_bit - one; - let exponent_mask = F::EXPONENT_MASK; - let inf_rep = exponent_mask; - let quiet_bit = implicit_bit >> 1; - let qnan_rep = exponent_mask | quiet_bit; - - #[inline(always)] - fn negate_u32(a: u32) -> u32 { - (::wrapping_neg(a as i32)) as u32 - } - - let a_rep = a.repr(); - let b_rep = b.repr(); - - let a_exponent = (a_rep >> significand_bits) & max_exponent.cast(); - let b_exponent = (b_rep >> significand_bits) & max_exponent.cast(); - let quotient_sign = (a_rep ^ b_rep) & sign_bit; - - let mut a_significand = a_rep & significand_mask; - let mut b_significand = b_rep & significand_mask; - let mut scale = 0; - - // Detect if a or b is zero, denormal, infinity, or NaN. - if a_exponent.wrapping_sub(one) >= (max_exponent - 1).cast() - || b_exponent.wrapping_sub(one) >= (max_exponent - 1).cast() - { - let a_abs = a_rep & abs_mask; - let b_abs = b_rep & abs_mask; - - // NaN / anything = qNaN - if a_abs > inf_rep { - return F::from_repr(a_rep | quiet_bit); - } - // anything / NaN = qNaN - if b_abs > inf_rep { - return F::from_repr(b_rep | quiet_bit); - } - - if a_abs == inf_rep { - if b_abs == inf_rep { - // infinity / infinity = NaN - return F::from_repr(qnan_rep); - } else { - // infinity / anything else = +/- infinity - return F::from_repr(a_abs | quotient_sign); - } - } - - // anything else / infinity = +/- 0 - if b_abs == inf_rep { - return F::from_repr(quotient_sign); - } - - if a_abs == zero { - if b_abs == zero { - // zero / zero = NaN - return F::from_repr(qnan_rep); - } else { - // zero / anything else = +/- zero - return F::from_repr(quotient_sign); - } - } - - // anything else / zero = +/- infinity - if b_abs == zero { - return F::from_repr(inf_rep | quotient_sign); - } - - // one or both of a or b is denormal, the other (if applicable) is a - // normal number. Renormalize one or both of a and b, and set scale to - // include the necessary exponent adjustment. - if a_abs < implicit_bit { - let (exponent, significand) = F::normalize(a_significand); - scale += exponent; - a_significand = significand; - } - - if b_abs < implicit_bit { - let (exponent, significand) = F::normalize(b_significand); - scale -= exponent; - b_significand = significand; - } - } - - // Set the implicit significand bit. If we fell through from the - // denormal path it was already set by normalize( ), but setting it twice - // won't hurt anything. - a_significand |= implicit_bit; - b_significand |= implicit_bit; - - let written_exponent: i32 = CastInto::::cast( - a_exponent - .wrapping_sub(b_exponent) - .wrapping_add(scale.cast()), - ) - .wrapping_add(exponent_bias) as i32; - let b_uq1 = b_significand << (F::BITS - significand_bits - 1); - - // Align the significand of b as a UQ1.(n-1) fixed-point number in the range - // [1.0, 2.0) and get a UQ0.n approximate reciprocal using a small minimax - // polynomial approximation: x0 = 3/4 + 1/sqrt(2) - b/2. - // The max error for this approximation is achieved at endpoints, so - // abs(x0(b) - 1/b) <= abs(x0(1) - 1/1) = 3/4 - 1/sqrt(2) = 0.04289..., - // which is about 4.5 bits. - // The initial approximation is between x0(1.0) = 0.9571... and x0(2.0) = 0.4571... - - // Then, refine the reciprocal estimate using a quadratically converging - // Newton-Raphson iteration: - // x_{n+1} = x_n * (2 - x_n * b) - // - // Let b be the original divisor considered "in infinite precision" and - // obtained from IEEE754 representation of function argument (with the - // implicit bit set). Corresponds to rep_t-sized b_UQ1 represented in - // UQ1.(W-1). - // - // Let b_hw be an infinitely precise number obtained from the highest (HW-1) - // bits of divisor significand (with the implicit bit set). Corresponds to - // half_rep_t-sized b_UQ1_hw represented in UQ1.(HW-1) that is a **truncated** - // version of b_UQ1. - // - // Let e_n := x_n - 1/b_hw - // E_n := x_n - 1/b - // abs(E_n) <= abs(e_n) + (1/b_hw - 1/b) - // = abs(e_n) + (b - b_hw) / (b*b_hw) - // <= abs(e_n) + 2 * 2^-HW - - // rep_t-sized iterations may be slower than the corresponding half-width - // variant depending on the handware and whether single/double/quad precision - // is selected. - // NB: Using half-width iterations increases computation errors due to - // rounding, so error estimations have to be computed taking the selected - // mode into account! - - #[allow(clippy::absurd_extreme_comparisons)] - let mut x_uq0 = if NUMBER_OF_HALF_ITERATIONS > 0 { - // Starting with (n-1) half-width iterations - let b_uq1_hw: u16 = - (CastInto::::cast(b_significand) >> (significand_bits + 1 - hw)) as u16; - - // C is (3/4 + 1/sqrt(2)) - 1 truncated to W0 fractional bits as UQ0.HW - // with W0 being either 16 or 32 and W0 <= HW. - // That is, C is the aforementioned 3/4 + 1/sqrt(2) constant (from which - // b/2 is subtracted to obtain x0) wrapped to [0, 1) range. - - // HW is at least 32. Shifting into the highest bits if needed. - let c_hw = (0x7504_u32 as u16).wrapping_shl(hw.wrapping_sub(32)); - - // b >= 1, thus an upper bound for 3/4 + 1/sqrt(2) - b/2 is about 0.9572, - // so x0 fits to UQ0.HW without wrapping. - let x_uq0_hw: u16 = { - let mut x_uq0_hw: u16 = c_hw.wrapping_sub(b_uq1_hw /* exact b_hw/2 as UQ0.HW */); - // An e_0 error is comprised of errors due to - // * x0 being an inherently imprecise first approximation of 1/b_hw - // * C_hw being some (irrational) number **truncated** to W0 bits - // Please note that e_0 is calculated against the infinitely precise - // reciprocal of b_hw (that is, **truncated** version of b). - // - // e_0 <= 3/4 - 1/sqrt(2) + 2^-W0 - - // By construction, 1 <= b < 2 - // f(x) = x * (2 - b*x) = 2*x - b*x^2 - // f'(x) = 2 * (1 - b*x) - // - // On the [0, 1] interval, f(0) = 0, - // then it increses until f(1/b) = 1 / b, maximum on (0, 1), - // then it decreses to f(1) = 2 - b - // - // Let g(x) = x - f(x) = b*x^2 - x. - // On (0, 1/b), g(x) < 0 <=> f(x) > x - // On (1/b, 1], g(x) > 0 <=> f(x) < x - // - // For half-width iterations, b_hw is used instead of b. - #[allow(clippy::reversed_empty_ranges)] - for _ in 0..NUMBER_OF_HALF_ITERATIONS { - // corr_UQ1_hw can be **larger** than 2 - b_hw*x by at most 1*Ulp - // of corr_UQ1_hw. - // "0.0 - (...)" is equivalent to "2.0 - (...)" in UQ1.(HW-1). - // On the other hand, corr_UQ1_hw should not overflow from 2.0 to 0.0 provided - // no overflow occurred earlier: ((rep_t)x_UQ0_hw * b_UQ1_hw >> HW) is - // expected to be strictly positive because b_UQ1_hw has its highest bit set - // and x_UQ0_hw should be rather large (it converges to 1/2 < 1/b_hw <= 1). - let corr_uq1_hw: u16 = - 0.wrapping_sub((x_uq0_hw as u32).wrapping_mul(b_uq1_hw.cast()) >> hw) as u16; - - // Now, we should multiply UQ0.HW and UQ1.(HW-1) numbers, naturally - // obtaining an UQ1.(HW-1) number and proving its highest bit could be - // considered to be 0 to be able to represent it in UQ0.HW. - // From the above analysis of f(x), if corr_UQ1_hw would be represented - // without any intermediate loss of precision (that is, in twice_rep_t) - // x_UQ0_hw could be at most [1.]000... if b_hw is exactly 1.0 and strictly - // less otherwise. On the other hand, to obtain [1.]000..., one have to pass - // 1/b_hw == 1.0 to f(x), so this cannot occur at all without overflow (due - // to 1.0 being not representable as UQ0.HW). - // The fact corr_UQ1_hw was virtually round up (due to result of - // multiplication being **first** truncated, then negated - to improve - // error estimations) can increase x_UQ0_hw by up to 2*Ulp of x_UQ0_hw. - x_uq0_hw = ((x_uq0_hw as u32).wrapping_mul(corr_uq1_hw as u32) >> (hw - 1)) as u16; - // Now, either no overflow occurred or x_UQ0_hw is 0 or 1 in its half_rep_t - // representation. In the latter case, x_UQ0_hw will be either 0 or 1 after - // any number of iterations, so just subtract 2 from the reciprocal - // approximation after last iteration. - - // In infinite precision, with 0 <= eps1, eps2 <= U = 2^-HW: - // corr_UQ1_hw = 2 - (1/b_hw + e_n) * b_hw + 2*eps1 - // = 1 - e_n * b_hw + 2*eps1 - // x_UQ0_hw = (1/b_hw + e_n) * (1 - e_n*b_hw + 2*eps1) - eps2 - // = 1/b_hw - e_n + 2*eps1/b_hw + e_n - e_n^2*b_hw + 2*e_n*eps1 - eps2 - // = 1/b_hw + 2*eps1/b_hw - e_n^2*b_hw + 2*e_n*eps1 - eps2 - // e_{n+1} = -e_n^2*b_hw + 2*eps1/b_hw + 2*e_n*eps1 - eps2 - // = 2*e_n*eps1 - (e_n^2*b_hw + eps2) + 2*eps1/b_hw - // \------ >0 -------/ \-- >0 ---/ - // abs(e_{n+1}) <= 2*abs(e_n)*U + max(2*e_n^2 + U, 2 * U) - } - // For initial half-width iterations, U = 2^-HW - // Let abs(e_n) <= u_n * U, - // then abs(e_{n+1}) <= 2 * u_n * U^2 + max(2 * u_n^2 * U^2 + U, 2 * U) - // u_{n+1} <= 2 * u_n * U + max(2 * u_n^2 * U + 1, 2) - - // Account for possible overflow (see above). For an overflow to occur for the - // first time, for "ideal" corr_UQ1_hw (that is, without intermediate - // truncation), the result of x_UQ0_hw * corr_UQ1_hw should be either maximum - // value representable in UQ0.HW or less by 1. This means that 1/b_hw have to - // be not below that value (see g(x) above), so it is safe to decrement just - // once after the final iteration. On the other hand, an effective value of - // divisor changes after this point (from b_hw to b), so adjust here. - x_uq0_hw.wrapping_sub(1_u16) - }; - - // Error estimations for full-precision iterations are calculated just - // as above, but with U := 2^-W and taking extra decrementing into account. - // We need at least one such iteration. - - // Simulating operations on a twice_rep_t to perform a single final full-width - // iteration. Using ad-hoc multiplication implementations to take advantage - // of particular structure of operands. - - let blo: u32 = (CastInto::::cast(b_uq1)) & lo_mask; - // x_UQ0 = x_UQ0_hw * 2^HW - 1 - // x_UQ0 * b_UQ1 = (x_UQ0_hw * 2^HW) * (b_UQ1_hw * 2^HW + blo) - b_UQ1 - // - // <--- higher half ---><--- lower half ---> - // [x_UQ0_hw * b_UQ1_hw] - // + [ x_UQ0_hw * blo ] - // - [ b_UQ1 ] - // = [ result ][.... discarded ...] - let corr_uq1 = negate_u32( - (x_uq0_hw as u32) * (b_uq1_hw as u32) + (((x_uq0_hw as u32) * (blo)) >> hw) - 1, - ); // account for *possible* carry - let lo_corr = corr_uq1 & lo_mask; - let hi_corr = corr_uq1 >> hw; - // x_UQ0 * corr_UQ1 = (x_UQ0_hw * 2^HW) * (hi_corr * 2^HW + lo_corr) - corr_UQ1 - let mut x_uq0: ::Int = ((((x_uq0_hw as u32) * hi_corr) << 1) - .wrapping_add(((x_uq0_hw as u32) * lo_corr) >> (hw - 1)) - .wrapping_sub(2)) - .cast(); // 1 to account for the highest bit of corr_UQ1 can be 1 - // 1 to account for possible carry - // Just like the case of half-width iterations but with possibility - // of overflowing by one extra Ulp of x_UQ0. - x_uq0 -= one; - // ... and then traditional fixup by 2 should work - - // On error estimation: - // abs(E_{N-1}) <= (u_{N-1} + 2 /* due to conversion e_n -> E_n */) * 2^-HW - // + (2^-HW + 2^-W)) - // abs(E_{N-1}) <= (u_{N-1} + 3.01) * 2^-HW - - // Then like for the half-width iterations: - // With 0 <= eps1, eps2 < 2^-W - // E_N = 4 * E_{N-1} * eps1 - (E_{N-1}^2 * b + 4 * eps2) + 4 * eps1 / b - // abs(E_N) <= 2^-W * [ 4 * abs(E_{N-1}) + max(2 * abs(E_{N-1})^2 * 2^W + 4, 8)) ] - // abs(E_N) <= 2^-W * [ 4 * (u_{N-1} + 3.01) * 2^-HW + max(4 + 2 * (u_{N-1} + 3.01)^2, 8) ] - x_uq0 - } else { - // C is (3/4 + 1/sqrt(2)) - 1 truncated to 32 fractional bits as UQ0.n - let c: ::Int = (0x7504F333 << (F::BITS - 32)).cast(); - let x_uq0: ::Int = c.wrapping_sub(b_uq1); - // E_0 <= 3/4 - 1/sqrt(2) + 2 * 2^-32 - x_uq0 - }; - - let mut x_uq0 = if USE_NATIVE_FULL_ITERATIONS { - for _ in 0..NUMBER_OF_FULL_ITERATIONS { - let corr_uq1: u32 = 0.wrapping_sub( - ((CastInto::::cast(x_uq0) as u64) * (CastInto::::cast(b_uq1) as u64)) - >> F::BITS, - ) as u32; - x_uq0 = ((((CastInto::::cast(x_uq0) as u64) * (corr_uq1 as u64)) >> (F::BITS - 1)) - as u32) - .cast(); - } - x_uq0 - } else { - // not using native full iterations - x_uq0 - }; - - // Finally, account for possible overflow, as explained above. - x_uq0 = x_uq0.wrapping_sub(2.cast()); - - // u_n for different precisions (with N-1 half-width iterations): - // W0 is the precision of C - // u_0 = (3/4 - 1/sqrt(2) + 2^-W0) * 2^HW - - // Estimated with bc: - // define half1(un) { return 2.0 * (un + un^2) / 2.0^hw + 1.0; } - // define half2(un) { return 2.0 * un / 2.0^hw + 2.0; } - // define full1(un) { return 4.0 * (un + 3.01) / 2.0^hw + 2.0 * (un + 3.01)^2 + 4.0; } - // define full2(un) { return 4.0 * (un + 3.01) / 2.0^hw + 8.0; } - - // | f32 (0 + 3) | f32 (2 + 1) | f64 (3 + 1) | f128 (4 + 1) - // u_0 | < 184224974 | < 2812.1 | < 184224974 | < 791240234244348797 - // u_1 | < 15804007 | < 242.7 | < 15804007 | < 67877681371350440 - // u_2 | < 116308 | < 2.81 | < 116308 | < 499533100252317 - // u_3 | < 7.31 | | < 7.31 | < 27054456580 - // u_4 | | | | < 80.4 - // Final (U_N) | same as u_3 | < 72 | < 218 | < 13920 - - // Add 2 to U_N due to final decrement. - - let reciprocal_precision: ::Int = 10.cast(); - - // Suppose 1/b - P * 2^-W < x < 1/b + P * 2^-W - let x_uq0 = x_uq0 - reciprocal_precision; - // Now 1/b - (2*P) * 2^-W < x < 1/b - // FIXME Is x_UQ0 still >= 0.5? - - let mut quotient: ::Int = x_uq0.widen_mul(a_significand << 1).hi(); - // Now, a/b - 4*P * 2^-W < q < a/b for q= in UQ1.(SB+1+W). - - // quotient_UQ1 is in [0.5, 2.0) as UQ1.(SB+1), - // adjust it to be in [1.0, 2.0) as UQ1.SB. - let (mut residual, written_exponent) = if quotient < (implicit_bit << 1) { - // Highest bit is 0, so just reinterpret quotient_UQ1 as UQ1.SB, - // effectively doubling its value as well as its error estimation. - let residual_lo = (a_significand << (significand_bits + 1)).wrapping_sub( - (CastInto::::cast(quotient).wrapping_mul(CastInto::::cast(b_significand))) - .cast(), - ); - a_significand <<= 1; - (residual_lo, written_exponent.wrapping_sub(1)) - } else { - // Highest bit is 1 (the UQ1.(SB+1) value is in [1, 2)), convert it - // to UQ1.SB by right shifting by 1. Least significant bit is omitted. - quotient >>= 1; - let residual_lo = (a_significand << significand_bits).wrapping_sub( - (CastInto::::cast(quotient).wrapping_mul(CastInto::::cast(b_significand))) - .cast(), - ); - (residual_lo, written_exponent) - }; - - //drop mutability - let quotient = quotient; - - // NB: residualLo is calculated above for the normal result case. - // It is re-computed on denormal path that is expected to be not so - // performance-sensitive. - - // Now, q cannot be greater than a/b and can differ by at most 8*P * 2^-W + 2^-SB - // Each NextAfter() increments the floating point value by at least 2^-SB - // (more, if exponent was incremented). - // Different cases (<---> is of 2^-SB length, * = a/b that is shown as a midpoint): - // q - // | | * | | | | | - // <---> 2^t - // | | | | | * | | - // q - // To require at most one NextAfter(), an error should be less than 1.5 * 2^-SB. - // (8*P) * 2^-W + 2^-SB < 1.5 * 2^-SB - // (8*P) * 2^-W < 0.5 * 2^-SB - // P < 2^(W-4-SB) - // Generally, for at most R NextAfter() to be enough, - // P < (2*R - 1) * 2^(W-4-SB) - // For f32 (0+3): 10 < 32 (OK) - // For f32 (2+1): 32 < 74 < 32 * 3, so two NextAfter() are required - // For f64: 220 < 256 (OK) - // For f128: 4096 * 3 < 13922 < 4096 * 5 (three NextAfter() are required) - - // If we have overflowed the exponent, return infinity - if written_exponent >= max_exponent as i32 { - return F::from_repr(inf_rep | quotient_sign); - } - - // Now, quotient <= the correctly-rounded result - // and may need taking NextAfter() up to 3 times (see error estimates above) - // r = a - b * q - let abs_result = if written_exponent > 0 { - let mut ret = quotient & significand_mask; - ret |= ((written_exponent as u32) << significand_bits).cast(); - residual <<= 1; - ret - } else { - if (significand_bits as i32 + written_exponent) < 0 { - return F::from_repr(quotient_sign); - } - let ret = quotient.wrapping_shr(negate_u32(CastInto::::cast(written_exponent)) + 1); - residual = (CastInto::::cast( - a_significand.wrapping_shl( - significand_bits.wrapping_add(CastInto::::cast(written_exponent)), - ), - ) - .wrapping_sub( - (CastInto::::cast(ret).wrapping_mul(CastInto::::cast(b_significand))) << 1, - )) - .cast(); - ret - }; - // Round - let abs_result = { - residual += abs_result & one; // tie to even - // The above line conditionally turns the below LT comparison into LTE - - if residual > b_significand { - abs_result + one - } else { - abs_result - } - }; - F::from_repr(abs_result | quotient_sign) -} - -fn div64(a: F, b: F) -> F +fn div(a: F, b: F) -> F where - F::Int: CastInto, F::Int: CastInto, - F::Int: CastInto>, F::Int: From>, F::Int: From, - F::Int: CastInto, - F::Int: CastInto, F::Int: HInt + DInt, + ::D: ops::Shr::D>, + F::Int: From, u16: CastInto, i32: CastInto, - i64: CastInto, u32: CastInto, - u64: CastInto, - u64: CastInto>, + u128: CastInto>, { - const NUMBER_OF_HALF_ITERATIONS: usize = 3; - const NUMBER_OF_FULL_ITERATIONS: usize = 1; - const USE_NATIVE_FULL_ITERATIONS: bool = false; - let one = F::Int::ONE; let zero = F::Int::ZERO; + let one_hw = HalfRep::::ONE; + let zero_hw = HalfRep::::ZERO; let hw = F::BITS / 2; let lo_mask = F::Int::MAX >> hw; let significand_bits = F::SIGNIFICAND_BITS; - let max_exponent = F::EXPONENT_MAX; + // Saturated exponent, representing infinity + let exponent_sat: F::Int = F::EXPONENT_MAX.cast(); let exponent_bias = F::EXPONENT_BIAS; - let implicit_bit = F::IMPLICIT_BIT; let significand_mask = F::SIGNIFICAND_MASK; - let sign_bit = F::SIGN_MASK as F::Int; + let sign_bit = F::SIGN_MASK; let abs_mask = sign_bit - one; let exponent_mask = F::EXPONENT_MASK; let inf_rep = exponent_mask; let quiet_bit = implicit_bit >> 1; let qnan_rep = exponent_mask | quiet_bit; + let (mut half_iterations, full_iterations) = get_iterations::(); + let recip_precision = reciprocal_precision::(); - #[inline(always)] - fn negate_u64(a: u64) -> u64 { - (::wrapping_neg(a as i64)) as u64 + if F::BITS == 128 { + // FIXME(tgross35): f128 seems to require one more half iteration than expected + half_iterations += 1; } let a_rep = a.repr(); let b_rep = b.repr(); - let a_exponent = (a_rep >> significand_bits) & max_exponent.cast(); - let b_exponent = (b_rep >> significand_bits) & max_exponent.cast(); + // Exponent numeric representationm not accounting for bias + let a_exponent = (a_rep >> significand_bits) & exponent_sat; + let b_exponent = (b_rep >> significand_bits) & exponent_sat; let quotient_sign = (a_rep ^ b_rep) & sign_bit; let mut a_significand = a_rep & significand_mask; let mut b_significand = b_rep & significand_mask; - let mut scale = 0; + + // The exponent of our final result in its encoded form + let mut res_exponent: i32 = + i32::cast_from(a_exponent) - i32::cast_from(b_exponent) + (exponent_bias as i32); // Detect if a or b is zero, denormal, infinity, or NaN. - if a_exponent.wrapping_sub(one) >= (max_exponent - 1).cast() - || b_exponent.wrapping_sub(one) >= (max_exponent - 1).cast() + if a_exponent.wrapping_sub(one) >= (exponent_sat - one) + || b_exponent.wrapping_sub(one) >= (exponent_sat - one) { let a_abs = a_rep & abs_mask; let b_abs = b_rep & abs_mask; @@ -521,6 +152,7 @@ where if a_abs > inf_rep { return F::from_repr(a_rep | quiet_bit); } + // anything / NaN = qNaN if b_abs > inf_rep { return F::from_repr(b_rep | quiet_bit); @@ -556,34 +188,31 @@ where return F::from_repr(inf_rep | quotient_sign); } - // one or both of a or b is denormal, the other (if applicable) is a - // normal number. Renormalize one or both of a and b, and set scale to - // include the necessary exponent adjustment. + // a is denormal. Renormalize it and set the scale to include the necessary exponent + // adjustment. if a_abs < implicit_bit { let (exponent, significand) = F::normalize(a_significand); - scale += exponent; + res_exponent += exponent; a_significand = significand; } + // b is denormal. Renormalize it and set the scale to include the necessary exponent + // adjustment. if b_abs < implicit_bit { let (exponent, significand) = F::normalize(b_significand); - scale -= exponent; + res_exponent -= exponent; b_significand = significand; } } - // Set the implicit significand bit. If we fell through from the + // Set the implicit significand bit. If we fell through from the // denormal path it was already set by normalize( ), but setting it twice // won't hurt anything. a_significand |= implicit_bit; b_significand |= implicit_bit; - let written_exponent: i64 = CastInto::::cast( - a_exponent - .wrapping_sub(b_exponent) - .wrapping_add(scale.cast()), - ) - .wrapping_add(exponent_bias as u64) as i64; + // Transform to a fixed-point representation by shifting the significand to the high bits. We + // know this is in the range [1.0, 2.0] since the implicit bit is set to 1 above. let b_uq1 = b_significand << (F::BITS - significand_bits - 1); // Align the significand of b as a UQ1.(n-1) fixed-point number in the range @@ -593,7 +222,7 @@ where // abs(x0(b) - 1/b) <= abs(x0(1) - 1/1) = 3/4 - 1/sqrt(2) = 0.04289..., // which is about 4.5 bits. // The initial approximation is between x0(1.0) = 0.9571... and x0(2.0) = 0.4571... - + // // Then, refine the reciprocal estimate using a quadratically converging // Newton-Raphson iteration: // x_{n+1} = x_n * (2 - x_n * b) @@ -613,123 +242,116 @@ where // abs(E_n) <= abs(e_n) + (1/b_hw - 1/b) // = abs(e_n) + (b - b_hw) / (b*b_hw) // <= abs(e_n) + 2 * 2^-HW - + // // rep_t-sized iterations may be slower than the corresponding half-width // variant depending on the handware and whether single/double/quad precision // is selected. + // // NB: Using half-width iterations increases computation errors due to // rounding, so error estimations have to be computed taking the selected // mode into account! - - let mut x_uq0 = if NUMBER_OF_HALF_ITERATIONS > 0 { + let mut x_uq0 = if half_iterations > 0 { // Starting with (n-1) half-width iterations - let b_uq1_hw: HalfRep = CastInto::>::cast( - CastInto::::cast(b_significand) >> (significand_bits + 1 - hw), - ); + let b_uq1_hw: HalfRep = b_uq1.hi(); // C is (3/4 + 1/sqrt(2)) - 1 truncated to W0 fractional bits as UQ0.HW // with W0 being either 16 or 32 and W0 <= HW. // That is, C is the aforementioned 3/4 + 1/sqrt(2) constant (from which // b/2 is subtracted to obtain x0) wrapped to [0, 1) range. + let c_hw = c_hw::(); - // HW is at least 32. Shifting into the highest bits if needed. - let c_hw = (CastInto::>::cast(0x7504F333_u64)).wrapping_shl(hw.wrapping_sub(32)); + // Check that the top bit is set, i.e. value is within `[1, 2)`. + debug_assert!(b_uq1_hw & one_hw << (HalfRep::::BITS - 1) > zero_hw); // b >= 1, thus an upper bound for 3/4 + 1/sqrt(2) - b/2 is about 0.9572, // so x0 fits to UQ0.HW without wrapping. - let x_uq0_hw: HalfRep = { - let mut x_uq0_hw: HalfRep = - c_hw.wrapping_sub(b_uq1_hw /* exact b_hw/2 as UQ0.HW */); - // dbg!(x_uq0_hw); - // An e_0 error is comprised of errors due to - // * x0 being an inherently imprecise first approximation of 1/b_hw - // * C_hw being some (irrational) number **truncated** to W0 bits - // Please note that e_0 is calculated against the infinitely precise - // reciprocal of b_hw (that is, **truncated** version of b). - // - // e_0 <= 3/4 - 1/sqrt(2) + 2^-W0 - - // By construction, 1 <= b < 2 - // f(x) = x * (2 - b*x) = 2*x - b*x^2 - // f'(x) = 2 * (1 - b*x) + let mut x_uq0_hw: HalfRep = + c_hw.wrapping_sub(b_uq1_hw /* exact b_hw/2 as UQ0.HW */); + + // An e_0 error is comprised of errors due to + // * x0 being an inherently imprecise first approximation of 1/b_hw + // * C_hw being some (irrational) number **truncated** to W0 bits + // Please note that e_0 is calculated against the infinitely precise + // reciprocal of b_hw (that is, **truncated** version of b). + // + // e_0 <= 3/4 - 1/sqrt(2) + 2^-W0 + // + // By construction, 1 <= b < 2 + // f(x) = x * (2 - b*x) = 2*x - b*x^2 + // f'(x) = 2 * (1 - b*x) + // + // On the [0, 1] interval, f(0) = 0, + // then it increses until f(1/b) = 1 / b, maximum on (0, 1), + // then it decreses to f(1) = 2 - b + // + // Let g(x) = x - f(x) = b*x^2 - x. + // On (0, 1/b), g(x) < 0 <=> f(x) > x + // On (1/b, 1], g(x) > 0 <=> f(x) < x + // + // For half-width iterations, b_hw is used instead of b. + for _ in 0..half_iterations { + // corr_UQ1_hw can be **larger** than 2 - b_hw*x by at most 1*Ulp + // of corr_UQ1_hw. + // "0.0 - (...)" is equivalent to "2.0 - (...)" in UQ1.(HW-1). + // On the other hand, corr_UQ1_hw should not overflow from 2.0 to 0.0 provided + // no overflow occurred earlier: ((rep_t)x_UQ0_hw * b_UQ1_hw >> HW) is + // expected to be strictly positive because b_UQ1_hw has its highest bit set + // and x_UQ0_hw should be rather large (it converges to 1/2 < 1/b_hw <= 1). // - // On the [0, 1] interval, f(0) = 0, - // then it increses until f(1/b) = 1 / b, maximum on (0, 1), - // then it decreses to f(1) = 2 - b + // Now, we should multiply UQ0.HW and UQ1.(HW-1) numbers, naturally + // obtaining an UQ1.(HW-1) number and proving its highest bit could be + // considered to be 0 to be able to represent it in UQ0.HW. + // From the above analysis of f(x), if corr_UQ1_hw would be represented + // without any intermediate loss of precision (that is, in twice_rep_t) + // x_UQ0_hw could be at most [1.]000... if b_hw is exactly 1.0 and strictly + // less otherwise. On the other hand, to obtain [1.]000..., one have to pass + // 1/b_hw == 1.0 to f(x), so this cannot occur at all without overflow (due + // to 1.0 being not representable as UQ0.HW). + // The fact corr_UQ1_hw was virtually round up (due to result of + // multiplication being **first** truncated, then negated - to improve + // error estimations) can increase x_UQ0_hw by up to 2*Ulp of x_UQ0_hw. // - // Let g(x) = x - f(x) = b*x^2 - x. - // On (0, 1/b), g(x) < 0 <=> f(x) > x - // On (1/b, 1], g(x) > 0 <=> f(x) < x + // Now, either no overflow occurred or x_UQ0_hw is 0 or 1 in its half_rep_t + // representation. In the latter case, x_UQ0_hw will be either 0 or 1 after + // any number of iterations, so just subtract 2 from the reciprocal + // approximation after last iteration. // - // For half-width iterations, b_hw is used instead of b. - for _ in 0..NUMBER_OF_HALF_ITERATIONS { - // corr_UQ1_hw can be **larger** than 2 - b_hw*x by at most 1*Ulp - // of corr_UQ1_hw. - // "0.0 - (...)" is equivalent to "2.0 - (...)" in UQ1.(HW-1). - // On the other hand, corr_UQ1_hw should not overflow from 2.0 to 0.0 provided - // no overflow occurred earlier: ((rep_t)x_UQ0_hw * b_UQ1_hw >> HW) is - // expected to be strictly positive because b_UQ1_hw has its highest bit set - // and x_UQ0_hw should be rather large (it converges to 1/2 < 1/b_hw <= 1). - let corr_uq1_hw: HalfRep = CastInto::>::cast(zero.wrapping_sub( - ((F::Int::from(x_uq0_hw)).wrapping_mul(F::Int::from(b_uq1_hw))) >> hw, - )); - // dbg!(corr_uq1_hw); - - // Now, we should multiply UQ0.HW and UQ1.(HW-1) numbers, naturally - // obtaining an UQ1.(HW-1) number and proving its highest bit could be - // considered to be 0 to be able to represent it in UQ0.HW. - // From the above analysis of f(x), if corr_UQ1_hw would be represented - // without any intermediate loss of precision (that is, in twice_rep_t) - // x_UQ0_hw could be at most [1.]000... if b_hw is exactly 1.0 and strictly - // less otherwise. On the other hand, to obtain [1.]000..., one have to pass - // 1/b_hw == 1.0 to f(x), so this cannot occur at all without overflow (due - // to 1.0 being not representable as UQ0.HW). - // The fact corr_UQ1_hw was virtually round up (due to result of - // multiplication being **first** truncated, then negated - to improve - // error estimations) can increase x_UQ0_hw by up to 2*Ulp of x_UQ0_hw. - x_uq0_hw = ((F::Int::from(x_uq0_hw)).wrapping_mul(F::Int::from(corr_uq1_hw)) - >> (hw - 1)) - .cast(); - // dbg!(x_uq0_hw); - // Now, either no overflow occurred or x_UQ0_hw is 0 or 1 in its half_rep_t - // representation. In the latter case, x_UQ0_hw will be either 0 or 1 after - // any number of iterations, so just subtract 2 from the reciprocal - // approximation after last iteration. - - // In infinite precision, with 0 <= eps1, eps2 <= U = 2^-HW: - // corr_UQ1_hw = 2 - (1/b_hw + e_n) * b_hw + 2*eps1 - // = 1 - e_n * b_hw + 2*eps1 - // x_UQ0_hw = (1/b_hw + e_n) * (1 - e_n*b_hw + 2*eps1) - eps2 - // = 1/b_hw - e_n + 2*eps1/b_hw + e_n - e_n^2*b_hw + 2*e_n*eps1 - eps2 - // = 1/b_hw + 2*eps1/b_hw - e_n^2*b_hw + 2*e_n*eps1 - eps2 - // e_{n+1} = -e_n^2*b_hw + 2*eps1/b_hw + 2*e_n*eps1 - eps2 - // = 2*e_n*eps1 - (e_n^2*b_hw + eps2) + 2*eps1/b_hw - // \------ >0 -------/ \-- >0 ---/ - // abs(e_{n+1}) <= 2*abs(e_n)*U + max(2*e_n^2 + U, 2 * U) - } - // For initial half-width iterations, U = 2^-HW - // Let abs(e_n) <= u_n * U, - // then abs(e_{n+1}) <= 2 * u_n * U^2 + max(2 * u_n^2 * U^2 + U, 2 * U) - // u_{n+1} <= 2 * u_n * U + max(2 * u_n^2 * U + 1, 2) - - // Account for possible overflow (see above). For an overflow to occur for the - // first time, for "ideal" corr_UQ1_hw (that is, without intermediate - // truncation), the result of x_UQ0_hw * corr_UQ1_hw should be either maximum - // value representable in UQ0.HW or less by 1. This means that 1/b_hw have to - // be not below that value (see g(x) above), so it is safe to decrement just - // once after the final iteration. On the other hand, an effective value of - // divisor changes after this point (from b_hw to b), so adjust here. - x_uq0_hw.wrapping_sub(HalfRep::::ONE) - }; + // In infinite precision, with 0 <= eps1, eps2 <= U = 2^-HW: + // corr_UQ1_hw = 2 - (1/b_hw + e_n) * b_hw + 2*eps1 + // = 1 - e_n * b_hw + 2*eps1 + // x_UQ0_hw = (1/b_hw + e_n) * (1 - e_n*b_hw + 2*eps1) - eps2 + // = 1/b_hw - e_n + 2*eps1/b_hw + e_n - e_n^2*b_hw + 2*e_n*eps1 - eps2 + // = 1/b_hw + 2*eps1/b_hw - e_n^2*b_hw + 2*e_n*eps1 - eps2 + // e_{n+1} = -e_n^2*b_hw + 2*eps1/b_hw + 2*e_n*eps1 - eps2 + // = 2*e_n*eps1 - (e_n^2*b_hw + eps2) + 2*eps1/b_hw + // \------ >0 -------/ \-- >0 ---/ + // abs(e_{n+1}) <= 2*abs(e_n)*U + max(2*e_n^2 + U, 2 * U) + x_uq0_hw = next_guess(x_uq0_hw, b_uq1_hw); + } + + // For initial half-width iterations, U = 2^-HW + // Let abs(e_n) <= u_n * U, + // then abs(e_{n+1}) <= 2 * u_n * U^2 + max(2 * u_n^2 * U^2 + U, 2 * U) + // u_{n+1} <= 2 * u_n * U + max(2 * u_n^2 * U + 1, 2) + // + // Account for possible overflow (see above). For an overflow to occur for the + // first time, for "ideal" corr_UQ1_hw (that is, without intermediate + // truncation), the result of x_UQ0_hw * corr_UQ1_hw should be either maximum + // value representable in UQ0.HW or less by 1. This means that 1/b_hw have to + // be not below that value (see g(x) above), so it is safe to decrement just + // once after the final iteration. On the other hand, an effective value of + // divisor changes after this point (from b_hw to b), so adjust here. + x_uq0_hw = x_uq0_hw.wrapping_sub(one_hw); // Error estimations for full-precision iterations are calculated just // as above, but with U := 2^-W and taking extra decrementing into account. // We need at least one such iteration. - + // // Simulating operations on a twice_rep_t to perform a single final full-width // iteration. Using ad-hoc multiplication implementations to take advantage // of particular structure of operands. let blo: F::Int = b_uq1 & lo_mask; + // x_UQ0 = x_UQ0_hw * 2^HW - 1 // x_UQ0 * b_UQ1 = (x_UQ0_hw * 2^HW) * (b_UQ1_hw * 2^HW + blo) - b_UQ1 // @@ -742,16 +364,19 @@ where + ((F::Int::from(x_uq0_hw) * blo) >> hw)) .wrapping_sub(one) .wrapping_neg(); // account for *possible* carry + let lo_corr: F::Int = corr_uq1 & lo_mask; let hi_corr: F::Int = corr_uq1 >> hw; + // x_UQ0 * corr_UQ1 = (x_UQ0_hw * 2^HW) * (hi_corr * 2^HW + lo_corr) - corr_UQ1 let mut x_uq0: F::Int = ((F::Int::from(x_uq0_hw) * hi_corr) << 1) .wrapping_add((F::Int::from(x_uq0_hw) * lo_corr) >> (hw - 1)) + // 1 to account for the highest bit of corr_UQ1 can be 1 + // 1 to account for possible carry + // Just like the case of half-width iterations but with possibility + // of overflowing by one extra Ulp of x_UQ0. .wrapping_sub(F::Int::from(2u8)); - // 1 to account for the highest bit of corr_UQ1 can be 1 - // 1 to account for possible carry - // Just like the case of half-width iterations but with possibility - // of overflowing by one extra Ulp of x_UQ0. + x_uq0 -= one; // ... and then traditional fixup by 2 should work @@ -759,7 +384,7 @@ where // abs(E_{N-1}) <= (u_{N-1} + 2 /* due to conversion e_n -> E_n */) * 2^-HW // + (2^-HW + 2^-W)) // abs(E_{N-1}) <= (u_{N-1} + 3.01) * 2^-HW - + // // Then like for the half-width iterations: // With 0 <= eps1, eps2 < 2^-W // E_N = 4 * E_{N-1} * eps1 - (E_{N-1}^2 * b + 4 * eps2) + 4 * eps1 / b @@ -768,89 +393,54 @@ where x_uq0 } else { // C is (3/4 + 1/sqrt(2)) - 1 truncated to 64 fractional bits as UQ0.n - let c: F::Int = (0x7504F333 << (F::BITS - 32)).cast(); - let x_uq0: F::Int = c.wrapping_sub(b_uq1); - // E_0 <= 3/4 - 1/sqrt(2) + 2 * 2^-64 - x_uq0 - }; + let c: F::Int = F::Int::from(0x7504F333u32) << (F::BITS - 32); + let mut x_uq0: F::Int = c.wrapping_sub(b_uq1); - let mut x_uq0 = if USE_NATIVE_FULL_ITERATIONS { - for _ in 0..NUMBER_OF_FULL_ITERATIONS { - let corr_uq1: u64 = 0.wrapping_sub( - (CastInto::::cast(x_uq0) * (CastInto::::cast(b_uq1))) >> F::BITS, - ); - x_uq0 = ((((CastInto::::cast(x_uq0) as u128) * (corr_uq1 as u128)) - >> (F::BITS - 1)) as u64) - .cast(); + // E_0 <= 3/4 - 1/sqrt(2) + 2 * 2^-64 + // x_uq0 + for _ in 0..full_iterations { + x_uq0 = next_guess(x_uq0, b_uq1); } - x_uq0 - } else { - // not using native full iterations + x_uq0 }; // Finally, account for possible overflow, as explained above. x_uq0 = x_uq0.wrapping_sub(2.cast()); - // u_n for different precisions (with N-1 half-width iterations): - // W0 is the precision of C - // u_0 = (3/4 - 1/sqrt(2) + 2^-W0) * 2^HW - - // Estimated with bc: - // define half1(un) { return 2.0 * (un + un^2) / 2.0^hw + 1.0; } - // define half2(un) { return 2.0 * un / 2.0^hw + 2.0; } - // define full1(un) { return 4.0 * (un + 3.01) / 2.0^hw + 2.0 * (un + 3.01)^2 + 4.0; } - // define full2(un) { return 4.0 * (un + 3.01) / 2.0^hw + 8.0; } - - // | f32 (0 + 3) | f32 (2 + 1) | f64 (3 + 1) | f128 (4 + 1) - // u_0 | < 184224974 | < 2812.1 | < 184224974 | < 791240234244348797 - // u_1 | < 15804007 | < 242.7 | < 15804007 | < 67877681371350440 - // u_2 | < 116308 | < 2.81 | < 116308 | < 499533100252317 - // u_3 | < 7.31 | | < 7.31 | < 27054456580 - // u_4 | | | | < 80.4 - // Final (U_N) | same as u_3 | < 72 | < 218 | < 13920 - - // Add 2 to U_N due to final decrement. - - let reciprocal_precision: ::Int = 220.cast(); - // Suppose 1/b - P * 2^-W < x < 1/b + P * 2^-W - let x_uq0 = x_uq0 - reciprocal_precision; + x_uq0 -= recip_precision.cast(); + // Now 1/b - (2*P) * 2^-W < x < 1/b // FIXME Is x_UQ0 still >= 0.5? - let mut quotient: F::Int = x_uq0.widen_mul(a_significand << 1).hi(); + let mut quotient_uq1: F::Int = x_uq0.widen_mul(a_significand << 1).hi(); // Now, a/b - 4*P * 2^-W < q < a/b for q= in UQ1.(SB+1+W). // quotient_UQ1 is in [0.5, 2.0) as UQ1.(SB+1), // adjust it to be in [1.0, 2.0) as UQ1.SB. - let (mut residual, written_exponent) = if quotient < (implicit_bit << 1) { + let mut residual_lo = if quotient_uq1 < (implicit_bit << 1) { // Highest bit is 0, so just reinterpret quotient_UQ1 as UQ1.SB, // effectively doubling its value as well as its error estimation. - let residual_lo = (a_significand << (significand_bits + 1)).wrapping_sub( - (CastInto::::cast(quotient).wrapping_mul(CastInto::::cast(b_significand))) - .cast(), - ); + let residual_lo = (a_significand << (significand_bits + 1)) + .wrapping_sub(quotient_uq1.wrapping_mul(b_significand)); + res_exponent -= 1; a_significand <<= 1; - (residual_lo, written_exponent.wrapping_sub(1)) + residual_lo } else { // Highest bit is 1 (the UQ1.(SB+1) value is in [1, 2)), convert it // to UQ1.SB by right shifting by 1. Least significant bit is omitted. - quotient >>= 1; - let residual_lo = (a_significand << significand_bits).wrapping_sub( - (CastInto::::cast(quotient).wrapping_mul(CastInto::::cast(b_significand))) - .cast(), - ); - (residual_lo, written_exponent) + quotient_uq1 >>= 1; + (a_significand << significand_bits).wrapping_sub(quotient_uq1.wrapping_mul(b_significand)) }; - //drop mutability - let quotient = quotient; + // drop mutability + let quotient = quotient_uq1; // NB: residualLo is calculated above for the normal result case. // It is re-computed on denormal path that is expected to be not so // performance-sensitive. - + // // Now, q cannot be greater than a/b and can differ by at most 8*P * 2^-W + 2^-SB // Each NextAfter() increments the floating point value by at least 2^-SB // (more, if exponent was incremented). @@ -870,60 +460,161 @@ where // For f32 (2+1): 32 < 74 < 32 * 3, so two NextAfter() are required // For f64: 220 < 256 (OK) // For f128: 4096 * 3 < 13922 < 4096 * 5 (three NextAfter() are required) - + // // If we have overflowed the exponent, return infinity - if written_exponent >= max_exponent as i64 { + if res_exponent >= i32::cast_from(exponent_sat) { return F::from_repr(inf_rep | quotient_sign); } // Now, quotient <= the correctly-rounded result // and may need taking NextAfter() up to 3 times (see error estimates above) // r = a - b * q - let abs_result = if written_exponent > 0 { + let mut abs_result = if res_exponent > 0 { let mut ret = quotient & significand_mask; - ret |= written_exponent.cast() << significand_bits; - residual <<= 1; + ret |= F::Int::from(res_exponent as u32) << significand_bits; + residual_lo <<= 1; ret } else { - if (significand_bits as i64 + written_exponent) < 0 { + if ((significand_bits as i32) + res_exponent) < 0 { return F::from_repr(quotient_sign); } - let ret = - quotient.wrapping_shr((negate_u64(CastInto::::cast(written_exponent)) + 1) as u32); - residual = (CastInto::::cast( - a_significand.wrapping_shl( - significand_bits.wrapping_add(CastInto::::cast(written_exponent)), - ), - ) - .wrapping_sub( - (CastInto::::cast(ret).wrapping_mul(CastInto::::cast(b_significand))) << 1, - )) - .cast(); + + let ret = quotient.wrapping_shr(u32::cast_from(res_exponent.wrapping_neg()) + 1); + residual_lo = a_significand + .wrapping_shl(significand_bits.wrapping_add(CastInto::::cast(res_exponent))) + .wrapping_sub(ret.wrapping_mul(b_significand) << 1); ret }; - // Round - let abs_result = { - residual += abs_result & one; // tie to even - // conditionally turns the below LT comparison into LTE - if residual > b_significand { - abs_result + one - } else { - abs_result - } - }; + + residual_lo += abs_result & one; // tie to even + // conditionally turns the below LT comparison into LTE + abs_result += u8::from(residual_lo > b_significand).into(); + + if F::BITS == 128 || (F::BITS == 32 && half_iterations > 0) { + // Do not round Infinity to NaN + abs_result += + u8::from(abs_result < inf_rep && residual_lo > (2 + 1).cast() * b_significand).into(); + } + + if F::BITS == 128 { + abs_result += + u8::from(abs_result < inf_rep && residual_lo > (4 + 1).cast() * b_significand).into(); + } + F::from_repr(abs_result | quotient_sign) } +/// Calculate the number of iterations required for a float type's precision. +/// +/// This returns `(h, f)` where `h` is the number of iterations to be done using integers at half +/// the float's bit width, and `f` is the number of iterations done using integers of the float's +/// full width. This is further explained in the module documentation. +/// +/// # Requirements +/// +/// The initial estimate should have at least 8 bits of precision. If this is not true, results +/// will be inaccurate. +const fn get_iterations() -> (usize, usize) { + // Precision doubles with each iteration. Assume we start with 8 bits of precision. + let total_iterations = F::BITS.ilog2() as usize - 2; + + if 2 * size_of::() <= size_of::<*const ()>() { + // If widening multiplication will be efficient (uses word-sized integers), there is no + // reason to use half-sized iterations. + (0, total_iterations) + } else { + // Otherwise, do as many iterations as possible at half width. + (total_iterations - 1, 1) + } +} + +/// `u_n` for different precisions (with N-1 half-width iterations). +/// +/// W0 is the precision of C +/// u_0 = (3/4 - 1/sqrt(2) + 2^-W0) * 2^HW +/// +/// Estimated with bc: +/// +/// ```text +/// define half1(un) { return 2.0 * (un + un^2) / 2.0^hw + 1.0; } +/// define half2(un) { return 2.0 * un / 2.0^hw + 2.0; } +/// define full1(un) { return 4.0 * (un + 3.01) / 2.0^hw + 2.0 * (un + 3.01)^2 + 4.0; } +/// define full2(un) { return 4.0 * (un + 3.01) / 2.0^hw + 8.0; } +/// +/// | f32 (0 + 3) | f32 (2 + 1) | f64 (3 + 1) | f128 (4 + 1) +/// u_0 | < 184224974 | < 2812.1 | < 184224974 | < 791240234244348797 +/// u_1 | < 15804007 | < 242.7 | < 15804007 | < 67877681371350440 +/// u_2 | < 116308 | < 2.81 | < 116308 | < 499533100252317 +/// u_3 | < 7.31 | | < 7.31 | < 27054456580 +/// u_4 | | | | < 80.4 +/// Final (U_N) | same as u_3 | < 72 | < 218 | < 13920 +/// ```` +/// +/// Add 2 to `U_N` due to final decrement. +const fn reciprocal_precision() -> u16 { + let (half_iterations, full_iterations) = get_iterations::(); + + if full_iterations < 1 { + panic!("Must have at least one full iteration"); + } + + // FIXME(tgross35): calculate this programmatically + if F::BITS == 32 && half_iterations == 2 && full_iterations == 1 { + 74u16 + } else if F::BITS == 32 && half_iterations == 0 && full_iterations == 3 { + 10 + } else if F::BITS == 64 && half_iterations == 3 && full_iterations == 1 { + 220 + } else if F::BITS == 128 && half_iterations == 4 && full_iterations == 1 { + 13922 + } else { + panic!("Invalid number of iterations") + } +} + +/// The value of `C` adjusted to half width. +/// +/// C is (3/4 + 1/sqrt(2)) - 1 truncated to W0 fractional bits as UQ0.HW with W0 being either +/// 16 or 32 and W0 <= HW. That is, C is the aforementioned 3/4 + 1/sqrt(2) constant (from +/// which b/2 is subtracted to obtain x0) wrapped to [0, 1) range. +fn c_hw() -> HalfRep +where + F::Int: DInt, + u128: CastInto>, +{ + const C_U128: u128 = 0x7504f333f9de6108b2fb1366eaa6a542; + const { C_U128 >> (u128::BITS - >::BITS) }.cast() +} + +/// Perform one iteration at any width to approach `1/b`, given previous guess `x`. Returns +/// the next `x` as a UQ0 number. +/// +/// This is the `x_{n+1} = 2*x_n - b*x_n^2` algorithm, implemented as `x_n * (2 - b*x_n)`. It +/// uses widening multiplication to calculate the result with necessary precision. +fn next_guess(x_uq0: I, b_uq1: I) -> I +where + I: Int + HInt, + ::D: ops::Shr::D>, +{ + // `corr = 2 - b*x_n` + // + // This looks like `0 - b*x_n`. However, this works - in `UQ1`, `0.0 - x = 2.0 - x`. + let corr_uq1: I = I::ZERO.wrapping_sub(x_uq0.widen_mul(b_uq1).hi()); + + // `x_n * corr = x_n * (2 - b*x_n)` + (x_uq0.widen_mul(corr_uq1) >> (I::BITS - 1)).lo() +} + intrinsics! { #[avr_skip] #[arm_aeabi_alias = __aeabi_fdiv] pub extern "C" fn __divsf3(a: f32, b: f32) -> f32 { - div32(a, b) + div(a, b) } #[avr_skip] #[arm_aeabi_alias = __aeabi_ddiv] pub extern "C" fn __divdf3(a: f64, b: f64) -> f64 { - div64(a, b) + div(a, b) } } diff --git a/library/compiler-builtins/testcrate/tests/div_rem.rs b/library/compiler-builtins/testcrate/tests/div_rem.rs index 418e9c18937d2..2de61c707d810 100644 --- a/library/compiler-builtins/testcrate/tests/div_rem.rs +++ b/library/compiler-builtins/testcrate/tests/div_rem.rs @@ -115,7 +115,13 @@ macro_rules! float { fuzz_float_2(N, |x: $f, y: $f| { let quo0: $f = apfloat_fallback!($f, $apfloat_ty, $sys_available, Div::div, x, y); let quo1: $f = $fn(x, y); - #[cfg(not(target_arch = "arm"))] + + // ARM SIMD instructions always flush subnormals to zero + if cfg!(target_arch = "arm") && + ((Float::is_subnormal(quo0)) || Float::is_subnormal(quo1)) { + return; + } + if !Float::eq_repr(quo0, quo1) { panic!( "{}({:?}, {:?}): std: {:?}, builtins: {:?}", @@ -126,21 +132,6 @@ macro_rules! float { quo1 ); } - - // ARM SIMD instructions always flush subnormals to zero - #[cfg(target_arch = "arm")] - if !(Float::is_subnormal(quo0) || Float::is_subnormal(quo1)) { - if !Float::eq_repr(quo0, quo1) { - panic!( - "{}({:?}, {:?}): std: {:?}, builtins: {:?}", - stringify!($fn), - x, - y, - quo0, - quo1 - ); - } - } }); } )* From 764a177497f9cb27d788e5734b775053187607ac Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 19 Aug 2024 15:46:05 -0500 Subject: [PATCH 1322/4206] Add `f128` division Use the new generic division algorithm to expose `__divtf3` and `__divkf3`. --- library/compiler-builtins/README.md | 2 +- library/compiler-builtins/build.rs | 1 - .../compiler-builtins/examples/intrinsics.rs | 5 +++++ library/compiler-builtins/src/float/div.rs | 17 +++++++++++++++++ .../testcrate/tests/div_rem.rs | 16 ++++++++++++++++ 5 files changed, 39 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 46983a281eb08..06137f3c754b4 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -222,7 +222,7 @@ of being added to Rust. - [x] addtf3.c - [x] comparetf2.c -- [ ] divtf3.c +- [x] divtf3.c - [x] extenddftf2.c - [x] extendhfsf2.c - [x] extendhftf2.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 5ccff76e7c53c..3b2805f832810 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -526,7 +526,6 @@ mod c { ("__floatsitf", "floatsitf.c"), ("__floatunditf", "floatunditf.c"), ("__floatunsitf", "floatunsitf.c"), - ("__divtf3", "divtf3.c"), ("__powitf2", "powitf2.c"), ("__fe_getround", "fp_mode.c"), ("__fe_raise_inexact", "fp_mode.c"), diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 8bb70767376ec..6dcd3820f0d78 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -256,6 +256,10 @@ mod intrinsics { a * b } + pub fn divtf(a: f128, b: f128) -> f128 { + a / b + } + pub fn subtf(a: f128, b: f128) -> f128 { a - b } @@ -440,6 +444,7 @@ fn run() { bb(aeabi_uldivmod(bb(2), bb(3))); bb(ashlti3(bb(2), bb(2))); bb(ashrti3(bb(2), bb(2))); + bb(divtf(bb(2.), bb(2.))); bb(divti3(bb(2), bb(2))); bb(eqtf(bb(2.), bb(2.))); bb(extendhfdf(bb(2.))); diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index 4aec3418f4bc3..f085455fa3eba 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -617,4 +617,21 @@ intrinsics! { pub extern "C" fn __divdf3(a: f64, b: f64) -> f64 { div(a, b) } + + #[avr_skip] + #[ppc_alias = __divkf3] + #[cfg(not(feature = "no-f16-f128"))] + pub extern "C" fn __divtf3(a: f128, b: f128) -> f128 { + div(a, b) + } + + #[cfg(target_arch = "arm")] + pub extern "C" fn __divsf3vfp(a: f32, b: f32) -> f32 { + a / b + } + + #[cfg(target_arch = "arm")] + pub extern "C" fn __divdf3vfp(a: f64, b: f64) -> f64 { + a / b + } } diff --git a/library/compiler-builtins/testcrate/tests/div_rem.rs b/library/compiler-builtins/testcrate/tests/div_rem.rs index 2de61c707d810..ac87eb6302b6c 100644 --- a/library/compiler-builtins/testcrate/tests/div_rem.rs +++ b/library/compiler-builtins/testcrate/tests/div_rem.rs @@ -1,3 +1,4 @@ +#![feature(f128)] #![allow(unused_macros)] use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divmodti4}; @@ -146,4 +147,19 @@ mod float_div { f32, __divsf3, Single, all(); f64, __divdf3, Double, all(); } + + #[cfg(not(feature = "no-f16-f128"))] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + float! { + 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"))); + } + + #[cfg(not(feature = "no-f16-f128"))] + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + float! { + f128, __divkf3, Quad, not(feature = "no-sys-f128"); + } } From 4842bd6ab10b0d99c9e12c96490089e6edf4a3c8 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 19 Aug 2024 15:46:40 -0500 Subject: [PATCH 1323/4206] Add benchmarks for `f128` division --- .../testcrate/benches/float_div.rs | 29 +++++++++++++++++-- .../compiler-builtins/testcrate/src/bench.rs | 7 +++-- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/testcrate/benches/float_div.rs b/library/compiler-builtins/testcrate/benches/float_div.rs index 6ba439b042068..6a039a82a93c0 100644 --- a/library/compiler-builtins/testcrate/benches/float_div.rs +++ b/library/compiler-builtins/testcrate/benches/float_div.rs @@ -1,5 +1,7 @@ +#![cfg_attr(f128_enabled, feature(f128))] + use compiler_builtins::float::div; -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{criterion_main, Criterion}; use testcrate::float_bench; float_bench! { @@ -64,5 +66,28 @@ float_bench! { ], } -criterion_group!(float_div, div_f32, div_f64); +#[cfg(f128_enabled)] +float_bench! { + name: div_f128, + sig: (a: f128, b: f128) -> f128, + crate_fn: div::__divtf3, + crate_fn_ppc: div::__divkf3, + sys_fn: __divtf3, + sys_fn_ppc: __divkf3, + sys_available: not(feature = "no-sys-f128"), + asm: [] +} + +pub fn float_div() { + let mut criterion = Criterion::default().configure_from_args(); + + div_f32(&mut criterion); + div_f64(&mut criterion); + + #[cfg(f128_enabled)] + { + div_f128(&mut criterion); + } +} + criterion_main!(float_div); diff --git a/library/compiler-builtins/testcrate/src/bench.rs b/library/compiler-builtins/testcrate/src/bench.rs index 1d571a6cf3b5b..f831b5a665568 100644 --- a/library/compiler-builtins/testcrate/src/bench.rs +++ b/library/compiler-builtins/testcrate/src/bench.rs @@ -30,13 +30,14 @@ pub fn skip_sys_checks(test_name: &str) -> bool { // FIXME(f16_f128): system symbols have incorrect results // - const X86_NO_SSE_SKIPPED: &[&str] = - &["add_f128", "sub_f128", "mul_f128", "powi_f32", "powi_f64"]; + const X86_NO_SSE_SKIPPED: &[&str] = &[ + "add_f128", "sub_f128", "mul_f128", "div_f128", "powi_f32", "powi_f64", + ]; // FIXME(f16_f128): Wide multiply carry bug in `compiler-rt`, re-enable when nightly no longer // uses `compiler-rt` version. // - const AARCH64_SKIPPED: &[&str] = &["mul_f128"]; + const AARCH64_SKIPPED: &[&str] = &["mul_f128", "div_f128"]; // FIXME(llvm): system symbols have incorrect results on Windows // From d6d29197e46cea8e43e0cdfe64c60027278dba10 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 16:40:44 +0000 Subject: [PATCH 1324/4206] chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 1aa6e5668d9c8..fa89c152e5b6e 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.126" +version = "0.1.127" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 70d74bb7a431a19c2d20d2cdf100da789ab877df Mon Sep 17 00:00:00 2001 From: Artyom Tetyukhin <51746822+arttet@users.noreply.github.com> Date: Wed, 25 Sep 2024 18:21:36 +0400 Subject: [PATCH 1325/4206] Bump cc dependency --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index fa89c152e5b6e..86cddd24d6ec9 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -34,7 +34,7 @@ test = false core = { version = "1.0.0", optional = true, package = 'rustc-std-workspace-core' } [build-dependencies] -cc = { optional = true, version = "1.0" } +cc = { optional = true, version = "1.1" } [dev-dependencies] panic-handler = { path = 'crates/panic-handler' } From 1e5bf9e1661d18059948e73d6bde54ea7a547ebf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 14:37:03 +0000 Subject: [PATCH 1326/4206] chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 86cddd24d6ec9..7fd3b22300c8b 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.127" +version = "0.1.128" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 8c31ec9e7df736487be79280d3021ecca2ef85fa Mon Sep 17 00:00:00 2001 From: Davide Mor Date: Thu, 26 Sep 2024 15:17:47 +0200 Subject: [PATCH 1327/4206] Fixed `__divtf3` having wrong cfg for f128 --- library/compiler-builtins/src/float/div.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index f085455fa3eba..f125771a017ac 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -620,7 +620,7 @@ intrinsics! { #[avr_skip] #[ppc_alias = __divkf3] - #[cfg(not(feature = "no-f16-f128"))] + #[cfg(f128_enabled)] pub extern "C" fn __divtf3(a: f128, b: f128) -> f128 { div(a, b) } From 1649f72ea628d372f7c3f67f32b76d048e7d0472 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 27 Sep 2024 07:00:19 -0400 Subject: [PATCH 1328/4206] Revert "Bump cc dependency" --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 7fd3b22300c8b..75cebda89f9f6 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -34,7 +34,7 @@ test = false core = { version = "1.0.0", optional = true, package = 'rustc-std-workspace-core' } [build-dependencies] -cc = { optional = true, version = "1.1" } +cc = { optional = true, version = "1.0" } [dev-dependencies] panic-handler = { path = 'crates/panic-handler' } From c48926906a30cb858fd8e6177023db3d516dd727 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 27 Sep 2024 11:08:02 +0000 Subject: [PATCH 1329/4206] chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 75cebda89f9f6..670bcd74ad0b6 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.128" +version = "0.1.129" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 18b42ebb78fe378c179859136c0774e9c85da41e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 27 Sep 2024 00:01:01 -0400 Subject: [PATCH 1330/4206] Remove unneeded features A few of the features that we enable have been stabilized, others may have been needed at some point but are no longer required. Clean this up. --- library/compiler-builtins/examples/intrinsics.rs | 2 -- library/compiler-builtins/src/lib.rs | 6 ------ library/compiler-builtins/testcrate/tests/aeabi_memclr.rs | 1 - library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs | 1 - library/compiler-builtins/testcrate/tests/aeabi_memset.rs | 1 - 5 files changed, 11 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 6dcd3820f0d78..06d7723302713 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -4,12 +4,10 @@ // to link due to the missing intrinsic (symbol). #![allow(unused_features)] -#![allow(stable_features)] // bench_black_box feature is stable, leaving for backcompat #![allow(internal_features)] #![cfg_attr(thumb, no_main)] #![deny(dead_code)] #![feature(allocator_api)] -#![feature(bench_black_box)] #![feature(f128)] #![feature(f16)] #![feature(lang_items)] diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index b85f789fdd032..dea30a3c6ace6 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,18 +1,12 @@ #![cfg_attr(feature = "compiler-builtins", compiler_builtins)] -#![cfg_attr(not(feature = "no-asm"), feature(asm))] #![feature(abi_unadjusted)] #![feature(asm_experimental_arch)] -#![cfg_attr(not(feature = "no-asm"), feature(global_asm))] #![feature(cfg_target_has_atomic)] #![feature(compiler_builtins)] -#![feature(core_ffi_c)] #![feature(core_intrinsics)] -#![feature(inline_const)] -#![feature(lang_items)] #![feature(linkage)] #![feature(naked_functions)] #![feature(repr_simd)] -#![feature(c_unwind)] #![cfg_attr(f16_enabled, feature(f16))] #![cfg_attr(f128_enabled, feature(f128))] #![no_builtins] diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs b/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs index 59507693988c4..bfd15a391aab2 100644 --- a/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs +++ b/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs @@ -5,7 +5,6 @@ feature = "mem" ))] #![feature(compiler_builtins_lib)] -#![feature(lang_items)] #![no_std] extern crate compiler_builtins; diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs b/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs index 2d72dfbbaa6e0..c892c5aba0f74 100644 --- a/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs +++ b/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs @@ -5,7 +5,6 @@ feature = "mem" ))] #![feature(compiler_builtins_lib)] -#![feature(lang_items)] #![no_std] extern crate compiler_builtins; diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memset.rs b/library/compiler-builtins/testcrate/tests/aeabi_memset.rs index f03729bed35ad..34ab3acc78c16 100644 --- a/library/compiler-builtins/testcrate/tests/aeabi_memset.rs +++ b/library/compiler-builtins/testcrate/tests/aeabi_memset.rs @@ -5,7 +5,6 @@ feature = "mem" ))] #![feature(compiler_builtins_lib)] -#![feature(lang_items)] #![no_std] extern crate compiler_builtins; From 2a32f80cdc060eb55eb2abd5a9dccc297fb31b9a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 19 Aug 2024 17:31:23 -0400 Subject: [PATCH 1331/4206] Move `float_pow` tests to their own file --- .../testcrate/tests/float_pow.rs | 54 ++++++++++++++++++ .../compiler-builtins/testcrate/tests/misc.rs | 56 ------------------- 2 files changed, 54 insertions(+), 56 deletions(-) create mode 100644 library/compiler-builtins/testcrate/tests/float_pow.rs diff --git a/library/compiler-builtins/testcrate/tests/float_pow.rs b/library/compiler-builtins/testcrate/tests/float_pow.rs new file mode 100644 index 0000000000000..761a6611dda3e --- /dev/null +++ b/library/compiler-builtins/testcrate/tests/float_pow.rs @@ -0,0 +1,54 @@ +#![allow(unused_macros)] +#![cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] + +use testcrate::*; + +// This is approximate because of issues related to +// https://github.com/rust-lang/rust/issues/73920. +// TODO how do we resolve this indeterminacy? +macro_rules! pow { + ($($f:ty, $tolerance:expr, $fn:ident);*;) => { + $( + #[test] + fn $fn() { + use compiler_builtins::float::pow::$fn; + use compiler_builtins::float::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>::SIGNIFICAND_MASK; + let n = (n as <$f as Float>::SignedInt) >> <$f as Float>::SIGNIFICAND_BITS; + let n = n as i32; + let tmp0: $f = x.powi(n); + let tmp1: $f = $fn(x, n); + let (a, b) = if tmp0 < tmp1 { + (tmp0, tmp1) + } else { + (tmp1, tmp0) + }; + + let good = if a == b { + // handles infinity equality + true + } else if a < $tolerance { + b < $tolerance + } else { + let quo = b / a; + (quo < (1. + $tolerance)) && (quo > (1. - $tolerance)) + }; + + assert!( + good, + "{}({:?}, {:?}): std: {:?}, builtins: {:?}", + stringify!($fn), x, n, tmp0, tmp1 + ); + } + }); + } + )* + }; +} + +pow! { + f32, 1e-4, __powisf2; + f64, 1e-12, __powidf2; +} diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index f9431915b15d2..f5ac2ab7da1bb 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -207,59 +207,3 @@ fn bswap() { ); } } - -// This is approximate because of issues related to -// https://github.com/rust-lang/rust/issues/73920. -// TODO how do we resolve this indeterminacy? -macro_rules! pow { - ($($f:ty, $tolerance:expr, $fn:ident);*;) => { - $( - #[test] - fn $fn() { - use compiler_builtins::float::pow::$fn; - use compiler_builtins::float::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>::SIGNIFICAND_MASK; - let n = (n as <$f as Float>::SignedInt) >> <$f as Float>::SIGNIFICAND_BITS; - let n = n as i32; - let tmp0: $f = x.powi(n); - let tmp1: $f = $fn(x, n); - let (a, b) = if tmp0 < tmp1 { - (tmp0, tmp1) - } else { - (tmp1, tmp0) - }; - let good = { - if a == b { - // handles infinity equality - true - } else if a < $tolerance { - b < $tolerance - } else { - let quo = b / a; - (quo < (1. + $tolerance)) && (quo > (1. - $tolerance)) - } - }; - if !good { - panic!( - "{}({}, {}): std: {}, builtins: {}", - stringify!($fn), x, n, tmp0, tmp1 - ); - } - } - }); - } - )* - }; -} - -#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] -mod float_pow { - use super::*; - - pow! { - f32, 1e-4, __powisf2; - f64, 1e-12, __powidf2; - } -} From 606d971958936c77245d77b0ebd0cf09a2d461c2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 19 Aug 2024 17:32:42 -0400 Subject: [PATCH 1332/4206] Add support for `f128` integer exponentiation Create the symbol `__powitf2`. --- library/compiler-builtins/README.md | 2 +- library/compiler-builtins/build.rs | 1 - library/compiler-builtins/src/float/pow.rs | 9 +++++++ .../testcrate/tests/float_pow.rs | 24 ++++++++++++++++--- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 06137f3c754b4..985020f5a8f56 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -240,7 +240,7 @@ of being added to Rust. - [ ] floatunsitf.c - [ ] floatuntitf.c - [x] multf3.c -- [ ] powitf2.c +- [x] powitf2.c - [x] subtf3.c - [x] truncdfhf2.c - [x] truncsfhf2.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 3b2805f832810..df98688d16afd 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -526,7 +526,6 @@ mod c { ("__floatsitf", "floatsitf.c"), ("__floatunditf", "floatunditf.c"), ("__floatunsitf", "floatunsitf.c"), - ("__powitf2", "powitf2.c"), ("__fe_getround", "fp_mode.c"), ("__fe_raise_inexact", "fp_mode.c"), ]); diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/src/float/pow.rs index 3103fe6f6972c..dac768f7be3e5 100644 --- a/library/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/src/float/pow.rs @@ -35,4 +35,13 @@ intrinsics! { pub extern "C" fn __powidf2(a: f64, b: i32) -> f64 { pow(a, b) } + + #[avr_skip] + #[ppc_alias = __powikf2] + #[cfg(f128_enabled)] + // FIXME(f16_f128): MSVC cannot build these until `__divtf3` is available in nightly. + #[cfg(not(target_env = "msvc"))] + pub extern "C" fn __powitf2(a: f128, b: i32) -> f128 { + pow(a, b) + } } diff --git a/library/compiler-builtins/testcrate/tests/float_pow.rs b/library/compiler-builtins/testcrate/tests/float_pow.rs index 761a6611dda3e..d85ee99dfd307 100644 --- a/library/compiler-builtins/testcrate/tests/float_pow.rs +++ b/library/compiler-builtins/testcrate/tests/float_pow.rs @@ -1,4 +1,5 @@ #![allow(unused_macros)] +#![cfg_attr(f128_enabled, feature(f128))] #![cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] use testcrate::*; @@ -7,9 +8,12 @@ use testcrate::*; // https://github.com/rust-lang/rust/issues/73920. // TODO how do we resolve this indeterminacy? macro_rules! pow { - ($($f:ty, $tolerance:expr, $fn:ident);*;) => { + ($($f:ty, $tolerance:expr, $fn:ident, $sys_available:meta);*;) => { $( #[test] + // FIXME(apfloat): We skip tests if system symbols aren't available rather + // than providing a fallback, since `rustc_apfloat` does not provide `pow`. + #[cfg($sys_available)] fn $fn() { use compiler_builtins::float::pow::$fn; use compiler_builtins::float::Float; @@ -49,6 +53,20 @@ macro_rules! pow { } pow! { - f32, 1e-4, __powisf2; - f64, 1e-12, __powidf2; + f32, 1e-4, __powisf2, all(); + f64, 1e-12, __powidf2, all(); +} + +#[cfg(f128_enabled)] +// FIXME(f16_f128): MSVC cannot build these until `__divtf3` is available in nightly. +#[cfg(not(target_env = "msvc"))] +#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] +pow! { + f128, 1e-36, __powitf2, not(feature = "no-sys-f128"); +} + +#[cfg(f128_enabled)] +#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +pow! { + f128, 1e-36, __powikf2, not(feature = "no-sys-f128"); } From b2db9e8e897c97acf9baf394104faf6a6b62549f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 19 Aug 2024 17:37:41 -0400 Subject: [PATCH 1333/4206] Add a benchmark for `__powitf2` --- .../testcrate/benches/float_pow.rs | 31 +++++++++++++++++-- .../compiler-builtins/testcrate/src/bench.rs | 2 ++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/testcrate/benches/float_pow.rs b/library/compiler-builtins/testcrate/benches/float_pow.rs index 252f740120db2..46da3f25ceb74 100644 --- a/library/compiler-builtins/testcrate/benches/float_pow.rs +++ b/library/compiler-builtins/testcrate/benches/float_pow.rs @@ -1,5 +1,7 @@ +#![cfg_attr(f128_enabled, feature(f128))] + use compiler_builtins::float::pow; -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{criterion_main, Criterion}; use testcrate::float_bench; float_bench! { @@ -20,5 +22,28 @@ float_bench! { asm: [], } -criterion_group!(float_add, powi_f32, powi_f64); -criterion_main!(float_add); +// 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")))] +float_bench! { + name: powi_f128, + sig: (a: f128, b: i32) -> f128, + crate_fn: pow::__powitf2, + crate_fn_ppc: pow::__powikf2, + sys_fn: __powitf2, + sys_fn_ppc: __powikf2, + sys_available: not(feature = "no-sys-f128"), + asm: [] +} + +pub fn float_pow() { + let mut criterion = Criterion::default().configure_from_args(); + + powi_f32(&mut criterion); + powi_f64(&mut criterion); + + #[cfg(all(f128_enabled, not(feature = "no-sys-f128")))] + powi_f128(&mut criterion); +} + +criterion_main!(float_pow); diff --git a/library/compiler-builtins/testcrate/src/bench.rs b/library/compiler-builtins/testcrate/src/bench.rs index f831b5a665568..798be6579d6b9 100644 --- a/library/compiler-builtins/testcrate/src/bench.rs +++ b/library/compiler-builtins/testcrate/src/bench.rs @@ -360,3 +360,5 @@ impl_testio!(int i16, i32, i64, i128); impl_testio!(int u16, u32, u64, u128); impl_testio!((float, int)(f32, i32)); impl_testio!((float, int)(f64, i32)); +#[cfg(f128_enabled)] +impl_testio!((float, int)(f128, i32)); From 8a13ab7dfccc876a4442c24a4212eff9c0bbb49d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 28 Sep 2024 15:13:17 +0000 Subject: [PATCH 1334/4206] chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 670bcd74ad0b6..e84c5545e1967 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.129" +version = "0.1.130" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 4ae984cbce80966be33cfc9f229e8c62e659e122 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 28 Sep 2024 17:57:06 -0400 Subject: [PATCH 1335/4206] Resolve FIXMEs related to `f16` assembly We have a couple FIXMEs from before aarch64 `f16` assembly support existed. We have this available now, so resolve the notes here. --- .../testcrate/benches/float_extend.rs | 7 ++----- .../testcrate/benches/float_trunc.rs | 14 +++++--------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/testcrate/benches/float_extend.rs b/library/compiler-builtins/testcrate/benches/float_extend.rs index a9563741a68e0..a0cdaf48acab2 100644 --- a/library/compiler-builtins/testcrate/benches/float_extend.rs +++ b/library/compiler-builtins/testcrate/benches/float_extend.rs @@ -15,11 +15,10 @@ float_bench! { sys_available: not(feature = "no-sys-f16"), asm: [ #[cfg(target_arch = "aarch64")] { - // FIXME(f16_f128): remove `to_bits()` after f16 asm support (rust-lang/rust/#116909) let ret: f32; asm!( "fcvt {ret:s}, {a:h}", - a = in(vreg) a.to_bits(), + a = in(vreg) a, ret = lateout(vreg) ret, options(nomem, nostack, pure), ); @@ -96,9 +95,7 @@ pub fn float_extend() { extend_f16_f32(&mut criterion); #[cfg(f128_enabled)] - { - extend_f16_f128(&mut criterion); - } + extend_f16_f128(&mut criterion); } extend_f32_f64(&mut criterion); diff --git a/library/compiler-builtins/testcrate/benches/float_trunc.rs b/library/compiler-builtins/testcrate/benches/float_trunc.rs index 8d874e4b2e0b3..de9b5bf8c0bd1 100644 --- a/library/compiler-builtins/testcrate/benches/float_trunc.rs +++ b/library/compiler-builtins/testcrate/benches/float_trunc.rs @@ -14,8 +14,7 @@ float_bench! { sys_available: not(feature = "no-sys-f16"), asm: [ #[cfg(target_arch = "aarch64")] { - // FIXME(f16_f128): remove `from_bits()` after f16 asm support (rust-lang/rust/#116909) - let ret: u16; + let ret: f16; asm!( "fcvt {ret:h}, {a:s}", a = in(vreg) a, @@ -23,7 +22,7 @@ float_bench! { options(nomem, nostack, pure), ); - f16::from_bits(ret) + ret }; ], } @@ -37,8 +36,7 @@ float_bench! { sys_available: not(feature = "no-sys-f16"), asm: [ #[cfg(target_arch = "aarch64")] { - // FIXME(f16_f128): remove `from_bits()` after f16 asm support (rust-lang/rust/#116909) - let ret: u16; + let ret: f16; asm!( "fcvt {ret:h}, {a:d}", a = in(vreg) a, @@ -46,7 +44,7 @@ float_bench! { options(nomem, nostack, pure), ); - f16::from_bits(ret) + ret }; ], } @@ -138,9 +136,7 @@ pub fn float_trunc() { // FIXME(#655): `f16` tests disabled until we can bootstrap symbols #[cfg(f16_enabled)] #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] - { - trunc_f128_f16(&mut criterion); - } + trunc_f128_f16(&mut criterion); trunc_f128_f32(&mut criterion); trunc_f128_f64(&mut criterion); From e226c0dce5c610194ac1c2562318f3306b5ea742 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 28 Sep 2024 18:11:38 -0400 Subject: [PATCH 1336/4206] Ungate tests that were skipped due to a broken implementation The upstream issue [1] has been resolved so we can enable these tests again. [1]: https://github.com/rust-lang/compiler-builtins/issues/616 --- library/compiler-builtins/testcrate/src/bench.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/testcrate/src/bench.rs b/library/compiler-builtins/testcrate/src/bench.rs index 798be6579d6b9..f5da1f3ae50ed 100644 --- a/library/compiler-builtins/testcrate/src/bench.rs +++ b/library/compiler-builtins/testcrate/src/bench.rs @@ -82,12 +82,9 @@ pub fn skip_sys_checks(test_name: &str) -> bool { /// Still run benchmarks/tests but don't check correctness between compiler-builtins and /// assembly functions -pub fn skip_asm_checks(test_name: &str) -> bool { - // FIXME(f16_f128): rounding error - // - const SKIPPED: &[&str] = &["mul_f32", "mul_f64"]; - - SKIPPED.contains(&test_name) +pub fn skip_asm_checks(_test_name: &str) -> bool { + // Nothing to skip at this time + false } /// Create a comparison of the system symbol, compiler_builtins, and optionally handwritten From c6b434e5a3279244c48a84e74387cbacf35a419c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 28 Sep 2024 18:19:52 -0400 Subject: [PATCH 1337/4206] Revert "Temporarily `use define_rust_probestack;`" has been resolved. Remove the workaround that was introduced to suppress it. This reverts commit 254edbcad4cfd6a8af32e3297c1037d7984c3c49. --- library/compiler-builtins/src/probestack.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 46caf16768701..0c30384db385a 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -120,10 +120,6 @@ macro_rules! define_rust_probestack { }; } -// FIXME(rust-lang/rust#126984): Remove allow once lint is fixed -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -use define_rust_probestack; - // Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax, // ensuring that if any pages are unmapped we'll make a page fault. // From 85cd4c06608870bb9fcb4630adc6ea9348329695 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 28 Sep 2024 19:53:09 -0400 Subject: [PATCH 1338/4206] Fix some warnings from shellcheck --- library/compiler-builtins/ci/run-docker.sh | 14 +++++----- library/compiler-builtins/ci/run.sh | 31 +++++++++++++++------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 50ae9dc83a1f5..215ad71a3c165 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -14,7 +14,7 @@ run() { # will be owned by root mkdir -p target - if [ $(uname -s) = "Linux" ] && [ -z "${DOCKER_BASE_IMAGE:-}" ]; then + if [ "$(uname -s)" = "Linux" ] && [ -z "${DOCKER_BASE_IMAGE:-}" ]; then # Share the host rustc and target. Do this only on Linux and if the image # isn't overridden run_args=( @@ -43,19 +43,21 @@ run() { if [ "${GITHUB_ACTIONS:-}" = "true" ]; then # Enable Docker image caching on GHA - + build_cmd=("buildx" "build") build_args=( "--cache-from" "type=local,src=/tmp/.buildx-cache" "--cache-to" "type=local,dest=/tmp/.buildx-cache-new" - "${build_args[@]:-}" + # This is the beautiful bash syntax for expanding an array but neither + # raising an error nor returning an empty string if the array is empty. + "${build_args[@]:+"${build_args[@]}"}" "--load" ) fi - docker ${build_cmd[@]:-build} \ + docker "${build_cmd[@]:-build}" \ -t "builtins-$target" \ - ${build_args[@]:-} \ + "${build_args[@]:-}" \ "ci/docker/$target" docker run \ --rm \ @@ -64,7 +66,7 @@ run() { -e "CARGO_TARGET_DIR=/builtins-target" \ -v "$(pwd):/checkout:ro" \ -w /checkout \ - ${run_args[@]:-} \ + "${run_args[@]:-}" \ --init \ "builtins-$target" \ sh -c "$run_cmd" diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index dcbe1caf4ef4d..057cdb083f765 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -38,17 +38,24 @@ fi if [ "${TEST_VERBATIM:-}" = "1" ]; then verb_path=$(cmd.exe //C echo \\\\?\\%cd%\\testcrate\\target2) - cargo build --manifest-path testcrate/Cargo.toml --target $target --target-dir $verb_path --features c + cargo build --manifest-path testcrate/Cargo.toml \ + --target "$target" --target-dir "$verb_path" --features c fi -if [ -d /builtins-target ]; then - rlib_paths=/builtins-target/"${target}"/debug/deps/libcompiler_builtins-*.rlib -else - rlib_paths=target/"${target}"/debug/deps/libcompiler_builtins-*.rlib -fi +declare -a rlib_paths + +# Set the `rlib_paths` global array to a list of all compiler-builtins rlibs +update_rlib_paths() { + if [ -d /builtins-target ]; then + rlib_paths=( /builtins-target/"${target}"/debug/deps/libcompiler_builtins-*.rlib ) + else + rlib_paths=( target/"${target}"/debug/deps/libcompiler_builtins-*.rlib ) + fi +} # Remove any existing artifacts from previous tests that don't set #![compiler_builtins] -rm -f $rlib_paths +update_rlib_paths +rm -f "${rlib_paths[@]}" cargo build --target "$target" cargo build --target "$target" --release @@ -76,6 +83,7 @@ NM=$(find "$(rustc --print sysroot)" \( -name llvm-nm -o -name llvm-nm.exe \) ) if [ "$NM" = "" ]; then NM="${PREFIX}nm" fi + # i686-pc-windows-gnu tools have a dependency on some DLLs, so run it with # rustup run to ensure that those are in PATH. TOOLCHAIN="$(rustup show active-toolchain | sed 's/ (default)//')" @@ -84,11 +92,13 @@ if [[ "$TOOLCHAIN" == *i686-pc-windows-gnu ]]; then fi # Look out for duplicated symbols when we include the compiler-rt (C) implementation -for rlib in $rlib_paths; do +update_rlib_paths +for rlib in "${rlib_paths[@]}"; do set +x echo "================================================================" echo "checking $rlib for duplicate symbols" echo "================================================================" + set -x duplicates_found=0 @@ -108,7 +118,7 @@ for rlib in $rlib_paths; do fi done -rm -f $rlib_paths +rm -f "${rlib_paths[@]}" build_intrinsics() { cargo build --target "$target" -v --example intrinsics "$@" @@ -128,7 +138,8 @@ CARGO_PROFILE_RELEASE_LTO=true \ cargo build --target "$target" --example intrinsics --release # Ensure no references to any symbols from core -for rlib in $(echo $rlib_paths); do +update_rlib_paths +for rlib in "${rlib_paths[@]}"; do set +x echo "================================================================" echo "checking $rlib for references to core" From 0c97b10dc0034216bef6a81e02cd2b57773d387f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 2 Oct 2024 16:23:46 -0400 Subject: [PATCH 1339/4206] Add riscv64gc to CI There is a proposal to promote `riscv64gc-unknown-linux-gnu` to tier 1 [1]. We do not currently test RISC-V in CI; add it here. [1]: https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Imminent.20RFC.20PR.3A.20riscv64gc-unknown-linux-gnu.20to.20Tier-1 --- .../compiler-builtins/.github/workflows/main.yml | 3 +++ .../docker/riscv64gc-unknown-linux-gnu/Dockerfile | 13 +++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 library/compiler-builtins/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index fddb5973eb51c..001acd2cc5768 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -61,6 +61,9 @@ jobs: - target: powerpc64le-unknown-linux-gnu os: ubuntu-latest rust: nightly + - target: riscv64gc-unknown-linux-gnu + os: ubuntu-latest + rust: nightly - target: thumbv6m-none-eabi os: ubuntu-latest rust: nightly diff --git a/library/compiler-builtins/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile new file mode 100644 index 0000000000000..4d4a194fdc670 --- /dev/null +++ b/library/compiler-builtins/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile @@ -0,0 +1,13 @@ +ARG IMAGE=ubuntu:24.04 +FROM $IMAGE + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user-static ca-certificates \ + gcc-riscv64-linux-gnu libc6-dev-riscv64-cross \ + qemu-system-riscv64 + +ENV CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER=riscv64-linux-gnu-gcc \ + CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_RUNNER=qemu-riscv64-static \ + QEMU_LD_PREFIX=/usr/riscv64-linux-gnu \ + RUST_TEST_THREADS=1 From edc6f80dcc83722bfbf8dcba278163fd669b86f1 Mon Sep 17 00:00:00 2001 From: Alan Wu Date: Thu, 30 May 2024 16:44:39 -0400 Subject: [PATCH 1340/4206] Build with `-Werror=implicit-function-declaration` To prevent fail-fast in situations like https://github.com/rust-lang/rust/issues/125619, where an upstream source compiles but creates a link error way downstream. --- library/compiler-builtins/build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index df98688d16afd..e5503e88fc304 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -327,6 +327,8 @@ mod c { // 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); + // Avoid implicitly creating references to undefined functions + cfg.flag("-Werror=implicit-function-declaration"); } // int_util.c tries to include stdlib.h if `_WIN32` is defined, From 859e22b4aee859b09f636193b84ecb9d76a9161f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 3 Oct 2024 15:37:33 +0000 Subject: [PATCH 1341/4206] chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index e84c5545e1967..835a476492209 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.130" +version = "0.1.131" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 76580a96a7573c304792631e1d3a49f9d5821551 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 2 Oct 2024 13:53:56 -0400 Subject: [PATCH 1342/4206] Upgrade CI LLVM version to 19.1 19.1 is the latest stable release from 2024-09-17. This will match what is currently being used in rust-lang/rust. --- library/compiler-builtins/.github/workflows/main.yml | 2 +- library/compiler-builtins/README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 001acd2cc5768..ec5c059bac0ea 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -4,7 +4,7 @@ on: [push, pull_request] env: RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings - RUST_LLVM_VERSION: 18.0-2024-02-13 + RUST_LLVM_VERSION: 19.1-2024-09-17 RUST_COMPILER_RT_ROOT: ./compiler-rt jobs: diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 985020f5a8f56..f792d188324d6 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -89,8 +89,8 @@ to test against, located in a directory called `compiler-rt`. This can be obtained with the following: ```sh -curl -L -o rustc-llvm-18.0.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/18.0-2024-02-13.tar.gz -tar xzf rustc-llvm-18.0.tar.gz --strip-components 1 llvm-project-rustc-18.0-2024-02-13/compiler-rt +curl -L -o rustc-llvm-19.1.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/19.1-2024-09-17.tar.gz +tar xzf rustc-llvm-19.1.tar.gz --strip-components 1 llvm-project-rustc-19.1-2024-09-17/compiler-rt ``` Local targets may also be tested with `./ci/run.sh [target]`. From 3f70601e3c78c4af30cb2016cb91a1d37d046460 Mon Sep 17 00:00:00 2001 From: Alan Wu Date: Fri, 4 Oct 2024 12:33:16 -0400 Subject: [PATCH 1343/4206] Allow implicit function decl on A64 Testing in , we found that is unusable with the current LLVM version. --- library/compiler-builtins/build.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index e5503e88fc304..2863c979fa3ba 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -327,8 +327,16 @@ mod c { // 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); - // Avoid implicitly creating references to undefined functions - cfg.flag("-Werror=implicit-function-declaration"); + + if let "aarch64" | "arm64ec" = 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"); + } } // int_util.c tries to include stdlib.h if `_WIN32` is defined, From 3edc27ef567f70a7dbcb145ebbd49f6540dce9b7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2024 17:17:03 +0000 Subject: [PATCH 1344/4206] chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 835a476492209..d0adf7444618e 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.131" +version = "0.1.132" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From f59dd82cca4d5320065d60559ce259a5a30768b6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 5 Oct 2024 13:57:10 -0500 Subject: [PATCH 1345/4206] Move `musl-reference-tests` to a new `libm-test` crate There isn't any reason for this feature to be exposed or part of the build script. Move it to a separate crate. We will also want more tests that require some support functions; this will create a place for them. --- .../compiler-builtins/libm/CONTRIBUTING.md | 4 +- library/compiler-builtins/libm/Cargo.toml | 11 +- library/compiler-builtins/libm/build.rs | 452 +---------------- library/compiler-builtins/libm/ci/run.sh | 14 +- .../libm/crates/libm-test/Cargo.toml | 18 + .../libm/crates/libm-test/build.rs | 456 ++++++++++++++++++ .../libm/crates/libm-test/src/lib.rs | 1 + .../libm/crates/libm-test/tests/musl_biteq.rs | 4 + library/compiler-builtins/libm/src/lib.rs | 5 - 9 files changed, 494 insertions(+), 471 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/Cargo.toml create mode 100644 library/compiler-builtins/libm/crates/libm-test/build.rs create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/lib.rs create mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md index 59c37a6f95926..c15c45a4336c0 100644 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -7,7 +7,7 @@ in `src/lib.rs`. - Write some simple tests in your module (using `#[test]`) - Run `cargo test` to make sure it works -- Run `cargo test --features musl-reference-tests` to compare your +- Run `cargo test --features libm-test/musl-reference-tests` to compare your implementation against musl's - Send us a pull request! Make sure to run `cargo fmt` on your code before sending the PR. Also include "closes #42" in the PR description to close the @@ -88,7 +88,7 @@ If you'd like to run tests with randomized inputs that get compared against musl itself, you'll need to be on a Linux system and then you can execute: ``` -cargo test --features musl-reference-tests +cargo test --features libm-test/musl-reference-tests ``` Note that you may need to pass `--release` to Cargo if there are errors related diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index c2388083b611d..fc2db0c208885 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -19,10 +19,6 @@ default = [] # that it should activate any useful Nightly things accordingly. unstable = [] -# Generate tests which are random inputs and the outputs are calculated with -# musl libc. -musl-reference-tests = ['rand'] - # Used to prevent using any intrinsics or arch-specific code. force-soft-floats = [] @@ -30,13 +26,16 @@ force-soft-floats = [] members = [ "crates/compiler-builtins-smoke-test", "crates/libm-bench", + "crates/libm-test", +] +default-members = [ + ".", + "crates/libm-test", ] [dev-dependencies] no-panic = "0.1.8" -[build-dependencies] -rand = { version = "0.6.5", optional = true } # This is needed for no-panic to correctly detect the lack of panics [profile.release] diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index c9ae232607fb9..653ccf7993f70 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -5,10 +5,8 @@ fn main() { println!("cargo::rustc-check-cfg=cfg(assert_no_panic)"); println!("cargo::rustc-check-cfg=cfg(feature, values(\"unstable\"))"); - #[cfg(feature = "musl-reference-tests")] - musl_reference_tests::generate(); - println!("cargo::rustc-check-cfg=cfg(feature, values(\"checked\"))"); + #[allow(unexpected_cfgs)] if !cfg!(feature = "checked") { let lvl = env::var("OPT_LEVEL").unwrap(); @@ -17,451 +15,3 @@ fn main() { } } } - -#[cfg(feature = "musl-reference-tests")] -mod musl_reference_tests { - use rand::seq::SliceRandom; - use rand::Rng; - use std::env; - use std::fs; - use std::process::Command; - - // Number of tests to generate for each function - const NTESTS: usize = 500; - - // These files are all internal functions or otherwise miscellaneous, not - // defining a function we want to test. - const IGNORED_FILES: &[&str] = &[ - "fenv.rs", - // These are giving slightly different results compared to musl - "lgamma.rs", - "lgammaf.rs", - "tgamma.rs", - "j0.rs", - "j0f.rs", - "jn.rs", - "jnf.rs", - "j1.rs", - "j1f.rs", - ]; - - struct Function { - name: String, - args: Vec, - ret: Vec, - tests: Vec, - } - - enum Ty { - F32, - F64, - I32, - Bool, - } - - struct Test { - inputs: Vec, - outputs: Vec, - } - - pub fn generate() { - // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 - let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); - if target_arch == "powerpc64" { - return; - } - - let files = fs::read_dir("src/math") - .unwrap() - .map(|f| f.unwrap().path()) - .collect::>(); - - let mut math = Vec::new(); - for file in files { - if IGNORED_FILES.iter().any(|f| file.ends_with(f)) { - continue; - } - - println!("generating musl reference tests in {:?}", file); - - let contents = fs::read_to_string(file).unwrap(); - let mut functions = contents.lines().filter(|f| f.starts_with("pub fn")); - while let Some(function_to_test) = functions.next() { - math.push(parse(function_to_test)); - } - } - - // Generate a bunch of random inputs for each function. This will - // attempt to generate a good set of uniform test cases for exercising - // all the various functionality. - generate_random_tests(&mut math, &mut rand::thread_rng()); - - // After we have all our inputs, use the x86_64-unknown-linux-musl - // target to generate the expected output. - generate_test_outputs(&mut math); - //panic!("Boo"); - // ... and now that we have both inputs and expected outputs, do a bunch - // of codegen to create the unit tests which we'll actually execute. - generate_unit_tests(&math); - } - - /// A "poor man's" parser for the signature of a function - fn parse(s: &str) -> Function { - let s = eat(s, "pub fn "); - let pos = s.find('(').unwrap(); - let name = &s[..pos]; - let s = &s[pos + 1..]; - let end = s.find(')').unwrap(); - let args = s[..end] - .split(',') - .map(|arg| { - let colon = arg.find(':').unwrap(); - parse_ty(arg[colon + 1..].trim()) - }) - .collect::>(); - let tail = &s[end + 1..]; - let tail = eat(tail, " -> "); - let ret = parse_retty(tail.replace("{", "").trim()); - - return Function { - name: name.to_string(), - args, - ret, - tests: Vec::new(), - }; - - fn parse_ty(s: &str) -> Ty { - match s { - "f32" => Ty::F32, - "f64" => Ty::F64, - "i32" => Ty::I32, - "bool" => Ty::Bool, - other => panic!("unknown type `{}`", other), - } - } - - fn parse_retty(s: &str) -> Vec { - match s { - "(f32, f32)" => vec![Ty::F32, Ty::F32], - "(f32, i32)" => vec![Ty::F32, Ty::I32], - "(f64, f64)" => vec![Ty::F64, Ty::F64], - "(f64, i32)" => vec![Ty::F64, Ty::I32], - other => vec![parse_ty(other)], - } - } - - fn eat<'a>(s: &'a str, prefix: &str) -> &'a str { - if s.starts_with(prefix) { - &s[prefix.len()..] - } else { - panic!("{:?} didn't start with {:?}", s, prefix) - } - } - } - - fn generate_random_tests(functions: &mut [Function], rng: &mut R) { - for function in functions { - for _ in 0..NTESTS { - function.tests.push(generate_test(function, rng)); - } - } - - fn generate_test(function: &Function, rng: &mut R) -> Test { - let mut inputs = function - .args - .iter() - .map(|ty| ty.gen_i64(rng)) - .collect::>(); - - // First argument to this function appears to be a number of - // iterations, so passing in massive random numbers causes it to - // take forever to execute, so make sure we're not running random - // math code until the heat death of the universe. - if function.name == "jn" || function.name == "jnf" { - inputs[0] &= 0xffff; - } - - Test { - inputs, - // zero output for now since we'll generate it later - outputs: vec![], - } - } - } - - impl Ty { - fn gen_i64(&self, r: &mut R) -> i64 { - use std::f32; - use std::f64; - - return match self { - Ty::F32 => { - if r.gen_range(0, 20) < 1 { - let i = *[f32::NAN, f32::INFINITY, f32::NEG_INFINITY] - .choose(r) - .unwrap(); - i.to_bits().into() - } else { - r.gen::().to_bits().into() - } - } - Ty::F64 => { - if r.gen_range(0, 20) < 1 { - let i = *[f64::NAN, f64::INFINITY, f64::NEG_INFINITY] - .choose(r) - .unwrap(); - i.to_bits() as i64 - } else { - r.gen::().to_bits() as i64 - } - } - Ty::I32 => { - if r.gen_range(0, 10) < 1 { - let i = *[i32::max_value(), 0, i32::min_value()].choose(r).unwrap(); - i.into() - } else { - r.gen::().into() - } - } - Ty::Bool => r.gen::() as i64, - }; - } - - fn libc_ty(&self) -> &'static str { - match self { - Ty::F32 => "f32", - Ty::F64 => "f64", - Ty::I32 => "i32", - Ty::Bool => "i32", - } - } - - fn libc_pty(&self) -> &'static str { - match self { - Ty::F32 => "*mut f32", - Ty::F64 => "*mut f64", - Ty::I32 => "*mut i32", - Ty::Bool => "*mut i32", - } - } - - fn default(&self) -> &'static str { - match self { - Ty::F32 => "0_f32", - Ty::F64 => "0_f64", - Ty::I32 => "0_i32", - Ty::Bool => "false", - } - } - - fn to_i64(&self) -> &'static str { - match self { - Ty::F32 => ".to_bits() as i64", - Ty::F64 => ".to_bits() as i64", - Ty::I32 => " as i64", - Ty::Bool => " as i64", - } - } - } - - fn generate_test_outputs(functions: &mut [Function]) { - let mut src = String::new(); - let dst = std::env::var("OUT_DIR").unwrap(); - - // Generate a program which will run all tests with all inputs in - // `functions`. This program will write all outputs to stdout (in a - // binary format). - src.push_str("use std::io::Write;"); - src.push_str("fn main() {"); - src.push_str("let mut result = Vec::new();"); - for function in functions.iter_mut() { - src.push_str("unsafe {"); - src.push_str("extern { fn "); - src.push_str(&function.name); - src.push_str("("); - - let (ret, retptr) = match function.name.as_str() { - "sincos" | "sincosf" => (None, &function.ret[..]), - _ => (Some(&function.ret[0]), &function.ret[1..]), - }; - for (i, arg) in function.args.iter().enumerate() { - src.push_str(&format!("arg{}: {},", i, arg.libc_ty())); - } - for (i, ret) in retptr.iter().enumerate() { - src.push_str(&format!("argret{}: {},", i, ret.libc_pty())); - } - src.push_str(")"); - if let Some(ty) = ret { - src.push_str(" -> "); - src.push_str(ty.libc_ty()); - } - src.push_str("; }"); - - src.push_str(&format!("static TESTS: &[[i64; {}]]", function.args.len())); - src.push_str(" = &["); - for test in function.tests.iter() { - src.push_str("["); - for val in test.inputs.iter() { - src.push_str(&val.to_string()); - src.push_str(","); - } - src.push_str("],"); - } - src.push_str("];"); - - src.push_str("for test in TESTS {"); - for (i, arg) in retptr.iter().enumerate() { - src.push_str(&format!("let mut argret{} = {};", i, arg.default())); - } - src.push_str("let output = "); - src.push_str(&function.name); - src.push_str("("); - for (i, arg) in function.args.iter().enumerate() { - src.push_str(&match arg { - Ty::F32 => format!("f32::from_bits(test[{}] as u32)", i), - Ty::F64 => format!("f64::from_bits(test[{}] as u64)", i), - Ty::I32 => format!("test[{}] as i32", i), - Ty::Bool => format!("test[{}] as i32", i), - }); - src.push_str(","); - } - for (i, _) in retptr.iter().enumerate() { - src.push_str(&format!("&mut argret{},", i)); - } - src.push_str(");"); - if let Some(ty) = &ret { - src.push_str(&format!("let output = output{};", ty.to_i64())); - src.push_str("result.extend_from_slice(&output.to_le_bytes());"); - } - - for (i, ret) in retptr.iter().enumerate() { - src.push_str(&format!( - "result.extend_from_slice(&(argret{}{}).to_le_bytes());", - i, - ret.to_i64(), - )); - } - src.push_str("}"); - - src.push_str("}"); - } - - src.push_str("std::io::stdout().write_all(&result).unwrap();"); - - src.push_str("}"); - - let path = format!("{}/gen.rs", dst); - fs::write(&path, src).unwrap(); - - // Make it somewhat pretty if something goes wrong - drop(Command::new("rustfmt").arg(&path).status()); - - // Compile and execute this tests for the musl target, assuming we're an - // x86_64 host effectively. - let status = Command::new("rustc") - .current_dir(&dst) - .arg(&path) - .arg("--target=x86_64-unknown-linux-musl") - .status() - .unwrap(); - assert!(status.success()); - let output = Command::new("./gen").current_dir(&dst).output().unwrap(); - assert!(output.status.success()); - assert!(output.stderr.is_empty()); - - // Map all the output bytes back to an `i64` and then shove it all into - // the expected results. - let mut results = output.stdout.chunks_exact(8).map(|buf| { - let mut exact = [0; 8]; - exact.copy_from_slice(buf); - i64::from_le_bytes(exact) - }); - - for f in functions.iter_mut() { - for test in f.tests.iter_mut() { - test.outputs = (0..f.ret.len()).map(|_| results.next().unwrap()).collect(); - } - } - assert!(results.next().is_none()); - } - - /// Codegens a file which has a ton of `#[test]` annotations for all the - /// tests that we generated above. - fn generate_unit_tests(functions: &[Function]) { - let mut src = String::new(); - let dst = std::env::var("OUT_DIR").unwrap(); - - for function in functions { - src.push_str("#[test]"); - src.push_str("fn "); - src.push_str(&function.name); - src.push_str("_matches_musl() {"); - src.push_str(&format!( - "static TESTS: &[([i64; {}], [i64; {}])]", - function.args.len(), - function.ret.len(), - )); - src.push_str(" = &["); - for test in function.tests.iter() { - src.push_str("(["); - for val in test.inputs.iter() { - src.push_str(&val.to_string()); - src.push_str(","); - } - src.push_str("],"); - src.push_str("["); - for val in test.outputs.iter() { - src.push_str(&val.to_string()); - src.push_str(","); - } - src.push_str("],"); - src.push_str("),"); - } - src.push_str("];"); - - src.push_str("for (test, expected) in TESTS {"); - src.push_str("let output = "); - src.push_str(&function.name); - src.push_str("("); - for (i, arg) in function.args.iter().enumerate() { - src.push_str(&match arg { - Ty::F32 => format!("f32::from_bits(test[{}] as u32)", i), - Ty::F64 => format!("f64::from_bits(test[{}] as u64)", i), - Ty::I32 => format!("test[{}] as i32", i), - Ty::Bool => format!("test[{}] as i32", i), - }); - src.push_str(","); - } - src.push_str(");"); - - for (i, ret) in function.ret.iter().enumerate() { - let get = if function.ret.len() == 1 { - String::new() - } else { - format!(".{}", i) - }; - src.push_str(&(match ret { - Ty::F32 => format!("if _eqf(output{}, f32::from_bits(expected[{}] as u32)).is_ok() {{ continue }}", get, i), - Ty::F64 => format!("if _eq(output{}, f64::from_bits(expected[{}] as u64)).is_ok() {{ continue }}", get, i), - Ty::I32 => format!("if output{} as i64 == expected[{}] {{ continue }}", get, i), - Ty::Bool => unreachable!(), - })); - } - - src.push_str( - r#" - panic!("INPUT: {:?} EXPECTED: {:?} ACTUAL {:?}", test, expected, output); - "#, - ); - src.push_str("}"); - - src.push_str("}"); - } - - let path = format!("{}/musl-tests.rs", dst); - fs::write(&path, src).unwrap(); - - // Try to make it somewhat pretty - drop(Command::new("rustfmt").arg(&path).status()); - } -} diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index d0cd42a8d0b84..2a1ac52b13c03 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -3,19 +3,19 @@ set -ex TARGET=$1 -CMD="cargo test --all --target $TARGET" +cmd="cargo test --all --target $TARGET" # Needed for no-panic to correct detect a lack of panics export RUSTFLAGS="$RUSTFLAGS -Ccodegen-units=1" # stable by default -$CMD -$CMD --release +$cmd +$cmd --release # unstable with a feature -$CMD --features 'unstable' -$CMD --release --features 'unstable' +$cmd --features 'unstable' +$cmd --release --features 'unstable' # also run the reference tests -$CMD --features 'unstable musl-reference-tests' -$CMD --release --features 'unstable musl-reference-tests' +$cmd --features 'unstable libm-test/musl-reference-tests' +$cmd --release --features 'unstable libm-test/musl-reference-tests' diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml new file mode 100644 index 0000000000000..03e55b1d9a413 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "libm-test" +version = "0.1.0" +edition = "2021" +publish = false + +[features] +default = [] + +# Generate tests which are random inputs and the outputs are calculated with +# musl libc. +musl-reference-tests = ["rand"] + +[dependencies] +libm = { path = "../.." } + +[build-dependencies] +rand = { version = "0.6.5", optional = true } diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs new file mode 100644 index 0000000000000..fc8f305d6656e --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/build.rs @@ -0,0 +1,456 @@ +fn main() { + #[cfg(feature = "musl-reference-tests")] + musl_reference_tests::generate(); +} + +#[cfg(feature = "musl-reference-tests")] +mod musl_reference_tests { + use rand::seq::SliceRandom; + use rand::Rng; + use std::env; + use std::fs; + use std::path::PathBuf; + use std::process::Command; + + // Number of tests to generate for each function + const NTESTS: usize = 500; + + // These files are all internal functions or otherwise miscellaneous, not + // defining a function we want to test. + const IGNORED_FILES: &[&str] = &[ + "fenv.rs", + // These are giving slightly different results compared to musl + "lgamma.rs", + "lgammaf.rs", + "tgamma.rs", + "j0.rs", + "j0f.rs", + "jn.rs", + "jnf.rs", + "j1.rs", + "j1f.rs", + ]; + + struct Function { + name: String, + args: Vec, + ret: Vec, + tests: Vec, + } + + enum Ty { + F32, + F64, + I32, + Bool, + } + + struct Test { + inputs: Vec, + outputs: Vec, + } + + pub fn generate() { + // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + let libm_test = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); + let math_src = libm_test.join("../../src/math"); + + if target_arch == "powerpc64" { + return; + } + + let files = fs::read_dir(math_src) + .unwrap() + .map(|f| f.unwrap().path()) + .collect::>(); + + let mut math = Vec::new(); + for file in files { + if IGNORED_FILES.iter().any(|f| file.ends_with(f)) { + continue; + } + + println!("generating musl reference tests in {:?}", file); + + let contents = fs::read_to_string(file).unwrap(); + let mut functions = contents.lines().filter(|f| f.starts_with("pub fn")); + while let Some(function_to_test) = functions.next() { + math.push(parse(function_to_test)); + } + } + + // Generate a bunch of random inputs for each function. This will + // attempt to generate a good set of uniform test cases for exercising + // all the various functionality. + generate_random_tests(&mut math, &mut rand::thread_rng()); + + // After we have all our inputs, use the x86_64-unknown-linux-musl + // target to generate the expected output. + generate_test_outputs(&mut math); + //panic!("Boo"); + // ... and now that we have both inputs and expected outputs, do a bunch + // of codegen to create the unit tests which we'll actually execute. + generate_unit_tests(&math); + } + + /// A "poor man's" parser for the signature of a function + fn parse(s: &str) -> Function { + let s = eat(s, "pub fn "); + let pos = s.find('(').unwrap(); + let name = &s[..pos]; + let s = &s[pos + 1..]; + let end = s.find(')').unwrap(); + let args = s[..end] + .split(',') + .map(|arg| { + let colon = arg.find(':').unwrap(); + parse_ty(arg[colon + 1..].trim()) + }) + .collect::>(); + let tail = &s[end + 1..]; + let tail = eat(tail, " -> "); + let ret = parse_retty(tail.replace("{", "").trim()); + + return Function { + name: name.to_string(), + args, + ret, + tests: Vec::new(), + }; + + fn parse_ty(s: &str) -> Ty { + match s { + "f32" => Ty::F32, + "f64" => Ty::F64, + "i32" => Ty::I32, + "bool" => Ty::Bool, + other => panic!("unknown type `{}`", other), + } + } + + fn parse_retty(s: &str) -> Vec { + match s { + "(f32, f32)" => vec![Ty::F32, Ty::F32], + "(f32, i32)" => vec![Ty::F32, Ty::I32], + "(f64, f64)" => vec![Ty::F64, Ty::F64], + "(f64, i32)" => vec![Ty::F64, Ty::I32], + other => vec![parse_ty(other)], + } + } + + fn eat<'a>(s: &'a str, prefix: &str) -> &'a str { + if s.starts_with(prefix) { + &s[prefix.len()..] + } else { + panic!("{:?} didn't start with {:?}", s, prefix) + } + } + } + + fn generate_random_tests(functions: &mut [Function], rng: &mut R) { + for function in functions { + for _ in 0..NTESTS { + function.tests.push(generate_test(function, rng)); + } + } + + fn generate_test(function: &Function, rng: &mut R) -> Test { + let mut inputs = function + .args + .iter() + .map(|ty| ty.gen_i64(rng)) + .collect::>(); + + // First argument to this function appears to be a number of + // iterations, so passing in massive random numbers causes it to + // take forever to execute, so make sure we're not running random + // math code until the heat death of the universe. + if function.name == "jn" || function.name == "jnf" { + inputs[0] &= 0xffff; + } + + Test { + inputs, + // zero output for now since we'll generate it later + outputs: vec![], + } + } + } + + impl Ty { + fn gen_i64(&self, r: &mut R) -> i64 { + use std::f32; + use std::f64; + + return match self { + Ty::F32 => { + if r.gen_range(0, 20) < 1 { + let i = *[f32::NAN, f32::INFINITY, f32::NEG_INFINITY] + .choose(r) + .unwrap(); + i.to_bits().into() + } else { + r.gen::().to_bits().into() + } + } + Ty::F64 => { + if r.gen_range(0, 20) < 1 { + let i = *[f64::NAN, f64::INFINITY, f64::NEG_INFINITY] + .choose(r) + .unwrap(); + i.to_bits() as i64 + } else { + r.gen::().to_bits() as i64 + } + } + Ty::I32 => { + if r.gen_range(0, 10) < 1 { + let i = *[i32::max_value(), 0, i32::min_value()].choose(r).unwrap(); + i.into() + } else { + r.gen::().into() + } + } + Ty::Bool => r.gen::() as i64, + }; + } + + fn libc_ty(&self) -> &'static str { + match self { + Ty::F32 => "f32", + Ty::F64 => "f64", + Ty::I32 => "i32", + Ty::Bool => "i32", + } + } + + fn libc_pty(&self) -> &'static str { + match self { + Ty::F32 => "*mut f32", + Ty::F64 => "*mut f64", + Ty::I32 => "*mut i32", + Ty::Bool => "*mut i32", + } + } + + fn default(&self) -> &'static str { + match self { + Ty::F32 => "0_f32", + Ty::F64 => "0_f64", + Ty::I32 => "0_i32", + Ty::Bool => "false", + } + } + + fn to_i64(&self) -> &'static str { + match self { + Ty::F32 => ".to_bits() as i64", + Ty::F64 => ".to_bits() as i64", + Ty::I32 => " as i64", + Ty::Bool => " as i64", + } + } + } + + fn generate_test_outputs(functions: &mut [Function]) { + let mut src = String::new(); + let dst = std::env::var("OUT_DIR").unwrap(); + + // Generate a program which will run all tests with all inputs in + // `functions`. This program will write all outputs to stdout (in a + // binary format). + src.push_str("use std::io::Write;"); + src.push_str("fn main() {"); + src.push_str("let mut result = Vec::new();"); + for function in functions.iter_mut() { + src.push_str("unsafe {"); + src.push_str("extern { fn "); + src.push_str(&function.name); + src.push_str("("); + + let (ret, retptr) = match function.name.as_str() { + "sincos" | "sincosf" => (None, &function.ret[..]), + _ => (Some(&function.ret[0]), &function.ret[1..]), + }; + for (i, arg) in function.args.iter().enumerate() { + src.push_str(&format!("arg{}: {},", i, arg.libc_ty())); + } + for (i, ret) in retptr.iter().enumerate() { + src.push_str(&format!("argret{}: {},", i, ret.libc_pty())); + } + src.push_str(")"); + if let Some(ty) = ret { + src.push_str(" -> "); + src.push_str(ty.libc_ty()); + } + src.push_str("; }"); + + src.push_str(&format!("static TESTS: &[[i64; {}]]", function.args.len())); + src.push_str(" = &["); + for test in function.tests.iter() { + src.push_str("["); + for val in test.inputs.iter() { + src.push_str(&val.to_string()); + src.push_str(","); + } + src.push_str("],"); + } + src.push_str("];"); + + src.push_str("for test in TESTS {"); + for (i, arg) in retptr.iter().enumerate() { + src.push_str(&format!("let mut argret{} = {};", i, arg.default())); + } + src.push_str("let output = "); + src.push_str(&function.name); + src.push_str("("); + for (i, arg) in function.args.iter().enumerate() { + src.push_str(&match arg { + Ty::F32 => format!("f32::from_bits(test[{}] as u32)", i), + Ty::F64 => format!("f64::from_bits(test[{}] as u64)", i), + Ty::I32 => format!("test[{}] as i32", i), + Ty::Bool => format!("test[{}] as i32", i), + }); + src.push_str(","); + } + for (i, _) in retptr.iter().enumerate() { + src.push_str(&format!("&mut argret{},", i)); + } + src.push_str(");"); + if let Some(ty) = &ret { + src.push_str(&format!("let output = output{};", ty.to_i64())); + src.push_str("result.extend_from_slice(&output.to_le_bytes());"); + } + + for (i, ret) in retptr.iter().enumerate() { + src.push_str(&format!( + "result.extend_from_slice(&(argret{}{}).to_le_bytes());", + i, + ret.to_i64(), + )); + } + src.push_str("}"); + + src.push_str("}"); + } + + src.push_str("std::io::stdout().write_all(&result).unwrap();"); + + src.push_str("}"); + + let path = format!("{}/gen.rs", dst); + fs::write(&path, src).unwrap(); + + // Make it somewhat pretty if something goes wrong + drop(Command::new("rustfmt").arg(&path).status()); + + // Compile and execute this tests for the musl target, assuming we're an + // x86_64 host effectively. + let status = Command::new("rustc") + .current_dir(&dst) + .arg(&path) + .arg("--target=x86_64-unknown-linux-musl") + .status() + .unwrap(); + assert!(status.success()); + let output = Command::new("./gen").current_dir(&dst).output().unwrap(); + assert!(output.status.success()); + assert!(output.stderr.is_empty()); + + // Map all the output bytes back to an `i64` and then shove it all into + // the expected results. + let mut results = output.stdout.chunks_exact(8).map(|buf| { + let mut exact = [0; 8]; + exact.copy_from_slice(buf); + i64::from_le_bytes(exact) + }); + + for f in functions.iter_mut() { + for test in f.tests.iter_mut() { + test.outputs = (0..f.ret.len()).map(|_| results.next().unwrap()).collect(); + } + } + assert!(results.next().is_none()); + } + + /// Codegens a file which has a ton of `#[test]` annotations for all the + /// tests that we generated above. + fn generate_unit_tests(functions: &[Function]) { + let mut src = String::new(); + let dst = std::env::var("OUT_DIR").unwrap(); + + for function in functions { + src.push_str("#[test]"); + src.push_str("fn "); + src.push_str(&function.name); + src.push_str("_matches_musl() {"); + src.push_str(&format!( + "static TESTS: &[([i64; {}], [i64; {}])]", + function.args.len(), + function.ret.len(), + )); + src.push_str(" = &["); + for test in function.tests.iter() { + src.push_str("(["); + for val in test.inputs.iter() { + src.push_str(&val.to_string()); + src.push_str(","); + } + src.push_str("],"); + src.push_str("["); + for val in test.outputs.iter() { + src.push_str(&val.to_string()); + src.push_str(","); + } + src.push_str("],"); + src.push_str("),"); + } + src.push_str("];"); + + src.push_str("for (test, expected) in TESTS {"); + src.push_str("let output = libm::"); + src.push_str(&function.name); + src.push_str("("); + for (i, arg) in function.args.iter().enumerate() { + src.push_str(&match arg { + Ty::F32 => format!("f32::from_bits(test[{}] as u32)", i), + Ty::F64 => format!("f64::from_bits(test[{}] as u64)", i), + Ty::I32 => format!("test[{}] as i32", i), + Ty::Bool => format!("test[{}] as i32", i), + }); + src.push_str(","); + } + src.push_str(");"); + + for (i, ret) in function.ret.iter().enumerate() { + let get = if function.ret.len() == 1 { + String::new() + } else { + format!(".{}", i) + }; + src.push_str(&(match ret { + Ty::F32 => format!("if libm::_eqf(output{}, f32::from_bits(expected[{}] as u32)).is_ok() {{ continue }}", get, i), + Ty::F64 => format!("if libm::_eq(output{}, f64::from_bits(expected[{}] as u64)).is_ok() {{ continue }}", get, i), + Ty::I32 => format!("if output{} as i64 == expected[{}] {{ continue }}", get, i), + Ty::Bool => unreachable!(), + })); + } + + src.push_str( + r#" + panic!("INPUT: {:?} EXPECTED: {:?} ACTUAL {:?}", test, expected, output); + "#, + ); + src.push_str("}"); + + src.push_str("}"); + } + + let path = format!("{}/musl-tests.rs", dst); + fs::write(&path, src).unwrap(); + + // Try to make it somewhat pretty + drop(Command::new("rustfmt").arg(&path).status()); + } +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs new file mode 100644 index 0000000000000..8b137891791fe --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -0,0 +1 @@ + diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs b/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs new file mode 100644 index 0000000000000..46d4f35630641 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs @@ -0,0 +1,4 @@ +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +#[cfg(all(test, feature = "musl-reference-tests"))] +include!(concat!(env!("OUT_DIR"), "/musl-tests.rs")); diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 1f23ef8a80e17..23885ecf8dabf 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -53,8 +53,3 @@ pub fn _eq(a: f64, b: f64) -> Result<(), u64> { } } } - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(all(test, feature = "musl-reference-tests"))] -include!(concat!(env!("OUT_DIR"), "/musl-tests.rs")); From 8153729f91e925902490a995c72537208b0232aa Mon Sep 17 00:00:00 2001 From: "Enzo \"raskyld\" Nocera" Date: Sun, 6 Oct 2024 03:45:06 +0200 Subject: [PATCH 1346/4206] fix(int): avoid infinite recursion on left shift Please, see this discussion for the full context: https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/.5Bwasm32.5D.20Infinite.20recursion.20.60compiler-builtins.60.20.60__multi3.60 Signed-off-by: Enzo "raskyld" Nocera We determined that some recursion problems on SPARC and WASM were due to infinite recusion. This was introduced at 9c6fcb56e8 ("Split Int into Int and MinInt") when moving the implementation of `widen_hi` from something on each `impl` block to a default on the trait. The reasoning is not fully understood, but undoing this portion of the change seems to resolve the issue. [ add the above context - Trevor ] Signed-off-by: Trevor Gross --- library/compiler-builtins/src/int/big.rs | 8 ++++++++ library/compiler-builtins/src/int/mod.rs | 7 ++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/src/int/big.rs b/library/compiler-builtins/src/int/big.rs index e565da8972034..0ef3caaedffce 100644 --- a/library/compiler-builtins/src/int/big.rs +++ b/library/compiler-builtins/src/int/big.rs @@ -222,6 +222,10 @@ impl HInt for u128 { 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 { @@ -247,6 +251,10 @@ impl HInt for i128 { 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 { diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 5f56c6b6ee135..c7ca45e713e24 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -319,9 +319,7 @@ pub(crate) trait HInt: Int { /// 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 { - self.widen() << ::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. @@ -364,6 +362,9 @@ macro_rules! impl_h_int { fn widen_mul(self, rhs: Self) -> Self::D { self.widen().wrapping_mul(rhs.widen()) } + fn widen_hi(self) -> Self::D { + (self as $X) << ::BITS + } } )* }; From 996799a896c9d64f5d7d6e5f9c959b0268a0e693 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 5 Oct 2024 20:55:47 -0500 Subject: [PATCH 1347/4206] Add a note about avoiding default implemenations in some places Link: https://github.com/rust-lang/compiler-builtins/pull/707 --- library/compiler-builtins/src/int/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index c7ca45e713e24..e6f31c5301324 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -313,6 +313,10 @@ pub(crate) 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 From fedfc6aaab58eee7af80db5c0315fb916bba6661 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 6 Oct 2024 02:08:00 +0000 Subject: [PATCH 1348/4206] chore: release --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index d0adf7444618e..34e1dcdfd43e5 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.132" +version = "0.1.133" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From c236051681210a65a9a6bf8f8ceb06b359e355c1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 5 Oct 2024 21:42:28 -0500 Subject: [PATCH 1349/4206] Rename the `musl-reference-tests` feature to `musl-bitwise-tests` The plan is to add more test related features that could be considered "reference tests". Rename the feature here to avoid future confusion. --- library/compiler-builtins/libm/CONTRIBUTING.md | 4 ++-- library/compiler-builtins/libm/ci/run.sh | 4 ++-- library/compiler-builtins/libm/crates/libm-test/Cargo.toml | 2 +- library/compiler-builtins/libm/crates/libm-test/build.rs | 4 ++-- .../libm/crates/libm-test/tests/musl_biteq.rs | 4 +++- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md index c15c45a4336c0..1b5235db9ce00 100644 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -7,7 +7,7 @@ in `src/lib.rs`. - Write some simple tests in your module (using `#[test]`) - Run `cargo test` to make sure it works -- Run `cargo test --features libm-test/musl-reference-tests` to compare your +- Run `cargo test --features libm-test/musl-bitwise-tests` to compare your implementation against musl's - Send us a pull request! Make sure to run `cargo fmt` on your code before sending the PR. Also include "closes #42" in the PR description to close the @@ -88,7 +88,7 @@ If you'd like to run tests with randomized inputs that get compared against musl itself, you'll need to be on a Linux system and then you can execute: ``` -cargo test --features libm-test/musl-reference-tests +cargo test --features libm-test/musl-bitwise-tests ``` Note that you may need to pass `--release` to Cargo if there are errors related diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 2a1ac52b13c03..b5d6e45f7108f 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -17,5 +17,5 @@ $cmd --features 'unstable' $cmd --release --features 'unstable' # also run the reference tests -$cmd --features 'unstable libm-test/musl-reference-tests' -$cmd --release --features 'unstable libm-test/musl-reference-tests' +$cmd --features 'unstable libm-test/musl-bitwise-tests' +$cmd --release --features 'unstable libm-test/musl-bitwise-tests' diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 03e55b1d9a413..d044523763977 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -9,7 +9,7 @@ default = [] # Generate tests which are random inputs and the outputs are calculated with # musl libc. -musl-reference-tests = ["rand"] +musl-bitwise-tests = ["rand"] [dependencies] libm = { path = "../.." } diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs index fc8f305d6656e..09eb384103ac3 100644 --- a/library/compiler-builtins/libm/crates/libm-test/build.rs +++ b/library/compiler-builtins/libm/crates/libm-test/build.rs @@ -1,9 +1,9 @@ fn main() { - #[cfg(feature = "musl-reference-tests")] + #[cfg(feature = "musl-bitwise-tests")] musl_reference_tests::generate(); } -#[cfg(feature = "musl-reference-tests")] +#[cfg(feature = "musl-bitwise-tests")] mod musl_reference_tests { use rand::seq::SliceRandom; use rand::Rng; diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs b/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs index 46d4f35630641..1a6b7181709fa 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs @@ -1,4 +1,6 @@ +//! compare + // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 #[cfg(not(target_arch = "powerpc64"))] -#[cfg(all(test, feature = "musl-reference-tests"))] +#[cfg(all(test, feature = "musl-bitwise-tests"))] include!(concat!(env!("OUT_DIR"), "/musl-tests.rs")); From cb305df1940fc52fd1004046b7c33afc6b56aa39 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 5 Oct 2024 22:24:14 -0500 Subject: [PATCH 1350/4206] Upgrade all dependencies None of these affect the distributed library. --- library/compiler-builtins/libm/Cargo.toml | 2 +- library/compiler-builtins/libm/crates/libm-bench/Cargo.toml | 4 ++-- library/compiler-builtins/libm/crates/libm-test/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index fc2db0c208885..712baee79a5b1 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -34,7 +34,7 @@ default-members = [ ] [dev-dependencies] -no-panic = "0.1.8" +no-panic = "0.1.30" # This is needed for no-panic to correctly detect the lack of panics diff --git a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml index b09db339b5b27..ac9cb83a601e7 100644 --- a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml @@ -7,8 +7,8 @@ license = "MIT OR Apache-2.0" [dependencies] libm = { path = "../..", default-features = false } -rand = "0.6.5" -paste = "0.1.5" +rand = "0.8.5" +paste = "1.0.15" [features] default = [] diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index d044523763977..7c193d3bbca83 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -15,4 +15,4 @@ musl-bitwise-tests = ["rand"] libm = { path = "../.." } [build-dependencies] -rand = { version = "0.6.5", optional = true } +rand = { version = "0.8.5", optional = true } From d8c234b959959d832c2b8532d843d62ca779b4e8 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 5 Oct 2024 22:28:38 -0500 Subject: [PATCH 1351/4206] Do library updates necessary with dependency upgrades --- library/compiler-builtins/libm/crates/libm-test/build.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs index 09eb384103ac3..c2c4b0bd28ed2 100644 --- a/library/compiler-builtins/libm/crates/libm-test/build.rs +++ b/library/compiler-builtins/libm/crates/libm-test/build.rs @@ -185,7 +185,7 @@ mod musl_reference_tests { return match self { Ty::F32 => { - if r.gen_range(0, 20) < 1 { + if r.gen_range(0..20) < 1 { let i = *[f32::NAN, f32::INFINITY, f32::NEG_INFINITY] .choose(r) .unwrap(); @@ -195,7 +195,7 @@ mod musl_reference_tests { } } Ty::F64 => { - if r.gen_range(0, 20) < 1 { + if r.gen_range(0..20) < 1 { let i = *[f64::NAN, f64::INFINITY, f64::NEG_INFINITY] .choose(r) .unwrap(); @@ -205,7 +205,7 @@ mod musl_reference_tests { } } Ty::I32 => { - if r.gen_range(0, 10) < 1 { + if r.gen_range(0..10) < 1 { let i = *[i32::max_value(), 0, i32::min_value()].choose(r).unwrap(); i.into() } else { From 0be441d5adb1079b2a158278c5787c8803e2805f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 6 Oct 2024 00:07:55 -0500 Subject: [PATCH 1352/4206] Update Ubuntu images to 24.04 We don't have any specific reason to stay on 18.04, so upgrade to the latest LTS version. --- .../libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile | 3 ++- .../libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile | 3 ++- .../libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile | 3 ++- .../libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile | 3 ++- .../libm/ci/docker/i686-unknown-linux-gnu/Dockerfile | 3 ++- .../libm/ci/docker/mips-unknown-linux-gnu/Dockerfile | 2 +- .../libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile | 3 ++- .../libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile | 3 ++- .../libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile | 2 +- .../libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile | 2 +- .../libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile | 2 +- .../libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile | 2 +- .../libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile | 3 ++- 13 files changed, 21 insertions(+), 13 deletions(-) diff --git a/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile index 9e2559f4ab3a2..b6b23d86522f8 100644 --- a/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ diff --git a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile index afab874bc2817..ff340fba4c772 100644 --- a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ diff --git a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile index 3ed3602b0dc97..15cd6eee909d6 100644 --- a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ diff --git a/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile index 6617af1558c9a..3090a83f80839 100644 --- a/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ diff --git a/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile index 5783e28e12200..3b0bfc0d3d9d2 100644 --- a/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc-multilib libc6-dev ca-certificates diff --git a/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile index f47e8f5227b49..2850e775ca324 100644 --- a/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile index 8fa77c7bd0737..ec23159c9aa1b 100644 --- a/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 + RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates \ diff --git a/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile index c6611d9ac899c..0ff1fba9c007d 100644 --- a/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 + RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates \ diff --git a/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile index 0bc695624620e..dfb9d0c87e259 100644 --- a/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile index 2d39fef6142bb..532f2cb05f75b 100644 --- a/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile index 653cd351156e1..3ce687873f1f0 100644 --- a/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile index 63ea9af9d2023..90212fe45c313 100644 --- a/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile index 98000f4eb81a7..15723ab57ee05 100644 --- a/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates From d0f1dd6010eb14f025cd814df9272a5cb3d15726 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 6 Oct 2024 00:12:58 -0500 Subject: [PATCH 1353/4206] Set target-specific `AR` and `CC` arguments The Rust `cc` crate reads these, so make sure they are set for when we start making use of `cc`. --- .../libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile | 6 +++++- .../libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile | 6 +++++- .../libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile | 6 +++++- .../ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile | 6 +++++- .../libm/ci/docker/mips-unknown-linux-gnu/Dockerfile | 5 ++++- .../ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile | 7 +++++-- .../ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile | 7 +++++-- .../libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile | 5 ++++- .../libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile | 5 ++++- .../libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile | 6 ++++-- .../ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile | 5 ++++- 11 files changed, 50 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile index b6b23d86522f8..a7b23cb9e0271 100644 --- a/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -5,7 +5,11 @@ RUN apt-get update && \ gcc libc6-dev ca-certificates \ gcc-aarch64-linux-gnu libc6-dev-arm64-cross \ qemu-user-static -ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ + +ENV TOOLCHAIN_PREFIX=aarch64-linux-gnu- +ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER=qemu-aarch64-static \ + AR_aarch64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_aarch64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/aarch64-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile index ff340fba4c772..e070a7d936ea1 100644 --- a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile @@ -4,7 +4,11 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-linux-gnueabi libc6-dev-armel-cross qemu-user-static -ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER=arm-linux-gnueabi-gcc \ + +ENV TOOLCHAIN_PREFIX=arm-linux-gnueabi- +ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_RUNNER=qemu-arm-static \ + AR_arm_unknown_linux_gnueabi="$TOOLCHAIN_PREFIX"ar \ + CC_arm_unknown_linux_gnueabi="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabi \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile index 15cd6eee909d6..29f1e04a9b5b2 100644 --- a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile @@ -4,7 +4,11 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static -ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + +ENV TOOLCHAIN_PREFIX=arm-linux-gnueabihf- +ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \ + AR_arm_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"ar \ + CC_arm_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile index 3090a83f80839..0a30801b44deb 100644 --- a/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile @@ -4,7 +4,11 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static -ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + +ENV TOOLCHAIN_PREFIX=arm-linux-gnueabihf- +ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \ + AR_armv7_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"ar \ + CC_armv7_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile index 2850e775ca324..298208c925ac4 100644 --- a/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile @@ -6,7 +6,10 @@ RUN apt-get update && \ gcc-mips-linux-gnu libc6-dev-mips-cross \ binfmt-support qemu-user-static qemu-system-mips -ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER=mips-linux-gnu-gcc \ +ENV TOOLCHAIN_PREFIX=mips-linux-gnu- +ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_RUNNER=qemu-mips-static \ + AR_mips_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_mips_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/mips-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile index ec23159c9aa1b..101b3853efee2 100644 --- a/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile @@ -9,8 +9,11 @@ RUN apt-get update && \ libc6-dev-mips64-cross \ qemu-user-static \ qemu-system-mips -ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER=mips64-linux-gnuabi64-gcc \ + +ENV TOOLCHAIN_PREFIX=mips64-linux-gnuabi64- +ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64-static \ - CC_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-gcc \ + AR_mips64_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"ar \ + CC_mips64_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/mips64-linux-gnuabi64 \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile index 0ff1fba9c007d..0eb14f9acf5d8 100644 --- a/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile @@ -8,8 +8,11 @@ RUN apt-get update && \ libc6-dev \ libc6-dev-mips64el-cross \ qemu-user-static -ENV CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_LINKER=mips64el-linux-gnuabi64-gcc \ + +ENV TOOLCHAIN_PREFIX=mips64el-linux-gnuabi64- +ENV CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64el-static \ - CC_mips64el_unknown_linux_gnuabi64=mips64el-linux-gnuabi64-gcc \ + AR_mips64el_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"ar \ + CC_mips64el_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/mips64el-linux-gnuabi64 \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile index dfb9d0c87e259..1b9817cfef88a 100644 --- a/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile @@ -6,7 +6,10 @@ RUN apt-get update && \ gcc-mipsel-linux-gnu libc6-dev-mipsel-cross \ binfmt-support qemu-user-static -ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER=mipsel-linux-gnu-gcc \ +ENV TOOLCHAIN_PREFIX=mipsel-linux-gnu- +ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_RUNNER=qemu-mipsel-static \ + AR_mipsel_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_mipsel_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/mipsel-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile index 532f2cb05f75b..1ea2e30a2429d 100644 --- a/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile @@ -6,7 +6,10 @@ RUN apt-get update && \ gcc-powerpc-linux-gnu libc6-dev-powerpc-cross \ qemu-system-ppc -ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER=powerpc-linux-gnu-gcc \ +ENV TOOLCHAIN_PREFIX=powerpc-linux-gnu- +ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc-static \ + AR_powerpc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_powerpc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/powerpc-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile index 3ce687873f1f0..373814bcafd7c 100644 --- a/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile @@ -6,8 +6,10 @@ RUN apt-get update && \ gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross \ binfmt-support qemu-user-static qemu-system-ppc -ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER=powerpc64-linux-gnu-gcc \ +ENV TOOLCHAIN_PREFIX=powerpc64-linux-gnu- +ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64-static \ - CC_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-gcc \ + AR_powerpc64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_powerpc64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile index 90212fe45c313..403bb1d95b2b6 100644 --- a/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile @@ -6,8 +6,11 @@ RUN apt-get update && \ gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross \ qemu-system-ppc -ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER=powerpc64le-linux-gnu-gcc \ +ENV TOOLCHAIN_PREFIX=powerpc64le-linux-gnu- +ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64le-static \ + AR_powerpc64le_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_powerpc64le_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_CPU=POWER8 \ QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu \ RUST_TEST_THREADS=1 From d82eb887223582c0fd678ecfd2913ae48b90d452 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 6 Oct 2024 13:44:25 -0500 Subject: [PATCH 1354/4206] Fix shellcheck warnings in scripts --- .../compiler-builtins/libm/ci/run-docker.sh | 24 +++++++++++-------- library/compiler-builtins/libm/ci/run.sh | 9 +++---- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh index 8d323634a67ec..9191a17e2ba5d 100755 --- a/library/compiler-builtins/libm/ci/run-docker.sh +++ b/library/compiler-builtins/libm/ci/run-docker.sh @@ -1,36 +1,40 @@ +#!/bin/bash + # Small script to run tests for a target (or all targets) inside all the # respective docker images. -set -ex +set -euxo pipefail run() { local target=$1 - echo $target + echo "testing target: $target" # This directory needs to exist before calling docker, otherwise docker will create it but it # will be owned by root mkdir -p target - docker build -t $target ci/docker/$target + docker build -t "$target" "ci/docker/$target" docker run \ --rm \ - --user $(id -u):$(id -g) \ + --user "$(id -u):$(id -g)" \ -e RUSTFLAGS \ -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ - -v "${HOME}/.cargo":/cargo \ - -v `pwd`/target:/target \ - -v `pwd`:/checkout:ro \ - -v `rustc --print sysroot`:/rust:ro \ + -v "${HOME}/.cargo:/cargo" \ + -v "$(pwd)/target:/target" \ + -v "$(pwd):/checkout:ro" \ + -v "$(rustc --print sysroot):/rust:ro" \ --init \ -w /checkout \ - $target \ + "$target" \ sh -c "HOME=/tmp PATH=\$PATH:/rust/bin exec ci/run.sh $target" } if [ -z "$1" ]; then - for d in `ls ci/docker/`; do + echo "running tests for all targets" + + for d in ci/docker/*; do run $d done else diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index b5d6e45f7108f..1b016cc4fb2ad 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -1,9 +1,10 @@ -#!/usr/bin/env sh +#!/bin/sh -set -ex -TARGET=$1 +set -eux -cmd="cargo test --all --target $TARGET" +target="$1" + +cmd="cargo test --all --target $target" # Needed for no-panic to correct detect a lack of panics export RUSTFLAGS="$RUSTFLAGS -Ccodegen-units=1" From d3943b1863e47cc207820c9c0eda13fc045a805b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 7 Oct 2024 00:18:41 -0500 Subject: [PATCH 1355/4206] Set edition to 2021 for all crates --- library/compiler-builtins/libm/Cargo.toml | 2 +- .../libm/crates/compiler-builtins-smoke-test/Cargo.toml | 1 + .../libm/crates/compiler-builtins-smoke-test/src/lib.rs | 2 ++ library/compiler-builtins/libm/crates/libm-bench/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 712baee79a5b1..181000f343e39 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -9,7 +9,7 @@ name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/libm" version = "0.2.8" -edition = "2018" +edition = "2021" exclude = ["/ci/", "/.github/workflows/"] [features] diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index 481d386a4b221..4bc62304a9d64 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -2,6 +2,7 @@ name = "cb" version = "0.1.0" authors = ["Jorge Aparicio "] +edition = "2021" [lib] test = false diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index ab744c45bcec7..e65cb8da3c4f6 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -2,6 +2,8 @@ //! //! This is used to test that we can source import `libm` into the compiler-builtins crate. +#![feature(core_intrinsics)] +#![allow(internal_features)] #![allow(dead_code)] #![no_std] diff --git a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml index ac9cb83a601e7..282752c6183a1 100644 --- a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml @@ -2,7 +2,7 @@ name = "libm-bench" version = "0.1.0" authors = ["Gonzalo Brito Gadeschi "] -edition = "2018" +edition = "2021" license = "MIT OR Apache-2.0" [dependencies] From 2a738c50ab2899194ca7bbed287961f7a1d9fb3a Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Wed, 16 Oct 2024 22:12:38 -0400 Subject: [PATCH 1356/4206] Use wrapping pointer arithmetic in mem/impls.rs Add a comment (and fix a typo) --- library/compiler-builtins/src/mem/impls.rs | 105 ++++++++++++--------- 1 file changed, 61 insertions(+), 44 deletions(-) diff --git a/library/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/src/mem/impls.rs index 23c9d8d327536..c602a67dbd7a4 100644 --- a/library/compiler-builtins/src/mem/impls.rs +++ b/library/compiler-builtins/src/mem/impls.rs @@ -1,3 +1,20 @@ +// In C and Rust it is UB to read or write to usize::MAX because if an allocation extends to the +// last byte of address space (there must be an allocation to do the read or write), in C computing +// its one-past-the-end pointer would be equal to NULL and in Rust computing the address of a +// trailing ZST member with a safe place projection would wrap (place projection address computation +// is non-wrapping). +// +// However, some embedded systems have special memory at usize::MAX, and need to access that +// memory. If they do that with the intrinsics provided by compiler-builtins (such as memcpy!), the +// 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... +// 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 +// crate doing wrapping pointer arithmetic with a method that must not wrap won't be the problem if +// something does go wrong at runtime. use core::intrinsics::likely; const WORD_SIZE: usize = core::mem::size_of::(); @@ -9,7 +26,7 @@ const WORD_MASK: usize = WORD_SIZE - 1; // word-wise copy. // * The word-wise copy logic needs to perform some checks so it has some small overhead. // ensures that even on 32-bit platforms we have copied at least 8 bytes through -// word-wise copy so the saving of word-wise copy outweights the fixed overhead. +// word-wise copy so the saving of word-wise copy outweighs the fixed overhead. const WORD_COPY_THRESHOLD: usize = if 2 * WORD_SIZE > 16 { 2 * WORD_SIZE } else { @@ -28,11 +45,11 @@ unsafe fn read_usize_unaligned(x: *const usize) -> usize { pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) { #[inline(always)] unsafe fn copy_forward_bytes(mut dest: *mut u8, mut src: *const u8, n: usize) { - let dest_end = dest.add(n); + let dest_end = dest.wrapping_add(n); while dest < dest_end { *dest = *src; - dest = dest.add(1); - src = src.add(1); + dest = dest.wrapping_add(1); + src = src.wrapping_add(1); } } @@ -40,12 +57,12 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) unsafe fn copy_forward_aligned_words(dest: *mut u8, src: *const u8, n: usize) { let mut dest_usize = dest as *mut usize; let mut src_usize = src as *mut usize; - let dest_end = dest.add(n) as *mut usize; + let dest_end = dest.wrapping_add(n) as *mut usize; while dest_usize < dest_end { *dest_usize = *src_usize; - dest_usize = dest_usize.add(1); - src_usize = src_usize.add(1); + dest_usize = dest_usize.wrapping_add(1); + src_usize = src_usize.wrapping_add(1); } } @@ -53,7 +70,7 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) #[inline(always)] unsafe fn copy_forward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { let mut dest_usize = dest as *mut usize; - let dest_end = dest.add(n) as *mut usize; + let dest_end = dest.wrapping_add(n) as *mut usize; // Calculate the misalignment offset and shift needed to reassemble value. let offset = src as usize & WORD_MASK; @@ -70,7 +87,7 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) let mut prev_word = core::ptr::read_volatile(src_aligned); while dest_usize < dest_end { - src_aligned = src_aligned.add(1); + src_aligned = src_aligned.wrapping_add(1); let cur_word = *src_aligned; #[cfg(target_endian = "little")] let resembled = prev_word >> shift | cur_word << (WORD_SIZE * 8 - shift); @@ -79,7 +96,7 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) prev_word = cur_word; *dest_usize = resembled; - dest_usize = dest_usize.add(1); + dest_usize = dest_usize.wrapping_add(1); } } @@ -88,12 +105,12 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) unsafe fn copy_forward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { let mut dest_usize = dest as *mut usize; let mut src_usize = src as *mut usize; - let dest_end = dest.add(n) as *mut usize; + let dest_end = dest.wrapping_add(n) as *mut usize; while dest_usize < dest_end { *dest_usize = read_usize_unaligned(src_usize); - dest_usize = dest_usize.add(1); - src_usize = src_usize.add(1); + dest_usize = dest_usize.wrapping_add(1); + src_usize = src_usize.wrapping_add(1); } } @@ -102,8 +119,8 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) // Because of n >= 2 * WORD_SIZE, dst_misalignment < n let dest_misalignment = (dest as usize).wrapping_neg() & WORD_MASK; copy_forward_bytes(dest, src, dest_misalignment); - dest = dest.add(dest_misalignment); - src = src.add(dest_misalignment); + dest = dest.wrapping_add(dest_misalignment); + src = src.wrapping_add(dest_misalignment); n -= dest_misalignment; let n_words = n & !WORD_MASK; @@ -113,8 +130,8 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) } else { copy_forward_misaligned_words(dest, src, n_words); } - dest = dest.add(n_words); - src = src.add(n_words); + dest = dest.wrapping_add(n_words); + src = src.wrapping_add(n_words); n -= n_words; } copy_forward_bytes(dest, src, n); @@ -126,10 +143,10 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { // as their inputs instead of pointers to the start! #[inline(always)] unsafe fn copy_backward_bytes(mut dest: *mut u8, mut src: *const u8, n: usize) { - let dest_start = dest.sub(n); + let dest_start = dest.wrapping_sub(n); while dest_start < dest { - dest = dest.sub(1); - src = src.sub(1); + dest = dest.wrapping_sub(1); + src = src.wrapping_sub(1); *dest = *src; } } @@ -138,11 +155,11 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { unsafe fn copy_backward_aligned_words(dest: *mut u8, src: *const u8, n: usize) { let mut dest_usize = dest as *mut usize; let mut src_usize = src as *mut usize; - let dest_start = dest.sub(n) as *mut usize; + let dest_start = dest.wrapping_sub(n) as *mut usize; while dest_start < dest_usize { - dest_usize = dest_usize.sub(1); - src_usize = src_usize.sub(1); + dest_usize = dest_usize.wrapping_sub(1); + src_usize = src_usize.wrapping_sub(1); *dest_usize = *src_usize; } } @@ -151,7 +168,7 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { #[inline(always)] unsafe fn copy_backward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { let mut dest_usize = dest as *mut usize; - let dest_start = dest.sub(n) as *mut usize; + let dest_start = dest.wrapping_sub(n) as *mut usize; // Calculate the misalignment offset and shift needed to reassemble value. let offset = src as usize & WORD_MASK; @@ -168,7 +185,7 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { let mut prev_word = core::ptr::read_volatile(src_aligned); while dest_start < dest_usize { - src_aligned = src_aligned.sub(1); + src_aligned = src_aligned.wrapping_sub(1); let cur_word = *src_aligned; #[cfg(target_endian = "little")] let resembled = prev_word << (WORD_SIZE * 8 - shift) | cur_word >> shift; @@ -176,7 +193,7 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { let resembled = prev_word >> (WORD_SIZE * 8 - shift) | cur_word << shift; prev_word = cur_word; - dest_usize = dest_usize.sub(1); + dest_usize = dest_usize.wrapping_sub(1); *dest_usize = resembled; } } @@ -186,25 +203,25 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { unsafe fn copy_backward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { let mut dest_usize = dest as *mut usize; let mut src_usize = src as *mut usize; - let dest_start = dest.sub(n) as *mut usize; + let dest_start = dest.wrapping_sub(n) as *mut usize; while dest_start < dest_usize { - dest_usize = dest_usize.sub(1); - src_usize = src_usize.sub(1); + dest_usize = dest_usize.wrapping_sub(1); + src_usize = src_usize.wrapping_sub(1); *dest_usize = read_usize_unaligned(src_usize); } } - let mut dest = dest.add(n); - let mut src = src.add(n); + let mut dest = dest.wrapping_add(n); + let mut src = src.wrapping_add(n); if n >= WORD_COPY_THRESHOLD { // Align dest // Because of n >= 2 * WORD_SIZE, dst_misalignment < n let dest_misalignment = dest as usize & WORD_MASK; copy_backward_bytes(dest, src, dest_misalignment); - dest = dest.sub(dest_misalignment); - src = src.sub(dest_misalignment); + dest = dest.wrapping_sub(dest_misalignment); + src = src.wrapping_sub(dest_misalignment); n -= dest_misalignment; let n_words = n & !WORD_MASK; @@ -214,8 +231,8 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { } else { copy_backward_misaligned_words(dest, src, n_words); } - dest = dest.sub(n_words); - src = src.sub(n_words); + dest = dest.wrapping_sub(n_words); + src = src.wrapping_sub(n_words); n -= n_words; } copy_backward_bytes(dest, src, n); @@ -225,10 +242,10 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { pub unsafe fn set_bytes(mut s: *mut u8, c: u8, mut n: usize) { #[inline(always)] pub unsafe fn set_bytes_bytes(mut s: *mut u8, c: u8, n: usize) { - let end = s.add(n); + let end = s.wrapping_add(n); while s < end { *s = c; - s = s.add(1); + s = s.wrapping_add(1); } } @@ -242,11 +259,11 @@ pub unsafe fn set_bytes(mut s: *mut u8, c: u8, mut n: usize) { } let mut s_usize = s as *mut usize; - let end = s.add(n) as *mut usize; + let end = s.wrapping_add(n) as *mut usize; while s_usize < end { *s_usize = broadcast; - s_usize = s_usize.add(1); + s_usize = s_usize.wrapping_add(1); } } @@ -255,12 +272,12 @@ pub unsafe fn set_bytes(mut s: *mut u8, c: u8, mut n: usize) { // Because of n >= 2 * WORD_SIZE, dst_misalignment < n let misalignment = (s as usize).wrapping_neg() & WORD_MASK; set_bytes_bytes(s, c, misalignment); - s = s.add(misalignment); + s = s.wrapping_add(misalignment); n -= misalignment; let n_words = n & !WORD_MASK; set_bytes_words(s, c, n_words); - s = s.add(n_words); + s = s.wrapping_add(n_words); n -= n_words; } set_bytes_bytes(s, c, n); @@ -270,8 +287,8 @@ pub unsafe fn set_bytes(mut s: *mut u8, c: u8, mut n: usize) { pub unsafe fn compare_bytes(s1: *const u8, s2: *const u8, n: usize) -> i32 { let mut i = 0; while i < n { - let a = *s1.add(i); - let b = *s2.add(i); + let a = *s1.wrapping_add(i); + let b = *s2.wrapping_add(i); if a != b { return a as i32 - b as i32; } @@ -285,7 +302,7 @@ pub unsafe fn c_string_length(mut s: *const core::ffi::c_char) -> usize { let mut n = 0; while *s != 0 { n += 1; - s = s.add(1); + s = s.wrapping_add(1); } n } From 3e922da15677f0bb29550e722e850665c94c03de Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2024 23:55:25 +0000 Subject: [PATCH 1357/4206] chore: release v0.1.134 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 34e1dcdfd43e5..7b853dedddf95 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.133" +version = "0.1.134" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 68b820187bd0637c1b81cf1933e346ed774d2981 Mon Sep 17 00:00:00 2001 From: Niklas Sombert Date: Mon, 21 Oct 2024 15:35:31 +0200 Subject: [PATCH 1358/4206] Re-enable math module on i686-unknown-uefi In 9ba77d1583e6de5ab9cf7c9b82827ba8fcb9062f, this was disabled for x86 without sse2. It should be fine to re-enable it for UEFI, as explained at . --- library/compiler-builtins/src/lib.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index dea30a3c6ace6..ffcd3586ce7eb 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -44,10 +44,16 @@ pub mod int; // Disable for any of the following: // - x86 without sse2 due to ABI issues // - +// - but exclude UEFI since it is a soft-float target +// - // - All unix targets (linux, macos, freebsd, android, etc) // - wasm with known target_os #[cfg(not(any( - all(target_arch = "x86", not(target_feature = "sse2")), + all( + target_arch = "x86", + not(target_feature = "sse2"), + not(target_os = "uefi"), + ), unix, all(target_family = "wasm", not(target_os = "unknown")) )))] From ce89a70ae42ccad1c7d856c33e0cf300de9951ed Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 23 Oct 2024 09:57:03 +0000 Subject: [PATCH 1359/4206] chore: release v0.1.135 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 7b853dedddf95..ab966b84eb835 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.134" +version = "0.1.135" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 2f7fafd182f53e827f12da5af5ab42b3484e44d6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 25 Oct 2024 14:18:53 -0500 Subject: [PATCH 1360/4206] Rename `Float::repr` and `Float::from_repr` `to_bits` and `from_bits` are builtin methods on float types. Rename `repr` to `to_bits` and `from_repr` to `from_bits` so this is consistent with usage that doesn't go through the trait. --- library/compiler-builtins/src/float/add.rs | 20 ++++++------- library/compiler-builtins/src/float/cmp.rs | 12 ++++---- library/compiler-builtins/src/float/conv.rs | 6 ++-- library/compiler-builtins/src/float/div.rs | 26 ++++++++--------- library/compiler-builtins/src/float/extend.rs | 6 ++-- library/compiler-builtins/src/float/mod.rs | 28 +++++++++---------- library/compiler-builtins/src/float/mul.rs | 26 ++++++++--------- library/compiler-builtins/src/float/sub.rs | 6 ++-- library/compiler-builtins/src/float/trunc.rs | 9 +++--- .../compiler-builtins/testcrate/src/lib.rs | 4 +-- 10 files changed, 71 insertions(+), 72 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index bceef7b0ed996..ecb96264a18e8 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -25,8 +25,8 @@ where let quiet_bit = implicit_bit >> 1; let qnan_rep = exponent_mask | quiet_bit; - let mut a_rep = a.repr(); - let mut b_rep = b.repr(); + let mut a_rep = a.to_bits(); + let mut b_rep = b.to_bits(); let a_abs = a_rep & abs_mask; let b_abs = b_rep & abs_mask; @@ -34,17 +34,17 @@ where if a_abs.wrapping_sub(one) >= inf_rep - one || b_abs.wrapping_sub(one) >= inf_rep - one { // NaN + anything = qNaN if a_abs > inf_rep { - return F::from_repr(a_abs | quiet_bit); + return F::from_bits(a_abs | quiet_bit); } // anything + NaN = qNaN if b_abs > inf_rep { - return F::from_repr(b_abs | quiet_bit); + return F::from_bits(b_abs | quiet_bit); } if a_abs == inf_rep { // +/-infinity + -/+infinity = qNaN - if (a.repr() ^ b.repr()) == sign_bit { - return F::from_repr(qnan_rep); + if (a.to_bits() ^ b.to_bits()) == sign_bit { + return F::from_bits(qnan_rep); } else { // +/-infinity + anything remaining = +/- infinity return a; @@ -60,7 +60,7 @@ where if a_abs == MinInt::ZERO { // but we need to get the sign right for zero + zero if b_abs == MinInt::ZERO { - return F::from_repr(a.repr() & b.repr()); + return F::from_bits(a.to_bits() & b.to_bits()); } else { return b; } @@ -126,7 +126,7 @@ where a_significand = a_significand.wrapping_sub(b_significand); // If a == -b, return +zero. if a_significand == MinInt::ZERO { - return F::from_repr(MinInt::ZERO); + return F::from_bits(MinInt::ZERO); } // If partial cancellation occured, we need to left-shift the result @@ -152,7 +152,7 @@ where // If we have overflowed the type, return +/- infinity: if a_exponent >= max_exponent as i32 { - return F::from_repr(inf_rep | result_sign); + return F::from_bits(inf_rep | result_sign); } if a_exponent <= 0 { @@ -185,7 +185,7 @@ where result += result & one; } - F::from_repr(result) + F::from_bits(result) } intrinsics! { diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index bb7d4b498fe2c..8b97a0b5ccebf 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -41,8 +41,8 @@ fn cmp(a: F, b: F) -> Result { let exponent_mask = F::EXPONENT_MASK; let inf_rep = exponent_mask; - let a_rep = a.repr(); - let b_rep = b.repr(); + let a_rep = a.to_bits(); + let b_rep = b.to_bits(); let a_abs = a_rep & abs_mask; let b_abs = b_rep & abs_mask; @@ -56,8 +56,8 @@ fn cmp(a: F, b: F) -> Result { return Result::Equal; } - let a_srep = a.signed_repr(); - let b_srep = b.signed_repr(); + let a_srep = a.to_bits_signed(); + let b_srep = b.to_bits_signed(); // If at least one of a and b is positive, we get the same result comparing // a and b as signed integers as we would with a fp_ting-point compare. @@ -90,8 +90,8 @@ fn unord(a: F, b: F) -> bool { let exponent_mask = F::EXPONENT_MASK; let inf_rep = exponent_mask; - let a_rep = a.repr(); - let b_rep = b.repr(); + let a_rep = a.to_bits(); + let b_rep = b.to_bits(); let a_abs = a_rep & abs_mask; let b_abs = b_rep & abs_mask; diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index d275f982bb44d..e86fee6dc5f76 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -158,7 +158,7 @@ where F::Int: CastInto, u32: CastFrom, { - float_to_int_inner::(f.repr(), |i: U| i, || U::MAX) + float_to_int_inner::(f.to_bits(), |i: U| i, || U::MAX) } /// Generic float to signed int conversions. @@ -172,7 +172,7 @@ where u32: CastFrom, { float_to_int_inner::( - f.repr() & !F::SIGN_MASK, + f.to_bits() & !F::SIGN_MASK, |i: I| if f.is_sign_negative() { -i } else { i }, || if f.is_sign_negative() { I::MIN } else { I::MAX }, ) @@ -203,7 +203,7 @@ where let int_max_exp = F::EXPONENT_BIAS + I::MAX.ilog2() + 1; let foobar = F::EXPONENT_BIAS + I::UnsignedInt::BITS - 1; - if fbits < F::ONE.repr() { + if fbits < F::ONE.to_bits() { // < 0 gets rounded to 0 I::ZERO } else if fbits < F::Int::cast_from(int_max_exp) << F::SIGNIFICAND_BITS { diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index f125771a017ac..4b3f97c35750d 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -126,8 +126,8 @@ where half_iterations += 1; } - let a_rep = a.repr(); - let b_rep = b.repr(); + let a_rep = a.to_bits(); + let b_rep = b.to_bits(); // Exponent numeric representationm not accounting for bias let a_exponent = (a_rep >> significand_bits) & exponent_sat; @@ -150,42 +150,42 @@ where // NaN / anything = qNaN if a_abs > inf_rep { - return F::from_repr(a_rep | quiet_bit); + return F::from_bits(a_rep | quiet_bit); } // anything / NaN = qNaN if b_abs > inf_rep { - return F::from_repr(b_rep | quiet_bit); + return F::from_bits(b_rep | quiet_bit); } if a_abs == inf_rep { if b_abs == inf_rep { // infinity / infinity = NaN - return F::from_repr(qnan_rep); + return F::from_bits(qnan_rep); } else { // infinity / anything else = +/- infinity - return F::from_repr(a_abs | quotient_sign); + return F::from_bits(a_abs | quotient_sign); } } // anything else / infinity = +/- 0 if b_abs == inf_rep { - return F::from_repr(quotient_sign); + return F::from_bits(quotient_sign); } if a_abs == zero { if b_abs == zero { // zero / zero = NaN - return F::from_repr(qnan_rep); + return F::from_bits(qnan_rep); } else { // zero / anything else = +/- zero - return F::from_repr(quotient_sign); + return F::from_bits(quotient_sign); } } // anything else / zero = +/- infinity if b_abs == zero { - return F::from_repr(inf_rep | quotient_sign); + return F::from_bits(inf_rep | quotient_sign); } // a is denormal. Renormalize it and set the scale to include the necessary exponent @@ -463,7 +463,7 @@ where // // If we have overflowed the exponent, return infinity if res_exponent >= i32::cast_from(exponent_sat) { - return F::from_repr(inf_rep | quotient_sign); + return F::from_bits(inf_rep | quotient_sign); } // Now, quotient <= the correctly-rounded result @@ -476,7 +476,7 @@ where ret } else { if ((significand_bits as i32) + res_exponent) < 0 { - return F::from_repr(quotient_sign); + return F::from_bits(quotient_sign); } let ret = quotient.wrapping_shr(u32::cast_from(res_exponent.wrapping_neg()) + 1); @@ -501,7 +501,7 @@ where u8::from(abs_result < inf_rep && residual_lo > (4 + 1).cast() * b_significand).into(); } - F::from_repr(abs_result | quotient_sign) + F::from_bits(abs_result | quotient_sign) } /// Calculate the number of iterations required for a float type's precision. diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index 997475c8e0482..2ec79070cb80a 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -32,7 +32,7 @@ where let sign_bits_delta = dst_sign_bits - src_sign_bits; let exp_bias_delta = dst_exp_bias - src_exp_bias; - let a_abs = a.repr() & src_abs_mask; + let a_abs = a.to_bits() & src_abs_mask; let mut abs_result = R::Int::ZERO; if a_abs.wrapping_sub(src_min_normal) < src_infinity.wrapping_sub(src_min_normal) { @@ -65,8 +65,8 @@ where abs_result = (abs_result ^ dst_min_normal) | (bias_dst.wrapping_shl(dst_sign_bits)); } - let sign_result: R::Int = (a.repr() & src_sign_mask).cast(); - R::from_repr(abs_result | (sign_result.wrapping_shl(dst_bits - src_bits))) + let sign_result: R::Int = (a.to_bits() & src_sign_mask).cast(); + R::from_bits(abs_result | (sign_result.wrapping_shl(dst_bits - src_bits))) } intrinsics! { diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 704bba0c025f7..5eedf544f1201 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -70,10 +70,10 @@ pub(crate) trait Float: const EXPONENT_MASK: Self::Int; /// Returns `self` transmuted to `Self::Int` - fn repr(self) -> Self::Int; + fn to_bits(self) -> Self::Int; /// Returns `self` transmuted to `Self::SignedInt` - fn signed_repr(self) -> 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 @@ -93,10 +93,10 @@ pub(crate) trait Float: fn imp_frac(self) -> Self::Int; /// Returns a `Self::Int` transmuted back to `Self` - fn from_repr(a: Self::Int) -> 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(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self; + fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self; /// Returns (normalized exponent, normalized significand) fn normalize(significand: Self::Int) -> (i32, Self::Int); @@ -124,10 +124,10 @@ macro_rules! float_impl { const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); - fn repr(self) -> Self::Int { + fn to_bits(self) -> Self::Int { self.to_bits() } - fn signed_repr(self) -> Self::SignedInt { + fn to_bits_signed(self) -> Self::SignedInt { self.to_bits() as Self::SignedInt } fn eq_repr(self, rhs: Self) -> bool { @@ -137,8 +137,8 @@ macro_rules! float_impl { // 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.repr() & $ty::EXPONENT_MASK == $ty::EXPONENT_MASK - && x.repr() & $ty::SIGNIFICAND_MASK != 0 + x.to_bits() & $ty::EXPONENT_MASK == $ty::EXPONENT_MASK + && x.to_bits() & $ty::SIGNIFICAND_MASK != 0 } #[cfg(not(feature = "mangled-names"))] fn is_nan(x: $ty) -> bool { @@ -147,7 +147,7 @@ macro_rules! float_impl { if is_nan(self) && is_nan(rhs) { true } else { - self.repr() == rhs.repr() + self.to_bits() == rhs.to_bits() } } fn is_sign_negative(self) -> bool { @@ -162,12 +162,12 @@ macro_rules! float_impl { fn imp_frac(self) -> Self::Int { self.frac() | Self::IMPLICIT_BIT } - fn from_repr(a: Self::Int) -> Self { + fn from_bits(a: Self::Int) -> Self { Self::from_bits(a) } - fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_repr( - ((sign as Self::Int) << (Self::BITS - 1)) + fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self { + Self::from_bits( + ((negative as Self::Int) << (Self::BITS - 1)) | ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) | (significand & Self::SIGNIFICAND_MASK), ) @@ -182,7 +182,7 @@ macro_rules! float_impl { ) } fn is_subnormal(self) -> bool { - (self.repr() & Self::EXPONENT_MASK) == Self::Int::ZERO + (self.to_bits() & Self::EXPONENT_MASK) == Self::Int::ZERO } } }; diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index a4c69ea8707e4..77a271d65a9c8 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -28,8 +28,8 @@ where let qnan_rep = exponent_mask | quiet_bit; let exponent_bits = F::EXPONENT_BITS; - let a_rep = a.repr(); - let b_rep = b.repr(); + let a_rep = a.to_bits(); + let b_rep = b.to_bits(); let a_exponent = (a_rep >> significand_bits) & max_exponent.cast(); let b_exponent = (b_rep >> significand_bits) & max_exponent.cast(); @@ -48,41 +48,41 @@ where // NaN + anything = qNaN if a_abs > inf_rep { - return F::from_repr(a_rep | quiet_bit); + return F::from_bits(a_rep | quiet_bit); } // anything + NaN = qNaN if b_abs > inf_rep { - return F::from_repr(b_rep | quiet_bit); + return F::from_bits(b_rep | quiet_bit); } if a_abs == inf_rep { if b_abs != zero { // infinity * non-zero = +/- infinity - return F::from_repr(a_abs | product_sign); + return F::from_bits(a_abs | product_sign); } else { // infinity * zero = NaN - return F::from_repr(qnan_rep); + return F::from_bits(qnan_rep); } } if b_abs == inf_rep { if a_abs != zero { // infinity * non-zero = +/- infinity - return F::from_repr(b_abs | product_sign); + return F::from_bits(b_abs | product_sign); } else { // infinity * zero = NaN - return F::from_repr(qnan_rep); + return F::from_bits(qnan_rep); } } // zero * anything = +/- zero if a_abs == zero { - return F::from_repr(product_sign); + return F::from_bits(product_sign); } // anything * zero = +/- zero if b_abs == zero { - return F::from_repr(product_sign); + return F::from_bits(product_sign); } // one or both of a or b is denormal, the other (if applicable) is a @@ -133,7 +133,7 @@ where // If we have overflowed the type, return +/- infinity. if product_exponent >= max_exponent as i32 { - return F::from_repr(inf_rep | product_sign); + return F::from_bits(inf_rep | product_sign); } if product_exponent <= 0 { @@ -145,7 +145,7 @@ where // simplify the shift logic. let shift = one.wrapping_sub(product_exponent.cast()).cast(); if shift >= bits { - return F::from_repr(product_sign); + return F::from_bits(product_sign); } // Otherwise, shift the significand of the result so that the round @@ -176,7 +176,7 @@ where product_high += product_high & one; } - F::from_repr(product_high) + F::from_bits(product_high) } intrinsics! { diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/src/float/sub.rs index 7e8a894584839..175b3a1650027 100644 --- a/library/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/src/float/sub.rs @@ -4,13 +4,13 @@ intrinsics! { #[avr_skip] #[arm_aeabi_alias = __aeabi_fsub] pub extern "C" fn __subsf3(a: f32, b: f32) -> f32 { - crate::float::add::__addsf3(a, f32::from_repr(b.repr() ^ f32::SIGN_MASK)) + crate::float::add::__addsf3(a, f32::from_bits(b.to_bits() ^ f32::SIGN_MASK)) } #[avr_skip] #[arm_aeabi_alias = __aeabi_dsub] pub extern "C" fn __subdf3(a: f64, b: f64) -> f64 { - crate::float::add::__adddf3(a, f64::from_repr(b.repr() ^ f64::SIGN_MASK)) + crate::float::add::__adddf3(a, f64::from_bits(b.to_bits() ^ f64::SIGN_MASK)) } #[ppc_alias = __subkf3] @@ -21,6 +21,6 @@ intrinsics! { #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] use crate::float::add::__addtf3; - __addtf3(a, f128::from_repr(b.repr() ^ f128::SIGN_MASK)) + __addtf3(a, f128::from_bits(b.to_bits() ^ f128::SIGN_MASK)) } } diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index a25b6eabc5e29..6fe44f50b9442 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -7,7 +7,6 @@ where F::Int: CastInto, u64: CastInto, u32: CastInto, - R::Int: CastInto, u32: CastInto, F::Int: CastInto, @@ -43,8 +42,8 @@ where let sign_bits_delta = F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS; // Break a into a sign and representation of the absolute value. - let a_abs = a.repr() & src_abs_mask; - let sign = a.repr() & src_sign_mask; + let a_abs = a.to_bits() & src_abs_mask; + let sign = a.to_bits() & src_sign_mask; let mut abs_result: R::Int; if a_abs.wrapping_sub(underflow) < a_abs.wrapping_sub(overflow) { @@ -87,7 +86,7 @@ where let a_exp: u32 = (a_abs >> F::SIGNIFICAND_BITS).cast(); let shift = src_exp_bias - dst_exp_bias - a_exp + 1; - let significand = (a.repr() & src_significand_mask) | src_min_normal; + let significand = (a.to_bits() & src_significand_mask) | src_min_normal; // Right shift by the denormalization amount with sticky. if shift > F::SIGNIFICAND_BITS { @@ -114,7 +113,7 @@ where } // Apply the signbit to the absolute value. - R::from_repr(abs_result | sign.wrapping_shr(src_bits - dst_bits).cast()) + R::from_bits(abs_result | sign.wrapping_shr(src_bits - dst_bits).cast()) } intrinsics! { diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index cc9e73938fbc2..58419bf1bd07b 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -190,7 +190,7 @@ fn fuzz_float_step(rng: &mut Xoshiro128StarStar, f: &mut F) { let tmp = ones.wrapping_shr(r0); (tmp.wrapping_shl(r1) | tmp.wrapping_shr(F::EXPONENT_BITS - r1)) & ones }; - let mut exp = (f.repr() & F::EXPONENT_MASK) >> F::SIGNIFICAND_BITS; + let mut exp = (f.to_bits() & F::EXPONENT_MASK) >> F::SIGNIFICAND_BITS; match (rng32 >> 9) % 4 { 0 => exp |= mask, 1 => exp &= mask, @@ -198,7 +198,7 @@ fn fuzz_float_step(rng: &mut Xoshiro128StarStar, f: &mut F) { } // significand fuzzing - let mut sig = f.repr() & F::SIGNIFICAND_MASK; + let mut sig = f.to_bits() & F::SIGNIFICAND_MASK; fuzz_step(rng, &mut sig); sig &= F::SIGNIFICAND_MASK; From 394fb9f2bcf0fa2e6d0ab6d0787e7859cdd9e8ac Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 25 Oct 2024 14:30:03 -0500 Subject: [PATCH 1361/4206] Add an `abs` function to the `Float` trait There is no in-crate use for this yet, but we will make use of it in `libm`. --- library/compiler-builtins/src/float/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 5eedf544f1201..af83986447e1a 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -98,6 +98,11 @@ pub(crate) trait Float: /// 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); From a68516ed6aa0489a1e225277598423f627fd45f4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 25 Oct 2024 20:57:19 -0400 Subject: [PATCH 1362/4206] Rename the `musl-bitwise-tests` feature to `test-musl-serialized` We will have more test features in the near future, and it would be nice for them all to have a common `test-` prefix. Reverse the existing feature so this is the case. --- library/compiler-builtins/libm/CONTRIBUTING.md | 8 ++++---- library/compiler-builtins/libm/ci/run.sh | 4 ++-- .../compiler-builtins/libm/crates/libm-test/Cargo.toml | 2 +- library/compiler-builtins/libm/crates/libm-test/build.rs | 4 ++-- .../libm/crates/libm-test/tests/musl_biteq.rs | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md index 1b5235db9ce00..a39623696c4a0 100644 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -7,7 +7,7 @@ in `src/lib.rs`. - Write some simple tests in your module (using `#[test]`) - Run `cargo test` to make sure it works -- Run `cargo test --features libm-test/musl-bitwise-tests` to compare your +- Run `cargo test --features libm-test/test-musl-serialized` to compare your implementation against musl's - Send us a pull request! Make sure to run `cargo fmt` on your code before sending the PR. Also include "closes #42" in the PR description to close the @@ -80,15 +80,15 @@ let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 12 Normal tests can be executed with: -``` +```sh cargo test ``` If you'd like to run tests with randomized inputs that get compared against musl itself, you'll need to be on a Linux system and then you can execute: -``` -cargo test --features libm-test/musl-bitwise-tests +```sh +cargo test --features libm-test/test-musl-serialized ``` Note that you may need to pass `--release` to Cargo if there are errors related diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 1b016cc4fb2ad..505e2589187ba 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -18,5 +18,5 @@ $cmd --features 'unstable' $cmd --release --features 'unstable' # also run the reference tests -$cmd --features 'unstable libm-test/musl-bitwise-tests' -$cmd --release --features 'unstable libm-test/musl-bitwise-tests' +$cmd --features 'unstable libm-test/test-musl-serialized' +$cmd --release --features 'unstable libm-test/test-musl-serialized' diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 7c193d3bbca83..6367bdca52c04 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -9,7 +9,7 @@ default = [] # Generate tests which are random inputs and the outputs are calculated with # musl libc. -musl-bitwise-tests = ["rand"] +test-musl-serialized = ["rand"] [dependencies] libm = { path = "../.." } diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs index c2c4b0bd28ed2..3a49e3c573151 100644 --- a/library/compiler-builtins/libm/crates/libm-test/build.rs +++ b/library/compiler-builtins/libm/crates/libm-test/build.rs @@ -1,9 +1,9 @@ fn main() { - #[cfg(feature = "musl-bitwise-tests")] + #[cfg(feature = "test-musl-serialized")] musl_reference_tests::generate(); } -#[cfg(feature = "musl-bitwise-tests")] +#[cfg(feature = "test-musl-serialized")] mod musl_reference_tests { use rand::seq::SliceRandom; use rand::Rng; diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs b/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs index 1a6b7181709fa..f586fd03d12c8 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs @@ -2,5 +2,5 @@ // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 #[cfg(not(target_arch = "powerpc64"))] -#[cfg(all(test, feature = "musl-bitwise-tests"))] +#[cfg(all(test, feature = "test-musl-serialized"))] include!(concat!(env!("OUT_DIR"), "/musl-tests.rs")); From 79bf4fe1f2f527563969276e723511366efaf046 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 00:54:26 -0500 Subject: [PATCH 1363/4206] Don't deny warnings in lib.rs Having `#![deny(warnings)]` for the entire crate is a bit of a development annoyance. We already run CI with `RUSTFLAGS=-Dwarnings` so there isn't much of a reason to check this locally. Thus, remove the attribute. Additionally, sort the clippy allows. --- library/compiler-builtins/libm/src/lib.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 23885ecf8dabf..04f4ac0f2e18a 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -1,17 +1,16 @@ //! libm in pure Rust -#![deny(warnings)] #![no_std] #![cfg_attr(feature = "unstable", allow(internal_features))] #![cfg_attr(feature = "unstable", feature(core_intrinsics))] -#![allow(clippy::unreadable_literal)] -#![allow(clippy::many_single_char_names)] -#![allow(clippy::needless_return)] -#![allow(clippy::int_plus_one)] +#![allow(clippy::assign_op_pattern)] #![allow(clippy::deprecated_cfg_attr)] -#![allow(clippy::mixed_case_hex_literals)] -#![allow(clippy::float_cmp)] #![allow(clippy::eq_op)] -#![allow(clippy::assign_op_pattern)] +#![allow(clippy::float_cmp)] +#![allow(clippy::int_plus_one)] +#![allow(clippy::many_single_char_names)] +#![allow(clippy::mixed_case_hex_literals)] +#![allow(clippy::needless_return)] +#![allow(clippy::unreadable_literal)] mod libm_helper; mod math; From bd82e67afc5ac829eba994a3e6f27739a27fa435 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 24 Oct 2024 18:53:46 -0500 Subject: [PATCH 1364/4206] Update licensing to MIT AND (MIT OR Apache-2.0) Currently both Cargo.toml and the license files indicate that this library may be used under either MIT or Apache-2.0. However, this is not accurate; since portions of this library were derived from musl libc, which is available under the MIT license, this terms of use for this library must also include use under the MIT license. That is, it is not correct that this library may be used under only the Apache-2.0 license. Update the SPDX license identifier to `MIT OR (MIT AND Apache-2.0)` to indicate that use must include the MIT license, but to clarify that contributions are made under `MIT OR Apache-2.0`. This is compatible with the current state of this repository since it has always contained both license files, and the `Cargo.toml` license field has indicated `MIT OR Apache-2.0` since it was added. In accordance with the above, replace the two license files with a combined LICENSE.txt that makes these terms clear and gives attribution to works from which this library is derived. Fixes: https://github.com/rust-lang/libm/issues/215 Link: https://rust-lang.zulipchat.com/#narrow/channel/335408-foundation/topic/Request.20for.20legal.20team.20input.20on.20crate.20licensing Link: https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT --- library/compiler-builtins/libm/Cargo.toml | 2 +- library/compiler-builtins/libm/LICENSE-APACHE | 201 -------------- library/compiler-builtins/libm/LICENSE-MIT | 25 -- library/compiler-builtins/libm/LICENSE.txt | 258 ++++++++++++++++++ library/compiler-builtins/libm/README.md | 19 +- 5 files changed, 269 insertions(+), 236 deletions(-) delete mode 100644 library/compiler-builtins/libm/LICENSE-APACHE delete mode 100644 library/compiler-builtins/libm/LICENSE-MIT create mode 100644 library/compiler-builtins/libm/LICENSE.txt diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 181000f343e39..9ae8bd84156fc 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -4,7 +4,7 @@ categories = ["no-std"] description = "libm in pure Rust" documentation = "https://docs.rs/libm" keywords = ["libm", "math"] -license = "MIT OR Apache-2.0" +license = "MIT AND (MIT OR Apache-2.0)" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/libm" diff --git a/library/compiler-builtins/libm/LICENSE-APACHE b/library/compiler-builtins/libm/LICENSE-APACHE deleted file mode 100644 index 16fe87b06e802..0000000000000 --- a/library/compiler-builtins/libm/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/library/compiler-builtins/libm/LICENSE-MIT b/library/compiler-builtins/libm/LICENSE-MIT deleted file mode 100644 index 432fbea04d382..0000000000000 --- a/library/compiler-builtins/libm/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2018 Jorge Aparicio - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/library/compiler-builtins/libm/LICENSE.txt b/library/compiler-builtins/libm/LICENSE.txt new file mode 100644 index 0000000000000..2f8e41f147472 --- /dev/null +++ b/library/compiler-builtins/libm/LICENSE.txt @@ -0,0 +1,258 @@ +rust-lang/libm as a whole is available for use under the MIT license: + +------------------------------------------------------------------------------ +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ + +As a contributor, you agree that your code can be used under either the MIT +license or the Apache-2.0 license: + +------------------------------------------------------------------------------ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +------------------------------------------------------------------------------ + +This Rust library contains the following copyrights: + + Copyright (c) 2018 Jorge Aparicio + +Portions of this software are derived from third-party works licensed under +terms compatible with the above MIT license: + +* musl libc https://www.musl-libc.org/. This library contains the following + copyright: + + Copyright © 2005-2020 Rich Felker, et al. + +* The CORE-MATH project https://core-math.gitlabpages.inria.fr/. CORE-MATH + routines are available under the MIT license on a per-file basis. + +The musl libc COPYRIGHT file also includes the following notice relevant to +math portions of the library: + +------------------------------------------------------------------------------ +Much of the math library code (src/math/* and src/complex/*) is +Copyright © 1993,2004 Sun Microsystems or +Copyright © 2003-2011 David Schultz or +Copyright © 2003-2009 Steven G. Kargl or +Copyright © 2003-2009 Bruce D. Evans or +Copyright © 2008 Stephen L. Moshier or +Copyright © 2017-2018 Arm Limited +and labelled as such in comments in the individual source files. All +have been licensed under extremely permissive terms. +------------------------------------------------------------------------------ + +Copyright notices are retained in src/* files where relevant. diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index b864b5df8e79c..24ee3d1c16314 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -36,16 +36,17 @@ Please check [CONTRIBUTING.md](CONTRIBUTING.md) ## License -Licensed under either of +Usage is licensed under the MIT license ([LICENSE-MIT](LICENSE-MIT) or +http://opensource.org/licenses/MIT). -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. ### Contribution -Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the -work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any -additional terms or conditions. +Contributions are licensed under both the MIT license and the Apache License, +Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or +http://www.apache.org/licenses/LICENSE-2.0). Unless you explicitly state +otherwise, any contribution intentionally submitted for inclusion in the work +by you, as defined in the Apache-2.0 license, shall be dual licensed as +mentioned, without any additional terms or conditions. + +See `LICENSE.txt` for full details. From 6399bed36c0613e6ccb0366bcb7425aa2e64ecbc Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 24 Oct 2024 20:13:56 -0500 Subject: [PATCH 1365/4206] Update licensing to MIT AND Apache-2.0 WITH LLVM-exception Currently, Cargo.toml specifies Apache-2.0 OR MIT, but LICENSE.txt describes MIT OR NCSA. compiler-builtins is derived from LLVM's compiler-rt. LICENSE.txt correctly reflects the state of compiler-rt prior to relicensing on 2019-01-19, during which time software was available for use under either MIT or the University of Illinois NCSA license. After relicensing, however, compiler-rt is available for use only under Apache-2.0 with the LLVM exception; this is not reflected anywhere in the repository. Update the SPDX license identifier to `MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)`. Each AND portion covers something specific: * Apache-2.0 WITH LLVM-exception: this covers work that is derived from the LLVM repository since after the LLVM relicensing. * MIT: This covers work that is derived from LLVM before the LLVM relicensing (under MIT OR NCSA), as well as the vendored `libm` components. * MIT AND Apache-2.0: This ensures that any contributions to this repository, in addition to meeting the above required licenses, is also released for use under the Rust-standard Apache-2.0 with no LLVM exception. See also the parallel license update in rust-lang/libm [1]. Fixes: https://github.com/rust-lang/compiler-builtins/issues/307 Closes: https://github.com/rust-lang/compiler-builtins/pull/511 Link: https://rust-lang.zulipchat.com/#narrow/channel/335408-foundation/topic/Request.20for.20legal.20team.20input.20on.20crate.20licensing Link: https://github.com/rust-lang/libm/pull/317 [1] --- library/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/LICENSE.txt | 317 ++++++++++++++++++++------ 2 files changed, 249 insertions(+), 70 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index ab966b84eb835..c29fe6afe620e 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -2,7 +2,7 @@ authors = ["Jorge Aparicio "] name = "compiler_builtins" version = "0.1.135" -license = "MIT/Apache-2.0" +license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" homepage = "https://github.com/rust-lang/compiler-builtins" diff --git a/library/compiler-builtins/LICENSE.txt b/library/compiler-builtins/LICENSE.txt index 92bbe113ab2a1..367e3538df08f 100644 --- a/library/compiler-builtins/LICENSE.txt +++ b/library/compiler-builtins/LICENSE.txt @@ -1,91 +1,270 @@ -============================================================================== -compiler-builtins License -============================================================================== +compiler-builtins as a whole is available for use under both the MIT license +and the Apache-2.0 license with the LLVM exception (MIT AND Apache-2.0 WITH +LLVM-exception). -The compiler-builtins crate is dual licensed under both the University of -Illinois "BSD-Like" license and the MIT license. As a user of this code you may -choose to use it under either license. As a contributor, you agree to allow -your code to be used under both. +As a contributor, you agree that your code can be used under either the MIT +license, or the Apache-2.0 license, or the Apache-2.0 license with the LLVM +exception. -Full text of the relevant licenses is included below. +Text of the relevant licenses is provided below: -============================================================================== +------------------------------------------------------------------------------ +MIT License -University of Illinois/NCSA -Open Source License +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -Copyright (c) 2009-2016 by the contributors listed in CREDITS.TXT +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -All rights reserved. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -Developed by: + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - LLVM Team + 1. Definitions. - University of Illinois at Urbana-Champaign + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. - http://llvm.org + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal with -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimers. + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimers in the - documentation and/or other materials provided with the distribution. + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. - * Neither the names of the LLVM Team, University of Illinois at - Urbana-Champaign, nor the names of its contributors may be used to - endorse or promote products derived from this Software without specific - prior written permission. + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE -SOFTWARE. + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). -============================================================================== + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. -Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -============================================================================== -Copyrights and Licenses for Third Party Software Distributed with LLVM: -============================================================================== -The LLVM software contains code written by third parties. Such software will -have its own individual LICENSE.TXT file in the directory in which it appears. -This file will describe the copyrights, license, and restrictions which apply -to that code. - -The disclaimer of warranty in the University of Illinois Open Source License -applies to all code in the LLVM Distribution, and nothing in any of the -other licenses gives permission to use the names of the LLVM Team or the -University of Illinois to endorse or promote products derived from this + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +---- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined Software. +------------------------------------------------------------------------------ + +Portions of this software are derived from third-party works licensed under +terms compatible with the above Apache-2.0 WITH LLVM-exception AND MIT +license: + +* compiler-builtins is derived from LLVM's compiler-rt (https://llvm.org/). + Work derived from compiler-rt prior to 2019-01-19 is usable under the MIT + license, with the following copyright: + + Copyright (c) 2009-2016 by the contributors listed in CREDITS.TXT + + The relevant CREDITS.TXT is located at + https://github.com/llvm/llvm-project/blob/main/compiler-rt/CREDITS.TXT. + +* Work derived from compiler-rt after 2019-01-19 is usable under the + Apache-2.0 license with the LLVM exception. + +* The bundled `math` module is from rust-lang/libm, usable under the MIT + license. See https://github.com/rust-lang/libm for details. +Additionally, some source files may contain comments with specific copyrights +or licenses. From 47961340db34c5c70ea98ed4bfc61cf539a1b68c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 17:57:24 -0500 Subject: [PATCH 1366/4206] Add release-plz for automated releases --- .../libm/.github/workflows/publish.yml | 29 +++++++++++++++++++ .../compiler-builtins-smoke-test/Cargo.toml | 1 + .../libm/crates/libm-bench/Cargo.toml | 1 + 3 files changed, 31 insertions(+) create mode 100644 library/compiler-builtins/libm/.github/workflows/publish.yml diff --git a/library/compiler-builtins/libm/.github/workflows/publish.yml b/library/compiler-builtins/libm/.github/workflows/publish.yml new file mode 100644 index 0000000000000..1241181a0268c --- /dev/null +++ b/library/compiler-builtins/libm/.github/workflows/publish.yml @@ -0,0 +1,29 @@ +name: Release-plz + +permissions: + pull-requests: write + contents: write + +on: + push: + branches: + - master + +jobs: + release-plz: + name: Release-plz + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install Rust (rustup) + run: rustup update nightly --no-self-update && rustup default nightly + - name: Publish `libm` as part of builtins, rather than its own crate + run: rm libm/Cargo.toml + - name: Run release-plz + uses: MarcoIeni/release-plz-action@v0.5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index 4bc62304a9d64..8d084ee341e90 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -3,6 +3,7 @@ name = "cb" version = "0.1.0" authors = ["Jorge Aparicio "] edition = "2021" +publish = false [lib] test = false diff --git a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml index 282752c6183a1..ee8c5820037f8 100644 --- a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors = ["Gonzalo Brito Gadeschi "] edition = "2021" license = "MIT OR Apache-2.0" +publish = false [dependencies] libm = { path = "../..", default-features = false } From 0433caa0ba6f8c5fc4231e6944af6b4bd943ecd6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 18:01:56 -0500 Subject: [PATCH 1367/4206] Fix release-plz workflow configuration --- library/compiler-builtins/libm/.github/workflows/publish.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/publish.yml b/library/compiler-builtins/libm/.github/workflows/publish.yml index 1241181a0268c..e715c61871fdd 100644 --- a/library/compiler-builtins/libm/.github/workflows/publish.yml +++ b/library/compiler-builtins/libm/.github/workflows/publish.yml @@ -20,8 +20,6 @@ jobs: fetch-depth: 0 - name: Install Rust (rustup) run: rustup update nightly --no-self-update && rustup default nightly - - name: Publish `libm` as part of builtins, rather than its own crate - run: rm libm/Cargo.toml - name: Run release-plz uses: MarcoIeni/release-plz-action@v0.5 env: From 4f3418a4d77ba4cfb4e55055e87ab78173a0ca65 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 26 Oct 2024 23:04:46 +0000 Subject: [PATCH 1368/4206] chore: release v0.2.9 --- library/compiler-builtins/libm/CHANGELOG.md | 39 +++++++++++++++++++-- library/compiler-builtins/libm/Cargo.toml | 2 +- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index e8e9acf9b5c09..36ed41d6ba545 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -1,20 +1,50 @@ -# Change Log +# Changelog All notable changes to this project will be documented in this file. -This project adheres to [Semantic Versioning](http://semver.org/). + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to +[Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] -... +## [0.2.9](https://github.com/rust-lang/libm/compare/libm-v0.2.8...libm-v0.2.9) - 2024-10-26 + +### Fixed + +- Update exponent calculations in nextafter to match musl + +### Changed + +- Update licensing to MIT AND (MIT OR Apache-2.0), as this is derivative from + MIT-licensed musl. +- Set edition to 2021 for all crates +- Upgrade all dependencies + +### Other + +- Don't deny warnings in lib.rs +- Rename the `musl-bitwise-tests` feature to `test-musl-serialized` +- Rename the `musl-reference-tests` feature to `musl-bitwise-tests` +- Move `musl-reference-tests` to a new `libm-test` crate +- Add a `force-soft-floats` feature to prevent using any intrinsics or + arch-specific code +- Deny warnings in CI +- Fix `clippy::deprecated_cfg_attr` on compiler_builtins +- Corrected English typos +- Remove unneeded `extern core` in `tgamma` +- Allow internal_features lint when building with "unstable" ## [v0.2.1] - 2019-11-22 ### Fixed + - sincosf ## [v0.2.0] - 2019-10-18 ### Added + - Benchmarks - signum - remainder @@ -23,17 +53,20 @@ This project adheres to [Semantic Versioning](http://semver.org/). - nextafterf ### Fixed + - Rounding to negative zero - Overflows in rem_pio2 and remquo - Overflows in fma - sincosf ### Removed + - F32Ext and F64Ext traits ## [v0.1.4] - 2019-06-12 ### Fixed + - Restored compatibility with Rust 1.31.0 ## [v0.1.3] - 2019-05-14 diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 9ae8bd84156fc..f04fc12df4d80 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT AND (MIT OR Apache-2.0)" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/libm" -version = "0.2.8" +version = "0.2.9" edition = "2021" exclude = ["/ci/", "/.github/workflows/"] From 01a2a13a01ba323791bd2b229bebeda1726a45d8 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 18:19:18 -0500 Subject: [PATCH 1369/4206] Update the libm submodule --- library/compiler-builtins/libm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 300edb32520b1..f4e5b38aee0e0 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 300edb32520b1673e16d2411a0e2e6273959eb46 +Subproject commit f4e5b38aee0e0c592a82ed45b21cd068c9b6c89a From f9914e98b3cb55af066ac3062d16d4ae504c53d0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 26 Oct 2024 23:29:14 +0000 Subject: [PATCH 1370/4206] chore: release v0.1.136 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index c29fe6afe620e..4a85e5215b279 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.135" +version = "0.1.136" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 710ca6e38ecde09939c51a81752ae27d966ae974 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 20:18:50 -0500 Subject: [PATCH 1371/4206] Add a rustfmt.toml file matching rust-lang/rust Duplicate the settings from rust-lang/rust to this repository. This is mostly for consistency, but `use_small_heuristics = "Max"` does make a large difference with lookup tables. Also apply the needed CI changes to run nightly rustfmt. --- library/compiler-builtins/libm/.github/workflows/main.yml | 2 +- library/compiler-builtins/libm/.rustfmt.toml | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/libm/.rustfmt.toml diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 322043d85af3b..f312e1f5e67c7 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -41,7 +41,7 @@ jobs: steps: - uses: actions/checkout@master - name: Install Rust - run: rustup update stable && rustup default stable && rustup component add rustfmt + run: rustup update nightly && rustup default nightly && rustup component add rustfmt - run: cargo fmt -- --check wasm: diff --git a/library/compiler-builtins/libm/.rustfmt.toml b/library/compiler-builtins/libm/.rustfmt.toml new file mode 100644 index 0000000000000..c73bb9301e340 --- /dev/null +++ b/library/compiler-builtins/libm/.rustfmt.toml @@ -0,0 +1,5 @@ +# This matches rustc +style_edition = "2024" +use_small_heuristics = "Max" +group_imports = "StdExternalCrate" +imports_granularity = "Module" From ab0c8e84fb3b76136aa38b800a17c0f97fa469a7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 20:22:24 -0500 Subject: [PATCH 1372/4206] Run `cargo fmt` with new settings Apply the changes from the `.rustfmt.toml` file added in the previous commit. --- .../libm/crates/libm-test/build.rs | 43 ++++------------ library/compiler-builtins/libm/src/lib.rs | 15 ++---- .../compiler-builtins/libm/src/math/asin.rs | 6 +-- .../compiler-builtins/libm/src/math/asinf.rs | 6 +-- .../compiler-builtins/libm/src/math/asinh.rs | 6 +-- .../compiler-builtins/libm/src/math/asinhf.rs | 6 +-- .../compiler-builtins/libm/src/math/atan.rs | 12 ++--- .../compiler-builtins/libm/src/math/atan2.rs | 3 +- .../compiler-builtins/libm/src/math/atan2f.rs | 3 +- .../compiler-builtins/libm/src/math/atanf.rs | 15 ++---- .../compiler-builtins/libm/src/math/atanh.rs | 6 +-- .../compiler-builtins/libm/src/math/atanhf.rs | 6 +-- .../compiler-builtins/libm/src/math/ceil.rs | 15 ++---- .../compiler-builtins/libm/src/math/ceilf.rs | 3 +- .../compiler-builtins/libm/src/math/cosf.rs | 4 +- .../compiler-builtins/libm/src/math/cosh.rs | 4 +- .../compiler-builtins/libm/src/math/coshf.rs | 4 +- .../compiler-builtins/libm/src/math/erf.rs | 12 +---- .../compiler-builtins/libm/src/math/erff.rs | 12 +---- .../compiler-builtins/libm/src/math/exp.rs | 6 +-- .../compiler-builtins/libm/src/math/exp10f.rs | 5 +- .../compiler-builtins/libm/src/math/expf.rs | 6 +-- .../compiler-builtins/libm/src/math/expm1f.rs | 6 +-- .../compiler-builtins/libm/src/math/fabs.rs | 3 +- .../compiler-builtins/libm/src/math/fabsf.rs | 3 +- .../compiler-builtins/libm/src/math/floor.rs | 15 ++---- .../compiler-builtins/libm/src/math/floorf.rs | 3 +- .../compiler-builtins/libm/src/math/fma.rs | 10 +--- .../compiler-builtins/libm/src/math/fmaf.rs | 8 +-- .../compiler-builtins/libm/src/math/fmodf.rs | 3 +- .../compiler-builtins/libm/src/math/ilogb.rs | 6 +-- .../compiler-builtins/libm/src/math/ilogbf.rs | 6 +-- library/compiler-builtins/libm/src/math/jn.rs | 12 +---- .../compiler-builtins/libm/src/math/jnf.rs | 12 +---- .../compiler-builtins/libm/src/math/k_sin.rs | 6 +-- .../compiler-builtins/libm/src/math/log1p.rs | 6 +-- .../compiler-builtins/libm/src/math/log1pf.rs | 6 +-- .../compiler-builtins/libm/src/math/mod.rs | 32 +++++------- .../compiler-builtins/libm/src/math/pow.rs | 50 +++++-------------- .../compiler-builtins/libm/src/math/powf.rs | 12 +---- .../libm/src/math/rem_pio2.rs | 20 ++------ .../libm/src/math/rem_pio2_large.rs | 3 +- .../libm/src/math/rem_pio2f.rs | 4 +- .../compiler-builtins/libm/src/math/remquo.rs | 6 +-- .../libm/src/math/remquof.rs | 6 +-- .../compiler-builtins/libm/src/math/rint.rs | 10 +--- .../compiler-builtins/libm/src/math/rintf.rs | 10 +--- .../compiler-builtins/libm/src/math/round.rs | 4 +- .../compiler-builtins/libm/src/math/roundf.rs | 4 +- .../compiler-builtins/libm/src/math/sinf.rs | 16 ++---- .../compiler-builtins/libm/src/math/sinhf.rs | 3 +- .../compiler-builtins/libm/src/math/sqrt.rs | 3 +- .../compiler-builtins/libm/src/math/sqrtf.rs | 10 ++-- .../compiler-builtins/libm/src/math/tan.rs | 6 +-- .../compiler-builtins/libm/src/math/tanf.rs | 10 ++-- .../compiler-builtins/libm/src/math/tanh.rs | 6 +-- .../compiler-builtins/libm/src/math/tanhf.rs | 6 +-- 57 files changed, 131 insertions(+), 393 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs index 3a49e3c573151..9653bd8301359 100644 --- a/library/compiler-builtins/libm/crates/libm-test/build.rs +++ b/library/compiler-builtins/libm/crates/libm-test/build.rs @@ -5,12 +5,12 @@ fn main() { #[cfg(feature = "test-musl-serialized")] mod musl_reference_tests { - use rand::seq::SliceRandom; - use rand::Rng; - use std::env; - use std::fs; use std::path::PathBuf; use std::process::Command; + use std::{env, fs}; + + use rand::Rng; + use rand::seq::SliceRandom; // Number of tests to generate for each function const NTESTS: usize = 500; @@ -60,10 +60,7 @@ mod musl_reference_tests { return; } - let files = fs::read_dir(math_src) - .unwrap() - .map(|f| f.unwrap().path()) - .collect::>(); + let files = fs::read_dir(math_src).unwrap().map(|f| f.unwrap().path()).collect::>(); let mut math = Vec::new(); for file in files { @@ -112,12 +109,7 @@ mod musl_reference_tests { let tail = eat(tail, " -> "); let ret = parse_retty(tail.replace("{", "").trim()); - return Function { - name: name.to_string(), - args, - ret, - tests: Vec::new(), - }; + return Function { name: name.to_string(), args, ret, tests: Vec::new() }; fn parse_ty(s: &str) -> Ty { match s { @@ -156,11 +148,7 @@ mod musl_reference_tests { } fn generate_test(function: &Function, rng: &mut R) -> Test { - let mut inputs = function - .args - .iter() - .map(|ty| ty.gen_i64(rng)) - .collect::>(); + let mut inputs = function.args.iter().map(|ty| ty.gen_i64(rng)).collect::>(); // First argument to this function appears to be a number of // iterations, so passing in massive random numbers causes it to @@ -180,15 +168,12 @@ mod musl_reference_tests { impl Ty { fn gen_i64(&self, r: &mut R) -> i64 { - use std::f32; - use std::f64; + use std::{f32, f64}; return match self { Ty::F32 => { if r.gen_range(0..20) < 1 { - let i = *[f32::NAN, f32::INFINITY, f32::NEG_INFINITY] - .choose(r) - .unwrap(); + let i = *[f32::NAN, f32::INFINITY, f32::NEG_INFINITY].choose(r).unwrap(); i.to_bits().into() } else { r.gen::().to_bits().into() @@ -196,9 +181,7 @@ mod musl_reference_tests { } Ty::F64 => { if r.gen_range(0..20) < 1 { - let i = *[f64::NAN, f64::INFINITY, f64::NEG_INFINITY] - .choose(r) - .unwrap(); + let i = *[f64::NAN, f64::INFINITY, f64::NEG_INFINITY].choose(r).unwrap(); i.to_bits() as i64 } else { r.gen::().to_bits() as i64 @@ -424,11 +407,7 @@ mod musl_reference_tests { src.push_str(");"); for (i, ret) in function.ret.iter().enumerate() { - let get = if function.ret.len() == 1 { - String::new() - } else { - format!(".{}", i) - }; + let get = if function.ret.len() == 1 { String::new() } else { format!(".{}", i) }; src.push_str(&(match ret { Ty::F32 => format!("if libm::_eqf(output{}, f32::from_bits(expected[{}] as u32)).is_ok() {{ continue }}", get, i), Ty::F64 => format!("if libm::_eq(output{}, f64::from_bits(expected[{}] as u64)).is_ok() {{ continue }}", get, i), diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 04f4ac0f2e18a..6d95fa1737b35 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -17,9 +17,10 @@ mod math; use core::{f32, f64}; -pub use self::math::*; pub use libm_helper::*; +pub use self::math::*; + /// Approximate equality with 1 ULP of tolerance #[doc(hidden)] #[inline] @@ -29,11 +30,7 @@ pub fn _eqf(a: f32, b: f32) -> Result<(), u32> { } else { let err = (a.to_bits() as i32).wrapping_sub(b.to_bits() as i32).abs(); - if err <= 1 { - Ok(()) - } else { - Err(err as u32) - } + if err <= 1 { Ok(()) } else { Err(err as u32) } } } @@ -45,10 +42,6 @@ pub fn _eq(a: f64, b: f64) -> Result<(), u64> { } else { let err = (a.to_bits() as i64).wrapping_sub(b.to_bits() as i64).abs(); - if err <= 1 { - Ok(()) - } else { - Err(err as u64) - } + if err <= 1 { Ok(()) } else { Err(err as u64) } } } diff --git a/library/compiler-builtins/libm/src/math/asin.rs b/library/compiler-builtins/libm/src/math/asin.rs index 3e4b7c56ebae1..12fe08fc74527 100644 --- a/library/compiler-builtins/libm/src/math/asin.rs +++ b/library/compiler-builtins/libm/src/math/asin.rs @@ -111,9 +111,5 @@ pub fn asin(mut x: f64) -> f64 { c = (z - f * f) / (s + f); x = 0.5 * PIO2_HI - (2.0 * s * r - (PIO2_LO - 2.0 * c) - (0.5 * PIO2_HI - 2.0 * f)); } - if hx >> 31 != 0 { - -x - } else { - x - } + if hx >> 31 != 0 { -x } else { x } } diff --git a/library/compiler-builtins/libm/src/math/asinf.rs b/library/compiler-builtins/libm/src/math/asinf.rs index 6ec61b6297823..2c785abe2baf2 100644 --- a/library/compiler-builtins/libm/src/math/asinf.rs +++ b/library/compiler-builtins/libm/src/math/asinf.rs @@ -64,9 +64,5 @@ pub fn asinf(mut x: f32) -> f32 { let z = (1. - fabsf(x)) * 0.5; let s = sqrt(z as f64); x = (PIO2 - 2. * (s + s * (r(z) as f64))) as f32; - if (hx >> 31) != 0 { - -x - } else { - x - } + if (hx >> 31) != 0 { -x } else { x } } diff --git a/library/compiler-builtins/libm/src/math/asinh.rs b/library/compiler-builtins/libm/src/math/asinh.rs index 0abd80c2fd723..75d3c3ad462ac 100644 --- a/library/compiler-builtins/libm/src/math/asinh.rs +++ b/library/compiler-builtins/libm/src/math/asinh.rs @@ -32,9 +32,5 @@ pub fn asinh(mut x: f64) -> f64 { force_eval!(x + x1p120); } - if sign { - -x - } else { - x - } + if sign { -x } else { x } } diff --git a/library/compiler-builtins/libm/src/math/asinhf.rs b/library/compiler-builtins/libm/src/math/asinhf.rs index 09c77823e1050..27ed9dd372daa 100644 --- a/library/compiler-builtins/libm/src/math/asinhf.rs +++ b/library/compiler-builtins/libm/src/math/asinhf.rs @@ -31,9 +31,5 @@ pub fn asinhf(mut x: f32) -> f32 { force_eval!(x + x1p120); } - if sign { - -x - } else { - x - } + if sign { -x } else { x } } diff --git a/library/compiler-builtins/libm/src/math/atan.rs b/library/compiler-builtins/libm/src/math/atan.rs index 4259dc71aaba5..4ca5cc91a1e48 100644 --- a/library/compiler-builtins/libm/src/math/atan.rs +++ b/library/compiler-builtins/libm/src/math/atan.rs @@ -29,9 +29,10 @@ * to produce the hexadecimal values shown. */ -use super::fabs; use core::f64; +use super::fabs; + const ATANHI: [f64; 4] = [ 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */ 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */ @@ -128,18 +129,15 @@ pub fn atan(x: f64) -> f64 { let z = i!(ATANHI, id as usize) - (x * (s1 + s2) - i!(ATANLO, id as usize) - x); - if sign != 0 { - -z - } else { - z - } + if sign != 0 { -z } else { z } } #[cfg(test)] mod tests { - use super::atan; use core::f64; + use super::atan; + #[test] fn sanity_check() { for (input, answer) in [ diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs index fb2ea4edaf56d..b9bf0da935bc7 100644 --- a/library/compiler-builtins/libm/src/math/atan2.rs +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -37,8 +37,7 @@ * to produce the hexadecimal values shown. */ -use super::atan; -use super::fabs; +use super::{atan, fabs}; const PI: f64 = 3.1415926535897931160E+00; /* 0x400921FB, 0x54442D18 */ const PI_LO: f64 = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ diff --git a/library/compiler-builtins/libm/src/math/atan2f.rs b/library/compiler-builtins/libm/src/math/atan2f.rs index eae3b002daeec..fa33f54f6f76c 100644 --- a/library/compiler-builtins/libm/src/math/atan2f.rs +++ b/library/compiler-builtins/libm/src/math/atan2f.rs @@ -13,8 +13,7 @@ * ==================================================== */ -use super::atanf; -use super::fabsf; +use super::{atanf, fabsf}; const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ const PI_LO: f32 = -8.7422776573e-08; /* 0xb3bbbd2e */ diff --git a/library/compiler-builtins/libm/src/math/atanf.rs b/library/compiler-builtins/libm/src/math/atanf.rs index d042b3bc0fd91..eb3d401cd967e 100644 --- a/library/compiler-builtins/libm/src/math/atanf.rs +++ b/library/compiler-builtins/libm/src/math/atanf.rs @@ -29,13 +29,8 @@ const ATAN_LO: [f32; 4] = [ 7.5497894159e-08, /* atan(inf)lo 0x33a22168 */ ]; -const A_T: [f32; 5] = [ - 3.3333328366e-01, - -1.9999158382e-01, - 1.4253635705e-01, - -1.0648017377e-01, - 6.1687607318e-02, -]; +const A_T: [f32; 5] = + [3.3333328366e-01, -1.9999158382e-01, 1.4253635705e-01, -1.0648017377e-01, 6.1687607318e-02]; /// Arctangent (f32) /// @@ -104,9 +99,5 @@ pub fn atanf(mut x: f32) -> f32 { } let id = id as usize; let z = i!(ATAN_HI, id) - ((x * (s1 + s2) - i!(ATAN_LO, id)) - x); - if sign { - -z - } else { - z - } + if sign { -z } else { z } } diff --git a/library/compiler-builtins/libm/src/math/atanh.rs b/library/compiler-builtins/libm/src/math/atanh.rs index b984c4ac62820..9dc826f5605b8 100644 --- a/library/compiler-builtins/libm/src/math/atanh.rs +++ b/library/compiler-builtins/libm/src/math/atanh.rs @@ -29,9 +29,5 @@ pub fn atanh(x: f64) -> f64 { y = 0.5 * log1p(2.0 * (y / (1.0 - y))); } - if sign { - -y - } else { - y - } + if sign { -y } else { y } } diff --git a/library/compiler-builtins/libm/src/math/atanhf.rs b/library/compiler-builtins/libm/src/math/atanhf.rs index a1aa314a50f35..3545411bbd5ba 100644 --- a/library/compiler-builtins/libm/src/math/atanhf.rs +++ b/library/compiler-builtins/libm/src/math/atanhf.rs @@ -29,9 +29,5 @@ pub fn atanhf(mut x: f32) -> f32 { x = 0.5 * log1pf(2.0 * (x / (1.0 - x))); } - if sign { - -x - } else { - x - } + if sign { -x } else { x } } diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index cde5a19d0c807..1593fdaffcee7 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -42,28 +42,21 @@ pub fn ceil(x: f64) -> f64 { return x; } // y = int(x) - x, where int(x) is an integer neighbor of x - y = if (u >> 63) != 0 { - x - TOINT + TOINT - x - } else { - x + TOINT - TOINT - x - }; + y = if (u >> 63) != 0 { x - TOINT + TOINT - x } else { x + TOINT - TOINT - x }; // special case because of non-nearest rounding modes if e < 0x3ff { force_eval!(y); return if (u >> 63) != 0 { -0. } else { 1. }; } - if y < 0. { - x + y + 1. - } else { - x + y - } + if y < 0. { x + y + 1. } else { x + y } } #[cfg(test)] mod tests { - use super::*; use core::f64::*; + use super::*; + #[test] fn sanity_check() { assert_eq!(ceil(1.1), 2.0); diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index 7bcc647ca76a1..bf9ba12279cf0 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -44,9 +44,10 @@ pub fn ceilf(x: f32) -> f32 { #[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { - use super::*; use core::f32::*; + use super::*; + #[test] fn sanity_check() { assert_eq!(ceilf(1.1), 2.0); diff --git a/library/compiler-builtins/libm/src/math/cosf.rs b/library/compiler-builtins/libm/src/math/cosf.rs index 424fa42eda612..0a01335f7707e 100644 --- a/library/compiler-builtins/libm/src/math/cosf.rs +++ b/library/compiler-builtins/libm/src/math/cosf.rs @@ -14,10 +14,10 @@ * ==================================================== */ -use super::{k_cosf, k_sinf, rem_pio2f}; - use core::f64::consts::FRAC_PI_2; +use super::{k_cosf, k_sinf, rem_pio2f}; + /* Small multiples of pi/2 rounded to double precision. */ const C1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ const C2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ diff --git a/library/compiler-builtins/libm/src/math/cosh.rs b/library/compiler-builtins/libm/src/math/cosh.rs index 2fb568ab314c3..d2e43fd6cb690 100644 --- a/library/compiler-builtins/libm/src/math/cosh.rs +++ b/library/compiler-builtins/libm/src/math/cosh.rs @@ -1,6 +1,4 @@ -use super::exp; -use super::expm1; -use super::k_expo2; +use super::{exp, expm1, k_expo2}; /// Hyperbolic cosine (f64) /// diff --git a/library/compiler-builtins/libm/src/math/coshf.rs b/library/compiler-builtins/libm/src/math/coshf.rs index e7b684587887e..567a24410e796 100644 --- a/library/compiler-builtins/libm/src/math/coshf.rs +++ b/library/compiler-builtins/libm/src/math/coshf.rs @@ -1,6 +1,4 @@ -use super::expf; -use super::expm1f; -use super::k_expo2f; +use super::{expf, expm1f, k_expo2f}; /// Hyperbolic cosine (f64) /// diff --git a/library/compiler-builtins/libm/src/math/erf.rs b/library/compiler-builtins/libm/src/math/erf.rs index 55569affc9753..1b634abec6bc6 100644 --- a/library/compiler-builtins/libm/src/math/erf.rs +++ b/library/compiler-builtins/libm/src/math/erf.rs @@ -256,11 +256,7 @@ pub fn erf(x: f64) -> f64 { y = 1.0 - x1p_1022; } - if sign != 0 { - -y - } else { - y - } + if sign != 0 { -y } else { y } } /// Complementary error function (f64) @@ -310,9 +306,5 @@ pub fn erfc(x: f64) -> f64 { } let x1p_1022 = f64::from_bits(0x0010000000000000); - if sign != 0 { - 2.0 - x1p_1022 - } else { - x1p_1022 * x1p_1022 - } + if sign != 0 { 2.0 - x1p_1022 } else { x1p_1022 * x1p_1022 } } diff --git a/library/compiler-builtins/libm/src/math/erff.rs b/library/compiler-builtins/libm/src/math/erff.rs index 7b25474f6025e..2e41183bfc0f7 100644 --- a/library/compiler-builtins/libm/src/math/erff.rs +++ b/library/compiler-builtins/libm/src/math/erff.rs @@ -167,11 +167,7 @@ pub fn erff(x: f32) -> f32 { y = 1.0 - x1p_120; } - if sign != 0 { - -y - } else { - y - } + if sign != 0 { -y } else { y } } /// Complementary error function (f32) @@ -222,9 +218,5 @@ pub fn erfcf(x: f32) -> f32 { } let x1p_120 = f32::from_bits(0x03800000); - if sign != 0 { - 2.0 - x1p_120 - } else { - x1p_120 * x1p_120 - } + if sign != 0 { 2.0 - x1p_120 } else { x1p_120 * x1p_120 } } diff --git a/library/compiler-builtins/libm/src/math/exp.rs b/library/compiler-builtins/libm/src/math/exp.rs index d4994277f8954..782042b62cd3a 100644 --- a/library/compiler-builtins/libm/src/math/exp.rs +++ b/library/compiler-builtins/libm/src/math/exp.rs @@ -146,9 +146,5 @@ pub fn exp(mut x: f64) -> f64 { xx = x * x; c = x - xx * (P1 + xx * (P2 + xx * (P3 + xx * (P4 + xx * P5)))); y = 1. + (x * c / (2. - c) - lo + hi); - if k == 0 { - y - } else { - scalbn(y, k) - } + if k == 0 { y } else { scalbn(y, k) } } diff --git a/library/compiler-builtins/libm/src/math/exp10f.rs b/library/compiler-builtins/libm/src/math/exp10f.rs index 1279bc6c566b9..786305481dcfb 100644 --- a/library/compiler-builtins/libm/src/math/exp10f.rs +++ b/library/compiler-builtins/libm/src/math/exp10f.rs @@ -2,9 +2,8 @@ use super::{exp2, exp2f, modff}; const LN10_F32: f32 = 3.32192809488736234787031942948939; const LN10_F64: f64 = 3.32192809488736234787031942948939; -const P10: &[f32] = &[ - 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, -]; +const P10: &[f32] = + &[1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7]; #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp10f(x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs index a53aa90a646a9..8dc067ab0846f 100644 --- a/library/compiler-builtins/libm/src/math/expf.rs +++ b/library/compiler-builtins/libm/src/math/expf.rs @@ -93,9 +93,5 @@ pub fn expf(mut x: f32) -> f32 { let xx = x * x; let c = x - xx * (P1 + xx * P2); let y = 1. + (x * c / (2. - c) - lo + hi); - if k == 0 { - y - } else { - scalbnf(y, k) - } + if k == 0 { y } else { scalbnf(y, k) } } diff --git a/library/compiler-builtins/libm/src/math/expm1f.rs b/library/compiler-builtins/libm/src/math/expm1f.rs index 3fc2a247b5bee..a862fe2558c49 100644 --- a/library/compiler-builtins/libm/src/math/expm1f.rs +++ b/library/compiler-builtins/libm/src/math/expm1f.rs @@ -126,9 +126,5 @@ pub fn expm1f(mut x: f32) -> f32 { return y - 1.; } let uf = f32::from_bits(((0x7f - k) << 23) as u32); /* 2^-k */ - if k < 23 { - (x - e + (1. - uf)) * twopk - } else { - (x - (e + uf) + 1.) * twopk - } + if k < 23 { (x - e + (1. - uf)) * twopk } else { (x - (e + uf) + 1.) * twopk } } diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index b2255ad32cf32..3b0628aa63a74 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -18,9 +18,10 @@ pub fn fabs(x: f64) -> f64 { #[cfg(test)] mod tests { - use super::*; use core::f64::*; + use super::*; + #[test] fn sanity_check() { assert_eq!(fabs(-1.0), 1.0); diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index 23f3646dc4a5a..f81c8ca44236d 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -18,9 +18,10 @@ pub fn fabsf(x: f32) -> f32 { #[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { - use super::*; use core::f32::*; + use super::*; + #[test] fn sanity_check() { assert_eq!(fabsf(-1.0), 1.0); diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index b7d1a04d2cd35..e8fb21e5884bc 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -41,28 +41,21 @@ pub fn floor(x: f64) -> f64 { return x; } /* y = int(x) - x, where int(x) is an integer neighbor of x */ - let y = if (ui >> 63) != 0 { - x - TOINT + TOINT - x - } else { - x + TOINT - TOINT - x - }; + let y = if (ui >> 63) != 0 { x - TOINT + TOINT - x } else { x + TOINT - TOINT - x }; /* special case because of non-nearest rounding modes */ if e < 0x3ff { force_eval!(y); return if (ui >> 63) != 0 { -1. } else { 0. }; } - if y > 0. { - x + y - 1. - } else { - x + y - } + if y > 0. { x + y - 1. } else { x + y } } #[cfg(test)] mod tests { - use super::*; use core::f64::*; + use super::*; + #[test] fn sanity_check() { assert_eq!(floor(1.1), 1.0); diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index dfdab91a0f695..f66cab74fdcfd 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -44,9 +44,10 @@ pub fn floorf(x: f32) -> f32 { #[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { - use super::*; use core::f32::*; + use super::*; + #[test] fn sanity_check() { assert_eq!(floorf(0.5), 0.0); diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 940ee2db927bc..bb2028fa77f25 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -216,17 +216,11 @@ mod tests { #[test] fn fma_sbb() { - assert_eq!( - fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), - -3991680619069439e277 - ); + assert_eq!(fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), -3991680619069439e277); } #[test] fn fma_underflow() { - assert_eq!( - fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), - 0.0, - ); + assert_eq!(fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), 0.0,); } } diff --git a/library/compiler-builtins/libm/src/math/fmaf.rs b/library/compiler-builtins/libm/src/math/fmaf.rs index 2848f2aee0c37..10bdaeab33dec 100644 --- a/library/compiler-builtins/libm/src/math/fmaf.rs +++ b/library/compiler-builtins/libm/src/math/fmaf.rs @@ -29,7 +29,7 @@ use core::f32; use core::ptr::read_volatile; use super::fenv::{ - feclearexcept, fegetround, feraiseexcept, fetestexcept, FE_INEXACT, FE_TONEAREST, FE_UNDERFLOW, + FE_INEXACT, FE_TONEAREST, FE_UNDERFLOW, feclearexcept, fegetround, feraiseexcept, fetestexcept, }; /* @@ -91,11 +91,7 @@ pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { * we need to adjust the low-order bit in the direction of the error. */ let neg = ui >> 63 != 0; - let err = if neg == (z as f64 > xy) { - xy - result + z as f64 - } else { - z as f64 - result + xy - }; + let err = if neg == (z as f64 > xy) { xy - result + z as f64 } else { z as f64 - result + xy }; if neg == (err < 0.0) { ui += 1; } else { diff --git a/library/compiler-builtins/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs index c53dc186aebac..1d80013842e70 100644 --- a/library/compiler-builtins/libm/src/math/fmodf.rs +++ b/library/compiler-builtins/libm/src/math/fmodf.rs @@ -1,5 +1,4 @@ -use core::f32; -use core::u32; +use core::{f32, u32}; #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmodf(x: f32, y: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/ilogb.rs b/library/compiler-builtins/libm/src/math/ilogb.rs index 7d74dcfb666d8..9d58d06081b76 100644 --- a/library/compiler-builtins/libm/src/math/ilogb.rs +++ b/library/compiler-builtins/libm/src/math/ilogb.rs @@ -21,11 +21,7 @@ pub fn ilogb(x: f64) -> i32 { e } else if e == 0x7ff { force_eval!(0.0 / 0.0); - if (i << 12) != 0 { - FP_ILOGBNAN - } else { - i32::max_value() - } + if (i << 12) != 0 { FP_ILOGBNAN } else { i32::max_value() } } else { e - 0x3ff } diff --git a/library/compiler-builtins/libm/src/math/ilogbf.rs b/library/compiler-builtins/libm/src/math/ilogbf.rs index 0fa58748c2f5e..85deb43c83b76 100644 --- a/library/compiler-builtins/libm/src/math/ilogbf.rs +++ b/library/compiler-builtins/libm/src/math/ilogbf.rs @@ -21,11 +21,7 @@ pub fn ilogbf(x: f32) -> i32 { e } else if e == 0xff { force_eval!(0.0 / 0.0); - if (i << 9) != 0 { - FP_ILOGBNAN - } else { - i32::max_value() - } + if (i << 9) != 0 { FP_ILOGBNAN } else { i32::max_value() } } else { e - 0x7f } diff --git a/library/compiler-builtins/libm/src/math/jn.rs b/library/compiler-builtins/libm/src/math/jn.rs index 1be167f8461aa..22ced20c15a4a 100644 --- a/library/compiler-builtins/libm/src/math/jn.rs +++ b/library/compiler-builtins/libm/src/math/jn.rs @@ -244,11 +244,7 @@ pub fn jn(n: i32, mut x: f64) -> f64 { } } - if sign { - -b - } else { - b - } + if sign { -b } else { b } } pub fn yn(n: i32, x: f64) -> f64 { @@ -335,9 +331,5 @@ pub fn yn(n: i32, x: f64) -> f64 { } } - if sign { - -b - } else { - b - } + if sign { -b } else { b } } diff --git a/library/compiler-builtins/libm/src/math/jnf.rs b/library/compiler-builtins/libm/src/math/jnf.rs index 360f62e201d46..9cd0bb37de9dc 100644 --- a/library/compiler-builtins/libm/src/math/jnf.rs +++ b/library/compiler-builtins/libm/src/math/jnf.rs @@ -188,11 +188,7 @@ pub fn jnf(n: i32, mut x: f32) -> f32 { } } - if sign { - -b - } else { - b - } + if sign { -b } else { b } } pub fn ynf(n: i32, x: f32) -> f32 { @@ -251,9 +247,5 @@ pub fn ynf(n: i32, x: f32) -> f32 { a = temp; } - if sign { - -b - } else { - b - } + if sign { -b } else { b } } diff --git a/library/compiler-builtins/libm/src/math/k_sin.rs b/library/compiler-builtins/libm/src/math/k_sin.rs index 9dd96c944744d..42441455ff32f 100644 --- a/library/compiler-builtins/libm/src/math/k_sin.rs +++ b/library/compiler-builtins/libm/src/math/k_sin.rs @@ -49,9 +49,5 @@ pub(crate) fn k_sin(x: f64, y: f64, iy: i32) -> f64 { let w = z * z; let r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6); let v = z * x; - if iy == 0 { - x + v * (S1 + z * r) - } else { - x - ((z * (0.5 * y - v * r) - y) - v * S1) - } + if iy == 0 { x + v * (S1 + z * r) } else { x - ((z * (0.5 * y - v * r) - y) - v * S1) } } diff --git a/library/compiler-builtins/libm/src/math/log1p.rs b/library/compiler-builtins/libm/src/math/log1p.rs index 4fd1c73eb81e5..552de549bfc68 100644 --- a/library/compiler-builtins/libm/src/math/log1p.rs +++ b/library/compiler-builtins/libm/src/math/log1p.rs @@ -117,11 +117,7 @@ pub fn log1p(x: f64) -> f64 { k = (hu >> 20) as i32 - 0x3ff; /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ if k < 54 { - c = if k >= 2 { - 1. - (f64::from_bits(ui) - x) - } else { - x - (f64::from_bits(ui) - 1.) - }; + c = if k >= 2 { 1. - (f64::from_bits(ui) - x) } else { x - (f64::from_bits(ui) - 1.) }; c /= f64::from_bits(ui); } else { c = 0.; diff --git a/library/compiler-builtins/libm/src/math/log1pf.rs b/library/compiler-builtins/libm/src/math/log1pf.rs index 500e8eeaa85e9..8068128db4f8d 100644 --- a/library/compiler-builtins/libm/src/math/log1pf.rs +++ b/library/compiler-builtins/libm/src/math/log1pf.rs @@ -72,11 +72,7 @@ pub fn log1pf(x: f32) -> f32 { k = (iu >> 23) as i32 - 0x7f; /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ if k < 25 { - c = if k >= 2 { - 1. - (f32::from_bits(ui) - x) - } else { - x - (f32::from_bits(ui) - 1.) - }; + c = if k >= 2 { 1. - (f32::from_bits(ui) - x) } else { x - (f32::from_bits(ui) - 1.) }; c /= f32::from_bits(ui); } else { c = 0.; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index a56532dddc141..85c9fc5bf1566 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -218,15 +218,13 @@ pub use self::cos::cos; pub use self::cosf::cosf; pub use self::cosh::cosh; pub use self::coshf::coshf; -pub use self::erf::erf; -pub use self::erf::erfc; -pub use self::erff::erfcf; -pub use self::erff::erff; +pub use self::erf::{erf, erfc}; +pub use self::erff::{erfcf, erff}; pub use self::exp::exp; -pub use self::exp10::exp10; -pub use self::exp10f::exp10f; pub use self::exp2::exp2; pub use self::exp2f::exp2f; +pub use self::exp10::exp10; +pub use self::exp10f::exp10f; pub use self::expf::expf; pub use self::expm1::expm1; pub use self::expm1f::expm1f; @@ -250,18 +248,12 @@ pub use self::hypot::hypot; pub use self::hypotf::hypotf; pub use self::ilogb::ilogb; pub use self::ilogbf::ilogbf; -pub use self::j0::j0; -pub use self::j0::y0; -pub use self::j0f::j0f; -pub use self::j0f::y0f; -pub use self::j1::j1; -pub use self::j1::y1; -pub use self::j1f::j1f; -pub use self::j1f::y1f; -pub use self::jn::jn; -pub use self::jn::yn; -pub use self::jnf::jnf; -pub use self::jnf::ynf; +pub use self::j0::{j0, y0}; +pub use self::j0f::{j0f, y0f}; +pub use self::j1::{j1, y1}; +pub use self::j1f::{j1f, y1f}; +pub use self::jn::{jn, yn}; +pub use self::jnf::{jnf, ynf}; pub use self::ldexp::ldexp; pub use self::ldexpf::ldexpf; pub use self::lgamma::lgamma; @@ -269,12 +261,12 @@ pub use self::lgamma_r::lgamma_r; pub use self::lgammaf::lgammaf; pub use self::lgammaf_r::lgammaf_r; pub use self::log::log; -pub use self::log10::log10; -pub use self::log10f::log10f; pub use self::log1p::log1p; pub use self::log1pf::log1pf; pub use self::log2::log2; pub use self::log2f::log2f; +pub use self::log10::log10; +pub use self::log10f::log10f; pub use self::logf::logf; pub use self::modf::modf; pub use self::modff::modff; diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 09d12c1851b48..9b617cadbfede 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -159,18 +159,10 @@ pub fn pow(x: f64, y: f64) -> f64 { 1.0 } else if ix >= 0x3ff00000 { /* (|x|>1)**+-inf = inf,0 */ - if hy >= 0 { - y - } else { - 0.0 - } + if hy >= 0 { y } else { 0.0 } } else { /* (|x|<1)**+-inf = 0,inf */ - if hy >= 0 { - 0.0 - } else { - -y - } + if hy >= 0 { 0.0 } else { -y } }; } @@ -246,18 +238,10 @@ pub fn pow(x: f64, y: f64) -> f64 { /* over/underflow if x is not close to one */ if ix < 0x3fefffff { - return if hy < 0 { - s * HUGE * HUGE - } else { - s * TINY * TINY - }; + return if hy < 0 { s * HUGE * HUGE } else { s * TINY * TINY }; } if ix > 0x3ff00000 { - return if hy > 0 { - s * HUGE * HUGE - } else { - s * TINY * TINY - }; + return if hy > 0 { s * HUGE * HUGE } else { s * TINY * TINY }; } /* now |1-x| is TINY <= 2**-20, suffice to compute @@ -455,11 +439,7 @@ mod tests { fn pow_test(base: f64, exponent: f64, expected: f64) { let res = pow(base, exponent); assert!( - if expected.is_nan() { - res.is_nan() - } else { - pow(base, exponent) == expected - }, + if expected.is_nan() { res.is_nan() } else { pow(base, exponent) == expected }, "{} ** {} was {} instead of {}", base, exponent, @@ -469,13 +449,11 @@ mod tests { } fn test_sets_as_base(sets: &[&[f64]], exponent: f64, expected: f64) { - sets.iter() - .for_each(|s| s.iter().for_each(|val| pow_test(*val, exponent, expected))); + sets.iter().for_each(|s| s.iter().for_each(|val| pow_test(*val, exponent, expected))); } fn test_sets_as_exponent(base: f64, sets: &[&[f64]], expected: f64) { - sets.iter() - .for_each(|s| s.iter().for_each(|val| pow_test(base, *val, expected))); + sets.iter().for_each(|s| s.iter().for_each(|val| pow_test(base, *val, expected))); } fn test_sets(sets: &[&[f64]], computed: &dyn Fn(f64) -> f64, expected: &dyn Fn(f64) -> f64) { @@ -489,11 +467,7 @@ mod tests { #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] let res = force_eval!(res); assert!( - if exp.is_nan() { - res.is_nan() - } else { - exp == res - }, + if exp.is_nan() { res.is_nan() } else { exp == res }, "test for {} was {} instead of {}", val, res, @@ -608,15 +582,15 @@ mod tests { // Factoring -1 out: // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer)) - (&[POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS]) - .iter() - .for_each(|int_set| { + (&[POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS]).iter().for_each( + |int_set| { int_set.iter().for_each(|int| { test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| { pow(-1.0, *int) * pow(v, *int) }); }) - }); + }, + ); // Negative base (imaginary results): // (-anything except 0 and Infinity ^ non-integer should be NAN) diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs index 68d2083bbdd79..d47ab4b3d1d9d 100644 --- a/library/compiler-builtins/libm/src/math/powf.rs +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -181,19 +181,11 @@ pub fn powf(x: f32, y: f32) -> f32 { /* if |y| > 2**27 */ /* over/underflow if x is not close to one */ if ix < 0x3f7ffff8 { - return if hy < 0 { - sn * HUGE * HUGE - } else { - sn * TINY * TINY - }; + return if hy < 0 { sn * HUGE * HUGE } else { sn * TINY * TINY }; } if ix > 0x3f800007 { - return if hy > 0 { - sn * HUGE * HUGE - } else { - sn * TINY * TINY - }; + return if hy > 0 { sn * HUGE * HUGE } else { sn * TINY * TINY }; } /* now |1-x| is TINY <= 2**-20, suffice to compute diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 644616f2df84d..6be23a43cede2 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -197,28 +197,16 @@ mod tests { fn test_near_pi() { let arg = 3.141592025756836; let arg = force_eval!(arg); - assert_eq!( - rem_pio2(arg), - (2, -6.278329573009626e-7, -2.1125998133974653e-23) - ); + assert_eq!(rem_pio2(arg), (2, -6.278329573009626e-7, -2.1125998133974653e-23)); let arg = 3.141592033207416; let arg = force_eval!(arg); - assert_eq!( - rem_pio2(arg), - (2, -6.20382377148128e-7, -2.1125998133974653e-23) - ); + assert_eq!(rem_pio2(arg), (2, -6.20382377148128e-7, -2.1125998133974653e-23)); let arg = 3.141592144966125; let arg = force_eval!(arg); - assert_eq!( - rem_pio2(arg), - (2, -5.086236681942706e-7, -2.1125998133974653e-23) - ); + assert_eq!(rem_pio2(arg), (2, -5.086236681942706e-7, -2.1125998133974653e-23)); let arg = 3.141592979431152; let arg = force_eval!(arg); - assert_eq!( - rem_pio2(arg), - (2, 3.2584135866119817e-7, -2.1125998133974653e-23) - ); + assert_eq!(rem_pio2(arg), (2, 3.2584135866119817e-7, -2.1125998133974653e-23)); } #[test] 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 db97a39d49021..1dfbba3b1b226 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -11,8 +11,7 @@ * ==================================================== */ -use super::floor; -use super::scalbn; +use super::{floor, scalbn}; // initial value for jk const INIT_JK: [usize; 4] = [3, 4, 4, 6]; diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs index 775f5d750fb11..3c658fe3dbce2 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2f.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2f.rs @@ -14,10 +14,10 @@ * ==================================================== */ -use super::rem_pio2_large; - use core::f64; +use super::rem_pio2_large; + const TOINT: f64 = 1.5 / f64::EPSILON; /// 53 bits of 2/pi diff --git a/library/compiler-builtins/libm/src/math/remquo.rs b/library/compiler-builtins/libm/src/math/remquo.rs index 0afd1f7f5f2a3..4c11e848746bc 100644 --- a/library/compiler-builtins/libm/src/math/remquo.rs +++ b/library/compiler-builtins/libm/src/math/remquo.rs @@ -91,11 +91,7 @@ pub fn remquo(mut x: f64, mut y: f64) -> (f64, i32) { } q &= 0x7fffffff; let quo = if sx ^ sy { -(q as i32) } else { q as i32 }; - if sx { - (-x, quo) - } else { - (x, quo) - } + if sx { (-x, quo) } else { (x, quo) } } #[cfg(test)] diff --git a/library/compiler-builtins/libm/src/math/remquof.rs b/library/compiler-builtins/libm/src/math/remquof.rs index d71bd38e3ddca..b0e85ca661160 100644 --- a/library/compiler-builtins/libm/src/math/remquof.rs +++ b/library/compiler-builtins/libm/src/math/remquof.rs @@ -89,9 +89,5 @@ pub fn remquof(mut x: f32, mut y: f32) -> (f32, i32) { } q &= 0x7fffffff; let quo = if sx ^ sy { -(q as i32) } else { q as i32 }; - if sx { - (-x, quo) - } else { - (x, quo) - } + if sx { (-x, quo) } else { (x, quo) } } diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index 8edbe34402232..618b26e5466b9 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -23,15 +23,7 @@ pub fn rint(x: f64) -> f64 { xminusoneovere + one_over_e }; - if ans == 0.0 { - if is_positive { - 0.0 - } else { - -0.0 - } - } else { - ans - } + if ans == 0.0 { if is_positive { 0.0 } else { -0.0 } } else { ans } } } diff --git a/library/compiler-builtins/libm/src/math/rintf.rs b/library/compiler-builtins/libm/src/math/rintf.rs index 7a7da618ad8f6..0726d83ba6732 100644 --- a/library/compiler-builtins/libm/src/math/rintf.rs +++ b/library/compiler-builtins/libm/src/math/rintf.rs @@ -23,15 +23,7 @@ pub fn rintf(x: f32) -> f32 { xminusoneovere + one_over_e }; - if ans == 0.0 { - if is_positive { - 0.0 - } else { - -0.0 - } - } else { - ans - } + if ans == 0.0 { if is_positive { 0.0 } else { -0.0 } } else { ans } } } diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs index 46fabc90ff534..b81ebaa1dbecc 100644 --- a/library/compiler-builtins/libm/src/math/round.rs +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -1,7 +1,7 @@ -use super::copysign; -use super::trunc; use core::f64; +use super::{copysign, trunc}; + #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn round(x: f64) -> f64 { trunc(x + copysign(0.5 - 0.25 * f64::EPSILON, x)) diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs index becdb5620a903..fb974bbfe73fe 100644 --- a/library/compiler-builtins/libm/src/math/roundf.rs +++ b/library/compiler-builtins/libm/src/math/roundf.rs @@ -1,7 +1,7 @@ -use super::copysignf; -use super::truncf; use core::f32; +use super::{copysignf, truncf}; + #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn roundf(x: f32) -> f32 { truncf(x + copysignf(0.5 - 0.25 * f32::EPSILON, x)) diff --git a/library/compiler-builtins/libm/src/math/sinf.rs b/library/compiler-builtins/libm/src/math/sinf.rs index 6e20be2aeee38..ca181462723ee 100644 --- a/library/compiler-builtins/libm/src/math/sinf.rs +++ b/library/compiler-builtins/libm/src/math/sinf.rs @@ -14,10 +14,10 @@ * ==================================================== */ -use super::{k_cosf, k_sinf, rem_pio2f}; - use core::f64::consts::FRAC_PI_2; +use super::{k_cosf, k_sinf, rem_pio2f}; + /* Small multiples of pi/2 rounded to double precision. */ const S1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ const S2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ @@ -39,11 +39,7 @@ pub fn sinf(x: f32) -> f32 { if ix < 0x39800000 { /* |x| < 2**-12 */ /* raise inexact if x!=0 and underflow if subnormal */ - force_eval!(if ix < 0x00800000 { - x / x1p120 - } else { - x + x1p120 - }); + force_eval!(if ix < 0x00800000 { x / x1p120 } else { x + x1p120 }); return x; } return k_sinf(x64); @@ -58,11 +54,7 @@ pub fn sinf(x: f32) -> f32 { return k_cosf(x64 - S1_PIO2); } } - return k_sinf(if sign { - -(x64 + S2_PIO2) - } else { - -(x64 - S2_PIO2) - }); + return k_sinf(if sign { -(x64 + S2_PIO2) } else { -(x64 - S2_PIO2) }); } if ix <= 0x40e231d5 { /* |x| ~<= 9*pi/4 */ diff --git a/library/compiler-builtins/libm/src/math/sinhf.rs b/library/compiler-builtins/libm/src/math/sinhf.rs index 24f863c4465e2..6788642f0c90e 100644 --- a/library/compiler-builtins/libm/src/math/sinhf.rs +++ b/library/compiler-builtins/libm/src/math/sinhf.rs @@ -1,5 +1,4 @@ -use super::expm1f; -use super::k_expo2f; +use super::{expm1f, k_expo2f}; #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sinhf(x: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 66cb7659c2dbe..5862b119b6410 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -242,9 +242,10 @@ pub fn sqrt(x: f64) -> f64 { #[cfg(test)] mod tests { - use super::*; use core::f64::*; + use super::*; + #[test] fn sanity_check() { assert_eq!(sqrt(100.0), 10.0); diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 16cbb2f977018..f7324c9413780 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -132,9 +132,10 @@ pub fn sqrtf(x: f32) -> f32 { #[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { - use super::*; use core::f32::*; + use super::*; + #[test] fn sanity_check() { assert_eq!(sqrtf(100.0), 10.0); @@ -154,12 +155,7 @@ mod tests { #[test] fn conformance_tests() { - let values = [ - 3.14159265359f32, - 10000.0f32, - f32::from_bits(0x0000000f), - INFINITY, - ]; + let values = [3.14159265359f32, 10000.0f32, f32::from_bits(0x0000000f), INFINITY]; let results = [1071833029u32, 1120403456u32, 456082799u32, 2139095040u32]; for i in 0..values.len() { diff --git a/library/compiler-builtins/libm/src/math/tan.rs b/library/compiler-builtins/libm/src/math/tan.rs index 5a72f68014abe..5aa44aeef72f6 100644 --- a/library/compiler-builtins/libm/src/math/tan.rs +++ b/library/compiler-builtins/libm/src/math/tan.rs @@ -49,11 +49,7 @@ pub fn tan(x: f64) -> f64 { if ix < 0x3e400000 { /* |x| < 2**-27 */ /* raise inexact if x!=0 and underflow if subnormal */ - force_eval!(if ix < 0x00100000 { - x / x1p120 as f64 - } else { - x + x1p120 as f64 - }); + force_eval!(if ix < 0x00100000 { x / x1p120 as f64 } else { x + x1p120 as f64 }); return x; } return k_tan(x, 0.0, 0); diff --git a/library/compiler-builtins/libm/src/math/tanf.rs b/library/compiler-builtins/libm/src/math/tanf.rs index 10de59c3917de..f6b2399d0941f 100644 --- a/library/compiler-builtins/libm/src/math/tanf.rs +++ b/library/compiler-builtins/libm/src/math/tanf.rs @@ -14,10 +14,10 @@ * ==================================================== */ -use super::{k_tanf, rem_pio2f}; - use core::f64::consts::FRAC_PI_2; +use super::{k_tanf, rem_pio2f}; + /* Small multiples of pi/2 rounded to double precision. */ const T1_PIO2: f64 = 1. * FRAC_PI_2; /* 0x3FF921FB, 0x54442D18 */ const T2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ @@ -39,11 +39,7 @@ pub fn tanf(x: f32) -> f32 { if ix < 0x39800000 { /* |x| < 2**-12 */ /* raise inexact if x!=0 and underflow if subnormal */ - force_eval!(if ix < 0x00800000 { - x / x1p120 - } else { - x + x1p120 - }); + force_eval!(if ix < 0x00800000 { x / x1p120 } else { x + x1p120 }); return x; } return k_tanf(x64, false); diff --git a/library/compiler-builtins/libm/src/math/tanh.rs b/library/compiler-builtins/libm/src/math/tanh.rs index 980c68554fd8b..cfea2c1670392 100644 --- a/library/compiler-builtins/libm/src/math/tanh.rs +++ b/library/compiler-builtins/libm/src/math/tanh.rs @@ -45,9 +45,5 @@ pub fn tanh(mut x: f64) -> f64 { t = x; } - if sign { - -t - } else { - t - } + if sign { -t } else { t } } diff --git a/library/compiler-builtins/libm/src/math/tanhf.rs b/library/compiler-builtins/libm/src/math/tanhf.rs index fc94e3ddd5899..ab13e1abf4c8d 100644 --- a/library/compiler-builtins/libm/src/math/tanhf.rs +++ b/library/compiler-builtins/libm/src/math/tanhf.rs @@ -31,9 +31,5 @@ pub fn tanhf(mut x: f32) -> f32 { force_eval!(x * x); x }; - if sign { - -tt - } else { - tt - } + if sign { -tt } else { tt } } From 79f065ab24d763de2aff166e297ba6df713651c5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 20:25:50 -0500 Subject: [PATCH 1373/4206] Add a .git-blame-ignore-revs file Include the recent formatting commit. --- library/compiler-builtins/libm/.git-blame-ignore-revs | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 library/compiler-builtins/libm/.git-blame-ignore-revs diff --git a/library/compiler-builtins/libm/.git-blame-ignore-revs b/library/compiler-builtins/libm/.git-blame-ignore-revs new file mode 100644 index 0000000000000..c1e43134f36fd --- /dev/null +++ b/library/compiler-builtins/libm/.git-blame-ignore-revs @@ -0,0 +1,5 @@ +# Use `git config blame.ignorerevsfile .git-blame-ignore-revs` to make +# `git blame` ignore the following commits. + +# Reformat with a new `.rustfmt.toml` +5882cabb83c30bf7c36023f9a55a80583636b0e8 From 4d6aeca6b3ae26628b73725a2b754f888dbb483a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 27 Oct 2024 01:08:38 -0500 Subject: [PATCH 1374/4206] Add a CI test that the crate builds on stable Currently everything we have runs with nightly Rust. Add a stable test to make sure we don't accidentally make use of behavior that isn't yet stable without gating it. --- .../compiler-builtins/libm/.github/workflows/main.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index f312e1f5e67c7..5340e91e56932 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -35,6 +35,16 @@ jobs: - run: cargo generate-lockfile - run: ./ci/run-docker.sh ${{ matrix.target }} + stable: + name: Build succeeds on stable + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Install Rust + run: rustup update stable && rustup default stable + - run: cargo build -p libm + + rustfmt: name: Rustfmt runs-on: ubuntu-latest From 3180b04aa3e7a09a9ba5c02d35348090d25e287d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 27 Oct 2024 22:45:37 -0500 Subject: [PATCH 1375/4206] Change `build.rs` to use the older `:` rather than `::` This allows supporting Rust < 1.77. --- library/compiler-builtins/libm/build.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 653ccf7993f70..b683557e4af8e 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -2,10 +2,10 @@ use std::env; fn main() { println!("cargo:rerun-if-changed=build.rs"); - println!("cargo::rustc-check-cfg=cfg(assert_no_panic)"); - println!("cargo::rustc-check-cfg=cfg(feature, values(\"unstable\"))"); + println!("cargo:rustc-check-cfg=cfg(assert_no_panic)"); + println!("cargo:rustc-check-cfg=cfg(feature, values(\"unstable\"))"); - println!("cargo::rustc-check-cfg=cfg(feature, values(\"checked\"))"); + println!("cargo:rustc-check-cfg=cfg(feature, values(\"checked\"))"); #[allow(unexpected_cfgs)] if !cfg!(feature = "checked") { From 3541e834df89db5e64c7baa29ea2ad743af05858 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 27 Oct 2024 22:46:22 -0500 Subject: [PATCH 1376/4206] Set the MSRV to 1.63 and document it as such Fixes: https://github.com/rust-lang/libm/issues/330 --- .../compiler-builtins/libm/.github/workflows/main.yml | 10 +++++++--- library/compiler-builtins/libm/Cargo.toml | 1 + library/compiler-builtins/libm/README.md | 4 ++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 5340e91e56932..400ca2c0b07cd 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -35,13 +35,17 @@ jobs: - run: cargo generate-lockfile - run: ./ci/run-docker.sh ${{ matrix.target }} - stable: - name: Build succeeds on stable + msrv: + name: Check MSRV runs-on: ubuntu-latest steps: - uses: actions/checkout@master + - run: | + msrv="$(perl -ne 'print if s/rust-version\s*=\s*"(.*)"/\1/g' Cargo.toml)" + echo "MSRV: $msrv" + echo "MSRV=$msrv" >> "$GITHUB_ENV" - name: Install Rust - run: rustup update stable && rustup default stable + run: rustup update "$MSRV" && rustup default "$MSRV" - run: cargo build -p libm diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index f04fc12df4d80..a498b4eb78d90 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -11,6 +11,7 @@ repository = "https://github.com/rust-lang/libm" version = "0.2.9" edition = "2021" exclude = ["/ci/", "/.github/workflows/"] +rust-version = "1.63" [features] default = [] diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 24ee3d1c16314..e5d64bd2dc031 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -34,6 +34,10 @@ To run all benchmarks: Please check [CONTRIBUTING.md](CONTRIBUTING.md) +## Minimum Rust version policy + +This crate supports rustc 1.63 and newer. + ## License Usage is licensed under the MIT license ([LICENSE-MIT](LICENSE-MIT) or From 476585d6a0befbfcaae2435e77591e4388600aab Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 03:49:48 +0000 Subject: [PATCH 1377/4206] chore: release v0.2.10 --- library/compiler-builtins/libm/CHANGELOG.md | 6 ++++++ library/compiler-builtins/libm/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index 36ed41d6ba545..317dfafc00797 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -8,6 +8,12 @@ and this project adheres to ## [Unreleased] +## [0.2.10](https://github.com/rust-lang/libm/compare/libm-v0.2.9...libm-v0.2.10) - 2024-10-28 + +### Other + +- Set the MSRV to 1.63 and test this in CI + ## [0.2.9](https://github.com/rust-lang/libm/compare/libm-v0.2.8...libm-v0.2.9) - 2024-10-26 ### Fixed diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index a498b4eb78d90..9282b71576d6f 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT AND (MIT OR Apache-2.0)" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/libm" -version = "0.2.9" +version = "0.2.10" edition = "2021" exclude = ["/ci/", "/.github/workflows/"] rust-version = "1.63" From b49ef8c5101cedf6e16966de970b84c916e78fe4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 27 Oct 2024 23:17:52 -0500 Subject: [PATCH 1378/4206] Don't deny warnings when checking MSRV 1.63 reports some false positive lints that we don't need to worry about. Make sure we don't fail CI for this. --- library/compiler-builtins/libm/.github/workflows/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 400ca2c0b07cd..f834b5defa1fc 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -38,6 +38,8 @@ jobs: msrv: name: Check MSRV runs-on: ubuntu-latest + env: + RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings` steps: - uses: actions/checkout@master - run: | From a3fd7732f0f0fd001950e094902c55b6d6429603 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 27 Oct 2024 23:41:29 -0500 Subject: [PATCH 1379/4206] ci: `rustup --no-self-update` and reuqire MSRV checks Pass `--no-self-update` to `rustup`, which is typical for CI. Also add the MSRV job to `success` so GitHub won't merge without it passing. --- .../libm/.github/workflows/main.yml | 63 ++++++++++--------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index f834b5defa1fc..926e3c19e2e7d 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -29,44 +29,19 @@ jobs: steps: - uses: actions/checkout@master - name: Install Rust - run: rustup update nightly && rustup default nightly + run: rustup update nightly --no-self-update && rustup default nightly - run: rustup target add ${{ matrix.target }} - run: rustup target add x86_64-unknown-linux-musl - run: cargo generate-lockfile - run: ./ci/run-docker.sh ${{ matrix.target }} - msrv: - name: Check MSRV - runs-on: ubuntu-latest - env: - RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings` - steps: - - uses: actions/checkout@master - - run: | - msrv="$(perl -ne 'print if s/rust-version\s*=\s*"(.*)"/\1/g' Cargo.toml)" - echo "MSRV: $msrv" - echo "MSRV=$msrv" >> "$GITHUB_ENV" - - name: Install Rust - run: rustup update "$MSRV" && rustup default "$MSRV" - - run: cargo build -p libm - - - rustfmt: - name: Rustfmt - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - name: Install Rust - run: rustup update nightly && rustup default nightly && rustup component add rustfmt - - run: cargo fmt -- --check - wasm: name: WebAssembly runs-on: ubuntu-latest steps: - uses: actions/checkout@master - name: Install Rust - run: rustup update nightly && rustup default nightly + run: rustup update nightly --no-self-update && rustup default nightly - run: rustup target add wasm32-unknown-unknown - run: cargo build --target wasm32-unknown-unknown @@ -76,7 +51,7 @@ jobs: steps: - uses: actions/checkout@master - name: Install Rust - run: rustup update nightly && rustup default nightly + run: rustup update nightly --no-self-update && rustup default nightly - run: cargo build -p cb benchmarks: @@ -85,16 +60,44 @@ jobs: steps: - uses: actions/checkout@master - name: Install Rust - run: rustup update nightly && rustup default nightly + run: rustup update nightly --no-self-update && rustup default nightly - run: cargo bench --all + msrv: + name: Check MSRV + runs-on: ubuntu-latest + env: + RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings` + steps: + - uses: actions/checkout@master + - run: | + msrv="$(perl -ne 'print if s/rust-version\s*=\s*"(.*)"/\1/g' Cargo.toml)" + echo "MSRV: $msrv" + echo "MSRV=$msrv" >> "$GITHUB_ENV" + - name: Install Rust + run: rustup update "$MSRV" --no-self-update && rustup default "$MSRV" + - run: cargo build -p libm + + rustfmt: + name: Rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Install Rust + run: | + rustup update nightly --no-self-update + rustup default nightly + rustup component add rustfmt + - run: cargo fmt -- --check + success: needs: - docker - - rustfmt - wasm - cb - benchmarks + - msrv + - rustfmt runs-on: ubuntu-latest # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency # failed" as success. So we have to do some contortions to ensure the job fails if any of its From db55857a731cb3d09ff309e00d1797c753e2141c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <44257381+JSorngard@users.noreply.github.com> Date: Mon, 28 Oct 2024 18:12:45 +0100 Subject: [PATCH 1380/4206] Add basic docstrings to some functions (#337) * Add docstring to Bessel functions * Add docstrings to logarithm functions * Add docstrings to pow functions * Specify argument bit-size of the Bessel functions * Specify argument bit-size for pow functions * Specify argument bit-size for logarithms * Add docstrings to sin, cos, sincos and sinh functions * Add docstrings to sqrt * Add docstrings to tan and tanh functions * Add an inline link to https://en.wikipedia.org/wiki/Bessel_function to the docstrings of all Bessel functions. --- library/compiler-builtins/libm/src/math/cos.rs | 4 ++++ library/compiler-builtins/libm/src/math/cosf.rs | 3 +++ library/compiler-builtins/libm/src/math/j0.rs | 2 ++ library/compiler-builtins/libm/src/math/j0f.rs | 2 ++ library/compiler-builtins/libm/src/math/j1.rs | 2 ++ library/compiler-builtins/libm/src/math/j1f.rs | 2 ++ library/compiler-builtins/libm/src/math/jn.rs | 2 ++ library/compiler-builtins/libm/src/math/jnf.rs | 2 ++ library/compiler-builtins/libm/src/math/log.rs | 1 + library/compiler-builtins/libm/src/math/log10.rs | 1 + library/compiler-builtins/libm/src/math/log10f.rs | 1 + library/compiler-builtins/libm/src/math/log1p.rs | 1 + library/compiler-builtins/libm/src/math/log1pf.rs | 1 + library/compiler-builtins/libm/src/math/log2.rs | 1 + library/compiler-builtins/libm/src/math/log2f.rs | 1 + library/compiler-builtins/libm/src/math/logf.rs | 1 + library/compiler-builtins/libm/src/math/pow.rs | 1 + library/compiler-builtins/libm/src/math/powf.rs | 1 + library/compiler-builtins/libm/src/math/sin.rs | 4 ++++ library/compiler-builtins/libm/src/math/sincos.rs | 3 +++ library/compiler-builtins/libm/src/math/sincosf.rs | 3 +++ library/compiler-builtins/libm/src/math/sinf.rs | 3 +++ library/compiler-builtins/libm/src/math/sinh.rs | 2 ++ library/compiler-builtins/libm/src/math/sinhf.rs | 1 + library/compiler-builtins/libm/src/math/sqrt.rs | 1 + library/compiler-builtins/libm/src/math/sqrtf.rs | 1 + library/compiler-builtins/libm/src/math/tan.rs | 4 ++++ library/compiler-builtins/libm/src/math/tanf.rs | 3 +++ library/compiler-builtins/libm/src/math/tanh.rs | 4 ++++ library/compiler-builtins/libm/src/math/tanhf.rs | 3 +++ 30 files changed, 61 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/cos.rs b/library/compiler-builtins/libm/src/math/cos.rs index db8bc49892610..de99cd4c5e454 100644 --- a/library/compiler-builtins/libm/src/math/cos.rs +++ b/library/compiler-builtins/libm/src/math/cos.rs @@ -41,6 +41,10 @@ use super::{k_cos, k_sin, rem_pio2}; // Accuracy: // TRIG(x) returns trig(x) nearly rounded // + +/// The cosine of `x` (f64). +/// +/// `x` is specified in radians. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cos(x: f64) -> f64 { let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff; diff --git a/library/compiler-builtins/libm/src/math/cosf.rs b/library/compiler-builtins/libm/src/math/cosf.rs index 0a01335f7707e..27c2fc3b9945f 100644 --- a/library/compiler-builtins/libm/src/math/cosf.rs +++ b/library/compiler-builtins/libm/src/math/cosf.rs @@ -24,6 +24,9 @@ const C2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ const C3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ const C4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ +/// The cosine of `x` (f32). +/// +/// `x` is specified in radians. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cosf(x: f32) -> f32 { let x64 = x as f64; diff --git a/library/compiler-builtins/libm/src/math/j0.rs b/library/compiler-builtins/libm/src/math/j0.rs index c4258ccca162d..5e5e839f81a5d 100644 --- a/library/compiler-builtins/libm/src/math/j0.rs +++ b/library/compiler-builtins/libm/src/math/j0.rs @@ -109,6 +109,7 @@ const S02: f64 = 1.16926784663337450260e-04; /* 0x3F1EA6D2, 0xDD57DBF4 */ const S03: f64 = 5.13546550207318111446e-07; /* 0x3EA13B54, 0xCE84D5A9 */ const S04: f64 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ +/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64). pub fn j0(mut x: f64) -> f64 { let z: f64; let r: f64; @@ -162,6 +163,7 @@ const V02: f64 = 7.60068627350353253702e-05; /* 0x3F13ECBB, 0xF578C6C1 */ const V03: f64 = 2.59150851840457805467e-07; /* 0x3E91642D, 0x7FF202FD */ const V04: f64 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ +/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64). pub fn y0(x: f64) -> f64 { let z: f64; let u: f64; diff --git a/library/compiler-builtins/libm/src/math/j0f.rs b/library/compiler-builtins/libm/src/math/j0f.rs index 91c03dbbcdd28..afb6ee9ba8bc2 100644 --- a/library/compiler-builtins/libm/src/math/j0f.rs +++ b/library/compiler-builtins/libm/src/math/j0f.rs @@ -62,6 +62,7 @@ const S02: f32 = 1.1692678527e-04; /* 0x38f53697 */ const S03: f32 = 5.1354652442e-07; /* 0x3509daa6 */ const S04: f32 = 1.1661400734e-09; /* 0x30a045e8 */ +/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). pub fn j0f(mut x: f32) -> f32 { let z: f32; let r: f32; @@ -107,6 +108,7 @@ const V02: f32 = 7.6006865129e-05; /* 0x389f65e0 */ const V03: f32 = 2.5915085189e-07; /* 0x348b216c */ const V04: f32 = 4.4111031494e-10; /* 0x2ff280c2 */ +/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). pub fn y0f(x: f32) -> f32 { let z: f32; let u: f32; diff --git a/library/compiler-builtins/libm/src/math/j1.rs b/library/compiler-builtins/libm/src/math/j1.rs index 02a65ca5a2916..cef17a63e3701 100644 --- a/library/compiler-builtins/libm/src/math/j1.rs +++ b/library/compiler-builtins/libm/src/math/j1.rs @@ -113,6 +113,7 @@ const S03: f64 = 1.17718464042623683263e-06; /* 0x3EB3BFF8, 0x333F8498 */ const S04: f64 = 5.04636257076217042715e-09; /* 0x3E35AC88, 0xC97DFF2C */ const S05: f64 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ +/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64). pub fn j1(x: f64) -> f64 { let mut z: f64; let r: f64; @@ -158,6 +159,7 @@ const V0: [f64; 5] = [ 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ ]; +/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64). pub fn y1(x: f64) -> f64 { let z: f64; let u: f64; diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs index c39f8ff7e9648..02a3efd2435fe 100644 --- a/library/compiler-builtins/libm/src/math/j1f.rs +++ b/library/compiler-builtins/libm/src/math/j1f.rs @@ -63,6 +63,7 @@ const S03: f32 = 1.1771846857e-06; /* 0x359dffc2 */ const S04: f32 = 5.0463624390e-09; /* 0x31ad6446 */ const S05: f32 = 1.2354227016e-11; /* 0x2d59567e */ +/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). pub fn j1f(x: f32) -> f32 { let mut z: f32; let r: f32; @@ -107,6 +108,7 @@ const V0: [f32; 5] = [ 1.6655924903e-11, /* 0x2d9281cf */ ]; +/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). pub fn y1f(x: f32) -> f32 { let z: f32; let u: f32; diff --git a/library/compiler-builtins/libm/src/math/jn.rs b/library/compiler-builtins/libm/src/math/jn.rs index 22ced20c15a4a..aff051f24061b 100644 --- a/library/compiler-builtins/libm/src/math/jn.rs +++ b/library/compiler-builtins/libm/src/math/jn.rs @@ -38,6 +38,7 @@ use super::{cos, fabs, get_high_word, get_low_word, j0, j1, log, sin, sqrt, y0, const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ +/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64). pub fn jn(n: i32, mut x: f64) -> f64 { let mut ix: u32; let lx: u32; @@ -247,6 +248,7 @@ pub fn jn(n: i32, mut x: f64) -> f64 { if sign { -b } else { b } } +/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64). pub fn yn(n: i32, x: f64) -> f64 { let mut ix: u32; let lx: u32; diff --git a/library/compiler-builtins/libm/src/math/jnf.rs b/library/compiler-builtins/libm/src/math/jnf.rs index 9cd0bb37de9dc..e5afda44896df 100644 --- a/library/compiler-builtins/libm/src/math/jnf.rs +++ b/library/compiler-builtins/libm/src/math/jnf.rs @@ -15,6 +15,7 @@ use super::{fabsf, j0f, j1f, logf, y0f, y1f}; +/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). pub fn jnf(n: i32, mut x: f32) -> f32 { let mut ix: u32; let mut nm1: i32; @@ -191,6 +192,7 @@ pub fn jnf(n: i32, mut x: f32) -> f32 { if sign { -b } else { b } } +/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). pub fn ynf(n: i32, x: f32) -> f32 { let mut ix: u32; let mut ib: u32; diff --git a/library/compiler-builtins/libm/src/math/log.rs b/library/compiler-builtins/libm/src/math/log.rs index 27a26da60a987..f2dc47ec5ccff 100644 --- a/library/compiler-builtins/libm/src/math/log.rs +++ b/library/compiler-builtins/libm/src/math/log.rs @@ -70,6 +70,7 @@ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +/// The natural logarithm of `x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log(mut x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 diff --git a/library/compiler-builtins/libm/src/math/log10.rs b/library/compiler-builtins/libm/src/math/log10.rs index 40dacf2c916bc..f9d118f129296 100644 --- a/library/compiler-builtins/libm/src/math/log10.rs +++ b/library/compiler-builtins/libm/src/math/log10.rs @@ -31,6 +31,7 @@ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +/// The base 10 logarithm of `x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log10(mut x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 diff --git a/library/compiler-builtins/libm/src/math/log10f.rs b/library/compiler-builtins/libm/src/math/log10f.rs index 108dfa8b508ea..18bf8fcc8320e 100644 --- a/library/compiler-builtins/libm/src/math/log10f.rs +++ b/library/compiler-builtins/libm/src/math/log10f.rs @@ -25,6 +25,7 @@ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ +/// The base 10 logarithm of `x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log10f(mut x: f32) -> f32 { let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 diff --git a/library/compiler-builtins/libm/src/math/log1p.rs b/library/compiler-builtins/libm/src/math/log1p.rs index 552de549bfc68..80561ec74159e 100644 --- a/library/compiler-builtins/libm/src/math/log1p.rs +++ b/library/compiler-builtins/libm/src/math/log1p.rs @@ -65,6 +65,7 @@ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +/// The natural logarithm of 1+`x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log1p(x: f64) -> f64 { let mut ui: u64 = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/log1pf.rs b/library/compiler-builtins/libm/src/math/log1pf.rs index 8068128db4f8d..bba5b8a2f211c 100644 --- a/library/compiler-builtins/libm/src/math/log1pf.rs +++ b/library/compiler-builtins/libm/src/math/log1pf.rs @@ -20,6 +20,7 @@ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ +/// The natural logarithm of 1+`x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log1pf(x: f32) -> f32 { let mut ui: u32 = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/log2.rs b/library/compiler-builtins/libm/src/math/log2.rs index 83da3a19366f7..59533340bd878 100644 --- a/library/compiler-builtins/libm/src/math/log2.rs +++ b/library/compiler-builtins/libm/src/math/log2.rs @@ -29,6 +29,7 @@ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ +/// The base 2 logarithm of `x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log2(mut x: f64) -> f64 { let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 diff --git a/library/compiler-builtins/libm/src/math/log2f.rs b/library/compiler-builtins/libm/src/math/log2f.rs index 3a20fb15bd699..5ba2427d1d468 100644 --- a/library/compiler-builtins/libm/src/math/log2f.rs +++ b/library/compiler-builtins/libm/src/math/log2f.rs @@ -23,6 +23,7 @@ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ +/// The base 2 logarithm of `x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn log2f(mut x: f32) -> f32 { let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 diff --git a/library/compiler-builtins/libm/src/math/logf.rs b/library/compiler-builtins/libm/src/math/logf.rs index 2b57b934fb9f6..68d1943025e35 100644 --- a/library/compiler-builtins/libm/src/math/logf.rs +++ b/library/compiler-builtins/libm/src/math/logf.rs @@ -21,6 +21,7 @@ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ +/// The natural logarithm of `x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn logf(mut x: f32) -> f32 { let x1p25 = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 9b617cadbfede..7ecad291d1823 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -89,6 +89,7 @@ const IVLN2: f64 = 1.44269504088896338700e+00; /* 0x3ff71547_652b82fe =1/ln2 */ const IVLN2_H: f64 = 1.44269502162933349609e+00; /* 0x3ff71547_60000000 =24b 1/ln2*/ const IVLN2_L: f64 = 1.92596299112661746887e-08; /* 0x3e54ae0b_f85ddf44 =1/ln2 tail*/ +/// Returns `x` to the power of `y` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn pow(x: f64, y: f64) -> f64 { let t1: f64; diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs index d47ab4b3d1d9d..2d9d1e4bbfdde 100644 --- a/library/compiler-builtins/libm/src/math/powf.rs +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -43,6 +43,7 @@ const IVLN2: f32 = 1.4426950216e+00; const IVLN2_H: f32 = 1.4426879883e+00; const IVLN2_L: f32 = 7.0526075433e-06; +/// Returns `x` to the power of `y` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn powf(x: f32, y: f32) -> f32 { let mut z: f32; diff --git a/library/compiler-builtins/libm/src/math/sin.rs b/library/compiler-builtins/libm/src/math/sin.rs index a53843dcdaeb9..e04e0d6a09dce 100644 --- a/library/compiler-builtins/libm/src/math/sin.rs +++ b/library/compiler-builtins/libm/src/math/sin.rs @@ -40,6 +40,10 @@ use super::{k_cos, k_sin, rem_pio2}; // // Accuracy: // TRIG(x) returns trig(x) nearly rounded + +/// The sine of `x` (f64). +/// +/// `x` is specified in radians. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sin(x: f64) -> f64 { let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 diff --git a/library/compiler-builtins/libm/src/math/sincos.rs b/library/compiler-builtins/libm/src/math/sincos.rs index ff5d87a1c60ff..ebf482f2df350 100644 --- a/library/compiler-builtins/libm/src/math/sincos.rs +++ b/library/compiler-builtins/libm/src/math/sincos.rs @@ -12,6 +12,9 @@ use super::{get_high_word, k_cos, k_sin, rem_pio2}; +/// Both the sine and cosine of `x` (f64). +/// +/// `x` is specified in radians and the return value is (sin(x), cos(x)). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sincos(x: f64) -> (f64, f64) { let s: f64; diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs index 9a4c36104e92c..82c40fb8c89c9 100644 --- a/library/compiler-builtins/libm/src/math/sincosf.rs +++ b/library/compiler-builtins/libm/src/math/sincosf.rs @@ -23,6 +23,9 @@ const S2PIO2: f32 = 2.0 * PI_2; /* 0x400921FB, 0x54442D18 */ const S3PIO2: f32 = 3.0 * PI_2; /* 0x4012D97C, 0x7F3321D2 */ const S4PIO2: f32 = 4.0 * PI_2; /* 0x401921FB, 0x54442D18 */ +/// Both the sine and cosine of `x` (f32). +/// +/// `x` is specified in radians and the return value is (sin(x), cos(x)). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sincosf(x: f32) -> (f32, f32) { let s: f32; diff --git a/library/compiler-builtins/libm/src/math/sinf.rs b/library/compiler-builtins/libm/src/math/sinf.rs index ca181462723ee..b8fae2c980170 100644 --- a/library/compiler-builtins/libm/src/math/sinf.rs +++ b/library/compiler-builtins/libm/src/math/sinf.rs @@ -24,6 +24,9 @@ const S2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ const S3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ const S4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ +/// The sine of `x` (f32). +/// +/// `x` is specified in radians. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sinf(x: f32) -> f32 { let x64 = x as f64; diff --git a/library/compiler-builtins/libm/src/math/sinh.rs b/library/compiler-builtins/libm/src/math/sinh.rs index fd24fd20cf72b..79184198263c6 100644 --- a/library/compiler-builtins/libm/src/math/sinh.rs +++ b/library/compiler-builtins/libm/src/math/sinh.rs @@ -4,6 +4,8 @@ use super::{expm1, expo2}; // = (exp(x)-1 + (exp(x)-1)/exp(x))/2 // = x + x^3/6 + o(x^5) // + +/// The hyperbolic sine of `x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sinh(x: f64) -> f64 { // union {double f; uint64_t i;} u = {.f = x}; diff --git a/library/compiler-builtins/libm/src/math/sinhf.rs b/library/compiler-builtins/libm/src/math/sinhf.rs index 6788642f0c90e..44d2e3560d579 100644 --- a/library/compiler-builtins/libm/src/math/sinhf.rs +++ b/library/compiler-builtins/libm/src/math/sinhf.rs @@ -1,5 +1,6 @@ use super::{expm1f, k_expo2f}; +/// The hyperbolic sine of `x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sinhf(x: f32) -> f32 { let mut h = 0.5f32; diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 5862b119b6410..e2907384dcdbe 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -78,6 +78,7 @@ use core::f64; +/// The square root of `x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrt(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index f7324c9413780..a738fc0b663a7 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -13,6 +13,7 @@ * ==================================================== */ +/// The square root of `x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrtf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized diff --git a/library/compiler-builtins/libm/src/math/tan.rs b/library/compiler-builtins/libm/src/math/tan.rs index 5aa44aeef72f6..a074ca5540acb 100644 --- a/library/compiler-builtins/libm/src/math/tan.rs +++ b/library/compiler-builtins/libm/src/math/tan.rs @@ -39,6 +39,10 @@ use super::{k_tan, rem_pio2}; // // Accuracy: // TRIG(x) returns trig(x) nearly rounded + +/// The tangent of `x` (f64). +/// +/// `x` is specified in radians. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tan(x: f64) -> f64 { let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 diff --git a/library/compiler-builtins/libm/src/math/tanf.rs b/library/compiler-builtins/libm/src/math/tanf.rs index f6b2399d0941f..7586aae4c7e58 100644 --- a/library/compiler-builtins/libm/src/math/tanf.rs +++ b/library/compiler-builtins/libm/src/math/tanf.rs @@ -24,6 +24,9 @@ const T2_PIO2: f64 = 2. * FRAC_PI_2; /* 0x400921FB, 0x54442D18 */ const T3_PIO2: f64 = 3. * FRAC_PI_2; /* 0x4012D97C, 0x7F3321D2 */ const T4_PIO2: f64 = 4. * FRAC_PI_2; /* 0x401921FB, 0x54442D18 */ +/// The tangent of `x` (f32). +/// +/// `x` is specified in radians. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tanf(x: f32) -> f32 { let x64 = x as f64; diff --git a/library/compiler-builtins/libm/src/math/tanh.rs b/library/compiler-builtins/libm/src/math/tanh.rs index cfea2c1670392..cc0abe4fcb2d4 100644 --- a/library/compiler-builtins/libm/src/math/tanh.rs +++ b/library/compiler-builtins/libm/src/math/tanh.rs @@ -4,6 +4,10 @@ use super::expm1; * = (exp(2*x) - 1)/(exp(2*x) - 1 + 2) * = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2) */ + +/// The hyperbolic tangent of `x` (f64). +/// +/// `x` is specified in radians. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tanh(mut x: f64) -> f64 { let mut uf: f64 = x; diff --git a/library/compiler-builtins/libm/src/math/tanhf.rs b/library/compiler-builtins/libm/src/math/tanhf.rs index ab13e1abf4c8d..fffbba6c6ec41 100644 --- a/library/compiler-builtins/libm/src/math/tanhf.rs +++ b/library/compiler-builtins/libm/src/math/tanhf.rs @@ -1,5 +1,8 @@ use super::expm1f; +/// The hyperbolic tangent of `x` (f32). +/// +/// `x` is specified in radians. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tanhf(mut x: f32) -> f32 { /* x = |x| */ From 750027cbbeece8bcd5852d621c150ef01179e9b8 Mon Sep 17 00:00:00 2001 From: quaternic <57393910+quaternic@users.noreply.github.com> Date: Mon, 28 Oct 2024 19:59:21 +0200 Subject: [PATCH 1381/4206] fix type of constants in ported sincosf (#331) * fix type of constants in ported sincosf --- .../libm/src/math/sincosf.rs | 50 ++++++++----------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs index 82c40fb8c89c9..423845e44c2ab 100644 --- a/library/compiler-builtins/libm/src/math/sincosf.rs +++ b/library/compiler-builtins/libm/src/math/sincosf.rs @@ -17,11 +17,11 @@ use super::{k_cosf, k_sinf, rem_pio2f}; /* Small multiples of pi/2 rounded to double precision. */ -const PI_2: f32 = 0.5 * 3.1415926535897931160E+00; -const S1PIO2: f32 = 1.0 * PI_2; /* 0x3FF921FB, 0x54442D18 */ -const S2PIO2: f32 = 2.0 * PI_2; /* 0x400921FB, 0x54442D18 */ -const S3PIO2: f32 = 3.0 * PI_2; /* 0x4012D97C, 0x7F3321D2 */ -const S4PIO2: f32 = 4.0 * PI_2; /* 0x401921FB, 0x54442D18 */ +const PI_2: f64 = 0.5 * 3.1415926535897931160E+00; +const S1PIO2: f64 = 1.0 * PI_2; /* 0x3FF921FB, 0x54442D18 */ +const S2PIO2: f64 = 2.0 * PI_2; /* 0x400921FB, 0x54442D18 */ +const S3PIO2: f64 = 3.0 * PI_2; /* 0x4012D97C, 0x7F3321D2 */ +const S4PIO2: f64 = 4.0 * PI_2; /* 0x401921FB, 0x54442D18 */ /// Both the sine and cosine of `x` (f32). /// @@ -59,21 +59,21 @@ pub fn sincosf(x: f32) -> (f32, f32) { if ix <= 0x4016cbe3 { /* |x| ~<= 3pi/4 */ if sign { - s = -k_cosf((x + S1PIO2) as f64); - c = k_sinf((x + S1PIO2) as f64); + s = -k_cosf(x as f64 + S1PIO2); + c = k_sinf(x as f64 + S1PIO2); } else { - s = k_cosf((S1PIO2 - x) as f64); - c = k_sinf((S1PIO2 - x) as f64); + s = k_cosf(S1PIO2 - x as f64); + c = k_sinf(S1PIO2 - x as f64); } } /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ else { if sign { - s = -k_sinf((x + S2PIO2) as f64); - c = -k_cosf((x + S2PIO2) as f64); + s = -k_sinf(x as f64 + S2PIO2); + c = -k_cosf(x as f64 + S2PIO2); } else { - s = -k_sinf((x - S2PIO2) as f64); - c = -k_cosf((x - S2PIO2) as f64); + s = -k_sinf(x as f64 - S2PIO2); + c = -k_cosf(x as f64 - S2PIO2); } } @@ -85,19 +85,19 @@ pub fn sincosf(x: f32) -> (f32, f32) { if ix <= 0x40afeddf { /* |x| ~<= 7*pi/4 */ if sign { - s = k_cosf((x + S3PIO2) as f64); - c = -k_sinf((x + S3PIO2) as f64); + s = k_cosf(x as f64 + S3PIO2); + c = -k_sinf(x as f64 + S3PIO2); } else { - s = -k_cosf((x - S3PIO2) as f64); - c = k_sinf((x - S3PIO2) as f64); + s = -k_cosf(x as f64 - S3PIO2); + c = k_sinf(x as f64 - S3PIO2); } } else { if sign { - s = k_sinf((x + S4PIO2) as f64); - c = k_cosf((x + S4PIO2) as f64); + s = k_sinf(x as f64 + S4PIO2); + c = k_cosf(x as f64 + S4PIO2); } else { - s = k_sinf((x - S4PIO2) as f64); - c = k_cosf((x - S4PIO2) as f64); + s = k_sinf(x as f64 - S4PIO2); + c = k_cosf(x as f64 - S4PIO2); } } @@ -131,14 +131,6 @@ pub fn sincosf(x: f32) -> (f32, f32) { #[cfg(test)] mod tests { use super::sincosf; - use crate::_eqf; - - #[test] - fn with_pi() { - let (s, c) = sincosf(core::f32::consts::PI); - _eqf(s.abs(), 0.0).unwrap(); - _eqf(c, -1.0).unwrap(); - } #[test] fn rotational_symmetry() { From 36b52c7d1b281b257c09179eae3e11bfdc17595a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Oct 2024 22:25:16 -0500 Subject: [PATCH 1382/4206] Introduce `musl-math-sys` for bindings to musl math symbols This crate builds math symbols from a musl checkout and provides a Rust interface. The intent is that we will be able to compare our implementations against musl on more than just linux (which are the only currently the only targets we run `*-musl` targets against for comparison). Musl libc can't compile on anything other than Linux; however, the routines in `src/math` are cross platform enough to build on MacOS and windows-gnu with only minor adjustments. We take advantage of this and build only needed files using `cc`. The build script also performs remapping (via defines) so that e.g. `cos` gets defined as `musl_cos`. This gives us more certainty that we are actually testing against the intended symbol; without it, it is easy to unknowingly link to system libraries or even Rust's `libm` itself and wind up with an ineffective test. There is also a small procedure to verify remapping worked correctly by checking symbols in object files. --- library/compiler-builtins/libm/.gitignore | 5 +- library/compiler-builtins/libm/Cargo.toml | 2 + .../libm/crates/musl-math-sys/Cargo.toml | 12 + .../libm/crates/musl-math-sys/build.rs | 328 ++++++++++++++++++ .../crates/musl-math-sys/c_patches/alias.c | 40 +++ .../crates/musl-math-sys/c_patches/features.h | 39 +++ .../libm/crates/musl-math-sys/src/lib.rs | 279 +++++++++++++++ 7 files changed, 703 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml create mode 100644 library/compiler-builtins/libm/crates/musl-math-sys/build.rs create mode 100644 library/compiler-builtins/libm/crates/musl-math-sys/c_patches/alias.c create mode 100644 library/compiler-builtins/libm/crates/musl-math-sys/c_patches/features.h create mode 100644 library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs diff --git a/library/compiler-builtins/libm/.gitignore b/library/compiler-builtins/libm/.gitignore index 39950911a6249..b6a53275151d5 100644 --- a/library/compiler-builtins/libm/.gitignore +++ b/library/compiler-builtins/libm/.gitignore @@ -1,8 +1,9 @@ -**/*.rs.bk +**.bk .#* /bin /math/src /math/target /target -/tests Cargo.lock +musl/ +**.tar.gz diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 9282b71576d6f..99bfdbfdc859e 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -24,10 +24,12 @@ unstable = [] force-soft-floats = [] [workspace] +resolver = "2" members = [ "crates/compiler-builtins-smoke-test", "crates/libm-bench", "crates/libm-test", + "crates/musl-math-sys", ] default-members = [ ".", diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml new file mode 100644 index 0000000000000..449ce4f3ed1fc --- /dev/null +++ b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "musl-math-sys" +version = "0.1.0" +edition = "2021" + +[dependencies] + +[dev-dependencies] +libm = { path = "../../" } + +[build-dependencies] +cc = "1.1.24" diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/build.rs b/library/compiler-builtins/libm/crates/musl-math-sys/build.rs new file mode 100644 index 0000000000000..03df06c7934df --- /dev/null +++ b/library/compiler-builtins/libm/crates/musl-math-sys/build.rs @@ -0,0 +1,328 @@ +use std::collections::BTreeMap; +use std::path::{Path, PathBuf}; +use std::process::{Command, Stdio}; +use std::{env, fs, str}; + +/// Static library that will be built +const LIB_NAME: &str = "musl_math_prefixed"; + +/// Files that have more than one symbol. Map of file names to the symbols defined in that file. +const MULTIPLE_SYMBOLS: &[(&str, &[&str])] = &[ + ("__invtrigl", &["__invtrigl", "__invtrigl_R", "__pio2_hi", "__pio2_lo"]), + ("__polevll", &["__polevll", "__p1evll"]), + ("erf", &["erf", "erfc"]), + ("erff", &["erff", "erfcf"]), + ("erfl", &["erfl", "erfcl"]), + ("exp10", &["exp10", "pow10"]), + ("exp10f", &["exp10f", "pow10f"]), + ("exp10l", &["exp10l", "pow10l"]), + ("exp2f_data", &["exp2f_data", "__exp2f_data"]), + ("exp_data", &["exp_data", "__exp_data"]), + ("j0", &["j0", "y0"]), + ("j0f", &["j0f", "y0f"]), + ("j1", &["j1", "y1"]), + ("j1f", &["j1f", "y1f"]), + ("jn", &["jn", "yn"]), + ("jnf", &["jnf", "ynf"]), + ("lgamma", &["lgamma", "__lgamma_r"]), + ("remainder", &["remainder", "drem"]), + ("remainderf", &["remainderf", "dremf"]), + ("lgammaf", &["lgammaf", "lgammaf_r", "__lgammaf_r"]), + ("lgammal", &["lgammal", "lgammal_r", "__lgammal_r"]), + ("log2_data", &["log2_data", "__log2_data"]), + ("log2f_data", &["log2f_data", "__log2f_data"]), + ("log_data", &["log_data", "__log_data"]), + ("logf_data", &["logf_data", "__logf_data"]), + ("pow_data", &["pow_data", "__pow_log_data"]), + ("powf_data", &["powf_data", "__powf_log2_data"]), + ("signgam", &["signgam", "__signgam"]), + ("sqrt_data", &["sqrt_data", "__rsqrt_tab"]), +]; + +fn main() { + let cfg = Config::from_env(); + + if cfg.target_env == "msvc" + || cfg.target_family == "wasm" + || cfg.target_features.iter().any(|f| f == "thumb-mode") + { + println!( + "cargo::warning=Musl doesn't compile with the current \ + target {}; skipping build", + &cfg.target_string + ); + return; + } + + build_musl_math(&cfg); +} + +#[allow(dead_code)] +#[derive(Debug)] +struct Config { + manifest_dir: PathBuf, + out_dir: PathBuf, + musl_dir: PathBuf, + musl_arch: String, + target_arch: String, + target_env: String, + target_family: String, + target_os: String, + target_string: String, + target_vendor: String, + target_features: Vec, +} + +impl Config { + fn from_env() -> Self { + let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); + let target_features = env::var("CARGO_CFG_TARGET_FEATURE") + .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) + .unwrap_or_default(); + + // Default to the `{workspace_root}/musl` if not specified + let musl_dir = env::var("MUSL_SOURCE_DIR") + .map(PathBuf::from) + .unwrap_or_else(|_| manifest_dir.parent().unwrap().parent().unwrap().join("musl")); + + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + let musl_arch = if target_arch == "x86" { "i386".to_owned() } else { target_arch.clone() }; + + println!("cargo::rerun-if-changed={}/c_patches", manifest_dir.display()); + println!("cargo::rerun-if-env-changed=MUSL_SOURCE_DIR"); + println!("cargo::rerun-if-changed={}", musl_dir.display()); + + Self { + manifest_dir, + out_dir: PathBuf::from(env::var("OUT_DIR").unwrap()), + musl_dir, + musl_arch, + target_arch, + target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), + target_family: env::var("CARGO_CFG_TARGET_FAMILY").unwrap(), + target_os: env::var("CARGO_CFG_TARGET_OS").unwrap(), + target_string: env::var("TARGET").unwrap(), + target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), + target_features, + } + } +} + +/// Build musl math symbols to a static library +fn build_musl_math(cfg: &Config) { + let musl_dir = &cfg.musl_dir; + assert!( + musl_dir.exists(), + "musl source is missing. it can be downloaded with ./ci/download-musl.sh" + ); + + let math = musl_dir.join("src/math"); + let arch_dir = musl_dir.join("arch").join(&cfg.musl_arch); + let source_map = find_math_source(&math, cfg); + let out_path = cfg.out_dir.join(format!("lib{LIB_NAME}.a")); + + // Run configuration steps. Usually done as part of the musl `Makefile`. + let obj_include = cfg.out_dir.join("musl_obj/include"); + fs::create_dir_all(&obj_include).unwrap(); + fs::create_dir_all(&obj_include.join("bits")).unwrap(); + let sed_stat = Command::new("sed") + .arg("-f") + .arg(musl_dir.join("tools/mkalltypes.sed")) + .arg(arch_dir.join("bits/alltypes.h.in")) + .arg(musl_dir.join("include/alltypes.h.in")) + .stderr(Stdio::inherit()) + .output() + .unwrap(); + assert!(sed_stat.status.success(), "sed command failed: {:?}", sed_stat.status); + + fs::write(obj_include.join("bits/alltypes.h"), sed_stat.stdout).unwrap(); + + let mut cbuild = cc::Build::new(); + cbuild + .extra_warnings(false) + .warnings(false) + .flag_if_supported("-Wno-bitwise-op-parentheses") + .flag_if_supported("-Wno-literal-range") + .flag_if_supported("-Wno-parentheses") + .flag_if_supported("-Wno-shift-count-overflow") + .flag_if_supported("-Wno-shift-op-parentheses") + .flag_if_supported("-Wno-unused-but-set-variable") + .flag_if_supported("-std=c99") + .flag_if_supported("-ffreestanding") + .flag_if_supported("-nostdinc") + .define("_ALL_SOURCE", "1") + .opt_level(3) + .define( + "ROOT_INCLUDE_FEATURES", + Some(musl_dir.join("include/features.h").to_str().unwrap()), + ) + // Our overrides are in this directory + .include(cfg.manifest_dir.join("c_patches")) + .include(musl_dir.join("arch").join(&cfg.musl_arch)) + .include(musl_dir.join("arch/generic")) + .include(musl_dir.join("src/include")) + .include(musl_dir.join("src/internal")) + .include(obj_include) + .include(musl_dir.join("include")) + .file(cfg.manifest_dir.join("c_patches/alias.c")); + + for (sym_name, src_file) in source_map { + // Build the source file + cbuild.file(src_file); + + // Trickery! Redefine the symbol names to have the prefix `musl_`, which allows us to + // differentiate these symbols from whatever we provide. + if let Some((_names, syms)) = + MULTIPLE_SYMBOLS.iter().find(|(name, _syms)| *name == sym_name) + { + // Handle the occasional file that defines multiple symbols + for sym in *syms { + cbuild.define(sym, Some(format!("musl_{sym}").as_str())); + } + } else { + // If the file doesn't define multiple symbols, the file name will be the symbol + cbuild.define(&sym_name, Some(format!("musl_{sym_name}").as_str())); + } + } + + if cfg!(windows) { + // On Windows we don't have a good way to check symbols, so skip that step. + cbuild.compile(LIB_NAME); + return; + } + + let objfiles = cbuild.compile_intermediates(); + + // We create the archive ourselves with relocations rather than letting `cc` do it so we can + // encourage it to resolve symbols now. This should help avoid accidentally linking the wrong + // thing. + let stat = cbuild + .get_compiler() + .to_command() + .arg("-r") + .arg("-o") + .arg(&out_path) + .args(objfiles) + .status() + .unwrap(); + assert!(stat.success()); + + println!("cargo::rustc-link-lib={LIB_NAME}"); + println!("cargo::rustc-link-search=native={}", cfg.out_dir.display()); + + validate_archive_symbols(&out_path); +} + +/// Build a map of `name -> path`. `name` is typically the symbol name, but this doesn't account +/// for files that provide multiple symbols. +fn find_math_source(math_root: &Path, cfg: &Config) -> BTreeMap { + let mut map = BTreeMap::new(); + let mut arch_dir = None; + + // Locate all files and directories + for item in fs::read_dir(math_root).unwrap() { + let path = item.unwrap().path(); + let meta = fs::metadata(&path).unwrap(); + + if meta.is_dir() { + // Make note of the arch-specific directory if it exists + if path.file_name().unwrap() == cfg.target_arch.as_str() { + arch_dir = Some(path); + } + continue; + } + + // Skip non-source files + if path.extension().is_some_and(|ext| ext == "h") { + continue; + } + + let sym_name = path.file_stem().unwrap(); + map.insert(sym_name.to_str().unwrap().to_owned(), path.to_owned()); + } + + // If arch-specific versions are available, build those instead. + if let Some(arch_dir) = arch_dir { + for item in fs::read_dir(arch_dir).unwrap() { + let path = item.unwrap().path(); + let sym_name = path.file_stem().unwrap(); + + if path.extension().unwrap() == "s" { + // FIXME: we never build assembly versions since we have no good way to + // rename the symbol (our options are probably preprocessor or objcopy). + continue; + } + map.insert(sym_name.to_str().unwrap().to_owned(), path); + } + } + + map +} + +/// Make sure we don't have something like a loose unprefixed `_cos` called somewhere, which could +/// wind up linking to system libraries rather than the built musl library. +fn validate_archive_symbols(out_path: &Path) { + const ALLOWED_UNDEF_PFX: &[&str] = &[ + // PIC and arch-specific + ".TOC", + "_GLOBAL_OFFSET_TABLE_", + "__x86.get_pc_thunk", + // gcc/compiler-rt/compiler-builtins symbols + "__add", + "__aeabi_", + "__div", + "__eq", + "__extend", + "__fix", + "__float", + "__gcc_", + "__ge", + "__gt", + "__le", + "__lshr", + "__lt", + "__mul", + "__ne", + "__stack_chk_fail", + "__stack_chk_guard", + "__sub", + "__trunc", + "__undef", + // string routines + "__bzero", + "bzero", + // FPENV interfaces + "feclearexcept", + "fegetround", + "feraiseexcept", + "fesetround", + "fetestexcept", + ]; + + // List global undefined symbols + let out = + Command::new("nm").arg("-guj").arg(out_path).stderr(Stdio::inherit()).output().unwrap(); + + let undef = str::from_utf8(&out.stdout).unwrap(); + let mut undef = undef.lines().collect::>(); + undef.retain(|sym| { + // Account for file formats that add a leading `_` + !ALLOWED_UNDEF_PFX.iter().any(|pfx| sym.starts_with(pfx) || sym[1..].starts_with(pfx)) + }); + + assert!(undef.is_empty(), "found disallowed undefined symbols: {undef:#?}"); + + // Find any symbols that are missing the `_musl_` prefix` + let out = + Command::new("nm").arg("-gUj").arg(out_path).stderr(Stdio::inherit()).output().unwrap(); + + let defined = str::from_utf8(&out.stdout).unwrap(); + let mut defined = defined.lines().collect::>(); + defined.retain(|sym| { + !(sym.starts_with("_musl_") + || sym.starts_with("musl_") + || sym.starts_with("__x86.get_pc_thunk")) + }); + + assert!(defined.is_empty(), "found unprefixed symbols: {defined:#?}"); +} diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/c_patches/alias.c b/library/compiler-builtins/libm/crates/musl-math-sys/c_patches/alias.c new file mode 100644 index 0000000000000..63e0f08d5eb69 --- /dev/null +++ b/library/compiler-builtins/libm/crates/musl-math-sys/c_patches/alias.c @@ -0,0 +1,40 @@ +/* On platforms that don't support weak symbols, define required aliases + * as wrappers. See comments in `features.h` for more. + */ +#if defined(__APPLE__) || defined(__MINGW32__) + +double __lgamma_r(double a, int *b); +float __lgammaf_r(float a, int *b); +long __lgammal_r(long double a, int *b); +double exp10(double a); +float exp10f(float a); +long exp10l(long double a); +double remainder(double a, double b); +float remainderf(float a, float b); + +double lgamma_r(double a, int *b) { + return __lgamma_r(a, b); +} +float lgammaf_r(float a, int *b) { + return __lgammaf_r(a, b); +} +long double lgammal_r(long double a, int *b) { + return __lgammal_r(a, b); +} +double pow10(double a) { + return exp10(a); +} +float pow10f(float a) { + return exp10f(a); +} +long double pow10l(long double a) { + return exp10l(a); +} +double drem(double a, double b) { + return remainder(a, b); +} +float dremf(float a, float b) { + return remainderf(a, b); +} + +#endif diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/c_patches/features.h b/library/compiler-builtins/libm/crates/musl-math-sys/c_patches/features.h new file mode 100644 index 0000000000000..97af935979a2e --- /dev/null +++ b/library/compiler-builtins/libm/crates/musl-math-sys/c_patches/features.h @@ -0,0 +1,39 @@ +/* This is meant to override Musl's src/include/features.h + * + * We use a separate file here to redefine some attributes that don't work on + * all platforms that we would like to build on. + */ + +#ifndef FEATURES_H +#define FEATURES_H + +/* Get the required `#include "../../include/features.h"` since we can't use + * the relative path. The C macros need double indirection to get a usable + * string. */ +#define _stringify_inner(s) #s +#define _stringify(s) _stringify_inner(s) +#include _stringify(ROOT_INCLUDE_FEATURES) + +#if defined(__APPLE__) +#define weak __attribute__((__weak__)) +#define hidden __attribute__((__visibility__("hidden"))) + +/* We _should_ be able to define this as: + * _Pragma(_stringify(weak musl_ ## new = musl_ ## old)) + * However, weak symbols aren't handled correctly [1]. So we manually write + * wrappers, which are in `alias.c`. + * + * [1]: https://github.com/llvm/llvm-project/issues/111321 + */ +#define weak_alias(old, new) /* nothing */ + +#else +#define weak __attribute__((__weak__)) +#define hidden __attribute__((__visibility__("hidden"))) +#define weak_alias(old, new) \ + extern __typeof(old) musl_ ## new \ + __attribute__((__weak__, __alias__(_stringify(musl_ ## old)))) + +#endif /* defined(__APPLE__) */ + +#endif diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs b/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs new file mode 100644 index 0000000000000..fe3c89229b6fe --- /dev/null +++ b/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs @@ -0,0 +1,279 @@ +//! Bindings to Musl math functions (these are built in `build.rs`). + +use std::ffi::{c_char, c_int, c_long}; + +/// Macro for creating bindings and exposing a safe function (since the implementations have no +/// preconditions). Included functions must have correct signatures, otherwise this will be +/// unsound. +macro_rules! functions { + ( $( + $pfx_name:ident: $name:ident( $($arg:ident: $aty:ty),+ ) -> $rty:ty; + )* ) => { + extern "C" { + $( fn $pfx_name( $($arg: $aty),+ ) -> $rty; )* + } + + $( + // Expose a safe version + pub fn $name( $($arg: $aty),+ ) -> $rty { + // SAFETY: FFI calls with no preconditions + unsafe { $pfx_name( $($arg),+ ) } + } + )* + + #[cfg(test)] + mod tests { + use super::*; + use test_support::CallTest; + + $( functions!( + @single_test + $name($($arg: $aty),+) -> $rty + ); )* + } + }; + + (@single_test + $name:ident( $($arg:ident: $aty:ty),+ ) -> $rty:ty + ) => { + // Run a simple check to ensure we can link and call the function without crashing. + #[test] + // FIXME(#309): LE PPC crashes calling some musl functions + #[cfg_attr(all(target_arch = "powerpc64", target_endian = "little"), ignore)] + fn $name() { + $rty>::check(super::$name); + } + }; +} + +#[cfg(test)] +mod test_support { + use core::ffi::c_char; + + /// Just verify that we are able to call the function. + pub trait CallTest { + fn check(f: Self); + } + + macro_rules! impl_calltest { + ($( ($($arg:ty),*) -> $ret:ty; )*) => { + $( + impl CallTest for fn($($arg),*) -> $ret { + fn check(f: Self) { + f($(1 as $arg),*); + } + } + )* + }; + } + + impl_calltest! { + (f32) -> f32; + (f64) -> f64; + (f32, f32) -> f32; + (f64, f64) -> f64; + (i32, f32) -> f32; + (i32, f64) -> f64; + (f32, f32, f32) -> f32; + (f64, f64, f64) -> f64; + (f32, i32) -> f32; + (f32, i64) -> f32; + (f32) -> i32; + (f64) -> i32; + (f64, i32) -> f64; + (f64, i64) -> f64; + } + + impl CallTest for fn(f32, &mut f32) -> f32 { + fn check(f: Self) { + let mut tmp = 0.0; + f(0.0, &mut tmp); + } + } + impl CallTest for fn(f64, &mut f64) -> f64 { + fn check(f: Self) { + let mut tmp = 0.0; + f(0.0, &mut tmp); + } + } + impl CallTest for fn(f32, &mut i32) -> f32 { + fn check(f: Self) { + let mut tmp = 1; + f(0.0, &mut tmp); + } + } + impl CallTest for fn(f64, &mut i32) -> f64 { + fn check(f: Self) { + let mut tmp = 1; + f(0.0, &mut tmp); + } + } + impl CallTest for fn(f32, f32, &mut i32) -> f32 { + fn check(f: Self) { + let mut tmp = 1; + f(0.0, 0.0, &mut tmp); + } + } + impl CallTest for fn(f64, f64, &mut i32) -> f64 { + fn check(f: Self) { + let mut tmp = 1; + f(0.0, 0.0, &mut tmp); + } + } + impl CallTest for fn(f32, &mut f32, &mut f32) { + fn check(f: Self) { + let mut tmp1 = 1.0; + let mut tmp2 = 1.0; + f(0.0, &mut tmp1, &mut tmp2); + } + } + impl CallTest for fn(f64, &mut f64, &mut f64) { + fn check(f: Self) { + let mut tmp1 = 1.0; + let mut tmp2 = 1.0; + f(0.0, &mut tmp1, &mut tmp2); + } + } + impl CallTest for fn(*const c_char) -> f32 { + fn check(f: Self) { + f(c"1".as_ptr()); + } + } + impl CallTest for fn(*const c_char) -> f64 { + fn check(f: Self) { + f(c"1".as_ptr()); + } + } +} + +functions! { + musl_acos: acos(a: f64) -> f64; + musl_acosf: acosf(a: f32) -> f32; + musl_acosh: acosh(a: f64) -> f64; + musl_acoshf: acoshf(a: f32) -> f32; + musl_asin: asin(a: f64) -> f64; + musl_asinf: asinf(a: f32) -> f32; + musl_asinh: asinh(a: f64) -> f64; + musl_asinhf: asinhf(a: f32) -> f32; + musl_atan2: atan2(a: f64, b: f64) -> f64; + musl_atan2f: atan2f(a: f32, b: f32) -> f32; + musl_atan: atan(a: f64) -> f64; + musl_atanf: atanf(a: f32) -> f32; + musl_atanh: atanh(a: f64) -> f64; + musl_atanhf: atanhf(a: f32) -> f32; + musl_cbrt: cbrt(a: f64) -> f64; + musl_cbrtf: cbrtf(a: f32) -> f32; + musl_ceil: ceil(a: f64) -> f64; + musl_ceilf: ceilf(a: f32) -> f32; + musl_copysign: copysign(a: f64, b: f64) -> f64; + musl_copysignf: copysignf(a: f32, b: f32) -> f32; + musl_cos: cos(a: f64) -> f64; + musl_cosf: cosf(a: f32) -> f32; + musl_cosh: cosh(a: f64) -> f64; + musl_coshf: coshf(a: f32) -> f32; + musl_drem: drem(a: f64, b: f64) -> f64; + musl_dremf: dremf(a: f32, b: f32) -> f32; + musl_erf: erf(a: f64) -> f64; + musl_erfc: erfc(a: f64) -> f64; + musl_erfcf: erfcf(a: f32) -> f32; + musl_erff: erff(a: f32) -> f32; + musl_exp10: exp10(a: f64) -> f64; + musl_exp10f: exp10f(a: f32) -> f32; + musl_exp2: exp2(a: f64) -> f64; + musl_exp2f: exp2f(a: f32) -> f32; + musl_exp: exp(a: f64) -> f64; + musl_expf: expf(a: f32) -> f32; + musl_expm1: expm1(a: f64) -> f64; + musl_expm1f: expm1f(a: f32) -> f32; + musl_fabs: fabs(a: f64) -> f64; + musl_fabsf: fabsf(a: f32) -> f32; + musl_fdim: fdim(a: f64, b: f64) -> f64; + musl_fdimf: fdimf(a: f32, b: f32) -> f32; + musl_finite: finite(a: f64) -> c_int; + musl_finitef: finitef(a: f32) -> c_int; + musl_floor: floor(a: f64) -> f64; + musl_floorf: floorf(a: f32) -> f32; + musl_fma: fma(a: f64, b: f64, c: f64) -> f64; + musl_fmaf: fmaf(a: f32, b: f32, c: f32) -> f32; + musl_fmax: fmax(a: f64, b: f64) -> f64; + musl_fmaxf: fmaxf(a: f32, b: f32) -> f32; + musl_fmin: fmin(a: f64, b: f64) -> f64; + musl_fminf: fminf(a: f32, b: f32) -> f32; + musl_fmod: fmod(a: f64, b: f64) -> f64; + musl_fmodf: fmodf(a: f32, b: f32) -> f32; + musl_frexp: frexp(a: f64, b: &mut c_int) -> f64; + musl_frexpf: frexpf(a: f32, b: &mut c_int) -> f32; + musl_hypot: hypot(a: f64, b: f64) -> f64; + musl_hypotf: hypotf(a: f32, b: f32) -> f32; + musl_ilogb: ilogb(a: f64) -> c_int; + musl_ilogbf: ilogbf(a: f32) -> c_int; + musl_j0: j0(a: f64) -> f64; + musl_j0f: j0f(a: f32) -> f32; + musl_j1: j1(a: f64) -> f64; + musl_j1f: j1f(a: f32) -> f32; + musl_jn: jn(a: c_int, b: f64) -> f64; + musl_jnf: jnf(a: c_int, b: f32) -> f32; + musl_ldexp: ldexp(a: f64, b: c_int) -> f64; + musl_ldexpf: ldexpf(a: f32, b: c_int) -> f32; + musl_lgamma: lgamma(a: f64) -> f64; + musl_lgamma_r: lgamma_r(a: f64, b: &mut c_int) -> f64; + musl_lgammaf: lgammaf(a: f32) -> f32; + musl_lgammaf_r: lgammaf_r(a: f32, b: &mut c_int) -> f32; + musl_log10: log10(a: f64) -> f64; + musl_log10f: log10f(a: f32) -> f32; + musl_log1p: log1p(a: f64) -> f64; + musl_log1pf: log1pf(a: f32) -> f32; + musl_log2: log2(a: f64) -> f64; + musl_log2f: log2f(a: f32) -> f32; + musl_log: log(a: f64) -> f64; + musl_logb: logb(a: f64) -> f64; + musl_logbf: logbf(a: f32) -> f32; + musl_logf: logf(a: f32) -> f32; + musl_modf: modf(a: f64, b: &mut f64) -> f64; + musl_modff: modff(a: f32, b: &mut f32) -> f32; + musl_nan: nan(a: *const c_char) -> f64; + musl_nanf: nanf(a: *const c_char) -> f32; + musl_nearbyint: nearbyint(a: f64) -> f64; + musl_nearbyintf: nearbyintf(a: f32) -> f32; + musl_nextafter: nextafter(a: f64, b: f64) -> f64; + musl_nextafterf: nextafterf(a: f32, b: f32) -> f32; + musl_pow10: pow10(a: f64) -> f64; + musl_pow10f: pow10f(a: f32) -> f32; + musl_pow: pow(a: f64, b: f64) -> f64; + musl_powf: powf(a: f32, b: f32) -> f32; + musl_remainder: remainder(a: f64, b: f64) -> f64; + musl_remainderf: remainderf(a: f32, b: f32) -> f32; + musl_remquo: remquo(a: f64, b: f64, c: &mut c_int) -> f64; + musl_remquof: remquof(a: f32, b: f32, c: &mut c_int) -> f32; + musl_rint: rint(a: f64) -> f64; + musl_rintf: rintf(a: f32) -> f32; + musl_round: round(a: f64) -> f64; + musl_roundf: roundf(a: f32) -> f32; + musl_scalbln: scalbln(a: f64, b: c_long) -> f64; + musl_scalblnf: scalblnf(a: f32, b: c_long) -> f32; + musl_scalbn: scalbn(a: f64, b: c_int) -> f64; + musl_scalbnf: scalbnf(a: f32, b: c_int) -> f32; + musl_significand: significand(a: f64) -> f64; + musl_significandf: significandf(a: f32) -> f32; + musl_sin: sin(a: f64) -> f64; + musl_sincos: sincos(a: f64, b: &mut f64, c: &mut f64) -> (); + musl_sincosf: sincosf(a: f32, b: &mut f32, c: &mut f32) -> (); + musl_sinf: sinf(a: f32) -> f32; + musl_sinh: sinh(a: f64) -> f64; + musl_sinhf: sinhf(a: f32) -> f32; + musl_sqrt: sqrt(a: f64) -> f64; + musl_sqrtf: sqrtf(a: f32) -> f32; + musl_tan: tan(a: f64) -> f64; + musl_tanf: tanf(a: f32) -> f32; + musl_tanh: tanh(a: f64) -> f64; + musl_tanhf: tanhf(a: f32) -> f32; + musl_tgamma: tgamma(a: f64) -> f64; + musl_tgammaf: tgammaf(a: f32) -> f32; + musl_trunc: trunc(a: f64) -> f64; + musl_truncf: truncf(a: f32) -> f32; + musl_y0: y0(a: f64) -> f64; + musl_y0f: y0f(a: f32) -> f32; + musl_y1: y1(a: f64) -> f64; + musl_y1f: y1f(a: f32) -> f32; + musl_ynf: ynf(a: c_int, b: f32) -> f32; +} From 5fc3068762a9b04899e894cd20eb4da509e30dfb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Oct 2024 22:36:05 -0500 Subject: [PATCH 1383/4206] Add a script for downloading musl --- .../libm/ci/download-musl.sh | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100755 library/compiler-builtins/libm/ci/download-musl.sh diff --git a/library/compiler-builtins/libm/ci/download-musl.sh b/library/compiler-builtins/libm/ci/download-musl.sh new file mode 100755 index 0000000000000..d0d8b310e876d --- /dev/null +++ b/library/compiler-builtins/libm/ci/download-musl.sh @@ -0,0 +1,24 @@ +#!/bin/sh +# Download the expected version of musl to a directory `musl` + +set -eux + +fname=musl-1.2.5.tar.gz +sha=a9a118bbe84d8764da0ea0d28b3ab3fae8477fc7e4085d90102b8596fc7c75e4 + +mkdir musl +curl "https://musl.libc.org/releases/$fname" -O + +case "$(uname -s)" in + MINGW*) + # Need to extract the second line because certutil does human output + fsha=$(certutil -hashfile "$fname" SHA256 | sed -n '2p') + [ "$sha" = "$fsha" ] || exit 1 + ;; + *) + echo "$sha $fname" | shasum -a 256 --check || exit 1 + ;; +esac + +tar -xzf "$fname" -C musl --strip-components 1 +rm "$fname" From 56deb13bd4d767193bf49b3ff137533706398bbf Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Oct 2024 22:37:44 -0500 Subject: [PATCH 1384/4206] Add a procedural macro for expanding all function signatures Introduce `libm_test::for_each_function`. which macro takes a callback macro and invokes it once per function signature. This provides an easier way of registering various tests and benchmarks without duplicating the function names and signatures each time. --- library/compiler-builtins/libm/Cargo.toml | 2 + .../libm/crates/libm-macros/Cargo.toml | 12 + .../libm/crates/libm-macros/src/lib.rs | 541 ++++++++++++++++++ .../libm/crates/libm-macros/src/parse.rs | 236 ++++++++ .../libm/crates/libm-macros/tests/basic.rs | 96 ++++ 5 files changed, 887 insertions(+) create mode 100644 library/compiler-builtins/libm/crates/libm-macros/Cargo.toml create mode 100644 library/compiler-builtins/libm/crates/libm-macros/src/lib.rs create mode 100644 library/compiler-builtins/libm/crates/libm-macros/src/parse.rs create mode 100644 library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 99bfdbfdc859e..72b6dcd5e8e19 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -28,11 +28,13 @@ resolver = "2" members = [ "crates/compiler-builtins-smoke-test", "crates/libm-bench", + "crates/libm-macros", "crates/libm-test", "crates/musl-math-sys", ] default-members = [ ".", + "crates/libm-macros", "crates/libm-test", ] diff --git a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml new file mode 100644 index 0000000000000..9d2b08e2d78f2 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "libm-macros" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0.88" +quote = "1.0.37" +syn = { version = "2.0.79", features = ["full", "extra-traits", "visit-mut"] } diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs new file mode 100644 index 0000000000000..dc78598ca7619 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs @@ -0,0 +1,541 @@ +mod parse; +use std::sync::LazyLock; + +use parse::{Invocation, StructuredInput}; +use proc_macro as pm; +use proc_macro2::{self as pm2, Span}; +use quote::{ToTokens, quote}; +use syn::Ident; +use syn::visit_mut::VisitMut; + +const ALL_FUNCTIONS: &[(Signature, Option, &[&str])] = &[ + ( + // `fn(f32) -> f32` + Signature { args: &[Ty::F32], returns: &[Ty::F32] }, + None, + &[ + "acosf", "acoshf", "asinf", "asinhf", "atanf", "atanhf", "cbrtf", "ceilf", "cosf", + "coshf", "erff", "exp10f", "exp2f", "expf", "expm1f", "fabsf", "floorf", "j0f", "j1f", + "lgammaf", "log10f", "log1pf", "log2f", "logf", "rintf", "roundf", "sinf", "sinhf", + "sqrtf", "tanf", "tanhf", "tgammaf", "truncf", + ], + ), + ( + // `(f64) -> f64` + Signature { args: &[Ty::F64], returns: &[Ty::F64] }, + None, + &[ + "acos", "acosh", "asin", "asinh", "atan", "atanh", "cbrt", "ceil", "cos", "cosh", + "erf", "exp10", "exp2", "exp", "expm1", "fabs", "floor", "j0", "j1", "lgamma", "log10", + "log1p", "log2", "log", "rint", "round", "sin", "sinh", "sqrt", "tan", "tanh", + "tgamma", "trunc", + ], + ), + ( + // `(f32, f32) -> f32` + Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32] }, + None, + &[ + "atan2f", + "copysignf", + "fdimf", + "fmaxf", + "fminf", + "fmodf", + "hypotf", + "nextafterf", + "powf", + "remainderf", + ], + ), + ( + // `(f64, f64) -> f64` + Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64] }, + None, + &[ + "atan2", + "copysign", + "fdim", + "fmax", + "fmin", + "fmod", + "hypot", + "nextafter", + "pow", + "remainder", + ], + ), + ( + // `(f32, f32, f32) -> f32` + Signature { args: &[Ty::F32, Ty::F32, Ty::F32], returns: &[Ty::F32] }, + None, + &["fmaf"], + ), + ( + // `(f64, f64, f64) -> f64` + Signature { args: &[Ty::F64, Ty::F64, Ty::F64], returns: &[Ty::F64] }, + None, + &["fma"], + ), + ( + // `(f32) -> i32` + Signature { args: &[Ty::F32], returns: &[Ty::I32] }, + None, + &["ilogbf"], + ), + ( + // `(f64) -> i32` + Signature { args: &[Ty::F64], returns: &[Ty::I32] }, + None, + &["ilogb"], + ), + ( + // `(i32, f32) -> f32` + Signature { args: &[Ty::I32, Ty::F32], returns: &[Ty::F32] }, + None, + &["jnf"], + ), + ( + // `(i32, f64) -> f64` + Signature { args: &[Ty::I32, Ty::F64], returns: &[Ty::F64] }, + None, + &["jn"], + ), + ( + // `(f32, i32) -> f32` + Signature { args: &[Ty::F32, Ty::I32], returns: &[Ty::F32] }, + None, + &["scalbnf", "ldexpf"], + ), + ( + // `(f64, i64) -> f64` + Signature { args: &[Ty::F64, Ty::I32], returns: &[Ty::F64] }, + None, + &["scalbn", "ldexp"], + ), + ( + // `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)` + Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] }, + Some(Signature { args: &[Ty::F32, Ty::MutF32], returns: &[Ty::F32] }), + &["modff"], + ), + ( + // `(f64, &mut f64) -> f64` as `(f64) -> (f64, f64)` + Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] }, + Some(Signature { args: &[Ty::F64, Ty::MutF64], returns: &[Ty::F64] }), + &["modf"], + ), + ( + // `(f32, &mut c_int) -> f32` as `(f32) -> (f32, i32)` + Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::I32] }, + Some(Signature { args: &[Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }), + &["frexpf", "lgammaf_r"], + ), + ( + // `(f64, &mut c_int) -> f64` as `(f64) -> (f64, i32)` + Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::I32] }, + Some(Signature { args: &[Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }), + &["frexp", "lgamma_r"], + ), + ( + // `(f32, f32, &mut c_int) -> f32` as `(f32, f32) -> (f32, i32)` + Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32, Ty::I32] }, + Some(Signature { args: &[Ty::F32, Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }), + &["remquof"], + ), + ( + // `(f64, f64, &mut c_int) -> f64` as `(f64, f64) -> (f64, i32)` + Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64, Ty::I32] }, + Some(Signature { args: &[Ty::F64, Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }), + &["remquo"], + ), + ( + // `(f32, &mut f32, &mut f32)` as `(f32) -> (f32, f32)` + Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] }, + Some(Signature { args: &[Ty::F32, Ty::MutF32, Ty::MutF32], returns: &[] }), + &["sincosf"], + ), + ( + // `(f64, &mut f64, &mut f64)` as `(f64) -> (f64, f64)` + Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] }, + Some(Signature { args: &[Ty::F64, Ty::MutF64, Ty::MutF64], returns: &[] }), + &["sincos"], + ), +]; + +/// A type used in a function signature. +#[allow(dead_code)] +#[derive(Debug, Clone, Copy)] +enum Ty { + F16, + F32, + F64, + F128, + I32, + CInt, + MutF16, + MutF32, + MutF64, + MutF128, + MutI32, + MutCInt, +} + +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::CInt => quote! { ::core::ffi::c_int }, + Ty::MutF16 => quote! { &mut f16 }, + Ty::MutF32 => quote! { &mut f32 }, + Ty::MutF64 => quote! { &mut f64 }, + Ty::MutF128 => quote! { &mut f128 }, + Ty::MutI32 => quote! { &mut i32 }, + Ty::MutCInt => quote! { &mut core::ffi::c_int }, + }; + + tokens.extend(ts); + } +} + +/// Representation of e.g. `(f32, f32) -> f32` +#[derive(Debug, Clone)] +struct Signature { + args: &'static [Ty], + returns: &'static [Ty], +} + +/// Combined information about a function implementation. +#[derive(Debug, Clone)] +struct FunctionInfo { + name: &'static str, + /// Function signature for C implementations + c_sig: Signature, + /// Function signature for Rust implementations + rust_sig: Signature, +} + +/// A flat representation of `ALL_FUNCTIONS`. +static ALL_FUNCTIONS_FLAT: LazyLock> = LazyLock::new(|| { + let mut ret = Vec::new(); + + for (rust_sig, c_sig, names) in ALL_FUNCTIONS { + for name in *names { + let api = FunctionInfo { + name, + rust_sig: rust_sig.clone(), + c_sig: c_sig.clone().unwrap_or_else(|| rust_sig.clone()), + }; + ret.push(api); + } + } + + ret.sort_by_key(|item| item.name); + ret +}); + +/// Do something for each function present in this crate. +/// +/// Takes a callback macro and invokes it multiple times, once for each function that +/// this crate exports. This makes it easy to create generic tests, benchmarks, or other checks +/// and apply it to each symbol. +/// +/// Additionally, the `extra` and `fn_extra` patterns can make use of magic identifiers: +/// +/// - `MACRO_FN_NAME`: gets replaced with the name of the function on that invocation. +/// - `MACRO_FN_NAME_NORMALIZED`: similar to the above, but removes sufixes so e.g. `sinf` becomes +/// `sin`, `cosf128` becomes `cos`, etc. +/// +/// Invoke as: +/// +/// ``` +/// // Macro that is invoked once per function +/// macro_rules! callback_macro { +/// ( +/// // Name of that function +/// fn_name: $fn_name:ident, +/// // 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)`) +/// CArgs: $CArgs:ty, +/// // The C version's return type (e.g. `f32`) +/// CRet: $CRet:ty, +/// // Function signature of the Rust version (e.g. `fn(f32) -> (f32, f32)`) +/// RustFn: $RustFn:ty, +/// // A tuple representing the Rust version's arguments (e.g. `(f32,)`) +/// RustArgs: $RustArgs:ty, +/// // The Rust version's return type (e.g. `(f32, f32)`) +/// RustRet: $RustRet:ty, +/// // Attributes for the current function, if any +/// attrs: [$($meta:meta)*] +/// // Extra tokens passed directly (if any) +/// extra: [$extra:ident], +/// // Extra function-tokens passed directly (if any) +/// fn_extra: $fn_extra:expr, +/// ) => { }; +/// } +/// +/// libm_macros::for_each_function! { +/// // The macro to invoke as a callback +/// callback: callback_macro, +/// // Functions to skip, i.e. `callback` shouldn't be called at all for these. +/// // +/// // This is an optional field. +/// skip: [sin, cos], +/// // Attributes passed as `attrs` for specific functions. For example, here the invocation +/// // with `sinf` and that with `cosf` will both get `meta1` and `meta2`, but no others will. +/// // +/// // This is an optional field. +/// attributes: [ +/// #[meta1] +/// #[meta2] +/// [sinf, cosf], +/// ], +/// // Any tokens that should be passed directly to all invocations of the callback. This can +/// // be used to pass local variables or other things the macro needs access to. +/// // +/// // This is an optional field. +/// extra: [foo], +/// // Similar to `extra`, but allow providing a pattern for only specific functions. Uses +/// // a simplified match-like syntax. +/// fn_extra: match MACRO_FN_NAME { +/// hypot | hypotf => |x| x.hypot(), +/// _ => |x| x, +/// }, +/// } +/// ``` +#[proc_macro] +pub fn for_each_function(tokens: pm::TokenStream) -> pm::TokenStream { + let input = syn::parse_macro_input!(tokens as Invocation); + + let res = StructuredInput::from_fields(input) + .and_then(|s_in| validate(&s_in).map(|fn_list| (s_in, fn_list))) + .and_then(|(s_in, fn_list)| expand(s_in, &fn_list)); + + match res { + Ok(ts) => ts.into(), + Err(e) => e.into_compile_error().into(), + } +} + +/// Check for any input that is structurally correct but has other problems. +/// +/// Returns the list of function names that we should expand for. +fn validate(input: &StructuredInput) -> syn::Result> { + // Collect lists of all functions that are provied as macro inputs in various fields (only, + // skip, attributes). + let attr_mentions = input + .attributes + .iter() + .flat_map(|map_list| map_list.iter()) + .flat_map(|attr_map| attr_map.names.iter()); + let only_mentions = input.only.iter().flat_map(|only_list| only_list.iter()); + let fn_extra_mentions = + input.fn_extra.iter().flat_map(|v| v.keys()).filter(|name| *name != "_"); + let all_mentioned_fns = + input.skip.iter().chain(only_mentions).chain(attr_mentions).chain(fn_extra_mentions); + + // Make sure that every function mentioned is a real function + for mentioned in all_mentioned_fns { + if !ALL_FUNCTIONS_FLAT.iter().any(|func| mentioned == func.name) { + let e = syn::Error::new( + mentioned.span(), + format!("unrecognized function name `{mentioned}`"), + ); + return Err(e); + } + } + + if !input.skip.is_empty() && input.only.is_some() { + let e = syn::Error::new( + input.only_span.unwrap(), + format!("only one of `skip` or `only` may be specified"), + ); + return Err(e); + } + + // Construct a list of what we intend to expand + let mut fn_list = Vec::new(); + for func in ALL_FUNCTIONS_FLAT.iter() { + let fn_name = func.name; + // If we have an `only` list and it does _not_ contain this function name, skip it + if input.only.as_ref().is_some_and(|only| !only.iter().any(|o| o == fn_name)) { + continue; + } + + // If there is a `skip` list that contains this function name, skip it + if input.skip.iter().any(|s| s == fn_name) { + continue; + } + + // Run everything else + fn_list.push(func); + } + + if let Some(map) = &input.fn_extra { + if !map.keys().any(|key| key == "_") { + // No default provided; make sure every expected function is covered + let mut fns_not_covered = Vec::new(); + for func in &fn_list { + if !map.keys().any(|key| key == func.name) { + // `name` was not mentioned in the `match` statement + fns_not_covered.push(func); + } + } + + if !fns_not_covered.is_empty() { + let e = syn::Error::new( + input.fn_extra_span.unwrap(), + format!( + "`fn_extra`: no default `_` pattern specified and the following \ + patterns are not covered: {fns_not_covered:#?}" + ), + ); + return Err(e); + } + } + }; + + Ok(fn_list) +} + +/// Expand our structured macro input into invocations of the callback macro. +fn expand(input: StructuredInput, fn_list: &[&FunctionInfo]) -> syn::Result { + let mut out = pm2::TokenStream::new(); + let default_ident = Ident::new("_", Span::call_site()); + let callback = input.callback; + + for func in fn_list { + let fn_name = Ident::new(func.name, Span::call_site()); + + // Prepare attributes in an `attrs: ...` field + let meta_field = match &input.attributes { + Some(attrs) => { + let meta = attrs + .iter() + .filter(|map| map.names.contains(&fn_name)) + .flat_map(|map| &map.meta); + quote! { attrs: [ #( #meta )* ] } + } + None => pm2::TokenStream::new(), + }; + + // Prepare extra in an `extra: ...` field, running the replacer + let extra_field = match input.extra.clone() { + Some(mut extra) => { + let mut v = MacroReplace::new(func.name); + v.visit_expr_mut(&mut extra); + v.finish()?; + + quote! { extra: #extra, } + } + None => pm2::TokenStream::new(), + }; + + // Prepare function-specific extra in a `fn_extra: ...` field, running the replacer + let fn_extra_field = match input.fn_extra { + Some(ref map) => { + let mut fn_extra = + map.get(&fn_name).or_else(|| map.get(&default_ident)).unwrap().clone(); + + let mut v = MacroReplace::new(func.name); + v.visit_expr_mut(&mut fn_extra); + v.finish()?; + + quote! { fn_extra: #fn_extra, } + } + None => 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 new = quote! { + #callback! { + fn_name: #fn_name, + CFn: fn( #(#c_args),* ,) -> ( #(#c_ret),* ), + CArgs: ( #(#c_args),* ,), + CRet: ( #(#c_ret),* ), + RustFn: fn( #(#rust_args),* ,) -> ( #(#rust_ret),* ), + RustArgs: ( #(#rust_args),* ,), + RustRet: ( #(#rust_ret),* ), + #meta_field + #extra_field + #fn_extra_field + } + }; + + out.extend(new); + } + + Ok(out) +} + +/// Visitor to replace "magic" identifiers that we allow: `MACRO_FN_NAME` and +/// `MACRO_FN_NAME_NORMALIZED`. +struct MacroReplace { + fn_name: &'static str, + /// Remove the trailing `f` or `f128` to make + norm_name: String, + error: Option, +} + +impl MacroReplace { + fn new(name: &'static str) -> Self { + // Keep this in sync with `libm_test::canonical_name` + let known_mappings = &[ + ("erff", "erf"), + ("erf", "erf"), + ("lgammaf_r", "lgamma_r"), + ("modff", "modf"), + ("modf", "modf"), + ]; + + let norm_name = 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("f128")) + .unwrap_or(name), + }; + + Self { fn_name: name, norm_name: norm_name.to_owned(), error: None } + } + + fn finish(self) -> syn::Result<()> { + match self.error { + Some(e) => Err(e), + None => Ok(()), + } + } + + fn visit_ident_inner(&mut self, i: &mut Ident) { + let s = i.to_string(); + if !s.starts_with("MACRO") || self.error.is_some() { + return; + } + + match s.as_str() { + "MACRO_FN_NAME" => *i = Ident::new(self.fn_name, i.span()), + "MACRO_FN_NAME_NORMALIZED" => *i = Ident::new(&self.norm_name, i.span()), + _ => { + self.error = + Some(syn::Error::new(i.span(), format!("unrecognized meta expression `{s}`"))); + } + } + } +} + +impl VisitMut for MacroReplace { + fn visit_ident_mut(&mut self, i: &mut Ident) { + self.visit_ident_inner(i); + syn::visit_mut::visit_ident_mut(self, i); + } +} diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/parse.rs b/library/compiler-builtins/libm/crates/libm-macros/src/parse.rs new file mode 100644 index 0000000000000..ee9bd524bbefb --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-macros/src/parse.rs @@ -0,0 +1,236 @@ +use std::collections::BTreeMap; + +use proc_macro2::Span; +use quote::ToTokens; +use syn::parse::{Parse, ParseStream, Parser}; +use syn::punctuated::Punctuated; +use syn::spanned::Spanned; +use syn::token::Comma; +use syn::{Arm, Attribute, Expr, ExprMatch, Ident, Meta, Token, bracketed}; + +/// The input to our macro; just a list of `field: value` items. +#[derive(Debug)] +pub struct Invocation { + fields: Punctuated, +} + +impl Parse for Invocation { + fn parse(input: ParseStream) -> syn::Result { + Ok(Self { fields: input.parse_terminated(Mapping::parse, Token![,])? }) + } +} + +/// A `key: expression` mapping with nothing else. Basically a simplified `syn::Field`. +#[derive(Debug)] +struct Mapping { + name: Ident, + _sep: Token![:], + expr: Expr, +} + +impl Parse for Mapping { + fn parse(input: ParseStream) -> syn::Result { + Ok(Self { name: input.parse()?, _sep: input.parse()?, expr: input.parse()? }) + } +} + +/// The input provided to our proc macro, after parsing into the form we expect. +#[derive(Debug)] +pub struct StructuredInput { + /// Macro to invoke once per function + pub callback: Ident, + /// Skip these functions + pub skip: Vec, + /// Invoke only for these functions + pub only: Option>, + /// Attributes that get applied to specific functions + pub attributes: Option>, + /// Extra expressions to pass to all invocations of the macro + pub extra: Option, + /// Per-function extra expressions to pass to the macro + pub fn_extra: Option>, + // For diagnostics + pub only_span: Option, + pub fn_extra_span: Option, +} + +impl StructuredInput { + pub fn from_fields(input: Invocation) -> syn::Result { + let mut map: Vec<_> = input.fields.into_iter().collect(); + let cb_expr = expect_field(&mut map, "callback")?; + let skip_expr = expect_field(&mut map, "skip").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(); + let fn_extra = expect_field(&mut map, "fn_extra").ok(); + + if !map.is_empty() { + Err(syn::Error::new( + map.first().unwrap().name.span(), + format!("unexpected fields {map:?}"), + ))?; + } + + let skip = match skip_expr { + Some(expr) => Parser::parse2(parse_ident_array, expr.into_token_stream())?, + None => Vec::new(), + }; + + 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())?), + None => None, + }; + + let attributes = match attr_expr { + Some(expr) => { + let mut attributes = Vec::new(); + let attr_exprs = Parser::parse2(parse_expr_array, expr.into_token_stream())?; + + for attr in attr_exprs { + attributes.push(syn::parse2(attr.into_token_stream())?); + } + Some(attributes) + } + None => None, + }; + + let fn_extra_span = fn_extra.as_ref().map(|expr| expr.span()); + let fn_extra = match fn_extra { + Some(expr) => Some(extract_fn_extra_field(expr)?), + None => None, + }; + + Ok(Self { + callback: expect_ident(cb_expr)?, + skip, + only, + only_span, + attributes, + extra, + fn_extra, + fn_extra_span, + }) + } +} + +fn extract_fn_extra_field(expr: Expr) -> syn::Result> { + let Expr::Match(mexpr) = expr else { + let e = syn::Error::new(expr.span(), "`fn_extra` expects a match expression"); + return Err(e); + }; + + let ExprMatch { attrs, match_token: _, expr, brace_token: _, arms } = mexpr; + + expect_empty_attrs(&attrs)?; + + let match_on = expect_ident(*expr)?; + if match_on != "MACRO_FN_NAME" { + let e = syn::Error::new(match_on.span(), "only allowed to match on `MACRO_FN_NAME`"); + return Err(e); + } + + let mut res = BTreeMap::new(); + + for arm in arms { + let Arm { attrs, pat, guard, fat_arrow_token: _, body, comma: _ } = arm; + + expect_empty_attrs(&attrs)?; + + let keys = match pat { + syn::Pat::Wild(w) => vec![Ident::new("_", w.span())], + _ => Parser::parse2(parse_ident_pat, pat.into_token_stream())?, + }; + + if let Some(guard) = guard { + let e = syn::Error::new(guard.0.span(), "no guards allowed in this position"); + return Err(e); + } + + for key in keys { + let inserted = res.insert(key.clone(), *body.clone()); + if inserted.is_some() { + let e = syn::Error::new(key.span(), format!("key `{key}` specified twice")); + return Err(e); + } + } + } + + Ok(res) +} + +fn expect_empty_attrs(attrs: &[Attribute]) -> syn::Result<()> { + if attrs.is_empty() { + return Ok(()); + } + + let e = + syn::Error::new(attrs.first().unwrap().span(), "no attributes allowed in this position"); + Err(e) +} + +/// Extract a named field from a map, raising an error if it doesn't exist. +fn expect_field(v: &mut Vec, name: &str) -> syn::Result { + let pos = v.iter().position(|v| v.name == name).ok_or_else(|| { + syn::Error::new(Span::call_site(), format!("missing expected field `{name}`")) + })?; + + Ok(v.remove(pos).expr) +} + +/// Coerce an expression into a simple identifier. +fn expect_ident(expr: Expr) -> syn::Result { + syn::parse2(expr.into_token_stream()) +} + +/// Parse an array of expressions. +fn parse_expr_array(input: ParseStream) -> syn::Result> { + let content; + let _ = bracketed!(content in input); + let fields = content.parse_terminated(Expr::parse, Token![,])?; + Ok(fields.into_iter().collect()) +} + +/// Parse an array of idents, e.g. `[foo, bar, baz]`. +fn parse_ident_array(input: ParseStream) -> syn::Result> { + let content; + let _ = bracketed!(content in input); + let fields = content.parse_terminated(Ident::parse, Token![,])?; + Ok(fields.into_iter().collect()) +} + +/// Parse an pattern of idents, specifically `(foo | bar | baz)`. +fn parse_ident_pat(input: ParseStream) -> syn::Result> { + if !input.peek2(Token![|]) { + return Ok(vec![input.parse()?]); + } + + let fields = Punctuated::::parse_separated_nonempty(input)?; + Ok(fields.into_iter().collect()) +} + +/// A mapping of attributes to identifiers (just a simplified `Expr`). +/// +/// Expressed as: +/// +/// ```ignore +/// #[meta1] +/// #[meta2] +/// [foo, bar, baz] +/// ``` +#[derive(Debug)] +pub struct AttributeMap { + pub meta: Vec, + pub names: Vec, +} + +impl Parse for AttributeMap { + fn parse(input: ParseStream) -> syn::Result { + let attrs = input.call(Attribute::parse_outer)?; + + Ok(Self { + meta: attrs.into_iter().map(|a| a.meta).collect(), + names: parse_ident_array(input)?, + }) + } +} diff --git a/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs b/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs new file mode 100644 index 0000000000000..8f8c09f1b64a8 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs @@ -0,0 +1,96 @@ +// `STATUS_DLL_NOT_FOUND` on i686 MinGW, not worth looking into. +#![cfg(not(all(target_arch = "x86", target_os = "windows", target_env = "gnu")))] + +macro_rules! basic { + ( + fn_name: $fn_name:ident, + CFn: $CFn:ty, + CArgs: $CArgs:ty, + CRet: $CRet:ty, + RustFn: $RustFn:ty, + RustArgs: $RustArgs:ty, + RustRet: $RustRet:ty, + attrs: [$($meta:meta)*] + extra: [$($extra_tt:tt)*], + fn_extra: $fn_extra:expr, + ) => { + $(#[$meta])* + mod $fn_name { + #[allow(unused)] + type CFnTy = $CFn; + // type CArgsTy<'_> = $CArgs; + // type CRetTy<'_> = $CRet; + #[allow(unused)] + type RustFnTy = $RustFn; + #[allow(unused)] + type RustArgsTy = $RustArgs; + #[allow(unused)] + type RustRetTy = $RustRet; + #[allow(unused)] + const A: &[&str] = &[$($extra_tt)*]; + #[allow(unused)] + fn foo(a: f32) -> f32 { + $fn_extra(a) + } + } + }; +} + +mod test_basic { + libm_macros::for_each_function! { + callback: basic, + skip: [sin, cos], + attributes: [ + // just some random attributes + #[allow(clippy::pedantic)] + #[allow(dead_code)] + [sinf, cosf] + ], + extra: ["foo", "bar"], + fn_extra: match MACRO_FN_NAME { + sin => |x| x + 2.0, + cos | cosf => |x: f32| x.MACRO_FN_NAME_NORMALIZED(), + _ => |_x| 100.0 + } + } +} + +macro_rules! basic_no_extra { + ( + fn_name: $fn_name:ident, + CFn: $CFn:ty, + CArgs: $CArgs:ty, + CRet: $CRet:ty, + RustFn: $RustFn:ty, + RustArgs: $RustArgs:ty, + RustRet: $RustRet:ty, + ) => { + mod $fn_name { + #[allow(unused)] + type CFnTy = $CFn; + // type CArgsTy<'_> = $CArgs; + // type CRetTy<'_> = $CRet; + #[allow(unused)] + type RustFnTy = $RustFn; + #[allow(unused)] + type RustArgsTy = $RustArgs; + #[allow(unused)] + type RustRetTy = $RustRet; + } + }; +} + +mod test_basic_no_extra { + // Test with no extra, no skip, and no attributes + libm_macros::for_each_function! { + callback: basic_no_extra, + } +} + +mod test_only { + // Test that only works + libm_macros::for_each_function! { + callback: basic_no_extra, + only: [sin, sinf], + } +} From 0acb3e2b50781a59c5932b4af71fe7a8b20d0e1a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Oct 2024 22:41:07 -0500 Subject: [PATCH 1385/4206] Collect all function names to an array Use a build script for `libm-test` to enumerate all symbols provided by `libm` and provide this list in a variable. This will allow us to make sure no functions are missed anytime they must be manually listed. Additionally, introduce some helper config options. --- .../libm/crates/libm-test/build.rs | 100 +++++++++++++++++- .../libm/crates/libm-test/src/lib.rs | 3 +- 2 files changed, 100 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs index 9653bd8301359..472dec9d33e10 100644 --- a/library/compiler-builtins/libm/crates/libm-test/build.rs +++ b/library/compiler-builtins/libm/crates/libm-test/build.rs @@ -1,10 +1,106 @@ +use std::fmt::Write; +use std::path::PathBuf; +use std::{env, fs}; + fn main() { + let cfg = Config::from_env(); + + emit_optimization_cfg(&cfg); + emit_cfg_shorthands(&cfg); + list_all_tests(&cfg); + #[cfg(feature = "test-musl-serialized")] - musl_reference_tests::generate(); + musl_serialized_tests::generate(); +} + +#[allow(dead_code)] +struct Config { + manifest_dir: PathBuf, + out_dir: PathBuf, + opt_level: u8, + target_arch: String, + target_env: String, + target_family: Option, + target_os: String, + target_string: String, + target_vendor: String, + target_features: Vec, +} + +impl Config { + fn from_env() -> Self { + let target_features = env::var("CARGO_CFG_TARGET_FEATURE") + .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) + .unwrap_or_default(); + + Self { + 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().parse().unwrap(), + target_arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), + target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), + target_family: env::var("CARGO_CFG_TARGET_FAMILY").ok(), + target_os: env::var("CARGO_CFG_TARGET_OS").unwrap(), + target_string: env::var("TARGET").unwrap(), + target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), + target_features, + } + } +} + +/// 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 cfg.opt_level >= 2 { + println!("cargo::rustc-cfg=optimizations_enabled"); + } +} + +/// 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") { + // Shorthand to detect i586 targets + println!("cargo::rustc-cfg=x86_no_sse"); + } +} + +/// Create a list of all source files in an array. This can be used for making sure that +/// all functions are tested or otherwise covered in some way. +// FIXME: it would probably be better to use rustdoc JSON output to get public functions. +fn list_all_tests(cfg: &Config) { + let math_src = cfg.manifest_dir.join("../../src/math"); + + let mut files = fs::read_dir(math_src) + .unwrap() + .map(|f| f.unwrap().path()) + .filter(|entry| entry.is_file()) + .map(|f| f.file_stem().unwrap().to_str().unwrap().to_owned()) + .collect::>(); + files.sort(); + + let mut s = "pub const ALL_FUNCTIONS: &[&str] = &[".to_owned(); + for f in files { + if f == "mod" { + // skip mod.rs + continue; + } + write!(s, "\"{f}\",").unwrap(); + } + write!(s, "];").unwrap(); + + let outfile = cfg.out_dir.join("all_files.rs"); + fs::write(outfile, s).unwrap(); } +/// At build time, generate the output of what the corresponding `*musl` target does with a range +/// of inputs. +/// +/// Serialize that target's output, run the same thing with our symbols, then load and compare +/// the resulting values. #[cfg(feature = "test-musl-serialized")] -mod musl_reference_tests { +mod musl_serialized_tests { use std::path::PathBuf; use std::process::Command; use std::{env, fs}; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 8b137891791fe..32c0618964fe0 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -1 +1,2 @@ - +// List of all files present in libm's source +include!(concat!(env!("OUT_DIR"), "/all_files.rs")); From 05c9691f15b09b8adff1b775275fe43902091124 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Oct 2024 22:44:31 -0500 Subject: [PATCH 1386/4206] Add a test that `for_each_fn` correctly lists all functions Create a new test that checks `for_each_fn` against `ALL_FUNCTIONS`, i.e. the manually entered function list against the automatically collected list. If any are missing (e.g. new symbol added), then this will produce an error. --- .../libm/crates/libm-test/Cargo.toml | 1 + .../crates/libm-test/tests/check_coverage.rs | 60 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 6367bdca52c04..1e76fb70707e0 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -13,6 +13,7 @@ test-musl-serialized = ["rand"] [dependencies] libm = { path = "../.." } +libm-macros = { path = "../libm-macros" } [build-dependencies] rand = { version = "0.8.5", optional = true } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs b/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs new file mode 100644 index 0000000000000..ef6d21fdbbad5 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs @@ -0,0 +1,60 @@ +//! Ensure that `for_each_function!` isn't missing any symbols. + +/// Files in `src/` that do not export a testable symbol. +const ALLOWED_SKIPS: &[&str] = &[ + // Not a generic test function + "fenv", + // Nonpublic functions + "expo2", + "k_cos", + "k_cosf", + "k_expo2", + "k_expo2f", + "k_sin", + "k_sinf", + "k_tan", + "k_tanf", + "rem_pio2", + "rem_pio2_large", + "rem_pio2f", +]; + +macro_rules! callback { + ( + fn_name: $name:ident, + CFn: $_CFn:ty, + CArgs: $_CArgs:ty, + CRet: $_CRet:ty, + RustFn: $_RustFn:ty, + RustArgs: $_RustArgs:ty, + RustRet: $_RustRet:ty, + extra: [$push_to:ident], + ) => { + $push_to.push(stringify!($name)); + }; +} + +#[test] +fn test_for_each_function_all_included() { + let mut included = Vec::new(); + let mut missing = Vec::new(); + + libm_macros::for_each_function! { + callback: callback, + extra: [included], + }; + + for f in libm_test::ALL_FUNCTIONS { + if !included.contains(f) && !ALLOWED_SKIPS.contains(f) { + missing.push(f) + } + } + + if !missing.is_empty() { + panic!( + "missing tests for the following: {missing:#?} \ + \nmake sure any new functions are entered in \ + `ALL_FUNCTIONS` (in `libm-macros`)." + ); + } +} From 8be6ef1e0a29864131de6046dc44230b1a2e7eeb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Oct 2024 22:47:55 -0500 Subject: [PATCH 1387/4206] Add numeric traits These traits are simplified versions of what we have in `compiler_builtins` and will be used for tests. --- .../libm/crates/libm-test/src/lib.rs | 4 + .../libm/crates/libm-test/src/num_traits.rs | 181 ++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 32c0618964fe0..5444709d87cf7 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -1,2 +1,6 @@ +mod num_traits; + +pub use num_traits::{Float, Hex, Int}; + // List of all files present in libm's source include!(concat!(env!("OUT_DIR"), "/all_files.rs")); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs new file mode 100644 index 0000000000000..835d6e46d437f --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs @@ -0,0 +1,181 @@ +use std::fmt; + +/// Common types and methods for floating point numbers. +pub trait Float: Copy + fmt::Display + fmt::Debug + PartialEq { + type Int: Int; + type SignedInt: Int + Int; + + const ZERO: Self; + const ONE: Self; + + /// The bitwidth of the float type + const BITS: u32; + + /// The bitwidth of the significand + const SIGNIFICAND_BITS: u32; + + /// The bitwidth of the exponent + const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1; + + fn is_nan(self) -> bool; + fn is_infinite(self) -> bool; + fn to_bits(self) -> Self::Int; + fn from_bits(bits: Self::Int) -> Self; + fn signum(self) -> Self; +} + +macro_rules! impl_float { + ($($fty:ty, $ui:ty, $si:ty, $significand_bits:expr;)+) => { + $( + impl Float for $fty { + type Int = $ui; + type SignedInt = $si; + + const ZERO: Self = 0.0; + const ONE: Self = 1.0; + + const BITS: u32 = <$ui>::BITS; + const SIGNIFICAND_BITS: u32 = $significand_bits; + + fn is_nan(self) -> bool { + self.is_nan() + } + fn is_infinite(self) -> bool { + self.is_infinite() + } + fn to_bits(self) -> Self::Int { + self.to_bits() + } + fn from_bits(bits: Self::Int) -> Self { + Self::from_bits(bits) + } + fn signum(self) -> Self { + self.signum() + } + } + + impl Hex for $fty { + fn hex(self) -> String { + self.to_bits().hex() + } + } + )+ + } +} + +impl_float!( + f32, u32, i32, 23; + f64, u64, i64, 52; +); + +/// Common types and methods for integers. +pub trait Int: Copy + fmt::Display + fmt::Debug + PartialEq { + type OtherSign: Int; + type Unsigned: Int; + const BITS: u32; + const SIGNED: bool; + + fn signed(self) -> ::OtherSign; + fn unsigned(self) -> Self::Unsigned; + fn checked_sub(self, other: Self) -> Option; + fn abs(self) -> Self; +} + +macro_rules! impl_int { + ($($ui:ty, $si:ty ;)+) => { + $( + impl Int for $ui { + type OtherSign = $si; + type Unsigned = Self; + const BITS: u32 = <$ui>::BITS; + const SIGNED: bool = false; + fn signed(self) -> Self::OtherSign { + self as $si + } + fn unsigned(self) -> Self { + self + } + fn checked_sub(self, other: Self) -> Option { + self.checked_sub(other) + } + fn abs(self) -> Self { + unimplemented!() + } + } + + impl Int for $si { + type OtherSign = $ui; + type Unsigned = $ui; + const BITS: u32 = <$ui>::BITS; + const SIGNED: bool = true; + fn signed(self) -> Self { + self + } + fn unsigned(self) -> $ui { + self as $ui + } + fn checked_sub(self, other: Self) -> Option { + self.checked_sub(other) + } + fn abs(self) -> Self { + self.abs() + } + } + + impl_int!(@for_both $si); + impl_int!(@for_both $ui); + + )+ + }; + + (@for_both $ty:ty) => { + impl Hex for $ty { + fn hex(self) -> String { + format!("{self:#0width$x}", width = ((Self::BITS / 4) + 2) as usize) + } + } + } +} + +impl_int!( + u32, i32; + u64, i64; +); + +/// 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 { + fn hex(self) -> String; +} + +impl Hex for (T1,) +where + T1: Hex, +{ + fn hex(self) -> String { + format!("({},)", self.0.hex()) + } +} + +impl Hex for (T1, T2) +where + T1: Hex, + T2: Hex, +{ + fn hex(self) -> String { + format!("({}, {})", self.0.hex(), self.1.hex()) + } +} + +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()) + } +} From d45f6f6fad392b7d84ce788c2236bc3b282f2241 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Oct 2024 22:55:05 -0500 Subject: [PATCH 1388/4206] Add traits for testing These traits give us a more generic way to interface with tuples used for (1) test input, (2) function arguments, and (3) test input. --- .../libm/crates/libm-test/Cargo.toml | 1 + .../libm/crates/libm-test/src/lib.rs | 6 + .../libm/crates/libm-test/src/num_traits.rs | 25 ++ .../libm/crates/libm-test/src/test_traits.rs | 217 ++++++++++++++++++ 4 files changed, 249 insertions(+) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 1e76fb70707e0..b6e2ced5877d3 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -12,6 +12,7 @@ default = [] test-musl-serialized = ["rand"] [dependencies] +anyhow = "1.0.90" libm = { path = "../.." } libm-macros = { path = "../libm-macros" } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 5444709d87cf7..41873099f637a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -1,6 +1,12 @@ mod num_traits; +mod test_traits; pub use num_traits::{Float, Hex, Int}; +pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, TupleCall}; + +/// Result type for tests is usually from `anyhow`. Most times there is no success value to +/// propagate. +pub type TestResult = Result; // List of all files present in libm's source include!(concat!(env!("OUT_DIR"), "/all_files.rs")); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs index 835d6e46d437f..d7d806bab9eaa 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs @@ -1,5 +1,7 @@ use std::fmt; +use crate::TestResult; + /// Common types and methods for floating point numbers. pub trait Float: Copy + fmt::Display + fmt::Debug + PartialEq { type Int: Int; @@ -134,6 +136,29 @@ macro_rules! impl_int { format!("{self:#0width$x}", width = ((Self::BITS / 4) + 2) as usize) } } + + impl $crate::CheckOutput for $ty { + fn validate<'a>( + self, + expected: Self, + input: Input, + _ctx: &$crate::CheckCtx, + ) -> TestResult { + anyhow::ensure!( + self == expected, + "\ + \n input: {input:?} {ibits}\ + \n expected: {expected:<22?} {expbits}\ + \n actual: {self:<22?} {actbits}\ + ", + actbits = self.hex(), + expbits = expected.hex(), + ibits = input.hex(), + ); + + Ok(()) + } + } } } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs new file mode 100644 index 0000000000000..c6f1f84ae05cf --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -0,0 +1,217 @@ +//! Traits related to testing. +//! +//! There are three main traits in this module: +//! +//! - `GenerateInput`: implemented on any types that create test cases. +//! - `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. + +use std::fmt; + +use anyhow::{Context, bail, ensure}; + +use crate::{Float, Hex, Int, TestResult}; + +/// Implement this on types that can generate a sequence of tuples for test input. +pub trait GenerateInput { + fn get_cases(&self) -> impl Iterator; +} + +/// Trait for calling a function with a tuple as arguments. +/// +/// Implemented on the tuple with the function signature as the generic (so we can use the same +/// tuple for multiple signatures). +pub trait TupleCall: fmt::Debug { + type Output; + fn call(self, f: Func) -> Self::Output; +} + +/// Context passed to [`CheckOutput`]. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CheckCtx { + /// Allowed ULP deviation + pub ulp: u32, + /// Function name. + pub fname: &'static str, + /// Source of truth for tests. + pub basis: CheckBasis, +} + +/// Possible items to test against +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum CheckBasis {} + +/// 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. + /// + /// `input` is only used here for error messages. + fn validate<'a>(self, expected: Self, input: Input, ctx: &CheckCtx) -> TestResult; +} + +impl TupleCall R> for (T1,) +where + T1: fmt::Debug, +{ + type Output = R; + + fn call(self, f: fn(T1) -> R) -> Self::Output { + f(self.0) + } +} + +impl TupleCall R> for (T1, T2) +where + T1: fmt::Debug, + T2: fmt::Debug, +{ + type Output = R; + + fn call(self, f: fn(T1, T2) -> R) -> Self::Output { + f(self.0, self.1) + } +} + +impl TupleCall R> for (T1,) +where + T1: fmt::Debug, + T2: fmt::Debug + Default, +{ + type Output = (R, T2); + + fn call(self, f: fn(T1, &mut T2) -> R) -> Self::Output { + let mut t2 = T2::default(); + (f(self.0, &mut t2), t2) + } +} + +impl TupleCall R> for (T1, T2, T3) +where + T1: fmt::Debug, + T2: fmt::Debug, + T3: fmt::Debug, +{ + type Output = R; + + fn call(self, f: fn(T1, T2, T3) -> R) -> Self::Output { + f(self.0, self.1, self.2) + } +} + +impl TupleCall R> for (T1, T2) +where + T1: fmt::Debug, + T2: fmt::Debug, + T3: fmt::Debug + Default, +{ + type Output = (R, T3); + + fn call(self, f: fn(T1, T2, &mut T3) -> R) -> Self::Output { + let mut t3 = T3::default(); + (f(self.0, self.1, &mut t3), t3) + } +} + +impl TupleCall for (T1,) +where + T1: fmt::Debug, + T2: fmt::Debug + Default, + T3: fmt::Debug + Default, +{ + type Output = (T2, T3); + + fn call(self, f: fn(T1, &mut T2, &mut T3)) -> Self::Output { + let mut t2 = T2::default(); + let mut t3 = T3::default(); + f(self.0, &mut t2, &mut t3); + (t2, t3) + } +} + +// Implement for floats +impl CheckOutput for F +where + F: Float + Hex, + Input: Hex + fmt::Debug, + u32: TryFrom, +{ + fn validate<'a>(self, expected: Self, input: Input, ctx: &CheckCtx) -> TestResult { + // Create a wrapper function so we only need to `.with_context` once. + let inner = || -> TestResult { + // Check when both are NaNs + if self.is_nan() && expected.is_nan() { + ensure!(self.to_bits() == expected.to_bits(), "NaNs have different bitpatterns"); + // Nothing else to check + return Ok(()); + } else if self.is_nan() || expected.is_nan() { + // Check when only one is a NaN + bail!("real value != NaN") + } + + // Make sure that the signs are the same before checing ULP to avoid wraparound + let act_sig = self.signum(); + let exp_sig = expected.signum(); + ensure!(act_sig == exp_sig, "mismatched signs {act_sig} {exp_sig}"); + + if self.is_infinite() ^ expected.is_infinite() { + bail!("mismatched infinities"); + } + + let act_bits = self.to_bits().signed(); + let exp_bits = expected.to_bits().signed(); + + let ulp_diff = act_bits.checked_sub(exp_bits).unwrap().abs(); + + let ulp_u32 = u32::try_from(ulp_diff) + .map_err(|e| anyhow::anyhow!("{e:?}: ulp of {ulp_diff} exceeds u32::MAX"))?; + + let allowed_ulp = ctx.ulp; + ensure!(ulp_u32 <= allowed_ulp, "ulp {ulp_diff} > {allowed_ulp}",); + + Ok(()) + }; + + inner().with_context(|| { + format!( + "\ + \n input: {input:?} {ibits}\ + \n expected: {expected:<22?} {expbits}\ + \n actual: {self:<22?} {actbits}\ + ", + actbits = self.hex(), + expbits = expected.hex(), + ibits = input.hex(), + ) + }) + } +} + +/// Implement `CheckOutput` for combinations of types. +macro_rules! impl_tuples { + ($(($a:ty, $b:ty);)*) => { + $( + impl CheckOutput for ($a, $b) { + fn validate<'a>( + self, + expected: Self, + input: Input, + ctx: &CheckCtx, + ) -> TestResult { + self.0.validate(expected.0, input, ctx,) + .and_then(|()| self.1.validate(expected.1, input, ctx)) + .with_context(|| format!( + "full input {input:?} full actual {self:?} expected {expected:?}" + )) + } + } + )* + }; +} + +impl_tuples!( + (f32, i32); + (f64, i32); + (f32, f32); + (f64, f64); +); From 128e572054342be4bffc283bf235cfa17c7f5640 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Oct 2024 22:56:28 -0500 Subject: [PATCH 1389/4206] Add a helper for cached test inputs Add a type that caches values used to implement `GenerateInput` on a variety of signatures. --- .../libm/crates/libm-test/src/gen.rs | 71 +++++++++++++++++++ .../libm/crates/libm-test/src/lib.rs | 1 + 2 files changed, 72 insertions(+) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/gen.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs new file mode 100644 index 0000000000000..12e17d476538b --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs @@ -0,0 +1,71 @@ +//! Different generators that can create random or systematic bit patterns. + +use crate::GenerateInput; + +/// Helper type to turn any reusable input into a generator. +#[derive(Clone, Debug, Default)] +pub struct CachedInput { + pub inputs_f32: Vec<(f32, f32, f32)>, + pub inputs_f64: Vec<(f64, f64, f64)>, + pub inputs_i32: Vec<(i32, i32, i32)>, +} + +impl GenerateInput<(f32,)> for CachedInput { + fn get_cases(&self) -> impl Iterator { + self.inputs_f32.iter().map(|f| (f.0,)) + } +} + +impl GenerateInput<(f32, f32)> for CachedInput { + fn get_cases(&self) -> impl Iterator { + self.inputs_f32.iter().map(|f| (f.0, f.1)) + } +} + +impl GenerateInput<(i32, f32)> for CachedInput { + fn get_cases(&self) -> impl Iterator { + self.inputs_i32.iter().zip(self.inputs_f32.iter()).map(|(i, f)| (i.0, f.0)) + } +} + +impl GenerateInput<(f32, i32)> for CachedInput { + fn get_cases(&self) -> impl Iterator { + GenerateInput::<(i32, f32)>::get_cases(self).map(|(i, f)| (f, i)) + } +} + +impl GenerateInput<(f32, f32, f32)> for CachedInput { + fn get_cases(&self) -> impl Iterator { + self.inputs_f32.iter().copied() + } +} + +impl GenerateInput<(f64,)> for CachedInput { + fn get_cases(&self) -> impl Iterator { + self.inputs_f64.iter().map(|f| (f.0,)) + } +} + +impl GenerateInput<(f64, f64)> for CachedInput { + fn get_cases(&self) -> impl Iterator { + self.inputs_f64.iter().map(|f| (f.0, f.1)) + } +} + +impl GenerateInput<(i32, f64)> for CachedInput { + fn get_cases(&self) -> impl Iterator { + self.inputs_i32.iter().zip(self.inputs_f64.iter()).map(|(i, f)| (i.0, f.0)) + } +} + +impl GenerateInput<(f64, i32)> for CachedInput { + fn get_cases(&self) -> impl Iterator { + GenerateInput::<(i32, f64)>::get_cases(self).map(|(i, f)| (f, i)) + } +} + +impl GenerateInput<(f64, f64, f64)> for CachedInput { + fn get_cases(&self) -> impl Iterator { + self.inputs_f64.iter().copied() + } +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 41873099f637a..fc5385ecbc29d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -1,3 +1,4 @@ +pub mod gen; mod num_traits; mod test_traits; From 593fa8f3cba2daa5b35d87965c5be4e0b59341d0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Oct 2024 16:59:14 -0500 Subject: [PATCH 1390/4206] Add a deterministic random generator Create a test generator that creates a known number of random inputs and caches them, such that the same inputs are used for all functions. --- .../libm/crates/libm-test/Cargo.toml | 6 + .../libm/crates/libm-test/src/gen.rs | 1 + .../libm/crates/libm-test/src/gen/random.rs | 125 ++++++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index b6e2ced5877d3..760340e518c70 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -15,6 +15,12 @@ test-musl-serialized = ["rand"] anyhow = "1.0.90" libm = { path = "../.." } libm-macros = { path = "../libm-macros" } +rand = "0.8.5" +rand_chacha = "0.3.1" + +[target.'cfg(target_family = "wasm")'.dependencies] +# Enable randomness on WASM +getrandom = { version = "0.2", features = ["js"] } [build-dependencies] rand = { version = "0.8.5", optional = true } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs index 12e17d476538b..3e9eca37a6778 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs @@ -1,6 +1,7 @@ //! Different generators that can create random or systematic bit patterns. use crate::GenerateInput; +pub mod random; /// Helper type to turn any reusable input into a generator. #[derive(Clone, Debug, Default)] diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs new file mode 100644 index 0000000000000..e5964319569d7 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -0,0 +1,125 @@ +//! A simple generator that produces deterministic random input, caching to use the same +//! inputs for all functions. + +use std::sync::LazyLock; + +use rand::{Rng, SeedableRng}; +use rand_chacha::ChaCha8Rng; + +use super::CachedInput; +use crate::GenerateInput; + +const SEED: [u8; 32] = *b"3.141592653589793238462643383279"; + +/// Number of tests to run. +const NTESTS: usize = { + let ntests = if cfg!(optimizations_enabled) { + if cfg!(target_arch = "x86_64") || cfg!(target_arch = "aarch64") { + 5_000_000 + } else if !cfg!(target_pointer_width = "64") + || cfg!(all(target_arch = "x86_64", target_vendor = "apple")) + || option_env!("EMULATED").is_some() + && cfg!(any(target_arch = "aarch64", target_arch = "powerpc64")) + { + // Tests are pretty slow on: + // - Non-64-bit targets + // - Emulated ppc + // - Emulated aarch64 + // - x86 MacOS + // So reduce the number of iterations + 100_000 + } else { + // Most everything else gets tested in docker and works okay, but we still + // don't need 20 minutes of tests. + 1_000_000 + } + } else { + 800 + }; + + ntests +}; + +/// Tested inputs. +static TEST_CASES: LazyLock = LazyLock::new(|| make_test_cases(NTESTS)); + +/// The first argument to `jn` and `jnf` is the number of iterations. Make this a reasonable +/// value so tests don't run forever. +static TEST_CASES_JN: LazyLock = LazyLock::new(|| { + // Start with regular test cases + let mut cases = (&*TEST_CASES).clone(); + + // These functions are extremely slow, limit them + cases.inputs_i32.truncate((NTESTS / 1000).max(80)); + cases.inputs_f32.truncate((NTESTS / 1000).max(80)); + cases.inputs_f64.truncate((NTESTS / 1000).max(80)); + + // It is easy to overflow the stack with these in debug mode + let max_iterations = if cfg!(optimizations_enabled) && cfg!(target_pointer_width = "64") { + 0xffff + } else if cfg!(windows) { + 0x00ff + } else { + 0x0fff + }; + + let mut rng = ChaCha8Rng::from_seed(SEED); + + for case in cases.inputs_i32.iter_mut() { + case.0 = rng.gen_range(3..=max_iterations); + } + + cases +}); + +fn make_test_cases(ntests: usize) -> CachedInput { + let mut rng = ChaCha8Rng::from_seed(SEED); + + // make sure we include some basic cases + let mut inputs_i32 = vec![(0, 0, 0), (1, 1, 1), (-1, -1, -1)]; + let mut inputs_f32 = vec![ + (0.0, 0.0, 0.0), + (f32::EPSILON, f32::EPSILON, f32::EPSILON), + (f32::INFINITY, f32::INFINITY, f32::INFINITY), + (f32::NEG_INFINITY, f32::NEG_INFINITY, f32::NEG_INFINITY), + (f32::MAX, f32::MAX, f32::MAX), + (f32::MIN, f32::MIN, f32::MIN), + (f32::MIN_POSITIVE, f32::MIN_POSITIVE, f32::MIN_POSITIVE), + (f32::NAN, f32::NAN, f32::NAN), + ]; + let mut inputs_f64 = vec![ + (0.0, 0.0, 0.0), + (f64::EPSILON, f64::EPSILON, f64::EPSILON), + (f64::INFINITY, f64::INFINITY, f64::INFINITY), + (f64::NEG_INFINITY, f64::NEG_INFINITY, f64::NEG_INFINITY), + (f64::MAX, f64::MAX, f64::MAX), + (f64::MIN, f64::MIN, f64::MIN), + (f64::MIN_POSITIVE, f64::MIN_POSITIVE, f64::MIN_POSITIVE), + (f64::NAN, f64::NAN, f64::NAN), + ]; + + inputs_i32.extend((0..(ntests - inputs_i32.len())).map(|_| rng.gen::<(i32, i32, i32)>())); + + // Generate integers to get a full range of bitpatterns, then convert back to + // floats. + inputs_f32.extend((0..(ntests - inputs_f32.len())).map(|_| { + let ints = rng.gen::<(u32, u32, u32)>(); + (f32::from_bits(ints.0), f32::from_bits(ints.1), f32::from_bits(ints.2)) + })); + inputs_f64.extend((0..(ntests - inputs_f64.len())).map(|_| { + let ints = rng.gen::<(u64, u64, u64)>(); + (f64::from_bits(ints.0), f64::from_bits(ints.1), f64::from_bits(ints.2)) + })); + + CachedInput { inputs_f32, inputs_f64, inputs_i32 } +} + +/// Create a test case iterator. +pub fn get_test_cases(fname: &str) -> impl Iterator +where + CachedInput: GenerateInput, +{ + let inputs = if fname == "jn" || fname == "jnf" { &TEST_CASES_JN } else { &TEST_CASES }; + + CachedInput::get_cases(inputs) +} From 98647ddc2fb3ff6f9bdff9792b967d5b626ea76f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 22 Oct 2024 00:52:00 -0500 Subject: [PATCH 1391/4206] Introduce a generic way to control checks for specific cases Sometimes we want to be able to xfail specific inputs without changing the checked ULP for all cases or skipping the tests. There are also some cases where we need to perform extra checks for only specific functions. Add a trait that provides a hook for providing extra checks or skipping existing checks on a per-function or per-input basis. --- .../libm/crates/libm-test/src/lib.rs | 23 +++++ .../libm/crates/libm-test/src/num_traits.rs | 14 ++- .../libm/crates/libm-test/src/special_case.rs | 95 +++++++++++++++++++ .../libm/crates/libm-test/src/test_traits.rs | 39 +++++++- 4 files changed, 163 insertions(+), 8 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/special_case.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index fc5385ecbc29d..511b5139f0d0a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -1,8 +1,10 @@ pub mod gen; mod num_traits; +mod special_case; mod test_traits; pub use num_traits::{Float, Hex, Int}; +pub use special_case::{MaybeOverride, SpecialCase}; pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, TupleCall}; /// Result type for tests is usually from `anyhow`. Most times there is no success value to @@ -11,3 +13,24 @@ pub type TestResult = Result; // List of all files present in libm's source include!(concat!(env!("OUT_DIR"), "/all_files.rs")); + +/// 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`. +pub fn canonical_name(name: &str) -> &str { + let known_mappings = &[ + ("erff", "erf"), + ("erf", "erf"), + ("lgammaf_r", "lgamma_r"), + ("modff", "modf"), + ("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("f128")) + .unwrap_or(name), + } +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs index d7d806bab9eaa..e16f4e4dca450 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs @@ -1,6 +1,6 @@ use std::fmt; -use crate::TestResult; +use crate::{MaybeOverride, SpecialCase, TestResult}; /// Common types and methods for floating point numbers. pub trait Float: Copy + fmt::Display + fmt::Debug + PartialEq { @@ -137,13 +137,21 @@ macro_rules! impl_int { } } - impl $crate::CheckOutput for $ty { + impl $crate::CheckOutput for $ty + where + Input: Hex + fmt::Debug, + SpecialCase: MaybeOverride, + { fn validate<'a>( self, expected: Self, input: Input, - _ctx: &$crate::CheckCtx, + ctx: &$crate::CheckCtx, ) -> TestResult { + if let Some(res) = SpecialCase::check_int(input, self, expected, ctx) { + return res; + } + anyhow::ensure!( self == expected, "\ diff --git a/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs b/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs new file mode 100644 index 0000000000000..116a0a1881e39 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs @@ -0,0 +1,95 @@ +//! Configuration for skipping or changing the result for individual test cases (inputs) rather +//! than ignoring entire tests. + +use crate::{CheckCtx, Float, Int, TestResult}; + +/// Type implementing [`IgnoreCase`]. +pub struct SpecialCase; + +/// Don't run further validation on this test case. +const SKIP: Option = Some(Ok(())); + +/// Return this to skip checks on a test that currently fails but shouldn't. Looks +/// the same as skip, but we keep them separate to better indicate purpose. +const XFAIL: Option = Some(Ok(())); + +/// Allow overriding the outputs of specific test cases. +/// +/// There are some cases where we want to xfail specific cases or handle certain inputs +/// differently than the rest of calls to `validate`. This provides a hook to do that. +/// +/// If `None` is returned, checks will proceed as usual. If `Some(result)` is returned, checks +/// are skipped and the provided result is returned instead. +/// +/// This gets implemented once per input type, then the functions provide further filtering +/// based on function name and values. +/// +/// `ulp` can also be set to adjust the ULP for that specific test, even if `None` is still +/// returned. +pub trait MaybeOverride { + fn check_float( + _input: Input, + _actual: F, + _expected: F, + _ulp: &mut u32, + _ctx: &CheckCtx, + ) -> Option { + None + } + + fn check_int( + _input: Input, + _actual: I, + _expected: I, + _ctx: &CheckCtx, + ) -> Option { + None + } +} + +impl MaybeOverride<(f32,)> for SpecialCase { + fn check_float( + _input: (f32,), + actual: F, + expected: F, + _ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + maybe_check_nan_bits(actual, expected, ctx) + } +} + +impl MaybeOverride<(f64,)> for SpecialCase { + fn check_float( + _input: (f64,), + actual: F, + expected: F, + _ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + maybe_check_nan_bits(actual, expected, ctx) + } +} + +impl MaybeOverride<(f32, f32)> for SpecialCase {} +impl MaybeOverride<(f64, f64)> for SpecialCase {} +impl MaybeOverride<(f32, f32, f32)> for SpecialCase {} +impl MaybeOverride<(f64, f64, f64)> for SpecialCase {} +impl MaybeOverride<(i32, f32)> for SpecialCase {} +impl MaybeOverride<(i32, f64)> for SpecialCase {} +impl MaybeOverride<(f32, i32)> for SpecialCase {} +impl MaybeOverride<(f64, i32)> for SpecialCase {} + +/// Check NaN bits if the function requires it +fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Option { + if !(ctx.canonical_name == "abs" || ctx.canonical_name == "copysigh") { + return None; + } + + // abs and copysign require signaling NaNs to be propagated, so verify bit equality. + if actual.to_bits() == expected.to_bits() { + return SKIP; + } else { + Some(Err(anyhow::anyhow!("NaNs have different bitpatterns"))) + } +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index c6f1f84ae05cf..296f1b0fd188a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -11,7 +11,7 @@ use std::fmt; use anyhow::{Context, bail, ensure}; -use crate::{Float, Hex, Int, TestResult}; +use crate::{Float, Hex, Int, MaybeOverride, SpecialCase, TestResult}; /// Implement this on types that can generate a sequence of tuples for test input. pub trait GenerateInput { @@ -34,10 +34,19 @@ pub struct CheckCtx { pub ulp: u32, /// Function name. pub fname: &'static str, + /// Return the unsuffixed version of the function name. + pub canonical_name: &'static str, /// Source of truth for tests. pub basis: CheckBasis, } +impl CheckCtx { + pub fn new(ulp: u32, fname: &'static str, basis: CheckBasis) -> Self { + let canonical_fname = crate::canonical_name(fname); + Self { ulp, fname, canonical_name: canonical_fname, basis } + } +} + /// Possible items to test against #[derive(Clone, Debug, PartialEq, Eq)] pub enum CheckBasis {} @@ -135,10 +144,20 @@ where F: Float + Hex, Input: Hex + fmt::Debug, u32: TryFrom, + SpecialCase: MaybeOverride, { fn validate<'a>(self, expected: Self, input: Input, ctx: &CheckCtx) -> TestResult { // Create a wrapper function so we only need to `.with_context` once. let inner = || -> TestResult { + let mut allowed_ulp = ctx.ulp; + + // If the tested function requires a nonstandard test, run it here. + if let Some(res) = + SpecialCase::check_float(input, self, expected, &mut allowed_ulp, ctx) + { + return res; + } + // Check when both are NaNs if self.is_nan() && expected.is_nan() { ensure!(self.to_bits() == expected.to_bits(), "NaNs have different bitpatterns"); @@ -166,7 +185,6 @@ where let ulp_u32 = u32::try_from(ulp_diff) .map_err(|e| anyhow::anyhow!("{e:?}: ulp of {ulp_diff} exceeds u32::MAX"))?; - let allowed_ulp = ctx.ulp; ensure!(ulp_u32 <= allowed_ulp, "ulp {ulp_diff} > {allowed_ulp}",); Ok(()) @@ -191,17 +209,28 @@ where macro_rules! impl_tuples { ($(($a:ty, $b:ty);)*) => { $( - impl CheckOutput for ($a, $b) { + impl CheckOutput for ($a, $b) + where + Input: Hex + 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 input {input:?} full actual {self:?} expected {expected:?}" + "full context:\ + \n input: {input:?} {ibits}\ + \n expected: {expected:?} {expbits}\ + \n actual: {self:?} {actbits}\ + ", + actbits = self.hex(), + expbits = expected.hex(), + ibits = input.hex(), )) } } From 1073858c72cf7fed6a40a5ab24a80c696e56c384 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Oct 2024 22:59:17 -0500 Subject: [PATCH 1392/4206] Add a test against musl libm Check our functions against `musl-math-sys`. This is similar to the existing musl tests that go through binary serialization, but works on more platforms. --- .../libm/crates/libm-test/Cargo.toml | 5 + .../libm/crates/libm-test/src/lib.rs | 28 +++ .../libm/crates/libm-test/src/special_case.rs | 170 ++++++++++++++++-- .../libm/crates/libm-test/src/test_traits.rs | 8 +- .../libm-test/tests/compare_built_musl.rs | 52 ++++++ 5 files changed, 247 insertions(+), 16 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 760340e518c70..703524bcd708a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -11,10 +11,15 @@ default = [] # musl libc. test-musl-serialized = ["rand"] +# Build our own musl for testing and benchmarks +build-musl = ["dep:musl-math-sys"] + [dependencies] anyhow = "1.0.90" libm = { path = "../.." } libm-macros = { path = "../libm-macros" } +musl-math-sys = { path = "../musl-math-sys", optional = true } +paste = "1.0.15" rand = "0.8.5" rand_chacha = "0.3.1" diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 511b5139f0d0a..3baf77524f0ea 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -14,6 +14,34 @@ pub type TestResult = Result; // List of all files present in libm's source include!(concat!(env!("OUT_DIR"), "/all_files.rs")); +/// ULP allowed to differ from musl (note that musl itself may not be accurate). +const MUSL_DEFAULT_ULP: u32 = 2; + +/// Certain functions have different allowed ULP (consider these xfail). +/// +/// Note that these results were obtained using 400,000,000 rounds of random inputs, which +/// is not a value used by default. +pub fn musl_allowed_ulp(name: &str) -> u32 { + match name { + #[cfg(x86_no_sse)] + "asinh" | "asinhf" => 6, + "lgamma" | "lgamma_r" | "lgammaf" | "lgammaf_r" => 400, + "tanh" | "tanhf" => 4, + "tgamma" => 20, + "j0" | "j0f" | "j1" | "j1f" => { + // Results seem very target-dependent + if cfg!(target_arch = "x86_64") { 4000 } else { 800_000 } + } + "jn" | "jnf" => 1000, + "sincosf" => 500, + #[cfg(not(target_pointer_width = "64"))] + "exp10" => 4, + #[cfg(not(target_pointer_width = "64"))] + "exp10f" => 4, + _ => MUSL_DEFAULT_ULP, + } +} + /// 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`. pub fn canonical_name(name: &str) -> &str { diff --git a/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs b/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs index 116a0a1881e39..df263d7428ccc 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs @@ -1,7 +1,9 @@ //! Configuration for skipping or changing the result for individual test cases (inputs) rather //! than ignoring entire tests. -use crate::{CheckCtx, Float, Int, TestResult}; +use core::f32; + +use crate::{CheckBasis, CheckCtx, Float, Int, TestResult}; /// Type implementing [`IgnoreCase`]. pub struct SpecialCase; @@ -49,43 +51,97 @@ pub trait MaybeOverride { impl MaybeOverride<(f32,)> for SpecialCase { fn check_float( - _input: (f32,), + input: (f32,), actual: F, expected: F, _ulp: &mut u32, ctx: &CheckCtx, ) -> Option { + if ctx.basis == CheckBasis::Musl { + if ctx.fname == "acoshf" && input.0 < -1.0 { + // acoshf is undefined for x <= 1.0, but we return a random result at lower + // values. + return XFAIL; + } + + if ctx.fname == "sincosf" { + let factor_frac_pi_2 = input.0.abs() / f32::consts::FRAC_PI_2; + if (factor_frac_pi_2 - factor_frac_pi_2.round()).abs() < 1e-2 { + // we have a bad approximation near multiples of pi/2 + return XFAIL; + } + } + + if ctx.fname == "expm1f" && input.0 > 80.0 && actual.is_infinite() { + // we return infinity but the number is representable + return XFAIL; + } + + if ctx.fname == "sinhf" && input.0.abs() > 80.0 && actual.is_nan() { + // we return some NaN that should be real values or infinite + // doesn't seem to happen on x86 + return XFAIL; + } + + if ctx.fname == "lgammaf" || ctx.fname == "lgammaf_r" && input.0 < 0.0 { + // loggamma should not be defined for x < 0, yet we both return results + return XFAIL; + } + } + maybe_check_nan_bits(actual, expected, ctx) } } impl MaybeOverride<(f64,)> for SpecialCase { fn check_float( - _input: (f64,), + input: (f64,), actual: F, expected: F, _ulp: &mut u32, ctx: &CheckCtx, ) -> Option { + if ctx.basis == CheckBasis::Musl { + if cfg!(target_arch = "x86") && ctx.fname == "acosh" && input.0 < 1.0 { + // The function is undefined, both implementations return random results + return SKIP; + } + + if cfg!(x86_no_sse) + && ctx.fname == "ceil" + && input.0 < 0.0 + && input.0 > -1.0 + && expected == F::ZERO + && actual == F::ZERO + { + // musl returns -0.0, we return +0.0 + return XFAIL; + } + + if ctx.fname == "lgamma" || ctx.fname == "lgamma_r" && input.0 < 0.0 { + // loggamma should not be defined for x < 0, yet we both return results + return XFAIL; + } + } + maybe_check_nan_bits(actual, expected, ctx) } } -impl MaybeOverride<(f32, f32)> for SpecialCase {} -impl MaybeOverride<(f64, f64)> for SpecialCase {} -impl MaybeOverride<(f32, f32, f32)> for SpecialCase {} -impl MaybeOverride<(f64, f64, f64)> for SpecialCase {} -impl MaybeOverride<(i32, f32)> for SpecialCase {} -impl MaybeOverride<(i32, f64)> for SpecialCase {} -impl MaybeOverride<(f32, i32)> for SpecialCase {} -impl MaybeOverride<(f64, i32)> for SpecialCase {} - /// Check NaN bits if the function requires it fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Option { - if !(ctx.canonical_name == "abs" || ctx.canonical_name == "copysigh") { + if !(ctx.canonical_name == "fabs" || ctx.canonical_name == "copysign") { return None; } + // LLVM currently uses x87 instructions which quieten signalling NaNs to handle the i686 + // `extern "C"` `f32`/`f64` return ABI. + // LLVM issue + // Rust issue + if cfg!(target_arch = "x86") && ctx.basis == CheckBasis::Musl { + return SKIP; + } + // abs and copysign require signaling NaNs to be propagated, so verify bit equality. if actual.to_bits() == expected.to_bits() { return SKIP; @@ -93,3 +149,91 @@ fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Opt Some(Err(anyhow::anyhow!("NaNs have different bitpatterns"))) } } + +impl MaybeOverride<(f32, f32)> for SpecialCase { + fn check_float( + input: (f32, f32), + _actual: F, + expected: F, + _ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + maybe_skip_min_max_nan(input, expected, ctx) + } +} +impl MaybeOverride<(f64, f64)> for SpecialCase { + fn check_float( + input: (f64, f64), + _actual: F, + expected: F, + _ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + maybe_skip_min_max_nan(input, expected, ctx) + } +} + +/// Musl propagates NaNs if one is provided as the input, but we return the other input. +// F1 and F2 are always the same type, this is just to please generics +fn maybe_skip_min_max_nan( + input: (F1, F1), + expected: F2, + ctx: &CheckCtx, +) -> Option { + if (ctx.canonical_name == "fmax" || ctx.canonical_name == "fmin") + && (input.0.is_nan() || input.1.is_nan()) + && expected.is_nan() + { + return XFAIL; + } else { + None + } +} + +impl MaybeOverride<(i32, f32)> for SpecialCase { + fn check_float( + input: (i32, f32), + _actual: F, + _expected: F, + ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + bessel_prec_dropoff(input, ulp, ctx) + } +} +impl MaybeOverride<(i32, f64)> for SpecialCase { + fn check_float( + input: (i32, f64), + _actual: F, + _expected: F, + ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + bessel_prec_dropoff(input, ulp, ctx) + } +} + +/// Our bessel functions blow up with large N values +fn bessel_prec_dropoff( + input: (i32, F), + ulp: &mut u32, + ctx: &CheckCtx, +) -> Option { + if ctx.canonical_name == "jn" { + if input.0 > 4000 { + return XFAIL; + } else if input.0 > 2000 { + // *ulp = 20_000; + *ulp = 20000; + } else if input.0 > 1000 { + *ulp = 4000; + } + } + + None +} + +impl MaybeOverride<(f32, f32, f32)> for SpecialCase {} +impl MaybeOverride<(f64, f64, f64)> for SpecialCase {} +impl MaybeOverride<(f32, i32)> for SpecialCase {} +impl MaybeOverride<(f64, i32)> for SpecialCase {} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index 296f1b0fd188a..c24ac6e43bc26 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -49,7 +49,10 @@ impl CheckCtx { /// Possible items to test against #[derive(Clone, Debug, PartialEq, Eq)] -pub enum CheckBasis {} +pub enum CheckBasis { + /// Check against Musl's math sources. + Musl, +} /// A trait to implement on any output type so we can verify it in a generic way. pub trait CheckOutput: Sized { @@ -160,8 +163,7 @@ where // Check when both are NaNs if self.is_nan() && expected.is_nan() { - ensure!(self.to_bits() == expected.to_bits(), "NaNs have different bitpatterns"); - // Nothing else to check + // By default, NaNs have nothing special to check. return Ok(()); } else if self.is_nan() || expected.is_nan() { // Check when only one is a NaN diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs new file mode 100644 index 0000000000000..208b8e28618e1 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -0,0 +1,52 @@ +//! Compare our implementations with the result of musl functions, as provided by `musl-math-sys`. +//! +//! Currently this only tests randomized inputs. In the future this may be improved to test edge +//! cases or run exhaustive tests. +//! +//! Note that musl functions do not always provide 0.5ULP rounding, so our functions can do better +//! than these results. + +// There are some targets we can't build musl for +#![cfg(feature = "build-musl")] + +use libm_test::gen::random; +use libm_test::{CheckBasis, CheckCtx, CheckOutput, TupleCall, musl_allowed_ulp}; +use musl_math_sys as musl; + +macro_rules! musl_rand_tests { + ( + fn_name: $fn_name:ident, + CFn: $CFn:ty, + CArgs: $CArgs:ty, + CRet: $CRet:ty, + RustFn: $RustFn:ty, + RustArgs: $RustArgs:ty, + RustRet: $RustRet:ty, + attrs: [$($meta:meta)*] + ) => { paste::paste! { + #[test] + $(#[$meta])* + fn [< musl_random_ $fn_name >]() { + let fname = stringify!($fn_name); + let ulp = musl_allowed_ulp(fname); + let cases = random::get_test_cases::<$RustArgs>(fname); + let ctx = CheckCtx::new(ulp, fname, CheckBasis::Musl); + + for input in cases { + let musl_res = input.call(musl::$fn_name as $CFn); + let crate_res = input.call(libm::$fn_name as $RustFn); + + crate_res.validate(musl_res, input, &ctx).unwrap(); + } + } + } }; +} + +libm_macros::for_each_function! { + callback: musl_rand_tests, + skip: [], + attributes: [ + #[cfg_attr(x86_no_sse, ignore)] // FIXME(correctness): wrong result on i586 + [exp10, exp10f, exp2, exp2f, rint] + ], +} From 31d0132ac14dc2e2b3fb24ac38309ca5ab7ca235 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Oct 2024 22:33:27 -0500 Subject: [PATCH 1393/4206] Add dockerfiles for i586, riscv, and thumb These targets are tested in `compiler-builtins`, but not yet `libm`. Add dockerfiles to prepare for this. --- .../ci/docker/i586-unknown-linux-gnu/Dockerfile | 5 +++++ .../docker/riscv64gc-unknown-linux-gnu/Dockerfile | 15 +++++++++++++++ .../libm/ci/docker/thumbv6m-none-eabi/Dockerfile | 9 +++++++++ .../libm/ci/docker/thumbv7em-none-eabi/Dockerfile | 9 +++++++++ .../ci/docker/thumbv7em-none-eabihf/Dockerfile | 9 +++++++++ .../libm/ci/docker/thumbv7m-none-eabi/Dockerfile | 9 +++++++++ 6 files changed, 56 insertions(+) create mode 100644 library/compiler-builtins/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/thumbv6m-none-eabi/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabi/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile create mode 100644 library/compiler-builtins/libm/ci/docker/thumbv7m-none-eabi/Dockerfile diff --git a/library/compiler-builtins/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile new file mode 100644 index 0000000000000..3b0bfc0d3d9d2 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile @@ -0,0 +1,5 @@ +FROM ubuntu:24.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc-multilib libc6-dev ca-certificates diff --git a/library/compiler-builtins/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile new file mode 100644 index 0000000000000..5f8a289241148 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile @@ -0,0 +1,15 @@ +FROM ubuntu:24.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user-static ca-certificates \ + gcc-riscv64-linux-gnu libc6-dev-riscv64-cross \ + qemu-system-riscv64 + +ENV TOOLCHAIN_PREFIX=riscv64-linux-gnu- +ENV CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ + CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_RUNNER=qemu-riscv64-static \ + AR_riscv64gc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_riscv64gc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ + QEMU_LD_PREFIX=/usr/riscv64-linux-gnu \ + RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/libm/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/libm/ci/docker/thumbv6m-none-eabi/Dockerfile new file mode 100644 index 0000000000000..ad0d4351ea654 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -0,0 +1,9 @@ +ARG IMAGE=ubuntu:24.04 +FROM $IMAGE + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-none-eabi \ + libnewlib-arm-none-eabi +ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabi/Dockerfile new file mode 100644 index 0000000000000..ad0d4351ea654 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -0,0 +1,9 @@ +ARG IMAGE=ubuntu:24.04 +FROM $IMAGE + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-none-eabi \ + libnewlib-arm-none-eabi +ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile new file mode 100644 index 0000000000000..ad0d4351ea654 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -0,0 +1,9 @@ +ARG IMAGE=ubuntu:24.04 +FROM $IMAGE + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-none-eabi \ + libnewlib-arm-none-eabi +ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/libm/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/libm/ci/docker/thumbv7m-none-eabi/Dockerfile new file mode 100644 index 0000000000000..ad0d4351ea654 --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -0,0 +1,9 @@ +ARG IMAGE=ubuntu:24.04 +FROM $IMAGE + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-none-eabi \ + libnewlib-arm-none-eabi +ENV BUILD_ONLY=1 From ee131ffa47ee17f4ac1f3d32230bbb3638183c0c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Oct 2024 23:00:17 -0500 Subject: [PATCH 1394/4206] Disable a unit test that is failing on i586 --- library/compiler-builtins/libm/src/math/rem_pio2.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 6be23a43cede2..4dfb8c6588379 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -194,6 +194,8 @@ mod tests { use super::rem_pio2; #[test] + // FIXME(correctness): inaccurate results on i586 + #[cfg_attr(all(target_arch = "x86", not(target_feature = "sse")), ignore)] fn test_near_pi() { let arg = 3.141592025756836; let arg = force_eval!(arg); From f5d30ecc3b8b886c2ce0cd7ebaf3cbb80206eac1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Oct 2024 22:59:59 -0500 Subject: [PATCH 1395/4206] Enable more targets on CI This brings the targets tested here in line with those tested in `compiler-builtins`. --- .../libm/.github/workflows/main.yml | 121 ++++++++++++++---- .../compiler-builtins/libm/ci/run-docker.sh | 1 + library/compiler-builtins/libm/ci/run.sh | 69 ++++++++-- 3 files changed, 151 insertions(+), 40 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 926e3c19e2e7d..a2c7795261d64 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -2,38 +2,103 @@ name: CI on: [push, pull_request] env: + CARGO_TERM_VERBOSE: true RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings + RUST_BACKTRACE: full jobs: - docker: + test: name: Docker - runs-on: ubuntu-latest + timeout-minutes: 20 strategy: + fail-fast: false matrix: - target: - - aarch64-unknown-linux-gnu - - arm-unknown-linux-gnueabi - - arm-unknown-linux-gnueabihf - - armv7-unknown-linux-gnueabihf - # - i686-unknown-linux-gnu - # MIPS targets disabled since they are dropped to tier 3. - # See https://github.com/rust-lang/compiler-team/issues/648 - #- mips-unknown-linux-gnu - #- mips64-unknown-linux-gnuabi64 - #- mips64el-unknown-linux-gnuabi64 - - powerpc-unknown-linux-gnu - - powerpc64-unknown-linux-gnu - - powerpc64le-unknown-linux-gnu - - x86_64-unknown-linux-gnu + include: + - target: aarch64-apple-darwin + os: macos-latest + - target: aarch64-unknown-linux-gnu + os: ubuntu-latest + - target: aarch64-pc-windows-msvc + os: windows-latest + build_only: 1 # Can't run on x86 hosts + - target: arm-unknown-linux-gnueabi + os: ubuntu-latest + - target: arm-unknown-linux-gnueabihf + os: ubuntu-latest + - target: armv7-unknown-linux-gnueabihf + os: ubuntu-latest + - target: i586-unknown-linux-gnu + os: ubuntu-latest + - target: i686-unknown-linux-gnu + os: ubuntu-latest + - target: powerpc-unknown-linux-gnu + os: ubuntu-latest + - target: powerpc64-unknown-linux-gnu + os: ubuntu-latest + - target: powerpc64le-unknown-linux-gnu + os: ubuntu-latest + - target: riscv64gc-unknown-linux-gnu + os: ubuntu-latest + - target: thumbv6m-none-eabi + os: ubuntu-latest + - target: thumbv7em-none-eabi + os: ubuntu-latest + - target: thumbv7em-none-eabihf + os: ubuntu-latest + - target: thumbv7m-none-eabi + os: ubuntu-latest + - target: x86_64-unknown-linux-gnu + os: ubuntu-latest + - target: x86_64-apple-darwin + os: macos-13 + - target: i686-pc-windows-msvc + os: windows-latest + - target: x86_64-pc-windows-msvc + os: windows-latest + - target: i686-pc-windows-gnu + os: windows-latest + channel: nightly-i686-gnu + - target: x86_64-pc-windows-gnu + os: windows-latest + channel: nightly-x86_64-gnu + runs-on: ${{ matrix.os }} + env: + BUILD_ONLY: ${{ matrix.build_only }} steps: - - uses: actions/checkout@master - - name: Install Rust - run: rustup update nightly --no-self-update && rustup default nightly - - run: rustup target add ${{ matrix.target }} - - run: rustup target add x86_64-unknown-linux-musl - - run: cargo generate-lockfile - - run: ./ci/run-docker.sh ${{ matrix.target }} + - name: Print runner information + run: uname -a + - uses: actions/checkout@v4 + - name: Install Rust (rustup) + shell: bash + run: | + channel="nightly" + # Account for channels that have required components (MinGW) + [ -n "${{ matrix.channel }}" ] && channel="${{ matrix.channel }}" + rustup update "$channel" --no-self-update + rustup default "$channel" + rustup target add ${{ matrix.target }} + rustup component add llvm-tools-preview + - uses: Swatinem/rust-cache@v2 + with: + key: ${{ matrix.target }} + + - name: Download musl source + run: ./ci/download-musl.sh + shell: bash + + # Non-linux tests just use our raw script + - name: Run locally + if: matrix.os != 'ubuntu-latest' + shell: bash + run: ./ci/run.sh ${{ matrix.target }} + + # Otherwise we use our docker containers to run builds + - name: Run in Docker + if: matrix.os == 'ubuntu-latest' + run: | + rustup target add x86_64-unknown-linux-musl + cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} wasm: name: WebAssembly @@ -45,7 +110,7 @@ jobs: - run: rustup target add wasm32-unknown-unknown - run: cargo build --target wasm32-unknown-unknown - cb: + builtins: name: "The compiler-builtins crate works" runs-on: ubuntu-latest steps: @@ -61,6 +126,8 @@ jobs: - uses: actions/checkout@master - name: Install Rust run: rustup update nightly --no-self-update && rustup default nightly + - name: Download musl source + run: ./ci/download-musl.sh - run: cargo bench --all msrv: @@ -92,9 +159,9 @@ jobs: success: needs: - - docker + - test - wasm - - cb + - builtins - benchmarks - msrv - rustfmt diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh index 9191a17e2ba5d..2e09dd41a5748 100755 --- a/library/compiler-builtins/libm/ci/run-docker.sh +++ b/library/compiler-builtins/libm/ci/run-docker.sh @@ -21,6 +21,7 @@ run() { -e RUSTFLAGS \ -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ + -e EMULATED=1 \ -v "${HOME}/.cargo:/cargo" \ -v "$(pwd)/target:/target" \ -v "$(pwd):/checkout:ro" \ diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 505e2589187ba..f61fff8433e3a 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -2,21 +2,64 @@ set -eux -target="$1" +export RUST_BACKTRACE="${RUST_BACKTRACE:-full}" +# Needed for no-panic to correct detect a lack of panics +export RUSTFLAGS="${RUSTFLAGS:-} -Ccodegen-units=1" -cmd="cargo test --all --target $target" +target="${1:-}" -# Needed for no-panic to correct detect a lack of panics -export RUSTFLAGS="$RUSTFLAGS -Ccodegen-units=1" +if [ -z "$target" ]; then + host_target=$(rustc -vV | awk '/^host/ { print $2 }') + echo "Defaulted to host target $host_target" + target="$host_target" +fi + +extra_flags="" + +# 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 + # Can't build at all on MSVC, WASM, or thumb + *windows-msvc*) extra_flags="$extra_flags --exclude musl-math-sys" ;; + *wasm*) extra_flags="$extra_flags --exclude musl-math-sys" ;; + *thumb*) extra_flags="$extra_flags --exclude musl-math-sys" ;; + + # We can build musl on MinGW but running tests gets a stack overflow + *windows-gnu*) ;; + # FIXME(#309): LE PPC crashes calling the musl version of some functions. It + # seems like a qemu bug but should be investigated further at some point. + # See . + *powerpc64le*) ;; + + # Everything else gets musl enabled + *) extra_flags="$extra_flags --features libm-test/build-musl" ;; +esac + +# FIXME: `STATUS_DLL_NOT_FOUND` testing macros on CI. +# +case "$target" in + *windows-gnu) extra_flags="$extra_flags --exclude libm-macros" ;; +esac + +if [ "$(uname -a)" = "Linux" ]; then + # also run the reference tests when we can. requires a Linux host. + extra_flags="$extra_flags --features libm-test/test-musl-serialized" +fi + +if [ "${BUILD_ONLY:-}" = "1" ]; then + cmd="cargo build --target $target --package libm" + $cmd + $cmd --features 'unstable' -# stable by default -$cmd -$cmd --release + echo "can't run tests on $target" +else + cmd="cargo test --all --target $target $extra_flags" -# unstable with a feature -$cmd --features 'unstable' -$cmd --release --features 'unstable' + # stable by default + $cmd + $cmd --release -# also run the reference tests -$cmd --features 'unstable libm-test/test-musl-serialized' -$cmd --release --features 'unstable libm-test/test-musl-serialized' + # unstable with a feature + $cmd --features 'unstable' + $cmd --release --features 'unstable' +fi From bf757e3a7b35473ca3affdff0ab2b8e7e422b3fe Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Oct 2024 13:22:57 -0500 Subject: [PATCH 1396/4206] Mark libm-macros and musl-math-sys as publish=false --- library/compiler-builtins/libm/crates/libm-macros/Cargo.toml | 1 + library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml index 9d2b08e2d78f2..3da9d45a2b9db 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml @@ -2,6 +2,7 @@ name = "libm-macros" version = "0.1.0" edition = "2021" +publish = false [lib] proc-macro = true diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml index 449ce4f3ed1fc..7f6272d79ed96 100644 --- a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml +++ b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml @@ -2,6 +2,7 @@ name = "musl-math-sys" version = "0.1.0" edition = "2021" +publish = false [dependencies] From ebb2dc11d854f048537bbc41fb11448e4ce27481 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Oct 2024 13:30:39 -0500 Subject: [PATCH 1397/4206] Reduce the number of iterations on emulated aarch64 Linux CI for aarch64 Linux is significantly slower than the others. Adjust how iteration selection is done to better handle this case, which also simplifies things. Also set the `EMULATED` environment variable in Docker to be more accurate, and reindents run-docker.sh. --- .../compiler-builtins/libm/ci/run-docker.sh | 48 +++++++++++-------- .../libm/crates/libm-test/src/gen/random.rs | 26 ++++------ .../libm/crates/libm-test/src/lib.rs | 9 ++++ 3 files changed, 46 insertions(+), 37 deletions(-) diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh index 2e09dd41a5748..a040126df8459 100755 --- a/library/compiler-builtins/libm/ci/run-docker.sh +++ b/library/compiler-builtins/libm/ci/run-docker.sh @@ -5,39 +5,49 @@ set -euxo pipefail +host_arch="$(uname -m | sed 's/arm64/aarch64/')" + run() { local target=$1 echo "testing target: $target" + target_arch="$(echo "$target" | cut -d'-' -f1)" + + emulated="" + if [ "$target_arch" != "$host_arch" ]; then + emulated=1 + echo "target is emulated" + fi + # This directory needs to exist before calling docker, otherwise docker will create it but it # will be owned by root mkdir -p target docker build -t "$target" "ci/docker/$target" docker run \ - --rm \ - --user "$(id -u):$(id -g)" \ - -e RUSTFLAGS \ - -e CARGO_HOME=/cargo \ - -e CARGO_TARGET_DIR=/target \ - -e EMULATED=1 \ - -v "${HOME}/.cargo:/cargo" \ - -v "$(pwd)/target:/target" \ - -v "$(pwd):/checkout:ro" \ - -v "$(rustc --print sysroot):/rust:ro" \ - --init \ - -w /checkout \ - "$target" \ - sh -c "HOME=/tmp PATH=\$PATH:/rust/bin exec ci/run.sh $target" + --rm \ + --user "$(id -u):$(id -g)" \ + -e RUSTFLAGS \ + -e CARGO_HOME=/cargo \ + -e CARGO_TARGET_DIR=/target \ + -e "EMULATED=$emulated" \ + -v "${HOME}/.cargo:/cargo" \ + -v "$(pwd)/target:/target" \ + -v "$(pwd):/checkout:ro" \ + -v "$(rustc --print sysroot):/rust:ro" \ + --init \ + -w /checkout \ + "$target" \ + sh -c "HOME=/tmp PATH=\$PATH:/rust/bin exec ci/run.sh $target" } if [ -z "$1" ]; then - echo "running tests for all targets" + echo "running tests for all targets" - for d in ci/docker/*; do - run $d - done + for d in ci/docker/*; do + run $d + done else - run $1 + run $1 fi diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index e5964319569d7..601ef4f1d46da 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -13,31 +13,21 @@ const SEED: [u8; 32] = *b"3.141592653589793238462643383279"; /// Number of tests to run. const NTESTS: usize = { - let ntests = if cfg!(optimizations_enabled) { - if cfg!(target_arch = "x86_64") || cfg!(target_arch = "aarch64") { - 5_000_000 - } else if !cfg!(target_pointer_width = "64") + if cfg!(optimizations_enabled) { + if crate::emulated() + || !cfg!(target_pointer_width = "64") || cfg!(all(target_arch = "x86_64", target_vendor = "apple")) - || option_env!("EMULATED").is_some() - && cfg!(any(target_arch = "aarch64", target_arch = "powerpc64")) { - // Tests are pretty slow on: - // - Non-64-bit targets - // - Emulated ppc - // - Emulated aarch64 - // - x86 MacOS - // So reduce the number of iterations + // Tests are pretty slow on non-64-bit targets, x86 MacOS, and targets that run + // in QEMU. 100_000 } else { - // Most everything else gets tested in docker and works okay, but we still - // don't need 20 minutes of tests. - 1_000_000 + 5_000_000 } } else { + // Without optimizations just run a quick check 800 - }; - - ntests + } }; /// Tested inputs. diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 3baf77524f0ea..2abe7f605ea61 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -62,3 +62,12 @@ pub fn canonical_name(name: &str) -> &str { .unwrap_or(name), } } + +/// True if `EMULATED` is set and nonempty. Used to determine how many iterations to run. +pub const fn emulated() -> bool { + match option_env!("EMULATED") { + Some(s) if s.is_empty() => false, + None => false, + Some(_) => true, + } +} From 0109445d5967f59d48f8e530acc36c29cb1912c1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Oct 2024 15:07:34 -0500 Subject: [PATCH 1398/4206] Enable caching on all CI jobs that build the crate (#341) --- library/compiler-builtins/libm/.github/workflows/main.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index a2c7795261d64..15eba6e890519 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -108,6 +108,7 @@ jobs: - name: Install Rust run: rustup update nightly --no-self-update && rustup default nightly - run: rustup target add wasm32-unknown-unknown + - uses: Swatinem/rust-cache@v2 - run: cargo build --target wasm32-unknown-unknown builtins: @@ -117,6 +118,7 @@ jobs: - uses: actions/checkout@master - name: Install Rust run: rustup update nightly --no-self-update && rustup default nightly + - uses: Swatinem/rust-cache@v2 - run: cargo build -p cb benchmarks: @@ -126,6 +128,7 @@ jobs: - uses: actions/checkout@master - name: Install Rust run: rustup update nightly --no-self-update && rustup default nightly + - uses: Swatinem/rust-cache@v2 - name: Download musl source run: ./ci/download-musl.sh - run: cargo bench --all @@ -143,6 +146,7 @@ jobs: echo "MSRV=$msrv" >> "$GITHUB_ENV" - name: Install Rust run: rustup update "$MSRV" --no-self-update && rustup default "$MSRV" + - uses: Swatinem/rust-cache@v2 - run: cargo build -p libm rustfmt: From c14fac725a16d121047dcd1d2bd97e8e28b963c6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 20:08:07 +0000 Subject: [PATCH 1399/4206] chore: release v0.2.11 --- library/compiler-builtins/libm/CHANGELOG.md | 13 +++++++++++++ library/compiler-builtins/libm/Cargo.toml | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index 317dfafc00797..4e5acb899d2b7 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -8,6 +8,19 @@ and this project adheres to ## [Unreleased] +## [0.2.11](https://github.com/rust-lang/libm/compare/libm-v0.2.10...libm-v0.2.11) - 2024-10-28 + +### Fixed + +- fix type of constants in ported sincosf ([#331](https://github.com/rust-lang/libm/pull/331)) + +### Other + +- Disable a unit test that is failing on i586 +- Add a procedural macro for expanding all function signatures +- Introduce `musl-math-sys` for bindings to musl math symbols +- Add basic docstrings to some functions ([#337](https://github.com/rust-lang/libm/pull/337)) + ## [0.2.10](https://github.com/rust-lang/libm/compare/libm-v0.2.9...libm-v0.2.10) - 2024-10-28 ### Other diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 72b6dcd5e8e19..aa6c08ddb0119 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT AND (MIT OR Apache-2.0)" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/libm" -version = "0.2.10" +version = "0.2.11" edition = "2021" exclude = ["/ci/", "/.github/workflows/"] rust-version = "1.63" From 66f8906862fba51ffde9d9a73b527a29402bce93 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Oct 2024 17:44:02 -0500 Subject: [PATCH 1400/4206] Move the existing "unstable" feature to "unstable-intrinsics" Currently there is a single feature called "unstable" that is used to control whether intrinsics may be called. In anticipation of adding other unstable features that we will want to control separately, create a new feature called "unstable-intrinsics" that is enabled by "unstable". Then move everything gated by "unstable" to "unstable-intrinsics". --- library/compiler-builtins/libm/Cargo.toml | 5 ++++- library/compiler-builtins/libm/ci/run.sh | 6 +++--- .../libm/crates/compiler-builtins-smoke-test/Cargo.toml | 2 ++ library/compiler-builtins/libm/src/lib.rs | 4 ++-- library/compiler-builtins/libm/src/math/mod.rs | 8 +++++--- 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index aa6c08ddb0119..de450468a472b 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -18,7 +18,10 @@ default = [] # This tells the compiler to assume that a Nightly toolchain is being used and # that it should activate any useful Nightly things accordingly. -unstable = [] +unstable = ["unstable-intrinsics"] + +# Enable calls to functions in `core::intrinsics` +unstable-intrinsics = [] # Used to prevent using any intrinsics or arch-specific code. force-soft-floats = [] diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index f61fff8433e3a..f1ca4b0cb109e 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -49,7 +49,7 @@ fi if [ "${BUILD_ONLY:-}" = "1" ]; then cmd="cargo build --target $target --package libm" $cmd - $cmd --features 'unstable' + $cmd --features "unstable-intrinsics" echo "can't run tests on $target" else @@ -60,6 +60,6 @@ else $cmd --release # unstable with a feature - $cmd --features 'unstable' - $cmd --release --features 'unstable' + $cmd --features "unstable-intrinsics" + $cmd --release --features "unstable-intrinsics" fi diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index 8d084ee341e90..2aa7c83718b44 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -10,6 +10,8 @@ test = false bench = false [features] +# Duplicated from libm's Cargo.toml unstable = [] +unstable-intrinsics = [] checked = [] force-soft-floats = [] diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 6d95fa1737b35..1305d35abf7de 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -1,7 +1,7 @@ //! libm in pure Rust #![no_std] -#![cfg_attr(feature = "unstable", allow(internal_features))] -#![cfg_attr(feature = "unstable", feature(core_intrinsics))] +#![cfg_attr(feature = "unstable-intrinsics", allow(internal_features))] +#![cfg_attr(feature = "unstable-intrinsics", feature(core_intrinsics))] #![allow(clippy::assign_op_pattern)] #![allow(clippy::deprecated_cfg_attr)] #![allow(clippy::eq_op)] diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 85c9fc5bf1566..17b9e6b4cf673 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -60,14 +60,14 @@ macro_rules! i { // the time of this writing this is only used in a few places, and once // rust-lang/rust#72751 is fixed then this macro will no longer be necessary and // the native `/` operator can be used and panics won't be codegen'd. -#[cfg(any(debug_assertions, not(feature = "unstable")))] +#[cfg(any(debug_assertions, not(feature = "unstable-intrinsics")))] macro_rules! div { ($a:expr, $b:expr) => { $a / $b }; } -#[cfg(all(not(debug_assertions), feature = "unstable"))] +#[cfg(all(not(debug_assertions), feature = "unstable-intrinsics"))] macro_rules! div { ($a:expr, $b:expr) => { unsafe { core::intrinsics::unchecked_div($a, $b) } @@ -76,7 +76,9 @@ macro_rules! div { macro_rules! llvm_intrinsically_optimized { (#[cfg($($clause:tt)*)] $e:expr) => { - #[cfg(all(feature = "unstable", not(feature = "force-soft-floats"), $($clause)*))] + #[cfg(all( + feature = "unstable-intrinsics", not(feature = "force-soft-floats"), $($clause)* + ))] { if true { // thwart the dead code lint $e From e6f7053c2e2d7fe2de0cf5582bfd529c2cd3b5a7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Oct 2024 18:15:19 -0500 Subject: [PATCH 1401/4206] Replace `feature = "unstable-intrinsics"` with `intrinsics_enabled` We currently have a non-additive feature, "force-soft-floats", and we will need to gain another "no-f16-f128". This makes `cfg` usage in code somewhat confusing and redundant. Use `build.rs` to figure out if "unstable-intrinsics" is enabled while "force-soft-floats" is not enabled and if so, emit a cfg `intrinsics_enabled`. This is cleaner to use and should make adding more features easier to reason about. Also use this as an opportunity to eliminate the build.rs from the compiler-builtins test crate, replaced with the `[lints]` table in Cargo.toml. --- library/compiler-builtins/libm/Cargo.toml | 5 +++++ library/compiler-builtins/libm/build.rs | 15 ++++++++++++++- library/compiler-builtins/libm/ci/run.sh | 4 ++++ .../compiler-builtins-smoke-test/Cargo.toml | 6 ++++++ .../crates/compiler-builtins-smoke-test/build.rs | 3 --- library/compiler-builtins/libm/src/lib.rs | 4 ++-- library/compiler-builtins/libm/src/math/mod.rs | 8 +++----- 7 files changed, 34 insertions(+), 11 deletions(-) delete mode 100644 library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index de450468a472b..5e4565556b021 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -24,6 +24,11 @@ unstable = ["unstable-intrinsics"] unstable-intrinsics = [] # 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. force-soft-floats = [] [workspace] diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index b683557e4af8e..adb5214073084 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -3,7 +3,6 @@ use std::env; fn main() { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rustc-check-cfg=cfg(assert_no_panic)"); - println!("cargo:rustc-check-cfg=cfg(feature, values(\"unstable\"))"); println!("cargo:rustc-check-cfg=cfg(feature, values(\"checked\"))"); @@ -14,4 +13,18 @@ fn main() { println!("cargo:rustc-cfg=assert_no_panic"); } } + + configure_intrinsics(); +} + +/// Simplify the feature logic for enabling intrinsics so code only needs to use +/// `cfg(intrinsics_enabled)`. +fn configure_intrinsics() { + 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"); + } } diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index f1ca4b0cb109e..d3fc4ce240dd2 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -46,6 +46,10 @@ if [ "$(uname -a)" = "Linux" ]; then extra_flags="$extra_flags --features libm-test/test-musl-serialized" fi +# Make sure we can build with overriding features. We test the indibidual +# features it controls separately. +cargo check --features "force-soft-floats" + if [ "${BUILD_ONLY:-}" = "1" ]; then cmd="cargo build --target $target --package libm" $cmd diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index 2aa7c83718b44..2a6c62961e361 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -15,3 +15,9 @@ unstable = [] unstable-intrinsics = [] checked = [] force-soft-floats = [] + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = [ + "cfg(assert_no_panic)", + "cfg(intrinsics_enabled)", +] } diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs deleted file mode 100644 index 27d4a0e89d0ba..0000000000000 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("cargo::rustc-check-cfg=cfg(assert_no_panic)"); -} diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 1305d35abf7de..98ac55988d0ad 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -1,7 +1,7 @@ //! libm in pure Rust #![no_std] -#![cfg_attr(feature = "unstable-intrinsics", allow(internal_features))] -#![cfg_attr(feature = "unstable-intrinsics", feature(core_intrinsics))] +#![cfg_attr(intrinsics_enabled, allow(internal_features))] +#![cfg_attr(intrinsics_enabled, feature(core_intrinsics))] #![allow(clippy::assign_op_pattern)] #![allow(clippy::deprecated_cfg_attr)] #![allow(clippy::eq_op)] diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 17b9e6b4cf673..9baa57fc8825b 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -60,14 +60,14 @@ macro_rules! i { // the time of this writing this is only used in a few places, and once // rust-lang/rust#72751 is fixed then this macro will no longer be necessary and // the native `/` operator can be used and panics won't be codegen'd. -#[cfg(any(debug_assertions, not(feature = "unstable-intrinsics")))] +#[cfg(any(debug_assertions, not(intrinsics_enabled)))] macro_rules! div { ($a:expr, $b:expr) => { $a / $b }; } -#[cfg(all(not(debug_assertions), feature = "unstable-intrinsics"))] +#[cfg(all(not(debug_assertions), intrinsics_enabled))] macro_rules! div { ($a:expr, $b:expr) => { unsafe { core::intrinsics::unchecked_div($a, $b) } @@ -76,9 +76,7 @@ macro_rules! div { macro_rules! llvm_intrinsically_optimized { (#[cfg($($clause:tt)*)] $e:expr) => { - #[cfg(all( - feature = "unstable-intrinsics", not(feature = "force-soft-floats"), $($clause)* - ))] + #[cfg(all(intrinsics_enabled, not(feature = "force-soft-floats"), $($clause)*))] { if true { // thwart the dead code lint $e From 1b7346bf5fb63c4c74ad492e7a566b01feec6f56 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Oct 2024 19:30:04 -0500 Subject: [PATCH 1402/4206] Introduce `math::arch::intrinsics` This module provides implementations of basic functions that defer to LLVM for what to do, rather than either using a builtin operation or calling another function in this library. `math::arch` will become the home of anything architecture-specific in the future. --- .../libm/src/math/arch/intrinsics.rs | 52 +++++++++++++++++++ .../libm/src/math/arch/mod.rs | 9 ++++ .../compiler-builtins/libm/src/math/mod.rs | 1 + 3 files changed, 62 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/arch/intrinsics.rs create mode 100644 library/compiler-builtins/libm/src/math/arch/mod.rs diff --git a/library/compiler-builtins/libm/src/math/arch/intrinsics.rs b/library/compiler-builtins/libm/src/math/arch/intrinsics.rs new file mode 100644 index 0000000000000..1cf9291f4c75e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/intrinsics.rs @@ -0,0 +1,52 @@ +// Config is needed for times when this module is available but we don't call everything +#![allow(dead_code)] + +pub fn ceil(x: f64) -> f64 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::ceilf64(x) } +} + +pub fn ceilf(x: f32) -> f32 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::ceilf32(x) } +} + +pub fn fabs(x: f64) -> f64 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::fabsf64(x) } +} + +pub fn fabsf(x: f32) -> f32 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::fabsf32(x) } +} + +pub fn floor(x: f64) -> f64 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::floorf64(x) } +} + +pub fn floorf(x: f32) -> f32 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::floorf32(x) } +} + +pub fn sqrt(x: f64) -> f64 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::sqrtf64(x) } +} + +pub fn sqrtf(x: f32) -> f32 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::sqrtf32(x) } +} + +pub fn trunc(x: f64) -> f64 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::truncf64(x) } +} + +pub fn truncf(x: f32) -> f32 { + // SAFETY: safe intrinsic with no preconditions + unsafe { core::intrinsics::truncf32(x) } +} diff --git a/library/compiler-builtins/libm/src/math/arch/mod.rs b/library/compiler-builtins/libm/src/math/arch/mod.rs new file mode 100644 index 0000000000000..a4bc218b743d9 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/mod.rs @@ -0,0 +1,9 @@ +//! Architecture-specific routines and operations. +//! +//! LLVM will already optimize calls to some of these in cases that there are hardware +//! instructions. Providing an implementation here just ensures that the faster implementation +//! is used when calling the function directly. This helps anyone who uses `libm` directly, as +//! well as improving things when these routines are called as part of other implementations. + +#[cfg(intrinsics_enabled)] +pub mod intrinsics; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 9baa57fc8825b..e3e6846d377f9 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -302,6 +302,7 @@ pub use self::trunc::trunc; pub use self::truncf::truncf; // Private modules +mod arch; mod expo2; mod fenv; mod k_cos; From d54896343cab56e2f4c9866e54e7954c9c70d753 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 02:56:22 -0500 Subject: [PATCH 1403/4206] Introduce a `select_implementation` macro Currently there is a macro called `llvm_intrinsically_optimized` that uses an intrinsic rather than the function implementation if the configuration is correct. Add a new macro `select_implementation` that is somewhat cleaner to use. In the future, we can update this macro with more fields to specify other implementations that may be selected, such as something architecture-specific or e.g. using a generic implementation for `f32` routines, rather than those that convert to `f64`. This introduces a `macros` module within `math/support`. We will be able to move more things here later. --- .../compiler-builtins/libm/src/math/mod.rs | 63 ++++++++++--------- .../libm/src/math/support/macros.rs | 34 ++++++++++ .../libm/src/math/support/mod.rs | 2 + 3 files changed, 69 insertions(+), 30 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/support/macros.rs create mode 100644 library/compiler-builtins/libm/src/math/support/mod.rs diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index e3e6846d377f9..a7e16bfc865cc 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -74,6 +74,7 @@ macro_rules! div { }; } +// FIXME: phase this out, to be replaced by the more flexible `select_implementation` macro_rules! llvm_intrinsically_optimized { (#[cfg($($clause:tt)*)] $e:expr) => { #[cfg(all(intrinsics_enabled, not(feature = "force-soft-floats"), $($clause)*))] @@ -85,6 +86,38 @@ macro_rules! llvm_intrinsically_optimized { }; } +// Private modules +#[macro_use] +mod support; +mod arch; +mod expo2; +mod fenv; +mod k_cos; +mod k_cosf; +mod k_expo2; +mod k_expo2f; +mod k_sin; +mod k_sinf; +mod k_tan; +mod k_tanf; +mod rem_pio2; +mod rem_pio2_large; +mod rem_pio2f; + +// Private re-imports +use self::expo2::expo2; +use self::k_cos::k_cos; +use self::k_cosf::k_cosf; +use self::k_expo2::k_expo2; +use self::k_expo2f::k_expo2f; +use self::k_sin::k_sin; +use self::k_sinf::k_sinf; +use self::k_tan::k_tan; +use self::k_tanf::k_tanf; +use self::rem_pio2::rem_pio2; +use self::rem_pio2_large::rem_pio2_large; +use self::rem_pio2f::rem_pio2f; + // Public modules mod acos; mod acosf; @@ -301,36 +334,6 @@ pub use self::tgammaf::tgammaf; pub use self::trunc::trunc; pub use self::truncf::truncf; -// Private modules -mod arch; -mod expo2; -mod fenv; -mod k_cos; -mod k_cosf; -mod k_expo2; -mod k_expo2f; -mod k_sin; -mod k_sinf; -mod k_tan; -mod k_tanf; -mod rem_pio2; -mod rem_pio2_large; -mod rem_pio2f; - -// Private re-imports -use self::expo2::expo2; -use self::k_cos::k_cos; -use self::k_cosf::k_cosf; -use self::k_expo2::k_expo2; -use self::k_expo2f::k_expo2f; -use self::k_sin::k_sin; -use self::k_sinf::k_sinf; -use self::k_tan::k_tan; -use self::k_tanf::k_tanf; -use self::rem_pio2::rem_pio2; -use self::rem_pio2_large::rem_pio2_large; -use self::rem_pio2f::rem_pio2f; - #[inline] fn get_high_word(x: f64) -> u32 { (x.to_bits() >> 32) as u32 diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs new file mode 100644 index 0000000000000..6bc75837a3494 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -0,0 +1,34 @@ +/// Choose among using an intrinsic (if available) and falling back to the default function body. +/// Returns directly if the intrinsic version is used, otherwise continues to the rest of the +/// function. +/// +/// Use this if the intrinsic is likely to be more performant on the platform(s) specified +/// in `intrinsic_available`. +/// +/// The `cfg` used here is controlled by `build.rs` so the passed meta does not need to account +/// for e.g. the `unstable-intrinsics` or `force-soft-float` features. +macro_rules! select_implementation { + ( + name: $fname:ident, + // Configuration meta for when to call intrinsics and let LLVM figure it out + $( use_intrinsic: $use_intrinsic:meta, )? + args: $($arg:ident),+ , + ) => { + // FIXME: these use paths that are a pretty fragile (`super`). We should figure out + // something better w.r.t. how this is vendored into compiler-builtins. + + // Never use intrinsics if we are forcing soft floats, and only enable with the + // `unstable-intrinsics` feature. + #[cfg(intrinsics_enabled)] + select_implementation! { + @cfg $( $use_intrinsic )?; + if true { + return super::arch::intrinsics::$fname( $($arg),+ ); + } + } + }; + + // Coalesce helper to construct an expression only if a config is provided + (@cfg ; $ex:expr) => { }; + (@cfg $provided:meta; $ex:expr) => { #[cfg($provided)] $ex }; +} diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs new file mode 100644 index 0000000000000..10532f0d115a8 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -0,0 +1,2 @@ +#[macro_use] +pub mod macros; From 60e7e3b338c3aea7b615073d712c9c568e2a0e9a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Oct 2024 19:38:19 -0500 Subject: [PATCH 1404/4206] Make use of `select_implementation` Replace all uses of `llvm_intrinsically` with select_implementation`. --- library/compiler-builtins/libm/src/math/ceil.rs | 12 +++++------- library/compiler-builtins/libm/src/math/ceilf.rs | 12 +++++------- library/compiler-builtins/libm/src/math/fabs.rs | 12 +++++------- library/compiler-builtins/libm/src/math/fabsf.rs | 12 +++++------- library/compiler-builtins/libm/src/math/floor.rs | 12 +++++------- .../compiler-builtins/libm/src/math/floorf.rs | 12 +++++------- library/compiler-builtins/libm/src/math/mod.rs | 12 ------------ library/compiler-builtins/libm/src/math/sqrt.rs | 16 +++++----------- library/compiler-builtins/libm/src/math/sqrtf.rs | 16 +++++----------- library/compiler-builtins/libm/src/math/trunc.rs | 12 +++++------- .../compiler-builtins/libm/src/math/truncf.rs | 12 +++++------- 11 files changed, 50 insertions(+), 90 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index 1593fdaffcee7..0da01b4d0b690 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -8,14 +8,12 @@ const TOINT: f64 = 1. / f64::EPSILON; /// Finds the nearest integer greater than or equal to `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ceil(x: f64) -> f64 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f64.ceil` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return unsafe { ::core::intrinsics::ceilf64(x) } - } + select_implementation! { + name: ceil, + use_intrinsic: target_arch = "wasm32", + args: x, } + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] { //use an alternative implementation on x86, because the diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index bf9ba12279cf0..0da384350aee8 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -5,14 +5,12 @@ use core::f32; /// Finds the nearest integer greater than or equal to `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ceilf(x: f32) -> f32 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f32.ceil` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return unsafe { ::core::intrinsics::ceilf32(x) } - } + select_implementation! { + name: ceilf, + use_intrinsic: target_arch = "wasm32", + args: x, } + let mut ui = x.to_bits(); let e = (((ui >> 23) & 0xff).wrapping_sub(0x7f)) as i32; diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index 3b0628aa63a74..8d3ea2fd64795 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -5,14 +5,12 @@ use core::u64; /// by direct manipulation of the bit representation of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fabs(x: f64) -> f64 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f64.abs` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return unsafe { ::core::intrinsics::fabsf64(x) } - } + select_implementation! { + name: fabs, + use_intrinsic: target_arch = "wasm32", + args: x, } + f64::from_bits(x.to_bits() & (u64::MAX / 2)) } diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index f81c8ca44236d..1dac6389d8f44 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -3,14 +3,12 @@ /// by direct manipulation of the bit representation of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fabsf(x: f32) -> f32 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f32.abs` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return unsafe { ::core::intrinsics::fabsf32(x) } - } + select_implementation! { + name: fabsf, + use_intrinsic: target_arch = "wasm32", + args: x, } + f32::from_bits(x.to_bits() & 0x7fffffff) } diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index e8fb21e5884bc..2b9955ebae349 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -8,14 +8,12 @@ const TOINT: f64 = 1. / f64::EPSILON; /// Finds the nearest integer less than or equal to `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn floor(x: f64) -> f64 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f64.floor` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return unsafe { ::core::intrinsics::floorf64(x) } - } + select_implementation! { + name: floor, + use_intrinsic: target_arch = "wasm32", + args: x, } + #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] { //use an alternative implementation on x86, because the diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index f66cab74fdcfd..4f38cb15b7d83 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -5,14 +5,12 @@ use core::f32; /// Finds the nearest integer less than or equal to `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn floorf(x: f32) -> f32 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f32.floor` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return unsafe { ::core::intrinsics::floorf32(x) } - } + select_implementation! { + name: floorf, + use_intrinsic: target_arch = "wasm32", + args: x, } + let mut ui = x.to_bits(); let e = (((ui >> 23) as i32) & 0xff) - 0x7f; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index a7e16bfc865cc..393bc51509387 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -74,18 +74,6 @@ macro_rules! div { }; } -// FIXME: phase this out, to be replaced by the more flexible `select_implementation` -macro_rules! llvm_intrinsically_optimized { - (#[cfg($($clause:tt)*)] $e:expr) => { - #[cfg(all(intrinsics_enabled, not(feature = "force-soft-floats"), $($clause)*))] - { - if true { // thwart the dead code lint - $e - } - } - }; -} - // Private modules #[macro_use] mod support; diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index e2907384dcdbe..2e856100f7ddd 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -81,18 +81,12 @@ use core::f64; /// The square root of `x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrt(x: f64) -> f64 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f64.sqrt` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return if x < 0.0 { - f64::NAN - } else { - unsafe { ::core::intrinsics::sqrtf64(x) } - } - } + select_implementation! { + name: sqrt, + use_intrinsic: target_arch = "wasm32", + args: x, } + #[cfg(all(target_feature = "sse2", not(feature = "force-soft-floats")))] { // Note: This path is unlikely since LLVM will usually have already diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index a738fc0b663a7..b2996b350cb4a 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -16,18 +16,12 @@ /// The square root of `x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrtf(x: f32) -> f32 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f32.sqrt` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return if x < 0.0 { - ::core::f32::NAN - } else { - unsafe { ::core::intrinsics::sqrtf32(x) } - } - } + select_implementation! { + name: sqrtf, + use_intrinsic: target_arch = "wasm32", + args: x, } + #[cfg(all(target_feature = "sse", not(feature = "force-soft-floats")))] { // Note: This path is unlikely since LLVM will usually have already diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs index f7892a2c55367..6961bb950600e 100644 --- a/library/compiler-builtins/libm/src/math/trunc.rs +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -2,14 +2,12 @@ use core::f64; #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn trunc(x: f64) -> f64 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f64.trunc` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return unsafe { ::core::intrinsics::truncf64(x) } - } + select_implementation! { + name: trunc, + use_intrinsic: target_arch = "wasm32", + args: x, } + let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 let mut i: u64 = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs index 20d5b73bd675e..8270c8eb392d8 100644 --- a/library/compiler-builtins/libm/src/math/truncf.rs +++ b/library/compiler-builtins/libm/src/math/truncf.rs @@ -2,14 +2,12 @@ use core::f32; #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn truncf(x: f32) -> f32 { - // On wasm32 we know that LLVM's intrinsic will compile to an optimized - // `f32.trunc` native instruction, so we can leverage this for both code size - // and speed. - llvm_intrinsically_optimized! { - #[cfg(target_arch = "wasm32")] { - return unsafe { ::core::intrinsics::truncf32(x) } - } + select_implementation! { + name: truncf, + use_intrinsic: target_arch = "wasm32", + args: x, } + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 let mut i: u32 = x.to_bits(); From 3502d8eff6a26c67d5564e3012434d2f54248ff9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Oct 2024 20:45:12 -0500 Subject: [PATCH 1405/4206] Combine the WASM CI job with the others There isn't any reason to be distinct here, and it would be better to test with all feature configurations in run.sh anyway. --- .../libm/.github/workflows/main.yml | 23 ++++++------------- library/compiler-builtins/libm/ci/run.sh | 2 +- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 15eba6e890519..cc0d23ffc2f1e 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -9,7 +9,7 @@ env: jobs: test: - name: Docker + name: Build and test timeout-minutes: 20 strategy: fail-fast: false @@ -52,6 +52,9 @@ jobs: os: ubuntu-latest - target: x86_64-apple-darwin os: macos-13 + - target: wasm32-unknown-unknown + os: ubuntu-latest + build_only: 1 - target: i686-pc-windows-msvc os: windows-latest - target: x86_64-pc-windows-msvc @@ -89,30 +92,19 @@ jobs: # Non-linux tests just use our raw script - name: Run locally - if: matrix.os != 'ubuntu-latest' + if: matrix.os != 'ubuntu-latest' || contains(matrix.target, 'wasm') shell: bash run: ./ci/run.sh ${{ matrix.target }} # Otherwise we use our docker containers to run builds - name: Run in Docker - if: matrix.os == 'ubuntu-latest' + if: matrix.os == 'ubuntu-latest' && !contains(matrix.target, 'wasm') run: | rustup target add x86_64-unknown-linux-musl cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} - wasm: - name: WebAssembly - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - name: Install Rust - run: rustup update nightly --no-self-update && rustup default nightly - - run: rustup target add wasm32-unknown-unknown - - uses: Swatinem/rust-cache@v2 - - run: cargo build --target wasm32-unknown-unknown - builtins: - name: "The compiler-builtins crate works" + name: Check use with compiler-builtins runs-on: ubuntu-latest steps: - uses: actions/checkout@master @@ -164,7 +156,6 @@ jobs: success: needs: - test - - wasm - builtins - benchmarks - msrv diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index d3fc4ce240dd2..30265e513a2ac 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -55,7 +55,7 @@ if [ "${BUILD_ONLY:-}" = "1" ]; then $cmd $cmd --features "unstable-intrinsics" - echo "can't run tests on $target" + echo "can't run tests on $target; skipping" else cmd="cargo test --all --target $target $extra_flags" From c09e58be46e9fd2b2961c155d40cb04b04866a26 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Oct 2024 17:38:57 -0500 Subject: [PATCH 1406/4206] Create interfaces for testing against MPFR Add a way to call MPFR versions of functions in a predictable way, using the `MpOp` trait. Everything new here is guarded by the feature `test-multiprecision` since MPFR cannot easily build on Windows or any cross compiled targets. --- .../libm/crates/libm-test/Cargo.toml | 3 + .../libm/crates/libm-test/src/lib.rs | 2 + .../libm/crates/libm-test/src/mpfloat.rs | 389 ++++++++++++++++++ 3 files changed, 394 insertions(+) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 703524bcd708a..72ac57232b3d1 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -10,18 +10,21 @@ default = [] # Generate tests which are random inputs and the outputs are calculated with # musl libc. test-musl-serialized = ["rand"] +test-multiprecision = ["dep:az", "dep:rug"] # Build our own musl for testing and benchmarks build-musl = ["dep:musl-math-sys"] [dependencies] anyhow = "1.0.90" +az = { version = "1.2.1", optional = true } libm = { path = "../.." } libm-macros = { path = "../libm-macros" } musl-math-sys = { path = "../musl-math-sys", optional = true } paste = "1.0.15" rand = "0.8.5" rand_chacha = "0.3.1" +rug = { version = "1.26.1", optional = true, default-features = false, features = ["float", "std"] } [target.'cfg(target_family = "wasm")'.dependencies] # Enable randomness on WASM diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 2abe7f605ea61..64343e00d5dbb 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -1,4 +1,6 @@ pub mod gen; +#[cfg(feature = "test-multiprecision")] +pub mod mpfloat; mod num_traits; mod special_case; mod test_traits; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs new file mode 100644 index 0000000000000..db072780aeb63 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -0,0 +1,389 @@ +//! Interfaces needed to support testing with multi-precision floating point numbers. +//! +//! Within this module, the macros create a submodule for each `libm` function. These contain +//! a struct named `Operation` that implements [`MpOp`]. + +use std::cmp::Ordering; + +use az::Az; +use rug::Assign; +pub use rug::Float as MpFloat; +use rug::float::Round::Nearest; +use rug::ops::{PowAssignRound, RemAssignRound}; + +use crate::Float; + +/// Create a multiple-precision float with the correct number of bits for a concrete float type. +fn new_mpfloat() -> MpFloat { + MpFloat::new(F::SIGNIFICAND_BITS + 1) +} + +/// Set subnormal emulation and convert to a concrete float type. +fn prep_retval(mp: &mut MpFloat, ord: Ordering) -> F +where + for<'a> &'a MpFloat: az::Cast, +{ + mp.subnormalize_ieee_round(ord, Nearest); + (&*mp).az::() +} + +/// Structures that represent a float operation. +/// +/// The struct itself should hold any context that can be reused among calls to `run` (allocated +/// `MpFloat`s). +pub trait MpOp { + /// Inputs to the operation (concrete float types). + type Input; + + /// Outputs from the operation (concrete float types). + type Output; + + /// Create a new instance. + fn new() -> Self; + + /// Perform the operation. + /// + /// Usually this means assigning inputs to cached floats, performing the operation, applying + /// subnormal approximation, and converting the result back to concrete values. + fn run(&mut self, input: Self::Input) -> Self::Output; +} + +/// Implement `MpOp` for functions with a single return value. +macro_rules! impl_mp_op { + // Matcher for unary functions + ( + fn_name: $fn_name:ident, + CFn: $CFn:ty, + CArgs: $CArgs:ty, + CRet: $CRet:ty, + RustFn: fn($fty:ty,) -> $_ret:ty, + RustArgs: $RustArgs:ty, + RustRet: $RustRet:ty, + fn_extra: $fn_name_normalized:expr, + ) => { + paste::paste! { + pub mod $fn_name { + use super::*; + pub struct Operation(MpFloat); + + impl MpOp for Operation { + type Input = $RustArgs; + type Output = $RustRet; + + fn new() -> Self { + Self(new_mpfloat::<$fty>()) + } + + fn run(&mut self, input: Self::Input) -> Self::Output { + self.0.assign(input.0); + let ord = self.0.[< $fn_name_normalized _round >](Nearest); + prep_retval::(&mut self.0, ord) + } + } + } + } + }; + // Matcher for binary functions + ( + fn_name: $fn_name:ident, + CFn: $CFn:ty, + CArgs: $CArgs:ty, + CRet: $CRet:ty, + RustFn: fn($fty:ty, $_fty2:ty,) -> $_ret:ty, + RustArgs: $RustArgs:ty, + RustRet: $RustRet:ty, + fn_extra: $fn_name_normalized:expr, + ) => { + paste::paste! { + pub mod $fn_name { + use super::*; + pub struct Operation(MpFloat, MpFloat); + + impl MpOp for Operation { + type Input = $RustArgs; + type Output = $RustRet; + + fn new() -> Self { + Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) + } + + fn run(&mut self, input: Self::Input) -> Self::Output { + self.0.assign(input.0); + self.1.assign(input.1); + let ord = self.0.[< $fn_name_normalized _round >](&self.1, Nearest); + prep_retval::(&mut self.0, ord) + } + } + } + } + }; + // Matcher for ternary functions + ( + fn_name: $fn_name:ident, + CFn: $CFn:ty, + CArgs: $CArgs:ty, + CRet: $CRet:ty, + RustFn: fn($fty:ty, $_fty2:ty, $_fty3:ty,) -> $_ret:ty, + RustArgs: $RustArgs:ty, + RustRet: $RustRet:ty, + fn_extra: $fn_name_normalized:expr, + ) => { + paste::paste! { + pub mod $fn_name { + use super::*; + pub struct Operation(MpFloat, MpFloat, MpFloat); + + impl MpOp for Operation { + type Input = $RustArgs; + type Output = $RustRet; + + fn new() -> Self { + Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) + } + + fn run(&mut self, input: Self::Input) -> Self::Output { + self.0.assign(input.0); + self.1.assign(input.1); + self.2.assign(input.2); + let ord = self.0.[< $fn_name_normalized _round >](&self.1, &self.2, Nearest); + prep_retval::(&mut self.0, ord) + } + } + } + } + }; +} + +libm_macros::for_each_function! { + callback: impl_mp_op, + skip: [ + // Most of these need a manual implementation + fabs, ceil, copysign, floor, rint, round, trunc, + fabsf, ceilf, copysignf, floorf, rintf, roundf, truncf, + fmod, fmodf, frexp, frexpf, ilogb, ilogbf, jn, jnf, ldexp, ldexpf, + lgamma_r, lgammaf_r, modf, modff, nextafter, nextafterf, pow,powf, + remquo, remquof, scalbn, scalbnf, sincos, sincosf, + ], + fn_extra: match MACRO_FN_NAME { + // Remap function names that are different between mpfr and libm + expm1 | expm1f => exp_m1, + fabs | fabsf => abs, + fdim | fdimf => positive_diff, + fma | fmaf => mul_add, + fmax | fmaxf => max, + fmin | fminf => min, + lgamma | lgammaf => ln_gamma, + log | logf => ln, + log1p | log1pf => ln_1p, + tgamma | tgammaf => gamma, + _ => MACRO_FN_NAME_NORMALIZED + } +} + +/// Implement unary functions that don't have a `_round` version +macro_rules! impl_no_round { + // Unary matcher + ($($fn_name:ident, $rug_name:ident;)*) => { + paste::paste! { + // Implement for both f32 and f64 + $( impl_no_round!{ @inner_unary [< $fn_name f >], (f32,), $rug_name } )* + $( impl_no_round!{ @inner_unary $fn_name, (f64,), $rug_name } )* + } + }; + + (@inner_unary $fn_name:ident, ($fty:ty,), $rug_name:ident) => { + pub mod $fn_name { + use super::*; + pub struct Operation(MpFloat); + + impl MpOp for Operation { + type Input = ($fty,); + type Output = $fty; + + fn new() -> Self { + Self(new_mpfloat::<$fty>()) + } + + fn run(&mut self, input: Self::Input) -> Self::Output { + self.0.assign(input.0); + self.0.$rug_name(); + prep_retval::(&mut self.0, Ordering::Equal) + } + } + } + }; +} + +impl_no_round! { + fabs, abs_mut; + ceil, ceil_mut; + floor, floor_mut; + rint, round_even_mut; // FIXME: respect rounding mode + round, round_mut; + trunc, trunc_mut; +} + +/// Some functions are difficult to do in a generic way. Implement them here. +macro_rules! impl_op_for_ty { + ($fty:ty, $suffix:literal) => { + paste::paste! { + pub mod [] { + use super::*; + pub struct Operation(MpFloat, MpFloat); + + impl MpOp for Operation { + type Input = ($fty, $fty); + type Output = $fty; + + fn new() -> Self { + Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) + } + + fn run(&mut self, input: Self::Input) -> Self::Output { + self.0.assign(input.0); + self.1.assign(input.1); + self.0.copysign_mut(&self.1); + prep_retval::(&mut self.0, Ordering::Equal) + } + } + } + + pub mod [] { + use super::*; + pub struct Operation(MpFloat, MpFloat); + + impl MpOp for Operation { + type Input = ($fty, $fty); + type Output = $fty; + + fn new() -> Self { + Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) + } + + fn run(&mut self, input: Self::Input) -> Self::Output { + self.0.assign(input.0); + self.1.assign(input.1); + self.0.next_toward(&self.1); + prep_retval::(&mut self.0, Ordering::Equal) + } + } + } + + pub mod [] { + use super::*; + pub struct Operation(MpFloat, MpFloat); + + impl MpOp for Operation { + type Input = ($fty, $fty); + type Output = $fty; + + fn new() -> Self { + Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) + } + + fn run(&mut self, input: Self::Input) -> Self::Output { + self.0.assign(input.0); + self.1.assign(input.1); + let ord = self.0.pow_assign_round(&self.1, Nearest); + prep_retval::(&mut self.0, ord) + } + } + } + + pub mod [] { + use super::*; + pub struct Operation(MpFloat, MpFloat); + + impl MpOp for Operation { + type Input = ($fty, $fty); + type Output = $fty; + + fn new() -> Self { + Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) + } + + fn run(&mut self, input: Self::Input) -> Self::Output { + self.0.assign(input.0); + self.1.assign(input.1); + let ord = self.0.rem_assign_round(&self.1, Nearest); + prep_retval::(&mut self.0, ord) + } + } + } + + pub mod [] { + use super::*; + pub struct Operation(MpFloat); + + impl MpOp for Operation { + type Input = ($fty,); + type Output = ($fty, i32); + + fn new() -> Self { + Self(new_mpfloat::<$fty>()) + } + + fn run(&mut self, input: Self::Input) -> Self::Output { + self.0.assign(input.0); + let (sign, ord) = self.0.ln_abs_gamma_round(Nearest); + let ret = prep_retval::<$fty>(&mut self.0, ord); + (ret, sign as i32) + } + } + } + + pub mod [] { + use super::*; + pub struct Operation(i32, MpFloat); + + impl MpOp for Operation { + type Input = (i32, $fty); + type Output = $fty; + + fn new() -> Self { + Self(0, new_mpfloat::<$fty>()) + } + + fn run(&mut self, input: Self::Input) -> Self::Output { + self.0 = input.0; + self.1.assign(input.1); + let ord = self.1.jn_round(self.0, Nearest); + prep_retval::<$fty>(&mut self.1, ord) + } + } + } + + pub mod [] { + use super::*; + pub struct Operation(MpFloat, MpFloat); + + impl MpOp for Operation { + type Input = ($fty,); + type Output = ($fty, $fty); + + fn new() -> Self { + Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) + } + + fn run(&mut self, input: Self::Input) -> Self::Output { + self.0.assign(input.0); + self.1.assign(0.0); + let (sord, cord) = self.0.sin_cos_round(&mut self.1, Nearest); + ( + prep_retval::<$fty>(&mut self.0, sord), + prep_retval::<$fty>(&mut self.1, cord) + ) + } + } + } + } + }; +} + +impl_op_for_ty!(f32, "f"); +impl_op_for_ty!(f64, ""); + +// Account for `lgamma_r` not having a simple `f` suffix +pub mod lgammaf_r { + pub use super::lgamma_rf::*; +} From 64131ec5cdb74213f3f9b0fa435f97ebd9fedba7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Oct 2024 17:41:24 -0500 Subject: [PATCH 1407/4206] Add a test against MPFR using random inputs --- .../libm/crates/libm-test/src/gen/random.rs | 16 +- .../libm/crates/libm-test/src/lib.rs | 29 +++- .../libm/crates/libm-test/src/mpfloat.rs | 21 --- .../libm/crates/libm-test/src/special_case.rs | 157 +++++++++++++----- .../libm/crates/libm-test/src/test_traits.rs | 2 + .../libm-test/tests/compare_built_musl.rs | 2 +- .../crates/libm-test/tests/multiprecision.rs | 71 ++++++++ 7 files changed, 228 insertions(+), 70 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index 601ef4f1d46da..c73937aacc9fe 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -7,7 +7,7 @@ use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; use super::CachedInput; -use crate::GenerateInput; +use crate::{CheckCtx, GenerateInput}; const SEED: [u8; 32] = *b"3.141592653589793238462643383279"; @@ -40,9 +40,10 @@ static TEST_CASES_JN: LazyLock = LazyLock::new(|| { let mut cases = (&*TEST_CASES).clone(); // These functions are extremely slow, limit them - cases.inputs_i32.truncate((NTESTS / 1000).max(80)); - cases.inputs_f32.truncate((NTESTS / 1000).max(80)); - cases.inputs_f64.truncate((NTESTS / 1000).max(80)); + let ntests_jn = (NTESTS / 1000).max(80); + cases.inputs_i32.truncate(ntests_jn); + cases.inputs_f32.truncate(ntests_jn); + cases.inputs_f64.truncate(ntests_jn); // It is easy to overflow the stack with these in debug mode let max_iterations = if cfg!(optimizations_enabled) && cfg!(target_pointer_width = "64") { @@ -105,11 +106,10 @@ fn make_test_cases(ntests: usize) -> CachedInput { } /// Create a test case iterator. -pub fn get_test_cases(fname: &str) -> impl Iterator +pub fn get_test_cases(ctx: &CheckCtx) -> impl Iterator where CachedInput: GenerateInput, { - let inputs = if fname == "jn" || fname == "jnf" { &TEST_CASES_JN } else { &TEST_CASES }; - - CachedInput::get_cases(inputs) + let inputs = if ctx.fname == "jn" || ctx.fname == "jnf" { &TEST_CASES_JN } else { &TEST_CASES }; + inputs.get_cases() } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 64343e00d5dbb..13b76d6c5a822 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -16,14 +16,18 @@ pub type TestResult = Result; // List of all files present in libm's source include!(concat!(env!("OUT_DIR"), "/all_files.rs")); -/// ULP allowed to differ from musl (note that musl itself may not be accurate). +/// Default ULP allowed to differ from musl (note that musl itself may not be accurate). const MUSL_DEFAULT_ULP: u32 = 2; -/// Certain functions have different allowed ULP (consider these xfail). +/// Default ULP allowed to differ from multiprecision (i.e. infinite) results. +const MULTIPREC_DEFAULT_ULP: u32 = 1; + +/// ULP allowed to differ from muls results. /// /// Note that these results were obtained using 400,000,000 rounds of random inputs, which /// is not a value used by default. pub fn musl_allowed_ulp(name: &str) -> u32 { + // Consider overrides xfail match name { #[cfg(x86_no_sse)] "asinh" | "asinhf" => 6, @@ -44,6 +48,27 @@ pub fn musl_allowed_ulp(name: &str) -> u32 { } } +/// ULP allowed to differ from multiprecision results. +pub fn multiprec_allowed_ulp(name: &str) -> u32 { + // Consider overrides xfail + match name { + "asinh" | "asinhf" => 2, + "acoshf" => 4, + "atanh" | "atanhf" => 2, + "exp10" | "exp10f" => 3, + "j0" | "j0f" | "j1" | "j1f" => { + // Results seem very target-dependent + if cfg!(target_arch = "x86_64") { 4000 } else { 800_000 } + } + "jn" | "jnf" => 1000, + "lgamma" | "lgammaf" | "lgamma_r" | "lgammaf_r" => 16, + "sinh" | "sinhf" => 2, + "tanh" | "tanhf" => 2, + "tgamma" => 20, + _ => MULTIPREC_DEFAULT_ULP, + } +} + /// 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`. pub fn canonical_name(name: &str) -> &str { diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index db072780aeb63..44962d11679f5 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -248,27 +248,6 @@ macro_rules! impl_op_for_ty { } } - pub mod [] { - use super::*; - pub struct Operation(MpFloat, MpFloat); - - impl MpOp for Operation { - type Input = ($fty, $fty); - type Output = $fty; - - fn new() -> Self { - Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) - } - - fn run(&mut self, input: Self::Input) -> Self::Output { - self.0.assign(input.0); - self.1.assign(input.1); - self.0.next_toward(&self.1); - prep_retval::(&mut self.0, Ordering::Equal) - } - } - } - pub mod [] { use super::*; pub struct Operation(MpFloat, MpFloat); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs b/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs index df263d7428ccc..dac7a349dc4e5 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs @@ -58,20 +58,6 @@ impl MaybeOverride<(f32,)> for SpecialCase { ctx: &CheckCtx, ) -> Option { if ctx.basis == CheckBasis::Musl { - if ctx.fname == "acoshf" && input.0 < -1.0 { - // acoshf is undefined for x <= 1.0, but we return a random result at lower - // values. - return XFAIL; - } - - if ctx.fname == "sincosf" { - let factor_frac_pi_2 = input.0.abs() / f32::consts::FRAC_PI_2; - if (factor_frac_pi_2 - factor_frac_pi_2.round()).abs() < 1e-2 { - // we have a bad approximation near multiples of pi/2 - return XFAIL; - } - } - if ctx.fname == "expm1f" && input.0 > 80.0 && actual.is_infinite() { // we return infinity but the number is representable return XFAIL; @@ -82,15 +68,40 @@ impl MaybeOverride<(f32,)> for SpecialCase { // doesn't seem to happen on x86 return XFAIL; } + } - if ctx.fname == "lgammaf" || ctx.fname == "lgammaf_r" && input.0 < 0.0 { - // loggamma should not be defined for x < 0, yet we both return results - return XFAIL; - } + if ctx.fname == "acoshf" && input.0 < -1.0 { + // acoshf is undefined for x <= 1.0, but we return a random result at lower + // values. + return XFAIL; + } + + if ctx.fname == "lgammaf" || ctx.fname == "lgammaf_r" && input.0 < 0.0 { + // loggamma should not be defined for x < 0, yet we both return results + return XFAIL; } maybe_check_nan_bits(actual, expected, ctx) } + + fn check_int( + input: (f32,), + actual: I, + expected: I, + ctx: &CheckCtx, + ) -> Option> { + // On MPFR for lgammaf_r, we set -1 as the integer result for negative infinity but MPFR + // sets +1 + if ctx.basis == CheckBasis::Mpfr + && ctx.fname == "lgammaf_r" + && input.0 == f32::NEG_INFINITY + && actual.abs() == expected.abs() + { + XFAIL + } else { + None + } + } } impl MaybeOverride<(f64,)> for SpecialCase { @@ -117,15 +128,40 @@ impl MaybeOverride<(f64,)> for SpecialCase { // musl returns -0.0, we return +0.0 return XFAIL; } + } - if ctx.fname == "lgamma" || ctx.fname == "lgamma_r" && input.0 < 0.0 { - // loggamma should not be defined for x < 0, yet we both return results - return XFAIL; - } + if ctx.fname == "acosh" && input.0 < 1.0 { + // The function is undefined for the inputs, musl and our libm both return + // random results. + return XFAIL; + } + + if ctx.fname == "lgamma" || ctx.fname == "lgamma_r" && input.0 < 0.0 { + // loggamma should not be defined for x < 0, yet we both return results + return XFAIL; } maybe_check_nan_bits(actual, expected, ctx) } + + fn check_int( + input: (f64,), + actual: I, + expected: I, + ctx: &CheckCtx, + ) -> Option> { + // On MPFR for lgamma_r, we set -1 as the integer result for negative infinity but MPFR + // sets +1 + if ctx.basis == CheckBasis::Mpfr + && ctx.fname == "lgamma_r" + && input.0 == f64::NEG_INFINITY + && actual.abs() == expected.abs() + { + XFAIL + } else { + None + } + } } /// Check NaN bits if the function requires it @@ -142,6 +178,11 @@ fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Opt return SKIP; } + // MPFR only has one NaN bitpattern; allow the default `.is_nan()` checks to validate. + if ctx.basis == CheckBasis::Mpfr { + return SKIP; + } + // abs and copysign require signaling NaNs to be propagated, so verify bit equality. if actual.to_bits() == expected.to_bits() { return SKIP; @@ -158,9 +199,10 @@ impl MaybeOverride<(f32, f32)> for SpecialCase { _ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - maybe_skip_min_max_nan(input, expected, ctx) + maybe_skip_binop_nan(input, expected, ctx) } } + impl MaybeOverride<(f64, f64)> for SpecialCase { fn check_float( input: (f64, f64), @@ -169,47 +211,86 @@ impl MaybeOverride<(f64, f64)> for SpecialCase { _ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - maybe_skip_min_max_nan(input, expected, ctx) + maybe_skip_binop_nan(input, expected, ctx) } } /// Musl propagates NaNs if one is provided as the input, but we return the other input. // F1 and F2 are always the same type, this is just to please generics -fn maybe_skip_min_max_nan( +fn maybe_skip_binop_nan( input: (F1, F1), expected: F2, ctx: &CheckCtx, ) -> Option { - if (ctx.canonical_name == "fmax" || ctx.canonical_name == "fmin") - && (input.0.is_nan() || input.1.is_nan()) - && expected.is_nan() - { - return XFAIL; - } else { - None + match ctx.basis { + CheckBasis::Musl => { + if (ctx.canonical_name == "fmax" || ctx.canonical_name == "fmin") + && (input.0.is_nan() || input.1.is_nan()) + && expected.is_nan() + { + XFAIL + } else { + None + } + } + CheckBasis::Mpfr => { + if ctx.canonical_name == "copysign" && input.1.is_nan() { + SKIP + } else { + None + } + } } } impl MaybeOverride<(i32, f32)> for SpecialCase { fn check_float( input: (i32, f32), - _actual: F, - _expected: F, + actual: F, + expected: F, ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - bessel_prec_dropoff(input, ulp, ctx) + match ctx.basis { + CheckBasis::Musl => bessel_prec_dropoff(input, ulp, ctx), + CheckBasis::Mpfr => { + // We return +0.0, MPFR returns -0.0 + if ctx.fname == "jnf" + && input.1 == f32::NEG_INFINITY + && actual == F::ZERO + && expected == F::ZERO + { + XFAIL + } else { + None + } + } + } } } impl MaybeOverride<(i32, f64)> for SpecialCase { fn check_float( input: (i32, f64), - _actual: F, - _expected: F, + actual: F, + expected: F, ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - bessel_prec_dropoff(input, ulp, ctx) + match ctx.basis { + CheckBasis::Musl => bessel_prec_dropoff(input, ulp, ctx), + CheckBasis::Mpfr => { + // We return +0.0, MPFR returns -0.0 + if ctx.fname == "jn" + && input.1 == f64::NEG_INFINITY + && actual == F::ZERO + && expected == F::ZERO + { + XFAIL + } else { + bessel_prec_dropoff(input, ulp, ctx) + } + } + } } } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index c24ac6e43bc26..deb837887fafa 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -52,6 +52,8 @@ impl CheckCtx { pub enum CheckBasis { /// Check against Musl's math sources. Musl, + /// Check against infinite precision (MPFR). + Mpfr, } /// A trait to implement on any output type so we can verify it in a generic way. diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 208b8e28618e1..5a118f7c209d9 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -29,8 +29,8 @@ macro_rules! musl_rand_tests { fn [< musl_random_ $fn_name >]() { let fname = stringify!($fn_name); let ulp = musl_allowed_ulp(fname); - let cases = random::get_test_cases::<$RustArgs>(fname); let ctx = CheckCtx::new(ulp, fname, CheckBasis::Musl); + let cases = random::get_test_cases::<$RustArgs>(&ctx); for input in cases { let musl_res = input.call(musl::$fn_name as $CFn); diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs new file mode 100644 index 0000000000000..f8d94a1609e90 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -0,0 +1,71 @@ +//! Test with "infinite precision" + +#![cfg(feature = "test-multiprecision")] + +use libm_test::gen::random; +use libm_test::mpfloat::{self, MpOp}; +use libm_test::{CheckBasis, CheckCtx, CheckOutput, TupleCall, multiprec_allowed_ulp}; + +/// Implement a test against MPFR with random inputs. +macro_rules! multiprec_rand_tests { + ( + fn_name: $fn_name:ident, + CFn: $CFn:ty, + CArgs: $CArgs:ty, + CRet: $CRet:ty, + RustFn: $RustFn:ty, + RustArgs: $RustArgs:ty, + RustRet: $RustRet:ty, + attrs: [$($meta:meta)*] + ) => { + paste::paste! { + #[test] + $(#[$meta])* + fn [< multiprec_random_ $fn_name >]() { + type MpOpTy = mpfloat::$fn_name::Operation; + + let fname = stringify!($fn_name); + let ulp = multiprec_allowed_ulp(fname); + let mut mp_vals = MpOpTy::new(); + let ctx = CheckCtx::new(ulp, fname, CheckBasis::Mpfr); + let cases = random::get_test_cases::<$RustArgs>(&ctx); + + for input in cases { + let mp_res = mp_vals.run(input); + let crate_res = input.call(libm::$fn_name as $RustFn); + + crate_res.validate(mp_res, input, &ctx).unwrap(); + } + } + } + }; +} + +libm_macros::for_each_function! { + callback: multiprec_rand_tests, + attributes: [ + // Also an assertion failure on i686: at `MPFR_ASSERTN (! mpfr_erangeflag_p ())` + #[ignore = "large values are infeasible in MPFR"] + [jn, jnf], + ], + skip: [ + // FIXME: MPFR tests needed + frexp, + frexpf, + ilogb, + ilogbf, + ldexp, + ldexpf, + modf, + modff, + remquo, + remquof, + scalbn, + scalbnf, + + // FIXME: test needed, see + // https://github.com/rust-lang/libm/pull/311#discussion_r1818273392 + nextafter, + nextafterf, + ], +} From 54c8ae0980a6b53495a6af3e1d85796f2e53fd8b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Oct 2024 17:41:42 -0500 Subject: [PATCH 1408/4206] Run tests against MPFR on CI where possible This effectively gives us tests against infinite-precision results on MacOS and x86+sse Linux. --- .../docker/aarch64-unknown-linux-gnu/Dockerfile | 2 +- .../ci/docker/i686-unknown-linux-gnu/Dockerfile | 2 +- .../docker/x86_64-unknown-linux-gnu/Dockerfile | 2 +- library/compiler-builtins/libm/ci/run.sh | 16 ++++++++++++++++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile index a7b23cb9e0271..7fa06b2860106 100644 --- a/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -3,7 +3,7 @@ FROM ubuntu:24.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ - gcc-aarch64-linux-gnu libc6-dev-arm64-cross \ + gcc-aarch64-linux-gnu m4 make libc6-dev-arm64-cross \ qemu-user-static ENV TOOLCHAIN_PREFIX=aarch64-linux-gnu- diff --git a/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile index 3b0bfc0d3d9d2..37e206a84fcb5 100644 --- a/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile @@ -2,4 +2,4 @@ FROM ubuntu:24.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ - gcc-multilib libc6-dev ca-certificates + gcc-multilib m4 make libc6-dev ca-certificates diff --git a/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile index 15723ab57ee05..c84a31c57a96a 100644 --- a/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile @@ -2,4 +2,4 @@ FROM ubuntu:24.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates + gcc m4 make libc6-dev ca-certificates diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 30265e513a2ac..94612adc72f49 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -35,6 +35,22 @@ case "$target" in *) extra_flags="$extra_flags --features libm-test/build-musl" ;; esac +# Configure which targets test against MPFR +case "$target" in + # MSVC cannot link MPFR + *windows-msvc*) ;; + # FIXME: MinGW should be able to build MPFR, but setup in CI is nontrivial. + *windows-gnu*) ;; + # Targets that aren't cross compiled work fine + # FIXME(ci): we should be able to enable aarch64 Linux here once GHA + # support rolls out. + x86_64*) extra_flags="$extra_flags --features libm-test/test-multiprecision" ;; + # i686 works fine, i586 does not + i686*) extra_flags="$extra_flags --features libm-test/test-multiprecision" ;; + # Apple aarch64 is native + aarch64*apple*) extra_flags="$extra_flags --features libm-test/test-multiprecision" ;; +esac + # FIXME: `STATUS_DLL_NOT_FOUND` testing macros on CI. # case "$target" in From 395419d2d2178dade8bfc51935ae596c3231175b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Oct 2024 21:44:28 -0500 Subject: [PATCH 1409/4206] Rename the `special_case` module to `precision` and move default ULP Having the default ULP in lib.rs doesn't make much sense when everything else precision-related is in special_case.rs. Rename `special_case` to `precision` and move the `*_allowed_ulp` functions there. --- .../libm/crates/libm-test/src/lib.rs | 57 +------------------ .../src/{special_case.rs => precision.rs} | 53 +++++++++++++++++ 2 files changed, 55 insertions(+), 55 deletions(-) rename library/compiler-builtins/libm/crates/libm-test/src/{special_case.rs => precision.rs} (84%) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 13b76d6c5a822..31b95e46c0682 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -2,11 +2,11 @@ pub mod gen; #[cfg(feature = "test-multiprecision")] pub mod mpfloat; mod num_traits; -mod special_case; +mod precision; mod test_traits; pub use num_traits::{Float, Hex, Int}; -pub use special_case::{MaybeOverride, SpecialCase}; +pub use precision::{MaybeOverride, SpecialCase, multiprec_allowed_ulp, musl_allowed_ulp}; pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, TupleCall}; /// Result type for tests is usually from `anyhow`. Most times there is no success value to @@ -16,59 +16,6 @@ pub type TestResult = Result; // List of all files present in libm's source include!(concat!(env!("OUT_DIR"), "/all_files.rs")); -/// Default ULP allowed to differ from musl (note that musl itself may not be accurate). -const MUSL_DEFAULT_ULP: u32 = 2; - -/// Default ULP allowed to differ from multiprecision (i.e. infinite) results. -const MULTIPREC_DEFAULT_ULP: u32 = 1; - -/// ULP allowed to differ from muls results. -/// -/// Note that these results were obtained using 400,000,000 rounds of random inputs, which -/// is not a value used by default. -pub fn musl_allowed_ulp(name: &str) -> u32 { - // Consider overrides xfail - match name { - #[cfg(x86_no_sse)] - "asinh" | "asinhf" => 6, - "lgamma" | "lgamma_r" | "lgammaf" | "lgammaf_r" => 400, - "tanh" | "tanhf" => 4, - "tgamma" => 20, - "j0" | "j0f" | "j1" | "j1f" => { - // Results seem very target-dependent - if cfg!(target_arch = "x86_64") { 4000 } else { 800_000 } - } - "jn" | "jnf" => 1000, - "sincosf" => 500, - #[cfg(not(target_pointer_width = "64"))] - "exp10" => 4, - #[cfg(not(target_pointer_width = "64"))] - "exp10f" => 4, - _ => MUSL_DEFAULT_ULP, - } -} - -/// ULP allowed to differ from multiprecision results. -pub fn multiprec_allowed_ulp(name: &str) -> u32 { - // Consider overrides xfail - match name { - "asinh" | "asinhf" => 2, - "acoshf" => 4, - "atanh" | "atanhf" => 2, - "exp10" | "exp10f" => 3, - "j0" | "j0f" | "j1" | "j1f" => { - // Results seem very target-dependent - if cfg!(target_arch = "x86_64") { 4000 } else { 800_000 } - } - "jn" | "jnf" => 1000, - "lgamma" | "lgammaf" | "lgamma_r" | "lgammaf_r" => 16, - "sinh" | "sinhf" => 2, - "tanh" | "tanhf" => 2, - "tgamma" => 20, - _ => MULTIPREC_DEFAULT_ULP, - } -} - /// 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`. pub fn canonical_name(name: &str) -> &str { diff --git a/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs similarity index 84% rename from library/compiler-builtins/libm/crates/libm-test/src/special_case.rs rename to library/compiler-builtins/libm/crates/libm-test/src/precision.rs index dac7a349dc4e5..e2ad638c41231 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/special_case.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -8,6 +8,59 @@ use crate::{CheckBasis, CheckCtx, Float, Int, TestResult}; /// Type implementing [`IgnoreCase`]. pub struct SpecialCase; +/// Default ULP allowed to differ from musl (note that musl itself may not be accurate). +const MUSL_DEFAULT_ULP: u32 = 2; + +/// Default ULP allowed to differ from multiprecision (i.e. infinite) results. +const MULTIPREC_DEFAULT_ULP: u32 = 1; + +/// ULP allowed to differ from muls results. +/// +/// Note that these results were obtained using 400,000,000 rounds of random inputs, which +/// is not a value used by default. +pub fn musl_allowed_ulp(name: &str) -> u32 { + // Consider overrides xfail + match name { + #[cfg(x86_no_sse)] + "asinh" | "asinhf" => 6, + "lgamma" | "lgamma_r" | "lgammaf" | "lgammaf_r" => 400, + "tanh" | "tanhf" => 4, + "tgamma" => 20, + "j0" | "j0f" | "j1" | "j1f" => { + // Results seem very target-dependent + if cfg!(target_arch = "x86_64") { 4000 } else { 800_000 } + } + "jn" | "jnf" => 1000, + "sincosf" => 500, + #[cfg(not(target_pointer_width = "64"))] + "exp10" => 4, + #[cfg(not(target_pointer_width = "64"))] + "exp10f" => 4, + _ => MUSL_DEFAULT_ULP, + } +} + +/// ULP allowed to differ from multiprecision results. +pub fn multiprec_allowed_ulp(name: &str) -> u32 { + // Consider overrides xfail + match name { + "asinh" | "asinhf" => 2, + "acoshf" => 4, + "atanh" | "atanhf" => 2, + "exp10" | "exp10f" => 3, + "j0" | "j0f" | "j1" | "j1f" => { + // Results seem very target-dependent + if cfg!(target_arch = "x86_64") { 4000 } else { 800_000 } + } + "jn" | "jnf" => 1000, + "lgamma" | "lgammaf" | "lgamma_r" | "lgammaf_r" => 16, + "sinh" | "sinhf" => 2, + "tanh" | "tanhf" => 2, + "tgamma" => 20, + _ => MULTIPREC_DEFAULT_ULP, + } +} + /// Don't run further validation on this test case. const SKIP: Option = Some(Ok(())); From ad1c65229384b21e3dafdc40f8d2119df3186cae Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 03:05:01 -0500 Subject: [PATCH 1410/4206] Update `libm-test/build.rs` to skip directories Don't try to generate tests for directories, or for files that contain `f16` or `f128` (as these types are not provided by musl's math implementations). (cherry picked from commit fd7ad36b70d0bbc0f0b9bc7e54d10258423fda29) --- .../libm/crates/libm-test/build.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs index 472dec9d33e10..40b3e56c046b8 100644 --- a/library/compiler-builtins/libm/crates/libm-test/build.rs +++ b/library/compiler-builtins/libm/crates/libm-test/build.rs @@ -156,7 +156,11 @@ mod musl_serialized_tests { return; } - let files = fs::read_dir(math_src).unwrap().map(|f| f.unwrap().path()).collect::>(); + let files = fs::read_dir(math_src) + .unwrap() + .map(|f| f.unwrap().path()) + .filter(file_needs_test) + .collect::>(); let mut math = Vec::new(); for file in files { @@ -187,6 +191,19 @@ mod musl_serialized_tests { generate_unit_tests(&math); } + /// Check whether a path within `src/math` should get tests generated. + fn file_needs_test(path: &PathBuf) -> bool { + // Skip directories + if path.is_dir() { + return false; + } + + let fname = path.file_name().unwrap().to_str().unwrap(); + + // Musl doesn't support `f16` or `f128` + !(fname.contains("f16") || fname.contains("f128")) + } + /// A "poor man's" parser for the signature of a function fn parse(s: &str) -> Function { let s = eat(s, "pub fn "); From ec1ca5129826bdaf4f6f1c97255547bfc8d12b77 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 02:56:22 -0500 Subject: [PATCH 1411/4206] Vendor `cfg_if::cfg_if!` `cfg_if` is helpful for applying `cfg` attributes to groups of items, like we will need to do with architecture-specific modules of `f16` and `f128`. However, `libm` can't have dependencies. The `cfg_if` macro is complex but small, so just vendor it here. --- .../libm/src/math/support/macros.rs | 46 +++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index 6bc75837a3494..39a6fe827725a 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -1,6 +1,46 @@ -/// Choose among using an intrinsic (if available) and falling back to the default function body. -/// Returns directly if the intrinsic version is used, otherwise continues to the rest of the -/// function. +/// `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)* } )* + ) => { + cfg_if! { + @__items + () ; + ( ($i_met) ($($i_tokens)*) ), + $( ( ($e_met) ($($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)* } + }; + + // Internal macro to make __apply work out right for different match types, + // because of how macros matching/expand stuff. + (@__identity $($tokens:tt)*) => { $($tokens)* }; +} + +/// Choose between using an intrinsic (if available) and the function body. Returns directly if +/// the intrinsic is used, otherwise the rest of the function body is used. /// /// Use this if the intrinsic is likely to be more performant on the platform(s) specified /// in `intrinsic_available`. From 6d1033e7fc2beb6ce494c7099770326a8a3883c4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Oct 2024 20:24:46 -0500 Subject: [PATCH 1412/4206] Add an "arch" Cargo feature that is on by default Introduce a Cargo feature to enable or disable architecture-specific features (SIMD, assembly), which is on by default. This allows for more fine grained control compared to relying on the `force-soft-floats` feature. Similar to "unstable-intrinsics", introduce a build.rs config option for `unstable-intrinsics AND NOT force-soft-floats`, which makes this easier to work with in code. Effectively, this allows moving our non-additive Cargo feature (force-soft-floats) to a positive one by default, allowing for an override when needed. --- library/compiler-builtins/libm/Cargo.toml | 5 ++++- library/compiler-builtins/libm/build.rs | 12 ++++++++++++ library/compiler-builtins/libm/ci/run.sh | 1 + .../crates/compiler-builtins-smoke-test/Cargo.toml | 1 + 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 5e4565556b021..2e74012eae442 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -14,7 +14,10 @@ exclude = ["/ci/", "/.github/workflows/"] rust-version = "1.63" [features] -default = [] +default = ["arch"] + +# Enable architecture-specific features such as SIMD or assembly routines. +arch = [] # This tells the compiler to assume that a Nightly toolchain is being used and # that it should activate any useful Nightly things accordingly. diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index adb5214073084..0010292361138 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -15,6 +15,7 @@ fn main() { } configure_intrinsics(); + configure_arch(); } /// Simplify the feature logic for enabling intrinsics so code only needs to use @@ -28,3 +29,14 @@ fn configure_intrinsics() { println!("cargo:rustc-cfg=intrinsics_enabled"); } } + +/// Simplify the feature logic for enabling arch-specific features so code only needs to use +/// `cfg(arch_enabled)`. +fn configure_arch() { + 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"); + } +} diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 94612adc72f49..9f642326ba82d 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -64,6 +64,7 @@ fi # Make sure we can build with overriding features. We test the indibidual # features it controls separately. +cargo check --no-default-features cargo check --features "force-soft-floats" if [ "${BUILD_ONLY:-}" = "1" ]; then diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index 2a6c62961e361..7118bfe06f1d8 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -18,6 +18,7 @@ force-soft-floats = [] [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = [ + "cfg(arch_enabled)", "cfg(assert_no_panic)", "cfg(intrinsics_enabled)", ] } From 7108e80dc23b9c4971151b0627925554013346de Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Oct 2024 20:29:55 -0500 Subject: [PATCH 1413/4206] Update `select_implementation` to accept arch configuration --- .../libm/src/math/support/macros.rs | 45 ++++++++++++++++--- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index 39a6fe827725a..f85a6122ee8a5 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -39,17 +39,31 @@ macro_rules! cfg_if { (@__identity $($tokens:tt)*) => { $($tokens)* }; } -/// Choose between using an intrinsic (if available) and the function body. Returns directly if -/// the intrinsic is used, otherwise the rest of the function body is used. +/// Choose among using an intrinsic, an arch-specific implementation, and the function body. +/// Returns directly if the intrinsic or arch is used, otherwise continue with the rest of the +/// function. /// -/// Use this if the intrinsic is likely to be more performant on the platform(s) specified -/// in `intrinsic_available`. +/// Specify a `use_intrinsic` meta field if the intrinsic is (1) available on the platforms (i.e. +/// LLVM lowers it without libcalls that may recurse), (2) it is likely to be more performant. +/// Intrinsics require wrappers in the `math::arch::intrinsics` module. /// -/// The `cfg` used here is controlled by `build.rs` so the passed meta does not need to account -/// for e.g. the `unstable-intrinsics` or `force-soft-float` features. +/// Specify a `use_arch` meta field if an architecture-specific implementation is provided. +/// 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`). +/// +/// The passed meta options do not need to account for relevant Cargo features +/// (`unstable-intrinsics`, `arch`, `force-soft-floats`), this macro handles that part. macro_rules! select_implementation { ( name: $fname:ident, + // Configuration meta for when to use arch-specific implementation that requires hard + // float ops + $( use_arch: $use_arch:meta, )? + // Configuration meta for when to use the arch module regardless of whether softfloats + // have been requested. + $( use_arch_required: $use_arch_required:meta, )? // Configuration meta for when to call intrinsics and let LLVM figure it out $( use_intrinsic: $use_intrinsic:meta, )? args: $($arg:ident),+ , @@ -57,6 +71,25 @@ macro_rules! select_implementation { // FIXME: these use paths that are a pretty fragile (`super`). We should figure out // something better w.r.t. how this is vendored into compiler-builtins. + // However, we do need a few things from `arch` that are used even with soft floats. + // + select_implementation! { + @cfg $($use_arch_required)?; + if true { + return super::arch::$fname( $($arg),+ ); + } + } + + // By default, never use arch-specific implementations if we have force-soft-floats + #[cfg(arch_enabled)] + select_implementation! { + @cfg $($use_arch)?; + // Wrap in `if true` to avoid unused warnings + if true { + return super::arch::$fname( $($arg),+ ); + } + } + // Never use intrinsics if we are forcing soft floats, and only enable with the // `unstable-intrinsics` feature. #[cfg(intrinsics_enabled)] From d6646ae2d1170e2716c5f964cc394f14b4b6a7da Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Oct 2024 20:31:48 -0500 Subject: [PATCH 1414/4206] Move architecture-specific code to `src/math/arch` Move the code and call into its new location with `select_implementation`. --- .../libm/src/math/arch/i586.rs | 37 +++ .../libm/src/math/arch/i686.rs | 24 ++ .../libm/src/math/arch/mod.rs | 19 ++ .../compiler-builtins/libm/src/math/ceil.rs | 19 +- .../compiler-builtins/libm/src/math/floor.rs | 19 +- .../compiler-builtins/libm/src/math/sqrt.rs | 233 ++++++++---------- .../compiler-builtins/libm/src/math/sqrtf.rs | 159 ++++++------ 7 files changed, 261 insertions(+), 249 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/arch/i586.rs create mode 100644 library/compiler-builtins/libm/src/math/arch/i686.rs diff --git a/library/compiler-builtins/libm/src/math/arch/i586.rs b/library/compiler-builtins/libm/src/math/arch/i586.rs new file mode 100644 index 0000000000000..f92b9a2af711f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/i586.rs @@ -0,0 +1,37 @@ +//! Architecture-specific support for x86-32 without SSE2 + +use super::super::fabs; + +/// 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. +/// Basic implementation taken from https://github.com/rust-lang/libm/issues/219. +pub fn ceil(x: f64) -> f64 { + if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { + let truncated = x as i64 as f64; + if truncated < x { + return truncated + 1.0; + } else { + return truncated; + } + } else { + return x; + } +} + +/// 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. +/// Basic implementation taken from https://github.com/rust-lang/libm/issues/219. +pub fn floor(x: f64) -> f64 { + if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { + let truncated = x as i64 as f64; + if truncated > x { + return truncated - 1.0; + } else { + return truncated; + } + } else { + return x; + } +} diff --git a/library/compiler-builtins/libm/src/math/arch/i686.rs b/library/compiler-builtins/libm/src/math/arch/i686.rs new file mode 100644 index 0000000000000..80f7face17424 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/i686.rs @@ -0,0 +1,24 @@ +//! Architecture-specific support for x86-32 and x86-64 with SSE2 + +#![cfg(not(feature = "force-soft-floats"))] + +#[cfg(target_arch = "x86")] +use core::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64::*; + +pub fn sqrtf(x: f32) -> f32 { + unsafe { + let m = _mm_set_ss(x); + let m_sqrt = _mm_sqrt_ss(m); + _mm_cvtss_f32(m_sqrt) + } +} + +pub fn sqrt(x: f64) -> f64 { + unsafe { + let m = _mm_set_sd(x); + let m_sqrt = _mm_sqrt_pd(m); + _mm_cvtsd_f64(m_sqrt) + } +} diff --git a/library/compiler-builtins/libm/src/math/arch/mod.rs b/library/compiler-builtins/libm/src/math/arch/mod.rs index a4bc218b743d9..cf9547117b830 100644 --- a/library/compiler-builtins/libm/src/math/arch/mod.rs +++ b/library/compiler-builtins/libm/src/math/arch/mod.rs @@ -7,3 +7,22 @@ #[cfg(intrinsics_enabled)] pub mod intrinsics; + +// Most implementations should be defined here, to ensure they are not made available when +// soft floats are required. +#[cfg(arch_enabled)] +cfg_if! { + if #[cfg(target_feature = "sse2")] { + mod i686; + pub use i686::{sqrt, sqrtf}; + } +} + +// 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}; + } +} diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index 0da01b4d0b690..c7e857dbb6fb8 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -10,28 +10,11 @@ const TOINT: f64 = 1. / f64::EPSILON; pub fn ceil(x: f64) -> f64 { select_implementation! { name: ceil, + use_arch_required: all(target_arch = "x86", not(target_feature = "sse2")), use_intrinsic: target_arch = "wasm32", args: x, } - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - { - //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. - //basic implementation taken from https://github.com/rust-lang/libm/issues/219 - use super::fabs; - if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { - let truncated = x as i64 as f64; - if truncated < x { - return truncated + 1.0; - } else { - return truncated; - } - } else { - return x; - } - } let u: u64 = x.to_bits(); let e: i64 = (u >> 52 & 0x7ff) as i64; let y: f64; diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index 2b9955ebae349..532226b9f86aa 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -10,28 +10,11 @@ const TOINT: f64 = 1. / f64::EPSILON; pub fn floor(x: f64) -> f64 { select_implementation! { name: floor, + use_arch_required: all(target_arch = "x86", not(target_feature = "sse2")), use_intrinsic: target_arch = "wasm32", args: x, } - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - { - //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. - //basic implementation taken from https://github.com/rust-lang/libm/issues/219 - use super::fabs; - if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { - let truncated = x as i64 as f64; - if truncated > x { - return truncated - 1.0; - } else { - return truncated; - } - } else { - return x; - } - } let ui = x.to_bits(); let e = ((ui >> 52) & 0x7ff) as i32; diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 2e856100f7ddd..a443b7e4c613d 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -83,156 +83,139 @@ use core::f64; pub fn sqrt(x: f64) -> f64 { select_implementation! { name: sqrt, + use_arch: target_feature = "sse2", use_intrinsic: target_arch = "wasm32", args: x, } - #[cfg(all(target_feature = "sse2", not(feature = "force-soft-floats")))] - { - // Note: This path is unlikely since LLVM will usually have already - // optimized sqrt calls into hardware instructions if sse2 is available, - // but if someone does end up here they'll appreciate the speed increase. - #[cfg(target_arch = "x86")] - use core::arch::x86::*; - #[cfg(target_arch = "x86_64")] - use core::arch::x86_64::*; - unsafe { - let m = _mm_set_sd(x); - let m_sqrt = _mm_sqrt_pd(m); - _mm_cvtsd_f64(m_sqrt) - } - } - #[cfg(any(not(target_feature = "sse2"), feature = "force-soft-floats"))] - { - use core::num::Wrapping; + use core::num::Wrapping; - const TINY: f64 = 1.0e-300; + const TINY: f64 = 1.0e-300; - let mut z: f64; - let sign: Wrapping = Wrapping(0x80000000); - let mut ix0: i32; - let mut s0: i32; - let mut q: i32; - let mut m: i32; - let mut t: i32; - let mut i: i32; - let mut r: Wrapping; - let mut t1: Wrapping; - let mut s1: Wrapping; - let mut ix1: Wrapping; - let mut q1: Wrapping; + let mut z: f64; + let sign: Wrapping = Wrapping(0x80000000); + let mut ix0: i32; + let mut s0: i32; + let mut q: i32; + let mut m: i32; + let mut t: i32; + let mut i: i32; + let mut r: Wrapping; + let mut t1: Wrapping; + let mut s1: Wrapping; + let mut ix1: Wrapping; + let mut q1: Wrapping; - ix0 = (x.to_bits() >> 32) as i32; - ix1 = Wrapping(x.to_bits() as u32); + ix0 = (x.to_bits() >> 32) as i32; + ix1 = Wrapping(x.to_bits() as u32); - /* take care of Inf and NaN */ - if (ix0 & 0x7ff00000) == 0x7ff00000 { - return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + /* take care of Inf and NaN */ + if (ix0 & 0x7ff00000) == 0x7ff00000 { + return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + } + /* take care of zero */ + if ix0 <= 0 { + if ((ix0 & !(sign.0 as i32)) | ix1.0 as i32) == 0 { + return x; /* sqrt(+-0) = +-0 */ } - /* take care of zero */ - if ix0 <= 0 { - if ((ix0 & !(sign.0 as i32)) | ix1.0 as i32) == 0 { - return x; /* sqrt(+-0) = +-0 */ - } - if ix0 < 0 { - return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ - } + if ix0 < 0 { + return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ } - /* normalize x */ - m = ix0 >> 20; - if m == 0 { - /* subnormal x */ - while ix0 == 0 { - m -= 21; - ix0 |= (ix1 >> 11).0 as i32; - ix1 <<= 21; - } - i = 0; - while (ix0 & 0x00100000) == 0 { - i += 1; - ix0 <<= 1; - } - m -= i - 1; - ix0 |= (ix1 >> (32 - i) as usize).0 as i32; - ix1 = ix1 << i as usize; + } + /* normalize x */ + m = ix0 >> 20; + if m == 0 { + /* subnormal x */ + while ix0 == 0 { + m -= 21; + ix0 |= (ix1 >> 11).0 as i32; + ix1 <<= 21; } - m -= 1023; /* unbias exponent */ - ix0 = (ix0 & 0x000fffff) | 0x00100000; - if (m & 1) == 1 { - /* odd m, double x to make it even */ - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; + i = 0; + while (ix0 & 0x00100000) == 0 { + i += 1; + ix0 <<= 1; } - m >>= 1; /* m = [m/2] */ - - /* generate sqrt(x) bit by bit */ + m -= i - 1; + ix0 |= (ix1 >> (32 - i) as usize).0 as i32; + ix1 = ix1 << i as usize; + } + m -= 1023; /* unbias exponent */ + ix0 = (ix0 & 0x000fffff) | 0x00100000; + if (m & 1) == 1 { + /* odd m, double x to make it even */ ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; ix1 += ix1; - q = 0; /* [q,q1] = sqrt(x) */ - q1 = Wrapping(0); - s0 = 0; - s1 = Wrapping(0); - r = Wrapping(0x00200000); /* r = moving bit from right to left */ + } + m >>= 1; /* m = [m/2] */ - while r != Wrapping(0) { - t = s0 + r.0 as i32; - if t <= ix0 { - s0 = t + r.0 as i32; - ix0 -= t; - q += r.0 as i32; - } - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - r >>= 1; + /* generate sqrt(x) bit by bit */ + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + q = 0; /* [q,q1] = sqrt(x) */ + q1 = Wrapping(0); + s0 = 0; + s1 = Wrapping(0); + r = Wrapping(0x00200000); /* r = moving bit from right to left */ + + while r != Wrapping(0) { + t = s0 + r.0 as i32; + if t <= ix0 { + s0 = t + r.0 as i32; + ix0 -= t; + q += r.0 as i32; } + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + r >>= 1; + } - r = sign; - while r != Wrapping(0) { - t1 = s1 + r; - t = s0; - if t < ix0 || (t == ix0 && t1 <= ix1) { - s1 = t1 + r; - if (t1 & sign) == sign && (s1 & sign) == Wrapping(0) { - s0 += 1; - } - ix0 -= t; - if ix1 < t1 { - ix0 -= 1; - } - ix1 -= t1; - q1 += r; + r = sign; + while r != Wrapping(0) { + t1 = s1 + r; + t = s0; + if t < ix0 || (t == ix0 && t1 <= ix1) { + s1 = t1 + r; + if (t1 & sign) == sign && (s1 & sign) == Wrapping(0) { + s0 += 1; } - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - r >>= 1; + ix0 -= t; + if ix1 < t1 { + ix0 -= 1; + } + ix1 -= t1; + q1 += r; } + ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix1 += ix1; + r >>= 1; + } - /* use floating add to find out rounding direction */ - if (ix0 as u32 | ix1.0) != 0 { - z = 1.0 - TINY; /* raise inexact flag */ - if z >= 1.0 { - z = 1.0 + TINY; - if q1.0 == 0xffffffff { - q1 = Wrapping(0); + /* use floating add to find out rounding direction */ + if (ix0 as u32 | ix1.0) != 0 { + z = 1.0 - TINY; /* raise inexact flag */ + if z >= 1.0 { + z = 1.0 + TINY; + if q1.0 == 0xffffffff { + q1 = Wrapping(0); + q += 1; + } else if z > 1.0 { + if q1.0 == 0xfffffffe { q += 1; - } else if z > 1.0 { - if q1.0 == 0xfffffffe { - q += 1; - } - q1 += Wrapping(2); - } else { - q1 += q1 & Wrapping(1); } + q1 += Wrapping(2); + } else { + q1 += q1 & Wrapping(1); } } - ix0 = (q >> 1) + 0x3fe00000; - ix1 = q1 >> 1; - if (q & 1) == 1 { - ix1 |= sign; - } - ix0 += m << 20; - f64::from_bits((ix0 as u64) << 32 | ix1.0 as u64) } + ix0 = (q >> 1) + 0x3fe00000; + ix1 = q1 >> 1; + if (q & 1) == 1 { + ix1 |= sign; + } + ix0 += m << 20; + f64::from_bits((ix0 as u64) << 32 | ix1.0 as u64) } #[cfg(test)] diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index b2996b350cb4a..d2f7ae70334c3 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -18,109 +18,92 @@ pub fn sqrtf(x: f32) -> f32 { select_implementation! { name: sqrtf, + use_arch: target_feature = "sse2", use_intrinsic: target_arch = "wasm32", args: x, } - #[cfg(all(target_feature = "sse", not(feature = "force-soft-floats")))] - { - // Note: This path is unlikely since LLVM will usually have already - // optimized sqrt calls into hardware instructions if sse is available, - // but if someone does end up here they'll appreciate the speed increase. - #[cfg(target_arch = "x86")] - use core::arch::x86::*; - #[cfg(target_arch = "x86_64")] - use core::arch::x86_64::*; - unsafe { - let m = _mm_set_ss(x); - let m_sqrt = _mm_sqrt_ss(m); - _mm_cvtss_f32(m_sqrt) - } - } - #[cfg(any(not(target_feature = "sse"), feature = "force-soft-floats"))] - { - const TINY: f32 = 1.0e-30; - - let mut z: f32; - let sign: i32 = 0x80000000u32 as i32; - let mut ix: i32; - let mut s: i32; - let mut q: i32; - let mut m: i32; - let mut t: i32; - let mut i: i32; - let mut r: u32; - - ix = x.to_bits() as i32; - - /* take care of Inf and NaN */ - if (ix as u32 & 0x7f800000) == 0x7f800000 { - return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ - } + const TINY: f32 = 1.0e-30; - /* take care of zero */ - if ix <= 0 { - if (ix & !sign) == 0 { - return x; /* sqrt(+-0) = +-0 */ - } - if ix < 0 { - return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ - } - } + let mut z: f32; + let sign: i32 = 0x80000000u32 as i32; + let mut ix: i32; + let mut s: i32; + let mut q: i32; + let mut m: i32; + let mut t: i32; + let mut i: i32; + let mut r: u32; - /* normalize x */ - m = ix >> 23; - if m == 0 { - /* subnormal x */ - i = 0; - while ix & 0x00800000 == 0 { - ix <<= 1; - i = i + 1; - } - m -= i - 1; + ix = x.to_bits() as i32; + + /* take care of Inf and NaN */ + if (ix as u32 & 0x7f800000) == 0x7f800000 { + return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + } + + /* take care of zero */ + if ix <= 0 { + if (ix & !sign) == 0 { + return x; /* sqrt(+-0) = +-0 */ } - m -= 127; /* unbias exponent */ - ix = (ix & 0x007fffff) | 0x00800000; - if m & 1 == 1 { - /* odd m, double x to make it even */ - ix += ix; + if ix < 0 { + return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ } - m >>= 1; /* m = [m/2] */ + } - /* generate sqrt(x) bit by bit */ + /* normalize x */ + m = ix >> 23; + if m == 0 { + /* subnormal x */ + i = 0; + while ix & 0x00800000 == 0 { + ix <<= 1; + i = i + 1; + } + m -= i - 1; + } + m -= 127; /* unbias exponent */ + ix = (ix & 0x007fffff) | 0x00800000; + if m & 1 == 1 { + /* odd m, double x to make it even */ ix += ix; - q = 0; - s = 0; - r = 0x01000000; /* r = moving bit from right to left */ - - while r != 0 { - t = s + r as i32; - if t <= ix { - s = t + r as i32; - ix -= t; - q += r as i32; - } - ix += ix; - r >>= 1; + } + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix += ix; + q = 0; + s = 0; + r = 0x01000000; /* r = moving bit from right to left */ + + while r != 0 { + t = s + r as i32; + if t <= ix { + s = t + r as i32; + ix -= t; + q += r as i32; } + ix += ix; + r >>= 1; + } - /* use floating add to find out rounding direction */ - if ix != 0 { - z = 1.0 - TINY; /* raise inexact flag */ - if z >= 1.0 { - z = 1.0 + TINY; - if z > 1.0 { - q += 2; - } else { - q += q & 1; - } + /* use floating add to find out rounding direction */ + if ix != 0 { + z = 1.0 - TINY; /* raise inexact flag */ + if z >= 1.0 { + z = 1.0 + TINY; + if z > 1.0 { + q += 2; + } else { + q += q & 1; } } - - ix = (q >> 1) + 0x3f000000; - ix += m << 23; - f32::from_bits(ix as u32) } + + ix = (q >> 1) + 0x3f000000; + ix += m << 23; + f32::from_bits(ix as u32) } // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 From 360d3ee184e821e9329a71a18361123aac8e2f8d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 00:42:02 -0500 Subject: [PATCH 1415/4206] Add float and integer traits from compiler-builtins In preparation of adding generic algorithms to `libm`, add the traits from `compiler-builtins`. Eventually we should be able to unify the two crates so we don't have duplicate implementations. --- .../compiler-builtins/libm/src/math/mod.rs | 2 + .../libm/src/math/support/float_traits.rs | 168 +++++++++ .../libm/src/math/support/int_traits.rs | 343 ++++++++++++++++++ .../libm/src/math/support/mod.rs | 5 + 4 files changed, 518 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/support/float_traits.rs create mode 100644 library/compiler-builtins/libm/src/math/support/int_traits.rs diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 393bc51509387..2cd77f1327b2c 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -105,6 +105,8 @@ use self::k_tanf::k_tanf; use self::rem_pio2::rem_pio2; use self::rem_pio2_large::rem_pio2_large; use self::rem_pio2f::rem_pio2f; +#[allow(unused_imports)] +use self::support::{CastFrom, CastInto, DInt, Float, HInt, Int, MinInt}; // Public modules mod acos; diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs new file mode 100644 index 0000000000000..4cf5d7c616578 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -0,0 +1,168 @@ +use core::ops; + +use super::int_traits::{Int, MinInt}; + +/// 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 SIGNIFICAND_BITS: u32; + + /// The bitwidth of the exponent + const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1; + + /// The saturated value of the exponent (infinite representation), in the rightmost postiion. + const EXPONENT_MAX: u32 = (1 << Self::EXPONENT_BITS) - 1; + + /// The exponent bias value + const EXPONENT_BIAS: u32 = Self::EXPONENT_MAX >> 1; + + /// A mask for the sign bit + const SIGN_MASK: Self::Int; + + /// A mask for the significand + const SIGNIFICAND_MASK: Self::Int; + + /// The implicit bit of the float format + const IMPLICIT_BIT: Self::Int; + + /// A mask for the exponent + const EXPONENT_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 SIGNIFICAND_BITS: u32 = $significand_bits; + + const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); + const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1; + const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; + const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_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 { + 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::EXPONENT_MASK == $ty::EXPONENT_MASK + && x.to_bits() & $ty::SIGNIFICAND_MASK != 0 + } + 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::EXPONENT_MASK) >> Self::SIGNIFICAND_BITS) as Self::ExpInt + } + fn frac(self) -> Self::Int { + self.to_bits() & Self::SIGNIFICAND_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::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) + | (significand & Self::SIGNIFICAND_MASK), + ) + } + fn normalize(significand: Self::Int) -> (i32, Self::Int) { + let shift = significand.leading_zeros().wrapping_sub(Self::EXPONENT_BITS); + (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) + } + fn is_subnormal(self) -> bool { + (self.to_bits() & Self::EXPONENT_MASK) == Self::Int::ZERO + } + } + }; +} + +float_impl!(f32, u32, i32, i16, 32, 23); +float_impl!(f64, u64, i64, i16, 64, 52); diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs new file mode 100644 index 0000000000000..bdf3afd48cefd --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -0,0 +1,343 @@ +use core::{fmt, ops}; + +/// Minimal integer implementations needed on all integer types, including wide integers. +#[allow(dead_code)] +pub trait MinInt: + Copy + + fmt::Debug + + ops::BitOr + + ops::Not + + ops::Shl +{ + /// Type with the same width but other signedness + type OtherSign: MinInt; + /// Unsigned version of Self + type UnsignedInt: MinInt; + + /// If `Self` is a signed integer + const SIGNED: bool; + + /// The bitwidth of the int type + const BITS: u32; + + const ZERO: Self; + const ONE: Self; + const MIN: Self; + const MAX: Self; +} + +/// Trait for some basic operations on integers +#[allow(dead_code)] +pub trait Int: + MinInt + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::SubAssign + + ops::BitAndAssign + + ops::BitOrAssign + + ops::BitXorAssign + + ops::ShlAssign + + ops::ShrAssign + + ops::Add + + ops::Sub + + ops::Mul + + ops::Div + + ops::Shr + + ops::BitXor + + ops::BitAnd +{ + fn unsigned(self) -> Self::UnsignedInt; + fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; + + fn from_bool(b: bool) -> Self; + + /// Prevents the need for excessive conversions between signed and unsigned + fn logical_shr(self, other: u32) -> Self; + + /// Absolute difference between two integers. + fn abs_diff(self, other: Self) -> Self::UnsignedInt; + + // copied from primitive integers, but put in a trait + fn is_zero(self) -> bool; + fn wrapping_neg(self) -> Self; + fn wrapping_add(self, other: Self) -> Self; + fn wrapping_mul(self, other: Self) -> Self; + fn wrapping_sub(self, other: Self) -> Self; + fn wrapping_shl(self, other: u32) -> Self; + fn wrapping_shr(self, other: u32) -> Self; + fn rotate_left(self, other: u32) -> Self; + fn overflowing_add(self, other: Self) -> (Self, bool); + fn leading_zeros(self) -> u32; + fn ilog2(self) -> u32; +} + +macro_rules! int_impl_common { + ($ty:ty) => { + fn from_bool(b: bool) -> Self { + b as $ty + } + + fn logical_shr(self, other: u32) -> Self { + Self::from_unsigned(self.unsigned().wrapping_shr(other)) + } + + fn is_zero(self) -> bool { + self == Self::ZERO + } + + fn wrapping_neg(self) -> Self { + ::wrapping_neg(self) + } + + fn wrapping_add(self, other: Self) -> Self { + ::wrapping_add(self, other) + } + + fn wrapping_mul(self, other: Self) -> Self { + ::wrapping_mul(self, other) + } + + fn wrapping_sub(self, other: Self) -> Self { + ::wrapping_sub(self, other) + } + + fn wrapping_shl(self, other: u32) -> Self { + ::wrapping_shl(self, other) + } + + fn wrapping_shr(self, other: u32) -> Self { + ::wrapping_shr(self, other) + } + + fn rotate_left(self, other: u32) -> Self { + ::rotate_left(self, other) + } + + fn overflowing_add(self, other: Self) -> (Self, bool) { + ::overflowing_add(self, other) + } + + fn leading_zeros(self) -> u32 { + ::leading_zeros(self) + } + + fn ilog2(self) -> u32 { + ::ilog2(self) + } + }; +} + +macro_rules! int_impl { + ($ity:ty, $uty:ty) => { + impl MinInt for $uty { + type OtherSign = $ity; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $uty { + fn unsigned(self) -> $uty { + self + } + + // It makes writing macros easier if this is implemented for both signed and unsigned + #[allow(clippy::wrong_self_convention)] + fn from_unsigned(me: $uty) -> Self { + me + } + + fn abs_diff(self, other: Self) -> Self { + if self < other { other.wrapping_sub(self) } else { self.wrapping_sub(other) } + } + + int_impl_common!($uty); + } + + impl MinInt for $ity { + type OtherSign = $uty; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $ity { + fn unsigned(self) -> $uty { + self as $uty + } + + fn from_unsigned(me: $uty) -> Self { + me as $ity + } + + fn abs_diff(self, other: Self) -> $uty { + self.wrapping_sub(other).wrapping_abs() as $uty + } + + int_impl_common!($ity); + } + }; +} + +int_impl!(isize, usize); +int_impl!(i8, u8); +int_impl!(i16, u16); +int_impl!(i32, u32); +int_impl!(i64, u64); +int_impl!(i128, u128); + +/// 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. +#[allow(unused)] +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. +#[allow(unused)] +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 +); + +/// Trait to express (possibly lossy) casting of integers +#[allow(unused)] +pub trait CastInto: Copy { + fn cast(self) -> T; +} + +#[allow(unused)] +pub trait CastFrom: Copy { + fn cast_from(value: T) -> Self; +} + +impl + Copy> CastFrom for T { + fn cast_from(value: U) -> Self { + value.cast() + } +} + +macro_rules! cast_into { + ($ty:ty) => { + cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); + }; + ($ty:ty; $($into:ty),*) => {$( + impl CastInto<$into> for $ty { + fn cast(self) -> $into { + self as $into + } + } + )*}; +} + +cast_into!(usize); +cast_into!(isize); +cast_into!(u8); +cast_into!(i8); +cast_into!(u16); +cast_into!(i16); +cast_into!(u32); +cast_into!(i32); +cast_into!(u64); +cast_into!(i64); +cast_into!(u128); +cast_into!(i128); diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index 10532f0d115a8..f054df6cdf312 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -1,2 +1,7 @@ #[macro_use] pub mod macros; +mod float_traits; +mod int_traits; + +pub use float_traits::Float; +pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; From 1dc50415cdf4ae22ef7001ae264be0fe4040c81a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 29 May 2024 02:56:59 -0500 Subject: [PATCH 1416/4206] Add an apfloat fallback for int to float tests --- .../compiler-builtins/testcrate/tests/conv.rs | 129 +++++++++++------- 1 file changed, 77 insertions(+), 52 deletions(-) diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 24f3a04a4eedc..6096803871bbc 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -12,60 +12,82 @@ mod int_to_float { use super::*; macro_rules! i_to_f { - ($($from:ty, $into:ty, $fn:ident);*;) => { + ($f_ty:ty, $apfloat_ty:ident, $sys_available:meta, $($i_ty:ty, $fn:ident);*;) => { $( #[test] fn $fn() { use compiler_builtins::float::conv::$fn; use compiler_builtins::int::Int; - fuzz(N, |x: $from| { - let f0 = x as $into; - let f1: $into = $fn(x); - // This makes sure that the conversion produced the best rounding possible, and does - // this independent of `x as $into` rounding correctly. - // This assumes that float to integer conversion is correct. - let y_minus_ulp = <$into>::from_bits(f1.to_bits().wrapping_sub(1)) as $from; - let y = f1 as $from; - let y_plus_ulp = <$into>::from_bits(f1.to_bits().wrapping_add(1)) as $from; - let error_minus = <$from as Int>::abs_diff(y_minus_ulp, x); - let error = <$from as Int>::abs_diff(y, x); - let error_plus = <$from as Int>::abs_diff(y_plus_ulp, x); - // The first two conditions check that none of the two closest float values are - // strictly closer in representation to `x`. The second makes sure that rounding is - // towards even significand if two float values are equally close to the integer. - if error_minus < error - || error_plus < error - || ((error_minus == error || error_plus == error) - && ((f0.to_bits() & 1) != 0)) - { - if !cfg!(any( - target_arch = "powerpc", - target_arch = "powerpc64" - )) { - panic!( - "incorrect rounding by {}({}): {}, ({}, {}, {}), errors ({}, {}, {})", - stringify!($fn), - x, - f1.to_bits(), - y_minus_ulp, - y, - y_plus_ulp, - error_minus, - error, - error_plus, - ); + fuzz(N, |x: $i_ty| { + let f0 = apfloat_fallback!( + $f_ty, $apfloat_ty, $sys_available, + |x| x as $f_ty; + // 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; + + let apf = if <$i_ty>::SIGNED { + FloatTy::from_i128(x.try_into().unwrap()).value + } else { + FloatTy::from_u128(x.try_into().unwrap()).value + }; + + <$f_ty>::from_bits(apf.to_bits()) + }, + x + ); + let f1: $f_ty = $fn(x); + + #[cfg($sys_available)] { + // This makes sure that the conversion produced the best rounding possible, and does + // this independent of `x as $into` rounding correctly. + // This assumes that float to integer conversion is correct. + let y_minus_ulp = <$f_ty>::from_bits(f1.to_bits().wrapping_sub(1)) as $i_ty; + let y = f1 as $i_ty; + let y_plus_ulp = <$f_ty>::from_bits(f1.to_bits().wrapping_add(1)) as $i_ty; + let error_minus = <$i_ty as Int>::abs_diff(y_minus_ulp, x); + let error = <$i_ty as Int>::abs_diff(y, x); + let error_plus = <$i_ty as Int>::abs_diff(y_plus_ulp, x); + + // The first two conditions check that none of the two closest float values are + // strictly closer in representation to `x`. The second makes sure that rounding is + // towards even significand if two float values are equally close to the integer. + if error_minus < error + || error_plus < error + || ((error_minus == error || error_plus == error) + && ((f0.to_bits() & 1) != 0)) + { + if !cfg!(any( + target_arch = "powerpc", + target_arch = "powerpc64" + )) { + panic!( + "incorrect rounding by {}({}): {}, ({}, {}, {}), errors ({}, {}, {})", + stringify!($fn), + x, + f1.to_bits(), + y_minus_ulp, + y, + y_plus_ulp, + error_minus, + error, + error_plus, + ); + } } } + // Test against native conversion. We disable testing on all `x86` because of // rounding bugs with `i686`. `powerpc` also has the same rounding bug. - if f0 != f1 && !cfg!(any( + if !Float::eq_repr(f0, f1) && !cfg!(any( target_arch = "x86", target_arch = "powerpc", target_arch = "powerpc64" )) { panic!( - "{}({}): std: {}, builtins: {}", + "{}({}): std: {:?}, builtins: {:?}", stringify!($fn), x, f0, @@ -78,19 +100,22 @@ mod int_to_float { }; } - i_to_f! { - u32, f32, __floatunsisf; - u32, f64, __floatunsidf; - i32, f32, __floatsisf; - i32, f64, __floatsidf; - u64, f32, __floatundisf; - u64, f64, __floatundidf; - i64, f32, __floatdisf; - i64, f64, __floatdidf; - u128, f32, __floatuntisf; - u128, f64, __floatuntidf; - i128, f32, __floattisf; - i128, f64, __floattidf; + i_to_f! { f32, Single, all(), + u32, __floatunsisf; + i32, __floatsisf; + u64, __floatundisf; + i64, __floatdisf; + u128, __floatuntisf; + i128, __floattisf; + } + + i_to_f! { f64, Double, all(), + u32, __floatunsidf; + i32, __floatsidf; + u64, __floatundidf; + i64, __floatdidf; + u128, __floatuntidf; + i128, __floattidf; } } From 51dd4da05328da2f2e658b815046d9845a0214c5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 13 Jun 2024 06:50:44 -0500 Subject: [PATCH 1417/4206] Refactor integer to float conversion Extract some common routines to separate functions in order to deduplicate code and remove some of the magic. --- library/compiler-builtins/src/float/conv.rs | 174 +++++++++++++----- library/compiler-builtins/src/int/mod.rs | 10 +- .../compiler-builtins/testcrate/tests/conv.rs | 2 +- 3 files changed, 138 insertions(+), 48 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index e86fee6dc5f76..da87b3caef827 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -6,21 +6,91 @@ use super::Float; /// Conversions from integers to floats. /// -/// These are hand-optimized bit twiddling code, -/// which unfortunately isn't the easiest kind of code to read. +/// The algorithm is explained here: . It roughly does the following: +/// - Calculate a base mantissa by shifting the integer into mantissa position. This gives us a +/// mantissa _with the implicit bit set_! +/// - Figure out if rounding needs to occur by classifying the bits that are to be truncated. Some +/// patterns are used to simplify this. Adjust the mantissa with the result if needed. +/// - Calculate the exponent based on the base-2 logarithm of `i` (leading zeros). Subtract one. +/// - Shift the exponent and add the mantissa to create the final representation. Subtracting one +/// from the exponent (above) accounts for the explicit bit being set in the mantissa. /// -/// The algorithm is explained here: +/// # Terminology +/// +/// - `i`: the original integer +/// - `i_m`: the integer, shifted fully left (no leading zeros) +/// - `n`: number of leading zeroes +/// - `e`: the resulting exponent. Usually 1 is subtracted to offset the mantissa implicit bit. +/// - `m_base`: the mantissa before adjusting for truncated bits. Implicit bit is usually set. +/// - `adj`: the bits that will be truncated, possibly compressed in some way. +/// - `m`: the resulting mantissa. Implicit bit is usually set. mod int_to_float { + use super::*; + + /// Calculate the exponent from the number of leading zeros. + /// + /// Usually 1 is subtracted from this function's result, so that a mantissa with the implicit + /// bit set can be added back later. + fn exp>>(n: u32) -> F::Int { + F::Int::cast_from(F::EXPONENT_BIAS - 1 + I::BITS - n) + } + + /// Adjust a mantissa with dropped bits to perform correct rounding. + /// + /// The dropped bits should be exactly the bits that get truncated (left-aligned), but they + /// can be combined or compressed in some way that simplifies operations. + fn m_adj(m_base: F::Int, dropped_bits: F::Int) -> F::Int { + // Branchlessly extract a `1` if rounding up should happen, 0 otherwise + // This accounts for rounding to even. + let adj = (dropped_bits - (dropped_bits >> (F::BITS - 1) & !m_base)) >> (F::BITS - 1); + + // Add one when we need to round up. Break ties to even. + m_base + adj + } + + /// Shift the exponent to its position and add the mantissa. + /// + /// If the mantissa has the implicit bit set, the exponent should be one less than its actual + /// value to cancel it out. + fn repr(e: F::Int, m: F::Int) -> F::Int { + // + rather than | so the mantissa can overflow into the exponent + (e << F::SIGNIFICAND_BITS) + m + } + + /// Shift distance from a left-aligned integer to a smaller float. + fn shift_f_lt_i() -> u32 { + (I::BITS - F::BITS) + F::EXPONENT_BITS + } + + /// Shift distance from an integer with `n` leading zeros to a smaller float. + fn shift_f_gt_i(n: u32) -> u32 { + F::SIGNIFICAND_BITS - I::BITS + 1 + n + } + + /// Perform a signed operation as unsigned, then add the sign back. + pub fn signed(i: I, conv: Conv) -> F + where + F: Float, + I: Int, + F::Int: CastFrom, + Conv: Fn(I::UnsignedInt) -> F::Int, + { + let sign_bit = F::Int::cast_from(i >> (I::BITS - 1)) << (F::BITS - 1); + F::from_bits(conv(i.unsigned_abs()) | sign_bit) + } + pub fn u32_to_f32_bits(i: u32) -> u32 { if i == 0 { return 0; } let n = i.leading_zeros(); - let a = (i << n) >> 8; // Significant bits, with bit 24 still in tact. - let b = (i << n) << 24; // Insignificant bits, only relevant for rounding. - let m = a + ((b - (b >> 31 & !a)) >> 31); // Add one when we need to round up. Break ties to even. - let e = 157 - n; // Exponent plus 127, minus one. - (e << 23) + m // + not |, so the mantissa can overflow into the exponent. + // Mantissa with implicit bit set (significant bits) + let m_base = (i << n) >> f32::EXPONENT_BITS; + // Bits that will be dropped (insignificant bits) + let adj = (i << n) << (f32::SIGNIFICAND_BITS + 1); + let m = m_adj::(m_base, adj); + let e = exp::(n) - 1; + repr::(e, m) } pub fn u32_to_f64_bits(i: u32) -> u64 { @@ -28,19 +98,23 @@ mod int_to_float { return 0; } let n = i.leading_zeros(); - let m = (i as u64) << (21 + n); // Significant bits, with bit 53 still in tact. - let e = 1053 - n as u64; // Exponent plus 1023, minus one. - (e << 52) + m // Bit 53 of m will overflow into e. + // Mantissa with implicit bit set + let m = (i as u64) << shift_f_gt_i::(n); + let e = exp::(n) - 1; + repr::(e, m) } pub fn u64_to_f32_bits(i: u64) -> u32 { let n = i.leading_zeros(); - let y = i.wrapping_shl(n); - let a = (y >> 40) as u32; // Significant bits, with bit 24 still in tact. - let b = (y >> 8 | y & 0xFFFF) as u32; // Insignificant bits, only relevant for rounding. - let m = a + ((b - (b >> 31 & !a)) >> 31); // Add one when we need to round up. Break ties to even. - let e = if i == 0 { 0 } else { 189 - n }; // Exponent plus 127, minus one, except for zero. - (e << 23) + m // + not |, so the mantissa can overflow into the exponent. + let i_m = i.wrapping_shl(n); + // Mantissa with implicit bit set + let m_base: u32 = (i_m >> shift_f_lt_i::()) as u32; + // The entire lower half of `i` will be truncated (masked portion), plus the + // next `EXPONENT_BITS` bits. + let adj = (i_m >> f32::EXPONENT_BITS | i_m & 0xFFFF) as u32; + let m = m_adj::(m_base, adj); + let e = if i == 0 { 0 } else { exp::(n) - 1 }; + repr::(e, m) } pub fn u64_to_f64_bits(i: u64) -> u64 { @@ -48,31 +122,45 @@ mod int_to_float { return 0; } let n = i.leading_zeros(); - let a = (i << n) >> 11; // Significant bits, with bit 53 still in tact. - let b = (i << n) << 53; // Insignificant bits, only relevant for rounding. - let m = a + ((b - (b >> 63 & !a)) >> 63); // Add one when we need to round up. Break ties to even. - let e = 1085 - n as u64; // Exponent plus 1023, minus one. - (e << 52) + m // + not |, so the mantissa can overflow into the exponent. + // Mantissa with implicit bit set + let m_base = (i << n) >> f64::EXPONENT_BITS; + let adj = (i << n) << (f64::SIGNIFICAND_BITS + 1); + let m = m_adj::(m_base, adj); + let e = exp::(n) - 1; + repr::(e, m) } pub fn u128_to_f32_bits(i: u128) -> u32 { let n = i.leading_zeros(); - let y = i.wrapping_shl(n); - let a = (y >> 104) as u32; // Significant bits, with bit 24 still in tact. - let b = (y >> 72) as u32 | ((y << 32) >> 32 != 0) as u32; // Insignificant bits, only relevant for rounding. - let m = a + ((b - (b >> 31 & !a)) >> 31); // Add one when we need to round up. Break ties to even. - let e = if i == 0 { 0 } else { 253 - n }; // Exponent plus 127, minus one, except for zero. - (e << 23) + m // + not |, so the mantissa can overflow into the exponent. + let i_m = i.wrapping_shl(n); // Mantissa, shifted so the first bit is nonzero + let m_base: u32 = (i_m >> shift_f_lt_i::()) as u32; + + // Within the upper `F::BITS`, everything except for the signifcand + // gets truncated + let d1: u32 = (i_m >> (u128::BITS - f32::BITS - f32::SIGNIFICAND_BITS - 1)).cast(); + + // The entire rest of `i_m` gets truncated. Zero the upper `F::BITS` then just + // check if it is nonzero. + let d2: u32 = (i_m << f32::BITS >> f32::BITS != 0).into(); + let adj = d1 | d2; + + // Mantissa with implicit bit set + let m = m_adj::(m_base, adj); + let e = if i == 0 { 0 } else { exp::(n) - 1 }; + repr::(e, m) } pub fn u128_to_f64_bits(i: u128) -> u64 { let n = i.leading_zeros(); - let y = i.wrapping_shl(n); - let a = (y >> 75) as u64; // Significant bits, with bit 53 still in tact. - let b = (y >> 11 | y & 0xFFFF_FFFF) as u64; // Insignificant bits, only relevant for rounding. - let m = a + ((b - (b >> 63 & !a)) >> 63); // Add one when we need to round up. Break ties to even. - let e = if i == 0 { 0 } else { 1149 - n as u64 }; // Exponent plus 1023, minus one, except for zero. - (e << 52) + m // + not |, so the mantissa can overflow into the exponent. + let i_m = i.wrapping_shl(n); + // Mantissa with implicit bit set + let m_base: u64 = (i_m >> shift_f_lt_i::()) as u64; + // The entire lower half of `i` will be truncated (masked portion), plus the + // next `EXPONENT_BITS` bits. + let adj = (i_m >> f64::EXPONENT_BITS | i_m & 0xFFFF_FFFF) as u64; + let m = m_adj::(m_base, adj); + let e = if i == 0 { 0 } else { exp::(n) - 1 }; + repr::(e, m) } } @@ -113,38 +201,32 @@ intrinsics! { intrinsics! { #[arm_aeabi_alias = __aeabi_i2f] pub extern "C" fn __floatsisf(i: i32) -> f32 { - let sign_bit = ((i >> 31) as u32) << 31; - f32::from_bits(int_to_float::u32_to_f32_bits(i.unsigned_abs()) | sign_bit) + int_to_float::signed(i, int_to_float::u32_to_f32_bits) } #[arm_aeabi_alias = __aeabi_i2d] pub extern "C" fn __floatsidf(i: i32) -> f64 { - let sign_bit = ((i >> 31) as u64) << 63; - f64::from_bits(int_to_float::u32_to_f64_bits(i.unsigned_abs()) | sign_bit) + int_to_float::signed(i, int_to_float::u32_to_f64_bits) } #[arm_aeabi_alias = __aeabi_l2f] pub extern "C" fn __floatdisf(i: i64) -> f32 { - let sign_bit = ((i >> 63) as u32) << 31; - f32::from_bits(int_to_float::u64_to_f32_bits(i.unsigned_abs()) | sign_bit) + int_to_float::signed(i, int_to_float::u64_to_f32_bits) } #[arm_aeabi_alias = __aeabi_l2d] pub extern "C" fn __floatdidf(i: i64) -> f64 { - let sign_bit = ((i >> 63) as u64) << 63; - f64::from_bits(int_to_float::u64_to_f64_bits(i.unsigned_abs()) | sign_bit) + int_to_float::signed(i, int_to_float::u64_to_f64_bits) } #[cfg_attr(target_os = "uefi", unadjusted_on_win64)] pub extern "C" fn __floattisf(i: i128) -> f32 { - let sign_bit = ((i >> 127) as u32) << 31; - f32::from_bits(int_to_float::u128_to_f32_bits(i.unsigned_abs()) | sign_bit) + int_to_float::signed(i, int_to_float::u128_to_f32_bits) } #[cfg_attr(target_os = "uefi", unadjusted_on_win64)] pub extern "C" fn __floattidf(i: i128) -> f64 { - let sign_bit = ((i >> 127) as u64) << 63; - f64::from_bits(int_to_float::u128_to_f64_bits(i.unsigned_abs()) | sign_bit) + int_to_float::signed(i, int_to_float::u128_to_f64_bits) } } diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index e6f31c5301324..0d3b0ce4048d2 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -83,6 +83,7 @@ pub(crate) trait Int: MinInt fn unsigned(self) -> Self::UnsignedInt; fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; + fn unsigned_abs(self) -> Self::UnsignedInt; fn from_bool(b: bool) -> Self; @@ -178,7 +179,6 @@ macro_rules! int_impl_common { fn wrapping_mul(self, other: Self) -> Self { ::wrapping_mul(self, other) } - fn wrapping_sub(self, other: Self) -> Self { ::wrapping_sub(self, other) } @@ -235,6 +235,10 @@ macro_rules! int_impl { me } + fn unsigned_abs(self) -> Self { + self + } + fn abs_diff(self, other: Self) -> Self { if self < other { other.wrapping_sub(self) @@ -268,6 +272,10 @@ macro_rules! int_impl { me as $ity } + fn unsigned_abs(self) -> Self::UnsignedInt { + self.unsigned_abs() + } + fn abs_diff(self, other: Self) -> $uty { self.wrapping_sub(other).wrapping_abs() as $uty } diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 6096803871bbc..01cc588cf3cf2 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -8,7 +8,7 @@ use compiler_builtins::float::Float; use rustc_apfloat::{Float as _, FloatConvert as _}; use testcrate::*; -mod int_to_float { +mod i_to_f { use super::*; macro_rules! i_to_f { From fbd690735826fd4b3b3f9862820944b23ae9000e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 13 Jun 2024 06:52:46 -0500 Subject: [PATCH 1418/4206] Add integer to `f128` conversions --- library/compiler-builtins/README.md | 12 +- library/compiler-builtins/build.rs | 18 +- .../compiler-builtins/examples/intrinsics.rs | 62 ++++- library/compiler-builtins/src/float/conv.rs | 80 +++++++ .../testcrate/benches/float_conv.rs | 222 ++++++++++++++---- .../compiler-builtins/testcrate/tests/conv.rs | 22 ++ 6 files changed, 348 insertions(+), 68 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index f792d188324d6..a2b38cce0efa8 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -233,12 +233,12 @@ of being added to Rust. - [x] fixunstfdi.c - [x] fixunstfsi.c - [x] fixunstfti.c -- [ ] floatditf.c -- [ ] floatsitf.c -- [ ] floattitf.c -- [ ] floatunditf.c -- [ ] floatunsitf.c -- [ ] floatuntitf.c +- [x] floatditf.c +- [x] floatsitf.c +- [x] floattitf.c +- [x] floatunditf.c +- [x] floatunsitf.c +- [x] floatuntitf.c - [x] multf3.c - [x] powitf2.c - [x] subtf3.c diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 2863c979fa3ba..22ec9e4d27549 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -532,10 +532,6 @@ mod c { if (target.arch == "aarch64" || target.arch == "arm64ec") && consider_float_intrinsics { sources.extend(&[ ("__comparetf2", "comparetf2.c"), - ("__floatditf", "floatditf.c"), - ("__floatsitf", "floatsitf.c"), - ("__floatunditf", "floatunditf.c"), - ("__floatunsitf", "floatunsitf.c"), ("__fe_getround", "fp_mode.c"), ("__fe_raise_inexact", "fp_mode.c"), ]); @@ -550,21 +546,11 @@ mod c { } if target.arch == "mips64" { - sources.extend(&[ - ("__netf2", "comparetf2.c"), - ("__floatsitf", "floatsitf.c"), - ("__floatunsitf", "floatunsitf.c"), - ("__fe_getround", "fp_mode.c"), - ]); + sources.extend(&[("__netf2", "comparetf2.c"), ("__fe_getround", "fp_mode.c")]); } if target.arch == "loongarch64" { - sources.extend(&[ - ("__netf2", "comparetf2.c"), - ("__floatsitf", "floatsitf.c"), - ("__floatunsitf", "floatunsitf.c"), - ("__fe_getround", "fp_mode.c"), - ]); + sources.extend(&[("__netf2", "comparetf2.c"), ("__fe_getround", "fp_mode.c")]); } // Remove the assembly implementations that won't compile for the target diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 06d7723302713..368da6af2e4e0 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -264,14 +264,18 @@ mod intrinsics { /* i32 operations */ + // floatsisf + pub fn aeabi_i2f(x: i32) -> f32 { + x as f32 + } + // floatsidf pub fn aeabi_i2d(x: i32) -> f64 { x as f64 } - // floatsisf - pub fn aeabi_i2f(x: i32) -> f32 { - x as f32 + pub fn floatsitf(x: i32) -> f128 { + x as f128 } pub fn aeabi_idiv(a: i32, b: i32) -> i32 { @@ -294,6 +298,10 @@ mod intrinsics { x as f64 } + pub fn floatditf(x: i64) -> f128 { + x as f128 + } + pub fn mulodi4(a: i64, b: i64) -> i64 { a * b } @@ -314,6 +322,18 @@ mod intrinsics { /* i128 operations */ + pub fn floattisf(x: i128) -> f32 { + x as f32 + } + + pub fn floattidf(x: i128) -> f64 { + x as f64 + } + + pub fn floattitf(x: i128) -> f128 { + x as f128 + } + pub fn lshrti3(a: i128, b: usize) -> i128 { a >> b } @@ -328,14 +348,18 @@ mod intrinsics { /* u32 operations */ + // floatunsisf + pub fn aeabi_ui2f(x: u32) -> f32 { + x as f32 + } + // floatunsidf pub fn aeabi_ui2d(x: u32) -> f64 { x as f64 } - // floatunsisf - pub fn aeabi_ui2f(x: u32) -> f32 { - x as f32 + pub fn floatunsitf(x: u32) -> f128 { + x as f128 } pub fn aeabi_uidiv(a: u32, b: u32) -> u32 { @@ -358,6 +382,10 @@ mod intrinsics { x as f64 } + pub fn floatunditf(x: u64) -> f128 { + x as f128 + } + // udivdi3 pub fn aeabi_uldivmod(a: u64, b: u64) -> u64 { a * b @@ -369,6 +397,18 @@ mod intrinsics { /* u128 operations */ + pub fn floatuntisf(x: u128) -> f32 { + x as f32 + } + + pub fn floatuntidf(x: u128) -> f64 { + x as f64 + } + + pub fn floatuntitf(x: u128) -> f128 { + x as f128 + } + pub fn muloti4(a: u128, b: u128) -> Option { a.checked_mul(b) } @@ -466,6 +506,16 @@ fn run() { bb(fixunstfsi(bb(2.))); #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] bb(fixunstfti(bb(2.))); + bb(floatditf(bb(2))); + bb(floatsitf(bb(2))); + bb(floattidf(bb(2))); + bb(floattisf(bb(2))); + bb(floattitf(bb(2))); + bb(floatunditf(bb(2))); + bb(floatunsitf(bb(2))); + bb(floatuntidf(bb(2))); + bb(floatuntisf(bb(2))); + bb(floatuntitf(bb(2))); bb(gttf(bb(2.), bb(2.))); bb(lshrti3(bb(2), bb(2))); bb(lttf(bb(2.), bb(2.))); diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index da87b3caef827..4aea67c915275 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -104,6 +104,24 @@ mod int_to_float { repr::(e, m) } + #[cfg(f128_enabled)] + pub fn u32_to_f128_bits(i: u32) -> u128 { + if i == 0 { + return 0; + } + let n = i.leading_zeros(); + + // Shift into mantissa position that is correct for the type, but shifted into the lower + // 64 bits over so can can avoid 128-bit math. + let m = (i as u64) << (shift_f_gt_i::(n) - 64); + let e = exp::(n) as u64 - 1; + // High 64 bits of f128 representation. + let h = (e << (f128::SIGNIFICAND_BITS - 64)) + m; + + // Shift back to the high bits, the rest of the mantissa will always be 0. + (h as u128) << 64 + } + pub fn u64_to_f32_bits(i: u64) -> u32 { let n = i.leading_zeros(); let i_m = i.wrapping_shl(n); @@ -130,6 +148,18 @@ mod int_to_float { repr::(e, m) } + #[cfg(f128_enabled)] + pub fn u64_to_f128_bits(i: u64) -> u128 { + if i == 0 { + return 0; + } + let n = i.leading_zeros(); + // Mantissa with implicit bit set + let m = (i as u128) << shift_f_gt_i::(n); + let e = exp::(n) - 1; + repr::(e, m) + } + pub fn u128_to_f32_bits(i: u128) -> u32 { let n = i.leading_zeros(); let i_m = i.wrapping_shl(n); // Mantissa, shifted so the first bit is nonzero @@ -162,6 +192,20 @@ mod int_to_float { let e = if i == 0 { 0 } else { exp::(n) - 1 }; repr::(e, m) } + + #[cfg(f128_enabled)] + pub fn u128_to_f128_bits(i: u128) -> u128 { + if i == 0 { + return 0; + } + let n = i.leading_zeros(); + // Mantissa with implicit bit set + let m_base = (i << n) >> f128::EXPONENT_BITS; + let adj = (i << n) << (f128::SIGNIFICAND_BITS + 1); + let m = m_adj::(m_base, adj); + let e = exp::(n) - 1; + repr::(e, m) + } } // Conversions from unsigned integers to floats. @@ -195,6 +239,24 @@ intrinsics! { pub extern "C" fn __floatuntidf(i: u128) -> f64 { f64::from_bits(int_to_float::u128_to_f64_bits(i)) } + + #[ppc_alias = __floatunsikf] + #[cfg(f128_enabled)] + pub extern "C" fn __floatunsitf(i: u32) -> f128 { + f128::from_bits(int_to_float::u32_to_f128_bits(i)) + } + + #[ppc_alias = __floatundikf] + #[cfg(f128_enabled)] + pub extern "C" fn __floatunditf(i: u64) -> f128 { + f128::from_bits(int_to_float::u64_to_f128_bits(i)) + } + + #[ppc_alias = __floatuntikf] + #[cfg(f128_enabled)] + pub extern "C" fn __floatuntitf(i: u128) -> f128 { + f128::from_bits(int_to_float::u128_to_f128_bits(i)) + } } // Conversions from signed integers to floats. @@ -228,6 +290,24 @@ intrinsics! { pub extern "C" fn __floattidf(i: i128) -> f64 { int_to_float::signed(i, int_to_float::u128_to_f64_bits) } + + #[ppc_alias = __floatsikf] + #[cfg(f128_enabled)] + pub extern "C" fn __floatsitf(i: i32) -> f128 { + int_to_float::signed(i, int_to_float::u32_to_f128_bits) + } + + #[ppc_alias = __floatdikf] + #[cfg(f128_enabled)] + pub extern "C" fn __floatditf(i: i64) -> f128 { + int_to_float::signed(i, int_to_float::u64_to_f128_bits) + } + + #[ppc_alias = __floattikf] + #[cfg(f128_enabled)] + pub extern "C" fn __floattitf(i: i128) -> f128 { + int_to_float::signed(i, int_to_float::u128_to_f128_bits) + } } /// Generic float to unsigned int conversions. diff --git a/library/compiler-builtins/testcrate/benches/float_conv.rs b/library/compiler-builtins/testcrate/benches/float_conv.rs index de2043b04f859..0625a1ae5dd4e 100644 --- a/library/compiler-builtins/testcrate/benches/float_conv.rs +++ b/library/compiler-builtins/testcrate/benches/float_conv.rs @@ -1,7 +1,8 @@ #![allow(improper_ctypes)] +#![cfg_attr(f128_enabled, feature(f128))] use compiler_builtins::float::conv; -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{criterion_main, Criterion}; use testcrate::float_bench; /* unsigned int -> float */ @@ -76,6 +77,18 @@ float_bench! { ], } +#[cfg(f128_enabled)] +float_bench! { + name: conv_u32_f128, + sig: (a: u32) -> f128, + crate_fn: conv::__floatunsitf, + crate_fn_ppc: conv::__floatunsikf, + sys_fn: __floatunsitf, + sys_fn_ppc: __floatunsikf, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + float_bench! { name: conv_u64_f32, sig: (a: u64) -> f32, @@ -118,6 +131,18 @@ float_bench! { ], } +#[cfg(f128_enabled)] +float_bench! { + name: conv_u64_f128, + sig: (a: u64) -> f128, + crate_fn: conv::__floatunditf, + crate_fn_ppc: conv::__floatundikf, + sys_fn: __floatunditf, + sys_fn_ppc: __floatundikf, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + float_bench! { name: conv_u128_f32, sig: (a: u128) -> f32, @@ -136,6 +161,18 @@ float_bench! { asm: [] } +#[cfg(f128_enabled)] +float_bench! { + name: conv_u128_f128, + sig: (a: u128) -> f128, + crate_fn: conv::__floatuntitf, + crate_fn_ppc: conv::__floatuntikf, + sys_fn: __floatuntitf, + sys_fn_ppc: __floatuntikf, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + /* signed int -> float */ float_bench! { @@ -205,6 +242,18 @@ float_bench! { ], } +#[cfg(f128_enabled)] +float_bench! { + name: conv_i32_f128, + sig: (a: i32) -> f128, + crate_fn: conv::__floatsitf, + crate_fn_ppc: conv::__floatsikf, + sys_fn: __floatsitf, + sys_fn_ppc: __floatsikf, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + float_bench! { name: conv_i64_f32, sig: (a: i64) -> f32, @@ -272,6 +321,18 @@ float_bench! { ], } +#[cfg(f128_enabled)] +float_bench! { + name: conv_i64_f128, + sig: (a: i64) -> f128, + crate_fn: conv::__floatditf, + crate_fn_ppc: conv::__floatdikf, + sys_fn: __floatditf, + sys_fn_ppc: __floatdikf, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + float_bench! { name: conv_i128_f32, sig: (a: i128) -> f32, @@ -290,6 +351,18 @@ float_bench! { asm: [] } +#[cfg(f128_enabled)] +float_bench! { + name: conv_i128_f128, + sig: (a: i128) -> f128, + crate_fn: conv::__floattitf, + crate_fn_ppc: conv::__floattikf, + sys_fn: __floattitf, + sys_fn_ppc: __floattikf, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + /* float -> unsigned int */ #[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] @@ -397,6 +470,39 @@ float_bench! { asm: [] } +#[cfg(f128_enabled)] +float_bench! { + name: conv_f128_u32, + sig: (a: f128) -> u32, + crate_fn: conv::__fixunstfsi, + crate_fn_ppc: conv::__fixunskfsi, + sys_fn: __fixunstfsi, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + +#[cfg(f128_enabled)] +float_bench! { + name: conv_f128_u64, + sig: (a: f128) -> u64, + crate_fn: conv::__fixunstfdi, + crate_fn_ppc: conv::__fixunskfdi, + sys_fn: __fixunstfdi, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + +#[cfg(f128_enabled)] +float_bench! { + name: conv_f128_u128, + sig: (a: f128) -> u128, + crate_fn: conv::__fixunstfti, + crate_fn_ppc: conv::__fixunskfti, + sys_fn: __fixunstfti, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + /* float -> signed int */ #[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] @@ -504,43 +610,79 @@ float_bench! { asm: [] } -criterion_group!( - float_conv, - conv_u32_f32, - conv_u32_f64, - conv_u64_f32, - conv_u64_f64, - conv_u128_f32, - conv_u128_f64, - conv_i32_f32, - conv_i32_f64, - conv_i64_f32, - conv_i64_f64, - conv_i128_f32, - conv_i128_f64, - conv_f64_u32, - conv_f64_u64, - conv_f64_u128, - conv_f64_i32, - conv_f64_i64, - conv_f64_i128, -); - -// FIXME: ppc64le has a sporadic overflow panic in the crate functions -// -#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] -criterion_group!( - float_conv_not_ppc64le, - conv_f32_u32, - conv_f32_u64, - conv_f32_u128, - conv_f32_i32, - conv_f32_i64, - conv_f32_i128, -); - -#[cfg(all(target_arch = "powerpc64", target_endian = "little"))] -criterion_main!(float_conv); +#[cfg(f128_enabled)] +float_bench! { + name: conv_f128_i32, + sig: (a: f128) -> i32, + crate_fn: conv::__fixtfsi, + crate_fn_ppc: conv::__fixkfsi, + sys_fn: __fixtfsi, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} -#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] -criterion_main!(float_conv, float_conv_not_ppc64le); +#[cfg(f128_enabled)] +float_bench! { + name: conv_f128_i64, + sig: (a: f128) -> i64, + crate_fn: conv::__fixtfdi, + crate_fn_ppc: conv::__fixkfdi, + sys_fn: __fixtfdi, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + +#[cfg(f128_enabled)] +float_bench! { + name: conv_f128_i128, + sig: (a: f128) -> i128, + crate_fn: conv::__fixtfti, + crate_fn_ppc: conv::__fixkfti, + sys_fn: __fixtfti, + sys_available: not(feature = "no-sys-f16-f128-convert"), + asm: [] +} + +pub fn float_conv() { + let mut criterion = Criterion::default().configure_from_args(); + + conv_u32_f32(&mut criterion); + conv_u32_f64(&mut criterion); + conv_u64_f32(&mut criterion); + conv_u64_f64(&mut criterion); + conv_u128_f32(&mut criterion); + conv_u128_f64(&mut criterion); + conv_i32_f32(&mut criterion); + conv_i32_f64(&mut criterion); + conv_i64_f32(&mut criterion); + conv_i64_f64(&mut criterion); + conv_i128_f32(&mut criterion); + conv_i128_f64(&mut criterion); + conv_f64_u32(&mut criterion); + conv_f64_u64(&mut criterion); + conv_f64_u128(&mut criterion); + conv_f64_i32(&mut criterion); + conv_f64_i64(&mut criterion); + conv_f64_i128(&mut criterion); + + #[cfg(all(f128_enabled))] + // FIXME: ppc64le has a sporadic overflow panic in the crate functions + // + #[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] + { + conv_u32_f128(&mut criterion); + conv_u64_f128(&mut criterion); + conv_u128_f128(&mut criterion); + conv_i32_f128(&mut criterion); + conv_i64_f128(&mut criterion); + conv_i128_f128(&mut criterion); + conv_f128_u32(&mut criterion); + conv_f128_u64(&mut criterion); + conv_f128_u128(&mut criterion); + conv_f128_i32(&mut criterion); + conv_f128_i64(&mut criterion); + conv_f128_i128(&mut criterion); + } +} + +criterion_main!(float_conv); diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 01cc588cf3cf2..a08748af78159 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -117,6 +117,28 @@ mod i_to_f { u128, __floatuntidf; i128, __floattidf; } + + #[cfg(not(feature = "no-f16-f128"))] + #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + i_to_f! { f128, Quad, not(feature = "no-sys-f128-int-convert"), + u32, __floatunsitf; + i32, __floatsitf; + u64, __floatunditf; + i64, __floatditf; + u128, __floatuntitf; + i128, __floattitf; + } + + #[cfg(not(feature = "no-f16-f128"))] + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + i_to_f! { f128, Quad, not(feature = "no-sys-f128-int-convert"), + u32, __floatunsikf; + i32, __floatsikf; + u64, __floatundikf; + i64, __floatdikf; + u128, __floatuntikf; + i128, __floattikf; + } } // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 From 9818afad7c5952cbfbb80a064055ca8e1860dfbb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 30 Oct 2024 12:27:59 -0500 Subject: [PATCH 1419/4206] Remove the unneeded `isqrt` feature gate [1] has been stabilized so we no longer need to enable it. [1]: https://github.com/rust-lang/rust/issues/116226 --- library/compiler-builtins/testcrate/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index 58419bf1bd07b..4154e0fb34f9e 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -15,7 +15,6 @@ #![no_std] #![cfg_attr(f128_enabled, feature(f128))] #![cfg_attr(f16_enabled, feature(f16))] -#![feature(isqrt)] pub mod bench; extern crate alloc; From 55236070450c7be6a8c20c3f880472e57632fc81 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 30 Oct 2024 13:45:53 -0500 Subject: [PATCH 1420/4206] Rename `canonical_name` to `base_name` "Canonical" isn't really the right word here, update to "base". --- .../libm/crates/libm-test/src/gen/random.rs | 3 +- .../libm/crates/libm-test/src/lib.rs | 2 +- .../libm/crates/libm-test/src/precision.rs | 32 +++++++++---------- .../libm/crates/libm-test/src/test_traits.rs | 8 ++--- .../libm/src/math/support/macros.rs | 8 ++--- 5 files changed, 27 insertions(+), 26 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index c73937aacc9fe..d03d1ff797f29 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -110,6 +110,7 @@ pub fn get_test_cases(ctx: &CheckCtx) -> impl Iterator, { - let inputs = if ctx.fname == "jn" || ctx.fname == "jnf" { &TEST_CASES_JN } else { &TEST_CASES }; + let inputs = + if ctx.fn_name == "jn" || ctx.fn_name == "jnf" { &TEST_CASES_JN } else { &TEST_CASES }; inputs.get_cases() } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 31b95e46c0682..6c7a3f5ece288 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -18,7 +18,7 @@ include!(concat!(env!("OUT_DIR"), "/all_files.rs")); /// 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`. -pub fn canonical_name(name: &str) -> &str { +pub fn base_name(name: &str) -> &str { let known_mappings = &[ ("erff", "erf"), ("erf", "erf"), diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index e2ad638c41231..9ef0e818d13c8 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -111,25 +111,25 @@ impl MaybeOverride<(f32,)> for SpecialCase { ctx: &CheckCtx, ) -> Option { if ctx.basis == CheckBasis::Musl { - if ctx.fname == "expm1f" && input.0 > 80.0 && actual.is_infinite() { + if ctx.fn_name == "expm1f" && input.0 > 80.0 && actual.is_infinite() { // we return infinity but the number is representable return XFAIL; } - if ctx.fname == "sinhf" && input.0.abs() > 80.0 && actual.is_nan() { + if ctx.fn_name == "sinhf" && input.0.abs() > 80.0 && actual.is_nan() { // we return some NaN that should be real values or infinite // doesn't seem to happen on x86 return XFAIL; } } - if ctx.fname == "acoshf" && input.0 < -1.0 { + if ctx.fn_name == "acoshf" && input.0 < -1.0 { // acoshf is undefined for x <= 1.0, but we return a random result at lower // values. return XFAIL; } - if ctx.fname == "lgammaf" || ctx.fname == "lgammaf_r" && input.0 < 0.0 { + if ctx.fn_name == "lgammaf" || ctx.fn_name == "lgammaf_r" && input.0 < 0.0 { // loggamma should not be defined for x < 0, yet we both return results return XFAIL; } @@ -146,7 +146,7 @@ impl MaybeOverride<(f32,)> for SpecialCase { // On MPFR for lgammaf_r, we set -1 as the integer result for negative infinity but MPFR // sets +1 if ctx.basis == CheckBasis::Mpfr - && ctx.fname == "lgammaf_r" + && ctx.fn_name == "lgammaf_r" && input.0 == f32::NEG_INFINITY && actual.abs() == expected.abs() { @@ -166,13 +166,13 @@ impl MaybeOverride<(f64,)> for SpecialCase { ctx: &CheckCtx, ) -> Option { if ctx.basis == CheckBasis::Musl { - if cfg!(target_arch = "x86") && ctx.fname == "acosh" && input.0 < 1.0 { + if cfg!(target_arch = "x86") && ctx.fn_name == "acosh" && input.0 < 1.0 { // The function is undefined, both implementations return random results return SKIP; } if cfg!(x86_no_sse) - && ctx.fname == "ceil" + && ctx.fn_name == "ceil" && input.0 < 0.0 && input.0 > -1.0 && expected == F::ZERO @@ -183,13 +183,13 @@ impl MaybeOverride<(f64,)> for SpecialCase { } } - if ctx.fname == "acosh" && input.0 < 1.0 { + if ctx.fn_name == "acosh" && input.0 < 1.0 { // The function is undefined for the inputs, musl and our libm both return // random results. return XFAIL; } - if ctx.fname == "lgamma" || ctx.fname == "lgamma_r" && input.0 < 0.0 { + if ctx.fn_name == "lgamma" || ctx.fn_name == "lgamma_r" && input.0 < 0.0 { // loggamma should not be defined for x < 0, yet we both return results return XFAIL; } @@ -206,7 +206,7 @@ impl MaybeOverride<(f64,)> for SpecialCase { // On MPFR for lgamma_r, we set -1 as the integer result for negative infinity but MPFR // sets +1 if ctx.basis == CheckBasis::Mpfr - && ctx.fname == "lgamma_r" + && ctx.fn_name == "lgamma_r" && input.0 == f64::NEG_INFINITY && actual.abs() == expected.abs() { @@ -219,7 +219,7 @@ impl MaybeOverride<(f64,)> for SpecialCase { /// Check NaN bits if the function requires it fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Option { - if !(ctx.canonical_name == "fabs" || ctx.canonical_name == "copysign") { + if !(ctx.base_name == "fabs" || ctx.base_name == "copysign") { return None; } @@ -277,7 +277,7 @@ fn maybe_skip_binop_nan( ) -> Option { match ctx.basis { CheckBasis::Musl => { - if (ctx.canonical_name == "fmax" || ctx.canonical_name == "fmin") + if (ctx.base_name == "fmax" || ctx.base_name == "fmin") && (input.0.is_nan() || input.1.is_nan()) && expected.is_nan() { @@ -287,7 +287,7 @@ fn maybe_skip_binop_nan( } } CheckBasis::Mpfr => { - if ctx.canonical_name == "copysign" && input.1.is_nan() { + if ctx.base_name == "copysign" && input.1.is_nan() { SKIP } else { None @@ -308,7 +308,7 @@ impl MaybeOverride<(i32, f32)> for SpecialCase { CheckBasis::Musl => bessel_prec_dropoff(input, ulp, ctx), CheckBasis::Mpfr => { // We return +0.0, MPFR returns -0.0 - if ctx.fname == "jnf" + if ctx.fn_name == "jnf" && input.1 == f32::NEG_INFINITY && actual == F::ZERO && expected == F::ZERO @@ -333,7 +333,7 @@ impl MaybeOverride<(i32, f64)> for SpecialCase { CheckBasis::Musl => bessel_prec_dropoff(input, ulp, ctx), CheckBasis::Mpfr => { // We return +0.0, MPFR returns -0.0 - if ctx.fname == "jn" + if ctx.fn_name == "jn" && input.1 == f64::NEG_INFINITY && actual == F::ZERO && expected == F::ZERO @@ -353,7 +353,7 @@ fn bessel_prec_dropoff( ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - if ctx.canonical_name == "jn" { + if ctx.base_name == "jn" { if input.0 > 4000 { return XFAIL; } else if input.0 > 2000 { diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index deb837887fafa..34e15e0b28632 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -33,17 +33,17 @@ pub struct CheckCtx { /// Allowed ULP deviation pub ulp: u32, /// Function name. - pub fname: &'static str, + pub fn_name: &'static str, /// Return the unsuffixed version of the function name. - pub canonical_name: &'static str, + pub base_name: &'static str, /// Source of truth for tests. pub basis: CheckBasis, } impl CheckCtx { pub fn new(ulp: u32, fname: &'static str, basis: CheckBasis) -> Self { - let canonical_fname = crate::canonical_name(fname); - Self { ulp, fname, canonical_name: canonical_fname, basis } + let base_name = crate::base_name(fname); + Self { ulp, fn_name: fname, base_name, basis } } } diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index f85a6122ee8a5..b14bbec388d22 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -57,7 +57,7 @@ macro_rules! cfg_if { /// (`unstable-intrinsics`, `arch`, `force-soft-floats`), this macro handles that part. macro_rules! select_implementation { ( - name: $fname:ident, + name: $fn_name:ident, // Configuration meta for when to use arch-specific implementation that requires hard // float ops $( use_arch: $use_arch:meta, )? @@ -76,7 +76,7 @@ macro_rules! select_implementation { select_implementation! { @cfg $($use_arch_required)?; if true { - return super::arch::$fname( $($arg),+ ); + return super::arch::$fn_name( $($arg),+ ); } } @@ -86,7 +86,7 @@ macro_rules! select_implementation { @cfg $($use_arch)?; // Wrap in `if true` to avoid unused warnings if true { - return super::arch::$fname( $($arg),+ ); + return super::arch::$fn_name( $($arg),+ ); } } @@ -96,7 +96,7 @@ macro_rules! select_implementation { select_implementation! { @cfg $( $use_intrinsic )?; if true { - return super::arch::intrinsics::$fname( $($arg),+ ); + return super::arch::intrinsics::$fn_name( $($arg),+ ); } } }; From baae082fc5227a0e7e34fcee2e441d14d0044320 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Thu, 31 Oct 2024 19:29:13 +0800 Subject: [PATCH 1421/4206] ci: add support for loongarch64-unknown-linux-gnu --- .../libm/.github/workflows/main.yml | 2 ++ .../docker/loongarch64-unknown-linux-gnu/Dockerfile | 13 +++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 library/compiler-builtins/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index cc0d23ffc2f1e..f0c5fe7c03e50 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -32,6 +32,8 @@ jobs: os: ubuntu-latest - target: i686-unknown-linux-gnu os: ubuntu-latest + - target: loongarch64-unknown-linux-gnu + os: ubuntu-latest - target: powerpc-unknown-linux-gnu os: ubuntu-latest - target: powerpc64-unknown-linux-gnu diff --git a/library/compiler-builtins/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile new file mode 100644 index 0000000000000..a9ce320e8b4ab --- /dev/null +++ b/library/compiler-builtins/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,13 @@ +FROM ubuntu:24.04 + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user-static ca-certificates \ + gcc-14-loongarch64-linux-gnu libc6-dev-loong64-cross + +ENV CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_LINKER=loongarch64-linux-gnu-gcc-14 \ + CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_RUNNER=qemu-loongarch64-static \ + AR_loongarch64_unknown_linux_gnu=loongarch64-linux-gnu-ar \ + CC_loongarch64_unknown_linux_gnu=loongarch64-linux-gnu-gcc-14 \ + QEMU_LD_PREFIX=/usr/loongarch64-linux-gnu \ + RUST_TEST_THREADS=1 From 94e6ed373a0597f4a9c6141c7a5e6d5fa0209daf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:36:39 +0000 Subject: [PATCH 1422/4206] chore: release v0.1.137 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 4a85e5215b279..ecd5ecd082278 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.136" +version = "0.1.137" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From abff7cd82a392c48e141d5f3f09bd02869352d9b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Oct 2024 18:27:01 -0500 Subject: [PATCH 1423/4206] Add benchmarks against musl libm Add a benchmark for each function that checks against `musl_math_sys`. --- .../libm/crates/libm-test/Cargo.toml | 13 ++ .../libm/crates/libm-test/benches/random.rs | 119 ++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 library/compiler-builtins/libm/crates/libm-test/benches/random.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 72ac57232b3d1..fedf745ed7f42 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -15,6 +15,12 @@ test-multiprecision = ["dep:az", "dep:rug"] # Build our own musl for testing and benchmarks build-musl = ["dep:musl-math-sys"] +# Enable report generation without bringing in more dependencies by default +benchmarking-reports = ["criterion/plotters", "criterion/html_reports"] + +# Run with a reduced set of benchmarks, such as for CI +short-benchmarks = [] + [dependencies] anyhow = "1.0.90" az = { version = "1.2.1", optional = true } @@ -32,3 +38,10 @@ getrandom = { version = "0.2", features = ["js"] } [build-dependencies] rand = { version = "0.8.5", optional = true } + +[dev-dependencies] +criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } + +[[bench]] +name = "random" +harness = false diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs new file mode 100644 index 0000000000000..6c9047c3cdb4f --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -0,0 +1,119 @@ +use std::hint::black_box; +use std::time::Duration; + +use criterion::{Criterion, criterion_main}; +use libm_test::gen::random; +use libm_test::{CheckBasis, CheckCtx, TupleCall}; + +/// Benchmark with this many items to get a variety +const BENCH_ITER_ITEMS: usize = if cfg!(feature = "short-benchmarks") { 50 } else { 500 }; + +macro_rules! musl_rand_benches { + ( + fn_name: $fn_name:ident, + CFn: $CFn:ty, + CArgs: $CArgs:ty, + CRet: $CRet:ty, + RustFn: $RustFn:ty, + RustArgs: $RustArgs:ty, + RustRet: $RustRet:ty, + fn_extra: $skip_on_i586:expr, + ) => { + paste::paste! { + fn [< musl_bench_ $fn_name >](c: &mut Criterion) { + let fn_name = stringify!($fn_name); + + let ulp = libm_test::musl_allowed_ulp(fn_name); + let ctx = CheckCtx::new(ulp, fn_name, CheckBasis::Musl); + let benchvec: Vec<_> = random::get_test_cases::<$RustArgs>(&ctx) + .take(BENCH_ITER_ITEMS) + .collect(); + + // Perform a sanity check that we are benchmarking the same thing + // Don't test against musl if it is not available + #[cfg(feature = "build-musl")] + for input in benchvec.iter().copied() { + use anyhow::Context; + use libm_test::{CheckBasis, CheckCtx, CheckOutput}; + + if cfg!(x86_no_sse) && $skip_on_i586 { + break; + } + + let musl_res = input.call(musl_math_sys::$fn_name as $CFn); + let crate_res = input.call(libm::$fn_name as $RustFn); + + let ctx = CheckCtx::new(ulp, fn_name, CheckBasis::Musl); + crate_res.validate(musl_res, input, &ctx).context(fn_name).unwrap(); + } + + /* Function pointers are black boxed to avoid inlining in the benchmark loop */ + + let mut group = c.benchmark_group(fn_name); + group.bench_function("crate", |b| b.iter(|| { + let f = black_box(libm::$fn_name as $RustFn); + for input in benchvec.iter().copied() { + input.call(f); + } + })); + + // Don't test against musl if it is not available + #[cfg(feature = "build-musl")] + group.bench_function("musl", |b| b.iter(|| { + let f = black_box(musl_math_sys::$fn_name as $CFn); + for input in benchvec.iter().copied() { + input.call(f); + } + })); + } + } + }; +} + +libm_macros::for_each_function! { + callback: musl_rand_benches, + skip: [], + fn_extra: match MACRO_FN_NAME { + // FIXME(correctness): wrong result on i586 + exp10 | exp10f | exp2 | exp2f => true, + _ => false + } +} + +macro_rules! run_callback { + ( + fn_name: $fn_name:ident, + CFn: $_CFn:ty, + CArgs: $_CArgs:ty, + CRet: $_CRet:ty, + RustFn: $_RustFn:ty, + RustArgs: $_RustArgs:ty, + RustRet: $_RustRet:ty, + extra: [$criterion:ident], + ) => { + paste::paste! { + [< musl_bench_ $fn_name >](&mut $criterion) + } + }; +} + +pub fn musl_random() { + let mut criterion = Criterion::default(); + + // For CI, run a short 0.5s warmup and 1.0s tests. This makes benchmarks complete in + // about the same time as other tests. + if cfg!(feature = "short-benchmarks") { + criterion = criterion + .warm_up_time(Duration::from_millis(500)) + .measurement_time(Duration::from_millis(1000)); + } + + criterion = criterion.configure_from_args(); + + libm_macros::for_each_function! { + callback: run_callback, + extra: [criterion], + }; +} + +criterion_main!(musl_random); From f770ec04b02282e652f38e1b6ec9da31e39777cc Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Oct 2024 18:27:58 -0500 Subject: [PATCH 1424/4206] Remove `libm-bench` This has been superseded by the benchmarks in `libm-test`. --- library/compiler-builtins/libm/Cargo.toml | 1 - .../libm/crates/libm-bench/Cargo.toml | 16 --- .../libm/crates/libm-bench/benches/bench.rs | 116 ------------------ 3 files changed, 133 deletions(-) delete mode 100644 library/compiler-builtins/libm/crates/libm-bench/Cargo.toml delete mode 100644 library/compiler-builtins/libm/crates/libm-bench/benches/bench.rs diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 2e74012eae442..1786277664a1f 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -38,7 +38,6 @@ force-soft-floats = [] resolver = "2" members = [ "crates/compiler-builtins-smoke-test", - "crates/libm-bench", "crates/libm-macros", "crates/libm-test", "crates/musl-math-sys", diff --git a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml b/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml deleted file mode 100644 index ee8c5820037f8..0000000000000 --- a/library/compiler-builtins/libm/crates/libm-bench/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "libm-bench" -version = "0.1.0" -authors = ["Gonzalo Brito Gadeschi "] -edition = "2021" -license = "MIT OR Apache-2.0" -publish = false - -[dependencies] -libm = { path = "../..", default-features = false } -rand = "0.8.5" -paste = "1.0.15" - -[features] -default = [] -unstable = [ "libm/unstable" ] diff --git a/library/compiler-builtins/libm/crates/libm-bench/benches/bench.rs b/library/compiler-builtins/libm/crates/libm-bench/benches/bench.rs deleted file mode 100644 index ca999b90f27c4..0000000000000 --- a/library/compiler-builtins/libm/crates/libm-bench/benches/bench.rs +++ /dev/null @@ -1,116 +0,0 @@ -#![feature(test)] -extern crate test; - -use rand::Rng; -use test::Bencher; - -macro_rules! unary { - ($($func:ident),*) => ($( - paste::item! { - #[bench] - pub fn [<$func>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let x = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func>](x))) - } - #[bench] - pub fn [<$func f>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let x = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func f>](x))) - } - } - )*); -} -macro_rules! binary { - ($($func:ident),*) => ($( - paste::item! { - #[bench] - pub fn [<$func>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let x = rng.gen::(); - let y = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func>](x, y))) - } - #[bench] - pub fn [<$func f>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let x = rng.gen::(); - let y = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func f>](x, y))) - } - } - )*); - ($($func:ident);*) => ($( - paste::item! { - #[bench] - pub fn [<$func>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let x = rng.gen::(); - let n = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func>](x, n))) - } - #[bench] - pub fn [<$func f>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let x = rng.gen::(); - let n = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func f>](x, n))) - } - } - )*); -} -macro_rules! trinary { - ($($func:ident),*) => ($( - paste::item! { - #[bench] - pub fn [<$func>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let x = rng.gen::(); - let y = rng.gen::(); - let z = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func>](x, y, z))) - } - #[bench] - pub fn [<$func f>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let x = rng.gen::(); - let y = rng.gen::(); - let z = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func f>](x, y, z))) - } - } - )*); -} -macro_rules! bessel { - ($($func:ident),*) => ($( - paste::item! { - #[bench] - pub fn [<$func>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let mut n = rng.gen::(); - n &= 0xffff; - let x = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func>](n, x))) - } - #[bench] - pub fn [<$func f>](bh: &mut Bencher) { - let mut rng = rand::thread_rng(); - let mut n = rng.gen::(); - n &= 0xffff; - let x = rng.gen::(); - bh.iter(|| test::black_box(libm::[<$func f>](n, x))) - } - } - )*); -} - -unary!( - acos, acosh, asin, atan, cbrt, ceil, cos, cosh, erf, exp, exp2, exp10, expm1, fabs, floor, j0, - j1, lgamma, log, log1p, log2, log10, rint, round, sin, sinh, sqrt, tan, tanh, tgamma, trunc, - y0, y1 -); -binary!(atan2, copysign, fdim, fmax, fmin, fmod, hypot, pow); -trinary!(fma); -bessel!(jn, yn); -binary!(ldexp; scalbn); From be72d14ed5af76e233a18d76b0222d5805cf9147 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Oct 2024 18:35:11 -0500 Subject: [PATCH 1425/4206] Check benchmarks in CI --- library/compiler-builtins/libm/.github/workflows/main.yml | 2 +- library/compiler-builtins/libm/ci/run.sh | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index f0c5fe7c03e50..bfd86497b4ecf 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -125,7 +125,7 @@ jobs: - uses: Swatinem/rust-cache@v2 - name: Download musl source run: ./ci/download-musl.sh - - run: cargo bench --all + - run: cargo bench --all --features libm-test/short-benchmarks,libm-test/build-musl msrv: name: Check MSRV diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 9f642326ba82d..a211bc98cbf97 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -83,4 +83,8 @@ else # unstable with a feature $cmd --features "unstable-intrinsics" $cmd --release --features "unstable-intrinsics" + + # Make sure benchmarks have correct results + $cmd --benches + $cmd --benches --release fi From 4c1772ed85c9cc7cb37ab26a2f369a1e54fda748 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 31 Oct 2024 22:47:11 -0500 Subject: [PATCH 1426/4206] Change prefixes used by the `Float` trait Change `EXPONENT_` to `EXP_` and `SIGNIFICAND_` to `SIG_`. These are pretty unambiguous, and just makes for less to type once these get used. --- .../libm/crates/libm-test/src/mpfloat.rs | 2 +- .../libm/src/math/support/float_traits.rs | 45 ++++++++++--------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 44962d11679f5..2e6fdae7f19d1 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -15,7 +15,7 @@ use crate::Float; /// Create a multiple-precision float with the correct number of bits for a concrete float type. fn new_mpfloat() -> MpFloat { - MpFloat::new(F::SIGNIFICAND_BITS + 1) + MpFloat::new(F::SIG_BITS + 1) } /// Set subnormal emulation and convert to a concrete float type. 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 4cf5d7c616578..f90e99d5228b2 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -27,34 +27,37 @@ pub trait Float: const ZERO: Self; const ONE: Self; + const INFINITY: Self; + const NEG_INFINITY: Self; + const NAN: Self; /// The bitwidth of the float type const BITS: u32; /// The bitwidth of the significand - const SIGNIFICAND_BITS: u32; + const SIG_BITS: u32; /// The bitwidth of the exponent - const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1; + const EXP_BITS: u32 = Self::BITS - Self::SIG_BITS - 1; /// The saturated value of the exponent (infinite representation), in the rightmost postiion. - const EXPONENT_MAX: u32 = (1 << Self::EXPONENT_BITS) - 1; + const EXP_MAX: u32 = (1 << Self::EXP_BITS) - 1; /// The exponent bias value - const EXPONENT_BIAS: u32 = Self::EXPONENT_MAX >> 1; + const EXP_BIAS: u32 = Self::EXP_MAX >> 1; /// A mask for the sign bit const SIGN_MASK: Self::Int; /// A mask for the significand - const SIGNIFICAND_MASK: Self::Int; + const SIG_MASK: Self::Int; + + /// A mask for the exponent + const EXP_MASK: Self::Int; /// The implicit bit of the float format const IMPLICIT_BIT: Self::Int; - /// A mask for the exponent - const EXPONENT_MASK: Self::Int; - /// Returns `self` transmuted to `Self::Int` fn to_bits(self) -> Self::Int; @@ -105,14 +108,17 @@ macro_rules! float_impl { const ZERO: Self = 0.0; const ONE: Self = 1.0; + const INFINITY: Self = Self::INFINITY; + const NEG_INFINITY: Self = Self::NEG_INFINITY; + const NAN: Self = Self::NAN; const BITS: u32 = $bits; - const SIGNIFICAND_BITS: u32 = $significand_bits; + const SIG_BITS: u32 = $significand_bits; const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); - const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1; - const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; - const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); + const SIG_MASK: Self::Int = (1 << Self::SIG_BITS) - 1; + const EXP_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIG_MASK); + const IMPLICIT_BIT: Self::Int = 1 << Self::SIG_BITS; fn to_bits(self) -> Self::Int { self.to_bits() @@ -126,8 +132,7 @@ macro_rules! float_impl { // 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::EXPONENT_MASK == $ty::EXPONENT_MASK - && x.to_bits() & $ty::SIGNIFICAND_MASK != 0 + x.to_bits() & $ty::EXP_MASK == $ty::EXP_MASK && x.to_bits() & $ty::SIG_MASK != 0 } if is_nan(self) && is_nan(rhs) { true } else { self.to_bits() == rhs.to_bits() } } @@ -135,10 +140,10 @@ macro_rules! float_impl { self.is_sign_negative() } fn exp(self) -> Self::ExpInt { - ((self.to_bits() & Self::EXPONENT_MASK) >> Self::SIGNIFICAND_BITS) as Self::ExpInt + ((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS) as Self::ExpInt } fn frac(self) -> Self::Int { - self.to_bits() & Self::SIGNIFICAND_MASK + self.to_bits() & Self::SIG_MASK } fn imp_frac(self) -> Self::Int { self.frac() | Self::IMPLICIT_BIT @@ -149,16 +154,16 @@ macro_rules! float_impl { fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self { Self::from_bits( ((negative as Self::Int) << (Self::BITS - 1)) - | ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) - | (significand & Self::SIGNIFICAND_MASK), + | ((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::EXPONENT_BITS); + 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::EXPONENT_MASK) == Self::Int::ZERO + (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO } } }; From 5f54ad6389397af45bf38e1deed2dc8d92bd11ca Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 31 Oct 2024 23:47:41 -0500 Subject: [PATCH 1427/4206] Update libm `Float` and `Int` with functions from the test traits The test versions of `Float` and `Int` have a few more methods and constants availablee. Update the in `libm` with everything missing from `libm_test` so we will be able to merge these. --- .../libm/src/math/support/float_traits.rs | 50 +++++++++++++++---- .../libm/src/math/support/int_traits.rs | 43 +++++++++++++--- 2 files changed, 77 insertions(+), 16 deletions(-) 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 f90e99d5228b2..a1d84faf2e254 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -1,4 +1,4 @@ -use core::ops; +use core::{fmt, ops}; use super::int_traits::{Int, MinInt}; @@ -6,7 +6,8 @@ use super::int_traits::{Int, MinInt}; #[allow(dead_code)] pub trait Float: Copy - + core::fmt::Debug + + fmt::Debug + + fmt::Display + PartialEq + PartialOrd + ops::AddAssign @@ -17,16 +18,17 @@ pub trait Float: + ops::Rem { /// A uint of the same width as the float - type Int: Int; + type Int: Int; /// A int of the same width as the float - type SignedInt: Int + MinInt; + 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; + const NEG_ONE: Self; const INFINITY: Self; const NEG_INFINITY: Self; const NAN: Self; @@ -69,9 +71,18 @@ pub trait Float: /// compared. fn eq_repr(self, rhs: Self) -> bool; - /// Returns true if the sign is negative + /// Returns true if the value is NaN. + fn is_nan(self) -> bool; + + /// Returns true if the value is +inf or -inf. + fn is_infinite(self) -> bool; + + /// Returns true if the sign is negative. fn is_sign_negative(self) -> bool; + /// Returns if `self` is subnormal + fn is_subnormal(self) -> bool; + /// Returns the exponent, not adjusting for bias. fn exp(self) -> Self::ExpInt; @@ -95,8 +106,11 @@ pub trait Float: /// Returns (normalized exponent, normalized significand) fn normalize(significand: Self::Int) -> (i32, Self::Int); - /// Returns if `self` is subnormal - fn is_subnormal(self) -> bool; + /// Returns a number composed of the magnitude of self and the sign of sign. + fn copysign(self, other: Self) -> Self; + + /// Returns a number that represents the sign of self. + fn signum(self) -> Self; } macro_rules! float_impl { @@ -108,6 +122,7 @@ macro_rules! float_impl { const ZERO: Self = 0.0; const ONE: Self = 1.0; + const NEG_ONE: Self = -1.0; const INFINITY: Self = Self::INFINITY; const NEG_INFINITY: Self = Self::NEG_INFINITY; const NAN: Self = Self::NAN; @@ -136,9 +151,18 @@ macro_rules! float_impl { } if is_nan(self) && is_nan(rhs) { true } else { self.to_bits() == rhs.to_bits() } } + fn is_nan(self) -> bool { + self.is_nan() + } + fn is_infinite(self) -> bool { + self.is_infinite() + } fn is_sign_negative(self) -> bool { self.is_sign_negative() } + fn is_subnormal(self) -> bool { + (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO + } fn exp(self) -> Self::ExpInt { ((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS) as Self::ExpInt } @@ -162,8 +186,16 @@ macro_rules! float_impl { 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 + fn copysign(self, other: Self) -> Self { + let mut x = self.to_bits(); + let y = other.to_bits(); + x &= !Self::SIGN_MASK; + x |= y & Self::SIGN_MASK; + Self::from_bits(x) + } + + fn signum(self) -> Self { + if self.is_nan() { self } else { Self::ONE.copysign(self) } } } }; 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 bdf3afd48cefd..c5feef8d7268c 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -12,7 +12,7 @@ pub trait MinInt: /// Type with the same width but other signedness type OtherSign: MinInt; /// Unsigned version of Self - type UnsignedInt: MinInt; + type Unsigned: MinInt; /// If `Self` is a signed integer const SIGNED: bool; @@ -30,6 +30,7 @@ pub trait MinInt: #[allow(dead_code)] pub trait Int: MinInt + + fmt::Display + PartialEq + PartialOrd + ops::AddAssign @@ -47,8 +48,10 @@ pub trait Int: + ops::BitXor + ops::BitAnd { - fn unsigned(self) -> Self::UnsignedInt; - fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; + fn signed(self) -> ::OtherSign; + fn unsigned(self) -> Self::Unsigned; + fn from_unsigned(unsigned: Self::Unsigned) -> Self; + fn abs(self) -> Self; fn from_bool(b: bool) -> Self; @@ -56,10 +59,12 @@ pub trait Int: fn logical_shr(self, other: u32) -> Self; /// Absolute difference between two integers. - fn abs_diff(self, other: Self) -> Self::UnsignedInt; + fn abs_diff(self, other: Self) -> Self::Unsigned; // copied from primitive integers, but put in a trait fn is_zero(self) -> bool; + fn checked_add(self, other: Self) -> Option; + fn checked_sub(self, other: Self) -> Option; fn wrapping_neg(self) -> Self; fn wrapping_add(self, other: Self) -> Self; fn wrapping_mul(self, other: Self) -> Self; @@ -86,6 +91,14 @@ macro_rules! int_impl_common { self == Self::ZERO } + fn checked_add(self, other: Self) -> Option { + self.checked_add(other) + } + + fn checked_sub(self, other: Self) -> Option { + self.checked_sub(other) + } + fn wrapping_neg(self) -> Self { ::wrapping_neg(self) } @@ -132,7 +145,7 @@ macro_rules! int_impl { ($ity:ty, $uty:ty) => { impl MinInt for $uty { type OtherSign = $ity; - type UnsignedInt = $uty; + type Unsigned = $uty; const BITS: u32 = ::ZERO.count_zeros(); const SIGNED: bool = Self::MIN != Self::ZERO; @@ -144,10 +157,18 @@ macro_rules! int_impl { } impl Int for $uty { - fn unsigned(self) -> $uty { + fn signed(self) -> $ity { + self as $ity + } + + fn unsigned(self) -> Self { self } + fn abs(self) -> Self { + unimplemented!() + } + // It makes writing macros easier if this is implemented for both signed and unsigned #[allow(clippy::wrong_self_convention)] fn from_unsigned(me: $uty) -> Self { @@ -163,7 +184,7 @@ macro_rules! int_impl { impl MinInt for $ity { type OtherSign = $uty; - type UnsignedInt = $uty; + type Unsigned = $uty; const BITS: u32 = ::ZERO.count_zeros(); const SIGNED: bool = Self::MIN != Self::ZERO; @@ -175,10 +196,18 @@ macro_rules! int_impl { } impl Int for $ity { + fn signed(self) -> Self { + self + } + fn unsigned(self) -> $uty { self as $uty } + fn abs(self) -> Self { + self.abs() + } + fn from_unsigned(me: $uty) -> Self { me as $ity } From 4b12a8404f3397c93d59711a3499a8e86213a015 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 31 Oct 2024 23:52:27 -0500 Subject: [PATCH 1428/4206] Expose the `support` module publicly with a test feature --- library/compiler-builtins/libm/Cargo.toml | 3 +++ .../libm/crates/compiler-builtins-smoke-test/Cargo.toml | 1 + library/compiler-builtins/libm/src/math/mod.rs | 9 ++++++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 1786277664a1f..98a60bfe3fe97 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -26,6 +26,9 @@ unstable = ["unstable-intrinsics"] # Enable calls to functions in `core::intrinsics` unstable-intrinsics = [] +# Make some internal things public for testing. +unstable-test-support = [] + # 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 diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index 7118bfe06f1d8..e75c4f42bfa2a 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -13,6 +13,7 @@ bench = false # Duplicated from libm's Cargo.toml unstable = [] unstable-intrinsics = [] +unstable-test-support = [] checked = [] force-soft-floats = [] diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 2cd77f1327b2c..afebdf5864c5d 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -74,9 +74,16 @@ macro_rules! div { }; } -// Private modules +// `support` may be public for testing +#[macro_use] +#[cfg(feature = "unstable-test-support")] +pub mod support; + #[macro_use] +#[cfg(not(feature = "unstable-test-support"))] mod support; + +// Private modules mod arch; mod expo2; mod fenv; From dbf8a4ebe5106a28c7c95dc87b38ce716d6950c4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 31 Oct 2024 23:53:03 -0500 Subject: [PATCH 1429/4206] Replace `libm_test::{Float, Int}` with `libm::{Float, Int}` This involves moving some things from full generic implementations (e.g. `impl SomeTrait for F { /* ... */ }` to generic functions and macros to implement traits that call them, due to orphan rule violations after `Float` became a not-in-crate trait. `Hex` was moved to `test_traits` so we can eliminate `num_traits`. --- .../libm/crates/libm-test/Cargo.toml | 2 +- .../libm/crates/libm-test/src/lib.rs | 5 +- .../libm/crates/libm-test/src/num_traits.rs | 214 -------------- .../libm/crates/libm-test/src/test_traits.rs | 261 +++++++++++++----- 4 files changed, 199 insertions(+), 283 deletions(-) delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index fedf745ed7f42..3587b44e6a47d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -24,7 +24,7 @@ short-benchmarks = [] [dependencies] anyhow = "1.0.90" az = { version = "1.2.1", optional = true } -libm = { path = "../.." } +libm = { path = "../..", features = ["unstable-test-support"] } libm-macros = { path = "../libm-macros" } musl-math-sys = { path = "../musl-math-sys", optional = true } paste = "1.0.15" diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 6c7a3f5ece288..56a872779d6cc 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -1,13 +1,12 @@ pub mod gen; #[cfg(feature = "test-multiprecision")] pub mod mpfloat; -mod num_traits; mod precision; mod test_traits; -pub use num_traits::{Float, Hex, Int}; +pub use libm::support::{Float, Int}; pub use precision::{MaybeOverride, SpecialCase, multiprec_allowed_ulp, musl_allowed_ulp}; -pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, TupleCall}; +pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, Hex, 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/crates/libm-test/src/num_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs deleted file mode 100644 index e16f4e4dca450..0000000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/num_traits.rs +++ /dev/null @@ -1,214 +0,0 @@ -use std::fmt; - -use crate::{MaybeOverride, SpecialCase, TestResult}; - -/// Common types and methods for floating point numbers. -pub trait Float: Copy + fmt::Display + fmt::Debug + PartialEq { - type Int: Int; - type SignedInt: Int + Int; - - const ZERO: Self; - const ONE: Self; - - /// The bitwidth of the float type - const BITS: u32; - - /// The bitwidth of the significand - const SIGNIFICAND_BITS: u32; - - /// The bitwidth of the exponent - const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1; - - fn is_nan(self) -> bool; - fn is_infinite(self) -> bool; - fn to_bits(self) -> Self::Int; - fn from_bits(bits: Self::Int) -> Self; - fn signum(self) -> Self; -} - -macro_rules! impl_float { - ($($fty:ty, $ui:ty, $si:ty, $significand_bits:expr;)+) => { - $( - impl Float for $fty { - type Int = $ui; - type SignedInt = $si; - - const ZERO: Self = 0.0; - const ONE: Self = 1.0; - - const BITS: u32 = <$ui>::BITS; - const SIGNIFICAND_BITS: u32 = $significand_bits; - - fn is_nan(self) -> bool { - self.is_nan() - } - fn is_infinite(self) -> bool { - self.is_infinite() - } - fn to_bits(self) -> Self::Int { - self.to_bits() - } - fn from_bits(bits: Self::Int) -> Self { - Self::from_bits(bits) - } - fn signum(self) -> Self { - self.signum() - } - } - - impl Hex for $fty { - fn hex(self) -> String { - self.to_bits().hex() - } - } - )+ - } -} - -impl_float!( - f32, u32, i32, 23; - f64, u64, i64, 52; -); - -/// Common types and methods for integers. -pub trait Int: Copy + fmt::Display + fmt::Debug + PartialEq { - type OtherSign: Int; - type Unsigned: Int; - const BITS: u32; - const SIGNED: bool; - - fn signed(self) -> ::OtherSign; - fn unsigned(self) -> Self::Unsigned; - fn checked_sub(self, other: Self) -> Option; - fn abs(self) -> Self; -} - -macro_rules! impl_int { - ($($ui:ty, $si:ty ;)+) => { - $( - impl Int for $ui { - type OtherSign = $si; - type Unsigned = Self; - const BITS: u32 = <$ui>::BITS; - const SIGNED: bool = false; - fn signed(self) -> Self::OtherSign { - self as $si - } - fn unsigned(self) -> Self { - self - } - fn checked_sub(self, other: Self) -> Option { - self.checked_sub(other) - } - fn abs(self) -> Self { - unimplemented!() - } - } - - impl Int for $si { - type OtherSign = $ui; - type Unsigned = $ui; - const BITS: u32 = <$ui>::BITS; - const SIGNED: bool = true; - fn signed(self) -> Self { - self - } - fn unsigned(self) -> $ui { - self as $ui - } - fn checked_sub(self, other: Self) -> Option { - self.checked_sub(other) - } - fn abs(self) -> Self { - self.abs() - } - } - - impl_int!(@for_both $si); - impl_int!(@for_both $ui); - - )+ - }; - - (@for_both $ty:ty) => { - impl Hex for $ty { - fn hex(self) -> String { - format!("{self:#0width$x}", width = ((Self::BITS / 4) + 2) as usize) - } - } - - impl $crate::CheckOutput for $ty - where - Input: Hex + fmt::Debug, - SpecialCase: MaybeOverride, - { - fn validate<'a>( - self, - expected: Self, - input: Input, - ctx: &$crate::CheckCtx, - ) -> TestResult { - if let Some(res) = SpecialCase::check_int(input, self, expected, ctx) { - return res; - } - - anyhow::ensure!( - self == expected, - "\ - \n input: {input:?} {ibits}\ - \n expected: {expected:<22?} {expbits}\ - \n actual: {self:<22?} {actbits}\ - ", - actbits = self.hex(), - expbits = expected.hex(), - ibits = input.hex(), - ); - - Ok(()) - } - } - } -} - -impl_int!( - u32, i32; - u64, i64; -); - -/// 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 { - fn hex(self) -> String; -} - -impl Hex for (T1,) -where - T1: Hex, -{ - fn hex(self) -> String { - format!("({},)", self.0.hex()) - } -} - -impl Hex for (T1, T2) -where - T1: Hex, - T2: Hex, -{ - fn hex(self) -> String { - format!("({}, {})", self.0.hex(), self.1.hex()) - } -} - -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()) - } -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index 34e15e0b28632..67df83fb49215 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -11,21 +11,7 @@ use std::fmt; use anyhow::{Context, bail, ensure}; -use crate::{Float, Hex, Int, MaybeOverride, SpecialCase, TestResult}; - -/// Implement this on types that can generate a sequence of tuples for test input. -pub trait GenerateInput { - fn get_cases(&self) -> impl Iterator; -} - -/// Trait for calling a function with a tuple as arguments. -/// -/// Implemented on the tuple with the function signature as the generic (so we can use the same -/// tuple for multiple signatures). -pub trait TupleCall: fmt::Debug { - type Output; - fn call(self, f: Func) -> Self::Output; -} +use crate::{Float, Int, MaybeOverride, SpecialCase, TestResult}; /// Context passed to [`CheckOutput`]. #[derive(Clone, Debug, PartialEq, Eq)] @@ -56,14 +42,38 @@ pub enum CheckBasis { Mpfr, } +/// Implement this on types that can generate a sequence of tuples for test input. +pub trait GenerateInput { + fn get_cases(&self) -> impl Iterator; +} + +/// Trait for calling a function with a tuple as arguments. +/// +/// Implemented on the tuple with the function signature as the generic (so we can use the same +/// tuple for multiple signatures). +pub trait TupleCall: fmt::Debug { + type Output; + fn call(self, f: Func) -> Self::Output; +} + /// 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. /// /// `input` is only used here for error messages. - fn validate<'a>(self, expected: Self, input: Input, ctx: &CheckCtx) -> TestResult; + 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 { + fn hex(self) -> String; } +/* implement `TupleCall` */ + impl TupleCall R> for (T1,) where T1: fmt::Debug, @@ -143,72 +153,193 @@ where } } -// Implement for floats -impl CheckOutput for F +/* implement `Hex` */ + +impl Hex for (T1,) where - F: Float + Hex, + T1: Hex, +{ + fn hex(self) -> String { + format!("({},)", self.0.hex()) + } +} + +impl Hex for (T1, T2) +where + T1: Hex, + T2: Hex, +{ + fn hex(self) -> String { + format!("({}, {})", self.0.hex(), self.1.hex()) + } +} + +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()) + } +} + +/* trait implementations for ints */ + +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) + } + } + + impl $crate::CheckOutput for $ty + where + Input: Hex + fmt::Debug, + SpecialCase: MaybeOverride, + { + fn validate<'a>( + self, + expected: Self, + input: Input, + ctx: &$crate::CheckCtx, + ) -> TestResult { + validate_int(self, expected, input, ctx) + } + } + )* + }; +} + +fn validate_int<'a, I, Input>(actual: I, expected: I, input: Input, ctx: &CheckCtx) -> TestResult +where + I: Int + Hex, Input: Hex + fmt::Debug, - u32: TryFrom, SpecialCase: MaybeOverride, { - fn validate<'a>(self, expected: Self, input: Input, ctx: &CheckCtx) -> TestResult { - // Create a wrapper function so we only need to `.with_context` once. - let inner = || -> TestResult { - let mut allowed_ulp = ctx.ulp; - - // If the tested function requires a nonstandard test, run it here. - if let Some(res) = - SpecialCase::check_float(input, self, expected, &mut allowed_ulp, ctx) - { - return res; + if let Some(res) = SpecialCase::check_int(input, actual, expected, ctx) { + return res; + } + + anyhow::ensure!( + actual == expected, + "\ + \n input: {input:?} {ibits}\ + \n expected: {expected:<22?} {expbits}\ + \n actual: {actual:<22?} {actbits}\ + ", + actbits = actual.hex(), + expbits = expected.hex(), + ibits = input.hex(), + ); + + Ok(()) +} + +impl_int!(u32, i32, u64, i64); + +/* trait implementations for floats */ + +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 + ) + } } - // Check when both are NaNs - if self.is_nan() && expected.is_nan() { - // By default, NaNs have nothing special to check. - return Ok(()); - } else if self.is_nan() || expected.is_nan() { - // Check when only one is a NaN - bail!("real value != NaN") + impl $crate::CheckOutput for $ty + where + Input: Hex + fmt::Debug, + SpecialCase: MaybeOverride, + { + fn validate<'a>( + self, + expected: Self, + input: Input, + ctx: &$crate::CheckCtx, + ) -> TestResult { + validate_float(self, expected, input, ctx) + } } + )* + }; +} + +fn validate_float<'a, F, Input>(actual: F, expected: F, input: Input, ctx: &CheckCtx) -> TestResult +where + F: Float + Hex, + Input: Hex + fmt::Debug, + u32: TryFrom, + SpecialCase: MaybeOverride, +{ + // Create a wrapper function so we only need to `.with_context` once. + let inner = || -> TestResult { + let mut allowed_ulp = ctx.ulp; - // Make sure that the signs are the same before checing ULP to avoid wraparound - let act_sig = self.signum(); - let exp_sig = expected.signum(); - ensure!(act_sig == exp_sig, "mismatched signs {act_sig} {exp_sig}"); + // If the tested function requires a nonstandard test, run it here. + if let Some(res) = SpecialCase::check_float(input, actual, expected, &mut allowed_ulp, ctx) + { + return res; + } - if self.is_infinite() ^ expected.is_infinite() { - bail!("mismatched infinities"); - } + // Check when both are NaNs + if actual.is_nan() && expected.is_nan() { + // By default, NaNs have nothing special to check. + return Ok(()); + } else if actual.is_nan() || expected.is_nan() { + // Check when only one is a NaN + bail!("real value != NaN") + } - let act_bits = self.to_bits().signed(); - let exp_bits = expected.to_bits().signed(); + // Make sure that the signs are the same before checing ULP to avoid wraparound + let act_sig = actual.signum(); + let exp_sig = expected.signum(); + ensure!(act_sig == exp_sig, "mismatched signs {act_sig} {exp_sig}"); - let ulp_diff = act_bits.checked_sub(exp_bits).unwrap().abs(); + if actual.is_infinite() ^ expected.is_infinite() { + bail!("mismatched infinities"); + } - let ulp_u32 = u32::try_from(ulp_diff) - .map_err(|e| anyhow::anyhow!("{e:?}: ulp of {ulp_diff} exceeds u32::MAX"))?; + let act_bits = actual.to_bits().signed(); + let exp_bits = expected.to_bits().signed(); - ensure!(ulp_u32 <= allowed_ulp, "ulp {ulp_diff} > {allowed_ulp}",); + let ulp_diff = act_bits.checked_sub(exp_bits).unwrap().abs(); - Ok(()) - }; + let ulp_u32 = u32::try_from(ulp_diff) + .map_err(|e| anyhow::anyhow!("{e:?}: ulp of {ulp_diff} exceeds u32::MAX"))?; - inner().with_context(|| { - format!( - "\ - \n input: {input:?} {ibits}\ - \n expected: {expected:<22?} {expbits}\ - \n actual: {self:<22?} {actbits}\ - ", - actbits = self.hex(), - expbits = expected.hex(), - ibits = input.hex(), - ) - }) - } + ensure!(ulp_u32 <= allowed_ulp, "ulp {ulp_diff} > {allowed_ulp}",); + + Ok(()) + }; + + inner().with_context(|| { + format!( + "\ + \n input: {input:?} {ibits}\ + \n expected: {expected:<22?} {expbits}\ + \n actual: {actual:<22?} {actbits}\ + ", + actbits = actual.hex(), + expbits = expected.hex(), + ibits = input.hex(), + ) + }) } +impl_float!(f32, f64); + +/* trait implementations for compound types */ + /// Implement `CheckOutput` for combinations of types. macro_rules! impl_tuples { ($(($a:ty, $b:ty);)*) => { From 53b3e71bbcab44510a0c3e0ff9e721a6592d677d Mon Sep 17 00:00:00 2001 From: hev Date: Fri, 1 Nov 2024 18:00:00 +0800 Subject: [PATCH 1430/4206] Disable `f16` for LoongArch64 (#722) Disable `f161` for LoongArch64 due to incorrect code generation on LLVM 19, which causes failures in `testcrate/tests/conv.rs`. This workaround will remain in place until llvm/llvm-project#109093 is merged or we upgrade to LLVM 20. --- library/compiler-builtins/configure.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs index e23c0e839359a..68b4d68e61bb1 100644 --- a/library/compiler-builtins/configure.rs +++ b/library/compiler-builtins/configure.rs @@ -64,6 +64,8 @@ pub fn configure_f16_f128(target: &Target) { "arm64ec" => (false, false), // `f16` crashes "s390x" => (false, true), + // FIXME(llvm): `f16` test failures fixed by + "loongarch64" => (false, true), // `f128` crashes "mips64" | "mips64r6" => (true, false), // `f128` crashes From ca996df5c14554ce6c237972a06f7e3f0c8ae919 Mon Sep 17 00:00:00 2001 From: hev Date: Fri, 1 Nov 2024 18:34:51 +0800 Subject: [PATCH 1431/4206] Use `f16_enabled`/`f128_enabled` in `examples/intrinsics.rs` (#724) Enable conditional compilation for intrinsics with `f16_enabled` and `f128_enabled` --- .../compiler-builtins/examples/intrinsics.rs | 122 +++++++++++++++--- 1 file changed, 106 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 368da6af2e4e0..ef7a3d43030d2 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -28,21 +28,28 @@ extern "C" {} mod intrinsics { /* f16 operations */ + #[cfg(f16_enabled)] pub fn extendhfsf(x: f16) -> f32 { x as f32 } + #[cfg(f16_enabled)] pub fn extendhfdf(x: f16) -> f64 { x as f64 } - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f16_enabled, + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] pub fn extendhftf(x: f16) -> f128 { x as f128 } /* f32 operations */ + #[cfg(f16_enabled)] pub fn truncsfhf(x: f32) -> f16 { x as f16 } @@ -52,6 +59,7 @@ mod intrinsics { x as f64 } + #[cfg(f128_enabled)] pub fn extendsftf(x: f32) -> f128 { x as f128 } @@ -191,73 +199,104 @@ mod intrinsics { /* f128 operations */ - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f16_enabled, + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] pub fn trunctfhf(x: f128) -> f16 { x as f16 } + #[cfg(f128_enabled)] pub fn trunctfsf(x: f128) -> f32 { x as f32 } + #[cfg(f128_enabled)] pub fn trunctfdf(x: f128) -> f64 { x as f64 } - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] pub fn fixtfsi(x: f128) -> i32 { x as i32 } - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] pub fn fixtfdi(x: f128) -> i64 { x as i64 } - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] pub fn fixtfti(x: f128) -> i128 { x as i128 } - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] pub fn fixunstfsi(x: f128) -> u32 { x as u32 } - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] pub fn fixunstfdi(x: f128) -> u64 { x as u64 } - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] pub fn fixunstfti(x: f128) -> u128 { x as u128 } + #[cfg(f128_enabled)] pub fn addtf(a: f128, b: f128) -> f128 { a + b } + #[cfg(f128_enabled)] pub fn eqtf(a: f128, b: f128) -> bool { a == b } + #[cfg(f128_enabled)] pub fn gttf(a: f128, b: f128) -> bool { a > b } + #[cfg(f128_enabled)] pub fn lttf(a: f128, b: f128) -> bool { a < b } + #[cfg(f128_enabled)] pub fn multf(a: f128, b: f128) -> f128 { a * b } + #[cfg(f128_enabled)] pub fn divtf(a: f128, b: f128) -> f128 { a / b } + #[cfg(f128_enabled)] pub fn subtf(a: f128, b: f128) -> f128 { a - b } @@ -274,6 +313,7 @@ mod intrinsics { x as f64 } + #[cfg(f128_enabled)] pub fn floatsitf(x: i32) -> f128 { x as f128 } @@ -298,6 +338,7 @@ mod intrinsics { x as f64 } + #[cfg(f128_enabled)] pub fn floatditf(x: i64) -> f128 { x as f128 } @@ -330,6 +371,7 @@ mod intrinsics { x as f64 } + #[cfg(f128_enabled)] pub fn floattitf(x: i128) -> f128 { x as f128 } @@ -358,6 +400,7 @@ mod intrinsics { x as f64 } + #[cfg(f128_enabled)] pub fn floatunsitf(x: u32) -> f128 { x as f128 } @@ -382,6 +425,7 @@ mod intrinsics { x as f64 } + #[cfg(f128_enabled)] pub fn floatunditf(x: u64) -> f128 { x as f128 } @@ -405,6 +449,7 @@ mod intrinsics { x as f64 } + #[cfg(f128_enabled)] pub fn floatuntitf(x: u128) -> f128 { x as f128 } @@ -440,6 +485,7 @@ fn run() { // FIXME(f16_f128): some PPC f128 <-> int conversion functions have the wrong names + #[cfg(f128_enabled)] bb(addtf(bb(2.), bb(2.))); bb(aeabi_d2f(bb(2.))); bb(aeabi_d2i(bb(2.))); @@ -482,54 +528,98 @@ fn run() { bb(aeabi_uldivmod(bb(2), bb(3))); bb(ashlti3(bb(2), bb(2))); bb(ashrti3(bb(2), bb(2))); + #[cfg(f128_enabled)] bb(divtf(bb(2.), bb(2.))); bb(divti3(bb(2), bb(2))); + #[cfg(f128_enabled)] bb(eqtf(bb(2.), bb(2.))); + #[cfg(f16_enabled)] bb(extendhfdf(bb(2.))); + #[cfg(f16_enabled)] bb(extendhfsf(bb(2.))); - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f16_enabled, + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] bb(extendhftf(bb(2.))); + #[cfg(f128_enabled)] bb(extendsftf(bb(2.))); bb(fixdfti(bb(2.))); bb(fixsfti(bb(2.))); - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] bb(fixtfdi(bb(2.))); - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] bb(fixtfsi(bb(2.))); - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] bb(fixtfti(bb(2.))); bb(fixunsdfti(bb(2.))); bb(fixunssfti(bb(2.))); - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] bb(fixunstfdi(bb(2.))); - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] bb(fixunstfsi(bb(2.))); - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] bb(fixunstfti(bb(2.))); + #[cfg(f128_enabled)] bb(floatditf(bb(2))); + #[cfg(f128_enabled)] bb(floatsitf(bb(2))); bb(floattidf(bb(2))); bb(floattisf(bb(2))); + #[cfg(f128_enabled)] bb(floattitf(bb(2))); + #[cfg(f128_enabled)] bb(floatunditf(bb(2))); + #[cfg(f128_enabled)] bb(floatunsitf(bb(2))); bb(floatuntidf(bb(2))); bb(floatuntisf(bb(2))); + #[cfg(f128_enabled)] bb(floatuntitf(bb(2))); + #[cfg(f128_enabled)] bb(gttf(bb(2.), bb(2.))); bb(lshrti3(bb(2), bb(2))); + #[cfg(f128_enabled)] bb(lttf(bb(2.), bb(2.))); bb(moddi3(bb(2), bb(3))); bb(modti3(bb(2), bb(2))); bb(mulodi4(bb(2), bb(3))); bb(muloti4(bb(2), bb(2))); + #[cfg(f128_enabled)] bb(multf(bb(2.), bb(2.))); bb(multi3(bb(2), bb(2))); + #[cfg(f128_enabled)] bb(subtf(bb(2.), bb(2.))); + #[cfg(f16_enabled)] bb(truncsfhf(bb(2.))); + #[cfg(f128_enabled)] bb(trunctfdf(bb(2.))); - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(all( + f16_enabled, + f128_enabled, + not(any(target_arch = "powerpc", target_arch = "powerpc64")) + ))] bb(trunctfhf(bb(2.))); + #[cfg(f128_enabled)] bb(trunctfsf(bb(2.))); bb(udivti3(bb(2), bb(2))); bb(umoddi3(bb(2), bb(3))); From ec673535f7b0f6dd390a35d3cdd30fba8891edef Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Thu, 31 Oct 2024 21:36:57 +0800 Subject: [PATCH 1432/4206] ci: add support for loongarch64-unknown-linux-gnu --- .../compiler-builtins/.github/workflows/main.yml | 3 +++ .../docker/loongarch64-unknown-linux-gnu/Dockerfile | 13 +++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 library/compiler-builtins/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index ec5c059bac0ea..fee5c45eaf0e0 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -38,6 +38,9 @@ jobs: - target: i686-unknown-linux-gnu os: ubuntu-latest rust: nightly + - target: loongarch64-unknown-linux-gnu + os: ubuntu-latest + rust: nightly # MIPS targets disabled since they are dropped to tier 3. # See https://github.com/rust-lang/compiler-team/issues/648 #- target: mips-unknown-linux-gnu diff --git a/library/compiler-builtins/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile new file mode 100644 index 0000000000000..5107d20a2a80d --- /dev/null +++ b/library/compiler-builtins/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,13 @@ +ARG IMAGE=ubuntu:24.04 +FROM $IMAGE + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user-static ca-certificates \ + gcc-14-loongarch64-linux-gnu libc6-dev-loong64-cross + +ENV CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_LINKER=loongarch64-linux-gnu-gcc-14 \ + CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_RUNNER=qemu-loongarch64-static \ + CC_loongarch64_unknown_linux_gnu=loongarch64-linux-gnu-gcc-14 \ + QEMU_LD_PREFIX=/usr/loongarch64-linux-gnu \ + RUST_TEST_THREADS=1 From 28fb4bc8689987b8f42d6bb5becb1a02251472a7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 1 Nov 2024 05:48:10 -0500 Subject: [PATCH 1433/4206] Enable the changelog for `release-plz` This crate isn't meant for direct use, but having an easy way to see what changed between versions would still be helpful when this crate is updated in rust-lang/rust. --- library/compiler-builtins/.release-plz.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/.release-plz.toml b/library/compiler-builtins/.release-plz.toml index fce19d1575597..e32f676108462 100644 --- a/library/compiler-builtins/.release-plz.toml +++ b/library/compiler-builtins/.release-plz.toml @@ -1,5 +1,4 @@ [workspace] -changelog_update = false semver_check = false # As part of the release process, we delete `libm/Cargo.toml`. Since From 4c7450d10cfec44c6a7b6d6b83fd0643dba819b2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 11:00:27 +0000 Subject: [PATCH 1434/4206] chore: release v0.1.138 --- library/compiler-builtins/CHANGELOG.md | 15 +++++++++++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/CHANGELOG.md diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md new file mode 100644 index 0000000000000..f43b63b2b0c42 --- /dev/null +++ b/library/compiler-builtins/CHANGELOG.md @@ -0,0 +1,15 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.1.138](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.137...compiler_builtins-v0.1.138) - 2024-11-01 + +### Other + +- Use `f16_enabled`/`f128_enabled` in `examples/intrinsics.rs` ([#724](https://github.com/rust-lang/compiler-builtins/pull/724)) +- Disable `f16` for LoongArch64 ([#722](https://github.com/rust-lang/compiler-builtins/pull/722)) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index ecd5ecd082278..3d8a1f255039d 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.137" +version = "0.1.138" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From c2402e4d3c2708cba97e463f7a863d08af8d51a1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 1 Nov 2024 06:05:42 -0500 Subject: [PATCH 1435/4206] Fix errors reported by Clippy in `libm` --- library/compiler-builtins/libm/src/lib.rs | 3 + .../compiler-builtins/libm/src/math/asin.rs | 2 +- .../compiler-builtins/libm/src/math/asinf.rs | 2 +- .../compiler-builtins/libm/src/math/atan2f.rs | 22 +- .../compiler-builtins/libm/src/math/atanhf.rs | 2 +- .../compiler-builtins/libm/src/math/exp2f.rs | 4 +- .../compiler-builtins/libm/src/math/expm1.rs | 2 +- .../compiler-builtins/libm/src/math/expm1f.rs | 2 +- .../compiler-builtins/libm/src/math/fabs.rs | 2 - .../compiler-builtins/libm/src/math/fdim.rs | 6 +- .../compiler-builtins/libm/src/math/fdimf.rs | 6 +- .../compiler-builtins/libm/src/math/fmaf.rs | 2 +- .../compiler-builtins/libm/src/math/fmod.rs | 4 +- .../compiler-builtins/libm/src/math/fmodf.rs | 2 +- .../compiler-builtins/libm/src/math/ilogb.rs | 2 +- .../compiler-builtins/libm/src/math/ilogbf.rs | 2 +- library/compiler-builtins/libm/src/math/jn.rs | 238 +++++++++--------- .../compiler-builtins/libm/src/math/jnf.rs | 230 +++++++++-------- .../libm/src/math/lgamma_r.rs | 3 +- .../libm/src/math/lgammaf_r.rs | 3 +- .../libm/src/math/nextafter.rs | 4 +- .../compiler-builtins/libm/src/math/pow.rs | 6 +- .../compiler-builtins/libm/src/math/powf.rs | 12 +- .../libm/src/math/rem_pio2.rs | 2 +- .../libm/src/math/rem_pio2_large.rs | 2 - .../libm/src/math/sincosf.rs | 26 +- .../compiler-builtins/libm/src/math/sqrt.rs | 12 +- .../libm/src/math/support/int_traits.rs | 3 + .../compiler-builtins/libm/src/math/tgamma.rs | 5 +- 29 files changed, 306 insertions(+), 305 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 98ac55988d0ad..511ab598dbad9 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -5,12 +5,15 @@ #![allow(clippy::assign_op_pattern)] #![allow(clippy::deprecated_cfg_attr)] #![allow(clippy::eq_op)] +#![allow(clippy::excessive_precision)] #![allow(clippy::float_cmp)] #![allow(clippy::int_plus_one)] #![allow(clippy::many_single_char_names)] #![allow(clippy::mixed_case_hex_literals)] +#![allow(clippy::needless_late_init)] #![allow(clippy::needless_return)] #![allow(clippy::unreadable_literal)] +#![allow(clippy::zero_divided_by_zero)] mod libm_helper; mod math; diff --git a/library/compiler-builtins/libm/src/math/asin.rs b/library/compiler-builtins/libm/src/math/asin.rs index 12fe08fc74527..12d0cd35fa58a 100644 --- a/library/compiler-builtins/libm/src/math/asin.rs +++ b/library/compiler-builtins/libm/src/math/asin.rs @@ -90,7 +90,7 @@ pub fn asin(mut x: f64) -> f64 { /* |x| < 0.5 */ if ix < 0x3fe00000 { /* if 0x1p-1022 <= |x| < 0x1p-26, avoid raising underflow */ - if ix < 0x3e500000 && ix >= 0x00100000 { + if (0x00100000..0x3e500000).contains(&ix) { return x; } else { return x + x * comp_r(x * x); diff --git a/library/compiler-builtins/libm/src/math/asinf.rs b/library/compiler-builtins/libm/src/math/asinf.rs index 2c785abe2baf2..0ea49c0767cd9 100644 --- a/library/compiler-builtins/libm/src/math/asinf.rs +++ b/library/compiler-builtins/libm/src/math/asinf.rs @@ -54,7 +54,7 @@ pub fn asinf(mut x: f32) -> f32 { if ix < 0x3f000000 { /* |x| < 0.5 */ /* if 0x1p-126 <= |x| < 0x1p-12, avoid raising underflow */ - if (ix < 0x39800000) && (ix >= 0x00800000) { + if (0x00800000..0x39800000).contains(&ix) { return x; } return x + x * r(x * x); diff --git a/library/compiler-builtins/libm/src/math/atan2f.rs b/library/compiler-builtins/libm/src/math/atan2f.rs index fa33f54f6f76c..95b466fff4e42 100644 --- a/library/compiler-builtins/libm/src/math/atan2f.rs +++ b/library/compiler-builtins/libm/src/math/atan2f.rs @@ -42,9 +42,9 @@ pub fn atan2f(y: f32, x: f32) -> f32 { /* when y = 0 */ if iy == 0 { return match m { - 0 | 1 => y, /* atan(+-0,+anything)=+-0 */ - 2 => PI, /* atan(+0,-anything) = pi */ - 3 | _ => -PI, /* atan(-0,-anything) =-pi */ + 0 | 1 => y, /* atan(+-0,+anything)=+-0 */ + 2 => PI, /* atan(+0,-anything) = pi */ + _ => -PI, /* atan(-0,-anything) =-pi */ }; } /* when x = 0 */ @@ -55,17 +55,17 @@ pub fn atan2f(y: f32, x: f32) -> f32 { if ix == 0x7f800000 { return if iy == 0x7f800000 { match m { - 0 => PI / 4., /* atan(+INF,+INF) */ - 1 => -PI / 4., /* atan(-INF,+INF) */ - 2 => 3. * PI / 4., /* atan(+INF,-INF)*/ - 3 | _ => -3. * PI / 4., /* atan(-INF,-INF)*/ + 0 => PI / 4., /* atan(+INF,+INF) */ + 1 => -PI / 4., /* atan(-INF,+INF) */ + 2 => 3. * PI / 4., /* atan(+INF,-INF)*/ + _ => -3. * PI / 4., /* atan(-INF,-INF)*/ } } else { match m { - 0 => 0., /* atan(+...,+INF) */ - 1 => -0., /* atan(-...,+INF) */ - 2 => PI, /* atan(+...,-INF) */ - 3 | _ => -PI, /* atan(-...,-INF) */ + 0 => 0., /* atan(+...,+INF) */ + 1 => -0., /* atan(-...,+INF) */ + 2 => PI, /* atan(+...,-INF) */ + _ => -PI, /* atan(-...,-INF) */ } }; } diff --git a/library/compiler-builtins/libm/src/math/atanhf.rs b/library/compiler-builtins/libm/src/math/atanhf.rs index 3545411bbd5ba..80ccec1f67fe4 100644 --- a/library/compiler-builtins/libm/src/math/atanhf.rs +++ b/library/compiler-builtins/libm/src/math/atanhf.rs @@ -18,7 +18,7 @@ pub fn atanhf(mut x: f32) -> f32 { if u < 0x3f800000 - (32 << 23) { /* handle underflow */ if u < (1 << 23) { - force_eval!((x * x) as f32); + force_eval!(x * x); } } else { /* |x| < 0.5, up to 1.7ulp error */ diff --git a/library/compiler-builtins/libm/src/math/exp2f.rs b/library/compiler-builtins/libm/src/math/exp2f.rs index f4867b80eedb5..f452b6a20f802 100644 --- a/library/compiler-builtins/libm/src/math/exp2f.rs +++ b/library/compiler-builtins/libm/src/math/exp2f.rs @@ -95,7 +95,7 @@ pub fn exp2f(mut x: f32) -> f32 { /* NaN */ return x; } - if ui >= 0x43000000 && ui < 0x80000000 { + if (0x43000000..0x80000000).contains(&ui) { /* x >= 128 */ x *= x1p127; return x; @@ -127,7 +127,7 @@ pub fn exp2f(mut x: f32) -> f32 { let z: f64 = (x - uf) as f64; /* Compute r = exp2(y) = exp2ft[i0] * p(z). */ let r: f64 = f64::from_bits(i!(EXP2FT, i0 as usize)); - let t: f64 = r as f64 * z; + let t: f64 = r * z; let r: f64 = r + t * (p1 as f64 + z * p2 as f64) + t * (z * z) * (p3 as f64 + z * p4 as f64); /* Scale by 2**k */ diff --git a/library/compiler-builtins/libm/src/math/expm1.rs b/library/compiler-builtins/libm/src/math/expm1.rs index 42608509a402e..f25153f32a34d 100644 --- a/library/compiler-builtins/libm/src/math/expm1.rs +++ b/library/compiler-builtins/libm/src/math/expm1.rs @@ -115,7 +115,7 @@ pub fn expm1(mut x: f64) -> f64 { } ui = ((0x3ff + k) as u64) << 52; /* 2^k */ let twopk = f64::from_bits(ui); - if k < 0 || k > 56 { + if !(0..=56).contains(&k) { /* suffice to return exp(x)-1 */ y = x - e + 1.0; if k == 1024 { diff --git a/library/compiler-builtins/libm/src/math/expm1f.rs b/library/compiler-builtins/libm/src/math/expm1f.rs index a862fe2558c49..12c6f532b96a5 100644 --- a/library/compiler-builtins/libm/src/math/expm1f.rs +++ b/library/compiler-builtins/libm/src/math/expm1f.rs @@ -115,7 +115,7 @@ pub fn expm1f(mut x: f32) -> f32 { return 1. + 2. * (x - e); } let twopk = f32::from_bits(((0x7f + k) << 23) as u32); /* 2^k */ - if (k < 0) || (k > 56) { + if !(0..=56).contains(&k) { /* suffice to return exp(x)-1 */ let mut y = x - e + 1.; if k == 128 { diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index 8d3ea2fd64795..d7980eb65f2a6 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -1,5 +1,3 @@ -use core::u64; - /// Absolute value (magnitude) (f64) /// Calculates the absolute value (magnitude) of the argument `x`, /// by direct manipulation of the bit representation of `x`. diff --git a/library/compiler-builtins/libm/src/math/fdim.rs b/library/compiler-builtins/libm/src/math/fdim.rs index 014930097a02d..7c58cb5a9a27f 100644 --- a/library/compiler-builtins/libm/src/math/fdim.rs +++ b/library/compiler-builtins/libm/src/math/fdim.rs @@ -3,9 +3,9 @@ use core::f64; /// Positive difference (f64) /// /// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. /// /// A range error may occur. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] diff --git a/library/compiler-builtins/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/src/math/fdimf.rs index ea0b592d7ab97..2abd49a64c9f9 100644 --- a/library/compiler-builtins/libm/src/math/fdimf.rs +++ b/library/compiler-builtins/libm/src/math/fdimf.rs @@ -3,9 +3,9 @@ use core::f32; /// Positive difference (f32) /// /// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. /// /// A range error may occur. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] diff --git a/library/compiler-builtins/libm/src/math/fmaf.rs b/library/compiler-builtins/libm/src/math/fmaf.rs index 10bdaeab33dec..79371c836c8ff 100644 --- a/library/compiler-builtins/libm/src/math/fmaf.rs +++ b/library/compiler-builtins/libm/src/math/fmaf.rs @@ -71,7 +71,7 @@ pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { underflow may not be raised correctly, example: fmaf(0x1p-120f, 0x1p-120f, 0x1p-149f) */ - if e < 0x3ff - 126 && e >= 0x3ff - 149 && fetestexcept(FE_INEXACT) != 0 { + if ((0x3ff - 149)..(0x3ff - 126)).contains(&e) && fetestexcept(FE_INEXACT) != 0 { feclearexcept(FE_INEXACT); // prevent `xy + vz` from being CSE'd with `xy + z` above let vz: f32 = unsafe { read_volatile(&z) }; diff --git a/library/compiler-builtins/libm/src/math/fmod.rs b/library/compiler-builtins/libm/src/math/fmod.rs index d892ffd8b72a2..df16162bcae86 100644 --- a/library/compiler-builtins/libm/src/math/fmod.rs +++ b/library/compiler-builtins/libm/src/math/fmod.rs @@ -1,5 +1,3 @@ -use core::u64; - #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmod(x: f64, y: f64) -> f64 { let mut uxi = x.to_bits(); @@ -74,7 +72,7 @@ pub fn fmod(x: f64, y: f64) -> f64 { } else { uxi >>= -ex + 1; } - uxi |= (sx as u64) << 63; + uxi |= sx << 63; f64::from_bits(uxi) } diff --git a/library/compiler-builtins/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs index 1d80013842e70..671af85800f1f 100644 --- a/library/compiler-builtins/libm/src/math/fmodf.rs +++ b/library/compiler-builtins/libm/src/math/fmodf.rs @@ -1,4 +1,4 @@ -use core::{f32, u32}; +use core::f32; #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmodf(x: f32, y: f32) -> f32 { diff --git a/library/compiler-builtins/libm/src/math/ilogb.rs b/library/compiler-builtins/libm/src/math/ilogb.rs index 9d58d06081b76..ccc4914be2bf7 100644 --- a/library/compiler-builtins/libm/src/math/ilogb.rs +++ b/library/compiler-builtins/libm/src/math/ilogb.rs @@ -21,7 +21,7 @@ pub fn ilogb(x: f64) -> i32 { e } else if e == 0x7ff { force_eval!(0.0 / 0.0); - if (i << 12) != 0 { FP_ILOGBNAN } else { i32::max_value() } + if (i << 12) != 0 { FP_ILOGBNAN } else { i32::MAX } } else { e - 0x3ff } diff --git a/library/compiler-builtins/libm/src/math/ilogbf.rs b/library/compiler-builtins/libm/src/math/ilogbf.rs index 85deb43c83b76..3585d6d36f164 100644 --- a/library/compiler-builtins/libm/src/math/ilogbf.rs +++ b/library/compiler-builtins/libm/src/math/ilogbf.rs @@ -21,7 +21,7 @@ pub fn ilogbf(x: f32) -> i32 { e } else if e == 0xff { force_eval!(0.0 / 0.0); - if (i << 9) != 0 { FP_ILOGBNAN } else { i32::max_value() } + if (i << 9) != 0 { FP_ILOGBNAN } else { i32::MAX } } else { e - 0x7f } diff --git a/library/compiler-builtins/libm/src/math/jn.rs b/library/compiler-builtins/libm/src/math/jn.rs index aff051f24061b..7f98ddc055a62 100644 --- a/library/compiler-builtins/libm/src/math/jn.rs +++ b/library/compiler-builtins/libm/src/math/jn.rs @@ -104,7 +104,8 @@ pub fn jn(n: i32, mut x: f64) -> f64 { 0 => -cos(x) + sin(x), 1 => -cos(x) - sin(x), 2 => cos(x) - sin(x), - 3 | _ => cos(x) + sin(x), + // 3 + _ => cos(x) + sin(x), }; b = INVSQRTPI * temp / sqrt(x); } else { @@ -118,130 +119,128 @@ pub fn jn(n: i32, mut x: f64) -> f64 { a = temp; } } - } else { - if ix < 0x3e100000 { - /* x < 2**-29 */ - /* x is tiny, return the first Taylor expansion of J(n,x) - * J(n,x) = 1/n!*(x/2)^n - ... - */ - if nm1 > 32 { - /* underflow */ - b = 0.0; - } else { - temp = x * 0.5; - b = temp; - a = 1.0; - i = 2; - while i <= nm1 + 1 { - a *= i as f64; /* a = n! */ - b *= temp; /* b = (x/2)^n */ - i += 1; - } - b = b / a; - } + } else if ix < 0x3e100000 { + /* x < 2**-29 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if nm1 > 32 { + /* underflow */ + b = 0.0; } else { - /* use backward recurrence */ - /* x x^2 x^2 - * J(n,x)/J(n-1,x) = ---- ------ ------ ..... - * 2n - 2(n+1) - 2(n+2) - * - * 1 1 1 - * (for large x) = ---- ------ ------ ..... - * 2n 2(n+1) 2(n+2) - * -- - ------ - ------ - - * x x x - * - * Let w = 2n/x and h=2/x, then the above quotient - * is equal to the continued fraction: - * 1 - * = ----------------------- - * 1 - * w - ----------------- - * 1 - * w+h - --------- - * w+2h - ... - * - * To determine how many terms needed, let - * Q(0) = w, Q(1) = w(w+h) - 1, - * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), - * When Q(k) > 1e4 good for single - * When Q(k) > 1e9 good for double - * When Q(k) > 1e17 good for quadruple - */ - /* determine k */ - let mut t: f64; - let mut q0: f64; - let mut q1: f64; - let mut w: f64; - let h: f64; - let mut z: f64; - let mut tmp: f64; - let nf: f64; + temp = x * 0.5; + b = temp; + a = 1.0; + i = 2; + while i <= nm1 + 1 { + a *= i as f64; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + i += 1; + } + b = b / a; + } + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + let mut t: f64; + let mut q0: f64; + let mut q1: f64; + let mut w: f64; + let h: f64; + let mut z: f64; + let mut tmp: f64; + let nf: f64; - let mut k: i32; + let mut k: i32; - nf = (nm1 as f64) + 1.0; - w = 2.0 * nf / x; - h = 2.0 / x; - z = w + h; - q0 = w; - q1 = w * z - 1.0; - k = 1; - while q1 < 1.0e9 { - k += 1; - z += h; - tmp = z * q1 - q0; - q0 = q1; - q1 = tmp; - } - t = 0.0; - i = k; - while i >= 0 { - t = 1.0 / (2.0 * ((i as f64) + nf) / x - t); + nf = (nm1 as f64) + 1.0; + w = 2.0 * nf / x; + h = 2.0 / x; + z = w + h; + q0 = w; + q1 = w * z - 1.0; + k = 1; + while q1 < 1.0e9 { + k += 1; + z += h; + tmp = z * q1 - q0; + q0 = q1; + q1 = tmp; + } + t = 0.0; + i = k; + while i >= 0 { + t = 1.0 / (2.0 * ((i as f64) + nf) / x - t); + i -= 1; + } + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf * log(fabs(w)); + if tmp < 7.09782712893383973096e+02 { + i = nm1; + while i > 0 { + temp = b; + b = b * (2.0 * (i as f64)) / x - a; + a = temp; i -= 1; } - a = t; - b = 1.0; - /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) - * Hence, if n*(log(2n/x)) > ... - * single 8.8722839355e+01 - * double 7.09782712893383973096e+02 - * long double 1.1356523406294143949491931077970765006170e+04 - * then recurrent value may overflow and the result is - * likely underflow to zero - */ - tmp = nf * log(fabs(w)); - if tmp < 7.09782712893383973096e+02 { - i = nm1; - while i > 0 { - temp = b; - b = b * (2.0 * (i as f64)) / x - a; - a = temp; - i -= 1; - } - } else { - i = nm1; - while i > 0 { - temp = b; - b = b * (2.0 * (i as f64)) / x - a; - a = temp; - /* scale b to avoid spurious overflow */ - let x1p500 = f64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 - if b > x1p500 { - a /= b; - t /= b; - b = 1.0; - } - i -= 1; + } else { + i = nm1; + while i > 0 { + temp = b; + b = b * (2.0 * (i as f64)) / x - a; + a = temp; + /* scale b to avoid spurious overflow */ + let x1p500 = f64::from_bits(0x5f30000000000000); // 0x1p500 == 2^500 + if b > x1p500 { + a /= b; + t /= b; + b = 1.0; } + i -= 1; } - z = j0(x); - w = j1(x); - if fabs(z) >= fabs(w) { - b = t * z / b; - } else { - b = t * w / a; - } + } + z = j0(x); + w = j1(x); + if fabs(z) >= fabs(w) { + b = t * z / b; + } else { + b = t * w / a; } } @@ -315,7 +314,8 @@ pub fn yn(n: i32, x: f64) -> f64 { 0 => -sin(x) - cos(x), 1 => -sin(x) + cos(x), 2 => sin(x) + cos(x), - 3 | _ => sin(x) - cos(x), + // 3 + _ => sin(x) - cos(x), }; b = INVSQRTPI * temp / sqrt(x); } else { diff --git a/library/compiler-builtins/libm/src/math/jnf.rs b/library/compiler-builtins/libm/src/math/jnf.rs index e5afda44896df..754f8f33b5af5 100644 --- a/library/compiler-builtins/libm/src/math/jnf.rs +++ b/library/compiler-builtins/libm/src/math/jnf.rs @@ -64,128 +64,126 @@ pub fn jnf(n: i32, mut x: f32) -> f32 { b = b * (2.0 * (i as f32) / x) - a; a = temp; } + } else if ix < 0x35800000 { + /* x < 2**-20 */ + /* x is tiny, return the first Taylor expansion of J(n,x) + * J(n,x) = 1/n!*(x/2)^n - ... + */ + if nm1 > 8 { + /* underflow */ + nm1 = 8; + } + temp = 0.5 * x; + b = temp; + a = 1.0; + i = 2; + while i <= nm1 + 1 { + a *= i as f32; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + i += 1; + } + b = b / a; } else { - if ix < 0x35800000 { - /* x < 2**-20 */ - /* x is tiny, return the first Taylor expansion of J(n,x) - * J(n,x) = 1/n!*(x/2)^n - ... - */ - if nm1 > 8 { - /* underflow */ - nm1 = 8; - } - temp = 0.5 * x; - b = temp; - a = 1.0; - i = 2; - while i <= nm1 + 1 { - a *= i as f32; /* a = n! */ - b *= temp; /* b = (x/2)^n */ - i += 1; - } - b = b / a; - } else { - /* use backward recurrence */ - /* x x^2 x^2 - * J(n,x)/J(n-1,x) = ---- ------ ------ ..... - * 2n - 2(n+1) - 2(n+2) - * - * 1 1 1 - * (for large x) = ---- ------ ------ ..... - * 2n 2(n+1) 2(n+2) - * -- - ------ - ------ - - * x x x - * - * Let w = 2n/x and h=2/x, then the above quotient - * is equal to the continued fraction: - * 1 - * = ----------------------- - * 1 - * w - ----------------- - * 1 - * w+h - --------- - * w+2h - ... - * - * To determine how many terms needed, let - * Q(0) = w, Q(1) = w(w+h) - 1, - * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), - * When Q(k) > 1e4 good for single - * When Q(k) > 1e9 good for double - * When Q(k) > 1e17 good for quadruple - */ - /* determine k */ - let mut t: f32; - let mut q0: f32; - let mut q1: f32; - let mut w: f32; - let h: f32; - let mut z: f32; - let mut tmp: f32; - let nf: f32; - let mut k: i32; + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + let mut t: f32; + let mut q0: f32; + let mut q1: f32; + let mut w: f32; + let h: f32; + let mut z: f32; + let mut tmp: f32; + let nf: f32; + let mut k: i32; - nf = (nm1 as f32) + 1.0; - w = 2.0 * (nf as f32) / x; - h = 2.0 / x; - z = w + h; - q0 = w; - q1 = w * z - 1.0; - k = 1; - while q1 < 1.0e4 { - k += 1; - z += h; - tmp = z * q1 - q0; - q0 = q1; - q1 = tmp; - } - t = 0.0; - i = k; - while i >= 0 { - t = 1.0 / (2.0 * ((i as f32) + nf) / x - t); + nf = (nm1 as f32) + 1.0; + w = 2.0 * nf / x; + h = 2.0 / x; + z = w + h; + q0 = w; + q1 = w * z - 1.0; + k = 1; + while q1 < 1.0e4 { + k += 1; + z += h; + tmp = z * q1 - q0; + q0 = q1; + q1 = tmp; + } + t = 0.0; + i = k; + while i >= 0 { + t = 1.0 / (2.0 * ((i as f32) + nf) / x - t); + i -= 1; + } + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf * logf(fabsf(w)); + if tmp < 88.721679688 { + i = nm1; + while i > 0 { + temp = b; + b = 2.0 * (i as f32) * b / x - a; + a = temp; i -= 1; } - a = t; - b = 1.0; - /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) - * Hence, if n*(log(2n/x)) > ... - * single 8.8722839355e+01 - * double 7.09782712893383973096e+02 - * long double 1.1356523406294143949491931077970765006170e+04 - * then recurrent value may overflow and the result is - * likely underflow to zero - */ - tmp = nf * logf(fabsf(w)); - if tmp < 88.721679688 { - i = nm1; - while i > 0 { - temp = b; - b = 2.0 * (i as f32) * b / x - a; - a = temp; - i -= 1; - } - } else { - i = nm1; - while i > 0 { - temp = b; - b = 2.0 * (i as f32) * b / x - a; - a = temp; - /* scale b to avoid spurious overflow */ - let x1p60 = f32::from_bits(0x5d800000); // 0x1p60 == 2^60 - if b > x1p60 { - a /= b; - t /= b; - b = 1.0; - } - i -= 1; + } else { + i = nm1; + while i > 0 { + temp = b; + b = 2.0 * (i as f32) * b / x - a; + a = temp; + /* scale b to avoid spurious overflow */ + let x1p60 = f32::from_bits(0x5d800000); // 0x1p60 == 2^60 + if b > x1p60 { + a /= b; + t /= b; + b = 1.0; } + i -= 1; } - z = j0f(x); - w = j1f(x); - if fabsf(z) >= fabsf(w) { - b = t * z / b; - } else { - b = t * w / a; - } + } + z = j0f(x); + w = j1f(x); + if fabsf(z) >= fabsf(w) { + b = t * z / b; + } else { + b = t * w / a; } } diff --git a/library/compiler-builtins/libm/src/math/lgamma_r.rs b/library/compiler-builtins/libm/src/math/lgamma_r.rs index b26177e6ebf75..6becaad2ce91d 100644 --- a/library/compiler-builtins/libm/src/math/lgamma_r.rs +++ b/library/compiler-builtins/libm/src/math/lgamma_r.rs @@ -160,7 +160,8 @@ fn sin_pi(mut x: f64) -> f64 { 1 => k_cos(x, 0.0), 2 => k_sin(-x, 0.0, 0), 3 => -k_cos(x, 0.0), - 0 | _ => k_sin(x, 0.0, 0), + // 0 + _ => k_sin(x, 0.0, 0), } } diff --git a/library/compiler-builtins/libm/src/math/lgammaf_r.rs b/library/compiler-builtins/libm/src/math/lgammaf_r.rs index 723c90daf1ed1..10cecee541ccc 100644 --- a/library/compiler-builtins/libm/src/math/lgammaf_r.rs +++ b/library/compiler-builtins/libm/src/math/lgammaf_r.rs @@ -95,7 +95,8 @@ fn sin_pi(mut x: f32) -> f32 { 1 => k_cosf(y), 2 => k_sinf(-y), 3 => -k_cosf(y), - 0 | _ => k_sinf(y), + // 0 + _ => k_sinf(y), } } diff --git a/library/compiler-builtins/libm/src/math/nextafter.rs b/library/compiler-builtins/libm/src/math/nextafter.rs index 05762619109a2..422bd7496d5ef 100644 --- a/library/compiler-builtins/libm/src/math/nextafter.rs +++ b/library/compiler-builtins/libm/src/math/nextafter.rs @@ -10,8 +10,8 @@ pub fn nextafter(x: f64, y: f64) -> f64 { return y; } - let ax = ux_i & !1_u64 / 2; - let ay = uy_i & !1_u64 / 2; + let ax = ux_i & (!1_u64 / 2); + let ay = uy_i & (!1_u64 / 2); if ax == 0 { if ay == 0 { return y; diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 7ecad291d1823..736465cd16f6c 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -98,8 +98,8 @@ pub fn pow(x: f64, y: f64) -> f64 { let (hx, lx): (i32, u32) = ((x.to_bits() >> 32) as i32, x.to_bits() as u32); let (hy, ly): (i32, u32) = ((y.to_bits() >> 32) as i32, y.to_bits() as u32); - let mut ix: i32 = (hx & 0x7fffffff) as i32; - let iy: i32 = (hy & 0x7fffffff) as i32; + let mut ix: i32 = hx & 0x7fffffff_i32; + let iy: i32 = hy & 0x7fffffff_i32; /* x**0 = 1, even if x is NaN */ if ((iy as u32) | ly) == 0 { @@ -355,7 +355,7 @@ pub fn pow(x: f64, y: f64) -> f64 { } /* compute 2**(p_h+p_l) */ - let i: i32 = j & (0x7fffffff as i32); + let i: i32 = j & 0x7fffffff_i32; k = (i >> 20) - 0x3ff; let mut n: i32 = 0; diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs index 2d9d1e4bbfdde..839c6c23d436d 100644 --- a/library/compiler-builtins/libm/src/math/powf.rs +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -13,6 +13,8 @@ * ==================================================== */ +use core::cmp::Ordering; + use super::{fabsf, scalbnf, sqrtf}; const BP: [f32; 2] = [1.0, 1.5]; @@ -115,15 +117,13 @@ pub fn powf(x: f32, y: f32) -> f32 { /* special value of y */ if iy == 0x7f800000 { /* y is +-inf */ - if ix == 0x3f800000 { + match ix.cmp(&0x3f800000) { /* (-1)**+-inf is 1 */ - return 1.0; - } else if ix > 0x3f800000 { + Ordering::Equal => return 1.0, /* (|x|>1)**+-inf = inf,0 */ - return if hy >= 0 { y } else { 0.0 }; - } else { + Ordering::Greater => return if hy >= 0 { y } else { 0.0 }, /* (|x|<1)**+-inf = 0,inf */ - return if hy >= 0 { 0.0 } else { -y }; + Ordering::Less => return if hy >= 0 { 0.0 } else { -y }, } } if iy == 0x3f800000 { diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 4dfb8c6588379..917e90819a50d 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -50,7 +50,7 @@ pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { fn medium(x: f64, ix: u32) -> (i32, f64, f64) { /* rint(x/(pi/2)), Assume round-to-nearest. */ - let tmp = x as f64 * INV_PIO2 + TO_INT; + 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")))] 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 1dfbba3b1b226..ec8397f4b6fc2 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -425,8 +425,6 @@ pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> for i in (0..=jz).rev() { fw += i!(fq, i); } - // TODO: drop excess precision here once double_t is used - fw = fw as f64; i!(y, 0, =, if ih == 0 { fw } else { -fw }); fw = i!(fq, 0) - fw; for i in 1..=jz { diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs index 423845e44c2ab..f3360767683eb 100644 --- a/library/compiler-builtins/libm/src/math/sincosf.rs +++ b/library/compiler-builtins/libm/src/math/sincosf.rs @@ -67,14 +67,12 @@ pub fn sincosf(x: f32) -> (f32, f32) { } } /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ - else { - if sign { - s = -k_sinf(x as f64 + S2PIO2); - c = -k_cosf(x as f64 + S2PIO2); - } else { - s = -k_sinf(x as f64 - S2PIO2); - c = -k_cosf(x as f64 - S2PIO2); - } + else if sign { + s = -k_sinf(x as f64 + S2PIO2); + c = -k_cosf(x as f64 + S2PIO2); + } else { + s = -k_sinf(x as f64 - S2PIO2); + c = -k_cosf(x as f64 - S2PIO2); } return (s, c); @@ -91,14 +89,12 @@ pub fn sincosf(x: f32) -> (f32, f32) { s = -k_cosf(x as f64 - S3PIO2); c = k_sinf(x as f64 - S3PIO2); } + } else if sign { + s = k_sinf(x as f64 + S4PIO2); + c = k_cosf(x as f64 + S4PIO2); } else { - if sign { - s = k_sinf(x as f64 + S4PIO2); - c = k_cosf(x as f64 + S4PIO2); - } else { - s = k_sinf(x as f64 - S4PIO2); - c = k_cosf(x as f64 - S4PIO2); - } + s = k_sinf(x as f64 - S4PIO2); + c = k_cosf(x as f64 - S4PIO2); } return (s, c); diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index a443b7e4c613d..3eaf52cda8ea0 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -144,13 +144,15 @@ pub fn sqrt(x: f64) -> f64 { ix0 = (ix0 & 0x000fffff) | 0x00100000; if (m & 1) == 1 { /* odd m, double x to make it even */ - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix0 *= 2; + ix0 += ((ix1 & sign) >> 31).0 as i32; ix1 += ix1; } m >>= 1; /* m = [m/2] */ /* generate sqrt(x) bit by bit */ - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix0 *= 2; + ix0 += ((ix1 & sign) >> 31).0 as i32; ix1 += ix1; q = 0; /* [q,q1] = sqrt(x) */ q1 = Wrapping(0); @@ -165,7 +167,8 @@ pub fn sqrt(x: f64) -> f64 { ix0 -= t; q += r.0 as i32; } - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix0 *= 2; + ix0 += ((ix1 & sign) >> 31).0 as i32; ix1 += ix1; r >>= 1; } @@ -186,7 +189,8 @@ pub fn sqrt(x: f64) -> f64 { ix1 -= t1; q1 += r; } - ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32; + ix0 *= 2; + ix0 += ((ix1 & sign) >> 31).0 as i32; ix1 += ix1; r >>= 1; } 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 c5feef8d7268c..b08907aa5b87c 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -136,6 +136,9 @@ macro_rules! int_impl_common { } fn ilog2(self) -> u32 { + // On our older MSRV, this resolves to the trait method. Which won't actually work, + // but this is only called behind other gates. + #[allow(clippy::incompatible_msrv)] ::ilog2(self) } }; diff --git a/library/compiler-builtins/libm/src/math/tgamma.rs b/library/compiler-builtins/libm/src/math/tgamma.rs index 3f38c0b1d9fd7..60451416ab322 100644 --- a/library/compiler-builtins/libm/src/math/tgamma.rs +++ b/library/compiler-builtins/libm/src/math/tgamma.rs @@ -45,7 +45,8 @@ fn sinpi(mut x: f64) -> f64 { 1 => k_cos(x, 0.0), 2 => k_sin(-x, 0.0, 0), 3 => -k_cos(x, 0.0), - 0 | _ => k_sin(x, 0.0, 0), + // 0 + _ => k_sin(x, 0.0, 0), } } @@ -143,7 +144,7 @@ pub fn tgamma(mut x: f64) -> f64 { /* special cases */ if ix >= 0x7ff00000 { /* tgamma(nan)=nan, tgamma(inf)=inf, tgamma(-inf)=nan with invalid */ - return x + core::f64::INFINITY; + return x + f64::INFINITY; } if ix < ((0x3ff - 54) << 20) { /* |x| < 2^-54: tgamma(x) ~ 1/x, +-0 raises div-by-zero */ From 659cdcad33b0baf5d98af698ccd05fa9369a0cc9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 1 Nov 2024 06:32:06 -0500 Subject: [PATCH 1436/4206] Enable clippy for `libm` in CI --- .../compiler-builtins/libm/.github/workflows/main.yml | 10 ++++++++-- library/compiler-builtins/libm/ci/run.sh | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index bfd86497b4ecf..14e5578847960 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -82,8 +82,8 @@ jobs: [ -n "${{ matrix.channel }}" ] && channel="${{ matrix.channel }}" rustup update "$channel" --no-self-update rustup default "$channel" - rustup target add ${{ matrix.target }} - rustup component add llvm-tools-preview + rustup target add "${{ matrix.target }}" + rustup component add clippy llvm-tools-preview - uses: Swatinem/rust-cache@v2 with: key: ${{ matrix.target }} @@ -105,6 +105,12 @@ jobs: rustup target add x86_64-unknown-linux-musl cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} + - name: Clippy + run: | + # Run clippy on `libm` + cargo clippy --target "${{ matrix.target }}" --package libm + + builtins: name: Check use with compiler-builtins runs-on: ubuntu-latest diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index a211bc98cbf97..32453663e0543 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -88,3 +88,4 @@ else $cmd --benches $cmd --benches --release fi + From 0f9503532b2a52c4fe523c91d3b459c2be09a1fe Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 31 Oct 2024 03:05:45 -0500 Subject: [PATCH 1437/4206] Introduce `hf32!` and `hf64!` macros for hex float support Rust does not have any native way to parse hex floats, but they are heavily used in the C algorithms that we derive from. Introduce a const function that can parse these, as well as macros `hf32!` and `hf64!` that ensure the string literals get handled at compiler time. These are currently not used but making everything available now will ease future development. Co-authored-by: quaternic <57393910+quaternic@users.noreply.github.com> --- .../compiler-builtins/libm/CONTRIBUTING.md | 34 +- .../libm/src/math/support/hex_float.rs | 399 ++++++++++++++++++ .../libm/src/math/support/macros.rs | 20 + .../libm/src/math/support/mod.rs | 3 + 4 files changed, 430 insertions(+), 26 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/support/hex_float.rs diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md index a39623696c4a0..0a1741631909b 100644 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -44,37 +44,19 @@ Check [PR #65] for an example. `mod.rs`. - You may encounter weird literals like `0x1p127f` in the MUSL code. These are hexadecimal floating - point literals. Rust (the language) doesn't support these kind of literals. The best way I have - found to deal with these literals is to turn them into their integer representation using the - [`hexf!`] macro and then turn them back into floats. See below: + point literals. Rust (the language) doesn't support these kind of literals. This crate provides + two macros, `hf32!` and `hf64!`, which convert string literals to floats at compile time. -[`hexf!`]: https://crates.io/crates/hexf - -``` rust -// Step 1: write a program to convert the float into its integer representation -#[macro_use] -extern crate hexf; - -fn main() { - println!("{:#x}", hexf32!("0x1.0p127").to_bits()); -} -``` - -``` console -$ # Step 2: run the program -$ cargo run -0x7f000000 -``` - -``` rust -// Step 3: copy paste the output into libm -let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 12 -``` + ```rust + assert_eq!(hf32!("0x1.ffep+8").to_bits(), 0x43fff000); + assert_eq!(hf64!("0x1.ffep+8").to_bits(), 0x407ffe0000000000); + ``` - Rust code panics on arithmetic overflows when not optimized. You may need to use the [`Wrapping`] - newtype to avoid this problem. + newtype to avoid this problem, or individual methods like [`wrapping_add`]. [`Wrapping`]: https://doc.rust-lang.org/std/num/struct.Wrapping.html +[`wrapping_add`]: https://doc.rust-lang.org/std/primitive.u32.html#method.wrapping_add ## Testing diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs new file mode 100644 index 0000000000000..80434a5ec3e97 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -0,0 +1,399 @@ +//! Utilities for working with hex float formats. + +#![allow(dead_code)] // FIXME: remove once this gets used + +/// Construct a 32-bit float from hex float representation (C-style) +pub const fn hf32(s: &str) -> f32 { + f32_from_bits(parse_any(s, 32, 23) as u32) +} + +/// Construct a 64-bit float from hex float representation (C-style) +pub const fn hf64(s: &str) -> f64 { + f64_from_bits(parse_any(s, 64, 52) as u64) +} + +const fn parse_any(s: &str, bits: u32, sig_bits: u32) -> u128 { + let exp_bits: u32 = bits - sig_bits - 1; + let max_msb: i32 = (1 << (exp_bits - 1)) - 1; + // The exponent of one ULP in the subnormals + let min_lsb: i32 = 1 - max_msb - sig_bits as i32; + + let (neg, mut sig, exp) = parse_hex(s.as_bytes()); + + if sig == 0 { + return (neg as u128) << (bits - 1); + } + + // exponents of the least and most significant bits in the value + let lsb = sig.trailing_zeros() as i32; + let msb = u128_ilog2(sig) as i32; + let sig_bits = sig_bits as i32; + + assert!(msb - lsb <= sig_bits, "the value is too precise"); + assert!(msb + exp <= max_msb, "the value is too huge"); + assert!(lsb + exp >= min_lsb, "the value is too tiny"); + + // The parsed value is X = sig * 2^exp + // Expressed as a multiple U of the smallest subnormal value: + // X = U * 2^min_lsb, so U = sig * 2^(exp-min_lsb) + let mut uexp = exp - min_lsb; + + let shift = if uexp + msb >= sig_bits { + // normal, shift msb to position sig_bits + sig_bits - msb + } else { + // subnormal, shift so that uexp becomes 0 + uexp + }; + + if shift >= 0 { + sig <<= shift; + } else { + sig >>= -shift; + } + uexp -= shift; + + // the most significant bit is like having 1 in the exponent bits + // add any leftover exponent to that + assert!(uexp >= 0 && uexp < (1 << exp_bits) - 2); + sig += (uexp as u128) << sig_bits; + + // finally, set the sign bit if necessary + sig | ((neg as u128) << (bits - 1)) +} + +/// Parse a hexadecimal float x +/// returns (s,n,e): +/// s == x.is_sign_negative() +/// n * 2^e == x.abs() +const fn parse_hex(mut b: &[u8]) -> (bool, u128, i32) { + let mut neg = false; + let mut sig: u128 = 0; + let mut exp: i32 = 0; + + if let &[c @ (b'-' | b'+'), ref rest @ ..] = b { + b = rest; + neg = c == b'-'; + } + + if let &[b'0', b'x' | b'X', ref rest @ ..] = b { + b = rest; + } else { + panic!("no hex indicator"); + } + + let mut seen_point = false; + let mut some_digits = false; + + while let &[c, ref rest @ ..] = b { + b = rest; + + match c { + b'.' => { + assert!(!seen_point); + seen_point = true; + continue; + } + b'p' | b'P' => break, + c => { + let digit = hex_digit(c); + some_digits = true; + let of; + (sig, of) = sig.overflowing_mul(16); + assert!(!of, "too many digits"); + sig |= digit as u128; + // up until the fractional point, the value grows + // with more digits, but after it the exponent is + // compensated to match. + if seen_point { + exp -= 4; + } + } + } + } + assert!(some_digits, "at least one digit is required"); + some_digits = false; + + let mut negate_exp = false; + if let &[c @ (b'-' | b'+'), ref rest @ ..] = b { + b = rest; + negate_exp = c == b'-'; + } + + let mut pexp: i32 = 0; + while let &[c, ref rest @ ..] = b { + b = rest; + let digit = dec_digit(c); + some_digits = true; + let of; + (pexp, of) = pexp.overflowing_mul(10); + assert!(!of, "too many exponent digits"); + pexp += digit as i32; + } + assert!(some_digits, "at least one exponent digit is required"); + + if negate_exp { + exp -= pexp; + } else { + exp += pexp; + } + + (neg, sig, exp) +} + +const fn dec_digit(c: u8) -> u8 { + match c { + b'0'..=b'9' => c - b'0', + _ => panic!("bad char"), + } +} + +const fn hex_digit(c: u8) -> u8 { + match c { + b'0'..=b'9' => c - b'0', + b'a'..=b'f' => c - b'a' + 10, + b'A'..=b'F' => c - b'A' + 10, + _ => panic!("bad char"), + } +} + +/* FIXME(msrv): vendor some things that are not const stable at our MSRV */ + +/// `f32::from_bits` +const fn f32_from_bits(v: u32) -> f32 { + unsafe { core::mem::transmute(v) } +} + +/// `f64::from_bits` +const fn f64_from_bits(v: u64) -> f64 { + unsafe { core::mem::transmute(v) } +} + +/// `u128::ilog2` +const fn u128_ilog2(v: u128) -> u32 { + assert!(v != 0); + u128::BITS - 1 - v.leading_zeros() +} + +#[cfg(test)] +mod tests { + extern crate std; + use std::{format, println}; + + use super::*; + + #[test] + fn test_parse_any() { + for k in -149..=127 { + let s = format!("0x1p{k}"); + let x = hf32(&s); + let y = if k < 0 { 0.5f32.powi(-k) } else { 2.0f32.powi(k) }; + assert_eq!(x, y); + } + + let mut s = *b"0x.0000000p-121"; + for e in 0..40 { + for k in 0..(1 << 15) { + let expected = f32::from_bits(k) * 2.0f32.powi(e); + let x = hf32(std::str::from_utf8(&s).unwrap()); + assert_eq!( + x.to_bits(), + expected.to_bits(), + "\ + e={e}\n\ + k={k}\n\ + x={x}\n\ + expected={expected}\n\ + s={}\n\ + f32::from_bits(k)={}\n\ + 2.0f32.powi(e)={}\ + ", + std::str::from_utf8(&s).unwrap(), + f32::from_bits(k), + 2.0f32.powi(e), + ); + for i in (3..10).rev() { + if s[i] == b'f' { + s[i] = b'0'; + } else if s[i] == b'9' { + s[i] = b'a'; + break; + } else { + s[i] += 1; + break; + } + } + } + for i in (12..15).rev() { + if s[i] == b'0' { + s[i] = b'9'; + } else { + s[i] -= 1; + break; + } + } + for i in (3..10).rev() { + s[i] = b'0'; + } + } + } + + #[test] + fn test_f32() { + let checks = [ + ("0x.1234p+16", (0x1234 as f32).to_bits()), + ("0x1.234p+12", (0x1234 as f32).to_bits()), + ("0x12.34p+8", (0x1234 as f32).to_bits()), + ("0x123.4p+4", (0x1234 as f32).to_bits()), + ("0x1234p+0", (0x1234 as f32).to_bits()), + ("0x1234.p+0", (0x1234 as f32).to_bits()), + ("0x1234.0p+0", (0x1234 as f32).to_bits()), + ("0x1.fffffep+127", f32::MAX.to_bits()), + ("0x1.0p+1", 2.0f32.to_bits()), + ("0x1.0p+0", 1.0f32.to_bits()), + ("0x1.ffep+8", 0x43fff000), + ("+0x1.ffep+8", 0x43fff000), + ("0x1p+0", 0x3f800000), + ("0x1.99999ap-4", 0x3dcccccd), + ("0x1.9p+6", 0x42c80000), + ("0x1.2d5ed2p+20", 0x4996af69), + ("-0x1.348eb8p+10", 0xc49a475c), + ("-0x1.33dcfep-33", 0xaf19ee7f), + ("0x0.0p0", 0.0f32.to_bits()), + ("-0x0.0p0", (-0.0f32).to_bits()), + ("0x1.0p0", 1.0f32.to_bits()), + ("0x1.99999ap-4", (0.1f32).to_bits()), + ("-0x1.99999ap-4", (-0.1f32).to_bits()), + ("0x1.111114p-127", 0x00444445), + ("0x1.23456p-130", 0x00091a2b), + ("0x1p-149", 0x00000001), + ]; + for (s, exp) in checks { + println!("parsing {s}"); + let act = hf32(s).to_bits(); + assert_eq!( + act, exp, + "parsing {s}: {act:#010x} != {exp:#010x}\nact: {act:#034b}\nexp: {exp:#034b}" + ); + } + } + + #[test] + fn test_f64() { + let checks = [ + ("0x.1234p+16", (0x1234 as f64).to_bits()), + ("0x1.234p+12", (0x1234 as f64).to_bits()), + ("0x12.34p+8", (0x1234 as f64).to_bits()), + ("0x123.4p+4", (0x1234 as f64).to_bits()), + ("0x1234p+0", (0x1234 as f64).to_bits()), + ("0x1234.p+0", (0x1234 as f64).to_bits()), + ("0x1234.0p+0", (0x1234 as f64).to_bits()), + ("0x1.ffep+8", 0x407ffe0000000000), + ("0x1p+0", 0x3ff0000000000000), + ("0x1.999999999999ap-4", 0x3fb999999999999a), + ("0x1.9p+6", 0x4059000000000000), + ("0x1.2d5ed1fe1da7bp+20", 0x4132d5ed1fe1da7b), + ("-0x1.348eb851eb852p+10", 0xc09348eb851eb852), + ("-0x1.33dcfe54a3803p-33", 0xbde33dcfe54a3803), + ("0x1.0p0", 1.0f64.to_bits()), + ("0x0.0p0", 0.0f64.to_bits()), + ("-0x0.0p0", (-0.0f64).to_bits()), + ("0x1.999999999999ap-4", 0.1f64.to_bits()), + ("0x1.999999999998ap-4", (0.1f64 - f64::EPSILON).to_bits()), + ("-0x1.999999999999ap-4", (-0.1f64).to_bits()), + ("-0x1.999999999998ap-4", (-0.1f64 + f64::EPSILON).to_bits()), + ("0x0.8000000000001p-1022", 0x0008000000000001), + ("0x0.123456789abcdp-1022", 0x000123456789abcd), + ("0x0.0000000000002p-1022", 0x0000000000000002), + ]; + for (s, exp) in checks { + println!("parsing {s}"); + let act = hf64(s).to_bits(); + assert_eq!( + act, exp, + "parsing {s}: {act:#018x} != {exp:#018x}\nact: {act:#066b}\nexp: {exp:#066b}" + ); + } + } + + #[test] + fn test_f32_almost_extra_precision() { + // Exact maximum precision allowed + hf32("0x1.abcdeep+0"); + } + + #[test] + fn test_macros() { + assert_eq!(hf32!("0x1.ffep+8").to_bits(), 0x43fff000u32); + assert_eq!(hf64!("0x1.ffep+8").to_bits(), 0x407ffe0000000000u64); + } +} + +#[cfg(test)] +// FIXME(ppc): something with `should_panic` tests cause a SIGILL with ppc64le +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +mod tests_panicking { + extern crate std; + use super::*; + + #[test] + #[should_panic] + fn test_f32_extra_precision2() { + // One bit more than the above. + hf32("0x1.ffffffp+127"); + } + + #[test] + #[should_panic(expected = "the value is too huge")] + fn test_f32_overflow() { + // One bit more than the above. + hf32("0x1p+128"); + } + + #[test] + #[should_panic(expected = "the value is too precise")] + fn test_f32_extra_precision() { + // One bit more than the above. + hf32("0x1.abcdefp+0"); + } + + #[test] + fn test_f32_tiniest() { + let x = hf32("0x1.p-149"); + let y = hf32("0x0.0000000000000001p-85"); + let z = hf32("0x0.8p-148"); + assert_eq!(x, y); + assert_eq!(x, z); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f32_too_tiny() { + hf32("0x1.p-150"); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f32_also_too_tiny() { + hf32("0x0.8p-149"); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f32_again_too_tiny() { + hf32("0x0.0000000000000001p-86"); + } + + #[test] + fn test_f64_almost_extra_precision() { + // Exact maximum precision allowed + hf64("0x1.abcdabcdabcdfp+0"); + } + + #[test] + #[should_panic(expected = "the value is too precise")] + fn test_f64_extra_precision() { + // One bit more than the above. + hf64("0x1.abcdabcdabcdf8p+0"); + } +} diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index b14bbec388d22..9441eace529da 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -105,3 +105,23 @@ macro_rules! select_implementation { (@cfg ; $ex:expr) => { }; (@cfg $provided:meta; $ex:expr) => { #[cfg($provided)] $ex }; } + +/// Construct a 32-bit float from hex float representation (C-style), guaranteed to +/// evaluate at compile time. +#[allow(unused_macros)] +macro_rules! hf32 { + ($s:literal) => {{ + const X: f32 = $crate::math::support::hf32($s); + X + }}; +} + +/// Construct a 64-bit float from hex float representation (C-style), guaranteed to +/// evaluate at compile time. +#[allow(unused_macros)] +macro_rules! hf64 { + ($s:literal) => {{ + const X: f64 = $crate::math::support::hf64($s); + X + }}; +} diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index f054df6cdf312..04a313abc97c9 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -1,7 +1,10 @@ #[macro_use] pub mod macros; mod float_traits; +mod hex_float; mod int_traits; pub use float_traits::Float; +#[allow(unused_imports)] +pub use hex_float::{hf32, hf64}; pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; From 9a9e47798f903447ffc3beb89b22284009c30e3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <44257381+JSorngard@users.noreply.github.com> Date: Fri, 1 Nov 2024 13:29:03 +0100 Subject: [PATCH 1438/4206] Add some more basic docstrings (#352) * Add docstrings to the tgamma functions * Add docstrings to the lgamma functions * Add docstrings to trunc * Add docstrings to exp10 functions --- library/compiler-builtins/libm/src/math/exp10.rs | 1 + library/compiler-builtins/libm/src/math/exp10f.rs | 1 + library/compiler-builtins/libm/src/math/lgamma.rs | 2 ++ library/compiler-builtins/libm/src/math/lgammaf.rs | 2 ++ library/compiler-builtins/libm/src/math/tgamma.rs | 1 + library/compiler-builtins/libm/src/math/tgammaf.rs | 1 + library/compiler-builtins/libm/src/math/trunc.rs | 3 +++ library/compiler-builtins/libm/src/math/truncf.rs | 3 +++ 8 files changed, 14 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/exp10.rs b/library/compiler-builtins/libm/src/math/exp10.rs index 559930e109fe6..2c3df0173441a 100644 --- a/library/compiler-builtins/libm/src/math/exp10.rs +++ b/library/compiler-builtins/libm/src/math/exp10.rs @@ -6,6 +6,7 @@ const P10: &[f64] = &[ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, ]; +/// Calculates 10 raised to the power of `x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp10(x: f64) -> f64 { let (mut y, n) = modf(x); diff --git a/library/compiler-builtins/libm/src/math/exp10f.rs b/library/compiler-builtins/libm/src/math/exp10f.rs index 786305481dcfb..e81d18380b940 100644 --- a/library/compiler-builtins/libm/src/math/exp10f.rs +++ b/library/compiler-builtins/libm/src/math/exp10f.rs @@ -5,6 +5,7 @@ const LN10_F64: f64 = 3.32192809488736234787031942948939; const P10: &[f32] = &[1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7]; +/// Calculates 10 raised to the power of `x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn exp10f(x: f32) -> f32 { let (mut y, n) = modff(x); diff --git a/library/compiler-builtins/libm/src/math/lgamma.rs b/library/compiler-builtins/libm/src/math/lgamma.rs index a08bc5b641e4f..8312dc18648e0 100644 --- a/library/compiler-builtins/libm/src/math/lgamma.rs +++ b/library/compiler-builtins/libm/src/math/lgamma.rs @@ -1,5 +1,7 @@ use super::lgamma_r; +/// The natural logarithm of the +/// [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn lgamma(x: f64) -> f64 { lgamma_r(x).0 diff --git a/library/compiler-builtins/libm/src/math/lgammaf.rs b/library/compiler-builtins/libm/src/math/lgammaf.rs index a9c2da75bd779..d37512397cb39 100644 --- a/library/compiler-builtins/libm/src/math/lgammaf.rs +++ b/library/compiler-builtins/libm/src/math/lgammaf.rs @@ -1,5 +1,7 @@ use super::lgammaf_r; +/// The natural logarithm of the +/// [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn lgammaf(x: f32) -> f32 { lgammaf_r(x).0 diff --git a/library/compiler-builtins/libm/src/math/tgamma.rs b/library/compiler-builtins/libm/src/math/tgamma.rs index 60451416ab322..3059860646a5b 100644 --- a/library/compiler-builtins/libm/src/math/tgamma.rs +++ b/library/compiler-builtins/libm/src/math/tgamma.rs @@ -130,6 +130,7 @@ fn s(x: f64) -> f64 { return num / den; } +/// The [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tgamma(mut x: f64) -> f64 { let u: u64 = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/tgammaf.rs b/library/compiler-builtins/libm/src/math/tgammaf.rs index 23e3814f99fd1..fe178f7a3c0ea 100644 --- a/library/compiler-builtins/libm/src/math/tgammaf.rs +++ b/library/compiler-builtins/libm/src/math/tgammaf.rs @@ -1,5 +1,6 @@ use super::tgamma; +/// The [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn tgammaf(x: f32) -> f32 { tgamma(x as f64) as f32 diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs index 6961bb950600e..34bc2fdfa48ca 100644 --- a/library/compiler-builtins/libm/src/math/trunc.rs +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -1,5 +1,8 @@ use core::f64; +/// Rounds the number toward 0 to the closest integral value (f64). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn trunc(x: f64) -> f64 { select_implementation! { diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs index 8270c8eb392d8..a74f789877236 100644 --- a/library/compiler-builtins/libm/src/math/truncf.rs +++ b/library/compiler-builtins/libm/src/math/truncf.rs @@ -1,5 +1,8 @@ use core::f32; +/// Rounds the number toward 0 to the closest integral value (f32). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn truncf(x: f32) -> f32 { select_implementation! { From c0f7b95e4350526519ab6c2044d1a1bc273297cd Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 1 Nov 2024 07:45:19 -0500 Subject: [PATCH 1439/4206] Resolve clippy errors in `libm` tests and check this in CI --- .../libm/.github/workflows/main.yml | 5 +- .../compiler-builtins/libm/src/math/ceil.rs | 6 +- .../compiler-builtins/libm/src/math/ceilf.rs | 6 +- .../compiler-builtins/libm/src/math/fabs.rs | 8 +- .../compiler-builtins/libm/src/math/fabsf.rs | 8 +- .../compiler-builtins/libm/src/math/floor.rs | 6 +- .../compiler-builtins/libm/src/math/floorf.rs | 6 +- .../compiler-builtins/libm/src/math/pow.rs | 85 +++++++++---------- .../compiler-builtins/libm/src/math/sqrt.rs | 9 +- .../compiler-builtins/libm/src/math/sqrtf.rs | 9 +- 10 files changed, 65 insertions(+), 83 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 14e5578847960..c79d637ec0392 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -106,9 +106,10 @@ jobs: cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} - name: Clippy - run: | + # Tests and utilities can't build on no_std targets + if: "!contains(matrix.target, 'thumb')" # Run clippy on `libm` - cargo clippy --target "${{ matrix.target }}" --package libm + run: cargo clippy --target "${{ matrix.target }}" --package libm --all-targets builtins: diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index c7e857dbb6fb8..c198ebcfe1bf3 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -34,8 +34,6 @@ pub fn ceil(x: f64) -> f64 { #[cfg(test)] mod tests { - use core::f64::*; - use super::*; #[test] @@ -48,8 +46,8 @@ mod tests { #[test] fn spec_tests() { // Not Asserted: that the current rounding mode has no effect. - assert!(ceil(NAN).is_nan()); - for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { + assert!(ceil(f64::NAN).is_nan()); + for f in [0.0, -0.0, f64::INFINITY, f64::NEG_INFINITY].iter().copied() { assert_eq!(ceil(f), f); } } diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index 0da384350aee8..9eb2ec07a422a 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -42,8 +42,6 @@ pub fn ceilf(x: f32) -> f32 { #[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { - use core::f32::*; - use super::*; #[test] @@ -56,8 +54,8 @@ mod tests { #[test] fn spec_tests() { // Not Asserted: that the current rounding mode has no effect. - assert!(ceilf(NAN).is_nan()); - for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { + assert!(ceilf(f32::NAN).is_nan()); + for f in [0.0, -0.0, f32::INFINITY, f32::NEG_INFINITY].iter().copied() { assert_eq!(ceilf(f), f); } } diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index d7980eb65f2a6..d083053e18834 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -14,8 +14,6 @@ pub fn fabs(x: f64) -> f64 { #[cfg(test)] mod tests { - use core::f64::*; - use super::*; #[test] @@ -27,12 +25,12 @@ mod tests { /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs #[test] fn spec_tests() { - assert!(fabs(NAN).is_nan()); + assert!(fabs(f64::NAN).is_nan()); for f in [0.0, -0.0].iter().copied() { assert_eq!(fabs(f), 0.0); } - for f in [INFINITY, NEG_INFINITY].iter().copied() { - assert_eq!(fabs(f), INFINITY); + for f in [f64::INFINITY, f64::NEG_INFINITY].iter().copied() { + assert_eq!(fabs(f), f64::INFINITY); } } } diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index 1dac6389d8f44..eabe87254b74a 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -16,8 +16,6 @@ pub fn fabsf(x: f32) -> f32 { #[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { - use core::f32::*; - use super::*; #[test] @@ -29,12 +27,12 @@ mod tests { /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs #[test] fn spec_tests() { - assert!(fabsf(NAN).is_nan()); + assert!(fabsf(f32::NAN).is_nan()); for f in [0.0, -0.0].iter().copied() { assert_eq!(fabsf(f), 0.0); } - for f in [INFINITY, NEG_INFINITY].iter().copied() { - assert_eq!(fabsf(f), INFINITY); + for f in [f32::INFINITY, f32::NEG_INFINITY].iter().copied() { + assert_eq!(fabsf(f), f32::INFINITY); } } } diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index 532226b9f86aa..e478f6d547288 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -33,8 +33,6 @@ pub fn floor(x: f64) -> f64 { #[cfg(test)] mod tests { - use core::f64::*; - use super::*; #[test] @@ -47,8 +45,8 @@ mod tests { #[test] fn spec_tests() { // Not Asserted: that the current rounding mode has no effect. - assert!(floor(NAN).is_nan()); - for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { + assert!(floor(f64::NAN).is_nan()); + for f in [0.0, -0.0, f64::INFINITY, f64::NEG_INFINITY].iter().copied() { assert_eq!(floor(f), f); } } diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index 4f38cb15b7d83..bd1570c86969c 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -42,8 +42,6 @@ pub fn floorf(x: f32) -> f32 { #[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { - use core::f32::*; - use super::*; #[test] @@ -57,8 +55,8 @@ mod tests { #[test] fn spec_tests() { // Not Asserted: that the current rounding mode has no effect. - assert!(floorf(NAN).is_nan()); - for f in [0.0, -0.0, INFINITY, NEG_INFINITY].iter().copied() { + assert!(floorf(f32::NAN).is_nan()); + for f in [0.0, -0.0, f32::INFINITY, f32::NEG_INFINITY].iter().copied() { assert_eq!(floorf(f), f); } } diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 736465cd16f6c..80b2a24999ccd 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -398,7 +398,6 @@ mod tests { extern crate core; use self::core::f64::consts::{E, PI}; - use self::core::f64::{EPSILON, INFINITY, MAX, MIN, MIN_POSITIVE, NAN, NEG_INFINITY}; use super::pow; const POS_ZERO: &[f64] = &[0.0]; @@ -407,15 +406,15 @@ mod tests { const NEG_ONE: &[f64] = &[-1.0]; const POS_FLOATS: &[f64] = &[99.0 / 70.0, E, PI]; const NEG_FLOATS: &[f64] = &[-99.0 / 70.0, -E, -PI]; - const POS_SMALL_FLOATS: &[f64] = &[(1.0 / 2.0), MIN_POSITIVE, EPSILON]; - const NEG_SMALL_FLOATS: &[f64] = &[-(1.0 / 2.0), -MIN_POSITIVE, -EPSILON]; - const POS_EVENS: &[f64] = &[2.0, 6.0, 8.0, 10.0, 22.0, 100.0, MAX]; - const NEG_EVENS: &[f64] = &[MIN, -100.0, -22.0, -10.0, -8.0, -6.0, -2.0]; + const POS_SMALL_FLOATS: &[f64] = &[(1.0 / 2.0), f64::MIN_POSITIVE, f64::EPSILON]; + const NEG_SMALL_FLOATS: &[f64] = &[-(1.0 / 2.0), -f64::MIN_POSITIVE, -f64::EPSILON]; + const POS_EVENS: &[f64] = &[2.0, 6.0, 8.0, 10.0, 22.0, 100.0, f64::MAX]; + const NEG_EVENS: &[f64] = &[f64::MIN, -100.0, -22.0, -10.0, -8.0, -6.0, -2.0]; const POS_ODDS: &[f64] = &[3.0, 7.0]; const NEG_ODDS: &[f64] = &[-7.0, -3.0]; - const NANS: &[f64] = &[NAN]; - const POS_INF: &[f64] = &[INFINITY]; - const NEG_INF: &[f64] = &[NEG_INFINITY]; + const NANS: &[f64] = &[f64::NAN]; + const POS_INF: &[f64] = &[f64::INFINITY]; + const NEG_INF: &[f64] = &[f64::NEG_INFINITY]; const ALL: &[&[f64]] = &[ POS_ZERO, @@ -492,83 +491,83 @@ mod tests { #[test] fn nan_inputs() { // NAN as the base: - // (NAN ^ anything *but 0* should be NAN) - test_sets_as_exponent(NAN, &ALL[2..], NAN); + // (f64::NAN ^ anything *but 0* should be f64::NAN) + test_sets_as_exponent(f64::NAN, &ALL[2..], f64::NAN); - // NAN as the exponent: - // (anything *but 1* ^ NAN should be NAN) - test_sets_as_base(&ALL[..(ALL.len() - 2)], NAN, NAN); + // f64::NAN as the exponent: + // (anything *but 1* ^ f64::NAN should be f64::NAN) + test_sets_as_base(&ALL[..(ALL.len() - 2)], f64::NAN, f64::NAN); } #[test] fn infinity_as_base() { // Positive Infinity as the base: - // (+Infinity ^ positive anything but 0 and NAN should be +Infinity) - test_sets_as_exponent(INFINITY, &POS[1..], INFINITY); + // (+Infinity ^ positive anything but 0 and f64::NAN should be +Infinity) + test_sets_as_exponent(f64::INFINITY, &POS[1..], f64::INFINITY); - // (+Infinity ^ negative anything except 0 and NAN should be 0.0) - test_sets_as_exponent(INFINITY, &NEG[1..], 0.0); + // (+Infinity ^ negative anything except 0 and f64::NAN should be 0.0) + test_sets_as_exponent(f64::INFINITY, &NEG[1..], 0.0); // Negative Infinity as the base: // (-Infinity ^ positive odd ints should be -Infinity) - test_sets_as_exponent(NEG_INFINITY, &[POS_ODDS], NEG_INFINITY); + test_sets_as_exponent(f64::NEG_INFINITY, &[POS_ODDS], f64::NEG_INFINITY); // (-Infinity ^ anything but odd ints should be == -0 ^ (-anything)) // We can lump in pos/neg odd ints here because they don't seem to // cause panics (div by zero) in release mode (I think). - test_sets(ALL, &|v: f64| pow(NEG_INFINITY, v), &|v: f64| pow(-0.0, -v)); + test_sets(ALL, &|v: f64| pow(f64::NEG_INFINITY, v), &|v: f64| pow(-0.0, -v)); } #[test] fn infinity_as_exponent() { // Positive/Negative base greater than 1: - // (pos/neg > 1 ^ Infinity should be Infinity - note this excludes NAN as the base) - test_sets_as_base(&ALL[5..(ALL.len() - 2)], INFINITY, INFINITY); + // (pos/neg > 1 ^ Infinity should be Infinity - note this excludes f64::NAN as the base) + test_sets_as_base(&ALL[5..(ALL.len() - 2)], f64::INFINITY, f64::INFINITY); // (pos/neg > 1 ^ -Infinity should be 0.0) - test_sets_as_base(&ALL[5..ALL.len() - 2], NEG_INFINITY, 0.0); + test_sets_as_base(&ALL[5..ALL.len() - 2], f64::NEG_INFINITY, 0.0); // Positive/Negative base less than 1: let base_below_one = &[POS_ZERO, NEG_ZERO, NEG_SMALL_FLOATS, POS_SMALL_FLOATS]; - // (pos/neg < 1 ^ Infinity should be 0.0 - this also excludes NAN as the base) - test_sets_as_base(base_below_one, INFINITY, 0.0); + // (pos/neg < 1 ^ Infinity should be 0.0 - this also excludes f64::NAN as the base) + test_sets_as_base(base_below_one, f64::INFINITY, 0.0); // (pos/neg < 1 ^ -Infinity should be Infinity) - test_sets_as_base(base_below_one, NEG_INFINITY, INFINITY); + test_sets_as_base(base_below_one, f64::NEG_INFINITY, f64::INFINITY); // Positive/Negative 1 as the base: // (pos/neg 1 ^ Infinity should be 1) - test_sets_as_base(&[NEG_ONE, POS_ONE], INFINITY, 1.0); + test_sets_as_base(&[NEG_ONE, POS_ONE], f64::INFINITY, 1.0); // (pos/neg 1 ^ -Infinity should be 1) - test_sets_as_base(&[NEG_ONE, POS_ONE], NEG_INFINITY, 1.0); + test_sets_as_base(&[NEG_ONE, POS_ONE], f64::NEG_INFINITY, 1.0); } #[test] fn zero_as_base() { // Positive Zero as the base: - // (+0 ^ anything positive but 0 and NAN should be +0) + // (+0 ^ anything positive but 0 and f64::NAN should be +0) test_sets_as_exponent(0.0, &POS[1..], 0.0); - // (+0 ^ anything negative but 0 and NAN should be Infinity) + // (+0 ^ anything negative but 0 and f64::NAN should be Infinity) // (this should panic because we're dividing by zero) - test_sets_as_exponent(0.0, &NEG[1..], INFINITY); + test_sets_as_exponent(0.0, &NEG[1..], f64::INFINITY); // Negative Zero as the base: - // (-0 ^ anything positive but 0, NAN, and odd ints should be +0) + // (-0 ^ anything positive but 0, f64::NAN, and odd ints should be +0) test_sets_as_exponent(-0.0, &POS[3..], 0.0); - // (-0 ^ anything negative but 0, NAN, and odd ints should be Infinity) + // (-0 ^ anything negative but 0, f64::NAN, and odd ints should be Infinity) // (should panic because of divide by zero) - test_sets_as_exponent(-0.0, &NEG[3..], INFINITY); + test_sets_as_exponent(-0.0, &NEG[3..], f64::INFINITY); // (-0 ^ positive odd ints should be -0) test_sets_as_exponent(-0.0, &[POS_ODDS], -0.0); // (-0 ^ negative odd ints should be -Infinity) // (should panic because of divide by zero) - test_sets_as_exponent(-0.0, &[NEG_ODDS], NEG_INFINITY); + test_sets_as_exponent(-0.0, &[NEG_ODDS], f64::NEG_INFINITY); } #[test] @@ -583,21 +582,17 @@ mod tests { // Factoring -1 out: // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer)) - (&[POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS]).iter().for_each( - |int_set| { - int_set.iter().for_each(|int| { - test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| { - pow(-1.0, *int) * pow(v, *int) - }); - }) - }, - ); + [POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS].iter().for_each(|int_set| { + int_set.iter().for_each(|int| { + test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| pow(-1.0, *int) * pow(v, *int)); + }) + }); // Negative base (imaginary results): // (-anything except 0 and Infinity ^ non-integer should be NAN) - (&NEG[1..(NEG.len() - 1)]).iter().for_each(|set| { + NEG[1..(NEG.len() - 1)].iter().for_each(|set| { set.iter().for_each(|val| { - test_sets(&ALL[3..7], &|v: f64| pow(*val, v), &|_| NAN); + test_sets(&ALL[3..7], &|v: f64| pow(*val, v), &|_| f64::NAN); }) }); } diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 3eaf52cda8ea0..d9a8f184ce0c2 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -224,8 +224,6 @@ pub fn sqrt(x: f64) -> f64 { #[cfg(test)] mod tests { - use core::f64::*; - use super::*; #[test] @@ -239,15 +237,16 @@ mod tests { fn spec_tests() { // Not Asserted: FE_INVALID exception is raised if argument is negative. assert!(sqrt(-1.0).is_nan()); - assert!(sqrt(NAN).is_nan()); - for f in [0.0, -0.0, INFINITY].iter().copied() { + assert!(sqrt(f64::NAN).is_nan()); + for f in [0.0, -0.0, f64::INFINITY].iter().copied() { assert_eq!(sqrt(f), f); } } #[test] + #[allow(clippy::approx_constant)] fn conformance_tests() { - let values = [3.14159265359, 10000.0, f64::from_bits(0x0000000f), INFINITY]; + let values = [3.14159265359, 10000.0, f64::from_bits(0x0000000f), f64::INFINITY]; let results = [ 4610661241675116657u64, 4636737291354636288u64, diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index d2f7ae70334c3..23f9a8443294e 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -110,8 +110,6 @@ pub fn sqrtf(x: f32) -> f32 { #[cfg(not(target_arch = "powerpc64"))] #[cfg(test)] mod tests { - use core::f32::*; - use super::*; #[test] @@ -125,15 +123,16 @@ mod tests { fn spec_tests() { // Not Asserted: FE_INVALID exception is raised if argument is negative. assert!(sqrtf(-1.0).is_nan()); - assert!(sqrtf(NAN).is_nan()); - for f in [0.0, -0.0, INFINITY].iter().copied() { + assert!(sqrtf(f32::NAN).is_nan()); + for f in [0.0, -0.0, f32::INFINITY].iter().copied() { assert_eq!(sqrtf(f), f); } } #[test] + #[allow(clippy::approx_constant)] fn conformance_tests() { - let values = [3.14159265359f32, 10000.0f32, f32::from_bits(0x0000000f), INFINITY]; + let values = [3.14159265359f32, 10000.0f32, f32::from_bits(0x0000000f), f32::INFINITY]; let results = [1071833029u32, 1120403456u32, 456082799u32, 2139095040u32]; for i in 0..values.len() { From 241135794761352bd48642fab948d889435915b8 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 1 Nov 2024 06:40:17 -0500 Subject: [PATCH 1440/4206] Fix clippy lints in `crates/` and enable this on CI --- .../libm/.github/workflows/main.yml | 24 ++++++++++++++----- .../libm/crates/libm-macros/src/lib.rs | 2 +- .../libm/crates/libm-test/src/gen/random.rs | 2 +- .../libm/crates/libm-test/src/precision.rs | 2 +- .../libm/crates/libm-test/src/test_traits.rs | 4 ++-- .../libm/crates/musl-math-sys/build.rs | 2 +- .../libm/crates/musl-math-sys/src/lib.rs | 7 ++++++ 7 files changed, 31 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index c79d637ec0392..866f0de9ec010 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -105,12 +105,24 @@ jobs: rustup target add x86_64-unknown-linux-musl cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} - - name: Clippy - # Tests and utilities can't build on no_std targets - if: "!contains(matrix.target, 'thumb')" - # Run clippy on `libm` - run: cargo clippy --target "${{ matrix.target }}" --package libm --all-targets - + clippy: + name: Clippy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Install Rust + run: | + rustup update nightly --no-self-update + rustup default nightly + rustup component add clippy + - uses: Swatinem/rust-cache@v2 + - name: Download musl source + run: ./ci/download-musl.sh + - run: | + cargo clippy --all \ + --exclude cb \ + --features libm-test/build-musl,libm-test/test-multiprecision \ + --all-targets builtins: name: Check use with compiler-builtins diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs index dc78598ca7619..41d13035cf47c 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs @@ -353,7 +353,7 @@ fn validate(input: &StructuredInput) -> syn::Result> if !input.skip.is_empty() && input.only.is_some() { let e = syn::Error::new( input.only_span.unwrap(), - format!("only one of `skip` or `only` may be specified"), + "only one of `skip` or `only` may be specified", ); return Err(e); } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index d03d1ff797f29..e347b3c63aeb9 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -37,7 +37,7 @@ static TEST_CASES: LazyLock = LazyLock::new(|| make_test_cases(NTES /// value so tests don't run forever. static TEST_CASES_JN: LazyLock = LazyLock::new(|| { // Start with regular test cases - let mut cases = (&*TEST_CASES).clone(); + let mut cases = (*TEST_CASES).clone(); // These functions are extremely slow, limit them let ntests_jn = (NTESTS / 1000).max(80); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 9ef0e818d13c8..5b021e9467dcf 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -238,7 +238,7 @@ fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Opt // abs and copysign require signaling NaNs to be propagated, so verify bit equality. if actual.to_bits() == expected.to_bits() { - return SKIP; + SKIP } else { Some(Err(anyhow::anyhow!("NaNs have different bitpatterns"))) } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index 67df83fb49215..e69e16d24a960 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -214,7 +214,7 @@ macro_rules! impl_int { }; } -fn validate_int<'a, I, Input>(actual: I, expected: I, input: Input, ctx: &CheckCtx) -> TestResult +fn validate_int(actual: I, expected: I, input: Input, ctx: &CheckCtx) -> TestResult where I: Int + Hex, Input: Hex + fmt::Debug, @@ -274,7 +274,7 @@ macro_rules! impl_float { }; } -fn validate_float<'a, F, Input>(actual: F, expected: F, input: Input, ctx: &CheckCtx) -> TestResult +fn validate_float(actual: F, expected: F, input: Input, ctx: &CheckCtx) -> TestResult where F: Float + Hex, Input: Hex + fmt::Debug, diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/build.rs b/library/compiler-builtins/libm/crates/musl-math-sys/build.rs index 03df06c7934df..03deb4ff0ac03 100644 --- a/library/compiler-builtins/libm/crates/musl-math-sys/build.rs +++ b/library/compiler-builtins/libm/crates/musl-math-sys/build.rs @@ -124,7 +124,7 @@ fn build_musl_math(cfg: &Config) { // Run configuration steps. Usually done as part of the musl `Makefile`. let obj_include = cfg.out_dir.join("musl_obj/include"); fs::create_dir_all(&obj_include).unwrap(); - fs::create_dir_all(&obj_include.join("bits")).unwrap(); + fs::create_dir_all(obj_include.join("bits")).unwrap(); let sed_stat = Command::new("sed") .arg("-f") .arg(musl_dir.join("tools/mkalltypes.sed")) diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs b/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs index fe3c89229b6fe..db352fab8df06 100644 --- a/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs +++ b/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs @@ -7,6 +7,7 @@ use std::ffi::{c_char, c_int, c_long}; /// unsound. macro_rules! functions { ( $( + $( #[$meta:meta] )* $pfx_name:ident: $name:ident( $($arg:ident: $aty:ty),+ ) -> $rty:ty; )* ) => { extern "C" { @@ -15,6 +16,7 @@ macro_rules! functions { $( // Expose a safe version + $( #[$meta] )* pub fn $name( $($arg: $aty),+ ) -> $rty { // SAFETY: FFI calls with no preconditions unsafe { $pfx_name( $($arg),+ ) } @@ -231,8 +233,13 @@ functions! { musl_logf: logf(a: f32) -> f32; musl_modf: modf(a: f64, b: &mut f64) -> f64; musl_modff: modff(a: f32, b: &mut f32) -> f32; + + // FIXME: these need to be unsafe + #[allow(clippy::not_unsafe_ptr_arg_deref)] musl_nan: nan(a: *const c_char) -> f64; + #[allow(clippy::not_unsafe_ptr_arg_deref)] musl_nanf: nanf(a: *const c_char) -> f32; + musl_nearbyint: nearbyint(a: f64) -> f64; musl_nearbyintf: nearbyintf(a: f32) -> f32; musl_nextafter: nextafter(a: f64, b: f64) -> f64; From 5b0a775c1244d40c7aa5b20b6f05279a14777374 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 31 Oct 2024 02:44:00 -0500 Subject: [PATCH 1441/4206] Adjust how the proc macro emits types and add an enum Currently the macro always provides `CFn`, `RustFn`, `RustArgs`, etc. Change this so that: 1. This information must be explicily requested in the invocation. 2. There is a new `FTy` field available that emits a single float type, rather than a tuple or signature. Additionally, add two new macros that create enums representing function names. --- .../libm/crates/libm-macros/Cargo.toml | 1 + .../libm/crates/libm-macros/src/enums.rs | 132 ++++++++++++ .../libm/crates/libm-macros/src/lib.rs | 191 ++++++++++++++---- .../libm/crates/libm-macros/src/parse.rs | 24 ++- .../libm/crates/libm-macros/tests/basic.rs | 50 +++-- .../libm/crates/libm-macros/tests/enum.rs | 19 ++ 6 files changed, 354 insertions(+), 63 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-macros/src/enums.rs create mode 100644 library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml index 3da9d45a2b9db..c9defb1c5cbb4 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml @@ -8,6 +8,7 @@ publish = false proc-macro = true [dependencies] +heck = "0.5.0" proc-macro2 = "1.0.88" quote = "1.0.37" syn = { version = "2.0.79", features = ["full", "extra-traits", "visit-mut"] } diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs b/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs new file mode 100644 index 0000000000000..d9017dff72bce --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs @@ -0,0 +1,132 @@ +use heck::ToUpperCamelCase; +use proc_macro2 as pm2; +use proc_macro2::{Ident, Span}; +use quote::quote; +use syn::spanned::Spanned; +use syn::{Fields, ItemEnum, Variant}; + +use crate::{ALL_FUNCTIONS_FLAT, base_name}; + +/// Implement `#[function_enum]`, see documentation in `lib.rs`. +pub fn function_enum( + mut item: ItemEnum, + attributes: pm2::TokenStream, +) -> syn::Result { + expect_empty_enum(&item)?; + let attr_span = attributes.span(); + let mut attr = attributes.into_iter(); + + // Attribute should be the identifier of the `BaseName` enum. + let Some(tt) = attr.next() else { + return Err(syn::Error::new(attr_span, "expected one attribute")); + }; + + let pm2::TokenTree::Ident(base_enum) = tt else { + return Err(syn::Error::new(tt.span(), "expected an identifier")); + }; + + if let Some(tt) = attr.next() { + return Err(syn::Error::new(tt.span(), "unexpected token after identifier")); + } + + let enum_name = &item.ident; + let mut as_str_arms = Vec::new(); + let mut base_arms = Vec::new(); + + for func in ALL_FUNCTIONS_FLAT.iter() { + let fn_name = func.name; + let ident = Ident::new(&fn_name.to_upper_camel_case(), Span::call_site()); + let bname_ident = Ident::new(&base_name(fn_name).to_upper_camel_case(), Span::call_site()); + + // Match arm for `fn as_str(self)` matcher + as_str_arms.push(quote! { Self::#ident => #fn_name }); + + // Match arm for `fn base_name(self)` matcher + base_arms.push(quote! { Self::#ident => #base_enum::#bname_ident }); + + let variant = + Variant { attrs: Vec::new(), ident, fields: Fields::Unit, discriminant: None }; + + item.variants.push(variant); + } + + let res = quote! { + // Instantiate the enum + #item + + impl #enum_name { + /// The stringified version of this function name. + const fn as_str(self) -> &'static str { + match self { + #( #as_str_arms , )* + } + } + + /// The base name enum for this function. + const fn base_name(self) -> #base_enum { + match self { + #( #base_arms, )* + } + } + } + }; + + Ok(res) +} + +/// Implement `#[base_name_enum]`, see documentation in `lib.rs`. +pub fn base_name_enum( + mut item: ItemEnum, + attributes: pm2::TokenStream, +) -> syn::Result { + expect_empty_enum(&item)?; + if !attributes.is_empty() { + let sp = attributes.span(); + return Err(syn::Error::new(sp.span(), "no attributes expected")); + } + + let mut base_names: Vec<_> = + ALL_FUNCTIONS_FLAT.iter().map(|func| base_name(func.name)).collect(); + base_names.sort_unstable(); + base_names.dedup(); + + let item_name = &item.ident; + let mut as_str_arms = Vec::new(); + + for base_name in base_names { + let ident = Ident::new(&base_name.to_upper_camel_case(), Span::call_site()); + + // Match arm for `fn as_str(self)` matcher + as_str_arms.push(quote! { Self::#ident => #base_name }); + + let variant = + Variant { attrs: Vec::new(), ident, fields: Fields::Unit, discriminant: None }; + + item.variants.push(variant); + } + + let res = quote! { + // Instantiate the enum + #item + + impl #item_name { + /// The stringified version of this base name. + const fn as_str(self) -> &'static str { + match self { + #( #as_str_arms ),* + } + } + } + }; + + Ok(res) +} + +/// Verify that an enum is empty, otherwise return an error +fn expect_empty_enum(item: &ItemEnum) -> syn::Result<()> { + if !item.variants.is_empty() { + Err(syn::Error::new(item.variants.span(), "expected an empty enum")) + } else { + Ok(()) + } +} diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs index 41d13035cf47c..2db412e79a1d7 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs @@ -1,16 +1,20 @@ +mod enums; mod parse; + use std::sync::LazyLock; use parse::{Invocation, StructuredInput}; use proc_macro as pm; use proc_macro2::{self as pm2, Span}; use quote::{ToTokens, quote}; -use syn::Ident; +use syn::spanned::Spanned; use syn::visit_mut::VisitMut; +use syn::{Ident, ItemEnum}; -const ALL_FUNCTIONS: &[(Signature, Option, &[&str])] = &[ +const ALL_FUNCTIONS: &[(Ty, Signature, Option, &[&str])] = &[ ( // `fn(f32) -> f32` + Ty::F32, Signature { args: &[Ty::F32], returns: &[Ty::F32] }, None, &[ @@ -22,6 +26,7 @@ const ALL_FUNCTIONS: &[(Signature, Option, &[&str])] = &[ ), ( // `(f64) -> f64` + Ty::F64, Signature { args: &[Ty::F64], returns: &[Ty::F64] }, None, &[ @@ -33,6 +38,7 @@ const ALL_FUNCTIONS: &[(Signature, Option, &[&str])] = &[ ), ( // `(f32, f32) -> f32` + Ty::F32, Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32] }, None, &[ @@ -50,6 +56,7 @@ const ALL_FUNCTIONS: &[(Signature, Option, &[&str])] = &[ ), ( // `(f64, f64) -> f64` + Ty::F64, Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64] }, None, &[ @@ -67,102 +74,120 @@ const ALL_FUNCTIONS: &[(Signature, Option, &[&str])] = &[ ), ( // `(f32, f32, f32) -> f32` + Ty::F32, Signature { args: &[Ty::F32, Ty::F32, Ty::F32], returns: &[Ty::F32] }, None, &["fmaf"], ), ( // `(f64, f64, f64) -> f64` + Ty::F64, Signature { args: &[Ty::F64, Ty::F64, Ty::F64], returns: &[Ty::F64] }, None, &["fma"], ), ( // `(f32) -> i32` + Ty::F32, Signature { args: &[Ty::F32], returns: &[Ty::I32] }, None, &["ilogbf"], ), ( // `(f64) -> i32` + Ty::F64, Signature { args: &[Ty::F64], returns: &[Ty::I32] }, None, &["ilogb"], ), ( // `(i32, f32) -> f32` + Ty::F32, Signature { args: &[Ty::I32, Ty::F32], returns: &[Ty::F32] }, None, &["jnf"], ), ( // `(i32, f64) -> f64` + Ty::F64, Signature { args: &[Ty::I32, Ty::F64], returns: &[Ty::F64] }, None, &["jn"], ), ( // `(f32, i32) -> f32` + Ty::F32, Signature { args: &[Ty::F32, Ty::I32], returns: &[Ty::F32] }, None, &["scalbnf", "ldexpf"], ), ( // `(f64, i64) -> f64` + Ty::F64, Signature { args: &[Ty::F64, Ty::I32], returns: &[Ty::F64] }, None, &["scalbn", "ldexp"], ), ( // `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)` + Ty::F32, Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] }, Some(Signature { args: &[Ty::F32, Ty::MutF32], returns: &[Ty::F32] }), &["modff"], ), ( // `(f64, &mut f64) -> f64` as `(f64) -> (f64, f64)` + Ty::F64, Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] }, Some(Signature { args: &[Ty::F64, Ty::MutF64], returns: &[Ty::F64] }), &["modf"], ), ( // `(f32, &mut c_int) -> f32` as `(f32) -> (f32, i32)` + Ty::F32, Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::I32] }, Some(Signature { args: &[Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }), &["frexpf", "lgammaf_r"], ), ( // `(f64, &mut c_int) -> f64` as `(f64) -> (f64, i32)` + Ty::F64, Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::I32] }, Some(Signature { args: &[Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }), &["frexp", "lgamma_r"], ), ( // `(f32, f32, &mut c_int) -> f32` as `(f32, f32) -> (f32, i32)` + Ty::F32, Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32, Ty::I32] }, Some(Signature { args: &[Ty::F32, Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }), &["remquof"], ), ( // `(f64, f64, &mut c_int) -> f64` as `(f64, f64) -> (f64, i32)` + Ty::F64, Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64, Ty::I32] }, Some(Signature { args: &[Ty::F64, Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }), &["remquo"], ), ( // `(f32, &mut f32, &mut f32)` as `(f32) -> (f32, f32)` + Ty::F32, Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] }, Some(Signature { args: &[Ty::F32, Ty::MutF32, Ty::MutF32], returns: &[] }), &["sincosf"], ), ( // `(f64, &mut f64, &mut f64)` as `(f64) -> (f64, f64)` + Ty::F64, Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] }, Some(Signature { args: &[Ty::F64, Ty::MutF64, Ty::MutF64], returns: &[] }), &["sincos"], ), ]; +const KNOWN_TYPES: &[&str] = &["FTy", "CFn", "CArgs", "CRet", "RustFn", "RustArgs", "RustRet"]; + /// A type used in a function signature. #[allow(dead_code)] #[derive(Debug, Clone, Copy)] @@ -190,12 +215,12 @@ impl ToTokens for Ty { Ty::F128 => quote! { f128 }, Ty::I32 => quote! { i32 }, Ty::CInt => quote! { ::core::ffi::c_int }, - Ty::MutF16 => quote! { &mut f16 }, - Ty::MutF32 => quote! { &mut f32 }, - Ty::MutF64 => quote! { &mut f64 }, - Ty::MutF128 => quote! { &mut f128 }, - Ty::MutI32 => quote! { &mut i32 }, - Ty::MutCInt => quote! { &mut 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); @@ -213,6 +238,7 @@ struct Signature { #[derive(Debug, Clone)] struct FunctionInfo { name: &'static str, + base_fty: Ty, /// Function signature for C implementations c_sig: Signature, /// Function signature for Rust implementations @@ -223,10 +249,11 @@ struct FunctionInfo { static ALL_FUNCTIONS_FLAT: LazyLock> = LazyLock::new(|| { let mut ret = Vec::new(); - for (rust_sig, c_sig, names) in ALL_FUNCTIONS { + for (base_fty, rust_sig, c_sig, names) in ALL_FUNCTIONS { for name in *names { let api = FunctionInfo { name, + base_fty: *base_fty, rust_sig: rust_sig.clone(), c_sig: c_sig.clone().unwrap_or_else(|| rust_sig.clone()), }; @@ -238,6 +265,37 @@ static ALL_FUNCTIONS_FLAT: LazyLock> = LazyLock::new(|| { ret }); +/// Populate an enum with a variant representing function. Names are in upper camel case. +/// +/// Applied to an empty enum. Expects one attribute `#[function_enum(BaseName)]` that provides +/// the name of the `BaseName` enum. +#[proc_macro_attribute] +pub fn function_enum(attributes: pm::TokenStream, tokens: pm::TokenStream) -> pm::TokenStream { + let item = syn::parse_macro_input!(tokens as ItemEnum); + let res = enums::function_enum(item, attributes.into()); + + match res { + Ok(ts) => ts, + Err(e) => e.into_compile_error(), + } + .into() +} + +/// Create an enum representing all possible base names, with names in upper camel case. +/// +/// Applied to an empty enum. +#[proc_macro_attribute] +pub fn base_name_enum(attributes: pm::TokenStream, tokens: pm::TokenStream) -> pm::TokenStream { + let item = syn::parse_macro_input!(tokens as ItemEnum); + let res = enums::base_name_enum(item, attributes.into()); + + match res { + Ok(ts) => ts, + Err(e) => e.into_compile_error(), + } + .into() +} + /// Do something for each function present in this crate. /// /// Takes a callback macro and invokes it multiple times, once for each function that @@ -258,6 +316,8 @@ static ALL_FUNCTIONS_FLAT: LazyLock> = LazyLock::new(|| { /// ( /// // 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)`) @@ -279,17 +339,16 @@ static ALL_FUNCTIONS_FLAT: LazyLock> = LazyLock::new(|| { /// ) => { }; /// } /// +/// // All fields except for `callback` are optional. /// libm_macros::for_each_function! { /// // The macro to invoke as a callback /// callback: callback_macro, +/// // Which types to include either as a list (`[CFn, RustFn, RustArgs]`) or "all" +/// emit_types: all, /// // Functions to skip, i.e. `callback` shouldn't be called at all for these. -/// // -/// // This is an optional field. /// skip: [sin, cos], /// // Attributes passed as `attrs` for specific functions. For example, here the invocation /// // with `sinf` and that with `cosf` will both get `meta1` and `meta2`, but no others will. -/// // -/// // This is an optional field. /// attributes: [ /// #[meta1] /// #[meta2] @@ -297,8 +356,6 @@ static ALL_FUNCTIONS_FLAT: LazyLock> = LazyLock::new(|| { /// ], /// // Any tokens that should be passed directly to all invocations of the callback. This can /// // be used to pass local variables or other things the macro needs access to. -/// // -/// // This is an optional field. /// extra: [foo], /// // Similar to `extra`, but allow providing a pattern for only specific functions. Uses /// // a simplified match-like syntax. @@ -313,7 +370,7 @@ pub fn for_each_function(tokens: pm::TokenStream) -> pm::TokenStream { let input = syn::parse_macro_input!(tokens as Invocation); let res = StructuredInput::from_fields(input) - .and_then(|s_in| validate(&s_in).map(|fn_list| (s_in, fn_list))) + .and_then(|mut s_in| validate(&mut s_in).map(|fn_list| (s_in, fn_list))) .and_then(|(s_in, fn_list)| expand(s_in, &fn_list)); match res { @@ -325,7 +382,7 @@ pub fn for_each_function(tokens: pm::TokenStream) -> pm::TokenStream { /// Check for any input that is structurally correct but has other problems. /// /// Returns the list of function names that we should expand for. -fn validate(input: &StructuredInput) -> syn::Result> { +fn validate(input: &mut StructuredInput) -> syn::Result> { // Collect lists of all functions that are provied as macro inputs in various fields (only, // skip, attributes). let attr_mentions = input @@ -376,6 +433,43 @@ fn validate(input: &StructuredInput) -> syn::Result> fn_list.push(func); } + // Types that the user would like us to provide in the macro + let mut add_all_types = false; + for ty in &input.emit_types { + let ty_name = ty.to_string(); + if ty_name == "all" { + add_all_types = true; + continue; + } + + // Check that all requested types are valid + if !KNOWN_TYPES.contains(&ty_name.as_str()) { + let e = syn::Error::new( + ty_name.span(), + format!("unrecognized type identifier `{ty_name}`"), + ); + return Err(e); + } + } + + if add_all_types { + // Ensure that if `all` was specified that nothing else was + if input.emit_types.len() > 1 { + let e = syn::Error::new( + input.emit_types_span.unwrap(), + "if `all` is specified, no other type identifiers may be given", + ); + return Err(e); + } + + // ...and then add all types + input.emit_types.clear(); + for ty in KNOWN_TYPES { + let ident = Ident::new(ty, Span::call_site()); + input.emit_types.push(ident); + } + } + if let Some(map) = &input.fn_extra { if !map.keys().any(|key| key == "_") { // No default provided; make sure every expected function is covered @@ -451,20 +545,31 @@ fn expand(input: StructuredInput, fn_list: &[&FunctionInfo]) -> syn::Result pm2::TokenStream::new(), }; + let base_fty = func.base_fty; 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 mut ty_fields = Vec::new(); + for ty in &input.emit_types { + let field = match ty.to_string().as_str() { + "FTy" => quote! { FTy: #base_fty, }, + "CFn" => quote! { CFn: fn( #(#c_args),* ,) -> ( #(#c_ret),* ), }, + "CArgs" => quote! { CArgs: ( #(#c_args),* ,), }, + "CRet" => quote! { CRet: ( #(#c_ret),* ), }, + "RustFn" => quote! { RustFn: fn( #(#rust_args),* ,) -> ( #(#rust_ret),* ), }, + "RustArgs" => quote! { RustArgs: ( #(#rust_args),* ,), }, + "RustRet" => quote! { RustRet: ( #(#rust_ret),* ), }, + _ => unreachable!("checked in validation"), + }; + ty_fields.push(field); + } + let new = quote! { #callback! { fn_name: #fn_name, - CFn: fn( #(#c_args),* ,) -> ( #(#c_ret),* ), - CArgs: ( #(#c_args),* ,), - CRet: ( #(#c_ret),* ), - RustFn: fn( #(#rust_args),* ,) -> ( #(#rust_ret),* ), - RustArgs: ( #(#rust_args),* ,), - RustRet: ( #(#rust_ret),* ), + #( #ty_fields )* #meta_field #extra_field #fn_extra_field @@ -488,24 +593,7 @@ struct MacroReplace { impl MacroReplace { fn new(name: &'static str) -> Self { - // Keep this in sync with `libm_test::canonical_name` - let known_mappings = &[ - ("erff", "erf"), - ("erf", "erf"), - ("lgammaf_r", "lgamma_r"), - ("modff", "modf"), - ("modf", "modf"), - ]; - - let norm_name = 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("f128")) - .unwrap_or(name), - }; - + let norm_name = base_name(name); Self { fn_name: name, norm_name: norm_name.to_owned(), error: None } } @@ -539,3 +627,24 @@ impl VisitMut for MacroReplace { syn::visit_mut::visit_ident_mut(self, i); } } + +/// Return the unsuffixed name of a function. +fn base_name(name: &str) -> &str { + // Keep this in sync with `libm_test::base_name` + let known_mappings = &[ + ("erff", "erf"), + ("erf", "erf"), + ("lgammaf_r", "lgamma_r"), + ("modff", "modf"), + ("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("f128")) + .unwrap_or(name), + } +} diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/parse.rs b/library/compiler-builtins/libm/crates/libm-macros/src/parse.rs index ee9bd524bbefb..369bbae2f4faf 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/parse.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/parse.rs @@ -5,7 +5,7 @@ use quote::ToTokens; use syn::parse::{Parse, ParseStream, Parser}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; -use syn::token::Comma; +use syn::token::{self, Comma}; use syn::{Arm, Attribute, Expr, ExprMatch, Ident, Meta, Token, bracketed}; /// The input to our macro; just a list of `field: value` items. @@ -39,6 +39,9 @@ impl Parse for Mapping { pub struct StructuredInput { /// Macro to invoke once per function pub callback: Ident, + /// Whether or not to provide `CFn` `CArgs` `RustFn` etc. This is really only needed + /// once for crate to set up the main trait. + pub emit_types: Vec, /// Skip these functions pub skip: Vec, /// Invoke only for these functions @@ -50,6 +53,7 @@ pub struct StructuredInput { /// Per-function extra expressions to pass to the macro pub fn_extra: Option>, // For diagnostics + pub emit_types_span: Option, pub only_span: Option, pub fn_extra_span: Option, } @@ -58,6 +62,7 @@ impl StructuredInput { pub fn from_fields(input: Invocation) -> syn::Result { let mut map: Vec<_> = input.fields.into_iter().collect(); let cb_expr = expect_field(&mut map, "callback")?; + let emit_types_expr = expect_field(&mut map, "emit_types").ok(); let skip_expr = expect_field(&mut map, "skip").ok(); let only_expr = expect_field(&mut map, "only").ok(); let attr_expr = expect_field(&mut map, "attributes").ok(); @@ -71,6 +76,12 @@ impl StructuredInput { ))?; } + let emit_types_span = emit_types_expr.as_ref().map(|expr| expr.span()); + let emit_types = match emit_types_expr { + Some(expr) => Parser::parse2(parse_ident_or_array, expr.into_token_stream())?, + None => Vec::new(), + }; + let skip = match skip_expr { Some(expr) => Parser::parse2(parse_ident_array, expr.into_token_stream())?, None => Vec::new(), @@ -103,6 +114,7 @@ impl StructuredInput { Ok(Self { callback: expect_ident(cb_expr)?, + emit_types, skip, only, only_span, @@ -110,6 +122,7 @@ impl StructuredInput { extra, fn_extra, fn_extra_span, + emit_types_span, }) } } @@ -183,6 +196,15 @@ fn expect_ident(expr: Expr) -> syn::Result { syn::parse2(expr.into_token_stream()) } +/// Parse either a single identifier (`foo`) or an array of identifiers (`[foo, bar, baz]`). +fn parse_ident_or_array(input: ParseStream) -> syn::Result> { + if !input.peek(token::Bracket) { + return Ok(vec![input.parse()?]); + } + + parse_ident_array(input) +} + /// Parse an array of expressions. fn parse_expr_array(input: ParseStream) -> syn::Result> { let content; diff --git a/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs b/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs index 8f8c09f1b64a8..2eaba04f4c676 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs @@ -4,6 +4,7 @@ macro_rules! basic { ( fn_name: $fn_name:ident, + FTy: $FTy:ty, CFn: $CFn:ty, CArgs: $CArgs:ty, CRet: $CRet:ty, @@ -17,9 +18,9 @@ macro_rules! basic { $(#[$meta])* mod $fn_name { #[allow(unused)] - type CFnTy = $CFn; - // type CArgsTy<'_> = $CArgs; - // type CRetTy<'_> = $CRet; + type FTy= $FTy; + #[allow(unused)] + type CFnTy<'a> = $CFn; #[allow(unused)] type RustFnTy = $RustFn; #[allow(unused)] @@ -39,6 +40,7 @@ macro_rules! basic { mod test_basic { libm_macros::for_each_function! { callback: basic, + emit_types: all, skip: [sin, cos], attributes: [ // just some random attributes @@ -58,25 +60,8 @@ mod test_basic { macro_rules! basic_no_extra { ( fn_name: $fn_name:ident, - CFn: $CFn:ty, - CArgs: $CArgs:ty, - CRet: $CRet:ty, - RustFn: $RustFn:ty, - RustArgs: $RustArgs:ty, - RustRet: $RustRet:ty, ) => { - mod $fn_name { - #[allow(unused)] - type CFnTy = $CFn; - // type CArgsTy<'_> = $CArgs; - // type CRetTy<'_> = $CRet; - #[allow(unused)] - type RustFnTy = $RustFn; - #[allow(unused)] - type RustArgsTy = $RustArgs; - #[allow(unused)] - type RustRetTy = $RustRet; - } + mod $fn_name {} }; } @@ -94,3 +79,26 @@ mod test_only { only: [sin, sinf], } } + +macro_rules! specified_types { + ( + fn_name: $fn_name:ident, + RustFn: $RustFn:ty, + RustArgs: $RustArgs:ty, + ) => { + mod $fn_name { + #[allow(unused)] + type RustFnTy = $RustFn; + #[allow(unused)] + type RustArgsTy = $RustArgs; + } + }; +} + +mod test_emit_types { + // Test that we can specify a couple types to emit + libm_macros::for_each_function! { + callback: specified_types, + emit_types: [RustFn, RustArgs], + } +} diff --git a/library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs b/library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs new file mode 100644 index 0000000000000..884b8d8d65189 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs @@ -0,0 +1,19 @@ +#[libm_macros::function_enum(BaseName)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum Function {} + +#[libm_macros::base_name_enum] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum BaseName {} + +#[test] +fn as_str() { + assert_eq!(Function::Sin.as_str(), "sin"); + assert_eq!(Function::Sinf.as_str(), "sinf"); +} + +#[test] +fn basename() { + assert_eq!(Function::Sin.base_name(), BaseName::Sin); + assert_eq!(Function::Sinf.base_name(), BaseName::Sin); +} From 7db74d78e8918eaa091f546931a3b7b9b64b68b4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 31 Oct 2024 02:45:37 -0500 Subject: [PATCH 1442/4206] Introduce a `op` module with struct representations of each routine This contains: 1. Per-function and per-operation enums created by the proc macro 2. The `MathOp` trait which is implemented once per struct representing a function 3. Submodules for each function, each containing a `Routine` struct that implements `MathOp` --- .../libm/crates/libm-test/src/lib.rs | 2 + .../libm/crates/libm-test/src/op.rs | 111 ++++++++++++++++++ .../libm/crates/libm-test/src/test_traits.rs | 4 +- 3 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/op.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 56a872779d6cc..e64ad62640852 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -1,10 +1,12 @@ pub mod gen; #[cfg(feature = "test-multiprecision")] pub mod mpfloat; +pub mod op; mod precision; mod test_traits; pub use libm::support::{Float, Int}; +pub use op::{BaseName, MathOp, Name}; pub use precision::{MaybeOverride, SpecialCase, multiprec_allowed_ulp, musl_allowed_ulp}; pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, Hex, TupleCall}; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/op.rs b/library/compiler-builtins/libm/crates/libm-test/src/op.rs new file mode 100644 index 0000000000000..fe0a08a28e511 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/op.rs @@ -0,0 +1,111 @@ +//! Types representing individual functions. +//! +//! Each routine gets a module with its name, e.g. `mod sinf { /* ... */ }`. The module +//! contains a unit struct `Routine` which implements `MathOp`. +//! +//! Basically everything could be called a "function" here, so we loosely use the following +//! terminology: +//! +//! - "Function": the math operation that does not have an associated precision. E.g. `f(x) = e^x`, +//! `f(x) = log(x)`. +//! - "Routine": A code implementation of a math operation with a specific precision. E.g. `exp`, +//! `expf`, `expl`, `log`, `logf`. +//! - "Operation" / "Op": Something that relates a routine to a function or is otherwise higher +//! level. `Op` is also used as the name for generic parameters since it is terse. + +use crate::{CheckOutput, Float, TupleCall}; + +/// An enum representing each possible routine name. +#[libm_macros::function_enum(BaseName)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum Name {} + +/// The name without any type specifier, e.g. `sin` and `sinf` both become `sin`. +#[libm_macros::base_name_enum] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum 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; + + /// Arguments passed to the C library function as a tuple. These may include `&mut` return + /// values. + type CArgs<'a> + where + Self: 'a; + + /// The type returned by C implementations. + type CRet; + + /// The signature of the Rust function as a `fn(...) -> ...` type. + type RustFn: Copy; + + /// Arguments passed to the Rust library function as a tuple. + /// + /// The required `TupleCall` bounds ensure this type can be passed either to the C function or + /// to the Rust function. + type RustArgs: Copy + + TupleCall + + TupleCall; + + /// Type returned from the Rust function. + type RustRet: CheckOutput; + + /// The name of this function, including suffix (e.g. `sin`, `sinf`). + const NAME: Name; + + /// The name as a string. + const NAME_STR: &'static str = Self::NAME.as_str(); + + /// The name of the function excluding the type suffix, e.g. `sin` and `sinf` are both `sin`. + const BASE_NAME: BaseName = Self::NAME.base_name(); + + /// The function in `libm` which can be called. + const ROUTINE: Self::RustFn; +} + +macro_rules! do_thing { + // Matcher for unary functions + ( + fn_name: $fn_name:ident, + FTy: $FTy:ty, + CFn: $CFn:ty, + CArgs: $CArgs:ty, + CRet: $CRet:ty, + RustFn: $RustFn:ty, + RustArgs: $RustArgs:ty, + RustRet: $RustRet:ty, + ) => { + paste::paste! { + pub mod $fn_name { + use super::*; + 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; + type RustFn = $RustFn; + type RustArgs = $RustArgs; + type RustRet = $RustRet; + + const NAME: Name = Name::[< $fn_name:camel >]; + const ROUTINE: Self::RustFn = libm::$fn_name; + } + } + + } + }; +} + +libm_macros::for_each_function! { + callback: do_thing, + emit_types: all, +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index e69e16d24a960..b9bec9a447957 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -137,7 +137,7 @@ where } } -impl TupleCall for (T1,) +impl TupleCall fn(T1, &'a mut T2, &'a mut T3)> for (T1,) where T1: fmt::Debug, T2: fmt::Debug + Default, @@ -145,7 +145,7 @@ where { type Output = (T2, T3); - fn call(self, f: fn(T1, &mut T2, &mut T3)) -> Self::Output { + fn call(self, f: for<'a> fn(T1, &'a mut T2, &'a mut T3)) -> Self::Output { let mut t2 = T2::default(); let mut t3 = T3::default(); f(self.0, &mut t2, &mut t3); From f7f24a4ed899d75179176709622d4f6912188262 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 31 Oct 2024 02:46:21 -0500 Subject: [PATCH 1443/4206] Rework tests to make use of the new `MathOp` trait --- .../libm/crates/libm-test/benches/random.rs | 129 ++++--- .../libm/crates/libm-test/src/mpfloat.rs | 355 +++++++----------- .../crates/libm-test/tests/check_coverage.rs | 6 - .../libm-test/tests/compare_built_musl.rs | 54 +-- .../crates/libm-test/tests/multiprecision.rs | 49 +-- 5 files changed, 278 insertions(+), 315 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 6c9047c3cdb4f..6f2305dd27eba 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -2,72 +2,103 @@ use std::hint::black_box; use std::time::Duration; use criterion::{Criterion, criterion_main}; -use libm_test::gen::random; -use libm_test::{CheckBasis, CheckCtx, TupleCall}; +use libm_test::gen::{CachedInput, random}; +use libm_test::{CheckBasis, CheckCtx, GenerateInput, MathOp, TupleCall}; /// Benchmark with this many items to get a variety const BENCH_ITER_ITEMS: usize = if cfg!(feature = "short-benchmarks") { 50 } else { 500 }; +/// Extra parameters we only care about if we are benchmarking against musl. +#[allow(dead_code)] +struct MuslExtra { + musl_fn: Option, + skip_on_i586: bool, +} + macro_rules! musl_rand_benches { ( fn_name: $fn_name:ident, - CFn: $CFn:ty, - CArgs: $CArgs:ty, - CRet: $CRet:ty, - RustFn: $RustFn:ty, - RustArgs: $RustArgs:ty, - RustRet: $RustRet:ty, fn_extra: $skip_on_i586:expr, ) => { paste::paste! { fn [< musl_bench_ $fn_name >](c: &mut Criterion) { - let fn_name = stringify!($fn_name); - - let ulp = libm_test::musl_allowed_ulp(fn_name); - let ctx = CheckCtx::new(ulp, fn_name, CheckBasis::Musl); - let benchvec: Vec<_> = random::get_test_cases::<$RustArgs>(&ctx) - .take(BENCH_ITER_ITEMS) - .collect(); + type Op = libm_test::op::$fn_name::Routine; - // Perform a sanity check that we are benchmarking the same thing - // Don't test against musl if it is not available #[cfg(feature = "build-musl")] - for input in benchvec.iter().copied() { - use anyhow::Context; - use libm_test::{CheckBasis, CheckCtx, CheckOutput}; + let musl_extra = MuslExtra { + musl_fn: Some(musl_math_sys::$fn_name as ::CFn), + skip_on_i586: $skip_on_i586 + }; + + #[cfg(not(feature = "build-musl"))] + let musl_extra = MuslExtra { + musl_fn: None, + skip_on_i586: $skip_on_i586 + }; + + bench_one::(c, musl_extra); + } + } + }; +} - if cfg!(x86_no_sse) && $skip_on_i586 { - break; - } +fn bench_one(c: &mut Criterion, musl_extra: MuslExtra) +where + Op: MathOp, + CachedInput: GenerateInput, +{ + let name = Op::NAME_STR; + + let ulp = libm_test::musl_allowed_ulp(name); + let ctx = CheckCtx::new(ulp, name, CheckBasis::Musl); + let benchvec: Vec<_> = + random::get_test_cases::(&ctx).take(BENCH_ITER_ITEMS).collect(); + + // Perform a sanity check that we are benchmarking the same thing + // Don't test against musl if it is not available + #[cfg(feature = "build-musl")] + for input in benchvec.iter().copied() { + use anyhow::Context; + use libm_test::CheckOutput; + + if cfg!(x86_no_sse) && musl_extra.skip_on_i586 { + break; + } - let musl_res = input.call(musl_math_sys::$fn_name as $CFn); - let crate_res = input.call(libm::$fn_name as $RustFn); + let musl_res = input.call(musl_extra.musl_fn.unwrap()); + let crate_res = input.call(Op::ROUTINE); - let ctx = CheckCtx::new(ulp, fn_name, CheckBasis::Musl); - crate_res.validate(musl_res, input, &ctx).context(fn_name).unwrap(); - } + crate_res.validate(musl_res, input, &ctx).context(name).unwrap(); + } - /* Function pointers are black boxed to avoid inlining in the benchmark loop */ + #[cfg(not(feature = "build-musl"))] + let _ = musl_extra; // silence unused warnings - let mut group = c.benchmark_group(fn_name); - group.bench_function("crate", |b| b.iter(|| { - let f = black_box(libm::$fn_name as $RustFn); - for input in benchvec.iter().copied() { - input.call(f); - } - })); + /* Option pointers are black boxed to avoid inlining in the benchmark loop */ - // Don't test against musl if it is not available - #[cfg(feature = "build-musl")] - group.bench_function("musl", |b| b.iter(|| { - let f = black_box(musl_math_sys::$fn_name as $CFn); - for input in benchvec.iter().copied() { - input.call(f); - } - })); + let mut group = c.benchmark_group(name); + group.bench_function("crate", |b| { + b.iter(|| { + let f = black_box(Op::ROUTINE); + for input in benchvec.iter().copied() { + input.call(f); } - } - }; + }) + }); + + // Don't test against musl if it is not available + #[cfg(feature = "build-musl")] + { + let musl_fn = musl_extra.musl_fn.unwrap(); + group.bench_function("musl", |b| { + b.iter(|| { + let f = black_box(musl_fn); + for input in benchvec.iter().copied() { + input.call(f); + } + }) + }); + } } libm_macros::for_each_function! { @@ -83,12 +114,6 @@ libm_macros::for_each_function! { macro_rules! run_callback { ( fn_name: $fn_name:ident, - CFn: $_CFn:ty, - CArgs: $_CArgs:ty, - CRet: $_CRet:ty, - RustFn: $_RustFn:ty, - RustArgs: $_RustArgs:ty, - RustRet: $_RustRet:ty, extra: [$criterion:ident], ) => { paste::paste! { diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 2e6fdae7f19d1..507b077b37cda 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -11,7 +11,7 @@ pub use rug::Float as MpFloat; use rug::float::Round::Nearest; use rug::ops::{PowAssignRound, RemAssignRound}; -use crate::Float; +use crate::{Float, MathOp}; /// Create a multiple-precision float with the correct number of bits for a concrete float type. fn new_mpfloat() -> MpFloat { @@ -29,23 +29,19 @@ where /// Structures that represent a float operation. /// -/// The struct itself should hold any context that can be reused among calls to `run` (allocated -/// `MpFloat`s). -pub trait MpOp { - /// Inputs to the operation (concrete float types). - type Input; - - /// Outputs from the operation (concrete float types). - type Output; +pub trait MpOp: MathOp { + /// The struct itself should hold any context that can be reused among calls to `run` (allocated + /// `MpFloat`s). + type MpTy; /// Create a new instance. - fn new() -> Self; + fn new_mp() -> Self::MpTy; /// Perform the operation. /// /// Usually this means assigning inputs to cached floats, performing the operation, applying /// subnormal approximation, and converting the result back to concrete values. - fn run(&mut self, input: Self::Input) -> Self::Output; + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet; } /// Implement `MpOp` for functions with a single return value. @@ -53,32 +49,21 @@ macro_rules! impl_mp_op { // Matcher for unary functions ( fn_name: $fn_name:ident, - CFn: $CFn:ty, - CArgs: $CArgs:ty, - CRet: $CRet:ty, - RustFn: fn($fty:ty,) -> $_ret:ty, - RustArgs: $RustArgs:ty, - RustRet: $RustRet:ty, + RustFn: fn($_fty:ty,) -> $_ret:ty, fn_extra: $fn_name_normalized:expr, ) => { paste::paste! { - pub mod $fn_name { - use super::*; - pub struct Operation(MpFloat); - - impl MpOp for Operation { - type Input = $RustArgs; - type Output = $RustRet; - - fn new() -> Self { - Self(new_mpfloat::<$fty>()) - } - - fn run(&mut self, input: Self::Input) -> Self::Output { - self.0.assign(input.0); - let ord = self.0.[< $fn_name_normalized _round >](Nearest); - prep_retval::(&mut self.0, ord) - } + impl MpOp for crate::op::$fn_name::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.[< $fn_name_normalized _round >](Nearest); + prep_retval::(this, ord) } } } @@ -86,33 +71,22 @@ macro_rules! impl_mp_op { // Matcher for binary functions ( fn_name: $fn_name:ident, - CFn: $CFn:ty, - CArgs: $CArgs:ty, - CRet: $CRet:ty, - RustFn: fn($fty:ty, $_fty2:ty,) -> $_ret:ty, - RustArgs: $RustArgs:ty, - RustRet: $RustRet:ty, + RustFn: fn($_fty:ty, $_fty2:ty,) -> $_ret:ty, fn_extra: $fn_name_normalized:expr, ) => { paste::paste! { - pub mod $fn_name { - use super::*; - pub struct Operation(MpFloat, MpFloat); - - impl MpOp for Operation { - type Input = $RustArgs; - type Output = $RustRet; - - fn new() -> Self { - Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) - } - - fn run(&mut self, input: Self::Input) -> Self::Output { - self.0.assign(input.0); - self.1.assign(input.1); - let ord = self.0.[< $fn_name_normalized _round >](&self.1, Nearest); - prep_retval::(&mut self.0, ord) - } + impl MpOp for crate::op::$fn_name::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.[< $fn_name_normalized _round >](&this.1, Nearest); + prep_retval::(&mut this.0, ord) } } } @@ -120,34 +94,27 @@ macro_rules! impl_mp_op { // Matcher for ternary functions ( fn_name: $fn_name:ident, - CFn: $CFn:ty, - CArgs: $CArgs:ty, - CRet: $CRet:ty, - RustFn: fn($fty:ty, $_fty2:ty, $_fty3:ty,) -> $_ret:ty, - RustArgs: $RustArgs:ty, - RustRet: $RustRet:ty, + RustFn: fn($_fty:ty, $_fty2:ty, $_fty3:ty,) -> $_ret:ty, fn_extra: $fn_name_normalized:expr, ) => { paste::paste! { - pub mod $fn_name { - use super::*; - pub struct Operation(MpFloat, MpFloat, MpFloat); - - impl MpOp for Operation { - type Input = $RustArgs; - type Output = $RustRet; - - fn new() -> Self { - Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) - } - - fn run(&mut self, input: Self::Input) -> Self::Output { - self.0.assign(input.0); - self.1.assign(input.1); - self.2.assign(input.2); - let ord = self.0.[< $fn_name_normalized _round >](&self.1, &self.2, Nearest); - prep_retval::(&mut self.0, ord) - } + impl MpOp for crate::op::$fn_name::Routine { + type MpTy = (MpFloat, MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + ( + new_mpfloat::(), + 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.2.assign(input.2); + let ord = this.0.[< $fn_name_normalized _round >](&this.1, &this.2, Nearest); + prep_retval::(&mut this.0, ord) } } } @@ -156,6 +123,7 @@ macro_rules! impl_mp_op { libm_macros::for_each_function! { callback: impl_mp_op, + emit_types: [RustFn], skip: [ // Most of these need a manual implementation fabs, ceil, copysign, floor, rint, round, trunc, @@ -186,29 +154,23 @@ macro_rules! impl_no_round { ($($fn_name:ident, $rug_name:ident;)*) => { paste::paste! { // Implement for both f32 and f64 - $( impl_no_round!{ @inner_unary [< $fn_name f >], (f32,), $rug_name } )* - $( impl_no_round!{ @inner_unary $fn_name, (f64,), $rug_name } )* + $( impl_no_round!{ @inner_unary [< $fn_name f >], $rug_name } )* + $( impl_no_round!{ @inner_unary $fn_name, $rug_name } )* } }; - (@inner_unary $fn_name:ident, ($fty:ty,), $rug_name:ident) => { - pub mod $fn_name { - use super::*; - pub struct Operation(MpFloat); + (@inner_unary $fn_name:ident, $rug_name:ident) => { + impl MpOp for crate::op::$fn_name::Routine { + type MpTy = MpFloat; - impl MpOp for Operation { - type Input = ($fty,); - type Output = $fty; - - fn new() -> Self { - Self(new_mpfloat::<$fty>()) - } + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } - fn run(&mut self, input: Self::Input) -> Self::Output { - self.0.assign(input.0); - self.0.$rug_name(); - prep_retval::(&mut self.0, Ordering::Equal) - } + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + this.$rug_name(); + prep_retval::(this, Ordering::Equal) } } }; @@ -227,132 +189,81 @@ impl_no_round! { macro_rules! impl_op_for_ty { ($fty:ty, $suffix:literal) => { paste::paste! { - pub mod [] { - use super::*; - pub struct Operation(MpFloat, MpFloat); - - impl MpOp for Operation { - type Input = ($fty, $fty); - type Output = $fty; - - fn new() -> Self { - Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) - } - - fn run(&mut self, input: Self::Input) -> Self::Output { - self.0.assign(input.0); - self.1.assign(input.1); - self.0.copysign_mut(&self.1); - prep_retval::(&mut self.0, Ordering::Equal) - } + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) } - } - pub mod [] { - use super::*; - pub struct Operation(MpFloat, MpFloat); + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + this.0.copysign_mut(&this.1); + prep_retval::(&mut this.0, Ordering::Equal) + } + } - impl MpOp for Operation { - type Input = ($fty, $fty); - type Output = $fty; + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); - fn new() -> Self { - Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) - } + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } - fn run(&mut self, input: Self::Input) -> Self::Output { - self.0.assign(input.0); - self.1.assign(input.1); - let ord = self.0.pow_assign_round(&self.1, Nearest); - prep_retval::(&mut self.0, ord) - } + 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.pow_assign_round(&this.1, Nearest); + prep_retval::(&mut this.0, ord) } } - pub mod [] { - use super::*; - pub struct Operation(MpFloat, MpFloat); + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); - impl MpOp for Operation { - type Input = ($fty, $fty); - type Output = $fty; - - fn new() -> Self { - Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) - } + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } - fn run(&mut self, input: Self::Input) -> Self::Output { - self.0.assign(input.0); - self.1.assign(input.1); - let ord = self.0.rem_assign_round(&self.1, Nearest); - prep_retval::(&mut self.0, ord) - } + 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.rem_assign_round(&this.1, Nearest); + prep_retval::(&mut this.0, ord) } } - pub mod [] { - use super::*; - pub struct Operation(MpFloat); - - impl MpOp for Operation { - type Input = ($fty,); - type Output = ($fty, i32); + impl MpOp for crate::op::[]::Routine { + type MpTy = (i32, MpFloat); - fn new() -> Self { - Self(new_mpfloat::<$fty>()) - } + fn new_mp() -> Self::MpTy { + (0, new_mpfloat::()) + } - fn run(&mut self, input: Self::Input) -> Self::Output { - self.0.assign(input.0); - let (sign, ord) = self.0.ln_abs_gamma_round(Nearest); - let ret = prep_retval::<$fty>(&mut self.0, ord); - (ret, sign as i32) - } + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0 = input.0; + this.1.assign(input.1); + let ord = this.1.jn_round(this.0, Nearest); + prep_retval::(&mut this.1, ord) } } - pub mod [] { - use super::*; - pub struct Operation(i32, MpFloat); - - impl MpOp for Operation { - type Input = (i32, $fty); - type Output = $fty; + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); - fn new() -> Self { - Self(0, new_mpfloat::<$fty>()) - } - - fn run(&mut self, input: Self::Input) -> Self::Output { - self.0 = input.0; - self.1.assign(input.1); - let ord = self.1.jn_round(self.0, Nearest); - prep_retval::<$fty>(&mut self.1, ord) - } + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) } - } - pub mod [] { - use super::*; - pub struct Operation(MpFloat, MpFloat); - - impl MpOp for Operation { - type Input = ($fty,); - type Output = ($fty, $fty); - - fn new() -> Self { - Self(new_mpfloat::<$fty>(), new_mpfloat::<$fty>()) - } - - fn run(&mut self, input: Self::Input) -> Self::Output { - self.0.assign(input.0); - self.1.assign(0.0); - let (sord, cord) = self.0.sin_cos_round(&mut self.1, Nearest); - ( - prep_retval::<$fty>(&mut self.0, sord), - prep_retval::<$fty>(&mut self.1, cord) - ) - } + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + 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) + ) } } } @@ -362,7 +273,33 @@ macro_rules! impl_op_for_ty { impl_op_for_ty!(f32, "f"); impl_op_for_ty!(f64, ""); -// Account for `lgamma_r` not having a simple `f` suffix -pub mod lgammaf_r { - pub use super::lgamma_rf::*; +// `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; + + fn new_mp() -> Self::MpTy { + 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); + (ret, sign as i32) + } +} + +impl MpOp for crate::op::lgammaf_r::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 (sign, ord) = this.ln_abs_gamma_round(Nearest); + let ret = prep_retval::(this, ord); + (ret, sign as i32) + } } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs b/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs index ef6d21fdbbad5..b7988660e6623 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs @@ -22,12 +22,6 @@ const ALLOWED_SKIPS: &[&str] = &[ macro_rules! callback { ( fn_name: $name:ident, - CFn: $_CFn:ty, - CArgs: $_CArgs:ty, - CRet: $_CRet:ty, - RustFn: $_RustFn:ty, - RustArgs: $_RustArgs:ty, - RustRet: $_RustRet:ty, extra: [$push_to:ident], ) => { $push_to.push(stringify!($name)); diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 5a118f7c209d9..d4ba9e90010b0 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -9,42 +9,46 @@ // There are some targets we can't build musl for #![cfg(feature = "build-musl")] -use libm_test::gen::random; -use libm_test::{CheckBasis, CheckCtx, CheckOutput, TupleCall, musl_allowed_ulp}; -use musl_math_sys as musl; +use libm_test::gen::{CachedInput, random}; +use libm_test::{ + CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, TupleCall, musl_allowed_ulp, +}; macro_rules! musl_rand_tests { ( fn_name: $fn_name:ident, - CFn: $CFn:ty, - CArgs: $CArgs:ty, - CRet: $CRet:ty, - RustFn: $RustFn:ty, - RustArgs: $RustArgs:ty, - RustRet: $RustRet:ty, attrs: [$($meta:meta)*] - ) => { paste::paste! { - #[test] - $(#[$meta])* - fn [< musl_random_ $fn_name >]() { - let fname = stringify!($fn_name); - let ulp = musl_allowed_ulp(fname); - let ctx = CheckCtx::new(ulp, fname, CheckBasis::Musl); - let cases = random::get_test_cases::<$RustArgs>(&ctx); - - for input in cases { - let musl_res = input.call(musl::$fn_name as $CFn); - let crate_res = input.call(libm::$fn_name as $RustFn); - - crate_res.validate(musl_res, input, &ctx).unwrap(); + ) => { + paste::paste! { + #[test] + $(#[$meta])* + fn [< musl_random_ $fn_name >]() { + test_one::(musl_math_sys::$fn_name); } } - } }; + }; +} + +fn test_one(musl_fn: Op::CFn) +where + Op: MathOp, + CachedInput: GenerateInput, +{ + let name = Op::NAME_STR; + let ulp = musl_allowed_ulp(name); + let ctx = CheckCtx::new(ulp, name, CheckBasis::Musl); + let cases = random::get_test_cases::(&ctx); + + for input in cases { + let musl_res = input.call(musl_fn); + let crate_res = input.call(Op::ROUTINE); + + crate_res.validate(musl_res, input, &ctx).unwrap(); + } } libm_macros::for_each_function! { callback: musl_rand_tests, - skip: [], attributes: [ #[cfg_attr(x86_no_sse, ignore)] // FIXME(correctness): wrong result on i586 [exp10, exp10f, exp2, exp2f, rint] diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index f8d94a1609e90..676ee86a0d00b 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -2,45 +2,48 @@ #![cfg(feature = "test-multiprecision")] -use libm_test::gen::random; -use libm_test::mpfloat::{self, MpOp}; -use libm_test::{CheckBasis, CheckCtx, CheckOutput, TupleCall, multiprec_allowed_ulp}; +use libm_test::gen::{CachedInput, random}; +use libm_test::mpfloat::MpOp; +use libm_test::{ + CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, TupleCall, multiprec_allowed_ulp, +}; /// Implement a test against MPFR with random inputs. macro_rules! multiprec_rand_tests { ( fn_name: $fn_name:ident, - CFn: $CFn:ty, - CArgs: $CArgs:ty, - CRet: $CRet:ty, - RustFn: $RustFn:ty, - RustArgs: $RustArgs:ty, - RustRet: $RustRet:ty, attrs: [$($meta:meta)*] ) => { paste::paste! { #[test] $(#[$meta])* fn [< multiprec_random_ $fn_name >]() { - type MpOpTy = mpfloat::$fn_name::Operation; - - let fname = stringify!($fn_name); - let ulp = multiprec_allowed_ulp(fname); - let mut mp_vals = MpOpTy::new(); - let ctx = CheckCtx::new(ulp, fname, CheckBasis::Mpfr); - let cases = random::get_test_cases::<$RustArgs>(&ctx); - - for input in cases { - let mp_res = mp_vals.run(input); - let crate_res = input.call(libm::$fn_name as $RustFn); - - crate_res.validate(mp_res, input, &ctx).unwrap(); - } + test_one::(); } } }; } +fn test_one() +where + Op: MathOp + MpOp, + CachedInput: GenerateInput, +{ + let name = Op::NAME_STR; + + let ulp = multiprec_allowed_ulp(name); + let mut mp_vals = Op::new_mp(); + let ctx = CheckCtx::new(ulp, name, CheckBasis::Mpfr); + let cases = random::get_test_cases::(&ctx); + + for input in cases { + let mp_res = Op::run(&mut mp_vals, input); + let crate_res = input.call(Op::ROUTINE); + + crate_res.validate(mp_res, input, &ctx).unwrap(); + } +} + libm_macros::for_each_function! { callback: multiprec_rand_tests, attributes: [ From 6aef9e17c8b3f606cf42a7a233f69e489f17edb6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 2 Nov 2024 16:52:28 -0500 Subject: [PATCH 1444/4206] Correct the proc macro to emit `pub` functions --- .../compiler-builtins/libm/crates/libm-macros/src/enums.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs b/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs index d9017dff72bce..1f9fca2ef9e9d 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs @@ -56,14 +56,14 @@ pub fn function_enum( impl #enum_name { /// The stringified version of this function name. - const fn as_str(self) -> &'static str { + pub const fn as_str(self) -> &'static str { match self { #( #as_str_arms , )* } } /// The base name enum for this function. - const fn base_name(self) -> #base_enum { + pub const fn base_name(self) -> #base_enum { match self { #( #base_arms, )* } @@ -111,7 +111,7 @@ pub fn base_name_enum( impl #item_name { /// The stringified version of this base name. - const fn as_str(self) -> &'static str { + pub const fn as_str(self) -> &'static str { match self { #( #as_str_arms ),* } From 2fab4f4580b584489d25ed1f1173a3fc8713997f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 2 Nov 2024 22:35:30 -0500 Subject: [PATCH 1445/4206] Change the `CheckCtx` constructor to take a `Name` enum This prepares to eliminate some reliance on string matching but does not yet make those changes. --- .../libm/crates/libm-macros/src/lib.rs | 4 +-- .../libm/crates/libm-test/benches/random.rs | 2 +- .../libm/crates/libm-test/src/gen/random.rs | 7 ++-- .../libm/crates/libm-test/src/lib.rs | 21 ------------ .../libm/crates/libm-test/src/precision.rs | 32 +++++++++---------- .../libm/crates/libm-test/src/test_traits.rs | 20 ++++++++---- .../libm-test/tests/compare_built_musl.rs | 2 +- .../crates/libm-test/tests/multiprecision.rs | 2 +- 8 files changed, 40 insertions(+), 50 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs index 2db412e79a1d7..1e7cd08b908eb 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs @@ -628,9 +628,9 @@ impl VisitMut for MacroReplace { } } -/// Return the unsuffixed name of a function. +/// 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 { - // Keep this in sync with `libm_test::base_name` let known_mappings = &[ ("erff", "erf"), ("erf", "erf"), diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 6f2305dd27eba..72ace5d5335e2 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -50,7 +50,7 @@ where let name = Op::NAME_STR; let ulp = libm_test::musl_allowed_ulp(name); - let ctx = CheckCtx::new(ulp, name, CheckBasis::Musl); + let ctx = CheckCtx::new(ulp, Op::NAME, CheckBasis::Musl); let benchvec: Vec<_> = random::get_test_cases::(&ctx).take(BENCH_ITER_ITEMS).collect(); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index e347b3c63aeb9..b72247a4e9f04 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -110,7 +110,10 @@ pub fn get_test_cases(ctx: &CheckCtx) -> impl Iterator, { - let inputs = - if ctx.fn_name == "jn" || ctx.fn_name == "jnf" { &TEST_CASES_JN } else { &TEST_CASES }; + let inputs = if ctx.fn_name_str == "jn" || ctx.fn_name_str == "jnf" { + &TEST_CASES_JN + } else { + &TEST_CASES + }; inputs.get_cases() } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index e64ad62640852..af6ad6da56a31 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -17,27 +17,6 @@ pub type TestResult = Result; // List of all files present in libm's source include!(concat!(env!("OUT_DIR"), "/all_files.rs")); -/// 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`. -pub fn base_name(name: &str) -> &str { - let known_mappings = &[ - ("erff", "erf"), - ("erf", "erf"), - ("lgammaf_r", "lgamma_r"), - ("modff", "modf"), - ("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("f128")) - .unwrap_or(name), - } -} - /// True if `EMULATED` is set and nonempty. Used to determine how many iterations to run. pub const fn emulated() -> bool { match option_env!("EMULATED") { diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 5b021e9467dcf..5b5743020d737 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -111,25 +111,25 @@ impl MaybeOverride<(f32,)> for SpecialCase { ctx: &CheckCtx, ) -> Option { if ctx.basis == CheckBasis::Musl { - if ctx.fn_name == "expm1f" && input.0 > 80.0 && actual.is_infinite() { + if ctx.fn_name_str == "expm1f" && input.0 > 80.0 && actual.is_infinite() { // we return infinity but the number is representable return XFAIL; } - if ctx.fn_name == "sinhf" && input.0.abs() > 80.0 && actual.is_nan() { + if ctx.fn_name_str == "sinhf" && input.0.abs() > 80.0 && actual.is_nan() { // we return some NaN that should be real values or infinite // doesn't seem to happen on x86 return XFAIL; } } - if ctx.fn_name == "acoshf" && input.0 < -1.0 { + if ctx.fn_name_str == "acoshf" && input.0 < -1.0 { // acoshf is undefined for x <= 1.0, but we return a random result at lower // values. return XFAIL; } - if ctx.fn_name == "lgammaf" || ctx.fn_name == "lgammaf_r" && input.0 < 0.0 { + if ctx.fn_name_str == "lgammaf" || ctx.fn_name_str == "lgammaf_r" && input.0 < 0.0 { // loggamma should not be defined for x < 0, yet we both return results return XFAIL; } @@ -146,7 +146,7 @@ impl MaybeOverride<(f32,)> for SpecialCase { // On MPFR for lgammaf_r, we set -1 as the integer result for negative infinity but MPFR // sets +1 if ctx.basis == CheckBasis::Mpfr - && ctx.fn_name == "lgammaf_r" + && ctx.fn_name_str == "lgammaf_r" && input.0 == f32::NEG_INFINITY && actual.abs() == expected.abs() { @@ -166,13 +166,13 @@ impl MaybeOverride<(f64,)> for SpecialCase { ctx: &CheckCtx, ) -> Option { if ctx.basis == CheckBasis::Musl { - if cfg!(target_arch = "x86") && ctx.fn_name == "acosh" && input.0 < 1.0 { + if cfg!(target_arch = "x86") && ctx.fn_name_str == "acosh" && input.0 < 1.0 { // The function is undefined, both implementations return random results return SKIP; } if cfg!(x86_no_sse) - && ctx.fn_name == "ceil" + && ctx.fn_name_str == "ceil" && input.0 < 0.0 && input.0 > -1.0 && expected == F::ZERO @@ -183,13 +183,13 @@ impl MaybeOverride<(f64,)> for SpecialCase { } } - if ctx.fn_name == "acosh" && input.0 < 1.0 { + if ctx.fn_name_str == "acosh" && input.0 < 1.0 { // The function is undefined for the inputs, musl and our libm both return // random results. return XFAIL; } - if ctx.fn_name == "lgamma" || ctx.fn_name == "lgamma_r" && input.0 < 0.0 { + if ctx.fn_name_str == "lgamma" || ctx.fn_name_str == "lgamma_r" && input.0 < 0.0 { // loggamma should not be defined for x < 0, yet we both return results return XFAIL; } @@ -206,7 +206,7 @@ impl MaybeOverride<(f64,)> for SpecialCase { // On MPFR for lgamma_r, we set -1 as the integer result for negative infinity but MPFR // sets +1 if ctx.basis == CheckBasis::Mpfr - && ctx.fn_name == "lgamma_r" + && ctx.fn_name_str == "lgamma_r" && input.0 == f64::NEG_INFINITY && actual.abs() == expected.abs() { @@ -219,7 +219,7 @@ impl MaybeOverride<(f64,)> for SpecialCase { /// Check NaN bits if the function requires it fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Option { - if !(ctx.base_name == "fabs" || ctx.base_name == "copysign") { + if !(ctx.base_name_str == "fabs" || ctx.base_name_str == "copysign") { return None; } @@ -277,7 +277,7 @@ fn maybe_skip_binop_nan( ) -> Option { match ctx.basis { CheckBasis::Musl => { - if (ctx.base_name == "fmax" || ctx.base_name == "fmin") + if (ctx.base_name_str == "fmax" || ctx.base_name_str == "fmin") && (input.0.is_nan() || input.1.is_nan()) && expected.is_nan() { @@ -287,7 +287,7 @@ fn maybe_skip_binop_nan( } } CheckBasis::Mpfr => { - if ctx.base_name == "copysign" && input.1.is_nan() { + if ctx.base_name_str == "copysign" && input.1.is_nan() { SKIP } else { None @@ -308,7 +308,7 @@ impl MaybeOverride<(i32, f32)> for SpecialCase { CheckBasis::Musl => bessel_prec_dropoff(input, ulp, ctx), CheckBasis::Mpfr => { // We return +0.0, MPFR returns -0.0 - if ctx.fn_name == "jnf" + if ctx.fn_name_str == "jnf" && input.1 == f32::NEG_INFINITY && actual == F::ZERO && expected == F::ZERO @@ -333,7 +333,7 @@ impl MaybeOverride<(i32, f64)> for SpecialCase { CheckBasis::Musl => bessel_prec_dropoff(input, ulp, ctx), CheckBasis::Mpfr => { // We return +0.0, MPFR returns -0.0 - if ctx.fn_name == "jn" + if ctx.fn_name_str == "jn" && input.1 == f64::NEG_INFINITY && actual == F::ZERO && expected == F::ZERO @@ -353,7 +353,7 @@ fn bessel_prec_dropoff( ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - if ctx.base_name == "jn" { + if ctx.base_name_str == "jn" { if input.0 > 4000 { return XFAIL; } else if input.0 > 2000 { diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index b9bec9a447957..65faefd33a9c3 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -11,25 +11,33 @@ use std::fmt; use anyhow::{Context, bail, ensure}; -use crate::{Float, Int, MaybeOverride, SpecialCase, TestResult}; +use crate::{BaseName, Float, Int, MaybeOverride, Name, SpecialCase, TestResult}; /// Context passed to [`CheckOutput`]. #[derive(Clone, Debug, PartialEq, Eq)] pub struct CheckCtx { /// Allowed ULP deviation pub ulp: u32, + pub fn_name: Name, + pub base_name: BaseName, /// Function name. - pub fn_name: &'static str, + pub fn_name_str: &'static str, /// Return the unsuffixed version of the function name. - pub base_name: &'static str, + pub base_name_str: &'static str, /// Source of truth for tests. pub basis: CheckBasis, } impl CheckCtx { - pub fn new(ulp: u32, fname: &'static str, basis: CheckBasis) -> Self { - let base_name = crate::base_name(fname); - Self { ulp, fn_name: fname, base_name, basis } + pub fn new(ulp: u32, fn_name: Name, basis: CheckBasis) -> Self { + Self { + ulp, + fn_name, + fn_name_str: fn_name.as_str(), + base_name: fn_name.base_name(), + base_name_str: fn_name.base_name().as_str(), + basis, + } } } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index d4ba9e90010b0..f4c827fc93152 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -36,7 +36,7 @@ where { let name = Op::NAME_STR; let ulp = musl_allowed_ulp(name); - let ctx = CheckCtx::new(ulp, name, CheckBasis::Musl); + let ctx = CheckCtx::new(ulp, Op::NAME, CheckBasis::Musl); let cases = random::get_test_cases::(&ctx); for input in cases { diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 676ee86a0d00b..5f38d846226b5 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -33,7 +33,7 @@ where let ulp = multiprec_allowed_ulp(name); let mut mp_vals = Op::new_mp(); - let ctx = CheckCtx::new(ulp, name, CheckBasis::Mpfr); + let ctx = CheckCtx::new(ulp, Op::NAME, CheckBasis::Mpfr); let cases = random::get_test_cases::(&ctx); for input in cases { From f113f2be1e2b58d9a99807d3fd921c61799eff0f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 2 Nov 2024 22:40:09 -0500 Subject: [PATCH 1446/4206] Rename `Name` to `Identifier` to avoid some ambiguity of "name" --- .../libm/crates/libm-test/benches/random.rs | 4 ++-- .../libm/crates/libm-test/src/gen/random.rs | 7 ++---- .../libm/crates/libm-test/src/lib.rs | 2 +- .../libm/crates/libm-test/src/op.rs | 12 +++++----- .../libm/crates/libm-test/src/precision.rs | 24 +++++++++---------- .../libm/crates/libm-test/src/test_traits.rs | 16 ++++++------- .../libm-test/tests/compare_built_musl.rs | 4 ++-- .../crates/libm-test/tests/multiprecision.rs | 4 ++-- 8 files changed, 35 insertions(+), 38 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 72ace5d5335e2..5eea433194549 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -47,10 +47,10 @@ where Op: MathOp, CachedInput: GenerateInput, { - let name = Op::NAME_STR; + let name = Op::NAME; let ulp = libm_test::musl_allowed_ulp(name); - let ctx = CheckCtx::new(ulp, Op::NAME, CheckBasis::Musl); + let ctx = CheckCtx::new(ulp, Op::IDENTIFIER, CheckBasis::Musl); let benchvec: Vec<_> = random::get_test_cases::(&ctx).take(BENCH_ITER_ITEMS).collect(); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index b72247a4e9f04..e347b3c63aeb9 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -110,10 +110,7 @@ pub fn get_test_cases(ctx: &CheckCtx) -> impl Iterator, { - let inputs = if ctx.fn_name_str == "jn" || ctx.fn_name_str == "jnf" { - &TEST_CASES_JN - } else { - &TEST_CASES - }; + let inputs = + if ctx.fn_name == "jn" || ctx.fn_name == "jnf" { &TEST_CASES_JN } else { &TEST_CASES }; inputs.get_cases() } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index af6ad6da56a31..914e5824486f8 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -6,7 +6,7 @@ mod precision; mod test_traits; pub use libm::support::{Float, Int}; -pub use op::{BaseName, MathOp, Name}; +pub use op::{BaseName, Identifier, MathOp}; pub use precision::{MaybeOverride, SpecialCase, multiprec_allowed_ulp, musl_allowed_ulp}; pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, Hex, TupleCall}; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/op.rs b/library/compiler-builtins/libm/crates/libm-test/src/op.rs index fe0a08a28e511..50b455d3a9366 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/op.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/op.rs @@ -15,10 +15,10 @@ use crate::{CheckOutput, Float, TupleCall}; -/// An enum representing each possible routine name. +/// An enum representing each possible symbol name (`sin`, `sinf`, `sinl`, etc). #[libm_macros::function_enum(BaseName)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum Name {} +pub enum Identifier {} /// The name without any type specifier, e.g. `sin` and `sinf` both become `sin`. #[libm_macros::base_name_enum] @@ -58,13 +58,13 @@ pub trait MathOp { type RustRet: CheckOutput; /// The name of this function, including suffix (e.g. `sin`, `sinf`). - const NAME: Name; + const IDENTIFIER: Identifier; /// The name as a string. - const NAME_STR: &'static str = Self::NAME.as_str(); + const NAME: &'static str = Self::IDENTIFIER.as_str(); /// The name of the function excluding the type suffix, e.g. `sin` and `sinf` are both `sin`. - const BASE_NAME: BaseName = Self::NAME.base_name(); + const BASE_NAME: BaseName = Self::IDENTIFIER.base_name(); /// The function in `libm` which can be called. const ROUTINE: Self::RustFn; @@ -96,7 +96,7 @@ macro_rules! do_thing { type RustArgs = $RustArgs; type RustRet = $RustRet; - const NAME: Name = Name::[< $fn_name:camel >]; + const IDENTIFIER: Identifier = Identifier::[< $fn_name:camel >]; const ROUTINE: Self::RustFn = libm::$fn_name; } } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 5b5743020d737..afe8c1fb75948 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -111,25 +111,25 @@ impl MaybeOverride<(f32,)> for SpecialCase { ctx: &CheckCtx, ) -> Option { if ctx.basis == CheckBasis::Musl { - if ctx.fn_name_str == "expm1f" && input.0 > 80.0 && actual.is_infinite() { + if ctx.fn_name == "expm1f" && input.0 > 80.0 && actual.is_infinite() { // we return infinity but the number is representable return XFAIL; } - if ctx.fn_name_str == "sinhf" && input.0.abs() > 80.0 && actual.is_nan() { + if ctx.fn_name == "sinhf" && input.0.abs() > 80.0 && actual.is_nan() { // we return some NaN that should be real values or infinite // doesn't seem to happen on x86 return XFAIL; } } - if ctx.fn_name_str == "acoshf" && input.0 < -1.0 { + if ctx.fn_name == "acoshf" && input.0 < -1.0 { // acoshf is undefined for x <= 1.0, but we return a random result at lower // values. return XFAIL; } - if ctx.fn_name_str == "lgammaf" || ctx.fn_name_str == "lgammaf_r" && input.0 < 0.0 { + if ctx.fn_name == "lgammaf" || ctx.fn_name == "lgammaf_r" && input.0 < 0.0 { // loggamma should not be defined for x < 0, yet we both return results return XFAIL; } @@ -146,7 +146,7 @@ impl MaybeOverride<(f32,)> for SpecialCase { // On MPFR for lgammaf_r, we set -1 as the integer result for negative infinity but MPFR // sets +1 if ctx.basis == CheckBasis::Mpfr - && ctx.fn_name_str == "lgammaf_r" + && ctx.fn_name == "lgammaf_r" && input.0 == f32::NEG_INFINITY && actual.abs() == expected.abs() { @@ -166,13 +166,13 @@ impl MaybeOverride<(f64,)> for SpecialCase { ctx: &CheckCtx, ) -> Option { if ctx.basis == CheckBasis::Musl { - if cfg!(target_arch = "x86") && ctx.fn_name_str == "acosh" && input.0 < 1.0 { + if cfg!(target_arch = "x86") && ctx.fn_name == "acosh" && input.0 < 1.0 { // The function is undefined, both implementations return random results return SKIP; } if cfg!(x86_no_sse) - && ctx.fn_name_str == "ceil" + && ctx.fn_name == "ceil" && input.0 < 0.0 && input.0 > -1.0 && expected == F::ZERO @@ -183,13 +183,13 @@ impl MaybeOverride<(f64,)> for SpecialCase { } } - if ctx.fn_name_str == "acosh" && input.0 < 1.0 { + if ctx.fn_name == "acosh" && input.0 < 1.0 { // The function is undefined for the inputs, musl and our libm both return // random results. return XFAIL; } - if ctx.fn_name_str == "lgamma" || ctx.fn_name_str == "lgamma_r" && input.0 < 0.0 { + if ctx.fn_name == "lgamma" || ctx.fn_name == "lgamma_r" && input.0 < 0.0 { // loggamma should not be defined for x < 0, yet we both return results return XFAIL; } @@ -206,7 +206,7 @@ impl MaybeOverride<(f64,)> for SpecialCase { // On MPFR for lgamma_r, we set -1 as the integer result for negative infinity but MPFR // sets +1 if ctx.basis == CheckBasis::Mpfr - && ctx.fn_name_str == "lgamma_r" + && ctx.fn_name == "lgamma_r" && input.0 == f64::NEG_INFINITY && actual.abs() == expected.abs() { @@ -308,7 +308,7 @@ impl MaybeOverride<(i32, f32)> for SpecialCase { CheckBasis::Musl => bessel_prec_dropoff(input, ulp, ctx), CheckBasis::Mpfr => { // We return +0.0, MPFR returns -0.0 - if ctx.fn_name_str == "jnf" + if ctx.fn_name == "jnf" && input.1 == f32::NEG_INFINITY && actual == F::ZERO && expected == F::ZERO @@ -333,7 +333,7 @@ impl MaybeOverride<(i32, f64)> for SpecialCase { CheckBasis::Musl => bessel_prec_dropoff(input, ulp, ctx), CheckBasis::Mpfr => { // We return +0.0, MPFR returns -0.0 - if ctx.fn_name_str == "jn" + if ctx.fn_name == "jn" && input.1 == f64::NEG_INFINITY && actual == F::ZERO && expected == F::ZERO diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index 65faefd33a9c3..1803300588a92 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -11,17 +11,17 @@ use std::fmt; use anyhow::{Context, bail, ensure}; -use crate::{BaseName, Float, Int, MaybeOverride, Name, SpecialCase, TestResult}; +use crate::{BaseName, Float, Identifier, Int, MaybeOverride, SpecialCase, TestResult}; /// Context passed to [`CheckOutput`]. #[derive(Clone, Debug, PartialEq, Eq)] pub struct CheckCtx { /// Allowed ULP deviation pub ulp: u32, - pub fn_name: Name, + pub fn_ident: Identifier, pub base_name: BaseName, /// Function name. - pub fn_name_str: &'static str, + pub fn_name: &'static str, /// Return the unsuffixed version of the function name. pub base_name_str: &'static str, /// Source of truth for tests. @@ -29,13 +29,13 @@ pub struct CheckCtx { } impl CheckCtx { - pub fn new(ulp: u32, fn_name: Name, basis: CheckBasis) -> Self { + pub fn new(ulp: u32, fn_ident: Identifier, basis: CheckBasis) -> Self { Self { ulp, - fn_name, - fn_name_str: fn_name.as_str(), - base_name: fn_name.base_name(), - base_name_str: fn_name.base_name().as_str(), + fn_ident, + fn_name: fn_ident.as_str(), + base_name: fn_ident.base_name(), + base_name_str: fn_ident.base_name().as_str(), basis, } } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index f4c827fc93152..c029a5d975887 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -34,9 +34,9 @@ where Op: MathOp, CachedInput: GenerateInput, { - let name = Op::NAME_STR; + let name = Op::NAME; let ulp = musl_allowed_ulp(name); - let ctx = CheckCtx::new(ulp, Op::NAME, CheckBasis::Musl); + let ctx = CheckCtx::new(ulp, Op::IDENTIFIER, CheckBasis::Musl); let cases = random::get_test_cases::(&ctx); for input in cases { diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 5f38d846226b5..00c6278f67fa6 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -29,11 +29,11 @@ where Op: MathOp + MpOp, CachedInput: GenerateInput, { - let name = Op::NAME_STR; + let name = Op::NAME; let ulp = multiprec_allowed_ulp(name); let mut mp_vals = Op::new_mp(); - let ctx = CheckCtx::new(ulp, Op::NAME, CheckBasis::Mpfr); + let ctx = CheckCtx::new(ulp, Op::IDENTIFIER, CheckBasis::Mpfr); let cases = random::get_test_cases::(&ctx); for input in cases { From 5032fcf1399447d34cd16b9c9bb7fd64133db0d2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 2 Nov 2024 23:03:41 -0500 Subject: [PATCH 1447/4206] Change default ULP to use enum matching Migrate from string to enum matching and tie this to `CheckCtx::new`, so no tests need to explicitly set ULP. --- .../libm/crates/libm-test/benches/random.rs | 3 +- .../libm/crates/libm-test/src/lib.rs | 2 +- .../libm/crates/libm-test/src/precision.rs | 73 +++++++++---------- .../libm/crates/libm-test/src/test_traits.rs | 11 ++- .../libm-test/tests/compare_built_musl.rs | 8 +- .../crates/libm-test/tests/multiprecision.rs | 9 +-- 6 files changed, 47 insertions(+), 59 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 5eea433194549..d77d579080e88 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -49,8 +49,7 @@ where { let name = Op::NAME; - let ulp = libm_test::musl_allowed_ulp(name); - let ctx = CheckCtx::new(ulp, Op::IDENTIFIER, CheckBasis::Musl); + let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl); let benchvec: Vec<_> = random::get_test_cases::(&ctx).take(BENCH_ITER_ITEMS).collect(); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 914e5824486f8..7f0d9aa755318 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -7,7 +7,7 @@ mod test_traits; pub use libm::support::{Float, Int}; pub use op::{BaseName, Identifier, MathOp}; -pub use precision::{MaybeOverride, SpecialCase, multiprec_allowed_ulp, musl_allowed_ulp}; +pub use precision::{MaybeOverride, SpecialCase, default_ulp}; pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, Hex, TupleCall}; /// Result type for tests is usually from `anyhow`. Most times there is no success value to diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index afe8c1fb75948..c761709b8832a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -3,7 +3,10 @@ use core::f32; -use crate::{CheckBasis, CheckCtx, Float, Int, TestResult}; +use CheckBasis::{Mpfr, Musl}; +use Identifier as Id; + +use crate::{CheckBasis, CheckCtx, Float, Identifier, Int, TestResult}; /// Type implementing [`IgnoreCase`]. pub struct SpecialCase; @@ -14,50 +17,42 @@ const MUSL_DEFAULT_ULP: u32 = 2; /// Default ULP allowed to differ from multiprecision (i.e. infinite) results. const MULTIPREC_DEFAULT_ULP: u32 = 1; -/// ULP allowed to differ from muls results. +/// ULP allowed to differ from the results returned by a test basis. /// -/// Note that these results were obtained using 400,000,000 rounds of random inputs, which +/// Note that these results were obtained using 400M rounds of random inputs, which /// is not a value used by default. -pub fn musl_allowed_ulp(name: &str) -> u32 { - // Consider overrides xfail - match name { - #[cfg(x86_no_sse)] - "asinh" | "asinhf" => 6, - "lgamma" | "lgamma_r" | "lgammaf" | "lgammaf_r" => 400, - "tanh" | "tanhf" => 4, - "tgamma" => 20, - "j0" | "j0f" | "j1" | "j1f" => { +pub fn default_ulp(ctx: &CheckCtx) -> u32 { + match (&ctx.basis, ctx.fn_ident) { + // Overrides that apply to either basis + (_, Id::J0 | Id::J0f | Id::J1 | Id::J1f) => { // Results seem very target-dependent if cfg!(target_arch = "x86_64") { 4000 } else { 800_000 } } - "jn" | "jnf" => 1000, - "sincosf" => 500, - #[cfg(not(target_pointer_width = "64"))] - "exp10" => 4, - #[cfg(not(target_pointer_width = "64"))] - "exp10f" => 4, - _ => MUSL_DEFAULT_ULP, - } -} + (_, Id::Jn | Id::Jnf) => 1000, -/// ULP allowed to differ from multiprecision results. -pub fn multiprec_allowed_ulp(name: &str) -> u32 { - // Consider overrides xfail - match name { - "asinh" | "asinhf" => 2, - "acoshf" => 4, - "atanh" | "atanhf" => 2, - "exp10" | "exp10f" => 3, - "j0" | "j0f" | "j1" | "j1f" => { - // Results seem very target-dependent - if cfg!(target_arch = "x86_64") { 4000 } else { 800_000 } - } - "jn" | "jnf" => 1000, - "lgamma" | "lgammaf" | "lgamma_r" | "lgammaf_r" => 16, - "sinh" | "sinhf" => 2, - "tanh" | "tanhf" => 2, - "tgamma" => 20, - _ => MULTIPREC_DEFAULT_ULP, + // Overrides for musl + #[cfg(x86_no_sse)] + (Musl, Id::Asinh | Id::Asinhf) => 6, + #[cfg(not(target_pointer_width = "64"))] + (Musl, Id::Exp10 | Id::Exp10f) => 4, + (Musl, Id::Lgamma | Id::LgammaR | Id::Lgammaf | Id::LgammafR) => 400, + (Musl, Id::Sincosf) => 500, + (Musl, Id::Tanh | Id::Tanhf) => 4, + (Musl, Id::Tgamma) => 20, + + // Overrides for MPFR + (Mpfr, Id::Acoshf) => 4, + (Mpfr, Id::Asinh | Id::Asinhf) => 2, + (Mpfr, Id::Atanh | Id::Atanhf) => 2, + (Mpfr, Id::Exp10 | Id::Exp10f) => 3, + (Mpfr, Id::Lgamma | Id::LgammaR | Id::Lgammaf | Id::LgammafR) => 16, + (Mpfr, Id::Sinh | Id::Sinhf) => 2, + (Mpfr, Id::Tanh | Id::Tanhf) => 2, + (Mpfr, Id::Tgamma) => 20, + + // Defaults + (Musl, _) => MUSL_DEFAULT_ULP, + (Mpfr, _) => MULTIPREC_DEFAULT_ULP, } } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index 1803300588a92..ec14a8cf20a33 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -29,15 +29,18 @@ pub struct CheckCtx { } impl CheckCtx { - pub fn new(ulp: u32, fn_ident: Identifier, basis: CheckBasis) -> Self { - Self { - ulp, + /// Create a new check context, using the default ULP for the function. + pub fn new(fn_ident: Identifier, basis: CheckBasis) -> Self { + let mut ret = Self { + ulp: 0, fn_ident, fn_name: fn_ident.as_str(), base_name: fn_ident.base_name(), base_name_str: fn_ident.base_name().as_str(), basis, - } + }; + ret.ulp = crate::default_ulp(&ret); + ret } } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index c029a5d975887..0022ee03c2104 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -10,9 +10,7 @@ #![cfg(feature = "build-musl")] use libm_test::gen::{CachedInput, random}; -use libm_test::{ - CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, TupleCall, musl_allowed_ulp, -}; +use libm_test::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, TupleCall}; macro_rules! musl_rand_tests { ( @@ -34,9 +32,7 @@ where Op: MathOp, CachedInput: GenerateInput, { - let name = Op::NAME; - let ulp = musl_allowed_ulp(name); - let ctx = CheckCtx::new(ulp, Op::IDENTIFIER, CheckBasis::Musl); + let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl); let cases = random::get_test_cases::(&ctx); for input in cases { diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 00c6278f67fa6..47a85bdb3e5c6 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -4,9 +4,7 @@ use libm_test::gen::{CachedInput, random}; use libm_test::mpfloat::MpOp; -use libm_test::{ - CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, TupleCall, multiprec_allowed_ulp, -}; +use libm_test::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, TupleCall}; /// Implement a test against MPFR with random inputs. macro_rules! multiprec_rand_tests { @@ -29,11 +27,8 @@ where Op: MathOp + MpOp, CachedInput: GenerateInput, { - let name = Op::NAME; - - let ulp = multiprec_allowed_ulp(name); let mut mp_vals = Op::new_mp(); - let ctx = CheckCtx::new(ulp, Op::IDENTIFIER, CheckBasis::Mpfr); + let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); let cases = random::get_test_cases::(&ctx); for input in cases { From 10bdf3b6c1e0178ee934a6cdcb876ac79ef8b72c Mon Sep 17 00:00:00 2001 From: beetrees Date: Sun, 3 Nov 2024 22:54:01 +0000 Subject: [PATCH 1448/4206] Remove incorrect `sparcv9` match pattern from `configure_f16_f128` --- library/compiler-builtins/configure.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs index 68b4d68e61bb1..f8aafbe703a58 100644 --- a/library/compiler-builtins/configure.rs +++ b/library/compiler-builtins/configure.rs @@ -71,7 +71,7 @@ pub fn configure_f16_f128(target: &Target) { // `f128` crashes "powerpc64" if &target.os == "aix" => (true, false), // `f128` crashes - "sparc" | "sparcv9" => (true, false), + "sparc" => (true, false), // `f16` miscompiles "wasm32" | "wasm64" => (false, true), // Most everything else works as of LLVM 19 From c33f521bb523cc3ddcb7b14085a59712bad8d3d5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 3 Nov 2024 23:08:41 +0000 Subject: [PATCH 1449/4206] chore: release v0.1.139 --- library/compiler-builtins/CHANGELOG.md | 6 ++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index f43b63b2b0c42..5c65aa8713e68 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.139](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.138...compiler_builtins-v0.1.139) - 2024-11-03 + +### Other + +- Remove incorrect `sparcv9` match pattern from `configure_f16_f128` + ## [0.1.138](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.137...compiler_builtins-v0.1.138) - 2024-11-01 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 3d8a1f255039d..33f1c9a3ad89c 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.138" +version = "0.1.139" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From fcf8670668238b0ee5379dc0af04709e47e670c5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 3 Nov 2024 20:24:26 -0600 Subject: [PATCH 1450/4206] Change the `multiprec_` prefix to `mp_` Currently there is a combination of names starting with `multiprecision_`, `mp_` and `multiprec_`. Update so `multiprecision_` is always used when a long form makes sense, `mp_` otherwise (eliminating `multiprec_`). --- .../libm/crates/libm-test/src/precision.rs | 4 ++-- .../libm/crates/libm-test/tests/multiprecision.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index c761709b8832a..cf9115430c4f2 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -15,7 +15,7 @@ pub struct SpecialCase; const MUSL_DEFAULT_ULP: u32 = 2; /// Default ULP allowed to differ from multiprecision (i.e. infinite) results. -const MULTIPREC_DEFAULT_ULP: u32 = 1; +const MP_DEFAULT_ULP: u32 = 1; /// ULP allowed to differ from the results returned by a test basis. /// @@ -52,7 +52,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { // Defaults (Musl, _) => MUSL_DEFAULT_ULP, - (Mpfr, _) => MULTIPREC_DEFAULT_ULP, + (Mpfr, _) => MP_DEFAULT_ULP, } } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 47a85bdb3e5c6..0b41fba82e5c4 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -7,7 +7,7 @@ use libm_test::mpfloat::MpOp; use libm_test::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, TupleCall}; /// Implement a test against MPFR with random inputs. -macro_rules! multiprec_rand_tests { +macro_rules! mp_rand_tests { ( fn_name: $fn_name:ident, attrs: [$($meta:meta)*] @@ -15,7 +15,7 @@ macro_rules! multiprec_rand_tests { paste::paste! { #[test] $(#[$meta])* - fn [< multiprec_random_ $fn_name >]() { + fn [< mp_random_ $fn_name >]() { test_one::(); } } @@ -40,7 +40,7 @@ where } libm_macros::for_each_function! { - callback: multiprec_rand_tests, + callback: mp_rand_tests, attributes: [ // Also an assertion failure on i686: at `MPFR_ASSERTN (! mpfr_erangeflag_p ())` #[ignore = "large values are infeasible in MPFR"] From 9a2774a0ae661f0a0a905f3800bfec6e5696de32 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 3 Nov 2024 20:52:28 -0600 Subject: [PATCH 1451/4206] Move some numeric trait logic to default implementations There are a handful of functions we can move out of the macro and to the numeric traits as default implementations; do that here. Additionally, add some bounds that make sense for completeness. --- .../libm/crates/libm-test/src/test_traits.rs | 2 +- .../libm/src/math/support/float_traits.rs | 106 ++++++++++-------- .../libm/src/math/support/int_traits.rs | 7 +- 3 files changed, 67 insertions(+), 48 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index ec14a8cf20a33..b8e0aa108a376 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -314,7 +314,7 @@ where // Make sure that the signs are the same before checing ULP to avoid wraparound let act_sig = actual.signum(); let exp_sig = expected.signum(); - ensure!(act_sig == exp_sig, "mismatched signs {act_sig} {exp_sig}"); + ensure!(act_sig == exp_sig, "mismatched signs {act_sig:?} {exp_sig:?}"); if actual.is_infinite() ^ expected.is_infinite() { bail!("mismatched infinities"); 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 a1d84faf2e254..0047ba3689e3e 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -1,4 +1,4 @@ -use core::{fmt, ops}; +use core::{fmt, mem, ops}; use super::int_traits::{Int, MinInt}; @@ -7,15 +7,17 @@ use super::int_traits::{Int, MinInt}; pub trait Float: Copy + fmt::Debug - + fmt::Display + PartialEq + PartialOrd + ops::AddAssign + ops::MulAssign + ops::Add + ops::Sub + + ops::Mul + ops::Div + ops::Rem + + ops::Neg + + 'static { /// A uint of the same width as the float type Int: Int; @@ -27,11 +29,16 @@ pub trait Float: type ExpInt: Int; const ZERO: Self; + const NEG_ZERO: Self; const ONE: Self; const NEG_ONE: Self; const INFINITY: Self; const NEG_INFINITY: Self; const NAN: Self; + const MAX: Self; + const MIN: Self; + const PI: Self; + const FRAC_PI_2: Self; /// The bitwidth of the float type const BITS: u32; @@ -69,7 +76,19 @@ pub trait Float: /// 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; + fn eq_repr(self, rhs: Self) -> bool { + let is_nan = |x: Self| -> bool { + // } + // fn is_nan(x: Self) -> 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() & Self::EXP_MASK == Self::EXP_MASK + && x.to_bits() & Self::SIG_MASK != Self::Int::ZERO + }; + if is_nan(self) && is_nan(rhs) { true } else { self.to_bits() == rhs.to_bits() } + } /// Returns true if the value is NaN. fn is_nan(self) -> bool; @@ -81,22 +100,35 @@ pub trait Float: fn is_sign_negative(self) -> bool; /// Returns if `self` is subnormal - fn is_subnormal(self) -> bool; + fn is_subnormal(self) -> bool { + (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO + } /// 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; + fn frac(self) -> Self::Int { + self.to_bits() & Self::SIG_MASK + } /// Returns the significand with implicit bit - fn imp_frac(self) -> Self::Int; + fn imp_frac(self) -> Self::Int { + self.frac() | Self::IMPLICIT_BIT + } /// 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 from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self { + let sign = if negative { Self::Int::ONE } else { Self::Int::ZERO }; + Self::from_bits( + (sign << (Self::BITS - 1)) + | ((exponent << Self::SIG_BITS) & Self::EXP_MASK) + | (significand & Self::SIG_MASK), + ) + } fn abs(self) -> Self { let abs_mask = !Self::SIGN_MASK; @@ -107,10 +139,18 @@ pub trait Float: fn normalize(significand: Self::Int) -> (i32, Self::Int); /// Returns a number composed of the magnitude of self and the sign of sign. - fn copysign(self, other: Self) -> Self; + fn copysign(self, other: Self) -> Self { + let mut x = self.to_bits(); + let y = other.to_bits(); + x &= !Self::SIGN_MASK; + x |= y & Self::SIGN_MASK; + Self::from_bits(x) + } /// Returns a number that represents the sign of self. - fn signum(self) -> Self; + fn signum(self) -> Self { + if self.is_nan() { self } else { Self::ONE.copysign(self) } + } } macro_rules! float_impl { @@ -121,11 +161,22 @@ macro_rules! float_impl { type ExpInt = $expty; const ZERO: Self = 0.0; + const NEG_ZERO: Self = -0.0; const ONE: Self = 1.0; const NEG_ONE: Self = -1.0; const INFINITY: Self = Self::INFINITY; const NEG_INFINITY: Self = Self::NEG_INFINITY; const NAN: Self = Self::NAN; + const MAX: Self = -Self::MIN; + // Sign bit set, saturated mantissa, saturated exponent with last bit zeroed + // FIXME(msrv): just use `from_bits` when available + // SAFETY: POD cast with no preconditions + const MIN: Self = unsafe { + mem::transmute::(Self::Int::MAX & !(1 << Self::SIG_BITS)) + }; + + const PI: Self = core::$ty::consts::PI; + const FRAC_PI_2: Self = core::$ty::consts::FRAC_PI_2; const BITS: u32 = $bits; const SIG_BITS: u32 = $significand_bits; @@ -141,16 +192,6 @@ macro_rules! float_impl { fn to_bits_signed(self) -> Self::SignedInt { self.to_bits() as Self::SignedInt } - fn eq_repr(self, rhs: Self) -> bool { - 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 - } - if is_nan(self) && is_nan(rhs) { true } else { self.to_bits() == rhs.to_bits() } - } fn is_nan(self) -> bool { self.is_nan() } @@ -160,43 +201,16 @@ macro_rules! float_impl { fn is_sign_negative(self) -> bool { self.is_sign_negative() } - fn is_subnormal(self) -> bool { - (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO - } 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 copysign(self, other: Self) -> Self { - let mut x = self.to_bits(); - let y = other.to_bits(); - x &= !Self::SIGN_MASK; - x |= y & Self::SIGN_MASK; - Self::from_bits(x) - } - - fn signum(self) -> Self { - if self.is_nan() { self } else { Self::ONE.copysign(self) } - } } }; } 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 b08907aa5b87c..c72c1d5cbbbfe 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -1,4 +1,4 @@ -use core::{fmt, ops}; +use core::{cmp, fmt, ops}; /// Minimal integer implementations needed on all integer types, including wide integers. #[allow(dead_code)] @@ -31,6 +31,8 @@ pub trait MinInt: pub trait Int: MinInt + fmt::Display + + fmt::Binary + + fmt::LowerHex + PartialEq + PartialOrd + ops::AddAssign @@ -47,6 +49,9 @@ pub trait Int: + ops::Shr + ops::BitXor + ops::BitAnd + + cmp::Ord + + CastInto + + CastFrom { fn signed(self) -> ::OtherSign; fn unsigned(self) -> Self::Unsigned; From 04ccb683d940e2171bda34ba2228c62ac581e3a6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 5 Nov 2024 02:43:33 -0600 Subject: [PATCH 1452/4206] Disable `f16` on platforms that have recursion problems CI in [1] seems to indicate that there are cases where the `f16` infinite recursion bug ([2], [3]) can make its way into what gets called during tests, even though this doesn't seem to be the usual case. In order to make sure that we avoid these completely, just unset `f16_enabled` on any platforms that have the recursion problem. This also refactors the `match` statement to be more in line with `library/std/build.rs`. [1]: https://github.com/rust-lang/compiler-builtins/pull/729 [2]: https://github.com/llvm/llvm-project/issues/97981 [3]: https://github.com/rust-lang/compiler-builtins/issues/651 --- library/compiler-builtins/configure.rs | 55 ++++++++++++++++---------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs index f8aafbe703a58..0a0bd503d531f 100644 --- a/library/compiler-builtins/configure.rs +++ b/library/compiler-builtins/configure.rs @@ -51,31 +51,46 @@ impl Target { /// Configure whether or not `f16` and `f128` support should be enabled. pub fn configure_f16_f128(target: &Target) { // Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means - // that the backend will not crash when using these types. This does not mean that the - // backend does the right thing, or that the platform doesn't have ABI bugs. + // that the backend will not crash when using these types and generates code that can be called + // without crashing (no infinite recursion). This does not mean that the platform doesn't have + // ABI or other bugs. // // We do this here rather than in `rust-lang/rust` because configuring via cargo features is // not straightforward. // // Original source of this list: // - let (f16_ok, f128_ok) = match target.arch.as_str() { - // `f16` and `f128` both crash - "arm64ec" => (false, false), - // `f16` crashes - "s390x" => (false, true), - // FIXME(llvm): `f16` test failures fixed by - "loongarch64" => (false, true), - // `f128` crashes - "mips64" | "mips64r6" => (true, false), - // `f128` crashes - "powerpc64" if &target.os == "aix" => (true, false), - // `f128` crashes - "sparc" => (true, false), - // `f16` miscompiles - "wasm32" | "wasm64" => (false, true), + let f16_enabled = match target.arch.as_str() { + // Unsupported + "arm64ec" => false, + // Selection failure + "s390x" => false, + // Infinite recursion + // FIXME(llvm): loongarch fixed by + "csky" => false, + "hexagon" => false, + "loongarch64" => false, + "mips" | "mips64" | "mips32r6" | "mips64r6" => false, + "powerpc" | "powerpc64" => false, + "sparc" | "sparc64" => false, + "wasm32" | "wasm64" => false, // Most everything else works as of LLVM 19 - _ => (true, true), + _ => true, + }; + + let f128_enabled = match target.arch.as_str() { + // Unsupported + "arm64ec" => false, + // Selection failure + "mips64" | "mips64r6" => false, + // Selection failure + "nvptx64" => false, + // Selection failure + "powerpc64" if &target.os == "aix" => false, + // Selection failure + "sparc" => false, + // Most everything else works as of LLVM 19 + _ => true, }; // If the feature is set, disable these types. @@ -84,11 +99,11 @@ pub fn configure_f16_f128(target: &Target) { println!("cargo::rustc-check-cfg=cfg(f16_enabled)"); println!("cargo::rustc-check-cfg=cfg(f128_enabled)"); - if f16_ok && !disable_both { + if f16_enabled && !disable_both { println!("cargo::rustc-cfg=f16_enabled"); } - if f128_ok && !disable_both { + if f128_enabled && !disable_both { println!("cargo::rustc-cfg=f128_enabled"); } } From 7c1072e3fc7bb80c34edbac666a53c59e569c4e4 Mon Sep 17 00:00:00 2001 From: beetrees Date: Thu, 14 Nov 2024 18:13:10 +0000 Subject: [PATCH 1453/4206] Use `https:` links in `README.md` --- library/compiler-builtins/libm/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index e5d64bd2dc031..52d760a4f1599 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -41,14 +41,14 @@ This crate supports rustc 1.63 and newer. ## License Usage is licensed under the MIT license ([LICENSE-MIT](LICENSE-MIT) or -http://opensource.org/licenses/MIT). +https://opensource.org/licenses/MIT). ### Contribution Contributions are licensed under both the MIT license and the Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or -http://www.apache.org/licenses/LICENSE-2.0). Unless you explicitly state +https://www.apache.org/licenses/LICENSE-2.0). Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as mentioned, without any additional terms or conditions. From b208706b6e2d7b2a218347e4311a05fe3a022d52 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sat, 16 Nov 2024 22:23:19 +0200 Subject: [PATCH 1454/4206] Add `DerefMut` for `Lazy[Cell/Lock]` that delegates to the unstable `force_mut()` --- library/core/src/cell/lazy.rs | 10 +++++++++- library/std/src/sync/lazy_lock.rs | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs index 5ac33516684d7..c9c4a6d311192 100644 --- a/library/core/src/cell/lazy.rs +++ b/library/core/src/cell/lazy.rs @@ -1,6 +1,6 @@ use super::UnsafeCell; use crate::hint::unreachable_unchecked; -use crate::ops::Deref; +use crate::ops::{Deref, DerefMut}; use crate::{fmt, mem}; enum State { @@ -284,6 +284,14 @@ impl T> Deref for LazyCell { } } +#[stable(feature = "lazy_deref_mut", since = "CURRENT_RUSTC_VERSION")] +impl T> DerefMut for LazyCell { + #[inline] + fn deref_mut(&mut self) -> &mut T { + LazyCell::force_mut(self) + } +} + #[stable(feature = "lazy_cell", since = "1.80.0")] impl Default for LazyCell { /// Creates a new lazy value using `Default` as the initializing function. diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index 40510f5613450..4379a1519c6bc 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -1,7 +1,7 @@ use super::once::ExclusiveState; use crate::cell::UnsafeCell; use crate::mem::ManuallyDrop; -use crate::ops::Deref; +use crate::ops::{Deref, DerefMut}; use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::sync::Once; use crate::{fmt, ptr}; @@ -312,6 +312,14 @@ impl T> Deref for LazyLock { } } +#[stable(feature = "lazy_deref_mut", since = "CURRENT_RUSTC_VERSION")] +impl T> DerefMut for LazyLock { + #[inline] + fn deref_mut(&mut self) -> &mut T { + LazyLock::force_mut(self) + } +} + #[stable(feature = "lazy_cell", since = "1.80.0")] impl Default for LazyLock { /// Creates a new lazy value using `Default` as the initializing function. From 76f37552e7463598d8374fc15a11891031dd051a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Dec 2024 05:03:21 +0000 Subject: [PATCH 1455/4206] Remove tests against system musl We now have tests against our custom-built musl as well as tests against MPFR. The tests against system musl covers less than those against custom-built musl, and are less portable; there isn't much benefit to keeping them around so just remove them. --- .../compiler-builtins/libm/CONTRIBUTING.md | 20 +- library/compiler-builtins/libm/ci/run.sh | 5 - .../libm/crates/libm-test/Cargo.toml | 1 - .../libm/crates/libm-test/build.rs | 456 ------------------ .../libm/crates/libm-test/tests/musl_biteq.rs | 6 - library/compiler-builtins/libm/src/lib.rs | 25 - 6 files changed, 12 insertions(+), 501 deletions(-) delete mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md index 0a1741631909b..aadcdf03618e2 100644 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -6,9 +6,8 @@ `src/math/mod.rs` accordingly. Also, uncomment the corresponding trait method in `src/lib.rs`. - Write some simple tests in your module (using `#[test]`) -- Run `cargo test` to make sure it works -- Run `cargo test --features libm-test/test-musl-serialized` to compare your - implementation against musl's +- Run `cargo test` to make sure it works. Full tests are only run when enabling + features, see [Testing](#testing) below. - Send us a pull request! Make sure to run `cargo fmt` on your code before sending the PR. Also include "closes #42" in the PR description to close the corresponding issue. @@ -66,12 +65,17 @@ Normal tests can be executed with: cargo test ``` -If you'd like to run tests with randomized inputs that get compared against musl -itself, you'll need to be on a Linux system and then you can execute: +If you'd like to run tests with randomized inputs that get compared against +infinite-precision results, run: ```sh -cargo test --features libm-test/test-musl-serialized +cargo test --features libm-test/test-multiprecision,libm-test/build-musl --release ``` -Note that you may need to pass `--release` to Cargo if there are errors related -to integer overflow. +The multiprecision tests use the [`rug`] crate for bindings to MPFR. MPFR can +be difficult to build on non-Unix systems, refer to [`gmp_mpfr_sys`] for help. + +`build-musl` does not build with MSVC, Wasm, or Thumb. + +[`rug`]: https://docs.rs/rug/latest/rug/ +[`gmp_mpfr_sys`]: https://docs.rs/gmp-mpfr-sys/1.6.4/gmp_mpfr_sys/ diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 32453663e0543..d89c8bdf06024 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -57,11 +57,6 @@ case "$target" in *windows-gnu) extra_flags="$extra_flags --exclude libm-macros" ;; esac -if [ "$(uname -a)" = "Linux" ]; then - # also run the reference tests when we can. requires a Linux host. - extra_flags="$extra_flags --features libm-test/test-musl-serialized" -fi - # Make sure we can build with overriding features. We test the indibidual # features it controls separately. cargo check --no-default-features diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 3587b44e6a47d..4d75b25f81e48 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -9,7 +9,6 @@ default = [] # Generate tests which are random inputs and the outputs are calculated with # musl libc. -test-musl-serialized = ["rand"] test-multiprecision = ["dep:az", "dep:rug"] # Build our own musl for testing and benchmarks diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs index 40b3e56c046b8..dc3126dbb9459 100644 --- a/library/compiler-builtins/libm/crates/libm-test/build.rs +++ b/library/compiler-builtins/libm/crates/libm-test/build.rs @@ -8,9 +8,6 @@ fn main() { emit_optimization_cfg(&cfg); emit_cfg_shorthands(&cfg); list_all_tests(&cfg); - - #[cfg(feature = "test-musl-serialized")] - musl_serialized_tests::generate(); } #[allow(dead_code)] @@ -93,456 +90,3 @@ fn list_all_tests(cfg: &Config) { let outfile = cfg.out_dir.join("all_files.rs"); fs::write(outfile, s).unwrap(); } - -/// At build time, generate the output of what the corresponding `*musl` target does with a range -/// of inputs. -/// -/// Serialize that target's output, run the same thing with our symbols, then load and compare -/// the resulting values. -#[cfg(feature = "test-musl-serialized")] -mod musl_serialized_tests { - use std::path::PathBuf; - use std::process::Command; - use std::{env, fs}; - - use rand::Rng; - use rand::seq::SliceRandom; - - // Number of tests to generate for each function - const NTESTS: usize = 500; - - // These files are all internal functions or otherwise miscellaneous, not - // defining a function we want to test. - const IGNORED_FILES: &[&str] = &[ - "fenv.rs", - // These are giving slightly different results compared to musl - "lgamma.rs", - "lgammaf.rs", - "tgamma.rs", - "j0.rs", - "j0f.rs", - "jn.rs", - "jnf.rs", - "j1.rs", - "j1f.rs", - ]; - - struct Function { - name: String, - args: Vec, - ret: Vec, - tests: Vec, - } - - enum Ty { - F32, - F64, - I32, - Bool, - } - - struct Test { - inputs: Vec, - outputs: Vec, - } - - pub fn generate() { - // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 - let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); - let libm_test = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); - let math_src = libm_test.join("../../src/math"); - - if target_arch == "powerpc64" { - return; - } - - let files = fs::read_dir(math_src) - .unwrap() - .map(|f| f.unwrap().path()) - .filter(file_needs_test) - .collect::>(); - - let mut math = Vec::new(); - for file in files { - if IGNORED_FILES.iter().any(|f| file.ends_with(f)) { - continue; - } - - println!("generating musl reference tests in {:?}", file); - - let contents = fs::read_to_string(file).unwrap(); - let mut functions = contents.lines().filter(|f| f.starts_with("pub fn")); - while let Some(function_to_test) = functions.next() { - math.push(parse(function_to_test)); - } - } - - // Generate a bunch of random inputs for each function. This will - // attempt to generate a good set of uniform test cases for exercising - // all the various functionality. - generate_random_tests(&mut math, &mut rand::thread_rng()); - - // After we have all our inputs, use the x86_64-unknown-linux-musl - // target to generate the expected output. - generate_test_outputs(&mut math); - //panic!("Boo"); - // ... and now that we have both inputs and expected outputs, do a bunch - // of codegen to create the unit tests which we'll actually execute. - generate_unit_tests(&math); - } - - /// Check whether a path within `src/math` should get tests generated. - fn file_needs_test(path: &PathBuf) -> bool { - // Skip directories - if path.is_dir() { - return false; - } - - let fname = path.file_name().unwrap().to_str().unwrap(); - - // Musl doesn't support `f16` or `f128` - !(fname.contains("f16") || fname.contains("f128")) - } - - /// A "poor man's" parser for the signature of a function - fn parse(s: &str) -> Function { - let s = eat(s, "pub fn "); - let pos = s.find('(').unwrap(); - let name = &s[..pos]; - let s = &s[pos + 1..]; - let end = s.find(')').unwrap(); - let args = s[..end] - .split(',') - .map(|arg| { - let colon = arg.find(':').unwrap(); - parse_ty(arg[colon + 1..].trim()) - }) - .collect::>(); - let tail = &s[end + 1..]; - let tail = eat(tail, " -> "); - let ret = parse_retty(tail.replace("{", "").trim()); - - return Function { name: name.to_string(), args, ret, tests: Vec::new() }; - - fn parse_ty(s: &str) -> Ty { - match s { - "f32" => Ty::F32, - "f64" => Ty::F64, - "i32" => Ty::I32, - "bool" => Ty::Bool, - other => panic!("unknown type `{}`", other), - } - } - - fn parse_retty(s: &str) -> Vec { - match s { - "(f32, f32)" => vec![Ty::F32, Ty::F32], - "(f32, i32)" => vec![Ty::F32, Ty::I32], - "(f64, f64)" => vec![Ty::F64, Ty::F64], - "(f64, i32)" => vec![Ty::F64, Ty::I32], - other => vec![parse_ty(other)], - } - } - - fn eat<'a>(s: &'a str, prefix: &str) -> &'a str { - if s.starts_with(prefix) { - &s[prefix.len()..] - } else { - panic!("{:?} didn't start with {:?}", s, prefix) - } - } - } - - fn generate_random_tests(functions: &mut [Function], rng: &mut R) { - for function in functions { - for _ in 0..NTESTS { - function.tests.push(generate_test(function, rng)); - } - } - - fn generate_test(function: &Function, rng: &mut R) -> Test { - let mut inputs = function.args.iter().map(|ty| ty.gen_i64(rng)).collect::>(); - - // First argument to this function appears to be a number of - // iterations, so passing in massive random numbers causes it to - // take forever to execute, so make sure we're not running random - // math code until the heat death of the universe. - if function.name == "jn" || function.name == "jnf" { - inputs[0] &= 0xffff; - } - - Test { - inputs, - // zero output for now since we'll generate it later - outputs: vec![], - } - } - } - - impl Ty { - fn gen_i64(&self, r: &mut R) -> i64 { - use std::{f32, f64}; - - return match self { - Ty::F32 => { - if r.gen_range(0..20) < 1 { - let i = *[f32::NAN, f32::INFINITY, f32::NEG_INFINITY].choose(r).unwrap(); - i.to_bits().into() - } else { - r.gen::().to_bits().into() - } - } - Ty::F64 => { - if r.gen_range(0..20) < 1 { - let i = *[f64::NAN, f64::INFINITY, f64::NEG_INFINITY].choose(r).unwrap(); - i.to_bits() as i64 - } else { - r.gen::().to_bits() as i64 - } - } - Ty::I32 => { - if r.gen_range(0..10) < 1 { - let i = *[i32::max_value(), 0, i32::min_value()].choose(r).unwrap(); - i.into() - } else { - r.gen::().into() - } - } - Ty::Bool => r.gen::() as i64, - }; - } - - fn libc_ty(&self) -> &'static str { - match self { - Ty::F32 => "f32", - Ty::F64 => "f64", - Ty::I32 => "i32", - Ty::Bool => "i32", - } - } - - fn libc_pty(&self) -> &'static str { - match self { - Ty::F32 => "*mut f32", - Ty::F64 => "*mut f64", - Ty::I32 => "*mut i32", - Ty::Bool => "*mut i32", - } - } - - fn default(&self) -> &'static str { - match self { - Ty::F32 => "0_f32", - Ty::F64 => "0_f64", - Ty::I32 => "0_i32", - Ty::Bool => "false", - } - } - - fn to_i64(&self) -> &'static str { - match self { - Ty::F32 => ".to_bits() as i64", - Ty::F64 => ".to_bits() as i64", - Ty::I32 => " as i64", - Ty::Bool => " as i64", - } - } - } - - fn generate_test_outputs(functions: &mut [Function]) { - let mut src = String::new(); - let dst = std::env::var("OUT_DIR").unwrap(); - - // Generate a program which will run all tests with all inputs in - // `functions`. This program will write all outputs to stdout (in a - // binary format). - src.push_str("use std::io::Write;"); - src.push_str("fn main() {"); - src.push_str("let mut result = Vec::new();"); - for function in functions.iter_mut() { - src.push_str("unsafe {"); - src.push_str("extern { fn "); - src.push_str(&function.name); - src.push_str("("); - - let (ret, retptr) = match function.name.as_str() { - "sincos" | "sincosf" => (None, &function.ret[..]), - _ => (Some(&function.ret[0]), &function.ret[1..]), - }; - for (i, arg) in function.args.iter().enumerate() { - src.push_str(&format!("arg{}: {},", i, arg.libc_ty())); - } - for (i, ret) in retptr.iter().enumerate() { - src.push_str(&format!("argret{}: {},", i, ret.libc_pty())); - } - src.push_str(")"); - if let Some(ty) = ret { - src.push_str(" -> "); - src.push_str(ty.libc_ty()); - } - src.push_str("; }"); - - src.push_str(&format!("static TESTS: &[[i64; {}]]", function.args.len())); - src.push_str(" = &["); - for test in function.tests.iter() { - src.push_str("["); - for val in test.inputs.iter() { - src.push_str(&val.to_string()); - src.push_str(","); - } - src.push_str("],"); - } - src.push_str("];"); - - src.push_str("for test in TESTS {"); - for (i, arg) in retptr.iter().enumerate() { - src.push_str(&format!("let mut argret{} = {};", i, arg.default())); - } - src.push_str("let output = "); - src.push_str(&function.name); - src.push_str("("); - for (i, arg) in function.args.iter().enumerate() { - src.push_str(&match arg { - Ty::F32 => format!("f32::from_bits(test[{}] as u32)", i), - Ty::F64 => format!("f64::from_bits(test[{}] as u64)", i), - Ty::I32 => format!("test[{}] as i32", i), - Ty::Bool => format!("test[{}] as i32", i), - }); - src.push_str(","); - } - for (i, _) in retptr.iter().enumerate() { - src.push_str(&format!("&mut argret{},", i)); - } - src.push_str(");"); - if let Some(ty) = &ret { - src.push_str(&format!("let output = output{};", ty.to_i64())); - src.push_str("result.extend_from_slice(&output.to_le_bytes());"); - } - - for (i, ret) in retptr.iter().enumerate() { - src.push_str(&format!( - "result.extend_from_slice(&(argret{}{}).to_le_bytes());", - i, - ret.to_i64(), - )); - } - src.push_str("}"); - - src.push_str("}"); - } - - src.push_str("std::io::stdout().write_all(&result).unwrap();"); - - src.push_str("}"); - - let path = format!("{}/gen.rs", dst); - fs::write(&path, src).unwrap(); - - // Make it somewhat pretty if something goes wrong - drop(Command::new("rustfmt").arg(&path).status()); - - // Compile and execute this tests for the musl target, assuming we're an - // x86_64 host effectively. - let status = Command::new("rustc") - .current_dir(&dst) - .arg(&path) - .arg("--target=x86_64-unknown-linux-musl") - .status() - .unwrap(); - assert!(status.success()); - let output = Command::new("./gen").current_dir(&dst).output().unwrap(); - assert!(output.status.success()); - assert!(output.stderr.is_empty()); - - // Map all the output bytes back to an `i64` and then shove it all into - // the expected results. - let mut results = output.stdout.chunks_exact(8).map(|buf| { - let mut exact = [0; 8]; - exact.copy_from_slice(buf); - i64::from_le_bytes(exact) - }); - - for f in functions.iter_mut() { - for test in f.tests.iter_mut() { - test.outputs = (0..f.ret.len()).map(|_| results.next().unwrap()).collect(); - } - } - assert!(results.next().is_none()); - } - - /// Codegens a file which has a ton of `#[test]` annotations for all the - /// tests that we generated above. - fn generate_unit_tests(functions: &[Function]) { - let mut src = String::new(); - let dst = std::env::var("OUT_DIR").unwrap(); - - for function in functions { - src.push_str("#[test]"); - src.push_str("fn "); - src.push_str(&function.name); - src.push_str("_matches_musl() {"); - src.push_str(&format!( - "static TESTS: &[([i64; {}], [i64; {}])]", - function.args.len(), - function.ret.len(), - )); - src.push_str(" = &["); - for test in function.tests.iter() { - src.push_str("(["); - for val in test.inputs.iter() { - src.push_str(&val.to_string()); - src.push_str(","); - } - src.push_str("],"); - src.push_str("["); - for val in test.outputs.iter() { - src.push_str(&val.to_string()); - src.push_str(","); - } - src.push_str("],"); - src.push_str("),"); - } - src.push_str("];"); - - src.push_str("for (test, expected) in TESTS {"); - src.push_str("let output = libm::"); - src.push_str(&function.name); - src.push_str("("); - for (i, arg) in function.args.iter().enumerate() { - src.push_str(&match arg { - Ty::F32 => format!("f32::from_bits(test[{}] as u32)", i), - Ty::F64 => format!("f64::from_bits(test[{}] as u64)", i), - Ty::I32 => format!("test[{}] as i32", i), - Ty::Bool => format!("test[{}] as i32", i), - }); - src.push_str(","); - } - src.push_str(");"); - - for (i, ret) in function.ret.iter().enumerate() { - let get = if function.ret.len() == 1 { String::new() } else { format!(".{}", i) }; - src.push_str(&(match ret { - Ty::F32 => format!("if libm::_eqf(output{}, f32::from_bits(expected[{}] as u32)).is_ok() {{ continue }}", get, i), - Ty::F64 => format!("if libm::_eq(output{}, f64::from_bits(expected[{}] as u64)).is_ok() {{ continue }}", get, i), - Ty::I32 => format!("if output{} as i64 == expected[{}] {{ continue }}", get, i), - Ty::Bool => unreachable!(), - })); - } - - src.push_str( - r#" - panic!("INPUT: {:?} EXPECTED: {:?} ACTUAL {:?}", test, expected, output); - "#, - ); - src.push_str("}"); - - src.push_str("}"); - } - - let path = format!("{}/musl-tests.rs", dst); - fs::write(&path, src).unwrap(); - - // Try to make it somewhat pretty - drop(Command::new("rustfmt").arg(&path).status()); - } -} diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs b/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs deleted file mode 100644 index f586fd03d12c8..0000000000000 --- a/library/compiler-builtins/libm/crates/libm-test/tests/musl_biteq.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! compare - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(all(test, feature = "test-musl-serialized"))] -include!(concat!(env!("OUT_DIR"), "/musl-tests.rs")); diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 511ab598dbad9..6bb06b5b81f56 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -23,28 +23,3 @@ use core::{f32, f64}; pub use libm_helper::*; pub use self::math::*; - -/// Approximate equality with 1 ULP of tolerance -#[doc(hidden)] -#[inline] -pub fn _eqf(a: f32, b: f32) -> Result<(), u32> { - if a.is_nan() && b.is_nan() { - Ok(()) - } else { - let err = (a.to_bits() as i32).wrapping_sub(b.to_bits() as i32).abs(); - - if err <= 1 { Ok(()) } else { Err(err as u32) } - } -} - -#[doc(hidden)] -#[inline] -pub fn _eq(a: f64, b: f64) -> Result<(), u64> { - if a.is_nan() && b.is_nan() { - Ok(()) - } else { - let err = (a.to_bits() as i64).wrapping_sub(b.to_bits() as i64).abs(); - - if err <= 1 { Ok(()) } else { Err(err as u64) } - } -} From a4d9b4a6a25dbe8bcdea6344256139a735d61135 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Dec 2024 21:49:37 +0000 Subject: [PATCH 1456/4206] Fix a bug in `abs_diff` These implementations of `abs_diff` were added in c2ff1b3119 ("Completely overhaul fuzz testing"), but the signed implementation is wrong when |x| + |y| exceeds the integer's limits (e.g. `(-128).abs_diff(1)` should be 128 but currently these return 127. Resolve this by just using `std`'s implementation since that is stable now. This isn't used anywhere critical, we probably just weren't hitting the edge case. --- library/compiler-builtins/src/int/mod.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 0d3b0ce4048d2..c0d5a6715e3ae 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -240,11 +240,7 @@ macro_rules! int_impl { } fn abs_diff(self, other: Self) -> Self { - if self < other { - other.wrapping_sub(self) - } else { - self.wrapping_sub(other) - } + self.abs_diff(other) } int_impl_common!($uty); @@ -277,7 +273,7 @@ macro_rules! int_impl { } fn abs_diff(self, other: Self) -> $uty { - self.wrapping_sub(other).wrapping_abs() as $uty + self.abs_diff(other) } int_impl_common!($ity); From 2cbacf89afcc5a2db36c9f682f46e21b132944b0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Dec 2024 22:24:38 +0000 Subject: [PATCH 1457/4206] Fix a bug in `abs_diff` These were taken from `compiler-builtins` but the implementation has a bug near the integer limits. Fixed in `compiler-builtins` by using `core`'s implementation at [1], this is the corresponding fix for `libm`. [1]: https://github.com/rust-lang/compiler-builtins/pull/736 --- library/compiler-builtins/libm/src/math/support/int_traits.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 c72c1d5cbbbfe..ded990bdfdebb 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -184,7 +184,7 @@ macro_rules! int_impl { } fn abs_diff(self, other: Self) -> Self { - if self < other { other.wrapping_sub(self) } else { self.wrapping_sub(other) } + self.abs_diff(other) } int_impl_common!($uty); @@ -221,7 +221,7 @@ macro_rules! int_impl { } fn abs_diff(self, other: Self) -> $uty { - self.wrapping_sub(other).wrapping_abs() as $uty + self.abs_diff(other) } int_impl_common!($ity); From 4cdb9ec6749e45982cbb4ff1d6d788a8136e551f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Dec 2024 23:15:16 +0000 Subject: [PATCH 1458/4206] Introduce helper types for accessing trait items The ambiguous associated types error sometimes fires in cases where it shouldn't be ambiguous ([1]), which can make things clunky when working with chained associated types (e.g. `Op::FTy::Int::*` does not work). Add helper types that we can use instead of the full syntax. There aren't too many cases in-crate now but this is relevant for some open PRs. [1]: https://github.com/rust-lang/rust/issues/38078 --- .../libm/crates/libm-test/benches/random.rs | 2 +- .../compiler-builtins/libm/crates/libm-test/src/lib.rs | 4 ++-- .../compiler-builtins/libm/crates/libm-test/src/op.rs | 9 +++++++++ .../libm/src/math/support/float_traits.rs | 4 ++++ .../libm/src/math/support/int_traits.rs | 6 +++++- library/compiler-builtins/libm/src/math/support/mod.rs | 3 ++- 6 files changed, 23 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index d77d579080e88..9ccc38fe3a023 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -26,7 +26,7 @@ macro_rules! musl_rand_benches { #[cfg(feature = "build-musl")] let musl_extra = MuslExtra { - musl_fn: Some(musl_math_sys::$fn_name as ::CFn), + musl_fn: Some(musl_math_sys::$fn_name as libm_test::CFn), skip_on_i586: $skip_on_i586 }; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 7f0d9aa755318..bc96b466b56d0 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -5,8 +5,8 @@ pub mod op; mod precision; mod test_traits; -pub use libm::support::{Float, Int}; -pub use op::{BaseName, Identifier, MathOp}; +pub use libm::support::{Float, Int, IntTy}; +pub use op::{BaseName, CFn, FTy, Identifier, MathOp, RustFn, RustRet}; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, Hex, TupleCall}; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/op.rs b/library/compiler-builtins/libm/crates/libm-test/src/op.rs index 50b455d3a9366..0faeceb09970d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/op.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/op.rs @@ -70,6 +70,15 @@ pub trait MathOp { const ROUTINE: Self::RustFn; } +/// Access the associated `FTy` type from an op (helper to avoid ambiguous associated types). +pub type FTy = ::FTy; +/// Access the associated `CFn` type from an op (helper to avoid ambiguous associated types). +pub type CFn = ::CFn; +/// Access the associated `RustFn` type from an op (helper to avoid ambiguous associated types). +pub type RustFn = ::RustFn; +/// Access the associated `RustRet` type from an op (helper to avoid ambiguous associated types). +pub type RustRet = ::RustRet; + macro_rules! do_thing { // Matcher for unary functions ( 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 0047ba3689e3e..5808aeebc1393 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -153,6 +153,10 @@ pub trait Float: } } +/// Access the associated `Int` type from a float (helper to avoid ambiguous associated types). +#[allow(dead_code)] +pub type IntTy = ::Int; + macro_rules! float_impl { ($ty:ident, $ity:ident, $sity:ident, $expty:ident, $bits:expr, $significand_bits:expr) => { impl Float for $ty { 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 ded990bdfdebb..380313c1e6ba4 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -26,6 +26,10 @@ pub trait MinInt: const MAX: Self; } +/// Access the associated `OtherSign` type from an int (helper to avoid ambiguous associated +/// types). +pub type OtherSign = ::OtherSign; + /// Trait for some basic operations on integers #[allow(dead_code)] pub trait Int: @@ -53,7 +57,7 @@ pub trait Int: + CastInto + CastFrom { - fn signed(self) -> ::OtherSign; + fn signed(self) -> OtherSign; fn unsigned(self) -> Self::Unsigned; fn from_unsigned(unsigned: Self::Unsigned) -> Self; fn abs(self) -> Self; diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index 04a313abc97c9..25681c307da49 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -4,7 +4,8 @@ mod float_traits; mod hex_float; mod int_traits; -pub use float_traits::Float; +#[allow(unused_imports)] +pub use float_traits::{Float, IntTy}; #[allow(unused_imports)] pub use hex_float::{hf32, hf64}; pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; From ba1d271158fb73b71955680dea6280bfa753cf2b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Dec 2024 23:56:45 +0000 Subject: [PATCH 1459/4206] Rename associated type helpers, add `OpITy` Change the names to make them less ambiguous. Additionally add `OpITy` for accessing the same-sized integer of an operation's float type. --- .../libm/crates/libm-test/benches/random.rs | 2 +- .../compiler-builtins/libm/crates/libm-test/src/lib.rs | 2 +- .../compiler-builtins/libm/crates/libm-test/src/op.rs | 10 ++++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 9ccc38fe3a023..b9c39334c1475 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -26,7 +26,7 @@ macro_rules! musl_rand_benches { #[cfg(feature = "build-musl")] let musl_extra = MuslExtra { - musl_fn: Some(musl_math_sys::$fn_name as libm_test::CFn), + musl_fn: Some(musl_math_sys::$fn_name as libm_test::OpCFn), skip_on_i586: $skip_on_i586 }; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index bc96b466b56d0..17a06b3be3a2d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -6,7 +6,7 @@ mod precision; mod test_traits; pub use libm::support::{Float, Int, IntTy}; -pub use op::{BaseName, CFn, FTy, Identifier, MathOp, RustFn, RustRet}; +pub use op::{BaseName, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet}; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, Hex, TupleCall}; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/op.rs b/library/compiler-builtins/libm/crates/libm-test/src/op.rs index 0faeceb09970d..bcea31c22b6e6 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/op.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/op.rs @@ -71,13 +71,15 @@ pub trait MathOp { } /// Access the associated `FTy` type from an op (helper to avoid ambiguous associated types). -pub type FTy = ::FTy; +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). -pub type CFn = ::CFn; +pub type OpCFn = ::CFn; /// Access the associated `RustFn` type from an op (helper to avoid ambiguous associated types). -pub type RustFn = ::RustFn; +pub type OpRustFn = ::RustFn; /// Access the associated `RustRet` type from an op (helper to avoid ambiguous associated types). -pub type RustRet = ::RustRet; +pub type OpRustRet = ::RustRet; macro_rules! do_thing { // Matcher for unary functions From e8eb76a45af2290ca8b00a82eef11a03ee559cc5 Mon Sep 17 00:00:00 2001 From: Sebastian Neubauer Date: Thu, 26 Dec 2024 06:01:14 +0100 Subject: [PATCH 1460/4206] Disable f128 for amdgpu (#737) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `compiler_builtins` fails to compile to amdgpu if f128 is enabled. The reason seems to be that compiler_builtins uses libcalls in the implementation. I’m not really familiar with what libcalls are, but the LLVM amdgpu backend explicitly does not support them. Error message: ``` LLVM ERROR: unsupported libcall legalization ``` --- library/compiler-builtins/configure.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs index 0a0bd503d531f..e20c717ec75a9 100644 --- a/library/compiler-builtins/configure.rs +++ b/library/compiler-builtins/configure.rs @@ -79,6 +79,8 @@ pub fn configure_f16_f128(target: &Target) { }; let f128_enabled = match target.arch.as_str() { + // Unsupported (libcall is not supported) + "amdgpu" => false, // Unsupported "arm64ec" => false, // Selection failure From a078f5a0c54ec041cdfe351f2413214ea1b56966 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 26 Dec 2024 05:01:38 +0000 Subject: [PATCH 1461/4206] chore: release v0.1.140 --- library/compiler-builtins/CHANGELOG.md | 8 ++++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index 5c65aa8713e68..f888591437bfd 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.140](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.139...compiler_builtins-v0.1.140) - 2024-12-26 + +### Other + +- Disable f128 for amdgpu ([#737](https://github.com/rust-lang/compiler-builtins/pull/737)) +- Fix a bug in `abs_diff` +- Disable `f16` on platforms that have recursion problems + ## [0.1.139](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.138...compiler_builtins-v0.1.139) - 2024-11-03 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 33f1c9a3ad89c..33d5c06b78c76 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.139" +version = "0.1.140" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 723e68d137ad20b20912be802669a6ce8367a17e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 26 Dec 2024 09:13:58 +0000 Subject: [PATCH 1462/4206] Replace string function name matching with enums where possible --- .../libm/crates/libm-test/src/gen/random.rs | 5 +- .../libm/crates/libm-test/src/precision.rs | 100 ++++++++---------- .../libm/crates/libm-test/src/test_traits.rs | 3 - 3 files changed, 46 insertions(+), 62 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index e347b3c63aeb9..527cd1351422b 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -7,7 +7,7 @@ use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; use super::CachedInput; -use crate::{CheckCtx, GenerateInput}; +use crate::{BaseName, CheckCtx, GenerateInput}; const SEED: [u8; 32] = *b"3.141592653589793238462643383279"; @@ -110,7 +110,6 @@ pub fn get_test_cases(ctx: &CheckCtx) -> impl Iterator, { - let inputs = - if ctx.fn_name == "jn" || ctx.fn_name == "jnf" { &TEST_CASES_JN } else { &TEST_CASES }; + let inputs = if ctx.base_name == BaseName::Jn { &TEST_CASES_JN } else { &TEST_CASES }; inputs.get_cases() } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index cf9115430c4f2..c7f9d9e30118a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -6,7 +6,7 @@ use core::f32; use CheckBasis::{Mpfr, Musl}; use Identifier as Id; -use crate::{CheckBasis, CheckCtx, Float, Identifier, Int, TestResult}; +use crate::{BaseName, CheckBasis, CheckCtx, Float, Identifier, Int, TestResult}; /// Type implementing [`IgnoreCase`]. pub struct SpecialCase; @@ -106,25 +106,26 @@ impl MaybeOverride<(f32,)> for SpecialCase { ctx: &CheckCtx, ) -> Option { if ctx.basis == CheckBasis::Musl { - if ctx.fn_name == "expm1f" && input.0 > 80.0 && actual.is_infinite() { + if ctx.base_name == BaseName::Expm1 && input.0 > 80.0 && actual.is_infinite() { // we return infinity but the number is representable return XFAIL; } - if ctx.fn_name == "sinhf" && input.0.abs() > 80.0 && actual.is_nan() { + if ctx.base_name == BaseName::Sinh && input.0.abs() > 80.0 && actual.is_nan() { // we return some NaN that should be real values or infinite // doesn't seem to happen on x86 return XFAIL; } } - if ctx.fn_name == "acoshf" && input.0 < -1.0 { + if ctx.base_name == BaseName::Acosh && input.0 < -1.0 { // acoshf is undefined for x <= 1.0, but we return a random result at lower // values. return XFAIL; } - if ctx.fn_name == "lgammaf" || ctx.fn_name == "lgammaf_r" && input.0 < 0.0 { + if ctx.base_name == BaseName::Lgamma || ctx.base_name == BaseName::LgammaR && input.0 < 0.0 + { // loggamma should not be defined for x < 0, yet we both return results return XFAIL; } @@ -141,7 +142,7 @@ impl MaybeOverride<(f32,)> for SpecialCase { // On MPFR for lgammaf_r, we set -1 as the integer result for negative infinity but MPFR // sets +1 if ctx.basis == CheckBasis::Mpfr - && ctx.fn_name == "lgammaf_r" + && ctx.base_name == BaseName::LgammaR && input.0 == f32::NEG_INFINITY && actual.abs() == expected.abs() { @@ -161,13 +162,13 @@ impl MaybeOverride<(f64,)> for SpecialCase { ctx: &CheckCtx, ) -> Option { if ctx.basis == CheckBasis::Musl { - if cfg!(target_arch = "x86") && ctx.fn_name == "acosh" && input.0 < 1.0 { + if cfg!(target_arch = "x86") && ctx.base_name == BaseName::Acosh && input.0 < 1.0 { // The function is undefined, both implementations return random results return SKIP; } if cfg!(x86_no_sse) - && ctx.fn_name == "ceil" + && ctx.base_name == BaseName::Ceil && input.0 < 0.0 && input.0 > -1.0 && expected == F::ZERO @@ -178,13 +179,14 @@ impl MaybeOverride<(f64,)> for SpecialCase { } } - if ctx.fn_name == "acosh" && input.0 < 1.0 { + if ctx.base_name == BaseName::Acosh && input.0 < 1.0 { // The function is undefined for the inputs, musl and our libm both return // random results. return XFAIL; } - if ctx.fn_name == "lgamma" || ctx.fn_name == "lgamma_r" && input.0 < 0.0 { + if ctx.base_name == BaseName::Lgamma || ctx.base_name == BaseName::LgammaR && input.0 < 0.0 + { // loggamma should not be defined for x < 0, yet we both return results return XFAIL; } @@ -201,7 +203,7 @@ impl MaybeOverride<(f64,)> for SpecialCase { // On MPFR for lgamma_r, we set -1 as the integer result for negative infinity but MPFR // sets +1 if ctx.basis == CheckBasis::Mpfr - && ctx.fn_name == "lgamma_r" + && ctx.base_name == BaseName::LgammaR && input.0 == f64::NEG_INFINITY && actual.abs() == expected.abs() { @@ -214,7 +216,7 @@ impl MaybeOverride<(f64,)> for SpecialCase { /// Check NaN bits if the function requires it fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Option { - if !(ctx.base_name_str == "fabs" || ctx.base_name_str == "copysign") { + if !(ctx.base_name == BaseName::Fabs || ctx.base_name == BaseName::Copysign) { return None; } @@ -270,24 +272,16 @@ fn maybe_skip_binop_nan( expected: F2, ctx: &CheckCtx, ) -> Option { - match ctx.basis { - CheckBasis::Musl => { - if (ctx.base_name_str == "fmax" || ctx.base_name_str == "fmin") - && (input.0.is_nan() || input.1.is_nan()) - && expected.is_nan() - { - XFAIL - } else { - None - } - } - CheckBasis::Mpfr => { - if ctx.base_name_str == "copysign" && input.1.is_nan() { - SKIP - } else { - None - } + match (&ctx.basis, ctx.base_name) { + (Musl, BaseName::Fmin | BaseName::Fmax) + if (input.0.is_nan() || input.1.is_nan()) && expected.is_nan() => + { + XFAIL } + + (Mpfr, BaseName::Copysign) if input.1.is_nan() => SKIP, + + _ => None, } } @@ -299,20 +293,17 @@ impl MaybeOverride<(i32, f32)> for SpecialCase { ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - match ctx.basis { - CheckBasis::Musl => bessel_prec_dropoff(input, ulp, ctx), - CheckBasis::Mpfr => { - // We return +0.0, MPFR returns -0.0 - if ctx.fn_name == "jnf" - && input.1 == f32::NEG_INFINITY - && actual == F::ZERO - && expected == F::ZERO - { - XFAIL - } else { - None - } + match (&ctx.basis, ctx.base_name) { + (Musl, _) => bessel_prec_dropoff(input, ulp, ctx), + + // We return +0.0, MPFR returns -0.0 + (Mpfr, BaseName::Jn) + if input.1 == f32::NEG_INFINITY && actual == F::ZERO && expected == F::ZERO => + { + XFAIL } + + _ => None, } } } @@ -324,20 +315,17 @@ impl MaybeOverride<(i32, f64)> for SpecialCase { ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - match ctx.basis { - CheckBasis::Musl => bessel_prec_dropoff(input, ulp, ctx), - CheckBasis::Mpfr => { - // We return +0.0, MPFR returns -0.0 - if ctx.fn_name == "jn" - && input.1 == f64::NEG_INFINITY - && actual == F::ZERO - && expected == F::ZERO - { - XFAIL - } else { - bessel_prec_dropoff(input, ulp, ctx) - } + match (&ctx.basis, ctx.base_name) { + (Musl, _) => bessel_prec_dropoff(input, ulp, ctx), + + // We return +0.0, MPFR returns -0.0 + (Mpfr, BaseName::Jn) + if input.1 == f64::NEG_INFINITY && actual == F::ZERO && expected == F::ZERO => + { + XFAIL } + + _ => None, } } } @@ -348,7 +336,7 @@ fn bessel_prec_dropoff( ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - if ctx.base_name_str == "jn" { + if ctx.base_name == BaseName::Jn { if input.0 > 4000 { return XFAIL; } else if input.0 > 2000 { diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index b8e0aa108a376..ca933bbda63ec 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -22,8 +22,6 @@ pub struct CheckCtx { pub base_name: BaseName, /// Function name. pub fn_name: &'static str, - /// Return the unsuffixed version of the function name. - pub base_name_str: &'static str, /// Source of truth for tests. pub basis: CheckBasis, } @@ -36,7 +34,6 @@ impl CheckCtx { fn_ident, fn_name: fn_ident.as_str(), base_name: fn_ident.base_name(), - base_name_str: fn_ident.base_name().as_str(), basis, }; ret.ulp = crate::default_ulp(&ret); From 80dca45a80ebb17cc9974591289050b9dd867363 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 27 Dec 2024 10:58:36 +0000 Subject: [PATCH 1463/4206] Fix new `clippy::precedence` lints [1] extends Clippy's `precedence` lint to cover `&`, `|`, and bitshifts. Update cases that are flagged by this in the most recent nightly. [1]: https://github.com/rust-lang/rust-clippy/pull/13743 --- library/compiler-builtins/libm/src/math/ceil.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/fma.rs | 12 ++++++------ library/compiler-builtins/libm/src/math/fmod.rs | 4 ++-- library/compiler-builtins/libm/src/math/fmodf.rs | 4 ++-- library/compiler-builtins/libm/src/math/j1.rs | 4 ++-- library/compiler-builtins/libm/src/math/jn.rs | 4 ++-- library/compiler-builtins/libm/src/math/log10.rs | 2 +- library/compiler-builtins/libm/src/math/log1p.rs | 2 +- library/compiler-builtins/libm/src/math/log2.rs | 2 +- library/compiler-builtins/libm/src/math/mod.rs | 2 +- library/compiler-builtins/libm/src/math/modf.rs | 2 +- library/compiler-builtins/libm/src/math/modff.rs | 2 +- library/compiler-builtins/libm/src/math/nextafter.rs | 6 +++--- library/compiler-builtins/libm/src/math/rint.rs | 2 +- library/compiler-builtins/libm/src/math/rintf.rs | 2 +- library/compiler-builtins/libm/src/math/sqrt.rs | 2 +- library/compiler-builtins/libm/src/math/trunc.rs | 2 +- library/compiler-builtins/libm/src/math/truncf.rs | 2 +- 21 files changed, 32 insertions(+), 32 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index c198ebcfe1bf3..b0576f3dc1f8e 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -16,7 +16,7 @@ pub fn ceil(x: f64) -> f64 { } let u: u64 = x.to_bits(); - let e: i64 = (u >> 52 & 0x7ff) as i64; + let e: i64 = ((u >> 52) & 0x7ff) as i64; let y: f64; if e >= 0x3ff + 52 || x == 0. { diff --git a/library/compiler-builtins/libm/src/math/exp10.rs b/library/compiler-builtins/libm/src/math/exp10.rs index 2c3df0173441a..7c33c92b6032c 100644 --- a/library/compiler-builtins/libm/src/math/exp10.rs +++ b/library/compiler-builtins/libm/src/math/exp10.rs @@ -12,7 +12,7 @@ pub fn exp10(x: f64) -> f64 { let (mut y, n) = modf(x); let u: u64 = n.to_bits(); /* fabs(n) < 16 without raising invalid on nan */ - if (u >> 52 & 0x7ff) < 0x3ff + 4 { + if ((u >> 52) & 0x7ff) < 0x3ff + 4 { if y == 0.0 { return i!(P10, ((n as isize) + 15) as usize); } diff --git a/library/compiler-builtins/libm/src/math/exp10f.rs b/library/compiler-builtins/libm/src/math/exp10f.rs index e81d18380b940..0520a41f2e97c 100644 --- a/library/compiler-builtins/libm/src/math/exp10f.rs +++ b/library/compiler-builtins/libm/src/math/exp10f.rs @@ -11,7 +11,7 @@ pub fn exp10f(x: f32) -> f32 { let (mut y, n) = modff(x); let u = n.to_bits(); /* fabsf(n) < 8 without raising invalid on nan */ - if (u >> 23 & 0xff) < 0x7f + 3 { + if ((u >> 23) & 0xff) < 0x7f + 3 { if y == 0.0 { return i!(P10, ((n as isize) + 7) as usize); } diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs index dce2ab4df6ff6..6e98d066cbfce 100644 --- a/library/compiler-builtins/libm/src/math/exp2.rs +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -341,7 +341,7 @@ pub fn exp2(mut x: f64) -> f64 { /* Filter out exceptional cases. */ let ui = f64::to_bits(x); - let ix = ui >> 32 & 0x7fffffff; + let ix = (ui >> 32) & 0x7fffffff; if ix >= 0x408ff000 { /* |x| >= 1022 or nan */ if ix >= 0x40900000 && ui >> 63 == 0 { diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index bb2028fa77f25..826143d5a47c4 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -82,7 +82,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { d -= 64; if d == 0 { } else if d < 64 { - rlo = rhi << (64 - d) | rlo >> d | ((rlo << (64 - d)) != 0) as u64; + rlo = (rhi << (64 - d)) | (rlo >> d) | ((rlo << (64 - d)) != 0) as u64; rhi = rhi >> d; } else { rlo = 1; @@ -95,7 +95,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { if d == 0 { zlo = nz.m; } else if d < 64 { - zlo = nz.m >> d | ((nz.m << (64 - d)) != 0) as u64; + zlo = (nz.m >> d) | ((nz.m << (64 - d)) != 0) as u64; } else { zlo = 1; } @@ -127,11 +127,11 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { e += 64; d = rhi.leading_zeros() as i32 - 1; /* note: d > 0 */ - rhi = rhi << d | rlo >> (64 - d) | ((rlo << d) != 0) as u64; + rhi = (rhi << d) | (rlo >> (64 - d)) | ((rlo << d) != 0) as u64; } else if rlo != 0 { d = rlo.leading_zeros() as i32 - 1; if d < 0 { - rhi = rlo >> 1 | (rlo & 1); + rhi = (rlo >> 1) | (rlo & 1); } else { rhi = rlo << d; } @@ -165,7 +165,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { /* one bit is lost when scaled, add another top bit to only round once at conversion if it is inexact */ if (rhi << 53) != 0 { - i = (rhi >> 1 | (rhi & 1) | 1 << 62) as i64; + i = ((rhi >> 1) | (rhi & 1) | (1 << 62)) as i64; if sign != 0 { i = -i; } @@ -182,7 +182,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 { } else { /* only round once when scaled */ d = 10; - i = ((rhi >> d | ((rhi << (64 - d)) != 0) as u64) << d) as i64; + i = (((rhi >> d) | ((rhi << (64 - d)) != 0) as u64) << d) as i64; if sign != 0 { i = -i; } diff --git a/library/compiler-builtins/libm/src/math/fmod.rs b/library/compiler-builtins/libm/src/math/fmod.rs index df16162bcae86..b68e6b0ea3c86 100644 --- a/library/compiler-builtins/libm/src/math/fmod.rs +++ b/library/compiler-builtins/libm/src/math/fmod.rs @@ -2,8 +2,8 @@ pub fn fmod(x: f64, y: f64) -> f64 { let mut uxi = x.to_bits(); let mut uyi = y.to_bits(); - let mut ex = (uxi >> 52 & 0x7ff) as i64; - let mut ey = (uyi >> 52 & 0x7ff) as i64; + let mut ex = ((uxi >> 52) & 0x7ff) as i64; + let mut ey = ((uyi >> 52) & 0x7ff) as i64; let sx = uxi >> 63; let mut i; diff --git a/library/compiler-builtins/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs index 671af85800f1f..4de18195770da 100644 --- a/library/compiler-builtins/libm/src/math/fmodf.rs +++ b/library/compiler-builtins/libm/src/math/fmodf.rs @@ -4,8 +4,8 @@ use core::f32; pub fn fmodf(x: f32, y: f32) -> f32 { let mut uxi = x.to_bits(); let mut uyi = y.to_bits(); - let mut ex = (uxi >> 23 & 0xff) as i32; - let mut ey = (uyi >> 23 & 0xff) as i32; + let mut ex = ((uxi >> 23) & 0xff) as i32; + let mut ey = ((uyi >> 23) & 0xff) as i32; let sx = uxi & 0x80000000; let mut i; diff --git a/library/compiler-builtins/libm/src/math/j1.rs b/library/compiler-builtins/libm/src/math/j1.rs index cef17a63e3701..578ae59d3ab69 100644 --- a/library/compiler-builtins/libm/src/math/j1.rs +++ b/library/compiler-builtins/libm/src/math/j1.rs @@ -171,10 +171,10 @@ pub fn y1(x: f64) -> f64 { lx = get_low_word(x); /* y1(nan)=nan, y1(<0)=nan, y1(0)=-inf, y1(inf)=0 */ - if (ix << 1 | lx) == 0 { + if (ix << 1) | lx == 0 { return -1.0 / 0.0; } - if (ix >> 31) != 0 { + if ix >> 31 != 0 { return 0.0 / 0.0; } if ix >= 0x7ff00000 { diff --git a/library/compiler-builtins/libm/src/math/jn.rs b/library/compiler-builtins/libm/src/math/jn.rs index 7f98ddc055a62..d228781d12aa4 100644 --- a/library/compiler-builtins/libm/src/math/jn.rs +++ b/library/compiler-builtins/libm/src/math/jn.rs @@ -55,7 +55,7 @@ pub fn jn(n: i32, mut x: f64) -> f64 { ix &= 0x7fffffff; // -lx == !lx + 1 - if (ix | (lx | ((!lx).wrapping_add(1))) >> 31) > 0x7ff00000 { + if ix | ((lx | (!lx).wrapping_add(1)) >> 31) > 0x7ff00000 { /* nan */ return x; } @@ -265,7 +265,7 @@ pub fn yn(n: i32, x: f64) -> f64 { ix &= 0x7fffffff; // -lx == !lx + 1 - if (ix | (lx | ((!lx).wrapping_add(1))) >> 31) > 0x7ff00000 { + if ix | ((lx | (!lx).wrapping_add(1)) >> 31) > 0x7ff00000 { /* nan */ return x; } diff --git a/library/compiler-builtins/libm/src/math/log10.rs b/library/compiler-builtins/libm/src/math/log10.rs index f9d118f129296..8c9d68c492dbd 100644 --- a/library/compiler-builtins/libm/src/math/log10.rs +++ b/library/compiler-builtins/libm/src/math/log10.rs @@ -78,7 +78,7 @@ pub fn log10(mut x: f64) -> f64 { hx += 0x3ff00000 - 0x3fe6a09e; k += (hx >> 20) as i32 - 0x3ff; hx = (hx & 0x000fffff) + 0x3fe6a09e; - ui = (hx as u64) << 32 | (ui & 0xffffffff); + ui = ((hx as u64) << 32) | (ui & 0xffffffff); x = f64::from_bits(ui); f = x - 1.0; diff --git a/library/compiler-builtins/libm/src/math/log1p.rs b/library/compiler-builtins/libm/src/math/log1p.rs index 80561ec74159e..b7f3fb09e1574 100644 --- a/library/compiler-builtins/libm/src/math/log1p.rs +++ b/library/compiler-builtins/libm/src/math/log1p.rs @@ -125,7 +125,7 @@ pub fn log1p(x: f64) -> f64 { } /* reduce u into [sqrt(2)/2, sqrt(2)] */ hu = (hu & 0x000fffff) + 0x3fe6a09e; - ui = (hu as u64) << 32 | (ui & 0xffffffff); + ui = ((hu as u64) << 32) | (ui & 0xffffffff); f = f64::from_bits(ui) - 1.; } hfsq = 0.5 * f * f; diff --git a/library/compiler-builtins/libm/src/math/log2.rs b/library/compiler-builtins/libm/src/math/log2.rs index 59533340bd878..701f63c25e72b 100644 --- a/library/compiler-builtins/libm/src/math/log2.rs +++ b/library/compiler-builtins/libm/src/math/log2.rs @@ -75,7 +75,7 @@ pub fn log2(mut x: f64) -> f64 { hx += 0x3ff00000 - 0x3fe6a09e; k += (hx >> 20) as i32 - 0x3ff; hx = (hx & 0x000fffff) + 0x3fe6a09e; - ui = (hx as u64) << 32 | (ui & 0xffffffff); + ui = ((hx as u64) << 32) | (ui & 0xffffffff); x = f64::from_bits(ui); f = x - 1.0; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index afebdf5864c5d..3852c774e80c6 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -359,5 +359,5 @@ fn with_set_low_word(f: f64, lo: u32) -> f64 { #[inline] fn combine_words(hi: u32, lo: u32) -> f64 { - f64::from_bits((hi as u64) << 32 | lo as u64) + f64::from_bits(((hi as u64) << 32) | lo as u64) } diff --git a/library/compiler-builtins/libm/src/math/modf.rs b/library/compiler-builtins/libm/src/math/modf.rs index bcab33a810d66..e29e80ccf5f39 100644 --- a/library/compiler-builtins/libm/src/math/modf.rs +++ b/library/compiler-builtins/libm/src/math/modf.rs @@ -2,7 +2,7 @@ pub fn modf(x: f64) -> (f64, f64) { let rv2: f64; let mut u = x.to_bits(); let mask: u64; - let e = ((u >> 52 & 0x7ff) as i32) - 0x3ff; + let e = (((u >> 52) & 0x7ff) as i32) - 0x3ff; /* no fractional part */ if e >= 52 { diff --git a/library/compiler-builtins/libm/src/math/modff.rs b/library/compiler-builtins/libm/src/math/modff.rs index 56ece12e3c0de..fac60abaa55c1 100644 --- a/library/compiler-builtins/libm/src/math/modff.rs +++ b/library/compiler-builtins/libm/src/math/modff.rs @@ -2,7 +2,7 @@ pub fn modff(x: f32) -> (f32, f32) { let rv2: f32; let mut u: u32 = x.to_bits(); let mask: u32; - let e = ((u >> 23 & 0xff) as i32) - 0x7f; + let e = (((u >> 23) & 0xff) as i32) - 0x7f; /* no fractional part */ if e >= 23 { diff --git a/library/compiler-builtins/libm/src/math/nextafter.rs b/library/compiler-builtins/libm/src/math/nextafter.rs index 422bd7496d5ef..c991ff6f2330d 100644 --- a/library/compiler-builtins/libm/src/math/nextafter.rs +++ b/library/compiler-builtins/libm/src/math/nextafter.rs @@ -16,14 +16,14 @@ pub fn nextafter(x: f64, y: f64) -> f64 { if ay == 0 { return y; } - ux_i = (uy_i & 1_u64 << 63) | 1; - } else if ax > ay || ((ux_i ^ uy_i) & 1_u64 << 63) != 0 { + ux_i = (uy_i & (1_u64 << 63)) | 1; + } else if ax > ay || ((ux_i ^ uy_i) & (1_u64 << 63)) != 0 { ux_i -= 1; } else { ux_i += 1; } - let e = ux_i >> 52 & 0x7ff; + let e = (ux_i >> 52) & 0x7ff; // raise overflow if ux.f is infinite and x is finite if e == 0x7ff { force_eval!(x + x); diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index 618b26e5466b9..cbdc3c2b91c82 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -2,7 +2,7 @@ pub fn rint(x: f64) -> f64 { let one_over_e = 1.0 / f64::EPSILON; let as_u64: u64 = x.to_bits(); - let exponent: u64 = as_u64 >> 52 & 0x7ff; + let exponent: u64 = (as_u64 >> 52) & 0x7ff; let is_positive = (as_u64 >> 63) == 0; if exponent >= 0x3ff + 52 { x diff --git a/library/compiler-builtins/libm/src/math/rintf.rs b/library/compiler-builtins/libm/src/math/rintf.rs index 0726d83ba6732..2d22c9393543a 100644 --- a/library/compiler-builtins/libm/src/math/rintf.rs +++ b/library/compiler-builtins/libm/src/math/rintf.rs @@ -2,7 +2,7 @@ pub fn rintf(x: f32) -> f32 { let one_over_e = 1.0 / f32::EPSILON; let as_u32: u32 = x.to_bits(); - let exponent: u32 = as_u32 >> 23 & 0xff; + let exponent: u32 = (as_u32 >> 23) & 0xff; let is_positive = (as_u32 >> 31) == 0; if exponent >= 0x7f + 23 { x diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index d9a8f184ce0c2..3f1a10fddc6e5 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -219,7 +219,7 @@ pub fn sqrt(x: f64) -> f64 { ix1 |= sign; } ix0 += m << 20; - f64::from_bits((ix0 as u64) << 32 | ix1.0 as u64) + f64::from_bits(((ix0 as u64) << 32) | ix1.0 as u64) } #[cfg(test)] diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs index 34bc2fdfa48ca..d85bffb40e4aa 100644 --- a/library/compiler-builtins/libm/src/math/trunc.rs +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -14,7 +14,7 @@ pub fn trunc(x: f64) -> f64 { let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 let mut i: u64 = x.to_bits(); - let mut e: i64 = (i >> 52 & 0x7ff) as i64 - 0x3ff + 12; + let mut e: i64 = ((i >> 52) & 0x7ff) as i64 - 0x3ff + 12; let m: u64; if e >= 52 + 12 { diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs index a74f789877236..82017b87b7cef 100644 --- a/library/compiler-builtins/libm/src/math/truncf.rs +++ b/library/compiler-builtins/libm/src/math/truncf.rs @@ -14,7 +14,7 @@ pub fn truncf(x: f32) -> f32 { let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 let mut i: u32 = x.to_bits(); - let mut e: i32 = (i >> 23 & 0xff) as i32 - 0x7f + 9; + let mut e: i32 = ((i >> 23) & 0xff) as i32 - 0x7f + 9; let m: u32; if e >= 23 + 9 { From 4e5a156cd0e5269991e16dbef059a9979540def2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 27 Dec 2024 11:02:40 +0000 Subject: [PATCH 1464/4206] Allow Clippy lints in `compiler-builtins-smoke-test` Rather than always needing to exclude `cb` when running `cargo clippy`, just disable Clippy for the included module. --- library/compiler-builtins/libm/.github/workflows/main.yml | 1 - .../libm/crates/compiler-builtins-smoke-test/src/lib.rs | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 866f0de9ec010..d290d09a55ff2 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -120,7 +120,6 @@ jobs: run: ./ci/download-musl.sh - run: | cargo clippy --all \ - --exclude cb \ --features libm-test/build-musl,libm-test/test-multiprecision \ --all-targets diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index e65cb8da3c4f6..e3a51a575e489 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -4,8 +4,9 @@ #![feature(core_intrinsics)] #![allow(internal_features)] -#![allow(dead_code)] #![no_std] +#[allow(dead_code)] +#[allow(clippy::all)] // We don't get `libm`'s list of `allow`s, so just ignore Clippy. #[path = "../../../src/math/mod.rs"] pub mod libm; From 51956a53c31ce2d96fce25bf4e8a024f47480f06 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 29 Dec 2024 06:46:22 +0000 Subject: [PATCH 1465/4206] Change from `-latest` to named CI images GitHub will be upgrading the `-latest` tags of these images in the near future. Change all images to specify the latest version. --- .../libm/.github/workflows/main.yml | 62 +++++++++---------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index d290d09a55ff2..93cd541f8385d 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -16,56 +16,56 @@ jobs: matrix: include: - target: aarch64-apple-darwin - os: macos-latest + os: macos-15 - target: aarch64-unknown-linux-gnu - os: ubuntu-latest + os: ubuntu-24.04 - target: aarch64-pc-windows-msvc - os: windows-latest + os: windows-2025 build_only: 1 # Can't run on x86 hosts - target: arm-unknown-linux-gnueabi - os: ubuntu-latest + os: ubuntu-24.04 - target: arm-unknown-linux-gnueabihf - os: ubuntu-latest + os: ubuntu-24.04 - target: armv7-unknown-linux-gnueabihf - os: ubuntu-latest + os: ubuntu-24.04 - target: i586-unknown-linux-gnu - os: ubuntu-latest + os: ubuntu-24.04 - target: i686-unknown-linux-gnu - os: ubuntu-latest + os: ubuntu-24.04 - target: loongarch64-unknown-linux-gnu - os: ubuntu-latest + os: ubuntu-24.04 - target: powerpc-unknown-linux-gnu - os: ubuntu-latest + os: ubuntu-24.04 - target: powerpc64-unknown-linux-gnu - os: ubuntu-latest + os: ubuntu-24.04 - target: powerpc64le-unknown-linux-gnu - os: ubuntu-latest + os: ubuntu-24.04 - target: riscv64gc-unknown-linux-gnu - os: ubuntu-latest + os: ubuntu-24.04 - target: thumbv6m-none-eabi - os: ubuntu-latest + os: ubuntu-24.04 - target: thumbv7em-none-eabi - os: ubuntu-latest + os: ubuntu-24.04 - target: thumbv7em-none-eabihf - os: ubuntu-latest + os: ubuntu-24.04 - target: thumbv7m-none-eabi - os: ubuntu-latest + os: ubuntu-24.04 - target: x86_64-unknown-linux-gnu - os: ubuntu-latest + os: ubuntu-24.04 - target: x86_64-apple-darwin os: macos-13 - target: wasm32-unknown-unknown - os: ubuntu-latest + os: ubuntu-24.04 build_only: 1 - target: i686-pc-windows-msvc - os: windows-latest + os: windows-2025 - target: x86_64-pc-windows-msvc - os: windows-latest + os: windows-2025 - target: i686-pc-windows-gnu - os: windows-latest + os: windows-2025 channel: nightly-i686-gnu - target: x86_64-pc-windows-gnu - os: windows-latest + os: windows-2025 channel: nightly-x86_64-gnu runs-on: ${{ matrix.os }} env: @@ -94,20 +94,20 @@ jobs: # Non-linux tests just use our raw script - name: Run locally - if: matrix.os != 'ubuntu-latest' || contains(matrix.target, 'wasm') + if: matrix.os != 'ubuntu-24.04' || contains(matrix.target, 'wasm') shell: bash run: ./ci/run.sh ${{ matrix.target }} # Otherwise we use our docker containers to run builds - name: Run in Docker - if: matrix.os == 'ubuntu-latest' && !contains(matrix.target, 'wasm') + if: matrix.os == 'ubuntu-24.04' && !contains(matrix.target, 'wasm') run: | rustup target add x86_64-unknown-linux-musl cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} clippy: name: Clippy - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@master - name: Install Rust @@ -125,7 +125,7 @@ jobs: builtins: name: Check use with compiler-builtins - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@master - name: Install Rust @@ -135,7 +135,7 @@ jobs: benchmarks: name: Benchmarks - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@master - name: Install Rust @@ -147,7 +147,7 @@ jobs: msrv: name: Check MSRV - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 env: RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings` steps: @@ -163,7 +163,7 @@ jobs: rustfmt: name: Rustfmt - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@master - name: Install Rust @@ -180,7 +180,7 @@ jobs: - benchmarks - msrv - rustfmt - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency # failed" as success. So we have to do some contortions to ensure the job fails if any of its # dependencies fails. From b9871da445687345ebf73476b595b991b4f1b793 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 03:07:58 -0500 Subject: [PATCH 1466/4206] Introduce generic `abs` and `copysign` Add generic versions of `abs` and `copysign`, which will provide an entrypoint for adding `f16` and `f128`. Since this implementation is identical to the existing type-specific implementations, make use of it for `f32` and `f64`. --- library/compiler-builtins/libm/src/math/copysign.rs | 6 +----- library/compiler-builtins/libm/src/math/copysignf.rs | 6 +----- library/compiler-builtins/libm/src/math/fabs.rs | 2 +- library/compiler-builtins/libm/src/math/fabsf.rs | 2 +- library/compiler-builtins/libm/src/math/generic/abs.rs | 6 ++++++ .../libm/src/math/generic/copysign.rs | 10 ++++++++++ library/compiler-builtins/libm/src/math/generic/mod.rs | 5 +++++ library/compiler-builtins/libm/src/math/mod.rs | 1 + 8 files changed, 26 insertions(+), 12 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/abs.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/copysign.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/mod.rs diff --git a/library/compiler-builtins/libm/src/math/copysign.rs b/library/compiler-builtins/libm/src/math/copysign.rs index 1f4a35a331b9a..552bf3975b8f1 100644 --- a/library/compiler-builtins/libm/src/math/copysign.rs +++ b/library/compiler-builtins/libm/src/math/copysign.rs @@ -4,9 +4,5 @@ /// first argument, `x`, and the sign of its second argument, `y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn copysign(x: f64, y: f64) -> f64 { - let mut ux = x.to_bits(); - let uy = y.to_bits(); - ux &= (!0) >> 1; - ux |= uy & (1 << 63); - f64::from_bits(ux) + super::generic::copysign(x, y) } diff --git a/library/compiler-builtins/libm/src/math/copysignf.rs b/library/compiler-builtins/libm/src/math/copysignf.rs index 6c346e3a52804..8b9bed4c0c427 100644 --- a/library/compiler-builtins/libm/src/math/copysignf.rs +++ b/library/compiler-builtins/libm/src/math/copysignf.rs @@ -4,9 +4,5 @@ /// first argument, `x`, and the sign of its second argument, `y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn copysignf(x: f32, y: f32) -> f32 { - let mut ux = x.to_bits(); - let uy = y.to_bits(); - ux &= 0x7fffffff; - ux |= uy & 0x80000000; - f32::from_bits(ux) + super::generic::copysign(x, y) } diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index d083053e18834..2163637e72801 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -9,7 +9,7 @@ pub fn fabs(x: f64) -> f64 { args: x, } - f64::from_bits(x.to_bits() & (u64::MAX / 2)) + super::generic::abs(x) } #[cfg(test)] diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index eabe87254b74a..ac77c9201ade3 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -9,7 +9,7 @@ pub fn fabsf(x: f32) -> f32 { args: x, } - f32::from_bits(x.to_bits() & 0x7fffffff) + super::generic::abs(x) } // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 diff --git a/library/compiler-builtins/libm/src/math/generic/abs.rs b/library/compiler-builtins/libm/src/math/generic/abs.rs new file mode 100644 index 0000000000000..2c9a43c1249a5 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/abs.rs @@ -0,0 +1,6 @@ +use super::super::Float; + +/// Absolute value. +pub fn abs(x: F) -> F { + x.abs() +} diff --git a/library/compiler-builtins/libm/src/math/generic/copysign.rs b/library/compiler-builtins/libm/src/math/generic/copysign.rs new file mode 100644 index 0000000000000..d6b8148919357 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/copysign.rs @@ -0,0 +1,10 @@ +use super::super::Float; + +/// Copy the sign of `y` to `x`. +pub fn copysign(x: F, y: F) -> F { + let mut ux = x.to_bits(); + let uy = y.to_bits(); + ux &= !F::SIGN_MASK; + ux |= uy & (F::SIGN_MASK); + F::from_bits(ux) +} diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs new file mode 100644 index 0000000000000..1ddd08f0eff97 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -0,0 +1,5 @@ +mod abs; +mod copysign; + +pub use abs::abs; +pub use copysign::copysign; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 3852c774e80c6..ba1995228162f 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -87,6 +87,7 @@ mod support; mod arch; mod expo2; mod fenv; +mod generic; mod k_cos; mod k_cosf; mod k_expo2; From f2e16b6ac1f3f5516f31809c0712b9a91eaa1a85 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 26 Oct 2024 00:44:50 -0500 Subject: [PATCH 1467/4206] Add `f16` and `f128` configuration from `compiler-builtins` In preparation of adding routines from these two types, duplicate the `compiler-builtins` configuration here. --- library/compiler-builtins/libm/Cargo.toml | 5 +- library/compiler-builtins/libm/build.rs | 30 +--- library/compiler-builtins/libm/configure.rs | 168 ++++++++++++++++++ .../compiler-builtins-smoke-test/Cargo.toml | 2 + .../libm/crates/libm-macros/Cargo.toml | 7 + .../libm/crates/libm-test/Cargo.toml | 11 +- .../libm/crates/libm-test/build.rs | 62 +------ library/compiler-builtins/libm/src/lib.rs | 2 + .../libm/src/math/support/float_traits.rs | 4 + 9 files changed, 208 insertions(+), 83 deletions(-) create mode 100644 library/compiler-builtins/libm/configure.rs diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 98a60bfe3fe97..bfc11509e4246 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -21,7 +21,7 @@ arch = [] # This tells the compiler to assume that a Nightly toolchain is being used and # that it should activate any useful Nightly things accordingly. -unstable = ["unstable-intrinsics"] +unstable = ["unstable-intrinsics", "unstable-float"] # Enable calls to functions in `core::intrinsics` unstable-intrinsics = [] @@ -29,6 +29,9 @@ unstable-intrinsics = [] # Make some internal things public for testing. unstable-test-support = [] +# 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 diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 0010292361138..9c9e0e7232864 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -1,6 +1,10 @@ use std::env; +mod configure; + fn main() { + let cfg = configure::Config::from_env(); + println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rustc-check-cfg=cfg(assert_no_panic)"); @@ -14,29 +18,5 @@ fn main() { } } - configure_intrinsics(); - configure_arch(); -} - -/// Simplify the feature logic for enabling intrinsics so code only needs to use -/// `cfg(intrinsics_enabled)`. -fn configure_intrinsics() { - 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"); - } -} - -/// Simplify the feature logic for enabling arch-specific features so code only needs to use -/// `cfg(arch_enabled)`. -fn configure_arch() { - 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"); - } + configure::emit_libm_config(&cfg); } diff --git a/library/compiler-builtins/libm/configure.rs b/library/compiler-builtins/libm/configure.rs new file mode 100644 index 0000000000000..389e86c33889f --- /dev/null +++ b/library/compiler-builtins/libm/configure.rs @@ -0,0 +1,168 @@ +// Configuration shared with both libm and libm-test + +use std::env; +use std::path::PathBuf; + +#[allow(dead_code)] +pub struct Config { + pub manifest_dir: PathBuf, + pub out_dir: PathBuf, + pub opt_level: u8, + pub target_arch: String, + pub target_env: String, + pub target_family: Option, + pub target_os: String, + pub target_string: String, + pub target_vendor: String, + pub target_features: Vec, +} + +impl Config { + pub fn from_env() -> Self { + let target_features = env::var("CARGO_CFG_TARGET_FEATURE") + .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) + .unwrap_or_default(); + + Self { + 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().parse().unwrap(), + target_arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), + target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), + target_family: env::var("CARGO_CFG_TARGET_FAMILY").ok(), + target_os: env::var("CARGO_CFG_TARGET_OS").unwrap(), + target_string: env::var("TARGET").unwrap(), + target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), + target_features, + } + } +} + +/// Libm gets most config options made available. +#[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_f16_f128_cfg(cfg); +} + +/// Tests don't need most feature-related config. +#[allow(dead_code)] +pub fn emit_test_config(cfg: &Config) { + emit_optimization_cfg(cfg); + emit_cfg_shorthands(cfg); + emit_f16_f128_cfg(cfg); +} + +/// 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"); + } +} + +/// 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"); + } +} + +/// 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 cfg.opt_level >= 2 { + println!("cargo:rustc-cfg=optimizations_enabled"); + } +} + +/// 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") { + // Shorthand to detect i586 targets + println!("cargo:rustc-cfg=x86_no_sse"); + } +} + +/// 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. + if !cfg!(feature = "unstable-float") { + return; + } + + // Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means + // that the backend will not crash when using these types and generates code that can be called + // without crashing (no infinite recursion). This does not mean that the platform doesn't have + // ABI or other bugs. + // + // We do this here rather than in `rust-lang/rust` because configuring via cargo features is + // not straightforward. + // + // Original source of this list: + // + let f16_enabled = match cfg.target_arch.as_str() { + // Unsupported + "arm64ec" => false, + // Selection failure + "s390x" => false, + // Infinite recursion + // FIXME(llvm): loongarch fixed by + "csky" => false, + "hexagon" => false, + "loongarch64" => false, + "mips" | "mips64" | "mips32r6" | "mips64r6" => false, + "powerpc" | "powerpc64" => false, + "sparc" | "sparc64" => false, + "wasm32" | "wasm64" => false, + // Most everything else works as of LLVM 19 + _ => true, + }; + + let f128_enabled = match cfg.target_arch.as_str() { + // Unsupported (libcall is not supported) + "amdgpu" => false, + // Unsupported + "arm64ec" => false, + // Selection failure + "mips64" | "mips64r6" => false, + // Selection failure + "nvptx64" => false, + // Selection failure + "powerpc64" if &cfg.target_os == "aix" => false, + // Selection failure + "sparc" => false, + // Most everything else works as of LLVM 19 + _ => true, + }; + + // If the feature is set, disable these types. + let disable_both = env::var_os("CARGO_FEATURE_NO_F16_F128").is_some(); + + println!("cargo:rustc-check-cfg=cfg(f16_enabled)"); + println!("cargo:rustc-check-cfg=cfg(f128_enabled)"); + + if f16_enabled && !disable_both { + println!("cargo:rustc-cfg=f16_enabled"); + } + + if f128_enabled && !disable_both { + println!("cargo:rustc-cfg=f128_enabled"); + } +} diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index e75c4f42bfa2a..82cfeecb90fef 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -21,5 +21,7 @@ force-soft-floats = [] unexpected_cfgs = { level = "warn", check-cfg = [ "cfg(arch_enabled)", "cfg(assert_no_panic)", + "cfg(f128_enabled)", + "cfg(f16_enabled)", "cfg(intrinsics_enabled)", ] } diff --git a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml index c9defb1c5cbb4..9194232b24c2f 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml @@ -12,3 +12,10 @@ heck = "0.5.0" proc-macro2 = "1.0.88" quote = "1.0.37" syn = { version = "2.0.79", features = ["full", "extra-traits", "visit-mut"] } + +[lints.rust] +# Values used during testing +unexpected_cfgs = { level = "warn", check-cfg = [ + 'cfg(f16_enabled)', + 'cfg(f128_enabled)', +] } diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 4d75b25f81e48..f2dd88fa14c9c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -5,7 +5,10 @@ edition = "2021" publish = false [features] -default = [] +default = ["unstable-float"] + +# Propagated from libm because this affects which functions we test. +unstable-float = ["libm/unstable-float"] # Generate tests which are random inputs and the outputs are calculated with # musl libc. @@ -44,3 +47,9 @@ criterion = { version = "0.5.1", default-features = false, features = ["cargo_be [[bench]] name = "random" 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"))', +] } diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs index dc3126dbb9459..f2cd298baf213 100644 --- a/library/compiler-builtins/libm/crates/libm-test/build.rs +++ b/library/compiler-builtins/libm/crates/libm-test/build.rs @@ -1,66 +1,16 @@ use std::fmt::Write; -use std::path::PathBuf; -use std::{env, fs}; +use std::fs; + +#[path = "../../configure.rs"] +mod configure; +use configure::Config; fn main() { let cfg = Config::from_env(); - emit_optimization_cfg(&cfg); - emit_cfg_shorthands(&cfg); list_all_tests(&cfg); -} - -#[allow(dead_code)] -struct Config { - manifest_dir: PathBuf, - out_dir: PathBuf, - opt_level: u8, - target_arch: String, - target_env: String, - target_family: Option, - target_os: String, - target_string: String, - target_vendor: String, - target_features: Vec, -} - -impl Config { - fn from_env() -> Self { - let target_features = env::var("CARGO_CFG_TARGET_FEATURE") - .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) - .unwrap_or_default(); - - Self { - 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().parse().unwrap(), - target_arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), - target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), - target_family: env::var("CARGO_CFG_TARGET_FAMILY").ok(), - target_os: env::var("CARGO_CFG_TARGET_OS").unwrap(), - target_string: env::var("TARGET").unwrap(), - target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), - target_features, - } - } -} -/// 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 cfg.opt_level >= 2 { - println!("cargo::rustc-cfg=optimizations_enabled"); - } -} - -/// 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") { - // Shorthand to detect i586 targets - println!("cargo::rustc-cfg=x86_no_sse"); - } + configure::emit_test_config(&cfg); } /// Create a list of all source files in an array. This can be used for making sure that diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 6bb06b5b81f56..327e3d6e65b43 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -2,6 +2,8 @@ #![no_std] #![cfg_attr(intrinsics_enabled, allow(internal_features))] #![cfg_attr(intrinsics_enabled, feature(core_intrinsics))] +#![cfg_attr(f128_enabled, feature(f128))] +#![cfg_attr(f16_enabled, feature(f16))] #![allow(clippy::assign_op_pattern)] #![allow(clippy::deprecated_cfg_attr)] #![allow(clippy::eq_op)] 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 5808aeebc1393..7b3f6904b9df3 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -219,5 +219,9 @@ macro_rules! float_impl { }; } +#[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); From 2323d3a2e3ed5a60fc13c7bf177bf875f91868db Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 29 Dec 2024 07:37:01 +0000 Subject: [PATCH 1468/4206] Always enable `unstable-float` in CI Since these add new API but do not affect runtime, we can enable it for all tests that run with nightly. --- library/compiler-builtins/libm/ci/run.sh | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index d89c8bdf06024..7e514a1cd2e51 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -62,22 +62,26 @@ esac cargo check --no-default-features cargo check --features "force-soft-floats" +# Always enable `unstable-float` since it expands available API but does not +# change any implementations. +extra_flags="$extra_flags --features unstable-float" + if [ "${BUILD_ONLY:-}" = "1" ]; then cmd="cargo build --target $target --package libm" $cmd - $cmd --features "unstable-intrinsics" + $cmd --features unstable-intrinsics echo "can't run tests on $target; skipping" else cmd="cargo test --all --target $target $extra_flags" - # stable by default + # Test without intrinsics $cmd $cmd --release - # unstable with a feature - $cmd --features "unstable-intrinsics" - $cmd --release --features "unstable-intrinsics" + # Test with intrinsic use + $cmd --features unstable-intrinsics + $cmd --release --features unstable-intrinsics # Make sure benchmarks have correct results $cmd --benches From 5e6b813e514eb7147a139fb757b875a9fa8962f7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 19 Dec 2024 11:47:04 +0000 Subject: [PATCH 1469/4206] Update and slightly refactor some of the `Float` trait Add a constant for negative pi and provide a standalone const `from_bits`, which can be combined with what we already had in `hex_float`. Also provide another default method to reduce what needs to be provided by the macro. --- .../libm/src/math/support/float_traits.rs | 47 +++++++++++++------ .../libm/src/math/support/hex_float.rs | 12 +---- .../libm/src/math/support/mod.rs | 1 + 3 files changed, 36 insertions(+), 24 deletions(-) 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 7b3f6904b9df3..68ba600309a93 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -38,6 +38,7 @@ pub trait Float: const MAX: Self; const MIN: Self; const PI: Self; + const NEG_PI: Self; const FRAC_PI_2: Self; /// The bitwidth of the float type @@ -71,7 +72,9 @@ pub trait Float: fn to_bits(self) -> Self::Int; /// Returns `self` transmuted to `Self::SignedInt` - fn to_bits_signed(self) -> Self::SignedInt; + fn to_bits_signed(self) -> Self::SignedInt { + self.to_bits().signed() + } /// 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 @@ -158,7 +161,15 @@ pub trait Float: pub type IntTy = ::Int; macro_rules! float_impl { - ($ty:ident, $ity:ident, $sity:ident, $expty:ident, $bits:expr, $significand_bits:expr) => { + ( + $ty:ident, + $ity:ident, + $sity:ident, + $expty:ident, + $bits:expr, + $significand_bits:expr, + $from_bits:path + ) => { impl Float for $ty { type Int = $ity; type SignedInt = $sity; @@ -173,13 +184,10 @@ macro_rules! float_impl { const NAN: Self = Self::NAN; const MAX: Self = -Self::MIN; // Sign bit set, saturated mantissa, saturated exponent with last bit zeroed - // FIXME(msrv): just use `from_bits` when available - // SAFETY: POD cast with no preconditions - const MIN: Self = unsafe { - mem::transmute::(Self::Int::MAX & !(1 << Self::SIG_BITS)) - }; + const MIN: Self = $from_bits(Self::Int::MAX & !(1 << Self::SIG_BITS)); const PI: Self = core::$ty::consts::PI; + const NEG_PI: Self = -Self::PI; const FRAC_PI_2: Self = core::$ty::consts::FRAC_PI_2; const BITS: u32 = $bits; @@ -193,9 +201,6 @@ macro_rules! float_impl { fn to_bits(self) -> Self::Int { self.to_bits() } - fn to_bits_signed(self) -> Self::SignedInt { - self.to_bits() as Self::SignedInt - } fn is_nan(self) -> bool { self.is_nan() } @@ -220,8 +225,22 @@ macro_rules! float_impl { } #[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); +float_impl!(f16, u16, i16, i8, 16, 10, f16::from_bits); +float_impl!(f32, u32, i32, i16, 32, 23, f32_from_bits); +float_impl!(f64, u64, i64, i16, 64, 52, f64_from_bits); #[cfg(f128_enabled)] -float_impl!(f128, u128, i128, i16, 128, 112); +float_impl!(f128, u128, i128, i16, 128, 112, f128::from_bits); + +/* FIXME(msrv): vendor some things that are not const stable at our MSRV */ + +/// `f32::from_bits` +pub const fn f32_from_bits(bits: u32) -> f32 { + // SAFETY: POD cast with no preconditions + unsafe { mem::transmute::(bits) } +} + +/// `f64::from_bits` +pub const fn f64_from_bits(bits: u64) -> f64 { + // SAFETY: POD cast with no preconditions + unsafe { mem::transmute::(bits) } +} 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 80434a5ec3e97..1666c6153608a 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -2,6 +2,8 @@ #![allow(dead_code)] // FIXME: remove once this gets used +use super::{f32_from_bits, f64_from_bits}; + /// Construct a 32-bit float from hex float representation (C-style) pub const fn hf32(s: &str) -> f32 { f32_from_bits(parse_any(s, 32, 23) as u32) @@ -159,16 +161,6 @@ const fn hex_digit(c: u8) -> u8 { /* FIXME(msrv): vendor some things that are not const stable at our MSRV */ -/// `f32::from_bits` -const fn f32_from_bits(v: u32) -> f32 { - unsafe { core::mem::transmute(v) } -} - -/// `f64::from_bits` -const fn f64_from_bits(v: u64) -> f64 { - unsafe { core::mem::transmute(v) } -} - /// `u128::ilog2` const fn u128_ilog2(v: u128) -> u32 { assert!(v != 0); diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index 25681c307da49..e2f4e0e981d6b 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -6,6 +6,7 @@ mod int_traits; #[allow(unused_imports)] pub use float_traits::{Float, IntTy}; +pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; #[allow(unused_imports)] pub use hex_float::{hf32, hf64}; pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; From bae68206fad9089da26f1b82cb6082c592b6d253 Mon Sep 17 00:00:00 2001 From: beetrees Date: Thu, 19 Dec 2024 11:59:09 +0000 Subject: [PATCH 1470/4206] Remove an `is_nan` workaround that is no longer needed --- .../libm/src/math/support/float_traits.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) 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 68ba600309a93..e64640a0d154a 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -80,17 +80,7 @@ pub trait Float: /// represented in multiple different ways. This method returns `true` if two NaNs are /// compared. fn eq_repr(self, rhs: Self) -> bool { - let is_nan = |x: Self| -> bool { - // } - // fn is_nan(x: Self) -> 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() & Self::EXP_MASK == Self::EXP_MASK - && x.to_bits() & Self::SIG_MASK != Self::Int::ZERO - }; - if is_nan(self) && is_nan(rhs) { true } else { self.to_bits() == rhs.to_bits() } + if self.is_nan() && rhs.is_nan() { true } else { self.to_bits() == rhs.to_bits() } } /// Returns true if the value is NaN. From 8d224a0de03bab7bd77c0784a4114a53b702e3f4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 19 Dec 2024 11:18:33 +0000 Subject: [PATCH 1471/4206] Add an 8-bit float type for testing purposes Introduce `f8`, which is an 8-bit float compliant with IEEE-754. This type is useful for testing since it is easily possible to enumerate all values. --- .../libm/crates/libm-test/src/f8_impl.rs | 487 ++++++++++++++++++ .../libm/crates/libm-test/src/lib.rs | 4 + 2 files changed, 491 insertions(+) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs new file mode 100644 index 0000000000000..babcc6357a408 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs @@ -0,0 +1,487 @@ +//! An IEEE-compliant 8-bit float type for testing purposes. + +use std::cmp::{self, Ordering}; +use std::{fmt, ops}; + +use crate::Float; + +/// Sometimes verifying float logic is easiest when all values can quickly be checked exhaustively +/// or by hand. +/// +/// IEEE-754 compliant type that includes a 1 bit sign, 4 bit exponent, and 3 bit significand. +/// Bias is -7. +/// +/// Based on . +#[derive(Clone, Copy)] +#[repr(transparent)] +#[allow(non_camel_case_types)] +pub struct f8(u8); + +impl Float for f8 { + type Int = u8; + type SignedInt = i8; + type ExpInt = i8; + + const ZERO: Self = Self(0b0_0000_000); + const NEG_ZERO: Self = Self(0b1_0000_000); + const ONE: Self = Self(0b0_0111_000); + const NEG_ONE: Self = Self(0b1_0111_000); + const MAX: Self = Self(0b0_1110_111); + const MIN: Self = Self(0b1_1110_111); + const INFINITY: Self = Self(0b0_1111_000); + const NEG_INFINITY: Self = Self(0b1_1111_000); + const NAN: Self = Self(0b0_1111_100); + const PI: Self = Self::ZERO; + const NEG_PI: Self = Self::ZERO; + const FRAC_PI_2: Self = Self::ZERO; + + const BITS: u32 = 8; + const SIG_BITS: u32 = 3; + const SIGN_MASK: Self::Int = 0b1_0000_000; + const SIG_MASK: Self::Int = 0b0_0000_111; + const EXP_MASK: Self::Int = 0b0_1111_000; + const IMPLICIT_BIT: Self::Int = 0b0_0001_000; + + fn to_bits(self) -> Self::Int { + self.0 + } + + fn to_bits_signed(self) -> Self::SignedInt { + self.0 as i8 + } + + fn is_nan(self) -> bool { + self.0 & Self::EXP_MASK == Self::EXP_MASK && self.0 & Self::SIG_MASK != 0 + } + + fn is_infinite(self) -> bool { + self.0 & Self::EXP_MASK == Self::EXP_MASK && self.0 & Self::SIG_MASK == 0 + } + + fn is_sign_negative(self) -> bool { + self.0 & Self::SIGN_MASK != 0 + } + + fn exp(self) -> Self::ExpInt { + unimplemented!() + } + + fn from_bits(a: Self::Int) -> Self { + Self(a) + } + + fn normalize(_significand: Self::Int) -> (i32, Self::Int) { + unimplemented!() + } +} + +impl f8 { + pub const ALL_LEN: usize = 240; + + /// All non-infinite non-NaN values of `f8` + pub const ALL: [Self; Self::ALL_LEN] = [ + // -m*2^7 + Self(0b1_1110_111), // -240 + Self(0b1_1110_110), + Self(0b1_1110_101), + Self(0b1_1110_100), + Self(0b1_1110_011), + Self(0b1_1110_010), + Self(0b1_1110_001), + Self(0b1_1110_000), // -128 + // -m*2^6 + Self(0b1_1101_111), // -120 + Self(0b1_1101_110), + Self(0b1_1101_101), + Self(0b1_1101_100), + Self(0b1_1101_011), + Self(0b1_1101_010), + Self(0b1_1101_001), + Self(0b1_1101_000), // -64 + // -m*2^5 + Self(0b1_1100_111), // -60 + Self(0b1_1100_110), + Self(0b1_1100_101), + Self(0b1_1100_100), + Self(0b1_1100_011), + Self(0b1_1100_010), + Self(0b1_1100_001), + Self(0b1_1100_000), // -32 + // -m*2^4 + Self(0b1_1011_111), // -30 + Self(0b1_1011_110), + Self(0b1_1011_101), + Self(0b1_1011_100), + Self(0b1_1011_011), + Self(0b1_1011_010), + Self(0b1_1011_001), + Self(0b1_1011_000), // -16 + // -m*2^3 + Self(0b1_1010_111), // -15 + Self(0b1_1010_110), + Self(0b1_1010_101), + Self(0b1_1010_100), + Self(0b1_1010_011), + Self(0b1_1010_010), + Self(0b1_1010_001), + Self(0b1_1010_000), // -8 + // -m*2^2 + Self(0b1_1001_111), // -7.5 + Self(0b1_1001_110), + Self(0b1_1001_101), + Self(0b1_1001_100), + Self(0b1_1001_011), + Self(0b1_1001_010), + Self(0b1_1001_001), + Self(0b1_1001_000), // -4 + // -m*2^1 + Self(0b1_1000_111), // -3.75 + Self(0b1_1000_110), + Self(0b1_1000_101), + Self(0b1_1000_100), + Self(0b1_1000_011), + Self(0b1_1000_010), + Self(0b1_1000_001), + Self(0b1_1000_000), // -2 + // -m*2^0 + Self(0b1_0111_111), // -1.875 + Self(0b1_0111_110), + Self(0b1_0111_101), + Self(0b1_0111_100), + Self(0b1_0111_011), + Self(0b1_0111_010), + Self(0b1_0111_001), + Self(0b1_0111_000), // -1 + // -m*2^-1 + Self(0b1_0110_111), // −0.9375 + Self(0b1_0110_110), + Self(0b1_0110_101), + Self(0b1_0110_100), + Self(0b1_0110_011), + Self(0b1_0110_010), + Self(0b1_0110_001), + Self(0b1_0110_000), // -0.5 + // -m*2^-2 + Self(0b1_0101_111), // −0.46875 + Self(0b1_0101_110), + Self(0b1_0101_101), + Self(0b1_0101_100), + Self(0b1_0101_011), + Self(0b1_0101_010), + Self(0b1_0101_001), + Self(0b1_0101_000), // -0.25 + // -m*2^-3 + Self(0b1_0100_111), // −0.234375 + Self(0b1_0100_110), + Self(0b1_0100_101), + Self(0b1_0100_100), + Self(0b1_0100_011), + Self(0b1_0100_010), + Self(0b1_0100_001), + Self(0b1_0100_000), // -0.125 + // -m*2^-4 + Self(0b1_0011_111), // −0.1171875 + Self(0b1_0011_110), + Self(0b1_0011_101), + Self(0b1_0011_100), + Self(0b1_0011_011), + Self(0b1_0011_010), + Self(0b1_0011_001), + Self(0b1_0011_000), // −0.0625 + // -m*2^-5 + Self(0b1_0010_111), // −0.05859375 + Self(0b1_0010_110), + Self(0b1_0010_101), + Self(0b1_0010_100), + Self(0b1_0010_011), + Self(0b1_0010_010), + Self(0b1_0010_001), + Self(0b1_0010_000), // −0.03125 + // -m*2^-6 + Self(0b1_0001_111), // −0.029296875 + Self(0b1_0001_110), + Self(0b1_0001_101), + Self(0b1_0001_100), + Self(0b1_0001_011), + Self(0b1_0001_010), + Self(0b1_0001_001), + Self(0b1_0001_000), // −0.015625 + // -m*2^-7 subnormal numbers + Self(0b1_0000_111), // −0.013671875 + Self(0b1_0000_110), + Self(0b1_0000_101), + Self(0b1_0000_100), + Self(0b1_0000_011), + Self(0b1_0000_010), + Self(0b1_0000_001), // −0.001953125 + // Zeroes + Self(0b1_0000_000), // -0.0 + Self(0b0_0000_000), // 0.0 + // m*2^-7 // subnormal numbers + Self(0b0_0000_001), + Self(0b0_0000_010), + Self(0b0_0000_011), + Self(0b0_0000_100), + Self(0b0_0000_101), + Self(0b0_0000_110), + Self(0b0_0000_111), // 0.013671875 + // m*2^-6 + Self(0b0_0001_000), // 0.015625 + Self(0b0_0001_001), + Self(0b0_0001_010), + Self(0b0_0001_011), + Self(0b0_0001_100), + Self(0b0_0001_101), + Self(0b0_0001_110), + Self(0b0_0001_111), // 0.029296875 + // m*2^-5 + Self(0b0_0010_000), // 0.03125 + Self(0b0_0010_001), + Self(0b0_0010_010), + Self(0b0_0010_011), + Self(0b0_0010_100), + Self(0b0_0010_101), + Self(0b0_0010_110), + Self(0b0_0010_111), // 0.05859375 + // m*2^-4 + Self(0b0_0011_000), // 0.0625 + Self(0b0_0011_001), + Self(0b0_0011_010), + Self(0b0_0011_011), + Self(0b0_0011_100), + Self(0b0_0011_101), + Self(0b0_0011_110), + Self(0b0_0011_111), // 0.1171875 + // m*2^-3 + Self(0b0_0100_000), // 0.125 + Self(0b0_0100_001), + Self(0b0_0100_010), + Self(0b0_0100_011), + Self(0b0_0100_100), + Self(0b0_0100_101), + Self(0b0_0100_110), + Self(0b0_0100_111), // 0.234375 + // m*2^-2 + Self(0b0_0101_000), // 0.25 + Self(0b0_0101_001), + Self(0b0_0101_010), + Self(0b0_0101_011), + Self(0b0_0101_100), + Self(0b0_0101_101), + Self(0b0_0101_110), + Self(0b0_0101_111), // 0.46875 + // m*2^-1 + Self(0b0_0110_000), // 0.5 + Self(0b0_0110_001), + Self(0b0_0110_010), + Self(0b0_0110_011), + Self(0b0_0110_100), + Self(0b0_0110_101), + Self(0b0_0110_110), + Self(0b0_0110_111), // 0.9375 + // m*2^0 + Self(0b0_0111_000), // 1 + Self(0b0_0111_001), + Self(0b0_0111_010), + Self(0b0_0111_011), + Self(0b0_0111_100), + Self(0b0_0111_101), + Self(0b0_0111_110), + Self(0b0_0111_111), // 1.875 + // m*2^1 + Self(0b0_1000_000), // 2 + Self(0b0_1000_001), + Self(0b0_1000_010), + Self(0b0_1000_011), + Self(0b0_1000_100), + Self(0b0_1000_101), + Self(0b0_1000_110), + Self(0b0_1000_111), // 3.75 + // m*2^2 + Self(0b0_1001_000), // 4 + Self(0b0_1001_001), + Self(0b0_1001_010), + Self(0b0_1001_011), + Self(0b0_1001_100), + Self(0b0_1001_101), + Self(0b0_1001_110), + Self(0b0_1001_111), // 7.5 + // m*2^3 + Self(0b0_1010_000), // 8 + Self(0b0_1010_001), + Self(0b0_1010_010), + Self(0b0_1010_011), + Self(0b0_1010_100), + Self(0b0_1010_101), + Self(0b0_1010_110), + Self(0b0_1010_111), // 15 + // m*2^4 + Self(0b0_1011_000), // 16 + Self(0b0_1011_001), + Self(0b0_1011_010), + Self(0b0_1011_011), + Self(0b0_1011_100), + Self(0b0_1011_101), + Self(0b0_1011_110), + Self(0b0_1011_111), // 30 + // m*2^5 + Self(0b0_1100_000), // 32 + Self(0b0_1100_001), + Self(0b0_1100_010), + Self(0b0_1100_011), + Self(0b0_1100_100), + Self(0b0_1100_101), + Self(0b0_1100_110), + Self(0b0_1100_111), // 60 + // m*2^6 + Self(0b0_1101_000), // 64 + Self(0b0_1101_001), + Self(0b0_1101_010), + Self(0b0_1101_011), + Self(0b0_1101_100), + Self(0b0_1101_101), + Self(0b0_1101_110), + Self(0b0_1101_111), // 120 + // m*2^7 + Self(0b0_1110_000), // 128 + Self(0b0_1110_001), + Self(0b0_1110_010), + Self(0b0_1110_011), + Self(0b0_1110_100), + Self(0b0_1110_101), + Self(0b0_1110_110), + Self(0b0_1110_111), // 240 + ]; +} + +impl ops::Add for f8 { + type Output = Self; + fn add(self, _rhs: Self) -> Self::Output { + unimplemented!() + } +} + +impl ops::Sub for f8 { + type Output = Self; + fn sub(self, _rhs: Self) -> Self::Output { + unimplemented!() + } +} +impl ops::Mul for f8 { + type Output = Self; + fn mul(self, _rhs: Self) -> Self::Output { + unimplemented!() + } +} +impl ops::Div for f8 { + type Output = Self; + fn div(self, _rhs: Self) -> Self::Output { + unimplemented!() + } +} + +impl ops::Neg for f8 { + type Output = Self; + fn neg(self) -> Self::Output { + Self(self.0 ^ Self::SIGN_MASK) + } +} + +impl ops::Rem for f8 { + type Output = Self; + fn rem(self, _rhs: Self) -> Self::Output { + unimplemented!() + } +} + +impl ops::AddAssign for f8 { + fn add_assign(&mut self, _rhs: Self) { + unimplemented!() + } +} + +impl ops::SubAssign for f8 { + fn sub_assign(&mut self, _rhs: Self) { + unimplemented!() + } +} + +impl ops::MulAssign for f8 { + fn mul_assign(&mut self, _rhs: Self) { + unimplemented!() + } +} + +impl cmp::PartialEq for f8 { + fn eq(&self, other: &Self) -> bool { + if self.is_nan() || other.is_nan() { + false + } else if self.abs().to_bits() | other.abs().to_bits() == 0 { + true + } else { + self.0 == other.0 + } + } +} +impl cmp::PartialOrd for f8 { + fn partial_cmp(&self, other: &Self) -> Option { + let inf_rep = f8::EXP_MASK; + + let a_abs = self.abs().to_bits(); + let b_abs = other.abs().to_bits(); + + // If either a or b is NaN, they are unordered. + if a_abs > inf_rep || b_abs > inf_rep { + return None; + } + + // If a and b are both zeros, they are equal. + if a_abs | b_abs == 0 { + return Some(Ordering::Equal); + } + + let a_srep = self.to_bits_signed(); + let b_srep = other.to_bits_signed(); + let res = a_srep.cmp(&b_srep); + + if a_srep & b_srep >= 0 { + // If at least one of a and b is positive, we get the same result comparing + // a and b as signed integers as we would with a fp_ting-point compare. + Some(res) + } else { + // Otherwise, both are negative, so we need to flip the sense of the + // comparison to get the correct result. + Some(res.reverse()) + } + } +} +impl fmt::Display for f8 { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + unimplemented!() + } +} + +impl fmt::Debug for f8 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Binary::fmt(self, f) + } +} + +impl fmt::Binary for f8 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let v = self.0; + write!( + f, + "0b{:b}_{:04b}_{:03b}", + v >> 7, + (v & Self::EXP_MASK) >> Self::SIG_BITS, + v & Self::SIG_MASK + ) + } +} + +impl fmt::LowerHex for f8 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 17a06b3be3a2d..ed7131713d52d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -1,3 +1,6 @@ +#![allow(clippy::unusual_byte_groupings)] // sometimes we group by sign_exp_sig + +mod f8_impl; pub mod gen; #[cfg(feature = "test-multiprecision")] pub mod mpfloat; @@ -5,6 +8,7 @@ pub mod op; mod precision; mod test_traits; +pub use f8_impl::f8; pub use libm::support::{Float, Int, IntTy}; pub use op::{BaseName, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet}; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; From 163ed2a133c36d42f67bcf09696057037dcbff5a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 19 Dec 2024 15:10:35 +0000 Subject: [PATCH 1472/4206] Introduce a float extension trait and some numerical routines --- .../libm/crates/libm-test/src/lib.rs | 4 +- .../libm/crates/libm-test/src/num.rs | 458 ++++++++++++++++++ 2 files changed, 461 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/num.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index ed7131713d52d..48b382d20c1cf 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -4,12 +4,14 @@ mod f8_impl; pub mod gen; #[cfg(feature = "test-multiprecision")] pub mod mpfloat; +mod num; pub mod op; mod precision; mod test_traits; pub use f8_impl::f8; -pub use libm::support::{Float, Int, IntTy}; +pub use libm::support::{Float, Int, IntTy, MinInt}; +pub use num::{FloatExt, logspace}; pub use op::{BaseName, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet}; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, Hex, TupleCall}; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/num.rs b/library/compiler-builtins/libm/crates/libm-test/src/num.rs new file mode 100644 index 0000000000000..4aa7f61b05a2c --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/num.rs @@ -0,0 +1,458 @@ +//! Helpful numeric operations. + +use std::cmp::min; + +use libm::support::{CastInto, Float}; + +use crate::{Int, MinInt}; + +/// Extension to `libm`'s `Float` trait with methods that are useful for tests but not +/// needed in `libm` itself. +pub trait FloatExt: Float { + /// The minimum subnormal number. + const TINY_BITS: Self::Int = Self::Int::ONE; + + /// Retrieve additional constants for this float type. + fn consts() -> Consts { + Consts::new() + } + + /// Increment by one ULP, saturating at infinity. + fn next_up(self) -> Self { + let bits = self.to_bits(); + if self.is_nan() || bits == Self::INFINITY.to_bits() { + return self; + } + + let abs = self.abs().to_bits(); + let next_bits = if abs == Self::Int::ZERO { + // Next up from 0 is the smallest subnormal + Self::TINY_BITS + } else if bits == abs { + // Positive: counting up is more positive + bits + Self::Int::ONE + } else { + // Negative: counting down is more positive + bits - Self::Int::ONE + }; + Self::from_bits(next_bits) + } + + /// A faster way to effectively call `next_up` `n` times. + fn n_up(self, n: Self::Int) -> Self { + let bits = self.to_bits(); + if self.is_nan() || bits == Self::INFINITY.to_bits() || n == Self::Int::ZERO { + return self; + } + + let abs = self.abs().to_bits(); + let is_positive = bits == abs; + let crosses_zero = !is_positive && n > abs; + let inf_bits = Self::INFINITY.to_bits(); + + let next_bits = if abs == Self::Int::ZERO { + min(n, inf_bits) + } else if crosses_zero { + min(n - abs, inf_bits) + } else if is_positive { + // Positive, counting up is more positive but this may overflow + match bits.checked_add(n) { + Some(v) if v >= inf_bits => inf_bits, + Some(v) => v, + None => inf_bits, + } + } else { + // Negative, counting down is more positive + bits - n + }; + Self::from_bits(next_bits) + } + + /// Decrement by one ULP, saturating at negative infinity. + fn next_down(self) -> Self { + let bits = self.to_bits(); + if self.is_nan() || bits == Self::NEG_INFINITY.to_bits() { + return self; + } + + let abs = self.abs().to_bits(); + let next_bits = if abs == Self::Int::ZERO { + // Next up from 0 is the smallest negative subnormal + Self::TINY_BITS | Self::SIGN_MASK + } else if bits == abs { + // Positive: counting down is more negative + bits - Self::Int::ONE + } else { + // Negative: counting up is more negative + bits + Self::Int::ONE + }; + Self::from_bits(next_bits) + } + + /// A faster way to effectively call `next_down` `n` times. + fn n_down(self, n: Self::Int) -> Self { + let bits = self.to_bits(); + if self.is_nan() || bits == Self::NEG_INFINITY.to_bits() || n == Self::Int::ZERO { + return self; + } + + let abs = self.abs().to_bits(); + let is_positive = bits == abs; + let crosses_zero = is_positive && n > abs; + let inf_bits = Self::INFINITY.to_bits(); + let ninf_bits = Self::NEG_INFINITY.to_bits(); + + let next_bits = if abs == Self::Int::ZERO { + min(n, inf_bits) | Self::SIGN_MASK + } else if crosses_zero { + min(n - abs, inf_bits) | Self::SIGN_MASK + } else if is_positive { + // Positive, counting down is more negative + bits - n + } else { + // Negative, counting up is more negative but this may overflow + match bits.checked_add(n) { + Some(v) if v > ninf_bits => ninf_bits, + Some(v) => v, + None => ninf_bits, + } + }; + Self::from_bits(next_bits) + } +} + +impl FloatExt for F where F: Float {} + +/// Extra constants that are useful for tests. +#[derive(Debug, Clone, Copy)] +pub struct Consts { + /// The default quiet NaN, which is also the minimum quiet NaN. + pub pos_nan: F, + /// The default quiet NaN with negative sign. + pub neg_nan: F, + /// NaN with maximum (unsigned) significand to be a quiet NaN. The significand is saturated. + pub max_qnan: F, + /// NaN with minimum (unsigned) significand to be a signaling NaN. + pub min_snan: F, + /// NaN with maximum (unsigned) significand to be a signaling NaN. + pub max_snan: F, + pub neg_max_qnan: F, + pub neg_min_snan: F, + pub neg_max_snan: F, +} + +impl Consts { + fn new() -> Self { + let top_sigbit_mask = F::Int::ONE << (F::SIG_BITS - 1); + let pos_nan = F::EXP_MASK | top_sigbit_mask; + let max_qnan = F::EXP_MASK | F::SIG_MASK; + let min_snan = F::EXP_MASK | F::Int::ONE; + let max_snan = (F::EXP_MASK | F::SIG_MASK) ^ top_sigbit_mask; + + let neg_nan = pos_nan | F::SIGN_MASK; + let neg_max_qnan = max_qnan | F::SIGN_MASK; + let neg_min_snan = min_snan | F::SIGN_MASK; + let neg_max_snan = max_snan | F::SIGN_MASK; + + Self { + pos_nan: F::from_bits(pos_nan), + neg_nan: F::from_bits(neg_nan), + max_qnan: F::from_bits(max_qnan), + min_snan: F::from_bits(min_snan), + max_snan: F::from_bits(max_snan), + neg_max_qnan: F::from_bits(neg_max_qnan), + neg_min_snan: F::from_bits(neg_min_snan), + neg_max_snan: F::from_bits(neg_max_snan), + } + } + + pub fn iter(self) -> impl Iterator { + // Destructure so we get unused warnings if we forget a list entry. + let Self { + pos_nan, + neg_nan, + max_qnan, + min_snan, + max_snan, + neg_max_qnan, + neg_min_snan, + neg_max_snan, + } = self; + + [pos_nan, neg_nan, max_qnan, min_snan, max_snan, neg_max_qnan, neg_min_snan, neg_max_snan] + .into_iter() + } +} + +/// Return the number of steps between two floats, returning `None` if either input is NaN. +/// +/// This is the number of steps needed for `n_up` or `n_down` to go between values. Infinities +/// are treated the same as those functions (will return the nearest finite value), and only one +/// of `-0` or `+0` is counted. It does not matter which value is greater. +pub fn ulp_between(x: F, y: F) -> Option { + let a = as_ulp_steps(x)?; + let b = as_ulp_steps(y)?; + Some(a.abs_diff(b)) +} + +/// Return the (signed) number of steps from zero to `x`. +fn as_ulp_steps(x: F) -> Option { + let s = x.to_bits_signed(); + let val = if s >= F::SignedInt::ZERO { + // each increment from `s = 0` is one step up from `x = 0.0` + s + } else { + // each increment from `s = F::SignedInt::MIN` is one step down from `x = -0.0` + F::SignedInt::MIN - s + }; + + // If `x` is NaN, return `None` + (!x.is_nan()).then_some(val) +} + +/// An iterator that returns floats with linearly spaced integer representations, which translates +/// to logarithmic spacing of their values. +/// +/// Note that this tends to skip negative zero, so that needs to be checked explicitly. +pub fn logspace(start: F, end: F, steps: F::Int) -> impl Iterator { + assert!(!start.is_nan()); + assert!(!end.is_nan()); + assert!(end >= start); + + let mut steps = steps.checked_sub(F::Int::ONE).expect("`steps` must be at least 2"); + let between = ulp_between(start, end).expect("`start` or `end` is NaN"); + let spacing = (between / steps).max(F::Int::ONE); + steps = steps.min(between); // At maximum, one step per ULP + + let mut x = start; + (0..=steps.cast()).map(move |_| { + let ret = x; + x = x.n_up(spacing); + ret + }) +} + +#[cfg(test)] +mod tests { + use std::cmp::max; + + use super::*; + use crate::f8; + + #[test] + fn test_next_up_down() { + for (i, v) in f8::ALL.into_iter().enumerate() { + let down = v.next_down().to_bits(); + let up = v.next_up().to_bits(); + + if i == 0 { + assert_eq!(down, f8::NEG_INFINITY.to_bits(), "{i} next_down({v:#010b})"); + } else { + let expected = + if v == f8::ZERO { 1 | f8::SIGN_MASK } else { f8::ALL[i - 1].to_bits() }; + assert_eq!(down, expected, "{i} next_down({v:#010b})"); + } + + if i == f8::ALL_LEN - 1 { + assert_eq!(up, f8::INFINITY.to_bits(), "{i} next_up({v:#010b})"); + } else { + let expected = if v == f8::NEG_ZERO { 1 } else { f8::ALL[i + 1].to_bits() }; + assert_eq!(up, expected, "{i} next_up({v:#010b})"); + } + } + } + + #[test] + fn test_next_up_down_inf_nan() { + assert_eq!(f8::NEG_INFINITY.next_up().to_bits(), f8::ALL[0].to_bits(),); + assert_eq!(f8::NEG_INFINITY.next_down().to_bits(), f8::NEG_INFINITY.to_bits(),); + assert_eq!(f8::INFINITY.next_down().to_bits(), f8::ALL[f8::ALL_LEN - 1].to_bits(),); + assert_eq!(f8::INFINITY.next_up().to_bits(), f8::INFINITY.to_bits(),); + assert_eq!(f8::NAN.next_up().to_bits(), f8::NAN.to_bits(),); + assert_eq!(f8::NAN.next_down().to_bits(), f8::NAN.to_bits(),); + } + + #[test] + fn test_n_up_down_quick() { + assert_eq!(f8::ALL[0].n_up(4).to_bits(), f8::ALL[4].to_bits(),); + assert_eq!( + f8::ALL[f8::ALL_LEN - 1].n_down(4).to_bits(), + f8::ALL[f8::ALL_LEN - 5].to_bits(), + ); + + // Check around zero + assert_eq!(f8::from_bits(0b0).n_up(7).to_bits(), 0b0_0000_111); + assert_eq!(f8::from_bits(0b0).n_down(7).to_bits(), 0b1_0000_111); + + // Check across zero + assert_eq!(f8::from_bits(0b1_0000_111).n_up(8).to_bits(), 0b0_0000_001); + assert_eq!(f8::from_bits(0b0_0000_111).n_down(8).to_bits(), 0b1_0000_001); + } + + #[test] + fn test_n_up_down_one() { + // Verify that `n_up(1)` and `n_down(1)` are the same as `next_up()` and next_down()`.` + for i in 0..u8::MAX { + let v = f8::from_bits(i); + assert_eq!(v.next_up().to_bits(), v.n_up(1).to_bits()); + assert_eq!(v.next_down().to_bits(), v.n_down(1).to_bits()); + } + } + + #[test] + fn test_n_up_down_inf_nan_zero() { + assert_eq!(f8::NEG_INFINITY.n_up(1).to_bits(), f8::ALL[0].to_bits()); + assert_eq!(f8::NEG_INFINITY.n_up(239).to_bits(), f8::ALL[f8::ALL_LEN - 1].to_bits()); + assert_eq!(f8::NEG_INFINITY.n_up(240).to_bits(), f8::INFINITY.to_bits()); + assert_eq!(f8::NEG_INFINITY.n_down(u8::MAX).to_bits(), f8::NEG_INFINITY.to_bits()); + + assert_eq!(f8::INFINITY.n_down(1).to_bits(), f8::ALL[f8::ALL_LEN - 1].to_bits()); + assert_eq!(f8::INFINITY.n_down(239).to_bits(), f8::ALL[0].to_bits()); + assert_eq!(f8::INFINITY.n_down(240).to_bits(), f8::NEG_INFINITY.to_bits()); + assert_eq!(f8::INFINITY.n_up(u8::MAX).to_bits(), f8::INFINITY.to_bits()); + + assert_eq!(f8::NAN.n_up(u8::MAX).to_bits(), f8::NAN.to_bits()); + assert_eq!(f8::NAN.n_down(u8::MAX).to_bits(), f8::NAN.to_bits()); + + assert_eq!(f8::ZERO.n_down(1).to_bits(), f8::TINY_BITS | f8::SIGN_MASK); + assert_eq!(f8::NEG_ZERO.n_up(1).to_bits(), f8::TINY_BITS); + } + + /// True if the specified range of `f8::ALL` includes both +0 and -0 + fn crossed_zero(start: usize, end: usize) -> bool { + let crossed = &f8::ALL[start..=end]; + crossed.iter().any(|f| f8::eq_repr(*f, f8::ZERO)) + && crossed.iter().any(|f| f8::eq_repr(*f, f8::NEG_ZERO)) + } + + #[test] + fn test_n_up_down() { + for (i, v) in f8::ALL.into_iter().enumerate() { + for n in 0..f8::ALL_LEN { + let down = v.n_down(n as u8).to_bits(); + let up = v.n_up(n as u8).to_bits(); + + if let Some(down_exp_idx) = i.checked_sub(n) { + // No overflow + let mut expected = f8::ALL[down_exp_idx].to_bits(); + if n >= 1 && crossed_zero(down_exp_idx, i) { + // If both -0 and +0 are included, we need to adjust our expected value + match down_exp_idx.checked_sub(1) { + Some(v) => expected = f8::ALL[v].to_bits(), + // Saturate to -inf if we are out of values + None => expected = f8::NEG_INFINITY.to_bits(), + } + } + assert_eq!(down, expected, "{i} {n} n_down({v:#010b})"); + } else { + // Overflow to -inf + assert_eq!(down, f8::NEG_INFINITY.to_bits(), "{i} {n} n_down({v:#010b})"); + } + + let mut up_exp_idx = i + n; + if up_exp_idx < f8::ALL_LEN { + // No overflow + if n >= 1 && up_exp_idx < f8::ALL_LEN && crossed_zero(i, up_exp_idx) { + // If both -0 and +0 are included, we need to adjust our expected value + up_exp_idx += 1; + } + + let expected = if up_exp_idx >= f8::ALL_LEN { + f8::INFINITY.to_bits() + } else { + f8::ALL[up_exp_idx].to_bits() + }; + + assert_eq!(up, expected, "{i} {n} n_up({v:#010b})"); + } else { + // Overflow to +inf + assert_eq!(up, f8::INFINITY.to_bits(), "{i} {n} n_up({v:#010b})"); + } + } + } + } + + #[test] + fn test_ulp_between() { + for (i, x) in f8::ALL.into_iter().enumerate() { + for (j, y) in f8::ALL.into_iter().enumerate() { + let ulp = ulp_between(x, y).unwrap(); + let make_msg = || format!("i: {i} j: {j} x: {x:b} y: {y:b} ulp {ulp}"); + + let i_low = min(i, j); + let i_hi = max(i, j); + let mut expected = u8::try_from(i_hi - i_low).unwrap(); + if crossed_zero(i_low, i_hi) { + expected -= 1; + } + + assert_eq!(ulp, expected, "{}", make_msg()); + + // Skip if either are zero since `next_{up,down}` will count over it + let either_zero = x == f8::ZERO || y == f8::ZERO; + if x < y && !either_zero { + assert_eq!(x.n_up(ulp).to_bits(), y.to_bits(), "{}", make_msg()); + assert_eq!(y.n_down(ulp).to_bits(), x.to_bits(), "{}", make_msg()); + } else if !either_zero { + assert_eq!(y.n_up(ulp).to_bits(), x.to_bits(), "{}", make_msg()); + assert_eq!(x.n_down(ulp).to_bits(), y.to_bits(), "{}", make_msg()); + } + } + } + } + + #[test] + fn test_ulp_between_inf_nan_zero() { + assert_eq!(ulp_between(f8::NEG_INFINITY, f8::INFINITY).unwrap(), f8::ALL_LEN as u8); + assert_eq!(ulp_between(f8::INFINITY, f8::NEG_INFINITY).unwrap(), f8::ALL_LEN as u8); + assert_eq!( + ulp_between(f8::NEG_INFINITY, f8::ALL[f8::ALL_LEN - 1]).unwrap(), + f8::ALL_LEN as u8 - 1 + ); + assert_eq!(ulp_between(f8::INFINITY, f8::ALL[0]).unwrap(), f8::ALL_LEN as u8 - 1); + + assert_eq!(ulp_between(f8::ZERO, f8::NEG_ZERO).unwrap(), 0); + assert_eq!(ulp_between(f8::NAN, f8::ZERO), None); + assert_eq!(ulp_between(f8::ZERO, f8::NAN), None); + } + + #[test] + fn test_logspace() { + let ls: Vec<_> = logspace(f8::from_bits(0x0), f8::from_bits(0x4), 2).collect(); + let exp = [f8::from_bits(0x0), f8::from_bits(0x4)]; + assert_eq!(ls, exp); + + let ls: Vec<_> = logspace(f8::from_bits(0x0), f8::from_bits(0x4), 3).collect(); + let exp = [f8::from_bits(0x0), f8::from_bits(0x2), f8::from_bits(0x4)]; + assert_eq!(ls, exp); + + // Check that we include all values with no repeats if `steps` exceeds the maximum number + // of steps. + let ls: Vec<_> = logspace(f8::from_bits(0x0), f8::from_bits(0x3), 10).collect(); + let exp = [f8::from_bits(0x0), f8::from_bits(0x1), f8::from_bits(0x2), f8::from_bits(0x3)]; + assert_eq!(ls, exp); + } + + #[test] + fn test_consts() { + let Consts { + pos_nan, + neg_nan, + max_qnan, + min_snan, + max_snan, + neg_max_qnan, + neg_min_snan, + neg_max_snan, + } = f8::consts(); + + assert_eq!(pos_nan.to_bits(), 0b0_1111_100); + assert_eq!(neg_nan.to_bits(), 0b1_1111_100); + assert_eq!(max_qnan.to_bits(), 0b0_1111_111); + assert_eq!(min_snan.to_bits(), 0b0_1111_001); + assert_eq!(max_snan.to_bits(), 0b0_1111_011); + assert_eq!(neg_max_qnan.to_bits(), 0b1_1111_111); + assert_eq!(neg_min_snan.to_bits(), 0b1_1111_001); + assert_eq!(neg_max_snan.to_bits(), 0b1_1111_011); + } +} From a8a2f70ae6d1945be3af8c21a839c1d1df7e0e8e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 19 Dec 2024 11:19:01 +0000 Subject: [PATCH 1473/4206] Add interfaces and tests based on function domains Create a type representing a function's domain and a test that does a logarithmic sweep of points within the domain. --- .../libm/crates/libm-test/src/domain.rs | 186 ++++++++++++++++++ .../libm/crates/libm-test/src/gen.rs | 1 + .../libm-test/src/gen/domain_logspace.rs | 43 ++++ .../libm/crates/libm-test/src/lib.rs | 1 + .../crates/libm-test/tests/multiprecision.rs | 101 +++++++++- 5 files changed, 327 insertions(+), 5 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/domain.rs create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs new file mode 100644 index 0000000000000..43ba21974c85b --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs @@ -0,0 +1,186 @@ +//! Traits and operations related to bounds of a function. + +use std::fmt; +use std::ops::{self, Bound}; + +use crate::Float; + +/// Representation of a function's domain. +#[derive(Clone, Debug)] +pub struct Domain { + /// Start of the region for which a function is defined (ignoring poles). + pub start: Bound, + /// Endof the region for which a function is defined (ignoring poles). + pub end: Bound, + /// Additional points to check closer around. These can be e.g. undefined asymptotes or + /// inflection points. + pub check_points: Option BoxIter>, +} + +type BoxIter = Box>; + +impl Domain { + /// The start of this domain, saturating at negative infinity. + pub fn range_start(&self) -> F { + match self.start { + Bound::Included(v) => v, + Bound::Excluded(v) => v.next_up(), + Bound::Unbounded => F::NEG_INFINITY, + } + } + + /// The end of this domain, saturating at infinity. + pub fn range_end(&self) -> F { + match self.end { + Bound::Included(v) => v, + Bound::Excluded(v) => v.next_down(), + Bound::Unbounded => F::INFINITY, + } + } +} + +impl Domain { + /// x ∈ ℝ + pub const UNBOUNDED: Self = + Self { start: Bound::Unbounded, end: Bound::Unbounded, check_points: None }; + + /// x ∈ ℝ >= 0 + pub const POSITIVE: Self = + Self { start: Bound::Included(F::ZERO), end: Bound::Unbounded, check_points: None }; + + /// x ∈ ℝ > 0 + pub const STRICTLY_POSITIVE: Self = + Self { start: Bound::Excluded(F::ZERO), end: Bound::Unbounded, check_points: None }; + + /// Used for versions of `asin` and `acos`. + pub const INVERSE_TRIG_PERIODIC: Self = Self { + start: Bound::Included(F::NEG_ONE), + end: Bound::Included(F::ONE), + check_points: None, + }; + + /// Domain for `acosh` + pub const ACOSH: Self = + Self { start: Bound::Included(F::ONE), end: Bound::Unbounded, check_points: None }; + + /// Domain for `atanh` + pub const ATANH: Self = Self { + start: Bound::Excluded(F::NEG_ONE), + end: Bound::Excluded(F::ONE), + check_points: None, + }; + + /// Domain for `sin`, `cos`, and `tan` + pub const TRIG: Self = Self { + // TODO + check_points: Some(|| Box::new([-F::PI, -F::FRAC_PI_2, F::FRAC_PI_2, F::PI].into_iter())), + ..Self::UNBOUNDED + }; + + /// Domain for `log` in various bases + pub const LOG: Self = Self::STRICTLY_POSITIVE; + + /// Domain for `log1p` i.e. `log(1 + x)` + pub const LOG1P: Self = + Self { start: Bound::Excluded(F::NEG_ONE), end: Bound::Unbounded, check_points: None }; + + /// Domain for `sqrt` + pub const SQRT: Self = Self::POSITIVE; + + /// Domain for `gamma` + pub const GAMMA: Self = Self { + check_points: Some(|| { + // Negative integers are asymptotes + Box::new((0..u8::MAX).map(|scale| { + let mut base = F::ZERO; + for _ in 0..scale { + base = base - F::ONE; + } + base + })) + }), + // Whether or not gamma is defined for negative numbers is implementation dependent + ..Self::UNBOUNDED + }; + + /// Domain for `loggamma` + pub const LGAMMA: Self = Self::STRICTLY_POSITIVE; +} + +/// Implement on `op::*` types to indicate how they are bounded. +pub trait HasDomain +where + T: Copy + fmt::Debug + ops::Add + ops::Sub + PartialOrd + 'static, +{ + const DOMAIN: Domain; +} + +/// Implement [`HasDomain`] for both the `f32` and `f64` variants of a function. +macro_rules! impl_has_domain { + ($($fn_name:ident => $domain:expr;)*) => { + paste::paste! { + $( + // Implement for f64 functions + impl HasDomain for $crate::op::$fn_name::Routine { + const DOMAIN: Domain = Domain::::$domain; + } + + // Implement for f32 functions + impl HasDomain for $crate::op::[< $fn_name f >]::Routine { + const DOMAIN: Domain = Domain::::$domain; + } + )* + } + }; +} + +// Tie functions together with their domains. +impl_has_domain! { + acos => INVERSE_TRIG_PERIODIC; + acosh => ACOSH; + asin => INVERSE_TRIG_PERIODIC; + asinh => UNBOUNDED; + atan => UNBOUNDED; + atanh => ATANH; + cbrt => UNBOUNDED; + ceil => UNBOUNDED; + cos => TRIG; + cosh => UNBOUNDED; + erf => UNBOUNDED; + exp => UNBOUNDED; + exp10 => UNBOUNDED; + exp2 => UNBOUNDED; + expm1 => UNBOUNDED; + fabs => UNBOUNDED; + floor => UNBOUNDED; + frexp => UNBOUNDED; + ilogb => UNBOUNDED; + j0 => UNBOUNDED; + j1 => UNBOUNDED; + lgamma => LGAMMA; + log => LOG; + log10 => LOG; + log1p => LOG1P; + log2 => LOG; + modf => UNBOUNDED; + rint => UNBOUNDED; + round => UNBOUNDED; + sin => TRIG; + sincos => TRIG; + sinh => UNBOUNDED; + sqrt => SQRT; + tan => TRIG; + tanh => UNBOUNDED; + tgamma => GAMMA; + trunc => UNBOUNDED; +} + +/* Manual implementations, these functions don't follow `foo`->`foof` naming */ + +impl HasDomain for crate::op::lgammaf_r::Routine { + const DOMAIN: Domain = Domain::::LGAMMA; +} + +impl HasDomain for crate::op::lgamma_r::Routine { + const DOMAIN: Domain = Domain::::LGAMMA; +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs index 3e9eca37a6778..e3c88c44a9ebb 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs @@ -1,6 +1,7 @@ //! Different generators that can create random or systematic bit patterns. use crate::GenerateInput; +pub mod domain_logspace; pub mod random; /// Helper type to turn any reusable input into a generator. diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs new file mode 100644 index 0000000000000..e8cdb9d2b91cf --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs @@ -0,0 +1,43 @@ +//! A generator that produces logarithmically spaced values within domain bounds. + +use libm::support::{IntTy, MinInt}; + +use crate::domain::HasDomain; +use crate::op::OpITy; +use crate::{MathOp, logspace}; + +/// Number of tests to run. +// FIXME(ntests): replace this with a more logical algorithm +const NTESTS: usize = { + if cfg!(optimizations_enabled) { + if crate::emulated() + || !cfg!(target_pointer_width = "64") + || cfg!(all(target_arch = "x86_64", target_vendor = "apple")) + { + // Tests are pretty slow on non-64-bit targets, x86 MacOS, and targets that run + // in QEMU. + 100_000 + } else { + 5_000_000 + } + } else { + // Without optimizations just run a quick check + 800 + } +}; + +/// Create a range of logarithmically spaced inputs within a function's domain. +/// +/// This allows us to get reasonably thorough coverage without wasting time on values that are +/// NaN or out of range. Random tests will still cover values that are excluded here. +pub fn get_test_cases() -> impl Iterator +where + Op: MathOp + HasDomain, + IntTy: TryFrom, +{ + let domain = Op::DOMAIN; + let start = domain.range_start(); + let end = domain.range_end(); + let steps = OpITy::::try_from(NTESTS).unwrap_or(OpITy::::MAX); + logspace(start, end, steps).map(|v| (v,)) +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 48b382d20c1cf..622b2dec98caa 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -1,5 +1,6 @@ #![allow(clippy::unusual_byte_groupings)] // sometimes we group by sign_exp_sig +pub mod domain; mod f8_impl; pub mod gen; #[cfg(feature = "test-multiprecision")] diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 0b41fba82e5c4..e643f3c9c2c2c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -2,11 +2,14 @@ #![cfg(feature = "test-multiprecision")] -use libm_test::gen::{CachedInput, random}; +use libm_test::domain::HasDomain; +use libm_test::gen::{CachedInput, domain_logspace, random}; use libm_test::mpfloat::MpOp; -use libm_test::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, TupleCall}; +use libm_test::{ + CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, OpFTy, OpRustFn, OpRustRet, TupleCall, +}; -/// Implement a test against MPFR with random inputs. +/// Test against MPFR with random inputs. macro_rules! mp_rand_tests { ( fn_name: $fn_name:ident, @@ -16,13 +19,14 @@ macro_rules! mp_rand_tests { #[test] $(#[$meta])* fn [< mp_random_ $fn_name >]() { - test_one::(); + test_one_random::(); } } }; } -fn test_one() +/// Test a single routine with random inputs +fn test_one_random() where Op: MathOp + MpOp, CachedInput: GenerateInput, @@ -67,3 +71,90 @@ libm_macros::for_each_function! { nextafterf, ], } + +/// Test against MPFR with generators from a domain. +macro_rules! mp_domain_tests { + ( + fn_name: $fn_name:ident, + attrs: [$($meta:meta)*] + ) => { + paste::paste! { + #[test] + $(#[$meta])* + fn [< mp_logspace_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + domain_test_runner::(domain_logspace::get_test_cases::()); + } + } + }; +} + +/// Test a single routine against domaine-aware inputs. +fn domain_test_runner(cases: impl Iterator) +where + // Complicated generics... + // The operation must take a single float argument (unary only) + Op: MathOp::FTy,)>, + // It must also support multiprecision operations + Op: MpOp, + // And it must have a domain specified + Op: HasDomain, + // The single float argument tuple must be able to call the `RustFn` and return `RustRet` + (OpFTy,): TupleCall, Output = OpRustRet>, +{ + let mut mp_vals = Op::new_mp(); + let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); + + for input in cases { + let mp_res = Op::run(&mut mp_vals, input); + let crate_res = input.call(Op::ROUTINE); + + crate_res.validate(mp_res, input, &ctx).unwrap(); + } +} + +libm_macros::for_each_function! { + callback: mp_domain_tests, + attributes: [], + skip: [ + // Functions with multiple inputs + atan2, + atan2f, + copysign, + copysignf, + fdim, + fdimf, + fma, + fmaf, + fmax, + fmaxf, + fmin, + fminf, + fmod, + fmodf, + hypot, + hypotf, + jn, + jnf, + ldexp, + ldexpf, + nextafter, + nextafterf, + pow, + powf, + remainder, + remainderf, + remquo, + remquof, + scalbn, + scalbnf, + + // FIXME: MPFR tests needed + frexp, + frexpf, + ilogb, + ilogbf, + modf, + modff, + ], +} From 13611a1b7685e4e92b8b1b85449c2a6eb915f382 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 19 Dec 2024 11:22:02 +0000 Subject: [PATCH 1474/4206] Add tests for edge cases Introduce a generator that will tests various points of interest including zeros, infinities, and NaNs. --- .../libm/crates/libm-test/src/domain.rs | 4 +- .../libm/crates/libm-test/src/gen.rs | 1 + .../crates/libm-test/src/gen/edge_cases.rs | 90 +++++++++++++++++++ .../crates/libm-test/tests/multiprecision.rs | 9 +- 4 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs index 43ba21974c85b..9ee8a19b97096 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs @@ -3,7 +3,7 @@ use std::fmt; use std::ops::{self, Bound}; -use crate::Float; +use crate::{Float, FloatExt}; /// Representation of a function's domain. #[derive(Clone, Debug)] @@ -19,7 +19,7 @@ pub struct Domain { type BoxIter = Box>; -impl Domain { +impl Domain { /// The start of this domain, saturating at negative infinity. pub fn range_start(&self) -> F { match self.start { diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs index e3c88c44a9ebb..2d15915d91ae4 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs @@ -2,6 +2,7 @@ use crate::GenerateInput; pub mod domain_logspace; +pub mod edge_cases; pub mod random; /// Helper type to turn any reusable input into a generator. diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs new file mode 100644 index 0000000000000..625e18bc7a831 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs @@ -0,0 +1,90 @@ +//! A generator that checks a handful of cases near infinities, zeros, asymptotes, and NaNs. + +use libm::support::Float; + +use crate::domain::HasDomain; +use crate::{FloatExt, MathOp}; + +/// Number of values near an interesting point to check. +// FIXME(ntests): replace this with a more logical algorithm +const AROUND: usize = 100; + +/// Functions have infinite asymptotes, limit how many we check. +// FIXME(ntests): replace this with a more logical algorithm +const MAX_CHECK_POINTS: usize = 10; + +/// Create a list of values around interesting points (infinities, zeroes, NaNs). +pub fn get_test_cases() -> impl Iterator +where + Op: MathOp + HasDomain, + F: Float, +{ + let mut ret = Vec::new(); + let values = &mut ret; + let domain = Op::DOMAIN; + let domain_start = domain.range_start(); + let domain_end = domain.range_end(); + + // Check near some notable constants + count_up(F::ONE, values); + count_up(F::ZERO, values); + count_up(F::NEG_ONE, values); + count_down(F::ONE, values); + count_down(F::ZERO, values); + count_down(F::NEG_ONE, values); + values.push(F::NEG_ZERO); + + // Check values near the extremes + count_up(F::NEG_INFINITY, values); + count_down(F::INFINITY, values); + count_down(domain_end, values); + count_up(domain_start, values); + count_down(domain_start, values); + count_up(domain_end, values); + count_down(domain_end, values); + + // Check some special values that aren't included in the above ranges + values.push(F::NAN); + values.extend(F::consts().iter()); + + // Check around asymptotes + if let Some(f) = domain.check_points { + let iter = f(); + for x in iter.take(MAX_CHECK_POINTS) { + count_up(x, values); + count_down(x, values); + } + } + + // Some results may overlap so deduplicate the vector to save test cycles. + values.sort_by_key(|x| x.to_bits()); + values.dedup_by_key(|x| x.to_bits()); + + ret.into_iter().map(|v| (v,)) +} + +/// Add `AROUND` values starting at and including `x` and counting up. Uses the smallest possible +/// increments (1 ULP). +fn count_up(mut x: F, values: &mut Vec) { + assert!(!x.is_nan()); + + let mut count = 0; + while x < F::INFINITY && count < AROUND { + values.push(x); + x = x.next_up(); + count += 1; + } +} + +/// Add `AROUND` values starting at and including `x` and counting down. Uses the smallest possible +/// increments (1 ULP). +fn count_down(mut x: F, values: &mut Vec) { + assert!(!x.is_nan()); + + let mut count = 0; + while x > F::NEG_INFINITY && count < AROUND { + values.push(x); + x = x.next_down(); + count += 1; + } +} diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index e643f3c9c2c2c..5255dc1cfd7ef 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -3,7 +3,7 @@ #![cfg(feature = "test-multiprecision")] use libm_test::domain::HasDomain; -use libm_test::gen::{CachedInput, domain_logspace, random}; +use libm_test::gen::{CachedInput, domain_logspace, edge_cases, random}; use libm_test::mpfloat::MpOp; use libm_test::{ CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, OpFTy, OpRustFn, OpRustRet, TupleCall, @@ -79,6 +79,13 @@ macro_rules! mp_domain_tests { attrs: [$($meta:meta)*] ) => { paste::paste! { + #[test] + $(#[$meta])* + fn [< mp_edge_case_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + domain_test_runner::(edge_cases::get_test_cases::()); + } + #[test] $(#[$meta])* fn [< mp_logspace_ $fn_name >]() { From 3c61c560acab44a41836d05b8c68482f3d82cd93 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 19 Dec 2024 14:23:05 +0000 Subject: [PATCH 1475/4206] Update allowed precision to account for new tests --- .../libm/crates/libm-test/src/precision.rs | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index c7f9d9e30118a..b878212faf800 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -41,10 +41,11 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { (Musl, Id::Tgamma) => 20, // Overrides for MPFR + (Mpfr, Id::Acosh) => 4, (Mpfr, Id::Acoshf) => 4, (Mpfr, Id::Asinh | Id::Asinhf) => 2, (Mpfr, Id::Atanh | Id::Atanhf) => 2, - (Mpfr, Id::Exp10 | Id::Exp10f) => 3, + (Mpfr, Id::Exp10 | Id::Exp10f) => 6, (Mpfr, Id::Lgamma | Id::LgammaR | Id::Lgammaf | Id::LgammafR) => 16, (Mpfr, Id::Sinh | Id::Sinhf) => 2, (Mpfr, Id::Tanh | Id::Tanhf) => 2, @@ -105,17 +106,14 @@ impl MaybeOverride<(f32,)> for SpecialCase { _ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - if ctx.basis == CheckBasis::Musl { - if ctx.base_name == BaseName::Expm1 && input.0 > 80.0 && actual.is_infinite() { - // we return infinity but the number is representable - return XFAIL; - } + if ctx.base_name == BaseName::Expm1 && input.0 > 80.0 && actual.is_infinite() { + // we return infinity but the number is representable + return XFAIL; + } - if ctx.base_name == BaseName::Sinh && input.0.abs() > 80.0 && actual.is_nan() { - // we return some NaN that should be real values or infinite - // doesn't seem to happen on x86 - return XFAIL; - } + if ctx.base_name == BaseName::Sinh && input.0.abs() > 80.0 && actual.is_nan() { + // we return some NaN that should be real values or infinite + return XFAIL; } if ctx.base_name == BaseName::Acosh && input.0 < -1.0 { From d86f8bee8b1bfa24a2fb3a08fa36b83810f5ba92 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 19 Dec 2024 11:22:22 +0000 Subject: [PATCH 1476/4206] Add a way to plot the output from generators For visualization, add a simple script for generating scatter plots and a binary (via examples) to plot the inputs given various domains. --- .../crates/libm-test/examples/plot_domains.rs | 105 ++++++++++++ .../crates/libm-test/examples/plot_file.jl | 157 ++++++++++++++++++ 2 files changed, 262 insertions(+) create mode 100644 library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs create mode 100644 library/compiler-builtins/libm/crates/libm-test/examples/plot_file.jl diff --git a/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs b/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs new file mode 100644 index 0000000000000..630a0c2337b9d --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs @@ -0,0 +1,105 @@ +//! Program to write all inputs from a generator to a file, then invoke a Julia script to plot +//! them. Output is in `target/plots`. +//! +//! Requires Julia with the `CairoMakie` dependency. +//! +//! Note that running in release mode by default generates a _lot_ more datapoints, which +//! causes plotting to be extremely slow (some simplification to be done in the script). + +use std::fmt::Write as _; +use std::io::{BufWriter, Write}; +use std::path::Path; +use std::process::Command; +use std::{env, fs}; + +use libm_test::domain::HasDomain; +use libm_test::gen::{domain_logspace, edge_cases}; +use libm_test::{MathOp, op}; + +const JL_PLOT: &str = "examples/plot_file.jl"; + +fn main() { + let manifest_env = env::var("CARGO_MANIFEST_DIR").unwrap(); + let manifest_dir = Path::new(&manifest_env); + let out_dir = manifest_dir.join("../../target/plots"); + if !out_dir.exists() { + fs::create_dir(&out_dir).unwrap(); + } + + let jl_script = manifest_dir.join(JL_PLOT); + let mut config = format!(r#"out_dir = "{}""#, out_dir.display()); + config.write_str("\n\n").unwrap(); + + // Plot a few domains with some functions that use them. + plot_one_operator::(&out_dir, &mut config); + plot_one_operator::(&out_dir, &mut config); + plot_one_operator::(&out_dir, &mut config); + + let config_path = out_dir.join("config.toml"); + fs::write(&config_path, config).unwrap(); + + // The script expects a path to `config.toml` to be passed as its only argument + let mut cmd = Command::new("julia"); + if cfg!(optimizations_enabled) { + cmd.arg("-O3"); + } + cmd.arg(jl_script).arg(config_path); + + println!("launching script... {cmd:?}"); + cmd.status().unwrap(); +} + +/// Run multiple generators for a single operator. +fn plot_one_operator(out_dir: &Path, config: &mut String) +where + Op: MathOp + HasDomain, +{ + plot_one_generator( + out_dir, + Op::BASE_NAME.as_str(), + "logspace", + config, + domain_logspace::get_test_cases::(), + ); + plot_one_generator( + out_dir, + Op::BASE_NAME.as_str(), + "edge_cases", + config, + edge_cases::get_test_cases::(), + ); +} + +/// Plot the output of a single generator. +fn plot_one_generator( + out_dir: &Path, + fn_name: &str, + gen_name: &str, + config: &mut String, + gen: impl Iterator, +) { + let text_file = out_dir.join(format!("input-{fn_name}-{gen_name}.txt")); + + let f = fs::File::create(&text_file).unwrap(); + let mut w = BufWriter::new(f); + let mut count = 0u64; + + for input in gen { + writeln!(w, "{:e}", input.0).unwrap(); + count += 1; + } + + w.flush().unwrap(); + println!("generated {count} inputs for {fn_name}-{gen_name}"); + + writeln!( + config, + r#"[[input]] +function = "{fn_name}" +generator = "{gen_name}" +input_file = "{}" +"#, + text_file.to_str().unwrap() + ) + .unwrap() +} diff --git a/library/compiler-builtins/libm/crates/libm-test/examples/plot_file.jl b/library/compiler-builtins/libm/crates/libm-test/examples/plot_file.jl new file mode 100644 index 0000000000000..14a128303c696 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/examples/plot_file.jl @@ -0,0 +1,157 @@ +"A quick script for plotting a list of floats. + +Takes a path to a TOML file (Julia has builtin TOML support but not JSON) which +specifies a list of source files to plot. Plots are done with both a linear and +a log scale. + +Requires [Makie] (specifically CairoMakie) for plotting. + +[Makie]: https://docs.makie.org/stable/ +" + +using CairoMakie +using TOML + +function main()::Nothing + CairoMakie.activate!(px_per_unit=10) + config_path = ARGS[1] + + cfg = Dict() + open(config_path, "r") do f + cfg = TOML.parse(f) + end + + out_dir = cfg["out_dir"] + for input in cfg["input"] + fn_name = input["function"] + gen_name = input["generator"] + input_file = input["input_file"] + + plot_one(input_file, out_dir, fn_name, gen_name) + end +end + +"Read inputs from a file, create both linear and log plots for one function" +function plot_one( + input_file::String, + out_dir::String, + fn_name::String, + gen_name::String, +)::Nothing + fig = Figure() + + lin_out_file = joinpath(out_dir, "plot-$fn_name-$gen_name.png") + log_out_file = joinpath(out_dir, "plot-$fn_name-$gen_name-log.png") + + # Map string function names to callable functions + if fn_name == "cos" + orig_func = cos + xlims = (-6.0, 6.0) + xlims_log = (-pi * 10, pi * 10) + elseif fn_name == "cbrt" + orig_func = cbrt + xlims = (-2.0, 2.0) + xlims_log = (-1000.0, 1000.0) + elseif fn_name == "sqrt" + orig_func = sqrt + xlims = (-1.1, 6.0) + xlims_log = (-1.1, 5000.0) + else + println("unrecognized function name `$fn_name`; update plot_file.jl") + exit(1) + end + + # Edge cases don't do much beyond +/-1, except for infinity. + if gen_name == "edge_cases" + xlims = (-1.1, 1.1) + xlims_log = (-1.1, 1.1) + end + + # Turn domain errors into NaN + func(x) = map_or(x, orig_func, NaN) + + # Parse a series of X values produced by the generator + inputs = readlines(input_file) + gen_x = map((v) -> parse(Float32, v), inputs) + + do_plot( + fig, gen_x, func, xlims[1], xlims[2], + "$fn_name $gen_name (linear scale)", + lin_out_file, false, + ) + + do_plot( + fig, gen_x, func, xlims_log[1], xlims_log[2], + "$fn_name $gen_name (log scale)", + log_out_file, true, + ) +end + +"Create a single plot" +function do_plot( + fig::Figure, + gen_x::Vector{F}, + func::Function, + xmin::AbstractFloat, + xmax::AbstractFloat, + title::String, + out_file::String, + logscale::Bool, +)::Nothing where F<:AbstractFloat + println("plotting $title") + + # `gen_x` is the values the generator produces. `actual_x` is for plotting a + # continuous function. + input_min = xmin - 1.0 + input_max = xmax + 1.0 + gen_x = filter((v) -> v >= input_min && v <= input_max, gen_x) + markersize = length(gen_x) < 10_000 ? 6.0 : 4.0 + + steps = 10_000 + if logscale + r = LinRange(symlog10(input_min), symlog10(input_max), steps) + actual_x = sympow10.(r) + xscale = Makie.pseudolog10 + else + actual_x = LinRange(input_min, input_max, steps) + xscale = identity + end + + gen_y = @. func(gen_x) + actual_y = @. func(actual_x) + + ax = Axis(fig[1, 1], xscale=xscale, title=title) + + lines!( + ax, actual_x, actual_y, color=(:lightblue, 0.6), + linewidth=6.0, label="true function", + ) + scatter!( + ax, gen_x, gen_y, color=(:darkblue, 0.9), + markersize=markersize, label="checked inputs", + ) + axislegend(ax, position=:rb, framevisible=false) + + save(out_file, fig) + delete!(ax) +end + +"Apply a function, returning the default if there is a domain error" +function map_or( + input::AbstractFloat, + f::Function, + default::Any +)::Union{AbstractFloat,Any} + try + return f(input) + catch + return default + end +end + +# Operations for logarithms that are symmetric about 0 +C = 10 +symlog10(x::Number) = sign(x) * (log10(1 + abs(x)/(10^C))) +sympow10(x::Number) = (10^C) * (10^x - 1) + +main() From 1069346b6dcfac68e3d059bdd79000406b04c95c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Dec 2024 11:22:02 +0000 Subject: [PATCH 1477/4206] Move the macro's input function list to a new module `shared` This will enable us to `include!` the file to access these types in `libm-test`, rather than somehow reproducing the types as part of the macro. Ideally `libm-test` would just `use` the types from `libm-macros` but proc macro crates cannot currently export anything else. This also adjusts naming to closer match the scheme described in `libm_test::op`. --- .../libm/crates/libm-macros/src/enums.rs | 7 +- .../libm/crates/libm-macros/src/lib.rs | 299 +++--------------- .../libm/crates/libm-macros/src/shared.rs | 277 ++++++++++++++++ 3 files changed, 320 insertions(+), 263 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-macros/src/shared.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs b/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs index 1f9fca2ef9e9d..82dedc66ecd97 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs @@ -5,7 +5,7 @@ use quote::quote; use syn::spanned::Spanned; use syn::{Fields, ItemEnum, Variant}; -use crate::{ALL_FUNCTIONS_FLAT, base_name}; +use crate::{ALL_OPERATIONS, base_name}; /// Implement `#[function_enum]`, see documentation in `lib.rs`. pub fn function_enum( @@ -33,7 +33,7 @@ pub fn function_enum( let mut as_str_arms = Vec::new(); let mut base_arms = Vec::new(); - for func in ALL_FUNCTIONS_FLAT.iter() { + for func in ALL_OPERATIONS.iter() { let fn_name = func.name; let ident = Ident::new(&fn_name.to_upper_camel_case(), Span::call_site()); let bname_ident = Ident::new(&base_name(fn_name).to_upper_camel_case(), Span::call_site()); @@ -85,8 +85,7 @@ pub fn base_name_enum( return Err(syn::Error::new(sp.span(), "no attributes expected")); } - let mut base_names: Vec<_> = - ALL_FUNCTIONS_FLAT.iter().map(|func| base_name(func.name)).collect(); + let mut base_names: Vec<_> = ALL_OPERATIONS.iter().map(|func| base_name(func.name)).collect(); base_names.sort_unstable(); base_names.dedup(); diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs index 1e7cd08b908eb..916b539ed58ca 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs @@ -1,270 +1,18 @@ mod enums; mod parse; - -use std::sync::LazyLock; +mod shared; 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 syn::spanned::Spanned; use syn::visit_mut::VisitMut; use syn::{Ident, ItemEnum}; -const ALL_FUNCTIONS: &[(Ty, Signature, Option, &[&str])] = &[ - ( - // `fn(f32) -> f32` - Ty::F32, - Signature { args: &[Ty::F32], returns: &[Ty::F32] }, - None, - &[ - "acosf", "acoshf", "asinf", "asinhf", "atanf", "atanhf", "cbrtf", "ceilf", "cosf", - "coshf", "erff", "exp10f", "exp2f", "expf", "expm1f", "fabsf", "floorf", "j0f", "j1f", - "lgammaf", "log10f", "log1pf", "log2f", "logf", "rintf", "roundf", "sinf", "sinhf", - "sqrtf", "tanf", "tanhf", "tgammaf", "truncf", - ], - ), - ( - // `(f64) -> f64` - Ty::F64, - Signature { args: &[Ty::F64], returns: &[Ty::F64] }, - None, - &[ - "acos", "acosh", "asin", "asinh", "atan", "atanh", "cbrt", "ceil", "cos", "cosh", - "erf", "exp10", "exp2", "exp", "expm1", "fabs", "floor", "j0", "j1", "lgamma", "log10", - "log1p", "log2", "log", "rint", "round", "sin", "sinh", "sqrt", "tan", "tanh", - "tgamma", "trunc", - ], - ), - ( - // `(f32, f32) -> f32` - Ty::F32, - Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32] }, - None, - &[ - "atan2f", - "copysignf", - "fdimf", - "fmaxf", - "fminf", - "fmodf", - "hypotf", - "nextafterf", - "powf", - "remainderf", - ], - ), - ( - // `(f64, f64) -> f64` - Ty::F64, - Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64] }, - None, - &[ - "atan2", - "copysign", - "fdim", - "fmax", - "fmin", - "fmod", - "hypot", - "nextafter", - "pow", - "remainder", - ], - ), - ( - // `(f32, f32, f32) -> f32` - Ty::F32, - Signature { args: &[Ty::F32, Ty::F32, Ty::F32], returns: &[Ty::F32] }, - None, - &["fmaf"], - ), - ( - // `(f64, f64, f64) -> f64` - Ty::F64, - Signature { args: &[Ty::F64, Ty::F64, Ty::F64], returns: &[Ty::F64] }, - None, - &["fma"], - ), - ( - // `(f32) -> i32` - Ty::F32, - Signature { args: &[Ty::F32], returns: &[Ty::I32] }, - None, - &["ilogbf"], - ), - ( - // `(f64) -> i32` - Ty::F64, - Signature { args: &[Ty::F64], returns: &[Ty::I32] }, - None, - &["ilogb"], - ), - ( - // `(i32, f32) -> f32` - Ty::F32, - Signature { args: &[Ty::I32, Ty::F32], returns: &[Ty::F32] }, - None, - &["jnf"], - ), - ( - // `(i32, f64) -> f64` - Ty::F64, - Signature { args: &[Ty::I32, Ty::F64], returns: &[Ty::F64] }, - None, - &["jn"], - ), - ( - // `(f32, i32) -> f32` - Ty::F32, - Signature { args: &[Ty::F32, Ty::I32], returns: &[Ty::F32] }, - None, - &["scalbnf", "ldexpf"], - ), - ( - // `(f64, i64) -> f64` - Ty::F64, - Signature { args: &[Ty::F64, Ty::I32], returns: &[Ty::F64] }, - None, - &["scalbn", "ldexp"], - ), - ( - // `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)` - Ty::F32, - Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] }, - Some(Signature { args: &[Ty::F32, Ty::MutF32], returns: &[Ty::F32] }), - &["modff"], - ), - ( - // `(f64, &mut f64) -> f64` as `(f64) -> (f64, f64)` - Ty::F64, - Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] }, - Some(Signature { args: &[Ty::F64, Ty::MutF64], returns: &[Ty::F64] }), - &["modf"], - ), - ( - // `(f32, &mut c_int) -> f32` as `(f32) -> (f32, i32)` - Ty::F32, - Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::I32] }, - Some(Signature { args: &[Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }), - &["frexpf", "lgammaf_r"], - ), - ( - // `(f64, &mut c_int) -> f64` as `(f64) -> (f64, i32)` - Ty::F64, - Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::I32] }, - Some(Signature { args: &[Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }), - &["frexp", "lgamma_r"], - ), - ( - // `(f32, f32, &mut c_int) -> f32` as `(f32, f32) -> (f32, i32)` - Ty::F32, - Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32, Ty::I32] }, - Some(Signature { args: &[Ty::F32, Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }), - &["remquof"], - ), - ( - // `(f64, f64, &mut c_int) -> f64` as `(f64, f64) -> (f64, i32)` - Ty::F64, - Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64, Ty::I32] }, - Some(Signature { args: &[Ty::F64, Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }), - &["remquo"], - ), - ( - // `(f32, &mut f32, &mut f32)` as `(f32) -> (f32, f32)` - Ty::F32, - Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] }, - Some(Signature { args: &[Ty::F32, Ty::MutF32, Ty::MutF32], returns: &[] }), - &["sincosf"], - ), - ( - // `(f64, &mut f64, &mut f64)` as `(f64) -> (f64, f64)` - Ty::F64, - Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] }, - Some(Signature { args: &[Ty::F64, Ty::MutF64, Ty::MutF64], returns: &[] }), - &["sincos"], - ), -]; - const KNOWN_TYPES: &[&str] = &["FTy", "CFn", "CArgs", "CRet", "RustFn", "RustArgs", "RustRet"]; -/// A type used in a function signature. -#[allow(dead_code)] -#[derive(Debug, Clone, Copy)] -enum Ty { - F16, - F32, - F64, - F128, - I32, - CInt, - MutF16, - MutF32, - MutF64, - MutF128, - MutI32, - MutCInt, -} - -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::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); - } -} - -/// Representation of e.g. `(f32, f32) -> f32` -#[derive(Debug, Clone)] -struct Signature { - args: &'static [Ty], - returns: &'static [Ty], -} - -/// Combined information about a function implementation. -#[derive(Debug, Clone)] -struct FunctionInfo { - name: &'static str, - base_fty: Ty, - /// Function signature for C implementations - c_sig: Signature, - /// Function signature for Rust implementations - rust_sig: Signature, -} - -/// A flat representation of `ALL_FUNCTIONS`. -static ALL_FUNCTIONS_FLAT: LazyLock> = LazyLock::new(|| { - let mut ret = Vec::new(); - - for (base_fty, rust_sig, c_sig, names) in ALL_FUNCTIONS { - for name in *names { - let api = FunctionInfo { - name, - base_fty: *base_fty, - rust_sig: rust_sig.clone(), - c_sig: c_sig.clone().unwrap_or_else(|| rust_sig.clone()), - }; - ret.push(api); - } - } - - ret.sort_by_key(|item| item.name); - ret -}); - /// Populate an enum with a variant representing function. Names are in upper camel case. /// /// Applied to an empty enum. Expects one attribute `#[function_enum(BaseName)]` that provides @@ -382,7 +130,7 @@ pub fn for_each_function(tokens: pm::TokenStream) -> pm::TokenStream { /// Check for any input that is structurally correct but has other problems. /// /// Returns the list of function names that we should expand for. -fn validate(input: &mut StructuredInput) -> syn::Result> { +fn validate(input: &mut StructuredInput) -> syn::Result> { // Collect lists of all functions that are provied as macro inputs in various fields (only, // skip, attributes). let attr_mentions = input @@ -398,7 +146,7 @@ fn validate(input: &mut StructuredInput) -> syn::Result syn::Result syn::Result syn::Result { +fn expand(input: StructuredInput, fn_list: &[&MathOpInfo]) -> syn::Result { let mut out = pm2::TokenStream::new(); let default_ident = Ident::new("_", Span::call_site()); let callback = input.callback; @@ -545,7 +293,7 @@ fn expand(input: StructuredInput, fn_list: &[&FunctionInfo]) -> syn::Result pm2::TokenStream::new(), }; - let base_fty = func.base_fty; + 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; @@ -648,3 +396,36 @@ fn base_name(name: &str) -> &str { .unwrap_or(name), } } + +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::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); + } +} +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/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs new file mode 100644 index 0000000000000..100bcc7ad8cb6 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -0,0 +1,277 @@ +/* List of all functions that is shared between `libm-macros` and `libm-test`. */ + +use std::fmt; +use std::sync::LazyLock; + +const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] = &[ + ( + // `fn(f32) -> f32` + FloatTy::F32, + Signature { args: &[Ty::F32], returns: &[Ty::F32] }, + None, + &[ + "acosf", "acoshf", "asinf", "asinhf", "atanf", "atanhf", "cbrtf", "ceilf", "cosf", + "coshf", "erff", "exp10f", "exp2f", "expf", "expm1f", "fabsf", "floorf", "j0f", "j1f", + "lgammaf", "log10f", "log1pf", "log2f", "logf", "rintf", "roundf", "sinf", "sinhf", + "sqrtf", "tanf", "tanhf", "tgammaf", "truncf", + ], + ), + ( + // `(f64) -> f64` + FloatTy::F64, + Signature { args: &[Ty::F64], returns: &[Ty::F64] }, + None, + &[ + "acos", "acosh", "asin", "asinh", "atan", "atanh", "cbrt", "ceil", "cos", "cosh", + "erf", "exp10", "exp2", "exp", "expm1", "fabs", "floor", "j0", "j1", "lgamma", "log10", + "log1p", "log2", "log", "rint", "round", "sin", "sinh", "sqrt", "tan", "tanh", + "tgamma", "trunc", + ], + ), + ( + // `(f32, f32) -> f32` + FloatTy::F32, + Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32] }, + None, + &[ + "atan2f", + "copysignf", + "fdimf", + "fmaxf", + "fminf", + "fmodf", + "hypotf", + "nextafterf", + "powf", + "remainderf", + ], + ), + ( + // `(f64, f64) -> f64` + FloatTy::F64, + Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64] }, + None, + &[ + "atan2", + "copysign", + "fdim", + "fmax", + "fmin", + "fmod", + "hypot", + "nextafter", + "pow", + "remainder", + ], + ), + ( + // `(f32, f32, f32) -> f32` + FloatTy::F32, + Signature { args: &[Ty::F32, Ty::F32, Ty::F32], returns: &[Ty::F32] }, + None, + &["fmaf"], + ), + ( + // `(f64, f64, f64) -> f64` + FloatTy::F64, + Signature { args: &[Ty::F64, Ty::F64, Ty::F64], returns: &[Ty::F64] }, + None, + &["fma"], + ), + ( + // `(f32) -> i32` + FloatTy::F32, + Signature { args: &[Ty::F32], returns: &[Ty::I32] }, + None, + &["ilogbf"], + ), + ( + // `(f64) -> i32` + FloatTy::F64, + Signature { args: &[Ty::F64], returns: &[Ty::I32] }, + None, + &["ilogb"], + ), + ( + // `(i32, f32) -> f32` + FloatTy::F32, + Signature { args: &[Ty::I32, Ty::F32], returns: &[Ty::F32] }, + None, + &["jnf"], + ), + ( + // `(i32, f64) -> f64` + FloatTy::F64, + Signature { args: &[Ty::I32, Ty::F64], returns: &[Ty::F64] }, + None, + &["jn"], + ), + ( + // `(f32, i32) -> f32` + FloatTy::F32, + Signature { args: &[Ty::F32, Ty::I32], returns: &[Ty::F32] }, + None, + &["scalbnf", "ldexpf"], + ), + ( + // `(f64, i64) -> f64` + FloatTy::F64, + Signature { args: &[Ty::F64, Ty::I32], returns: &[Ty::F64] }, + None, + &["scalbn", "ldexp"], + ), + ( + // `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)` + FloatTy::F32, + Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] }, + Some(Signature { args: &[Ty::F32, Ty::MutF32], returns: &[Ty::F32] }), + &["modff"], + ), + ( + // `(f64, &mut f64) -> f64` as `(f64) -> (f64, f64)` + FloatTy::F64, + Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] }, + Some(Signature { args: &[Ty::F64, Ty::MutF64], returns: &[Ty::F64] }), + &["modf"], + ), + ( + // `(f32, &mut c_int) -> f32` as `(f32) -> (f32, i32)` + FloatTy::F32, + Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::I32] }, + Some(Signature { args: &[Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }), + &["frexpf", "lgammaf_r"], + ), + ( + // `(f64, &mut c_int) -> f64` as `(f64) -> (f64, i32)` + FloatTy::F64, + Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::I32] }, + Some(Signature { args: &[Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }), + &["frexp", "lgamma_r"], + ), + ( + // `(f32, f32, &mut c_int) -> f32` as `(f32, f32) -> (f32, i32)` + FloatTy::F32, + Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32, Ty::I32] }, + Some(Signature { args: &[Ty::F32, Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }), + &["remquof"], + ), + ( + // `(f64, f64, &mut c_int) -> f64` as `(f64, f64) -> (f64, i32)` + FloatTy::F64, + Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64, Ty::I32] }, + Some(Signature { args: &[Ty::F64, Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }), + &["remquo"], + ), + ( + // `(f32, &mut f32, &mut f32)` as `(f32) -> (f32, f32)` + FloatTy::F32, + Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] }, + Some(Signature { args: &[Ty::F32, Ty::MutF32, Ty::MutF32], returns: &[] }), + &["sincosf"], + ), + ( + // `(f64, &mut f64, &mut f64)` as `(f64) -> (f64, f64)` + FloatTy::F64, + Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] }, + Some(Signature { args: &[Ty::F64, Ty::MutF64, Ty::MutF64], returns: &[] }), + &["sincos"], + ), +]; + +/// A type used in a function signature. +#[allow(dead_code)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum Ty { + F16, + F32, + F64, + F128, + I32, + CInt, + MutF16, + MutF32, + MutF64, + MutF128, + MutI32, + MutCInt, +} + +/// A subset of [`Ty`] representing only floats. +#[allow(dead_code)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum FloatTy { + F16, + F32, + F64, + F128, +} + +impl fmt::Display for Ty { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match self { + Ty::F16 => "f16", + Ty::F32 => "f32", + Ty::F64 => "f64", + Ty::F128 => "f128", + Ty::I32 => "i32", + Ty::CInt => "::core::ffi::c_int", + Ty::MutF16 => "&mut f16", + Ty::MutF32 => "&mut f32", + Ty::MutF64 => "&mut f64", + Ty::MutF128 => "&mut f128", + Ty::MutI32 => "&mut i32", + Ty::MutCInt => "&mut ::core::ffi::c_int", + }; + f.write_str(s) + } +} + +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 { + pub args: &'static [Ty], + pub returns: &'static [Ty], +} + +/// Combined information about a function implementation. +#[derive(Debug, Clone)] +pub struct MathOpInfo { + pub name: &'static str, + pub float_ty: FloatTy, + /// Function signature for C implementations + pub c_sig: Signature, + /// Function signature for Rust implementations + pub rust_sig: Signature, +} + +/// A flat representation of `ALL_FUNCTIONS`. +pub static ALL_OPERATIONS: LazyLock> = LazyLock::new(|| { + let mut ret = Vec::new(); + + for (base_fty, rust_sig, c_sig, names) in ALL_OPERATIONS_NESTED { + for name in *names { + let api = MathOpInfo { + name, + float_ty: *base_fty, + rust_sig: rust_sig.clone(), + c_sig: c_sig.clone().unwrap_or_else(|| rust_sig.clone()), + }; + ret.push(api); + } + } + + ret.sort_by_key(|item| item.name); + ret +}); From fc4b88aecd8c044d246e026d0c267a10350e9406 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Dec 2024 11:41:43 +0000 Subject: [PATCH 1478/4206] Include `shared.rs` in `libm_test::op` These types from `libm-macros` provide a way to get information about an operation at runtime, rather than only being encoded in the type system. Include the file and reexport relevant types. --- .../compiler-builtins/libm/crates/libm-test/src/lib.rs | 2 +- library/compiler-builtins/libm/crates/libm-test/src/op.rs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 622b2dec98caa..e3a690678416b 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -13,7 +13,7 @@ mod test_traits; pub use f8_impl::f8; pub use libm::support::{Float, Int, IntTy, MinInt}; pub use num::{FloatExt, logspace}; -pub use op::{BaseName, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet}; +pub use op::{BaseName, FloatTy, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet, Ty}; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, Hex, TupleCall}; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/op.rs b/library/compiler-builtins/libm/crates/libm-test/src/op.rs index bcea31c22b6e6..a2f21d3c19160 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/op.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/op.rs @@ -13,8 +13,16 @@ //! - "Operation" / "Op": Something that relates a routine to a function or is otherwise higher //! level. `Op` is also used as the name for generic parameters since it is terse. +use std::fmt; + +pub use shared::{ALL_OPERATIONS, FloatTy, MathOpInfo, Ty}; + use crate::{CheckOutput, Float, TupleCall}; +mod shared { + include!("../../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, Hash)] From b9ecacf03b7d295f898368216d2c9750b1affe5f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 29 Dec 2024 08:06:53 +0000 Subject: [PATCH 1479/4206] Add new trait implementations for `Identifier` and `BaseName` These allow for more convenient printing, as well as storage in map types. --- .../libm/crates/libm-test/src/op.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/op.rs b/library/compiler-builtins/libm/crates/libm-test/src/op.rs index a2f21d3c19160..e58c28903628e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/op.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/op.rs @@ -25,14 +25,26 @@ mod shared { /// An enum representing each possible symbol name (`sin`, `sinf`, `sinl`, etc). #[libm_macros::function_enum(BaseName)] -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Identifier {} +impl fmt::Display for Identifier { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + /// The name without any type specifier, e.g. `sin` and `sinf` both become `sin`. #[libm_macros::base_name_enum] -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum BaseName {} +impl fmt::Display for BaseName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + /// Attributes ascribed to a `libm` routine including signature, type information, /// and naming. pub trait MathOp { From 6e97fef9c9b340b71e8f5051389ed24185003909 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Dec 2024 11:26:22 +0000 Subject: [PATCH 1480/4206] Add `ALL`, `from_str` and `math_op` to `Identifier` Introduce new API to iterate the function list and associate items with their `MathOp`. --- .../libm/crates/libm-macros/src/enums.rs | 23 +++++++++++++++ .../libm/crates/libm-macros/tests/enum.rs | 29 +++++++++++++++---- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs b/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs index 82dedc66ecd97..864b625eab38f 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs @@ -31,6 +31,7 @@ pub fn function_enum( let enum_name = &item.ident; let mut as_str_arms = Vec::new(); + let mut from_str_arms = Vec::new(); let mut base_arms = Vec::new(); for func in ALL_OPERATIONS.iter() { @@ -40,6 +41,7 @@ pub fn function_enum( // Match arm for `fn as_str(self)` matcher as_str_arms.push(quote! { Self::#ident => #fn_name }); + from_str_arms.push(quote! { #fn_name => Self::#ident }); // Match arm for `fn base_name(self)` matcher base_arms.push(quote! { Self::#ident => #base_enum::#bname_ident }); @@ -50,11 +52,18 @@ pub fn function_enum( item.variants.push(variant); } + let variants = item.variants.iter(); + let res = quote! { // Instantiate the enum #item impl #enum_name { + /// All variants of this enum. + pub const ALL: &[Self] = &[ + #( Self::#variants, )* + ]; + /// The stringified version of this function name. pub const fn as_str(self) -> &'static str { match self { @@ -62,12 +71,26 @@ pub fn function_enum( } } + /// If `s` is the name of a function, return it. + pub fn from_str(s: &str) -> Option { + let ret = match s { + #( #from_str_arms , )* + _ => return None, + }; + Some(ret) + } + /// The base name enum for this function. pub const fn base_name(self) -> #base_enum { match self { #( #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/libm/crates/libm-macros/tests/enum.rs b/library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs index 884b8d8d65189..93e209a0dcc90 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs @@ -1,6 +1,6 @@ #[libm_macros::function_enum(BaseName)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum Function {} +pub enum Identifier {} #[libm_macros::base_name_enum] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -8,12 +8,31 @@ pub enum BaseName {} #[test] fn as_str() { - assert_eq!(Function::Sin.as_str(), "sin"); - assert_eq!(Function::Sinf.as_str(), "sinf"); + assert_eq!(Identifier::Sin.as_str(), "sin"); + assert_eq!(Identifier::Sinf.as_str(), "sinf"); +} + +#[test] +fn from_str() { + assert_eq!(Identifier::from_str("sin").unwrap(), Identifier::Sin); + assert_eq!(Identifier::from_str("sinf").unwrap(), Identifier::Sinf); } #[test] fn basename() { - assert_eq!(Function::Sin.base_name(), BaseName::Sin); - assert_eq!(Function::Sinf.base_name(), BaseName::Sin); + 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; From 86aeee818b4c888279b1feb48161f7d93871ca8f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 26 Dec 2024 07:43:56 +0000 Subject: [PATCH 1481/4206] Move `CheckBasis` and `CheckCtx` to a new `run_cfg` module These are used more places than just test traits, so this new module should be a better home. `run_cfg` will also be expanded in the near future. --- .../libm/crates/libm-test/src/lib.rs | 4 +- .../libm/crates/libm-test/src/run_cfg.rs | 51 +++++++++++++++++++ .../libm/crates/libm-test/src/test_traits.rs | 39 +------------- 3 files changed, 55 insertions(+), 39 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index e3a690678416b..eb457b0ae7bb8 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -8,6 +8,7 @@ pub mod mpfloat; mod num; pub mod op; mod precision; +mod run_cfg; mod test_traits; pub use f8_impl::f8; @@ -15,7 +16,8 @@ pub use libm::support::{Float, Int, IntTy, MinInt}; pub use num::{FloatExt, logspace}; pub use op::{BaseName, FloatTy, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet, Ty}; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; -pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, Hex, TupleCall}; +pub use run_cfg::{CheckBasis, CheckCtx}; +pub use test_traits::{CheckOutput, GenerateInput, Hex, 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/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs new file mode 100644 index 0000000000000..eb7e0e2c1a94e --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -0,0 +1,51 @@ +//! Configuration for how tests get run. + +#![allow(unused)] + +use std::collections::BTreeMap; +use std::env; +use std::sync::LazyLock; + +use crate::{BaseName, FloatTy, Identifier, op}; + +pub const EXTENSIVE_ENV: &str = "LIBM_EXTENSIVE_TESTS"; + +/// Context passed to [`CheckOutput`]. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CheckCtx { + /// Allowed ULP deviation + pub ulp: u32, + pub fn_ident: Identifier, + pub base_name: BaseName, + /// Function name. + pub fn_name: &'static str, + /// Return the unsuffixed version of the function name. + pub base_name_str: &'static str, + /// Source of truth for tests. + pub basis: CheckBasis, +} + +impl CheckCtx { + /// Create a new check context, using the default ULP for the function. + pub fn new(fn_ident: Identifier, basis: CheckBasis) -> Self { + let mut ret = Self { + ulp: 0, + fn_ident, + fn_name: fn_ident.as_str(), + base_name: fn_ident.base_name(), + base_name_str: fn_ident.base_name().as_str(), + basis, + }; + ret.ulp = crate::default_ulp(&ret); + ret + } +} + +/// Possible items to test against +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum CheckBasis { + /// Check against Musl's math sources. + Musl, + /// Check against infinite precision (MPFR). + Mpfr, +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index ca933bbda63ec..6b833dfb5ddb0 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -11,44 +11,7 @@ use std::fmt; use anyhow::{Context, bail, ensure}; -use crate::{BaseName, Float, Identifier, Int, MaybeOverride, SpecialCase, TestResult}; - -/// Context passed to [`CheckOutput`]. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct CheckCtx { - /// Allowed ULP deviation - pub ulp: u32, - pub fn_ident: Identifier, - pub base_name: BaseName, - /// Function name. - pub fn_name: &'static str, - /// Source of truth for tests. - pub basis: CheckBasis, -} - -impl CheckCtx { - /// Create a new check context, using the default ULP for the function. - pub fn new(fn_ident: Identifier, basis: CheckBasis) -> Self { - let mut ret = Self { - ulp: 0, - fn_ident, - fn_name: fn_ident.as_str(), - base_name: fn_ident.base_name(), - basis, - }; - ret.ulp = crate::default_ulp(&ret); - ret - } -} - -/// Possible items to test against -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum CheckBasis { - /// Check against Musl's math sources. - Musl, - /// Check against infinite precision (MPFR). - Mpfr, -} +use crate::{CheckCtx, Float, Int, MaybeOverride, SpecialCase, TestResult}; /// Implement this on types that can generate a sequence of tuples for test input. pub trait GenerateInput { From 7082f9baf72fbcff1a3a824848439bdc4b602f12 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 26 Dec 2024 07:42:13 +0000 Subject: [PATCH 1482/4206] Use `CheckCtx` in more places Rather than passing names or identifiers, just pass `CheckCtx` in a few more places. --- .../libm/crates/libm-test/examples/plot_domains.rs | 14 ++++++++------ .../crates/libm-test/src/gen/domain_logspace.rs | 4 ++-- .../libm/crates/libm-test/src/gen/edge_cases.rs | 4 ++-- .../libm/crates/libm-test/tests/multiprecision.rs | 8 +++++--- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs b/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs index 630a0c2337b9d..62651124535ca 100644 --- a/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs +++ b/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs @@ -14,7 +14,7 @@ use std::{env, fs}; use libm_test::domain::HasDomain; use libm_test::gen::{domain_logspace, edge_cases}; -use libm_test::{MathOp, op}; +use libm_test::{CheckBasis, CheckCtx, MathOp, op}; const JL_PLOT: &str = "examples/plot_file.jl"; @@ -54,30 +54,32 @@ fn plot_one_operator(out_dir: &Path, config: &mut String) where Op: MathOp + HasDomain, { + let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); plot_one_generator( out_dir, - Op::BASE_NAME.as_str(), + &ctx, "logspace", config, - domain_logspace::get_test_cases::(), + domain_logspace::get_test_cases::(&ctx), ); plot_one_generator( out_dir, - Op::BASE_NAME.as_str(), + &ctx, "edge_cases", config, - edge_cases::get_test_cases::(), + edge_cases::get_test_cases::(&ctx), ); } /// Plot the output of a single generator. fn plot_one_generator( out_dir: &Path, - fn_name: &str, + ctx: &CheckCtx, gen_name: &str, config: &mut String, gen: impl Iterator, ) { + let fn_name = ctx.base_name_str; let text_file = out_dir.join(format!("input-{fn_name}-{gen_name}.txt")); let f = fs::File::create(&text_file).unwrap(); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs index e8cdb9d2b91cf..3e69bee34ddea 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs @@ -4,7 +4,7 @@ use libm::support::{IntTy, MinInt}; use crate::domain::HasDomain; use crate::op::OpITy; -use crate::{MathOp, logspace}; +use crate::{CheckCtx, MathOp, logspace}; /// Number of tests to run. // FIXME(ntests): replace this with a more logical algorithm @@ -30,7 +30,7 @@ const NTESTS: usize = { /// /// This allows us to get reasonably thorough coverage without wasting time on values that are /// NaN or out of range. Random tests will still cover values that are excluded here. -pub fn get_test_cases() -> impl Iterator +pub fn get_test_cases(_ctx: &CheckCtx) -> impl Iterator where Op: MathOp + HasDomain, IntTy: TryFrom, diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs index 625e18bc7a831..3387f6c485aee 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs @@ -3,7 +3,7 @@ use libm::support::Float; use crate::domain::HasDomain; -use crate::{FloatExt, MathOp}; +use crate::{CheckCtx, FloatExt, MathOp}; /// Number of values near an interesting point to check. // FIXME(ntests): replace this with a more logical algorithm @@ -14,7 +14,7 @@ const AROUND: usize = 100; const MAX_CHECK_POINTS: usize = 10; /// Create a list of values around interesting points (infinities, zeroes, NaNs). -pub fn get_test_cases() -> impl Iterator +pub fn get_test_cases(_ctx: &CheckCtx) -> impl Iterator where Op: MathOp + HasDomain, F: Float, diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 5255dc1cfd7ef..2675ca0185a16 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -83,21 +83,21 @@ macro_rules! mp_domain_tests { $(#[$meta])* fn [< mp_edge_case_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; - domain_test_runner::(edge_cases::get_test_cases::()); + domain_test_runner::(edge_cases::get_test_cases::); } #[test] $(#[$meta])* fn [< mp_logspace_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; - domain_test_runner::(domain_logspace::get_test_cases::()); + domain_test_runner::(domain_logspace::get_test_cases::); } } }; } /// Test a single routine against domaine-aware inputs. -fn domain_test_runner(cases: impl Iterator) +fn domain_test_runner(gen: impl FnOnce(&CheckCtx) -> I) where // Complicated generics... // The operation must take a single float argument (unary only) @@ -108,9 +108,11 @@ where Op: HasDomain, // The single float argument tuple must be able to call the `RustFn` and return `RustRet` (OpFTy,): TupleCall, Output = OpRustRet>, + I: Iterator, { let mut mp_vals = Op::new_mp(); let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); + let cases = gen(&ctx); for input in cases { let mp_res = Op::run(&mut mp_vals, input); From a93f659d7c3378569da9b6c8ef6a9d963d420dcd Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 29 Dec 2024 09:04:18 +0000 Subject: [PATCH 1483/4206] Don't run `push` CI on anything other than `master` --- library/compiler-builtins/libm/.github/workflows/main.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 93cd541f8385d..83875f3682c62 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -1,5 +1,9 @@ name: CI -on: [push, pull_request] +on: + push: + branches: + - master + pull_request: env: CARGO_TERM_VERBOSE: true From e8c501861a30b45111cb4fed85e184accd75782f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 30 Dec 2024 01:53:29 +0000 Subject: [PATCH 1484/4206] Set the allowed FMA ULP to 0 It is currently getting the default of 1 or 2. Since this operation should always be infinite precision, no deviation is allowed. --- .../compiler-builtins/libm/crates/libm-test/src/precision.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index b878212faf800..058d01c6e4ef9 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -24,6 +24,8 @@ const MP_DEFAULT_ULP: u32 = 1; pub fn default_ulp(ctx: &CheckCtx) -> u32 { match (&ctx.basis, ctx.fn_ident) { // Overrides that apply to either basis + // FMA is expected to be infinite precision. + (_, Id::Fma | Id::Fmaf) => 0, (_, Id::J0 | Id::J0f | Id::J1 | Id::J1f) => { // Results seem very target-dependent if cfg!(target_arch = "x86_64") { 4000 } else { 800_000 } From cf58a7ce90c21093e1f390ab899d29932d17d42c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 30 Dec 2024 05:55:41 +0000 Subject: [PATCH 1485/4206] Remove lossy casting in `logspace` Currently `logspace` does a lossy cast from `F::Int` to `usize`. This could be problematic in the rare cases that this is called with a step count exceeding what is representable in `usize`. Resolve this by instead adding bounds so the float's integer type itself can be iterated. --- .../libm/crates/libm-test/src/gen/domain_logspace.rs | 3 +++ .../compiler-builtins/libm/crates/libm-test/src/num.rs | 10 +++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs index 3e69bee34ddea..5e37170fa1a4d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs @@ -1,5 +1,7 @@ //! A generator that produces logarithmically spaced values within domain bounds. +use std::ops::RangeInclusive; + use libm::support::{IntTy, MinInt}; use crate::domain::HasDomain; @@ -34,6 +36,7 @@ pub fn get_test_cases(_ctx: &CheckCtx) -> impl Iterator where Op: MathOp + HasDomain, IntTy: TryFrom, + RangeInclusive>: Iterator, { let domain = Op::DOMAIN; let start = domain.range_start(); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/num.rs b/library/compiler-builtins/libm/crates/libm-test/src/num.rs index 4aa7f61b05a2c..eff2fbc1fdd24 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/num.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/num.rs @@ -1,8 +1,9 @@ //! Helpful numeric operations. use std::cmp::min; +use std::ops::RangeInclusive; -use libm::support::{CastInto, Float}; +use libm::support::Float; use crate::{Int, MinInt}; @@ -214,7 +215,10 @@ fn as_ulp_steps(x: F) -> Option { /// to logarithmic spacing of their values. /// /// Note that this tends to skip negative zero, so that needs to be checked explicitly. -pub fn logspace(start: F, end: F, steps: F::Int) -> impl Iterator { +pub fn logspace(start: F, end: F, steps: F::Int) -> impl Iterator +where + RangeInclusive: Iterator, +{ assert!(!start.is_nan()); assert!(!end.is_nan()); assert!(end >= start); @@ -225,7 +229,7 @@ pub fn logspace(start: F, end: F, steps: F::Int) -> impl Iterator Date: Sun, 22 Dec 2024 10:14:56 +0000 Subject: [PATCH 1486/4206] Forward the `CI` environment variable when running in Docker We want to be able to adjust our configuration based on whether we are running in CI, propagate this so our tests can use it. --- library/compiler-builtins/libm/ci/run-docker.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh index a040126df8459..d9f29656d7132 100755 --- a/library/compiler-builtins/libm/ci/run-docker.sh +++ b/library/compiler-builtins/libm/ci/run-docker.sh @@ -28,6 +28,7 @@ run() { docker run \ --rm \ --user "$(id -u):$(id -g)" \ + -e CI \ -e RUSTFLAGS \ -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ From ed72c4ec69a132890b782d3c9e44e387d44a5799 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 31 Dec 2024 22:56:36 +0000 Subject: [PATCH 1487/4206] Use `rustdoc` output to create a list of public API Rather than collecting a list of file names in `libm-test/build.rs`, just use a script to parse rustdoc's JSON output. --- .../libm/.github/workflows/main.yml | 4 + .../libm/crates/libm-test/build.rs | 34 ----- .../libm/crates/libm-test/src/lib.rs | 12 +- .../crates/libm-test/tests/check_coverage.rs | 70 ++++++----- .../libm/etc/function-list.txt | 115 +++++++++++++++++ .../libm/etc/update-api-list.py | 117 ++++++++++++++++++ 6 files changed, 283 insertions(+), 69 deletions(-) create mode 100644 library/compiler-builtins/libm/etc/function-list.txt create mode 100755 library/compiler-builtins/libm/etc/update-api-list.py diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 83875f3682c62..0f5becf7305ba 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -96,6 +96,10 @@ jobs: run: ./ci/download-musl.sh shell: bash + - name: Verify API list + if: matrix.os == 'ubuntu-24.04' + run: python3 etc/update-api-list.py --check + # Non-linux tests just use our raw script - name: Run locally if: matrix.os != 'ubuntu-24.04' || contains(matrix.target, 'wasm') diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs index f2cd298baf213..134fb11ceeb6c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/build.rs +++ b/library/compiler-builtins/libm/crates/libm-test/build.rs @@ -1,42 +1,8 @@ -use std::fmt::Write; -use std::fs; - #[path = "../../configure.rs"] mod configure; use configure::Config; fn main() { let cfg = Config::from_env(); - - list_all_tests(&cfg); - configure::emit_test_config(&cfg); } - -/// Create a list of all source files in an array. This can be used for making sure that -/// all functions are tested or otherwise covered in some way. -// FIXME: it would probably be better to use rustdoc JSON output to get public functions. -fn list_all_tests(cfg: &Config) { - let math_src = cfg.manifest_dir.join("../../src/math"); - - let mut files = fs::read_dir(math_src) - .unwrap() - .map(|f| f.unwrap().path()) - .filter(|entry| entry.is_file()) - .map(|f| f.file_stem().unwrap().to_str().unwrap().to_owned()) - .collect::>(); - files.sort(); - - let mut s = "pub const ALL_FUNCTIONS: &[&str] = &[".to_owned(); - for f in files { - if f == "mod" { - // skip mod.rs - continue; - } - write!(s, "\"{f}\",").unwrap(); - } - write!(s, "];").unwrap(); - - let outfile = cfg.out_dir.join("all_files.rs"); - fs::write(outfile, s).unwrap(); -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index eb457b0ae7bb8..fdba0357f7f03 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -23,9 +23,6 @@ pub use test_traits::{CheckOutput, GenerateInput, Hex, TupleCall}; /// propagate. pub type TestResult = Result; -// List of all files present in libm's source -include!(concat!(env!("OUT_DIR"), "/all_files.rs")); - /// True if `EMULATED` is set and nonempty. Used to determine how many iterations to run. pub const fn emulated() -> bool { match option_env!("EMULATED") { @@ -34,3 +31,12 @@ pub const fn emulated() -> bool { Some(_) => true, } } + +/// True if `CI` is set and nonempty. +pub const fn ci() -> bool { + match option_env!("CI") { + Some(s) if s.is_empty() => false, + None => false, + Some(_) => true, + } +} diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs b/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs index b7988660e6623..9f85d64244bf6 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs @@ -1,54 +1,60 @@ //! Ensure that `for_each_function!` isn't missing any symbols. -/// Files in `src/` that do not export a testable symbol. -const ALLOWED_SKIPS: &[&str] = &[ - // Not a generic test function - "fenv", - // Nonpublic functions - "expo2", - "k_cos", - "k_cosf", - "k_expo2", - "k_expo2f", - "k_sin", - "k_sinf", - "k_tan", - "k_tanf", - "rem_pio2", - "rem_pio2_large", - "rem_pio2f", -]; +use std::collections::HashSet; +use std::env; +use std::path::Path; +use std::process::Command; macro_rules! callback { ( fn_name: $name:ident, - extra: [$push_to:ident], + extra: [$set:ident], ) => { - $push_to.push(stringify!($name)); + let name = stringify!($name); + let new = $set.insert(name); + assert!(new, "duplicate function `{name}` in `ALL_OPERATIONS`"); }; } #[test] fn test_for_each_function_all_included() { - let mut included = Vec::new(); - let mut missing = Vec::new(); + let all_functions: HashSet<_> = include_str!("../../../etc/function-list.txt") + .lines() + .filter(|line| !line.starts_with("#")) + .collect(); + + let mut tested = HashSet::new(); libm_macros::for_each_function! { callback: callback, - extra: [included], + extra: [tested], }; - for f in libm_test::ALL_FUNCTIONS { - if !included.contains(f) && !ALLOWED_SKIPS.contains(f) { - missing.push(f) - } - } - - if !missing.is_empty() { + let untested = all_functions.difference(&tested); + if untested.clone().next().is_some() { panic!( - "missing tests for the following: {missing:#?} \ + "missing tests for the following: {untested:#?} \ \nmake sure any new functions are entered in \ - `ALL_FUNCTIONS` (in `libm-macros`)." + `ALL_OPERATIONS` (in `libm-macros`)." ); } + assert_eq!(all_functions, tested); +} + +#[test] +fn ensure_list_updated() { + if libm_test::ci() { + // Most CI tests run in Docker where we don't have Python or Rustdoc, so it's easiest + // to just run the python file directly when it is available. + eprintln!("skipping test; CI runs the python file directly"); + return; + } + + let res = Command::new("python3") + .arg(Path::new(env!("CARGO_MANIFEST_DIR")).join("../../etc/update-api-list.py")) + .arg("--check") + .status() + .unwrap(); + + assert!(res.success(), "May need to run `./etc/update-api-list.py`"); } diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt new file mode 100644 index 0000000000000..51f5b221c26f3 --- /dev/null +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -0,0 +1,115 @@ +# autogenerated by update-api-list.py +acos +acosf +acosh +acoshf +asin +asinf +asinh +asinhf +atan +atan2 +atan2f +atanf +atanh +atanhf +cbrt +cbrtf +ceil +ceilf +copysign +copysignf +cos +cosf +cosh +coshf +erf +erfc +erfcf +erff +exp +exp10 +exp10f +exp2 +exp2f +expf +expm1 +expm1f +fabs +fabsf +fdim +fdimf +floor +floorf +fma +fmaf +fmax +fmaxf +fmin +fminf +fmod +fmodf +frexp +frexpf +hypot +hypotf +ilogb +ilogbf +j0 +j0f +j1 +j1f +jn +jnf +ldexp +ldexpf +lgamma +lgamma_r +lgammaf +lgammaf_r +log +log10 +log10f +log1p +log1pf +log2 +log2f +logf +modf +modff +nextafter +nextafterf +pow +powf +remainder +remainderf +remquo +remquof +rint +rintf +round +roundf +scalbn +scalbnf +sin +sincos +sincosf +sinf +sinh +sinhf +sqrt +sqrtf +tan +tanf +tanh +tanhf +tgamma +tgammaf +trunc +truncf +y0 +y0f +y1 +y1f +yn +ynf diff --git a/library/compiler-builtins/libm/etc/update-api-list.py b/library/compiler-builtins/libm/etc/update-api-list.py new file mode 100755 index 0000000000000..7284a628c6a6d --- /dev/null +++ b/library/compiler-builtins/libm/etc/update-api-list.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 +"""Create a text file listing all public API. This can be used to ensure that all +functions are covered by our macros. +""" + +import json +import subprocess as sp +import sys +import difflib +from pathlib import Path +from typing import Any + +ETC_DIR = Path(__file__).parent + + +def get_rustdoc_json() -> dict[Any, Any]: + """Get rustdoc's JSON output for the `libm` crate.""" + + librs_path = ETC_DIR.joinpath("../src/lib.rs") + j = sp.check_output( + [ + "rustdoc", + librs_path, + "--edition=2021", + "--output-format=json", + "-Zunstable-options", + "-o-", + ], + text=True, + ) + j = json.loads(j) + return j + + +def list_public_functions() -> list[str]: + """Get a list of public functions from rustdoc JSON output. + + Note that this only finds functions that are reexported in `lib.rs`, this will + need to be adjusted if we need to account for functions that are defined there. + """ + names = [] + index: dict[str, dict[str, Any]] = get_rustdoc_json()["index"] + for item in index.values(): + # Find public items + if item["visibility"] != "public": + continue + + # Find only reexports + if "use" not in item["inner"].keys(): + continue + + # Locate the item that is reexported + id = item["inner"]["use"]["id"] + srcitem = index.get(str(id)) + + # External crate + if srcitem is None: + continue + + # Skip if not a function + if "function" not in srcitem["inner"].keys(): + continue + + names.append(srcitem["name"]) + + names.sort() + return names + + +def diff_and_exit(actual: str, expected: str): + """If the two strings are different, print a diff between them and then exit + with an error. + """ + if actual == expected: + print("output matches expected; success") + return + + a = [f"{line}\n" for line in actual.splitlines()] + b = [f"{line}\n" for line in expected.splitlines()] + + diff = difflib.unified_diff(a, b, "actual", "expected") + sys.stdout.writelines(diff) + print("mismatched function list") + exit(1) + + +def main(): + """By default overwrite the file. If `--check` is passed, print a diff instead and + error if the files are different. + """ + match sys.argv: + case [_]: + check = False + case [_, "--check"]: + check = True + case _: + print("unrecognized arguments") + exit(1) + + names = list_public_functions() + output = "# autogenerated by update-api-list.py\n" + for name in names: + output += f"{name}\n" + + out_file = ETC_DIR.joinpath("function-list.txt") + + if check: + with open(out_file, "r") as f: + current = f.read() + diff_and_exit(current, output) + else: + with open(out_file, "w") as f: + f.write(output) + + +if __name__ == "__main__": + main() From e754ecb6d99aa8c76824ac56bb332320e1cf9ac4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 31 Dec 2024 22:57:21 +0000 Subject: [PATCH 1488/4206] Add missing functions to the macro list Now that we are using rustdoc output to locate public functions, the test is indicating a few that were missed since they don't have their own function. Update everything to now include the following routines: * `erfc` * `erfcf` * `y0` * `y0f` * `y1` * `y1f` * `yn` * `ynf` --- .../libm/crates/libm-macros/src/shared.rs | 16 ++++++++-------- .../libm/crates/libm-test/src/domain.rs | 3 +++ .../libm/crates/libm-test/src/gen/random.rs | 6 +++++- .../libm/crates/libm-test/src/mpfloat.rs | 17 ++++++++++++++++- .../libm/crates/libm-test/src/precision.rs | 14 ++++++-------- .../crates/libm-test/tests/multiprecision.rs | 4 +++- .../libm/crates/musl-math-sys/src/lib.rs | 1 + 7 files changed, 42 insertions(+), 19 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index 100bcc7ad8cb6..ef0f188014b79 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -11,9 +11,9 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] None, &[ "acosf", "acoshf", "asinf", "asinhf", "atanf", "atanhf", "cbrtf", "ceilf", "cosf", - "coshf", "erff", "exp10f", "exp2f", "expf", "expm1f", "fabsf", "floorf", "j0f", "j1f", - "lgammaf", "log10f", "log1pf", "log2f", "logf", "rintf", "roundf", "sinf", "sinhf", - "sqrtf", "tanf", "tanhf", "tgammaf", "truncf", + "coshf", "erff", "erfcf", "exp10f", "exp2f", "expf", "expm1f", "fabsf", "floorf", + "j0f", "j1f", "lgammaf", "log10f", "log1pf", "log2f", "logf", "rintf", "roundf", + "sinf", "sinhf", "sqrtf", "tanf", "tanhf", "tgammaf", "truncf", "y0f", "y1f", ], ), ( @@ -23,9 +23,9 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] None, &[ "acos", "acosh", "asin", "asinh", "atan", "atanh", "cbrt", "ceil", "cos", "cosh", - "erf", "exp10", "exp2", "exp", "expm1", "fabs", "floor", "j0", "j1", "lgamma", "log10", - "log1p", "log2", "log", "rint", "round", "sin", "sinh", "sqrt", "tan", "tanh", - "tgamma", "trunc", + "erf", "erfc", "exp10", "exp2", "exp", "expm1", "fabs", "floor", "j0", "j1", "lgamma", + "log10", "log1p", "log2", "log", "rint", "round", "sin", "sinh", "sqrt", "tan", "tanh", + "tgamma", "trunc", "y0", "y1", ], ), ( @@ -97,14 +97,14 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F32, Signature { args: &[Ty::I32, Ty::F32], returns: &[Ty::F32] }, None, - &["jnf"], + &["jnf", "ynf"], ), ( // `(i32, f64) -> f64` FloatTy::F64, Signature { args: &[Ty::I32, Ty::F64], returns: &[Ty::F64] }, None, - &["jn"], + &["jn", "yn"], ), ( // `(f32, i32) -> f32` diff --git a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs index 9ee8a19b97096..7b5a01b968340 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs @@ -147,6 +147,7 @@ impl_has_domain! { cos => TRIG; cosh => UNBOUNDED; erf => UNBOUNDED; + erfc => UNBOUNDED; exp => UNBOUNDED; exp10 => UNBOUNDED; exp2 => UNBOUNDED; @@ -173,6 +174,8 @@ impl_has_domain! { tanh => UNBOUNDED; tgamma => GAMMA; trunc => UNBOUNDED; + y0 => UNBOUNDED; + y1 => UNBOUNDED; } /* Manual implementations, these functions don't follow `foo`->`foof` naming */ diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index 527cd1351422b..4f75da07b898d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -110,6 +110,10 @@ pub fn get_test_cases(ctx: &CheckCtx) -> impl Iterator, { - let inputs = if ctx.base_name == BaseName::Jn { &TEST_CASES_JN } else { &TEST_CASES }; + let inputs = if ctx.base_name == BaseName::Jn || ctx.base_name == BaseName::Yn { + &TEST_CASES_JN + } else { + &TEST_CASES + }; inputs.get_cases() } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 507b077b37cda..28df916bd6129 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -130,7 +130,7 @@ libm_macros::for_each_function! { fabsf, ceilf, copysignf, floorf, rintf, roundf, truncf, fmod, fmodf, frexp, frexpf, ilogb, ilogbf, jn, jnf, ldexp, ldexpf, lgamma_r, lgammaf_r, modf, modff, nextafter, nextafterf, pow,powf, - remquo, remquof, scalbn, scalbnf, sincos, sincosf, + remquo, remquof, scalbn, scalbnf, sincos, sincosf, yn, ynf, ], fn_extra: match MACRO_FN_NAME { // Remap function names that are different between mpfr and libm @@ -266,6 +266,21 @@ macro_rules! impl_op_for_ty { ) } } + + impl MpOp for crate::op::[]::Routine { + type MpTy = (i32, MpFloat); + + fn new_mp() -> Self::MpTy { + (0, new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0 = input.0; + this.1.assign(input.1); + let ord = this.1.yn_round(this.0, Nearest); + prep_retval::(&mut this.1, ord) + } + } } }; } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 058d01c6e4ef9..6d4561c43767f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -26,11 +26,9 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { // Overrides that apply to either basis // FMA is expected to be infinite precision. (_, Id::Fma | Id::Fmaf) => 0, - (_, Id::J0 | Id::J0f | Id::J1 | Id::J1f) => { - // Results seem very target-dependent - if cfg!(target_arch = "x86_64") { 4000 } else { 800_000 } - } - (_, Id::Jn | Id::Jnf) => 1000, + (_, Id::J0 | Id::J0f | Id::J1 | Id::J1f | Id::Y0 | Id::Y0f | Id::Y1 | Id::Y1f) => 800_000, + (_, Id::Jn | Id::Jnf | Id::Yn | Id::Ynf) => 1000, + (_, Id::Erfc | Id::Erfcf) => 4, // Overrides for musl #[cfg(x86_no_sse)] @@ -297,7 +295,7 @@ impl MaybeOverride<(i32, f32)> for SpecialCase { (Musl, _) => bessel_prec_dropoff(input, ulp, ctx), // We return +0.0, MPFR returns -0.0 - (Mpfr, BaseName::Jn) + (Mpfr, BaseName::Jn | BaseName::Yn) if input.1 == f32::NEG_INFINITY && actual == F::ZERO && expected == F::ZERO => { XFAIL @@ -319,7 +317,7 @@ impl MaybeOverride<(i32, f64)> for SpecialCase { (Musl, _) => bessel_prec_dropoff(input, ulp, ctx), // We return +0.0, MPFR returns -0.0 - (Mpfr, BaseName::Jn) + (Mpfr, BaseName::Jn | BaseName::Yn) if input.1 == f64::NEG_INFINITY && actual == F::ZERO && expected == F::ZERO => { XFAIL @@ -336,7 +334,7 @@ fn bessel_prec_dropoff( ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - if ctx.base_name == BaseName::Jn { + if ctx.base_name == BaseName::Jn || ctx.base_name == BaseName::Yn { if input.0 > 4000 { return XFAIL; } else if input.0 > 2000 { diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 2675ca0185a16..4821f74461f31 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -48,7 +48,7 @@ libm_macros::for_each_function! { attributes: [ // Also an assertion failure on i686: at `MPFR_ASSERTN (! mpfr_erangeflag_p ())` #[ignore = "large values are infeasible in MPFR"] - [jn, jnf], + [jn, jnf, yn, ynf], ], skip: [ // FIXME: MPFR tests needed @@ -157,6 +157,8 @@ libm_macros::for_each_function! { remquof, scalbn, scalbnf, + yn, + ynf, // FIXME: MPFR tests needed frexp, diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs b/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs index db352fab8df06..07277ef3e6e22 100644 --- a/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs +++ b/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs @@ -282,5 +282,6 @@ functions! { musl_y0f: y0f(a: f32) -> f32; musl_y1: y1(a: f64) -> f64; musl_y1f: y1f(a: f32) -> f32; + musl_yn: yn(a: c_int, b: f64) -> f64; musl_ynf: ynf(a: c_int, b: f32) -> f32; } From 3fb16fbdbe6bd0953a43797bb275bfa1d39692e2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 2 Jan 2025 21:23:28 +0000 Subject: [PATCH 1489/4206] macros: Always emit `f16_enabled` and `f128_enabled` attributes Once we start addinf `f16` and `f128` routines, we will need to have this cfg for almost all uses of `for_each_function`. Rather than needing to specify this each time, always emit `#[cfg(f16_enabled)]` or `#[cfg(f128_enabled)]` for each function that uses `f16` or `f128`, respectively. --- .../libm/crates/libm-macros/src/lib.rs | 37 +++++++++++++------ .../libm/crates/libm-macros/tests/basic.rs | 10 ++++- .../libm/crates/libm-test/benches/random.rs | 4 ++ .../libm/crates/libm-test/src/lib.rs | 2 + .../libm/crates/libm-test/src/mpfloat.rs | 6 +++ .../libm/crates/libm-test/src/op.rs | 3 ++ .../crates/libm-test/tests/check_coverage.rs | 1 + .../libm-test/tests/compare_built_musl.rs | 4 +- .../crates/libm-test/tests/multiprecision.rs | 10 ++--- 9 files changed, 57 insertions(+), 20 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs index 916b539ed58ca..3cee5385b62ff 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs @@ -79,7 +79,7 @@ pub fn base_name_enum(attributes: pm::TokenStream, tokens: pm::TokenStream) -> p /// // The Rust version's return type (e.g. `(f32, f32)`) /// RustRet: $RustRet:ty, /// // Attributes for the current function, if any -/// attrs: [$($meta:meta)*] +/// attrs: [$($attr:meta),*], /// // Extra tokens passed directly (if any) /// extra: [$extra:ident], /// // Extra function-tokens passed directly (if any) @@ -97,6 +97,9 @@ pub fn base_name_enum(attributes: pm::TokenStream, tokens: pm::TokenStream) -> p /// skip: [sin, cos], /// // Attributes passed as `attrs` for specific functions. For example, here the invocation /// // with `sinf` and that with `cosf` will both get `meta1` and `meta2`, but no others will. +/// // +/// // Note that `f16_enabled` and `f128_enabled` will always get emitted regardless of whether +/// // or not this is specified. /// attributes: [ /// #[meta1] /// #[meta2] @@ -255,16 +258,28 @@ fn expand(input: StructuredInput, fn_list: &[&MathOpInfo]) -> syn::Result { - let meta = attrs - .iter() - .filter(|map| map.names.contains(&fn_name)) - .flat_map(|map| &map.meta); - quote! { attrs: [ #( #meta )* ] } - } - None => pm2::TokenStream::new(), - }; + let mut meta_fields = Vec::new(); + if let Some(attrs) = &input.attributes { + let meta_iter = attrs + .iter() + .filter(|map| map.names.contains(&fn_name)) + .flat_map(|map| &map.meta) + .map(|v| v.into_token_stream()); + + meta_fields.extend(meta_iter); + } + + // Always emit f16 and f128 meta so this doesn't need to be repeated everywhere + if func.rust_sig.args.contains(&Ty::F16) || func.rust_sig.returns.contains(&Ty::F16) { + let ts = quote! { cfg(f16_enabled) }; + meta_fields.push(ts); + } + if func.rust_sig.args.contains(&Ty::F128) || func.rust_sig.returns.contains(&Ty::F128) { + let ts = quote! { cfg(f128_enabled) }; + meta_fields.push(ts); + } + + let meta_field = quote! { attrs: [ #( #meta_fields ),* ], }; // Prepare extra in an `extra: ...` field, running the replacer let extra_field = match input.extra.clone() { diff --git a/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs b/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs index 2eaba04f4c676..0aa417f13c82c 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs @@ -1,3 +1,5 @@ +#![feature(f16)] +#![feature(f128)] // `STATUS_DLL_NOT_FOUND` on i686 MinGW, not worth looking into. #![cfg(not(all(target_arch = "x86", target_os = "windows", target_env = "gnu")))] @@ -11,11 +13,11 @@ macro_rules! basic { RustFn: $RustFn:ty, RustArgs: $RustArgs:ty, RustRet: $RustRet:ty, - attrs: [$($meta:meta)*] + attrs: [$($attr:meta),*], extra: [$($extra_tt:tt)*], fn_extra: $fn_extra:expr, ) => { - $(#[$meta])* + $(#[$attr])* mod $fn_name { #[allow(unused)] type FTy= $FTy; @@ -60,7 +62,9 @@ mod test_basic { macro_rules! basic_no_extra { ( fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], ) => { + $(#[$attr])* mod $fn_name {} }; } @@ -85,7 +89,9 @@ macro_rules! specified_types { fn_name: $fn_name:ident, RustFn: $RustFn:ty, RustArgs: $RustArgs:ty, + attrs: [$($attr:meta),*], ) => { + $(#[$attr])* mod $fn_name { #[allow(unused)] type RustFnTy = $RustFn; diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index b9c39334c1475..06997cd3621e7 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -18,9 +18,11 @@ struct MuslExtra { macro_rules! musl_rand_benches { ( fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], fn_extra: $skip_on_i586:expr, ) => { paste::paste! { + $(#[$attr])* fn [< musl_bench_ $fn_name >](c: &mut Criterion) { type Op = libm_test::op::$fn_name::Routine; @@ -113,9 +115,11 @@ libm_macros::for_each_function! { macro_rules! run_callback { ( fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], extra: [$criterion:ident], ) => { paste::paste! { + $(#[$attr])* [< musl_bench_ $fn_name >](&mut $criterion) } }; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index fdba0357f7f03..97907b2a16077 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -1,3 +1,5 @@ +#![cfg_attr(f16_enabled, feature(f16))] +#![cfg_attr(f128_enabled, feature(f128))] #![allow(clippy::unusual_byte_groupings)] // sometimes we group by sign_exp_sig pub mod domain; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 28df916bd6129..edb4cb962dcf5 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -50,9 +50,11 @@ macro_rules! impl_mp_op { ( fn_name: $fn_name:ident, RustFn: fn($_fty:ty,) -> $_ret:ty, + attrs: [$($attr:meta),*], fn_extra: $fn_name_normalized:expr, ) => { paste::paste! { + $(#[$attr])* impl MpOp for crate::op::$fn_name::Routine { type MpTy = MpFloat; @@ -72,9 +74,11 @@ macro_rules! impl_mp_op { ( fn_name: $fn_name:ident, RustFn: fn($_fty:ty, $_fty2:ty,) -> $_ret:ty, + attrs: [$($attr:meta),*], fn_extra: $fn_name_normalized:expr, ) => { paste::paste! { + $(#[$attr])* impl MpOp for crate::op::$fn_name::Routine { type MpTy = (MpFloat, MpFloat); @@ -95,9 +99,11 @@ macro_rules! impl_mp_op { ( fn_name: $fn_name:ident, RustFn: fn($_fty:ty, $_fty2:ty, $_fty3:ty,) -> $_ret:ty, + attrs: [$($attr:meta),*], fn_extra: $fn_name_normalized:expr, ) => { paste::paste! { + $(#[$attr])* impl MpOp for crate::op::$fn_name::Routine { type MpTy = (MpFloat, MpFloat, MpFloat); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/op.rs b/library/compiler-builtins/libm/crates/libm-test/src/op.rs index e58c28903628e..ee61eb0b84067 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/op.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/op.rs @@ -112,8 +112,11 @@ macro_rules! do_thing { RustFn: $RustFn:ty, RustArgs: $RustArgs:ty, RustRet: $RustRet:ty, + attrs: [$($attr:meta),*], + ) => { paste::paste! { + $(#[$attr])* pub mod $fn_name { use super::*; pub struct Routine; diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs b/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs index 9f85d64244bf6..c23298686fac3 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs @@ -8,6 +8,7 @@ use std::process::Command; macro_rules! callback { ( fn_name: $name:ident, + attrs: [$($attr:meta),*], extra: [$set:ident], ) => { let name = stringify!($name); diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 0022ee03c2104..71f080ab18f8f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -15,11 +15,11 @@ use libm_test::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, TupleC macro_rules! musl_rand_tests { ( fn_name: $fn_name:ident, - attrs: [$($meta:meta)*] + attrs: [$($attr:meta),*], ) => { paste::paste! { #[test] - $(#[$meta])* + $(#[$attr])* fn [< musl_random_ $fn_name >]() { test_one::(musl_math_sys::$fn_name); } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 4821f74461f31..71ff2ff965ff9 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -13,11 +13,11 @@ use libm_test::{ macro_rules! mp_rand_tests { ( fn_name: $fn_name:ident, - attrs: [$($meta:meta)*] + attrs: [$($attr:meta),*], ) => { paste::paste! { #[test] - $(#[$meta])* + $(#[$attr])* fn [< mp_random_ $fn_name >]() { test_one_random::(); } @@ -76,18 +76,18 @@ libm_macros::for_each_function! { macro_rules! mp_domain_tests { ( fn_name: $fn_name:ident, - attrs: [$($meta:meta)*] + attrs: [$($attr:meta),*], ) => { paste::paste! { #[test] - $(#[$meta])* + $(#[$attr])* fn [< mp_edge_case_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; domain_test_runner::(edge_cases::get_test_cases::); } #[test] - $(#[$meta])* + $(#[$attr])* fn [< mp_logspace_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; domain_test_runner::(domain_logspace::get_test_cases::); From a277ec6954384a02be15c3ed6560e4fc9b0c8cfa Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 2 Jan 2025 10:19:54 +0000 Subject: [PATCH 1490/4206] Rename generic `abs` to `fabs` Using the same name as the routines themselves means this will correctly get picked up by the CI job looking for exhaustive tests. --- library/compiler-builtins/libm/src/math/fabs.rs | 2 +- library/compiler-builtins/libm/src/math/fabsf.rs | 2 +- .../libm/src/math/generic/{abs.rs => fabs.rs} | 2 +- library/compiler-builtins/libm/src/math/generic/mod.rs | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) rename library/compiler-builtins/libm/src/math/generic/{abs.rs => fabs.rs} (63%) diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index 2163637e72801..6687fdcc35633 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -9,7 +9,7 @@ pub fn fabs(x: f64) -> f64 { args: x, } - super::generic::abs(x) + super::generic::fabs(x) } #[cfg(test)] diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index ac77c9201ade3..99bb5b5f1c9d5 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -9,7 +9,7 @@ pub fn fabsf(x: f32) -> f32 { args: x, } - super::generic::abs(x) + super::generic::fabs(x) } // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 diff --git a/library/compiler-builtins/libm/src/math/generic/abs.rs b/library/compiler-builtins/libm/src/math/generic/fabs.rs similarity index 63% rename from library/compiler-builtins/libm/src/math/generic/abs.rs rename to library/compiler-builtins/libm/src/math/generic/fabs.rs index 2c9a43c1249a5..f2c7f0f465bc9 100644 --- a/library/compiler-builtins/libm/src/math/generic/abs.rs +++ b/library/compiler-builtins/libm/src/math/generic/fabs.rs @@ -1,6 +1,6 @@ use super::super::Float; /// Absolute value. -pub fn abs(x: F) -> F { +pub fn fabs(x: F) -> F { x.abs() } diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index 1ddd08f0eff97..08524b685e251 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -1,5 +1,5 @@ -mod abs; mod copysign; +mod fabs; -pub use abs::abs; pub use copysign::copysign; +pub use fabs::fabs; From b47d3cc2f8e0b364cbd1288be2e1a856dadc9ec0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 3 Jan 2025 02:53:35 +0000 Subject: [PATCH 1491/4206] Shorten prefixes for float constants Change `SIGNIFICAND_*` to `SIG_*` and `EXPONENT_*` to `EXP_*`. This makes things more consistent with `libm`, and terseness is convenient here since there isn't anything to confuse. --- library/compiler-builtins/src/float/add.rs | 8 +-- library/compiler-builtins/src/float/cmp.rs | 4 +- library/compiler-builtins/src/float/conv.rs | 46 ++++++++-------- library/compiler-builtins/src/float/div.rs | 10 ++-- library/compiler-builtins/src/float/extend.rs | 14 ++--- library/compiler-builtins/src/float/mod.rs | 53 +++++++++---------- library/compiler-builtins/src/float/mul.rs | 14 ++--- library/compiler-builtins/src/float/trunc.rs | 40 +++++++------- .../compiler-builtins/testcrate/src/lib.rs | 34 ++++++------ .../testcrate/tests/float_pow.rs | 4 +- 10 files changed, 111 insertions(+), 116 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index ecb96264a18e8..743cc441b3639 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -13,14 +13,14 @@ where let zero = F::Int::ZERO; let bits = F::BITS.cast(); - let significand_bits = F::SIGNIFICAND_BITS; - let max_exponent = F::EXPONENT_MAX; + let significand_bits = F::SIG_BITS; + let max_exponent = F::EXP_MAX; let implicit_bit = F::IMPLICIT_BIT; - let significand_mask = F::SIGNIFICAND_MASK; + let significand_mask = F::SIG_MASK; let sign_bit = F::SIGN_MASK as F::Int; let abs_mask = sign_bit - one; - let exponent_mask = F::EXPONENT_MASK; + let exponent_mask = F::EXP_MASK; let inf_rep = exponent_mask; let quiet_bit = implicit_bit >> 1; let qnan_rep = exponent_mask | quiet_bit; diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/src/float/cmp.rs index 8b97a0b5ccebf..b9b4d0114b789 100644 --- a/library/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/src/float/cmp.rs @@ -38,7 +38,7 @@ fn cmp(a: F, b: F) -> Result { let sign_bit = F::SIGN_MASK as F::Int; let abs_mask = sign_bit - one; - let exponent_mask = F::EXPONENT_MASK; + let exponent_mask = F::EXP_MASK; let inf_rep = exponent_mask; let a_rep = a.to_bits(); @@ -87,7 +87,7 @@ fn unord(a: F, b: F) -> bool { let sign_bit = F::SIGN_MASK as F::Int; let abs_mask = sign_bit - one; - let exponent_mask = F::EXPONENT_MASK; + let exponent_mask = F::EXP_MASK; let inf_rep = exponent_mask; let a_rep = a.to_bits(); diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 4aea67c915275..40d304719cda4 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -32,7 +32,7 @@ mod int_to_float { /// Usually 1 is subtracted from this function's result, so that a mantissa with the implicit /// bit set can be added back later. fn exp>>(n: u32) -> F::Int { - F::Int::cast_from(F::EXPONENT_BIAS - 1 + I::BITS - n) + F::Int::cast_from(F::EXP_BIAS - 1 + I::BITS - n) } /// Adjust a mantissa with dropped bits to perform correct rounding. @@ -54,17 +54,17 @@ mod int_to_float { /// value to cancel it out. fn repr(e: F::Int, m: F::Int) -> F::Int { // + rather than | so the mantissa can overflow into the exponent - (e << F::SIGNIFICAND_BITS) + m + (e << F::SIG_BITS) + m } /// Shift distance from a left-aligned integer to a smaller float. fn shift_f_lt_i() -> u32 { - (I::BITS - F::BITS) + F::EXPONENT_BITS + (I::BITS - F::BITS) + F::EXP_BITS } /// Shift distance from an integer with `n` leading zeros to a smaller float. fn shift_f_gt_i(n: u32) -> u32 { - F::SIGNIFICAND_BITS - I::BITS + 1 + n + F::SIG_BITS - I::BITS + 1 + n } /// Perform a signed operation as unsigned, then add the sign back. @@ -85,9 +85,9 @@ mod int_to_float { } let n = i.leading_zeros(); // Mantissa with implicit bit set (significant bits) - let m_base = (i << n) >> f32::EXPONENT_BITS; + let m_base = (i << n) >> f32::EXP_BITS; // Bits that will be dropped (insignificant bits) - let adj = (i << n) << (f32::SIGNIFICAND_BITS + 1); + let adj = (i << n) << (f32::SIG_BITS + 1); let m = m_adj::(m_base, adj); let e = exp::(n) - 1; repr::(e, m) @@ -116,7 +116,7 @@ mod int_to_float { let m = (i as u64) << (shift_f_gt_i::(n) - 64); let e = exp::(n) as u64 - 1; // High 64 bits of f128 representation. - let h = (e << (f128::SIGNIFICAND_BITS - 64)) + m; + let h = (e << (f128::SIG_BITS - 64)) + m; // Shift back to the high bits, the rest of the mantissa will always be 0. (h as u128) << 64 @@ -128,8 +128,8 @@ mod int_to_float { // Mantissa with implicit bit set let m_base: u32 = (i_m >> shift_f_lt_i::()) as u32; // The entire lower half of `i` will be truncated (masked portion), plus the - // next `EXPONENT_BITS` bits. - let adj = (i_m >> f32::EXPONENT_BITS | i_m & 0xFFFF) as u32; + // next `EXP_BITS` bits. + let adj = (i_m >> f32::EXP_BITS | i_m & 0xFFFF) as u32; let m = m_adj::(m_base, adj); let e = if i == 0 { 0 } else { exp::(n) - 1 }; repr::(e, m) @@ -141,8 +141,8 @@ mod int_to_float { } let n = i.leading_zeros(); // Mantissa with implicit bit set - let m_base = (i << n) >> f64::EXPONENT_BITS; - let adj = (i << n) << (f64::SIGNIFICAND_BITS + 1); + let m_base = (i << n) >> f64::EXP_BITS; + let adj = (i << n) << (f64::SIG_BITS + 1); let m = m_adj::(m_base, adj); let e = exp::(n) - 1; repr::(e, m) @@ -167,7 +167,7 @@ mod int_to_float { // Within the upper `F::BITS`, everything except for the signifcand // gets truncated - let d1: u32 = (i_m >> (u128::BITS - f32::BITS - f32::SIGNIFICAND_BITS - 1)).cast(); + let d1: u32 = (i_m >> (u128::BITS - f32::BITS - f32::SIG_BITS - 1)).cast(); // The entire rest of `i_m` gets truncated. Zero the upper `F::BITS` then just // check if it is nonzero. @@ -186,8 +186,8 @@ mod int_to_float { // Mantissa with implicit bit set let m_base: u64 = (i_m >> shift_f_lt_i::()) as u64; // The entire lower half of `i` will be truncated (masked portion), plus the - // next `EXPONENT_BITS` bits. - let adj = (i_m >> f64::EXPONENT_BITS | i_m & 0xFFFF_FFFF) as u64; + // next `EXP_BITS` bits. + let adj = (i_m >> f64::EXP_BITS | i_m & 0xFFFF_FFFF) as u64; let m = m_adj::(m_base, adj); let e = if i == 0 { 0 } else { exp::(n) - 1 }; repr::(e, m) @@ -200,8 +200,8 @@ mod int_to_float { } let n = i.leading_zeros(); // Mantissa with implicit bit set - let m_base = (i << n) >> f128::EXPONENT_BITS; - let adj = (i << n) << (f128::SIGNIFICAND_BITS + 1); + let m_base = (i << n) >> f128::EXP_BITS; + let adj = (i << n) << (f128::SIG_BITS + 1); let m = m_adj::(m_base, adj); let e = exp::(n) - 1; repr::(e, m) @@ -362,29 +362,29 @@ where F::Int: CastFrom, u32: CastFrom, { - let int_max_exp = F::EXPONENT_BIAS + I::MAX.ilog2() + 1; - let foobar = F::EXPONENT_BIAS + I::UnsignedInt::BITS - 1; + let int_max_exp = F::EXP_BIAS + I::MAX.ilog2() + 1; + let foobar = F::EXP_BIAS + I::UnsignedInt::BITS - 1; if fbits < F::ONE.to_bits() { // < 0 gets rounded to 0 I::ZERO - } else if fbits < F::Int::cast_from(int_max_exp) << F::SIGNIFICAND_BITS { + } else if fbits < F::Int::cast_from(int_max_exp) << F::SIG_BITS { // >= 1, < integer max let m_base = if I::UnsignedInt::BITS >= F::Int::BITS { - I::UnsignedInt::cast_from(fbits) << (I::BITS - F::SIGNIFICAND_BITS - 1) + I::UnsignedInt::cast_from(fbits) << (I::BITS - F::SIG_BITS - 1) } else { - I::UnsignedInt::cast_from(fbits >> (F::SIGNIFICAND_BITS - I::BITS + 1)) + I::UnsignedInt::cast_from(fbits >> (F::SIG_BITS - I::BITS + 1)) }; // Set the implicit 1-bit. let m: I::UnsignedInt = I::UnsignedInt::ONE << (I::BITS - 1) | m_base; // Shift based on the exponent and bias. - let s: u32 = (foobar) - u32::cast_from(fbits >> F::SIGNIFICAND_BITS); + let s: u32 = (foobar) - u32::cast_from(fbits >> F::SIG_BITS); let unsigned = m >> s; map_inbounds(I::from_unsigned(unsigned)) - } else if fbits <= F::EXPONENT_MASK { + } else if fbits <= F::EXP_MASK { // >= max (incl. inf) out_of_bounds() } else { diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index 4b3f97c35750d..c211fabadda2c 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -105,16 +105,16 @@ where let hw = F::BITS / 2; let lo_mask = F::Int::MAX >> hw; - let significand_bits = F::SIGNIFICAND_BITS; + let significand_bits = F::SIG_BITS; // Saturated exponent, representing infinity - let exponent_sat: F::Int = F::EXPONENT_MAX.cast(); + let exponent_sat: F::Int = F::EXP_MAX.cast(); - let exponent_bias = F::EXPONENT_BIAS; + let exponent_bias = F::EXP_BIAS; let implicit_bit = F::IMPLICIT_BIT; - let significand_mask = F::SIGNIFICAND_MASK; + let significand_mask = F::SIG_MASK; let sign_bit = F::SIGN_MASK; let abs_mask = sign_bit - one; - let exponent_mask = F::EXPONENT_MASK; + let exponent_mask = F::EXP_MASK; let inf_rep = exponent_mask; let quiet_bit = implicit_bit >> 1; let qnan_rep = exponent_mask | quiet_bit; diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index 2ec79070cb80a..a5d69864b1fe9 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -15,19 +15,19 @@ where let src_zero = F::Int::ZERO; let src_one = F::Int::ONE; let src_bits = F::BITS; - let src_sign_bits = F::SIGNIFICAND_BITS; - let src_exp_bias = F::EXPONENT_BIAS; + let src_sign_bits = F::SIG_BITS; + let src_exp_bias = F::EXP_BIAS; let src_min_normal = F::IMPLICIT_BIT; - let src_infinity = F::EXPONENT_MASK; + let src_infinity = F::EXP_MASK; let src_sign_mask = F::SIGN_MASK as F::Int; let src_abs_mask = src_sign_mask - src_one; - let src_qnan = F::SIGNIFICAND_MASK; + let src_qnan = F::SIG_MASK; let src_nan_code = src_qnan - src_one; let dst_bits = R::BITS; - let dst_sign_bits = R::SIGNIFICAND_BITS; - let dst_inf_exp = R::EXPONENT_MAX; - let dst_exp_bias = R::EXPONENT_BIAS; + let dst_sign_bits = R::SIG_BITS; + let dst_inf_exp = R::EXP_MAX; + let dst_exp_bias = R::EXP_BIAS; let dst_min_normal = R::IMPLICIT_BIT; let sign_bits_delta = dst_sign_bits - src_sign_bits; diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index af83986447e1a..9ba447f97e333 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -42,32 +42,32 @@ pub(crate) trait Float: const ZERO: Self; const ONE: Self; - /// The bitwidth of the float type + /// The bitwidth of the float type. const BITS: u32; - /// The bitwidth of the significand - const SIGNIFICAND_BITS: u32; + /// The bitwidth of the significand. + const SIG_BITS: u32; - /// The bitwidth of the exponent - const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1; + /// The bitwidth of the exponent. + const EXP_BITS: u32 = Self::BITS - Self::SIG_BITS - 1; /// The saturated value of the exponent (infinite representation), in the rightmost postiion. - const EXPONENT_MAX: u32 = (1 << Self::EXPONENT_BITS) - 1; + const EXP_MAX: u32 = (1 << Self::EXP_BITS) - 1; - /// The exponent bias value - const EXPONENT_BIAS: u32 = Self::EXPONENT_MAX >> 1; + /// The exponent bias value. + const EXP_BIAS: u32 = Self::EXP_MAX >> 1; - /// A mask for the sign bit + /// A mask for the sign bit. const SIGN_MASK: Self::Int; - /// A mask for the significand - const SIGNIFICAND_MASK: Self::Int; + /// A mask for the significand. + const SIG_MASK: Self::Int; - /// The implicit bit of the float format + /// The implicit bit of the float format. const IMPLICIT_BIT: Self::Int; - /// A mask for the exponent - const EXPONENT_MASK: Self::Int; + /// A mask for the exponent. + const EXP_MASK: Self::Int; /// Returns `self` transmuted to `Self::Int` fn to_bits(self) -> Self::Int; @@ -122,12 +122,12 @@ macro_rules! float_impl { const ONE: Self = 1.0; const BITS: u32 = $bits; - const SIGNIFICAND_BITS: u32 = $significand_bits; + const SIG_BITS: u32 = $significand_bits; const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); - const SIGNIFICAND_MASK: Self::Int = (1 << Self::SIGNIFICAND_BITS) - 1; - const IMPLICIT_BIT: Self::Int = 1 << Self::SIGNIFICAND_BITS; - const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK); + 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() @@ -142,8 +142,7 @@ macro_rules! float_impl { // 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::EXPONENT_MASK == $ty::EXPONENT_MASK - && x.to_bits() & $ty::SIGNIFICAND_MASK != 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 { @@ -159,10 +158,10 @@ macro_rules! float_impl { self.is_sign_negative() } fn exp(self) -> Self::ExpInt { - ((self.to_bits() & Self::EXPONENT_MASK) >> Self::SIGNIFICAND_BITS) as Self::ExpInt + ((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS) as Self::ExpInt } fn frac(self) -> Self::Int { - self.to_bits() & Self::SIGNIFICAND_MASK + self.to_bits() & Self::SIG_MASK } fn imp_frac(self) -> Self::Int { self.frac() | Self::IMPLICIT_BIT @@ -173,21 +172,19 @@ macro_rules! float_impl { fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self { Self::from_bits( ((negative as Self::Int) << (Self::BITS - 1)) - | ((exponent << Self::SIGNIFICAND_BITS) & Self::EXPONENT_MASK) - | (significand & Self::SIGNIFICAND_MASK), + | ((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::EXPONENT_BITS); + 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::EXPONENT_MASK) == Self::Int::ZERO + (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO } } }; diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index 77a271d65a9c8..62895293abbfb 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -13,20 +13,20 @@ where let zero = F::Int::ZERO; let bits = F::BITS; - let significand_bits = F::SIGNIFICAND_BITS; - let max_exponent = F::EXPONENT_MAX; + let significand_bits = F::SIG_BITS; + let max_exponent = F::EXP_MAX; - let exponent_bias = F::EXPONENT_BIAS; + let exponent_bias = F::EXP_BIAS; let implicit_bit = F::IMPLICIT_BIT; - let significand_mask = F::SIGNIFICAND_MASK; - let sign_bit = F::SIGN_MASK as F::Int; + let significand_mask = F::SIG_MASK; + let sign_bit = F::SIGN_MASK; let abs_mask = sign_bit - one; - let exponent_mask = F::EXPONENT_MASK; + let exponent_mask = F::EXP_MASK; let inf_rep = exponent_mask; let quiet_bit = implicit_bit >> 1; let qnan_rep = exponent_mask | quiet_bit; - let exponent_bits = F::EXPONENT_BITS; + let exponent_bits = F::EXP_BITS; let a_rep = a.to_bits(); let b_rep = b.to_bits(); diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index 6fe44f50b9442..c95e9c198e384 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -14,33 +14,33 @@ where let src_zero = F::Int::ZERO; let src_one = F::Int::ONE; let src_bits = F::BITS; - let src_exp_bias = F::EXPONENT_BIAS; + let src_exp_bias = F::EXP_BIAS; let src_min_normal = F::IMPLICIT_BIT; - let src_significand_mask = F::SIGNIFICAND_MASK; - let src_infinity = F::EXPONENT_MASK; + let src_significand_mask = F::SIG_MASK; + let src_infinity = F::EXP_MASK; let src_sign_mask = F::SIGN_MASK; let src_abs_mask = src_sign_mask - src_one; - let round_mask = (src_one << (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS)) - src_one; - let halfway = src_one << (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS - 1); - let src_qnan = src_one << (F::SIGNIFICAND_BITS - 1); + let round_mask = (src_one << (F::SIG_BITS - R::SIG_BITS)) - src_one; + let halfway = src_one << (F::SIG_BITS - R::SIG_BITS - 1); + let src_qnan = src_one << (F::SIG_BITS - 1); let src_nan_code = src_qnan - src_one; let dst_zero = R::Int::ZERO; let dst_one = R::Int::ONE; let dst_bits = R::BITS; - let dst_inf_exp = R::EXPONENT_MAX; - let dst_exp_bias = R::EXPONENT_BIAS; + let dst_inf_exp = R::EXP_MAX; + let dst_exp_bias = R::EXP_BIAS; let underflow_exponent: F::Int = (src_exp_bias + 1 - dst_exp_bias).cast(); let overflow_exponent: F::Int = (src_exp_bias + dst_inf_exp - dst_exp_bias).cast(); - let underflow: F::Int = underflow_exponent << F::SIGNIFICAND_BITS; - let overflow: F::Int = overflow_exponent << F::SIGNIFICAND_BITS; + let underflow: F::Int = underflow_exponent << F::SIG_BITS; + let overflow: F::Int = overflow_exponent << F::SIG_BITS; - let dst_qnan = R::Int::ONE << (R::SIGNIFICAND_BITS - 1); + let dst_qnan = R::Int::ONE << (R::SIG_BITS - 1); let dst_nan_code = dst_qnan - dst_one; - let sign_bits_delta = F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS; + let sign_bits_delta = F::SIG_BITS - R::SIG_BITS; // Break a into a sign and representation of the absolute value. let a_abs = a.to_bits() & src_abs_mask; let sign = a.to_bits() & src_sign_mask; @@ -53,7 +53,7 @@ where abs_result = (a_abs >> sign_bits_delta).cast(); // Cast before shifting to prevent overflow. let bias_diff: R::Int = src_exp_bias.wrapping_sub(dst_exp_bias).cast(); - let tmp = bias_diff << R::SIGNIFICAND_BITS; + let tmp = bias_diff << R::SIG_BITS; abs_result = abs_result.wrapping_sub(tmp); let round_bits = a_abs & round_mask; @@ -70,26 +70,25 @@ where // bit and inserting the (truncated) trailing NaN field. // Cast before shifting to prevent overflow. let dst_inf_exp: R::Int = dst_inf_exp.cast(); - abs_result = dst_inf_exp << R::SIGNIFICAND_BITS; + abs_result = dst_inf_exp << R::SIG_BITS; abs_result |= dst_qnan; - abs_result |= dst_nan_code - & ((a_abs & src_nan_code) >> (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS)).cast(); + abs_result |= dst_nan_code & ((a_abs & src_nan_code) >> (F::SIG_BITS - R::SIG_BITS)).cast(); } else if a_abs >= overflow { // a overflows to infinity. // Cast before shifting to prevent overflow. let dst_inf_exp: R::Int = dst_inf_exp.cast(); - abs_result = dst_inf_exp << R::SIGNIFICAND_BITS; + abs_result = dst_inf_exp << R::SIG_BITS; } else { // a underflows on conversion to the destination type or is an exact // zero. The result may be a denormal or zero. Extract the exponent // to get the shift amount for the denormalization. - let a_exp: u32 = (a_abs >> F::SIGNIFICAND_BITS).cast(); + let a_exp: u32 = (a_abs >> F::SIG_BITS).cast(); let shift = src_exp_bias - dst_exp_bias - a_exp + 1; let significand = (a.to_bits() & src_significand_mask) | src_min_normal; // Right shift by the denormalization amount with sticky. - if shift > F::SIGNIFICAND_BITS { + if shift > F::SIG_BITS { abs_result = dst_zero; } else { let sticky = if (significand << (src_bits - shift)) != src_zero { @@ -98,8 +97,7 @@ where src_zero }; let denormalized_significand: F::Int = significand >> shift | sticky; - abs_result = - (denormalized_significand >> (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS)).cast(); + abs_result = (denormalized_significand >> (F::SIG_BITS - R::SIG_BITS)).cast(); let round_bits = denormalized_significand & round_mask; // Round to nearest if round_bits > halfway { diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index 4154e0fb34f9e..894c2782a45fd 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -178,18 +178,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::EXPONENT_BITS) - F::Int::ONE; - let r0 = (rng32 >> 1) % F::EXPONENT_BITS; - let r1 = (rng32 >> 5) % F::EXPONENT_BITS; + let ones = (F::Int::ONE << F::EXP_BITS) - F::Int::ONE; + 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) } else { let tmp = ones.wrapping_shr(r0); - (tmp.wrapping_shl(r1) | tmp.wrapping_shr(F::EXPONENT_BITS - r1)) & ones + (tmp.wrapping_shl(r1) | tmp.wrapping_shr(F::EXP_BITS - r1)) & ones }; - let mut exp = (f.to_bits() & F::EXPONENT_MASK) >> F::SIGNIFICAND_BITS; + let mut exp = (f.to_bits() & F::EXP_MASK) >> F::SIG_BITS; match (rng32 >> 9) % 4 { 0 => exp |= mask, 1 => exp &= mask, @@ -197,9 +197,9 @@ fn fuzz_float_step(rng: &mut Xoshiro128StarStar, f: &mut F) { } // significand fuzzing - let mut sig = f.to_bits() & F::SIGNIFICAND_MASK; + let mut sig = f.to_bits() & F::SIG_MASK; fuzz_step(rng, &mut sig); - sig &= F::SIGNIFICAND_MASK; + sig &= F::SIG_MASK; *f = F::from_parts(sign, exp, sig); } @@ -209,22 +209,22 @@ macro_rules! float_edge_cases { for exponent in [ F::Int::ZERO, F::Int::ONE, - F::Int::ONE << (F::EXPONENT_BITS / 2), - (F::Int::ONE << (F::EXPONENT_BITS - 1)) - F::Int::ONE, - F::Int::ONE << (F::EXPONENT_BITS - 1), - (F::Int::ONE << (F::EXPONENT_BITS - 1)) + F::Int::ONE, - (F::Int::ONE << F::EXPONENT_BITS) - 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, ] .iter() { for significand in [ F::Int::ZERO, F::Int::ONE, - F::Int::ONE << (F::SIGNIFICAND_BITS / 2), - (F::Int::ONE << (F::SIGNIFICAND_BITS - 1)) - F::Int::ONE, - F::Int::ONE << (F::SIGNIFICAND_BITS - 1), - (F::Int::ONE << (F::SIGNIFICAND_BITS - 1)) + F::Int::ONE, - (F::Int::ONE << F::SIGNIFICAND_BITS) - F::Int::ONE, + F::Int::ONE << (F::SIG_BITS / 2), + (F::Int::ONE << (F::SIG_BITS - 1)) - F::Int::ONE, + F::Int::ONE << (F::SIG_BITS - 1), + (F::Int::ONE << (F::SIG_BITS - 1)) + F::Int::ONE, + (F::Int::ONE << F::SIG_BITS) - F::Int::ONE, ] .iter() { diff --git a/library/compiler-builtins/testcrate/tests/float_pow.rs b/library/compiler-builtins/testcrate/tests/float_pow.rs index d85ee99dfd307..8d86392f535a4 100644 --- a/library/compiler-builtins/testcrate/tests/float_pow.rs +++ b/library/compiler-builtins/testcrate/tests/float_pow.rs @@ -19,8 +19,8 @@ macro_rules! pow { use compiler_builtins::float::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>::SIGNIFICAND_MASK; - let n = (n as <$f as Float>::SignedInt) >> <$f as Float>::SIGNIFICAND_BITS; + let n = y.to_bits() & !<$f as Float>::SIG_MASK; + let n = (n as <$f as Float>::SignedInt) >> <$f as Float>::SIG_BITS; let n = n as i32; let tmp0: $f = x.powi(n); let tmp1: $f = $fn(x, n); From 7065cd0420e3932071e87f23c2b51d1c29179f81 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 3 Jan 2025 02:56:34 +0000 Subject: [PATCH 1492/4206] Rename `EXP_MAX` to `EXP_SAT` "Maximum" is technically correct here with regards to what the bitpattern can represent, but it is not the numeric maximum value of the exponent which has a relationship with the bias. So, replace the maximum terminology with "saturated" to indicate it only means the full bitpattern. This change is more relevant to `libm` than `compiler-builtins`. --- library/compiler-builtins/src/float/add.rs | 2 +- library/compiler-builtins/src/float/div.rs | 2 +- library/compiler-builtins/src/float/extend.rs | 2 +- library/compiler-builtins/src/float/mod.rs | 9 ++++++--- library/compiler-builtins/src/float/mul.rs | 2 +- library/compiler-builtins/src/float/trunc.rs | 2 +- 6 files changed, 11 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 743cc441b3639..004ea3ebca842 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -14,7 +14,7 @@ where let bits = F::BITS.cast(); let significand_bits = F::SIG_BITS; - let max_exponent = F::EXP_MAX; + let max_exponent = F::EXP_SAT; let implicit_bit = F::IMPLICIT_BIT; let significand_mask = F::SIG_MASK; diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index c211fabadda2c..a461397ea90e9 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -107,7 +107,7 @@ where let significand_bits = F::SIG_BITS; // Saturated exponent, representing infinity - let exponent_sat: F::Int = F::EXP_MAX.cast(); + let exponent_sat: F::Int = F::EXP_SAT.cast(); let exponent_bias = F::EXP_BIAS; let implicit_bit = F::IMPLICIT_BIT; diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index a5d69864b1fe9..a1a9b9720a888 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -26,7 +26,7 @@ where let dst_bits = R::BITS; let dst_sign_bits = R::SIG_BITS; - let dst_inf_exp = R::EXP_MAX; + let dst_inf_exp = R::EXP_SAT; let dst_exp_bias = R::EXP_BIAS; let dst_min_normal = R::IMPLICIT_BIT; diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 9ba447f97e333..6ee55950e18e8 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -51,11 +51,14 @@ pub(crate) trait Float: /// The bitwidth of the exponent. const EXP_BITS: u32 = Self::BITS - Self::SIG_BITS - 1; - /// The saturated value of the exponent (infinite representation), in the rightmost postiion. - const EXP_MAX: u32 = (1 << Self::EXP_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_MAX >> 1; + const EXP_BIAS: u32 = Self::EXP_SAT >> 1; /// A mask for the sign bit. const SIGN_MASK: Self::Int; diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index 62895293abbfb..f0f261a284499 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -14,7 +14,7 @@ where let bits = F::BITS; let significand_bits = F::SIG_BITS; - let max_exponent = F::EXP_MAX; + let max_exponent = F::EXP_SAT; let exponent_bias = F::EXP_BIAS; diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index c95e9c198e384..5efeac98e4429 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -29,7 +29,7 @@ where let dst_zero = R::Int::ZERO; let dst_one = R::Int::ONE; let dst_bits = R::BITS; - let dst_inf_exp = R::EXP_MAX; + let dst_inf_exp = R::EXP_SAT; let dst_exp_bias = R::EXP_BIAS; let underflow_exponent: F::Int = (src_exp_bias + 1 - dst_exp_bias).cast(); From 5d60d2a905179a021b90928729e2cc1c16374884 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 3 Jan 2025 03:09:07 +0000 Subject: [PATCH 1493/4206] Fix new `clippy::precedence` errors `clippy::precedence` now applies to bitwise `&` and `|`. Update with all of its suggestions, including a separate elided lifetime suggestion. --- library/compiler-builtins/examples/intrinsics.rs | 2 +- library/compiler-builtins/src/float/add.rs | 8 ++++---- library/compiler-builtins/src/float/conv.rs | 8 ++++---- library/compiler-builtins/src/float/div.rs | 2 +- library/compiler-builtins/src/float/mul.rs | 2 +- library/compiler-builtins/src/float/trunc.rs | 2 +- library/compiler-builtins/src/mem/mod.rs | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index ef7a3d43030d2..e13c0fb1fa28e 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -640,7 +640,7 @@ fn run() { fn something_with_a_dtor(f: &dyn Fn()) { struct A<'a>(&'a (dyn Fn() + 'a)); - impl<'a> Drop for A<'a> { + impl Drop for A<'_> { fn drop(&mut self) { (self.0)(); } diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/src/float/add.rs index 004ea3ebca842..ef04ddc165c58 100644 --- a/library/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/src/float/add.rs @@ -143,9 +143,9 @@ where // If the addition carried up, we need to right-shift the result and // adjust the exponent: - if a_significand & implicit_bit << 4 != MinInt::ZERO { + if a_significand & (implicit_bit << 4) != MinInt::ZERO { let sticky = F::Int::from_bool(a_significand & one != MinInt::ZERO); - a_significand = a_significand >> 1 | sticky; + a_significand = (a_significand >> 1) | sticky; a_exponent += 1; } } @@ -161,7 +161,7 @@ where let shift = (1 - a_exponent).cast(); let sticky = F::Int::from_bool((a_significand << bits.wrapping_sub(shift).cast()) != MinInt::ZERO); - a_significand = a_significand >> shift.cast() | sticky; + a_significand = (a_significand >> shift.cast()) | sticky; a_exponent = 0; } @@ -170,7 +170,7 @@ where let round_guard_sticky: i32 = a_significand_i32 & 0x7; // Shift the significand into place, and mask off the implicit bit. - let mut result = a_significand >> 3 & significand_mask; + let mut result = (a_significand >> 3) & significand_mask; // Insert the exponent and sign. result |= a_exponent.cast() << significand_bits; diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 40d304719cda4..83a181c37d402 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -42,7 +42,7 @@ mod int_to_float { fn m_adj(m_base: F::Int, dropped_bits: F::Int) -> F::Int { // Branchlessly extract a `1` if rounding up should happen, 0 otherwise // This accounts for rounding to even. - let adj = (dropped_bits - (dropped_bits >> (F::BITS - 1) & !m_base)) >> (F::BITS - 1); + let adj = (dropped_bits - ((dropped_bits >> (F::BITS - 1)) & !m_base)) >> (F::BITS - 1); // Add one when we need to round up. Break ties to even. m_base + adj @@ -129,7 +129,7 @@ mod int_to_float { let m_base: u32 = (i_m >> shift_f_lt_i::()) as u32; // The entire lower half of `i` will be truncated (masked portion), plus the // next `EXP_BITS` bits. - let adj = (i_m >> f32::EXP_BITS | i_m & 0xFFFF) as u32; + let adj = ((i_m >> f32::EXP_BITS) | i_m & 0xFFFF) as u32; let m = m_adj::(m_base, adj); let e = if i == 0 { 0 } else { exp::(n) - 1 }; repr::(e, m) @@ -187,7 +187,7 @@ mod int_to_float { let m_base: u64 = (i_m >> shift_f_lt_i::()) as u64; // The entire lower half of `i` will be truncated (masked portion), plus the // next `EXP_BITS` bits. - let adj = (i_m >> f64::EXP_BITS | i_m & 0xFFFF_FFFF) as u64; + let adj = ((i_m >> f64::EXP_BITS) | i_m & 0xFFFF_FFFF) as u64; let m = m_adj::(m_base, adj); let e = if i == 0 { 0 } else { exp::(n) - 1 }; repr::(e, m) @@ -377,7 +377,7 @@ where }; // Set the implicit 1-bit. - let m: I::UnsignedInt = I::UnsignedInt::ONE << (I::BITS - 1) | m_base; + let m: I::UnsignedInt = (I::UnsignedInt::ONE << (I::BITS - 1)) | m_base; // Shift based on the exponent and bias. let s: u32 = (foobar) - u32::cast_from(fbits >> F::SIG_BITS); diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/src/float/div.rs index a461397ea90e9..21c757dd639c2 100644 --- a/library/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/src/float/div.rs @@ -261,7 +261,7 @@ where let c_hw = c_hw::(); // Check that the top bit is set, i.e. value is within `[1, 2)`. - debug_assert!(b_uq1_hw & one_hw << (HalfRep::::BITS - 1) > zero_hw); + debug_assert!(b_uq1_hw & (one_hw << (HalfRep::::BITS - 1)) > zero_hw); // b >= 1, thus an upper bound for 3/4 + 1/sqrt(2) - b/2 is about 0.9572, // so x0 fits to UQ0.HW without wrapping. diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/src/float/mul.rs index f0f261a284499..58636cb5ebeed 100644 --- a/library/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/src/float/mul.rs @@ -154,7 +154,7 @@ where // not all zero so that the result is correctly rounded below. let sticky = product_low << (bits - shift) != zero; product_low = - product_high << (bits - shift) | product_low >> shift | (sticky as u32).cast(); + (product_high << (bits - shift)) | (product_low >> shift) | (sticky as u32).cast(); product_high >>= shift; } else { // Result is normal before rounding; insert the exponent. diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index 5efeac98e4429..3759aa7dc43dd 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -96,7 +96,7 @@ where } else { src_zero }; - let denormalized_significand: F::Int = significand >> shift | sticky; + let denormalized_significand: F::Int = (significand >> shift) | sticky; abs_result = (denormalized_significand >> (F::SIG_BITS - R::SIG_BITS)).cast(); let round_bits = denormalized_significand & round_mask; // Round to nearest diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index d0ff501585b3a..f10439e2d3f14 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -111,7 +111,7 @@ where let mut x = T::from(c); let mut i = 1; while i < mem::size_of::() { - x = x << 8 | T::from(c); + x = (x << 8) | T::from(c); i += 1; } From 14e6d05dfba4ec4cf69d347f4510640ff97419bc Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 3 Jan 2025 12:04:45 +0000 Subject: [PATCH 1494/4206] Use intrinsics for `abs` and `copysign` when available Currently our implementations for `abs` and `copysign` are defined on the trait, and these are then called from `generic`. It would be better to call core's `.abs()` / `.copysign(y)`, but we can't do this in the generic because calling the standalone function could become recursive (`fabsf` becomes `intrinsics::fabsf32`, that may lower to a call to `fabsf`). Change this so the traits uses the call to `core` if available, falling back to a call to the standalone generic function. In practice the recursion isn't likely to be a problem since LLVM probably always lowers `abs`/`copysign` to assembly, but this pattern should be more correct for functions that we will add in the future (e.g. `fma`). This should eventually be followed by a change to call the trait methods rather than `fabs`/`copysign` directly. --- .../libm/crates/libm-test/src/f8_impl.rs | 8 ++++ .../libm/src/math/generic/copysign.rs | 2 +- .../libm/src/math/generic/fabs.rs | 3 +- .../compiler-builtins/libm/src/math/mod.rs | 9 ++++- .../libm/src/math/support/float_traits.rs | 37 ++++++++++++------- 5 files changed, 43 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs index babcc6357a408..d378863f2fd92 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs @@ -70,6 +70,14 @@ impl Float for f8 { Self(a) } + fn abs(self) -> Self { + libm::generic::fabs(self) + } + + fn copysign(self, other: Self) -> Self { + libm::generic::copysign(self, other) + } + fn normalize(_significand: Self::Int) -> (i32, Self::Int) { unimplemented!() } diff --git a/library/compiler-builtins/libm/src/math/generic/copysign.rs b/library/compiler-builtins/libm/src/math/generic/copysign.rs index d6b8148919357..04864a3590567 100644 --- a/library/compiler-builtins/libm/src/math/generic/copysign.rs +++ b/library/compiler-builtins/libm/src/math/generic/copysign.rs @@ -5,6 +5,6 @@ pub fn copysign(x: F, y: F) -> F { let mut ux = x.to_bits(); let uy = y.to_bits(); ux &= !F::SIGN_MASK; - ux |= uy & (F::SIGN_MASK); + ux |= uy & F::SIGN_MASK; F::from_bits(ux) } diff --git a/library/compiler-builtins/libm/src/math/generic/fabs.rs b/library/compiler-builtins/libm/src/math/generic/fabs.rs index f2c7f0f465bc9..75b473107c671 100644 --- a/library/compiler-builtins/libm/src/math/generic/fabs.rs +++ b/library/compiler-builtins/libm/src/math/generic/fabs.rs @@ -2,5 +2,6 @@ use super::super::Float; /// Absolute value. pub fn fabs(x: F) -> F { - x.abs() + let abs_mask = !F::SIGN_MASK; + F::from_bits(x.to_bits() & abs_mask) } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index ba1995228162f..e7b21de67621e 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -83,11 +83,18 @@ pub mod support; #[cfg(not(feature = "unstable-test-support"))] mod support; +cfg_if! { + if #[cfg(feature = "unstable-test-support")] { + pub mod generic; + } else { + mod generic; + } +} + // Private modules mod arch; mod expo2; mod fenv; -mod generic; mod k_cos; mod k_cosf; mod k_expo2; 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 e64640a0d154a..3b5be4fa3d3df 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -123,23 +123,14 @@ pub trait Float: ) } - fn abs(self) -> Self { - let abs_mask = !Self::SIGN_MASK; - Self::from_bits(self.to_bits() & abs_mask) - } + fn abs(self) -> Self; + + /// Returns a number composed of the magnitude of self and the sign of sign. + fn copysign(self, other: Self) -> Self; /// Returns (normalized exponent, normalized significand) fn normalize(significand: Self::Int) -> (i32, Self::Int); - /// Returns a number composed of the magnitude of self and the sign of sign. - fn copysign(self, other: Self) -> Self { - let mut x = self.to_bits(); - let y = other.to_bits(); - x &= !Self::SIGN_MASK; - x |= y & Self::SIGN_MASK; - Self::from_bits(x) - } - /// Returns a number that represents the sign of self. fn signum(self) -> Self { if self.is_nan() { self } else { Self::ONE.copysign(self) } @@ -206,6 +197,26 @@ macro_rules! float_impl { fn from_bits(a: Self::Int) -> Self { Self::from_bits(a) } + fn abs(self) -> Self { + cfg_if! { + // FIXME(msrv): `abs` is available in `core` starting with 1.85. + if #[cfg(feature = "unstable-intrinsics")] { + self.abs() + } else { + super::super::generic::fabs(self) + } + } + } + fn copysign(self, other: Self) -> Self { + cfg_if! { + // FIXME(msrv): `copysign` is available in `core` starting with 1.85. + if #[cfg(feature = "unstable-intrinsics")] { + self.copysign(other) + } else { + super::super::generic::copysign(self, other) + } + } + } 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) From 3030182c6692c6007c126d933cf57f5d96124205 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 3 Jan 2025 22:26:39 +0000 Subject: [PATCH 1495/4206] Change to exhaustive matching for `default_ulp` Make it more obvious what the expected ULP for a given routine is. This also narrows ULP to 0 for operations that require exact results. --- .../libm/crates/libm-test/src/precision.rs | 130 ++++++++++++------ 1 file changed, 91 insertions(+), 39 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 6d4561c43767f..89b66146c4317 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -4,57 +4,109 @@ use core::f32; use CheckBasis::{Mpfr, Musl}; -use Identifier as Id; +use {BaseName as Bn, Identifier as Id}; use crate::{BaseName, CheckBasis, CheckCtx, Float, Identifier, Int, TestResult}; /// Type implementing [`IgnoreCase`]. pub struct SpecialCase; -/// Default ULP allowed to differ from musl (note that musl itself may not be accurate). -const MUSL_DEFAULT_ULP: u32 = 2; - -/// Default ULP allowed to differ from multiprecision (i.e. infinite) results. -const MP_DEFAULT_ULP: u32 = 1; - /// ULP allowed to differ from the results returned by a test basis. /// /// Note that these results were obtained using 400M rounds of random inputs, which /// is not a value used by default. pub fn default_ulp(ctx: &CheckCtx) -> u32 { - match (&ctx.basis, ctx.fn_ident) { - // Overrides that apply to either basis - // FMA is expected to be infinite precision. - (_, Id::Fma | Id::Fmaf) => 0, - (_, Id::J0 | Id::J0f | Id::J1 | Id::J1f | Id::Y0 | Id::Y0f | Id::Y1 | Id::Y1f) => 800_000, - (_, Id::Jn | Id::Jnf | Id::Yn | Id::Ynf) => 1000, - (_, Id::Erfc | Id::Erfcf) => 4, - - // Overrides for musl - #[cfg(x86_no_sse)] - (Musl, Id::Asinh | Id::Asinhf) => 6, - #[cfg(not(target_pointer_width = "64"))] - (Musl, Id::Exp10 | Id::Exp10f) => 4, - (Musl, Id::Lgamma | Id::LgammaR | Id::Lgammaf | Id::LgammafR) => 400, - (Musl, Id::Sincosf) => 500, - (Musl, Id::Tanh | Id::Tanhf) => 4, - (Musl, Id::Tgamma) => 20, - - // Overrides for MPFR - (Mpfr, Id::Acosh) => 4, - (Mpfr, Id::Acoshf) => 4, - (Mpfr, Id::Asinh | Id::Asinhf) => 2, - (Mpfr, Id::Atanh | Id::Atanhf) => 2, - (Mpfr, Id::Exp10 | Id::Exp10f) => 6, - (Mpfr, Id::Lgamma | Id::LgammaR | Id::Lgammaf | Id::LgammafR) => 16, - (Mpfr, Id::Sinh | Id::Sinhf) => 2, - (Mpfr, Id::Tanh | Id::Tanhf) => 2, - (Mpfr, Id::Tgamma) => 20, - - // Defaults - (Musl, _) => MUSL_DEFAULT_ULP, - (Mpfr, _) => MP_DEFAULT_ULP, + // ULP compared to the infinite (MPFR) result. + let mut ulp = match ctx.base_name { + // Operations that require exact results. This list should correlate with what we + // have documented at . + Bn::Ceil + | Bn::Copysign + | Bn::Fabs + | Bn::Fdim + | Bn::Floor + | Bn::Fma + | Bn::Fmax + | Bn::Fmin + | Bn::Fmod + | Bn::Frexp + | Bn::Ldexp + | Bn::Modf + | Bn::Nextafter + | Bn::Remainder + | Bn::Remquo + | Bn::Rint + | Bn::Round + | Bn::Scalbn + | Bn::Sqrt + | Bn::Trunc => 0, + + // Operations that aren't required to be exact, but our implementations are. + Bn::Cbrt if ctx.fn_ident != Id::Cbrt => 0, + Bn::Ilogb => 0, + Bn::Tgamma if ctx.fn_ident != Id::Tgamma => 0, + + // Bessel functions have large inaccuracies. + Bn::J0 | Bn::J1 | Bn::Y0 | Bn::Y1 => 8_000_000, + Bn::Jn | Bn::Yn => 1_000, + + // For all other operations, specify our implementation's worst case precision. + Bn::Acos => 1, + Bn::Acosh => 4, + Bn::Asin => 1, + Bn::Asinh => 2, + Bn::Atan => 1, + Bn::Atan2 => 1, + Bn::Atanh => 2, + Bn::Cbrt => 1, + Bn::Cos => 1, + Bn::Cosh => 1, + Bn::Erf => 1, + Bn::Erfc => 4, + Bn::Exp => 1, + Bn::Exp10 => 6, + Bn::Exp2 => 1, + Bn::Expm1 => 1, + Bn::Hypot => 1, + Bn::Lgamma | Bn::LgammaR => 16, + Bn::Log => 1, + Bn::Log10 => 1, + Bn::Log1p => 1, + Bn::Log2 => 1, + Bn::Pow => 1, + Bn::Sin => 1, + Bn::Sincos => 1, + Bn::Sinh => 2, + Bn::Tan => 1, + Bn::Tanh => 2, + Bn::Tgamma => 20, + }; + + // 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::Lgamma | Bn::LgammaR => ulp = 400, + Bn::Tanh => ulp = 4, + _ if ctx.fn_ident == Id::Sincosf => ulp = 500, + _ if ctx.fn_ident == Id::Tgamma => ulp = 20, + _ => (), + } } + + // In some cases, our implementation is less accurate than musl on i586. + if cfg!(x86_no_sse) { + match ctx.fn_ident { + Id::Log1p | Id::Log1pf => ulp = 2, + Id::Round => ulp = 1, + Id::Tan => ulp = 2, + _ => (), + } + } + + ulp } /// Don't run further validation on this test case. From d50c12b21953e19dee6722e0e2abd718ef65ead6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 4 Jan 2025 11:14:31 +0000 Subject: [PATCH 1496/4206] precision: Sort `ilogb` with other precise operations This is a nonfunctional change. --- .../compiler-builtins/libm/crates/libm-test/src/precision.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 89b66146c4317..8bedcde4427fc 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -30,6 +30,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { | Bn::Fmin | Bn::Fmod | Bn::Frexp + | Bn::Ilogb | Bn::Ldexp | Bn::Modf | Bn::Nextafter @@ -43,7 +44,6 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { // Operations that aren't required to be exact, but our implementations are. Bn::Cbrt if ctx.fn_ident != Id::Cbrt => 0, - Bn::Ilogb => 0, Bn::Tgamma if ctx.fn_ident != Id::Tgamma => 0, // Bessel functions have large inaccuracies. From f99d8acc203823dc957ee8843b4edfbe0021cb78 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 5 Jan 2025 02:06:02 +0000 Subject: [PATCH 1497/4206] Clean up integers stored in `MpTy` There isn't any need to cache the integer since it gets provided as an argument anyway. Simplify this in `jn` and `yn`. --- .../libm/crates/libm-test/src/mpfloat.rs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index edb4cb962dcf5..5e516ef68756a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -241,17 +241,17 @@ macro_rules! impl_op_for_ty { } impl MpOp for crate::op::[]::Routine { - type MpTy = (i32, MpFloat); + type MpTy = MpFloat; fn new_mp() -> Self::MpTy { - (0, new_mpfloat::()) + new_mpfloat::() } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.0 = input.0; - this.1.assign(input.1); - let ord = this.1.jn_round(this.0, Nearest); - prep_retval::(&mut this.1, ord) + let (n, x) = input; + this.assign(x); + let ord = this.jn_round(n, Nearest); + prep_retval::(this, ord) } } @@ -274,17 +274,17 @@ macro_rules! impl_op_for_ty { } impl MpOp for crate::op::[]::Routine { - type MpTy = (i32, MpFloat); + type MpTy = MpFloat; fn new_mp() -> Self::MpTy { - (0, new_mpfloat::()) + new_mpfloat::() } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - this.0 = input.0; - this.1.assign(input.1); - let ord = this.1.yn_round(this.0, Nearest); - prep_retval::(&mut this.1, ord) + let (n, x) = input; + this.assign(x); + let ord = this.yn_round(n, Nearest); + prep_retval::(this, ord) } } } From 59964fbbca7757c4d95a925f9e590837c3e4fa83 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 4 Jan 2025 09:53:58 +0000 Subject: [PATCH 1498/4206] Add tests against MPFR for `modf` and `modff` Rug provides `trunc_fract_round`, which implements `modf`, use it to add a test. --- .../libm/crates/libm-test/src/mpfloat.rs | 18 ++++++++++++++++++ .../crates/libm-test/tests/multiprecision.rs | 4 ---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 5e516ef68756a..b9e71d68aaa21 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -210,6 +210,24 @@ macro_rules! impl_op_for_ty { } } + 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(&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), + ) + } + } + impl MpOp for crate::op::[]::Routine { type MpTy = (MpFloat, MpFloat); diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 71ff2ff965ff9..54d313059f936 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -58,8 +58,6 @@ libm_macros::for_each_function! { ilogbf, ldexp, ldexpf, - modf, - modff, remquo, remquof, scalbn, @@ -165,7 +163,5 @@ libm_macros::for_each_function! { frexpf, ilogb, ilogbf, - modf, - modff, ], } From e9bc33e8d398b412b49315a67c7b3cc246b977e9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 4 Jan 2025 10:39:27 +0000 Subject: [PATCH 1499/4206] Add tests against MPFR for `frexp` and `frexpf` This implementation comes from `rug::Float::to_f32_exp` [1]. [1]: https://docs.rs/rug/1.26.1/rug/struct.Float.html#method.to_f32_exp --- .../libm/crates/libm-test/src/mpfloat.rs | 19 +++++++++++++++++++ .../crates/libm-test/tests/multiprecision.rs | 4 ---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index b9e71d68aaa21..4d40858f2b216 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -258,6 +258,25 @@ macro_rules! impl_op_for_ty { } } + 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 { + // Implementation taken from `rug::Float::to_f32_exp`. + this.assign(input.0); + let exp = this.get_exp().unwrap_or(0); + if exp != 0 { + *this >>= exp; + } + + (prep_retval::(this, Ordering::Equal), exp) + } + } + impl MpOp for crate::op::[]::Routine { type MpTy = MpFloat; diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 54d313059f936..ade5a255384d9 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -52,8 +52,6 @@ libm_macros::for_each_function! { ], skip: [ // FIXME: MPFR tests needed - frexp, - frexpf, ilogb, ilogbf, ldexp, @@ -159,8 +157,6 @@ libm_macros::for_each_function! { ynf, // FIXME: MPFR tests needed - frexp, - frexpf, ilogb, ilogbf, ], From 4b15d9e5e362ba8bbf1bb71437c11d359bf6309c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 3 Jan 2025 05:28:39 +0000 Subject: [PATCH 1500/4206] Add tests against MPFR for `scalbn{f}` and `ldexp{f}` --- .../libm/crates/libm-test/src/mpfloat.rs | 28 +++++++++++++++++++ .../crates/libm-test/tests/multiprecision.rs | 4 --- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 4d40858f2b216..8b8298004896f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -292,6 +292,34 @@ macro_rules! impl_op_for_ty { } } + // `ldexp` and `scalbn` are the same for binary floating point, so just forward all + // methods. + impl MpOp for crate::op::[]::Routine { + type MpTy = ]::Routine as MpOp>::MpTy; + + fn new_mp() -> Self::MpTy { + ]::Routine as MpOp>::new_mp() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + ]::Routine as MpOp>::run(this, input) + } + } + + 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 <<= input.1; + prep_retval::(this, Ordering::Equal) + } + } + impl MpOp for crate::op::[]::Routine { type MpTy = (MpFloat, MpFloat); diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index ade5a255384d9..4cdba0942cd6d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -54,12 +54,8 @@ libm_macros::for_each_function! { // FIXME: MPFR tests needed ilogb, ilogbf, - ldexp, - ldexpf, remquo, remquof, - scalbn, - scalbnf, // FIXME: test needed, see // https://github.com/rust-lang/libm/pull/311#discussion_r1818273392 From b7b22b54c0f008993bea29ac26c3db042601ee06 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 29 Dec 2024 08:45:08 +0000 Subject: [PATCH 1501/4206] Add a way for tests to log to a file Occasionally it is useful to see some information from running tests without making everything noisy from `--nocapture`. Add a function to log this kind of output to a file, and print the file as part of CI. --- .../libm/.github/workflows/main.yml | 5 ++ library/compiler-builtins/libm/configure.rs | 15 ++++++ .../libm/crates/libm-test/src/lib.rs | 53 +++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 0f5becf7305ba..023ec58c06a2e 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -113,6 +113,11 @@ jobs: rustup target add x86_64-unknown-linux-musl cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} + - name: Print test logs if available + if: always() + run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi + shell: bash + clippy: name: Clippy runs-on: ubuntu-24.04 diff --git a/library/compiler-builtins/libm/configure.rs b/library/compiler-builtins/libm/configure.rs index 389e86c33889f..a18937c3c9e26 100644 --- a/library/compiler-builtins/libm/configure.rs +++ b/library/compiler-builtins/libm/configure.rs @@ -8,6 +8,7 @@ pub struct Config { pub manifest_dir: PathBuf, pub out_dir: PathBuf, pub opt_level: u8, + pub cargo_features: Vec, pub target_arch: String, pub target_env: String, pub target_family: Option, @@ -22,11 +23,16 @@ impl Config { let target_features = env::var("CARGO_CFG_TARGET_FEATURE") .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) .unwrap_or_default(); + 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(); Self { 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().parse().unwrap(), + cargo_features, target_arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), target_family: env::var("CARGO_CFG_TARGET_FAMILY").ok(), @@ -45,6 +51,7 @@ pub fn emit_libm_config(cfg: &Config) { emit_arch_cfg(); emit_optimization_cfg(cfg); emit_cfg_shorthands(cfg); + emit_cfg_env(cfg); emit_f16_f128_cfg(cfg); } @@ -53,6 +60,7 @@ pub fn emit_libm_config(cfg: &Config) { pub fn emit_test_config(cfg: &Config) { emit_optimization_cfg(cfg); emit_cfg_shorthands(cfg); + emit_cfg_env(cfg); emit_f16_f128_cfg(cfg); } @@ -97,6 +105,13 @@ fn emit_cfg_shorthands(cfg: &Config) { } } +/// Reemit config that we make use of for test logging. +fn emit_cfg_env(cfg: &Config) { + 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); +} + /// 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)"); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 97907b2a16077..c1aec0230303f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -13,6 +13,13 @@ mod precision; mod run_cfg; mod test_traits; +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; +use std::sync::LazyLock; +use std::time::SystemTime; + pub use f8_impl::f8; pub use libm::support::{Float, Int, IntTy, MinInt}; pub use num::{FloatExt, logspace}; @@ -42,3 +49,49 @@ pub const fn ci() -> bool { Some(_) => true, } } + +/// Print to stderr and additionally log it to `target/test-log.txt`. This is useful for saving +/// output that would otherwise be consumed by the test harness. +pub fn test_log(s: &str) { + // Handle to a file opened in append mode, unless a suitable path can't be determined. + static OUTFILE: LazyLock> = LazyLock::new(|| { + // If the target directory is overridden, use that environment variable. Otherwise, save + // at the default path `{workspace_root}/target`. + let target_dir = match env::var("CARGO_TARGET_DIR") { + Ok(s) => PathBuf::from(s), + Err(_) => { + let Ok(x) = env::var("CARGO_MANIFEST_DIR") else { + return None; + }; + + PathBuf::from(x).parent().unwrap().parent().unwrap().join("target") + } + }; + let outfile = target_dir.join("test-log.txt"); + + let mut f = File::options() + .create(true) + .append(true) + .open(outfile) + .expect("failed to open logfile"); + let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap(); + + writeln!(f, "\n\nTest run at {}", now.as_secs()).unwrap(); + writeln!(f, "arch: {}", env::consts::ARCH).unwrap(); + writeln!(f, "os: {}", env::consts::OS).unwrap(); + writeln!(f, "bits: {}", usize::BITS).unwrap(); + writeln!(f, "emulated: {}", emulated()).unwrap(); + writeln!(f, "ci: {}", ci()).unwrap(); + writeln!(f, "cargo features: {}", env!("CFG_CARGO_FEATURES")).unwrap(); + writeln!(f, "opt level: {}", env!("CFG_OPT_LEVEL")).unwrap(); + writeln!(f, "target features: {}", env!("CFG_TARGET_FEATURES")).unwrap(); + + Some(f) + }); + + eprintln!("{s}"); + + if let Some(mut f) = OUTFILE.as_ref() { + writeln!(f, "{s}").unwrap(); + } +} From 9a7a5193706319b17c260da433f27c2c2c8f5b07 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 26 Dec 2024 07:44:54 +0000 Subject: [PATCH 1502/4206] Streamline the way that test iteration count is determined Currently, tests use a handful of constants to determine how many iterations to perform: `NTESTS`, `AROUND`, and `MAX_CHECK_POINTS`. This configuration is not very straightforward to adjust and needs to be repeated everywhere it is used. Replace this with new functions in the `run_cfg` module that determine iteration counts in a more reusable and documented way. This only updates `edge_cases` and `domain_logspace`, `random` is refactored in a later commit. --- .../libm-test/src/gen/domain_logspace.rs | 31 +-- .../crates/libm-test/src/gen/edge_cases.rs | 54 +++--- .../libm/crates/libm-test/src/gen/random.rs | 1 + .../libm/crates/libm-test/src/lib.rs | 2 +- .../libm/crates/libm-test/src/run_cfg.rs | 177 +++++++++++++++++- 5 files changed, 208 insertions(+), 57 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs index 5e37170fa1a4d..3d8a3e7fe7335 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs @@ -6,41 +6,26 @@ use libm::support::{IntTy, MinInt}; use crate::domain::HasDomain; use crate::op::OpITy; +use crate::run_cfg::{GeneratorKind, iteration_count}; use crate::{CheckCtx, MathOp, logspace}; -/// Number of tests to run. -// FIXME(ntests): replace this with a more logical algorithm -const NTESTS: usize = { - if cfg!(optimizations_enabled) { - if crate::emulated() - || !cfg!(target_pointer_width = "64") - || cfg!(all(target_arch = "x86_64", target_vendor = "apple")) - { - // Tests are pretty slow on non-64-bit targets, x86 MacOS, and targets that run - // in QEMU. - 100_000 - } else { - 5_000_000 - } - } else { - // Without optimizations just run a quick check - 800 - } -}; - /// Create a range of logarithmically spaced inputs within a function's domain. /// /// This allows us to get reasonably thorough coverage without wasting time on values that are /// NaN or out of range. Random tests will still cover values that are excluded here. -pub fn get_test_cases(_ctx: &CheckCtx) -> impl Iterator +pub fn get_test_cases(ctx: &CheckCtx) -> impl Iterator where Op: MathOp + HasDomain, - IntTy: TryFrom, + IntTy: TryFrom, RangeInclusive>: Iterator, { let domain = Op::DOMAIN; + let ntests = iteration_count(ctx, GeneratorKind::Domain, 0); + + // We generate logspaced inputs within a specific range, excluding values that are out of + // range in order to make iterations useful (random tests still cover the full range). let start = domain.range_start(); let end = domain.range_end(); - let steps = OpITy::::try_from(NTESTS).unwrap_or(OpITy::::MAX); + let steps = OpITy::::try_from(ntests).unwrap_or(OpITy::::MAX); logspace(start, end, steps).map(|v| (v,)) } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs index 3387f6c485aee..1f27c1467dcd0 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs @@ -3,18 +3,11 @@ use libm::support::Float; use crate::domain::HasDomain; +use crate::run_cfg::{check_near_count, check_point_count}; use crate::{CheckCtx, FloatExt, MathOp}; -/// Number of values near an interesting point to check. -// FIXME(ntests): replace this with a more logical algorithm -const AROUND: usize = 100; - -/// Functions have infinite asymptotes, limit how many we check. -// FIXME(ntests): replace this with a more logical algorithm -const MAX_CHECK_POINTS: usize = 10; - /// Create a list of values around interesting points (infinities, zeroes, NaNs). -pub fn get_test_cases(_ctx: &CheckCtx) -> impl Iterator +pub fn get_test_cases(ctx: &CheckCtx) -> impl Iterator where Op: MathOp + HasDomain, F: Float, @@ -25,23 +18,26 @@ where let domain_start = domain.range_start(); let domain_end = domain.range_end(); + let check_points = check_point_count(ctx); + let near_points = check_near_count(ctx); + // Check near some notable constants - count_up(F::ONE, values); - count_up(F::ZERO, values); - count_up(F::NEG_ONE, values); - count_down(F::ONE, values); - count_down(F::ZERO, values); - count_down(F::NEG_ONE, values); + 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(F::NEG_INFINITY, values); - count_down(F::INFINITY, values); - count_down(domain_end, values); - count_up(domain_start, values); - count_down(domain_start, values); - count_up(domain_end, values); - count_down(domain_end, 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); + count_up(domain_end, near_points, values); + count_down(domain_end, near_points, values); // Check some special values that aren't included in the above ranges values.push(F::NAN); @@ -50,9 +46,9 @@ where // Check around asymptotes if let Some(f) = domain.check_points { let iter = f(); - for x in iter.take(MAX_CHECK_POINTS) { - count_up(x, values); - count_down(x, values); + for x in iter.take(check_points) { + count_up(x, near_points, values); + count_down(x, near_points, values); } } @@ -65,11 +61,11 @@ where /// Add `AROUND` values starting at and including `x` and counting up. Uses the smallest possible /// increments (1 ULP). -fn count_up(mut x: F, values: &mut Vec) { +fn count_up(mut x: F, points: u64, values: &mut Vec) { assert!(!x.is_nan()); let mut count = 0; - while x < F::INFINITY && count < AROUND { + while x < F::INFINITY && count < points { values.push(x); x = x.next_up(); count += 1; @@ -78,11 +74,11 @@ fn count_up(mut x: F, values: &mut Vec) { /// Add `AROUND` values starting at and including `x` and counting down. Uses the smallest possible /// increments (1 ULP). -fn count_down(mut x: F, values: &mut Vec) { +fn count_down(mut x: F, points: u64, values: &mut Vec) { assert!(!x.is_nan()); let mut count = 0; - while x > F::NEG_INFINITY && count < AROUND { + while x > F::NEG_INFINITY && count < points { values.push(x); x = x.next_down(); count += 1; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index 4f75da07b898d..a30a3674e6a4e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -12,6 +12,7 @@ use crate::{BaseName, CheckCtx, GenerateInput}; const SEED: [u8; 32] = *b"3.141592653589793238462643383279"; /// Number of tests to run. +// FIXME(ntests): clean this up when possible const NTESTS: usize = { if cfg!(optimizations_enabled) { if crate::emulated() diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index c1aec0230303f..80ec237361571 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -25,7 +25,7 @@ pub use libm::support::{Float, Int, IntTy, MinInt}; pub use num::{FloatExt, logspace}; pub use op::{BaseName, FloatTy, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet, Ty}; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; -pub use run_cfg::{CheckBasis, CheckCtx}; +pub use run_cfg::{CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind}; pub use test_traits::{CheckOutput, GenerateInput, Hex, TupleCall}; /// Result type for tests is usually from `anyhow`. Most times there is no success value to diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index eb7e0e2c1a94e..46a6a1fadaa20 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -1,13 +1,11 @@ //! Configuration for how tests get run. -#![allow(unused)] - -use std::collections::BTreeMap; use std::env; use std::sync::LazyLock; -use crate::{BaseName, FloatTy, Identifier, op}; +use crate::{BaseName, FloatTy, Identifier, test_log}; +/// The environment variable indicating which extensive tests should be run. pub const EXTENSIVE_ENV: &str = "LIBM_EXTENSIVE_TESTS"; /// Context passed to [`CheckOutput`]. @@ -49,3 +47,174 @@ pub enum CheckBasis { /// Check against infinite precision (MPFR). Mpfr, } + +/// The different kinds of generators that provide test input. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum GeneratorKind { + Domain, + Random, +} + +/// A list of all functions that should get extensive tests. +/// +/// This also supports the special test name `all` to run all tests, as well as `all_f16`, +/// `all_f32`, `all_f64`, and `all_f128` to run all tests for a specific float type. +static EXTENSIVE: LazyLock> = LazyLock::new(|| { + let var = env::var(EXTENSIVE_ENV).unwrap_or_default(); + 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 iter = Identifier::ALL.iter().filter(move |id| id.math_op().float_ty == fty).copied(); + ret.extend(iter); + }; + + 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), + s => { + let id = Identifier::from_str(s) + .unwrap_or_else(|| panic!("unrecognized test name `{s}`")); + ret.push(id); + } + } + } + + ret +}); + +/// 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, + /// Env indicates that an extensive test should be run. + should_run_extensive: bool, + /// Multiprecision tests will be run. + mp_tests_enabled: bool, + /// The number of inputs to the function. + input_count: usize, +} + +impl TestEnv { + fn from_env(ctx: &CheckCtx) -> Self { + let id = ctx.fn_ident; + let op = id.math_op(); + + let will_run_mp = cfg!(feature = "test-multiprecision"); + + // Tests are pretty slow on non-64-bit targets, x86 MacOS, and targets that run in QEMU. Start + // with a reduced number on these platforms. + let slow_on_ci = crate::emulated() + || usize::BITS < 64 + || cfg!(all(target_arch = "x86_64", target_vendor = "apple")); + let slow_platform = slow_on_ci && crate::ci(); + + let large_float_ty = match op.float_ty { + FloatTy::F16 | FloatTy::F32 => false, + FloatTy::F64 | FloatTy::F128 => true, + }; + + let will_run_extensive = EXTENSIVE.contains(&id); + + let input_count = op.rust_sig.args.len(); + + Self { + slow_platform, + large_float_ty, + should_run_extensive: will_run_extensive, + mp_tests_enabled: will_run_mp, + input_count, + } + } +} + +/// The number of iterations to run for a given test. +pub fn iteration_count(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) -> u64 { + let t_env = TestEnv::from_env(ctx); + + // Ideally run 5M tests + let mut domain_iter_count: u64 = 4_000_000; + + // Start with a reduced number of tests on slow platforms. + if t_env.slow_platform { + domain_iter_count = 100_000; + } + + // Larger float types get more iterations. + if t_env.large_float_ty { + domain_iter_count *= 4; + } + + // Functions with more arguments get more iterations. + let arg_multiplier = 1 << (t_env.input_count - 1); + domain_iter_count *= arg_multiplier; + + // If we will be running tests against MPFR, we don't need to test as much against musl. + // However, there are some platforms where we have to test against musl since MPFR can't be + // built. + if t_env.mp_tests_enabled && ctx.basis == CheckBasis::Musl { + domain_iter_count /= 100; + } + + // Run fewer random tests than domain tests. + let random_iter_count = domain_iter_count / 100; + + let mut total_iterations = match gen_kind { + GeneratorKind::Domain => domain_iter_count, + GeneratorKind::Random => random_iter_count, + }; + + if cfg!(optimizations_enabled) { + // Always run at least 10,000 tests. + total_iterations = total_iterations.max(10_000); + } else { + // Without optimizations, just run a quick check regardless of other parameters. + total_iterations = 800; + } + + // Adjust for the number of inputs + let ntests = match t_env.input_count { + 1 => total_iterations, + 2 => (total_iterations as f64).sqrt().ceil() as u64, + 3 => (total_iterations as f64).cbrt().ceil() as u64, + _ => panic!("test has more than three arguments"), + }; + let total = ntests.pow(t_env.input_count.try_into().unwrap()); + + test_log(&format!( + "{gen_kind:?} {basis:?} {fn_ident} arg {arg}/{args}: {ntests} iterations \ + ({total} total)", + basis = ctx.basis, + fn_ident = ctx.fn_ident, + arg = argnum + 1, + args = t_env.input_count, + )); + + ntests +} + +/// For domain tests, limit how many asymptotes or specified check points we test. +pub fn check_point_count(ctx: &CheckCtx) -> usize { + let t_env = TestEnv::from_env(ctx); + if t_env.slow_platform || !cfg!(optimizations_enabled) { 4 } else { 10 } +} + +/// When validating points of interest (e.g. asymptotes, inflection points, extremes), also check +/// this many surrounding values. +pub fn check_near_count(_ctx: &CheckCtx) -> u64 { + if cfg!(optimizations_enabled) { 100 } else { 10 } +} + +/// Check whether extensive actions should be run or skipped. +#[expect(dead_code, reason = "extensive tests have not yet been added")] +pub fn skip_extensive_test(ctx: &CheckCtx) -> bool { + let t_env = TestEnv::from_env(ctx); + !t_env.should_run_extensive +} From b78f7b7b482fa6dbc540cabd6f1a6233d48f0b9f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 30 Dec 2024 06:12:16 +0000 Subject: [PATCH 1503/4206] Add an iterator that ensures known size Introduce the `KnownSize` iterator wrapper, which allows providing the size at construction time. This provides an `ExactSizeIterator` implemenation so we can check a generator's value count during testing. --- .../libm/crates/libm-test/src/gen.rs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs index 2d15915d91ae4..2305d2a23773a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs @@ -5,6 +5,43 @@ pub mod domain_logspace; pub mod edge_cases; pub mod random; +/// A wrapper to turn any iterator into an `ExactSizeIterator`. Asserts the final result to ensure +/// the provided size was correct. +#[derive(Debug)] +pub struct KnownSize { + total: u64, + current: u64, + iter: I, +} + +impl KnownSize { + pub fn new(iter: I, total: u64) -> Self { + Self { total, current: 0, iter } + } +} + +impl Iterator for KnownSize { + type Item = I::Item; + + fn next(&mut self) -> Option { + let next = self.iter.next(); + if next.is_some() { + self.current += 1; + return next; + } + + assert_eq!(self.current, self.total, "total items did not match expected"); + None + } + + fn size_hint(&self) -> (usize, Option) { + let remaining = usize::try_from(self.total - self.current).unwrap(); + (remaining, Some(remaining)) + } +} + +impl ExactSizeIterator for KnownSize {} + /// Helper type to turn any reusable input into a generator. #[derive(Clone, Debug, Default)] pub struct CachedInput { From 37dbc534cba00c25d06fb6421facc9b39b69b6eb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 29 Dec 2024 11:23:08 +0000 Subject: [PATCH 1504/4206] Rewrite the random test generator Currently, all inputs are generated and then cached. This works reasonably well but it isn't very configurable or extensible (adding `f16` and `f128` is awkward). Replace this with a trait for generating random sequences of tuples. This also removes possible storage limitations of caching all inputs. --- .../libm/crates/libm-test/benches/random.rs | 7 +- .../libm/crates/libm-test/src/gen.rs | 69 ------ .../libm/crates/libm-test/src/gen/random.rs | 206 +++++++++--------- .../libm/crates/libm-test/src/lib.rs | 2 +- .../libm/crates/libm-test/src/run_cfg.rs | 32 ++- .../libm/crates/libm-test/src/test_traits.rs | 8 +- .../libm-test/tests/compare_built_musl.rs | 11 +- .../crates/libm-test/tests/multiprecision.rs | 9 +- 8 files changed, 148 insertions(+), 196 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 06997cd3621e7..23f4294558328 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -2,8 +2,9 @@ use std::hint::black_box; use std::time::Duration; use criterion::{Criterion, criterion_main}; -use libm_test::gen::{CachedInput, random}; -use libm_test::{CheckBasis, CheckCtx, GenerateInput, MathOp, TupleCall}; +use libm_test::gen::random; +use libm_test::gen::random::RandomInput; +use libm_test::{CheckBasis, CheckCtx, MathOp, TupleCall}; /// Benchmark with this many items to get a variety const BENCH_ITER_ITEMS: usize = if cfg!(feature = "short-benchmarks") { 50 } else { 500 }; @@ -47,7 +48,7 @@ macro_rules! musl_rand_benches { fn bench_one(c: &mut Criterion, musl_extra: MuslExtra) where Op: MathOp, - CachedInput: GenerateInput, + Op::RustArgs: RandomInput, { let name = Op::NAME; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs index 2305d2a23773a..83e00f31d2854 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs @@ -1,6 +1,5 @@ //! Different generators that can create random or systematic bit patterns. -use crate::GenerateInput; pub mod domain_logspace; pub mod edge_cases; pub mod random; @@ -41,71 +40,3 @@ impl Iterator for KnownSize { } impl ExactSizeIterator for KnownSize {} - -/// Helper type to turn any reusable input into a generator. -#[derive(Clone, Debug, Default)] -pub struct CachedInput { - pub inputs_f32: Vec<(f32, f32, f32)>, - pub inputs_f64: Vec<(f64, f64, f64)>, - pub inputs_i32: Vec<(i32, i32, i32)>, -} - -impl GenerateInput<(f32,)> for CachedInput { - fn get_cases(&self) -> impl Iterator { - self.inputs_f32.iter().map(|f| (f.0,)) - } -} - -impl GenerateInput<(f32, f32)> for CachedInput { - fn get_cases(&self) -> impl Iterator { - self.inputs_f32.iter().map(|f| (f.0, f.1)) - } -} - -impl GenerateInput<(i32, f32)> for CachedInput { - fn get_cases(&self) -> impl Iterator { - self.inputs_i32.iter().zip(self.inputs_f32.iter()).map(|(i, f)| (i.0, f.0)) - } -} - -impl GenerateInput<(f32, i32)> for CachedInput { - fn get_cases(&self) -> impl Iterator { - GenerateInput::<(i32, f32)>::get_cases(self).map(|(i, f)| (f, i)) - } -} - -impl GenerateInput<(f32, f32, f32)> for CachedInput { - fn get_cases(&self) -> impl Iterator { - self.inputs_f32.iter().copied() - } -} - -impl GenerateInput<(f64,)> for CachedInput { - fn get_cases(&self) -> impl Iterator { - self.inputs_f64.iter().map(|f| (f.0,)) - } -} - -impl GenerateInput<(f64, f64)> for CachedInput { - fn get_cases(&self) -> impl Iterator { - self.inputs_f64.iter().map(|f| (f.0, f.1)) - } -} - -impl GenerateInput<(i32, f64)> for CachedInput { - fn get_cases(&self) -> impl Iterator { - self.inputs_i32.iter().zip(self.inputs_f64.iter()).map(|(i, f)| (i.0, f.0)) - } -} - -impl GenerateInput<(f64, i32)> for CachedInput { - fn get_cases(&self) -> impl Iterator { - GenerateInput::<(i32, f64)>::get_cases(self).map(|(i, f)| (f, i)) - } -} - -impl GenerateInput<(f64, f64, f64)> for CachedInput { - fn get_cases(&self) -> impl Iterator { - self.inputs_f64.iter().copied() - } -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index a30a3674e6a4e..6df9443178a11 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -1,120 +1,118 @@ -//! A simple generator that produces deterministic random input, caching to use the same -//! inputs for all functions. - +use std::env; +use std::ops::RangeInclusive; use std::sync::LazyLock; +use libm::support::Float; +use rand::distributions::{Alphanumeric, Standard}; +use rand::prelude::Distribution; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; -use super::CachedInput; -use crate::{BaseName, CheckCtx, GenerateInput}; - -const SEED: [u8; 32] = *b"3.141592653589793238462643383279"; - -/// Number of tests to run. -// FIXME(ntests): clean this up when possible -const NTESTS: usize = { - if cfg!(optimizations_enabled) { - if crate::emulated() - || !cfg!(target_pointer_width = "64") - || cfg!(all(target_arch = "x86_64", target_vendor = "apple")) - { - // Tests are pretty slow on non-64-bit targets, x86 MacOS, and targets that run - // in QEMU. - 100_000 - } else { - 5_000_000 - } - } else { - // Without optimizations just run a quick check - 800 - } -}; - -/// Tested inputs. -static TEST_CASES: LazyLock = LazyLock::new(|| make_test_cases(NTESTS)); - -/// The first argument to `jn` and `jnf` is the number of iterations. Make this a reasonable -/// value so tests don't run forever. -static TEST_CASES_JN: LazyLock = LazyLock::new(|| { - // Start with regular test cases - let mut cases = (*TEST_CASES).clone(); - - // These functions are extremely slow, limit them - let ntests_jn = (NTESTS / 1000).max(80); - cases.inputs_i32.truncate(ntests_jn); - cases.inputs_f32.truncate(ntests_jn); - cases.inputs_f64.truncate(ntests_jn); - - // It is easy to overflow the stack with these in debug mode - let max_iterations = if cfg!(optimizations_enabled) && cfg!(target_pointer_width = "64") { - 0xffff - } else if cfg!(windows) { - 0x00ff - } else { - 0x0fff - }; +use super::KnownSize; +use crate::run_cfg::{int_range, iteration_count}; +use crate::{CheckCtx, GeneratorKind}; - let mut rng = ChaCha8Rng::from_seed(SEED); +pub(crate) const SEED_ENV: &str = "LIBM_SEED"; - for case in cases.inputs_i32.iter_mut() { - case.0 = rng.gen_range(3..=max_iterations); - } +pub(crate) static SEED: LazyLock<[u8; 32]> = LazyLock::new(|| { + let s = env::var(SEED_ENV).unwrap_or_else(|_| { + let mut rng = rand::thread_rng(); + (0..32).map(|_| rng.sample(Alphanumeric) as char).collect() + }); - cases + s.as_bytes().try_into().unwrap_or_else(|_| { + panic!("Seed must be 32 characters, got `{s}`"); + }) }); -fn make_test_cases(ntests: usize) -> CachedInput { - let mut rng = ChaCha8Rng::from_seed(SEED); - - // make sure we include some basic cases - let mut inputs_i32 = vec![(0, 0, 0), (1, 1, 1), (-1, -1, -1)]; - let mut inputs_f32 = vec![ - (0.0, 0.0, 0.0), - (f32::EPSILON, f32::EPSILON, f32::EPSILON), - (f32::INFINITY, f32::INFINITY, f32::INFINITY), - (f32::NEG_INFINITY, f32::NEG_INFINITY, f32::NEG_INFINITY), - (f32::MAX, f32::MAX, f32::MAX), - (f32::MIN, f32::MIN, f32::MIN), - (f32::MIN_POSITIVE, f32::MIN_POSITIVE, f32::MIN_POSITIVE), - (f32::NAN, f32::NAN, f32::NAN), - ]; - let mut inputs_f64 = vec![ - (0.0, 0.0, 0.0), - (f64::EPSILON, f64::EPSILON, f64::EPSILON), - (f64::INFINITY, f64::INFINITY, f64::INFINITY), - (f64::NEG_INFINITY, f64::NEG_INFINITY, f64::NEG_INFINITY), - (f64::MAX, f64::MAX, f64::MAX), - (f64::MIN, f64::MIN, f64::MIN), - (f64::MIN_POSITIVE, f64::MIN_POSITIVE, f64::MIN_POSITIVE), - (f64::NAN, f64::NAN, f64::NAN), - ]; - - inputs_i32.extend((0..(ntests - inputs_i32.len())).map(|_| rng.gen::<(i32, i32, i32)>())); - - // Generate integers to get a full range of bitpatterns, then convert back to - // floats. - inputs_f32.extend((0..(ntests - inputs_f32.len())).map(|_| { - let ints = rng.gen::<(u32, u32, u32)>(); - (f32::from_bits(ints.0), f32::from_bits(ints.1), f32::from_bits(ints.2)) - })); - inputs_f64.extend((0..(ntests - inputs_f64.len())).map(|_| { - let ints = rng.gen::<(u64, u64, u64)>(); - (f64::from_bits(ints.0), f64::from_bits(ints.1), f64::from_bits(ints.2)) - })); - - CachedInput { inputs_f32, inputs_f64, inputs_i32 } +/// Generate a sequence of random values of this type. +pub trait RandomInput { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator; } -/// Create a test case iterator. -pub fn get_test_cases(ctx: &CheckCtx) -> impl Iterator +/// Generate a sequence of deterministically random floats. +fn random_floats(count: u64) -> impl Iterator where - CachedInput: GenerateInput, + Standard: Distribution, { - let inputs = if ctx.base_name == BaseName::Jn || ctx.base_name == BaseName::Yn { - &TEST_CASES_JN - } else { - &TEST_CASES + let mut rng = ChaCha8Rng::from_seed(*SEED); + + // Generate integers to get a full range of bitpatterns (including NaNs), then convert back + // to the float type. + (0..count).map(move |_| F::from_bits(rng.gen::())) +} + +/// Generate a sequence of deterministically random `i32`s within a specified range. +fn random_ints(count: u64, range: RangeInclusive) -> impl Iterator { + let mut rng = ChaCha8Rng::from_seed(*SEED); + (0..count).map(move |_| rng.gen_range::(range.clone())) +} + +macro_rules! impl_random_input { + ($fty:ty) => { + impl RandomInput for ($fty,) { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let count = iteration_count(ctx, GeneratorKind::Random, 0); + let iter = random_floats(count).map(|f: $fty| (f,)); + KnownSize::new(iter, count) + } + } + + impl RandomInput for ($fty, $fty) { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let count0 = iteration_count(ctx, GeneratorKind::Random, 0); + let count1 = iteration_count(ctx, GeneratorKind::Random, 1); + let iter = random_floats(count0) + .flat_map(move |f1: $fty| random_floats(count1).map(move |f2: $fty| (f1, f2))); + KnownSize::new(iter, count0 * count1) + } + } + + impl RandomInput for ($fty, $fty, $fty) { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let count0 = iteration_count(ctx, GeneratorKind::Random, 0); + let count1 = iteration_count(ctx, GeneratorKind::Random, 1); + let count2 = iteration_count(ctx, GeneratorKind::Random, 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)) + }) + }); + KnownSize::new(iter, count0 * count1 * count2) + } + } + + impl RandomInput for (i32, $fty) { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let count0 = iteration_count(ctx, GeneratorKind::Random, 0); + let count1 = iteration_count(ctx, GeneratorKind::Random, 1); + let range0 = int_range(ctx, 0); + let iter = random_ints(count0, range0) + .flat_map(move |f1: i32| random_floats(count1).map(move |f2: $fty| (f1, f2))); + KnownSize::new(iter, count0 * count1) + } + } + + impl RandomInput for ($fty, i32) { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let count0 = iteration_count(ctx, GeneratorKind::Random, 0); + let count1 = iteration_count(ctx, GeneratorKind::Random, 1); + let range1 = int_range(ctx, 1); + let iter = random_floats(count0).flat_map(move |f1: $fty| { + random_ints(count1, range1.clone()).map(move |f2: i32| (f1, f2)) + }); + KnownSize::new(iter, count0 * count1) + } + } }; - inputs.get_cases() +} + +impl_random_input!(f32); +impl_random_input!(f64); + +/// Create a test case iterator. +pub fn get_test_cases( + ctx: &CheckCtx, +) -> impl Iterator + use<'_, RustArgs> { + RustArgs::get_cases(ctx) } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 80ec237361571..8a4e782df70f6 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -26,7 +26,7 @@ pub use num::{FloatExt, logspace}; pub use op::{BaseName, FloatTy, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet, Ty}; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; pub use run_cfg::{CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind}; -pub use test_traits::{CheckOutput, GenerateInput, Hex, TupleCall}; +pub use test_traits::{CheckOutput, Hex, 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/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index 46a6a1fadaa20..9cede0cc722f5 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -1,8 +1,10 @@ //! Configuration for how tests get run. -use std::env; +use std::ops::RangeInclusive; use std::sync::LazyLock; +use std::{env, str}; +use crate::gen::random::{SEED, SEED_ENV}; use crate::{BaseName, FloatTy, Identifier, test_log}; /// The environment variable indicating which extensive tests should be run. @@ -188,9 +190,16 @@ pub fn iteration_count(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) - }; let total = ntests.pow(t_env.input_count.try_into().unwrap()); + let seed_msg = match gen_kind { + GeneratorKind::Domain => String::new(), + GeneratorKind::Random => { + format!(" using `{SEED_ENV}={}`", str::from_utf8(SEED.as_slice()).unwrap()) + } + }; + test_log(&format!( "{gen_kind:?} {basis:?} {fn_ident} arg {arg}/{args}: {ntests} iterations \ - ({total} total)", + ({total} total){seed_msg}", basis = ctx.basis, fn_ident = ctx.fn_ident, arg = argnum + 1, @@ -200,6 +209,25 @@ pub fn iteration_count(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) - ntests } +/// Some tests require that an integer be kept within reasonable limits; generate that here. +pub fn int_range(ctx: &CheckCtx, argnum: usize) -> RangeInclusive { + let t_env = TestEnv::from_env(ctx); + + if !matches!(ctx.base_name, BaseName::Jn | BaseName::Yn) { + return i32::MIN..=i32::MAX; + } + + assert_eq!(argnum, 0, "For `jn`/`yn`, only the first argument takes an integer"); + + // The integer argument to `jn` is an iteration count. Limit this to ensure tests can be + // completed in a reasonable amount of time. + if t_env.slow_platform || !cfg!(optimizations_enabled) { + (-0xf)..=0xff + } else { + (-0xff)..=0xffff + } +} + /// For domain tests, limit how many asymptotes or specified check points we test. pub fn check_point_count(ctx: &CheckCtx) -> usize { let t_env = TestEnv::from_env(ctx); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index 6b833dfb5ddb0..261d1f2540d48 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -1,8 +1,7 @@ //! Traits related to testing. //! -//! There are three main traits in this module: +//! There are two main traits in this module: //! -//! - `GenerateInput`: implemented on any types that create test cases. //! - `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. @@ -13,11 +12,6 @@ use anyhow::{Context, bail, ensure}; use crate::{CheckCtx, Float, Int, MaybeOverride, SpecialCase, TestResult}; -/// Implement this on types that can generate a sequence of tuples for test input. -pub trait GenerateInput { - fn get_cases(&self) -> impl Iterator; -} - /// Trait for calling a function with a tuple as arguments. /// /// Implemented on the tuple with the function signature as the generic (so we can use the same diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 71f080ab18f8f..ecd379a0a6865 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -9,8 +9,9 @@ // There are some targets we can't build musl for #![cfg(feature = "build-musl")] -use libm_test::gen::{CachedInput, random}; -use libm_test::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, TupleCall}; +use libm_test::gen::random; +use libm_test::gen::random::RandomInput; +use libm_test::{CheckBasis, CheckCtx, CheckOutput, MathOp, TupleCall}; macro_rules! musl_rand_tests { ( @@ -21,16 +22,16 @@ macro_rules! musl_rand_tests { #[test] $(#[$attr])* fn [< musl_random_ $fn_name >]() { - test_one::(musl_math_sys::$fn_name); + test_one_random::(musl_math_sys::$fn_name); } } }; } -fn test_one(musl_fn: Op::CFn) +fn test_one_random(musl_fn: Op::CFn) where Op: MathOp, - CachedInput: GenerateInput, + Op::RustArgs: RandomInput, { let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl); let cases = random::get_test_cases::(&ctx); diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 4cdba0942cd6d..960c370d4b5b8 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -3,11 +3,10 @@ #![cfg(feature = "test-multiprecision")] use libm_test::domain::HasDomain; -use libm_test::gen::{CachedInput, domain_logspace, edge_cases, random}; +use libm_test::gen::random::RandomInput; +use libm_test::gen::{domain_logspace, edge_cases, random}; use libm_test::mpfloat::MpOp; -use libm_test::{ - CheckBasis, CheckCtx, CheckOutput, GenerateInput, MathOp, OpFTy, OpRustFn, OpRustRet, TupleCall, -}; +use libm_test::{CheckBasis, CheckCtx, CheckOutput, MathOp, OpFTy, OpRustFn, OpRustRet, TupleCall}; /// Test against MPFR with random inputs. macro_rules! mp_rand_tests { @@ -29,7 +28,7 @@ macro_rules! mp_rand_tests { fn test_one_random() where Op: MathOp + MpOp, - CachedInput: GenerateInput, + Op::RustArgs: RandomInput, { let mut mp_vals = Op::new_mp(); let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); From cc6a84bf438072033d577284d0dabdd0a5d354d7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 Jan 2025 00:36:18 +0000 Subject: [PATCH 1505/4206] Update precision based on new test results --- .../libm/crates/libm-test/src/precision.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 8bedcde4427fc..a8efe1015f8d3 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -90,8 +90,15 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { Bn::Exp10 if usize::BITS < 64 => ulp = 4, Bn::Lgamma | Bn::LgammaR => ulp = 400, Bn::Tanh => ulp = 4, - _ if ctx.fn_ident == Id::Sincosf => ulp = 500, - _ if ctx.fn_ident == Id::Tgamma => ulp = 20, + _ => (), + } + + match ctx.fn_ident { + // FIXME(#401): musl has an incorrect result here. + Id::Fdim => ulp = 2, + Id::Jnf | Id::Ynf => ulp = 4000, + Id::Sincosf => ulp = 500, + Id::Tgamma => ulp = 20, _ => (), } } @@ -99,6 +106,8 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { // In some cases, our implementation is less accurate than musl on i586. if cfg!(x86_no_sse) { match ctx.fn_ident { + Id::Asinh => ulp = 3, + Id::Asinhf => ulp = 3, Id::Log1p | Id::Log1pf => ulp = 2, Id::Round => ulp = 1, Id::Tan => ulp = 2, From ea21b6045f07dd4b01a54c74f3b2a87d85ff1588 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 Jan 2025 02:52:24 +0000 Subject: [PATCH 1506/4206] Rename `unstable-test-support` to `unstable-public-internals` The `support` module that this feature makes public will be useful for implementations in `compiler-builtins`, not only for testing. Give this feature a more accurate name. --- library/compiler-builtins/libm/Cargo.toml | 2 +- .../crates/compiler-builtins-smoke-test/Cargo.toml | 13 +++++-------- .../libm/crates/libm-test/Cargo.toml | 2 +- library/compiler-builtins/libm/src/math/mod.rs | 6 +++--- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index bfc11509e4246..dc362779e84a2 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -27,7 +27,7 @@ unstable = ["unstable-intrinsics", "unstable-float"] unstable-intrinsics = [] # Make some internal things public for testing. -unstable-test-support = [] +unstable-public-internals = [] # Enable the nightly-only `f16` and `f128`. unstable-float = [] diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index 82cfeecb90fef..1f09ce99c482d 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -9,14 +9,6 @@ publish = false test = false bench = false -[features] -# Duplicated from libm's Cargo.toml -unstable = [] -unstable-intrinsics = [] -unstable-test-support = [] -checked = [] -force-soft-floats = [] - [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = [ "cfg(arch_enabled)", @@ -24,4 +16,9 @@ unexpected_cfgs = { level = "warn", check-cfg = [ "cfg(f128_enabled)", "cfg(f16_enabled)", "cfg(intrinsics_enabled)", + 'cfg(feature, values("checked"))', + 'cfg(feature, values("force-soft-floats"))', + 'cfg(feature, values("unstable"))', + 'cfg(feature, values("unstable-intrinsics"))', + 'cfg(feature, values("unstable-public-internals"))', ] } diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index f2dd88fa14c9c..9b3ab5c53b10c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -26,7 +26,7 @@ short-benchmarks = [] [dependencies] anyhow = "1.0.90" az = { version = "1.2.1", optional = true } -libm = { path = "../..", features = ["unstable-test-support"] } +libm = { path = "../..", features = ["unstable-public-internals"] } libm-macros = { path = "../libm-macros" } musl-math-sys = { path = "../musl-math-sys", optional = true } paste = "1.0.15" diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index e7b21de67621e..9003a83428806 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -76,15 +76,15 @@ macro_rules! div { // `support` may be public for testing #[macro_use] -#[cfg(feature = "unstable-test-support")] +#[cfg(feature = "unstable-public-internals")] pub mod support; #[macro_use] -#[cfg(not(feature = "unstable-test-support"))] +#[cfg(not(feature = "unstable-public-internals"))] mod support; cfg_if! { - if #[cfg(feature = "unstable-test-support")] { + if #[cfg(feature = "unstable-public-internals")] { pub mod generic; } else { mod generic; From 206bf326d54fba056129150afbc083e5a7f3447a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 Jan 2025 03:00:54 +0000 Subject: [PATCH 1507/4206] Increase the precision for `jn` and `jnf` New random seeds seem to indicate that this test does have some more failures, this is a recent failure on i586: ---- musl_random_jnf stdout ---- Random Musl jnf arg 1/2: 100 iterations (10000 total) using `LIBM_SEED=nLfzQ3U1OBVvqWaMBcto84UTMsC5FIaC` Random Musl jnf arg 2/2: 100 iterations (10000 total) using `LIBM_SEED=nLfzQ3U1OBVvqWaMBcto84UTMsC5FIaC` thread 'musl_random_jnf' panicked at crates/libm-test/tests/compare_built_musl.rs:43:51: called `Result::unwrap()` on an `Err` value: input: (205, 5497.891) (0x000000cd, 0x45abcf21) expected: 7.3291517e-6 0x36f5ecef actual: 7.331668e-6 0x36f6028c Caused by: ulp 5533 > 4000 It seems unlikely that `jn` would somehow have better precision than `j0`/`j1`, so just use the same precision. --- .../compiler-builtins/libm/crates/libm-test/src/precision.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index a8efe1015f8d3..4a6ca8af7b6bf 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -47,8 +47,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { Bn::Tgamma if ctx.fn_ident != Id::Tgamma => 0, // Bessel functions have large inaccuracies. - Bn::J0 | Bn::J1 | Bn::Y0 | Bn::Y1 => 8_000_000, - Bn::Jn | Bn::Yn => 1_000, + Bn::J0 | Bn::J1 | Bn::Y0 | Bn::Y1 | Bn::Jn | Bn::Yn => 8_000_000, // For all other operations, specify our implementation's worst case precision. Bn::Acos => 1, @@ -96,7 +95,6 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { match ctx.fn_ident { // FIXME(#401): musl has an incorrect result here. Id::Fdim => ulp = 2, - Id::Jnf | Id::Ynf => ulp = 4000, Id::Sincosf => ulp = 500, Id::Tgamma => ulp = 20, _ => (), From f453f5e5b561642bfc859e332a1e4ba8381b872f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 5 Jan 2025 01:58:40 +0000 Subject: [PATCH 1508/4206] Add tests against MPFR for `ilogb` and `ilogbf` --- .../libm/crates/libm-test/src/mpfloat.rs | 23 +++++++++++++++++++ .../crates/libm-test/tests/multiprecision.rs | 6 ----- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 8b8298004896f..ad98fafc87d16 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -277,6 +277,29 @@ macro_rules! impl_op_for_ty { } } + 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); + + // `get_exp` follows `frexp` for `0.5 <= |m| < 1.0`. Adjust the exponent by + // one to scale the significand to `1.0 <= |m| < 2.0`. + this.get_exp().map(|v| v - 1).unwrap_or_else(|| { + if this.is_infinite() { + i32::MAX + } else { + // Zero or NaN + i32::MIN + } + }) + } + } + impl MpOp for crate::op::[]::Routine { type MpTy = MpFloat; diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 960c370d4b5b8..42ec965c1440a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -51,8 +51,6 @@ libm_macros::for_each_function! { ], skip: [ // FIXME: MPFR tests needed - ilogb, - ilogbf, remquo, remquof, @@ -150,9 +148,5 @@ libm_macros::for_each_function! { scalbnf, yn, ynf, - - // FIXME: MPFR tests needed - ilogb, - ilogbf, ], } From 7c04b1916a442949523fac7c18ddcd611cee7cbe Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 2 Jan 2025 10:21:35 +0000 Subject: [PATCH 1509/4206] Add more detailed definition output for `update-api-list.py` Update the script to produce, in addition to the simple text list, a JSON file listing routine names, the types they work with, and the source files that contain a function with the routine name. This gets consumed by another script and will be used to determine which extensive CI jobs to run. --- .../libm/etc/function-definitions.json | 764 ++++++++++++++++++ .../libm/etc/update-api-list.py | 246 ++++-- 2 files changed, 945 insertions(+), 65 deletions(-) create mode 100644 library/compiler-builtins/libm/etc/function-definitions.json diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json new file mode 100644 index 0000000000000..4b10812c3a7bb --- /dev/null +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -0,0 +1,764 @@ +{ + "__comment": "Autogenerated by update-api-list.py. List of files that define a function with a given name. This file is checked in to make it obvious if refactoring breaks things", + "acos": { + "sources": [ + "src/libm_helper.rs", + "src/math/acos.rs" + ], + "type": "f64" + }, + "acosf": { + "sources": [ + "src/math/acosf.rs" + ], + "type": "f32" + }, + "acosh": { + "sources": [ + "src/libm_helper.rs", + "src/math/acosh.rs" + ], + "type": "f64" + }, + "acoshf": { + "sources": [ + "src/math/acoshf.rs" + ], + "type": "f32" + }, + "asin": { + "sources": [ + "src/libm_helper.rs", + "src/math/asin.rs" + ], + "type": "f64" + }, + "asinf": { + "sources": [ + "src/math/asinf.rs" + ], + "type": "f32" + }, + "asinh": { + "sources": [ + "src/libm_helper.rs", + "src/math/asinh.rs" + ], + "type": "f64" + }, + "asinhf": { + "sources": [ + "src/math/asinhf.rs" + ], + "type": "f32" + }, + "atan": { + "sources": [ + "src/libm_helper.rs", + "src/math/atan.rs" + ], + "type": "f64" + }, + "atan2": { + "sources": [ + "src/libm_helper.rs", + "src/math/atan2.rs" + ], + "type": "f64" + }, + "atan2f": { + "sources": [ + "src/math/atan2f.rs" + ], + "type": "f32" + }, + "atanf": { + "sources": [ + "src/math/atanf.rs" + ], + "type": "f32" + }, + "atanh": { + "sources": [ + "src/libm_helper.rs", + "src/math/atanh.rs" + ], + "type": "f64" + }, + "atanhf": { + "sources": [ + "src/math/atanhf.rs" + ], + "type": "f32" + }, + "cbrt": { + "sources": [ + "src/libm_helper.rs", + "src/math/cbrt.rs" + ], + "type": "f64" + }, + "cbrtf": { + "sources": [ + "src/math/cbrtf.rs" + ], + "type": "f32" + }, + "ceil": { + "sources": [ + "src/libm_helper.rs", + "src/math/arch/i586.rs", + "src/math/arch/intrinsics.rs", + "src/math/ceil.rs" + ], + "type": "f64" + }, + "ceilf": { + "sources": [ + "src/math/arch/intrinsics.rs", + "src/math/ceilf.rs" + ], + "type": "f32" + }, + "copysign": { + "sources": [ + "src/libm_helper.rs", + "src/math/copysign.rs", + "src/math/generic/copysign.rs", + "src/math/support/float_traits.rs" + ], + "type": "f64" + }, + "copysignf": { + "sources": [ + "src/math/copysignf.rs", + "src/math/generic/copysign.rs" + ], + "type": "f32" + }, + "cos": { + "sources": [ + "src/libm_helper.rs", + "src/math/cos.rs" + ], + "type": "f64" + }, + "cosf": { + "sources": [ + "src/math/cosf.rs" + ], + "type": "f32" + }, + "cosh": { + "sources": [ + "src/libm_helper.rs", + "src/math/cosh.rs" + ], + "type": "f64" + }, + "coshf": { + "sources": [ + "src/math/coshf.rs" + ], + "type": "f32" + }, + "erf": { + "sources": [ + "src/libm_helper.rs", + "src/math/erf.rs" + ], + "type": "f64" + }, + "erfc": { + "sources": [ + "src/libm_helper.rs", + "src/math/erf.rs" + ], + "type": "f64" + }, + "erfcf": { + "sources": [ + "src/math/erff.rs" + ], + "type": "f32" + }, + "erff": { + "sources": [ + "src/math/erff.rs" + ], + "type": "f32" + }, + "exp": { + "sources": [ + "src/libm_helper.rs", + "src/math/exp.rs", + "src/math/support/float_traits.rs" + ], + "type": "f64" + }, + "exp10": { + "sources": [ + "src/libm_helper.rs", + "src/math/exp10.rs" + ], + "type": "f64" + }, + "exp10f": { + "sources": [ + "src/math/exp10f.rs" + ], + "type": "f32" + }, + "exp2": { + "sources": [ + "src/libm_helper.rs", + "src/math/exp2.rs" + ], + "type": "f64" + }, + "exp2f": { + "sources": [ + "src/math/exp2f.rs" + ], + "type": "f32" + }, + "expf": { + "sources": [ + "src/math/expf.rs" + ], + "type": "f32" + }, + "expm1": { + "sources": [ + "src/libm_helper.rs", + "src/math/expm1.rs" + ], + "type": "f64" + }, + "expm1f": { + "sources": [ + "src/math/expm1f.rs" + ], + "type": "f32" + }, + "fabs": { + "sources": [ + "src/libm_helper.rs", + "src/math/arch/intrinsics.rs", + "src/math/fabs.rs", + "src/math/generic/fabs.rs" + ], + "type": "f64" + }, + "fabsf": { + "sources": [ + "src/math/arch/intrinsics.rs", + "src/math/fabsf.rs", + "src/math/generic/fabs.rs" + ], + "type": "f32" + }, + "fdim": { + "sources": [ + "src/libm_helper.rs", + "src/math/fdim.rs" + ], + "type": "f64" + }, + "fdimf": { + "sources": [ + "src/math/fdimf.rs" + ], + "type": "f32" + }, + "floor": { + "sources": [ + "src/libm_helper.rs", + "src/math/arch/i586.rs", + "src/math/arch/intrinsics.rs", + "src/math/floor.rs" + ], + "type": "f64" + }, + "floorf": { + "sources": [ + "src/math/arch/intrinsics.rs", + "src/math/floorf.rs" + ], + "type": "f32" + }, + "fma": { + "sources": [ + "src/libm_helper.rs", + "src/math/fma.rs" + ], + "type": "f64" + }, + "fmaf": { + "sources": [ + "src/math/fmaf.rs" + ], + "type": "f32" + }, + "fmax": { + "sources": [ + "src/libm_helper.rs", + "src/math/fmax.rs" + ], + "type": "f64" + }, + "fmaxf": { + "sources": [ + "src/math/fmaxf.rs" + ], + "type": "f32" + }, + "fmin": { + "sources": [ + "src/libm_helper.rs", + "src/math/fmin.rs" + ], + "type": "f64" + }, + "fminf": { + "sources": [ + "src/math/fminf.rs" + ], + "type": "f32" + }, + "fmod": { + "sources": [ + "src/libm_helper.rs", + "src/math/fmod.rs" + ], + "type": "f64" + }, + "fmodf": { + "sources": [ + "src/math/fmodf.rs" + ], + "type": "f32" + }, + "frexp": { + "sources": [ + "src/libm_helper.rs", + "src/math/frexp.rs" + ], + "type": "f64" + }, + "frexpf": { + "sources": [ + "src/math/frexpf.rs" + ], + "type": "f32" + }, + "hypot": { + "sources": [ + "src/libm_helper.rs", + "src/math/hypot.rs" + ], + "type": "f64" + }, + "hypotf": { + "sources": [ + "src/math/hypotf.rs" + ], + "type": "f32" + }, + "ilogb": { + "sources": [ + "src/libm_helper.rs", + "src/math/ilogb.rs" + ], + "type": "f64" + }, + "ilogbf": { + "sources": [ + "src/math/ilogbf.rs" + ], + "type": "f32" + }, + "j0": { + "sources": [ + "src/libm_helper.rs", + "src/math/j0.rs" + ], + "type": "f64" + }, + "j0f": { + "sources": [ + "src/math/j0f.rs" + ], + "type": "f32" + }, + "j1": { + "sources": [ + "src/libm_helper.rs", + "src/math/j1.rs" + ], + "type": "f64" + }, + "j1f": { + "sources": [ + "src/math/j1f.rs" + ], + "type": "f32" + }, + "jn": { + "sources": [ + "src/libm_helper.rs", + "src/math/jn.rs" + ], + "type": "f64" + }, + "jnf": { + "sources": [ + "src/math/jnf.rs" + ], + "type": "f32" + }, + "ldexp": { + "sources": [ + "src/libm_helper.rs", + "src/math/ldexp.rs" + ], + "type": "f64" + }, + "ldexpf": { + "sources": [ + "src/math/ldexpf.rs" + ], + "type": "f32" + }, + "lgamma": { + "sources": [ + "src/libm_helper.rs", + "src/math/lgamma.rs" + ], + "type": "f64" + }, + "lgamma_r": { + "sources": [ + "src/libm_helper.rs", + "src/math/lgamma_r.rs" + ], + "type": "f64" + }, + "lgammaf": { + "sources": [ + "src/math/lgammaf.rs" + ], + "type": "f32" + }, + "lgammaf_r": { + "sources": [ + "src/math/lgammaf_r.rs" + ], + "type": "f32" + }, + "log": { + "sources": [ + "src/libm_helper.rs", + "src/math/log.rs" + ], + "type": "f64" + }, + "log10": { + "sources": [ + "src/libm_helper.rs", + "src/math/log10.rs" + ], + "type": "f64" + }, + "log10f": { + "sources": [ + "src/math/log10f.rs" + ], + "type": "f32" + }, + "log1p": { + "sources": [ + "src/libm_helper.rs", + "src/math/log1p.rs" + ], + "type": "f64" + }, + "log1pf": { + "sources": [ + "src/math/log1pf.rs" + ], + "type": "f32" + }, + "log2": { + "sources": [ + "src/libm_helper.rs", + "src/math/log2.rs" + ], + "type": "f64" + }, + "log2f": { + "sources": [ + "src/math/log2f.rs" + ], + "type": "f32" + }, + "logf": { + "sources": [ + "src/math/logf.rs" + ], + "type": "f32" + }, + "modf": { + "sources": [ + "src/libm_helper.rs", + "src/math/modf.rs" + ], + "type": "f64" + }, + "modff": { + "sources": [ + "src/math/modff.rs" + ], + "type": "f32" + }, + "nextafter": { + "sources": [ + "src/libm_helper.rs", + "src/math/nextafter.rs" + ], + "type": "f64" + }, + "nextafterf": { + "sources": [ + "src/math/nextafterf.rs" + ], + "type": "f32" + }, + "pow": { + "sources": [ + "src/libm_helper.rs", + "src/math/pow.rs" + ], + "type": "f64" + }, + "powf": { + "sources": [ + "src/math/powf.rs" + ], + "type": "f32" + }, + "remainder": { + "sources": [ + "src/libm_helper.rs", + "src/math/remainder.rs" + ], + "type": "f64" + }, + "remainderf": { + "sources": [ + "src/math/remainderf.rs" + ], + "type": "f32" + }, + "remquo": { + "sources": [ + "src/libm_helper.rs", + "src/math/remquo.rs" + ], + "type": "f64" + }, + "remquof": { + "sources": [ + "src/math/remquof.rs" + ], + "type": "f32" + }, + "rint": { + "sources": [ + "src/libm_helper.rs", + "src/math/rint.rs" + ], + "type": "f64" + }, + "rintf": { + "sources": [ + "src/math/rintf.rs" + ], + "type": "f32" + }, + "round": { + "sources": [ + "src/libm_helper.rs", + "src/math/round.rs" + ], + "type": "f64" + }, + "roundf": { + "sources": [ + "src/math/roundf.rs" + ], + "type": "f32" + }, + "scalbn": { + "sources": [ + "src/libm_helper.rs", + "src/math/scalbn.rs" + ], + "type": "f64" + }, + "scalbnf": { + "sources": [ + "src/math/scalbnf.rs" + ], + "type": "f32" + }, + "sin": { + "sources": [ + "src/libm_helper.rs", + "src/math/sin.rs" + ], + "type": "f64" + }, + "sincos": { + "sources": [ + "src/libm_helper.rs", + "src/math/sincos.rs" + ], + "type": "f64" + }, + "sincosf": { + "sources": [ + "src/math/sincosf.rs" + ], + "type": "f32" + }, + "sinf": { + "sources": [ + "src/math/sinf.rs" + ], + "type": "f32" + }, + "sinh": { + "sources": [ + "src/libm_helper.rs", + "src/math/sinh.rs" + ], + "type": "f64" + }, + "sinhf": { + "sources": [ + "src/math/sinhf.rs" + ], + "type": "f32" + }, + "sqrt": { + "sources": [ + "src/libm_helper.rs", + "src/math/arch/i686.rs", + "src/math/arch/intrinsics.rs", + "src/math/sqrt.rs" + ], + "type": "f64" + }, + "sqrtf": { + "sources": [ + "src/math/arch/i686.rs", + "src/math/arch/intrinsics.rs", + "src/math/sqrtf.rs" + ], + "type": "f32" + }, + "tan": { + "sources": [ + "src/libm_helper.rs", + "src/math/tan.rs" + ], + "type": "f64" + }, + "tanf": { + "sources": [ + "src/math/tanf.rs" + ], + "type": "f32" + }, + "tanh": { + "sources": [ + "src/libm_helper.rs", + "src/math/tanh.rs" + ], + "type": "f64" + }, + "tanhf": { + "sources": [ + "src/math/tanhf.rs" + ], + "type": "f32" + }, + "tgamma": { + "sources": [ + "src/libm_helper.rs", + "src/math/tgamma.rs" + ], + "type": "f64" + }, + "tgammaf": { + "sources": [ + "src/math/tgammaf.rs" + ], + "type": "f32" + }, + "trunc": { + "sources": [ + "src/libm_helper.rs", + "src/math/arch/intrinsics.rs", + "src/math/trunc.rs" + ], + "type": "f64" + }, + "truncf": { + "sources": [ + "src/math/arch/intrinsics.rs", + "src/math/truncf.rs" + ], + "type": "f32" + }, + "y0": { + "sources": [ + "src/libm_helper.rs", + "src/math/j0.rs" + ], + "type": "f64" + }, + "y0f": { + "sources": [ + "src/math/j0f.rs" + ], + "type": "f32" + }, + "y1": { + "sources": [ + "src/libm_helper.rs", + "src/math/j1.rs" + ], + "type": "f64" + }, + "y1f": { + "sources": [ + "src/math/j1f.rs" + ], + "type": "f32" + }, + "yn": { + "sources": [ + "src/libm_helper.rs", + "src/math/jn.rs" + ], + "type": "f64" + }, + "ynf": { + "sources": [ + "src/math/jnf.rs" + ], + "type": "f32" + } +} diff --git a/library/compiler-builtins/libm/etc/update-api-list.py b/library/compiler-builtins/libm/etc/update-api-list.py index 7284a628c6a6d..a4587aa81d534 100755 --- a/library/compiler-builtins/libm/etc/update-api-list.py +++ b/library/compiler-builtins/libm/etc/update-api-list.py @@ -3,68 +3,166 @@ functions are covered by our macros. """ +import difflib import json import subprocess as sp import sys -import difflib +from dataclasses import dataclass +from glob import glob from pathlib import Path -from typing import Any +from typing import Any, TypeAlias ETC_DIR = Path(__file__).parent +IndexTy: TypeAlias = dict[str, dict[str, Any]] +"""Type of the `index` item in rustdoc's JSON output""" -def get_rustdoc_json() -> dict[Any, Any]: - """Get rustdoc's JSON output for the `libm` crate.""" - - librs_path = ETC_DIR.joinpath("../src/lib.rs") - j = sp.check_output( - [ - "rustdoc", - librs_path, - "--edition=2021", - "--output-format=json", - "-Zunstable-options", - "-o-", - ], - text=True, - ) - j = json.loads(j) - return j - -def list_public_functions() -> list[str]: - """Get a list of public functions from rustdoc JSON output. - - Note that this only finds functions that are reexported in `lib.rs`, this will - need to be adjusted if we need to account for functions that are defined there. +@dataclass +class Crate: + """Representation of public interfaces and function defintion locations in + `libm`. """ - names = [] - index: dict[str, dict[str, Any]] = get_rustdoc_json()["index"] - for item in index.values(): - # Find public items - if item["visibility"] != "public": - continue - - # Find only reexports - if "use" not in item["inner"].keys(): - continue - # Locate the item that is reexported - id = item["inner"]["use"]["id"] - srcitem = index.get(str(id)) - - # External crate - if srcitem is None: - continue - - # Skip if not a function - if "function" not in srcitem["inner"].keys(): - continue - - names.append(srcitem["name"]) - - names.sort() - return names + public_functions: list[str] + """List of all public functions.""" + defs: dict[str, list[str]] + """Map from `name->[source files]` to find all places that define a public + function. We track this to know which tests need to be rerun when specific files + get updated. + """ + types: dict[str, str] + """Map from `name->type`.""" + + def __init__(self) -> None: + self.public_functions = [] + self.defs = {} + self.types = {} + + j = self.get_rustdoc_json() + index: IndexTy = j["index"] + self._init_function_list(index) + self._init_defs(index) + self._init_types() + + @staticmethod + def get_rustdoc_json() -> dict[Any, Any]: + """Get rustdoc's JSON output for the `libm` crate.""" + + j = sp.check_output( + [ + "rustdoc", + "src/lib.rs", + "--edition=2021", + "--document-private-items", + "--output-format=json", + "-Zunstable-options", + "-o-", + ], + cwd=ETC_DIR.parent, + text=True, + ) + j = json.loads(j) + return j + + def _init_function_list(self, index: IndexTy) -> None: + """Get a list of public functions from rustdoc JSON output. + + Note that this only finds functions that are reexported in `lib.rs`, this will + need to be adjusted if we need to account for functions that are defined there, or + glob reexports in other locations. + """ + # Filter out items that are not public + public = [i for i in index.values() if i["visibility"] == "public"] + + # Collect a list of source IDs for reexported items in `lib.rs` or `mod math`. + use = (i for i in public if "use" in i["inner"]) + use = ( + i for i in use if i["span"]["filename"] in ["src/math/mod.rs", "src/lib.rs"] + ) + reexported_ids = [item["inner"]["use"]["id"] for item in use] + + # Collect a list of reexported items that are functions + for id in reexported_ids: + srcitem = index.get(str(id)) + # External crate + if srcitem is None: + continue + + # Skip if not a function + if "function" not in srcitem["inner"]: + continue + + self.public_functions.append(srcitem["name"]) + self.public_functions.sort() + + 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"]) + + # A lot of the `arch` module is often configured out so doesn't show up in docs. Use + # string matching as a fallback. + for fname in glob("src/math/arch/**.rs", root_dir=ETC_DIR.parent): + contents = Path(fname).read_text() + + for name in self.public_functions: + if f"fn {name}" in contents: + defs[name].add(fname) + + for name, sources in defs.items(): + base_sources = defs[base_name(name)[0]] + for src in (s for s in base_sources if "generic" in s): + sources.add(src) + + # Sort the set + self.defs = {k: sorted(v) for (k, v) in defs.items()} + + def _init_types(self) -> None: + self.types = {name: base_name(name)[1] for name in self.public_functions} + + def write_function_list(self, check: bool) -> None: + """Collect the list of public functions to a simple text file.""" + output = "# autogenerated by update-api-list.py\n" + for name in self.public_functions: + output += f"{name}\n" + + out_file = ETC_DIR.joinpath("function-list.txt") + + if check: + with open(out_file, "r") as f: + current = f.read() + diff_and_exit(current, output) + else: + with open(out_file, "w") as f: + f.write(output) + + def write_function_defs(self, check: bool) -> None: + """Collect the list of information about public functions to a JSON file .""" + comment = ( + "Autogenerated by update-api-list.py. " + "List of files that define a function with a given name. " + "This file is checked in to make it obvious if refactoring breaks things" + ) + + d = {"__comment": comment} + d |= { + name: {"sources": self.defs[name], "type": self.types[name]} + for name in self.public_functions + } + + out_file = ETC_DIR.joinpath("function-definitions.json") + output = json.dumps(d, indent=4) + "\n" + + if check: + with open(out_file, "r") as f: + current = f.read() + diff_and_exit(current, output) + else: + with open(out_file, "w") as f: + f.write(output) def diff_and_exit(actual: str, expected: str): @@ -84,6 +182,35 @@ def diff_and_exit(actual: str, expected: str): exit(1) +def base_name(name: str) -> tuple[str, str]: + """Return the basename and type from a full function name. Keep in sync with Rust's + `fn base_name`. + """ + known_mappings = [ + ("erff", ("erf", "f32")), + ("erf", ("erf", "f64")), + ("modff", ("modf", "f32")), + ("modf", ("modf", "f64")), + ("lgammaf_r", ("lgamma_r", "f32")), + ("lgamma_r", ("lgamma_r", "f64")), + ] + + found = next((base for (full, base) in known_mappings if full == name), None) + if found is not None: + return found + + if name.endswith("f"): + return (name.rstrip("f"), "f32") + + if name.endswith("f16"): + return (name.rstrip("f16"), "f16") + + if name.endswith("f128"): + return (name.rstrip("f128"), "f128") + + return (name, "f64") + + def main(): """By default overwrite the file. If `--check` is passed, print a diff instead and error if the files are different. @@ -97,20 +224,9 @@ def main(): print("unrecognized arguments") exit(1) - names = list_public_functions() - output = "# autogenerated by update-api-list.py\n" - for name in names: - output += f"{name}\n" - - out_file = ETC_DIR.joinpath("function-list.txt") - - if check: - with open(out_file, "r") as f: - current = f.read() - diff_and_exit(current, output) - else: - with open(out_file, "w") as f: - f.write(output) + crate = Crate() + crate.write_function_list(check) + crate.write_function_defs(check) if __name__ == "__main__": From 1bbf8b12daf95a2a65c1dd7e16c3a2ceb2680b7c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Dec 2024 11:47:44 +0000 Subject: [PATCH 1510/4206] Add extensive and exhaustive tests Add a generator that will test all inputs for input spaces `u32::MAX` or smaller (e.g. single-argument `f32` routines). For anything larger, still run approximately `u32::MAX` tests, but distribute inputs evenly across the function domain. Since we often only want to run one of these tests at a time, this implementation parallelizes within each test using `rayon`. A custom test runner is used so a progress bar is possible. Specific tests must be enabled by setting the `LIBM_EXTENSIVE_TESTS` environment variable, e.g. LIBM_EXTENSIVE_TESTS=all_f16,cos,cosf cargo run ... Testing on a recent machine, most tests take about two minutes or less. The Bessel functions are quite slow and take closer to 10 minutes, and FMA is increased to run for about the same. --- .../libm/crates/libm-test/Cargo.toml | 9 + .../libm/crates/libm-test/src/gen.rs | 1 + .../crates/libm-test/src/gen/extensive.rs | 153 ++++++++++++ .../libm/crates/libm-test/src/gen/random.rs | 4 +- .../libm/crates/libm-test/src/lib.rs | 4 +- .../libm/crates/libm-test/src/num.rs | 2 +- .../libm/crates/libm-test/src/run_cfg.rs | 37 ++- .../libm-test/tests/z_extensive/main.rs | 14 ++ .../crates/libm-test/tests/z_extensive/run.rs | 234 ++++++++++++++++++ 9 files changed, 450 insertions(+), 8 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs create mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/main.rs create mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 9b3ab5c53b10c..69e96034ef822 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -26,12 +26,14 @@ short-benchmarks = [] [dependencies] anyhow = "1.0.90" az = { version = "1.2.1", optional = true } +indicatif = { version = "0.17.9", default-features = false } libm = { path = "../..", features = ["unstable-public-internals"] } libm-macros = { path = "../libm-macros" } musl-math-sys = { path = "../musl-math-sys", optional = true } paste = "1.0.15" rand = "0.8.5" rand_chacha = "0.3.1" +rayon = "1.10.0" rug = { version = "1.26.1", optional = true, default-features = false, features = ["float", "std"] } [target.'cfg(target_family = "wasm")'.dependencies] @@ -43,11 +45,18 @@ rand = { version = "0.8.5", optional = true } [dev-dependencies] criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } +libtest-mimic = "0.8.1" [[bench]] name = "random" harness = false +[[test]] +# No harness so that we can skip tests at runtime based on env. Prefixed with +# `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 = [ diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs index 83e00f31d2854..e2bfcdf34c8c2 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs @@ -2,6 +2,7 @@ pub mod domain_logspace; pub mod edge_cases; +pub mod extensive; pub mod random; /// A wrapper to turn any iterator into an `ExactSizeIterator`. Asserts the final result to ensure diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs new file mode 100644 index 0000000000000..d8b991b2a5f33 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs @@ -0,0 +1,153 @@ +use std::fmt; +use std::ops::RangeInclusive; + +use libm::support::MinInt; + +use crate::domain::HasDomain; +use crate::gen::KnownSize; +use crate::op::OpITy; +use crate::run_cfg::{int_range, iteration_count}; +use crate::{CheckCtx, GeneratorKind, MathOp, logspace}; + +/// Generate a sequence of inputs that either cover the domain in completeness (for smaller float +/// types and single argument functions) or provide evenly spaced inputs across the domain with +/// approximately `u32::MAX` total iterations. +pub trait ExtensiveInput { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator + Send; +} + +/// Construct an iterator from `logspace` and also calculate the total number of steps expected +/// for that iterator. +fn logspace_steps( + start: Op::FTy, + end: Op::FTy, + ctx: &CheckCtx, + argnum: usize, +) -> (impl Iterator + Clone, u64) +where + Op: MathOp, + OpITy: TryFrom, + RangeInclusive>: Iterator, +{ + let max_steps = iteration_count(ctx, GeneratorKind::Extensive, argnum); + let max_steps = OpITy::::try_from(max_steps).unwrap_or(OpITy::::MAX); + let iter = logspace(start, end, max_steps); + + // `logspace` can't implement `ExactSizeIterator` because of the range, but its size hint + // should be accurate (assuming <= usize::MAX iterations). + let size_hint = iter.size_hint(); + assert_eq!(size_hint.0, size_hint.1.unwrap()); + + (iter, size_hint.0.try_into().unwrap()) +} + +macro_rules! impl_extensive_input { + ($fty:ty) => { + impl ExtensiveInput for ($fty,) + where + Op: MathOp, + Op: HasDomain, + { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let start = Op::DOMAIN.range_start(); + let end = Op::DOMAIN.range_end(); + let (iter0, steps0) = logspace_steps::(start, end, ctx, 0); + let iter0 = iter0.map(|v| (v,)); + KnownSize::new(iter0, steps0) + } + } + + impl ExtensiveInput for ($fty, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let start = <$fty>::NEG_INFINITY; + let end = <$fty>::INFINITY; + let (iter0, steps0) = logspace_steps::(start, end, ctx, 0); + let (iter1, steps1) = logspace_steps::(start, end, ctx, 1); + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = steps0.checked_mul(steps1).unwrap(); + KnownSize::new(iter, count) + } + } + + impl ExtensiveInput for ($fty, $fty, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let start = <$fty>::NEG_INFINITY; + let end = <$fty>::INFINITY; + + let (iter0, steps0) = logspace_steps::(start, end, ctx, 0); + let (iter1, steps1) = logspace_steps::(start, end, ctx, 1); + let (iter2, steps2) = logspace_steps::(start, end, 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 count = steps0.checked_mul(steps1).unwrap().checked_mul(steps2).unwrap(); + + KnownSize::new(iter, count) + } + } + + impl ExtensiveInput for (i32, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let start = <$fty>::NEG_INFINITY; + let end = <$fty>::INFINITY; + + let iter0 = int_range(ctx, GeneratorKind::Extensive, 0); + let steps0 = iteration_count(ctx, GeneratorKind::Extensive, 0); + let (iter1, steps1) = logspace_steps::(start, end, ctx, 1); + + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = steps0.checked_mul(steps1).unwrap(); + + KnownSize::new(iter, count) + } + } + + impl ExtensiveInput for ($fty, i32) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let start = <$fty>::NEG_INFINITY; + let end = <$fty>::INFINITY; + + let (iter0, steps0) = logspace_steps::(start, end, ctx, 0); + let iter1 = int_range(ctx, GeneratorKind::Extensive, 0); + let steps1 = iteration_count(ctx, GeneratorKind::Extensive, 0); + + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = steps0.checked_mul(steps1).unwrap(); + + KnownSize::new(iter, count) + } + } + }; +} + +impl_extensive_input!(f32); +impl_extensive_input!(f64); + +/// Create a test case iterator for extensive inputs. +pub fn get_test_cases( + ctx: &CheckCtx, +) -> impl ExactSizeIterator + Send + use<'_, Op> +where + Op: MathOp, + Op::RustArgs: ExtensiveInput, +{ + Op::RustArgs::get_cases(ctx) +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index 6df9443178a11..29a9dcd2b0825 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -86,7 +86,7 @@ macro_rules! impl_random_input { fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { let count0 = iteration_count(ctx, GeneratorKind::Random, 0); let count1 = iteration_count(ctx, GeneratorKind::Random, 1); - let range0 = int_range(ctx, 0); + let range0 = int_range(ctx, GeneratorKind::Random, 0); let iter = random_ints(count0, range0) .flat_map(move |f1: i32| random_floats(count1).map(move |f2: $fty| (f1, f2))); KnownSize::new(iter, count0 * count1) @@ -97,7 +97,7 @@ macro_rules! impl_random_input { fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { let count0 = iteration_count(ctx, GeneratorKind::Random, 0); let count1 = iteration_count(ctx, GeneratorKind::Random, 1); - let range1 = int_range(ctx, 1); + let range1 = int_range(ctx, GeneratorKind::Random, 1); let iter = random_floats(count0).flat_map(move |f1: $fty| { random_ints(count1, range1.clone()).map(move |f2: i32| (f1, f2)) }); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 8a4e782df70f6..a940db1d20665 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -25,7 +25,8 @@ pub use libm::support::{Float, Int, IntTy, MinInt}; pub use num::{FloatExt, logspace}; pub use op::{BaseName, FloatTy, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet, Ty}; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; -pub use run_cfg::{CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind}; +use run_cfg::EXTENSIVE_MAX_ITERATIONS; +pub use run_cfg::{CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind, skip_extensive_test}; pub use test_traits::{CheckOutput, Hex, TupleCall}; /// Result type for tests is usually from `anyhow`. Most times there is no success value to @@ -85,6 +86,7 @@ pub fn test_log(s: &str) { writeln!(f, "cargo features: {}", env!("CFG_CARGO_FEATURES")).unwrap(); writeln!(f, "opt level: {}", env!("CFG_OPT_LEVEL")).unwrap(); writeln!(f, "target features: {}", env!("CFG_TARGET_FEATURES")).unwrap(); + writeln!(f, "extensive iterations {}", *EXTENSIVE_MAX_ITERATIONS).unwrap(); Some(f) }); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/num.rs b/library/compiler-builtins/libm/crates/libm-test/src/num.rs index eff2fbc1fdd24..f693ef02f1f6f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/num.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/num.rs @@ -215,7 +215,7 @@ fn as_ulp_steps(x: F) -> Option { /// to logarithmic spacing of their values. /// /// Note that this tends to skip negative zero, so that needs to be checked explicitly. -pub fn logspace(start: F, end: F, steps: F::Int) -> impl Iterator +pub fn logspace(start: F, end: F, steps: F::Int) -> impl Iterator + Clone where RangeInclusive: Iterator, { diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index 9cede0cc722f5..48a654caaf8fb 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -10,6 +10,22 @@ use crate::{BaseName, FloatTy, Identifier, test_log}; /// The environment variable indicating which extensive tests should be run. pub const EXTENSIVE_ENV: &str = "LIBM_EXTENSIVE_TESTS"; +/// Specify the number of iterations via this environment variable, rather than using the default. +pub const EXTENSIVE_ITER_ENV: &str = "LIBM_EXTENSIVE_ITERATIONS"; + +/// Maximum number of iterations to run for a single routine. +/// +/// The default value of one greater than `u32::MAX` allows testing single-argument `f32` routines +/// and single- or double-argument `f16` routines exhaustively. `f64` and `f128` can't feasibly +/// be tested exhaustively; however, [`EXTENSIVE_ITER_ENV`] can be set to run tests for multiple +/// hours. +pub static EXTENSIVE_MAX_ITERATIONS: LazyLock = LazyLock::new(|| { + let default = 1 << 32; + env::var(EXTENSIVE_ITER_ENV) + .map(|v| v.parse().expect("failed to parse iteration count")) + .unwrap_or(default) +}); + /// Context passed to [`CheckOutput`]. #[derive(Clone, Debug, PartialEq, Eq)] pub struct CheckCtx { @@ -54,6 +70,7 @@ pub enum CheckBasis { #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum GeneratorKind { Domain, + Extensive, Random, } @@ -171,8 +188,14 @@ pub fn iteration_count(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) - let mut total_iterations = match gen_kind { GeneratorKind::Domain => domain_iter_count, GeneratorKind::Random => random_iter_count, + GeneratorKind::Extensive => *EXTENSIVE_MAX_ITERATIONS, }; + // FMA has a huge domain but is reasonably fast to run, so increase iterations. + if ctx.base_name == BaseName::Fma { + total_iterations *= 4; + } + if cfg!(optimizations_enabled) { // Always run at least 10,000 tests. total_iterations = total_iterations.max(10_000); @@ -191,7 +214,7 @@ pub fn iteration_count(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) - let total = ntests.pow(t_env.input_count.try_into().unwrap()); let seed_msg = match gen_kind { - GeneratorKind::Domain => String::new(), + GeneratorKind::Domain | GeneratorKind::Extensive => String::new(), GeneratorKind::Random => { format!(" using `{SEED_ENV}={}`", str::from_utf8(SEED.as_slice()).unwrap()) } @@ -210,7 +233,7 @@ pub fn iteration_count(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) - } /// Some tests require that an integer be kept within reasonable limits; generate that here. -pub fn int_range(ctx: &CheckCtx, argnum: usize) -> RangeInclusive { +pub fn int_range(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) -> RangeInclusive { let t_env = TestEnv::from_env(ctx); if !matches!(ctx.base_name, BaseName::Jn | BaseName::Yn) { @@ -221,10 +244,17 @@ pub fn int_range(ctx: &CheckCtx, argnum: usize) -> RangeInclusive { // The integer argument to `jn` is an iteration count. Limit this to ensure tests can be // completed in a reasonable amount of time. - if t_env.slow_platform || !cfg!(optimizations_enabled) { + let non_extensive_range = if t_env.slow_platform || !cfg!(optimizations_enabled) { (-0xf)..=0xff } else { (-0xff)..=0xffff + }; + + let extensive_range = (-0xfff)..=0xfffff; + + match gen_kind { + GeneratorKind::Extensive => extensive_range, + GeneratorKind::Domain | GeneratorKind::Random => non_extensive_range, } } @@ -241,7 +271,6 @@ pub fn check_near_count(_ctx: &CheckCtx) -> u64 { } /// Check whether extensive actions should be run or skipped. -#[expect(dead_code, reason = "extensive tests have not yet been added")] pub fn skip_extensive_test(ctx: &CheckCtx) -> bool { let t_env = TestEnv::from_env(ctx); !t_env.should_run_extensive diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/main.rs b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/main.rs new file mode 100644 index 0000000000000..3a2af88bd83b0 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/main.rs @@ -0,0 +1,14 @@ +//! `main` is just a wrapper to handle configuration. + +#[cfg(not(feature = "test-multiprecision"))] +fn main() { + eprintln!("multiprecision not enabled; skipping extensive tests"); +} + +#[cfg(feature = "test-multiprecision")] +mod run; + +#[cfg(feature = "test-multiprecision")] +fn main() { + run::run(); +} diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs new file mode 100644 index 0000000000000..7acff5324abcd --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs @@ -0,0 +1,234 @@ +//! Exhaustive tests for `f16` and `f32`, high-iteration for `f64` and `f128`. + +use std::fmt; +use std::io::{self, IsTerminal}; +use std::sync::atomic::{AtomicU64, Ordering}; +use std::time::Duration; + +use indicatif::{ProgressBar, ProgressStyle}; +use libm_test::gen::extensive::{self, ExtensiveInput}; +use libm_test::mpfloat::MpOp; +use libm_test::{ + CheckBasis, CheckCtx, CheckOutput, MathOp, TestResult, TupleCall, skip_extensive_test, +}; +use libtest_mimic::{Arguments, Trial}; +use rayon::prelude::*; + +/// Run the extensive test suite. +pub fn run() { + let mut args = Arguments::from_args(); + // Prevent multiple tests from running in parallel, each test gets parallized internally. + args.test_threads = Some(1); + let tests = register_all_tests(); + + // With default parallelism, the CPU doesn't saturate. We don't need to be nice to + // other processes, so do 1.5x to make sure we use all available resources. + let threads = std::thread::available_parallelism().map(Into::into).unwrap_or(0) * 3 / 2; + rayon::ThreadPoolBuilder::new().num_threads(threads).build_global().unwrap(); + + libtest_mimic::run(&args, tests).exit(); +} + +macro_rules! mp_extensive_tests { + ( + fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], + extra: [$push_to:ident], + ) => { + $(#[$attr])* + register_single_test::(&mut $push_to); + }; +} + +/// Create a list of tests for consumption by `libtest_mimic`. +fn register_all_tests() -> Vec { + let mut all_tests = Vec::new(); + + libm_macros::for_each_function! { + callback: mp_extensive_tests, + extra: [all_tests], + skip: [ + // FIXME: MPFR tests needed + remquo, + remquof, + + // FIXME: test needed, see + // https://github.com/rust-lang/libm/pull/311#discussion_r1818273392 + nextafter, + nextafterf, + ], + } + + all_tests +} + +/// Add a single test to the list. +fn register_single_test(all: &mut Vec) +where + Op: MathOp + MpOp, + Op::RustArgs: ExtensiveInput + Send, +{ + let test_name = format!("mp_extensive_{}", Op::NAME); + let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); + let skip = skip_extensive_test(&ctx); + + let runner = move || { + if !cfg!(optimizations_enabled) { + panic!("extensive tests should be run with --release"); + } + + let res = run_single_test::(); + let e = match res { + Ok(()) => return Ok(()), + Err(e) => e, + }; + + // Format with the `Debug` implementation so we get the error cause chain, and print it + // here so we see the result immediately (rather than waiting for all tests to conclude). + let e = format!("{e:?}"); + eprintln!("failure testing {}:{e}\n", Op::IDENTIFIER); + + Err(e.into()) + }; + + all.push(Trial::test(test_name, runner).with_ignored_flag(skip)); +} + +/// Test runner for a signle routine. +fn run_single_test() -> TestResult +where + Op: MathOp + MpOp, + Op::RustArgs: ExtensiveInput + Send, +{ + // Small delay before printing anything so other output from the runner has a chance to flush. + std::thread::sleep(Duration::from_millis(500)); + eprintln!(); + + let completed = AtomicU64::new(0); + let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); + let cases = &mut extensive::get_test_cases::(&ctx); + let total: u64 = cases.len().try_into().unwrap(); + let pb = Progress::new(Op::NAME, total); + + let test_single_chunk = |mp_vals: &mut Op::MpTy, input_vec: Vec| -> TestResult { + for input in input_vec { + // Test the input. + let mp_res = Op::run(mp_vals, input); + let crate_res = input.call(Op::ROUTINE); + crate_res.validate(mp_res, input, &ctx)?; + + let completed = completed.fetch_add(1, Ordering::Relaxed) + 1; + pb.update(completed, input); + } + + Ok(()) + }; + + // Chunk the cases so Rayon doesn't switch threads between each iterator item. 50k seems near + // a performance sweet spot. Ideally we would reuse these allocations rather than discarding, + // but that is difficult with Rayon's API. + let chunk_size = 50_000; + let chunks = std::iter::from_fn(move || { + let mut v = Vec::with_capacity(chunk_size); + v.extend(cases.take(chunk_size)); + (!v.is_empty()).then_some(v) + }); + + // Run the actual tests + let res = chunks.par_bridge().try_for_each_init(Op::new_mp, test_single_chunk); + + let real_total = completed.load(Ordering::Relaxed); + pb.complete(real_total); + + if res.is_ok() && real_total != total { + // Provide a warning if our estimate needs to be updated. + panic!("total run {real_total} does not match expected {total}"); + } + + res +} + +/// Wrapper around a `ProgressBar` that handles styles and non-TTY messages. +struct Progress { + pb: ProgressBar, + name_padded: String, + final_style: ProgressStyle, + is_tty: bool, +} + +impl Progress { + const PB_TEMPLATE: &str = "[{elapsed:3} {percent:3}%] {bar:20.cyan/blue} NAME \ + {human_pos:>13}/{human_len:13} {per_sec:18} eta {eta:8} {msg}"; + const PB_TEMPLATE_FINAL: &str = "[{elapsed:3} {percent:3}%] {bar:20.cyan/blue} NAME \ + {human_pos:>13}/{human_len:13} {per_sec:18} done in {elapsed_precise}"; + + fn new(name: &str, total: u64) -> Self { + eprintln!("starting extensive tests for `{name}`"); + let name_padded = format!("{name:9}"); + let is_tty = io::stderr().is_terminal(); + + let initial_style = + ProgressStyle::with_template(&Self::PB_TEMPLATE.replace("NAME", &name_padded)) + .unwrap() + .progress_chars("##-"); + + let final_style = + ProgressStyle::with_template(&Self::PB_TEMPLATE_FINAL.replace("NAME", &name_padded)) + .unwrap() + .progress_chars("##-"); + + let pb = ProgressBar::new(total); + pb.set_style(initial_style); + + Self { pb, final_style, name_padded, is_tty } + } + + fn update(&self, completed: u64, input: impl fmt::Debug) { + // Infrequently update the progress bar. + if completed % 20_000 == 0 { + self.pb.set_position(completed); + } + + if completed % 500_000 == 0 { + self.pb.set_message(format!("input: {input:<24?}")); + } + + if !self.is_tty && completed % 5_000_000 == 0 { + let len = self.pb.length().unwrap_or_default(); + eprintln!( + "[{elapsed:3?}s {percent:3.0}%] {name} \ + {human_pos:>10}/{human_len:<10} {per_sec:14.2}/s eta {eta:4}s {input:<24?}", + elapsed = self.pb.elapsed().as_secs(), + percent = completed as f32 * 100.0 / len as f32, + name = self.name_padded, + human_pos = completed, + human_len = len, + per_sec = self.pb.per_sec(), + eta = self.pb.eta().as_secs() + ); + } + } + + fn complete(self, real_total: u64) { + self.pb.set_style(self.final_style); + self.pb.set_position(real_total); + self.pb.abandon(); + + if !self.is_tty { + let len = self.pb.length().unwrap_or_default(); + eprintln!( + "[{elapsed:3}s {percent:3.0}%] {name} \ + {human_pos:>10}/{human_len:<10} {per_sec:14.2}/s done in {elapsed_precise}", + elapsed = self.pb.elapsed().as_secs(), + percent = real_total as f32 * 100.0 / len as f32, + name = self.name_padded, + human_pos = real_total, + human_len = len, + per_sec = self.pb.per_sec(), + elapsed_precise = self.pb.elapsed().as_secs(), + ); + } + + eprintln!(); + } +} From 05a1f4a982b09f8c9293e5c8cf4300a995432a6f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Dec 2024 11:47:53 +0000 Subject: [PATCH 1511/4206] Update precision based on failures from extensive tests --- .../libm/crates/libm-test/src/precision.rs | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 4a6ca8af7b6bf..696bb373578d4 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -55,7 +55,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { Bn::Asin => 1, Bn::Asinh => 2, Bn::Atan => 1, - Bn::Atan2 => 1, + Bn::Atan2 => 2, Bn::Atanh => 2, Bn::Cbrt => 1, Bn::Cos => 1, @@ -187,6 +187,20 @@ impl MaybeOverride<(f32,)> for SpecialCase { return XFAIL; } + if (ctx.base_name == BaseName::Lgamma || ctx.base_name == BaseName::LgammaR) + && input.0 > 4e36 + && expected.is_infinite() + && !actual.is_infinite() + { + // This result should saturate but we return a finite value. + return XFAIL; + } + + if ctx.base_name == BaseName::J0 && input.0 < -1e34 { + // Errors get huge close to -inf + return XFAIL; + } + maybe_check_nan_bits(actual, expected, ctx) } @@ -248,6 +262,11 @@ impl MaybeOverride<(f64,)> for SpecialCase { return XFAIL; } + if ctx.base_name == BaseName::J0 && input.0 < -1e300 { + // Errors get huge close to -inf + return XFAIL; + } + maybe_check_nan_bits(actual, expected, ctx) } @@ -364,6 +383,7 @@ impl MaybeOverride<(i32, f32)> for SpecialCase { } } } + impl MaybeOverride<(i32, f64)> for SpecialCase { fn check_float( input: (i32, f64), From f8a184e6af9540e0329fd50944c604d82ba1fb14 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 2 Jan 2025 10:25:27 +0000 Subject: [PATCH 1512/4206] Run extensive tests in CI when relevant files change Add a CI job with a dynamically calculated matrix that runs extensive jobs on changed files. This makes use of the new `function-definitions.json` file to determine which changed files require full tests for a routine to run. --- .../libm/.github/workflows/main.yml | 59 ++++++- .../libm/ci/calculate-exhaustive-matrix.py | 148 ++++++++++++++++++ 2 files changed, 206 insertions(+), 1 deletion(-) create mode 100755 library/compiler-builtins/libm/ci/calculate-exhaustive-matrix.py diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 023ec58c06a2e..1b2fd12ba87e1 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -14,7 +14,7 @@ env: jobs: test: name: Build and test - timeout-minutes: 20 + timeout-minutes: 25 strategy: fail-fast: false matrix: @@ -186,6 +186,62 @@ jobs: rustup component add rustfmt - run: cargo fmt -- --check + # Determine which extensive tests should be run based on changed files. + calculate_extensive_matrix: + name: Calculate job matrix + runs-on: ubuntu-24.04 + outputs: + matrix: ${{ steps.script.outputs.matrix }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 100 + - name: Fetch pull request ref + run: git fetch origin "$GITHUB_REF:$GITHUB_REF" + - run: python3 ci/calculate-exhaustive-matrix.py >> "$GITHUB_OUTPUT" + id: script + + extensive: + name: Extensive tests for ${{ matrix.ty }} + needs: + # Wait on `clippy` so we have some confidence that the crate will build + - clippy + - calculate_extensive_matrix + runs-on: ubuntu-24.04 + timeout-minutes: 80 + strategy: + matrix: + # Use the output from `calculate_extensive_matrix` to calculate the matrix + # FIXME: it would be better to run all jobs (i.e. all types) but mark those that + # didn't change as skipped, rather than completely excluding the job. However, + # this is not currently possible https://github.com/actions/runner/issues/1985. + include: ${{ fromJSON(needs.calculate_extensive_matrix.outputs.matrix).matrix }} + env: + CHANGED: ${{ matrix.changed }} + steps: + - uses: actions/checkout@v4 + - name: Install Rust + run: | + rustup update nightly --no-self-update + rustup default nightly + - uses: Swatinem/rust-cache@v2 + - name: Download musl source + run: ./ci/download-musl.sh + - name: Run extensive tests + run: | + echo "Changed: '$CHANGED'" + if [ -z "$CHANGED" ]; then + echo "No tests to run, exiting." + exit + fi + + LIBM_EXTENSIVE_TESTS="$CHANGED" cargo t \ + --features test-multiprecision,unstable \ + --release -- extensive + - name: Print test logs if available + run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi + shell: bash + success: needs: - test @@ -193,6 +249,7 @@ jobs: - benchmarks - msrv - rustfmt + - extensive runs-on: ubuntu-24.04 # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency # failed" as success. So we have to do some contortions to ensure the job fails if any of its diff --git a/library/compiler-builtins/libm/ci/calculate-exhaustive-matrix.py b/library/compiler-builtins/libm/ci/calculate-exhaustive-matrix.py new file mode 100755 index 0000000000000..8b42f9389f93b --- /dev/null +++ b/library/compiler-builtins/libm/ci/calculate-exhaustive-matrix.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python3 +"""Calculate which exhaustive tests should be run as part of CI. + +This dynamically prepares a list of routines that had a source file change based on +git history. +""" + +import subprocess as sp +import sys +import json +from dataclasses import dataclass +from os import getenv +from pathlib import Path +from typing import TypedDict + + +REPO_ROOT = Path(__file__).parent.parent +GIT = ["git", "-C", REPO_ROOT] + +# Don't run exhaustive tests if these files change, even if they contaiin a function +# definition. +IGNORE_FILES = [ + "src/math/support/", + "src/libm_helper.rs", + "src/math/arch/intrinsics.rs", +] + +TYPES = ["f16", "f32", "f64", "f128"] + + +class FunctionDef(TypedDict): + """Type for an entry in `function-definitions.json`""" + + sources: list[str] + type: str + + +@dataclass +class Context: + gh_ref: str | None + changed: list[Path] + defs: dict[str, FunctionDef] + + def __init__(self) -> None: + self.gh_ref = getenv("GITHUB_REF") + self.changed = [] + self._init_change_list() + + with open(REPO_ROOT.joinpath("etc/function-definitions.json")) as f: + defs = json.load(f) + + defs.pop("__comment", None) + self.defs = defs + + def _init_change_list(self): + """Create a list of files that have been changed. This uses GITHUB_REF if + available, otherwise a diff between `HEAD` and `master`. + """ + + # For pull requests, GitHub creates a ref `refs/pull/1234/merge` (1234 being + # the PR number), and sets this as `GITHUB_REF`. + ref = self.gh_ref + eprint(f"using ref `{ref}`") + if ref is None or "merge" not in ref: + # If the ref is not for `merge` then we are not in PR CI + eprint("No diff available for ref") + return + + # The ref is for a dummy merge commit. We can extract the merge base by + # inspecting all parents (`^@`). + merge_sha = sp.check_output( + GIT + ["show-ref", "--hash", ref], text=True + ).strip() + merge_log = sp.check_output(GIT + ["log", "-1", merge_sha], text=True) + eprint(f"Merge:\n{merge_log}\n") + + parents = ( + sp.check_output(GIT + ["rev-parse", f"{merge_sha}^@"], text=True) + .strip() + .splitlines() + ) + assert len(parents) == 2, f"expected two-parent merge but got:\n{parents}" + base = parents[0].strip() + incoming = parents[1].strip() + + eprint(f"base: {base}, incoming: {incoming}") + textlist = sp.check_output( + GIT + ["diff", base, incoming, "--name-only"], text=True + ) + self.changed = [Path(p) for p in textlist.splitlines()] + + @staticmethod + def _ignore_file(fname: str) -> bool: + return any(fname.startswith(pfx) for pfx in IGNORE_FILES) + + def changed_routines(self) -> dict[str, list[str]]: + """Create a list of routines for which one or more files have been updated, + separated by type. + """ + routines = set() + for name, meta in self.defs.items(): + # Don't update if changes to the file should be ignored + sources = (f for f in meta["sources"] if not self._ignore_file(f)) + + # Select changed files + changed = [f for f in sources if Path(f) in self.changed] + + if len(changed) > 0: + eprint(f"changed files for {name}: {changed}") + routines.add(name) + + ret = {} + for r in sorted(routines): + ret.setdefault(self.defs[r]["type"], []).append(r) + + return ret + + def make_workflow_output(self) -> str: + """Create a JSON object a list items for each type's changed files, if any + did change, and the routines that were affected by the change. + """ + changed = self.changed_routines() + ret = [] + for ty in TYPES: + ty_changed = changed.get(ty, []) + item = { + "ty": ty, + "changed": ",".join(ty_changed), + } + ret.append(item) + output = json.dumps({"matrix": ret}, separators=(",", ":")) + eprint(f"output: {output}") + return output + + +def eprint(*args, **kwargs): + """Print to stderr.""" + print(*args, file=sys.stderr, **kwargs) + + +def main(): + ctx = Context() + output = ctx.make_workflow_output() + print(f"matrix={output}") + + +if __name__ == "__main__": + main() From aabb7d9dcc9037579df402cbb45abbac2e3f551c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 2 Jan 2025 21:41:58 +0000 Subject: [PATCH 1513/4206] Enable `f16` and `f128` when creating the API change list Additionally, read glob output as absoulte paths. This enables the script to work properly even when invoked from a different directory. --- library/compiler-builtins/libm/etc/update-api-list.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/etc/update-api-list.py b/library/compiler-builtins/libm/etc/update-api-list.py index a4587aa81d534..67f73e59cf140 100755 --- a/library/compiler-builtins/libm/etc/update-api-list.py +++ b/library/compiler-builtins/libm/etc/update-api-list.py @@ -13,6 +13,7 @@ from typing import Any, TypeAlias ETC_DIR = Path(__file__).parent +ROOT_DIR = ETC_DIR.parent IndexTy: TypeAlias = dict[str, dict[str, Any]] """Type of the `index` item in rustdoc's JSON output""" @@ -56,10 +57,12 @@ def get_rustdoc_json() -> dict[Any, Any]: "--edition=2021", "--document-private-items", "--output-format=json", + "--cfg=f16_enabled", + "--cfg=f128_enabled", "-Zunstable-options", "-o-", ], - cwd=ETC_DIR.parent, + cwd=ROOT_DIR, text=True, ) j = json.loads(j) @@ -105,8 +108,8 @@ def _init_defs(self, index: IndexTy) -> None: # A lot of the `arch` module is often configured out so doesn't show up in docs. Use # string matching as a fallback. - for fname in glob("src/math/arch/**.rs", root_dir=ETC_DIR.parent): - contents = Path(fname).read_text() + for fname in glob("src/math/arch/**.rs", root_dir=ROOT_DIR): + contents = (ROOT_DIR.joinpath(fname)).read_text() for name in self.public_functions: if f"fn {name}" in contents: From 42c7ace5ba74b78bb06765438a9dd6f6fa57d58f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 2 Jan 2025 21:11:50 +0000 Subject: [PATCH 1514/4206] Add `fabsf16`, `fabsf128`, `copysignf16`, and `copysignf128` Use the generic implementations to provide these simple methods. --- .../compiler-builtins/libm/src/libm_helper.rs | 24 ++++++++++-- .../libm/src/math/copysignf128.rs | 8 ++++ .../libm/src/math/copysignf16.rs | 8 ++++ .../compiler-builtins/libm/src/math/fabs.rs | 1 + .../compiler-builtins/libm/src/math/fabsf.rs | 1 + .../libm/src/math/fabsf128.rs | 37 +++++++++++++++++++ .../libm/src/math/fabsf16.rs | 37 +++++++++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 20 ++++++++++ 8 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/copysignf128.rs create mode 100644 library/compiler-builtins/libm/src/math/copysignf16.rs create mode 100644 library/compiler-builtins/libm/src/math/fabsf128.rs create mode 100644 library/compiler-builtins/libm/src/math/fabsf16.rs diff --git a/library/compiler-builtins/libm/src/libm_helper.rs b/library/compiler-builtins/libm/src/libm_helper.rs index 52d0c4c2a11e4..f087267e46c7e 100644 --- a/library/compiler-builtins/libm/src/libm_helper.rs +++ b/library/compiler-builtins/libm/src/libm_helper.rs @@ -30,7 +30,7 @@ macro_rules! libm_helper { } }; - ({$($func:tt);*}) => { + ({$($func:tt;)*}) => { $( libm_helper! { $func } )* @@ -103,7 +103,7 @@ libm_helper! { (fn trunc(x: f32) -> (f32); => truncf); (fn y0(x: f32) -> (f32); => y0f); (fn y1(x: f32) -> (f32); => y1f); - (fn yn(n: i32, x: f32) -> (f32); => ynf) + (fn yn(n: i32, x: f32) -> (f32); => ynf); } } @@ -166,6 +166,24 @@ libm_helper! { (fn trunc(x: f64) -> (f64); => trunc); (fn y0(x: f64) -> (f64); => y0); (fn y1(x: f64) -> (f64); => y1); - (fn yn(n: i32, x: f64) -> (f64); => yn) + (fn yn(n: i32, x: f64) -> (f64); => yn); + } +} + +#[cfg(f16_enabled)] +libm_helper! { + f16, + funcs: { + (fn copysign(x: f16, y: f16) -> (f16); => copysignf16); + (fn fabs(x: f16) -> (f16); => fabsf16); + } +} + +#[cfg(f128_enabled)] +libm_helper! { + f128, + funcs: { + (fn copysign(x: f128, y: f128) -> (f128); => copysignf128); + (fn fabs(x: f128) -> (f128); => fabsf128); } } diff --git a/library/compiler-builtins/libm/src/math/copysignf128.rs b/library/compiler-builtins/libm/src/math/copysignf128.rs new file mode 100644 index 0000000000000..7bd81d42b2e9a --- /dev/null +++ b/library/compiler-builtins/libm/src/math/copysignf128.rs @@ -0,0 +1,8 @@ +/// Sign of Y, magnitude of X (f128) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf128(x: f128, y: f128) -> f128 { + super::generic::copysign(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/copysignf16.rs b/library/compiler-builtins/libm/src/math/copysignf16.rs new file mode 100644 index 0000000000000..8206586860102 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/copysignf16.rs @@ -0,0 +1,8 @@ +/// Sign of Y, magnitude of X (f16) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf16(x: f16, y: f16) -> f16 { + super::generic::copysign(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index 6687fdcc35633..46c0d88a5c045 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -1,4 +1,5 @@ /// Absolute value (magnitude) (f64) +/// /// Calculates the absolute value (magnitude) of the argument `x`, /// by direct manipulation of the bit representation of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index 99bb5b5f1c9d5..d5775b600d97a 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -1,4 +1,5 @@ /// Absolute value (magnitude) (f32) +/// /// Calculates the absolute value (magnitude) of the argument `x`, /// by direct manipulation of the bit representation of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] diff --git a/library/compiler-builtins/libm/src/math/fabsf128.rs b/library/compiler-builtins/libm/src/math/fabsf128.rs new file mode 100644 index 0000000000000..ef531bd91a454 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fabsf128.rs @@ -0,0 +1,37 @@ +/// Absolute value (magnitude) (f128) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf128(x: f128) -> f128 { + select_implementation! { + name: fabsf, + use_intrinsic: target_arch = "wasm32", + args: x, + } + + super::generic::fabs(x) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sanity_check() { + assert_eq!(fabsf128(-1.0), 1.0); + assert_eq!(fabsf128(2.8), 2.8); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs + #[test] + fn spec_tests() { + assert!(fabsf128(f128::NAN).is_nan()); + for f in [0.0, -0.0].iter().copied() { + assert_eq!(fabsf128(f), 0.0); + } + for f in [f128::INFINITY, f128::NEG_INFINITY].iter().copied() { + assert_eq!(fabsf128(f), f128::INFINITY); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/fabsf16.rs b/library/compiler-builtins/libm/src/math/fabsf16.rs new file mode 100644 index 0000000000000..eb41f7391e51e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fabsf16.rs @@ -0,0 +1,37 @@ +/// Absolute value (magnitude) (f16) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf16(x: f16) -> f16 { + select_implementation! { + name: fabsf, + use_intrinsic: target_arch = "wasm32", + args: x, + } + + super::generic::fabs(x) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sanity_check() { + assert_eq!(fabsf16(-1.0), 1.0); + assert_eq!(fabsf16(2.8), 2.8); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs + #[test] + fn spec_tests() { + assert!(fabsf16(f16::NAN).is_nan()); + for f in [0.0, -0.0].iter().copied() { + assert_eq!(fabsf16(f), 0.0); + } + for f in [f16::INFINITY, f16::NEG_INFINITY].iter().copied() { + assert_eq!(fabsf16(f), f16::INFINITY); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 9003a83428806..5baf35e424533 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -339,6 +339,26 @@ pub use self::tgammaf::tgammaf; pub use self::trunc::trunc; pub use self::truncf::truncf; +cfg_if! { + if #[cfg(f16_enabled)] { + mod copysignf16; + mod fabsf16; + + pub use self::copysignf16::copysignf16; + pub use self::fabsf16::fabsf16; + } +} + +cfg_if! { + if #[cfg(f128_enabled)] { + mod copysignf128; + mod fabsf128; + + pub use self::copysignf128::copysignf128; + pub use self::fabsf128::fabsf128; + } +} + #[inline] fn get_high_word(x: f64) -> u32 { (x.to_bits() >> 32) as u32 From 6b5e8b20f0ca6573307f68f4fdbfc177bcb3850f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 3 Jan 2025 00:12:53 +0000 Subject: [PATCH 1515/4206] Add test infrastructure for `f16` and `f128` Update test traits to support `f16` and `f128`, as applicable. Add the new routines (`fabs` and `copysign` for `f16` and `f128`) to the list of all operations. --- .../libm/crates/libm-macros/src/shared.rs | 28 +++++++ .../libm/crates/libm-test/Cargo.toml | 2 +- .../libm/crates/libm-test/benches/random.rs | 47 ++++++----- .../libm/crates/libm-test/src/domain.rs | 12 +++ .../crates/libm-test/src/gen/extensive.rs | 4 + .../libm/crates/libm-test/src/gen/random.rs | 4 + .../libm/crates/libm-test/src/mpfloat.rs | 77 +++++++++++++------ .../libm/crates/libm-test/src/precision.rs | 32 ++++++++ .../libm/crates/libm-test/src/test_traits.rs | 6 ++ .../libm-test/tests/compare_built_musl.rs | 2 + .../crates/libm-test/tests/multiprecision.rs | 2 + .../libm/etc/function-definitions.json | 28 +++++++ .../libm/etc/function-list.txt | 4 + 13 files changed, 205 insertions(+), 43 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index ef0f188014b79..16547404fffa1 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -4,6 +4,13 @@ use std::fmt; use std::sync::LazyLock; const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] = &[ + ( + // `fn(f16) -> f16` + FloatTy::F16, + Signature { args: &[Ty::F16], returns: &[Ty::F16] }, + None, + &["fabsf16"], + ), ( // `fn(f32) -> f32` FloatTy::F32, @@ -28,6 +35,20 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "tgamma", "trunc", "y0", "y1", ], ), + ( + // `fn(f128) -> f128` + FloatTy::F128, + Signature { args: &[Ty::F128], returns: &[Ty::F128] }, + None, + &["fabsf128"], + ), + ( + // `(f16, f16) -> f16` + FloatTy::F16, + Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16] }, + None, + &["copysignf16"], + ), ( // `(f32, f32) -> f32` FloatTy::F32, @@ -64,6 +85,13 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "remainder", ], ), + ( + // `(f128, f128) -> f128` + FloatTy::F128, + Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128] }, + None, + &["copysignf128"], + ), ( // `(f32, f32, f32) -> f32` FloatTy::F32, diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 69e96034ef822..2761d3d521333 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -8,7 +8,7 @@ publish = false default = ["unstable-float"] # Propagated from libm because this affects which functions we test. -unstable-float = ["libm/unstable-float"] +unstable-float = ["libm/unstable-float", "rug?/nightly-float"] # Generate tests which are random inputs and the outputs are calculated with # musl libc. diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 23f4294558328..cd1e2d2ccc6ff 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -20,7 +20,7 @@ macro_rules! musl_rand_benches { ( fn_name: $fn_name:ident, attrs: [$($attr:meta),*], - fn_extra: $skip_on_i586:expr, + fn_extra: ($skip_on_i586:expr, $musl_fn:expr), ) => { paste::paste! { $(#[$attr])* @@ -28,15 +28,15 @@ macro_rules! musl_rand_benches { type Op = libm_test::op::$fn_name::Routine; #[cfg(feature = "build-musl")] - let musl_extra = MuslExtra { - musl_fn: Some(musl_math_sys::$fn_name as libm_test::OpCFn), - skip_on_i586: $skip_on_i586 + let musl_extra = MuslExtra::> { + musl_fn: $musl_fn, + skip_on_i586: $skip_on_i586, }; #[cfg(not(feature = "build-musl"))] let musl_extra = MuslExtra { musl_fn: None, - skip_on_i586: $skip_on_i586 + skip_on_i586: $skip_on_i586, }; bench_one::(c, musl_extra); @@ -67,7 +67,10 @@ where break; } - let musl_res = input.call(musl_extra.musl_fn.unwrap()); + let Some(musl_fn) = musl_extra.musl_fn else { + continue; + }; + let musl_res = input.call(musl_fn); let crate_res = input.call(Op::ROUTINE); crate_res.validate(musl_res, input, &ctx).context(name).unwrap(); @@ -91,15 +94,16 @@ where // Don't test against musl if it is not available #[cfg(feature = "build-musl")] { - let musl_fn = musl_extra.musl_fn.unwrap(); - group.bench_function("musl", |b| { - b.iter(|| { - let f = black_box(musl_fn); - for input in benchvec.iter().copied() { - input.call(f); - } - }) - }); + if let Some(musl_fn) = musl_extra.musl_fn { + group.bench_function("musl", |b| { + b.iter(|| { + let f = black_box(musl_fn); + for input in benchvec.iter().copied() { + input.call(f); + } + }) + }); + } } } @@ -107,9 +111,16 @@ libm_macros::for_each_function! { callback: musl_rand_benches, skip: [], fn_extra: match MACRO_FN_NAME { - // FIXME(correctness): wrong result on i586 - exp10 | exp10f | exp2 | exp2f => true, - _ => false + // We pass a tuple of `(skip_on_i586, musl_fn)` + + // FIXME(correctness): exp functions have the wrong result on i586 + exp10 | exp10f | exp2 | exp2f => (true, Some(musl_math_sys::MACRO_FN_NAME)), + + // Musl does not provide `f16` and `f128` functions + copysignf16 | copysignf128 | fabsf16 | fabsf128 => (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/crates/libm-test/src/domain.rs b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs index 7b5a01b968340..52393d40243ec 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs @@ -187,3 +187,15 @@ impl HasDomain for crate::op::lgammaf_r::Routine { impl HasDomain for crate::op::lgamma_r::Routine { const DOMAIN: Domain = Domain::::LGAMMA; } + +/* Not all `f16` and `f128` functions exist yet so we can't easily use the macros. */ + +#[cfg(f16_enabled)] +impl HasDomain for crate::op::fabsf16::Routine { + const DOMAIN: Domain = Domain::::UNBOUNDED; +} + +#[cfg(f128_enabled)] +impl HasDomain for crate::op::fabsf128::Routine { + const DOMAIN: Domain = Domain::::UNBOUNDED; +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs index d8b991b2a5f33..d724226e95be9 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs @@ -138,8 +138,12 @@ macro_rules! impl_extensive_input { }; } +#[cfg(f16_enabled)] +impl_extensive_input!(f16); impl_extensive_input!(f32); impl_extensive_input!(f64); +#[cfg(f128_enabled)] +impl_extensive_input!(f128); /// Create a test case iterator for extensive inputs. pub fn get_test_cases( diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index 29a9dcd2b0825..6b08e560dff56 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -107,8 +107,12 @@ macro_rules! impl_random_input { }; } +#[cfg(f16_enabled)] +impl_random_input!(f16); impl_random_input!(f32); impl_random_input!(f64); +#[cfg(f128_enabled)] +impl_random_input!(f128); /// Create a test case iterator. pub fn get_test_cases( diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index ad98fafc87d16..f2b7b2f25da99 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -137,6 +137,7 @@ libm_macros::for_each_function! { fmod, fmodf, frexp, frexpf, ilogb, ilogbf, jn, jnf, ldexp, ldexpf, lgamma_r, lgammaf_r, modf, modff, nextafter, nextafterf, pow,powf, remquo, remquof, scalbn, scalbnf, sincos, sincosf, yn, ynf, + copysignf16, copysignf128, fabsf16, fabsf128, ], fn_extra: match MACRO_FN_NAME { // Remap function names that are different between mpfr and libm @@ -157,10 +158,8 @@ libm_macros::for_each_function! { /// Implement unary functions that don't have a `_round` version macro_rules! impl_no_round { // Unary matcher - ($($fn_name:ident, $rug_name:ident;)*) => { + ($($fn_name:ident => $rug_name:ident;)*) => { paste::paste! { - // Implement for both f32 and f64 - $( impl_no_round!{ @inner_unary [< $fn_name f >], $rug_name } )* $( impl_no_round!{ @inner_unary $fn_name, $rug_name } )* } }; @@ -183,33 +182,34 @@ macro_rules! impl_no_round { } impl_no_round! { - fabs, abs_mut; - ceil, ceil_mut; - floor, floor_mut; - rint, round_even_mut; // FIXME: respect rounding mode - round, round_mut; - trunc, trunc_mut; + ceil => ceil_mut; + ceilf => ceil_mut; + fabs => abs_mut; + fabsf => abs_mut; + floor => floor_mut; + floorf => floor_mut; + rint => round_even_mut; // FIXME: respect rounding mode + rintf => round_even_mut; // FIXME: respect rounding mode + round => round_mut; + roundf => round_mut; + trunc => trunc_mut; + truncf => trunc_mut; +} + +#[cfg(f16_enabled)] +impl_no_round! { + fabsf16 => abs_mut; +} + +#[cfg(f128_enabled)] +impl_no_round! { + fabsf128 => abs_mut; } /// Some functions are difficult to do in a generic way. Implement them here. macro_rules! impl_op_for_ty { ($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); - this.0.copysign_mut(&this.1); - prep_retval::(&mut this.0, Ordering::Equal) - } - } - impl MpOp for crate::op::[]::Routine { type MpTy = (MpFloat, MpFloat); @@ -379,9 +379,38 @@ macro_rules! impl_op_for_ty { }; } +/// Version of `impl_op_for_ty` with only functions that have `f16` and `f128` implementations. +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); + this.0.copysign_mut(&this.1); + prep_retval::(&mut this.0, Ordering::Equal) + } + } + } + }; +} + impl_op_for_ty!(f32, "f"); impl_op_for_ty!(f64, ""); +#[cfg(f16_enabled)] +impl_op_for_ty_all!(f16, "f16"); +impl_op_for_ty_all!(f32, "f"); +impl_op_for_ty_all!(f64, ""); +#[cfg(f128_enabled)] +impl_op_for_ty_all!(f128, "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/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 696bb373578d4..f8c3a7b8fcf35 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -157,6 +157,9 @@ pub trait MaybeOverride { } } +#[cfg(f16_enabled)] +impl MaybeOverride<(f16,)> for SpecialCase {} + impl MaybeOverride<(f32,)> for SpecialCase { fn check_float( input: (f32,), @@ -290,6 +293,9 @@ impl MaybeOverride<(f64,)> for SpecialCase { } } +#[cfg(f128_enabled)] +impl MaybeOverride<(f128,)> for SpecialCase {} + /// Check NaN bits if the function requires it fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Option { if !(ctx.base_name == BaseName::Fabs || ctx.base_name == BaseName::Copysign) { @@ -317,6 +323,19 @@ fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Opt } } +#[cfg(f16_enabled)] +impl MaybeOverride<(f16, f16)> for SpecialCase { + fn check_float( + input: (f16, f16), + _actual: F, + expected: F, + _ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + maybe_skip_binop_nan(input, expected, ctx) + } +} + impl MaybeOverride<(f32, f32)> for SpecialCase { fn check_float( input: (f32, f32), @@ -341,6 +360,19 @@ impl MaybeOverride<(f64, f64)> for SpecialCase { } } +#[cfg(f128_enabled)] +impl MaybeOverride<(f128, f128)> for SpecialCase { + fn check_float( + input: (f128, f128), + _actual: F, + expected: F, + _ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + maybe_skip_binop_nan(input, expected, ctx) + } +} + /// Musl propagates NaNs if one is provided as the input, but we return the other input. // F1 and F2 are always the same type, this is just to please generics fn maybe_skip_binop_nan( diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index 261d1f2540d48..0a4baa2e36f74 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -303,6 +303,12 @@ where impl_float!(f32, f64); +#[cfg(f16_enabled)] +impl_float!(f16); + +#[cfg(f128_enabled)] +impl_float!(f128); + /* trait implementations for compound types */ /// Implement `CheckOutput` for combinations of types. diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index ecd379a0a6865..3e11d322acd7a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -46,6 +46,8 @@ where libm_macros::for_each_function! { callback: musl_rand_tests, + // Musl does not support `f16` and `f128` on all platforms. + skip: [copysignf16, copysignf128, fabsf16, fabsf128], attributes: [ #[cfg_attr(x86_no_sse, ignore)] // FIXME(correctness): wrong result on i586 [exp10, exp10f, exp2, exp2f, rint] diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 42ec965c1440a..7961b0802589e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -120,6 +120,8 @@ libm_macros::for_each_function! { atan2f, copysign, copysignf, + copysignf16, + copysignf128, fdim, fdimf, fma, diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 4b10812c3a7bb..0b2d6214f76c9 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -136,6 +136,20 @@ ], "type": "f32" }, + "copysignf128": { + "sources": [ + "src/math/copysignf128.rs", + "src/math/generic/copysign.rs" + ], + "type": "f128" + }, + "copysignf16": { + "sources": [ + "src/math/copysignf16.rs", + "src/math/generic/copysign.rs" + ], + "type": "f16" + }, "cos": { "sources": [ "src/libm_helper.rs", @@ -258,6 +272,20 @@ ], "type": "f32" }, + "fabsf128": { + "sources": [ + "src/math/fabsf128.rs", + "src/math/generic/fabs.rs" + ], + "type": "f128" + }, + "fabsf16": { + "sources": [ + "src/math/fabsf16.rs", + "src/math/generic/fabs.rs" + ], + "type": "f16" + }, "fdim": { "sources": [ "src/libm_helper.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 51f5b221c26f3..0a1bbab244d62 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -19,6 +19,8 @@ ceil ceilf copysign copysignf +copysignf128 +copysignf16 cos cosf cosh @@ -37,6 +39,8 @@ expm1 expm1f fabs fabsf +fabsf128 +fabsf16 fdim fdimf floor From a3363785ea5e496e8dd925abe611169a6c11cbab Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 28 Dec 2024 09:52:19 +0000 Subject: [PATCH 1516/4206] Add domain and edge case tests to musl This provides an increase in test coverage on platforms that cannot test against MPFR. --- .../libm/crates/libm-test/src/lib.rs | 4 +- .../libm/crates/libm-test/src/op.rs | 2 + .../libm-test/tests/compare_built_musl.rs | 97 ++++++++++++++++++- 3 files changed, 101 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index a940db1d20665..251114a0dcb9a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -23,7 +23,9 @@ use std::time::SystemTime; pub use f8_impl::f8; pub use libm::support::{Float, Int, IntTy, MinInt}; pub use num::{FloatExt, logspace}; -pub use op::{BaseName, FloatTy, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet, Ty}; +pub use op::{ + BaseName, FloatTy, Identifier, MathOp, OpCFn, OpCRet, OpFTy, OpRustFn, OpRustRet, Ty, +}; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; use run_cfg::EXTENSIVE_MAX_ITERATIONS; pub use run_cfg::{CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind, skip_extensive_test}; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/op.rs b/library/compiler-builtins/libm/crates/libm-test/src/op.rs index ee61eb0b84067..8329d3424c324 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/op.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/op.rs @@ -96,6 +96,8 @@ pub type OpFTy = ::FTy; pub type OpITy = <::FTy as Float>::Int; /// Access the associated `CFn` type from an op (helper to avoid ambiguous associated types). pub type OpCFn = ::CFn; +/// Access the associated `CRet` type from an op (helper to avoid ambiguous associated types). +pub type OpCRet = ::CRet; /// Access the associated `RustFn` type from an op (helper to avoid ambiguous associated types). pub type OpRustFn = ::RustFn; /// Access the associated `RustRet` type from an op (helper to avoid ambiguous associated types). diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 3e11d322acd7a..b91d7f9f50d9f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -9,8 +9,9 @@ // There are some targets we can't build musl for #![cfg(feature = "build-musl")] -use libm_test::gen::random; +use libm_test::domain::HasDomain; use libm_test::gen::random::RandomInput; +use libm_test::gen::{domain_logspace, edge_cases, random}; use libm_test::{CheckBasis, CheckCtx, CheckOutput, MathOp, TupleCall}; macro_rules! musl_rand_tests { @@ -53,3 +54,97 @@ libm_macros::for_each_function! { [exp10, exp10f, exp2, exp2f, rint] ], } + +/// Test against musl with generators from a domain. +macro_rules! musl_domain_tests { + ( + fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], + ) => { + paste::paste! { + #[test] + $(#[$attr])* + fn [< musl_edge_case_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + domain_test_runner::( + edge_cases::get_test_cases::, + musl_math_sys::$fn_name, + ); + } + + #[test] + $(#[$attr])* + fn [< musl_logspace_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + domain_test_runner::( + domain_logspace::get_test_cases::, + musl_math_sys::$fn_name, + ); + } + } + }; +} + +/// Test a single routine against domaine-aware inputs. +fn domain_test_runner(gen: impl FnOnce(&CheckCtx) -> I, musl_fn: Op::CFn) +where + Op: MathOp, + Op: HasDomain, + I: Iterator, +{ + let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl); + let cases = gen(&ctx); + + for input in cases { + let musl_res = input.call(musl_fn); + let crate_res = input.call(Op::ROUTINE); + + crate_res.validate(musl_res, input, &ctx).unwrap(); + } +} + +libm_macros::for_each_function! { + callback: musl_domain_tests, + attributes: [], + skip: [ + // Functions with multiple inputs + atan2, + atan2f, + copysign, + copysignf, + copysignf16, + copysignf128, + fdim, + fdimf, + fma, + fmaf, + fmax, + fmaxf, + fmin, + fminf, + fmod, + fmodf, + hypot, + hypotf, + jn, + jnf, + ldexp, + ldexpf, + nextafter, + nextafterf, + pow, + powf, + remainder, + remainderf, + remquo, + remquof, + scalbn, + scalbnf, + yn, + ynf, + + // Not provided by musl + fabsf16, + fabsf128, + ], +} From 4b014bff40c0fffe97fd64f854c152c0d33b4973 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 Jan 2025 09:26:27 +0000 Subject: [PATCH 1517/4206] Add an override for failing ceil/floor tests on i586 --- .../libm/crates/libm-test/src/precision.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index f8c3a7b8fcf35..817ea0fae644b 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -270,6 +270,16 @@ impl MaybeOverride<(f64,)> for SpecialCase { return XFAIL; } + if (ctx.fn_ident == Identifier::Ceil || ctx.fn_ident == Identifier::Floor) + && expected.eq_repr(F::NEG_ZERO) + && actual.eq_repr(F::ZERO) + && cfg!(x86_no_sse) + { + // FIXME: the x87 implementations do not keep the distinction between -0.0 and 0.0. + // See https://github.com/rust-lang/libm/pull/404#issuecomment-2572399955 + return XFAIL; + } + maybe_check_nan_bits(actual, expected, ctx) } From 449d41a24fffd282b088c4b2967e5c3e9899189c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 Jan 2025 09:46:16 +0000 Subject: [PATCH 1518/4206] Loosen precision on i586 based on new tests --- .../libm/crates/libm-test/src/precision.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 817ea0fae644b..1a66a430c50ae 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -106,7 +106,11 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { match ctx.fn_ident { Id::Asinh => ulp = 3, Id::Asinhf => ulp = 3, + Id::Exp10 | Id::Exp10f => ulp = 1_000_000, + Id::Exp2 | Id::Exp2f => ulp = 10_000_000, + Id::Fmaf => ulp = 1, Id::Log1p | Id::Log1pf => ulp = 2, + Id::Rint => ulp = 100_000, Id::Round => ulp = 1, Id::Tan => ulp = 2, _ => (), @@ -271,15 +275,23 @@ impl MaybeOverride<(f64,)> for SpecialCase { } if (ctx.fn_ident == Identifier::Ceil || ctx.fn_ident == Identifier::Floor) + && cfg!(x86_no_sse) && expected.eq_repr(F::NEG_ZERO) && actual.eq_repr(F::ZERO) - && cfg!(x86_no_sse) { // FIXME: the x87 implementations do not keep the distinction between -0.0 and 0.0. // See https://github.com/rust-lang/libm/pull/404#issuecomment-2572399955 return XFAIL; } + if (ctx.fn_ident == Identifier::Exp10 || ctx.fn_ident == Identifier::Exp2) + && cfg!(x86_no_sse) + { + // FIXME: i586 has very imprecise results with ULP > u32::MAX for these + // operations so we can't reasonably provide a limit. + return XFAIL; + } + maybe_check_nan_bits(actual, expected, ctx) } From a882639e7f76d6f599840fa23e691c4dc30cc5f2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 Jan 2025 20:17:38 +0000 Subject: [PATCH 1519/4206] ci: Only update the github ref for pull requests On master, this fetch fails with: fatal: refusing to fetch into branch 'refs/heads/master' checked out at '/home/runner/work/libm/libm' Just skip the command when this shouldn't be needed. --- library/compiler-builtins/libm/.github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 1b2fd12ba87e1..320800f2ea7e6 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -198,6 +198,7 @@ jobs: fetch-depth: 100 - name: Fetch pull request ref run: git fetch origin "$GITHUB_REF:$GITHUB_REF" + if: github.event_name == 'pull_request' - run: python3 ci/calculate-exhaustive-matrix.py >> "$GITHUB_OUTPUT" id: script From a9407010b4fc2c5971f639d65b3c6585f2779be5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 Jan 2025 05:15:40 +0000 Subject: [PATCH 1520/4206] Enable MPFR tests on i586 MPFR does build and run correctly without SSE, but requires `force-cross` be enabled. --- .../libm/ci/docker/i586-unknown-linux-gnu/Dockerfile | 2 +- library/compiler-builtins/libm/ci/run.sh | 2 +- library/compiler-builtins/libm/crates/libm-test/Cargo.toml | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile index 3b0bfc0d3d9d2..37e206a84fcb5 100644 --- a/library/compiler-builtins/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile @@ -2,4 +2,4 @@ FROM ubuntu:24.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ - gcc-multilib libc6-dev ca-certificates + gcc-multilib m4 make libc6-dev ca-certificates diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 7e514a1cd2e51..70fc271f1941f 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -45,8 +45,8 @@ case "$target" in # FIXME(ci): we should be able to enable aarch64 Linux here once GHA # support rolls out. x86_64*) extra_flags="$extra_flags --features libm-test/test-multiprecision" ;; - # i686 works fine, i586 does not i686*) extra_flags="$extra_flags --features libm-test/test-multiprecision" ;; + i586*) extra_flags="$extra_flags --features libm-test/test-multiprecision --features gmp-mpfr-sys/force-cross" ;; # Apple aarch64 is native aarch64*apple*) extra_flags="$extra_flags --features libm-test/test-multiprecision" ;; esac diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 2761d3d521333..371beb19aa52a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -12,7 +12,7 @@ unstable-float = ["libm/unstable-float", "rug?/nightly-float"] # Generate tests which are random inputs and the outputs are calculated with # musl libc. -test-multiprecision = ["dep:az", "dep:rug"] +test-multiprecision = ["dep:az", "dep:rug", "dep:gmp-mpfr-sys"] # Build our own musl for testing and benchmarks build-musl = ["dep:musl-math-sys"] @@ -26,6 +26,7 @@ short-benchmarks = [] [dependencies] anyhow = "1.0.90" az = { version = "1.2.1", optional = true } +gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false, features = ["mpfr"] } indicatif = { version = "0.17.9", default-features = false } libm = { path = "../..", features = ["unstable-public-internals"] } libm-macros = { path = "../libm-macros" } From 05b87887f46fb81a8ac3d06cd582d8220ddd8702 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 Jan 2025 20:27:48 +0000 Subject: [PATCH 1521/4206] Increase the allowed precision for failing tests on i586 These will need to be fixed, for now just xfail them so this doesn't block better test coverage. --- .../compiler-builtins/libm/crates/libm-test/src/precision.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 1a66a430c50ae..03bf7ceccc375 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -104,11 +104,14 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { // 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::Asinh => ulp = 3, Id::Asinhf => ulp = 3, Id::Exp10 | Id::Exp10f => ulp = 1_000_000, Id::Exp2 | Id::Exp2f => ulp = 10_000_000, - Id::Fmaf => ulp = 1, Id::Log1p | Id::Log1pf => ulp = 2, Id::Rint => ulp = 100_000, Id::Round => ulp = 1, From ac9fec04efbe4e65ab15b868dcc9a95fcc3a7280 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 Jan 2025 21:57:29 +0000 Subject: [PATCH 1522/4206] Switch from using `unstable-intrinsics` to `intrinsics_enabled` Unlike `unstable-intrinsics`, `intrinsics_enabled` gets disabled with `force-soft-floats` which is what we want here. --- library/compiler-builtins/libm/src/math/arch/intrinsics.rs | 6 ++---- .../compiler-builtins/libm/src/math/support/float_traits.rs | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/arch/intrinsics.rs b/library/compiler-builtins/libm/src/math/arch/intrinsics.rs index 1cf9291f4c75e..733af0f1a96e6 100644 --- a/library/compiler-builtins/libm/src/math/arch/intrinsics.rs +++ b/library/compiler-builtins/libm/src/math/arch/intrinsics.rs @@ -12,13 +12,11 @@ pub fn ceilf(x: f32) -> f32 { } pub fn fabs(x: f64) -> f64 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::fabsf64(x) } + x.abs() } pub fn fabsf(x: f32) -> f32 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::fabsf32(x) } + x.abs() } pub fn floor(x: f64) -> f64 { 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 3b5be4fa3d3df..6970509665896 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -200,7 +200,7 @@ macro_rules! float_impl { fn abs(self) -> Self { cfg_if! { // FIXME(msrv): `abs` is available in `core` starting with 1.85. - if #[cfg(feature = "unstable-intrinsics")] { + if #[cfg(intrinsics_enabled)] { self.abs() } else { super::super::generic::fabs(self) @@ -210,7 +210,7 @@ macro_rules! float_impl { fn copysign(self, other: Self) -> Self { cfg_if! { // FIXME(msrv): `copysign` is available in `core` starting with 1.85. - if #[cfg(feature = "unstable-intrinsics")] { + if #[cfg(intrinsics_enabled)] { self.copysign(other) } else { super::super::generic::copysign(self, other) From b5a217b11c3ef6f4b22f82b67b0b06dc9cb739c9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 Jan 2025 22:52:01 +0000 Subject: [PATCH 1523/4206] Remove an unused `feature = "force-soft-floats"` gate --- library/compiler-builtins/libm/src/math/arch/i686.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/arch/i686.rs b/library/compiler-builtins/libm/src/math/arch/i686.rs index 80f7face17424..ad54d8b61d779 100644 --- a/library/compiler-builtins/libm/src/math/arch/i686.rs +++ b/library/compiler-builtins/libm/src/math/arch/i686.rs @@ -1,7 +1,5 @@ //! Architecture-specific support for x86-32 and x86-64 with SSE2 -#![cfg(not(feature = "force-soft-floats"))] - #[cfg(target_arch = "x86")] use core::arch::x86::*; #[cfg(target_arch = "x86_64")] From c5741455771caef8810428647b39b91f5b81d3ea Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 Jan 2025 23:17:38 +0000 Subject: [PATCH 1524/4206] Don't use intrinsics abs for `f16` and `f128` on wasm32 This configuration was duplicated from `fabs` and `fabsf`, but wasm is unlikely to have an intrinsic lowering for these float types. So, just always use the generic. --- library/compiler-builtins/libm/src/math/fabsf128.rs | 6 ------ library/compiler-builtins/libm/src/math/fabsf16.rs | 6 ------ 2 files changed, 12 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/fabsf128.rs b/library/compiler-builtins/libm/src/math/fabsf128.rs index ef531bd91a454..46429ca494033 100644 --- a/library/compiler-builtins/libm/src/math/fabsf128.rs +++ b/library/compiler-builtins/libm/src/math/fabsf128.rs @@ -4,12 +4,6 @@ /// by direct manipulation of the bit representation of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fabsf128(x: f128) -> f128 { - select_implementation! { - name: fabsf, - use_intrinsic: target_arch = "wasm32", - args: x, - } - super::generic::fabs(x) } diff --git a/library/compiler-builtins/libm/src/math/fabsf16.rs b/library/compiler-builtins/libm/src/math/fabsf16.rs index eb41f7391e51e..eee42ac6a3c60 100644 --- a/library/compiler-builtins/libm/src/math/fabsf16.rs +++ b/library/compiler-builtins/libm/src/math/fabsf16.rs @@ -4,12 +4,6 @@ /// by direct manipulation of the bit representation of `x`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fabsf16(x: f16) -> f16 { - select_implementation! { - name: fabsf, - use_intrinsic: target_arch = "wasm32", - args: x, - } - super::generic::fabs(x) } From f4f942c3e9aa46a3bd729dcf9721c5762936af9f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 6 Jan 2025 01:10:04 +0000 Subject: [PATCH 1525/4206] Update the `libm` submodule --- library/compiler-builtins/build.rs | 49 +++++++++++++++++++++++--- library/compiler-builtins/configure.rs | 8 +++++ library/compiler-builtins/libm | 2 +- library/compiler-builtins/src/math.rs | 1 + 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 22ec9e4d27549..2bb8651d7f7f7 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -14,12 +14,9 @@ fn main() { configure_check_cfg(); configure_f16_f128(&target); - println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display()); + configure_libm(&target); - // Activate libm's unstable features to make full use of Nightly. - println!("cargo::rustc-check-cfg=cfg(feature, values(\"unstable\", \"force-soft-floats\"))"); - println!("cargo:rustc-cfg=feature=\"unstable\""); - println!("cargo:rustc-cfg=feature=\"force-soft-floats\""); + println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display()); // Emscripten's runtime includes all the builtins if target.os == "emscripten" { @@ -104,6 +101,48 @@ fn main() { } } +/// 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"); + + // The arch module may contain assembly. + if cfg!(feature = "no-asm") { + println!("cargo:rustc-cfg=feature=\"force-soft-floats\""); + } else { + println!("cargo:rustc-cfg=arch_enabled"); + } + + println!("cargo:rustc-check-cfg=cfg(optimizations_enabled)"); + if target.opt_level >= 2 { + println!("cargo:rustc-cfg=optimizations_enabled"); + } + + // Config shorthands + println!("cargo:rustc-check-cfg=cfg(x86_no_sse)"); + if target.arch == "x86" && !target.features.iter().any(|f| f == "sse") { + // Shorthand to detect i586 targets + println!("cargo:rustc-cfg=x86_no_sse"); + } + + println!( + "cargo:rustc-env=CFG_CARGO_FEATURES={:?}", + target.cargo_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\""); +} + fn aarch64_symbol(ordering: Ordering) -> &'static str { match ordering { Ordering::Relaxed => "relax", diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs index e20c717ec75a9..6cfbe11c2ed7b 100644 --- a/library/compiler-builtins/configure.rs +++ b/library/compiler-builtins/configure.rs @@ -6,6 +6,8 @@ use std::env; #[allow(dead_code)] pub struct Target { pub triple: String, + pub opt_level: u8, + pub cargo_features: Vec, pub os: String, pub arch: String, pub vendor: String, @@ -22,10 +24,16 @@ impl Target { "big" => false, x => panic!("unknown endian {x}"), }; + 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(); Self { triple: env::var("TARGET").unwrap(), os: env::var("CARGO_CFG_TARGET_OS").unwrap(), + opt_level: env::var("OPT_LEVEL").unwrap().parse().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(), diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index f4e5b38aee0e0..424c3ece1a754 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit f4e5b38aee0e0c592a82ed45b21cd068c9b6c89a +Subproject commit 424c3ece1a7546de8530fa9d0fbf90d3b182cd18 diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 477dfe3651614..da208239e834c 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -1,3 +1,4 @@ +#[rustfmt::skip] #[allow(dead_code)] #[allow(unused_imports)] #[allow(clippy::all)] From f3ad123a090f50991796cf766ab00ec24210c8bb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 7 Jan 2025 00:19:26 +0000 Subject: [PATCH 1526/4206] Replace "intrinsic" config with "arch" config WASM is the only architecture we use `intrinsics::` for. We probably don't want to do this for any other architectures since it is better to use assembly, or work toward getting the functions available in `core`. To more accurately reflect the relationship between arch and intrinsics, make wasm32 an `arch` module and call the intrinsics from there. --- .../libm/etc/function-definitions.json | 20 +++++++-------- .../libm/src/math/arch/mod.rs | 8 +++--- .../math/arch/{intrinsics.rs => wasm32.rs} | 6 +++-- .../compiler-builtins/libm/src/math/ceil.rs | 2 +- .../compiler-builtins/libm/src/math/ceilf.rs | 2 +- .../compiler-builtins/libm/src/math/fabs.rs | 2 +- .../compiler-builtins/libm/src/math/fabsf.rs | 2 +- .../compiler-builtins/libm/src/math/floor.rs | 2 +- .../compiler-builtins/libm/src/math/floorf.rs | 2 +- .../compiler-builtins/libm/src/math/sqrt.rs | 6 +++-- .../compiler-builtins/libm/src/math/sqrtf.rs | 6 +++-- .../libm/src/math/support/macros.rs | 25 +++---------------- .../compiler-builtins/libm/src/math/trunc.rs | 2 +- .../compiler-builtins/libm/src/math/truncf.rs | 2 +- 14 files changed, 37 insertions(+), 50 deletions(-) rename library/compiler-builtins/libm/src/math/arch/{intrinsics.rs => wasm32.rs} (82%) diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 0b2d6214f76c9..3cf7e0fed3de8 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -108,14 +108,14 @@ "sources": [ "src/libm_helper.rs", "src/math/arch/i586.rs", - "src/math/arch/intrinsics.rs", + "src/math/arch/wasm32.rs", "src/math/ceil.rs" ], "type": "f64" }, "ceilf": { "sources": [ - "src/math/arch/intrinsics.rs", + "src/math/arch/wasm32.rs", "src/math/ceilf.rs" ], "type": "f32" @@ -258,7 +258,7 @@ "fabs": { "sources": [ "src/libm_helper.rs", - "src/math/arch/intrinsics.rs", + "src/math/arch/wasm32.rs", "src/math/fabs.rs", "src/math/generic/fabs.rs" ], @@ -266,7 +266,7 @@ }, "fabsf": { "sources": [ - "src/math/arch/intrinsics.rs", + "src/math/arch/wasm32.rs", "src/math/fabsf.rs", "src/math/generic/fabs.rs" ], @@ -303,14 +303,14 @@ "sources": [ "src/libm_helper.rs", "src/math/arch/i586.rs", - "src/math/arch/intrinsics.rs", + "src/math/arch/wasm32.rs", "src/math/floor.rs" ], "type": "f64" }, "floorf": { "sources": [ - "src/math/arch/intrinsics.rs", + "src/math/arch/wasm32.rs", "src/math/floorf.rs" ], "type": "f32" @@ -683,7 +683,7 @@ "sources": [ "src/libm_helper.rs", "src/math/arch/i686.rs", - "src/math/arch/intrinsics.rs", + "src/math/arch/wasm32.rs", "src/math/sqrt.rs" ], "type": "f64" @@ -691,7 +691,7 @@ "sqrtf": { "sources": [ "src/math/arch/i686.rs", - "src/math/arch/intrinsics.rs", + "src/math/arch/wasm32.rs", "src/math/sqrtf.rs" ], "type": "f32" @@ -738,14 +738,14 @@ "trunc": { "sources": [ "src/libm_helper.rs", - "src/math/arch/intrinsics.rs", + "src/math/arch/wasm32.rs", "src/math/trunc.rs" ], "type": "f64" }, "truncf": { "sources": [ - "src/math/arch/intrinsics.rs", + "src/math/arch/wasm32.rs", "src/math/truncf.rs" ], "type": "f32" diff --git a/library/compiler-builtins/libm/src/math/arch/mod.rs b/library/compiler-builtins/libm/src/math/arch/mod.rs index cf9547117b830..bd79ae1c69c2c 100644 --- a/library/compiler-builtins/libm/src/math/arch/mod.rs +++ b/library/compiler-builtins/libm/src/math/arch/mod.rs @@ -5,14 +5,14 @@ //! is used when calling the function directly. This helps anyone who uses `libm` directly, as //! well as improving things when these routines are called as part of other implementations. -#[cfg(intrinsics_enabled)] -pub mod intrinsics; - // Most implementations should be defined here, to ensure they are not made available when // soft floats are required. #[cfg(arch_enabled)] cfg_if! { - if #[cfg(target_feature = "sse2")] { + if #[cfg(all(target_arch = "wasm32", intrinsics_enabled))] { + mod wasm32; + pub use wasm32::{ceil, ceilf, fabs, fabsf, floor, floorf, sqrt, sqrtf, trunc, truncf}; + } else if #[cfg(target_feature = "sse2")] { mod i686; pub use i686::{sqrt, sqrtf}; } diff --git a/library/compiler-builtins/libm/src/math/arch/intrinsics.rs b/library/compiler-builtins/libm/src/math/arch/wasm32.rs similarity index 82% rename from library/compiler-builtins/libm/src/math/arch/intrinsics.rs rename to library/compiler-builtins/libm/src/math/arch/wasm32.rs index 733af0f1a96e6..09df8624e8b67 100644 --- a/library/compiler-builtins/libm/src/math/arch/intrinsics.rs +++ b/library/compiler-builtins/libm/src/math/arch/wasm32.rs @@ -1,5 +1,7 @@ -// Config is needed for times when this module is available but we don't call everything -#![allow(dead_code)] +//! Wasm asm is not stable; just use intrinsics for operations that have asm routine equivalents. +//! +//! Note that we need to be absolutely certain that everything here lowers to assembly operations, +//! otherwise libcalls will be recursive. pub fn ceil(x: f64) -> f64 { // SAFETY: safe intrinsic with no preconditions diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index b0576f3dc1f8e..398bfee47a21d 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -10,8 +10,8 @@ const TOINT: f64 = 1. / f64::EPSILON; 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_intrinsic: target_arch = "wasm32", args: x, } diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index 9eb2ec07a422a..9e8e78e3e532b 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -7,7 +7,7 @@ use core::f32; pub fn ceilf(x: f32) -> f32 { select_implementation! { name: ceilf, - use_intrinsic: target_arch = "wasm32", + use_arch: all(target_arch = "wasm32", intrinsics_enabled), args: x, } diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index 46c0d88a5c045..22867fab05698 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -6,7 +6,7 @@ pub fn fabs(x: f64) -> f64 { select_implementation! { name: fabs, - use_intrinsic: target_arch = "wasm32", + use_arch: all(target_arch = "wasm32", intrinsics_enabled), args: x, } diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs index d5775b600d97a..e5820a26c5238 100644 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ b/library/compiler-builtins/libm/src/math/fabsf.rs @@ -6,7 +6,7 @@ pub fn fabsf(x: f32) -> f32 { select_implementation! { name: fabsf, - use_intrinsic: target_arch = "wasm32", + use_arch: all(target_arch = "wasm32", intrinsics_enabled), args: x, } diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index e478f6d547288..2823bf44d9c3e 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -10,8 +10,8 @@ const TOINT: f64 = 1. / f64::EPSILON; 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_intrinsic: target_arch = "wasm32", args: x, } diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index bd1570c86969c..23a18c0f73761 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -7,7 +7,7 @@ use core::f32; pub fn floorf(x: f32) -> f32 { select_implementation! { name: floorf, - use_intrinsic: target_arch = "wasm32", + use_arch: all(target_arch = "wasm32", intrinsics_enabled), args: x, } diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 3f1a10fddc6e5..2fd7070b11019 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -83,8 +83,10 @@ use core::f64; pub fn sqrt(x: f64) -> f64 { select_implementation! { name: sqrt, - use_arch: target_feature = "sse2", - use_intrinsic: target_arch = "wasm32", + use_arch: any( + all(target_arch = "wasm32", intrinsics_enabled), + target_feature = "sse2" + ), args: x, } diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 23f9a8443294e..319335163ae85 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -18,8 +18,10 @@ pub fn sqrtf(x: f32) -> f32 { select_implementation! { name: sqrtf, - use_arch: target_feature = "sse2", - use_intrinsic: target_arch = "wasm32", + use_arch: any( + all(target_arch = "wasm32", intrinsics_enabled), + target_feature = "sse2" + ), args: x, } diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index 9441eace529da..f5094b9da8956 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -39,13 +39,8 @@ macro_rules! cfg_if { (@__identity $($tokens:tt)*) => { $($tokens)* }; } -/// Choose among using an intrinsic, an arch-specific implementation, and the function body. -/// Returns directly if the intrinsic or arch is used, otherwise continue with the rest of the -/// function. -/// -/// Specify a `use_intrinsic` meta field if the intrinsic is (1) available on the platforms (i.e. -/// LLVM lowers it without libcalls that may recurse), (2) it is likely to be more performant. -/// Intrinsics require wrappers in the `math::arch::intrinsics` module. +/// Choose between using an arch-specific implementation and the function body. Returns directly +/// if the arch implementation is used, otherwise continue with the rest of the function. /// /// Specify a `use_arch` meta field if an architecture-specific implementation is provided. /// These live in the `math::arch::some_target_arch` module. @@ -53,8 +48,7 @@ macro_rules! cfg_if { /// Specify a `use_arch_required` meta field if something architecture-specific must be used /// regardless of feature configuration (`force-soft-floats`). /// -/// The passed meta options do not need to account for relevant Cargo features -/// (`unstable-intrinsics`, `arch`, `force-soft-floats`), this macro handles that part. +/// The passed meta options do not need to account for the `arch` target feature. macro_rules! select_implementation { ( name: $fn_name:ident, @@ -64,15 +58,12 @@ macro_rules! select_implementation { // Configuration meta for when to use the arch module regardless of whether softfloats // have been requested. $( use_arch_required: $use_arch_required:meta, )? - // Configuration meta for when to call intrinsics and let LLVM figure it out - $( use_intrinsic: $use_intrinsic:meta, )? args: $($arg:ident),+ , ) => { // FIXME: these use paths that are a pretty fragile (`super`). We should figure out // something better w.r.t. how this is vendored into compiler-builtins. // However, we do need a few things from `arch` that are used even with soft floats. - // select_implementation! { @cfg $($use_arch_required)?; if true { @@ -89,16 +80,6 @@ macro_rules! select_implementation { return super::arch::$fn_name( $($arg),+ ); } } - - // Never use intrinsics if we are forcing soft floats, and only enable with the - // `unstable-intrinsics` feature. - #[cfg(intrinsics_enabled)] - select_implementation! { - @cfg $( $use_intrinsic )?; - if true { - return super::arch::intrinsics::$fn_name( $($arg),+ ); - } - } }; // Coalesce helper to construct an expression only if a config is provided diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs index d85bffb40e4aa..7e5c4f2c2ae51 100644 --- a/library/compiler-builtins/libm/src/math/trunc.rs +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -7,7 +7,7 @@ use core::f64; pub fn trunc(x: f64) -> f64 { select_implementation! { name: trunc, - use_intrinsic: target_arch = "wasm32", + use_arch: all(target_arch = "wasm32", intrinsics_enabled), args: x, } diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs index 82017b87b7cef..b491747d999e6 100644 --- a/library/compiler-builtins/libm/src/math/truncf.rs +++ b/library/compiler-builtins/libm/src/math/truncf.rs @@ -7,7 +7,7 @@ use core::f32; pub fn truncf(x: f32) -> f32 { select_implementation! { name: truncf, - use_intrinsic: target_arch = "wasm32", + use_arch: all(target_arch = "wasm32", intrinsics_enabled), args: x, } From e6ea2802d17ab8a388ebb9b38ea87267ba15235c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 7 Jan 2025 01:49:52 +0000 Subject: [PATCH 1527/4206] Update the `libm` submodule --- library/compiler-builtins/libm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 424c3ece1a754..44770b9692055 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 424c3ece1a7546de8530fa9d0fbf90d3b182cd18 +Subproject commit 44770b96920557baf38990d2ee4142e166be579d From 1b0adb233c5c249ed4282bd54302abf6ebd29ca1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 7 Jan 2025 01:57:53 +0000 Subject: [PATCH 1528/4206] chore: release v0.1.141 --- library/compiler-builtins/CHANGELOG.md | 9 +++++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index f888591437bfd..ccfc97d1bb021 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.141](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.140...compiler_builtins-v0.1.141) - 2025-01-07 + +### Other + +- Update the `libm` submodule +- Fix new `clippy::precedence` errors +- Rename `EXP_MAX` to `EXP_SAT` +- Shorten prefixes for float constants + ## [0.1.140](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.139...compiler_builtins-v0.1.140) - 2024-12-26 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 33d5c06b78c76..a0c4cfaaffdbc 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.140" +version = "0.1.141" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 0359db23c7ad1e8ee023150b938a4e28110b245e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 7 Jan 2025 02:54:37 +0000 Subject: [PATCH 1529/4206] Increase the allowed ULP for `tgammaf` Extensive tests report that the precision isn't actually 0: ---- mp_extensive_tgammaf ---- input: (-0.00063536887,) (0xba268ee2,) expected: -1574.4668 0xc4c4cef0 actual: -1574.4667 0xc4c4ceef Caused by: ulp 1 > 0 Update ULP to reflect this. After this change, `tgammaf` extensive tests pass. --- .../compiler-builtins/libm/crates/libm-test/src/precision.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 03bf7ceccc375..cbe4bdf8848fb 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -44,7 +44,6 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { // Operations that aren't required to be exact, but our implementations are. Bn::Cbrt if ctx.fn_ident != Id::Cbrt => 0, - Bn::Tgamma if ctx.fn_ident != Id::Tgamma => 0, // Bessel functions have large inaccuracies. Bn::J0 | Bn::J1 | Bn::Y0 | Bn::Y1 | Bn::Jn | Bn::Yn => 8_000_000, @@ -78,6 +77,8 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { Bn::Sinh => 2, Bn::Tan => 1, Bn::Tanh => 2, + // tgammaf has higher accuracy than tgamma. + Bn::Tgamma if ctx.fn_ident != Id::Tgamma => 1, Bn::Tgamma => 20, }; From 76714a5657d8e876a41f49e87c8008110304fd61 Mon Sep 17 00:00:00 2001 From: beetrees Date: Tue, 7 Jan 2025 13:51:15 +0000 Subject: [PATCH 1530/4206] Make extensive tests exhaustive if there are enough iterations available --- .../libm-test/src/gen/domain_logspace.rs | 2 +- .../crates/libm-test/src/gen/extensive.rs | 237 +++++++++++++----- .../libm/crates/libm-test/src/lib.rs | 2 +- .../libm/crates/libm-test/src/num.rs | 89 ++++++- .../crates/libm-test/tests/z_extensive/run.rs | 3 +- 5 files changed, 252 insertions(+), 81 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs index 3d8a3e7fe7335..c6963ad436a6a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs @@ -27,5 +27,5 @@ where let start = domain.range_start(); let end = domain.range_end(); let steps = OpITy::::try_from(ntests).unwrap_or(OpITy::::MAX); - logspace(start, end, steps).map(|v| (v,)) + logspace(start, end, steps).0.map(|v| (v,)) } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs index d724226e95be9..fb709e54684ea 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs @@ -1,19 +1,18 @@ use std::fmt; use std::ops::RangeInclusive; -use libm::support::MinInt; +use libm::support::{Float, MinInt}; use crate::domain::HasDomain; -use crate::gen::KnownSize; use crate::op::OpITy; use crate::run_cfg::{int_range, iteration_count}; -use crate::{CheckCtx, GeneratorKind, MathOp, logspace}; +use crate::{CheckCtx, GeneratorKind, MathOp, linear_ints, logspace}; /// Generate a sequence of inputs that either cover the domain in completeness (for smaller float /// types and single argument functions) or provide evenly spaced inputs across the domain with /// approximately `u32::MAX` total iterations. pub trait ExtensiveInput { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator + Send; + fn get_cases(ctx: &CheckCtx) -> (impl Iterator + Send, u64); } /// Construct an iterator from `logspace` and also calculate the total number of steps expected @@ -21,24 +20,60 @@ pub trait ExtensiveInput { fn logspace_steps( start: Op::FTy, end: Op::FTy, - ctx: &CheckCtx, - argnum: usize, + max_steps: u64, ) -> (impl Iterator + Clone, u64) where Op: MathOp, OpITy: TryFrom, + u64: TryFrom, Error: fmt::Debug>, RangeInclusive>: Iterator, { - let max_steps = iteration_count(ctx, GeneratorKind::Extensive, argnum); let max_steps = OpITy::::try_from(max_steps).unwrap_or(OpITy::::MAX); - let iter = logspace(start, end, max_steps); + let (iter, steps) = logspace(start, end, max_steps); + + // `steps` will be <= the original `max_steps`, which is a `u64`. + (iter, steps.try_into().unwrap()) +} + +/// Represents the iterator in either `Left` or `Right`. +enum EitherIter { + A(A), + B(B), +} - // `logspace` can't implement `ExactSizeIterator` because of the range, but its size hint - // should be accurate (assuming <= usize::MAX iterations). - let size_hint = iter.size_hint(); - assert_eq!(size_hint.0, size_hint.1.unwrap()); +impl, B: Iterator> Iterator for EitherIter { + type Item = T; - (iter, size_hint.0.try_into().unwrap()) + fn next(&mut self) -> Option { + match self { + Self::A(iter) => iter.next(), + Self::B(iter) => iter.next(), + } + } + + fn size_hint(&self) -> (usize, Option) { + match self { + Self::A(iter) => iter.size_hint(), + Self::B(iter) => iter.size_hint(), + } + } +} + +/// Gets the total number of possible values, returning `None` if that number doesn't fit in a +/// `u64`. +fn value_count() -> Option +where + u64: TryFrom, +{ + u64::try_from(F::Int::MAX).ok().and_then(|max| max.checked_add(1)) +} + +/// Returns an iterator of every possible value of type `F`. +fn all_values() -> impl Iterator +where + RangeInclusive: Iterator, +{ + (F::Int::MIN..=F::Int::MAX).map(|bits| F::from_bits(bits)) } macro_rules! impl_extensive_input { @@ -48,12 +83,23 @@ macro_rules! impl_extensive_input { Op: MathOp, Op: HasDomain, { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { - let start = Op::DOMAIN.range_start(); - let end = Op::DOMAIN.range_end(); - let (iter0, steps0) = logspace_steps::(start, end, ctx, 0); - let iter0 = iter0.map(|v| (v,)); - KnownSize::new(iter0, steps0) + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let max_steps0 = iteration_count(ctx, GeneratorKind::Extensive, 0); + // `f16` and `f32` can have exhaustive tests. + match value_count::() { + Some(steps0) if steps0 <= max_steps0 => { + let iter0 = all_values(); + let iter0 = iter0.map(|v| (v,)); + (EitherIter::A(iter0), steps0) + } + _ => { + let start = Op::DOMAIN.range_start(); + let end = Op::DOMAIN.range_end(); + let (iter0, steps0) = logspace_steps::(start, end, max_steps0); + let iter0 = iter0.map(|v| (v,)); + (EitherIter::B(iter0), steps0) + } + } } } @@ -61,15 +107,28 @@ macro_rules! impl_extensive_input { where Op: MathOp, { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { - let start = <$fty>::NEG_INFINITY; - let end = <$fty>::INFINITY; - let (iter0, steps0) = logspace_steps::(start, end, ctx, 0); - let (iter1, steps1) = logspace_steps::(start, end, ctx, 1); - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); - let count = steps0.checked_mul(steps1).unwrap(); - KnownSize::new(iter, count) + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let max_steps0 = iteration_count(ctx, GeneratorKind::Extensive, 0); + let max_steps1 = iteration_count(ctx, GeneratorKind::Extensive, 1); + // `f16` can have exhaustive tests. + 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 start = <$fty>::NEG_INFINITY; + let end = <$fty>::INFINITY; + let (iter0, steps0) = logspace_steps::(start, end, max_steps0); + let (iter1, steps1) = logspace_steps::(start, end, 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) + } + } } } @@ -77,22 +136,41 @@ macro_rules! impl_extensive_input { where Op: MathOp, { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { - let start = <$fty>::NEG_INFINITY; - let end = <$fty>::INFINITY; - - let (iter0, steps0) = logspace_steps::(start, end, ctx, 0); - let (iter1, steps1) = logspace_steps::(start, end, ctx, 1); - let (iter2, steps2) = logspace_steps::(start, end, 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 count = steps0.checked_mul(steps1).unwrap().checked_mul(steps2).unwrap(); - - KnownSize::new(iter, count) + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let max_steps0 = iteration_count(ctx, GeneratorKind::Extensive, 0); + let max_steps1 = iteration_count(ctx, GeneratorKind::Extensive, 1); + let max_steps2 = iteration_count(ctx, GeneratorKind::Extensive, 2); + // `f16` can be exhaustive tested if `LIBM_EXTENSIVE_TESTS` is incresed. + match 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)) + }) + }); + (EitherIter::A(iter), count.checked_pow(3).unwrap()) + } + _ => { + let start = <$fty>::NEG_INFINITY; + let end = <$fty>::INFINITY; + + let (iter0, steps0) = logspace_steps::(start, end, max_steps0); + let (iter1, steps1) = logspace_steps::(start, end, max_steps1); + let (iter2, steps2) = logspace_steps::(start, end, 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.checked_mul(steps1).unwrap().checked_mul(steps2).unwrap(); + + (EitherIter::B(iter), count) + } + } } } @@ -100,19 +178,32 @@ macro_rules! impl_extensive_input { where Op: MathOp, { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { - let start = <$fty>::NEG_INFINITY; - let end = <$fty>::INFINITY; + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let range0 = int_range(ctx, GeneratorKind::Extensive, 0); + let max_steps0 = iteration_count(ctx, GeneratorKind::Extensive, 0); + let max_steps1 = iteration_count(ctx, GeneratorKind::Extensive, 1); + match 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))); + (EitherIter::A(iter), steps0.checked_mul(count1).unwrap()) + } + _ => { + let start = <$fty>::NEG_INFINITY; + let end = <$fty>::INFINITY; - let iter0 = int_range(ctx, GeneratorKind::Extensive, 0); - let steps0 = iteration_count(ctx, GeneratorKind::Extensive, 0); - let (iter1, steps1) = logspace_steps::(start, end, ctx, 1); + let (iter0, steps0) = linear_ints(range0, max_steps0); + let (iter1, steps1) = logspace_steps::(start, end, max_steps1); - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); - let count = steps0.checked_mul(steps1).unwrap(); + let iter = iter0.flat_map(move |first| { + iter1.clone().map(move |second| (first, second)) + }); + let count = steps0.checked_mul(steps1).unwrap(); - KnownSize::new(iter, count) + (EitherIter::B(iter), count) + } + } } } @@ -120,19 +211,33 @@ macro_rules! impl_extensive_input { where Op: MathOp, { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { - let start = <$fty>::NEG_INFINITY; - let end = <$fty>::INFINITY; + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let max_steps0 = iteration_count(ctx, GeneratorKind::Extensive, 0); + let range1 = int_range(ctx, GeneratorKind::Extensive, 1); + let max_steps1 = iteration_count(ctx, GeneratorKind::Extensive, 1); + 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| { + iter1.clone().map(move |second| (first, second)) + }); + (EitherIter::A(iter), count0.checked_mul(steps1).unwrap()) + } + _ => { + let start = <$fty>::NEG_INFINITY; + let end = <$fty>::INFINITY; - let (iter0, steps0) = logspace_steps::(start, end, ctx, 0); - let iter1 = int_range(ctx, GeneratorKind::Extensive, 0); - let steps1 = iteration_count(ctx, GeneratorKind::Extensive, 0); + let (iter0, steps0) = logspace_steps::(start, end, 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(); + let iter = iter0.flat_map(move |first| { + iter1.clone().map(move |second| (first, second)) + }); + let count = steps0.checked_mul(steps1).unwrap(); - KnownSize::new(iter, count) + (EitherIter::B(iter), count) + } + } } } }; @@ -145,10 +250,10 @@ impl_extensive_input!(f64); #[cfg(f128_enabled)] impl_extensive_input!(f128); -/// Create a test case iterator for extensive inputs. +/// Create a test case iterator for extensive inputs. Also returns the total test case count. pub fn get_test_cases( ctx: &CheckCtx, -) -> impl ExactSizeIterator + Send + use<'_, Op> +) -> (impl Iterator + Send + use<'_, Op>, u64) where Op: MathOp, Op::RustArgs: ExtensiveInput, diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 251114a0dcb9a..6e7017f093c38 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -22,7 +22,7 @@ use std::time::SystemTime; pub use f8_impl::f8; pub use libm::support::{Float, Int, IntTy, MinInt}; -pub use num::{FloatExt, logspace}; +pub use num::{FloatExt, linear_ints, logspace}; pub use op::{ BaseName, FloatTy, Identifier, MathOp, OpCFn, OpCRet, OpFTy, OpRustFn, OpRustRet, Ty, }; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/num.rs b/library/compiler-builtins/libm/crates/libm-test/src/num.rs index f693ef02f1f6f..eed941423d3dc 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/num.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/num.rs @@ -215,7 +215,13 @@ fn as_ulp_steps(x: F) -> Option { /// to logarithmic spacing of their values. /// /// Note that this tends to skip negative zero, so that needs to be checked explicitly. -pub fn logspace(start: F, end: F, steps: F::Int) -> impl Iterator + Clone +/// +/// Returns `(iterator, iterator_length)`. +pub fn logspace( + start: F, + end: F, + steps: F::Int, +) -> (impl Iterator + Clone, F::Int) where RangeInclusive: Iterator, { @@ -223,17 +229,42 @@ where assert!(!end.is_nan()); assert!(end >= start); - let mut steps = steps.checked_sub(F::Int::ONE).expect("`steps` must be at least 2"); + let steps = steps.checked_sub(F::Int::ONE).expect("`steps` must be at least 2"); let between = ulp_between(start, end).expect("`start` or `end` is NaN"); let spacing = (between / steps).max(F::Int::ONE); - steps = steps.min(between); // At maximum, one step per ULP + let steps = steps.min(between); // At maximum, one step per ULP let mut x = start; - (F::Int::ZERO..=steps).map(move |_| { - let ret = x; - x = x.n_up(spacing); - ret - }) + ( + (F::Int::ZERO..=steps).map(move |_| { + let ret = x; + x = x.n_up(spacing); + ret + }), + steps + F::Int::ONE, + ) +} + +/// Returns an iterator of up to `steps` integers evenly distributed. +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(); + ( + (0..=steps).map(move |_| { + let res = x; + // Wrapping add to avoid panic on last item (where `x` could overflow past i32::MAX as + // there is no next item). + x = x.wrapping_add(spacing); + res + }), + steps + 1, + ) } #[cfg(test)] @@ -422,19 +453,55 @@ mod tests { #[test] fn test_logspace() { - let ls: Vec<_> = logspace(f8::from_bits(0x0), f8::from_bits(0x4), 2).collect(); + let (ls, count) = logspace(f8::from_bits(0x0), f8::from_bits(0x4), 2); + let ls: Vec<_> = ls.collect(); let exp = [f8::from_bits(0x0), f8::from_bits(0x4)]; assert_eq!(ls, exp); + assert_eq!(ls.len(), usize::from(count)); - let ls: Vec<_> = logspace(f8::from_bits(0x0), f8::from_bits(0x4), 3).collect(); + let (ls, count) = logspace(f8::from_bits(0x0), f8::from_bits(0x4), 3); + let ls: Vec<_> = ls.collect(); let exp = [f8::from_bits(0x0), f8::from_bits(0x2), f8::from_bits(0x4)]; assert_eq!(ls, exp); + assert_eq!(ls.len(), usize::from(count)); // Check that we include all values with no repeats if `steps` exceeds the maximum number // of steps. - let ls: Vec<_> = logspace(f8::from_bits(0x0), f8::from_bits(0x3), 10).collect(); + let (ls, count) = logspace(f8::from_bits(0x0), f8::from_bits(0x3), 10); + let ls: Vec<_> = ls.collect(); let exp = [f8::from_bits(0x0), f8::from_bits(0x1), f8::from_bits(0x2), f8::from_bits(0x3)]; assert_eq!(ls, exp); + assert_eq!(ls.len(), usize::from(count)); + } + + #[test] + fn test_linear_ints() { + let (ints, count) = linear_ints(0..=4, 2); + let ints: Vec<_> = ints.collect(); + let exp = [0, 4]; + assert_eq!(ints, exp); + assert_eq!(ints.len(), usize::try_from(count).unwrap()); + + let (ints, count) = linear_ints(0..=4, 3); + let ints: Vec<_> = ints.collect(); + let exp = [0, 2, 4]; + assert_eq!(ints, exp); + assert_eq!(ints.len(), usize::try_from(count).unwrap()); + + // Check that we include all values with no repeats if `steps` exceeds the maximum number + // of steps. + let (ints, count) = linear_ints(0x0..=0x3, 10); + let ints: Vec<_> = ints.collect(); + let exp = [0, 1, 2, 3]; + assert_eq!(ints, exp); + assert_eq!(ints.len(), usize::try_from(count).unwrap()); + + // Check that there are no panics around `i32::MAX`. + let (ints, count) = linear_ints(i32::MAX - 1..=i32::MAX, 5); + let ints: Vec<_> = ints.collect(); + let exp = [i32::MAX - 1, i32::MAX]; + assert_eq!(ints, exp); + assert_eq!(ints.len(), usize::try_from(count).unwrap()); } #[test] diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs index 7acff5324abcd..07f4d5370dceb 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs @@ -106,8 +106,7 @@ where let completed = AtomicU64::new(0); let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); - let cases = &mut extensive::get_test_cases::(&ctx); - let total: u64 = cases.len().try_into().unwrap(); + let (ref mut cases, total) = extensive::get_test_cases::(&ctx); let pb = Progress::new(Op::NAME, total); let test_single_chunk = |mp_vals: &mut Op::MpTy, input_vec: Vec| -> TestResult { From 2b99475df321e952f2a4266468623683aad13b03 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 7 Jan 2025 17:30:05 -0500 Subject: [PATCH 1531/4206] Account for optimization levels other than numbers The build script currently panics with `opt-level=z` or `opt-level=s`. Account for this here. --- library/compiler-builtins/libm/configure.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/configure.rs b/library/compiler-builtins/libm/configure.rs index a18937c3c9e26..8b8ba98156557 100644 --- a/library/compiler-builtins/libm/configure.rs +++ b/library/compiler-builtins/libm/configure.rs @@ -7,7 +7,7 @@ use std::path::PathBuf; pub struct Config { pub manifest_dir: PathBuf, pub out_dir: PathBuf, - pub opt_level: u8, + pub opt_level: String, pub cargo_features: Vec, pub target_arch: String, pub target_env: String, @@ -31,7 +31,7 @@ impl Config { Self { 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().parse().unwrap(), + opt_level: env::var("OPT_LEVEL").unwrap(), cargo_features, target_arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), @@ -91,7 +91,7 @@ fn emit_arch_cfg() { fn emit_optimization_cfg(cfg: &Config) { println!("cargo:rustc-check-cfg=cfg(optimizations_enabled)"); - if cfg.opt_level >= 2 { + if !matches!(cfg.opt_level.as_str(), "0" | "1") { println!("cargo:rustc-cfg=optimizations_enabled"); } } From 77f34f3a4c6d50688c8d456e5bbe192050807932 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 7 Jan 2025 18:11:40 -0500 Subject: [PATCH 1532/4206] Update the `libm` submodule This includes [1], which fixes a bug parsing non-numeric optimization levels. [1]: https://github.com/rust-lang/libm/pull/417 --- library/compiler-builtins/libm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 44770b9692055..8e82616f154b0 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 44770b96920557baf38990d2ee4142e166be579d +Subproject commit 8e82616f154b06cf4ee9cdb82a4f56474a403d04 From 83a61e67fdd9fdaeb915e63ff3f280b79b6d75e0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 7 Jan 2025 18:12:19 -0500 Subject: [PATCH 1533/4206] Account for optimization levels other than numbers The build script currently panics with `opt-level=z` or `opt-level=s`. Account for this here. This is the `compiler-builtins` version of [1]. Fixes: https://github.com/rust-lang/compiler-builtins/issues/742 [1]: https://github.com/rust-lang/libm/pull/417 --- library/compiler-builtins/build.rs | 2 +- library/compiler-builtins/configure.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 2bb8651d7f7f7..f512fc2e6672c 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -121,7 +121,7 @@ fn configure_libm(target: &Target) { } println!("cargo:rustc-check-cfg=cfg(optimizations_enabled)"); - if target.opt_level >= 2 { + if !matches!(target.opt_level.as_str(), "0" | "1") { println!("cargo:rustc-cfg=optimizations_enabled"); } diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs index 6cfbe11c2ed7b..87bc7a0eed302 100644 --- a/library/compiler-builtins/configure.rs +++ b/library/compiler-builtins/configure.rs @@ -6,7 +6,7 @@ use std::env; #[allow(dead_code)] pub struct Target { pub triple: String, - pub opt_level: u8, + pub opt_level: String, pub cargo_features: Vec, pub os: String, pub arch: String, @@ -32,7 +32,7 @@ impl Target { Self { triple: env::var("TARGET").unwrap(), os: env::var("CARGO_CFG_TARGET_OS").unwrap(), - opt_level: env::var("OPT_LEVEL").unwrap().parse().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(), From d0a79fd542f2aaaa9af3ebf79f0e0d8d58a0ab6d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 7 Jan 2025 23:21:35 +0000 Subject: [PATCH 1534/4206] chore: release v0.1.142 --- library/compiler-builtins/CHANGELOG.md | 6 ++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index ccfc97d1bb021..305f2790f33cc 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.142](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.141...compiler_builtins-v0.1.142) - 2025-01-07 + +### Other + +- Account for optimization levels other than numbers + ## [0.1.141](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.140...compiler_builtins-v0.1.141) - 2025-01-07 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index a0c4cfaaffdbc..943adc4c1f2b1 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.141" +version = "0.1.142" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From a0c03b2537cadc9b74c5dd5d86d4a995553d9961 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 5 Jan 2025 11:21:00 +0000 Subject: [PATCH 1535/4206] Add tests against MPFR for `remquo` and `remquof` Rug does not yet expose this function, but it is possible to use the MPFR bindings directly. --- .../libm/crates/libm-test/Cargo.toml | 2 +- .../libm/crates/libm-test/src/mpfloat.rs | 50 +++++++++++++++++++ .../crates/libm-test/tests/multiprecision.rs | 4 -- .../crates/libm-test/tests/z_extensive/run.rs | 4 -- 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 371beb19aa52a..621e587c56daf 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -35,7 +35,7 @@ paste = "1.0.15" rand = "0.8.5" rand_chacha = "0.3.1" rayon = "1.10.0" -rug = { version = "1.26.1", optional = true, default-features = false, features = ["float", "std"] } +rug = { version = "1.26.1", optional = true, default-features = false, features = ["float", "integer", "std"] } [target.'cfg(target_family = "wasm")'.dependencies] # Enable randomness on WASM diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index f2b7b2f25da99..f71e72cd57129 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -4,10 +4,13 @@ //! a struct named `Operation` that implements [`MpOp`]. use std::cmp::Ordering; +use std::ffi::{c_int, c_long}; use az::Az; +use gmp_mpfr_sys::mpfr::rnd_t; use rug::Assign; pub use rug::Float as MpFloat; +use rug::float::Round; use rug::float::Round::Nearest; use rug::ops::{PowAssignRound, RemAssignRound}; @@ -361,6 +364,32 @@ macro_rules! impl_op_for_ty { } } + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + ( + new_mpfloat::(), + 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, ql) = mpfr_remquo(&mut this.2, &this.0, &this.1, Nearest); + + // `remquo` integer results are sign-magnitude representation. Transfer the + // sign bit from the long result to the int result. + let clear = !(1 << (c_int::BITS - 1)); + let sign = ((ql >> (c_long::BITS - 1)) as i32) << (c_int::BITS - 1); + let q = (ql as i32) & clear | sign; + + (prep_retval::(&mut this.2, ord), q) + } + } + impl MpOp for crate::op::[]::Routine { type MpTy = MpFloat; @@ -441,3 +470,24 @@ impl MpOp for crate::op::lgammaf_r::Routine { (ret, sign as i32) } } + +/// `rug` does not provide `remquo` so this exposes `mpfr_remquo`. See rug#76. +fn mpfr_remquo(r: &mut MpFloat, x: &MpFloat, y: &MpFloat, round: Round) -> (Ordering, c_long) { + let r = r.as_raw_mut(); + let x = x.as_raw(); + let y = y.as_raw(); + let mut q: c_long = 0; + + let round = match round { + Round::Nearest => rnd_t::RNDN, + Round::Zero => rnd_t::RNDZ, + Round::Up => rnd_t::RNDU, + Round::Down => rnd_t::RNDD, + Round::AwayZero => rnd_t::RNDA, + _ => unreachable!(), + }; + + // SAFETY: mutable and const pointers are valid and do not alias, by Rust's rules. + let ord = unsafe { gmp_mpfr_sys::mpfr::remquo(r, &mut q, x, y, round) }; + (ord.cmp(&0), q) +} diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 7961b0802589e..e2766cfdabd75 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -50,10 +50,6 @@ libm_macros::for_each_function! { [jn, jnf, yn, ynf], ], skip: [ - // FIXME: MPFR tests needed - remquo, - remquof, - // FIXME: test needed, see // https://github.com/rust-lang/libm/pull/311#discussion_r1818273392 nextafter, diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs index 07f4d5370dceb..7ee9678515ea3 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs @@ -48,10 +48,6 @@ fn register_all_tests() -> Vec { callback: mp_extensive_tests, extra: [all_tests], skip: [ - // FIXME: MPFR tests needed - remquo, - remquof, - // FIXME: test needed, see // https://github.com/rust-lang/libm/pull/311#discussion_r1818273392 nextafter, From ab1038a32bc6217104808020570016545c940904 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 11 Jan 2025 21:24:06 +0000 Subject: [PATCH 1536/4206] Use `core::arch::wasm` functions rather than intrinsics These wasm functions are available in `core::arch::wasm32` since [1], so we can use them while avoiding the possibly-recursive `intrinsics::*` calls (in practice none of those should always lower to libcalls on wasm, but that is up to LLVM). Since these require an unstable feature, they are still gated under `unstable-intrinsics`. [1]: https://github.com/rust-lang/stdarch/pull/1677 --- library/compiler-builtins/libm/src/lib.rs | 1 + .../libm/src/math/arch/wasm32.rs | 30 +++++++------------ 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 327e3d6e65b43..b0e4312110f3a 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -2,6 +2,7 @@ #![no_std] #![cfg_attr(intrinsics_enabled, allow(internal_features))] #![cfg_attr(intrinsics_enabled, feature(core_intrinsics))] +#![cfg_attr(all(intrinsics_enabled, target_family = "wasm"), feature(wasm_numeric_instr))] #![cfg_attr(f128_enabled, feature(f128))] #![cfg_attr(f16_enabled, feature(f16))] #![allow(clippy::assign_op_pattern)] diff --git a/library/compiler-builtins/libm/src/math/arch/wasm32.rs b/library/compiler-builtins/libm/src/math/arch/wasm32.rs index 09df8624e8b67..384445f129142 100644 --- a/library/compiler-builtins/libm/src/math/arch/wasm32.rs +++ b/library/compiler-builtins/libm/src/math/arch/wasm32.rs @@ -1,16 +1,12 @@ -//! Wasm asm is not stable; just use intrinsics for operations that have asm routine equivalents. -//! -//! Note that we need to be absolutely certain that everything here lowers to assembly operations, -//! otherwise libcalls will be recursive. +//! 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 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::ceilf64(x) } + core::arch::wasm32::f64_ceil(x) } pub fn ceilf(x: f32) -> f32 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::ceilf32(x) } + core::arch::wasm32::f32_ceil(x) } pub fn fabs(x: f64) -> f64 { @@ -22,31 +18,25 @@ pub fn fabsf(x: f32) -> f32 { } pub fn floor(x: f64) -> f64 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::floorf64(x) } + core::arch::wasm32::f64_floor(x) } pub fn floorf(x: f32) -> f32 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::floorf32(x) } + core::arch::wasm32::f32_floor(x) } pub fn sqrt(x: f64) -> f64 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::sqrtf64(x) } + core::arch::wasm32::f64_sqrt(x) } pub fn sqrtf(x: f32) -> f32 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::sqrtf32(x) } + core::arch::wasm32::f32_sqrt(x) } pub fn trunc(x: f64) -> f64 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::truncf64(x) } + core::arch::wasm32::f64_trunc(x) } pub fn truncf(x: f32) -> f32 { - // SAFETY: safe intrinsic with no preconditions - unsafe { core::intrinsics::truncf32(x) } + core::arch::wasm32::f32_trunc(x) } From beb34db83d4637199ee264ae427c0337aa92cd63 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 11 Jan 2025 22:04:32 +0000 Subject: [PATCH 1537/4206] Split `cast` into `cast` and `cast_lossy` There is a difference in intent between wishing to cast and truncate the value, and expecting the input to be within range. To make this clear, add separate `cast_lossy` and `cast_from_lossy` to indicate what that truncation is intended, leaving `cast` and `cast_from` to only be casts that expected not to truncate. Actually enforcing this at runtime is likely to have a cost, so just `debug_assert!` that `cast` doesn't truncate. --- .../libm/src/math/support/int_traits.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) 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 380313c1e6ba4..0f2d72d9be383 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -343,18 +343,30 @@ impl_h_int!( /// Trait to express (possibly lossy) casting of integers #[allow(unused)] pub trait CastInto: Copy { + /// By default, casts should be exact. fn cast(self) -> T; + + /// Call for casts that are expected to truncate. + fn cast_lossy(self) -> T; } #[allow(unused)] pub trait CastFrom: Copy { + /// By default, casts should be exact. fn cast_from(value: T) -> Self; + + /// Call for casts that are expected to truncate. + fn cast_from_lossy(value: T) -> Self; } impl + Copy> CastFrom for T { fn cast_from(value: U) -> Self { value.cast() } + + fn cast_from_lossy(value: U) -> Self { + value.cast_lossy() + } } macro_rules! cast_into { @@ -364,6 +376,13 @@ macro_rules! cast_into { ($ty:ty; $($into:ty),*) => {$( impl CastInto<$into> for $ty { fn cast(self) -> $into { + // All we can really do to enforce casting rules is check the rules when in + // debug mode. + debug_assert!(<$into>::try_from(self).is_ok(), "failed cast from {self}"); + self as $into + } + + fn cast_lossy(self) -> $into { self as $into } } From 5e13eeca0147854cf4bb29189910d87d3878af05 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 11 Jan 2025 23:22:12 +0000 Subject: [PATCH 1538/4206] Reorder tests in `run.sh` I do not believe Cargo separately caches crates with different sets of features enabled. So, ensuring that tests run with `unstable-intrinsics` are always grouped should slightly reduce runtime. As an added benefit, all the debug mode tests run first so initial feedback is available faster. --- library/compiler-builtins/libm/ci/run.sh | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 70fc271f1941f..89c9c86315f3a 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -75,16 +75,14 @@ if [ "${BUILD_ONLY:-}" = "1" ]; then else cmd="cargo test --all --target $target $extra_flags" - # Test without intrinsics + # Test once without intrinsics, once with intrinsics enabled $cmd - $cmd --release - - # Test with intrinsic use $cmd --features unstable-intrinsics + $cmd --features unstable-intrinsics --benches + + # Test the same in release mode, which also increases coverage. + $cmd --release $cmd --release --features unstable-intrinsics - - # Make sure benchmarks have correct results - $cmd --benches - $cmd --benches --release + $cmd --release --features unstable-intrinsics --benches fi From 721960c17244975f65f6b542e39a00d04807728e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 11 Jan 2025 23:40:19 +0000 Subject: [PATCH 1539/4206] Remove `ExpInt` from `Float`, always use `i32` instead `ExpInt` is likely to only have performance benefits on 16-bit platforms, but makes working with the exponent more difficult. It seems like a worthwhile tradeoff to instead just use `i32`, so do that here. --- .../libm/crates/libm-test/src/f8_impl.rs | 5 ----- .../libm/src/math/support/float_traits.rs | 22 +++++++------------ .../libm/src/math/support/int_traits.rs | 2 ++ 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs index d378863f2fd92..299553d202ad2 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs @@ -20,7 +20,6 @@ pub struct f8(u8); impl Float for f8 { type Int = u8; type SignedInt = i8; - type ExpInt = i8; const ZERO: Self = Self(0b0_0000_000); const NEG_ZERO: Self = Self(0b1_0000_000); @@ -62,10 +61,6 @@ impl Float for f8 { self.0 & Self::SIGN_MASK != 0 } - fn exp(self) -> Self::ExpInt { - unimplemented!() - } - fn from_bits(a: Self::Int) -> Self { Self(a) } 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 6970509665896..f795527db9771 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,6 @@ use core::{fmt, mem, ops}; -use super::int_traits::{Int, MinInt}; +use super::int_traits::{CastInto, Int, MinInt}; /// Trait for some basic operations on floats #[allow(dead_code)] @@ -25,9 +25,6 @@ pub trait Float: /// 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 NEG_ZERO: Self; const ONE: Self; @@ -98,7 +95,9 @@ pub trait Float: } /// Returns the exponent, not adjusting for bias. - fn exp(self) -> Self::ExpInt; + fn exp(self) -> i32 { + ((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS).cast() + } /// Returns the significand with no implicit bit (or the "fractional" part) fn frac(self) -> Self::Int { @@ -146,7 +145,6 @@ macro_rules! float_impl { $ty:ident, $ity:ident, $sity:ident, - $expty:ident, $bits:expr, $significand_bits:expr, $from_bits:path @@ -154,7 +152,6 @@ macro_rules! float_impl { impl Float for $ty { type Int = $ity; type SignedInt = $sity; - type ExpInt = $expty; const ZERO: Self = 0.0; const NEG_ZERO: Self = -0.0; @@ -191,9 +188,6 @@ macro_rules! float_impl { 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 from_bits(a: Self::Int) -> Self { Self::from_bits(a) } @@ -226,11 +220,11 @@ macro_rules! float_impl { } #[cfg(f16_enabled)] -float_impl!(f16, u16, i16, i8, 16, 10, f16::from_bits); -float_impl!(f32, u32, i32, i16, 32, 23, f32_from_bits); -float_impl!(f64, u64, i64, i16, 64, 52, f64_from_bits); +float_impl!(f16, u16, i16, 16, 10, f16::from_bits); +float_impl!(f32, u32, i32, 32, 23, f32_from_bits); +float_impl!(f64, u64, i64, 64, 52, f64_from_bits); #[cfg(f128_enabled)] -float_impl!(f128, u128, i128, i16, 128, 112, f128::from_bits); +float_impl!(f128, u128, i128, 128, 112, f128::from_bits); /* FIXME(msrv): vendor some things that are not const stable at our MSRV */ 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 0f2d72d9be383..459f0a58bb2a0 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -55,6 +55,8 @@ pub trait Int: + ops::BitAnd + cmp::Ord + CastInto + + CastInto + + CastFrom + CastFrom { fn signed(self) -> OtherSign; From 5c94cce6b2912d1d325d0d863195a6ea37e41503 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 11 Jan 2025 22:30:30 +0000 Subject: [PATCH 1540/4206] Add a `release-checked` profile with debug and overflow assertions A failing debug assertion or overflow without correctly wrapping or saturating is a bug, but the `debug` profile that has these enabled does not run enough test cases to hit edge cases that may trigger these. Add a new `release-checked` profile that enables debug assertions and overflow checks. This seems to only extend per-function test time by a few seconds (or around a minute on longer extensive tests), so enable this as the default on CI. In order to ensure `no_panic` still gets checked, add a build-only step to CI. --- library/compiler-builtins/libm/.github/workflows/main.yml | 3 ++- library/compiler-builtins/libm/Cargo.toml | 7 +++++++ library/compiler-builtins/libm/build.rs | 6 +++++- library/compiler-builtins/libm/ci/run.sh | 8 +++++--- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 320800f2ea7e6..98505ea35c5f3 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -238,7 +238,8 @@ jobs: LIBM_EXTENSIVE_TESTS="$CHANGED" cargo t \ --features test-multiprecision,unstable \ - --release -- extensive + --profile release-checked \ + -- extensive - name: Print test logs if available run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi shell: bash diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index dc362779e84a2..0e444b5834f59 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -61,3 +61,10 @@ no-panic = "0.1.30" # This is needed for no-panic to correctly detect the lack of panics [profile.release] lto = "fat" + +# Release mode with debug assertions +[profile.release-checked] +inherits = "release" +debug-assertions = true +lto = "fat" +overflow-checks = true diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 9c9e0e7232864..ca4a639a12ac9 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -13,8 +13,12 @@ fn main() { #[allow(unexpected_cfgs)] if !cfg!(feature = "checked") { let lvl = env::var("OPT_LEVEL").unwrap(); - if lvl != "0" { + if lvl != "0" && !cfg!(debug_assertions) { println!("cargo:rustc-cfg=assert_no_panic"); + } else if env::var("ENSURE_NO_PANIC").is_ok() { + // Give us a defensive way of ensureing that no-panic is checked when we + // expect it to be. + panic!("`assert_no_panic `was not enabled"); } } diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 89c9c86315f3a..244a22a076de3 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -81,8 +81,10 @@ else $cmd --features unstable-intrinsics --benches # Test the same in release mode, which also increases coverage. - $cmd --release - $cmd --release --features unstable-intrinsics - $cmd --release --features unstable-intrinsics --benches + $cmd --profile release-checked + $cmd --profile release-checked --features unstable-intrinsics + $cmd --profile release-checked --features unstable-intrinsics --benches + + ENSURE_NO_PANIC=1 cargo build --target "$target" --release fi From e1749bdb6d836e6d93c5e694c912b16bee29b317 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 12 Jan 2025 03:25:25 +0000 Subject: [PATCH 1541/4206] Add `biteq` and `exp_unbiased` to `Float` These are two convenience methods. Additionally, add tests for the trait methods, and an `assert_biteq!` macro to check and print the output. --- .../libm/src/math/support/float_traits.rs | 125 ++++++++++++++++-- .../libm/src/math/support/int_traits.rs | 8 +- .../libm/src/math/support/macros.rs | 20 +++ 3 files changed, 143 insertions(+), 10 deletions(-) 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 f795527db9771..3aa0d844a7218 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,6 @@ use core::{fmt, mem, ops}; -use super::int_traits::{CastInto, Int, MinInt}; +use super::int_traits::{CastFrom, CastInto, Int, MinInt}; /// Trait for some basic operations on floats #[allow(dead_code)] @@ -73,11 +73,18 @@ pub trait Float: self.to_bits().signed() } + /// Check bitwise equality. + fn biteq(self, rhs: Self) -> bool { + self.to_bits() == rhs.to_bits() + } + /// 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. + /// represented in multiple different ways. + /// + /// This method returns `true` if two NaNs are compared. Use [`biteq`](Self::biteq) instead + /// if `NaN` should not be treated separately. fn eq_repr(self, rhs: Self) -> bool { - if self.is_nan() && rhs.is_nan() { true } else { self.to_bits() == rhs.to_bits() } + if self.is_nan() && rhs.is_nan() { true } else { self.biteq(rhs) } } /// Returns true if the value is NaN. @@ -94,17 +101,22 @@ pub trait Float: (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO } - /// Returns the exponent, not adjusting for bias. + /// Returns the exponent, not adjusting for bias, not accounting for subnormals or zero. fn exp(self) -> i32 { ((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS).cast() } + /// Extract the exponent and adjust it for bias, not accounting for subnormals or zero. + fn exp_unbiased(self) -> i32 { + self.exp() - (Self::EXP_BIAS as i32) + } + /// Returns the significand with no implicit bit (or the "fractional" part) fn frac(self) -> Self::Int { self.to_bits() & Self::SIG_MASK } - /// Returns the significand with implicit bit + /// Returns the significand with implicit bit. fn imp_frac(self) -> Self::Int { self.frac() | Self::IMPLICIT_BIT } @@ -113,11 +125,11 @@ pub trait Float: 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 from_parts(negative: bool, exponent: i32, significand: Self::Int) -> Self { let sign = if negative { Self::Int::ONE } else { Self::Int::ZERO }; Self::from_bits( (sign << (Self::BITS - 1)) - | ((exponent << Self::SIG_BITS) & Self::EXP_MASK) + | (Self::Int::cast_from(exponent as u32 & Self::EXP_MAX) << Self::SIG_BITS) | (significand & Self::SIG_MASK), ) } @@ -239,3 +251,100 @@ pub const fn f64_from_bits(bits: u64) -> f64 { // SAFETY: POD cast with no preconditions unsafe { mem::transmute::(bits) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg(f16_enabled)] + fn check_f16() { + // Constants + assert_eq!(f16::EXP_MAX, 0b11111); + assert_eq!(f16::EXP_BIAS, 15); + + // `exp_unbiased` + assert_eq!(f16::FRAC_PI_2.exp_unbiased(), 0); + assert_eq!((1.0f16 / 2.0).exp_unbiased(), -1); + assert_eq!(f16::MAX.exp_unbiased(), 15); + assert_eq!(f16::MIN.exp_unbiased(), 15); + assert_eq!(f16::MIN_POSITIVE.exp_unbiased(), -14); + // This is a convenience method and not ldexp, `exp_unbiased` does not return correct + // results for zero and subnormals. + assert_eq!(f16::ZERO.exp_unbiased(), -15); + assert_eq!(f16::from_bits(0x1).exp_unbiased(), -15); + + // `from_parts` + assert_biteq!(f16::from_parts(true, f16::EXP_BIAS as i32, 0), -1.0f16); + assert_biteq!(f16::from_parts(false, 0, 1), f16::from_bits(0x1)); + } + + #[test] + fn check_f32() { + // Constants + assert_eq!(f32::EXP_MAX, 0b11111111); + assert_eq!(f32::EXP_BIAS, 127); + + // `exp_unbiased` + assert_eq!(f32::FRAC_PI_2.exp_unbiased(), 0); + assert_eq!((1.0f32 / 2.0).exp_unbiased(), -1); + assert_eq!(f32::MAX.exp_unbiased(), 127); + assert_eq!(f32::MIN.exp_unbiased(), 127); + assert_eq!(f32::MIN_POSITIVE.exp_unbiased(), -126); + // This is a convenience method and not ldexp, `exp_unbiased` does not return correct + // results for zero and subnormals. + assert_eq!(f32::ZERO.exp_unbiased(), -127); + assert_eq!(f32::from_bits(0x1).exp_unbiased(), -127); + + // `from_parts` + assert_biteq!(f32::from_parts(true, f32::EXP_BIAS as i32, 0), -1.0f32); + assert_biteq!(f32::from_parts(false, 10 + f32::EXP_BIAS as i32, 0), hf32!("0x1p10")); + assert_biteq!(f32::from_parts(false, 0, 1), f32::from_bits(0x1)); + } + + #[test] + fn check_f64() { + // Constants + assert_eq!(f64::EXP_MAX, 0b11111111111); + assert_eq!(f64::EXP_BIAS, 1023); + + // `exp_unbiased` + assert_eq!(f64::FRAC_PI_2.exp_unbiased(), 0); + assert_eq!((1.0f64 / 2.0).exp_unbiased(), -1); + assert_eq!(f64::MAX.exp_unbiased(), 1023); + assert_eq!(f64::MIN.exp_unbiased(), 1023); + assert_eq!(f64::MIN_POSITIVE.exp_unbiased(), -1022); + // This is a convenience method and not ldexp, `exp_unbiased` does not return correct + // results for zero and subnormals. + assert_eq!(f64::ZERO.exp_unbiased(), -1023); + assert_eq!(f64::from_bits(0x1).exp_unbiased(), -1023); + + // `from_parts` + assert_biteq!(f64::from_parts(true, f64::EXP_BIAS as i32, 0), -1.0f64); + assert_biteq!(f64::from_parts(false, 10 + f64::EXP_BIAS as i32, 0), hf64!("0x1p10")); + assert_biteq!(f64::from_parts(false, 0, 1), f64::from_bits(0x1)); + } + + #[test] + #[cfg(f128_enabled)] + fn check_f128() { + // Constants + assert_eq!(f128::EXP_MAX, 0b111111111111111); + assert_eq!(f128::EXP_BIAS, 16383); + + // `exp_unbiased` + assert_eq!(f128::FRAC_PI_2.exp_unbiased(), 0); + assert_eq!((1.0f128 / 2.0).exp_unbiased(), -1); + assert_eq!(f128::MAX.exp_unbiased(), 16383); + assert_eq!(f128::MIN.exp_unbiased(), 16383); + assert_eq!(f128::MIN_POSITIVE.exp_unbiased(), -16382); + // This is a convenience method and not ldexp, `exp_unbiased` does not return correct + // results for zero and subnormals. + assert_eq!(f128::ZERO.exp_unbiased(), -16383); + assert_eq!(f128::from_bits(0x1).exp_unbiased(), -16383); + + // `from_parts` + assert_biteq!(f128::from_parts(true, f128::EXP_BIAS as i32, 0), -1.0f128); + assert_biteq!(f128::from_parts(false, 0, 1), f128::from_bits(0x1)); + } +} 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 459f0a58bb2a0..db799c030c286 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -54,10 +54,14 @@ pub trait Int: + ops::BitXor + ops::BitAnd + cmp::Ord - + CastInto - + CastInto + CastFrom + + CastFrom + CastFrom + + CastFrom + + CastInto + + CastInto + + CastInto + + CastInto { fn signed(self) -> OtherSign; fn unsigned(self) -> Self::Unsigned; diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index f5094b9da8956..076fdf1f775eb 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -106,3 +106,23 @@ macro_rules! hf64 { X }}; } + +/// Assert `F::biteq` with better messages. +#[cfg(test)] +macro_rules! assert_biteq { + ($left:expr, $right:expr, $($arg:tt)*) => {{ + let bits = ($left.to_bits() * 0).leading_zeros(); // hack to get the width from the value + assert!( + $left.biteq($right), + "\nl: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})", + l = $left, + lb = $left.to_bits(), + r = $right, + rb = $right.to_bits(), + width = ((bits / 4) + 2) as usize + ); + }}; + ($left:expr, $right:expr $(,)?) => { + assert_biteq!($left, $right,) + }; +} From 2912076e50f6887315c2bd53359eb57171e1615e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 12 Jan 2025 03:55:46 +0000 Subject: [PATCH 1542/4206] Always use the same seed for benchmarking It would be preferable to switch to a different generator, or at least set the seed within the benchmark, but this is the most straightforward way to make things simple. --- library/compiler-builtins/libm/.github/workflows/main.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 98505ea35c5f3..b14ab40ecda3b 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -156,7 +156,11 @@ jobs: - uses: Swatinem/rust-cache@v2 - name: Download musl source run: ./ci/download-musl.sh - - run: cargo bench --all --features libm-test/short-benchmarks,libm-test/build-musl + - run: | + # Always use the same seed for benchmarks. Ideally we should switch to a + # non-random generator. + export LIBM_SEED=benchesbenchesbenchesbencheswoo! + cargo bench --all --features libm-test/short-benchmarks,libm-test/build-musl msrv: name: Check MSRV From 5b1c1fca03586645768771b5fb1332d37708b182 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 12 Jan 2025 07:43:24 +0000 Subject: [PATCH 1543/4206] Expose C versions of `libm` functions in the `cb` crate `compiler_builtins` exposes an `extern "C"` version of `libm` routines, so add the same here. There really isn't much to test here (unless we later add tests against C `libm` suites), but one nice benefit is this gives us a library with unmangled names that is easy to `objdump`. In accordance with that, also update `cb` to be a `staticlib`. Unfortunately this also means we have to remove it from the workspace, since Cargo doesn't allow setting `panic = "abort"` for a single crate. --- .../libm/.github/workflows/main.yml | 2 +- library/compiler-builtins/libm/.gitignore | 3 +- library/compiler-builtins/libm/Cargo.toml | 5 +- .../compiler-builtins-smoke-test/Cargo.toml | 18 +- .../compiler-builtins-smoke-test/build.rs | 7 + .../compiler-builtins-smoke-test/src/lib.rs | 171 ++++++++++++++++++ 6 files changed, 200 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index b14ab40ecda3b..7e371d6136dad 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -144,7 +144,7 @@ jobs: - name: Install Rust run: rustup update nightly --no-self-update && rustup default nightly - uses: Swatinem/rust-cache@v2 - - run: cargo build -p cb + - run: cargo test --manifest-path crates/compiler-builtins-smoke-test/Cargo.toml benchmarks: name: Benchmarks diff --git a/library/compiler-builtins/libm/.gitignore b/library/compiler-builtins/libm/.gitignore index b6a53275151d5..4e9c9c03ddf3d 100644 --- a/library/compiler-builtins/libm/.gitignore +++ b/library/compiler-builtins/libm/.gitignore @@ -2,8 +2,7 @@ .#* /bin /math/src -/math/target -/target +target Cargo.lock musl/ **.tar.gz diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 0e444b5834f59..fc881b77e548e 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -43,7 +43,6 @@ force-soft-floats = [] [workspace] resolver = "2" members = [ - "crates/compiler-builtins-smoke-test", "crates/libm-macros", "crates/libm-test", "crates/musl-math-sys", @@ -53,6 +52,10 @@ default-members = [ "crates/libm-macros", "crates/libm-test", ] +exclude = [ + # Requires `panic = abort` so can't be a member of the workspace + "crates/compiler-builtins-smoke-test", +] [dev-dependencies] no-panic = "0.1.30" diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index 1f09ce99c482d..d578b0dcd0bdb 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -6,15 +6,21 @@ edition = "2021" publish = false [lib] +crate-type = ["staticlib"] test = false bench = false +[features] +default = ["arch", "unstable-float"] + +# Copied from `libm`'s root `Cargo.toml`' +unstable-float = [] +arch = [] + [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = [ "cfg(arch_enabled)", "cfg(assert_no_panic)", - "cfg(f128_enabled)", - "cfg(f16_enabled)", "cfg(intrinsics_enabled)", 'cfg(feature, values("checked"))', 'cfg(feature, values("force-soft-floats"))', @@ -22,3 +28,11 @@ unexpected_cfgs = { level = "warn", check-cfg = [ 'cfg(feature, values("unstable-intrinsics"))', 'cfg(feature, values("unstable-public-internals"))', ] } + +[profile.dev] +panic = "abort" + +[profile.release] +panic = "abort" +codegen-units = 1 +lto = "fat" diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs new file mode 100644 index 0000000000000..401b7e1eb3aac --- /dev/null +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs @@ -0,0 +1,7 @@ +#[path = "../../configure.rs"] +mod configure; + +fn main() { + let cfg = configure::Config::from_env(); + configure::emit_libm_config(&cfg); +} diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index e3a51a575e489..95ecb840d296e 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -1,8 +1,12 @@ //! Fake compiler-builtins crate //! //! This is used to test that we can source import `libm` into the compiler-builtins crate. +//! Additionally, it provides a `#[no_mangle]` C API that can be easier to inspect than the +//! default `.rlib`. #![feature(core_intrinsics)] +#![feature(f16)] +#![feature(f128)] #![allow(internal_features)] #![no_std] @@ -10,3 +14,170 @@ #[allow(clippy::all)] // We don't get `libm`'s list of `allow`s, so just ignore Clippy. #[path = "../../../src/math/mod.rs"] pub mod libm; + +use core::ffi::c_int; + +/// Mark functions `#[no_mangle]` and with the C ABI. +macro_rules! no_mangle { + ($( $name:ident( $($tt:tt)+ ) -> $ret:ty; )+) => { + $( no_mangle!(@inner $name( $($tt)+ ) -> $ret); )+ + }; + + // Handle simple functions with single return types + (@inner $name:ident( $($arg:ident: $aty:ty),+ ) -> $ret:ty) => { + #[no_mangle] + extern "C" fn $name($($arg: $aty),+) -> $ret { + libm::$name($($arg),+) + } + }; + + + // Functions with `&mut` return values need to be handled differently, use `|` to + // separate inputs vs. outputs. + ( + @inner $name:ident( $($arg:ident: $aty:ty),+ | $($rarg:ident: $rty:ty),+) -> $ret:ty + ) => { + #[no_mangle] + extern "C" fn $name($($arg: $aty,)+ $($rarg: $rty),+) -> $ret { + let ret; + (ret, $(*$rarg),+) = libm::$name($($arg),+); + ret + } + }; +} + +no_mangle! { + frexp(x: f64 | y: &mut c_int) -> f64; + frexpf(x: f32 | y: &mut c_int) -> f32; + acos(x: f64) -> f64; + acosf(x: f32) -> f32; + acosh(x: f64) -> f64; + acoshf(x: f32) -> f32; + asin(x: f64) -> f64; + asinf(x: f32) -> f32; + asinh(x: f64) -> f64; + asinhf(x: f32) -> f32; + atan(x: f64) -> f64; + atan2(x: f64, y: f64) -> f64; + atan2f(x: f32, y: f32) -> f32; + atanf(x: f32) -> f32; + atanh(x: f64) -> f64; + atanhf(x: f32) -> f32; + cbrt(x: f64) -> f64; + cbrtf(x: f32) -> f32; + ceil(x: f64) -> f64; + ceilf(x: f32) -> f32; + copysign(x: f64, y: f64) -> f64; + copysignf(x: f32, y: f32) -> f32; + copysignf128(x: f128, y: f128) -> f128; + copysignf16(x: f16, y: f16) -> f16; + cos(x: f64) -> f64; + cosf(x: f32) -> f32; + cosh(x: f64) -> f64; + coshf(x: f32) -> f32; + erf(x: f64) -> f64; + erfc(x: f64) -> f64; + erfcf(x: f32) -> f32; + erff(x: f32) -> f32; + exp(x: f64) -> f64; + exp10(x: f64) -> f64; + exp10f(x: f32) -> f32; + exp2(x: f64) -> f64; + exp2f(x: f32) -> f32; + expf(x: f32) -> f32; + expm1(x: f64) -> f64; + expm1f(x: f32) -> f32; + fabs(x: f64) -> f64; + fabsf(x: f32) -> f32; + fabsf128(x: f128) -> f128; + fabsf16(x: f16) -> f16; + fdim(x: f64, y: f64) -> f64; + fdimf(x: f32, y: f32) -> f32; + floor(x: f64) -> f64; + floorf(x: f32) -> f32; + fma(x: f64, y: f64, z: f64) -> f64; + fmaf(x: f32, y: f32, z: f32) -> f32; + fmax(x: f64, y: f64) -> f64; + fmaxf(x: f32, y: f32) -> f32; + fmin(x: f64, y: f64) -> f64; + fminf(x: f32, y: f32) -> f32; + fmod(x: f64, y: f64) -> f64; + fmodf(x: f32, y: f32) -> f32; + hypot(x: f64, y: f64) -> f64; + hypotf(x: f32, y: f32) -> f32; + ilogb(x: f64) -> c_int; + ilogbf(x: f32) -> c_int; + j0(x: f64) -> f64; + j0f(x: f32) -> f32; + j1(x: f64) -> f64; + j1f(x: f32) -> f32; + jn(x: c_int, y: f64) -> f64; + jnf(x: c_int, y: f32) -> f32; + ldexp(x: f64, y: c_int) -> f64; + ldexpf(x: f32, y: c_int) -> f32; + lgamma(x: f64) -> f64; + lgamma_r(x: f64 | r: &mut c_int) -> f64; + lgammaf(x: f32) -> f32; + lgammaf_r(x: f32 | r: &mut c_int) -> f32; + log(x: f64) -> f64; + log10(x: f64) -> f64; + log10f(x: f32) -> f32; + log1p(x: f64) -> f64; + log1pf(x: f32) -> f32; + log2(x: f64) -> f64; + log2f(x: f32) -> f32; + logf(x: f32) -> f32; + modf(x: f64 | r: &mut f64) -> f64; + modff(x: f32 | r: &mut f32) -> f32; + nextafter(x: f64, y: f64) -> f64; + nextafterf(x: f32, y: f32) -> f32; + pow(x: f64, y: f64) -> f64; + powf(x: f32, y: f32) -> f32; + remainder(x: f64, y: f64) -> f64; + remainderf(x: f32, y: f32) -> f32; + remquo(x: f64, y: f64 | q: &mut c_int) -> f64; + remquof(x: f32, y: f32 | q: &mut c_int) -> f32; + rint(x: f64) -> f64; + rintf(x: f32) -> f32; + round(x: f64) -> f64; + roundf(x: f32) -> f32; + scalbn(x: f64, y: c_int) -> f64; + scalbnf(x: f32, y: c_int) -> f32; + sin(x: f64) -> f64; + sinf(x: f32) -> f32; + sinh(x: f64) -> f64; + sinhf(x: f32) -> f32; + sqrt(x: f64) -> f64; + sqrtf(x: f32) -> f32; + tan(x: f64) -> f64; + tanf(x: f32) -> f32; + tanh(x: f64) -> f64; + tanhf(x: f32) -> f32; + tgamma(x: f64) -> f64; + tgammaf(x: f32) -> f32; + trunc(x: f64) -> f64; + truncf(x: f32) -> f32; + y0(x: f64) -> f64; + y0f(x: f32) -> f32; + y1(x: f64) -> f64; + y1f(x: f32) -> f32; + yn(x: c_int, y: f64) -> f64; + ynf(x: c_int, y: f32) -> f32; +} + +/* sincos has no direct return type, not worth handling in the macro */ + +#[no_mangle] +extern "C" fn sincos(x: f64, s: &mut f64, c: &mut f64) { + (*s, *c) = libm::sincos(x); +} + +#[no_mangle] +extern "C" fn sincosf(x: f32, s: &mut f32, c: &mut f32) { + (*s, *c) = libm::sincosf(x); +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} From 228c716a43f9c1e8f81762c4662c4cc5dd2c90f1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 12 Jan 2025 04:24:03 +0000 Subject: [PATCH 1544/4206] Add a new precision adjustment for i586 `rint` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `rint` had a couple recent failures from the random tests: ---- mp_random_rint stdout ---- Random Mpfr rint arg 1/1: 10000 iterations (10000 total) using `LIBM_SEED=Fl1f69DaJnwkHN2FeuCXaBFRvJYsPvEY` thread 'mp_random_rint' panicked at crates/libm-test/tests/multiprecision.rs:41:49: called `Result::unwrap()` on an `Err` value: input: (-849751480.5001163,) (0xc1c95316dc4003d0,) expected: -849751481.0 0xc1c95316dc800000 actual: -849751480.0 0xc1c95316dc000000 Caused by: ulp 8388608 > 100000 And: ---- mp_random_rint stdout ---- Random Mpfr rint arg 1/1: 10000 iterations (10000 total) using `LIBM_SEED=XN7VCGhX3Wu6Mzn8COvJPITyZlGP7gN7` thread 'mp_random_rint' panicked at crates/libm-test/tests/multiprecision.rs:41:49: called `Result::unwrap()` on an `Err` value: input: (-12493089.499809155,) (0xc167d4242ffe6fc5,) expected: -12493089.0 0xc167d42420000000 actual: -12493090.0 0xc167d42440000000 Caused by: ulp 536870912 > 100000 It seems we just implement an incorrect rounding mode. Replace the existing `rint` override with an xfail if the difference is 0.0 <= ε <= 1.0. --- .../libm/crates/libm-test/src/precision.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index cbe4bdf8848fb..75b99c6524e5d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -114,7 +114,6 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { Id::Exp10 | Id::Exp10f => ulp = 1_000_000, Id::Exp2 | Id::Exp2f => ulp = 10_000_000, Id::Log1p | Id::Log1pf => ulp = 2, - Id::Rint => ulp = 100_000, Id::Round => ulp = 1, Id::Tan => ulp = 2, _ => (), @@ -261,6 +260,15 @@ impl MaybeOverride<(f64,)> for SpecialCase { } } + if cfg!(x86_no_sse) + && ctx.base_name == BaseName::Rint + && (expected - actual).abs() <= F::ONE + && (expected - actual).abs() > F::ZERO + { + // Our rounding mode is incorrect. + return XFAIL; + } + if ctx.base_name == BaseName::Acosh && input.0 < 1.0 { // The function is undefined for the inputs, musl and our libm both return // random results. From b50ea809ff78b75787dce326c64eab2eebe162d5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 12 Jan 2025 08:02:44 +0000 Subject: [PATCH 1545/4206] Add a new precision adjustment for i586 `exp2f` There was a recent failure from the random tests: ---- mp_random_exp2f stdout ---- Random Mpfr exp2f arg 1/1: 10000 iterations (10000 total) using `LIBM_SEED=fqgMuzs6eqH1VZSEmQpLnThnaIyRUOWe` thread 'mp_random_exp2f' panicked at crates/libm-test/tests/multiprecision.rs:41:49: called `Result::unwrap()` on an `Err` value: input: (127.97238,) (0x42fff1dc,) expected: 3.3383009e38 0x7f7b2556 actual: inf 0x7f800000 Caused by: mismatched infinities Add an xfail for mismatched infinities on i586. --- .../libm/crates/libm-test/src/precision.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 75b99c6524e5d..15913fe6d7599 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -211,6 +211,15 @@ impl MaybeOverride<(f32,)> for SpecialCase { return XFAIL; } + if cfg!(x86_no_sse) + && ctx.base_name == BaseName::Exp2 + && !expected.is_infinite() + && actual.is_infinite() + { + // We return infinity when there is a representable value. Test input: 127.97238 + return XFAIL; + } + maybe_check_nan_bits(actual, expected, ctx) } From 7defd9b4290bce1fd912f55887217c213a642937 Mon Sep 17 00:00:00 2001 From: Hanna Kruppe Date: Sun, 12 Jan 2025 10:56:30 +0100 Subject: [PATCH 1546/4206] Use wasm32 arch intrinsics for rint{,f} --- .../compiler-builtins/libm/etc/function-definitions.json | 2 ++ library/compiler-builtins/libm/src/math/arch/mod.rs | 4 +++- library/compiler-builtins/libm/src/math/arch/wasm32.rs | 8 ++++++++ library/compiler-builtins/libm/src/math/rint.rs | 6 ++++++ library/compiler-builtins/libm/src/math/rintf.rs | 6 ++++++ 5 files changed, 25 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 3cf7e0fed3de8..f60a7e5673c96 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -604,12 +604,14 @@ "rint": { "sources": [ "src/libm_helper.rs", + "src/math/arch/wasm32.rs", "src/math/rint.rs" ], "type": "f64" }, "rintf": { "sources": [ + "src/math/arch/wasm32.rs", "src/math/rintf.rs" ], "type": "f32" diff --git a/library/compiler-builtins/libm/src/math/arch/mod.rs b/library/compiler-builtins/libm/src/math/arch/mod.rs index bd79ae1c69c2c..3992419cbaade 100644 --- a/library/compiler-builtins/libm/src/math/arch/mod.rs +++ b/library/compiler-builtins/libm/src/math/arch/mod.rs @@ -11,7 +11,9 @@ cfg_if! { if #[cfg(all(target_arch = "wasm32", intrinsics_enabled))] { mod wasm32; - pub use wasm32::{ceil, ceilf, fabs, fabsf, floor, floorf, sqrt, sqrtf, trunc, truncf}; + pub use wasm32::{ + ceil, ceilf, fabs, fabsf, floor, floorf, rint, rintf, sqrt, sqrtf, trunc, truncf, + }; } else if #[cfg(target_feature = "sse2")] { mod i686; pub use i686::{sqrt, sqrtf}; diff --git a/library/compiler-builtins/libm/src/math/arch/wasm32.rs b/library/compiler-builtins/libm/src/math/arch/wasm32.rs index 384445f129142..de80c8a581726 100644 --- a/library/compiler-builtins/libm/src/math/arch/wasm32.rs +++ b/library/compiler-builtins/libm/src/math/arch/wasm32.rs @@ -25,6 +25,14 @@ 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 rintf(x: f32) -> f32 { + core::arch::wasm32::f32_nearest(x) +} + pub fn sqrt(x: f64) -> f64 { core::arch::wasm32::f64_sqrt(x) } diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index cbdc3c2b91c82..50192ffdf03db 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -1,5 +1,11 @@ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn rint(x: f64) -> f64 { + select_implementation! { + name: rint, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + let one_over_e = 1.0 / f64::EPSILON; let as_u64: u64 = x.to_bits(); let exponent: u64 = (as_u64 >> 52) & 0x7ff; diff --git a/library/compiler-builtins/libm/src/math/rintf.rs b/library/compiler-builtins/libm/src/math/rintf.rs index 2d22c9393543a..64968b6be3a3d 100644 --- a/library/compiler-builtins/libm/src/math/rintf.rs +++ b/library/compiler-builtins/libm/src/math/rintf.rs @@ -1,5 +1,11 @@ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn rintf(x: f32) -> f32 { + select_implementation! { + name: rintf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + let one_over_e = 1.0 / f32::EPSILON; let as_u32: u32 = x.to_bits(); let exponent: u32 = (as_u32 >> 23) & 0xff; From 87cc064e35d4fc65caf2da13bf263b1323b16760 Mon Sep 17 00:00:00 2001 From: Hanna Kruppe Date: Sun, 12 Jan 2025 11:16:40 +0100 Subject: [PATCH 1547/4206] Introduce arch::aarch64 and use it for rint{,f} --- .../libm/etc/function-definitions.json | 2 ++ .../libm/src/math/arch/aarch64.rs | 33 +++++++++++++++++++ .../libm/src/math/arch/mod.rs | 7 ++++ .../compiler-builtins/libm/src/math/rint.rs | 5 ++- .../compiler-builtins/libm/src/math/rintf.rs | 5 ++- 5 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/arch/aarch64.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index f60a7e5673c96..39b6c97029cb4 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -604,6 +604,7 @@ "rint": { "sources": [ "src/libm_helper.rs", + "src/math/arch/aarch64.rs", "src/math/arch/wasm32.rs", "src/math/rint.rs" ], @@ -611,6 +612,7 @@ }, "rintf": { "sources": [ + "src/math/arch/aarch64.rs", "src/math/arch/wasm32.rs", "src/math/rintf.rs" ], diff --git a/library/compiler-builtins/libm/src/math/arch/aarch64.rs b/library/compiler-builtins/libm/src/math/arch/aarch64.rs new file mode 100644 index 0000000000000..374ec11bfec3f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/aarch64.rs @@ -0,0 +1,33 @@ +use core::arch::aarch64::{ + float32x2_t, float64x1_t, vdup_n_f32, vdup_n_f64, vget_lane_f32, vget_lane_f64, vrndn_f32, + vrndn_f64, +}; + +pub fn rint(x: f64) -> f64 { + // SAFETY: only requires target_feature=neon, ensured by `cfg_if` in parent module. + let x_vec: float64x1_t = unsafe { vdup_n_f64(x) }; + + // SAFETY: only requires target_feature=neon, ensured by `cfg_if` in parent module. + let result_vec: float64x1_t = unsafe { vrndn_f64(x_vec) }; + + // SAFETY: only requires target_feature=neon, ensured by `cfg_if` in parent module. + let result: f64 = unsafe { vget_lane_f64::<0>(result_vec) }; + + result +} + +pub fn rintf(x: f32) -> f32 { + // There's a scalar form of this instruction (FRINTN) but core::arch doesn't expose it, so we + // have to use the vector form and drop the other lanes afterwards. + + // SAFETY: only requires target_feature=neon, ensured by `cfg_if` in parent module. + let x_vec: float32x2_t = unsafe { vdup_n_f32(x) }; + + // SAFETY: only requires target_feature=neon, ensured by `cfg_if` in parent module. + let result_vec: float32x2_t = unsafe { vrndn_f32(x_vec) }; + + // SAFETY: only requires target_feature=neon, ensured by `cfg_if` in parent module. + let result: f32 = unsafe { vget_lane_f32::<0>(result_vec) }; + + result +} diff --git a/library/compiler-builtins/libm/src/math/arch/mod.rs b/library/compiler-builtins/libm/src/math/arch/mod.rs index 3992419cbaade..091d7650a5acc 100644 --- a/library/compiler-builtins/libm/src/math/arch/mod.rs +++ b/library/compiler-builtins/libm/src/math/arch/mod.rs @@ -17,6 +17,13 @@ cfg_if! { } else if #[cfg(target_feature = "sse2")] { mod i686; pub use i686::{sqrt, sqrtf}; + } else if #[cfg(all( + target_arch = "aarch64", // TODO: also arm64ec? + target_feature = "neon", + target_endian = "little", // see https://github.com/rust-lang/stdarch/issues/1484 + ))] { + mod aarch64; + pub use aarch64::{rint, rintf}; } } diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index 50192ffdf03db..c9ea6402ec73d 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -2,7 +2,10 @@ pub fn rint(x: f64) -> f64 { select_implementation! { name: rint, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), + use_arch: any( + all(target_arch = "wasm32", intrinsics_enabled), + all(target_arch = "aarch64", target_feature = "neon", target_endian = "little"), + ), args: x, } diff --git a/library/compiler-builtins/libm/src/math/rintf.rs b/library/compiler-builtins/libm/src/math/rintf.rs index 64968b6be3a3d..33b5b3ddebf67 100644 --- a/library/compiler-builtins/libm/src/math/rintf.rs +++ b/library/compiler-builtins/libm/src/math/rintf.rs @@ -2,7 +2,10 @@ pub fn rintf(x: f32) -> f32 { select_implementation! { name: rintf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), + use_arch: any( + all(target_arch = "wasm32", intrinsics_enabled), + all(target_arch = "aarch64", target_feature = "neon", target_endian = "little"), + ), args: x, } From 504616d5a087126825357aae5a4a319d05f1a3ad Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 03:14:43 +0000 Subject: [PATCH 1548/4206] Rename the `test-multiprecision` feature to `build-mpfr` Currently the features that control what we test against are `build-musl` and `test-multiprecision`. I didn't name them very consistently and there isn't really any reason for that. Rename `test-multiprecision` to `build-mpfr` to better reflect what it actually does and to be more consistent with `build-musl`. --- library/compiler-builtins/libm/.github/workflows/main.yml | 4 ++-- library/compiler-builtins/libm/CONTRIBUTING.md | 2 +- library/compiler-builtins/libm/ci/run.sh | 8 ++++---- .../compiler-builtins/libm/crates/libm-test/Cargo.toml | 2 +- .../compiler-builtins/libm/crates/libm-test/src/lib.rs | 2 +- .../libm/crates/libm-test/src/run_cfg.rs | 2 +- .../libm/crates/libm-test/tests/multiprecision.rs | 2 +- .../libm/crates/libm-test/tests/z_extensive/main.rs | 6 +++--- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 7e371d6136dad..d54288574ac8c 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -133,7 +133,7 @@ jobs: run: ./ci/download-musl.sh - run: | cargo clippy --all \ - --features libm-test/build-musl,libm-test/test-multiprecision \ + --features libm-test/build-musl,libm-test/build-mpfr \ --all-targets builtins: @@ -241,7 +241,7 @@ jobs: fi LIBM_EXTENSIVE_TESTS="$CHANGED" cargo t \ - --features test-multiprecision,unstable \ + --features build-mpfr,unstable \ --profile release-checked \ -- extensive - name: Print test logs if available diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md index aadcdf03618e2..f7560878ddf66 100644 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -69,7 +69,7 @@ If you'd like to run tests with randomized inputs that get compared against infinite-precision results, run: ```sh -cargo test --features libm-test/test-multiprecision,libm-test/build-musl --release +cargo test --features libm-test/build-mpfr,libm-test/build-musl --release ``` The multiprecision tests use the [`rug`] crate for bindings to MPFR. MPFR can diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 244a22a076de3..63678620c7c0c 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -44,11 +44,11 @@ case "$target" in # Targets that aren't cross compiled work fine # FIXME(ci): we should be able to enable aarch64 Linux here once GHA # support rolls out. - x86_64*) extra_flags="$extra_flags --features libm-test/test-multiprecision" ;; - i686*) extra_flags="$extra_flags --features libm-test/test-multiprecision" ;; - i586*) extra_flags="$extra_flags --features libm-test/test-multiprecision --features gmp-mpfr-sys/force-cross" ;; + x86_64*) extra_flags="$extra_flags --features libm-test/build-mpfr" ;; + i686*) extra_flags="$extra_flags --features libm-test/build-mpfr" ;; + i586*) extra_flags="$extra_flags --features libm-test/build-mpfr --features gmp-mpfr-sys/force-cross" ;; # Apple aarch64 is native - aarch64*apple*) extra_flags="$extra_flags --features libm-test/test-multiprecision" ;; + aarch64*apple*) extra_flags="$extra_flags --features libm-test/build-mpfr" ;; esac # FIXME: `STATUS_DLL_NOT_FOUND` testing macros on CI. diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 621e587c56daf..3cf4a08e1dabf 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -12,7 +12,7 @@ unstable-float = ["libm/unstable-float", "rug?/nightly-float"] # Generate tests which are random inputs and the outputs are calculated with # musl libc. -test-multiprecision = ["dep:az", "dep:rug", "dep:gmp-mpfr-sys"] +build-mpfr = ["dep:az", "dep:rug", "dep:gmp-mpfr-sys"] # Build our own musl for testing and benchmarks build-musl = ["dep:musl-math-sys"] diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 6e7017f093c38..cb89f1c8ba7f7 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -5,7 +5,7 @@ pub mod domain; mod f8_impl; pub mod gen; -#[cfg(feature = "test-multiprecision")] +#[cfg(feature = "build-mpfr")] pub mod mpfloat; mod num; pub mod op; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index 48a654caaf8fb..4a52091fe8d28 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -126,7 +126,7 @@ impl TestEnv { let id = ctx.fn_ident; let op = id.math_op(); - let will_run_mp = cfg!(feature = "test-multiprecision"); + let will_run_mp = cfg!(feature = "build-mpfr"); // Tests are pretty slow on non-64-bit targets, x86 MacOS, and targets that run in QEMU. Start // with a reduced number on these platforms. diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index e2766cfdabd75..2d8856e166e4c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -1,6 +1,6 @@ //! Test with "infinite precision" -#![cfg(feature = "test-multiprecision")] +#![cfg(feature = "build-mpfr")] use libm_test::domain::HasDomain; use libm_test::gen::random::RandomInput; diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/main.rs b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/main.rs index 3a2af88bd83b0..5448cb6eaa5bd 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/main.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/main.rs @@ -1,14 +1,14 @@ //! `main` is just a wrapper to handle configuration. -#[cfg(not(feature = "test-multiprecision"))] +#[cfg(not(feature = "build-mpfr"))] fn main() { eprintln!("multiprecision not enabled; skipping extensive tests"); } -#[cfg(feature = "test-multiprecision")] +#[cfg(feature = "build-mpfr")] mod run; -#[cfg(feature = "test-multiprecision")] +#[cfg(feature = "build-mpfr")] fn main() { run::run(); } From 3de783c40f5675f239db882f2aecf614907f1b01 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 03:17:54 +0000 Subject: [PATCH 1549/4206] Enable `build-mpfr` and `build-musl` by default Most users who are developing this crate are likely running on a Unix system, since there isn't much to test against otherwise. For convenience, enable the features required to run these tests by default. --- .../libm/.github/workflows/main.yml | 5 +--- .../compiler-builtins/libm/CONTRIBUTING.md | 11 +++----- library/compiler-builtins/libm/ci/run.sh | 27 +++++++++++-------- .../libm/crates/libm-test/Cargo.toml | 2 +- 4 files changed, 22 insertions(+), 23 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index d54288574ac8c..35b307f77116c 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -131,10 +131,7 @@ jobs: - uses: Swatinem/rust-cache@v2 - name: Download musl source run: ./ci/download-musl.sh - - run: | - cargo clippy --all \ - --features libm-test/build-musl,libm-test/build-mpfr \ - --all-targets + - run: cargo clippy --all --all-features --all-targets builtins: name: Check use with compiler-builtins diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md index f7560878ddf66..ba7f78ca014ce 100644 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -62,15 +62,12 @@ Check [PR #65] for an example. Normal tests can be executed with: ```sh -cargo test +# `--release` ables more test cases +cargo test --release ``` -If you'd like to run tests with randomized inputs that get compared against -infinite-precision results, run: - -```sh -cargo test --features libm-test/build-mpfr,libm-test/build-musl --release -``` +If you are on a system that cannot build musl or MPFR, passing +`--no-default-features` will run some limited tests. The multiprecision tests use the [`rug`] crate for bindings to MPFR. MPFR can be difficult to build on non-Unix systems, refer to [`gmp_mpfr_sys`] for help. diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 63678620c7c0c..35b84809fa2c7 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -14,7 +14,15 @@ if [ -z "$target" ]; then target="$host_target" fi -extra_flags="" +# We enumerate features manually. +extra_flags="--no-default-features" + +# Enable arch-specific routines when available. +extra_flags="$extra_flags --features arch" + +# Always enable `unstable-float` since it expands available API but does not +# change any implementations. +extra_flags="$extra_flags --features unstable-float" # We need to specifically skip tests for musl-math-sys on systems that can't # build musl since otherwise `--all` will activate it. @@ -57,14 +65,8 @@ case "$target" in *windows-gnu) extra_flags="$extra_flags --exclude libm-macros" ;; esac -# Make sure we can build with overriding features. We test the indibidual -# features it controls separately. -cargo check --no-default-features -cargo check --features "force-soft-floats" - -# Always enable `unstable-float` since it expands available API but does not -# change any implementations. -extra_flags="$extra_flags --features unstable-float" +# Make sure we can build with overriding features. +cargo check -p libm --no-default-features if [ "${BUILD_ONLY:-}" = "1" ]; then cmd="cargo build --target $target --package libm" @@ -80,11 +82,14 @@ else $cmd --features unstable-intrinsics $cmd --features unstable-intrinsics --benches - # Test the same in release mode, which also increases coverage. + # Test the same in release mode, which also increases coverage. Also ensure + # the soft float routines are checked. $cmd --profile release-checked + $cmd --profile release-checked --features force-soft-floats $cmd --profile release-checked --features unstable-intrinsics $cmd --profile release-checked --features unstable-intrinsics --benches - ENSURE_NO_PANIC=1 cargo build --target "$target" --release + # Ensure that the routines do not panic. + ENSURE_NO_PANIC=1 cargo build -p libm --target "$target" --no-default-features --release fi diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 3cf4a08e1dabf..d3f18ab3e5bc8 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [features] -default = ["unstable-float"] +default = ["build-mpfr", "build-musl", "unstable-float"] # Propagated from libm because this affects which functions we test. unstable-float = ["libm/unstable-float", "rug?/nightly-float"] From dfa694a8e43ad3fd56f2897ab48327a242d7c5b8 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 03:12:12 +0000 Subject: [PATCH 1550/4206] Add a utility crate for quick evaluation Introduce a simple binary that can run arbitrary input against any of the available implementations (musl, MPFR, our libm). This provides an easy way to check results, or run specific cases against a debugger. Examples: $ cargo run -p util -- eval libm pow 1.6 2.4 3.089498284311124 $ cargo run -p util -- eval mpfr pow 1.6 2.4 3.089498284311124 $ cargo run -p util -- eval musl tgamma 1.2344597839132 0.9097442657960874 $ cargo run -p util -- eval mpfr tgamma 1.2344597839132 0.9097442657960874 $ cargo run -p util -- eval libm tgamma 1.2344597839132 0.9097442657960871 $ cargo run -p util -- eval musl sincos 3.1415926535 (8.979318433952318e-11, -1.0) --- library/compiler-builtins/libm/Cargo.toml | 1 + .../libm/crates/libm-test/src/mpfloat.rs | 26 ++ .../libm/crates/util/Cargo.toml | 19 ++ .../libm/crates/util/build.rs | 9 + .../libm/crates/util/src/main.rs | 243 ++++++++++++++++++ 5 files changed, 298 insertions(+) create mode 100644 library/compiler-builtins/libm/crates/util/Cargo.toml create mode 100644 library/compiler-builtins/libm/crates/util/build.rs create mode 100644 library/compiler-builtins/libm/crates/util/src/main.rs diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index fc881b77e548e..820c013478f43 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -46,6 +46,7 @@ members = [ "crates/libm-macros", "crates/libm-test", "crates/musl-math-sys", + "crates/util", ] default-members = [ ".", diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index f71e72cd57129..092f5f1d24d75 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -471,6 +471,32 @@ impl MpOp for crate::op::lgammaf_r::Routine { } } +/* stub implementations so we don't need to special case them */ + +impl MpOp for crate::op::nextafter::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + unimplemented!("nextafter does not yet have a MPFR operation"); + } + + fn run(_this: &mut Self::MpTy, _input: Self::RustArgs) -> Self::RustRet { + unimplemented!("nextafter does not yet have a MPFR operation"); + } +} + +impl MpOp for crate::op::nextafterf::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + unimplemented!("nextafter does not yet have a MPFR operation"); + } + + fn run(_this: &mut Self::MpTy, _input: Self::RustArgs) -> Self::RustRet { + unimplemented!("nextafter does not yet have a MPFR operation"); + } +} + /// `rug` does not provide `remquo` so this exposes `mpfr_remquo`. See rug#76. fn mpfr_remquo(r: &mut MpFloat, x: &MpFloat, y: &MpFloat, round: Round) -> (Ordering, c_long) { let r = r.as_raw_mut(); diff --git a/library/compiler-builtins/libm/crates/util/Cargo.toml b/library/compiler-builtins/libm/crates/util/Cargo.toml new file mode 100644 index 0000000000000..acf5db704b159 --- /dev/null +++ b/library/compiler-builtins/libm/crates/util/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "util" +version = "0.1.0" +edition = "2021" +publish = false + +[features] +default = ["build-musl", "build-mpfr", "unstable-float"] +build-musl = ["libm-test/build-musl", "dep:musl-math-sys"] +build-mpfr = ["libm-test/build-mpfr", "dep:az", "dep:rug"] +unstable-float = ["libm/unstable-float", "libm-test/unstable-float", "rug?/nightly-float"] + +[dependencies] +az = { version = "1.2.1", optional = true } +libm = { path = "../..", default-features = false } +libm-macros = { path = "../libm-macros" } +libm-test = { path = "../libm-test", default-features = false } +musl-math-sys = { path = "../musl-math-sys", optional = true } +rug = { version = "1.26.1", optional = true, default-features = false, features = ["float", "std"] } diff --git a/library/compiler-builtins/libm/crates/util/build.rs b/library/compiler-builtins/libm/crates/util/build.rs new file mode 100644 index 0000000000000..0745ef3dd6f3a --- /dev/null +++ b/library/compiler-builtins/libm/crates/util/build.rs @@ -0,0 +1,9 @@ +#![allow(unexpected_cfgs)] + +#[path = "../../configure.rs"] +mod configure; + +fn main() { + let cfg = configure::Config::from_env(); + configure::emit_libm_config(&cfg); +} diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs new file mode 100644 index 0000000000000..f7bd31bb689c0 --- /dev/null +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -0,0 +1,243 @@ +//! Helper CLI utility for common tasks. + +#![cfg_attr(f16_enabled, feature(f16))] +#![cfg_attr(f128_enabled, feature(f128))] + +use std::any::type_name; +use std::env; +use std::str::FromStr; + +#[cfg(feature = "build-mpfr")] +use az::Az; +#[cfg(feature = "build-mpfr")] +use libm_test::mpfloat::MpOp; +use libm_test::{MathOp, TupleCall}; + +const USAGE: &str = "\ +usage: + +cargo run -p util -- + +SUBCOMMAND: + eval inputs... + Evaulate the expression with a given basis. This can be useful for + running routines with a debugger, or quickly checking input. Examples: + * eval musl sinf 1.234 # print the results of musl sinf(1.234f32) + * eval mpfr pow 1.234 2.432 # print the results of mpfr pow(1.234, 2.432) +"; + +fn main() { + let args = env::args().collect::>(); + let str_args = args.iter().map(|s| s.as_str()).collect::>(); + + match &str_args.as_slice()[1..] { + ["eval", basis, op, inputs @ ..] => do_eval(basis, op, inputs), + _ => { + println!("{USAGE}\nunrecognized input `{str_args:?}`"); + std::process::exit(1); + } + } +} + +macro_rules! handle_call { + ( + fn_name: $fn_name:ident, + CFn: $CFn:ty, + RustFn: $RustFn:ty, + RustArgs: $RustArgs:ty, + attrs: [$($attr:meta),*], + extra: ($basis:ident, $op:ident, $inputs:ident), + fn_extra: $musl_fn:expr, + ) => { + $(#[$attr])* + if $op == stringify!($fn_name) { + type Op = libm_test::op::$fn_name::Routine; + + let input = <$RustArgs>::parse($inputs); + let libm_fn: ::RustFn = libm::$fn_name; + + let output = match $basis { + "libm" => input.call(libm_fn), + #[cfg(feature = "build-musl")] + "musl" => { + let musl_fn: ::CFn = + $musl_fn.unwrap_or_else(|| panic!("no musl function for {}", $op)); + input.call(musl_fn) + } + #[cfg(feature = "build-mpfr")] + "mpfr" => { + let mut mp = ::new_mp(); + Op::run(&mut mp, input) + } + _ => panic!("unrecognized or disabled basis '{}'", $basis), + }; + println!("{output:?}"); + return; + } + }; +} + +/// Evaluate the specified operation with a given basis. +fn do_eval(basis: &str, op: &str, inputs: &[&str]) { + libm_macros::for_each_function! { + callback: handle_call, + emit_types: [CFn, RustFn, RustArgs], + extra: (basis, op, inputs), + fn_extra: match MACRO_FN_NAME { + copysignf16 | copysignf128 | fabsf16 | fabsf128 => None, + _ => Some(musl_math_sys::MACRO_FN_NAME) + } + } + + panic!("no operation matching {op}"); +} + +/// Parse a tuple from a space-delimited string. +trait ParseTuple { + fn parse(input: &[&str]) -> Self; +} + +macro_rules! impl_parse_tuple { + ($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 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)) + } + } + + impl ParseTuple for ($ty, i32) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); + (parse(input, 0), parse(input, 1)) + } + } + + impl ParseTuple for (i32, $ty) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); + (parse(input, 0), parse(input, 1)) + } + } + + impl ParseTuple for ($ty, $ty, $ty) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 2, "expected three arguments, got {input:?}"); + (parse(input, 0), parse(input, 1), parse(input, 3)) + } + } + }; +} + +#[allow(unused_macros)] +#[cfg(feature = "build-mpfr")] +macro_rules! impl_parse_tuple_via_rug { + ($ty:ty) => { + impl ParseTuple for ($ty,) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 1, "expected a single argument, got {input:?}"); + (parse_rug(input, 0),) + } + } + + impl ParseTuple for ($ty, $ty) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); + (parse_rug(input, 0), parse_rug(input, 1)) + } + } + + impl ParseTuple for ($ty, i32) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); + (parse_rug(input, 0), parse(input, 1)) + } + } + + impl ParseTuple for (i32, $ty) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); + (parse(input, 0), parse_rug(input, 1)) + } + } + + impl ParseTuple for ($ty, $ty, $ty) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 2, "expected three arguments, got {input:?}"); + (parse_rug(input, 0), parse_rug(input, 1), parse_rug(input, 3)) + } + } + }; +} + +// Fallback for when Rug is not built. +#[allow(unused_macros)] +#[cfg(not(feature = "build-mpfr"))] +macro_rules! impl_parse_tuple_via_rug { + ($ty:ty) => { + impl ParseTuple for ($ty,) { + fn parse(_input: &[&str]) -> Self { + panic!("parsing this type requires the `build-mpfr` feature") + } + } + + impl ParseTuple for ($ty, $ty) { + fn parse(_input: &[&str]) -> Self { + panic!("parsing this type requires the `build-mpfr` feature") + } + } + + impl ParseTuple for ($ty, i32) { + fn parse(_input: &[&str]) -> Self { + panic!("parsing this type requires the `build-mpfr` feature") + } + } + + impl ParseTuple for (i32, $ty) { + fn parse(_input: &[&str]) -> Self { + panic!("parsing this type requires the `build-mpfr` feature") + } + } + + impl ParseTuple for ($ty, $ty, $ty) { + fn parse(_input: &[&str]) -> Self { + panic!("parsing this type requires the `build-mpfr` feature") + } + } + }; +} + +impl_parse_tuple!(f32); +impl_parse_tuple!(f64); + +#[cfg(f16_enabled)] +impl_parse_tuple_via_rug!(f16); +#[cfg(f128_enabled)] +impl_parse_tuple_via_rug!(f128); + +/// Try to parse the number, printing a nice message on failure. +fn parse(input: &[&str], idx: usize) -> F { + let s = input[idx]; + s.parse().unwrap_or_else(|_| panic!("invalid {} input '{s}'", type_name::())) +} + +/// Try to parse the float type going via `rug`, for `f16` and `f128` which don't yet implement +/// `FromStr`. +#[cfg(feature = "build-mpfr")] +fn parse_rug(input: &[&str], idx: usize) -> F +where + rug::Float: az::Cast, +{ + let s = input[idx]; + let x = + rug::Float::parse(s).unwrap_or_else(|_| panic!("invalid {} input '{s}'", type_name::())); + let x = rug::Float::with_val(F::BITS, x); + x.az() +} From 6ac06a97e591f3373b16859756567901ff5056fb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 11 Jan 2025 23:38:19 +0000 Subject: [PATCH 1551/4206] Add a generic version of `trunc` The algorithm is identical for both types, so this is a straightforward routine to port. --- .../libm/src/math/generic/mod.rs | 2 + .../libm/src/math/generic/trunc.rs | 54 +++++++++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 2 +- .../compiler-builtins/libm/src/math/trunc.rs | 30 +---------- .../compiler-builtins/libm/src/math/truncf.rs | 22 +------- 5 files changed, 59 insertions(+), 51 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/trunc.rs diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index 08524b685e251..e5166ca10eb32 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -1,5 +1,7 @@ mod copysign; mod fabs; +mod trunc; pub use copysign::copysign; pub use fabs::fabs; +pub use trunc::trunc; diff --git a/library/compiler-builtins/libm/src/math/generic/trunc.rs b/library/compiler-builtins/libm/src/math/generic/trunc.rs new file mode 100644 index 0000000000000..5d0ba6109afa3 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/trunc.rs @@ -0,0 +1,54 @@ +use super::super::{Float, Int, IntTy, MinInt}; + +pub fn trunc(x: F) -> F { + let mut xi: F::Int = x.to_bits(); + let e: i32 = x.exp_unbiased(); + + // C1: The represented value has no fractional part, so no truncation is needed + if e >= F::SIG_BITS as i32 { + return x; + } + + let mask = if e < 0 { + // C2: If the exponent is negative, the result will be zero so we mask out everything + // except the sign. + F::SIGN_MASK + } else { + // C3: Otherwise, we mask out the last `e` bits of the significand. + !(F::SIG_MASK >> e.unsigned()) + }; + + // C4: If the to-be-masked-out portion is already zero, we have an exact result + if (xi & !mask) == IntTy::::ZERO { + return x; + } + + // C5: Otherwise the result is inexact and we will truncate. Raise `FE_INEXACT`, mask the + // result, and return. + force_eval!(x + F::MAX); + xi &= mask; + F::from_bits(xi) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sanity_check() { + assert_biteq!(trunc(1.1f32), 1.0); + assert_biteq!(trunc(1.1f64), 1.0); + + // C1 + assert_biteq!(trunc(hf32!("0x1p23")), hf32!("0x1p23")); + assert_biteq!(trunc(hf64!("0x1p52")), hf64!("0x1p52")); + assert_biteq!(trunc(hf32!("-0x1p23")), hf32!("-0x1p23")); + assert_biteq!(trunc(hf64!("-0x1p52")), hf64!("-0x1p52")); + + // C2 + assert_biteq!(trunc(hf32!("0x1p-1")), 0.0); + assert_biteq!(trunc(hf64!("0x1p-1")), 0.0); + assert_biteq!(trunc(hf32!("-0x1p-1")), -0.0); + assert_biteq!(trunc(hf64!("-0x1p-1")), -0.0); + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 5baf35e424533..c0d038a0c67f1 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -121,7 +121,7 @@ use self::rem_pio2::rem_pio2; use self::rem_pio2_large::rem_pio2_large; use self::rem_pio2f::rem_pio2f; #[allow(unused_imports)] -use self::support::{CastFrom, CastInto, DInt, Float, HInt, Int, MinInt}; +use self::support::{CastFrom, CastInto, DInt, Float, HInt, Int, IntTy, MinInt}; // Public modules mod acos; diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs index 7e5c4f2c2ae51..2cc8aaa7e8f98 100644 --- a/library/compiler-builtins/libm/src/math/trunc.rs +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -1,5 +1,3 @@ -use core::f64; - /// Rounds the number toward 0 to the closest integral value (f64). /// /// This effectively removes the decimal part of the number, leaving the integral part. @@ -11,31 +9,5 @@ pub fn trunc(x: f64) -> f64 { args: x, } - let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120 - - let mut i: u64 = x.to_bits(); - let mut e: i64 = ((i >> 52) & 0x7ff) as i64 - 0x3ff + 12; - let m: u64; - - if e >= 52 + 12 { - return x; - } - if e < 12 { - e = 1; - } - m = -1i64 as u64 >> e; - if (i & m) == 0 { - return x; - } - force_eval!(x + x1p120); - i &= !m; - f64::from_bits(i) -} - -#[cfg(test)] -mod tests { - #[test] - fn sanity_check() { - assert_eq!(super::trunc(1.1), 1.0); - } + super::generic::trunc(x) } diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs index b491747d999e6..14533a2670632 100644 --- a/library/compiler-builtins/libm/src/math/truncf.rs +++ b/library/compiler-builtins/libm/src/math/truncf.rs @@ -1,5 +1,3 @@ -use core::f32; - /// Rounds the number toward 0 to the closest integral value (f32). /// /// This effectively removes the decimal part of the number, leaving the integral part. @@ -11,25 +9,7 @@ pub fn truncf(x: f32) -> f32 { args: x, } - let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 - - let mut i: u32 = x.to_bits(); - let mut e: i32 = ((i >> 23) & 0xff) as i32 - 0x7f + 9; - let m: u32; - - if e >= 23 + 9 { - return x; - } - if e < 9 { - e = 1; - } - m = -1i32 as u32 >> e; - if (i & m) == 0 { - return x; - } - force_eval!(x + x1p120); - i &= !m; - f32::from_bits(i) + super::generic::trunc(x) } // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 From b558b365d380448159564df45de9638a60905815 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 12 Jan 2025 04:12:56 +0000 Subject: [PATCH 1552/4206] Add `truncf16` and `truncf128` Use the generic algorithms to provide implementations for these routines. --- .../compiler-builtins-smoke-test/src/lib.rs | 2 ++ .../libm/crates/libm-macros/src/shared.rs | 4 ++-- .../libm/crates/libm-test/benches/random.rs | 2 +- .../libm/crates/libm-test/src/domain.rs | 10 ++++++++++ .../libm/crates/libm-test/src/mpfloat.rs | 3 +++ .../crates/libm-test/tests/compare_built_musl.rs | 4 +++- .../libm/crates/util/src/main.rs | 2 +- .../libm/etc/function-definitions.json | 16 ++++++++++++++++ .../compiler-builtins/libm/etc/function-list.txt | 2 ++ .../libm/src/math/generic/trunc.rs | 3 +++ library/compiler-builtins/libm/src/math/mod.rs | 4 ++++ .../compiler-builtins/libm/src/math/truncf128.rs | 7 +++++++ .../compiler-builtins/libm/src/math/truncf16.rs | 7 +++++++ 13 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/truncf128.rs create mode 100644 library/compiler-builtins/libm/src/math/truncf16.rs diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index 95ecb840d296e..3416a2229598d 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -157,6 +157,8 @@ no_mangle! { tgammaf(x: f32) -> f32; trunc(x: f64) -> f64; truncf(x: f32) -> f32; + truncf128(x: f128) -> f128; + truncf16(x: f16) -> f16; y0(x: f64) -> f64; y0f(x: f32) -> f32; y1(x: f64) -> f64; diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index 16547404fffa1..24fccd6f2489d 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -9,7 +9,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16], returns: &[Ty::F16] }, None, - &["fabsf16"], + &["fabsf16", "truncf16"], ), ( // `fn(f32) -> f32` @@ -40,7 +40,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F128, Signature { args: &[Ty::F128], returns: &[Ty::F128] }, None, - &["fabsf128"], + &["fabsf128", "truncf128"], ), ( // `(f16, f16) -> f16` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index cd1e2d2ccc6ff..8c6afff25981d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -117,7 +117,7 @@ libm_macros::for_each_function! { exp10 | exp10f | exp2 | exp2f => (true, Some(musl_math_sys::MACRO_FN_NAME)), // Musl does not provide `f16` and `f128` functions - copysignf16 | copysignf128 | fabsf16 | fabsf128 => (false, None), + copysignf16 | copysignf128 | fabsf16 | fabsf128 | truncf16 | truncf128 => (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/crates/libm-test/src/domain.rs b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs index 52393d40243ec..adafb9faa3513 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs @@ -199,3 +199,13 @@ impl HasDomain for crate::op::fabsf16::Routine { impl HasDomain for crate::op::fabsf128::Routine { const DOMAIN: Domain = Domain::::UNBOUNDED; } + +#[cfg(f16_enabled)] +impl HasDomain for crate::op::truncf16::Routine { + const DOMAIN: Domain = Domain::::UNBOUNDED; +} + +#[cfg(f128_enabled)] +impl HasDomain for crate::op::truncf128::Routine { + const DOMAIN: Domain = Domain::::UNBOUNDED; +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 092f5f1d24d75..2a740ed477eb1 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -141,6 +141,7 @@ libm_macros::for_each_function! { lgamma_r, lgammaf_r, modf, modff, nextafter, nextafterf, pow,powf, remquo, remquof, scalbn, scalbnf, sincos, sincosf, yn, ynf, copysignf16, copysignf128, fabsf16, fabsf128, + truncf16, truncf128, ], fn_extra: match MACRO_FN_NAME { // Remap function names that are different between mpfr and libm @@ -202,11 +203,13 @@ impl_no_round! { #[cfg(f16_enabled)] impl_no_round! { fabsf16 => abs_mut; + truncf16 => trunc_mut; } #[cfg(f128_enabled)] impl_no_round! { fabsf128 => abs_mut; + truncf128 => trunc_mut; } /// Some functions are difficult to do in a generic way. Implement them here. diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index b91d7f9f50d9f..a395c6c5d38d7 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -48,7 +48,7 @@ where libm_macros::for_each_function! { callback: musl_rand_tests, // Musl does not support `f16` and `f128` on all platforms. - skip: [copysignf16, copysignf128, fabsf16, fabsf128], + skip: [copysignf16, copysignf128, fabsf16, fabsf128, truncf16, truncf128], attributes: [ #[cfg_attr(x86_no_sse, ignore)] // FIXME(correctness): wrong result on i586 [exp10, exp10f, exp2, exp2f, rint] @@ -146,5 +146,7 @@ libm_macros::for_each_function! { // Not provided by musl fabsf16, fabsf128, + truncf16, + truncf128, ], } diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index f7bd31bb689c0..c8a03068a319f 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -84,7 +84,7 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { emit_types: [CFn, RustFn, RustArgs], extra: (basis, op, inputs), fn_extra: match MACRO_FN_NAME { - copysignf16 | copysignf128 | fabsf16 | fabsf128 => None, + copysignf16 | copysignf128 | fabsf16 | fabsf128 | truncf16 | truncf128 => None, _ => Some(musl_math_sys::MACRO_FN_NAME) } } diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 39b6c97029cb4..86fa0210189cf 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -743,6 +743,7 @@ "sources": [ "src/libm_helper.rs", "src/math/arch/wasm32.rs", + "src/math/generic/trunc.rs", "src/math/trunc.rs" ], "type": "f64" @@ -750,10 +751,25 @@ "truncf": { "sources": [ "src/math/arch/wasm32.rs", + "src/math/generic/trunc.rs", "src/math/truncf.rs" ], "type": "f32" }, + "truncf128": { + "sources": [ + "src/math/generic/trunc.rs", + "src/math/truncf128.rs" + ], + "type": "f128" + }, + "truncf16": { + "sources": [ + "src/math/generic/trunc.rs", + "src/math/truncf16.rs" + ], + "type": "f16" + }, "y0": { "sources": [ "src/libm_helper.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 0a1bbab244d62..8aa901762abb2 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -111,6 +111,8 @@ tgamma tgammaf trunc truncf +truncf128 +truncf16 y0 y0f y1 diff --git a/library/compiler-builtins/libm/src/math/generic/trunc.rs b/library/compiler-builtins/libm/src/math/generic/trunc.rs index 5d0ba6109afa3..ca5f1bdd6276e 100644 --- a/library/compiler-builtins/libm/src/math/generic/trunc.rs +++ b/library/compiler-builtins/libm/src/math/generic/trunc.rs @@ -1,3 +1,6 @@ +/* SPDX-License-Identifier: MIT + * origin: musl src/math/trunc.c */ + use super::super::{Float, Int, IntTy, MinInt}; pub fn trunc(x: F) -> F { diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index c0d038a0c67f1..723be0e1dfd31 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -343,9 +343,11 @@ cfg_if! { if #[cfg(f16_enabled)] { mod copysignf16; mod fabsf16; + mod truncf16; pub use self::copysignf16::copysignf16; pub use self::fabsf16::fabsf16; + pub use self::truncf16::truncf16; } } @@ -353,9 +355,11 @@ cfg_if! { if #[cfg(f128_enabled)] { mod copysignf128; mod fabsf128; + mod truncf128; pub use self::copysignf128::copysignf128; pub use self::fabsf128::fabsf128; + pub use self::truncf128::truncf128; } } diff --git a/library/compiler-builtins/libm/src/math/truncf128.rs b/library/compiler-builtins/libm/src/math/truncf128.rs new file mode 100644 index 0000000000000..9dccc0d0e9d7f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/truncf128.rs @@ -0,0 +1,7 @@ +/// Rounds the number toward 0 to the closest integral value (f128). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf128(x: f128) -> f128 { + super::generic::trunc(x) +} diff --git a/library/compiler-builtins/libm/src/math/truncf16.rs b/library/compiler-builtins/libm/src/math/truncf16.rs new file mode 100644 index 0000000000000..d7c3d225cf9b8 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/truncf16.rs @@ -0,0 +1,7 @@ +/// 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_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf16(x: f16) -> f16 { + super::generic::trunc(x) +} From 23c9f74b584f93dada7d7556ac9112b51a844fdd Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 10:17:51 +0000 Subject: [PATCH 1553/4206] Disable `util` and `libm-macros` for optimized tests These crates take time building in CI, especially with the release profile having LTO enabled, but there isn't really any reason to test them with different features or in release mode. Disable this to save some CI runtime. --- library/compiler-builtins/libm/ci/run.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 35b84809fa2c7..94ff54cb7256c 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -77,8 +77,14 @@ if [ "${BUILD_ONLY:-}" = "1" ]; then else cmd="cargo test --all --target $target $extra_flags" - # Test once without intrinsics, once with intrinsics enabled + # Test once without intrinsics $cmd + + # 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="$cmd --exclude util --exclude libm-macros" + + # Test once with intrinsics enabled $cmd --features unstable-intrinsics $cmd --features unstable-intrinsics --benches From 23dfe62a9db9ac4470b830a466fbaee8035780c4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 10:29:56 +0000 Subject: [PATCH 1554/4206] Format the MPFR manual implementation list --- .../libm/crates/libm-test/src/mpfloat.rs | 48 ++++++++++++++++--- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 2a740ed477eb1..a4aad81f7092e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -135,13 +135,47 @@ libm_macros::for_each_function! { emit_types: [RustFn], skip: [ // Most of these need a manual implementation - fabs, ceil, copysign, floor, rint, round, trunc, - fabsf, ceilf, copysignf, floorf, rintf, roundf, truncf, - fmod, fmodf, frexp, frexpf, ilogb, ilogbf, jn, jnf, ldexp, ldexpf, - lgamma_r, lgammaf_r, modf, modff, nextafter, nextafterf, pow,powf, - remquo, remquof, scalbn, scalbnf, sincos, sincosf, yn, ynf, - copysignf16, copysignf128, fabsf16, fabsf128, - truncf16, truncf128, + ceil, + ceilf, + copysign, + copysignf, + copysignf128, + copysignf16, + fabs, + fabsf, + fabsf128, + fabsf16,floor, + floorf, + fmod, + fmodf, + frexp, + frexpf, + ilogb, + ilogbf, + jn, + jnf, + ldexp,ldexpf, + lgamma_r, + lgammaf_r, + modf, + modff, + nextafter, + nextafterf, + pow, + powf,remquo, + remquof, + rint, + rintf, + round, + roundf, + scalbn, + scalbnf, + sincos,sincosf, + trunc, + truncf, + truncf128, + truncf16,yn, + ynf, ], fn_extra: match MACRO_FN_NAME { // Remap function names that are different between mpfr and libm From 0f285df71649ca3120ca52b91b6398e6c9b17a10 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 13:49:43 +0000 Subject: [PATCH 1555/4206] Add a generic version of `fdim` --- .../libm/etc/function-definitions.json | 6 ++++-- library/compiler-builtins/libm/src/math/fdim.rs | 12 +----------- library/compiler-builtins/libm/src/math/fdimf.rs | 12 +----------- .../compiler-builtins/libm/src/math/generic/fdim.rs | 13 +++++++++++++ .../compiler-builtins/libm/src/math/generic/mod.rs | 2 ++ 5 files changed, 21 insertions(+), 24 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/fdim.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 86fa0210189cf..1e6d260feea29 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -289,13 +289,15 @@ "fdim": { "sources": [ "src/libm_helper.rs", - "src/math/fdim.rs" + "src/math/fdim.rs", + "src/math/generic/fdim.rs" ], "type": "f64" }, "fdimf": { "sources": [ - "src/math/fdimf.rs" + "src/math/fdimf.rs", + "src/math/generic/fdim.rs" ], "type": "f32" }, diff --git a/library/compiler-builtins/libm/src/math/fdim.rs b/library/compiler-builtins/libm/src/math/fdim.rs index 7c58cb5a9a27f..10ffa2881ddf7 100644 --- a/library/compiler-builtins/libm/src/math/fdim.rs +++ b/library/compiler-builtins/libm/src/math/fdim.rs @@ -1,5 +1,3 @@ -use core::f64; - /// Positive difference (f64) /// /// Determines the positive difference between arguments, returning: @@ -10,13 +8,5 @@ use core::f64; /// A range error may occur. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fdim(x: f64, y: f64) -> f64 { - if x.is_nan() { - x - } else if y.is_nan() { - y - } else if x > y { - x - y - } else { - 0.0 - } + super::generic::fdim(x, y) } diff --git a/library/compiler-builtins/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/src/math/fdimf.rs index 2abd49a64c9f9..367ef517c63be 100644 --- a/library/compiler-builtins/libm/src/math/fdimf.rs +++ b/library/compiler-builtins/libm/src/math/fdimf.rs @@ -1,5 +1,3 @@ -use core::f32; - /// Positive difference (f32) /// /// Determines the positive difference between arguments, returning: @@ -10,13 +8,5 @@ use core::f32; /// A range error may occur. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fdimf(x: f32, y: f32) -> f32 { - if x.is_nan() { - x - } else if y.is_nan() { - y - } else if x > y { - x - y - } else { - 0.0 - } + super::generic::fdim(x, y) } diff --git a/library/compiler-builtins/libm/src/math/generic/fdim.rs b/library/compiler-builtins/libm/src/math/generic/fdim.rs new file mode 100644 index 0000000000000..2e54a41deea72 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fdim.rs @@ -0,0 +1,13 @@ +use super::super::Float; + +pub fn fdim(x: F, y: F) -> F { + if x.is_nan() { + x + } else if y.is_nan() { + y + } else if x > y { + x - y + } else { + F::ZERO + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index e5166ca10eb32..2b068d6c54d34 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -1,7 +1,9 @@ mod copysign; mod fabs; +mod fdim; mod trunc; pub use copysign::copysign; pub use fabs::fabs; +pub use fdim::fdim; pub use trunc::trunc; From 13b5bf3959b93e4aa32c519f999d8e3cb1f95176 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 13:58:40 +0000 Subject: [PATCH 1556/4206] Add `fdimf16` and `fdimf128` Use the generic algorithms to provide implementations for these routines. --- .../compiler-builtins-smoke-test/src/lib.rs | 2 ++ .../libm/crates/libm-macros/src/shared.rs | 4 ++-- .../libm/crates/libm-test/benches/random.rs | 9 ++++++++- .../libm/crates/libm-test/src/domain.rs | 10 ++++++++++ .../libm/crates/libm-test/src/mpfloat.rs | 2 +- .../libm-test/tests/compare_built_musl.rs | 17 ++++++++++++++--- .../crates/libm-test/tests/multiprecision.rs | 2 ++ .../libm/crates/util/src/main.rs | 9 ++++++++- .../libm/etc/function-definitions.json | 14 ++++++++++++++ .../libm/etc/function-list.txt | 2 ++ .../compiler-builtins/libm/src/libm_helper.rs | 2 ++ .../compiler-builtins/libm/src/math/fdimf128.rs | 12 ++++++++++++ .../compiler-builtins/libm/src/math/fdimf16.rs | 12 ++++++++++++ library/compiler-builtins/libm/src/math/mod.rs | 4 ++++ 14 files changed, 93 insertions(+), 8 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fdimf128.rs create mode 100644 library/compiler-builtins/libm/src/math/fdimf16.rs diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index 3416a2229598d..b9521eb071528 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -93,6 +93,8 @@ no_mangle! { fabsf16(x: f16) -> f16; fdim(x: f64, y: f64) -> f64; fdimf(x: f32, y: f32) -> f32; + fdimf128(x: f128, y: f128) -> f128; + fdimf16(x: f16, y: f16) -> f16; floor(x: f64) -> f64; floorf(x: f32) -> f32; fma(x: f64, y: f64, z: f64) -> f64; diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index 24fccd6f2489d..60838196236f5 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -47,7 +47,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16] }, None, - &["copysignf16"], + &["copysignf16", "fdimf16"], ), ( // `(f32, f32) -> f32` @@ -90,7 +90,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F128, Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128] }, None, - &["copysignf128"], + &["copysignf128", "fdimf128"], ), ( // `(f32, f32, f32) -> f32` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 8c6afff25981d..e790022779f51 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -117,7 +117,14 @@ libm_macros::for_each_function! { exp10 | exp10f | exp2 | exp2f => (true, Some(musl_math_sys::MACRO_FN_NAME)), // Musl does not provide `f16` and `f128` functions - copysignf16 | copysignf128 | fabsf16 | fabsf128 | truncf16 | truncf128 => (false, None), + copysignf128 + | copysignf16 + | fabsf128 + | fabsf16 + | fdimf128 + | fdimf16 + | truncf128 + | truncf16 => (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/crates/libm-test/src/domain.rs b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs index adafb9faa3513..68b91bf02e8ce 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs @@ -200,6 +200,16 @@ impl HasDomain for crate::op::fabsf128::Routine { const DOMAIN: Domain = Domain::::UNBOUNDED; } +#[cfg(f16_enabled)] +impl HasDomain for crate::op::fdimf16::Routine { + const DOMAIN: Domain = Domain::::UNBOUNDED; +} + +#[cfg(f128_enabled)] +impl HasDomain for crate::op::fdimf128::Routine { + const DOMAIN: Domain = Domain::::UNBOUNDED; +} + #[cfg(f16_enabled)] impl HasDomain for crate::op::truncf16::Routine { const DOMAIN: Domain = Domain::::UNBOUNDED; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index a4aad81f7092e..9d95356d39b34 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -181,7 +181,7 @@ libm_macros::for_each_function! { // Remap function names that are different between mpfr and libm expm1 | expm1f => exp_m1, fabs | fabsf => abs, - fdim | fdimf => positive_diff, + fdim | fdimf | fdimf16 | fdimf128 => positive_diff, fma | fmaf => mul_add, fmax | fmaxf => max, fmin | fminf => min, diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index a395c6c5d38d7..836c425a5896e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -48,7 +48,16 @@ where libm_macros::for_each_function! { callback: musl_rand_tests, // Musl does not support `f16` and `f128` on all platforms. - skip: [copysignf16, copysignf128, fabsf16, fabsf128, truncf16, truncf128], + skip: [ + copysignf128, + copysignf16, + fabsf128, + fabsf16, + fdimf128, + fdimf16, + truncf128, + truncf16, + ], attributes: [ #[cfg_attr(x86_no_sse, ignore)] // FIXME(correctness): wrong result on i586 [exp10, exp10f, exp2, exp2f, rint] @@ -144,9 +153,11 @@ libm_macros::for_each_function! { ynf, // Not provided by musl - fabsf16, fabsf128, - truncf16, + fabsf16, + fdimf128, + fdimf16, truncf128, + truncf16, ], } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 2d8856e166e4c..123abfdaf8b11 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -120,6 +120,8 @@ libm_macros::for_each_function! { copysignf128, fdim, fdimf, + fdimf16, + fdimf128, fma, fmaf, fmax, diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index c8a03068a319f..b979c60ad3c02 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -84,7 +84,14 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { emit_types: [CFn, RustFn, RustArgs], extra: (basis, op, inputs), fn_extra: match MACRO_FN_NAME { - copysignf16 | copysignf128 | fabsf16 | fabsf128 | truncf16 | truncf128 => None, + copysignf128 + | copysignf16 + | fabsf128 + | fabsf16 + | fdimf128 + | fdimf16 + | truncf128 + | truncf16 => None, _ => Some(musl_math_sys::MACRO_FN_NAME) } } diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 1e6d260feea29..dbaac931c7697 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -301,6 +301,20 @@ ], "type": "f32" }, + "fdimf128": { + "sources": [ + "src/math/fdimf128.rs", + "src/math/generic/fdim.rs" + ], + "type": "f128" + }, + "fdimf16": { + "sources": [ + "src/math/fdimf16.rs", + "src/math/generic/fdim.rs" + ], + "type": "f16" + }, "floor": { "sources": [ "src/libm_helper.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 8aa901762abb2..7f96a436227e9 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -43,6 +43,8 @@ fabsf128 fabsf16 fdim fdimf +fdimf128 +fdimf16 floor floorf fma diff --git a/library/compiler-builtins/libm/src/libm_helper.rs b/library/compiler-builtins/libm/src/libm_helper.rs index f087267e46c7e..73bae456761bf 100644 --- a/library/compiler-builtins/libm/src/libm_helper.rs +++ b/library/compiler-builtins/libm/src/libm_helper.rs @@ -176,6 +176,7 @@ libm_helper! { funcs: { (fn copysign(x: f16, y: f16) -> (f16); => copysignf16); (fn fabs(x: f16) -> (f16); => fabsf16); + (fn fdim(x: f16, y: f16) -> (f16); => fdimf16); } } @@ -185,5 +186,6 @@ libm_helper! { funcs: { (fn copysign(x: f128, y: f128) -> (f128); => copysignf128); (fn fabs(x: f128) -> (f128); => fabsf128); + (fn fdim(x: f128, y: f128) -> (f128); => fdimf128); } } diff --git a/library/compiler-builtins/libm/src/math/fdimf128.rs b/library/compiler-builtins/libm/src/math/fdimf128.rs new file mode 100644 index 0000000000000..6f3d1d0ff1d54 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fdimf128.rs @@ -0,0 +1,12 @@ +/// Positive difference (f128) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf128(x: f128, y: f128) -> f128 { + super::generic::fdim(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/fdimf16.rs b/library/compiler-builtins/libm/src/math/fdimf16.rs new file mode 100644 index 0000000000000..37bd688581797 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fdimf16.rs @@ -0,0 +1,12 @@ +/// Positive difference (f16) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf16(x: f16, y: f16) -> f16 { + super::generic::fdim(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 723be0e1dfd31..03adb6be19341 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -343,10 +343,12 @@ cfg_if! { if #[cfg(f16_enabled)] { mod copysignf16; mod fabsf16; + mod fdimf16; mod truncf16; pub use self::copysignf16::copysignf16; pub use self::fabsf16::fabsf16; + pub use self::fdimf16::fdimf16; pub use self::truncf16::truncf16; } } @@ -355,10 +357,12 @@ cfg_if! { if #[cfg(f128_enabled)] { mod copysignf128; mod fabsf128; + mod fdimf128; mod truncf128; pub use self::copysignf128::copysignf128; pub use self::fabsf128::fabsf128; + pub use self::fdimf128::fdimf128; pub use self::truncf128::truncf128; } } From fd7a45f7f6c68f7d2c3ba6851c313c4163a4782b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 22:57:38 +0000 Subject: [PATCH 1557/4206] Don't set `codegen-units=1` by default in CI We can set this only for the release profile, there isn't any reason to have it set for debug tests. --- library/compiler-builtins/libm/Cargo.toml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 820c013478f43..f84f3eac6a4d0 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -61,14 +61,15 @@ exclude = [ [dev-dependencies] no-panic = "0.1.30" - -# This is needed for no-panic to correctly detect the lack of panics [profile.release] +# Options for no-panic to correctly detect the lack of panics +codegen-units = 1 lto = "fat" # Release mode with debug assertions [profile.release-checked] -inherits = "release" +codegen-units = 1 debug-assertions = true +inherits = "release" lto = "fat" overflow-checks = true From bcd9d8a5c33d24b2f817a3e9cf5d5a16606f83cd Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 23:00:39 +0000 Subject: [PATCH 1558/4206] Reduce indentation in `run.sh` using early return --- library/compiler-builtins/libm/ci/run.sh | 47 ++++++++++++------------ 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 94ff54cb7256c..008f32d5b8c87 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -3,8 +3,6 @@ set -eux export RUST_BACKTRACE="${RUST_BACKTRACE:-full}" -# Needed for no-panic to correct detect a lack of panics -export RUSTFLAGS="${RUSTFLAGS:-} -Ccodegen-units=1" target="${1:-}" @@ -69,33 +67,36 @@ esac cargo check -p libm --no-default-features if [ "${BUILD_ONLY:-}" = "1" ]; then + # If we are on targets that can't run tests, verify that we can build. cmd="cargo build --target $target --package libm" $cmd $cmd --features unstable-intrinsics echo "can't run tests on $target; skipping" -else - cmd="cargo test --all --target $target $extra_flags" + exit +fi - # Test once without intrinsics - $cmd +# Otherwise, run the test suite. - # 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="$cmd --exclude util --exclude libm-macros" +cmd="cargo test --all --target $target $extra_flags" - # Test once with intrinsics enabled - $cmd --features unstable-intrinsics - $cmd --features unstable-intrinsics --benches - - # Test the same in release mode, which also increases coverage. Also ensure - # the soft float routines are checked. - $cmd --profile release-checked - $cmd --profile release-checked --features force-soft-floats - $cmd --profile release-checked --features unstable-intrinsics - $cmd --profile release-checked --features unstable-intrinsics --benches - - # Ensure that the routines do not panic. - ENSURE_NO_PANIC=1 cargo build -p libm --target "$target" --no-default-features --release -fi +# Test once without intrinsics +$cmd + +# 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="$cmd --exclude util --exclude libm-macros" + +# Test once with intrinsics enabled +$cmd --features unstable-intrinsics +$cmd --features unstable-intrinsics --benches + +# Test the same in release mode, which also increases coverage. Also ensure +# the soft float routines are checked. +$cmd --profile release-checked +$cmd --profile release-checked --features force-soft-floats +$cmd --profile release-checked --features unstable-intrinsics +$cmd --profile release-checked --features unstable-intrinsics --benches +# Ensure that the routines do not panic. +ENSURE_NO_PANIC=1 cargo build -p libm --target "$target" --no-default-features --release From bfbe919adfae9ce1b0dc17260db2dba097c3c37c Mon Sep 17 00:00:00 2001 From: quaternic <57393910+quaternic@users.noreply.github.com> Date: Tue, 14 Jan 2025 03:55:26 +0200 Subject: [PATCH 1559/4206] Simplify and optimize `fdim` (#442) The cases with NaN arguments can be handled by the same x - y expression, and this generates much better code: https://godbolt.org/z/f3rnT8jx4. --- .../compiler-builtins/libm/src/math/generic/fdim.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/generic/fdim.rs b/library/compiler-builtins/libm/src/math/generic/fdim.rs index 2e54a41deea72..bf971cd7d18c8 100644 --- a/library/compiler-builtins/libm/src/math/generic/fdim.rs +++ b/library/compiler-builtins/libm/src/math/generic/fdim.rs @@ -1,13 +1,5 @@ use super::super::Float; pub fn fdim(x: F, y: F) -> F { - if x.is_nan() { - x - } else if y.is_nan() { - y - } else if x > y { - x - y - } else { - F::ZERO - } + if x <= y { F::ZERO } else { x - y } } From 26df5d6689635a1f78573c66baa802a0abc6ec8d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 23:40:42 +0000 Subject: [PATCH 1560/4206] Use cargo-nextest for running tests in CI The test suite for this repo has quite a lot of tests, and it is difficult to tell which contribute the most to the long CI runtime. libtest does have an unstable flag to report test times, but that is inconvenient to use because it needs to be passed only to libtest binaries. Switch to cargo-nextest [1] which provides time reporting and, overall, a better test UI. It may also improve test runtime, though this seems unlikely since we have larger test binaries with many small tests (nextest benefits the most when there are larger binaries that can be run in parallel). For anyone running locally without, `run.sh` should still fall back to `cargo test` if `cargo-nextest` is not available. This diff includes some cleanup and consistency changes to other CI-related files. [1]: https://nexte.st --- .../libm/.github/workflows/main.yml | 2 + .../libm/.github/workflows/publish.yml | 2 +- .../libm/ci/download-musl.sh | 2 +- .../compiler-builtins/libm/ci/run-docker.sh | 8 ++- library/compiler-builtins/libm/ci/run.sh | 58 +++++++++++++------ 5 files changed, 48 insertions(+), 24 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yml index 35b307f77116c..30976d4726270 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yml +++ b/library/compiler-builtins/libm/.github/workflows/main.yml @@ -6,6 +6,7 @@ on: pull_request: env: + CARGO_TERM_COLOR: always CARGO_TERM_VERBOSE: true RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings @@ -88,6 +89,7 @@ jobs: rustup default "$channel" rustup target add "${{ matrix.target }}" rustup component add clippy llvm-tools-preview + - uses: taiki-e/install-action@nextest - uses: Swatinem/rust-cache@v2 with: key: ${{ matrix.target }} diff --git a/library/compiler-builtins/libm/.github/workflows/publish.yml b/library/compiler-builtins/libm/.github/workflows/publish.yml index e715c61871fdd..15904079d2772 100644 --- a/library/compiler-builtins/libm/.github/workflows/publish.yml +++ b/library/compiler-builtins/libm/.github/workflows/publish.yml @@ -12,7 +12,7 @@ on: jobs: release-plz: name: Release-plz - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/library/compiler-builtins/libm/ci/download-musl.sh b/library/compiler-builtins/libm/ci/download-musl.sh index d0d8b310e876d..039e961575bde 100755 --- a/library/compiler-builtins/libm/ci/download-musl.sh +++ b/library/compiler-builtins/libm/ci/download-musl.sh @@ -7,7 +7,7 @@ fname=musl-1.2.5.tar.gz sha=a9a118bbe84d8764da0ea0d28b3ab3fae8477fc7e4085d90102b8596fc7c75e4 mkdir musl -curl "https://musl.libc.org/releases/$fname" -O +curl -L "https://musl.libc.org/releases/$fname" -O case "$(uname -s)" in MINGW*) diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/libm/ci/run-docker.sh index d9f29656d7132..6626e72268578 100755 --- a/library/compiler-builtins/libm/ci/run-docker.sh +++ b/library/compiler-builtins/libm/ci/run-docker.sh @@ -24,12 +24,14 @@ run() { # will be owned by root mkdir -p target - docker build -t "$target" "ci/docker/$target" + set_env="HOME=/tmp PATH=\$PATH:/rust/bin:/cargo/bin" + docker build -t "libm-$target" "ci/docker/$target" docker run \ --rm \ --user "$(id -u):$(id -g)" \ -e CI \ -e RUSTFLAGS \ + -e CARGO_TERM_COLOR \ -e CARGO_HOME=/cargo \ -e CARGO_TARGET_DIR=/target \ -e "EMULATED=$emulated" \ @@ -39,8 +41,8 @@ run() { -v "$(rustc --print sysroot):/rust:ro" \ --init \ -w /checkout \ - "$target" \ - sh -c "HOME=/tmp PATH=\$PATH:/rust/bin exec ci/run.sh $target" + "libm-$target" \ + sh -c "$set_env exec ci/run.sh $target" } if [ -z "$1" ]; then diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 008f32d5b8c87..08ffaa81c6ebd 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -3,8 +3,10 @@ set -eux export RUST_BACKTRACE="${RUST_BACKTRACE:-full}" +export NEXTEST_STATUS_LEVEL=all target="${1:-}" +flags="" if [ -z "$target" ]; then host_target=$(rustc -vV | awk '/^host/ { print $2 }') @@ -13,22 +15,22 @@ if [ -z "$target" ]; then fi # We enumerate features manually. -extra_flags="--no-default-features" +flags="$flags --no-default-features" # Enable arch-specific routines when available. -extra_flags="$extra_flags --features arch" +flags="$flags --features arch" # Always enable `unstable-float` since it expands available API but does not # change any implementations. -extra_flags="$extra_flags --features unstable-float" +flags="$flags --features unstable-float" # 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 # Can't build at all on MSVC, WASM, or thumb - *windows-msvc*) extra_flags="$extra_flags --exclude musl-math-sys" ;; - *wasm*) extra_flags="$extra_flags --exclude musl-math-sys" ;; - *thumb*) extra_flags="$extra_flags --exclude musl-math-sys" ;; + *windows-msvc*) flags="$flags --exclude musl-math-sys" ;; + *wasm*) flags="$flags --exclude musl-math-sys" ;; + *thumb*) flags="$flags --exclude musl-math-sys" ;; # We can build musl on MinGW but running tests gets a stack overflow *windows-gnu*) ;; @@ -38,7 +40,7 @@ case "$target" in *powerpc64le*) ;; # Everything else gets musl enabled - *) extra_flags="$extra_flags --features libm-test/build-musl" ;; + *) flags="$flags --features libm-test/build-musl" ;; esac # Configure which targets test against MPFR @@ -50,17 +52,17 @@ case "$target" in # Targets that aren't cross compiled work fine # FIXME(ci): we should be able to enable aarch64 Linux here once GHA # support rolls out. - x86_64*) extra_flags="$extra_flags --features libm-test/build-mpfr" ;; - i686*) extra_flags="$extra_flags --features libm-test/build-mpfr" ;; - i586*) extra_flags="$extra_flags --features libm-test/build-mpfr --features gmp-mpfr-sys/force-cross" ;; + x86_64*) flags="$flags --features libm-test/build-mpfr" ;; + i686*) flags="$flags --features libm-test/build-mpfr" ;; + i586*) flags="$flags --features libm-test/build-mpfr --features gmp-mpfr-sys/force-cross" ;; # Apple aarch64 is native - aarch64*apple*) extra_flags="$extra_flags --features libm-test/build-mpfr" ;; + aarch64*apple*) flags="$flags --features libm-test/build-mpfr" ;; esac # FIXME: `STATUS_DLL_NOT_FOUND` testing macros on CI. # case "$target" in - *windows-gnu) extra_flags="$extra_flags --exclude libm-macros" ;; + *windows-gnu) flags="$flags --exclude libm-macros" ;; esac # Make sure we can build with overriding features. @@ -76,13 +78,31 @@ if [ "${BUILD_ONLY:-}" = "1" ]; then exit fi -# Otherwise, run the test suite. - -cmd="cargo test --all --target $target $extra_flags" +flags="$flags --all --target $target" +cmd="cargo test $flags" +profile="--profile" + +# If nextest is available, use that +command -v cargo-nextest && nextest=1 || nextest=0 +if [ "$nextest" = "1" ]; then + # Workaround for https://github.com/nextest-rs/nextest/issues/2066 + if [ -f /.dockerenv ]; then + cfg_file="/tmp/nextest-config.toml" + echo "[store]" >> "$cfg_file" + echo "dir = \"$CARGO_TARGET_DIR/nextest\"" >> "$cfg_file" + cfg_flag="--config-file $cfg_file" + fi + + cmd="cargo nextest run ${cfg_flag:-} $flags" + profile="--cargo-profile" +fi # Test once without intrinsics $cmd +# Run doctests if they were excluded by nextest +[ "$nextest" = "1" ] && cargo test --doc $flags + # 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="$cmd --exclude util --exclude libm-macros" @@ -93,10 +113,10 @@ $cmd --features unstable-intrinsics --benches # Test the same in release mode, which also increases coverage. Also ensure # the soft float routines are checked. -$cmd --profile release-checked -$cmd --profile release-checked --features force-soft-floats -$cmd --profile release-checked --features unstable-intrinsics -$cmd --profile release-checked --features unstable-intrinsics --benches +$cmd "$profile" release-checked +$cmd "$profile" release-checked --features force-soft-floats +$cmd "$profile" release-checked --features unstable-intrinsics +$cmd "$profile" release-checked --features unstable-intrinsics --benches # Ensure that the routines do not panic. ENSURE_NO_PANIC=1 cargo build -p libm --target "$target" --no-default-features --release From 5e65179a3912f3b293fd39b05bf8903428a86346 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 14 Jan 2025 03:24:14 +0000 Subject: [PATCH 1561/4206] Change `.yml` files to the canonical extension `.yaml` --- .../libm/.github/workflows/{main.yml => main.yaml} | 0 .../libm/.github/workflows/{publish.yml => publish.yaml} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename library/compiler-builtins/libm/.github/workflows/{main.yml => main.yaml} (100%) rename library/compiler-builtins/libm/.github/workflows/{publish.yml => publish.yaml} (100%) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yml b/library/compiler-builtins/libm/.github/workflows/main.yaml similarity index 100% rename from library/compiler-builtins/libm/.github/workflows/main.yml rename to library/compiler-builtins/libm/.github/workflows/main.yaml diff --git a/library/compiler-builtins/libm/.github/workflows/publish.yml b/library/compiler-builtins/libm/.github/workflows/publish.yaml similarity index 100% rename from library/compiler-builtins/libm/.github/workflows/publish.yml rename to library/compiler-builtins/libm/.github/workflows/publish.yaml From f63ef37218c7def3efeb7a434fcfd0a2b87dcaec Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 14 Jan 2025 07:46:20 +0000 Subject: [PATCH 1562/4206] Slightly restructure `ci/calculate-exhaustive-matrix.py` Change this script into a generic CI utility that we will be able to expand in the future. --- .../libm/.github/workflows/main.yaml | 3 +- ...culate-exhaustive-matrix.py => ci-util.py} | 30 +++++++++++++++---- 2 files changed, 26 insertions(+), 7 deletions(-) rename library/compiler-builtins/libm/ci/{calculate-exhaustive-matrix.py => ci-util.py} (87%) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index 30976d4726270..40b67c4c251a9 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -7,7 +7,6 @@ on: env: CARGO_TERM_COLOR: always - CARGO_TERM_VERBOSE: true RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings RUST_BACKTRACE: full @@ -202,7 +201,7 @@ jobs: - name: Fetch pull request ref run: git fetch origin "$GITHUB_REF:$GITHUB_REF" if: github.event_name == 'pull_request' - - run: python3 ci/calculate-exhaustive-matrix.py >> "$GITHUB_OUTPUT" + - run: python3 ci/ci-util.py generate-matrix >> "$GITHUB_OUTPUT" id: script extensive: diff --git a/library/compiler-builtins/libm/ci/calculate-exhaustive-matrix.py b/library/compiler-builtins/libm/ci/ci-util.py similarity index 87% rename from library/compiler-builtins/libm/ci/calculate-exhaustive-matrix.py rename to library/compiler-builtins/libm/ci/ci-util.py index 8b42f9389f93b..733ec26fa33c3 100755 --- a/library/compiler-builtins/libm/ci/calculate-exhaustive-matrix.py +++ b/library/compiler-builtins/libm/ci/ci-util.py @@ -1,18 +1,30 @@ #!/usr/bin/env python3 -"""Calculate which exhaustive tests should be run as part of CI. +"""Utilities for CI. This dynamically prepares a list of routines that had a source file change based on git history. """ +import json import subprocess as sp import sys -import json from dataclasses import dataclass +from inspect import cleandoc from os import getenv from pathlib import Path from typing import TypedDict +USAGE = cleandoc( + """ + usage: + + ./ci/ci-util.py + + SUBCOMMAND: + generate-matrix Calculate a matrix of which functions had source change, + print that as JSON object. + """ +) REPO_ROOT = Path(__file__).parent.parent GIT = ["git", "-C", REPO_ROOT] @@ -139,9 +151,17 @@ def eprint(*args, **kwargs): def main(): - ctx = Context() - output = ctx.make_workflow_output() - print(f"matrix={output}") + match sys.argv[1:]: + case ["generate-matrix"]: + ctx = Context() + output = ctx.make_workflow_output() + print(f"matrix={output}") + case ["--help" | "-h"]: + print(USAGE) + exit() + case _: + eprint(USAGE) + exit(1) if __name__ == "__main__": From b251f74843e654479fcea9b7954d474b05517a56 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 15 Jan 2025 00:54:55 +0000 Subject: [PATCH 1563/4206] Pass --max-fail to nextest so it doesn't fail fast --- library/compiler-builtins/libm/ci/run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 08ffaa81c6ebd..bb749b72ad339 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -93,7 +93,7 @@ if [ "$nextest" = "1" ]; then cfg_flag="--config-file $cfg_file" fi - cmd="cargo nextest run ${cfg_flag:-} $flags" + cmd="cargo nextest run ${cfg_flag:-} --max-fail=10 $flags" profile="--cargo-profile" fi From 45e3b98165090965e3ec5c24ae497444703d33c9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 15 Jan 2025 01:05:38 +0000 Subject: [PATCH 1564/4206] Add an override for a recent failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Failed on i686: ──── STDERR: libm-test::bench/random y1f/crate thread 'main' panicked at crates/libm-test/benches/random.rs:76:65: called `Result::unwrap()` on an `Err` value: ynf Caused by: 0: input: (213, 109.15641) (0x000000d5, 0x42da5015) expected: -3.3049217e38 0xff78a27a actual: -inf 0xff800000 1: mismatched infinities --- .../libm/crates/libm-test/src/precision.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 15913fe6d7599..0b3fe89befd15 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -454,6 +454,13 @@ impl MaybeOverride<(i32, f32)> for SpecialCase { XFAIL } + // `ynf(213, 109.15641) = -inf` with our library, should be finite. + (_, BaseName::Yn) + if input.0 > 200 && !expected.is_infinite() && actual.is_infinite() => + { + XFAIL + } + _ => None, } } From 7a87cdbae5e97ccd4fa24b729ac5cfb9d8daf58b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 15 Dec 2024 09:11:37 +0000 Subject: [PATCH 1565/4206] Use a C-safe return type for `__rust_[ui]128_*` overflowing intrinsics Most of our Rust-specific overflowing intrinsics currently return `(i128, bool)`, which is not guaranteed to have a stable ABI. Switch to returning the overflow via a mutable parameter and only directly returning the integer result. `__rust_i128_mulo` now matches the function signature of `__muloti4`, but they do not share the same ABI on Windows so we cannot easily deduplicate them. --- library/compiler-builtins/src/int/addsub.rs | 24 ++++++++++++------- library/compiler-builtins/src/int/mul.rs | 12 ++++++---- .../testcrate/tests/addsub.rs | 18 +++++++------- .../compiler-builtins/testcrate/tests/mul.rs | 9 +++---- 4 files changed, 39 insertions(+), 24 deletions(-) diff --git a/library/compiler-builtins/src/int/addsub.rs b/library/compiler-builtins/src/int/addsub.rs index e95590d84dcb7..1f84e8eb1e117 100644 --- a/library/compiler-builtins/src/int/addsub.rs +++ b/library/compiler-builtins/src/int/addsub.rs @@ -66,31 +66,39 @@ intrinsics! { AddSub::add(a,b) } - pub extern "C" fn __rust_i128_addo(a: i128, b: i128) -> (i128, bool) { - a.addo(b) + pub extern "C" fn __rust_i128_addo(a: i128, b: i128, oflow: &mut i32) -> i128 { + let (add, o) = a.addo(b); + *oflow = o.into(); + add } pub extern "C" fn __rust_u128_add(a: u128, b: u128) -> u128 { AddSub::add(a,b) } - pub extern "C" fn __rust_u128_addo(a: u128, b: u128) -> (u128, bool) { - a.addo(b) + pub extern "C" fn __rust_u128_addo(a: u128, b: u128, oflow: &mut i32) -> u128 { + let (add, o) = a.addo(b); + *oflow = o.into(); + add } pub extern "C" fn __rust_i128_sub(a: i128, b: i128) -> i128 { AddSub::sub(a,b) } - pub extern "C" fn __rust_i128_subo(a: i128, b: i128) -> (i128, bool) { - a.subo(b) + pub extern "C" fn __rust_i128_subo(a: i128, b: i128, oflow: &mut i32) -> i128 { + let (sub, o) = a.subo(b); + *oflow = o.into(); + sub } pub extern "C" fn __rust_u128_sub(a: u128, b: u128) -> u128 { AddSub::sub(a,b) } - pub extern "C" fn __rust_u128_subo(a: u128, b: u128) -> (u128, bool) { - a.subo(b) + pub extern "C" fn __rust_u128_subo(a: u128, b: u128, oflow: &mut i32) -> u128 { + let (sub, o) = a.subo(b); + *oflow = o.into(); + sub } } diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/src/int/mul.rs index e0093a725c2a5..040c69342d148 100644 --- a/library/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/src/int/mul.rs @@ -128,11 +128,15 @@ intrinsics! { mul } - pub extern "C" fn __rust_i128_mulo(a: i128, b: i128) -> (i128, bool) { - i128_overflowing_mul(a, b) + pub extern "C" fn __rust_i128_mulo(a: i128, b: i128, oflow: &mut i32) -> i128 { + let (mul, o) = i128_overflowing_mul(a, b); + *oflow = o.into(); + mul } - pub extern "C" fn __rust_u128_mulo(a: u128, b: u128) -> (u128, bool) { - a.mulo(b) + pub extern "C" fn __rust_u128_mulo(a: u128, b: u128, oflow: &mut i32) -> u128 { + let (mul, o) = a.mulo(b); + *oflow = o.into(); + mul } } diff --git a/library/compiler-builtins/testcrate/tests/addsub.rs b/library/compiler-builtins/testcrate/tests/addsub.rs index 284a2bf5a1127..3c0e20f77b18c 100644 --- a/library/compiler-builtins/testcrate/tests/addsub.rs +++ b/library/compiler-builtins/testcrate/tests/addsub.rs @@ -44,20 +44,22 @@ mod int_addsub { use compiler_builtins::int::addsub::{$fn_add, $fn_sub}; fuzz_2(N, |x: $i, y: $i| { - let add0 = x.overflowing_add(y); - let sub0 = x.overflowing_sub(y); - let add1: ($i, bool) = $fn_add(x, y); - let sub1: ($i, bool) = $fn_sub(x, y); - if add0.0 != add1.0 || add0.1 != add1.1 { + let (add0, add_o0)= x.overflowing_add(y); + let (sub0, sub_o0)= x.overflowing_sub(y); + let mut add_o1 = 0; + let mut sub_o1 = 0; + let add1: $i = $fn_add(x, y, &mut add_o1); + let sub1: $i = $fn_sub(x, y, &mut sub_o1); + if add0 != add1 || i32::from(add_o0) != add_o1 { panic!( "{}({}, {}): std: {:?}, builtins: {:?}", - stringify!($fn_add), x, y, add0, add1 + stringify!($fn_add), x, y, (add0, add_o0) , (add1, add_o1) ); } - if sub0.0 != sub1.0 || sub0.1 != sub1.1 { + if sub0 != sub1 || i32::from(sub_o0) != sub_o1 { panic!( "{}({}, {}): std: {:?}, builtins: {:?}", - stringify!($fn_sub), x, y, sub0, sub1 + stringify!($fn_sub), x, y, (sub0, sub_o0) , (sub1, sub_o1) ); } }); diff --git a/library/compiler-builtins/testcrate/tests/mul.rs b/library/compiler-builtins/testcrate/tests/mul.rs index 449d194804aee..2113b177db410 100644 --- a/library/compiler-builtins/testcrate/tests/mul.rs +++ b/library/compiler-builtins/testcrate/tests/mul.rs @@ -73,9 +73,10 @@ mod int_overflowing_mul { use compiler_builtins::int::mul::{__rust_i128_mulo, __rust_u128_mulo}; fuzz_2(N, |x: u128, y: u128| { + let mut o1 = 0; let (mul0, o0) = x.overflowing_mul(y); - let (mul1, o1) = __rust_u128_mulo(x, y); - if mul0 != mul1 || o0 != o1 { + let mul1 = __rust_u128_mulo(x, y, &mut o1); + if mul0 != mul1 || i32::from(o0) != o1 { panic!( "__rust_u128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})", x, y, mul0, o0, mul1, o1 @@ -84,8 +85,8 @@ mod int_overflowing_mul { let x = x as i128; let y = y as i128; let (mul0, o0) = x.overflowing_mul(y); - let (mul1, o1) = __rust_i128_mulo(x, y); - if mul0 != mul1 || o0 != o1 { + let mul1 = __rust_i128_mulo(x, y, &mut o1); + if mul0 != mul1 || i32::from(o0) != o1 { panic!( "__rust_i128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})", x, y, mul0, o0, mul1, o1 From 05d429523de334a1a34666ff32ea1e74ddab66dd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 15 Jan 2025 03:53:29 +0000 Subject: [PATCH 1566/4206] chore: release v0.1.143 --- library/compiler-builtins/CHANGELOG.md | 6 ++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index 305f2790f33cc..3c21dc2d2829b 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.143](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.142...compiler_builtins-v0.1.143) - 2025-01-15 + +### Other + +- Use a C-safe return type for `__rust_[ui]128_*` overflowing intrinsics + ## [0.1.142](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.141...compiler_builtins-v0.1.142) - 2025-01-07 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 943adc4c1f2b1..4d5bbe4a9029f 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.142" +version = "0.1.143" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 095ecabcad55f43dcf4beb8b420ad712e0c5671f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 15 Jan 2025 05:27:14 +0000 Subject: [PATCH 1567/4206] Eliminate the use of `public_test_dep!` Replace `public_test_dep!` by placing optionally public items into new modules, then controlling what is exported with the `public-test-deps` feature. This is nicer for automatic formatting and diagnostics. This is a reland of 2e2a9255 ("Eliminate the use of `public_test_dep!`"), which was reverted in 47e50fd2 ('Revert "Eliminate the use of..."') due to a bug exposed at [1]. This was fixed in [2], so the cleanup should be able to be applied again. [1]: https://github.com/rust-lang/rust/pull/128691 [2]: https://github.com/rust-lang/rust/pull/135278 --- library/compiler-builtins/src/float/mod.rs | 195 +------- library/compiler-builtins/src/float/traits.rs | 189 ++++++++ .../src/int/leading_zeros.rs | 227 +++++----- library/compiler-builtins/src/int/mod.rs | 424 +----------------- .../src/int/specialized_div_rem/delegate.rs | 4 +- .../src/int/trailing_zeros.rs | 69 +-- library/compiler-builtins/src/int/traits.rs | 411 +++++++++++++++++ library/compiler-builtins/src/macros.rs | 16 - 8 files changed, 763 insertions(+), 772 deletions(-) create mode 100644 library/compiler-builtins/src/float/traits.rs create mode 100644 library/compiler-builtins/src/int/traits.rs diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 6ee55950e18e8..41b308626b392 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,7 +1,3 @@ -use core::ops; - -use crate::int::{DInt, Int, MinInt}; - pub mod add; pub mod cmp; pub mod conv; @@ -10,192 +6,11 @@ pub mod extend; pub mod mul; pub mod pow; pub mod sub; +pub(crate) mod traits; pub mod trunc; -/// Wrapper to extract the integer type half of the float's size -pub(crate) type HalfRep = <::Int as DInt>::H; - -public_test_dep! { -/// Trait for some basic operations on floats -#[allow(dead_code)] -pub(crate) 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(not(feature = "public-test-deps"))] +pub(crate) use traits::{Float, HalfRep}; -#[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); +#[cfg(feature = "public-test-deps")] +pub use traits::{Float, HalfRep}; diff --git a/library/compiler-builtins/src/float/traits.rs b/library/compiler-builtins/src/float/traits.rs new file mode 100644 index 0000000000000..8ccaa7bcbd78a --- /dev/null +++ b/library/compiler-builtins/src/float/traits.rs @@ -0,0 +1,189 @@ +use core::ops; + +use crate::int::{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/src/int/leading_zeros.rs b/library/compiler-builtins/src/int/leading_zeros.rs index 1fee9fcf5d8fd..ba735aa74620b 100644 --- a/library/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/src/int/leading_zeros.rs @@ -3,135 +3,138 @@ // adding a zero check at the beginning, but `__clzsi2` has a precondition that `x != 0`. // Compilers will insert the check for zero in cases where it is needed. -use crate::int::{CastInto, Int}; +#[cfg(feature = "public-test-deps")] +pub use implementation::{leading_zeros_default, leading_zeros_riscv}; +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use implementation::{leading_zeros_default, leading_zeros_riscv}; -public_test_dep! { -/// Returns the number of leading binary zeros in `x`. -#[allow(dead_code)] -pub(crate) fn leading_zeros_default>(x: T) -> usize { - // The basic idea is to test if the higher bits of `x` are zero and bisect the number - // of leading zeros. It is possible for all branches of the bisection to use the same - // code path by conditionally shifting the higher parts down to let the next bisection - // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` - // and adding to the number of zeros, it is slightly faster to start with - // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, - // because it simplifies the final bisection step. - let mut x = x; - // the number of potential leading zeros - let mut z = T::BITS as usize; - // a temporary - let mut t: T; +mod implementation { + use crate::int::{CastInto, Int}; - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - t = x >> 32; + /// Returns the number of leading binary zeros in `x`. + #[allow(dead_code)] + pub fn leading_zeros_default>(x: T) -> usize { + // The basic idea is to test if the higher bits of `x` are zero and bisect the number + // of leading zeros. It is possible for all branches of the bisection to use the same + // code path by conditionally shifting the higher parts down to let the next bisection + // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` + // and adding to the number of zeros, it is slightly faster to start with + // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, + // because it simplifies the final bisection step. + let mut x = x; + // the number of potential leading zeros + let mut z = T::BITS as usize; + // a temporary + let mut t: T; + + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + t = x >> 32; + if t != T::ZERO { + z -= 32; + x = t; + } + } + if T::BITS >= 32 { + t = x >> 16; + if t != T::ZERO { + z -= 16; + x = t; + } + } + const { assert!(T::BITS >= 16) }; + t = x >> 8; if t != T::ZERO { - z -= 32; + z -= 8; x = t; } - } - if T::BITS >= 32 { - t = x >> 16; + t = x >> 4; if t != T::ZERO { - z -= 16; + z -= 4; x = t; } - } - const { assert!(T::BITS >= 16) }; - t = x >> 8; - if t != T::ZERO { - z -= 8; - x = t; - } - t = x >> 4; - if t != T::ZERO { - z -= 4; - x = t; - } - t = x >> 2; - if t != T::ZERO { - z -= 2; - x = t; - } - // the last two bisections are combined into one conditional - t = x >> 1; - if t != T::ZERO { - z - 2 - } else { - z - x.cast() - } + t = x >> 2; + if t != T::ZERO { + z -= 2; + x = t; + } + // the last two bisections are combined into one conditional + t = x >> 1; + if t != T::ZERO { + z - 2 + } else { + z - x.cast() + } - // We could potentially save a few cycles by using the LUT trick from - // "https://embeddedgurus.com/state-space/2014/09/-%20%20%20%20//%20fast-deterministic-and-portable-counting-leading-zeros/". - // However, 256 bytes for a LUT is too large for embedded use cases. We could remove - // the last 3 bisections and use this 16 byte LUT for the rest of the work: - //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; - //z -= LUT[x] as usize; - //z - // However, it ends up generating about the same number of instructions. When benchmarked - // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO - // execution effects. Changing to using a LUT and branching is risky for smaller cores. -} -} + // We could potentially save a few cycles by using the LUT trick from + // "https://embeddedgurus.com/state-space/2014/09/+%20%20%20%20%20%20%20%20//%20fast-deterministic-and-portable-counting-leading-zeros/". + // However, 256 bytes for a LUT is too large for embedded use cases. We could remove + // the last 3 bisections and use this 16 byte LUT for the rest of the work: + //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; + //z -= LUT[x] as usize; + //z + // However, it ends up generating about the same number of instructions. When benchmarked + // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO + // execution effects. Changing to using a LUT and branching is risky for smaller cores. + } -// The above method does not compile well on RISC-V (because of the lack of predicated -// instructions), producing code with many branches or using an excessively long -// branchless solution. This method takes advantage of the set-if-less-than instruction on -// RISC-V that allows `(x >= power-of-two) as usize` to be branchless. + // The above method does not compile well on RISC-V (because of the lack of predicated + // instructions), producing code with many branches or using an excessively long + // branchless solution. This method takes advantage of the set-if-less-than instruction on + // RISC-V that allows `(x >= power-of-two) as usize` to be branchless. -public_test_dep! { -/// Returns the number of leading binary zeros in `x`. -#[allow(dead_code)] -pub(crate) fn leading_zeros_riscv>(x: T) -> usize { - let mut x = x; - // the number of potential leading zeros - let mut z = T::BITS; - // a temporary - let mut t: u32; + /// Returns the number of leading binary zeros in `x`. + #[allow(dead_code)] + pub fn leading_zeros_riscv>(x: T) -> usize { + let mut x = x; + // the number of potential leading zeros + let mut z = T::BITS; + // a temporary + let mut t: u32; - // RISC-V does not have a set-if-greater-than-or-equal instruction and - // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is - // still the most optimal method. A conditional set can only be turned into a single - // immediate instruction if `x` is compared with an immediate `imm` (that can fit into - // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the - // right). If we try to save an instruction by using `x < imm` for each bisection, we - // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, - // but the immediate will never fit into 12 bits and never save an instruction. - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise - // `t` is set to 0. - t = ((x >= (T::ONE << 32)) as u32) << 5; - // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the - // next step to process. + // RISC-V does not have a set-if-greater-than-or-equal instruction and + // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is + // still the most optimal method. A conditional set can only be turned into a single + // immediate instruction if `x` is compared with an immediate `imm` (that can fit into + // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the + // right). If we try to save an instruction by using `x < imm` for each bisection, we + // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, + // but the immediate will never fit into 12 bits and never save an instruction. + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise + // `t` is set to 0. + t = ((x >= (T::ONE << 32)) as u32) << 5; + // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the + // next step to process. + x >>= t; + // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential + // leading zeros + z -= t; + } + if T::BITS >= 32 { + t = ((x >= (T::ONE << 16)) as u32) << 4; + x >>= t; + z -= t; + } + const { assert!(T::BITS >= 16) }; + t = ((x >= (T::ONE << 8)) as u32) << 3; x >>= t; - // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential - // leading zeros z -= t; - } - if T::BITS >= 32 { - t = ((x >= (T::ONE << 16)) as u32) << 4; + t = ((x >= (T::ONE << 4)) as u32) << 2; + x >>= t; + z -= t; + t = ((x >= (T::ONE << 2)) as u32) << 1; x >>= t; z -= t; + t = (x >= (T::ONE << 1)) as u32; + x >>= t; + z -= t; + // All bits except the LSB are guaranteed to be zero for this final bisection step. + // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. + z as usize - x.cast() } - const { assert!(T::BITS >= 16) }; - t = ((x >= (T::ONE << 8)) as u32) << 3; - x >>= t; - z -= t; - t = ((x >= (T::ONE << 4)) as u32) << 2; - x >>= t; - z -= t; - t = ((x >= (T::ONE << 2)) as u32) << 1; - x >>= t; - z -= t; - t = (x >= (T::ONE << 1)) as u32; - x >>= t; - z -= t; - // All bits except the LSB are guaranteed to be zero for this final bisection step. - // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. - z as usize - x.cast() -} } intrinsics! { diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index c0d5a6715e3ae..1f1be711bbda2 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -1,5 +1,3 @@ -use core::ops; - mod specialized_div_rem; pub mod addsub; @@ -10,425 +8,13 @@ pub mod mul; pub mod sdiv; pub mod shift; pub mod trailing_zeros; +mod traits; pub mod udiv; pub use big::{i256, u256}; -public_test_dep! { -/// Minimal integer implementations needed on all integer types, including wide integers. -#[allow(dead_code)] -pub(crate) trait MinInt: Copy - + core::fmt::Debug - + ops::BitOr - + ops::Not - + ops::Shl -{ - - /// Type with the same width but other signedness - type OtherSign: MinInt; - /// Unsigned version of Self - type UnsignedInt: MinInt; - - /// If `Self` is a signed integer - const SIGNED: bool; - - /// The bitwidth of the int type - const BITS: u32; - - const ZERO: Self; - const ONE: Self; - const MIN: Self; - const MAX: Self; -} -} - -public_test_dep! { -/// Trait for some basic operations on integers -#[allow(dead_code)] -pub(crate) trait Int: MinInt - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::SubAssign - + ops::BitAndAssign - + ops::BitOrAssign - + ops::BitXorAssign - + ops::ShlAssign - + ops::ShrAssign - + ops::Add - + ops::Sub - + ops::Mul - + ops::Div - + ops::Shr - + ops::BitXor - + ops::BitAnd -{ - /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing - /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, - /// 112,119,120,125,126,127]. - const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); - - /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. - const FUZZ_NUM: usize = { - let log2 = (::BITS - 1).count_ones() as usize; - if log2 == 3 { - // case for u8 - 6 - } else { - // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate - // boundaries. - 8 + (4 * (log2 - 4)) - } - }; - - fn unsigned(self) -> Self::UnsignedInt; - fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; - fn unsigned_abs(self) -> Self::UnsignedInt; - - fn from_bool(b: bool) -> Self; - - /// Prevents the need for excessive conversions between signed and unsigned - fn logical_shr(self, other: u32) -> Self; - - /// Absolute difference between two integers. - fn abs_diff(self, other: Self) -> Self::UnsignedInt; - - // copied from primitive integers, but put in a trait - fn is_zero(self) -> bool; - fn wrapping_neg(self) -> Self; - fn wrapping_add(self, other: Self) -> Self; - fn wrapping_mul(self, other: Self) -> Self; - fn wrapping_sub(self, other: Self) -> Self; - fn wrapping_shl(self, other: u32) -> Self; - fn wrapping_shr(self, other: u32) -> Self; - fn rotate_left(self, other: u32) -> Self; - fn overflowing_add(self, other: Self) -> (Self, bool); - fn leading_zeros(self) -> u32; - fn ilog2(self) -> u32; -} -} - -pub(crate) const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { - let mut v = [0u8; 20]; - v[0] = 0; - v[1] = 1; - v[2] = 2; // important for parity and the iX::MIN case when reversed - let mut i = 3; - - // No need for any more until the byte boundary, because there should be no algorithms - // that are sensitive to anything not next to byte boundaries after 2. We also scale - // in powers of two, which is important to prevent u128 corner tests from getting too - // big. - let mut l = 8; - loop { - if l >= ((bits / 2) as u8) { - break; - } - // get both sides of the byte boundary - v[i] = l - 1; - i += 1; - v[i] = l; - i += 1; - l *= 2; - } - - if bits != 8 { - // add the lower side of the middle boundary - v[i] = ((bits / 2) - 1) as u8; - i += 1; - } - - // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS - // boundary because of algorithms that split the high part up. We reverse the scaling - // as we go to Self::BITS. - let mid = i; - let mut j = 1; - loop { - v[i] = (bits as u8) - (v[mid - j]) - 1; - if j == mid { - break; - } - i += 1; - j += 1; - } - v -} - -macro_rules! int_impl_common { - ($ty:ty) => { - fn from_bool(b: bool) -> Self { - b as $ty - } - - fn logical_shr(self, other: u32) -> Self { - Self::from_unsigned(self.unsigned().wrapping_shr(other)) - } - - fn is_zero(self) -> bool { - self == Self::ZERO - } - - fn wrapping_neg(self) -> Self { - ::wrapping_neg(self) - } - - fn wrapping_add(self, other: Self) -> Self { - ::wrapping_add(self, other) - } - - fn wrapping_mul(self, other: Self) -> Self { - ::wrapping_mul(self, other) - } - fn wrapping_sub(self, other: Self) -> Self { - ::wrapping_sub(self, other) - } - - fn wrapping_shl(self, other: u32) -> Self { - ::wrapping_shl(self, other) - } - - fn wrapping_shr(self, other: u32) -> Self { - ::wrapping_shr(self, other) - } - - fn rotate_left(self, other: u32) -> Self { - ::rotate_left(self, other) - } - - fn overflowing_add(self, other: Self) -> (Self, bool) { - ::overflowing_add(self, other) - } - - fn leading_zeros(self) -> u32 { - ::leading_zeros(self) - } - - fn ilog2(self) -> u32 { - ::ilog2(self) - } - }; -} - -macro_rules! int_impl { - ($ity:ty, $uty:ty) => { - impl MinInt for $uty { - type OtherSign = $ity; - type UnsignedInt = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $uty { - fn unsigned(self) -> $uty { - self - } - - // It makes writing macros easier if this is implemented for both signed and unsigned - #[allow(clippy::wrong_self_convention)] - fn from_unsigned(me: $uty) -> Self { - me - } - - fn unsigned_abs(self) -> Self { - self - } - - fn abs_diff(self, other: Self) -> Self { - self.abs_diff(other) - } - - int_impl_common!($uty); - } - - impl MinInt for $ity { - type OtherSign = $uty; - type UnsignedInt = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $ity { - fn unsigned(self) -> $uty { - self as $uty - } - - fn from_unsigned(me: $uty) -> Self { - me as $ity - } - - fn unsigned_abs(self) -> Self::UnsignedInt { - self.unsigned_abs() - } - - fn abs_diff(self, other: Self) -> $uty { - self.abs_diff(other) - } - - int_impl_common!($ity); - } - }; -} - -int_impl!(isize, usize); -int_impl!(i8, u8); -int_impl!(i16, u16); -int_impl!(i32, u32); -int_impl!(i64, u64); -int_impl!(i128, u128); - -public_test_dep! { -/// 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(crate) 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() - } -} -} - -public_test_dep! { -/// 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(crate) 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 -); - -public_test_dep! { -/// Trait to express (possibly lossy) casting of integers -pub(crate) trait CastInto: Copy { - fn cast(self) -> T; -} - -pub(crate) trait CastFrom:Copy { - fn cast_from(value: T) -> Self; -} -} - -impl + Copy> CastFrom for T { - fn cast_from(value: U) -> Self { - value.cast() - } -} - -macro_rules! cast_into { - ($ty:ty) => { - cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); - }; - ($ty:ty; $($into:ty),*) => {$( - impl CastInto<$into> for $ty { - fn cast(self) -> $into { - self as $into - } - } - )*}; -} +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; -cast_into!(usize); -cast_into!(isize); -cast_into!(u8); -cast_into!(i8); -cast_into!(u16); -cast_into!(i16); -cast_into!(u32); -cast_into!(i32); -cast_into!(u64); -cast_into!(i64); -cast_into!(u128); -cast_into!(i128); +#[cfg(feature = "public-test-deps")] +pub use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; diff --git a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs index 330c6e4f80bb7..f5c6e50239a35 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs @@ -185,7 +185,6 @@ macro_rules! impl_delegate { }; } -public_test_dep! { /// Returns `n / d` and sets `*rem = n % d`. /// /// This specialization exists because: @@ -195,7 +194,7 @@ public_test_dep! { /// delegate algorithm strategy the only reasonably fast way to perform `u128` division. // used on SPARC #[allow(dead_code)] -pub(crate) fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { +pub fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { use super::*; let duo_lo = duo as u64; let duo_hi = (duo >> 64) as u64; @@ -316,4 +315,3 @@ pub(crate) fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { } } } -} diff --git a/library/compiler-builtins/src/int/trailing_zeros.rs b/library/compiler-builtins/src/int/trailing_zeros.rs index cea366b07549f..dbc0cce9facc9 100644 --- a/library/compiler-builtins/src/int/trailing_zeros.rs +++ b/library/compiler-builtins/src/int/trailing_zeros.rs @@ -1,44 +1,49 @@ -use crate::int::{CastInto, Int}; +#[cfg(feature = "public-test-deps")] +pub use implementation::trailing_zeros; +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use implementation::trailing_zeros; -public_test_dep! { -/// Returns number of trailing binary zeros in `x`. -#[allow(dead_code)] -pub(crate) fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { - let mut x = x; - let mut r: u32 = 0; - let mut t: u32; +mod implementation { + use crate::int::{CastInto, Int}; - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 - x >>= r; // remove 32 zero bits - } + /// Returns number of trailing binary zeros in `x`. + #[allow(dead_code)] + pub fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { + let mut x = x; + let mut r: u32 = 0; + let mut t: u32; - if T::BITS >= 32 { - t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 - r += t; - x >>= t; // x = [0 - 0xFFFF] + higher garbage bits - } + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 + x >>= r; // remove 32 zero bits + } - const { assert!(T::BITS >= 16) }; - t = ((CastInto::::cast(x) == 0) as u32) << 3; - x >>= t; // x = [0 - 0xFF] + higher garbage bits - r += t; + if T::BITS >= 32 { + t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 + r += t; + x >>= t; // x = [0 - 0xFFFF] + higher garbage bits + } - let mut x: u8 = x.cast(); + const { assert!(T::BITS >= 16) }; + t = ((CastInto::::cast(x) == 0) as u32) << 3; + x >>= t; // x = [0 - 0xFF] + higher garbage bits + r += t; - t = (((x & 0x0F) == 0) as u32) << 2; - x >>= t; // x = [0 - 0xF] + higher garbage bits - r += t; + let mut x: u8 = x.cast(); - t = (((x & 0x3) == 0) as u32) << 1; - x >>= t; // x = [0 - 0x3] + higher garbage bits - r += t; + t = (((x & 0x0F) == 0) as u32) << 2; + x >>= t; // x = [0 - 0xF] + higher garbage bits + r += t; - x &= 3; + t = (((x & 0x3) == 0) as u32) << 1; + x >>= t; // x = [0 - 0x3] + higher garbage bits + r += t; - r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) -} + x &= 3; + + r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) + } } intrinsics! { diff --git a/library/compiler-builtins/src/int/traits.rs b/library/compiler-builtins/src/int/traits.rs new file mode 100644 index 0000000000000..9b079e2aa59ae --- /dev/null +++ b/library/compiler-builtins/src/int/traits.rs @@ -0,0 +1,411 @@ +use core::ops; + +/// Minimal integer implementations needed on all integer types, including wide integers. +#[allow(dead_code)] +pub trait MinInt: + Copy + + core::fmt::Debug + + ops::BitOr + + ops::Not + + ops::Shl +{ + /// Type with the same width but other signedness + type OtherSign: MinInt; + /// Unsigned version of Self + type UnsignedInt: MinInt; + + /// If `Self` is a signed integer + const SIGNED: bool; + + /// The bitwidth of the int type + const BITS: u32; + + const ZERO: Self; + const ONE: Self; + const MIN: Self; + const MAX: Self; +} + +/// Trait for some basic operations on integers +#[allow(dead_code)] +pub trait Int: + MinInt + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::SubAssign + + ops::BitAndAssign + + ops::BitOrAssign + + ops::BitXorAssign + + ops::ShlAssign + + ops::ShrAssign + + ops::Add + + ops::Sub + + ops::Mul + + ops::Div + + ops::Shr + + ops::BitXor + + ops::BitAnd +{ + /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing + /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, + /// 112,119,120,125,126,127]. + const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); + + /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. + const FUZZ_NUM: usize = { + let log2 = (::BITS - 1).count_ones() as usize; + if log2 == 3 { + // case for u8 + 6 + } else { + // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate + // boundaries. + 8 + (4 * (log2 - 4)) + } + }; + + fn unsigned(self) -> Self::UnsignedInt; + fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; + fn unsigned_abs(self) -> Self::UnsignedInt; + + fn from_bool(b: bool) -> Self; + + /// Prevents the need for excessive conversions between signed and unsigned + fn logical_shr(self, other: u32) -> Self; + + /// Absolute difference between two integers. + fn abs_diff(self, other: Self) -> Self::UnsignedInt; + + // copied from primitive integers, but put in a trait + fn is_zero(self) -> bool; + fn wrapping_neg(self) -> Self; + fn wrapping_add(self, other: Self) -> Self; + fn wrapping_mul(self, other: Self) -> Self; + fn wrapping_sub(self, other: Self) -> Self; + fn wrapping_shl(self, other: u32) -> Self; + fn wrapping_shr(self, other: u32) -> Self; + fn rotate_left(self, other: u32) -> Self; + fn overflowing_add(self, other: Self) -> (Self, bool); + fn leading_zeros(self) -> u32; + fn ilog2(self) -> u32; +} + +pub(crate) const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { + let mut v = [0u8; 20]; + v[0] = 0; + v[1] = 1; + v[2] = 2; // important for parity and the iX::MIN case when reversed + let mut i = 3; + + // No need for any more until the byte boundary, because there should be no algorithms + // that are sensitive to anything not next to byte boundaries after 2. We also scale + // in powers of two, which is important to prevent u128 corner tests from getting too + // big. + let mut l = 8; + loop { + if l >= ((bits / 2) as u8) { + break; + } + // get both sides of the byte boundary + v[i] = l - 1; + i += 1; + v[i] = l; + i += 1; + l *= 2; + } + + if bits != 8 { + // add the lower side of the middle boundary + v[i] = ((bits / 2) - 1) as u8; + i += 1; + } + + // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS + // boundary because of algorithms that split the high part up. We reverse the scaling + // as we go to Self::BITS. + let mid = i; + let mut j = 1; + loop { + v[i] = (bits as u8) - (v[mid - j]) - 1; + if j == mid { + break; + } + i += 1; + j += 1; + } + v +} + +macro_rules! int_impl_common { + ($ty:ty) => { + fn from_bool(b: bool) -> Self { + b as $ty + } + + fn logical_shr(self, other: u32) -> Self { + Self::from_unsigned(self.unsigned().wrapping_shr(other)) + } + + fn is_zero(self) -> bool { + self == Self::ZERO + } + + fn wrapping_neg(self) -> Self { + ::wrapping_neg(self) + } + + fn wrapping_add(self, other: Self) -> Self { + ::wrapping_add(self, other) + } + + fn wrapping_mul(self, other: Self) -> Self { + ::wrapping_mul(self, other) + } + fn wrapping_sub(self, other: Self) -> Self { + ::wrapping_sub(self, other) + } + + fn wrapping_shl(self, other: u32) -> Self { + ::wrapping_shl(self, other) + } + + fn wrapping_shr(self, other: u32) -> Self { + ::wrapping_shr(self, other) + } + + fn rotate_left(self, other: u32) -> Self { + ::rotate_left(self, other) + } + + fn overflowing_add(self, other: Self) -> (Self, bool) { + ::overflowing_add(self, other) + } + + fn leading_zeros(self) -> u32 { + ::leading_zeros(self) + } + + fn ilog2(self) -> u32 { + ::ilog2(self) + } + }; +} + +macro_rules! int_impl { + ($ity:ty, $uty:ty) => { + impl MinInt for $uty { + type OtherSign = $ity; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $uty { + fn unsigned(self) -> $uty { + self + } + + // It makes writing macros easier if this is implemented for both signed and unsigned + #[allow(clippy::wrong_self_convention)] + fn from_unsigned(me: $uty) -> Self { + me + } + + fn unsigned_abs(self) -> Self { + self + } + + fn abs_diff(self, other: Self) -> Self { + self.abs_diff(other) + } + + int_impl_common!($uty); + } + + impl MinInt for $ity { + type OtherSign = $uty; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $ity { + fn unsigned(self) -> $uty { + self as $uty + } + + fn from_unsigned(me: $uty) -> Self { + me as $ity + } + + fn unsigned_abs(self) -> Self::UnsignedInt { + self.unsigned_abs() + } + + fn abs_diff(self, other: Self) -> $uty { + self.abs_diff(other) + } + + int_impl_common!($ity); + } + }; +} + +int_impl!(isize, usize); +int_impl!(i8, u8); +int_impl!(i16, u16); +int_impl!(i32, u32); +int_impl!(i64, u64); +int_impl!(i128, u128); + +/// 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 +); + +/// Trait to express (possibly lossy) casting of integers +pub trait CastInto: Copy { + fn cast(self) -> T; +} + +pub trait CastFrom: Copy { + fn cast_from(value: T) -> Self; +} + +impl + Copy> CastFrom for T { + fn cast_from(value: U) -> Self { + value.cast() + } +} + +macro_rules! cast_into { + ($ty:ty) => { + cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); + }; + ($ty:ty; $($into:ty),*) => {$( + impl CastInto<$into> for $ty { + fn cast(self) -> $into { + self as $into + } + } + )*}; +} + +cast_into!(usize); +cast_into!(isize); +cast_into!(u8); +cast_into!(i8); +cast_into!(u16); +cast_into!(i16); +cast_into!(u32); +cast_into!(i32); +cast_into!(u64); +cast_into!(i64); +cast_into!(u128); +cast_into!(i128); diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index f51e49e987661..91606d42be17c 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -1,21 +1,5 @@ //! Macros shared throughout the compiler-builtins implementation -/// Changes the visibility to `pub` if feature "public-test-deps" is set -#[cfg(not(feature = "public-test-deps"))] -macro_rules! public_test_dep { - ($(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*) => { - $(#[$($meta)*])* pub(crate) $ident $($tokens)* - }; -} - -/// Changes the visibility to `pub` if feature "public-test-deps" is set -#[cfg(feature = "public-test-deps")] -macro_rules! public_test_dep { - {$(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*} => { - $(#[$($meta)*])* pub $ident $($tokens)* - }; -} - /// The "main macro" used for defining intrinsics. /// /// The compiler-builtins library is super platform-specific with tons of crazy From 49595ea04e8f8b658910a64734f2c7362ca44d60 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 15 Jan 2025 21:19:09 +0000 Subject: [PATCH 1568/4206] chore: release v0.1.144 --- library/compiler-builtins/CHANGELOG.md | 6 ++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index 3c21dc2d2829b..a1f95d178700d 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.144](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.143...compiler_builtins-v0.1.144) - 2025-01-15 + +### Other + +- Eliminate the use of `public_test_dep!` + ## [0.1.143](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.142...compiler_builtins-v0.1.143) - 2025-01-15 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 4d5bbe4a9029f..0b0b7c36528a2 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.143" +version = "0.1.144" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 2d857e1c218ced55debba0981c22affeabe396d2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 7 Jan 2025 06:28:04 +0000 Subject: [PATCH 1569/4206] Replace `HasDomain` to enable multi-argument edge case and domain tests This also allows reusing the same generator logic between logspace tests and extensive tests, so comes with a nice bit of cleanup. Changes: * Make the generator part of `CheckCtx` since a `Generator` and `CheckCtx` are almost always passed together. * Rename `domain_logspace` to `spaced` since this no longer only operates within a domain and we may want to handle integer spacing. * Domain is now calculated at runtime rather than using traits, which is much easier to work with. * With the above, domains for multidimensional functions are added. * The extensive test generator code tests has been combined with the domain_logspace generator code. With this, the domain tests have just become a subset of extensive tests. These were renamed to "quickspace" since, technically, the extensive tests are also "domain" or "domain logspace" tests. * Edge case generators now handle functions with multiple inputs. * The test runners can be significantly cleaned up and deduplicated. --- .../libm/crates/libm-test/benches/random.rs | 4 +- .../crates/libm-test/examples/plot_domains.rs | 28 +- .../libm/crates/libm-test/src/domain.rs | 303 ++++++++++-------- .../libm/crates/libm-test/src/gen.rs | 3 +- .../libm-test/src/gen/domain_logspace.rs | 31 -- .../crates/libm-test/src/gen/edge_cases.rs | 185 +++++++++-- .../libm/crates/libm-test/src/gen/random.rs | 26 +- .../src/gen/{extensive.rs => spaced.rs} | 93 +++--- .../libm/crates/libm-test/src/run_cfg.rs | 60 +++- .../libm-test/tests/compare_built_musl.rs | 132 ++------ .../crates/libm-test/tests/multiprecision.rs | 142 ++------ .../crates/libm-test/tests/z_extensive/run.rs | 24 +- 12 files changed, 525 insertions(+), 506 deletions(-) delete mode 100644 library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs rename library/compiler-builtins/libm/crates/libm-test/src/gen/{extensive.rs => spaced.rs} (76%) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index e790022779f51..dcc7c1acac36f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -4,7 +4,7 @@ use std::time::Duration; use criterion::{Criterion, criterion_main}; use libm_test::gen::random; use libm_test::gen::random::RandomInput; -use libm_test::{CheckBasis, CheckCtx, MathOp, TupleCall}; +use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, TupleCall}; /// Benchmark with this many items to get a variety const BENCH_ITER_ITEMS: usize = if cfg!(feature = "short-benchmarks") { 50 } else { 500 }; @@ -52,7 +52,7 @@ where { let name = Op::NAME; - let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl); + let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl, GeneratorKind::Random); let benchvec: Vec<_> = random::get_test_cases::(&ctx).take(BENCH_ITER_ITEMS).collect(); diff --git a/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs b/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs index 62651124535ca..fb7b854df85c1 100644 --- a/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs +++ b/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs @@ -12,9 +12,9 @@ use std::path::Path; use std::process::Command; use std::{env, fs}; -use libm_test::domain::HasDomain; -use libm_test::gen::{domain_logspace, edge_cases}; -use libm_test::{CheckBasis, CheckCtx, MathOp, op}; +use libm_test::gen::spaced::SpacedInput; +use libm_test::gen::{edge_cases, spaced}; +use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, op}; const JL_PLOT: &str = "examples/plot_file.jl"; @@ -52,23 +52,13 @@ fn main() { /// Run multiple generators for a single operator. fn plot_one_operator(out_dir: &Path, config: &mut String) where - Op: MathOp + HasDomain, + Op: MathOp, + Op::RustArgs: SpacedInput, { - let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); - plot_one_generator( - out_dir, - &ctx, - "logspace", - config, - domain_logspace::get_test_cases::(&ctx), - ); - plot_one_generator( - out_dir, - &ctx, - "edge_cases", - config, - edge_cases::get_test_cases::(&ctx), - ); + let mut ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr, GeneratorKind::QuickSpaced); + plot_one_generator(out_dir, &ctx, "logspace", config, spaced::get_test_cases::(&ctx).0); + ctx.gen_kind = GeneratorKind::EdgeCases; + plot_one_generator(out_dir, &ctx, "edge_cases", config, edge_cases::get_test_cases::(&ctx)); } /// Plot the output of a single generator. diff --git a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs index 68b91bf02e8ce..5d650c00a3bd3 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs @@ -1,11 +1,13 @@ //! Traits and operations related to bounds of a function. use std::fmt; -use std::ops::{self, Bound}; +use std::ops::Bound; -use crate::{Float, FloatExt}; +use libm::support::Int; -/// Representation of a function's domain. +use crate::{BaseName, Float, FloatExt, Identifier}; + +/// Representation of a single dimension of a function's domain. #[derive(Clone, Debug)] pub struct Domain { /// Start of the region for which a function is defined (ignoring poles). @@ -39,56 +41,131 @@ impl Domain { } } +/// A value that may be any float type or any integer type. +#[derive(Clone, Debug)] +pub enum EitherPrim { + Float(F), + Int(I), +} + +impl EitherPrim { + pub fn unwrap_float(self) -> F { + match self { + EitherPrim::Float(f) => f, + EitherPrim::Int(_) => panic!("expected float; got {self:?}"), + } + } + + pub fn unwrap_int(self) -> I { + match self { + EitherPrim::Float(_) => panic!("expected int; got {self:?}"), + EitherPrim::Int(i) => i, + } + } +} + +/// Convenience 1-dimensional float domains. impl Domain { /// x ∈ ℝ - pub const UNBOUNDED: Self = + const UNBOUNDED: Self = Self { start: Bound::Unbounded, end: Bound::Unbounded, check_points: None }; /// x ∈ ℝ >= 0 - pub const POSITIVE: Self = + const POSITIVE: Self = Self { start: Bound::Included(F::ZERO), end: Bound::Unbounded, check_points: None }; /// x ∈ ℝ > 0 - pub const STRICTLY_POSITIVE: Self = + const STRICTLY_POSITIVE: Self = Self { start: Bound::Excluded(F::ZERO), end: Bound::Unbounded, check_points: None }; + /// Wrap in the float variant of [`EitherPrim`]. + const fn into_prim_float(self) -> EitherPrim> { + EitherPrim::Float(self) + } +} + +/// Convenience 1-dimensional integer domains. +impl Domain { + /// x ∈ ℝ + const UNBOUNDED_INT: Self = + Self { start: Bound::Unbounded, end: Bound::Unbounded, check_points: None }; + + /// Wrap in the int variant of [`EitherPrim`]. + const fn into_prim_int(self) -> EitherPrim, Self> { + EitherPrim::Int(self) + } +} + +/// Multidimensional domains, represented as an array of 1-D domains. +impl EitherPrim, Domain> { + /// x ∈ ℝ + const UNBOUNDED1: [Self; 1] = + [Domain { start: Bound::Unbounded, end: Bound::Unbounded, check_points: None } + .into_prim_float()]; + + /// {x1, x2} ∈ ℝ + const UNBOUNDED2: [Self; 2] = + [Domain::UNBOUNDED.into_prim_float(), Domain::UNBOUNDED.into_prim_float()]; + + /// {x1, x2, x3} ∈ ℝ + const UNBOUNDED3: [Self; 3] = [ + Domain::UNBOUNDED.into_prim_float(), + Domain::UNBOUNDED.into_prim_float(), + Domain::UNBOUNDED.into_prim_float(), + ]; + + /// {x1, x2} ∈ ℝ, one float and one int + const UNBOUNDED_F_I: [Self; 2] = + [Domain::UNBOUNDED.into_prim_float(), Domain::UNBOUNDED_INT.into_prim_int()]; + + /// x ∈ ℝ >= 0 + const POSITIVE: [Self; 1] = [Domain::POSITIVE.into_prim_float()]; + + /// x ∈ ℝ > 0 + const STRICTLY_POSITIVE: [Self; 1] = [Domain::STRICTLY_POSITIVE.into_prim_float()]; + /// Used for versions of `asin` and `acos`. - pub const INVERSE_TRIG_PERIODIC: Self = Self { + const INVERSE_TRIG_PERIODIC: [Self; 1] = [Domain { start: Bound::Included(F::NEG_ONE), end: Bound::Included(F::ONE), check_points: None, - }; + } + .into_prim_float()]; /// Domain for `acosh` - pub const ACOSH: Self = - Self { start: Bound::Included(F::ONE), end: Bound::Unbounded, check_points: None }; + const ACOSH: [Self; 1] = + [Domain { start: Bound::Included(F::ONE), end: Bound::Unbounded, check_points: None } + .into_prim_float()]; /// Domain for `atanh` - pub const ATANH: Self = Self { + const ATANH: [Self; 1] = [Domain { start: Bound::Excluded(F::NEG_ONE), end: Bound::Excluded(F::ONE), check_points: None, - }; + } + .into_prim_float()]; /// Domain for `sin`, `cos`, and `tan` - pub const TRIG: Self = Self { - // TODO + const TRIG: [Self; 1] = [Domain { + // Trig functions have special behavior at fractions of π. check_points: Some(|| Box::new([-F::PI, -F::FRAC_PI_2, F::FRAC_PI_2, F::PI].into_iter())), - ..Self::UNBOUNDED - }; + ..Domain::UNBOUNDED + } + .into_prim_float()]; /// Domain for `log` in various bases - pub const LOG: Self = Self::STRICTLY_POSITIVE; + const LOG: [Self; 1] = Self::STRICTLY_POSITIVE; /// Domain for `log1p` i.e. `log(1 + x)` - pub const LOG1P: Self = - Self { start: Bound::Excluded(F::NEG_ONE), end: Bound::Unbounded, check_points: None }; + const LOG1P: [Self; 1] = + [Domain { start: Bound::Excluded(F::NEG_ONE), end: Bound::Unbounded, check_points: None } + .into_prim_float()]; /// Domain for `sqrt` - pub const SQRT: Self = Self::POSITIVE; + const SQRT: [Self; 1] = Self::POSITIVE; /// Domain for `gamma` - pub const GAMMA: Self = Self { + const GAMMA: [Self; 1] = [Domain { check_points: Some(|| { // Negative integers are asymptotes Box::new((0..u8::MAX).map(|scale| { @@ -100,122 +177,84 @@ impl Domain { })) }), // Whether or not gamma is defined for negative numbers is implementation dependent - ..Self::UNBOUNDED - }; + ..Domain::UNBOUNDED + } + .into_prim_float()]; /// Domain for `loggamma` - pub const LGAMMA: Self = Self::STRICTLY_POSITIVE; -} + const LGAMMA: [Self; 1] = Self::STRICTLY_POSITIVE; -/// Implement on `op::*` types to indicate how they are bounded. -pub trait HasDomain -where - T: Copy + fmt::Debug + ops::Add + ops::Sub + PartialOrd + 'static, -{ - const DOMAIN: Domain; + /// Domain for `jn` and `yn`. + // FIXME: the domain should provide some sort of "reasonable range" so we don't actually test + // the entire system unbounded. + const BESSEL_N: [Self; 2] = + [Domain::UNBOUNDED_INT.into_prim_int(), Domain::UNBOUNDED.into_prim_float()]; } -/// Implement [`HasDomain`] for both the `f32` and `f64` variants of a function. -macro_rules! impl_has_domain { - ($($fn_name:ident => $domain:expr;)*) => { - paste::paste! { - $( - // Implement for f64 functions - impl HasDomain for $crate::op::$fn_name::Routine { - const DOMAIN: Domain = Domain::::$domain; - } - - // Implement for f32 functions - impl HasDomain for $crate::op::[< $fn_name f >]::Routine { - const DOMAIN: Domain = Domain::::$domain; - } - )* - } +/// Get the domain for a given function. +pub fn get_domain( + id: Identifier, + argnum: usize, +) -> EitherPrim, Domain> { + let x = match id.base_name() { + BaseName::Acos => &EitherPrim::INVERSE_TRIG_PERIODIC[..], + BaseName::Acosh => &EitherPrim::ACOSH[..], + BaseName::Asin => &EitherPrim::INVERSE_TRIG_PERIODIC[..], + BaseName::Asinh => &EitherPrim::UNBOUNDED1[..], + BaseName::Atan => &EitherPrim::UNBOUNDED1[..], + BaseName::Atan2 => &EitherPrim::UNBOUNDED2[..], + BaseName::Cbrt => &EitherPrim::UNBOUNDED1[..], + BaseName::Atanh => &EitherPrim::ATANH[..], + BaseName::Ceil => &EitherPrim::UNBOUNDED1[..], + BaseName::Cosh => &EitherPrim::UNBOUNDED1[..], + BaseName::Copysign => &EitherPrim::UNBOUNDED2[..], + BaseName::Cos => &EitherPrim::TRIG[..], + BaseName::Exp => &EitherPrim::UNBOUNDED1[..], + BaseName::Erf => &EitherPrim::UNBOUNDED1[..], + BaseName::Erfc => &EitherPrim::UNBOUNDED1[..], + BaseName::Expm1 => &EitherPrim::UNBOUNDED1[..], + BaseName::Exp10 => &EitherPrim::UNBOUNDED1[..], + BaseName::Exp2 => &EitherPrim::UNBOUNDED1[..], + BaseName::Frexp => &EitherPrim::UNBOUNDED1[..], + BaseName::Fabs => &EitherPrim::UNBOUNDED1[..], + BaseName::Fdim => &EitherPrim::UNBOUNDED2[..], + BaseName::Floor => &EitherPrim::UNBOUNDED1[..], + BaseName::Fma => &EitherPrim::UNBOUNDED3[..], + BaseName::Fmax => &EitherPrim::UNBOUNDED2[..], + BaseName::Fmin => &EitherPrim::UNBOUNDED2[..], + BaseName::Fmod => &EitherPrim::UNBOUNDED2[..], + BaseName::Hypot => &EitherPrim::UNBOUNDED2[..], + BaseName::Ilogb => &EitherPrim::UNBOUNDED1[..], + BaseName::J0 => &EitherPrim::UNBOUNDED1[..], + BaseName::J1 => &EitherPrim::UNBOUNDED1[..], + BaseName::Jn => &EitherPrim::BESSEL_N[..], + BaseName::Ldexp => &EitherPrim::UNBOUNDED_F_I[..], + BaseName::Lgamma => &EitherPrim::LGAMMA[..], + BaseName::LgammaR => &EitherPrim::LGAMMA[..], + BaseName::Log => &EitherPrim::LOG[..], + BaseName::Log10 => &EitherPrim::LOG[..], + BaseName::Log1p => &EitherPrim::LOG1P[..], + BaseName::Log2 => &EitherPrim::LOG[..], + BaseName::Modf => &EitherPrim::UNBOUNDED1[..], + BaseName::Nextafter => &EitherPrim::UNBOUNDED2[..], + BaseName::Pow => &EitherPrim::UNBOUNDED2[..], + BaseName::Remainder => &EitherPrim::UNBOUNDED2[..], + BaseName::Remquo => &EitherPrim::UNBOUNDED2[..], + BaseName::Rint => &EitherPrim::UNBOUNDED1[..], + BaseName::Round => &EitherPrim::UNBOUNDED1[..], + BaseName::Scalbn => &EitherPrim::UNBOUNDED_F_I[..], + BaseName::Sin => &EitherPrim::TRIG[..], + BaseName::Sincos => &EitherPrim::TRIG[..], + BaseName::Sinh => &EitherPrim::UNBOUNDED1[..], + BaseName::Sqrt => &EitherPrim::SQRT[..], + BaseName::Tan => &EitherPrim::TRIG[..], + BaseName::Tanh => &EitherPrim::UNBOUNDED1[..], + BaseName::Tgamma => &EitherPrim::GAMMA[..], + BaseName::Trunc => &EitherPrim::UNBOUNDED1[..], + BaseName::Y0 => &EitherPrim::UNBOUNDED1[..], + BaseName::Y1 => &EitherPrim::UNBOUNDED1[..], + BaseName::Yn => &EitherPrim::BESSEL_N[..], }; -} - -// Tie functions together with their domains. -impl_has_domain! { - acos => INVERSE_TRIG_PERIODIC; - acosh => ACOSH; - asin => INVERSE_TRIG_PERIODIC; - asinh => UNBOUNDED; - atan => UNBOUNDED; - atanh => ATANH; - cbrt => UNBOUNDED; - ceil => UNBOUNDED; - cos => TRIG; - cosh => UNBOUNDED; - erf => UNBOUNDED; - erfc => UNBOUNDED; - exp => UNBOUNDED; - exp10 => UNBOUNDED; - exp2 => UNBOUNDED; - expm1 => UNBOUNDED; - fabs => UNBOUNDED; - floor => UNBOUNDED; - frexp => UNBOUNDED; - ilogb => UNBOUNDED; - j0 => UNBOUNDED; - j1 => UNBOUNDED; - lgamma => LGAMMA; - log => LOG; - log10 => LOG; - log1p => LOG1P; - log2 => LOG; - modf => UNBOUNDED; - rint => UNBOUNDED; - round => UNBOUNDED; - sin => TRIG; - sincos => TRIG; - sinh => UNBOUNDED; - sqrt => SQRT; - tan => TRIG; - tanh => UNBOUNDED; - tgamma => GAMMA; - trunc => UNBOUNDED; - y0 => UNBOUNDED; - y1 => UNBOUNDED; -} - -/* Manual implementations, these functions don't follow `foo`->`foof` naming */ - -impl HasDomain for crate::op::lgammaf_r::Routine { - const DOMAIN: Domain = Domain::::LGAMMA; -} - -impl HasDomain for crate::op::lgamma_r::Routine { - const DOMAIN: Domain = Domain::::LGAMMA; -} - -/* Not all `f16` and `f128` functions exist yet so we can't easily use the macros. */ - -#[cfg(f16_enabled)] -impl HasDomain for crate::op::fabsf16::Routine { - const DOMAIN: Domain = Domain::::UNBOUNDED; -} - -#[cfg(f128_enabled)] -impl HasDomain for crate::op::fabsf128::Routine { - const DOMAIN: Domain = Domain::::UNBOUNDED; -} - -#[cfg(f16_enabled)] -impl HasDomain for crate::op::fdimf16::Routine { - const DOMAIN: Domain = Domain::::UNBOUNDED; -} - -#[cfg(f128_enabled)] -impl HasDomain for crate::op::fdimf128::Routine { - const DOMAIN: Domain = Domain::::UNBOUNDED; -} - -#[cfg(f16_enabled)] -impl HasDomain for crate::op::truncf16::Routine { - const DOMAIN: Domain = Domain::::UNBOUNDED; -} -#[cfg(f128_enabled)] -impl HasDomain for crate::op::truncf128::Routine { - const DOMAIN: Domain = Domain::::UNBOUNDED; + x[argnum].clone() } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs index e2bfcdf34c8c2..e0a7f5766805e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs @@ -1,9 +1,8 @@ //! Different generators that can create random or systematic bit patterns. -pub mod domain_logspace; pub mod edge_cases; -pub mod extensive; pub mod random; +pub mod spaced; /// A wrapper to turn any iterator into an `ExactSizeIterator`. Asserts the final result to ensure /// the provided size was correct. diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs deleted file mode 100644 index c6963ad436a6a..0000000000000 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/domain_logspace.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! A generator that produces logarithmically spaced values within domain bounds. - -use std::ops::RangeInclusive; - -use libm::support::{IntTy, MinInt}; - -use crate::domain::HasDomain; -use crate::op::OpITy; -use crate::run_cfg::{GeneratorKind, iteration_count}; -use crate::{CheckCtx, MathOp, logspace}; - -/// Create a range of logarithmically spaced inputs within a function's domain. -/// -/// This allows us to get reasonably thorough coverage without wasting time on values that are -/// NaN or out of range. Random tests will still cover values that are excluded here. -pub fn get_test_cases(ctx: &CheckCtx) -> impl Iterator -where - Op: MathOp + HasDomain, - IntTy: TryFrom, - RangeInclusive>: Iterator, -{ - let domain = Op::DOMAIN; - let ntests = iteration_count(ctx, GeneratorKind::Domain, 0); - - // We generate logspaced inputs within a specific range, excluding values that are out of - // range in order to make iterations useful (random tests still cover the full range). - let start = domain.range_start(); - let end = domain.range_end(); - let steps = OpITy::::try_from(ntests).unwrap_or(OpITy::::MAX); - logspace(start, end, steps).0.map(|v| (v,)) -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs index 1f27c1467dcd0..d4014bdb36097 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs @@ -1,20 +1,28 @@ //! A generator that checks a handful of cases near infinities, zeros, asymptotes, and NaNs. -use libm::support::Float; +use libm::support::{Float, Int}; -use crate::domain::HasDomain; +use crate::domain::get_domain; +use crate::gen::KnownSize; use crate::run_cfg::{check_near_count, check_point_count}; -use crate::{CheckCtx, FloatExt, MathOp}; +use crate::{CheckCtx, FloatExt, MathOp, test_log}; + +/// Generate a sequence of edge cases, e.g. numbers near zeroes and infiniteis. +pub trait EdgeCaseInput { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator + Send; +} /// Create a list of values around interesting points (infinities, zeroes, NaNs). -pub fn get_test_cases(ctx: &CheckCtx) -> impl Iterator +fn float_edge_cases( + ctx: &CheckCtx, + argnum: usize, +) -> (impl Iterator + Clone, u64) where - Op: MathOp + HasDomain, - F: Float, + Op: MathOp, { let mut ret = Vec::new(); let values = &mut ret; - let domain = Op::DOMAIN; + let domain = get_domain::<_, i8>(ctx.fn_ident, argnum).unwrap_float(); let domain_start = domain.range_start(); let domain_end = domain.range_end(); @@ -22,17 +30,17 @@ where let near_points = check_near_count(ctx); // Check near some notable constants - 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); + 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); // Check values near the extremes - count_up(F::NEG_INFINITY, near_points, values); - count_down(F::INFINITY, near_points, values); + count_up(Op::FTy::NEG_INFINITY, near_points, values); + count_down(Op::FTy::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); @@ -40,8 +48,8 @@ where count_down(domain_end, near_points, values); // Check some special values that aren't included in the above ranges - values.push(F::NAN); - values.extend(F::consts().iter()); + values.push(Op::FTy::NAN); + values.extend(Op::FTy::consts().iter()); // Check around asymptotes if let Some(f) = domain.check_points { @@ -56,7 +64,18 @@ where values.sort_by_key(|x| x.to_bits()); values.dedup_by_key(|x| x.to_bits()); - ret.into_iter().map(|v| (v,)) + let count = ret.len().try_into().unwrap(); + + test_log(&format!( + "{gen_kind:?} {basis:?} {fn_ident} arg {arg}/{args}: {count} edge cases", + gen_kind = ctx.gen_kind, + basis = ctx.basis, + fn_ident = ctx.fn_ident, + arg = argnum + 1, + args = ctx.input_count(), + )); + + (ret.into_iter(), count) } /// Add `AROUND` values starting at and including `x` and counting up. Uses the smallest possible @@ -84,3 +103,131 @@ fn count_down(mut x: F, points: u64, values: &mut Vec) { count += 1; } } + +/// Create a list of values around interesting integer points (min, zero, max). +pub fn int_edge_cases( + ctx: &CheckCtx, + _argnum: usize, +) -> (impl Iterator + Clone, u64) { + let mut values = Vec::new(); + let near_points = check_near_count(ctx); + + for up_from in [I::MIN, I::ZERO] { + let mut x = up_from; + for _ in 0..near_points { + values.push(x); + x += I::ONE; + } + } + + for down_from in [I::ZERO, I::MAX] { + let mut x = down_from; + for _ in 0..near_points { + values.push(x); + x -= I::ONE; + } + } + + values.sort(); + values.dedup(); + let len = values.len().try_into().unwrap(); + (values.into_iter(), len) +} + +macro_rules! impl_edge_case_input { + ($fty:ty) => { + impl EdgeCaseInput for ($fty,) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + let (iter0, steps0) = float_edge_cases::(ctx, 0); + let iter0 = iter0.map(|v| (v,)); + KnownSize::new(iter0, steps0) + } + } + + impl EdgeCaseInput for ($fty, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + 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(); + KnownSize::new(iter, count) + } + } + + impl EdgeCaseInput for ($fty, $fty, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + 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))) + .flat_map(move |(first, second)| { + iter2.clone().map(move |third| (first, second, third)) + }); + let count = steps0.checked_mul(steps1).unwrap().checked_mul(steps2).unwrap(); + + KnownSize::new(iter, count) + } + } + + impl EdgeCaseInput for (i32, $fty) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + 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 count = steps0.checked_mul(steps1).unwrap(); + + KnownSize::new(iter, count) + } + } + + impl EdgeCaseInput for ($fty, i32) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + 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 count = steps0.checked_mul(steps1).unwrap(); + + KnownSize::new(iter, count) + } + } + }; +} + +#[cfg(f16_enabled)] +impl_edge_case_input!(f16); +impl_edge_case_input!(f32); +impl_edge_case_input!(f64); +#[cfg(f128_enabled)] +impl_edge_case_input!(f128); + +pub fn get_test_cases( + ctx: &CheckCtx, +) -> impl ExactSizeIterator + use<'_, Op> +where + Op: MathOp, + Op::RustArgs: EdgeCaseInput, +{ + Op::RustArgs::get_cases(ctx) +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index 6b08e560dff56..56c39981a44eb 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -9,8 +9,8 @@ use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; use super::KnownSize; +use crate::CheckCtx; use crate::run_cfg::{int_range, iteration_count}; -use crate::{CheckCtx, GeneratorKind}; pub(crate) const SEED_ENV: &str = "LIBM_SEED"; @@ -52,7 +52,7 @@ macro_rules! impl_random_input { ($fty:ty) => { impl RandomInput for ($fty,) { fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { - let count = iteration_count(ctx, GeneratorKind::Random, 0); + let count = iteration_count(ctx, 0); let iter = random_floats(count).map(|f: $fty| (f,)); KnownSize::new(iter, count) } @@ -60,8 +60,8 @@ macro_rules! impl_random_input { impl RandomInput for ($fty, $fty) { fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { - let count0 = iteration_count(ctx, GeneratorKind::Random, 0); - let count1 = iteration_count(ctx, GeneratorKind::Random, 1); + 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))); KnownSize::new(iter, count0 * count1) @@ -70,9 +70,9 @@ macro_rules! impl_random_input { impl RandomInput for ($fty, $fty, $fty) { fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { - let count0 = iteration_count(ctx, GeneratorKind::Random, 0); - let count1 = iteration_count(ctx, GeneratorKind::Random, 1); - let count2 = iteration_count(ctx, GeneratorKind::Random, 2); + 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)) @@ -84,9 +84,9 @@ macro_rules! impl_random_input { impl RandomInput for (i32, $fty) { fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { - let count0 = iteration_count(ctx, GeneratorKind::Random, 0); - let count1 = iteration_count(ctx, GeneratorKind::Random, 1); - let range0 = int_range(ctx, GeneratorKind::Random, 0); + let count0 = iteration_count(ctx, 0); + let count1 = iteration_count(ctx, 1); + let range0 = int_range(ctx, 0); let iter = random_ints(count0, range0) .flat_map(move |f1: i32| random_floats(count1).map(move |f2: $fty| (f1, f2))); KnownSize::new(iter, count0 * count1) @@ -95,9 +95,9 @@ macro_rules! impl_random_input { impl RandomInput for ($fty, i32) { fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { - let count0 = iteration_count(ctx, GeneratorKind::Random, 0); - let count1 = iteration_count(ctx, GeneratorKind::Random, 1); - let range1 = int_range(ctx, GeneratorKind::Random, 1); + let count0 = iteration_count(ctx, 0); + let count1 = iteration_count(ctx, 1); + let range1 = int_range(ctx, 1); let iter = random_floats(count0).flat_map(move |f1: $fty| { random_ints(count1, range1.clone()).map(move |f2: i32| (f1, f2)) }); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/spaced.rs similarity index 76% rename from library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs rename to library/compiler-builtins/libm/crates/libm-test/src/gen/spaced.rs index fb709e54684ea..bea3f4c7e1b26 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/extensive.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/spaced.rs @@ -3,23 +3,23 @@ use std::ops::RangeInclusive; use libm::support::{Float, MinInt}; -use crate::domain::HasDomain; +use crate::domain::get_domain; use crate::op::OpITy; use crate::run_cfg::{int_range, iteration_count}; -use crate::{CheckCtx, GeneratorKind, MathOp, linear_ints, logspace}; +use crate::{CheckCtx, MathOp, linear_ints, logspace}; -/// Generate a sequence of inputs that either cover the domain in completeness (for smaller float +/// 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 /// approximately `u32::MAX` total iterations. -pub trait ExtensiveInput { +pub trait SpacedInput { fn get_cases(ctx: &CheckCtx) -> (impl Iterator + Send, u64); } /// Construct an iterator from `logspace` and also calculate the total number of steps expected /// for that iterator. fn logspace_steps( - start: Op::FTy, - end: Op::FTy, + ctx: &CheckCtx, + argnum: usize, max_steps: u64, ) -> (impl Iterator + Clone, u64) where @@ -28,6 +28,11 @@ where u64: TryFrom, Error: fmt::Debug>, RangeInclusive>: Iterator, { + // i8 is a dummy type here, it can be any integer. + 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 (iter, steps) = logspace(start, end, max_steps); @@ -76,15 +81,14 @@ where (F::Int::MIN..=F::Int::MAX).map(|bits| F::from_bits(bits)) } -macro_rules! impl_extensive_input { +macro_rules! impl_spaced_input { ($fty:ty) => { - impl ExtensiveInput for ($fty,) + impl SpacedInput for ($fty,) where Op: MathOp, - Op: HasDomain, { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let max_steps0 = iteration_count(ctx, GeneratorKind::Extensive, 0); + let max_steps0 = iteration_count(ctx, 0); // `f16` and `f32` can have exhaustive tests. match value_count::() { Some(steps0) if steps0 <= max_steps0 => { @@ -93,9 +97,7 @@ macro_rules! impl_extensive_input { (EitherIter::A(iter0), steps0) } _ => { - let start = Op::DOMAIN.range_start(); - let end = Op::DOMAIN.range_end(); - let (iter0, steps0) = logspace_steps::(start, end, max_steps0); + let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); let iter0 = iter0.map(|v| (v,)); (EitherIter::B(iter0), steps0) } @@ -103,13 +105,13 @@ macro_rules! impl_extensive_input { } } - impl ExtensiveInput for ($fty, $fty) + impl SpacedInput for ($fty, $fty) where Op: MathOp, { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let max_steps0 = iteration_count(ctx, GeneratorKind::Extensive, 0); - let max_steps1 = iteration_count(ctx, GeneratorKind::Extensive, 1); + let max_steps0 = iteration_count(ctx, 0); + let max_steps1 = iteration_count(ctx, 1); // `f16` can have exhaustive tests. match value_count::() { Some(count) if count <= max_steps0 && count <= max_steps1 => { @@ -118,10 +120,8 @@ macro_rules! impl_extensive_input { (EitherIter::A(iter), count.checked_mul(count).unwrap()) } _ => { - let start = <$fty>::NEG_INFINITY; - let end = <$fty>::INFINITY; - let (iter0, steps0) = logspace_steps::(start, end, max_steps0); - let (iter1, steps1) = logspace_steps::(start, end, 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)) }); @@ -132,14 +132,14 @@ macro_rules! impl_extensive_input { } } - impl ExtensiveInput for ($fty, $fty, $fty) + impl SpacedInput for ($fty, $fty, $fty) where Op: MathOp, { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let max_steps0 = iteration_count(ctx, GeneratorKind::Extensive, 0); - let max_steps1 = iteration_count(ctx, GeneratorKind::Extensive, 1); - let max_steps2 = iteration_count(ctx, GeneratorKind::Extensive, 2); + 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::() { Some(count) @@ -153,12 +153,9 @@ macro_rules! impl_extensive_input { (EitherIter::A(iter), count.checked_pow(3).unwrap()) } _ => { - let start = <$fty>::NEG_INFINITY; - let end = <$fty>::INFINITY; - - let (iter0, steps0) = logspace_steps::(start, end, max_steps0); - let (iter1, steps1) = logspace_steps::(start, end, max_steps1); - let (iter2, steps2) = logspace_steps::(start, end, 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))) @@ -174,14 +171,14 @@ macro_rules! impl_extensive_input { } } - impl ExtensiveInput for (i32, $fty) + impl SpacedInput for (i32, $fty) where Op: MathOp, { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let range0 = int_range(ctx, GeneratorKind::Extensive, 0); - let max_steps0 = iteration_count(ctx, GeneratorKind::Extensive, 0); - let max_steps1 = iteration_count(ctx, GeneratorKind::Extensive, 1); + let range0 = int_range(ctx, 0); + let max_steps0 = iteration_count(ctx, 0); + let max_steps1 = iteration_count(ctx, 1); match value_count::() { Some(count1) if count1 <= max_steps1 => { let (iter0, steps0) = linear_ints(range0, max_steps0); @@ -190,11 +187,8 @@ macro_rules! impl_extensive_input { (EitherIter::A(iter), steps0.checked_mul(count1).unwrap()) } _ => { - let start = <$fty>::NEG_INFINITY; - let end = <$fty>::INFINITY; - let (iter0, steps0) = linear_ints(range0, max_steps0); - let (iter1, steps1) = logspace_steps::(start, end, 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)) @@ -207,14 +201,14 @@ macro_rules! impl_extensive_input { } } - impl ExtensiveInput for ($fty, i32) + impl SpacedInput for ($fty, i32) where Op: MathOp, { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let max_steps0 = iteration_count(ctx, GeneratorKind::Extensive, 0); - let range1 = int_range(ctx, GeneratorKind::Extensive, 1); - let max_steps1 = iteration_count(ctx, GeneratorKind::Extensive, 1); + let max_steps0 = iteration_count(ctx, 0); + let range1 = int_range(ctx, 1); + let max_steps1 = iteration_count(ctx, 1); match value_count::() { Some(count0) if count0 <= max_steps0 => { let (iter1, steps1) = linear_ints(range1, max_steps1); @@ -224,10 +218,7 @@ macro_rules! impl_extensive_input { (EitherIter::A(iter), count0.checked_mul(steps1).unwrap()) } _ => { - let start = <$fty>::NEG_INFINITY; - let end = <$fty>::INFINITY; - - let (iter0, steps0) = logspace_steps::(start, end, 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| { @@ -244,11 +235,11 @@ macro_rules! impl_extensive_input { } #[cfg(f16_enabled)] -impl_extensive_input!(f16); -impl_extensive_input!(f32); -impl_extensive_input!(f64); +impl_spaced_input!(f16); +impl_spaced_input!(f32); +impl_spaced_input!(f64); #[cfg(f128_enabled)] -impl_extensive_input!(f128); +impl_spaced_input!(f128); /// Create a test case iterator for extensive inputs. Also returns the total test case count. pub fn get_test_cases( @@ -256,7 +247,7 @@ pub fn get_test_cases( ) -> (impl Iterator + Send + use<'_, Op>, u64) where Op: MathOp, - Op::RustArgs: ExtensiveInput, + Op::RustArgs: SpacedInput, { Op::RustArgs::get_cases(ctx) } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index 4a52091fe8d28..6763de8bcc8db 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -39,11 +39,12 @@ pub struct CheckCtx { pub base_name_str: &'static str, /// Source of truth for tests. pub basis: CheckBasis, + pub gen_kind: GeneratorKind, } impl CheckCtx { /// Create a new check context, using the default ULP for the function. - pub fn new(fn_ident: Identifier, basis: CheckBasis) -> Self { + pub fn new(fn_ident: Identifier, basis: CheckBasis, gen_kind: GeneratorKind) -> Self { let mut ret = Self { ulp: 0, fn_ident, @@ -51,10 +52,16 @@ impl CheckCtx { base_name: fn_ident.base_name(), base_name_str: fn_ident.base_name().as_str(), basis, + gen_kind, }; ret.ulp = crate::default_ulp(&ret); ret } + + /// The number of input arguments for this function. + pub fn input_count(&self) -> usize { + self.fn_ident.math_op().rust_sig.args.len() + } } /// Possible items to test against @@ -66,11 +73,13 @@ pub enum CheckBasis { Mpfr, } -/// The different kinds of generators that provide test input. +/// The different kinds of generators that provide test input, which account for input pattern +/// and quantity. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum GeneratorKind { - Domain, + EdgeCases, Extensive, + QuickSpaced, Random, } @@ -155,7 +164,7 @@ impl TestEnv { } /// The number of iterations to run for a given test. -pub fn iteration_count(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) -> u64 { +pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { let t_env = TestEnv::from_env(ctx); // Ideally run 5M tests @@ -185,10 +194,13 @@ pub fn iteration_count(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) - // Run fewer random tests than domain tests. let random_iter_count = domain_iter_count / 100; - let mut total_iterations = match gen_kind { - GeneratorKind::Domain => domain_iter_count, + let mut total_iterations = match ctx.gen_kind { + GeneratorKind::QuickSpaced => domain_iter_count, GeneratorKind::Random => random_iter_count, GeneratorKind::Extensive => *EXTENSIVE_MAX_ITERATIONS, + GeneratorKind::EdgeCases => { + unimplemented!("edge case tests shoudn't need `iteration_count`") + } }; // FMA has a huge domain but is reasonably fast to run, so increase iterations. @@ -213,16 +225,18 @@ pub fn iteration_count(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) - }; let total = ntests.pow(t_env.input_count.try_into().unwrap()); - let seed_msg = match gen_kind { - GeneratorKind::Domain | GeneratorKind::Extensive => String::new(), + let seed_msg = match ctx.gen_kind { + GeneratorKind::QuickSpaced | GeneratorKind::Extensive => String::new(), GeneratorKind::Random => { format!(" using `{SEED_ENV}={}`", str::from_utf8(SEED.as_slice()).unwrap()) } + GeneratorKind::EdgeCases => unreachable!(), }; test_log(&format!( "{gen_kind:?} {basis:?} {fn_ident} arg {arg}/{args}: {ntests} iterations \ ({total} total){seed_msg}", + gen_kind = ctx.gen_kind, basis = ctx.basis, fn_ident = ctx.fn_ident, arg = argnum + 1, @@ -233,7 +247,7 @@ pub fn iteration_count(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) - } /// Some tests require that an integer be kept within reasonable limits; generate that here. -pub fn int_range(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) -> RangeInclusive { +pub fn int_range(ctx: &CheckCtx, argnum: usize) -> RangeInclusive { let t_env = TestEnv::from_env(ctx); if !matches!(ctx.base_name, BaseName::Jn | BaseName::Yn) { @@ -252,22 +266,42 @@ pub fn int_range(ctx: &CheckCtx, gen_kind: GeneratorKind, argnum: usize) -> Rang let extensive_range = (-0xfff)..=0xfffff; - match gen_kind { + match ctx.gen_kind { GeneratorKind::Extensive => extensive_range, - GeneratorKind::Domain | GeneratorKind::Random => non_extensive_range, + GeneratorKind::QuickSpaced | GeneratorKind::Random => non_extensive_range, + GeneratorKind::EdgeCases => extensive_range, } } /// For domain tests, limit how many asymptotes or specified check points we test. pub fn check_point_count(ctx: &CheckCtx) -> usize { + assert_eq!( + ctx.gen_kind, + GeneratorKind::EdgeCases, + "check_point_count is intended for edge case tests" + ); let t_env = TestEnv::from_env(ctx); if t_env.slow_platform || !cfg!(optimizations_enabled) { 4 } else { 10 } } /// When validating points of interest (e.g. asymptotes, inflection points, extremes), also check /// this many surrounding values. -pub fn check_near_count(_ctx: &CheckCtx) -> u64 { - if cfg!(optimizations_enabled) { 100 } else { 10 } +pub fn check_near_count(ctx: &CheckCtx) -> u64 { + assert_eq!( + ctx.gen_kind, + GeneratorKind::EdgeCases, + "check_near_count is intended for edge case tests" + ); + if cfg!(optimizations_enabled) { + // Taper based on the number of inputs. + match ctx.input_count() { + 1 | 2 => 100, + 3 => 50, + x => panic!("unexpected argument count {x}"), + } + } else { + 10 + } } /// Check whether extensive actions should be run or skipped. diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 836c425a5896e..f540a0b15517f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -9,150 +9,78 @@ // There are some targets we can't build musl for #![cfg(feature = "build-musl")] -use libm_test::domain::HasDomain; -use libm_test::gen::random::RandomInput; -use libm_test::gen::{domain_logspace, edge_cases, random}; -use libm_test::{CheckBasis, CheckCtx, CheckOutput, MathOp, TupleCall}; +use libm_test::gen::{edge_cases, random, spaced}; +use libm_test::{CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TupleCall}; -macro_rules! musl_rand_tests { - ( - fn_name: $fn_name:ident, - attrs: [$($attr:meta),*], - ) => { - paste::paste! { - #[test] - $(#[$attr])* - fn [< musl_random_ $fn_name >]() { - test_one_random::(musl_math_sys::$fn_name); - } - } - }; -} - -fn test_one_random(musl_fn: Op::CFn) -where - Op: MathOp, - Op::RustArgs: RandomInput, -{ - let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl); - let cases = random::get_test_cases::(&ctx); +const BASIS: CheckBasis = CheckBasis::Musl; +fn musl_runner( + ctx: &CheckCtx, + cases: impl Iterator, + musl_fn: Op::CFn, +) { for input in cases { let musl_res = input.call(musl_fn); let crate_res = input.call(Op::ROUTINE); - crate_res.validate(musl_res, input, &ctx).unwrap(); + crate_res.validate(musl_res, input, ctx).unwrap(); } } -libm_macros::for_each_function! { - callback: musl_rand_tests, - // Musl does not support `f16` and `f128` on all platforms. - skip: [ - copysignf128, - copysignf16, - fabsf128, - fabsf16, - fdimf128, - fdimf16, - truncf128, - truncf16, - ], - attributes: [ - #[cfg_attr(x86_no_sse, ignore)] // FIXME(correctness): wrong result on i586 - [exp10, exp10f, exp2, exp2f, rint] - ], -} - /// Test against musl with generators from a domain. -macro_rules! musl_domain_tests { +macro_rules! musl_tests { ( fn_name: $fn_name:ident, attrs: [$($attr:meta),*], ) => { paste::paste! { + #[test] + $(#[$attr])* + fn [< musl_random_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::Random); + let cases = random::get_test_cases::<::RustArgs>(&ctx); + musl_runner::(&ctx, cases, musl_math_sys::$fn_name); + } + #[test] $(#[$attr])* fn [< musl_edge_case_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; - domain_test_runner::( - edge_cases::get_test_cases::, - musl_math_sys::$fn_name, - ); + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::EdgeCases); + let cases = edge_cases::get_test_cases::(&ctx); + musl_runner::(&ctx, cases, musl_math_sys::$fn_name); } #[test] $(#[$attr])* - fn [< musl_logspace_ $fn_name >]() { + fn [< musl_quickspace_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; - domain_test_runner::( - domain_logspace::get_test_cases::, - musl_math_sys::$fn_name, - ); + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::QuickSpaced); + let cases = spaced::get_test_cases::(&ctx).0; + musl_runner::(&ctx, cases, musl_math_sys::$fn_name); } } }; } -/// Test a single routine against domaine-aware inputs. -fn domain_test_runner(gen: impl FnOnce(&CheckCtx) -> I, musl_fn: Op::CFn) -where - Op: MathOp, - Op: HasDomain, - I: Iterator, -{ - let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl); - let cases = gen(&ctx); - - for input in cases { - let musl_res = input.call(musl_fn); - let crate_res = input.call(Op::ROUTINE); - - crate_res.validate(musl_res, input, &ctx).unwrap(); - } -} - libm_macros::for_each_function! { - callback: musl_domain_tests, + callback: musl_tests, attributes: [], skip: [ - // Functions with multiple inputs - atan2, - atan2f, - copysign, - copysignf, - copysignf16, - copysignf128, - fdim, - fdimf, - fma, - fmaf, - fmax, - fmaxf, - fmin, - fminf, - fmod, - fmodf, - hypot, - hypotf, + // TODO integer inputs jn, jnf, ldexp, ldexpf, - nextafter, - nextafterf, - pow, - powf, - remainder, - remainderf, - remquo, - remquof, scalbn, scalbnf, yn, ynf, // Not provided by musl + copysignf128, + copysignf16, fabsf128, fabsf16, fdimf128, diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 123abfdaf8b11..761ca1f851e21 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -2,151 +2,69 @@ #![cfg(feature = "build-mpfr")] -use libm_test::domain::HasDomain; -use libm_test::gen::random::RandomInput; -use libm_test::gen::{domain_logspace, edge_cases, random}; +use libm_test::gen::{edge_cases, random, spaced}; use libm_test::mpfloat::MpOp; -use libm_test::{CheckBasis, CheckCtx, CheckOutput, MathOp, OpFTy, OpRustFn, OpRustRet, TupleCall}; +use libm_test::{CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TupleCall}; -/// Test against MPFR with random inputs. -macro_rules! mp_rand_tests { - ( - fn_name: $fn_name:ident, - attrs: [$($attr:meta),*], - ) => { - paste::paste! { - #[test] - $(#[$attr])* - fn [< mp_random_ $fn_name >]() { - test_one_random::(); - } - } - }; -} +const BASIS: CheckBasis = CheckBasis::Mpfr; -/// Test a single routine with random inputs -fn test_one_random() -where - Op: MathOp + MpOp, - Op::RustArgs: RandomInput, -{ +fn mp_runner(ctx: &CheckCtx, cases: impl Iterator) { let mut mp_vals = Op::new_mp(); - let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); - let cases = random::get_test_cases::(&ctx); - for input in cases { let mp_res = Op::run(&mut mp_vals, input); let crate_res = input.call(Op::ROUTINE); - crate_res.validate(mp_res, input, &ctx).unwrap(); + crate_res.validate(mp_res, input, ctx).unwrap(); } } -libm_macros::for_each_function! { - callback: mp_rand_tests, - attributes: [ - // Also an assertion failure on i686: at `MPFR_ASSERTN (! mpfr_erangeflag_p ())` - #[ignore = "large values are infeasible in MPFR"] - [jn, jnf, yn, ynf], - ], - skip: [ - // FIXME: test needed, see - // https://github.com/rust-lang/libm/pull/311#discussion_r1818273392 - nextafter, - nextafterf, - ], -} - -/// Test against MPFR with generators from a domain. -macro_rules! mp_domain_tests { +macro_rules! mp_tests { ( fn_name: $fn_name:ident, attrs: [$($attr:meta),*], ) => { paste::paste! { + #[test] + $(#[$attr])* + fn [< mp_random_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::Random); + let cases = random::get_test_cases::<::RustArgs>(&ctx); + mp_runner::(&ctx, cases); + } + #[test] $(#[$attr])* fn [< mp_edge_case_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; - domain_test_runner::(edge_cases::get_test_cases::); + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::EdgeCases); + let cases = edge_cases::get_test_cases::(&ctx); + mp_runner::(&ctx, cases); } #[test] $(#[$attr])* - fn [< mp_logspace_ $fn_name >]() { + fn [< mp_quickspace_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; - domain_test_runner::(domain_logspace::get_test_cases::); + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::QuickSpaced); + let cases = spaced::get_test_cases::(&ctx).0; + mp_runner::(&ctx, cases); } } }; } -/// Test a single routine against domaine-aware inputs. -fn domain_test_runner(gen: impl FnOnce(&CheckCtx) -> I) -where - // Complicated generics... - // The operation must take a single float argument (unary only) - Op: MathOp::FTy,)>, - // It must also support multiprecision operations - Op: MpOp, - // And it must have a domain specified - Op: HasDomain, - // The single float argument tuple must be able to call the `RustFn` and return `RustRet` - (OpFTy,): TupleCall, Output = OpRustRet>, - I: Iterator, -{ - let mut mp_vals = Op::new_mp(); - let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); - let cases = gen(&ctx); - - for input in cases { - let mp_res = Op::run(&mut mp_vals, input); - let crate_res = input.call(Op::ROUTINE); - - crate_res.validate(mp_res, input, &ctx).unwrap(); - } -} - libm_macros::for_each_function! { - callback: mp_domain_tests, - attributes: [], + callback: mp_tests, + attributes: [ + // Also an assertion failure on i686: at `MPFR_ASSERTN (! mpfr_erangeflag_p ())` + #[ignore = "large values are infeasible in MPFR"] + [jn, jnf, yn, ynf], + ], skip: [ - // Functions with multiple inputs - atan2, - atan2f, - copysign, - copysignf, - copysignf16, - copysignf128, - fdim, - fdimf, - fdimf16, - fdimf128, - fma, - fmaf, - fmax, - fmaxf, - fmin, - fminf, - fmod, - fmodf, - hypot, - hypotf, - jn, - jnf, - ldexp, - ldexpf, + // FIXME: test needed, see + // https://github.com/rust-lang/libm/pull/311#discussion_r1818273392 nextafter, nextafterf, - pow, - powf, - remainder, - remainderf, - remquo, - remquof, - scalbn, - scalbnf, - yn, - ynf, ], } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs index 7ee9678515ea3..a323c9110ee8f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs @@ -6,13 +6,18 @@ use std::sync::atomic::{AtomicU64, Ordering}; use std::time::Duration; use indicatif::{ProgressBar, ProgressStyle}; -use libm_test::gen::extensive::{self, ExtensiveInput}; +use libm_test::gen::spaced; use libm_test::mpfloat::MpOp; use libm_test::{ - CheckBasis, CheckCtx, CheckOutput, MathOp, TestResult, TupleCall, skip_extensive_test, + CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TestResult, TupleCall, + skip_extensive_test, }; use libtest_mimic::{Arguments, Trial}; use rayon::prelude::*; +use spaced::SpacedInput; + +const BASIS: CheckBasis = CheckBasis::Mpfr; +const GEN_KIND: GeneratorKind = GeneratorKind::Extensive; /// Run the extensive test suite. pub fn run() { @@ -62,10 +67,10 @@ fn register_all_tests() -> Vec { fn register_single_test(all: &mut Vec) where Op: MathOp + MpOp, - Op::RustArgs: ExtensiveInput + Send, + Op::RustArgs: SpacedInput + Send, { let test_name = format!("mp_extensive_{}", Op::NAME); - let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GEN_KIND); let skip = skip_extensive_test(&ctx); let runner = move || { @@ -73,7 +78,7 @@ where panic!("extensive tests should be run with --release"); } - let res = run_single_test::(); + let res = run_single_test::(&ctx); let e = match res { Ok(()) => return Ok(()), Err(e) => e, @@ -91,18 +96,17 @@ where } /// Test runner for a signle routine. -fn run_single_test() -> TestResult +fn run_single_test(ctx: &CheckCtx) -> TestResult where Op: MathOp + MpOp, - Op::RustArgs: ExtensiveInput + Send, + Op::RustArgs: SpacedInput + Send, { // Small delay before printing anything so other output from the runner has a chance to flush. std::thread::sleep(Duration::from_millis(500)); eprintln!(); let completed = AtomicU64::new(0); - let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr); - let (ref mut cases, total) = extensive::get_test_cases::(&ctx); + let (ref mut cases, total) = spaced::get_test_cases::(ctx); let pb = Progress::new(Op::NAME, total); let test_single_chunk = |mp_vals: &mut Op::MpTy, input_vec: Vec| -> TestResult { @@ -110,7 +114,7 @@ where // Test the input. let mp_res = Op::run(mp_vals, input); let crate_res = input.call(Op::ROUTINE); - crate_res.validate(mp_res, input, &ctx)?; + crate_res.validate(mp_res, input, ctx)?; let completed = completed.fetch_add(1, Ordering::Relaxed) + 1; pb.update(completed, input); From ecca4879a2eb69dda14611260c54c95c0b1df93e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 21:10:12 +0000 Subject: [PATCH 1570/4206] Adjust precision and add xfails based on new tests --- .../libm/crates/libm-test/src/precision.rs | 149 ++++++++++++++++-- .../libm/src/math/support/float_traits.rs | 7 +- 2 files changed, 143 insertions(+), 13 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 0b3fe89befd15..3cb5e420f2601 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -102,6 +102,15 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { } } + if cfg!(target_arch = "x86") { + match ctx.fn_ident { + // Input `fma(0.999999999999999, 1.0000000000000013, 0.0) = 1.0000000000000002` is + // incorrect on i586 and i686. + 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 { @@ -370,59 +379,129 @@ fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Opt impl MaybeOverride<(f16, f16)> for SpecialCase { fn check_float( input: (f16, f16), - _actual: F, + actual: F, expected: F, _ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - maybe_skip_binop_nan(input, expected, ctx) + binop_common(input, actual, expected, ctx) } } impl MaybeOverride<(f32, f32)> for SpecialCase { fn check_float( input: (f32, f32), - _actual: F, + actual: F, expected: F, _ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - maybe_skip_binop_nan(input, expected, ctx) + if ctx.base_name == BaseName::Fmin + && input.0.biteq(f32::NEG_ZERO) + && input.1.biteq(f32::ZERO) + && expected.biteq(F::NEG_ZERO) + && actual.biteq(F::ZERO) + { + return XFAIL; + } + + binop_common(input, actual, expected, ctx) + } + + fn check_int( + _input: (f32, f32), + actual: I, + expected: I, + ctx: &CheckCtx, + ) -> Option { + remquo_common(actual, expected, ctx) } } impl MaybeOverride<(f64, f64)> for SpecialCase { fn check_float( input: (f64, f64), - _actual: F, + actual: F, expected: F, _ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - maybe_skip_binop_nan(input, expected, ctx) + if ctx.base_name == BaseName::Fmin + && input.0.biteq(f64::NEG_ZERO) + && input.1.biteq(f64::ZERO) + && expected.biteq(F::ZERO) + && actual.biteq(F::NEG_ZERO) + { + return XFAIL; + } + + binop_common(input, actual, expected, ctx) + } + + fn check_int( + _input: (f64, f64), + actual: I, + expected: I, + ctx: &CheckCtx, + ) -> Option { + remquo_common(actual, expected, ctx) + } +} + +fn remquo_common(actual: I, expected: I, ctx: &CheckCtx) -> Option { + // FIXME: Our MPFR implementation disagrees with musl and may need to be updated. + if ctx.basis == CheckBasis::Mpfr + && ctx.base_name == BaseName::Remquo + && expected == I::MIN + && actual == I::ZERO + { + return XFAIL; } + + None } #[cfg(f128_enabled)] impl MaybeOverride<(f128, f128)> for SpecialCase { fn check_float( input: (f128, f128), - _actual: F, + actual: F, expected: F, _ulp: &mut u32, ctx: &CheckCtx, ) -> Option { - maybe_skip_binop_nan(input, expected, ctx) + binop_common(input, actual, expected, ctx) } } -/// Musl propagates NaNs if one is provided as the input, but we return the other input. // F1 and F2 are always the same type, this is just to please generics -fn maybe_skip_binop_nan( +fn binop_common( input: (F1, F1), + actual: F2, expected: F2, ctx: &CheckCtx, ) -> Option { + /* FIXME(#439): we do not compare signed zeros */ + + if ctx.base_name == BaseName::Fmin + && input.0.biteq(F1::NEG_ZERO) + && input.1.biteq(F1::ZERO) + && expected.biteq(F2::NEG_ZERO) + && actual.biteq(F2::ZERO) + { + return XFAIL; + } + + if ctx.base_name == BaseName::Fmax + && input.0.biteq(F1::NEG_ZERO) + && input.1.biteq(F1::ZERO) + && expected.biteq(F2::ZERO) + && actual.biteq(F2::NEG_ZERO) + { + return XFAIL; + } + + // Musl propagates NaNs if one is provided as the input, but we return the other input. match (&ctx.basis, ctx.base_name) { (Musl, BaseName::Fmin | BaseName::Fmax) if (input.0.is_nan() || input.1.is_nan()) && expected.is_nan() => @@ -509,7 +588,53 @@ fn bessel_prec_dropoff( None } -impl MaybeOverride<(f32, f32, f32)> for SpecialCase {} -impl MaybeOverride<(f64, f64, f64)> for SpecialCase {} impl MaybeOverride<(f32, i32)> for SpecialCase {} impl MaybeOverride<(f64, i32)> for SpecialCase {} + +impl MaybeOverride<(f32, f32, f32)> for SpecialCase { + fn check_float( + input: (f32, f32, f32), + actual: F, + expected: F, + _ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + ternop_common(input, actual, expected, ctx) + } +} +impl MaybeOverride<(f64, f64, f64)> for SpecialCase { + fn check_float( + input: (f64, f64, f64), + actual: F, + expected: F, + _ulp: &mut u32, + ctx: &CheckCtx, + ) -> Option { + ternop_common(input, actual, expected, ctx) + } +} + +// F1 and F2 are always the same type, this is just to please generics +fn ternop_common( + input: (F1, F1, F1), + actual: F2, + expected: F2, + ctx: &CheckCtx, +) -> Option { + // FIXME(fma): 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result + // of fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the + // exact result". Our implementation returns the wrong sign: + // fma(5e-324, -5e-324, 0.0) = 0.0 (should be -0.0) + if ctx.base_name == BaseName::Fma + && (input.0.is_sign_negative() ^ input.1.is_sign_negative()) + && input.0 != F1::ZERO + && input.1 != F1::ZERO + && input.2.biteq(F1::ZERO) + && expected.biteq(F2::NEG_ZERO) + && actual.biteq(F2::ZERO) + { + return XFAIL; + } + + None +} 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 3aa0d844a7218..647f4f5e251b2 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -93,9 +93,14 @@ pub trait Float: /// Returns true if the value is +inf or -inf. fn is_infinite(self) -> bool; - /// Returns true if the sign is negative. + /// Returns true if the sign is negative. Extracts the sign bit regardless of zero or NaN. fn is_sign_negative(self) -> bool; + /// Returns true if the sign is positive. Extracts the sign bit regardless of zero or NaN. + fn is_sign_positive(self) -> bool { + !self.is_sign_negative() + } + /// Returns if `self` is subnormal fn is_subnormal(self) -> bool { (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO From 17c86e4e7fea6a245641f576a48aeaf362f562ef Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 22:48:03 +0000 Subject: [PATCH 1571/4206] Increase the CI timeout --- library/compiler-builtins/libm/.github/workflows/main.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index 40b67c4c251a9..99a32a82ec1d8 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -14,7 +14,7 @@ env: jobs: test: name: Build and test - timeout-minutes: 25 + timeout-minutes: 40 strategy: fail-fast: false matrix: From f56b41dbbdc660f303e0946c50be8989e3657689 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 16 Jan 2025 07:30:51 +0000 Subject: [PATCH 1572/4206] Provide a way to override iteration count Benchmarks need a way to limit how many iterations get run. Introuce a way to inject this information here. --- .../libm/crates/libm-test/src/run_cfg.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index 6763de8bcc8db..3e91101f6cacf 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -40,6 +40,8 @@ pub struct CheckCtx { /// Source of truth for tests. pub basis: CheckBasis, pub gen_kind: GeneratorKind, + /// If specified, this value will override the value returned by [`iteration_count`]. + pub override_iterations: Option, } impl CheckCtx { @@ -53,6 +55,7 @@ impl CheckCtx { base_name_str: fn_ident.base_name().as_str(), basis, gen_kind, + override_iterations: None, }; ret.ulp = crate::default_ulp(&ret); ret @@ -62,6 +65,10 @@ impl CheckCtx { pub fn input_count(&self) -> usize { self.fn_ident.math_op().rust_sig.args.len() } + + pub fn override_iterations(&mut self, count: u64) { + self.override_iterations = Some(count) + } } /// Possible items to test against @@ -71,6 +78,8 @@ pub enum CheckBasis { Musl, /// Check against infinite precision (MPFR). Mpfr, + /// Benchmarks or other times when this is not relevant. + None, } /// The different kinds of generators that provide test input, which account for input pattern @@ -216,6 +225,12 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { total_iterations = 800; } + let mut overridden = false; + if let Some(count) = ctx.override_iterations { + total_iterations = count; + overridden = true; + } + // Adjust for the number of inputs let ntests = match t_env.input_count { 1 => total_iterations, @@ -223,6 +238,7 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { 3 => (total_iterations as f64).cbrt().ceil() as u64, _ => panic!("test has more than three arguments"), }; + let total = ntests.pow(t_env.input_count.try_into().unwrap()); let seed_msg = match ctx.gen_kind { @@ -235,12 +251,13 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { test_log(&format!( "{gen_kind:?} {basis:?} {fn_ident} arg {arg}/{args}: {ntests} iterations \ - ({total} total){seed_msg}", + ({total} total){seed_msg}{omsg}", gen_kind = ctx.gen_kind, basis = ctx.basis, fn_ident = ctx.fn_ident, arg = argnum + 1, args = t_env.input_count, + omsg = if overridden { " (overridden)" } else { "" } )); ntests From 490ebbb187ff309db6599eb1616b100114dc834d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 16 Jan 2025 07:30:38 +0000 Subject: [PATCH 1573/4206] Add benchmarks using iai-callgrind Running walltime benchmarks in CI is notoriously unstable, Introduce benchmarks that instead use instruction count and other more reproducible metrics, using `iai-callgrind` [1], which we are able to run in CI with a high degree of reproducibility. Inputs to this benchmark are a logspace sweep, which gives an approximation for real-world use, but may fail to indicate outlier cases. [1]: https://github.com/iai-callgrind/iai-callgrind --- library/compiler-builtins/libm/Cargo.toml | 4 + .../libm/crates/libm-test/Cargo.toml | 9 + .../libm/crates/libm-test/benches/icount.rs | 175 ++++++++++++++++++ .../libm/crates/libm-test/src/lib.rs | 3 +- .../libm/crates/libm-test/src/op.rs | 2 + 5 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/benches/icount.rs diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index f84f3eac6a4d0..18d89997dcba6 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -73,3 +73,7 @@ debug-assertions = true inherits = "release" lto = "fat" overflow-checks = true + +[profile.bench] +# Required for iai-callgrind +debug = true diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index d3f18ab3e5bc8..3a1ba87962a7d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -20,6 +20,9 @@ build-musl = ["dep:musl-math-sys"] # Enable report generation without bringing in more dependencies by default benchmarking-reports = ["criterion/plotters", "criterion/html_reports"] +# Enable icount benchmarks (requires iai-callgrind and valgrind) +icount = ["dep:iai-callgrind"] + # Run with a reduced set of benchmarks, such as for CI short-benchmarks = [] @@ -27,6 +30,7 @@ short-benchmarks = [] anyhow = "1.0.90" az = { version = "1.2.1", optional = true } gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false, features = ["mpfr"] } +iai-callgrind = { version = "0.14.0", optional = true } indicatif = { version = "0.17.9", default-features = false } libm = { path = "../..", features = ["unstable-public-internals"] } libm-macros = { path = "../libm-macros" } @@ -48,6 +52,11 @@ rand = { version = "0.8.5", optional = true } criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } libtest-mimic = "0.8.1" +[[bench]] +name = "icount" +harness = false +required-features = ["icount"] + [[bench]] name = "random" harness = false diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs new file mode 100644 index 0000000000000..3a66249e85dc5 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -0,0 +1,175 @@ +//! Benchmarks that use `iai-cachegrind` to be reasonably CI-stable. + +use std::hint::black_box; + +use iai_callgrind::{library_benchmark, library_benchmark_group, main}; +use libm_test::gen::spaced; +use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, OpRustArgs, TupleCall, op}; + +const BENCH_ITER_ITEMS: u64 = 500; + +macro_rules! icount_benches { + ( + fn_name: $fn_name:ident, + attrs: [$($_attr:meta),*], + ) => { + paste::paste! { + // Construct benchmark inputs from the logspace generator. + fn [< setup_ $fn_name >]() -> Vec> { + type Op = op::$fn_name::Routine; + let mut ctx = CheckCtx::new( + Op::IDENTIFIER, + CheckBasis::None, + GeneratorKind::QuickSpaced + ); + ctx.override_iterations(BENCH_ITER_ITEMS); + let ret = spaced::get_test_cases::(&ctx).0.collect::>(); + println!("operation {}, {} steps", Op::NAME, ret.len()); + ret + } + + // Run benchmarks with the above inputs. + #[library_benchmark] + #[bench::logspace([< setup_ $fn_name >]())] + fn [< icount_bench_ $fn_name >](cases: Vec>) { + type Op = op::$fn_name::Routine; + let f = black_box(Op::ROUTINE); + for input in cases.iter().copied() { + input.call(f); + } + } + + library_benchmark_group!( + name = [< icount_bench_ $fn_name _group >]; + benchmarks = [< icount_bench_ $fn_name >] + ); + } + }; +} + +libm_macros::for_each_function! { + callback: icount_benches, +} + +main!( + library_benchmark_groups = icount_bench_acos_group, + icount_bench_acosf_group, + icount_bench_acosh_group, + icount_bench_acoshf_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_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_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_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_floorf_group, + icount_bench_fma_group, + icount_bench_fmaf_group, + icount_bench_fmax_group, + icount_bench_fmaxf_group, + icount_bench_fmin_group, + icount_bench_fminf_group, + icount_bench_fmod_group, + icount_bench_fmodf_group, + icount_bench_frexp_group, + icount_bench_frexpf_group, + icount_bench_hypot_group, + icount_bench_hypotf_group, + icount_bench_ilogb_group, + icount_bench_ilogbf_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_ldexpf_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_modf_group, + icount_bench_modff_group, + icount_bench_nextafter_group, + icount_bench_nextafterf_group, + icount_bench_pow_group, + icount_bench_powf_group, + icount_bench_remainder_group, + icount_bench_remainderf_group, + icount_bench_remquo_group, + icount_bench_remquof_group, + icount_bench_rint_group, + icount_bench_rintf_group, + icount_bench_round_group, + icount_bench_roundf_group, + icount_bench_scalbn_group, + icount_bench_scalbnf_group, + icount_bench_sin_group, + icount_bench_sinf_group, + icount_bench_sinh_group, + icount_bench_sinhf_group, + icount_bench_sqrt_group, + icount_bench_sqrtf_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_trunc_group, + icount_bench_truncf128_group, + icount_bench_truncf16_group, + icount_bench_truncf_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, +); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index cb89f1c8ba7f7..b90423c1bacce 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -24,7 +24,8 @@ pub use f8_impl::f8; 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, OpRustFn, OpRustRet, Ty, + BaseName, FloatTy, Identifier, MathOp, OpCFn, OpCRet, OpFTy, OpRustArgs, OpRustFn, OpRustRet, + Ty, }; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; use run_cfg::EXTENSIVE_MAX_ITERATIONS; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/op.rs b/library/compiler-builtins/libm/crates/libm-test/src/op.rs index 8329d3424c324..239c9a3e1fdfa 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/op.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/op.rs @@ -100,6 +100,8 @@ pub type OpCFn = ::CFn; pub type OpCRet = ::CRet; /// Access the associated `RustFn` type from an op (helper to avoid ambiguous associated types). pub type OpRustFn = ::RustFn; +/// Access the associated `RustArgs` type from an op (helper to avoid ambiguous associated types). +pub type OpRustArgs = ::RustArgs; /// Access the associated `RustRet` type from an op (helper to avoid ambiguous associated types). pub type OpRustRet = ::RustRet; From cdb1e680e03bf1ec9330c0951a8ee328f6a272b6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 16 Jan 2025 07:31:34 +0000 Subject: [PATCH 1574/4206] Run iai-callgrind benchmarks in CI Add support in `ci-util.py` for finding the most recent baseline and downloading it, which new tests can then be compared against. Arbitrarily select nightly-2025-01-16 as the rustc version to pin to in benchmarks. --- .../libm/.github/workflows/main.yaml | 58 ++++++- library/compiler-builtins/libm/ci/ci-util.py | 159 +++++++++++++++++- 2 files changed, 207 insertions(+), 10 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index 99a32a82ec1d8..9face93110b15 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -10,6 +10,7 @@ env: RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings RUST_BACKTRACE: full + BENCHMARK_RUSTC: nightly-2025-01-16 # Pin the toolchain for reproducable results jobs: test: @@ -147,19 +148,70 @@ jobs: benchmarks: name: Benchmarks runs-on: ubuntu-24.04 + timeout-minutes: 20 steps: - uses: actions/checkout@master - - name: Install Rust - run: rustup update nightly --no-self-update && rustup default nightly + - uses: taiki-e/install-action@cargo-binstall + + - name: Set up dependencies + run: | + rustup update "$BENCHMARK_RUSTC" --no-self-update + rustup default "$BENCHMARK_RUSTC" + # Install the version of iai-callgrind-runner that is specified in Cargo.toml + iai_version="$(cargo metadata --format-version=1 --features icount | + jq -r '.packages[] | select(.name == "iai-callgrind").version')" + cargo binstall -y iai-callgrind-runner --version "$iai_version" + sudo apt-get install valgrind + - uses: Swatinem/rust-cache@v2 - name: Download musl source run: ./ci/download-musl.sh - - run: | + + - name: Run icount benchmarks + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -eux + iai_home="iai-home" + # Download the baseline from master + ./ci/ci-util.py locate-baseline --download --extract + + # Run iai-callgrind benchmarks + cargo bench --no-default-features \ + --features unstable,unstable-float,icount \ + --bench icount \ + -- \ + --save-baseline=default \ + --home "$(pwd)/$iai_home" \ + --regression='ir=5.0' \ + --save-summary + # NB: iai-callgrind should exit on error but does not, so we inspect the sumary + # for errors. See https://github.com/iai-callgrind/iai-callgrind/issues/337 + ./ci/ci-util.py check-regressions "$iai_home" + + # Name and tar the new baseline + name="baseline-icount-$(date -u +'%Y%m%d%H%M')-${GITHUB_SHA:0:12}" + echo "BASELINE_NAME=$name" >> "$GITHUB_ENV" + tar cJf "$name.tar.xz" "$iai_home" + + - name: Upload the benchmark baseline + uses: actions/upload-artifact@v4 + with: + name: ${{ env.BASELINE_NAME }} + path: ${{ env.BASELINE_NAME }}.tar.xz + + - name: Run wall time benchmarks + run: | # Always use the same seed for benchmarks. Ideally we should switch to a # non-random generator. export LIBM_SEED=benchesbenchesbenchesbencheswoo! cargo bench --all --features libm-test/short-benchmarks,libm-test/build-musl + - name: Print test logs if available + if: always() + run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi + shell: bash + msrv: name: Check MSRV runs-on: ubuntu-24.04 diff --git a/library/compiler-builtins/libm/ci/ci-util.py b/library/compiler-builtins/libm/ci/ci-util.py index 733ec26fa33c3..1ec69b002aed0 100755 --- a/library/compiler-builtins/libm/ci/ci-util.py +++ b/library/compiler-builtins/libm/ci/ci-util.py @@ -9,6 +9,7 @@ import subprocess as sp import sys from dataclasses import dataclass +from glob import glob, iglob from inspect import cleandoc from os import getenv from pathlib import Path @@ -18,16 +19,33 @@ """ usage: - ./ci/ci-util.py + ./ci/ci-util.py [flags] - SUBCOMMAND: - generate-matrix Calculate a matrix of which functions had source change, - print that as JSON object. + COMMAND: + generate-matrix + Calculate a matrix of which functions had source change, print that as + a JSON object. + + locate-baseline [--download] [--extract] + Locate the most recent benchmark baseline available in CI and, if flags + specify, download and extract it. Never exits with nonzero status if + downloading fails. + + Note that `--extract` will overwrite files in `iai-home`. + + check-regressions [iai-home] + Check `iai-home` (or `iai-home` if unspecified) for `summary.json` + files and see if there are any regressions. This is used as a workaround + for `iai-callgrind` not exiting with error status; see + . """ ) REPO_ROOT = Path(__file__).parent.parent GIT = ["git", "-C", REPO_ROOT] +DEFAULT_BRANCH = "master" +WORKFLOW_NAME = "CI" # Workflow that generates the benchmark artifacts +ARTIFACT_GLOB = "baseline-icount*" # Don't run exhaustive tests if these files change, even if they contaiin a function # definition. @@ -40,6 +58,11 @@ TYPES = ["f16", "f32", "f64", "f128"] +def eprint(*args, **kwargs): + """Print to stderr.""" + print(*args, file=sys.stderr, **kwargs) + + class FunctionDef(TypedDict): """Type for an entry in `function-definitions.json`""" @@ -145,9 +168,125 @@ def make_workflow_output(self) -> str: return output -def eprint(*args, **kwargs): - """Print to stderr.""" - print(*args, file=sys.stderr, **kwargs) +def locate_baseline(flags: list[str]) -> None: + """Find the most recent baseline from CI, download it if specified. + + This returns rather than erroring, even if the `gh` commands fail. This is to avoid + erroring in CI if the baseline is unavailable (artifact time limit exceeded, first + run on the branch, etc). + """ + + download = False + extract = False + + while len(flags) > 0: + match flags[0]: + case "--download": + download = True + case "--extract": + extract = True + case _: + eprint(USAGE) + exit(1) + flags = flags[1:] + + if extract and not download: + eprint("cannot extract without downloading") + exit(1) + + try: + # Locate the most recent job to complete with success on our branch + latest_job = sp.check_output( + [ + "gh", + "run", + "list", + "--limit=1", + "--status=success", + f"--branch={DEFAULT_BRANCH}", + "--json=databaseId,url,headSha,conclusion,createdAt," + "status,workflowDatabaseId,workflowName", + f'--jq=select(.[].workflowName == "{WORKFLOW_NAME}")', + ], + text=True, + ) + eprint(f"latest: '{latest_job}'") + except sp.CalledProcessError as e: + eprint(f"failed to run github command: {e}") + return + + try: + latest = json.loads(latest_job)[0] + eprint("latest job: ", json.dumps(latest, indent=4)) + except json.JSONDecodeError as e: + eprint(f"failed to decode json '{latest_job}', {e}") + return + + if not download: + eprint("--download not specified, returning") + return + + job_id = latest.get("databaseId") + if job_id is None: + eprint("skipping download step") + return + + sp.run( + ["gh", "run", "download", str(job_id), f"--pattern={ARTIFACT_GLOB}"], + check=False, + ) + + if not extract: + eprint("skipping extraction step") + return + + # Find the baseline with the most recent timestamp. GH downloads the files to e.g. + # `some-dirname/some-dirname.tar.xz`, so just glob the whole thing together. + candidate_baselines = glob(f"{ARTIFACT_GLOB}/{ARTIFACT_GLOB}") + if len(candidate_baselines) == 0: + eprint("no possible baseline directories found") + return + + candidate_baselines.sort(reverse=True) + baseline_archive = candidate_baselines[0] + eprint(f"extracting {baseline_archive}") + sp.run(["tar", "xJvf", baseline_archive], check=True) + eprint("baseline extracted successfully") + + +def check_iai_regressions(iai_home: str | None | Path): + """Find regressions in iai summary.json files, exit with failure if any are + found. + """ + if iai_home is None: + iai_home = "iai-home" + iai_home = Path(iai_home) + + found_summaries = False + regressions = [] + for summary_path in iglob("**/summary.json", root_dir=iai_home, recursive=True): + found_summaries = True + with open(iai_home / summary_path, "r") as f: + summary = json.load(f) + + summary_regs = [] + run = summary["callgrind_summary"]["callgrind_run"] + name_entry = {"name": f"{summary["function_name"]}.{summary["id"]}"} + + for segment in run["segments"]: + summary_regs.extend(segment["regressions"]) + + summary_regs.extend(run["total"]["regressions"]) + + regressions.extend(name_entry | reg for reg in summary_regs) + + if not found_summaries: + eprint(f"did not find any summary.json files within {iai_home}") + exit(1) + + if len(regressions) > 0: + eprint("Found regressions:", json.dumps(regressions, indent=4)) + exit(1) def main(): @@ -156,6 +295,12 @@ def main(): ctx = Context() output = ctx.make_workflow_output() print(f"matrix={output}") + case ["locate-baseline", *flags]: + locate_baseline(flags) + case ["check-regressions"]: + check_iai_regressions(None) + case ["check-regressions", iai_home]: + check_iai_regressions(iai_home) case ["--help" | "-h"]: print(USAGE) exit() From 5139ba6f46923dc673a7449c09d396cba2a6eba6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 16 Jan 2025 07:31:07 +0000 Subject: [PATCH 1575/4206] Reduce the warm up and measurement time for `short-benchmarks` The icount benchmarks are what we will be relying on in CI more than the existing benchmarks. There isn't much reason to keep these around, but there isn't much point in dropping them either. So, just reduce the runtime. --- .../compiler-builtins/libm/crates/libm-test/benches/random.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index dcc7c1acac36f..8881612651004 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -151,8 +151,8 @@ pub fn musl_random() { // about the same time as other tests. if cfg!(feature = "short-benchmarks") { criterion = criterion - .warm_up_time(Duration::from_millis(500)) - .measurement_time(Duration::from_millis(1000)); + .warm_up_time(Duration::from_millis(200)) + .measurement_time(Duration::from_millis(600)); } criterion = criterion.configure_from_args(); From 3986206ce0f601d747953333bc82b836820443e9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 16 Jan 2025 09:47:00 +0000 Subject: [PATCH 1576/4206] Add an xfail for recent ynf failures This failed a couple of times recently in CI, once on i686 and once on aarch64-apple: thread 'main' panicked at crates/libm-test/benches/random.rs:76:65: called `Result::unwrap()` on an `Err` value: ynf Caused by: 0: input: (681, 509.90924) (0x000002a9, 0x43fef462) expected: -3.2161271e38 0xff71f45b actual: -inf 0xff800000 1: mismatched infinities thread 'main' panicked at crates/libm-test/benches/random.rs:76:65: called `Result::unwrap()` on an `Err` value: ynf Caused by: 0: input: (132, 50.46604) (0x00000084, 0x4249dd3a) expected: -3.3364996e38 0xff7b02a5 actual: -inf 0xff800000 1: mismatched infinities Add a new override to account for this. --- .../libm/crates/libm-test/src/precision.rs | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 3cb5e420f2601..9d17ab8cccfd3 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -4,6 +4,7 @@ use core::f32; use CheckBasis::{Mpfr, Musl}; +use libm::support::CastFrom; use {BaseName as Bn, Identifier as Id}; use crate::{BaseName, CheckBasis, CheckCtx, Float, Identifier, Int, TestResult}; @@ -524,7 +525,7 @@ impl MaybeOverride<(i32, f32)> for SpecialCase { ctx: &CheckCtx, ) -> Option { match (&ctx.basis, ctx.base_name) { - (Musl, _) => bessel_prec_dropoff(input, ulp, ctx), + (Musl, _) => bessel_prec_dropoff(input, actual, expected, ulp, ctx), // We return +0.0, MPFR returns -0.0 (Mpfr, BaseName::Jn | BaseName::Yn) @@ -554,7 +555,7 @@ impl MaybeOverride<(i32, f64)> for SpecialCase { ctx: &CheckCtx, ) -> Option { match (&ctx.basis, ctx.base_name) { - (Musl, _) => bessel_prec_dropoff(input, ulp, ctx), + (Musl, _) => bessel_prec_dropoff(input, actual, expected, ulp, ctx), // We return +0.0, MPFR returns -0.0 (Mpfr, BaseName::Jn | BaseName::Yn) @@ -569,8 +570,10 @@ impl MaybeOverride<(i32, f64)> for SpecialCase { } /// Our bessel functions blow up with large N values -fn bessel_prec_dropoff( - input: (i32, F), +fn bessel_prec_dropoff( + input: (i32, F1), + actual: F2, + expected: F2, ulp: &mut u32, ctx: &CheckCtx, ) -> Option { @@ -585,6 +588,17 @@ fn bessel_prec_dropoff( } } + // Values near infinity sometimes get cut off for us. `ynf(681, 509.90924) = -inf` but should + // be -3.2161271e38. + if ctx.fn_ident == Identifier::Ynf + && !expected.is_infinite() + && actual.is_infinite() + && (expected.abs().to_bits().abs_diff(actual.abs().to_bits()) + < F2::Int::cast_from(1_000_000u32)) + { + return XFAIL; + } + None } From f39af6cb976ce8e3bd92ae543c21a5f6527081e2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 16 Jan 2025 20:30:47 +0000 Subject: [PATCH 1577/4206] Remove the limit for querying a baseline `--limit=1` seems to apply before `jq` filtering, meaning our `WORKFLOW_NAME` ("CI") workflow may not appear in the input to the jq query. Removing `--limit` provides a default amount of inputs that jq can then filter from, so this works better. --- library/compiler-builtins/libm/ci/ci-util.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/ci/ci-util.py b/library/compiler-builtins/libm/ci/ci-util.py index 1ec69b002aed0..7a9f1bd2bbec1 100755 --- a/library/compiler-builtins/libm/ci/ci-util.py +++ b/library/compiler-builtins/libm/ci/ci-util.py @@ -201,22 +201,24 @@ def locate_baseline(flags: list[str]) -> None: "gh", "run", "list", - "--limit=1", "--status=success", f"--branch={DEFAULT_BRANCH}", "--json=databaseId,url,headSha,conclusion,createdAt," "status,workflowDatabaseId,workflowName", - f'--jq=select(.[].workflowName == "{WORKFLOW_NAME}")', + # Return the first array element matching our workflow name. NB: cannot + # just use `--limit=1`, jq filtering happens after limiting. We also + # cannot just use `--workflow` because GH gets confused from + # different file names in history. + f'--jq=[.[] | select(.workflowName == "{WORKFLOW_NAME}")][0]', ], text=True, ) - eprint(f"latest: '{latest_job}'") except sp.CalledProcessError as e: eprint(f"failed to run github command: {e}") return try: - latest = json.loads(latest_job)[0] + latest = json.loads(latest_job) eprint("latest job: ", json.dumps(latest, indent=4)) except json.JSONDecodeError as e: eprint(f"failed to decode json '{latest_job}', {e}") From f9041943f1c5c2cc83b0c781ff0b48ba6301927f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 16 Jan 2025 19:50:29 +0000 Subject: [PATCH 1578/4206] Switch to the arm-linux runner and enable MPFR The free arm64 Linux runners are now available [1]. Switch to using this image in CI, and enable tests against MPFR since this is now a native platform. [1]: https://github.blog/changelog/2025-01-16-linux-arm64-hosted-runners-now-available-for-free-in-public-repositories-public-preview/ --- .../libm/.github/workflows/main.yaml | 2 +- library/compiler-builtins/libm/ci/run.sh | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index 9face93110b15..8c0ff237d2fec 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -23,7 +23,7 @@ jobs: - target: aarch64-apple-darwin os: macos-15 - target: aarch64-unknown-linux-gnu - os: ubuntu-24.04 + os: ubuntu-24.04-arm - target: aarch64-pc-windows-msvc os: windows-2025 build_only: 1 # Can't run on x86 hosts diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index bb749b72ad339..6b2f07ab283a1 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -49,14 +49,12 @@ case "$target" in *windows-msvc*) ;; # FIXME: MinGW should be able to build MPFR, but setup in CI is nontrivial. *windows-gnu*) ;; - # Targets that aren't cross compiled work fine - # FIXME(ci): we should be able to enable aarch64 Linux here once GHA - # support rolls out. - x86_64*) flags="$flags --features libm-test/build-mpfr" ;; - i686*) flags="$flags --features libm-test/build-mpfr" ;; - i586*) flags="$flags --features libm-test/build-mpfr --features gmp-mpfr-sys/force-cross" ;; - # Apple aarch64 is native + # Targets that aren't cross compiled in CI work fine aarch64*apple*) flags="$flags --features libm-test/build-mpfr" ;; + aarch64*linux*) flags="$flags --features libm-test/build-mpfr" ;; + i586*) flags="$flags --features libm-test/build-mpfr --features gmp-mpfr-sys/force-cross" ;; + i686*) flags="$flags --features libm-test/build-mpfr" ;; + x86_64*) flags="$flags --features libm-test/build-mpfr" ;; esac # FIXME: `STATUS_DLL_NOT_FOUND` testing macros on CI. From ba0cfe58dd1fc460cbbe5d61f2aa3650d05ec16b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 21 Jan 2025 07:44:13 +0000 Subject: [PATCH 1579/4206] Run icount benchmarks once with softfloat and once with hardfloat These benchmarks are fast to run, so the time cost here is pretty minimal. Running softfloat benchmarks just ensures that we don't e.g. test the performance of `_mm_sqrt_ss` rather than our implementation, and running without softfloat gives us a way to see the effect of arch intrinsics. --- .../libm/.github/workflows/main.yaml | 24 +-------- .../compiler-builtins/libm/ci/bench-icount.sh | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+), 23 deletions(-) create mode 100755 library/compiler-builtins/libm/ci/bench-icount.sh diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index 8c0ff237d2fec..f9d3a5a159cb1 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -170,29 +170,7 @@ jobs: - name: Run icount benchmarks env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - set -eux - iai_home="iai-home" - # Download the baseline from master - ./ci/ci-util.py locate-baseline --download --extract - - # Run iai-callgrind benchmarks - cargo bench --no-default-features \ - --features unstable,unstable-float,icount \ - --bench icount \ - -- \ - --save-baseline=default \ - --home "$(pwd)/$iai_home" \ - --regression='ir=5.0' \ - --save-summary - # NB: iai-callgrind should exit on error but does not, so we inspect the sumary - # for errors. See https://github.com/iai-callgrind/iai-callgrind/issues/337 - ./ci/ci-util.py check-regressions "$iai_home" - - # Name and tar the new baseline - name="baseline-icount-$(date -u +'%Y%m%d%H%M')-${GITHUB_SHA:0:12}" - echo "BASELINE_NAME=$name" >> "$GITHUB_ENV" - tar cJf "$name.tar.xz" "$iai_home" + run: ./ci/bench-icount.sh - name: Upload the benchmark baseline uses: actions/upload-artifact@v4 diff --git a/library/compiler-builtins/libm/ci/bench-icount.sh b/library/compiler-builtins/libm/ci/bench-icount.sh new file mode 100755 index 0000000000000..40b3ac95c7bdb --- /dev/null +++ b/library/compiler-builtins/libm/ci/bench-icount.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +set -eux + +iai_home="iai-home" + +# Download the baseline from master +./ci/ci-util.py locate-baseline --download --extract + +# Run benchmarks once +function run_icount_benchmarks() { + cargo_args=( + "--bench" "icount" + "--no-default-features" + "--features" "unstable,unstable-float,icount" + ) + + iai_args=( + "--home" "$(pwd)/$iai_home" + "--regression=ir=5.0" + "--save-summary" + ) + + # Parse `cargo_arg0 cargo_arg1 -- iai_arg0 iai_arg1` syntax + parsing_iai_args=0 + while [ "$#" -gt 0 ]; do + if [ "$parsing_iai_args" == "1" ]; then + iai_args+=("$1") + elif [ "$1" == "--" ]; then + parsing_iai_args=1 + else + cargo_args+=("$1") + fi + + shift + done + + # Run iai-callgrind benchmarks + cargo bench "${cargo_args[@]}" -- "${iai_args[@]}" + + # NB: iai-callgrind should exit on error but does not, so we inspect the sumary + # for errors. See https://github.com/iai-callgrind/iai-callgrind/issues/337 + ./ci/ci-util.py check-regressions --home "$iai_home" || true +} + +# 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 + +# Name and tar the new baseline +name="baseline-icount-$(date -u +'%Y%m%d%H%M')-${GITHUB_SHA:0:12}" +echo "BASELINE_NAME=$name" >>"$GITHUB_ENV" +tar cJf "$name.tar.xz" "$iai_home" From c5dc1b8ca027d04245c2b68427f7f42e11c36e33 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 21 Jan 2025 07:45:44 +0000 Subject: [PATCH 1580/4206] Run wall time benchmarks with `--features force-soft-floats` Similar to changes for `icount` benchmarks, this ensures we aren't testing the throughput of architecture instructions. --- library/compiler-builtins/libm/.github/workflows/main.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index f9d3a5a159cb1..f019c73f8340d 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -183,7 +183,7 @@ jobs: # Always use the same seed for benchmarks. Ideally we should switch to a # non-random generator. export LIBM_SEED=benchesbenchesbenchesbencheswoo! - cargo bench --all --features libm-test/short-benchmarks,libm-test/build-musl + cargo bench --all --features short-benchmarks,build-musl,force-soft-floats - name: Print test logs if available if: always() From d3328a0dab30f5be9d896f38c87ac9824a52245b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 21 Jan 2025 07:47:41 +0000 Subject: [PATCH 1581/4206] Add a way to ignore benchmark regression checks Introduce a way to ignore the results of icount regression tests, by specifying `allow-regressions` in the pull request body. This should apply to both pull requests and the merges based on them, since `gh pr view` automatically handles both. --- .../libm/.github/workflows/main.yaml | 1 + .../compiler-builtins/libm/ci/bench-icount.sh | 7 ++- library/compiler-builtins/libm/ci/ci-util.py | 63 +++++++++++++++---- 3 files changed, 59 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index f019c73f8340d..7693de6559a12 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -170,6 +170,7 @@ jobs: - name: Run icount benchmarks env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} run: ./ci/bench-icount.sh - name: Upload the benchmark baseline diff --git a/library/compiler-builtins/libm/ci/bench-icount.sh b/library/compiler-builtins/libm/ci/bench-icount.sh index 40b3ac95c7bdb..3a2155f50113a 100755 --- a/library/compiler-builtins/libm/ci/bench-icount.sh +++ b/library/compiler-builtins/libm/ci/bench-icount.sh @@ -40,7 +40,12 @@ function run_icount_benchmarks() { # NB: iai-callgrind should exit on error but does not, so we inspect the sumary # for errors. See https://github.com/iai-callgrind/iai-callgrind/issues/337 - ./ci/ci-util.py check-regressions --home "$iai_home" || true + if [ -n "${PR_NUMBER:-}" ]; then + # If this is for a pull request, ignore regressions if specified. + ./ci/ci-util.py check-regressions --home "$iai_home" --allow-pr-override "$PR_NUMBER" + else + ./ci/ci-util.py check-regressions --home "$iai_home" || true + fi } # Run once with softfloats, once with arch instructions enabled diff --git a/library/compiler-builtins/libm/ci/ci-util.py b/library/compiler-builtins/libm/ci/ci-util.py index 7a9f1bd2bbec1..7464fd42595d6 100755 --- a/library/compiler-builtins/libm/ci/ci-util.py +++ b/library/compiler-builtins/libm/ci/ci-util.py @@ -33,11 +33,14 @@ Note that `--extract` will overwrite files in `iai-home`. - check-regressions [iai-home] + check-regressions [--home iai-home] [--allow-pr-override pr_number] Check `iai-home` (or `iai-home` if unspecified) for `summary.json` files and see if there are any regressions. This is used as a workaround for `iai-callgrind` not exiting with error status; see . + + If `--allow-pr-override` is specified, the regression check will not exit + with failure if any line in the PR starts with `allow-regressions`. """ ) @@ -46,6 +49,8 @@ DEFAULT_BRANCH = "master" WORKFLOW_NAME = "CI" # Workflow that generates the benchmark artifacts ARTIFACT_GLOB = "baseline-icount*" +# Place this in a PR body to skip regression checks (must be at the start of a line). +REGRESSION_DIRECTIVE = "ci: allow-regressions" # Don't run exhaustive tests if these files change, even if they contaiin a function # definition. @@ -256,12 +261,26 @@ def locate_baseline(flags: list[str]) -> None: eprint("baseline extracted successfully") -def check_iai_regressions(iai_home: str | None | Path): +def check_iai_regressions(args: list[str]): """Find regressions in iai summary.json files, exit with failure if any are found. """ - if iai_home is None: - iai_home = "iai-home" + + iai_home = "iai-home" + pr_number = False + + while len(args) > 0: + match args: + case ["--home", home, *rest]: + iai_home = home + args = rest + case ["--allow-pr-override", pr_num, *rest]: + pr_number = pr_num + args = rest + case _: + eprint(USAGE) + exit(1) + iai_home = Path(iai_home) found_summaries = False @@ -286,9 +305,33 @@ def check_iai_regressions(iai_home: str | None | Path): eprint(f"did not find any summary.json files within {iai_home}") exit(1) - if len(regressions) > 0: - eprint("Found regressions:", json.dumps(regressions, indent=4)) - exit(1) + if len(regressions) == 0: + eprint("No regressions found") + return + + eprint("Found regressions:", json.dumps(regressions, indent=4)) + + if pr_number is not None: + pr_info = sp.check_output( + [ + "gh", + "pr", + "view", + str(pr_number), + "--json=number,commits,body,createdAt", + "--jq=.commits |= map(.oid)", + ], + text=True, + ) + pr = json.loads(pr_info) + eprint("PR info:", json.dumps(pr, indent=4)) + + lines = pr["body"].splitlines() + if any(line.startswith(REGRESSION_DIRECTIVE) for line in lines): + eprint("PR allows regressions, returning") + return + + exit(1) def main(): @@ -299,10 +342,8 @@ def main(): print(f"matrix={output}") case ["locate-baseline", *flags]: locate_baseline(flags) - case ["check-regressions"]: - check_iai_regressions(None) - case ["check-regressions", iai_home]: - check_iai_regressions(iai_home) + case ["check-regressions", *args]: + check_iai_regressions(args) case ["--help" | "-h"]: print(USAGE) exit() From e21618c73e9c1a05aa4d5c75a3d144960d43158b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 21 Jan 2025 07:52:26 +0000 Subject: [PATCH 1582/4206] Ignore files relevant to benchmarking --- library/compiler-builtins/libm/.gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/libm/.gitignore b/library/compiler-builtins/libm/.gitignore index 4e9c9c03ddf3d..a447c34cd0f63 100644 --- a/library/compiler-builtins/libm/.gitignore +++ b/library/compiler-builtins/libm/.gitignore @@ -6,3 +6,7 @@ target Cargo.lock musl/ **.tar.gz + +# Benchmark cache +iai-home +baseline-* From b3d57f8c28da068201f64b26243f962390fcf3c9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 22 Jan 2025 00:58:33 +0000 Subject: [PATCH 1583/4206] Remove trailing whitespace in scripts, run JuliaFormatter --- .../compiler-builtins/libm/ci/bench-icount.sh | 2 +- library/compiler-builtins/libm/ci/run.sh | 4 +- .../crates/libm-test/examples/plot_file.jl | 52 ++++++++++++------- 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/library/compiler-builtins/libm/ci/bench-icount.sh b/library/compiler-builtins/libm/ci/bench-icount.sh index 3a2155f50113a..4d93e257a6cb0 100755 --- a/library/compiler-builtins/libm/ci/bench-icount.sh +++ b/library/compiler-builtins/libm/ci/bench-icount.sh @@ -7,7 +7,7 @@ iai_home="iai-home" # Download the baseline from master ./ci/ci-util.py locate-baseline --download --extract -# Run benchmarks once +# Run benchmarks once function run_icount_benchmarks() { cargo_args=( "--bench" "icount" diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 6b2f07ab283a1..296986d972716 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -90,7 +90,7 @@ if [ "$nextest" = "1" ]; then echo "dir = \"$CARGO_TARGET_DIR/nextest\"" >> "$cfg_file" cfg_flag="--config-file $cfg_file" fi - + cmd="cargo nextest run ${cfg_flag:-} --max-fail=10 $flags" profile="--cargo-profile" fi @@ -111,7 +111,7 @@ $cmd --features unstable-intrinsics --benches # Test the same in release mode, which also increases coverage. Also ensure # the soft float routines are checked. -$cmd "$profile" release-checked +$cmd "$profile" release-checked $cmd "$profile" release-checked --features force-soft-floats $cmd "$profile" release-checked --features unstable-intrinsics $cmd "$profile" release-checked --features unstable-intrinsics --benches diff --git a/library/compiler-builtins/libm/crates/libm-test/examples/plot_file.jl b/library/compiler-builtins/libm/crates/libm-test/examples/plot_file.jl index 14a128303c696..acffd97569f5c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/examples/plot_file.jl +++ b/library/compiler-builtins/libm/crates/libm-test/examples/plot_file.jl @@ -13,7 +13,7 @@ using CairoMakie using TOML function main()::Nothing - CairoMakie.activate!(px_per_unit=10) + CairoMakie.activate!(px_per_unit = 10) config_path = ARGS[1] cfg = Dict() @@ -75,15 +75,25 @@ function plot_one( gen_x = map((v) -> parse(Float32, v), inputs) do_plot( - fig, gen_x, func, xlims[1], xlims[2], + fig, + gen_x, + func, + xlims[1], + xlims[2], "$fn_name $gen_name (linear scale)", - lin_out_file, false, + lin_out_file, + false, ) do_plot( - fig, gen_x, func, xlims_log[1], xlims_log[2], + fig, + gen_x, + func, + xlims_log[1], + xlims_log[2], "$fn_name $gen_name (log scale)", - log_out_file, true, + log_out_file, + true, ) end @@ -97,7 +107,7 @@ function do_plot( title::String, out_file::String, logscale::Bool, -)::Nothing where F<:AbstractFloat +)::Nothing where {F<:AbstractFloat} println("plotting $title") # `gen_x` is the values the generator produces. `actual_x` is for plotting a @@ -116,32 +126,36 @@ function do_plot( actual_x = LinRange(input_min, input_max, steps) xscale = identity end - + gen_y = @. func(gen_x) actual_y = @. func(actual_x) - ax = Axis(fig[1, 1], xscale=xscale, title=title) + ax = Axis(fig[1, 1], xscale = xscale, title = title) lines!( - ax, actual_x, actual_y, color=(:lightblue, 0.6), - linewidth=6.0, label="true function", + ax, + actual_x, + actual_y, + color = (:lightblue, 0.6), + linewidth = 6.0, + label = "true function", ) scatter!( - ax, gen_x, gen_y, color=(:darkblue, 0.9), - markersize=markersize, label="checked inputs", + ax, + gen_x, + gen_y, + color = (:darkblue, 0.9), + markersize = markersize, + label = "checked inputs", ) - axislegend(ax, position=:rb, framevisible=false) + axislegend(ax, position = :rb, framevisible = false) save(out_file, fig) delete!(ax) end "Apply a function, returning the default if there is a domain error" -function map_or( - input::AbstractFloat, - f::Function, - default::Any -)::Union{AbstractFloat,Any} +function map_or(input::AbstractFloat, f::Function, default::Any)::Union{AbstractFloat,Any} try return f(input) catch @@ -151,7 +165,7 @@ end # Operations for logarithms that are symmetric about 0 C = 10 -symlog10(x::Number) = sign(x) * (log10(1 + abs(x)/(10^C))) +symlog10(x::Number) = sign(x) * (log10(1 + abs(x) / (10^C))) sympow10(x::Number) = (10^C) * (10^x - 1) main() From 6ac9c14933a363a4a31bc8425d63b68df1fce364 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 22 Jan 2025 02:35:29 +0000 Subject: [PATCH 1584/4206] Add a retry to the musl download This download has occasionally been failing in CI recently. Add a retry so this is less likely to cause the workflow to fail. --- library/compiler-builtins/libm/ci/download-musl.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/ci/download-musl.sh b/library/compiler-builtins/libm/ci/download-musl.sh index 039e961575bde..8a8c58550bb47 100755 --- a/library/compiler-builtins/libm/ci/download-musl.sh +++ b/library/compiler-builtins/libm/ci/download-musl.sh @@ -7,7 +7,7 @@ fname=musl-1.2.5.tar.gz sha=a9a118bbe84d8764da0ea0d28b3ab3fae8477fc7e4085d90102b8596fc7c75e4 mkdir musl -curl -L "https://musl.libc.org/releases/$fname" -O +curl -L "https://musl.libc.org/releases/$fname" -O --retry 5 case "$(uname -s)" in MINGW*) From 9c98c461473a26354c519702d79a689dda7f9645 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 15 Jan 2025 11:34:17 +0000 Subject: [PATCH 1585/4206] Don't set `opt_level` in the musl build script `cc` automatically reads this from Cargo's `OPT_LEVEL` variable so we don't need to set it explicitly. Remove this so running in a debugger makes more sense. --- library/compiler-builtins/libm/crates/musl-math-sys/build.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/build.rs b/library/compiler-builtins/libm/crates/musl-math-sys/build.rs index 03deb4ff0ac03..d75748159cad5 100644 --- a/library/compiler-builtins/libm/crates/musl-math-sys/build.rs +++ b/library/compiler-builtins/libm/crates/musl-math-sys/build.rs @@ -151,7 +151,6 @@ fn build_musl_math(cfg: &Config) { .flag_if_supported("-ffreestanding") .flag_if_supported("-nostdinc") .define("_ALL_SOURCE", "1") - .opt_level(3) .define( "ROOT_INCLUDE_FEATURES", Some(musl_dir.join("include/features.h").to_str().unwrap()), From 8927014e919b789ef957d82ed13eaebe33922e29 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 22 Jan 2025 05:29:36 +0000 Subject: [PATCH 1586/4206] Enable `force-soft-floats` for extensive tests Any architecture-specific float operations are likely to consist of only a few instructions, but the softfloat implementations are much more complex. Ensure this is what gets tested. --- library/compiler-builtins/libm/.github/workflows/main.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index 7693de6559a12..89c5facef44da 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -270,7 +270,7 @@ jobs: fi LIBM_EXTENSIVE_TESTS="$CHANGED" cargo t \ - --features build-mpfr,unstable \ + --features build-mpfr,unstable,force-soft-floats \ --profile release-checked \ -- extensive - name: Print test logs if available From 573ded2ee8a59d3f3bb2a56477fc939b0922cf44 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 12 Jan 2025 11:45:40 +0000 Subject: [PATCH 1587/4206] Port the most recent version of Musl's `sqrt` as a generic algorithm Musl commit 97e9b73d59 ("math: new software sqrt") adds a new algorithm using Goldschmidt division. Port this algorithm to Rust and make it generic, which shows a notable performance improvement over the existing algorithm. This also allows adding square root routines for `f16` and `f128`. --- .../libm/etc/function-definitions.json | 2 + .../libm/src/math/generic/mod.rs | 2 + .../libm/src/math/generic/sqrt.rs | 419 ++++++++++++++++++ .../compiler-builtins/libm/src/math/sqrt.rs | 252 +---------- .../compiler-builtins/libm/src/math/sqrtf.rs | 133 +----- .../libm/src/math/support/int_traits.rs | 2 + .../libm/src/math/support/macros.rs | 22 +- .../libm/src/math/support/mod.rs | 11 + 8 files changed, 450 insertions(+), 393 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/sqrt.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index dbaac931c7697..9f7c8ab25a033 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -704,6 +704,7 @@ "src/libm_helper.rs", "src/math/arch/i686.rs", "src/math/arch/wasm32.rs", + "src/math/generic/sqrt.rs", "src/math/sqrt.rs" ], "type": "f64" @@ -712,6 +713,7 @@ "sources": [ "src/math/arch/i686.rs", "src/math/arch/wasm32.rs", + "src/math/generic/sqrt.rs", "src/math/sqrtf.rs" ], "type": "f32" diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index 2b068d6c54d34..3b5a2c3effd7d 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -1,9 +1,11 @@ mod copysign; mod fabs; mod fdim; +mod sqrt; mod trunc; pub use copysign::copysign; pub use fabs::fabs; pub use fdim::fdim; +pub use sqrt::sqrt; pub use trunc::trunc; diff --git a/library/compiler-builtins/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/src/math/generic/sqrt.rs new file mode 100644 index 0000000000000..a2e054f3cf2b7 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/sqrt.rs @@ -0,0 +1,419 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/sqrt.c. Ported to generic Rust algorithm in 2025, TG. */ + +//! Generic square root algorithm. +//! +//! This routine operates around `m_u2`, a U.2 (fixed point with two integral bits) mantissa +//! within the range [1, 4). A table lookup provides an initial estimate, then goldschmidt +//! iterations at various widths are used to approach the real values. +//! +//! For the iterations, `r` is a U0 number that approaches `1/sqrt(m_u2)`, and `s` is a U2 number +//! that approaches `sqrt(m_u2)`. Recall that m_u2 ∈ [1, 4). +//! +//! With Newton-Raphson iterations, this would be: +//! +//! - `w = r * r w ~ 1 / m` +//! - `u = 3 - m * w u ~ 3 - m * w = 3 - m / m = 2` +//! - `r = r * u / 2 r ~ r` +//! +//! (Note that the righthand column does not show anything analytically meaningful (i.e. r ~ r), +//! since the value of performing one iteration is in reducing the error representable by `~`). +//! +//! Instead of Newton-Raphson iterations, Goldschmidt iterations are used to calculate +//! `s = m * r`: +//! +//! - `s = m * r s ~ m / sqrt(m)` +//! - `u = 3 - s * r u ~ 3 - (m / sqrt(m)) * (1 / sqrt(m)) = 3 - m / m = 2` +//! - `r = r * u / 2 r ~ r` +//! - `s = s * u / 2 s ~ s` +//! +//! The above is precise because it uses the original value `m`. There is also a faster version +//! that performs fewer steps but does not use `m`: +//! +//! - `u = 3 - s * r u ~ 3 - 1` +//! - `r = r * u / 2 r ~ r` +//! - `s = s * u / 2 s ~ s` +//! +//! Rounding errors accumulate faster with the second version, so it is only used for subsequent +//! iterations within the same width integer. The first version is always used for the first +//! iteration at a new width in order to avoid this accumulation. +//! +//! Goldschmidt has the advantage over Newton-Raphson that `sqrt(x)` and `1/sqrt(x)` are +//! computed at the same time, i.e. there is no need to calculate `1/sqrt(x)` and invert it. + +use super::super::support::{IntTy, cold_path, raise_invalid}; +use super::super::{CastFrom, CastInto, DInt, Float, HInt, Int, MinInt}; + +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, +{ + let zero = IntTy::::ZERO; + let one = IntTy::::ONE; + + let mut ix = x.to_bits(); + + // Top is the exponent and sign, which may or may not be shifted. If the float fits into a + // `u32`, we can get by without paying shifting costs. + let noshift = F::BITS <= u32::BITS; + let (mut top, special_case) = if noshift { + let exp_lsb = one << F::SIG_BITS; + let special_case = ix.wrapping_sub(exp_lsb) >= F::EXP_MASK - exp_lsb; + (Exp::NoShift(()), special_case) + } else { + let top = u32::cast_from(ix >> F::SIG_BITS); + let special_case = top.wrapping_sub(1) >= F::EXP_MAX - 1; + (Exp::Shifted(top), special_case) + }; + + // Handle NaN, zero, and out of domain (<= 0) + if special_case { + cold_path(); + + // +/-0 + if ix << 1 == zero { + return x; + } + + // Positive infinity + if ix == F::EXP_MASK { + return x; + } + + // NaN or negative + if ix > F::EXP_MASK { + return raise_invalid(x); + } + + // Normalize subnormals by multiplying by 1.0 << SIG_BITS (e.g. 0x1p52 for doubles). + let scaled = x * F::from_parts(false, (F::SIG_BITS + F::EXP_BIAS) as i32, zero); + ix = scaled.to_bits(); + match top { + Exp::Shifted(ref mut v) => { + *v = scaled.exp().unsigned(); + *v = (*v).wrapping_sub(F::SIG_BITS); + } + Exp::NoShift(()) => { + ix = ix.wrapping_sub((F::SIG_BITS << F::SIG_BITS).cast()); + } + } + } + + // Reduce arguments such that `x = 4^e * m`: + // + // - m_u2 ∈ [1, 4), a fixed point U2.BITS number + // - 2^e is the exponent part of the result + let (m_u2, exp) = match top { + Exp::Shifted(top) => { + // We now know `x` is positive, so `top` is just its (biased) exponent + let mut e = top; + // Construct a fixed point representation of the mantissa. + let mut m_u2 = (ix | F::IMPLICIT_BIT) << F::EXP_BITS; + let even = (e & 1) != 0; + if even { + m_u2 >>= 1; + } + e = (e.wrapping_add(F::EXP_MAX >> 1)) >> 1; + (m_u2, Exp::Shifted(e)) + } + Exp::NoShift(()) => { + let even = ix & (one << F::SIG_BITS) != zero; + + // Exponent part of the return value + let mut e_noshift = ix >> 1; + // ey &= (F::EXP_MASK << 2) >> 2; // clear the top exponent bit (result = 1.0) + e_noshift += (F::EXP_MASK ^ (F::SIGN_MASK >> 1)) >> 1; + e_noshift &= F::EXP_MASK; + + let m1 = (ix << F::EXP_BITS) | F::SIGN_MASK; + let m0 = (ix << (F::EXP_BITS - 1)) & !F::SIGN_MASK; + let m_u2 = if even { m0 } else { m1 }; + + (m_u2, Exp::NoShift(e_noshift)) + } + }; + + // Extract the top 6 bits of the significand with the lowest bit of the exponent. + let i = usize::cast_from(ix >> (F::SIG_BITS - 6)) & 0b1111111; + + // Start with an initial guess for `r = 1 / sqrt(m)` from the table, and shift `m` as an + // initial value for `s = sqrt(m)`. See the module documentation for details. + let r1_u0: F::ISet1 = F::ISet1::cast_from(RSQRT_TAB[i]) << (F::ISet1::BITS - 16); + 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); + + // 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); + + // 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); + + // Shift back to mantissa position. + let mut m = s_u2 >> (F::EXP_BITS - 2); + + // The musl source includes the following comment (with literals replaced): + // + // > s < sqrt(m) < s + 0x1.09p-SIG_BITS + // > compute nearest rounded result: the nearest result to SIG_BITS bits is either s or + // > s+0x1p-SIG_BITS, we can decide by comparing (2^SIG_BITS s + 0.5)^2 to 2^(2*SIG_BITS) m. + // + // Expanding this with , with `SIG_BITS = p` and adjusting based on the operations done to + // `d0` and `d1`: + // + // - `2^(2p)m ≟ ((2^p)m + 0.5)^2` + // - `2^(2p)m ≟ 2^(2p)m^2 + (2^p)m + 0.25` + // - `2^(2p)m - m^2 ≟ (2^(2p) - 1)m^2 + (2^p)m + 0.25` + // - `(1 - 2^(2p))m + m^2 ≟ (1 - 2^(2p))m^2 + (1 - 2^p)m + 0.25` (?) + // + // I do not follow how the rounding bit is extracted from this comparison with the below + // operations. In any case, the algorithm is well tested. + + // The value needed to shift `m_u2` by to create `m*2^(2p)`. `2p = 2 * F::SIG_BITS`, + // `F::BITS - 2` accounts for the offset that `m_u2` already has. + let shift = 2 * F::SIG_BITS - (F::BITS - 2); + + // `2^(2p)m - m^2` + let d0 = (m_u2 << shift).wrapping_sub(m.wrapping_mul(m)); + // `m - 2^(2p)m + m^2` + let d1 = m.wrapping_sub(d0); + m += d1 >> (F::BITS - 1); + m &= F::SIG_MASK; + + match exp { + Exp::Shifted(e) => m |= IntTy::::cast_from(e) << F::SIG_BITS, + Exp::NoShift(e) => m |= e, + }; + + let mut y = F::from_bits(m); + + // FIXME(f16): the fenv math does not work for `f16` + if F::BITS > 16 { + // Handle rounding and inexact. `(m + 1)^2 == 2^shift m` is exact; for all other cases, add + // a tiny value to cause fenv effects. + let d2 = d1.wrapping_add(m).wrapping_add(one); + let mut tiny = if d2 == zero { + cold_path(); + zero + } else { + F::IMPLICIT_BIT + }; + + tiny |= (d1 ^ d2) & F::SIGN_MASK; + let t = F::from_bits(tiny); + y = y + t; + } + + y +} + +/// Multiply at the wider integer size, returning the high half. +fn wmulh(a: I, b: I) -> I { + a.widen_mul(b).hi() +} + +/// Perform `count` goldschmidt iterations, returning `(r_u0, s_u?)`. +/// +/// - `r_u0` is the reciprocal `r ~ 1 / sqrt(m)`, as U0. +/// - `s_u2` is the square root, `s ~ sqrt(m)`, as U2. +/// - `count` is the number of iterations to perform. +/// - `final_set` should be true if this is the last round (same-sized integer). If so, the +/// returned `s` will be U3, for later shifting. Otherwise, the returned `s` is U2. +/// +/// 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) +where + F: SqrtHelper, + I: HInt + From, +{ + let three_u2 = I::from(0b11u8) << (I::BITS - 2); + let mut u_u0 = r_u0; + + for i in 0..count { + // First iteration: `s = m*r` (`u_u0 = r_u0` set above) + // Subsequent iterations: `s=s*u/2` + s_u2 = wmulh(s_u2, u_u0); + + // Perform `s /= 2` if: + // + // 1. This is not the first iteration (the first iteration is `s = m*r`)... + // 2. ... and this is not the last set of iterations + // 3. ... or, if this is the last set, it is not the last iteration + // + // This step is not performed for the final iteration because the shift is combined with + // a later shift (moving `s` into the mantissa). + if i > 0 && (!final_set || i + 1 < count) { + s_u2 <<= 1; + } + + // u = 3 - s*r + let d_u2 = wmulh(s_u2, r_u0); + u_u0 = three_u2.wrapping_sub(d_u2); + + // r = r*u/2 + r_u0 = wmulh(r_u0, u_u0) << 1; + } + + (r_u0, s_u2) +} + +/// Representation of whether we shift the exponent into a `u32`, or modify it in place to save +/// the shift operations. +enum Exp { + /// The exponent has been shifted to a `u32` and is LSB-aligned. + Shifted(u32), + /// The exponent is in its natural position in integer repr. + NoShift(T), +} + +/// Size-specific constants related to the square root routine. +pub trait SqrtHelper: Float { + /// Integer for the first set of rounds. If unused, set to the same type as the next set. + type ISet1: HInt + Into + CastFrom + From; + /// Integer for the second set of rounds. If unused, set to the same type as the next set. + type ISet2: HInt + From + From; + + /// Number of rounds at `ISet1`. + const SET1_ROUNDS: u32 = 0; + /// Number of rounds at `ISet2`. + const SET2_ROUNDS: u32 = 0; + /// Number of rounds at `Self::Int`. + const FINAL_ROUNDS: u32; +} + +impl SqrtHelper for f32 { + type ISet1 = u32; // unused + type ISet2 = u32; // unused + + const FINAL_ROUNDS: u32 = 3; +} + +impl SqrtHelper for f64 { + type ISet1 = u32; // unused + type ISet2 = u32; + + const SET2_ROUNDS: u32 = 2; + const FINAL_ROUNDS: u32 = 2; +} + +/// A U0.16 representation of `1/sqrt(x)`. +/// +// / The index is a 7-bit number consisting of a single exponent bit and 6 bits of significand. +#[rustfmt::skip] +static RSQRT_TAB: [u16; 128] = [ + 0xb451, 0xb2f0, 0xb196, 0xb044, 0xaef9, 0xadb6, 0xac79, 0xab43, + 0xaa14, 0xa8eb, 0xa7c8, 0xa6aa, 0xa592, 0xa480, 0xa373, 0xa26b, + 0xa168, 0xa06a, 0x9f70, 0x9e7b, 0x9d8a, 0x9c9d, 0x9bb5, 0x9ad1, + 0x99f0, 0x9913, 0x983a, 0x9765, 0x9693, 0x95c4, 0x94f8, 0x9430, + 0x936b, 0x92a9, 0x91ea, 0x912e, 0x9075, 0x8fbe, 0x8f0a, 0x8e59, + 0x8daa, 0x8cfe, 0x8c54, 0x8bac, 0x8b07, 0x8a64, 0x89c4, 0x8925, + 0x8889, 0x87ee, 0x8756, 0x86c0, 0x862b, 0x8599, 0x8508, 0x8479, + 0x83ec, 0x8361, 0x82d8, 0x8250, 0x81c9, 0x8145, 0x80c2, 0x8040, + 0xff02, 0xfd0e, 0xfb25, 0xf947, 0xf773, 0xf5aa, 0xf3ea, 0xf234, + 0xf087, 0xeee3, 0xed47, 0xebb3, 0xea27, 0xe8a3, 0xe727, 0xe5b2, + 0xe443, 0xe2dc, 0xe17a, 0xe020, 0xdecb, 0xdd7d, 0xdc34, 0xdaf1, + 0xd9b3, 0xd87b, 0xd748, 0xd61a, 0xd4f1, 0xd3cd, 0xd2ad, 0xd192, + 0xd07b, 0xcf69, 0xce5b, 0xcd51, 0xcc4a, 0xcb48, 0xca4a, 0xc94f, + 0xc858, 0xc764, 0xc674, 0xc587, 0xc49d, 0xc3b7, 0xc2d4, 0xc1f4, + 0xc116, 0xc03c, 0xbf65, 0xbe90, 0xbdbe, 0xbcef, 0xbc23, 0xbb59, + 0xba91, 0xb9cc, 0xb90a, 0xb84a, 0xb78c, 0xb6d0, 0xb617, 0xb560, +]; + +#[cfg(test)] +mod tests { + use super::*; + + /// Test against edge cases from https://en.cppreference.com/w/cpp/numeric/math/sqrt + fn spec_test() + where + F: Float + SqrtHelper, + F::Int: HInt, + F::Int: From, + F::Int: From, + F::Int: CastInto, + F::Int: CastInto, + u32: CastInto, + { + // Not Asserted: FE_INVALID exception is raised if argument is negative. + assert!(sqrt(F::NEG_ONE).is_nan()); + assert!(sqrt(F::NAN).is_nan()); + for f in [F::ZERO, F::NEG_ZERO, F::INFINITY].iter().copied() { + assert_biteq!(sqrt(f), f); + } + } + + #[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() + ); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 2fd7070b11019..0e1d0cd2c1c96 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -1,83 +1,3 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_sqrt.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* sqrt(x) - * Return correctly rounded sqrt. - * ------------------------------------------ - * | Use the hardware sqrt if you have one | - * ------------------------------------------ - * Method: - * Bit by bit method using integer arithmetic. (Slow, but portable) - * 1. Normalization - * Scale x to y in [1,4) with even powers of 2: - * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then - * sqrt(x) = 2^k * sqrt(y) - * 2. Bit by bit computation - * Let q = sqrt(y) truncated to i bit after binary point (q = 1), - * i 0 - * i+1 2 - * s = 2*q , and y = 2 * ( y - q ). (1) - * i i i i - * - * To compute q from q , one checks whether - * i+1 i - * - * -(i+1) 2 - * (q + 2 ) <= y. (2) - * i - * -(i+1) - * If (2) is false, then q = q ; otherwise q = q + 2 . - * i+1 i i+1 i - * - * With some algebraic manipulation, it is not difficult to see - * that (2) is equivalent to - * -(i+1) - * s + 2 <= y (3) - * i i - * - * The advantage of (3) is that s and y can be computed by - * i i - * the following recurrence formula: - * if (3) is false - * - * s = s , y = y ; (4) - * i+1 i i+1 i - * - * otherwise, - * -i -(i+1) - * s = s + 2 , y = y - s - 2 (5) - * i+1 i i+1 i i - * - * One may easily use induction to prove (4) and (5). - * Note. Since the left hand side of (3) contain only i+2 bits, - * it does not necessary to do a full (53-bit) comparison - * in (3). - * 3. Final rounding - * After generating the 53 bits result, we compute one more bit. - * Together with the remainder, we can decide whether the - * result is exact, bigger than 1/2ulp, or less than 1/2ulp - * (it will never equal to 1/2ulp). - * The rounding mode can be detected by checking whether - * huge + tiny is equal to huge, and whether huge - tiny is - * equal to huge for some floating point number "huge" and "tiny". - * - * Special cases: - * sqrt(+-0) = +-0 ... exact - * sqrt(inf) = inf - * sqrt(-ve) = NaN ... with invalid signal - * sqrt(NaN) = NaN ... with invalid signal for signaling NaN - */ - -use core::f64; - /// The square root of `x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrt(x: f64) -> f64 { @@ -90,175 +10,5 @@ pub fn sqrt(x: f64) -> f64 { args: x, } - use core::num::Wrapping; - - const TINY: f64 = 1.0e-300; - - let mut z: f64; - let sign: Wrapping = Wrapping(0x80000000); - let mut ix0: i32; - let mut s0: i32; - let mut q: i32; - let mut m: i32; - let mut t: i32; - let mut i: i32; - let mut r: Wrapping; - let mut t1: Wrapping; - let mut s1: Wrapping; - let mut ix1: Wrapping; - let mut q1: Wrapping; - - ix0 = (x.to_bits() >> 32) as i32; - ix1 = Wrapping(x.to_bits() as u32); - - /* take care of Inf and NaN */ - if (ix0 & 0x7ff00000) == 0x7ff00000 { - return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ - } - /* take care of zero */ - if ix0 <= 0 { - if ((ix0 & !(sign.0 as i32)) | ix1.0 as i32) == 0 { - return x; /* sqrt(+-0) = +-0 */ - } - if ix0 < 0 { - return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ - } - } - /* normalize x */ - m = ix0 >> 20; - if m == 0 { - /* subnormal x */ - while ix0 == 0 { - m -= 21; - ix0 |= (ix1 >> 11).0 as i32; - ix1 <<= 21; - } - i = 0; - while (ix0 & 0x00100000) == 0 { - i += 1; - ix0 <<= 1; - } - m -= i - 1; - ix0 |= (ix1 >> (32 - i) as usize).0 as i32; - ix1 = ix1 << i as usize; - } - m -= 1023; /* unbias exponent */ - ix0 = (ix0 & 0x000fffff) | 0x00100000; - if (m & 1) == 1 { - /* odd m, double x to make it even */ - ix0 *= 2; - ix0 += ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - } - m >>= 1; /* m = [m/2] */ - - /* generate sqrt(x) bit by bit */ - ix0 *= 2; - ix0 += ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - q = 0; /* [q,q1] = sqrt(x) */ - q1 = Wrapping(0); - s0 = 0; - s1 = Wrapping(0); - r = Wrapping(0x00200000); /* r = moving bit from right to left */ - - while r != Wrapping(0) { - t = s0 + r.0 as i32; - if t <= ix0 { - s0 = t + r.0 as i32; - ix0 -= t; - q += r.0 as i32; - } - ix0 *= 2; - ix0 += ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - r >>= 1; - } - - r = sign; - while r != Wrapping(0) { - t1 = s1 + r; - t = s0; - if t < ix0 || (t == ix0 && t1 <= ix1) { - s1 = t1 + r; - if (t1 & sign) == sign && (s1 & sign) == Wrapping(0) { - s0 += 1; - } - ix0 -= t; - if ix1 < t1 { - ix0 -= 1; - } - ix1 -= t1; - q1 += r; - } - ix0 *= 2; - ix0 += ((ix1 & sign) >> 31).0 as i32; - ix1 += ix1; - r >>= 1; - } - - /* use floating add to find out rounding direction */ - if (ix0 as u32 | ix1.0) != 0 { - z = 1.0 - TINY; /* raise inexact flag */ - if z >= 1.0 { - z = 1.0 + TINY; - if q1.0 == 0xffffffff { - q1 = Wrapping(0); - q += 1; - } else if z > 1.0 { - if q1.0 == 0xfffffffe { - q += 1; - } - q1 += Wrapping(2); - } else { - q1 += q1 & Wrapping(1); - } - } - } - ix0 = (q >> 1) + 0x3fe00000; - ix1 = q1 >> 1; - if (q & 1) == 1 { - ix1 |= sign; - } - ix0 += m << 20; - f64::from_bits(((ix0 as u64) << 32) | ix1.0 as u64) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(sqrt(100.0), 10.0); - assert_eq!(sqrt(4.0), 2.0); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/sqrt - #[test] - fn spec_tests() { - // Not Asserted: FE_INVALID exception is raised if argument is negative. - assert!(sqrt(-1.0).is_nan()); - assert!(sqrt(f64::NAN).is_nan()); - for f in [0.0, -0.0, f64::INFINITY].iter().copied() { - assert_eq!(sqrt(f), f); - } - } - - #[test] - #[allow(clippy::approx_constant)] - fn conformance_tests() { - let values = [3.14159265359, 10000.0, f64::from_bits(0x0000000f), f64::INFINITY]; - let results = [ - 4610661241675116657u64, - 4636737291354636288u64, - 2197470602079456986u64, - 9218868437227405312u64, - ]; - - for i in 0..values.len() { - let bits = f64::to_bits(sqrt(values[i])); - assert_eq!(results[i], bits); - } - } + super::generic::sqrt(x) } diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 319335163ae85..2e69a4b669428 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -1,18 +1,3 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_sqrtf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - */ -/* - * ==================================================== - * 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. - * ==================================================== - */ - /// The square root of `x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrtf(x: f32) -> f32 { @@ -25,121 +10,5 @@ pub fn sqrtf(x: f32) -> f32 { args: x, } - const TINY: f32 = 1.0e-30; - - let mut z: f32; - let sign: i32 = 0x80000000u32 as i32; - let mut ix: i32; - let mut s: i32; - let mut q: i32; - let mut m: i32; - let mut t: i32; - let mut i: i32; - let mut r: u32; - - ix = x.to_bits() as i32; - - /* take care of Inf and NaN */ - if (ix as u32 & 0x7f800000) == 0x7f800000 { - return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ - } - - /* take care of zero */ - if ix <= 0 { - if (ix & !sign) == 0 { - return x; /* sqrt(+-0) = +-0 */ - } - if ix < 0 { - return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ - } - } - - /* normalize x */ - m = ix >> 23; - if m == 0 { - /* subnormal x */ - i = 0; - while ix & 0x00800000 == 0 { - ix <<= 1; - i = i + 1; - } - m -= i - 1; - } - m -= 127; /* unbias exponent */ - ix = (ix & 0x007fffff) | 0x00800000; - if m & 1 == 1 { - /* odd m, double x to make it even */ - ix += ix; - } - m >>= 1; /* m = [m/2] */ - - /* generate sqrt(x) bit by bit */ - ix += ix; - q = 0; - s = 0; - r = 0x01000000; /* r = moving bit from right to left */ - - while r != 0 { - t = s + r as i32; - if t <= ix { - s = t + r as i32; - ix -= t; - q += r as i32; - } - ix += ix; - r >>= 1; - } - - /* use floating add to find out rounding direction */ - if ix != 0 { - z = 1.0 - TINY; /* raise inexact flag */ - if z >= 1.0 { - z = 1.0 + TINY; - if z > 1.0 { - q += 2; - } else { - q += q & 1; - } - } - } - - ix = (q >> 1) + 0x3f000000; - ix += m << 23; - f32::from_bits(ix as u32) -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(sqrtf(100.0), 10.0); - assert_eq!(sqrtf(4.0), 2.0); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/sqrt - #[test] - fn spec_tests() { - // Not Asserted: FE_INVALID exception is raised if argument is negative. - assert!(sqrtf(-1.0).is_nan()); - assert!(sqrtf(f32::NAN).is_nan()); - for f in [0.0, -0.0, f32::INFINITY].iter().copied() { - assert_eq!(sqrtf(f), f); - } - } - - #[test] - #[allow(clippy::approx_constant)] - fn conformance_tests() { - let values = [3.14159265359f32, 10000.0f32, f32::from_bits(0x0000000f), f32::INFINITY]; - let results = [1071833029u32, 1120403456u32, 456082799u32, 2139095040u32]; - - for i in 0..values.len() { - let bits = f32::to_bits(sqrtf(values[i])); - assert_eq!(results[i], bits); - } - } + super::generic::sqrt(x) } 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 db799c030c286..cf19762e8169c 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -55,10 +55,12 @@ pub trait Int: + ops::BitAnd + cmp::Ord + CastFrom + + CastFrom + CastFrom + CastFrom + CastFrom + CastInto + + CastInto + CastInto + CastInto + CastInto diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index 076fdf1f775eb..c9a36c0db1a7b 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -110,19 +110,21 @@ macro_rules! hf64 { /// Assert `F::biteq` with better messages. #[cfg(test)] macro_rules! assert_biteq { - ($left:expr, $right:expr, $($arg:tt)*) => {{ - let bits = ($left.to_bits() * 0).leading_zeros(); // hack to get the width from the value + ($left:expr, $right:expr, $($tt:tt)*) => {{ + let l = $left; + let r = $right; + let bits = (l.to_bits() - l.to_bits()).leading_zeros(); // hack to get the width from the value assert!( - $left.biteq($right), - "\nl: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})", - l = $left, - lb = $left.to_bits(), - r = $right, - rb = $right.to_bits(), - width = ((bits / 4) + 2) as usize + l.biteq(r), + "{}\nl: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})", + format_args!($($tt)*), + lb = l.to_bits(), + rb = r.to_bits(), + width = ((bits / 4) + 2) as usize, + ); }}; ($left:expr, $right:expr $(,)?) => { - assert_biteq!($left, $right,) + assert_biteq!($left, $right, "") }; } diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index e2f4e0e981d6b..b4a57a34ed426 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -10,3 +10,14 @@ pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; #[allow(unused_imports)] pub use hex_float::{hf32, hf64}; pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; + +/// Hint to the compiler that the current path is cold. +pub fn cold_path() { + #[cfg(intrinsics_enabled)] + core::intrinsics::cold_path(); +} + +/// Return `x`, first raising `FE_INVALID`. +pub fn raise_invalid(x: F) -> F { + (x - x) / (x - x) +} From 03041a0371565f1a32583d770e15f4ffb60232b5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 15 Jan 2025 11:49:28 +0000 Subject: [PATCH 1588/4206] Copy the u256 implementation from compiler_builtins --- .../libm/src/math/support/big.rs | 302 ++++++++++++++++++ .../libm/src/math/support/big/tests.rs | 110 +++++++ .../libm/src/math/support/mod.rs | 1 + 3 files changed, 413 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/support/big.rs create mode 100644 library/compiler-builtins/libm/src/math/support/big/tests.rs diff --git a/library/compiler-builtins/libm/src/math/support/big.rs b/library/compiler-builtins/libm/src/math/support/big.rs new file mode 100644 index 0000000000000..e0f5e52634efb --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/big.rs @@ -0,0 +1,302 @@ +//! Integers used for wide operations, larger than `u128`. + +#![allow(unused)] + +#[cfg(test)] +mod tests; + +use core::{fmt, ops}; + +use super::{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; + + // FIXME(msrv): could be let...else. + let base = match ret.0.get(base_idx) { + Some(v) => v, + None => { + 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/libm/src/math/support/big/tests.rs b/library/compiler-builtins/libm/src/math/support/big/tests.rs new file mode 100644 index 0000000000000..f95f829731613 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/big/tests.rs @@ -0,0 +1,110 @@ +extern crate std; +use std::string::String; +use std::vec::Vec; +use std::{eprintln, format}; + +use super::{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/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index b4a57a34ed426..ddfc2e3e0717a 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -1,5 +1,6 @@ #[macro_use] pub mod macros; +mod big; mod float_traits; mod hex_float; mod int_traits; From 186eac9227e83b9ba0d771ac9326632d42e25086 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 21 Jan 2025 23:59:07 +0000 Subject: [PATCH 1589/4206] Add `sqrtf16` and `sqrtf128` Use the generic algorithms to provide implementations for these routines. --- .../libm/crates/libm-macros/src/shared.rs | 4 +- .../libm/crates/libm-test/benches/icount.rs | 2 + .../libm/crates/libm-test/benches/random.rs | 2 + .../libm-test/tests/compare_built_musl.rs | 2 + .../libm/crates/util/src/main.rs | 2 + .../libm/etc/function-definitions.json | 14 +++ .../libm/etc/function-list.txt | 2 + .../libm/src/math/generic/sqrt.rs | 92 +++++++++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 4 + .../libm/src/math/sqrtf128.rs | 5 + .../libm/src/math/sqrtf16.rs | 5 + 11 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/sqrtf128.rs create mode 100644 library/compiler-builtins/libm/src/math/sqrtf16.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index 60838196236f5..d17bc6ffccb7d 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -9,7 +9,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16], returns: &[Ty::F16] }, None, - &["fabsf16", "truncf16"], + &["fabsf16", "sqrtf16", "truncf16"], ), ( // `fn(f32) -> f32` @@ -40,7 +40,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F128, Signature { args: &[Ty::F128], returns: &[Ty::F128] }, None, - &["fabsf128", "truncf128"], + &["fabsf128", "sqrtf128", "truncf128"], ), ( // `(f16, f16) -> f16` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index 3a66249e85dc5..c8451f88cd388 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -155,6 +155,8 @@ main!( 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_tan_group, icount_bench_tanf_group, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 8881612651004..0268412025322 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -123,6 +123,8 @@ libm_macros::for_each_function! { | fabsf16 | fdimf128 | fdimf16 + | sqrtf16 + | sqrtf128 | truncf128 | truncf16 => (false, None), diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index f540a0b15517f..24703f2731683 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -87,5 +87,7 @@ libm_macros::for_each_function! { fdimf16, truncf128, truncf16, + sqrtf16, + sqrtf128, ], } diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index b979c60ad3c02..cd68d9afd1a23 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -90,6 +90,8 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | fabsf16 | fdimf128 | fdimf16 + | sqrtf128 + | sqrtf16 | truncf128 | truncf16 => None, _ => Some(musl_math_sys::MACRO_FN_NAME) diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 9f7c8ab25a033..2d0af3bcff02a 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -718,6 +718,20 @@ ], "type": "f32" }, + "sqrtf128": { + "sources": [ + "src/math/generic/sqrt.rs", + "src/math/sqrtf128.rs" + ], + "type": "f128" + }, + "sqrtf16": { + "sources": [ + "src/math/generic/sqrt.rs", + "src/math/sqrtf16.rs" + ], + "type": "f16" + }, "tan": { "sources": [ "src/libm_helper.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 7f96a436227e9..47c34ab905219 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -105,6 +105,8 @@ sinh sinhf sqrt sqrtf +sqrtf128 +sqrtf16 tan tanf tanh diff --git a/library/compiler-builtins/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/src/math/generic/sqrt.rs index a2e054f3cf2b7..c892f99972410 100644 --- a/library/compiler-builtins/libm/src/math/generic/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/generic/sqrt.rs @@ -294,6 +294,14 @@ pub trait SqrtHelper: Float { const FINAL_ROUNDS: u32; } +#[cfg(f16_enabled)] +impl SqrtHelper for f16 { + type ISet1 = u16; // unused + type ISet2 = u16; // unused + + const FINAL_ROUNDS: u32 = 2; +} + impl SqrtHelper for f32 { type ISet1 = u32; // unused type ISet2 = u32; // unused @@ -309,6 +317,16 @@ impl SqrtHelper for f64 { const FINAL_ROUNDS: u32 = 2; } +#[cfg(f128_enabled)] +impl SqrtHelper for f128 { + type ISet1 = u32; + type ISet2 = u64; + + const SET1_ROUNDS: u32 = 1; + const SET2_ROUNDS: u32 = 2; + const FINAL_ROUNDS: u32 = 2; +} + /// A U0.16 representation of `1/sqrt(x)`. /// // / The index is a 7-bit number consisting of a single exponent bit and 6 bits of significand. @@ -355,6 +373,42 @@ mod tests { } } + #[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), + // 10_000.0, using a hex literal for MSRV hack (Rust < 1.67 checks literal widths as + // part of the AST, so the `cfg` is irrelevant here). + (f16::from_bits(0x70e2), 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); @@ -416,4 +470,42 @@ mod tests { ); } } + + #[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/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 03adb6be19341..3684025a6c100 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -344,11 +344,13 @@ cfg_if! { mod copysignf16; mod fabsf16; mod fdimf16; + mod sqrtf16; mod truncf16; pub use self::copysignf16::copysignf16; pub use self::fabsf16::fabsf16; pub use self::fdimf16::fdimf16; + pub use self::sqrtf16::sqrtf16; pub use self::truncf16::truncf16; } } @@ -358,11 +360,13 @@ cfg_if! { mod copysignf128; mod fabsf128; mod fdimf128; + mod sqrtf128; mod truncf128; pub use self::copysignf128::copysignf128; pub use self::fabsf128::fabsf128; pub use self::fdimf128::fdimf128; + pub use self::sqrtf128::sqrtf128; pub use self::truncf128::truncf128; } } diff --git a/library/compiler-builtins/libm/src/math/sqrtf128.rs b/library/compiler-builtins/libm/src/math/sqrtf128.rs new file mode 100644 index 0000000000000..eaef6ae0c1c85 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sqrtf128.rs @@ -0,0 +1,5 @@ +/// The square root of `x` (f128). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf128(x: f128) -> f128 { + return super::generic::sqrt(x); +} diff --git a/library/compiler-builtins/libm/src/math/sqrtf16.rs b/library/compiler-builtins/libm/src/math/sqrtf16.rs new file mode 100644 index 0000000000000..549bf902c7221 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sqrtf16.rs @@ -0,0 +1,5 @@ +/// The square root of `x` (f16). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf16(x: f16) -> f16 { + return super::generic::sqrt(x); +} From 5ac2f99954f2bd2d7d1c342abcaa5ffed7418e08 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 11:58:17 +0000 Subject: [PATCH 1590/4206] Shift then mask, rather than mask then shift This may allow for small optimizations with larger float types since `u32` math can be used after shifting. LLVM may be already getting this anyway. --- .../compiler-builtins/libm/src/math/support/float_traits.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 647f4f5e251b2..2e467111f32f4 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,6 @@ use core::{fmt, mem, ops}; -use super::int_traits::{CastFrom, CastInto, Int, MinInt}; +use super::int_traits::{CastFrom, Int, MinInt}; /// Trait for some basic operations on floats #[allow(dead_code)] @@ -108,7 +108,7 @@ pub trait Float: /// Returns the exponent, not adjusting for bias, not accounting for subnormals or zero. fn exp(self) -> i32 { - ((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS).cast() + (u32::cast_from(self.to_bits() >> Self::SIG_BITS) & Self::EXP_MAX).signed() } /// Extract the exponent and adjust it for bias, not accounting for subnormals or zero. From a7cd13b6a32874dd6bc18cdb7e7d7e6bda105adf Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 22 Jan 2025 07:13:45 +0000 Subject: [PATCH 1591/4206] Make `Float::exp` return an unsigned integer `exp` does not perform any form of unbiasing, so there isn't any reason it should be signed. Change this. Additionally, add `EPSILON` to the `Float` trait. --- .../libm/crates/libm-test/src/f8_impl.rs | 2 ++ library/compiler-builtins/libm/src/math/generic/sqrt.rs | 2 +- .../libm/src/math/support/float_traits.rs | 8 +++++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs index 299553d202ad2..96b78392453fa 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs @@ -30,6 +30,8 @@ impl Float for f8 { const INFINITY: Self = Self(0b0_1111_000); const NEG_INFINITY: Self = Self(0b1_1111_000); const NAN: Self = Self(0b0_1111_100); + // FIXME: incorrect values + const EPSILON: Self = Self::ZERO; const PI: Self = Self::ZERO; const NEG_PI: Self = Self::ZERO; const FRAC_PI_2: Self = Self::ZERO; diff --git a/library/compiler-builtins/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/src/math/generic/sqrt.rs index c892f99972410..22ee93f57a3c4 100644 --- a/library/compiler-builtins/libm/src/math/generic/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/generic/sqrt.rs @@ -96,7 +96,7 @@ where ix = scaled.to_bits(); match top { Exp::Shifted(ref mut v) => { - *v = scaled.exp().unsigned(); + *v = scaled.exp(); *v = (*v).wrapping_sub(F::SIG_BITS); } Exp::NoShift(()) => { 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 2e467111f32f4..1abb7c4ded841 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -34,6 +34,7 @@ pub trait Float: const NAN: Self; const MAX: Self; const MIN: Self; + const EPSILON: Self; const PI: Self; const NEG_PI: Self; const FRAC_PI_2: Self; @@ -107,13 +108,13 @@ pub trait Float: } /// Returns the exponent, not adjusting for bias, not accounting for subnormals or zero. - fn exp(self) -> i32 { - (u32::cast_from(self.to_bits() >> Self::SIG_BITS) & Self::EXP_MAX).signed() + fn exp(self) -> u32 { + u32::cast_from(self.to_bits() >> Self::SIG_BITS) & Self::EXP_MAX } /// Extract the exponent and adjust it for bias, not accounting for subnormals or zero. fn exp_unbiased(self) -> i32 { - self.exp() - (Self::EXP_BIAS as i32) + self.exp().signed() - (Self::EXP_BIAS as i32) } /// Returns the significand with no implicit bit (or the "fractional" part) @@ -180,6 +181,7 @@ macro_rules! float_impl { const MAX: Self = -Self::MIN; // Sign bit set, saturated mantissa, saturated exponent with last bit zeroed const MIN: Self = $from_bits(Self::Int::MAX & !(1 << Self::SIG_BITS)); + const EPSILON: Self = <$ty>::EPSILON; const PI: Self = core::$ty::consts::PI; const NEG_PI: Self = -Self::PI; From c00f1191666e6803fdd61eca2ac5f0cb07360656 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 11:17:03 +0000 Subject: [PATCH 1592/4206] Add a generic version of `ceil` Additionally, make use of this version to implement `ceil` and `ceilf`. Musl's `ceilf` algorithm seems to work better for all versions of the functions. Testing with a generic version of musl's `ceil` routine showed the following regressions: icount::icount_bench_ceil_group::icount_bench_ceil logspace:setup_ceil() Performance has regressed: Instructions (14064 > 13171) regressed by +6.78005% (>+5.00000) Baselines: softfloat|softfloat Instructions: 14064|13171 (+6.78005%) [+1.06780x] L1 Hits: 16697|15803 (+5.65715%) [+1.05657x] L2 Hits: 0|0 (No change) RAM Hits: 7|8 (-12.5000%) [-1.14286x] Total read+write: 16704|15811 (+5.64797%) [+1.05648x] Estimated Cycles: 16942|16083 (+5.34104%) [+1.05341x] icount::icount_bench_ceilf_group::icount_bench_ceilf logspace:setup_ceilf() Performance has regressed: Instructions (14732 > 9901) regressed by +48.7931% (>+5.00000) Baselines: softfloat|softfloat Instructions: 14732|9901 (+48.7931%) [+1.48793x] L1 Hits: 17494|12611 (+38.7202%) [+1.38720x] L2 Hits: 0|0 (No change) RAM Hits: 6|6 (No change) Total read+write: 17500|12617 (+38.7018%) [+1.38702x] Estimated Cycles: 17704|12821 (+38.0860%) [+1.38086x] --- .../compiler-builtins/libm/src/math/ceil.rs | 42 +-------- .../compiler-builtins/libm/src/math/ceilf.rs | 51 +---------- .../libm/src/math/generic/ceil.rs | 87 +++++++++++++++++++ .../libm/src/math/generic/mod.rs | 2 + 4 files changed, 91 insertions(+), 91 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/ceil.rs diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index 398bfee47a21d..535f434ac2437 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -1,8 +1,3 @@ -#![allow(unreachable_code)] -use core::f64; - -const TOINT: f64 = 1. / f64::EPSILON; - /// Ceil (f64) /// /// Finds the nearest integer greater than or equal to `x`. @@ -15,40 +10,5 @@ pub fn ceil(x: f64) -> f64 { args: x, } - let u: u64 = x.to_bits(); - let e: i64 = ((u >> 52) & 0x7ff) as i64; - let y: f64; - - if e >= 0x3ff + 52 || x == 0. { - return x; - } - // y = int(x) - x, where int(x) is an integer neighbor of x - y = if (u >> 63) != 0 { x - TOINT + TOINT - x } else { x + TOINT - TOINT - x }; - // special case because of non-nearest rounding modes - if e < 0x3ff { - force_eval!(y); - return if (u >> 63) != 0 { -0. } else { 1. }; - } - if y < 0. { x + y + 1. } else { x + y } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(ceil(1.1), 2.0); - assert_eq!(ceil(2.9), 3.0); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/ceil - #[test] - fn spec_tests() { - // Not Asserted: that the current rounding mode has no effect. - assert!(ceil(f64::NAN).is_nan()); - for f in [0.0, -0.0, f64::INFINITY, f64::NEG_INFINITY].iter().copied() { - assert_eq!(ceil(f), f); - } - } + super::generic::ceil(x) } diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs index 9e8e78e3e532b..66d44189c9212 100644 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ b/library/compiler-builtins/libm/src/math/ceilf.rs @@ -1,5 +1,3 @@ -use core::f32; - /// Ceil (f32) /// /// Finds the nearest integer greater than or equal to `x`. @@ -11,52 +9,5 @@ pub fn ceilf(x: f32) -> f32 { args: x, } - let mut ui = x.to_bits(); - let e = (((ui >> 23) & 0xff).wrapping_sub(0x7f)) as i32; - - if e >= 23 { - return x; - } - if e >= 0 { - let m = 0x007fffff >> e; - if (ui & m) == 0 { - return x; - } - force_eval!(x + f32::from_bits(0x7b800000)); - if ui >> 31 == 0 { - ui += m; - } - ui &= !m; - } else { - force_eval!(x + f32::from_bits(0x7b800000)); - if ui >> 31 != 0 { - return -0.0; - } else if ui << 1 != 0 { - return 1.0; - } - } - f32::from_bits(ui) -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(ceilf(1.1), 2.0); - assert_eq!(ceilf(2.9), 3.0); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/ceil - #[test] - fn spec_tests() { - // Not Asserted: that the current rounding mode has no effect. - assert!(ceilf(f32::NAN).is_nan()); - for f in [0.0, -0.0, f32::INFINITY, f32::NEG_INFINITY].iter().copied() { - assert_eq!(ceilf(f), f); - } - } + super::generic::ceil(x) } diff --git a/library/compiler-builtins/libm/src/math/generic/ceil.rs b/library/compiler-builtins/libm/src/math/generic/ceil.rs new file mode 100644 index 0000000000000..d16d0657279e7 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/ceil.rs @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/ceilf.c */ + +//! Generic `ceil` algorithm. +//! +//! Note that this uses the algorithm from musl's `ceilf` rather than `ceil` or `ceill` because +//! performance seems to be better (based on icount) and it does not seem to experience rounding +//! errors on i386. + +use super::super::{Float, Int, IntTy, MinInt}; + +pub fn ceil(x: F) -> F { + let zero = IntTy::::ZERO; + + let mut ix = x.to_bits(); + let e = x.exp_unbiased(); + + // If the represented value has no fractional part, no truncation is needed. + if e >= F::SIG_BITS as i32 { + return x; + } + + if e >= 0 { + // |x| >= 1.0 + + let m = F::SIG_MASK >> e.unsigned(); + if (ix & m) == zero { + // Portion to be masked is already zero; no adjustment needed. + return x; + } + + // Otherwise, raise an inexact exception. + force_eval!(x + F::MAX); + if x.is_sign_positive() { + ix += m; + } + ix &= !m; + } else { + // |x| < 1.0, raise an inexact exception since truncation will happen (unless x == 0). + force_eval!(x + F::MAX); + + if x.is_sign_negative() { + // -1.0 < x <= -0.0; rounding up goes toward -0.0. + return F::NEG_ZERO; + } else if ix << 1 != zero { + // 0.0 < x < 1.0; rounding up goes toward +1.0. + return F::ONE; + } + } + + F::from_bits(ix) +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Test against https://en.cppreference.com/w/cpp/numeric/math/ceil + fn spec_test() { + // Not Asserted: that the current rounding mode has no effect. + for f in [F::ZERO, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY].iter().copied() { + assert_biteq!(ceil(f), f); + } + } + + #[test] + fn sanity_check_f32() { + assert_eq!(ceil(1.1f32), 2.0); + assert_eq!(ceil(2.9f32), 3.0); + } + + #[test] + fn spec_tests_f32() { + spec_test::(); + } + + #[test] + fn sanity_check_f64() { + assert_eq!(ceil(1.1f64), 2.0); + assert_eq!(ceil(2.9f64), 3.0); + } + + #[test] + fn spec_tests_f64() { + spec_test::(); + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index 3b5a2c3effd7d..f8bb9fa6adb1e 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -1,9 +1,11 @@ +mod ceil; mod copysign; mod fabs; mod fdim; mod sqrt; mod trunc; +pub use ceil::ceil; pub use copysign::copysign; pub use fabs::fabs; pub use fdim::fdim; From 9064c42abe93f9864243aa982b529d54a731db80 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 11:17:17 +0000 Subject: [PATCH 1593/4206] Add `ceilf16` and `ceilf128` Use the generic algorithms to provide implementations for these routines. --- .../libm/crates/libm-macros/src/shared.rs | 4 ++-- .../libm/crates/libm-test/benches/icount.rs | 2 ++ .../libm/crates/libm-test/benches/random.rs | 4 +++- .../libm/crates/libm-test/src/mpfloat.rs | 4 ++++ .../libm-test/tests/compare_built_musl.rs | 2 ++ .../libm/crates/util/src/main.rs | 4 +++- .../libm/etc/function-definitions.json | 20 +++++++++++++++++-- .../libm/etc/function-list.txt | 2 ++ .../libm/src/math/ceilf128.rs | 7 +++++++ .../libm/src/math/ceilf16.rs | 7 +++++++ .../libm/src/math/generic/ceil.rs | 14 +++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 4 ++++ 12 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/ceilf128.rs create mode 100644 library/compiler-builtins/libm/src/math/ceilf16.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index d17bc6ffccb7d..e7d3d18d9a1bd 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -9,7 +9,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16], returns: &[Ty::F16] }, None, - &["fabsf16", "sqrtf16", "truncf16"], + &["ceilf16", "fabsf16", "sqrtf16", "truncf16"], ), ( // `fn(f32) -> f32` @@ -40,7 +40,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F128, Signature { args: &[Ty::F128], returns: &[Ty::F128] }, None, - &["fabsf128", "sqrtf128", "truncf128"], + &["ceilf128", "fabsf128", "sqrtf128", "truncf128"], ), ( // `(f16, f16) -> f16` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index c8451f88cd388..84be3d5245b67 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -69,6 +69,8 @@ main!( 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, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 0268412025322..511e26d912672 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -117,7 +117,9 @@ libm_macros::for_each_function! { exp10 | exp10f | exp2 | exp2f => (true, Some(musl_math_sys::MACRO_FN_NAME)), // Musl does not provide `f16` and `f128` functions - copysignf128 + ceilf128 + | ceilf16 + | copysignf128 | copysignf16 | fabsf128 | fabsf16 diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 9d95356d39b34..bbd19dbb07bac 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -137,6 +137,8 @@ libm_macros::for_each_function! { // Most of these need a manual implementation ceil, ceilf, + ceilf128, + ceilf16, copysign, copysignf, copysignf128, @@ -237,12 +239,14 @@ impl_no_round! { #[cfg(f16_enabled)] impl_no_round! { fabsf16 => abs_mut; + ceilf16 => ceil_mut; truncf16 => trunc_mut; } #[cfg(f128_enabled)] impl_no_round! { fabsf128 => abs_mut; + ceilf128 => ceil_mut; truncf128 => trunc_mut; } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 24703f2731683..e13acf3de216a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -79,6 +79,8 @@ libm_macros::for_each_function! { ynf, // Not provided by musl + ceilf128, + ceilf16, copysignf128, copysignf16, fabsf128, diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index cd68d9afd1a23..810919339ec6f 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -84,7 +84,9 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { emit_types: [CFn, RustFn, RustArgs], extra: (basis, op, inputs), fn_extra: match MACRO_FN_NAME { - copysignf128 + ceilf128 + | ceilf16 + | copysignf128 | copysignf16 | fabsf128 | fabsf16 diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 2d0af3bcff02a..c75152f630195 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -109,17 +109,33 @@ "src/libm_helper.rs", "src/math/arch/i586.rs", "src/math/arch/wasm32.rs", - "src/math/ceil.rs" + "src/math/ceil.rs", + "src/math/generic/ceil.rs" ], "type": "f64" }, "ceilf": { "sources": [ "src/math/arch/wasm32.rs", - "src/math/ceilf.rs" + "src/math/ceilf.rs", + "src/math/generic/ceil.rs" ], "type": "f32" }, + "ceilf128": { + "sources": [ + "src/math/ceilf128.rs", + "src/math/generic/ceil.rs" + ], + "type": "f128" + }, + "ceilf16": { + "sources": [ + "src/math/ceilf16.rs", + "src/math/generic/ceil.rs" + ], + "type": "f16" + }, "copysign": { "sources": [ "src/libm_helper.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 47c34ab905219..337e7e434e5f2 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -17,6 +17,8 @@ cbrt cbrtf ceil ceilf +ceilf128 +ceilf16 copysign copysignf copysignf128 diff --git a/library/compiler-builtins/libm/src/math/ceilf128.rs b/library/compiler-builtins/libm/src/math/ceilf128.rs new file mode 100644 index 0000000000000..89980858eb5be --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ceilf128.rs @@ -0,0 +1,7 @@ +/// Ceil (f128) +/// +/// Finds the nearest integer greater than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ceilf128(x: f128) -> f128 { + super::generic::ceil(x) +} diff --git a/library/compiler-builtins/libm/src/math/ceilf16.rs b/library/compiler-builtins/libm/src/math/ceilf16.rs new file mode 100644 index 0000000000000..2af67eff0d2aa --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ceilf16.rs @@ -0,0 +1,7 @@ +/// Ceil (f16) +/// +/// Finds the nearest integer greater than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ceilf16(x: f16) -> f16 { + super::generic::ceil(x) +} diff --git a/library/compiler-builtins/libm/src/math/generic/ceil.rs b/library/compiler-builtins/libm/src/math/generic/ceil.rs index d16d0657279e7..34261faf782f9 100644 --- a/library/compiler-builtins/libm/src/math/generic/ceil.rs +++ b/library/compiler-builtins/libm/src/math/generic/ceil.rs @@ -63,6 +63,14 @@ mod tests { } } + /* Skipping f16 / f128 "sanity_check"s due to rejected literal lexing at MSRV */ + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(); + } + #[test] fn sanity_check_f32() { assert_eq!(ceil(1.1f32), 2.0); @@ -84,4 +92,10 @@ mod tests { fn spec_tests_f64() { spec_test::(); } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(); + } } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 3684025a6c100..5228e78b7f333 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -341,12 +341,14 @@ pub use self::truncf::truncf; cfg_if! { if #[cfg(f16_enabled)] { + mod ceilf16; mod copysignf16; mod fabsf16; mod fdimf16; mod sqrtf16; mod truncf16; + pub use self::ceilf16::ceilf16; pub use self::copysignf16::copysignf16; pub use self::fabsf16::fabsf16; pub use self::fdimf16::fdimf16; @@ -357,12 +359,14 @@ cfg_if! { cfg_if! { if #[cfg(f128_enabled)] { + mod ceilf128; mod copysignf128; mod fabsf128; mod fdimf128; mod sqrtf128; mod truncf128; + pub use self::ceilf128::ceilf128; pub use self::copysignf128::copysignf128; pub use self::fabsf128::fabsf128; pub use self::fdimf128::fdimf128; From 42fce292ab45c4d28de82799a83f3313b9ca9907 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 13:27:22 +0000 Subject: [PATCH 1594/4206] Add a generic version of `floor` Additionally, make use of this version to implement `floor` and `floorf`. Similar to `ceil`, musl'f `ceilf` routine seems to work better for all float widths than the `ceil` algorithm. Trying with the `ceil` (`f64`) algorithm produced the following regressions: icount::icount_bench_floor_group::icount_bench_floor logspace:setup_floor() Performance has regressed: Instructions (14064 > 13171) regressed by +6.78005% (>+5.00000) Baselines: softfloat|softfloat Instructions: 14064|13171 (+6.78005%) [+1.06780x] L1 Hits: 16821|15802 (+6.44855%) [+1.06449x] L2 Hits: 0|0 (No change) RAM Hits: 8|9 (-11.1111%) [-1.12500x] Total read+write: 16829|15811 (+6.43856%) [+1.06439x] Estimated Cycles: 17101|16117 (+6.10535%) [+1.06105x] icount::icount_bench_floorf128_group::icount_bench_floorf128 logspace:setup_floorf128() Baselines: softfloat|softfloat Instructions: 166868|N/A (*********) L1 Hits: 221429|N/A (*********) L2 Hits: 1|N/A (*********) RAM Hits: 34|N/A (*********) Total read+write: 221464|N/A (*********) Estimated Cycles: 222624|N/A (*********) icount::icount_bench_floorf16_group::icount_bench_floorf16 logspace:setup_floorf16() Baselines: softfloat|softfloat Instructions: 143029|N/A (*********) L1 Hits: 176517|N/A (*********) L2 Hits: 1|N/A (*********) RAM Hits: 13|N/A (*********) Total read+write: 176531|N/A (*********) Estimated Cycles: 176977|N/A (*********) icount::icount_bench_floorf_group::icount_bench_floorf logspace:setup_floorf() Performance has regressed: Instructions (14732 > 10441) regressed by +41.0976% (>+5.00000) Baselines: softfloat|softfloat Instructions: 14732|10441 (+41.0976%) [+1.41098x] L1 Hits: 17616|13027 (+35.2268%) [+1.35227x] L2 Hits: 0|0 (No change) RAM Hits: 8|6 (+33.3333%) [+1.33333x] Total read+write: 17624|13033 (+35.2260%) [+1.35226x] Estimated Cycles: 17896|13237 (+35.1968%) [+1.35197x] --- .../libm/etc/function-definitions.json | 6 +- .../compiler-builtins/libm/src/math/floor.rs | 41 +------ .../compiler-builtins/libm/src/math/floorf.rs | 52 +-------- .../libm/src/math/generic/floor.rs | 106 ++++++++++++++++++ .../libm/src/math/generic/mod.rs | 2 + 5 files changed, 114 insertions(+), 93 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/floor.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index c75152f630195..6a865f42784d8 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -336,14 +336,16 @@ "src/libm_helper.rs", "src/math/arch/i586.rs", "src/math/arch/wasm32.rs", - "src/math/floor.rs" + "src/math/floor.rs", + "src/math/generic/floor.rs" ], "type": "f64" }, "floorf": { "sources": [ "src/math/arch/wasm32.rs", - "src/math/floorf.rs" + "src/math/floorf.rs", + "src/math/generic/floor.rs" ], "type": "f32" }, diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index 2823bf44d9c3e..b4f02abc49112 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -1,8 +1,3 @@ -#![allow(unreachable_code)] -use core::f64; - -const TOINT: f64 = 1. / f64::EPSILON; - /// Floor (f64) /// /// Finds the nearest integer less than or equal to `x`. @@ -15,39 +10,5 @@ pub fn floor(x: f64) -> f64 { args: x, } - let ui = x.to_bits(); - let e = ((ui >> 52) & 0x7ff) as i32; - - if (e >= 0x3ff + 52) || (x == 0.) { - return x; - } - /* y = int(x) - x, where int(x) is an integer neighbor of x */ - let y = if (ui >> 63) != 0 { x - TOINT + TOINT - x } else { x + TOINT - TOINT - x }; - /* special case because of non-nearest rounding modes */ - if e < 0x3ff { - force_eval!(y); - return if (ui >> 63) != 0 { -1. } else { 0. }; - } - if y > 0. { x + y - 1. } else { x + y } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(floor(1.1), 1.0); - assert_eq!(floor(2.9), 2.0); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/floor - #[test] - fn spec_tests() { - // Not Asserted: that the current rounding mode has no effect. - assert!(floor(f64::NAN).is_nan()); - for f in [0.0, -0.0, f64::INFINITY, f64::NEG_INFINITY].iter().copied() { - assert_eq!(floor(f), f); - } - } + return super::generic::floor(x); } diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs index 23a18c0f73761..16957b7f35573 100644 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ b/library/compiler-builtins/libm/src/math/floorf.rs @@ -1,5 +1,3 @@ -use core::f32; - /// Floor (f32) /// /// Finds the nearest integer less than or equal to `x`. @@ -11,53 +9,5 @@ pub fn floorf(x: f32) -> f32 { args: x, } - let mut ui = x.to_bits(); - let e = (((ui >> 23) as i32) & 0xff) - 0x7f; - - if e >= 23 { - return x; - } - if e >= 0 { - let m: u32 = 0x007fffff >> e; - if (ui & m) == 0 { - return x; - } - force_eval!(x + f32::from_bits(0x7b800000)); - if ui >> 31 != 0 { - ui += m; - } - ui &= !m; - } else { - force_eval!(x + f32::from_bits(0x7b800000)); - if ui >> 31 == 0 { - ui = 0; - } else if ui << 1 != 0 { - return -1.0; - } - } - f32::from_bits(ui) -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(floorf(0.5), 0.0); - assert_eq!(floorf(1.1), 1.0); - assert_eq!(floorf(2.9), 2.0); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/floor - #[test] - fn spec_tests() { - // Not Asserted: that the current rounding mode has no effect. - assert!(floorf(f32::NAN).is_nan()); - for f in [0.0, -0.0, f32::INFINITY, f32::NEG_INFINITY].iter().copied() { - assert_eq!(floorf(f), f); - } - } + return super::generic::floor(x); } diff --git a/library/compiler-builtins/libm/src/math/generic/floor.rs b/library/compiler-builtins/libm/src/math/generic/floor.rs new file mode 100644 index 0000000000000..6754c08f870bb --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/floor.rs @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: MIT + * origin: musl src/math/floor.c */ + +//! Generic `floor` algorithm. +//! +//! Note that this uses the algorithm from musl's `floorf` rather than `floor` or `floorl` because +//! performance seems to be better (based on icount) and it does not seem to experience rounding +//! errors on i386. + +use super::super::{Float, Int, IntTy, MinInt}; + +pub fn floor(x: F) -> F { + let zero = IntTy::::ZERO; + + let mut ix = x.to_bits(); + let e = x.exp_unbiased(); + + // If the represented value has no fractional part, no truncation is needed. + if e >= F::SIG_BITS as i32 { + return x; + } + + if e >= 0 { + // |x| >= 1.0 + + let m = F::SIG_MASK >> e.unsigned(); + if ix & m == zero { + // Portion to be masked is already zero; no adjustment needed. + return x; + } + + // Otherwise, raise an inexact exception. + force_eval!(x + F::MAX); + + if x.is_sign_negative() { + ix += m; + } + + ix &= !m; + F::from_bits(ix) + } else { + // |x| < 1.0, raise an inexact exception since truncation will happen (unless x == 0). + force_eval!(x + F::MAX); + + if x.is_sign_positive() { + // 0.0 <= x < 1.0; rounding down goes toward +0.0. + F::ZERO + } else if ix << 1 != zero { + // -1.0 < x < 0.0; rounding down goes toward -1.0. + F::NEG_ONE + } else { + // -0.0 remains unchanged + x + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Test against https://en.cppreference.com/w/cpp/numeric/math/floor + fn spec_test() { + // Not Asserted: that the current rounding mode has no effect. + for f in [F::ZERO, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY].iter().copied() { + assert_biteq!(floor(f), f); + } + } + + /* Skipping f16 / f128 "sanity_check"s due to rejected literal lexing at MSRV */ + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(); + } + + #[test] + fn sanity_check_f32() { + assert_eq!(floor(0.5f32), 0.0); + assert_eq!(floor(1.1f32), 1.0); + assert_eq!(floor(2.9f32), 2.0); + } + + #[test] + fn spec_tests_f32() { + spec_test::(); + } + + #[test] + fn sanity_check_f64() { + assert_eq!(floor(1.1f64), 1.0); + assert_eq!(floor(2.9f64), 2.0); + } + + #[test] + fn spec_tests_f64() { + spec_test::(); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(); + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index f8bb9fa6adb1e..b08a77d5d6493 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -2,6 +2,7 @@ mod ceil; mod copysign; mod fabs; mod fdim; +mod floor; mod sqrt; mod trunc; @@ -9,5 +10,6 @@ pub use ceil::ceil; pub use copysign::copysign; pub use fabs::fabs; pub use fdim::fdim; +pub use floor::floor; pub use sqrt::sqrt; pub use trunc::trunc; From 6a8bb0fa80ba2e777dea045441a0a879c4247b93 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 13 Jan 2025 13:33:24 +0000 Subject: [PATCH 1595/4206] Add `floorf16` and `floorf128` Use the generic algorithms to provide implementations for these routines. --- .../crates/compiler-builtins-smoke-test/src/lib.rs | 2 ++ .../libm/crates/libm-macros/src/shared.rs | 4 ++-- .../libm/crates/libm-test/benches/icount.rs | 2 ++ .../libm/crates/libm-test/benches/random.rs | 4 +++- .../libm/crates/libm-test/src/mpfloat.rs | 4 ++++ .../crates/libm-test/tests/compare_built_musl.rs | 2 ++ .../compiler-builtins/libm/crates/util/src/main.rs | 2 ++ .../libm/etc/function-definitions.json | 14 ++++++++++++++ .../compiler-builtins/libm/etc/function-list.txt | 2 ++ .../compiler-builtins/libm/src/math/floorf128.rs | 7 +++++++ .../compiler-builtins/libm/src/math/floorf16.rs | 7 +++++++ library/compiler-builtins/libm/src/math/mod.rs | 4 ++++ 12 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/floorf128.rs create mode 100644 library/compiler-builtins/libm/src/math/floorf16.rs diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index b9521eb071528..4834ba256eb2f 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -97,6 +97,8 @@ no_mangle! { fdimf16(x: f16, y: f16) -> f16; floor(x: f64) -> f64; floorf(x: f32) -> f32; + floorf128(x: f128) -> f128; + floorf16(x: f16) -> f16; fma(x: f64, y: f64, z: f64) -> f64; fmaf(x: f32, y: f32, z: f32) -> f32; fmax(x: f64, y: f64) -> f64; diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index e7d3d18d9a1bd..64623658d655d 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -9,7 +9,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16], returns: &[Ty::F16] }, None, - &["ceilf16", "fabsf16", "sqrtf16", "truncf16"], + &["ceilf16", "fabsf16", "floorf16", "sqrtf16", "truncf16"], ), ( // `fn(f32) -> f32` @@ -40,7 +40,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F128, Signature { args: &[Ty::F128], returns: &[Ty::F128] }, None, - &["ceilf128", "fabsf128", "sqrtf128", "truncf128"], + &["ceilf128", "fabsf128", "floorf128", "sqrtf128", "truncf128"], ), ( // `(f16, f16) -> f16` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index 84be3d5245b67..eae63619c579d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -101,6 +101,8 @@ main!( 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_fmaf_group, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 511e26d912672..bd7b3597196ce 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -125,8 +125,10 @@ libm_macros::for_each_function! { | fabsf16 | fdimf128 | fdimf16 - | sqrtf16 + | floorf128 + | floorf16 | sqrtf128 + | sqrtf16 | truncf128 | truncf16 => (false, None), diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index bbd19dbb07bac..53fade7d0ef6d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -148,6 +148,8 @@ libm_macros::for_each_function! { fabsf128, fabsf16,floor, floorf, + floorf128, + floorf16, fmod, fmodf, frexp, @@ -240,6 +242,7 @@ impl_no_round! { impl_no_round! { fabsf16 => abs_mut; ceilf16 => ceil_mut; + floorf16 => floor_mut; truncf16 => trunc_mut; } @@ -247,6 +250,7 @@ impl_no_round! { impl_no_round! { fabsf128 => abs_mut; ceilf128 => ceil_mut; + floorf128 => floor_mut; truncf128 => trunc_mut; } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index e13acf3de216a..335496fce36c4 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -87,6 +87,8 @@ libm_macros::for_each_function! { fabsf16, fdimf128, fdimf16, + floorf128, + floorf16, truncf128, truncf16, sqrtf16, diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index 810919339ec6f..988c01d076072 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -92,6 +92,8 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | fabsf16 | fdimf128 | fdimf16 + | floorf128 + | floorf16 | sqrtf128 | sqrtf16 | truncf128 diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 6a865f42784d8..eef176fb57c8e 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -349,6 +349,20 @@ ], "type": "f32" }, + "floorf128": { + "sources": [ + "src/math/floorf128.rs", + "src/math/generic/floor.rs" + ], + "type": "f128" + }, + "floorf16": { + "sources": [ + "src/math/floorf16.rs", + "src/math/generic/floor.rs" + ], + "type": "f16" + }, "fma": { "sources": [ "src/libm_helper.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 337e7e434e5f2..3bb895f4a2976 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -49,6 +49,8 @@ fdimf128 fdimf16 floor floorf +floorf128 +floorf16 fma fmaf fmax diff --git a/library/compiler-builtins/libm/src/math/floorf128.rs b/library/compiler-builtins/libm/src/math/floorf128.rs new file mode 100644 index 0000000000000..9a9fe4151152b --- /dev/null +++ b/library/compiler-builtins/libm/src/math/floorf128.rs @@ -0,0 +1,7 @@ +/// Floor (f128) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf128(x: f128) -> f128 { + return super::generic::floor(x); +} diff --git a/library/compiler-builtins/libm/src/math/floorf16.rs b/library/compiler-builtins/libm/src/math/floorf16.rs new file mode 100644 index 0000000000000..f9b868e04109d --- /dev/null +++ b/library/compiler-builtins/libm/src/math/floorf16.rs @@ -0,0 +1,7 @@ +/// Floor (f16) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf16(x: f16) -> f16 { + return super::generic::floor(x); +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 5228e78b7f333..68d201524b4be 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -345,6 +345,7 @@ cfg_if! { mod copysignf16; mod fabsf16; mod fdimf16; + mod floorf16; mod sqrtf16; mod truncf16; @@ -352,6 +353,7 @@ cfg_if! { pub use self::copysignf16::copysignf16; pub use self::fabsf16::fabsf16; pub use self::fdimf16::fdimf16; + pub use self::floorf16::floorf16; pub use self::sqrtf16::sqrtf16; pub use self::truncf16::truncf16; } @@ -363,6 +365,7 @@ cfg_if! { mod copysignf128; mod fabsf128; mod fdimf128; + mod floorf128; mod sqrtf128; mod truncf128; @@ -370,6 +373,7 @@ cfg_if! { pub use self::copysignf128::copysignf128; pub use self::fabsf128::fabsf128; pub use self::fdimf128::fdimf128; + pub use self::floorf128::floorf128; pub use self::sqrtf128::sqrtf128; pub use self::truncf128::truncf128; } From 3ae70a4a6cdf1bd11be554ac3ba272707ce8da56 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 22 Jan 2025 08:48:02 +0000 Subject: [PATCH 1596/4206] Adjust `ceil` style to be more similar to `floor` --- .../crates/compiler-builtins-smoke-test/src/lib.rs | 2 ++ .../compiler-builtins/libm/src/math/generic/ceil.rs | 12 ++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index 4834ba256eb2f..1a7aa983ee44f 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -67,6 +67,8 @@ no_mangle! { cbrtf(x: f32) -> f32; ceil(x: f64) -> f64; ceilf(x: f32) -> f32; + ceilf128(x: f128) -> f128; + ceilf16(x: f16) -> f16; copysign(x: f64, y: f64) -> f64; copysignf(x: f32, y: f32) -> f32; copysignf128(x: f128, y: f128) -> f128; diff --git a/library/compiler-builtins/libm/src/math/generic/ceil.rs b/library/compiler-builtins/libm/src/math/generic/ceil.rs index 34261faf782f9..971a4d3d8c5ff 100644 --- a/library/compiler-builtins/libm/src/math/generic/ceil.rs +++ b/library/compiler-builtins/libm/src/math/generic/ceil.rs @@ -31,24 +31,28 @@ pub fn ceil(x: F) -> F { // Otherwise, raise an inexact exception. force_eval!(x + F::MAX); + if x.is_sign_positive() { ix += m; } + ix &= !m; + F::from_bits(ix) } else { // |x| < 1.0, raise an inexact exception since truncation will happen (unless x == 0). force_eval!(x + F::MAX); if x.is_sign_negative() { // -1.0 < x <= -0.0; rounding up goes toward -0.0. - return F::NEG_ZERO; + F::NEG_ZERO } else if ix << 1 != zero { // 0.0 < x < 1.0; rounding up goes toward +1.0. - return F::ONE; + F::ONE + } else { + // +0.0 remains unchanged + x } } - - F::from_bits(ix) } #[cfg(test)] From bf2d171b1a29849b745cfd0dd6409c0c2b3c0cea Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 22 Jan 2025 09:06:26 +0000 Subject: [PATCH 1597/4206] Add a generic version of `rint` Use this to implement `rint` and `rintf`. --- .../libm/etc/function-definitions.json | 2 + .../libm/src/math/generic/mod.rs | 2 + .../libm/src/math/generic/rint.rs | 72 +++++++++++++++++++ .../compiler-builtins/libm/src/math/rint.rs | 48 +------------ .../compiler-builtins/libm/src/math/rintf.rs | 48 +------------ 5 files changed, 78 insertions(+), 94 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/rint.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index eef176fb57c8e..86b0882927ccd 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -654,6 +654,7 @@ "src/libm_helper.rs", "src/math/arch/aarch64.rs", "src/math/arch/wasm32.rs", + "src/math/generic/rint.rs", "src/math/rint.rs" ], "type": "f64" @@ -662,6 +663,7 @@ "sources": [ "src/math/arch/aarch64.rs", "src/math/arch/wasm32.rs", + "src/math/generic/rint.rs", "src/math/rintf.rs" ], "type": "f32" diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index b08a77d5d6493..d3df650e1a5be 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -3,6 +3,7 @@ mod copysign; mod fabs; mod fdim; mod floor; +mod rint; mod sqrt; mod trunc; @@ -11,5 +12,6 @@ pub use copysign::copysign; pub use fabs::fabs; pub use fdim::fdim; pub use floor::floor; +pub use rint::rint; pub use sqrt::sqrt; pub use trunc::trunc; diff --git a/library/compiler-builtins/libm/src/math/generic/rint.rs b/library/compiler-builtins/libm/src/math/generic/rint.rs new file mode 100644 index 0000000000000..80ba1faac3111 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/rint.rs @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/rint.c */ + +use super::super::Float; + +pub fn rint(x: F) -> F { + let toint = F::ONE / F::EPSILON; + let e = x.exp(); + let positive = x.is_sign_positive(); + + // 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 use_force = cfg!(x86_no_sse) && F::BITS == 32 || F::BITS == 64; + + if e >= F::EXP_BIAS + F::SIG_BITS { + // No fractional part; exact result can be returned. + x + } else { + // Apply a net-zero adjustment that nudges `y` in the direction of the rounding mode. + let y = if positive { + let tmp = if use_force { force_eval!(x) } else { x } + toint; + (if use_force { force_eval!(tmp) } else { tmp } - toint) + } else { + let tmp = if use_force { force_eval!(x) } else { x } - toint; + (if use_force { force_eval!(tmp) } else { tmp } + toint) + }; + + if y == F::ZERO { + // A zero result takes the sign of the input. + if positive { F::ZERO } else { F::NEG_ZERO } + } else { + y + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn zeroes_f32() { + assert_biteq!(rint(0.0_f32), 0.0_f32); + assert_biteq!(rint(-0.0_f32), -0.0_f32); + } + + #[test] + fn sanity_check_f32() { + assert_biteq!(rint(-1.0_f32), -1.0); + assert_biteq!(rint(2.8_f32), 3.0); + assert_biteq!(rint(-0.5_f32), -0.0); + assert_biteq!(rint(0.5_f32), 0.0); + assert_biteq!(rint(-1.5_f32), -2.0); + assert_biteq!(rint(1.5_f32), 2.0); + } + + #[test] + fn zeroes_f64() { + assert_biteq!(rint(0.0_f64), 0.0_f64); + assert_biteq!(rint(-0.0_f64), -0.0_f64); + } + + #[test] + fn sanity_check_f64() { + assert_biteq!(rint(-1.0_f64), -1.0); + assert_biteq!(rint(2.8_f64), 3.0); + assert_biteq!(rint(-0.5_f64), -0.0); + assert_biteq!(rint(0.5_f64), 0.0); + assert_biteq!(rint(-1.5_f64), -2.0); + assert_biteq!(rint(1.5_f64), 2.0); + } +} diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index c9ea6402ec73d..592583aa5e54e 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -9,51 +9,5 @@ pub fn rint(x: f64) -> f64 { args: x, } - let one_over_e = 1.0 / f64::EPSILON; - let as_u64: u64 = x.to_bits(); - let exponent: u64 = (as_u64 >> 52) & 0x7ff; - let is_positive = (as_u64 >> 63) == 0; - if exponent >= 0x3ff + 52 { - x - } else { - let ans = if is_positive { - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let x = force_eval!(x); - let xplusoneovere = x + one_over_e; - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let xplusoneovere = force_eval!(xplusoneovere); - xplusoneovere - one_over_e - } else { - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let x = force_eval!(x); - let xminusoneovere = x - one_over_e; - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let xminusoneovere = force_eval!(xminusoneovere); - xminusoneovere + one_over_e - }; - - if ans == 0.0 { if is_positive { 0.0 } else { -0.0 } } else { ans } - } -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::rint; - - #[test] - fn negative_zero() { - assert_eq!(rint(-0.0_f64).to_bits(), (-0.0_f64).to_bits()); - } - - #[test] - fn sanity_check() { - assert_eq!(rint(-1.0), -1.0); - assert_eq!(rint(2.8), 3.0); - assert_eq!(rint(-0.5), -0.0); - assert_eq!(rint(0.5), 0.0); - assert_eq!(rint(-1.5), -2.0); - assert_eq!(rint(1.5), 2.0); - } + super::generic::rint(x) } diff --git a/library/compiler-builtins/libm/src/math/rintf.rs b/library/compiler-builtins/libm/src/math/rintf.rs index 33b5b3ddebf67..56666df115428 100644 --- a/library/compiler-builtins/libm/src/math/rintf.rs +++ b/library/compiler-builtins/libm/src/math/rintf.rs @@ -9,51 +9,5 @@ pub fn rintf(x: f32) -> f32 { args: x, } - let one_over_e = 1.0 / f32::EPSILON; - let as_u32: u32 = x.to_bits(); - let exponent: u32 = (as_u32 >> 23) & 0xff; - let is_positive = (as_u32 >> 31) == 0; - if exponent >= 0x7f + 23 { - x - } else { - let ans = if is_positive { - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let x = force_eval!(x); - let xplusoneovere = x + one_over_e; - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let xplusoneovere = force_eval!(xplusoneovere); - xplusoneovere - one_over_e - } else { - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let x = force_eval!(x); - let xminusoneovere = x - one_over_e; - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let xminusoneovere = force_eval!(xminusoneovere); - xminusoneovere + one_over_e - }; - - if ans == 0.0 { if is_positive { 0.0 } else { -0.0 } } else { ans } - } -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::rintf; - - #[test] - fn negative_zero() { - assert_eq!(rintf(-0.0_f32).to_bits(), (-0.0_f32).to_bits()); - } - - #[test] - fn sanity_check() { - assert_eq!(rintf(-1.0), -1.0); - assert_eq!(rintf(2.8), 3.0); - assert_eq!(rintf(-0.5), -0.0); - assert_eq!(rintf(0.5), 0.0); - assert_eq!(rintf(-1.5), -2.0); - assert_eq!(rintf(1.5), 2.0); - } + super::generic::rint(x) } From b22398d6580d1f90e020404e427b06403d204c9f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 22 Jan 2025 10:58:29 +0000 Subject: [PATCH 1598/4206] Add `rintf16` and `rintf128` Use the generic algorithms to provide implementations for these routines. --- .../crates/compiler-builtins-smoke-test/src/lib.rs | 2 ++ .../libm/crates/libm-macros/src/shared.rs | 4 ++-- .../libm/crates/libm-test/benches/icount.rs | 2 ++ .../libm/crates/libm-test/benches/random.rs | 2 ++ .../libm/crates/libm-test/src/mpfloat.rs | 8 ++++++-- .../crates/libm-test/tests/compare_built_musl.rs | 6 ++++-- .../compiler-builtins/libm/crates/util/src/main.rs | 2 ++ .../libm/etc/function-definitions.json | 14 ++++++++++++++ .../compiler-builtins/libm/etc/function-list.txt | 2 ++ library/compiler-builtins/libm/src/math/mod.rs | 4 ++++ library/compiler-builtins/libm/src/math/rint.rs | 1 + library/compiler-builtins/libm/src/math/rintf.rs | 1 + .../compiler-builtins/libm/src/math/rintf128.rs | 5 +++++ library/compiler-builtins/libm/src/math/rintf16.rs | 5 +++++ 14 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/rintf128.rs create mode 100644 library/compiler-builtins/libm/src/math/rintf16.rs diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index 1a7aa983ee44f..ccd0642a20e38 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -145,6 +145,8 @@ no_mangle! { remquof(x: f32, y: f32 | q: &mut c_int) -> f32; rint(x: f64) -> f64; rintf(x: f32) -> f32; + rintf128(x: f128) -> f128; + rintf16(x: f16) -> f16; round(x: f64) -> f64; roundf(x: f32) -> f32; scalbn(x: f64, y: c_int) -> f64; diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index 64623658d655d..80bd3e90753b3 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -9,7 +9,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16], returns: &[Ty::F16] }, None, - &["ceilf16", "fabsf16", "floorf16", "sqrtf16", "truncf16"], + &["ceilf16", "fabsf16", "floorf16", "rintf16", "sqrtf16", "truncf16"], ), ( // `fn(f32) -> f32` @@ -40,7 +40,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F128, Signature { args: &[Ty::F128], returns: &[Ty::F128] }, None, - &["ceilf128", "fabsf128", "floorf128", "sqrtf128", "truncf128"], + &["ceilf128", "fabsf128", "floorf128", "rintf128", "sqrtf128", "truncf128"], ), ( // `(f16, f16) -> f16` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index eae63619c579d..84f9532626799 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -149,6 +149,8 @@ main!( 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_roundf_group, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index bd7b3597196ce..4d050e817e235 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -127,6 +127,8 @@ libm_macros::for_each_function! { | fdimf16 | floorf128 | floorf16 + | rintf128 + | rintf16 | sqrtf128 | sqrtf16 | truncf128 diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 53fade7d0ef6d..a404f227b2623 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -170,6 +170,8 @@ libm_macros::for_each_function! { remquof, rint, rintf, + rintf128, + rintf16, round, roundf, scalbn, @@ -240,17 +242,19 @@ impl_no_round! { #[cfg(f16_enabled)] impl_no_round! { - fabsf16 => abs_mut; ceilf16 => ceil_mut; + fabsf16 => abs_mut; floorf16 => floor_mut; + rintf16 => round_even_mut; // FIXME: respect rounding mode truncf16 => trunc_mut; } #[cfg(f128_enabled)] impl_no_round! { - fabsf128 => abs_mut; ceilf128 => ceil_mut; + fabsf128 => abs_mut; floorf128 => floor_mut; + rintf128 => round_even_mut; // FIXME: respect rounding mode truncf128 => trunc_mut; } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 335496fce36c4..f009816c97f14 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -89,9 +89,11 @@ libm_macros::for_each_function! { fdimf16, floorf128, floorf16, + rintf128, + rintf16, + sqrtf128, + sqrtf16, truncf128, truncf16, - sqrtf16, - sqrtf128, ], } diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index 988c01d076072..41d995b3b395f 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -94,6 +94,8 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | fdimf16 | floorf128 | floorf16 + | rintf128 + | rintf16 | sqrtf128 | sqrtf16 | truncf128 diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 86b0882927ccd..d3810b940cb03 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -668,6 +668,20 @@ ], "type": "f32" }, + "rintf128": { + "sources": [ + "src/math/generic/rint.rs", + "src/math/rintf128.rs" + ], + "type": "f128" + }, + "rintf16": { + "sources": [ + "src/math/generic/rint.rs", + "src/math/rintf16.rs" + ], + "type": "f16" + }, "round": { "sources": [ "src/libm_helper.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 3bb895f4a2976..41bb4e06be8d1 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -97,6 +97,8 @@ remquo remquof rint rintf +rintf128 +rintf16 round roundf scalbn diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 68d201524b4be..53d06974ceec5 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -346,6 +346,7 @@ cfg_if! { mod fabsf16; mod fdimf16; mod floorf16; + mod rintf16; mod sqrtf16; mod truncf16; @@ -354,6 +355,7 @@ cfg_if! { pub use self::fabsf16::fabsf16; pub use self::fdimf16::fdimf16; pub use self::floorf16::floorf16; + pub use self::rintf16::rintf16; pub use self::sqrtf16::sqrtf16; pub use self::truncf16::truncf16; } @@ -366,6 +368,7 @@ cfg_if! { mod fabsf128; mod fdimf128; mod floorf128; + mod rintf128; mod sqrtf128; mod truncf128; @@ -374,6 +377,7 @@ cfg_if! { pub use self::fabsf128::fabsf128; pub use self::fdimf128::fdimf128; pub use self::floorf128::floorf128; + pub use self::rintf128::rintf128; pub use self::sqrtf128::sqrtf128; pub use self::truncf128::truncf128; } diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index 592583aa5e54e..f409ec2821d87 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -1,3 +1,4 @@ +/// Round `x` to the nearest integer, breaking ties toward even. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn rint(x: f64) -> f64 { select_implementation! { diff --git a/library/compiler-builtins/libm/src/math/rintf.rs b/library/compiler-builtins/libm/src/math/rintf.rs index 56666df115428..5e9f5f7187697 100644 --- a/library/compiler-builtins/libm/src/math/rintf.rs +++ b/library/compiler-builtins/libm/src/math/rintf.rs @@ -1,3 +1,4 @@ +/// Round `x` to the nearest integer, breaking ties toward even. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn rintf(x: f32) -> f32 { select_implementation! { diff --git a/library/compiler-builtins/libm/src/math/rintf128.rs b/library/compiler-builtins/libm/src/math/rintf128.rs new file mode 100644 index 0000000000000..6b16fcd841a67 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/rintf128.rs @@ -0,0 +1,5 @@ +/// Round `x` to the nearest integer, breaking ties toward even. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn rintf128(x: f128) -> f128 { + super::generic::rint(x) +} diff --git a/library/compiler-builtins/libm/src/math/rintf16.rs b/library/compiler-builtins/libm/src/math/rintf16.rs new file mode 100644 index 0000000000000..84d792561f742 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/rintf16.rs @@ -0,0 +1,5 @@ +/// Round `x` to the nearest integer, breaking ties toward even. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn rintf16(x: f16) -> f16 { + super::generic::rint(x) +} From c788ced5022520ed2adbdbb788c18478b8f201b2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 22 Jan 2025 21:31:06 +0000 Subject: [PATCH 1599/4206] Add the ability to parse hex, binary, and float hex with util --- .../libm/crates/util/src/main.rs | 94 ++++++++++++++++++- 1 file changed, 89 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index 41d995b3b395f..23aed06c00d7d 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -5,10 +5,12 @@ use std::any::type_name; use std::env; +use std::num::ParseIntError; use std::str::FromStr; #[cfg(feature = "build-mpfr")] use az::Az; +use libm::support::{hf32, hf64}; #[cfg(feature = "build-mpfr")] use libm_test::mpfloat::MpOp; use libm_test::{MathOp, TupleCall}; @@ -238,21 +240,103 @@ impl_parse_tuple_via_rug!(f16); impl_parse_tuple_via_rug!(f128); /// Try to parse the number, printing a nice message on failure. -fn parse(input: &[&str], idx: usize) -> F { +fn parse(input: &[&str], idx: usize) -> T { let s = input[idx]; - s.parse().unwrap_or_else(|_| panic!("invalid {} input '{s}'", type_name::())) + + let msg = || format!("invalid {} input '{s}'", type_name::()); + + if s.starts_with("0x") { + return T::from_str_radix(s, 16).unwrap_or_else(|_| panic!("{}", msg())); + } + + if s.starts_with("0b") { + return T::from_str_radix(s, 2).unwrap_or_else(|_| panic!("{}", msg())); + } + + s.parse().unwrap_or_else(|_| panic!("{}", msg())) } /// Try to parse the float type going via `rug`, for `f16` and `f128` which don't yet implement /// `FromStr`. #[cfg(feature = "build-mpfr")] -fn parse_rug(input: &[&str], idx: usize) -> F +fn parse_rug(input: &[&str], idx: usize) -> F where + F: libm_test::Float + FromStrRadix, rug::Float: az::Cast, { let s = input[idx]; - let x = - rug::Float::parse(s).unwrap_or_else(|_| panic!("invalid {} input '{s}'", type_name::())); + + let msg = || format!("invalid {} input '{s}'", type_name::()); + + if s.starts_with("0x") { + return F::from_str_radix(s, 16).unwrap_or_else(|_| panic!("{}", msg())); + } + + if s.starts_with("0b") { + return F::from_str_radix(s, 2).unwrap_or_else(|_| panic!("{}", msg())); + } + + let x = rug::Float::parse(s).unwrap_or_else(|_| panic!("{}", msg())); let x = rug::Float::with_val(F::BITS, x); x.az() } + +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 { + let s = strip_radix_prefix(s, radix); + u16::from_str_radix(s, radix).map(Self::from_bits) + } +} + +impl FromStrRadix for f32 { + fn from_str_radix(s: &str, radix: u32) -> Result { + if radix == 16 && s.contains("p") { + // Parse as hex float + return Ok(hf32(s)); + } + + let s = strip_radix_prefix(s, radix); + u32::from_str_radix(s, radix).map(Self::from_bits) + } +} + +impl FromStrRadix for f64 { + fn from_str_radix(s: &str, radix: u32) -> Result { + if s.contains("p") { + return Ok(hf64(s)); + } + + let s = strip_radix_prefix(s, radix); + u64::from_str_radix(s, radix).map(Self::from_bits) + } +} + +#[cfg(f128_enabled)] +impl FromStrRadix for f128 { + fn from_str_radix(s: &str, radix: u32) -> Result { + let s = strip_radix_prefix(s, radix); + u128::from_str_radix(s, radix).map(Self::from_bits) + } +} + +fn strip_radix_prefix(s: &str, radix: u32) -> &str { + if radix == 16 { + s.strip_prefix("0x").unwrap() + } else if radix == 2 { + s.strip_prefix("0b").unwrap() + } else { + s + } +} From 42e22132b41f3ee3839355513173854f17b460f5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 22 Jan 2025 23:01:29 +0000 Subject: [PATCH 1600/4206] Fix the parsing of three-item tuples in `util` --- library/compiler-builtins/libm/crates/util/src/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index 23aed06c00d7d..889823d2e4ab4 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -146,8 +146,8 @@ macro_rules! impl_parse_tuple { impl ParseTuple for ($ty, $ty, $ty) { fn parse(input: &[&str]) -> Self { - assert_eq!(input.len(), 2, "expected three arguments, got {input:?}"); - (parse(input, 0), parse(input, 1), parse(input, 3)) + assert_eq!(input.len(), 3, "expected three arguments, got {input:?}"); + (parse(input, 0), parse(input, 1), parse(input, 2)) } } }; @@ -187,8 +187,8 @@ macro_rules! impl_parse_tuple_via_rug { impl ParseTuple for ($ty, $ty, $ty) { fn parse(input: &[&str]) -> Self { - assert_eq!(input.len(), 2, "expected three arguments, got {input:?}"); - (parse_rug(input, 0), parse_rug(input, 1), parse_rug(input, 3)) + assert_eq!(input.len(), 3, "expected three arguments, got {input:?}"); + (parse_rug(input, 0), parse_rug(input, 1), parse_rug(input, 2)) } } }; From 8dc4ef6f0fb9df5da1bcd9931c018d9233595d53 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 22 Jan 2025 22:41:49 +0000 Subject: [PATCH 1601/4206] Add `hf16!` and `hf128!` Expand the existing hex float functions and macros with versions that work with `f16` and `f128`. --- .../libm/src/math/support/hex_float.rs | 246 +++++++++++++++++- .../libm/src/math/support/macros.rs | 22 ++ .../libm/src/math/support/mod.rs | 4 + 3 files changed, 266 insertions(+), 6 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 1666c6153608a..949f21a57ff35 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -4,6 +4,12 @@ use super::{f32_from_bits, f64_from_bits}; +/// Construct a 16-bit float from hex float representation (C-style) +#[cfg(f16_enabled)] +pub const fn hf16(s: &str) -> f16 { + f16::from_bits(parse_any(s, 16, 10) as u16) +} + /// Construct a 32-bit float from hex float representation (C-style) pub const fn hf32(s: &str) -> f32 { f32_from_bits(parse_any(s, 32, 23) as u32) @@ -14,6 +20,12 @@ pub const fn hf64(s: &str) -> f64 { f64_from_bits(parse_any(s, 64, 52) as u64) } +/// Construct a 128-bit float from hex float representation (C-style) +#[cfg(f128_enabled)] +pub const fn hf128(s: &str) -> f128 { + f128::from_bits(parse_any(s, 128, 112)) +} + const fn parse_any(s: &str, bits: u32, sig_bits: u32) -> u128 { let exp_bits: u32 = bits - sig_bits - 1; let max_msb: i32 = (1 << (exp_bits - 1)) - 1; @@ -230,6 +242,57 @@ mod tests { } } + // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to + // hide them from the AST. + #[cfg(f16_enabled)] + macro_rules! f16_tests { + () => { + #[test] + fn test_f16() { + let checks = [ + ("0x.1234p+16", (0x1234 as f16).to_bits()), + ("0x1.234p+12", (0x1234 as f16).to_bits()), + ("0x12.34p+8", (0x1234 as f16).to_bits()), + ("0x123.4p+4", (0x1234 as f16).to_bits()), + ("0x1234p+0", (0x1234 as f16).to_bits()), + ("0x1234.p+0", (0x1234 as f16).to_bits()), + ("0x1234.0p+0", (0x1234 as f16).to_bits()), + ("0x1.ffcp+15", f16::MAX.to_bits()), + ("0x1.0p+1", 2.0f16.to_bits()), + ("0x1.0p+0", 1.0f16.to_bits()), + ("0x1.ffp+8", 0x5ffc), + ("+0x1.ffp+8", 0x5ffc), + ("0x1p+0", 0x3c00), + ("0x1.998p-4", 0x2e66), + ("0x1.9p+6", 0x5640), + ("0x0.0p0", 0.0f16.to_bits()), + ("-0x0.0p0", (-0.0f16).to_bits()), + ("0x1.0p0", 1.0f16.to_bits()), + ("0x1.998p-4", (0.1f16).to_bits()), + ("-0x1.998p-4", (-0.1f16).to_bits()), + ("0x0.123p-12", 0x0123), + ("0x1p-24", 0x0001), + ]; + for (s, exp) in checks { + println!("parsing {s}"); + let act = hf16(s).to_bits(); + assert_eq!( + act, exp, + "parsing {s}: {act:#06x} != {exp:#06x}\nact: {act:#018b}\nexp: {exp:#018b}" + ); + } + } + + #[test] + fn test_macros_f16() { + assert_eq!(hf16!("0x1.ffp+8").to_bits(), 0x5ffc_u16); + } + }; + } + + #[cfg(f16_enabled)] + f16_tests!(); + #[test] fn test_f32() { let checks = [ @@ -308,16 +371,67 @@ mod tests { } } - #[test] - fn test_f32_almost_extra_precision() { - // Exact maximum precision allowed - hf32("0x1.abcdeep+0"); + // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to + // hide them from the AST. + #[cfg(f128_enabled)] + macro_rules! f128_tests { + () => { + #[test] + fn test_f128() { + let checks = [ + ("0x.1234p+16", (0x1234 as f128).to_bits()), + ("0x1.234p+12", (0x1234 as f128).to_bits()), + ("0x12.34p+8", (0x1234 as f128).to_bits()), + ("0x123.4p+4", (0x1234 as f128).to_bits()), + ("0x1234p+0", (0x1234 as f128).to_bits()), + ("0x1234.p+0", (0x1234 as f128).to_bits()), + ("0x1234.0p+0", (0x1234 as f128).to_bits()), + ("0x1.ffffffffffffffffffffffffffffp+16383", f128::MAX.to_bits()), + ("0x1.0p+1", 2.0f128.to_bits()), + ("0x1.0p+0", 1.0f128.to_bits()), + ("0x1.ffep+8", 0x4007ffe0000000000000000000000000), + ("+0x1.ffep+8", 0x4007ffe0000000000000000000000000), + ("0x1p+0", 0x3fff0000000000000000000000000000), + ("0x1.999999999999999999999999999ap-4", 0x3ffb999999999999999999999999999a), + ("0x1.9p+6", 0x40059000000000000000000000000000), + ("0x0.0p0", 0.0f128.to_bits()), + ("-0x0.0p0", (-0.0f128).to_bits()), + ("0x1.0p0", 1.0f128.to_bits()), + ("0x1.999999999999999999999999999ap-4", (0.1f128).to_bits()), + ("-0x1.999999999999999999999999999ap-4", (-0.1f128).to_bits()), + ("0x0.abcdef0123456789abcdef012345p-16382", 0x0000abcdef0123456789abcdef012345), + ("0x1p-16494", 0x00000000000000000000000000000001), + ]; + for (s, exp) in checks { + println!("parsing {s}"); + let act = hf128(s).to_bits(); + assert_eq!( + act, exp, + "parsing {s}: {act:#034x} != {exp:#034x}\nact: {act:#0130b}\nexp: {exp:#0130b}" + ); + } + } + + #[test] + fn test_macros_f128() { + assert_eq!(hf128!("0x1.ffep+8").to_bits(), 0x4007ffe0000000000000000000000000_u128); + } + } } + #[cfg(f128_enabled)] + f128_tests!(); + #[test] fn test_macros() { - assert_eq!(hf32!("0x1.ffep+8").to_bits(), 0x43fff000u32); - assert_eq!(hf64!("0x1.ffep+8").to_bits(), 0x407ffe0000000000u64); + // FIXME(msrv): enable once parsing works + // #[cfg(f16_enabled)] + // assert_eq!(hf16!("0x1.ffp+8").to_bits(), 0x5ffc_u16); + assert_eq!(hf32!("0x1.ffep+8").to_bits(), 0x43fff000_u32); + assert_eq!(hf64!("0x1.ffep+8").to_bits(), 0x407ffe0000000000_u64); + // FIXME(msrv): enable once parsing works + // #[cfg(f128_enabled)] + // assert_eq!(hf128!("0x1.ffep+8").to_bits(), 0x4007ffe0000000000000000000000000_u128); } } @@ -328,6 +442,69 @@ 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. + #[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"); + } + + #[test] + #[should_panic(expected = "the value is too huge")] + fn test_f16_overflow() { + // One bit more than the above. + hf16("0x1p+16"); + } + + #[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] + #[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_also_too_tiny() { + hf16("0x0.8p-24"); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f16_again_too_tiny() { + hf16("0x0.001p-13"); + } + }; + } + + #[cfg(f16_enabled)] + f16_tests!(); + + #[test] + fn test_f32_almost_extra_precision() { + // Exact maximum precision allowed + hf32("0x1.abcdeep+0"); + } + #[test] #[should_panic] fn test_f32_extra_precision2() { @@ -388,4 +565,61 @@ mod tests_panicking { // One bit more than the above. 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. + #[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() { + // One bit more than the above. + hf128("0x1.ffffffffffffffffffffffffffff8p+16383"); + } + + #[test] + #[should_panic(expected = "the value is too huge")] + fn test_f128_overflow() { + // One bit more than the above. + hf128("0x1p+16384"); + } + + #[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] + #[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_again_too_tiny() { + hf128("0x0.0000000000000001p-16431"); + } + + #[test] + #[should_panic(expected = "the value is too tiny")] + fn test_f128_also_too_tiny() { + hf128("0x0.8p-16494"); + } + }; + } + + #[cfg(f128_enabled)] + f128_tests!(); } diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index c9a36c0db1a7b..d8ba04cffe7f0 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -87,6 +87,17 @@ macro_rules! select_implementation { (@cfg $provided:meta; $ex:expr) => { #[cfg($provided)] $ex }; } +/// Construct a 16-bit float from hex float representation (C-style), guaranteed to +/// evaluate at compile time. +#[cfg(f16_enabled)] +#[allow(unused_macros)] +macro_rules! hf16 { + ($s:literal) => {{ + const X: f16 = $crate::math::support::hf16($s); + X + }}; +} + /// Construct a 32-bit float from hex float representation (C-style), guaranteed to /// evaluate at compile time. #[allow(unused_macros)] @@ -107,6 +118,17 @@ macro_rules! hf64 { }}; } +/// Construct a 128-bit float from hex float representation (C-style), guaranteed to +/// evaluate at compile time. +#[cfg(f128_enabled)] +#[allow(unused_macros)] +macro_rules! hf128 { + ($s:literal) => {{ + const X: f128 = $crate::math::support::hf128($s); + X + }}; +} + /// Assert `F::biteq` with better messages. #[cfg(test)] macro_rules! assert_biteq { diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index ddfc2e3e0717a..da9e2c9ed62cb 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -8,6 +8,10 @@ mod int_traits; #[allow(unused_imports)] pub use float_traits::{Float, IntTy}; pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; +#[cfg(f16_enabled)] +pub use hex_float::hf16; +#[cfg(f128_enabled)] +pub use hex_float::hf128; #[allow(unused_imports)] pub use hex_float::{hf32, hf64}; pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; From ca8dccc5b6638aba06f4d3c06493500af3146846 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 23 Jan 2025 05:08:10 +0000 Subject: [PATCH 1602/4206] Introduce XFAILs that assert failure Currently our XFAILs are open ended; we do not check that it actually fails, so we have no easy way of knowing that a previously-failing test starts passing. Introduce a new enum that we return from overrides to give us more flexibility here, including the ability to assert that expected failures happen. With the new enum, it is also possible to specify ULP via return value rather than passing a `&mut u32` parameter. This includes refactoring of `precision.rs` to be more accurate about where errors come from, if possible. Fixes: https://github.com/rust-lang/libm/issues/455 --- .../libm/crates/libm-test/src/precision.rs | 461 +++++++++--------- .../libm/crates/libm-test/src/test_traits.rs | 60 ++- 2 files changed, 268 insertions(+), 253 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 9d17ab8cccfd3..800425f12adfc 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -118,13 +118,13 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { // FIXME(#401): these need to be correctly rounded but are not. Id::Fmaf => ulp = 1, Id::Fdim => ulp = 1, + Id::Round => ulp = 1, Id::Asinh => ulp = 3, Id::Asinhf => ulp = 3, Id::Exp10 | Id::Exp10f => ulp = 1_000_000, Id::Exp2 | Id::Exp2f => ulp = 10_000_000, Id::Log1p | Id::Log1pf => ulp = 2, - Id::Round => ulp = 1, Id::Tan => ulp = 2, _ => (), } @@ -133,12 +133,42 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { ulp } +/// Result of checking for possible overrides. +#[derive(Debug, Default)] +pub enum CheckAction { + /// The check should pass. Default case. + #[default] + AssertSuccess, + + /// Override the ULP for this check. + AssertWithUlp(u32), + + /// Failure is expected, ensure this is the case (xfail). Takes a contxt string to help trace + /// back exactly why we expect this to fail. + AssertFailure(&'static str), + + /// The override somehow validated the result, here it is. + Custom(TestResult), + + /// Disregard the output. + Skip, +} + /// Don't run further validation on this test case. -const SKIP: Option = Some(Ok(())); +const SKIP: CheckAction = CheckAction::Skip; -/// Return this to skip checks on a test that currently fails but shouldn't. Looks -/// the same as skip, but we keep them separate to better indicate purpose. -const XFAIL: Option = Some(Ok(())); +/// Return this to skip checks on a test that currently fails but shouldn't. Takes a description +/// of context. +const XFAIL: fn(&'static str) -> CheckAction = CheckAction::AssertFailure; + +/// Indicates that we expect a test to fail but we aren't asserting that it does (e.g. some results +/// within a range do actually pass). +/// +/// Same as `SKIP`, just indicates we have something to eventually fix. +const XFAIL_NOCHECK: CheckAction = CheckAction::Skip; + +/// By default, all tests should pass. +const DEFAULT: CheckAction = CheckAction::AssertSuccess; /// Allow overriding the outputs of specific test cases. /// @@ -158,19 +188,13 @@ pub trait MaybeOverride { _input: Input, _actual: F, _expected: F, - _ulp: &mut u32, _ctx: &CheckCtx, - ) -> Option { - None + ) -> CheckAction { + DEFAULT } - fn check_int( - _input: Input, - _actual: I, - _expected: I, - _ctx: &CheckCtx, - ) -> Option { - None + fn check_int(_input: Input, _actual: I, _expected: I, _ctx: &CheckCtx) -> CheckAction { + DEFAULT } } @@ -178,33 +202,35 @@ pub trait MaybeOverride { impl MaybeOverride<(f16,)> for SpecialCase {} impl MaybeOverride<(f32,)> for SpecialCase { - fn check_float( - input: (f32,), - actual: F, - expected: F, - _ulp: &mut u32, - ctx: &CheckCtx, - ) -> Option { - if ctx.base_name == BaseName::Expm1 && input.0 > 80.0 && actual.is_infinite() { + fn check_float(input: (f32,), actual: F, expected: F, ctx: &CheckCtx) -> CheckAction { + if ctx.base_name == BaseName::Expm1 + && !input.0.is_infinite() + && input.0 > 80.0 + && actual.is_infinite() + && !expected.is_infinite() + { // we return infinity but the number is representable - return XFAIL; - } - - if ctx.base_name == BaseName::Sinh && input.0.abs() > 80.0 && actual.is_nan() { - // we return some NaN that should be real values or infinite - return XFAIL; + if ctx.basis == CheckBasis::Musl { + return XFAIL_NOCHECK; + } + return XFAIL("expm1 representable numbers"); } - if ctx.base_name == BaseName::Acosh && input.0 < -1.0 { - // acoshf is undefined for x <= 1.0, but we return a random result at lower - // values. - return XFAIL; + if cfg!(x86_no_sse) + && ctx.base_name == BaseName::Exp2 + && !expected.is_infinite() + && actual.is_infinite() + { + // We return infinity when there is a representable value. Test input: 127.97238 + return XFAIL("586 exp2 representable numbers"); } - if ctx.base_name == BaseName::Lgamma || ctx.base_name == BaseName::LgammaR && input.0 < 0.0 - { - // loggamma should not be defined for x < 0, yet we both return results - return XFAIL; + if ctx.base_name == BaseName::Sinh && input.0.abs() > 80.0 && actual.is_nan() { + // we return some NaN that should be real values or infinite + if ctx.basis == CheckBasis::Musl { + return XFAIL_NOCHECK; + } + return XFAIL("sinh unexpected NaN"); } if (ctx.base_name == BaseName::Lgamma || ctx.base_name == BaseName::LgammaR) @@ -213,32 +239,18 @@ impl MaybeOverride<(f32,)> for SpecialCase { && !actual.is_infinite() { // This result should saturate but we return a finite value. - return XFAIL; + return XFAIL_NOCHECK; } if ctx.base_name == BaseName::J0 && input.0 < -1e34 { // Errors get huge close to -inf - return XFAIL; - } - - if cfg!(x86_no_sse) - && ctx.base_name == BaseName::Exp2 - && !expected.is_infinite() - && actual.is_infinite() - { - // We return infinity when there is a representable value. Test input: 127.97238 - return XFAIL; + return XFAIL_NOCHECK; } - maybe_check_nan_bits(actual, expected, ctx) + unop_common(input, actual, expected, ctx) } - fn check_int( - input: (f32,), - actual: I, - expected: I, - ctx: &CheckCtx, - ) -> Option> { + fn check_int(input: (f32,), actual: I, expected: I, ctx: &CheckCtx) -> CheckAction { // On MPFR for lgammaf_r, we set -1 as the integer result for negative infinity but MPFR // sets +1 if ctx.basis == CheckBasis::Mpfr @@ -246,37 +258,25 @@ impl MaybeOverride<(f32,)> for SpecialCase { && input.0 == f32::NEG_INFINITY && actual.abs() == expected.abs() { - XFAIL - } else { - None + return XFAIL("lgammar integer result"); } + + DEFAULT } } impl MaybeOverride<(f64,)> for SpecialCase { - fn check_float( - input: (f64,), - actual: F, - expected: F, - _ulp: &mut u32, - ctx: &CheckCtx, - ) -> Option { - if ctx.basis == CheckBasis::Musl { - if cfg!(target_arch = "x86") && ctx.base_name == BaseName::Acosh && input.0 < 1.0 { - // The function is undefined, both implementations return random results - return SKIP; - } - - if cfg!(x86_no_sse) - && ctx.base_name == BaseName::Ceil - && input.0 < 0.0 - && input.0 > -1.0 - && expected == F::ZERO - && actual == F::ZERO - { - // musl returns -0.0, we return +0.0 - return XFAIL; - } + fn check_float(input: (f64,), actual: F, expected: F, ctx: &CheckCtx) -> CheckAction { + if cfg!(x86_no_sse) + && ctx.base_name == BaseName::Ceil + && ctx.basis == CheckBasis::Musl + && input.0 < 0.0 + && input.0 > -1.0 + && expected == F::ZERO + && actual == F::ZERO + { + // musl returns -0.0, we return +0.0 + return XFAIL("i586 ceil signed zero"); } if cfg!(x86_no_sse) @@ -285,53 +285,37 @@ impl MaybeOverride<(f64,)> for SpecialCase { && (expected - actual).abs() > F::ZERO { // Our rounding mode is incorrect. - return XFAIL; - } - - if ctx.base_name == BaseName::Acosh && input.0 < 1.0 { - // The function is undefined for the inputs, musl and our libm both return - // random results. - return XFAIL; - } - - if ctx.base_name == BaseName::Lgamma || ctx.base_name == BaseName::LgammaR && input.0 < 0.0 - { - // loggamma should not be defined for x < 0, yet we both return results - return XFAIL; + return XFAIL("i586 rint rounding mode"); } - if ctx.base_name == BaseName::J0 && input.0 < -1e300 { - // Errors get huge close to -inf - return XFAIL; - } - - if (ctx.fn_ident == Identifier::Ceil || ctx.fn_ident == Identifier::Floor) - && cfg!(x86_no_sse) + if cfg!(x86_no_sse) + && (ctx.fn_ident == Identifier::Ceil || ctx.fn_ident == Identifier::Floor) && expected.eq_repr(F::NEG_ZERO) && actual.eq_repr(F::ZERO) { // FIXME: the x87 implementations do not keep the distinction between -0.0 and 0.0. // See https://github.com/rust-lang/libm/pull/404#issuecomment-2572399955 - return XFAIL; + return XFAIL("i586 ceil/floor signed zero"); } - if (ctx.fn_ident == Identifier::Exp10 || ctx.fn_ident == Identifier::Exp2) - && cfg!(x86_no_sse) + if cfg!(x86_no_sse) + && (ctx.fn_ident == Identifier::Exp10 || ctx.fn_ident == Identifier::Exp2) { // FIXME: i586 has very imprecise results with ULP > u32::MAX for these // operations so we can't reasonably provide a limit. - return XFAIL; + return XFAIL_NOCHECK; } - maybe_check_nan_bits(actual, expected, ctx) + if ctx.base_name == BaseName::J0 && input.0 < -1e300 { + // Errors get huge close to -inf + return XFAIL_NOCHECK; + } + + // maybe_check_nan_bits(actual, expected, ctx) + unop_common(input, actual, expected, ctx) } - fn check_int( - input: (f64,), - actual: I, - expected: I, - ctx: &CheckCtx, - ) -> Option> { + fn check_int(input: (f64,), actual: I, expected: I, ctx: &CheckCtx) -> CheckAction { // On MPFR for lgamma_r, we set -1 as the integer result for negative infinity but MPFR // sets +1 if ctx.basis == CheckBasis::Mpfr @@ -339,41 +323,68 @@ impl MaybeOverride<(f64,)> for SpecialCase { && input.0 == f64::NEG_INFINITY && actual.abs() == expected.abs() { - XFAIL - } else { - None + return XFAIL("lgammar integer result"); } + + DEFAULT } } #[cfg(f128_enabled)] impl MaybeOverride<(f128,)> for SpecialCase {} -/// Check NaN bits if the function requires it -fn maybe_check_nan_bits(actual: F, expected: F, ctx: &CheckCtx) -> Option { - if !(ctx.base_name == BaseName::Fabs || ctx.base_name == BaseName::Copysign) { - return None; - } +// F1 and F2 are always the same type, this is just to please generics +fn unop_common( + input: (F1,), + actual: F2, + expected: F2, + ctx: &CheckCtx, +) -> CheckAction { + if ctx.base_name == BaseName::Acosh + && input.0 < F1::NEG_ONE + && !(expected.is_nan() && actual.is_nan()) + { + // acoshf is undefined for x <= 1.0, but we return a random result at lower values. - // LLVM currently uses x87 instructions which quieten signalling NaNs to handle the i686 - // `extern "C"` `f32`/`f64` return ABI. - // LLVM issue - // Rust issue - if cfg!(target_arch = "x86") && ctx.basis == CheckBasis::Musl { - return SKIP; + if ctx.basis == CheckBasis::Musl { + return XFAIL_NOCHECK; + } + + return XFAIL("acoshf undefined"); } - // MPFR only has one NaN bitpattern; allow the default `.is_nan()` checks to validate. - if ctx.basis == CheckBasis::Mpfr { - return SKIP; + if (ctx.base_name == BaseName::Lgamma || ctx.base_name == BaseName::LgammaR) + && input.0 < F1::ZERO + && !input.0.is_infinite() + { + // loggamma should not be defined for x < 0, yet we both return results + return XFAIL_NOCHECK; } - // abs and copysign require signaling NaNs to be propagated, so verify bit equality. - if actual.to_bits() == expected.to_bits() { - SKIP - } else { - Some(Err(anyhow::anyhow!("NaNs have different bitpatterns"))) + // fabs and copysign must leave NaNs untouched. + if ctx.base_name == BaseName::Fabs && input.0.is_nan() { + // LLVM currently uses x87 instructions which quieten signalling NaNs to handle the i686 + // `extern "C"` `f32`/`f64` return ABI. + // LLVM issue + // Rust issue + if cfg!(target_arch = "x86") && ctx.basis == CheckBasis::Musl && actual.is_nan() { + return XFAIL_NOCHECK; + } + + // MPFR only has one NaN bitpattern; allow the default `.is_nan()` checks to validate. + if ctx.basis == CheckBasis::Mpfr { + return DEFAULT; + } + + // abs and copysign require signaling NaNs to be propagated, so verify bit equality. + if actual.to_bits() == expected.to_bits() { + return CheckAction::Custom(Ok(())); + } else { + return CheckAction::Custom(Err(anyhow::anyhow!("NaNs have different bitpatterns"))); + } } + + DEFAULT } #[cfg(f16_enabled)] @@ -382,9 +393,8 @@ impl MaybeOverride<(f16, f16)> for SpecialCase { input: (f16, f16), actual: F, expected: F, - _ulp: &mut u32, ctx: &CheckCtx, - ) -> Option { + ) -> CheckAction { binop_common(input, actual, expected, ctx) } } @@ -394,18 +404,8 @@ impl MaybeOverride<(f32, f32)> for SpecialCase { input: (f32, f32), actual: F, expected: F, - _ulp: &mut u32, ctx: &CheckCtx, - ) -> Option { - if ctx.base_name == BaseName::Fmin - && input.0.biteq(f32::NEG_ZERO) - && input.1.biteq(f32::ZERO) - && expected.biteq(F::NEG_ZERO) - && actual.biteq(F::ZERO) - { - return XFAIL; - } - + ) -> CheckAction { binop_common(input, actual, expected, ctx) } @@ -414,7 +414,7 @@ impl MaybeOverride<(f32, f32)> for SpecialCase { actual: I, expected: I, ctx: &CheckCtx, - ) -> Option { + ) -> CheckAction { remquo_common(actual, expected, ctx) } } @@ -424,18 +424,8 @@ impl MaybeOverride<(f64, f64)> for SpecialCase { input: (f64, f64), actual: F, expected: F, - _ulp: &mut u32, ctx: &CheckCtx, - ) -> Option { - if ctx.base_name == BaseName::Fmin - && input.0.biteq(f64::NEG_ZERO) - && input.1.biteq(f64::ZERO) - && expected.biteq(F::ZERO) - && actual.biteq(F::NEG_ZERO) - { - return XFAIL; - } - + ) -> CheckAction { binop_common(input, actual, expected, ctx) } @@ -444,33 +434,19 @@ impl MaybeOverride<(f64, f64)> for SpecialCase { actual: I, expected: I, ctx: &CheckCtx, - ) -> Option { + ) -> CheckAction { remquo_common(actual, expected, ctx) } } -fn remquo_common(actual: I, expected: I, ctx: &CheckCtx) -> Option { - // FIXME: Our MPFR implementation disagrees with musl and may need to be updated. - if ctx.basis == CheckBasis::Mpfr - && ctx.base_name == BaseName::Remquo - && expected == I::MIN - && actual == I::ZERO - { - return XFAIL; - } - - None -} - #[cfg(f128_enabled)] impl MaybeOverride<(f128, f128)> for SpecialCase { fn check_float( input: (f128, f128), actual: F, expected: F, - _ulp: &mut u32, ctx: &CheckCtx, - ) -> Option { + ) -> CheckAction { binop_common(input, actual, expected, ctx) } } @@ -481,8 +457,17 @@ fn binop_common( actual: F2, expected: F2, ctx: &CheckCtx, -) -> Option { - /* FIXME(#439): we do not compare signed zeros */ +) -> CheckAction { + // MPFR only has one NaN bitpattern; allow the default `.is_nan()` checks to validate. Skip if + // the first input (magnitude source) is NaN and the output is also a NaN, or if the second + // input (sign source) is NaN. + if ctx.basis == CheckBasis::Mpfr + && ((input.0.is_nan() && actual.is_nan() && expected.is_nan()) || input.1.is_nan()) + { + return SKIP; + } + + /* FIXME(#439): our fmin and fmax do not compare signed zeros */ if ctx.base_name == BaseName::Fmin && input.0.biteq(F1::NEG_ZERO) @@ -490,7 +475,7 @@ fn binop_common( && expected.biteq(F2::NEG_ZERO) && actual.biteq(F2::ZERO) { - return XFAIL; + return XFAIL("fmin signed zeroes"); } if ctx.base_name == BaseName::Fmax @@ -499,21 +484,32 @@ fn binop_common( && expected.biteq(F2::ZERO) && actual.biteq(F2::NEG_ZERO) { - return XFAIL; + return XFAIL("fmax signed zeroes"); } // Musl propagates NaNs if one is provided as the input, but we return the other input. - match (&ctx.basis, ctx.base_name) { - (Musl, BaseName::Fmin | BaseName::Fmax) - if (input.0.is_nan() || input.1.is_nan()) && expected.is_nan() => - { - XFAIL - } + if (ctx.base_name == BaseName::Fmax || ctx.base_name == BaseName::Fmin) + && ctx.basis == Musl + && (input.0.is_nan() ^ input.1.is_nan()) + && expected.is_nan() + { + return XFAIL("fmax/fmin musl NaN"); + } - (Mpfr, BaseName::Copysign) if input.1.is_nan() => SKIP, + DEFAULT +} - _ => None, +fn remquo_common(actual: I, expected: I, ctx: &CheckCtx) -> CheckAction { + // FIXME: Our MPFR implementation disagrees with musl and may need to be updated. + if ctx.basis == CheckBasis::Mpfr + && ctx.base_name == BaseName::Remquo + && expected == I::MIN + && actual == I::ZERO + { + return XFAIL("remquo integer mismatch"); } + + DEFAULT } impl MaybeOverride<(i32, f32)> for SpecialCase { @@ -521,28 +517,19 @@ impl MaybeOverride<(i32, f32)> for SpecialCase { input: (i32, f32), actual: F, expected: F, - ulp: &mut u32, ctx: &CheckCtx, - ) -> Option { - match (&ctx.basis, ctx.base_name) { - (Musl, _) => bessel_prec_dropoff(input, actual, expected, ulp, ctx), - - // We return +0.0, MPFR returns -0.0 - (Mpfr, BaseName::Jn | BaseName::Yn) - if input.1 == f32::NEG_INFINITY && actual == F::ZERO && expected == F::ZERO => - { - XFAIL - } - - // `ynf(213, 109.15641) = -inf` with our library, should be finite. - (_, BaseName::Yn) - if input.0 > 200 && !expected.is_infinite() && actual.is_infinite() => - { - XFAIL - } - - _ => None, + ) -> CheckAction { + // `ynf(213, 109.15641) = -inf` with our library, should be finite. + if ctx.basis == Mpfr + && ctx.base_name == BaseName::Yn + && input.0 > 200 + && !expected.is_infinite() + && actual.is_infinite() + { + return XFAIL("ynf infinity mismatch"); } + + int_float_common(input, actual, expected, ctx) } } @@ -551,55 +538,51 @@ impl MaybeOverride<(i32, f64)> for SpecialCase { input: (i32, f64), actual: F, expected: F, - ulp: &mut u32, ctx: &CheckCtx, - ) -> Option { - match (&ctx.basis, ctx.base_name) { - (Musl, _) => bessel_prec_dropoff(input, actual, expected, ulp, ctx), - - // We return +0.0, MPFR returns -0.0 - (Mpfr, BaseName::Jn | BaseName::Yn) - if input.1 == f64::NEG_INFINITY && actual == F::ZERO && expected == F::ZERO => - { - XFAIL - } - - _ => None, - } + ) -> CheckAction { + int_float_common(input, actual, expected, ctx) } } -/// Our bessel functions blow up with large N values -fn bessel_prec_dropoff( +fn int_float_common( input: (i32, F1), actual: F2, expected: F2, - ulp: &mut u32, ctx: &CheckCtx, -) -> Option { - if ctx.base_name == BaseName::Jn || ctx.base_name == BaseName::Yn { +) -> CheckAction { + if ctx.basis == Mpfr + && (ctx.base_name == BaseName::Jn || ctx.base_name == BaseName::Yn) + && input.1 == F1::NEG_INFINITY + && actual == F2::ZERO + && expected == F2::ZERO + { + return XFAIL("mpfr b"); + } + + // Our bessel functions blow up with large N values + if ctx.basis == Musl && (ctx.base_name == BaseName::Jn || ctx.base_name == BaseName::Yn) { if input.0 > 4000 { - return XFAIL; + return XFAIL_NOCHECK; } else if input.0 > 2000 { - // *ulp = 20_000; - *ulp = 20000; + return CheckAction::AssertWithUlp(20_000); } else if input.0 > 1000 { - *ulp = 4000; + return CheckAction::AssertWithUlp(4_000); } } // Values near infinity sometimes get cut off for us. `ynf(681, 509.90924) = -inf` but should // be -3.2161271e38. - if ctx.fn_ident == Identifier::Ynf + if ctx.basis == Musl + && ctx.fn_ident == Identifier::Ynf && !expected.is_infinite() && actual.is_infinite() && (expected.abs().to_bits().abs_diff(actual.abs().to_bits()) < F2::Int::cast_from(1_000_000u32)) { - return XFAIL; + return XFAIL_NOCHECK; } - None + DEFAULT } impl MaybeOverride<(f32, i32)> for SpecialCase {} @@ -610,9 +593,8 @@ impl MaybeOverride<(f32, f32, f32)> for SpecialCase { input: (f32, f32, f32), actual: F, expected: F, - _ulp: &mut u32, ctx: &CheckCtx, - ) -> Option { + ) -> CheckAction { ternop_common(input, actual, expected, ctx) } } @@ -621,9 +603,8 @@ impl MaybeOverride<(f64, f64, f64)> for SpecialCase { input: (f64, f64, f64), actual: F, expected: F, - _ulp: &mut u32, ctx: &CheckCtx, - ) -> Option { + ) -> CheckAction { ternop_common(input, actual, expected, ctx) } } @@ -634,7 +615,7 @@ fn ternop_common( actual: F2, expected: F2, ctx: &CheckCtx, -) -> Option { +) -> CheckAction { // FIXME(fma): 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result // of fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the // exact result". Our implementation returns the wrong sign: @@ -647,8 +628,8 @@ fn ternop_common( && expected.biteq(F2::NEG_ZERO) && actual.biteq(F2::ZERO) { - return XFAIL; + return XFAIL("fma sign"); } - None + DEFAULT } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index 0a4baa2e36f74..a5806943e1127 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -8,8 +8,9 @@ use std::fmt; -use anyhow::{Context, bail, ensure}; +use anyhow::{Context, anyhow, bail, ensure}; +use crate::precision::CheckAction; use crate::{CheckCtx, Float, Int, MaybeOverride, SpecialCase, TestResult}; /// Trait for calling a function with a tuple as arguments. @@ -185,20 +186,34 @@ where Input: Hex + fmt::Debug, SpecialCase: MaybeOverride, { - if let Some(res) = SpecialCase::check_int(input, actual, expected, ctx) { - return res; - } + let (result, xfail_msg) = match SpecialCase::check_int(input, actual, expected, ctx) { + CheckAction::AssertSuccess => (actual == expected, None), + CheckAction::AssertFailure(msg) => (actual != expected, Some(msg)), + CheckAction::Custom(res) => return res, + CheckAction::Skip => return Ok(()), + CheckAction::AssertWithUlp(_) => panic!("ulp has no meaning for integer checks"), + }; + + let make_xfail_msg = || match xfail_msg { + Some(m) => format!( + "expected failure but test passed. Does an XFAIL need to be updated?\n\ + failed at: {m}", + ), + None => String::new(), + }; anyhow::ensure!( - actual == expected, + result, "\ \n input: {input:?} {ibits}\ \n expected: {expected:<22?} {expbits}\ \n actual: {actual:<22?} {actbits}\ + \n {msg}\ ", actbits = actual.hex(), expbits = expected.hex(), ibits = input.hex(), + msg = make_xfail_msg() ); Ok(()) @@ -246,15 +261,19 @@ where u32: TryFrom, SpecialCase: MaybeOverride, { + let mut assert_failure_msg = None; + // Create a wrapper function so we only need to `.with_context` once. - let inner = || -> TestResult { + let mut inner = || -> TestResult { let mut allowed_ulp = ctx.ulp; - // If the tested function requires a nonstandard test, run it here. - if let Some(res) = SpecialCase::check_float(input, actual, expected, &mut allowed_ulp, ctx) - { - return res; - } + match SpecialCase::check_float(input, actual, expected, ctx) { + CheckAction::AssertSuccess => (), + CheckAction::AssertFailure(msg) => assert_failure_msg = Some(msg), + CheckAction::Custom(res) => return res, + CheckAction::Skip => return Ok(()), + CheckAction::AssertWithUlp(ulp_override) => allowed_ulp = ulp_override, + }; // Check when both are NaNs if actual.is_nan() && expected.is_nan() { @@ -280,14 +299,29 @@ where let ulp_diff = act_bits.checked_sub(exp_bits).unwrap().abs(); let ulp_u32 = u32::try_from(ulp_diff) - .map_err(|e| anyhow::anyhow!("{e:?}: ulp of {ulp_diff} exceeds u32::MAX"))?; + .map_err(|e| anyhow!("{e:?}: ulp of {ulp_diff} exceeds u32::MAX"))?; ensure!(ulp_u32 <= allowed_ulp, "ulp {ulp_diff} > {allowed_ulp}",); Ok(()) }; - inner().with_context(|| { + let mut res = inner(); + + if let Some(msg) = assert_failure_msg { + // Invert `Ok` and `Err` if the test is an xfail. + if res.is_ok() { + let e = anyhow!( + "expected failure but test passed. Does an XFAIL need to be updated?\n\ + failed at: {msg}", + ); + res = Err(e) + } else { + res = Ok(()) + } + } + + res.with_context(|| { format!( "\ \n input: {input:?} {ibits}\ From b8da1919f92b9a7a97ac58ebe4623daeb098b01c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 23 Jan 2025 09:15:43 +0000 Subject: [PATCH 1603/4206] Change `from_parts` to take a `u32` exponent rather than `i32` Make things more consistent with other API that works with a bitwise representation of the exponent. That is, use `u32` when working with a bitwise (biased) representation, use `i32` when the bitwise representation has been adjusted for bias and ay be negative. Every place this has been used so far has an `as i32`, so this change makes things cleaner anyway. --- .../libm/src/math/generic/sqrt.rs | 2 +- .../libm/src/math/support/float_traits.rs | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/src/math/generic/sqrt.rs index 22ee93f57a3c4..c20c0f20525e7 100644 --- a/library/compiler-builtins/libm/src/math/generic/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/generic/sqrt.rs @@ -92,7 +92,7 @@ where } // Normalize subnormals by multiplying by 1.0 << SIG_BITS (e.g. 0x1p52 for doubles). - let scaled = x * F::from_parts(false, (F::SIG_BITS + F::EXP_BIAS) as i32, zero); + let scaled = x * F::from_parts(false, F::SIG_BITS + F::EXP_BIAS, zero); ix = scaled.to_bits(); match top { Exp::Shifted(ref mut v) => { 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 1abb7c4ded841..57e4aebecfc8f 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -131,11 +131,11 @@ pub trait Float: 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: i32, significand: Self::Int) -> Self { + fn from_parts(negative: bool, exponent: u32, significand: Self::Int) -> Self { let sign = if negative { Self::Int::ONE } else { Self::Int::ZERO }; Self::from_bits( (sign << (Self::BITS - 1)) - | (Self::Int::cast_from(exponent as u32 & Self::EXP_MAX) << Self::SIG_BITS) + | (Self::Int::cast_from(exponent & Self::EXP_MAX) << Self::SIG_BITS) | (significand & Self::SIG_MASK), ) } @@ -282,7 +282,7 @@ mod tests { assert_eq!(f16::from_bits(0x1).exp_unbiased(), -15); // `from_parts` - assert_biteq!(f16::from_parts(true, f16::EXP_BIAS as i32, 0), -1.0f16); + assert_biteq!(f16::from_parts(true, f16::EXP_BIAS, 0), -1.0f16); assert_biteq!(f16::from_parts(false, 0, 1), f16::from_bits(0x1)); } @@ -304,8 +304,8 @@ mod tests { assert_eq!(f32::from_bits(0x1).exp_unbiased(), -127); // `from_parts` - assert_biteq!(f32::from_parts(true, f32::EXP_BIAS as i32, 0), -1.0f32); - assert_biteq!(f32::from_parts(false, 10 + f32::EXP_BIAS as i32, 0), hf32!("0x1p10")); + assert_biteq!(f32::from_parts(true, f32::EXP_BIAS, 0), -1.0f32); + assert_biteq!(f32::from_parts(false, 10 + f32::EXP_BIAS, 0), hf32!("0x1p10")); assert_biteq!(f32::from_parts(false, 0, 1), f32::from_bits(0x1)); } @@ -327,8 +327,8 @@ mod tests { assert_eq!(f64::from_bits(0x1).exp_unbiased(), -1023); // `from_parts` - assert_biteq!(f64::from_parts(true, f64::EXP_BIAS as i32, 0), -1.0f64); - assert_biteq!(f64::from_parts(false, 10 + f64::EXP_BIAS as i32, 0), hf64!("0x1p10")); + assert_biteq!(f64::from_parts(true, f64::EXP_BIAS, 0), -1.0f64); + assert_biteq!(f64::from_parts(false, 10 + f64::EXP_BIAS, 0), hf64!("0x1p10")); assert_biteq!(f64::from_parts(false, 0, 1), f64::from_bits(0x1)); } @@ -351,7 +351,7 @@ mod tests { assert_eq!(f128::from_bits(0x1).exp_unbiased(), -16383); // `from_parts` - assert_biteq!(f128::from_parts(true, f128::EXP_BIAS as i32, 0), -1.0f128); + assert_biteq!(f128::from_parts(true, f128::EXP_BIAS, 0), -1.0f128); assert_biteq!(f128::from_parts(false, 0, 1), f128::from_bits(0x1)); } } From 3aa2d1cfc2b47f23299bdf14214e2eb176482d05 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 23 Jan 2025 22:02:22 +0000 Subject: [PATCH 1604/4206] Add a generic version of `scalbn` This replaces the `f32` and `f64` versions of `scalbn` and `ldexp`. --- .../libm/crates/libm-test/src/mpfloat.rs | 3 +- .../libm/etc/function-definitions.json | 2 + .../libm/src/math/generic/mod.rs | 2 + .../libm/src/math/generic/scalbn.rs | 123 ++++++++++++++++++ .../compiler-builtins/libm/src/math/scalbn.rs | 33 +---- .../libm/src/math/scalbnf.rs | 29 +---- 6 files changed, 133 insertions(+), 59 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/scalbn.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index a404f227b2623..4ac70c2eb5e76 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -158,7 +158,8 @@ libm_macros::for_each_function! { ilogbf, jn, jnf, - ldexp,ldexpf, + ldexp, + ldexpf, lgamma_r, lgammaf_r, modf, diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index d3810b940cb03..bbb2b40f14d46 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -698,12 +698,14 @@ "scalbn": { "sources": [ "src/libm_helper.rs", + "src/math/generic/scalbn.rs", "src/math/scalbn.rs" ], "type": "f64" }, "scalbnf": { "sources": [ + "src/math/generic/scalbn.rs", "src/math/scalbnf.rs" ], "type": "f32" diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index d3df650e1a5be..c7741cb460077 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -4,6 +4,7 @@ mod fabs; mod fdim; mod floor; mod rint; +mod scalbn; mod sqrt; mod trunc; @@ -13,5 +14,6 @@ pub use fabs::fabs; pub use fdim::fdim; pub use floor::floor; pub use rint::rint; +pub use scalbn::scalbn; pub use sqrt::sqrt; pub use trunc::trunc; diff --git a/library/compiler-builtins/libm/src/math/generic/scalbn.rs b/library/compiler-builtins/libm/src/math/generic/scalbn.rs new file mode 100644 index 0000000000000..f036c15cc0312 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/scalbn.rs @@ -0,0 +1,123 @@ +use super::super::{CastFrom, CastInto, Float, IntTy, MinInt}; + +/// Scale the exponent. +/// +/// From N3220: +/// +/// > The scalbn and scalbln functions compute `x * b^n`, where `b = FLT_RADIX` if the return type +/// > of the function is a standard floating type, or `b = 10` if the return type of the function +/// > is a decimal floating type. A range error occurs for some finite x, depending on n. +/// > +/// > [...] +/// > +/// > * `scalbn(±0, n)` returns `±0`. +/// > * `scalbn(x, 0)` returns `x`. +/// > * `scalbn(±∞, n)` returns `±∞`. +/// > +/// > If the calculation does not overflow or underflow, the returned value is exact and +/// > independent of the current rounding direction mode. +pub fn scalbn(mut x: F, mut n: i32) -> F +where + u32: CastInto, + F::Int: CastFrom, + F::Int: CastFrom, +{ + let zero = IntTy::::ZERO; + + // Bits including the implicit bit + let sig_total_bits = F::SIG_BITS + 1; + + // Maximum and minimum values when biased + let exp_max: i32 = F::EXP_BIAS as i32; + let exp_min = -(exp_max - 1); + + // 2 ^ Emax, where Emax is the maximum biased exponent value (1023 for f64) + let f_exp_max = F::from_parts(false, F::EXP_BIAS << 1, zero); + + // 2 ^ Emin, where Emin is the minimum biased exponent value (-1022 for f64) + let f_exp_min = F::from_parts(false, 1, zero); + + // 2 ^ sig_total_bits, representation of what can be accounted for with subnormals + let f_exp_subnorm = F::from_parts(false, sig_total_bits + F::EXP_BIAS, zero); + + if n > exp_max { + x *= f_exp_max; + n -= exp_max; + if n > exp_max { + x *= f_exp_max; + n -= exp_max; + if n > exp_max { + n = exp_max; + } + } + } else if n < exp_min { + let mul = f_exp_min * f_exp_subnorm; + let add = (exp_max - 1) - sig_total_bits as i32; + + x *= mul; + n += add; + if n < exp_min { + x *= mul; + n += add; + if n < exp_min { + n = exp_min; + } + } + } + + x * F::from_parts(false, (F::EXP_BIAS as i32 + n) as u32, zero) +} + +#[cfg(test)] +mod tests { + use super::super::super::Int; + use super::*; + + // Tests against N3220 + fn spec_test() + where + u32: CastInto, + F::Int: CastFrom, + F::Int: CastFrom, + { + // `scalbn(±0, n)` returns `±0`. + assert_biteq!(scalbn(F::NEG_ZERO, 10), F::NEG_ZERO); + assert_biteq!(scalbn(F::NEG_ZERO, 0), F::NEG_ZERO); + assert_biteq!(scalbn(F::NEG_ZERO, -10), F::NEG_ZERO); + assert_biteq!(scalbn(F::ZERO, 10), F::ZERO); + assert_biteq!(scalbn(F::ZERO, 0), F::ZERO); + assert_biteq!(scalbn(F::ZERO, -10), F::ZERO); + + // `scalbn(x, 0)` returns `x`. + assert_biteq!(scalbn(F::MIN, 0), F::MIN); + assert_biteq!(scalbn(F::MAX, 0), F::MAX); + assert_biteq!(scalbn(F::INFINITY, 0), F::INFINITY); + assert_biteq!(scalbn(F::NEG_INFINITY, 0), F::NEG_INFINITY); + assert_biteq!(scalbn(F::ZERO, 0), F::ZERO); + assert_biteq!(scalbn(F::NEG_ZERO, 0), F::NEG_ZERO); + + // `scalbn(±∞, n)` returns `±∞`. + assert_biteq!(scalbn(F::INFINITY, 10), F::INFINITY); + assert_biteq!(scalbn(F::INFINITY, -10), F::INFINITY); + assert_biteq!(scalbn(F::NEG_INFINITY, 10), F::NEG_INFINITY); + assert_biteq!(scalbn(F::NEG_INFINITY, -10), F::NEG_INFINITY); + + // NaN should remain NaNs. + assert!(scalbn(F::NAN, 10).is_nan()); + assert!(scalbn(F::NAN, 0).is_nan()); + assert!(scalbn(F::NAN, -10).is_nan()); + assert!(scalbn(-F::NAN, 10).is_nan()); + assert!(scalbn(-F::NAN, 0).is_nan()); + assert!(scalbn(-F::NAN, -10).is_nan()); + } + + #[test] + fn spec_test_f32() { + spec_test::(); + } + + #[test] + fn spec_test_f64() { + spec_test::(); + } +} diff --git a/library/compiler-builtins/libm/src/math/scalbn.rs b/library/compiler-builtins/libm/src/math/scalbn.rs index 00c455a106531..f809dad518a1e 100644 --- a/library/compiler-builtins/libm/src/math/scalbn.rs +++ b/library/compiler-builtins/libm/src/math/scalbn.rs @@ -1,33 +1,4 @@ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbn(x: f64, mut n: i32) -> f64 { - let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023 - let x1p53 = f64::from_bits(0x4340000000000000); // 0x1p53 === 2 ^ 53 - let x1p_1022 = f64::from_bits(0x0010000000000000); // 0x1p-1022 === 2 ^ (-1022) - - let mut y = x; - - if n > 1023 { - y *= x1p1023; - n -= 1023; - if n > 1023 { - y *= x1p1023; - n -= 1023; - if n > 1023 { - n = 1023; - } - } - } else if n < -1022 { - /* make sure final n < -53 to avoid double - rounding in the subnormal range */ - y *= x1p_1022 * x1p53; - n += 1022 - 53; - if n < -1022 { - y *= x1p_1022 * x1p53; - n += 1022 - 53; - if n < -1022 { - n = -1022; - } - } - } - y * f64::from_bits(((0x3ff + n) as u64) << 52) +pub fn scalbn(x: f64, n: i32) -> f64 { + super::generic::scalbn(x, n) } diff --git a/library/compiler-builtins/libm/src/math/scalbnf.rs b/library/compiler-builtins/libm/src/math/scalbnf.rs index 73f4bb57aaf2f..57e7ba76f60b5 100644 --- a/library/compiler-builtins/libm/src/math/scalbnf.rs +++ b/library/compiler-builtins/libm/src/math/scalbnf.rs @@ -1,29 +1,4 @@ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf(mut x: f32, mut n: i32) -> f32 { - let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127 - let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 - let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24 - - if n > 127 { - x *= x1p127; - n -= 127; - if n > 127 { - x *= x1p127; - n -= 127; - if n > 127 { - n = 127; - } - } - } else if n < -126 { - x *= x1p_126 * x1p24; - n += 126 - 24; - if n < -126 { - x *= x1p_126 * x1p24; - n += 126 - 24; - if n < -126 { - n = -126; - } - } - } - x * f32::from_bits(((0x7f + n) as u32) << 23) +pub fn scalbnf(x: f32, n: i32) -> f32 { + super::generic::scalbn(x, n) } From cdbe65b5036f69188978405d1a8785d7a846140a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Jan 2025 01:49:23 +0000 Subject: [PATCH 1605/4206] Add a generic version of `round` This replaces `round` and `roundf`. --- .../libm/etc/function-definitions.json | 2 + .../libm/src/math/generic/mod.rs | 2 + .../libm/src/math/generic/round.rs | 46 +++++++++++++++++++ .../compiler-builtins/libm/src/math/round.rs | 27 +---------- .../compiler-builtins/libm/src/math/roundf.rs | 29 +----------- 5 files changed, 54 insertions(+), 52 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/round.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index bbb2b40f14d46..4aea45a078142 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -685,12 +685,14 @@ "round": { "sources": [ "src/libm_helper.rs", + "src/math/generic/round.rs", "src/math/round.rs" ], "type": "f64" }, "roundf": { "sources": [ + "src/math/generic/round.rs", "src/math/roundf.rs" ], "type": "f32" diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index c7741cb460077..1f557719f42cd 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -4,6 +4,7 @@ mod fabs; mod fdim; mod floor; mod rint; +mod round; mod scalbn; mod sqrt; mod trunc; @@ -14,6 +15,7 @@ pub use fabs::fabs; pub use fdim::fdim; pub use floor::floor; pub use rint::rint; +pub use round::round; pub use scalbn::scalbn; pub use sqrt::sqrt; pub use trunc::trunc; diff --git a/library/compiler-builtins/libm/src/math/generic/round.rs b/library/compiler-builtins/libm/src/math/generic/round.rs new file mode 100644 index 0000000000000..fc9a1b675c61b --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/round.rs @@ -0,0 +1,46 @@ +use super::super::{Float, MinInt}; +use super::{copysign, trunc}; + +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] + 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); + } +} diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs index b81ebaa1dbecc..36e0eb1f2ed49 100644 --- a/library/compiler-builtins/libm/src/math/round.rs +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -1,28 +1,5 @@ -use core::f64; - -use super::{copysign, trunc}; - +/// Round `x` to the nearest integer, breaking ties away from zero. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn round(x: f64) -> f64 { - trunc(x + copysign(0.5 - 0.25 * f64::EPSILON, x)) -} - -#[cfg(test)] -mod tests { - use super::round; - - #[test] - fn negative_zero() { - assert_eq!(round(-0.0_f64).to_bits(), (-0.0_f64).to_bits()); - } - - #[test] - fn sanity_check() { - assert_eq!(round(-1.0), -1.0); - assert_eq!(round(2.8), 3.0); - assert_eq!(round(-0.5), -1.0); - assert_eq!(round(0.5), 1.0); - assert_eq!(round(-1.5), -2.0); - assert_eq!(round(1.5), 2.0); - } + super::generic::round(x) } diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs index fb974bbfe73fe..b5d7c9d693e71 100644 --- a/library/compiler-builtins/libm/src/math/roundf.rs +++ b/library/compiler-builtins/libm/src/math/roundf.rs @@ -1,30 +1,5 @@ -use core::f32; - -use super::{copysignf, truncf}; - +/// Round `x` to the nearest integer, breaking ties away from zero. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn roundf(x: f32) -> f32 { - truncf(x + copysignf(0.5 - 0.25 * f32::EPSILON, x)) -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::roundf; - - #[test] - fn negative_zero() { - assert_eq!(roundf(-0.0_f32).to_bits(), (-0.0_f32).to_bits()); - } - - #[test] - fn sanity_check() { - assert_eq!(roundf(-1.0), -1.0); - assert_eq!(roundf(2.8), 3.0); - assert_eq!(roundf(-0.5), -1.0); - assert_eq!(roundf(0.5), 1.0); - assert_eq!(roundf(-1.5), -2.0); - assert_eq!(roundf(1.5), 2.0); - } + super::generic::round(x) } From d20a5e82a5a25e180482a0a4644adbbb33601545 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Jan 2025 01:57:12 +0000 Subject: [PATCH 1606/4206] Add `roundf16` and `roundf128` --- .../libm/crates/libm-macros/src/shared.rs | 4 +-- .../libm/crates/libm-test/benches/random.rs | 2 ++ .../libm/crates/libm-test/src/mpfloat.rs | 4 +++ .../libm-test/tests/compare_built_musl.rs | 2 ++ .../libm/crates/util/src/main.rs | 2 ++ .../libm/etc/function-definitions.json | 14 ++++++++ .../libm/etc/function-list.txt | 2 ++ .../libm/src/math/generic/round.rs | 36 +++++++++++++++++++ .../compiler-builtins/libm/src/math/mod.rs | 4 +++ .../libm/src/math/roundf128.rs | 5 +++ .../libm/src/math/roundf16.rs | 5 +++ 11 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/roundf128.rs create mode 100644 library/compiler-builtins/libm/src/math/roundf16.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index 80bd3e90753b3..b233e34f18223 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -9,7 +9,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16], returns: &[Ty::F16] }, None, - &["ceilf16", "fabsf16", "floorf16", "rintf16", "sqrtf16", "truncf16"], + &["ceilf16", "fabsf16", "floorf16", "rintf16", "roundf16", "sqrtf16", "truncf16"], ), ( // `fn(f32) -> f32` @@ -40,7 +40,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F128, Signature { args: &[Ty::F128], returns: &[Ty::F128] }, None, - &["ceilf128", "fabsf128", "floorf128", "rintf128", "sqrtf128", "truncf128"], + &["ceilf128", "fabsf128", "floorf128", "rintf128", "roundf128", "sqrtf128", "truncf128"], ), ( // `(f16, f16) -> f16` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 4d050e817e235..d0ecd851e346f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -129,6 +129,8 @@ libm_macros::for_each_function! { | floorf16 | rintf128 | rintf16 + | roundf128 + | roundf16 | sqrtf128 | sqrtf16 | truncf128 diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 4ac70c2eb5e76..4422ab88d0d15 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -175,6 +175,8 @@ libm_macros::for_each_function! { rintf16, round, roundf, + roundf128, + roundf16, scalbn, scalbnf, sincos,sincosf, @@ -247,6 +249,7 @@ impl_no_round! { fabsf16 => abs_mut; floorf16 => floor_mut; rintf16 => round_even_mut; // FIXME: respect rounding mode + roundf16 => round_mut; truncf16 => trunc_mut; } @@ -256,6 +259,7 @@ impl_no_round! { fabsf128 => abs_mut; floorf128 => floor_mut; rintf128 => round_even_mut; // FIXME: respect rounding mode + roundf128 => round_mut; truncf128 => trunc_mut; } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index f009816c97f14..0fc1b0df13da7 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -91,6 +91,8 @@ libm_macros::for_each_function! { floorf16, rintf128, rintf16, + roundf128, + roundf16, sqrtf128, sqrtf16, truncf128, diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index 889823d2e4ab4..aaedda6d152b2 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -98,6 +98,8 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | floorf16 | rintf128 | rintf16 + | roundf128 + | roundf16 | sqrtf128 | sqrtf16 | truncf128 diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 4aea45a078142..8c5903e93b922 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -697,6 +697,20 @@ ], "type": "f32" }, + "roundf128": { + "sources": [ + "src/math/generic/round.rs", + "src/math/roundf128.rs" + ], + "type": "f128" + }, + "roundf16": { + "sources": [ + "src/math/generic/round.rs", + "src/math/roundf16.rs" + ], + "type": "f16" + }, "scalbn": { "sources": [ "src/libm_helper.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 41bb4e06be8d1..0b6eed828b521 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -101,6 +101,8 @@ rintf128 rintf16 round roundf +roundf128 +roundf16 scalbn scalbnf sin diff --git a/library/compiler-builtins/libm/src/math/generic/round.rs b/library/compiler-builtins/libm/src/math/generic/round.rs index fc9a1b675c61b..8b51381880ccc 100644 --- a/library/compiler-builtins/libm/src/math/generic/round.rs +++ b/library/compiler-builtins/libm/src/math/generic/round.rs @@ -12,6 +12,24 @@ pub fn round(x: F) -> F { 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); @@ -43,4 +61,22 @@ mod tests { 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); + } } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 53d06974ceec5..8db17a02dfce6 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -347,6 +347,7 @@ cfg_if! { mod fdimf16; mod floorf16; mod rintf16; + mod roundf16; mod sqrtf16; mod truncf16; @@ -356,6 +357,7 @@ cfg_if! { pub use self::fdimf16::fdimf16; pub use self::floorf16::floorf16; pub use self::rintf16::rintf16; + pub use self::roundf16::roundf16; pub use self::sqrtf16::sqrtf16; pub use self::truncf16::truncf16; } @@ -369,6 +371,7 @@ cfg_if! { mod fdimf128; mod floorf128; mod rintf128; + mod roundf128; mod sqrtf128; mod truncf128; @@ -378,6 +381,7 @@ cfg_if! { pub use self::fdimf128::fdimf128; pub use self::floorf128::floorf128; pub use self::rintf128::rintf128; + pub use self::roundf128::roundf128; pub use self::sqrtf128::sqrtf128; pub use self::truncf128::truncf128; } diff --git a/library/compiler-builtins/libm/src/math/roundf128.rs b/library/compiler-builtins/libm/src/math/roundf128.rs new file mode 100644 index 0000000000000..fc3164929fe4f --- /dev/null +++ b/library/compiler-builtins/libm/src/math/roundf128.rs @@ -0,0 +1,5 @@ +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf128(x: f128) -> f128 { + super::generic::round(x) +} diff --git a/library/compiler-builtins/libm/src/math/roundf16.rs b/library/compiler-builtins/libm/src/math/roundf16.rs new file mode 100644 index 0000000000000..8b356eaabeecd --- /dev/null +++ b/library/compiler-builtins/libm/src/math/roundf16.rs @@ -0,0 +1,5 @@ +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf16(x: f16) -> f16 { + super::generic::round(x) +} From 357ee34abbabd9742ff03013df9d764e0fffe8ab Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Jan 2025 01:57:41 +0000 Subject: [PATCH 1607/4206] Remove an outdated note about precision --- .../compiler-builtins/libm/crates/libm-test/src/precision.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 800425f12adfc..bed6158825a52 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -13,9 +13,6 @@ use crate::{BaseName, CheckBasis, CheckCtx, Float, Identifier, Int, TestResult}; pub struct SpecialCase; /// ULP allowed to differ from the results returned by a test basis. -/// -/// Note that these results were obtained using 400M rounds of random inputs, which -/// is not a value used by default. pub fn default_ulp(ctx: &CheckCtx) -> u32 { // ULP compared to the infinite (MPFR) result. let mut ulp = match ctx.base_name { From f94df5d52450a20a30b39a029ff4297fce35504a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Jan 2025 02:10:52 +0000 Subject: [PATCH 1608/4206] Add a generic version of `fmin` and `fmax` These can be used for `fmin`, `fminf`, `fmax`, and `fmaxf`. No changes to the implementation are made, so [1] is not fixed. [1]: https://github.com/rust-lang/libm/issues/439 --- .../libm/etc/function-definitions.json | 12 ++++++++---- library/compiler-builtins/libm/src/math/fmax.rs | 11 ++--------- library/compiler-builtins/libm/src/math/fmaxf.rs | 11 ++--------- library/compiler-builtins/libm/src/math/fmin.rs | 11 ++--------- library/compiler-builtins/libm/src/math/fminf.rs | 11 ++--------- .../libm/src/math/generic/fmax.rs | 14 ++++++++++++++ .../libm/src/math/generic/fmin.rs | 13 +++++++++++++ .../compiler-builtins/libm/src/math/generic/mod.rs | 4 ++++ 8 files changed, 47 insertions(+), 40 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/fmax.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/fmin.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 8c5903e93b922..7ffe91eadd6f1 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -379,26 +379,30 @@ "fmax": { "sources": [ "src/libm_helper.rs", - "src/math/fmax.rs" + "src/math/fmax.rs", + "src/math/generic/fmax.rs" ], "type": "f64" }, "fmaxf": { "sources": [ - "src/math/fmaxf.rs" + "src/math/fmaxf.rs", + "src/math/generic/fmax.rs" ], "type": "f32" }, "fmin": { "sources": [ "src/libm_helper.rs", - "src/math/fmin.rs" + "src/math/fmin.rs", + "src/math/generic/fmin.rs" ], "type": "f64" }, "fminf": { "sources": [ - "src/math/fminf.rs" + "src/math/fminf.rs", + "src/math/generic/fmin.rs" ], "type": "f32" }, diff --git a/library/compiler-builtins/libm/src/math/fmax.rs b/library/compiler-builtins/libm/src/math/fmax.rs index 93c97bc611c7a..d5d9b513b8494 100644 --- a/library/compiler-builtins/libm/src/math/fmax.rs +++ b/library/compiler-builtins/libm/src/math/fmax.rs @@ -1,12 +1,5 @@ +/// Return the greater of two arguments or, if either argument is NaN, the other argument. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmax(x: f64, y: f64) -> f64 { - // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if x.is_nan() || x < y { y } else { x }) * 1.0 + super::generic::fmax(x, y) } diff --git a/library/compiler-builtins/libm/src/math/fmaxf.rs b/library/compiler-builtins/libm/src/math/fmaxf.rs index 60774664752d7..3197d5cf2ca1f 100644 --- a/library/compiler-builtins/libm/src/math/fmaxf.rs +++ b/library/compiler-builtins/libm/src/math/fmaxf.rs @@ -1,12 +1,5 @@ +/// Return the greater of two arguments or, if either argument is NaN, the other argument. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmaxf(x: f32, y: f32) -> f32 { - // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if x.is_nan() || x < y { y } else { x }) * 1.0 + super::generic::fmax(x, y) } diff --git a/library/compiler-builtins/libm/src/math/fmin.rs b/library/compiler-builtins/libm/src/math/fmin.rs index ab1509f34a652..df8ff7c32e3b2 100644 --- a/library/compiler-builtins/libm/src/math/fmin.rs +++ b/library/compiler-builtins/libm/src/math/fmin.rs @@ -1,12 +1,5 @@ +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmin(x: f64, y: f64) -> f64 { - // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if y.is_nan() || x < y { x } else { y }) * 1.0 + super::generic::fmin(x, y) } diff --git a/library/compiler-builtins/libm/src/math/fminf.rs b/library/compiler-builtins/libm/src/math/fminf.rs index 0049e7117ae05..b2cdfe89d64db 100644 --- a/library/compiler-builtins/libm/src/math/fminf.rs +++ b/library/compiler-builtins/libm/src/math/fminf.rs @@ -1,12 +1,5 @@ +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fminf(x: f32, y: f32) -> f32 { - // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if y.is_nan() || x < y { x } else { y }) * 1.0 + super::generic::fmin(x, y) } diff --git a/library/compiler-builtins/libm/src/math/generic/fmax.rs b/library/compiler-builtins/libm/src/math/generic/fmax.rs new file mode 100644 index 0000000000000..97803052bc27a --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fmax.rs @@ -0,0 +1,14 @@ +use super::super::Float; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmax(x: F, y: F) -> F { + // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if x.is_nan() || x < y { y } else { x }) * F::ONE +} diff --git a/library/compiler-builtins/libm/src/math/generic/fmin.rs b/library/compiler-builtins/libm/src/math/generic/fmin.rs new file mode 100644 index 0000000000000..697f720048603 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fmin.rs @@ -0,0 +1,13 @@ +use super::super::Float; + +pub fn fmin(x: F, y: F) -> F { + // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if y.is_nan() || x < y { x } else { y }) * F::ONE +} diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index 1f557719f42cd..819781a219aa6 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -3,6 +3,8 @@ mod copysign; mod fabs; mod fdim; mod floor; +mod fmax; +mod fmin; mod rint; mod round; mod scalbn; @@ -14,6 +16,8 @@ pub use copysign::copysign; pub use fabs::fabs; pub use fdim::fdim; pub use floor::floor; +pub use fmax::fmax; +pub use fmin::fmin; pub use rint::rint; pub use round::round; pub use scalbn::scalbn; From 6d5105c00636a4f8a8c8c76217db7f59ebd1f846 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Jan 2025 02:57:35 +0000 Subject: [PATCH 1609/4206] Add `fminf16`, `fmaxf16`, `fminf128`, and `fmaxf128` --- .../libm/crates/libm-macros/src/shared.rs | 4 +-- .../libm/crates/libm-test/benches/random.rs | 4 +++ .../libm/crates/libm-test/src/mpfloat.rs | 4 +-- .../libm-test/tests/compare_built_musl.rs | 4 +++ .../libm/crates/util/src/main.rs | 4 +++ .../libm/etc/function-definitions.json | 28 +++++++++++++++++++ .../libm/etc/function-list.txt | 4 +++ .../libm/src/math/fmaxf128.rs | 5 ++++ .../libm/src/math/fmaxf16.rs | 5 ++++ .../libm/src/math/fminf128.rs | 5 ++++ .../libm/src/math/fminf16.rs | 5 ++++ .../compiler-builtins/libm/src/math/mod.rs | 8 ++++++ 12 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fmaxf128.rs create mode 100644 library/compiler-builtins/libm/src/math/fmaxf16.rs create mode 100644 library/compiler-builtins/libm/src/math/fminf128.rs create mode 100644 library/compiler-builtins/libm/src/math/fminf16.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index b233e34f18223..fbe0702a60d0c 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -47,7 +47,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16] }, None, - &["copysignf16", "fdimf16"], + &["copysignf16", "fdimf16", "fmaxf16", "fminf16"], ), ( // `(f32, f32) -> f32` @@ -90,7 +90,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F128, Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128] }, None, - &["copysignf128", "fdimf128"], + &["copysignf128", "fdimf128", "fmaxf128", "fminf128"], ), ( // `(f32, f32, f32) -> f32` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index d0ecd851e346f..aac8379fd4239 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -127,6 +127,10 @@ libm_macros::for_each_function! { | fdimf16 | floorf128 | floorf16 + | fmaxf128 + | fmaxf16 + | fminf128 + | fminf16 | rintf128 | rintf16 | roundf128 diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 4422ab88d0d15..da674c16273d5 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -192,8 +192,8 @@ libm_macros::for_each_function! { fabs | fabsf => abs, fdim | fdimf | fdimf16 | fdimf128 => positive_diff, fma | fmaf => mul_add, - fmax | fmaxf => max, - fmin | fminf => min, + fmax | fmaxf | fmaxf16 | fmaxf128 => max, + fmin | fminf | fminf16 | fminf128 => min, lgamma | lgammaf => ln_gamma, log | logf => ln, log1p | log1pf => ln_1p, diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 0fc1b0df13da7..ca070e8f6ac44 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -89,6 +89,10 @@ libm_macros::for_each_function! { fdimf16, floorf128, floorf16, + fmaxf128, + fmaxf16, + fminf128, + fminf16, rintf128, rintf16, roundf128, diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index aaedda6d152b2..eb8e37589561e 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -96,6 +96,10 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | fdimf16 | floorf128 | floorf16 + | fmaxf128 + | fmaxf16 + | fminf128 + | fminf16 | rintf128 | rintf16 | roundf128 diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 7ffe91eadd6f1..b6653295c10cb 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -391,6 +391,20 @@ ], "type": "f32" }, + "fmaxf128": { + "sources": [ + "src/math/fmaxf128.rs", + "src/math/generic/fmax.rs" + ], + "type": "f128" + }, + "fmaxf16": { + "sources": [ + "src/math/fmaxf16.rs", + "src/math/generic/fmax.rs" + ], + "type": "f16" + }, "fmin": { "sources": [ "src/libm_helper.rs", @@ -406,6 +420,20 @@ ], "type": "f32" }, + "fminf128": { + "sources": [ + "src/math/fminf128.rs", + "src/math/generic/fmin.rs" + ], + "type": "f128" + }, + "fminf16": { + "sources": [ + "src/math/fminf16.rs", + "src/math/generic/fmin.rs" + ], + "type": "f16" + }, "fmod": { "sources": [ "src/libm_helper.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 0b6eed828b521..25b92e58badaa 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -55,8 +55,12 @@ fma fmaf fmax fmaxf +fmaxf128 +fmaxf16 fmin fminf +fminf128 +fminf16 fmod fmodf frexp diff --git a/library/compiler-builtins/libm/src/math/fmaxf128.rs b/library/compiler-builtins/libm/src/math/fmaxf128.rs new file mode 100644 index 0000000000000..bace9ab53f2af --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmaxf128.rs @@ -0,0 +1,5 @@ +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaxf128(x: f128, y: f128) -> f128 { + super::generic::fmax(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/fmaxf16.rs b/library/compiler-builtins/libm/src/math/fmaxf16.rs new file mode 100644 index 0000000000000..fea15be8f1478 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmaxf16.rs @@ -0,0 +1,5 @@ +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaxf16(x: f16, y: f16) -> f16 { + super::generic::fmax(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/fminf128.rs b/library/compiler-builtins/libm/src/math/fminf128.rs new file mode 100644 index 0000000000000..a9224c22aa5de --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fminf128.rs @@ -0,0 +1,5 @@ +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminf128(x: f128, y: f128) -> f128 { + super::generic::fmin(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/fminf16.rs b/library/compiler-builtins/libm/src/math/fminf16.rs new file mode 100644 index 0000000000000..6d936be347a12 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fminf16.rs @@ -0,0 +1,5 @@ +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminf16(x: f16, y: f16) -> f16 { + super::generic::fmin(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 8db17a02dfce6..cb83b2587ee7a 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -346,6 +346,8 @@ cfg_if! { mod fabsf16; mod fdimf16; mod floorf16; + mod fmaxf16; + mod fminf16; mod rintf16; mod roundf16; mod sqrtf16; @@ -356,6 +358,8 @@ cfg_if! { pub use self::fabsf16::fabsf16; pub use self::fdimf16::fdimf16; pub use self::floorf16::floorf16; + pub use self::fmaxf16::fmaxf16; + pub use self::fminf16::fminf16; pub use self::rintf16::rintf16; pub use self::roundf16::roundf16; pub use self::sqrtf16::sqrtf16; @@ -370,6 +374,8 @@ cfg_if! { mod fabsf128; mod fdimf128; mod floorf128; + mod fmaxf128; + mod fminf128; mod rintf128; mod roundf128; mod sqrtf128; @@ -380,6 +386,8 @@ cfg_if! { pub use self::fabsf128::fabsf128; pub use self::fdimf128::fdimf128; pub use self::floorf128::floorf128; + pub use self::fmaxf128::fmaxf128; + pub use self::fminf128::fminf128; pub use self::rintf128::rintf128; pub use self::roundf128::roundf128; pub use self::sqrtf128::sqrtf128; From 08eda86de291c1cfa5959dac6f26fd7bd5a7392c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Jan 2025 05:02:47 +0000 Subject: [PATCH 1610/4206] Add a generic version of `fmod` This can replace `fmod` and `fmodf`. As part of this change I was able to replace some of the `while` loops with `leading_zeros`. --- .../libm/etc/function-definitions.json | 6 +- .../compiler-builtins/libm/src/math/fmod.rs | 77 +--------------- .../compiler-builtins/libm/src/math/fmodf.rs | 87 +------------------ .../libm/src/math/generic/fmod.rs | 84 ++++++++++++++++++ .../libm/src/math/generic/mod.rs | 2 + .../libm/src/math/support/int_traits.rs | 2 + 6 files changed, 96 insertions(+), 162 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/fmod.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index b6653295c10cb..866e9a4393092 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -437,13 +437,15 @@ "fmod": { "sources": [ "src/libm_helper.rs", - "src/math/fmod.rs" + "src/math/fmod.rs", + "src/math/generic/fmod.rs" ], "type": "f64" }, "fmodf": { "sources": [ - "src/math/fmodf.rs" + "src/math/fmodf.rs", + "src/math/generic/fmod.rs" ], "type": "f32" }, diff --git a/library/compiler-builtins/libm/src/math/fmod.rs b/library/compiler-builtins/libm/src/math/fmod.rs index b68e6b0ea3c86..d9786b53d7190 100644 --- a/library/compiler-builtins/libm/src/math/fmod.rs +++ b/library/compiler-builtins/libm/src/math/fmod.rs @@ -1,78 +1,5 @@ +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmod(x: f64, y: f64) -> f64 { - let mut uxi = x.to_bits(); - let mut uyi = y.to_bits(); - let mut ex = ((uxi >> 52) & 0x7ff) as i64; - let mut ey = ((uyi >> 52) & 0x7ff) as i64; - let sx = uxi >> 63; - let mut i; - - if uyi << 1 == 0 || y.is_nan() || ex == 0x7ff { - return (x * y) / (x * y); - } - if uxi << 1 <= uyi << 1 { - if uxi << 1 == uyi << 1 { - return 0.0 * x; - } - return x; - } - - /* normalize x and y */ - if ex == 0 { - i = uxi << 12; - while i >> 63 == 0 { - ex -= 1; - i <<= 1; - } - uxi <<= -ex + 1; - } else { - uxi &= u64::MAX >> 12; - uxi |= 1 << 52; - } - if ey == 0 { - i = uyi << 12; - while i >> 63 == 0 { - ey -= 1; - i <<= 1; - } - uyi <<= -ey + 1; - } else { - uyi &= u64::MAX >> 12; - uyi |= 1 << 52; - } - - /* x mod y */ - while ex > ey { - i = uxi.wrapping_sub(uyi); - if i >> 63 == 0 { - if i == 0 { - return 0.0 * x; - } - uxi = i; - } - uxi <<= 1; - ex -= 1; - } - i = uxi.wrapping_sub(uyi); - if i >> 63 == 0 { - if i == 0 { - return 0.0 * x; - } - uxi = i; - } - while uxi >> 52 == 0 { - uxi <<= 1; - ex -= 1; - } - - /* scale result */ - if ex > 0 { - uxi -= 1 << 52; - uxi |= (ex as u64) << 52; - } else { - uxi >>= -ex + 1; - } - uxi |= sx << 63; - - f64::from_bits(uxi) + super::generic::fmod(x, y) } diff --git a/library/compiler-builtins/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs index 4de18195770da..4e95696e20d63 100644 --- a/library/compiler-builtins/libm/src/math/fmodf.rs +++ b/library/compiler-builtins/libm/src/math/fmodf.rs @@ -1,88 +1,5 @@ -use core::f32; - +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmodf(x: f32, y: f32) -> f32 { - let mut uxi = x.to_bits(); - let mut uyi = y.to_bits(); - let mut ex = ((uxi >> 23) & 0xff) as i32; - let mut ey = ((uyi >> 23) & 0xff) as i32; - let sx = uxi & 0x80000000; - let mut i; - - if uyi << 1 == 0 || y.is_nan() || ex == 0xff { - return (x * y) / (x * y); - } - - if uxi << 1 <= uyi << 1 { - if uxi << 1 == uyi << 1 { - return 0.0 * x; - } - - return x; - } - - /* normalize x and y */ - if ex == 0 { - i = uxi << 9; - while i >> 31 == 0 { - ex -= 1; - i <<= 1; - } - - uxi <<= -ex + 1; - } else { - uxi &= u32::MAX >> 9; - uxi |= 1 << 23; - } - - if ey == 0 { - i = uyi << 9; - while i >> 31 == 0 { - ey -= 1; - i <<= 1; - } - - uyi <<= -ey + 1; - } else { - uyi &= u32::MAX >> 9; - uyi |= 1 << 23; - } - - /* x mod y */ - while ex > ey { - i = uxi.wrapping_sub(uyi); - if i >> 31 == 0 { - if i == 0 { - return 0.0 * x; - } - uxi = i; - } - uxi <<= 1; - - ex -= 1; - } - - i = uxi.wrapping_sub(uyi); - if i >> 31 == 0 { - if i == 0 { - return 0.0 * x; - } - uxi = i; - } - - while uxi >> 23 == 0 { - uxi <<= 1; - ex -= 1; - } - - /* scale result up */ - if ex > 0 { - uxi -= 1 << 23; - uxi |= (ex as u32) << 23; - } else { - uxi >>= -ex + 1; - } - uxi |= sx; - - f32::from_bits(uxi) + super::generic::fmod(x, y) } diff --git a/library/compiler-builtins/libm/src/math/generic/fmod.rs b/library/compiler-builtins/libm/src/math/generic/fmod.rs new file mode 100644 index 0000000000000..93da6c51e7e1b --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fmod.rs @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/fmod.c. Ported to generic Rust algorithm in 2025, TG. */ + +use super::super::{CastFrom, Float, Int, MinInt}; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmod(x: F, y: F) -> F { + let zero = F::Int::ZERO; + let one = F::Int::ONE; + let mut ix = x.to_bits(); + let mut iy = y.to_bits(); + let mut ex = x.exp().signed(); + let mut ey = y.exp().signed(); + let sx = ix & F::SIGN_MASK; + + if iy << 1 == zero || y.is_nan() || ex == F::EXP_MAX as i32 { + return (x * y) / (x * y); + } + + if ix << 1 <= iy << 1 { + if ix << 1 == iy << 1 { + return F::ZERO * x; + } + return x; + } + + /* normalize x and y */ + if ex == 0 { + let i = ix << F::EXP_BITS; + ex -= i.leading_zeros() as i32; + ix <<= -ex + 1; + } else { + ix &= F::Int::MAX >> F::EXP_BITS; + ix |= one << F::SIG_BITS; + } + + if ey == 0 { + let i = iy << F::EXP_BITS; + ey -= i.leading_zeros() as i32; + iy <<= -ey + 1; + } else { + iy &= F::Int::MAX >> F::EXP_BITS; + iy |= one << F::SIG_BITS; + } + + /* x mod y */ + while ex > ey { + let i = ix.wrapping_sub(iy); + if i >> (F::BITS - 1) == zero { + if i == zero { + return F::ZERO * x; + } + ix = i; + } + + ix <<= 1; + ex -= 1; + } + + let i = ix.wrapping_sub(iy); + if i >> (F::BITS - 1) == zero { + if i == zero { + return F::ZERO * x; + } + + ix = i; + } + + let shift = ix.leading_zeros().saturating_sub(F::EXP_BITS); + ix <<= shift; + ex -= shift as i32; + + /* scale result */ + if ex > 0 { + ix -= one << F::SIG_BITS; + ix |= F::Int::cast_from(ex) << F::SIG_BITS; + } else { + ix >>= -ex + 1; + } + + ix |= sx; + + F::from_bits(ix) +} diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index 819781a219aa6..68686b0b25503 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -5,6 +5,7 @@ mod fdim; mod floor; mod fmax; mod fmin; +mod fmod; mod rint; mod round; mod scalbn; @@ -18,6 +19,7 @@ pub use fdim::fdim; pub use floor::floor; pub use fmax::fmax; pub use fmin::fmin; +pub use fmod::fmod; pub use rint::rint; pub use round::round; pub use scalbn::scalbn; 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 cf19762e8169c..b403c658cb697 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -45,7 +45,9 @@ pub trait Int: + ops::BitOrAssign + ops::BitXorAssign + ops::ShlAssign + + ops::ShlAssign + ops::ShrAssign + + ops::ShrAssign + ops::Add + ops::Sub + ops::Mul From 67218cbaa5870c1fef896762719b4ba04b9fccdd Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Jan 2025 05:09:08 +0000 Subject: [PATCH 1611/4206] Add `fmodf16` using the generic implementation --- .../libm/crates/libm-macros/src/shared.rs | 2 +- .../libm/crates/libm-test/benches/icount.rs | 1 + .../libm/crates/libm-test/benches/random.rs | 1 + .../libm/crates/libm-test/src/mpfloat.rs | 17 +++++++++++++++++ .../libm-test/tests/compare_built_musl.rs | 1 + .../libm/crates/util/src/main.rs | 1 + .../libm/etc/function-definitions.json | 7 +++++++ .../libm/etc/function-list.txt | 1 + .../compiler-builtins/libm/src/math/fmodf16.rs | 5 +++++ library/compiler-builtins/libm/src/math/mod.rs | 2 ++ 10 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/libm/src/math/fmodf16.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index fbe0702a60d0c..69fe45e03ce07 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -47,7 +47,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16] }, None, - &["copysignf16", "fdimf16", "fmaxf16", "fminf16"], + &["copysignf16", "fdimf16", "fmaxf16", "fminf16", "fmodf16"], ), ( // `(f32, f32) -> f32` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index 84f9532626799..97e78d8f1b121 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -111,6 +111,7 @@ main!( icount_bench_fmin_group, icount_bench_fminf_group, icount_bench_fmod_group, + icount_bench_fmodf16_group, icount_bench_fmodf_group, icount_bench_frexp_group, icount_bench_frexpf_group, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index aac8379fd4239..3e816e81a6131 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -131,6 +131,7 @@ libm_macros::for_each_function! { | fmaxf16 | fminf128 | fminf16 + | fmodf16 | rintf128 | rintf16 | roundf128 diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index da674c16273d5..56234b14a527b 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -152,6 +152,7 @@ libm_macros::for_each_function! { floorf16, fmod, fmodf, + fmodf16, frexp, frexpf, ilogb, @@ -525,6 +526,22 @@ impl MpOp for crate::op::lgammaf_r::Routine { } } +// No fmodf128 yet +impl MpOp for crate::op::fmodf16::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.rem_assign_round(&this.1, Nearest); + prep_retval::(&mut this.0, ord) + } +} + /* stub implementations so we don't need to special case them */ impl MpOp for crate::op::nextafter::Routine { diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index ca070e8f6ac44..46474c04688e3 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -93,6 +93,7 @@ libm_macros::for_each_function! { fmaxf16, fminf128, fminf16, + fmodf16, rintf128, rintf16, roundf128, diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index eb8e37589561e..999b03af9e311 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -100,6 +100,7 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | fmaxf16 | fminf128 | fminf16 + | fmodf16 | rintf128 | rintf16 | roundf128 diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 866e9a4393092..966060f77c446 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -449,6 +449,13 @@ ], "type": "f32" }, + "fmodf16": { + "sources": [ + "src/math/fmodf16.rs", + "src/math/generic/fmod.rs" + ], + "type": "f16" + }, "frexp": { "sources": [ "src/libm_helper.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 25b92e58badaa..ff4de0cb5d4e0 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -63,6 +63,7 @@ fminf128 fminf16 fmod fmodf +fmodf16 frexp frexpf hypot diff --git a/library/compiler-builtins/libm/src/math/fmodf16.rs b/library/compiler-builtins/libm/src/math/fmodf16.rs new file mode 100644 index 0000000000000..11972a7de4ff0 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmodf16.rs @@ -0,0 +1,5 @@ +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf16(x: f16, y: f16) -> f16 { + super::generic::fmod(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index cb83b2587ee7a..aab551bedbdba 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -348,6 +348,7 @@ cfg_if! { mod floorf16; mod fmaxf16; mod fminf16; + mod fmodf16; mod rintf16; mod roundf16; mod sqrtf16; @@ -360,6 +361,7 @@ cfg_if! { pub use self::floorf16::floorf16; pub use self::fmaxf16::fmaxf16; pub use self::fminf16::fminf16; + pub use self::fmodf16::fmodf16; pub use self::rintf16::rintf16; pub use self::roundf16::roundf16; pub use self::sqrtf16::sqrtf16; From 9d38c93fb080ce30b2f57b017f9220f26f3b9d13 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Jan 2025 06:24:45 +0000 Subject: [PATCH 1612/4206] Increase or set CI timeouts With the new routines, some of our tests are running close to their timeouts. Increase the timeout for test jobs, and set a short timeout for all other jobs that did not have one. --- .../compiler-builtins/libm/.github/workflows/main.yaml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index 89c5facef44da..59955271170fb 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -15,7 +15,7 @@ env: jobs: test: name: Build and test - timeout-minutes: 40 + timeout-minutes: 60 strategy: fail-fast: false matrix: @@ -123,6 +123,7 @@ jobs: clippy: name: Clippy runs-on: ubuntu-24.04 + timeout-minutes: 10 steps: - uses: actions/checkout@master - name: Install Rust @@ -138,6 +139,7 @@ jobs: builtins: name: Check use with compiler-builtins runs-on: ubuntu-24.04 + timeout-minutes: 10 steps: - uses: actions/checkout@master - name: Install Rust @@ -194,6 +196,7 @@ jobs: msrv: name: Check MSRV runs-on: ubuntu-24.04 + timeout-minutes: 10 env: RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings` steps: @@ -210,6 +213,7 @@ jobs: rustfmt: name: Rustfmt runs-on: ubuntu-24.04 + timeout-minutes: 10 steps: - uses: actions/checkout@master - name: Install Rust @@ -223,6 +227,7 @@ jobs: calculate_extensive_matrix: name: Calculate job matrix runs-on: ubuntu-24.04 + timeout-minutes: 10 outputs: matrix: ${{ steps.script.outputs.matrix }} steps: @@ -242,7 +247,7 @@ jobs: - clippy - calculate_extensive_matrix runs-on: ubuntu-24.04 - timeout-minutes: 80 + timeout-minutes: 180 strategy: matrix: # Use the output from `calculate_extensive_matrix` to calculate the matrix @@ -286,6 +291,7 @@ jobs: - rustfmt - extensive runs-on: ubuntu-24.04 + timeout-minutes: 10 # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency # failed" as success. So we have to do some contortions to ensure the job fails if any of its # dependencies fails. From b863308979d4e57115227f751ab408c8b4cfc3a5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Jan 2025 07:59:09 +0000 Subject: [PATCH 1613/4206] Add way to override the number of iterations for specific tests Certain functions (`fmodf128`) are significantly slower than others, to the point that running the default number of tests adds tens of minutes to PR CI and extensive test time increases to ~1day. It does not make sense to do this by default; so, introduce `EXTREMELY_SLOW_TESTS` to test configuration that allows setting specific tests that need to have a reduced iteration count. --- .../libm/crates/libm-test/src/lib.rs | 4 +-- .../libm/crates/libm-test/src/run_cfg.rs | 34 +++++++++++++++---- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index b90423c1bacce..78b011b1f2338 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -28,7 +28,7 @@ pub use op::{ Ty, }; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; -use run_cfg::EXTENSIVE_MAX_ITERATIONS; +use run_cfg::extensive_max_iterations; pub use run_cfg::{CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind, skip_extensive_test}; pub use test_traits::{CheckOutput, Hex, TupleCall}; @@ -89,7 +89,7 @@ pub fn test_log(s: &str) { writeln!(f, "cargo features: {}", env!("CFG_CARGO_FEATURES")).unwrap(); writeln!(f, "opt level: {}", env!("CFG_OPT_LEVEL")).unwrap(); writeln!(f, "target features: {}", env!("CFG_TARGET_FEATURES")).unwrap(); - writeln!(f, "extensive iterations {}", *EXTENSIVE_MAX_ITERATIONS).unwrap(); + writeln!(f, "extensive iterations {}", extensive_max_iterations()).unwrap(); Some(f) }); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index 3e91101f6cacf..c76b6699faf35 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -13,18 +13,27 @@ pub const EXTENSIVE_ENV: &str = "LIBM_EXTENSIVE_TESTS"; /// Specify the number of iterations via this environment variable, rather than using the default. pub const EXTENSIVE_ITER_ENV: &str = "LIBM_EXTENSIVE_ITERATIONS"; +/// The override value, if set by the above environment. +static EXTENSIVE_ITER_OVERRIDE: LazyLock> = LazyLock::new(|| { + env::var(EXTENSIVE_ITER_ENV).map(|v| v.parse().expect("failed to parse iteration count")).ok() +}); + +/// Specific tests that need to have a reduced amount of iterations to complete in a reasonable +/// amount of time. +/// +/// Contains the itentifier+generator combo to match on, plus the factor to reduce by. +const EXTEMELY_SLOW_TESTS: &[(Identifier, GeneratorKind, u64)] = &[]; + /// Maximum number of iterations to run for a single routine. /// /// The default value of one greater than `u32::MAX` allows testing single-argument `f32` routines /// and single- or double-argument `f16` routines exhaustively. `f64` and `f128` can't feasibly /// be tested exhaustively; however, [`EXTENSIVE_ITER_ENV`] can be set to run tests for multiple /// hours. -pub static EXTENSIVE_MAX_ITERATIONS: LazyLock = LazyLock::new(|| { - let default = 1 << 32; - env::var(EXTENSIVE_ITER_ENV) - .map(|v| v.parse().expect("failed to parse iteration count")) - .unwrap_or(default) -}); +pub fn extensive_max_iterations() -> u64 { + let default = 1 << 32; // default value + EXTENSIVE_ITER_OVERRIDE.unwrap_or(default) +} /// Context passed to [`CheckOutput`]. #[derive(Clone, Debug, PartialEq, Eq)] @@ -206,12 +215,23 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { let mut total_iterations = match ctx.gen_kind { GeneratorKind::QuickSpaced => domain_iter_count, GeneratorKind::Random => random_iter_count, - GeneratorKind::Extensive => *EXTENSIVE_MAX_ITERATIONS, + GeneratorKind::Extensive => extensive_max_iterations(), GeneratorKind::EdgeCases => { unimplemented!("edge case tests shoudn't need `iteration_count`") } }; + // Some tests are significantly slower than others and need to be further reduced. + if let Some((_id, _gen, scale)) = EXTEMELY_SLOW_TESTS + .iter() + .find(|(id, gen, _scale)| *id == ctx.fn_ident && *gen == ctx.gen_kind) + { + // However, do not override if the extensive iteration count has been manually set. + if !(ctx.gen_kind == GeneratorKind::Extensive && EXTENSIVE_ITER_OVERRIDE.is_some()) { + total_iterations /= scale; + } + } + // FMA has a huge domain but is reasonably fast to run, so increase iterations. if ctx.base_name == BaseName::Fma { total_iterations *= 4; From 71200bc3ce854c6c15e05c9588954b49a7aea095 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Jan 2025 05:58:08 +0000 Subject: [PATCH 1614/4206] Add `fmodf128` This function is significantly slower than all others so includes an override in `EXTREMELY_SLOW_TESTS`. Without it, PR CI takes ~1hour and the extensive tests in CI take ~1day. --- .../libm/crates/libm-macros/src/shared.rs | 2 +- .../libm/crates/libm-test/benches/icount.rs | 1 + .../libm/crates/libm-test/benches/random.rs | 1 + .../libm/crates/libm-test/src/mpfloat.rs | 47 +++++++------------ .../libm/crates/libm-test/src/run_cfg.rs | 5 +- .../libm-test/tests/compare_built_musl.rs | 1 + .../libm/crates/util/src/main.rs | 1 + .../libm/etc/function-definitions.json | 7 +++ .../libm/etc/function-list.txt | 1 + .../libm/src/math/fmodf128.rs | 5 ++ .../compiler-builtins/libm/src/math/mod.rs | 2 + 11 files changed, 40 insertions(+), 33 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fmodf128.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index 69fe45e03ce07..b1f4f46cc3bb6 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -90,7 +90,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F128, Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128] }, None, - &["copysignf128", "fdimf128", "fmaxf128", "fminf128"], + &["copysignf128", "fdimf128", "fmaxf128", "fminf128", "fmodf128"], ), ( // `(f32, f32, f32) -> f32` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index 97e78d8f1b121..46a659524a69c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -111,6 +111,7 @@ main!( icount_bench_fmin_group, icount_bench_fminf_group, icount_bench_fmod_group, + icount_bench_fmodf128_group, icount_bench_fmodf16_group, icount_bench_fmodf_group, icount_bench_frexp_group, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 3e816e81a6131..ca9e86c10bf95 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -131,6 +131,7 @@ libm_macros::for_each_function! { | fmaxf16 | fminf128 | fminf16 + | fmodf128 | fmodf16 | rintf128 | rintf16 diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 56234b14a527b..98b80505f264a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -152,6 +152,7 @@ libm_macros::for_each_function! { floorf16, fmod, fmodf, + fmodf128, fmodf16, frexp, frexpf, @@ -301,21 +302,6 @@ macro_rules! impl_op_for_ty { } } - 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.rem_assign_round(&this.1, Nearest); - prep_retval::(&mut this.0, ord) - } - } - impl MpOp for crate::op::[]::Routine { type MpTy = MpFloat; @@ -481,6 +467,21 @@ macro_rules! impl_op_for_ty_all { prep_retval::(&mut this.0, Ordering::Equal) } } + + 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.rem_assign_round(&this.1, Nearest); + prep_retval::(&mut this.0, ord) + } + } } }; } @@ -526,22 +527,6 @@ impl MpOp for crate::op::lgammaf_r::Routine { } } -// No fmodf128 yet -impl MpOp for crate::op::fmodf16::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.rem_assign_round(&this.1, Nearest); - prep_retval::(&mut this.0, ord) - } -} - /* stub implementations so we don't need to special case them */ impl MpOp for crate::op::nextafter::Routine { diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index c76b6699faf35..783142e37836a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -22,7 +22,10 @@ static EXTENSIVE_ITER_OVERRIDE: LazyLock> = LazyLock::new(|| { /// amount of time. /// /// Contains the itentifier+generator combo to match on, plus the factor to reduce by. -const EXTEMELY_SLOW_TESTS: &[(Identifier, GeneratorKind, u64)] = &[]; +const EXTEMELY_SLOW_TESTS: &[(Identifier, GeneratorKind, u64)] = &[ + (Identifier::Fmodf128, GeneratorKind::QuickSpaced, 40), + (Identifier::Fmodf128, GeneratorKind::Extensive, 40), +]; /// Maximum number of iterations to run for a single routine. /// diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 46474c04688e3..5466edf4f4c1f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -93,6 +93,7 @@ libm_macros::for_each_function! { fmaxf16, fminf128, fminf16, + fmodf128, fmodf16, rintf128, rintf16, diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index 999b03af9e311..f4ee8fd2e3864 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -100,6 +100,7 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | fmaxf16 | fminf128 | fminf16 + | fmodf128 | fmodf16 | rintf128 | rintf16 diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 966060f77c446..574ffea2e5082 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -449,6 +449,13 @@ ], "type": "f32" }, + "fmodf128": { + "sources": [ + "src/math/fmodf128.rs", + "src/math/generic/fmod.rs" + ], + "type": "f128" + }, "fmodf16": { "sources": [ "src/math/fmodf16.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index ff4de0cb5d4e0..d82838b3233d4 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -63,6 +63,7 @@ fminf128 fminf16 fmod fmodf +fmodf128 fmodf16 frexp frexpf diff --git a/library/compiler-builtins/libm/src/math/fmodf128.rs b/library/compiler-builtins/libm/src/math/fmodf128.rs new file mode 100644 index 0000000000000..ff0e0493e26b6 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmodf128.rs @@ -0,0 +1,5 @@ +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf128(x: f128, y: f128) -> f128 { + super::generic::fmod(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index aab551bedbdba..969c1bfd942aa 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -378,6 +378,7 @@ cfg_if! { mod floorf128; mod fmaxf128; mod fminf128; + mod fmodf128; mod rintf128; mod roundf128; mod sqrtf128; @@ -390,6 +391,7 @@ cfg_if! { pub use self::floorf128::floorf128; pub use self::fmaxf128::fmaxf128; pub use self::fminf128::fminf128; + pub use self::fmodf128::fmodf128; pub use self::rintf128::rintf128; pub use self::roundf128::roundf128; pub use self::sqrtf128::sqrtf128; From 173a48ce8c8f6acfa2cc7173138600d3fde9d12e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Jan 2025 09:11:07 +0000 Subject: [PATCH 1615/4206] Enable missing icount benchmarks A few new functions were added but this list did not get updated. Do so here. --- .../libm/crates/libm-test/benches/icount.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index 46a659524a69c..d5026f461b0f5 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -107,8 +107,12 @@ main!( icount_bench_fma_group, icount_bench_fmaf_group, icount_bench_fmax_group, + icount_bench_fmaxf128_group, + icount_bench_fmaxf16_group, icount_bench_fmaxf_group, icount_bench_fmin_group, + icount_bench_fminf128_group, + icount_bench_fminf16_group, icount_bench_fminf_group, icount_bench_fmod_group, icount_bench_fmodf128_group, @@ -155,6 +159,8 @@ main!( icount_bench_rintf16_group, icount_bench_rintf_group, icount_bench_round_group, + icount_bench_roundf128_group, + icount_bench_roundf16_group, icount_bench_roundf_group, icount_bench_scalbn_group, icount_bench_scalbnf_group, From 7c6c0c1b79e92e36525faa4de90eee0fefde1a73 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 25 Jan 2025 00:50:02 +0000 Subject: [PATCH 1616/4206] Upgrade all dependencies to the latest version In particular, this includes updates to Rug that we can make use of [1], [2], [3], [4]. [1]: https://gitlab.com/tspiteri/rug/-/issues/78 [2]: https://gitlab.com/tspiteri/rug/-/issues/80 [3]: https://gitlab.com/tspiteri/rug/-/issues/76 [4]: https://gitlab.com/tspiteri/rug/-/issues/73 --- library/compiler-builtins/libm/Cargo.toml | 2 +- .../compiler-builtins/libm/crates/libm-macros/Cargo.toml | 6 +++--- library/compiler-builtins/libm/crates/libm-test/Cargo.toml | 4 ++-- .../compiler-builtins/libm/crates/musl-math-sys/Cargo.toml | 2 +- library/compiler-builtins/libm/crates/util/Cargo.toml | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 18d89997dcba6..7b6f9e1cecba9 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -59,7 +59,7 @@ exclude = [ ] [dev-dependencies] -no-panic = "0.1.30" +no-panic = "0.1.33" [profile.release] # Options for no-panic to correctly detect the lack of panics diff --git a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml index 9194232b24c2f..f0de0e17689c3 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml @@ -9,9 +9,9 @@ proc-macro = true [dependencies] heck = "0.5.0" -proc-macro2 = "1.0.88" -quote = "1.0.37" -syn = { version = "2.0.79", features = ["full", "extra-traits", "visit-mut"] } +proc-macro2 = "1.0.93" +quote = "1.0.38" +syn = { version = "2.0.96", features = ["full", "extra-traits", "visit-mut"] } [lints.rust] # Values used during testing diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 3a1ba87962a7d..137b814642309 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -27,7 +27,7 @@ icount = ["dep:iai-callgrind"] short-benchmarks = [] [dependencies] -anyhow = "1.0.90" +anyhow = "1.0.95" az = { version = "1.2.1", optional = true } gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false, features = ["mpfr"] } iai-callgrind = { version = "0.14.0", optional = true } @@ -39,7 +39,7 @@ paste = "1.0.15" rand = "0.8.5" rand_chacha = "0.3.1" rayon = "1.10.0" -rug = { version = "1.26.1", optional = true, default-features = false, features = ["float", "integer", "std"] } +rug = { version = "1.27.0", optional = true, default-features = false, features = ["float", "integer", "std"] } [target.'cfg(target_family = "wasm")'.dependencies] # Enable randomness on WASM diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml index 7f6272d79ed96..cde78fd3c9712 100644 --- a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml +++ b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml @@ -10,4 +10,4 @@ publish = false libm = { path = "../../" } [build-dependencies] -cc = "1.1.24" +cc = "1.2.10" diff --git a/library/compiler-builtins/libm/crates/util/Cargo.toml b/library/compiler-builtins/libm/crates/util/Cargo.toml index acf5db704b159..51f44dddfaf79 100644 --- a/library/compiler-builtins/libm/crates/util/Cargo.toml +++ b/library/compiler-builtins/libm/crates/util/Cargo.toml @@ -16,4 +16,4 @@ libm = { path = "../..", default-features = false } libm-macros = { path = "../libm-macros" } libm-test = { path = "../libm-test", default-features = false } musl-math-sys = { path = "../musl-math-sys", optional = true } -rug = { version = "1.26.1", optional = true, default-features = false, features = ["float", "std"] } +rug = { version = "1.27.0", optional = true, default-features = false, features = ["float", "std"] } From 62f0fd40d1ca80b11ad68f4d310069b76ed12aa5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 25 Jan 2025 00:55:03 +0000 Subject: [PATCH 1617/4206] Use `az` exported from Rug Since Rug 1.27.0, `az` is reexported. This means we no longer need to track it as a separate dependency. --- library/compiler-builtins/libm/crates/libm-test/Cargo.toml | 3 +-- .../compiler-builtins/libm/crates/libm-test/src/mpfloat.rs | 2 +- library/compiler-builtins/libm/crates/util/Cargo.toml | 3 +-- library/compiler-builtins/libm/crates/util/src/main.rs | 4 ++-- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 137b814642309..31cbf6e680246 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -12,7 +12,7 @@ unstable-float = ["libm/unstable-float", "rug?/nightly-float"] # Generate tests which are random inputs and the outputs are calculated with # musl libc. -build-mpfr = ["dep:az", "dep:rug", "dep:gmp-mpfr-sys"] +build-mpfr = ["dep:rug", "dep:gmp-mpfr-sys"] # Build our own musl for testing and benchmarks build-musl = ["dep:musl-math-sys"] @@ -28,7 +28,6 @@ short-benchmarks = [] [dependencies] anyhow = "1.0.95" -az = { version = "1.2.1", optional = true } gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false, features = ["mpfr"] } iai-callgrind = { version = "0.14.0", optional = true } indicatif = { version = "0.17.9", default-features = false } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 98b80505f264a..e2be6584d2323 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -6,10 +6,10 @@ use std::cmp::Ordering; use std::ffi::{c_int, c_long}; -use az::Az; use gmp_mpfr_sys::mpfr::rnd_t; use rug::Assign; pub use rug::Float as MpFloat; +use rug::az::{self, Az}; use rug::float::Round; use rug::float::Round::Nearest; use rug::ops::{PowAssignRound, RemAssignRound}; diff --git a/library/compiler-builtins/libm/crates/util/Cargo.toml b/library/compiler-builtins/libm/crates/util/Cargo.toml index 51f44dddfaf79..8005459dbf930 100644 --- a/library/compiler-builtins/libm/crates/util/Cargo.toml +++ b/library/compiler-builtins/libm/crates/util/Cargo.toml @@ -7,11 +7,10 @@ publish = false [features] default = ["build-musl", "build-mpfr", "unstable-float"] build-musl = ["libm-test/build-musl", "dep:musl-math-sys"] -build-mpfr = ["libm-test/build-mpfr", "dep:az", "dep:rug"] +build-mpfr = ["libm-test/build-mpfr", "dep:rug"] unstable-float = ["libm/unstable-float", "libm-test/unstable-float", "rug?/nightly-float"] [dependencies] -az = { version = "1.2.1", optional = true } libm = { path = "../..", default-features = false } libm-macros = { path = "../libm-macros" } libm-test = { path = "../libm-test", default-features = false } diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index f4ee8fd2e3864..6ea1be3d9aedc 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -8,12 +8,12 @@ use std::env; use std::num::ParseIntError; use std::str::FromStr; -#[cfg(feature = "build-mpfr")] -use az::Az; use libm::support::{hf32, hf64}; #[cfg(feature = "build-mpfr")] use libm_test::mpfloat::MpOp; use libm_test::{MathOp, TupleCall}; +#[cfg(feature = "build-mpfr")] +use rug::az::{self, Az}; const USAGE: &str = "\ usage: From edd12893410c1fdcb73a4a365b28bd8a9b998e8a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 25 Jan 2025 01:00:01 +0000 Subject: [PATCH 1618/4206] Use `frexp` from Rug Rug 1.27.0 exposes `frexp`. Make use of it for our tests. --- .../compiler-builtins/libm/crates/libm-test/src/mpfloat.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index e2be6584d2323..6896425d15733 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -310,13 +310,8 @@ macro_rules! impl_op_for_ty { } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - // Implementation taken from `rug::Float::to_f32_exp`. this.assign(input.0); - let exp = this.get_exp().unwrap_or(0); - if exp != 0 { - *this >>= exp; - } - + let exp = this.frexp_mut(); (prep_retval::(this, Ordering::Equal), exp) } } From b9bd107a6747b3ac44e45b2acbe8a665deb9ffaf Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 25 Jan 2025 01:01:24 +0000 Subject: [PATCH 1619/4206] Use `remquo` from Rug Rug 1.27.0 exposes `remquo`; make use of it for our tests. Removing our workaround also allows removing the direct dependency on `gmp-mpfr-sys` --- .../libm/crates/libm-test/Cargo.toml | 3 +- .../libm/crates/libm-test/src/mpfloat.rs | 38 ++----------------- .../libm/crates/libm-test/src/precision.rs | 31 --------------- 3 files changed, 5 insertions(+), 67 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 31cbf6e680246..dcbddb667e81e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -28,7 +28,8 @@ short-benchmarks = [] [dependencies] anyhow = "1.0.95" -gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false, features = ["mpfr"] } +# This is not directly used but is required so we can enable `gmp-mpfr-sys/force-cross`. +gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false } iai-callgrind = { version = "0.14.0", optional = true } indicatif = { version = "0.17.9", default-features = false } libm = { path = "../..", features = ["unstable-public-internals"] } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 6896425d15733..3d84740ccd792 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -4,13 +4,10 @@ //! a struct named `Operation` that implements [`MpOp`]. use std::cmp::Ordering; -use std::ffi::{c_int, c_long}; -use gmp_mpfr_sys::mpfr::rnd_t; use rug::Assign; pub use rug::Float as MpFloat; use rug::az::{self, Az}; -use rug::float::Round; use rug::float::Round::Nearest; use rug::ops::{PowAssignRound, RemAssignRound}; @@ -401,28 +398,20 @@ macro_rules! impl_op_for_ty { } impl MpOp for crate::op::[]::Routine { - type MpTy = (MpFloat, MpFloat, MpFloat); + type MpTy = (MpFloat, MpFloat); fn new_mp() -> Self::MpTy { ( new_mpfloat::(), 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, ql) = mpfr_remquo(&mut this.2, &this.0, &this.1, Nearest); - - // `remquo` integer results are sign-magnitude representation. Transfer the - // sign bit from the long result to the int result. - let clear = !(1 << (c_int::BITS - 1)); - let sign = ((ql >> (c_long::BITS - 1)) as i32) << (c_int::BITS - 1); - let q = (ql as i32) & clear | sign; - - (prep_retval::(&mut this.2, ord), q) + let (ord, q) = this.0.remainder_quo31_round(&this.1, Nearest); + (prep_retval::(&mut this.0, ord), q) } } @@ -547,24 +536,3 @@ impl MpOp for crate::op::nextafterf::Routine { unimplemented!("nextafter does not yet have a MPFR operation"); } } - -/// `rug` does not provide `remquo` so this exposes `mpfr_remquo`. See rug#76. -fn mpfr_remquo(r: &mut MpFloat, x: &MpFloat, y: &MpFloat, round: Round) -> (Ordering, c_long) { - let r = r.as_raw_mut(); - let x = x.as_raw(); - let y = y.as_raw(); - let mut q: c_long = 0; - - let round = match round { - Round::Nearest => rnd_t::RNDN, - Round::Zero => rnd_t::RNDZ, - Round::Up => rnd_t::RNDU, - Round::Down => rnd_t::RNDD, - Round::AwayZero => rnd_t::RNDA, - _ => unreachable!(), - }; - - // SAFETY: mutable and const pointers are valid and do not alias, by Rust's rules. - let ord = unsafe { gmp_mpfr_sys::mpfr::remquo(r, &mut q, x, y, round) }; - (ord.cmp(&0), q) -} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index bed6158825a52..ffb322e38ff86 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -405,15 +405,6 @@ impl MaybeOverride<(f32, f32)> for SpecialCase { ) -> CheckAction { binop_common(input, actual, expected, ctx) } - - fn check_int( - _input: (f32, f32), - actual: I, - expected: I, - ctx: &CheckCtx, - ) -> CheckAction { - remquo_common(actual, expected, ctx) - } } impl MaybeOverride<(f64, f64)> for SpecialCase { @@ -425,15 +416,6 @@ impl MaybeOverride<(f64, f64)> for SpecialCase { ) -> CheckAction { binop_common(input, actual, expected, ctx) } - - fn check_int( - _input: (f64, f64), - actual: I, - expected: I, - ctx: &CheckCtx, - ) -> CheckAction { - remquo_common(actual, expected, ctx) - } } #[cfg(f128_enabled)] @@ -496,19 +478,6 @@ fn binop_common( DEFAULT } -fn remquo_common(actual: I, expected: I, ctx: &CheckCtx) -> CheckAction { - // FIXME: Our MPFR implementation disagrees with musl and may need to be updated. - if ctx.basis == CheckBasis::Mpfr - && ctx.base_name == BaseName::Remquo - && expected == I::MIN - && actual == I::ZERO - { - return XFAIL("remquo integer mismatch"); - } - - DEFAULT -} - impl MaybeOverride<(i32, f32)> for SpecialCase { fn check_float( input: (i32, f32), From 4a98907b8a9f7cabf758fa7241466a62735fba88 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 25 Jan 2025 04:18:44 +0000 Subject: [PATCH 1620/4206] Remove remnants of the `checked` feature The Cargo feature `checked` was added in 410b0633a6b9 ("Overhaul tests") and later removed in e4ac1399062c ("swap stable to be unstable, checked is now debug_assertions"). However, there are a few remaining uses of `feature = "checked"` that did not get removed. Clean these up here. --- library/compiler-builtins/libm/build.rs | 19 +++++++------------ .../compiler-builtins-smoke-test/Cargo.toml | 1 - .../libm/src/math/rem_pio2_large.rs | 5 +++-- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index ca4a639a12ac9..caf5a108a263a 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -8,18 +8,13 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rustc-check-cfg=cfg(assert_no_panic)"); - println!("cargo:rustc-check-cfg=cfg(feature, values(\"checked\"))"); - - #[allow(unexpected_cfgs)] - if !cfg!(feature = "checked") { - let lvl = env::var("OPT_LEVEL").unwrap(); - if lvl != "0" && !cfg!(debug_assertions) { - println!("cargo:rustc-cfg=assert_no_panic"); - } else if env::var("ENSURE_NO_PANIC").is_ok() { - // Give us a defensive way of ensureing that no-panic is checked when we - // expect it to be. - panic!("`assert_no_panic `was not enabled"); - } + let lvl = env::var("OPT_LEVEL").unwrap(); + if lvl != "0" && !cfg!(debug_assertions) { + println!("cargo:rustc-cfg=assert_no_panic"); + } else if env::var("ENSURE_NO_PANIC").is_ok() { + // Give us a defensive way of ensureing that no-panic is checked when we + // expect it to be. + panic!("`assert_no_panic `was not enabled"); } configure::emit_libm_config(&cfg); diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index d578b0dcd0bdb..24b33645e97c5 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -22,7 +22,6 @@ unexpected_cfgs = { level = "warn", check-cfg = [ "cfg(arch_enabled)", "cfg(assert_no_panic)", "cfg(intrinsics_enabled)", - 'cfg(feature, values("checked"))', 'cfg(feature, values("force-soft-floats"))', 'cfg(feature, values("unstable"))', 'cfg(feature, values("unstable-intrinsics"))', 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 ec8397f4b6fc2..6d679bbe98c48 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -226,8 +226,9 @@ pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24 let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24) - #[cfg(all(target_pointer_width = "64", feature = "checked"))] - assert!(e0 <= 16360); + if cfg!(target_pointer_width = "64") { + debug_assert!(e0 <= 16360); + } let nx = x.len(); From f0b932e723f05035ced4f04ff069437d4015b3d1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 25 Jan 2025 05:22:11 +0000 Subject: [PATCH 1621/4206] Rework the available Cargo profiles Currently the default release profile enables LTO and single CGU builds, which is very slow to build. Most tests are better run with optimizations enabled since it allows testing a much larger number of inputs, so it is inconvenient that building can sometimes take significantly longer than the tests. Remedy this by doing the following: * Move the existing `release` profile to `release-opt`. * With the above, the default `release` profile is untouched (16 CGUs and thin local LTO). * `release-checked` inherits `release`, so no LTO or single CGU. This means that the simple `cargo test --release` becomes much faster for local development. We are able to enable the other profiles as needed in CI. Tests should ideally still be run with `--profile release-checked` to ensure there are no debug assetions or unexpected wrapping math hit. `no-panic` still needs a single CGU, so must be run with `--profile release-opt`. Since it is not possible to detect CGU or profilel configuration from within build scripts, the `ENSURE_NO_PANIC` environment variable must now always be set. --- library/compiler-builtins/libm/Cargo.toml | 14 ++++++++------ library/compiler-builtins/libm/build.rs | 8 ++------ library/compiler-builtins/libm/ci/run.sh | 12 +++++++++++- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 7b6f9e1cecba9..08342a929290a 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -61,18 +61,20 @@ exclude = [ [dev-dependencies] no-panic = "0.1.33" -[profile.release] -# Options for no-panic to correctly detect the lack of panics -codegen-units = 1 -lto = "fat" +# The default release profile is unchanged. # Release mode with debug assertions [profile.release-checked] -codegen-units = 1 +inherits = "release" debug-assertions = true +overflow-checks = true + +# Release with maximum optimizations, which is very slow to build. This is also +# what is needed to check `no-panic`. +[profile.release-opt] inherits = "release" +codegen-units = 1 lto = "fat" -overflow-checks = true [profile.bench] # Required for iai-callgrind diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index caf5a108a263a..7042b54d7e806 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -8,13 +8,9 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rustc-check-cfg=cfg(assert_no_panic)"); - let lvl = env::var("OPT_LEVEL").unwrap(); - if lvl != "0" && !cfg!(debug_assertions) { + // 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"); - } else if env::var("ENSURE_NO_PANIC").is_ok() { - // Give us a defensive way of ensureing that no-panic is checked when we - // expect it to be. - panic!("`assert_no_panic `was not enabled"); } configure::emit_libm_config(&cfg); diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/libm/ci/run.sh index 296986d972716..a946d325ebd41 100755 --- a/library/compiler-builtins/libm/ci/run.sh +++ b/library/compiler-builtins/libm/ci/run.sh @@ -117,4 +117,14 @@ $cmd "$profile" release-checked --features unstable-intrinsics $cmd "$profile" release-checked --features unstable-intrinsics --benches # Ensure that the routines do not panic. -ENSURE_NO_PANIC=1 cargo build -p libm --target "$target" --no-default-features --release +# +# `--tests` must be passed because no-panic is only enabled as a dev +# dependency. The `release-opt` profile must be used to enable LTO and a +# single CGU. +ENSURE_NO_PANIC=1 cargo build \ + -p libm \ + --target "$target" \ + --no-default-features \ + --features unstable-float \ + --tests \ + --profile release-opt From 90c76ad3cb1663592d875d0e2468a84961187800 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 27 Jan 2025 11:37:01 +0000 Subject: [PATCH 1622/4206] Ignore specific `atan2` and `sin` tests on i586 There seems to be a case of unsoundness with the `i586` version of `atan2`. For the following test: assert_eq!(atan2(2.0, -1.0), atan(2.0 / -1.0) + PI);atan2(2.0, -1.0) The output is optimization-dependent. The new `release-checked` profile produces the following failure: thread 'math::atan2::sanity_check' panicked at src/math/atan2.rs:123:5: assertion `left == right` failed left: 2.0344439357957027 right: 2.0344439357957027 Similarly, `sin::test_near_pi` fails with the following: thread 'math::sin::test_near_pi' panicked at src/math/sin.rs:91:5: assertion `left == right` failed left: 6.273720864039203e-7 right: 6.273720864039205e-7 Mark the tests ignored on `i586` for now. --- .../compiler-builtins/libm/src/math/atan2.rs | 22 ++++++++++++------- .../compiler-builtins/libm/src/math/sin.rs | 19 +++++++++------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs index b9bf0da935bc7..c668731cf3760 100644 --- a/library/compiler-builtins/libm/src/math/atan2.rs +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -114,12 +114,18 @@ pub fn atan2(y: f64, x: f64) -> f64 { } } -#[test] -fn sanity_check() { - assert_eq!(atan2(0.0, 1.0), 0.0); - assert_eq!(atan2(0.0, -1.0), PI); - assert_eq!(atan2(-0.0, -1.0), -PI); - assert_eq!(atan2(3.0, 2.0), atan(3.0 / 2.0)); - assert_eq!(atan2(2.0, -1.0), atan(2.0 / -1.0) + PI); - assert_eq!(atan2(-2.0, -1.0), atan(-2.0 / -1.0) - PI); +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg_attr(x86_no_sse, 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); + assert_eq!(atan2(-0.0, -1.0), -PI); + assert_eq!(atan2(3.0, 2.0), atan(3.0 / 2.0)); + assert_eq!(atan2(2.0, -1.0), atan(2.0 / -1.0) + PI); + assert_eq!(atan2(-2.0, -1.0), atan(-2.0 / -1.0) - PI); + } } diff --git a/library/compiler-builtins/libm/src/math/sin.rs b/library/compiler-builtins/libm/src/math/sin.rs index e04e0d6a09dce..229fa4bef0830 100644 --- a/library/compiler-builtins/libm/src/math/sin.rs +++ b/library/compiler-builtins/libm/src/math/sin.rs @@ -81,12 +81,15 @@ pub fn sin(x: f64) -> f64 { } } -#[test] -fn test_near_pi() { - let x = f64::from_bits(0x400921fb000FD5DD); // 3.141592026217707 - let sx = f64::from_bits(0x3ea50d15ced1a4a2); // 6.273720864039205e-7 - let result = sin(x); - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let result = force_eval!(result); - assert_eq!(result, sx); +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg_attr(x86_no_sse, 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 + assert_eq!(sin(x), sx); + } } From 64e0a0a68da8a6f5a885e5034b4e4cf44a769d41 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 27 Jan 2025 12:56:15 +0000 Subject: [PATCH 1623/4206] Remove use of the `start` feature `#![feature(start)]` was removed in [1], but we make use of it in the intrinsics example. Replace use of this feature with `#[no_mangle]` applied to `#[main]`. We don't actually run this example so it is not a problem if this is not entirely accurate. Currently the example does not run to completion, instead invoking `rust_begin_unwind`. [1]: https://github.com/rust-lang/rust/pull/134299 --- library/compiler-builtins/examples/intrinsics.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index e13c0fb1fa28e..59a70e20745c8 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -5,14 +5,13 @@ #![allow(unused_features)] #![allow(internal_features)] -#![cfg_attr(thumb, no_main)] #![deny(dead_code)] #![feature(allocator_api)] #![feature(f128)] #![feature(f16)] #![feature(lang_items)] -#![feature(start)] #![no_std] +#![no_main] extern crate panic_handler; @@ -630,11 +629,10 @@ fn run() { extern "C" { fn rust_begin_unwind(x: usize); } - // if bb(false) { + unsafe { rust_begin_unwind(0); } - // } } fn something_with_a_dtor(f: &dyn Fn()) { @@ -649,15 +647,15 @@ fn something_with_a_dtor(f: &dyn Fn()) { f(); } +#[no_mangle] #[cfg(not(thumb))] -#[start] -fn main(_: isize, _: *const *const u8) -> isize { +fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int { run(); 0 } -#[cfg(thumb)] #[no_mangle] +#[cfg(thumb)] pub fn _start() -> ! { run(); loop {} From 4e1b885595447386c925be1732cccfed9daf8807 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Jan 2025 08:45:56 +0000 Subject: [PATCH 1624/4206] Add a version to some FIXMEs that will be resolved in LLVM 20 --- library/compiler-builtins/configure.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs index 87bc7a0eed302..fa3e302ea87cd 100644 --- a/library/compiler-builtins/configure.rs +++ b/library/compiler-builtins/configure.rs @@ -74,7 +74,7 @@ pub fn configure_f16_f128(target: &Target) { // Selection failure "s390x" => false, // Infinite recursion - // FIXME(llvm): loongarch fixed by + // FIXME(llvm20): loongarch fixed by "csky" => false, "hexagon" => false, "loongarch64" => false, @@ -91,7 +91,7 @@ pub fn configure_f16_f128(target: &Target) { "amdgpu" => false, // Unsupported "arm64ec" => false, - // Selection failure + // FIXME(llvm20): fixed by "mips64" | "mips64r6" => false, // Selection failure "nvptx64" => false, From 259e544192999988c2ad7e4264e650c0db0524ce Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 27 Jan 2025 23:25:00 +0000 Subject: [PATCH 1625/4206] Switch musl from a script download to a submodule Rather than keeping a script that downloads the tarball, we can just add musl as a submodule and let git handle the synchronizatoin. Do so here. --- .../libm/.github/workflows/main.yaml | 18 +++++++------- library/compiler-builtins/libm/.gitignore | 1 - library/compiler-builtins/libm/.gitmodules | 4 ++++ .../compiler-builtins/libm/CONTRIBUTING.md | 4 ++++ .../libm/ci/download-musl.sh | 24 ------------------- .../libm/crates/musl-math-sys/build.rs | 14 +++-------- .../libm/crates/musl-math-sys/musl | 1 + 7 files changed, 20 insertions(+), 46 deletions(-) create mode 100644 library/compiler-builtins/libm/.gitmodules delete mode 100755 library/compiler-builtins/libm/ci/download-musl.sh create mode 160000 library/compiler-builtins/libm/crates/musl-math-sys/musl diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index 59955271170fb..e03d7ecd31910 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -79,6 +79,8 @@ jobs: - name: Print runner information run: uname -a - uses: actions/checkout@v4 + with: + submodules: true - name: Install Rust (rustup) shell: bash run: | @@ -94,10 +96,6 @@ jobs: with: key: ${{ matrix.target }} - - name: Download musl source - run: ./ci/download-musl.sh - shell: bash - - name: Verify API list if: matrix.os == 'ubuntu-24.04' run: python3 etc/update-api-list.py --check @@ -126,14 +124,14 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@master + with: + submodules: true - name: Install Rust run: | rustup update nightly --no-self-update rustup default nightly rustup component add clippy - uses: Swatinem/rust-cache@v2 - - name: Download musl source - run: ./ci/download-musl.sh - run: cargo clippy --all --all-features --all-targets builtins: @@ -153,6 +151,8 @@ jobs: timeout-minutes: 20 steps: - uses: actions/checkout@master + with: + submodules: true - uses: taiki-e/install-action@cargo-binstall - name: Set up dependencies @@ -166,8 +166,6 @@ jobs: sudo apt-get install valgrind - uses: Swatinem/rust-cache@v2 - - name: Download musl source - run: ./ci/download-musl.sh - name: Run icount benchmarks env: @@ -259,13 +257,13 @@ jobs: CHANGED: ${{ matrix.changed }} steps: - uses: actions/checkout@v4 + with: + submodules: true - name: Install Rust run: | rustup update nightly --no-self-update rustup default nightly - uses: Swatinem/rust-cache@v2 - - name: Download musl source - run: ./ci/download-musl.sh - name: Run extensive tests run: | echo "Changed: '$CHANGED'" diff --git a/library/compiler-builtins/libm/.gitignore b/library/compiler-builtins/libm/.gitignore index a447c34cd0f63..d5caba1a0f33d 100644 --- a/library/compiler-builtins/libm/.gitignore +++ b/library/compiler-builtins/libm/.gitignore @@ -4,7 +4,6 @@ /math/src target Cargo.lock -musl/ **.tar.gz # Benchmark cache diff --git a/library/compiler-builtins/libm/.gitmodules b/library/compiler-builtins/libm/.gitmodules new file mode 100644 index 0000000000000..35b269eadd4e1 --- /dev/null +++ b/library/compiler-builtins/libm/.gitmodules @@ -0,0 +1,4 @@ +[submodule "musl"] + path = crates/musl-math-sys/musl + url = https://git.musl-libc.org/git/musl + shallow = true diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/libm/CONTRIBUTING.md index ba7f78ca014ce..dc40060357c4e 100644 --- a/library/compiler-builtins/libm/CONTRIBUTING.md +++ b/library/compiler-builtins/libm/CONTRIBUTING.md @@ -62,6 +62,10 @@ Check [PR #65] for an example. Normal tests can be executed with: ```sh +# Tests against musl require that the submodule is up to date. +git submodule init +git submodule update + # `--release` ables more test cases cargo test --release ``` diff --git a/library/compiler-builtins/libm/ci/download-musl.sh b/library/compiler-builtins/libm/ci/download-musl.sh deleted file mode 100755 index 8a8c58550bb47..0000000000000 --- a/library/compiler-builtins/libm/ci/download-musl.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# Download the expected version of musl to a directory `musl` - -set -eux - -fname=musl-1.2.5.tar.gz -sha=a9a118bbe84d8764da0ea0d28b3ab3fae8477fc7e4085d90102b8596fc7c75e4 - -mkdir musl -curl -L "https://musl.libc.org/releases/$fname" -O --retry 5 - -case "$(uname -s)" in - MINGW*) - # Need to extract the second line because certutil does human output - fsha=$(certutil -hashfile "$fname" SHA256 | sed -n '2p') - [ "$sha" = "$fsha" ] || exit 1 - ;; - *) - echo "$sha $fname" | shasum -a 256 --check || exit 1 - ;; -esac - -tar -xzf "$fname" -C musl --strip-components 1 -rm "$fname" diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/build.rs b/library/compiler-builtins/libm/crates/musl-math-sys/build.rs index d75748159cad5..f06d84ee267e6 100644 --- a/library/compiler-builtins/libm/crates/musl-math-sys/build.rs +++ b/library/compiler-builtins/libm/crates/musl-math-sys/build.rs @@ -79,17 +79,12 @@ impl Config { let target_features = env::var("CARGO_CFG_TARGET_FEATURE") .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) .unwrap_or_default(); - - // Default to the `{workspace_root}/musl` if not specified - let musl_dir = env::var("MUSL_SOURCE_DIR") - .map(PathBuf::from) - .unwrap_or_else(|_| manifest_dir.parent().unwrap().parent().unwrap().join("musl")); + let musl_dir = manifest_dir.join("musl"); let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); let musl_arch = if target_arch == "x86" { "i386".to_owned() } else { target_arch.clone() }; println!("cargo::rerun-if-changed={}/c_patches", manifest_dir.display()); - println!("cargo::rerun-if-env-changed=MUSL_SOURCE_DIR"); println!("cargo::rerun-if-changed={}", musl_dir.display()); Self { @@ -111,13 +106,10 @@ impl Config { /// Build musl math symbols to a static library fn build_musl_math(cfg: &Config) { let musl_dir = &cfg.musl_dir; - assert!( - musl_dir.exists(), - "musl source is missing. it can be downloaded with ./ci/download-musl.sh" - ); - let math = musl_dir.join("src/math"); let arch_dir = musl_dir.join("arch").join(&cfg.musl_arch); + assert!(math.exists(), "musl source not found. Is the submodule up to date?"); + let source_map = find_math_source(&math, cfg); let out_path = cfg.out_dir.join(format!("lib{LIB_NAME}.a")); diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/musl b/library/compiler-builtins/libm/crates/musl-math-sys/musl new file mode 160000 index 0000000000000..0784374d56143 --- /dev/null +++ b/library/compiler-builtins/libm/crates/musl-math-sys/musl @@ -0,0 +1 @@ +Subproject commit 0784374d561435f7c787a555aeab8ede699ed298 From 176d22db1269f6a84277978ea28cefb66f76369e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 28 Jan 2025 10:31:33 +0000 Subject: [PATCH 1626/4206] Temporarily pin `indicatif` to 0.17.9 0.17.10 introduced a change that removes `Sync` from `ProgressStyle`, which makes it more difficult to share in a callback. Pin the dependency for now until we see if `indicatif` will change this back or if we need to find a workaround. --- library/compiler-builtins/libm/crates/libm-test/Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index dcbddb667e81e..63e75260e86d4 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -31,7 +31,8 @@ anyhow = "1.0.95" # This is not directly used but is required so we can enable `gmp-mpfr-sys/force-cross`. gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false } iai-callgrind = { version = "0.14.0", optional = true } -indicatif = { version = "0.17.9", default-features = false } +# 0.17.10 made `ProgressStyle` non-`Sync` +indicatif = { version = "=0.17.9", default-features = false } libm = { path = "../..", features = ["unstable-public-internals"] } libm-macros = { path = "../libm-macros" } musl-math-sys = { path = "../musl-math-sys", optional = true } From ececfaba78f150818b846b897f0fe8151258dd3e Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 28 Jan 2025 15:40:23 +0100 Subject: [PATCH 1627/4206] Don't build out of line atomics support code for uefi https://github.com/llvm/llvm-project/pull/116706 added Windows support to cpu_model. Compiling for UEFI also goes through that code path, because we treat it as a windows target. However, including windows.h is not actually going to work (and the used API would not be available in an UEFI environment). Disable building of cpu_model on UEFI to fix this. --- library/compiler-builtins/build.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index f512fc2e6672c..39cee311f85a4 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -644,9 +644,10 @@ mod c { // 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). + // 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" { + if target.arch == "aarch64" && target.env != "msvc" && target.os != "uefi" { // See below for why we're building these as separate libraries. build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg); From 396725e1464564ae052cd6ad8191d4d8ab38d804 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 28 Jan 2025 13:54:26 -0600 Subject: [PATCH 1628/4206] Revert "Temporarily pin `indicatif` to 0.17.9" This reverts commit 1dacdabdb6186f97144c50f8952575576deb3730. --- library/compiler-builtins/libm/crates/libm-test/Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 63e75260e86d4..dcbddb667e81e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -31,8 +31,7 @@ anyhow = "1.0.95" # This is not directly used but is required so we can enable `gmp-mpfr-sys/force-cross`. gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false } iai-callgrind = { version = "0.14.0", optional = true } -# 0.17.10 made `ProgressStyle` non-`Sync` -indicatif = { version = "=0.17.9", default-features = false } +indicatif = { version = "0.17.9", default-features = false } libm = { path = "../..", features = ["unstable-public-internals"] } libm-macros = { path = "../libm-macros" } musl-math-sys = { path = "../musl-math-sys", optional = true } From 99c1080556577145387a1a4cf75e17548eb78eaa Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 28 Jan 2025 09:50:21 +0000 Subject: [PATCH 1629/4206] Support parsing NaN and infinities from the `hf*` functions This isn't very useful for constants since the trait constants are available, but does enable roundtripping via hex float syntax. --- .../libm/crates/libm-test/src/f8_impl.rs | 6 ++ .../libm/crates/libm-test/src/lib.rs | 2 +- .../libm/src/math/support/hex_float.rs | 63 ++++++++++++++++--- .../libm/src/math/support/mod.rs | 2 +- 4 files changed, 61 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs index 96b78392453fa..5dce9be1891df 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs @@ -3,6 +3,8 @@ use std::cmp::{self, Ordering}; use std::{fmt, ops}; +use libm::support::hex_float::parse_any; + use crate::Float; /// Sometimes verifying float logic is easiest when all values can quickly be checked exhaustively @@ -490,3 +492,7 @@ impl fmt::LowerHex for f8 { self.0.fmt(f) } } + +pub const fn hf8(s: &str) -> f8 { + f8(parse_any(s, 8, 3) as u8) +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 78b011b1f2338..d2fef2325059c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -20,7 +20,7 @@ use std::path::PathBuf; use std::sync::LazyLock; use std::time::SystemTime; -pub use f8_impl::f8; +pub use f8_impl::{f8, hf8}; pub use libm::support::{Float, Int, IntTy, MinInt}; pub use num::{FloatExt, linear_ints, logspace}; pub use op::{ 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 949f21a57ff35..6eb1bd67a99a1 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -26,17 +26,25 @@ pub const fn hf128(s: &str) -> f128 { f128::from_bits(parse_any(s, 128, 112)) } -const fn parse_any(s: &str, bits: u32, sig_bits: u32) -> u128 { +/// Parse any float from hex to its bitwise representation. +/// +/// `nan_repr` is passed rather than constructed so the platform-specific NaN is returned. +pub const fn parse_any(s: &str, bits: u32, sig_bits: u32) -> u128 { let exp_bits: u32 = bits - sig_bits - 1; let max_msb: i32 = (1 << (exp_bits - 1)) - 1; // The exponent of one ULP in the subnormals let min_lsb: i32 = 1 - max_msb - sig_bits as i32; - let (neg, mut sig, exp) = parse_hex(s.as_bytes()); + let exp_mask = ((1 << exp_bits) - 1) << sig_bits; - if sig == 0 { - return (neg as u128) << (bits - 1); - } + let (neg, mut sig, exp) = match parse_hex(s.as_bytes()) { + Parsed::Finite { neg, sig: 0, .. } => return (neg as u128) << (bits - 1), + Parsed::Finite { neg, sig, exp } => (neg, sig, exp), + Parsed::Infinite { neg } => return ((neg as u128) << (bits - 1)) | exp_mask, + Parsed::Nan { neg } => { + return ((neg as u128) << (bits - 1)) | exp_mask | 1 << (sig_bits - 1); + } + }; // exponents of the least and most significant bits in the value let lsb = sig.trailing_zeros() as i32; @@ -76,11 +84,24 @@ const fn parse_any(s: &str, bits: u32, sig_bits: u32) -> u128 { sig | ((neg as u128) << (bits - 1)) } +/// A parsed floating point number. +enum Parsed { + /// Absolute value sig * 2^e + Finite { + neg: bool, + sig: u128, + exp: i32, + }, + Infinite { + neg: bool, + }, + Nan { + neg: bool, + }, +} + /// Parse a hexadecimal float x -/// returns (s,n,e): -/// s == x.is_sign_negative() -/// n * 2^e == x.abs() -const fn parse_hex(mut b: &[u8]) -> (bool, u128, i32) { +const fn parse_hex(mut b: &[u8]) -> Parsed { let mut neg = false; let mut sig: u128 = 0; let mut exp: i32 = 0; @@ -90,6 +111,12 @@ const fn parse_hex(mut b: &[u8]) -> (bool, u128, i32) { neg = c == b'-'; } + match *b { + [b'i' | b'I', b'n' | b'N', b'f' | b'F'] => return Parsed::Infinite { neg }, + [b'n' | b'N', b'a' | b'A', b'n' | b'N'] => return Parsed::Nan { neg }, + _ => (), + } + if let &[b'0', b'x' | b'X', ref rest @ ..] = b { b = rest; } else { @@ -152,7 +179,7 @@ const fn parse_hex(mut b: &[u8]) -> (bool, u128, i32) { exp += pexp; } - (neg, sig, exp) + Parsed::Finite { neg, sig, exp } } const fn dec_digit(c: u8) -> u8 { @@ -272,6 +299,10 @@ mod tests { ("-0x1.998p-4", (-0.1f16).to_bits()), ("0x0.123p-12", 0x0123), ("0x1p-24", 0x0001), + ("nan", f16::NAN.to_bits()), + ("-nan", (-f16::NAN).to_bits()), + ("inf", f16::INFINITY.to_bits()), + ("-inf", f16::NEG_INFINITY.to_bits()), ]; for (s, exp) in checks { println!("parsing {s}"); @@ -322,6 +353,10 @@ mod tests { ("0x1.111114p-127", 0x00444445), ("0x1.23456p-130", 0x00091a2b), ("0x1p-149", 0x00000001), + ("nan", f32::NAN.to_bits()), + ("-nan", (-f32::NAN).to_bits()), + ("inf", f32::INFINITY.to_bits()), + ("-inf", f32::NEG_INFINITY.to_bits()), ]; for (s, exp) in checks { println!("parsing {s}"); @@ -360,6 +395,10 @@ mod tests { ("0x0.8000000000001p-1022", 0x0008000000000001), ("0x0.123456789abcdp-1022", 0x000123456789abcd), ("0x0.0000000000002p-1022", 0x0000000000000002), + ("nan", f64::NAN.to_bits()), + ("-nan", (-f64::NAN).to_bits()), + ("inf", f64::INFINITY.to_bits()), + ("-inf", f64::NEG_INFINITY.to_bits()), ]; for (s, exp) in checks { println!("parsing {s}"); @@ -401,6 +440,10 @@ mod tests { ("-0x1.999999999999999999999999999ap-4", (-0.1f128).to_bits()), ("0x0.abcdef0123456789abcdef012345p-16382", 0x0000abcdef0123456789abcdef012345), ("0x1p-16494", 0x00000000000000000000000000000001), + ("nan", f128::NAN.to_bits()), + ("-nan", (-f128::NAN).to_bits()), + ("inf", f128::INFINITY.to_bits()), + ("-inf", f128::NEG_INFINITY.to_bits()), ]; for (s, exp) in checks { println!("parsing {s}"); diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index da9e2c9ed62cb..b82a2ea0540d2 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -2,7 +2,7 @@ pub mod macros; mod big; mod float_traits; -mod hex_float; +pub mod hex_float; mod int_traits; #[allow(unused_imports)] From f767b58ba4fad1e8184f699dad5eb83734a5346d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 28 Jan 2025 09:51:43 +0000 Subject: [PATCH 1630/4206] Introduce a wrapper type for IEEE hex float formatting --- .../libm/src/math/support/hex_float.rs | 183 +++++++++++++++++- .../libm/src/math/support/mod.rs | 2 +- 2 files changed, 181 insertions(+), 4 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 6eb1bd67a99a1..da41622f29675 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -2,7 +2,9 @@ #![allow(dead_code)] // FIXME: remove once this gets used -use super::{f32_from_bits, f64_from_bits}; +use core::fmt; + +use super::{Float, f32_from_bits, f64_from_bits}; /// Construct a 16-bit float from hex float representation (C-style) #[cfg(f16_enabled)] @@ -42,7 +44,7 @@ pub const fn parse_any(s: &str, bits: u32, sig_bits: u32) -> u128 { Parsed::Finite { neg, sig, exp } => (neg, sig, exp), Parsed::Infinite { neg } => return ((neg as u128) << (bits - 1)) | exp_mask, Parsed::Nan { neg } => { - return ((neg as u128) << (bits - 1)) | exp_mask | 1 << (sig_bits - 1); + return ((neg as u128) << (bits - 1)) | exp_mask | (1 << (sig_bits - 1)); } }; @@ -206,8 +208,107 @@ const fn u128_ilog2(v: u128) -> u32 { u128::BITS - 1 - v.leading_zeros() } +/// Format a floating point number as its IEEE hex (`%a`) representation. +pub struct Hexf(pub F); + +// Adapted from https://github.com/ericseppanen/hexfloat2/blob/a5c27932f0ff/src/format.rs +fn fmt_any_hex(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if x.is_sign_negative() { + write!(f, "-")?; + } + + if x.is_nan() { + return write!(f, "NaN"); + } else if x.is_infinite() { + return write!(f, "inf"); + } else if *x == F::ZERO { + return write!(f, "0x0p+0"); + } + + let mut exponent = x.exp_unbiased(); + let sig = x.to_bits() & F::SIG_MASK; + + let bias = F::EXP_BIAS as i32; + // The mantissa MSB needs to be shifted up to the nearest nibble. + let mshift = (4 - (F::SIG_BITS % 4)) % 4; + let sig = sig << mshift; + // The width is rounded up to the nearest char (4 bits) + let mwidth = (F::SIG_BITS as usize + 3) / 4; + let leading = if exponent == -bias { + // subnormal number means we shift our output by 1 bit. + exponent += 1; + "0." + } else { + "1." + }; + + write!(f, "0x{leading}{sig:0mwidth$x}p{exponent:+}") +} + +#[cfg(f16_enabled)] +impl fmt::LowerHex for Hexf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt_any_hex(&self.0, f) + } +} + +impl fmt::LowerHex for Hexf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt_any_hex(&self.0, f) + } +} + +impl fmt::LowerHex for Hexf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt_any_hex(&self.0, f) + } +} + +#[cfg(f128_enabled)] +impl fmt::LowerHex for Hexf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt_any_hex(&self.0, f) + } +} + +impl fmt::LowerHex for Hexf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::LowerHex::fmt(&self.0, f) + } +} + +impl fmt::LowerHex for Hexf<(T1, T2)> +where + T1: Copy, + T2: Copy, + Hexf: fmt::LowerHex, + Hexf: fmt::LowerHex, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) + } +} + +impl fmt::Debug for Hexf +where + Hexf: fmt::LowerHex, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::LowerHex::fmt(self, f) + } +} + +impl fmt::Display for Hexf +where + Hexf: fmt::LowerHex, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::LowerHex::fmt(self, f) + } +} + #[cfg(test)] -mod tests { +mod parse_tests { extern crate std; use std::{format, println}; @@ -666,3 +767,79 @@ mod tests_panicking { #[cfg(f128_enabled)] f128_tests!(); } + +#[cfg(test)] +mod print_tests { + extern crate std; + use std::string::ToString; + + use super::*; + + #[test] + #[cfg(f16_enabled)] + fn test_f16() { + use std::format; + // Exhaustively check that `f16` roundtrips. + for x in 0..=u16::MAX { + let f = f16::from_bits(x); + let s = format!("{}", Hexf(f)); + let from_s = hf16(&s); + + if f.is_nan() && from_s.is_nan() { + continue; + } + + assert_eq!( + f.to_bits(), + from_s.to_bits(), + "{f:?} formatted as {s} but parsed as {from_s:?}" + ); + } + } + + #[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!(Hexf(f32::MIN).to_string(), "-0x1.fffffep+127"); + assert_eq!(Hexf(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!(Hexf(f32::NEG_ZERO).to_string(), "-0x0p+0"); + assert_eq!(Hexf(f64::NEG_ZERO).to_string(), "-0x0p+0"); + + assert_eq!(Hexf(f32::NAN).to_string(), "NaN"); + assert_eq!(Hexf(f64::NAN).to_string(), "NaN"); + + assert_eq!(Hexf(f32::INFINITY).to_string(), "inf"); + assert_eq!(Hexf(f64::INFINITY).to_string(), "inf"); + + assert_eq!(Hexf(f32::NEG_INFINITY).to_string(), "-inf"); + assert_eq!(Hexf(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(), "NaN"); + assert_eq!(Hexf(f16::INFINITY).to_string(), "inf"); + assert_eq!(Hexf(f16::NEG_INFINITY).to_string(), "-inf"); + } + + #[cfg(f128_enabled)] + { + assert_eq!(Hexf(f128::MAX).to_string(), "0x1.ffffffffffffffffffffffffffffp+16383"); + assert_eq!(Hexf(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(), "NaN"); + assert_eq!(Hexf(f128::INFINITY).to_string(), "inf"); + assert_eq!(Hexf(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 b82a2ea0540d2..d471c5b701336 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -13,7 +13,7 @@ pub use hex_float::hf16; #[cfg(f128_enabled)] pub use hex_float::hf128; #[allow(unused_imports)] -pub use hex_float::{hf32, hf64}; +pub use hex_float::{Hexf, hf32, hf64}; pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; /// Hint to the compiler that the current path is cold. From e283c25602a7ab12ea8e4b62db1fe18c4678da1f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 28 Jan 2025 10:09:27 +0000 Subject: [PATCH 1631/4206] Util: also print the hex float format for outputs --- .../compiler-builtins/libm/crates/util/src/main.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index 6ea1be3d9aedc..357df6b4fe218 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -8,7 +8,7 @@ use std::env; use std::num::ParseIntError; use std::str::FromStr; -use libm::support::{hf32, hf64}; +use libm::support::{Hexf, hf32, hf64}; #[cfg(feature = "build-mpfr")] use libm_test::mpfloat::MpOp; use libm_test::{MathOp, TupleCall}; @@ -73,7 +73,7 @@ macro_rules! handle_call { } _ => panic!("unrecognized or disabled basis '{}'", $basis), }; - println!("{output:?}"); + println!("{output:?} {:x}", Hexf(output)); return; } }; @@ -303,6 +303,10 @@ impl FromStrRadix for i32 { #[cfg(f16_enabled)] impl FromStrRadix for f16 { fn from_str_radix(s: &str, radix: u32) -> Result { + if radix == 16 && s.contains("p") { + return Ok(libm::support::hf16(s)); + } + let s = strip_radix_prefix(s, radix); u16::from_str_radix(s, radix).map(Self::from_bits) } @@ -334,6 +338,9 @@ impl FromStrRadix for f64 { #[cfg(f128_enabled)] impl FromStrRadix for f128 { fn from_str_radix(s: &str, radix: u32) -> Result { + if radix == 16 && s.contains("p") { + return Ok(libm::support::hf128(s)); + } let s = strip_radix_prefix(s, radix); u128::from_str_radix(s, radix).map(Self::from_bits) } From 7d674145aee6065c61f71f176fa8acc229f00953 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 30 Jan 2025 13:06:41 -0800 Subject: [PATCH 1632/4206] Specify license as just MIT Simplify the SPDX string to the user-facing version to make it easier for users and tooling to understand. Contributions must still be `MIT OR Apache-2.0`. [ add commit body with context - Trevor ] --- library/compiler-builtins/libm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 08342a929290a..f24f4423c7b4a 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -4,7 +4,7 @@ categories = ["no-std"] description = "libm in pure Rust" documentation = "https://docs.rs/libm" keywords = ["libm", "math"] -license = "MIT AND (MIT OR Apache-2.0)" +license = "MIT" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/libm" From 8db5ff73e62605ad5d94bb0c17124475058b8b54 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 31 Jan 2025 12:31:35 +0000 Subject: [PATCH 1633/4206] Rename `EXP_MAX` to `EXP_SAT` `EXP_MAX` sounds like it would be the maximum value representable by that float type's exponent, rather than the maximum unsigned value of its bits. Clarify this by renaming to `EXP_SAT`, the "saturated" exponent representation. --- .../libm/src/math/generic/fmod.rs | 2 +- .../libm/src/math/generic/sqrt.rs | 4 ++-- .../libm/src/math/support/float_traits.rs | 21 +++++++++++-------- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/generic/fmod.rs b/library/compiler-builtins/libm/src/math/generic/fmod.rs index 93da6c51e7e1b..ca1cda383235a 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmod.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmod.rs @@ -13,7 +13,7 @@ pub fn fmod(x: F, y: F) -> F { let mut ey = y.exp().signed(); let sx = ix & F::SIGN_MASK; - if iy << 1 == zero || y.is_nan() || ex == F::EXP_MAX as i32 { + if iy << 1 == zero || y.is_nan() || ex == F::EXP_SAT as i32 { return (x * y) / (x * y); } diff --git a/library/compiler-builtins/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/src/math/generic/sqrt.rs index c20c0f20525e7..90d6c01e91719 100644 --- a/library/compiler-builtins/libm/src/math/generic/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/generic/sqrt.rs @@ -68,7 +68,7 @@ where (Exp::NoShift(()), special_case) } else { let top = u32::cast_from(ix >> F::SIG_BITS); - let special_case = top.wrapping_sub(1) >= F::EXP_MAX - 1; + let special_case = top.wrapping_sub(1) >= F::EXP_SAT - 1; (Exp::Shifted(top), special_case) }; @@ -119,7 +119,7 @@ where if even { m_u2 >>= 1; } - e = (e.wrapping_add(F::EXP_MAX >> 1)) >> 1; + e = (e.wrapping_add(F::EXP_SAT >> 1)) >> 1; (m_u2, Exp::Shifted(e)) } Exp::NoShift(()) => { 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 57e4aebecfc8f..1fe2cb424b9a1 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -48,11 +48,14 @@ pub trait Float: /// The bitwidth of the exponent const EXP_BITS: u32 = Self::BITS - Self::SIG_BITS - 1; - /// The saturated value of the exponent (infinite representation), in the rightmost postiion. - const EXP_MAX: u32 = (1 << Self::EXP_BITS) - 1; + /// The saturated (maximum bitpattern) value of the exponent, i.e. the infinite + /// representation. + /// + /// This shifted fully right, 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_MAX >> 1; + const EXP_BIAS: u32 = Self::EXP_SAT >> 1; /// A mask for the sign bit const SIGN_MASK: Self::Int; @@ -109,7 +112,7 @@ pub trait Float: /// Returns the exponent, not adjusting for bias, not accounting for subnormals or zero. fn exp(self) -> u32 { - u32::cast_from(self.to_bits() >> Self::SIG_BITS) & Self::EXP_MAX + u32::cast_from(self.to_bits() >> Self::SIG_BITS) & Self::EXP_SAT } /// Extract the exponent and adjust it for bias, not accounting for subnormals or zero. @@ -135,7 +138,7 @@ pub trait Float: let sign = if negative { Self::Int::ONE } else { Self::Int::ZERO }; Self::from_bits( (sign << (Self::BITS - 1)) - | (Self::Int::cast_from(exponent & Self::EXP_MAX) << Self::SIG_BITS) + | (Self::Int::cast_from(exponent & Self::EXP_SAT) << Self::SIG_BITS) | (significand & Self::SIG_MASK), ) } @@ -267,7 +270,7 @@ mod tests { #[cfg(f16_enabled)] fn check_f16() { // Constants - assert_eq!(f16::EXP_MAX, 0b11111); + assert_eq!(f16::EXP_SAT, 0b11111); assert_eq!(f16::EXP_BIAS, 15); // `exp_unbiased` @@ -289,7 +292,7 @@ mod tests { #[test] fn check_f32() { // Constants - assert_eq!(f32::EXP_MAX, 0b11111111); + assert_eq!(f32::EXP_SAT, 0b11111111); assert_eq!(f32::EXP_BIAS, 127); // `exp_unbiased` @@ -312,7 +315,7 @@ mod tests { #[test] fn check_f64() { // Constants - assert_eq!(f64::EXP_MAX, 0b11111111111); + assert_eq!(f64::EXP_SAT, 0b11111111111); assert_eq!(f64::EXP_BIAS, 1023); // `exp_unbiased` @@ -336,7 +339,7 @@ mod tests { #[cfg(f128_enabled)] fn check_f128() { // Constants - assert_eq!(f128::EXP_MAX, 0b111111111111111); + assert_eq!(f128::EXP_SAT, 0b111111111111111); assert_eq!(f128::EXP_BIAS, 16383); // `exp_unbiased` From 5a5a5a39ad87a3a78e4a67da7bb7c53203381663 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Sat, 1 Feb 2025 02:14:22 +0300 Subject: [PATCH 1634/4206] Indentation fix to please clippy --- library/compiler-builtins/src/float/conv.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 83a181c37d402..4f52ac7120d94 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -344,8 +344,7 @@ where /// /// Parameters: /// - `fbits`: `abg(f)` bitcasted to an integer. -/// - `map_inbounds`: apply this transformation to integers that are within range (add the sign -/// back). +/// - `map_inbounds`: apply this transformation to integers that are within range (add the sign back). /// - `out_of_bounds`: return value when out of range for `I`. fn float_to_int_inner( fbits: F::Int, From 57572a583da932aed817b0677bf6a85d135dc920 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 4 Feb 2025 10:36:45 +0000 Subject: [PATCH 1635/4206] Revert "Eliminate the use of `public_test_dep!`" [1] has not gone forward, so this needs to be reverted again in order to unblock a compiler-builtins upgrade that is necessary for the LLVM 20 upgrade. This reverts commit a2494f14e99ae90c964f12bf0c059d63ccc07c2a. [1]: https://github.com/rust-lang/rust/pull/135501 --- library/compiler-builtins/src/float/mod.rs | 195 +++++++- library/compiler-builtins/src/float/traits.rs | 189 -------- .../src/int/leading_zeros.rs | 227 +++++----- library/compiler-builtins/src/int/mod.rs | 424 +++++++++++++++++- .../src/int/specialized_div_rem/delegate.rs | 4 +- .../src/int/trailing_zeros.rs | 69 ++- library/compiler-builtins/src/int/traits.rs | 411 ----------------- library/compiler-builtins/src/macros.rs | 16 + 8 files changed, 772 insertions(+), 763 deletions(-) delete mode 100644 library/compiler-builtins/src/float/traits.rs delete mode 100644 library/compiler-builtins/src/int/traits.rs diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 41b308626b392..6ee55950e18e8 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,3 +1,7 @@ +use core::ops; + +use crate::int::{DInt, Int, MinInt}; + pub mod add; pub mod cmp; pub mod conv; @@ -6,11 +10,192 @@ pub mod extend; pub mod mul; pub mod pow; pub mod sub; -pub(crate) mod traits; pub mod trunc; -#[cfg(not(feature = "public-test-deps"))] -pub(crate) use traits::{Float, HalfRep}; +/// Wrapper to extract the integer type half of the float's size +pub(crate) type HalfRep = <::Int as DInt>::H; + +public_test_dep! { +/// Trait for some basic operations on floats +#[allow(dead_code)] +pub(crate) 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(feature = "public-test-deps")] -pub use traits::{Float, HalfRep}; +#[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/src/float/traits.rs b/library/compiler-builtins/src/float/traits.rs deleted file mode 100644 index 8ccaa7bcbd78a..0000000000000 --- a/library/compiler-builtins/src/float/traits.rs +++ /dev/null @@ -1,189 +0,0 @@ -use core::ops; - -use crate::int::{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/src/int/leading_zeros.rs b/library/compiler-builtins/src/int/leading_zeros.rs index ba735aa74620b..1fee9fcf5d8fd 100644 --- a/library/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/src/int/leading_zeros.rs @@ -3,138 +3,135 @@ // adding a zero check at the beginning, but `__clzsi2` has a precondition that `x != 0`. // Compilers will insert the check for zero in cases where it is needed. -#[cfg(feature = "public-test-deps")] -pub use implementation::{leading_zeros_default, leading_zeros_riscv}; -#[cfg(not(feature = "public-test-deps"))] -pub(crate) use implementation::{leading_zeros_default, leading_zeros_riscv}; +use crate::int::{CastInto, Int}; -mod implementation { - use crate::int::{CastInto, Int}; +public_test_dep! { +/// Returns the number of leading binary zeros in `x`. +#[allow(dead_code)] +pub(crate) fn leading_zeros_default>(x: T) -> usize { + // The basic idea is to test if the higher bits of `x` are zero and bisect the number + // of leading zeros. It is possible for all branches of the bisection to use the same + // code path by conditionally shifting the higher parts down to let the next bisection + // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` + // and adding to the number of zeros, it is slightly faster to start with + // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, + // because it simplifies the final bisection step. + let mut x = x; + // the number of potential leading zeros + let mut z = T::BITS as usize; + // a temporary + let mut t: T; - /// Returns the number of leading binary zeros in `x`. - #[allow(dead_code)] - pub fn leading_zeros_default>(x: T) -> usize { - // The basic idea is to test if the higher bits of `x` are zero and bisect the number - // of leading zeros. It is possible for all branches of the bisection to use the same - // code path by conditionally shifting the higher parts down to let the next bisection - // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` - // and adding to the number of zeros, it is slightly faster to start with - // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, - // because it simplifies the final bisection step. - let mut x = x; - // the number of potential leading zeros - let mut z = T::BITS as usize; - // a temporary - let mut t: T; - - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - t = x >> 32; - if t != T::ZERO { - z -= 32; - x = t; - } - } - if T::BITS >= 32 { - t = x >> 16; - if t != T::ZERO { - z -= 16; - x = t; - } - } - const { assert!(T::BITS >= 16) }; - t = x >> 8; + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + t = x >> 32; if t != T::ZERO { - z -= 8; + z -= 32; x = t; } - t = x >> 4; - if t != T::ZERO { - z -= 4; - x = t; - } - t = x >> 2; + } + if T::BITS >= 32 { + t = x >> 16; if t != T::ZERO { - z -= 2; + z -= 16; x = t; } - // the last two bisections are combined into one conditional - t = x >> 1; - if t != T::ZERO { - z - 2 - } else { - z - x.cast() - } - - // We could potentially save a few cycles by using the LUT trick from - // "https://embeddedgurus.com/state-space/2014/09/-%20%20%20%20%20%20%20%20//%20fast-deterministic-and-portable-counting-leading-zeros/". - // However, 256 bytes for a LUT is too large for embedded use cases. We could remove - // the last 3 bisections and use this 16 byte LUT for the rest of the work: - //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; - //z -= LUT[x] as usize; - //z - // However, it ends up generating about the same number of instructions. When benchmarked - // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO - // execution effects. Changing to using a LUT and branching is risky for smaller cores. + } + const { assert!(T::BITS >= 16) }; + t = x >> 8; + if t != T::ZERO { + z -= 8; + x = t; + } + t = x >> 4; + if t != T::ZERO { + z -= 4; + x = t; + } + t = x >> 2; + if t != T::ZERO { + z -= 2; + x = t; + } + // the last two bisections are combined into one conditional + t = x >> 1; + if t != T::ZERO { + z - 2 + } else { + z - x.cast() } - // The above method does not compile well on RISC-V (because of the lack of predicated - // instructions), producing code with many branches or using an excessively long - // branchless solution. This method takes advantage of the set-if-less-than instruction on - // RISC-V that allows `(x >= power-of-two) as usize` to be branchless. + // We could potentially save a few cycles by using the LUT trick from + // "https://embeddedgurus.com/state-space/2014/09/+%20%20%20%20//%20fast-deterministic-and-portable-counting-leading-zeros/". + // However, 256 bytes for a LUT is too large for embedded use cases. We could remove + // the last 3 bisections and use this 16 byte LUT for the rest of the work: + //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; + //z -= LUT[x] as usize; + //z + // However, it ends up generating about the same number of instructions. When benchmarked + // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO + // execution effects. Changing to using a LUT and branching is risky for smaller cores. +} +} - /// Returns the number of leading binary zeros in `x`. - #[allow(dead_code)] - pub fn leading_zeros_riscv>(x: T) -> usize { - let mut x = x; - // the number of potential leading zeros - let mut z = T::BITS; - // a temporary - let mut t: u32; +// The above method does not compile well on RISC-V (because of the lack of predicated +// instructions), producing code with many branches or using an excessively long +// branchless solution. This method takes advantage of the set-if-less-than instruction on +// RISC-V that allows `(x >= power-of-two) as usize` to be branchless. - // RISC-V does not have a set-if-greater-than-or-equal instruction and - // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is - // still the most optimal method. A conditional set can only be turned into a single - // immediate instruction if `x` is compared with an immediate `imm` (that can fit into - // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the - // right). If we try to save an instruction by using `x < imm` for each bisection, we - // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, - // but the immediate will never fit into 12 bits and never save an instruction. - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise - // `t` is set to 0. - t = ((x >= (T::ONE << 32)) as u32) << 5; - // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the - // next step to process. - x >>= t; - // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential - // leading zeros - z -= t; - } - if T::BITS >= 32 { - t = ((x >= (T::ONE << 16)) as u32) << 4; - x >>= t; - z -= t; - } - const { assert!(T::BITS >= 16) }; - t = ((x >= (T::ONE << 8)) as u32) << 3; - x >>= t; - z -= t; - t = ((x >= (T::ONE << 4)) as u32) << 2; - x >>= t; - z -= t; - t = ((x >= (T::ONE << 2)) as u32) << 1; +public_test_dep! { +/// Returns the number of leading binary zeros in `x`. +#[allow(dead_code)] +pub(crate) fn leading_zeros_riscv>(x: T) -> usize { + let mut x = x; + // the number of potential leading zeros + let mut z = T::BITS; + // a temporary + let mut t: u32; + + // RISC-V does not have a set-if-greater-than-or-equal instruction and + // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is + // still the most optimal method. A conditional set can only be turned into a single + // immediate instruction if `x` is compared with an immediate `imm` (that can fit into + // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the + // right). If we try to save an instruction by using `x < imm` for each bisection, we + // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, + // but the immediate will never fit into 12 bits and never save an instruction. + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise + // `t` is set to 0. + t = ((x >= (T::ONE << 32)) as u32) << 5; + // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the + // next step to process. x >>= t; + // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential + // leading zeros z -= t; - t = (x >= (T::ONE << 1)) as u32; + } + if T::BITS >= 32 { + t = ((x >= (T::ONE << 16)) as u32) << 4; x >>= t; z -= t; - // All bits except the LSB are guaranteed to be zero for this final bisection step. - // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. - z as usize - x.cast() } + const { assert!(T::BITS >= 16) }; + t = ((x >= (T::ONE << 8)) as u32) << 3; + x >>= t; + z -= t; + t = ((x >= (T::ONE << 4)) as u32) << 2; + x >>= t; + z -= t; + t = ((x >= (T::ONE << 2)) as u32) << 1; + x >>= t; + z -= t; + t = (x >= (T::ONE << 1)) as u32; + x >>= t; + z -= t; + // All bits except the LSB are guaranteed to be zero for this final bisection step. + // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. + z as usize - x.cast() +} } intrinsics! { diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index 1f1be711bbda2..c0d5a6715e3ae 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -1,3 +1,5 @@ +use core::ops; + mod specialized_div_rem; pub mod addsub; @@ -8,13 +10,425 @@ 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 = "public-test-deps"))] -pub(crate) use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; +public_test_dep! { +/// Minimal integer implementations needed on all integer types, including wide integers. +#[allow(dead_code)] +pub(crate) trait MinInt: Copy + + core::fmt::Debug + + ops::BitOr + + ops::Not + + ops::Shl +{ + + /// Type with the same width but other signedness + type OtherSign: MinInt; + /// Unsigned version of Self + type UnsignedInt: MinInt; + + /// If `Self` is a signed integer + const SIGNED: bool; + + /// The bitwidth of the int type + const BITS: u32; + + const ZERO: Self; + const ONE: Self; + const MIN: Self; + const MAX: Self; +} +} + +public_test_dep! { +/// Trait for some basic operations on integers +#[allow(dead_code)] +pub(crate) trait Int: MinInt + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::SubAssign + + ops::BitAndAssign + + ops::BitOrAssign + + ops::BitXorAssign + + ops::ShlAssign + + ops::ShrAssign + + ops::Add + + ops::Sub + + ops::Mul + + ops::Div + + ops::Shr + + ops::BitXor + + ops::BitAnd +{ + /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing + /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, + /// 112,119,120,125,126,127]. + const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); + + /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. + const FUZZ_NUM: usize = { + let log2 = (::BITS - 1).count_ones() as usize; + if log2 == 3 { + // case for u8 + 6 + } else { + // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate + // boundaries. + 8 + (4 * (log2 - 4)) + } + }; + + fn unsigned(self) -> Self::UnsignedInt; + fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; + fn unsigned_abs(self) -> Self::UnsignedInt; + + fn from_bool(b: bool) -> Self; + + /// Prevents the need for excessive conversions between signed and unsigned + fn logical_shr(self, other: u32) -> Self; + + /// Absolute difference between two integers. + fn abs_diff(self, other: Self) -> Self::UnsignedInt; + + // copied from primitive integers, but put in a trait + fn is_zero(self) -> bool; + fn wrapping_neg(self) -> Self; + fn wrapping_add(self, other: Self) -> Self; + fn wrapping_mul(self, other: Self) -> Self; + fn wrapping_sub(self, other: Self) -> Self; + fn wrapping_shl(self, other: u32) -> Self; + fn wrapping_shr(self, other: u32) -> Self; + fn rotate_left(self, other: u32) -> Self; + fn overflowing_add(self, other: Self) -> (Self, bool); + fn leading_zeros(self) -> u32; + fn ilog2(self) -> u32; +} +} + +pub(crate) const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { + let mut v = [0u8; 20]; + v[0] = 0; + v[1] = 1; + v[2] = 2; // important for parity and the iX::MIN case when reversed + let mut i = 3; + + // No need for any more until the byte boundary, because there should be no algorithms + // that are sensitive to anything not next to byte boundaries after 2. We also scale + // in powers of two, which is important to prevent u128 corner tests from getting too + // big. + let mut l = 8; + loop { + if l >= ((bits / 2) as u8) { + break; + } + // get both sides of the byte boundary + v[i] = l - 1; + i += 1; + v[i] = l; + i += 1; + l *= 2; + } + + if bits != 8 { + // add the lower side of the middle boundary + v[i] = ((bits / 2) - 1) as u8; + i += 1; + } + + // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS + // boundary because of algorithms that split the high part up. We reverse the scaling + // as we go to Self::BITS. + let mid = i; + let mut j = 1; + loop { + v[i] = (bits as u8) - (v[mid - j]) - 1; + if j == mid { + break; + } + i += 1; + j += 1; + } + v +} + +macro_rules! int_impl_common { + ($ty:ty) => { + fn from_bool(b: bool) -> Self { + b as $ty + } + + fn logical_shr(self, other: u32) -> Self { + Self::from_unsigned(self.unsigned().wrapping_shr(other)) + } + + fn is_zero(self) -> bool { + self == Self::ZERO + } + + fn wrapping_neg(self) -> Self { + ::wrapping_neg(self) + } + + fn wrapping_add(self, other: Self) -> Self { + ::wrapping_add(self, other) + } + + fn wrapping_mul(self, other: Self) -> Self { + ::wrapping_mul(self, other) + } + fn wrapping_sub(self, other: Self) -> Self { + ::wrapping_sub(self, other) + } + + fn wrapping_shl(self, other: u32) -> Self { + ::wrapping_shl(self, other) + } + + fn wrapping_shr(self, other: u32) -> Self { + ::wrapping_shr(self, other) + } + + fn rotate_left(self, other: u32) -> Self { + ::rotate_left(self, other) + } + + fn overflowing_add(self, other: Self) -> (Self, bool) { + ::overflowing_add(self, other) + } + + fn leading_zeros(self) -> u32 { + ::leading_zeros(self) + } + + fn ilog2(self) -> u32 { + ::ilog2(self) + } + }; +} + +macro_rules! int_impl { + ($ity:ty, $uty:ty) => { + impl MinInt for $uty { + type OtherSign = $ity; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $uty { + fn unsigned(self) -> $uty { + self + } + + // It makes writing macros easier if this is implemented for both signed and unsigned + #[allow(clippy::wrong_self_convention)] + fn from_unsigned(me: $uty) -> Self { + me + } + + fn unsigned_abs(self) -> Self { + self + } + + fn abs_diff(self, other: Self) -> Self { + self.abs_diff(other) + } + + int_impl_common!($uty); + } + + impl MinInt for $ity { + type OtherSign = $uty; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $ity { + fn unsigned(self) -> $uty { + self as $uty + } + + fn from_unsigned(me: $uty) -> Self { + me as $ity + } + + fn unsigned_abs(self) -> Self::UnsignedInt { + self.unsigned_abs() + } + + fn abs_diff(self, other: Self) -> $uty { + self.abs_diff(other) + } + + int_impl_common!($ity); + } + }; +} + +int_impl!(isize, usize); +int_impl!(i8, u8); +int_impl!(i16, u16); +int_impl!(i32, u32); +int_impl!(i64, u64); +int_impl!(i128, u128); + +public_test_dep! { +/// 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(crate) 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() + } +} +} + +public_test_dep! { +/// 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(crate) 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 +); + +public_test_dep! { +/// Trait to express (possibly lossy) casting of integers +pub(crate) trait CastInto: Copy { + fn cast(self) -> T; +} + +pub(crate) trait CastFrom:Copy { + fn cast_from(value: T) -> Self; +} +} + +impl + Copy> CastFrom for T { + fn cast_from(value: U) -> Self { + value.cast() + } +} + +macro_rules! cast_into { + ($ty:ty) => { + cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); + }; + ($ty:ty; $($into:ty),*) => {$( + impl CastInto<$into> for $ty { + fn cast(self) -> $into { + self as $into + } + } + )*}; +} -#[cfg(feature = "public-test-deps")] -pub use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; +cast_into!(usize); +cast_into!(isize); +cast_into!(u8); +cast_into!(i8); +cast_into!(u16); +cast_into!(i16); +cast_into!(u32); +cast_into!(i32); +cast_into!(u64); +cast_into!(i64); +cast_into!(u128); +cast_into!(i128); diff --git a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs index f5c6e50239a35..330c6e4f80bb7 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs @@ -185,6 +185,7 @@ macro_rules! impl_delegate { }; } +public_test_dep! { /// Returns `n / d` and sets `*rem = n % d`. /// /// This specialization exists because: @@ -194,7 +195,7 @@ macro_rules! impl_delegate { /// delegate algorithm strategy the only reasonably fast way to perform `u128` division. // used on SPARC #[allow(dead_code)] -pub fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { +pub(crate) fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { use super::*; let duo_lo = duo as u64; let duo_hi = (duo >> 64) as u64; @@ -315,3 +316,4 @@ pub fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { } } } +} diff --git a/library/compiler-builtins/src/int/trailing_zeros.rs b/library/compiler-builtins/src/int/trailing_zeros.rs index dbc0cce9facc9..cea366b07549f 100644 --- a/library/compiler-builtins/src/int/trailing_zeros.rs +++ b/library/compiler-builtins/src/int/trailing_zeros.rs @@ -1,49 +1,44 @@ -#[cfg(feature = "public-test-deps")] -pub use implementation::trailing_zeros; -#[cfg(not(feature = "public-test-deps"))] -pub(crate) use implementation::trailing_zeros; +use crate::int::{CastInto, Int}; -mod implementation { - use crate::int::{CastInto, Int}; +public_test_dep! { +/// Returns number of trailing binary zeros in `x`. +#[allow(dead_code)] +pub(crate) fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { + let mut x = x; + let mut r: u32 = 0; + let mut t: u32; - /// Returns number of trailing binary zeros in `x`. - #[allow(dead_code)] - pub fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { - let mut x = x; - let mut r: u32 = 0; - let mut t: u32; - - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 - x >>= r; // remove 32 zero bits - } - - if T::BITS >= 32 { - t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 - r += t; - x >>= t; // x = [0 - 0xFFFF] + higher garbage bits - } + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 + x >>= r; // remove 32 zero bits + } - const { assert!(T::BITS >= 16) }; - t = ((CastInto::::cast(x) == 0) as u32) << 3; - x >>= t; // x = [0 - 0xFF] + higher garbage bits + if T::BITS >= 32 { + t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 r += t; + x >>= t; // x = [0 - 0xFFFF] + higher garbage bits + } - let mut x: u8 = x.cast(); + const { assert!(T::BITS >= 16) }; + t = ((CastInto::::cast(x) == 0) as u32) << 3; + x >>= t; // x = [0 - 0xFF] + higher garbage bits + r += t; - t = (((x & 0x0F) == 0) as u32) << 2; - x >>= t; // x = [0 - 0xF] + higher garbage bits - r += t; + let mut x: u8 = x.cast(); - t = (((x & 0x3) == 0) as u32) << 1; - x >>= t; // x = [0 - 0x3] + higher garbage bits - r += t; + t = (((x & 0x0F) == 0) as u32) << 2; + x >>= t; // x = [0 - 0xF] + higher garbage bits + r += t; - x &= 3; + t = (((x & 0x3) == 0) as u32) << 1; + x >>= t; // x = [0 - 0x3] + higher garbage bits + r += t; - r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) - } + x &= 3; + + r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) +} } intrinsics! { diff --git a/library/compiler-builtins/src/int/traits.rs b/library/compiler-builtins/src/int/traits.rs deleted file mode 100644 index 9b079e2aa59ae..0000000000000 --- a/library/compiler-builtins/src/int/traits.rs +++ /dev/null @@ -1,411 +0,0 @@ -use core::ops; - -/// Minimal integer implementations needed on all integer types, including wide integers. -#[allow(dead_code)] -pub trait MinInt: - Copy - + core::fmt::Debug - + ops::BitOr - + ops::Not - + ops::Shl -{ - /// Type with the same width but other signedness - type OtherSign: MinInt; - /// Unsigned version of Self - type UnsignedInt: MinInt; - - /// If `Self` is a signed integer - const SIGNED: bool; - - /// The bitwidth of the int type - const BITS: u32; - - const ZERO: Self; - const ONE: Self; - const MIN: Self; - const MAX: Self; -} - -/// Trait for some basic operations on integers -#[allow(dead_code)] -pub trait Int: - MinInt - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::SubAssign - + ops::BitAndAssign - + ops::BitOrAssign - + ops::BitXorAssign - + ops::ShlAssign - + ops::ShrAssign - + ops::Add - + ops::Sub - + ops::Mul - + ops::Div - + ops::Shr - + ops::BitXor - + ops::BitAnd -{ - /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing - /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, - /// 112,119,120,125,126,127]. - const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); - - /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. - const FUZZ_NUM: usize = { - let log2 = (::BITS - 1).count_ones() as usize; - if log2 == 3 { - // case for u8 - 6 - } else { - // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate - // boundaries. - 8 + (4 * (log2 - 4)) - } - }; - - fn unsigned(self) -> Self::UnsignedInt; - fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; - fn unsigned_abs(self) -> Self::UnsignedInt; - - fn from_bool(b: bool) -> Self; - - /// Prevents the need for excessive conversions between signed and unsigned - fn logical_shr(self, other: u32) -> Self; - - /// Absolute difference between two integers. - fn abs_diff(self, other: Self) -> Self::UnsignedInt; - - // copied from primitive integers, but put in a trait - fn is_zero(self) -> bool; - fn wrapping_neg(self) -> Self; - fn wrapping_add(self, other: Self) -> Self; - fn wrapping_mul(self, other: Self) -> Self; - fn wrapping_sub(self, other: Self) -> Self; - fn wrapping_shl(self, other: u32) -> Self; - fn wrapping_shr(self, other: u32) -> Self; - fn rotate_left(self, other: u32) -> Self; - fn overflowing_add(self, other: Self) -> (Self, bool); - fn leading_zeros(self) -> u32; - fn ilog2(self) -> u32; -} - -pub(crate) const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { - let mut v = [0u8; 20]; - v[0] = 0; - v[1] = 1; - v[2] = 2; // important for parity and the iX::MIN case when reversed - let mut i = 3; - - // No need for any more until the byte boundary, because there should be no algorithms - // that are sensitive to anything not next to byte boundaries after 2. We also scale - // in powers of two, which is important to prevent u128 corner tests from getting too - // big. - let mut l = 8; - loop { - if l >= ((bits / 2) as u8) { - break; - } - // get both sides of the byte boundary - v[i] = l - 1; - i += 1; - v[i] = l; - i += 1; - l *= 2; - } - - if bits != 8 { - // add the lower side of the middle boundary - v[i] = ((bits / 2) - 1) as u8; - i += 1; - } - - // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS - // boundary because of algorithms that split the high part up. We reverse the scaling - // as we go to Self::BITS. - let mid = i; - let mut j = 1; - loop { - v[i] = (bits as u8) - (v[mid - j]) - 1; - if j == mid { - break; - } - i += 1; - j += 1; - } - v -} - -macro_rules! int_impl_common { - ($ty:ty) => { - fn from_bool(b: bool) -> Self { - b as $ty - } - - fn logical_shr(self, other: u32) -> Self { - Self::from_unsigned(self.unsigned().wrapping_shr(other)) - } - - fn is_zero(self) -> bool { - self == Self::ZERO - } - - fn wrapping_neg(self) -> Self { - ::wrapping_neg(self) - } - - fn wrapping_add(self, other: Self) -> Self { - ::wrapping_add(self, other) - } - - fn wrapping_mul(self, other: Self) -> Self { - ::wrapping_mul(self, other) - } - fn wrapping_sub(self, other: Self) -> Self { - ::wrapping_sub(self, other) - } - - fn wrapping_shl(self, other: u32) -> Self { - ::wrapping_shl(self, other) - } - - fn wrapping_shr(self, other: u32) -> Self { - ::wrapping_shr(self, other) - } - - fn rotate_left(self, other: u32) -> Self { - ::rotate_left(self, other) - } - - fn overflowing_add(self, other: Self) -> (Self, bool) { - ::overflowing_add(self, other) - } - - fn leading_zeros(self) -> u32 { - ::leading_zeros(self) - } - - fn ilog2(self) -> u32 { - ::ilog2(self) - } - }; -} - -macro_rules! int_impl { - ($ity:ty, $uty:ty) => { - impl MinInt for $uty { - type OtherSign = $ity; - type UnsignedInt = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $uty { - fn unsigned(self) -> $uty { - self - } - - // It makes writing macros easier if this is implemented for both signed and unsigned - #[allow(clippy::wrong_self_convention)] - fn from_unsigned(me: $uty) -> Self { - me - } - - fn unsigned_abs(self) -> Self { - self - } - - fn abs_diff(self, other: Self) -> Self { - self.abs_diff(other) - } - - int_impl_common!($uty); - } - - impl MinInt for $ity { - type OtherSign = $uty; - type UnsignedInt = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $ity { - fn unsigned(self) -> $uty { - self as $uty - } - - fn from_unsigned(me: $uty) -> Self { - me as $ity - } - - fn unsigned_abs(self) -> Self::UnsignedInt { - self.unsigned_abs() - } - - fn abs_diff(self, other: Self) -> $uty { - self.abs_diff(other) - } - - int_impl_common!($ity); - } - }; -} - -int_impl!(isize, usize); -int_impl!(i8, u8); -int_impl!(i16, u16); -int_impl!(i32, u32); -int_impl!(i64, u64); -int_impl!(i128, u128); - -/// 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 -); - -/// Trait to express (possibly lossy) casting of integers -pub trait CastInto: Copy { - fn cast(self) -> T; -} - -pub trait CastFrom: Copy { - fn cast_from(value: T) -> Self; -} - -impl + Copy> CastFrom for T { - fn cast_from(value: U) -> Self { - value.cast() - } -} - -macro_rules! cast_into { - ($ty:ty) => { - cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); - }; - ($ty:ty; $($into:ty),*) => {$( - impl CastInto<$into> for $ty { - fn cast(self) -> $into { - self as $into - } - } - )*}; -} - -cast_into!(usize); -cast_into!(isize); -cast_into!(u8); -cast_into!(i8); -cast_into!(u16); -cast_into!(i16); -cast_into!(u32); -cast_into!(i32); -cast_into!(u64); -cast_into!(i64); -cast_into!(u128); -cast_into!(i128); diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 91606d42be17c..f51e49e987661 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -1,5 +1,21 @@ //! Macros shared throughout the compiler-builtins implementation +/// Changes the visibility to `pub` if feature "public-test-deps" is set +#[cfg(not(feature = "public-test-deps"))] +macro_rules! public_test_dep { + ($(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*) => { + $(#[$($meta)*])* pub(crate) $ident $($tokens)* + }; +} + +/// Changes the visibility to `pub` if feature "public-test-deps" is set +#[cfg(feature = "public-test-deps")] +macro_rules! public_test_dep { + {$(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*} => { + $(#[$($meta)*])* pub $ident $($tokens)* + }; +} + /// The "main macro" used for defining intrinsics. /// /// The compiler-builtins library is super platform-specific with tons of crazy From dbd3032d42e322730394dd6662b9bb8db0329a17 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 4 Feb 2025 10:46:49 +0000 Subject: [PATCH 1636/4206] chore: release v0.1.145 --- library/compiler-builtins/CHANGELOG.md | 10 ++++++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index a1f95d178700d..ddebb78231c44 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.145](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.144...compiler_builtins-v0.1.145) - 2025-02-04 + +### Other + +- Revert "Eliminate the use of `public_test_dep!`" +- Indentation fix to please clippy +- Don't build out of line atomics support code for uefi +- Add a version to some FIXMEs that will be resolved in LLVM 20 +- Remove use of the `start` feature + ## [0.1.144](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.143...compiler_builtins-v0.1.144) - 2025-01-15 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 0b0b7c36528a2..fcbc602382a4e 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.144" +version = "0.1.145" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 98bee053ef9741f8968441cb6d06b9b85f2c7c9b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 30 Jan 2025 12:52:35 +0000 Subject: [PATCH 1637/4206] Fix hex float trait recursion problem --- .../libm/src/math/support/hex_float.rs | 30 ++++--------------- 1 file changed, 5 insertions(+), 25 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 da41622f29675..ebc4f7c64fabe 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -245,29 +245,21 @@ fn fmt_any_hex(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "0x{leading}{sig:0mwidth$x}p{exponent:+}") } -#[cfg(f16_enabled)] -impl fmt::LowerHex for Hexf { +impl fmt::LowerHex for Hexf { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt_any_hex(&self.0, f) } } -impl fmt::LowerHex for Hexf { +impl fmt::LowerHex for Hexf<(F, F)> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_any_hex(&self.0, f) - } -} - -impl fmt::LowerHex for Hexf { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_any_hex(&self.0, f) + write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) } } -#[cfg(f128_enabled)] -impl fmt::LowerHex for Hexf { +impl fmt::LowerHex for Hexf<(F, i32)> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_any_hex(&self.0, f) + write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) } } @@ -277,18 +269,6 @@ impl fmt::LowerHex for Hexf { } } -impl fmt::LowerHex for Hexf<(T1, T2)> -where - T1: Copy, - T2: Copy, - Hexf: fmt::LowerHex, - Hexf: fmt::LowerHex, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) - } -} - impl fmt::Debug for Hexf where Hexf: fmt::LowerHex, From cc2874c9a9e6d58dbd487a543ece7fef68a92df5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 3 Jan 2025 04:34:21 +0000 Subject: [PATCH 1638/4206] Add `scalbnf16`, `scalbnf128`, `ldexpf16`, and `ldexpf128` Use the generic `scalbn` to provide `f16` and `f128` versions, which also work for `ldexp`. This involves a new algorithm for `f16` because the default does not converge fast enough with a limited number of rounds. --- .../libm/crates/libm-macros/src/shared.rs | 14 +++ .../libm/crates/libm-test/benches/icount.rs | 4 + .../libm/crates/libm-test/benches/random.rs | 4 + .../libm/crates/libm-test/src/mpfloat.rs | 61 +++++++------ .../libm/crates/libm-test/src/precision.rs | 4 + .../libm-test/tests/compare_built_musl.rs | 4 + .../libm/crates/util/src/main.rs | 4 + .../libm/etc/function-definitions.json | 26 ++++++ .../libm/etc/function-list.txt | 4 + .../libm/src/math/generic/scalbn.rs | 85 ++++++++++++++++--- .../libm/src/math/ldexpf128.rs | 4 + .../libm/src/math/ldexpf16.rs | 4 + .../compiler-builtins/libm/src/math/mod.rs | 8 ++ .../libm/src/math/scalbnf128.rs | 4 + .../libm/src/math/scalbnf16.rs | 4 + 15 files changed, 195 insertions(+), 39 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/ldexpf128.rs create mode 100644 library/compiler-builtins/libm/src/math/ldexpf16.rs create mode 100644 library/compiler-builtins/libm/src/math/scalbnf128.rs create mode 100644 library/compiler-builtins/libm/src/math/scalbnf16.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index b1f4f46cc3bb6..4fd0834f66280 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -134,6 +134,13 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] None, &["jn", "yn"], ), + ( + // `(f16, i32) -> f16` + FloatTy::F16, + Signature { args: &[Ty::F16, Ty::I32], returns: &[Ty::F16] }, + None, + &["scalbnf16", "ldexpf16"], + ), ( // `(f32, i32) -> f32` FloatTy::F32, @@ -148,6 +155,13 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] None, &["scalbn", "ldexp"], ), + ( + // `(f128, i32) -> f128` + FloatTy::F128, + Signature { args: &[Ty::F128, Ty::I32], returns: &[Ty::F128] }, + None, + &["scalbnf128", "ldexpf128"], + ), ( // `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)` FloatTy::F32, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index d5026f461b0f5..13de799c77f72 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -131,6 +131,8 @@ main!( 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_lgamma_group, icount_bench_lgamma_r_group, @@ -163,6 +165,8 @@ main!( 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_sinf_group, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index ca9e86c10bf95..56d288c332ed1 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -133,10 +133,14 @@ libm_macros::for_each_function! { | fminf16 | fmodf128 | fmodf16 + | ldexpf128 + | ldexpf16 | rintf128 | rintf16 | roundf128 | roundf16 + | scalbnf128 + | scalbnf16 | sqrtf128 | sqrtf16 | truncf128 diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 3d84740ccd792..e3211b9137945 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -159,6 +159,8 @@ libm_macros::for_each_function! { jnf, ldexp, ldexpf, + ldexpf128, + ldexpf16, lgamma_r, lgammaf_r, modf, @@ -178,6 +180,8 @@ libm_macros::for_each_function! { roundf16, scalbn, scalbnf, + scalbnf128, + scalbnf16, sincos,sincosf, trunc, truncf, @@ -351,34 +355,6 @@ macro_rules! impl_op_for_ty { } } - // `ldexp` and `scalbn` are the same for binary floating point, so just forward all - // methods. - impl MpOp for crate::op::[]::Routine { - type MpTy = ]::Routine as MpOp>::MpTy; - - fn new_mp() -> Self::MpTy { - ]::Routine as MpOp>::new_mp() - } - - fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { - ]::Routine as MpOp>::run(this, input) - } - } - - 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 <<= input.1; - prep_retval::(this, Ordering::Equal) - } - } - impl MpOp for crate::op::[]::Routine { type MpTy = (MpFloat, MpFloat); @@ -464,6 +440,35 @@ macro_rules! impl_op_for_ty_all { this.1.assign(input.1); let ord = this.0.rem_assign_round(&this.1, Nearest); prep_retval::(&mut this.0, ord) + + } + } + + // `ldexp` and `scalbn` are the same for binary floating point, so just forward all + // methods. + impl MpOp for crate::op::[]::Routine { + type MpTy = ]::Routine as MpOp>::MpTy; + + fn new_mp() -> Self::MpTy { + ]::Routine as MpOp>::new_mp() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + ]::Routine as MpOp>::run(this, input) + } + } + + 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 <<= input.1; + prep_retval::(this, Ordering::Equal) } } } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index ffb322e38ff86..051960b7a5520 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -551,8 +551,12 @@ fn int_float_common( DEFAULT } +#[cfg(f16_enabled)] +impl MaybeOverride<(f16, i32)> for SpecialCase {} impl MaybeOverride<(f32, i32)> for SpecialCase {} impl MaybeOverride<(f64, i32)> for SpecialCase {} +#[cfg(f128_enabled)] +impl MaybeOverride<(f128, i32)> for SpecialCase {} impl MaybeOverride<(f32, f32, f32)> for SpecialCase { fn check_float( diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 5466edf4f4c1f..191c7e69de393 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -95,10 +95,14 @@ libm_macros::for_each_function! { fminf16, fmodf128, fmodf16, + ldexpf128, + ldexpf16, rintf128, rintf16, roundf128, roundf16, + scalbnf128, + scalbnf16, sqrtf128, sqrtf16, truncf128, diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index 357df6b4fe218..e5d6f374ad85d 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -102,10 +102,14 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | fminf16 | fmodf128 | fmodf16 + | ldexpf128 + | ldexpf16 | rintf128 | rintf16 | roundf128 | roundf16 + | scalbnf128 + | scalbnf16 | sqrtf128 | sqrtf16 | truncf128 diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 574ffea2e5082..e38dfd236635d 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -554,6 +554,18 @@ ], "type": "f32" }, + "ldexpf128": { + "sources": [ + "src/math/ldexpf128.rs" + ], + "type": "f128" + }, + "ldexpf16": { + "sources": [ + "src/math/ldexpf16.rs" + ], + "type": "f16" + }, "lgamma": { "sources": [ "src/libm_helper.rs", @@ -774,6 +786,20 @@ ], "type": "f32" }, + "scalbnf128": { + "sources": [ + "src/math/generic/scalbn.rs", + "src/math/scalbnf128.rs" + ], + "type": "f128" + }, + "scalbnf16": { + "sources": [ + "src/math/generic/scalbn.rs", + "src/math/scalbnf16.rs" + ], + "type": "f16" + }, "sin": { "sources": [ "src/libm_helper.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index d82838b3233d4..c92eaf9e23eb6 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -79,6 +79,8 @@ jn jnf ldexp ldexpf +ldexpf128 +ldexpf16 lgamma lgamma_r lgammaf @@ -111,6 +113,8 @@ roundf128 roundf16 scalbn scalbnf +scalbnf128 +scalbnf16 sin sincos sincosf diff --git a/library/compiler-builtins/libm/src/math/generic/scalbn.rs b/library/compiler-builtins/libm/src/math/generic/scalbn.rs index f036c15cc0312..f15cb75d63123 100644 --- a/library/compiler-builtins/libm/src/math/generic/scalbn.rs +++ b/library/compiler-builtins/libm/src/math/generic/scalbn.rs @@ -31,16 +31,27 @@ where let exp_max: i32 = F::EXP_BIAS as i32; let exp_min = -(exp_max - 1); - // 2 ^ Emax, where Emax is the maximum biased exponent value (1023 for f64) + // 2 ^ Emax, maximum positive with null significand (0x1p1023 for f64) let f_exp_max = F::from_parts(false, F::EXP_BIAS << 1, zero); - // 2 ^ Emin, where Emin is the minimum biased exponent value (-1022 for f64) + // 2 ^ Emin, minimum positive normal with null significand (0x1p-1022 for f64) let f_exp_min = F::from_parts(false, 1, zero); - // 2 ^ sig_total_bits, representation of what can be accounted for with subnormals - let f_exp_subnorm = F::from_parts(false, sig_total_bits + F::EXP_BIAS, zero); + // 2 ^ sig_total_bits, moltiplier to normalize subnormals (0x1p53 for f64) + let f_pow_subnorm = F::from_parts(false, sig_total_bits + F::EXP_BIAS, zero); + + /* + * The goal is to multiply `x` by a scale factor that applies `n`. However, there are cases + * where `2^n` is not representable by `F` but the result should be, e.g. `x = 2^Emin` with + * `n = -EMin + 2` (one out of range of 2^Emax). To get around this, reduce the magnitude of + * the final scale operation by prescaling by the max/min power representable by `F`. + */ if n > exp_max { + // Worse case positive `n`: `x` is the minimum subnormal value, the result is `F::MAX`. + // This can be reached by three scaling multiplications (two here and one final). + debug_assert!(-exp_min + F::SIG_BITS as i32 + exp_max <= exp_max * 3); + x *= f_exp_max; n -= exp_max; if n > exp_max { @@ -51,21 +62,61 @@ where } } } else if n < exp_min { - let mul = f_exp_min * f_exp_subnorm; - let add = (exp_max - 1) - sig_total_bits as i32; + // When scaling toward 0, the prescaling is limited to a value that does not allow `x` to + // go subnormal. This avoids double rounding. + if F::BITS > 16 { + // `mul` s.t. `!(x * mul).is_subnormal() ∀ x` + let mul = f_exp_min * f_pow_subnorm; + let add = -exp_min - sig_total_bits as i32; + + // Worse case negative `n`: `x` is the maximum positive value, the result is `F::MIN`. + // This must be reachable by three scaling multiplications (two here and one final). + debug_assert!(-exp_min + F::SIG_BITS as i32 + exp_max <= add * 2 + -exp_min); - x *= mul; - n += add; - if n < exp_min { x *= mul; n += add; + if n < exp_min { - n = exp_min; + x *= mul; + n += add; + + if n < exp_min { + n = exp_min; + } + } + } else { + // `f16` is unique compared to other float types in that the difference between the + // minimum exponent and the significand bits (`add = -exp_min - sig_total_bits`) is + // small, only three. The above method depend on decrementing `n` by `add` two times; + // for other float types this works out because `add` is a substantial fraction of + // the exponent range. For `f16`, however, 3 is relatively small compared to the + // exponent range (which is 39), so that requires ~10 prescale rounds rather than two. + // + // Work aroudn this by using a different algorithm that calculates the prescale + // dynamically based on the maximum possible value. This adds more operations per round + // since it needs to construct the scale, but works better in the general case. + let add = -(n + sig_total_bits as i32).clamp(exp_min, sig_total_bits as i32); + let mul = F::from_parts(false, (F::EXP_BIAS as i32 - add) as u32, zero); + + x *= mul; + n += add; + + if n < exp_min { + let add = -(n + sig_total_bits as i32).clamp(exp_min, sig_total_bits as i32); + let mul = F::from_parts(false, (F::EXP_BIAS as i32 - add) as u32, zero); + + x *= mul; + n += add; + + if n < exp_min { + n = exp_min; + } } } } - x * F::from_parts(false, (F::EXP_BIAS as i32 + n) as u32, zero) + let scale = F::from_parts(false, (F::EXP_BIAS as i32 + n) as u32, zero); + x * scale } #[cfg(test)] @@ -111,6 +162,12 @@ mod tests { assert!(scalbn(-F::NAN, -10).is_nan()); } + #[test] + #[cfg(f16_enabled)] + fn spec_test_f16() { + spec_test::(); + } + #[test] fn spec_test_f32() { spec_test::(); @@ -120,4 +177,10 @@ mod tests { fn spec_test_f64() { spec_test::(); } + + #[test] + #[cfg(f128_enabled)] + fn spec_test_f128() { + spec_test::(); + } } diff --git a/library/compiler-builtins/libm/src/math/ldexpf128.rs b/library/compiler-builtins/libm/src/math/ldexpf128.rs new file mode 100644 index 0000000000000..b35277d15fbae --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ldexpf128.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf128(x: f128, n: i32) -> f128 { + super::scalbnf128(x, n) +} diff --git a/library/compiler-builtins/libm/src/math/ldexpf16.rs b/library/compiler-builtins/libm/src/math/ldexpf16.rs new file mode 100644 index 0000000000000..8de6cffd69987 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/ldexpf16.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf16(x: f16, n: i32) -> f16 { + super::scalbnf16(x, n) +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 969c1bfd942aa..9b07dc8a75ebd 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -349,8 +349,10 @@ cfg_if! { mod fmaxf16; mod fminf16; mod fmodf16; + mod ldexpf16; mod rintf16; mod roundf16; + mod scalbnf16; mod sqrtf16; mod truncf16; @@ -362,8 +364,10 @@ cfg_if! { pub use self::fmaxf16::fmaxf16; pub use self::fminf16::fminf16; pub use self::fmodf16::fmodf16; + pub use self::ldexpf16::ldexpf16; pub use self::rintf16::rintf16; pub use self::roundf16::roundf16; + pub use self::scalbnf16::scalbnf16; pub use self::sqrtf16::sqrtf16; pub use self::truncf16::truncf16; } @@ -379,8 +383,10 @@ cfg_if! { mod fmaxf128; mod fminf128; mod fmodf128; + mod ldexpf128; mod rintf128; mod roundf128; + mod scalbnf128; mod sqrtf128; mod truncf128; @@ -392,8 +398,10 @@ cfg_if! { pub use self::fmaxf128::fmaxf128; pub use self::fminf128::fminf128; pub use self::fmodf128::fmodf128; + pub use self::ldexpf128::ldexpf128; pub use self::rintf128::rintf128; pub use self::roundf128::roundf128; + pub use self::scalbnf128::scalbnf128; pub use self::sqrtf128::sqrtf128; pub use self::truncf128::truncf128; } diff --git a/library/compiler-builtins/libm/src/math/scalbnf128.rs b/library/compiler-builtins/libm/src/math/scalbnf128.rs new file mode 100644 index 0000000000000..c1d2b48558568 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/scalbnf128.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf128(x: f128, n: i32) -> f128 { + super::generic::scalbn(x, n) +} diff --git a/library/compiler-builtins/libm/src/math/scalbnf16.rs b/library/compiler-builtins/libm/src/math/scalbnf16.rs new file mode 100644 index 0000000000000..2209e1a179566 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/scalbnf16.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf16(x: f16, n: i32) -> f16 { + super::generic::scalbn(x, n) +} From cc1a55a77ee02f23c0b138701c3e24eea247b523 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 5 Feb 2025 15:00:04 +0000 Subject: [PATCH 1639/4206] Add a check in the `shared.rs` that the function list is sorted --- .../libm/crates/libm-macros/src/shared.rs | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index 4fd0834f66280..da16cd8e2874f 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -18,7 +18,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] None, &[ "acosf", "acoshf", "asinf", "asinhf", "atanf", "atanhf", "cbrtf", "ceilf", "cosf", - "coshf", "erff", "erfcf", "exp10f", "exp2f", "expf", "expm1f", "fabsf", "floorf", + "coshf", "erfcf", "erff", "exp10f", "exp2f", "expf", "expm1f", "fabsf", "floorf", "j0f", "j1f", "lgammaf", "log10f", "log1pf", "log2f", "logf", "rintf", "roundf", "sinf", "sinhf", "sqrtf", "tanf", "tanhf", "tgammaf", "truncf", "y0f", "y1f", ], @@ -30,8 +30,8 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] None, &[ "acos", "acosh", "asin", "asinh", "atan", "atanh", "cbrt", "ceil", "cos", "cosh", - "erf", "erfc", "exp10", "exp2", "exp", "expm1", "fabs", "floor", "j0", "j1", "lgamma", - "log10", "log1p", "log2", "log", "rint", "round", "sin", "sinh", "sqrt", "tan", "tanh", + "erf", "erfc", "exp", "exp10", "exp2", "expm1", "fabs", "floor", "j0", "j1", "lgamma", + "log", "log10", "log1p", "log2", "rint", "round", "sin", "sinh", "sqrt", "tan", "tanh", "tgamma", "trunc", "y0", "y1", ], ), @@ -139,28 +139,28 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16, Ty::I32], returns: &[Ty::F16] }, None, - &["scalbnf16", "ldexpf16"], + &["ldexpf16", "scalbnf16"], ), ( // `(f32, i32) -> f32` FloatTy::F32, Signature { args: &[Ty::F32, Ty::I32], returns: &[Ty::F32] }, None, - &["scalbnf", "ldexpf"], + &["ldexpf", "scalbnf"], ), ( // `(f64, i64) -> f64` FloatTy::F64, Signature { args: &[Ty::F64, Ty::I32], returns: &[Ty::F64] }, None, - &["scalbn", "ldexp"], + &["ldexp", "scalbn"], ), ( // `(f128, i32) -> f128` FloatTy::F128, Signature { args: &[Ty::F128, Ty::I32], returns: &[Ty::F128] }, None, - &["scalbnf128", "ldexpf128"], + &["ldexpf128", "scalbnf128"], ), ( // `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)` @@ -312,6 +312,12 @@ pub static ALL_OPERATIONS: LazyLock> = LazyLock::new(|| { }; ret.push(api); } + + if !names.is_sorted() { + let mut sorted = (*names).to_owned(); + sorted.sort_unstable(); + panic!("names list is not sorted: {names:?}\nExpected: {sorted:?}"); + } } ret.sort_by_key(|item| item.name); From f7765fae89b69f9a6c6727bb0af181ac9099f9b1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 5 Feb 2025 15:02:17 +0000 Subject: [PATCH 1640/4206] Do not add `libm_helper.rs` to the sources list This is just a collection of all functions and should not trigger extensive tests when changed. --- .../libm/etc/function-definitions.json | 57 ------------------- .../libm/etc/update-api-list.py | 9 +++ 2 files changed, 9 insertions(+), 57 deletions(-) diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index e38dfd236635d..a1d3adf591f42 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -2,7 +2,6 @@ "__comment": "Autogenerated by update-api-list.py. List of files that define a function with a given name. This file is checked in to make it obvious if refactoring breaks things", "acos": { "sources": [ - "src/libm_helper.rs", "src/math/acos.rs" ], "type": "f64" @@ -15,7 +14,6 @@ }, "acosh": { "sources": [ - "src/libm_helper.rs", "src/math/acosh.rs" ], "type": "f64" @@ -28,7 +26,6 @@ }, "asin": { "sources": [ - "src/libm_helper.rs", "src/math/asin.rs" ], "type": "f64" @@ -41,7 +38,6 @@ }, "asinh": { "sources": [ - "src/libm_helper.rs", "src/math/asinh.rs" ], "type": "f64" @@ -54,14 +50,12 @@ }, "atan": { "sources": [ - "src/libm_helper.rs", "src/math/atan.rs" ], "type": "f64" }, "atan2": { "sources": [ - "src/libm_helper.rs", "src/math/atan2.rs" ], "type": "f64" @@ -80,7 +74,6 @@ }, "atanh": { "sources": [ - "src/libm_helper.rs", "src/math/atanh.rs" ], "type": "f64" @@ -93,7 +86,6 @@ }, "cbrt": { "sources": [ - "src/libm_helper.rs", "src/math/cbrt.rs" ], "type": "f64" @@ -106,7 +98,6 @@ }, "ceil": { "sources": [ - "src/libm_helper.rs", "src/math/arch/i586.rs", "src/math/arch/wasm32.rs", "src/math/ceil.rs", @@ -138,7 +129,6 @@ }, "copysign": { "sources": [ - "src/libm_helper.rs", "src/math/copysign.rs", "src/math/generic/copysign.rs", "src/math/support/float_traits.rs" @@ -168,7 +158,6 @@ }, "cos": { "sources": [ - "src/libm_helper.rs", "src/math/cos.rs" ], "type": "f64" @@ -181,7 +170,6 @@ }, "cosh": { "sources": [ - "src/libm_helper.rs", "src/math/cosh.rs" ], "type": "f64" @@ -194,14 +182,12 @@ }, "erf": { "sources": [ - "src/libm_helper.rs", "src/math/erf.rs" ], "type": "f64" }, "erfc": { "sources": [ - "src/libm_helper.rs", "src/math/erf.rs" ], "type": "f64" @@ -220,7 +206,6 @@ }, "exp": { "sources": [ - "src/libm_helper.rs", "src/math/exp.rs", "src/math/support/float_traits.rs" ], @@ -228,7 +213,6 @@ }, "exp10": { "sources": [ - "src/libm_helper.rs", "src/math/exp10.rs" ], "type": "f64" @@ -241,7 +225,6 @@ }, "exp2": { "sources": [ - "src/libm_helper.rs", "src/math/exp2.rs" ], "type": "f64" @@ -260,7 +243,6 @@ }, "expm1": { "sources": [ - "src/libm_helper.rs", "src/math/expm1.rs" ], "type": "f64" @@ -273,7 +255,6 @@ }, "fabs": { "sources": [ - "src/libm_helper.rs", "src/math/arch/wasm32.rs", "src/math/fabs.rs", "src/math/generic/fabs.rs" @@ -304,7 +285,6 @@ }, "fdim": { "sources": [ - "src/libm_helper.rs", "src/math/fdim.rs", "src/math/generic/fdim.rs" ], @@ -333,7 +313,6 @@ }, "floor": { "sources": [ - "src/libm_helper.rs", "src/math/arch/i586.rs", "src/math/arch/wasm32.rs", "src/math/floor.rs", @@ -365,7 +344,6 @@ }, "fma": { "sources": [ - "src/libm_helper.rs", "src/math/fma.rs" ], "type": "f64" @@ -378,7 +356,6 @@ }, "fmax": { "sources": [ - "src/libm_helper.rs", "src/math/fmax.rs", "src/math/generic/fmax.rs" ], @@ -407,7 +384,6 @@ }, "fmin": { "sources": [ - "src/libm_helper.rs", "src/math/fmin.rs", "src/math/generic/fmin.rs" ], @@ -436,7 +412,6 @@ }, "fmod": { "sources": [ - "src/libm_helper.rs", "src/math/fmod.rs", "src/math/generic/fmod.rs" ], @@ -465,7 +440,6 @@ }, "frexp": { "sources": [ - "src/libm_helper.rs", "src/math/frexp.rs" ], "type": "f64" @@ -478,7 +452,6 @@ }, "hypot": { "sources": [ - "src/libm_helper.rs", "src/math/hypot.rs" ], "type": "f64" @@ -491,7 +464,6 @@ }, "ilogb": { "sources": [ - "src/libm_helper.rs", "src/math/ilogb.rs" ], "type": "f64" @@ -504,7 +476,6 @@ }, "j0": { "sources": [ - "src/libm_helper.rs", "src/math/j0.rs" ], "type": "f64" @@ -517,7 +488,6 @@ }, "j1": { "sources": [ - "src/libm_helper.rs", "src/math/j1.rs" ], "type": "f64" @@ -530,7 +500,6 @@ }, "jn": { "sources": [ - "src/libm_helper.rs", "src/math/jn.rs" ], "type": "f64" @@ -543,7 +512,6 @@ }, "ldexp": { "sources": [ - "src/libm_helper.rs", "src/math/ldexp.rs" ], "type": "f64" @@ -568,14 +536,12 @@ }, "lgamma": { "sources": [ - "src/libm_helper.rs", "src/math/lgamma.rs" ], "type": "f64" }, "lgamma_r": { "sources": [ - "src/libm_helper.rs", "src/math/lgamma_r.rs" ], "type": "f64" @@ -594,14 +560,12 @@ }, "log": { "sources": [ - "src/libm_helper.rs", "src/math/log.rs" ], "type": "f64" }, "log10": { "sources": [ - "src/libm_helper.rs", "src/math/log10.rs" ], "type": "f64" @@ -614,7 +578,6 @@ }, "log1p": { "sources": [ - "src/libm_helper.rs", "src/math/log1p.rs" ], "type": "f64" @@ -627,7 +590,6 @@ }, "log2": { "sources": [ - "src/libm_helper.rs", "src/math/log2.rs" ], "type": "f64" @@ -646,7 +608,6 @@ }, "modf": { "sources": [ - "src/libm_helper.rs", "src/math/modf.rs" ], "type": "f64" @@ -659,7 +620,6 @@ }, "nextafter": { "sources": [ - "src/libm_helper.rs", "src/math/nextafter.rs" ], "type": "f64" @@ -672,7 +632,6 @@ }, "pow": { "sources": [ - "src/libm_helper.rs", "src/math/pow.rs" ], "type": "f64" @@ -685,7 +644,6 @@ }, "remainder": { "sources": [ - "src/libm_helper.rs", "src/math/remainder.rs" ], "type": "f64" @@ -698,7 +656,6 @@ }, "remquo": { "sources": [ - "src/libm_helper.rs", "src/math/remquo.rs" ], "type": "f64" @@ -711,7 +668,6 @@ }, "rint": { "sources": [ - "src/libm_helper.rs", "src/math/arch/aarch64.rs", "src/math/arch/wasm32.rs", "src/math/generic/rint.rs", @@ -744,7 +700,6 @@ }, "round": { "sources": [ - "src/libm_helper.rs", "src/math/generic/round.rs", "src/math/round.rs" ], @@ -773,7 +728,6 @@ }, "scalbn": { "sources": [ - "src/libm_helper.rs", "src/math/generic/scalbn.rs", "src/math/scalbn.rs" ], @@ -802,14 +756,12 @@ }, "sin": { "sources": [ - "src/libm_helper.rs", "src/math/sin.rs" ], "type": "f64" }, "sincos": { "sources": [ - "src/libm_helper.rs", "src/math/sincos.rs" ], "type": "f64" @@ -828,7 +780,6 @@ }, "sinh": { "sources": [ - "src/libm_helper.rs", "src/math/sinh.rs" ], "type": "f64" @@ -841,7 +792,6 @@ }, "sqrt": { "sources": [ - "src/libm_helper.rs", "src/math/arch/i686.rs", "src/math/arch/wasm32.rs", "src/math/generic/sqrt.rs", @@ -874,7 +824,6 @@ }, "tan": { "sources": [ - "src/libm_helper.rs", "src/math/tan.rs" ], "type": "f64" @@ -887,7 +836,6 @@ }, "tanh": { "sources": [ - "src/libm_helper.rs", "src/math/tanh.rs" ], "type": "f64" @@ -900,7 +848,6 @@ }, "tgamma": { "sources": [ - "src/libm_helper.rs", "src/math/tgamma.rs" ], "type": "f64" @@ -913,7 +860,6 @@ }, "trunc": { "sources": [ - "src/libm_helper.rs", "src/math/arch/wasm32.rs", "src/math/generic/trunc.rs", "src/math/trunc.rs" @@ -944,7 +890,6 @@ }, "y0": { "sources": [ - "src/libm_helper.rs", "src/math/j0.rs" ], "type": "f64" @@ -957,7 +902,6 @@ }, "y1": { "sources": [ - "src/libm_helper.rs", "src/math/j1.rs" ], "type": "f64" @@ -970,7 +914,6 @@ }, "yn": { "sources": [ - "src/libm_helper.rs", "src/math/jn.rs" ], "type": "f64" diff --git a/library/compiler-builtins/libm/etc/update-api-list.py b/library/compiler-builtins/libm/etc/update-api-list.py index 67f73e59cf140..54da13257958f 100755 --- a/library/compiler-builtins/libm/etc/update-api-list.py +++ b/library/compiler-builtins/libm/etc/update-api-list.py @@ -1,6 +1,9 @@ #!/usr/bin/env python3 """Create a text file listing all public API. This can be used to ensure that all functions are covered by our macros. + +This file additionally does tidy-esque checks that all functions are listed where +needed, or that lists are sorted. """ import difflib @@ -15,6 +18,9 @@ ETC_DIR = Path(__file__).parent ROOT_DIR = ETC_DIR.parent +# These files do not trigger a retest. +IGNORED_SOURCES = ["src/libm_helper.rs"] + IndexTy: TypeAlias = dict[str, dict[str, Any]] """Type of the `index` item in rustdoc's JSON output""" @@ -120,6 +126,9 @@ def _init_defs(self, index: IndexTy) -> None: for src in (s for s in base_sources if "generic" in s): sources.add(src) + for src in IGNORED_SOURCES: + sources.discard(src) + # Sort the set self.defs = {k: sorted(v) for (k, v) in defs.items()} From eee632ee1b75f2fcc6ee679d340169a7386a0604 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 5 Feb 2025 15:03:34 +0000 Subject: [PATCH 1641/4206] Add checks via annotation that lists are sorted or exhaustive This crate has a handful of lists that need to list all API and can't easily be verified. Additionally, some longer lists should be kept sorted so they are easier to look through. Resolve both of these by adding a check in `update-api-list.py` that looks for annotations and verifies the contents are as expected. Annotations are `verify-apilist-start`, `verify-apilist-end`, `verify-sorted-start`, and `verify-sorted-end`. This includes fixes for anything that did not meet the criteria. --- .../libm/crates/libm-test/benches/icount.rs | 9 +- .../libm/crates/libm-test/src/mpfloat.rs | 2 + .../libm-test/tests/compare_built_musl.rs | 2 + .../libm/etc/update-api-list.py | 143 ++++++++++++++++-- .../compiler-builtins/libm/src/libm_helper.rs | 44 +++++- .../compiler-builtins/libm/src/math/mod.rs | 8 + 6 files changed, 187 insertions(+), 21 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index 13de799c77f72..53ecb5a37c4bd 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -52,7 +52,10 @@ libm_macros::for_each_function! { } main!( - library_benchmark_groups = icount_bench_acos_group, + library_benchmark_groups = + // verify-apilist-start + // verify-sorted-start + icount_bench_acos_group, icount_bench_acosf_group, icount_bench_acosh_group, icount_bench_acoshf_group, @@ -169,6 +172,8 @@ main!( 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, @@ -192,4 +197,6 @@ main!( icount_bench_y1f_group, icount_bench_yn_group, icount_bench_ynf_group, + // verify-sorted-end + // verify-apilist-end ); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index e3211b9137945..ab77d541c812d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -132,6 +132,7 @@ libm_macros::for_each_function! { emit_types: [RustFn], skip: [ // Most of these need a manual implementation + // verify-sorted-start ceil, ceilf, ceilf128, @@ -188,6 +189,7 @@ libm_macros::for_each_function! { truncf128, truncf16,yn, ynf, + // verify-sorted-end ], fn_extra: match MACRO_FN_NAME { // Remap function names that are different between mpfr and libm diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 191c7e69de393..0b0a9f0972166 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -79,6 +79,7 @@ libm_macros::for_each_function! { ynf, // Not provided by musl + // verify-sorted-start ceilf128, ceilf16, copysignf128, @@ -107,5 +108,6 @@ libm_macros::for_each_function! { sqrtf16, truncf128, truncf16, + // verify-sorted-end ], } diff --git a/library/compiler-builtins/libm/etc/update-api-list.py b/library/compiler-builtins/libm/etc/update-api-list.py index 54da13257958f..9cf6255542233 100755 --- a/library/compiler-builtins/libm/etc/update-api-list.py +++ b/library/compiler-builtins/libm/etc/update-api-list.py @@ -8,16 +8,21 @@ import difflib import json +import re import subprocess as sp import sys from dataclasses import dataclass -from glob import glob +from glob import glob, iglob from pathlib import Path -from typing import Any, TypeAlias +from typing import Any, Callable, TypeAlias -ETC_DIR = Path(__file__).parent +SELF_PATH = Path(__file__) +ETC_DIR = SELF_PATH.parent ROOT_DIR = ETC_DIR.parent +# Loose approximation of what gets checked in to git, without needing `git ls-files`. +DIRECTORIES = [".github", "ci", "crates", "etc", "src"] + # These files do not trigger a retest. IGNORED_SOURCES = ["src/libm_helper.rs"] @@ -25,6 +30,11 @@ """Type of the `index` item in rustdoc's JSON output""" +def eprint(*args, **kwargs): + """Print to stderr.""" + print(*args, file=sys.stderr, **kwargs) + + @dataclass class Crate: """Representation of public interfaces and function defintion locations in @@ -146,7 +156,7 @@ def write_function_list(self, check: bool) -> None: if check: with open(out_file, "r") as f: current = f.read() - diff_and_exit(current, output) + diff_and_exit(current, output, "function list") else: with open(out_file, "w") as f: f.write(output) @@ -171,18 +181,115 @@ def write_function_defs(self, check: bool) -> None: if check: with open(out_file, "r") as f: current = f.read() - diff_and_exit(current, output) + diff_and_exit(current, output, "source list") else: 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. + """ + for dirname in DIRECTORIES: + dir = ROOT_DIR.joinpath(dirname) + for fname in iglob("**", root_dir=dir, recursive=True): + fpath = dir.joinpath(fname) + 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. + """ + not_found = [] + for func in self.public_functions: + # The function name may be on its own or somewhere in a snake case string. + pat = re.compile(rf"(\b|_){func}(\b|_)") + found = next((line for line in lines if pat.search(line)), None) + + if found is None: + not_found.append(func) + + if len(not_found) == 0: + return + + relpath = fpath.relative_to(ROOT_DIR) + eprint(f"functions not found at {relpath}:{line_num}: {not_found}") + 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( + "".join(lines), + "".join(sorted(lines)), + f"sorted block at {relpath}:{block_start_line}", + ) -def diff_and_exit(actual: str, expected: str): + +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. """ if actual == expected: - print("output matches expected; success") + print(f"{name} output matches expected; success") return a = [f"{line}\n" for line in actual.splitlines()] @@ -190,7 +297,7 @@ def diff_and_exit(actual: str, expected: str): diff = difflib.unified_diff(a, b, "actual", "expected") sys.stdout.writelines(diff) - print("mismatched function list") + print(f"mismatched {name}") exit(1) @@ -223,23 +330,31 @@ def base_name(name: str) -> tuple[str, str]: return (name, "f64") +def ensure_updated_list(check: bool) -> None: + """Runner to update the function list and JSON, or check that it is already up + to date. + """ + crate = Crate() + crate.write_function_list(check) + crate.write_function_defs(check) + + if check: + crate.tidy_lists() + + def main(): """By default overwrite the file. If `--check` is passed, print a diff instead and error if the files are different. """ match sys.argv: case [_]: - check = False + ensure_updated_list(False) case [_, "--check"]: - check = True + ensure_updated_list(True) case _: print("unrecognized arguments") exit(1) - crate = Crate() - crate.write_function_list(check) - crate.write_function_defs(check) - if __name__ == "__main__": main() diff --git a/library/compiler-builtins/libm/src/libm_helper.rs b/library/compiler-builtins/libm/src/libm_helper.rs index 73bae456761bf..0768839c77993 100644 --- a/library/compiler-builtins/libm/src/libm_helper.rs +++ b/library/compiler-builtins/libm/src/libm_helper.rs @@ -44,9 +44,11 @@ macro_rules! libm_helper { }; } +// verify-apilist-start libm_helper! { f32, funcs: { + // verify-sorted-start (fn acos(x: f32) -> (f32); => acosf); (fn acosh(x: f32) -> (f32); => acoshf); (fn asin(x: f32) -> (f32); => asinf); @@ -62,8 +64,8 @@ libm_helper! { (fn erf(x: f32) -> (f32); => erff); (fn erfc(x: f32) -> (f32); => erfcf); (fn exp(x: f32) -> (f32); => expf); - (fn exp2(x: f32) -> (f32); => exp2f); (fn exp10(x: f32) -> (f32); => exp10f); + (fn exp2(x: f32) -> (f32); => exp2f); (fn expm1(x: f32) -> (f32); => expm1f); (fn fabs(x: f32) -> (f32); => fabsf); (fn fdim(x: f32, y: f32) -> (f32); => fdimf); @@ -79,12 +81,12 @@ libm_helper! { (fn j1(x: f32) -> (f32); => j1f); (fn jn(n: i32, x: f32) -> (f32); => jnf); (fn ldexp(x: f32, n: i32) -> (f32); => ldexpf); - (fn lgamma_r(x: f32) -> (f32, i32); => lgammaf_r); (fn lgamma(x: f32) -> (f32); => lgammaf); + (fn lgamma_r(x: f32) -> (f32, i32); => lgammaf_r); (fn log(x: f32) -> (f32); => logf); + (fn log10(x: f32) -> (f32); => log10f); (fn log1p(x: f32) -> (f32); => log1pf); (fn log2(x: f32) -> (f32); => log2f); - (fn log10(x: f32) -> (f32); => log10f); (fn modf(x: f32) -> (f32, f32); => modff); (fn nextafter(x: f32, y: f32) -> (f32); => nextafterf); (fn pow(x: f32, y: f32) -> (f32); => powf); @@ -104,12 +106,14 @@ libm_helper! { (fn y0(x: f32) -> (f32); => y0f); (fn y1(x: f32) -> (f32); => y1f); (fn yn(n: i32, x: f32) -> (f32); => ynf); + // verify-sorted-end } } libm_helper! { f64, funcs: { + // verify-sorted-start (fn acos(x: f64) -> (f64); => acos); (fn acosh(x: f64) -> (f64); => acosh); (fn asin(x: f64) -> (f64); => asin); @@ -125,8 +129,8 @@ libm_helper! { (fn erf(x: f64) -> (f64); => erf); (fn erfc(x: f64) -> (f64); => erfc); (fn exp(x: f64) -> (f64); => exp); - (fn exp2(x: f64) -> (f64); => exp2); (fn exp10(x: f64) -> (f64); => exp10); + (fn exp2(x: f64) -> (f64); => exp2); (fn expm1(x: f64) -> (f64); => expm1); (fn fabs(x: f64) -> (f64); => fabs); (fn fdim(x: f64, y: f64) -> (f64); => fdim); @@ -142,12 +146,12 @@ libm_helper! { (fn j1(x: f64) -> (f64); => j1); (fn jn(n: i32, x: f64) -> (f64); => jn); (fn ldexp(x: f64, n: i32) -> (f64); => ldexp); - (fn lgamma_r(x: f64) -> (f64, i32); => lgamma_r); (fn lgamma(x: f64) -> (f64); => lgamma); + (fn lgamma_r(x: f64) -> (f64, i32); => lgamma_r); (fn log(x: f64) -> (f64); => log); + (fn log10(x: f64) -> (f64); => log10); (fn log1p(x: f64) -> (f64); => log1p); (fn log2(x: f64) -> (f64); => log2); - (fn log10(x: f64) -> (f64); => log10); (fn modf(x: f64) -> (f64, f64); => modf); (fn nextafter(x: f64, y: f64) -> (f64); => nextafter); (fn pow(x: f64, y: f64) -> (f64); => pow); @@ -167,6 +171,7 @@ libm_helper! { (fn y0(x: f64) -> (f64); => y0); (fn y1(x: f64) -> (f64); => y1); (fn yn(n: i32, x: f64) -> (f64); => yn); + // verify-sorted-end } } @@ -174,9 +179,22 @@ libm_helper! { libm_helper! { f16, funcs: { + // verify-sorted-start + (fn ceilf(x: f16) -> (f16); => ceilf16); (fn copysign(x: f16, y: f16) -> (f16); => copysignf16); (fn fabs(x: f16) -> (f16); => fabsf16); (fn fdim(x: f16, y: f16) -> (f16); => fdimf16); + (fn floorf(x: f16) -> (f16); => floorf16); + (fn fmaxf(x: f16, y: f16) -> (f16); => fmaxf16); + (fn fminf(x: f16, y: f16) -> (f16); => fminf16); + (fn fmodf(x: f16, y: f16) -> (f16); => fmodf16); + (fn ldexpf16(x: f16, n: i32) -> (f16); => ldexpf16); + (fn rintf(x: f16) -> (f16); => rintf16); + (fn roundf(x: f16) -> (f16); => roundf16); + (fn scalbnf16(x: f16, n: i32) -> (f16); => ldexpf16); + (fn sqrtf(x: f16) -> (f16); => sqrtf16); + (fn truncf(x: f16) -> (f16); => truncf16); + // verify-sorted-end } } @@ -184,8 +202,22 @@ libm_helper! { libm_helper! { f128, funcs: { + // verify-sorted-start + (fn ceil(x: f128) -> (f128); => ceilf128); (fn copysign(x: f128, y: f128) -> (f128); => copysignf128); (fn fabs(x: f128) -> (f128); => fabsf128); (fn fdim(x: f128, y: f128) -> (f128); => fdimf128); + (fn floor(x: f128) -> (f128); => floorf128); + (fn fmax(x: f128, y: f128) -> (f128); => fmaxf128); + (fn fmin(x: f128, y: f128) -> (f128); => fminf128); + (fn fmod(x: f128, y: f128) -> (f128); => fmodf128); + (fn ldexpf128(x: f128, n: i32) -> (f128); => ldexpf128); + (fn rint(x: f128) -> (f128); => rintf128); + (fn round(x: f128) -> (f128); => roundf128); + (fn scalbnf128(x: f128, n: i32) -> (f128); => ldexpf128); + (fn sqrt(x: f128) -> (f128); => sqrtf128); + (fn trunc(x: f128) -> (f128); => truncf128); + // verify-sorted-end } } +// verify-apilist-end diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 9b07dc8a75ebd..f0698ad02ebaa 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -341,6 +341,7 @@ pub use self::truncf::truncf; cfg_if! { if #[cfg(f16_enabled)] { + // verify-sorted-start mod ceilf16; mod copysignf16; mod fabsf16; @@ -355,7 +356,9 @@ cfg_if! { mod scalbnf16; mod sqrtf16; mod truncf16; + // verify-sorted-end + // verify-sorted-start pub use self::ceilf16::ceilf16; pub use self::copysignf16::copysignf16; pub use self::fabsf16::fabsf16; @@ -370,11 +373,13 @@ cfg_if! { pub use self::scalbnf16::scalbnf16; pub use self::sqrtf16::sqrtf16; pub use self::truncf16::truncf16; + // verify-sorted-end } } cfg_if! { if #[cfg(f128_enabled)] { + // verify-sorted-start mod ceilf128; mod copysignf128; mod fabsf128; @@ -389,7 +394,9 @@ cfg_if! { mod scalbnf128; mod sqrtf128; mod truncf128; + // verify-sorted-end + // verify-sorted-start pub use self::ceilf128::ceilf128; pub use self::copysignf128::copysignf128; pub use self::fabsf128::fabsf128; @@ -404,6 +411,7 @@ cfg_if! { pub use self::scalbnf128::scalbnf128; pub use self::sqrtf128::sqrtf128; pub use self::truncf128::truncf128; + // verify-sorted-end } } From 9458abd20439c75584bd1b33a1ef7b6891ab5e8a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 23 Jan 2025 08:28:58 +0000 Subject: [PATCH 1642/4206] Start converting `fma` to a generic function This is the first step toward making `fma` usable for `f128`, and possibly `f32` on platforms where growing to `f64` is not fast. This does not yet work for anything other than `f64`. --- .../libm/etc/function-definitions.json | 6 +- .../compiler-builtins/libm/src/math/fma.rs | 192 +-------------- .../libm/src/math/generic/fma.rs | 227 ++++++++++++++++++ .../libm/src/math/generic/mod.rs | 2 + .../libm/src/math/support/float_traits.rs | 4 +- .../libm/src/math/support/int_traits.rs | 39 +++ 6 files changed, 278 insertions(+), 192 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/fma.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index a1d3adf591f42..243862075ff08 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -344,13 +344,15 @@ }, "fma": { "sources": [ - "src/math/fma.rs" + "src/math/fma.rs", + "src/math/generic/fma.rs" ], "type": "f64" }, "fmaf": { "sources": [ - "src/math/fmaf.rs" + "src/math/fmaf.rs", + "src/math/generic/fma.rs" ], "type": "f32" }, diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 826143d5a47c4..69cc3eb6726d2 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -1,195 +1,9 @@ -use core::{f32, f64}; - -use super::scalbn; - -const ZEROINFNAN: i32 = 0x7ff - 0x3ff - 52 - 1; - -struct Num { - m: u64, - e: i32, - sign: i32, -} - -fn normalize(x: f64) -> Num { - let x1p63: f64 = f64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63 - - let mut ix: u64 = x.to_bits(); - let mut e: i32 = (ix >> 52) as i32; - let sign: i32 = e & 0x800; - e &= 0x7ff; - if e == 0 { - ix = (x * x1p63).to_bits(); - e = (ix >> 52) as i32 & 0x7ff; - e = if e != 0 { e - 63 } else { 0x800 }; - } - ix &= (1 << 52) - 1; - ix |= 1 << 52; - ix <<= 1; - e -= 0x3ff + 52 + 1; - Num { m: ix, e, sign } -} - -#[inline] -fn mul(x: u64, y: u64) -> (u64, u64) { - let t = (x as u128).wrapping_mul(y as u128); - ((t >> 64) as u64, t as u64) -} - -/// Floating multiply add (f64) +/// Fused multiply add (f64) /// -/// Computes `(x*y)+z`, rounded as one ternary operation: -/// Computes the value (as if) to infinite precision and rounds once to the result format, -/// according to the rounding mode characterized by the value of FLT_ROUNDS. +/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fma(x: f64, y: f64, z: f64) -> f64 { - let x1p63: f64 = f64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63 - let x0_ffffff8p_63 = f64::from_bits(0x3bfffffff0000000); // 0x0.ffffff8p-63 - - /* normalize so top 10bits and last bit are 0 */ - let nx = normalize(x); - let ny = normalize(y); - let nz = normalize(z); - - if nx.e >= ZEROINFNAN || ny.e >= ZEROINFNAN { - return x * y + z; - } - if nz.e >= ZEROINFNAN { - if nz.e > ZEROINFNAN { - /* z==0 */ - return x * y + z; - } - return z; - } - - /* mul: r = x*y */ - let zhi: u64; - let zlo: u64; - let (mut rhi, mut rlo) = mul(nx.m, ny.m); - /* either top 20 or 21 bits of rhi and last 2 bits of rlo are 0 */ - - /* align exponents */ - let mut e: i32 = nx.e + ny.e; - let mut d: i32 = nz.e - e; - /* shift bits z<<=kz, r>>=kr, so kz+kr == d, set e = e+kr (== ez-kz) */ - if d > 0 { - if d < 64 { - zlo = nz.m << d; - zhi = nz.m >> (64 - d); - } else { - zlo = 0; - zhi = nz.m; - e = nz.e - 64; - d -= 64; - if d == 0 { - } else if d < 64 { - rlo = (rhi << (64 - d)) | (rlo >> d) | ((rlo << (64 - d)) != 0) as u64; - rhi = rhi >> d; - } else { - rlo = 1; - rhi = 0; - } - } - } else { - zhi = 0; - d = -d; - if d == 0 { - zlo = nz.m; - } else if d < 64 { - zlo = (nz.m >> d) | ((nz.m << (64 - d)) != 0) as u64; - } else { - zlo = 1; - } - } - - /* add */ - let mut sign: i32 = nx.sign ^ ny.sign; - let samesign: bool = (sign ^ nz.sign) == 0; - let mut nonzero: i32 = 1; - if samesign { - /* r += z */ - rlo = rlo.wrapping_add(zlo); - rhi += zhi + (rlo < zlo) as u64; - } else { - /* r -= z */ - let (res, borrow) = rlo.overflowing_sub(zlo); - rlo = res; - rhi = rhi.wrapping_sub(zhi.wrapping_add(borrow as u64)); - if (rhi >> 63) != 0 { - rlo = (rlo as i64).wrapping_neg() as u64; - rhi = (rhi as i64).wrapping_neg() as u64 - (rlo != 0) as u64; - sign = (sign == 0) as i32; - } - nonzero = (rhi != 0) as i32; - } - - /* set rhi to top 63bit of the result (last bit is sticky) */ - if nonzero != 0 { - e += 64; - d = rhi.leading_zeros() as i32 - 1; - /* note: d > 0 */ - rhi = (rhi << d) | (rlo >> (64 - d)) | ((rlo << d) != 0) as u64; - } else if rlo != 0 { - d = rlo.leading_zeros() as i32 - 1; - if d < 0 { - rhi = (rlo >> 1) | (rlo & 1); - } else { - rhi = rlo << d; - } - } else { - /* exact +-0 */ - return x * y + z; - } - e -= d; - - /* convert to double */ - let mut i: i64 = rhi as i64; /* i is in [1<<62,(1<<63)-1] */ - if sign != 0 { - i = -i; - } - let mut r: f64 = i as f64; /* |r| is in [0x1p62,0x1p63] */ - - if e < -1022 - 62 { - /* result is subnormal before rounding */ - if e == -1022 - 63 { - let mut c: f64 = x1p63; - if sign != 0 { - c = -c; - } - if r == c { - /* min normal after rounding, underflow depends - on arch behaviour which can be imitated by - a double to float conversion */ - let fltmin: f32 = (x0_ffffff8p_63 * f32::MIN_POSITIVE as f64 * r) as f32; - return f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * fltmin as f64; - } - /* one bit is lost when scaled, add another top bit to - only round once at conversion if it is inexact */ - if (rhi << 53) != 0 { - i = ((rhi >> 1) | (rhi & 1) | (1 << 62)) as i64; - if sign != 0 { - i = -i; - } - r = i as f64; - r = 2. * r - c; /* remove top bit */ - - /* raise underflow portably, such that it - cannot be optimized away */ - { - let tiny: f64 = f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * r; - r += (tiny * tiny) * (r - r); - } - } - } else { - /* only round once when scaled */ - d = 10; - i = (((rhi >> d) | ((rhi << (64 - d)) != 0) as u64) << d) as i64; - if sign != 0 { - i = -i; - } - r = i as f64; - } - } - scalbn(r, e) + return super::generic::fma(x, y, z); } #[cfg(test)] diff --git a/library/compiler-builtins/libm/src/math/generic/fma.rs b/library/compiler-builtins/libm/src/math/generic/fma.rs new file mode 100644 index 0000000000000..3d5459f1a04f7 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fma.rs @@ -0,0 +1,227 @@ +use core::{f32, f64}; + +use super::super::support::{DInt, HInt, IntTy}; +use super::super::{CastFrom, CastInto, Float, Int, MinInt}; + +const ZEROINFNAN: i32 = 0x7ff - 0x3ff - 52 - 1; + +/// Fused multiply-add that works when there is not a larger float size available. Currently this +/// is still specialized only for `f64`. Computes `(x * y) + z`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fma(x: F, y: F, z: F) -> F +where + F: Float + FmaHelper, + F: CastFrom, + F: CastFrom, + F::Int: HInt, + u32: CastInto, +{ + let one = IntTy::::ONE; + let zero = IntTy::::ZERO; + let magic = F::from_parts(false, F::BITS - 1 + F::EXP_BIAS, zero); + + /* normalize so top 10bits and last bit are 0 */ + let nx = Norm::from_float(x); + let ny = Norm::from_float(y); + let nz = Norm::from_float(z); + + if nx.e >= ZEROINFNAN || ny.e >= ZEROINFNAN { + return x * y + z; + } + if nz.e >= ZEROINFNAN { + if nz.e > ZEROINFNAN { + /* z==0 */ + return x * y + z; + } + return z; + } + + /* mul: r = x*y */ + let zhi: F::Int; + let zlo: F::Int; + let (mut rlo, mut rhi) = nx.m.widen_mul(ny.m).lo_hi(); + + /* either top 20 or 21 bits of rhi and last 2 bits of rlo are 0 */ + + /* align exponents */ + let mut e: i32 = nx.e + ny.e; + let mut d: i32 = nz.e - e; + let sbits = F::BITS as i32; + + /* shift bits z<<=kz, r>>=kr, so kz+kr == d, set e = e+kr (== ez-kz) */ + if d > 0 { + if d < sbits { + zlo = nz.m << d; + zhi = nz.m >> (sbits - d); + } else { + zlo = zero; + zhi = nz.m; + e = nz.e - sbits; + d -= sbits; + if d == 0 { + } else if d < sbits { + rlo = (rhi << (sbits - d)) + | (rlo >> d) + | IntTy::::from((rlo << (sbits - d)) != zero); + rhi = rhi >> d; + } else { + rlo = one; + rhi = zero; + } + } + } else { + zhi = zero; + d = -d; + if d == 0 { + zlo = nz.m; + } else if d < sbits { + zlo = (nz.m >> d) | IntTy::::from((nz.m << (sbits - d)) != zero); + } else { + zlo = one; + } + } + + /* add */ + let mut neg = nx.neg ^ ny.neg; + let samesign: bool = !neg ^ nz.neg; + let mut nonzero: i32 = 1; + if samesign { + /* r += z */ + rlo = rlo.wrapping_add(zlo); + rhi += zhi + IntTy::::from(rlo < zlo); + } else { + /* r -= z */ + let (res, borrow) = rlo.overflowing_sub(zlo); + rlo = res; + rhi = rhi.wrapping_sub(zhi.wrapping_add(IntTy::::from(borrow))); + if (rhi >> (F::BITS - 1)) != zero { + rlo = rlo.signed().wrapping_neg().unsigned(); + rhi = rhi.signed().wrapping_neg().unsigned() - IntTy::::from(rlo != zero); + neg = !neg; + } + nonzero = (rhi != zero) as i32; + } + + /* set rhi to top 63bit of the result (last bit is sticky) */ + if nonzero != 0 { + e += sbits; + d = rhi.leading_zeros() as i32 - 1; + /* note: d > 0 */ + rhi = (rhi << d) | (rlo >> (sbits - d)) | IntTy::::from((rlo << d) != zero); + } else if rlo != zero { + d = rlo.leading_zeros() as i32 - 1; + if d < 0 { + rhi = (rlo >> 1) | (rlo & one); + } else { + rhi = rlo << d; + } + } else { + /* exact +-0 */ + return x * y + z; + } + e -= d; + + /* convert to double */ + let mut i: F::SignedInt = rhi.signed(); /* i is in [1<<62,(1<<63)-1] */ + if neg { + i = -i; + } + + let mut r: F = F::cast_from_lossy(i); /* |r| is in [0x1p62,0x1p63] */ + + if e < -(F::EXP_BIAS as i32 - 1) - (sbits - 2) { + /* result is subnormal before rounding */ + if e == -(F::EXP_BIAS as i32 - 1) - (sbits - 1) { + let mut c: F = magic; + if neg { + c = -c; + } + if r == c { + /* min normal after rounding, underflow depends + * on arch behaviour which can be imitated by + * a double to float conversion */ + return r.raise_underflow(); + } + /* one bit is lost when scaled, add another top bit to + * only round once at conversion if it is inexact */ + if (rhi << F::SIG_BITS) != zero { + let iu: F::Int = (rhi >> 1) | (rhi & one) | (one << 62); + i = iu.signed(); + if neg { + i = -i; + } + r = F::cast_from_lossy(i); + r = F::cast_from(2i8) * r - c; /* remove top bit */ + + /* raise underflow portably, such that it + * cannot be optimized away */ + r += r.raise_underflow2(); + } + } else { + /* only round once when scaled */ + d = 10; + i = (((rhi >> d) | IntTy::::from(rhi << (F::BITS as i32 - d) != zero)) << d) + .signed(); + if neg { + i = -i; + } + r = F::cast_from(i); + } + } + + super::scalbn(r, e) +} + +/// Representation of `F` that has handled subnormals. +struct Norm { + /// Normalized significand with one guard bit. + m: F::Int, + /// Unbiased exponent, normalized. + e: i32, + neg: bool, +} + +impl Norm { + fn from_float(x: F) -> Self { + let mut ix = x.to_bits(); + let mut e = x.exp() as i32; + let neg = x.is_sign_negative(); + if e == 0 { + // Normalize subnormals by multiplication + let magic = F::from_parts(false, F::BITS - 1 + F::EXP_BIAS, F::Int::ZERO); + let scaled = x * magic; + ix = scaled.to_bits(); + e = scaled.exp() as i32; + e = if e != 0 { e - (F::BITS as i32 - 1) } else { 0x800 }; + } + + e -= F::EXP_BIAS as i32 + 52 + 1; + + ix &= F::SIG_MASK; + ix |= F::IMPLICIT_BIT; + ix <<= 1; // add a guard bit + + Self { m: ix, e, neg } + } +} + +/// Type-specific helpers that are not needed outside of fma. +pub trait FmaHelper { + fn raise_underflow(self) -> Self; + fn raise_underflow2(self) -> Self; +} + +impl FmaHelper for f64 { + fn raise_underflow(self) -> Self { + let x0_ffffff8p_63 = f64::from_bits(0x3bfffffff0000000); // 0x0.ffffff8p-63 + let fltmin: f32 = (x0_ffffff8p_63 * f32::MIN_POSITIVE as f64 * self) as f32; + f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * fltmin as f64 + } + + fn raise_underflow2(self) -> Self { + /* raise underflow portably, such that it + * cannot be optimized away */ + let tiny: f64 = f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * self; + (tiny * tiny) * (self - self) + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index 68686b0b25503..e19cc83a9acc3 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -3,6 +3,7 @@ mod copysign; mod fabs; mod fdim; mod floor; +mod fma; mod fmax; mod fmin; mod fmod; @@ -17,6 +18,7 @@ pub use copysign::copysign; pub use fabs::fabs; pub use fdim::fdim; pub use floor::floor; +pub use fma::fma; pub use fmax::fmax; pub use fmin::fmin; pub use fmod::fmod; 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 1fe2cb424b9a1..24cf7d4b05cde 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -23,7 +23,9 @@ pub trait Float: type Int: Int; /// A int of the same width as the float - type SignedInt: Int + MinInt; + type SignedInt: Int + + MinInt + + ops::Neg; const ZERO: Self; const NEG_ZERO: Self; 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 b403c658cb697..793a0f3069f90 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -52,10 +52,14 @@ pub trait Int: + ops::Sub + ops::Mul + ops::Div + + ops::Shl + + ops::Shl + + ops::Shr + ops::Shr + ops::BitXor + ops::BitAnd + cmp::Ord + + From + CastFrom + CastFrom + CastFrom @@ -92,6 +96,7 @@ pub trait Int: fn wrapping_shr(self, other: u32) -> Self; fn rotate_left(self, other: u32) -> Self; fn overflowing_add(self, other: Self) -> (Self, bool); + fn overflowing_sub(self, other: Self) -> (Self, bool); fn leading_zeros(self) -> u32; fn ilog2(self) -> u32; } @@ -150,6 +155,10 @@ macro_rules! int_impl_common { ::overflowing_add(self, other) } + fn overflowing_sub(self, other: Self) -> (Self, bool) { + ::overflowing_sub(self, other) + } + fn leading_zeros(self) -> u32 { ::leading_zeros(self) } @@ -399,6 +408,30 @@ macro_rules! cast_into { )*}; } +macro_rules! cast_into_float { + ($ty:ty) => { + #[cfg(f16_enabled)] + cast_into_float!($ty; f16); + + cast_into_float!($ty; f32, f64); + + #[cfg(f128_enabled)] + cast_into_float!($ty; f128); + }; + ($ty:ty; $($into:ty),*) => {$( + impl CastInto<$into> for $ty { + fn cast(self) -> $into { + debug_assert_eq!(self as $into as $ty, self, "inexact float cast"); + self as $into + } + + fn cast_lossy(self) -> $into { + self as $into + } + } + )*}; +} + cast_into!(usize); cast_into!(isize); cast_into!(u8); @@ -411,3 +444,9 @@ cast_into!(u64); cast_into!(i64); cast_into!(u128); cast_into!(i128); + +cast_into_float!(i8); +cast_into_float!(i16); +cast_into_float!(i32); +cast_into_float!(i64); +cast_into_float!(i128); From e01ce5d53a929019a8c9655c7dee4c74a911d465 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 5 Feb 2025 21:18:33 +0000 Subject: [PATCH 1643/4206] Commonize the signature for all instances of `get_test_cases` In order to make these more interchangeable in more places, always return `(impl Iterator, u64)`. This will facilitate using other generators for extensive tests. --- .../libm/crates/libm-test/benches/random.rs | 2 +- .../crates/libm-test/examples/plot_domains.rs | 8 ++++- .../crates/libm-test/src/gen/edge_cases.rs | 29 +++++++++-------- .../libm/crates/libm-test/src/gen/random.rs | 31 ++++++++++--------- .../libm-test/tests/compare_built_musl.rs | 4 +-- .../crates/libm-test/tests/multiprecision.rs | 4 +-- 6 files changed, 45 insertions(+), 33 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 56d288c332ed1..66486a56a2a9f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -54,7 +54,7 @@ where let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl, GeneratorKind::Random); let benchvec: Vec<_> = - random::get_test_cases::(&ctx).take(BENCH_ITER_ITEMS).collect(); + random::get_test_cases::(&ctx).0.take(BENCH_ITER_ITEMS).collect(); // Perform a sanity check that we are benchmarking the same thing // Don't test against musl if it is not available diff --git a/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs b/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs index fb7b854df85c1..441889c694175 100644 --- a/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs +++ b/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs @@ -58,7 +58,13 @@ where let mut ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr, GeneratorKind::QuickSpaced); plot_one_generator(out_dir, &ctx, "logspace", config, spaced::get_test_cases::(&ctx).0); ctx.gen_kind = GeneratorKind::EdgeCases; - plot_one_generator(out_dir, &ctx, "edge_cases", config, edge_cases::get_test_cases::(&ctx)); + plot_one_generator( + out_dir, + &ctx, + "edge_cases", + config, + edge_cases::get_test_cases::(&ctx).0, + ); } /// Plot the output of a single generator. diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs index d4014bdb36097..8de954ae332c0 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs @@ -9,7 +9,7 @@ use crate::{CheckCtx, FloatExt, MathOp, test_log}; /// Generate a sequence of edge cases, e.g. numbers near zeroes and infiniteis. pub trait EdgeCaseInput { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator + Send; + fn get_cases(ctx: &CheckCtx) -> (impl Iterator + Send, u64); } /// Create a list of values around interesting points (infinities, zeroes, NaNs). @@ -140,10 +140,10 @@ macro_rules! impl_edge_case_input { where Op: MathOp, { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let (iter0, steps0) = float_edge_cases::(ctx, 0); let iter0 = iter0.map(|v| (v,)); - KnownSize::new(iter0, steps0) + (iter0, steps0) } } @@ -151,13 +151,13 @@ macro_rules! impl_edge_case_input { where Op: MathOp, { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + 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 count = steps0.checked_mul(steps1).unwrap(); - KnownSize::new(iter, count) + (iter, count) } } @@ -165,7 +165,7 @@ macro_rules! impl_edge_case_input { where Op: MathOp, { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + 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); @@ -177,7 +177,7 @@ macro_rules! impl_edge_case_input { }); let count = steps0.checked_mul(steps1).unwrap().checked_mul(steps2).unwrap(); - KnownSize::new(iter, count) + (iter, count) } } @@ -185,7 +185,7 @@ macro_rules! impl_edge_case_input { where Op: MathOp, { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let (iter0, steps0) = int_edge_cases(ctx, 0); let (iter1, steps1) = float_edge_cases::(ctx, 1); @@ -193,7 +193,7 @@ macro_rules! impl_edge_case_input { iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); let count = steps0.checked_mul(steps1).unwrap(); - KnownSize::new(iter, count) + (iter, count) } } @@ -201,7 +201,7 @@ macro_rules! impl_edge_case_input { where Op: MathOp, { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let (iter0, steps0) = float_edge_cases::(ctx, 0); let (iter1, steps1) = int_edge_cases(ctx, 1); @@ -209,7 +209,7 @@ macro_rules! impl_edge_case_input { iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); let count = steps0.checked_mul(steps1).unwrap(); - KnownSize::new(iter, count) + (iter, count) } } }; @@ -224,10 +224,13 @@ impl_edge_case_input!(f128); pub fn get_test_cases( ctx: &CheckCtx, -) -> impl ExactSizeIterator + use<'_, Op> +) -> (impl Iterator + Send + use<'_, Op>, u64) where Op: MathOp, Op::RustArgs: EdgeCaseInput, { - Op::RustArgs::get_cases(ctx) + let (iter, count) = Op::RustArgs::get_cases(ctx); + + // Wrap in `KnownSize` so we get an assertion if the cuunt is wrong. + (KnownSize::new(iter, count), count) } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index 56c39981a44eb..5b127f38d09f4 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -26,8 +26,8 @@ pub(crate) static SEED: LazyLock<[u8; 32]> = LazyLock::new(|| { }); /// Generate a sequence of random values of this type. -pub trait RandomInput { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator; +pub trait RandomInput: Sized { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator + Send, u64); } /// Generate a sequence of deterministically random floats. @@ -51,25 +51,25 @@ fn random_ints(count: u64, range: RangeInclusive) -> impl Iterator { impl RandomInput for ($fty,) { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let count = iteration_count(ctx, 0); let iter = random_floats(count).map(|f: $fty| (f,)); - KnownSize::new(iter, count) + (iter, count) } } impl RandomInput for ($fty, $fty) { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + 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))); - KnownSize::new(iter, count0 * count1) + (iter, count0 * count1) } } impl RandomInput for ($fty, $fty, $fty) { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let count0 = iteration_count(ctx, 0); let count1 = iteration_count(ctx, 1); let count2 = iteration_count(ctx, 2); @@ -78,30 +78,30 @@ macro_rules! impl_random_input { random_floats(count2).map(move |f3: $fty| (f1, f2, f3)) }) }); - KnownSize::new(iter, count0 * count1 * count2) + (iter, count0 * count1 * count2) } } impl RandomInput for (i32, $fty) { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + 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 iter = random_ints(count0, range0) .flat_map(move |f1: i32| random_floats(count1).map(move |f2: $fty| (f1, f2))); - KnownSize::new(iter, count0 * count1) + (iter, count0 * count1) } } impl RandomInput for ($fty, i32) { - fn get_cases(ctx: &CheckCtx) -> impl ExactSizeIterator { + 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 iter = random_floats(count0).flat_map(move |f1: $fty| { random_ints(count1, range1.clone()).map(move |f2: i32| (f1, f2)) }); - KnownSize::new(iter, count0 * count1) + (iter, count0 * count1) } } }; @@ -117,6 +117,9 @@ impl_random_input!(f128); /// Create a test case iterator. pub fn get_test_cases( ctx: &CheckCtx, -) -> impl Iterator + use<'_, RustArgs> { - RustArgs::get_cases(ctx) +) -> (impl Iterator + Send + use<'_, RustArgs>, u64) { + let (iter, count) = RustArgs::get_cases(ctx); + + // Wrap in `KnownSize` so we get an assertion if the cuunt is wrong. + (KnownSize::new(iter, count), count) } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 0b0a9f0972166..c8beaffc3af21 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -39,7 +39,7 @@ macro_rules! musl_tests { fn [< musl_random_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::Random); - let cases = random::get_test_cases::<::RustArgs>(&ctx); + let cases = random::get_test_cases::<::RustArgs>(&ctx).0; musl_runner::(&ctx, cases, musl_math_sys::$fn_name); } @@ -48,7 +48,7 @@ macro_rules! musl_tests { fn [< musl_edge_case_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::EdgeCases); - let cases = edge_cases::get_test_cases::(&ctx); + let cases = edge_cases::get_test_cases::(&ctx).0; musl_runner::(&ctx, cases, musl_math_sys::$fn_name); } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 761ca1f851e21..0d5c5e60c20c7 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -29,7 +29,7 @@ macro_rules! mp_tests { fn [< mp_random_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::Random); - let cases = random::get_test_cases::<::RustArgs>(&ctx); + let cases = random::get_test_cases::<::RustArgs>(&ctx).0; mp_runner::(&ctx, cases); } @@ -38,7 +38,7 @@ macro_rules! mp_tests { fn [< mp_edge_case_ $fn_name >]() { type Op = libm_test::op::$fn_name::Routine; let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::EdgeCases); - let cases = edge_cases::get_test_cases::(&ctx); + let cases = edge_cases::get_test_cases::(&ctx).0; mp_runner::(&ctx, cases); } From 3fbe59f8503fb5eb151bc995ba2c1ebad80dcbb5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 6 Feb 2025 00:02:00 +0000 Subject: [PATCH 1644/4206] Print the hex float format upon failure Now that we have a hex float formatter, make use of it for test output. This produces values that are easier to read than the bitwise hex representation. Example: thread 'mp_quickspace_fmaf128' panicked at crates/libm-test/tests/multiprecision.rs:17:48: called `Result::unwrap()` on an `Err` value: input: (0xe38d71c71c71c71c71c71c71c71c71c8, 0xe38d71c71c71c71c71c71c71c71c71c8, 0xffff0000000000000000000000000000) as hex: (-0x1.71c71c71c71c71c71c71c71c71c8p+9102, -0x1.71c71c71c71c71c71c71c71c71c8p+9102, -inf) as bits: (0xe38d71c71c71c71c71c71c71c71c71c8, 0xe38d71c71c71c71c71c71c71c71c71c8, 0xffff0000000000000000000000000000) expected: 0xffff0000000000000000000000000000 -inf 0xffff0000000000000000000000000000 actual: 0x7fff8000000000000000000000000000 NaN 0x7fff8000000000000000000000000000 Caused by: real value != NaN --- .../libm/crates/libm-test/src/test_traits.rs | 46 ++++++++++++++++--- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index a5806943e1127..1bd5bce162bd7 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -9,6 +9,7 @@ use std::fmt; use anyhow::{Context, anyhow, bail, ensure}; +use libm::support::Hexf; use crate::precision::CheckAction; use crate::{CheckCtx, Float, Int, MaybeOverride, SpecialCase, TestResult}; @@ -35,7 +36,10 @@ pub trait CheckOutput: Sized { /// /// 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` */ @@ -128,6 +132,10 @@ where fn hex(self) -> String { format!("({},)", self.0.hex()) } + + fn hexf(self) -> String { + format!("({},)", self.0.hexf()) + } } impl Hex for (T1, T2) @@ -138,6 +146,10 @@ where 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) @@ -149,6 +161,10 @@ where 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 ints */ @@ -160,6 +176,10 @@ macro_rules! impl_int { 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 @@ -234,6 +254,10 @@ macro_rules! impl_float { width = ((Self::BITS / 4) + 2) as usize ) } + + fn hexf(self) -> String { + format!("{}", Hexf(self)) + } } impl $crate::CheckOutput for $ty @@ -324,13 +348,18 @@ where res.with_context(|| { format!( "\ - \n input: {input:?} {ibits}\ - \n expected: {expected:<22?} {expbits}\ - \n actual: {actual:<22?} {actbits}\ + \n input: {input:?}\ + \n as hex: {ihex}\ + \n as bits: {ibits}\ + \n expected: {expected:<22?} {exphex} {expbits}\ + \n actual: {actual:<22?} {acthex} {actbits}\ ", - actbits = actual.hex(), - expbits = expected.hex(), + ihex = input.hexf(), ibits = input.hex(), + exphex = expected.hexf(), + expbits = expected.hex(), + actbits = actual.hex(), + acthex = actual.hexf(), ) }) } @@ -365,12 +394,15 @@ macro_rules! impl_tuples { .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}\ ", - actbits = self.hex(), - expbits = expected.hex(), + ihex = input.hexf(), ibits = input.hex(), + expbits = expected.hex(), + actbits = self.hex(), )) } } From 23989245ce549411b9d80323b89c9eb48fff53ec Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 6 Feb 2025 00:34:56 +0000 Subject: [PATCH 1645/4206] fma: Ensure zero has the correct sign Currently, `fma(tiny, -tiny, 0.0)` returns 0.0 while the answer should be -0.0. This is because `-0.0 + 0.0 = +0.0` in the default rounding mode; however, the result should be negative. Musl has the same pattern but that version worked because the C compiler was contracting `x*y + z` to (ironically) `fmadd`. Musl was fixed in 9683bd6241 ("math: fix fma(x,y,0) when x*y rounds to -0"). Add the same fix here, which allows dropping the xfails. --- .../libm/crates/libm-test/src/precision.rs | 47 +------------------ .../libm/src/math/generic/fma.rs | 2 +- 2 files changed, 3 insertions(+), 46 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 051960b7a5520..596f91fe1efae 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -558,48 +558,5 @@ impl MaybeOverride<(f64, i32)> for SpecialCase {} #[cfg(f128_enabled)] impl MaybeOverride<(f128, i32)> for SpecialCase {} -impl MaybeOverride<(f32, f32, f32)> for SpecialCase { - fn check_float( - input: (f32, f32, f32), - actual: F, - expected: F, - ctx: &CheckCtx, - ) -> CheckAction { - ternop_common(input, actual, expected, ctx) - } -} -impl MaybeOverride<(f64, f64, f64)> for SpecialCase { - fn check_float( - input: (f64, f64, f64), - actual: F, - expected: F, - ctx: &CheckCtx, - ) -> CheckAction { - ternop_common(input, actual, expected, ctx) - } -} - -// F1 and F2 are always the same type, this is just to please generics -fn ternop_common( - input: (F1, F1, F1), - actual: F2, - expected: F2, - ctx: &CheckCtx, -) -> CheckAction { - // FIXME(fma): 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result - // of fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the - // exact result". Our implementation returns the wrong sign: - // fma(5e-324, -5e-324, 0.0) = 0.0 (should be -0.0) - if ctx.base_name == BaseName::Fma - && (input.0.is_sign_negative() ^ input.1.is_sign_negative()) - && input.0 != F1::ZERO - && input.1 != F1::ZERO - && input.2.biteq(F1::ZERO) - && expected.biteq(F2::NEG_ZERO) - && actual.biteq(F2::ZERO) - { - return XFAIL("fma sign"); - } - - DEFAULT -} +impl MaybeOverride<(f32, f32, f32)> for SpecialCase {} +impl MaybeOverride<(f64, f64, f64)> for SpecialCase {} diff --git a/library/compiler-builtins/libm/src/math/generic/fma.rs b/library/compiler-builtins/libm/src/math/generic/fma.rs index 3d5459f1a04f7..b0e2117ea0988 100644 --- a/library/compiler-builtins/libm/src/math/generic/fma.rs +++ b/library/compiler-builtins/libm/src/math/generic/fma.rs @@ -31,7 +31,7 @@ where if nz.e >= ZEROINFNAN { if nz.e > ZEROINFNAN { /* z==0 */ - return x * y + z; + return x * y; } return z; } From ada2d9ae1d8747cd6159fc090c4fa39b0c74d3bd Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 6 Feb 2025 01:59:44 +0000 Subject: [PATCH 1646/4206] Switch `musl` to track `master` A few bugs have been fixed, including the sign of `fma(tiny, -tiny, 0.0)`. Switch to tracking `master` rather than the latest tag so we don't need to xfail these tests. --- library/compiler-builtins/libm/crates/musl-math-sys/musl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/musl b/library/compiler-builtins/libm/crates/musl-math-sys/musl index 0784374d56143..61399d4bd02ae 160000 --- a/library/compiler-builtins/libm/crates/musl-math-sys/musl +++ b/library/compiler-builtins/libm/crates/musl-math-sys/musl @@ -1 +1 @@ -Subproject commit 0784374d561435f7c787a555aeab8ede699ed298 +Subproject commit 61399d4bd02ae1ec03068445aa7ffe9174466bfd From 4bf116f146b9f3d918e9d8be74616eb044fd5ead Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 6 Feb 2025 04:03:11 +0000 Subject: [PATCH 1647/4206] Add an integration test that verifies a list of cases We need someplace to collect known failures, previous regressions, edge cases that are difficult to construct from generics, and similar. Introduce this here. --- .../libm/crates/libm-test/src/gen.rs | 1 + .../crates/libm-test/src/gen/case_list.rs | 686 ++++++++++++++++++ .../libm/crates/libm-test/src/run_cfg.rs | 8 +- .../libm-test/tests/compare_built_musl.rs | 11 +- .../crates/libm-test/tests/multiprecision.rs | 11 +- .../libm/crates/libm-test/tests/standalone.rs | 38 + 6 files changed, 750 insertions(+), 5 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs create mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/standalone.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs index e0a7f5766805e..89ca09a7a0b82 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen.rs @@ -1,5 +1,6 @@ //! Different generators that can create random or systematic bit patterns. +pub mod case_list; pub mod edge_cases; pub mod random; pub mod spaced; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs new file mode 100644 index 0000000000000..9720f68e9612f --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs @@ -0,0 +1,686 @@ +//! Test cases to verify specific values. +//! +//! Each routine can have a set of inputs and, optinoally, outputs. If an output is provided, it +//! will be used to check against. If only inputs are provided, the case will be checked against +//! a basis. +//! +//! This is useful for adding regression tests or expected failures. + +use crate::{CheckBasis, CheckCtx, GeneratorKind, MathOp, op}; + +pub struct TestCase { + pub input: Op::RustArgs, + 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, 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 })); + } +} + +fn acos_cases() -> Vec> { + vec![] +} + +fn acosf_cases() -> Vec> { + vec![] +} + +fn acosh_cases() -> Vec> { + vec![] +} + +fn acoshf_cases() -> Vec> { + vec![] +} + +fn asin_cases() -> Vec> { + vec![] +} + +fn asinf_cases() -> Vec> { + vec![] +} + +fn asinh_cases() -> Vec> { + vec![] +} + +fn asinhf_cases() -> Vec> { + vec![] +} + +fn atan_cases() -> Vec> { + vec![] +} + +fn atan2_cases() -> Vec> { + vec![] +} + +fn atan2f_cases() -> Vec> { + vec![] +} + +fn atanf_cases() -> Vec> { + vec![] +} + +fn atanh_cases() -> Vec> { + vec![] +} + +fn atanhf_cases() -> Vec> { + vec![] +} + +fn cbrt_cases() -> Vec> { + vec![] +} + +fn cbrtf_cases() -> Vec> { + vec![] +} + +fn ceil_cases() -> Vec> { + vec![] +} + +fn ceilf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn ceilf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn ceilf16_cases() -> Vec> { + vec![] +} + +fn copysign_cases() -> Vec> { + vec![] +} + +fn copysignf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn copysignf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn copysignf16_cases() -> Vec> { + vec![] +} + +fn cos_cases() -> Vec> { + vec![] +} + +fn cosf_cases() -> Vec> { + vec![] +} + +fn cosh_cases() -> Vec> { + vec![] +} + +fn coshf_cases() -> Vec> { + vec![] +} + +fn erf_cases() -> Vec> { + vec![] +} + +fn erfc_cases() -> Vec> { + vec![] +} + +fn erfcf_cases() -> Vec> { + vec![] +} + +fn erff_cases() -> Vec> { + vec![] +} + +fn exp_cases() -> Vec> { + vec![] +} + +fn exp10_cases() -> Vec> { + vec![] +} + +fn exp10f_cases() -> Vec> { + vec![] +} + +fn exp2_cases() -> Vec> { + vec![] +} + +fn exp2f_cases() -> Vec> { + vec![] +} + +fn expf_cases() -> Vec> { + vec![] +} + +fn expm1_cases() -> Vec> { + vec![] +} + +fn expm1f_cases() -> Vec> { + vec![] +} + +fn fabs_cases() -> Vec> { + vec![] +} + +fn fabsf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fabsf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fabsf16_cases() -> Vec> { + vec![] +} + +fn fdim_cases() -> Vec> { + vec![] +} + +fn fdimf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fdimf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fdimf16_cases() -> Vec> { + vec![] +} + +fn floor_cases() -> Vec> { + vec![] +} + +fn floorf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn floorf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn floorf16_cases() -> Vec> { + vec![] +} + +fn fma_cases() -> Vec> { + let mut v = vec![]; + TestCase::append_pairs( + &mut v, + &[ + // Previously failure with incorrect sign + ((5e-324, -5e-324, 0.0), Some(-0.0)), + ], + ); + v +} + +fn fmaf_cases() -> Vec> { + vec![] +} + +fn fmax_cases() -> Vec> { + vec![] +} + +fn fmaxf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fmaxf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fmaxf16_cases() -> Vec> { + vec![] +} + +fn fmin_cases() -> Vec> { + vec![] +} + +fn fminf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fminf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fminf16_cases() -> Vec> { + vec![] +} + +fn fmod_cases() -> Vec> { + vec![] +} + +fn fmodf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fmodf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fmodf16_cases() -> Vec> { + vec![] +} + +fn frexp_cases() -> Vec> { + vec![] +} + +fn frexpf_cases() -> Vec> { + vec![] +} + +fn hypot_cases() -> Vec> { + vec![] +} + +fn hypotf_cases() -> Vec> { + vec![] +} + +fn ilogb_cases() -> Vec> { + vec![] +} + +fn ilogbf_cases() -> Vec> { + vec![] +} + +fn j0_cases() -> Vec> { + vec![] +} + +fn j0f_cases() -> Vec> { + vec![] +} + +fn j1_cases() -> Vec> { + vec![] +} + +fn j1f_cases() -> Vec> { + vec![] +} + +fn jn_cases() -> Vec> { + vec![] +} + +fn jnf_cases() -> Vec> { + vec![] +} + +fn ldexp_cases() -> Vec> { + vec![] +} + +fn ldexpf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn ldexpf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn ldexpf16_cases() -> Vec> { + vec![] +} + +fn lgamma_cases() -> Vec> { + vec![] +} + +fn lgamma_r_cases() -> Vec> { + vec![] +} + +fn lgammaf_cases() -> Vec> { + vec![] +} + +fn lgammaf_r_cases() -> Vec> { + vec![] +} + +fn log_cases() -> Vec> { + vec![] +} + +fn log10_cases() -> Vec> { + vec![] +} + +fn log10f_cases() -> Vec> { + vec![] +} + +fn log1p_cases() -> Vec> { + vec![] +} + +fn log1pf_cases() -> Vec> { + vec![] +} + +fn log2_cases() -> Vec> { + vec![] +} + +fn log2f_cases() -> Vec> { + vec![] +} + +fn logf_cases() -> Vec> { + vec![] +} + +fn modf_cases() -> Vec> { + vec![] +} + +fn modff_cases() -> Vec> { + vec![] +} + +fn nextafter_cases() -> Vec> { + vec![] +} + +fn nextafterf_cases() -> Vec> { + vec![] +} + +fn pow_cases() -> Vec> { + vec![] +} + +fn powf_cases() -> Vec> { + vec![] +} + +fn remainder_cases() -> Vec> { + vec![] +} + +fn remainderf_cases() -> Vec> { + vec![] +} + +fn remquo_cases() -> Vec> { + vec![] +} + +fn remquof_cases() -> Vec> { + vec![] +} + +fn rint_cases() -> Vec> { + vec![] +} + +fn rintf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn rintf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn rintf16_cases() -> Vec> { + vec![] +} + +fn round_cases() -> Vec> { + vec![] +} + +fn roundf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn roundf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn roundf16_cases() -> Vec> { + vec![] +} + +fn scalbn_cases() -> Vec> { + vec![] +} + +fn scalbnf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn scalbnf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn scalbnf16_cases() -> Vec> { + vec![] +} + +fn sin_cases() -> Vec> { + vec![] +} + +fn sincos_cases() -> Vec> { + vec![] +} + +fn sincosf_cases() -> Vec> { + vec![] +} + +fn sinf_cases() -> Vec> { + vec![] +} + +fn sinh_cases() -> Vec> { + vec![] +} + +fn sinhf_cases() -> Vec> { + vec![] +} + +fn sqrt_cases() -> Vec> { + vec![] +} + +fn sqrtf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn sqrtf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn sqrtf16_cases() -> Vec> { + vec![] +} + +fn tan_cases() -> Vec> { + vec![] +} + +fn tanf_cases() -> Vec> { + vec![] +} + +fn tanh_cases() -> Vec> { + vec![] +} + +fn tanhf_cases() -> Vec> { + vec![] +} + +fn tgamma_cases() -> Vec> { + vec![] +} + +fn tgammaf_cases() -> Vec> { + vec![] +} + +fn trunc_cases() -> Vec> { + vec![] +} + +fn truncf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn truncf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn truncf16_cases() -> Vec> { + vec![] +} + +fn y0_cases() -> Vec> { + vec![] +} + +fn y0f_cases() -> Vec> { + vec![] +} + +fn y1_cases() -> Vec> { + vec![] +} + +fn y1f_cases() -> Vec> { + vec![] +} + +fn yn_cases() -> Vec> { + vec![] +} + +fn ynf_cases() -> Vec> { + vec![] +} + +pub trait CaseListInput: MathOp + Sized { + fn get_cases() -> Vec>; +} + +macro_rules! impl_case_list { + ( + fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], + ) => { + paste::paste! { + $(#[$attr])* + impl CaseListInput for crate::op::$fn_name::Routine { + fn get_cases() -> Vec> { + [< $fn_name _cases >]() + } + } + } + }; +} + +libm_macros::for_each_function! { + callback: impl_case_list, +} + +/// This is the test generator for standalone tests, i.e. those with no basis. For this, it +/// only extracts tests with a known output. +pub fn get_test_cases_standalone( + ctx: &CheckCtx, +) -> impl Iterator + use<'_, Op> +where + Op: MathOp + CaseListInput, +{ + assert_eq!(ctx.basis, CheckBasis::None); + assert_eq!(ctx.gen_kind, GeneratorKind::List); + Op::get_cases().into_iter().filter_map(|x| x.output.map(|o| (x.input, o))) +} + +/// Opposite of the above; extract only test cases that don't have a known output, to be run +/// against a basis. +pub fn get_test_cases_basis( + ctx: &CheckCtx, +) -> (impl Iterator + use<'_, Op>, u64) +where + Op: MathOp + CaseListInput, +{ + assert_ne!(ctx.basis, CheckBasis::None); + assert_eq!(ctx.gen_kind, GeneratorKind::List); + + let cases = Op::get_cases(); + let count: u64 = cases.iter().filter(|case| case.output.is_none()).count().try_into().unwrap(); + + (cases.into_iter().filter(|x| x.output.is_none()).map(|x| x.input), count) +} diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index 783142e37836a..5728c3b2e5b04 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -102,6 +102,7 @@ pub enum GeneratorKind { Extensive, QuickSpaced, Random, + List, } /// A list of all functions that should get extensive tests. @@ -219,8 +220,8 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { GeneratorKind::QuickSpaced => domain_iter_count, GeneratorKind::Random => random_iter_count, GeneratorKind::Extensive => extensive_max_iterations(), - GeneratorKind::EdgeCases => { - unimplemented!("edge case tests shoudn't need `iteration_count`") + GeneratorKind::EdgeCases | GeneratorKind::List => { + unimplemented!("shoudn't need `iteration_count` for {:?}", ctx.gen_kind) } }; @@ -269,7 +270,7 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { GeneratorKind::Random => { format!(" using `{SEED_ENV}={}`", str::from_utf8(SEED.as_slice()).unwrap()) } - GeneratorKind::EdgeCases => unreachable!(), + GeneratorKind::EdgeCases | GeneratorKind::List => unimplemented!(), }; test_log(&format!( @@ -310,6 +311,7 @@ pub fn int_range(ctx: &CheckCtx, argnum: usize) -> RangeInclusive { GeneratorKind::Extensive => extensive_range, GeneratorKind::QuickSpaced | GeneratorKind::Random => non_extensive_range, GeneratorKind::EdgeCases => extensive_range, + GeneratorKind::List => unimplemented!("shoudn't need range for {:?}", ctx.gen_kind), } } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index c8beaffc3af21..927cb25afc476 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -9,7 +9,7 @@ // There are some targets we can't build musl for #![cfg(feature = "build-musl")] -use libm_test::gen::{edge_cases, random, spaced}; +use libm_test::gen::{case_list, edge_cases, random, spaced}; use libm_test::{CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TupleCall}; const BASIS: CheckBasis = CheckBasis::Musl; @@ -34,6 +34,15 @@ macro_rules! musl_tests { attrs: [$($attr:meta),*], ) => { paste::paste! { + #[test] + $(#[$attr])* + fn [< musl_case_list_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::List); + let cases = case_list::get_test_cases_basis::(&ctx).0; + musl_runner::(&ctx, cases, musl_math_sys::$fn_name); + } + #[test] $(#[$attr])* fn [< musl_random_ $fn_name >]() { diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 0d5c5e60c20c7..fd1f11610f52c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -2,7 +2,7 @@ #![cfg(feature = "build-mpfr")] -use libm_test::gen::{edge_cases, random, spaced}; +use libm_test::gen::{case_list, edge_cases, random, spaced}; use libm_test::mpfloat::MpOp; use libm_test::{CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TupleCall}; @@ -24,6 +24,15 @@ macro_rules! mp_tests { attrs: [$($attr:meta),*], ) => { paste::paste! { + #[test] + $(#[$attr])* + fn [< mp_case_list_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::List); + let cases = case_list::get_test_cases_basis::(&ctx).0; + mp_runner::(&ctx, cases); + } + #[test] $(#[$attr])* fn [< mp_random_ $fn_name >]() { diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/standalone.rs b/library/compiler-builtins/libm/crates/libm-test/tests/standalone.rs new file mode 100644 index 0000000000000..d6417acac2bd1 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/tests/standalone.rs @@ -0,0 +1,38 @@ +//! Test cases that have both an input and an output, so do not require a basis. + +use libm_test::gen::case_list; +use libm_test::{CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TupleCall}; + +const BASIS: CheckBasis = CheckBasis::None; + +fn standalone_runner( + ctx: &CheckCtx, + cases: impl Iterator, +) { + for (input, expected) in cases { + let crate_res = input.call(Op::ROUTINE); + crate_res.validate(expected, input, ctx).unwrap(); + } +} + +macro_rules! mp_tests { + ( + fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], + ) => { + paste::paste! { + #[test] + $(#[$attr])* + fn [< standalone_ $fn_name >]() { + type Op = libm_test::op::$fn_name::Routine; + let ctx = CheckCtx::new(Op::IDENTIFIER, BASIS, GeneratorKind::List); + let cases = case_list::get_test_cases_standalone::(&ctx); + standalone_runner::(&ctx, cases); + } + } + }; +} + +libm_macros::for_each_function! { + callback: mp_tests, +} From 7f3bd59cdf5f833f848097ecf8ccac73b8ae650c Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Sat, 1 Feb 2025 02:10:59 +0300 Subject: [PATCH 1648/4206] Expose erf{,c}{,f} from libm --- library/compiler-builtins/src/math.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index da208239e834c..21670f2434f20 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -91,6 +91,11 @@ no_mangle! { fn fmod(x: f64, y: f64) -> f64; // `f32 % f32` fn fmodf(x: f32, y: f32) -> f32; + + fn erf(x: f64) -> f64; + fn erff(x: f32) -> f32; + fn erfc(x: f64) -> f64; + fn erfcf(x: f32) -> f32; } // allow for windows (and other targets) From 84cb50e5b5e00d70679bccdc006350e5b1580996 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 6 Feb 2025 20:55:26 +0000 Subject: [PATCH 1649/4206] chore: release v0.1.146 --- library/compiler-builtins/CHANGELOG.md | 6 ++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index ddebb78231c44..d6962dc5b5e03 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.146](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.145...compiler_builtins-v0.1.146) - 2025-02-06 + +### Other + +- Expose erf{,c}{,f} from libm + ## [0.1.145](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.144...compiler_builtins-v0.1.145) - 2025-02-04 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index fcbc602382a4e..c93ca563c4e74 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.145" +version = "0.1.146" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 3aa4da2756bd5fcd3f8c7173d941bd5664b3efc7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 6 Feb 2025 23:17:27 +0000 Subject: [PATCH 1650/4206] Improve tidy output Print a better diff when lists are unsorted, and always check tidy lists even if `--check` is not passed. --- library/compiler-builtins/libm/etc/update-api-list.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/etc/update-api-list.py b/library/compiler-builtins/libm/etc/update-api-list.py index 9cf6255542233..c0b6e41d3002e 100755 --- a/library/compiler-builtins/libm/etc/update-api-list.py +++ b/library/compiler-builtins/libm/etc/update-api-list.py @@ -278,8 +278,8 @@ 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( - "".join(lines), - "".join(sorted(lines)), + "\n".join(lines), + "\n".join(sorted(lines)), f"sorted block at {relpath}:{block_start_line}", ) @@ -338,8 +338,7 @@ def ensure_updated_list(check: bool) -> None: crate.write_function_list(check) crate.write_function_defs(check) - if check: - crate.tidy_lists() + crate.tidy_lists() def main(): From bbdcc7ef899b57f6afa836f0cc4f0b7cb090c555 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 6 Feb 2025 23:18:31 +0000 Subject: [PATCH 1651/4206] Make it possible to use `hf32!` and similar macros outside of `libm` Adjust paths such that these macros don't go through the private `math` module. `feature = "private-test-deps"` is still needed. Additionally, ensure that `cargo check` for this crate gets run in CI because `cargo test` does not seem to identify this problem. `compiler_builtins` will need to reexport the `support` module. --- .../libm/.github/workflows/main.yaml | 1 + .../crates/compiler-builtins-smoke-test/src/lib.rs | 3 +++ library/compiler-builtins/libm/src/math/mod.rs | 2 +- .../libm/src/math/support/float_traits.rs | 2 +- .../libm/src/math/support/macros.rs | 12 ++++++++---- .../compiler-builtins/libm/src/math/support/mod.rs | 2 ++ 6 files changed, 16 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index e03d7ecd31910..e1d263deac1d4 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -143,6 +143,7 @@ jobs: - name: Install Rust run: rustup update nightly --no-self-update && rustup default nightly - uses: Swatinem/rust-cache@v2 + - run: cargo check --manifest-path crates/compiler-builtins-smoke-test/Cargo.toml - run: cargo test --manifest-path crates/compiler-builtins-smoke-test/Cargo.toml benchmarks: diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index ccd0642a20e38..77a4666a1023a 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -17,6 +17,9 @@ pub mod libm; use core::ffi::c_int; +// Required for macro paths. +use libm::support; + /// Mark functions `#[no_mangle]` and with the C ABI. macro_rules! no_mangle { ($( $name:ident( $($tt:tt)+ ) -> $ret:ty; )+) => { diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index f0698ad02ebaa..7ad808cf7522f 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -81,7 +81,7 @@ pub mod support; #[macro_use] #[cfg(not(feature = "unstable-public-internals"))] -mod support; +pub(crate) mod support; cfg_if! { if #[cfg(feature = "unstable-public-internals")] { 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 24cf7d4b05cde..328b706106132 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -107,7 +107,7 @@ pub trait Float: !self.is_sign_negative() } - /// Returns if `self` is subnormal + /// Returns if `self` is subnormal. fn is_subnormal(self) -> bool { (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO } diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index d8ba04cffe7f0..c80e7751159d6 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -90,10 +90,11 @@ macro_rules! select_implementation { /// Construct a 16-bit float from hex float representation (C-style), guaranteed to /// evaluate at compile time. #[cfg(f16_enabled)] +#[cfg_attr(feature = "unstable-public-internals", macro_export)] #[allow(unused_macros)] macro_rules! hf16 { ($s:literal) => {{ - const X: f16 = $crate::math::support::hf16($s); + const X: f16 = $crate::support::hf16($s); X }}; } @@ -101,9 +102,10 @@ macro_rules! hf16 { /// Construct a 32-bit float from hex float representation (C-style), guaranteed to /// evaluate at compile time. #[allow(unused_macros)] +#[cfg_attr(feature = "unstable-public-internals", macro_export)] macro_rules! hf32 { ($s:literal) => {{ - const X: f32 = $crate::math::support::hf32($s); + const X: f32 = $crate::support::hf32($s); X }}; } @@ -111,9 +113,10 @@ macro_rules! hf32 { /// Construct a 64-bit float from hex float representation (C-style), guaranteed to /// evaluate at compile time. #[allow(unused_macros)] +#[cfg_attr(feature = "unstable-public-internals", macro_export)] macro_rules! hf64 { ($s:literal) => {{ - const X: f64 = $crate::math::support::hf64($s); + const X: f64 = $crate::support::hf64($s); X }}; } @@ -122,9 +125,10 @@ macro_rules! hf64 { /// evaluate at compile time. #[cfg(f128_enabled)] #[allow(unused_macros)] +#[cfg_attr(feature = "unstable-public-internals", macro_export)] macro_rules! hf128 { ($s:literal) => {{ - const X: f128 = $crate::math::support::hf128($s); + const X: f128 = $crate::support::hf128($s); X }}; } diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index d471c5b701336..68f1e49e5c480 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -9,8 +9,10 @@ mod int_traits; pub use float_traits::{Float, IntTy}; pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; #[cfg(f16_enabled)] +#[allow(unused_imports)] pub use hex_float::hf16; #[cfg(f128_enabled)] +#[allow(unused_imports)] pub use hex_float::hf128; #[allow(unused_imports)] pub use hex_float::{Hexf, hf32, hf64}; From 9223d60dfa4c81e677c1c4d5b5ac8d8488fdbca0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 5 Feb 2025 23:45:14 +0000 Subject: [PATCH 1652/4206] Add `fmaf128` Resolve all remaining `f64`-specific items in the generic version of `fma`, then expose `fmaf128`. --- .../libm/crates/libm-macros/src/shared.rs | 7 + .../libm/crates/libm-test/benches/icount.rs | 1 + .../libm/crates/libm-test/benches/random.rs | 1 + .../crates/libm-test/src/gen/case_list.rs | 23 +- .../libm/crates/libm-test/src/mpfloat.rs | 2 +- .../libm/crates/libm-test/src/precision.rs | 2 + .../libm-test/tests/compare_built_musl.rs | 1 + .../libm/crates/util/src/main.rs | 1 + .../libm/etc/function-definitions.json | 7 + .../libm/etc/function-list.txt | 1 + .../compiler-builtins/libm/src/libm_helper.rs | 1 + .../libm/src/math/fmaf128.rs | 7 + .../libm/src/math/generic/fma.rs | 248 +++++++++++++----- .../compiler-builtins/libm/src/math/mod.rs | 2 + 14 files changed, 237 insertions(+), 67 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fmaf128.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index da16cd8e2874f..48d19c50d19a8 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -106,6 +106,13 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] None, &["fma"], ), + ( + // `(f128, f128, f128) -> f128` + FloatTy::F128, + Signature { args: &[Ty::F128, Ty::F128, Ty::F128], returns: &[Ty::F128] }, + None, + &["fmaf128"], + ), ( // `(f32) -> i32` FloatTy::F32, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index 53ecb5a37c4bd..c41cef24e54d5 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -108,6 +108,7 @@ main!( 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, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 66486a56a2a9f..6e8a334795a27 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -127,6 +127,7 @@ libm_macros::for_each_function! { | fdimf16 | floorf128 | floorf16 + | fmaf128 | fmaxf128 | fmaxf16 | fminf128 diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs index 9720f68e9612f..302d5c3918468 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs @@ -6,6 +6,9 @@ //! //! This is useful for adding regression tests or expected failures. +#[cfg(f128_enabled)] +use libm::hf128; + use crate::{CheckBasis, CheckCtx, GeneratorKind, MathOp, op}; pub struct TestCase { @@ -250,7 +253,7 @@ fn fma_cases() -> Vec> { TestCase::append_pairs( &mut v, &[ - // Previously failure with incorrect sign + // Previous failure with incorrect sign ((5e-324, -5e-324, 0.0), Some(-0.0)), ], ); @@ -261,6 +264,24 @@ fn fmaf_cases() -> Vec> { vec![] } +#[cfg(f128_enabled)] +fn fmaf128_cases() -> Vec> { + let mut v = vec![]; + TestCase::append_pairs( + &mut v, + &[( + // 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")), + )], + ); + v +} + fn fmax_cases() -> Vec> { vec![] } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index ab77d541c812d..f4a9ff7ffd5dc 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -196,7 +196,7 @@ libm_macros::for_each_function! { expm1 | expm1f => exp_m1, fabs | fabsf => abs, fdim | fdimf | fdimf16 | fdimf128 => positive_diff, - fma | fmaf => mul_add, + fma | fmaf | fmaf128 => mul_add, fmax | fmaxf | fmaxf16 | fmaxf128 => max, fmin | fminf | fminf16 | fminf128 => min, lgamma | lgammaf => ln_gamma, diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 596f91fe1efae..20aa96b6aba36 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -560,3 +560,5 @@ impl MaybeOverride<(f128, i32)> for SpecialCase {} impl MaybeOverride<(f32, f32, f32)> for SpecialCase {} impl MaybeOverride<(f64, f64, f64)> for SpecialCase {} +#[cfg(f128_enabled)] +impl MaybeOverride<(f128, f128, f128)> for SpecialCase {} diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 927cb25afc476..7fa77e832b176 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -99,6 +99,7 @@ libm_macros::for_each_function! { fdimf16, floorf128, floorf16, + fmaf128, fmaxf128, fmaxf16, fminf128, diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index e5d6f374ad85d..0f845a1c4d0da 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -96,6 +96,7 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | fdimf16 | floorf128 | floorf16 + | fmaf128 | fmaxf128 | fmaxf16 | fminf128 diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 243862075ff08..5742ed585f583 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -356,6 +356,13 @@ ], "type": "f32" }, + "fmaf128": { + "sources": [ + "src/math/fmaf128.rs", + "src/math/generic/fma.rs" + ], + "type": "f128" + }, "fmax": { "sources": [ "src/math/fmax.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index c92eaf9e23eb6..1c9c5e3bc337c 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -53,6 +53,7 @@ floorf128 floorf16 fma fmaf +fmaf128 fmax fmaxf fmaxf128 diff --git a/library/compiler-builtins/libm/src/libm_helper.rs b/library/compiler-builtins/libm/src/libm_helper.rs index 0768839c77993..68f1fb362666d 100644 --- a/library/compiler-builtins/libm/src/libm_helper.rs +++ b/library/compiler-builtins/libm/src/libm_helper.rs @@ -208,6 +208,7 @@ libm_helper! { (fn fabs(x: f128) -> (f128); => fabsf128); (fn fdim(x: f128, y: f128) -> (f128); => fdimf128); (fn floor(x: f128) -> (f128); => floorf128); + (fn fmaf128(x: f128, y: f128, z: f128) -> (f128); => fmaf128); (fn fmax(x: f128, y: f128) -> (f128); => fmaxf128); (fn fmin(x: f128, y: f128) -> (f128); => fminf128); (fn fmod(x: f128, y: f128) -> (f128); => fmodf128); diff --git a/library/compiler-builtins/libm/src/math/fmaf128.rs b/library/compiler-builtins/libm/src/math/fmaf128.rs new file mode 100644 index 0000000000000..50f7360deb45c --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmaf128.rs @@ -0,0 +1,7 @@ +/// Fused multiply add (f128) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaf128(x: f128, y: f128, z: f128) -> f128 { + return super::generic::fma(x, y, z); +} diff --git a/library/compiler-builtins/libm/src/math/generic/fma.rs b/library/compiler-builtins/libm/src/math/generic/fma.rs index b0e2117ea0988..ac53acadfe1a4 100644 --- a/library/compiler-builtins/libm/src/math/generic/fma.rs +++ b/library/compiler-builtins/libm/src/math/generic/fma.rs @@ -1,10 +1,11 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/fma.c. Ported to generic Rust algorithm in 2025, TG. */ + use core::{f32, f64}; use super::super::support::{DInt, HInt, IntTy}; use super::super::{CastFrom, CastInto, Float, Int, MinInt}; -const ZEROINFNAN: i32 = 0x7ff - 0x3ff - 52 - 1; - /// Fused multiply-add that works when there is not a larger float size available. Currently this /// is still specialized only for `f64`. Computes `(x * y) + z`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] @@ -18,79 +19,99 @@ where { let one = IntTy::::ONE; let zero = IntTy::::ZERO; - let magic = F::from_parts(false, F::BITS - 1 + F::EXP_BIAS, zero); - /* normalize so top 10bits and last bit are 0 */ + // Normalize such that the top of the mantissa is zero and we have a guard bit. let nx = Norm::from_float(x); let ny = Norm::from_float(y); let nz = Norm::from_float(z); - if nx.e >= ZEROINFNAN || ny.e >= ZEROINFNAN { + if nx.is_zero_nan_inf() || ny.is_zero_nan_inf() { + // Value will overflow, defer to non-fused operations. return x * y + z; } - if nz.e >= ZEROINFNAN { - if nz.e > ZEROINFNAN { - /* z==0 */ + + if nz.is_zero_nan_inf() { + if nz.is_zero() { + // Empty add component means we only need to multiply. return x * y; } + // `z` is NaN or infinity, which sets the result. return z; } - /* mul: r = x*y */ + // multiply: r = x * y let zhi: F::Int; let zlo: F::Int; let (mut rlo, mut rhi) = nx.m.widen_mul(ny.m).lo_hi(); - /* either top 20 or 21 bits of rhi and last 2 bits of rlo are 0 */ - - /* align exponents */ + // Exponent result of multiplication let mut e: i32 = nx.e + ny.e; + // Needed shift to align `z` to the multiplication result let mut d: i32 = nz.e - e; let sbits = F::BITS as i32; - /* shift bits z<<=kz, r>>=kr, so kz+kr == d, set e = e+kr (== ez-kz) */ + // Scale `z`. Shift `z <<= kz`, `r >>= kr`, so `kz+kr == d`, set `e = e+kr` (== ez-kz) if d > 0 { + // The magnitude of `z` is larger than `x * y` if d < sbits { + // Maximum shift of one `F::BITS` means shifted `z` will fit into `2 * F::BITS`. Shift + // it into `(zhi, zlo)`. No exponent adjustment necessary. zlo = nz.m << d; zhi = nz.m >> (sbits - d); } else { + // Shift larger than `sbits`, `z` only needs the top half `zhi`. Place it there (acts + // as a shift by `sbits`). zlo = zero; zhi = nz.m; - e = nz.e - sbits; d -= sbits; + + // `z`'s exponent is large enough that it now needs to be taken into account. + e = nz.e - sbits; + if d == 0 { + // Exactly `sbits`, nothing to do } else if d < sbits { - rlo = (rhi << (sbits - d)) - | (rlo >> d) - | IntTy::::from((rlo << (sbits - d)) != zero); + // Remaining shift fits within `sbits`. Leave `z` in place, shift `x * y` + rlo = (rhi << (sbits - d)) | (rlo >> d); + // Set the sticky bit + rlo |= IntTy::::from((rlo << (sbits - d)) != zero); rhi = rhi >> d; } else { + // `z`'s magnitude is enough that `x * y` is irrelevant. It was nonzero, so set + // the sticky bit. rlo = one; rhi = zero; } } } else { + // `z`'s magnitude once shifted fits entirely within `zlo` zhi = zero; d = -d; if d == 0 { + // No shift needed zlo = nz.m; } else if d < sbits { - zlo = (nz.m >> d) | IntTy::::from((nz.m << (sbits - d)) != zero); + // Shift s.t. `nz.m` fits into `zlo` + let sticky = IntTy::::from((nz.m << (sbits - d)) != zero); + zlo = (nz.m >> d) | sticky; } else { + // Would be entirely shifted out, only set the sticky bit zlo = one; } } - /* add */ + /* addition */ + let mut neg = nx.neg ^ ny.neg; let samesign: bool = !neg ^ nz.neg; - let mut nonzero: i32 = 1; + let mut rhi_nonzero = true; + if samesign { - /* r += z */ + // r += z rlo = rlo.wrapping_add(zlo); rhi += zhi + IntTy::::from(rlo < zlo); } else { - /* r -= z */ + // r -= z let (res, borrow) = rlo.overflowing_sub(zlo); rlo = res; rhi = rhi.wrapping_sub(zhi.wrapping_add(IntTy::::from(borrow))); @@ -99,129 +120,226 @@ where rhi = rhi.signed().wrapping_neg().unsigned() - IntTy::::from(rlo != zero); neg = !neg; } - nonzero = (rhi != zero) as i32; + rhi_nonzero = rhi != zero; } - /* set rhi to top 63bit of the result (last bit is sticky) */ - if nonzero != 0 { + /* Construct result */ + + // Shift result into `rhi`, left-aligned. Last bit is sticky + if rhi_nonzero { + // `d` > 0, need to shift both `rhi` and `rlo` into result e += sbits; d = rhi.leading_zeros() as i32 - 1; - /* note: d > 0 */ - rhi = (rhi << d) | (rlo >> (sbits - d)) | IntTy::::from((rlo << d) != zero); + rhi = (rhi << d) | (rlo >> (sbits - d)); + // Update sticky + rhi |= IntTy::::from((rlo << d) != zero); } else if rlo != zero { + // `rhi` is zero, `rlo` is the entire result and needs to be shifted d = rlo.leading_zeros() as i32 - 1; if d < 0 { + // Shift and set sticky rhi = (rlo >> 1) | (rlo & one); } else { rhi = rlo << d; } } else { - /* exact +-0 */ + // exact +/- 0.0 return x * y + z; } e -= d; - /* convert to double */ - let mut i: F::SignedInt = rhi.signed(); /* i is in [1<<62,(1<<63)-1] */ + // Use int->float conversion to populate the significand. + // i is in [1 << (BITS - 2), (1 << (BITS - 1)) - 1] + let mut i: F::SignedInt = rhi.signed(); + if neg { i = -i; } - let mut r: F = F::cast_from_lossy(i); /* |r| is in [0x1p62,0x1p63] */ + // `|r|` is in `[0x1p62,0x1p63]` for `f64` + let mut r: F = F::cast_from_lossy(i); + + /* Account for subnormal and rounding */ + + // Unbiased exponent for the maximum value of `r` + let max_pow = F::BITS - 1 + F::EXP_BIAS; - if e < -(F::EXP_BIAS as i32 - 1) - (sbits - 2) { - /* result is subnormal before rounding */ - if e == -(F::EXP_BIAS as i32 - 1) - (sbits - 1) { - let mut c: F = magic; + if e < -(max_pow as i32 - 2) { + // Result is subnormal before rounding + if e == -(max_pow as i32 - 1) { + let mut c = F::from_parts(false, max_pow, zero); if neg { c = -c; } + if r == c { - /* min normal after rounding, underflow depends - * on arch behaviour which can be imitated by - * a double to float conversion */ - return r.raise_underflow(); + // Min normal after rounding, + return r.raise_underflow_ret_self(); } - /* one bit is lost when scaled, add another top bit to - * only round once at conversion if it is inexact */ - if (rhi << F::SIG_BITS) != zero { - let iu: F::Int = (rhi >> 1) | (rhi & one) | (one << 62); + + if (rhi << (F::SIG_BITS + 1)) != zero { + // Account for truncated bits. One bit will be lost in the `scalbn` call, add + // another top bit to avoid double rounding if inexact. + let iu: F::Int = (rhi >> 1) | (rhi & one) | (one << (F::BITS - 2)); i = iu.signed(); + if neg { i = -i; } + r = F::cast_from_lossy(i); - r = F::cast_from(2i8) * r - c; /* remove top bit */ - /* raise underflow portably, such that it - * cannot be optimized away */ - r += r.raise_underflow2(); + // Remove the top bit + r = F::cast_from(2i8) * r - c; + r += r.raise_underflow_ret_zero(); } } else { - /* only round once when scaled */ - d = 10; - i = (((rhi >> d) | IntTy::::from(rhi << (F::BITS as i32 - d) != zero)) << d) - .signed(); + // Only round once when scaled + d = F::EXP_BITS as i32 - 1; + let sticky = IntTy::::from(rhi << (F::BITS as i32 - d) != zero); + i = (((rhi >> d) | sticky) << d).signed(); + if neg { i = -i; } - r = F::cast_from(i); + + r = F::cast_from_lossy(i); } } + // Use our exponent to scale the final value. super::scalbn(r, e) } /// Representation of `F` that has handled subnormals. +#[derive(Clone, Copy, Debug)] struct Norm { - /// Normalized significand with one guard bit. + /// Normalized significand with one guard bit, unsigned. m: F::Int, - /// Unbiased exponent, normalized. + /// Exponent of the mantissa such that `m * 2^e = x`. Accounts for the shift in the mantissa + /// and the guard bit; that is, 1.0 will normalize as `m = 1 << 53` and `e = -53`. e: i32, neg: bool, } impl Norm { + /// Unbias the exponent and account for the mantissa's precision, including the guard bit. + const EXP_UNBIAS: u32 = F::EXP_BIAS + F::SIG_BITS + 1; + + /// Values greater than this had a saturated exponent (infinity or NaN), OR were zero and we + /// adjusted the exponent such that it exceeds this threashold. + const ZERO_INF_NAN: u32 = F::EXP_SAT - Self::EXP_UNBIAS; + fn from_float(x: F) -> Self { let mut ix = x.to_bits(); let mut e = x.exp() as i32; let neg = x.is_sign_negative(); if e == 0 { // Normalize subnormals by multiplication - let magic = F::from_parts(false, F::BITS - 1 + F::EXP_BIAS, F::Int::ZERO); - let scaled = x * magic; + let scale_i = F::BITS - 1; + let scale_f = F::from_parts(false, scale_i + F::EXP_BIAS, F::Int::ZERO); + let scaled = x * scale_f; ix = scaled.to_bits(); e = scaled.exp() as i32; - e = if e != 0 { e - (F::BITS as i32 - 1) } else { 0x800 }; + e = if e == 0 { + // If the exponent is still zero, the input was zero. Artifically set this value + // such that the final `e` will exceed `ZERO_INF_NAN`. + 1 << F::EXP_BITS + } else { + // Otherwise, account for the scaling we just did. + e - scale_i as i32 + }; } - e -= F::EXP_BIAS as i32 + 52 + 1; + e -= Self::EXP_UNBIAS as i32; + // Absolute value, set the implicit bit, and shift to create a guard bit ix &= F::SIG_MASK; ix |= F::IMPLICIT_BIT; - ix <<= 1; // add a guard bit + ix <<= 1; Self { m: ix, e, neg } } + + /// True if the value was zero, infinity, or NaN. + fn is_zero_nan_inf(self) -> bool { + self.e >= Self::ZERO_INF_NAN as i32 + } + + /// The only value we have + fn is_zero(self) -> bool { + // The only exponent that strictly exceeds this value is our sentinel value for zero. + self.e > Self::ZERO_INF_NAN as i32 + } } /// Type-specific helpers that are not needed outside of fma. pub trait FmaHelper { - fn raise_underflow(self) -> Self; - fn raise_underflow2(self) -> Self; + fn raise_underflow_ret_self(self) -> Self; + fn raise_underflow_ret_zero(self) -> Self; } impl FmaHelper for f64 { - fn raise_underflow(self) -> Self { - let x0_ffffff8p_63 = f64::from_bits(0x3bfffffff0000000); // 0x0.ffffff8p-63 - let fltmin: f32 = (x0_ffffff8p_63 * f32::MIN_POSITIVE as f64 * self) as f32; + fn raise_underflow_ret_self(self) -> Self { + /* min normal after rounding, underflow depends + * on arch behaviour which can be imitated by + * a double to float conversion */ + let fltmin: f32 = (hf64!("0x0.ffffff8p-63") * f32::MIN_POSITIVE as f64 * self) as f32; f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * fltmin as f64 } - fn raise_underflow2(self) -> Self { + fn raise_underflow_ret_zero(self) -> Self { /* raise underflow portably, such that it * cannot be optimized away */ let tiny: f64 = f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * self; (tiny * tiny) * (self - self) } } + +#[cfg(f128_enabled)] +impl FmaHelper for f128 { + fn raise_underflow_ret_self(self) -> Self { + self + } + + fn raise_underflow_ret_zero(self) -> Self { + f128::ZERO + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn spec_test() + where + F: Float + FmaHelper, + F: CastFrom, + F: CastFrom, + F::Int: HInt, + u32: CastInto, + { + let x = F::from_bits(F::Int::ONE); + let y = F::from_bits(F::Int::ONE); + let z = F::ZERO; + + // 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result of + // fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the + // exact result" + assert_biteq!(fma(x, y, z), F::ZERO); + assert_biteq!(fma(x, -y, z), F::NEG_ZERO); + assert_biteq!(fma(-x, y, z), F::NEG_ZERO); + assert_biteq!(fma(-x, -y, z), F::ZERO); + } + + #[test] + fn spec_test_f64() { + spec_test::(); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_test_f128() { + spec_test::(); + } +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 7ad808cf7522f..677ed8d6e9316 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -385,6 +385,7 @@ cfg_if! { mod fabsf128; mod fdimf128; mod floorf128; + mod fmaf128; mod fmaxf128; mod fminf128; mod fmodf128; @@ -402,6 +403,7 @@ cfg_if! { pub use self::fabsf128::fabsf128; pub use self::fdimf128::fdimf128; pub use self::floorf128::floorf128; + pub use self::fmaf128::fmaf128; pub use self::fmaxf128::fmaxf128; pub use self::fminf128::fminf128; pub use self::fmodf128::fmodf128; From aac4901953c475ba4ab911978661c7d478b32cff Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 7 Feb 2025 00:47:00 +0000 Subject: [PATCH 1653/4206] Add better edge case testing for `scalbn` Include integer values around the minimum and maximum exponents which require different behavior in the scale functions. --- .../crates/libm-test/src/gen/edge_cases.rs | 100 ++++++++++++++---- .../libm/src/math/generic/scalbn.rs | 4 +- .../libm/src/math/support/float_traits.rs | 21 ++++ 3 files changed, 101 insertions(+), 24 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs index 8de954ae332c0..8da635114d2f2 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs @@ -1,11 +1,11 @@ //! A generator that checks a handful of cases near infinities, zeros, asymptotes, and NaNs. -use libm::support::{Float, Int}; +use libm::support::{CastInto, Float, Int}; use crate::domain::get_domain; use crate::gen::KnownSize; use crate::run_cfg::{check_near_count, check_point_count}; -use crate::{CheckCtx, FloatExt, MathOp, test_log}; +use crate::{BaseName, CheckCtx, FloatExt, FloatTy, MathOp, test_log}; /// Generate a sequence of edge cases, e.g. numbers near zeroes and infiniteis. pub trait EdgeCaseInput { @@ -78,7 +78,7 @@ where (ret.into_iter(), count) } -/// Add `AROUND` values starting at and including `x` and counting up. Uses the smallest possible +/// Add `points` values starting at and including `x` and counting up. Uses the smallest possible /// increments (1 ULP). fn count_up(mut x: F, points: u64, values: &mut Vec) { assert!(!x.is_nan()); @@ -91,7 +91,7 @@ fn count_up(mut x: F, points: u64, values: &mut Vec) { } } -/// Add `AROUND` values starting at and including `x` and counting down. Uses the smallest possible +/// Add `points` values starting at and including `x` and counting down. Uses the smallest possible /// increments (1 ULP). fn count_down(mut x: F, points: u64, values: &mut Vec) { assert!(!x.is_nan()); @@ -107,31 +107,87 @@ fn count_down(mut x: F, points: u64, values: &mut Vec) { /// Create a list of values around interesting integer points (min, zero, max). pub fn int_edge_cases( ctx: &CheckCtx, - _argnum: usize, -) -> (impl Iterator + Clone, u64) { + argnum: usize, +) -> (impl Iterator + Clone, u64) +where + i32: CastInto, +{ let mut values = Vec::new(); let near_points = check_near_count(ctx); - for up_from in [I::MIN, I::ZERO] { - let mut x = up_from; - for _ in 0..near_points { - values.push(x); - x += I::ONE; - } - } - - for down_from in [I::ZERO, I::MAX] { - let mut x = down_from; - for _ in 0..near_points { - values.push(x); - x -= I::ONE; - } + // Check around max/min and zero + int_count_around(I::MIN, near_points, &mut values); + int_count_around(I::MAX, near_points, &mut values); + int_count_around(I::ZERO, near_points, &mut values); + int_count_around(I::ZERO, near_points, &mut values); + + 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 => { + #[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 => { + #[cfg(not(f128_enabled))] + unreachable!(); + #[cfg(f128_enabled)] + (f128::EXP_MAX, f128::EXP_MIN, f128::EXP_MIN_SUBNORM) + } + }; + + // `scalbn`/`ldexp` have their trickiest behavior around exponent limits + int_count_around(emax.cast(), near_points, &mut values); + int_count_around(emin.cast(), near_points, &mut values); + int_count_around(emin_sn.cast(), near_points, &mut values); + int_count_around((-emin_sn).cast(), near_points, &mut values); + + // Also check values that cause the maximum possible difference in exponents + int_count_around((emax - emin).cast(), near_points, &mut values); + int_count_around((emin - emax).cast(), near_points, &mut values); + int_count_around((emax - emin_sn).cast(), near_points, &mut values); + int_count_around((emin_sn - emax).cast(), near_points, &mut values); } values.sort(); values.dedup(); - let len = values.len().try_into().unwrap(); - (values.into_iter(), len) + let count = values.len().try_into().unwrap(); + + test_log(&format!( + "{gen_kind:?} {basis:?} {fn_ident} arg {arg}/{args}: {count} edge cases", + gen_kind = ctx.gen_kind, + basis = ctx.basis, + fn_ident = ctx.fn_ident, + arg = argnum + 1, + args = ctx.input_count(), + )); + + (values.into_iter(), count) +} + +/// Add `points` values both up and down, starting at and including `x`. +fn int_count_around(x: I, points: u64, values: &mut Vec) { + let mut current = x; + for _ in 0..points { + values.push(current); + current = match current.checked_add(I::ONE) { + Some(v) => v, + None => break, + }; + } + + current = x; + for _ in 0..points { + values.push(current); + current = match current.checked_sub(I::ONE) { + Some(v) => v, + None => break, + }; + } } macro_rules! impl_edge_case_input { diff --git a/library/compiler-builtins/libm/src/math/generic/scalbn.rs b/library/compiler-builtins/libm/src/math/generic/scalbn.rs index f15cb75d63123..5ba7f2ab2d5f5 100644 --- a/library/compiler-builtins/libm/src/math/generic/scalbn.rs +++ b/library/compiler-builtins/libm/src/math/generic/scalbn.rs @@ -28,8 +28,8 @@ where let sig_total_bits = F::SIG_BITS + 1; // Maximum and minimum values when biased - let exp_max: i32 = F::EXP_BIAS as i32; - let exp_min = -(exp_max - 1); + let exp_max = F::EXP_MAX; + let exp_min = F::EXP_MIN; // 2 ^ Emax, maximum positive with null significand (0x1p1023 for f64) let f_exp_max = F::from_parts(false, F::EXP_BIAS << 1, zero); 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 328b706106132..d6ce13f690733 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -59,6 +59,15 @@ pub trait Float: /// The exponent bias value const EXP_BIAS: u32 = Self::EXP_SAT >> 1; + /// Maximum unbiased exponent value. + const EXP_MAX: i32 = Self::EXP_BIAS as i32; + + /// Minimum *NORMAL* unbiased exponent value. + const EXP_MIN: i32 = -(Self::EXP_MAX - 1); + + /// Minimum subnormal exponent value. + const EXP_MIN_SUBNORM: i32 = Self::EXP_MIN - Self::SIG_BITS as i32; + /// A mask for the sign bit const SIGN_MASK: Self::Int; @@ -274,6 +283,9 @@ mod tests { // Constants assert_eq!(f16::EXP_SAT, 0b11111); assert_eq!(f16::EXP_BIAS, 15); + assert_eq!(f16::EXP_MAX, 15); + assert_eq!(f16::EXP_MIN, -14); + assert_eq!(f16::EXP_MIN_SUBNORM, -24); // `exp_unbiased` assert_eq!(f16::FRAC_PI_2.exp_unbiased(), 0); @@ -296,6 +308,9 @@ mod tests { // Constants assert_eq!(f32::EXP_SAT, 0b11111111); assert_eq!(f32::EXP_BIAS, 127); + assert_eq!(f32::EXP_MAX, 127); + assert_eq!(f32::EXP_MIN, -126); + assert_eq!(f32::EXP_MIN_SUBNORM, -149); // `exp_unbiased` assert_eq!(f32::FRAC_PI_2.exp_unbiased(), 0); @@ -319,6 +334,9 @@ mod tests { // Constants assert_eq!(f64::EXP_SAT, 0b11111111111); assert_eq!(f64::EXP_BIAS, 1023); + assert_eq!(f64::EXP_MAX, 1023); + assert_eq!(f64::EXP_MIN, -1022); + assert_eq!(f64::EXP_MIN_SUBNORM, -1074); // `exp_unbiased` assert_eq!(f64::FRAC_PI_2.exp_unbiased(), 0); @@ -343,6 +361,9 @@ mod tests { // Constants assert_eq!(f128::EXP_SAT, 0b111111111111111); assert_eq!(f128::EXP_BIAS, 16383); + assert_eq!(f128::EXP_MAX, 16383); + assert_eq!(f128::EXP_MIN, -16382); + assert_eq!(f128::EXP_MIN_SUBNORM, -16494); // `exp_unbiased` assert_eq!(f128::FRAC_PI_2.exp_unbiased(), 0); From 69ebd750ccacd44fab4407501d568abd1e0801c1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 7 Feb 2025 01:23:19 +0000 Subject: [PATCH 1654/4206] Run standard tests before running integration tests To ensure we don't waste time running extensive tests when there is an easily identifiable failure, run the normal test suite for relevant functions before starting extensive tests. --- library/compiler-builtins/libm/.github/workflows/main.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index e1d263deac1d4..de131639b5656 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -273,6 +273,9 @@ jobs: exit fi + # Run the non-extensive tests first to catch any easy failures + cargo t --profile release-checked -- "$CHANGED" + LIBM_EXTENSIVE_TESTS="$CHANGED" cargo t \ --features build-mpfr,unstable,force-soft-floats \ --profile release-checked \ From f028611faf62a9b87430ff782ab0bb91d5c63a8f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 7 Feb 2025 01:05:38 +0000 Subject: [PATCH 1655/4206] Check more subnormal values during edge cases tests Add checks at the max subnormal value and a couple values scatted throughout the subnormal range. This helped identifiy a bug in `fmaf128`. As part of this, slightly reduce the amount of edge cases checked without optimizations because the change makes it become noticible. --- .../crates/libm-test/src/gen/edge_cases.rs | 20 ++++++++++++++++++- .../libm/crates/libm-test/src/run_cfg.rs | 2 +- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs index 8da635114d2f2..69b59a1056741 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs @@ -1,9 +1,10 @@ //! A generator that checks a handful of cases near infinities, zeros, asymptotes, and NaNs. -use libm::support::{CastInto, Float, Int}; +use libm::support::{CastInto, Float, Int, MinInt}; use crate::domain::get_domain; use crate::gen::KnownSize; +use crate::op::OpITy; use crate::run_cfg::{check_near_count, check_point_count}; use crate::{BaseName, CheckCtx, FloatExt, FloatTy, MathOp, test_log}; @@ -21,6 +22,7 @@ where Op: MathOp, { let mut ret = Vec::new(); + let one = OpITy::::ONE; let values = &mut ret; let domain = get_domain::<_, i8>(ctx.fn_ident, argnum).unwrap_float(); let domain_start = domain.range_start(); @@ -51,6 +53,22 @@ where values.push(Op::FTy::NAN); values.extend(Op::FTy::consts().iter()); + // Check around the maximum subnormal value + let sub_max = Op::FTy::from_bits(Op::FTy::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); + count_up(v, 2, values); + count_down(v, 2, values); + count_up(-v, 2, values); + count_down(-v, 2, values); + } + // Check around asymptotes if let Some(f) = domain.check_points { let iter = f(); diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index 5728c3b2e5b04..4dd43bdf3868c 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -342,7 +342,7 @@ pub fn check_near_count(ctx: &CheckCtx) -> u64 { x => panic!("unexpected argument count {x}"), } } else { - 10 + 8 } } From d35a44352750cc74f0ba49e3a0bd47d5310d90a5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 7 Feb 2025 00:52:56 +0000 Subject: [PATCH 1656/4206] fmaf128: fix exponent calculation for subnormals When `fmaf128` was introduced in [1], it included a bug where `self` gets returned rather than the expected minimum positive value. Resolve this and add a regression test. [1]: https://github.com/rust-lang/libm/pull/494 --- .../crates/libm-test/src/gen/case_list.rs | 25 +++++++++++++------ .../libm/src/math/generic/fma.rs | 13 ++++++---- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs index 302d5c3918468..23226d5c25101 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs @@ -269,15 +269,26 @@ fn fmaf128_cases() -> Vec> { let mut v = vec![]; TestCase::append_pairs( &mut v, - &[( - // 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"), + // Subnormal edge case that caused a failure + ( + hf128!("0x0.7ffffffffffffffffffffffffff7p-16382"), + hf128!("0x1.ffffffffffffffffffffffffffffp-1"), + hf128!("0x0.8000000000000000000000000009p-16382"), + ), + Some(hf128!("0x1.0000000000000000000000000000p-16382")), ), - Some(hf128!("0x0.c5171470a3ff5e0f68d751491b18p-16382")), - )], + ], ); v } diff --git a/library/compiler-builtins/libm/src/math/generic/fma.rs b/library/compiler-builtins/libm/src/math/generic/fma.rs index ac53acadfe1a4..4c6f1fad681da 100644 --- a/library/compiler-builtins/libm/src/math/generic/fma.rs +++ b/library/compiler-builtins/libm/src/math/generic/fma.rs @@ -146,6 +146,7 @@ where // exact +/- 0.0 return x * y + z; } + e -= d; // Use int->float conversion to populate the significand. @@ -174,7 +175,7 @@ where if r == c { // Min normal after rounding, - return r.raise_underflow_ret_self(); + return r.raise_underflow_as_min_positive(); } if (rhi << (F::SIG_BITS + 1)) != zero { @@ -275,12 +276,14 @@ impl Norm { /// Type-specific helpers that are not needed outside of fma. pub trait FmaHelper { - fn raise_underflow_ret_self(self) -> Self; + /// Raise underflow and return the minimum positive normal value with the sign of `self`. + fn raise_underflow_as_min_positive(self) -> Self; + /// Raise underflow and return zero. fn raise_underflow_ret_zero(self) -> Self; } impl FmaHelper for f64 { - fn raise_underflow_ret_self(self) -> Self { + fn raise_underflow_as_min_positive(self) -> Self { /* min normal after rounding, underflow depends * on arch behaviour which can be imitated by * a double to float conversion */ @@ -298,8 +301,8 @@ impl FmaHelper for f64 { #[cfg(f128_enabled)] impl FmaHelper for f128 { - fn raise_underflow_ret_self(self) -> Self { - self + fn raise_underflow_as_min_positive(self) -> Self { + f128::MIN_POSITIVE.copysign(self) } fn raise_underflow_ret_zero(self) -> Self { From 3e2de21344f2179016c6d04aaeb0668c21abaa52 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 7 Feb 2025 02:36:58 +0000 Subject: [PATCH 1657/4206] Remove or reduce the scope of `allow(unused)` where possible Now that we have more in this crate making use of traits, try to be more specific about what is actually unused. --- .../libm/crates/libm-macros/tests/basic.rs | 13 +++---------- .../libm/src/math/support/big.rs | 11 +++++------ .../libm/src/math/support/float_traits.rs | 17 ++++++++++------- .../libm/src/math/support/int_traits.rs | 7 ++----- .../libm/src/math/support/mod.rs | 1 - 5 files changed, 20 insertions(+), 29 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs b/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs index 0aa417f13c82c..5314e84bbb0a1 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs @@ -18,20 +18,14 @@ macro_rules! basic { fn_extra: $fn_extra:expr, ) => { $(#[$attr])* - mod $fn_name { - #[allow(unused)] + #[allow(dead_code)] + pub mod $fn_name { type FTy= $FTy; - #[allow(unused)] type CFnTy<'a> = $CFn; - #[allow(unused)] type RustFnTy = $RustFn; - #[allow(unused)] type RustArgsTy = $RustArgs; - #[allow(unused)] type RustRetTy = $RustRet; - #[allow(unused)] const A: &[&str] = &[$($extra_tt)*]; - #[allow(unused)] fn foo(a: f32) -> f32 { $fn_extra(a) } @@ -92,10 +86,9 @@ macro_rules! specified_types { attrs: [$($attr:meta),*], ) => { $(#[$attr])* + #[allow(dead_code)] mod $fn_name { - #[allow(unused)] type RustFnTy = $RustFn; - #[allow(unused)] type RustArgsTy = $RustArgs; } }; diff --git a/library/compiler-builtins/libm/src/math/support/big.rs b/library/compiler-builtins/libm/src/math/support/big.rs index e0f5e52634efb..bf47d20010480 100644 --- a/library/compiler-builtins/libm/src/math/support/big.rs +++ b/library/compiler-builtins/libm/src/math/support/big.rs @@ -1,11 +1,9 @@ //! Integers used for wide operations, larger than `u128`. -#![allow(unused)] - #[cfg(test)] mod tests; -use core::{fmt, ops}; +use core::ops; use super::{DInt, HInt, Int, MinInt}; @@ -13,7 +11,6 @@ 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. /// @@ -23,6 +20,7 @@ const U128_HI_MASK: u128 = (u64::MAX as u128) << 64; pub struct u256(pub [u64; 4]); impl u256 { + #[cfg(test)] pub const MAX: Self = Self([u64::MAX, u64::MAX, u64::MAX, u64::MAX]); /// Reinterpret as a signed integer @@ -40,6 +38,7 @@ pub struct i256(pub [u64; 4]); impl i256 { /// Reinterpret as an unsigned integer + #[cfg(test)] pub fn unsigned(self) -> u256 { u256(self.0) } @@ -96,7 +95,7 @@ macro_rules! impl_common { impl ops::Shl for $ty { type Output = Self; - fn shl(self, rhs: u32) -> Self::Output { + fn shl(self, _rhs: u32) -> Self::Output { unimplemented!("only used to meet trait bounds") } } @@ -256,7 +255,7 @@ impl HInt for i128 { self.unsigned().zero_widen_mul(rhs.unsigned()).signed() } - fn widen_mul(self, rhs: Self) -> Self::D { + fn widen_mul(self, _rhs: Self) -> Self::D { unimplemented!("signed i128 widening multiply is not used") } 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 d6ce13f690733..3b27f8de50a93 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -3,7 +3,7 @@ use core::{fmt, mem, ops}; use super::int_traits::{CastFrom, Int, MinInt}; /// Trait for some basic operations on floats -#[allow(dead_code)] +// #[allow(dead_code)] pub trait Float: Copy + fmt::Debug @@ -84,11 +84,13 @@ pub trait Float: fn to_bits(self) -> Self::Int; /// Returns `self` transmuted to `Self::SignedInt` + #[allow(dead_code)] fn to_bits_signed(self) -> Self::SignedInt { self.to_bits().signed() } /// Check bitwise equality. + #[allow(dead_code)] fn biteq(self, rhs: Self) -> bool { self.to_bits() == rhs.to_bits() } @@ -98,6 +100,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) } } @@ -117,6 +120,7 @@ pub trait Float: } /// Returns if `self` is subnormal. + #[allow(dead_code)] fn is_subnormal(self) -> bool { (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO } @@ -132,15 +136,11 @@ pub trait Float: } /// Returns the significand with no implicit bit (or the "fractional" part) + #[allow(dead_code)] fn frac(self) -> Self::Int { self.to_bits() & Self::SIG_MASK } - /// Returns the significand with implicit bit. - fn imp_frac(self) -> Self::Int { - self.frac() | Self::IMPLICIT_BIT - } - /// Returns a `Self::Int` transmuted back to `Self` fn from_bits(a: Self::Int) -> Self; @@ -154,22 +154,25 @@ pub trait Float: ) } + #[allow(dead_code)] fn abs(self) -> Self; /// Returns a number composed of the magnitude of self and the sign of sign. + #[allow(dead_code)] fn copysign(self, other: Self) -> Self; /// Returns (normalized exponent, normalized significand) + #[allow(dead_code)] fn normalize(significand: Self::Int) -> (i32, Self::Int); /// Returns a number that represents the sign of self. + #[allow(dead_code)] fn signum(self) -> Self { if self.is_nan() { self } else { Self::ONE.copysign(self) } } } /// Access the associated `Int` type from a float (helper to avoid ambiguous associated types). -#[allow(dead_code)] pub type IntTy = ::Int; macro_rules! float_impl { 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 793a0f3069f90..d34797764a0ef 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -1,7 +1,6 @@ use core::{cmp, fmt, ops}; /// Minimal integer implementations needed on all integer types, including wide integers. -#[allow(dead_code)] pub trait MinInt: Copy + fmt::Debug @@ -261,7 +260,6 @@ int_impl!(i128, u128); /// 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. -#[allow(unused)] pub trait DInt: MinInt { /// Integer that is half the bit width of the integer this trait is implemented for type H: HInt; @@ -275,6 +273,7 @@ pub trait DInt: MinInt { (self.lo(), self.hi()) } /// Constructs an integer using lower and higher half parts + #[allow(unused)] fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { lo.zero_widen() | hi.widen_hi() } @@ -282,7 +281,6 @@ pub trait DInt: MinInt { /// 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. -#[allow(unused)] pub trait HInt: Int { /// Integer that is double the bit width of the integer this trait is implemented for type D: DInt + MinInt; @@ -297,6 +295,7 @@ pub trait HInt: Int { /// 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 + #[allow(unused)] fn widen_hi(self) -> Self::D; /// Widening multiplication with zero widening. This cannot overflow. fn zero_widen_mul(self, rhs: Self) -> Self::D; @@ -360,7 +359,6 @@ impl_h_int!( ); /// Trait to express (possibly lossy) casting of integers -#[allow(unused)] pub trait CastInto: Copy { /// By default, casts should be exact. fn cast(self) -> T; @@ -369,7 +367,6 @@ pub trait CastInto: Copy { fn cast_lossy(self) -> T; } -#[allow(unused)] pub trait CastFrom: Copy { /// By default, casts should be exact. fn cast_from(value: T) -> Self; diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index 68f1e49e5c480..d3c932b977169 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -5,7 +5,6 @@ mod float_traits; pub mod hex_float; mod int_traits; -#[allow(unused_imports)] pub use float_traits::{Float, IntTy}; pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; #[cfg(f16_enabled)] From aa4ae487d457b51e32081638b6603d1c75300d55 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 7 Feb 2025 03:41:05 +0000 Subject: [PATCH 1658/4206] Convert `fmaf` to a generic implementation Introduce a version of generic `fma` that works when there is a larger hardware-backed float type available to compute the result with more precision. This is currently used only for `f32`, but with some minor adjustments it should work for `f16` as well. --- .../compiler-builtins/libm/src/math/fmaf.rs | 96 +------------------ .../libm/src/math/generic/fma.rs | 67 ++++++++++++- .../libm/src/math/generic/mod.rs | 2 +- .../compiler-builtins/libm/src/math/mod.rs | 2 +- .../libm/src/math/support/float_traits.rs | 58 +++++++++++ .../libm/src/math/support/mod.rs | 3 +- 6 files changed, 129 insertions(+), 99 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/fmaf.rs b/library/compiler-builtins/libm/src/math/fmaf.rs index 79371c836c8ff..40d7f40d61738 100644 --- a/library/compiler-builtins/libm/src/math/fmaf.rs +++ b/library/compiler-builtins/libm/src/math/fmaf.rs @@ -1,103 +1,11 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_fmaf.c */ -/*- - * Copyright (c) 2005-2011 David Schultz - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -use core::f32; -use core::ptr::read_volatile; - -use super::fenv::{ - FE_INEXACT, FE_TONEAREST, FE_UNDERFLOW, feclearexcept, fegetround, feraiseexcept, fetestexcept, -}; - -/* - * Fused multiply-add: Compute x * y + z with a single rounding error. - * - * A double has more than twice as much precision than a float, so - * direct double-precision arithmetic suffices, except where double - * rounding occurs. - */ - /// Floating multiply add (f32) /// /// Computes `(x*y)+z`, rounded as one ternary operation: /// Computes the value (as if) to infinite precision and rounds once to the result format, /// according to the rounding mode characterized by the value of FLT_ROUNDS. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 { - let xy: f64; - let mut result: f64; - let mut ui: u64; - let e: i32; - - xy = x as f64 * y as f64; - result = xy + z as f64; - ui = result.to_bits(); - e = (ui >> 52) as i32 & 0x7ff; - /* Common case: The double precision result is fine. */ - if ( - /* not a halfway case */ - ui & 0x1fffffff) != 0x10000000 || - /* NaN */ - e == 0x7ff || - /* exact */ - (result - xy == z as f64 && result - z as f64 == xy) || - /* not round-to-nearest */ - fegetround() != FE_TONEAREST - { - /* - underflow may not be raised correctly, example: - fmaf(0x1p-120f, 0x1p-120f, 0x1p-149f) - */ - if ((0x3ff - 149)..(0x3ff - 126)).contains(&e) && fetestexcept(FE_INEXACT) != 0 { - feclearexcept(FE_INEXACT); - // prevent `xy + vz` from being CSE'd with `xy + z` above - let vz: f32 = unsafe { read_volatile(&z) }; - result = xy + vz as f64; - if fetestexcept(FE_INEXACT) != 0 { - feraiseexcept(FE_UNDERFLOW); - } else { - feraiseexcept(FE_INEXACT); - } - } - z = result as f32; - return z; - } - - /* - * If result is inexact, and exactly halfway between two float values, - * we need to adjust the low-order bit in the direction of the error. - */ - let neg = ui >> 63 != 0; - let err = if neg == (z as f64 > xy) { xy - result + z as f64 } else { z as f64 - result + xy }; - if neg == (err < 0.0) { - ui += 1; - } else { - ui -= 1; - } - f64::from_bits(ui) as f32 +pub fn fmaf(x: f32, y: f32, z: f32) -> f32 { + super::generic::fma_wide(x, y, z) } #[cfg(test)] diff --git a/library/compiler-builtins/libm/src/math/generic/fma.rs b/library/compiler-builtins/libm/src/math/generic/fma.rs index 4c6f1fad681da..a40d7aaaf5e0c 100644 --- a/library/compiler-builtins/libm/src/math/generic/fma.rs +++ b/library/compiler-builtins/libm/src/math/generic/fma.rs @@ -1,10 +1,13 @@ /* SPDX-License-Identifier: MIT */ -/* origin: musl src/math/fma.c. Ported to generic Rust algorithm in 2025, TG. */ +/* origin: musl src/math/{fma,fmaf}.c. Ported to generic Rust algorithm in 2025, TG. */ use core::{f32, f64}; +use super::super::fenv::{ + FE_INEXACT, FE_TONEAREST, FE_UNDERFLOW, feclearexcept, fegetround, feraiseexcept, fetestexcept, +}; use super::super::support::{DInt, HInt, IntTy}; -use super::super::{CastFrom, CastInto, Float, Int, MinInt}; +use super::super::{CastFrom, CastInto, DFloat, Float, HFloat, Int, MinInt}; /// Fused multiply-add that works when there is not a larger float size available. Currently this /// is still specialized only for `f64`. Computes `(x * y) + z`. @@ -212,6 +215,66 @@ where super::scalbn(r, e) } +/// Fma implementation when a hardware-backed larger float type is available. For `f32` and `f64`, +/// `f64` has enough precision to represent the `f32` in its entirety, except for double rounding. +pub fn fma_wide(x: F, y: F, z: F) -> F +where + F: Float + HFloat, + B: Float + DFloat, + B::Int: CastInto, + i32: CastFrom, +{ + let one = IntTy::::ONE; + + let xy: B = x.widen() * y.widen(); + let mut result: B = xy + z.widen(); + let mut ui: B::Int = result.to_bits(); + let re = result.exp(); + let zb: B = z.widen(); + + let prec_diff = B::SIG_BITS - F::SIG_BITS; + let excess_prec = ui & ((one << prec_diff) - one); + let halfway = one << (prec_diff - 1); + + // Common case: the larger precision is fine if... + // This is not a halfway case + if excess_prec != halfway + // Or the result is NaN + || re == B::EXP_SAT + // Or the result is exact + || (result - xy == zb && result - zb == xy) + // Or the mode is something other than round to nearest + || fegetround() != FE_TONEAREST + { + let min_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN_SUBNORM) as u32; + let max_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN) as u32; + + if (min_inexact_exp..max_inexact_exp).contains(&re) && fetestexcept(FE_INEXACT) != 0 { + feclearexcept(FE_INEXACT); + // prevent `xy + vz` from being CSE'd with `xy + z` above + let vz: F = force_eval!(z); + result = xy + vz.widen(); + if fetestexcept(FE_INEXACT) != 0 { + feraiseexcept(FE_UNDERFLOW); + } else { + feraiseexcept(FE_INEXACT); + } + } + + return result.narrow(); + } + + let neg = ui >> (B::BITS - 1) != IntTy::::ZERO; + let err = if neg == (zb > xy) { xy - result + zb } else { zb - result + xy }; + if neg == (err < B::ZERO) { + ui += one; + } else { + ui -= one; + } + + B::from_bits(ui).narrow() +} + /// Representation of `F` that has handled subnormals. #[derive(Clone, Copy, Debug)] struct Norm { diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index e19cc83a9acc3..b34d3dfae945c 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -18,7 +18,7 @@ pub use copysign::copysign; pub use fabs::fabs; pub use fdim::fdim; pub use floor::floor; -pub use fma::fma; +pub use fma::{fma, fma_wide}; pub use fmax::fmax; pub use fmin::fmin; pub use fmod::fmod; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 677ed8d6e9316..e32045021dae5 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -121,7 +121,7 @@ use self::rem_pio2::rem_pio2; use self::rem_pio2_large::rem_pio2_large; use self::rem_pio2f::rem_pio2f; #[allow(unused_imports)] -use self::support::{CastFrom, CastInto, DInt, Float, HInt, Int, IntTy, MinInt}; +use self::support::{CastFrom, CastInto, DFloat, DInt, Float, HFloat, HInt, Int, IntTy, MinInt}; // Public modules mod acos; 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 3b27f8de50a93..ee83c793da32a 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -276,6 +276,64 @@ pub const fn f64_from_bits(bits: u64) -> f64 { unsafe { mem::transmute::(bits) } } +/// Trait for floats twice the bit width of another integer. +pub trait DFloat: Float { + /// Float that is half the bit width of the floatthis trait is implemented for. + type H: HFloat; + + /// Narrow the float type. + fn narrow(self) -> Self::H; +} + +/// Trait for floats half the bit width of another float. +pub trait HFloat: Float { + /// Float that is double the bit width of the float this trait is implemented for. + type D: DFloat; + + /// Widen the float type. + fn widen(self) -> Self::D; +} + +macro_rules! impl_d_float { + ($($X:ident $D:ident),*) => { + $( + impl DFloat for $D { + type H = $X; + + fn narrow(self) -> Self::H { + self as $X + } + } + )* + }; +} + +macro_rules! impl_h_float { + ($($H:ident $X:ident),*) => { + $( + impl HFloat for $H { + type D = $X; + + fn widen(self) -> Self::D { + self as $X + } + } + )* + }; +} + +impl_d_float!(f32 f64); +#[cfg(f16_enabled)] +impl_d_float!(f16 f32); +#[cfg(f128_enabled)] +impl_d_float!(f64 f128); + +impl_h_float!(f32 f64); +#[cfg(f16_enabled)] +impl_h_float!(f16 f32); +#[cfg(f128_enabled)] +impl_h_float!(f64 f128); + #[cfg(test)] mod tests { use super::*; diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index d3c932b977169..9eebd4403719d 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -5,7 +5,8 @@ mod float_traits; pub mod hex_float; mod int_traits; -pub use float_traits::{Float, IntTy}; +#[allow(unused_imports)] +pub use float_traits::{DFloat, Float, HFloat, IntTy}; pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; #[cfg(f16_enabled)] #[allow(unused_imports)] From 9169216f4126833868c5f15b034ae3d77ce7b3ac Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 7 Feb 2025 21:25:03 +0000 Subject: [PATCH 1659/4206] Uncomment some hex float tests that should work now --- .../libm/src/math/support/hex_float.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 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 ebc4f7c64fabe..99ad8bec3770b 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -1,7 +1,5 @@ //! Utilities for working with hex float formats. -#![allow(dead_code)] // FIXME: remove once this gets used - use core::fmt; use super::{Float, f32_from_bits, f64_from_bits}; @@ -13,6 +11,7 @@ pub const fn hf16(s: &str) -> f16 { } /// Construct a 32-bit float from hex float representation (C-style) +#[allow(unused)] pub const fn hf32(s: &str) -> f32 { f32_from_bits(parse_any(s, 32, 23) as u32) } @@ -548,14 +547,12 @@ mod parse_tests { #[test] fn test_macros() { - // FIXME(msrv): enable once parsing works - // #[cfg(f16_enabled)] - // assert_eq!(hf16!("0x1.ffp+8").to_bits(), 0x5ffc_u16); + #[cfg(f16_enabled)] + assert_eq!(hf16!("0x1.ffp+8").to_bits(), 0x5ffc_u16); assert_eq!(hf32!("0x1.ffep+8").to_bits(), 0x43fff000_u32); assert_eq!(hf64!("0x1.ffep+8").to_bits(), 0x407ffe0000000000_u64); - // FIXME(msrv): enable once parsing works - // #[cfg(f128_enabled)] - // assert_eq!(hf128!("0x1.ffep+8").to_bits(), 0x4007ffe0000000000000000000000000_u128); + #[cfg(f128_enabled)] + assert_eq!(hf128!("0x1.ffep+8").to_bits(), 0x4007ffe0000000000000000000000000_u128); } } From f45cc66e8e4b09ee447e3519e7d8e85f06a00001 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 7 Feb 2025 22:28:19 +0000 Subject: [PATCH 1660/4206] Work arouind iai-callgrind apt failures Usually `cargo binstall iai-callgrind-runner` handles apt dependencies. However, the following has been happening: Err:11 mirror+file:/etc/apt/apt-mirrors.txt noble-updates/main amd64 libc6-dbg amd64 2.39-0ubuntu8.3 404 Not Found [IP: 40.81.13.82 80] E: Failed to fetch mirror+file:/etc/apt/apt-mirrors.txt/pool/main/g/glibc/libc6-dbg_2.39-0ubuntu8.3_amd64.deb 404 Not Found [IP: 40.81.13.82 80] Fetched 19.8 MB in 6s (3138 kB/s) E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing? Installing the dependencies manually seems to resolve the issue. --- library/compiler-builtins/libm/.github/workflows/main.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index de131639b5656..265702965ebe0 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -158,6 +158,8 @@ jobs: - name: Set up dependencies run: | + sudo apt update + sudo apt install -y valgrind gdb libc6-dbg # Needed for iai-callgrind rustup update "$BENCHMARK_RUSTC" --no-self-update rustup default "$BENCHMARK_RUSTC" # Install the version of iai-callgrind-runner that is specified in Cargo.toml From f1afc26b8a7691808f6be04493798620fe90e5fb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 25 Jan 2025 00:29:04 +0000 Subject: [PATCH 1661/4206] Add an enum representation of rounding mode We only round using nearest, but some incoming code has more handling of rounding modes that would be nice to `match` on. Rather than checking integer values, add an enum representation. --- .../compiler-builtins/libm/src/math/fenv.rs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/fenv.rs b/library/compiler-builtins/libm/src/math/fenv.rs index c91272e826852..328c9f3467c6a 100644 --- a/library/compiler-builtins/libm/src/math/fenv.rs +++ b/library/compiler-builtins/libm/src/math/fenv.rs @@ -5,6 +5,9 @@ pub(crate) const FE_UNDERFLOW: i32 = 0; pub(crate) const FE_INEXACT: i32 = 0; pub(crate) const FE_TONEAREST: i32 = 0; +pub(crate) const FE_DOWNWARD: i32 = 1; +pub(crate) const FE_UPWARD: i32 = 2; +pub(crate) const FE_TOWARDZERO: i32 = 3; #[inline] pub(crate) fn feclearexcept(_mask: i32) -> i32 { @@ -25,3 +28,22 @@ pub(crate) fn fetestexcept(_mask: i32) -> i32 { pub(crate) fn fegetround() -> i32 { FE_TONEAREST } + +#[derive(Clone, Copy, Debug, PartialEq)] +pub(crate) enum Rounding { + Nearest = FE_TONEAREST as isize, + Downward = FE_DOWNWARD as isize, + Upward = FE_UPWARD as isize, + ToZero = FE_TOWARDZERO as isize, +} + +impl Rounding { + pub(crate) fn get() -> Self { + match fegetround() { + x if x == FE_DOWNWARD => Self::Downward, + x if x == FE_UPWARD => Self::Upward, + x if x == FE_TOWARDZERO => Self::ToZero, + _ => Self::Nearest, + } + } +} From 2fa2b10ba4e0e5b89c9c17056459151129ee8cb1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 25 Oct 2024 03:56:09 -0500 Subject: [PATCH 1662/4206] Port the CORE-MATH version of `cbrt` Replace our current implementation with one that is correctly rounded. Source: https://gitlab.inria.fr/core-math/core-math/-/blob/81d447bb1c46592291bec3476bc24fa2c2688c67/src/binary64/cbrt/cbrt.c --- .../compiler-builtins/libm/src/math/cbrt.rs | 319 ++++++++++++------ 1 file changed, 216 insertions(+), 103 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/cbrt.rs b/library/compiler-builtins/libm/src/math/cbrt.rs index b4e77eaa27c82..fbf81f77d2e3f 100644 --- a/library/compiler-builtins/libm/src/math/cbrt.rs +++ b/library/compiler-builtins/libm/src/math/cbrt.rs @@ -1,113 +1,226 @@ -/* 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. +/* SPDX-License-Identifier: MIT */ +/* origin: core-math/src/binary64/cbrt/cbrt.c + * Copyright (c) 2021-2022 Alexei Sibidanov. + * Ported to Rust in 2025 by Trevor Gross. */ -/* 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 */ +use super::Float; +use super::fenv::Rounding; +use super::support::cold_path; -/* |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. +/// Compute the cube root of the argument. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cbrt(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; + const ESCALE: [f64; 3] = [ + 1.0, + hf64!("0x1.428a2f98d728bp+0"), /* 2^(1/3) */ + hf64!("0x1.965fea53d6e3dp+0"), /* 2^(2/3) */ + ]; + + /* the polynomial c0+c1*x+c2*x^2+c3*x^3 approximates x^(1/3) on [1,2] + with maximal error < 9.2e-5 (attained at x=2) */ + const C: [f64; 4] = [ + hf64!("0x1.1b0babccfef9cp-1"), + hf64!("0x1.2c9a3e94d1da5p-1"), + hf64!("-0x1.4dc30b1a1ddbap-3"), + hf64!("0x1.7a8d3e4ec9b07p-6"), + ]; + + let u0: f64 = hf64!("0x1.5555555555555p-2"); + let u1: f64 = hf64!("0x1.c71c71c71c71cp-3"); + + let rsc = [1.0, -1.0, 0.5, -0.5, 0.25, -0.25]; + + let off = [hf64!("0x1p-53"), 0.0, 0.0, 0.0]; + + let rm = Rounding::get(); + + /* rm=0 for rounding to nearest, and other values for directed roundings */ + let hx: u64 = x.to_bits(); + let mut mant: u64 = hx & f64::SIG_MASK; + let sign: u64 = hx >> 63; + + let mut e: u32 = (hx >> f64::SIG_BITS) as u32 & f64::EXP_SAT; + + if ((e + 1) & f64::EXP_SAT) < 2 { + cold_path(); + + let ix: u64 = hx & !f64::SIGN_MASK; + + /* 0, inf, nan: we return x + x instead of simply x, + to that for x a signaling NaN, it correctly triggers + the invalid exception. */ + if e == f64::EXP_SAT || ix == 0 { + return x + x; + } + + let nz = ix.leading_zeros() - 11; /* subnormal */ + mant <<= nz; + mant &= f64::SIG_MASK; + e = e.wrapping_sub(nz - 1); + } + + e = e.wrapping_add(3072); + let cvt1: u64 = mant | (0x3ffu64 << 52); + let mut cvt5: u64 = cvt1; + + let et: u32 = e / 3; + let it: u32 = e % 3; + + /* 2^(3k+it) <= x < 2^(3k+it+1), with 0 <= it <= 3 */ + cvt5 += u64::from(it) << f64::SIG_BITS; + cvt5 |= sign << 63; + let zz: f64 = f64::from_bits(cvt5); + + /* cbrt(x) = cbrt(zz)*2^(et-1365) where 1 <= zz < 8 */ + let mut isc: u64 = ESCALE[it as usize].to_bits(); // todo: index + isc |= sign << 63; + let cvt2: u64 = isc; + let z: f64 = f64::from_bits(cvt1); + + /* cbrt(zz) = cbrt(z)*isc, where isc encodes 1, 2^(1/3) or 2^(2/3), + and 1 <= z < 2 */ + let r: f64 = 1.0 / z; + let rr: f64 = r * rsc[((it as usize) << 1) | sign as usize]; + let z2: f64 = z * z; + let c0: f64 = C[0] + z * C[1]; + let c2: f64 = C[2] + z * C[3]; + let mut y: f64 = c0 + z2 * c2; + let mut y2: f64 = y * y; + + /* y is an approximation of z^(1/3) */ + let mut h: f64 = y2 * (y * r) - 1.0; + + /* h determines the error between y and z^(1/3) */ + y -= (h * y) * (u0 - u1 * h); + + /* The correction y -= (h*y)*(u0 - u1*h) corresponds to a cubic variant + of Newton's method, with the function f(y) = 1-z/y^3. */ + y *= f64::from_bits(cvt2); + + /* Now y is an approximation of zz^(1/3), + * and rr an approximation of 1/zz. We now perform another iteration of + * Newton-Raphson, this time with a linear approximation only. */ + y2 = y * y; + let mut y2l: f64 = fmaf64(y, y, -y2); + + /* y2 + y2l = y^2 exactly */ + let mut y3: f64 = y2 * y; + let mut y3l: f64 = fmaf64(y, y2, -y3) + y * y2l; + + /* y3 + y3l approximates y^3 with about 106 bits of accuracy */ + h = ((y3 - zz) + y3l) * rr; + let mut dy: f64 = h * (y * u0); + + /* the approximation of zz^(1/3) is y - dy */ + let mut y1: f64 = y - dy; + dy = (y - y1) - dy; + + /* the approximation of zz^(1/3) is now y1 + dy, where |dy| < 1/2 ulp(y) + * (for rounding to nearest) */ + let mut ady: f64 = dy.abs(); + + /* For directed roundings, ady0 is tiny when dy is tiny, or ady0 is near + * from ulp(1); + * for rounding to nearest, ady0 is tiny when dy is near from 1/2 ulp(1), + * or from 3/2 ulp(1). */ + let mut ady0: f64 = (ady - off[rm as usize]).abs(); + let mut ady1: f64 = (ady - (hf64!("0x1p-52") + off[rm as usize])).abs(); + + if ady0 < hf64!("0x1p-75") || ady1 < hf64!("0x1p-75") { + cold_path(); + + y2 = y1 * y1; + y2l = fmaf64(y1, y1, -y2); + y3 = y2 * y1; + y3l = fmaf64(y1, y2, -y3) + y1 * y2l; + h = ((y3 - zz) + y3l) * rr; + dy = h * (y1 * u0); + y = y1 - dy; + dy = (y1 - y) - dy; + y1 = y; + ady = dy.abs(); + ady0 = (ady - off[rm as usize]).abs(); + ady1 = (ady - (hf64!("0x1p-52") + off[rm as usize])).abs(); + + if ady0 < hf64!("0x1p-98") || ady1 < hf64!("0x1p-98") { + cold_path(); + let azz: f64 = zz.abs(); + + // ~ 0x1.79d15d0e8d59b80000000000000ffc3dp+0 + if azz == hf64!("0x1.9b78223aa307cp+1") { + y1 = hf64!("0x1.79d15d0e8d59cp+0").copysign(zz); + } + + // ~ 0x1.de87aa837820e80000000000001c0f08p+0 + if azz == hf64!("0x1.a202bfc89ddffp+2") { + y1 = hf64!("0x1.de87aa837820fp+0").copysign(zz); + } + + if rm != Rounding::Nearest { + let wlist = [ + (hf64!("0x1.3a9ccd7f022dbp+0"), hf64!("0x1.1236160ba9b93p+0")), // ~ 0x1.1236160ba9b930000000000001e7e8fap+0 + (hf64!("0x1.7845d2faac6fep+0"), hf64!("0x1.23115e657e49cp+0")), // ~ 0x1.23115e657e49c0000000000001d7a799p+0 + (hf64!("0x1.d1ef81cbbbe71p+0"), hf64!("0x1.388fb44cdcf5ap+0")), // ~ 0x1.388fb44cdcf5a0000000000002202c55p+0 + (hf64!("0x1.0a2014f62987cp+1"), hf64!("0x1.46bcbf47dc1e8p+0")), // ~ 0x1.46bcbf47dc1e8000000000000303aa2dp+0 + (hf64!("0x1.fe18a044a5501p+1"), hf64!("0x1.95decfec9c904p+0")), // ~ 0x1.95decfec9c9040000000000000159e8ep+0 + (hf64!("0x1.a6bb8c803147bp+2"), hf64!("0x1.e05335a6401dep+0")), // ~ 0x1.e05335a6401de00000000000027ca017p+0 + (hf64!("0x1.ac8538a031cbdp+2"), hf64!("0x1.e281d87098de8p+0")), // ~ 0x1.e281d87098de80000000000000ee9314p+0 + ]; + + for (a, b) in wlist { + if azz == a { + let tmp = if rm as u64 + sign == 2 { hf64!("0x1p-52") } else { 0.0 }; + y1 = (b + tmp).copysign(zz); + } + } + } + } + } + + let mut cvt3: u64 = y1.to_bits(); + cvt3 = cvt3.wrapping_add(((et.wrapping_sub(342).wrapping_sub(1023)) as u64) << 52); + let m0: u64 = cvt3 << 30; + let m1 = m0 >> 63; + + if (m0 ^ m1) <= (1u64 << 30) { + cold_path(); + + let mut cvt4: u64 = y1.to_bits(); + cvt4 = (cvt4 + (164 << 15)) & 0xffffffffffff0000u64; + + if ((f64::from_bits(cvt4) - y1) - dy).abs() < hf64!("0x1p-60") || (zz).abs() == 1.0 { + cvt3 = (cvt3 + (1u64 << 15)) & 0xffffffffffff0000u64; + } } - /* - * 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 */ + f64::from_bits(cvt3) +} + +fn fmaf64(x: f64, y: f64, z: f64) -> f64 { + #[cfg(intrinsics_enabled)] + { + return unsafe { core::intrinsics::fmaf64(x, y, z) }; + } + + #[cfg(not(intrinsics_enabled))] + { + return super::fma(x, y, z); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn spot_checks() { + if !cfg!(x86_no_sse) { + // Exposes a rounding mode problem. Ignored on i586 because of inaccurate FMA. + assert_biteq!( + cbrt(f64::from_bits(0xf7f792b28f600000)), + f64::from_bits(0xd29ce68655d962f3) + ); } - 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 } From 35c201c37f06f086d327de7a007e3bc97257351b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 25 Jan 2025 00:31:49 +0000 Subject: [PATCH 1663/4206] Decrease the allowed error for `cbrt` With the correctly rounded implementation, we can reduce the ULP requirement for `cbrt` to zero. There is still an override required for `i586` because of the imprecise FMA. --- .../compiler-builtins/libm/crates/libm-test/src/precision.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 20aa96b6aba36..a859965395c92 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -41,7 +41,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { | Bn::Trunc => 0, // Operations that aren't required to be exact, but our implementations are. - Bn::Cbrt if ctx.fn_ident != Id::Cbrt => 0, + Bn::Cbrt => 0, // Bessel functions have large inaccuracies. Bn::J0 | Bn::J1 | Bn::Y0 | Bn::Y1 | Bn::Jn | Bn::Yn => 8_000_000, @@ -54,7 +54,6 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { Bn::Atan => 1, Bn::Atan2 => 2, Bn::Atanh => 2, - Bn::Cbrt => 1, Bn::Cos => 1, Bn::Cosh => 1, Bn::Erf => 1, @@ -92,6 +91,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { } match ctx.fn_ident { + Id::Cbrt => ulp = 2, // FIXME(#401): musl has an incorrect result here. Id::Fdim => ulp = 2, Id::Sincosf => ulp = 500, @@ -119,6 +119,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { Id::Asinh => ulp = 3, Id::Asinhf => ulp = 3, + Id::Cbrt => ulp = 1, Id::Exp10 | Id::Exp10f => ulp = 1_000_000, Id::Exp2 | Id::Exp2f => ulp = 10_000_000, Id::Log1p | Id::Log1pf => ulp = 2, From 0a43f24a30c4952eb6b990051b6b37800b79da26 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 8 Feb 2025 07:06:59 +0000 Subject: [PATCH 1664/4206] Add simple icount benchmarks for `u256` operations --- .../libm/crates/libm-test/benches/icount.rs | 101 ++++++++++++++++++ .../libm/src/math/support/big.rs | 2 +- .../libm/src/math/support/mod.rs | 2 + 3 files changed, 104 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index c41cef24e54d5..232a3de38aa2d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -1,8 +1,10 @@ //! Benchmarks that use `iai-cachegrind` to be reasonably CI-stable. use std::hint::black_box; +use std::ops::Shr; use iai_callgrind::{library_benchmark, library_benchmark_group, main}; +use libm::support::{HInt, u256}; use libm_test::gen::spaced; use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, OpRustArgs, TupleCall, op}; @@ -51,8 +53,107 @@ libm_macros::for_each_function! { callback: icount_benches, } +fn setup_u128_mul() -> Vec<(u128, u128)> { + let step = u128::MAX / 300; + let mut x = 0u128; + let mut y = 0u128; + let mut v = Vec::new(); + + loop { + 'inner: loop { + match y.checked_add(step) { + Some(new) => y = new, + None => break 'inner, + } + + v.push((x, y)) + } + + match x.checked_add(step) { + Some(new) => x = new, + None => break, + } + } + + v +} + +/* +fn setup_u256_add() -> Vec<(u256, u256)> { + let mut v = Vec::new(); + for (x, y) in setup_u128_mul() { + // square the u128 inputs to cover most of the u256 range + v.push((x.widen_mul(x), y.widen_mul(y))); + } + // Doesn't get covered by `u128:MAX^2` + v.push((u256::MAX, u256::MAX)); + v +} +*/ + +fn setup_u256_shift() -> Vec<(u256, u32)> { + let mut v = Vec::new(); + + for (x, _) in setup_u128_mul() { + let x2 = x.widen_mul(x); + for y in 0u32..256 { + v.push((x2, y)); + } + } + + v +} + +#[library_benchmark] +#[bench::linspace(setup_u128_mul())] +fn icount_bench_u128_widen_mul(cases: Vec<(u128, u128)>) { + let f = black_box(u128::zero_widen_mul); + for (x, y) in cases.iter().copied() { + f(x, y); + } +} + +library_benchmark_group!( + name = icount_bench_u128_widen_mul_group; + benchmarks = icount_bench_u128_widen_mul +); + +/* Not yet implemented +#[library_benchmark] +#[bench::linspace(setup_u256_add())] +fn icount_bench_u256_add(cases: Vec<(u256, u256)>) { + let f = black_box(u256::add); + for (x, y) in cases.iter().copied() { + f(x, y); + } +} + +library_benchmark_group!( + name = icount_bench_u256_add_group; + benchmarks = icount_bench_u256_add +); +*/ + +#[library_benchmark] +#[bench::linspace(setup_u256_shift())] +fn icount_bench_u256_shr(cases: Vec<(u256, u32)>) { + let f = black_box(u256::shr); + for (x, y) in cases.iter().copied() { + f(x, y); + } +} + +library_benchmark_group!( + name = icount_bench_u256_shr_group; + benchmarks = icount_bench_u256_shr +); + main!( library_benchmark_groups = + // u256-related benchmarks + icount_bench_u128_widen_mul_group, + // icount_bench_u256_add_group, + icount_bench_u256_shr_group, // verify-apilist-start // verify-sorted-start icount_bench_acos_group, diff --git a/library/compiler-builtins/libm/src/math/support/big.rs b/library/compiler-builtins/libm/src/math/support/big.rs index bf47d20010480..7a437b67ac4db 100644 --- a/library/compiler-builtins/libm/src/math/support/big.rs +++ b/library/compiler-builtins/libm/src/math/support/big.rs @@ -20,7 +20,7 @@ const U128_LO_MASK: u128 = u64::MAX as u128; pub struct u256(pub [u64; 4]); impl u256 { - #[cfg(test)] + #[allow(unused)] pub const MAX: Self = Self([u64::MAX, u64::MAX, u64::MAX, u64::MAX]); /// Reinterpret as a signed integer diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index 9eebd4403719d..28e9fd4132f42 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -5,6 +5,8 @@ mod float_traits; pub mod hex_float; mod int_traits; +#[allow(unused_imports)] +pub use big::{i256, u256}; #[allow(unused_imports)] pub use float_traits::{DFloat, Float, HFloat, IntTy}; pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; From 900b61f363e88aae7a1292e480c36a6cd8fcf3b9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 8 Feb 2025 09:39:05 +0000 Subject: [PATCH 1665/4206] Change how operators are `black_box`ed For some reason, the upcoming limb changes in [1] seem to ignore the black boxing when applied to the operator function. Changing to instead black box the inputs appears to fix this. [1]: https://github.com/rust-lang/libm/pull/503 --- .../libm/crates/libm-test/benches/icount.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index 232a3de38aa2d..9fac52e0b852e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -1,7 +1,6 @@ //! Benchmarks that use `iai-cachegrind` to be reasonably CI-stable. use std::hint::black_box; -use std::ops::Shr; use iai_callgrind::{library_benchmark, library_benchmark_group, main}; use libm::support::{HInt, u256}; @@ -107,9 +106,8 @@ fn setup_u256_shift() -> Vec<(u256, u32)> { #[library_benchmark] #[bench::linspace(setup_u128_mul())] fn icount_bench_u128_widen_mul(cases: Vec<(u128, u128)>) { - let f = black_box(u128::zero_widen_mul); for (x, y) in cases.iter().copied() { - f(x, y); + black_box(black_box(x).zero_widen_mul(black_box(y))); } } @@ -122,9 +120,8 @@ library_benchmark_group!( #[library_benchmark] #[bench::linspace(setup_u256_add())] fn icount_bench_u256_add(cases: Vec<(u256, u256)>) { - let f = black_box(u256::add); for (x, y) in cases.iter().copied() { - f(x, y); + black_box(black_box(x) + black_box(y)); } } @@ -137,9 +134,8 @@ library_benchmark_group!( #[library_benchmark] #[bench::linspace(setup_u256_shift())] fn icount_bench_u256_shr(cases: Vec<(u256, u32)>) { - let f = black_box(u256::shr); for (x, y) in cases.iter().copied() { - f(x, y); + black_box(black_box(x) >> black_box(y)); } } From 017f1035f12c2b7740bdbd0b27203f45c9777338 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 8 Feb 2025 09:48:14 +0000 Subject: [PATCH 1666/4206] Replace an `assert!` with `debug_assert!` in `u256::shr` The implementation came from the `compiler_builtins` port but this should be weakened to match other integer types. --- .../libm/src/math/support/big.rs | 5 ++++- .../libm/src/math/support/big/tests.rs | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/support/big.rs b/library/compiler-builtins/libm/src/math/support/big.rs index 7a437b67ac4db..017e9455e406e 100644 --- a/library/compiler-builtins/libm/src/math/support/big.rs +++ b/library/compiler-builtins/libm/src/math/support/big.rs @@ -109,7 +109,10 @@ 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"); + debug_assert!(rhs < Self::BITS, "attempted to shift right with overflow"); + if rhs >= Self::BITS { + return Self::ZERO; + } if rhs == 0 { return self; 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 f95f829731613..815a62dfee84e 100644 --- a/library/compiler-builtins/libm/src/math/support/big/tests.rs +++ b/library/compiler-builtins/libm/src/math/support/big/tests.rs @@ -108,3 +108,22 @@ fn shr_u128() { } assert!(errors.is_empty()); } + +#[test] +#[should_panic] +#[cfg(debug_assertions)] +// FIXME(ppc): ppc64le seems to have issues with `should_panic` tests. +#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] +fn shr_u256_overflow() { + // Like regular shr, panic on overflow with debug assertions + let _ = u256::MAX >> 256; +} + +#[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); +} From 1efdc9697400d19948d178f2d1db8f181f1ad836 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 10 Feb 2025 02:05:41 +0000 Subject: [PATCH 1667/4206] Increase the tolerance for `jn` and `yn` These still fail random tests, e.g.: called `Result::unwrap()` on an `Err` value: jn Caused by: 0: input: (1068, -16013.98381387313) as hex: (, -0x1.f46fded9ced39p+13) as bits: (0x0000042c, 0xc0cf46fded9ced39) expected: 6.7603314308122506e-6 0x1.c5ad9c102d413p-18 0x3edc5ad9c102d413 actual: 6.7603314308006335e-6 0x1.c5ad9c1029e80p-18 0x3edc5ad9c1029e80 1: ulp 13715 > 4000 Caused by: 0: input: (195, 42147.94) as hex: (, 0x1.4947e2p+15) as bits: (0x000000c3, 0x4724a3f1) expected: -2.13669e-7 -0x1.cad9c6p-23 0xb4656ce3 actual: -2.1376937e-7 -0x1.cb10f4p-23 0xb465887a 1: ulp 7063 > 4000 Caused by: 0: input: (194, 740.1916) as hex: (, 0x1.721886p+9) as bits: (0x000000c2, 0x44390c43) expected: 1.212096e-6 0x1.455e9ap-20 0x35a2af4d actual: 1.2172386e-6 0x1.46c000p-20 0x35a36000 1: ulp 45235 > 10000 Increase allowed precision to avoid spurious failures. --- .../libm/crates/libm-test/src/precision.rs | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index a859965395c92..2f55ad22ec760 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -523,18 +523,7 @@ fn int_float_common( && actual == F2::ZERO && expected == F2::ZERO { - return XFAIL("mpfr b"); - } - - // Our bessel functions blow up with large N values - if ctx.basis == Musl && (ctx.base_name == BaseName::Jn || ctx.base_name == BaseName::Yn) { - if input.0 > 4000 { - return XFAIL_NOCHECK; - } else if input.0 > 2000 { - return CheckAction::AssertWithUlp(20_000); - } else if input.0 > 1000 { - return CheckAction::AssertWithUlp(4_000); - } + return XFAIL("we disagree with MPFR on the sign of zero"); } // Values near infinity sometimes get cut off for us. `ynf(681, 509.90924) = -inf` but should @@ -549,6 +538,19 @@ fn int_float_common( return XFAIL_NOCHECK; } + // Our bessel functions blow up with large N values + if ctx.basis == Musl && (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 { + return XFAIL_NOCHECK; + } else if input.0 > 100 { + return CheckAction::AssertWithUlp(1_000_000); + } + } DEFAULT } From b7fdce0505cf015d4f983064adf2b6a31d52db69 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 9 Feb 2025 22:40:20 +0000 Subject: [PATCH 1668/4206] ci: Pin the nightly toolchain for i686-pc-windows-gnu Pin i686-pc-windows-gnu to nightly-2025-02-07 until [1] is resolved. [1]: https://github.com/rust-lang/rust/issues/136795 --- library/compiler-builtins/libm/.github/workflows/main.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index 265702965ebe0..f066f4a8c1f85 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -68,7 +68,8 @@ jobs: os: windows-2025 - target: i686-pc-windows-gnu os: windows-2025 - channel: nightly-i686-gnu + # FIXME: pinned due to https://github.com/rust-lang/rust/issues/136795 + channel: nightly-2025-02-07-i686-gnu - target: x86_64-pc-windows-gnu os: windows-2025 channel: nightly-x86_64-gnu From 2f0685a9a2a72248b10cd70ca9d013c0ab9bf286 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 8 Feb 2025 04:09:59 +0000 Subject: [PATCH 1669/4206] Implement `u256` with two `u128`s rather than `u64` This produces better assembly, e.g. on aarch64: .globl libm::u128_wmul .p2align 2 libm::u128_wmul: Lfunc_begin124: .cfi_startproc mul x9, x2, x0 umulh x10, x2, x0 umulh x11, x3, x0 mul x12, x3, x0 umulh x13, x2, x1 mul x14, x2, x1 umulh x15, x3, x1 mul x16, x3, x1 adds x10, x10, x14 cinc x13, x13, hs adds x13, x13, x16 cinc x14, x15, hs adds x10, x10, x12 cinc x11, x11, hs adds x11, x13, x11 stp x9, x10, [x8] cinc x9, x14, hs stp x11, x9, [x8, rust-lang/libm#16] ret The original was ~70 instructions so the improvement is significant. With these changes, the result is reasonably close to what LLVM generates using `u256` operands [1]. [1]: https://llvm.godbolt.org/z/re1aGdaqY --- .../libm/crates/libm-test/benches/icount.rs | 6 +- .../libm/crates/libm-test/src/gen/random.rs | 2 +- .../libm/crates/libm-test/src/lib.rs | 5 +- .../libm/crates/libm-test/src/run_cfg.rs | 30 ++- .../libm/crates/libm-test/tests/u256.rs | 147 ++++++++++++ .../libm/src/math/support/big.rs | 217 ++++++------------ .../libm/src/math/support/big/tests.rs | 79 ++++--- 7 files changed, 298 insertions(+), 188 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-test/tests/u256.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index 9fac52e0b852e..be85dd5676c2f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -77,7 +77,6 @@ fn setup_u128_mul() -> Vec<(u128, u128)> { v } -/* fn setup_u256_add() -> Vec<(u256, u256)> { let mut v = Vec::new(); for (x, y) in setup_u128_mul() { @@ -88,7 +87,6 @@ fn setup_u256_add() -> Vec<(u256, u256)> { v.push((u256::MAX, u256::MAX)); v } -*/ fn setup_u256_shift() -> Vec<(u256, u32)> { let mut v = Vec::new(); @@ -116,7 +114,6 @@ library_benchmark_group!( benchmarks = icount_bench_u128_widen_mul ); -/* Not yet implemented #[library_benchmark] #[bench::linspace(setup_u256_add())] fn icount_bench_u256_add(cases: Vec<(u256, u256)>) { @@ -129,7 +126,6 @@ library_benchmark_group!( name = icount_bench_u256_add_group; benchmarks = icount_bench_u256_add ); -*/ #[library_benchmark] #[bench::linspace(setup_u256_shift())] @@ -148,7 +144,7 @@ main!( library_benchmark_groups = // u256-related benchmarks icount_bench_u128_widen_mul_group, - // icount_bench_u256_add_group, + icount_bench_u256_add_group, icount_bench_u256_shr_group, // verify-apilist-start // verify-sorted-start diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index 5b127f38d09f4..c2cd172d1ee47 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -14,7 +14,7 @@ use crate::run_cfg::{int_range, iteration_count}; pub(crate) const SEED_ENV: &str = "LIBM_SEED"; -pub(crate) static SEED: LazyLock<[u8; 32]> = LazyLock::new(|| { +pub static SEED: LazyLock<[u8; 32]> = LazyLock::new(|| { let s = env::var(SEED_ENV).unwrap_or_else(|_| { let mut rng = rand::thread_rng(); (0..32).map(|_| rng.sample(Alphanumeric) as char).collect() diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index d2fef2325059c..824f09a33873d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -29,7 +29,10 @@ pub use op::{ }; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; use run_cfg::extensive_max_iterations; -pub use run_cfg::{CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind, skip_extensive_test}; +pub use run_cfg::{ + CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind, bigint_fuzz_iteration_count, + skip_extensive_test, +}; pub use test_traits::{CheckOutput, Hex, TupleCall}; /// Result type for tests is usually from `anyhow`. Most times there is no success value to diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index 4dd43bdf3868c..6b268997666ac 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -158,14 +158,6 @@ impl TestEnv { let op = id.math_op(); let will_run_mp = cfg!(feature = "build-mpfr"); - - // Tests are pretty slow on non-64-bit targets, x86 MacOS, and targets that run in QEMU. Start - // with a reduced number on these platforms. - let slow_on_ci = crate::emulated() - || usize::BITS < 64 - || cfg!(all(target_arch = "x86_64", target_vendor = "apple")); - let slow_platform = slow_on_ci && crate::ci(); - let large_float_ty = match op.float_ty { FloatTy::F16 | FloatTy::F32 => false, FloatTy::F64 | FloatTy::F128 => true, @@ -176,7 +168,7 @@ impl TestEnv { let input_count = op.rust_sig.args.len(); Self { - slow_platform, + slow_platform: slow_platform(), large_float_ty, should_run_extensive: will_run_extensive, mp_tests_enabled: will_run_mp, @@ -185,6 +177,17 @@ impl TestEnv { } } +/// Tests are pretty slow on non-64-bit targets, x86 MacOS, and targets that run in QEMU. Start +/// with a reduced number on these platforms. +fn slow_platform() -> bool { + let slow_on_ci = crate::emulated() + || usize::BITS < 64 + || cfg!(all(target_arch = "x86_64", target_vendor = "apple")); + + // If not running in CI, there is no need to reduce iteration count. + slow_on_ci && crate::ci() +} + /// The number of iterations to run for a given test. pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { let t_env = TestEnv::from_env(ctx); @@ -351,3 +354,12 @@ pub fn skip_extensive_test(ctx: &CheckCtx) -> bool { let t_env = TestEnv::from_env(ctx); !t_env.should_run_extensive } + +/// The number of iterations to run for `u256` fuzz tests. +pub fn bigint_fuzz_iteration_count() -> u64 { + if !cfg!(optimizations_enabled) { + return 1000; + } + + if slow_platform() { 100_000 } else { 5_000_000 } +} diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs b/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs new file mode 100644 index 0000000000000..4174820c05b44 --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs @@ -0,0 +1,147 @@ +//! Test the u256 implementation. the ops already get exercised reasonably well through the `f128` +//! routines, so this only does a few million fuzz iterations against GMP. + +#![cfg(feature = "build-mpfr")] + +use std::sync::LazyLock; + +use libm::support::{HInt, u256}; +type BigInt = rug::Integer; + +use libm_test::bigint_fuzz_iteration_count; +use libm_test::gen::random::SEED; +use rand::{Rng, SeedableRng}; +use rand_chacha::ChaCha8Rng; +use rug::Assign; +use rug::integer::Order; +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.gen(); + let hi: u128 = rng.gen(); + u256 { lo, hi } +} + +fn assign_bigint(bx: &mut BigInt, x: u256) { + bx.assign_digits(&[x.lo, x.hi], Order::Lsf); +} + +fn from_bigint(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); + u256 { lo: bres[0], hi: bres[1] } +} + +fn check_one( + x: impl FnOnce() -> String, + y: impl FnOnce() -> Option, + 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: {}\ + ", + hexu(actual), + hexu(expected), + ) + } +} + +#[test] +fn mp_u256_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_u256(&mut rng); + let y = random_u256(&mut rng); + assign_bigint(&mut bx, x); + assign_bigint(&mut by, y); + let actual = x | y; + bx |= &by; + check_one(|| hexu(x), || Some(hexu(y)), actual, &mut bx); + } +} + +#[test] +fn mp_u256_not() { + 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(&mut bx, x); + let actual = !x; + bx.not_assign(); + check_one(|| hexu(x), || None, actual, &mut bx); + } +} + +#[test] +fn mp_u256_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_u256(&mut rng); + let y = random_u256(&mut rng); + assign_bigint(&mut bx, x); + assign_bigint(&mut by, y); + let actual = x + y; + bx += &by; + check_one(|| hexu(x), || Some(hexu(y)), actual, &mut bx); + } +} + +#[test] +fn mp_u256_shr() { + 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); + let shift: u32 = rng.gen_range(0..255); + assign_bigint(&mut bx, x); + let actual = x >> shift; + bx >>= shift; + check_one(|| hexu(x), || Some(shift.to_string()), actual, &mut bx); + } +} + +#[test] +fn mp_u256_widen_mul() { + 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: u128 = rng.gen(); + let y: u128 = rng.gen(); + bx.assign(x); + by.assign(y); + let actual = x.widen_mul(y); + bx *= &by; + check_one(|| format!("{x:#034x}"), || Some(format!("{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 017e9455e406e..eae08238e0997 100644 --- a/library/compiler-builtins/libm/src/math/support/big.rs +++ b/library/compiler-builtins/libm/src/math/support/big.rs @@ -7,40 +7,39 @@ use core::ops; use super::{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; -/// 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. +/// A 256-bit unsigned integer represented as two 128-bit native-endian limbs. #[allow(non_camel_case_types)] #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] -pub struct u256(pub [u64; 4]); +pub struct u256 { + pub lo: u128, + pub hi: u128, +} impl u256 { - #[allow(unused)] - pub const MAX: Self = Self([u64::MAX, u64::MAX, u64::MAX, u64::MAX]); + #[cfg(any(test, feature = "unstable-public-internals"))] + pub const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX }; /// Reinterpret as a signed integer pub fn signed(self) -> i256 { - i256(self.0) + i256 { lo: self.lo, hi: self.hi } } } -/// 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. +/// A 256-bit signed integer represented as two 128-bit native-endian limbs. #[allow(non_camel_case_types)] #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] -pub struct i256(pub [u64; 4]); +pub struct i256 { + pub lo: u128, + pub hi: u128, +} impl i256 { /// Reinterpret as an unsigned integer - #[cfg(test)] + #[cfg(any(test, feature = "unstable-public-internals"))] pub fn unsigned(self) -> u256 { - u256(self.0) + u256 { lo: self.lo, hi: self.hi } } } @@ -51,10 +50,10 @@ impl MinInt for 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]); + 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 }; } impl MinInt for i256 { @@ -64,10 +63,10 @@ impl MinInt for i256 { 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]); + const ZERO: Self = Self { lo: 0, hi: 0 }; + const ONE: Self = Self { lo: 1, hi: 0 }; + const MIN: Self = Self { lo: 0, hi: 1 << 127 }; + const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX << 1 }; } macro_rules! impl_common { @@ -76,10 +75,8 @@ macro_rules! impl_common { 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.lo |= rhs.lo; + self.hi |= rhs.hi; self } } @@ -87,8 +84,10 @@ macro_rules! impl_common { 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]]) + fn not(mut self) -> Self::Output { + self.lo = !self.lo; + self.hi = !self.hi; + self } } @@ -105,10 +104,21 @@ macro_rules! impl_common { impl_common!(i256); impl_common!(u256); +impl ops::Add for u256 { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + let (lo, carry) = self.lo.overflowing_add(rhs.lo); + let hi = self.hi.wrapping_add(carry as u128).wrapping_add(rhs.hi); + + Self { lo, hi } + } +} + impl ops::Shr for u256 { type Output = Self; - fn shr(self, rhs: u32) -> Self::Output { + fn shr(mut self, rhs: u32) -> Self::Output { debug_assert!(rhs < Self::BITS, "attempted to shift right with overflow"); if rhs >= Self::BITS { return Self::ZERO; @@ -118,57 +128,28 @@ impl ops::Shr for u256 { 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; - - // FIXME(msrv): could be let...else. - let base = match ret.0.get(base_idx) { - Some(v) => v, - None => { - 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; - } + if rhs < 128 { + self.lo >>= rhs; + self.lo |= self.hi << (128 - rhs); + } else { + self.lo = self.hi >> (rhs - 128); + } - ret.0[idx] = new_val; + if rhs < 128 { + self.hi >>= rhs; + } else { + self.hi = 0; } - ret + self } } -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]) + u256 { lo: self, hi: 0 } } fn zero_widen(self) -> Self::D { @@ -176,57 +157,24 @@ impl HInt for u128 { } 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, - ]) + let l0 = self & U128_LO_MASK; + let l1 = rhs & U128_LO_MASK; + let h0 = self >> 64; + let h1 = rhs >> 64; + + let p_ll: u128 = l0.overflowing_mul(l1).0; + let p_lh: u128 = l0.overflowing_mul(h1).0; + let p_hl: u128 = h0.overflowing_mul(l1).0; + let p_hh: u128 = h0.overflowing_mul(h1).0; + + let s0 = p_hl + (p_ll >> 64); + let s1 = (p_ll & U128_LO_MASK) + (s0 << 64); + let s2 = p_lh + (s1 >> 64); + + let lo = (p_ll & U128_LO_MASK) + (s2 << 64); + let hi = p_hh + (s0 >> 64) + (s2 >> 64); + + u256 { lo, hi } } fn widen_mul(self, rhs: Self) -> Self::D { @@ -244,8 +192,7 @@ impl HInt for i128 { 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.hi = u128::MAX; } ret } @@ -271,17 +218,11 @@ 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) + self.lo } 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) + self.hi } } @@ -289,16 +230,10 @@ 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) + self.lo as i128 } 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) + self.hi as i128 } } 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 815a62dfee84e..6d06c700a5ee8 100644 --- a/library/compiler-builtins/libm/src/math/support/big/tests.rs +++ b/library/compiler-builtins/libm/src/math/support/big/tests.rs @@ -9,33 +9,30 @@ 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]) + format!("0x{:032x}{:032x}", v.hi, v.lo) } #[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])); + assert_eq!(u128::MAX.widen(), u256 { lo: u128::MAX, hi: 0 }); + assert_eq!(LOHI_SPLIT.widen(), u256 { lo: LOHI_SPLIT, hi: 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!((LOHI_SPLIT as i128).widen(), i256 { lo: LOHI_SPLIT, hi: u128::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), + (u128::MAX / 2, 2_u128, u256 { lo: u128::MAX - 1, hi: 0 }), + (u128::MAX, 2_u128, u256 { lo: u128::MAX - 1, hi: 1 }), + (u128::MAX, u128::MAX, u256 { lo: 1, hi: u128::MAX - 1 }), + (0, 0, u256::ZERO), + (1234u128, 0, u256::ZERO), (0, 1234, u256::ZERO), ]; @@ -50,20 +47,27 @@ fn widen_mul_u128() { } for (i, a, b, exp, res) in &errors { - eprintln!("FAILURE ({i}): {a:#034x} * {b:#034x} = {} got {}", hexu(*exp), hexu(*res)); + eprintln!( + "\ + FAILURE ({i}): {a:#034x} * {b:#034x}\n\ + expected: {}\n\ + got: {}\ + ", + hexu(*exp), + hexu(*res) + ); } assert!(errors.is_empty()); } #[test] -fn not_u128() { +fn not_u256() { assert_eq!(!u256::ZERO, u256::MAX); } #[test] -fn shr_u128() { +fn shr_u256() { 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 { @@ -80,20 +84,24 @@ fn shr_u128() { } 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])), + (u256::MAX, 1, u256 { lo: u128::MAX, hi: u128::MAX >> 1 }), + (u256::MAX, 5, u256 { lo: u128::MAX, hi: u128::MAX >> 5 }), + (u256::MAX, 63, u256 { lo: u128::MAX, hi: u64::MAX as u128 | (1 << 64) }), + (u256::MAX, 64, u256 { lo: u128::MAX, hi: u64::MAX as u128 }), + (u256::MAX, 65, u256 { lo: u128::MAX, hi: (u64::MAX >> 1) as u128 }), + (u256::MAX, 127, u256 { lo: u128::MAX, hi: 1 }), + (u256::MAX, 128, u256 { lo: u128::MAX, hi: 0 }), + (u256::MAX, 129, u256 { lo: u128::MAX >> 1, hi: 0 }), + (u256::MAX, 191, u256 { lo: u64::MAX as u128 | 1 << 64, hi: 0 }), + (u256::MAX, 192, u256 { lo: u64::MAX as u128, hi: 0 }), + (u256::MAX, 193, u256 { lo: u64::MAX as u128 >> 1, hi: 0 }), + (u256::MAX, 254, u256 { lo: 0b11, hi: 0 }), + (u256::MAX, 255, u256 { lo: 1, hi: 0 }), + ( + u256 { hi: LOHI_SPLIT, lo: 0 }, + 64, + u256 { lo: 0xffffffffffffffff0000000000000000, hi: 0xaaaaaaaaaaaaaaaa }, + ), ]; for (input, shift, expected) in check { @@ -104,7 +112,16 @@ fn shr_u128() { } for (a, b, res, expected) in &errors { - eprintln!("FAILURE: {} >> {b} = {} got {}", hexu(*a), hexu(*expected), hexu(*res),); + eprintln!( + "\ + FAILURE: {} >> {b}\n\ + expected: {}\n\ + got: {}\ + ", + hexu(*a), + hexu(*expected), + hexu(*res) + ); } assert!(errors.is_empty()); } From 35f5731d62049ab8dfb3686bd0328ee796e9f8c5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 10 Feb 2025 08:17:57 +0000 Subject: [PATCH 1670/4206] Introduce a trait constant for the minimum positive normal value --- .../libm/crates/libm-test/src/f8_impl.rs | 1 + .../libm/src/math/support/float_traits.rs | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs index 5dce9be1891df..56ea0b72995c7 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs @@ -32,6 +32,7 @@ impl Float for f8 { const INFINITY: Self = Self(0b0_1111_000); const NEG_INFINITY: Self = Self(0b1_1111_000); const NAN: Self = Self(0b0_1111_100); + const MIN_POSITIVE_NORMAL: Self = Self(1 << Self::SIG_BITS); // FIXME: incorrect values const EPSILON: Self = Self::ZERO; const PI: Self = Self::ZERO; 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 ee83c793da32a..42ce3148464fd 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -41,6 +41,8 @@ pub trait Float: const NEG_PI: Self; const FRAC_PI_2: Self; + const MIN_POSITIVE_NORMAL: Self; + /// The bitwidth of the float type const BITS: u32; @@ -200,6 +202,9 @@ macro_rules! float_impl { const MIN: Self = $from_bits(Self::Int::MAX & !(1 << Self::SIG_BITS)); const EPSILON: Self = <$ty>::EPSILON; + // Exponent is a 1 in the LSB + const MIN_POSITIVE_NORMAL: Self = $from_bits(1 << Self::SIG_BITS); + const PI: Self = core::$ty::consts::PI; const NEG_PI: Self = -Self::PI; const FRAC_PI_2: Self = core::$ty::consts::FRAC_PI_2; @@ -358,6 +363,7 @@ mod tests { // results for zero and subnormals. assert_eq!(f16::ZERO.exp_unbiased(), -15); assert_eq!(f16::from_bits(0x1).exp_unbiased(), -15); + assert_eq!(f16::MIN_POSITIVE, f16::MIN_POSITIVE_NORMAL); // `from_parts` assert_biteq!(f16::from_parts(true, f16::EXP_BIAS, 0), -1.0f16); @@ -383,6 +389,7 @@ mod tests { // results for zero and subnormals. assert_eq!(f32::ZERO.exp_unbiased(), -127); assert_eq!(f32::from_bits(0x1).exp_unbiased(), -127); + assert_eq!(f32::MIN_POSITIVE, f32::MIN_POSITIVE_NORMAL); // `from_parts` assert_biteq!(f32::from_parts(true, f32::EXP_BIAS, 0), -1.0f32); @@ -409,6 +416,7 @@ mod tests { // results for zero and subnormals. assert_eq!(f64::ZERO.exp_unbiased(), -1023); assert_eq!(f64::from_bits(0x1).exp_unbiased(), -1023); + assert_eq!(f64::MIN_POSITIVE, f64::MIN_POSITIVE_NORMAL); // `from_parts` assert_biteq!(f64::from_parts(true, f64::EXP_BIAS, 0), -1.0f64); @@ -436,6 +444,7 @@ mod tests { // results for zero and subnormals. assert_eq!(f128::ZERO.exp_unbiased(), -16383); assert_eq!(f128::from_bits(0x1).exp_unbiased(), -16383); + assert_eq!(f128::MIN_POSITIVE, f128::MIN_POSITIVE_NORMAL); // `from_parts` assert_biteq!(f128::from_parts(true, f128::EXP_BIAS, 0), -1.0f128); From 105cd79578c5ad4326d83afa6ff1c962745d8d8a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 10 Feb 2025 09:17:54 +0000 Subject: [PATCH 1671/4206] Migrate away from nonfunctional `fenv` stubs Many routines have some form of handling for rounding mode and floating point exceptions, which are implemented via a combination of stubs and `force_eval!` use. This is suboptimal, however, because: 1. Rust does not interact with the floating point environment, so most of this code does nothing. 2. The parts of the code that are not dead are not testable. 3. `force_eval!` blocks optimizations, which is unnecessary because we do not rely on its side effects. We cannot ensure correct rounding and exception handling in all cases without some form of arithmetic operations that are aware of this behavior. However, the cases where rounding mode is explicitly handled or exceptions are explicitly raised are testable. Make this possible here for functions that depend on `math::fenv` by moving the implementation to a nonpublic function that takes a `Round` and returns a `Status`. Link: https://github.com/rust-lang/libm/issues/480 --- .../compiler-builtins/libm/src/math/cbrt.rs | 25 ++-- .../compiler-builtins/libm/src/math/fenv.rs | 49 ------- .../libm/src/math/generic/fma.rs | 133 ++++++++++-------- .../libm/src/math/generic/sqrt.rs | 48 +++++-- .../compiler-builtins/libm/src/math/mod.rs | 1 - .../libm/src/math/support/env.rs | 118 ++++++++++++++++ .../libm/src/math/support/mod.rs | 7 +- 7 files changed, 240 insertions(+), 141 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/fenv.rs create mode 100644 library/compiler-builtins/libm/src/math/support/env.rs diff --git a/library/compiler-builtins/libm/src/math/cbrt.rs b/library/compiler-builtins/libm/src/math/cbrt.rs index fbf81f77d2e3f..8560d37abf326 100644 --- a/library/compiler-builtins/libm/src/math/cbrt.rs +++ b/library/compiler-builtins/libm/src/math/cbrt.rs @@ -5,12 +5,15 @@ */ use super::Float; -use super::fenv::Rounding; -use super::support::cold_path; +use super::support::{FpResult, Round, cold_path}; /// Compute the cube root of the argument. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn cbrt(x: f64) -> f64 { + cbrt_round(x, Round::Nearest).val +} + +pub fn cbrt_round(x: f64, round: Round) -> FpResult { const ESCALE: [f64; 3] = [ 1.0, hf64!("0x1.428a2f98d728bp+0"), /* 2^(1/3) */ @@ -33,8 +36,6 @@ pub fn cbrt(x: f64) -> f64 { let off = [hf64!("0x1p-53"), 0.0, 0.0, 0.0]; - let rm = Rounding::get(); - /* rm=0 for rounding to nearest, and other values for directed roundings */ let hx: u64 = x.to_bits(); let mut mant: u64 = hx & f64::SIG_MASK; @@ -51,7 +52,7 @@ pub fn cbrt(x: f64) -> f64 { to that for x a signaling NaN, it correctly triggers the invalid exception. */ if e == f64::EXP_SAT || ix == 0 { - return x + x; + return FpResult::ok(x + x); } let nz = ix.leading_zeros() - 11; /* subnormal */ @@ -124,8 +125,8 @@ pub fn cbrt(x: f64) -> f64 { * from ulp(1); * for rounding to nearest, ady0 is tiny when dy is near from 1/2 ulp(1), * or from 3/2 ulp(1). */ - let mut ady0: f64 = (ady - off[rm as usize]).abs(); - let mut ady1: f64 = (ady - (hf64!("0x1p-52") + off[rm as usize])).abs(); + let mut ady0: f64 = (ady - off[round as usize]).abs(); + let mut ady1: f64 = (ady - (hf64!("0x1p-52") + off[round as usize])).abs(); if ady0 < hf64!("0x1p-75") || ady1 < hf64!("0x1p-75") { cold_path(); @@ -140,8 +141,8 @@ pub fn cbrt(x: f64) -> f64 { dy = (y1 - y) - dy; y1 = y; ady = dy.abs(); - ady0 = (ady - off[rm as usize]).abs(); - ady1 = (ady - (hf64!("0x1p-52") + off[rm as usize])).abs(); + ady0 = (ady - off[round as usize]).abs(); + ady1 = (ady - (hf64!("0x1p-52") + off[round as usize])).abs(); if ady0 < hf64!("0x1p-98") || ady1 < hf64!("0x1p-98") { cold_path(); @@ -157,7 +158,7 @@ pub fn cbrt(x: f64) -> f64 { y1 = hf64!("0x1.de87aa837820fp+0").copysign(zz); } - if rm != Rounding::Nearest { + if round != Round::Nearest { let wlist = [ (hf64!("0x1.3a9ccd7f022dbp+0"), hf64!("0x1.1236160ba9b93p+0")), // ~ 0x1.1236160ba9b930000000000001e7e8fap+0 (hf64!("0x1.7845d2faac6fep+0"), hf64!("0x1.23115e657e49cp+0")), // ~ 0x1.23115e657e49c0000000000001d7a799p+0 @@ -170,7 +171,7 @@ pub fn cbrt(x: f64) -> f64 { for (a, b) in wlist { if azz == a { - let tmp = if rm as u64 + sign == 2 { hf64!("0x1p-52") } else { 0.0 }; + let tmp = if round as u64 + sign == 2 { hf64!("0x1p-52") } else { 0.0 }; y1 = (b + tmp).copysign(zz); } } @@ -194,7 +195,7 @@ pub fn cbrt(x: f64) -> f64 { } } - f64::from_bits(cvt3) + FpResult::ok(f64::from_bits(cvt3)) } fn fmaf64(x: f64, y: f64, z: f64) -> f64 { diff --git a/library/compiler-builtins/libm/src/math/fenv.rs b/library/compiler-builtins/libm/src/math/fenv.rs deleted file mode 100644 index 328c9f3467c6a..0000000000000 --- a/library/compiler-builtins/libm/src/math/fenv.rs +++ /dev/null @@ -1,49 +0,0 @@ -// src: musl/src/fenv/fenv.c -/* Dummy functions for archs lacking fenv implementation */ - -pub(crate) const FE_UNDERFLOW: i32 = 0; -pub(crate) const FE_INEXACT: i32 = 0; - -pub(crate) const FE_TONEAREST: i32 = 0; -pub(crate) const FE_DOWNWARD: i32 = 1; -pub(crate) const FE_UPWARD: i32 = 2; -pub(crate) const FE_TOWARDZERO: i32 = 3; - -#[inline] -pub(crate) fn feclearexcept(_mask: i32) -> i32 { - 0 -} - -#[inline] -pub(crate) fn feraiseexcept(_mask: i32) -> i32 { - 0 -} - -#[inline] -pub(crate) fn fetestexcept(_mask: i32) -> i32 { - 0 -} - -#[inline] -pub(crate) fn fegetround() -> i32 { - FE_TONEAREST -} - -#[derive(Clone, Copy, Debug, PartialEq)] -pub(crate) enum Rounding { - Nearest = FE_TONEAREST as isize, - Downward = FE_DOWNWARD as isize, - Upward = FE_UPWARD as isize, - ToZero = FE_TOWARDZERO as isize, -} - -impl Rounding { - pub(crate) fn get() -> Self { - match fegetround() { - x if x == FE_DOWNWARD => Self::Downward, - x if x == FE_UPWARD => Self::Upward, - x if x == FE_TOWARDZERO => Self::ToZero, - _ => Self::Nearest, - } - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/fma.rs b/library/compiler-builtins/libm/src/math/generic/fma.rs index a40d7aaaf5e0c..821aee09028ba 100644 --- a/library/compiler-builtins/libm/src/math/generic/fma.rs +++ b/library/compiler-builtins/libm/src/math/generic/fma.rs @@ -1,12 +1,7 @@ /* SPDX-License-Identifier: MIT */ /* origin: musl src/math/{fma,fmaf}.c. Ported to generic Rust algorithm in 2025, TG. */ -use core::{f32, f64}; - -use super::super::fenv::{ - FE_INEXACT, FE_TONEAREST, FE_UNDERFLOW, feclearexcept, fegetround, feraiseexcept, fetestexcept, -}; -use super::super::support::{DInt, HInt, IntTy}; +use super::super::support::{DInt, FpResult, HInt, IntTy, Round, Status}; use super::super::{CastFrom, CastInto, DFloat, Float, HFloat, Int, MinInt}; /// Fused multiply-add that works when there is not a larger float size available. Currently this @@ -14,7 +9,18 @@ use super::super::{CastFrom, CastInto, DFloat, Float, HFloat, Int, MinInt}; #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fma(x: F, y: F, z: F) -> F where - F: Float + FmaHelper, + F: Float, + F: CastFrom, + F: CastFrom, + F::Int: HInt, + u32: CastInto, +{ + fma_round(x, y, z, Round::Nearest).val +} + +pub fn fma_round(x: F, y: F, z: F, _round: Round) -> FpResult +where + F: Float, F: CastFrom, F: CastFrom, F::Int: HInt, @@ -30,16 +36,16 @@ where if nx.is_zero_nan_inf() || ny.is_zero_nan_inf() { // Value will overflow, defer to non-fused operations. - return x * y + z; + return FpResult::ok(x * y + z); } if nz.is_zero_nan_inf() { if nz.is_zero() { // Empty add component means we only need to multiply. - return x * y; + return FpResult::ok(x * y); } // `z` is NaN or infinity, which sets the result. - return z; + return FpResult::ok(z); } // multiply: r = x * y @@ -147,7 +153,7 @@ where } } else { // exact +/- 0.0 - return x * y + z; + return FpResult::ok(x * y + z); } e -= d; @@ -168,6 +174,8 @@ where // Unbiased exponent for the maximum value of `r` let max_pow = F::BITS - 1 + F::EXP_BIAS; + let mut status = Status::OK; + if e < -(max_pow as i32 - 2) { // Result is subnormal before rounding if e == -(max_pow as i32 - 1) { @@ -178,7 +186,9 @@ where if r == c { // Min normal after rounding, - return r.raise_underflow_as_min_positive(); + status.set_underflow(true); + r = F::MIN_POSITIVE_NORMAL.copysign(r); + return FpResult::new(r, status); } if (rhi << (F::SIG_BITS + 1)) != zero { @@ -195,7 +205,7 @@ where // Remove the top bit r = F::cast_from(2i8) * r - c; - r += r.raise_underflow_ret_zero(); + status.set_underflow(true); } } else { // Only round once when scaled @@ -212,12 +222,22 @@ where } // Use our exponent to scale the final value. - super::scalbn(r, e) + FpResult::new(super::scalbn(r, e), status) } /// Fma implementation when a hardware-backed larger float type is available. For `f32` and `f64`, /// `f64` has enough precision to represent the `f32` in its entirety, except for double rounding. pub fn fma_wide(x: F, y: F, z: F) -> F +where + F: Float + HFloat, + B: Float + DFloat, + B::Int: CastInto, + i32: CastFrom, +{ + fma_wide_round(x, y, z, Round::Nearest).val +} + +pub fn fma_wide_round(x: F, y: F, z: F, round: Round) -> FpResult where F: Float + HFloat, B: Float + DFloat, @@ -244,24 +264,26 @@ where // Or the result is exact || (result - xy == zb && result - zb == xy) // Or the mode is something other than round to nearest - || fegetround() != FE_TONEAREST + || round != Round::Nearest { let min_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN_SUBNORM) as u32; let max_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN) as u32; - if (min_inexact_exp..max_inexact_exp).contains(&re) && fetestexcept(FE_INEXACT) != 0 { - feclearexcept(FE_INEXACT); - // prevent `xy + vz` from being CSE'd with `xy + z` above - let vz: F = force_eval!(z); - result = xy + vz.widen(); - if fetestexcept(FE_INEXACT) != 0 { - feraiseexcept(FE_UNDERFLOW); + let mut status = Status::OK; + + if (min_inexact_exp..max_inexact_exp).contains(&re) && status.inexact() { + // This branch is never hit; requires previous operations to set a status + status.set_inexact(false); + + result = xy + z.widen(); + if status.inexact() { + status.set_underflow(true); } else { - feraiseexcept(FE_INEXACT); + status.set_inexact(true); } } - return result.narrow(); + return FpResult { val: result.narrow(), status }; } let neg = ui >> (B::BITS - 1) != IntTy::::ZERO; @@ -272,7 +294,7 @@ where ui -= one; } - B::from_bits(ui).narrow() + FpResult::ok(B::from_bits(ui).narrow()) } /// Representation of `F` that has handled subnormals. @@ -337,49 +359,13 @@ impl Norm { } } -/// Type-specific helpers that are not needed outside of fma. -pub trait FmaHelper { - /// Raise underflow and return the minimum positive normal value with the sign of `self`. - fn raise_underflow_as_min_positive(self) -> Self; - /// Raise underflow and return zero. - fn raise_underflow_ret_zero(self) -> Self; -} - -impl FmaHelper for f64 { - fn raise_underflow_as_min_positive(self) -> Self { - /* min normal after rounding, underflow depends - * on arch behaviour which can be imitated by - * a double to float conversion */ - let fltmin: f32 = (hf64!("0x0.ffffff8p-63") * f32::MIN_POSITIVE as f64 * self) as f32; - f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * fltmin as f64 - } - - fn raise_underflow_ret_zero(self) -> Self { - /* raise underflow portably, such that it - * cannot be optimized away */ - let tiny: f64 = f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * self; - (tiny * tiny) * (self - self) - } -} - -#[cfg(f128_enabled)] -impl FmaHelper for f128 { - fn raise_underflow_as_min_positive(self) -> Self { - f128::MIN_POSITIVE.copysign(self) - } - - fn raise_underflow_ret_zero(self) -> Self { - f128::ZERO - } -} - #[cfg(test)] mod tests { use super::*; fn spec_test() where - F: Float + FmaHelper, + F: Float, F: CastFrom, F: CastFrom, F::Int: HInt, @@ -401,6 +387,29 @@ mod tests { #[test] fn spec_test_f64() { spec_test::(); + + let expect_underflow = [ + ( + hf64!("0x1.0p-1070"), + hf64!("0x1.0p-1070"), + hf64!("0x1.ffffffffffffp-1023"), + hf64!("0x0.ffffffffffff8p-1022"), + ), + ( + // FIXME: we raise underflow but this should only be inexact (based on C and + // `rustc_apfloat`). + hf64!("0x1.0p-1070"), + hf64!("0x1.0p-1070"), + hf64!("-0x1.0p-1022"), + hf64!("-0x1.0p-1022"), + ), + ]; + + for (x, y, z, res) in expect_underflow { + let FpResult { val, status } = fma_round(x, y, z, Round::Nearest); + assert_biteq!(val, res); + assert_eq!(status, Status::UNDERFLOW); + } } #[test] diff --git a/library/compiler-builtins/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/src/math/generic/sqrt.rs index 90d6c01e91719..fdd612493b79e 100644 --- a/library/compiler-builtins/libm/src/math/generic/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/generic/sqrt.rs @@ -41,10 +41,23 @@ //! Goldschmidt has the advantage over Newton-Raphson that `sqrt(x)` and `1/sqrt(x)` are //! computed at the same time, i.e. there is no need to calculate `1/sqrt(x)` and invert it. -use super::super::support::{IntTy, cold_path, raise_invalid}; +use super::super::support::{FpResult, IntTy, Round, Status, cold_path}; use super::super::{CastFrom, CastInto, DInt, Float, HInt, Int, MinInt}; 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 +} + +pub fn sqrt_round(x: F, _round: Round) -> FpResult where F: Float + SqrtHelper, F::Int: HInt, @@ -78,17 +91,17 @@ where // +/-0 if ix << 1 == zero { - return x; + return FpResult::ok(x); } // Positive infinity if ix == F::EXP_MASK { - return x; + return FpResult::ok(x); } // NaN or negative if ix > F::EXP_MASK { - return raise_invalid(x); + return FpResult::new(F::NAN, Status::INVALID); } // Normalize subnormals by multiplying by 1.0 << SIG_BITS (e.g. 0x1p52 for doubles). @@ -215,7 +228,7 @@ where y = y + t; } - y + FpResult::ok(y) } /// Multiply at the wider integer size, returning the high half. @@ -329,7 +342,7 @@ impl SqrtHelper for f128 { /// A U0.16 representation of `1/sqrt(x)`. /// -// / The index is a 7-bit number consisting of a single exponent bit and 6 bits of significand. +/// The index is a 7-bit number consisting of a single exponent bit and 6 bits of significand. #[rustfmt::skip] static RSQRT_TAB: [u16; 128] = [ 0xb451, 0xb2f0, 0xb196, 0xb044, 0xaef9, 0xadb6, 0xac79, 0xab43, @@ -354,7 +367,7 @@ static RSQRT_TAB: [u16; 128] = [ mod tests { use super::*; - /// Test against edge cases from https://en.cppreference.com/w/cpp/numeric/math/sqrt + /// Test behavior specified in IEEE 754 `squareRoot`. fn spec_test() where F: Float + SqrtHelper, @@ -365,11 +378,22 @@ mod tests { F::Int: CastInto, u32: CastInto, { - // Not Asserted: FE_INVALID exception is raised if argument is negative. - assert!(sqrt(F::NEG_ONE).is_nan()); - assert!(sqrt(F::NAN).is_nan()); - for f in [F::ZERO, F::NEG_ZERO, F::INFINITY].iter().copied() { - assert_biteq!(sqrt(f), f); + // 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); } } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index e32045021dae5..ae4a278f287a3 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -94,7 +94,6 @@ cfg_if! { // Private modules mod arch; mod expo2; -mod fenv; mod k_cos; mod k_cosf; mod k_expo2; diff --git a/library/compiler-builtins/libm/src/math/support/env.rs b/library/compiler-builtins/libm/src/math/support/env.rs new file mode 100644 index 0000000000000..7244381dacc60 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/support/env.rs @@ -0,0 +1,118 @@ +//! Support for rounding directions and status flags as specified by IEEE 754. +//! +//! Rust does not support the floating point environment so rounding mode is passed as an argument +//! and status flags are returned as part of the result. There is currently not much support for +//! this; most existing ports from musl use a form of `force_eval!` to raise exceptions, but this +//! has no side effects in Rust. Further, correct behavior relies on elementary operations making +//! use of the correct rounding and raising relevant exceptions, which is not the case for Rust. +//! +//! This module exists so no functionality is lost when porting algorithms that respect floating +//! point environment, and so that some functionality may be tested (that which does not rely on +//! side effects from elementary operations). Full support would require wrappers around basic +//! operations, but there is no plan to add this at the current time. + +/// A value combined with a floating point status. +pub struct FpResult { + pub val: T, + #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] + pub status: Status, +} + +impl FpResult { + pub fn new(val: T, status: Status) -> Self { + Self { val, status } + } + + /// Return `val` with `Status::OK`. + pub fn ok(val: T) -> Self { + Self { val, status: Status::OK } + } +} + +/// IEEE 754 rounding mode, excluding the optional `roundTiesToAway` version of nearest. +/// +/// Integer representation comes from what CORE-MATH uses for indexing. +#[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum Round { + /// IEEE 754 nearest, `roundTiesToEven`. + Nearest = 0, + /// IEEE 754 `roundTowardNegative`. + Negative = 1, + /// IEEE 754 `roundTowardPositive`. + Positive = 2, + /// IEEE 754 `roundTowardZero`. + Zero = 3, +} + +/// IEEE 754 exception status flags. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Status(u8); + +impl Status { + /// Default status indicating no errors. + pub const OK: Self = Self(0); + + /// No definable result. + /// + /// Includes: + /// - Any ops on sNaN, with a few exceptions. + /// - `0 * inf`, `inf * 0`. + /// - `fma(0, inf, c)` or `fma(inf, 0, c)`, possibly excluding `c = qNaN`. + /// - `+inf + -inf` and similar (includes subtraction and fma). + /// - `0.0 / 0.0`, `inf / inf` + /// - `remainder(x, y)` if `y == 0.0` or `x == inf`, and neither is NaN. + /// - `sqrt(x)` with `x < 0.0`. + pub const INVALID: Self = Self(1); + + /// Division by zero. + /// + /// The default result for division is +/-inf based on operand sign. For `logB`, the default + /// result is -inf. + /// `x / y` when `x != 0.0` and `y == 0.0`, + + #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] + pub const DIVIDE_BY_ZERO: Self = Self(1 << 2); + + /// The result exceeds the maximum finite value. + /// + /// The default result depends on rounding mode. `Nearest*` rounds to +/- infinity, sign based + /// on the intermediate result. `Zero` rounds to the signed maximum finite. `Positive` and + /// `Negative` round to signed maximum finite in one direction, signed infinity in the other. + #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] + pub const OVERFLOW: Self = Self(1 << 3); + + /// The result is subnormal and lost precision. + pub const UNDERFLOW: Self = Self(1 << 4); + + /// The finite-precision result does not match that of infinite precision, and the reason + /// is not represented by one of the other flags. + pub const INEXACT: Self = Self(1 << 5); + + /// True if `UNDERFLOW` is set. + #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] + pub fn underflow(self) -> bool { + self.0 & Self::UNDERFLOW.0 != 0 + } + + pub fn set_underflow(&mut self, val: bool) { + self.set_flag(val, Self::UNDERFLOW); + } + + /// True if `INEXACT` is set. + pub fn inexact(self) -> bool { + self.0 & Self::INEXACT.0 != 0 + } + + pub fn set_inexact(&mut self, val: bool) { + self.set_flag(val, Self::INEXACT); + } + + fn set_flag(&mut self, val: bool, mask: Self) { + if val { + self.0 |= mask.0; + } else { + self.0 &= !mask.0; + } + } +} diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index 28e9fd4132f42..ee3f2bbdf02db 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -1,12 +1,14 @@ #[macro_use] pub mod macros; mod big; +mod env; mod float_traits; pub mod hex_float; mod int_traits; #[allow(unused_imports)] pub use big::{i256, u256}; +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}; @@ -25,8 +27,3 @@ pub fn cold_path() { #[cfg(intrinsics_enabled)] core::intrinsics::cold_path(); } - -/// Return `x`, first raising `FE_INVALID`. -pub fn raise_invalid(x: F) -> F { - (x - x) / (x - x) -} From e94e9873999afed5948594569f049f20ebddd495 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 10 Feb 2025 12:01:16 +0000 Subject: [PATCH 1672/4206] Eliminate the use of `force_eval!` in `ceil`, `floor`, and `trunc` --- .../libm/src/math/generic/ceil.rs | 91 ++++++++++++++++--- .../libm/src/math/generic/floor.rs | 77 ++++++++++++---- .../libm/src/math/generic/trunc.rs | 89 +++++++++++++++++- 3 files changed, 220 insertions(+), 37 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/generic/ceil.rs b/library/compiler-builtins/libm/src/math/generic/ceil.rs index 971a4d3d8c5ff..bf7e1d8e2100b 100644 --- a/library/compiler-builtins/libm/src/math/generic/ceil.rs +++ b/library/compiler-builtins/libm/src/math/generic/ceil.rs @@ -7,9 +7,14 @@ //! performance seems to be better (based on icount) and it does not seem to experience rounding //! errors on i386. +use super::super::support::{FpResult, Status}; use super::super::{Float, Int, IntTy, MinInt}; pub fn ceil(x: F) -> F { + ceil_status(x).val +} + +pub fn ceil_status(x: F) -> FpResult { let zero = IntTy::::ZERO; let mut ix = x.to_bits(); @@ -17,20 +22,20 @@ pub fn ceil(x: F) -> F { // If the represented value has no fractional part, no truncation is needed. if e >= F::SIG_BITS as i32 { - return x; + return FpResult::ok(x); } - if e >= 0 { + let status; + let res = if e >= 0 { // |x| >= 1.0 - let m = F::SIG_MASK >> e.unsigned(); if (ix & m) == zero { // Portion to be masked is already zero; no adjustment needed. - return x; + return FpResult::ok(x); } // Otherwise, raise an inexact exception. - force_eval!(x + F::MAX); + status = Status::INEXACT; if x.is_sign_positive() { ix += m; @@ -40,7 +45,11 @@ pub fn ceil(x: F) -> F { F::from_bits(ix) } else { // |x| < 1.0, raise an inexact exception since truncation will happen (unless x == 0). - force_eval!(x + F::MAX); + if ix & F::SIG_MASK == F::Int::ZERO { + status = Status::OK; + } else { + status = Status::INEXACT; + } if x.is_sign_negative() { // -1.0 < x <= -0.0; rounding up goes toward -0.0. @@ -52,18 +61,30 @@ pub fn ceil(x: F) -> F { // +0.0 remains unchanged x } - } + }; + + FpResult::new(res, status) } #[cfg(test)] mod tests { use super::*; + use crate::support::Hexf; /// Test against https://en.cppreference.com/w/cpp/numeric/math/ceil - fn spec_test() { - // Not Asserted: that the current rounding mode has no effect. - for f in [F::ZERO, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY].iter().copied() { - assert_biteq!(ceil(f), f); + 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 } = ceil_status(x); + assert_biteq!(val, x, "{}", Hexf(x)); + assert_eq!(status, Status::OK, "{}", Hexf(x)); + } + + for &(x, res, res_stat) in cases { + let FpResult { val, status } = ceil_status(x); + assert_biteq!(val, res, "{}", Hexf(x)); + assert_eq!(status, res_stat, "{}", Hexf(x)); } } @@ -72,7 +93,17 @@ mod tests { #[test] #[cfg(f16_enabled)] fn spec_tests_f16() { - spec_test::(); + let cases = [ + (0.1, 1.0, Status::INEXACT), + (-0.1, -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.9, 2.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ]; + spec_test::(&cases); } #[test] @@ -83,7 +114,17 @@ mod tests { #[test] fn spec_tests_f32() { - spec_test::(); + let cases = [ + (0.1, 1.0, Status::INEXACT), + (-0.1, -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.9, 2.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ]; + spec_test::(&cases); } #[test] @@ -94,12 +135,32 @@ mod tests { #[test] fn spec_tests_f64() { - spec_test::(); + let cases = [ + (0.1, 1.0, Status::INEXACT), + (-0.1, -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.9, 2.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ]; + spec_test::(&cases); } #[test] #[cfg(f128_enabled)] fn spec_tests_f128() { - spec_test::(); + let cases = [ + (0.1, 1.0, Status::INEXACT), + (-0.1, -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.9, 2.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ]; + spec_test::(&cases); } } diff --git a/library/compiler-builtins/libm/src/math/generic/floor.rs b/library/compiler-builtins/libm/src/math/generic/floor.rs index 6754c08f870bb..7799551644f3c 100644 --- a/library/compiler-builtins/libm/src/math/generic/floor.rs +++ b/library/compiler-builtins/libm/src/math/generic/floor.rs @@ -7,9 +7,14 @@ //! performance seems to be better (based on icount) and it does not seem to experience rounding //! errors on i386. +use super::super::support::{FpResult, Status}; use super::super::{Float, Int, IntTy, MinInt}; pub fn floor(x: F) -> F { + floor_status(x).val +} + +pub fn floor_status(x: F) -> FpResult { let zero = IntTy::::ZERO; let mut ix = x.to_bits(); @@ -17,20 +22,20 @@ pub fn floor(x: F) -> F { // If the represented value has no fractional part, no truncation is needed. if e >= F::SIG_BITS as i32 { - return x; + return FpResult::ok(x); } - if e >= 0 { + let status; + let res = if e >= 0 { // |x| >= 1.0 - let m = F::SIG_MASK >> e.unsigned(); if ix & m == zero { // Portion to be masked is already zero; no adjustment needed. - return x; + return FpResult::ok(x); } // Otherwise, raise an inexact exception. - force_eval!(x + F::MAX); + status = Status::INEXACT; if x.is_sign_negative() { ix += m; @@ -39,8 +44,12 @@ pub fn floor(x: F) -> F { ix &= !m; F::from_bits(ix) } else { - // |x| < 1.0, raise an inexact exception since truncation will happen (unless x == 0). - force_eval!(x + F::MAX); + // |x| < 1.0, raise an inexact exception since truncation will happen. + if ix & F::SIG_MASK == F::Int::ZERO { + status = Status::OK; + } else { + status = Status::INEXACT; + } if x.is_sign_positive() { // 0.0 <= x < 1.0; rounding down goes toward +0.0. @@ -52,27 +61,40 @@ pub fn floor(x: F) -> F { // -0.0 remains unchanged x } - } + }; + + FpResult::new(res, status) } #[cfg(test)] mod tests { use super::*; + use crate::support::Hexf; /// Test against https://en.cppreference.com/w/cpp/numeric/math/floor - fn spec_test() { - // Not Asserted: that the current rounding mode has no effect. - for f in [F::ZERO, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY].iter().copied() { - assert_biteq!(floor(f), f); + 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 } = floor_status(x); + assert_biteq!(val, x, "{}", Hexf(x)); + assert_eq!(status, Status::OK, "{}", Hexf(x)); + } + + for &(x, res, res_stat) in cases { + let FpResult { val, status } = floor_status(x); + assert_biteq!(val, res, "{}", Hexf(x)); + assert_eq!(status, res_stat, "{}", Hexf(x)); } } - /* Skipping f16 / f128 "sanity_check"s due to rejected literal lexing at MSRV */ + /* Skipping f16 / f128 "sanity_check"s and spec cases due to rejected literal lexing at MSRV */ #[test] #[cfg(f16_enabled)] fn spec_tests_f16() { - spec_test::(); + let cases = []; + spec_test::(&cases); } #[test] @@ -84,7 +106,17 @@ mod tests { #[test] fn spec_tests_f32() { - spec_test::(); + let cases = [ + (0.1, 0.0, Status::INEXACT), + (-0.1, -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.9, 1.0, Status::INEXACT), + (-1.9, -2.0, Status::INEXACT), + ]; + spec_test::(&cases); } #[test] @@ -95,12 +127,23 @@ mod tests { #[test] fn spec_tests_f64() { - spec_test::(); + let cases = [ + (0.1, 0.0, Status::INEXACT), + (-0.1, -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.9, 1.0, Status::INEXACT), + (-1.9, -2.0, Status::INEXACT), + ]; + spec_test::(&cases); } #[test] #[cfg(f128_enabled)] fn spec_tests_f128() { - spec_test::(); + let cases = []; + spec_test::(&cases); } } diff --git a/library/compiler-builtins/libm/src/math/generic/trunc.rs b/library/compiler-builtins/libm/src/math/generic/trunc.rs index ca5f1bdd6276e..0fb3fa5ad3b80 100644 --- a/library/compiler-builtins/libm/src/math/generic/trunc.rs +++ b/library/compiler-builtins/libm/src/math/generic/trunc.rs @@ -1,15 +1,20 @@ /* SPDX-License-Identifier: MIT * origin: musl src/math/trunc.c */ +use super::super::support::{FpResult, Status}; use super::super::{Float, Int, IntTy, MinInt}; pub fn trunc(x: F) -> F { + trunc_status(x).val +} + +pub fn trunc_status(x: F) -> FpResult { let mut xi: F::Int = x.to_bits(); let e: i32 = x.exp_unbiased(); // C1: The represented value has no fractional part, so no truncation is needed if e >= F::SIG_BITS as i32 { - return x; + return FpResult::ok(x); } let mask = if e < 0 { @@ -23,22 +28,68 @@ pub fn trunc(x: F) -> F { // C4: If the to-be-masked-out portion is already zero, we have an exact result if (xi & !mask) == IntTy::::ZERO { - return x; + return FpResult::ok(x); } // C5: Otherwise the result is inexact and we will truncate. Raise `FE_INEXACT`, mask the // result, and return. - force_eval!(x + F::MAX); + + let status = if xi & F::SIG_MASK == F::Int::ZERO { Status::OK } else { Status::INEXACT }; xi &= mask; - F::from_bits(xi) + FpResult::new(F::from_bits(xi), status) } #[cfg(test)] mod tests { use super::*; + use crate::support::Hexf; + + 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 } = trunc_status(x); + assert_biteq!(val, x, "{}", Hexf(x)); + assert_eq!(status, Status::OK, "{}", Hexf(x)); + } + + for &(x, res, res_stat) in cases { + let FpResult { val, status } = trunc_status(x); + assert_biteq!(val, res, "{}", Hexf(x)); + assert_eq!(status, res_stat, "{}", Hexf(x)); + } + } + + /* Skipping f16 / f128 "sanity_check"s and spec cases due to rejected literal lexing at MSRV */ + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + let cases = []; + spec_test::(&cases); + } + + #[test] + fn sanity_check_f32() { + assert_eq!(trunc(0.5f32), 0.0); + assert_eq!(trunc(1.1f32), 1.0); + assert_eq!(trunc(2.9f32), 2.0); + } #[test] - fn sanity_check() { + fn spec_tests_f32() { + let cases = [ + (0.1, 0.0, Status::INEXACT), + (-0.1, -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.9, 1.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ]; + spec_test::(&cases); + assert_biteq!(trunc(1.1f32), 1.0); assert_biteq!(trunc(1.1f64), 1.0); @@ -54,4 +105,32 @@ mod tests { assert_biteq!(trunc(hf32!("-0x1p-1")), -0.0); assert_biteq!(trunc(hf64!("-0x1p-1")), -0.0); } + + #[test] + fn sanity_check_f64() { + assert_eq!(trunc(1.1f64), 1.0); + assert_eq!(trunc(2.9f64), 2.0); + } + + #[test] + fn spec_tests_f64() { + let cases = [ + (0.1, 0.0, Status::INEXACT), + (-0.1, -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.9, 1.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ]; + spec_test::(&cases); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + let cases = []; + spec_test::(&cases); + } } From a6dd7980f1553511ed6c03213924f202ee77ae4d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 10 Feb 2025 05:26:50 +0000 Subject: [PATCH 1673/4206] Small refactor of bigint tests Print errors immediately rather than deferring to the end, so any debug output shows up immediately before the relevant failed test. --- .../libm/src/math/support/big/tests.rs | 65 ++++++++++--------- 1 file changed, 34 insertions(+), 31 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 6d06c700a5ee8..2c71191ba5331 100644 --- a/library/compiler-builtins/libm/src/math/support/big/tests.rs +++ b/library/compiler-builtins/libm/src/math/support/big/tests.rs @@ -1,6 +1,5 @@ extern crate std; use std::string::String; -use std::vec::Vec; use std::{eprintln, format}; use super::{HInt, MinInt, i256, u256}; @@ -36,28 +35,30 @@ fn widen_mul_u128() { (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 { + let mut has_errors = false; + let mut add_error = |i, a, b, expected, actual| { + has_errors = true; eprintln!( "\ FAILURE ({i}): {a:#034x} * {b:#034x}\n\ expected: {}\n\ got: {}\ ", - hexu(*exp), - hexu(*res) + hexu(expected), + hexu(actual) ); + }; + + 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 { + add_error(i, a, b, exp, res); + } } - assert!(errors.is_empty()); + + assert!(!has_errors); } #[test] @@ -68,7 +69,21 @@ fn not_u256() { #[test] fn shr_u256() { let only_low = [1, u16::MAX.into(), u32::MAX.into(), u64::MAX.into(), u128::MAX]; - let mut errors = Vec::new(); + 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_low { for perturb in 0..10 { @@ -77,7 +92,7 @@ fn shr_u256() { let res = a.widen() >> shift; let expected = (a >> shift).widen(); if res != expected { - errors.push((a.widen(), shift, res, expected)); + add_error(a.widen(), shift, expected, res); } } } @@ -107,23 +122,11 @@ fn shr_u256() { for (input, shift, expected) in check { let res = input >> shift; if res != expected { - errors.push((input, shift, res, expected)); + add_error(input, shift, expected, res); } } - for (a, b, res, expected) in &errors { - eprintln!( - "\ - FAILURE: {} >> {b}\n\ - expected: {}\n\ - got: {}\ - ", - hexu(*a), - hexu(*expected), - hexu(*res) - ); - } - assert!(errors.is_empty()); + assert!(!has_errors); } #[test] From 86ee1f99c9d361338017282810966efc33901c3d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 10 Feb 2025 19:56:52 +0000 Subject: [PATCH 1674/4206] Combine `fmin{,f,f16,f128}` and `fmax{,f,f16,128}` into a single file These don't have much content since they now use the generic implementation. There will be more similar functions in the near future (fminimum, fmaximum, fminimum_num, fmaximum_num); start the pattern of combining similar functions now so we don't have to eventually maintain similar docs across 24 different files. --- .../libm/etc/function-definitions.json | 16 +++--- .../compiler-builtins/libm/src/math/fmax.rs | 5 -- .../compiler-builtins/libm/src/math/fmaxf.rs | 5 -- .../libm/src/math/fmaxf128.rs | 5 -- .../libm/src/math/fmaxf16.rs | 5 -- .../compiler-builtins/libm/src/math/fmin.rs | 5 -- .../libm/src/math/fmin_fmax.rs | 51 +++++++++++++++++++ .../compiler-builtins/libm/src/math/fminf.rs | 5 -- .../libm/src/math/fminf128.rs | 5 -- .../libm/src/math/fminf16.rs | 5 -- .../compiler-builtins/libm/src/math/mod.rs | 22 +++----- 11 files changed, 65 insertions(+), 64 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/fmax.rs delete mode 100644 library/compiler-builtins/libm/src/math/fmaxf.rs delete mode 100644 library/compiler-builtins/libm/src/math/fmaxf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/fmaxf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/fmin.rs create mode 100644 library/compiler-builtins/libm/src/math/fmin_fmax.rs delete mode 100644 library/compiler-builtins/libm/src/math/fminf.rs delete mode 100644 library/compiler-builtins/libm/src/math/fminf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/fminf16.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 5742ed585f583..d3e51f29a07cf 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -365,56 +365,56 @@ }, "fmax": { "sources": [ - "src/math/fmax.rs", + "src/math/fmin_fmax.rs", "src/math/generic/fmax.rs" ], "type": "f64" }, "fmaxf": { "sources": [ - "src/math/fmaxf.rs", + "src/math/fmin_fmax.rs", "src/math/generic/fmax.rs" ], "type": "f32" }, "fmaxf128": { "sources": [ - "src/math/fmaxf128.rs", + "src/math/fmin_fmax.rs", "src/math/generic/fmax.rs" ], "type": "f128" }, "fmaxf16": { "sources": [ - "src/math/fmaxf16.rs", + "src/math/fmin_fmax.rs", "src/math/generic/fmax.rs" ], "type": "f16" }, "fmin": { "sources": [ - "src/math/fmin.rs", + "src/math/fmin_fmax.rs", "src/math/generic/fmin.rs" ], "type": "f64" }, "fminf": { "sources": [ - "src/math/fminf.rs", + "src/math/fmin_fmax.rs", "src/math/generic/fmin.rs" ], "type": "f32" }, "fminf128": { "sources": [ - "src/math/fminf128.rs", + "src/math/fmin_fmax.rs", "src/math/generic/fmin.rs" ], "type": "f128" }, "fminf16": { "sources": [ - "src/math/fminf16.rs", + "src/math/fmin_fmax.rs", "src/math/generic/fmin.rs" ], "type": "f16" diff --git a/library/compiler-builtins/libm/src/math/fmax.rs b/library/compiler-builtins/libm/src/math/fmax.rs deleted file mode 100644 index d5d9b513b8494..0000000000000 --- a/library/compiler-builtins/libm/src/math/fmax.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Return the greater of two arguments or, if either argument is NaN, the other argument. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmax(x: f64, y: f64) -> f64 { - super::generic::fmax(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fmaxf.rs b/library/compiler-builtins/libm/src/math/fmaxf.rs deleted file mode 100644 index 3197d5cf2ca1f..0000000000000 --- a/library/compiler-builtins/libm/src/math/fmaxf.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Return the greater of two arguments or, if either argument is NaN, the other argument. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaxf(x: f32, y: f32) -> f32 { - super::generic::fmax(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fmaxf128.rs b/library/compiler-builtins/libm/src/math/fmaxf128.rs deleted file mode 100644 index bace9ab53f2af..0000000000000 --- a/library/compiler-builtins/libm/src/math/fmaxf128.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Return the greater of two arguments or, if either argument is NaN, the other argument. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaxf128(x: f128, y: f128) -> f128 { - super::generic::fmax(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fmaxf16.rs b/library/compiler-builtins/libm/src/math/fmaxf16.rs deleted file mode 100644 index fea15be8f1478..0000000000000 --- a/library/compiler-builtins/libm/src/math/fmaxf16.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Return the greater of two arguments or, if either argument is NaN, the other argument. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaxf16(x: f16, y: f16) -> f16 { - super::generic::fmax(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fmin.rs b/library/compiler-builtins/libm/src/math/fmin.rs deleted file mode 100644 index df8ff7c32e3b2..0000000000000 --- a/library/compiler-builtins/libm/src/math/fmin.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Return the lesser of two arguments or, if either argument is NaN, the other argument. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmin(x: f64, y: f64) -> f64 { - super::generic::fmin(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fmin_fmax.rs b/library/compiler-builtins/libm/src/math/fmin_fmax.rs new file mode 100644 index 0000000000000..97912e7582663 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fmin_fmax.rs @@ -0,0 +1,51 @@ +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminf16(x: f16, y: f16) -> f16 { + super::generic::fmin(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminf(x: f32, y: f32) -> f32 { + super::generic::fmin(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmin(x: f64, y: f64) -> f64 { + super::generic::fmin(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminf128(x: f128, y: f128) -> f128 { + super::generic::fmin(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaxf16(x: f16, y: f16) -> f16 { + super::generic::fmax(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaxf(x: f32, y: f32) -> f32 { + super::generic::fmax(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmax(x: f64, y: f64) -> f64 { + super::generic::fmax(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaxf128(x: f128, y: f128) -> f128 { + super::generic::fmax(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/fminf.rs b/library/compiler-builtins/libm/src/math/fminf.rs deleted file mode 100644 index b2cdfe89d64db..0000000000000 --- a/library/compiler-builtins/libm/src/math/fminf.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Return the lesser of two arguments or, if either argument is NaN, the other argument. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminf(x: f32, y: f32) -> f32 { - super::generic::fmin(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fminf128.rs b/library/compiler-builtins/libm/src/math/fminf128.rs deleted file mode 100644 index a9224c22aa5de..0000000000000 --- a/library/compiler-builtins/libm/src/math/fminf128.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Return the lesser of two arguments or, if either argument is NaN, the other argument. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminf128(x: f128, y: f128) -> f128 { - super::generic::fmin(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fminf16.rs b/library/compiler-builtins/libm/src/math/fminf16.rs deleted file mode 100644 index 6d936be347a12..0000000000000 --- a/library/compiler-builtins/libm/src/math/fminf16.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Return the lesser of two arguments or, if either argument is NaN, the other argument. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fminf16(x: f16, y: f16) -> f16 { - super::generic::fmin(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index ae4a278f287a3..ba0b933f17c81 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -165,10 +165,7 @@ mod floor; mod floorf; mod fma; mod fmaf; -mod fmax; -mod fmaxf; -mod fmin; -mod fminf; +mod fmin_fmax; mod fmod; mod fmodf; mod frexp; @@ -273,10 +270,7 @@ pub use self::floor::floor; pub use self::floorf::floorf; pub use self::fma::fma; pub use self::fmaf::fmaf; -pub use self::fmax::fmax; -pub use self::fmaxf::fmaxf; -pub use self::fmin::fmin; -pub use self::fminf::fminf; +pub use self::fmin_fmax::{fmax, fmaxf, fmin, fminf}; pub use self::fmod::fmod; pub use self::fmodf::fmodf; pub use self::frexp::frexp; @@ -346,8 +340,6 @@ cfg_if! { mod fabsf16; mod fdimf16; mod floorf16; - mod fmaxf16; - mod fminf16; mod fmodf16; mod ldexpf16; mod rintf16; @@ -363,8 +355,8 @@ cfg_if! { pub use self::fabsf16::fabsf16; pub use self::fdimf16::fdimf16; pub use self::floorf16::floorf16; - pub use self::fmaxf16::fmaxf16; - pub use self::fminf16::fminf16; + pub use self::fmin_fmax::fmaxf16; + pub use self::fmin_fmax::fminf16; pub use self::fmodf16::fmodf16; pub use self::ldexpf16::ldexpf16; pub use self::rintf16::rintf16; @@ -385,8 +377,6 @@ cfg_if! { mod fdimf128; mod floorf128; mod fmaf128; - mod fmaxf128; - mod fminf128; mod fmodf128; mod ldexpf128; mod rintf128; @@ -403,8 +393,8 @@ cfg_if! { pub use self::fdimf128::fdimf128; pub use self::floorf128::floorf128; pub use self::fmaf128::fmaf128; - pub use self::fmaxf128::fmaxf128; - pub use self::fminf128::fminf128; + pub use self::fmin_fmax::fmaxf128; + pub use self::fmin_fmax::fminf128; pub use self::fmodf128::fmodf128; pub use self::ldexpf128::ldexpf128; pub use self::rintf128::rintf128; From 669731335e05705eae35f6ba16bdcce9fabf1e90 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 10 Feb 2025 19:43:49 +0000 Subject: [PATCH 1675/4206] Add `fminimum`, `fmaximum`, `fminimum_num`, and `fmaximum_num` These functions represent new operations from IEEE 754-2019. Introduce them for all float sizes. --- .../libm/crates/libm-macros/src/shared.rs | 32 ++++- .../libm/crates/libm-test/benches/icount.rs | 16 +++ .../libm/crates/libm-test/benches/random.rs | 16 +++ .../libm/crates/libm-test/src/domain.rs | 4 + .../crates/libm-test/src/gen/case_list.rs | 80 ++++++++++++- .../libm/crates/libm-test/src/mpfloat.rs | 54 ++++++++- .../libm/crates/libm-test/src/precision.rs | 4 + .../libm-test/tests/compare_built_musl.rs | 16 +++ .../libm/crates/util/src/main.rs | 16 +++ .../libm/etc/function-definitions.json | 112 ++++++++++++++++++ .../libm/etc/function-list.txt | 16 +++ .../compiler-builtins/libm/src/libm_helper.rs | 18 ++- .../libm/src/math/fmin_fmax.rs | 24 ++++ .../libm/src/math/fminimum_fmaximum.rs | 67 +++++++++++ .../libm/src/math/fminimum_fmaximum_num.rs | 67 +++++++++++ .../libm/src/math/generic/fmax.rs | 77 ++++++++++-- .../libm/src/math/generic/fmaximum.rs | 78 ++++++++++++ .../libm/src/math/generic/fmaximum_num.rs | 77 ++++++++++++ .../libm/src/math/generic/fmin.rs | 77 ++++++++++-- .../libm/src/math/generic/fminimum.rs | 78 ++++++++++++ .../libm/src/math/generic/fminimum_num.rs | 77 ++++++++++++ .../libm/src/math/generic/mod.rs | 8 ++ .../compiler-builtins/libm/src/math/mod.rs | 14 ++- 23 files changed, 997 insertions(+), 31 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs create mode 100644 library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/fmaximum.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/fminimum.rs create mode 100644 library/compiler-builtins/libm/src/math/generic/fminimum_num.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index 48d19c50d19a8..cb5a1d1873404 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -47,7 +47,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16] }, None, - &["copysignf16", "fdimf16", "fmaxf16", "fminf16", "fmodf16"], + &[ + "copysignf16", + "fdimf16", + "fmaxf16", + "fmaximum_numf16", + "fmaximumf16", + "fminf16", + "fminimum_numf16", + "fminimumf16", + "fmodf16", + ], ), ( // `(f32, f32) -> f32` @@ -59,7 +69,11 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "copysignf", "fdimf", "fmaxf", + "fmaximum_numf", + "fmaximumf", "fminf", + "fminimum_numf", + "fminimumf", "fmodf", "hypotf", "nextafterf", @@ -77,7 +91,11 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "copysign", "fdim", "fmax", + "fmaximum", + "fmaximum_num", "fmin", + "fminimum", + "fminimum_num", "fmod", "hypot", "nextafter", @@ -90,7 +108,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F128, Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128] }, None, - &["copysignf128", "fdimf128", "fmaxf128", "fminf128", "fmodf128"], + &[ + "copysignf128", + "fdimf128", + "fmaxf128", + "fmaximum_numf128", + "fmaximumf128", + "fminf128", + "fminimum_numf128", + "fminimumf128", + "fmodf128", + ], ), ( // `(f32, f32, f32) -> f32` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index be85dd5676c2f..e28f4973cb084 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -207,10 +207,26 @@ main!( 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, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 6e8a334795a27..6f6b05d959619 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -130,8 +130,24 @@ libm_macros::for_each_function! { | fmaf128 | fmaxf128 | fmaxf16 + | fmaximum + | fmaximum_num + | fmaximum_numf + | fmaximum_numf128 + | fmaximum_numf16 + | fmaximumf + | fmaximumf128 + | fmaximumf16 | fminf128 | fminf16 + | fminimum + | fminimum_num + | fminimum_numf + | fminimum_numf128 + | fminimum_numf16 + | fminimumf + | fminimumf128 + | fminimumf16 | fmodf128 | fmodf16 | ldexpf128 diff --git a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs index 5d650c00a3bd3..c662e95b4b47f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs @@ -221,7 +221,11 @@ pub fn get_domain( BaseName::Floor => &EitherPrim::UNBOUNDED1[..], BaseName::Fma => &EitherPrim::UNBOUNDED3[..], BaseName::Fmax => &EitherPrim::UNBOUNDED2[..], + BaseName::Fmaximum => &EitherPrim::UNBOUNDED2[..], + BaseName::FmaximumNum => &EitherPrim::UNBOUNDED2[..], BaseName::Fmin => &EitherPrim::UNBOUNDED2[..], + BaseName::Fminimum => &EitherPrim::UNBOUNDED2[..], + BaseName::FminimumNum => &EitherPrim::UNBOUNDED2[..], BaseName::Fmod => &EitherPrim::UNBOUNDED2[..], BaseName::Hypot => &EitherPrim::UNBOUNDED2[..], BaseName::Ilogb => &EitherPrim::UNBOUNDED1[..], diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs index 23226d5c25101..49e731b88b744 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs @@ -293,7 +293,8 @@ fn fmaf128_cases() -> Vec> { v } -fn fmax_cases() -> Vec> { +#[cfg(f16_enabled)] +fn fmaxf16_cases() -> Vec> { vec![] } @@ -301,17 +302,53 @@ fn fmaxf_cases() -> Vec> { vec![] } +fn fmax_cases() -> Vec> { + vec![] +} + #[cfg(f128_enabled)] fn fmaxf128_cases() -> Vec> { vec![] } #[cfg(f16_enabled)] -fn fmaxf16_cases() -> Vec> { +fn fmaximumf16_cases() -> Vec> { vec![] } -fn fmin_cases() -> Vec> { +fn fmaximumf_cases() -> Vec> { + vec![] +} + +fn fmaximum_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fmaximumf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fmaximum_numf16_cases() -> Vec> { + vec![] +} + +fn fmaximum_numf_cases() -> Vec> { + vec![] +} + +fn fmaximum_num_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fmaximum_numf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fminf16_cases() -> Vec> { vec![] } @@ -319,13 +356,48 @@ fn fminf_cases() -> Vec> { vec![] } +fn fmin_cases() -> Vec> { + vec![] +} + #[cfg(f128_enabled)] fn fminf128_cases() -> Vec> { vec![] } #[cfg(f16_enabled)] -fn fminf16_cases() -> Vec> { +fn fminimumf16_cases() -> Vec> { + vec![] +} + +fn fminimumf_cases() -> Vec> { + vec![] +} + +fn fminimum_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fminimumf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn fminimum_numf16_cases() -> Vec> { + vec![] +} + +fn fminimum_numf_cases() -> Vec> { + vec![] +} + +fn fminimum_num_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn fminimum_numf128_cases() -> Vec> { vec![] } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index f4a9ff7ffd5dc..63cdebe4eeeae 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -148,6 +148,14 @@ libm_macros::for_each_function! { floorf, floorf128, floorf16, + fmaximum, + fmaximumf, + fmaximumf128, + fmaximumf16, + fminimum, + fminimumf, + fminimumf128, + fminimumf16, fmod, fmodf, fmodf128, @@ -197,8 +205,10 @@ libm_macros::for_each_function! { fabs | fabsf => abs, fdim | fdimf | fdimf16 | fdimf128 => positive_diff, fma | fmaf | fmaf128 => mul_add, - fmax | fmaxf | fmaxf16 | fmaxf128 => max, - fmin | fminf | fminf16 | fminf128 => min, + fmax | fmaxf | fmaxf16 | fmaxf128 | + fmaximum_num | fmaximum_numf | fmaximum_numf16 | fmaximum_numf128 => max, + fmin | fminf | fminf16 | fminf128 | + fminimum_num | fminimum_numf | fminimum_numf16 | fminimum_numf128 => min, lgamma | lgammaf => ln_gamma, log | logf => ln, log1p | log1pf => ln_1p, @@ -446,6 +456,46 @@ macro_rules! impl_op_for_ty_all { } } + impl MpOp for crate::op::[< fmaximum $suffix >]::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 = if this.0.is_nan() || this.1.is_nan() { + this.0.assign($fty::NAN); + Ordering::Equal + } else { + this.0.max_round(&this.1, Nearest) + }; + prep_retval::(&mut this.0, ord) + } + } + + impl MpOp for crate::op::[< fminimum $suffix >]::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 = if this.0.is_nan() || this.1.is_nan() { + this.0.assign($fty::NAN); + Ordering::Equal + } else { + this.0.min_round(&this.1, Nearest) + }; + prep_retval::(&mut this.0, ord) + } + } + // `ldexp` and `scalbn` are the same for binary floating point, so just forward all // methods. impl MpOp for crate::op::[]::Routine { diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 2f55ad22ec760..1d916e5726a8e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -25,7 +25,11 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { | Bn::Floor | Bn::Fma | Bn::Fmax + | Bn::Fmaximum + | Bn::FmaximumNum | Bn::Fmin + | Bn::Fminimum + | Bn::FminimumNum | Bn::Fmod | Bn::Frexp | Bn::Ilogb diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 7fa77e832b176..ffd7f1f60c667 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -102,8 +102,24 @@ libm_macros::for_each_function! { fmaf128, fmaxf128, fmaxf16, + fmaximum, + fmaximum_num, + fmaximum_numf, + fmaximum_numf128, + fmaximum_numf16, + fmaximumf, + fmaximumf128, + fmaximumf16, fminf128, fminf16, + fminimum, + fminimum_num, + fminimum_numf, + fminimum_numf128, + fminimum_numf16, + fminimumf, + fminimumf128, + fminimumf16, fmodf128, fmodf16, ldexpf128, diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index 0f845a1c4d0da..a519713c0b1c3 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -99,8 +99,24 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | fmaf128 | fmaxf128 | fmaxf16 + | fmaximum + | fmaximum_num + | fmaximum_numf + | fmaximum_numf128 + | fmaximum_numf16 + | fmaximumf + | fmaximumf128 + | fmaximumf16 | fminf128 | fminf16 + | fminimum + | fminimum_num + | fminimum_numf + | fminimum_numf128 + | fminimum_numf16 + | fminimumf + | fminimumf128 + | fminimumf16 | fmodf128 | fmodf16 | ldexpf128 diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index d3e51f29a07cf..008a47df21974 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -391,6 +391,62 @@ ], "type": "f16" }, + "fmaximum": { + "sources": [ + "src/math/fminimum_fmaximum.rs", + "src/math/generic/fmaximum.rs" + ], + "type": "f64" + }, + "fmaximum_num": { + "sources": [ + "src/math/fminimum_fmaximum_num.rs", + "src/math/generic/fmaximum_num.rs" + ], + "type": "f64" + }, + "fmaximum_numf": { + "sources": [ + "src/math/fminimum_fmaximum_num.rs", + "src/math/generic/fmaximum_num.rs" + ], + "type": "f32" + }, + "fmaximum_numf128": { + "sources": [ + "src/math/fminimum_fmaximum_num.rs", + "src/math/generic/fmaximum_num.rs" + ], + "type": "f128" + }, + "fmaximum_numf16": { + "sources": [ + "src/math/fminimum_fmaximum_num.rs", + "src/math/generic/fmaximum_num.rs" + ], + "type": "f16" + }, + "fmaximumf": { + "sources": [ + "src/math/fminimum_fmaximum.rs", + "src/math/generic/fmaximum.rs" + ], + "type": "f32" + }, + "fmaximumf128": { + "sources": [ + "src/math/fminimum_fmaximum.rs", + "src/math/generic/fmaximum.rs" + ], + "type": "f128" + }, + "fmaximumf16": { + "sources": [ + "src/math/fminimum_fmaximum.rs", + "src/math/generic/fmaximum.rs" + ], + "type": "f16" + }, "fmin": { "sources": [ "src/math/fmin_fmax.rs", @@ -419,6 +475,62 @@ ], "type": "f16" }, + "fminimum": { + "sources": [ + "src/math/fminimum_fmaximum.rs", + "src/math/generic/fminimum.rs" + ], + "type": "f64" + }, + "fminimum_num": { + "sources": [ + "src/math/fminimum_fmaximum_num.rs", + "src/math/generic/fminimum_num.rs" + ], + "type": "f64" + }, + "fminimum_numf": { + "sources": [ + "src/math/fminimum_fmaximum_num.rs", + "src/math/generic/fminimum_num.rs" + ], + "type": "f32" + }, + "fminimum_numf128": { + "sources": [ + "src/math/fminimum_fmaximum_num.rs", + "src/math/generic/fminimum_num.rs" + ], + "type": "f128" + }, + "fminimum_numf16": { + "sources": [ + "src/math/fminimum_fmaximum_num.rs", + "src/math/generic/fminimum_num.rs" + ], + "type": "f16" + }, + "fminimumf": { + "sources": [ + "src/math/fminimum_fmaximum.rs", + "src/math/generic/fminimum.rs" + ], + "type": "f32" + }, + "fminimumf128": { + "sources": [ + "src/math/fminimum_fmaximum.rs", + "src/math/generic/fminimum.rs" + ], + "type": "f128" + }, + "fminimumf16": { + "sources": [ + "src/math/fminimum_fmaximum.rs", + "src/math/generic/fminimum.rs" + ], + "type": "f16" + }, "fmod": { "sources": [ "src/math/fmod.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 1c9c5e3bc337c..90ca8f34e62e2 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -58,10 +58,26 @@ fmax fmaxf fmaxf128 fmaxf16 +fmaximum +fmaximum_num +fmaximum_numf +fmaximum_numf128 +fmaximum_numf16 +fmaximumf +fmaximumf128 +fmaximumf16 fmin fminf fminf128 fminf16 +fminimum +fminimum_num +fminimum_numf +fminimum_numf128 +fminimum_numf16 +fminimumf +fminimumf128 +fminimumf16 fmod fmodf fmodf128 diff --git a/library/compiler-builtins/libm/src/libm_helper.rs b/library/compiler-builtins/libm/src/libm_helper.rs index 68f1fb362666d..489dbc0d4df18 100644 --- a/library/compiler-builtins/libm/src/libm_helper.rs +++ b/library/compiler-builtins/libm/src/libm_helper.rs @@ -137,7 +137,15 @@ libm_helper! { (fn floor(x: f64) -> (f64); => floor); (fn fma(x: f64, y: f64, z: f64) -> (f64); => fma); (fn fmax(x: f64, y: f64) -> (f64); => fmax); + (fn fmaximum(x: f64, y: f64) -> (f64); => fmaximum); + (fn fmaximum_num(x: f64, y: f64) -> (f64); => fmaximum_num); + (fn fmaximum_numf(x: f32, y: f32) -> (f32); => fmaximum_numf); + (fn fmaximumf(x: f32, y: f32) -> (f32); => fmaximumf); (fn fmin(x: f64, y: f64) -> (f64); => fmin); + (fn fminimum(x: f64, y: f64) -> (f64); => fminimum); + (fn fminimum_num(x: f64, y: f64) -> (f64); => fminimum_num); + (fn fminimum_numf(x: f32, y: f32) -> (f32); => fminimum_numf); + (fn fminimumf(x: f32, y: f32) -> (f32); => fminimumf); (fn fmod(x: f64, y: f64) -> (f64); => fmod); (fn frexp(x: f64) -> (f64, i32); => frexp); (fn hypot(x: f64, y: f64) -> (f64); => hypot); @@ -186,7 +194,11 @@ libm_helper! { (fn fdim(x: f16, y: f16) -> (f16); => fdimf16); (fn floorf(x: f16) -> (f16); => floorf16); (fn fmaxf(x: f16, y: f16) -> (f16); => fmaxf16); + (fn fmaximum_numf16(x: f16, y: f16) -> (f16); => fmaximum_numf16); + (fn fmaximumf16(x: f16, y: f16) -> (f16); => fmaximumf16); (fn fminf(x: f16, y: f16) -> (f16); => fminf16); + (fn fminimum_numf16(x: f16, y: f16) -> (f16); => fminimum_numf16); + (fn fminimumf16(x: f16, y: f16) -> (f16); => fminimumf16); (fn fmodf(x: f16, y: f16) -> (f16); => fmodf16); (fn ldexpf16(x: f16, n: i32) -> (f16); => ldexpf16); (fn rintf(x: f16) -> (f16); => rintf16); @@ -208,9 +220,13 @@ libm_helper! { (fn fabs(x: f128) -> (f128); => fabsf128); (fn fdim(x: f128, y: f128) -> (f128); => fdimf128); (fn floor(x: f128) -> (f128); => floorf128); - (fn fmaf128(x: f128, y: f128, z: f128) -> (f128); => fmaf128); + (fn fmaf128(x: f128, y: f128, z: f128) -> (f128); => fmaf128); (fn fmax(x: f128, y: f128) -> (f128); => fmaxf128); + (fn fmaximum_numf128(x: f128, y: f128) -> (f128); => fmaximum_numf128); + (fn fmaximumf128(x: f128, y: f128) -> (f128); => fmaximumf128); (fn fmin(x: f128, y: f128) -> (f128); => fminf128); + (fn fminimum_numf128(x: f128, y: f128) -> (f128); => fminimum_numf128); + (fn fminimumf128(x: f128, y: f128) -> (f128); => fminimumf128); (fn fmod(x: f128, y: f128) -> (f128); => fmodf128); (fn ldexpf128(x: f128, n: i32) -> (f128); => ldexpf128); (fn rint(x: f128) -> (f128); => rintf128); diff --git a/library/compiler-builtins/libm/src/math/fmin_fmax.rs b/library/compiler-builtins/libm/src/math/fmin_fmax.rs index 97912e7582663..4f9136dbbcd44 100644 --- a/library/compiler-builtins/libm/src/math/fmin_fmax.rs +++ b/library/compiler-builtins/libm/src/math/fmin_fmax.rs @@ -1,4 +1,7 @@ /// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). #[cfg(f16_enabled)] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fminf16(x: f16, y: f16) -> f16 { @@ -6,18 +9,27 @@ pub fn fminf16(x: f16, y: f16) -> f16 { } /// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fminf(x: f32, y: f32) -> f32 { super::generic::fmin(x, y) } /// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmin(x: f64, y: f64) -> f64 { super::generic::fmin(x, y) } /// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `minNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). #[cfg(f128_enabled)] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fminf128(x: f128, y: f128) -> f128 { @@ -25,6 +37,9 @@ pub fn fminf128(x: f128, y: f128) -> f128 { } /// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). #[cfg(f16_enabled)] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmaxf16(x: f16, y: f16) -> f16 { @@ -32,18 +47,27 @@ pub fn fmaxf16(x: f16, y: f16) -> f16 { } /// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmaxf(x: f32, y: f32) -> f32 { super::generic::fmax(x, y) } /// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmax(x: f64, y: f64) -> f64 { super::generic::fmax(x, y) } /// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2011 `maxNum`. The result disregards signed zero (meaning if +/// the inputs are -0.0 and +0.0, either may be returned). #[cfg(f128_enabled)] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmaxf128(x: f128, y: f128) -> f128 { diff --git a/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs b/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs new file mode 100644 index 0000000000000..fd3c5ed103911 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs @@ -0,0 +1,67 @@ +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimumf16(x: f16, y: f16) -> f16 { + super::generic::fminimum(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimum(x: f64, y: f64) -> f64 { + super::generic::fminimum(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimumf(x: f32, y: f32) -> f32 { + super::generic::fminimum(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimumf128(x: f128, y: f128) -> f128 { + super::generic::fminimum(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximumf16(x: f16, y: f16) -> f16 { + super::generic::fmaximum(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximumf(x: f32, y: f32) -> f32 { + super::generic::fmaximum(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximum(x: f64, y: f64) -> f64 { + super::generic::fmaximum(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +/// +/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximumf128(x: f128, y: f128) -> f128 { + super::generic::fmaximum(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs b/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs new file mode 100644 index 0000000000000..640ddfc9b6612 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs @@ -0,0 +1,67 @@ +/// Return the lesser of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimum_numf16(x: f16, y: f16) -> f16 { + super::generic::fminimum_num(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimum_numf(x: f32, y: f32) -> f32 { + super::generic::fminimum_num(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimum_num(x: f64, y: f64) -> f64 { + super::generic::fminimum_num(x, y) +} + +/// Return the lesser of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminimum_numf128(x: f128, y: f128) -> f128 { + super::generic::fminimum_num(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximum_numf16(x: f16, y: f16) -> f16 { + super::generic::fmaximum_num(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximum_numf(x: f32, y: f32) -> f32 { + super::generic::fmaximum_num(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximum_num(x: f64, y: f64) -> f64 { + super::generic::fmaximum_num(x, y) +} + +/// Return the greater of two arguments or, if either argument is NaN, NaN. +/// +/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaximum_numf128(x: f128, y: f128) -> f128 { + super::generic::fmaximum_num(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/generic/fmax.rs b/library/compiler-builtins/libm/src/math/generic/fmax.rs index 97803052bc27a..32613a46b9372 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmax.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmax.rs @@ -1,14 +1,73 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +//! IEEE 754-2011 `maxNum`. This has been superseded by IEEE 754-2019 `maximumNumber`. +//! +//! Per the spec, returns the canonicalized result of: +//! - `x` if `x > y` +//! - `y` if `y > x` +//! - The other number if one is NaN +//! - Otherwise, either `x` or `y`, canonicalized +//! - -0.0 and +0.0 may be disregarded (unlike newer operations) +//! +//! Excluded from our implementation is sNaN handling. +//! +//! More on the differences: [link]. +//! +//! [link]: https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/minNum_maxNum_Removal_Demotion_v3.pdf + use super::super::Float; #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmax(x: F, y: F) -> F { - // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if x.is_nan() || x < y { y } else { x }) * F::ONE + let res = if x.is_nan() || x < y { y } else { x }; + // Canonicalize + res * F::ONE +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Hexf, Int}; + + fn spec_test() { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ONE), + (F::ONE, F::ZERO, F::ONE), + (F::ZERO, F::NEG_ONE, F::ZERO), + (F::NEG_ONE, F::ZERO, F::ZERO), + (F::INFINITY, F::ZERO, F::INFINITY), + (F::NEG_INFINITY, F::ZERO, F::ZERO), + (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NAN, F::NAN), + ]; + + for (x, y, res) in cases { + let val = fmax(x, y); + assert_biteq!(val, res, "fmax({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(); + } + + #[test] + fn spec_tests_f32() { + spec_test::(); + } + + #[test] + fn spec_tests_f64() { + spec_test::(); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(); + } } diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs new file mode 100644 index 0000000000000..5f653ce94e282 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +//! IEEE 754-2019 `maximum`. +//! +//! Per the spec, returns the canonicalized result of: +//! - `x` if `x > y` +//! - `y` if `y > x` +//! - qNaN if either operation is NaN +//! - Logic following +0.0 > -0.0 +//! +//! Excluded from our implementation is sNaN handling. + +use super::super::Float; + +pub fn fmaximum(x: F, y: F) -> F { + let res = if x.is_nan() { + x + } else if y.is_nan() { + y + } else if x > y || (y.to_bits() == F::NEG_ZERO.to_bits() && x.is_sign_positive()) { + x + } else { + y + }; + + // Canonicalize + res * F::ONE +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Hexf, Int}; + + fn spec_test() { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ONE), + (F::ONE, F::ZERO, F::ONE), + (F::ZERO, F::NEG_ONE, F::ZERO), + (F::NEG_ONE, F::ZERO, F::ZERO), + (F::INFINITY, F::ZERO, F::INFINITY), + (F::NEG_INFINITY, F::ZERO, F::ZERO), + (F::NAN, F::ZERO, F::NAN), + (F::ZERO, F::NAN, F::NAN), + (F::NAN, F::NAN, F::NAN), + (F::ZERO, F::NEG_ZERO, F::ZERO), + (F::NEG_ZERO, F::ZERO, F::ZERO), + ]; + + for (x, y, res) in cases { + let val = fmaximum(x, y); + assert_biteq!(val, res, "fmaximum({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(); + } + + #[test] + fn spec_tests_f32() { + spec_test::(); + } + + #[test] + fn spec_tests_f64() { + spec_test::(); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(); + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs new file mode 100644 index 0000000000000..2246601239214 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +//! IEEE 754-2019 `maximumNumber`. +//! +//! Per the spec, returns: +//! - `x` if `x > y` +//! - `y` if `y > x` +//! - Non-NaN if one operand is NaN +//! - Logic following +0.0 > -0.0 +//! - Either `x` or `y` if `x == y` and the signs are the same +//! - qNaN if either operand is a NaN +//! +//! Excluded from our implementation is sNaN handling. + +use super::super::Float; + +pub fn fmaximum_num(x: F, y: F) -> F { + let res = + if x.is_nan() || x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { + y + } else { + x + }; + + // Canonicalize + res * F::ONE +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Hexf, Int}; + + fn spec_test() { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ONE), + (F::ONE, F::ZERO, F::ONE), + (F::ZERO, F::NEG_ONE, F::ZERO), + (F::NEG_ONE, F::ZERO, F::ZERO), + (F::INFINITY, F::ZERO, F::INFINITY), + (F::NEG_INFINITY, F::ZERO, F::ZERO), + (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NAN, F::NAN), + (F::ZERO, F::NEG_ZERO, F::ZERO), + (F::NEG_ZERO, F::ZERO, F::ZERO), + ]; + + for (x, y, res) in cases { + let val = fmaximum_num(x, y); + assert_biteq!(val, res, "fmaximum_num({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(); + } + + #[test] + fn spec_tests_f32() { + spec_test::(); + } + + #[test] + fn spec_tests_f64() { + spec_test::(); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(); + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/fmin.rs b/library/compiler-builtins/libm/src/math/generic/fmin.rs index 697f720048603..5cc33e904edf8 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmin.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmin.rs @@ -1,13 +1,72 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +//! IEEE 754-2008 `minNum`. This has been superseded by IEEE 754-2019 `minimumNumber`. +//! +//! Per the spec, returns the canonicalized result of: +//! - `x` if `x < y` +//! - `y` if `y < x` +//! - The other number if one is NaN +//! - Otherwise, either `x` or `y`, canonicalized +//! - -0.0 and +0.0 may be disregarded (unlike newer operations) +//! +//! Excluded from our implementation is sNaN handling. +//! +//! More on the differences: [link]. +//! +//! [link]: https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/minNum_maxNum_Removal_Demotion_v3.pdf + use super::super::Float; pub fn fmin(x: F, y: F) -> F { - // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if y.is_nan() || x < y { x } else { y }) * F::ONE + let res = if y.is_nan() || x < y { x } else { y }; + // Canonicalize + res * F::ONE +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Hexf, Int}; + + fn spec_test() { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ZERO), + (F::ONE, F::ZERO, F::ZERO), + (F::ZERO, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::ZERO, F::NEG_ONE), + (F::INFINITY, F::ZERO, F::ZERO), + (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), + (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NAN, F::NAN), + ]; + + for (x, y, res) in cases { + let val = fmin(x, y); + assert_biteq!(val, res, "fmin({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(); + } + + #[test] + fn spec_tests_f32() { + spec_test::(); + } + + #[test] + fn spec_tests_f64() { + spec_test::(); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(); + } } diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum.rs b/library/compiler-builtins/libm/src/math/generic/fminimum.rs new file mode 100644 index 0000000000000..f566d9631d3a3 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fminimum.rs @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +//! IEEE 754-2019 `minimum`. +//! +//! Per the spec, returns the canonicalized result of: +//! - `x` if `x < y` +//! - `y` if `y < x` +//! - qNaN if either operation is NaN +//! - Logic following +0.0 > -0.0 +//! +//! Excluded from our implementation is sNaN handling. + +use super::super::Float; + +pub fn fminimum(x: F, y: F) -> F { + let res = if x.is_nan() { + x + } else if y.is_nan() { + y + } else if x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { + x + } else { + y + }; + + // Canonicalize + res * F::ONE +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Hexf, Int}; + + fn spec_test() { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ZERO), + (F::ONE, F::ZERO, F::ZERO), + (F::ZERO, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::ZERO, F::NEG_ONE), + (F::INFINITY, F::ZERO, F::ZERO), + (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), + (F::NAN, F::ZERO, F::NAN), + (F::ZERO, F::NAN, F::NAN), + (F::NAN, F::NAN, F::NAN), + (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), + ]; + + for (x, y, res) in cases { + let val = fminimum(x, y); + assert_biteq!(val, res, "fminimum({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(); + } + + #[test] + fn spec_tests_f32() { + spec_test::(); + } + + #[test] + fn spec_tests_f64() { + spec_test::(); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(); + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs new file mode 100644 index 0000000000000..e58a585c329c5 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ +//! IEEE 754-2019 `minimum`. +//! +//! Per the spec, returns: +//! - `x` if `x < y` +//! - `y` if `y < x` +//! - Non-NaN if one operand is NaN +//! - Logic following +0.0 > -0.0 +//! - Either `x` or `y` if `x == y` and the signs are the same +//! - qNaN if either operand is a NaN +//! +//! Excluded from our implementation is sNaN handling. + +use super::super::Float; + +pub fn fminimum_num(x: F, y: F) -> F { + let res = + if y.is_nan() || x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { + x + } else { + y + }; + + // Canonicalize + res * F::ONE +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Hexf, Int}; + + fn spec_test() { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ZERO), + (F::ONE, F::ZERO, F::ZERO), + (F::ZERO, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::ZERO, F::NEG_ONE), + (F::INFINITY, F::ZERO, F::ZERO), + (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), + (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NAN, F::NAN), + (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), + ]; + + for (x, y, res) in cases { + let val = fminimum_num(x, y); + assert_biteq!(val, res, "fminimum_num({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(); + } + + #[test] + fn spec_tests_f32() { + spec_test::(); + } + + #[test] + fn spec_tests_f64() { + spec_test::(); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(); + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index b34d3dfae945c..092f9317bc57a 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -5,7 +5,11 @@ mod fdim; mod floor; mod fma; mod fmax; +mod fmaximum; +mod fmaximum_num; mod fmin; +mod fminimum; +mod fminimum_num; mod fmod; mod rint; mod round; @@ -20,7 +24,11 @@ pub use fdim::fdim; pub use floor::floor; pub use fma::{fma, fma_wide}; pub use fmax::fmax; +pub use fmaximum::fmaximum; +pub use fmaximum_num::fmaximum_num; pub use fmin::fmin; +pub use fminimum::fminimum; +pub use fminimum_num::fminimum_num; pub use fmod::fmod; pub use rint::rint; pub use round::round; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index ba0b933f17c81..4e75292a6ef16 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -166,6 +166,8 @@ mod floorf; mod fma; mod fmaf; mod fmin_fmax; +mod fminimum_fmaximum; +mod fminimum_fmaximum_num; mod fmod; mod fmodf; mod frexp; @@ -271,6 +273,8 @@ pub use self::floorf::floorf; pub use self::fma::fma; pub use self::fmaf::fmaf; pub use self::fmin_fmax::{fmax, fmaxf, fmin, fminf}; +pub use self::fminimum_fmaximum::{fmaximum, fmaximumf, fminimum, fminimumf}; +pub use self::fminimum_fmaximum_num::{fmaximum_num, fmaximum_numf, fminimum_num, fminimum_numf}; pub use self::fmod::fmod; pub use self::fmodf::fmodf; pub use self::frexp::frexp; @@ -355,8 +359,9 @@ cfg_if! { pub use self::fabsf16::fabsf16; pub use self::fdimf16::fdimf16; pub use self::floorf16::floorf16; - pub use self::fmin_fmax::fmaxf16; - pub use self::fmin_fmax::fminf16; + pub use self::fmin_fmax::{fmaxf16, fminf16}; + pub use self::fminimum_fmaximum::{fmaximumf16, fminimumf16}; + pub use self::fminimum_fmaximum_num::{fmaximum_numf16, fminimum_numf16}; pub use self::fmodf16::fmodf16; pub use self::ldexpf16::ldexpf16; pub use self::rintf16::rintf16; @@ -393,8 +398,9 @@ cfg_if! { pub use self::fdimf128::fdimf128; pub use self::floorf128::floorf128; pub use self::fmaf128::fmaf128; - pub use self::fmin_fmax::fmaxf128; - pub use self::fmin_fmax::fminf128; + pub use self::fmin_fmax::{fmaxf128, fminf128}; + pub use self::fminimum_fmaximum::{fmaximumf128, fminimumf128}; + pub use self::fminimum_fmaximum_num::{fmaximum_numf128, fminimum_numf128}; pub use self::fmodf128::fmodf128; pub use self::ldexpf128::ldexpf128; pub use self::rintf128::rintf128; From e79fb05b2554aa641425e9e7aa5ec70e483b6427 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 10 Feb 2025 21:42:26 +0000 Subject: [PATCH 1676/4206] Increase allowed offset from infinity for ynf Failed with called `Result::unwrap()` on an `Err` value: ynf Caused by: 0: input: (223, 116.89665) as hex: (, 0x1.d3962cp+6) as bits: (0x000000df, 0x42e9cb16) expected: -3.1836905e38 -0x1.df074cp+127 0xff6f83a6 actual: -inf -inf 0xff800000 1: mismatched infinities --- .../compiler-builtins/libm/crates/libm-test/src/precision.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 1d916e5726a8e..8b08925469e5e 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -537,7 +537,7 @@ fn int_float_common( && !expected.is_infinite() && actual.is_infinite() && (expected.abs().to_bits().abs_diff(actual.abs().to_bits()) - < F2::Int::cast_from(1_000_000u32)) + < F2::Int::cast_from(10_000_000u32)) { return XFAIL_NOCHECK; } From 2a3ef8b9a2365365aae80419a9bbac0bddf64c71 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 11 Feb 2025 02:17:06 +0000 Subject: [PATCH 1677/4206] Fix parsing of negative hex float literals in util --- library/compiler-builtins/libm/crates/util/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index a519713c0b1c3..710adbb17945d 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -274,7 +274,7 @@ fn parse(input: &[&str], idx: usize) -> T { let msg = || format!("invalid {} input '{s}'", type_name::()); - if s.starts_with("0x") { + if s.starts_with("0x") || s.starts_with("-0x") { return T::from_str_radix(s, 16).unwrap_or_else(|_| panic!("{}", msg())); } From 53a055049cde50f6a42cf3cb5a7826142ea396e0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 11 Feb 2025 00:17:32 +0000 Subject: [PATCH 1678/4206] Add `roundeven{,f,f16,f128}` C23 specifies a new set of `roundeven` functions that round to the nearest integral, with ties to even. It does not raise any floating point exceptions. This behavior is similar to two other functions: 1. `rint`, which rounds to the nearest integer respecting rounding mode and possibly raising exceptions. 2. `nearbyint`, which is identical to `rint` except it may not raise exceptions. Technically `rint`, `nearbyint`, and `roundeven` all behave the same in Rust because we assume default floating point environment. The backends are allowed to lower to `roundeven`, however, so we should provide it in case the fallback is needed. Add the `roundeven` family here and convert `rint` to a function that takes a rounding mode. This currently has no effect. --- .../libm/crates/libm-macros/src/shared.rs | 104 +++++++++++++++-- .../libm/crates/libm-test/benches/icount.rs | 4 + .../libm/crates/libm-test/benches/random.rs | 4 + .../libm/crates/libm-test/src/domain.rs | 1 + .../crates/libm-test/src/gen/case_list.rs | 39 ++++++- .../libm/crates/libm-test/src/mpfloat.rs | 8 ++ .../libm/crates/libm-test/src/precision.rs | 3 +- .../libm-test/tests/compare_built_musl.rs | 4 + .../libm/crates/util/src/main.rs | 4 + .../libm/etc/function-definitions.json | 34 ++++-- .../libm/etc/function-list.txt | 4 + .../compiler-builtins/libm/src/libm_helper.rs | 42 +++---- .../libm/src/math/generic/mod.rs | 2 +- .../libm/src/math/generic/rint.rs | 105 +++++++++++++----- .../compiler-builtins/libm/src/math/mod.rs | 14 +-- .../compiler-builtins/libm/src/math/rint.rs | 33 +++++- .../compiler-builtins/libm/src/math/rintf.rs | 14 --- .../libm/src/math/rintf128.rs | 5 - .../libm/src/math/rintf16.rs | 5 - .../libm/src/math/roundeven.rs | 35 ++++++ 20 files changed, 363 insertions(+), 101 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/rintf.rs delete mode 100644 library/compiler-builtins/libm/src/math/rintf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/rintf16.rs create mode 100644 library/compiler-builtins/libm/src/math/roundeven.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index cb5a1d1873404..5e58220eb3984 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -9,7 +9,16 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16], returns: &[Ty::F16] }, None, - &["ceilf16", "fabsf16", "floorf16", "rintf16", "roundf16", "sqrtf16", "truncf16"], + &[ + "ceilf16", + "fabsf16", + "floorf16", + "rintf16", + "roundevenf16", + "roundf16", + "sqrtf16", + "truncf16", + ], ), ( // `fn(f32) -> f32` @@ -17,10 +26,43 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] Signature { args: &[Ty::F32], returns: &[Ty::F32] }, None, &[ - "acosf", "acoshf", "asinf", "asinhf", "atanf", "atanhf", "cbrtf", "ceilf", "cosf", - "coshf", "erfcf", "erff", "exp10f", "exp2f", "expf", "expm1f", "fabsf", "floorf", - "j0f", "j1f", "lgammaf", "log10f", "log1pf", "log2f", "logf", "rintf", "roundf", - "sinf", "sinhf", "sqrtf", "tanf", "tanhf", "tgammaf", "truncf", "y0f", "y1f", + "acosf", + "acoshf", + "asinf", + "asinhf", + "atanf", + "atanhf", + "cbrtf", + "ceilf", + "cosf", + "coshf", + "erfcf", + "erff", + "exp10f", + "exp2f", + "expf", + "expm1f", + "fabsf", + "floorf", + "j0f", + "j1f", + "lgammaf", + "log10f", + "log1pf", + "log2f", + "logf", + "rintf", + "roundevenf", + "roundf", + "sinf", + "sinhf", + "sqrtf", + "tanf", + "tanhf", + "tgammaf", + "truncf", + "y0f", + "y1f", ], ), ( @@ -29,10 +71,43 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] Signature { args: &[Ty::F64], returns: &[Ty::F64] }, None, &[ - "acos", "acosh", "asin", "asinh", "atan", "atanh", "cbrt", "ceil", "cos", "cosh", - "erf", "erfc", "exp", "exp10", "exp2", "expm1", "fabs", "floor", "j0", "j1", "lgamma", - "log", "log10", "log1p", "log2", "rint", "round", "sin", "sinh", "sqrt", "tan", "tanh", - "tgamma", "trunc", "y0", "y1", + "acos", + "acosh", + "asin", + "asinh", + "atan", + "atanh", + "cbrt", + "ceil", + "cos", + "cosh", + "erf", + "erfc", + "exp", + "exp10", + "exp2", + "expm1", + "fabs", + "floor", + "j0", + "j1", + "lgamma", + "log", + "log10", + "log1p", + "log2", + "rint", + "round", + "roundeven", + "sin", + "sinh", + "sqrt", + "tan", + "tanh", + "tgamma", + "trunc", + "y0", + "y1", ], ), ( @@ -40,7 +115,16 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F128, Signature { args: &[Ty::F128], returns: &[Ty::F128] }, None, - &["ceilf128", "fabsf128", "floorf128", "rintf128", "roundf128", "sqrtf128", "truncf128"], + &[ + "ceilf128", + "fabsf128", + "floorf128", + "rintf128", + "roundevenf128", + "roundf128", + "sqrtf128", + "truncf128", + ], ), ( // `(f16, f16) -> f16` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index e28f4973cb084..4a10ec383ae80 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -274,6 +274,10 @@ main!( 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, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 6f6b05d959619..17e4e0d55fc54 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -154,6 +154,10 @@ libm_macros::for_each_function! { | ldexpf16 | rintf128 | rintf16 + | roundeven + | roundevenf + | roundevenf128 + | roundevenf16 | roundf128 | roundf16 | scalbnf128 diff --git a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs index c662e95b4b47f..41e948461634d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/domain.rs @@ -246,6 +246,7 @@ pub fn get_domain( BaseName::Remquo => &EitherPrim::UNBOUNDED2[..], BaseName::Rint => &EitherPrim::UNBOUNDED1[..], BaseName::Round => &EitherPrim::UNBOUNDED1[..], + BaseName::Roundeven => &EitherPrim::UNBOUNDED1[..], BaseName::Scalbn => &EitherPrim::UNBOUNDED_F_I[..], BaseName::Sin => &EitherPrim::TRIG[..], BaseName::Sincos => &EitherPrim::TRIG[..], diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs index 49e731b88b744..8c7a735fa707d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs @@ -6,6 +6,7 @@ //! //! This is useful for adding regression tests or expected failures. +use libm::hf64; #[cfg(f128_enabled)] use libm::hf128; @@ -574,7 +575,15 @@ fn remquof_cases() -> Vec> { } fn rint_cases() -> Vec> { - vec![] + let mut v = vec![]; + TestCase::append_pairs( + &mut v, + &[ + // Failure on i586 + ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff994000p+38"))), + ], + ); + v } fn rintf_cases() -> Vec> { @@ -591,6 +600,11 @@ fn rintf16_cases() -> Vec> { vec![] } +#[cfg(f16_enabled)] +fn roundf16_cases() -> Vec> { + vec![] +} + fn round_cases() -> Vec> { vec![] } @@ -605,7 +619,28 @@ fn roundf128_cases() -> Vec> { } #[cfg(f16_enabled)] -fn roundf16_cases() -> Vec> { +fn roundevenf16_cases() -> Vec> { + vec![] +} + +fn roundeven_cases() -> Vec> { + let mut v = vec![]; + TestCase::append_pairs( + &mut v, + &[ + // Failure on i586 + ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff994000p+38"))), + ], + ); + v +} + +fn roundevenf_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn roundevenf128_cases() -> Vec> { vec![] } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 63cdebe4eeeae..9b51dc6051d03 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -184,6 +184,10 @@ libm_macros::for_each_function! { rintf128, rintf16, round, + roundeven, + roundevenf, + roundevenf128, + roundevenf16, roundf, roundf128, roundf16, @@ -253,6 +257,8 @@ impl_no_round! { rint => round_even_mut; // FIXME: respect rounding mode rintf => round_even_mut; // FIXME: respect rounding mode round => round_mut; + roundeven => round_even_mut; + roundevenf => round_even_mut; roundf => round_mut; trunc => trunc_mut; truncf => trunc_mut; @@ -265,6 +271,7 @@ impl_no_round! { floorf16 => floor_mut; rintf16 => round_even_mut; // FIXME: respect rounding mode roundf16 => round_mut; + roundevenf16 => round_even_mut; truncf16 => trunc_mut; } @@ -275,6 +282,7 @@ impl_no_round! { floorf128 => floor_mut; rintf128 => round_even_mut; // FIXME: respect rounding mode roundf128 => round_mut; + roundevenf128 => round_even_mut; truncf128 => trunc_mut; } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 8b08925469e5e..8916b43ab1729 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -40,6 +40,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { | Bn::Remquo | Bn::Rint | Bn::Round + | Bn::Roundeven | Bn::Scalbn | Bn::Sqrt | Bn::Trunc => 0, @@ -282,7 +283,7 @@ impl MaybeOverride<(f64,)> for SpecialCase { } if cfg!(x86_no_sse) - && ctx.base_name == BaseName::Rint + && (ctx.base_name == BaseName::Rint || ctx.base_name == BaseName::Roundeven) && (expected - actual).abs() <= F::ONE && (expected - actual).abs() > F::ZERO { diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index ffd7f1f60c667..2b16b9aa091b0 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -126,6 +126,10 @@ libm_macros::for_each_function! { ldexpf16, rintf128, rintf16, + roundeven, + roundevenf, + roundevenf128, + roundevenf16, roundf128, roundf16, scalbnf128, diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index 710adbb17945d..130ac45319bed 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -123,6 +123,10 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | ldexpf16 | rintf128 | rintf16 + | roundeven + | roundevenf + | roundevenf128 + | roundevenf16 | roundf128 | roundf16 | scalbnf128 diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 008a47df21974..a47aaad57c786 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -791,7 +791,6 @@ "sources": [ "src/math/arch/aarch64.rs", "src/math/arch/wasm32.rs", - "src/math/generic/rint.rs", "src/math/rint.rs" ], "type": "f64" @@ -800,22 +799,19 @@ "sources": [ "src/math/arch/aarch64.rs", "src/math/arch/wasm32.rs", - "src/math/generic/rint.rs", - "src/math/rintf.rs" + "src/math/rint.rs" ], "type": "f32" }, "rintf128": { "sources": [ - "src/math/generic/rint.rs", - "src/math/rintf128.rs" + "src/math/rint.rs" ], "type": "f128" }, "rintf16": { "sources": [ - "src/math/generic/rint.rs", - "src/math/rintf16.rs" + "src/math/rint.rs" ], "type": "f16" }, @@ -826,6 +822,30 @@ ], "type": "f64" }, + "roundeven": { + "sources": [ + "src/math/roundeven.rs" + ], + "type": "f64" + }, + "roundevenf": { + "sources": [ + "src/math/roundeven.rs" + ], + "type": "f32" + }, + "roundevenf128": { + "sources": [ + "src/math/roundeven.rs" + ], + "type": "f128" + }, + "roundevenf16": { + "sources": [ + "src/math/roundeven.rs" + ], + "type": "f16" + }, "roundf": { "sources": [ "src/math/generic/round.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 90ca8f34e62e2..1f226c8c0ff3b 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -125,6 +125,10 @@ rintf rintf128 rintf16 round +roundeven +roundevenf +roundevenf128 +roundevenf16 roundf roundf128 roundf16 diff --git a/library/compiler-builtins/libm/src/libm_helper.rs b/library/compiler-builtins/libm/src/libm_helper.rs index 489dbc0d4df18..dfa1ff77bf2e4 100644 --- a/library/compiler-builtins/libm/src/libm_helper.rs +++ b/library/compiler-builtins/libm/src/libm_helper.rs @@ -94,6 +94,7 @@ libm_helper! { (fn remquo(x: f32, y: f32) -> (f32, i32); => remquof); (fn rint(x: f32) -> (f32); => rintf); (fn round(x: f32) -> (f32); => roundf); + (fn roundeven(x: f32) -> (f32); => roundevenf); (fn scalbn(x: f32, n: i32) -> (f32); => scalbnf); (fn sin(x: f32) -> (f32); => sinf); (fn sincos(x: f32) -> (f32, f32); => sincosf); @@ -167,6 +168,7 @@ libm_helper! { (fn remquo(x: f64, y: f64) -> (f64, i32); => remquo); (fn rint(x: f64) -> (f64); => rint); (fn round(x: f64) -> (f64); => round); + (fn roundevem(x: f64) -> (f64); => roundeven); (fn scalbn(x: f64, n: i32) -> (f64); => scalbn); (fn sin(x: f64) -> (f64); => sin); (fn sincos(x: f64) -> (f64, f64); => sincos); @@ -188,22 +190,23 @@ libm_helper! { f16, funcs: { // verify-sorted-start - (fn ceilf(x: f16) -> (f16); => ceilf16); + (fn ceil(x: f16) -> (f16); => ceilf16); (fn copysign(x: f16, y: f16) -> (f16); => copysignf16); (fn fabs(x: f16) -> (f16); => fabsf16); (fn fdim(x: f16, y: f16) -> (f16); => fdimf16); - (fn floorf(x: f16) -> (f16); => floorf16); - (fn fmaxf(x: f16, y: f16) -> (f16); => fmaxf16); - (fn fmaximum_numf16(x: f16, y: f16) -> (f16); => fmaximum_numf16); + (fn floor(x: f16) -> (f16); => floorf16); + (fn fmax(x: f16, y: f16) -> (f16); => fmaxf16); + (fn fmaximum_num(x: f16, y: f16) -> (f16); => fmaximum_numf16); (fn fmaximumf16(x: f16, y: f16) -> (f16); => fmaximumf16); - (fn fminf(x: f16, y: f16) -> (f16); => fminf16); - (fn fminimum_numf16(x: f16, y: f16) -> (f16); => fminimum_numf16); - (fn fminimumf16(x: f16, y: f16) -> (f16); => fminimumf16); - (fn fmodf(x: f16, y: f16) -> (f16); => fmodf16); - (fn ldexpf16(x: f16, n: i32) -> (f16); => ldexpf16); - (fn rintf(x: f16) -> (f16); => rintf16); - (fn roundf(x: f16) -> (f16); => roundf16); - (fn scalbnf16(x: f16, n: i32) -> (f16); => ldexpf16); + (fn fmin(x: f16, y: f16) -> (f16); => fminf16); + (fn fminimum(x: f16, y: f16) -> (f16); => fminimumf16); + (fn fminimum_num(x: f16, y: f16) -> (f16); => fminimum_numf16); + (fn fmod(x: f16, y: f16) -> (f16); => fmodf16); + (fn ldexp(x: f16, n: i32) -> (f16); => ldexpf16); + (fn rint(x: f16) -> (f16); => rintf16); + (fn round(x: f16) -> (f16); => roundf16); + (fn roundeven(x: f16) -> (f16); => roundevenf16); + (fn scalbn(x: f16, n: i32) -> (f16); => scalbnf16); (fn sqrtf(x: f16) -> (f16); => sqrtf16); (fn truncf(x: f16) -> (f16); => truncf16); // verify-sorted-end @@ -220,18 +223,19 @@ libm_helper! { (fn fabs(x: f128) -> (f128); => fabsf128); (fn fdim(x: f128, y: f128) -> (f128); => fdimf128); (fn floor(x: f128) -> (f128); => floorf128); - (fn fmaf128(x: f128, y: f128, z: f128) -> (f128); => fmaf128); + (fn fma(x: f128, y: f128, z: f128) -> (f128); => fmaf128); (fn fmax(x: f128, y: f128) -> (f128); => fmaxf128); - (fn fmaximum_numf128(x: f128, y: f128) -> (f128); => fmaximum_numf128); - (fn fmaximumf128(x: f128, y: f128) -> (f128); => fmaximumf128); + (fn fmaximum(x: f128, y: f128) -> (f128); => fmaximumf128); + (fn fmaximum_num(x: f128, y: f128) -> (f128); => fmaximum_numf128); (fn fmin(x: f128, y: f128) -> (f128); => fminf128); - (fn fminimum_numf128(x: f128, y: f128) -> (f128); => fminimum_numf128); - (fn fminimumf128(x: f128, y: f128) -> (f128); => fminimumf128); + (fn fminimum(x: f128, y: f128) -> (f128); => fminimumf128); + (fn fminimum_num(x: f128, y: f128) -> (f128); => fminimum_numf128); (fn fmod(x: f128, y: f128) -> (f128); => fmodf128); - (fn ldexpf128(x: f128, n: i32) -> (f128); => ldexpf128); + (fn ldexp(x: f128, n: i32) -> (f128); => ldexpf128); (fn rint(x: f128) -> (f128); => rintf128); (fn round(x: f128) -> (f128); => roundf128); - (fn scalbnf128(x: f128, n: i32) -> (f128); => ldexpf128); + (fn roundeven(x: f128) -> (f128); => roundevenf128); + (fn scalbn(x: f128, n: i32) -> (f128); => scalbnf128); (fn sqrt(x: f128) -> (f128); => sqrtf128); (fn trunc(x: f128) -> (f128); => truncf128); // verify-sorted-end diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index 092f9317bc57a..f224eba731c3b 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -30,7 +30,7 @@ pub use fmin::fmin; pub use fminimum::fminimum; pub use fminimum_num::fminimum_num; pub use fmod::fmod; -pub use rint::rint; +pub use rint::rint_round; pub use round::round; pub use scalbn::scalbn; pub use sqrt::sqrt; diff --git a/library/compiler-builtins/libm/src/math/generic/rint.rs b/library/compiler-builtins/libm/src/math/generic/rint.rs index 80ba1faac3111..04e8f332f2200 100644 --- a/library/compiler-builtins/libm/src/math/generic/rint.rs +++ b/library/compiler-builtins/libm/src/math/generic/rint.rs @@ -2,27 +2,31 @@ /* origin: musl src/math/rint.c */ use super::super::Float; +use super::super::support::{FpResult, Round}; -pub fn rint(x: F) -> F { +/// IEEE 754-2019 `roundToIntegralExact`, which respects rounding mode and raises inexact if +/// applicable. +pub fn rint_round(x: F, _round: Round) -> FpResult { let toint = F::ONE / F::EPSILON; let e = x.exp(); let positive = x.is_sign_positive(); // 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 use_force = cfg!(x86_no_sse) && F::BITS == 32 || F::BITS == 64; + let force = |x| { + if cfg!(x86_no_sse) && (F::BITS == 32 || F::BITS == 64) { force_eval!(x) } else { x } + }; - if e >= F::EXP_BIAS + F::SIG_BITS { + let res = if e >= F::EXP_BIAS + F::SIG_BITS { // No fractional part; exact result can be returned. x } else { - // Apply a net-zero adjustment that nudges `y` in the direction of the rounding mode. + // Apply a net-zero adjustment that nudges `y` in the direction of the rounding mode. For + // Rust this is always nearest, but ideally it would take `round` into account. let y = if positive { - let tmp = if use_force { force_eval!(x) } else { x } + toint; - (if use_force { force_eval!(tmp) } else { tmp } - toint) + force(force(x) + toint) - toint } else { - let tmp = if use_force { force_eval!(x) } else { x } - toint; - (if use_force { force_eval!(tmp) } else { tmp } + toint) + force(force(x) - toint) + toint }; if y == F::ZERO { @@ -31,42 +35,85 @@ pub fn rint(x: F) -> F { } else { y } - } + }; + + FpResult::ok(res) } #[cfg(test)] mod tests { use super::*; + use crate::support::{Hexf, Int, 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({})", Hexf(x)); + assert_eq!(status, Status::OK, "{}", Hexf(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)); + } + } #[test] - fn zeroes_f32() { - assert_biteq!(rint(0.0_f32), 0.0_f32); - assert_biteq!(rint(-0.0_f32), -0.0_f32); + #[cfg(f16_enabled)] + fn spec_tests_f16() { + let cases = []; + spec_test::(&cases); } #[test] - fn sanity_check_f32() { - assert_biteq!(rint(-1.0_f32), -1.0); - assert_biteq!(rint(2.8_f32), 3.0); - assert_biteq!(rint(-0.5_f32), -0.0); - assert_biteq!(rint(0.5_f32), 0.0); - assert_biteq!(rint(-1.5_f32), -2.0); - assert_biteq!(rint(1.5_f32), 2.0); + 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 zeroes_f64() { - assert_biteq!(rint(0.0_f64), 0.0_f64); - assert_biteq!(rint(-0.0_f64), -0.0_f64); + 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] - fn sanity_check_f64() { - assert_biteq!(rint(-1.0_f64), -1.0); - assert_biteq!(rint(2.8_f64), 3.0); - assert_biteq!(rint(-0.5_f64), -0.0); - assert_biteq!(rint(0.5_f64), 0.0); - assert_biteq!(rint(-1.5_f64), -2.0); - assert_biteq!(rint(1.5_f64), 2.0); + #[cfg(f128_enabled)] + fn spec_tests_f128() { + let cases = []; + spec_test::(&cases); } } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 4e75292a6ef16..e58d79adc419e 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -207,8 +207,8 @@ mod remainderf; mod remquo; mod remquof; mod rint; -mod rintf; mod round; +mod roundeven; mod roundf; mod scalbn; mod scalbnf; @@ -313,9 +313,9 @@ pub use self::remainder::remainder; pub use self::remainderf::remainderf; pub use self::remquo::remquo; pub use self::remquof::remquof; -pub use self::rint::rint; -pub use self::rintf::rintf; +pub use self::rint::{rint, rintf}; pub use self::round::round; +pub use self::roundeven::{roundeven, roundevenf}; pub use self::roundf::roundf; pub use self::scalbn::scalbn; pub use self::scalbnf::scalbnf; @@ -346,7 +346,6 @@ cfg_if! { mod floorf16; mod fmodf16; mod ldexpf16; - mod rintf16; mod roundf16; mod scalbnf16; mod sqrtf16; @@ -364,7 +363,8 @@ cfg_if! { pub use self::fminimum_fmaximum_num::{fmaximum_numf16, fminimum_numf16}; pub use self::fmodf16::fmodf16; pub use self::ldexpf16::ldexpf16; - pub use self::rintf16::rintf16; + pub use self::rint::rintf16; + pub use self::roundeven::roundevenf16; pub use self::roundf16::roundf16; pub use self::scalbnf16::scalbnf16; pub use self::sqrtf16::sqrtf16; @@ -384,7 +384,6 @@ cfg_if! { mod fmaf128; mod fmodf128; mod ldexpf128; - mod rintf128; mod roundf128; mod scalbnf128; mod sqrtf128; @@ -403,7 +402,8 @@ cfg_if! { pub use self::fminimum_fmaximum_num::{fmaximum_numf128, fminimum_numf128}; pub use self::fmodf128::fmodf128; pub use self::ldexpf128::ldexpf128; - pub use self::rintf128::rintf128; + pub use self::rint::rintf128; + pub use self::roundeven::roundevenf128; pub use self::roundf128::roundf128; pub use self::scalbnf128::scalbnf128; pub use self::sqrtf128::sqrtf128; diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index f409ec2821d87..8a5cbeab49793 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -1,3 +1,27 @@ +use super::support::Round; + +/// Round `x` to the nearest integer, breaking ties toward even. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn rintf16(x: f16) -> f16 { + super::generic::rint_round(x, Round::Nearest).val +} + +/// Round `x` to the nearest integer, breaking ties toward even. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn rintf(x: f32) -> f32 { + select_implementation! { + name: rintf, + use_arch: any( + all(target_arch = "wasm32", intrinsics_enabled), + all(target_arch = "aarch64", target_feature = "neon", target_endian = "little"), + ), + args: x, + } + + super::generic::rint_round(x, Round::Nearest).val +} + /// Round `x` to the nearest integer, breaking ties toward even. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn rint(x: f64) -> f64 { @@ -10,5 +34,12 @@ pub fn rint(x: f64) -> f64 { args: x, } - super::generic::rint(x) + super::generic::rint_round(x, Round::Nearest).val +} + +/// Round `x` to the nearest integer, breaking ties toward even. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn rintf128(x: f128) -> f128 { + super::generic::rint_round(x, Round::Nearest).val } diff --git a/library/compiler-builtins/libm/src/math/rintf.rs b/library/compiler-builtins/libm/src/math/rintf.rs deleted file mode 100644 index 5e9f5f7187697..0000000000000 --- a/library/compiler-builtins/libm/src/math/rintf.rs +++ /dev/null @@ -1,14 +0,0 @@ -/// Round `x` to the nearest integer, breaking ties toward even. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn rintf(x: f32) -> f32 { - select_implementation! { - name: rintf, - use_arch: any( - all(target_arch = "wasm32", intrinsics_enabled), - all(target_arch = "aarch64", target_feature = "neon", target_endian = "little"), - ), - args: x, - } - - super::generic::rint(x) -} diff --git a/library/compiler-builtins/libm/src/math/rintf128.rs b/library/compiler-builtins/libm/src/math/rintf128.rs deleted file mode 100644 index 6b16fcd841a67..0000000000000 --- a/library/compiler-builtins/libm/src/math/rintf128.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Round `x` to the nearest integer, breaking ties toward even. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn rintf128(x: f128) -> f128 { - super::generic::rint(x) -} diff --git a/library/compiler-builtins/libm/src/math/rintf16.rs b/library/compiler-builtins/libm/src/math/rintf16.rs deleted file mode 100644 index 84d792561f742..0000000000000 --- a/library/compiler-builtins/libm/src/math/rintf16.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Round `x` to the nearest integer, breaking ties toward even. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn rintf16(x: f16) -> f16 { - super::generic::rint(x) -} diff --git a/library/compiler-builtins/libm/src/math/roundeven.rs b/library/compiler-builtins/libm/src/math/roundeven.rs new file mode 100644 index 0000000000000..ec1738285e620 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/roundeven.rs @@ -0,0 +1,35 @@ +use super::support::{Float, Round}; + +/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 +/// `roundToIntegralTiesToEven`. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundevenf16(x: f16) -> f16 { + roundeven_impl(x) +} + +/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 +/// `roundToIntegralTiesToEven`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundevenf(x: f32) -> f32 { + roundeven_impl(x) +} + +/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 +/// `roundToIntegralTiesToEven`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundeven(x: f64) -> f64 { + roundeven_impl(x) +} + +/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 +/// `roundToIntegralTiesToEven`. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundevenf128(x: f128) -> f128 { + roundeven_impl(x) +} + +pub fn roundeven_impl(x: F) -> F { + super::generic::rint_round(x, Round::Nearest).val +} From 7db47c741c173b94730b3017851924b1e7525dea Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 11 Feb 2025 07:45:14 +0000 Subject: [PATCH 1679/4206] Check exact values for specified cases Inputs in `case_list` shouldn't hit xfails or increased ULP tolerance. Ensure that overrides are skipped when testing against MPFR or a specified value and that NaNs, if any, are checked bitwise. --- .../libm/crates/libm-test/src/gen/case_list.rs | 10 ++++++++-- .../libm/crates/libm-test/src/test_traits.rs | 14 +++++++++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs index 8c7a735fa707d..7cb9897d8d2a8 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs @@ -579,8 +579,11 @@ fn rint_cases() -> Vec> { TestCase::append_pairs( &mut v, &[ - // Failure on i586 + // 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 @@ -628,8 +631,11 @@ fn roundeven_cases() -> Vec> { TestCase::append_pairs( &mut v, &[ - // Failure on i586 + // 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 diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index 1bd5bce162bd7..bba1fca64e6fc 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -12,7 +12,9 @@ use anyhow::{Context, anyhow, bail, ensure}; use libm::support::Hexf; use crate::precision::CheckAction; -use crate::{CheckCtx, Float, Int, MaybeOverride, SpecialCase, TestResult}; +use crate::{ + CheckBasis, CheckCtx, Float, GeneratorKind, Int, MaybeOverride, SpecialCase, TestResult, +}; /// Trait for calling a function with a tuple as arguments. /// @@ -207,6 +209,8 @@ where SpecialCase: MaybeOverride, { let (result, xfail_msg) = match SpecialCase::check_int(input, actual, expected, ctx) { + // `require_biteq` forbids overrides. + _ if ctx.gen_kind == GeneratorKind::List => (actual == expected, None), CheckAction::AssertSuccess => (actual == expected, None), CheckAction::AssertFailure(msg) => (actual != expected, Some(msg)), CheckAction::Custom(res) => return res, @@ -291,7 +295,12 @@ where let mut inner = || -> TestResult { let mut allowed_ulp = ctx.ulp; + // Forbid overrides if the items came from an explicit list, as long as we are checking + // against either MPFR or the result itself. + let require_biteq = ctx.gen_kind == GeneratorKind::List && ctx.basis != CheckBasis::Musl; + match SpecialCase::check_float(input, actual, expected, ctx) { + _ if require_biteq => (), CheckAction::AssertSuccess => (), CheckAction::AssertFailure(msg) => assert_failure_msg = Some(msg), CheckAction::Custom(res) => return res, @@ -301,6 +310,9 @@ where // Check when both are NaNs if actual.is_nan() && expected.is_nan() { + if require_biteq && ctx.basis == CheckBasis::None { + ensure!(actual.to_bits() == expected.to_bits(), "mismatched NaN bitpatterns"); + } // By default, NaNs have nothing special to check. return Ok(()); } else if actual.is_nan() || expected.is_nan() { From aa26cab257d34a8d8786f6c607b67fd70b467ce6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 11 Feb 2025 15:40:17 +0000 Subject: [PATCH 1680/4206] Rename `Float::exp` to `Float::ex` Our function to get the exponent conflicts with the inherent `exp` function for `e^x`. Rename `exp` to `ex` to avoid confusion and usage problems. --- .../compiler-builtins/libm/etc/function-definitions.json | 3 +-- library/compiler-builtins/libm/src/math/generic/fma.rs | 6 +++--- library/compiler-builtins/libm/src/math/generic/fmod.rs | 4 ++-- library/compiler-builtins/libm/src/math/generic/rint.rs | 2 +- library/compiler-builtins/libm/src/math/generic/sqrt.rs | 2 +- .../compiler-builtins/libm/src/math/support/float_traits.rs | 4 ++-- 6 files changed, 10 insertions(+), 11 deletions(-) diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index a47aaad57c786..63d9927ad6f8c 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -206,8 +206,7 @@ }, "exp": { "sources": [ - "src/math/exp.rs", - "src/math/support/float_traits.rs" + "src/math/exp.rs" ], "type": "f64" }, diff --git a/library/compiler-builtins/libm/src/math/generic/fma.rs b/library/compiler-builtins/libm/src/math/generic/fma.rs index 821aee09028ba..cb1061cc38b18 100644 --- a/library/compiler-builtins/libm/src/math/generic/fma.rs +++ b/library/compiler-builtins/libm/src/math/generic/fma.rs @@ -249,7 +249,7 @@ where let xy: B = x.widen() * y.widen(); let mut result: B = xy + z.widen(); let mut ui: B::Int = result.to_bits(); - let re = result.exp(); + let re = result.ex(); let zb: B = z.widen(); let prec_diff = B::SIG_BITS - F::SIG_BITS; @@ -318,7 +318,7 @@ impl Norm { fn from_float(x: F) -> Self { let mut ix = x.to_bits(); - let mut e = x.exp() as i32; + let mut e = x.ex() as i32; let neg = x.is_sign_negative(); if e == 0 { // Normalize subnormals by multiplication @@ -326,7 +326,7 @@ impl Norm { let scale_f = F::from_parts(false, scale_i + F::EXP_BIAS, F::Int::ZERO); let scaled = x * scale_f; ix = scaled.to_bits(); - e = scaled.exp() as i32; + e = scaled.ex() as i32; e = if e == 0 { // If the exponent is still zero, the input was zero. Artifically set this value // such that the final `e` will exceed `ZERO_INF_NAN`. diff --git a/library/compiler-builtins/libm/src/math/generic/fmod.rs b/library/compiler-builtins/libm/src/math/generic/fmod.rs index ca1cda383235a..c74b593d559e7 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmod.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmod.rs @@ -9,8 +9,8 @@ pub fn fmod(x: F, y: F) -> F { let one = F::Int::ONE; let mut ix = x.to_bits(); let mut iy = y.to_bits(); - let mut ex = x.exp().signed(); - let mut ey = y.exp().signed(); + let mut ex = x.ex().signed(); + let mut ey = y.ex().signed(); let sx = ix & F::SIGN_MASK; if iy << 1 == zero || y.is_nan() || ex == F::EXP_SAT as i32 { diff --git a/library/compiler-builtins/libm/src/math/generic/rint.rs b/library/compiler-builtins/libm/src/math/generic/rint.rs index 04e8f332f2200..2f8b2b365912e 100644 --- a/library/compiler-builtins/libm/src/math/generic/rint.rs +++ b/library/compiler-builtins/libm/src/math/generic/rint.rs @@ -8,7 +8,7 @@ use super::super::support::{FpResult, Round}; /// applicable. pub fn rint_round(x: F, _round: Round) -> FpResult { let toint = F::ONE / F::EPSILON; - let e = x.exp(); + let e = x.ex(); let positive = x.is_sign_positive(); // On i386 `force_eval!` must be used to force rounding via storage to memory. Otherwise, diff --git a/library/compiler-builtins/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/src/math/generic/sqrt.rs index fdd612493b79e..5918025bc678d 100644 --- a/library/compiler-builtins/libm/src/math/generic/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/generic/sqrt.rs @@ -109,7 +109,7 @@ where ix = scaled.to_bits(); match top { Exp::Shifted(ref mut v) => { - *v = scaled.exp(); + *v = scaled.ex(); *v = (*v).wrapping_sub(F::SIG_BITS); } Exp::NoShift(()) => { 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 42ce3148464fd..534ca9a07fa71 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -128,13 +128,13 @@ pub trait Float: } /// Returns the exponent, not adjusting for bias, not accounting for subnormals or zero. - fn exp(self) -> u32 { + fn ex(self) -> u32 { u32::cast_from(self.to_bits() >> Self::SIG_BITS) & Self::EXP_SAT } /// Extract the exponent and adjust it for bias, not accounting for subnormals or zero. fn exp_unbiased(self) -> i32 { - self.exp().signed() - (Self::EXP_BIAS as i32) + self.ex().signed() - (Self::EXP_BIAS as i32) } /// Returns the significand with no implicit bit (or the "fractional" part) From e106d63516b7e1a75c3e2e8873ac805b8833b192 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 12 Feb 2025 03:48:20 +0000 Subject: [PATCH 1681/4206] Add a way to print inputs on failure When there is a panic in an extensive test, tracing down where it came from can be difficult since no information is provides (messeges are e.g. "attempted to subtract with overflow"). Resolve this by calling the functions within `panic::catch_unwind`, printing the input, and continuing. --- .../libm/crates/libm-test/src/op.rs | 6 ++++-- .../libm/crates/libm-test/src/test_traits.rs | 19 ++++++++++++++++++- .../libm-test/tests/compare_built_musl.rs | 2 +- .../crates/libm-test/tests/multiprecision.rs | 2 +- .../libm/crates/libm-test/tests/standalone.rs | 2 +- .../crates/libm-test/tests/z_extensive/run.rs | 2 +- .../libm/crates/util/src/main.rs | 2 +- 7 files changed, 27 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/op.rs b/library/compiler-builtins/libm/crates/libm-test/src/op.rs index 239c9a3e1fdfa..47d72ae58b392 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/op.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/op.rs @@ -14,6 +14,7 @@ //! level. `Op` is also used as the name for generic parameters since it is terse. use std::fmt; +use std::panic::{RefUnwindSafe, UnwindSafe}; pub use shared::{ALL_OPERATIONS, FloatTy, MathOpInfo, Ty}; @@ -64,7 +65,7 @@ pub trait MathOp { type CRet; /// The signature of the Rust function as a `fn(...) -> ...` type. - type RustFn: Copy; + type RustFn: Copy + UnwindSafe; /// Arguments passed to the Rust library function as a tuple. /// @@ -72,7 +73,8 @@ pub trait MathOp { /// to the Rust function. type RustArgs: Copy + TupleCall - + TupleCall; + + TupleCall + + RefUnwindSafe; /// Type returned from the Rust function. type RustRet: CheckOutput; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs index bba1fca64e6fc..c560dade8848d 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs @@ -6,7 +6,8 @@ //! - `CheckOutput`: implemented on anything that is an output type for validation against an //! expected value. -use std::fmt; +use std::panic::{RefUnwindSafe, UnwindSafe}; +use std::{fmt, panic}; use anyhow::{Context, anyhow, bail, ensure}; use libm::support::Hexf; @@ -23,6 +24,22 @@ use crate::{ pub trait TupleCall: fmt::Debug { type Output; fn call(self, f: Func) -> Self::Output; + + /// Intercept panics and print the input to stderr before continuing. + fn call_intercept_panics(self, f: Func) -> Self::Output + where + Self: RefUnwindSafe + Copy, + Func: UnwindSafe, + { + let res = panic::catch_unwind(|| self.call(f)); + match res { + Ok(v) => v, + Err(e) => { + eprintln!("panic with the following input: {self:?}"); + panic::resume_unwind(e) + } + } + } } /// A trait to implement on any output type so we can verify it in a generic way. diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 2b16b9aa091b0..897dfc26e8cab 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -21,7 +21,7 @@ fn musl_runner( ) { for input in cases { let musl_res = input.call(musl_fn); - let crate_res = input.call(Op::ROUTINE); + let crate_res = input.call_intercept_panics(Op::ROUTINE); crate_res.validate(musl_res, input, ctx).unwrap(); } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index fd1f11610f52c..0ab4b64da8141 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -12,7 +12,7 @@ fn mp_runner(ctx: &CheckCtx, cases: impl Iterator( cases: impl Iterator, ) { for (input, expected) in cases { - let crate_res = input.call(Op::ROUTINE); + let crate_res = input.call_intercept_panics(Op::ROUTINE); crate_res.validate(expected, input, ctx).unwrap(); } } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs index a323c9110ee8f..786546a9d6d5b 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs @@ -113,7 +113,7 @@ where for input in input_vec { // Test the input. let mp_res = Op::run(mp_vals, input); - let crate_res = input.call(Op::ROUTINE); + let crate_res = input.call_intercept_panics(Op::ROUTINE); crate_res.validate(mp_res, input, ctx)?; let completed = completed.fetch_add(1, Ordering::Relaxed) + 1; diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index 130ac45319bed..ef70ec9035b84 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -59,7 +59,7 @@ macro_rules! handle_call { let libm_fn: ::RustFn = libm::$fn_name; let output = match $basis { - "libm" => input.call(libm_fn), + "libm" => input.call_intercept_panics(libm_fn), #[cfg(feature = "build-musl")] "musl" => { let musl_fn: ::CFn = From dea2ed3d1d2e43df597f72e097e8fd439143e956 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 12 Feb 2025 09:25:16 +0000 Subject: [PATCH 1682/4206] Scale test iteration count at a later point Currently the argument multiplier and large float multiplier happen before selecting count based on generator. However, this means that bivariate and trivariate functions don't get scaled at all (except for the special cased fma). Move this scaling to a later point. --- .../libm/crates/libm-test/src/run_cfg.rs | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index 6b268997666ac..8e4fff53cb292 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -23,8 +23,8 @@ static EXTENSIVE_ITER_OVERRIDE: LazyLock> = LazyLock::new(|| { /// /// Contains the itentifier+generator combo to match on, plus the factor to reduce by. const EXTEMELY_SLOW_TESTS: &[(Identifier, GeneratorKind, u64)] = &[ - (Identifier::Fmodf128, GeneratorKind::QuickSpaced, 40), - (Identifier::Fmodf128, GeneratorKind::Extensive, 40), + (Identifier::Fmodf128, GeneratorKind::QuickSpaced, 50), + (Identifier::Fmodf128, GeneratorKind::Extensive, 50), ]; /// Maximum number of iterations to run for a single routine. @@ -200,15 +200,6 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { domain_iter_count = 100_000; } - // Larger float types get more iterations. - if t_env.large_float_ty { - domain_iter_count *= 4; - } - - // Functions with more arguments get more iterations. - let arg_multiplier = 1 << (t_env.input_count - 1); - domain_iter_count *= arg_multiplier; - // If we will be running tests against MPFR, we don't need to test as much against musl. // However, there are some platforms where we have to test against musl since MPFR can't be // built. @@ -228,6 +219,25 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { } }; + // Larger float types get more iterations. + if t_env.large_float_ty && ctx.gen_kind != GeneratorKind::Extensive { + if ctx.gen_kind == GeneratorKind::Extensive { + // Extensive already has a pretty high test count. + total_iterations *= 2; + } else { + total_iterations *= 4; + } + } + + // Functions with more arguments get more iterations. + let arg_multiplier = 1 << (t_env.input_count - 1); + total_iterations *= arg_multiplier; + + // FMA has a huge domain but is reasonably fast to run, so increase another 1.5x. + if ctx.base_name == BaseName::Fma { + total_iterations = 3 * total_iterations / 2; + } + // Some tests are significantly slower than others and need to be further reduced. if let Some((_id, _gen, scale)) = EXTEMELY_SLOW_TESTS .iter() @@ -239,11 +249,6 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { } } - // FMA has a huge domain but is reasonably fast to run, so increase iterations. - if ctx.base_name == BaseName::Fma { - total_iterations *= 4; - } - if cfg!(optimizations_enabled) { // Always run at least 10,000 tests. total_iterations = total_iterations.max(10_000); From 212d463e89b0b2db7560fde4216b0c48a5448f34 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 12 Feb 2025 10:12:24 +0000 Subject: [PATCH 1683/4206] fma refactor 1/3: remove math/fma.rs Done in stages so git tracks the moved file correctly. --- .../compiler-builtins/libm/src/math/fma.rs | 40 ------------------- 1 file changed, 40 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/fma.rs diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs deleted file mode 100644 index 69cc3eb6726d2..0000000000000 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ /dev/null @@ -1,40 +0,0 @@ -/// Fused multiply add (f64) -/// -/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fma(x: f64, y: f64, z: f64) -> f64 { - return super::generic::fma(x, y, z); -} - -#[cfg(test)] -mod tests { - use super::*; - #[test] - fn fma_segfault() { - // These two inputs cause fma to segfault on release due to overflow: - assert_eq!( - fma( - -0.0000000000000002220446049250313, - -0.0000000000000002220446049250313, - -0.0000000000000002220446049250313 - ), - -0.00000000000000022204460492503126, - ); - - 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")))] - let result = force_eval!(result); - assert_eq!(result, -0.007936000000000007,); - } - - #[test] - fn fma_sbb() { - assert_eq!(fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), -3991680619069439e277); - } - - #[test] - fn fma_underflow() { - assert_eq!(fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), 0.0,); - } -} From bcbdb0b74f0acb339fb49902fe0ebecc4f2c3509 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 12 Feb 2025 10:12:24 +0000 Subject: [PATCH 1684/4206] fma refactor 2/3: move math/generic/fma.rs to math/fma.rs Done in stages so git tracks the moved file correctly. --- library/compiler-builtins/libm/src/math/{generic => }/fma.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename library/compiler-builtins/libm/src/math/{generic => }/fma.rs (100%) diff --git a/library/compiler-builtins/libm/src/math/generic/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/generic/fma.rs rename to library/compiler-builtins/libm/src/math/fma.rs From 720ba18931628f28fb690a2936e53a32233f88d5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 12 Feb 2025 09:55:04 +0000 Subject: [PATCH 1685/4206] fma refactor 3/3: combine `fma` public API with its implementation Similar to other recent changes, just put public API in the same file as its generic implementation. To keep things slightly cleaner, split the default implementation from the `_wide` implementation. Also introduces a stub `fmaf16`. --- .../libm/etc/function-definitions.json | 9 +- .../compiler-builtins/libm/src/math/fma.rs | 140 +++++++----------- .../libm/src/math/fma_wide.rs | 97 ++++++++++++ .../compiler-builtins/libm/src/math/fmaf.rs | 21 --- .../libm/src/math/fmaf128.rs | 7 - .../libm/src/math/generic/mod.rs | 2 - .../compiler-builtins/libm/src/math/mod.rs | 10 +- 7 files changed, 161 insertions(+), 125 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/fma_wide.rs delete mode 100644 library/compiler-builtins/libm/src/math/fmaf.rs delete mode 100644 library/compiler-builtins/libm/src/math/fmaf128.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 63d9927ad6f8c..a966852b1128e 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -343,22 +343,19 @@ }, "fma": { "sources": [ - "src/math/fma.rs", - "src/math/generic/fma.rs" + "src/math/fma.rs" ], "type": "f64" }, "fmaf": { "sources": [ - "src/math/fmaf.rs", - "src/math/generic/fma.rs" + "src/math/fma_wide.rs" ], "type": "f32" }, "fmaf128": { "sources": [ - "src/math/fmaf128.rs", - "src/math/generic/fma.rs" + "src/math/fma.rs" ], "type": "f128" }, diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index cb1061cc38b18..a54984c936b7f 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -1,23 +1,28 @@ /* SPDX-License-Identifier: MIT */ -/* origin: musl src/math/{fma,fmaf}.c. Ported to generic Rust algorithm in 2025, TG. */ +/* origin: musl src/math/fma.c. Ported to generic Rust algorithm in 2025, TG. */ use super::super::support::{DInt, FpResult, HInt, IntTy, Round, Status}; -use super::super::{CastFrom, CastInto, DFloat, Float, HFloat, Int, MinInt}; +use super::{CastFrom, CastInto, Float, Int, MinInt}; -/// Fused multiply-add that works when there is not a larger float size available. Currently this -/// is still specialized only for `f64`. Computes `(x * y) + z`. +/// Fused multiply add (f64) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fma(x: F, y: F, z: F) -> F -where - F: Float, - F: CastFrom, - F: CastFrom, - F::Int: HInt, - u32: CastInto, -{ +pub fn fma(x: f64, y: f64, z: f64) -> f64 { + fma_round(x, y, z, Round::Nearest).val +} + +/// Fused multiply add (f128) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaf128(x: f128, y: f128, z: f128) -> f128 { fma_round(x, y, z, Round::Nearest).val } +/// Fused multiply-add that works when there is not a larger float size available. Computes +/// `(x * y) + z`. pub fn fma_round(x: F, y: F, z: F, _round: Round) -> FpResult where F: Float, @@ -222,79 +227,7 @@ where } // Use our exponent to scale the final value. - FpResult::new(super::scalbn(r, e), status) -} - -/// Fma implementation when a hardware-backed larger float type is available. For `f32` and `f64`, -/// `f64` has enough precision to represent the `f32` in its entirety, except for double rounding. -pub fn fma_wide(x: F, y: F, z: F) -> F -where - F: Float + HFloat, - B: Float + DFloat, - B::Int: CastInto, - i32: CastFrom, -{ - fma_wide_round(x, y, z, Round::Nearest).val -} - -pub fn fma_wide_round(x: F, y: F, z: F, round: Round) -> FpResult -where - F: Float + HFloat, - B: Float + DFloat, - B::Int: CastInto, - i32: CastFrom, -{ - let one = IntTy::::ONE; - - let xy: B = x.widen() * y.widen(); - let mut result: B = xy + z.widen(); - let mut ui: B::Int = result.to_bits(); - let re = result.ex(); - let zb: B = z.widen(); - - let prec_diff = B::SIG_BITS - F::SIG_BITS; - let excess_prec = ui & ((one << prec_diff) - one); - let halfway = one << (prec_diff - 1); - - // Common case: the larger precision is fine if... - // This is not a halfway case - if excess_prec != halfway - // Or the result is NaN - || re == B::EXP_SAT - // Or the result is exact - || (result - xy == zb && result - zb == xy) - // Or the mode is something other than round to nearest - || round != Round::Nearest - { - let min_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN_SUBNORM) as u32; - let max_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN) as u32; - - let mut status = Status::OK; - - if (min_inexact_exp..max_inexact_exp).contains(&re) && status.inexact() { - // This branch is never hit; requires previous operations to set a status - status.set_inexact(false); - - result = xy + z.widen(); - if status.inexact() { - status.set_underflow(true); - } else { - status.set_inexact(true); - } - } - - return FpResult { val: result.narrow(), status }; - } - - let neg = ui >> (B::BITS - 1) != IntTy::::ZERO; - let err = if neg == (zb > xy) { xy - result + zb } else { zb - result + xy }; - if neg == (err < B::ZERO) { - ui += one; - } else { - ui -= one; - } - - FpResult::ok(B::from_bits(ui).narrow()) + FpResult::new(super::generic::scalbn(r, e), status) } /// Representation of `F` that has handled subnormals. @@ -363,6 +296,7 @@ impl Norm { mod tests { use super::*; + /// Test the generic `fma_round` algorithm for a given float. fn spec_test() where F: Float, @@ -375,6 +309,8 @@ mod tests { let y = F::from_bits(F::Int::ONE); let z = F::ZERO; + let fma = |x, y, z| fma_round(x, y, z, Round::Nearest).val; + // 754-2020 says "When the exact result of (a × b) + c is non-zero yet the result of // fusedMultiplyAdd is zero because of rounding, the zero result takes the sign of the // exact result" @@ -384,6 +320,11 @@ mod tests { assert_biteq!(fma(-x, -y, z), F::ZERO); } + #[test] + fn spec_test_f32() { + spec_test::(); + } + #[test] fn spec_test_f64() { spec_test::(); @@ -417,4 +358,33 @@ mod tests { fn spec_test_f128() { spec_test::(); } + + #[test] + fn fma_segfault() { + // These two inputs cause fma to segfault on release due to overflow: + assert_eq!( + fma( + -0.0000000000000002220446049250313, + -0.0000000000000002220446049250313, + -0.0000000000000002220446049250313 + ), + -0.00000000000000022204460492503126, + ); + + 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")))] + let result = force_eval!(result); + assert_eq!(result, -0.007936000000000007,); + } + + #[test] + fn fma_sbb() { + assert_eq!(fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), -3991680619069439e277); + } + + #[test] + fn fma_underflow() { + assert_eq!(fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), 0.0,); + } } diff --git a/library/compiler-builtins/libm/src/math/fma_wide.rs b/library/compiler-builtins/libm/src/math/fma_wide.rs new file mode 100644 index 0000000000000..a8c1a548879d8 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/fma_wide.rs @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/fmaf.c. Ported to generic Rust algorithm in 2025, TG. */ + +use super::super::support::{FpResult, IntTy, Round, Status}; +use super::{CastFrom, CastInto, DFloat, Float, HFloat, MinInt}; + +// Placeholder so we can have `fmaf16` in the `Float` trait. +#[allow(unused)] +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub(crate) fn fmaf16(_x: f16, _y: f16, _z: f16) -> f16 { + unimplemented!() +} + +/// Floating multiply add (f32) +/// +/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaf(x: f32, y: f32, z: f32) -> f32 { + fma_wide_round(x, y, z, Round::Nearest).val +} + +/// Fma implementation when a hardware-backed larger float type is available. For `f32` and `f64`, +/// `f64` has enough precision to represent the `f32` in its entirety, except for double rounding. +pub fn fma_wide_round(x: F, y: F, z: F, round: Round) -> FpResult +where + F: Float + HFloat, + B: Float + DFloat, + B::Int: CastInto, + i32: CastFrom, +{ + let one = IntTy::::ONE; + + let xy: B = x.widen() * y.widen(); + let mut result: B = xy + z.widen(); + let mut ui: B::Int = result.to_bits(); + let re = result.ex(); + let zb: B = z.widen(); + + let prec_diff = B::SIG_BITS - F::SIG_BITS; + let excess_prec = ui & ((one << prec_diff) - one); + let halfway = one << (prec_diff - 1); + + // Common case: the larger precision is fine if... + // This is not a halfway case + if excess_prec != halfway + // Or the result is NaN + || re == B::EXP_SAT + // Or the result is exact + || (result - xy == zb && result - zb == xy) + // Or the mode is something other than round to nearest + || round != Round::Nearest + { + let min_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN_SUBNORM) as u32; + let max_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN) as u32; + + let mut status = Status::OK; + + if (min_inexact_exp..max_inexact_exp).contains(&re) && status.inexact() { + // This branch is never hit; requires previous operations to set a status + status.set_inexact(false); + + result = xy + z.widen(); + if status.inexact() { + status.set_underflow(true); + } else { + status.set_inexact(true); + } + } + + return FpResult { val: result.narrow(), status }; + } + + let neg = ui >> (B::BITS - 1) != IntTy::::ZERO; + let err = if neg == (zb > xy) { xy - result + zb } else { zb - result + xy }; + if neg == (err < B::ZERO) { + ui += one; + } else { + ui -= one; + } + + FpResult::ok(B::from_bits(ui).narrow()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn issue_263() { + let a = f32::from_bits(1266679807); + let b = f32::from_bits(1300234242); + let c = f32::from_bits(1115553792); + let expected = f32::from_bits(1501560833); + assert_eq!(fmaf(a, b, c), expected); + } +} diff --git a/library/compiler-builtins/libm/src/math/fmaf.rs b/library/compiler-builtins/libm/src/math/fmaf.rs deleted file mode 100644 index 40d7f40d61738..0000000000000 --- a/library/compiler-builtins/libm/src/math/fmaf.rs +++ /dev/null @@ -1,21 +0,0 @@ -/// Floating multiply add (f32) -/// -/// Computes `(x*y)+z`, rounded as one ternary operation: -/// Computes the value (as if) to infinite precision and rounds once to the result format, -/// according to the rounding mode characterized by the value of FLT_ROUNDS. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaf(x: f32, y: f32, z: f32) -> f32 { - super::generic::fma_wide(x, y, z) -} - -#[cfg(test)] -mod tests { - #[test] - fn issue_263() { - let a = f32::from_bits(1266679807); - let b = f32::from_bits(1300234242); - let c = f32::from_bits(1115553792); - let expected = f32::from_bits(1501560833); - assert_eq!(super::fmaf(a, b, c), expected); - } -} diff --git a/library/compiler-builtins/libm/src/math/fmaf128.rs b/library/compiler-builtins/libm/src/math/fmaf128.rs deleted file mode 100644 index 50f7360deb45c..0000000000000 --- a/library/compiler-builtins/libm/src/math/fmaf128.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Fused multiply add (f128) -/// -/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmaf128(x: f128, y: f128, z: f128) -> f128 { - return super::generic::fma(x, y, z); -} diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index f224eba731c3b..9be185f809f19 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -3,7 +3,6 @@ mod copysign; mod fabs; mod fdim; mod floor; -mod fma; mod fmax; mod fmaximum; mod fmaximum_num; @@ -22,7 +21,6 @@ pub use copysign::copysign; pub use fabs::fabs; pub use fdim::fdim; pub use floor::floor; -pub use fma::{fma, fma_wide}; pub use fmax::fmax; pub use fmaximum::fmaximum; pub use fmaximum_num::fmaximum_num; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index e58d79adc419e..5fc8fa0b3cd02 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -164,7 +164,7 @@ mod fdimf; mod floor; mod floorf; mod fma; -mod fmaf; +mod fma_wide; mod fmin_fmax; mod fminimum_fmaximum; mod fminimum_fmaximum_num; @@ -271,7 +271,7 @@ pub use self::fdimf::fdimf; pub use self::floor::floor; pub use self::floorf::floorf; pub use self::fma::fma; -pub use self::fmaf::fmaf; +pub use self::fma_wide::fmaf; pub use self::fmin_fmax::{fmax, fmaxf, fmin, fminf}; pub use self::fminimum_fmaximum::{fmaximum, fmaximumf, fminimum, fminimumf}; pub use self::fminimum_fmaximum_num::{fmaximum_num, fmaximum_numf, fminimum_num, fminimum_numf}; @@ -370,6 +370,9 @@ cfg_if! { pub use self::sqrtf16::sqrtf16; pub use self::truncf16::truncf16; // verify-sorted-end + + #[allow(unused_imports)] + pub(crate) use self::fma_wide::fmaf16; } } @@ -381,7 +384,6 @@ cfg_if! { mod fabsf128; mod fdimf128; mod floorf128; - mod fmaf128; mod fmodf128; mod ldexpf128; mod roundf128; @@ -396,7 +398,7 @@ cfg_if! { pub use self::fabsf128::fabsf128; pub use self::fdimf128::fdimf128; pub use self::floorf128::floorf128; - pub use self::fmaf128::fmaf128; + pub use self::fma::fmaf128; pub use self::fmin_fmax::{fmaxf128, fminf128}; pub use self::fminimum_fmaximum::{fmaximumf128, fminimumf128}; pub use self::fminimum_fmaximum_num::{fmaximum_numf128, fminimum_numf128}; From c01153d29b1917d0d1c805f98a751f3ecaf5952b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 12 Feb 2025 10:16:48 +0000 Subject: [PATCH 1686/4206] Make `fma` a trait method on `Float` --- .../libm/crates/libm-test/src/f8_impl.rs | 4 +++ .../libm/etc/function-definitions.json | 3 +-- .../libm/etc/update-api-list.py | 2 +- .../compiler-builtins/libm/src/math/cbrt.rs | 20 +++----------- .../libm/src/math/support/float_traits.rs | 26 ++++++++++++++----- 5 files changed, 30 insertions(+), 25 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs index 56ea0b72995c7..0683d83926625 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs @@ -78,6 +78,10 @@ impl Float for f8 { libm::generic::copysign(self, other) } + fn fma(self, _y: Self, _z: Self) -> Self { + unimplemented!() + } + fn normalize(_significand: Self::Int) -> (i32, Self::Int) { unimplemented!() } diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index a966852b1128e..64a775ba9f173 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -130,8 +130,7 @@ "copysign": { "sources": [ "src/math/copysign.rs", - "src/math/generic/copysign.rs", - "src/math/support/float_traits.rs" + "src/math/generic/copysign.rs" ], "type": "f64" }, diff --git a/library/compiler-builtins/libm/etc/update-api-list.py b/library/compiler-builtins/libm/etc/update-api-list.py index c0b6e41d3002e..67d1b0508616e 100755 --- a/library/compiler-builtins/libm/etc/update-api-list.py +++ b/library/compiler-builtins/libm/etc/update-api-list.py @@ -24,7 +24,7 @@ DIRECTORIES = [".github", "ci", "crates", "etc", "src"] # These files do not trigger a retest. -IGNORED_SOURCES = ["src/libm_helper.rs"] +IGNORED_SOURCES = ["src/libm_helper.rs", "src/math/support/float_traits.rs"] IndexTy: TypeAlias = dict[str, dict[str, Any]] """Type of the `index` item in rustdoc's JSON output""" diff --git a/library/compiler-builtins/libm/src/math/cbrt.rs b/library/compiler-builtins/libm/src/math/cbrt.rs index 8560d37abf326..9d3311cd6a87a 100644 --- a/library/compiler-builtins/libm/src/math/cbrt.rs +++ b/library/compiler-builtins/libm/src/math/cbrt.rs @@ -103,11 +103,11 @@ pub fn cbrt_round(x: f64, round: Round) -> FpResult { * and rr an approximation of 1/zz. We now perform another iteration of * Newton-Raphson, this time with a linear approximation only. */ y2 = y * y; - let mut y2l: f64 = fmaf64(y, y, -y2); + let mut y2l: f64 = y.fma(y, -y2); /* y2 + y2l = y^2 exactly */ let mut y3: f64 = y2 * y; - let mut y3l: f64 = fmaf64(y, y2, -y3) + y * y2l; + let mut y3l: f64 = y.fma(y2, -y3) + y * y2l; /* y3 + y3l approximates y^3 with about 106 bits of accuracy */ h = ((y3 - zz) + y3l) * rr; @@ -132,9 +132,9 @@ pub fn cbrt_round(x: f64, round: Round) -> FpResult { cold_path(); y2 = y1 * y1; - y2l = fmaf64(y1, y1, -y2); + y2l = y1.fma(y1, -y2); y3 = y2 * y1; - y3l = fmaf64(y1, y2, -y3) + y1 * y2l; + y3l = y1.fma(y2, -y3) + y1 * y2l; h = ((y3 - zz) + y3l) * rr; dy = h * (y1 * u0); y = y1 - dy; @@ -198,18 +198,6 @@ pub fn cbrt_round(x: f64, round: Round) -> FpResult { FpResult::ok(f64::from_bits(cvt3)) } -fn fmaf64(x: f64, y: f64, z: f64) -> f64 { - #[cfg(intrinsics_enabled)] - { - return unsafe { core::intrinsics::fmaf64(x, y, z) }; - } - - #[cfg(not(intrinsics_enabled))] - { - return super::fma(x, y, z); - } -} - #[cfg(test)] mod tests { use super::*; 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 534ca9a07fa71..96c209c852b1d 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -160,9 +160,11 @@ pub trait Float: fn abs(self) -> Self; /// Returns a number composed of the magnitude of self and the sign of sign. - #[allow(dead_code)] fn copysign(self, other: Self) -> Self; + /// Fused multiply add, rounding once. + fn fma(self, y: Self, z: Self) -> Self; + /// Returns (normalized exponent, normalized significand) #[allow(dead_code)] fn normalize(significand: Self::Int) -> (i32, Self::Int); @@ -184,7 +186,9 @@ macro_rules! float_impl { $sity:ident, $bits:expr, $significand_bits:expr, - $from_bits:path + $from_bits:path, + $fma_fn:ident, + $fma_intrinsic:ident ) => { impl Float for $ty { type Int = $ity; @@ -252,6 +256,16 @@ macro_rules! float_impl { } } } + fn fma(self, y: Self, z: Self) -> Self { + cfg_if! { + // fma is not yet available in `core` + if #[cfg(intrinsics_enabled)] { + unsafe{ core::intrinsics::$fma_intrinsic(self, y, z) } + } else { + super::super::$fma_fn(self, y, z) + } + } + } 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) @@ -261,11 +275,11 @@ macro_rules! float_impl { } #[cfg(f16_enabled)] -float_impl!(f16, u16, i16, 16, 10, f16::from_bits); -float_impl!(f32, u32, i32, 32, 23, f32_from_bits); -float_impl!(f64, u64, i64, 64, 52, f64_from_bits); +float_impl!(f16, u16, i16, 16, 10, f16::from_bits, fmaf16, fmaf16); +float_impl!(f32, u32, i32, 32, 23, f32_from_bits, fmaf, fmaf32); +float_impl!(f64, u64, i64, 64, 52, f64_from_bits, fma, fmaf64); #[cfg(f128_enabled)] -float_impl!(f128, u128, i128, 128, 112, f128::from_bits); +float_impl!(f128, u128, i128, 128, 112, f128::from_bits, fmaf128, fmaf128); /* FIXME(msrv): vendor some things that are not const stable at our MSRV */ From bd41642818aa2f1ba3dea5a2ee0358bef3cd8f92 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 12 Feb 2025 21:06:15 +0000 Subject: [PATCH 1687/4206] Use `git ls-files` rather than manually globbing for tidy This avoids matching build directories, ignored files, and submodules. --- .../libm/etc/update-api-list.py | 54 +++++++++---------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/library/compiler-builtins/libm/etc/update-api-list.py b/library/compiler-builtins/libm/etc/update-api-list.py index 67d1b0508616e..b4ce2c453ce67 100755 --- a/library/compiler-builtins/libm/etc/update-api-list.py +++ b/library/compiler-builtins/libm/etc/update-api-list.py @@ -12,7 +12,7 @@ import subprocess as sp import sys from dataclasses import dataclass -from glob import glob, iglob +from glob import glob from pathlib import Path from typing import Any, Callable, TypeAlias @@ -20,9 +20,6 @@ ETC_DIR = SELF_PATH.parent ROOT_DIR = ETC_DIR.parent -# Loose approximation of what gets checked in to git, without needing `git ls-files`. -DIRECTORIES = [".github", "ci", "crates", "etc", "src"] - # These files do not trigger a retest. IGNORED_SOURCES = ["src/libm_helper.rs", "src/math/support/float_traits.rs"] @@ -190,30 +187,31 @@ def tidy_lists(self) -> None: """In each file, check annotations indicating blocks of code should be sorted or should include all public API. """ - for dirname in DIRECTORIES: - dir = ROOT_DIR.joinpath(dirname) - for fname in iglob("**", root_dir=dir, recursive=True): - fpath = dir.joinpath(fname) - 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), - ) + + 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 From 37da10edded0cd384769cbfc0c00e31a928bac66 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 18 Feb 2025 15:39:18 -0500 Subject: [PATCH 1688/4206] ci: Update actions/cache to v4 Github has deprecated v2 so this needs to be bumped. --- library/compiler-builtins/.github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index fee5c45eaf0e0..a801f2722b540 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -117,7 +117,7 @@ jobs: with: key: ${{ matrix.target }} - name: Cache Docker layers - uses: actions/cache@v2 + uses: actions/cache@v4 if: matrix.os == 'ubuntu-latest' with: path: /tmp/.buildx-cache From 4517c7ea90372047d5fbc7d84fcbf69e512b38a1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 18 Feb 2025 15:48:46 -0500 Subject: [PATCH 1689/4206] ci: Pin the nightly toolchain for i686-pc-windows-gnu Pin i686-pc-windows-gnu to nightly-2025-02-07 until [1] is resolved. [1]: https://github.com/rust-lang/rust/issues/136795 --- library/compiler-builtins/.github/workflows/main.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index a801f2722b540..1575730fe63fe 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -98,7 +98,8 @@ jobs: test_verbatim: 1 - target: i686-pc-windows-gnu os: windows-latest - rust: nightly-i686-gnu + # FIXME: pinned due to https://github.com/rust-lang/rust/issues/136795 + rust: nightly-2025-02-07-i686-gnu - target: x86_64-pc-windows-gnu os: windows-latest rust: nightly-x86_64-gnu From bade6290c8530005f06703a2bc2c4d595917c183 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 19 Feb 2025 15:26:07 -0500 Subject: [PATCH 1690/4206] ci: Pin the nightly toolchain for aarch64-unknown-linux-gnu Pin aarch64-unknown-linux-gnu to nightly-2025-02-07 until [1] is resolved. [1]: https://github.com/llvm/llvm-project/issues/127804 --- library/compiler-builtins/.github/workflows/main.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 1575730fe63fe..c179a33912785 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -20,7 +20,8 @@ jobs: rust: nightly - target: aarch64-unknown-linux-gnu os: ubuntu-latest - rust: nightly + # FIXME: pinned due to https://github.com/llvm/llvm-project/issues/127804 + rust: nightly-2025-02-07 - target: aarch64-pc-windows-msvc os: windows-latest rust: nightly From 2b6de7a68fb00157be0a3aa72612008dfe774cf4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Feb 2025 14:29:37 +0100 Subject: [PATCH 1691/4206] remove win64_128bit_abi_hack --- library/compiler-builtins/src/float/conv.rs | 4 -- library/compiler-builtins/src/int/sdiv.rs | 4 +- library/compiler-builtins/src/int/udiv.rs | 3 - library/compiler-builtins/src/macros.rs | 71 --------------------- 4 files changed, 2 insertions(+), 80 deletions(-) diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/src/float/conv.rs index 4f52ac7120d94..42a526bd52410 100644 --- a/library/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/src/float/conv.rs @@ -403,7 +403,6 @@ intrinsics! { float_to_unsigned_int(f) } - #[win64_128bit_abi_hack] pub extern "C" fn __fixunssfti(f: f32) -> u128 { float_to_unsigned_int(f) } @@ -418,7 +417,6 @@ intrinsics! { float_to_unsigned_int(f) } - #[win64_128bit_abi_hack] pub extern "C" fn __fixunsdfti(f: f64) -> u128 { float_to_unsigned_int(f) } @@ -454,7 +452,6 @@ intrinsics! { float_to_signed_int(f) } - #[win64_128bit_abi_hack] pub extern "C" fn __fixsfti(f: f32) -> i128 { float_to_signed_int(f) } @@ -469,7 +466,6 @@ intrinsics! { float_to_signed_int(f) } - #[win64_128bit_abi_hack] pub extern "C" fn __fixdfti(f: f64) -> i128 { float_to_signed_int(f) } diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/src/int/sdiv.rs index 9d316c76ecad3..9630c7d7de374 100644 --- a/library/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/src/int/sdiv.rs @@ -165,5 +165,5 @@ sdivmod!( i128, maybe_use_optimized_c_shim ); -sdiv!(__udivti3, __divti3, u128, i128, win64_128bit_abi_hack); -smod!(__umodti3, __modti3, u128, i128, win64_128bit_abi_hack); +sdiv!(__udivti3, __divti3, u128, i128,); +smod!(__umodti3, __modti3, u128, i128,); diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/src/int/udiv.rs index c891eede4b1aa..1fa761212b2f2 100644 --- a/library/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/src/int/udiv.rs @@ -58,7 +58,6 @@ intrinsics! { // the existence of `u128_div_rem` to get 32-bit SPARC to compile, see `u128_divide_sparc` docs. #[avr_skip] - #[win64_128bit_abi_hack] /// Returns `n / d` pub extern "C" fn __udivti3(n: u128, d: u128) -> u128 { #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] { @@ -70,7 +69,6 @@ intrinsics! { } #[avr_skip] - #[win64_128bit_abi_hack] /// Returns `n % d` pub extern "C" fn __umodti3(n: u128, d: u128) -> u128 { #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] { @@ -84,7 +82,6 @@ intrinsics! { } #[avr_skip] - #[win64_128bit_abi_hack] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmodti4(n: u128, d: u128, rem: Option<&mut u128>) -> u128 { #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] { diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index f51e49e987661..88b54e82ca0f5 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -60,9 +60,6 @@ macro_rules! public_test_dep { /// the specified ABI everywhere else. /// * `unadjusted_on_win64` - like `aapcs_on_arm` this switches to the /// `"unadjusted"` abi on Win64 and the specified abi elsewhere. -/// * `win64_128bit_abi_hack` - this attribute is used for 128-bit integer -/// intrinsics where the ABI is slightly tweaked on Windows platforms, but -/// it's a normal ABI elsewhere for returning a 128 bit integer. /// * `arm_aeabi_alias` - handles the "aliasing" of various intrinsics on ARM /// their otherwise typical names to other prefixed ones. /// * `ppc_alias` - changes the name of the symbol on PowerPC platforms without @@ -231,51 +228,6 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); - // Some intrinsics on win64 which return a 128-bit integer have an.. unusual - // calling convention. That's managed here with this "abi hack" which alters - // the generated symbol's ABI. - // - // This will still define a function in this crate with the given name and - // signature, but the actual symbol for the intrinsic may have a slightly - // different ABI on win64. - ( - #[win64_128bit_abi_hack] - $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { - $($body:tt)* - } - - $($rest:tt)* - ) => ( - #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64"))] - $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - - #[cfg(all(any(windows, target_os = "uefi"), target_arch = "x86_64", not(feature = "mangled-names")))] - mod $name { - #[no_mangle] - #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] - extern $abi fn $name( $($argname: $ty),* ) - -> $crate::macros::win64_128bit_abi_hack::U64x2 - { - let e: $($ret)? = super::$name($($argname),*); - $crate::macros::win64_128bit_abi_hack::U64x2::from(e) - } - } - - #[cfg(not(all(any(windows, target_os = "uefi"), target_arch = "x86_64")))] - intrinsics! { - $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - } - - intrinsics!($($rest)*); - ); - // `arm_aeabi_alias` would conflict with `f16_apple_{arg,ret}_abi` not handled here. Avoid macro ambiguity by combining in a // single `#[]`. ( @@ -576,26 +528,3 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); } - -// Hack for LLVM expectations for ABI on windows. This is used by the -// `#[win64_128bit_abi_hack]` attribute recognized above -#[cfg(all(any(windows, target_os = "uefi"), target_pointer_width = "64"))] -pub mod win64_128bit_abi_hack { - #[repr(simd)] - pub struct U64x2([u64; 2]); - - impl From for U64x2 { - fn from(i: i128) -> U64x2 { - use crate::int::DInt; - let j = i as u128; - U64x2([j.lo(), j.hi()]) - } - } - - impl From for U64x2 { - fn from(i: u128) -> U64x2 { - use crate::int::DInt; - U64x2([i.lo(), i.hi()]) - } - } -} From f851256581d697ee1b211a57403ba4dd468d7f52 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 19 Feb 2025 20:45:07 +0000 Subject: [PATCH 1692/4206] chore: release v0.1.147 --- library/compiler-builtins/CHANGELOG.md | 6 ++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index d6962dc5b5e03..a3890c6ce732d 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.147](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.146...compiler_builtins-v0.1.147) - 2025-02-19 + +### Other + +- remove win64_128bit_abi_hack + ## [0.1.146](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.145...compiler_builtins-v0.1.146) - 2025-02-06 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index c93ca563c4e74..ff1a10fc6267e 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.146" +version = "0.1.147" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 0fdeab95250126d135a4bf14cb8959038481204c Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Thu, 20 Feb 2025 08:23:08 -0800 Subject: [PATCH 1693/4206] Guarantee behavior of transmuting Option::::None subject to NPO --- library/core/src/option.rs | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index ff48575e2c06f..7b55093694217 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -120,20 +120,22 @@ //! //! Rust guarantees to optimize the following types `T` such that //! [`Option`] has the same size, alignment, and [function call ABI] as `T`. In some -//! of these cases, Rust further guarantees that -//! `transmute::<_, Option>([0u8; size_of::()])` is sound and -//! produces `Option::::None`. These cases are identified by the -//! second column: -//! -//! | `T` | `transmute::<_, Option>([0u8; size_of::()])` sound? | -//! |---------------------------------------------------------------------|----------------------------------------------------------------------| -//! | [`Box`] (specifically, only `Box`) | when `U: Sized` | -//! | `&U` | when `U: Sized` | -//! | `&mut U` | when `U: Sized` | -//! | `fn`, `extern "C" fn`[^extern_fn] | always | -//! | [`num::NonZero*`] | always | -//! | [`ptr::NonNull`] | when `U: Sized` | -//! | `#[repr(transparent)]` struct around one of the types in this list. | when it holds for the inner type | +//! of these cases, Rust further guarantees the following: +//! - `transmute::<_, Option>([0u8; size_of::()])` is sound and produces +//! `Option::::None` +//! - `transmute::<_, [u8; size_of::()]>(Option::::None)` is sound and produces +//! `[0u8; size_of::()]` +//! These cases are identified by the second column: +//! +//! | `T` | Transmuting between `[0u8; size_of::()]` and `Option::::None` sound? | +//! |---------------------------------------------------------------------|----------------------------------------------------------------------------| +//! | [`Box`] (specifically, only `Box`) | when `U: Sized` | +//! | `&U` | when `U: Sized` | +//! | `&mut U` | when `U: Sized` | +//! | `fn`, `extern "C" fn`[^extern_fn] | always | +//! | [`num::NonZero*`] | always | +//! | [`ptr::NonNull`] | when `U: Sized` | +//! | `#[repr(transparent)]` struct around one of the types in this list. | when it holds for the inner type | //! //! [^extern_fn]: this remains true for any argument/return types and any other ABI: `extern "abi" fn` (_e.g._, `extern "system" fn`) //! From 3d50334314cb41f2334f201458d4be0aa15ae203 Mon Sep 17 00:00:00 2001 From: yukang Date: Thu, 16 Jan 2025 10:25:59 +0800 Subject: [PATCH 1694/4206] Add ignore value suggestion in closure body --- compiler/rustc_hir_typeck/src/coercion.rs | 7 ++--- compiler/rustc_hir_typeck/src/expr.rs | 2 +- .../src/fn_ctxt/suggestions.rs | 13 ++++++++++ .../closure-ty-mismatch-issue-128561.rs | 10 +++++++ .../closure-ty-mismatch-issue-128561.stderr | 26 +++++++++++++++++++ 5 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 tests/ui/typeck/closure-ty-mismatch-issue-128561.rs create mode 100644 tests/ui/typeck/closure-ty-mismatch-issue-128561.stderr diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 625c7f38fbb40..2217eb33062d7 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1891,9 +1891,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { kind: hir::ExprKind::Closure(&hir::Closure { body, .. }), .. }) = parent - && !matches!(fcx.tcx.hir_body(body).value.kind, hir::ExprKind::Block(..)) { - fcx.suggest_missing_semicolon(&mut err, expr, expected, true); + let needs_block = + !matches!(fcx.tcx.hir_body(body).value.kind, hir::ExprKind::Block(..)); + fcx.suggest_missing_semicolon(&mut err, expr, expected, needs_block, true); } // Verify that this is a tail expression of a function, otherwise the // label pointing out the cause for the type coercion will be wrong @@ -1901,7 +1902,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { if let Some(expr) = expression && due_to_block { - fcx.suggest_missing_semicolon(&mut err, expr, expected, false); + fcx.suggest_missing_semicolon(&mut err, expr, expected, false, false); let pointing_at_return_type = fcx.suggest_mismatched_types_on_tail( &mut err, expr, diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 277396da19c13..25b58c7fd9d44 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -921,7 +921,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self, &cause, |mut err| { - self.suggest_missing_semicolon(&mut err, expr, e_ty, false); + self.suggest_missing_semicolon(&mut err, expr, e_ty, false, false); self.suggest_mismatched_types_on_tail( &mut err, expr, ty, e_ty, target_id, ); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index f9fc121593637..f8d860cf7b7ac 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -754,6 +754,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expression: &'tcx hir::Expr<'tcx>, expected: Ty<'tcx>, needs_block: bool, + parent_is_closure: bool, ) { if expected.is_unit() { // `BlockTailExpression` only relevant if the tail expr would be @@ -789,6 +790,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } } + ExprKind::Path(..) | ExprKind::Lit(_) if parent_is_closure => { + err.span_suggestion( + expression.span.shrink_to_lo(), + "consider ignore the value here", + "_ = ", + if in_external_macro(self.tcx.sess, expression.span) { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }, + ); + } _ => (), } } diff --git a/tests/ui/typeck/closure-ty-mismatch-issue-128561.rs b/tests/ui/typeck/closure-ty-mismatch-issue-128561.rs new file mode 100644 index 0000000000000..589a90e71d6ec --- /dev/null +++ b/tests/ui/typeck/closure-ty-mismatch-issue-128561.rs @@ -0,0 +1,10 @@ +fn main() { + b"abc".iter().for_each(|x| x); //~ ERROR: mismatched types + + b"abc".iter().for_each(|x| dbg!(x)); //~ ERROR: mismatched types + + b"abc".iter().for_each(|x| { + println!("{}", x); + x //~ ERROR: mismatched types + }) +} diff --git a/tests/ui/typeck/closure-ty-mismatch-issue-128561.stderr b/tests/ui/typeck/closure-ty-mismatch-issue-128561.stderr new file mode 100644 index 0000000000000..f9b606cd52da7 --- /dev/null +++ b/tests/ui/typeck/closure-ty-mismatch-issue-128561.stderr @@ -0,0 +1,26 @@ +error[E0308]: mismatched types + --> $DIR/closure-ty-mismatch-issue-128561.rs:2:32 + | +LL | b"abc".iter().for_each(|x| x); + | ^ + | | + | expected `()`, found `&u8` + | help: consider ignore the value here: `_ =` + +error[E0308]: mismatched types + --> $DIR/closure-ty-mismatch-issue-128561.rs:4:32 + | +LL | b"abc".iter().for_each(|x| dbg!(x)); + | ^^^^^^^ expected `()`, found `&u8` + | + = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> $DIR/closure-ty-mismatch-issue-128561.rs:8:9 + | +LL | x + | ^ expected `()`, found `&u8` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. From 8cddffb74ef7fa75767c710e9f85bd4389159adb Mon Sep 17 00:00:00 2001 From: Yukang Date: Fri, 17 Jan 2025 08:19:17 +0800 Subject: [PATCH 1695/4206] Update compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs Co-authored-by: Esteban Kuber --- compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index f8d860cf7b7ac..a34f3d27fb6c5 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -793,7 +793,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::Path(..) | ExprKind::Lit(_) if parent_is_closure => { err.span_suggestion( expression.span.shrink_to_lo(), - "consider ignore the value here", + "consider ignoring the value", "_ = ", if in_external_macro(self.tcx.sess, expression.span) { Applicability::MaybeIncorrect From d6d9c2e7516c687553480a4e171f89dfc22009dd Mon Sep 17 00:00:00 2001 From: Yukang Date: Fri, 17 Jan 2025 08:19:23 +0800 Subject: [PATCH 1696/4206] Update compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs Co-authored-by: Esteban Kuber --- compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 2 +- .../ui/typeck/closure-ty-mismatch-issue-128561.stderr | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index a34f3d27fb6c5..a31abef43757b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -791,7 +791,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } ExprKind::Path(..) | ExprKind::Lit(_) if parent_is_closure => { - err.span_suggestion( + err.span_suggestion_verbose( expression.span.shrink_to_lo(), "consider ignoring the value", "_ = ", diff --git a/tests/ui/typeck/closure-ty-mismatch-issue-128561.stderr b/tests/ui/typeck/closure-ty-mismatch-issue-128561.stderr index f9b606cd52da7..31acc5bb10ec0 100644 --- a/tests/ui/typeck/closure-ty-mismatch-issue-128561.stderr +++ b/tests/ui/typeck/closure-ty-mismatch-issue-128561.stderr @@ -2,10 +2,12 @@ error[E0308]: mismatched types --> $DIR/closure-ty-mismatch-issue-128561.rs:2:32 | LL | b"abc".iter().for_each(|x| x); - | ^ - | | - | expected `()`, found `&u8` - | help: consider ignore the value here: `_ =` + | ^ expected `()`, found `&u8` + | +help: consider ignoring the value + | +LL | b"abc".iter().for_each(|x| _ = x); + | +++ error[E0308]: mismatched types --> $DIR/closure-ty-mismatch-issue-128561.rs:4:32 From 774ab462d692615d65dc79bb36685ac5cfebd7d4 Mon Sep 17 00:00:00 2001 From: yukang Date: Fri, 17 Jan 2025 12:15:25 +0800 Subject: [PATCH 1697/4206] code cleanup and do not suggest for external macro except we get better solution --- compiler/rustc_hir_typeck/src/coercion.rs | 4 +--- compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 11 +++++------ 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 2217eb33062d7..afa7175238c6b 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1883,9 +1883,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { fcx.err_ctxt().report_mismatched_types(cause, fcx.param_env, expected, found, ty_err); let due_to_block = matches!(fcx.tcx.hir_node(block_or_return_id), hir::Node::Block(..)); - - let parent_id = fcx.tcx.parent_hir_id(block_or_return_id); - let parent = fcx.tcx.hir_node(parent_id); + let parent = fcx.tcx.parent_hir_node(block_or_return_id); if let Some(expr) = expression && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { body, .. }), diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index a31abef43757b..8f2665212b86b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -790,16 +790,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } } - ExprKind::Path(..) | ExprKind::Lit(_) if parent_is_closure => { + ExprKind::Path(..) | ExprKind::Lit(_) + if parent_is_closure + && !expression.span.in_external_macro(self.tcx.sess.source_map()) => + { err.span_suggestion_verbose( expression.span.shrink_to_lo(), "consider ignoring the value", "_ = ", - if in_external_macro(self.tcx.sess, expression.span) { - Applicability::MaybeIncorrect - } else { - Applicability::MachineApplicable - }, + Applicability::MachineApplicable, ); } _ => (), From 54e7ff15c08ee84db226d4e79ad703c689588ffc Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 23 Feb 2025 08:21:22 +0000 Subject: [PATCH 1698/4206] Revert "ci: Pin the nightly toolchain for i686-pc-windows-gnu" Since [1], the issue should be resolved so the workaround can be dropped. This reverts commit 88e83b96ad09f3cf9e2d1b4543a7d43f9c5a77c0. [1]: https://github.com/rust-lang/compiler-builtins/pull/759 --- library/compiler-builtins/.github/workflows/main.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index c179a33912785..7336efc4224e7 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -99,8 +99,7 @@ jobs: test_verbatim: 1 - target: i686-pc-windows-gnu os: windows-latest - # FIXME: pinned due to https://github.com/rust-lang/rust/issues/136795 - rust: nightly-2025-02-07-i686-gnu + rust: nightly-i686-gnu - target: x86_64-pc-windows-gnu os: windows-latest rust: nightly-x86_64-gnu From c32bc8398a546c0346dbb3e563c8658d1d772349 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 24 Feb 2025 01:23:37 +0000 Subject: [PATCH 1699/4206] ci: Pin the nightly toolchain for aarch64 jobs Pin aarch64-unknown-linux-gnu and aarch64-apple-darwin to nightly-2025-02-07 until [1] makes it to a Rust nightly. [1]: https://github.com/llvm/llvm-project/issues/127804 --- library/compiler-builtins/libm/.github/workflows/main.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index f066f4a8c1f85..e86f936f74fa8 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -22,8 +22,12 @@ jobs: include: - target: aarch64-apple-darwin os: macos-15 + # FIXME: pinned due to https://github.com/llvm/llvm-project/issues/127804 + channel: nightly-2025-02-07 - target: aarch64-unknown-linux-gnu os: ubuntu-24.04-arm + # FIXME: pinned due to https://github.com/llvm/llvm-project/issues/127804 + channel: nightly-2025-02-07 - target: aarch64-pc-windows-msvc os: windows-2025 build_only: 1 # Can't run on x86 hosts From ba8f07282e233413ed34aaf7576690265aeed25f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 24 Feb 2025 00:01:04 +0000 Subject: [PATCH 1700/4206] Make the compiler-builtins test more accurately mirror compiler-builtins In `compiler-builtins`, `libm` is contained within a `math` module. The smoke test in this repo has a slightly different layout so some things were passing that shouldn't be. Change module layouts in `compiler-builtins-smoke-test` to match `compiler-builtins` and update a few instances of broken paths. --- .../compiler-builtins-smoke-test/src/lib.rs | 185 +----------------- .../compiler-builtins-smoke-test/src/math.rs | 182 +++++++++++++++++ .../compiler-builtins/libm/src/math/fma.rs | 2 +- .../libm/src/math/fma_wide.rs | 2 +- 4 files changed, 186 insertions(+), 185 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index 77a4666a1023a..f9e6e75a870a3 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -10,187 +10,6 @@ #![allow(internal_features)] #![no_std] -#[allow(dead_code)] -#[allow(clippy::all)] // We don't get `libm`'s list of `allow`s, so just ignore Clippy. -#[path = "../../../src/math/mod.rs"] -pub mod libm; - -use core::ffi::c_int; - +mod math; // Required for macro paths. -use libm::support; - -/// Mark functions `#[no_mangle]` and with the C ABI. -macro_rules! no_mangle { - ($( $name:ident( $($tt:tt)+ ) -> $ret:ty; )+) => { - $( no_mangle!(@inner $name( $($tt)+ ) -> $ret); )+ - }; - - // Handle simple functions with single return types - (@inner $name:ident( $($arg:ident: $aty:ty),+ ) -> $ret:ty) => { - #[no_mangle] - extern "C" fn $name($($arg: $aty),+) -> $ret { - libm::$name($($arg),+) - } - }; - - - // Functions with `&mut` return values need to be handled differently, use `|` to - // separate inputs vs. outputs. - ( - @inner $name:ident( $($arg:ident: $aty:ty),+ | $($rarg:ident: $rty:ty),+) -> $ret:ty - ) => { - #[no_mangle] - extern "C" fn $name($($arg: $aty,)+ $($rarg: $rty),+) -> $ret { - let ret; - (ret, $(*$rarg),+) = libm::$name($($arg),+); - ret - } - }; -} - -no_mangle! { - frexp(x: f64 | y: &mut c_int) -> f64; - frexpf(x: f32 | y: &mut c_int) -> f32; - acos(x: f64) -> f64; - acosf(x: f32) -> f32; - acosh(x: f64) -> f64; - acoshf(x: f32) -> f32; - asin(x: f64) -> f64; - asinf(x: f32) -> f32; - asinh(x: f64) -> f64; - asinhf(x: f32) -> f32; - atan(x: f64) -> f64; - atan2(x: f64, y: f64) -> f64; - atan2f(x: f32, y: f32) -> f32; - atanf(x: f32) -> f32; - atanh(x: f64) -> f64; - atanhf(x: f32) -> f32; - cbrt(x: f64) -> f64; - cbrtf(x: f32) -> f32; - ceil(x: f64) -> f64; - ceilf(x: f32) -> f32; - ceilf128(x: f128) -> f128; - ceilf16(x: f16) -> f16; - copysign(x: f64, y: f64) -> f64; - copysignf(x: f32, y: f32) -> f32; - copysignf128(x: f128, y: f128) -> f128; - copysignf16(x: f16, y: f16) -> f16; - cos(x: f64) -> f64; - cosf(x: f32) -> f32; - cosh(x: f64) -> f64; - coshf(x: f32) -> f32; - erf(x: f64) -> f64; - erfc(x: f64) -> f64; - erfcf(x: f32) -> f32; - erff(x: f32) -> f32; - exp(x: f64) -> f64; - exp10(x: f64) -> f64; - exp10f(x: f32) -> f32; - exp2(x: f64) -> f64; - exp2f(x: f32) -> f32; - expf(x: f32) -> f32; - expm1(x: f64) -> f64; - expm1f(x: f32) -> f32; - fabs(x: f64) -> f64; - fabsf(x: f32) -> f32; - fabsf128(x: f128) -> f128; - fabsf16(x: f16) -> f16; - fdim(x: f64, y: f64) -> f64; - fdimf(x: f32, y: f32) -> f32; - fdimf128(x: f128, y: f128) -> f128; - fdimf16(x: f16, y: f16) -> f16; - floor(x: f64) -> f64; - floorf(x: f32) -> f32; - floorf128(x: f128) -> f128; - floorf16(x: f16) -> f16; - fma(x: f64, y: f64, z: f64) -> f64; - fmaf(x: f32, y: f32, z: f32) -> f32; - fmax(x: f64, y: f64) -> f64; - fmaxf(x: f32, y: f32) -> f32; - fmin(x: f64, y: f64) -> f64; - fminf(x: f32, y: f32) -> f32; - fmod(x: f64, y: f64) -> f64; - fmodf(x: f32, y: f32) -> f32; - hypot(x: f64, y: f64) -> f64; - hypotf(x: f32, y: f32) -> f32; - ilogb(x: f64) -> c_int; - ilogbf(x: f32) -> c_int; - j0(x: f64) -> f64; - j0f(x: f32) -> f32; - j1(x: f64) -> f64; - j1f(x: f32) -> f32; - jn(x: c_int, y: f64) -> f64; - jnf(x: c_int, y: f32) -> f32; - ldexp(x: f64, y: c_int) -> f64; - ldexpf(x: f32, y: c_int) -> f32; - lgamma(x: f64) -> f64; - lgamma_r(x: f64 | r: &mut c_int) -> f64; - lgammaf(x: f32) -> f32; - lgammaf_r(x: f32 | r: &mut c_int) -> f32; - log(x: f64) -> f64; - log10(x: f64) -> f64; - log10f(x: f32) -> f32; - log1p(x: f64) -> f64; - log1pf(x: f32) -> f32; - log2(x: f64) -> f64; - log2f(x: f32) -> f32; - logf(x: f32) -> f32; - modf(x: f64 | r: &mut f64) -> f64; - modff(x: f32 | r: &mut f32) -> f32; - nextafter(x: f64, y: f64) -> f64; - nextafterf(x: f32, y: f32) -> f32; - pow(x: f64, y: f64) -> f64; - powf(x: f32, y: f32) -> f32; - remainder(x: f64, y: f64) -> f64; - remainderf(x: f32, y: f32) -> f32; - remquo(x: f64, y: f64 | q: &mut c_int) -> f64; - remquof(x: f32, y: f32 | q: &mut c_int) -> f32; - rint(x: f64) -> f64; - rintf(x: f32) -> f32; - rintf128(x: f128) -> f128; - rintf16(x: f16) -> f16; - round(x: f64) -> f64; - roundf(x: f32) -> f32; - scalbn(x: f64, y: c_int) -> f64; - scalbnf(x: f32, y: c_int) -> f32; - sin(x: f64) -> f64; - sinf(x: f32) -> f32; - sinh(x: f64) -> f64; - sinhf(x: f32) -> f32; - sqrt(x: f64) -> f64; - sqrtf(x: f32) -> f32; - tan(x: f64) -> f64; - tanf(x: f32) -> f32; - tanh(x: f64) -> f64; - tanhf(x: f32) -> f32; - tgamma(x: f64) -> f64; - tgammaf(x: f32) -> f32; - trunc(x: f64) -> f64; - truncf(x: f32) -> f32; - truncf128(x: f128) -> f128; - truncf16(x: f16) -> f16; - y0(x: f64) -> f64; - y0f(x: f32) -> f32; - y1(x: f64) -> f64; - y1f(x: f32) -> f32; - yn(x: c_int, y: f64) -> f64; - ynf(x: c_int, y: f32) -> f32; -} - -/* sincos has no direct return type, not worth handling in the macro */ - -#[no_mangle] -extern "C" fn sincos(x: f64, s: &mut f64, c: &mut f64) { - (*s, *c) = libm::sincos(x); -} - -#[no_mangle] -extern "C" fn sincosf(x: f32, s: &mut f32, c: &mut f32) { - (*s, *c) = libm::sincosf(x); -} - -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} +use math::libm::support; diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs new file mode 100644 index 0000000000000..7e0146998aae1 --- /dev/null +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs @@ -0,0 +1,182 @@ +use core::ffi::c_int; + +#[allow(dead_code)] +#[allow(clippy::all)] // We don't get `libm`'s list of `allow`s, so just ignore Clippy. +#[allow(unused_imports)] +#[path = "../../../src/math/mod.rs"] +pub mod libm; + +/// Mark functions `#[no_mangle]` and with the C ABI. +macro_rules! no_mangle { + ($( $name:ident( $($tt:tt)+ ) -> $ret:ty; )+) => { + $( no_mangle!(@inner $name( $($tt)+ ) -> $ret); )+ + }; + + // Handle simple functions with single return types + (@inner $name:ident( $($arg:ident: $aty:ty),+ ) -> $ret:ty) => { + #[no_mangle] + extern "C" fn $name($($arg: $aty),+) -> $ret { + libm::$name($($arg),+) + } + }; + + + // Functions with `&mut` return values need to be handled differently, use `|` to + // separate inputs vs. outputs. + ( + @inner $name:ident( $($arg:ident: $aty:ty),+ | $($rarg:ident: $rty:ty),+) -> $ret:ty + ) => { + #[no_mangle] + extern "C" fn $name($($arg: $aty,)+ $($rarg: $rty),+) -> $ret { + let ret; + (ret, $(*$rarg),+) = libm::$name($($arg),+); + ret + } + }; +} + +no_mangle! { + frexp(x: f64 | y: &mut c_int) -> f64; + frexpf(x: f32 | y: &mut c_int) -> f32; + acos(x: f64) -> f64; + acosf(x: f32) -> f32; + acosh(x: f64) -> f64; + acoshf(x: f32) -> f32; + asin(x: f64) -> f64; + asinf(x: f32) -> f32; + asinh(x: f64) -> f64; + asinhf(x: f32) -> f32; + atan(x: f64) -> f64; + atan2(x: f64, y: f64) -> f64; + atan2f(x: f32, y: f32) -> f32; + atanf(x: f32) -> f32; + atanh(x: f64) -> f64; + atanhf(x: f32) -> f32; + cbrt(x: f64) -> f64; + cbrtf(x: f32) -> f32; + ceil(x: f64) -> f64; + ceilf(x: f32) -> f32; + ceilf128(x: f128) -> f128; + ceilf16(x: f16) -> f16; + copysign(x: f64, y: f64) -> f64; + copysignf(x: f32, y: f32) -> f32; + copysignf128(x: f128, y: f128) -> f128; + copysignf16(x: f16, y: f16) -> f16; + cos(x: f64) -> f64; + cosf(x: f32) -> f32; + cosh(x: f64) -> f64; + coshf(x: f32) -> f32; + erf(x: f64) -> f64; + erfc(x: f64) -> f64; + erfcf(x: f32) -> f32; + erff(x: f32) -> f32; + exp(x: f64) -> f64; + exp10(x: f64) -> f64; + exp10f(x: f32) -> f32; + exp2(x: f64) -> f64; + exp2f(x: f32) -> f32; + expf(x: f32) -> f32; + expm1(x: f64) -> f64; + expm1f(x: f32) -> f32; + fabs(x: f64) -> f64; + fabsf(x: f32) -> f32; + fabsf128(x: f128) -> f128; + fabsf16(x: f16) -> f16; + fdim(x: f64, y: f64) -> f64; + fdimf(x: f32, y: f32) -> f32; + fdimf128(x: f128, y: f128) -> f128; + fdimf16(x: f16, y: f16) -> f16; + floor(x: f64) -> f64; + floorf(x: f32) -> f32; + floorf128(x: f128) -> f128; + floorf16(x: f16) -> f16; + fma(x: f64, y: f64, z: f64) -> f64; + fmaf(x: f32, y: f32, z: f32) -> f32; + fmax(x: f64, y: f64) -> f64; + fmaxf(x: f32, y: f32) -> f32; + fmin(x: f64, y: f64) -> f64; + fminf(x: f32, y: f32) -> f32; + fmod(x: f64, y: f64) -> f64; + fmodf(x: f32, y: f32) -> f32; + hypot(x: f64, y: f64) -> f64; + hypotf(x: f32, y: f32) -> f32; + ilogb(x: f64) -> c_int; + ilogbf(x: f32) -> c_int; + j0(x: f64) -> f64; + j0f(x: f32) -> f32; + j1(x: f64) -> f64; + j1f(x: f32) -> f32; + jn(x: c_int, y: f64) -> f64; + jnf(x: c_int, y: f32) -> f32; + ldexp(x: f64, y: c_int) -> f64; + ldexpf(x: f32, y: c_int) -> f32; + lgamma(x: f64) -> f64; + lgamma_r(x: f64 | r: &mut c_int) -> f64; + lgammaf(x: f32) -> f32; + lgammaf_r(x: f32 | r: &mut c_int) -> f32; + log(x: f64) -> f64; + log10(x: f64) -> f64; + log10f(x: f32) -> f32; + log1p(x: f64) -> f64; + log1pf(x: f32) -> f32; + log2(x: f64) -> f64; + log2f(x: f32) -> f32; + logf(x: f32) -> f32; + modf(x: f64 | r: &mut f64) -> f64; + modff(x: f32 | r: &mut f32) -> f32; + nextafter(x: f64, y: f64) -> f64; + nextafterf(x: f32, y: f32) -> f32; + pow(x: f64, y: f64) -> f64; + powf(x: f32, y: f32) -> f32; + remainder(x: f64, y: f64) -> f64; + remainderf(x: f32, y: f32) -> f32; + remquo(x: f64, y: f64 | q: &mut c_int) -> f64; + remquof(x: f32, y: f32 | q: &mut c_int) -> f32; + rint(x: f64) -> f64; + rintf(x: f32) -> f32; + rintf128(x: f128) -> f128; + rintf16(x: f16) -> f16; + round(x: f64) -> f64; + roundf(x: f32) -> f32; + scalbn(x: f64, y: c_int) -> f64; + scalbnf(x: f32, y: c_int) -> f32; + sin(x: f64) -> f64; + sinf(x: f32) -> f32; + sinh(x: f64) -> f64; + sinhf(x: f32) -> f32; + sqrt(x: f64) -> f64; + sqrtf(x: f32) -> f32; + tan(x: f64) -> f64; + tanf(x: f32) -> f32; + tanh(x: f64) -> f64; + tanhf(x: f32) -> f32; + tgamma(x: f64) -> f64; + tgammaf(x: f32) -> f32; + trunc(x: f64) -> f64; + truncf(x: f32) -> f32; + truncf128(x: f128) -> f128; + truncf16(x: f16) -> f16; + y0(x: f64) -> f64; + y0f(x: f32) -> f32; + y1(x: f64) -> f64; + y1f(x: f32) -> f32; + yn(x: c_int, y: f64) -> f64; + ynf(x: c_int, y: f32) -> f32; +} + +/* sincos has no direct return type, not worth handling in the macro */ + +#[no_mangle] +extern "C" fn sincos(x: f64, s: &mut f64, c: &mut f64) { + (*s, *c) = libm::sincos(x); +} + +#[no_mangle] +extern "C" fn sincosf(x: f32, s: &mut f32, c: &mut f32) { + (*s, *c) = libm::sincosf(x); +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index a54984c936b7f..049f573cc92a6 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: MIT */ /* origin: musl src/math/fma.c. Ported to generic Rust algorithm in 2025, TG. */ -use super::super::support::{DInt, FpResult, HInt, IntTy, Round, Status}; +use super::support::{DInt, FpResult, HInt, IntTy, Round, Status}; use super::{CastFrom, CastInto, Float, Int, MinInt}; /// Fused multiply add (f64) diff --git a/library/compiler-builtins/libm/src/math/fma_wide.rs b/library/compiler-builtins/libm/src/math/fma_wide.rs index a8c1a548879d8..d0cf33baf7a87 100644 --- a/library/compiler-builtins/libm/src/math/fma_wide.rs +++ b/library/compiler-builtins/libm/src/math/fma_wide.rs @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: MIT */ /* origin: musl src/math/fmaf.c. Ported to generic Rust algorithm in 2025, TG. */ -use super::super::support::{FpResult, IntTy, Round, Status}; +use super::support::{FpResult, IntTy, Round, Status}; use super::{CastFrom, CastInto, DFloat, Float, HFloat, MinInt}; // Placeholder so we can have `fmaf16` in the `Float` trait. From f42c9632a60fab39127fd0bbbfab5d4b0d1c7862 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 15 Jan 2025 05:27:14 +0000 Subject: [PATCH 1701/4206] Eliminate the use of `public_test_dep!` for a third time Replace `public_test_dep!` by placing optionally public items into new modules, then controlling what is exported with the `public-test-deps` feature. This is nicer for automatic formatting and diagnostics. This is a reland of 2e2a9255 ("Eliminate the use of `public_test_dep!`"), which was reverted in 47e50fd2 ('Revert "Eliminate the use of..."') due to a bug exposed at [1], reapplied in d4abaf4efa because the issue should have been fixed in [2], then reverted again in f6eef07f53 because [2] did not actually fix the issue. [3] has landed in rust-lang/rust since then, which should resolve the last problem remaining after [2]. So, apply this change for what is hopefully the final time. [1]: https://github.com/rust-lang/rust/pull/128691 [2]: https://github.com/rust-lang/rust/pull/135278 [3]: https://github.com/rust-lang/rust/pull/135501 --- library/compiler-builtins/src/float/mod.rs | 195 +------- library/compiler-builtins/src/float/traits.rs | 189 ++++++++ .../src/int/leading_zeros.rs | 227 +++++----- library/compiler-builtins/src/int/mod.rs | 424 +----------------- .../src/int/specialized_div_rem/delegate.rs | 4 +- .../src/int/trailing_zeros.rs | 69 +-- library/compiler-builtins/src/int/traits.rs | 411 +++++++++++++++++ library/compiler-builtins/src/macros.rs | 16 - 8 files changed, 763 insertions(+), 772 deletions(-) create mode 100644 library/compiler-builtins/src/float/traits.rs create mode 100644 library/compiler-builtins/src/int/traits.rs diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/src/float/mod.rs index 6ee55950e18e8..41b308626b392 100644 --- a/library/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/src/float/mod.rs @@ -1,7 +1,3 @@ -use core::ops; - -use crate::int::{DInt, Int, MinInt}; - pub mod add; pub mod cmp; pub mod conv; @@ -10,192 +6,11 @@ pub mod extend; pub mod mul; pub mod pow; pub mod sub; +pub(crate) mod traits; pub mod trunc; -/// Wrapper to extract the integer type half of the float's size -pub(crate) type HalfRep = <::Int as DInt>::H; - -public_test_dep! { -/// Trait for some basic operations on floats -#[allow(dead_code)] -pub(crate) 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(not(feature = "public-test-deps"))] +pub(crate) use traits::{Float, HalfRep}; -#[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); +#[cfg(feature = "public-test-deps")] +pub use traits::{Float, HalfRep}; diff --git a/library/compiler-builtins/src/float/traits.rs b/library/compiler-builtins/src/float/traits.rs new file mode 100644 index 0000000000000..8ccaa7bcbd78a --- /dev/null +++ b/library/compiler-builtins/src/float/traits.rs @@ -0,0 +1,189 @@ +use core::ops; + +use crate::int::{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/src/int/leading_zeros.rs b/library/compiler-builtins/src/int/leading_zeros.rs index 1fee9fcf5d8fd..ba735aa74620b 100644 --- a/library/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/src/int/leading_zeros.rs @@ -3,135 +3,138 @@ // adding a zero check at the beginning, but `__clzsi2` has a precondition that `x != 0`. // Compilers will insert the check for zero in cases where it is needed. -use crate::int::{CastInto, Int}; +#[cfg(feature = "public-test-deps")] +pub use implementation::{leading_zeros_default, leading_zeros_riscv}; +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use implementation::{leading_zeros_default, leading_zeros_riscv}; -public_test_dep! { -/// Returns the number of leading binary zeros in `x`. -#[allow(dead_code)] -pub(crate) fn leading_zeros_default>(x: T) -> usize { - // The basic idea is to test if the higher bits of `x` are zero and bisect the number - // of leading zeros. It is possible for all branches of the bisection to use the same - // code path by conditionally shifting the higher parts down to let the next bisection - // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` - // and adding to the number of zeros, it is slightly faster to start with - // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, - // because it simplifies the final bisection step. - let mut x = x; - // the number of potential leading zeros - let mut z = T::BITS as usize; - // a temporary - let mut t: T; +mod implementation { + use crate::int::{CastInto, Int}; - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - t = x >> 32; + /// Returns the number of leading binary zeros in `x`. + #[allow(dead_code)] + pub fn leading_zeros_default>(x: T) -> usize { + // The basic idea is to test if the higher bits of `x` are zero and bisect the number + // of leading zeros. It is possible for all branches of the bisection to use the same + // code path by conditionally shifting the higher parts down to let the next bisection + // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` + // and adding to the number of zeros, it is slightly faster to start with + // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, + // because it simplifies the final bisection step. + let mut x = x; + // the number of potential leading zeros + let mut z = T::BITS as usize; + // a temporary + let mut t: T; + + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + t = x >> 32; + if t != T::ZERO { + z -= 32; + x = t; + } + } + if T::BITS >= 32 { + t = x >> 16; + if t != T::ZERO { + z -= 16; + x = t; + } + } + const { assert!(T::BITS >= 16) }; + t = x >> 8; if t != T::ZERO { - z -= 32; + z -= 8; x = t; } - } - if T::BITS >= 32 { - t = x >> 16; + t = x >> 4; if t != T::ZERO { - z -= 16; + z -= 4; x = t; } - } - const { assert!(T::BITS >= 16) }; - t = x >> 8; - if t != T::ZERO { - z -= 8; - x = t; - } - t = x >> 4; - if t != T::ZERO { - z -= 4; - x = t; - } - t = x >> 2; - if t != T::ZERO { - z -= 2; - x = t; - } - // the last two bisections are combined into one conditional - t = x >> 1; - if t != T::ZERO { - z - 2 - } else { - z - x.cast() - } + t = x >> 2; + if t != T::ZERO { + z -= 2; + x = t; + } + // the last two bisections are combined into one conditional + t = x >> 1; + if t != T::ZERO { + z - 2 + } else { + z - x.cast() + } - // We could potentially save a few cycles by using the LUT trick from - // "https://embeddedgurus.com/state-space/2014/09/-%20%20%20%20//%20fast-deterministic-and-portable-counting-leading-zeros/". - // However, 256 bytes for a LUT is too large for embedded use cases. We could remove - // the last 3 bisections and use this 16 byte LUT for the rest of the work: - //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; - //z -= LUT[x] as usize; - //z - // However, it ends up generating about the same number of instructions. When benchmarked - // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO - // execution effects. Changing to using a LUT and branching is risky for smaller cores. -} -} + // We could potentially save a few cycles by using the LUT trick from + // "https://embeddedgurus.com/state-space/2014/09/+%20%20%20%20%20%20%20%20//%20fast-deterministic-and-portable-counting-leading-zeros/". + // However, 256 bytes for a LUT is too large for embedded use cases. We could remove + // the last 3 bisections and use this 16 byte LUT for the rest of the work: + //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; + //z -= LUT[x] as usize; + //z + // However, it ends up generating about the same number of instructions. When benchmarked + // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO + // execution effects. Changing to using a LUT and branching is risky for smaller cores. + } -// The above method does not compile well on RISC-V (because of the lack of predicated -// instructions), producing code with many branches or using an excessively long -// branchless solution. This method takes advantage of the set-if-less-than instruction on -// RISC-V that allows `(x >= power-of-two) as usize` to be branchless. + // The above method does not compile well on RISC-V (because of the lack of predicated + // instructions), producing code with many branches or using an excessively long + // branchless solution. This method takes advantage of the set-if-less-than instruction on + // RISC-V that allows `(x >= power-of-two) as usize` to be branchless. -public_test_dep! { -/// Returns the number of leading binary zeros in `x`. -#[allow(dead_code)] -pub(crate) fn leading_zeros_riscv>(x: T) -> usize { - let mut x = x; - // the number of potential leading zeros - let mut z = T::BITS; - // a temporary - let mut t: u32; + /// Returns the number of leading binary zeros in `x`. + #[allow(dead_code)] + pub fn leading_zeros_riscv>(x: T) -> usize { + let mut x = x; + // the number of potential leading zeros + let mut z = T::BITS; + // a temporary + let mut t: u32; - // RISC-V does not have a set-if-greater-than-or-equal instruction and - // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is - // still the most optimal method. A conditional set can only be turned into a single - // immediate instruction if `x` is compared with an immediate `imm` (that can fit into - // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the - // right). If we try to save an instruction by using `x < imm` for each bisection, we - // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, - // but the immediate will never fit into 12 bits and never save an instruction. - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise - // `t` is set to 0. - t = ((x >= (T::ONE << 32)) as u32) << 5; - // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the - // next step to process. + // RISC-V does not have a set-if-greater-than-or-equal instruction and + // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is + // still the most optimal method. A conditional set can only be turned into a single + // immediate instruction if `x` is compared with an immediate `imm` (that can fit into + // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the + // right). If we try to save an instruction by using `x < imm` for each bisection, we + // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, + // but the immediate will never fit into 12 bits and never save an instruction. + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise + // `t` is set to 0. + t = ((x >= (T::ONE << 32)) as u32) << 5; + // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the + // next step to process. + x >>= t; + // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential + // leading zeros + z -= t; + } + if T::BITS >= 32 { + t = ((x >= (T::ONE << 16)) as u32) << 4; + x >>= t; + z -= t; + } + const { assert!(T::BITS >= 16) }; + t = ((x >= (T::ONE << 8)) as u32) << 3; x >>= t; - // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential - // leading zeros z -= t; - } - if T::BITS >= 32 { - t = ((x >= (T::ONE << 16)) as u32) << 4; + t = ((x >= (T::ONE << 4)) as u32) << 2; + x >>= t; + z -= t; + t = ((x >= (T::ONE << 2)) as u32) << 1; x >>= t; z -= t; + t = (x >= (T::ONE << 1)) as u32; + x >>= t; + z -= t; + // All bits except the LSB are guaranteed to be zero for this final bisection step. + // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. + z as usize - x.cast() } - const { assert!(T::BITS >= 16) }; - t = ((x >= (T::ONE << 8)) as u32) << 3; - x >>= t; - z -= t; - t = ((x >= (T::ONE << 4)) as u32) << 2; - x >>= t; - z -= t; - t = ((x >= (T::ONE << 2)) as u32) << 1; - x >>= t; - z -= t; - t = (x >= (T::ONE << 1)) as u32; - x >>= t; - z -= t; - // All bits except the LSB are guaranteed to be zero for this final bisection step. - // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. - z as usize - x.cast() -} } intrinsics! { diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/src/int/mod.rs index c0d5a6715e3ae..1f1be711bbda2 100644 --- a/library/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/src/int/mod.rs @@ -1,5 +1,3 @@ -use core::ops; - mod specialized_div_rem; pub mod addsub; @@ -10,425 +8,13 @@ pub mod mul; pub mod sdiv; pub mod shift; pub mod trailing_zeros; +mod traits; pub mod udiv; pub use big::{i256, u256}; -public_test_dep! { -/// Minimal integer implementations needed on all integer types, including wide integers. -#[allow(dead_code)] -pub(crate) trait MinInt: Copy - + core::fmt::Debug - + ops::BitOr - + ops::Not - + ops::Shl -{ - - /// Type with the same width but other signedness - type OtherSign: MinInt; - /// Unsigned version of Self - type UnsignedInt: MinInt; - - /// If `Self` is a signed integer - const SIGNED: bool; - - /// The bitwidth of the int type - const BITS: u32; - - const ZERO: Self; - const ONE: Self; - const MIN: Self; - const MAX: Self; -} -} - -public_test_dep! { -/// Trait for some basic operations on integers -#[allow(dead_code)] -pub(crate) trait Int: MinInt - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::SubAssign - + ops::BitAndAssign - + ops::BitOrAssign - + ops::BitXorAssign - + ops::ShlAssign - + ops::ShrAssign - + ops::Add - + ops::Sub - + ops::Mul - + ops::Div - + ops::Shr - + ops::BitXor - + ops::BitAnd -{ - /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing - /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, - /// 112,119,120,125,126,127]. - const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); - - /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. - const FUZZ_NUM: usize = { - let log2 = (::BITS - 1).count_ones() as usize; - if log2 == 3 { - // case for u8 - 6 - } else { - // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate - // boundaries. - 8 + (4 * (log2 - 4)) - } - }; - - fn unsigned(self) -> Self::UnsignedInt; - fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; - fn unsigned_abs(self) -> Self::UnsignedInt; - - fn from_bool(b: bool) -> Self; - - /// Prevents the need for excessive conversions between signed and unsigned - fn logical_shr(self, other: u32) -> Self; - - /// Absolute difference between two integers. - fn abs_diff(self, other: Self) -> Self::UnsignedInt; - - // copied from primitive integers, but put in a trait - fn is_zero(self) -> bool; - fn wrapping_neg(self) -> Self; - fn wrapping_add(self, other: Self) -> Self; - fn wrapping_mul(self, other: Self) -> Self; - fn wrapping_sub(self, other: Self) -> Self; - fn wrapping_shl(self, other: u32) -> Self; - fn wrapping_shr(self, other: u32) -> Self; - fn rotate_left(self, other: u32) -> Self; - fn overflowing_add(self, other: Self) -> (Self, bool); - fn leading_zeros(self) -> u32; - fn ilog2(self) -> u32; -} -} - -pub(crate) const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { - let mut v = [0u8; 20]; - v[0] = 0; - v[1] = 1; - v[2] = 2; // important for parity and the iX::MIN case when reversed - let mut i = 3; - - // No need for any more until the byte boundary, because there should be no algorithms - // that are sensitive to anything not next to byte boundaries after 2. We also scale - // in powers of two, which is important to prevent u128 corner tests from getting too - // big. - let mut l = 8; - loop { - if l >= ((bits / 2) as u8) { - break; - } - // get both sides of the byte boundary - v[i] = l - 1; - i += 1; - v[i] = l; - i += 1; - l *= 2; - } - - if bits != 8 { - // add the lower side of the middle boundary - v[i] = ((bits / 2) - 1) as u8; - i += 1; - } - - // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS - // boundary because of algorithms that split the high part up. We reverse the scaling - // as we go to Self::BITS. - let mid = i; - let mut j = 1; - loop { - v[i] = (bits as u8) - (v[mid - j]) - 1; - if j == mid { - break; - } - i += 1; - j += 1; - } - v -} - -macro_rules! int_impl_common { - ($ty:ty) => { - fn from_bool(b: bool) -> Self { - b as $ty - } - - fn logical_shr(self, other: u32) -> Self { - Self::from_unsigned(self.unsigned().wrapping_shr(other)) - } - - fn is_zero(self) -> bool { - self == Self::ZERO - } - - fn wrapping_neg(self) -> Self { - ::wrapping_neg(self) - } - - fn wrapping_add(self, other: Self) -> Self { - ::wrapping_add(self, other) - } - - fn wrapping_mul(self, other: Self) -> Self { - ::wrapping_mul(self, other) - } - fn wrapping_sub(self, other: Self) -> Self { - ::wrapping_sub(self, other) - } - - fn wrapping_shl(self, other: u32) -> Self { - ::wrapping_shl(self, other) - } - - fn wrapping_shr(self, other: u32) -> Self { - ::wrapping_shr(self, other) - } - - fn rotate_left(self, other: u32) -> Self { - ::rotate_left(self, other) - } - - fn overflowing_add(self, other: Self) -> (Self, bool) { - ::overflowing_add(self, other) - } - - fn leading_zeros(self) -> u32 { - ::leading_zeros(self) - } - - fn ilog2(self) -> u32 { - ::ilog2(self) - } - }; -} - -macro_rules! int_impl { - ($ity:ty, $uty:ty) => { - impl MinInt for $uty { - type OtherSign = $ity; - type UnsignedInt = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $uty { - fn unsigned(self) -> $uty { - self - } - - // It makes writing macros easier if this is implemented for both signed and unsigned - #[allow(clippy::wrong_self_convention)] - fn from_unsigned(me: $uty) -> Self { - me - } - - fn unsigned_abs(self) -> Self { - self - } - - fn abs_diff(self, other: Self) -> Self { - self.abs_diff(other) - } - - int_impl_common!($uty); - } - - impl MinInt for $ity { - type OtherSign = $uty; - type UnsignedInt = $uty; - - const BITS: u32 = ::ZERO.count_zeros(); - const SIGNED: bool = Self::MIN != Self::ZERO; - - const ZERO: Self = 0; - const ONE: Self = 1; - const MIN: Self = ::MIN; - const MAX: Self = ::MAX; - } - - impl Int for $ity { - fn unsigned(self) -> $uty { - self as $uty - } - - fn from_unsigned(me: $uty) -> Self { - me as $ity - } - - fn unsigned_abs(self) -> Self::UnsignedInt { - self.unsigned_abs() - } - - fn abs_diff(self, other: Self) -> $uty { - self.abs_diff(other) - } - - int_impl_common!($ity); - } - }; -} - -int_impl!(isize, usize); -int_impl!(i8, u8); -int_impl!(i16, u16); -int_impl!(i32, u32); -int_impl!(i64, u64); -int_impl!(i128, u128); - -public_test_dep! { -/// 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(crate) 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() - } -} -} - -public_test_dep! { -/// 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(crate) 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 -); - -public_test_dep! { -/// Trait to express (possibly lossy) casting of integers -pub(crate) trait CastInto: Copy { - fn cast(self) -> T; -} - -pub(crate) trait CastFrom:Copy { - fn cast_from(value: T) -> Self; -} -} - -impl + Copy> CastFrom for T { - fn cast_from(value: U) -> Self { - value.cast() - } -} - -macro_rules! cast_into { - ($ty:ty) => { - cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); - }; - ($ty:ty; $($into:ty),*) => {$( - impl CastInto<$into> for $ty { - fn cast(self) -> $into { - self as $into - } - } - )*}; -} +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; -cast_into!(usize); -cast_into!(isize); -cast_into!(u8); -cast_into!(i8); -cast_into!(u16); -cast_into!(i16); -cast_into!(u32); -cast_into!(i32); -cast_into!(u64); -cast_into!(i64); -cast_into!(u128); -cast_into!(i128); +#[cfg(feature = "public-test-deps")] +pub use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; diff --git a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs index 330c6e4f80bb7..f5c6e50239a35 100644 --- a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs +++ b/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs @@ -185,7 +185,6 @@ macro_rules! impl_delegate { }; } -public_test_dep! { /// Returns `n / d` and sets `*rem = n % d`. /// /// This specialization exists because: @@ -195,7 +194,7 @@ public_test_dep! { /// delegate algorithm strategy the only reasonably fast way to perform `u128` division. // used on SPARC #[allow(dead_code)] -pub(crate) fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { +pub fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { use super::*; let duo_lo = duo as u64; let duo_hi = (duo >> 64) as u64; @@ -316,4 +315,3 @@ pub(crate) fn u128_divide_sparc(duo: u128, div: u128, rem: &mut u128) -> u128 { } } } -} diff --git a/library/compiler-builtins/src/int/trailing_zeros.rs b/library/compiler-builtins/src/int/trailing_zeros.rs index cea366b07549f..dbc0cce9facc9 100644 --- a/library/compiler-builtins/src/int/trailing_zeros.rs +++ b/library/compiler-builtins/src/int/trailing_zeros.rs @@ -1,44 +1,49 @@ -use crate::int::{CastInto, Int}; +#[cfg(feature = "public-test-deps")] +pub use implementation::trailing_zeros; +#[cfg(not(feature = "public-test-deps"))] +pub(crate) use implementation::trailing_zeros; -public_test_dep! { -/// Returns number of trailing binary zeros in `x`. -#[allow(dead_code)] -pub(crate) fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { - let mut x = x; - let mut r: u32 = 0; - let mut t: u32; +mod implementation { + use crate::int::{CastInto, Int}; - const { assert!(T::BITS <= 64) }; - if T::BITS >= 64 { - r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 - x >>= r; // remove 32 zero bits - } + /// Returns number of trailing binary zeros in `x`. + #[allow(dead_code)] + pub fn trailing_zeros + CastInto + CastInto>(x: T) -> usize { + let mut x = x; + let mut r: u32 = 0; + let mut t: u32; - if T::BITS >= 32 { - t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 - r += t; - x >>= t; // x = [0 - 0xFFFF] + higher garbage bits - } + const { assert!(T::BITS <= 64) }; + if T::BITS >= 64 { + r += ((CastInto::::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0 + x >>= r; // remove 32 zero bits + } - const { assert!(T::BITS >= 16) }; - t = ((CastInto::::cast(x) == 0) as u32) << 3; - x >>= t; // x = [0 - 0xFF] + higher garbage bits - r += t; + if T::BITS >= 32 { + t = ((CastInto::::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0 + r += t; + x >>= t; // x = [0 - 0xFFFF] + higher garbage bits + } - let mut x: u8 = x.cast(); + const { assert!(T::BITS >= 16) }; + t = ((CastInto::::cast(x) == 0) as u32) << 3; + x >>= t; // x = [0 - 0xFF] + higher garbage bits + r += t; - t = (((x & 0x0F) == 0) as u32) << 2; - x >>= t; // x = [0 - 0xF] + higher garbage bits - r += t; + let mut x: u8 = x.cast(); - t = (((x & 0x3) == 0) as u32) << 1; - x >>= t; // x = [0 - 0x3] + higher garbage bits - r += t; + t = (((x & 0x0F) == 0) as u32) << 2; + x >>= t; // x = [0 - 0xF] + higher garbage bits + r += t; - x &= 3; + t = (((x & 0x3) == 0) as u32) << 1; + x >>= t; // x = [0 - 0x3] + higher garbage bits + r += t; - r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) -} + x &= 3; + + r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg()) + } } intrinsics! { diff --git a/library/compiler-builtins/src/int/traits.rs b/library/compiler-builtins/src/int/traits.rs new file mode 100644 index 0000000000000..9b079e2aa59ae --- /dev/null +++ b/library/compiler-builtins/src/int/traits.rs @@ -0,0 +1,411 @@ +use core::ops; + +/// Minimal integer implementations needed on all integer types, including wide integers. +#[allow(dead_code)] +pub trait MinInt: + Copy + + core::fmt::Debug + + ops::BitOr + + ops::Not + + ops::Shl +{ + /// Type with the same width but other signedness + type OtherSign: MinInt; + /// Unsigned version of Self + type UnsignedInt: MinInt; + + /// If `Self` is a signed integer + const SIGNED: bool; + + /// The bitwidth of the int type + const BITS: u32; + + const ZERO: Self; + const ONE: Self; + const MIN: Self; + const MAX: Self; +} + +/// Trait for some basic operations on integers +#[allow(dead_code)] +pub trait Int: + MinInt + + PartialEq + + PartialOrd + + ops::AddAssign + + ops::SubAssign + + ops::BitAndAssign + + ops::BitOrAssign + + ops::BitXorAssign + + ops::ShlAssign + + ops::ShrAssign + + ops::Add + + ops::Sub + + ops::Mul + + ops::Div + + ops::Shr + + ops::BitXor + + ops::BitAnd +{ + /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing + /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, + /// 112,119,120,125,126,127]. + const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); + + /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. + const FUZZ_NUM: usize = { + let log2 = (::BITS - 1).count_ones() as usize; + if log2 == 3 { + // case for u8 + 6 + } else { + // 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate + // boundaries. + 8 + (4 * (log2 - 4)) + } + }; + + fn unsigned(self) -> Self::UnsignedInt; + fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; + fn unsigned_abs(self) -> Self::UnsignedInt; + + fn from_bool(b: bool) -> Self; + + /// Prevents the need for excessive conversions between signed and unsigned + fn logical_shr(self, other: u32) -> Self; + + /// Absolute difference between two integers. + fn abs_diff(self, other: Self) -> Self::UnsignedInt; + + // copied from primitive integers, but put in a trait + fn is_zero(self) -> bool; + fn wrapping_neg(self) -> Self; + fn wrapping_add(self, other: Self) -> Self; + fn wrapping_mul(self, other: Self) -> Self; + fn wrapping_sub(self, other: Self) -> Self; + fn wrapping_shl(self, other: u32) -> Self; + fn wrapping_shr(self, other: u32) -> Self; + fn rotate_left(self, other: u32) -> Self; + fn overflowing_add(self, other: Self) -> (Self, bool); + fn leading_zeros(self) -> u32; + fn ilog2(self) -> u32; +} + +pub(crate) const fn make_fuzz_lengths(bits: u32) -> [u8; 20] { + let mut v = [0u8; 20]; + v[0] = 0; + v[1] = 1; + v[2] = 2; // important for parity and the iX::MIN case when reversed + let mut i = 3; + + // No need for any more until the byte boundary, because there should be no algorithms + // that are sensitive to anything not next to byte boundaries after 2. We also scale + // in powers of two, which is important to prevent u128 corner tests from getting too + // big. + let mut l = 8; + loop { + if l >= ((bits / 2) as u8) { + break; + } + // get both sides of the byte boundary + v[i] = l - 1; + i += 1; + v[i] = l; + i += 1; + l *= 2; + } + + if bits != 8 { + // add the lower side of the middle boundary + v[i] = ((bits / 2) - 1) as u8; + i += 1; + } + + // We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS + // boundary because of algorithms that split the high part up. We reverse the scaling + // as we go to Self::BITS. + let mid = i; + let mut j = 1; + loop { + v[i] = (bits as u8) - (v[mid - j]) - 1; + if j == mid { + break; + } + i += 1; + j += 1; + } + v +} + +macro_rules! int_impl_common { + ($ty:ty) => { + fn from_bool(b: bool) -> Self { + b as $ty + } + + fn logical_shr(self, other: u32) -> Self { + Self::from_unsigned(self.unsigned().wrapping_shr(other)) + } + + fn is_zero(self) -> bool { + self == Self::ZERO + } + + fn wrapping_neg(self) -> Self { + ::wrapping_neg(self) + } + + fn wrapping_add(self, other: Self) -> Self { + ::wrapping_add(self, other) + } + + fn wrapping_mul(self, other: Self) -> Self { + ::wrapping_mul(self, other) + } + fn wrapping_sub(self, other: Self) -> Self { + ::wrapping_sub(self, other) + } + + fn wrapping_shl(self, other: u32) -> Self { + ::wrapping_shl(self, other) + } + + fn wrapping_shr(self, other: u32) -> Self { + ::wrapping_shr(self, other) + } + + fn rotate_left(self, other: u32) -> Self { + ::rotate_left(self, other) + } + + fn overflowing_add(self, other: Self) -> (Self, bool) { + ::overflowing_add(self, other) + } + + fn leading_zeros(self) -> u32 { + ::leading_zeros(self) + } + + fn ilog2(self) -> u32 { + ::ilog2(self) + } + }; +} + +macro_rules! int_impl { + ($ity:ty, $uty:ty) => { + impl MinInt for $uty { + type OtherSign = $ity; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $uty { + fn unsigned(self) -> $uty { + self + } + + // It makes writing macros easier if this is implemented for both signed and unsigned + #[allow(clippy::wrong_self_convention)] + fn from_unsigned(me: $uty) -> Self { + me + } + + fn unsigned_abs(self) -> Self { + self + } + + fn abs_diff(self, other: Self) -> Self { + self.abs_diff(other) + } + + int_impl_common!($uty); + } + + impl MinInt for $ity { + type OtherSign = $uty; + type UnsignedInt = $uty; + + const BITS: u32 = ::ZERO.count_zeros(); + const SIGNED: bool = Self::MIN != Self::ZERO; + + const ZERO: Self = 0; + const ONE: Self = 1; + const MIN: Self = ::MIN; + const MAX: Self = ::MAX; + } + + impl Int for $ity { + fn unsigned(self) -> $uty { + self as $uty + } + + fn from_unsigned(me: $uty) -> Self { + me as $ity + } + + fn unsigned_abs(self) -> Self::UnsignedInt { + self.unsigned_abs() + } + + fn abs_diff(self, other: Self) -> $uty { + self.abs_diff(other) + } + + int_impl_common!($ity); + } + }; +} + +int_impl!(isize, usize); +int_impl!(i8, u8); +int_impl!(i16, u16); +int_impl!(i32, u32); +int_impl!(i64, u64); +int_impl!(i128, u128); + +/// 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 +); + +/// Trait to express (possibly lossy) casting of integers +pub trait CastInto: Copy { + fn cast(self) -> T; +} + +pub trait CastFrom: Copy { + fn cast_from(value: T) -> Self; +} + +impl + Copy> CastFrom for T { + fn cast_from(value: U) -> Self { + value.cast() + } +} + +macro_rules! cast_into { + ($ty:ty) => { + cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128); + }; + ($ty:ty; $($into:ty),*) => {$( + impl CastInto<$into> for $ty { + fn cast(self) -> $into { + self as $into + } + } + )*}; +} + +cast_into!(usize); +cast_into!(isize); +cast_into!(u8); +cast_into!(i8); +cast_into!(u16); +cast_into!(i16); +cast_into!(u32); +cast_into!(i32); +cast_into!(u64); +cast_into!(i64); +cast_into!(u128); +cast_into!(i128); diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 88b54e82ca0f5..5d9f581975791 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -1,21 +1,5 @@ //! Macros shared throughout the compiler-builtins implementation -/// Changes the visibility to `pub` if feature "public-test-deps" is set -#[cfg(not(feature = "public-test-deps"))] -macro_rules! public_test_dep { - ($(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*) => { - $(#[$($meta)*])* pub(crate) $ident $($tokens)* - }; -} - -/// Changes the visibility to `pub` if feature "public-test-deps" is set -#[cfg(feature = "public-test-deps")] -macro_rules! public_test_dep { - {$(#[$($meta:meta)*])* pub(crate) $ident:ident $($tokens:tt)*} => { - $(#[$($meta)*])* pub $ident $($tokens)* - }; -} - /// The "main macro" used for defining intrinsics. /// /// The compiler-builtins library is super platform-specific with tons of crazy From 49224fb9ed187db240912fb683613b795c9c0a45 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Tue, 18 Feb 2025 09:47:07 +0100 Subject: [PATCH 1702/4206] Enable `f16` for MIPS It seems as if `f16` works on MIPS now according to my testing on Rust master with LLVM 20, and I was asked to create PRs with my changes. I only tested on the flavour of `mipsel-unknown-linux-gnu` hardware that happens to be available to me, so I can't say anything about other MIPS hardware, but from a casual skimming of the LLVM code ([1], [2]) it seems like `f16` should work on all MIPS hardware. So enable it for all MIPS hardware. [1]: https://github.com/rust-lang/llvm-project/blob/rustc/20.1-2025-02-13/llvm/lib/Target/Mips/MipsISelLowering.h#L370 [2]: https://github.com/rust-lang/llvm-project/blob/rustc/20.1-2025-02-13/llvm/lib/CodeGen/TargetLoweringBase.cpp#L1367-L1388 --- library/compiler-builtins/configure.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs index fa3e302ea87cd..ff52e88da0c09 100644 --- a/library/compiler-builtins/configure.rs +++ b/library/compiler-builtins/configure.rs @@ -78,7 +78,6 @@ pub fn configure_f16_f128(target: &Target) { "csky" => false, "hexagon" => false, "loongarch64" => false, - "mips" | "mips64" | "mips32r6" | "mips64r6" => false, "powerpc" | "powerpc64" => false, "sparc" | "sparc64" => false, "wasm32" | "wasm64" => false, From 9021b2820c8d4b1db425dd1b59a74911ceabce4b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 24 Feb 2025 04:06:07 +0000 Subject: [PATCH 1703/4206] Resolve monomorphization errors in `compiler-builtins` `compiler-builtins` is not allowed to call anything from `core`; however, there are a couple of cases where we do so in `libm` for debug output. Gate relevant locations behind the `compiler-builtins` Cargo feature. --- library/compiler-builtins/libm/Cargo.toml | 7 +++++++ .../compiler-builtins-smoke-test/Cargo.toml | 1 + .../compiler-builtins-smoke-test/src/lib.rs | 2 ++ .../libm/src/math/support/hex_float.rs | 16 ++++++++++++++-- .../libm/src/math/support/int_traits.rs | 1 + 5 files changed, 25 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index f24f4423c7b4a..eb133dada16d5 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -61,6 +61,13 @@ exclude = [ [dev-dependencies] no-panic = "0.1.33" + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = [ + # compiler-builtins sets this feature, but we use it in `libm` + 'cfg(feature, values("compiler-builtins"))', +] } + # The default release profile is unchanged. # Release mode with debug assertions diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index 24b33645e97c5..6ef905ea759b6 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -22,6 +22,7 @@ unexpected_cfgs = { level = "warn", check-cfg = [ "cfg(arch_enabled)", "cfg(assert_no_panic)", "cfg(intrinsics_enabled)", + 'cfg(feature, values("compiler-builtins"))', 'cfg(feature, values("force-soft-floats"))', 'cfg(feature, values("unstable"))', 'cfg(feature, values("unstable-intrinsics"))', diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index f9e6e75a870a3..e70f6d9e04c9c 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -4,7 +4,9 @@ //! Additionally, it provides a `#[no_mangle]` C API that can be easier to inspect than the //! default `.rlib`. +#![compiler_builtins] #![feature(core_intrinsics)] +#![feature(compiler_builtins)] #![feature(f16)] #![feature(f128)] #![allow(internal_features)] 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 99ad8bec3770b..2155d5c58bcec 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -246,7 +246,13 @@ fn fmt_any_hex(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result { impl fmt::LowerHex for Hexf { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_any_hex(&self.0, f) + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + unreachable!() + } else { + fmt_any_hex(&self.0, f) + } + } } } @@ -264,7 +270,13 @@ impl fmt::LowerHex for Hexf<(F, i32)> { impl fmt::LowerHex for Hexf { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::LowerHex::fmt(&self.0, f) + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + unreachable!() + } else { + fmt::LowerHex::fmt(&self.0, f) + } + } } } 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 d34797764a0ef..f19c8683521ab 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -418,6 +418,7 @@ macro_rules! cast_into_float { ($ty:ty; $($into:ty),*) => {$( impl CastInto<$into> for $ty { fn cast(self) -> $into { + #[cfg(not(feature = "compiler-builtins"))] debug_assert_eq!(self as $into as $ty, self, "inexact float cast"); self as $into } From 3f6b08ac1ea7605c66a9c4c3f5c621267ace2883 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 24 Feb 2025 04:55:38 +0000 Subject: [PATCH 1704/4206] Ignore unused variables when `compiler-builtins` is set --- .../libm/crates/compiler-builtins-smoke-test/Cargo.toml | 6 +++--- .../compiler-builtins/libm/src/math/support/hex_float.rs | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml index 6ef905ea759b6..38a5116690a7c 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml @@ -11,18 +11,18 @@ test = false bench = false [features] -default = ["arch", "unstable-float"] +default = ["arch", "compiler-builtins", "unstable-float"] # Copied from `libm`'s root `Cargo.toml`' -unstable-float = [] arch = [] +compiler-builtins = [] +unstable-float = [] [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = [ "cfg(arch_enabled)", "cfg(assert_no_panic)", "cfg(intrinsics_enabled)", - 'cfg(feature, values("compiler-builtins"))', 'cfg(feature, values("force-soft-floats"))', 'cfg(feature, values("unstable"))', 'cfg(feature, values("unstable-intrinsics"))', 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 2155d5c58bcec..0ecf616954f96 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -248,7 +248,8 @@ impl fmt::LowerHex for Hexf { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { cfg_if! { if #[cfg(feature = "compiler-builtins")] { - unreachable!() + let _ = f; + unimplemented!() } else { fmt_any_hex(&self.0, f) } @@ -272,7 +273,8 @@ impl fmt::LowerHex for Hexf { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { cfg_if! { if #[cfg(feature = "compiler-builtins")] { - unreachable!() + let _ = f; + unimplemented!() } else { fmt::LowerHex::fmt(&self.0, f) } From 2615971f55e24570805180b820e85457b74ba1be Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 24 Feb 2025 05:45:41 +0000 Subject: [PATCH 1705/4206] Configure out remaining formatting when `compiler-builtins` is set These are still causing errors in the compiler-builtins CI. --- .../libm/src/math/support/hex_float.rs | 42 +++++++++++++++++-- 1 file changed, 38 insertions(+), 4 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 0ecf616954f96..be7d7607f91a2 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -211,6 +211,7 @@ const fn u128_ilog2(v: u128) -> u32 { pub struct Hexf(pub F); // Adapted from https://github.com/ericseppanen/hexfloat2/blob/a5c27932f0ff/src/format.rs +#[cfg(not(feature = "compiler-builtins"))] fn fmt_any_hex(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result { if x.is_sign_negative() { write!(f, "-")?; @@ -244,6 +245,11 @@ fn fmt_any_hex(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "0x{leading}{sig:0mwidth$x}p{exponent:+}") } +#[cfg(feature = "compiler-builtins")] +fn fmt_any_hex(_x: &F, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + unimplemented!() +} + impl fmt::LowerHex for Hexf { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { cfg_if! { @@ -259,13 +265,27 @@ impl fmt::LowerHex for Hexf { impl fmt::LowerHex for Hexf<(F, F)> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) + } + } } } impl fmt::LowerHex for Hexf<(F, i32)> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) + } + } } } @@ -287,7 +307,14 @@ where Hexf: fmt::LowerHex, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::LowerHex::fmt(self, f) + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + fmt::LowerHex::fmt(self, f) + } + } } } @@ -296,7 +323,14 @@ where Hexf: fmt::LowerHex, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::LowerHex::fmt(self, f) + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + fmt::LowerHex::fmt(self, f) + } + } } } From 17748827383d17e26cb222b4402976d1441378da Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 24 Feb 2025 06:52:48 +0000 Subject: [PATCH 1706/4206] Gate another assertion behind `compiler-builtins` This is causing link errors on Windows. --- library/compiler-builtins/libm/src/math/support/int_traits.rs | 1 + 1 file changed, 1 insertion(+) 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 f19c8683521ab..491adb1f22c35 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -394,6 +394,7 @@ macro_rules! cast_into { fn cast(self) -> $into { // All we can really do to enforce casting rules is check the rules when in // debug mode. + #[cfg(not(feature = "compiler-builtins"))] debug_assert!(<$into>::try_from(self).is_ok(), "failed cast from {self}"); self as $into } From 7055198acf005b30f7516997dbf1f5f6fe6867a3 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 23 Feb 2025 23:43:26 +0000 Subject: [PATCH 1707/4206] Update the `libm` submodule This requires privately reexporting `libm`'s `support` module at crate root, where it is expected for macros. Once `libm` is made always available, the reexport can be simplified. This delta adds a lot of routines to `f16` and `f128`: * ceil * floor * fma (f128 only) * fmax * fmin * fmod * ldexp * rint * round * scalbn * sqrt Additionally, the following new API was added for all four float types: * fmaximum * fmaximum_num * fminimum * fminimum_num * roundeven There are also some significant performance improvements for `sqrt` and `sqrtf`, as well as precision improvements for `cbrt` (both `f32` and `f64` versions of this function are now always correctly rounded). --- library/compiler-builtins/libm | 2 +- library/compiler-builtins/src/lib.rs | 15 +++++++++++++++ library/compiler-builtins/src/math.rs | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/libm index 8e82616f154b0..69219c491ee9f 160000 --- a/library/compiler-builtins/libm +++ b/library/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 8e82616f154b06cf4ee9cdb82a4f56474a403d04 +Subproject commit 69219c491ee9f05761d2068fd6d4c7c0de6faa3a diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index ffcd3586ce7eb..533878137dcd8 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -1,4 +1,5 @@ #![cfg_attr(feature = "compiler-builtins", compiler_builtins)] +#![cfg_attr(all(target_family = "wasm"), feature(wasm_numeric_instr))] #![feature(abi_unadjusted)] #![feature(asm_experimental_arch)] #![feature(cfg_target_has_atomic)] @@ -58,6 +59,20 @@ pub mod int; all(target_family = "wasm", not(target_os = "unknown")) )))] pub mod math; + +// `libm` expects its `support` module to be available in the crate root. This config can be +// cleaned up once `libm` is made always available. +#[cfg(not(any( + all( + target_arch = "x86", + not(target_feature = "sse2"), + not(target_os = "uefi"), + ), + unix, + all(target_family = "wasm", not(target_os = "unknown")) +)))] +use math::libm::support; + pub mod mem; #[cfg(target_arch = "arm")] diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index 21670f2434f20..fef5358e32340 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -3,7 +3,7 @@ #[allow(unused_imports)] #[allow(clippy::all)] #[path = "../libm/src/math/mod.rs"] -mod libm; +pub(crate) mod libm; #[allow(unused_macros)] macro_rules! no_mangle { From 95a5ad5225b3abe02b99d84612c49bc8716033f3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Feb 2025 07:34:00 +0000 Subject: [PATCH 1708/4206] chore: release v0.1.148 --- library/compiler-builtins/CHANGELOG.md | 8 ++++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index a3890c6ce732d..c1e1e73daf9b1 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.148](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.147...compiler_builtins-v0.1.148) - 2025-02-24 + +### Other + +- Update the `libm` submodule +- Enable `f16` for MIPS +- Eliminate the use of `public_test_dep!` for a third time + ## [0.1.147](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.146...compiler_builtins-v0.1.147) - 2025-02-19 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index ff1a10fc6267e..684a2a0b65546 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.147" +version = "0.1.148" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 55bbda8ff8c53984e1b15b69c3d0f7ed529e8b16 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 13 Feb 2025 03:27:00 +0000 Subject: [PATCH 1709/4206] Make a subset of `libm` symbols weakly available on all platforms 018616e78b ("Always have math functions but with `weak` linking attribute if we can") made all math symbols available on platforms that support weak linkage. This caused some unexpected regressions, however, because our less accurate and sometimes slow routines were being selected over the system `libm`, which also tends to be weak [1]. Thus, 0fab77e8d7 ("Don't include `math` for `unix` and `wasi` targets") was applied to undo these changes on many platforms. Now that some improvements have been made to `libm`, add back a subset of these functions: * cbrt * ceil * copysign * fabs * fdim * floor * fma * fmax * fmaximum * fmin * fminimum * fmod * rint * round * roundeven * sqrt * trunc This list includes only functions that produce exact results (verified with exhaustive / extensive tests, and also required by IEEE in most cases), and for which benchmarks indicate performance similar to or better than Musl's soft float math routines [^1]. All except `cbrt` also have `f16` and `f128` implementations. Once more routines meet these criteria, we can move them from platform-specific availability to always available. Once this change makes it to rust-lang/rust, we will also be able to move the relevant functions from `std` to `core`. [^1]: We still rely on the backend to provide optimized assmebly routines when available. [1]: https://github.com/rust-lang/rust/issues/128386 --- library/compiler-builtins/src/lib.rs | 29 +-- library/compiler-builtins/src/math.rs | 259 +++++++++++++++++--------- 2 files changed, 173 insertions(+), 115 deletions(-) diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/src/lib.rs index 533878137dcd8..6f5bd85981e87 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/src/lib.rs @@ -41,40 +41,13 @@ mod macros; pub mod float; pub mod int; - -// Disable for any of the following: -// - x86 without sse2 due to ABI issues -// - -// - but exclude UEFI since it is a soft-float target -// - -// - All unix targets (linux, macos, freebsd, android, etc) -// - wasm with known target_os -#[cfg(not(any( - all( - target_arch = "x86", - not(target_feature = "sse2"), - not(target_os = "uefi"), - ), - unix, - all(target_family = "wasm", not(target_os = "unknown")) -)))] pub mod math; +pub mod mem; // `libm` expects its `support` module to be available in the crate root. This config can be // cleaned up once `libm` is made always available. -#[cfg(not(any( - all( - target_arch = "x86", - not(target_feature = "sse2"), - not(target_os = "uefi"), - ), - unix, - all(target_family = "wasm", not(target_os = "unknown")) -)))] use math::libm::support; -pub mod mem; - #[cfg(target_arch = "arm")] pub mod arm; diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/src/math.rs index fef5358e32340..ccd9c54216c66 100644 --- a/library/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/src/math.rs @@ -5,110 +5,195 @@ #[path = "../libm/src/math/mod.rs"] pub(crate) mod libm; -#[allow(unused_macros)] -macro_rules! no_mangle { +macro_rules! libm_intrinsics { ($(fn $fun:ident($($iid:ident : $ity:ty),+) -> $oty:ty;)+) => { intrinsics! { $( pub extern "C" fn $fun($($iid: $ity),+) -> $oty { - self::libm::$fun($($iid),+) + $crate::math::libm::$fun($($iid),+) } )+ } } } -#[cfg(not(windows))] -no_mangle! { - fn acos(x: f64) -> f64; - fn asin(x: f64) -> f64; - fn cbrt(x: f64) -> f64; - fn expm1(x: f64) -> f64; - fn hypot(x: f64, y: f64) -> f64; - fn tan(x: f64) -> f64; - fn cos(x: f64) -> f64; - fn expf(x: f32) -> f32; - fn log2(x: f64) -> f64; - fn log2f(x: f32) -> f32; - fn log10(x: f64) -> f64; - fn log10f(x: f32) -> f32; - fn log(x: f64) -> f64; - fn logf(x: f32) -> f32; - fn round(x: f64) -> f64; - fn roundf(x: f32) -> f32; - fn rint(x: f64) -> f64; - fn rintf(x: f32) -> f32; - fn sin(x: f64) -> f64; - fn pow(x: f64, y: f64) -> f64; - fn powf(x: f32, y: f32) -> f32; - fn acosf(n: f32) -> f32; - fn atan2f(a: f32, b: f32) -> f32; - fn atanf(n: f32) -> f32; - fn coshf(n: f32) -> f32; - fn expm1f(n: f32) -> f32; - fn fdim(a: f64, b: f64) -> f64; - fn fdimf(a: f32, b: f32) -> f32; - fn log1pf(n: f32) -> f32; - fn sinhf(n: f32) -> f32; - fn tanhf(n: f32) -> f32; - fn ldexp(f: f64, n: i32) -> f64; - fn ldexpf(f: f32, n: i32) -> f32; - fn tgamma(x: f64) -> f64; - fn tgammaf(x: f32) -> f32; - fn atan(x: f64) -> f64; - fn atan2(x: f64, y: f64) -> f64; - fn cosh(x: f64) -> f64; - fn log1p(x: f64) -> f64; - fn sinh(x: f64) -> f64; - fn tanh(x: f64) -> f64; - fn cosf(x: f32) -> f32; - fn exp(x: f64) -> f64; - fn sinf(x: f32) -> f32; - fn exp2(x: f64) -> f64; - fn exp2f(x: f32) -> f32; - fn fma(x: f64, y: f64, z: f64) -> f64; - fn fmaf(x: f32, y: f32, z: f32) -> f32; - fn asinf(n: f32) -> f32; - fn cbrtf(n: f32) -> f32; - fn hypotf(x: f32, y: f32) -> f32; - fn tanf(n: f32) -> f32; +/// This set of functions is well tested in `libm` and known to provide similar performance to +/// system `libm`, as well as the same or better accuracy. +pub mod full_availability { + #[cfg(f16_enabled)] + libm_intrinsics! { + fn ceilf16(x: f16) -> f16; + fn copysignf16(x: f16, y: f16) -> f16; + fn fabsf16(x: f16) -> f16; + fn fdimf16(x: f16, y: f16) -> f16; + fn floorf16(x: f16) -> f16; + fn fmaxf16(x: f16, y: f16) -> f16; + fn fmaximumf16(x: f16, y: f16) -> f16; + fn fminf16(x: f16, y: f16) -> f16; + fn fminimumf16(x: f16, y: f16) -> f16; + fn fmodf16(x: f16, y: f16) -> f16; + fn rintf16(x: f16) -> f16; + fn roundevenf16(x: f16) -> f16; + fn roundf16(x: f16) -> f16; + fn sqrtf16(x: f16) -> f16; + fn truncf16(x: f16) -> f16; + } + + /* Weak linkage is unreliable on Windows and Apple, so we don't expose symbols that we know + * the system libc provides in order to avoid conflicts. */ - fn sqrtf(x: f32) -> f32; - fn sqrt(x: f64) -> f64; + #[cfg(all(not(windows), not(target_vendor = "apple")))] + libm_intrinsics! { + /* f32 */ + fn cbrtf(n: f32) -> f32; + fn ceilf(x: f32) -> f32; + fn copysignf(x: f32, y: f32) -> f32; + fn fabsf(x: f32) -> f32; + fn fdimf(a: f32, b: f32) -> f32; + fn floorf(x: f32) -> f32; + fn fmaf(x: f32, y: f32, z: f32) -> f32; + fn fmaxf(x: f32, y: f32) -> f32; + fn fminf(x: f32, y: f32) -> f32; + fn fmodf(x: f32, y: f32) -> f32; + fn rintf(x: f32) -> f32; + fn roundf(x: f32) -> f32; + fn sqrtf(x: f32) -> f32; + fn truncf(x: f32) -> f32; - fn ceil(x: f64) -> f64; - fn ceilf(x: f32) -> f32; - fn floor(x: f64) -> f64; - fn floorf(x: f32) -> f32; - fn trunc(x: f64) -> f64; - fn truncf(x: f32) -> f32; + /* f64 */ + fn cbrt(x: f64) -> f64; + fn ceil(x: f64) -> f64; + fn copysign(x: f64, y: f64) -> f64; + fn fabs(x: f64) -> f64; + fn fdim(a: f64, b: f64) -> f64; + fn floor(x: f64) -> f64; + fn fma(x: f64, y: f64, z: f64) -> f64; + fn fmax(x: f64, y: f64) -> f64; + fn fmin(x: f64, y: f64) -> f64; + fn fmod(x: f64, y: f64) -> f64; + fn rint(x: f64) -> f64; + fn round(x: f64) -> f64; + fn sqrt(x: f64) -> f64; + fn trunc(x: f64) -> f64; + } - fn fmin(x: f64, y: f64) -> f64; - fn fminf(x: f32, y: f32) -> f32; - fn fmax(x: f64, y: f64) -> f64; - fn fmaxf(x: f32, y: f32) -> f32; - // `f64 % f64` - fn fmod(x: f64, y: f64) -> f64; - // `f32 % f32` - fn fmodf(x: f32, y: f32) -> f32; + // Windows and MacOS do not yet expose roundeven and IEEE 754-2019 `maximum` / `minimum`, + // however, so we still provide a fallback. + libm_intrinsics! { + fn fmaximum(x: f64, y: f64) -> f64; + fn fmaximumf(x: f32, y: f32) -> f32; + fn fminimum(x: f64, y: f64) -> f64; + fn fminimumf(x: f32, y: f32) -> f32; + fn roundeven(x: f64) -> f64; + fn roundevenf(x: f32) -> f32; + } - fn erf(x: f64) -> f64; - fn erff(x: f32) -> f32; - fn erfc(x: f64) -> f64; - fn erfcf(x: f32) -> f32; + #[cfg(f128_enabled)] + libm_intrinsics! { + fn ceilf128(x: f128) -> f128; + fn copysignf128(x: f128, y: f128) -> f128; + fn fabsf128(x: f128) -> f128; + fn fdimf128(x: f128, y: f128) -> f128; + fn floorf128(x: f128) -> f128; + fn fmaf128(x: f128, y: f128, z: f128) -> f128; + fn fmaxf128(x: f128, y: f128) -> f128; + fn fmaximumf128(x: f128, y: f128) -> f128; + fn fminf128(x: f128, y: f128) -> f128; + fn fminimumf128(x: f128, y: f128) -> f128; + fn fmodf128(x: f128, y: f128) -> f128; + fn rintf128(x: f128) -> f128; + fn roundevenf128(x: f128) -> f128; + fn roundf128(x: f128) -> f128; + fn sqrtf128(x: f128) -> f128; + fn truncf128(x: f128) -> f128; + } } -// allow for windows (and other targets) -intrinsics! { - pub extern "C" fn lgamma_r(x: f64, s: &mut i32) -> f64 { - let r = self::libm::lgamma_r(x); - *s = r.1; - r.0 +/// This group of functions has more performance or precision issues than system versions, or +/// are otherwise less well tested. Provide them only on platforms that have problems with the +/// system `libm`. +/// +/// As `libm` improves, more functions will be moved from this group to the first group. +/// +/// Do not supply for any of the following: +/// - x86 without sse2 due to ABI issues +/// - +/// - but exclude UEFI since it is a soft-float target +/// - +/// - All unix targets (linux, macos, freebsd, android, etc) +/// - wasm with known target_os +#[cfg(not(any( + all( + target_arch = "x86", + not(target_feature = "sse2"), + not(target_os = "uefi"), + ), + unix, + all(target_family = "wasm", not(target_os = "unknown")) +)))] +pub mod partial_availability { + #[cfg(not(windows))] + libm_intrinsics! { + fn acos(x: f64) -> f64; + fn acosf(n: f32) -> f32; + fn asin(x: f64) -> f64; + fn asinf(n: f32) -> f32; + fn atan(x: f64) -> f64; + fn atan2(x: f64, y: f64) -> f64; + fn atan2f(a: f32, b: f32) -> f32; + fn atanf(n: f32) -> f32; + fn cos(x: f64) -> f64; + fn cosf(x: f32) -> f32; + fn cosh(x: f64) -> f64; + fn coshf(n: f32) -> f32; + fn erf(x: f64) -> f64; + fn erfc(x: f64) -> f64; + fn erfcf(x: f32) -> f32; + fn erff(x: f32) -> f32; + fn exp(x: f64) -> f64; + fn exp2(x: f64) -> f64; + fn exp2f(x: f32) -> f32; + fn expf(x: f32) -> f32; + fn expm1(x: f64) -> f64; + fn expm1f(n: f32) -> f32; + fn hypot(x: f64, y: f64) -> f64; + fn hypotf(x: f32, y: f32) -> f32; + fn ldexp(f: f64, n: i32) -> f64; + fn ldexpf(f: f32, n: i32) -> f32; + fn log(x: f64) -> f64; + fn log10(x: f64) -> f64; + fn log10f(x: f32) -> f32; + fn log1p(x: f64) -> f64; + fn log1pf(n: f32) -> f32; + fn log2(x: f64) -> f64; + fn log2f(x: f32) -> f32; + fn logf(x: f32) -> f32; + fn pow(x: f64, y: f64) -> f64; + fn powf(x: f32, y: f32) -> f32; + fn sin(x: f64) -> f64; + fn sinf(x: f32) -> f32; + fn sinh(x: f64) -> f64; + fn sinhf(n: f32) -> f32; + fn tan(x: f64) -> f64; + fn tanf(n: f32) -> f32; + fn tanh(x: f64) -> f64; + fn tanhf(n: f32) -> f32; + fn tgamma(x: f64) -> f64; + fn tgammaf(x: f32) -> f32; } - pub extern "C" fn lgammaf_r(x: f32, s: &mut i32) -> f32 { - let r = self::libm::lgammaf_r(x); - *s = r.1; - r.0 + // allow for windows (and other targets) + intrinsics! { + pub extern "C" fn lgamma_r(x: f64, s: &mut i32) -> f64 { + let r = super::libm::lgamma_r(x); + *s = r.1; + r.0 + } + + pub extern "C" fn lgammaf_r(x: f32, s: &mut i32) -> f32 { + let r = super::libm::lgammaf_r(x); + *s = r.1; + r.0 + } } } From 45c4a1d1b58c247070ec61d8fea19b49518f5e83 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 25 Feb 2025 18:55:26 +0000 Subject: [PATCH 1710/4206] chore: release v0.1.149 --- library/compiler-builtins/CHANGELOG.md | 6 ++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index c1e1e73daf9b1..9b8aaaa080964 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.149](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.148...compiler_builtins-v0.1.149) - 2025-02-25 + +### Other + +- Make a subset of `libm` symbols weakly available on all platforms + ## [0.1.148](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.147...compiler_builtins-v0.1.148) - 2025-02-24 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 684a2a0b65546..d1575d6df8f5a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.148" +version = "0.1.149" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 60ea5815b26aff290dce9f8a17973c59dc276dc8 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 26 Feb 2025 07:40:35 +0000 Subject: [PATCH 1711/4206] Update LLVM downloads to 20.1-2025-02-13 This matches the version used by rust-lang/rust. --- library/compiler-builtins/.github/workflows/main.yml | 2 +- library/compiler-builtins/README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 7336efc4224e7..fd1f6d5327d49 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -4,7 +4,7 @@ on: [push, pull_request] env: RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings - RUST_LLVM_VERSION: 19.1-2024-09-17 + RUST_LLVM_VERSION: 20.1-2025-02-13 RUST_COMPILER_RT_ROOT: ./compiler-rt jobs: diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index a2b38cce0efa8..d91d88a8559d0 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -89,8 +89,8 @@ to test against, located in a directory called `compiler-rt`. This can be obtained with the following: ```sh -curl -L -o rustc-llvm-19.1.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/19.1-2024-09-17.tar.gz -tar xzf rustc-llvm-19.1.tar.gz --strip-components 1 llvm-project-rustc-19.1-2024-09-17/compiler-rt +curl -L -o rustc-llvm-20.1.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/20.1-2025-02-13.tar.gz +tar xzf rustc-llvm-20.1.tar.gz --strip-components 1 llvm-project-rustc-20.1-2025-02-13/compiler-rt ``` Local targets may also be tested with `./ci/run.sh [target]`. From afea1c05553570f6766abf91766982d108e71f12 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 1 Mar 2025 19:32:06 +0000 Subject: [PATCH 1712/4206] Disable `f16` on AArch64 without the `neon` feature There is an LLVM regression that breaks some `f16`-related code when `fp-armv8` is disabled [1]. Since Rust ties that feature to `neon`, disable `f16` if `neon` is not available. [1]: https://github.com/llvm/llvm-project/issues/129394 --- library/compiler-builtins/configure.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs index ff52e88da0c09..2bb0f83832c59 100644 --- a/library/compiler-builtins/configure.rs +++ b/library/compiler-builtins/configure.rs @@ -71,6 +71,8 @@ pub fn configure_f16_f128(target: &Target) { let f16_enabled = match target.arch.as_str() { // Unsupported "arm64ec" => false, + // Crash in LLVM20 + "aarch64" if !target.features.iter().any(|f| f == "neon") => false, // Selection failure "s390x" => false, // Infinite recursion From 4b664fd2ef43c5b53d2e7c80fc77f9848a937fcd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 1 Mar 2025 19:40:30 +0000 Subject: [PATCH 1713/4206] chore: release v0.1.150 --- library/compiler-builtins/CHANGELOG.md | 7 +++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index 9b8aaaa080964..087a912d7059b 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.150](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.149...compiler_builtins-v0.1.150) - 2025-03-01 + +### Other + +- Disable `f16` on AArch64 without the `neon` feature +- Update LLVM downloads to 20.1-2025-02-13 + ## [0.1.149](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.148...compiler_builtins-v0.1.149) - 2025-02-25 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index d1575d6df8f5a..3bf9b8ddda8e1 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.149" +version = "0.1.150" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 41f1ad27320e44bfe4e359188f0a627143065494 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 1 Mar 2025 23:20:04 -0500 Subject: [PATCH 1714/4206] Remove outdated information from the readme --- library/compiler-builtins/README.md | 48 +++-------------------------- 1 file changed, 5 insertions(+), 43 deletions(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index d91d88a8559d0..d76bd289ba53a 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -1,50 +1,12 @@ # `compiler-builtins` -> Porting `compiler-rt` intrinsics to Rust +This crate provides external symbols that the compiler expects to be available when +building Rust projects, typically software routines for basic operations that do not +have hardware support. It is largely a port of LLVM's [`compiler-rt`]. -See [rust-lang/rust#35437][0]. +It is distributed as part of Rust's sysroot. -[0]: https://github.com/rust-lang/rust/issues/35437 - -## When and how to use this crate? - -If you are working with a target that doesn't have binary releases of std -available via rustup (this probably means you are building the core crate -yourself) and need compiler-rt intrinsics (i.e. you are probably getting linker -errors when building an executable: `undefined reference to __aeabi_memcpy`), -you can use this crate to get those intrinsics and solve the linker errors. To -do that, add this crate somewhere in the dependency graph of the crate you are -building: - -```toml -# Cargo.toml -[dependencies] -compiler_builtins = { git = "https://github.com/rust-lang/compiler-builtins" } -``` - -```rust -extern crate compiler_builtins; - -// ... -``` - -If you still get an "undefined reference to $INTRINSIC" error after that change, -that means that we haven't ported `$INTRINSIC` to Rust yet! Please open [an -issue] with the name of the intrinsic and the LLVM triple (e.g. -thumbv7m-none-eabi) of the target you are using. That way we can prioritize -porting that particular intrinsic. - -If you've got a C compiler available for your target then while we implement -this intrinsic you can temporarily enable a fallback to the actual compiler-rt -implementation as well for unimplemented intrinsics: - -```toml -[dependencies.compiler_builtins] -git = "https://github.com/rust-lang/compiler-builtins" -features = ["c"] -``` - -[an issue]: https://github.com/rust-lang/compiler-builtins/issues +[`compiler-rt`]: https://github.com/llvm/llvm-project/tree/1b1dc505057322f4fa1110ef4f53c44347f52986/compiler-rt ## Contributing From 2de09ac46a493569c6ef8cd2505c238f5469b781 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 4 Mar 2025 16:21:15 -0500 Subject: [PATCH 1715/4206] Add __extendhfdf2 and add __truncdfhf2 test LLVM doesn't seem to emit this intrinsic but it probably should, in some cases it lowers f16->f64 conversions as f16->f32->f64 with two libcalls. GCC provides this intrinsic so it is good to have anyway. Additionally, add a test for f64->f16 which was missing. [1]: https://rust.godbolt.org/z/xezM9PEnz --- library/compiler-builtins/src/float/extend.rs | 8 +++++++ .../compiler-builtins/testcrate/Cargo.toml | 3 ++- .../testcrate/benches/float_extend.rs | 23 +++++++++++++++++++ .../testcrate/benches/float_trunc.rs | 2 +- library/compiler-builtins/testcrate/build.rs | 11 +++++++++ .../compiler-builtins/testcrate/tests/conv.rs | 2 ++ 6 files changed, 47 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index a1a9b9720a888..f05e3a924c1da 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -96,6 +96,14 @@ intrinsics! { extend(a) } + #[avr_skip] + #[aapcs_on_arm] + #[apple_f16_arg_abi] + #[cfg(f16_enabled)] + pub extern "C" fn __extendhfdf2(a: f16) -> f64 { + extend(a) + } + #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __extendhfkf2] diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 21cec17010933..91e2f668fc7ee 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -43,8 +43,9 @@ 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 = ["no-sys-f16-f64-convert"] # Enable report generation without bringing in more dependencies by default benchmarking-reports = ["criterion/plotters", "criterion/html_reports"] diff --git a/library/compiler-builtins/testcrate/benches/float_extend.rs b/library/compiler-builtins/testcrate/benches/float_extend.rs index a0cdaf48acab2..12f195984587b 100644 --- a/library/compiler-builtins/testcrate/benches/float_extend.rs +++ b/library/compiler-builtins/testcrate/benches/float_extend.rs @@ -28,6 +28,28 @@ float_bench! { ], } +#[cfg(f16_enabled)] +float_bench! { + name: extend_f16_f64, + sig: (a: f16) -> f64, + crate_fn: extend::__extendhfdf2, + sys_fn: __extendhfdf2, + sys_available: not(feature = "no-sys-f16-f64-convert"), + asm: [ + #[cfg(target_arch = "aarch64")] { + let ret: f64; + asm!( + "fcvt {ret:d}, {a:h}", + a = in(vreg) a, + ret = lateout(vreg) ret, + options(nomem, nostack, pure), + ); + + ret + }; + ], +} + #[cfg(all(f16_enabled, f128_enabled))] float_bench! { name: extend_f16_f128, @@ -93,6 +115,7 @@ pub fn float_extend() { #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] { extend_f16_f32(&mut criterion); + extend_f16_f64(&mut criterion); #[cfg(f128_enabled)] extend_f16_f128(&mut criterion); diff --git a/library/compiler-builtins/testcrate/benches/float_trunc.rs b/library/compiler-builtins/testcrate/benches/float_trunc.rs index de9b5bf8c0bd1..cb6aee13a7944 100644 --- a/library/compiler-builtins/testcrate/benches/float_trunc.rs +++ b/library/compiler-builtins/testcrate/benches/float_trunc.rs @@ -33,7 +33,7 @@ float_bench! { sig: (a: f64) -> f16, crate_fn: trunc::__truncdfhf2, sys_fn: __truncdfhf2, - sys_available: not(feature = "no-sys-f16"), + sys_available: not(feature = "no-sys-f16-f64-convert"), asm: [ #[cfg(target_arch = "aarch64")] { let ret: f16; diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 6205c7ac6fecb..3e5f780ac666b 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -6,6 +6,7 @@ enum Feature { NoSysF128, NoSysF128IntConvert, NoSysF16, + NoSysF16F64Convert, NoSysF16F128Convert, } @@ -66,9 +67,15 @@ fn main() { || target.arch == "wasm64" { features.insert(Feature::NoSysF16); + features.insert(Feature::NoSysF16F64Convert); features.insert(Feature::NoSysF16F128Convert); } + // These platforms are missing either `__extendhfdf2` or `__truncdfhf2`. + if target.vendor == "apple" || target.os == "windows" { + features.insert(Feature::NoSysF16F64Convert); + } + for feature in features { let (name, warning) = match feature { Feature::NoSysF128 => ("no-sys-f128", "using apfloat fallback for f128"), @@ -76,6 +83,10 @@ fn main() { "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", diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index a08748af78159..7f33d27cce0f6 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -311,6 +311,7 @@ mod extend { 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"); @@ -340,6 +341,7 @@ mod trunc { 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"); From 340d3d4bd7b804e976c5196da26c2af60e6267c1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 4 Mar 2025 17:46:50 -0500 Subject: [PATCH 1716/4206] Simplify test crate build features Since we have a handful of different float-related configuration in testcrate, track a list of which are implied by others rather than repeating the config. --- .../testcrate/benches/float_conv.rs | 2 +- library/compiler-builtins/testcrate/build.rs | 31 ++++++++++++++----- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/library/compiler-builtins/testcrate/benches/float_conv.rs b/library/compiler-builtins/testcrate/benches/float_conv.rs index 0625a1ae5dd4e..7d8549b43262d 100644 --- a/library/compiler-builtins/testcrate/benches/float_conv.rs +++ b/library/compiler-builtins/testcrate/benches/float_conv.rs @@ -665,7 +665,7 @@ pub fn float_conv() { conv_f64_i64(&mut criterion); conv_f64_i128(&mut criterion); - #[cfg(all(f128_enabled))] + #[cfg(f128_enabled)] // FIXME: ppc64le has a sporadic overflow panic in the crate functions // #[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))] diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 3e5f780ac666b..427fa799b8c95 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -1,7 +1,11 @@ use std::collections::HashSet; +mod builtins_configure { + include!("../configure.rs"); +} + /// Features to enable -#[derive(Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] enum Feature { NoSysF128, NoSysF128IntConvert, @@ -10,8 +14,16 @@ enum Feature { NoSysF16F128Convert, } -mod builtins_configure { - include!("../configure.rs"); +impl Feature { + fn implies(self) -> &'static [Self] { + match self { + Self::NoSysF128 => [Self::NoSysF128IntConvert, Self::NoSysF16F128Convert].as_slice(), + Self::NoSysF128IntConvert => [].as_slice(), + Self::NoSysF16 => [Self::NoSysF16F64Convert, Self::NoSysF16F128Convert].as_slice(), + Self::NoSysF16F64Convert => [].as_slice(), + Self::NoSysF16F128Convert => [].as_slice(), + } + } } fn main() { @@ -40,8 +52,6 @@ fn main() { || target.arch == "powerpc64" { features.insert(Feature::NoSysF128); - features.insert(Feature::NoSysF128IntConvert); - features.insert(Feature::NoSysF16F128Convert); } if target.arch == "x86" { @@ -67,8 +77,6 @@ fn main() { || target.arch == "wasm64" { features.insert(Feature::NoSysF16); - features.insert(Feature::NoSysF16F64Convert); - features.insert(Feature::NoSysF16F128Convert); } // These platforms are missing either `__extendhfdf2` or `__truncdfhf2`. @@ -76,6 +84,15 @@ fn main() { features.insert(Feature::NoSysF16F64Convert); } + // Add implied features. Collection is required for borrows. + features.extend( + features + .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"), From 968a7d0b7cdc071e866711a28466ae94e7c2b166 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 4 Mar 2025 17:36:27 -0500 Subject: [PATCH 1717/4206] Add a test config for __gnu_h2f_ieee and __gnu_f2h_ieee Some targets do not provide these symbols since they always use __extendhfsf and __truncsfhf. Add a configuration option for this. --- library/compiler-builtins/testcrate/Cargo.toml | 3 ++- library/compiler-builtins/testcrate/build.rs | 18 +++++++++++++++++- .../compiler-builtins/testcrate/tests/conv.rs | 4 ++-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 91e2f668fc7ee..e06864846fd9c 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -44,8 +44,9 @@ no-sys-f128 = ["no-sys-f128-int-convert", "no-sys-f16-f128-convert"] no-sys-f128-int-convert = [] no-sys-f16-f128-convert = [] no-sys-f16-f64-convert = [] +no-sys-f16-gnu-convert = [] # Skip tests that rely on f16 symbols being available on the system -no-sys-f16 = ["no-sys-f16-f64-convert"] +no-sys-f16 = ["no-sys-f16-f64-convert", "no-sys-f16-gnu-convert"] # Enable report generation without bringing in more dependencies by default benchmarking-reports = ["criterion/plotters", "criterion/html_reports"] diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 427fa799b8c95..171c1d52114cb 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -12,6 +12,7 @@ enum Feature { NoSysF16, NoSysF16F64Convert, NoSysF16F128Convert, + NoSysF16GnuConvert, } impl Feature { @@ -19,9 +20,15 @@ impl Feature { match self { Self::NoSysF128 => [Self::NoSysF128IntConvert, Self::NoSysF16F128Convert].as_slice(), Self::NoSysF128IntConvert => [].as_slice(), - Self::NoSysF16 => [Self::NoSysF16F64Convert, Self::NoSysF16F128Convert].as_slice(), + Self::NoSysF16 => [ + Self::NoSysF16F64Convert, + Self::NoSysF16F128Convert, + Feature::NoSysF16GnuConvert, + ] + .as_slice(), Self::NoSysF16F64Convert => [].as_slice(), Self::NoSysF16F128Convert => [].as_slice(), + Self::NoSysF16GnuConvert => [].as_slice(), } } } @@ -84,6 +91,11 @@ fn main() { features.insert(Feature::NoSysF16F64Convert); } + // These platforms do not have `__gnu_f2h_ieee` or `__gnu_h2f_ieee`. + if false { + features.insert(Feature::NoSysF16GnuConvert); + } + // Add implied features. Collection is required for borrows. features.extend( features @@ -108,6 +120,10 @@ fn main() { "no-sys-f16-f128-convert", "using apfloat fallback for f16 <-> f128 conversions", ), + Feature::NoSysF16GnuConvert => ( + "no-sys-f16-gnu-convert", + "using apfloat fallback for __gnu f16", + ), Feature::NoSysF16 => ("no-sys-f16", "using apfloat fallback for f16"), }; println!("cargo:warning={warning}"); diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index 7f33d27cce0f6..f94aaf174028d 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -310,7 +310,7 @@ 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 => f32, Half => Single, __gnu_h2f_ieee, not(feature = "no-sys-f16-gnu-convert"); 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"); @@ -340,7 +340,7 @@ 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"); + f32 => f16, Single => Half, __gnu_f2h_ieee, not(feature = "no-sys-f16-gnu-convert"); 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"); From e4c1eb803dccfb1d3398d0a4ac7464e9d1d87f78 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 4 Mar 2025 22:06:35 -0500 Subject: [PATCH 1718/4206] Revert "ci: Pin the nightly toolchain for aarch64-unknown-linux-gnu" The fix to this issue was synced in [1] so we should no longer need to keep aarch64 pinned. This reverts commit b2bcfc838e2a4b72fa62b333e3eb91f250aa4539. [1]: https://github.com/rust-lang/rust/pull/137661 --- library/compiler-builtins/.github/workflows/main.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index fd1f6d5327d49..1c367a2d0da5b 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -20,8 +20,7 @@ jobs: rust: nightly - target: aarch64-unknown-linux-gnu os: ubuntu-latest - # FIXME: pinned due to https://github.com/llvm/llvm-project/issues/127804 - rust: nightly-2025-02-07 + rust: nightly - target: aarch64-pc-windows-msvc os: windows-latest rust: nightly From 890cd1e0f99aabf36e09e1e31a21f9f7515c0073 Mon Sep 17 00:00:00 2001 From: hev Date: Wed, 5 Mar 2025 14:11:51 +0800 Subject: [PATCH 1719/4206] Enable `f16` for LoongArch (#770) [ the configured-out tests should be re-enabled once we have the symbols in nightly - Trevor ] --- library/compiler-builtins/configure.rs | 2 -- library/compiler-builtins/testcrate/build.rs | 1 + library/compiler-builtins/testcrate/tests/conv.rs | 12 ++++++++++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs index 2bb0f83832c59..931e966293920 100644 --- a/library/compiler-builtins/configure.rs +++ b/library/compiler-builtins/configure.rs @@ -76,10 +76,8 @@ pub fn configure_f16_f128(target: &Target) { // Selection failure "s390x" => false, // Infinite recursion - // FIXME(llvm20): loongarch fixed by "csky" => false, "hexagon" => false, - "loongarch64" => false, "powerpc" | "powerpc64" => false, "sparc" | "sparc64" => false, "wasm32" | "wasm64" => false, diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 171c1d52114cb..868d8700df392 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -75,6 +75,7 @@ fn main() { || target.arch == "powerpc" || target.arch == "powerpc64" || target.arch == "powerpc64le" + || target.arch == "loongarch64" || (target.arch == "x86" && !target.has_feature("sse")) || target.os == "windows" // Linking says "error: function signature mismatch: __extendhfsf2" and seems to diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index f94aaf174028d..d706635408b18 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -306,7 +306,11 @@ mod extend { } #[cfg(all(f16_enabled, f128_enabled))] - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(not(any( + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "loongarch64" + )))] f_to_f! { extend, f16 => f32, Half => Single, __extendhfsf2, not(feature = "no-sys-f16"); @@ -336,7 +340,11 @@ mod trunc { } #[cfg(all(f16_enabled, f128_enabled))] - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] + #[cfg(not(any( + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "loongarch64" + )))] f_to_f! { trunc, f32 => f16, Single => Half, __truncsfhf2, not(feature = "no-sys-f16"); From f5f09d2f4bbc4fc041554ea101a90cc5b23b3c62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Fri, 28 Feb 2025 23:17:56 +0800 Subject: [PATCH 1720/4206] Add cygwin support Co-authored-by: Ookiineko --- library/compiler-builtins/build.rs | 14 ++++++++------ .../compiler-builtins/examples/intrinsics.rs | 6 +++--- library/compiler-builtins/src/macros.rs | 18 +++++++++--------- library/compiler-builtins/src/probestack.rs | 4 ++-- library/compiler-builtins/src/x86_64.rs | 6 +++++- 5 files changed, 27 insertions(+), 21 deletions(-) diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 39cee311f85a4..3c04423f2d83c 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -575,7 +575,7 @@ mod c { ("__fe_raise_inexact", "fp_mode.c"), ]); - if target.os != "windows" { + if target.os != "windows" && target.os != "cygwin" { sources.extend(&[("__multc3", "multc3.c")]); } } @@ -608,13 +608,15 @@ mod c { sources.remove(&["__aeabi_cdcmp", "__aeabi_cfcmp"]); } - // Android uses emulated TLS so we need a runtime support function. - if target.os == "android" { + // Android and Cygwin uses emulated TLS so we need a runtime support function. + if target.os == "android" || 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. + // 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))"); } diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/examples/intrinsics.rs index 59a70e20745c8..e90cfb33dea56 100644 --- a/library/compiler-builtins/examples/intrinsics.rs +++ b/library/compiler-builtins/examples/intrinsics.rs @@ -673,17 +673,17 @@ pub fn __aeabi_unwind_cpp_pr0() {} #[no_mangle] pub fn __aeabi_unwind_cpp_pr1() {} -#[cfg(not(windows))] +#[cfg(not(any(windows, target_os = "cygwin")))] #[allow(non_snake_case)] #[no_mangle] pub fn _Unwind_Resume() {} -#[cfg(not(windows))] +#[cfg(not(any(windows, target_os = "cygwin")))] #[lang = "eh_personality"] #[no_mangle] pub extern "C" fn eh_personality() {} -#[cfg(all(windows, target_env = "gnu"))] +#[cfg(any(all(windows, target_env = "gnu"), target_os = "cygwin"))] mod mingw_unwinding { #[no_mangle] pub fn rust_eh_personality() {} diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/src/macros.rs index 5d9f581975791..b1b71379cc917 100644 --- a/library/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/src/macros.rs @@ -193,7 +193,7 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( - #[cfg(all(any(windows, all(target_os = "uefi", target_arch = "x86_64")), target_pointer_width = "64"))] + #[cfg(all(any(windows, target_os = "cygwin", all(target_os = "uefi", target_arch = "x86_64")), target_pointer_width = "64"))] intrinsics! { $(#[$($attr)*])* pub extern "unadjusted" fn $name( $($argname: $ty),* ) $(-> $ret)? { @@ -201,7 +201,7 @@ macro_rules! intrinsics { } } - #[cfg(not(all(any(windows, all(target_os = "uefi", target_arch = "x86_64")), target_pointer_width = "64")))] + #[cfg(not(all(any(windows, target_os = "cygwin", all(target_os = "uefi", target_arch = "x86_64")), target_pointer_width = "64")))] intrinsics! { $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { @@ -257,7 +257,7 @@ macro_rules! intrinsics { #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"), not(feature = "mangled-names")))] mod $name { #[no_mangle] - #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] + #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] $(#[$($attr)*])* extern $abi fn $name( $($argname: u16),* ) $(-> $ret)? { super::$name($(f16::from_bits($argname)),*) @@ -293,7 +293,7 @@ macro_rules! intrinsics { #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"), not(feature = "mangled-names")))] mod $name { #[no_mangle] - #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] + #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] $(#[$($attr)*])* extern $abi fn $name( $($argname: $ty),* ) -> u16 { super::$name($($argname),*).to_bits() @@ -334,7 +334,7 @@ macro_rules! intrinsics { #[cfg(all(target_arch = "arm", not(feature = "mangled-names")))] mod $name { #[no_mangle] - #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] + #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] $(#[$($attr)*])* extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) @@ -344,7 +344,7 @@ macro_rules! intrinsics { #[cfg(all(target_arch = "arm", not(feature = "mangled-names")))] mod $alias { #[no_mangle] - #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] + #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] $(#[$($attr)*])* extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) @@ -411,7 +411,7 @@ macro_rules! intrinsics { mod $name { $(#[$($attr)*])* #[no_mangle] - #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] + #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } @@ -436,7 +436,7 @@ macro_rules! intrinsics { #[naked] $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] - #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] + #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* } @@ -503,7 +503,7 @@ macro_rules! intrinsics { mod $name { $(#[$($attr)*])* #[no_mangle] - #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")] + #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] $(unsafe $($empty)?)? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) } diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/src/probestack.rs index 0c30384db385a..5b6abd21a1db3 100644 --- a/library/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/src/probestack.rs @@ -42,8 +42,8 @@ //! be more than welcome to accept such a change! #![cfg(not(feature = "mangled-names"))] -// Windows already has builtins to do this. -#![cfg(not(windows))] +// Windows and Cygwin already has builtins to do this. +#![cfg(not(any(windows, target_os = "cygwin")))] // All these builtins require assembly #![cfg(not(feature = "no-asm"))] // We only define stack probing for these architectures today. diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/src/x86_64.rs index 9c91a45561ee2..aae601f58bf07 100644 --- a/library/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/src/x86_64.rs @@ -10,7 +10,11 @@ use core::intrinsics; intrinsics! { #[naked] #[cfg(all( - any(all(windows, target_env = "gnu"), target_os = "uefi"), + any( + all(windows, target_env = "gnu"), + target_os = "cygwin", + target_os = "uefi" + ), not(feature = "no-asm") ))] pub unsafe extern "C" fn ___chkstk_ms() { From 795fa2f40a859514c20abb3be926ed430cf04907 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 5 Mar 2025 06:18:13 +0000 Subject: [PATCH 1721/4206] chore: release v0.1.151 --- library/compiler-builtins/CHANGELOG.md | 9 +++++++++ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md index 087a912d7059b..763b0e10ed003 100644 --- a/library/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/CHANGELOG.md @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.151](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.150...compiler_builtins-v0.1.151) - 2025-03-05 + +### Other + +- Add cygwin support +- Enable `f16` for LoongArch ([#770](https://github.com/rust-lang/compiler-builtins/pull/770)) +- Add __extendhfdf2 and add __truncdfhf2 test +- Remove outdated information from the readme + ## [0.1.150](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.149...compiler_builtins-v0.1.150) - 2025-03-01 ### Other diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 3bf9b8ddda8e1..baef22aa75a54 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.150" +version = "0.1.151" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 4735ded783f3e6cf1b31a19c7f7f21baee61d41f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 5 Mar 2025 01:36:52 -0500 Subject: [PATCH 1722/4206] Revert "Add a test config for __gnu_h2f_ieee and __gnu_f2h_ieee" This turned out to not be useful, so remove it. This reverts commit b7b93103fb9293c0c502dc1ae34e2ad5c871bc39. --- library/compiler-builtins/testcrate/Cargo.toml | 3 +-- library/compiler-builtins/testcrate/build.rs | 18 +----------------- .../compiler-builtins/testcrate/tests/conv.rs | 4 ++-- 3 files changed, 4 insertions(+), 21 deletions(-) diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index e06864846fd9c..91e2f668fc7ee 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -44,9 +44,8 @@ no-sys-f128 = ["no-sys-f128-int-convert", "no-sys-f16-f128-convert"] no-sys-f128-int-convert = [] no-sys-f16-f128-convert = [] no-sys-f16-f64-convert = [] -no-sys-f16-gnu-convert = [] # Skip tests that rely on f16 symbols being available on the system -no-sys-f16 = ["no-sys-f16-f64-convert", "no-sys-f16-gnu-convert"] +no-sys-f16 = ["no-sys-f16-f64-convert"] # Enable report generation without bringing in more dependencies by default benchmarking-reports = ["criterion/plotters", "criterion/html_reports"] diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 868d8700df392..15e4e771ca0f8 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -12,7 +12,6 @@ enum Feature { NoSysF16, NoSysF16F64Convert, NoSysF16F128Convert, - NoSysF16GnuConvert, } impl Feature { @@ -20,15 +19,9 @@ impl Feature { match self { Self::NoSysF128 => [Self::NoSysF128IntConvert, Self::NoSysF16F128Convert].as_slice(), Self::NoSysF128IntConvert => [].as_slice(), - Self::NoSysF16 => [ - Self::NoSysF16F64Convert, - Self::NoSysF16F128Convert, - Feature::NoSysF16GnuConvert, - ] - .as_slice(), + Self::NoSysF16 => [Self::NoSysF16F64Convert, Self::NoSysF16F128Convert].as_slice(), Self::NoSysF16F64Convert => [].as_slice(), Self::NoSysF16F128Convert => [].as_slice(), - Self::NoSysF16GnuConvert => [].as_slice(), } } } @@ -92,11 +85,6 @@ fn main() { features.insert(Feature::NoSysF16F64Convert); } - // These platforms do not have `__gnu_f2h_ieee` or `__gnu_h2f_ieee`. - if false { - features.insert(Feature::NoSysF16GnuConvert); - } - // Add implied features. Collection is required for borrows. features.extend( features @@ -121,10 +109,6 @@ fn main() { "no-sys-f16-f128-convert", "using apfloat fallback for f16 <-> f128 conversions", ), - Feature::NoSysF16GnuConvert => ( - "no-sys-f16-gnu-convert", - "using apfloat fallback for __gnu f16", - ), Feature::NoSysF16 => ("no-sys-f16", "using apfloat fallback for f16"), }; println!("cargo:warning={warning}"); diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index d706635408b18..db1493cae9a1e 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -314,7 +314,7 @@ 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-gnu-convert"); + 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"); @@ -348,7 +348,7 @@ 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-gnu-convert"); + 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"); From 2d8c36296392290f168a024d7a18954be5979e07 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 6 Mar 2025 08:50:35 +0000 Subject: [PATCH 1723/4206] Migrate `testcrate` and `panic-handler` to edition 2024 Includes `extern` -> `unsafe extern` blocks and formatting updates. --- library/compiler-builtins/crates/panic-handler/Cargo.toml | 2 +- library/compiler-builtins/testcrate/Cargo.toml | 2 +- library/compiler-builtins/testcrate/benches/float_add.rs | 2 +- library/compiler-builtins/testcrate/benches/float_cmp.rs | 2 +- library/compiler-builtins/testcrate/benches/float_conv.rs | 2 +- library/compiler-builtins/testcrate/benches/float_div.rs | 2 +- .../compiler-builtins/testcrate/benches/float_extend.rs | 2 +- library/compiler-builtins/testcrate/benches/float_mul.rs | 2 +- library/compiler-builtins/testcrate/benches/float_pow.rs | 2 +- library/compiler-builtins/testcrate/benches/float_sub.rs | 2 +- library/compiler-builtins/testcrate/benches/float_trunc.rs | 2 +- library/compiler-builtins/testcrate/benches/mem.rs | 2 +- library/compiler-builtins/testcrate/src/bench.rs | 7 ++++++- library/compiler-builtins/testcrate/src/lib.rs | 2 +- library/compiler-builtins/testcrate/tests/big.rs | 2 +- 15 files changed, 20 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/crates/panic-handler/Cargo.toml b/library/compiler-builtins/crates/panic-handler/Cargo.toml index 2ad85840900d8..96b83eaa2265a 100644 --- a/library/compiler-builtins/crates/panic-handler/Cargo.toml +++ b/library/compiler-builtins/crates/panic-handler/Cargo.toml @@ -2,7 +2,7 @@ name = "panic-handler" version = "0.1.0" authors = ["Alex Crichton "] -edition = "2021" +edition = "2024" publish = false [dependencies] diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 91e2f668fc7ee..71c461c578c23 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -2,7 +2,7 @@ name = "testcrate" version = "0.1.0" authors = ["Alex Crichton "] -edition = "2021" +edition = "2024" publish = false [lib] diff --git a/library/compiler-builtins/testcrate/benches/float_add.rs b/library/compiler-builtins/testcrate/benches/float_add.rs index 3311e7b5b299d..a578655f8f433 100644 --- a/library/compiler-builtins/testcrate/benches/float_add.rs +++ b/library/compiler-builtins/testcrate/benches/float_add.rs @@ -1,7 +1,7 @@ #![cfg_attr(f128_enabled, feature(f128))] use compiler_builtins::float::add; -use criterion::{criterion_main, Criterion}; +use criterion::{Criterion, criterion_main}; use testcrate::float_bench; float_bench! { diff --git a/library/compiler-builtins/testcrate/benches/float_cmp.rs b/library/compiler-builtins/testcrate/benches/float_cmp.rs index 400c09b427a53..4c269e4889c76 100644 --- a/library/compiler-builtins/testcrate/benches/float_cmp.rs +++ b/library/compiler-builtins/testcrate/benches/float_cmp.rs @@ -1,6 +1,6 @@ #![cfg_attr(f128_enabled, feature(f128))] -use criterion::{criterion_main, Criterion}; +use criterion::{Criterion, criterion_main}; use testcrate::float_bench; use compiler_builtins::float::cmp; diff --git a/library/compiler-builtins/testcrate/benches/float_conv.rs b/library/compiler-builtins/testcrate/benches/float_conv.rs index 7d8549b43262d..e3f2af86344fc 100644 --- a/library/compiler-builtins/testcrate/benches/float_conv.rs +++ b/library/compiler-builtins/testcrate/benches/float_conv.rs @@ -2,7 +2,7 @@ #![cfg_attr(f128_enabled, feature(f128))] use compiler_builtins::float::conv; -use criterion::{criterion_main, Criterion}; +use criterion::{Criterion, criterion_main}; use testcrate::float_bench; /* unsigned int -> float */ diff --git a/library/compiler-builtins/testcrate/benches/float_div.rs b/library/compiler-builtins/testcrate/benches/float_div.rs index 6a039a82a93c0..c42f3f386716e 100644 --- a/library/compiler-builtins/testcrate/benches/float_div.rs +++ b/library/compiler-builtins/testcrate/benches/float_div.rs @@ -1,7 +1,7 @@ #![cfg_attr(f128_enabled, feature(f128))] use compiler_builtins::float::div; -use criterion::{criterion_main, Criterion}; +use criterion::{Criterion, criterion_main}; use testcrate::float_bench; float_bench! { diff --git a/library/compiler-builtins/testcrate/benches/float_extend.rs b/library/compiler-builtins/testcrate/benches/float_extend.rs index 12f195984587b..1e7fedefe70ef 100644 --- a/library/compiler-builtins/testcrate/benches/float_extend.rs +++ b/library/compiler-builtins/testcrate/benches/float_extend.rs @@ -3,7 +3,7 @@ #![cfg_attr(f16_enabled, feature(f16))] use compiler_builtins::float::extend; -use criterion::{criterion_main, Criterion}; +use criterion::{Criterion, criterion_main}; use testcrate::float_bench; #[cfg(f16_enabled)] diff --git a/library/compiler-builtins/testcrate/benches/float_mul.rs b/library/compiler-builtins/testcrate/benches/float_mul.rs index 6e30b7866c715..0857a68a22e07 100644 --- a/library/compiler-builtins/testcrate/benches/float_mul.rs +++ b/library/compiler-builtins/testcrate/benches/float_mul.rs @@ -1,7 +1,7 @@ #![cfg_attr(f128_enabled, feature(f128))] use compiler_builtins::float::mul; -use criterion::{criterion_main, Criterion}; +use criterion::{Criterion, criterion_main}; use testcrate::float_bench; float_bench! { diff --git a/library/compiler-builtins/testcrate/benches/float_pow.rs b/library/compiler-builtins/testcrate/benches/float_pow.rs index 46da3f25ceb74..e84fee51ca97a 100644 --- a/library/compiler-builtins/testcrate/benches/float_pow.rs +++ b/library/compiler-builtins/testcrate/benches/float_pow.rs @@ -1,7 +1,7 @@ #![cfg_attr(f128_enabled, feature(f128))] use compiler_builtins::float::pow; -use criterion::{criterion_main, Criterion}; +use criterion::{Criterion, criterion_main}; use testcrate::float_bench; float_bench! { diff --git a/library/compiler-builtins/testcrate/benches/float_sub.rs b/library/compiler-builtins/testcrate/benches/float_sub.rs index cdb678eef052f..7a6c05ea5c1c4 100644 --- a/library/compiler-builtins/testcrate/benches/float_sub.rs +++ b/library/compiler-builtins/testcrate/benches/float_sub.rs @@ -1,7 +1,7 @@ #![cfg_attr(f128_enabled, feature(f128))] use compiler_builtins::float::sub; -use criterion::{criterion_main, Criterion}; +use criterion::{Criterion, criterion_main}; use testcrate::float_bench; float_bench! { diff --git a/library/compiler-builtins/testcrate/benches/float_trunc.rs b/library/compiler-builtins/testcrate/benches/float_trunc.rs index cb6aee13a7944..4ceb62ab06a4e 100644 --- a/library/compiler-builtins/testcrate/benches/float_trunc.rs +++ b/library/compiler-builtins/testcrate/benches/float_trunc.rs @@ -2,7 +2,7 @@ #![cfg_attr(f16_enabled, feature(f16))] use compiler_builtins::float::trunc; -use criterion::{criterion_main, Criterion}; +use criterion::{Criterion, criterion_main}; use testcrate::float_bench; #[cfg(f16_enabled)] diff --git a/library/compiler-builtins/testcrate/benches/mem.rs b/library/compiler-builtins/testcrate/benches/mem.rs index 98a040958c4d6..3f83926b6c5a2 100644 --- a/library/compiler-builtins/testcrate/benches/mem.rs +++ b/library/compiler-builtins/testcrate/benches/mem.rs @@ -1,7 +1,7 @@ #![feature(test)] extern crate test; -use test::{black_box, Bencher}; +use test::{Bencher, black_box}; extern crate compiler_builtins; use compiler_builtins::mem::{memcmp, memcpy, memmove, memset}; diff --git a/library/compiler-builtins/testcrate/src/bench.rs b/library/compiler-builtins/testcrate/src/bench.rs index f5da1f3ae50ed..45a3a1ad4671f 100644 --- a/library/compiler-builtins/testcrate/src/bench.rs +++ b/library/compiler-builtins/testcrate/src/bench.rs @@ -89,6 +89,10 @@ pub fn skip_asm_checks(_test_name: &str) -> bool { /// Create a comparison of the system symbol, compiler_builtins, and optionally handwritten /// assembly. +/// +/// # Safety +/// +/// The signature must be correct and any assembly must be sound. #[macro_export] macro_rules! float_bench { ( @@ -120,8 +124,9 @@ macro_rules! float_bench { ] $(,)? ) => {paste::paste! { + // SAFETY: macro invocation must use the correct signature #[cfg($sys_available)] - extern "C" { + unsafe extern "C" { /// Binding for the system function #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] fn $sys_fn($($arg: $arg_ty),*) -> $ret_ty; diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/testcrate/src/lib.rs index 894c2782a45fd..c61618755e930 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/testcrate/src/lib.rs @@ -22,8 +22,8 @@ extern crate alloc; use compiler_builtins::float::Float; use compiler_builtins::int::{Int, MinInt}; -use rand_xoshiro::rand_core::{RngCore, SeedableRng}; use rand_xoshiro::Xoshiro128StarStar; +use rand_xoshiro::rand_core::{RngCore, SeedableRng}; /// Sets the number of fuzz iterations run for most tests. In practice, the vast majority of bugs /// are caught by the edge case testers. Most of the remaining bugs triggered by more complex diff --git a/library/compiler-builtins/testcrate/tests/big.rs b/library/compiler-builtins/testcrate/tests/big.rs index 595f622560796..d1ae88bd16485 100644 --- a/library/compiler-builtins/testcrate/tests/big.rs +++ b/library/compiler-builtins/testcrate/tests/big.rs @@ -1,4 +1,4 @@ -use compiler_builtins::int::{i256, u256, HInt, MinInt}; +use compiler_builtins::int::{HInt, MinInt, i256, u256}; const LOHI_SPLIT: u128 = 0xaaaaaaaaaaaaaaaaffffffffffffffff; From 1112886edcfc515e4c3492dc60fa7234e5227caf Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 6 Mar 2025 08:57:10 +0000 Subject: [PATCH 1724/4206] Use the v2 resolver in the workspace --- library/compiler-builtins/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index baef22aa75a54..9d1448342065c 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -76,6 +76,7 @@ name = "intrinsics" required-features = ["compiler-builtins"] [workspace] +resolver = "2" members = ["testcrate"] [profile.release] From 1fb5e1a5ba8129c13790320a855623fb9e3170c3 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 8 Mar 2025 00:20:34 +0000 Subject: [PATCH 1725/4206] Replace some uses of `sign` with `sig` It seems like "sign" was used as a shortened version of "significand", but that is easy to confuse with "sign". Update these to use "sig" like most other places. --- library/compiler-builtins/src/float/extend.rs | 22 +++++++++---------- library/compiler-builtins/src/float/trunc.rs | 8 +++---- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/src/float/extend.rs index f05e3a924c1da..ce00da31dc5d9 100644 --- a/library/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/src/float/extend.rs @@ -15,22 +15,22 @@ where let src_zero = F::Int::ZERO; let src_one = F::Int::ONE; let src_bits = F::BITS; - let src_sign_bits = F::SIG_BITS; + let src_sig_bits = F::SIG_BITS; let src_exp_bias = F::EXP_BIAS; let src_min_normal = F::IMPLICIT_BIT; let src_infinity = F::EXP_MASK; - let src_sign_mask = F::SIGN_MASK as F::Int; + let src_sign_mask = F::SIGN_MASK; let src_abs_mask = src_sign_mask - src_one; let src_qnan = F::SIG_MASK; let src_nan_code = src_qnan - src_one; let dst_bits = R::BITS; - let dst_sign_bits = R::SIG_BITS; + let dst_sig_bits = R::SIG_BITS; let dst_inf_exp = R::EXP_SAT; let dst_exp_bias = R::EXP_BIAS; let dst_min_normal = R::IMPLICIT_BIT; - let sign_bits_delta = dst_sign_bits - src_sign_bits; + let sig_bits_delta = dst_sig_bits - src_sig_bits; let exp_bias_delta = dst_exp_bias - src_exp_bias; let a_abs = a.to_bits() & src_abs_mask; let mut abs_result = R::Int::ZERO; @@ -41,8 +41,8 @@ where // exponent into the proper position and rebiasing the exponent. let abs_dst: R::Int = a_abs.cast(); let bias_dst: R::Int = exp_bias_delta.cast(); - abs_result = abs_dst.wrapping_shl(sign_bits_delta); - abs_result += bias_dst.wrapping_shl(dst_sign_bits); + abs_result = abs_dst.wrapping_shl(sig_bits_delta); + abs_result += bias_dst.wrapping_shl(dst_sig_bits); } else if a_abs >= src_infinity { // a is NaN or infinity. // Conjure the result by beginning with infinity, then setting the qNaN @@ -51,9 +51,9 @@ where let qnan_dst: R::Int = (a_abs & src_qnan).cast(); let nan_code_dst: R::Int = (a_abs & src_nan_code).cast(); let inf_exp_dst: R::Int = dst_inf_exp.cast(); - abs_result = inf_exp_dst.wrapping_shl(dst_sign_bits); - abs_result |= qnan_dst.wrapping_shl(sign_bits_delta); - abs_result |= nan_code_dst.wrapping_shl(sign_bits_delta); + abs_result = inf_exp_dst.wrapping_shl(dst_sig_bits); + abs_result |= qnan_dst.wrapping_shl(sig_bits_delta); + abs_result |= nan_code_dst.wrapping_shl(sig_bits_delta); } else if a_abs != src_zero { // a is denormal. // Renormalize the significand and clear the leading bit, then insert @@ -61,8 +61,8 @@ where let scale = a_abs.leading_zeros() - src_min_normal.leading_zeros(); let abs_dst: R::Int = a_abs.cast(); let bias_dst: R::Int = (exp_bias_delta - scale + 1).cast(); - abs_result = abs_dst.wrapping_shl(sign_bits_delta + scale); - abs_result = (abs_result ^ dst_min_normal) | (bias_dst.wrapping_shl(dst_sign_bits)); + abs_result = abs_dst.wrapping_shl(sig_bits_delta + scale); + abs_result = (abs_result ^ dst_min_normal) | (bias_dst.wrapping_shl(dst_sig_bits)); } let sign_result: R::Int = (a.to_bits() & src_sign_mask).cast(); diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/src/float/trunc.rs index 3759aa7dc43dd..928eba0c8ef36 100644 --- a/library/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/src/float/trunc.rs @@ -17,7 +17,7 @@ where let src_exp_bias = F::EXP_BIAS; let src_min_normal = F::IMPLICIT_BIT; - let src_significand_mask = F::SIG_MASK; + let src_sig_mask = F::SIG_MASK; let src_infinity = F::EXP_MASK; let src_sign_mask = F::SIGN_MASK; let src_abs_mask = src_sign_mask - src_one; @@ -40,7 +40,7 @@ where let dst_qnan = R::Int::ONE << (R::SIG_BITS - 1); let dst_nan_code = dst_qnan - dst_one; - let sign_bits_delta = F::SIG_BITS - R::SIG_BITS; + let sig_bits_delta = F::SIG_BITS - R::SIG_BITS; // Break a into a sign and representation of the absolute value. let a_abs = a.to_bits() & src_abs_mask; let sign = a.to_bits() & src_sign_mask; @@ -50,7 +50,7 @@ where // The exponent of a is within the range of normal numbers in the // destination format. We can convert by simply right-shifting with // rounding and adjusting the exponent. - abs_result = (a_abs >> sign_bits_delta).cast(); + abs_result = (a_abs >> sig_bits_delta).cast(); // Cast before shifting to prevent overflow. let bias_diff: R::Int = src_exp_bias.wrapping_sub(dst_exp_bias).cast(); let tmp = bias_diff << R::SIG_BITS; @@ -85,7 +85,7 @@ where let a_exp: u32 = (a_abs >> F::SIG_BITS).cast(); let shift = src_exp_bias - dst_exp_bias - a_exp + 1; - let significand = (a.to_bits() & src_significand_mask) | src_min_normal; + let significand = (a.to_bits() & src_sig_mask) | src_min_normal; // Right shift by the denormalization amount with sticky. if shift > F::SIG_BITS { From 8bbc080cc71f4af39225d9b0f3e70cf478347f15 Mon Sep 17 00:00:00 2001 From: Nathaniel Woods Date: Tue, 4 Mar 2025 16:33:21 -0500 Subject: [PATCH 1726/4206] Added `Clone` implementation for `ChunkBy` --- library/alloctests/tests/slice.rs | 13 +++++++++++++ library/core/src/slice/iter.rs | 7 +++++++ 2 files changed, 20 insertions(+) diff --git a/library/alloctests/tests/slice.rs b/library/alloctests/tests/slice.rs index 2516563187f2d..1e15d54d979a2 100644 --- a/library/alloctests/tests/slice.rs +++ b/library/alloctests/tests/slice.rs @@ -1636,6 +1636,19 @@ fn test_chunk_by() { assert_eq!(iter.next_back(), Some(&[1][..])); assert_eq!(iter.next(), Some(&[2, 2, 2][..])); assert_eq!(iter.next_back(), None); + + let mut iter = slice.chunk_by(|a, b| a == b); + assert_eq!(iter.next(), Some(&[1, 1, 1][..])); + assert_eq!(iter.next(), Some(&[3, 3][..])); + let mut iter_clone = iter.clone(); + assert_eq!(iter.next(), Some(&[2, 2, 2][..])); + assert_eq!(iter.next(), Some(&[1][..])); + assert_eq!(iter.next(), Some(&[0][..])); + assert_eq!(iter.next(), None); + assert_eq!(iter_clone.next(), Some(&[2, 2, 2][..])); + assert_eq!(iter_clone.next(), Some(&[1][..])); + assert_eq!(iter_clone.next(), Some(&[0][..])); + assert_eq!(iter_clone.next(), None); } #[test] diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index a687ed7129dc8..bf48068b25457 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -3372,6 +3372,13 @@ where #[stable(feature = "slice_group_by", since = "1.77.0")] impl<'a, T: 'a, P> FusedIterator for ChunkBy<'a, T, P> where P: FnMut(&T, &T) -> bool {} +#[stable(feature = "slice_group_by", since = "1.77.0")] +impl<'a, T: 'a, P: Clone> Clone for ChunkBy<'a, T, P> { + fn clone(&self) -> Self { + Self { slice: self.slice, predicate: self.predicate.clone() } + } +} + #[stable(feature = "slice_group_by", since = "1.77.0")] impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for ChunkBy<'a, T, P> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { From e48617f817a2528502c7f6a59255e46c63d933d9 Mon Sep 17 00:00:00 2001 From: Nathaniel Woods Date: Thu, 6 Mar 2025 12:33:01 -0500 Subject: [PATCH 1727/4206] Changing #[stable] tag --- library/core/src/slice/iter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index bf48068b25457..8cbc6d4832eb8 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -3372,7 +3372,7 @@ where #[stable(feature = "slice_group_by", since = "1.77.0")] impl<'a, T: 'a, P> FusedIterator for ChunkBy<'a, T, P> where P: FnMut(&T, &T) -> bool {} -#[stable(feature = "slice_group_by", since = "1.77.0")] +#[stable(feature = "slice_group_by_clone", since = "CURRENT_RUSTC_VERSION")] impl<'a, T: 'a, P: Clone> Clone for ChunkBy<'a, T, P> { fn clone(&self) -> Self { Self { slice: self.slice, predicate: self.predicate.clone() } From 701b1948abd46425ab588108bb406b7519ec16fa Mon Sep 17 00:00:00 2001 From: tiif Date: Tue, 21 Jan 2025 08:08:58 +0000 Subject: [PATCH 1728/4206] impl Display for Conv --- .../rustc_const_eval/src/interpret/call.rs | 4 +-- compiler/rustc_target/src/callconv/mod.rs | 32 +++++++++++++++++++ src/tools/miri/src/helpers.rs | 3 +- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 29f819cca1fb6..35e2518770179 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -353,8 +353,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if caller_fn_abi.conv != callee_fn_abi.conv { throw_ub_custom!( fluent::const_eval_incompatible_calling_conventions, - callee_conv = format!("{:?}", callee_fn_abi.conv), - caller_conv = format!("{:?}", caller_fn_abi.conv), + callee_conv = format!("{}", callee_fn_abi.conv), + caller_conv = format!("{}", caller_fn_abi.conv), ) } diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 6d0ee3c7ee58a..0ea0d2d0173a8 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -1,3 +1,4 @@ +use std::fmt::Display; use std::str::FromStr; use std::{fmt, iter}; @@ -897,6 +898,37 @@ impl FromStr for Conv { } } +impl Display for Conv { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + Conv::C => "C", + Conv::Rust => "Rust", + Conv::Cold => "Cold", + Conv::PreserveMost => "PreserveMost", + Conv::PreserveAll => "PreserveAll", + Conv::ArmAapcs => "ArmAapcs", + Conv::CCmseNonSecureCall => "CCmseNonSecureCall", + Conv::CCmseNonSecureEntry => "CCmseNonSecureEntry", + Conv::Msp430Intr => "Msp430Intr", + Conv::PtxKernel => "PtxKernel", + Conv::GpuKernel => "GpuKernel", + Conv::X86Fastcall => "X86Fastcall", + Conv::X86Intr => "X86Intr", + Conv::X86Stdcall => "X86Stdcall", + Conv::X86ThisCall => "X86ThisCall", + Conv::X86VectorCall => "X86VectorCall", + Conv::X86_64SysV => "X86_64SysV", + Conv::X86_64Win64 => "X86_64Win64", + Conv::AvrInterrupt => "AvrInterrupt", + Conv::AvrNonBlockingInterrupt => "AvrNonBlockingInterrupt", + Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine } => "RiscvInterrupt(machine)", + Conv::RiscvInterrupt { kind: RiscvInterruptKind::Supervisor } => { + "RiscvInterrupt(supervisor)" + } + }) + } +} + // Some types are used a lot. Make sure they don't unintentionally get bigger. #[cfg(target_pointer_width = "64")] mod size_asserts { diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 12e7d0f1a62cf..bf08f9639c0cb 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -932,8 +932,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn check_abi<'a>(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, exp_abi: Conv) -> InterpResult<'a, ()> { if fn_abi.conv != exp_abi { throw_ub_format!( - "calling a function with ABI {:?} using caller ABI {:?}", - exp_abi, + "calling a function with ABI {exp_abi} using caller ABI {}", fn_abi.conv ); } From 17c6eae2910ffcb0e2a285625984f2eded45a285 Mon Sep 17 00:00:00 2001 From: tiif Date: Mon, 3 Feb 2025 13:50:39 +0000 Subject: [PATCH 1729/4206] Add test and change ub message wording --- src/tools/miri/src/helpers.rs | 8 ++++---- .../miri/tests/fail/shims/callconv_mismatch.rs | 11 +++++++++++ .../tests/fail/shims/callconv_mismatch.stderr | 15 +++++++++++++++ 3 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 src/tools/miri/tests/fail/shims/callconv_mismatch.rs create mode 100644 src/tools/miri/tests/fail/shims/callconv_mismatch.stderr diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index bf08f9639c0cb..04829a9424c13 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -928,11 +928,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { self.read_c_str_with_char_size(ptr, wchar_t.size, wchar_t.align.abi) } - /// Check that the ABI is what we expect. - fn check_abi<'a>(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, exp_abi: Conv) -> InterpResult<'a, ()> { + /// Check that the calling convention is what we expect. + fn check_callconv<'a>(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, exp_abi: Conv) -> InterpResult<'a, ()> { if fn_abi.conv != exp_abi { throw_ub_format!( - "calling a function with ABI {exp_abi} using caller ABI {}", + "calling a function with calling convention {exp_abi} using caller calling convention {}", fn_abi.conv ); } @@ -968,7 +968,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { exp_abi: Conv, link_name: Symbol, ) -> InterpResult<'tcx, ()> { - self.check_abi(abi, exp_abi)?; + self.check_callconv(abi, exp_abi)?; if let Some((body, instance)) = self.eval_context_mut().lookup_exported_symbol(link_name)? { // If compiler-builtins is providing the symbol, then don't treat it as a clash. // We'll use our built-in implementation in `emulate_foreign_item_inner` for increased diff --git a/src/tools/miri/tests/fail/shims/callconv_mismatch.rs b/src/tools/miri/tests/fail/shims/callconv_mismatch.rs new file mode 100644 index 0000000000000..2f9b89ae08d2b --- /dev/null +++ b/src/tools/miri/tests/fail/shims/callconv_mismatch.rs @@ -0,0 +1,11 @@ +extern "Rust" { + fn pipe(fds: *mut std::ffi::c_int) -> std::ffi::c_int; +} + +// Test the error for calling convention mismatch. +fn main() { + let mut fds = [-1, -1]; + let res = unsafe { pipe(fds.as_mut_ptr()) }; + //~^ ERROR: calling a function with calling convention C using caller calling convention Rust + assert_eq!(res, 0); +} \ No newline at end of file diff --git a/src/tools/miri/tests/fail/shims/callconv_mismatch.stderr b/src/tools/miri/tests/fail/shims/callconv_mismatch.stderr new file mode 100644 index 0000000000000..11b57de195391 --- /dev/null +++ b/src/tools/miri/tests/fail/shims/callconv_mismatch.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a function with calling convention C using caller calling convention Rust + --> tests/fail/shims/callconv_mismatch.rs:LL:CC + | +LL | let res = unsafe { pipe(fds.as_mut_ptr()) }; + | ^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention C using caller calling convention Rust + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail/shims/callconv_mismatch.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + From 43c51e9ff33e0014c0e17712d01ae8dc44a57096 Mon Sep 17 00:00:00 2001 From: tiif Date: Mon, 3 Feb 2025 13:51:44 +0000 Subject: [PATCH 1730/4206] Remove unnecessary assert --- src/tools/miri/tests/fail/shims/callconv_mismatch.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/miri/tests/fail/shims/callconv_mismatch.rs b/src/tools/miri/tests/fail/shims/callconv_mismatch.rs index 2f9b89ae08d2b..adde34dc1fae4 100644 --- a/src/tools/miri/tests/fail/shims/callconv_mismatch.rs +++ b/src/tools/miri/tests/fail/shims/callconv_mismatch.rs @@ -7,5 +7,4 @@ fn main() { let mut fds = [-1, -1]; let res = unsafe { pipe(fds.as_mut_ptr()) }; //~^ ERROR: calling a function with calling convention C using caller calling convention Rust - assert_eq!(res, 0); } \ No newline at end of file From d463c5d07c4715f4ebd86b2093139784fa69bd2b Mon Sep 17 00:00:00 2001 From: tiif Date: Tue, 11 Mar 2025 16:46:26 +0000 Subject: [PATCH 1731/4206] Implement Display by mapping Conv to ExternAbi --- compiler/rustc_target/src/callconv/mod.rs | 53 ++++++++++--------- .../fail/function_calls/check_arg_abi.rs | 2 +- .../fail/function_calls/check_arg_abi.stderr | 4 +- 3 files changed, 30 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 0ea0d2d0173a8..8d8270cd8cd9f 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -898,34 +898,35 @@ impl FromStr for Conv { } } +fn conv_to_externabi(conv: &Conv) -> ExternAbi { + match conv { + Conv::Rust => ExternAbi::Rust, + Conv::PreserveMost => ExternAbi::RustCold, + Conv::X86Stdcall => ExternAbi::Stdcall{unwind: false}, + Conv::X86Fastcall => ExternAbi::Fastcall{unwind: false}, + Conv::X86VectorCall => ExternAbi::Vectorcall{unwind: false}, + Conv::X86ThisCall => ExternAbi::Thiscall{unwind: false}, + Conv::C => ExternAbi::C{unwind: false}, + Conv::X86_64Win64 => ExternAbi::Win64{unwind: false}, + Conv::X86_64SysV => ExternAbi::SysV64{unwind: false}, + Conv::ArmAapcs => ExternAbi::Aapcs{unwind: false}, + Conv::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall, + Conv::CCmseNonSecureEntry => ExternAbi::CCmseNonSecureEntry, + Conv::PtxKernel => ExternAbi::PtxKernel, + Conv::Msp430Intr => ExternAbi::Msp430Interrupt, + Conv::X86Intr => ExternAbi::X86Interrupt, + Conv::GpuKernel => ExternAbi::GpuKernel, + Conv::AvrInterrupt => ExternAbi::AvrInterrupt, + Conv::AvrNonBlockingInterrupt => ExternAbi::AvrNonBlockingInterrupt, + Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine } => ExternAbi::RiscvInterruptM, + Conv::RiscvInterrupt { kind: RiscvInterruptKind::Supervisor } => ExternAbi::RiscvInterruptS, + Conv::Cold | Conv::PreserveAll => panic!("This is deadcode"), + } +} + impl Display for Conv { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(match self { - Conv::C => "C", - Conv::Rust => "Rust", - Conv::Cold => "Cold", - Conv::PreserveMost => "PreserveMost", - Conv::PreserveAll => "PreserveAll", - Conv::ArmAapcs => "ArmAapcs", - Conv::CCmseNonSecureCall => "CCmseNonSecureCall", - Conv::CCmseNonSecureEntry => "CCmseNonSecureEntry", - Conv::Msp430Intr => "Msp430Intr", - Conv::PtxKernel => "PtxKernel", - Conv::GpuKernel => "GpuKernel", - Conv::X86Fastcall => "X86Fastcall", - Conv::X86Intr => "X86Intr", - Conv::X86Stdcall => "X86Stdcall", - Conv::X86ThisCall => "X86ThisCall", - Conv::X86VectorCall => "X86VectorCall", - Conv::X86_64SysV => "X86_64SysV", - Conv::X86_64Win64 => "X86_64Win64", - Conv::AvrInterrupt => "AvrInterrupt", - Conv::AvrNonBlockingInterrupt => "AvrNonBlockingInterrupt", - Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine } => "RiscvInterrupt(machine)", - Conv::RiscvInterrupt { kind: RiscvInterruptKind::Supervisor } => { - "RiscvInterrupt(supervisor)" - } - }) + write!(f, "{}", conv_to_externabi(self)) } } diff --git a/src/tools/miri/tests/fail/function_calls/check_arg_abi.rs b/src/tools/miri/tests/fail/function_calls/check_arg_abi.rs index ffa0443ce507a..0e91636416903 100644 --- a/src/tools/miri/tests/fail/function_calls/check_arg_abi.rs +++ b/src/tools/miri/tests/fail/function_calls/check_arg_abi.rs @@ -4,6 +4,6 @@ fn main() { } unsafe { - let _ = malloc(0); //~ ERROR: calling a function with ABI C using caller ABI Rust + let _ = malloc(0); //~ ERROR: calling a function with calling convention "C" using caller calling convention "Rust" }; } diff --git a/src/tools/miri/tests/fail/function_calls/check_arg_abi.stderr b/src/tools/miri/tests/fail/function_calls/check_arg_abi.stderr index bf1fbb7721f1f..7873018292316 100644 --- a/src/tools/miri/tests/fail/function_calls/check_arg_abi.stderr +++ b/src/tools/miri/tests/fail/function_calls/check_arg_abi.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: calling a function with ABI C using caller ABI Rust +error: Undefined Behavior: calling a function with calling convention "C" using caller calling convention "Rust" --> tests/fail/function_calls/check_arg_abi.rs:LL:CC | LL | let _ = malloc(0); - | ^^^^^^^^^ calling a function with ABI C using caller ABI Rust + | ^^^^^^^^^ calling a function with calling convention "C" using caller calling convention "Rust" | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information From 3079213020e518c29046b01b483ea37e949eb27d Mon Sep 17 00:00:00 2001 From: tiif Date: Tue, 11 Mar 2025 16:47:40 +0000 Subject: [PATCH 1732/4206] Remove test --- .../miri/tests/fail/shims/callconv_mismatch.rs | 10 ---------- .../tests/fail/shims/callconv_mismatch.stderr | 15 --------------- 2 files changed, 25 deletions(-) delete mode 100644 src/tools/miri/tests/fail/shims/callconv_mismatch.rs delete mode 100644 src/tools/miri/tests/fail/shims/callconv_mismatch.stderr diff --git a/src/tools/miri/tests/fail/shims/callconv_mismatch.rs b/src/tools/miri/tests/fail/shims/callconv_mismatch.rs deleted file mode 100644 index adde34dc1fae4..0000000000000 --- a/src/tools/miri/tests/fail/shims/callconv_mismatch.rs +++ /dev/null @@ -1,10 +0,0 @@ -extern "Rust" { - fn pipe(fds: *mut std::ffi::c_int) -> std::ffi::c_int; -} - -// Test the error for calling convention mismatch. -fn main() { - let mut fds = [-1, -1]; - let res = unsafe { pipe(fds.as_mut_ptr()) }; - //~^ ERROR: calling a function with calling convention C using caller calling convention Rust -} \ No newline at end of file diff --git a/src/tools/miri/tests/fail/shims/callconv_mismatch.stderr b/src/tools/miri/tests/fail/shims/callconv_mismatch.stderr deleted file mode 100644 index 11b57de195391..0000000000000 --- a/src/tools/miri/tests/fail/shims/callconv_mismatch.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: calling a function with calling convention C using caller calling convention Rust - --> tests/fail/shims/callconv_mismatch.rs:LL:CC - | -LL | let res = unsafe { pipe(fds.as_mut_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention C using caller calling convention Rust - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `main` at tests/fail/shims/callconv_mismatch.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - From c8197b77c9dcda42df92944d10e45382b490e504 Mon Sep 17 00:00:00 2001 From: tiif Date: Tue, 11 Mar 2025 16:48:20 +0000 Subject: [PATCH 1733/4206] fmt --- compiler/rustc_target/src/callconv/mod.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 8d8270cd8cd9f..e019dc55950e8 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -902,14 +902,14 @@ fn conv_to_externabi(conv: &Conv) -> ExternAbi { match conv { Conv::Rust => ExternAbi::Rust, Conv::PreserveMost => ExternAbi::RustCold, - Conv::X86Stdcall => ExternAbi::Stdcall{unwind: false}, - Conv::X86Fastcall => ExternAbi::Fastcall{unwind: false}, - Conv::X86VectorCall => ExternAbi::Vectorcall{unwind: false}, - Conv::X86ThisCall => ExternAbi::Thiscall{unwind: false}, - Conv::C => ExternAbi::C{unwind: false}, - Conv::X86_64Win64 => ExternAbi::Win64{unwind: false}, - Conv::X86_64SysV => ExternAbi::SysV64{unwind: false}, - Conv::ArmAapcs => ExternAbi::Aapcs{unwind: false}, + Conv::X86Stdcall => ExternAbi::Stdcall { unwind: false }, + Conv::X86Fastcall => ExternAbi::Fastcall { unwind: false }, + Conv::X86VectorCall => ExternAbi::Vectorcall { unwind: false }, + Conv::X86ThisCall => ExternAbi::Thiscall { unwind: false }, + Conv::C => ExternAbi::C { unwind: false }, + Conv::X86_64Win64 => ExternAbi::Win64 { unwind: false }, + Conv::X86_64SysV => ExternAbi::SysV64 { unwind: false }, + Conv::ArmAapcs => ExternAbi::Aapcs { unwind: false }, Conv::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall, Conv::CCmseNonSecureEntry => ExternAbi::CCmseNonSecureEntry, Conv::PtxKernel => ExternAbi::PtxKernel, From 71c4b2492de8a34a81f362ef9769b1608b8310e4 Mon Sep 17 00:00:00 2001 From: tiif Date: Tue, 11 Mar 2025 17:23:12 +0000 Subject: [PATCH 1734/4206] Remove invalid Conv --- compiler/rustc_target/src/callconv/mod.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index e019dc55950e8..6aae8bc755602 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -900,22 +900,21 @@ impl FromStr for Conv { fn conv_to_externabi(conv: &Conv) -> ExternAbi { match conv { + Conv::C => ExternAbi::C { unwind: false }, Conv::Rust => ExternAbi::Rust, Conv::PreserveMost => ExternAbi::RustCold, - Conv::X86Stdcall => ExternAbi::Stdcall { unwind: false }, - Conv::X86Fastcall => ExternAbi::Fastcall { unwind: false }, - Conv::X86VectorCall => ExternAbi::Vectorcall { unwind: false }, - Conv::X86ThisCall => ExternAbi::Thiscall { unwind: false }, - Conv::C => ExternAbi::C { unwind: false }, - Conv::X86_64Win64 => ExternAbi::Win64 { unwind: false }, - Conv::X86_64SysV => ExternAbi::SysV64 { unwind: false }, Conv::ArmAapcs => ExternAbi::Aapcs { unwind: false }, Conv::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall, Conv::CCmseNonSecureEntry => ExternAbi::CCmseNonSecureEntry, - Conv::PtxKernel => ExternAbi::PtxKernel, Conv::Msp430Intr => ExternAbi::Msp430Interrupt, - Conv::X86Intr => ExternAbi::X86Interrupt, Conv::GpuKernel => ExternAbi::GpuKernel, + Conv::X86Fastcall => ExternAbi::Fastcall { unwind: false }, + Conv::X86Intr => ExternAbi::X86Interrupt, + Conv::X86Stdcall => ExternAbi::Stdcall { unwind: false }, + Conv::X86ThisCall => ExternAbi::Thiscall { unwind: false }, + Conv::X86VectorCall => ExternAbi::Vectorcall { unwind: false }, + Conv::X86_64SysV => ExternAbi::SysV64 { unwind: false }, + Conv::X86_64Win64 => ExternAbi::Win64 { unwind: false }, Conv::AvrInterrupt => ExternAbi::AvrInterrupt, Conv::AvrNonBlockingInterrupt => ExternAbi::AvrNonBlockingInterrupt, Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine } => ExternAbi::RiscvInterruptM, From 650c8a2fb592a7519c37549734b664301b4b13be Mon Sep 17 00:00:00 2001 From: tiif Date: Wed, 12 Mar 2025 16:59:25 +0000 Subject: [PATCH 1735/4206] bless test --- .../miri/tests/fail/function_calls/check_callback_abi.rs | 2 +- .../tests/fail/function_calls/check_callback_abi.stderr | 4 ++-- .../exported_symbol_abi_mismatch.cache.stderr | 4 ++-- .../exported_symbol_abi_mismatch.fn_ptr.stderr | 4 ++-- .../exported_symbol_abi_mismatch.no_cache.stderr | 4 ++-- .../fail/function_calls/exported_symbol_abi_mismatch.rs | 6 +++--- src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs | 2 +- src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr | 4 ++-- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/tools/miri/tests/fail/function_calls/check_callback_abi.rs b/src/tools/miri/tests/fail/function_calls/check_callback_abi.rs index 6a7a26710d16b..177e38105e6fa 100644 --- a/src/tools/miri/tests/fail/function_calls/check_callback_abi.rs +++ b/src/tools/miri/tests/fail/function_calls/check_callback_abi.rs @@ -9,7 +9,7 @@ fn main() { // Make sure we check the ABI when Miri itself invokes a function // as part of a shim implementation. std::intrinsics::catch_unwind( - //~^ ERROR: calling a function with calling convention C using calling convention Rust + //~^ ERROR: calling a function with calling convention "C" using calling convention "Rust" std::mem::transmute::(try_fn), std::ptr::null_mut(), |_, _| unreachable!(), diff --git a/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr b/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr index 6b0692e1c6e8d..20182ac923677 100644 --- a/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr +++ b/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: calling a function with calling convention C using calling convention Rust +error: Undefined Behavior: calling a function with calling convention "C" using calling convention "Rust" --> tests/fail/function_calls/check_callback_abi.rs:LL:CC | LL | / std::intrinsics::catch_unwind( @@ -7,7 +7,7 @@ LL | | std::mem::transmute::(try_fn), LL | | std::ptr::null_mut(), LL | | |_, _| unreachable!(), LL | | ); - | |_________^ calling a function with calling convention C using calling convention Rust + | |_________^ calling a function with calling convention "C" using calling convention "Rust" | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr index e4302ad1d3a53..46a32d1487ead 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: calling a function with calling convention Rust using calling convention C +error: Undefined Behavior: calling a function with calling convention "Rust" using calling convention "C" --> tests/fail/function_calls/exported_symbol_abi_mismatch.rs:LL:CC | LL | foo(); - | ^^^^^ calling a function with calling convention Rust using calling convention C + | ^^^^^ calling a function with calling convention "Rust" using calling convention "C" | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr index 9f40c48b338e3..3872528991905 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: calling a function with calling convention Rust using calling convention C +error: Undefined Behavior: calling a function with calling convention "Rust" using calling convention "C" --> tests/fail/function_calls/exported_symbol_abi_mismatch.rs:LL:CC | LL | std::mem::transmute::(foo)(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention Rust using calling convention C + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention "Rust" using calling convention "C" | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr index e4302ad1d3a53..46a32d1487ead 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: calling a function with calling convention Rust using calling convention C +error: Undefined Behavior: calling a function with calling convention "Rust" using calling convention "C" --> tests/fail/function_calls/exported_symbol_abi_mismatch.rs:LL:CC | LL | foo(); - | ^^^^^ calling a function with calling convention Rust using calling convention C + | ^^^^^ calling a function with calling convention "Rust" using calling convention "C" | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.rs b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.rs index 50a0e8e6edef8..1950e162c0700 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.rs +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.rs @@ -12,7 +12,7 @@ fn main() { #[cfg(fn_ptr)] unsafe { std::mem::transmute::(foo)(); - //~[fn_ptr]^ ERROR: calling a function with calling convention Rust using calling convention C + //~[fn_ptr]^ ERROR: calling a function with calling convention "Rust" using calling convention "C" } // `Instance` caching should not suppress ABI check. @@ -28,8 +28,8 @@ fn main() { } unsafe { foo(); - //~[no_cache]^ ERROR: calling a function with calling convention Rust using calling convention C - //~[cache]| ERROR: calling a function with calling convention Rust using calling convention C + //~[no_cache]^ ERROR: calling a function with calling convention "Rust" using calling convention "C" + //~[cache]| ERROR: calling a function with calling convention "Rust" using calling convention "C" } } } diff --git a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs index 5f00dbf257366..952f9697fc795 100644 --- a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs +++ b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs @@ -1,4 +1,4 @@ -//@error-in-other-file: Undefined Behavior: calling a function with calling convention C using calling convention Rust +//@error-in-other-file: Undefined Behavior: calling a function with calling convention "C" using calling convention "Rust" #![feature(explicit_tail_calls)] #![allow(incomplete_features)] diff --git a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr index 5061c9e8dc3f0..61ddea644720f 100644 --- a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr +++ b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: calling a function with calling convention C using calling convention Rust +error: Undefined Behavior: calling a function with calling convention "C" using calling convention "Rust" --> RUSTLIB/core/src/ops/function.rs:LL:CC | LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention C using calling convention Rust + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention "C" using calling convention "Rust" | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information From e74fe7a6ad02391ff873916a4e0243144e5e9355 Mon Sep 17 00:00:00 2001 From: tiif Date: Wed, 12 Mar 2025 17:13:47 +0000 Subject: [PATCH 1736/4206] Bless more test --- tests/ui/consts/miri_unleashed/abi-mismatch.rs | 2 +- tests/ui/consts/miri_unleashed/abi-mismatch.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/consts/miri_unleashed/abi-mismatch.rs b/tests/ui/consts/miri_unleashed/abi-mismatch.rs index ea640ae78d551..727cfecfa4165 100644 --- a/tests/ui/consts/miri_unleashed/abi-mismatch.rs +++ b/tests/ui/consts/miri_unleashed/abi-mismatch.rs @@ -10,6 +10,6 @@ const fn call_rust_fn(my_fn: extern "Rust" fn()) { static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn()) }); //~^ ERROR could not evaluate static initializer -//~| NOTE calling a function with calling convention C using calling convention Rust +//~| NOTE calling a function with calling convention "C" using calling convention "Rust" fn main() {} diff --git a/tests/ui/consts/miri_unleashed/abi-mismatch.stderr b/tests/ui/consts/miri_unleashed/abi-mismatch.stderr index 88623b134b0bf..7d1fdcce52614 100644 --- a/tests/ui/consts/miri_unleashed/abi-mismatch.stderr +++ b/tests/ui/consts/miri_unleashed/abi-mismatch.stderr @@ -2,7 +2,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/abi-mismatch.rs:11:18 | LL | static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn()) }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention C using calling convention Rust + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention "C" using calling convention "Rust" | note: inside `call_rust_fn` --> $DIR/abi-mismatch.rs:7:5 From 192206bfbb57ed2781ccc9319405038e5778c1a5 Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Mon, 17 Mar 2025 02:41:53 +0100 Subject: [PATCH 1737/4206] Revert "Disable some PPC64 tests which are failing due to an LLVM(?) bug" This reverts commit 265fdacab9b3c63b2c17a42fb17c51996c703ef8. Fixes: https://github.com/rust-lang/rust/issues/99853 Signed-off-by: Jens Reidel --- library/compiler-builtins/testcrate/tests/mem.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/library/compiler-builtins/testcrate/tests/mem.rs b/library/compiler-builtins/testcrate/tests/mem.rs index 5099d69ed6c3c..48ac95adc17f4 100644 --- a/library/compiler-builtins/testcrate/tests/mem.rs +++ b/library/compiler-builtins/testcrate/tests/mem.rs @@ -230,8 +230,6 @@ fn memmove_backward_aligned() { } } -// PowerPC tests are failing: https://github.com/rust-lang/rust/issues/99853 -#[cfg(not(target_arch = "powerpc64"))] #[test] fn memset_backward_misaligned_nonaligned_start() { let mut arr = gen_arr::<32>(); @@ -244,8 +242,6 @@ fn memset_backward_misaligned_nonaligned_start() { } } -// PowerPC tests are failing: https://github.com/rust-lang/rust/issues/99853 -#[cfg(not(target_arch = "powerpc64"))] #[test] fn memset_backward_misaligned_aligned_start() { let mut arr = gen_arr::<32>(); @@ -258,8 +254,6 @@ fn memset_backward_misaligned_aligned_start() { } } -// PowerPC tests are failing: https://github.com/rust-lang/rust/issues/99853 -#[cfg(not(target_arch = "powerpc64"))] #[test] fn memset_backward_aligned() { let mut arr = gen_arr::<32>(); From 6d353134bccd7e14aaba2c3476fc754f1fc16a48 Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Mon, 17 Mar 2025 21:59:56 +0100 Subject: [PATCH 1738/4206] Revert "Disable broken powerpc64 test due to https://github.com/rust-lang/rust/issues/88520" This reverts commit 55f6ecb6de9e2e10d9187b287b9e87b202d07d1e. Fixes: https://github.com/rust-lang/rust/issues/88520 Signed-off-by: Jens Reidel --- library/compiler-builtins/testcrate/tests/cmp.rs | 3 --- library/compiler-builtins/testcrate/tests/conv.rs | 2 -- 2 files changed, 5 deletions(-) diff --git a/library/compiler-builtins/testcrate/tests/cmp.rs b/library/compiler-builtins/testcrate/tests/cmp.rs index e3161f374290d..19d90c66493cc 100644 --- a/library/compiler-builtins/testcrate/tests/cmp.rs +++ b/library/compiler-builtins/testcrate/tests/cmp.rs @@ -2,11 +2,8 @@ #![allow(unreachable_code)] #![cfg_attr(f128_enabled, feature(f128))] -#[cfg(not(target_arch = "powerpc64"))] use testcrate::*; -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] mod float_comparisons { use super::*; diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs index db1493cae9a1e..381d3e155780c 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/testcrate/tests/conv.rs @@ -141,8 +141,6 @@ mod i_to_f { } } -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] mod f_to_i { use super::*; From 590a56483cc32e2cd38a6de76c71c319db997360 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Mar 2025 16:36:38 +0100 Subject: [PATCH 1739/4206] remove element_unordered_atomic intrinsics --- library/compiler-builtins/src/mem/mod.rs | 132 ----------------------- 1 file changed, 132 deletions(-) diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/src/mem/mod.rs index f10439e2d3f14..ec160039d0d03 100644 --- a/library/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/src/mem/mod.rs @@ -8,10 +8,6 @@ type c_int = i16; #[cfg(not(target_pointer_width = "16"))] type c_int = i32; -use core::intrinsics::{atomic_load_unordered, atomic_store_unordered, exact_div}; -use core::mem; -use core::ops::{BitOr, Shl}; - // memcpy/memmove/memset have optimized implementations on some architectures #[cfg_attr( all(not(feature = "no-asm"), target_arch = "x86_64"), @@ -60,131 +56,3 @@ intrinsics! { impls::c_string_length(s) } } - -// `bytes` must be a multiple of `mem::size_of::()` -#[cfg_attr(not(target_has_atomic_load_store = "8"), allow(dead_code))] -fn memcpy_element_unordered_atomic(dest: *mut T, src: *const T, bytes: usize) { - unsafe { - let n = exact_div(bytes, mem::size_of::()); - let mut i = 0; - while i < n { - atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i))); - i += 1; - } - } -} - -// `bytes` must be a multiple of `mem::size_of::()` -#[cfg_attr(not(target_has_atomic_load_store = "8"), allow(dead_code))] -fn memmove_element_unordered_atomic(dest: *mut T, src: *const T, bytes: usize) { - unsafe { - let n = exact_div(bytes, mem::size_of::()); - if src < dest as *const T { - // copy from end - let mut i = n; - while i != 0 { - i -= 1; - atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i))); - } - } else { - // copy from beginning - let mut i = 0; - while i < n { - atomic_store_unordered(dest.add(i), atomic_load_unordered(src.add(i))); - i += 1; - } - } - } -} - -// `T` must be a primitive integer type, and `bytes` must be a multiple of `mem::size_of::()` -#[cfg_attr(not(target_has_atomic_load_store = "8"), allow(dead_code))] -fn memset_element_unordered_atomic(s: *mut T, c: u8, bytes: usize) -where - T: Copy + From + Shl + BitOr, -{ - unsafe { - let n = exact_div(bytes, mem::size_of::()); - - // Construct a value of type `T` consisting of repeated `c` - // bytes, to let us ensure we write each `T` atomically. - let mut x = T::from(c); - let mut i = 1; - while i < mem::size_of::() { - x = (x << 8) | T::from(c); - i += 1; - } - - // Write it to `s` - let mut i = 0; - while i < n { - atomic_store_unordered(s.add(i), x); - i += 1; - } - } -} - -intrinsics! { - #[cfg(target_has_atomic_load_store = "8")] - pub unsafe extern "C" fn __llvm_memcpy_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () { - memcpy_element_unordered_atomic(dest, src, bytes); - } - #[cfg(target_has_atomic_load_store = "16")] - pub unsafe extern "C" fn __llvm_memcpy_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () { - memcpy_element_unordered_atomic(dest, src, bytes); - } - #[cfg(target_has_atomic_load_store = "32")] - pub unsafe extern "C" fn __llvm_memcpy_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () { - memcpy_element_unordered_atomic(dest, src, bytes); - } - #[cfg(target_has_atomic_load_store = "64")] - pub unsafe extern "C" fn __llvm_memcpy_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () { - memcpy_element_unordered_atomic(dest, src, bytes); - } - #[cfg(target_has_atomic_load_store = "128")] - pub unsafe extern "C" fn __llvm_memcpy_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () { - memcpy_element_unordered_atomic(dest, src, bytes); - } - - #[cfg(target_has_atomic_load_store = "8")] - pub unsafe extern "C" fn __llvm_memmove_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () { - memmove_element_unordered_atomic(dest, src, bytes); - } - #[cfg(target_has_atomic_load_store = "16")] - pub unsafe extern "C" fn __llvm_memmove_element_unordered_atomic_2(dest: *mut u16, src: *const u16, bytes: usize) -> () { - memmove_element_unordered_atomic(dest, src, bytes); - } - #[cfg(target_has_atomic_load_store = "32")] - pub unsafe extern "C" fn __llvm_memmove_element_unordered_atomic_4(dest: *mut u32, src: *const u32, bytes: usize) -> () { - memmove_element_unordered_atomic(dest, src, bytes); - } - #[cfg(target_has_atomic_load_store = "64")] - pub unsafe extern "C" fn __llvm_memmove_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () { - memmove_element_unordered_atomic(dest, src, bytes); - } - #[cfg(target_has_atomic_load_store = "128")] - pub unsafe extern "C" fn __llvm_memmove_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () { - memmove_element_unordered_atomic(dest, src, bytes); - } - - #[cfg(target_has_atomic_load_store = "8")] - pub unsafe extern "C" fn __llvm_memset_element_unordered_atomic_1(s: *mut u8, c: u8, bytes: usize) -> () { - memset_element_unordered_atomic(s, c, bytes); - } - #[cfg(target_has_atomic_load_store = "16")] - pub unsafe extern "C" fn __llvm_memset_element_unordered_atomic_2(s: *mut u16, c: u8, bytes: usize) -> () { - memset_element_unordered_atomic(s, c, bytes); - } - #[cfg(target_has_atomic_load_store = "32")] - pub unsafe extern "C" fn __llvm_memset_element_unordered_atomic_4(s: *mut u32, c: u8, bytes: usize) -> () { - memset_element_unordered_atomic(s, c, bytes); - } - #[cfg(target_has_atomic_load_store = "64")] - pub unsafe extern "C" fn __llvm_memset_element_unordered_atomic_8(s: *mut u64, c: u8, bytes: usize) -> () { - memset_element_unordered_atomic(s, c, bytes); - } - #[cfg(target_has_atomic_load_store = "128")] - pub unsafe extern "C" fn __llvm_memset_element_unordered_atomic_16(s: *mut u128, c: u8, bytes: usize) -> () { - memset_element_unordered_atomic(s, c, bytes); - } -} From a179959e0bc8dc061bcf9ec841b6a8b8b516e683 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 18 Mar 2025 10:13:47 +0000 Subject: [PATCH 1740/4206] Move `examples/intrinsics.rs` to its own crate Currently there is an interesting situation with the way features get enabled; `testcrate` enables `mangled-names`, but the `intrinsics.rs` example requires this feature be disabled (otherwise the test fails with missing symbols, as expected). This is also the reason that `testcrate` is not a default workspace member, meaning `cargo test` doesn't actually run `testcrate`'s tests; making it a default member would mean that `compiler-builtins/mangled-names` gets enabled when `examples/intrinsics.rs` gets built, due to the way features get unified. Simplify the situation by making moving the example to its own crate as `builtins-test-intrinsics`. This also means `testcrate` can become a default member so it is included in `cargo check` or `cargo test` when run at the workspace root. `testcrate` and `builtins-test-intrinsics` still can't be built at the same time since there isn't a straightforward way to have Cargo build `compiler-builtins` twice with different features. This is a side effect of us using non-additive features, but there isn't really a better option since enabling both mangled and unmangled names would render `builtins-test-intrinsics` useless. --- library/compiler-builtins/Cargo.toml | 17 +++++++++----- library/compiler-builtins/README.md | 4 ++-- library/compiler-builtins/build.rs | 17 ++------------ .../builtins-test-intrinsics/Cargo.toml | 11 ++++++++++ .../builtins-test-intrinsics/build.rs | 11 ++++++++++ .../src/main.rs} | 0 library/compiler-builtins/ci/run.sh | 18 +++++++-------- library/compiler-builtins/configure.rs | 22 ++++++++++++++++++- library/compiler-builtins/testcrate/build.rs | 1 + 9 files changed, 69 insertions(+), 32 deletions(-) create mode 100644 library/compiler-builtins/builtins-test-intrinsics/Cargo.toml create mode 100644 library/compiler-builtins/builtins-test-intrinsics/build.rs rename library/compiler-builtins/{examples/intrinsics.rs => builtins-test-intrinsics/src/main.rs} (100%) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 9d1448342065c..60de27758d8e3 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -71,13 +71,20 @@ rustc-dep-of-std = ['compiler-builtins', 'core'] # are not normally public but are required by the `testcrate` public-test-deps = [] -[[example]] -name = "intrinsics" -required-features = ["compiler-builtins"] - [workspace] resolver = "2" -members = ["testcrate"] +members = [ + # Note that builtins-test-intrinsics cannot be a default member because it + # needs the `mangled-names` feature disabled, while `testcrate` needs it + # enabled. + "builtins-test-intrinsics", + "testcrate", +] + +default-members = [ + ".", + "testcrate", +] [profile.release] panic = 'abort' diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index d76bd289ba53a..e5350d58c3e3f 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -16,8 +16,8 @@ It is distributed as part of Rust's sysroot. [C implementation][2] to Rust. 4. Add a test to compare the behavior of the ported intrinsic(s) with their implementation on the testing host. -5. Add the intrinsic to `examples/intrinsics.rs` to verify it can be linked on - all targets. +5. Add the intrinsic to `builtins-test-intrinsics/src/main.rs` to verify it + can be linked on all targets. 6. Send a Pull Request (PR). 7. Once the PR passes our extensive testing infrastructure, we'll merge it! 8. Celebrate :tada: diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 3c04423f2d83c..369354a1d52a4 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -2,7 +2,7 @@ use std::{collections::BTreeMap, env, path::PathBuf, sync::atomic::Ordering}; mod configure; -use configure::{configure_f16_f128, Target}; +use configure::{configure_aliases, configure_f16_f128, Target}; fn main() { println!("cargo::rerun-if-changed=build.rs"); @@ -13,6 +13,7 @@ fn main() { configure_check_cfg(); configure_f16_f128(&target); + configure_aliases(&target); configure_libm(&target); @@ -71,20 +72,6 @@ fn main() { } } - // To compile intrinsics.rs for thumb targets, where there is no libc - println!("cargo::rustc-check-cfg=cfg(thumb)"); - if llvm_target[0].starts_with("thumb") { - println!("cargo:rustc-cfg=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 llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" { - println!("cargo:rustc-cfg=thumb_1") - } - // 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). diff --git a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml new file mode 100644 index 0000000000000..8c7cca4bd996e --- /dev/null +++ b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "builtins-test-intrinsics" +version = "0.1.0" +edition = "2021" + +[dependencies] +compiler_builtins = { path = "../", features = ["compiler-builtins"]} +panic-handler = { path = '../crates/panic-handler' } + +[features] +c = ["compiler_builtins/c"] diff --git a/library/compiler-builtins/builtins-test-intrinsics/build.rs b/library/compiler-builtins/builtins-test-intrinsics/build.rs new file mode 100644 index 0000000000000..a38c6c1ff71ca --- /dev/null +++ b/library/compiler-builtins/builtins-test-intrinsics/build.rs @@ -0,0 +1,11 @@ +mod builtins_configure { + include!("../configure.rs"); +} + +fn main() { + println!("cargo::rerun-if-changed=../configure.rs"); + + let target = builtins_configure::Target::from_env(); + builtins_configure::configure_f16_f128(&target); + builtins_configure::configure_aliases(&target); +} diff --git a/library/compiler-builtins/examples/intrinsics.rs b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs similarity index 100% rename from library/compiler-builtins/examples/intrinsics.rs rename to library/compiler-builtins/builtins-test-intrinsics/src/main.rs diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 057cdb083f765..3625dde79ed55 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -120,22 +120,22 @@ done rm -f "${rlib_paths[@]}" -build_intrinsics() { - cargo build --target "$target" -v --example intrinsics "$@" +build_intrinsics_test() { + cargo build --target "$target" -v --package builtins-test-intrinsics "$@" } -# Verify that we haven't drop any intrinsic/symbol -build_intrinsics -build_intrinsics --release -build_intrinsics --features c -build_intrinsics --features c --release +# Verify that we haven't dropped any intrinsics/symbols +build_intrinsics_test +build_intrinsics_test --release +build_intrinsics_test --features c +build_intrinsics_test --features c --release # Verify that there are no undefined symbols to `panic` within our # implementations CARGO_PROFILE_DEV_LTO=true \ - cargo build --target "$target" --example intrinsics + cargo build --target "$target" --package builtins-test-intrinsics CARGO_PROFILE_RELEASE_LTO=true \ - cargo build --target "$target" --example intrinsics --release + cargo build --target "$target" --package builtins-test-intrinsics --release # Ensure no references to any symbols from core update_rlib_paths diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/configure.rs index 931e966293920..2f134e57818ca 100644 --- a/library/compiler-builtins/configure.rs +++ b/library/compiler-builtins/configure.rs @@ -6,6 +6,7 @@ use std::env; #[allow(dead_code)] pub struct Target { pub triple: String, + pub triple_split: Vec, pub opt_level: String, pub cargo_features: Vec, pub os: String, @@ -19,6 +20,8 @@ pub struct Target { impl Target { pub fn from_env() -> Self { + 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, @@ -30,7 +33,8 @@ impl Target { .collect(); Self { - triple: env::var("TARGET").unwrap(), + triple, + triple_split, os: env::var("CARGO_CFG_TARGET_OS").unwrap(), opt_level: env::var("OPT_LEVEL").unwrap(), cargo_features, @@ -56,6 +60,22 @@ 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") + } + + // 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") + } +} + /// Configure whether or not `f16` and `f128` support should be enabled. pub fn configure_f16_f128(target: &Target) { // Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 15e4e771ca0f8..566b985d24627 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -115,5 +115,6 @@ fn main() { println!("cargo:rustc-cfg=feature=\"{name}\""); } + builtins_configure::configure_aliases(&target); builtins_configure::configure_f16_f128(&target); } From afa3eed6f09151d763bdb11ec16fe84a400873fb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 18 Mar 2025 10:39:26 +0000 Subject: [PATCH 1741/4206] Mark `builtins-test-intrinsics` as `publish = false` --- library/compiler-builtins/builtins-test-intrinsics/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml index 8c7cca4bd996e..9b2e5bb7c8a6f 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml +++ b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml @@ -2,6 +2,7 @@ name = "builtins-test-intrinsics" version = "0.1.0" edition = "2021" +publish = false [dependencies] compiler_builtins = { path = "../", features = ["compiler-builtins"]} From f8b03df54eb35ec8e0c1f5fbb0ae1eb2c08d88b0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 18 Mar 2025 11:14:04 +0000 Subject: [PATCH 1742/4206] Add a script for downloading compiler-rt Rather than needing to copy the version and URL from the CI workflow, put this into a script that can be directly run locally. --- library/compiler-builtins/.github/workflows/main.yml | 7 ++----- library/compiler-builtins/build.rs | 5 ++++- library/compiler-builtins/ci/download-compiler-rt.sh | 10 ++++++++++ 3 files changed, 16 insertions(+), 6 deletions(-) create mode 100755 library/compiler-builtins/ci/download-compiler-rt.sh diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 1c367a2d0da5b..34742e34954b1 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -4,7 +4,6 @@ on: [push, pull_request] env: RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings - RUST_LLVM_VERSION: 20.1-2025-02-13 RUST_COMPILER_RT_ROOT: ./compiler-rt jobs: @@ -129,12 +128,10 @@ jobs: uses: actions/cache@v4 with: path: compiler-rt - key: ${{ runner.os }}-compiler-rt-${{ env.RUST_LLVM_VERSION }} + key: ${{ runner.os }}-compiler-rt-${{ hashFiles('ci/download-compiler-rt.sh') }} - name: Download compiler-rt reference sources if: steps.cache-compiler-rt.outputs.cache-hit != 'true' - run: | - curl -L -o code.tar.gz "https://github.com/rust-lang/llvm-project/archive/rustc/$%7BRUST_LLVM_VERSION%7D.tar.gz" - tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-${RUST_LLVM_VERSION}/compiler-rt + run: ./ci/download-compiler-rt.sh shell: bash # Non-linux tests just use our raw script diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/build.rs index 369354a1d52a4..3003d51aff859 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/build.rs @@ -619,7 +619,10 @@ mod c { let root = match env::var_os("RUST_COMPILER_RT_ROOT") { Some(s) => PathBuf::from(s), None => { - panic!("RUST_COMPILER_RT_ROOT is not set. You may need to download compiler-rt.") + panic!( + "RUST_COMPILER_RT_ROOT is not set. You may need to run \ + `ci/download-compiler-rt.sh`." + ); } }; if !root.exists() { diff --git a/library/compiler-builtins/ci/download-compiler-rt.sh b/library/compiler-builtins/ci/download-compiler-rt.sh new file mode 100755 index 0000000000000..bf7f8c2489643 --- /dev/null +++ b/library/compiler-builtins/ci/download-compiler-rt.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# Download sources to build C versions of intrinsics. Once being run, +# `RUST_COMPILER_RT_ROOT` must be set. + +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/$%7Brust_llvm_version%7D.tar.gz" +tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-${rust_llvm_version}/compiler-rt From 014f530f76917d21882be755571c58912a6ea409 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Mar 2025 22:24:20 +0100 Subject: [PATCH 1743/4206] nightlies without clippy are not a thing any more --- library/compiler-builtins/.github/workflows/main.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 34742e34954b1..50844a66c43a9 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -178,10 +178,9 @@ jobs: with: submodules: true # Unlike rustfmt, stable clippy does not work on code with nightly features. - # This acquires the most recent nightly with a clippy component. - name: Install nightly `clippy` run: | - rustup set profile minimal && rustup default "nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/clippy)" && rustup component add clippy + rustup set profile minimal && rustup default nightly && rustup component add clippy - uses: Swatinem/rust-cache@v2 - run: cargo clippy -- -D clippy::all From 725759602a1ca7bca8f2acf1b2cb13e7cb7fa01d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 18 Mar 2025 23:51:19 +0000 Subject: [PATCH 1744/4206] Upgrade all dependencies to the latest This is mostly done to get the latest version of `rand`, which includes some breaking changes. --- library/compiler-builtins/libm/Cargo.toml | 3 +-- .../libm/crates/libm-macros/Cargo.toml | 6 +++--- .../libm/crates/libm-test/Cargo.toml | 14 +++++--------- .../libm/crates/libm-test/src/gen/random.rs | 10 +++++----- .../libm/crates/libm-test/tests/u256.rs | 10 +++++----- .../libm/crates/musl-math-sys/Cargo.toml | 2 +- 6 files changed, 20 insertions(+), 25 deletions(-) diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index eb133dada16d5..e0aeb07d52772 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -59,8 +59,7 @@ exclude = [ ] [dev-dependencies] -no-panic = "0.1.33" - +no-panic = "0.1.35" [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = [ diff --git a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml index f0de0e17689c3..314f4ae3783a8 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml @@ -9,9 +9,9 @@ proc-macro = true [dependencies] heck = "0.5.0" -proc-macro2 = "1.0.93" -quote = "1.0.38" -syn = { version = "2.0.96", features = ["full", "extra-traits", "visit-mut"] } +proc-macro2 = "1.0.94" +quote = "1.0.40" +syn = { version = "2.0.100", features = ["full", "extra-traits", "visit-mut"] } [lints.rust] # Values used during testing diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index dcbddb667e81e..98da73ceadc93 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -27,26 +27,22 @@ icount = ["dep:iai-callgrind"] short-benchmarks = [] [dependencies] -anyhow = "1.0.95" +anyhow = "1.0.97" # This is not directly used but is required so we can enable `gmp-mpfr-sys/force-cross`. gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false } iai-callgrind = { version = "0.14.0", optional = true } -indicatif = { version = "0.17.9", default-features = false } +indicatif = { version = "0.17.11", default-features = false } libm = { path = "../..", features = ["unstable-public-internals"] } libm-macros = { path = "../libm-macros" } musl-math-sys = { path = "../musl-math-sys", optional = true } paste = "1.0.15" -rand = "0.8.5" -rand_chacha = "0.3.1" +rand = "0.9.0" +rand_chacha = "0.9.0" rayon = "1.10.0" rug = { version = "1.27.0", optional = true, default-features = false, features = ["float", "integer", "std"] } -[target.'cfg(target_family = "wasm")'.dependencies] -# Enable randomness on WASM -getrandom = { version = "0.2", features = ["js"] } - [build-dependencies] -rand = { version = "0.8.5", optional = true } +rand = { version = "0.9.0", optional = true } [dev-dependencies] criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs index c2cd172d1ee47..e8a7ee9057e34 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs @@ -3,7 +3,7 @@ use std::ops::RangeInclusive; use std::sync::LazyLock; use libm::support::Float; -use rand::distributions::{Alphanumeric, Standard}; +use rand::distr::{Alphanumeric, StandardUniform}; use rand::prelude::Distribution; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; @@ -16,7 +16,7 @@ pub(crate) const SEED_ENV: &str = "LIBM_SEED"; pub static SEED: LazyLock<[u8; 32]> = LazyLock::new(|| { let s = env::var(SEED_ENV).unwrap_or_else(|_| { - let mut rng = rand::thread_rng(); + let mut rng = rand::rng(); (0..32).map(|_| rng.sample(Alphanumeric) as char).collect() }); @@ -33,19 +33,19 @@ pub trait RandomInput: Sized { /// Generate a sequence of deterministically random floats. fn random_floats(count: u64) -> impl Iterator where - Standard: Distribution, + StandardUniform: Distribution, { let mut rng = ChaCha8Rng::from_seed(*SEED); // Generate integers to get a full range of bitpatterns (including NaNs), then convert back // to the float type. - (0..count).map(move |_| F::from_bits(rng.gen::())) + (0..count).map(move |_| F::from_bits(rng.random::())) } /// Generate a sequence of deterministically random `i32`s within a specified range. fn random_ints(count: u64, range: RangeInclusive) -> impl Iterator { let mut rng = ChaCha8Rng::from_seed(*SEED); - (0..count).map(move |_| rng.gen_range::(range.clone())) + (0..count).map(move |_| rng.random_range::(range.clone())) } macro_rules! impl_random_input { diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs b/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs index 4174820c05b44..4603534248cd9 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs @@ -25,8 +25,8 @@ fn hexu(v: u256) -> String { } fn random_u256(rng: &mut ChaCha8Rng) -> u256 { - let lo: u128 = rng.gen(); - let hi: u128 = rng.gen(); + let lo: u128 = rng.random(); + let hi: u128 = rng.random(); u256 { lo, hi } } @@ -121,7 +121,7 @@ fn mp_u256_shr() { for _ in 0..bigint_fuzz_iteration_count() { let x = random_u256(&mut rng); - let shift: u32 = rng.gen_range(0..255); + let shift: u32 = rng.random_range(0..255); assign_bigint(&mut bx, x); let actual = x >> shift; bx >>= shift; @@ -136,8 +136,8 @@ fn mp_u256_widen_mul() { let mut by = BigInt::new(); for _ in 0..bigint_fuzz_iteration_count() { - let x: u128 = rng.gen(); - let y: u128 = rng.gen(); + let x: u128 = rng.random(); + let y: u128 = rng.random(); bx.assign(x); by.assign(y); let actual = x.widen_mul(y); diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml index cde78fd3c9712..34682b74c672f 100644 --- a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml +++ b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml @@ -10,4 +10,4 @@ publish = false libm = { path = "../../" } [build-dependencies] -cc = "1.2.10" +cc = "1.2.16" From 3167cbb6d01e247ca679712fd923c7cfbc45d7fc Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 19 Mar 2025 04:02:54 +0000 Subject: [PATCH 1745/4206] Temporarily disable the test call to `rust_begin_unwind` Since [1] this symbol is mangled, meaning it is not easy to call directly. A better fix will come in [2] but for now, just disable that portion of the test. [1]: https://github.com/rust-lang/rust/pull/127173 [2]: https://github.com/rust-lang/compiler-builtins/pull/802 --- .../builtins-test-intrinsics/src/main.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs index e90cfb33dea56..21d0a083c71d6 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs +++ b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs @@ -626,13 +626,14 @@ fn run() { something_with_a_dtor(&|| assert_eq!(bb(1), 1)); - extern "C" { - fn rust_begin_unwind(x: usize); - } - - unsafe { - rust_begin_unwind(0); - } + // FIXME(#802): This should be re-enabled once a workaround is found. + // extern "C" { + // fn rust_begin_unwind(x: usize); + // } + + // unsafe { + // rust_begin_unwind(0); + // } } fn something_with_a_dtor(f: &dyn Fn()) { From 683485cda22efc3514da4de730968e691e3a902f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 19 Mar 2025 05:19:17 +0000 Subject: [PATCH 1746/4206] Switch repository layout to use a virtual manifest The current setup has the `Cargo.toml` for `compiler-builtins` at the repository root, which means all support crates and other files are located within the package root. This works for now but is not the cleanest setup since files that should or shouldn't be included in the package need to be configured in `Cargo.toml`. If we eventually merge `libm` development into this repository, it would be nice to make this separation more straightforward. Begin cleaning things up by moving the crate source to a new `compiler-builtins` directory and adding a virtual manifest. For now the `libm` submodule is also moved, but in the future it can likely move back to the top level (ideally `compiler-builtins/src` would contain a symlink to `libm/src/math`, but unfortunately it seems like Cargo does not like something about the submodule + symlink combination). --- .../.github/workflows/main.yml | 3 +- .../.github/workflows/publish.yml | 2 +- library/compiler-builtins/.gitmodules | 4 +- library/compiler-builtins/Cargo.toml | 80 +------------------ .../builtins-test-intrinsics/Cargo.toml | 2 +- .../builtins-test-intrinsics/build.rs | 2 +- library/compiler-builtins/ci/run-docker.sh | 2 +- library/compiler-builtins/ci/run.sh | 4 +- .../compiler-builtins/Cargo.toml | 72 +++++++++++++++++ .../{ => compiler-builtins}/build.rs | 4 +- .../{ => compiler-builtins}/configure.rs | 0 .../{ => compiler-builtins}/libm | 0 .../{ => compiler-builtins}/src/aarch64.rs | 0 .../src/aarch64_linux.rs | 0 .../{ => compiler-builtins}/src/arm.rs | 0 .../{ => compiler-builtins}/src/arm_linux.rs | 0 .../{ => compiler-builtins}/src/float/add.rs | 0 .../{ => compiler-builtins}/src/float/cmp.rs | 0 .../{ => compiler-builtins}/src/float/conv.rs | 0 .../{ => compiler-builtins}/src/float/div.rs | 0 .../src/float/extend.rs | 0 .../{ => compiler-builtins}/src/float/mod.rs | 0 .../{ => compiler-builtins}/src/float/mul.rs | 0 .../{ => compiler-builtins}/src/float/pow.rs | 0 .../{ => compiler-builtins}/src/float/sub.rs | 0 .../src/float/traits.rs | 0 .../src/float/trunc.rs | 0 .../{ => compiler-builtins}/src/hexagon.rs | 0 .../src/hexagon/dfaddsub.s | 0 .../src/hexagon/dfdiv.s | 0 .../src/hexagon/dffma.s | 0 .../src/hexagon/dfminmax.s | 0 .../src/hexagon/dfmul.s | 0 .../src/hexagon/dfsqrt.s | 0 .../src/hexagon/divdi3.s | 0 .../src/hexagon/divsi3.s | 0 .../src/hexagon/fastmath2_dlib_asm.s | 0 .../src/hexagon/fastmath2_ldlib_asm.s | 0 .../src/hexagon/func_macro.s | 0 .../src/hexagon/memcpy_forward_vp4cp4n2.s | 0 .../src/hexagon/memcpy_likely_aligned.s | 0 .../src/hexagon/moddi3.s | 0 .../src/hexagon/modsi3.s | 0 .../src/hexagon/sfdiv_opt.s | 0 .../src/hexagon/sfsqrt_opt.s | 0 .../src/hexagon/udivdi3.s | 0 .../src/hexagon/udivmoddi4.s | 0 .../src/hexagon/udivmodsi4.s | 0 .../src/hexagon/udivsi3.s | 0 .../src/hexagon/umoddi3.s | 0 .../src/hexagon/umodsi3.s | 0 .../{ => compiler-builtins}/src/int/addsub.rs | 0 .../{ => compiler-builtins}/src/int/big.rs | 0 .../{ => compiler-builtins}/src/int/bswap.rs | 0 .../src/int/leading_zeros.rs | 0 .../{ => compiler-builtins}/src/int/mod.rs | 0 .../{ => compiler-builtins}/src/int/mul.rs | 0 .../{ => compiler-builtins}/src/int/sdiv.rs | 0 .../{ => compiler-builtins}/src/int/shift.rs | 0 .../src/int/specialized_div_rem/asymmetric.rs | 0 .../int/specialized_div_rem/binary_long.rs | 0 .../src/int/specialized_div_rem/delegate.rs | 0 .../src/int/specialized_div_rem/mod.rs | 0 .../src/int/specialized_div_rem/norm_shift.rs | 0 .../src/int/specialized_div_rem/trifecta.rs | 0 .../src/int/trailing_zeros.rs | 0 .../{ => compiler-builtins}/src/int/traits.rs | 0 .../{ => compiler-builtins}/src/int/udiv.rs | 0 .../{ => compiler-builtins}/src/lib.miri.rs | 0 .../{ => compiler-builtins}/src/lib.rs | 3 +- .../{ => compiler-builtins}/src/macros.rs | 0 .../{ => compiler-builtins}/src/math.rs | 0 .../{ => compiler-builtins}/src/mem/impls.rs | 0 .../{ => compiler-builtins}/src/mem/mod.rs | 0 .../{ => compiler-builtins}/src/mem/x86_64.rs | 0 .../{ => compiler-builtins}/src/probestack.rs | 0 .../{ => compiler-builtins}/src/riscv.rs | 0 .../{ => compiler-builtins}/src/x86.rs | 0 .../{ => compiler-builtins}/src/x86_64.rs | 0 .../crates/panic-handler/Cargo.toml | 4 + .../compiler-builtins/testcrate/Cargo.toml | 2 +- library/compiler-builtins/testcrate/build.rs | 2 +- 82 files changed, 95 insertions(+), 91 deletions(-) create mode 100644 library/compiler-builtins/compiler-builtins/Cargo.toml rename library/compiler-builtins/{ => compiler-builtins}/build.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/configure.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/libm (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/aarch64.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/aarch64_linux.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/arm.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/arm_linux.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/float/add.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/float/cmp.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/float/conv.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/float/div.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/float/extend.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/float/mod.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/float/mul.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/float/pow.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/float/sub.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/float/traits.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/float/trunc.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/hexagon.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/hexagon/dfaddsub.s (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/hexagon/dfdiv.s (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/hexagon/dffma.s (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/hexagon/dfminmax.s (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/hexagon/dfmul.s (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/hexagon/dfsqrt.s (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/hexagon/divdi3.s (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/hexagon/divsi3.s (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/hexagon/fastmath2_dlib_asm.s (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/hexagon/fastmath2_ldlib_asm.s (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/hexagon/func_macro.s (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/hexagon/memcpy_forward_vp4cp4n2.s (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/hexagon/memcpy_likely_aligned.s (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/hexagon/moddi3.s (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/hexagon/modsi3.s (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/hexagon/sfdiv_opt.s (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/hexagon/sfsqrt_opt.s (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/hexagon/udivdi3.s (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/hexagon/udivmoddi4.s (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/hexagon/udivmodsi4.s (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/hexagon/udivsi3.s (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/hexagon/umoddi3.s (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/hexagon/umodsi3.s (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/int/addsub.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/int/big.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/int/bswap.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/int/leading_zeros.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/int/mod.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/int/mul.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/int/sdiv.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/int/shift.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/int/specialized_div_rem/asymmetric.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/int/specialized_div_rem/binary_long.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/int/specialized_div_rem/delegate.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/int/specialized_div_rem/mod.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/int/specialized_div_rem/norm_shift.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/int/specialized_div_rem/trifecta.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/int/trailing_zeros.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/int/traits.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/int/udiv.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/lib.miri.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/lib.rs (96%) rename library/compiler-builtins/{ => compiler-builtins}/src/macros.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/math.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/mem/impls.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/mem/mod.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/mem/x86_64.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/probestack.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/riscv.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/x86.rs (100%) rename library/compiler-builtins/{ => compiler-builtins}/src/x86_64.rs (100%) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index 50844a66c43a9..c337c26a272bd 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -4,7 +4,6 @@ on: [push, pull_request] env: RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings - RUST_COMPILER_RT_ROOT: ./compiler-rt jobs: test: @@ -133,6 +132,8 @@ jobs: if: steps.cache-compiler-rt.outputs.cache-hit != 'true' run: ./ci/download-compiler-rt.sh shell: bash + - run: echo "RUST_COMPILER_RT_ROOT=$(realpath ./compiler-rt)" >> "$GITHUB_ENV" + shell: bash # Non-linux tests just use our raw script - run: ./ci/run.sh ${{ matrix.target }} diff --git a/library/compiler-builtins/.github/workflows/publish.yml b/library/compiler-builtins/.github/workflows/publish.yml index d568f37573870..7d6a8df030538 100644 --- a/library/compiler-builtins/.github/workflows/publish.yml +++ b/library/compiler-builtins/.github/workflows/publish.yml @@ -22,7 +22,7 @@ jobs: - name: Install Rust (rustup) run: rustup update nightly --no-self-update && rustup default nightly - name: Publish `libm` as part of builtins, rather than its own crate - run: rm libm/Cargo.toml + run: rm compiler-builtins/libm/Cargo.toml - name: Run release-plz uses: MarcoIeni/release-plz-action@v0.5 env: diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index 726b1c5c67c99..a0b0d021deae8 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -1,3 +1,3 @@ -[submodule "libm"] - path = libm +[submodule "compiler-builtins/libm"] + path = compiler-builtins/libm url = https://github.com/rust-lang/libm.git diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 60de27758d8e3..db4c45dfa4b29 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,88 +1,16 @@ -[package] -authors = ["Jorge Aparicio "] -name = "compiler_builtins" -version = "0.1.151" -license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" -readme = "README.md" -repository = "https://github.com/rust-lang/compiler-builtins" -homepage = "https://github.com/rust-lang/compiler-builtins" -documentation = "https://docs.rs/compiler_builtins" -edition = "2021" -description = """ -Compiler intrinsics used by the Rust compiler. Also available for other targets -if necessary! -""" -include = [ - '/Cargo.toml', - '/build.rs', - '/configure.rs', - '/src/*', - '/examples/*', - '/LICENSE.txt', - '/README.md', - '/compiler-rt/*', - '/libm/src/math/*', -] -links = 'compiler-rt' - -[lib] -test = false - -[dependencies] -# For more information on this dependency see -# https://github.com/rust-lang/rust/tree/master/library/rustc-std-workspace-core -core = { version = "1.0.0", optional = true, package = 'rustc-std-workspace-core' } - -[build-dependencies] -cc = { optional = true, version = "1.0" } - -[dev-dependencies] -panic-handler = { path = 'crates/panic-handler' } - -[features] -default = ["compiler-builtins"] - -# Enable compilation of C code in compiler-rt, filling in some more optimized -# implementations and also filling in unimplemented intrinsics -c = ["cc"] - -# Workaround for the Cranelift codegen backend. Disables any implementations -# which use inline assembly and fall back to pure Rust versions (if avalible). -no-asm = [] - -# Workaround for codegen backends which haven't yet implemented `f16` and -# `f128` support. Disabled any intrinsics which use those types. -no-f16-f128 = [] - -# Flag this library as the unstable compiler-builtins lib -compiler-builtins = [] - -# 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 = [] - -# Only used in the compiler's build system -rustc-dep-of-std = ['compiler-builtins', 'core'] - -# This makes certain traits and function specializations public that -# are not normally public but are required by the `testcrate` -public-test-deps = [] - [workspace] -resolver = "2" +resolver = "3" members = [ - # Note that builtins-test-intrinsics cannot be a default member because it + # Note that builtins-test-intrinsics cannot be a default member because it # needs the `mangled-names` feature disabled, while `testcrate` needs it # enabled. "builtins-test-intrinsics", + "compiler-builtins", "testcrate", ] default-members = [ - ".", + "compiler-builtins", "testcrate", ] diff --git a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml index 9b2e5bb7c8a6f..9dbd3c32f969f 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml +++ b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [dependencies] -compiler_builtins = { path = "../", features = ["compiler-builtins"]} +compiler_builtins = { path = "../compiler-builtins", features = ["compiler-builtins"]} panic-handler = { path = '../crates/panic-handler' } [features] diff --git a/library/compiler-builtins/builtins-test-intrinsics/build.rs b/library/compiler-builtins/builtins-test-intrinsics/build.rs index a38c6c1ff71ca..89b126ff2b2ed 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/build.rs +++ b/library/compiler-builtins/builtins-test-intrinsics/build.rs @@ -1,5 +1,5 @@ mod builtins_configure { - include!("../configure.rs"); + include!("../compiler-builtins/configure.rs"); } fn main() { diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 215ad71a3c165..5e19cf4d0cbe8 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -38,7 +38,7 @@ run() { fi if [ -d compiler-rt ]; then - export RUST_COMPILER_RT_ROOT=./compiler-rt + export RUST_COMPILER_RT_ROOT="/checkout/compiler-rt" fi if [ "${GITHUB_ACTIONS:-}" = "true" ]; then diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 3625dde79ed55..9abbf25a7e7a2 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -23,7 +23,7 @@ fi if [ "${NO_STD:-}" = "1" ]; then echo "nothing to do for no_std" else - run="cargo test --manifest-path testcrate/Cargo.toml --no-fail-fast --target $target" + run="cargo test --package testcrate --no-fail-fast --target $target" $run $run --release $run --features c @@ -38,7 +38,7 @@ fi if [ "${TEST_VERBATIM:-}" = "1" ]; then verb_path=$(cmd.exe //C echo \\\\?\\%cd%\\testcrate\\target2) - cargo build --manifest-path testcrate/Cargo.toml \ + cargo build --package testcrate \ --target "$target" --target-dir "$verb_path" --features c fi diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml new file mode 100644 index 0000000000000..9797b5e65b5a8 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -0,0 +1,72 @@ +[package] +authors = ["Jorge Aparicio "] +name = "compiler_builtins" +version = "0.1.151" +license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" +readme = "../README.md" +repository = "https://github.com/rust-lang/compiler-builtins" +homepage = "https://github.com/rust-lang/compiler-builtins" +documentation = "https://docs.rs/compiler_builtins" +edition = "2021" +description = """ +Compiler intrinsics used by the Rust compiler. Also available for other targets +if necessary! +""" +include = [ + '/Cargo.toml', + '/build.rs', + '/configure.rs', + '/src/*', + '../LICENSE.txt', + '../README.md', + '../compiler-rt/*', + 'libm/src/math/*', +] +links = 'compiler-rt' + +[lib] +test = false +bench = false + +[dependencies] +# For more information on this dependency see +# https://github.com/rust-lang/rust/tree/master/library/rustc-std-workspace-core +core = { version = "1.0.0", optional = true, package = 'rustc-std-workspace-core' } + +[build-dependencies] +cc = { optional = true, version = "1.0" } + +[dev-dependencies] +panic-handler = { path = '../crates/panic-handler' } + +[features] +default = ["compiler-builtins"] + +# Enable compilation of C code in compiler-rt, filling in some more optimized +# implementations and also filling in unimplemented intrinsics +c = ["cc"] + +# Workaround for the Cranelift codegen backend. Disables any implementations +# which use inline assembly and fall back to pure Rust versions (if avalible). +no-asm = [] + +# Workaround for codegen backends which haven't yet implemented `f16` and +# `f128` support. Disabled any intrinsics which use those types. +no-f16-f128 = [] + +# Flag this library as the unstable compiler-builtins lib +compiler-builtins = [] + +# 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 = [] + +# Only used in the compiler's build system +rustc-dep-of-std = ['compiler-builtins', 'core'] + +# This makes certain traits and function specializations public that +# are not normally public but are required by the `testcrate` +public-test-deps = [] diff --git a/library/compiler-builtins/build.rs b/library/compiler-builtins/compiler-builtins/build.rs similarity index 100% rename from library/compiler-builtins/build.rs rename to library/compiler-builtins/compiler-builtins/build.rs index 3003d51aff859..fdfb61b17df7c 100644 --- a/library/compiler-builtins/build.rs +++ b/library/compiler-builtins/compiler-builtins/build.rs @@ -1,7 +1,7 @@ -use std::{collections::BTreeMap, env, path::PathBuf, sync::atomic::Ordering}; - mod configure; +use std::{collections::BTreeMap, env, path::PathBuf, sync::atomic::Ordering}; + use configure::{configure_aliases, configure_f16_f128, Target}; fn main() { diff --git a/library/compiler-builtins/configure.rs b/library/compiler-builtins/compiler-builtins/configure.rs similarity index 100% rename from library/compiler-builtins/configure.rs rename to library/compiler-builtins/compiler-builtins/configure.rs diff --git a/library/compiler-builtins/libm b/library/compiler-builtins/compiler-builtins/libm similarity index 100% rename from library/compiler-builtins/libm rename to library/compiler-builtins/compiler-builtins/libm diff --git a/library/compiler-builtins/src/aarch64.rs b/library/compiler-builtins/compiler-builtins/src/aarch64.rs similarity index 100% rename from library/compiler-builtins/src/aarch64.rs rename to library/compiler-builtins/compiler-builtins/src/aarch64.rs diff --git a/library/compiler-builtins/src/aarch64_linux.rs b/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs similarity index 100% rename from library/compiler-builtins/src/aarch64_linux.rs rename to library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs diff --git a/library/compiler-builtins/src/arm.rs b/library/compiler-builtins/compiler-builtins/src/arm.rs similarity index 100% rename from library/compiler-builtins/src/arm.rs rename to library/compiler-builtins/compiler-builtins/src/arm.rs diff --git a/library/compiler-builtins/src/arm_linux.rs b/library/compiler-builtins/compiler-builtins/src/arm_linux.rs similarity index 100% rename from library/compiler-builtins/src/arm_linux.rs rename to library/compiler-builtins/compiler-builtins/src/arm_linux.rs diff --git a/library/compiler-builtins/src/float/add.rs b/library/compiler-builtins/compiler-builtins/src/float/add.rs similarity index 100% rename from library/compiler-builtins/src/float/add.rs rename to library/compiler-builtins/compiler-builtins/src/float/add.rs diff --git a/library/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs similarity index 100% rename from library/compiler-builtins/src/float/cmp.rs rename to library/compiler-builtins/compiler-builtins/src/float/cmp.rs diff --git a/library/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/compiler-builtins/src/float/conv.rs similarity index 100% rename from library/compiler-builtins/src/float/conv.rs rename to library/compiler-builtins/compiler-builtins/src/float/conv.rs diff --git a/library/compiler-builtins/src/float/div.rs b/library/compiler-builtins/compiler-builtins/src/float/div.rs similarity index 100% rename from library/compiler-builtins/src/float/div.rs rename to library/compiler-builtins/compiler-builtins/src/float/div.rs diff --git a/library/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/compiler-builtins/src/float/extend.rs similarity index 100% rename from library/compiler-builtins/src/float/extend.rs rename to library/compiler-builtins/compiler-builtins/src/float/extend.rs diff --git a/library/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/compiler-builtins/src/float/mod.rs similarity index 100% rename from library/compiler-builtins/src/float/mod.rs rename to library/compiler-builtins/compiler-builtins/src/float/mod.rs diff --git a/library/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/compiler-builtins/src/float/mul.rs similarity index 100% rename from library/compiler-builtins/src/float/mul.rs rename to library/compiler-builtins/compiler-builtins/src/float/mul.rs diff --git a/library/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/compiler-builtins/src/float/pow.rs similarity index 100% rename from library/compiler-builtins/src/float/pow.rs rename to library/compiler-builtins/compiler-builtins/src/float/pow.rs diff --git a/library/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/compiler-builtins/src/float/sub.rs similarity index 100% rename from library/compiler-builtins/src/float/sub.rs rename to library/compiler-builtins/compiler-builtins/src/float/sub.rs diff --git a/library/compiler-builtins/src/float/traits.rs b/library/compiler-builtins/compiler-builtins/src/float/traits.rs similarity index 100% rename from library/compiler-builtins/src/float/traits.rs rename to library/compiler-builtins/compiler-builtins/src/float/traits.rs diff --git a/library/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/compiler-builtins/src/float/trunc.rs similarity index 100% rename from library/compiler-builtins/src/float/trunc.rs rename to library/compiler-builtins/compiler-builtins/src/float/trunc.rs diff --git a/library/compiler-builtins/src/hexagon.rs b/library/compiler-builtins/compiler-builtins/src/hexagon.rs similarity index 100% rename from library/compiler-builtins/src/hexagon.rs rename to library/compiler-builtins/compiler-builtins/src/hexagon.rs diff --git a/library/compiler-builtins/src/hexagon/dfaddsub.s b/library/compiler-builtins/compiler-builtins/src/hexagon/dfaddsub.s similarity index 100% rename from library/compiler-builtins/src/hexagon/dfaddsub.s rename to library/compiler-builtins/compiler-builtins/src/hexagon/dfaddsub.s diff --git a/library/compiler-builtins/src/hexagon/dfdiv.s b/library/compiler-builtins/compiler-builtins/src/hexagon/dfdiv.s similarity index 100% rename from library/compiler-builtins/src/hexagon/dfdiv.s rename to library/compiler-builtins/compiler-builtins/src/hexagon/dfdiv.s diff --git a/library/compiler-builtins/src/hexagon/dffma.s b/library/compiler-builtins/compiler-builtins/src/hexagon/dffma.s similarity index 100% rename from library/compiler-builtins/src/hexagon/dffma.s rename to library/compiler-builtins/compiler-builtins/src/hexagon/dffma.s diff --git a/library/compiler-builtins/src/hexagon/dfminmax.s b/library/compiler-builtins/compiler-builtins/src/hexagon/dfminmax.s similarity index 100% rename from library/compiler-builtins/src/hexagon/dfminmax.s rename to library/compiler-builtins/compiler-builtins/src/hexagon/dfminmax.s diff --git a/library/compiler-builtins/src/hexagon/dfmul.s b/library/compiler-builtins/compiler-builtins/src/hexagon/dfmul.s similarity index 100% rename from library/compiler-builtins/src/hexagon/dfmul.s rename to library/compiler-builtins/compiler-builtins/src/hexagon/dfmul.s diff --git a/library/compiler-builtins/src/hexagon/dfsqrt.s b/library/compiler-builtins/compiler-builtins/src/hexagon/dfsqrt.s similarity index 100% rename from library/compiler-builtins/src/hexagon/dfsqrt.s rename to library/compiler-builtins/compiler-builtins/src/hexagon/dfsqrt.s diff --git a/library/compiler-builtins/src/hexagon/divdi3.s b/library/compiler-builtins/compiler-builtins/src/hexagon/divdi3.s similarity index 100% rename from library/compiler-builtins/src/hexagon/divdi3.s rename to library/compiler-builtins/compiler-builtins/src/hexagon/divdi3.s diff --git a/library/compiler-builtins/src/hexagon/divsi3.s b/library/compiler-builtins/compiler-builtins/src/hexagon/divsi3.s similarity index 100% rename from library/compiler-builtins/src/hexagon/divsi3.s rename to library/compiler-builtins/compiler-builtins/src/hexagon/divsi3.s diff --git a/library/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s b/library/compiler-builtins/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s similarity index 100% rename from library/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s rename to library/compiler-builtins/compiler-builtins/src/hexagon/fastmath2_dlib_asm.s diff --git a/library/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s b/library/compiler-builtins/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s similarity index 100% rename from library/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s rename to library/compiler-builtins/compiler-builtins/src/hexagon/fastmath2_ldlib_asm.s diff --git a/library/compiler-builtins/src/hexagon/func_macro.s b/library/compiler-builtins/compiler-builtins/src/hexagon/func_macro.s similarity index 100% rename from library/compiler-builtins/src/hexagon/func_macro.s rename to library/compiler-builtins/compiler-builtins/src/hexagon/func_macro.s diff --git a/library/compiler-builtins/src/hexagon/memcpy_forward_vp4cp4n2.s b/library/compiler-builtins/compiler-builtins/src/hexagon/memcpy_forward_vp4cp4n2.s similarity index 100% rename from library/compiler-builtins/src/hexagon/memcpy_forward_vp4cp4n2.s rename to library/compiler-builtins/compiler-builtins/src/hexagon/memcpy_forward_vp4cp4n2.s diff --git a/library/compiler-builtins/src/hexagon/memcpy_likely_aligned.s b/library/compiler-builtins/compiler-builtins/src/hexagon/memcpy_likely_aligned.s similarity index 100% rename from library/compiler-builtins/src/hexagon/memcpy_likely_aligned.s rename to library/compiler-builtins/compiler-builtins/src/hexagon/memcpy_likely_aligned.s diff --git a/library/compiler-builtins/src/hexagon/moddi3.s b/library/compiler-builtins/compiler-builtins/src/hexagon/moddi3.s similarity index 100% rename from library/compiler-builtins/src/hexagon/moddi3.s rename to library/compiler-builtins/compiler-builtins/src/hexagon/moddi3.s diff --git a/library/compiler-builtins/src/hexagon/modsi3.s b/library/compiler-builtins/compiler-builtins/src/hexagon/modsi3.s similarity index 100% rename from library/compiler-builtins/src/hexagon/modsi3.s rename to library/compiler-builtins/compiler-builtins/src/hexagon/modsi3.s diff --git a/library/compiler-builtins/src/hexagon/sfdiv_opt.s b/library/compiler-builtins/compiler-builtins/src/hexagon/sfdiv_opt.s similarity index 100% rename from library/compiler-builtins/src/hexagon/sfdiv_opt.s rename to library/compiler-builtins/compiler-builtins/src/hexagon/sfdiv_opt.s diff --git a/library/compiler-builtins/src/hexagon/sfsqrt_opt.s b/library/compiler-builtins/compiler-builtins/src/hexagon/sfsqrt_opt.s similarity index 100% rename from library/compiler-builtins/src/hexagon/sfsqrt_opt.s rename to library/compiler-builtins/compiler-builtins/src/hexagon/sfsqrt_opt.s diff --git a/library/compiler-builtins/src/hexagon/udivdi3.s b/library/compiler-builtins/compiler-builtins/src/hexagon/udivdi3.s similarity index 100% rename from library/compiler-builtins/src/hexagon/udivdi3.s rename to library/compiler-builtins/compiler-builtins/src/hexagon/udivdi3.s diff --git a/library/compiler-builtins/src/hexagon/udivmoddi4.s b/library/compiler-builtins/compiler-builtins/src/hexagon/udivmoddi4.s similarity index 100% rename from library/compiler-builtins/src/hexagon/udivmoddi4.s rename to library/compiler-builtins/compiler-builtins/src/hexagon/udivmoddi4.s diff --git a/library/compiler-builtins/src/hexagon/udivmodsi4.s b/library/compiler-builtins/compiler-builtins/src/hexagon/udivmodsi4.s similarity index 100% rename from library/compiler-builtins/src/hexagon/udivmodsi4.s rename to library/compiler-builtins/compiler-builtins/src/hexagon/udivmodsi4.s diff --git a/library/compiler-builtins/src/hexagon/udivsi3.s b/library/compiler-builtins/compiler-builtins/src/hexagon/udivsi3.s similarity index 100% rename from library/compiler-builtins/src/hexagon/udivsi3.s rename to library/compiler-builtins/compiler-builtins/src/hexagon/udivsi3.s diff --git a/library/compiler-builtins/src/hexagon/umoddi3.s b/library/compiler-builtins/compiler-builtins/src/hexagon/umoddi3.s similarity index 100% rename from library/compiler-builtins/src/hexagon/umoddi3.s rename to library/compiler-builtins/compiler-builtins/src/hexagon/umoddi3.s diff --git a/library/compiler-builtins/src/hexagon/umodsi3.s b/library/compiler-builtins/compiler-builtins/src/hexagon/umodsi3.s similarity index 100% rename from library/compiler-builtins/src/hexagon/umodsi3.s rename to library/compiler-builtins/compiler-builtins/src/hexagon/umodsi3.s diff --git a/library/compiler-builtins/src/int/addsub.rs b/library/compiler-builtins/compiler-builtins/src/int/addsub.rs similarity index 100% rename from library/compiler-builtins/src/int/addsub.rs rename to library/compiler-builtins/compiler-builtins/src/int/addsub.rs diff --git a/library/compiler-builtins/src/int/big.rs b/library/compiler-builtins/compiler-builtins/src/int/big.rs similarity index 100% rename from library/compiler-builtins/src/int/big.rs rename to library/compiler-builtins/compiler-builtins/src/int/big.rs diff --git a/library/compiler-builtins/src/int/bswap.rs b/library/compiler-builtins/compiler-builtins/src/int/bswap.rs similarity index 100% rename from library/compiler-builtins/src/int/bswap.rs rename to library/compiler-builtins/compiler-builtins/src/int/bswap.rs diff --git a/library/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs similarity index 100% rename from library/compiler-builtins/src/int/leading_zeros.rs rename to library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs diff --git a/library/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/compiler-builtins/src/int/mod.rs similarity index 100% rename from library/compiler-builtins/src/int/mod.rs rename to library/compiler-builtins/compiler-builtins/src/int/mod.rs diff --git a/library/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/compiler-builtins/src/int/mul.rs similarity index 100% rename from library/compiler-builtins/src/int/mul.rs rename to library/compiler-builtins/compiler-builtins/src/int/mul.rs diff --git a/library/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/compiler-builtins/src/int/sdiv.rs similarity index 100% rename from library/compiler-builtins/src/int/sdiv.rs rename to library/compiler-builtins/compiler-builtins/src/int/sdiv.rs diff --git a/library/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/compiler-builtins/src/int/shift.rs similarity index 100% rename from library/compiler-builtins/src/int/shift.rs rename to library/compiler-builtins/compiler-builtins/src/int/shift.rs diff --git a/library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs similarity index 100% rename from library/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs rename to library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/asymmetric.rs diff --git a/library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/binary_long.rs similarity index 100% rename from library/compiler-builtins/src/int/specialized_div_rem/binary_long.rs rename to library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/binary_long.rs diff --git a/library/compiler-builtins/src/int/specialized_div_rem/delegate.rs b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/delegate.rs similarity index 100% rename from library/compiler-builtins/src/int/specialized_div_rem/delegate.rs rename to library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/delegate.rs diff --git a/library/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs similarity index 100% rename from library/compiler-builtins/src/int/specialized_div_rem/mod.rs rename to library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs diff --git a/library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs similarity index 100% rename from library/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs rename to library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/norm_shift.rs diff --git a/library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/trifecta.rs similarity index 100% rename from library/compiler-builtins/src/int/specialized_div_rem/trifecta.rs rename to library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/trifecta.rs diff --git a/library/compiler-builtins/src/int/trailing_zeros.rs b/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs similarity index 100% rename from library/compiler-builtins/src/int/trailing_zeros.rs rename to library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs diff --git a/library/compiler-builtins/src/int/traits.rs b/library/compiler-builtins/compiler-builtins/src/int/traits.rs similarity index 100% rename from library/compiler-builtins/src/int/traits.rs rename to library/compiler-builtins/compiler-builtins/src/int/traits.rs diff --git a/library/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/compiler-builtins/src/int/udiv.rs similarity index 100% rename from library/compiler-builtins/src/int/udiv.rs rename to library/compiler-builtins/compiler-builtins/src/int/udiv.rs diff --git a/library/compiler-builtins/src/lib.miri.rs b/library/compiler-builtins/compiler-builtins/src/lib.miri.rs similarity index 100% rename from library/compiler-builtins/src/lib.miri.rs rename to library/compiler-builtins/compiler-builtins/src/lib.miri.rs diff --git a/library/compiler-builtins/src/lib.rs b/library/compiler-builtins/compiler-builtins/src/lib.rs similarity index 96% rename from library/compiler-builtins/src/lib.rs rename to library/compiler-builtins/compiler-builtins/src/lib.rs index 6f5bd85981e87..16de96b4da07a 100644 --- a/library/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/compiler-builtins/src/lib.rs @@ -44,8 +44,7 @@ pub mod int; pub mod math; pub mod mem; -// `libm` expects its `support` module to be available in the crate root. This config can be -// cleaned up once `libm` is made always available. +// `libm` expects its `support` module to be available in the crate root. use math::libm::support; #[cfg(target_arch = "arm")] diff --git a/library/compiler-builtins/src/macros.rs b/library/compiler-builtins/compiler-builtins/src/macros.rs similarity index 100% rename from library/compiler-builtins/src/macros.rs rename to library/compiler-builtins/compiler-builtins/src/macros.rs diff --git a/library/compiler-builtins/src/math.rs b/library/compiler-builtins/compiler-builtins/src/math.rs similarity index 100% rename from library/compiler-builtins/src/math.rs rename to library/compiler-builtins/compiler-builtins/src/math.rs diff --git a/library/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/compiler-builtins/src/mem/impls.rs similarity index 100% rename from library/compiler-builtins/src/mem/impls.rs rename to library/compiler-builtins/compiler-builtins/src/mem/impls.rs diff --git a/library/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/compiler-builtins/src/mem/mod.rs similarity index 100% rename from library/compiler-builtins/src/mem/mod.rs rename to library/compiler-builtins/compiler-builtins/src/mem/mod.rs diff --git a/library/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs similarity index 100% rename from library/compiler-builtins/src/mem/x86_64.rs rename to library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs diff --git a/library/compiler-builtins/src/probestack.rs b/library/compiler-builtins/compiler-builtins/src/probestack.rs similarity index 100% rename from library/compiler-builtins/src/probestack.rs rename to library/compiler-builtins/compiler-builtins/src/probestack.rs diff --git a/library/compiler-builtins/src/riscv.rs b/library/compiler-builtins/compiler-builtins/src/riscv.rs similarity index 100% rename from library/compiler-builtins/src/riscv.rs rename to library/compiler-builtins/compiler-builtins/src/riscv.rs diff --git a/library/compiler-builtins/src/x86.rs b/library/compiler-builtins/compiler-builtins/src/x86.rs similarity index 100% rename from library/compiler-builtins/src/x86.rs rename to library/compiler-builtins/compiler-builtins/src/x86.rs diff --git a/library/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/compiler-builtins/src/x86_64.rs similarity index 100% rename from library/compiler-builtins/src/x86_64.rs rename to library/compiler-builtins/compiler-builtins/src/x86_64.rs diff --git a/library/compiler-builtins/crates/panic-handler/Cargo.toml b/library/compiler-builtins/crates/panic-handler/Cargo.toml index 96b83eaa2265a..a6764fc481b64 100644 --- a/library/compiler-builtins/crates/panic-handler/Cargo.toml +++ b/library/compiler-builtins/crates/panic-handler/Cargo.toml @@ -5,4 +5,8 @@ authors = ["Alex Crichton "] edition = "2024" publish = false +[lib] +test = false +bench = false + [dependencies] diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index 71c461c578c23..be60e694fa938 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -18,7 +18,7 @@ rand_xoshiro = "0.6" rustc_apfloat = "0.2.1" [dependencies.compiler_builtins] -path = ".." +path = "../compiler-builtins" default-features = false features = ["public-test-deps"] diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/testcrate/build.rs index 566b985d24627..e8f4eb4dd22eb 100644 --- a/library/compiler-builtins/testcrate/build.rs +++ b/library/compiler-builtins/testcrate/build.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; mod builtins_configure { - include!("../configure.rs"); + include!("../compiler-builtins/configure.rs"); } /// Features to enable From fc1b87da4a8ebe90f9203b6b8b2ac1c9d857edd9 Mon Sep 17 00:00:00 2001 From: beetrees Date: Wed, 12 Mar 2025 18:02:51 +0000 Subject: [PATCH 1747/4206] Remove use of `atomic_load_unordered` and undefined behaviour from `arm_linux.rs` --- .../compiler-builtins/src/arm_linux.rs | 47 +++++++++++++++++-- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/src/arm_linux.rs b/library/compiler-builtins/compiler-builtins/src/arm_linux.rs index 8f22eb6286600..aeb3ff3e50693 100644 --- a/library/compiler-builtins/compiler-builtins/src/arm_linux.rs +++ b/library/compiler-builtins/compiler-builtins/src/arm_linux.rs @@ -1,5 +1,6 @@ -use core::intrinsics; +use core::arch; use core::mem; +use core::sync::atomic::{AtomicU32, Ordering}; // Kernel-provided user-mode helper functions: // https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt @@ -7,6 +8,7 @@ unsafe fn __kuser_cmpxchg(oldval: u32, newval: u32, ptr: *mut u32) -> bool { let f: extern "C" fn(u32, u32, *mut u32) -> u32 = mem::transmute(0xffff0fc0usize as *const ()); f(oldval, newval, ptr) == 0 } + unsafe fn __kuser_memory_barrier() { let f: extern "C" fn() = mem::transmute(0xffff0fa0usize as *const ()); f(); @@ -54,13 +56,52 @@ fn insert_aligned(aligned: u32, val: u32, shift: u32, mask: u32) -> u32 { (aligned & !(mask << shift)) | ((val & mask) << shift) } +/// Performs a relaxed atomic load of 4 bytes at `ptr`. Some of the bytes are allowed to be out of +/// bounds as long as `size_of::()` bytes are in bounds. +/// +/// # Safety +/// +/// - `ptr` must be 4-aligned. +/// - `size_of::()` must be at most 4. +/// - if `size_of::() == 1`, `ptr` or `ptr` offset by 1, 2 or 3 bytes must be valid for a relaxed +/// atomic read of 1 byte. +/// - if `size_of::() == 2`, `ptr` or `ptr` offset by 2 bytes must be valid for a relaxed atomic +/// read of 2 bytes. +/// - if `size_of::() == 4`, `ptr` must be valid for a relaxed atomic read of 4 bytes. +unsafe fn atomic_load_aligned(ptr: *mut u32) -> u32 { + if mem::size_of::() == 4 { + // SAFETY: As `T` has a size of 4, the caller garantees this is sound. + unsafe { AtomicU32::from_ptr(ptr).load(Ordering::Relaxed) } + } else { + // SAFETY: + // As all 4 bytes pointed to by `ptr` might not be dereferenceable due to being out of + // bounds when doing atomic operations on a `u8`/`i8`/`u16`/`i16`, inline ASM is used to + // avoid causing undefined behaviour. However, as `ptr` is 4-aligned and at least 1 byte of + // `ptr` is dereferencable, the load won't cause a segfault as the page size is always + // larger than 4 bytes. + // The `ldr` instruction does not touch the stack or flags, or write to memory, so + // `nostack`, `preserves_flags` and `readonly` are sound. The caller garantees that `ptr` is + // 4-aligned, as required by `ldr`. + unsafe { + let res: u32; + arch::asm!( + "ldr {res}, [{ptr}]", + ptr = in(reg) ptr, + res = lateout(reg) res, + options(nostack, preserves_flags, readonly) + ); + res + } + } +} + // Generic atomic read-modify-write operation unsafe fn atomic_rmw u32, G: Fn(u32, u32) -> u32>(ptr: *mut T, f: F, g: G) -> u32 { let aligned_ptr = align_ptr(ptr); let (shift, mask) = get_shift_mask(ptr); loop { - let curval_aligned = intrinsics::atomic_load_unordered(aligned_ptr); + let curval_aligned = atomic_load_aligned::(aligned_ptr); let curval = extract_aligned(curval_aligned, shift, mask); let newval = f(curval); let newval_aligned = insert_aligned(curval_aligned, newval, shift, mask); @@ -76,7 +117,7 @@ unsafe fn atomic_cmpxchg(ptr: *mut T, oldval: u32, newval: u32) -> u32 { let (shift, mask) = get_shift_mask(ptr); loop { - let curval_aligned = intrinsics::atomic_load_unordered(aligned_ptr); + let curval_aligned = atomic_load_aligned::(aligned_ptr); let curval = extract_aligned(curval_aligned, shift, mask); if curval != oldval { return curval; From a0d40f287acc5604d225fee0bb7b09b4817a5f80 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 20 Mar 2025 02:02:43 +0000 Subject: [PATCH 1748/4206] chore: release v0.1.152 --- .../compiler-builtins/CHANGELOG.md | 15 +++++++++++++++ .../compiler-builtins/Cargo.toml | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 library/compiler-builtins/compiler-builtins/CHANGELOG.md diff --git a/library/compiler-builtins/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/compiler-builtins/CHANGELOG.md new file mode 100644 index 0000000000000..987f87713072a --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/CHANGELOG.md @@ -0,0 +1,15 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.1.152](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.151...compiler_builtins-v0.1.152) - 2025-03-20 + +### Other + +- Remove use of `atomic_load_unordered` and undefined behaviour from `arm_linux.rs` +- Switch repository layout to use a virtual manifest diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index 9797b5e65b5a8..8de8bce6a120f 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.151" +version = "0.1.152" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "../README.md" repository = "https://github.com/rust-lang/compiler-builtins" From f0f9cfa46304b025f23a10cc1103b186669fdc01 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 20 Mar 2025 11:19:09 +0000 Subject: [PATCH 1749/4206] Add benchmarks using `iai-callgrind` This crate [1] makes it reasonably easy to get instruction count performance metrics that are stable enough to run in CI, and has worked out well since integrating it with `libm`. Add new benchmarks for `mem` functions using `iai-callgrind`, modeling them off of the existing benchmarks. [1]: https://github.com/iai-callgrind/iai-callgrind --- .../compiler-builtins/testcrate/Cargo.toml | 14 + .../testcrate/benches/mem_icount.rs | 474 ++++++++++++++++++ 2 files changed, 488 insertions(+) create mode 100644 library/compiler-builtins/testcrate/benches/mem_icount.rs diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/testcrate/Cargo.toml index be60e694fa938..bda2b641d6f8a 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/testcrate/Cargo.toml @@ -16,6 +16,8 @@ doctest = false rand_xoshiro = "0.6" # To compare float builtins against rustc_apfloat = "0.2.1" +# Really a dev dependency, but dev dependencies can't be optional +iai-callgrind = { version = "0.14.0", optional = true } [dependencies.compiler_builtins] path = "../compiler-builtins" @@ -47,9 +49,16 @@ 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 iai-callgrind and valgrind) +icount = ["dep:iai-callgrind"] + # Enable report generation without bringing in more dependencies by default benchmarking-reports = ["criterion/plotters", "criterion/html_reports"] +# NOTE: benchmarks must be run with `--no-default-features` or with +# `-p testcrate`, otherwise the default `compiler-builtins` feature of the +# `compiler_builtins` crate gets activated, resulting in linker errors. + [[bench]] name = "float_add" harness = false @@ -85,3 +94,8 @@ harness = false [[bench]] name = "float_pow" harness = false + +[[bench]] +name = "mem_icount" +harness = false +required-features = ["icount"] diff --git a/library/compiler-builtins/testcrate/benches/mem_icount.rs b/library/compiler-builtins/testcrate/benches/mem_icount.rs new file mode 100644 index 0000000000000..be3d13dffdfa7 --- /dev/null +++ b/library/compiler-builtins/testcrate/benches/mem_icount.rs @@ -0,0 +1,474 @@ +//! Benchmarks that use Callgrind (via `iai_callgrind`) to report instruction count metrics. This +//! is stable enough to be tested in CI. + +use std::hint::black_box; +use std::{ops, slice}; + +use compiler_builtins::mem::{memcmp, memcpy, memmove, memset}; +use iai_callgrind::{library_benchmark, library_benchmark_group, main}; + +const PAGE_SIZE: usize = 0x1000; + +#[derive(Clone)] +#[repr(C, align(0x1000))] +struct Page([u8; PAGE_SIZE]); + +/// A buffer that is page-aligned by default, with an optional offset to create a +/// misalignment. +struct AlignedSlice { + buf: Box<[Page]>, + len: usize, + offset: usize, +} + +impl AlignedSlice { + /// Allocate a slice aligned to ALIGN with at least `len` items, with `offset` from + /// page alignment. + fn new_zeroed(len: usize, offset: usize) -> Self { + assert!(offset < PAGE_SIZE); + let total_len = len + offset; + let items = (total_len / PAGE_SIZE) + if total_len % PAGE_SIZE > 0 { 1 } else { 0 }; + let buf = vec![Page([0u8; PAGE_SIZE]); items].into_boxed_slice(); + AlignedSlice { buf, len, offset } + } +} + +impl ops::Deref for AlignedSlice { + type Target = [u8]; + fn deref(&self) -> &Self::Target { + unsafe { slice::from_raw_parts(self.buf.as_ptr().cast::().add(self.offset), self.len) } + } +} + +impl ops::DerefMut for AlignedSlice { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { + slice::from_raw_parts_mut( + self.buf.as_mut_ptr().cast::().add(self.offset), + self.len, + ) + } + } +} + +mod mcpy { + use super::*; + + struct Cfg { + len: usize, + s_off: usize, + d_off: usize, + } + + fn setup(cfg: Cfg) -> (usize, AlignedSlice, AlignedSlice) { + let Cfg { len, s_off, d_off } = cfg; + println!("{len} bytes, {s_off} src offset, {d_off} dst offset"); + let mut src = AlignedSlice::new_zeroed(len, s_off); + let dst = AlignedSlice::new_zeroed(len, d_off); + src.fill(1); + (len, src, dst) + } + + #[library_benchmark] + #[benches::aligned( + args = [ + Cfg { len: 16, s_off: 0, d_off: 0 }, + Cfg { len: 16, s_off: 0, d_off: 0 }, + Cfg { len: 28, s_off: 0, d_off: 0 }, + Cfg { len: 32, s_off: 0, d_off: 0 }, + Cfg { len: 36, s_off: 0, d_off: 0 }, + Cfg { len: 60, s_off: 0, d_off: 0 }, + Cfg { len: 64, s_off: 0, d_off: 0 }, + Cfg { len: 68, s_off: 0, d_off: 0 }, + Cfg { len: 128, s_off: 0, d_off: 0 }, + Cfg { len: 256, s_off: 0, d_off: 0 }, + Cfg { len: 512, s_off: 0, d_off: 0 }, + Cfg { len: 1024, s_off: 0, d_off: 0 }, + Cfg { len: 4096, s_off: 0, d_off: 0 }, + Cfg { len: 1048576, s_off: 0, d_off: 0 }, + ], + setup = setup, + )] + #[benches::offset( + args = [ + Cfg { len: 16, s_off: 65, d_off: 65 }, + Cfg { len: 28, s_off: 65, d_off: 65 }, + Cfg { len: 32, s_off: 65, d_off: 65 }, + Cfg { len: 36, s_off: 65, d_off: 65 }, + Cfg { len: 60, s_off: 65, d_off: 65 }, + Cfg { len: 64, s_off: 65, d_off: 65 }, + Cfg { len: 68, s_off: 65, d_off: 65 }, + Cfg { len: 128, s_off: 65, d_off: 65 }, + Cfg { len: 256, s_off: 65, d_off: 65 }, + Cfg { len: 512, s_off: 65, d_off: 65 }, + Cfg { len: 1024, s_off: 65, d_off: 65 }, + Cfg { len: 4096, s_off: 65, d_off: 65 }, + Cfg { len: 1048576, s_off: 65, d_off: 65 }, + ], + setup = setup, + )] + #[benches::misaligned( + args = [ + Cfg { len: 16, s_off: 65, d_off: 66 }, + Cfg { len: 28, s_off: 65, d_off: 66 }, + Cfg { len: 32, s_off: 65, d_off: 66 }, + Cfg { len: 36, s_off: 65, d_off: 66 }, + Cfg { len: 60, s_off: 65, d_off: 66 }, + Cfg { len: 64, s_off: 65, d_off: 66 }, + Cfg { len: 68, s_off: 65, d_off: 66 }, + Cfg { len: 128, s_off: 65, d_off: 66 }, + Cfg { len: 256, s_off: 65, d_off: 66 }, + Cfg { len: 512, s_off: 65, d_off: 66 }, + Cfg { len: 1024, s_off: 65, d_off: 66 }, + Cfg { len: 4096, s_off: 65, d_off: 66 }, + Cfg { len: 1048576, s_off: 65, d_off: 66 }, + ], + setup = setup, + )] + fn bench((len, mut dst, src): (usize, AlignedSlice, AlignedSlice)) { + unsafe { + black_box(memcpy( + black_box(dst.as_mut_ptr()), + black_box(src.as_ptr()), + black_box(len), + )); + } + } + + library_benchmark_group!(name = memcpy; benchmarks = bench); +} + +mod mset { + use super::*; + + struct Cfg { + len: usize, + offset: usize, + } + + fn setup(Cfg { len, offset }: Cfg) -> (usize, AlignedSlice) { + println!("{len} bytes, {offset} offset"); + (len, AlignedSlice::new_zeroed(len, offset)) + } + + #[library_benchmark] + #[benches::aligned( + args = [ + Cfg { len: 16, offset: 0 }, + Cfg { len: 32, offset: 0 }, + Cfg { len: 64, offset: 0 }, + Cfg { len: 512, offset: 0 }, + Cfg { len: 4096, offset: 0 }, + Cfg { len: 1048576, offset: 0 }, + ], + setup = setup, + )] + #[benches::offset( + args = [ + Cfg { len: 16, offset: 65 }, + Cfg { len: 32, offset: 65 }, + Cfg { len: 64, offset: 65 }, + Cfg { len: 512, offset: 65 }, + Cfg { len: 4096, offset: 65 }, + Cfg { len: 1048576, offset: 65 }, + ], + setup = setup, + )] + fn bench((len, mut dst): (usize, AlignedSlice)) { + unsafe { + black_box(memset( + black_box(dst.as_mut_ptr()), + black_box(27), + black_box(len), + )); + } + } + + library_benchmark_group!(name = memset; benchmarks = bench); +} + +mod mcmp { + use super::*; + + struct Cfg { + len: usize, + s_off: usize, + d_off: usize, + } + + fn setup(cfg: Cfg) -> (usize, AlignedSlice, AlignedSlice) { + let Cfg { len, s_off, d_off } = cfg; + println!("{len} bytes, {s_off} src offset, {d_off} dst offset"); + let b1 = AlignedSlice::new_zeroed(len, s_off); + let mut b2 = AlignedSlice::new_zeroed(len, d_off); + b2[len - 1] = 1; + (len, b1, b2) + } + + #[library_benchmark] + #[benches::aligned( + args = [ + Cfg { len: 16, s_off: 0, d_off: 0 }, + Cfg { len: 32, s_off: 0, d_off: 0 }, + Cfg { len: 64, s_off: 0, d_off: 0 }, + Cfg { len: 512, s_off: 0, d_off: 0 }, + Cfg { len: 4096, s_off: 0, d_off: 0 }, + Cfg { len: 1048576, s_off: 0, d_off: 0 }, + ], + setup = setup + )] + #[benches::offset( + args = [ + Cfg { len: 16, s_off: 65, d_off: 65 }, + Cfg { len: 32, s_off: 65, d_off: 65 }, + Cfg { len: 64, s_off: 65, d_off: 65 }, + Cfg { len: 512, s_off: 65, d_off: 65 }, + Cfg { len: 4096, s_off: 65, d_off: 65 }, + Cfg { len: 1048576, s_off: 65, d_off: 65 }, + ], + setup = setup + )] + #[benches::misaligned( + args = [ + Cfg { len: 16, s_off: 65, d_off: 66 }, + Cfg { len: 32, s_off: 65, d_off: 66 }, + Cfg { len: 64, s_off: 65, d_off: 66 }, + Cfg { len: 512, s_off: 65, d_off: 66 }, + Cfg { len: 4096, s_off: 65, d_off: 66 }, + Cfg { len: 1048576, s_off: 65, d_off: 66 }, + ], + setup = setup + )] + fn bench((len, mut dst, src): (usize, AlignedSlice, AlignedSlice)) { + unsafe { + black_box(memcmp( + black_box(dst.as_mut_ptr()), + black_box(src.as_ptr()), + black_box(len), + )); + } + } + + library_benchmark_group!(name = memcmp; benchmarks = bench); +} + +mod mmove { + use super::*; + use Spread::{Large, Medium, Small}; + + struct Cfg { + len: usize, + spread: Spread, + off: usize, + } + + enum Spread { + /// `src` and `dst` are close. + Small, + /// `src` and `dst` are halfway offset in the buffer. + Medium, + /// `src` and `dst` only overlap by a single byte. + Large, + } + + fn calculate_spread(len: usize, spread: Spread) -> usize { + match spread { + Small => 1, + Medium => len / 2, + Large => len - 1, + } + } + + fn setup_forward(cfg: Cfg) -> (usize, usize, AlignedSlice) { + let Cfg { len, spread, off } = cfg; + let spread = calculate_spread(len, spread); + println!("{len} bytes, {spread} spread, {off} offset"); + assert!(spread < len, "otherwise this just tests memcpy"); + let mut buf = AlignedSlice::new_zeroed(len + spread, off); + let mut fill: usize = 0; + buf[..len].fill_with(|| { + fill += 1; + fill as u8 + }); + (len, spread, buf) + } + + fn setup_backward(cfg: Cfg) -> (usize, usize, AlignedSlice) { + let Cfg { len, spread, off } = cfg; + let spread = calculate_spread(len, spread); + println!("{len} bytes, {spread} spread, {off} offset"); + assert!(spread < len, "otherwise this just tests memcpy"); + let mut buf = AlignedSlice::new_zeroed(len + spread, off); + let mut fill: usize = 0; + buf[spread..].fill_with(|| { + fill += 1; + fill as u8 + }); + (len, spread, buf) + } + + #[library_benchmark] + #[benches::small_spread( + args = [ + Cfg { len: 16, spread: Small, off: 0 }, + Cfg { len: 32, spread: Small, off: 0 }, + Cfg { len: 64, spread: Small, off: 0 }, + Cfg { len: 512, spread: Small, off: 0 }, + Cfg { len: 4096, spread: Small, off: 0 }, + Cfg { len: 1048576, spread: Small, off: 0 }, + ], + setup = setup_forward + )] + #[benches::medium_spread( + args = [ + Cfg { len: 16, spread: Medium, off: 0 }, + Cfg { len: 32, spread: Medium, off: 0 }, + Cfg { len: 64, spread: Medium, off: 0 }, + Cfg { len: 512, spread: Medium, off: 0 }, + Cfg { len: 4096, spread: Medium, off: 0 }, + Cfg { len: 1048576, spread: Medium, off: 0 }, + ], + setup = setup_forward + )] + #[benches::large_spread( + args = [ + Cfg { len: 16, spread: Large, off: 0 }, + Cfg { len: 32, spread: Large, off: 0 }, + Cfg { len: 64, spread: Large, off: 0 }, + Cfg { len: 512, spread: Large, off: 0 }, + Cfg { len: 4096, spread: Large, off: 0 }, + Cfg { len: 1048576, spread: Large, off: 0 }, + ], + setup = setup_forward + )] + #[benches::small_spread_offset( + args = [ + Cfg { len: 16, spread: Small, off: 63 }, + Cfg { len: 32, spread: Small, off: 63 }, + Cfg { len: 64, spread: Small, off: 63 }, + Cfg { len: 512, spread: Small, off: 63 }, + Cfg { len: 4096, spread: Small, off: 63 }, + Cfg { len: 1048576, spread: Small, off: 63 }, + ], + setup = setup_forward + )] + #[benches::medium_spread_offset( + args = [ + Cfg { len: 16, spread: Medium, off: 63 }, + Cfg { len: 32, spread: Medium, off: 63 }, + Cfg { len: 64, spread: Medium, off: 63 }, + Cfg { len: 512, spread: Medium, off: 63 }, + Cfg { len: 4096, spread: Medium, off: 63 }, + Cfg { len: 1048576, spread: Medium, off: 63 }, + ], + setup = setup_forward + )] + #[benches::large_spread_offset( + args = [ + Cfg { len: 16, spread: Large, off: 63 }, + Cfg { len: 32, spread: Large, off: 63 }, + Cfg { len: 64, spread: Large, off: 63 }, + Cfg { len: 512, spread: Large, off: 63 }, + Cfg { len: 4096, spread: Large, off: 63 }, + Cfg { len: 1048576, spread: Large, off: 63 }, + ], + setup = setup_forward + )] + fn forward((len, spread, mut buf): (usize, usize, AlignedSlice)) { + // Test moving from the start of the buffer toward the end + unsafe { + black_box(memmove( + black_box(buf[spread..].as_mut_ptr()), + black_box(buf.as_ptr()), + black_box(len), + )); + } + } + + #[library_benchmark] + #[benches::small_spread( + args = [ + Cfg { len: 16, spread: Small, off: 0 }, + Cfg { len: 32, spread: Small, off: 0 }, + Cfg { len: 64, spread: Small, off: 0 }, + Cfg { len: 512, spread: Small, off: 0 }, + Cfg { len: 4096, spread: Small, off: 0 }, + Cfg { len: 1048576, spread: Small, off: 0 }, + ], + setup = setup_backward + )] + #[benches::middle( + args = [ + Cfg { len: 16, spread: Medium, off: 0 }, + Cfg { len: 32, spread: Medium, off: 0 }, + Cfg { len: 64, spread: Medium, off: 0 }, + Cfg { len: 512, spread: Medium, off: 0 }, + Cfg { len: 4096, spread: Medium, off: 0 }, + Cfg { len: 1048576, spread: Medium, off: 0 }, + ], + setup = setup_backward + )] + #[benches::large_spread( + args = [ + Cfg { len: 16, spread: Large, off: 0 }, + Cfg { len: 32, spread: Large, off: 0 }, + Cfg { len: 64, spread: Large, off: 0 }, + Cfg { len: 512, spread: Large, off: 0 }, + Cfg { len: 4096, spread: Large, off: 0 }, + Cfg { len: 1048576, spread: Large, off: 0 }, + ], + setup = setup_backward + )] + #[benches::small_spread_off( + args = [ + Cfg { len: 16, spread: Small, off: 63 }, + Cfg { len: 32, spread: Small, off: 63 }, + Cfg { len: 64, spread: Small, off: 63 }, + Cfg { len: 512, spread: Small, off: 63 }, + Cfg { len: 4096, spread: Small, off: 63 }, + Cfg { len: 1048576, spread: Small, off: 63 }, + ], + setup = setup_backward + )] + #[benches::middle_off( + args = [ + Cfg { len: 16, spread: Medium, off: 63 }, + Cfg { len: 32, spread: Medium, off: 63 }, + Cfg { len: 64, spread: Medium, off: 63 }, + Cfg { len: 512, spread: Medium, off: 63 }, + Cfg { len: 4096, spread: Medium, off: 63 }, + Cfg { len: 1048576, spread: Medium, off: 63 }, + ], + setup = setup_backward + )] + #[benches::large_spread_off( + args = [ + Cfg { len: 16, spread: Large, off: 63 }, + Cfg { len: 32, spread: Large, off: 63 }, + Cfg { len: 64, spread: Large, off: 63 }, + Cfg { len: 512, spread: Large, off: 63 }, + Cfg { len: 4096, spread: Large, off: 63 }, + Cfg { len: 1048576, spread: Large, off: 63 }, + ], + setup = setup_backward + )] + fn backward((len, spread, mut buf): (usize, usize, AlignedSlice)) { + // Test moving from the end of the buffer toward the start + unsafe { + black_box(memmove( + black_box(buf.as_mut_ptr()), + black_box(buf[spread..].as_ptr()), + black_box(len), + )); + } + } + + library_benchmark_group!(name = memmove; benchmarks = forward, backward); +} + +use mcmp::memcmp; +use mcpy::memcpy; +use mmove::memmove; +use mset::memset; + +main!(library_benchmark_groups = memcpy, memset, memcmp, memmove); From 7b674e5a7568ef990d5ebc487be42a40d46bc36e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 22 Mar 2025 05:03:03 +0000 Subject: [PATCH 1750/4206] Clean up icount benchmarks * Delete some memcpy tests that were a bit excessive * Always use the same offset of 65 * Add a memmove test with aligned source and destination * Improve printing output and add more comments * Use a constant for 1 MiB so it shows up in the benchmark logs --- .../testcrate/benches/mem_icount.rs | 199 ++++++++++-------- 1 file changed, 112 insertions(+), 87 deletions(-) diff --git a/library/compiler-builtins/testcrate/benches/mem_icount.rs b/library/compiler-builtins/testcrate/benches/mem_icount.rs index be3d13dffdfa7..63045f6e1ec60 100644 --- a/library/compiler-builtins/testcrate/benches/mem_icount.rs +++ b/library/compiler-builtins/testcrate/benches/mem_icount.rs @@ -7,7 +7,9 @@ use std::{ops, slice}; use compiler_builtins::mem::{memcmp, memcpy, memmove, memset}; use iai_callgrind::{library_benchmark, library_benchmark_group, main}; -const PAGE_SIZE: usize = 0x1000; +const PAGE_SIZE: usize = 0x1000; // 4 kiB +const MAX_ALIGN: usize = 512; // assume we may use avx512 operations one day +const MEG1: usize = 1 << 20; // 1 MiB #[derive(Clone)] #[repr(C, align(0x1000))] @@ -62,7 +64,7 @@ mod mcpy { fn setup(cfg: Cfg) -> (usize, AlignedSlice, AlignedSlice) { let Cfg { len, s_off, d_off } = cfg; - println!("{len} bytes, {s_off} src offset, {d_off} dst offset"); + println!("bytes: {len} bytes, src offset: {s_off}, dst offset: {d_off}"); let mut src = AlignedSlice::new_zeroed(len, s_off); let dst = AlignedSlice::new_zeroed(len, d_off); src.fill(1); @@ -71,57 +73,38 @@ mod mcpy { #[library_benchmark] #[benches::aligned( + // Both aligned args = [ Cfg { len: 16, s_off: 0, d_off: 0 }, - Cfg { len: 16, s_off: 0, d_off: 0 }, - Cfg { len: 28, s_off: 0, d_off: 0 }, Cfg { len: 32, s_off: 0, d_off: 0 }, - Cfg { len: 36, s_off: 0, d_off: 0 }, - Cfg { len: 60, s_off: 0, d_off: 0 }, Cfg { len: 64, s_off: 0, d_off: 0 }, - Cfg { len: 68, s_off: 0, d_off: 0 }, - Cfg { len: 128, s_off: 0, d_off: 0 }, - Cfg { len: 256, s_off: 0, d_off: 0 }, Cfg { len: 512, s_off: 0, d_off: 0 }, - Cfg { len: 1024, s_off: 0, d_off: 0 }, Cfg { len: 4096, s_off: 0, d_off: 0 }, - Cfg { len: 1048576, s_off: 0, d_off: 0 }, + Cfg { len: MEG1, s_off: 0, d_off: 0 }, ], setup = setup, )] #[benches::offset( + // Both at the same offset args = [ Cfg { len: 16, s_off: 65, d_off: 65 }, - Cfg { len: 28, s_off: 65, d_off: 65 }, Cfg { len: 32, s_off: 65, d_off: 65 }, - Cfg { len: 36, s_off: 65, d_off: 65 }, - Cfg { len: 60, s_off: 65, d_off: 65 }, Cfg { len: 64, s_off: 65, d_off: 65 }, - Cfg { len: 68, s_off: 65, d_off: 65 }, - Cfg { len: 128, s_off: 65, d_off: 65 }, - Cfg { len: 256, s_off: 65, d_off: 65 }, Cfg { len: 512, s_off: 65, d_off: 65 }, - Cfg { len: 1024, s_off: 65, d_off: 65 }, Cfg { len: 4096, s_off: 65, d_off: 65 }, - Cfg { len: 1048576, s_off: 65, d_off: 65 }, + Cfg { len: MEG1, s_off: 65, d_off: 65 }, ], setup = setup, )] #[benches::misaligned( + // `src` and `dst` both misaligned by different amounts args = [ Cfg { len: 16, s_off: 65, d_off: 66 }, - Cfg { len: 28, s_off: 65, d_off: 66 }, Cfg { len: 32, s_off: 65, d_off: 66 }, - Cfg { len: 36, s_off: 65, d_off: 66 }, - Cfg { len: 60, s_off: 65, d_off: 66 }, Cfg { len: 64, s_off: 65, d_off: 66 }, - Cfg { len: 68, s_off: 65, d_off: 66 }, - Cfg { len: 128, s_off: 65, d_off: 66 }, - Cfg { len: 256, s_off: 65, d_off: 66 }, Cfg { len: 512, s_off: 65, d_off: 66 }, - Cfg { len: 1024, s_off: 65, d_off: 66 }, Cfg { len: 4096, s_off: 65, d_off: 66 }, - Cfg { len: 1048576, s_off: 65, d_off: 66 }, + Cfg { len: MEG1, s_off: 65, d_off: 66 }, ], setup = setup, )] @@ -147,7 +130,7 @@ mod mset { } fn setup(Cfg { len, offset }: Cfg) -> (usize, AlignedSlice) { - println!("{len} bytes, {offset} offset"); + println!("bytes: {len}, offset: {offset}"); (len, AlignedSlice::new_zeroed(len, offset)) } @@ -159,7 +142,7 @@ mod mset { Cfg { len: 64, offset: 0 }, Cfg { len: 512, offset: 0 }, Cfg { len: 4096, offset: 0 }, - Cfg { len: 1048576, offset: 0 }, + Cfg { len: MEG1, offset: 0 }, ], setup = setup, )] @@ -170,7 +153,7 @@ mod mset { Cfg { len: 64, offset: 65 }, Cfg { len: 512, offset: 65 }, Cfg { len: 4096, offset: 65 }, - Cfg { len: 1048576, offset: 65 }, + Cfg { len: MEG1, offset: 65 }, ], setup = setup, )] @@ -198,7 +181,7 @@ mod mcmp { fn setup(cfg: Cfg) -> (usize, AlignedSlice, AlignedSlice) { let Cfg { len, s_off, d_off } = cfg; - println!("{len} bytes, {s_off} src offset, {d_off} dst offset"); + println!("bytes: {len}, src offset: {s_off}, dst offset: {d_off}"); let b1 = AlignedSlice::new_zeroed(len, s_off); let mut b2 = AlignedSlice::new_zeroed(len, d_off); b2[len - 1] = 1; @@ -207,35 +190,38 @@ mod mcmp { #[library_benchmark] #[benches::aligned( + // Both aligned args = [ Cfg { len: 16, s_off: 0, d_off: 0 }, Cfg { len: 32, s_off: 0, d_off: 0 }, Cfg { len: 64, s_off: 0, d_off: 0 }, Cfg { len: 512, s_off: 0, d_off: 0 }, Cfg { len: 4096, s_off: 0, d_off: 0 }, - Cfg { len: 1048576, s_off: 0, d_off: 0 }, + Cfg { len: MEG1, s_off: 0, d_off: 0 }, ], setup = setup )] #[benches::offset( + // Both at the same offset args = [ Cfg { len: 16, s_off: 65, d_off: 65 }, Cfg { len: 32, s_off: 65, d_off: 65 }, Cfg { len: 64, s_off: 65, d_off: 65 }, Cfg { len: 512, s_off: 65, d_off: 65 }, Cfg { len: 4096, s_off: 65, d_off: 65 }, - Cfg { len: 1048576, s_off: 65, d_off: 65 }, + Cfg { len: MEG1, s_off: 65, d_off: 65 }, ], setup = setup )] #[benches::misaligned( + // `src` and `dst` both misaligned by different amounts args = [ Cfg { len: 16, s_off: 65, d_off: 66 }, Cfg { len: 32, s_off: 65, d_off: 66 }, Cfg { len: 64, s_off: 65, d_off: 66 }, Cfg { len: 512, s_off: 65, d_off: 66 }, Cfg { len: 4096, s_off: 65, d_off: 66 }, - Cfg { len: 1048576, s_off: 65, d_off: 66 }, + Cfg { len: MEG1, s_off: 65, d_off: 66 }, ], setup = setup )] @@ -254,7 +240,7 @@ mod mcmp { mod mmove { use super::*; - use Spread::{Large, Medium, Small}; + use Spread::{Aligned, Large, Medium, Small}; struct Cfg { len: usize, @@ -263,6 +249,8 @@ mod mmove { } enum Spread { + /// `src` and `dst` are close and have the same alignment (or offset). + Aligned, /// `src` and `dst` are close. Small, /// `src` and `dst` are halfway offset in the buffer. @@ -271,10 +259,16 @@ mod mmove { Large, } + // Note that small and large are fn calculate_spread(len: usize, spread: Spread) -> usize { match spread { + // Note that this test doesn't make sense for lengths less than len=128 + Aligned => { + assert!(len > MAX_ALIGN, "aligned memset would have no overlap"); + MAX_ALIGN + } Small => 1, - Medium => len / 2, + Medium => (len / 2) + 1, // add 1 so all are misaligned Large => len - 1, } } @@ -282,8 +276,8 @@ mod mmove { fn setup_forward(cfg: Cfg) -> (usize, usize, AlignedSlice) { let Cfg { len, spread, off } = cfg; let spread = calculate_spread(len, spread); - println!("{len} bytes, {spread} spread, {off} offset"); - assert!(spread < len, "otherwise this just tests memcpy"); + println!("bytes: {len}, spread: {spread}, offset: {off}, forward"); + assert!(spread < len, "memmove tests should have some overlap"); let mut buf = AlignedSlice::new_zeroed(len + spread, off); let mut fill: usize = 0; buf[..len].fill_with(|| { @@ -296,8 +290,8 @@ mod mmove { fn setup_backward(cfg: Cfg) -> (usize, usize, AlignedSlice) { let Cfg { len, spread, off } = cfg; let spread = calculate_spread(len, spread); - println!("{len} bytes, {spread} spread, {off} offset"); - assert!(spread < len, "otherwise this just tests memcpy"); + println!("bytes: {len}, spread: {spread}, offset: {off}, backward"); + assert!(spread < len, "memmove tests should have some overlap"); let mut buf = AlignedSlice::new_zeroed(len + spread, off); let mut fill: usize = 0; buf[spread..].fill_with(|| { @@ -308,6 +302,14 @@ mod mmove { } #[library_benchmark] + #[benches::aligned( + args = [ + // Don't test small spreads since there is no overlap + Cfg { len: 4096, spread: Aligned, off: 0 }, + Cfg { len: MEG1, spread: Aligned, off: 0 }, + ], + setup = setup_forward + )] #[benches::small_spread( args = [ Cfg { len: 16, spread: Small, off: 0 }, @@ -315,7 +317,7 @@ mod mmove { Cfg { len: 64, spread: Small, off: 0 }, Cfg { len: 512, spread: Small, off: 0 }, Cfg { len: 4096, spread: Small, off: 0 }, - Cfg { len: 1048576, spread: Small, off: 0 }, + Cfg { len: MEG1, spread: Small, off: 0 }, ], setup = setup_forward )] @@ -326,7 +328,7 @@ mod mmove { Cfg { len: 64, spread: Medium, off: 0 }, Cfg { len: 512, spread: Medium, off: 0 }, Cfg { len: 4096, spread: Medium, off: 0 }, - Cfg { len: 1048576, spread: Medium, off: 0 }, + Cfg { len: MEG1, spread: Medium, off: 0 }, ], setup = setup_forward )] @@ -337,40 +339,47 @@ mod mmove { Cfg { len: 64, spread: Large, off: 0 }, Cfg { len: 512, spread: Large, off: 0 }, Cfg { len: 4096, spread: Large, off: 0 }, - Cfg { len: 1048576, spread: Large, off: 0 }, + Cfg { len: MEG1, spread: Large, off: 0 }, ], setup = setup_forward )] - #[benches::small_spread_offset( + #[benches::aligned_off( + args = [ + Cfg { len: 4096, spread: Aligned, off: 65 }, + Cfg { len: MEG1, spread: Aligned, off: 65 }, + ], + setup = setup_forward + )] + #[benches::small_spread_off( args = [ - Cfg { len: 16, spread: Small, off: 63 }, - Cfg { len: 32, spread: Small, off: 63 }, - Cfg { len: 64, spread: Small, off: 63 }, - Cfg { len: 512, spread: Small, off: 63 }, - Cfg { len: 4096, spread: Small, off: 63 }, - Cfg { len: 1048576, spread: Small, off: 63 }, + Cfg { len: 16, spread: Small, off: 65 }, + Cfg { len: 32, spread: Small, off: 65 }, + Cfg { len: 64, spread: Small, off: 65 }, + Cfg { len: 512, spread: Small, off: 65 }, + Cfg { len: 4096, spread: Small, off: 65 }, + Cfg { len: MEG1, spread: Small, off: 65 }, ], setup = setup_forward )] - #[benches::medium_spread_offset( + #[benches::medium_spread_off( args = [ - Cfg { len: 16, spread: Medium, off: 63 }, - Cfg { len: 32, spread: Medium, off: 63 }, - Cfg { len: 64, spread: Medium, off: 63 }, - Cfg { len: 512, spread: Medium, off: 63 }, - Cfg { len: 4096, spread: Medium, off: 63 }, - Cfg { len: 1048576, spread: Medium, off: 63 }, + Cfg { len: 16, spread: Medium, off: 65 }, + Cfg { len: 32, spread: Medium, off: 65 }, + Cfg { len: 64, spread: Medium, off: 65 }, + Cfg { len: 512, spread: Medium, off: 65 }, + Cfg { len: 4096, spread: Medium, off: 65 }, + Cfg { len: MEG1, spread: Medium, off: 65 }, ], setup = setup_forward )] - #[benches::large_spread_offset( + #[benches::large_spread_off( args = [ - Cfg { len: 16, spread: Large, off: 63 }, - Cfg { len: 32, spread: Large, off: 63 }, - Cfg { len: 64, spread: Large, off: 63 }, - Cfg { len: 512, spread: Large, off: 63 }, - Cfg { len: 4096, spread: Large, off: 63 }, - Cfg { len: 1048576, spread: Large, off: 63 }, + Cfg { len: 16, spread: Large, off: 65 }, + Cfg { len: 32, spread: Large, off: 65 }, + Cfg { len: 64, spread: Large, off: 65 }, + Cfg { len: 512, spread: Large, off: 65 }, + Cfg { len: 4096, spread: Large, off: 65 }, + Cfg { len: MEG1, spread: Large, off: 65 }, ], setup = setup_forward )] @@ -386,6 +395,14 @@ mod mmove { } #[library_benchmark] + #[benches::aligned( + args = [ + // Don't test small spreads since there is no overlap + Cfg { len: 4096, spread: Aligned, off: 0 }, + Cfg { len: MEG1, spread: Aligned, off: 0 }, + ], + setup = setup_backward + )] #[benches::small_spread( args = [ Cfg { len: 16, spread: Small, off: 0 }, @@ -393,18 +410,18 @@ mod mmove { Cfg { len: 64, spread: Small, off: 0 }, Cfg { len: 512, spread: Small, off: 0 }, Cfg { len: 4096, spread: Small, off: 0 }, - Cfg { len: 1048576, spread: Small, off: 0 }, + Cfg { len: MEG1, spread: Small, off: 0 }, ], setup = setup_backward )] - #[benches::middle( + #[benches::medium_spread( args = [ Cfg { len: 16, spread: Medium, off: 0 }, Cfg { len: 32, spread: Medium, off: 0 }, Cfg { len: 64, spread: Medium, off: 0 }, Cfg { len: 512, spread: Medium, off: 0 }, Cfg { len: 4096, spread: Medium, off: 0 }, - Cfg { len: 1048576, spread: Medium, off: 0 }, + Cfg { len: MEG1, spread: Medium, off: 0 }, ], setup = setup_backward )] @@ -415,40 +432,48 @@ mod mmove { Cfg { len: 64, spread: Large, off: 0 }, Cfg { len: 512, spread: Large, off: 0 }, Cfg { len: 4096, spread: Large, off: 0 }, - Cfg { len: 1048576, spread: Large, off: 0 }, + Cfg { len: MEG1, spread: Large, off: 0 }, + ], + setup = setup_backward + )] + #[benches::aligned_off( + args = [ + // Don't test small spreads since there is no overlap + Cfg { len: 4096, spread: Aligned, off: 65 }, + Cfg { len: MEG1, spread: Aligned, off: 65 }, ], setup = setup_backward )] #[benches::small_spread_off( args = [ - Cfg { len: 16, spread: Small, off: 63 }, - Cfg { len: 32, spread: Small, off: 63 }, - Cfg { len: 64, spread: Small, off: 63 }, - Cfg { len: 512, spread: Small, off: 63 }, - Cfg { len: 4096, spread: Small, off: 63 }, - Cfg { len: 1048576, spread: Small, off: 63 }, + Cfg { len: 16, spread: Small, off: 65 }, + Cfg { len: 32, spread: Small, off: 65 }, + Cfg { len: 64, spread: Small, off: 65 }, + Cfg { len: 512, spread: Small, off: 65 }, + Cfg { len: 4096, spread: Small, off: 65 }, + Cfg { len: MEG1, spread: Small, off: 65 }, ], setup = setup_backward )] - #[benches::middle_off( + #[benches::medium_spread_off( args = [ - Cfg { len: 16, spread: Medium, off: 63 }, - Cfg { len: 32, spread: Medium, off: 63 }, - Cfg { len: 64, spread: Medium, off: 63 }, - Cfg { len: 512, spread: Medium, off: 63 }, - Cfg { len: 4096, spread: Medium, off: 63 }, - Cfg { len: 1048576, spread: Medium, off: 63 }, + Cfg { len: 16, spread: Medium, off: 65 }, + Cfg { len: 32, spread: Medium, off: 65 }, + Cfg { len: 64, spread: Medium, off: 65 }, + Cfg { len: 512, spread: Medium, off: 65 }, + Cfg { len: 4096, spread: Medium, off: 65 }, + Cfg { len: MEG1, spread: Medium, off: 65 }, ], setup = setup_backward )] #[benches::large_spread_off( args = [ - Cfg { len: 16, spread: Large, off: 63 }, - Cfg { len: 32, spread: Large, off: 63 }, - Cfg { len: 64, spread: Large, off: 63 }, - Cfg { len: 512, spread: Large, off: 63 }, - Cfg { len: 4096, spread: Large, off: 63 }, - Cfg { len: 1048576, spread: Large, off: 63 }, + Cfg { len: 16, spread: Large, off: 65 }, + Cfg { len: 32, spread: Large, off: 65 }, + Cfg { len: 64, spread: Large, off: 65 }, + Cfg { len: 512, spread: Large, off: 65 }, + Cfg { len: 4096, spread: Large, off: 65 }, + Cfg { len: MEG1, spread: Large, off: 65 }, ], setup = setup_backward )] From 5cf993880ae20a79eef9af486479dcfbbb26d848 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 Mar 2025 06:36:40 +0100 Subject: [PATCH 1751/4206] copy_misaligned_words: avoid out-of-bounds accesses (#799) * copy_misaligned_words: avoid out-of-bounds accesses * add test to make Miri able to detect OOB in memmove * run Miri on CI --- .../.github/workflows/main.yml | 16 ++ library/compiler-builtins/ci/miri.sh | 16 ++ .../compiler-builtins/src/mem/impls.rs | 160 ++++++++++++++---- .../compiler-builtins/testcrate/tests/mem.rs | 23 ++- 4 files changed, 183 insertions(+), 32 deletions(-) create mode 100755 library/compiler-builtins/ci/miri.sh diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yml index c337c26a272bd..003102d59438f 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yml @@ -160,6 +160,21 @@ jobs: rm -rf /tmp/.buildx-cache mv /tmp/.buildx-cache-new /tmp/.buildx-cache + miri: + name: Miri + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - 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 + - run: ./ci/miri.sh + rustfmt: name: Rustfmt runs-on: ubuntu-latest @@ -190,6 +205,7 @@ jobs: - test - rustfmt - clippy + - miri runs-on: ubuntu-latest # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency # failed" as success. So we have to do some contortions to ensure the job fails if any of its diff --git a/library/compiler-builtins/ci/miri.sh b/library/compiler-builtins/ci/miri.sh new file mode 100755 index 0000000000000..f9a1240a46593 --- /dev/null +++ b/library/compiler-builtins/ci/miri.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -ex + +# We need Tree Borrows as some of our raw pointer patterns are not +# compatible with Stacked Borrows. +export MIRIFLAGS="-Zmiri-tree-borrows" + +# One target that sets `mem-unaligned` and one that does not, +# and a big-endian target. +TARGETS=(x86_64-unknown-linux-gnu + armv7-unknown-linux-gnueabihf + s390x-unknown-linux-gnu) +for TARGET in "${TARGETS[@]}"; do + # Only run the `mem` tests to avoid this taking too long. + cargo miri test --manifest-path testcrate/Cargo.toml --features no-asm --target $TARGET -- mem +done diff --git a/library/compiler-builtins/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/compiler-builtins/src/mem/impls.rs index c602a67dbd7a4..dc12d69969c4e 100644 --- a/library/compiler-builtins/compiler-builtins/src/mem/impls.rs +++ b/library/compiler-builtins/compiler-builtins/src/mem/impls.rs @@ -41,6 +41,72 @@ unsafe fn read_usize_unaligned(x: *const usize) -> usize { core::mem::transmute(x_read) } +/// 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"))] +#[inline(always)] +unsafe fn load_chunk_aligned( + src: *const usize, + dst: *mut usize, + load_sz: usize, + offset: usize, +) -> usize { + let chunk_sz = core::mem::size_of::(); + if (load_sz & chunk_sz) != 0 { + *dst.wrapping_byte_add(offset).cast::() = *src.wrapping_byte_add(offset).cast::(); + offset | chunk_sz + } else { + offset + } +} + +/// 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"))] +#[inline(always)] +unsafe fn load_aligned_partial(src: *const usize, load_sz: usize) -> usize { + debug_assert!(load_sz < WORD_SIZE); + // We can read up to 7 bytes here, which is enough for WORD_SIZE of 8 + // (since `load_sz < WORD_SIZE`). + const { assert!(WORD_SIZE <= 8) }; + + let mut i = 0; + let mut out = 0usize; + // We load in decreasing order, so the pointers remain sufficiently aligned for the next step. + i = load_chunk_aligned::(src, &raw mut out, load_sz, i); + i = load_chunk_aligned::(src, &raw mut out, load_sz, i); + i = load_chunk_aligned::(src, &raw mut out, load_sz, i); + debug_assert!(i == load_sz); + out +} + +/// Load `load_sz` many bytes from `src.wrapping_byte_add(WORD_SIZE - load_sz)`. `src` must be +/// `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"))] +#[inline(always)] +unsafe fn load_aligned_end_partial(src: *const usize, load_sz: usize) -> usize { + debug_assert!(load_sz < WORD_SIZE); + // We can read up to 7 bytes here, which is enough for WORD_SIZE of 8 + // (since `load_sz < WORD_SIZE`). + const { assert!(WORD_SIZE <= 8) }; + + let mut i = 0; + let mut out = 0usize; + // Obtain pointers pointing to the beginning of the range we want to load. + let src_shifted = src.wrapping_byte_add(WORD_SIZE - load_sz); + let out_shifted = (&raw mut out).wrapping_byte_add(WORD_SIZE - load_sz); + // We load in increasing order, so by the time we reach `u16` things are 2-aligned etc. + i = load_chunk_aligned::(src_shifted, out_shifted, load_sz, i); + i = load_chunk_aligned::(src_shifted, out_shifted, load_sz, i); + i = load_chunk_aligned::(src_shifted, out_shifted, load_sz, i); + debug_assert!(i == load_sz); + out +} + #[inline(always)] pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) { #[inline(always)] @@ -66,40 +132,57 @@ 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"))] #[inline(always)] unsafe fn copy_forward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { + debug_assert!(n > 0 && n % WORD_SIZE == 0); + debug_assert!(src.addr() % WORD_SIZE != 0); + let mut dest_usize = dest as *mut usize; let dest_end = dest.wrapping_add(n) as *mut usize; // Calculate the misalignment offset and shift needed to reassemble value. + // Since `src` is definitely not aligned, `offset` is in the range 1..WORD_SIZE. let offset = src as usize & WORD_MASK; let shift = offset * 8; // Realign src - let mut src_aligned = (src as usize & !WORD_MASK) as *mut usize; - // This will read (but won't use) bytes out of bound. - // cfg needed because not all targets will have atomic loads that can be lowered - // (e.g. BPF, MSP430), or provided by an external library (e.g. RV32I) - #[cfg(target_has_atomic_load_store = "ptr")] - let mut prev_word = core::intrinsics::atomic_load_unordered(src_aligned); - #[cfg(not(target_has_atomic_load_store = "ptr"))] - let mut prev_word = core::ptr::read_volatile(src_aligned); + let mut src_aligned = src.wrapping_byte_sub(offset) as *mut usize; + let mut prev_word = load_aligned_end_partial(src_aligned, WORD_SIZE - offset); - while dest_usize < dest_end { + while dest_usize.wrapping_add(1) < dest_end { src_aligned = src_aligned.wrapping_add(1); let cur_word = *src_aligned; - #[cfg(target_endian = "little")] - let resembled = prev_word >> shift | cur_word << (WORD_SIZE * 8 - shift); - #[cfg(target_endian = "big")] - let resembled = prev_word << shift | cur_word >> (WORD_SIZE * 8 - shift); + let reassembled = if cfg!(target_endian = "little") { + prev_word >> shift | cur_word << (WORD_SIZE * 8 - shift) + } else { + prev_word << shift | cur_word >> (WORD_SIZE * 8 - shift) + }; prev_word = cur_word; - *dest_usize = resembled; + *dest_usize = reassembled; dest_usize = dest_usize.wrapping_add(1); } + + // There's one more element left to go, and we can't use the loop for that as on the `src` side, + // it is partially out-of-bounds. + src_aligned = src_aligned.wrapping_add(1); + let cur_word = load_aligned_partial(src_aligned, offset); + let reassembled = if cfg!(target_endian = "little") { + prev_word >> shift | cur_word << (WORD_SIZE * 8 - shift) + } else { + prev_word << shift | cur_word >> (WORD_SIZE * 8 - shift) + }; + // prev_word does not matter any more + + *dest_usize = reassembled; + // dest_usize does not matter any more } + /// `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")] #[inline(always)] unsafe fn copy_forward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { @@ -164,40 +247,57 @@ 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"))] #[inline(always)] unsafe fn copy_backward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { + debug_assert!(n > 0 && n % WORD_SIZE == 0); + debug_assert!(src.addr() % WORD_SIZE != 0); + let mut dest_usize = dest as *mut usize; - let dest_start = dest.wrapping_sub(n) as *mut usize; + let dest_start = dest.wrapping_sub(n) as *mut usize; // we're moving towards the start // Calculate the misalignment offset and shift needed to reassemble value. + // Since `src` is definitely not aligned, `offset` is in the range 1..WORD_SIZE. let offset = src as usize & WORD_MASK; let shift = offset * 8; - // Realign src_aligned - let mut src_aligned = (src as usize & !WORD_MASK) as *mut usize; - // This will read (but won't use) bytes out of bound. - // cfg needed because not all targets will have atomic loads that can be lowered - // (e.g. BPF, MSP430), or provided by an external library (e.g. RV32I) - #[cfg(target_has_atomic_load_store = "ptr")] - let mut prev_word = core::intrinsics::atomic_load_unordered(src_aligned); - #[cfg(not(target_has_atomic_load_store = "ptr"))] - let mut prev_word = core::ptr::read_volatile(src_aligned); + // Realign src + let mut src_aligned = src.wrapping_byte_sub(offset) as *mut usize; + let mut prev_word = load_aligned_partial(src_aligned, offset); - while dest_start < dest_usize { + while dest_start.wrapping_add(1) < dest_usize { src_aligned = src_aligned.wrapping_sub(1); let cur_word = *src_aligned; - #[cfg(target_endian = "little")] - let resembled = prev_word << (WORD_SIZE * 8 - shift) | cur_word >> shift; - #[cfg(target_endian = "big")] - let resembled = prev_word >> (WORD_SIZE * 8 - shift) | cur_word << shift; + let reassembled = if cfg!(target_endian = "little") { + prev_word << (WORD_SIZE * 8 - shift) | cur_word >> shift + } else { + prev_word >> (WORD_SIZE * 8 - shift) | cur_word << shift + }; prev_word = cur_word; dest_usize = dest_usize.wrapping_sub(1); - *dest_usize = resembled; + *dest_usize = reassembled; } + + // There's one more element left to go, and we can't use the loop for that as on the `src` side, + // it is partially out-of-bounds. + src_aligned = src_aligned.wrapping_sub(1); + let cur_word = load_aligned_end_partial(src_aligned, WORD_SIZE - offset); + let reassembled = if cfg!(target_endian = "little") { + prev_word << (WORD_SIZE * 8 - shift) | cur_word >> shift + } else { + prev_word >> (WORD_SIZE * 8 - shift) | cur_word << shift + }; + // prev_word does not matter any more + + dest_usize = dest_usize.wrapping_sub(1); + *dest_usize = reassembled; } + /// `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")] #[inline(always)] unsafe fn copy_backward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { diff --git a/library/compiler-builtins/testcrate/tests/mem.rs b/library/compiler-builtins/testcrate/tests/mem.rs index 48ac95adc17f4..d838ef159a024 100644 --- a/library/compiler-builtins/testcrate/tests/mem.rs +++ b/library/compiler-builtins/testcrate/tests/mem.rs @@ -128,11 +128,13 @@ fn memcmp_eq() { #[test] fn memcmp_ne() { let arr1 @ arr2 = gen_arr::<256>(); - for i in 0..256 { + // Reduce iteration count in Miri as it is too slow otherwise. + let limit = if cfg!(miri) { 64 } else { 256 }; + for i in 0..limit { let mut diff_arr = arr1; diff_arr.0[i] = 127; let expect = diff_arr.0[i].cmp(&arr2.0[i]); - for k in i + 1..256 { + for k in i + 1..limit { let result = unsafe { memcmp(diff_arr.0.as_ptr(), arr2.0.as_ptr(), k) }; assert_eq!(expect, result.cmp(&0)); } @@ -230,6 +232,23 @@ fn memmove_backward_aligned() { } } +#[test] +fn memmove_misaligned_bounds() { + // The above test have the downside that the addresses surrounding the range-to-copy are all + // still in-bounds, so Miri would not actually complain about OOB accesses. So we also test with + // an array that has just the right size. We test a few times to avoid it being accidentally + // aligned. + for _ in 0..8 { + let mut arr1 = [0u8; 17]; + let mut arr2 = [0u8; 17]; + unsafe { + // Copy both ways so we hit both the forward and backward cases. + memmove(arr1.as_mut_ptr(), arr2.as_mut_ptr(), 17); + memmove(arr2.as_mut_ptr(), arr1.as_mut_ptr(), 17); + } + } +} + #[test] fn memset_backward_misaligned_nonaligned_start() { let mut arr = gen_arr::<32>(); From 30c128006a71eb9f0c2039a7389c4b636c1ce018 Mon Sep 17 00:00:00 2001 From: Patryk Wychowaniec Date: Sun, 23 Mar 2025 08:44:22 +0100 Subject: [PATCH 1752/4206] avr: Skip No More! --- .../compiler-builtins/src/float/add.rs | 2 - .../compiler-builtins/src/float/cmp.rs | 81 ++++++++----------- .../compiler-builtins/src/float/div.rs | 3 - .../compiler-builtins/src/float/extend.rs | 7 -- .../compiler-builtins/src/float/mul.rs | 2 - .../compiler-builtins/src/float/pow.rs | 3 - .../compiler-builtins/src/float/sub.rs | 2 - .../compiler-builtins/src/float/trunc.rs | 7 -- .../compiler-builtins/src/int/bswap.rs | 3 - .../compiler-builtins/src/int/sdiv.rs | 42 +++++++++- .../compiler-builtins/src/int/shift.rs | 9 --- .../compiler-builtins/src/int/udiv.rs | 25 ++++-- .../compiler-builtins/src/macros.rs | 29 ------- .../compiler-builtins/testcrate/tests/misc.rs | 1 - 14 files changed, 91 insertions(+), 125 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/src/float/add.rs b/library/compiler-builtins/compiler-builtins/src/float/add.rs index ef04ddc165c58..0426c9cc44fbb 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/add.rs @@ -189,14 +189,12 @@ where } intrinsics! { - #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_fadd] pub extern "C" fn __addsf3(a: f32, b: f32) -> f32 { add(a, b) } - #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_dadd] pub extern "C" fn __adddf3(a: f64, b: f64) -> f64 { diff --git a/library/compiler-builtins/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs index b9b4d0114b789..296952821cb46 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs @@ -3,6 +3,14 @@ use crate::float::Float; use crate::int::MinInt; +// https://github.com/llvm/llvm-project/blob/1e6ba3cd2fe96be00b6ed6ba28b3d9f9271d784d/compiler-rt/lib/builtins/fp_compare_impl.inc#L22 +#[cfg(target_arch = "avr")] +pub type CmpResult = i8; + +// https://github.com/llvm/llvm-project/blob/1e6ba3cd2fe96be00b6ed6ba28b3d9f9271d784d/compiler-rt/lib/builtins/fp_compare_impl.inc#L25 +#[cfg(not(target_arch = "avr"))] +pub type CmpResult = i32; + #[derive(Clone, Copy)] enum Result { Less, @@ -12,7 +20,7 @@ enum Result { } impl Result { - fn to_le_abi(self) -> i32 { + fn to_le_abi(self) -> CmpResult { match self { Result::Less => -1, Result::Equal => 0, @@ -21,7 +29,7 @@ impl Result { } } - fn to_ge_abi(self) -> i32 { + fn to_ge_abi(self) -> CmpResult { match self { Result::Less => -1, Result::Equal => 0, @@ -99,120 +107,99 @@ fn unord(a: F, b: F) -> bool { } intrinsics! { - #[avr_skip] - pub extern "C" fn __lesf2(a: f32, b: f32) -> i32 { + pub extern "C" fn __lesf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() } - #[avr_skip] - pub extern "C" fn __gesf2(a: f32, b: f32) -> i32 { + pub extern "C" fn __gesf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { cmp(a, b).to_ge_abi() } - #[avr_skip] #[arm_aeabi_alias = __aeabi_fcmpun] - pub extern "C" fn __unordsf2(a: f32, b: f32) -> i32 { - unord(a, b) as i32 + pub extern "C" fn __unordsf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { + unord(a, b) as crate::float::cmp::CmpResult } - #[avr_skip] - pub extern "C" fn __eqsf2(a: f32, b: f32) -> i32 { + pub extern "C" fn __eqsf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() } - #[avr_skip] - pub extern "C" fn __ltsf2(a: f32, b: f32) -> i32 { + pub extern "C" fn __ltsf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() } - #[avr_skip] - pub extern "C" fn __nesf2(a: f32, b: f32) -> i32 { + pub extern "C" fn __nesf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() } - #[avr_skip] - pub extern "C" fn __gtsf2(a: f32, b: f32) -> i32 { + pub extern "C" fn __gtsf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { cmp(a, b).to_ge_abi() } - #[avr_skip] - pub extern "C" fn __ledf2(a: f64, b: f64) -> i32 { + pub extern "C" fn __ledf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() } - #[avr_skip] - pub extern "C" fn __gedf2(a: f64, b: f64) -> i32 { + pub extern "C" fn __gedf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { cmp(a, b).to_ge_abi() } - #[avr_skip] #[arm_aeabi_alias = __aeabi_dcmpun] - pub extern "C" fn __unorddf2(a: f64, b: f64) -> i32 { - unord(a, b) as i32 + pub extern "C" fn __unorddf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { + unord(a, b) as crate::float::cmp::CmpResult } - #[avr_skip] - pub extern "C" fn __eqdf2(a: f64, b: f64) -> i32 { + pub extern "C" fn __eqdf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() } - #[avr_skip] - pub extern "C" fn __ltdf2(a: f64, b: f64) -> i32 { + pub extern "C" fn __ltdf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() } - #[avr_skip] - pub extern "C" fn __nedf2(a: f64, b: f64) -> i32 { + pub extern "C" fn __nedf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() } - #[avr_skip] - pub extern "C" fn __gtdf2(a: f64, b: f64) -> i32 { + pub extern "C" fn __gtdf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { cmp(a, b).to_ge_abi() } } #[cfg(f128_enabled)] intrinsics! { - #[avr_skip] #[ppc_alias = __lekf2] - pub extern "C" fn __letf2(a: f128, b: f128) -> i32 { + pub extern "C" fn __letf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() } - #[avr_skip] #[ppc_alias = __gekf2] - pub extern "C" fn __getf2(a: f128, b: f128) -> i32 { + pub extern "C" fn __getf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { cmp(a, b).to_ge_abi() } - #[avr_skip] #[ppc_alias = __unordkf2] - pub extern "C" fn __unordtf2(a: f128, b: f128) -> i32 { - unord(a, b) as i32 + pub extern "C" fn __unordtf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { + unord(a, b) as crate::float::cmp::CmpResult } - #[avr_skip] #[ppc_alias = __eqkf2] - pub extern "C" fn __eqtf2(a: f128, b: f128) -> i32 { + pub extern "C" fn __eqtf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() } - #[avr_skip] #[ppc_alias = __ltkf2] - pub extern "C" fn __lttf2(a: f128, b: f128) -> i32 { + pub extern "C" fn __lttf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() } - #[avr_skip] #[ppc_alias = __nekf2] - pub extern "C" fn __netf2(a: f128, b: f128) -> i32 { + pub extern "C" fn __netf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { cmp(a, b).to_le_abi() } - #[avr_skip] #[ppc_alias = __gtkf2] - pub extern "C" fn __gttf2(a: f128, b: f128) -> i32 { + pub extern "C" fn __gttf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { cmp(a, b).to_ge_abi() } } diff --git a/library/compiler-builtins/compiler-builtins/src/float/div.rs b/library/compiler-builtins/compiler-builtins/src/float/div.rs index 21c757dd639c2..929f29197872b 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/div.rs @@ -606,19 +606,16 @@ where } intrinsics! { - #[avr_skip] #[arm_aeabi_alias = __aeabi_fdiv] pub extern "C" fn __divsf3(a: f32, b: f32) -> f32 { div(a, b) } - #[avr_skip] #[arm_aeabi_alias = __aeabi_ddiv] pub extern "C" fn __divdf3(a: f64, b: f64) -> f64 { div(a, b) } - #[avr_skip] #[ppc_alias = __divkf3] #[cfg(f128_enabled)] pub extern "C" fn __divtf3(a: f128, b: f128) -> f128 { diff --git a/library/compiler-builtins/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/compiler-builtins/src/float/extend.rs index ce00da31dc5d9..c4f1fe30e0ea8 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/extend.rs @@ -70,7 +70,6 @@ where } intrinsics! { - #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_f2d] pub extern "C" fn __extendsfdf2(a: f32) -> f64 { @@ -79,7 +78,6 @@ intrinsics! { } intrinsics! { - #[avr_skip] #[aapcs_on_arm] #[apple_f16_arg_abi] #[arm_aeabi_alias = __aeabi_h2f] @@ -88,7 +86,6 @@ intrinsics! { extend(a) } - #[avr_skip] #[aapcs_on_arm] #[apple_f16_arg_abi] #[cfg(f16_enabled)] @@ -96,7 +93,6 @@ intrinsics! { extend(a) } - #[avr_skip] #[aapcs_on_arm] #[apple_f16_arg_abi] #[cfg(f16_enabled)] @@ -104,7 +100,6 @@ intrinsics! { extend(a) } - #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __extendhfkf2] #[cfg(all(f16_enabled, f128_enabled))] @@ -112,7 +107,6 @@ intrinsics! { extend(a) } - #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __extendsfkf2] #[cfg(f128_enabled)] @@ -120,7 +114,6 @@ intrinsics! { extend(a) } - #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __extenddfkf2] #[cfg(f128_enabled)] diff --git a/library/compiler-builtins/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/compiler-builtins/src/float/mul.rs index 58636cb5ebeed..7f1f19d9bd7fb 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/mul.rs @@ -180,14 +180,12 @@ where } intrinsics! { - #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_fmul] pub extern "C" fn __mulsf3(a: f32, b: f32) -> f32 { mul(a, b) } - #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_dmul] pub extern "C" fn __muldf3(a: f64, b: f64) -> f64 { diff --git a/library/compiler-builtins/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/compiler-builtins/src/float/pow.rs index dac768f7be3e5..fe76060e0faa8 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/pow.rs @@ -26,17 +26,14 @@ fn pow(a: F, b: i32) -> F { } intrinsics! { - #[avr_skip] pub extern "C" fn __powisf2(a: f32, b: i32) -> f32 { pow(a, b) } - #[avr_skip] pub extern "C" fn __powidf2(a: f64, b: i32) -> f64 { pow(a, b) } - #[avr_skip] #[ppc_alias = __powikf2] #[cfg(f128_enabled)] // FIXME(f16_f128): MSVC cannot build these until `__divtf3` is available in nightly. diff --git a/library/compiler-builtins/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/compiler-builtins/src/float/sub.rs index 175b3a1650027..a0fd9dff97fcf 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/sub.rs @@ -1,13 +1,11 @@ use crate::float::Float; intrinsics! { - #[avr_skip] #[arm_aeabi_alias = __aeabi_fsub] pub extern "C" fn __subsf3(a: f32, b: f32) -> f32 { crate::float::add::__addsf3(a, f32::from_bits(b.to_bits() ^ f32::SIGN_MASK)) } - #[avr_skip] #[arm_aeabi_alias = __aeabi_dsub] pub extern "C" fn __subdf3(a: f64, b: f64) -> f64 { crate::float::add::__adddf3(a, f64::from_bits(b.to_bits() ^ f64::SIGN_MASK)) diff --git a/library/compiler-builtins/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/compiler-builtins/src/float/trunc.rs index 928eba0c8ef36..ca8a0f368b563 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/trunc.rs @@ -115,7 +115,6 @@ where } intrinsics! { - #[avr_skip] #[aapcs_on_arm] #[arm_aeabi_alias = __aeabi_d2f] pub extern "C" fn __truncdfsf2(a: f64) -> f32 { @@ -124,7 +123,6 @@ intrinsics! { } intrinsics! { - #[avr_skip] #[aapcs_on_arm] #[apple_f16_ret_abi] #[arm_aeabi_alias = __aeabi_f2h] @@ -133,7 +131,6 @@ intrinsics! { trunc(a) } - #[avr_skip] #[aapcs_on_arm] #[apple_f16_ret_abi] #[cfg(f16_enabled)] @@ -141,7 +138,6 @@ intrinsics! { trunc(a) } - #[avr_skip] #[aapcs_on_arm] #[apple_f16_ret_abi] #[arm_aeabi_alias = __aeabi_d2h] @@ -150,7 +146,6 @@ intrinsics! { trunc(a) } - #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __trunckfhf2] #[cfg(all(f16_enabled, f128_enabled))] @@ -158,7 +153,6 @@ intrinsics! { trunc(a) } - #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __trunckfsf2] #[cfg(f128_enabled)] @@ -166,7 +160,6 @@ intrinsics! { trunc(a) } - #[avr_skip] #[aapcs_on_arm] #[ppc_alias = __trunckfdf2] #[cfg(f128_enabled)] diff --git a/library/compiler-builtins/compiler-builtins/src/int/bswap.rs b/library/compiler-builtins/compiler-builtins/src/int/bswap.rs index 9df80204d0e6b..3ede08882dc90 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/bswap.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/bswap.rs @@ -1,20 +1,17 @@ intrinsics! { #[maybe_use_optimized_c_shim] - #[avr_skip] /// Swaps bytes in 32-bit number pub extern "C" fn __bswapsi2(x: u32) -> u32 { x.swap_bytes() } #[maybe_use_optimized_c_shim] - #[avr_skip] /// Swaps bytes in 64-bit number pub extern "C" fn __bswapdi2(x: u64) -> u64 { x.swap_bytes() } #[maybe_use_optimized_c_shim] - #[avr_skip] /// Swaps bytes in 128-bit number pub extern "C" fn __bswapti2(x: u128) -> u128 { x.swap_bytes() diff --git a/library/compiler-builtins/compiler-builtins/src/int/sdiv.rs b/library/compiler-builtins/compiler-builtins/src/int/sdiv.rs index 9630c7d7de374..6a9029de7f287 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/sdiv.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/sdiv.rs @@ -9,7 +9,6 @@ macro_rules! sdivmod { $($attr:tt),* // attributes ) => { intrinsics! { - #[avr_skip] $( #[$attr] )* @@ -19,15 +18,18 @@ macro_rules! sdivmod { let b_neg = b < 0; let mut a = a; let mut b = b; + if a_neg { a = a.wrapping_neg(); } if b_neg { b = b.wrapping_neg(); } + let mut r = *rem as $uX; let t = $unsigned_fn(a as $uX, b as $uX, Some(&mut r)) as $iX; let mut r = r as $iX; + if a_neg { r = r.wrapping_neg(); } @@ -51,7 +53,6 @@ macro_rules! sdiv { $($attr:tt),* // attributes ) => { intrinsics! { - #[avr_skip] $( #[$attr] )* @@ -87,7 +88,6 @@ macro_rules! smod { $($attr:tt),* // attributes ) => { intrinsics! { - #[avr_skip] $( #[$attr] )* @@ -114,6 +114,7 @@ macro_rules! smod { } } +#[cfg(not(target_arch = "avr"))] sdivmod!( __udivmodsi4, __divmodsi4, @@ -121,6 +122,41 @@ sdivmod!( i32, maybe_use_optimized_c_shim ); + +#[cfg(target_arch = "avr")] +intrinsics! { + /// Returns `a / b` and `a % b` packed together. + /// + /// Ideally we'd use `-> (u32, u32)` or some kind of a packed struct, but + /// both force a stack allocation, while our result has to be in R18:R26. + pub extern "C" fn __divmodsi4(a: i32, b: i32) -> u64 { + let a_neg = a < 0; + let b_neg = b < 0; + let mut a = a; + let mut b = b; + + if a_neg { + a = a.wrapping_neg(); + } + if b_neg { + b = b.wrapping_neg(); + } + + let tr = __udivmodsi4(a as u32, b as u32); + let mut t = tr as u32 as i32; + let mut r = (tr >> 32) as u32 as i32; + + if a_neg { + r = r.wrapping_neg(); + } + if a_neg != b_neg { + t = t.wrapping_neg(); + } + + ((r as u32 as u64) << 32) | (t as u32 as u64) + } +} + // The `#[arm_aeabi_alias = __aeabi_idiv]` attribute cannot be made to work with `intrinsics!` in macros intrinsics! { #[maybe_use_optimized_c_shim] diff --git a/library/compiler-builtins/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/compiler-builtins/src/int/shift.rs index 317272988ce6a..a85c1b33d6714 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/shift.rs @@ -69,56 +69,47 @@ impl Lshr for u64 {} impl Lshr for u128 {} intrinsics! { - #[avr_skip] #[maybe_use_optimized_c_shim] pub extern "C" fn __ashlsi3(a: u32, b: u32) -> u32 { a.ashl(b) } - #[avr_skip] #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_llsl] pub extern "C" fn __ashldi3(a: u64, b: core::ffi::c_uint) -> u64 { a.ashl(b as u32) } - #[avr_skip] pub extern "C" fn __ashlti3(a: u128, b: u32) -> u128 { a.ashl(b) } - #[avr_skip] #[maybe_use_optimized_c_shim] pub extern "C" fn __ashrsi3(a: i32, b: u32) -> i32 { a.ashr(b) } - #[avr_skip] #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_lasr] pub extern "C" fn __ashrdi3(a: i64, b: core::ffi::c_uint) -> i64 { a.ashr(b as u32) } - #[avr_skip] pub extern "C" fn __ashrti3(a: i128, b: u32) -> i128 { a.ashr(b) } - #[avr_skip] #[maybe_use_optimized_c_shim] pub extern "C" fn __lshrsi3(a: u32, b: u32) -> u32 { a.lshr(b) } - #[avr_skip] #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_llsr] pub extern "C" fn __lshrdi3(a: u64, b: core::ffi::c_uint) -> u64 { a.lshr(b as u32) } - #[avr_skip] pub extern "C" fn __lshrti3(a: u128, b: u32) -> u128 { a.lshr(b) } diff --git a/library/compiler-builtins/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/compiler-builtins/src/int/udiv.rs index 1fa761212b2f2..a5c16040a52a2 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/udiv.rs @@ -17,8 +17,10 @@ intrinsics! { pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 { u32_div_rem(n, d).1 } +} - #[avr_skip] +#[cfg(not(target_arch = "avr"))] +intrinsics! { #[maybe_use_optimized_c_shim] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 { @@ -28,22 +30,34 @@ intrinsics! { } quo_rem.0 } +} + +#[cfg(target_arch = "avr")] +intrinsics! { + /// Returns `n / d` and `n % d` packed together. + /// + /// Ideally we'd use `-> (u32, u32)` or some kind of a packed struct, but + /// both force a stack allocation, while our result has to be in R18:R26. + pub extern "C" fn __udivmodsi4(n: u32, d: u32) -> u64 { + let (div, rem) = u32_div_rem(n, d); - #[avr_skip] + ((rem as u64) << 32) | (div as u64) + } +} + +intrinsics! { #[maybe_use_optimized_c_shim] /// Returns `n / d` pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { u64_div_rem(n, d).0 } - #[avr_skip] #[maybe_use_optimized_c_shim] /// Returns `n % d` pub extern "C" fn __umoddi3(n: u64, d: u64) -> u64 { u64_div_rem(n, d).1 } - #[avr_skip] #[maybe_use_optimized_c_shim] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { @@ -57,7 +71,6 @@ intrinsics! { // Note: we use block configuration and not `if cfg!(...)`, because we need to entirely disable // the existence of `u128_div_rem` to get 32-bit SPARC to compile, see `u128_divide_sparc` docs. - #[avr_skip] /// Returns `n / d` pub extern "C" fn __udivti3(n: u128, d: u128) -> u128 { #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] { @@ -68,7 +81,6 @@ intrinsics! { } } - #[avr_skip] /// Returns `n % d` pub extern "C" fn __umodti3(n: u128, d: u128) -> u128 { #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] { @@ -81,7 +93,6 @@ intrinsics! { } } - #[avr_skip] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmodti4(n: u128, d: u128, rem: Option<&mut u128>) -> u128 { #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] { diff --git a/library/compiler-builtins/compiler-builtins/src/macros.rs b/library/compiler-builtins/compiler-builtins/src/macros.rs index b1b71379cc917..0397e4551fba4 100644 --- a/library/compiler-builtins/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/compiler-builtins/src/macros.rs @@ -445,35 +445,6 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); - // For some intrinsics, AVR uses a custom calling convention¹ that does not - // match our definitions here. Ideally we would just use hand-written naked - // functions, but that's quite a lot of code to port² - so for the time - // being we are just ignoring the problematic functions, letting avr-gcc - // (which is required to compile to AVR anyway) link them from libgcc. - // - // ¹ https://gcc.gnu.org/wiki/avr-gcc (see "Exceptions to the Calling - // Convention") - // ² https://github.com/gcc-mirror/gcc/blob/31048012db98f5ec9c2ba537bfd850374bdd771f/libgcc/config/avr/lib1funcs.S - ( - #[avr_skip] - $(#[$($attr:tt)*])* - pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { - $($body:tt)* - } - - $($rest:tt)* - ) => ( - #[cfg(not(target_arch = "avr"))] - intrinsics! { - $(#[$($attr)*])* - pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - $($body)* - } - } - - intrinsics!($($rest)*); - ); - // This is the final catch-all rule. At this point we generate an // intrinsic with a conditional `#[no_mangle]` directive to avoid // interfering with duplicate symbols and whatnot during testing. diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/testcrate/tests/misc.rs index f5ac2ab7da1bb..edbd3684d47ad 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/testcrate/tests/misc.rs @@ -175,7 +175,6 @@ fn trailing_zeros() { } #[test] -#[cfg(not(target_arch = "avr"))] fn bswap() { use compiler_builtins::int::bswap::{__bswapdi2, __bswapsi2}; fuzz(N, |x: u32| { From c56c2b7a0db7e0c4a3d1c659af67386f0d1ad648 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 19 Aug 2024 15:20:02 +0200 Subject: [PATCH 1753/4206] Rename `is_like_osx` to `is_like_darwin` --- src/abi/mod.rs | 2 +- src/constant.rs | 2 +- src/debuginfo/mod.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/abi/mod.rs b/src/abi/mod.rs index e8076ce77abcf..ddd119e0c6108 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -641,7 +641,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( .flat_map(|arg_abi| arg_abi.get_abi_param(fx.tcx).into_iter()), ); - if fx.tcx.sess.target.is_like_osx && fx.tcx.sess.target.arch == "aarch64" { + if fx.tcx.sess.target.is_like_darwin && fx.tcx.sess.target.arch == "aarch64" { // Add any padding arguments needed for Apple AArch64. // There's no need to pad the argument list unless variadic arguments are actually being // passed. diff --git a/src/constant.rs b/src/constant.rs index bcc70f4567fbd..c8527c3a57dfe 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -391,7 +391,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant data.set_align(alloc.align.bytes()); if let Some(section_name) = section_name { - let (segment_name, section_name) = if tcx.sess.target.is_like_osx { + let (segment_name, section_name) = if tcx.sess.target.is_like_darwin { // See https://github.com/llvm/llvm-project/blob/main/llvm/lib/MC/MCSectionMachO.cpp let mut parts = section_name.as_str().split(','); let Some(segment_name) = parts.next() else { diff --git a/src/debuginfo/mod.rs b/src/debuginfo/mod.rs index bba6567774d7e..286e02b986b3c 100644 --- a/src/debuginfo/mod.rs +++ b/src/debuginfo/mod.rs @@ -58,7 +58,7 @@ impl DebugContext { // FIXME this should be configurable // macOS doesn't seem to support DWARF > 3 // 5 version is required for md5 file hash - version: if tcx.sess.target.is_like_osx { + version: if tcx.sess.target.is_like_darwin { 3 } else { // FIXME change to version 5 once the gdb and lldb shipping with the latest debian From 15dbafa81ee8dcf70ead827bb4991d5be8cd99de Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 30 Mar 2025 15:43:48 +0000 Subject: [PATCH 1754/4206] Merge commit 'ba315abda789c9f59f2100102232bddb30b0d3d3' into sync_cg_clif-2025-03-30 --- .cirrus.yml | 41 +- .github/actions/github-release/README.md | 18 - .github/actions/github-release/action.yml | 13 - .github/actions/github-release/main.js | 162 ----- .../actions/github-release/package-lock.json | 571 ------------------ .github/actions/github-release/package.json | 11 - .github/workflows/abi-cafe.yml | 12 +- .github/workflows/main.yml | 43 +- .github/workflows/rustc.yml | 6 - .vscode/settings.json | 33 +- .zed/settings.json | 25 +- Cargo.lock | 87 +-- Cargo.toml | 24 +- Readme.md | 2 +- build_system/prepare.rs | 7 + build_system/tests.rs | 49 +- config.txt | 2 +- docs/usage.md | 11 +- ...root_tests-128bit-atomic-operations.patch} | 12 +- ...coretests-Disable-long-running-tests.patch | 48 -- ...oot_tests-Disable-long-running-tests.patch | 105 ++++ ...le-f16-and-f128-in-compiler-builtins.patch | 26 - patches/coretests-lock.toml | 35 -- rust-toolchain | 2 +- scripts/cargo-clif.rs | 14 +- scripts/filter_profile.rs | 2 +- scripts/rustup.sh | 2 +- scripts/setup_rust_fork.sh | 23 + scripts/test_rustc_tests.sh | 58 +- src/base.rs | 6 +- src/common.rs | 18 +- src/config.rs | 34 +- src/debuginfo/types.rs | 4 +- src/driver/aot.rs | 2 +- src/driver/jit.rs | 225 +------ src/inline_asm.rs | 48 +- src/intrinsics/llvm.rs | 8 + src/intrinsics/llvm_aarch64.rs | 123 +++- src/lib.rs | 26 +- src/num.rs | 8 +- src/value_and_place.rs | 6 +- 41 files changed, 533 insertions(+), 1419 deletions(-) delete mode 100644 .github/actions/github-release/README.md delete mode 100644 .github/actions/github-release/action.yml delete mode 100644 .github/actions/github-release/main.js delete mode 100644 .github/actions/github-release/package-lock.json delete mode 100644 .github/actions/github-release/package.json rename patches/{0027-coretests-128bit-atomic-operations.patch => 0027-sysroot_tests-128bit-atomic-operations.patch} (84%) delete mode 100644 patches/0028-coretests-Disable-long-running-tests.patch create mode 100644 patches/0028-sysroot_tests-Disable-long-running-tests.patch delete mode 100644 patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch delete mode 100644 patches/coretests-lock.toml diff --git a/.cirrus.yml b/.cirrus.yml index 1ec99eb3d17a5..ee5de8b42f465 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,20 +1,21 @@ -task: - name: freebsd - freebsd_instance: - image: freebsd-13-2-release-amd64 - setup_rust_script: - - pkg install -y git-tiny binutils - - curl https://sh.rustup.rs -sSf --output rustup.sh - - sh rustup.sh --default-toolchain none -y --profile=minimal - target_cache: - folder: build/cg_clif - prepare_script: - - . $HOME/.cargo/env - - ./y.sh prepare - test_script: - - . $HOME/.cargo/env - # Disabling incr comp reduces cache size and incr comp doesn't save as much - # on CI anyway. - - export CARGO_BUILD_INCREMENTAL=false - # Skip rand as it fails on FreeBSD due to rust-random/rand#1355 - - ./y.sh test --skip-test test.rust-random/rand +# FIXME re-enable once https://github.com/rust-lang/rust/issues/134863 is fixed. +# task: +# name: freebsd +# freebsd_instance: +# image: freebsd-13-2-release-amd64 +# setup_rust_script: +# - pkg install -y git-tiny binutils +# - curl https://sh.rustup.rs -sSf --output rustup.sh +# - sh rustup.sh --default-toolchain none -y --profile=minimal +# target_cache: +# folder: build/cg_clif +# prepare_script: +# - . $HOME/.cargo/env +# - ./y.sh prepare +# test_script: +# - . $HOME/.cargo/env +# # Disabling incr comp reduces cache size and incr comp doesn't save as much +# # on CI anyway. +# - export CARGO_BUILD_INCREMENTAL=false +# # Skip rand as it fails on FreeBSD due to rust-random/rand#1355 +# - ./y.sh test --skip-test test.rust-random/rand diff --git a/.github/actions/github-release/README.md b/.github/actions/github-release/README.md deleted file mode 100644 index c70ba8f495387..0000000000000 --- a/.github/actions/github-release/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# github-release - -An action used to publish GitHub releases for `wasmtime`. - -As of the time of this writing there's a few actions floating around which -perform github releases but they all tend to have their set of drawbacks. -Additionally nothing handles deleting releases which we need for our rolling -`dev` release. - -To handle all this this action rolls-its-own implementation using the -actions/toolkit repository and packages published there. These run in a Docker -container and take various inputs to orchestrate the release from the build. - -More comments can be found in `main.js`. - -Testing this is really hard. If you want to try though run `npm install` and -then `node main.js`. You'll have to configure a bunch of env vars though to get -anything reasonably working. diff --git a/.github/actions/github-release/action.yml b/.github/actions/github-release/action.yml deleted file mode 100644 index 36e5209f50c3b..0000000000000 --- a/.github/actions/github-release/action.yml +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -name: 'rustc_codegen_cranelift github releases' -description: 'rustc_codegen_cranelift github releases' -inputs: - token: - description: '' - required: true - files: - description: '' - required: true -runs: - using: 'node16' - main: 'main.js' diff --git a/.github/actions/github-release/main.js b/.github/actions/github-release/main.js deleted file mode 100644 index 1eb2b7f23b26c..0000000000000 --- a/.github/actions/github-release/main.js +++ /dev/null @@ -1,162 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -const core = require('@actions/core'); -const path = require("path"); -const fs = require("fs"); -const github = require('@actions/github'); -const glob = require('glob'); - -function sleep(milliseconds) { - return new Promise(resolve => setTimeout(resolve, milliseconds)) -} - -async function runOnce() { - // Load all our inputs and env vars. Note that `getInput` reads from `INPUT_*` - const files = core.getInput('files'); - const token = core.getInput('token'); - const slug = process.env.GITHUB_REPOSITORY; - const owner = slug.split('/')[0]; - const repo = slug.split('/')[1]; - const sha = process.env.GITHUB_SHA; - let name = 'dev'; - if (process.env.GITHUB_REF.startsWith('refs/tags/v')) { - name = process.env.GITHUB_REF.substring(10); - } - - core.info(`files: ${files}`); - core.info(`name: ${name}`); - core.info(`token: ${token}`); - - const octokit = github.getOctokit(token); - - // For the `dev` release we may need to update the tag to point to the new - // commit on this branch. All other names should already have tags associated - // with them. - if (name == 'dev') { - let tag = null; - try { - tag = await octokit.request("GET /repos/:owner/:repo/git/refs/tags/:name", { owner, repo, name }); - core.info(`found existing tag`); - console.log("tag: ", JSON.stringify(tag.data, null, 2)); - } catch (e) { - // ignore if this tag doesn't exist - core.info(`no existing tag found`); - } - - if (tag === null || tag.data.object.sha !== sha) { - core.info(`updating existing tag or creating new one`); - - try { - core.info(`updating dev tag`); - await octokit.rest.git.updateRef({ - owner, - repo, - ref: 'tags/dev', - sha, - force: true, - }); - } catch (e) { - console.log("ERROR: ", JSON.stringify(e.response, null, 2)); - core.info(`creating dev tag`); - try { - await octokit.rest.git.createRef({ - owner, - repo, - ref: 'refs/tags/dev', - sha, - }); - } catch (e) { - // we might race with others, so assume someone else has created the - // tag by this point. - console.log("failed to create tag: ", JSON.stringify(e.response, null, 2)); - } - } - - console.log("double-checking tag is correct"); - tag = await octokit.request("GET /repos/:owner/:repo/git/refs/tags/:name", { owner, repo, name }); - if (tag.data.object.sha !== sha) { - console.log("tag: ", JSON.stringify(tag.data, null, 2)); - throw new Error("tag didn't work"); - } - } else { - core.info(`existing tag works`); - } - } - - // Delete a previous release - try { - core.info(`fetching release`); - let release = await octokit.rest.repos.getReleaseByTag({ owner, repo, tag: name }); - console.log("found release: ", JSON.stringify(release.data, null, 2)); - await octokit.rest.repos.deleteRelease({ - owner, - repo, - release_id: release.data.id, - }); - console.log("deleted release"); - } catch (e) { - console.log("ERROR: ", JSON.stringify(e, null, 2)); - } - - console.log("creating a release"); - let release = await octokit.rest.repos.createRelease({ - owner, - repo, - tag_name: name, - prerelease: name === 'dev', - }); - - // Delete all assets from a previous run - for (const asset of release.data.assets) { - console.log(`deleting prior asset ${asset.id}`); - await octokit.rest.repos.deleteReleaseAsset({ - owner, - repo, - asset_id: asset.id, - }); - } - - // Upload all the relevant assets for this release as just general blobs. - for (const file of glob.sync(files)) { - const size = fs.statSync(file).size; - const name = path.basename(file); - core.info(`upload ${file}`); - await octokit.rest.repos.uploadReleaseAsset({ - data: fs.createReadStream(file), - headers: { 'content-length': size, 'content-type': 'application/octet-stream' }, - name, - url: release.data.upload_url, - }); - } -} - -async function run() { - const retries = 10; - for (let i = 0; i < retries; i++) { - try { - await runOnce(); - break; - } catch (e) { - if (i === retries - 1) - throw e; - logError(e); - console.log("RETRYING after 10s"); - await sleep(10000) - } - } -} - -function logError(e) { - console.log("ERROR: ", e.message); - try { - console.log(JSON.stringify(e, null, 2)); - } catch (e) { - // ignore json errors for now - } - console.log(e.stack); -} - -run().catch(err => { - logError(err); - core.setFailed(err.message); -}); diff --git a/.github/actions/github-release/package-lock.json b/.github/actions/github-release/package-lock.json deleted file mode 100644 index dd3b2a048f094..0000000000000 --- a/.github/actions/github-release/package-lock.json +++ /dev/null @@ -1,571 +0,0 @@ -{ - "name": "rustc_codegen_cranelift-github-release", - "version": "0.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "rustc_codegen_cranelift-github-release", - "version": "0.0.0", - "dependencies": { - "@actions/core": "^1.9.1", - "@actions/github": "^5.1.0", - "glob": "^7.1.5" - } - }, - "node_modules/@actions/core": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz", - "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==", - "dependencies": { - "@actions/http-client": "^2.0.1", - "uuid": "^8.3.2" - } - }, - "node_modules/@actions/github": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.0.tgz", - "integrity": "sha512-tuI80F7JQIhg77ZTTgUAPpVD7ZnP9oHSPN8xw7LOwtA4vEMbAjWJNbmLBfV7xua7r016GyjzWLuec5cs8f/a8A==", - "dependencies": { - "@actions/http-client": "^2.0.1", - "@octokit/core": "^3.6.0", - "@octokit/plugin-paginate-rest": "^2.17.0", - "@octokit/plugin-rest-endpoint-methods": "^5.13.0" - } - }, - "node_modules/@actions/http-client": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz", - "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==", - "dependencies": { - "tunnel": "^0.0.6" - } - }, - "node_modules/@octokit/auth-token": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", - "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", - "dependencies": { - "@octokit/types": "^6.0.3" - } - }, - "node_modules/@octokit/core": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz", - "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==", - "dependencies": { - "@octokit/auth-token": "^2.4.4", - "@octokit/graphql": "^4.5.8", - "@octokit/request": "^5.6.3", - "@octokit/request-error": "^2.0.5", - "@octokit/types": "^6.0.3", - "before-after-hook": "^2.2.0", - "universal-user-agent": "^6.0.0" - } - }, - "node_modules/@octokit/endpoint": { - "version": "6.0.12", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", - "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", - "dependencies": { - "@octokit/types": "^6.0.3", - "is-plain-object": "^5.0.0", - "universal-user-agent": "^6.0.0" - } - }, - "node_modules/@octokit/graphql": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", - "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", - "dependencies": { - "@octokit/request": "^5.6.0", - "@octokit/types": "^6.0.3", - "universal-user-agent": "^6.0.0" - } - }, - "node_modules/@octokit/openapi-types": { - "version": "12.11.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz", - "integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==" - }, - "node_modules/@octokit/plugin-paginate-rest": { - "version": "2.21.3", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz", - "integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==", - "dependencies": { - "@octokit/types": "^6.40.0" - }, - "peerDependencies": { - "@octokit/core": ">=2" - } - }, - "node_modules/@octokit/plugin-rest-endpoint-methods": { - "version": "5.16.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz", - "integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==", - "dependencies": { - "@octokit/types": "^6.39.0", - "deprecation": "^2.3.1" - }, - "peerDependencies": { - "@octokit/core": ">=3" - } - }, - "node_modules/@octokit/request": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz", - "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==", - "dependencies": { - "@octokit/endpoint": "^6.0.1", - "@octokit/request-error": "^2.1.0", - "@octokit/types": "^6.16.1", - "is-plain-object": "^5.0.0", - "node-fetch": "^2.6.7", - "universal-user-agent": "^6.0.0" - } - }, - "node_modules/@octokit/request-error": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", - "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", - "dependencies": { - "@octokit/types": "^6.0.3", - "deprecation": "^2.0.0", - "once": "^1.4.0" - } - }, - "node_modules/@octokit/types": { - "version": "6.41.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz", - "integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==", - "dependencies": { - "@octokit/openapi-types": "^12.11.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/before-after-hook": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", - "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==" - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "node_modules/deprecation": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", - "engines": { - "node": ">=0.6.11 <=0.7.0 || >=0.7.3" - } - }, - "node_modules/universal-user-agent": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - } - }, - "dependencies": { - "@actions/core": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz", - "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==", - "requires": { - "@actions/http-client": "^2.0.1", - "uuid": "^8.3.2" - } - }, - "@actions/github": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.0.tgz", - "integrity": "sha512-tuI80F7JQIhg77ZTTgUAPpVD7ZnP9oHSPN8xw7LOwtA4vEMbAjWJNbmLBfV7xua7r016GyjzWLuec5cs8f/a8A==", - "requires": { - "@actions/http-client": "^2.0.1", - "@octokit/core": "^3.6.0", - "@octokit/plugin-paginate-rest": "^2.17.0", - "@octokit/plugin-rest-endpoint-methods": "^5.13.0" - } - }, - "@actions/http-client": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz", - "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==", - "requires": { - "tunnel": "^0.0.6" - } - }, - "@octokit/auth-token": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", - "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", - "requires": { - "@octokit/types": "^6.0.3" - } - }, - "@octokit/core": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz", - "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==", - "requires": { - "@octokit/auth-token": "^2.4.4", - "@octokit/graphql": "^4.5.8", - "@octokit/request": "^5.6.3", - "@octokit/request-error": "^2.0.5", - "@octokit/types": "^6.0.3", - "before-after-hook": "^2.2.0", - "universal-user-agent": "^6.0.0" - } - }, - "@octokit/endpoint": { - "version": "6.0.12", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", - "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", - "requires": { - "@octokit/types": "^6.0.3", - "is-plain-object": "^5.0.0", - "universal-user-agent": "^6.0.0" - } - }, - "@octokit/graphql": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", - "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", - "requires": { - "@octokit/request": "^5.6.0", - "@octokit/types": "^6.0.3", - "universal-user-agent": "^6.0.0" - } - }, - "@octokit/openapi-types": { - "version": "12.11.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz", - "integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==" - }, - "@octokit/plugin-paginate-rest": { - "version": "2.21.3", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz", - "integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==", - "requires": { - "@octokit/types": "^6.40.0" - } - }, - "@octokit/plugin-rest-endpoint-methods": { - "version": "5.16.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz", - "integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==", - "requires": { - "@octokit/types": "^6.39.0", - "deprecation": "^2.3.1" - } - }, - "@octokit/request": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz", - "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==", - "requires": { - "@octokit/endpoint": "^6.0.1", - "@octokit/request-error": "^2.1.0", - "@octokit/types": "^6.16.1", - "is-plain-object": "^5.0.0", - "node-fetch": "^2.6.7", - "universal-user-agent": "^6.0.0" - } - }, - "@octokit/request-error": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", - "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", - "requires": { - "@octokit/types": "^6.0.3", - "deprecation": "^2.0.0", - "once": "^1.4.0" - } - }, - "@octokit/types": { - "version": "6.41.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz", - "integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==", - "requires": { - "@octokit/openapi-types": "^12.11.0" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "before-after-hook": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", - "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "deprecation": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { - "wrappy": "1" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" - }, - "universal-user-agent": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - } - } -} diff --git a/.github/actions/github-release/package.json b/.github/actions/github-release/package.json deleted file mode 100644 index d9c23f8873ece..0000000000000 --- a/.github/actions/github-release/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "rustc_codegen_cranelift-github-release", - "version": "0.0.0", - "license": "Apache-2.0 WITH LLVM-exception", - "main": "main.js", - "dependencies": { - "@actions/core": "^1.9.1", - "@actions/github": "^5.1.0", - "glob": "^7.1.5" - } -} diff --git a/.github/workflows/abi-cafe.yml b/.github/workflows/abi-cafe.yml index 30dc5cb16154b..6ad041a796c92 100644 --- a/.github/workflows/abi-cafe.yml +++ b/.github/workflows/abi-cafe.yml @@ -25,7 +25,10 @@ jobs: - os: ubuntu-latest env: TARGET_TRIPLE: x86_64-unknown-linux-gnu - - os: macos-latest + - os: ubuntu-24.04-arm + env: + TARGET_TRIPLE: aarch64-unknown-linux-gnu + - os: macos-13 env: TARGET_TRIPLE: x86_64-apple-darwin - os: macos-latest @@ -56,13 +59,6 @@ jobs: if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' run: rustup set default-host x86_64-pc-windows-gnu - - name: Use x86_64 compiler on macOS - if: matrix.os == 'macos-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-apple-darwin' - run: rustup set default-host x86_64-apple-darwin - - - name: Prepare dependencies - run: ./y.sh prepare - - name: Build run: ./y.sh build --sysroot none diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 61a4c1270c993..6fd288d195c05 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -53,13 +53,12 @@ jobs: - os: ubuntu-latest env: TARGET_TRIPLE: x86_64-unknown-linux-gnu - - os: macos-latest - env: - TARGET_TRIPLE: x86_64-apple-darwin - - os: ubuntu-latest + - os: ubuntu-24.04-arm env: TARGET_TRIPLE: aarch64-unknown-linux-gnu - apt_deps: gcc-aarch64-linux-gnu qemu-user + - os: macos-13 + env: + TARGET_TRIPLE: x86_64-apple-darwin - os: macos-latest env: TARGET_TRIPLE: aarch64-apple-darwin @@ -95,10 +94,6 @@ jobs: if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' run: rustup set default-host x86_64-pc-windows-gnu - - name: Use x86_64 compiler on macOS - if: matrix.os == 'macos-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-apple-darwin' - run: rustup set default-host x86_64-apple-darwin - - name: Install toolchain and emulator if: matrix.apt_deps != null run: | @@ -170,9 +165,6 @@ jobs: sudo apt update sudo apt install -y hyperfine - - name: Prepare dependencies - run: ./y.sh prepare - - name: Build run: ./y.sh build --sysroot none @@ -192,7 +184,10 @@ jobs: - os: ubuntu-22.04 env: TARGET_TRIPLE: x86_64-unknown-linux-gnu - - os: macos-latest + - os: ubuntu-24.04-arm + env: + TARGET_TRIPLE: aarch64-unknown-linux-gnu + - os: macos-13 env: TARGET_TRIPLE: x86_64-apple-darwin - os: macos-latest @@ -218,13 +213,6 @@ jobs: if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' run: rustup set default-host x86_64-pc-windows-gnu - - name: Use x86_64 compiler on macOS - if: matrix.os == 'macos-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-apple-darwin' - run: rustup set default-host x86_64-apple-darwin - - - name: Prepare dependencies - run: ./y.sh prepare - - name: Build backend run: ./y.sh build --sysroot none @@ -273,12 +261,9 @@ jobs: rmdir artifacts/ # verify all artifacts are represented in release/ ls -R release/ - - run: npm install --production - working-directory: .github/actions/github-release - - - name: Publish Release - uses: ./.github/actions/github-release - with: - files: "release/*" - token: ${{ github.token }} - continue-on-error: true + - name: Publish release + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release delete --cleanup-tag -y dev || true + gh release create --target $GITHUB_SHA --prerelease dev release/* diff --git a/.github/workflows/rustc.yml b/.github/workflows/rustc.yml index 70c214ce8b147..9253ab96353c3 100644 --- a/.github/workflows/rustc.yml +++ b/.github/workflows/rustc.yml @@ -22,9 +22,6 @@ jobs: path: build/cg_clif key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain', 'Cargo.lock') }} - - name: Prepare dependencies - run: ./y.sh prepare - - name: Test run: ./scripts/test_bootstrap.sh @@ -50,8 +47,5 @@ jobs: sudo apt update sudo apt install -y ripgrep - - name: Prepare dependencies - run: ./y.sh prepare - - name: Test run: ./scripts/test_rustc_tests.sh diff --git a/.vscode/settings.json b/.vscode/settings.json index 491646ce59bb3..68bd93aea8901 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,41 +1,40 @@ { "editor.formatOnSave": true, - // in case rustc.source is disabled for performance reasons; disable the errors about this - "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "unresolved-macro-call"], + "rust-analyzer.diagnostics.disabled": [ + "unresolved-extern-crate", + "unresolved-macro-call" + ], "rust-analyzer.rustc.source": "discover", "rust-analyzer.imports.granularity.enforce": true, "rust-analyzer.imports.granularity.group": "module", "rust-analyzer.imports.prefix": "crate", - "rust-analyzer.cargo.features": ["unstable-features"], + "rust-analyzer.cargo.features": [ + "unstable-features" + ], "rust-analyzer.linkedProjects": [ "./Cargo.toml", "./build_system/Cargo.toml", { + "sysroot_src": "./build/stdlib/library", "crates": [ { "root_module": "./example/mini_core.rs", - "edition": "2018", + "edition": "2015", "deps": [], "cfg": [], }, { "root_module": "./example/mini_core_hello_world.rs", - "edition": "2018", - "deps": [{ "crate": 0, "name": "mini_core" }], - "cfg": [], - }, - { - "root_module": "./example/mod_bench.rs", - "edition": "2018", - "deps": [], + "edition": "2015", + "deps": [ + { + "crate": 0, + "name": "mini_core" + } + ], "cfg": [], }, - ] - }, - { - "sysroot_src": "./build/stdlib/library", - "crates": [ { "root_module": "./example/std_example.rs", "edition": "2015", diff --git a/.zed/settings.json b/.zed/settings.json index e93bed3694921..4338a3473311b 100644 --- a/.zed/settings.json +++ b/.zed/settings.json @@ -5,7 +5,10 @@ "initialization_options": { "diagnostics": { // in case rustc.source is disabled for performance reasons; disable the errors about this - "disabled": ["unresolved-extern-crate", "unresolved-macro-call"] + "disabled": [ + "unresolved-extern-crate", + "unresolved-macro-call" + ] }, "rustc": { "source": "discover" @@ -18,22 +21,25 @@ "prefix": "crate" }, "cargo": { - "features": ["unstable-features"] + "features": [ + "unstable-features" + ] }, "linkedProjects": [ "./Cargo.toml", "./build_system/Cargo.toml", { + "sysroot_src": "./build/stdlib/library", "crates": [ { "root_module": "./example/mini_core.rs", - "edition": "2018", + "edition": "2015", "deps": [], "cfg": [] }, { "root_module": "./example/mini_core_hello_world.rs", - "edition": "2018", + "edition": "2015", "deps": [ { "crate": 0, @@ -42,17 +48,6 @@ ], "cfg": [] }, - { - "root_module": "./example/mod_bench.rs", - "edition": "2018", - "deps": [], - "cfg": [] - } - ] - }, - { - "sysroot_src": "./build/stdlib/library", - "crates": [ { "root_module": "./example/std_example.rs", "edition": "2015", diff --git a/Cargo.lock b/Cargo.lock index ca66ec5c6e930..e5f1896b9230b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,28 +41,44 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cranelift-assembler-x64" +version = "0.118.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4b56ebe316895d3fa37775d0a87b0c889cc933f5c8b253dbcc7c7bcb7fe7e4" +dependencies = [ + "cranelift-assembler-x64-meta", +] + +[[package]] +name = "cranelift-assembler-x64-meta" +version = "0.118.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95cabbc01dfbd7dcd6c329ca44f0212910309c221797ac736a67a5bc8857fe1b" + [[package]] name = "cranelift-bforest" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e15d04a0ce86cb36ead88ad68cf693ffd6cda47052b9e0ac114bc47fd9cd23c4" +checksum = "76ffe46df300a45f1dc6f609dc808ce963f0e3a2e971682c479a2d13e3b9b8ef" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c6e3969a7ce267259ce244b7867c5d3bc9e65b0a87e81039588dfdeaede9f34" +checksum = "b265bed7c51e1921fdae6419791d31af77d33662ee56d7b0fa0704dc8d231cab" [[package]] name = "cranelift-codegen" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c22032c4cb42558371cf516bb47f26cdad1819d3475c133e93c49f50ebf304e" +checksum = "e606230a7e3a6897d603761baee0d19f88d077f17b996bb5089488a29ae96e41" dependencies = [ "bumpalo", + "cranelift-assembler-x64", "cranelift-bforest", "cranelift-bitset", "cranelift-codegen-meta", @@ -71,7 +87,7 @@ dependencies = [ "cranelift-entity", "cranelift-isle", "gimli", - "hashbrown 0.14.5", + "hashbrown", "log", "regalloc2", "rustc-hash", @@ -82,42 +98,43 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c904bc71c61b27fc57827f4a1379f29de64fe95653b620a3db77d59655eee0b8" +checksum = "8a63bffafc23bc60969ad528e138788495999d935f0adcfd6543cb151ca8637d" dependencies = [ + "cranelift-assembler-x64", "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40180f5497572f644ce88c255480981ae2ec1d7bb4d8e0c0136a13b87a2f2ceb" +checksum = "af50281b67324b58e843170a6a5943cf6d387c06f7eeacc9f5696e4ab7ae7d7e" [[package]] name = "cranelift-control" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d132c6d0bd8a489563472afc171759da0707804a65ece7ceb15a8c6d7dd5ef" +checksum = "8c20c1b38d1abfbcebb0032e497e71156c0e3b8dcb3f0a92b9863b7bcaec290c" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d0d9618275474fbf679dd018ac6e009acbd6ae6850f6a67be33fb3b00b323" +checksum = "0c2c67d95507c51b4a1ff3f3555fe4bfec36b9e13c1b684ccc602736f5d5f4a2" dependencies = [ "cranelift-bitset", ] [[package]] name = "cranelift-frontend" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fac41e16729107393174b0c9e3730fb072866100e1e64e80a1a963b2e484d57" +checksum = "4e002691cc69c38b54fc7ec93e5be5b744f627d027031d991cc845d1d512d0ce" dependencies = [ "cranelift-codegen", "log", @@ -127,15 +144,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca20d576e5070044d0a72a9effc2deacf4d6aa650403189d8ea50126483944d" +checksum = "e93588ed1796cbcb0e2ad160403509e2c5d330d80dd6e0014ac6774c7ebac496" [[package]] name = "cranelift-jit" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e65c42755a719b09662b00c700daaf76cc35d5ace1f5c002ad404b591ff1978" +checksum = "17f6682f0b193d6b7873cc8e7ed67e8776a8a26f50eeabf88534e9be618b9a03" dependencies = [ "anyhow", "cranelift-codegen", @@ -153,9 +170,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d55612bebcf16ff7306c8a6f5bdb6d45662b8aa1ee058ecce8807ad87db719b" +checksum = "ff19784c6de05116e63e6a34791012bd927b2a4eac56233039c46f1b6a4edac8" dependencies = [ "anyhow", "cranelift-codegen", @@ -164,9 +181,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8dee82f3f1f2c4cba9177f1cc5e350fe98764379bcd29340caa7b01f85076c7" +checksum = "e5b09bdd6407bf5d89661b80cf926ce731c9e8cc184bf49102267a2369a8358e" dependencies = [ "cranelift-codegen", "libc", @@ -175,9 +192,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aad5a6d3e379493c3f8b35dc61c93d0bf5f27003bbe20614e0200b0ec372ef52" +checksum = "685e8661a30d1cb69509f589ac643adeee79c5f63c0da316431b9fad29e6d3b4" dependencies = [ "anyhow", "cranelift-codegen", @@ -226,12 +243,6 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - [[package]] name = "hashbrown" version = "0.15.2" @@ -248,7 +259,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown", ] [[package]] @@ -295,7 +306,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "crc32fast", - "hashbrown 0.15.2", + "hashbrown", "indexmap", "memchr", ] @@ -326,7 +337,7 @@ checksum = "145c1c267e14f20fb0f88aa76a1c5ffec42d592c1d28b3cd9148ae35916158d3" dependencies = [ "allocator-api2", "bumpalo", - "hashbrown 0.15.2", + "hashbrown", "log", "rustc-hash", "smallvec", @@ -425,9 +436,9 @@ checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "wasmtime-jit-icache-coherence" -version = "29.0.1" +version = "31.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec5e8552e01692e6c2e5293171704fed8abdec79d1a6995a0870ab190e5747d1" +checksum = "a54f6c6c7e9d7eeee32dfcc10db7f29d505ee7dd28d00593ea241d5f70698e64" dependencies = [ "anyhow", "cfg-if", diff --git a/Cargo.toml b/Cargo.toml index 670d6f4eef5c1..08b60de14c1f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,12 +8,12 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.116.0", default-features = false, features = ["std", "unwind", "all-native-arch"] } -cranelift-frontend = { version = "0.116.0" } -cranelift-module = { version = "0.116.0" } -cranelift-native = { version = "0.116.0" } -cranelift-jit = { version = "0.116.0", optional = true } -cranelift-object = { version = "0.116.0" } +cranelift-codegen = { version = "0.118.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } +cranelift-frontend = { version = "0.118.0" } +cranelift-module = { version = "0.118.0" } +cranelift-native = { version = "0.118.0" } +cranelift-jit = { version = "0.118.0", optional = true } +cranelift-object = { version = "0.118.0" } target-lexicon = "0.13" gimli = { version = "0.31", default-features = false, features = ["write"] } object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } @@ -24,12 +24,12 @@ smallvec = "1.8.1" [patch.crates-io] # Uncomment to use an unreleased version of cranelift -#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-29.0.0", version = "0.116.0" } -#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-29.0.0", version = "0.116.0" } -#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-29.0.0", version = "0.116.0" } -#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-29.0.0", version = "0.116.0" } -#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-29.0.0", version = "0.116.0" } -#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-29.0.0", version = "0.116.0" } +#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-31.0.0", version = "0.118.0" } +#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-31.0.0", version = "0.118.0" } +#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-31.0.0", version = "0.118.0" } +#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-31.0.0", version = "0.118.0" } +#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-31.0.0", version = "0.118.0" } +#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-31.0.0", version = "0.118.0" } # Uncomment to use local checkout of cranelift #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" } diff --git a/Readme.md b/Readme.md index 18a840f8a50e0..28edb5795ce3c 100644 --- a/Readme.md +++ b/Readme.md @@ -49,13 +49,13 @@ If you want to build the backend manually, you can download it from GitHub and b ```bash $ git clone https://github.com/rust-lang/rustc_codegen_cranelift $ cd rustc_codegen_cranelift -$ ./y.sh prepare $ ./y.sh build ``` To run the test suite replace the last command with: ```bash +$ ./y.sh prepare # only needs to be run the first time $ ./test.sh ``` diff --git a/build_system/prepare.rs b/build_system/prepare.rs index 11f73bdb61f97..ba5cc9a29f599 100644 --- a/build_system/prepare.rs +++ b/build_system/prepare.rs @@ -91,6 +91,13 @@ impl GitRepo { fn verify_checksum(&self, dirs: &Dirs) { let download_dir = self.download_dir(dirs); + if !download_dir.exists() { + eprintln!( + "Missing directory {download_dir}: Please run ./y.sh prepare to download.", + download_dir = download_dir.display(), + ); + std::process::exit(1); + } let actual_hash = format!("{:016x}", hash_dir(&download_dir)); if actual_hash != self.content_hash { eprintln!( diff --git a/build_system/tests.rs b/build_system/tests.rs index ea7e94c345ad0..122b541fa35f8 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -1,5 +1,4 @@ use std::ffi::OsStr; -use std::fs; use std::path::PathBuf; use std::process::Command; @@ -126,9 +125,9 @@ static PORTABLE_SIMD_SRC: RelPath = RelPath::build("portable-simd"); static PORTABLE_SIMD: CargoProject = CargoProject::new(&PORTABLE_SIMD_SRC, "portable-simd_target"); -static LIBCORE_TESTS_SRC: RelPath = RelPath::build("coretests"); +static SYSROOT_TESTS_SRC: RelPath = RelPath::build("sysroot_tests"); -static LIBCORE_TESTS: CargoProject = CargoProject::new(&LIBCORE_TESTS_SRC, "coretests_target"); +static SYSROOT_TESTS: CargoProject = CargoProject::new(&SYSROOT_TESTS_SRC, "sysroot_tests_target"); const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ TestCase::custom("test.rust-random/rand", &|runner| { @@ -147,28 +146,24 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ spawn_and_wait(build_cmd); } }), - TestCase::custom("test.libcore", &|runner| { + TestCase::custom("test.sysroot", &|runner| { apply_patches( &runner.dirs, - "coretests", - &runner.stdlib_source.join("library/coretests"), - &LIBCORE_TESTS_SRC.to_path(&runner.dirs), + "sysroot_tests", + &runner.stdlib_source.join("library"), + &SYSROOT_TESTS_SRC.to_path(&runner.dirs), ); - let source_lockfile = runner.dirs.source_dir.join("patches/coretests-lock.toml"); - let target_lockfile = LIBCORE_TESTS_SRC.to_path(&runner.dirs).join("Cargo.lock"); - fs::copy(source_lockfile, target_lockfile).unwrap(); - - LIBCORE_TESTS.clean(&runner.dirs); + SYSROOT_TESTS.clean(&runner.dirs); if runner.is_native { - let mut test_cmd = LIBCORE_TESTS.test(&runner.target_compiler, &runner.dirs); - test_cmd.arg("--").arg("-q"); + let mut test_cmd = SYSROOT_TESTS.test(&runner.target_compiler, &runner.dirs); + test_cmd.args(["-p", "coretests", "-p", "alloctests", "--", "-q"]); spawn_and_wait(test_cmd); } else { eprintln!("Cross-Compiling: Not running tests"); - let mut build_cmd = LIBCORE_TESTS.build(&runner.target_compiler, &runner.dirs); - build_cmd.arg("--tests"); + let mut build_cmd = SYSROOT_TESTS.build(&runner.target_compiler, &runner.dirs); + build_cmd.args(["-p", "coretests", "-p", "alloctests", "--tests"]); spawn_and_wait(build_cmd); } }), @@ -330,10 +325,8 @@ impl<'a> TestRunner<'a> { target_compiler.rustflags.extend(rustflags_from_env("RUSTFLAGS")); target_compiler.rustdocflags.extend(rustflags_from_env("RUSTDOCFLAGS")); - let jit_supported = use_unstable_features - && is_native - && target_compiler.triple.contains("x86_64") - && !target_compiler.triple.contains("windows"); + let jit_supported = + use_unstable_features && is_native && !target_compiler.triple.contains("windows"); Self { is_native, jit_supported, skip_tests, dirs, target_compiler, stdlib_source } } @@ -374,21 +367,7 @@ impl<'a> TestRunner<'a> { TestCaseCmd::JitBin { source, args } => { let mut jit_cmd = self.rustc_command([ "-Zunstable-options", - "-Cllvm-args=mode=jit", - "-Cprefer-dynamic", - source, - "--cfg", - "jit", - ]); - if !args.is_empty() { - jit_cmd.env("CG_CLIF_JIT_ARGS", args); - } - spawn_and_wait(jit_cmd); - - eprintln!("[JIT-lazy] {testname}"); - let mut jit_cmd = self.rustc_command([ - "-Zunstable-options", - "-Cllvm-args=mode=jit-lazy", + "-Cllvm-args=jit-mode", "-Cprefer-dynamic", source, "--cfg", diff --git a/config.txt b/config.txt index f578cbef35e68..714414fe8d685 100644 --- a/config.txt +++ b/config.txt @@ -35,6 +35,6 @@ aot.raw-dylib testsuite.extended_sysroot test.rust-random/rand -test.libcore +test.sysroot test.regex test.portable-simd diff --git a/docs/usage.md b/docs/usage.md index 135a51ce392b5..dbe36109f83e9 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -38,14 +38,7 @@ $ $cg_clif_dir/dist/cargo-clif jit or ```bash -$ $cg_clif_dir/dist/rustc-clif -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs -``` - -There is also an experimental lazy jit mode. In this mode functions are only compiled once they are -first called. - -```bash -$ $cg_clif_dir/dist/cargo-clif lazy-jit +$ $cg_clif_dir/dist/rustc-clif -Cllvm-args=jit-mode -Cprefer-dynamic my_crate.rs ``` ## Shell @@ -54,7 +47,7 @@ These are a few functions that allow you to easily run rust code from the shell ```bash function jit_naked() { - echo "$@" | $cg_clif_dir/dist/rustc-clif - -Zunstable-options -Cllvm-args=mode=jit-lazy -Cprefer-dynamic + echo "$@" | $cg_clif_dir/dist/rustc-clif - -Zunstable-options -Cllvm-args=jit-mode-Cprefer-dynamic } function jit() { diff --git a/patches/0027-coretests-128bit-atomic-operations.patch b/patches/0027-sysroot_tests-128bit-atomic-operations.patch similarity index 84% rename from patches/0027-coretests-128bit-atomic-operations.patch rename to patches/0027-sysroot_tests-128bit-atomic-operations.patch index 4a06dc3f7ef85..16c8488acdb56 100644 --- a/patches/0027-coretests-128bit-atomic-operations.patch +++ b/patches/0027-sysroot_tests-128bit-atomic-operations.patch @@ -10,20 +10,20 @@ Cranelift doesn't support them yet library/core/tests/atomic.rs | 4 --- 4 files changed, 4 insertions(+), 50 deletions(-) -diff --git a/tests/lib.rs b/tests/lib.rs +diff --git a/coretests/tests/lib.rs b/coretests/tests/lib.rs index 1e336bf..35e6f54 100644 ---- a/tests/lib.rs -+++ b/tests/lib.rs +--- a/coretests/tests/lib.rs ++++ b/coretests/tests/lib.rs @@ -2,5 +2,4 @@ // tidy-alphabetical-start -#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] #![cfg_attr(test, feature(cfg_match))] #![feature(alloc_layout_extra)] #![feature(array_chunks)] -diff --git a/tests/atomic.rs b/tests/atomic.rs +diff --git a/coretests/tests/atomic.rs b/coretests/tests/atomic.rs index b735957..ea728b6 100644 ---- a/tests/atomic.rs -+++ b/tests/atomic.rs +--- a/coretests/tests/atomic.rs ++++ b/coretests/tests/atomic.rs @@ -185,10 +185,6 @@ fn atomic_alignment() { assert_eq!(align_of::(), size_of::()); #[cfg(target_has_atomic = "64")] diff --git a/patches/0028-coretests-Disable-long-running-tests.patch b/patches/0028-coretests-Disable-long-running-tests.patch deleted file mode 100644 index f5ae66c0eb13d..0000000000000 --- a/patches/0028-coretests-Disable-long-running-tests.patch +++ /dev/null @@ -1,48 +0,0 @@ -From eb703e627e7a84f1cd8d0d87f0f69da1f0acf765 Mon Sep 17 00:00:00 2001 -From: bjorn3 -Date: Fri, 3 Dec 2021 12:16:30 +0100 -Subject: [PATCH] Disable long running tests - ---- - library/core/tests/slice.rs | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/tests/slice.rs b/tests/slice.rs -index 8402833..84592e0 100644 ---- a/tests/slice.rs -+++ b/tests/slice.rs -@@ -1809,6 +1809,7 @@ fn sort_unstable() { - } - } - -+/* - #[test] - #[cfg(not(target_arch = "wasm32"))] - #[cfg_attr(miri, ignore)] // Miri is too slow -@@ -1914,6 +1915,7 @@ fn select_nth_unstable() { - v.select_nth_unstable(0); - assert!(v == [0xDEADBEEF]); - } -+*/ - - #[test] - #[should_panic(expected = "index 0 greater than length of slice")] -@@ -2462,6 +2462,7 @@ take_tests! { - #[cfg(not(miri))] // unused in Miri - const EMPTY_MAX: &'static [()] = &[(); usize::MAX]; - -+/* - // can't be a constant due to const mutability rules - #[cfg(not(miri))] // unused in Miri - macro_rules! empty_max_mut { -@@ -2485,6 +2486,7 @@ take_tests! { - (split_off_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()), - (split_off_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()), - } -+*/ - - #[test] - fn test_slice_from_ptr_range() { --- -2.26.2.7.g19db9cfb68 - diff --git a/patches/0028-sysroot_tests-Disable-long-running-tests.patch b/patches/0028-sysroot_tests-Disable-long-running-tests.patch new file mode 100644 index 0000000000000..357b8d306cf6a --- /dev/null +++ b/patches/0028-sysroot_tests-Disable-long-running-tests.patch @@ -0,0 +1,105 @@ +From eb703e627e7a84f1cd8d0d87f0f69da1f0acf765 Mon Sep 17 00:00:00 2001 +From: bjorn3 +Date: Fri, 3 Dec 2021 12:16:30 +0100 +Subject: [PATCH] Disable long running tests + +--- + library/coretests/tests/slice.rs | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/coretests/tests/slice.rs b/coretests/tests/slice.rs +index 8402833..84592e0 100644 +--- a/coretests/tests/slice.rs ++++ b/coretests/tests/slice.rs +@@ -1809,6 +1809,7 @@ fn sort_unstable() { + } + } + ++/* + #[test] + #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr(miri, ignore)] // Miri is too slow +@@ -1914,6 +1915,7 @@ fn select_nth_unstable() { + v.select_nth_unstable(0); + assert!(v == [0xDEADBEEF]); + } ++*/ + + #[test] + #[should_panic(expected = "index 0 greater than length of slice")] +@@ -2462,6 +2462,7 @@ take_tests! { + #[cfg(not(miri))] // unused in Miri + const EMPTY_MAX: &'static [()] = &[(); usize::MAX]; + ++/* + // can't be a constant due to const mutability rules + #[cfg(not(miri))] // unused in Miri + macro_rules! empty_max_mut { +@@ -2485,6 +2486,7 @@ take_tests! { + (split_off_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()), + (split_off_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()), + } ++*/ + + #[test] + fn test_slice_from_ptr_range() { +diff --git a/alloctests/tests/sort/tests.rs b/alloctests/tests/sort/tests.rs +index d321f8d..8b2040a 100644 +--- a/alloctests/tests/sort/tests.rs ++++ b/alloctests/tests/sort/tests.rs +@@ -1,3 +1,5 @@ ++#![cfg(any())] ++ + use std::cell::Cell; + use std::cmp::Ordering; + use std::fmt::Debug; +diff --git a/alloctests/tests/str.rs b/alloctests/tests/str.rs +index 906fa2d..b82fa99 100644 +--- a/alloctests/tests/str.rs ++++ b/alloctests/tests/str.rs +@@ -2234,7 +2234,7 @@ fn const_str_ptr() { + const C: *const u8 = B as *const u8; + + // Miri does not deduplicate consts (https://github.com/rust-lang/miri/issues/131) +- #[cfg(not(miri))] ++ #[cfg(any())] + { + let foo = &A as *const u8; + assert_eq!(foo, C); +diff --git a/alloctests/tests/task.rs b/alloctests/tests/task.rs +index 390dec1..87df6e6 100644 +--- a/alloctests/tests/task.rs ++++ b/alloctests/tests/task.rs +@@ -4,7 +4,7 @@ use alloc::task::{LocalWake, Wake}; + use core::task::{LocalWaker, Waker}; + + #[test] +-#[cfg_attr(miri, ignore)] // `will_wake` doesn't guarantee that this test will work, and indeed on Miri it can fail ++#[ignore] // `will_wake` doesn't guarantee that this test will work, and indeed on Miri it can fail + fn test_waker_will_wake_clone() { + struct NoopWaker; + +@@ -20,7 +20,7 @@ fn test_waker_will_wake_clone() { + } + + #[test] +-#[cfg_attr(miri, ignore)] // `will_wake` doesn't guarantee that this test will work, and indeed on Miri it can fail ++#[ignore] // `will_wake` doesn't guarantee that this test will work, and indeed on Miri it can fail + fn test_local_waker_will_wake_clone() { + struct NoopWaker; + +diff --git a/alloctests/tests/vec.rs b/alloctests/tests/vec.rs +index f430d97..cfbd3cb 100644 +--- a/alloctests/tests/vec.rs ++++ b/alloctests/tests/vec.rs +@@ -762,6 +762,7 @@ fn test_drain_inclusive_range() { + } + + #[test] ++#[ignore] + fn test_drain_max_vec_size() { + let mut v = Vec::<()>::with_capacity(usize::MAX); + unsafe { +-- +2.26.2.7.g19db9cfb68 + diff --git a/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch b/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch deleted file mode 100644 index 34249ea483451..0000000000000 --- a/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 175d52c5e1779764b66777db1e6f172c2dc365ff Mon Sep 17 00:00:00 2001 -From: bjorn3 <17426603+bjorn3@users.noreply.github.com> -Date: Fri, 9 Aug 2024 15:44:51 +0000 -Subject: [PATCH] Disable f16 and f128 in compiler-builtins - ---- - library/liballoc/Cargo.toml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/library/liballoc/Cargo.toml b/library/liballoc/Cargo.toml -index 7165c3e48af..968552ad435 100644 ---- a/library/alloc/Cargo.toml -+++ b/library/alloc/Cargo.toml -@@ -11,7 +11,7 @@ test = { path = "../test" } - bench = false - - [dependencies] - core = { path = "../core", public = true } --compiler_builtins = { version = "=0.1.152", features = ['rustc-dep-of-std'] } -+compiler_builtins = { version = "=0.1.152", features = ['rustc-dep-of-std', 'no-f16-f128'] } - - [features] - compiler-builtins-mem = ['compiler_builtins/mem'] --- -2.34.1 - diff --git a/patches/coretests-lock.toml b/patches/coretests-lock.toml deleted file mode 100644 index af8f28a193bcd..0000000000000 --- a/patches/coretests-lock.toml +++ /dev/null @@ -1,35 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "coretests" -version = "0.0.0" -dependencies = [ - "rand", - "rand_xorshift", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" - -[[package]] -name = "rand_xorshift" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" -dependencies = [ - "rand_core", -] diff --git a/rust-toolchain b/rust-toolchain index 481903c6afb28..ceff15b1180a7 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-02-15" +channel = "nightly-2025-03-30" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" diff --git a/scripts/cargo-clif.rs b/scripts/cargo-clif.rs index ebbb687961058..e6c63bf5e6508 100644 --- a/scripts/cargo-clif.rs +++ b/scripts/cargo-clif.rs @@ -50,19 +50,7 @@ fn main() { .chain([ "--".to_string(), "-Zunstable-options".to_string(), - "-Cllvm-args=mode=jit".to_string(), - ]) - .collect() - } - Some("lazy-jit") => { - rustflags.push("-Cprefer-dynamic".to_owned()); - args.remove(0); - IntoIterator::into_iter(["rustc".to_string()]) - .chain(args) - .chain([ - "--".to_string(), - "-Zunstable-options".to_string(), - "-Cllvm-args=mode=jit-lazy".to_string(), + "-Cllvm-args=jit-mode".to_string(), ]) .collect() } diff --git a/scripts/filter_profile.rs b/scripts/filter_profile.rs index 0252d5b334036..4595063c032dc 100755 --- a/scripts/filter_profile.rs +++ b/scripts/filter_profile.rs @@ -4,7 +4,7 @@ pushd $(dirname "$0")/../ RUSTC="$(pwd)/dist/rustc-clif" popd -PROFILE=$1 OUTPUT=$2 exec $RUSTC -Zunstable-options -Cllvm-args=mode=jit -Cprefer-dynamic $0 +PROFILE=$1 OUTPUT=$2 exec $RUSTC -Zunstable-options -Cllvm-args=jit-mode -Cprefer-dynamic $0 #*/ //! This program filters away uninteresting samples and trims uninteresting frames for stackcollapse diff --git a/scripts/rustup.sh b/scripts/rustup.sh index 355282911c255..152c243aa6adc 100755 --- a/scripts/rustup.sh +++ b/scripts/rustup.sh @@ -64,7 +64,7 @@ case $1 in cg_clif=$(pwd) pushd ../rust git fetch origin master - git checkout "$RUST_VERS" + git -c advice.detachedHead=false checkout "$RUST_VERS" "$cg_clif/git-fixed-subtree.sh" push --prefix=compiler/rustc_codegen_cranelift/ "$cg_clif" sync_from_rust popd git merge sync_from_rust -m "Sync from rust $RUST_VERS" diff --git a/scripts/setup_rust_fork.sh b/scripts/setup_rust_fork.sh index 54f6baff4fecf..ca6426f2ba9d3 100644 --- a/scripts/setup_rust_fork.sh +++ b/scripts/setup_rust_fork.sh @@ -43,8 +43,31 @@ verbose-tests = false # disabled bootstrap will crash trying to copy llvm tools for the bootstrap # compiler. llvm-tools = false +std-features = ["panic-unwind", "compiler-builtins-no-f16-f128"] EOF + +cat <128bits not yet supported # requires LTO rm -r tests/run-make/cdylib @@ -120,6 +118,7 @@ rm tests/ui/mir/mir_raw_fat_ptr.rs # same rm tests/ui/consts/issue-33537.rs # same rm tests/ui/consts/const-mut-refs-crate.rs # same rm tests/ui/abi/large-byval-align.rs # exceeds implementation limit of Cranelift +rm tests/ui/abi/simd-abi-checks-avx.rs # attempts to declare function with two different signatures # doesn't work due to the way the rustc test suite is invoked. # should work when using ./x.py test the way it is intended @@ -136,7 +135,6 @@ rm -r tests/run-make/incr-add-rust-src-component # ============ rm -r tests/run-make/extern-fn-explicit-align # argument alignment not yet supported rm -r tests/run-make/panic-abort-eh_frame # .eh_frame emitted with panic=abort -rm tests/ui/deprecation/deprecated_inline_threshold.rs # missing deprecation warning for -Cinline-threshold # bugs in the test suite # ====================== @@ -150,48 +148,8 @@ rm tests/ui/intrinsics/panic-uninitialized-zeroed.rs # same rm tests/ui/process/process-panic-after-fork.rs # same cp ../dist/bin/rustdoc-clif ../dist/bin/rustdoc # some tests expect bin/rustdoc to exist -cp $(../dist/rustc-clif --print target-libdir)/libstd-*.so ../dist/lib/ -# prevent $(RUSTDOC) from picking up the sysroot built by x.py. It conflicts with the one used by -# rustdoc-clif cat < Self { - #[track_caller] - pub fn new() -> Self { - let mut cmd = setup_common(); -- cmd.arg("-L").arg(env_var_os("TARGET_RPATH_DIR")); - Self { cmd } - } - -diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs -index e7ae773ffa1d3..04bc2d7787da7 100644 ---- a/src/tools/compiletest/src/runtest/run_make.rs -+++ b/src/tools/compiletest/src/runtest/run_make.rs -@@ -329,7 +329,6 @@ impl TestCx<'_> { - .arg(format!("run_make_support={}", &support_lib_path.to_string_lossy())) - .arg("--edition=2021") - .arg(&self.testpaths.file.join("rmake.rs")) -- .arg("-Cprefer-dynamic") - // Provide necessary library search paths for rustc. - .env(dylib_env_var(), &env::join_paths(host_dylib_search_paths).unwrap()); - diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs index 30387af428c..f7895b12961 100644 --- a/tests/run-make/linker-warning/rmake.rs @@ -205,7 +163,19 @@ index 30387af428c..f7895b12961 100644 regex::escape(run_make_support::build_root().to_str().unwrap()), "/build-root", ) - .run(); + .normalize(r#""[^"]*\/symbols.o""#, "\\"/symbols.o\\"") +diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs +index 073116933bd..c3e4578204d 100644 +--- a/src/tools/compiletest/src/runtest/run_make.rs ++++ b/src/tools/compiletest/src/runtest/run_make.rs +@@ -109,7 +109,6 @@ pub(super) fn run_rmake_test(&self) { + // library or compiler features. Here, we force the stage 0 rustc to consider itself as + // a stable-channel compiler via \`RUSTC_BOOTSTRAP=-1\` to prevent *any* unstable + // library/compiler usages, even if stage 0 rustc is *actually* a nightly rustc. +- .env("RUSTC_BOOTSTRAP", "-1") + .arg("-o") + .arg(&recipe_bin) + // Specify library search paths for \`run_make_support\`. EOF echo "[TEST] rustc test suite" diff --git a/src/base.rs b/src/base.rs index 125a9201831ca..adaa754491e56 100644 --- a/src/base.rs +++ b/src/base.rs @@ -729,8 +729,10 @@ fn codegen_stmt<'tcx>( let to_ty = fx.monomorphize(to_ty); fn is_wide_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool { - ty.builtin_deref(true) - .is_some_and(|pointee_ty| has_ptr_meta(fx.tcx, pointee_ty)) + ty.builtin_deref(true).is_some_and(|pointee_ty| { + fx.tcx + .type_has_metadata(pointee_ty, ty::TypingEnv::fully_monomorphized()) + }) } if is_wide_ptr(fx, from_ty) { diff --git a/src/common.rs b/src/common.rs index 766278d87183b..abe2972ba0cbd 100644 --- a/src/common.rs +++ b/src/common.rs @@ -71,7 +71,7 @@ fn clif_type_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option pointer_ty(tcx), ty::RawPtr(pointee_ty, _) | ty::Ref(_, pointee_ty, _) => { - if has_ptr_meta(tcx, *pointee_ty) { + if tcx.type_has_metadata(*pointee_ty, ty::TypingEnv::fully_monomorphized()) { return None; } else { pointer_ty(tcx) @@ -91,7 +91,7 @@ fn clif_pair_type_from_ty<'tcx>( (clif_type_from_ty(tcx, types[0])?, clif_type_from_ty(tcx, types[1])?) } ty::RawPtr(pointee_ty, _) | ty::Ref(_, pointee_ty, _) => { - if has_ptr_meta(tcx, *pointee_ty) { + if tcx.type_has_metadata(*pointee_ty, ty::TypingEnv::fully_monomorphized()) { (pointer_ty(tcx), pointer_ty(tcx)) } else { return None; @@ -101,20 +101,6 @@ fn clif_pair_type_from_ty<'tcx>( }) } -/// Is a pointer to this type a wide ptr? -pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { - if ty.is_sized(tcx, ty::TypingEnv::fully_monomorphized()) { - return false; - } - - let tail = tcx.struct_tail_for_codegen(ty, ty::TypingEnv::fully_monomorphized()); - match tail.kind() { - ty::Foreign(..) => false, - ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, - _ => bug!("unexpected unsized tail: {:?}", tail), - } -} - pub(crate) fn codegen_icmp_imm( fx: &mut FunctionCx<'_, '_, '_>, intcc: IntCC, diff --git a/src/config.rs b/src/config.rs index d784f6e9d9eb7..d328b33a704f5 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,21 +1,10 @@ -/// The mode to use for compilation. -#[derive(Copy, Clone, Debug)] -pub enum CodegenMode { - /// AOT compile the crate. This is the default. - Aot, - /// JIT compile and execute the crate. - Jit, - /// JIT compile and execute the crate, but only compile functions the first time they are used. - JitLazy, -} - /// Configuration of cg_clif as passed in through `-Cllvm-args` and various env vars. #[derive(Clone, Debug)] pub struct BackendConfig { /// Should the crate be AOT compiled or JIT executed. /// - /// Defaults to AOT compilation. Can be set using `-Cllvm-args=mode=...`. - pub codegen_mode: CodegenMode, + /// Defaults to AOT compilation. Can be set using `-Cllvm-args=jit-mode`. + pub jit_mode: bool, /// When JIT mode is enable pass these arguments to the program. /// @@ -27,7 +16,7 @@ impl BackendConfig { /// Parse the configuration passed in using `-Cllvm-args`. pub fn from_opts(opts: &[String]) -> Result { let mut config = BackendConfig { - codegen_mode: CodegenMode::Aot, + jit_mode: false, jit_args: match std::env::var("CG_CLIF_JIT_ARGS") { Ok(args) => args.split(' ').map(|arg| arg.to_string()).collect(), Err(std::env::VarError::NotPresent) => vec![], @@ -43,20 +32,9 @@ impl BackendConfig { // testing cg_clif. continue; } - if let Some((name, value)) = opt.split_once('=') { - match name { - "mode" => { - config.codegen_mode = match value { - "aot" => CodegenMode::Aot, - "jit" => CodegenMode::Jit, - "jit-lazy" => CodegenMode::JitLazy, - _ => return Err(format!("Unknown codegen mode `{}`", value)), - }; - } - _ => return Err(format!("Unknown option `{}`", name)), - } - } else { - return Err(format!("Invalid option `{}`", opt)); + match &**opt { + "jit-mode" => config.jit_mode = true, + _ => return Err(format!("Unknown option `{}`", opt)), } } diff --git a/src/debuginfo/types.rs b/src/debuginfo/types.rs index 017d7784dc032..25b922c8be4c7 100644 --- a/src/debuginfo/types.rs +++ b/src/debuginfo/types.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty, TyCtxt}; -use crate::{DebugContext, FullyMonomorphizedLayoutCx, has_ptr_meta}; +use crate::{DebugContext, FullyMonomorphizedLayoutCx}; #[derive(Default)] pub(crate) struct TypeDebugContext<'tcx> { @@ -129,7 +129,7 @@ impl DebugContext { let name = type_names::compute_debuginfo_type_name(tcx, ptr_type, true); - if !has_ptr_meta(tcx, ptr_type) { + if !tcx.type_has_metadata(ptr_type, ty::TypingEnv::fully_monomorphized()) { let pointer_type_id = self.dwarf.unit.add(self.dwarf.unit.root(), gimli::DW_TAG_pointer_type); let pointer_entry = self.dwarf.unit.get_mut(pointer_type_id); diff --git a/src/driver/aot.rs b/src/driver/aot.rs index fb7864ae6124b..444dc4412868f 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -331,7 +331,7 @@ fn produce_final_output_artifacts( } fn make_module(sess: &Session, name: String) -> UnwindModule { - let isa = crate::build_isa(sess); + let isa = crate::build_isa(sess, false); let mut builder = ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap(); diff --git a/src/driver/jit.rs b/src/driver/jit.rs index 57c88f4b0f9f5..41f8bb9161ca2 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -1,75 +1,27 @@ //! The JIT driver uses [`cranelift_jit`] to JIT execute programs without writing any object //! files. -use std::cell::RefCell; use std::ffi::CString; use std::os::raw::{c_char, c_int}; -use std::sync::{Mutex, OnceLock, mpsc}; -use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use cranelift_jit::{JITBuilder, JITModule}; use rustc_codegen_ssa::CrateInfo; use rustc_middle::mir::mono::MonoItem; use rustc_session::Session; use rustc_span::sym; +use crate::CodegenCx; use crate::debuginfo::TypeDebugContext; use crate::prelude::*; use crate::unwind_module::UnwindModule; -use crate::{CodegenCx, CodegenMode}; -struct JitState { - jit_module: UnwindModule, -} - -thread_local! { - static LAZY_JIT_STATE: RefCell> = const { RefCell::new(None) }; -} - -/// The Sender owned by the rustc thread -static GLOBAL_MESSAGE_SENDER: OnceLock>> = OnceLock::new(); - -/// A message that is sent from the jitted runtime to the rustc thread. -/// Senders are responsible for upholding `Send` semantics. -enum UnsafeMessage { - /// Request that the specified `Instance` be lazily jitted. - /// - /// Nothing accessible through `instance_ptr` may be moved or mutated by the sender after - /// this message is sent. - JitFn { - instance_ptr: *const Instance<'static>, - trampoline_ptr: *const u8, - tx: mpsc::Sender<*const u8>, - }, -} -unsafe impl Send for UnsafeMessage {} - -impl UnsafeMessage { - /// Send the message. - fn send(self) { - thread_local! { - /// The Sender owned by the local thread - static LOCAL_MESSAGE_SENDER: mpsc::Sender = - GLOBAL_MESSAGE_SENDER - .get().unwrap() - .lock().unwrap() - .clone(); - } - LOCAL_MESSAGE_SENDER.with(|sender| { - sender.send(self).expect("rustc thread hung up before lazy JIT request was sent") - }) - } -} - -fn create_jit_module(tcx: TyCtxt<'_>, hotswap: bool) -> (UnwindModule, CodegenCx) { +fn create_jit_module(tcx: TyCtxt<'_>) -> (UnwindModule, CodegenCx) { let crate_info = CrateInfo::new(tcx, "dummy_target_cpu".to_string()); - let isa = crate::build_isa(tcx.sess); + let isa = crate::build_isa(tcx.sess, true); let mut jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names()); - jit_builder.hotswap(hotswap); crate::compiler_builtins::register_functions_for_jit(&mut jit_builder); jit_builder.symbol_lookup_fn(dep_symbol_lookup_fn(tcx.sess, crate_info)); - jit_builder.symbol("__clif_jit_fn", clif_jit_fn as *const u8); let mut jit_module = UnwindModule::new(JITModule::new(jit_builder), false); let cx = crate::CodegenCx::new(tcx, jit_module.isa(), false, sym::dummy_cgu_name); @@ -79,7 +31,7 @@ fn create_jit_module(tcx: TyCtxt<'_>, hotswap: bool) -> (UnwindModule (jit_module, cx) } -pub(crate) fn run_jit(tcx: TyCtxt<'_>, codegen_mode: CodegenMode, jit_args: Vec) -> ! { +pub(crate) fn run_jit(tcx: TyCtxt<'_>, jit_args: Vec) -> ! { if !tcx.sess.opts.output_types.should_codegen() { tcx.dcx().fatal("JIT mode doesn't work with `cargo check`"); } @@ -88,8 +40,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, codegen_mode: CodegenMode, jit_args: Vec< tcx.dcx().fatal("can't jit non-executable crate"); } - let (mut jit_module, mut cx) = - create_jit_module(tcx, matches!(codegen_mode, CodegenMode::JitLazy)); + let (mut jit_module, mut cx) = create_jit_module(tcx); let mut cached_context = Context::new(); let cgus = tcx.collect_and_partition_mono_items(()).codegen_units; @@ -105,21 +56,15 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, codegen_mode: CodegenMode, jit_args: Vec< super::predefine_mono_items(tcx, &mut jit_module, &mono_items); for (mono_item, _) in mono_items { match mono_item { - MonoItem::Fn(inst) => match codegen_mode { - CodegenMode::Aot => unreachable!(), - CodegenMode::Jit => { - codegen_and_compile_fn( - tcx, - &mut cx, - &mut cached_context, - &mut jit_module, - inst, - ); - } - CodegenMode::JitLazy => { - codegen_shim(tcx, &mut cached_context, &mut jit_module, inst) - } - }, + MonoItem::Fn(inst) => { + codegen_and_compile_fn( + tcx, + &mut cx, + &mut cached_context, + &mut jit_module, + inst, + ); + } MonoItem::Static(def_id) => { crate::constant::codegen_static(tcx, &mut jit_module, def_id); } @@ -161,41 +106,17 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, codegen_mode: CodegenMode, jit_args: Vec< let start_func_id = jit_module.declare_function("main", Linkage::Import, &start_sig).unwrap(); let finalized_start: *const u8 = jit_module.module.get_finalized_function(start_func_id); - LAZY_JIT_STATE.with(|lazy_jit_state| { - let mut lazy_jit_state = lazy_jit_state.borrow_mut(); - assert!(lazy_jit_state.is_none()); - *lazy_jit_state = Some(JitState { jit_module }); - }); - let f: extern "C" fn(c_int, *const *const c_char) -> c_int = unsafe { ::std::mem::transmute(finalized_start) }; - let (tx, rx) = mpsc::channel(); - GLOBAL_MESSAGE_SENDER.set(Mutex::new(tx)).unwrap(); - - // Spawn the jitted runtime in a new thread so that this rustc thread can handle messages - // (eg to lazily JIT further functions as required) - std::thread::spawn(move || { - let mut argv = args.iter().map(|arg| arg.as_ptr()).collect::>(); + let mut argv = args.iter().map(|arg| arg.as_ptr()).collect::>(); - // Push a null pointer as a terminating argument. This is required by POSIX and - // useful as some dynamic linkers use it as a marker to jump over. - argv.push(std::ptr::null()); + // Push a null pointer as a terminating argument. This is required by POSIX and + // useful as some dynamic linkers use it as a marker to jump over. + argv.push(std::ptr::null()); - let ret = f(args.len() as c_int, argv.as_ptr()); - std::process::exit(ret); - }); - - // Handle messages - loop { - match rx.recv().unwrap() { - // lazy JIT compilation request - compile requested instance and return pointer to result - UnsafeMessage::JitFn { instance_ptr, trampoline_ptr, tx } => { - tx.send(jit_fn(instance_ptr, trampoline_ptr)) - .expect("jitted runtime hung up before response to lazy JIT request was sent"); - } - } - } + let ret = f(args.len() as c_int, argv.as_ptr()); + std::process::exit(ret); } pub(crate) fn codegen_and_compile_fn<'tcx>( @@ -227,58 +148,6 @@ pub(crate) fn codegen_and_compile_fn<'tcx>( }); } -extern "C" fn clif_jit_fn( - instance_ptr: *const Instance<'static>, - trampoline_ptr: *const u8, -) -> *const u8 { - // send the JIT request to the rustc thread, with a channel for the response - let (tx, rx) = mpsc::channel(); - UnsafeMessage::JitFn { instance_ptr, trampoline_ptr, tx }.send(); - - // block on JIT compilation result - rx.recv().expect("rustc thread hung up before responding to sent lazy JIT request") -} - -fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) -> *const u8 { - rustc_middle::ty::tls::with(|tcx| { - // lift is used to ensure the correct lifetime for instance. - let instance = tcx.lift(unsafe { *instance_ptr }).unwrap(); - - LAZY_JIT_STATE.with(|lazy_jit_state| { - let mut lazy_jit_state = lazy_jit_state.borrow_mut(); - let lazy_jit_state = lazy_jit_state.as_mut().unwrap(); - let jit_module = &mut lazy_jit_state.jit_module; - - let name = tcx.symbol_name(instance).name; - let sig = crate::abi::get_function_sig( - tcx, - jit_module.target_config().default_call_conv, - instance, - ); - let func_id = jit_module.declare_function(name, Linkage::Export, &sig).unwrap(); - - let current_ptr = jit_module.module.read_got_entry(func_id); - - // If the function's GOT entry has already been updated to point at something other - // than the shim trampoline, don't re-jit but just return the new pointer instead. - // This does not need synchronization as this code is executed only by a sole rustc - // thread. - if current_ptr != trampoline_ptr { - return current_ptr; - } - - jit_module.module.prepare_for_function_redefine(func_id).unwrap(); - - let mut cx = crate::CodegenCx::new(tcx, jit_module.isa(), false, sym::dummy_cgu_name); - codegen_and_compile_fn(tcx, &mut cx, &mut Context::new(), jit_module, instance); - - assert!(cx.global_asm.is_empty()); - jit_module.finalize_definitions(); - jit_module.module.get_finalized_function(func_id) - }) - }) -} - fn dep_symbol_lookup_fn( sess: &Session, crate_info: CrateInfo, @@ -326,57 +195,3 @@ fn dep_symbol_lookup_fn( None }) } - -fn codegen_shim<'tcx>( - tcx: TyCtxt<'tcx>, - cached_context: &mut Context, - module: &mut UnwindModule, - inst: Instance<'tcx>, -) { - let pointer_type = module.target_config().pointer_type(); - - let name = tcx.symbol_name(inst).name; - let sig = crate::abi::get_function_sig(tcx, module.target_config().default_call_conv, inst); - let func_id = module.declare_function(name, Linkage::Export, &sig).unwrap(); - - let instance_ptr = Box::into_raw(Box::new(inst)); - - let jit_fn = module - .declare_function( - "__clif_jit_fn", - Linkage::Import, - &Signature { - call_conv: module.target_config().default_call_conv, - params: vec![AbiParam::new(pointer_type), AbiParam::new(pointer_type)], - returns: vec![AbiParam::new(pointer_type)], - }, - ) - .unwrap(); - - let context = cached_context; - context.clear(); - let trampoline = &mut context.func; - trampoline.signature = sig.clone(); - - let mut builder_ctx = FunctionBuilderContext::new(); - let mut trampoline_builder = FunctionBuilder::new(trampoline, &mut builder_ctx); - - let trampoline_fn = module.declare_func_in_func(func_id, trampoline_builder.func); - let jit_fn = module.declare_func_in_func(jit_fn, trampoline_builder.func); - let sig_ref = trampoline_builder.func.import_signature(sig); - - let entry_block = trampoline_builder.create_block(); - trampoline_builder.append_block_params_for_function_params(entry_block); - let fn_args = trampoline_builder.func.dfg.block_params(entry_block).to_vec(); - - trampoline_builder.switch_to_block(entry_block); - let instance_ptr = trampoline_builder.ins().iconst(pointer_type, instance_ptr as u64 as i64); - let trampoline_ptr = trampoline_builder.ins().func_addr(pointer_type, trampoline_fn); - let jitted_fn = trampoline_builder.ins().call(jit_fn, &[instance_ptr, trampoline_ptr]); - let jitted_fn = trampoline_builder.func.dfg.inst_results(jitted_fn)[0]; - let call_inst = trampoline_builder.ins().call_indirect(sig_ref, jitted_fn, &fn_args); - let ret_vals = trampoline_builder.func.dfg.inst_results(call_inst).to_vec(); - trampoline_builder.ins().return_(&ret_vals); - - module.define_function(func_id, context).unwrap(); -} diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 310b226814d40..fbc33a642853c 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -612,6 +612,15 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { generated_asm.push_str(".att_syntax\n"); } + if self.arch == InlineAsmArch::AArch64 { + for feature in &self.tcx.codegen_fn_attrs(self.enclosing_def_id).target_features { + if feature.name == sym::neon { + continue; + } + writeln!(generated_asm, ".arch_extension {}", feature.name).unwrap(); + } + } + // The actual inline asm for piece in self.template { match piece { @@ -652,6 +661,20 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { .emit(&mut generated_asm, InlineAsmArch::X86_64, *modifier) .unwrap(), }, + InlineAsmArch::AArch64 => match reg { + InlineAsmReg::AArch64(reg) if reg.vreg_index().is_some() => { + // rustc emits v0 rather than q0 + reg.emit( + &mut generated_asm, + InlineAsmArch::AArch64, + Some(modifier.unwrap_or('q')), + ) + .unwrap() + } + _ => reg + .emit(&mut generated_asm, InlineAsmArch::AArch64, *modifier) + .unwrap(), + }, _ => reg.emit(&mut generated_asm, self.arch, *modifier).unwrap(), } } @@ -665,6 +688,15 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { } generated_asm.push('\n'); + if self.arch == InlineAsmArch::AArch64 { + for feature in &self.tcx.codegen_fn_attrs(self.enclosing_def_id).target_features { + if feature.name == sym::neon { + continue; + } + writeln!(generated_asm, ".arch_extension no{}", feature.name).unwrap(); + } + } + if is_x86 && self.options.contains(InlineAsmOptions::ATT_SYNTAX) { generated_asm.push_str(".intel_syntax noprefix\n"); } @@ -809,7 +841,13 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { } InlineAsmArch::AArch64 => { generated_asm.push_str(" str "); - reg.emit(generated_asm, InlineAsmArch::AArch64, None).unwrap(); + match reg { + InlineAsmReg::AArch64(reg) if reg.vreg_index().is_some() => { + // rustc emits v0 rather than q0 + reg.emit(generated_asm, InlineAsmArch::AArch64, Some('q')).unwrap() + } + _ => reg.emit(generated_asm, InlineAsmArch::AArch64, None).unwrap(), + } writeln!(generated_asm, ", [x19, 0x{:x}]", offset.bytes()).unwrap(); } InlineAsmArch::RiscV64 => { @@ -851,7 +889,13 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { } InlineAsmArch::AArch64 => { generated_asm.push_str(" ldr "); - reg.emit(generated_asm, InlineAsmArch::AArch64, None).unwrap(); + match reg { + InlineAsmReg::AArch64(reg) if reg.vreg_index().is_some() => { + // rustc emits v0 rather than q0 + reg.emit(generated_asm, InlineAsmArch::AArch64, Some('q')).unwrap() + } + _ => reg.emit(generated_asm, InlineAsmArch::AArch64, None).unwrap(), + } writeln!(generated_asm, ", [x19, 0x{:x}]", offset.bytes()).unwrap(); } InlineAsmArch::RiscV64 => { diff --git a/src/intrinsics/llvm.rs b/src/intrinsics/llvm.rs index 720a0d8fbf593..eb0dfbb69c3b7 100644 --- a/src/intrinsics/llvm.rs +++ b/src/intrinsics/llvm.rs @@ -54,6 +54,14 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( ); } + "llvm.fptosi.sat.v4i32.v4f32" => { + intrinsic_args!(fx, args => (a); intrinsic); + + simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| { + fx.bcx.ins().fcvt_to_sint_sat(types::I32, lane) + }); + } + _ => { fx.tcx .dcx() diff --git a/src/intrinsics/llvm_aarch64.rs b/src/intrinsics/llvm_aarch64.rs index 4c59c81296bad..387c87d123a39 100644 --- a/src/intrinsics/llvm_aarch64.rs +++ b/src/intrinsics/llvm_aarch64.rs @@ -1,5 +1,9 @@ //! Emulate AArch64 LLVM intrinsics +use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use rustc_target::asm::*; + +use crate::inline_asm::{CInlineAsmOperand, codegen_inline_asm_inner}; use crate::intrinsics::*; use crate::prelude::*; @@ -17,7 +21,7 @@ pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( fx.bcx.ins().fence(); } - "llvm.aarch64.neon.ld1x4.v16i8.p0i8" => { + "llvm.aarch64.neon.ld1x4.v16i8.p0" => { intrinsic_args!(fx, args => (ptr); intrinsic); let ptr = ptr.load_scalar(fx); @@ -49,6 +53,121 @@ pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( }); } + "llvm.aarch64.neon.fcvtns.v4i32.v4f32" => { + intrinsic_args!(fx, args => (a); intrinsic); + + // Note: Using inline asm instead of fcvt_to_sint as the latter rounds to zero rather than to nearest + + let a_ptr = a.force_stack(fx).0.get_addr(fx); + let res_place = CPlace::new_stack_slot(fx, ret.layout()); + let res_ptr = res_place.to_ptr().get_addr(fx); + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String( + "ldr q0, [x0] + fcvtns v0.4s, v0.4s + str q0, [x1]" + .into(), + )], + &[ + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::x0, + )), + value: a_ptr, + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::x1, + )), + value: res_ptr, + }, + ], + InlineAsmOptions::NOSTACK, + ); + let res = res_place.to_cvalue(fx); + ret.write_cvalue_transmute(fx, res); + } + + "llvm.aarch64.neon.frecpe.v4f32" => { + intrinsic_args!(fx, args => (a); intrinsic); + + let a_ptr = a.force_stack(fx).0.get_addr(fx); + let res_place = CPlace::new_stack_slot(fx, ret.layout()); + let res_ptr = res_place.to_ptr().get_addr(fx); + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String( + "ldr q0, [x0] + frecpe v0.4s, v0.4s + str q0, [x1]" + .into(), + )], + &[ + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::x0, + )), + value: a_ptr, + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::x1, + )), + value: res_ptr, + }, + ], + InlineAsmOptions::NOSTACK, + ); + let res = res_place.to_cvalue(fx); + ret.write_cvalue_transmute(fx, res); + } + + "llvm.aarch64.neon.frecps.v4f32" => { + intrinsic_args!(fx, args => (a, b); intrinsic); + + let a_ptr = a.force_stack(fx).0.get_addr(fx); + let b_ptr = b.force_stack(fx).0.get_addr(fx); + let res_place = CPlace::new_stack_slot(fx, ret.layout()); + let res_ptr = res_place.to_ptr().get_addr(fx); + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String( + "ldr q0, [x0] + ldr q1, [x1] + frecps v0.4s, v0.4s, v1.4s + str q0, [x2]" + .into(), + )], + &[ + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::x0, + )), + value: a_ptr, + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::x1, + )), + value: b_ptr, + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::AArch64( + AArch64InlineAsmReg::x2, + )), + value: res_ptr, + }, + ], + InlineAsmOptions::NOSTACK, + ); + let res = res_place.to_cvalue(fx); + ret.write_cvalue_transmute(fx, res); + } + _ if intrinsic.starts_with("llvm.aarch64.neon.sqadd.v") || intrinsic.starts_with("llvm.aarch64.neon.uqadd.v") => { @@ -134,7 +253,7 @@ pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( } let res = CValue::by_val( fx.bcx.ins().uextend(types::I32, res_val), - fx.layout_of(fx.tcx.types.u32), + fx.layout_of(fx.tcx.types.i32), ); ret.write_cvalue(fx, res); } diff --git a/src/lib.rs b/src/lib.rs index ab3386a9b4ccf..e7afaff3b428f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,6 @@ use std::sync::Arc; use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::settings::{self, Configurable}; use rustc_codegen_ssa::CodegenResults; -use rustc_codegen_ssa::back::versioned_llvm_target; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; @@ -214,15 +213,14 @@ impl CodegenBackend for CraneliftCodegenBackend { BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args) .unwrap_or_else(|err| tcx.sess.dcx().fatal(err)) }); - match config.codegen_mode { - CodegenMode::Aot => driver::aot::run_aot(tcx, metadata, need_metadata_module), - CodegenMode::Jit | CodegenMode::JitLazy => { - #[cfg(feature = "jit")] - driver::jit::run_jit(tcx, config.codegen_mode, config.jit_args); - - #[cfg(not(feature = "jit"))] - tcx.dcx().fatal("jit support was disabled when compiling rustc_codegen_cranelift"); - } + if config.jit_mode { + #[cfg(feature = "jit")] + driver::jit::run_jit(tcx, config.jit_args); + + #[cfg(not(feature = "jit"))] + tcx.dcx().fatal("jit support was disabled when compiling rustc_codegen_cranelift"); + } else { + driver::aot::run_aot(tcx, metadata, need_metadata_module) } } @@ -247,21 +245,19 @@ fn enable_verifier(sess: &Session) -> bool { } fn target_triple(sess: &Session) -> target_lexicon::Triple { - // FIXME(madsmtm): Use `sess.target.llvm_target` once target-lexicon supports unversioned macOS. - // See - match versioned_llvm_target(sess).parse() { + match sess.target.llvm_target.parse() { Ok(triple) => triple, Err(err) => sess.dcx().fatal(format!("target not recognized: {}", err)), } } -fn build_isa(sess: &Session) -> Arc { +fn build_isa(sess: &Session, jit: bool) -> Arc { use target_lexicon::BinaryFormat; let target_triple = crate::target_triple(sess); let mut flags_builder = settings::builder(); - flags_builder.enable("is_pic").unwrap(); + flags_builder.set("is_pic", if jit { "false" } else { "true" }).unwrap(); let enable_verifier = if enable_verifier(sess) { "true" } else { "false" }; flags_builder.set("enable_verifier", enable_verifier).unwrap(); flags_builder.set("regalloc_checker", enable_verifier).unwrap(); diff --git a/src/num.rs b/src/num.rs index f44e2459a784d..2a4d1e3ae571d 100644 --- a/src/num.rs +++ b/src/num.rs @@ -395,8 +395,12 @@ pub(crate) fn codegen_ptr_binop<'tcx>( in_lhs: CValue<'tcx>, in_rhs: CValue<'tcx>, ) -> CValue<'tcx> { - let is_thin_ptr = - in_lhs.layout().ty.builtin_deref(true).map(|ty| !has_ptr_meta(fx.tcx, ty)).unwrap_or(true); + let is_thin_ptr = in_lhs + .layout() + .ty + .builtin_deref(true) + .map(|ty| !fx.tcx.type_has_metadata(ty, ty::TypingEnv::fully_monomorphized())) + .unwrap_or(true); if is_thin_ptr { match bin_op { diff --git a/src/value_and_place.rs b/src/value_and_place.rs index cc739fefcd066..f8a19589fdd72 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -746,7 +746,7 @@ impl<'tcx> CPlace<'tcx> { }; let (field_ptr, field_layout) = codegen_field(fx, base, extra, layout, field); - if has_ptr_meta(fx.tcx, field_layout.ty) { + if fx.tcx.type_has_metadata(field_layout.ty, ty::TypingEnv::fully_monomorphized()) { CPlace::for_ptr_with_extra(field_ptr, extra.unwrap(), field_layout) } else { CPlace::for_ptr(field_ptr, field_layout) @@ -832,7 +832,7 @@ impl<'tcx> CPlace<'tcx> { pub(crate) fn place_deref(self, fx: &mut FunctionCx<'_, '_, 'tcx>) -> CPlace<'tcx> { let inner_layout = fx.layout_of(self.layout().ty.builtin_deref(true).unwrap()); - if has_ptr_meta(fx.tcx, inner_layout.ty) { + if fx.tcx.type_has_metadata(inner_layout.ty, ty::TypingEnv::fully_monomorphized()) { let (addr, extra) = self.to_cvalue(fx).load_scalar_pair(fx); CPlace::for_ptr_with_extra(Pointer::new(addr), extra, inner_layout) } else { @@ -845,7 +845,7 @@ impl<'tcx> CPlace<'tcx> { fx: &mut FunctionCx<'_, '_, 'tcx>, layout: TyAndLayout<'tcx>, ) -> CValue<'tcx> { - if has_ptr_meta(fx.tcx, self.layout().ty) { + if fx.tcx.type_has_metadata(self.layout().ty, ty::TypingEnv::fully_monomorphized()) { let (ptr, extra) = self.to_ptr_unsized(); CValue::by_val_pair(ptr.get_addr(fx), extra, layout) } else { From 625b8000f7897ab51312f1800fcae280cc3ac81b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 1 Apr 2025 14:13:53 +0000 Subject: [PATCH 1755/4206] Allow formatting example/gen_block_iterate.rs --- example/gen_block_iterate.rs | 16 ++++++++++++---- rustfmt.toml | 4 ---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/example/gen_block_iterate.rs b/example/gen_block_iterate.rs index 25bfe542d228a..de9a3d550eccd 100644 --- a/example/gen_block_iterate.rs +++ b/example/gen_block_iterate.rs @@ -6,16 +6,25 @@ #![feature(gen_blocks)] fn foo() -> impl Iterator { - gen { yield 42; for x in 3..6 { yield x } } + gen { + yield 42; + for x in 3..6 { + yield x + } + } } fn moved() -> impl Iterator { let mut x = "foo".to_string(); gen move { yield 42; - if x == "foo" { return } + if x == "foo" { + return; + } x.clear(); - for x in 3..6 { yield x } + for x in 3..6 { + yield x + } } } @@ -32,5 +41,4 @@ fn main() { let mut iter = moved(); assert_eq!(iter.next(), Some(42)); assert_eq!(iter.next(), None); - } diff --git a/rustfmt.toml b/rustfmt.toml index f31fa9c76abc6..35c92663eb904 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,7 +1,3 @@ -ignore = [ - "example/gen_block_iterate.rs", # uses edition 2024 -] - # Matches rustfmt.toml of rustc style_edition = "2024" use_small_heuristics = "Max" From 9b8ccf67c691dd9ed1f1ba2b39608fdd03ce75dd Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 2 Apr 2025 19:19:43 +0000 Subject: [PATCH 1756/4206] Revert "Disable `f16` on AArch64 without the `neon` feature" The LLVM issue [1] was resolved and the fix was synced to rust-lang/rust in [2]. This reverts commit 5cf417a9e92bb48e4e55756a645826fd167b9f3a. [1]: https://github.com/llvm/llvm-project/issues/129394 [2]: https://github.com/rust-lang/rust/pull/138695 --- library/compiler-builtins/compiler-builtins/configure.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/configure.rs b/library/compiler-builtins/compiler-builtins/configure.rs index 2f134e57818ca..4be0b3ca23ca5 100644 --- a/library/compiler-builtins/compiler-builtins/configure.rs +++ b/library/compiler-builtins/compiler-builtins/configure.rs @@ -91,8 +91,6 @@ pub fn configure_f16_f128(target: &Target) { let f16_enabled = match target.arch.as_str() { // Unsupported "arm64ec" => false, - // Crash in LLVM20 - "aarch64" if !target.features.iter().any(|f| f == "neon") => false, // Selection failure "s390x" => false, // Infinite recursion From e58dd2568b5ba8524c3423495190313aa006ab53 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 31 Mar 2025 15:09:43 +0000 Subject: [PATCH 1757/4206] Unset RUSTC_WRAPPER in cg_clif's build system --- build_system/utils.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build_system/utils.rs b/build_system/utils.rs index c2114caf8692e..f239976845964 100644 --- a/build_system/utils.rs +++ b/build_system/utils.rs @@ -105,7 +105,11 @@ impl CargoProject { .arg(self.manifest_path(dirs)) .arg("--target-dir") .arg(self.target_dir(dirs)) - .arg("--locked"); + .arg("--locked") + // bootstrap sets both RUSTC and RUSTC_WRAPPER to the same wrapper. RUSTC is already + // respected by the rustc-clif wrapper, but RUSTC_WRAPPER will misinterpret rustc-clif + // as filename, so we need to unset it. + .env_remove("RUSTC_WRAPPER"); if dirs.frozen { cmd.arg("--frozen"); From bb2b3d04c31648ebd737b0ebc47b9d90fc3b777a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 1 Apr 2025 13:54:08 +0000 Subject: [PATCH 1758/4206] Run coretests and alloctests with cg_clif in CI --- build_system/tests.rs | 47 ++++++++++++++++++++++++------------------- config.txt | 2 +- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/build_system/tests.rs b/build_system/tests.rs index 122b541fa35f8..eb15a3fc027eb 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -99,6 +99,32 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[ runner.run_out_command("gen_block_iterate", &[]); }), TestCase::build_bin_and_run("aot.raw-dylib", "example/raw-dylib.rs", &[]), + TestCase::custom("test.sysroot", &|runner| { + apply_patches( + &runner.dirs, + "sysroot_tests", + &runner.stdlib_source.join("library"), + &SYSROOT_TESTS_SRC.to_path(&runner.dirs), + ); + + SYSROOT_TESTS.clean(&runner.dirs); + + // coretests and alloctests produce a bunch of warnings. When running + // in rust's CI warnings are denied, so we have to override that here. + let mut target_compiler = runner.target_compiler.clone(); + target_compiler.rustflags.push("--cap-lints=allow".to_owned()); + + if runner.is_native { + let mut test_cmd = SYSROOT_TESTS.test(&target_compiler, &runner.dirs); + test_cmd.args(["-p", "coretests", "-p", "alloctests", "--tests", "--", "-q"]); + spawn_and_wait(test_cmd); + } else { + eprintln!("Cross-Compiling: Not running tests"); + let mut build_cmd = SYSROOT_TESTS.build(&target_compiler, &runner.dirs); + build_cmd.args(["-p", "coretests", "-p", "alloctests", "--tests"]); + spawn_and_wait(build_cmd); + } + }), ]; pub(crate) static RAND_REPO: GitRepo = GitRepo::github( @@ -146,27 +172,6 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ spawn_and_wait(build_cmd); } }), - TestCase::custom("test.sysroot", &|runner| { - apply_patches( - &runner.dirs, - "sysroot_tests", - &runner.stdlib_source.join("library"), - &SYSROOT_TESTS_SRC.to_path(&runner.dirs), - ); - - SYSROOT_TESTS.clean(&runner.dirs); - - if runner.is_native { - let mut test_cmd = SYSROOT_TESTS.test(&runner.target_compiler, &runner.dirs); - test_cmd.args(["-p", "coretests", "-p", "alloctests", "--", "-q"]); - spawn_and_wait(test_cmd); - } else { - eprintln!("Cross-Compiling: Not running tests"); - let mut build_cmd = SYSROOT_TESTS.build(&runner.target_compiler, &runner.dirs); - build_cmd.args(["-p", "coretests", "-p", "alloctests", "--tests"]); - spawn_and_wait(build_cmd); - } - }), TestCase::custom("test.regex", &|runner| { REGEX_REPO.patch(&runner.dirs); diff --git a/config.txt b/config.txt index 714414fe8d685..6ae4767adfdf5 100644 --- a/config.txt +++ b/config.txt @@ -32,9 +32,9 @@ aot.issue-59326 aot.neon aot.gen_block_iterate aot.raw-dylib +test.sysroot testsuite.extended_sysroot test.rust-random/rand -test.sysroot test.regex test.portable-simd From ae0e3b7e38136b6303eb2362fca814600e34b024 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Wed, 2 Apr 2025 14:21:09 +0000 Subject: [PATCH 1759/4206] Default `trivial_copy_size_limit` to the width of a target pointer --- book/src/lint_configuration.md | 2 +- clippy_config/src/conf.rs | 2 +- clippy_lints/src/pass_by_ref_or_value.rs | 22 +-- tests/ui/trivially_copy_pass_by_ref.fixed | 179 +++++++++++++++++++++ tests/ui/trivially_copy_pass_by_ref.rs | 60 +++---- tests/ui/trivially_copy_pass_by_ref.stderr | 80 ++++----- 6 files changed, 251 insertions(+), 94 deletions(-) create mode 100644 tests/ui/trivially_copy_pass_by_ref.fixed diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index a677745379c28..add2f3909b54c 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -1002,7 +1002,7 @@ The order of associated items in traits. The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference. -**Default Value:** `target_pointer_width * 2` +**Default Value:** `target_pointer_width` --- **Affected lints:** diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 34c62318aad3d..4aab91eec1f07 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -818,7 +818,7 @@ define_Conf! { trait_assoc_item_kinds_order: SourceItemOrderingTraitAssocItemKinds = DEFAULT_TRAIT_ASSOC_ITEM_KINDS_ORDER.into(), /// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by /// reference. - #[default_text = "target_pointer_width * 2"] + #[default_text = "target_pointer_width"] #[lints(trivially_copy_pass_by_ref)] trivial_copy_size_limit: Option = None, /// The maximum complexity a type can have diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 5d30b66def2c8..dadf49b64e517 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -1,5 +1,3 @@ -use std::{cmp, iter}; - use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; @@ -20,6 +18,7 @@ use rustc_middle::ty::{self, RegionKind, TyCtxt}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{Span, sym}; +use std::iter; declare_clippy_lint! { /// ### What it does @@ -33,10 +32,8 @@ declare_clippy_lint! { /// registers. /// /// ### Known problems - /// This lint is target register size dependent, it is - /// limited to 32-bit to try and reduce portability problems between 32 and - /// 64-bit, but if you are compiling for 8 or 16-bit targets then the limit - /// will be different. + /// This lint is target dependent, some cases will lint on 64-bit targets but + /// not 32-bit or lower targets. /// /// The configuration option `trivial_copy_size_limit` can be set to override /// this limit for a project. @@ -112,16 +109,9 @@ pub struct PassByRefOrValue { impl PassByRefOrValue { pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { - let ref_min_size = conf.trivial_copy_size_limit.unwrap_or_else(|| { - let bit_width = u64::from(tcx.sess.target.pointer_width); - // Cap the calculated bit width at 32-bits to reduce - // portability problems between 32 and 64-bit targets - let bit_width = cmp::min(bit_width, 32); - #[expect(clippy::integer_division)] - let byte_width = bit_width / 8; - // Use a limit of 2 times the register byte width - byte_width * 2 - }); + let ref_min_size = conf + .trivial_copy_size_limit + .unwrap_or_else(|| u64::from(tcx.sess.target.pointer_width / 8)); Self { ref_min_size, diff --git a/tests/ui/trivially_copy_pass_by_ref.fixed b/tests/ui/trivially_copy_pass_by_ref.fixed new file mode 100644 index 0000000000000..af7d82130f01c --- /dev/null +++ b/tests/ui/trivially_copy_pass_by_ref.fixed @@ -0,0 +1,179 @@ +//@normalize-stderr-test: "\(\d+ byte\)" -> "(N byte)" +//@normalize-stderr-test: "\(limit: \d+ byte\)" -> "(limit: N byte)" +#![deny(clippy::trivially_copy_pass_by_ref)] +#![allow( + clippy::disallowed_names, + clippy::extra_unused_lifetimes, + clippy::needless_lifetimes, + clippy::needless_pass_by_ref_mut, + clippy::redundant_field_names, + clippy::uninlined_format_args +)] + +#[derive(Copy, Clone)] +struct Foo(u32); + +#[derive(Copy, Clone)] +struct Bar([u8; 24]); + +#[derive(Copy, Clone)] +pub struct Color { + pub r: u8, + pub g: u8, + pub b: u8, + pub a: u8, +} + +struct FooRef<'a> { + foo: &'a Foo, +} + +type Baz = u32; + +fn good(a: &mut u32, b: u32, c: &Bar) {} + +fn good_return_implicit_lt_ref(foo: &Foo) -> &u32 { + &foo.0 +} + +#[allow(clippy::needless_lifetimes)] +fn good_return_explicit_lt_ref<'a>(foo: &'a Foo) -> &'a u32 { + &foo.0 +} + +fn good_return_implicit_lt_struct(foo: &Foo) -> FooRef { + FooRef { foo } +} + +#[allow(clippy::needless_lifetimes)] +fn good_return_explicit_lt_struct<'a>(foo: &'a Foo) -> FooRef<'a> { + FooRef { foo } +} + +fn bad(x: u32, y: Foo, z: Baz) {} +//~^ ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by +//~| ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by +//~| ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by + +impl Foo { + fn good(self, a: &mut u32, b: u32, c: &Bar) {} + + fn good2(&mut self) {} + + fn bad(self, x: u32, y: Foo, z: Baz) {} + //~^ ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by + //~| ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by + //~| ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by + //~| ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by + + fn bad2(x: u32, y: Foo, z: Baz) {} + //~^ ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by + //~| ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by + //~| ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by + + fn bad_issue7518(self, other: Self) {} + //~^ ERROR: this argument (4 byte) is passed by reference, but would be more efficient if +} + +impl AsRef for Foo { + fn as_ref(&self) -> &u32 { + &self.0 + } +} + +impl Bar { + fn good(&self, a: &mut u32, b: u32, c: &Bar) {} + + fn bad2(x: u32, y: Foo, z: Baz) {} + //~^ ERROR: this argument (4 byte) is passed by reference, but would be more efficient if + //~| ERROR: this argument (4 byte) is passed by reference, but would be more efficient if + //~| ERROR: this argument (4 byte) is passed by reference, but would be more efficient if +} + +trait MyTrait { + fn trait_method(&self, foo: Foo); + //~^ ERROR: this argument (4 byte) is passed by reference, but would be more efficient if +} + +pub trait MyTrait2 { + fn trait_method2(&self, color: &Color); +} + +trait MyTrait3 { + #[expect(clippy::trivially_copy_pass_by_ref)] + fn trait_method(&self, foo: &Foo); +} + +// Trait impls should not warn +impl MyTrait3 for Foo { + fn trait_method(&self, foo: &Foo) { + unimplemented!() + } +} + +mod issue3992 { + pub trait A { + #[allow(clippy::trivially_copy_pass_by_ref)] + fn a(b: &u16) {} + } + + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn c(d: &u16) {} +} + +mod issue5876 { + // Don't lint here as it is always inlined + #[inline(always)] + fn foo_always(x: &i32) { + println!("{}", x); + } + + #[inline(never)] + fn foo_never(x: i32) { + //~^ ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by + println!("{}", x); + } + + #[inline] + fn foo(x: i32) { + //~^ ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by + println!("{}", x); + } +} + +fn ref_to_opt_ref_implicit(x: &u32) -> Option<&u32> { + Some(x) +} + +fn ref_to_opt_ref_explicit<'a>(x: &'a u32) -> Option<&'a u32> { + Some(x) +} + +fn with_constraint<'a, 'b: 'a>(x: &'b u32, y: &'a u32) -> &'a u32 { + if true { x } else { y } +} + +async fn async_implicit(x: &u32) -> &u32 { + x +} + +async fn async_explicit<'a>(x: &'a u32) -> &'a u32 { + x +} + +fn unrelated_lifetimes<'a, 'b>(_x: u32, y: &'b u32) -> &'b u32 { + //~^ ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by + y +} + +fn return_ptr(x: &u32) -> *const u32 { + x +} + +fn return_field_ptr(x: &(u32, u32)) -> *const u32 { + &x.0 +} + +fn return_field_ptr_addr_of(x: &(u32, u32)) -> *const u32 { + core::ptr::addr_of!(x.0) +} diff --git a/tests/ui/trivially_copy_pass_by_ref.rs b/tests/ui/trivially_copy_pass_by_ref.rs index 37bc6f89a20af..00e11a1ea2808 100644 --- a/tests/ui/trivially_copy_pass_by_ref.rs +++ b/tests/ui/trivially_copy_pass_by_ref.rs @@ -1,14 +1,15 @@ //@normalize-stderr-test: "\(\d+ byte\)" -> "(N byte)" -//@normalize-stderr-test: "\(limit: \d+ byte\)" -> "(limit: 8 byte)" +//@normalize-stderr-test: "\(limit: \d+ byte\)" -> "(limit: N byte)" #![deny(clippy::trivially_copy_pass_by_ref)] #![allow( clippy::disallowed_names, + clippy::extra_unused_lifetimes, clippy::needless_lifetimes, + clippy::needless_pass_by_ref_mut, clippy::redundant_field_names, - clippy::uninlined_format_args, - clippy::needless_pass_by_ref_mut + clippy::uninlined_format_args )] -//@no-rustfix + #[derive(Copy, Clone)] struct Foo(u32); @@ -90,21 +91,26 @@ impl Bar { } trait MyTrait { - fn trait_method(&self, _foo: &Foo); + fn trait_method(&self, foo: &Foo); //~^ ERROR: this argument (4 byte) is passed by reference, but would be more efficient if } pub trait MyTrait2 { - fn trait_method2(&self, _color: &Color); + fn trait_method2(&self, color: &Color); +} + +trait MyTrait3 { + #[expect(clippy::trivially_copy_pass_by_ref)] + fn trait_method(&self, foo: &Foo); } -impl MyTrait for Foo { - fn trait_method(&self, _foo: &Foo) { +// Trait impls should not warn +impl MyTrait3 for Foo { + fn trait_method(&self, foo: &Foo) { unimplemented!() } } -#[allow(unused_variables)] mod issue3992 { pub trait A { #[allow(clippy::trivially_copy_pass_by_ref)] @@ -135,57 +141,39 @@ mod issue5876 { } } -fn _ref_to_opt_ref_implicit(x: &u32) -> Option<&u32> { +fn ref_to_opt_ref_implicit(x: &u32) -> Option<&u32> { Some(x) } -#[allow(clippy::needless_lifetimes)] -fn _ref_to_opt_ref_explicit<'a>(x: &'a u32) -> Option<&'a u32> { +fn ref_to_opt_ref_explicit<'a>(x: &'a u32) -> Option<&'a u32> { Some(x) } -fn _with_constraint<'a, 'b: 'a>(x: &'b u32, y: &'a u32) -> &'a u32 { +fn with_constraint<'a, 'b: 'a>(x: &'b u32, y: &'a u32) -> &'a u32 { if true { x } else { y } } -async fn _async_implicit(x: &u32) -> &u32 { +async fn async_implicit(x: &u32) -> &u32 { x } -#[allow(clippy::needless_lifetimes)] -async fn _async_explicit<'a>(x: &'a u32) -> &'a u32 { +async fn async_explicit<'a>(x: &'a u32) -> &'a u32 { x } -fn _unrelated_lifetimes<'a, 'b>(_x: &'a u32, y: &'b u32) -> &'b u32 { +fn unrelated_lifetimes<'a, 'b>(_x: &'a u32, y: &'b u32) -> &'b u32 { //~^ ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by y } -fn _return_ptr(x: &u32) -> *const u32 { +fn return_ptr(x: &u32) -> *const u32 { x } -fn _return_field_ptr(x: &(u32, u32)) -> *const u32 { +fn return_field_ptr(x: &(u32, u32)) -> *const u32 { &x.0 } -fn _return_field_ptr_addr_of(x: &(u32, u32)) -> *const u32 { +fn return_field_ptr_addr_of(x: &(u32, u32)) -> *const u32 { core::ptr::addr_of!(x.0) } - -fn main() { - let (mut foo, bar) = (Foo(0), Bar([0; 24])); - let (mut a, b, c, x, y, z) = (0, 0, Bar([0; 24]), 0, Foo(0), 0); - good(&mut a, b, &c); - good_return_implicit_lt_ref(&y); - good_return_explicit_lt_ref(&y); - bad(&x, &y, &z); - foo.good(&mut a, b, &c); - foo.good2(); - foo.bad(&x, &y, &z); - Foo::bad2(&x, &y, &z); - bar.good(&mut a, b, &c); - Bar::bad2(&x, &y, &z); - foo.as_ref(); -} diff --git a/tests/ui/trivially_copy_pass_by_ref.stderr b/tests/ui/trivially_copy_pass_by_ref.stderr index e813fecf653ac..f101ac5ccd680 100644 --- a/tests/ui/trivially_copy_pass_by_ref.stderr +++ b/tests/ui/trivially_copy_pass_by_ref.stderr @@ -1,5 +1,5 @@ -error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:52:11 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) + --> tests/ui/trivially_copy_pass_by_ref.rs:53:11 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` @@ -10,107 +10,107 @@ note: the lint level is defined here LL | #![deny(clippy::trivially_copy_pass_by_ref)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:52:20 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) + --> tests/ui/trivially_copy_pass_by_ref.rs:53:20 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` -error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:52:29 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) + --> tests/ui/trivially_copy_pass_by_ref.rs:53:29 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` -error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:62:12 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) + --> tests/ui/trivially_copy_pass_by_ref.rs:63:12 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^^ help: consider passing by value instead: `self` -error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:62:22 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) + --> tests/ui/trivially_copy_pass_by_ref.rs:63:22 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` -error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:62:31 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) + --> tests/ui/trivially_copy_pass_by_ref.rs:63:31 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` -error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:62:40 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) + --> tests/ui/trivially_copy_pass_by_ref.rs:63:40 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` -error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:68:16 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) + --> tests/ui/trivially_copy_pass_by_ref.rs:69:16 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` -error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:68:25 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) + --> tests/ui/trivially_copy_pass_by_ref.rs:69:25 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` -error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:68:34 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) + --> tests/ui/trivially_copy_pass_by_ref.rs:69:34 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` -error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:73:35 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) + --> tests/ui/trivially_copy_pass_by_ref.rs:74:35 | LL | fn bad_issue7518(self, other: &Self) {} | ^^^^^ help: consider passing by value instead: `Self` -error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:86:16 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) + --> tests/ui/trivially_copy_pass_by_ref.rs:87:16 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` -error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:86:25 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) + --> tests/ui/trivially_copy_pass_by_ref.rs:87:25 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` -error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:86:34 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) + --> tests/ui/trivially_copy_pass_by_ref.rs:87:34 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` -error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:93:34 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) + --> tests/ui/trivially_copy_pass_by_ref.rs:94:33 | -LL | fn trait_method(&self, _foo: &Foo); - | ^^^^ help: consider passing by value instead: `Foo` +LL | fn trait_method(&self, foo: &Foo); + | ^^^^ help: consider passing by value instead: `Foo` -error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:126:21 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) + --> tests/ui/trivially_copy_pass_by_ref.rs:132:21 | LL | fn foo_never(x: &i32) { | ^^^^ help: consider passing by value instead: `i32` -error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:132:15 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) + --> tests/ui/trivially_copy_pass_by_ref.rs:138:15 | LL | fn foo(x: &i32) { | ^^^^ help: consider passing by value instead: `i32` -error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:160:37 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) + --> tests/ui/trivially_copy_pass_by_ref.rs:164:36 | -LL | fn _unrelated_lifetimes<'a, 'b>(_x: &'a u32, y: &'b u32) -> &'b u32 { - | ^^^^^^^ help: consider passing by value instead: `u32` +LL | fn unrelated_lifetimes<'a, 'b>(_x: &'a u32, y: &'b u32) -> &'b u32 { + | ^^^^^^^ help: consider passing by value instead: `u32` error: aborting due to 18 previous errors From e3a8d9c6a3ed67948cded5a3cbef65c15fd6b180 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 3 Apr 2025 15:30:01 +0000 Subject: [PATCH 1760/4206] Fix testing with randomized layouts enabled --- build_system/tests.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build_system/tests.rs b/build_system/tests.rs index eb15a3fc027eb..eec89c026b26a 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -109,10 +109,12 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[ SYSROOT_TESTS.clean(&runner.dirs); + let mut target_compiler = runner.target_compiler.clone(); // coretests and alloctests produce a bunch of warnings. When running // in rust's CI warnings are denied, so we have to override that here. - let mut target_compiler = runner.target_compiler.clone(); target_compiler.rustflags.push("--cap-lints=allow".to_owned()); + // The standard library may have been compiled with -Zrandomize-layout. + target_compiler.rustflags.extend(["--cfg".to_owned(), "randomized_layouts".to_owned()]); if runner.is_native { let mut test_cmd = SYSROOT_TESTS.test(&target_compiler, &runner.dirs); From 4807c29d0837c3ee0af94563b8a801f4f2c4c356 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 4 Apr 2025 10:30:15 +0000 Subject: [PATCH 1761/4206] Rustup to rustc 1.88.0-nightly (00095b3da 2025-04-03) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index ceff15b1180a7..c03f085756984 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-03-30" +channel = "nightly-2025-04-04" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From b0c23f78c98b71f6a202983b4278386cf1703ce7 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 4 Apr 2025 10:41:27 +0000 Subject: [PATCH 1762/4206] Fix rustc test suite --- scripts/test_rustc_tests.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 95a4302b5e471..01c8b474a9d11 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -130,6 +130,7 @@ rm -r tests/run-make/translation # same rm -r tests/run-make/missing-unstable-trait-bound # This disables support for unstable features, but running cg_clif needs some unstable features rm -r tests/run-make/const-trait-stable-toolchain # same rm -r tests/run-make/incr-add-rust-src-component +rm tests/ui/errors/remap-path-prefix-sysroot.rs # different sysroot source path # genuine bugs # ============ From 829413d208d4dc71e5b16ab2d60c86b5934122e8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 4 Apr 2025 10:46:47 +0000 Subject: [PATCH 1763/4206] Tell rustfmt to use the 2024 edition --- .github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6fd288d195c05..d92e0fdce99a8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,9 +34,9 @@ jobs: - name: Rustfmt run: | cargo fmt --check - rustfmt --check build_system/main.rs - rustfmt --check example/* - rustfmt --check scripts/*.rs + rustfmt --check --edition 2024 build_system/main.rs + rustfmt --check --edition 2024 example/* + rustfmt --check --edition 2024 scripts/*.rs test: From 4a8026ce639f2e5e09d20320ca569fedcafcef6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sun, 6 Apr 2025 15:10:23 +0200 Subject: [PATCH 1764/4206] update docs - src\doc\nomicon\src\ffi.md should also have its ABI list updated --- src/intrinsics/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index 75f3a3c19724f..d3f47ad726334 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -1,5 +1,4 @@ -//! Codegen of intrinsics. This includes `extern "rust-intrinsic"`, -//! functions marked with the `#[rustc_intrinsic]` attribute +//! Codegen of intrinsics. This includes functions marked with the `#[rustc_intrinsic]` attribute //! and LLVM intrinsics that have symbol names starting with `llvm.`. macro_rules! intrinsic_args { From 25f263ded766cdbb916de3ff5724fe1cfb2fb803 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 7 Apr 2025 19:40:28 +0000 Subject: [PATCH 1765/4206] Rustup to rustc 1.88.0-nightly (2fa8b11f0 2025-04-06) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index c03f085756984..01cba7ac9e09c 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-04-04" +channel = "nightly-2025-04-07" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 0e9a8540b011a8c0adb0e2c542cfb31c5aaf61a8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 7 Apr 2025 20:28:24 +0000 Subject: [PATCH 1766/4206] Preserve rustc_literal_escaper with --sysroot llvm --- build_system/build_sysroot.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build_system/build_sysroot.rs b/build_system/build_sysroot.rs index a73e3c87d43d0..a6e956c51f134 100644 --- a/build_system/build_sysroot.rs +++ b/build_system/build_sysroot.rs @@ -168,7 +168,8 @@ fn build_llvm_sysroot_for_triple(compiler: Compiler) -> SysrootTarget { let file_name_str = file.file_name().unwrap().to_str().unwrap(); if (file_name_str.contains("rustc_") && !file_name_str.contains("rustc_std_workspace_") - && !file_name_str.contains("rustc_demangle")) + && !file_name_str.contains("rustc_demangle") + && !file_name_str.contains("rustc_literal_escaper")) || file_name_str.contains("chalk") || file_name_str.contains("tracing") || file_name_str.contains("regex") From ab84fe61ed38bf68e1502d580a22b14535c49d9f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 6 Apr 2025 23:37:30 +0000 Subject: [PATCH 1767/4206] Simplify temp path creation a bit --- src/driver/aot.rs | 24 +++++++++--------------- src/global_asm.rs | 2 +- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/driver/aot.rs b/src/driver/aot.rs index 444dc4412868f..4ac7b86f0856f 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -169,8 +169,8 @@ fn produce_final_output_artifacts( if codegen_results.modules.len() == 1 { // 1) Only one codegen unit. In this case it's no difficulty // to copy `foo.0.x` to `foo.x`. - let module_name = Some(&codegen_results.modules[0].name[..]); - let path = crate_output.temp_path(output_type, module_name); + let path = + crate_output.temp_path_for_cgu(output_type, &codegen_results.modules[0].name); let output = crate_output.path(output_type); if !output_type.is_text_output() && output.is_tty() { sess.dcx() @@ -183,22 +183,16 @@ fn produce_final_output_artifacts( ensure_removed(sess.dcx(), &path); } } else { - let extension = crate_output - .temp_path(output_type, None) - .extension() - .unwrap() - .to_str() - .unwrap() - .to_owned(); - if crate_output.outputs.contains_explicit_name(&output_type) { // 2) Multiple codegen units, with `--emit foo=some_name`. We have // no good solution for this case, so warn the user. - sess.dcx().emit_warn(ssa_errors::IgnoringEmitPath { extension }); + sess.dcx() + .emit_warn(ssa_errors::IgnoringEmitPath { extension: output_type.extension() }); } else if crate_output.single_output_file.is_some() { // 3) Multiple codegen units, with `-o some_name`. We have // no good solution for this case, so warn the user. - sess.dcx().emit_warn(ssa_errors::IgnoringOutput { extension }); + sess.dcx() + .emit_warn(ssa_errors::IgnoringOutput { extension: output_type.extension() }); } else { // 4) Multiple codegen units, but no explicit name. We // just leave the `foo.0.x` files in place. @@ -409,7 +403,7 @@ fn emit_module( object.set_section_data(comment_section, producer, 1); } - let tmp_file = output_filenames.temp_path(OutputType::Object, Some(&name)); + let tmp_file = output_filenames.temp_path_for_cgu(OutputType::Object, &name); let file = match File::create(&tmp_file) { Ok(file) => file, Err(err) => return Err(format!("error creating object file: {}", err)), @@ -450,7 +444,7 @@ fn reuse_workproduct_for_cgu( ) -> Result { let work_product = cgu.previous_work_product(tcx); let obj_out_regular = - tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu.name().as_str())); + tcx.output_filenames(()).temp_path_for_cgu(OutputType::Object, cgu.name().as_str()); let source_file_regular = rustc_incremental::in_incr_comp_dir_sess( &tcx.sess, &work_product.saved_files.get("o").expect("no saved object file in work product"), @@ -627,7 +621,7 @@ fn emit_metadata_module(tcx: TyCtxt<'_>, metadata: &EncodedMetadata) -> Compiled .to_string(); let tmp_file = - tcx.output_filenames(()).temp_path(OutputType::Metadata, Some(&metadata_cgu_name)); + tcx.output_filenames(()).temp_path_for_cgu(OutputType::Metadata, &metadata_cgu_name); let symbol_name = rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx); let obj = create_compressed_metadata_file(tcx.sess, metadata, &symbol_name); diff --git a/src/global_asm.rs b/src/global_asm.rs index 9ea92c300f898..6e3b3677a7ff0 100644 --- a/src/global_asm.rs +++ b/src/global_asm.rs @@ -146,7 +146,7 @@ pub(crate) fn compile_global_asm( global_asm.push('\n'); let global_asm_object_file = add_file_stem_postfix( - config.output_filenames.temp_path(OutputType::Object, Some(cgu_name)), + config.output_filenames.temp_path_for_cgu(OutputType::Object, cgu_name), ".asm", ); From 68dd8b344a7882738cf816949e238578c7c4cc63 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 6 Apr 2025 23:50:16 +0000 Subject: [PATCH 1768/4206] Prepend temp files with a string per invocation of rustc --- src/driver/aot.rs | 35 +++++++++++++++++++++++++++-------- src/global_asm.rs | 3 ++- src/lib.rs | 2 ++ 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/driver/aot.rs b/src/driver/aot.rs index 4ac7b86f0856f..0ea0dbfc44b6d 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -169,8 +169,11 @@ fn produce_final_output_artifacts( if codegen_results.modules.len() == 1 { // 1) Only one codegen unit. In this case it's no difficulty // to copy `foo.0.x` to `foo.x`. - let path = - crate_output.temp_path_for_cgu(output_type, &codegen_results.modules[0].name); + let path = crate_output.temp_path_for_cgu( + output_type, + &codegen_results.modules[0].name, + sess.invocation_temp.as_deref(), + ); let output = crate_output.path(output_type); if !output_type.is_text_output() && output.is_tty() { sess.dcx() @@ -345,6 +348,7 @@ fn make_module(sess: &Session, name: String) -> UnwindModule { fn emit_cgu( output_filenames: &OutputFilenames, + invocation_temp: Option<&str>, prof: &SelfProfilerRef, name: String, module: UnwindModule, @@ -360,6 +364,7 @@ fn emit_cgu( let module_regular = emit_module( output_filenames, + invocation_temp, prof, product.object, ModuleKind::Regular, @@ -385,6 +390,7 @@ fn emit_cgu( fn emit_module( output_filenames: &OutputFilenames, + invocation_temp: Option<&str>, prof: &SelfProfilerRef, mut object: cranelift_object::object::write::Object<'_>, kind: ModuleKind, @@ -403,7 +409,7 @@ fn emit_module( object.set_section_data(comment_section, producer, 1); } - let tmp_file = output_filenames.temp_path_for_cgu(OutputType::Object, &name); + let tmp_file = output_filenames.temp_path_for_cgu(OutputType::Object, &name, invocation_temp); let file = match File::create(&tmp_file) { Ok(file) => file, Err(err) => return Err(format!("error creating object file: {}", err)), @@ -443,8 +449,11 @@ fn reuse_workproduct_for_cgu( cgu: &CodegenUnit<'_>, ) -> Result { let work_product = cgu.previous_work_product(tcx); - let obj_out_regular = - tcx.output_filenames(()).temp_path_for_cgu(OutputType::Object, cgu.name().as_str()); + let obj_out_regular = tcx.output_filenames(()).temp_path_for_cgu( + OutputType::Object, + cgu.name().as_str(), + tcx.sess.invocation_temp.as_deref(), + ); let source_file_regular = rustc_incremental::in_incr_comp_dir_sess( &tcx.sess, &work_product.saved_files.get("o").expect("no saved object file in work product"), @@ -589,13 +598,19 @@ fn module_codegen( let global_asm_object_file = profiler.generic_activity_with_arg("compile assembly", &*cgu_name).run(|| { - crate::global_asm::compile_global_asm(&global_asm_config, &cgu_name, &cx.global_asm) + crate::global_asm::compile_global_asm( + &global_asm_config, + &cgu_name, + &cx.global_asm, + cx.invocation_temp.as_deref(), + ) })?; let codegen_result = profiler.generic_activity_with_arg("write object file", &*cgu_name).run(|| { emit_cgu( &global_asm_config.output_filenames, + cx.invocation_temp.as_deref(), &profiler, cgu_name, module, @@ -620,8 +635,11 @@ fn emit_metadata_module(tcx: TyCtxt<'_>, metadata: &EncodedMetadata) -> Compiled .as_str() .to_string(); - let tmp_file = - tcx.output_filenames(()).temp_path_for_cgu(OutputType::Metadata, &metadata_cgu_name); + let tmp_file = tcx.output_filenames(()).temp_path_for_cgu( + OutputType::Metadata, + &metadata_cgu_name, + tcx.sess.invocation_temp.as_deref(), + ); let symbol_name = rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx); let obj = create_compressed_metadata_file(tcx.sess, metadata, &symbol_name); @@ -651,6 +669,7 @@ fn emit_allocator_module(tcx: TyCtxt<'_>) -> Option { match emit_module( tcx.output_filenames(()), + tcx.sess.invocation_temp.as_deref(), &tcx.sess.prof, product.object, ModuleKind::Allocator, diff --git a/src/global_asm.rs b/src/global_asm.rs index 6e3b3677a7ff0..79cefb05de322 100644 --- a/src/global_asm.rs +++ b/src/global_asm.rs @@ -132,6 +132,7 @@ pub(crate) fn compile_global_asm( config: &GlobalAsmConfig, cgu_name: &str, global_asm: &str, + invocation_temp: Option<&str>, ) -> Result, String> { if global_asm.is_empty() { return Ok(None); @@ -146,7 +147,7 @@ pub(crate) fn compile_global_asm( global_asm.push('\n'); let global_asm_object_file = add_file_stem_postfix( - config.output_filenames.temp_path_for_cgu(OutputType::Object, cgu_name), + config.output_filenames.temp_path_for_cgu(OutputType::Object, cgu_name, invocation_temp), ".asm", ); diff --git a/src/lib.rs b/src/lib.rs index e7afaff3b428f..9d9e790289cf6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -124,6 +124,7 @@ impl String> Drop for PrintOnPanic { /// inside a single codegen unit with the exception of the Cranelift [`Module`](cranelift_module::Module). struct CodegenCx { output_filenames: Arc, + invocation_temp: Option, should_write_ir: bool, global_asm: String, inline_asm_index: usize, @@ -142,6 +143,7 @@ impl CodegenCx { }; CodegenCx { output_filenames: tcx.output_filenames(()).clone(), + invocation_temp: tcx.sess.invocation_temp.clone(), should_write_ir: crate::pretty_clif::should_write_ir(tcx), global_asm: String::new(), inline_asm_index: 0, From b69a4787b4fc86a8d1cc2563d9d6aade092e83b5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 8 Apr 2025 09:47:26 +0000 Subject: [PATCH 1769/4206] Rustup to rustc 1.88.0-nightly (e643f59f6 2025-04-07) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 01cba7ac9e09c..4be668c7b8488 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-04-07" +channel = "nightly-2025-04-08" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 6424f0a7ba84253c8db42d66d3e80ef74e65f92b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 8 Apr 2025 10:25:03 +0000 Subject: [PATCH 1770/4206] Replace trap_unimplemented calls with codegen_panic_nounwind This will show a backtrace. Also added a reference to rust-lang/rustc_codegen_cranelift#171 in the unimplemented intrinsic error message. --- src/intrinsics/llvm.rs | 7 ++++++- src/intrinsics/llvm_aarch64.rs | 7 ++++++- src/intrinsics/llvm_x86.rs | 7 ++++++- src/intrinsics/mod.rs | 12 +++++++++-- src/lib.rs | 1 - src/trap.rs | 38 ---------------------------------- 6 files changed, 28 insertions(+), 44 deletions(-) delete mode 100644 src/trap.rs diff --git a/src/intrinsics/llvm.rs b/src/intrinsics/llvm.rs index eb0dfbb69c3b7..2e02e85a997d5 100644 --- a/src/intrinsics/llvm.rs +++ b/src/intrinsics/llvm.rs @@ -66,7 +66,12 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( fx.tcx .dcx() .warn(format!("unsupported llvm intrinsic {}; replacing with trap", intrinsic)); - crate::trap::trap_unimplemented(fx, intrinsic); + let msg = format!( + "{intrinsic} is not yet supported.\n\ + See https://github.com/rust-lang/rustc_codegen_cranelift/issues/171\n\ + Please open an issue at https://github.com/rust-lang/rustc_codegen_cranelift/issues" + ); + crate::base::codegen_panic_nounwind(fx, &msg, None); return; } } diff --git a/src/intrinsics/llvm_aarch64.rs b/src/intrinsics/llvm_aarch64.rs index 387c87d123a39..06e8663a8b774 100644 --- a/src/intrinsics/llvm_aarch64.rs +++ b/src/intrinsics/llvm_aarch64.rs @@ -507,7 +507,12 @@ pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( "unsupported AArch64 llvm intrinsic {}; replacing with trap", intrinsic )); - crate::trap::trap_unimplemented(fx, intrinsic); + let msg = format!( + "{intrinsic} is not yet supported.\n\ + See https://github.com/rust-lang/rustc_codegen_cranelift/issues/171\n\ + Please open an issue at https://github.com/rust-lang/rustc_codegen_cranelift/issues" + ); + crate::base::codegen_panic_nounwind(fx, &msg, None); return; } } diff --git a/src/intrinsics/llvm_x86.rs b/src/intrinsics/llvm_x86.rs index c02d31844e032..3adff1f749a8a 100644 --- a/src/intrinsics/llvm_x86.rs +++ b/src/intrinsics/llvm_x86.rs @@ -1316,7 +1316,12 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( fx.tcx .dcx() .warn(format!("unsupported x86 llvm intrinsic {}; replacing with trap", intrinsic)); - crate::trap::trap_unimplemented(fx, intrinsic); + let msg = format!( + "{intrinsic} is not yet supported.\n\ + See https://github.com/rust-lang/rustc_codegen_cranelift/issues/171\n\ + Please open an issue at https://github.com/rust-lang/rustc_codegen_cranelift/issues" + ); + crate::base::codegen_panic_nounwind(fx, &msg, None); return; } } diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index d3f47ad726334..0048a3e8db5a4 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -801,7 +801,11 @@ fn codegen_regular_intrinsic_call<'tcx>( // FIXME implement 128bit atomics if fx.tcx.is_compiler_builtins(LOCAL_CRATE) { // special case for compiler-builtins to avoid having to patch it - crate::trap::trap_unimplemented(fx, "128bit atomics not yet supported"); + crate::base::codegen_panic_nounwind( + fx, + "128bit atomics not yet supported", + None, + ); return Ok(()); } else { fx.tcx @@ -832,7 +836,11 @@ fn codegen_regular_intrinsic_call<'tcx>( // FIXME implement 128bit atomics if fx.tcx.is_compiler_builtins(LOCAL_CRATE) { // special case for compiler-builtins to avoid having to patch it - crate::trap::trap_unimplemented(fx, "128bit atomics not yet supported"); + crate::base::codegen_panic_nounwind( + fx, + "128bit atomics not yet supported", + None, + ); return Ok(()); } else { fx.tcx diff --git a/src/lib.rs b/src/lib.rs index e7afaff3b428f..c0063a40d39f6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -76,7 +76,6 @@ mod optimize; mod pointer; mod pretty_clif; mod toolchain; -mod trap; mod unsize; mod unwind_module; mod value_and_place; diff --git a/src/trap.rs b/src/trap.rs deleted file mode 100644 index ac3f58ee1ee6e..0000000000000 --- a/src/trap.rs +++ /dev/null @@ -1,38 +0,0 @@ -//! Helpers used to print a message and abort in case of certain panics and some detected UB. - -use crate::prelude::*; - -fn codegen_print(fx: &mut FunctionCx<'_, '_, '_>, msg: &str) { - let puts = fx - .module - .declare_function( - "puts", - Linkage::Import, - &Signature { - call_conv: fx.target_config.default_call_conv, - params: vec![AbiParam::new(fx.pointer_type)], - returns: vec![AbiParam::new(types::I32)], - }, - ) - .unwrap(); - let puts = fx.module.declare_func_in_func(puts, &mut fx.bcx.func); - if fx.clif_comments.enabled() { - fx.add_comment(puts, "puts"); - } - - let real_msg = format!("trap at {:?} ({}): {}\0", fx.instance, fx.symbol_name, msg); - let msg_ptr = fx.anonymous_str(&real_msg); - fx.bcx.ins().call(puts, &[msg_ptr]); -} - -/// Use this when something is unimplemented, but `libcore` or `libstd` requires it to codegen. -/// -/// Trap code: user65535 -pub(crate) fn trap_unimplemented(fx: &mut FunctionCx<'_, '_, '_>, msg: impl AsRef) { - codegen_print(fx, msg.as_ref()); - - let one = fx.bcx.ins().iconst(types::I32, 1); - fx.lib_call("exit", vec![AbiParam::new(types::I32)], vec![], &[one]); - - fx.bcx.ins().trap(TrapCode::user(3).unwrap()); -} From 420e44f57848e3b21d1b5dd983f77536a1b7d43b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 8 Apr 2025 18:41:42 +0000 Subject: [PATCH 1771/4206] Reduce visibility of a couple of functions --- src/driver/jit.rs | 2 +- src/intrinsics/llvm_aarch64.rs | 2 +- src/intrinsics/llvm_x86.rs | 2 +- src/num.rs | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/driver/jit.rs b/src/driver/jit.rs index 41f8bb9161ca2..0e2e1f6fc0a88 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -119,7 +119,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, jit_args: Vec) -> ! { std::process::exit(ret); } -pub(crate) fn codegen_and_compile_fn<'tcx>( +fn codegen_and_compile_fn<'tcx>( tcx: TyCtxt<'tcx>, cx: &mut crate::CodegenCx, cached_context: &mut Context, diff --git a/src/intrinsics/llvm_aarch64.rs b/src/intrinsics/llvm_aarch64.rs index 06e8663a8b774..d22483cf17764 100644 --- a/src/intrinsics/llvm_aarch64.rs +++ b/src/intrinsics/llvm_aarch64.rs @@ -7,7 +7,7 @@ use crate::inline_asm::{CInlineAsmOperand, codegen_inline_asm_inner}; use crate::intrinsics::*; use crate::prelude::*; -pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( +pub(super) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, intrinsic: &str, args: &[Spanned>], diff --git a/src/intrinsics/llvm_x86.rs b/src/intrinsics/llvm_x86.rs index 3adff1f749a8a..e145eda606855 100644 --- a/src/intrinsics/llvm_x86.rs +++ b/src/intrinsics/llvm_x86.rs @@ -7,7 +7,7 @@ use crate::inline_asm::{CInlineAsmOperand, codegen_inline_asm_inner}; use crate::intrinsics::*; use crate::prelude::*; -pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( +pub(super) fn codegen_x86_llvm_intrinsic_call<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, intrinsic: &str, args: &[Spanned>], diff --git a/src/num.rs b/src/num.rs index 2a4d1e3ae571d..90627f8060b8b 100644 --- a/src/num.rs +++ b/src/num.rs @@ -2,7 +2,7 @@ use crate::prelude::*; -pub(crate) fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> IntCC { +fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> IntCC { use BinOp::*; use IntCC::*; match bin_op { @@ -109,7 +109,7 @@ pub(crate) fn codegen_binop<'tcx>( } } -pub(crate) fn codegen_bool_binop<'tcx>( +fn codegen_bool_binop<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, bin_op: BinOp, in_lhs: CValue<'tcx>, @@ -389,7 +389,7 @@ pub(crate) fn codegen_float_binop<'tcx>( CValue::by_val(res, in_lhs.layout()) } -pub(crate) fn codegen_ptr_binop<'tcx>( +fn codegen_ptr_binop<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, bin_op: BinOp, in_lhs: CValue<'tcx>, From 87595c5d825a62219964752b2c63918ee97c5ab9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 9 Apr 2025 02:40:43 +0000 Subject: [PATCH 1772/4206] Remove a mention of `force-soft-float` in `build.rs` `libm` no longer uses this directly in `cfg`, it is only for setting other configuration in the `libm` `build.rs`. Clean up this configuration in `compiler-builtins` since it is unused. --- library/compiler-builtins/compiler-builtins/build.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/build.rs b/library/compiler-builtins/compiler-builtins/build.rs index fdfb61b17df7c..d627121f348be 100644 --- a/library/compiler-builtins/compiler-builtins/build.rs +++ b/library/compiler-builtins/compiler-builtins/build.rs @@ -101,9 +101,7 @@ fn configure_libm(target: &Target) { println!("cargo:rustc-cfg=intrinsics_enabled"); // The arch module may contain assembly. - if cfg!(feature = "no-asm") { - println!("cargo:rustc-cfg=feature=\"force-soft-floats\""); - } else { + if !cfg!(feature = "no-asm") { println!("cargo:rustc-cfg=arch_enabled"); } From 4e5cbbeda169377e5025a979105d0dac31bf560a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 9 Apr 2025 01:56:14 +0000 Subject: [PATCH 1773/4206] Replace calls to `core::arch` intrinsics with assembly Some backends may replace calls to `core::arch` with multiple calls to `sqrt` [1], which becomes recursive. Help mitigate this by replacing the call with assembly. Results in the same assembly as the current implementation when built with optimizations. [1]: https://github.com/rust-lang/compiler-builtins/issues/649 --- .../libm/src/math/arch/i686.rs | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/arch/i686.rs b/library/compiler-builtins/libm/src/math/arch/i686.rs index ad54d8b61d779..3e1d19bfab699 100644 --- a/library/compiler-builtins/libm/src/math/arch/i686.rs +++ b/library/compiler-builtins/libm/src/math/arch/i686.rs @@ -1,22 +1,27 @@ //! Architecture-specific support for x86-32 and x86-64 with SSE2 -#[cfg(target_arch = "x86")] -use core::arch::x86::*; -#[cfg(target_arch = "x86_64")] -use core::arch::x86_64::*; - -pub fn sqrtf(x: f32) -> f32 { +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. unsafe { - let m = _mm_set_ss(x); - let m_sqrt = _mm_sqrt_ss(m); - _mm_cvtss_f32(m_sqrt) - } + core::arch::asm!( + "sqrtss {x}, {x}", + x = inout(xmm_reg) x, + options(nostack, nomem, pure), + ) + }; + x } -pub fn sqrt(x: f64) -> f64 { +pub fn sqrt(mut x: f64) -> f64 { + // SAFETY: `sqrtsd` is part of `sse2`, which this module is gated behind. It has no memory + // access or side effects. unsafe { - let m = _mm_set_sd(x); - let m_sqrt = _mm_sqrt_pd(m); - _mm_cvtsd_f64(m_sqrt) - } + core::arch::asm!( + "sqrtsd {x}, {x}", + x = inout(xmm_reg) x, + options(nostack, nomem, pure), + ) + }; + x } From 375cb5402fb1aa6bf8b4c513921b5f087decb3ca Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 9 Apr 2025 02:22:15 +0000 Subject: [PATCH 1774/4206] Resolve small errors identified by recent clippy --- library/compiler-builtins/libm/crates/libm-test/src/precision.rs | 1 + library/compiler-builtins/libm/src/math/support/env.rs | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs index 8916b43ab1729..f5fb5f6707b08 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/precision.rs @@ -13,6 +13,7 @@ use crate::{BaseName, CheckBasis, CheckCtx, Float, Identifier, Int, TestResult}; 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 { // ULP compared to the infinite (MPFR) result. let mut ulp = match ctx.base_name { diff --git a/library/compiler-builtins/libm/src/math/support/env.rs b/library/compiler-builtins/libm/src/math/support/env.rs index 7244381dacc60..c05890d985186 100644 --- a/library/compiler-builtins/libm/src/math/support/env.rs +++ b/library/compiler-builtins/libm/src/math/support/env.rs @@ -70,7 +70,6 @@ impl Status { /// The default result for division is +/-inf based on operand sign. For `logB`, the default /// result is -inf. /// `x / y` when `x != 0.0` and `y == 0.0`, - #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] pub const DIVIDE_BY_ZERO: Self = Self(1 << 2); From 28b6df86036aeeb231e2ea09c78ea33645aa4325 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 23 Jan 2025 01:46:24 +0000 Subject: [PATCH 1775/4206] Add assembly version of simple operations on aarch64 Replace `core::arch` versions of the following with handwritten assembly, which avoids recursion issues (cg_gcc using `rint` as a fallback) as well as problems with `aarch64be`. * `rint` * `rintf` Additionally, add assembly versions of the following: * `fma` * `fmaf` * `sqrt` * `sqrtf` If the `fp16` target feature is available, which implies `neon`, also include the following: * `rintf16` * `sqrtf16` `sqrt` is added to match the implementation for `x86`. `fma` is included since it is used by many other routines. There are a handful of other operations that have assembly implementations. They are omitted here because we should have basic float math routines available in `core` in the near future, which will allow us to defer to LLVM for assembly lowering rather than implementing these ourselves. --- .../libm/etc/function-definitions.json | 6 + .../libm/src/math/arch/aarch64.rs | 126 +++++++++++++++--- .../libm/src/math/arch/mod.rs | 21 ++- .../compiler-builtins/libm/src/math/fma.rs | 6 + .../libm/src/math/fma_wide.rs | 6 + .../compiler-builtins/libm/src/math/rint.rs | 10 +- .../compiler-builtins/libm/src/math/sqrt.rs | 1 + .../compiler-builtins/libm/src/math/sqrtf.rs | 1 + .../libm/src/math/sqrtf16.rs | 6 + 9 files changed, 155 insertions(+), 28 deletions(-) diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 64a775ba9f173..bca58402f4e97 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -342,12 +342,14 @@ }, "fma": { "sources": [ + "src/math/arch/aarch64.rs", "src/math/fma.rs" ], "type": "f64" }, "fmaf": { "sources": [ + "src/math/arch/aarch64.rs", "src/math/fma_wide.rs" ], "type": "f32" @@ -806,6 +808,7 @@ }, "rintf16": { "sources": [ + "src/math/arch/aarch64.rs", "src/math/rint.rs" ], "type": "f16" @@ -928,6 +931,7 @@ }, "sqrt": { "sources": [ + "src/math/arch/aarch64.rs", "src/math/arch/i686.rs", "src/math/arch/wasm32.rs", "src/math/generic/sqrt.rs", @@ -937,6 +941,7 @@ }, "sqrtf": { "sources": [ + "src/math/arch/aarch64.rs", "src/math/arch/i686.rs", "src/math/arch/wasm32.rs", "src/math/generic/sqrt.rs", @@ -953,6 +958,7 @@ }, "sqrtf16": { "sources": [ + "src/math/arch/aarch64.rs", "src/math/generic/sqrt.rs", "src/math/sqrtf16.rs" ], diff --git a/library/compiler-builtins/libm/src/math/arch/aarch64.rs b/library/compiler-builtins/libm/src/math/arch/aarch64.rs index 374ec11bfec3f..020bb731cdc7a 100644 --- a/library/compiler-builtins/libm/src/math/arch/aarch64.rs +++ b/library/compiler-builtins/libm/src/math/arch/aarch64.rs @@ -1,33 +1,115 @@ -use core::arch::aarch64::{ - float32x2_t, float64x1_t, vdup_n_f32, vdup_n_f64, vget_lane_f32, vget_lane_f64, vrndn_f32, - vrndn_f64, -}; +//! Architecture-specific support for aarch64 with neon. -pub fn rint(x: f64) -> f64 { - // SAFETY: only requires target_feature=neon, ensured by `cfg_if` in parent module. - let x_vec: float64x1_t = unsafe { vdup_n_f64(x) }; +use core::arch::asm; - // SAFETY: only requires target_feature=neon, ensured by `cfg_if` in parent module. - let result_vec: float64x1_t = unsafe { vrndn_f64(x_vec) }; +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 +} - // SAFETY: only requires target_feature=neon, ensured by `cfg_if` in parent module. - let result: f64 = unsafe { vget_lane_f64::<0>(result_vec) }; +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 +} - result +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:d}, {x:d}", + x = inout(vreg) x, + options(nomem, nostack, pure) + ); + } + x } -pub fn rintf(x: f32) -> f32 { - // There's a scalar form of this instruction (FRINTN) but core::arch doesn't expose it, so we - // have to use the vector form and drop the other lanes afterwards. +pub fn rintf(mut x: f32) -> f32 { + // 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:s}, {x:s}", + x = inout(vreg) x, + options(nomem, nostack, pure) + ); + } + x +} - // SAFETY: only requires target_feature=neon, ensured by `cfg_if` in parent module. - let x_vec: float32x2_t = unsafe { vdup_n_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. + // + // `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}", + x = inout(vreg) x, + options(nomem, nostack, pure) + ); + } + x +} - // SAFETY: only requires target_feature=neon, ensured by `cfg_if` in parent module. - let result_vec: float32x2_t = unsafe { vrndn_f32(x_vec) }; +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 +} - // SAFETY: only requires target_feature=neon, ensured by `cfg_if` in parent module. - let result: f32 = unsafe { vget_lane_f32::<0>(result_vec) }; +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 +} - result +#[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/mod.rs b/library/compiler-builtins/libm/src/math/arch/mod.rs index 091d7650a5acc..d9f2aad66d40a 100644 --- a/library/compiler-builtins/libm/src/math/arch/mod.rs +++ b/library/compiler-builtins/libm/src/math/arch/mod.rs @@ -18,12 +18,25 @@ cfg_if! { mod i686; pub use i686::{sqrt, sqrtf}; } else if #[cfg(all( - target_arch = "aarch64", // TODO: also arm64ec? - target_feature = "neon", - target_endian = "little", // see https://github.com/rust-lang/stdarch/issues/1484 + any(target_arch = "aarch64", target_arch = "arm64ec"), + target_feature = "neon" ))] { mod aarch64; - pub use aarch64::{rint, rintf}; + + pub use aarch64::{ + fma, + fmaf, + rint, + rintf, + sqrt, + sqrtf, + }; + + #[cfg(all(f16_enabled, target_feature = "fp16"))] + pub use aarch64::{ + rintf16, + sqrtf16, + }; } } diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 049f573cc92a6..789b0836afbfa 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -9,6 +9,12 @@ use super::{CastFrom, CastInto, Float, Int, MinInt}; /// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fma(x: f64, y: f64, z: f64) -> f64 { + select_implementation! { + name: fma, + use_arch: all(target_arch = "aarch64", target_feature = "neon"), + args: x, y, z, + } + fma_round(x, y, z, Round::Nearest).val } diff --git a/library/compiler-builtins/libm/src/math/fma_wide.rs b/library/compiler-builtins/libm/src/math/fma_wide.rs index d0cf33baf7a87..8e908a14f2147 100644 --- a/library/compiler-builtins/libm/src/math/fma_wide.rs +++ b/library/compiler-builtins/libm/src/math/fma_wide.rs @@ -17,6 +17,12 @@ pub(crate) fn fmaf16(_x: f16, _y: f16, _z: f16) -> f16 { /// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmaf(x: f32, y: f32, z: f32) -> f32 { + select_implementation! { + name: fmaf, + use_arch: all(target_arch = "aarch64", target_feature = "neon"), + args: x, y, z, + } + fma_wide_round(x, y, z, Round::Nearest).val } diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index 8a5cbeab49793..e1c32c9435522 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -4,6 +4,12 @@ use super::support::Round; #[cfg(f16_enabled)] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn rintf16(x: f16) -> f16 { + select_implementation! { + name: rintf16, + use_arch: all(target_arch = "aarch64", target_feature = "fp16"), + args: x, + } + super::generic::rint_round(x, Round::Nearest).val } @@ -13,8 +19,8 @@ pub fn rintf(x: f32) -> f32 { select_implementation! { name: rintf, use_arch: any( + all(target_arch = "aarch64", target_feature = "neon"), all(target_arch = "wasm32", intrinsics_enabled), - all(target_arch = "aarch64", target_feature = "neon", target_endian = "little"), ), args: x, } @@ -28,8 +34,8 @@ pub fn rint(x: f64) -> f64 { select_implementation! { name: rint, use_arch: any( + all(target_arch = "aarch64", target_feature = "neon"), all(target_arch = "wasm32", intrinsics_enabled), - all(target_arch = "aarch64", target_feature = "neon", target_endian = "little"), ), args: x, } diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 0e1d0cd2c1c96..2bfc42bcfede9 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -4,6 +4,7 @@ pub fn sqrt(x: f64) -> f64 { select_implementation! { name: sqrt, use_arch: any( + all(target_arch = "aarch64", target_feature = "neon"), all(target_arch = "wasm32", intrinsics_enabled), target_feature = "sse2" ), diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs index 2e69a4b669428..c28a705e378e6 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf.rs @@ -4,6 +4,7 @@ pub fn sqrtf(x: f32) -> f32 { select_implementation! { name: sqrtf, use_arch: any( + all(target_arch = "aarch64", target_feature = "neon"), all(target_arch = "wasm32", intrinsics_enabled), target_feature = "sse2" ), diff --git a/library/compiler-builtins/libm/src/math/sqrtf16.rs b/library/compiler-builtins/libm/src/math/sqrtf16.rs index 549bf902c7221..7bedb7f8bbb6b 100644 --- a/library/compiler-builtins/libm/src/math/sqrtf16.rs +++ b/library/compiler-builtins/libm/src/math/sqrtf16.rs @@ -1,5 +1,11 @@ /// The square root of `x` (f16). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrtf16(x: f16) -> f16 { + select_implementation! { + name: sqrtf16, + use_arch: all(target_arch = "aarch64", target_feature = "fp16"), + args: x, + } + return super::generic::sqrt(x); } From ab514c95967a7c5d732aa1e3800afc4d9cb252f9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 9 Apr 2025 13:50:59 +0000 Subject: [PATCH 1776/4206] Pass UnwindAction to a couple of functions In preparation for future unwinding support. Part of rust-lang/rustc_codegen_cranelift#1567 --- src/abi/mod.rs | 20 +++++++++++++++----- src/abi/returning.rs | 12 +++++------- src/base.rs | 32 ++++++++++++++++++++++++++------ 3 files changed, 46 insertions(+), 18 deletions(-) diff --git a/src/abi/mod.rs b/src/abi/mod.rs index ddd119e0c6108..2c6dd851d4de3 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -20,6 +20,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::Session; use rustc_span::source_map::Spanned; use rustc_target::callconv::{Conv, FnAbi, PassMode}; +use smallvec::SmallVec; use self::pass_mode::*; pub(crate) use self::returning::codegen_return; @@ -384,6 +385,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( args: &[Spanned>], destination: Place<'tcx>, target: Option, + _unwind: UnwindAction, ) { let func = codegen_operand(fx, func); let fn_sig = func.layout().ty.fn_sig(fx.tcx); @@ -588,12 +590,14 @@ pub(crate) fn codegen_terminator_call<'tcx>( with_no_trimmed_paths!(fx.add_comment(nop_inst, format!("abi: {:?}", fn_abi))); } - match func_ref { + let call_inst = match func_ref { CallTarget::Direct(func_ref) => fx.bcx.ins().call(func_ref, &call_args), CallTarget::Indirect(sig, func_ptr) => { fx.bcx.ins().call_indirect(sig, func_ptr, &call_args) } - } + }; + + fx.bcx.func.dfg.inst_results(call_inst).iter().copied().collect::>() }); if let Some(dest) = target { @@ -703,14 +707,17 @@ pub(crate) fn codegen_drop<'tcx>( source_info: mir::SourceInfo, drop_place: CPlace<'tcx>, target: BasicBlock, + _unwind: UnwindAction, ) { let ty = drop_place.layout().ty; let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty); + let ret_block = fx.get_block(target); if let ty::InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None) = drop_instance.def { // we don't actually need to drop anything + fx.bcx.ins().jump(ret_block, &[]); } else { match ty.kind() { ty::Dynamic(_, _, ty::Dyn) => { @@ -747,7 +754,9 @@ pub(crate) fn codegen_drop<'tcx>( let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi); let sig = fx.bcx.import_signature(sig); + // FIXME implement cleanup on exceptions fx.bcx.ins().call_indirect(sig, drop_fn, &[ptr]); + fx.bcx.ins().jump(ret_block, &[]); } ty::Dynamic(_, _, ty::DynStar) => { // IN THIS ARM, WE HAVE: @@ -791,6 +800,8 @@ pub(crate) fn codegen_drop<'tcx>( let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi); let sig = fx.bcx.import_signature(sig); fx.bcx.ins().call_indirect(sig, drop_fn, &[data]); + // FIXME implement cleanup on exceptions + fx.bcx.ins().jump(ret_block, &[]); } _ => { assert!(!matches!(drop_instance.def, InstanceKind::Virtual(_, _))); @@ -816,10 +827,9 @@ pub(crate) fn codegen_drop<'tcx>( let func_ref = fx.get_function_ref(drop_instance); fx.bcx.ins().call(func_ref, &call_args); + // FIXME implement cleanup on exceptions + fx.bcx.ins().jump(ret_block, &[]); } } } - - let target_block = fx.get_block(target); - fx.bcx.ins().jump(target_block, &[]); } diff --git a/src/abi/returning.rs b/src/abi/returning.rs index 9e048c7badb84..36087f96dd776 100644 --- a/src/abi/returning.rs +++ b/src/abi/returning.rs @@ -46,7 +46,7 @@ pub(super) fn codegen_with_call_return_arg<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, ret_arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, ret_place: CPlace<'tcx>, - f: impl FnOnce(&mut FunctionCx<'_, '_, 'tcx>, Option) -> Inst, + f: impl FnOnce(&mut FunctionCx<'_, '_, 'tcx>, Option) -> SmallVec<[Value; 2]>, ) { let (ret_temp_place, return_ptr) = match ret_arg_abi.mode { PassMode::Ignore => (None, None), @@ -67,23 +67,21 @@ pub(super) fn codegen_with_call_return_arg<'tcx>( PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast { .. } => (None, None), }; - let call_inst = f(fx, return_ptr); + let results = f(fx, return_ptr); match ret_arg_abi.mode { PassMode::Ignore => {} PassMode::Direct(_) => { - let ret_val = fx.bcx.inst_results(call_inst)[0]; + let ret_val = results[0]; ret_place.write_cvalue(fx, CValue::by_val(ret_val, ret_arg_abi.layout)); } PassMode::Pair(_, _) => { - let ret_val_a = fx.bcx.inst_results(call_inst)[0]; - let ret_val_b = fx.bcx.inst_results(call_inst)[1]; + let ret_val_a = results[0]; + let ret_val_b = results[1]; ret_place .write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout)); } PassMode::Cast { ref cast, .. } => { - let results = - fx.bcx.inst_results(call_inst).iter().copied().collect::>(); let result = super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast); ret_place.write_cvalue(fx, result); diff --git a/src/base.rs b/src/base.rs index adaa754491e56..9d425a3b292a2 100644 --- a/src/base.rs +++ b/src/base.rs @@ -372,7 +372,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { TerminatorKind::Return => { crate::abi::codegen_return(fx); } - TerminatorKind::Assert { cond, expected, msg, target, unwind: _ } => { + TerminatorKind::Assert { cond, expected, msg, target, unwind } => { if !fx.tcx.sess.overflow_checks() && msg.is_optional_overflow_check() { let target = fx.get_block(*target); fx.bcx.ins().jump(target, &[]); @@ -402,6 +402,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { fx, rustc_hir::LangItem::PanicBoundsCheck, &[index, len, location], + *unwind, Some(source_info.span), ); } @@ -414,6 +415,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { fx, rustc_hir::LangItem::PanicMisalignedPointerDereference, &[required, found, location], + *unwind, Some(source_info.span), ); } @@ -424,6 +426,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { fx, rustc_hir::LangItem::PanicNullPointerDereference, &[location], + *unwind, Some(source_info.span), ) } @@ -434,6 +437,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { fx, msg.panic_function(), &[location], + *unwind, Some(source_info.span), ); } @@ -492,7 +496,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { destination, target, fn_span, - unwind: _, + unwind, call_source: _, } => { fx.tcx.prof.generic_activity("codegen call").run(|| { @@ -503,6 +507,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { args, *destination, *target, + *unwind, ) }); } @@ -565,9 +570,9 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { | TerminatorKind::CoroutineDrop => { bug!("shouldn't exist at codegen {:?}", bb_data.terminator()); } - TerminatorKind::Drop { place, target, unwind: _, replace: _ } => { + TerminatorKind::Drop { place, target, unwind, replace: _ } => { let drop_place = codegen_place(fx, *place); - crate::abi::codegen_drop(fx, source_info, drop_place, *target); + crate::abi::codegen_drop(fx, source_info, drop_place, *target, *unwind); } }; } @@ -1089,7 +1094,13 @@ pub(crate) fn codegen_panic_nounwind<'tcx>( let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap()); let args = [msg_ptr, msg_len]; - codegen_panic_inner(fx, rustc_hir::LangItem::PanicNounwind, &args, span); + codegen_panic_inner( + fx, + rustc_hir::LangItem::PanicNounwind, + &args, + UnwindAction::Terminate(UnwindTerminateReason::Abi), + span, + ); } pub(crate) fn codegen_unwind_terminate<'tcx>( @@ -1099,13 +1110,20 @@ pub(crate) fn codegen_unwind_terminate<'tcx>( ) { let args = []; - codegen_panic_inner(fx, reason.lang_item(), &args, Some(source_info.span)); + codegen_panic_inner( + fx, + reason.lang_item(), + &args, + UnwindAction::Terminate(UnwindTerminateReason::Abi), + Some(source_info.span), + ); } fn codegen_panic_inner<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, lang_item: rustc_hir::LangItem, args: &[Value], + _unwind: UnwindAction, span: Option, ) { fx.bcx.set_cold_block(fx.bcx.current_block().unwrap()); @@ -1121,6 +1139,8 @@ fn codegen_panic_inner<'tcx>( let symbol_name = fx.tcx.symbol_name(instance).name; + // FIXME implement cleanup on exceptions + fx.lib_call( symbol_name, args.iter().map(|&arg| AbiParam::new(fx.bcx.func.dfg.value_type(arg))).collect(), From 9495eb517e5a2b76fcdb514eeec5aa4d8fd16320 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 9 Apr 2025 14:05:27 +0000 Subject: [PATCH 1777/4206] Pass Module to UnwindContext Once writing the LSDA, it will need access to the Module to get a reference to the personality function and to define a data object for the LSDA. Part of rust-lang/rustc_codegen_cranelift#1567 --- src/debuginfo/unwind.rs | 20 +++++++++++++------- src/unwind_module.rs | 8 ++++---- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/debuginfo/unwind.rs b/src/debuginfo/unwind.rs index 362333d35a411..74b82a7139ab0 100644 --- a/src/debuginfo/unwind.rs +++ b/src/debuginfo/unwind.rs @@ -1,7 +1,6 @@ //! Unwind info generation (`.eh_frame`) use cranelift_codegen::ir::Endianness; -use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::isa::unwind::UnwindInfo; use cranelift_object::ObjectProduct; use gimli::RunTimeEndian; @@ -18,14 +17,14 @@ pub(crate) struct UnwindContext { } impl UnwindContext { - pub(crate) fn new(isa: &dyn TargetIsa, pic_eh_frame: bool) -> Self { - let endian = match isa.endianness() { + pub(crate) fn new(module: &mut dyn Module, pic_eh_frame: bool) -> Self { + let endian = match module.isa().endianness() { Endianness::Little => RunTimeEndian::Little, Endianness::Big => RunTimeEndian::Big, }; let mut frame_table = FrameTable::default(); - let cie_id = if let Some(mut cie) = isa.create_systemv_cie() { + let cie_id = if let Some(mut cie) = module.isa().create_systemv_cie() { if pic_eh_frame { cie.fde_address_encoding = gimli::DwEhPe(gimli::DW_EH_PE_pcrel.0 | gimli::DW_EH_PE_sdata4.0); @@ -38,8 +37,15 @@ impl UnwindContext { UnwindContext { endian, frame_table, cie_id } } - pub(crate) fn add_function(&mut self, func_id: FuncId, context: &Context, isa: &dyn TargetIsa) { - if let target_lexicon::OperatingSystem::MacOSX { .. } = isa.triple().operating_system { + pub(crate) fn add_function( + &mut self, + module: &mut dyn Module, + func_id: FuncId, + context: &Context, + ) { + if let target_lexicon::OperatingSystem::MacOSX { .. } = + module.isa().triple().operating_system + { // The object crate doesn't currently support DW_GNU_EH_PE_absptr, which macOS // requires for unwinding tables. In addition on arm64 it currently doesn't // support 32bit relocations as we currently use for the unwinding table. @@ -48,7 +54,7 @@ impl UnwindContext { } let unwind_info = if let Some(unwind_info) = - context.compiled_code().unwrap().create_unwind_info(isa).unwrap() + context.compiled_code().unwrap().create_unwind_info(module.isa()).unwrap() { unwind_info } else { diff --git a/src/unwind_module.rs b/src/unwind_module.rs index b950aaa29ce04..f963dc79fbb5c 100644 --- a/src/unwind_module.rs +++ b/src/unwind_module.rs @@ -17,8 +17,8 @@ pub(crate) struct UnwindModule { } impl UnwindModule { - pub(crate) fn new(module: T, pic_eh_frame: bool) -> Self { - let unwind_context = UnwindContext::new(module.isa(), pic_eh_frame); + pub(crate) fn new(mut module: T, pic_eh_frame: bool) -> Self { + let unwind_context = UnwindContext::new(&mut module, pic_eh_frame); UnwindModule { module, unwind_context } } } @@ -37,7 +37,7 @@ impl UnwindModule { self.module.finalize_definitions().unwrap(); let prev_unwind_context = std::mem::replace( &mut self.unwind_context, - UnwindContext::new(self.module.isa(), false), + UnwindContext::new(&mut self.module, false), ); unsafe { prev_unwind_context.register_jit(&self.module) }; } @@ -94,7 +94,7 @@ impl Module for UnwindModule { ctrl_plane: &mut ControlPlane, ) -> ModuleResult<()> { self.module.define_function_with_control_plane(func, ctx, ctrl_plane)?; - self.unwind_context.add_function(func, ctx, self.module.isa()); + self.unwind_context.add_function(&mut self.module, func, ctx); Ok(()) } From 571a3dce9e5c599119d113f95027698a1e921599 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 9 Apr 2025 17:44:37 +0000 Subject: [PATCH 1778/4206] Update the `libm` submodule Includes [1] and [2], which should resolve problems cg_gcc has using scalar math operations as a fallback for vector operations. [1]: https://github.com/rust-lang/libm/pull/459 [2]: https://github.com/rust-lang/libm/pull/534 --- library/compiler-builtins/compiler-builtins/libm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-builtins/libm b/library/compiler-builtins/compiler-builtins/libm index 69219c491ee9f..96d1400326f47 160000 --- a/library/compiler-builtins/compiler-builtins/libm +++ b/library/compiler-builtins/compiler-builtins/libm @@ -1 +1 @@ -Subproject commit 69219c491ee9f05761d2068fd6d4c7c0de6faa3a +Subproject commit 96d1400326f47381858f8149451a2b2fd8de2ea4 From 73a04443bdd2e5d9945f03438a0424996059837d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 9 Apr 2025 17:52:23 +0000 Subject: [PATCH 1779/4206] chore: release v0.1.153 --- library/compiler-builtins/compiler-builtins/CHANGELOG.md | 9 +++++++++ library/compiler-builtins/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/compiler-builtins/CHANGELOG.md index 987f87713072a..517ba7859a97a 100644 --- a/library/compiler-builtins/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/compiler-builtins/CHANGELOG.md @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.153](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.152...compiler_builtins-v0.1.153) - 2025-04-09 + +### Other + +- Remove a mention of `force-soft-float` in `build.rs` +- Revert "Disable `f16` on AArch64 without the `neon` feature" +- Skip No More! +- avoid out-of-bounds accesses ([#799](https://github.com/rust-lang/compiler-builtins/pull/799)) + ## [0.1.152](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.151...compiler_builtins-v0.1.152) - 2025-03-20 ### Other diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index 8de8bce6a120f..c0c40b5e17a07 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.152" +version = "0.1.153" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "../README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 547a31016d9725df7466f6064fdcf0e4fb031957 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 8 Apr 2025 12:23:07 +1000 Subject: [PATCH 1780/4206] Rename some `name` variables as `ident`. It bugs me when variables of type `Ident` are called `name`. It leads to silly things like `name.name`. `Ident` variables should be called `ident`, and `name` should be used for variables of type `Symbol`. This commit improves things by by doing `s/name/ident/` on a bunch of `Ident` variables. Not all of them, but a decent chunk. --- src/main_shim.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main_shim.rs b/src/main_shim.rs index 6d5df2b00437b..3b48adb7e918a 100644 --- a/src/main_shim.rs +++ b/src/main_shim.rs @@ -104,7 +104,7 @@ pub(crate) fn maybe_create_entry_wrapper( let termination_trait = tcx.require_lang_item(LangItem::Termination, None); let report = tcx .associated_items(termination_trait) - .find_by_name_and_kind( + .find_by_ident_and_kind( tcx, Ident::from_str("report"), AssocKind::Fn, From 180bc6c8f179cb192c98a08693802191452ee822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 27 Mar 2025 00:19:52 +0100 Subject: [PATCH 1781/4206] Remove the use of Rayon iterators --- src/driver/aot.rs | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/driver/aot.rs b/src/driver/aot.rs index 444dc4412868f..b1bc7e1707eb2 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -728,26 +728,27 @@ pub(crate) fn run_aot( let concurrency_limiter = IntoDynSyncSend(ConcurrencyLimiter::new(todo_cgus.len())); - let modules = tcx.sess.time("codegen mono items", || { - let mut modules: Vec<_> = par_map(todo_cgus, |(_, cgu)| { - let dep_node = cgu.codegen_dep_node(tcx); - tcx.dep_graph - .with_task( + let modules: Vec<_> = + tcx.sess.time("codegen mono items", || { + let modules: Vec<_> = par_map(todo_cgus, |(_, cgu)| { + let dep_node = cgu.codegen_dep_node(tcx); + let (module, _) = tcx.dep_graph.with_task( dep_node, tcx, (global_asm_config.clone(), cgu.name(), concurrency_limiter.acquire(tcx.dcx())), module_codegen, Some(rustc_middle::dep_graph::hash_result), - ) - .0 - }); - modules.extend( - done_cgus + ); + IntoDynSyncSend(module) + }); + modules .into_iter() - .map(|(_, cgu)| OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu))), - ); - modules - }); + .map(|module| module.0) + .chain(done_cgus.into_iter().map(|(_, cgu)| { + OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu)) + })) + .collect() + }); let allocator_module = emit_allocator_module(tcx); From 6fb7d53962623013ce9b4bae7318905a0e4e76ae Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Fri, 11 Apr 2025 14:22:09 +0200 Subject: [PATCH 1782/4206] Check if dropping an expression may have indirect side-effects It is not enough to check if an expression type implements `Drop` to determine whether it can have a significant side-effect. Also, add tests for unchecked cases which were explicitly handled in the code, such as checking for side effect in a `struct`'s fields, or in its base expression. --- clippy_lints/src/no_effect.rs | 14 +++++--- tests/ui/no_effect.rs | 53 ++++++++++++++++++++++++++++ tests/ui/single_range_in_vec_init.rs | 2 +- 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 7ab7976d5697a..02c48166131ef 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -221,10 +221,16 @@ fn is_operator_overridden(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } } +/// Checks if dropping `expr` might have a visible side effect. +fn expr_ty_has_significant_drop(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + let ty = cx.typeck_results().expr_ty(expr); + ty.has_significant_drop(cx.tcx, cx.typing_env()) +} + fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { match expr.kind { ExprKind::Lit(..) | ExprKind::Closure { .. } => true, - ExprKind::Path(..) => !has_drop(cx, cx.typeck_results().expr_ty(expr)), + ExprKind::Path(..) => !expr_ty_has_significant_drop(cx, expr), ExprKind::Index(a, b, _) | ExprKind::Binary(_, a, b) => has_no_effect(cx, a) && has_no_effect(cx, b), ExprKind::Array(v) | ExprKind::Tup(v) => v.iter().all(|val| has_no_effect(cx, val)), ExprKind::Repeat(inner, _) @@ -233,8 +239,8 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { | ExprKind::Unary(_, inner) | ExprKind::Field(inner, _) | ExprKind::AddrOf(_, _, inner) => has_no_effect(cx, inner), - ExprKind::Struct(_, fields, ref base) => { - !has_drop(cx, cx.typeck_results().expr_ty(expr)) + ExprKind::Struct(_, fields, base) => { + !expr_ty_has_significant_drop(cx, expr) && fields.iter().all(|field| has_no_effect(cx, field.expr)) && match &base { StructTailExpr::None | StructTailExpr::DefaultFields(_) => true, @@ -252,7 +258,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..) ); if def_matched || is_range_literal(expr) { - !has_drop(cx, cx.typeck_results().expr_ty(expr)) && args.iter().all(|arg| has_no_effect(cx, arg)) + !expr_ty_has_significant_drop(cx, expr) && args.iter().all(|arg| has_no_effect(cx, arg)) } else { false } diff --git a/tests/ui/no_effect.rs b/tests/ui/no_effect.rs index 703c2a3d98479..4ab5bc9acdeeb 100644 --- a/tests/ui/no_effect.rs +++ b/tests/ui/no_effect.rs @@ -221,3 +221,56 @@ fn main() { Cout << 142; -Cout; } + +fn issue14592() { + struct MyStruct { + _inner: MyInner, + } + struct MyInner {} + + impl Drop for MyInner { + fn drop(&mut self) { + println!("dropping"); + } + } + + let x = MyStruct { _inner: MyInner {} }; + + let closure = || { + // Do not lint: dropping the assignment or assigning to `_` would + // change the output. + let _x = x; + }; + + println!("1"); + closure(); + println!("2"); + + struct Innocuous { + a: i32, + } + + // Do not lint: one of the fields has a side effect. + let x = MyInner {}; + let closure = || { + let _x = Innocuous { + a: { + x; + 10 + }, + }; + }; + + // Do not lint: the base has a side effect. + let x = MyInner {}; + let closure = || { + let _x = Innocuous { + ..Innocuous { + a: { + x; + 10 + }, + } + }; + }; +} diff --git a/tests/ui/single_range_in_vec_init.rs b/tests/ui/single_range_in_vec_init.rs index c6c0cb347dc68..25884450b0842 100644 --- a/tests/ui/single_range_in_vec_init.rs +++ b/tests/ui/single_range_in_vec_init.rs @@ -1,6 +1,6 @@ //@aux-build:proc_macros.rs //@no-rustfix: overlapping suggestions -#![allow(clippy::no_effect, clippy::useless_vec, unused)] +#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::useless_vec, unused)] #![warn(clippy::single_range_in_vec_init)] #![feature(generic_arg_infer)] From 25f17dd8254588300f7bc431d586f3b7c4ee2df1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 29 Jan 2025 22:22:56 +0100 Subject: [PATCH 1783/4206] Optimize `ToString` implementation for integers --- library/alloc/src/string.rs | 48 +++++++++++++++++++++++++++++++++++++ library/core/src/fmt/num.rs | 28 +++++++++++++++------- 2 files changed, 67 insertions(+), 9 deletions(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 9a161d057db09..1a0b3b43eb698 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2824,7 +2824,54 @@ impl SpecToString for bool { } } +macro_rules! impl_to_string { + ($($signed:ident, $unsigned:ident,)*) => { + $( + #[cfg(not(no_global_oom_handling))] + #[cfg(not(feature = "optimize_for_size"))] + impl SpecToString for $signed { + #[inline] + fn spec_to_string(&self) -> String { + const SIZE: usize = $signed::MAX.ilog(10) as usize + 1; + let mut buf = [core::mem::MaybeUninit::::uninit(); SIZE]; + // Only difference between signed and unsigned are these 8 lines. + let mut out; + if *self < 0 { + out = String::with_capacity(SIZE + 1); + out.push('-'); + } else { + out = String::with_capacity(SIZE); + } + + out.push_str(self.unsigned_abs()._fmt(&mut buf)); + out + } + } + #[cfg(not(no_global_oom_handling))] + #[cfg(not(feature = "optimize_for_size"))] + impl SpecToString for $unsigned { + #[inline] + fn spec_to_string(&self) -> String { + const SIZE: usize = $unsigned::MAX.ilog(10) as usize + 1; + let mut buf = [core::mem::MaybeUninit::::uninit(); SIZE]; + + self._fmt(&mut buf).to_string() + } + } + )* + } +} + +impl_to_string! { + i8, u8, + i16, u16, + i32, u32, + i64, u64, + isize, usize, +} + #[cfg(not(no_global_oom_handling))] +#[cfg(feature = "optimize_for_size")] impl SpecToString for u8 { #[inline] fn spec_to_string(&self) -> String { @@ -2844,6 +2891,7 @@ impl SpecToString for u8 { } #[cfg(not(no_global_oom_handling))] +#[cfg(feature = "optimize_for_size")] impl SpecToString for i8 { #[inline] fn spec_to_string(&self) -> String { diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index 4467b37bd4510..ba30518d70bc2 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -208,7 +208,11 @@ macro_rules! impl_Display { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { #[cfg(not(feature = "optimize_for_size"))] { - self._fmt(true, f) + const MAX_DEC_N: usize = $unsigned::MAX.ilog(10) as usize + 1; + // Buffer decimals for $unsigned with right alignment. + let mut buf = [MaybeUninit::::uninit(); MAX_DEC_N]; + + f.pad_integral(true, "", self._fmt(&mut buf)) } #[cfg(feature = "optimize_for_size")] { @@ -222,7 +226,11 @@ macro_rules! impl_Display { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { #[cfg(not(feature = "optimize_for_size"))] { - return self.unsigned_abs()._fmt(*self >= 0, f); + const MAX_DEC_N: usize = $unsigned::MAX.ilog(10) as usize + 1; + // Buffer decimals for $unsigned with right alignment. + let mut buf = [MaybeUninit::::uninit(); MAX_DEC_N]; + + f.pad_integral(*self >= 0, "", self.unsigned_abs()._fmt(&mut buf)) } #[cfg(feature = "optimize_for_size")] { @@ -233,10 +241,13 @@ macro_rules! impl_Display { #[cfg(not(feature = "optimize_for_size"))] impl $unsigned { - fn _fmt(self, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { - const MAX_DEC_N: usize = $unsigned::MAX.ilog(10) as usize + 1; - // Buffer decimals for $unsigned with right alignment. - let mut buf = [MaybeUninit::::uninit(); MAX_DEC_N]; + #[doc(hidden)] + #[unstable( + feature = "fmt_internals", + reason = "specialized method meant to only be used by `SpecToString` implementation", + issue = "none" + )] + pub fn _fmt<'a>(self, buf: &'a mut [MaybeUninit::]) -> &'a str { // Count the number of bytes in buf that are not initialized. let mut offset = buf.len(); // Consume the least-significant decimals from a working copy. @@ -301,13 +312,12 @@ macro_rules! impl_Display { // SAFETY: All buf content since offset is set. let written = unsafe { buf.get_unchecked(offset..) }; // SAFETY: Writes use ASCII from the lookup table exclusively. - let as_str = unsafe { + unsafe { str::from_utf8_unchecked(slice::from_raw_parts( MaybeUninit::slice_as_ptr(written), written.len(), )) - }; - f.pad_integral(is_nonnegative, "", as_str) + } } })* From 1ef7585c9ef976211b897e22fad6ae9aa2c2f415 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 30 Jan 2025 11:05:34 +0100 Subject: [PATCH 1784/4206] Update weirdly failing ui tests --- tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.rs | 2 +- tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs | 2 +- .../equal-pointers-unequal/exposed-provenance/inline2.rs | 2 +- .../codegen/equal-pointers-unequal/exposed-provenance/zero.rs | 2 +- .../codegen/equal-pointers-unequal/strict-provenance/inline2.rs | 2 +- .../ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.rs index 9a1ace86e4db8..5ec3c7cbdf55b 100644 --- a/tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.rs +++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.rs @@ -23,7 +23,7 @@ fn main() { let v = 0; &v as *const _ as usize }; - assert_eq!(a.to_string(), b.to_string()); + assert_eq!(format!("{a}"), format!("{b}")); assert_eq!(format!("{}", a == b), "true"); assert_eq!(format!("{}", cmp_in(a, b)), "true"); assert_eq!(format!("{}", cmp(a, b)), "true"); diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs index d1aa95a9a569d..731c5b67882bd 100644 --- a/tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs +++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs @@ -21,7 +21,7 @@ fn main() { // It's not zero, which means `a` and `b` are not equal. assert_ne!(i, 0); // But it looks like zero... - assert_eq!(i.to_string(), "0"); + assert_eq!(format!("{i}"), "0"); // ...and now it *is* zero? assert_eq!(i, 0); // So `a` and `b` are equal after all? diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.rs index f128e1bb0841a..94739708ab8bd 100644 --- a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.rs +++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.rs @@ -25,7 +25,7 @@ fn main() { let v = 0; ptr::from_ref(&v).expose_provenance() }; - assert_eq!(a.to_string(), b.to_string()); + assert_eq!(format!("{a}"), format!("{b}")); assert_eq!(format!("{}", a == b), "true"); assert_eq!(format!("{}", cmp_in(a, b)), "true"); assert_eq!(format!("{}", cmp(a, b)), "true"); diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs index 7ccff8d0848e9..b7824f53d77f8 100644 --- a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs +++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs @@ -23,7 +23,7 @@ fn main() { // It's not zero, which means `a` and `b` are not equal. assert_ne!(i, 0); // But it looks like zero... - assert_eq!(i.to_string(), "0"); + assert_eq!(format!("{i}"), "0"); // ...and now it *is* zero? assert_eq!(i, 0); // So `a` and `b` are equal after all? diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs index 0414879804a5a..0f838af1fb190 100644 --- a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs +++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs @@ -25,7 +25,7 @@ fn main() { let v = 0; ptr::from_ref(&v).addr() }; - assert_eq!(a.to_string(), b.to_string()); + assert_eq!(format!("{a}"), format!("{b}")); assert_eq!(format!("{}", a == b), "true"); assert_eq!(format!("{}", cmp_in(a, b)), "true"); assert_eq!(format!("{}", cmp(a, b)), "true"); diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs index d963e45e4cdf2..20ed991ed3d66 100644 --- a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs +++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs @@ -23,7 +23,7 @@ fn main() { // It's not zero, which means `a` and `b` are not equal. assert_ne!(i, 0); // But it looks like zero... - assert_eq!(i.to_string(), "0"); + assert_eq!(format!("{i}"), "0"); // ...and now it *is* zero? assert_eq!(i, 0); // So `a` and `b` are equal after all? From 14662fabeb69fe5ab6c6e68051bf9f80d4aaaa35 Mon Sep 17 00:00:00 2001 From: Ruan Comelli Date: Sun, 13 Apr 2025 09:15:16 -0300 Subject: [PATCH 1785/4206] docs(library/core/src/pin): fix typo "necessarily" -> "necessary" --- library/core/src/pin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 2ef1bbfd1fa70..504801f3e4e5f 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -12,7 +12,7 @@ //! "pinned," in that it has been permanently (until the end of its lifespan) attached to its //! location in memory, as though pinned to a pinboard. Pinning a value is an incredibly useful //! building block for [`unsafe`] code to be able to reason about whether a raw pointer to the -//! pinned value is still valid. [As we'll see later][drop-guarantee], this is necessarily from the +//! pinned value is still valid. [As we'll see later][drop-guarantee], this is necessary from the //! time the value is first pinned until the end of its lifespan. This concept of "pinning" is //! necessary to implement safe interfaces on top of things like self-referential types and //! intrusive data structures which cannot currently be modeled in fully safe Rust using only From 6f23f167af57af26543fa93f87a12f637e66c5e8 Mon Sep 17 00:00:00 2001 From: Ruan Comelli Date: Sun, 13 Apr 2025 16:11:55 -0300 Subject: [PATCH 1786/4206] docs(library/core/src/pin): rewrite for clarity --- library/core/src/pin.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 504801f3e4e5f..9ee5369139ff9 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -12,11 +12,11 @@ //! "pinned," in that it has been permanently (until the end of its lifespan) attached to its //! location in memory, as though pinned to a pinboard. Pinning a value is an incredibly useful //! building block for [`unsafe`] code to be able to reason about whether a raw pointer to the -//! pinned value is still valid. [As we'll see later][drop-guarantee], this is necessary from the -//! time the value is first pinned until the end of its lifespan. This concept of "pinning" is -//! necessary to implement safe interfaces on top of things like self-referential types and -//! intrusive data structures which cannot currently be modeled in fully safe Rust using only -//! borrow-checked [references][reference]. +//! pinned value is still valid. [As we'll see later][drop-guarantee], once a value is pinned, +//! it is necessarily valid at its memory location until the end of its lifespan. This concept +//! of "pinning" is necessary to implement safe interfaces on top of things like self-referential +//! types and intrusive data structures which cannot currently be modeled in fully safe Rust using +//! only borrow-checked [references][reference]. //! //! "Pinning" allows us to put a *value* which exists at some location in memory into a state where //! safe code cannot *move* that value to a different location in memory or otherwise invalidate it From bc9dacdf9a0f123377f6f97ab23f13f5777e4041 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 11 Apr 2025 06:28:59 +1000 Subject: [PATCH 1787/4206] Move `has_self` field to `hir::AssocKind::Fn`. `hir::AssocItem` currently has a boolean `fn_has_self_parameter` field, which is misplaced, because it's only relevant for associated fns, not for associated consts or types. This commit moves it (and renames it) to the `AssocKind::Fn` variant, where it belongs. This requires introducing a new C-style enum, `AssocTag`, which is like `AssocKind` but without the fields. This is because `AssocKind` values are passed to various functions like `find_by_ident_and_kind` to indicate what kind of associated item should be searched for, and having to specify `has_self` isn't relevant there. New methods: - Predicates `AssocItem::is_fn` and `AssocItem::is_method`. - `AssocItem::as_tag` which converts `AssocItem::kind` to `AssocTag`. Removed `find_by_name_and_kinds`, which is unused. `AssocItem::descr` can now distinguish between methods and associated functions, which slightly improves some error messages. --- src/main_shim.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main_shim.rs b/src/main_shim.rs index 3b48adb7e918a..6eef97c14dd28 100644 --- a/src/main_shim.rs +++ b/src/main_shim.rs @@ -1,6 +1,6 @@ use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use rustc_hir::LangItem; -use rustc_middle::ty::{AssocKind, GenericArg}; +use rustc_middle::ty::{AssocTag, GenericArg}; use rustc_session::config::EntryFnType; use rustc_span::{DUMMY_SP, Ident}; @@ -107,7 +107,7 @@ pub(crate) fn maybe_create_entry_wrapper( .find_by_ident_and_kind( tcx, Ident::from_str("report"), - AssocKind::Fn, + AssocTag::Fn, termination_trait, ) .unwrap(); From f99bdfef831f86e3d32c9aade7e41020b067d393 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 14 Apr 2025 08:47:01 +0000 Subject: [PATCH 1788/4206] Rustup to rustc 1.88.0-nightly (092a284ba 2025-04-13) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 4be668c7b8488..1789b62917de9 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-04-08" +channel = "nightly-2025-04-14" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 1afce7c3548ff31174cb060f3217b1994d982bed Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 14 Apr 2025 09:13:37 +0000 Subject: [PATCH 1789/4206] Implement simd_insert_dyn and simd_extract_dyn intrinsics --- src/intrinsics/simd.rs | 28 ++++++++++++++++++++++++++++ src/value_and_place.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/src/intrinsics/simd.rs b/src/intrinsics/simd.rs index dd6d8dbb6f5e0..7a041469bccdd 100644 --- a/src/intrinsics/simd.rs +++ b/src/intrinsics/simd.rs @@ -283,6 +283,20 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( ret_lane.write_cvalue(fx, val); } + sym::simd_insert_dyn => { + intrinsic_args!(fx, args => (base, idx, val); intrinsic); + + if !base.layout().ty.is_simd() { + report_simd_type_validation_error(fx, intrinsic, span, base.layout().ty); + return; + } + + let idx = idx.load_scalar(fx); + + ret.write_cvalue(fx, base); + ret.write_lane_dyn(fx, idx, val); + } + sym::simd_extract => { let (v, idx) = match args { [v, idx] => (v, idx), @@ -318,6 +332,20 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( ret.write_cvalue(fx, ret_lane); } + sym::simd_extract_dyn => { + intrinsic_args!(fx, args => (v, idx); intrinsic); + + if !v.layout().ty.is_simd() { + report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty); + return; + } + + let idx = idx.load_scalar(fx); + + let ret_lane = v.value_lane_dyn(fx, idx); + ret.write_cvalue(fx, ret_lane); + } + sym::simd_neg | sym::simd_bswap | sym::simd_bitreverse diff --git a/src/value_and_place.rs b/src/value_and_place.rs index f8a19589fdd72..9fd71cd6f77f9 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -806,6 +806,34 @@ impl<'tcx> CPlace<'tcx> { } } + /// Write a value to an individual lane in a SIMD vector. + pub(crate) fn write_lane_dyn( + self, + fx: &mut FunctionCx<'_, '_, 'tcx>, + lane_idx: Value, + value: CValue<'tcx>, + ) { + let layout = self.layout(); + assert!(layout.ty.is_simd()); + let (_lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); + let lane_layout = fx.layout_of(lane_ty); + assert_eq!(lane_layout, value.layout()); + + match self.inner { + CPlaceInner::Var(_, _) => unreachable!(), + CPlaceInner::VarPair(_, _, _) => unreachable!(), + CPlaceInner::Addr(ptr, None) => { + let field_offset = fx + .bcx + .ins() + .imul_imm(lane_idx, i64::try_from(lane_layout.size.bytes()).unwrap()); + let field_ptr = ptr.offset_value(fx, field_offset); + CPlace::for_ptr(field_ptr, lane_layout).write_cvalue(fx, value); + } + CPlaceInner::Addr(_, Some(_)) => unreachable!(), + } + } + pub(crate) fn place_index( self, fx: &mut FunctionCx<'_, '_, 'tcx>, From 8582bc4e37a60957f78f39a64b6e0eeda8007dae Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 12 Dec 2024 19:52:38 +0000 Subject: [PATCH 1790/4206] Pass MonoItemData to MonoItem::define --- src/base.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/base.rs b/src/base.rs index 9b495174a3fab..292f0514070b4 100644 --- a/src/base.rs +++ b/src/base.rs @@ -223,8 +223,8 @@ pub fn compile_codegen_unit( } // ... and now that we have everything pre-defined, fill out those definitions. - for &(mono_item, _) in &mono_items { - mono_item.define::>(&cx); + for &(mono_item, item_data) in &mono_items { + mono_item.define::>(&cx, item_data); } // If this codegen unit contains the main function, also create the From c02e496ecc4e60b3c39bb361de5fac57fef83846 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 12 Dec 2024 20:31:20 +0000 Subject: [PATCH 1791/4206] Use cg_ssa's version of codegen_naked_asm in cg_clif --- src/base.rs | 39 +------ src/driver/aot.rs | 37 +++++-- src/driver/jit.rs | 12 ++- src/global_asm.rs | 260 ++++++++++++++++++++++++++++++++-------------- src/inline_asm.rs | 193 +++++++--------------------------- 5 files changed, 258 insertions(+), 283 deletions(-) diff --git a/src/base.rs b/src/base.rs index adaa754491e56..4acbd4b955980 100644 --- a/src/base.rs +++ b/src/base.rs @@ -8,8 +8,6 @@ use rustc_ast::InlineAsmOptions; use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_index::IndexVec; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::mir::InlineAsmMacro; use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv}; @@ -18,7 +16,6 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use crate::constant::ConstantCx; use crate::debuginfo::{FunctionDebugContext, TypeDebugContext}; use crate::enable_verifier; -use crate::inline_asm::codegen_naked_asm; use crate::prelude::*; use crate::pretty_clif::CommentWriter; @@ -37,7 +34,7 @@ pub(crate) fn codegen_fn<'tcx>( cached_func: Function, module: &mut dyn Module, instance: Instance<'tcx>, -) -> Option { +) -> CodegenedFunction { debug_assert!(!instance.args.has_infer()); let symbol_name = tcx.symbol_name(instance).name.to_string(); @@ -54,38 +51,6 @@ pub(crate) fn codegen_fn<'tcx>( String::from_utf8_lossy(&buf).into_owned() }); - if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) { - assert_eq!(mir.basic_blocks.len(), 1); - assert!(mir.basic_blocks[START_BLOCK].statements.is_empty()); - - match &mir.basic_blocks[START_BLOCK].terminator().kind { - TerminatorKind::InlineAsm { - asm_macro: InlineAsmMacro::NakedAsm, - template, - operands, - options, - line_spans: _, - targets: _, - unwind: _, - } => { - codegen_naked_asm( - tcx, - cx, - module, - instance, - mir.basic_blocks[START_BLOCK].terminator().source_info.span, - &symbol_name, - template, - operands, - *options, - ); - } - _ => unreachable!(), - } - - return None; - } - // Declare function let sig = get_function_sig(tcx, module.target_config().default_call_conv, instance); let func_id = module.declare_function(&symbol_name, Linkage::Local, &sig).unwrap(); @@ -166,7 +131,7 @@ pub(crate) fn codegen_fn<'tcx>( // Verify function verify_func(tcx, &clif_comments, &func); - Some(CodegenedFunction { symbol_name, func_id, func, clif_comments, func_debug_cx }) + CodegenedFunction { symbol_name, func_id, func, clif_comments, func_debug_cx } } pub(crate) fn compile_fn( diff --git a/src/driver/aot.rs b/src/driver/aot.rs index 00136ac4a5748..1cb8f8bc43993 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -22,7 +22,10 @@ use rustc_data_structures::sync::{IntoDynSyncSend, par_map}; use rustc_metadata::EncodedMetadata; use rustc_metadata::fs::copy_to_stdout; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::mir::mono::{CodegenUnit, MonoItem}; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::mir::mono::{ + CodegenUnit, Linkage as RLinkage, MonoItem, MonoItemData, Visibility, +}; use rustc_session::Session; use rustc_session::config::{DebugInfo, OutFileName, OutputFilenames, OutputType}; @@ -30,7 +33,7 @@ use crate::CodegenCx; use crate::base::CodegenedFunction; use crate::concurrency_limiter::{ConcurrencyLimiter, ConcurrencyLimiterToken}; use crate::debuginfo::TypeDebugContext; -use crate::global_asm::GlobalAsmConfig; +use crate::global_asm::{GlobalAsmConfig, GlobalAsmContext}; use crate::prelude::*; use crate::unwind_module::UnwindModule; @@ -530,19 +533,35 @@ fn codegen_cgu_content( let mut type_dbg = TypeDebugContext::default(); super::predefine_mono_items(tcx, module, &mono_items); let mut codegened_functions = vec![]; - for (mono_item, _) in mono_items { + for (mono_item, item_data) in mono_items { match mono_item { - MonoItem::Fn(inst) => { - if let Some(codegened_function) = crate::base::codegen_fn( + MonoItem::Fn(instance) => { + if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) + { + rustc_codegen_ssa::mir::naked_asm::codegen_naked_asm( + &mut GlobalAsmContext { tcx, global_asm: &mut cx.global_asm }, + instance, + MonoItemData { + linkage: RLinkage::External, + visibility: if item_data.linkage == RLinkage::Internal { + Visibility::Hidden + } else { + item_data.visibility + }, + ..item_data + }, + ); + continue; + } + let codegened_function = crate::base::codegen_fn( tcx, &mut cx, &mut type_dbg, Function::new(), module, - inst, - ) { - codegened_functions.push(codegened_function); - } + instance, + ); + codegened_functions.push(codegened_function); } MonoItem::Static(def_id) => { let data_id = crate::constant::codegen_static(tcx, module, def_id); diff --git a/src/driver/jit.rs b/src/driver/jit.rs index 41f8bb9161ca2..e368cf4386d01 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -126,6 +126,11 @@ pub(crate) fn codegen_and_compile_fn<'tcx>( module: &mut dyn Module, instance: Instance<'tcx>, ) { + if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) { + tcx.dcx() + .span_fatal(tcx.def_span(instance.def_id()), "Naked asm is not supported in JIT mode"); + } + cranelift_codegen::timing::set_thread_profiler(Box::new(super::MeasuremeProfiler( tcx.prof.clone(), ))); @@ -135,16 +140,15 @@ pub(crate) fn codegen_and_compile_fn<'tcx>( crate::PrintOnPanic(|| format!("{:?} {}", instance, tcx.symbol_name(instance).name)); let cached_func = std::mem::replace(&mut cached_context.func, Function::new()); - if let Some(codegened_func) = crate::base::codegen_fn( + let codegened_func = crate::base::codegen_fn( tcx, cx, &mut TypeDebugContext::default(), cached_func, module, instance, - ) { - crate::base::compile_fn(cx, &tcx.prof, cached_context, module, codegened_func); - } + ); + crate::base::compile_fn(cx, &tcx.prof, cached_context, module, codegened_func); }); } diff --git a/src/global_asm.rs b/src/global_asm.rs index 79cefb05de322..18944a3be2769 100644 --- a/src/global_asm.rs +++ b/src/global_asm.rs @@ -7,102 +7,206 @@ use std::process::{Command, Stdio}; use std::sync::Arc; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use rustc_codegen_ssa::traits::{AsmCodegenMethods, GlobalAsmOperandRef}; use rustc_hir::{InlineAsmOperand, ItemId}; use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::layout::{ + FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError, LayoutOfHelpers, +}; use rustc_session::config::{OutputFilenames, OutputType}; use rustc_target::asm::InlineAsmArch; use crate::prelude::*; +pub(crate) struct GlobalAsmContext<'a, 'tcx> { + pub tcx: TyCtxt<'tcx>, + pub global_asm: &'a mut String, +} + +impl<'tcx> AsmCodegenMethods<'tcx> for GlobalAsmContext<'_, 'tcx> { + fn codegen_global_asm( + &mut self, + template: &[InlineAsmTemplatePiece], + operands: &[GlobalAsmOperandRef<'tcx>], + options: InlineAsmOptions, + _line_spans: &[Span], + ) { + codegen_global_asm_inner(self.tcx, self.global_asm, template, operands, options); + } + + fn mangled_name(&self, instance: Instance<'tcx>) -> String { + self.tcx.symbol_name(instance).name.to_owned() + } +} + +impl<'tcx> LayoutOfHelpers<'tcx> for GlobalAsmContext<'_, 'tcx> { + #[inline] + fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { + if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err { + self.tcx.sess.dcx().span_fatal(span, err.to_string()) + } else { + self.tcx + .sess + .dcx() + .span_fatal(span, format!("failed to get layout for `{}`: {}", ty, err)) + } + } +} + +impl<'tcx> FnAbiOfHelpers<'tcx> for GlobalAsmContext<'_, 'tcx> { + #[inline] + fn handle_fn_abi_err( + &self, + err: FnAbiError<'tcx>, + span: Span, + fn_abi_request: FnAbiRequest<'tcx>, + ) -> ! { + FullyMonomorphizedLayoutCx(self.tcx).handle_fn_abi_err(err, span, fn_abi_request) + } +} + +impl<'tcx> HasTyCtxt<'tcx> for GlobalAsmContext<'_, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { + self.tcx + } +} + +impl<'tcx> rustc_abi::HasDataLayout for GlobalAsmContext<'_, 'tcx> { + fn data_layout(&self) -> &rustc_abi::TargetDataLayout { + &self.tcx.data_layout + } +} + +impl<'tcx> HasTypingEnv<'tcx> for GlobalAsmContext<'_, 'tcx> { + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + ty::TypingEnv::fully_monomorphized() + } +} + pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, item_id: ItemId) { let item = tcx.hir_item(item_id); - if let rustc_hir::ItemKind::GlobalAsm { asm, .. } = item.kind { - let is_x86 = - matches!(tcx.sess.asm_arch.unwrap(), InlineAsmArch::X86 | InlineAsmArch::X86_64); - - if is_x86 { - if !asm.options.contains(InlineAsmOptions::ATT_SYNTAX) { - global_asm.push_str("\n.intel_syntax noprefix\n"); - } else { - global_asm.push_str("\n.att_syntax\n"); + let rustc_hir::ItemKind::GlobalAsm { asm, .. } = item.kind else { + bug!("Expected GlobalAsm found {:?}", item); + }; + + // Adapted from rustc_codegen_ssa::mono_items::MonoItem::define + let operands: Vec<_> = asm + .operands + .iter() + .map(|(op, op_sp)| match *op { + InlineAsmOperand::Const { ref anon_const } => { + match tcx.const_eval_poly(anon_const.def_id.to_def_id()) { + Ok(const_value) => { + let ty = tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id); + let string = rustc_codegen_ssa::common::asm_const_to_str( + tcx, + *op_sp, + const_value, + FullyMonomorphizedLayoutCx(tcx).layout_of(ty), + ); + GlobalAsmOperandRef::Const { string } + } + Err(ErrorHandled::Reported { .. }) => { + // An error has already been reported and + // compilation is guaranteed to fail if execution + // hits this path. So an empty string instead of + // a stringified constant value will suffice. + GlobalAsmOperandRef::Const { string: String::new() } + } + Err(ErrorHandled::TooGeneric(_)) => { + span_bug!(*op_sp, "asm const cannot be resolved; too generic") + } + } + } + InlineAsmOperand::SymFn { expr } => { + if cfg!(not(feature = "inline_asm_sym")) { + tcx.dcx().span_err( + item.span, + "asm! and global_asm! sym operands are not yet supported", + ); + } + + let ty = tcx.typeck(item_id.owner_id).expr_ty(expr); + let instance = match ty.kind() { + &ty::FnDef(def_id, args) => Instance::new(def_id, args), + _ => span_bug!(*op_sp, "asm sym is not a function"), + }; + GlobalAsmOperandRef::SymFn { instance } } + InlineAsmOperand::SymStatic { path: _, def_id } => { + GlobalAsmOperandRef::SymStatic { def_id } + } + InlineAsmOperand::In { .. } + | InlineAsmOperand::Out { .. } + | InlineAsmOperand::InOut { .. } + | InlineAsmOperand::SplitInOut { .. } + | InlineAsmOperand::Label { .. } => { + span_bug!(*op_sp, "invalid operand type for global_asm!") + } + }) + .collect(); + + codegen_global_asm_inner(tcx, global_asm, asm.template, &operands, asm.options); +} + +fn codegen_global_asm_inner<'tcx>( + tcx: TyCtxt<'tcx>, + global_asm: &mut String, + template: &[InlineAsmTemplatePiece], + operands: &[GlobalAsmOperandRef<'tcx>], + options: InlineAsmOptions, +) { + let is_x86 = matches!(tcx.sess.asm_arch.unwrap(), InlineAsmArch::X86 | InlineAsmArch::X86_64); + + if is_x86 { + if !options.contains(InlineAsmOptions::ATT_SYNTAX) { + global_asm.push_str("\n.intel_syntax noprefix\n"); + } else { + global_asm.push_str("\n.att_syntax\n"); } - for piece in asm.template { - match *piece { - InlineAsmTemplatePiece::String(ref s) => global_asm.push_str(s), - InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span: op_sp } => { - match asm.operands[operand_idx].0 { - InlineAsmOperand::Const { ref anon_const } => { - match tcx.const_eval_poly(anon_const.def_id.to_def_id()) { - Ok(const_value) => { - let ty = tcx - .typeck_body(anon_const.body) - .node_type(anon_const.hir_id); - let string = rustc_codegen_ssa::common::asm_const_to_str( - tcx, - op_sp, - const_value, - FullyMonomorphizedLayoutCx(tcx).layout_of(ty), - ); - global_asm.push_str(&string); - } - Err(ErrorHandled::Reported { .. }) => { - // An error has already been reported and compilation is - // guaranteed to fail if execution hits this path. - } - Err(ErrorHandled::TooGeneric(_)) => { - span_bug!(op_sp, "asm const cannot be resolved; too generic"); - } - } - } - InlineAsmOperand::SymFn { expr } => { - if cfg!(not(feature = "inline_asm_sym")) { - tcx.dcx().span_err( - item.span, - "asm! and global_asm! sym operands are not yet supported", - ); - } - - let ty = tcx.typeck(item_id.owner_id).expr_ty(expr); - let instance = match ty.kind() { - &ty::FnDef(def_id, args) => Instance::new(def_id, args), - _ => span_bug!(op_sp, "asm sym is not a function"), - }; - let symbol = tcx.symbol_name(instance); - // FIXME handle the case where the function was made private to the - // current codegen unit - global_asm.push_str(symbol.name); - } - InlineAsmOperand::SymStatic { path: _, def_id } => { - if cfg!(not(feature = "inline_asm_sym")) { - tcx.dcx().span_err( - item.span, - "asm! and global_asm! sym operands are not yet supported", - ); - } - - let instance = Instance::mono(tcx, def_id); - let symbol = tcx.symbol_name(instance); - global_asm.push_str(symbol.name); + } + for piece in template { + match *piece { + InlineAsmTemplatePiece::String(ref s) => global_asm.push_str(s), + InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span } => { + match operands[operand_idx] { + GlobalAsmOperandRef::Const { ref string } => { + global_asm.push_str(string); + } + GlobalAsmOperandRef::SymFn { instance } => { + if cfg!(not(feature = "inline_asm_sym")) { + tcx.dcx().span_err( + span, + "asm! and global_asm! sym operands are not yet supported", + ); } - InlineAsmOperand::In { .. } - | InlineAsmOperand::Out { .. } - | InlineAsmOperand::InOut { .. } - | InlineAsmOperand::SplitInOut { .. } - | InlineAsmOperand::Label { .. } => { - span_bug!(op_sp, "invalid operand type for global_asm!") + + let symbol = tcx.symbol_name(instance); + // FIXME handle the case where the function was made private to the + // current codegen unit + global_asm.push_str(symbol.name); + } + GlobalAsmOperandRef::SymStatic { def_id } => { + if cfg!(not(feature = "inline_asm_sym")) { + tcx.dcx().span_err( + span, + "asm! and global_asm! sym operands are not yet supported", + ); } + + let instance = Instance::mono(tcx, def_id); + let symbol = tcx.symbol_name(instance); + global_asm.push_str(symbol.name); } } } } + } - global_asm.push('\n'); - if is_x86 { - global_asm.push_str(".att_syntax\n\n"); - } - } else { - bug!("Expected GlobalAsm found {:?}", item); + global_asm.push('\n'); + if is_x86 { + global_asm.push_str(".att_syntax\n\n"); } } diff --git a/src/inline_asm.rs b/src/inline_asm.rs index fbc33a642853c..afee50955497c 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -161,7 +161,6 @@ pub(crate) fn codegen_inline_asm_inner<'tcx>( stack_slots_input: Vec::new(), stack_slots_output: Vec::new(), stack_slot_size: Size::from_bytes(0), - is_naked: false, }; asm_gen.allocate_registers(); asm_gen.allocate_stack_slots(); @@ -201,114 +200,6 @@ pub(crate) fn codegen_inline_asm_inner<'tcx>( call_inline_asm(fx, &asm_name, asm_gen.stack_slot_size, inputs, outputs); } -pub(crate) fn codegen_naked_asm<'tcx>( - tcx: TyCtxt<'tcx>, - cx: &mut crate::CodegenCx, - module: &mut dyn Module, - instance: Instance<'tcx>, - span: Span, - symbol_name: &str, - template: &[InlineAsmTemplatePiece], - operands: &[InlineAsmOperand<'tcx>], - options: InlineAsmOptions, -) { - // FIXME add .eh_frame unwind info directives - - let operands = operands - .iter() - .map(|operand| match *operand { - InlineAsmOperand::In { .. } - | InlineAsmOperand::Out { .. } - | InlineAsmOperand::InOut { .. } => { - span_bug!(span, "invalid operand type for naked asm") - } - InlineAsmOperand::Const { ref value } => { - let cv = instance.instantiate_mir_and_normalize_erasing_regions( - tcx, - ty::TypingEnv::fully_monomorphized(), - ty::EarlyBinder::bind(value.const_), - ); - let const_value = cv - .eval(tcx, ty::TypingEnv::fully_monomorphized(), value.span) - .expect("erroneous constant missed by mono item collection"); - - let value = rustc_codegen_ssa::common::asm_const_to_str( - tcx, - span, - const_value, - FullyMonomorphizedLayoutCx(tcx).layout_of(cv.ty()), - ); - CInlineAsmOperand::Const { value } - } - InlineAsmOperand::SymFn { ref value } => { - if cfg!(not(feature = "inline_asm_sym")) { - tcx.dcx() - .span_err(span, "asm! and global_asm! sym operands are not yet supported"); - } - - let const_ = instance.instantiate_mir_and_normalize_erasing_regions( - tcx, - ty::TypingEnv::fully_monomorphized(), - ty::EarlyBinder::bind(value.const_), - ); - if let ty::FnDef(def_id, args) = *const_.ty().kind() { - let instance = ty::Instance::resolve_for_fn_ptr( - tcx, - ty::TypingEnv::fully_monomorphized(), - def_id, - args, - ) - .unwrap(); - let symbol = tcx.symbol_name(instance); - - // Pass a wrapper rather than the function itself as the function itself may not - // be exported from the main codegen unit and may thus be unreachable from the - // object file created by an external assembler. - let wrapper_name = format!( - "__inline_asm_{}_wrapper_n{}", - cx.cgu_name.as_str().replace('.', "__").replace('-', "_"), - cx.inline_asm_index - ); - cx.inline_asm_index += 1; - let sig = - get_function_sig(tcx, module.target_config().default_call_conv, instance); - create_wrapper_function(module, sig, &wrapper_name, symbol.name); - - CInlineAsmOperand::Symbol { symbol: wrapper_name } - } else { - span_bug!(span, "invalid type for asm sym (fn)"); - } - } - InlineAsmOperand::SymStatic { def_id } => { - assert!(tcx.is_static(def_id)); - let instance = Instance::mono(tcx, def_id); - CInlineAsmOperand::Symbol { symbol: tcx.symbol_name(instance).name.to_owned() } - } - InlineAsmOperand::Label { .. } => { - span_bug!(span, "asm! label operands are not yet supported"); - } - }) - .collect::>(); - - let asm_gen = InlineAssemblyGenerator { - tcx, - arch: tcx.sess.asm_arch.unwrap(), - enclosing_def_id: instance.def_id(), - template, - operands: &operands, - options, - registers: Vec::new(), - stack_slots_clobber: Vec::new(), - stack_slots_input: Vec::new(), - stack_slots_output: Vec::new(), - stack_slot_size: Size::from_bytes(0), - is_naked: true, - }; - - let generated_asm = asm_gen.generate_asm_wrapper(symbol_name); - cx.global_asm.push_str(&generated_asm); -} - struct InlineAssemblyGenerator<'a, 'tcx> { tcx: TyCtxt<'tcx>, arch: InlineAsmArch, @@ -321,13 +212,10 @@ struct InlineAssemblyGenerator<'a, 'tcx> { stack_slots_input: Vec>, stack_slots_output: Vec>, stack_slot_size: Size, - is_naked: bool, } impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { fn allocate_registers(&mut self) { - assert!(!self.is_naked); - let sess = self.tcx.sess; let map = allocatable_registers( self.arch, @@ -451,8 +339,6 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { } fn allocate_stack_slots(&mut self) { - assert!(!self.is_naked); - let mut slot_size = Size::from_bytes(0); let mut slots_clobber = vec![None; self.operands.len()]; let mut slots_input = vec![None; self.operands.len()]; @@ -582,32 +468,31 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { if is_x86 { generated_asm.push_str(".intel_syntax noprefix\n"); } - if !self.is_naked { - Self::prologue(&mut generated_asm, self.arch); - - // Save clobbered registers - if !self.options.contains(InlineAsmOptions::NORETURN) { - for (reg, slot) in self - .registers - .iter() - .zip(self.stack_slots_clobber.iter().copied()) - .filter_map(|(r, s)| r.zip(s)) - { - Self::save_register(&mut generated_asm, self.arch, reg, slot); - } - } - // Write input registers + Self::prologue(&mut generated_asm, self.arch); + + // Save clobbered registers + if !self.options.contains(InlineAsmOptions::NORETURN) { for (reg, slot) in self .registers .iter() - .zip(self.stack_slots_input.iter().copied()) + .zip(self.stack_slots_clobber.iter().copied()) .filter_map(|(r, s)| r.zip(s)) { - Self::restore_register(&mut generated_asm, self.arch, reg, slot); + Self::save_register(&mut generated_asm, self.arch, reg, slot); } } + // Write input registers + for (reg, slot) in self + .registers + .iter() + .zip(self.stack_slots_input.iter().copied()) + .filter_map(|(r, s)| r.zip(s)) + { + Self::restore_register(&mut generated_asm, self.arch, reg, slot); + } + if is_x86 && self.options.contains(InlineAsmOptions::ATT_SYNTAX) { generated_asm.push_str(".att_syntax\n"); } @@ -701,32 +586,30 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { generated_asm.push_str(".intel_syntax noprefix\n"); } - if !self.is_naked { - if !self.options.contains(InlineAsmOptions::NORETURN) { - // Read output registers - for (reg, slot) in self - .registers - .iter() - .zip(self.stack_slots_output.iter().copied()) - .filter_map(|(r, s)| r.zip(s)) - { - Self::save_register(&mut generated_asm, self.arch, reg, slot); - } - - // Restore clobbered registers - for (reg, slot) in self - .registers - .iter() - .zip(self.stack_slots_clobber.iter().copied()) - .filter_map(|(r, s)| r.zip(s)) - { - Self::restore_register(&mut generated_asm, self.arch, reg, slot); - } + if !self.options.contains(InlineAsmOptions::NORETURN) { + // Read output registers + for (reg, slot) in self + .registers + .iter() + .zip(self.stack_slots_output.iter().copied()) + .filter_map(|(r, s)| r.zip(s)) + { + Self::save_register(&mut generated_asm, self.arch, reg, slot); + } - Self::epilogue(&mut generated_asm, self.arch); - } else { - Self::epilogue_noreturn(&mut generated_asm, self.arch); + // Restore clobbered registers + for (reg, slot) in self + .registers + .iter() + .zip(self.stack_slots_clobber.iter().copied()) + .filter_map(|(r, s)| r.zip(s)) + { + Self::restore_register(&mut generated_asm, self.arch, reg, slot); } + + Self::epilogue(&mut generated_asm, self.arch); + } else { + Self::epilogue_noreturn(&mut generated_asm, self.arch); } if is_x86 { From b3b1eddc5b46da5482e5adb882791f239caffc5e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 13 Dec 2024 10:01:09 +0000 Subject: [PATCH 1792/4206] Share part of the global_asm!() implementation between cg_ssa and cg_clif --- src/driver/aot.rs | 5 +++- src/global_asm.rs | 68 ----------------------------------------------- 2 files changed, 4 insertions(+), 69 deletions(-) diff --git a/src/driver/aot.rs b/src/driver/aot.rs index 1cb8f8bc43993..5d07c94859f33 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -570,7 +570,10 @@ fn codegen_cgu_content( } } MonoItem::GlobalAsm(item_id) => { - crate::global_asm::codegen_global_asm_item(tcx, &mut cx.global_asm, item_id); + rustc_codegen_ssa::base::codegen_global_asm( + &mut GlobalAsmContext { tcx, global_asm: &mut cx.global_asm }, + item_id, + ); } } } diff --git a/src/global_asm.rs b/src/global_asm.rs index 18944a3be2769..eef5288027c32 100644 --- a/src/global_asm.rs +++ b/src/global_asm.rs @@ -8,8 +8,6 @@ use std::sync::Arc; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_codegen_ssa::traits::{AsmCodegenMethods, GlobalAsmOperandRef}; -use rustc_hir::{InlineAsmOperand, ItemId}; -use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::TyCtxt; use rustc_middle::ty::layout::{ FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError, LayoutOfHelpers, @@ -84,72 +82,6 @@ impl<'tcx> HasTypingEnv<'tcx> for GlobalAsmContext<'_, 'tcx> { } } -pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, item_id: ItemId) { - let item = tcx.hir_item(item_id); - let rustc_hir::ItemKind::GlobalAsm { asm, .. } = item.kind else { - bug!("Expected GlobalAsm found {:?}", item); - }; - - // Adapted from rustc_codegen_ssa::mono_items::MonoItem::define - let operands: Vec<_> = asm - .operands - .iter() - .map(|(op, op_sp)| match *op { - InlineAsmOperand::Const { ref anon_const } => { - match tcx.const_eval_poly(anon_const.def_id.to_def_id()) { - Ok(const_value) => { - let ty = tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id); - let string = rustc_codegen_ssa::common::asm_const_to_str( - tcx, - *op_sp, - const_value, - FullyMonomorphizedLayoutCx(tcx).layout_of(ty), - ); - GlobalAsmOperandRef::Const { string } - } - Err(ErrorHandled::Reported { .. }) => { - // An error has already been reported and - // compilation is guaranteed to fail if execution - // hits this path. So an empty string instead of - // a stringified constant value will suffice. - GlobalAsmOperandRef::Const { string: String::new() } - } - Err(ErrorHandled::TooGeneric(_)) => { - span_bug!(*op_sp, "asm const cannot be resolved; too generic") - } - } - } - InlineAsmOperand::SymFn { expr } => { - if cfg!(not(feature = "inline_asm_sym")) { - tcx.dcx().span_err( - item.span, - "asm! and global_asm! sym operands are not yet supported", - ); - } - - let ty = tcx.typeck(item_id.owner_id).expr_ty(expr); - let instance = match ty.kind() { - &ty::FnDef(def_id, args) => Instance::new(def_id, args), - _ => span_bug!(*op_sp, "asm sym is not a function"), - }; - GlobalAsmOperandRef::SymFn { instance } - } - InlineAsmOperand::SymStatic { path: _, def_id } => { - GlobalAsmOperandRef::SymStatic { def_id } - } - InlineAsmOperand::In { .. } - | InlineAsmOperand::Out { .. } - | InlineAsmOperand::InOut { .. } - | InlineAsmOperand::SplitInOut { .. } - | InlineAsmOperand::Label { .. } => { - span_bug!(*op_sp, "invalid operand type for global_asm!") - } - }) - .collect(); - - codegen_global_asm_inner(tcx, global_asm, asm.template, &operands, asm.options); -} - fn codegen_global_asm_inner<'tcx>( tcx: TyCtxt<'tcx>, global_asm: &mut String, From 25df5d021de5f109a71ad6a3a41f24aa9303d98d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 12 Dec 2024 20:16:58 +0000 Subject: [PATCH 1793/4206] Pass &mut self to codegen_global_asm --- src/asm.rs | 2 +- src/base.rs | 4 ++-- src/builder.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/asm.rs b/src/asm.rs index 415f8affab901..235814c948f78 100644 --- a/src/asm.rs +++ b/src/asm.rs @@ -794,7 +794,7 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl impl<'gcc, 'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn codegen_global_asm( - &self, + &mut self, template: &[InlineAsmTemplatePiece], operands: &[GlobalAsmOperandRef<'tcx>], options: InlineAsmOptions, diff --git a/src/base.rs b/src/base.rs index 292f0514070b4..a9d7808c833bb 100644 --- a/src/base.rs +++ b/src/base.rs @@ -206,7 +206,7 @@ pub fn compile_codegen_unit( let f128_type_supported = target_info.supports_target_dependent_type(CType::Float128); let u128_type_supported = target_info.supports_target_dependent_type(CType::UInt128t); // TODO: improve this to avoid passing that many arguments. - let cx = CodegenCx::new( + let mut cx = CodegenCx::new( &context, cgu, tcx, @@ -224,7 +224,7 @@ pub fn compile_codegen_unit( // ... and now that we have everything pre-defined, fill out those definitions. for &(mono_item, item_data) in &mono_items { - mono_item.define::>(&cx, item_data); + mono_item.define::>(&mut cx, item_data); } // If this codegen unit contains the main function, also create the diff --git a/src/builder.rs b/src/builder.rs index 6573b5b165e61..ecb4620e42617 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -45,7 +45,7 @@ enum ExtremumOperation { Min, } -pub struct Builder<'a: 'gcc, 'gcc, 'tcx> { +pub struct Builder<'a, 'gcc, 'tcx> { pub cx: &'a CodegenCx<'gcc, 'tcx>, pub block: Block<'gcc>, pub location: Option>, From 2d5e80b8cb89e9d809e569426d948e4f1fa6002d Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 10 Apr 2025 10:57:55 +0000 Subject: [PATCH 1794/4206] Handle regions equivalent to 'static in non_local_bounds `non_local_bounds` would only find non local bounds that strictly bound a given region, but it's possible that a local region is equated to 'static when showing a type referencing a locally bound lifetime, such as `dyn Any + 'a` in the tests added, is well-formed. In this case we should return 'static. --- .../src/type_check/free_region_relations.rs | 3 +- .../src/transitive_relation.rs | 14 +++ tests/crashes/122704.rs | 14 --- .../unconstrained-closure-lifetime-generic.rs | 22 ++++ ...onstrained-closure-lifetime-generic.stderr | 119 ++++++++++++++++++ ...nstrained-closure-lifetime-trait-object.rs | 11 ++ ...ained-closure-lifetime-trait-object.stderr | 17 +++ 7 files changed, 185 insertions(+), 15 deletions(-) delete mode 100644 tests/crashes/122704.rs create mode 100644 tests/ui/borrowck/unconstrained-closure-lifetime-generic.rs create mode 100644 tests/ui/borrowck/unconstrained-closure-lifetime-generic.stderr create mode 100644 tests/ui/borrowck/unconstrained-closure-lifetime-trait-object.rs create mode 100644 tests/ui/borrowck/unconstrained-closure-lifetime-trait-object.stderr diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index eaac633b512d6..aad10e3d6dc03 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -133,7 +133,8 @@ impl UniversalRegionRelations<'_> { assert!(self.universal_regions.is_universal_region(fr0)); let mut external_parents = vec![]; - let mut queue = vec![fr0]; + + let mut queue = vec![relation.minimal_scc_representative(fr0)]; // Keep expanding `fr` into its parents until we reach // non-local regions. diff --git a/compiler/rustc_data_structures/src/transitive_relation.rs b/compiler/rustc_data_structures/src/transitive_relation.rs index 33ac279f3e0ae..31abea938196c 100644 --- a/compiler/rustc_data_structures/src/transitive_relation.rs +++ b/compiler/rustc_data_structures/src/transitive_relation.rs @@ -354,6 +354,20 @@ impl TransitiveRelation { .collect() } + /// Given an element A, elements B with the lowest index such that `A R B` + /// and `B R A`, or `A` if no such element exists. + pub fn minimal_scc_representative(&self, a: T) -> T { + match self.index(a) { + Some(a_i) => self.with_closure(|closure| { + closure + .iter(a_i.0) + .find(|i| closure.contains(*i, a_i.0)) + .map_or(a, |i| self.elements[i]) + }), + None => a, + } + } + fn with_closure(&self, op: OP) -> R where OP: FnOnce(&BitMatrix) -> R, diff --git a/tests/crashes/122704.rs b/tests/crashes/122704.rs deleted file mode 100644 index d6c07be831885..0000000000000 --- a/tests/crashes/122704.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ known-bug: #122704 -use std::any::Any; - -pub struct Foo { - bar: Box Fn(&'a usize) -> Box>, -} - -impl Foo { - pub fn ack(&mut self, f: impl for<'a> Fn(&'a usize) -> Box) { - self.bar = Box::new(|baz| Box::new(f(baz))); - } -} - -fn main() {} diff --git a/tests/ui/borrowck/unconstrained-closure-lifetime-generic.rs b/tests/ui/borrowck/unconstrained-closure-lifetime-generic.rs new file mode 100644 index 0000000000000..4fdf5470feac6 --- /dev/null +++ b/tests/ui/borrowck/unconstrained-closure-lifetime-generic.rs @@ -0,0 +1,22 @@ +// Regression test for #122704 +use std::any::Any; + +pub struct Foo { + bar: Box Fn(&'a usize) -> Box>, +} + +impl Foo { + pub fn ack(&mut self, f: impl for<'a> Fn(&'a usize) -> Box) { + self.bar = Box::new(|baz| Box::new(f(baz))); + //~^ ERROR the parameter type `impl for<'a> Fn(&'a usize) -> Box` may not live long enough + //~| ERROR the parameter type `impl for<'a> Fn(&'a usize) -> Box` may not live long enough + //~| ERROR the parameter type `impl for<'a> Fn(&'a usize) -> Box` may not live long enough + //~| ERROR the parameter type `impl for<'a> Fn(&'a usize) -> Box` may not live long enough + //~| ERROR the parameter type `I` may not live long enough + //~| ERROR the parameter type `I` may not live long enough + //~| ERROR the parameter type `I` may not live long enough + //~| ERROR `f` does not live long enough + } +} + +fn main() {} diff --git a/tests/ui/borrowck/unconstrained-closure-lifetime-generic.stderr b/tests/ui/borrowck/unconstrained-closure-lifetime-generic.stderr new file mode 100644 index 0000000000000..df86ce79f09c7 --- /dev/null +++ b/tests/ui/borrowck/unconstrained-closure-lifetime-generic.stderr @@ -0,0 +1,119 @@ +error[E0310]: the parameter type `impl for<'a> Fn(&'a usize) -> Box` may not live long enough + --> $DIR/unconstrained-closure-lifetime-generic.rs:10:9 + | +LL | self.bar = Box::new(|baz| Box::new(f(baz))); + | ^^^^^^^^ + | | + | the parameter type `impl for<'a> Fn(&'a usize) -> Box` must be valid for the static lifetime... + | ...so that the type `impl for<'a> Fn(&'a usize) -> Box` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | pub fn ack(&mut self, f: impl for<'a> Fn(&'a usize) -> Box + 'static) { + | +++++++++ + +error[E0310]: the parameter type `impl for<'a> Fn(&'a usize) -> Box` may not live long enough + --> $DIR/unconstrained-closure-lifetime-generic.rs:10:9 + | +LL | self.bar = Box::new(|baz| Box::new(f(baz))); + | ^^^^^^^^ + | | + | the parameter type `impl for<'a> Fn(&'a usize) -> Box` must be valid for the static lifetime... + | ...so that the type `impl for<'a> Fn(&'a usize) -> Box` will meet its required lifetime bounds + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit lifetime bound + | +LL | pub fn ack(&mut self, f: impl for<'a> Fn(&'a usize) -> Box + 'static) { + | +++++++++ + +error[E0310]: the parameter type `impl for<'a> Fn(&'a usize) -> Box` may not live long enough + --> $DIR/unconstrained-closure-lifetime-generic.rs:10:20 + | +LL | self.bar = Box::new(|baz| Box::new(f(baz))); + | ^^^^^^^^ + | | + | the parameter type `impl for<'a> Fn(&'a usize) -> Box` must be valid for the static lifetime... + | ...so that the type `impl for<'a> Fn(&'a usize) -> Box` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | pub fn ack(&mut self, f: impl for<'a> Fn(&'a usize) -> Box + 'static) { + | +++++++++ + +error[E0310]: the parameter type `impl for<'a> Fn(&'a usize) -> Box` may not live long enough + --> $DIR/unconstrained-closure-lifetime-generic.rs:10:20 + | +LL | self.bar = Box::new(|baz| Box::new(f(baz))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the parameter type `impl for<'a> Fn(&'a usize) -> Box` must be valid for the static lifetime... + | ...so that the type `impl for<'a> Fn(&'a usize) -> Box` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | pub fn ack(&mut self, f: impl for<'a> Fn(&'a usize) -> Box + 'static) { + | +++++++++ + +error[E0310]: the parameter type `I` may not live long enough + --> $DIR/unconstrained-closure-lifetime-generic.rs:10:35 + | +LL | self.bar = Box::new(|baz| Box::new(f(baz))); + | ^^^^^^^^^^^^^^^^ + | | + | the parameter type `I` must be valid for the static lifetime... + | ...so that the type `I` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | pub fn ack(&mut self, f: impl for<'a> Fn(&'a usize) -> Box) { + | +++++++++ + +error[E0310]: the parameter type `I` may not live long enough + --> $DIR/unconstrained-closure-lifetime-generic.rs:10:35 + | +LL | self.bar = Box::new(|baz| Box::new(f(baz))); + | ^^^^^^^^^^^^^^^^ + | | + | the parameter type `I` must be valid for the static lifetime... + | ...so that the type `I` will meet its required lifetime bounds + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit lifetime bound + | +LL | pub fn ack(&mut self, f: impl for<'a> Fn(&'a usize) -> Box) { + | +++++++++ + +error[E0311]: the parameter type `I` may not live long enough + --> $DIR/unconstrained-closure-lifetime-generic.rs:10:35 + | +LL | pub fn ack(&mut self, f: impl for<'a> Fn(&'a usize) -> Box) { + | --------- the parameter type `I` must be valid for the anonymous lifetime defined here... +LL | self.bar = Box::new(|baz| Box::new(f(baz))); + | ^^^^^^^^^^^^^^^^ ...so that the type `I` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | pub fn ack<'a, I: 'a>(&'a mut self, f: impl for<'a> Fn(&'a usize) -> Box) { + | +++ ++++ ++ + +error[E0597]: `f` does not live long enough + --> $DIR/unconstrained-closure-lifetime-generic.rs:10:44 + | +LL | pub fn ack(&mut self, f: impl for<'a> Fn(&'a usize) -> Box) { + | - binding `f` declared here +LL | self.bar = Box::new(|baz| Box::new(f(baz))); + | -------- ----- ^ borrowed value does not live long enough + | | | + | | value captured here + | coercion requires that `f` is borrowed for `'static` +... +LL | } + | - `f` dropped here while still borrowed + | + = note: due to object lifetime defaults, `Box Fn(&'a usize) -> Box<(dyn Any + 'a)>>` actually means `Box<(dyn for<'a> Fn(&'a usize) -> Box<(dyn Any + 'a)> + 'static)>` + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0310, E0311, E0597. +For more information about an error, try `rustc --explain E0310`. diff --git a/tests/ui/borrowck/unconstrained-closure-lifetime-trait-object.rs b/tests/ui/borrowck/unconstrained-closure-lifetime-trait-object.rs new file mode 100644 index 0000000000000..3eee98d9bdb21 --- /dev/null +++ b/tests/ui/borrowck/unconstrained-closure-lifetime-trait-object.rs @@ -0,0 +1,11 @@ +// Regression test for #139004 +use std::any::Any; + +type B = Box Fn(&(dyn Any + 'a)) -> Box>; + +fn foo() -> B { + Box::new(|e| Box::new(e.is::())) + //~^ ERROR the parameter type `E` may not live long enough +} + +fn main() {} diff --git a/tests/ui/borrowck/unconstrained-closure-lifetime-trait-object.stderr b/tests/ui/borrowck/unconstrained-closure-lifetime-trait-object.stderr new file mode 100644 index 0000000000000..c9d5f78828d44 --- /dev/null +++ b/tests/ui/borrowck/unconstrained-closure-lifetime-trait-object.stderr @@ -0,0 +1,17 @@ +error[E0310]: the parameter type `E` may not live long enough + --> $DIR/unconstrained-closure-lifetime-trait-object.rs:7:29 + | +LL | Box::new(|e| Box::new(e.is::())) + | ^^ + | | + | the parameter type `E` must be valid for the static lifetime... + | ...so that the type `E` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo() -> B { + | +++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0310`. From c57ef293eb5c628b5a96253868c4ca171416780a Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 14 Apr 2025 10:40:44 +0000 Subject: [PATCH 1795/4206] Add unit tests for minimal_scc_representative --- .../src/transitive_relation/tests.rs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/compiler/rustc_data_structures/src/transitive_relation/tests.rs b/compiler/rustc_data_structures/src/transitive_relation/tests.rs index e756c546e41ba..cba14b5b64bc2 100644 --- a/compiler/rustc_data_structures/src/transitive_relation/tests.rs +++ b/compiler/rustc_data_structures/src/transitive_relation/tests.rs @@ -376,3 +376,44 @@ fn parent() { let p = relation.postdom_parent(3); assert_eq!(p, Some(0)); } + +#[test] +fn minimal_scc_representative_1() { + // +---------+ + // v | + // a -> c -> d -> e + // ^ ^ + // | | + // b ---+ + + // "digraph { a -> c -> d -> e -> c; b -> d; b -> e; }", + let mut relation = TransitiveRelationBuilder::default(); + relation.add("a", "c"); + relation.add("c", "d"); + relation.add("d", "e"); + relation.add("e", "c"); + relation.add("b", "d"); + relation.add("b", "e"); + let relation = relation.freeze(); + + assert_eq!(relation.minimal_scc_representative("a"), "a"); + assert_eq!(relation.minimal_scc_representative("b"), "b"); + assert_eq!(relation.minimal_scc_representative("c"), "c"); + assert_eq!(relation.minimal_scc_representative("d"), "c"); + assert_eq!(relation.minimal_scc_representative("e"), "c"); +} + +#[test] +fn minimal_scc_representative_2() { + // "digraph { a -> b; a -> a; b -> a; c -> c}", + let mut relation = TransitiveRelationBuilder::default(); + relation.add("a", "b"); + relation.add("b", "a"); + relation.add("a", "a"); + relation.add("c", "c"); + let relation = relation.freeze(); + + assert_eq!(relation.minimal_scc_representative("a"), "a"); + assert_eq!(relation.minimal_scc_representative("b"), "a"); + assert_eq!(relation.minimal_scc_representative("c"), "c"); +} From d39600e601fd9bb1cbd2257bf3bae270557edbe7 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Mon, 14 Apr 2025 19:44:25 +0200 Subject: [PATCH 1796/4206] =?UTF-8?q?Skip=20inner=20ordering=20checking=20?= =?UTF-8?q?in=20presence=20of=20`#[repr(=E2=80=A6)]`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A representation attribute `#[repr(…)]` might indicate that the ordering of the fields or the variants is dictated by the API the code is interfacing with. Better not lint with `arbitrary_source_item_ordering` in this case. --- .../src/arbitrary_source_item_ordering.rs | 19 +++- .../ordering_mixed.default.stderr | 70 +++++++++----- .../ordering_mixed.default_exp.stderr | 70 +++++++++----- .../ordering_mixed.ord_within.stderr | 94 +++++++++++++------ .../ordering_mixed.rs | 16 ++++ 5 files changed, 192 insertions(+), 77 deletions(-) diff --git a/clippy_lints/src/arbitrary_source_item_ordering.rs b/clippy_lints/src/arbitrary_source_item_ordering.rs index 8e261b9a882d8..5b8a746138631 100644 --- a/clippy_lints/src/arbitrary_source_item_ordering.rs +++ b/clippy_lints/src/arbitrary_source_item_ordering.rs @@ -6,9 +6,10 @@ use clippy_config::types::{ }; use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::is_cfg_test; +use rustc_attr_parsing::AttributeKind; use rustc_hir::{ - AssocItemKind, FieldDef, HirId, ImplItemRef, IsAuto, Item, ItemKind, Mod, QPath, TraitItemRef, TyKind, Variant, - VariantData, + AssocItemKind, Attribute, FieldDef, HirId, ImplItemRef, IsAuto, Item, ItemKind, Mod, QPath, TraitItemRef, TyKind, + Variant, VariantData, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; @@ -28,6 +29,11 @@ declare_clippy_lint! { /// implemented in the code. Sometimes this will be referred to as /// "bikeshedding". /// + /// The content of items with a representation clause attribute, such as + /// `#[repr(C)]` will not be checked, as the order of their fields or + /// variants might be dictated by an external API (application binary + /// interface). + /// /// ### Default Ordering and Configuration /// /// As there is no generally applicable rule, and each project may have @@ -256,6 +262,15 @@ impl ArbitrarySourceItemOrdering { impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + if cx + .tcx + .hir_attrs(item.hir_id()) + .iter() + .any(|attr| matches!(attr, Attribute::Parsed(AttributeKind::Repr(..)))) + { + // Do not lint items with a `#[repr]` attribute as their layout may be imposed by an external API. + return; + } match &item.kind { ItemKind::Enum(_, enum_def, _generics) if self.enable_ordering_for_enum => { let mut cur_v: Option<&Variant<'_>> = None; diff --git a/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default.stderr b/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default.stderr index 50567e32b1bb9..a3c35a31c3314 100644 --- a/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default.stderr +++ b/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default.stderr @@ -13,37 +13,37 @@ LL | const SNAKE_CASE: &str = "zzzzzzzz"; = help: to override `-D warnings` add `#[allow(clippy::arbitrary_source_item_ordering)]` error: incorrect ordering of items (module item groupings specify another order) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:149:7 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:165:7 | LL | const ZIS_SHOULD_BE_REALLY_EARLY: () = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `TraitUnorderedItemKinds` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:136:7 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:152:7 | LL | trait TraitUnorderedItemKinds { | ^^^^^^^^^^^^^^^^^^^^^^^ error: incorrect ordering of items (module item groupings specify another order) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:188:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:204:5 | LL | mod this_is_in_the_wrong_position { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `main` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:183:4 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:199:4 | LL | fn main() { | ^^^^ error: incorrect ordering of items (module item groupings specify another order) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:198:7 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:214:7 | LL | const ZIS_SHOULD_BE_EVEN_EARLIER: () = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `ZisShouldBeBeforeZeMainFn` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:196:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:212:8 | LL | struct ZisShouldBeBeforeZeMainFn; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,100 +61,124 @@ LL | C, | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:96:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:5 + | +LL | g: u8, + | ^ + | +note: should be placed before `r` + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:56:5 + | +LL | r: u8, + | ^ + +error: incorrect ordering of items (must be alphabetically ordered) + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:59:5 + | +LL | b: u8, + | ^ + | +note: should be placed before `g` + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:5 + | +LL | g: u8, + | ^ + +error: incorrect ordering of items (must be alphabetically ordered) + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:112:5 | LL | b: bool, | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:95:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:111:5 | LL | c: bool, | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:105:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:121:5 | LL | b: bool, | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:104:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:120:5 | LL | c: bool, | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:125:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:141:11 | LL | const B: bool; | ^ | note: should be placed before `C` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:124:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:140:11 | LL | const C: bool; | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:132:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:148:8 | LL | fn b(); | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:131:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:147:8 | LL | fn c(); | ^ error: incorrect ordering of trait items (defined order: [Const, Type, Fn]) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:139:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:155:5 | LL | const A: bool; | ^^^^^^^^^^^^^^ | note: should be placed before `SomeType` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:137:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:153:5 | LL | type SomeType; | ^^^^^^^^^^^^^^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:155:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:11 | LL | const B: bool = false; | ^ | note: should be placed before `C` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:154:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:170:11 | LL | const C: bool = false; | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:162:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:178:8 | LL | fn b() {} | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:161:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:177:8 | LL | fn c() {} | ^ error: incorrect ordering of impl items (defined order: [Const, Type, Fn]) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:173:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:189:5 | LL | const A: bool = false; | ^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `SomeType` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:187:5 | LL | type SomeType = (); | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 13 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default_exp.stderr b/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default_exp.stderr index 50567e32b1bb9..a3c35a31c3314 100644 --- a/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default_exp.stderr +++ b/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default_exp.stderr @@ -13,37 +13,37 @@ LL | const SNAKE_CASE: &str = "zzzzzzzz"; = help: to override `-D warnings` add `#[allow(clippy::arbitrary_source_item_ordering)]` error: incorrect ordering of items (module item groupings specify another order) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:149:7 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:165:7 | LL | const ZIS_SHOULD_BE_REALLY_EARLY: () = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `TraitUnorderedItemKinds` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:136:7 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:152:7 | LL | trait TraitUnorderedItemKinds { | ^^^^^^^^^^^^^^^^^^^^^^^ error: incorrect ordering of items (module item groupings specify another order) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:188:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:204:5 | LL | mod this_is_in_the_wrong_position { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `main` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:183:4 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:199:4 | LL | fn main() { | ^^^^ error: incorrect ordering of items (module item groupings specify another order) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:198:7 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:214:7 | LL | const ZIS_SHOULD_BE_EVEN_EARLIER: () = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `ZisShouldBeBeforeZeMainFn` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:196:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:212:8 | LL | struct ZisShouldBeBeforeZeMainFn; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,100 +61,124 @@ LL | C, | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:96:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:5 + | +LL | g: u8, + | ^ + | +note: should be placed before `r` + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:56:5 + | +LL | r: u8, + | ^ + +error: incorrect ordering of items (must be alphabetically ordered) + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:59:5 + | +LL | b: u8, + | ^ + | +note: should be placed before `g` + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:5 + | +LL | g: u8, + | ^ + +error: incorrect ordering of items (must be alphabetically ordered) + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:112:5 | LL | b: bool, | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:95:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:111:5 | LL | c: bool, | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:105:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:121:5 | LL | b: bool, | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:104:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:120:5 | LL | c: bool, | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:125:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:141:11 | LL | const B: bool; | ^ | note: should be placed before `C` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:124:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:140:11 | LL | const C: bool; | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:132:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:148:8 | LL | fn b(); | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:131:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:147:8 | LL | fn c(); | ^ error: incorrect ordering of trait items (defined order: [Const, Type, Fn]) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:139:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:155:5 | LL | const A: bool; | ^^^^^^^^^^^^^^ | note: should be placed before `SomeType` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:137:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:153:5 | LL | type SomeType; | ^^^^^^^^^^^^^^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:155:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:11 | LL | const B: bool = false; | ^ | note: should be placed before `C` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:154:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:170:11 | LL | const C: bool = false; | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:162:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:178:8 | LL | fn b() {} | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:161:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:177:8 | LL | fn c() {} | ^ error: incorrect ordering of impl items (defined order: [Const, Type, Fn]) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:173:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:189:5 | LL | const A: bool = false; | ^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `SomeType` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:187:5 | LL | type SomeType = (); | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 13 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.ord_within.stderr b/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.ord_within.stderr index ae5261dcc6df8..3fdd706fc627f 100644 --- a/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.ord_within.stderr +++ b/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.ord_within.stderr @@ -25,7 +25,19 @@ LL | const SNAKE_CASE: &str = "zzzzzzzz"; | ^^^^^^^^^^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:71:1 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:64:8 + | +LL | struct EnumWithExternButAtWrongPosition { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: should be placed before `EnumWithoutExtern` + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:55:8 + | +LL | struct EnumWithoutExtern { + | ^^^^^^^^^^^^^^^^^ + +error: incorrect ordering of items (must be alphabetically ordered) + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:87:1 | LL | / impl CloneSelf for StructOrdered { LL | | @@ -36,7 +48,7 @@ LL | | } | |_^ | note: should be placed before the following item - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:61:1 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:77:1 | LL | / impl Default for StructOrdered { LL | | fn default() -> Self { @@ -47,25 +59,25 @@ LL | | } | |_^ error: incorrect ordering of items (module item groupings specify another order) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:149:7 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:165:7 | LL | const ZIS_SHOULD_BE_REALLY_EARLY: () = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `TraitUnorderedItemKinds` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:136:7 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:152:7 | LL | trait TraitUnorderedItemKinds { | ^^^^^^^^^^^^^^^^^^^^^^^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:167:1 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:183:1 | LL | impl BasicEmptyTrait for StructOrdered {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before the following item - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:152:1 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:168:1 | LL | / impl TraitUnordered for StructUnordered { LL | | const A: bool = false; @@ -76,25 +88,25 @@ LL | | } | |_^ error: incorrect ordering of items (module item groupings specify another order) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:188:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:204:5 | LL | mod this_is_in_the_wrong_position { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `main` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:183:4 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:199:4 | LL | fn main() { | ^^^^ error: incorrect ordering of items (module item groupings specify another order) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:198:7 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:214:7 | LL | const ZIS_SHOULD_BE_EVEN_EARLIER: () = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `ZisShouldBeBeforeZeMainFn` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:196:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:212:8 | LL | struct ZisShouldBeBeforeZeMainFn; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -124,112 +136,136 @@ LL | C, | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:96:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:5 + | +LL | g: u8, + | ^ + | +note: should be placed before `r` + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:56:5 + | +LL | r: u8, + | ^ + +error: incorrect ordering of items (must be alphabetically ordered) + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:59:5 + | +LL | b: u8, + | ^ + | +note: should be placed before `g` + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:5 + | +LL | g: u8, + | ^ + +error: incorrect ordering of items (must be alphabetically ordered) + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:112:5 | LL | b: bool, | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:95:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:111:5 | LL | c: bool, | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:105:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:121:5 | LL | b: bool, | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:104:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:120:5 | LL | c: bool, | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:125:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:141:11 | LL | const B: bool; | ^ | note: should be placed before `C` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:124:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:140:11 | LL | const C: bool; | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:132:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:148:8 | LL | fn b(); | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:131:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:147:8 | LL | fn c(); | ^ error: incorrect ordering of trait items (defined order: [Const, Type, Fn]) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:139:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:155:5 | LL | const A: bool; | ^^^^^^^^^^^^^^ | note: should be placed before `SomeType` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:137:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:153:5 | LL | type SomeType; | ^^^^^^^^^^^^^^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:155:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:11 | LL | const B: bool = false; | ^ | note: should be placed before `C` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:154:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:170:11 | LL | const C: bool = false; | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:162:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:178:8 | LL | fn b() {} | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:161:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:177:8 | LL | fn c() {} | ^ error: incorrect ordering of impl items (defined order: [Const, Type, Fn]) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:173:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:189:5 | LL | const A: bool = false; | ^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `SomeType` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:187:5 | LL | type SomeType = (); | ^^^^^^^^^^^^^^^^^^^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:191:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:207:11 | LL | const A: i8 = 1; | ^ | note: should be placed before `C` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:190:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:206:11 | LL | const C: i8 = 0; | ^ -error: aborting due to 18 previous errors +error: aborting due to 21 previous errors diff --git a/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs b/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs index 90399470d4c09..1cfed9790c120 100644 --- a/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs +++ b/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs @@ -52,6 +52,22 @@ enum EnumUnorderedAllowed { B, } +struct EnumWithoutExtern { + r: u8, + g: u8, + //~^ arbitrary_source_item_ordering + b: u8, + //~^ arbitrary_source_item_ordering +} + +#[repr(C)] +struct EnumWithExternButAtWrongPosition { + //~[ord_within]^ arbitrary_source_item_ordering + r: u8, + g: u8, + b: u8, +} + struct StructOrdered { a: bool, b: bool, From b955cc691e07cbfca8000389cdbeaf587a0be19a Mon Sep 17 00:00:00 2001 From: quaternic <57393910+quaternic@users.noreply.github.com> Date: Tue, 15 Apr 2025 03:46:12 +0300 Subject: [PATCH 1797/4206] Implement rounding for the hex float parsing and prepare to improve error handling Parsing errors are now bubbled up part of the way, but that needs some more work. Rounding should be correct, and the `Status` returned by `parse_any` should have the correct bits set. These are used for the current (unchanged) behavior of the surface level functions like `hf64`: panic on invalid inputs, or values that aren't exactly representable. --- .../libm/crates/libm-test/src/f8_impl.rs | 5 +- .../libm/src/math/support/env.rs | 16 +- .../libm/src/math/support/hex_float.rs | 495 ++++++++++++++---- 3 files changed, 405 insertions(+), 111 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs index 0683d83926625..6772e092caacb 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs @@ -3,8 +3,6 @@ use std::cmp::{self, Ordering}; use std::{fmt, ops}; -use libm::support::hex_float::parse_any; - use crate::Float; /// Sometimes verifying float logic is easiest when all values can quickly be checked exhaustively @@ -499,5 +497,6 @@ impl fmt::LowerHex for f8 { } pub const fn hf8(s: &str) -> f8 { - f8(parse_any(s, 8, 3) as u8) + let Ok(bits) = libm::support::hex_float::parse_hex_exact(s, 8, 3) else { panic!() }; + f8(bits as u8) } diff --git a/library/compiler-builtins/libm/src/math/support/env.rs b/library/compiler-builtins/libm/src/math/support/env.rs index c05890d985186..796309372a5c3 100644 --- a/library/compiler-builtins/libm/src/math/support/env.rs +++ b/library/compiler-builtins/libm/src/math/support/env.rs @@ -46,7 +46,7 @@ pub enum Round { } /// IEEE 754 exception status flags. -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Status(u8); impl Status { @@ -90,16 +90,22 @@ impl Status { /// True if `UNDERFLOW` is set. #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] - pub fn underflow(self) -> bool { + pub const fn underflow(self) -> bool { self.0 & Self::UNDERFLOW.0 != 0 } + /// True if `OVERFLOW` is set. + #[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))] + pub const fn overflow(self) -> bool { + self.0 & Self::OVERFLOW.0 != 0 + } + pub fn set_underflow(&mut self, val: bool) { self.set_flag(val, Self::UNDERFLOW); } /// True if `INEXACT` is set. - pub fn inexact(self) -> bool { + pub const fn inexact(self) -> bool { self.0 & Self::INEXACT.0 != 0 } @@ -114,4 +120,8 @@ impl Status { self.0 &= !mask.0; } } + + pub(crate) const fn with(self, rhs: Self) -> Self { + Self(self.0 | rhs.0) + } } 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 be7d7607f91a2..819e2f56e36b2 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -2,149 +2,260 @@ use core::fmt; -use super::{Float, f32_from_bits, f64_from_bits}; +use super::{Float, Round, Status, f32_from_bits, f64_from_bits}; /// Construct a 16-bit float from hex float representation (C-style) #[cfg(f16_enabled)] pub const fn hf16(s: &str) -> f16 { - f16::from_bits(parse_any(s, 16, 10) as u16) + match parse_hex_exact(s, 16, 10) { + Ok(bits) => f16::from_bits(bits as u16), + Err(HexFloatParseError(s)) => panic!("{}", s), + } } /// Construct a 32-bit float from hex float representation (C-style) #[allow(unused)] pub const fn hf32(s: &str) -> f32 { - f32_from_bits(parse_any(s, 32, 23) as u32) + match parse_hex_exact(s, 32, 23) { + Ok(bits) => f32_from_bits(bits as u32), + Err(HexFloatParseError(s)) => panic!("{}", s), + } } /// Construct a 64-bit float from hex float representation (C-style) pub const fn hf64(s: &str) -> f64 { - f64_from_bits(parse_any(s, 64, 52) as u64) + match parse_hex_exact(s, 64, 52) { + Ok(bits) => f64_from_bits(bits as u64), + Err(HexFloatParseError(s)) => panic!("{}", s), + } } /// Construct a 128-bit float from hex float representation (C-style) #[cfg(f128_enabled)] pub const fn hf128(s: &str) -> f128 { - f128::from_bits(parse_any(s, 128, 112)) + match parse_hex_exact(s, 128, 112) { + Ok(bits) => f128::from_bits(bits), + Err(HexFloatParseError(s)) => panic!("{}", s), + } +} +#[derive(Copy, Clone, Debug)] +pub struct HexFloatParseError(&'static str); + +/// Parses any float to its bitwise representation, returning an error if it cannot be represented exactly +pub const fn parse_hex_exact( + s: &str, + bits: u32, + sig_bits: u32, +) -> Result { + match parse_any(s, bits, sig_bits, Round::Nearest) { + Err(e) => Err(e), + Ok((bits, Status::OK)) => Ok(bits), + Ok((_, status)) if status.overflow() => Err(HexFloatParseError("the value is too huge")), + Ok((_, status)) if status.underflow() => Err(HexFloatParseError("the value is too tiny")), + Ok((_, status)) if status.inexact() => Err(HexFloatParseError("the value is too precise")), + Ok(_) => unreachable!(), + } } /// Parse any float from hex to its bitwise representation. -/// -/// `nan_repr` is passed rather than constructed so the platform-specific NaN is returned. -pub const fn parse_any(s: &str, bits: u32, sig_bits: u32) -> u128 { +pub const fn parse_any( + s: &str, + bits: u32, + sig_bits: u32, + round: Round, +) -> Result<(u128, Status), HexFloatParseError> { + let mut b = s.as_bytes(); + + if sig_bits > 119 || bits > 128 || bits < sig_bits + 3 || bits > sig_bits + 30 { + return Err(HexFloatParseError("unsupported target float configuration")); + } + + let neg = matches!(b, [b'-', ..]); + if let &[b'-' | b'+', ref rest @ ..] = b { + b = rest; + } + + let sign_bit = 1 << (bits - 1); + let quiet_bit = 1 << (sig_bits - 1); + let nan = sign_bit - quiet_bit; + let inf = nan - quiet_bit; + + let (mut x, status) = match *b { + [b'i' | b'I', b'n' | b'N', b'f' | b'F'] => (inf, Status::OK), + [b'n' | b'N', b'a' | b'A', b'n' | b'N'] => (nan, Status::OK), + [b'0', b'x' | b'X', ref rest @ ..] => { + let round = match (neg, round) { + // parse("-x", Round::Positive) == -parse("x", Round::Negative) + (true, Round::Positive) => Round::Negative, + (true, Round::Negative) => Round::Positive, + // rounding toward nearest or zero are symmetric + (true, Round::Nearest | Round::Zero) | (false, _) => round, + }; + match parse_finite(rest, bits, sig_bits, round) { + Err(e) => return Err(e), + Ok(res) => res, + } + } + _ => return Err(HexFloatParseError("no hex indicator")), + }; + + if neg { + x ^= sign_bit; + } + + Ok((x, status)) +} + +const fn parse_finite( + b: &[u8], + bits: u32, + sig_bits: u32, + rounding_mode: Round, +) -> Result<(u128, Status), HexFloatParseError> { let exp_bits: u32 = bits - sig_bits - 1; let max_msb: i32 = (1 << (exp_bits - 1)) - 1; // The exponent of one ULP in the subnormals let min_lsb: i32 = 1 - max_msb - sig_bits as i32; - let exp_mask = ((1 << exp_bits) - 1) << sig_bits; + let (mut sig, mut exp) = match parse_hex(b) { + Err(e) => return Err(e), + Ok(Parsed { sig: 0, .. }) => return Ok((0, Status::OK)), + Ok(Parsed { sig, exp }) => (sig, exp), + }; + + let mut round_bits = u128_ilog2(sig) as i32 - sig_bits as i32; + + // Round at least up to min_lsb + if exp < min_lsb - round_bits { + round_bits = min_lsb - exp; + } + + let mut status = Status::OK; - let (neg, mut sig, exp) = match parse_hex(s.as_bytes()) { - Parsed::Finite { neg, sig: 0, .. } => return (neg as u128) << (bits - 1), - Parsed::Finite { neg, sig, exp } => (neg, sig, exp), - Parsed::Infinite { neg } => return ((neg as u128) << (bits - 1)) | exp_mask, - Parsed::Nan { neg } => { - return ((neg as u128) << (bits - 1)) | exp_mask | (1 << (sig_bits - 1)); + exp += round_bits; + + if round_bits > 0 { + // first, prepare for rounding exactly two bits + if round_bits == 1 { + sig <<= 1; + } else if round_bits > 2 { + sig = shr_odd_rounding(sig, (round_bits - 2) as u32); } - }; - // exponents of the least and most significant bits in the value - let lsb = sig.trailing_zeros() as i32; - let msb = u128_ilog2(sig) as i32; - let sig_bits = sig_bits as i32; + if sig & 0b11 != 0 { + status = Status::INEXACT; + } - assert!(msb - lsb <= sig_bits, "the value is too precise"); - assert!(msb + exp <= max_msb, "the value is too huge"); - assert!(lsb + exp >= min_lsb, "the value is too tiny"); + sig = shr2_round(sig, rounding_mode); + } else if round_bits < 0 { + sig <<= -round_bits; + } // The parsed value is X = sig * 2^exp // Expressed as a multiple U of the smallest subnormal value: // X = U * 2^min_lsb, so U = sig * 2^(exp-min_lsb) - let mut uexp = exp - min_lsb; + let uexp = (exp - min_lsb) as u128; + let uexp = uexp << sig_bits; - let shift = if uexp + msb >= sig_bits { - // normal, shift msb to position sig_bits - sig_bits - msb - } else { - // subnormal, shift so that uexp becomes 0 - uexp + // Note that it is possible for the exponent bits to equal 2 here + // if the value rounded up, but that means the mantissa is all zeroes + // so the value is still correct + debug_assert!(sig <= 2 << sig_bits); + + let inf = ((1 << exp_bits) - 1) << sig_bits; + + let bits = match sig.checked_add(uexp) { + Some(bits) if bits < inf => { + // inexact subnormal or zero? + if status.inexact() && bits < (1 << sig_bits) { + status = status.with(Status::UNDERFLOW); + } + bits + } + _ => { + // overflow to infinity + status = status.with(Status::OVERFLOW).with(Status::INEXACT); + match rounding_mode { + Round::Positive | Round::Nearest => inf, + Round::Negative | Round::Zero => inf - 1, + } + } }; + Ok((bits, status)) +} - if shift >= 0 { - sig <<= shift; +/// Shift right, rounding all inexact divisions to the nearest odd number +/// E.g. (0 >> 4) -> 0, (1..=31 >> 4) -> 1, (32 >> 4) -> 2, ... +/// +/// Useful for reducing a number before rounding the last two bits, since +/// the result of the final rounding is preserved for all rounding modes. +const fn shr_odd_rounding(x: u128, k: u32) -> u128 { + if k < 128 { + let inexact = x.trailing_zeros() < k; + (x >> k) | (inexact as u128) } else { - sig >>= -shift; + (x != 0) as u128 } - uexp -= shift; - - // the most significant bit is like having 1 in the exponent bits - // add any leftover exponent to that - assert!(uexp >= 0 && uexp < (1 << exp_bits) - 2); - sig += (uexp as u128) << sig_bits; +} - // finally, set the sign bit if necessary - sig | ((neg as u128) << (bits - 1)) +/// Divide by 4, rounding with the given mode +const fn shr2_round(mut x: u128, round: Round) -> u128 { + let t = (x as u32) & 0b111; + x >>= 2; + match round { + // Look-up-table on the last three bits for when to round up + Round::Nearest => x + ((0b11001000_u8 >> t) & 1) as u128, + + Round::Negative => x, + Round::Zero => x, + Round::Positive => x + (t & 0b11 != 0) as u128, + } } -/// A parsed floating point number. -enum Parsed { - /// Absolute value sig * 2^e - Finite { - neg: bool, - sig: u128, - exp: i32, - }, - Infinite { - neg: bool, - }, - Nan { - neg: bool, - }, +/// A parsed finite and unsigned floating point number. +struct Parsed { + /// Absolute value sig * 2^exp + sig: u128, + exp: i32, } /// Parse a hexadecimal float x -const fn parse_hex(mut b: &[u8]) -> Parsed { - let mut neg = false; +const fn parse_hex(mut b: &[u8]) -> Result { let mut sig: u128 = 0; let mut exp: i32 = 0; - if let &[c @ (b'-' | b'+'), ref rest @ ..] = b { - b = rest; - neg = c == b'-'; - } - - match *b { - [b'i' | b'I', b'n' | b'N', b'f' | b'F'] => return Parsed::Infinite { neg }, - [b'n' | b'N', b'a' | b'A', b'n' | b'N'] => return Parsed::Nan { neg }, - _ => (), - } - - if let &[b'0', b'x' | b'X', ref rest @ ..] = b { - b = rest; - } else { - panic!("no hex indicator"); - } - let mut seen_point = false; let mut some_digits = false; + let mut inexact = false; while let &[c, ref rest @ ..] = b { b = rest; match c { b'.' => { - assert!(!seen_point); + if seen_point { + return Err(HexFloatParseError("unexpected '.' parsing fractional digits")); + } seen_point = true; continue; } b'p' | b'P' => break, c => { - let digit = hex_digit(c); + let digit = match hex_digit(c) { + Some(d) => d, + None => return Err(HexFloatParseError("expected hexadecimal digit")), + }; some_digits = true; - let of; - (sig, of) = sig.overflowing_mul(16); - assert!(!of, "too many digits"); - sig |= digit as u128; - // up until the fractional point, the value grows + + if (sig >> 124) == 0 { + sig <<= 4; + sig |= digit as u128; + } else { + // FIXME: it is technically possible for exp to overflow if parsing a string with >500M digits + exp += 4; + inexact |= digit != 0; + } + // Up until the fractional point, the value grows // with more digits, but after it the exponent is // compensated to match. if seen_point { @@ -153,49 +264,79 @@ const fn parse_hex(mut b: &[u8]) -> Parsed { } } } - assert!(some_digits, "at least one digit is required"); + // If we've set inexact, the exact value has more than 125 + // significant bits, and lies somewhere between sig and sig + 1. + // Because we'll round off at least two of the trailing bits, + // setting the last bit gives correct rounding for inexact values. + sig |= inexact as u128; + + if !some_digits { + return Err(HexFloatParseError("at least one digit is required")); + }; + some_digits = false; - let mut negate_exp = false; - if let &[c @ (b'-' | b'+'), ref rest @ ..] = b { + let negate_exp = matches!(b, [b'-', ..]); + if let &[b'-' | b'+', ref rest @ ..] = b { b = rest; - negate_exp = c == b'-'; } - let mut pexp: i32 = 0; + let mut pexp: u32 = 0; while let &[c, ref rest @ ..] = b { b = rest; - let digit = dec_digit(c); + let digit = match dec_digit(c) { + Some(d) => d, + None => return Err(HexFloatParseError("expected decimal digit")), + }; some_digits = true; - let of; - (pexp, of) = pexp.overflowing_mul(10); - assert!(!of, "too many exponent digits"); - pexp += digit as i32; + pexp = pexp.saturating_mul(10); + pexp += digit as u32; } - assert!(some_digits, "at least one exponent digit is required"); + if !some_digits { + return Err(HexFloatParseError("at least one exponent digit is required")); + }; + + { + let e; + if negate_exp { + e = (exp as i64) - (pexp as i64); + } else { + e = (exp as i64) + (pexp as i64); + }; + + exp = if e < i32::MIN as i64 { + i32::MIN + } else if e > i32::MAX as i64 { + i32::MAX + } else { + e as i32 + }; + } + /* FIXME(msrv): once MSRV >= 1.66, replace the above workaround block with: if negate_exp { - exp -= pexp; + exp = exp.saturating_sub_unsigned(pexp); } else { - exp += pexp; - } + exp = exp.saturating_add_unsigned(pexp); + }; + */ - Parsed::Finite { neg, sig, exp } + Ok(Parsed { sig, exp }) } -const fn dec_digit(c: u8) -> u8 { +const fn dec_digit(c: u8) -> Option { match c { - b'0'..=b'9' => c - b'0', - _ => panic!("bad char"), + b'0'..=b'9' => Some(c - b'0'), + _ => None, } } -const fn hex_digit(c: u8) -> u8 { +const fn hex_digit(c: u8) -> Option { match c { - b'0'..=b'9' => c - b'0', - b'a'..=b'f' => c - b'a' + 10, - b'A'..=b'F' => c - b'A' + 10, - _ => panic!("bad char"), + b'0'..=b'9' => Some(c - b'0'), + b'a'..=b'f' => Some(c - b'a' + 10), + b'A'..=b'F' => Some(c - b'A' + 10), + _ => None, } } @@ -341,6 +482,61 @@ mod parse_tests { use super::*; + #[cfg(f16_enabled)] + fn rounding_properties(s: &str) -> Result<(), HexFloatParseError> { + let (xd, s0) = parse_any(s, 16, 10, Round::Negative)?; + let (xu, s1) = parse_any(s, 16, 10, Round::Positive)?; + let (xz, s2) = parse_any(s, 16, 10, Round::Zero)?; + let (xn, s3) = parse_any(s, 16, 10, Round::Nearest)?; + + // FIXME: A value between the least normal and largest subnormal + // could have underflow status depend on rounding mode. + + if let Status::OK = s0 { + // an exact result is the same for all rounding modes + assert_eq!(s0, s1); + assert_eq!(s0, s2); + assert_eq!(s0, s3); + + assert_eq!(xd, xu); + assert_eq!(xd, xz); + assert_eq!(xd, xn); + } else { + assert!([s0, s1, s2, s3].into_iter().all(Status::inexact)); + + let xd = f16::from_bits(xd as u16); + let xu = f16::from_bits(xu as u16); + let xz = f16::from_bits(xz as u16); + let xn = f16::from_bits(xn as u16); + + assert_biteq!(xd.next_up(), xu, "s={s}, xd={xd:?}, xu={xu:?}"); + + let signs = [xd, xu, xz, xn].map(f16::is_sign_negative); + + if signs == [true; 4] { + assert_biteq!(xz, xu); + } else { + assert_eq!(signs, [false; 4]); + assert_biteq!(xz, xd); + } + + if xn.to_bits() != xd.to_bits() { + assert_biteq!(xn, xu); + } + } + Ok(()) + } + #[test] + #[cfg(f16_enabled)] + fn test_rounding() { + 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))); + assert!(rounding_properties(&s).is_ok()); + } + } + #[test] fn test_parse_any() { for k in -149..=127 { @@ -397,6 +593,48 @@ mod parse_tests { } } + // FIXME: this test is causing failures that are likely UB on various platforms + #[cfg(all(target_arch = "x86_64", target_os = "linux"))] + #[test] + #[cfg(f128_enabled)] + fn rounding() { + let pi = std::f128::consts::PI; + let s = format!("{}", Hexf(pi)); + + for k in 0..=111 { + let (bits, status) = parse_any(&s, 128 - k, 112 - k, Round::Nearest).unwrap(); + let scale = (1u128 << (112 - k - 1)) as f128; + let expected = (pi * scale).round_ties_even() / scale; + assert_eq!(bits << k, expected.to_bits(), "k = {k}, s = {s}"); + assert_eq!(expected != pi, status.inexact()); + } + } + #[test] + fn rounding_extreme_underflow() { + for k in 1..1000 { + let s = format!("0x1p{}", -149 - k); + let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else { unreachable!() }; + assert_eq!(bits, 0, "{s} should round to zero, got bits={bits}"); + assert!(status.underflow(), "should indicate underflow when parsing {s}"); + assert!(status.inexact(), "should indicate inexact when parsing {s}"); + } + } + #[test] + fn long_tail() { + for k in 1..1000 { + let s = format!("0x1.{}p0", "0".repeat(k)); + let Ok(bits) = parse_hex_exact(&s, 32, 23) else { panic!("parsing {s} failed") }; + assert_eq!(f32::from_bits(bits as u32), 1.0); + + let s = format!("0x1.{}1p0", "0".repeat(k)); + let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else { unreachable!() }; + if status.inexact() { + assert!(1.0 == f32::from_bits(bits as u32)); + } else { + assert!(1.0 < f32::from_bits(bits as u32)); + } + } + } // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to // hide them from the AST. #[cfg(f16_enabled)] @@ -434,6 +672,7 @@ mod parse_tests { ]; for (s, exp) in checks { println!("parsing {s}"); + assert!(rounding_properties(s).is_ok()); let act = hf16(s).to_bits(); assert_eq!( act, exp, @@ -749,7 +988,13 @@ mod tests_panicking { #[test] #[should_panic(expected = "the value is too precise")] fn test_f128_extra_precision() { - // One bit more than the above. + // 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"); } @@ -822,6 +1067,46 @@ mod print_tests { } } + #[test] + #[cfg(f16_enabled)] + fn test_f16_to_f32() { + use std::format; + // Exhaustively check that these are equivalent for all `f16`: + // - `f16 -> f32` + // - `f16 -> str -> f32` + // - `f16 -> f32 -> str -> f32` + // - `f16 -> f32 -> str -> f16 -> f32` + for x in 0..=u16::MAX { + let f16 = f16::from_bits(x); + let s16 = format!("{}", Hexf(f16)); + let f32 = f16 as f32; + let s32 = format!("{}", Hexf(f32)); + + let a = hf32(&s16); + let b = hf32(&s32); + let c = hf16(&s32); + + if f32.is_nan() && a.is_nan() && b.is_nan() && c.is_nan() { + continue; + } + + assert_eq!( + f32.to_bits(), + a.to_bits(), + "{f16:?} : f16 formatted as {s16} which parsed as {a:?} : f16" + ); + assert_eq!( + f32.to_bits(), + b.to_bits(), + "{f32:?} : f32 formatted as {s32} which parsed as {b:?} : f32" + ); + assert_eq!( + f32.to_bits(), + (c as f32).to_bits(), + "{f32:?} : f32 formatted as {s32} which parsed as {c:?} : f16" + ); + } + } #[test] fn spot_checks() { assert_eq!(Hexf(f32::MAX).to_string(), "0x1.fffffep+127"); From 307a67a02a15ba0bfa26e48e0cdafbf889de5263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 15 Apr 2025 13:49:05 +0200 Subject: [PATCH 1798/4206] Replace flag `--doctest-compilation-args` with a simpler one: `--doctest-build-arg` More notably, the value of the new flag does *not* get lexed shell-like and ad hoc. --- src/librustdoc/config.rs | 6 +-- src/librustdoc/doctest.rs | 44 +------------------ src/librustdoc/doctest/tests.rs | 22 ---------- src/librustdoc/lib.rs | 6 +-- .../output-default.stdout | 5 ++- .../doctest/rustflags-multiple-args.rs | 7 ++- .../doctest/rustflags-multiple-args.stdout | 2 +- tests/rustdoc-ui/doctest/rustflags.rs | 2 +- 8 files changed, 15 insertions(+), 79 deletions(-) diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 23a2bcd9011ee..2f0113881b2bf 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -178,7 +178,7 @@ pub(crate) struct Options { pub(crate) expanded_args: Vec, /// Arguments to be used when compiling doctests. - pub(crate) doctest_compilation_args: Vec, + pub(crate) doctest_build_args: Vec, } impl fmt::Debug for Options { @@ -808,7 +808,7 @@ impl Options { let scrape_examples_options = ScrapeExamplesOptions::new(matches, dcx); let with_examples = matches.opt_strs("with-examples"); let call_locations = crate::scrape_examples::load_call_locations(with_examples, dcx); - let doctest_compilation_args = matches.opt_strs("doctest-compilation-args"); + let doctest_build_args = matches.opt_strs("doctest-build-arg"); let unstable_features = rustc_feature::UnstableFeatures::from_environment(crate_name.as_deref()); @@ -858,7 +858,7 @@ impl Options { scrape_examples_options, unstable_features, expanded_args: args, - doctest_compilation_args, + doctest_build_args, }; let render_options = RenderOptions { output, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 88eaa52c6deba..24509dc4229b0 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -51,46 +51,6 @@ pub(crate) struct GlobalTestOptions { pub(crate) args_file: PathBuf, } -/// Function used to split command line arguments just like a shell would. -fn split_args(args: &str) -> Vec { - let mut out = Vec::new(); - let mut iter = args.chars(); - let mut current = String::new(); - - while let Some(c) = iter.next() { - if c == '\\' { - if let Some(c) = iter.next() { - // If it's escaped, even a quote or a whitespace will be ignored. - current.push(c); - } - } else if c == '"' || c == '\'' { - while let Some(new_c) = iter.next() { - if new_c == c { - break; - } else if new_c == '\\' { - if let Some(c) = iter.next() { - // If it's escaped, even a quote will be ignored. - current.push(c); - } - } else { - current.push(new_c); - } - } - } else if " \n\t\r".contains(c) { - if !current.is_empty() { - out.push(current.clone()); - current.clear(); - } - } else { - current.push(c); - } - } - if !current.is_empty() { - out.push(current); - } - out -} - pub(crate) fn generate_args_file(file_path: &Path, options: &RustdocOptions) -> Result<(), String> { let mut file = File::create(file_path) .map_err(|error| format!("failed to create args file: {error:?}"))?; @@ -119,9 +79,7 @@ pub(crate) fn generate_args_file(file_path: &Path, options: &RustdocOptions) -> content.push(format!("-Z{unstable_option_str}")); } - for compilation_args in &options.doctest_compilation_args { - content.extend(split_args(compilation_args)); - } + content.extend(options.doctest_build_args.clone()); let content = content.join("\n"); diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs index 49add73e9d64b..618c2041b43c9 100644 --- a/src/librustdoc/doctest/tests.rs +++ b/src/librustdoc/doctest/tests.rs @@ -381,28 +381,6 @@ fn main() { assert_eq!((output, len), (expected, 1)); } -#[test] -fn check_split_args() { - fn compare(input: &str, expected: &[&str]) { - let output = super::split_args(input); - let expected = expected.iter().map(|s| s.to_string()).collect::>(); - assert_eq!(expected, output, "test failed for {input:?}"); - } - - compare("'a' \"b\"c", &["a", "bc"]); - compare("'a' \"b \"c d", &["a", "b c", "d"]); - compare("'a' \"b\\\"c\"", &["a", "b\"c"]); - compare("'a\"'", &["a\""]); - compare("\"a'\"", &["a'"]); - compare("\\ a", &[" a"]); - compare("\\\\", &["\\"]); - compare("a'", &["a"]); - compare("a ", &["a"]); - compare("a b", &["a", "b"]); - compare("a\n\t \rb", &["a", "b"]); - compare("a\n\t1 \rb", &["a", "1", "b"]); -} - #[test] fn comment_in_attrs() { // If there is an inline code comment after attributes, we need to ensure that diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 4fe5e13c3afe0..c1c2952ae2d89 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -646,9 +646,9 @@ fn opts() -> Vec { Unstable, Multi, "", - "doctest-compilation-args", - "", - "add arguments to be used when compiling doctests", + "doctest-build-arg", + "One argument (of possibly many) to be used when compiling doctests", + "ARG", ), opt( Unstable, diff --git a/tests/run-make/rustdoc-default-output/output-default.stdout b/tests/run-make/rustdoc-default-output/output-default.stdout index 01f470f6e162b..1ccb8ed1cbab9 100644 --- a/tests/run-make/rustdoc-default-output/output-default.stdout +++ b/tests/run-make/rustdoc-default-output/output-default.stdout @@ -191,8 +191,9 @@ Options: from provided path. Only use with --merge=finalize --html-no-source Disable HTML source code pages generation - --doctest-compilation-args add arguments to be used when compiling doctests - + --doctest-build-arg ARG + One argument (of possibly many) to be used when + compiling doctests --disable-minification disable the minification of CSS/JS files (perma-unstable, do not use with cached files) diff --git a/tests/rustdoc-ui/doctest/rustflags-multiple-args.rs b/tests/rustdoc-ui/doctest/rustflags-multiple-args.rs index 8d8c60ede5856..88e2e0cf01977 100644 --- a/tests/rustdoc-ui/doctest/rustflags-multiple-args.rs +++ b/tests/rustdoc-ui/doctest/rustflags-multiple-args.rs @@ -1,9 +1,8 @@ -// This test checks that the test behave when `--doctest-compilation-args` is passed -// multiple times. +// This test checks that the test behave when `--doctest-build-arg` is passed multiple times. //@ check-pass -//@ compile-flags: --test -Zunstable-options --doctest-compilation-args=--cfg=testcase_must_be_present -//@ compile-flags: --doctest-compilation-args=--cfg=another +//@ compile-flags: --test -Zunstable-options --doctest-build-arg=--cfg=testcase_must_be_present +//@ compile-flags: --doctest-build-arg=--cfg=another //@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" diff --git a/tests/rustdoc-ui/doctest/rustflags-multiple-args.stdout b/tests/rustdoc-ui/doctest/rustflags-multiple-args.stdout index 0e8a9e1efcf6f..f6b8ad6afabba 100644 --- a/tests/rustdoc-ui/doctest/rustflags-multiple-args.stdout +++ b/tests/rustdoc-ui/doctest/rustflags-multiple-args.stdout @@ -1,6 +1,6 @@ running 1 test -test $DIR/rustflags-multiple-args.rs - Bar (line 10) ... ok +test $DIR/rustflags-multiple-args.rs - Bar (line 9) ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/tests/rustdoc-ui/doctest/rustflags.rs b/tests/rustdoc-ui/doctest/rustflags.rs index 9f1e6017ea15f..f030158cdaa49 100644 --- a/tests/rustdoc-ui/doctest/rustflags.rs +++ b/tests/rustdoc-ui/doctest/rustflags.rs @@ -1,5 +1,5 @@ //@ check-pass -//@ compile-flags: --test -Zunstable-options --doctest-compilation-args=--cfg=testcase_must_be_present +//@ compile-flags: --test -Zunstable-options --doctest-build-arg=--cfg=testcase_must_be_present //@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" From b8083bd87d863b901bd713405e466db34c46b90d Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 13 Apr 2025 19:07:27 +0200 Subject: [PATCH 1799/4206] turn #[naked] into an unsafe attribute --- .../compiler-builtins/compiler-builtins/src/aarch64.rs | 2 +- .../compiler-builtins/src/aarch64_linux.rs | 8 ++++---- library/compiler-builtins/compiler-builtins/src/arm.rs | 8 ++++---- library/compiler-builtins/compiler-builtins/src/macros.rs | 4 ++-- library/compiler-builtins/compiler-builtins/src/x86.rs | 4 ++-- library/compiler-builtins/compiler-builtins/src/x86_64.rs | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/src/aarch64.rs b/library/compiler-builtins/compiler-builtins/src/aarch64.rs index cce485c46823d..80392187c89b4 100644 --- a/library/compiler-builtins/compiler-builtins/src/aarch64.rs +++ b/library/compiler-builtins/compiler-builtins/src/aarch64.rs @@ -3,7 +3,7 @@ use core::intrinsics; intrinsics! { - #[naked] + #[unsafe(naked)] #[cfg(all(target_os = "uefi", not(feature = "no-asm")))] pub unsafe extern "C" fn __chkstk() { core::arch::naked_asm!( diff --git a/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs b/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs index caac3e6025dc6..5515dbfc43af5 100644 --- a/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs +++ b/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs @@ -131,7 +131,7 @@ macro_rules! compare_and_swap { ($ordering:ident, $bytes:tt, $name:ident) => { intrinsics! { #[maybe_use_optimized_c_shim] - #[naked] + #[unsafe(naked)] pub unsafe extern "C" fn $name ( expected: int_ty!($bytes), desired: int_ty!($bytes), ptr: *mut int_ty!($bytes) ) -> int_ty!($bytes) { @@ -161,7 +161,7 @@ macro_rules! compare_and_swap_i128 { ($ordering:ident, $name:ident) => { intrinsics! { #[maybe_use_optimized_c_shim] - #[naked] + #[unsafe(naked)] pub unsafe extern "C" fn $name ( expected: i128, desired: i128, ptr: *mut i128 ) -> i128 { @@ -190,7 +190,7 @@ macro_rules! swap { ($ordering:ident, $bytes:tt, $name:ident) => { intrinsics! { #[maybe_use_optimized_c_shim] - #[naked] + #[unsafe(naked)] pub unsafe extern "C" fn $name ( left: int_ty!($bytes), right_ptr: *mut int_ty!($bytes) ) -> int_ty!($bytes) { @@ -215,7 +215,7 @@ macro_rules! fetch_op { ($ordering:ident, $bytes:tt, $name:ident, $op:literal) => { intrinsics! { #[maybe_use_optimized_c_shim] - #[naked] + #[unsafe(naked)] pub unsafe extern "C" fn $name ( val: int_ty!($bytes), ptr: *mut int_ty!($bytes) ) -> int_ty!($bytes) { diff --git a/library/compiler-builtins/compiler-builtins/src/arm.rs b/library/compiler-builtins/compiler-builtins/src/arm.rs index 9e6608397a846..878bb8c4331a0 100644 --- a/library/compiler-builtins/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/compiler-builtins/src/arm.rs @@ -20,7 +20,7 @@ macro_rules! bl { intrinsics! { // NOTE This function and the ones below are implemented using assembly because they are using a // custom calling convention which can't be implemented using a normal Rust function. - #[naked] + #[unsafe(naked)] #[cfg(not(target_env = "msvc"))] pub unsafe extern "C" fn __aeabi_uidivmod() { core::arch::naked_asm!( @@ -34,7 +34,7 @@ intrinsics! { ); } - #[naked] + #[unsafe(naked)] pub unsafe extern "C" fn __aeabi_uldivmod() { core::arch::naked_asm!( "push {{r4, lr}}", @@ -49,7 +49,7 @@ intrinsics! { ); } - #[naked] + #[unsafe(naked)] pub unsafe extern "C" fn __aeabi_idivmod() { core::arch::naked_asm!( "push {{r0, r1, r4, lr}}", @@ -61,7 +61,7 @@ intrinsics! { ); } - #[naked] + #[unsafe(naked)] pub unsafe extern "C" fn __aeabi_ldivmod() { core::arch::naked_asm!( "push {{r4, lr}}", diff --git a/library/compiler-builtins/compiler-builtins/src/macros.rs b/library/compiler-builtins/compiler-builtins/src/macros.rs index 0397e4551fba4..13c8ecee32d12 100644 --- a/library/compiler-builtins/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/compiler-builtins/src/macros.rs @@ -423,7 +423,7 @@ macro_rules! intrinsics { // Naked functions are special: we can't generate wrappers for them since // they use a custom calling convention. ( - #[naked] + #[unsafe(naked)] $(#[$($attr:tt)*])* pub unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { $($body:tt)* @@ -433,7 +433,7 @@ macro_rules! intrinsics { ) => ( // `#[naked]` definitions are referenced by other places, so we can't use `cfg` like the others pub mod $name { - #[naked] + #[unsafe(naked)] $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] diff --git a/library/compiler-builtins/compiler-builtins/src/x86.rs b/library/compiler-builtins/compiler-builtins/src/x86.rs index ad04d2108eadd..01152d9c79869 100644 --- a/library/compiler-builtins/compiler-builtins/src/x86.rs +++ b/library/compiler-builtins/compiler-builtins/src/x86.rs @@ -8,7 +8,7 @@ use core::intrinsics; // NOTE These functions are never mangled as they are not tested against compiler-rt intrinsics! { - #[naked] + #[unsafe(naked)] #[cfg(all( any(all(windows, target_env = "gnu"), target_os = "uefi"), not(feature = "no-asm") @@ -20,7 +20,7 @@ intrinsics! { ); } - #[naked] + #[unsafe(naked)] #[cfg(all( any(all(windows, target_env = "gnu"), target_os = "uefi"), not(feature = "no-asm") diff --git a/library/compiler-builtins/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/compiler-builtins/src/x86_64.rs index aae601f58bf07..af67e66e28d40 100644 --- a/library/compiler-builtins/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/compiler-builtins/src/x86_64.rs @@ -8,7 +8,7 @@ use core::intrinsics; // NOTE These functions are never mangled as they are not tested against compiler-rt intrinsics! { - #[naked] + #[unsafe(naked)] #[cfg(all( any( all(windows, target_env = "gnu"), From 377b08cc297cd9ae82bfa3e2604eaf64e426b7e6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 16 Apr 2025 18:23:30 +0000 Subject: [PATCH 1800/4206] chore: release v0.1.154 --- library/compiler-builtins/compiler-builtins/CHANGELOG.md | 6 ++++++ library/compiler-builtins/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/compiler-builtins/CHANGELOG.md index 517ba7859a97a..1dbccf38ec6be 100644 --- a/library/compiler-builtins/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/compiler-builtins/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.154](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.153...compiler_builtins-v0.1.154) - 2025-04-16 + +### Other + +- turn #[naked] into an unsafe attribute + ## [0.1.153](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.152...compiler_builtins-v0.1.153) - 2025-04-09 ### Other diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index c0c40b5e17a07..bd17885a10991 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.153" +version = "0.1.154" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "../README.md" repository = "https://github.com/rust-lang/compiler-builtins" From 14ab2453f235ce66074d54e4040ce06febfe54f4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 15 Apr 2025 04:20:17 +0000 Subject: [PATCH 1801/4206] fmod: Add regression tests for subnormal issue From discussion at [1] our loop count calculation is incorrect, causing an issue with subnormal numbers. Add test cases for known failures. [1]: https://github.com/rust-lang/libm/pull/469#discussion_r2012473920 --- .../crates/libm-test/src/gen/case_list.rs | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs index 7cb9897d8d2a8..e3628d51c9af5 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs @@ -403,11 +403,33 @@ fn fminimum_numf128_cases() -> Vec> { } fn fmod_cases() -> Vec> { - 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 } fn fmodf_cases() -> Vec> { - 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 } #[cfg(f128_enabled)] From e4d716c84801d1d91d473aaa28692f595f352b34 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 16 Apr 2025 18:43:25 +0000 Subject: [PATCH 1802/4206] fmod: Correct the normalization of subnormals Discussed at [1], there was an off-by-one mistake when converting from the loop routine to using `leading_zeros` for normalization. Currently, using `EXP_BITS` has the effect that `ix` after the branch has its MSB _one bit to the left_ of the implicit bit's position, whereas a shift by `EXP_BITS + 1` ensures that the MSB is exactly at the implicit bit's position, matching what is done for normals (where the implicit bit is set to be explicit). This doesn't seem to have any effect in our implementation since the failing test cases from [1] appear to still have correct results. Since the result of using `EXP_BITS + 1` is more consistent with what is done for normals, apply this here. [1]: https://github.com/rust-lang/libm/pull/469#discussion_r2012473920 --- library/compiler-builtins/libm/src/math/generic/fmod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/generic/fmod.rs b/library/compiler-builtins/libm/src/math/generic/fmod.rs index c74b593d559e7..cd23350ea3a6e 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmod.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmod.rs @@ -26,7 +26,7 @@ pub fn fmod(x: F, y: F) -> F { /* normalize x and y */ if ex == 0 { - let i = ix << F::EXP_BITS; + let i = ix << (F::EXP_BITS + 1); ex -= i.leading_zeros() as i32; ix <<= -ex + 1; } else { @@ -35,7 +35,7 @@ pub fn fmod(x: F, y: F) -> F { } if ey == 0 { - let i = iy << F::EXP_BITS; + let i = iy << (F::EXP_BITS + 1); ey -= i.leading_zeros() as i32; iy <<= -ey + 1; } else { From 7fb882c3fdf78bc1e3fe06c869e2d62ca64f3810 Mon Sep 17 00:00:00 2001 From: Paul Sbarra Date: Sat, 12 Apr 2025 16:14:24 -0500 Subject: [PATCH 1803/4206] avr: __udivmod(h|q)i4 --- .../compiler-builtins/src/int/udiv.rs | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/library/compiler-builtins/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/compiler-builtins/src/int/udiv.rs index a5c16040a52a2..f18537b006b0d 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/udiv.rs @@ -43,6 +43,92 @@ intrinsics! { ((rem as u64) << 32) | (div as u64) } + + #[unsafe(naked)] + pub unsafe extern "C" fn __udivmodqi4() { + // compute unsigned 8-bit `n / d` and `n % d`. + // + // Note: GCC implements a [non-standard calling convention](https://gcc.gnu.org/wiki/avr-gcc#Exceptions_to_the_Calling_Convention) for this function. + // Inputs: + // R24: dividend + // R22: divisor + // Outputs: + // R24: quotient (dividend / divisor) + // R25: remainder (dividend % divisor) + // Clobbers: + // R23: loop counter + core::arch::naked_asm!( + // This assembly routine implements the [long division](https://en.wikipedia.org/wiki/Division_algorithm#Long_division) algorithm. + // Bits shift out of the dividend and into the quotient, so R24 is used for both. + "clr R25", // remainder = 0 + + "ldi R23, 8", // for each bit + "1:", + "lsl R24", // shift the dividend MSb + "rol R25", // into the remainder LSb + + "cp R25, R22", // if remainder >= divisor + "brlo 2f", + "sub R25, R22", // remainder -= divisor + "sbr R24, 1", // quotient |= 1 + "2:", + + "dec R23", // end loop + "brne 1b", + "ret", + ); + } + + #[unsafe(naked)] + pub unsafe extern "C" fn __udivmodhi4() { + // compute unsigned 16-bit `n / d` and `n % d`. + // + // Note: GCC implements a [non-standard calling convention](https://gcc.gnu.org/wiki/avr-gcc#Exceptions_to_the_Calling_Convention) for this function. + // Inputs: + // R24: dividend [low] + // R25: dividend [high] + // R22: divisor [low] + // R23: divisor [high] + // Outputs: + // R22: quotient [low] (dividend / divisor) + // R23: quotient [high] + // R24: remainder [low] (dividend % divisor) + // R25: remainder [high] + // Clobbers: + // R21: loop counter + // R26: divisor [low] + // R27: divisor [high] + core::arch::naked_asm!( + // This assembly routine implements the [long division](https://en.wikipedia.org/wiki/Division_algorithm#Long_division) algorithm. + // Bits shift out of the dividend and into the quotient, so R24+R25 are used for both. + "mov R26, R22", // move divisor to make room for quotient + "mov R27, R23", + "mov R22, R24", // move dividend to output location (becomes quotient) + "mov R23, R25", + "clr R24", // remainder = 0 + "clr R25", + + "ldi R21, 16", // for each bit + "1:", + "lsl R22", // shift the dividend MSb + "rol R23", + "rol R24", // into the remainder LSb + "rol R25", + + "cp R24, R26", // if remainder >= divisor + "cpc R25, R27", + "brlo 2f", + "sub R24, R26", // remainder -= divisor + "sbc R25, R27", + "sbr R22, 1", // quotient |= 1 + "2:", + + "dec R21", // end loop + "brne 1b", + "ret", + ); + } + } intrinsics! { From 92725845336bf8dc4ceb1c2e5f04a6839b6dc5f5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 17 Apr 2025 08:19:50 +0000 Subject: [PATCH 1804/4206] Replace the `bl!` macro with `asm_sym` `bl!` is being used to add a leading underscore on Apple targets. `asm_sym` has been around since 2022 and handles platform-specific symbol names automatically, so make use of this instead. I have verified that `armv7s-apple-ios` still builds correctly. --- .../compiler-builtins/src/arm.rs | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/src/arm.rs b/library/compiler-builtins/compiler-builtins/src/arm.rs index 878bb8c4331a0..7859b51207c6e 100644 --- a/library/compiler-builtins/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/compiler-builtins/src/arm.rs @@ -1,20 +1,16 @@ #![cfg(not(feature = "no-asm"))] -#![allow(unused_imports)] -use core::intrinsics; - -// Apple symbols have a leading underscore. -#[cfg(target_vendor = "apple")] -macro_rules! bl { - ($func:literal) => { - concat!("bl _", $func) - }; +// Interfaces used by naked trampolines. +extern "C" { + fn __udivmodsi4(a: u32, b: u32, rem: *mut u32) -> u32; + fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64; + fn __divmoddi4(a: i64, b: i64, rem: *mut i64) -> i64; } -#[cfg(not(target_vendor = "apple"))] -macro_rules! bl { - ($func:literal) => { - concat!("bl ", $func) - }; + +extern "aapcs" { + // AAPCS is not always the correct ABI for these intrinsics, but we only use this to + // forward another `__aeabi_` call so it doesn't matter. + fn __aeabi_idiv(a: i32, b: i32) -> i32; } intrinsics! { @@ -27,10 +23,11 @@ intrinsics! { "push {{lr}}", "sub sp, sp, #4", "mov r2, sp", - bl!("__udivmodsi4"), + "bl {trampoline}", "ldr r1, [sp]", "add sp, sp, #4", "pop {{pc}}", + trampoline = sym crate::arm::__udivmodsi4 ); } @@ -41,11 +38,12 @@ intrinsics! { "sub sp, sp, #16", "add r4, sp, #8", "str r4, [sp]", - bl!("__udivmoddi4"), + "bl {trampoline}", "ldr r2, [sp, #8]", "ldr r3, [sp, #12]", "add sp, sp, #16", "pop {{r4, pc}}", + trampoline = sym crate::arm::__udivmoddi4 ); } @@ -53,11 +51,12 @@ intrinsics! { pub unsafe extern "C" fn __aeabi_idivmod() { core::arch::naked_asm!( "push {{r0, r1, r4, lr}}", - bl!("__aeabi_idiv"), + "bl {trampoline}", "pop {{r1, r2}}", "muls r2, r2, r0", "subs r1, r1, r2", "pop {{r4, pc}}", + trampoline = sym crate::arm::__aeabi_idiv, ); } @@ -68,11 +67,12 @@ intrinsics! { "sub sp, sp, #16", "add r4, sp, #8", "str r4, [sp]", - bl!("__divmoddi4"), + "bl {trampoline}", "ldr r2, [sp, #8]", "ldr r3, [sp, #12]", "add sp, sp, #16", "pop {{r4, pc}}", + trampoline = sym crate::arm::__divmoddi4, ); } From 7bfb15cd11d21c0edf0d60fb8419f0736e10937f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 17 Apr 2025 16:31:48 +0200 Subject: [PATCH 1805/4206] Fix `new_lint` clippy command --- clippy_dev/src/new_lint.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 96e12706c9e24..771f48b3f8b11 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -448,7 +448,7 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str> let mut file_contents = fs::read_to_string(path)?; assert!( - !file_contents.contains(&lint_name_upper), + !file_contents.contains(&format!("pub {lint_name_upper},")), "Lint `{}` already defined in `{}`", lint.name, path.display() From ec74a38b250387fb67acbb1cecca4f4c81b966cb Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 17 Apr 2025 12:27:35 +0200 Subject: [PATCH 1806/4206] use `#[cfg(bootstrap)]` for rustc sync --- .../compiler-builtins/compiler-builtins/Cargo.toml | 3 +++ .../compiler-builtins/compiler-builtins/src/macros.rs | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index bd17885a10991..f5bbf4cd4d50d 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -70,3 +70,6 @@ rustc-dep-of-std = ['compiler-builtins', 'core'] # This makes certain traits and function specializations public that # are not normally public but are required by the `testcrate` public-test-deps = [] + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(bootstrap)'] } diff --git a/library/compiler-builtins/compiler-builtins/src/macros.rs b/library/compiler-builtins/compiler-builtins/src/macros.rs index 13c8ecee32d12..b83414ce2b772 100644 --- a/library/compiler-builtins/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/compiler-builtins/src/macros.rs @@ -433,6 +433,17 @@ macro_rules! intrinsics { ) => ( // `#[naked]` definitions are referenced by other places, so we can't use `cfg` like the others pub mod $name { + // FIXME: when bootstrap supports `#[unsafe(naked)]` this duplication can be removed + #[cfg(bootstrap)] + #[naked] + $(#[$($attr)*])* + #[cfg_attr(not(feature = "mangled-names"), 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)* + } + + #[cfg(not(bootstrap))] #[unsafe(naked)] $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] From 3ea9f849d54b6fee2bdacea04cad4d15d68b3fb5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Apr 2025 18:57:23 +0000 Subject: [PATCH 1807/4206] chore: release v0.1.155 --- library/compiler-builtins/compiler-builtins/CHANGELOG.md | 8 ++++++++ library/compiler-builtins/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/compiler-builtins/CHANGELOG.md index 1dbccf38ec6be..9916f2986e98c 100644 --- a/library/compiler-builtins/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/compiler-builtins/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.155](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.154...compiler_builtins-v0.1.155) - 2025-04-17 + +### Other + +- use `#[cfg(bootstrap)]` for rustc sync +- Replace the `bl!` macro with `asm_sym` +- __udivmod(h|q)i4 + ## [0.1.154](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.153...compiler_builtins-v0.1.154) - 2025-04-16 ### Other diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index f5bbf4cd4d50d..eb5b2b9cc88e8 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.154" +version = "0.1.155" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "../README.md" repository = "https://github.com/rust-lang/compiler-builtins" From f88b7c8a46c6c129696a6c42d126388ec02ed0bf Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 00:18:12 +0000 Subject: [PATCH 1808/4206] Add `NEG_NAN` to `Float` Introduce a constant representing NaN with a negative sign bit for use with testing. There isn't really any guarantee that `F::NAN` is positive but in practice it always is, which is good enough for testing purposes. --- .../libm/crates/libm-test/src/f8_impl.rs | 1 + .../libm/src/math/support/float_traits.rs | 25 ++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs index 6772e092caacb..ddb7bf90e7f4a 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs @@ -30,6 +30,7 @@ impl Float for f8 { const INFINITY: Self = Self(0b0_1111_000); const NEG_INFINITY: Self = Self(0b1_1111_000); const NAN: Self = Self(0b0_1111_100); + const NEG_NAN: Self = Self(0b1_1111_100); const MIN_POSITIVE_NORMAL: Self = Self(1 << Self::SIG_BITS); // FIXME: incorrect values const EPSILON: Self = Self::ZERO; 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 96c209c852b1d..fac1048323765 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -34,6 +34,7 @@ pub trait Float: const INFINITY: Self; const NEG_INFINITY: Self; const NAN: Self; + const NEG_NAN: Self; const MAX: Self; const MIN: Self; const EPSILON: Self; @@ -187,6 +188,7 @@ macro_rules! float_impl { $bits:expr, $significand_bits:expr, $from_bits:path, + $to_bits:path, $fma_fn:ident, $fma_intrinsic:ident ) => { @@ -201,6 +203,9 @@ macro_rules! float_impl { const INFINITY: Self = Self::INFINITY; const NEG_INFINITY: Self = Self::NEG_INFINITY; const NAN: Self = Self::NAN; + // NAN isn't guaranteed to be positive but it usually is. We only use this for + // tests. + const NEG_NAN: Self = $from_bits($to_bits(Self::NAN) | Self::SIGN_MASK); const MAX: Self = -Self::MIN; // Sign bit set, saturated mantissa, saturated exponent with last bit zeroed const MIN: Self = $from_bits(Self::Int::MAX & !(1 << Self::SIG_BITS)); @@ -275,11 +280,11 @@ macro_rules! float_impl { } #[cfg(f16_enabled)] -float_impl!(f16, u16, i16, 16, 10, f16::from_bits, fmaf16, fmaf16); -float_impl!(f32, u32, i32, 32, 23, f32_from_bits, fmaf, fmaf32); -float_impl!(f64, u64, i64, 64, 52, f64_from_bits, fma, fmaf64); +float_impl!(f16, u16, i16, 16, 10, f16::from_bits, f16::to_bits, fmaf16, fmaf16); +float_impl!(f32, u32, i32, 32, 23, f32_from_bits, f32_to_bits, fmaf, fmaf32); +float_impl!(f64, u64, i64, 64, 52, f64_from_bits, f64_to_bits, fma, fmaf64); #[cfg(f128_enabled)] -float_impl!(f128, u128, i128, 128, 112, f128::from_bits, fmaf128, fmaf128); +float_impl!(f128, u128, i128, 128, 112, f128::from_bits, f128::to_bits, fmaf128, fmaf128); /* FIXME(msrv): vendor some things that are not const stable at our MSRV */ @@ -289,12 +294,24 @@ pub const fn f32_from_bits(bits: u32) -> f32 { unsafe { mem::transmute::(bits) } } +/// `f32::to_bits` +pub const fn f32_to_bits(x: f32) -> u32 { + // SAFETY: POD cast with no preconditions + unsafe { mem::transmute::(x) } +} + /// `f64::from_bits` pub const fn f64_from_bits(bits: u64) -> f64 { // SAFETY: POD cast with no preconditions unsafe { mem::transmute::(bits) } } +/// `f64::to_bits` +pub const fn f64_to_bits(x: f64) -> u64 { + // SAFETY: POD cast with no preconditions + unsafe { mem::transmute::(x) } +} + /// Trait for floats twice the bit width of another integer. pub trait DFloat: Float { /// Float that is half the bit width of the floatthis trait is implemented for. From 579627ddd58a620cfc7eeef65afdb7a5cae3c58b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 00:22:38 +0000 Subject: [PATCH 1809/4206] Make `assert_biteq!` not rely on having `Int` in scope --- library/compiler-builtins/libm/src/math/generic/fmax.rs | 2 +- library/compiler-builtins/libm/src/math/generic/fmaximum.rs | 2 +- .../compiler-builtins/libm/src/math/generic/fmaximum_num.rs | 2 +- library/compiler-builtins/libm/src/math/generic/fmin.rs | 2 +- library/compiler-builtins/libm/src/math/generic/fminimum.rs | 2 +- .../compiler-builtins/libm/src/math/generic/fminimum_num.rs | 2 +- library/compiler-builtins/libm/src/math/generic/rint.rs | 2 +- library/compiler-builtins/libm/src/math/generic/scalbn.rs | 1 - library/compiler-builtins/libm/src/math/support/macros.rs | 3 ++- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/generic/fmax.rs b/library/compiler-builtins/libm/src/math/generic/fmax.rs index 32613a46b9372..039ffce9ff5c9 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmax.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmax.rs @@ -26,7 +26,7 @@ pub fn fmax(x: F, y: F) -> F { #[cfg(test)] mod tests { use super::*; - use crate::support::{Hexf, Int}; + use crate::support::Hexf; fn spec_test() { let cases = [ diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs index 5f653ce94e282..b0fde88e8b47a 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs @@ -29,7 +29,7 @@ pub fn fmaximum(x: F, y: F) -> F { #[cfg(test)] mod tests { use super::*; - use crate::support::{Hexf, Int}; + use crate::support::Hexf; fn spec_test() { let cases = [ diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs index 2246601239214..68b03109d7b63 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs @@ -28,7 +28,7 @@ pub fn fmaximum_num(x: F, y: F) -> F { #[cfg(test)] mod tests { use super::*; - use crate::support::{Hexf, Int}; + use crate::support::Hexf; fn spec_test() { let cases = [ diff --git a/library/compiler-builtins/libm/src/math/generic/fmin.rs b/library/compiler-builtins/libm/src/math/generic/fmin.rs index 5cc33e904edf8..2aa7f6af7a051 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmin.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmin.rs @@ -25,7 +25,7 @@ pub fn fmin(x: F, y: F) -> F { #[cfg(test)] mod tests { use super::*; - use crate::support::{Hexf, Int}; + use crate::support::Hexf; fn spec_test() { let cases = [ diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum.rs b/library/compiler-builtins/libm/src/math/generic/fminimum.rs index f566d9631d3a3..e01c886464fab 100644 --- a/library/compiler-builtins/libm/src/math/generic/fminimum.rs +++ b/library/compiler-builtins/libm/src/math/generic/fminimum.rs @@ -29,7 +29,7 @@ pub fn fminimum(x: F, y: F) -> F { #[cfg(test)] mod tests { use super::*; - use crate::support::{Hexf, Int}; + use crate::support::Hexf; fn spec_test() { let cases = [ diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs index e58a585c329c5..3e97b893b319c 100644 --- a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs +++ b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs @@ -28,7 +28,7 @@ pub fn fminimum_num(x: F, y: F) -> F { #[cfg(test)] mod tests { use super::*; - use crate::support::{Hexf, Int}; + use crate::support::Hexf; fn spec_test() { let cases = [ diff --git a/library/compiler-builtins/libm/src/math/generic/rint.rs b/library/compiler-builtins/libm/src/math/generic/rint.rs index 2f8b2b365912e..45d2f3138665f 100644 --- a/library/compiler-builtins/libm/src/math/generic/rint.rs +++ b/library/compiler-builtins/libm/src/math/generic/rint.rs @@ -43,7 +43,7 @@ pub fn rint_round(x: F, _round: Round) -> FpResult { #[cfg(test)] mod tests { use super::*; - use crate::support::{Hexf, Int, Status}; + use crate::support::{Hexf, 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]; diff --git a/library/compiler-builtins/libm/src/math/generic/scalbn.rs b/library/compiler-builtins/libm/src/math/generic/scalbn.rs index 5ba7f2ab2d5f5..aaa243933d45a 100644 --- a/library/compiler-builtins/libm/src/math/generic/scalbn.rs +++ b/library/compiler-builtins/libm/src/math/generic/scalbn.rs @@ -121,7 +121,6 @@ where #[cfg(test)] mod tests { - use super::super::super::Int; use super::*; // Tests against N3220 diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index c80e7751159d6..0b72db0e46e8b 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -137,9 +137,10 @@ macro_rules! hf128 { #[cfg(test)] macro_rules! assert_biteq { ($left:expr, $right:expr, $($tt:tt)*) => {{ + use $crate::support::Int; let l = $left; let r = $right; - let bits = (l.to_bits() - l.to_bits()).leading_zeros(); // hack to get the width from the value + let bits = Int::leading_zeros(l.to_bits() - l.to_bits()); // hack to get the width from the value assert!( l.biteq(r), "{}\nl: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})", From a15c8c9a3d51cc917c09ba4be59f27ac17dd8664 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 00:22:21 +0000 Subject: [PATCH 1810/4206] Combine the source files for more generic implementations Splitting into different source files by float size doesn't have any benefit when the only content is a small function that forwards to the generic implementation. Combine the source files for all width versions of: * ceil * copysign * fabs * fdim * floor * fmaximum * fmaximum_num * fminimum * fminimum_num * ldexp * scalbn * sqrt * truc fmod is excluded to avoid conflicts with an open PR. As part of this change move unit tests out of the generic module, instead testing the type-specific functions (e.g. `ceilf16` rather than `ceil::()`). This ensures that unit tests are validating whatever we expose, such as arch-specific implementations via `select_implementation!`, which would otherwise be skipped. (They are still covered by integration tests). --- .../libm/etc/function-definitions.json | 60 +++++----- .../compiler-builtins/libm/src/math/acosf.rs | 2 +- .../compiler-builtins/libm/src/math/asinf.rs | 4 +- .../compiler-builtins/libm/src/math/ceil.rs | 32 ++++++ .../compiler-builtins/libm/src/math/ceilf.rs | 13 --- .../libm/src/math/ceilf128.rs | 7 -- .../libm/src/math/ceilf16.rs | 7 -- .../libm/src/math/copysign.rs | 80 ++++++++++++++ .../libm/src/math/copysignf.rs | 8 -- .../libm/src/math/copysignf128.rs | 8 -- .../libm/src/math/copysignf16.rs | 8 -- .../compiler-builtins/libm/src/math/fabs.rs | 103 ++++++++++++++++-- .../compiler-builtins/libm/src/math/fabsf.rs | 39 ------- .../libm/src/math/fabsf128.rs | 31 ------ .../libm/src/math/fabsf16.rs | 31 ------ .../compiler-builtins/libm/src/math/fdim.rs | 41 +++++++ .../compiler-builtins/libm/src/math/fdimf.rs | 12 -- .../libm/src/math/fdimf128.rs | 12 -- .../libm/src/math/fdimf16.rs | 12 -- .../compiler-builtins/libm/src/math/floor.rs | 32 ++++++ .../compiler-builtins/libm/src/math/floorf.rs | 13 --- .../libm/src/math/floorf128.rs | 7 -- .../libm/src/math/floorf16.rs | 7 -- .../libm/src/math/fmin_fmax.rs | 92 ++++++++++++++++ .../libm/src/math/fminimum_fmaximum.rs | 96 ++++++++++++++++ .../libm/src/math/fminimum_fmaximum_num.rs | 96 ++++++++++++++++ .../libm/src/math/generic/fmax.rs | 49 --------- .../libm/src/math/generic/fmaximum.rs | 51 --------- .../libm/src/math/generic/fmaximum_num.rs | 51 --------- .../libm/src/math/generic/fmin.rs | 49 --------- .../libm/src/math/generic/fminimum.rs | 51 --------- .../libm/src/math/generic/fminimum_num.rs | 51 --------- .../libm/src/math/generic/scalbn.rs | 65 ----------- .../compiler-builtins/libm/src/math/ldexp.rs | 17 +++ .../compiler-builtins/libm/src/math/ldexpf.rs | 4 - .../libm/src/math/ldexpf128.rs | 4 - .../libm/src/math/ldexpf16.rs | 4 - .../compiler-builtins/libm/src/math/mod.rs | 100 +++++------------ .../compiler-builtins/libm/src/math/round.rs | 20 ++++ .../compiler-builtins/libm/src/math/roundf.rs | 5 - .../libm/src/math/roundf128.rs | 5 - .../libm/src/math/roundf16.rs | 5 - .../compiler-builtins/libm/src/math/scalbn.rs | 83 ++++++++++++++ .../libm/src/math/scalbnf.rs | 4 - .../libm/src/math/scalbnf128.rs | 4 - .../libm/src/math/scalbnf16.rs | 4 - .../compiler-builtins/libm/src/math/sqrt.rs | 36 ++++++ .../compiler-builtins/libm/src/math/sqrtf.rs | 15 --- .../libm/src/math/sqrtf128.rs | 5 - .../libm/src/math/sqrtf16.rs | 11 -- .../compiler-builtins/libm/src/math/trunc.rs | 40 +++++++ .../compiler-builtins/libm/src/math/truncf.rs | 23 ---- .../libm/src/math/truncf128.rs | 7 -- .../libm/src/math/truncf16.rs | 7 -- 54 files changed, 819 insertions(+), 804 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/ceilf.rs delete mode 100644 library/compiler-builtins/libm/src/math/ceilf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/ceilf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/copysignf.rs delete mode 100644 library/compiler-builtins/libm/src/math/copysignf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/copysignf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/fabsf.rs delete mode 100644 library/compiler-builtins/libm/src/math/fabsf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/fabsf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/fdimf.rs delete mode 100644 library/compiler-builtins/libm/src/math/fdimf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/fdimf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/floorf.rs delete mode 100644 library/compiler-builtins/libm/src/math/floorf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/floorf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/ldexpf.rs delete mode 100644 library/compiler-builtins/libm/src/math/ldexpf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/ldexpf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/roundf.rs delete mode 100644 library/compiler-builtins/libm/src/math/roundf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/roundf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/scalbnf.rs delete mode 100644 library/compiler-builtins/libm/src/math/scalbnf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/scalbnf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/sqrtf.rs delete mode 100644 library/compiler-builtins/libm/src/math/sqrtf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/sqrtf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/truncf.rs delete mode 100644 library/compiler-builtins/libm/src/math/truncf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/truncf16.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index bca58402f4e97..801e74b22a57e 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -108,21 +108,21 @@ "ceilf": { "sources": [ "src/math/arch/wasm32.rs", - "src/math/ceilf.rs", + "src/math/ceil.rs", "src/math/generic/ceil.rs" ], "type": "f32" }, "ceilf128": { "sources": [ - "src/math/ceilf128.rs", + "src/math/ceil.rs", "src/math/generic/ceil.rs" ], "type": "f128" }, "ceilf16": { "sources": [ - "src/math/ceilf16.rs", + "src/math/ceil.rs", "src/math/generic/ceil.rs" ], "type": "f16" @@ -136,21 +136,21 @@ }, "copysignf": { "sources": [ - "src/math/copysignf.rs", + "src/math/copysign.rs", "src/math/generic/copysign.rs" ], "type": "f32" }, "copysignf128": { "sources": [ - "src/math/copysignf128.rs", + "src/math/copysign.rs", "src/math/generic/copysign.rs" ], "type": "f128" }, "copysignf16": { "sources": [ - "src/math/copysignf16.rs", + "src/math/copysign.rs", "src/math/generic/copysign.rs" ], "type": "f16" @@ -262,21 +262,21 @@ "fabsf": { "sources": [ "src/math/arch/wasm32.rs", - "src/math/fabsf.rs", + "src/math/fabs.rs", "src/math/generic/fabs.rs" ], "type": "f32" }, "fabsf128": { "sources": [ - "src/math/fabsf128.rs", + "src/math/fabs.rs", "src/math/generic/fabs.rs" ], "type": "f128" }, "fabsf16": { "sources": [ - "src/math/fabsf16.rs", + "src/math/fabs.rs", "src/math/generic/fabs.rs" ], "type": "f16" @@ -290,21 +290,21 @@ }, "fdimf": { "sources": [ - "src/math/fdimf.rs", + "src/math/fdim.rs", "src/math/generic/fdim.rs" ], "type": "f32" }, "fdimf128": { "sources": [ - "src/math/fdimf128.rs", + "src/math/fdim.rs", "src/math/generic/fdim.rs" ], "type": "f128" }, "fdimf16": { "sources": [ - "src/math/fdimf16.rs", + "src/math/fdim.rs", "src/math/generic/fdim.rs" ], "type": "f16" @@ -321,21 +321,21 @@ "floorf": { "sources": [ "src/math/arch/wasm32.rs", - "src/math/floorf.rs", + "src/math/floor.rs", "src/math/generic/floor.rs" ], "type": "f32" }, "floorf128": { "sources": [ - "src/math/floorf128.rs", + "src/math/floor.rs", "src/math/generic/floor.rs" ], "type": "f128" }, "floorf16": { "sources": [ - "src/math/floorf16.rs", + "src/math/floor.rs", "src/math/generic/floor.rs" ], "type": "f16" @@ -636,19 +636,19 @@ }, "ldexpf": { "sources": [ - "src/math/ldexpf.rs" + "src/math/ldexp.rs" ], "type": "f32" }, "ldexpf128": { "sources": [ - "src/math/ldexpf128.rs" + "src/math/ldexp.rs" ], "type": "f128" }, "ldexpf16": { "sources": [ - "src/math/ldexpf16.rs" + "src/math/ldexp.rs" ], "type": "f16" }, @@ -847,21 +847,21 @@ "roundf": { "sources": [ "src/math/generic/round.rs", - "src/math/roundf.rs" + "src/math/round.rs" ], "type": "f32" }, "roundf128": { "sources": [ "src/math/generic/round.rs", - "src/math/roundf128.rs" + "src/math/round.rs" ], "type": "f128" }, "roundf16": { "sources": [ "src/math/generic/round.rs", - "src/math/roundf16.rs" + "src/math/round.rs" ], "type": "f16" }, @@ -875,21 +875,21 @@ "scalbnf": { "sources": [ "src/math/generic/scalbn.rs", - "src/math/scalbnf.rs" + "src/math/scalbn.rs" ], "type": "f32" }, "scalbnf128": { "sources": [ "src/math/generic/scalbn.rs", - "src/math/scalbnf128.rs" + "src/math/scalbn.rs" ], "type": "f128" }, "scalbnf16": { "sources": [ "src/math/generic/scalbn.rs", - "src/math/scalbnf16.rs" + "src/math/scalbn.rs" ], "type": "f16" }, @@ -945,14 +945,14 @@ "src/math/arch/i686.rs", "src/math/arch/wasm32.rs", "src/math/generic/sqrt.rs", - "src/math/sqrtf.rs" + "src/math/sqrt.rs" ], "type": "f32" }, "sqrtf128": { "sources": [ "src/math/generic/sqrt.rs", - "src/math/sqrtf128.rs" + "src/math/sqrt.rs" ], "type": "f128" }, @@ -960,7 +960,7 @@ "sources": [ "src/math/arch/aarch64.rs", "src/math/generic/sqrt.rs", - "src/math/sqrtf16.rs" + "src/math/sqrt.rs" ], "type": "f16" }, @@ -1012,21 +1012,21 @@ "sources": [ "src/math/arch/wasm32.rs", "src/math/generic/trunc.rs", - "src/math/truncf.rs" + "src/math/trunc.rs" ], "type": "f32" }, "truncf128": { "sources": [ "src/math/generic/trunc.rs", - "src/math/truncf128.rs" + "src/math/trunc.rs" ], "type": "f128" }, "truncf16": { "sources": [ "src/math/generic/trunc.rs", - "src/math/truncf16.rs" + "src/math/trunc.rs" ], "type": "f16" }, diff --git a/library/compiler-builtins/libm/src/math/acosf.rs b/library/compiler-builtins/libm/src/math/acosf.rs index 1a60479e32a7f..dd88eea5b13a8 100644 --- a/library/compiler-builtins/libm/src/math/acosf.rs +++ b/library/compiler-builtins/libm/src/math/acosf.rs @@ -13,7 +13,7 @@ * ==================================================== */ -use super::sqrtf::sqrtf; +use super::sqrt::sqrtf; const PIO2_HI: f32 = 1.5707962513e+00; /* 0x3fc90fda */ const PIO2_LO: f32 = 7.5497894159e-08; /* 0x33a22168 */ diff --git a/library/compiler-builtins/libm/src/math/asinf.rs b/library/compiler-builtins/libm/src/math/asinf.rs index 0ea49c0767cd9..ed685556730e5 100644 --- a/library/compiler-builtins/libm/src/math/asinf.rs +++ b/library/compiler-builtins/libm/src/math/asinf.rs @@ -13,8 +13,8 @@ * ==================================================== */ -use super::fabsf::fabsf; use super::sqrt::sqrt; +use super::support::Float; const PIO2: f64 = 1.570796326794896558e+00; @@ -61,7 +61,7 @@ pub fn asinf(mut x: f32) -> f32 { } /* 1 > |x| >= 0.5 */ - let z = (1. - fabsf(x)) * 0.5; + let z = (1. - Float::abs(x)) * 0.5; let s = sqrt(z as f64); x = (PIO2 - 2. * (s + s * (r(z) as f64))) as f32; if (hx >> 31) != 0 { -x } else { x } diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index 535f434ac2437..4e103545727aa 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -1,3 +1,26 @@ +/// Ceil (f16) +/// +/// Finds the nearest integer greater than or equal to `x`. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ceilf16(x: f16) -> f16 { + super::generic::ceil(x) +} + +/// Ceil (f32) +/// +/// Finds the nearest integer greater than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ceilf(x: f32) -> f32 { + select_implementation! { + name: ceilf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + super::generic::ceil(x) +} + /// Ceil (f64) /// /// Finds the nearest integer greater than or equal to `x`. @@ -12,3 +35,12 @@ pub fn ceil(x: f64) -> f64 { super::generic::ceil(x) } + +/// Ceil (f128) +/// +/// Finds the nearest integer greater than or equal to `x`. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ceilf128(x: f128) -> f128 { + super::generic::ceil(x) +} diff --git a/library/compiler-builtins/libm/src/math/ceilf.rs b/library/compiler-builtins/libm/src/math/ceilf.rs deleted file mode 100644 index 66d44189c9212..0000000000000 --- a/library/compiler-builtins/libm/src/math/ceilf.rs +++ /dev/null @@ -1,13 +0,0 @@ -/// Ceil (f32) -/// -/// Finds the nearest integer greater than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ceilf(x: f32) -> f32 { - select_implementation! { - name: ceilf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - super::generic::ceil(x) -} diff --git a/library/compiler-builtins/libm/src/math/ceilf128.rs b/library/compiler-builtins/libm/src/math/ceilf128.rs deleted file mode 100644 index 89980858eb5be..0000000000000 --- a/library/compiler-builtins/libm/src/math/ceilf128.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Ceil (f128) -/// -/// Finds the nearest integer greater than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ceilf128(x: f128) -> f128 { - super::generic::ceil(x) -} diff --git a/library/compiler-builtins/libm/src/math/ceilf16.rs b/library/compiler-builtins/libm/src/math/ceilf16.rs deleted file mode 100644 index 2af67eff0d2aa..0000000000000 --- a/library/compiler-builtins/libm/src/math/ceilf16.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Ceil (f16) -/// -/// Finds the nearest integer greater than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ceilf16(x: f16) -> f16 { - super::generic::ceil(x) -} diff --git a/library/compiler-builtins/libm/src/math/copysign.rs b/library/compiler-builtins/libm/src/math/copysign.rs index 552bf3975b8f1..d2a86e7fd545f 100644 --- a/library/compiler-builtins/libm/src/math/copysign.rs +++ b/library/compiler-builtins/libm/src/math/copysign.rs @@ -1,3 +1,22 @@ +/// Sign of Y, magnitude of X (f16) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf16(x: f16, y: f16) -> f16 { + super::generic::copysign(x, y) +} + +/// Sign of Y, magnitude of X (f32) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf(x: f32, y: f32) -> f32 { + super::generic::copysign(x, y) +} + /// Sign of Y, magnitude of X (f64) /// /// Constructs a number with the magnitude (absolute value) of its @@ -6,3 +25,64 @@ pub fn copysign(x: f64, y: f64) -> f64 { super::generic::copysign(x, y) } + +/// Sign of Y, magnitude of X (f128) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf128(x: f128, y: f128) -> f128 { + super::generic::copysign(x, y) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::Float; + + fn spec_test(f: impl Fn(F, F) -> F) { + assert_biteq!(f(F::ZERO, F::ZERO), F::ZERO); + assert_biteq!(f(F::NEG_ZERO, F::ZERO), F::ZERO); + assert_biteq!(f(F::ZERO, F::NEG_ZERO), F::NEG_ZERO); + assert_biteq!(f(F::NEG_ZERO, F::NEG_ZERO), F::NEG_ZERO); + + assert_biteq!(f(F::ONE, F::ONE), F::ONE); + assert_biteq!(f(F::NEG_ONE, F::ONE), F::ONE); + assert_biteq!(f(F::ONE, F::NEG_ONE), F::NEG_ONE); + assert_biteq!(f(F::NEG_ONE, F::NEG_ONE), F::NEG_ONE); + + assert_biteq!(f(F::INFINITY, F::INFINITY), F::INFINITY); + assert_biteq!(f(F::NEG_INFINITY, F::INFINITY), F::INFINITY); + assert_biteq!(f(F::INFINITY, F::NEG_INFINITY), F::NEG_INFINITY); + assert_biteq!(f(F::NEG_INFINITY, F::NEG_INFINITY), F::NEG_INFINITY); + + // Not required but we expect it + assert_biteq!(f(F::NAN, F::NAN), F::NAN); + assert_biteq!(f(F::NEG_NAN, F::NAN), F::NAN); + assert_biteq!(f(F::NAN, F::NEG_NAN), F::NEG_NAN); + assert_biteq!(f(F::NEG_NAN, F::NEG_NAN), F::NEG_NAN); + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(copysignf16); + } + + #[test] + fn spec_tests_f32() { + spec_test::(copysignf); + } + + #[test] + fn spec_tests_f64() { + spec_test::(copysign); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(copysignf128); + } +} diff --git a/library/compiler-builtins/libm/src/math/copysignf.rs b/library/compiler-builtins/libm/src/math/copysignf.rs deleted file mode 100644 index 8b9bed4c0c427..0000000000000 --- a/library/compiler-builtins/libm/src/math/copysignf.rs +++ /dev/null @@ -1,8 +0,0 @@ -/// Sign of Y, magnitude of X (f32) -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysignf(x: f32, y: f32) -> f32 { - super::generic::copysign(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/copysignf128.rs b/library/compiler-builtins/libm/src/math/copysignf128.rs deleted file mode 100644 index 7bd81d42b2e9a..0000000000000 --- a/library/compiler-builtins/libm/src/math/copysignf128.rs +++ /dev/null @@ -1,8 +0,0 @@ -/// Sign of Y, magnitude of X (f128) -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysignf128(x: f128, y: f128) -> f128 { - super::generic::copysign(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/copysignf16.rs b/library/compiler-builtins/libm/src/math/copysignf16.rs deleted file mode 100644 index 8206586860102..0000000000000 --- a/library/compiler-builtins/libm/src/math/copysignf16.rs +++ /dev/null @@ -1,8 +0,0 @@ -/// Sign of Y, magnitude of X (f16) -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysignf16(x: f16, y: f16) -> f16 { - super::generic::copysign(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs index 22867fab05698..0050a309fee54 100644 --- a/library/compiler-builtins/libm/src/math/fabs.rs +++ b/library/compiler-builtins/libm/src/math/fabs.rs @@ -1,3 +1,28 @@ +/// Absolute value (magnitude) (f16) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf16(x: f16) -> f16 { + super::generic::fabs(x) +} + +/// Absolute value (magnitude) (f32) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf(x: f32) -> f32 { + select_implementation! { + name: fabsf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + super::generic::fabs(x) +} + /// Absolute value (magnitude) (f64) /// /// Calculates the absolute value (magnitude) of the argument `x`, @@ -13,25 +38,79 @@ pub fn fabs(x: f64) -> f64 { super::generic::fabs(x) } +/// Absolute value (magnitude) (f128) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf128(x: f128) -> f128 { + super::generic::fabs(x) +} + #[cfg(test)] mod tests { use super::*; + use crate::support::Float; + + /// Based on https://en.cppreference.com/w/cpp/numeric/math/fabs + fn spec_test(f: impl Fn(F) -> F) { + assert_biteq!(f(F::ZERO), F::ZERO); + assert_biteq!(f(F::NEG_ZERO), F::ZERO); + assert_biteq!(f(F::INFINITY), F::INFINITY); + assert_biteq!(f(F::NEG_INFINITY), F::INFINITY); + assert!(f(F::NAN).is_nan()); + + // Not spec rewquired but we expect it + assert!(f(F::NAN).is_sign_positive()); + assert!(f(F::from_bits(F::NAN.to_bits() | F::SIGN_MASK)).is_sign_positive()); + } + + #[test] + #[cfg(f16_enabled)] + fn sanity_check_f16() { + assert_eq!(fabsf16(-1.0f16), 1.0); + assert_eq!(fabsf16(2.8f16), 2.8); + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(fabsf16); + } + + #[test] + fn sanity_check_f32() { + assert_eq!(fabsf(-1.0f32), 1.0); + assert_eq!(fabsf(2.8f32), 2.8); + } + + #[test] + fn spec_tests_f32() { + spec_test::(fabsf); + } + + #[test] + fn sanity_check_f64() { + assert_eq!(fabs(-1.0f64), 1.0); + assert_eq!(fabs(2.8f64), 2.8); + } + + #[test] + fn spec_tests_f64() { + spec_test::(fabs); + } #[test] - fn sanity_check() { - assert_eq!(fabs(-1.0), 1.0); - assert_eq!(fabs(2.8), 2.8); + #[cfg(f128_enabled)] + fn sanity_check_f128() { + assert_eq!(fabsf128(-1.0f128), 1.0); + assert_eq!(fabsf128(2.8f128), 2.8); } - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs #[test] - fn spec_tests() { - assert!(fabs(f64::NAN).is_nan()); - for f in [0.0, -0.0].iter().copied() { - assert_eq!(fabs(f), 0.0); - } - for f in [f64::INFINITY, f64::NEG_INFINITY].iter().copied() { - assert_eq!(fabs(f), f64::INFINITY); - } + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(fabsf128); } } diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs deleted file mode 100644 index e5820a26c5238..0000000000000 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ /dev/null @@ -1,39 +0,0 @@ -/// Absolute value (magnitude) (f32) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabsf(x: f32) -> f32 { - select_implementation! { - name: fabsf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - super::generic::fabs(x) -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(fabsf(-1.0), 1.0); - assert_eq!(fabsf(2.8), 2.8); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs - #[test] - fn spec_tests() { - assert!(fabsf(f32::NAN).is_nan()); - for f in [0.0, -0.0].iter().copied() { - assert_eq!(fabsf(f), 0.0); - } - for f in [f32::INFINITY, f32::NEG_INFINITY].iter().copied() { - assert_eq!(fabsf(f), f32::INFINITY); - } - } -} diff --git a/library/compiler-builtins/libm/src/math/fabsf128.rs b/library/compiler-builtins/libm/src/math/fabsf128.rs deleted file mode 100644 index 46429ca494033..0000000000000 --- a/library/compiler-builtins/libm/src/math/fabsf128.rs +++ /dev/null @@ -1,31 +0,0 @@ -/// Absolute value (magnitude) (f128) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabsf128(x: f128) -> f128 { - super::generic::fabs(x) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(fabsf128(-1.0), 1.0); - assert_eq!(fabsf128(2.8), 2.8); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs - #[test] - fn spec_tests() { - assert!(fabsf128(f128::NAN).is_nan()); - for f in [0.0, -0.0].iter().copied() { - assert_eq!(fabsf128(f), 0.0); - } - for f in [f128::INFINITY, f128::NEG_INFINITY].iter().copied() { - assert_eq!(fabsf128(f), f128::INFINITY); - } - } -} diff --git a/library/compiler-builtins/libm/src/math/fabsf16.rs b/library/compiler-builtins/libm/src/math/fabsf16.rs deleted file mode 100644 index eee42ac6a3c60..0000000000000 --- a/library/compiler-builtins/libm/src/math/fabsf16.rs +++ /dev/null @@ -1,31 +0,0 @@ -/// Absolute value (magnitude) (f16) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabsf16(x: f16) -> f16 { - super::generic::fabs(x) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(fabsf16(-1.0), 1.0); - assert_eq!(fabsf16(2.8), 2.8); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs - #[test] - fn spec_tests() { - assert!(fabsf16(f16::NAN).is_nan()); - for f in [0.0, -0.0].iter().copied() { - assert_eq!(fabsf16(f), 0.0); - } - for f in [f16::INFINITY, f16::NEG_INFINITY].iter().copied() { - assert_eq!(fabsf16(f), f16::INFINITY); - } - } -} diff --git a/library/compiler-builtins/libm/src/math/fdim.rs b/library/compiler-builtins/libm/src/math/fdim.rs index 10ffa2881ddf7..082c5478b2aa6 100644 --- a/library/compiler-builtins/libm/src/math/fdim.rs +++ b/library/compiler-builtins/libm/src/math/fdim.rs @@ -1,3 +1,30 @@ +/// Positive difference (f16) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf16(x: f16, y: f16) -> f16 { + super::generic::fdim(x, y) +} + +/// Positive difference (f32) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf(x: f32, y: f32) -> f32 { + super::generic::fdim(x, y) +} + /// Positive difference (f64) /// /// Determines the positive difference between arguments, returning: @@ -10,3 +37,17 @@ pub fn fdim(x: f64, y: f64) -> f64 { super::generic::fdim(x, y) } + +/// Positive difference (f128) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf128(x: f128, y: f128) -> f128 { + super::generic::fdim(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/src/math/fdimf.rs deleted file mode 100644 index 367ef517c63be..0000000000000 --- a/library/compiler-builtins/libm/src/math/fdimf.rs +++ /dev/null @@ -1,12 +0,0 @@ -/// Positive difference (f32) -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdimf(x: f32, y: f32) -> f32 { - super::generic::fdim(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fdimf128.rs b/library/compiler-builtins/libm/src/math/fdimf128.rs deleted file mode 100644 index 6f3d1d0ff1d54..0000000000000 --- a/library/compiler-builtins/libm/src/math/fdimf128.rs +++ /dev/null @@ -1,12 +0,0 @@ -/// Positive difference (f128) -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdimf128(x: f128, y: f128) -> f128 { - super::generic::fdim(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fdimf16.rs b/library/compiler-builtins/libm/src/math/fdimf16.rs deleted file mode 100644 index 37bd688581797..0000000000000 --- a/library/compiler-builtins/libm/src/math/fdimf16.rs +++ /dev/null @@ -1,12 +0,0 @@ -/// Positive difference (f16) -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdimf16(x: f16, y: f16) -> f16 { - super::generic::fdim(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index b4f02abc49112..3c5eab101d18e 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -1,3 +1,12 @@ +/// Floor (f16) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf16(x: f16) -> f16 { + return super::generic::floor(x); +} + /// Floor (f64) /// /// Finds the nearest integer less than or equal to `x`. @@ -12,3 +21,26 @@ pub fn floor(x: f64) -> f64 { return super::generic::floor(x); } + +/// Floor (f32) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf(x: f32) -> f32 { + select_implementation! { + name: floorf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + return super::generic::floor(x); +} + +/// Floor (f128) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf128(x: f128) -> f128 { + return super::generic::floor(x); +} diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs deleted file mode 100644 index 16957b7f35573..0000000000000 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ /dev/null @@ -1,13 +0,0 @@ -/// Floor (f32) -/// -/// Finds the nearest integer less than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floorf(x: f32) -> f32 { - select_implementation! { - name: floorf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - return super::generic::floor(x); -} diff --git a/library/compiler-builtins/libm/src/math/floorf128.rs b/library/compiler-builtins/libm/src/math/floorf128.rs deleted file mode 100644 index 9a9fe4151152b..0000000000000 --- a/library/compiler-builtins/libm/src/math/floorf128.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Floor (f128) -/// -/// Finds the nearest integer less than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floorf128(x: f128) -> f128 { - return super::generic::floor(x); -} diff --git a/library/compiler-builtins/libm/src/math/floorf16.rs b/library/compiler-builtins/libm/src/math/floorf16.rs deleted file mode 100644 index f9b868e04109d..0000000000000 --- a/library/compiler-builtins/libm/src/math/floorf16.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Floor (f16) -/// -/// Finds the nearest integer less than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floorf16(x: f16) -> f16 { - return super::generic::floor(x); -} diff --git a/library/compiler-builtins/libm/src/math/fmin_fmax.rs b/library/compiler-builtins/libm/src/math/fmin_fmax.rs index 4f9136dbbcd44..2947b783e2fc5 100644 --- a/library/compiler-builtins/libm/src/math/fmin_fmax.rs +++ b/library/compiler-builtins/libm/src/math/fmin_fmax.rs @@ -73,3 +73,95 @@ pub fn fmax(x: f64, y: f64) -> f64 { pub fn fmaxf128(x: f128, y: f128) -> f128 { super::generic::fmax(x, y) } + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Float, Hexf}; + + fn fmin_spec_test(f: impl Fn(F, F) -> F) { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ZERO), + (F::ONE, F::ZERO, F::ZERO), + (F::ZERO, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::ZERO, F::NEG_ONE), + (F::INFINITY, F::ZERO, F::ZERO), + (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), + (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NAN, F::NAN), + ]; + + for (x, y, res) in cases { + let val = f(x, y); + assert_biteq!(val, res, "fmin({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn fmin_spec_tests_f16() { + fmin_spec_test::(fminf16); + } + + #[test] + fn fmin_spec_tests_f32() { + fmin_spec_test::(fminf); + } + + #[test] + fn fmin_spec_tests_f64() { + fmin_spec_test::(fmin); + } + + #[test] + #[cfg(f128_enabled)] + fn fmin_spec_tests_f128() { + fmin_spec_test::(fminf128); + } + + fn fmax_spec_test(f: impl Fn(F, F) -> F) { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ONE), + (F::ONE, F::ZERO, F::ONE), + (F::ZERO, F::NEG_ONE, F::ZERO), + (F::NEG_ONE, F::ZERO, F::ZERO), + (F::INFINITY, F::ZERO, F::INFINITY), + (F::NEG_INFINITY, F::ZERO, F::ZERO), + (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NAN, F::NAN), + ]; + + for (x, y, res) in cases { + let val = f(x, y); + assert_biteq!(val, res, "fmax({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn fmax_spec_tests_f16() { + fmax_spec_test::(fmaxf16); + } + + #[test] + fn fmax_spec_tests_f32() { + fmax_spec_test::(fmaxf); + } + + #[test] + fn fmax_spec_tests_f64() { + fmax_spec_test::(fmax); + } + + #[test] + #[cfg(f128_enabled)] + fn fmax_spec_tests_f128() { + fmax_spec_test::(fmaxf128); + } +} diff --git a/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs b/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs index fd3c5ed103911..b7999e27392b1 100644 --- a/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs +++ b/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs @@ -65,3 +65,99 @@ pub fn fmaximum(x: f64, y: f64) -> f64 { pub fn fmaximumf128(x: f128, y: f128) -> f128 { super::generic::fmaximum(x, y) } + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Float, Hexf}; + + fn fminimum_spec_test(f: impl Fn(F, F) -> F) { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ZERO), + (F::ONE, F::ZERO, F::ZERO), + (F::ZERO, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::ZERO, F::NEG_ONE), + (F::INFINITY, F::ZERO, F::ZERO), + (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), + (F::NAN, F::ZERO, F::NAN), + (F::ZERO, F::NAN, F::NAN), + (F::NAN, F::NAN, F::NAN), + (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), + ]; + + for (x, y, res) in cases { + let val = f(x, y); + assert_biteq!(val, res, "fminimum({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn fminimum_spec_tests_f16() { + fminimum_spec_test::(fminimumf16); + } + + #[test] + fn fminimum_spec_tests_f32() { + fminimum_spec_test::(fminimumf); + } + + #[test] + fn fminimum_spec_tests_f64() { + fminimum_spec_test::(fminimum); + } + + #[test] + #[cfg(f128_enabled)] + fn fminimum_spec_tests_f128() { + fminimum_spec_test::(fminimumf128); + } + + fn fmaximum_spec_test(f: impl Fn(F, F) -> F) { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ONE), + (F::ONE, F::ZERO, F::ONE), + (F::ZERO, F::NEG_ONE, F::ZERO), + (F::NEG_ONE, F::ZERO, F::ZERO), + (F::INFINITY, F::ZERO, F::INFINITY), + (F::NEG_INFINITY, F::ZERO, F::ZERO), + (F::NAN, F::ZERO, F::NAN), + (F::ZERO, F::NAN, F::NAN), + (F::NAN, F::NAN, F::NAN), + (F::ZERO, F::NEG_ZERO, F::ZERO), + (F::NEG_ZERO, F::ZERO, F::ZERO), + ]; + + for (x, y, res) in cases { + let val = f(x, y); + assert_biteq!(val, res, "fmaximum({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn fmaximum_spec_tests_f16() { + fmaximum_spec_test::(fmaximumf16); + } + + #[test] + fn fmaximum_spec_tests_f32() { + fmaximum_spec_test::(fmaximumf); + } + + #[test] + fn fmaximum_spec_tests_f64() { + fmaximum_spec_test::(fmaximum); + } + + #[test] + #[cfg(f128_enabled)] + fn fmaximum_spec_tests_f128() { + fmaximum_spec_test::(fmaximumf128); + } +} 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 640ddfc9b6612..180d21f72b74c 100644 --- a/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs +++ b/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs @@ -65,3 +65,99 @@ pub fn fmaximum_num(x: f64, y: f64) -> f64 { pub fn fmaximum_numf128(x: f128, y: f128) -> f128 { super::generic::fmaximum_num(x, y) } + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Float, Hexf}; + + fn fminimum_num_spec_test(f: impl Fn(F, F) -> F) { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ZERO), + (F::ONE, F::ZERO, F::ZERO), + (F::ZERO, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::ZERO, F::NEG_ONE), + (F::INFINITY, F::ZERO, F::ZERO), + (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), + (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NAN, F::NAN), + (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), + ]; + + for (x, y, res) in cases { + let val = f(x, y); + assert_biteq!(val, res, "fminimum_num({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn fminimum_num_spec_tests_f16() { + fminimum_num_spec_test::(fminimum_numf16); + } + + #[test] + fn fminimum_num_spec_tests_f32() { + fminimum_num_spec_test::(fminimum_numf); + } + + #[test] + fn fminimum_num_spec_tests_f64() { + fminimum_num_spec_test::(fminimum_num); + } + + #[test] + #[cfg(f128_enabled)] + fn fminimum_num_spec_tests_f128() { + fminimum_num_spec_test::(fminimum_numf128); + } + + fn fmaximum_num_spec_test(f: impl Fn(F, F) -> F) { + let cases = [ + (F::ZERO, F::ZERO, F::ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::ONE, F::ONE), + (F::ONE, F::ZERO, F::ONE), + (F::ZERO, F::NEG_ONE, F::ZERO), + (F::NEG_ONE, F::ZERO, F::ZERO), + (F::INFINITY, F::ZERO, F::INFINITY), + (F::NEG_INFINITY, F::ZERO, F::ZERO), + (F::NAN, F::ZERO, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NAN, F::NAN), + (F::ZERO, F::NEG_ZERO, F::ZERO), + (F::NEG_ZERO, F::ZERO, F::ZERO), + ]; + + for (x, y, res) in cases { + let val = f(x, y); + assert_biteq!(val, res, "fmaximum_num({}, {})", Hexf(x), Hexf(y)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn fmaximum_num_spec_tests_f16() { + fmaximum_num_spec_test::(fmaximum_numf16); + } + + #[test] + fn fmaximum_num_spec_tests_f32() { + fmaximum_num_spec_test::(fmaximum_numf); + } + + #[test] + fn fmaximum_num_spec_tests_f64() { + fmaximum_num_spec_test::(fmaximum_num); + } + + #[test] + #[cfg(f128_enabled)] + fn fmaximum_num_spec_tests_f128() { + fmaximum_num_spec_test::(fmaximum_numf128); + } +} diff --git a/library/compiler-builtins/libm/src/math/generic/fmax.rs b/library/compiler-builtins/libm/src/math/generic/fmax.rs index 039ffce9ff5c9..29a0311005716 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmax.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmax.rs @@ -22,52 +22,3 @@ pub fn fmax(x: F, y: F) -> F { // Canonicalize res * F::ONE } - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Hexf; - - fn spec_test() { - let cases = [ - (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ONE), - (F::ONE, F::ZERO, F::ONE), - (F::ZERO, F::NEG_ONE, F::ZERO), - (F::NEG_ONE, F::ZERO, F::ZERO), - (F::INFINITY, F::ZERO, F::INFINITY), - (F::NEG_INFINITY, F::ZERO, F::ZERO), - (F::NAN, F::ZERO, F::ZERO), - (F::ZERO, F::NAN, F::ZERO), - (F::NAN, F::NAN, F::NAN), - ]; - - for (x, y, res) in cases { - let val = fmax(x, y); - assert_biteq!(val, res, "fmax({}, {})", Hexf(x), Hexf(y)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - spec_test::(); - } - - #[test] - fn spec_tests_f32() { - spec_test::(); - } - - #[test] - fn spec_tests_f64() { - spec_test::(); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - spec_test::(); - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs index b0fde88e8b47a..9e8d1739f6786 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs @@ -25,54 +25,3 @@ pub fn fmaximum(x: F, y: F) -> F { // Canonicalize res * F::ONE } - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Hexf; - - fn spec_test() { - let cases = [ - (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ONE), - (F::ONE, F::ZERO, F::ONE), - (F::ZERO, F::NEG_ONE, F::ZERO), - (F::NEG_ONE, F::ZERO, F::ZERO), - (F::INFINITY, F::ZERO, F::INFINITY), - (F::NEG_INFINITY, F::ZERO, F::ZERO), - (F::NAN, F::ZERO, F::NAN), - (F::ZERO, F::NAN, F::NAN), - (F::NAN, F::NAN, F::NAN), - (F::ZERO, F::NEG_ZERO, F::ZERO), - (F::NEG_ZERO, F::ZERO, F::ZERO), - ]; - - for (x, y, res) in cases { - let val = fmaximum(x, y); - assert_biteq!(val, res, "fmaximum({}, {})", Hexf(x), Hexf(y)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - spec_test::(); - } - - #[test] - fn spec_tests_f32() { - spec_test::(); - } - - #[test] - fn spec_tests_f64() { - spec_test::(); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - spec_test::(); - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs index 68b03109d7b63..756ef5d9f6ded 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs @@ -24,54 +24,3 @@ pub fn fmaximum_num(x: F, y: F) -> F { // Canonicalize res * F::ONE } - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Hexf; - - fn spec_test() { - let cases = [ - (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ONE), - (F::ONE, F::ZERO, F::ONE), - (F::ZERO, F::NEG_ONE, F::ZERO), - (F::NEG_ONE, F::ZERO, F::ZERO), - (F::INFINITY, F::ZERO, F::INFINITY), - (F::NEG_INFINITY, F::ZERO, F::ZERO), - (F::NAN, F::ZERO, F::ZERO), - (F::ZERO, F::NAN, F::ZERO), - (F::NAN, F::NAN, F::NAN), - (F::ZERO, F::NEG_ZERO, F::ZERO), - (F::NEG_ZERO, F::ZERO, F::ZERO), - ]; - - for (x, y, res) in cases { - let val = fmaximum_num(x, y); - assert_biteq!(val, res, "fmaximum_num({}, {})", Hexf(x), Hexf(y)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - spec_test::(); - } - - #[test] - fn spec_tests_f32() { - spec_test::(); - } - - #[test] - fn spec_tests_f64() { - spec_test::(); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - spec_test::(); - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/fmin.rs b/library/compiler-builtins/libm/src/math/generic/fmin.rs index 2aa7f6af7a051..69fbf85a194ed 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmin.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmin.rs @@ -21,52 +21,3 @@ pub fn fmin(x: F, y: F) -> F { // Canonicalize res * F::ONE } - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Hexf; - - fn spec_test() { - let cases = [ - (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ZERO), - (F::ONE, F::ZERO, F::ZERO), - (F::ZERO, F::NEG_ONE, F::NEG_ONE), - (F::NEG_ONE, F::ZERO, F::NEG_ONE), - (F::INFINITY, F::ZERO, F::ZERO), - (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), - (F::NAN, F::ZERO, F::ZERO), - (F::ZERO, F::NAN, F::ZERO), - (F::NAN, F::NAN, F::NAN), - ]; - - for (x, y, res) in cases { - let val = fmin(x, y); - assert_biteq!(val, res, "fmin({}, {})", Hexf(x), Hexf(y)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - spec_test::(); - } - - #[test] - fn spec_tests_f32() { - spec_test::(); - } - - #[test] - fn spec_tests_f64() { - spec_test::(); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - spec_test::(); - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum.rs b/library/compiler-builtins/libm/src/math/generic/fminimum.rs index e01c886464fab..ee5493880eb43 100644 --- a/library/compiler-builtins/libm/src/math/generic/fminimum.rs +++ b/library/compiler-builtins/libm/src/math/generic/fminimum.rs @@ -25,54 +25,3 @@ pub fn fminimum(x: F, y: F) -> F { // Canonicalize res * F::ONE } - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Hexf; - - fn spec_test() { - let cases = [ - (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ZERO), - (F::ONE, F::ZERO, F::ZERO), - (F::ZERO, F::NEG_ONE, F::NEG_ONE), - (F::NEG_ONE, F::ZERO, F::NEG_ONE), - (F::INFINITY, F::ZERO, F::ZERO), - (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), - (F::NAN, F::ZERO, F::NAN), - (F::ZERO, F::NAN, F::NAN), - (F::NAN, F::NAN, F::NAN), - (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), - (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), - ]; - - for (x, y, res) in cases { - let val = fminimum(x, y); - assert_biteq!(val, res, "fminimum({}, {})", Hexf(x), Hexf(y)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - spec_test::(); - } - - #[test] - fn spec_tests_f32() { - spec_test::(); - } - - #[test] - fn spec_tests_f64() { - spec_test::(); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - spec_test::(); - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs index 3e97b893b319c..966618328242e 100644 --- a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs +++ b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs @@ -24,54 +24,3 @@ pub fn fminimum_num(x: F, y: F) -> F { // Canonicalize res * F::ONE } - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Hexf; - - fn spec_test() { - let cases = [ - (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), - (F::ZERO, F::ONE, F::ZERO), - (F::ONE, F::ZERO, F::ZERO), - (F::ZERO, F::NEG_ONE, F::NEG_ONE), - (F::NEG_ONE, F::ZERO, F::NEG_ONE), - (F::INFINITY, F::ZERO, F::ZERO), - (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), - (F::NAN, F::ZERO, F::ZERO), - (F::ZERO, F::NAN, F::ZERO), - (F::NAN, F::NAN, F::NAN), - (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), - (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), - ]; - - for (x, y, res) in cases { - let val = fminimum_num(x, y); - assert_biteq!(val, res, "fminimum_num({}, {})", Hexf(x), Hexf(y)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - spec_test::(); - } - - #[test] - fn spec_tests_f32() { - spec_test::(); - } - - #[test] - fn spec_tests_f64() { - spec_test::(); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - spec_test::(); - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/scalbn.rs b/library/compiler-builtins/libm/src/math/generic/scalbn.rs index aaa243933d45a..b2696e5cc9f5d 100644 --- a/library/compiler-builtins/libm/src/math/generic/scalbn.rs +++ b/library/compiler-builtins/libm/src/math/generic/scalbn.rs @@ -118,68 +118,3 @@ where let scale = F::from_parts(false, (F::EXP_BIAS as i32 + n) as u32, zero); x * scale } - -#[cfg(test)] -mod tests { - use super::*; - - // Tests against N3220 - fn spec_test() - where - u32: CastInto, - F::Int: CastFrom, - F::Int: CastFrom, - { - // `scalbn(±0, n)` returns `±0`. - assert_biteq!(scalbn(F::NEG_ZERO, 10), F::NEG_ZERO); - assert_biteq!(scalbn(F::NEG_ZERO, 0), F::NEG_ZERO); - assert_biteq!(scalbn(F::NEG_ZERO, -10), F::NEG_ZERO); - assert_biteq!(scalbn(F::ZERO, 10), F::ZERO); - assert_biteq!(scalbn(F::ZERO, 0), F::ZERO); - assert_biteq!(scalbn(F::ZERO, -10), F::ZERO); - - // `scalbn(x, 0)` returns `x`. - assert_biteq!(scalbn(F::MIN, 0), F::MIN); - assert_biteq!(scalbn(F::MAX, 0), F::MAX); - assert_biteq!(scalbn(F::INFINITY, 0), F::INFINITY); - assert_biteq!(scalbn(F::NEG_INFINITY, 0), F::NEG_INFINITY); - assert_biteq!(scalbn(F::ZERO, 0), F::ZERO); - assert_biteq!(scalbn(F::NEG_ZERO, 0), F::NEG_ZERO); - - // `scalbn(±∞, n)` returns `±∞`. - assert_biteq!(scalbn(F::INFINITY, 10), F::INFINITY); - assert_biteq!(scalbn(F::INFINITY, -10), F::INFINITY); - assert_biteq!(scalbn(F::NEG_INFINITY, 10), F::NEG_INFINITY); - assert_biteq!(scalbn(F::NEG_INFINITY, -10), F::NEG_INFINITY); - - // NaN should remain NaNs. - assert!(scalbn(F::NAN, 10).is_nan()); - assert!(scalbn(F::NAN, 0).is_nan()); - assert!(scalbn(F::NAN, -10).is_nan()); - assert!(scalbn(-F::NAN, 10).is_nan()); - assert!(scalbn(-F::NAN, 0).is_nan()); - assert!(scalbn(-F::NAN, -10).is_nan()); - } - - #[test] - #[cfg(f16_enabled)] - fn spec_test_f16() { - spec_test::(); - } - - #[test] - fn spec_test_f32() { - spec_test::(); - } - - #[test] - fn spec_test_f64() { - spec_test::(); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_test_f128() { - spec_test::(); - } -} diff --git a/library/compiler-builtins/libm/src/math/ldexp.rs b/library/compiler-builtins/libm/src/math/ldexp.rs index e46242e55b254..24899ba306af2 100644 --- a/library/compiler-builtins/libm/src/math/ldexp.rs +++ b/library/compiler-builtins/libm/src/math/ldexp.rs @@ -1,4 +1,21 @@ +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf16(x: f16, n: i32) -> f16 { + super::scalbnf16(x, n) +} + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf(x: f32, n: i32) -> f32 { + super::scalbnf(x, n) +} + #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ldexp(x: f64, n: i32) -> f64 { super::scalbn(x, n) } + +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf128(x: f128, n: i32) -> f128 { + super::scalbnf128(x, n) +} diff --git a/library/compiler-builtins/libm/src/math/ldexpf.rs b/library/compiler-builtins/libm/src/math/ldexpf.rs deleted file mode 100644 index 95b27fc49d28e..0000000000000 --- a/library/compiler-builtins/libm/src/math/ldexpf.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexpf(x: f32, n: i32) -> f32 { - super::scalbnf(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/ldexpf128.rs b/library/compiler-builtins/libm/src/math/ldexpf128.rs deleted file mode 100644 index b35277d15fbae..0000000000000 --- a/library/compiler-builtins/libm/src/math/ldexpf128.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexpf128(x: f128, n: i32) -> f128 { - super::scalbnf128(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/ldexpf16.rs b/library/compiler-builtins/libm/src/math/ldexpf16.rs deleted file mode 100644 index 8de6cffd69987..0000000000000 --- a/library/compiler-builtins/libm/src/math/ldexpf16.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexpf16(x: f16, n: i32) -> f16 { - super::scalbnf16(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 5fc8fa0b3cd02..023cf67a30615 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -140,9 +140,7 @@ mod atanhf; mod cbrt; mod cbrtf; mod ceil; -mod ceilf; mod copysign; -mod copysignf; mod cos; mod cosf; mod cosh; @@ -158,11 +156,8 @@ mod expf; mod expm1; mod expm1f; mod fabs; -mod fabsf; mod fdim; -mod fdimf; mod floor; -mod floorf; mod fma; mod fma_wide; mod fmin_fmax; @@ -183,7 +178,6 @@ mod j1f; mod jn; mod jnf; mod ldexp; -mod ldexpf; mod lgamma; mod lgamma_r; mod lgammaf; @@ -209,9 +203,7 @@ mod remquof; mod rint; mod round; mod roundeven; -mod roundf; mod scalbn; -mod scalbnf; mod sin; mod sincos; mod sincosf; @@ -219,7 +211,6 @@ mod sinf; mod sinh; mod sinhf; mod sqrt; -mod sqrtf; mod tan; mod tanf; mod tanh; @@ -227,7 +218,6 @@ mod tanhf; mod tgamma; mod tgammaf; mod trunc; -mod truncf; // Use separated imports instead of {}-grouped imports for easier merging. pub use self::acos::acos; @@ -246,10 +236,8 @@ pub use self::atanh::atanh; pub use self::atanhf::atanhf; pub use self::cbrt::cbrt; pub use self::cbrtf::cbrtf; -pub use self::ceil::ceil; -pub use self::ceilf::ceilf; -pub use self::copysign::copysign; -pub use self::copysignf::copysignf; +pub use self::ceil::{ceil, ceilf}; +pub use self::copysign::{copysign, copysignf}; pub use self::cos::cos; pub use self::cosf::cosf; pub use self::cosh::cosh; @@ -264,12 +252,9 @@ pub use self::exp10f::exp10f; pub use self::expf::expf; pub use self::expm1::expm1; pub use self::expm1f::expm1f; -pub use self::fabs::fabs; -pub use self::fabsf::fabsf; -pub use self::fdim::fdim; -pub use self::fdimf::fdimf; -pub use self::floor::floor; -pub use self::floorf::floorf; +pub use self::fabs::{fabs, fabsf}; +pub use self::fdim::{fdim, fdimf}; +pub use self::floor::{floor, floorf}; pub use self::fma::fma; pub use self::fma_wide::fmaf; pub use self::fmin_fmax::{fmax, fmaxf, fmin, fminf}; @@ -289,8 +274,7 @@ pub use self::j1::{j1, y1}; pub use self::j1f::{j1f, y1f}; pub use self::jn::{jn, yn}; pub use self::jnf::{jnf, ynf}; -pub use self::ldexp::ldexp; -pub use self::ldexpf::ldexpf; +pub use self::ldexp::{ldexp, ldexpf}; pub use self::lgamma::lgamma; pub use self::lgamma_r::lgamma_r; pub use self::lgammaf::lgammaf; @@ -314,61 +298,47 @@ pub use self::remainderf::remainderf; pub use self::remquo::remquo; pub use self::remquof::remquof; pub use self::rint::{rint, rintf}; -pub use self::round::round; +pub use self::round::{round, roundf}; pub use self::roundeven::{roundeven, roundevenf}; -pub use self::roundf::roundf; -pub use self::scalbn::scalbn; -pub use self::scalbnf::scalbnf; +pub use self::scalbn::{scalbn, scalbnf}; pub use self::sin::sin; pub use self::sincos::sincos; pub use self::sincosf::sincosf; pub use self::sinf::sinf; pub use self::sinh::sinh; pub use self::sinhf::sinhf; -pub use self::sqrt::sqrt; -pub use self::sqrtf::sqrtf; +pub use self::sqrt::{sqrt, sqrtf}; pub use self::tan::tan; pub use self::tanf::tanf; pub use self::tanh::tanh; pub use self::tanhf::tanhf; pub use self::tgamma::tgamma; pub use self::tgammaf::tgammaf; -pub use self::trunc::trunc; -pub use self::truncf::truncf; +pub use self::trunc::{trunc, truncf}; cfg_if! { if #[cfg(f16_enabled)] { // verify-sorted-start - mod ceilf16; - mod copysignf16; - mod fabsf16; - mod fdimf16; - mod floorf16; mod fmodf16; - mod ldexpf16; - mod roundf16; - mod scalbnf16; - mod sqrtf16; - mod truncf16; // verify-sorted-end // verify-sorted-start - pub use self::ceilf16::ceilf16; - pub use self::copysignf16::copysignf16; - pub use self::fabsf16::fabsf16; - pub use self::fdimf16::fdimf16; - pub use self::floorf16::floorf16; + pub use self::ceil::ceilf16; + pub use self::copysign::copysignf16; + pub use self::fabs::fabsf16; + pub use self::fdim::fdimf16; + pub use self::floor::floorf16; pub use self::fmin_fmax::{fmaxf16, fminf16}; pub use self::fminimum_fmaximum::{fmaximumf16, fminimumf16}; pub use self::fminimum_fmaximum_num::{fmaximum_numf16, fminimum_numf16}; pub use self::fmodf16::fmodf16; - pub use self::ldexpf16::ldexpf16; + pub use self::ldexp::ldexpf16; pub use self::rint::rintf16; + pub use self::round::roundf16; pub use self::roundeven::roundevenf16; - pub use self::roundf16::roundf16; - pub use self::scalbnf16::scalbnf16; - pub use self::sqrtf16::sqrtf16; - pub use self::truncf16::truncf16; + pub use self::scalbn::scalbnf16; + pub use self::sqrt::sqrtf16; + pub use self::trunc::truncf16; // verify-sorted-end #[allow(unused_imports)] @@ -379,37 +349,27 @@ cfg_if! { cfg_if! { if #[cfg(f128_enabled)] { // verify-sorted-start - mod ceilf128; - mod copysignf128; - mod fabsf128; - mod fdimf128; - mod floorf128; mod fmodf128; - mod ldexpf128; - mod roundf128; - mod scalbnf128; - mod sqrtf128; - mod truncf128; // verify-sorted-end // verify-sorted-start - pub use self::ceilf128::ceilf128; - pub use self::copysignf128::copysignf128; - pub use self::fabsf128::fabsf128; - pub use self::fdimf128::fdimf128; - pub use self::floorf128::floorf128; + pub use self::ceil::ceilf128; + pub use self::copysign::copysignf128; + pub use self::fabs::fabsf128; + pub use self::fdim::fdimf128; + pub use self::floor::floorf128; pub use self::fma::fmaf128; pub use self::fmin_fmax::{fmaxf128, fminf128}; pub use self::fminimum_fmaximum::{fmaximumf128, fminimumf128}; pub use self::fminimum_fmaximum_num::{fmaximum_numf128, fminimum_numf128}; pub use self::fmodf128::fmodf128; - pub use self::ldexpf128::ldexpf128; + pub use self::ldexp::ldexpf128; pub use self::rint::rintf128; + pub use self::round::roundf128; pub use self::roundeven::roundevenf128; - pub use self::roundf128::roundf128; - pub use self::scalbnf128::scalbnf128; - pub use self::sqrtf128::sqrtf128; - pub use self::truncf128::truncf128; + pub use self::scalbn::scalbnf128; + pub use self::sqrt::sqrtf128; + pub use self::trunc::truncf128; // verify-sorted-end } } diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs index 36e0eb1f2ed49..6cd091cd73cdc 100644 --- a/library/compiler-builtins/libm/src/math/round.rs +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -1,5 +1,25 @@ +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf16(x: f16) -> f16 { + super::generic::round(x) +} + +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf(x: f32) -> f32 { + super::generic::round(x) +} + /// Round `x` to the nearest integer, breaking ties away from zero. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn round(x: f64) -> f64 { super::generic::round(x) } + +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf128(x: f128) -> f128 { + super::generic::round(x) +} diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs deleted file mode 100644 index b5d7c9d693e71..0000000000000 --- a/library/compiler-builtins/libm/src/math/roundf.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Round `x` to the nearest integer, breaking ties away from zero. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundf(x: f32) -> f32 { - super::generic::round(x) -} diff --git a/library/compiler-builtins/libm/src/math/roundf128.rs b/library/compiler-builtins/libm/src/math/roundf128.rs deleted file mode 100644 index fc3164929fe4f..0000000000000 --- a/library/compiler-builtins/libm/src/math/roundf128.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Round `x` to the nearest integer, breaking ties away from zero. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundf128(x: f128) -> f128 { - super::generic::round(x) -} diff --git a/library/compiler-builtins/libm/src/math/roundf16.rs b/library/compiler-builtins/libm/src/math/roundf16.rs deleted file mode 100644 index 8b356eaabeecd..0000000000000 --- a/library/compiler-builtins/libm/src/math/roundf16.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Round `x` to the nearest integer, breaking ties away from zero. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundf16(x: f16) -> f16 { - super::generic::round(x) -} diff --git a/library/compiler-builtins/libm/src/math/scalbn.rs b/library/compiler-builtins/libm/src/math/scalbn.rs index f809dad518a1e..ed73c3f94f000 100644 --- a/library/compiler-builtins/libm/src/math/scalbn.rs +++ b/library/compiler-builtins/libm/src/math/scalbn.rs @@ -1,4 +1,87 @@ +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf16(x: f16, n: i32) -> f16 { + super::generic::scalbn(x, n) +} + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf(x: f32, n: i32) -> f32 { + super::generic::scalbn(x, n) +} + #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn scalbn(x: f64, n: i32) -> f64 { super::generic::scalbn(x, n) } + +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf128(x: f128, n: i32) -> f128 { + super::generic::scalbn(x, n) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{CastFrom, CastInto, Float}; + + // Tests against N3220 + fn spec_test(f: impl Fn(F, i32) -> F) + where + u32: CastInto, + F::Int: CastFrom, + F::Int: CastFrom, + { + // `scalbn(±0, n)` returns `±0`. + assert_biteq!(f(F::NEG_ZERO, 10), F::NEG_ZERO); + assert_biteq!(f(F::NEG_ZERO, 0), F::NEG_ZERO); + assert_biteq!(f(F::NEG_ZERO, -10), F::NEG_ZERO); + assert_biteq!(f(F::ZERO, 10), F::ZERO); + assert_biteq!(f(F::ZERO, 0), F::ZERO); + assert_biteq!(f(F::ZERO, -10), F::ZERO); + + // `scalbn(x, 0)` returns `x`. + assert_biteq!(f(F::MIN, 0), F::MIN); + assert_biteq!(f(F::MAX, 0), F::MAX); + assert_biteq!(f(F::INFINITY, 0), F::INFINITY); + assert_biteq!(f(F::NEG_INFINITY, 0), F::NEG_INFINITY); + assert_biteq!(f(F::ZERO, 0), F::ZERO); + assert_biteq!(f(F::NEG_ZERO, 0), F::NEG_ZERO); + + // `scalbn(±∞, n)` returns `±∞`. + assert_biteq!(f(F::INFINITY, 10), F::INFINITY); + assert_biteq!(f(F::INFINITY, -10), F::INFINITY); + assert_biteq!(f(F::NEG_INFINITY, 10), F::NEG_INFINITY); + assert_biteq!(f(F::NEG_INFINITY, -10), F::NEG_INFINITY); + + // NaN should remain NaNs. + assert!(f(F::NAN, 10).is_nan()); + assert!(f(F::NAN, 0).is_nan()); + assert!(f(F::NAN, -10).is_nan()); + assert!(f(-F::NAN, 10).is_nan()); + assert!(f(-F::NAN, 0).is_nan()); + assert!(f(-F::NAN, -10).is_nan()); + } + + #[test] + #[cfg(f16_enabled)] + fn spec_test_f16() { + spec_test::(scalbnf16); + } + + #[test] + fn spec_test_f32() { + spec_test::(scalbnf); + } + + #[test] + fn spec_test_f64() { + spec_test::(scalbn); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_test_f128() { + spec_test::(scalbnf128); + } +} diff --git a/library/compiler-builtins/libm/src/math/scalbnf.rs b/library/compiler-builtins/libm/src/math/scalbnf.rs deleted file mode 100644 index 57e7ba76f60b5..0000000000000 --- a/library/compiler-builtins/libm/src/math/scalbnf.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf(x: f32, n: i32) -> f32 { - super::generic::scalbn(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/scalbnf128.rs b/library/compiler-builtins/libm/src/math/scalbnf128.rs deleted file mode 100644 index c1d2b48558568..0000000000000 --- a/library/compiler-builtins/libm/src/math/scalbnf128.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf128(x: f128, n: i32) -> f128 { - super::generic::scalbn(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/scalbnf16.rs b/library/compiler-builtins/libm/src/math/scalbnf16.rs deleted file mode 100644 index 2209e1a179566..0000000000000 --- a/library/compiler-builtins/libm/src/math/scalbnf16.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf16(x: f16, n: i32) -> f16 { - super::generic::scalbn(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 2bfc42bcfede9..76bc240cf01cb 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -1,3 +1,32 @@ +/// The square root of `x` (f16). +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf16(x: f16) -> f16 { + select_implementation! { + name: sqrtf16, + use_arch: all(target_arch = "aarch64", target_feature = "fp16"), + args: x, + } + + return super::generic::sqrt(x); +} + +/// The square root of `x` (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf(x: f32) -> f32 { + select_implementation! { + name: sqrtf, + use_arch: any( + all(target_arch = "aarch64", target_feature = "neon"), + all(target_arch = "wasm32", intrinsics_enabled), + target_feature = "sse2" + ), + args: x, + } + + super::generic::sqrt(x) +} + /// The square root of `x` (f64). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn sqrt(x: f64) -> f64 { @@ -13,3 +42,10 @@ pub fn sqrt(x: f64) -> f64 { super::generic::sqrt(x) } + +/// The square root of `x` (f128). +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf128(x: f128) -> f128 { + return super::generic::sqrt(x); +} diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs deleted file mode 100644 index c28a705e378e6..0000000000000 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ /dev/null @@ -1,15 +0,0 @@ -/// The square root of `x` (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrtf(x: f32) -> f32 { - select_implementation! { - name: sqrtf, - use_arch: any( - all(target_arch = "aarch64", target_feature = "neon"), - all(target_arch = "wasm32", intrinsics_enabled), - target_feature = "sse2" - ), - args: x, - } - - super::generic::sqrt(x) -} diff --git a/library/compiler-builtins/libm/src/math/sqrtf128.rs b/library/compiler-builtins/libm/src/math/sqrtf128.rs deleted file mode 100644 index eaef6ae0c1c85..0000000000000 --- a/library/compiler-builtins/libm/src/math/sqrtf128.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// The square root of `x` (f128). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrtf128(x: f128) -> f128 { - return super::generic::sqrt(x); -} diff --git a/library/compiler-builtins/libm/src/math/sqrtf16.rs b/library/compiler-builtins/libm/src/math/sqrtf16.rs deleted file mode 100644 index 7bedb7f8bbb6b..0000000000000 --- a/library/compiler-builtins/libm/src/math/sqrtf16.rs +++ /dev/null @@ -1,11 +0,0 @@ -/// The square root of `x` (f16). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrtf16(x: f16) -> f16 { - select_implementation! { - name: sqrtf16, - use_arch: all(target_arch = "aarch64", target_feature = "fp16"), - args: x, - } - - return super::generic::sqrt(x); -} diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs index 2cc8aaa7e8f98..fa50d55e13687 100644 --- a/library/compiler-builtins/libm/src/math/trunc.rs +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -1,3 +1,26 @@ +/// 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(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf16(x: f16) -> f16 { + super::generic::trunc(x) +} + +/// Rounds the number toward 0 to the closest integral value (f32). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf(x: f32) -> f32 { + select_implementation! { + name: truncf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + super::generic::trunc(x) +} + /// Rounds the number toward 0 to the closest integral value (f64). /// /// This effectively removes the decimal part of the number, leaving the integral part. @@ -11,3 +34,20 @@ pub fn trunc(x: f64) -> f64 { super::generic::trunc(x) } + +/// Rounds the number toward 0 to the closest integral value (f128). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf128(x: f128) -> f128 { + super::generic::trunc(x) +} + +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::truncf(1.1), 1.0); + } +} diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs deleted file mode 100644 index 14533a2670632..0000000000000 --- a/library/compiler-builtins/libm/src/math/truncf.rs +++ /dev/null @@ -1,23 +0,0 @@ -/// Rounds the number toward 0 to the closest integral value (f32). -/// -/// This effectively removes the decimal part of the number, leaving the integral part. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn truncf(x: f32) -> f32 { - select_implementation! { - name: truncf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - super::generic::trunc(x) -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - #[test] - fn sanity_check() { - assert_eq!(super::truncf(1.1), 1.0); - } -} diff --git a/library/compiler-builtins/libm/src/math/truncf128.rs b/library/compiler-builtins/libm/src/math/truncf128.rs deleted file mode 100644 index 9dccc0d0e9d7f..0000000000000 --- a/library/compiler-builtins/libm/src/math/truncf128.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Rounds the number toward 0 to the closest integral value (f128). -/// -/// This effectively removes the decimal part of the number, leaving the integral part. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn truncf128(x: f128) -> f128 { - super::generic::trunc(x) -} diff --git a/library/compiler-builtins/libm/src/math/truncf16.rs b/library/compiler-builtins/libm/src/math/truncf16.rs deleted file mode 100644 index d7c3d225cf9b8..0000000000000 --- a/library/compiler-builtins/libm/src/math/truncf16.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// 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_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn truncf16(x: f16) -> f16 { - super::generic::trunc(x) -} From 014c3e4ccbb8afc3740acf5658c07e5783e3d848 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 03:22:13 +0000 Subject: [PATCH 1811/4206] ci: Cancel jobs when a new push happens Jobs should just cancel automatically, it isn't ideal that extensive jobs can continue running for multiple hours after code has been updated. Use a solution from [1] to do this. [1]: https://stackoverflow.com/a/72408109/5380651 --- library/compiler-builtins/libm/.github/workflows/main.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index e86f936f74fa8..93c56c9d40f3e 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -5,6 +5,11 @@ on: - master pull_request: +concurrency: + # Make sure that new pushes cancel running jobs + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + env: CARGO_TERM_COLOR: always RUSTDOCFLAGS: -Dwarnings From cad0d6f1875031a3f8c53815c38d3042b20f2f74 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 01:58:05 +0000 Subject: [PATCH 1812/4206] ci: Allow skipping extensive tests with `ci: skip-extensive` Sometimes we do refactoring that moves things around and triggers an extensive test, even though the implementation didn't change. There isn't any need to run full extensive CI in these cases, so add a way to skip it from the PR message. --- .../libm/.github/workflows/main.yaml | 15 ++-- library/compiler-builtins/libm/ci/ci-util.py | 88 +++++++++++++------ 2 files changed, 73 insertions(+), 30 deletions(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index 93c56c9d40f3e..2b2891ab2261e 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -239,6 +239,9 @@ jobs: name: Calculate job matrix runs-on: ubuntu-24.04 timeout-minutes: 10 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} outputs: matrix: ${{ steps.script.outputs.matrix }} steps: @@ -267,7 +270,7 @@ jobs: # this is not currently possible https://github.com/actions/runner/issues/1985. include: ${{ fromJSON(needs.calculate_extensive_matrix.outputs.matrix).matrix }} env: - CHANGED: ${{ matrix.changed }} + TO_TEST: ${{ matrix.to_test }} steps: - uses: actions/checkout@v4 with: @@ -279,16 +282,18 @@ jobs: - uses: Swatinem/rust-cache@v2 - name: Run extensive tests run: | - echo "Changed: '$CHANGED'" - if [ -z "$CHANGED" ]; then + echo "Tests to run: '$TO_TEST'" + if [ -z "$TO_TEST" ]; then echo "No tests to run, exiting." exit fi + set -x + # Run the non-extensive tests first to catch any easy failures - cargo t --profile release-checked -- "$CHANGED" + cargo t --profile release-checked -- "$TO_TEST" - LIBM_EXTENSIVE_TESTS="$CHANGED" cargo t \ + LIBM_EXTENSIVE_TESTS="$TO_TEST" cargo t \ --features build-mpfr,unstable,force-soft-floats \ --profile release-checked \ -- extensive diff --git a/library/compiler-builtins/libm/ci/ci-util.py b/library/compiler-builtins/libm/ci/ci-util.py index 7464fd42595d6..8b07dde31727b 100755 --- a/library/compiler-builtins/libm/ci/ci-util.py +++ b/library/compiler-builtins/libm/ci/ci-util.py @@ -6,6 +6,7 @@ """ import json +import os import subprocess as sp import sys from dataclasses import dataclass @@ -13,7 +14,7 @@ from inspect import cleandoc from os import getenv from pathlib import Path -from typing import TypedDict +from typing import TypedDict, Self USAGE = cleandoc( """ @@ -51,6 +52,8 @@ ARTIFACT_GLOB = "baseline-icount*" # Place this in a PR body to skip regression checks (must be at the start of a line). REGRESSION_DIRECTIVE = "ci: allow-regressions" +# Place this in a PR body to skip extensive tests +SKIP_EXTENSIVE_DIRECTIVE = "ci: skip-extensive" # Don't run exhaustive tests if these files change, even if they contaiin a function # definition. @@ -68,6 +71,39 @@ def eprint(*args, **kwargs): print(*args, file=sys.stderr, **kwargs) +@dataclass +class PrInfo: + """GitHub response for PR query""" + + body: str + commits: list[str] + created_at: str + number: int + + @classmethod + def load(cls, pr_number: int | str) -> Self: + """For a given PR number, query the body and commit list""" + pr_info = sp.check_output( + [ + "gh", + "pr", + "view", + str(pr_number), + "--json=number,commits,body,createdAt", + # Flatten the commit list to only hashes, change a key to snake naming + "--jq=.commits |= map(.oid) | .created_at = .createdAt | del(.createdAt)", + ], + text=True, + ) + eprint("PR info:", json.dumps(pr_info, indent=4)) + return cls(**json.loads(pr_info)) + + def contains_directive(self, directive: str) -> bool: + """Return true if the provided directive is on a line in the PR body""" + lines = self.body.splitlines() + return any(line.startswith(directive) for line in lines) + + class FunctionDef(TypedDict): """Type for an entry in `function-definitions.json`""" @@ -149,7 +185,7 @@ def changed_routines(self) -> dict[str, list[str]]: eprint(f"changed files for {name}: {changed}") routines.add(name) - ret = {} + ret: dict[str, list[str]] = {} for r in sorted(routines): ret.setdefault(self.defs[r]["type"], []).append(r) @@ -159,13 +195,27 @@ def make_workflow_output(self) -> str: """Create a JSON object a list items for each type's changed files, if any did change, and the routines that were affected by the change. """ + + pr_number = os.environ.get("PR_NUMBER") + skip_tests = False + + if pr_number is not None: + pr = PrInfo.load(pr_number) + skip_tests = pr.contains_directive(SKIP_EXTENSIVE_DIRECTIVE) + + if skip_tests: + eprint("Skipping all extensive tests") + changed = self.changed_routines() ret = [] for ty in TYPES: ty_changed = changed.get(ty, []) + changed_str = ",".join(ty_changed) + item = { "ty": ty, - "changed": ",".join(ty_changed), + "changed": changed_str, + "to_test": "" if skip_tests else changed_str, } ret.append(item) output = json.dumps({"matrix": ret}, separators=(",", ":")) @@ -266,13 +316,13 @@ def check_iai_regressions(args: list[str]): found. """ - iai_home = "iai-home" - pr_number = False + iai_home_str = "iai-home" + pr_number = None while len(args) > 0: match args: case ["--home", home, *rest]: - iai_home = home + iai_home_str = home args = rest case ["--allow-pr-override", pr_num, *rest]: pr_number = pr_num @@ -281,10 +331,10 @@ def check_iai_regressions(args: list[str]): eprint(USAGE) exit(1) - iai_home = Path(iai_home) + iai_home = Path(iai_home_str) found_summaries = False - regressions = [] + regressions: list[dict] = [] for summary_path in iglob("**/summary.json", root_dir=iai_home, recursive=True): found_summaries = True with open(iai_home / summary_path, "r") as f: @@ -292,7 +342,9 @@ def check_iai_regressions(args: list[str]): summary_regs = [] run = summary["callgrind_summary"]["callgrind_run"] - name_entry = {"name": f"{summary["function_name"]}.{summary["id"]}"} + fname = summary["function_name"] + id = summary["id"] + name_entry = {"name": f"{fname}.{id}"} for segment in run["segments"]: summary_regs.extend(segment["regressions"]) @@ -312,22 +364,8 @@ def check_iai_regressions(args: list[str]): eprint("Found regressions:", json.dumps(regressions, indent=4)) if pr_number is not None: - pr_info = sp.check_output( - [ - "gh", - "pr", - "view", - str(pr_number), - "--json=number,commits,body,createdAt", - "--jq=.commits |= map(.oid)", - ], - text=True, - ) - pr = json.loads(pr_info) - eprint("PR info:", json.dumps(pr, indent=4)) - - lines = pr["body"].splitlines() - if any(line.startswith(REGRESSION_DIRECTIVE) for line in lines): + pr = PrInfo.load(pr_number) + if pr.contains_directive(REGRESSION_DIRECTIVE): eprint("PR allows regressions, returning") return From a0e5a7a6360f78826757f7bb5e48350fbb3ff353 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 02:20:21 +0000 Subject: [PATCH 1813/4206] ci: Require `ci: allow-many-extensive` if a threshold is exceeded Error out when too many extensive tests would be run unless `ci: allow-many-extensive` is in the PR description. This allows us to set a much higher CI timeout with less risk that a 4+ hour job gets started by accident. --- library/compiler-builtins/libm/ci/ci-util.py | 28 +++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm/ci/ci-util.py b/library/compiler-builtins/libm/ci/ci-util.py index 8b07dde31727b..aae791d0f16a1 100755 --- a/library/compiler-builtins/libm/ci/ci-util.py +++ b/library/compiler-builtins/libm/ci/ci-util.py @@ -54,6 +54,11 @@ REGRESSION_DIRECTIVE = "ci: allow-regressions" # Place this in a PR body to skip extensive tests SKIP_EXTENSIVE_DIRECTIVE = "ci: skip-extensive" +# Place this in a PR body to allow running a large number of extensive tests. If not +# set, this script will error out if a threshold is exceeded in order to avoid +# accidentally spending huge amounts of CI time. +ALLOW_MANY_EXTENSIVE_DIRECTIVE = "ci: allow-many-extensive" +MANY_EXTENSIVE_THRESHOLD = 20 # Don't run exhaustive tests if these files change, even if they contaiin a function # definition. @@ -198,28 +203,45 @@ def make_workflow_output(self) -> str: pr_number = os.environ.get("PR_NUMBER") skip_tests = False + error_on_many_tests = False if pr_number is not None: pr = PrInfo.load(pr_number) skip_tests = pr.contains_directive(SKIP_EXTENSIVE_DIRECTIVE) + error_on_many_tests = not pr.contains_directive( + ALLOW_MANY_EXTENSIVE_DIRECTIVE + ) if skip_tests: eprint("Skipping all extensive tests") changed = self.changed_routines() ret = [] + total_to_test = 0 + for ty in TYPES: ty_changed = changed.get(ty, []) - changed_str = ",".join(ty_changed) + ty_to_test = [] if skip_tests else ty_changed + total_to_test += len(ty_to_test) item = { "ty": ty, - "changed": changed_str, - "to_test": "" if skip_tests else changed_str, + "changed": ",".join(ty_changed), + "to_test": ",".join(ty_to_test), } + ret.append(item) output = json.dumps({"matrix": ret}, separators=(",", ":")) eprint(f"output: {output}") + eprint(f"total extensive tests: {total_to_test}") + + if error_on_many_tests and total_to_test > MANY_EXTENSIVE_THRESHOLD: + eprint( + f"More than {MANY_EXTENSIVE_THRESHOLD} tests would be run; add" + f" `{ALLOW_MANY_EXTENSIVE_DIRECTIVE}` to the PR body if this is intentional" + ) + exit(1) + return output From 1cb17773f66493364d07ae13fd8e0d50ca44cfe0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 01:24:38 +0000 Subject: [PATCH 1814/4206] ci: Increase the timeout for extensive tests The reorganization PR has caused this to fail once before because every file shows up as changed. Increase the timeout so this doesn't happen. We now cancel the job if too many extensive tests are run unless `ci: allow-many-extensive` is in the PR description, so this helps prevent the limit being hit by accident. --- library/compiler-builtins/libm/.github/workflows/main.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index 2b2891ab2261e..c925e63aa59b0 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -261,7 +261,7 @@ jobs: - clippy - calculate_extensive_matrix runs-on: ubuntu-24.04 - timeout-minutes: 180 + timeout-minutes: 240 # 4 hours strategy: matrix: # Use the output from `calculate_extensive_matrix` to calculate the matrix From 2585a57dc742265f8400eaafb91a6990b6c7dc07 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 06:15:10 +0000 Subject: [PATCH 1815/4206] Ensure configure.rs changes trigger rebuilds --- .../libm/crates/compiler-builtins-smoke-test/build.rs | 1 + library/compiler-builtins/libm/crates/libm-test/build.rs | 1 + library/compiler-builtins/libm/crates/util/build.rs | 1 + 3 files changed, 3 insertions(+) diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs index 401b7e1eb3aac..4ee5ab585d502 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs @@ -2,6 +2,7 @@ mod configure; fn main() { + println!("cargo:rerun-if-changed=../../configure.rs"); let cfg = configure::Config::from_env(); configure::emit_libm_config(&cfg); } diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs index 134fb11ceeb6c..d2d0df9cbe925 100644 --- a/library/compiler-builtins/libm/crates/libm-test/build.rs +++ b/library/compiler-builtins/libm/crates/libm-test/build.rs @@ -3,6 +3,7 @@ mod configure; use configure::Config; fn main() { + println!("cargo:rerun-if-changed=../../configure.rs"); let cfg = Config::from_env(); configure::emit_test_config(&cfg); } diff --git a/library/compiler-builtins/libm/crates/util/build.rs b/library/compiler-builtins/libm/crates/util/build.rs index 0745ef3dd6f3a..b6cceb5f11b71 100644 --- a/library/compiler-builtins/libm/crates/util/build.rs +++ b/library/compiler-builtins/libm/crates/util/build.rs @@ -4,6 +4,7 @@ mod configure; fn main() { + println!("cargo:rerun-if-changed=../../configure.rs"); let cfg = configure::Config::from_env(); configure::emit_libm_config(&cfg); } From 2db05de8fdf0d8b92df083a088ebde412bf6d75c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 06:43:19 +0000 Subject: [PATCH 1816/4206] ci: Account for `PR_NUMBER` being set to an empty string This is the case for CI after merge that is no longer associated with a pull request. --- library/compiler-builtins/libm/ci/ci-util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/ci/ci-util.py b/library/compiler-builtins/libm/ci/ci-util.py index aae791d0f16a1..7468fd690cbbb 100755 --- a/library/compiler-builtins/libm/ci/ci-util.py +++ b/library/compiler-builtins/libm/ci/ci-util.py @@ -205,7 +205,7 @@ def make_workflow_output(self) -> str: skip_tests = False error_on_many_tests = False - if pr_number is not None: + if pr_number is not None and len(pr_number) > 0: pr = PrInfo.load(pr_number) skip_tests = pr.contains_directive(SKIP_EXTENSIVE_DIRECTIVE) error_on_many_tests = not pr.contains_directive( From 8da1290f04eec03298b4a905091a4ad4f7b1c4eb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 07:05:13 +0000 Subject: [PATCH 1817/4206] Ensure all public functions are marked `no_panic` Fixes: https://github.com/rust-lang/libm/issues/201 --- library/compiler-builtins/libm/src/math/frexpf.rs | 1 + library/compiler-builtins/libm/src/math/j0.rs | 2 ++ library/compiler-builtins/libm/src/math/j0f.rs | 2 ++ library/compiler-builtins/libm/src/math/j1.rs | 2 ++ library/compiler-builtins/libm/src/math/j1f.rs | 2 ++ library/compiler-builtins/libm/src/math/jn.rs | 2 ++ library/compiler-builtins/libm/src/math/jnf.rs | 2 ++ library/compiler-builtins/libm/src/math/modf.rs | 1 + library/compiler-builtins/libm/src/math/modff.rs | 1 + 9 files changed, 15 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/frexpf.rs b/library/compiler-builtins/libm/src/math/frexpf.rs index 2919c0ab02279..0ec91c2d3507d 100644 --- a/library/compiler-builtins/libm/src/math/frexpf.rs +++ b/library/compiler-builtins/libm/src/math/frexpf.rs @@ -1,3 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn frexpf(x: f32) -> (f32, i32) { let mut y = x.to_bits(); let ee: i32 = ((y >> 23) & 0xff) as i32; diff --git a/library/compiler-builtins/libm/src/math/j0.rs b/library/compiler-builtins/libm/src/math/j0.rs index 5e5e839f81a5d..99d656f0d08aa 100644 --- a/library/compiler-builtins/libm/src/math/j0.rs +++ b/library/compiler-builtins/libm/src/math/j0.rs @@ -110,6 +110,7 @@ const S03: f64 = 5.13546550207318111446e-07; /* 0x3EA13B54, 0xCE84D5A9 */ const S04: f64 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ /// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn j0(mut x: f64) -> f64 { let z: f64; let r: f64; @@ -164,6 +165,7 @@ const V03: f64 = 2.59150851840457805467e-07; /* 0x3E91642D, 0x7FF202FD */ const V04: f64 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ /// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn y0(x: f64) -> f64 { let z: f64; let u: f64; diff --git a/library/compiler-builtins/libm/src/math/j0f.rs b/library/compiler-builtins/libm/src/math/j0f.rs index afb6ee9ba8bc2..25e5b325c8cc0 100644 --- a/library/compiler-builtins/libm/src/math/j0f.rs +++ b/library/compiler-builtins/libm/src/math/j0f.rs @@ -63,6 +63,7 @@ const S03: f32 = 5.1354652442e-07; /* 0x3509daa6 */ const S04: f32 = 1.1661400734e-09; /* 0x30a045e8 */ /// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn j0f(mut x: f32) -> f32 { let z: f32; let r: f32; @@ -109,6 +110,7 @@ const V03: f32 = 2.5915085189e-07; /* 0x348b216c */ const V04: f32 = 4.4111031494e-10; /* 0x2ff280c2 */ /// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn y0f(x: f32) -> f32 { let z: f32; let u: f32; diff --git a/library/compiler-builtins/libm/src/math/j1.rs b/library/compiler-builtins/libm/src/math/j1.rs index 578ae59d3ab69..9b604d9e46e00 100644 --- a/library/compiler-builtins/libm/src/math/j1.rs +++ b/library/compiler-builtins/libm/src/math/j1.rs @@ -114,6 +114,7 @@ const S04: f64 = 5.04636257076217042715e-09; /* 0x3E35AC88, 0xC97DFF2C */ const S05: f64 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ /// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn j1(x: f64) -> f64 { let mut z: f64; let r: f64; @@ -160,6 +161,7 @@ const V0: [f64; 5] = [ ]; /// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn y1(x: f64) -> f64 { let z: f64; let u: f64; diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs index 02a3efd2435fe..a47472401ee27 100644 --- a/library/compiler-builtins/libm/src/math/j1f.rs +++ b/library/compiler-builtins/libm/src/math/j1f.rs @@ -64,6 +64,7 @@ const S04: f32 = 5.0463624390e-09; /* 0x31ad6446 */ const S05: f32 = 1.2354227016e-11; /* 0x2d59567e */ /// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn j1f(x: f32) -> f32 { let mut z: f32; let r: f32; @@ -109,6 +110,7 @@ const V0: [f32; 5] = [ ]; /// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn y1f(x: f32) -> f32 { let z: f32; let u: f32; diff --git a/library/compiler-builtins/libm/src/math/jn.rs b/library/compiler-builtins/libm/src/math/jn.rs index d228781d12aa4..31f8d9c538290 100644 --- a/library/compiler-builtins/libm/src/math/jn.rs +++ b/library/compiler-builtins/libm/src/math/jn.rs @@ -39,6 +39,7 @@ use super::{cos, fabs, get_high_word, get_low_word, j0, j1, log, sin, sqrt, y0, const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ /// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn jn(n: i32, mut x: f64) -> f64 { let mut ix: u32; let lx: u32; @@ -248,6 +249,7 @@ pub fn jn(n: i32, mut x: f64) -> f64 { } /// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn yn(n: i32, x: f64) -> f64 { let mut ix: u32; let lx: u32; diff --git a/library/compiler-builtins/libm/src/math/jnf.rs b/library/compiler-builtins/libm/src/math/jnf.rs index 754f8f33b5af5..52cf7d8a8bdad 100644 --- a/library/compiler-builtins/libm/src/math/jnf.rs +++ b/library/compiler-builtins/libm/src/math/jnf.rs @@ -16,6 +16,7 @@ use super::{fabsf, j0f, j1f, logf, y0f, y1f}; /// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn jnf(n: i32, mut x: f32) -> f32 { let mut ix: u32; let mut nm1: i32; @@ -191,6 +192,7 @@ pub fn jnf(n: i32, mut x: f32) -> f32 { } /// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn ynf(n: i32, x: f32) -> f32 { let mut ix: u32; let mut ib: u32; diff --git a/library/compiler-builtins/libm/src/math/modf.rs b/library/compiler-builtins/libm/src/math/modf.rs index e29e80ccf5f39..6541862cdd98e 100644 --- a/library/compiler-builtins/libm/src/math/modf.rs +++ b/library/compiler-builtins/libm/src/math/modf.rs @@ -1,3 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn modf(x: f64) -> (f64, f64) { let rv2: f64; let mut u = x.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/modff.rs b/library/compiler-builtins/libm/src/math/modff.rs index fac60abaa55c1..90c6bca7d8da9 100644 --- a/library/compiler-builtins/libm/src/math/modff.rs +++ b/library/compiler-builtins/libm/src/math/modff.rs @@ -1,3 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn modff(x: f32) -> (f32, f32) { let rv2: f32; let mut u: u32 = x.to_bits(); From c8c87421a5ef753edc27066a571fd0afcc066a6d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 15 Apr 2025 14:42:32 +0000 Subject: [PATCH 1818/4206] Nicer formatting for verifier errors during define_function --- src/base.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/base.rs b/src/base.rs index 9d425a3b292a2..6b850a9a6e691 100644 --- a/src/base.rs +++ b/src/base.rs @@ -228,6 +228,18 @@ pub(crate) fn compile_fn( name = codegened_func.symbol_name )); } + Err(ModuleError::Compilation(CodegenError::Verifier(err))) => { + let early_dcx = rustc_session::EarlyDiagCtxt::new( + rustc_session::config::ErrorOutputType::default(), + ); + let _ = early_dcx.early_err(format!("{:?}", err)); + let pretty_error = cranelift_codegen::print_errors::pretty_verifier_error( + &context.func, + Some(Box::new(&clif_comments)), + err, + ); + early_dcx.early_fatal(format!("cranelift verify error:\n{}", pretty_error)); + } Err(err) => { panic!("Error while defining {name}: {err:?}", name = codegened_func.symbol_name); } From 49bfa1aaf5f7e68079e6ed9b0d23dacebf38bac9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 18 Apr 2025 10:30:37 +0000 Subject: [PATCH 1819/4206] Fix simd_insert_dyn and simd_extract_dyn intrinsics with non-pointer sized indices --- src/value_and_place.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/value_and_place.rs b/src/value_and_place.rs index 9fd71cd6f77f9..4874a4ad9e0db 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -309,6 +309,7 @@ impl<'tcx> CValue<'tcx> { match self.0 { CValueInner::ByVal(_) | CValueInner::ByValPair(_, _) => unreachable!(), CValueInner::ByRef(ptr, None) => { + let lane_idx = clif_intcast(fx, lane_idx, fx.pointer_type, false); let field_offset = fx.bcx.ins().imul_imm(lane_idx, lane_layout.size.bytes() as i64); let field_ptr = ptr.offset_value(fx, field_offset); CValue::by_ref(field_ptr, lane_layout) @@ -823,6 +824,7 @@ impl<'tcx> CPlace<'tcx> { CPlaceInner::Var(_, _) => unreachable!(), CPlaceInner::VarPair(_, _, _) => unreachable!(), CPlaceInner::Addr(ptr, None) => { + let lane_idx = clif_intcast(fx, lane_idx, fx.pointer_type, false); let field_offset = fx .bcx .ins() From 3cecf22e0c20853675aad5d3977cb3712729a1f6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 07:15:26 +0000 Subject: [PATCH 1820/4206] Combine the source files for `fmod` Since `fmod` is generic, there isn't any need to have the small wrappers in separate files. Most operations was done in [1] but `fmod` was omitted until now. [1]: https://github.com/rust-lang/libm/pull/537 --- .../libm/etc/function-definitions.json | 6 +++--- .../compiler-builtins/libm/src/math/fmod.rs | 20 +++++++++++++++++++ .../compiler-builtins/libm/src/math/fmodf.rs | 5 ----- .../libm/src/math/fmodf128.rs | 5 ----- .../libm/src/math/fmodf16.rs | 5 ----- .../compiler-builtins/libm/src/math/frexp.rs | 1 + .../compiler-builtins/libm/src/math/mod.rs | 16 +++------------ 7 files changed, 27 insertions(+), 31 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/fmodf.rs delete mode 100644 library/compiler-builtins/libm/src/math/fmodf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/fmodf16.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 801e74b22a57e..ead1f807fc92d 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -537,21 +537,21 @@ }, "fmodf": { "sources": [ - "src/math/fmodf.rs", + "src/math/fmod.rs", "src/math/generic/fmod.rs" ], "type": "f32" }, "fmodf128": { "sources": [ - "src/math/fmodf128.rs", + "src/math/fmod.rs", "src/math/generic/fmod.rs" ], "type": "f128" }, "fmodf16": { "sources": [ - "src/math/fmodf16.rs", + "src/math/fmod.rs", "src/math/generic/fmod.rs" ], "type": "f16" diff --git a/library/compiler-builtins/libm/src/math/fmod.rs b/library/compiler-builtins/libm/src/math/fmod.rs index d9786b53d7190..c4752b92578fc 100644 --- a/library/compiler-builtins/libm/src/math/fmod.rs +++ b/library/compiler-builtins/libm/src/math/fmod.rs @@ -1,5 +1,25 @@ +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg(f16_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf16(x: f16, y: f16) -> f16 { + super::generic::fmod(x, y) +} + +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf(x: f32, y: f32) -> f32 { + super::generic::fmod(x, y) +} + /// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmod(x: f64, y: f64) -> f64 { super::generic::fmod(x, y) } + +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg(f128_enabled)] +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf128(x: f128, y: f128) -> f128 { + super::generic::fmod(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs deleted file mode 100644 index 4e95696e20d63..0000000000000 --- a/library/compiler-builtins/libm/src/math/fmodf.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmodf(x: f32, y: f32) -> f32 { - super::generic::fmod(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fmodf128.rs b/library/compiler-builtins/libm/src/math/fmodf128.rs deleted file mode 100644 index ff0e0493e26b6..0000000000000 --- a/library/compiler-builtins/libm/src/math/fmodf128.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmodf128(x: f128, y: f128) -> f128 { - super::generic::fmod(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fmodf16.rs b/library/compiler-builtins/libm/src/math/fmodf16.rs deleted file mode 100644 index 11972a7de4ff0..0000000000000 --- a/library/compiler-builtins/libm/src/math/fmodf16.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmodf16(x: f16, y: f16) -> f16 { - super::generic::fmod(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/frexp.rs b/library/compiler-builtins/libm/src/math/frexp.rs index badad786aa318..de7a64fdae1af 100644 --- a/library/compiler-builtins/libm/src/math/frexp.rs +++ b/library/compiler-builtins/libm/src/math/frexp.rs @@ -1,3 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn frexp(x: f64) -> (f64, i32) { let mut y = x.to_bits(); let ee = ((y >> 52) & 0x7ff) as i32; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 023cf67a30615..949c18b400098 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -164,7 +164,6 @@ mod fmin_fmax; mod fminimum_fmaximum; mod fminimum_fmaximum_num; mod fmod; -mod fmodf; mod frexp; mod frexpf; mod hypot; @@ -260,8 +259,7 @@ pub use self::fma_wide::fmaf; pub use self::fmin_fmax::{fmax, fmaxf, fmin, fminf}; pub use self::fminimum_fmaximum::{fmaximum, fmaximumf, fminimum, fminimumf}; pub use self::fminimum_fmaximum_num::{fmaximum_num, fmaximum_numf, fminimum_num, fminimum_numf}; -pub use self::fmod::fmod; -pub use self::fmodf::fmodf; +pub use self::fmod::{fmod, fmodf}; pub use self::frexp::frexp; pub use self::frexpf::frexpf; pub use self::hypot::hypot; @@ -318,10 +316,6 @@ pub use self::trunc::{trunc, truncf}; cfg_if! { if #[cfg(f16_enabled)] { - // verify-sorted-start - mod fmodf16; - // verify-sorted-end - // verify-sorted-start pub use self::ceil::ceilf16; pub use self::copysign::copysignf16; @@ -331,7 +325,7 @@ cfg_if! { pub use self::fmin_fmax::{fmaxf16, fminf16}; pub use self::fminimum_fmaximum::{fmaximumf16, fminimumf16}; pub use self::fminimum_fmaximum_num::{fmaximum_numf16, fminimum_numf16}; - pub use self::fmodf16::fmodf16; + pub use self::fmod::fmodf16; pub use self::ldexp::ldexpf16; pub use self::rint::rintf16; pub use self::round::roundf16; @@ -348,10 +342,6 @@ cfg_if! { cfg_if! { if #[cfg(f128_enabled)] { - // verify-sorted-start - mod fmodf128; - // verify-sorted-end - // verify-sorted-start pub use self::ceil::ceilf128; pub use self::copysign::copysignf128; @@ -362,7 +352,7 @@ cfg_if! { pub use self::fmin_fmax::{fmaxf128, fminf128}; pub use self::fminimum_fmaximum::{fmaximumf128, fminimumf128}; pub use self::fminimum_fmaximum_num::{fmaximum_numf128, fminimum_numf128}; - pub use self::fmodf128::fmodf128; + pub use self::fmod::fmodf128; pub use self::ldexp::ldexpf128; pub use self::rint::rintf128; pub use self::round::roundf128; From 88dcaf20b5400e023024daae6a3c927a32fa36ab Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 19:19:24 +0000 Subject: [PATCH 1821/4206] Mark generic functions `#[inline]` Benchmarks for [1] seemed to indicate that repository organization for some reason had an effect on performance, even though the exact same rustc commands were running (though some with a different order). After investigating more, it appears that dependencies may have an affect on inlining thresholds for generic functions. It is surprising that this happens, we more or less expect that public functions will be standalone but everything they call will be inlined. To help ensure this, mark all generic functions `#[inline]` if they should be merged into the public function. Zulip discussion at [2]. [1]: https://github.com/rust-lang/libm/pull/533 [2]: https://rust-lang.zulipchat.com/#narrow/channel/182449-t-compiler.2Fhelp/topic/Dependencies.20affecting.20codegen/with/513079387 --- library/compiler-builtins/libm/src/math/fma.rs | 1 + library/compiler-builtins/libm/src/math/fma_wide.rs | 1 + library/compiler-builtins/libm/src/math/generic/ceil.rs | 2 ++ library/compiler-builtins/libm/src/math/generic/copysign.rs | 1 + library/compiler-builtins/libm/src/math/generic/fabs.rs | 1 + library/compiler-builtins/libm/src/math/generic/fdim.rs | 1 + library/compiler-builtins/libm/src/math/generic/floor.rs | 2 ++ library/compiler-builtins/libm/src/math/generic/fmax.rs | 2 +- library/compiler-builtins/libm/src/math/generic/fmaximum.rs | 1 + .../compiler-builtins/libm/src/math/generic/fmaximum_num.rs | 1 + library/compiler-builtins/libm/src/math/generic/fmin.rs | 1 + library/compiler-builtins/libm/src/math/generic/fminimum.rs | 1 + .../compiler-builtins/libm/src/math/generic/fminimum_num.rs | 1 + library/compiler-builtins/libm/src/math/generic/fmod.rs | 2 +- library/compiler-builtins/libm/src/math/generic/mod.rs | 3 +++ library/compiler-builtins/libm/src/math/generic/rint.rs | 1 + library/compiler-builtins/libm/src/math/generic/round.rs | 1 + library/compiler-builtins/libm/src/math/generic/scalbn.rs | 1 + library/compiler-builtins/libm/src/math/generic/sqrt.rs | 2 ++ library/compiler-builtins/libm/src/math/generic/trunc.rs | 2 ++ library/compiler-builtins/libm/src/math/roundeven.rs | 1 + 21 files changed, 27 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 789b0836afbfa..e0b3347acf853 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -29,6 +29,7 @@ pub fn fmaf128(x: f128, y: f128, z: f128) -> f128 { /// Fused multiply-add that works when there is not a larger float size available. Computes /// `(x * y) + z`. +#[inline] pub fn fma_round(x: F, y: F, z: F, _round: Round) -> FpResult where F: Float, diff --git a/library/compiler-builtins/libm/src/math/fma_wide.rs b/library/compiler-builtins/libm/src/math/fma_wide.rs index 8e908a14f2147..08b78b0226454 100644 --- a/library/compiler-builtins/libm/src/math/fma_wide.rs +++ b/library/compiler-builtins/libm/src/math/fma_wide.rs @@ -28,6 +28,7 @@ pub fn fmaf(x: f32, y: f32, z: f32) -> f32 { /// Fma implementation when a hardware-backed larger float type is available. For `f32` and `f64`, /// `f64` has enough precision to represent the `f32` in its entirety, except for double rounding. +#[inline] pub fn fma_wide_round(x: F, y: F, z: F, round: Round) -> FpResult where F: Float + HFloat, diff --git a/library/compiler-builtins/libm/src/math/generic/ceil.rs b/library/compiler-builtins/libm/src/math/generic/ceil.rs index bf7e1d8e2100b..5c5bb47638fd8 100644 --- a/library/compiler-builtins/libm/src/math/generic/ceil.rs +++ b/library/compiler-builtins/libm/src/math/generic/ceil.rs @@ -10,10 +10,12 @@ use super::super::support::{FpResult, Status}; use super::super::{Float, Int, IntTy, MinInt}; +#[inline] pub fn ceil(x: F) -> F { ceil_status(x).val } +#[inline] pub fn ceil_status(x: F) -> FpResult { let zero = IntTy::::ZERO; diff --git a/library/compiler-builtins/libm/src/math/generic/copysign.rs b/library/compiler-builtins/libm/src/math/generic/copysign.rs index 04864a3590567..a61af22f04ab8 100644 --- a/library/compiler-builtins/libm/src/math/generic/copysign.rs +++ b/library/compiler-builtins/libm/src/math/generic/copysign.rs @@ -1,6 +1,7 @@ use super::super::Float; /// Copy the sign of `y` to `x`. +#[inline] pub fn copysign(x: F, y: F) -> F { let mut ux = x.to_bits(); let uy = y.to_bits(); diff --git a/library/compiler-builtins/libm/src/math/generic/fabs.rs b/library/compiler-builtins/libm/src/math/generic/fabs.rs index 75b473107c671..0fa0edf9b8760 100644 --- a/library/compiler-builtins/libm/src/math/generic/fabs.rs +++ b/library/compiler-builtins/libm/src/math/generic/fabs.rs @@ -1,6 +1,7 @@ use super::super::Float; /// Absolute value. +#[inline] pub fn fabs(x: F) -> F { let abs_mask = !F::SIGN_MASK; F::from_bits(x.to_bits() & abs_mask) diff --git a/library/compiler-builtins/libm/src/math/generic/fdim.rs b/library/compiler-builtins/libm/src/math/generic/fdim.rs index bf971cd7d18c8..a63007b191cca 100644 --- a/library/compiler-builtins/libm/src/math/generic/fdim.rs +++ b/library/compiler-builtins/libm/src/math/generic/fdim.rs @@ -1,5 +1,6 @@ use super::super::Float; +#[inline] pub fn fdim(x: F, y: F) -> F { if x <= y { F::ZERO } else { x - y } } diff --git a/library/compiler-builtins/libm/src/math/generic/floor.rs b/library/compiler-builtins/libm/src/math/generic/floor.rs index 7799551644f3c..2438046254fc4 100644 --- a/library/compiler-builtins/libm/src/math/generic/floor.rs +++ b/library/compiler-builtins/libm/src/math/generic/floor.rs @@ -10,10 +10,12 @@ use super::super::support::{FpResult, Status}; use super::super::{Float, Int, IntTy, MinInt}; +#[inline] pub fn floor(x: F) -> F { floor_status(x).val } +#[inline] pub fn floor_status(x: F) -> FpResult { let zero = IntTy::::ZERO; diff --git a/library/compiler-builtins/libm/src/math/generic/fmax.rs b/library/compiler-builtins/libm/src/math/generic/fmax.rs index 29a0311005716..bf3f847e89bbc 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmax.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmax.rs @@ -16,7 +16,7 @@ use super::super::Float; -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +#[inline] pub fn fmax(x: F, y: F) -> F { let res = if x.is_nan() || x < y { y } else { x }; // Canonicalize diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs index 9e8d1739f6786..387055af29c21 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs @@ -11,6 +11,7 @@ use super::super::Float; +#[inline] pub fn fmaximum(x: F, y: F) -> F { let res = if x.is_nan() { x diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs index 756ef5d9f6ded..f7efdde80ea7c 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs @@ -13,6 +13,7 @@ use super::super::Float; +#[inline] pub fn fmaximum_num(x: F, y: F) -> F { let res = if x.is_nan() || x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { diff --git a/library/compiler-builtins/libm/src/math/generic/fmin.rs b/library/compiler-builtins/libm/src/math/generic/fmin.rs index 69fbf85a194ed..cd3caeee4f201 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmin.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmin.rs @@ -16,6 +16,7 @@ use super::super::Float; +#[inline] pub fn fmin(x: F, y: F) -> F { let res = if y.is_nan() || x < y { x } else { y }; // Canonicalize diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum.rs b/library/compiler-builtins/libm/src/math/generic/fminimum.rs index ee5493880eb43..4ddb36455064f 100644 --- a/library/compiler-builtins/libm/src/math/generic/fminimum.rs +++ b/library/compiler-builtins/libm/src/math/generic/fminimum.rs @@ -11,6 +11,7 @@ use super::super::Float; +#[inline] pub fn fminimum(x: F, y: F) -> F { let res = if x.is_nan() { x diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs index 966618328242e..441c204a9219b 100644 --- a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs +++ b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs @@ -13,6 +13,7 @@ use super::super::Float; +#[inline] pub fn fminimum_num(x: F, y: F) -> F { let res = if y.is_nan() || x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) { diff --git a/library/compiler-builtins/libm/src/math/generic/fmod.rs b/library/compiler-builtins/libm/src/math/generic/fmod.rs index cd23350ea3a6e..6414bbd250812 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmod.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmod.rs @@ -3,7 +3,7 @@ use super::super::{CastFrom, Float, Int, MinInt}; -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +#[inline] pub fn fmod(x: F, y: F) -> F { let zero = F::Int::ZERO; let one = F::Int::ONE; diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index 9be185f809f19..35846351a6e8b 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -1,3 +1,6 @@ +// Note: generic functions are marked `#[inline]` because, even though generic functions are +// typically inlined, this does not seem to always be the case. + mod ceil; mod copysign; mod fabs; diff --git a/library/compiler-builtins/libm/src/math/generic/rint.rs b/library/compiler-builtins/libm/src/math/generic/rint.rs index 45d2f3138665f..9cdeb1185a867 100644 --- a/library/compiler-builtins/libm/src/math/generic/rint.rs +++ b/library/compiler-builtins/libm/src/math/generic/rint.rs @@ -6,6 +6,7 @@ use super::super::support::{FpResult, Round}; /// IEEE 754-2019 `roundToIntegralExact`, which respects rounding mode and raises inexact if /// applicable. +#[inline] pub fn rint_round(x: F, _round: Round) -> FpResult { let toint = F::ONE / F::EPSILON; let e = x.ex(); diff --git a/library/compiler-builtins/libm/src/math/generic/round.rs b/library/compiler-builtins/libm/src/math/generic/round.rs index 8b51381880ccc..01314ac70c27d 100644 --- a/library/compiler-builtins/libm/src/math/generic/round.rs +++ b/library/compiler-builtins/libm/src/math/generic/round.rs @@ -1,6 +1,7 @@ use super::super::{Float, MinInt}; use super::{copysign, trunc}; +#[inline] 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 diff --git a/library/compiler-builtins/libm/src/math/generic/scalbn.rs b/library/compiler-builtins/libm/src/math/generic/scalbn.rs index b2696e5cc9f5d..a45db1b4a024f 100644 --- a/library/compiler-builtins/libm/src/math/generic/scalbn.rs +++ b/library/compiler-builtins/libm/src/math/generic/scalbn.rs @@ -16,6 +16,7 @@ use super::super::{CastFrom, CastInto, Float, IntTy, MinInt}; /// > /// > If the calculation does not overflow or underflow, the returned value is exact and /// > independent of the current rounding direction mode. +#[inline] pub fn scalbn(mut x: F, mut n: i32) -> F where u32: CastInto, diff --git a/library/compiler-builtins/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/src/math/generic/sqrt.rs index 5918025bc678d..ec9ff22df2081 100644 --- a/library/compiler-builtins/libm/src/math/generic/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/generic/sqrt.rs @@ -44,6 +44,7 @@ use super::super::support::{FpResult, IntTy, Round, Status, cold_path}; use super::super::{CastFrom, CastInto, DInt, Float, HInt, Int, MinInt}; +#[inline] pub fn sqrt(x: F) -> F where F: Float + SqrtHelper, @@ -57,6 +58,7 @@ where sqrt_round(x, Round::Nearest).val } +#[inline] pub fn sqrt_round(x: F, _round: Round) -> FpResult where F: Float + SqrtHelper, diff --git a/library/compiler-builtins/libm/src/math/generic/trunc.rs b/library/compiler-builtins/libm/src/math/generic/trunc.rs index 0fb3fa5ad3b80..25414ecf426a3 100644 --- a/library/compiler-builtins/libm/src/math/generic/trunc.rs +++ b/library/compiler-builtins/libm/src/math/generic/trunc.rs @@ -4,10 +4,12 @@ use super::super::support::{FpResult, Status}; use super::super::{Float, Int, IntTy, MinInt}; +#[inline] pub fn trunc(x: F) -> F { trunc_status(x).val } +#[inline] pub fn trunc_status(x: F) -> FpResult { let mut xi: F::Int = x.to_bits(); let e: i32 = x.exp_unbiased(); diff --git a/library/compiler-builtins/libm/src/math/roundeven.rs b/library/compiler-builtins/libm/src/math/roundeven.rs index ec1738285e620..6e621d7628f2a 100644 --- a/library/compiler-builtins/libm/src/math/roundeven.rs +++ b/library/compiler-builtins/libm/src/math/roundeven.rs @@ -30,6 +30,7 @@ pub fn roundevenf128(x: f128) -> f128 { roundeven_impl(x) } +#[inline] pub fn roundeven_impl(x: F) -> F { super::generic::rint_round(x, Round::Nearest).val } From 7077daa6ad9fecd1cb5fa10a431ac86273abbb20 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 9 Apr 2025 01:21:33 +0000 Subject: [PATCH 1822/4206] refactor: Move the `libm` crate to a subdirectory In preparation for switching to a virtual manifest, move the `libm` crate into a subdirectory and update paths to match. Updating `Cargo.toml` is done in the next commit so git tracks the moved file correctly. --- .../libm/.github/workflows/main.yaml | 2 +- library/compiler-builtins/libm/ci/ci-util.py | 6 +-- .../compiler-builtins-smoke-test/build.rs | 4 +- .../compiler-builtins-smoke-test/src/math.rs | 2 +- .../libm/crates/libm-test/Cargo.toml | 2 +- .../libm/crates/libm-test/build.rs | 4 +- .../libm/crates/musl-math-sys/Cargo.toml | 2 +- .../libm/crates/util/Cargo.toml | 2 +- .../libm/crates/util/build.rs | 4 +- .../libm/etc/update-api-list.py | 18 ++++----- .../libm/{ => libm}/Cargo.toml | 0 .../libm/{ => libm}/build.rs | 1 + .../libm/{ => libm}/configure.rs | 0 .../libm/{ => libm}/src/lib.rs | 0 .../libm/{ => libm}/src/libm_helper.rs | 0 .../libm/{ => libm}/src/math/acos.rs | 0 .../libm/{ => libm}/src/math/acosf.rs | 0 .../libm/{ => libm}/src/math/acosh.rs | 0 .../libm/{ => libm}/src/math/acoshf.rs | 0 .../libm/{ => libm}/src/math/arch/aarch64.rs | 0 .../libm/{ => libm}/src/math/arch/i586.rs | 0 .../libm/{ => libm}/src/math/arch/i686.rs | 0 .../libm/{ => libm}/src/math/arch/mod.rs | 0 .../libm/{ => libm}/src/math/arch/wasm32.rs | 0 .../libm/{ => libm}/src/math/asin.rs | 0 .../libm/{ => libm}/src/math/asinf.rs | 0 .../libm/{ => libm}/src/math/asinh.rs | 0 .../libm/{ => libm}/src/math/asinhf.rs | 0 .../libm/{ => libm}/src/math/atan.rs | 0 .../libm/{ => libm}/src/math/atan2.rs | 0 .../libm/{ => libm}/src/math/atan2f.rs | 0 .../libm/{ => libm}/src/math/atanf.rs | 0 .../libm/{ => libm}/src/math/atanh.rs | 0 .../libm/{ => libm}/src/math/atanhf.rs | 0 .../libm/{ => libm}/src/math/cbrt.rs | 0 .../libm/{ => libm}/src/math/cbrtf.rs | 0 .../libm/{ => libm}/src/math/ceil.rs | 0 .../libm/{ => libm}/src/math/copysign.rs | 0 .../libm/libm/src/math/copysignf.rs | 8 ++++ .../libm/libm/src/math/copysignf128.rs | 8 ++++ .../libm/libm/src/math/copysignf16.rs | 8 ++++ .../libm/{ => libm}/src/math/cos.rs | 0 .../libm/{ => libm}/src/math/cosf.rs | 0 .../libm/{ => libm}/src/math/cosh.rs | 0 .../libm/{ => libm}/src/math/coshf.rs | 0 .../libm/{ => libm}/src/math/erf.rs | 0 .../libm/{ => libm}/src/math/erff.rs | 0 .../libm/{ => libm}/src/math/exp.rs | 0 .../libm/{ => libm}/src/math/exp10.rs | 0 .../libm/{ => libm}/src/math/exp10f.rs | 0 .../libm/{ => libm}/src/math/exp2.rs | 0 .../libm/{ => libm}/src/math/exp2f.rs | 0 .../libm/{ => libm}/src/math/expf.rs | 0 .../libm/{ => libm}/src/math/expm1.rs | 0 .../libm/{ => libm}/src/math/expm1f.rs | 0 .../libm/{ => libm}/src/math/expo2.rs | 0 .../libm/{ => libm}/src/math/fabs.rs | 0 .../libm/libm/src/math/fabsf.rs | 39 +++++++++++++++++++ .../libm/libm/src/math/fabsf128.rs | 31 +++++++++++++++ .../libm/libm/src/math/fabsf16.rs | 31 +++++++++++++++ .../libm/{ => libm}/src/math/fdim.rs | 0 .../libm/libm/src/math/fdimf.rs | 12 ++++++ .../libm/libm/src/math/fdimf128.rs | 12 ++++++ .../libm/libm/src/math/fdimf16.rs | 12 ++++++ .../libm/{ => libm}/src/math/floor.rs | 0 .../libm/libm/src/math/floorf.rs | 13 +++++++ .../libm/libm/src/math/floorf128.rs | 7 ++++ .../libm/libm/src/math/floorf16.rs | 7 ++++ .../libm/{ => libm}/src/math/fma.rs | 0 .../libm/{ => libm}/src/math/fma_wide.rs | 0 .../libm/{ => libm}/src/math/fmin_fmax.rs | 0 .../{ => libm}/src/math/fminimum_fmaximum.rs | 0 .../src/math/fminimum_fmaximum_num.rs | 0 .../libm/{ => libm}/src/math/fmod.rs | 0 .../libm/libm/src/math/fmodf.rs | 5 +++ .../libm/libm/src/math/fmodf128.rs | 5 +++ .../libm/libm/src/math/fmodf16.rs | 5 +++ .../libm/{ => libm}/src/math/frexp.rs | 0 .../libm/{ => libm}/src/math/frexpf.rs | 0 .../libm/{ => libm}/src/math/generic/ceil.rs | 0 .../{ => libm}/src/math/generic/copysign.rs | 0 .../libm/{ => libm}/src/math/generic/fabs.rs | 0 .../libm/{ => libm}/src/math/generic/fdim.rs | 0 .../libm/{ => libm}/src/math/generic/floor.rs | 0 .../libm/{ => libm}/src/math/generic/fmax.rs | 0 .../{ => libm}/src/math/generic/fmaximum.rs | 0 .../src/math/generic/fmaximum_num.rs | 0 .../libm/{ => libm}/src/math/generic/fmin.rs | 0 .../{ => libm}/src/math/generic/fminimum.rs | 0 .../src/math/generic/fminimum_num.rs | 0 .../libm/{ => libm}/src/math/generic/fmod.rs | 0 .../libm/{ => libm}/src/math/generic/mod.rs | 0 .../libm/{ => libm}/src/math/generic/rint.rs | 0 .../libm/{ => libm}/src/math/generic/round.rs | 0 .../{ => libm}/src/math/generic/scalbn.rs | 0 .../libm/{ => libm}/src/math/generic/sqrt.rs | 0 .../libm/{ => libm}/src/math/generic/trunc.rs | 0 .../libm/{ => libm}/src/math/hypot.rs | 0 .../libm/{ => libm}/src/math/hypotf.rs | 0 .../libm/{ => libm}/src/math/ilogb.rs | 0 .../libm/{ => libm}/src/math/ilogbf.rs | 0 .../libm/{ => libm}/src/math/j0.rs | 0 .../libm/{ => libm}/src/math/j0f.rs | 0 .../libm/{ => libm}/src/math/j1.rs | 0 .../libm/{ => libm}/src/math/j1f.rs | 0 .../libm/{ => libm}/src/math/jn.rs | 0 .../libm/{ => libm}/src/math/jnf.rs | 0 .../libm/{ => libm}/src/math/k_cos.rs | 0 .../libm/{ => libm}/src/math/k_cosf.rs | 0 .../libm/{ => libm}/src/math/k_expo2.rs | 0 .../libm/{ => libm}/src/math/k_expo2f.rs | 0 .../libm/{ => libm}/src/math/k_sin.rs | 0 .../libm/{ => libm}/src/math/k_sinf.rs | 0 .../libm/{ => libm}/src/math/k_tan.rs | 0 .../libm/{ => libm}/src/math/k_tanf.rs | 0 .../libm/{ => libm}/src/math/ldexp.rs | 0 .../libm/libm/src/math/ldexpf.rs | 4 ++ .../libm/libm/src/math/ldexpf128.rs | 4 ++ .../libm/libm/src/math/ldexpf16.rs | 4 ++ .../libm/{ => libm}/src/math/lgamma.rs | 0 .../libm/{ => libm}/src/math/lgamma_r.rs | 0 .../libm/{ => libm}/src/math/lgammaf.rs | 0 .../libm/{ => libm}/src/math/lgammaf_r.rs | 0 .../libm/{ => libm}/src/math/log.rs | 0 .../libm/{ => libm}/src/math/log10.rs | 0 .../libm/{ => libm}/src/math/log10f.rs | 0 .../libm/{ => libm}/src/math/log1p.rs | 0 .../libm/{ => libm}/src/math/log1pf.rs | 0 .../libm/{ => libm}/src/math/log2.rs | 0 .../libm/{ => libm}/src/math/log2f.rs | 0 .../libm/{ => libm}/src/math/logf.rs | 0 .../libm/{ => libm}/src/math/mod.rs | 0 .../libm/{ => libm}/src/math/modf.rs | 0 .../libm/{ => libm}/src/math/modff.rs | 0 .../libm/{ => libm}/src/math/nextafter.rs | 0 .../libm/{ => libm}/src/math/nextafterf.rs | 0 .../libm/{ => libm}/src/math/pow.rs | 0 .../libm/{ => libm}/src/math/powf.rs | 0 .../libm/{ => libm}/src/math/rem_pio2.rs | 0 .../{ => libm}/src/math/rem_pio2_large.rs | 0 .../libm/{ => libm}/src/math/rem_pio2f.rs | 0 .../libm/{ => libm}/src/math/remainder.rs | 0 .../libm/{ => libm}/src/math/remainderf.rs | 0 .../libm/{ => libm}/src/math/remquo.rs | 0 .../libm/{ => libm}/src/math/remquof.rs | 0 .../libm/{ => libm}/src/math/rint.rs | 0 .../libm/{ => libm}/src/math/round.rs | 0 .../libm/{ => libm}/src/math/roundeven.rs | 0 .../libm/libm/src/math/roundf.rs | 5 +++ .../libm/libm/src/math/roundf128.rs | 5 +++ .../libm/libm/src/math/roundf16.rs | 5 +++ .../libm/{ => libm}/src/math/scalbn.rs | 0 .../libm/libm/src/math/scalbnf.rs | 4 ++ .../libm/libm/src/math/scalbnf128.rs | 4 ++ .../libm/libm/src/math/scalbnf16.rs | 4 ++ .../libm/{ => libm}/src/math/sin.rs | 0 .../libm/{ => libm}/src/math/sincos.rs | 0 .../libm/{ => libm}/src/math/sincosf.rs | 0 .../libm/{ => libm}/src/math/sinf.rs | 0 .../libm/{ => libm}/src/math/sinh.rs | 0 .../libm/{ => libm}/src/math/sinhf.rs | 0 .../libm/{ => libm}/src/math/sqrt.rs | 0 .../libm/libm/src/math/sqrtf.rs | 15 +++++++ .../libm/libm/src/math/sqrtf128.rs | 5 +++ .../libm/libm/src/math/sqrtf16.rs | 11 ++++++ .../libm/{ => libm}/src/math/support/big.rs | 0 .../{ => libm}/src/math/support/big/tests.rs | 0 .../libm/{ => libm}/src/math/support/env.rs | 0 .../src/math/support/float_traits.rs | 0 .../{ => libm}/src/math/support/hex_float.rs | 0 .../{ => libm}/src/math/support/int_traits.rs | 0 .../{ => libm}/src/math/support/macros.rs | 0 .../libm/{ => libm}/src/math/support/mod.rs | 0 .../libm/{ => libm}/src/math/tan.rs | 0 .../libm/{ => libm}/src/math/tanf.rs | 0 .../libm/{ => libm}/src/math/tanh.rs | 0 .../libm/{ => libm}/src/math/tanhf.rs | 0 .../libm/{ => libm}/src/math/tgamma.rs | 0 .../libm/{ => libm}/src/math/tgammaf.rs | 0 .../libm/{ => libm}/src/math/trunc.rs | 0 .../libm/libm/src/math/truncf.rs | 23 +++++++++++ .../libm/libm/src/math/truncf128.rs | 7 ++++ .../libm/libm/src/math/truncf16.rs | 7 ++++ 183 files changed, 334 insertions(+), 23 deletions(-) rename library/compiler-builtins/libm/{ => libm}/Cargo.toml (100%) rename library/compiler-builtins/libm/{ => libm}/build.rs (88%) rename library/compiler-builtins/libm/{ => libm}/configure.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/lib.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/libm_helper.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/acos.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/acosf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/acosh.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/acoshf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/arch/aarch64.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/arch/i586.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/arch/i686.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/arch/mod.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/arch/wasm32.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/asin.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/asinf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/asinh.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/asinhf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/atan.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/atan2.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/atan2f.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/atanf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/atanh.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/atanhf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/cbrt.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/cbrtf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/ceil.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/copysign.rs (100%) create mode 100644 library/compiler-builtins/libm/libm/src/math/copysignf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/copysignf128.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/copysignf16.rs rename library/compiler-builtins/libm/{ => libm}/src/math/cos.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/cosf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/cosh.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/coshf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/erf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/erff.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/exp.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/exp10.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/exp10f.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/exp2.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/exp2f.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/expf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/expm1.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/expm1f.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/expo2.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/fabs.rs (100%) create mode 100644 library/compiler-builtins/libm/libm/src/math/fabsf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/fabsf128.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/fabsf16.rs rename library/compiler-builtins/libm/{ => libm}/src/math/fdim.rs (100%) create mode 100644 library/compiler-builtins/libm/libm/src/math/fdimf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/fdimf128.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/fdimf16.rs rename library/compiler-builtins/libm/{ => libm}/src/math/floor.rs (100%) create mode 100644 library/compiler-builtins/libm/libm/src/math/floorf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/floorf128.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/floorf16.rs rename library/compiler-builtins/libm/{ => libm}/src/math/fma.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/fma_wide.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/fmin_fmax.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/fminimum_fmaximum.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/fminimum_fmaximum_num.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/fmod.rs (100%) create mode 100644 library/compiler-builtins/libm/libm/src/math/fmodf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/fmodf128.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/fmodf16.rs rename library/compiler-builtins/libm/{ => libm}/src/math/frexp.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/frexpf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/generic/ceil.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/generic/copysign.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/generic/fabs.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/generic/fdim.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/generic/floor.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/generic/fmax.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/generic/fmaximum.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/generic/fmaximum_num.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/generic/fmin.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/generic/fminimum.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/generic/fminimum_num.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/generic/fmod.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/generic/mod.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/generic/rint.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/generic/round.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/generic/scalbn.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/generic/sqrt.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/generic/trunc.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/hypot.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/hypotf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/ilogb.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/ilogbf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/j0.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/j0f.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/j1.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/j1f.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/jn.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/jnf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/k_cos.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/k_cosf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/k_expo2.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/k_expo2f.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/k_sin.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/k_sinf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/k_tan.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/k_tanf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/ldexp.rs (100%) create mode 100644 library/compiler-builtins/libm/libm/src/math/ldexpf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/ldexpf128.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/ldexpf16.rs rename library/compiler-builtins/libm/{ => libm}/src/math/lgamma.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/lgamma_r.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/lgammaf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/lgammaf_r.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/log.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/log10.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/log10f.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/log1p.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/log1pf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/log2.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/log2f.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/logf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/mod.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/modf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/modff.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/nextafter.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/nextafterf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/pow.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/powf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/rem_pio2.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/rem_pio2_large.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/rem_pio2f.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/remainder.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/remainderf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/remquo.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/remquof.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/rint.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/round.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/roundeven.rs (100%) create mode 100644 library/compiler-builtins/libm/libm/src/math/roundf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/roundf128.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/roundf16.rs rename library/compiler-builtins/libm/{ => libm}/src/math/scalbn.rs (100%) create mode 100644 library/compiler-builtins/libm/libm/src/math/scalbnf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/scalbnf128.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/scalbnf16.rs rename library/compiler-builtins/libm/{ => libm}/src/math/sin.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/sincos.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/sincosf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/sinf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/sinh.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/sinhf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/sqrt.rs (100%) create mode 100644 library/compiler-builtins/libm/libm/src/math/sqrtf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/sqrtf128.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/sqrtf16.rs rename library/compiler-builtins/libm/{ => libm}/src/math/support/big.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/support/big/tests.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/support/env.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/support/float_traits.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/support/hex_float.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/support/int_traits.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/support/macros.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/support/mod.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/tan.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/tanf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/tanh.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/tanhf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/tgamma.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/tgammaf.rs (100%) rename library/compiler-builtins/libm/{ => libm}/src/math/trunc.rs (100%) create mode 100644 library/compiler-builtins/libm/libm/src/math/truncf.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/truncf128.rs create mode 100644 library/compiler-builtins/libm/libm/src/math/truncf16.rs diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index c925e63aa59b0..a717c3ea8f879 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -213,7 +213,7 @@ jobs: steps: - uses: actions/checkout@master - run: | - msrv="$(perl -ne 'print if s/rust-version\s*=\s*"(.*)"/\1/g' Cargo.toml)" + msrv="$(perl -ne 'print if s/rust-version\s*=\s*"(.*)"/\1/g' libm/Cargo.toml)" echo "MSRV: $msrv" echo "MSRV=$msrv" >> "$GITHUB_ENV" - name: Install Rust diff --git a/library/compiler-builtins/libm/ci/ci-util.py b/library/compiler-builtins/libm/ci/ci-util.py index 7468fd690cbbb..ed63d6deea1e9 100755 --- a/library/compiler-builtins/libm/ci/ci-util.py +++ b/library/compiler-builtins/libm/ci/ci-util.py @@ -63,9 +63,9 @@ # Don't run exhaustive tests if these files change, even if they contaiin a function # definition. IGNORE_FILES = [ - "src/math/support/", - "src/libm_helper.rs", - "src/math/arch/intrinsics.rs", + "libm/src/math/support/", + "libm/src/libm_helper.rs", + "libm/src/math/arch/intrinsics.rs", ] TYPES = ["f16", "f32", "f64", "f128"] diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs index 4ee5ab585d502..ef8d613c9f45b 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs @@ -1,8 +1,8 @@ -#[path = "../../configure.rs"] +#[path = "../../libm/configure.rs"] mod configure; fn main() { - println!("cargo:rerun-if-changed=../../configure.rs"); + println!("cargo:rerun-if-changed=../../libm/configure.rs"); let cfg = configure::Config::from_env(); configure::emit_libm_config(&cfg); } diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs index 7e0146998aae1..f17fc12316838 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs @@ -3,7 +3,7 @@ use core::ffi::c_int; #[allow(dead_code)] #[allow(clippy::all)] // We don't get `libm`'s list of `allow`s, so just ignore Clippy. #[allow(unused_imports)] -#[path = "../../../src/math/mod.rs"] +#[path = "../../../libm/src/math/mod.rs"] pub mod libm; /// Mark functions `#[no_mangle]` and with the C ABI. diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 98da73ceadc93..1bcc163ed1b66 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -32,7 +32,7 @@ anyhow = "1.0.97" gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false } iai-callgrind = { version = "0.14.0", optional = true } indicatif = { version = "0.17.11", default-features = false } -libm = { path = "../..", features = ["unstable-public-internals"] } +libm = { path = "../../libm", features = ["unstable-public-internals"] } libm-macros = { path = "../libm-macros" } musl-math-sys = { path = "../musl-math-sys", optional = true } paste = "1.0.15" diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm/crates/libm-test/build.rs index d2d0df9cbe925..f75e3dda5ff1f 100644 --- a/library/compiler-builtins/libm/crates/libm-test/build.rs +++ b/library/compiler-builtins/libm/crates/libm-test/build.rs @@ -1,9 +1,9 @@ -#[path = "../../configure.rs"] +#[path = "../../libm/configure.rs"] mod configure; use configure::Config; fn main() { - println!("cargo:rerun-if-changed=../../configure.rs"); + println!("cargo:rerun-if-changed=../../libm/configure.rs"); let cfg = Config::from_env(); configure::emit_test_config(&cfg); } diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml index 34682b74c672f..ad73578d8b8fa 100644 --- a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml +++ b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] [dev-dependencies] -libm = { path = "../../" } +libm = { path = "../../libm" } [build-dependencies] cc = "1.2.16" diff --git a/library/compiler-builtins/libm/crates/util/Cargo.toml b/library/compiler-builtins/libm/crates/util/Cargo.toml index 8005459dbf930..94c7f1033405f 100644 --- a/library/compiler-builtins/libm/crates/util/Cargo.toml +++ b/library/compiler-builtins/libm/crates/util/Cargo.toml @@ -11,7 +11,7 @@ build-mpfr = ["libm-test/build-mpfr", "dep:rug"] unstable-float = ["libm/unstable-float", "libm-test/unstable-float", "rug?/nightly-float"] [dependencies] -libm = { path = "../..", default-features = false } +libm = { path = "../../libm", default-features = false } libm-macros = { path = "../libm-macros" } libm-test = { path = "../libm-test", default-features = false } musl-math-sys = { path = "../musl-math-sys", optional = true } diff --git a/library/compiler-builtins/libm/crates/util/build.rs b/library/compiler-builtins/libm/crates/util/build.rs index b6cceb5f11b71..a1be4127527ae 100644 --- a/library/compiler-builtins/libm/crates/util/build.rs +++ b/library/compiler-builtins/libm/crates/util/build.rs @@ -1,10 +1,10 @@ #![allow(unexpected_cfgs)] -#[path = "../../configure.rs"] +#[path = "../../libm/configure.rs"] mod configure; fn main() { - println!("cargo:rerun-if-changed=../../configure.rs"); + println!("cargo:rerun-if-changed=../../libm/configure.rs"); let cfg = configure::Config::from_env(); configure::emit_libm_config(&cfg); } diff --git a/library/compiler-builtins/libm/etc/update-api-list.py b/library/compiler-builtins/libm/etc/update-api-list.py index b4ce2c453ce67..950824fc442f8 100755 --- a/library/compiler-builtins/libm/etc/update-api-list.py +++ b/library/compiler-builtins/libm/etc/update-api-list.py @@ -18,7 +18,7 @@ SELF_PATH = Path(__file__) ETC_DIR = SELF_PATH.parent -ROOT_DIR = ETC_DIR.parent +LIBM_DIR = ETC_DIR.parent.joinpath("libm") # These files do not trigger a retest. IGNORED_SOURCES = ["src/libm_helper.rs", "src/math/support/float_traits.rs"] @@ -75,7 +75,7 @@ def get_rustdoc_json() -> dict[Any, Any]: "-Zunstable-options", "-o-", ], - cwd=ROOT_DIR, + cwd=LIBM_DIR, text=True, ) j = json.loads(j) @@ -121,8 +121,8 @@ def _init_defs(self, index: IndexTy) -> None: # A lot of the `arch` module is often configured out so doesn't show up in docs. Use # string matching as a fallback. - for fname in glob("src/math/arch/**.rs", root_dir=ROOT_DIR): - contents = (ROOT_DIR.joinpath(fname)).read_text() + for fname in glob("src/math/arch/**.rs", root_dir=LIBM_DIR): + contents = (LIBM_DIR.joinpath(fname)).read_text() for name in self.public_functions: if f"fn {name}" in contents: @@ -188,10 +188,10 @@ def tidy_lists(self) -> None: include all public API. """ - flist = sp.check_output(["git", "ls-files"], cwd=ROOT_DIR, text=True) + flist = sp.check_output(["git", "ls-files"], cwd=LIBM_DIR, text=True) for path in flist.splitlines(): - fpath = ROOT_DIR.joinpath(path) + fpath = LIBM_DIR.joinpath(path) if fpath.is_dir() or fpath == SELF_PATH: continue @@ -229,7 +229,7 @@ def ensure_contains_api(self, fpath: Path, line_num: int, lines: list[str]): if len(not_found) == 0: return - relpath = fpath.relative_to(ROOT_DIR) + relpath = fpath.relative_to(LIBM_DIR) eprint(f"functions not found at {relpath}:{line_num}: {not_found}") exit(1) @@ -244,7 +244,7 @@ def validate_delimited_block( """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) + relpath = fpath.relative_to(LIBM_DIR) block_lines = [] block_start_line: None | int = None for line_num, line in enumerate(lines): @@ -274,7 +274,7 @@ def validate_delimited_block( 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) + relpath = fpath.relative_to(LIBM_DIR) diff_and_exit( "\n".join(lines), "\n".join(sorted(lines)), diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/libm/Cargo.toml similarity index 100% rename from library/compiler-builtins/libm/Cargo.toml rename to library/compiler-builtins/libm/libm/Cargo.toml diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/libm/build.rs similarity index 88% rename from library/compiler-builtins/libm/build.rs rename to library/compiler-builtins/libm/libm/build.rs index 7042b54d7e806..07d08ed4364db 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/libm/build.rs @@ -6,6 +6,7 @@ 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). diff --git a/library/compiler-builtins/libm/configure.rs b/library/compiler-builtins/libm/libm/configure.rs similarity index 100% rename from library/compiler-builtins/libm/configure.rs rename to library/compiler-builtins/libm/libm/configure.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/libm/src/lib.rs similarity index 100% rename from library/compiler-builtins/libm/src/lib.rs rename to library/compiler-builtins/libm/libm/src/lib.rs diff --git a/library/compiler-builtins/libm/src/libm_helper.rs b/library/compiler-builtins/libm/libm/src/libm_helper.rs similarity index 100% rename from library/compiler-builtins/libm/src/libm_helper.rs rename to library/compiler-builtins/libm/libm/src/libm_helper.rs diff --git a/library/compiler-builtins/libm/src/math/acos.rs b/library/compiler-builtins/libm/libm/src/math/acos.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/acos.rs rename to library/compiler-builtins/libm/libm/src/math/acos.rs diff --git a/library/compiler-builtins/libm/src/math/acosf.rs b/library/compiler-builtins/libm/libm/src/math/acosf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/acosf.rs rename to library/compiler-builtins/libm/libm/src/math/acosf.rs diff --git a/library/compiler-builtins/libm/src/math/acosh.rs b/library/compiler-builtins/libm/libm/src/math/acosh.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/acosh.rs rename to library/compiler-builtins/libm/libm/src/math/acosh.rs diff --git a/library/compiler-builtins/libm/src/math/acoshf.rs b/library/compiler-builtins/libm/libm/src/math/acoshf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/acoshf.rs rename to library/compiler-builtins/libm/libm/src/math/acoshf.rs diff --git a/library/compiler-builtins/libm/src/math/arch/aarch64.rs b/library/compiler-builtins/libm/libm/src/math/arch/aarch64.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/arch/aarch64.rs rename to library/compiler-builtins/libm/libm/src/math/arch/aarch64.rs diff --git a/library/compiler-builtins/libm/src/math/arch/i586.rs b/library/compiler-builtins/libm/libm/src/math/arch/i586.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/arch/i586.rs rename to library/compiler-builtins/libm/libm/src/math/arch/i586.rs diff --git a/library/compiler-builtins/libm/src/math/arch/i686.rs b/library/compiler-builtins/libm/libm/src/math/arch/i686.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/arch/i686.rs rename to library/compiler-builtins/libm/libm/src/math/arch/i686.rs diff --git a/library/compiler-builtins/libm/src/math/arch/mod.rs b/library/compiler-builtins/libm/libm/src/math/arch/mod.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/arch/mod.rs rename to library/compiler-builtins/libm/libm/src/math/arch/mod.rs diff --git a/library/compiler-builtins/libm/src/math/arch/wasm32.rs b/library/compiler-builtins/libm/libm/src/math/arch/wasm32.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/arch/wasm32.rs rename to library/compiler-builtins/libm/libm/src/math/arch/wasm32.rs diff --git a/library/compiler-builtins/libm/src/math/asin.rs b/library/compiler-builtins/libm/libm/src/math/asin.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/asin.rs rename to library/compiler-builtins/libm/libm/src/math/asin.rs diff --git a/library/compiler-builtins/libm/src/math/asinf.rs b/library/compiler-builtins/libm/libm/src/math/asinf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/asinf.rs rename to library/compiler-builtins/libm/libm/src/math/asinf.rs diff --git a/library/compiler-builtins/libm/src/math/asinh.rs b/library/compiler-builtins/libm/libm/src/math/asinh.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/asinh.rs rename to library/compiler-builtins/libm/libm/src/math/asinh.rs diff --git a/library/compiler-builtins/libm/src/math/asinhf.rs b/library/compiler-builtins/libm/libm/src/math/asinhf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/asinhf.rs rename to library/compiler-builtins/libm/libm/src/math/asinhf.rs diff --git a/library/compiler-builtins/libm/src/math/atan.rs b/library/compiler-builtins/libm/libm/src/math/atan.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/atan.rs rename to library/compiler-builtins/libm/libm/src/math/atan.rs diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/libm/src/math/atan2.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/atan2.rs rename to library/compiler-builtins/libm/libm/src/math/atan2.rs diff --git a/library/compiler-builtins/libm/src/math/atan2f.rs b/library/compiler-builtins/libm/libm/src/math/atan2f.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/atan2f.rs rename to library/compiler-builtins/libm/libm/src/math/atan2f.rs diff --git a/library/compiler-builtins/libm/src/math/atanf.rs b/library/compiler-builtins/libm/libm/src/math/atanf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/atanf.rs rename to library/compiler-builtins/libm/libm/src/math/atanf.rs diff --git a/library/compiler-builtins/libm/src/math/atanh.rs b/library/compiler-builtins/libm/libm/src/math/atanh.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/atanh.rs rename to library/compiler-builtins/libm/libm/src/math/atanh.rs diff --git a/library/compiler-builtins/libm/src/math/atanhf.rs b/library/compiler-builtins/libm/libm/src/math/atanhf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/atanhf.rs rename to library/compiler-builtins/libm/libm/src/math/atanhf.rs diff --git a/library/compiler-builtins/libm/src/math/cbrt.rs b/library/compiler-builtins/libm/libm/src/math/cbrt.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/cbrt.rs rename to library/compiler-builtins/libm/libm/src/math/cbrt.rs diff --git a/library/compiler-builtins/libm/src/math/cbrtf.rs b/library/compiler-builtins/libm/libm/src/math/cbrtf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/cbrtf.rs rename to library/compiler-builtins/libm/libm/src/math/cbrtf.rs diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/libm/src/math/ceil.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/ceil.rs rename to library/compiler-builtins/libm/libm/src/math/ceil.rs diff --git a/library/compiler-builtins/libm/src/math/copysign.rs b/library/compiler-builtins/libm/libm/src/math/copysign.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/copysign.rs rename to library/compiler-builtins/libm/libm/src/math/copysign.rs diff --git a/library/compiler-builtins/libm/libm/src/math/copysignf.rs b/library/compiler-builtins/libm/libm/src/math/copysignf.rs new file mode 100644 index 0000000000000..8b9bed4c0c427 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/copysignf.rs @@ -0,0 +1,8 @@ +/// Sign of Y, magnitude of X (f32) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf(x: f32, y: f32) -> f32 { + super::generic::copysign(x, y) +} diff --git a/library/compiler-builtins/libm/libm/src/math/copysignf128.rs b/library/compiler-builtins/libm/libm/src/math/copysignf128.rs new file mode 100644 index 0000000000000..7bd81d42b2e9a --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/copysignf128.rs @@ -0,0 +1,8 @@ +/// Sign of Y, magnitude of X (f128) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf128(x: f128, y: f128) -> f128 { + super::generic::copysign(x, y) +} diff --git a/library/compiler-builtins/libm/libm/src/math/copysignf16.rs b/library/compiler-builtins/libm/libm/src/math/copysignf16.rs new file mode 100644 index 0000000000000..8206586860102 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/copysignf16.rs @@ -0,0 +1,8 @@ +/// Sign of Y, magnitude of X (f16) +/// +/// Constructs a number with the magnitude (absolute value) of its +/// first argument, `x`, and the sign of its second argument, `y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn copysignf16(x: f16, y: f16) -> f16 { + super::generic::copysign(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/cos.rs b/library/compiler-builtins/libm/libm/src/math/cos.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/cos.rs rename to library/compiler-builtins/libm/libm/src/math/cos.rs diff --git a/library/compiler-builtins/libm/src/math/cosf.rs b/library/compiler-builtins/libm/libm/src/math/cosf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/cosf.rs rename to library/compiler-builtins/libm/libm/src/math/cosf.rs diff --git a/library/compiler-builtins/libm/src/math/cosh.rs b/library/compiler-builtins/libm/libm/src/math/cosh.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/cosh.rs rename to library/compiler-builtins/libm/libm/src/math/cosh.rs diff --git a/library/compiler-builtins/libm/src/math/coshf.rs b/library/compiler-builtins/libm/libm/src/math/coshf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/coshf.rs rename to library/compiler-builtins/libm/libm/src/math/coshf.rs diff --git a/library/compiler-builtins/libm/src/math/erf.rs b/library/compiler-builtins/libm/libm/src/math/erf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/erf.rs rename to library/compiler-builtins/libm/libm/src/math/erf.rs diff --git a/library/compiler-builtins/libm/src/math/erff.rs b/library/compiler-builtins/libm/libm/src/math/erff.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/erff.rs rename to library/compiler-builtins/libm/libm/src/math/erff.rs diff --git a/library/compiler-builtins/libm/src/math/exp.rs b/library/compiler-builtins/libm/libm/src/math/exp.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/exp.rs rename to library/compiler-builtins/libm/libm/src/math/exp.rs diff --git a/library/compiler-builtins/libm/src/math/exp10.rs b/library/compiler-builtins/libm/libm/src/math/exp10.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/exp10.rs rename to library/compiler-builtins/libm/libm/src/math/exp10.rs diff --git a/library/compiler-builtins/libm/src/math/exp10f.rs b/library/compiler-builtins/libm/libm/src/math/exp10f.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/exp10f.rs rename to library/compiler-builtins/libm/libm/src/math/exp10f.rs diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/libm/src/math/exp2.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/exp2.rs rename to library/compiler-builtins/libm/libm/src/math/exp2.rs diff --git a/library/compiler-builtins/libm/src/math/exp2f.rs b/library/compiler-builtins/libm/libm/src/math/exp2f.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/exp2f.rs rename to library/compiler-builtins/libm/libm/src/math/exp2f.rs diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/libm/src/math/expf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/expf.rs rename to library/compiler-builtins/libm/libm/src/math/expf.rs diff --git a/library/compiler-builtins/libm/src/math/expm1.rs b/library/compiler-builtins/libm/libm/src/math/expm1.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/expm1.rs rename to library/compiler-builtins/libm/libm/src/math/expm1.rs diff --git a/library/compiler-builtins/libm/src/math/expm1f.rs b/library/compiler-builtins/libm/libm/src/math/expm1f.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/expm1f.rs rename to library/compiler-builtins/libm/libm/src/math/expm1f.rs diff --git a/library/compiler-builtins/libm/src/math/expo2.rs b/library/compiler-builtins/libm/libm/src/math/expo2.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/expo2.rs rename to library/compiler-builtins/libm/libm/src/math/expo2.rs diff --git a/library/compiler-builtins/libm/src/math/fabs.rs b/library/compiler-builtins/libm/libm/src/math/fabs.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/fabs.rs rename to library/compiler-builtins/libm/libm/src/math/fabs.rs diff --git a/library/compiler-builtins/libm/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/libm/src/math/fabsf.rs new file mode 100644 index 0000000000000..e5820a26c5238 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fabsf.rs @@ -0,0 +1,39 @@ +/// Absolute value (magnitude) (f32) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf(x: f32) -> f32 { + select_implementation! { + name: fabsf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + super::generic::fabs(x) +} + +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sanity_check() { + assert_eq!(fabsf(-1.0), 1.0); + assert_eq!(fabsf(2.8), 2.8); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs + #[test] + fn spec_tests() { + assert!(fabsf(f32::NAN).is_nan()); + for f in [0.0, -0.0].iter().copied() { + assert_eq!(fabsf(f), 0.0); + } + for f in [f32::INFINITY, f32::NEG_INFINITY].iter().copied() { + assert_eq!(fabsf(f), f32::INFINITY); + } + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/fabsf128.rs b/library/compiler-builtins/libm/libm/src/math/fabsf128.rs new file mode 100644 index 0000000000000..46429ca494033 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fabsf128.rs @@ -0,0 +1,31 @@ +/// Absolute value (magnitude) (f128) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf128(x: f128) -> f128 { + super::generic::fabs(x) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sanity_check() { + assert_eq!(fabsf128(-1.0), 1.0); + assert_eq!(fabsf128(2.8), 2.8); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs + #[test] + fn spec_tests() { + assert!(fabsf128(f128::NAN).is_nan()); + for f in [0.0, -0.0].iter().copied() { + assert_eq!(fabsf128(f), 0.0); + } + for f in [f128::INFINITY, f128::NEG_INFINITY].iter().copied() { + assert_eq!(fabsf128(f), f128::INFINITY); + } + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/fabsf16.rs b/library/compiler-builtins/libm/libm/src/math/fabsf16.rs new file mode 100644 index 0000000000000..eee42ac6a3c60 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fabsf16.rs @@ -0,0 +1,31 @@ +/// Absolute value (magnitude) (f16) +/// +/// Calculates the absolute value (magnitude) of the argument `x`, +/// by direct manipulation of the bit representation of `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fabsf16(x: f16) -> f16 { + super::generic::fabs(x) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sanity_check() { + assert_eq!(fabsf16(-1.0), 1.0); + assert_eq!(fabsf16(2.8), 2.8); + } + + /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs + #[test] + fn spec_tests() { + assert!(fabsf16(f16::NAN).is_nan()); + for f in [0.0, -0.0].iter().copied() { + assert_eq!(fabsf16(f), 0.0); + } + for f in [f16::INFINITY, f16::NEG_INFINITY].iter().copied() { + assert_eq!(fabsf16(f), f16::INFINITY); + } + } +} diff --git a/library/compiler-builtins/libm/src/math/fdim.rs b/library/compiler-builtins/libm/libm/src/math/fdim.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/fdim.rs rename to library/compiler-builtins/libm/libm/src/math/fdim.rs diff --git a/library/compiler-builtins/libm/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/libm/src/math/fdimf.rs new file mode 100644 index 0000000000000..367ef517c63be --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fdimf.rs @@ -0,0 +1,12 @@ +/// Positive difference (f32) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf(x: f32, y: f32) -> f32 { + super::generic::fdim(x, y) +} diff --git a/library/compiler-builtins/libm/libm/src/math/fdimf128.rs b/library/compiler-builtins/libm/libm/src/math/fdimf128.rs new file mode 100644 index 0000000000000..6f3d1d0ff1d54 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fdimf128.rs @@ -0,0 +1,12 @@ +/// Positive difference (f128) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf128(x: f128, y: f128) -> f128 { + super::generic::fdim(x, y) +} diff --git a/library/compiler-builtins/libm/libm/src/math/fdimf16.rs b/library/compiler-builtins/libm/libm/src/math/fdimf16.rs new file mode 100644 index 0000000000000..37bd688581797 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fdimf16.rs @@ -0,0 +1,12 @@ +/// Positive difference (f16) +/// +/// Determines the positive difference between arguments, returning: +/// * x - y if x > y, or +/// * +0 if x <= y, or +/// * NAN if either argument is NAN. +/// +/// A range error may occur. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fdimf16(x: f16, y: f16) -> f16 { + super::generic::fdim(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/libm/src/math/floor.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/floor.rs rename to library/compiler-builtins/libm/libm/src/math/floor.rs diff --git a/library/compiler-builtins/libm/libm/src/math/floorf.rs b/library/compiler-builtins/libm/libm/src/math/floorf.rs new file mode 100644 index 0000000000000..16957b7f35573 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/floorf.rs @@ -0,0 +1,13 @@ +/// Floor (f32) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf(x: f32) -> f32 { + select_implementation! { + name: floorf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + return super::generic::floor(x); +} diff --git a/library/compiler-builtins/libm/libm/src/math/floorf128.rs b/library/compiler-builtins/libm/libm/src/math/floorf128.rs new file mode 100644 index 0000000000000..9a9fe4151152b --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/floorf128.rs @@ -0,0 +1,7 @@ +/// Floor (f128) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf128(x: f128) -> f128 { + return super::generic::floor(x); +} diff --git a/library/compiler-builtins/libm/libm/src/math/floorf16.rs b/library/compiler-builtins/libm/libm/src/math/floorf16.rs new file mode 100644 index 0000000000000..f9b868e04109d --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/floorf16.rs @@ -0,0 +1,7 @@ +/// Floor (f16) +/// +/// Finds the nearest integer less than or equal to `x`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn floorf16(x: f16) -> f16 { + return super::generic::floor(x); +} diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/libm/src/math/fma.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/fma.rs rename to library/compiler-builtins/libm/libm/src/math/fma.rs diff --git a/library/compiler-builtins/libm/src/math/fma_wide.rs b/library/compiler-builtins/libm/libm/src/math/fma_wide.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/fma_wide.rs rename to library/compiler-builtins/libm/libm/src/math/fma_wide.rs diff --git a/library/compiler-builtins/libm/src/math/fmin_fmax.rs b/library/compiler-builtins/libm/libm/src/math/fmin_fmax.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/fmin_fmax.rs rename to library/compiler-builtins/libm/libm/src/math/fmin_fmax.rs diff --git a/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs b/library/compiler-builtins/libm/libm/src/math/fminimum_fmaximum.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs rename to library/compiler-builtins/libm/libm/src/math/fminimum_fmaximum.rs diff --git a/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs b/library/compiler-builtins/libm/libm/src/math/fminimum_fmaximum_num.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs rename to library/compiler-builtins/libm/libm/src/math/fminimum_fmaximum_num.rs diff --git a/library/compiler-builtins/libm/src/math/fmod.rs b/library/compiler-builtins/libm/libm/src/math/fmod.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/fmod.rs rename to library/compiler-builtins/libm/libm/src/math/fmod.rs diff --git a/library/compiler-builtins/libm/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/libm/src/math/fmodf.rs new file mode 100644 index 0000000000000..4e95696e20d63 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fmodf.rs @@ -0,0 +1,5 @@ +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf(x: f32, y: f32) -> f32 { + super::generic::fmod(x, y) +} diff --git a/library/compiler-builtins/libm/libm/src/math/fmodf128.rs b/library/compiler-builtins/libm/libm/src/math/fmodf128.rs new file mode 100644 index 0000000000000..ff0e0493e26b6 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fmodf128.rs @@ -0,0 +1,5 @@ +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf128(x: f128, y: f128) -> f128 { + super::generic::fmod(x, y) +} diff --git a/library/compiler-builtins/libm/libm/src/math/fmodf16.rs b/library/compiler-builtins/libm/libm/src/math/fmodf16.rs new file mode 100644 index 0000000000000..11972a7de4ff0 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/fmodf16.rs @@ -0,0 +1,5 @@ +/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmodf16(x: f16, y: f16) -> f16 { + super::generic::fmod(x, y) +} diff --git a/library/compiler-builtins/libm/src/math/frexp.rs b/library/compiler-builtins/libm/libm/src/math/frexp.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/frexp.rs rename to library/compiler-builtins/libm/libm/src/math/frexp.rs diff --git a/library/compiler-builtins/libm/src/math/frexpf.rs b/library/compiler-builtins/libm/libm/src/math/frexpf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/frexpf.rs rename to library/compiler-builtins/libm/libm/src/math/frexpf.rs diff --git a/library/compiler-builtins/libm/src/math/generic/ceil.rs b/library/compiler-builtins/libm/libm/src/math/generic/ceil.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/generic/ceil.rs rename to library/compiler-builtins/libm/libm/src/math/generic/ceil.rs diff --git a/library/compiler-builtins/libm/src/math/generic/copysign.rs b/library/compiler-builtins/libm/libm/src/math/generic/copysign.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/generic/copysign.rs rename to library/compiler-builtins/libm/libm/src/math/generic/copysign.rs diff --git a/library/compiler-builtins/libm/src/math/generic/fabs.rs b/library/compiler-builtins/libm/libm/src/math/generic/fabs.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/generic/fabs.rs rename to library/compiler-builtins/libm/libm/src/math/generic/fabs.rs diff --git a/library/compiler-builtins/libm/src/math/generic/fdim.rs b/library/compiler-builtins/libm/libm/src/math/generic/fdim.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/generic/fdim.rs rename to library/compiler-builtins/libm/libm/src/math/generic/fdim.rs diff --git a/library/compiler-builtins/libm/src/math/generic/floor.rs b/library/compiler-builtins/libm/libm/src/math/generic/floor.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/generic/floor.rs rename to library/compiler-builtins/libm/libm/src/math/generic/floor.rs diff --git a/library/compiler-builtins/libm/src/math/generic/fmax.rs b/library/compiler-builtins/libm/libm/src/math/generic/fmax.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/generic/fmax.rs rename to library/compiler-builtins/libm/libm/src/math/generic/fmax.rs diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum.rs b/library/compiler-builtins/libm/libm/src/math/generic/fmaximum.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/generic/fmaximum.rs rename to library/compiler-builtins/libm/libm/src/math/generic/fmaximum.rs diff --git a/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs b/library/compiler-builtins/libm/libm/src/math/generic/fmaximum_num.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs rename to library/compiler-builtins/libm/libm/src/math/generic/fmaximum_num.rs diff --git a/library/compiler-builtins/libm/src/math/generic/fmin.rs b/library/compiler-builtins/libm/libm/src/math/generic/fmin.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/generic/fmin.rs rename to library/compiler-builtins/libm/libm/src/math/generic/fmin.rs diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum.rs b/library/compiler-builtins/libm/libm/src/math/generic/fminimum.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/generic/fminimum.rs rename to library/compiler-builtins/libm/libm/src/math/generic/fminimum.rs diff --git a/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs b/library/compiler-builtins/libm/libm/src/math/generic/fminimum_num.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/generic/fminimum_num.rs rename to library/compiler-builtins/libm/libm/src/math/generic/fminimum_num.rs diff --git a/library/compiler-builtins/libm/src/math/generic/fmod.rs b/library/compiler-builtins/libm/libm/src/math/generic/fmod.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/generic/fmod.rs rename to library/compiler-builtins/libm/libm/src/math/generic/fmod.rs diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/libm/src/math/generic/mod.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/generic/mod.rs rename to library/compiler-builtins/libm/libm/src/math/generic/mod.rs diff --git a/library/compiler-builtins/libm/src/math/generic/rint.rs b/library/compiler-builtins/libm/libm/src/math/generic/rint.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/generic/rint.rs rename to library/compiler-builtins/libm/libm/src/math/generic/rint.rs diff --git a/library/compiler-builtins/libm/src/math/generic/round.rs b/library/compiler-builtins/libm/libm/src/math/generic/round.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/generic/round.rs rename to library/compiler-builtins/libm/libm/src/math/generic/round.rs diff --git a/library/compiler-builtins/libm/src/math/generic/scalbn.rs b/library/compiler-builtins/libm/libm/src/math/generic/scalbn.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/generic/scalbn.rs rename to library/compiler-builtins/libm/libm/src/math/generic/scalbn.rs diff --git a/library/compiler-builtins/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/libm/src/math/generic/sqrt.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/generic/sqrt.rs rename to library/compiler-builtins/libm/libm/src/math/generic/sqrt.rs diff --git a/library/compiler-builtins/libm/src/math/generic/trunc.rs b/library/compiler-builtins/libm/libm/src/math/generic/trunc.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/generic/trunc.rs rename to library/compiler-builtins/libm/libm/src/math/generic/trunc.rs diff --git a/library/compiler-builtins/libm/src/math/hypot.rs b/library/compiler-builtins/libm/libm/src/math/hypot.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/hypot.rs rename to library/compiler-builtins/libm/libm/src/math/hypot.rs diff --git a/library/compiler-builtins/libm/src/math/hypotf.rs b/library/compiler-builtins/libm/libm/src/math/hypotf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/hypotf.rs rename to library/compiler-builtins/libm/libm/src/math/hypotf.rs diff --git a/library/compiler-builtins/libm/src/math/ilogb.rs b/library/compiler-builtins/libm/libm/src/math/ilogb.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/ilogb.rs rename to library/compiler-builtins/libm/libm/src/math/ilogb.rs diff --git a/library/compiler-builtins/libm/src/math/ilogbf.rs b/library/compiler-builtins/libm/libm/src/math/ilogbf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/ilogbf.rs rename to library/compiler-builtins/libm/libm/src/math/ilogbf.rs diff --git a/library/compiler-builtins/libm/src/math/j0.rs b/library/compiler-builtins/libm/libm/src/math/j0.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/j0.rs rename to library/compiler-builtins/libm/libm/src/math/j0.rs diff --git a/library/compiler-builtins/libm/src/math/j0f.rs b/library/compiler-builtins/libm/libm/src/math/j0f.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/j0f.rs rename to library/compiler-builtins/libm/libm/src/math/j0f.rs diff --git a/library/compiler-builtins/libm/src/math/j1.rs b/library/compiler-builtins/libm/libm/src/math/j1.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/j1.rs rename to library/compiler-builtins/libm/libm/src/math/j1.rs diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/libm/src/math/j1f.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/j1f.rs rename to library/compiler-builtins/libm/libm/src/math/j1f.rs diff --git a/library/compiler-builtins/libm/src/math/jn.rs b/library/compiler-builtins/libm/libm/src/math/jn.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/jn.rs rename to library/compiler-builtins/libm/libm/src/math/jn.rs diff --git a/library/compiler-builtins/libm/src/math/jnf.rs b/library/compiler-builtins/libm/libm/src/math/jnf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/jnf.rs rename to library/compiler-builtins/libm/libm/src/math/jnf.rs diff --git a/library/compiler-builtins/libm/src/math/k_cos.rs b/library/compiler-builtins/libm/libm/src/math/k_cos.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/k_cos.rs rename to library/compiler-builtins/libm/libm/src/math/k_cos.rs diff --git a/library/compiler-builtins/libm/src/math/k_cosf.rs b/library/compiler-builtins/libm/libm/src/math/k_cosf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/k_cosf.rs rename to library/compiler-builtins/libm/libm/src/math/k_cosf.rs diff --git a/library/compiler-builtins/libm/src/math/k_expo2.rs b/library/compiler-builtins/libm/libm/src/math/k_expo2.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/k_expo2.rs rename to library/compiler-builtins/libm/libm/src/math/k_expo2.rs diff --git a/library/compiler-builtins/libm/src/math/k_expo2f.rs b/library/compiler-builtins/libm/libm/src/math/k_expo2f.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/k_expo2f.rs rename to library/compiler-builtins/libm/libm/src/math/k_expo2f.rs diff --git a/library/compiler-builtins/libm/src/math/k_sin.rs b/library/compiler-builtins/libm/libm/src/math/k_sin.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/k_sin.rs rename to library/compiler-builtins/libm/libm/src/math/k_sin.rs diff --git a/library/compiler-builtins/libm/src/math/k_sinf.rs b/library/compiler-builtins/libm/libm/src/math/k_sinf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/k_sinf.rs rename to library/compiler-builtins/libm/libm/src/math/k_sinf.rs diff --git a/library/compiler-builtins/libm/src/math/k_tan.rs b/library/compiler-builtins/libm/libm/src/math/k_tan.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/k_tan.rs rename to library/compiler-builtins/libm/libm/src/math/k_tan.rs diff --git a/library/compiler-builtins/libm/src/math/k_tanf.rs b/library/compiler-builtins/libm/libm/src/math/k_tanf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/k_tanf.rs rename to library/compiler-builtins/libm/libm/src/math/k_tanf.rs diff --git a/library/compiler-builtins/libm/src/math/ldexp.rs b/library/compiler-builtins/libm/libm/src/math/ldexp.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/ldexp.rs rename to library/compiler-builtins/libm/libm/src/math/ldexp.rs diff --git a/library/compiler-builtins/libm/libm/src/math/ldexpf.rs b/library/compiler-builtins/libm/libm/src/math/ldexpf.rs new file mode 100644 index 0000000000000..95b27fc49d28e --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/ldexpf.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf(x: f32, n: i32) -> f32 { + super::scalbnf(x, n) +} diff --git a/library/compiler-builtins/libm/libm/src/math/ldexpf128.rs b/library/compiler-builtins/libm/libm/src/math/ldexpf128.rs new file mode 100644 index 0000000000000..b35277d15fbae --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/ldexpf128.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf128(x: f128, n: i32) -> f128 { + super::scalbnf128(x, n) +} diff --git a/library/compiler-builtins/libm/libm/src/math/ldexpf16.rs b/library/compiler-builtins/libm/libm/src/math/ldexpf16.rs new file mode 100644 index 0000000000000..8de6cffd69987 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/ldexpf16.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn ldexpf16(x: f16, n: i32) -> f16 { + super::scalbnf16(x, n) +} diff --git a/library/compiler-builtins/libm/src/math/lgamma.rs b/library/compiler-builtins/libm/libm/src/math/lgamma.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/lgamma.rs rename to library/compiler-builtins/libm/libm/src/math/lgamma.rs diff --git a/library/compiler-builtins/libm/src/math/lgamma_r.rs b/library/compiler-builtins/libm/libm/src/math/lgamma_r.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/lgamma_r.rs rename to library/compiler-builtins/libm/libm/src/math/lgamma_r.rs diff --git a/library/compiler-builtins/libm/src/math/lgammaf.rs b/library/compiler-builtins/libm/libm/src/math/lgammaf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/lgammaf.rs rename to library/compiler-builtins/libm/libm/src/math/lgammaf.rs diff --git a/library/compiler-builtins/libm/src/math/lgammaf_r.rs b/library/compiler-builtins/libm/libm/src/math/lgammaf_r.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/lgammaf_r.rs rename to library/compiler-builtins/libm/libm/src/math/lgammaf_r.rs diff --git a/library/compiler-builtins/libm/src/math/log.rs b/library/compiler-builtins/libm/libm/src/math/log.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/log.rs rename to library/compiler-builtins/libm/libm/src/math/log.rs diff --git a/library/compiler-builtins/libm/src/math/log10.rs b/library/compiler-builtins/libm/libm/src/math/log10.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/log10.rs rename to library/compiler-builtins/libm/libm/src/math/log10.rs diff --git a/library/compiler-builtins/libm/src/math/log10f.rs b/library/compiler-builtins/libm/libm/src/math/log10f.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/log10f.rs rename to library/compiler-builtins/libm/libm/src/math/log10f.rs diff --git a/library/compiler-builtins/libm/src/math/log1p.rs b/library/compiler-builtins/libm/libm/src/math/log1p.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/log1p.rs rename to library/compiler-builtins/libm/libm/src/math/log1p.rs diff --git a/library/compiler-builtins/libm/src/math/log1pf.rs b/library/compiler-builtins/libm/libm/src/math/log1pf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/log1pf.rs rename to library/compiler-builtins/libm/libm/src/math/log1pf.rs diff --git a/library/compiler-builtins/libm/src/math/log2.rs b/library/compiler-builtins/libm/libm/src/math/log2.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/log2.rs rename to library/compiler-builtins/libm/libm/src/math/log2.rs diff --git a/library/compiler-builtins/libm/src/math/log2f.rs b/library/compiler-builtins/libm/libm/src/math/log2f.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/log2f.rs rename to library/compiler-builtins/libm/libm/src/math/log2f.rs diff --git a/library/compiler-builtins/libm/src/math/logf.rs b/library/compiler-builtins/libm/libm/src/math/logf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/logf.rs rename to library/compiler-builtins/libm/libm/src/math/logf.rs diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/libm/src/math/mod.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/mod.rs rename to library/compiler-builtins/libm/libm/src/math/mod.rs diff --git a/library/compiler-builtins/libm/src/math/modf.rs b/library/compiler-builtins/libm/libm/src/math/modf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/modf.rs rename to library/compiler-builtins/libm/libm/src/math/modf.rs diff --git a/library/compiler-builtins/libm/src/math/modff.rs b/library/compiler-builtins/libm/libm/src/math/modff.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/modff.rs rename to library/compiler-builtins/libm/libm/src/math/modff.rs diff --git a/library/compiler-builtins/libm/src/math/nextafter.rs b/library/compiler-builtins/libm/libm/src/math/nextafter.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/nextafter.rs rename to library/compiler-builtins/libm/libm/src/math/nextafter.rs diff --git a/library/compiler-builtins/libm/src/math/nextafterf.rs b/library/compiler-builtins/libm/libm/src/math/nextafterf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/nextafterf.rs rename to library/compiler-builtins/libm/libm/src/math/nextafterf.rs diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/libm/src/math/pow.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/pow.rs rename to library/compiler-builtins/libm/libm/src/math/pow.rs diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/libm/src/math/powf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/powf.rs rename to library/compiler-builtins/libm/libm/src/math/powf.rs diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/libm/src/math/rem_pio2.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/rem_pio2.rs rename to library/compiler-builtins/libm/libm/src/math/rem_pio2.rs diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/libm/src/math/rem_pio2_large.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/rem_pio2_large.rs rename to library/compiler-builtins/libm/libm/src/math/rem_pio2_large.rs diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/libm/src/math/rem_pio2f.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/rem_pio2f.rs rename to library/compiler-builtins/libm/libm/src/math/rem_pio2f.rs diff --git a/library/compiler-builtins/libm/src/math/remainder.rs b/library/compiler-builtins/libm/libm/src/math/remainder.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/remainder.rs rename to library/compiler-builtins/libm/libm/src/math/remainder.rs diff --git a/library/compiler-builtins/libm/src/math/remainderf.rs b/library/compiler-builtins/libm/libm/src/math/remainderf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/remainderf.rs rename to library/compiler-builtins/libm/libm/src/math/remainderf.rs diff --git a/library/compiler-builtins/libm/src/math/remquo.rs b/library/compiler-builtins/libm/libm/src/math/remquo.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/remquo.rs rename to library/compiler-builtins/libm/libm/src/math/remquo.rs diff --git a/library/compiler-builtins/libm/src/math/remquof.rs b/library/compiler-builtins/libm/libm/src/math/remquof.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/remquof.rs rename to library/compiler-builtins/libm/libm/src/math/remquof.rs diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/libm/src/math/rint.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/rint.rs rename to library/compiler-builtins/libm/libm/src/math/rint.rs diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/libm/src/math/round.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/round.rs rename to library/compiler-builtins/libm/libm/src/math/round.rs diff --git a/library/compiler-builtins/libm/src/math/roundeven.rs b/library/compiler-builtins/libm/libm/src/math/roundeven.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/roundeven.rs rename to library/compiler-builtins/libm/libm/src/math/roundeven.rs diff --git a/library/compiler-builtins/libm/libm/src/math/roundf.rs b/library/compiler-builtins/libm/libm/src/math/roundf.rs new file mode 100644 index 0000000000000..b5d7c9d693e71 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/roundf.rs @@ -0,0 +1,5 @@ +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf(x: f32) -> f32 { + super::generic::round(x) +} diff --git a/library/compiler-builtins/libm/libm/src/math/roundf128.rs b/library/compiler-builtins/libm/libm/src/math/roundf128.rs new file mode 100644 index 0000000000000..fc3164929fe4f --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/roundf128.rs @@ -0,0 +1,5 @@ +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf128(x: f128) -> f128 { + super::generic::round(x) +} diff --git a/library/compiler-builtins/libm/libm/src/math/roundf16.rs b/library/compiler-builtins/libm/libm/src/math/roundf16.rs new file mode 100644 index 0000000000000..8b356eaabeecd --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/roundf16.rs @@ -0,0 +1,5 @@ +/// Round `x` to the nearest integer, breaking ties away from zero. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundf16(x: f16) -> f16 { + super::generic::round(x) +} diff --git a/library/compiler-builtins/libm/src/math/scalbn.rs b/library/compiler-builtins/libm/libm/src/math/scalbn.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/scalbn.rs rename to library/compiler-builtins/libm/libm/src/math/scalbn.rs diff --git a/library/compiler-builtins/libm/libm/src/math/scalbnf.rs b/library/compiler-builtins/libm/libm/src/math/scalbnf.rs new file mode 100644 index 0000000000000..57e7ba76f60b5 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/scalbnf.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf(x: f32, n: i32) -> f32 { + super::generic::scalbn(x, n) +} diff --git a/library/compiler-builtins/libm/libm/src/math/scalbnf128.rs b/library/compiler-builtins/libm/libm/src/math/scalbnf128.rs new file mode 100644 index 0000000000000..c1d2b48558568 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/scalbnf128.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf128(x: f128, n: i32) -> f128 { + super::generic::scalbn(x, n) +} diff --git a/library/compiler-builtins/libm/libm/src/math/scalbnf16.rs b/library/compiler-builtins/libm/libm/src/math/scalbnf16.rs new file mode 100644 index 0000000000000..2209e1a179566 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/scalbnf16.rs @@ -0,0 +1,4 @@ +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn scalbnf16(x: f16, n: i32) -> f16 { + super::generic::scalbn(x, n) +} diff --git a/library/compiler-builtins/libm/src/math/sin.rs b/library/compiler-builtins/libm/libm/src/math/sin.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/sin.rs rename to library/compiler-builtins/libm/libm/src/math/sin.rs diff --git a/library/compiler-builtins/libm/src/math/sincos.rs b/library/compiler-builtins/libm/libm/src/math/sincos.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/sincos.rs rename to library/compiler-builtins/libm/libm/src/math/sincos.rs diff --git a/library/compiler-builtins/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/libm/src/math/sincosf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/sincosf.rs rename to library/compiler-builtins/libm/libm/src/math/sincosf.rs diff --git a/library/compiler-builtins/libm/src/math/sinf.rs b/library/compiler-builtins/libm/libm/src/math/sinf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/sinf.rs rename to library/compiler-builtins/libm/libm/src/math/sinf.rs diff --git a/library/compiler-builtins/libm/src/math/sinh.rs b/library/compiler-builtins/libm/libm/src/math/sinh.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/sinh.rs rename to library/compiler-builtins/libm/libm/src/math/sinh.rs diff --git a/library/compiler-builtins/libm/src/math/sinhf.rs b/library/compiler-builtins/libm/libm/src/math/sinhf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/sinhf.rs rename to library/compiler-builtins/libm/libm/src/math/sinhf.rs diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/libm/src/math/sqrt.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/sqrt.rs rename to library/compiler-builtins/libm/libm/src/math/sqrt.rs diff --git a/library/compiler-builtins/libm/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/libm/src/math/sqrtf.rs new file mode 100644 index 0000000000000..c28a705e378e6 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/sqrtf.rs @@ -0,0 +1,15 @@ +/// The square root of `x` (f32). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf(x: f32) -> f32 { + select_implementation! { + name: sqrtf, + use_arch: any( + all(target_arch = "aarch64", target_feature = "neon"), + all(target_arch = "wasm32", intrinsics_enabled), + target_feature = "sse2" + ), + args: x, + } + + super::generic::sqrt(x) +} diff --git a/library/compiler-builtins/libm/libm/src/math/sqrtf128.rs b/library/compiler-builtins/libm/libm/src/math/sqrtf128.rs new file mode 100644 index 0000000000000..eaef6ae0c1c85 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/sqrtf128.rs @@ -0,0 +1,5 @@ +/// The square root of `x` (f128). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf128(x: f128) -> f128 { + return super::generic::sqrt(x); +} diff --git a/library/compiler-builtins/libm/libm/src/math/sqrtf16.rs b/library/compiler-builtins/libm/libm/src/math/sqrtf16.rs new file mode 100644 index 0000000000000..7bedb7f8bbb6b --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/sqrtf16.rs @@ -0,0 +1,11 @@ +/// The square root of `x` (f16). +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn sqrtf16(x: f16) -> f16 { + select_implementation! { + name: sqrtf16, + use_arch: all(target_arch = "aarch64", target_feature = "fp16"), + args: x, + } + + return super::generic::sqrt(x); +} diff --git a/library/compiler-builtins/libm/src/math/support/big.rs b/library/compiler-builtins/libm/libm/src/math/support/big.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/support/big.rs rename to library/compiler-builtins/libm/libm/src/math/support/big.rs diff --git a/library/compiler-builtins/libm/src/math/support/big/tests.rs b/library/compiler-builtins/libm/libm/src/math/support/big/tests.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/support/big/tests.rs rename to library/compiler-builtins/libm/libm/src/math/support/big/tests.rs diff --git a/library/compiler-builtins/libm/src/math/support/env.rs b/library/compiler-builtins/libm/libm/src/math/support/env.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/support/env.rs rename to library/compiler-builtins/libm/libm/src/math/support/env.rs diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/libm/src/math/support/float_traits.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/support/float_traits.rs rename to library/compiler-builtins/libm/libm/src/math/support/float_traits.rs diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/libm/src/math/support/hex_float.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/support/hex_float.rs rename to library/compiler-builtins/libm/libm/src/math/support/hex_float.rs diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/libm/src/math/support/int_traits.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/support/int_traits.rs rename to library/compiler-builtins/libm/libm/src/math/support/int_traits.rs diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/libm/src/math/support/macros.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/support/macros.rs rename to library/compiler-builtins/libm/libm/src/math/support/macros.rs diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/libm/src/math/support/mod.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/support/mod.rs rename to library/compiler-builtins/libm/libm/src/math/support/mod.rs diff --git a/library/compiler-builtins/libm/src/math/tan.rs b/library/compiler-builtins/libm/libm/src/math/tan.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/tan.rs rename to library/compiler-builtins/libm/libm/src/math/tan.rs diff --git a/library/compiler-builtins/libm/src/math/tanf.rs b/library/compiler-builtins/libm/libm/src/math/tanf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/tanf.rs rename to library/compiler-builtins/libm/libm/src/math/tanf.rs diff --git a/library/compiler-builtins/libm/src/math/tanh.rs b/library/compiler-builtins/libm/libm/src/math/tanh.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/tanh.rs rename to library/compiler-builtins/libm/libm/src/math/tanh.rs diff --git a/library/compiler-builtins/libm/src/math/tanhf.rs b/library/compiler-builtins/libm/libm/src/math/tanhf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/tanhf.rs rename to library/compiler-builtins/libm/libm/src/math/tanhf.rs diff --git a/library/compiler-builtins/libm/src/math/tgamma.rs b/library/compiler-builtins/libm/libm/src/math/tgamma.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/tgamma.rs rename to library/compiler-builtins/libm/libm/src/math/tgamma.rs diff --git a/library/compiler-builtins/libm/src/math/tgammaf.rs b/library/compiler-builtins/libm/libm/src/math/tgammaf.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/tgammaf.rs rename to library/compiler-builtins/libm/libm/src/math/tgammaf.rs diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/libm/src/math/trunc.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/trunc.rs rename to library/compiler-builtins/libm/libm/src/math/trunc.rs diff --git a/library/compiler-builtins/libm/libm/src/math/truncf.rs b/library/compiler-builtins/libm/libm/src/math/truncf.rs new file mode 100644 index 0000000000000..14533a2670632 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/truncf.rs @@ -0,0 +1,23 @@ +/// Rounds the number toward 0 to the closest integral value (f32). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf(x: f32) -> f32 { + select_implementation! { + name: truncf, + use_arch: all(target_arch = "wasm32", intrinsics_enabled), + args: x, + } + + super::generic::trunc(x) +} + +// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 +#[cfg(not(target_arch = "powerpc64"))] +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::truncf(1.1), 1.0); + } +} diff --git a/library/compiler-builtins/libm/libm/src/math/truncf128.rs b/library/compiler-builtins/libm/libm/src/math/truncf128.rs new file mode 100644 index 0000000000000..9dccc0d0e9d7f --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/truncf128.rs @@ -0,0 +1,7 @@ +/// Rounds the number toward 0 to the closest integral value (f128). +/// +/// This effectively removes the decimal part of the number, leaving the integral part. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf128(x: f128) -> f128 { + super::generic::trunc(x) +} diff --git a/library/compiler-builtins/libm/libm/src/math/truncf16.rs b/library/compiler-builtins/libm/libm/src/math/truncf16.rs new file mode 100644 index 0000000000000..d7c3d225cf9b8 --- /dev/null +++ b/library/compiler-builtins/libm/libm/src/math/truncf16.rs @@ -0,0 +1,7 @@ +/// 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_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn truncf16(x: f16) -> f16 { + super::generic::trunc(x) +} From 3a0b9c9f51ebfae460d1014080dfe20388fa9d29 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 9 Apr 2025 01:21:44 +0000 Subject: [PATCH 1823/4206] refactor: Introduce a virtual manifest Move the workspace configuration to a virtual manifest. This reorganization makes a more clear separation between package contents and support files that don't get distributed. It will also make it easier to merge this repository with `compiler-builtins` which is planned (builtins had a similar update done in [1]). LICENSE.txt and README.md are symlinkedinto the new directory to ensure they get included in the package. [1]: https://github.com/rust-lang/compiler-builtins/pull/702 --- library/compiler-builtins/libm/Cargo.toml | 37 ++ library/compiler-builtins/libm/ci/ci-util.py | 2 +- .../libm/etc/function-definitions.json | 502 +++++++++--------- .../libm/etc/update-api-list.py | 26 +- .../compiler-builtins/libm/libm/Cargo.toml | 38 -- .../compiler-builtins/libm/libm/LICENSE.txt | 1 + library/compiler-builtins/libm/libm/README.md | 1 + 7 files changed, 305 insertions(+), 302 deletions(-) create mode 100644 library/compiler-builtins/libm/Cargo.toml create mode 120000 library/compiler-builtins/libm/libm/LICENSE.txt create mode 120000 library/compiler-builtins/libm/libm/README.md diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml new file mode 100644 index 0000000000000..268b6fb0e6dfa --- /dev/null +++ b/library/compiler-builtins/libm/Cargo.toml @@ -0,0 +1,37 @@ +[workspace] +resolver = "2" +members = [ + "libm", + "crates/libm-macros", + "crates/libm-test", + "crates/musl-math-sys", + "crates/util", +] +default-members = [ + "libm", + "crates/libm-macros", + "crates/libm-test" +] +exclude = [ + # Requires `panic = abort` so can't be a member of the workspace + "crates/compiler-builtins-smoke-test", +] + +# The default release profile is unchanged. + +# Release mode with debug assertions +[profile.release-checked] +inherits = "release" +debug-assertions = true +overflow-checks = true + +# Release with maximum optimizations, which is very slow to build. This is also +# what is needed to check `no-panic`. +[profile.release-opt] +inherits = "release" +codegen-units = 1 +lto = "fat" + +[profile.bench] +# Required for iai-callgrind +debug = true diff --git a/library/compiler-builtins/libm/ci/ci-util.py b/library/compiler-builtins/libm/ci/ci-util.py index ed63d6deea1e9..d9e402d6bd711 100755 --- a/library/compiler-builtins/libm/ci/ci-util.py +++ b/library/compiler-builtins/libm/ci/ci-util.py @@ -25,7 +25,7 @@ COMMAND: generate-matrix Calculate a matrix of which functions had source change, print that as - a JSON object. + a JSON object. locate-baseline [--download] [--extract] Locate the most recent benchmark baseline available in CI and, if flags diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index ead1f807fc92d..3e33343c4647e 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -2,1067 +2,1067 @@ "__comment": "Autogenerated by update-api-list.py. List of files that define a function with a given name. This file is checked in to make it obvious if refactoring breaks things", "acos": { "sources": [ - "src/math/acos.rs" + "libm/src/math/acos.rs" ], "type": "f64" }, "acosf": { "sources": [ - "src/math/acosf.rs" + "libm/src/math/acosf.rs" ], "type": "f32" }, "acosh": { "sources": [ - "src/math/acosh.rs" + "libm/src/math/acosh.rs" ], "type": "f64" }, "acoshf": { "sources": [ - "src/math/acoshf.rs" + "libm/src/math/acoshf.rs" ], "type": "f32" }, "asin": { "sources": [ - "src/math/asin.rs" + "libm/src/math/asin.rs" ], "type": "f64" }, "asinf": { "sources": [ - "src/math/asinf.rs" + "libm/src/math/asinf.rs" ], "type": "f32" }, "asinh": { "sources": [ - "src/math/asinh.rs" + "libm/src/math/asinh.rs" ], "type": "f64" }, "asinhf": { "sources": [ - "src/math/asinhf.rs" + "libm/src/math/asinhf.rs" ], "type": "f32" }, "atan": { "sources": [ - "src/math/atan.rs" + "libm/src/math/atan.rs" ], "type": "f64" }, "atan2": { "sources": [ - "src/math/atan2.rs" + "libm/src/math/atan2.rs" ], "type": "f64" }, "atan2f": { "sources": [ - "src/math/atan2f.rs" + "libm/src/math/atan2f.rs" ], "type": "f32" }, "atanf": { "sources": [ - "src/math/atanf.rs" + "libm/src/math/atanf.rs" ], "type": "f32" }, "atanh": { "sources": [ - "src/math/atanh.rs" + "libm/src/math/atanh.rs" ], "type": "f64" }, "atanhf": { "sources": [ - "src/math/atanhf.rs" + "libm/src/math/atanhf.rs" ], "type": "f32" }, "cbrt": { "sources": [ - "src/math/cbrt.rs" + "libm/src/math/cbrt.rs" ], "type": "f64" }, "cbrtf": { "sources": [ - "src/math/cbrtf.rs" + "libm/src/math/cbrtf.rs" ], "type": "f32" }, "ceil": { "sources": [ - "src/math/arch/i586.rs", - "src/math/arch/wasm32.rs", - "src/math/ceil.rs", - "src/math/generic/ceil.rs" + "libm/src/math/arch/i586.rs", + "libm/src/math/arch/wasm32.rs", + "libm/src/math/ceil.rs", + "libm/src/math/generic/ceil.rs" ], "type": "f64" }, "ceilf": { "sources": [ - "src/math/arch/wasm32.rs", - "src/math/ceil.rs", - "src/math/generic/ceil.rs" + "libm/src/math/arch/wasm32.rs", + "libm/src/math/ceil.rs", + "libm/src/math/generic/ceil.rs" ], "type": "f32" }, "ceilf128": { "sources": [ - "src/math/ceil.rs", - "src/math/generic/ceil.rs" + "libm/src/math/ceil.rs", + "libm/src/math/generic/ceil.rs" ], "type": "f128" }, "ceilf16": { "sources": [ - "src/math/ceil.rs", - "src/math/generic/ceil.rs" + "libm/src/math/ceil.rs", + "libm/src/math/generic/ceil.rs" ], "type": "f16" }, "copysign": { "sources": [ - "src/math/copysign.rs", - "src/math/generic/copysign.rs" + "libm/src/math/copysign.rs", + "libm/src/math/generic/copysign.rs" ], "type": "f64" }, "copysignf": { "sources": [ - "src/math/copysign.rs", - "src/math/generic/copysign.rs" + "libm/src/math/copysign.rs", + "libm/src/math/generic/copysign.rs" ], "type": "f32" }, "copysignf128": { "sources": [ - "src/math/copysign.rs", - "src/math/generic/copysign.rs" + "libm/src/math/copysign.rs", + "libm/src/math/generic/copysign.rs" ], "type": "f128" }, "copysignf16": { "sources": [ - "src/math/copysign.rs", - "src/math/generic/copysign.rs" + "libm/src/math/copysign.rs", + "libm/src/math/generic/copysign.rs" ], "type": "f16" }, "cos": { "sources": [ - "src/math/cos.rs" + "libm/src/math/cos.rs" ], "type": "f64" }, "cosf": { "sources": [ - "src/math/cosf.rs" + "libm/src/math/cosf.rs" ], "type": "f32" }, "cosh": { "sources": [ - "src/math/cosh.rs" + "libm/src/math/cosh.rs" ], "type": "f64" }, "coshf": { "sources": [ - "src/math/coshf.rs" + "libm/src/math/coshf.rs" ], "type": "f32" }, "erf": { "sources": [ - "src/math/erf.rs" + "libm/src/math/erf.rs" ], "type": "f64" }, "erfc": { "sources": [ - "src/math/erf.rs" + "libm/src/math/erf.rs" ], "type": "f64" }, "erfcf": { "sources": [ - "src/math/erff.rs" + "libm/src/math/erff.rs" ], "type": "f32" }, "erff": { "sources": [ - "src/math/erff.rs" + "libm/src/math/erff.rs" ], "type": "f32" }, "exp": { "sources": [ - "src/math/exp.rs" + "libm/src/math/exp.rs" ], "type": "f64" }, "exp10": { "sources": [ - "src/math/exp10.rs" + "libm/src/math/exp10.rs" ], "type": "f64" }, "exp10f": { "sources": [ - "src/math/exp10f.rs" + "libm/src/math/exp10f.rs" ], "type": "f32" }, "exp2": { "sources": [ - "src/math/exp2.rs" + "libm/src/math/exp2.rs" ], "type": "f64" }, "exp2f": { "sources": [ - "src/math/exp2f.rs" + "libm/src/math/exp2f.rs" ], "type": "f32" }, "expf": { "sources": [ - "src/math/expf.rs" + "libm/src/math/expf.rs" ], "type": "f32" }, "expm1": { "sources": [ - "src/math/expm1.rs" + "libm/src/math/expm1.rs" ], "type": "f64" }, "expm1f": { "sources": [ - "src/math/expm1f.rs" + "libm/src/math/expm1f.rs" ], "type": "f32" }, "fabs": { "sources": [ - "src/math/arch/wasm32.rs", - "src/math/fabs.rs", - "src/math/generic/fabs.rs" + "libm/src/math/arch/wasm32.rs", + "libm/src/math/fabs.rs", + "libm/src/math/generic/fabs.rs" ], "type": "f64" }, "fabsf": { "sources": [ - "src/math/arch/wasm32.rs", - "src/math/fabs.rs", - "src/math/generic/fabs.rs" + "libm/src/math/arch/wasm32.rs", + "libm/src/math/fabs.rs", + "libm/src/math/generic/fabs.rs" ], "type": "f32" }, "fabsf128": { "sources": [ - "src/math/fabs.rs", - "src/math/generic/fabs.rs" + "libm/src/math/fabs.rs", + "libm/src/math/generic/fabs.rs" ], "type": "f128" }, "fabsf16": { "sources": [ - "src/math/fabs.rs", - "src/math/generic/fabs.rs" + "libm/src/math/fabs.rs", + "libm/src/math/generic/fabs.rs" ], "type": "f16" }, "fdim": { "sources": [ - "src/math/fdim.rs", - "src/math/generic/fdim.rs" + "libm/src/math/fdim.rs", + "libm/src/math/generic/fdim.rs" ], "type": "f64" }, "fdimf": { "sources": [ - "src/math/fdim.rs", - "src/math/generic/fdim.rs" + "libm/src/math/fdim.rs", + "libm/src/math/generic/fdim.rs" ], "type": "f32" }, "fdimf128": { "sources": [ - "src/math/fdim.rs", - "src/math/generic/fdim.rs" + "libm/src/math/fdim.rs", + "libm/src/math/generic/fdim.rs" ], "type": "f128" }, "fdimf16": { "sources": [ - "src/math/fdim.rs", - "src/math/generic/fdim.rs" + "libm/src/math/fdim.rs", + "libm/src/math/generic/fdim.rs" ], "type": "f16" }, "floor": { "sources": [ - "src/math/arch/i586.rs", - "src/math/arch/wasm32.rs", - "src/math/floor.rs", - "src/math/generic/floor.rs" + "libm/src/math/arch/i586.rs", + "libm/src/math/arch/wasm32.rs", + "libm/src/math/floor.rs", + "libm/src/math/generic/floor.rs" ], "type": "f64" }, "floorf": { "sources": [ - "src/math/arch/wasm32.rs", - "src/math/floor.rs", - "src/math/generic/floor.rs" + "libm/src/math/arch/wasm32.rs", + "libm/src/math/floor.rs", + "libm/src/math/generic/floor.rs" ], "type": "f32" }, "floorf128": { "sources": [ - "src/math/floor.rs", - "src/math/generic/floor.rs" + "libm/src/math/floor.rs", + "libm/src/math/generic/floor.rs" ], "type": "f128" }, "floorf16": { "sources": [ - "src/math/floor.rs", - "src/math/generic/floor.rs" + "libm/src/math/floor.rs", + "libm/src/math/generic/floor.rs" ], "type": "f16" }, "fma": { "sources": [ - "src/math/arch/aarch64.rs", - "src/math/fma.rs" + "libm/src/math/arch/aarch64.rs", + "libm/src/math/fma.rs" ], "type": "f64" }, "fmaf": { "sources": [ - "src/math/arch/aarch64.rs", - "src/math/fma_wide.rs" + "libm/src/math/arch/aarch64.rs", + "libm/src/math/fma_wide.rs" ], "type": "f32" }, "fmaf128": { "sources": [ - "src/math/fma.rs" + "libm/src/math/fma.rs" ], "type": "f128" }, "fmax": { "sources": [ - "src/math/fmin_fmax.rs", - "src/math/generic/fmax.rs" + "libm/src/math/fmin_fmax.rs", + "libm/src/math/generic/fmax.rs" ], "type": "f64" }, "fmaxf": { "sources": [ - "src/math/fmin_fmax.rs", - "src/math/generic/fmax.rs" + "libm/src/math/fmin_fmax.rs", + "libm/src/math/generic/fmax.rs" ], "type": "f32" }, "fmaxf128": { "sources": [ - "src/math/fmin_fmax.rs", - "src/math/generic/fmax.rs" + "libm/src/math/fmin_fmax.rs", + "libm/src/math/generic/fmax.rs" ], "type": "f128" }, "fmaxf16": { "sources": [ - "src/math/fmin_fmax.rs", - "src/math/generic/fmax.rs" + "libm/src/math/fmin_fmax.rs", + "libm/src/math/generic/fmax.rs" ], "type": "f16" }, "fmaximum": { "sources": [ - "src/math/fminimum_fmaximum.rs", - "src/math/generic/fmaximum.rs" + "libm/src/math/fminimum_fmaximum.rs", + "libm/src/math/generic/fmaximum.rs" ], "type": "f64" }, "fmaximum_num": { "sources": [ - "src/math/fminimum_fmaximum_num.rs", - "src/math/generic/fmaximum_num.rs" + "libm/src/math/fminimum_fmaximum_num.rs", + "libm/src/math/generic/fmaximum_num.rs" ], "type": "f64" }, "fmaximum_numf": { "sources": [ - "src/math/fminimum_fmaximum_num.rs", - "src/math/generic/fmaximum_num.rs" + "libm/src/math/fminimum_fmaximum_num.rs", + "libm/src/math/generic/fmaximum_num.rs" ], "type": "f32" }, "fmaximum_numf128": { "sources": [ - "src/math/fminimum_fmaximum_num.rs", - "src/math/generic/fmaximum_num.rs" + "libm/src/math/fminimum_fmaximum_num.rs", + "libm/src/math/generic/fmaximum_num.rs" ], "type": "f128" }, "fmaximum_numf16": { "sources": [ - "src/math/fminimum_fmaximum_num.rs", - "src/math/generic/fmaximum_num.rs" + "libm/src/math/fminimum_fmaximum_num.rs", + "libm/src/math/generic/fmaximum_num.rs" ], "type": "f16" }, "fmaximumf": { "sources": [ - "src/math/fminimum_fmaximum.rs", - "src/math/generic/fmaximum.rs" + "libm/src/math/fminimum_fmaximum.rs", + "libm/src/math/generic/fmaximum.rs" ], "type": "f32" }, "fmaximumf128": { "sources": [ - "src/math/fminimum_fmaximum.rs", - "src/math/generic/fmaximum.rs" + "libm/src/math/fminimum_fmaximum.rs", + "libm/src/math/generic/fmaximum.rs" ], "type": "f128" }, "fmaximumf16": { "sources": [ - "src/math/fminimum_fmaximum.rs", - "src/math/generic/fmaximum.rs" + "libm/src/math/fminimum_fmaximum.rs", + "libm/src/math/generic/fmaximum.rs" ], "type": "f16" }, "fmin": { "sources": [ - "src/math/fmin_fmax.rs", - "src/math/generic/fmin.rs" + "libm/src/math/fmin_fmax.rs", + "libm/src/math/generic/fmin.rs" ], "type": "f64" }, "fminf": { "sources": [ - "src/math/fmin_fmax.rs", - "src/math/generic/fmin.rs" + "libm/src/math/fmin_fmax.rs", + "libm/src/math/generic/fmin.rs" ], "type": "f32" }, "fminf128": { "sources": [ - "src/math/fmin_fmax.rs", - "src/math/generic/fmin.rs" + "libm/src/math/fmin_fmax.rs", + "libm/src/math/generic/fmin.rs" ], "type": "f128" }, "fminf16": { "sources": [ - "src/math/fmin_fmax.rs", - "src/math/generic/fmin.rs" + "libm/src/math/fmin_fmax.rs", + "libm/src/math/generic/fmin.rs" ], "type": "f16" }, "fminimum": { "sources": [ - "src/math/fminimum_fmaximum.rs", - "src/math/generic/fminimum.rs" + "libm/src/math/fminimum_fmaximum.rs", + "libm/src/math/generic/fminimum.rs" ], "type": "f64" }, "fminimum_num": { "sources": [ - "src/math/fminimum_fmaximum_num.rs", - "src/math/generic/fminimum_num.rs" + "libm/src/math/fminimum_fmaximum_num.rs", + "libm/src/math/generic/fminimum_num.rs" ], "type": "f64" }, "fminimum_numf": { "sources": [ - "src/math/fminimum_fmaximum_num.rs", - "src/math/generic/fminimum_num.rs" + "libm/src/math/fminimum_fmaximum_num.rs", + "libm/src/math/generic/fminimum_num.rs" ], "type": "f32" }, "fminimum_numf128": { "sources": [ - "src/math/fminimum_fmaximum_num.rs", - "src/math/generic/fminimum_num.rs" + "libm/src/math/fminimum_fmaximum_num.rs", + "libm/src/math/generic/fminimum_num.rs" ], "type": "f128" }, "fminimum_numf16": { "sources": [ - "src/math/fminimum_fmaximum_num.rs", - "src/math/generic/fminimum_num.rs" + "libm/src/math/fminimum_fmaximum_num.rs", + "libm/src/math/generic/fminimum_num.rs" ], "type": "f16" }, "fminimumf": { "sources": [ - "src/math/fminimum_fmaximum.rs", - "src/math/generic/fminimum.rs" + "libm/src/math/fminimum_fmaximum.rs", + "libm/src/math/generic/fminimum.rs" ], "type": "f32" }, "fminimumf128": { "sources": [ - "src/math/fminimum_fmaximum.rs", - "src/math/generic/fminimum.rs" + "libm/src/math/fminimum_fmaximum.rs", + "libm/src/math/generic/fminimum.rs" ], "type": "f128" }, "fminimumf16": { "sources": [ - "src/math/fminimum_fmaximum.rs", - "src/math/generic/fminimum.rs" + "libm/src/math/fminimum_fmaximum.rs", + "libm/src/math/generic/fminimum.rs" ], "type": "f16" }, "fmod": { "sources": [ - "src/math/fmod.rs", - "src/math/generic/fmod.rs" + "libm/src/math/fmod.rs", + "libm/src/math/generic/fmod.rs" ], "type": "f64" }, "fmodf": { "sources": [ - "src/math/fmod.rs", - "src/math/generic/fmod.rs" + "libm/src/math/fmod.rs", + "libm/src/math/generic/fmod.rs" ], "type": "f32" }, "fmodf128": { "sources": [ - "src/math/fmod.rs", - "src/math/generic/fmod.rs" + "libm/src/math/fmod.rs", + "libm/src/math/generic/fmod.rs" ], "type": "f128" }, "fmodf16": { "sources": [ - "src/math/fmod.rs", - "src/math/generic/fmod.rs" + "libm/src/math/fmod.rs", + "libm/src/math/generic/fmod.rs" ], "type": "f16" }, "frexp": { "sources": [ - "src/math/frexp.rs" + "libm/src/math/frexp.rs" ], "type": "f64" }, "frexpf": { "sources": [ - "src/math/frexpf.rs" + "libm/src/math/frexpf.rs" ], "type": "f32" }, "hypot": { "sources": [ - "src/math/hypot.rs" + "libm/src/math/hypot.rs" ], "type": "f64" }, "hypotf": { "sources": [ - "src/math/hypotf.rs" + "libm/src/math/hypotf.rs" ], "type": "f32" }, "ilogb": { "sources": [ - "src/math/ilogb.rs" + "libm/src/math/ilogb.rs" ], "type": "f64" }, "ilogbf": { "sources": [ - "src/math/ilogbf.rs" + "libm/src/math/ilogbf.rs" ], "type": "f32" }, "j0": { "sources": [ - "src/math/j0.rs" + "libm/src/math/j0.rs" ], "type": "f64" }, "j0f": { "sources": [ - "src/math/j0f.rs" + "libm/src/math/j0f.rs" ], "type": "f32" }, "j1": { "sources": [ - "src/math/j1.rs" + "libm/src/math/j1.rs" ], "type": "f64" }, "j1f": { "sources": [ - "src/math/j1f.rs" + "libm/src/math/j1f.rs" ], "type": "f32" }, "jn": { "sources": [ - "src/math/jn.rs" + "libm/src/math/jn.rs" ], "type": "f64" }, "jnf": { "sources": [ - "src/math/jnf.rs" + "libm/src/math/jnf.rs" ], "type": "f32" }, "ldexp": { "sources": [ - "src/math/ldexp.rs" + "libm/src/math/ldexp.rs" ], "type": "f64" }, "ldexpf": { "sources": [ - "src/math/ldexp.rs" + "libm/src/math/ldexp.rs" ], "type": "f32" }, "ldexpf128": { "sources": [ - "src/math/ldexp.rs" + "libm/src/math/ldexp.rs" ], "type": "f128" }, "ldexpf16": { "sources": [ - "src/math/ldexp.rs" + "libm/src/math/ldexp.rs" ], "type": "f16" }, "lgamma": { "sources": [ - "src/math/lgamma.rs" + "libm/src/math/lgamma.rs" ], "type": "f64" }, "lgamma_r": { "sources": [ - "src/math/lgamma_r.rs" + "libm/src/math/lgamma_r.rs" ], "type": "f64" }, "lgammaf": { "sources": [ - "src/math/lgammaf.rs" + "libm/src/math/lgammaf.rs" ], "type": "f32" }, "lgammaf_r": { "sources": [ - "src/math/lgammaf_r.rs" + "libm/src/math/lgammaf_r.rs" ], "type": "f32" }, "log": { "sources": [ - "src/math/log.rs" + "libm/src/math/log.rs" ], "type": "f64" }, "log10": { "sources": [ - "src/math/log10.rs" + "libm/src/math/log10.rs" ], "type": "f64" }, "log10f": { "sources": [ - "src/math/log10f.rs" + "libm/src/math/log10f.rs" ], "type": "f32" }, "log1p": { "sources": [ - "src/math/log1p.rs" + "libm/src/math/log1p.rs" ], "type": "f64" }, "log1pf": { "sources": [ - "src/math/log1pf.rs" + "libm/src/math/log1pf.rs" ], "type": "f32" }, "log2": { "sources": [ - "src/math/log2.rs" + "libm/src/math/log2.rs" ], "type": "f64" }, "log2f": { "sources": [ - "src/math/log2f.rs" + "libm/src/math/log2f.rs" ], "type": "f32" }, "logf": { "sources": [ - "src/math/logf.rs" + "libm/src/math/logf.rs" ], "type": "f32" }, "modf": { "sources": [ - "src/math/modf.rs" + "libm/src/math/modf.rs" ], "type": "f64" }, "modff": { "sources": [ - "src/math/modff.rs" + "libm/src/math/modff.rs" ], "type": "f32" }, "nextafter": { "sources": [ - "src/math/nextafter.rs" + "libm/src/math/nextafter.rs" ], "type": "f64" }, "nextafterf": { "sources": [ - "src/math/nextafterf.rs" + "libm/src/math/nextafterf.rs" ], "type": "f32" }, "pow": { "sources": [ - "src/math/pow.rs" + "libm/src/math/pow.rs" ], "type": "f64" }, "powf": { "sources": [ - "src/math/powf.rs" + "libm/src/math/powf.rs" ], "type": "f32" }, "remainder": { "sources": [ - "src/math/remainder.rs" + "libm/src/math/remainder.rs" ], "type": "f64" }, "remainderf": { "sources": [ - "src/math/remainderf.rs" + "libm/src/math/remainderf.rs" ], "type": "f32" }, "remquo": { "sources": [ - "src/math/remquo.rs" + "libm/src/math/remquo.rs" ], "type": "f64" }, "remquof": { "sources": [ - "src/math/remquof.rs" + "libm/src/math/remquof.rs" ], "type": "f32" }, "rint": { "sources": [ - "src/math/arch/aarch64.rs", - "src/math/arch/wasm32.rs", - "src/math/rint.rs" + "libm/src/math/arch/aarch64.rs", + "libm/src/math/arch/wasm32.rs", + "libm/src/math/rint.rs" ], "type": "f64" }, "rintf": { "sources": [ - "src/math/arch/aarch64.rs", - "src/math/arch/wasm32.rs", - "src/math/rint.rs" + "libm/src/math/arch/aarch64.rs", + "libm/src/math/arch/wasm32.rs", + "libm/src/math/rint.rs" ], "type": "f32" }, "rintf128": { "sources": [ - "src/math/rint.rs" + "libm/src/math/rint.rs" ], "type": "f128" }, "rintf16": { "sources": [ - "src/math/arch/aarch64.rs", - "src/math/rint.rs" + "libm/src/math/arch/aarch64.rs", + "libm/src/math/rint.rs" ], "type": "f16" }, "round": { "sources": [ - "src/math/generic/round.rs", - "src/math/round.rs" + "libm/src/math/generic/round.rs", + "libm/src/math/round.rs" ], "type": "f64" }, "roundeven": { "sources": [ - "src/math/roundeven.rs" + "libm/src/math/roundeven.rs" ], "type": "f64" }, "roundevenf": { "sources": [ - "src/math/roundeven.rs" + "libm/src/math/roundeven.rs" ], "type": "f32" }, "roundevenf128": { "sources": [ - "src/math/roundeven.rs" + "libm/src/math/roundeven.rs" ], "type": "f128" }, "roundevenf16": { "sources": [ - "src/math/roundeven.rs" + "libm/src/math/roundeven.rs" ], "type": "f16" }, "roundf": { "sources": [ - "src/math/generic/round.rs", - "src/math/round.rs" + "libm/src/math/generic/round.rs", + "libm/src/math/round.rs" ], "type": "f32" }, "roundf128": { "sources": [ - "src/math/generic/round.rs", - "src/math/round.rs" + "libm/src/math/generic/round.rs", + "libm/src/math/round.rs" ], "type": "f128" }, "roundf16": { "sources": [ - "src/math/generic/round.rs", - "src/math/round.rs" + "libm/src/math/generic/round.rs", + "libm/src/math/round.rs" ], "type": "f16" }, "scalbn": { "sources": [ - "src/math/generic/scalbn.rs", - "src/math/scalbn.rs" + "libm/src/math/generic/scalbn.rs", + "libm/src/math/scalbn.rs" ], "type": "f64" }, "scalbnf": { "sources": [ - "src/math/generic/scalbn.rs", - "src/math/scalbn.rs" + "libm/src/math/generic/scalbn.rs", + "libm/src/math/scalbn.rs" ], "type": "f32" }, "scalbnf128": { "sources": [ - "src/math/generic/scalbn.rs", - "src/math/scalbn.rs" + "libm/src/math/generic/scalbn.rs", + "libm/src/math/scalbn.rs" ], "type": "f128" }, "scalbnf16": { "sources": [ - "src/math/generic/scalbn.rs", - "src/math/scalbn.rs" + "libm/src/math/generic/scalbn.rs", + "libm/src/math/scalbn.rs" ], "type": "f16" }, "sin": { "sources": [ - "src/math/sin.rs" + "libm/src/math/sin.rs" ], "type": "f64" }, "sincos": { "sources": [ - "src/math/sincos.rs" + "libm/src/math/sincos.rs" ], "type": "f64" }, "sincosf": { "sources": [ - "src/math/sincosf.rs" + "libm/src/math/sincosf.rs" ], "type": "f32" }, "sinf": { "sources": [ - "src/math/sinf.rs" + "libm/src/math/sinf.rs" ], "type": "f32" }, "sinh": { "sources": [ - "src/math/sinh.rs" + "libm/src/math/sinh.rs" ], "type": "f64" }, "sinhf": { "sources": [ - "src/math/sinhf.rs" + "libm/src/math/sinhf.rs" ], "type": "f32" }, "sqrt": { "sources": [ - "src/math/arch/aarch64.rs", - "src/math/arch/i686.rs", - "src/math/arch/wasm32.rs", - "src/math/generic/sqrt.rs", - "src/math/sqrt.rs" + "libm/src/math/arch/aarch64.rs", + "libm/src/math/arch/i686.rs", + "libm/src/math/arch/wasm32.rs", + "libm/src/math/generic/sqrt.rs", + "libm/src/math/sqrt.rs" ], "type": "f64" }, "sqrtf": { "sources": [ - "src/math/arch/aarch64.rs", - "src/math/arch/i686.rs", - "src/math/arch/wasm32.rs", - "src/math/generic/sqrt.rs", - "src/math/sqrt.rs" + "libm/src/math/arch/aarch64.rs", + "libm/src/math/arch/i686.rs", + "libm/src/math/arch/wasm32.rs", + "libm/src/math/generic/sqrt.rs", + "libm/src/math/sqrt.rs" ], "type": "f32" }, "sqrtf128": { "sources": [ - "src/math/generic/sqrt.rs", - "src/math/sqrt.rs" + "libm/src/math/generic/sqrt.rs", + "libm/src/math/sqrt.rs" ], "type": "f128" }, "sqrtf16": { "sources": [ - "src/math/arch/aarch64.rs", - "src/math/generic/sqrt.rs", - "src/math/sqrt.rs" + "libm/src/math/arch/aarch64.rs", + "libm/src/math/generic/sqrt.rs", + "libm/src/math/sqrt.rs" ], "type": "f16" }, "tan": { "sources": [ - "src/math/tan.rs" + "libm/src/math/tan.rs" ], "type": "f64" }, "tanf": { "sources": [ - "src/math/tanf.rs" + "libm/src/math/tanf.rs" ], "type": "f32" }, "tanh": { "sources": [ - "src/math/tanh.rs" + "libm/src/math/tanh.rs" ], "type": "f64" }, "tanhf": { "sources": [ - "src/math/tanhf.rs" + "libm/src/math/tanhf.rs" ], "type": "f32" }, "tgamma": { "sources": [ - "src/math/tgamma.rs" + "libm/src/math/tgamma.rs" ], "type": "f64" }, "tgammaf": { "sources": [ - "src/math/tgammaf.rs" + "libm/src/math/tgammaf.rs" ], "type": "f32" }, "trunc": { "sources": [ - "src/math/arch/wasm32.rs", - "src/math/generic/trunc.rs", - "src/math/trunc.rs" + "libm/src/math/arch/wasm32.rs", + "libm/src/math/generic/trunc.rs", + "libm/src/math/trunc.rs" ], "type": "f64" }, "truncf": { "sources": [ - "src/math/arch/wasm32.rs", - "src/math/generic/trunc.rs", - "src/math/trunc.rs" + "libm/src/math/arch/wasm32.rs", + "libm/src/math/generic/trunc.rs", + "libm/src/math/trunc.rs" ], "type": "f32" }, "truncf128": { "sources": [ - "src/math/generic/trunc.rs", - "src/math/trunc.rs" + "libm/src/math/generic/trunc.rs", + "libm/src/math/trunc.rs" ], "type": "f128" }, "truncf16": { "sources": [ - "src/math/generic/trunc.rs", - "src/math/trunc.rs" + "libm/src/math/generic/trunc.rs", + "libm/src/math/trunc.rs" ], "type": "f16" }, "y0": { "sources": [ - "src/math/j0.rs" + "libm/src/math/j0.rs" ], "type": "f64" }, "y0f": { "sources": [ - "src/math/j0f.rs" + "libm/src/math/j0f.rs" ], "type": "f32" }, "y1": { "sources": [ - "src/math/j1.rs" + "libm/src/math/j1.rs" ], "type": "f64" }, "y1f": { "sources": [ - "src/math/j1f.rs" + "libm/src/math/j1f.rs" ], "type": "f32" }, "yn": { "sources": [ - "src/math/jn.rs" + "libm/src/math/jn.rs" ], "type": "f64" }, "ynf": { "sources": [ - "src/math/jnf.rs" + "libm/src/math/jnf.rs" ], "type": "f32" } diff --git a/library/compiler-builtins/libm/etc/update-api-list.py b/library/compiler-builtins/libm/etc/update-api-list.py index 950824fc442f8..0770a8b20fbe6 100755 --- a/library/compiler-builtins/libm/etc/update-api-list.py +++ b/library/compiler-builtins/libm/etc/update-api-list.py @@ -18,10 +18,10 @@ SELF_PATH = Path(__file__) ETC_DIR = SELF_PATH.parent -LIBM_DIR = ETC_DIR.parent.joinpath("libm") +ROOT_DIR = ETC_DIR.parent # These files do not trigger a retest. -IGNORED_SOURCES = ["src/libm_helper.rs", "src/math/support/float_traits.rs"] +IGNORED_SOURCES = ["libm/src/libm_helper.rs", "libm/src/math/support/float_traits.rs"] IndexTy: TypeAlias = dict[str, dict[str, Any]] """Type of the `index` item in rustdoc's JSON output""" @@ -66,7 +66,7 @@ def get_rustdoc_json() -> dict[Any, Any]: j = sp.check_output( [ "rustdoc", - "src/lib.rs", + "libm/src/lib.rs", "--edition=2021", "--document-private-items", "--output-format=json", @@ -75,7 +75,7 @@ def get_rustdoc_json() -> dict[Any, Any]: "-Zunstable-options", "-o-", ], - cwd=LIBM_DIR, + cwd=ROOT_DIR, text=True, ) j = json.loads(j) @@ -94,7 +94,9 @@ def _init_function_list(self, index: IndexTy) -> None: # Collect a list of source IDs for reexported items in `lib.rs` or `mod math`. use = (i for i in public if "use" in i["inner"]) use = ( - i for i in use if i["span"]["filename"] in ["src/math/mod.rs", "src/lib.rs"] + i + for i in use + if i["span"]["filename"] in ["libm/src/math/mod.rs", "libm/src/lib.rs"] ) reexported_ids = [item["inner"]["use"]["id"] for item in use] @@ -121,8 +123,8 @@ def _init_defs(self, index: IndexTy) -> None: # A lot of the `arch` module is often configured out so doesn't show up in docs. Use # string matching as a fallback. - for fname in glob("src/math/arch/**.rs", root_dir=LIBM_DIR): - contents = (LIBM_DIR.joinpath(fname)).read_text() + for fname in glob("libm/src/math/arch/**.rs", root_dir=ROOT_DIR): + contents = (ROOT_DIR.joinpath(fname)).read_text() for name in self.public_functions: if f"fn {name}" in contents: @@ -188,10 +190,10 @@ def tidy_lists(self) -> None: include all public API. """ - flist = sp.check_output(["git", "ls-files"], cwd=LIBM_DIR, text=True) + flist = sp.check_output(["git", "ls-files"], cwd=ROOT_DIR, text=True) for path in flist.splitlines(): - fpath = LIBM_DIR.joinpath(path) + fpath = ROOT_DIR.joinpath(path) if fpath.is_dir() or fpath == SELF_PATH: continue @@ -229,7 +231,7 @@ def ensure_contains_api(self, fpath: Path, line_num: int, lines: list[str]): if len(not_found) == 0: return - relpath = fpath.relative_to(LIBM_DIR) + relpath = fpath.relative_to(ROOT_DIR) eprint(f"functions not found at {relpath}:{line_num}: {not_found}") exit(1) @@ -244,7 +246,7 @@ def validate_delimited_block( """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(LIBM_DIR) + relpath = fpath.relative_to(ROOT_DIR) block_lines = [] block_start_line: None | int = None for line_num, line in enumerate(lines): @@ -274,7 +276,7 @@ def validate_delimited_block( 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(LIBM_DIR) + relpath = fpath.relative_to(ROOT_DIR) diff_and_exit( "\n".join(lines), "\n".join(sorted(lines)), diff --git a/library/compiler-builtins/libm/libm/Cargo.toml b/library/compiler-builtins/libm/libm/Cargo.toml index e0aeb07d52772..44154c1a8f5e3 100644 --- a/library/compiler-builtins/libm/libm/Cargo.toml +++ b/library/compiler-builtins/libm/libm/Cargo.toml @@ -10,7 +10,6 @@ readme = "README.md" repository = "https://github.com/rust-lang/libm" version = "0.2.11" edition = "2021" -exclude = ["/ci/", "/.github/workflows/"] rust-version = "1.63" [features] @@ -40,24 +39,6 @@ unstable-float = [] # hard float operations. force-soft-floats = [] -[workspace] -resolver = "2" -members = [ - "crates/libm-macros", - "crates/libm-test", - "crates/musl-math-sys", - "crates/util", -] -default-members = [ - ".", - "crates/libm-macros", - "crates/libm-test", -] -exclude = [ - # Requires `panic = abort` so can't be a member of the workspace - "crates/compiler-builtins-smoke-test", -] - [dev-dependencies] no-panic = "0.1.35" @@ -66,22 +47,3 @@ unexpected_cfgs = { level = "warn", check-cfg = [ # compiler-builtins sets this feature, but we use it in `libm` 'cfg(feature, values("compiler-builtins"))', ] } - -# The default release profile is unchanged. - -# Release mode with debug assertions -[profile.release-checked] -inherits = "release" -debug-assertions = true -overflow-checks = true - -# Release with maximum optimizations, which is very slow to build. This is also -# what is needed to check `no-panic`. -[profile.release-opt] -inherits = "release" -codegen-units = 1 -lto = "fat" - -[profile.bench] -# Required for iai-callgrind -debug = true diff --git a/library/compiler-builtins/libm/libm/LICENSE.txt b/library/compiler-builtins/libm/libm/LICENSE.txt new file mode 120000 index 0000000000000..4ab43736a839d --- /dev/null +++ b/library/compiler-builtins/libm/libm/LICENSE.txt @@ -0,0 +1 @@ +../LICENSE.txt \ No newline at end of file diff --git a/library/compiler-builtins/libm/libm/README.md b/library/compiler-builtins/libm/libm/README.md new file mode 120000 index 0000000000000..32d46ee883b58 --- /dev/null +++ b/library/compiler-builtins/libm/libm/README.md @@ -0,0 +1 @@ +../README.md \ No newline at end of file From 59c5ed0ba84d9007d8957dc1056f46bed381c100 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 29 Mar 2025 17:30:11 +0100 Subject: [PATCH 1824/4206] Make `#[naked]` an unsafe attribute --- example/mini_core_hello_world.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index 09d5b73fd3d9d..0b3a7281d5a06 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -387,11 +387,9 @@ global_asm! { } #[cfg(all(not(jit), target_arch = "x86_64"))] -#[naked] +#[unsafe(naked)] extern "C" fn naked_test() { - unsafe { - naked_asm!("ret"); - } + naked_asm!("ret") } #[repr(C)] From cd7c76aab3079191da631f80e58835c1356fe0d6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 19 Mar 2025 00:11:39 +0000 Subject: [PATCH 1825/4206] Migrate all crates except `libm` to edition 2024 Unfortunately this means we lose use of the convenient name `gen`, so this includes a handful of renaming. We can't increase the edition for `libm` yet due to MSRV, but we can enable `unsafe_op_in_unsafe_fn` to help make that change smoother in the future. --- .../libm/.github/workflows/main.yaml | 13 ++++++++----- .../crates/compiler-builtins-smoke-test/src/math.rs | 8 ++++---- .../libm/crates/libm-macros/Cargo.toml | 2 +- .../libm/crates/libm-test/Cargo.toml | 2 +- .../libm/crates/libm-test/benches/icount.rs | 2 +- .../libm/crates/libm-test/benches/random.rs | 4 ++-- .../libm/crates/libm-test/examples/plot_domains.rs | 8 ++++---- .../crates/libm-test/src/{gen.rs => generate.rs} | 0 .../libm-test/src/{gen => generate}/case_list.rs | 0 .../libm-test/src/{gen => generate}/edge_cases.rs | 2 +- .../libm-test/src/{gen => generate}/random.rs | 0 .../libm-test/src/{gen => generate}/spaced.rs | 0 .../libm/crates/libm-test/src/lib.rs | 2 +- .../libm/crates/libm-test/src/run_cfg.rs | 4 ++-- .../crates/libm-test/tests/compare_built_musl.rs | 2 +- .../libm/crates/libm-test/tests/multiprecision.rs | 2 +- .../libm/crates/libm-test/tests/standalone.rs | 2 +- .../libm/crates/libm-test/tests/u256.rs | 2 +- .../libm/crates/libm-test/tests/z_extensive/run.rs | 2 +- .../libm/crates/musl-math-sys/Cargo.toml | 2 +- .../libm/crates/musl-math-sys/src/lib.rs | 2 +- .../compiler-builtins/libm/crates/util/Cargo.toml | 2 +- library/compiler-builtins/libm/libm/src/lib.rs | 1 + 23 files changed, 34 insertions(+), 30 deletions(-) rename library/compiler-builtins/libm/crates/libm-test/src/{gen.rs => generate.rs} (100%) rename library/compiler-builtins/libm/crates/libm-test/src/{gen => generate}/case_list.rs (100%) rename library/compiler-builtins/libm/crates/libm-test/src/{gen => generate}/edge_cases.rs (99%) rename library/compiler-builtins/libm/crates/libm-test/src/{gen => generate}/random.rs (100%) rename library/compiler-builtins/libm/crates/libm-test/src/{gen => generate}/spaced.rs (100%) diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/libm/.github/workflows/main.yaml index a717c3ea8f879..5ce0dbc26c86d 100644 --- a/library/compiler-builtins/libm/.github/workflows/main.yaml +++ b/library/compiler-builtins/libm/.github/workflows/main.yaml @@ -212,14 +212,17 @@ jobs: RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings` steps: - uses: actions/checkout@master - - run: | + - name: Install Rust + run: | msrv="$(perl -ne 'print if s/rust-version\s*=\s*"(.*)"/\1/g' libm/Cargo.toml)" echo "MSRV: $msrv" - echo "MSRV=$msrv" >> "$GITHUB_ENV" - - name: Install Rust - run: rustup update "$MSRV" --no-self-update && rustup default "$MSRV" + rustup update "$msrv" --no-self-update && rustup default "$msrv" - uses: Swatinem/rust-cache@v2 - - run: cargo build -p libm + - run: | + # FIXME(msrv): Remove the workspace Cargo.toml so 1.63 cargo doesn't see + # `edition = "2024"` and get spooked. + rm Cargo.toml + cargo build --manifest-path libm/Cargo.toml rustfmt: name: Rustfmt diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs index f17fc12316838..58a5bfbb90f9e 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs @@ -14,7 +14,7 @@ macro_rules! no_mangle { // Handle simple functions with single return types (@inner $name:ident( $($arg:ident: $aty:ty),+ ) -> $ret:ty) => { - #[no_mangle] + #[unsafe(no_mangle)] extern "C" fn $name($($arg: $aty),+) -> $ret { libm::$name($($arg),+) } @@ -26,7 +26,7 @@ macro_rules! no_mangle { ( @inner $name:ident( $($arg:ident: $aty:ty),+ | $($rarg:ident: $rty:ty),+) -> $ret:ty ) => { - #[no_mangle] + #[unsafe(no_mangle)] extern "C" fn $name($($arg: $aty,)+ $($rarg: $rty),+) -> $ret { let ret; (ret, $(*$rarg),+) = libm::$name($($arg),+); @@ -166,12 +166,12 @@ no_mangle! { /* sincos has no direct return type, not worth handling in the macro */ -#[no_mangle] +#[unsafe(no_mangle)] extern "C" fn sincos(x: f64, s: &mut f64, c: &mut f64) { (*s, *c) = libm::sincos(x); } -#[no_mangle] +#[unsafe(no_mangle)] extern "C" fn sincosf(x: f32, s: &mut f32, c: &mut f32) { (*s, *c) = libm::sincosf(x); } diff --git a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml index 314f4ae3783a8..50c869db7ff6b 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "libm-macros" version = "0.1.0" -edition = "2021" +edition = "2024" publish = false [lib] diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml index 1bcc163ed1b66..5d150b4aeaa48 100644 --- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "libm-test" version = "0.1.0" -edition = "2021" +edition = "2024" publish = false [features] diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index 4a10ec383ae80..da8c6bfd15a03 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -4,7 +4,7 @@ use std::hint::black_box; use iai_callgrind::{library_benchmark, library_benchmark_group, main}; use libm::support::{HInt, u256}; -use libm_test::gen::spaced; +use libm_test::generate::spaced; use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, OpRustArgs, TupleCall, op}; const BENCH_ITER_ITEMS: u64 = 500; diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index 17e4e0d55fc54..63d7e5c6d2053 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -2,8 +2,8 @@ use std::hint::black_box; use std::time::Duration; use criterion::{Criterion, criterion_main}; -use libm_test::gen::random; -use libm_test::gen::random::RandomInput; +use libm_test::generate::random; +use libm_test::generate::random::RandomInput; use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, TupleCall}; /// Benchmark with this many items to get a variety diff --git a/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs b/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs index 441889c694175..78524761e2cbc 100644 --- a/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs +++ b/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs @@ -12,8 +12,8 @@ use std::path::Path; use std::process::Command; use std::{env, fs}; -use libm_test::gen::spaced::SpacedInput; -use libm_test::gen::{edge_cases, spaced}; +use libm_test::generate::spaced::SpacedInput; +use libm_test::generate::{edge_cases, spaced}; use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, op}; const JL_PLOT: &str = "examples/plot_file.jl"; @@ -73,7 +73,7 @@ fn plot_one_generator( ctx: &CheckCtx, gen_name: &str, config: &mut String, - gen: impl Iterator, + generator: impl Iterator, ) { let fn_name = ctx.base_name_str; let text_file = out_dir.join(format!("input-{fn_name}-{gen_name}.txt")); @@ -82,7 +82,7 @@ fn plot_one_generator( let mut w = BufWriter::new(f); let mut count = 0u64; - for input in gen { + for input in generator { writeln!(w, "{:e}", input.0).unwrap(); count += 1; } diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen.rs b/library/compiler-builtins/libm/crates/libm-test/src/generate.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/src/gen.rs rename to library/compiler-builtins/libm/crates/libm-test/src/generate.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs b/library/compiler-builtins/libm/crates/libm-test/src/generate/case_list.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/src/gen/case_list.rs rename to library/compiler-builtins/libm/crates/libm-test/src/generate/case_list.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs b/library/compiler-builtins/libm/crates/libm-test/src/generate/edge_cases.rs similarity index 99% rename from library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs rename to library/compiler-builtins/libm/crates/libm-test/src/generate/edge_cases.rs index 69b59a1056741..56cc9fa9a70ed 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/gen/edge_cases.rs +++ b/library/compiler-builtins/libm/crates/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::gen::KnownSize; +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}; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs b/library/compiler-builtins/libm/crates/libm-test/src/generate/random.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/src/gen/random.rs rename to library/compiler-builtins/libm/crates/libm-test/src/generate/random.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/gen/spaced.rs b/library/compiler-builtins/libm/crates/libm-test/src/generate/spaced.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/src/gen/spaced.rs rename to library/compiler-builtins/libm/crates/libm-test/src/generate/spaced.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 824f09a33873d..485c01a478222 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -4,7 +4,7 @@ pub mod domain; mod f8_impl; -pub mod gen; +pub mod generate; #[cfg(feature = "build-mpfr")] pub mod mpfloat; mod num; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs index 8e4fff53cb292..b36164b005fde 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs @@ -4,7 +4,7 @@ use std::ops::RangeInclusive; use std::sync::LazyLock; use std::{env, str}; -use crate::gen::random::{SEED, SEED_ENV}; +use crate::generate::random::{SEED, SEED_ENV}; use crate::{BaseName, FloatTy, Identifier, test_log}; /// The environment variable indicating which extensive tests should be run. @@ -241,7 +241,7 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { // Some tests are significantly slower than others and need to be further reduced. if let Some((_id, _gen, scale)) = EXTEMELY_SLOW_TESTS .iter() - .find(|(id, gen, _scale)| *id == ctx.fn_ident && *gen == ctx.gen_kind) + .find(|(id, generator, _scale)| *id == ctx.fn_ident && *generator == ctx.gen_kind) { // However, do not override if the extensive iteration count has been manually set. if !(ctx.gen_kind == GeneratorKind::Extensive && EXTENSIVE_ITER_OVERRIDE.is_some()) { diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 897dfc26e8cab..cbb4bd49b9c55 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -9,7 +9,7 @@ // There are some targets we can't build musl for #![cfg(feature = "build-musl")] -use libm_test::gen::{case_list, edge_cases, random, spaced}; +use libm_test::generate::{case_list, edge_cases, random, spaced}; use libm_test::{CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TupleCall}; const BASIS: CheckBasis = CheckBasis::Musl; diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs index 0ab4b64da8141..80b2c78688ea7 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs @@ -2,7 +2,7 @@ #![cfg(feature = "build-mpfr")] -use libm_test::gen::{case_list, edge_cases, random, spaced}; +use libm_test::generate::{case_list, edge_cases, random, spaced}; use libm_test::mpfloat::MpOp; use libm_test::{CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TupleCall}; diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/standalone.rs b/library/compiler-builtins/libm/crates/libm-test/tests/standalone.rs index 7d694843e9ce9..7b30a3b48d7f5 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/standalone.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/standalone.rs @@ -1,6 +1,6 @@ //! Test cases that have both an input and an output, so do not require a basis. -use libm_test::gen::case_list; +use libm_test::generate::case_list; use libm_test::{CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TupleCall}; const BASIS: CheckBasis = CheckBasis::None; diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs b/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs index 4603534248cd9..4444036d0a491 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs @@ -9,7 +9,7 @@ use libm::support::{HInt, u256}; type BigInt = rug::Integer; use libm_test::bigint_fuzz_iteration_count; -use libm_test::gen::random::SEED; +use libm_test::generate::random::SEED; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; use rug::Assign; diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs index 786546a9d6d5b..b10c231d18390 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs @@ -6,7 +6,7 @@ use std::sync::atomic::{AtomicU64, Ordering}; use std::time::Duration; use indicatif::{ProgressBar, ProgressStyle}; -use libm_test::gen::spaced; +use libm_test::generate::spaced; use libm_test::mpfloat::MpOp; use libm_test::{ CheckBasis, CheckCtx, CheckOutput, GeneratorKind, MathOp, TestResult, TupleCall, diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml index ad73578d8b8fa..9e866a9704f61 100644 --- a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml +++ b/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "musl-math-sys" version = "0.1.0" -edition = "2021" +edition = "2024" publish = false [dependencies] diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs b/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs index 07277ef3e6e22..6a4bf4859d931 100644 --- a/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs +++ b/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs @@ -10,7 +10,7 @@ macro_rules! functions { $( #[$meta:meta] )* $pfx_name:ident: $name:ident( $($arg:ident: $aty:ty),+ ) -> $rty:ty; )* ) => { - extern "C" { + unsafe extern "C" { $( fn $pfx_name( $($arg: $aty),+ ) -> $rty; )* } diff --git a/library/compiler-builtins/libm/crates/util/Cargo.toml b/library/compiler-builtins/libm/crates/util/Cargo.toml index 94c7f1033405f..4bcb9747297a5 100644 --- a/library/compiler-builtins/libm/crates/util/Cargo.toml +++ b/library/compiler-builtins/libm/crates/util/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "util" version = "0.1.0" -edition = "2021" +edition = "2024" publish = false [features] diff --git a/library/compiler-builtins/libm/libm/src/lib.rs b/library/compiler-builtins/libm/libm/src/lib.rs index b0e4312110f3a..7e56bd0796ca4 100644 --- a/library/compiler-builtins/libm/libm/src/lib.rs +++ b/library/compiler-builtins/libm/libm/src/lib.rs @@ -17,6 +17,7 @@ #![allow(clippy::needless_return)] #![allow(clippy::unreadable_literal)] #![allow(clippy::zero_divided_by_zero)] +#![forbid(unsafe_op_in_unsafe_fn)] mod libm_helper; mod math; From 92b1e8454d7c4ea424ff970e6be283144584f812 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 18 Mar 2025 09:52:53 +0000 Subject: [PATCH 1826/4206] Rename `testcrate` to `builtins-test` The repo will soon have `libm` as a top-level crate, so make it clear that this is only the test crate for `compiler-builtins`. --- library/compiler-builtins/Cargo.toml | 8 ++++---- .../{testcrate => builtins-test}/Cargo.toml | 7 ++++--- .../{testcrate => builtins-test}/benches/float_add.rs | 2 +- .../{testcrate => builtins-test}/benches/float_cmp.rs | 2 +- .../{testcrate => builtins-test}/benches/float_conv.rs | 2 +- .../{testcrate => builtins-test}/benches/float_div.rs | 2 +- .../{testcrate => builtins-test}/benches/float_extend.rs | 2 +- .../{testcrate => builtins-test}/benches/float_mul.rs | 2 +- .../{testcrate => builtins-test}/benches/float_pow.rs | 2 +- .../{testcrate => builtins-test}/benches/float_sub.rs | 2 +- .../{testcrate => builtins-test}/benches/float_trunc.rs | 2 +- .../{testcrate => builtins-test}/benches/mem.rs | 0 .../{testcrate => builtins-test}/benches/mem_icount.rs | 0 .../{testcrate => builtins-test}/build.rs | 0 .../{testcrate => builtins-test}/src/bench.rs | 0 .../{testcrate => builtins-test}/src/lib.rs | 4 ++-- .../{testcrate => builtins-test}/tests/addsub.rs | 2 +- .../{testcrate => builtins-test}/tests/aeabi_memclr.rs | 0 .../{testcrate => builtins-test}/tests/aeabi_memcpy.rs | 0 .../{testcrate => builtins-test}/tests/aeabi_memset.rs | 0 .../{testcrate => builtins-test}/tests/big.rs | 0 .../{testcrate => builtins-test}/tests/cmp.rs | 2 +- .../{testcrate => builtins-test}/tests/conv.rs | 2 +- .../{testcrate => builtins-test}/tests/div_rem.rs | 2 +- .../{testcrate => builtins-test}/tests/float_pow.rs | 2 +- .../{testcrate => builtins-test}/tests/lse.rs | 6 +++--- .../{testcrate => builtins-test}/tests/mem.rs | 0 .../{testcrate => builtins-test}/tests/misc.rs | 2 +- .../{testcrate => builtins-test}/tests/mul.rs | 2 +- .../{testcrate => builtins-test}/tests/shift.rs | 2 +- library/compiler-builtins/ci/miri.sh | 2 +- library/compiler-builtins/ci/run.sh | 6 +++--- library/compiler-builtins/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/compiler-builtins/configure.rs | 2 +- .../compiler-builtins/compiler-builtins/src/int/traits.rs | 4 ++-- 35 files changed, 38 insertions(+), 37 deletions(-) rename library/compiler-builtins/{testcrate => builtins-test}/Cargo.toml (93%) rename library/compiler-builtins/{testcrate => builtins-test}/benches/float_add.rs (98%) rename library/compiler-builtins/{testcrate => builtins-test}/benches/float_cmp.rs (99%) rename library/compiler-builtins/{testcrate => builtins-test}/benches/float_conv.rs (99%) rename library/compiler-builtins/{testcrate => builtins-test}/benches/float_div.rs (98%) rename library/compiler-builtins/{testcrate => builtins-test}/benches/float_extend.rs (99%) rename library/compiler-builtins/{testcrate => builtins-test}/benches/float_mul.rs (98%) rename library/compiler-builtins/{testcrate => builtins-test}/benches/float_pow.rs (97%) rename library/compiler-builtins/{testcrate => builtins-test}/benches/float_sub.rs (98%) rename library/compiler-builtins/{testcrate => builtins-test}/benches/float_trunc.rs (99%) rename library/compiler-builtins/{testcrate => builtins-test}/benches/mem.rs (100%) rename library/compiler-builtins/{testcrate => builtins-test}/benches/mem_icount.rs (100%) rename library/compiler-builtins/{testcrate => builtins-test}/build.rs (100%) rename library/compiler-builtins/{testcrate => builtins-test}/src/bench.rs (100%) rename library/compiler-builtins/{testcrate => builtins-test}/src/lib.rs (99%) rename library/compiler-builtins/{testcrate => builtins-test}/tests/addsub.rs (99%) rename library/compiler-builtins/{testcrate => builtins-test}/tests/aeabi_memclr.rs (100%) rename library/compiler-builtins/{testcrate => builtins-test}/tests/aeabi_memcpy.rs (100%) rename library/compiler-builtins/{testcrate => builtins-test}/tests/aeabi_memset.rs (100%) rename library/compiler-builtins/{testcrate => builtins-test}/tests/big.rs (100%) rename library/compiler-builtins/{testcrate => builtins-test}/tests/cmp.rs (99%) rename library/compiler-builtins/{testcrate => builtins-test}/tests/conv.rs (99%) rename library/compiler-builtins/{testcrate => builtins-test}/tests/div_rem.rs (99%) rename library/compiler-builtins/{testcrate => builtins-test}/tests/float_pow.rs (99%) rename library/compiler-builtins/{testcrate => builtins-test}/tests/lse.rs (93%) rename library/compiler-builtins/{testcrate => builtins-test}/tests/mem.rs (100%) rename library/compiler-builtins/{testcrate => builtins-test}/tests/misc.rs (99%) rename library/compiler-builtins/{testcrate => builtins-test}/tests/mul.rs (99%) rename library/compiler-builtins/{testcrate => builtins-test}/tests/shift.rs (97%) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index db4c45dfa4b29..2e17c303a5f54 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -2,16 +2,16 @@ resolver = "3" members = [ # Note that builtins-test-intrinsics cannot be a default member because it - # needs the `mangled-names` feature disabled, while `testcrate` needs it - # enabled. + # needs the `mangled-names` feature disabled, while `builtins-test` needs + # it enabled. + "builtins-test", "builtins-test-intrinsics", "compiler-builtins", - "testcrate", ] default-members = [ "compiler-builtins", - "testcrate", + "builtins-test", ] [profile.release] diff --git a/library/compiler-builtins/testcrate/Cargo.toml b/library/compiler-builtins/builtins-test/Cargo.toml similarity index 93% rename from library/compiler-builtins/testcrate/Cargo.toml rename to library/compiler-builtins/builtins-test/Cargo.toml index bda2b641d6f8a..526e9b18af08b 100644 --- a/library/compiler-builtins/testcrate/Cargo.toml +++ b/library/compiler-builtins/builtins-test/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "testcrate" +name = "builtins-test" version = "0.1.0" authors = ["Alex Crichton "] edition = "2024" @@ -56,8 +56,9 @@ icount = ["dep:iai-callgrind"] benchmarking-reports = ["criterion/plotters", "criterion/html_reports"] # NOTE: benchmarks must be run with `--no-default-features` or with -# `-p testcrate`, otherwise the default `compiler-builtins` feature of the -# `compiler_builtins` crate gets activated, resulting in linker errors. +# `-p builtins-test`, otherwise the default `compiler-builtins` feature +# of the `compiler_builtins` crate gets activated, resulting in linker +# errors. [[bench]] name = "float_add" diff --git a/library/compiler-builtins/testcrate/benches/float_add.rs b/library/compiler-builtins/builtins-test/benches/float_add.rs similarity index 98% rename from library/compiler-builtins/testcrate/benches/float_add.rs rename to library/compiler-builtins/builtins-test/benches/float_add.rs index a578655f8f433..197f90b319da4 100644 --- a/library/compiler-builtins/testcrate/benches/float_add.rs +++ b/library/compiler-builtins/builtins-test/benches/float_add.rs @@ -1,8 +1,8 @@ #![cfg_attr(f128_enabled, feature(f128))] +use builtins_test::float_bench; use compiler_builtins::float::add; use criterion::{Criterion, criterion_main}; -use testcrate::float_bench; float_bench! { name: add_f32, diff --git a/library/compiler-builtins/testcrate/benches/float_cmp.rs b/library/compiler-builtins/builtins-test/benches/float_cmp.rs similarity index 99% rename from library/compiler-builtins/testcrate/benches/float_cmp.rs rename to library/compiler-builtins/builtins-test/benches/float_cmp.rs index 4c269e4889c76..4493765ec1bad 100644 --- a/library/compiler-builtins/testcrate/benches/float_cmp.rs +++ b/library/compiler-builtins/builtins-test/benches/float_cmp.rs @@ -1,7 +1,7 @@ #![cfg_attr(f128_enabled, feature(f128))] +use builtins_test::float_bench; use criterion::{Criterion, criterion_main}; -use testcrate::float_bench; use compiler_builtins::float::cmp; diff --git a/library/compiler-builtins/testcrate/benches/float_conv.rs b/library/compiler-builtins/builtins-test/benches/float_conv.rs similarity index 99% rename from library/compiler-builtins/testcrate/benches/float_conv.rs rename to library/compiler-builtins/builtins-test/benches/float_conv.rs index e3f2af86344fc..d4a7346d1d588 100644 --- a/library/compiler-builtins/testcrate/benches/float_conv.rs +++ b/library/compiler-builtins/builtins-test/benches/float_conv.rs @@ -1,9 +1,9 @@ #![allow(improper_ctypes)] #![cfg_attr(f128_enabled, feature(f128))] +use builtins_test::float_bench; use compiler_builtins::float::conv; use criterion::{Criterion, criterion_main}; -use testcrate::float_bench; /* unsigned int -> float */ diff --git a/library/compiler-builtins/testcrate/benches/float_div.rs b/library/compiler-builtins/builtins-test/benches/float_div.rs similarity index 98% rename from library/compiler-builtins/testcrate/benches/float_div.rs rename to library/compiler-builtins/builtins-test/benches/float_div.rs index c42f3f386716e..d5b0ad0fd402b 100644 --- a/library/compiler-builtins/testcrate/benches/float_div.rs +++ b/library/compiler-builtins/builtins-test/benches/float_div.rs @@ -1,8 +1,8 @@ #![cfg_attr(f128_enabled, feature(f128))] +use builtins_test::float_bench; use compiler_builtins::float::div; use criterion::{Criterion, criterion_main}; -use testcrate::float_bench; float_bench! { name: div_f32, diff --git a/library/compiler-builtins/testcrate/benches/float_extend.rs b/library/compiler-builtins/builtins-test/benches/float_extend.rs similarity index 99% rename from library/compiler-builtins/testcrate/benches/float_extend.rs rename to library/compiler-builtins/builtins-test/benches/float_extend.rs index 1e7fedefe70ef..fc44e80c9e141 100644 --- a/library/compiler-builtins/testcrate/benches/float_extend.rs +++ b/library/compiler-builtins/builtins-test/benches/float_extend.rs @@ -2,9 +2,9 @@ #![cfg_attr(f128_enabled, feature(f128))] #![cfg_attr(f16_enabled, feature(f16))] +use builtins_test::float_bench; use compiler_builtins::float::extend; use criterion::{Criterion, criterion_main}; -use testcrate::float_bench; #[cfg(f16_enabled)] float_bench! { diff --git a/library/compiler-builtins/testcrate/benches/float_mul.rs b/library/compiler-builtins/builtins-test/benches/float_mul.rs similarity index 98% rename from library/compiler-builtins/testcrate/benches/float_mul.rs rename to library/compiler-builtins/builtins-test/benches/float_mul.rs index 0857a68a22e07..a7a2d34aa0489 100644 --- a/library/compiler-builtins/testcrate/benches/float_mul.rs +++ b/library/compiler-builtins/builtins-test/benches/float_mul.rs @@ -1,8 +1,8 @@ #![cfg_attr(f128_enabled, feature(f128))] +use builtins_test::float_bench; use compiler_builtins::float::mul; use criterion::{Criterion, criterion_main}; -use testcrate::float_bench; float_bench! { name: mul_f32, diff --git a/library/compiler-builtins/testcrate/benches/float_pow.rs b/library/compiler-builtins/builtins-test/benches/float_pow.rs similarity index 97% rename from library/compiler-builtins/testcrate/benches/float_pow.rs rename to library/compiler-builtins/builtins-test/benches/float_pow.rs index e84fee51ca97a..64e37dd32416e 100644 --- a/library/compiler-builtins/testcrate/benches/float_pow.rs +++ b/library/compiler-builtins/builtins-test/benches/float_pow.rs @@ -1,8 +1,8 @@ #![cfg_attr(f128_enabled, feature(f128))] +use builtins_test::float_bench; use compiler_builtins::float::pow; use criterion::{Criterion, criterion_main}; -use testcrate::float_bench; float_bench! { name: powi_f32, diff --git a/library/compiler-builtins/testcrate/benches/float_sub.rs b/library/compiler-builtins/builtins-test/benches/float_sub.rs similarity index 98% rename from library/compiler-builtins/testcrate/benches/float_sub.rs rename to library/compiler-builtins/builtins-test/benches/float_sub.rs index 7a6c05ea5c1c4..8bae294cd56b1 100644 --- a/library/compiler-builtins/testcrate/benches/float_sub.rs +++ b/library/compiler-builtins/builtins-test/benches/float_sub.rs @@ -1,8 +1,8 @@ #![cfg_attr(f128_enabled, feature(f128))] +use builtins_test::float_bench; use compiler_builtins::float::sub; use criterion::{Criterion, criterion_main}; -use testcrate::float_bench; float_bench! { name: sub_f32, diff --git a/library/compiler-builtins/testcrate/benches/float_trunc.rs b/library/compiler-builtins/builtins-test/benches/float_trunc.rs similarity index 99% rename from library/compiler-builtins/testcrate/benches/float_trunc.rs rename to library/compiler-builtins/builtins-test/benches/float_trunc.rs index 4ceb62ab06a4e..43310c7cfc825 100644 --- a/library/compiler-builtins/testcrate/benches/float_trunc.rs +++ b/library/compiler-builtins/builtins-test/benches/float_trunc.rs @@ -1,9 +1,9 @@ #![cfg_attr(f128_enabled, feature(f128))] #![cfg_attr(f16_enabled, feature(f16))] +use builtins_test::float_bench; use compiler_builtins::float::trunc; use criterion::{Criterion, criterion_main}; -use testcrate::float_bench; #[cfg(f16_enabled)] float_bench! { diff --git a/library/compiler-builtins/testcrate/benches/mem.rs b/library/compiler-builtins/builtins-test/benches/mem.rs similarity index 100% rename from library/compiler-builtins/testcrate/benches/mem.rs rename to library/compiler-builtins/builtins-test/benches/mem.rs diff --git a/library/compiler-builtins/testcrate/benches/mem_icount.rs b/library/compiler-builtins/builtins-test/benches/mem_icount.rs similarity index 100% rename from library/compiler-builtins/testcrate/benches/mem_icount.rs rename to library/compiler-builtins/builtins-test/benches/mem_icount.rs diff --git a/library/compiler-builtins/testcrate/build.rs b/library/compiler-builtins/builtins-test/build.rs similarity index 100% rename from library/compiler-builtins/testcrate/build.rs rename to library/compiler-builtins/builtins-test/build.rs diff --git a/library/compiler-builtins/testcrate/src/bench.rs b/library/compiler-builtins/builtins-test/src/bench.rs similarity index 100% rename from library/compiler-builtins/testcrate/src/bench.rs rename to library/compiler-builtins/builtins-test/src/bench.rs diff --git a/library/compiler-builtins/testcrate/src/lib.rs b/library/compiler-builtins/builtins-test/src/lib.rs similarity index 99% rename from library/compiler-builtins/testcrate/src/lib.rs rename to library/compiler-builtins/builtins-test/src/lib.rs index c61618755e930..a83aea56206b1 100644 --- a/library/compiler-builtins/testcrate/src/lib.rs +++ b/library/compiler-builtins/builtins-test/src/lib.rs @@ -7,8 +7,8 @@ //! edge case testing is crucial for checking cases like where both inputs are equal or equal to //! special values such as `i128::MIN`, which is unlikely for the random fuzzer by itself to //! encounter. The randomized fuzz testing is specially designed to cover wide swaths of search -//! space in as few iterations as possible. See `fuzz_values` in `testcrate/tests/misc.rs` for an -//! example. +//! space in as few iterations as possible. See `fuzz_values` in `builtins-test/tests/misc.rs` for +//! an example. //! //! Some floating point tests are disabled for specific architectures, because they do not have //! correct rounding. diff --git a/library/compiler-builtins/testcrate/tests/addsub.rs b/library/compiler-builtins/builtins-test/tests/addsub.rs similarity index 99% rename from library/compiler-builtins/testcrate/tests/addsub.rs rename to library/compiler-builtins/builtins-test/tests/addsub.rs index 3c0e20f77b18c..865b9e472ab4c 100644 --- a/library/compiler-builtins/testcrate/tests/addsub.rs +++ b/library/compiler-builtins/builtins-test/tests/addsub.rs @@ -1,7 +1,7 @@ #![allow(unused_macros)] #![cfg_attr(f128_enabled, feature(f128))] -use testcrate::*; +use builtins_test::*; mod int_addsub { use super::*; diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memclr.rs b/library/compiler-builtins/builtins-test/tests/aeabi_memclr.rs similarity index 100% rename from library/compiler-builtins/testcrate/tests/aeabi_memclr.rs rename to library/compiler-builtins/builtins-test/tests/aeabi_memclr.rs diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs b/library/compiler-builtins/builtins-test/tests/aeabi_memcpy.rs similarity index 100% rename from library/compiler-builtins/testcrate/tests/aeabi_memcpy.rs rename to library/compiler-builtins/builtins-test/tests/aeabi_memcpy.rs diff --git a/library/compiler-builtins/testcrate/tests/aeabi_memset.rs b/library/compiler-builtins/builtins-test/tests/aeabi_memset.rs similarity index 100% rename from library/compiler-builtins/testcrate/tests/aeabi_memset.rs rename to library/compiler-builtins/builtins-test/tests/aeabi_memset.rs diff --git a/library/compiler-builtins/testcrate/tests/big.rs b/library/compiler-builtins/builtins-test/tests/big.rs similarity index 100% rename from library/compiler-builtins/testcrate/tests/big.rs rename to library/compiler-builtins/builtins-test/tests/big.rs diff --git a/library/compiler-builtins/testcrate/tests/cmp.rs b/library/compiler-builtins/builtins-test/tests/cmp.rs similarity index 99% rename from library/compiler-builtins/testcrate/tests/cmp.rs rename to library/compiler-builtins/builtins-test/tests/cmp.rs index 19d90c66493cc..dbedd213e90e7 100644 --- a/library/compiler-builtins/testcrate/tests/cmp.rs +++ b/library/compiler-builtins/builtins-test/tests/cmp.rs @@ -2,7 +2,7 @@ #![allow(unreachable_code)] #![cfg_attr(f128_enabled, feature(f128))] -use testcrate::*; +use builtins_test::*; mod float_comparisons { use super::*; diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/builtins-test/tests/conv.rs similarity index 99% rename from library/compiler-builtins/testcrate/tests/conv.rs rename to library/compiler-builtins/builtins-test/tests/conv.rs index 381d3e155780c..491915d9bb172 100644 --- a/library/compiler-builtins/testcrate/tests/conv.rs +++ b/library/compiler-builtins/builtins-test/tests/conv.rs @@ -4,9 +4,9 @@ #![allow(unused_macros)] #![allow(unused_imports)] +use builtins_test::*; use compiler_builtins::float::Float; use rustc_apfloat::{Float as _, FloatConvert as _}; -use testcrate::*; mod i_to_f { use super::*; diff --git a/library/compiler-builtins/testcrate/tests/div_rem.rs b/library/compiler-builtins/builtins-test/tests/div_rem.rs similarity index 99% rename from library/compiler-builtins/testcrate/tests/div_rem.rs rename to library/compiler-builtins/builtins-test/tests/div_rem.rs index ac87eb6302b6c..6c0280a328698 100644 --- a/library/compiler-builtins/testcrate/tests/div_rem.rs +++ b/library/compiler-builtins/builtins-test/tests/div_rem.rs @@ -4,7 +4,7 @@ use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divmodti4}; use compiler_builtins::int::udiv::{__udivmoddi4, __udivmodsi4, __udivmodti4, u128_divide_sparc}; -use testcrate::*; +use builtins_test::*; // Division algorithms have by far the nastiest and largest number of edge cases, and experience shows // that sometimes 100_000 iterations of the random fuzzer is needed. diff --git a/library/compiler-builtins/testcrate/tests/float_pow.rs b/library/compiler-builtins/builtins-test/tests/float_pow.rs similarity index 99% rename from library/compiler-builtins/testcrate/tests/float_pow.rs rename to library/compiler-builtins/builtins-test/tests/float_pow.rs index 8d86392f535a4..8209543e666a0 100644 --- a/library/compiler-builtins/testcrate/tests/float_pow.rs +++ b/library/compiler-builtins/builtins-test/tests/float_pow.rs @@ -2,7 +2,7 @@ #![cfg_attr(f128_enabled, feature(f128))] #![cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] -use testcrate::*; +use builtins_test::*; // This is approximate because of issues related to // https://github.com/rust-lang/rust/issues/73920. diff --git a/library/compiler-builtins/testcrate/tests/lse.rs b/library/compiler-builtins/builtins-test/tests/lse.rs similarity index 93% rename from library/compiler-builtins/testcrate/tests/lse.rs rename to library/compiler-builtins/builtins-test/tests/lse.rs index cbecd6143e726..53167d98fc0e3 100644 --- a/library/compiler-builtins/testcrate/tests/lse.rs +++ b/library/compiler-builtins/builtins-test/tests/lse.rs @@ -14,7 +14,7 @@ mod cas { pub(super) macro test($_ordering:ident, $bytes:tt, $name:ident) { #[test] fn $name() { - testcrate::fuzz_2(10000, |expected: super::int_ty!($bytes), new| { + builtins_test::fuzz_2(10000, |expected: super::int_ty!($bytes), new| { let mut target = expected.wrapping_add(10); assert_eq!( unsafe { @@ -50,7 +50,7 @@ mod swap { pub(super) macro test($_ordering:ident, $bytes:tt, $name:ident) { #[test] fn $name() { - testcrate::fuzz_2(10000, |left: super::int_ty!($bytes), mut right| { + builtins_test::fuzz_2(10000, |left: super::int_ty!($bytes), mut right| { let orig_right = right; assert_eq!( unsafe { compiler_builtins::aarch64_linux::$name::$name(left, &mut right) }, @@ -69,7 +69,7 @@ macro_rules! test_op { ($_ordering:ident, $bytes:tt, $name:ident) => { #[test] fn $name() { - testcrate::fuzz_2(10000, |old, val| { + builtins_test::fuzz_2(10000, |old, val| { let mut target = old; let op: fn(super::int_ty!($bytes), super::int_ty!($bytes)) -> _ = $($op)*; let expected = op(old, val); diff --git a/library/compiler-builtins/testcrate/tests/mem.rs b/library/compiler-builtins/builtins-test/tests/mem.rs similarity index 100% rename from library/compiler-builtins/testcrate/tests/mem.rs rename to library/compiler-builtins/builtins-test/tests/mem.rs diff --git a/library/compiler-builtins/testcrate/tests/misc.rs b/library/compiler-builtins/builtins-test/tests/misc.rs similarity index 99% rename from library/compiler-builtins/testcrate/tests/misc.rs rename to library/compiler-builtins/builtins-test/tests/misc.rs index edbd3684d47ad..b8c75c02653d0 100644 --- a/library/compiler-builtins/testcrate/tests/misc.rs +++ b/library/compiler-builtins/builtins-test/tests/misc.rs @@ -1,7 +1,7 @@ // makes configuration easier #![allow(unused_macros)] -use testcrate::*; +use builtins_test::*; /// Make sure that the the edge case tester and randomized tester don't break, and list examples of /// fuzz values for documentation purposes. diff --git a/library/compiler-builtins/testcrate/tests/mul.rs b/library/compiler-builtins/builtins-test/tests/mul.rs similarity index 99% rename from library/compiler-builtins/testcrate/tests/mul.rs rename to library/compiler-builtins/builtins-test/tests/mul.rs index 2113b177db410..198cacb34890b 100644 --- a/library/compiler-builtins/testcrate/tests/mul.rs +++ b/library/compiler-builtins/builtins-test/tests/mul.rs @@ -1,7 +1,7 @@ #![allow(unused_macros)] #![cfg_attr(f128_enabled, feature(f128))] -use testcrate::*; +use builtins_test::*; mod int_mul { use super::*; diff --git a/library/compiler-builtins/testcrate/tests/shift.rs b/library/compiler-builtins/builtins-test/tests/shift.rs similarity index 97% rename from library/compiler-builtins/testcrate/tests/shift.rs rename to library/compiler-builtins/builtins-test/tests/shift.rs index 23e3395edc629..0f2483855e591 100644 --- a/library/compiler-builtins/testcrate/tests/shift.rs +++ b/library/compiler-builtins/builtins-test/tests/shift.rs @@ -1,4 +1,4 @@ -use testcrate::*; +use builtins_test::*; macro_rules! shift { ($($i:ty, $fn_std:ident, $fn_builtins:ident);*;) => { diff --git a/library/compiler-builtins/ci/miri.sh b/library/compiler-builtins/ci/miri.sh index f9a1240a46593..79e660bab6295 100755 --- a/library/compiler-builtins/ci/miri.sh +++ b/library/compiler-builtins/ci/miri.sh @@ -12,5 +12,5 @@ TARGETS=(x86_64-unknown-linux-gnu s390x-unknown-linux-gnu) for TARGET in "${TARGETS[@]}"; do # Only run the `mem` tests to avoid this taking too long. - cargo miri test --manifest-path testcrate/Cargo.toml --features no-asm --target $TARGET -- mem + cargo miri test --manifest-path builtins-test/Cargo.toml --features no-asm --target $TARGET -- mem done diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 9abbf25a7e7a2..8dcb139d49386 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -23,7 +23,7 @@ fi if [ "${NO_STD:-}" = "1" ]; then echo "nothing to do for no_std" else - run="cargo test --package testcrate --no-fail-fast --target $target" + run="cargo test --package builtins-test --no-fail-fast --target $target" $run $run --release $run --features c @@ -37,8 +37,8 @@ else fi if [ "${TEST_VERBATIM:-}" = "1" ]; then - verb_path=$(cmd.exe //C echo \\\\?\\%cd%\\testcrate\\target2) - cargo build --package testcrate \ + verb_path=$(cmd.exe //C echo \\\\?\\%cd%\\builtins-test\\target2) + cargo build --package builtins-test \ --target "$target" --target-dir "$verb_path" --features c fi diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index eb5b2b9cc88e8..3151546ab8dc4 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -68,7 +68,7 @@ mangled-names = [] rustc-dep-of-std = ['compiler-builtins', 'core'] # This makes certain traits and function specializations public that -# are not normally public but are required by the `testcrate` +# are not normally public but are required by the `builtins-test` public-test-deps = [] [lints.rust] diff --git a/library/compiler-builtins/compiler-builtins/configure.rs b/library/compiler-builtins/compiler-builtins/configure.rs index 4be0b3ca23ca5..d825f35a9aa05 100644 --- a/library/compiler-builtins/compiler-builtins/configure.rs +++ b/library/compiler-builtins/compiler-builtins/configure.rs @@ -1,4 +1,4 @@ -// Configuration that is shared between `compiler_builtins` and `testcrate`. +// Configuration that is shared between `compiler_builtins` and `builtins_test`. use std::env; diff --git a/library/compiler-builtins/compiler-builtins/src/int/traits.rs b/library/compiler-builtins/compiler-builtins/src/int/traits.rs index 9b079e2aa59ae..152cb2eee2ee6 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/traits.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/traits.rs @@ -48,8 +48,8 @@ pub trait Int: + ops::BitAnd { /// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing - /// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111, - /// 112,119,120,125,126,127]. + /// in `builtins-test`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96, + /// 111,112,119,120,125,126,127]. const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(::BITS); /// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128. From 01c58882462bb721b755c765507cdcd335b481d8 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 03:16:02 +0000 Subject: [PATCH 1827/4206] ci: Make CI configuration more similar to `libm` Apply a handful of changes to reduce the diff between the two: * Cancel running jobs on new pushes * Enable log color and backtraces * Add timeouts * Specify CI runner versions * Add an armv7 job * Replace the name NO_STD with BUILD_ONLY * Update the extension to the canonical .yaml * Set AR_ and CC_ environments in docker * Install requirements to build MPFR --- .../.github/workflows/{main.yml => main.yaml} | 173 ++++++++---------- .../workflows/{publish.yml => publish.yaml} | 0 .../aarch64-unknown-linux-gnu/Dockerfile | 9 +- .../arm-unknown-linux-gnueabi/Dockerfile | 7 +- .../arm-unknown-linux-gnueabihf/Dockerfile | 7 +- .../armv7-unknown-linux-gnueabihf/Dockerfile | 7 +- .../docker/i586-unknown-linux-gnu/Dockerfile | 3 +- .../docker/i686-unknown-linux-gnu/Dockerfile | 3 +- .../loongarch64-unknown-linux-gnu/Dockerfile | 1 + .../docker/mips-unknown-linux-gnu/Dockerfile | 5 +- .../mips64-unknown-linux-gnuabi64/Dockerfile | 8 +- .../Dockerfile | 8 +- .../mipsel-unknown-linux-gnu/Dockerfile | 5 +- .../powerpc-unknown-linux-gnu/Dockerfile | 5 +- .../powerpc64-unknown-linux-gnu/Dockerfile | 6 +- .../powerpc64le-unknown-linux-gnu/Dockerfile | 5 +- .../riscv64gc-unknown-linux-gnu/Dockerfile | 5 +- .../ci/docker/thumbv6m-none-eabi/Dockerfile | 3 +- .../ci/docker/thumbv7em-none-eabi/Dockerfile | 3 +- .../docker/thumbv7em-none-eabihf/Dockerfile | 3 +- .../ci/docker/thumbv7m-none-eabi/Dockerfile | 3 +- .../docker/wasm32-unknown-unknown/Dockerfile | 1 + .../x86_64-unknown-linux-gnu/Dockerfile | 3 +- library/compiler-builtins/ci/run.sh | 7 +- 24 files changed, 161 insertions(+), 119 deletions(-) rename library/compiler-builtins/.github/workflows/{main.yml => main.yaml} (62%) rename library/compiler-builtins/.github/workflows/{publish.yml => publish.yaml} (100%) diff --git a/library/compiler-builtins/.github/workflows/main.yml b/library/compiler-builtins/.github/workflows/main.yaml similarity index 62% rename from library/compiler-builtins/.github/workflows/main.yml rename to library/compiler-builtins/.github/workflows/main.yaml index 003102d59438f..eec747a243638 100644 --- a/library/compiler-builtins/.github/workflows/main.yml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -1,105 +1,85 @@ name: CI -on: [push, pull_request] +on: + push: { branches: [master] } + pull_request: + +concurrency: + # Make sure that new pushes cancel running jobs + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true env: + CARGO_TERM_COLOR: always RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings + RUST_BACKTRACE: full jobs: test: - name: Test - runs-on: ${{ matrix.os }} + name: Build and test + timeout-minutes: 60 strategy: fail-fast: false matrix: include: - target: aarch64-apple-darwin - os: macos-latest - rust: nightly + os: macos-15 - target: aarch64-unknown-linux-gnu - os: ubuntu-latest - rust: nightly + os: ubuntu-24.04-arm - target: aarch64-pc-windows-msvc - os: windows-latest - rust: nightly + os: windows-2025 test_verbatim: 1 - no_std: 1 + build_only: 1 - target: arm-unknown-linux-gnueabi - os: ubuntu-latest - rust: nightly + os: ubuntu-24.04 - target: arm-unknown-linux-gnueabihf - os: ubuntu-latest - rust: nightly + os: ubuntu-24.04 + - target: armv7-unknown-linux-gnueabihf + os: ubuntu-24.04 - target: i586-unknown-linux-gnu - os: ubuntu-latest - rust: nightly + os: ubuntu-24.04 - target: i686-unknown-linux-gnu - os: ubuntu-latest - rust: nightly + os: ubuntu-24.04 - target: loongarch64-unknown-linux-gnu - os: ubuntu-latest - rust: nightly - # MIPS targets disabled since they are dropped to tier 3. - # See https://github.com/rust-lang/compiler-team/issues/648 - #- target: mips-unknown-linux-gnu - # os: ubuntu-latest - # rust: nightly - #- target: mips64-unknown-linux-gnuabi64 - # os: ubuntu-latest - # rust: nightly - #- target: mips64el-unknown-linux-gnuabi64 - # os: ubuntu-latest - # rust: nightly - #- target: mipsel-unknown-linux-gnu - # os: ubuntu-latest - # rust: nightly + os: ubuntu-24.04 - target: powerpc-unknown-linux-gnu - os: ubuntu-latest - rust: nightly + os: ubuntu-24.04 - target: powerpc64-unknown-linux-gnu - os: ubuntu-latest - rust: nightly + os: ubuntu-24.04 - target: powerpc64le-unknown-linux-gnu - os: ubuntu-latest - rust: nightly + os: ubuntu-24.04 - target: riscv64gc-unknown-linux-gnu - os: ubuntu-latest - rust: nightly + os: ubuntu-24.04 - target: thumbv6m-none-eabi - os: ubuntu-latest - rust: nightly + os: ubuntu-24.04 - target: thumbv7em-none-eabi - os: ubuntu-latest - rust: nightly + os: ubuntu-24.04 - target: thumbv7em-none-eabihf - os: ubuntu-latest - rust: nightly + os: ubuntu-24.04 - target: thumbv7m-none-eabi - os: ubuntu-latest - rust: nightly + os: ubuntu-24.04 - target: wasm32-unknown-unknown - os: ubuntu-latest - rust: nightly + os: ubuntu-24.04 - target: x86_64-unknown-linux-gnu - os: ubuntu-latest - rust: nightly + os: ubuntu-24.04 - target: x86_64-apple-darwin os: macos-13 - rust: nightly - target: i686-pc-windows-msvc - os: windows-latest - rust: nightly + os: windows-2025 test_verbatim: 1 - target: x86_64-pc-windows-msvc - os: windows-latest - rust: nightly + os: windows-2025 test_verbatim: 1 - target: i686-pc-windows-gnu - os: windows-latest - rust: nightly-i686-gnu + os: windows-2025 + channel: nightly-i686-gnu - target: x86_64-pc-windows-gnu - os: windows-latest - rust: nightly-x86_64-gnu + os: windows-2025 + channel: nightly-x86_64-gnu + runs-on: ${{ matrix.os }} + env: + BUILD_ONLY: ${{ matrix.build_only }} + TEST_VERBATIM: ${{ matrix.test_verbatim }} steps: - name: Print runner information run: uname -a @@ -107,16 +87,21 @@ jobs: with: submodules: true - name: Install Rust (rustup) - run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }} shell: bash - - run: rustup target add ${{ matrix.target }} - - run: rustup component add llvm-tools-preview + run: | + channel="nightly" + # Account for channels that have required components (MinGW) + [ -n "${{ matrix.channel }}" ] && channel="${{ matrix.channel }}" + rustup update "$channel" --no-self-update + rustup default "$channel" + rustup target add "${{ matrix.target }}" + rustup component add llvm-tools-preview - uses: Swatinem/rust-cache@v2 with: key: ${{ matrix.target }} - name: Cache Docker layers uses: actions/cache@v4 - if: matrix.os == 'ubuntu-latest' + if: matrix.os == 'ubuntu-24.04' with: path: /tmp/.buildx-cache key: ${{ matrix.target }}-buildx-${{ github.sha }} @@ -136,33 +121,49 @@ jobs: shell: bash # Non-linux tests just use our raw script - - run: ./ci/run.sh ${{ matrix.target }} - if: matrix.os != 'ubuntu-latest' + - name: Run locally + if: matrix.os != 'ubuntu-24.04' shell: bash - env: - NO_STD: ${{ matrix.no_std }} - TEST_VERBATIM: ${{ matrix.test_verbatim }} + run: ./ci/run.sh ${{ matrix.target }} # Configure buildx to use Docker layer caching - uses: docker/setup-buildx-action@v3 - if: matrix.os == 'ubuntu-latest' + if: matrix.os == 'ubuntu-24.04' # Otherwise we use our docker containers to run builds - - run: cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} - if: matrix.os == 'ubuntu-latest' + - name: Run in Docker + if: matrix.os == 'ubuntu-24.04' + run: cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} # Workaround to keep Docker cache smaller # https://github.com/docker/build-push-action/issues/252 # https://github.com/moby/buildkit/issues/1896 - name: Move Docker cache - if: matrix.os == 'ubuntu-latest' + if: matrix.os == 'ubuntu-24.04' run: | rm -rf /tmp/.buildx-cache mv /tmp/.buildx-cache-new /tmp/.buildx-cache + clippy: + name: Clippy + runs-on: ubuntu-24.04 + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + with: + submodules: true + # Unlike rustfmt, stable clippy does not work on code with nightly features. + - name: Install nightly `clippy` + run: | + rustup set profile minimal + rustup default nightly + rustup component add clippy + - uses: Swatinem/rust-cache@v2 + - run: cargo clippy -- -D clippy::all + miri: name: Miri - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 with: @@ -177,7 +178,7 @@ jobs: rustfmt: name: Rustfmt - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 with: @@ -186,27 +187,13 @@ jobs: run: rustup set profile minimal && rustup default stable && rustup component add rustfmt - run: cargo fmt -- --check - clippy: - name: Clippy - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: true - # Unlike rustfmt, stable clippy does not work on code with nightly features. - - name: Install nightly `clippy` - run: | - rustup set profile minimal && rustup default nightly && rustup component add clippy - - uses: Swatinem/rust-cache@v2 - - run: cargo clippy -- -D clippy::all - success: needs: - test - rustfmt - clippy - miri - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency # failed" as success. So we have to do some contortions to ensure the job fails if any of its # dependencies fails. diff --git a/library/compiler-builtins/.github/workflows/publish.yml b/library/compiler-builtins/.github/workflows/publish.yaml similarity index 100% rename from library/compiler-builtins/.github/workflows/publish.yml rename to library/compiler-builtins/.github/workflows/publish.yaml 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 1aef14a962d64..df71804ba235e 100644 --- a/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -1,11 +1,16 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ - gcc-aarch64-linux-gnu libc6-dev-arm64-cross \ + gcc-aarch64-linux-gnu m4 make libc6-dev-arm64-cross \ qemu-user-static -ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ + +ENV TOOLCHAIN_PREFIX=aarch64-linux-gnu- +ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER=qemu-aarch64-static \ + AR_aarch64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_aarch64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/aarch64-linux-gnu \ RUST_TEST_THREADS=1 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 fc9803777f823..38ad1a136236c 100644 --- a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile @@ -1,10 +1,15 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-linux-gnueabi libc6-dev-armel-cross qemu-user-static -ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER=arm-linux-gnueabi-gcc \ + +ENV TOOLCHAIN_PREFIX=arm-linux-gnueabi- +ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_RUNNER=qemu-arm-static \ + AR_arm_unknown_linux_gnueabi="$TOOLCHAIN_PREFIX"ar \ + CC_arm_unknown_linux_gnueabi="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabi \ RUST_TEST_THREADS=1 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 a127f67cb7311..ffead05d5f22f 100644 --- a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile @@ -1,10 +1,15 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static -ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + +ENV TOOLCHAIN_PREFIX=arm-linux-gnueabihf- +ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \ + AR_arm_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"ar \ + CC_arm_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ RUST_TEST_THREADS=1 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 67a3e51a96457..9ab49e46ee3aa 100644 --- a/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile @@ -1,10 +1,15 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static -ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + +ENV TOOLCHAIN_PREFIX=arm-linux-gnueabihf- +ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \ + AR_armv7_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"ar \ + CC_armv7_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ RUST_TEST_THREADS=1 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 15285d9bb060e..d12ced3257fe3 100644 --- a/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile @@ -1,5 +1,6 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ - gcc-multilib libc6-dev ca-certificates + gcc-multilib m4 make libc6-dev ca-certificates 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 15285d9bb060e..d12ced3257fe3 100644 --- a/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile @@ -1,5 +1,6 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ - gcc-multilib libc6-dev ca-certificates + gcc-multilib m4 make libc6-dev ca-certificates 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 5107d20a2a80d..62b43da9e70d6 100644 --- a/library/compiler-builtins/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile @@ -8,6 +8,7 @@ RUN apt-get update && \ ENV CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_LINKER=loongarch64-linux-gnu-gcc-14 \ CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_RUNNER=qemu-loongarch64-static \ + AR_loongarch64_unknown_linux_gnu=loongarch64-linux-gnu-ar \ CC_loongarch64_unknown_linux_gnu=loongarch64-linux-gnu-gcc-14 \ QEMU_LD_PREFIX=/usr/loongarch64-linux-gnu \ RUST_TEST_THREADS=1 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 a47dd9f193134..c02a94672340e 100644 --- a/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile @@ -7,7 +7,10 @@ RUN apt-get update && \ gcc-mips-linux-gnu libc6-dev-mips-cross \ binfmt-support qemu-user-static qemu-system-mips -ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER=mips-linux-gnu-gcc \ +ENV TOOLCHAIN_PREFIX=mips-linux-gnu- +ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_RUNNER=qemu-mips-static \ + AR_mips_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_mips_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/mips-linux-gnu \ RUST_TEST_THREADS=1 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 688aa1ab231a1..6d8b96069bedb 100644 --- a/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile @@ -1,5 +1,6 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates \ @@ -9,8 +10,11 @@ RUN apt-get update && \ libc6-dev-mips64-cross \ qemu-user-static \ qemu-system-mips -ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER=mips64-linux-gnuabi64-gcc \ + +ENV TOOLCHAIN_PREFIX=mips64-linux-gnuabi64- +ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64-static \ - CC_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-gcc \ + AR_mips64_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"ar \ + CC_mips64_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/mips64-linux-gnuabi64 \ RUST_TEST_THREADS=1 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 27d032a1441c1..7e6ac7c3b8aae 100644 --- a/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile @@ -1,5 +1,6 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates \ @@ -8,8 +9,11 @@ RUN apt-get update && \ libc6-dev \ libc6-dev-mips64el-cross \ qemu-user-static -ENV CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_LINKER=mips64el-linux-gnuabi64-gcc \ + +ENV TOOLCHAIN_PREFIX=mips64el-linux-gnuabi64- +ENV CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64el-static \ - CC_mips64el_unknown_linux_gnuabi64=mips64el-linux-gnuabi64-gcc \ + AR_mips64el_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"ar \ + CC_mips64el_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/mips64el-linux-gnuabi64 \ RUST_TEST_THREADS=1 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 4d18a6edbc9db..9feadc7b5ce10 100644 --- a/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile @@ -7,7 +7,10 @@ RUN apt-get update && \ gcc-mipsel-linux-gnu libc6-dev-mipsel-cross \ binfmt-support qemu-user-static -ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER=mipsel-linux-gnu-gcc \ +ENV TOOLCHAIN_PREFIX=mipsel-linux-gnu- +ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_RUNNER=qemu-mipsel-static \ + AR_mipsel_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_mipsel_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/mipsel-linux-gnu \ RUST_TEST_THREADS=1 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 5225b833c0c07..84dcaf47ed5d1 100644 --- a/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile @@ -7,7 +7,10 @@ RUN apt-get update && \ gcc-powerpc-linux-gnu libc6-dev-powerpc-cross \ qemu-system-ppc -ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER=powerpc-linux-gnu-gcc \ +ENV TOOLCHAIN_PREFIX=powerpc-linux-gnu- +ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc-static \ + AR_powerpc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_powerpc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/powerpc-linux-gnu \ RUST_TEST_THREADS=1 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 cbd78eac4217c..b90fd5ec54562 100644 --- a/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile @@ -7,8 +7,10 @@ RUN apt-get update && \ gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross \ binfmt-support qemu-user-static qemu-system-ppc -ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER=powerpc64-linux-gnu-gcc \ +ENV TOOLCHAIN_PREFIX=powerpc64-linux-gnu- +ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64-static \ - CC_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-gcc \ + AR_powerpc64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_powerpc64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu \ RUST_TEST_THREADS=1 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 bad064297c394..e6d1d1cd0b53f 100644 --- a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile @@ -7,8 +7,11 @@ RUN apt-get update && \ gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross \ qemu-system-ppc -ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER=powerpc64le-linux-gnu-gcc \ +ENV TOOLCHAIN_PREFIX=powerpc64le-linux-gnu- +ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64le-static \ + AR_powerpc64le_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_powerpc64le_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_CPU=POWER8 \ QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu \ RUST_TEST_THREADS=1 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 4d4a194fdc670..eeb4ed0193e2d 100644 --- a/library/compiler-builtins/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile @@ -7,7 +7,10 @@ RUN apt-get update && \ gcc-riscv64-linux-gnu libc6-dev-riscv64-cross \ qemu-system-riscv64 -ENV CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER=riscv64-linux-gnu-gcc \ +ENV TOOLCHAIN_PREFIX=riscv64-linux-gnu- +ENV CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_RUNNER=qemu-riscv64-static \ + AR_riscv64gc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ + CC_riscv64gc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ QEMU_LD_PREFIX=/usr/riscv64-linux-gnu \ RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile index f966b2b9f2a5f..ad0d4351ea654 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -1,8 +1,9 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-none-eabi \ libnewlib-arm-none-eabi -ENV NO_STD=1 +ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile index f966b2b9f2a5f..ad0d4351ea654 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -1,8 +1,9 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-none-eabi \ libnewlib-arm-none-eabi -ENV NO_STD=1 +ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile index f966b2b9f2a5f..ad0d4351ea654 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -1,8 +1,9 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-none-eabi \ libnewlib-arm-none-eabi -ENV NO_STD=1 +ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile index f966b2b9f2a5f..ad0d4351ea654 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -1,8 +1,9 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev ca-certificates \ gcc-arm-none-eabi \ libnewlib-arm-none-eabi -ENV NO_STD=1 +ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile b/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile index 4d12b6ff4265b..2813d318670ea 100644 --- a/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile +++ b/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile @@ -1,5 +1,6 @@ ARG IMAGE=ubuntu:20.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc clang libc6-dev ca-certificates 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 670c2439764d6..c590adcddf64d 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,5 +1,6 @@ ARG IMAGE=ubuntu:24.04 FROM $IMAGE + RUN apt-get update && \ apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates + gcc m4 make libc6-dev ca-certificates diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 8dcb139d49386..49cc1628652cc 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -2,9 +2,10 @@ set -eux -target="${1:-}" - export RUST_BACKTRACE="${RUST_BACKTRACE:-full}" +export NEXTEST_STATUS_LEVEL=all + +target="${1:-}" if [ -z "$target" ]; then host_target=$(rustc -vV | awk '/^host/ { print $2 }') @@ -20,7 +21,7 @@ if [ "${USING_CONTAINER_RUSTC:-}" = 1 ]; then fi # Test our implementation -if [ "${NO_STD:-}" = "1" ]; then +if [ "${BUILD_ONLY:-}" = "1" ]; then echo "nothing to do for no_std" else run="cargo test --package builtins-test --no-fail-fast --target $target" From b0d6024f203fbf80c090e829115b2dbf459a8464 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 04:55:59 +0000 Subject: [PATCH 1828/4206] ci: Update `ci/run-docker.sh` to match libm Prepare for having the repositories combined by ensuring EMULATED, RUST_BACKTRACE, and CI are set or forwarded as applicable. Also re-indent the file to four spaces and do some reorganization. --- library/compiler-builtins/ci/run-docker.sh | 124 ++++++++++++--------- 1 file changed, 69 insertions(+), 55 deletions(-) diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 5e19cf4d0cbe8..2c27ab7955b3f 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -5,88 +5,102 @@ set -euxo pipefail +host_arch="$(uname -m | sed 's/arm64/aarch64/')" + run() { local target="$1" - echo "TESTING TARGET: $target" + echo "testing target: $target" + + emulated="" + target_arch="$(echo "$target" | cut -d'-' -f1)" + if [ "$target_arch" != "$host_arch" ]; then + emulated=1 + echo "target is emulated" + fi # This directory needs to exist before calling docker, otherwise docker will create it but it # will be owned by root mkdir -p target + run_cmd="HOME=/tmp" + + if [ "${GITHUB_ACTIONS:-}" = "true" ]; then + # Enable Docker image caching on GHA + build_cmd=("buildx" "build") + build_args=( + "--cache-from" "type=local,src=/tmp/.buildx-cache" + "--cache-to" "type=local,dest=/tmp/.buildx-cache-new" + # This is the beautiful bash syntax for expanding an array but neither + # raising an error nor returning an empty string if the array is empty. + "${build_args[@]:+"${build_args[@]}"}" + "--load" + ) + fi + if [ "$(uname -s)" = "Linux" ] && [ -z "${DOCKER_BASE_IMAGE:-}" ]; then - # Share the host rustc and target. Do this only on Linux and if the image - # isn't overridden - run_args=( - --user "$(id -u):$(id -g)" - -e "CARGO_HOME=/cargo" - -v "${HOME}/.cargo:/cargo" - -v "$(pwd)/target:/builtins-target" - -v "$(rustc --print sysroot):/rust:ro" - ) - run_cmd="HOME=/tmp PATH=\$PATH:/rust/bin ci/run.sh $target" + # Share the host rustc and target. Do this only on Linux and if the image + # isn't overridden + run_args=( + --user "$(id -u):$(id -g)" + -e "CARGO_HOME=/cargo" + -v "${HOME}/.cargo:/cargo" + -v "$(pwd)/target:/builtins-target" + -v "$(rustc --print sysroot):/rust:ro" + ) + run_cmd="$run_cmd PATH=\$PATH:/rust/bin" else - # Use rustc provided by a docker image - docker volume create compiler-builtins-cache - build_args=( - "--build-arg" "IMAGE=${DOCKER_BASE_IMAGE:-rustlang/rust:nightly}" - ) - run_args=( - -v "compiler-builtins-cache:/builtins-target" - ) - run_cmd="HOME=/tmp USING_CONTAINER_RUSTC=1 ci/run.sh $target" + # Use rustc provided by a docker image + docker volume create compiler-builtins-cache + build_args=( + "--build-arg" "IMAGE=${DOCKER_BASE_IMAGE:-rustlang/rust:nightly}" + ) + run_args=(-v "compiler-builtins-cache:/builtins-target") + run_cmd="$run_cmd HOME=/tmp" "USING_CONTAINER_RUSTC=1" fi if [ -d compiler-rt ]; then - export RUST_COMPILER_RT_ROOT="/checkout/compiler-rt" + export RUST_COMPILER_RT_ROOT="/checkout/compiler-rt" fi - if [ "${GITHUB_ACTIONS:-}" = "true" ]; then - # Enable Docker image caching on GHA - - build_cmd=("buildx" "build") - build_args=( - "--cache-from" "type=local,src=/tmp/.buildx-cache" - "--cache-to" "type=local,dest=/tmp/.buildx-cache-new" - # This is the beautiful bash syntax for expanding an array but neither - # raising an error nor returning an empty string if the array is empty. - "${build_args[@]:+"${build_args[@]}"}" - "--load" - ) - fi + run_cmd="$run_cmd ci/run.sh $target" docker "${build_cmd[@]:-build}" \ - -t "builtins-$target" \ - "${build_args[@]:-}" \ - "ci/docker/$target" + -t "builtins-$target" \ + "${build_args[@]:-}" \ + "ci/docker/$target" docker run \ - --rm \ - -e RUST_COMPILER_RT_ROOT \ - -e RUSTFLAGS \ - -e "CARGO_TARGET_DIR=/builtins-target" \ - -v "$(pwd):/checkout:ro" \ - -w /checkout \ - "${run_args[@]:-}" \ - --init \ - "builtins-$target" \ - sh -c "$run_cmd" + --rm \ + -e CI \ + -e CARGO_TARGET_DIR=/builtins-target \ + -e CARGO_TERM_COLOR \ + -e RUSTFLAGS \ + -e RUST_BACKTRACE \ + -e RUST_COMPILER_RT_ROOT \ + -e "EMULATED=$emulated" \ + -v "$(pwd):/checkout:ro" \ + -w /checkout \ + "${run_args[@]:-}" \ + --init \ + "builtins-$target" \ + sh -c "$run_cmd" } if [ "${1:-}" = "--help" ] || [ "$#" -gt 1 ]; then - set +x - echo "\ + set +x + echo "\ usage: ./ci/run-docker.sh [target] you can also set DOCKER_BASE_IMAGE to use something other than the default ubuntu:24.04 (or rustlang/rust:nightly). - " - exit + " + exit fi if [ -z "${1:-}" ]; then - for d in ci/docker/*; do - run $(basename "$d") - done + for d in ci/docker/*; do + run $(basename "$d") + done else - run "$1" + run "$1" fi From 0b27121212078b55296e5daf9332300266043d18 Mon Sep 17 00:00:00 2001 From: Cornelius Roemer Date: Sat, 19 Apr 2025 16:42:20 +0200 Subject: [PATCH 1829/4206] Fix clippy::version of elidable_lifetime_names to 1.87 The lint becomes part of stable in 1.87, not in 1.84 --- clippy_lints/src/lifetimes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index fd6208f6b5efe..de35a458afb55 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -88,7 +88,7 @@ declare_clippy_lint! { /// x.chars() /// } /// ``` - #[clippy::version = "1.84.0"] + #[clippy::version = "1.87.0"] pub ELIDABLE_LIFETIME_NAMES, pedantic, "lifetime name that can be replaced with the anonymous lifetime" From 1947f328a70b42aca3b6866c73ace5fe0e75deb2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 23:13:44 +0000 Subject: [PATCH 1830/4206] Remove the libm submodule --- library/compiler-builtins/.gitmodules | 3 --- library/compiler-builtins/compiler-builtins/libm | 1 - 2 files changed, 4 deletions(-) delete mode 160000 library/compiler-builtins/compiler-builtins/libm diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index a0b0d021deae8..e69de29bb2d1d 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -1,3 +0,0 @@ -[submodule "compiler-builtins/libm"] - path = compiler-builtins/libm - url = https://github.com/rust-lang/libm.git diff --git a/library/compiler-builtins/compiler-builtins/libm b/library/compiler-builtins/compiler-builtins/libm deleted file mode 160000 index 96d1400326f47..0000000000000 --- a/library/compiler-builtins/compiler-builtins/libm +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 96d1400326f47381858f8149451a2b2fd8de2ea4 From d794bb3492edf7506d4b59e168cb38bc528051b6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 23:42:14 +0000 Subject: [PATCH 1831/4206] Update submodules after the `libm` merge --- library/compiler-builtins/.gitmodules | 4 ++++ library/compiler-builtins/libm/.gitmodules | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) delete mode 100644 library/compiler-builtins/libm/.gitmodules diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index e69de29bb2d1d..ee941a47e776a 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -0,0 +1,4 @@ +[submodule "musl"] + path = libm/crates/musl-math-sys/musl + url = https://git.musl-libc.org/git/musl + shallow = true diff --git a/library/compiler-builtins/libm/.gitmodules b/library/compiler-builtins/libm/.gitmodules deleted file mode 100644 index 35b269eadd4e1..0000000000000 --- a/library/compiler-builtins/libm/.gitmodules +++ /dev/null @@ -1,4 +0,0 @@ -[submodule "musl"] - path = crates/musl-math-sys/musl - url = https://git.musl-libc.org/git/musl - shallow = true From 1af955be9a76d162abdf32125d0af88798104a09 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 23:44:45 +0000 Subject: [PATCH 1832/4206] Update path to libm after the merge --- library/compiler-builtins/compiler-builtins/src/math.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-builtins/src/math.rs b/library/compiler-builtins/compiler-builtins/src/math.rs index ccd9c54216c66..bd52a749e39a3 100644 --- a/library/compiler-builtins/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/compiler-builtins/src/math.rs @@ -2,7 +2,7 @@ #[allow(dead_code)] #[allow(unused_imports)] #[allow(clippy::all)] -#[path = "../libm/src/math/mod.rs"] +#[path = "../../libm/libm/src/math/mod.rs"] pub(crate) mod libm; macro_rules! libm_intrinsics { From 83a8482f9167e6a602e1ce95ee66831896dd8ec3 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 18 Apr 2025 23:48:27 +0000 Subject: [PATCH 1833/4206] Update .git-blame-ignore-revs after the libm merge --- library/compiler-builtins/{libm => }/.git-blame-ignore-revs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) rename library/compiler-builtins/{libm => }/.git-blame-ignore-revs (58%) diff --git a/library/compiler-builtins/libm/.git-blame-ignore-revs b/library/compiler-builtins/.git-blame-ignore-revs similarity index 58% rename from library/compiler-builtins/libm/.git-blame-ignore-revs rename to library/compiler-builtins/.git-blame-ignore-revs index c1e43134f36fd..2ede10da53d74 100644 --- a/library/compiler-builtins/libm/.git-blame-ignore-revs +++ b/library/compiler-builtins/.git-blame-ignore-revs @@ -2,4 +2,5 @@ # `git blame` ignore the following commits. # Reformat with a new `.rustfmt.toml` -5882cabb83c30bf7c36023f9a55a80583636b0e8 +# In rust-lang/libm this was 5882cabb83c30bf7c36023f9a55a80583636b0e8 +4bb07a6275cc628ef81c65ac971dc6479963322f From 806bb4fa6e35f65e63e1b96953fab68bfe5a67b4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 20:44:21 +0000 Subject: [PATCH 1834/4206] libm: Remove compiler-builtins-smoke-test Since `libm` is now part of the `compiler-builtins` repo, the crate to test that they work together is no longer needed. --- .../compiler-builtins-smoke-test/Cargo.toml | 38 ---- .../compiler-builtins-smoke-test/build.rs | 8 - .../compiler-builtins-smoke-test/src/lib.rs | 17 -- .../compiler-builtins-smoke-test/src/math.rs | 182 ------------------ 4 files changed, 245 deletions(-) delete mode 100644 library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml delete mode 100644 library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs delete mode 100644 library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs delete mode 100644 library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml deleted file mode 100644 index 38a5116690a7c..0000000000000 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/Cargo.toml +++ /dev/null @@ -1,38 +0,0 @@ -[package] -name = "cb" -version = "0.1.0" -authors = ["Jorge Aparicio "] -edition = "2021" -publish = false - -[lib] -crate-type = ["staticlib"] -test = false -bench = false - -[features] -default = ["arch", "compiler-builtins", "unstable-float"] - -# Copied from `libm`'s root `Cargo.toml`' -arch = [] -compiler-builtins = [] -unstable-float = [] - -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = [ - "cfg(arch_enabled)", - "cfg(assert_no_panic)", - "cfg(intrinsics_enabled)", - 'cfg(feature, values("force-soft-floats"))', - 'cfg(feature, values("unstable"))', - 'cfg(feature, values("unstable-intrinsics"))', - 'cfg(feature, values("unstable-public-internals"))', -] } - -[profile.dev] -panic = "abort" - -[profile.release] -panic = "abort" -codegen-units = 1 -lto = "fat" diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs deleted file mode 100644 index ef8d613c9f45b..0000000000000 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -#[path = "../../libm/configure.rs"] -mod configure; - -fn main() { - println!("cargo:rerun-if-changed=../../libm/configure.rs"); - let cfg = configure::Config::from_env(); - configure::emit_libm_config(&cfg); -} diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs deleted file mode 100644 index e70f6d9e04c9c..0000000000000 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! Fake compiler-builtins crate -//! -//! This is used to test that we can source import `libm` into the compiler-builtins crate. -//! Additionally, it provides a `#[no_mangle]` C API that can be easier to inspect than the -//! default `.rlib`. - -#![compiler_builtins] -#![feature(core_intrinsics)] -#![feature(compiler_builtins)] -#![feature(f16)] -#![feature(f128)] -#![allow(internal_features)] -#![no_std] - -mod math; -// Required for macro paths. -use math::libm::support; diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs deleted file mode 100644 index 58a5bfbb90f9e..0000000000000 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/math.rs +++ /dev/null @@ -1,182 +0,0 @@ -use core::ffi::c_int; - -#[allow(dead_code)] -#[allow(clippy::all)] // We don't get `libm`'s list of `allow`s, so just ignore Clippy. -#[allow(unused_imports)] -#[path = "../../../libm/src/math/mod.rs"] -pub mod libm; - -/// Mark functions `#[no_mangle]` and with the C ABI. -macro_rules! no_mangle { - ($( $name:ident( $($tt:tt)+ ) -> $ret:ty; )+) => { - $( no_mangle!(@inner $name( $($tt)+ ) -> $ret); )+ - }; - - // Handle simple functions with single return types - (@inner $name:ident( $($arg:ident: $aty:ty),+ ) -> $ret:ty) => { - #[unsafe(no_mangle)] - extern "C" fn $name($($arg: $aty),+) -> $ret { - libm::$name($($arg),+) - } - }; - - - // Functions with `&mut` return values need to be handled differently, use `|` to - // separate inputs vs. outputs. - ( - @inner $name:ident( $($arg:ident: $aty:ty),+ | $($rarg:ident: $rty:ty),+) -> $ret:ty - ) => { - #[unsafe(no_mangle)] - extern "C" fn $name($($arg: $aty,)+ $($rarg: $rty),+) -> $ret { - let ret; - (ret, $(*$rarg),+) = libm::$name($($arg),+); - ret - } - }; -} - -no_mangle! { - frexp(x: f64 | y: &mut c_int) -> f64; - frexpf(x: f32 | y: &mut c_int) -> f32; - acos(x: f64) -> f64; - acosf(x: f32) -> f32; - acosh(x: f64) -> f64; - acoshf(x: f32) -> f32; - asin(x: f64) -> f64; - asinf(x: f32) -> f32; - asinh(x: f64) -> f64; - asinhf(x: f32) -> f32; - atan(x: f64) -> f64; - atan2(x: f64, y: f64) -> f64; - atan2f(x: f32, y: f32) -> f32; - atanf(x: f32) -> f32; - atanh(x: f64) -> f64; - atanhf(x: f32) -> f32; - cbrt(x: f64) -> f64; - cbrtf(x: f32) -> f32; - ceil(x: f64) -> f64; - ceilf(x: f32) -> f32; - ceilf128(x: f128) -> f128; - ceilf16(x: f16) -> f16; - copysign(x: f64, y: f64) -> f64; - copysignf(x: f32, y: f32) -> f32; - copysignf128(x: f128, y: f128) -> f128; - copysignf16(x: f16, y: f16) -> f16; - cos(x: f64) -> f64; - cosf(x: f32) -> f32; - cosh(x: f64) -> f64; - coshf(x: f32) -> f32; - erf(x: f64) -> f64; - erfc(x: f64) -> f64; - erfcf(x: f32) -> f32; - erff(x: f32) -> f32; - exp(x: f64) -> f64; - exp10(x: f64) -> f64; - exp10f(x: f32) -> f32; - exp2(x: f64) -> f64; - exp2f(x: f32) -> f32; - expf(x: f32) -> f32; - expm1(x: f64) -> f64; - expm1f(x: f32) -> f32; - fabs(x: f64) -> f64; - fabsf(x: f32) -> f32; - fabsf128(x: f128) -> f128; - fabsf16(x: f16) -> f16; - fdim(x: f64, y: f64) -> f64; - fdimf(x: f32, y: f32) -> f32; - fdimf128(x: f128, y: f128) -> f128; - fdimf16(x: f16, y: f16) -> f16; - floor(x: f64) -> f64; - floorf(x: f32) -> f32; - floorf128(x: f128) -> f128; - floorf16(x: f16) -> f16; - fma(x: f64, y: f64, z: f64) -> f64; - fmaf(x: f32, y: f32, z: f32) -> f32; - fmax(x: f64, y: f64) -> f64; - fmaxf(x: f32, y: f32) -> f32; - fmin(x: f64, y: f64) -> f64; - fminf(x: f32, y: f32) -> f32; - fmod(x: f64, y: f64) -> f64; - fmodf(x: f32, y: f32) -> f32; - hypot(x: f64, y: f64) -> f64; - hypotf(x: f32, y: f32) -> f32; - ilogb(x: f64) -> c_int; - ilogbf(x: f32) -> c_int; - j0(x: f64) -> f64; - j0f(x: f32) -> f32; - j1(x: f64) -> f64; - j1f(x: f32) -> f32; - jn(x: c_int, y: f64) -> f64; - jnf(x: c_int, y: f32) -> f32; - ldexp(x: f64, y: c_int) -> f64; - ldexpf(x: f32, y: c_int) -> f32; - lgamma(x: f64) -> f64; - lgamma_r(x: f64 | r: &mut c_int) -> f64; - lgammaf(x: f32) -> f32; - lgammaf_r(x: f32 | r: &mut c_int) -> f32; - log(x: f64) -> f64; - log10(x: f64) -> f64; - log10f(x: f32) -> f32; - log1p(x: f64) -> f64; - log1pf(x: f32) -> f32; - log2(x: f64) -> f64; - log2f(x: f32) -> f32; - logf(x: f32) -> f32; - modf(x: f64 | r: &mut f64) -> f64; - modff(x: f32 | r: &mut f32) -> f32; - nextafter(x: f64, y: f64) -> f64; - nextafterf(x: f32, y: f32) -> f32; - pow(x: f64, y: f64) -> f64; - powf(x: f32, y: f32) -> f32; - remainder(x: f64, y: f64) -> f64; - remainderf(x: f32, y: f32) -> f32; - remquo(x: f64, y: f64 | q: &mut c_int) -> f64; - remquof(x: f32, y: f32 | q: &mut c_int) -> f32; - rint(x: f64) -> f64; - rintf(x: f32) -> f32; - rintf128(x: f128) -> f128; - rintf16(x: f16) -> f16; - round(x: f64) -> f64; - roundf(x: f32) -> f32; - scalbn(x: f64, y: c_int) -> f64; - scalbnf(x: f32, y: c_int) -> f32; - sin(x: f64) -> f64; - sinf(x: f32) -> f32; - sinh(x: f64) -> f64; - sinhf(x: f32) -> f32; - sqrt(x: f64) -> f64; - sqrtf(x: f32) -> f32; - tan(x: f64) -> f64; - tanf(x: f32) -> f32; - tanh(x: f64) -> f64; - tanhf(x: f32) -> f32; - tgamma(x: f64) -> f64; - tgammaf(x: f32) -> f32; - trunc(x: f64) -> f64; - truncf(x: f32) -> f32; - truncf128(x: f128) -> f128; - truncf16(x: f16) -> f16; - y0(x: f64) -> f64; - y0f(x: f32) -> f32; - y1(x: f64) -> f64; - y1f(x: f32) -> f32; - yn(x: c_int, y: f64) -> f64; - ynf(x: c_int, y: f32) -> f32; -} - -/* sincos has no direct return type, not worth handling in the macro */ - -#[unsafe(no_mangle)] -extern "C" fn sincos(x: f64, s: &mut f64, c: &mut f64) { - (*s, *c) = libm::sincos(x); -} - -#[unsafe(no_mangle)] -extern "C" fn sincosf(x: f32, s: &mut f32, c: &mut f32) { - (*s, *c) = libm::sincosf(x); -} - -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} From 911a70381a9e7c84400b156e3cbcd805f3e64034 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 20:58:25 +0000 Subject: [PATCH 1835/4206] libm: Reorganize into compiler-builtins Distribute everything from `libm/` to better locations in the repo. `libm/libm/*` has not moved yet to avoid Git seeing the move as an edit to `Cargo.toml`. Files that remain to be merged somehow are in `etc/libm`. --- .../{libm => }/crates/libm-macros/Cargo.toml | 0 .../crates/libm-macros/src/enums.rs | 0 .../{libm => }/crates/libm-macros/src/lib.rs | 0 .../crates/libm-macros/src/parse.rs | 0 .../crates/libm-macros/src/shared.rs | 0 .../crates/libm-macros/tests/basic.rs | 0 .../crates/libm-macros/tests/enum.rs | 0 .../crates/musl-math-sys/Cargo.toml | 0 .../{libm => }/crates/musl-math-sys/build.rs | 0 .../crates/musl-math-sys/c_patches/alias.c | 0 .../crates/musl-math-sys/c_patches/features.h | 0 .../crates/musl-math-sys/src/lib.rs | 0 .../{libm => }/crates/util/Cargo.toml | 0 .../{libm => }/crates/util/build.rs | 0 .../{libm => }/crates/util/src/main.rs | 0 .../{libm => }/etc/function-definitions.json | 0 .../{libm => }/etc/function-list.txt | 0 .../{ => etc}/libm/.editorconfig | 0 .../libm/.github/workflows/main.yaml | 0 .../libm/.github/workflows/publish.yaml | 0 .../{ => etc}/libm/.gitignore | 0 .../{ => etc}/libm/Cargo.toml | 0 .../{ => etc}/libm/ci/bench-icount.sh | 0 .../{ => etc}/libm/ci/ci-util.py | 0 .../aarch64-unknown-linux-gnu/Dockerfile | 0 .../arm-unknown-linux-gnueabi/Dockerfile | 0 .../arm-unknown-linux-gnueabihf/Dockerfile | 0 .../armv7-unknown-linux-gnueabihf/Dockerfile | 0 .../docker/i586-unknown-linux-gnu/Dockerfile | 0 .../docker/i686-unknown-linux-gnu/Dockerfile | 0 .../loongarch64-unknown-linux-gnu/Dockerfile | 0 .../docker/mips-unknown-linux-gnu/Dockerfile | 0 .../mips64-unknown-linux-gnuabi64/Dockerfile | 0 .../Dockerfile | 0 .../mipsel-unknown-linux-gnu/Dockerfile | 0 .../powerpc-unknown-linux-gnu/Dockerfile | 0 .../powerpc64-unknown-linux-gnu/Dockerfile | 0 .../powerpc64le-unknown-linux-gnu/Dockerfile | 0 .../riscv64gc-unknown-linux-gnu/Dockerfile | 0 .../ci/docker/thumbv6m-none-eabi/Dockerfile | 0 .../ci/docker/thumbv7em-none-eabi/Dockerfile | 0 .../docker/thumbv7em-none-eabihf/Dockerfile | 0 .../ci/docker/thumbv7m-none-eabi/Dockerfile | 0 .../x86_64-unknown-linux-gnu/Dockerfile | 0 .../{ => etc}/libm/ci/run-docker.sh | 0 .../{ => etc}/libm/ci/run.sh | 0 .../{libm => }/etc/update-api-list.py | 0 .../{libm/crates => }/libm-test/Cargo.toml | 0 .../crates => }/libm-test/benches/icount.rs | 0 .../crates => }/libm-test/benches/random.rs | 0 .../{libm/crates => }/libm-test/build.rs | 0 .../libm-test/examples/plot_domains.rs | 0 .../libm-test/examples/plot_file.jl | 0 .../{libm/crates => }/libm-test/src/domain.rs | 0 .../crates => }/libm-test/src/f8_impl.rs | 0 .../crates => }/libm-test/src/generate.rs | 0 .../libm-test/src/generate/case_list.rs | 0 .../libm-test/src/generate/edge_cases.rs | 0 .../libm-test/src/generate/random.rs | 0 .../libm-test/src/generate/spaced.rs | 0 .../{libm/crates => }/libm-test/src/lib.rs | 0 .../crates => }/libm-test/src/mpfloat.rs | 0 .../{libm/crates => }/libm-test/src/num.rs | 0 .../{libm/crates => }/libm-test/src/op.rs | 0 .../crates => }/libm-test/src/precision.rs | 0 .../crates => }/libm-test/src/run_cfg.rs | 0 .../crates => }/libm-test/src/test_traits.rs | 0 .../libm-test/tests/check_coverage.rs | 0 .../libm-test/tests/compare_built_musl.rs | 0 .../libm-test/tests/multiprecision.rs | 0 .../crates => }/libm-test/tests/standalone.rs | 0 .../{libm/crates => }/libm-test/tests/u256.rs | 0 .../libm-test/tests/z_extensive/main.rs | 0 .../libm-test/tests/z_extensive/run.rs | 0 library/compiler-builtins/libm/LICENSE.txt | 258 ----------------- library/compiler-builtins/libm/README.md | 56 ---- .../libm/crates/musl-math-sys/musl | 1 - .../compiler-builtins/libm/libm/LICENSE.txt | 259 +++++++++++++++++- library/compiler-builtins/libm/libm/README.md | 57 +++- 79 files changed, 314 insertions(+), 317 deletions(-) rename library/compiler-builtins/{libm => }/crates/libm-macros/Cargo.toml (100%) rename library/compiler-builtins/{libm => }/crates/libm-macros/src/enums.rs (100%) rename library/compiler-builtins/{libm => }/crates/libm-macros/src/lib.rs (100%) rename library/compiler-builtins/{libm => }/crates/libm-macros/src/parse.rs (100%) rename library/compiler-builtins/{libm => }/crates/libm-macros/src/shared.rs (100%) rename library/compiler-builtins/{libm => }/crates/libm-macros/tests/basic.rs (100%) rename library/compiler-builtins/{libm => }/crates/libm-macros/tests/enum.rs (100%) rename library/compiler-builtins/{libm => }/crates/musl-math-sys/Cargo.toml (100%) rename library/compiler-builtins/{libm => }/crates/musl-math-sys/build.rs (100%) rename library/compiler-builtins/{libm => }/crates/musl-math-sys/c_patches/alias.c (100%) rename library/compiler-builtins/{libm => }/crates/musl-math-sys/c_patches/features.h (100%) rename library/compiler-builtins/{libm => }/crates/musl-math-sys/src/lib.rs (100%) rename library/compiler-builtins/{libm => }/crates/util/Cargo.toml (100%) rename library/compiler-builtins/{libm => }/crates/util/build.rs (100%) rename library/compiler-builtins/{libm => }/crates/util/src/main.rs (100%) rename library/compiler-builtins/{libm => }/etc/function-definitions.json (100%) rename library/compiler-builtins/{libm => }/etc/function-list.txt (100%) rename library/compiler-builtins/{ => etc}/libm/.editorconfig (100%) rename library/compiler-builtins/{ => etc}/libm/.github/workflows/main.yaml (100%) rename library/compiler-builtins/{ => etc}/libm/.github/workflows/publish.yaml (100%) rename library/compiler-builtins/{ => etc}/libm/.gitignore (100%) rename library/compiler-builtins/{ => etc}/libm/Cargo.toml (100%) rename library/compiler-builtins/{ => etc}/libm/ci/bench-icount.sh (100%) rename library/compiler-builtins/{ => etc}/libm/ci/ci-util.py (100%) rename library/compiler-builtins/{ => etc}/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile (100%) rename library/compiler-builtins/{ => etc}/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile (100%) rename library/compiler-builtins/{ => etc}/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile (100%) rename library/compiler-builtins/{ => etc}/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile (100%) rename library/compiler-builtins/{ => etc}/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile (100%) rename library/compiler-builtins/{ => etc}/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile (100%) rename library/compiler-builtins/{ => etc}/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile (100%) rename library/compiler-builtins/{ => etc}/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile (100%) rename library/compiler-builtins/{ => etc}/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile (100%) rename library/compiler-builtins/{ => etc}/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile (100%) rename library/compiler-builtins/{ => etc}/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile (100%) rename library/compiler-builtins/{ => etc}/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile (100%) rename library/compiler-builtins/{ => etc}/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile (100%) rename library/compiler-builtins/{ => etc}/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile (100%) rename library/compiler-builtins/{ => etc}/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile (100%) rename library/compiler-builtins/{ => etc}/libm/ci/docker/thumbv6m-none-eabi/Dockerfile (100%) rename library/compiler-builtins/{ => etc}/libm/ci/docker/thumbv7em-none-eabi/Dockerfile (100%) rename library/compiler-builtins/{ => etc}/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile (100%) rename library/compiler-builtins/{ => etc}/libm/ci/docker/thumbv7m-none-eabi/Dockerfile (100%) rename library/compiler-builtins/{ => etc}/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile (100%) rename library/compiler-builtins/{ => etc}/libm/ci/run-docker.sh (100%) rename library/compiler-builtins/{ => etc}/libm/ci/run.sh (100%) rename library/compiler-builtins/{libm => }/etc/update-api-list.py (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/Cargo.toml (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/benches/icount.rs (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/benches/random.rs (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/build.rs (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/examples/plot_domains.rs (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/examples/plot_file.jl (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/src/domain.rs (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/src/f8_impl.rs (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/src/generate.rs (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/src/generate/case_list.rs (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/src/generate/edge_cases.rs (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/src/generate/random.rs (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/src/generate/spaced.rs (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/src/lib.rs (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/src/mpfloat.rs (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/src/num.rs (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/src/op.rs (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/src/precision.rs (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/src/run_cfg.rs (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/src/test_traits.rs (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/tests/check_coverage.rs (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/tests/compare_built_musl.rs (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/tests/multiprecision.rs (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/tests/standalone.rs (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/tests/u256.rs (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/tests/z_extensive/main.rs (100%) rename library/compiler-builtins/{libm/crates => }/libm-test/tests/z_extensive/run.rs (100%) delete mode 100644 library/compiler-builtins/libm/LICENSE.txt delete mode 100644 library/compiler-builtins/libm/README.md delete mode 160000 library/compiler-builtins/libm/crates/musl-math-sys/musl mode change 120000 => 100644 library/compiler-builtins/libm/libm/LICENSE.txt mode change 120000 => 100644 library/compiler-builtins/libm/libm/README.md diff --git a/library/compiler-builtins/libm/crates/libm-macros/Cargo.toml b/library/compiler-builtins/crates/libm-macros/Cargo.toml similarity index 100% rename from library/compiler-builtins/libm/crates/libm-macros/Cargo.toml rename to library/compiler-builtins/crates/libm-macros/Cargo.toml diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs b/library/compiler-builtins/crates/libm-macros/src/enums.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-macros/src/enums.rs rename to library/compiler-builtins/crates/libm-macros/src/enums.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs b/library/compiler-builtins/crates/libm-macros/src/lib.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-macros/src/lib.rs rename to library/compiler-builtins/crates/libm-macros/src/lib.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/parse.rs b/library/compiler-builtins/crates/libm-macros/src/parse.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-macros/src/parse.rs rename to library/compiler-builtins/crates/libm-macros/src/parse.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/crates/libm-macros/src/shared.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-macros/src/shared.rs rename to library/compiler-builtins/crates/libm-macros/src/shared.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs b/library/compiler-builtins/crates/libm-macros/tests/basic.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-macros/tests/basic.rs rename to library/compiler-builtins/crates/libm-macros/tests/basic.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs b/library/compiler-builtins/crates/libm-macros/tests/enum.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs rename to library/compiler-builtins/crates/libm-macros/tests/enum.rs diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml b/library/compiler-builtins/crates/musl-math-sys/Cargo.toml similarity index 100% rename from library/compiler-builtins/libm/crates/musl-math-sys/Cargo.toml rename to library/compiler-builtins/crates/musl-math-sys/Cargo.toml diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/build.rs b/library/compiler-builtins/crates/musl-math-sys/build.rs similarity index 100% rename from library/compiler-builtins/libm/crates/musl-math-sys/build.rs rename to library/compiler-builtins/crates/musl-math-sys/build.rs diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/c_patches/alias.c b/library/compiler-builtins/crates/musl-math-sys/c_patches/alias.c similarity index 100% rename from library/compiler-builtins/libm/crates/musl-math-sys/c_patches/alias.c rename to library/compiler-builtins/crates/musl-math-sys/c_patches/alias.c diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/c_patches/features.h b/library/compiler-builtins/crates/musl-math-sys/c_patches/features.h similarity index 100% rename from library/compiler-builtins/libm/crates/musl-math-sys/c_patches/features.h rename to library/compiler-builtins/crates/musl-math-sys/c_patches/features.h diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs b/library/compiler-builtins/crates/musl-math-sys/src/lib.rs similarity index 100% rename from library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs rename to library/compiler-builtins/crates/musl-math-sys/src/lib.rs diff --git a/library/compiler-builtins/libm/crates/util/Cargo.toml b/library/compiler-builtins/crates/util/Cargo.toml similarity index 100% rename from library/compiler-builtins/libm/crates/util/Cargo.toml rename to library/compiler-builtins/crates/util/Cargo.toml diff --git a/library/compiler-builtins/libm/crates/util/build.rs b/library/compiler-builtins/crates/util/build.rs similarity index 100% rename from library/compiler-builtins/libm/crates/util/build.rs rename to library/compiler-builtins/crates/util/build.rs diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/crates/util/src/main.rs similarity index 100% rename from library/compiler-builtins/libm/crates/util/src/main.rs rename to library/compiler-builtins/crates/util/src/main.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/etc/function-definitions.json similarity index 100% rename from library/compiler-builtins/libm/etc/function-definitions.json rename to library/compiler-builtins/etc/function-definitions.json diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/etc/function-list.txt similarity index 100% rename from library/compiler-builtins/libm/etc/function-list.txt rename to library/compiler-builtins/etc/function-list.txt diff --git a/library/compiler-builtins/libm/.editorconfig b/library/compiler-builtins/etc/libm/.editorconfig similarity index 100% rename from library/compiler-builtins/libm/.editorconfig rename to library/compiler-builtins/etc/libm/.editorconfig diff --git a/library/compiler-builtins/libm/.github/workflows/main.yaml b/library/compiler-builtins/etc/libm/.github/workflows/main.yaml similarity index 100% rename from library/compiler-builtins/libm/.github/workflows/main.yaml rename to library/compiler-builtins/etc/libm/.github/workflows/main.yaml diff --git a/library/compiler-builtins/libm/.github/workflows/publish.yaml b/library/compiler-builtins/etc/libm/.github/workflows/publish.yaml similarity index 100% rename from library/compiler-builtins/libm/.github/workflows/publish.yaml rename to library/compiler-builtins/etc/libm/.github/workflows/publish.yaml diff --git a/library/compiler-builtins/libm/.gitignore b/library/compiler-builtins/etc/libm/.gitignore similarity index 100% rename from library/compiler-builtins/libm/.gitignore rename to library/compiler-builtins/etc/libm/.gitignore diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/etc/libm/Cargo.toml similarity index 100% rename from library/compiler-builtins/libm/Cargo.toml rename to library/compiler-builtins/etc/libm/Cargo.toml diff --git a/library/compiler-builtins/libm/ci/bench-icount.sh b/library/compiler-builtins/etc/libm/ci/bench-icount.sh similarity index 100% rename from library/compiler-builtins/libm/ci/bench-icount.sh rename to library/compiler-builtins/etc/libm/ci/bench-icount.sh diff --git a/library/compiler-builtins/libm/ci/ci-util.py b/library/compiler-builtins/etc/libm/ci/ci-util.py similarity index 100% rename from library/compiler-builtins/libm/ci/ci-util.py rename to library/compiler-builtins/etc/libm/ci/ci-util.py diff --git a/library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile similarity index 100% rename from library/compiler-builtins/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile rename to library/compiler-builtins/etc/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile diff --git a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile similarity index 100% rename from library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile rename to library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile diff --git a/library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile similarity index 100% rename from library/compiler-builtins/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile rename to library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile diff --git a/library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile similarity index 100% rename from library/compiler-builtins/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile rename to library/compiler-builtins/etc/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile diff --git a/library/compiler-builtins/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile similarity index 100% rename from library/compiler-builtins/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile rename to library/compiler-builtins/etc/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile diff --git a/library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile similarity index 100% rename from library/compiler-builtins/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile rename to library/compiler-builtins/etc/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile diff --git a/library/compiler-builtins/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile similarity index 100% rename from library/compiler-builtins/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile rename to library/compiler-builtins/etc/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile diff --git a/library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile similarity index 100% rename from library/compiler-builtins/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile rename to library/compiler-builtins/etc/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile diff --git a/library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile similarity index 100% rename from library/compiler-builtins/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile rename to library/compiler-builtins/etc/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile diff --git a/library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile similarity index 100% rename from library/compiler-builtins/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile rename to library/compiler-builtins/etc/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile diff --git a/library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile similarity index 100% rename from library/compiler-builtins/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile rename to library/compiler-builtins/etc/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile diff --git a/library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile similarity index 100% rename from library/compiler-builtins/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile rename to library/compiler-builtins/etc/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile diff --git a/library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile similarity index 100% rename from library/compiler-builtins/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile rename to library/compiler-builtins/etc/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile diff --git a/library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile similarity index 100% rename from library/compiler-builtins/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile rename to library/compiler-builtins/etc/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile diff --git a/library/compiler-builtins/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile similarity index 100% rename from library/compiler-builtins/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile rename to library/compiler-builtins/etc/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile diff --git a/library/compiler-builtins/libm/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/thumbv6m-none-eabi/Dockerfile similarity index 100% rename from library/compiler-builtins/libm/ci/docker/thumbv6m-none-eabi/Dockerfile rename to library/compiler-builtins/etc/libm/ci/docker/thumbv6m-none-eabi/Dockerfile diff --git a/library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabi/Dockerfile similarity index 100% rename from library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabi/Dockerfile rename to library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabi/Dockerfile diff --git a/library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile similarity index 100% rename from library/compiler-builtins/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile rename to library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile diff --git a/library/compiler-builtins/libm/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/thumbv7m-none-eabi/Dockerfile similarity index 100% rename from library/compiler-builtins/libm/ci/docker/thumbv7m-none-eabi/Dockerfile rename to library/compiler-builtins/etc/libm/ci/docker/thumbv7m-none-eabi/Dockerfile diff --git a/library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile similarity index 100% rename from library/compiler-builtins/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile rename to library/compiler-builtins/etc/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile diff --git a/library/compiler-builtins/libm/ci/run-docker.sh b/library/compiler-builtins/etc/libm/ci/run-docker.sh similarity index 100% rename from library/compiler-builtins/libm/ci/run-docker.sh rename to library/compiler-builtins/etc/libm/ci/run-docker.sh diff --git a/library/compiler-builtins/libm/ci/run.sh b/library/compiler-builtins/etc/libm/ci/run.sh similarity index 100% rename from library/compiler-builtins/libm/ci/run.sh rename to library/compiler-builtins/etc/libm/ci/run.sh diff --git a/library/compiler-builtins/libm/etc/update-api-list.py b/library/compiler-builtins/etc/update-api-list.py similarity index 100% rename from library/compiler-builtins/libm/etc/update-api-list.py rename to library/compiler-builtins/etc/update-api-list.py diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm-test/Cargo.toml similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/Cargo.toml rename to library/compiler-builtins/libm-test/Cargo.toml diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm-test/benches/icount.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/benches/icount.rs rename to library/compiler-builtins/libm-test/benches/icount.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm-test/benches/random.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/benches/random.rs rename to library/compiler-builtins/libm-test/benches/random.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/build.rs b/library/compiler-builtins/libm-test/build.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/build.rs rename to library/compiler-builtins/libm-test/build.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs b/library/compiler-builtins/libm-test/examples/plot_domains.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/examples/plot_domains.rs rename to library/compiler-builtins/libm-test/examples/plot_domains.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/examples/plot_file.jl b/library/compiler-builtins/libm-test/examples/plot_file.jl similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/examples/plot_file.jl rename to library/compiler-builtins/libm-test/examples/plot_file.jl diff --git a/library/compiler-builtins/libm/crates/libm-test/src/domain.rs b/library/compiler-builtins/libm-test/src/domain.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/src/domain.rs rename to library/compiler-builtins/libm-test/src/domain.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm-test/src/f8_impl.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs rename to library/compiler-builtins/libm-test/src/f8_impl.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/generate.rs b/library/compiler-builtins/libm-test/src/generate.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/src/generate.rs rename to library/compiler-builtins/libm-test/src/generate.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/generate/case_list.rs b/library/compiler-builtins/libm-test/src/generate/case_list.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/src/generate/case_list.rs rename to library/compiler-builtins/libm-test/src/generate/case_list.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/generate/edge_cases.rs b/library/compiler-builtins/libm-test/src/generate/edge_cases.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/src/generate/edge_cases.rs rename to library/compiler-builtins/libm-test/src/generate/edge_cases.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/generate/random.rs b/library/compiler-builtins/libm-test/src/generate/random.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/src/generate/random.rs rename to library/compiler-builtins/libm-test/src/generate/random.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/generate/spaced.rs b/library/compiler-builtins/libm-test/src/generate/spaced.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/src/generate/spaced.rs rename to library/compiler-builtins/libm-test/src/generate/spaced.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm-test/src/lib.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/src/lib.rs rename to library/compiler-builtins/libm-test/src/lib.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm-test/src/mpfloat.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs rename to library/compiler-builtins/libm-test/src/mpfloat.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/num.rs b/library/compiler-builtins/libm-test/src/num.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/src/num.rs rename to library/compiler-builtins/libm-test/src/num.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/op.rs b/library/compiler-builtins/libm-test/src/op.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/src/op.rs rename to library/compiler-builtins/libm-test/src/op.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/precision.rs b/library/compiler-builtins/libm-test/src/precision.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/src/precision.rs rename to library/compiler-builtins/libm-test/src/precision.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm-test/src/run_cfg.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/src/run_cfg.rs rename to library/compiler-builtins/libm-test/src/run_cfg.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs b/library/compiler-builtins/libm-test/src/test_traits.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/src/test_traits.rs rename to library/compiler-builtins/libm-test/src/test_traits.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs b/library/compiler-builtins/libm-test/tests/check_coverage.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/tests/check_coverage.rs rename to library/compiler-builtins/libm-test/tests/check_coverage.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm-test/tests/compare_built_musl.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs rename to library/compiler-builtins/libm-test/tests/compare_built_musl.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs b/library/compiler-builtins/libm-test/tests/multiprecision.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/tests/multiprecision.rs rename to library/compiler-builtins/libm-test/tests/multiprecision.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/standalone.rs b/library/compiler-builtins/libm-test/tests/standalone.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/tests/standalone.rs rename to library/compiler-builtins/libm-test/tests/standalone.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/u256.rs b/library/compiler-builtins/libm-test/tests/u256.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/tests/u256.rs rename to library/compiler-builtins/libm-test/tests/u256.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/main.rs b/library/compiler-builtins/libm-test/tests/z_extensive/main.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/main.rs rename to library/compiler-builtins/libm-test/tests/z_extensive/main.rs diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs b/library/compiler-builtins/libm-test/tests/z_extensive/run.rs similarity index 100% rename from library/compiler-builtins/libm/crates/libm-test/tests/z_extensive/run.rs rename to library/compiler-builtins/libm-test/tests/z_extensive/run.rs diff --git a/library/compiler-builtins/libm/LICENSE.txt b/library/compiler-builtins/libm/LICENSE.txt deleted file mode 100644 index 2f8e41f147472..0000000000000 --- a/library/compiler-builtins/libm/LICENSE.txt +++ /dev/null @@ -1,258 +0,0 @@ -rust-lang/libm as a whole is available for use under the MIT license: - ------------------------------------------------------------------------------- -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ------------------------------------------------------------------------------- - -As a contributor, you agree that your code can be used under either the MIT -license or the Apache-2.0 license: - ------------------------------------------------------------------------------- - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ------------------------------------------------------------------------------- - -This Rust library contains the following copyrights: - - Copyright (c) 2018 Jorge Aparicio - -Portions of this software are derived from third-party works licensed under -terms compatible with the above MIT license: - -* musl libc https://www.musl-libc.org/. This library contains the following - copyright: - - Copyright © 2005-2020 Rich Felker, et al. - -* The CORE-MATH project https://core-math.gitlabpages.inria.fr/. CORE-MATH - routines are available under the MIT license on a per-file basis. - -The musl libc COPYRIGHT file also includes the following notice relevant to -math portions of the library: - ------------------------------------------------------------------------------- -Much of the math library code (src/math/* and src/complex/*) is -Copyright © 1993,2004 Sun Microsystems or -Copyright © 2003-2011 David Schultz or -Copyright © 2003-2009 Steven G. Kargl or -Copyright © 2003-2009 Bruce D. Evans or -Copyright © 2008 Stephen L. Moshier or -Copyright © 2017-2018 Arm Limited -and labelled as such in comments in the individual source files. All -have been licensed under extremely permissive terms. ------------------------------------------------------------------------------- - -Copyright notices are retained in src/* files where relevant. diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md deleted file mode 100644 index 52d760a4f1599..0000000000000 --- a/library/compiler-builtins/libm/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# `libm` - -A port of [MUSL]'s libm to Rust. - -[MUSL]: https://musl.libc.org/ - -## Goals - -The short term goal of this library is to [enable math support (e.g. `sin`, `atan2`) for the -`wasm32-unknown-unknown` target][wasm] (cf. [rust-lang/compiler-builtins][pr]). The longer -term goal is to enable [math support in the `core` crate][core]. - -[wasm]: https://github.com/rust-lang/libm/milestone/1 -[pr]: https://github.com/rust-lang/compiler-builtins/pull/248 -[core]: https://github.com/rust-lang/libm/milestone/2 - -## Already usable - -This crate is [on crates.io] and can be used today in stable `#![no_std]` programs. - -The API documentation can be found [here](https://docs.rs/libm). - -[on crates.io]: https://crates.io/crates/libm - -## Benchmark -[benchmark]: #benchmark - -The benchmarks are located in `crates/libm-bench` and require a nightly Rust toolchain. -To run all benchmarks: - -> cargo +nightly bench --all - -## Contributing - -Please check [CONTRIBUTING.md](CONTRIBUTING.md) - -## Minimum Rust version policy - -This crate supports rustc 1.63 and newer. - -## License - -Usage is licensed under the MIT license ([LICENSE-MIT](LICENSE-MIT) or -https://opensource.org/licenses/MIT). - - -### Contribution - -Contributions are licensed under both the MIT license and the Apache License, -Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or -https://www.apache.org/licenses/LICENSE-2.0). Unless you explicitly state -otherwise, any contribution intentionally submitted for inclusion in the work -by you, as defined in the Apache-2.0 license, shall be dual licensed as -mentioned, without any additional terms or conditions. - -See `LICENSE.txt` for full details. diff --git a/library/compiler-builtins/libm/crates/musl-math-sys/musl b/library/compiler-builtins/libm/crates/musl-math-sys/musl deleted file mode 160000 index 61399d4bd02ae..0000000000000 --- a/library/compiler-builtins/libm/crates/musl-math-sys/musl +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 61399d4bd02ae1ec03068445aa7ffe9174466bfd diff --git a/library/compiler-builtins/libm/libm/LICENSE.txt b/library/compiler-builtins/libm/libm/LICENSE.txt deleted file mode 120000 index 4ab43736a839d..0000000000000 --- a/library/compiler-builtins/libm/libm/LICENSE.txt +++ /dev/null @@ -1 +0,0 @@ -../LICENSE.txt \ No newline at end of file diff --git a/library/compiler-builtins/libm/libm/LICENSE.txt b/library/compiler-builtins/libm/libm/LICENSE.txt new file mode 100644 index 0000000000000..2f8e41f147472 --- /dev/null +++ b/library/compiler-builtins/libm/libm/LICENSE.txt @@ -0,0 +1,258 @@ +rust-lang/libm as a whole is available for use under the MIT license: + +------------------------------------------------------------------------------ +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ + +As a contributor, you agree that your code can be used under either the MIT +license or the Apache-2.0 license: + +------------------------------------------------------------------------------ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +------------------------------------------------------------------------------ + +This Rust library contains the following copyrights: + + Copyright (c) 2018 Jorge Aparicio + +Portions of this software are derived from third-party works licensed under +terms compatible with the above MIT license: + +* musl libc https://www.musl-libc.org/. This library contains the following + copyright: + + Copyright © 2005-2020 Rich Felker, et al. + +* The CORE-MATH project https://core-math.gitlabpages.inria.fr/. CORE-MATH + routines are available under the MIT license on a per-file basis. + +The musl libc COPYRIGHT file also includes the following notice relevant to +math portions of the library: + +------------------------------------------------------------------------------ +Much of the math library code (src/math/* and src/complex/*) is +Copyright © 1993,2004 Sun Microsystems or +Copyright © 2003-2011 David Schultz or +Copyright © 2003-2009 Steven G. Kargl or +Copyright © 2003-2009 Bruce D. Evans or +Copyright © 2008 Stephen L. Moshier or +Copyright © 2017-2018 Arm Limited +and labelled as such in comments in the individual source files. All +have been licensed under extremely permissive terms. +------------------------------------------------------------------------------ + +Copyright notices are retained in src/* files where relevant. diff --git a/library/compiler-builtins/libm/libm/README.md b/library/compiler-builtins/libm/libm/README.md deleted file mode 120000 index 32d46ee883b58..0000000000000 --- a/library/compiler-builtins/libm/libm/README.md +++ /dev/null @@ -1 +0,0 @@ -../README.md \ No newline at end of file diff --git a/library/compiler-builtins/libm/libm/README.md b/library/compiler-builtins/libm/libm/README.md new file mode 100644 index 0000000000000..52d760a4f1599 --- /dev/null +++ b/library/compiler-builtins/libm/libm/README.md @@ -0,0 +1,56 @@ +# `libm` + +A port of [MUSL]'s libm to Rust. + +[MUSL]: https://musl.libc.org/ + +## Goals + +The short term goal of this library is to [enable math support (e.g. `sin`, `atan2`) for the +`wasm32-unknown-unknown` target][wasm] (cf. [rust-lang/compiler-builtins][pr]). The longer +term goal is to enable [math support in the `core` crate][core]. + +[wasm]: https://github.com/rust-lang/libm/milestone/1 +[pr]: https://github.com/rust-lang/compiler-builtins/pull/248 +[core]: https://github.com/rust-lang/libm/milestone/2 + +## Already usable + +This crate is [on crates.io] and can be used today in stable `#![no_std]` programs. + +The API documentation can be found [here](https://docs.rs/libm). + +[on crates.io]: https://crates.io/crates/libm + +## Benchmark +[benchmark]: #benchmark + +The benchmarks are located in `crates/libm-bench` and require a nightly Rust toolchain. +To run all benchmarks: + +> cargo +nightly bench --all + +## Contributing + +Please check [CONTRIBUTING.md](CONTRIBUTING.md) + +## Minimum Rust version policy + +This crate supports rustc 1.63 and newer. + +## License + +Usage is licensed under the MIT license ([LICENSE-MIT](LICENSE-MIT) or +https://opensource.org/licenses/MIT). + + +### Contribution + +Contributions are licensed under both the MIT license and the Apache License, +Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or +https://www.apache.org/licenses/LICENSE-2.0). Unless you explicitly state +otherwise, any contribution intentionally submitted for inclusion in the work +by you, as defined in the Apache-2.0 license, shall be dual licensed as +mentioned, without any additional terms or conditions. + +See `LICENSE.txt` for full details. From 8b8bd8a0fd75e43a9b282284b849e651828ceec2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 21:09:49 +0000 Subject: [PATCH 1836/4206] libm: Flatten the `libm/libm` directory --- library/compiler-builtins/compiler-builtins/src/math.rs | 2 +- library/compiler-builtins/libm/{libm => }/Cargo.toml | 0 library/compiler-builtins/libm/{libm => }/LICENSE.txt | 0 library/compiler-builtins/libm/{libm => }/README.md | 0 library/compiler-builtins/libm/{libm => }/build.rs | 0 library/compiler-builtins/libm/{libm => }/configure.rs | 0 library/compiler-builtins/libm/{libm => }/src/lib.rs | 0 library/compiler-builtins/libm/{libm => }/src/libm_helper.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/acos.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/acosf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/acosh.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/acoshf.rs | 0 .../compiler-builtins/libm/{libm => }/src/math/arch/aarch64.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/arch/i586.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/arch/i686.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/arch/mod.rs | 0 .../compiler-builtins/libm/{libm => }/src/math/arch/wasm32.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/asin.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/asinf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/asinh.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/asinhf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/atan.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/atan2.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/atan2f.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/atanf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/atanh.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/atanhf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/cbrt.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/cbrtf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/ceil.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/copysign.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/copysignf.rs | 0 .../compiler-builtins/libm/{libm => }/src/math/copysignf128.rs | 0 .../compiler-builtins/libm/{libm => }/src/math/copysignf16.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/cos.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/cosf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/cosh.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/coshf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/erf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/erff.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/exp.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/exp10.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/exp10f.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/exp2.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/exp2f.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/expf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/expm1.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/expm1f.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/expo2.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/fabs.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/fabsf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/fabsf128.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/fabsf16.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/fdim.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/fdimf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/fdimf128.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/fdimf16.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/floor.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/floorf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/floorf128.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/floorf16.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/fma.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/fma_wide.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/fmin_fmax.rs | 0 .../libm/{libm => }/src/math/fminimum_fmaximum.rs | 0 .../libm/{libm => }/src/math/fminimum_fmaximum_num.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/fmod.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/fmodf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/fmodf128.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/fmodf16.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/frexp.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/frexpf.rs | 0 .../compiler-builtins/libm/{libm => }/src/math/generic/ceil.rs | 0 .../libm/{libm => }/src/math/generic/copysign.rs | 0 .../compiler-builtins/libm/{libm => }/src/math/generic/fabs.rs | 0 .../compiler-builtins/libm/{libm => }/src/math/generic/fdim.rs | 0 .../compiler-builtins/libm/{libm => }/src/math/generic/floor.rs | 0 .../compiler-builtins/libm/{libm => }/src/math/generic/fmax.rs | 0 .../libm/{libm => }/src/math/generic/fmaximum.rs | 0 .../libm/{libm => }/src/math/generic/fmaximum_num.rs | 0 .../compiler-builtins/libm/{libm => }/src/math/generic/fmin.rs | 0 .../libm/{libm => }/src/math/generic/fminimum.rs | 0 .../libm/{libm => }/src/math/generic/fminimum_num.rs | 0 .../compiler-builtins/libm/{libm => }/src/math/generic/fmod.rs | 0 .../compiler-builtins/libm/{libm => }/src/math/generic/mod.rs | 0 .../compiler-builtins/libm/{libm => }/src/math/generic/rint.rs | 0 .../compiler-builtins/libm/{libm => }/src/math/generic/round.rs | 0 .../libm/{libm => }/src/math/generic/scalbn.rs | 0 .../compiler-builtins/libm/{libm => }/src/math/generic/sqrt.rs | 0 .../compiler-builtins/libm/{libm => }/src/math/generic/trunc.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/hypot.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/hypotf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/ilogb.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/ilogbf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/j0.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/j0f.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/j1.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/j1f.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/jn.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/jnf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/k_cos.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/k_cosf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/k_expo2.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/k_expo2f.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/k_sin.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/k_sinf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/k_tan.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/k_tanf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/ldexp.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/ldexpf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/ldexpf128.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/ldexpf16.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/lgamma.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/lgamma_r.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/lgammaf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/lgammaf_r.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/log.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/log10.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/log10f.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/log1p.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/log1pf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/log2.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/log2f.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/logf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/mod.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/modf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/modff.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/nextafter.rs | 0 .../compiler-builtins/libm/{libm => }/src/math/nextafterf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/pow.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/powf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/rem_pio2.rs | 0 .../libm/{libm => }/src/math/rem_pio2_large.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/rem_pio2f.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/remainder.rs | 0 .../compiler-builtins/libm/{libm => }/src/math/remainderf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/remquo.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/remquof.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/rint.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/round.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/roundeven.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/roundf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/roundf128.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/roundf16.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/scalbn.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/scalbnf.rs | 0 .../compiler-builtins/libm/{libm => }/src/math/scalbnf128.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/scalbnf16.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/sin.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/sincos.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/sincosf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/sinf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/sinh.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/sinhf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/sqrt.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/sqrtf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/sqrtf128.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/sqrtf16.rs | 0 .../compiler-builtins/libm/{libm => }/src/math/support/big.rs | 0 .../libm/{libm => }/src/math/support/big/tests.rs | 0 .../compiler-builtins/libm/{libm => }/src/math/support/env.rs | 0 .../libm/{libm => }/src/math/support/float_traits.rs | 0 .../libm/{libm => }/src/math/support/hex_float.rs | 0 .../libm/{libm => }/src/math/support/int_traits.rs | 0 .../libm/{libm => }/src/math/support/macros.rs | 0 .../compiler-builtins/libm/{libm => }/src/math/support/mod.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/tan.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/tanf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/tanh.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/tanhf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/tgamma.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/tgammaf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/trunc.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/truncf.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/truncf128.rs | 0 library/compiler-builtins/libm/{libm => }/src/math/truncf16.rs | 0 176 files changed, 1 insertion(+), 1 deletion(-) rename library/compiler-builtins/libm/{libm => }/Cargo.toml (100%) rename library/compiler-builtins/libm/{libm => }/LICENSE.txt (100%) rename library/compiler-builtins/libm/{libm => }/README.md (100%) rename library/compiler-builtins/libm/{libm => }/build.rs (100%) rename library/compiler-builtins/libm/{libm => }/configure.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/lib.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/libm_helper.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/acos.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/acosf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/acosh.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/acoshf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/arch/aarch64.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/arch/i586.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/arch/i686.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/arch/mod.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/arch/wasm32.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/asin.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/asinf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/asinh.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/asinhf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/atan.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/atan2.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/atan2f.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/atanf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/atanh.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/atanhf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/cbrt.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/cbrtf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/ceil.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/copysign.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/copysignf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/copysignf128.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/copysignf16.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/cos.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/cosf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/cosh.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/coshf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/erf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/erff.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/exp.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/exp10.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/exp10f.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/exp2.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/exp2f.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/expf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/expm1.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/expm1f.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/expo2.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/fabs.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/fabsf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/fabsf128.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/fabsf16.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/fdim.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/fdimf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/fdimf128.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/fdimf16.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/floor.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/floorf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/floorf128.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/floorf16.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/fma.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/fma_wide.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/fmin_fmax.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/fminimum_fmaximum.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/fminimum_fmaximum_num.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/fmod.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/fmodf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/fmodf128.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/fmodf16.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/frexp.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/frexpf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/generic/ceil.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/generic/copysign.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/generic/fabs.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/generic/fdim.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/generic/floor.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/generic/fmax.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/generic/fmaximum.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/generic/fmaximum_num.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/generic/fmin.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/generic/fminimum.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/generic/fminimum_num.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/generic/fmod.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/generic/mod.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/generic/rint.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/generic/round.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/generic/scalbn.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/generic/sqrt.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/generic/trunc.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/hypot.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/hypotf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/ilogb.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/ilogbf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/j0.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/j0f.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/j1.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/j1f.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/jn.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/jnf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/k_cos.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/k_cosf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/k_expo2.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/k_expo2f.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/k_sin.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/k_sinf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/k_tan.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/k_tanf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/ldexp.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/ldexpf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/ldexpf128.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/ldexpf16.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/lgamma.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/lgamma_r.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/lgammaf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/lgammaf_r.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/log.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/log10.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/log10f.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/log1p.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/log1pf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/log2.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/log2f.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/logf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/mod.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/modf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/modff.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/nextafter.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/nextafterf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/pow.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/powf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/rem_pio2.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/rem_pio2_large.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/rem_pio2f.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/remainder.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/remainderf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/remquo.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/remquof.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/rint.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/round.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/roundeven.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/roundf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/roundf128.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/roundf16.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/scalbn.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/scalbnf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/scalbnf128.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/scalbnf16.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/sin.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/sincos.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/sincosf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/sinf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/sinh.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/sinhf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/sqrt.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/sqrtf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/sqrtf128.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/sqrtf16.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/support/big.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/support/big/tests.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/support/env.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/support/float_traits.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/support/hex_float.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/support/int_traits.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/support/macros.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/support/mod.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/tan.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/tanf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/tanh.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/tanhf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/tgamma.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/tgammaf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/trunc.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/truncf.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/truncf128.rs (100%) rename library/compiler-builtins/libm/{libm => }/src/math/truncf16.rs (100%) diff --git a/library/compiler-builtins/compiler-builtins/src/math.rs b/library/compiler-builtins/compiler-builtins/src/math.rs index bd52a749e39a3..722374f8e4f8f 100644 --- a/library/compiler-builtins/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/compiler-builtins/src/math.rs @@ -2,7 +2,7 @@ #[allow(dead_code)] #[allow(unused_imports)] #[allow(clippy::all)] -#[path = "../../libm/libm/src/math/mod.rs"] +#[path = "../../libm/src/math/mod.rs"] pub(crate) mod libm; macro_rules! libm_intrinsics { diff --git a/library/compiler-builtins/libm/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml similarity index 100% rename from library/compiler-builtins/libm/libm/Cargo.toml rename to library/compiler-builtins/libm/Cargo.toml diff --git a/library/compiler-builtins/libm/libm/LICENSE.txt b/library/compiler-builtins/libm/LICENSE.txt similarity index 100% rename from library/compiler-builtins/libm/libm/LICENSE.txt rename to library/compiler-builtins/libm/LICENSE.txt diff --git a/library/compiler-builtins/libm/libm/README.md b/library/compiler-builtins/libm/README.md similarity index 100% rename from library/compiler-builtins/libm/libm/README.md rename to library/compiler-builtins/libm/README.md diff --git a/library/compiler-builtins/libm/libm/build.rs b/library/compiler-builtins/libm/build.rs similarity index 100% rename from library/compiler-builtins/libm/libm/build.rs rename to library/compiler-builtins/libm/build.rs diff --git a/library/compiler-builtins/libm/libm/configure.rs b/library/compiler-builtins/libm/configure.rs similarity index 100% rename from library/compiler-builtins/libm/libm/configure.rs rename to library/compiler-builtins/libm/configure.rs diff --git a/library/compiler-builtins/libm/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/lib.rs rename to library/compiler-builtins/libm/src/lib.rs diff --git a/library/compiler-builtins/libm/libm/src/libm_helper.rs b/library/compiler-builtins/libm/src/libm_helper.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/libm_helper.rs rename to library/compiler-builtins/libm/src/libm_helper.rs diff --git a/library/compiler-builtins/libm/libm/src/math/acos.rs b/library/compiler-builtins/libm/src/math/acos.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/acos.rs rename to library/compiler-builtins/libm/src/math/acos.rs diff --git a/library/compiler-builtins/libm/libm/src/math/acosf.rs b/library/compiler-builtins/libm/src/math/acosf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/acosf.rs rename to library/compiler-builtins/libm/src/math/acosf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/acosh.rs b/library/compiler-builtins/libm/src/math/acosh.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/acosh.rs rename to library/compiler-builtins/libm/src/math/acosh.rs diff --git a/library/compiler-builtins/libm/libm/src/math/acoshf.rs b/library/compiler-builtins/libm/src/math/acoshf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/acoshf.rs rename to library/compiler-builtins/libm/src/math/acoshf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/arch/aarch64.rs b/library/compiler-builtins/libm/src/math/arch/aarch64.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/arch/aarch64.rs rename to library/compiler-builtins/libm/src/math/arch/aarch64.rs diff --git a/library/compiler-builtins/libm/libm/src/math/arch/i586.rs b/library/compiler-builtins/libm/src/math/arch/i586.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/arch/i586.rs rename to library/compiler-builtins/libm/src/math/arch/i586.rs diff --git a/library/compiler-builtins/libm/libm/src/math/arch/i686.rs b/library/compiler-builtins/libm/src/math/arch/i686.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/arch/i686.rs rename to library/compiler-builtins/libm/src/math/arch/i686.rs diff --git a/library/compiler-builtins/libm/libm/src/math/arch/mod.rs b/library/compiler-builtins/libm/src/math/arch/mod.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/arch/mod.rs rename to library/compiler-builtins/libm/src/math/arch/mod.rs diff --git a/library/compiler-builtins/libm/libm/src/math/arch/wasm32.rs b/library/compiler-builtins/libm/src/math/arch/wasm32.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/arch/wasm32.rs rename to library/compiler-builtins/libm/src/math/arch/wasm32.rs diff --git a/library/compiler-builtins/libm/libm/src/math/asin.rs b/library/compiler-builtins/libm/src/math/asin.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/asin.rs rename to library/compiler-builtins/libm/src/math/asin.rs diff --git a/library/compiler-builtins/libm/libm/src/math/asinf.rs b/library/compiler-builtins/libm/src/math/asinf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/asinf.rs rename to library/compiler-builtins/libm/src/math/asinf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/asinh.rs b/library/compiler-builtins/libm/src/math/asinh.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/asinh.rs rename to library/compiler-builtins/libm/src/math/asinh.rs diff --git a/library/compiler-builtins/libm/libm/src/math/asinhf.rs b/library/compiler-builtins/libm/src/math/asinhf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/asinhf.rs rename to library/compiler-builtins/libm/src/math/asinhf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/atan.rs b/library/compiler-builtins/libm/src/math/atan.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/atan.rs rename to library/compiler-builtins/libm/src/math/atan.rs diff --git a/library/compiler-builtins/libm/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/atan2.rs rename to library/compiler-builtins/libm/src/math/atan2.rs diff --git a/library/compiler-builtins/libm/libm/src/math/atan2f.rs b/library/compiler-builtins/libm/src/math/atan2f.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/atan2f.rs rename to library/compiler-builtins/libm/src/math/atan2f.rs diff --git a/library/compiler-builtins/libm/libm/src/math/atanf.rs b/library/compiler-builtins/libm/src/math/atanf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/atanf.rs rename to library/compiler-builtins/libm/src/math/atanf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/atanh.rs b/library/compiler-builtins/libm/src/math/atanh.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/atanh.rs rename to library/compiler-builtins/libm/src/math/atanh.rs diff --git a/library/compiler-builtins/libm/libm/src/math/atanhf.rs b/library/compiler-builtins/libm/src/math/atanhf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/atanhf.rs rename to library/compiler-builtins/libm/src/math/atanhf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/cbrt.rs b/library/compiler-builtins/libm/src/math/cbrt.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/cbrt.rs rename to library/compiler-builtins/libm/src/math/cbrt.rs diff --git a/library/compiler-builtins/libm/libm/src/math/cbrtf.rs b/library/compiler-builtins/libm/src/math/cbrtf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/cbrtf.rs rename to library/compiler-builtins/libm/src/math/cbrtf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/ceil.rs rename to library/compiler-builtins/libm/src/math/ceil.rs diff --git a/library/compiler-builtins/libm/libm/src/math/copysign.rs b/library/compiler-builtins/libm/src/math/copysign.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/copysign.rs rename to library/compiler-builtins/libm/src/math/copysign.rs diff --git a/library/compiler-builtins/libm/libm/src/math/copysignf.rs b/library/compiler-builtins/libm/src/math/copysignf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/copysignf.rs rename to library/compiler-builtins/libm/src/math/copysignf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/copysignf128.rs b/library/compiler-builtins/libm/src/math/copysignf128.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/copysignf128.rs rename to library/compiler-builtins/libm/src/math/copysignf128.rs diff --git a/library/compiler-builtins/libm/libm/src/math/copysignf16.rs b/library/compiler-builtins/libm/src/math/copysignf16.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/copysignf16.rs rename to library/compiler-builtins/libm/src/math/copysignf16.rs diff --git a/library/compiler-builtins/libm/libm/src/math/cos.rs b/library/compiler-builtins/libm/src/math/cos.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/cos.rs rename to library/compiler-builtins/libm/src/math/cos.rs diff --git a/library/compiler-builtins/libm/libm/src/math/cosf.rs b/library/compiler-builtins/libm/src/math/cosf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/cosf.rs rename to library/compiler-builtins/libm/src/math/cosf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/cosh.rs b/library/compiler-builtins/libm/src/math/cosh.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/cosh.rs rename to library/compiler-builtins/libm/src/math/cosh.rs diff --git a/library/compiler-builtins/libm/libm/src/math/coshf.rs b/library/compiler-builtins/libm/src/math/coshf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/coshf.rs rename to library/compiler-builtins/libm/src/math/coshf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/erf.rs b/library/compiler-builtins/libm/src/math/erf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/erf.rs rename to library/compiler-builtins/libm/src/math/erf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/erff.rs b/library/compiler-builtins/libm/src/math/erff.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/erff.rs rename to library/compiler-builtins/libm/src/math/erff.rs diff --git a/library/compiler-builtins/libm/libm/src/math/exp.rs b/library/compiler-builtins/libm/src/math/exp.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/exp.rs rename to library/compiler-builtins/libm/src/math/exp.rs diff --git a/library/compiler-builtins/libm/libm/src/math/exp10.rs b/library/compiler-builtins/libm/src/math/exp10.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/exp10.rs rename to library/compiler-builtins/libm/src/math/exp10.rs diff --git a/library/compiler-builtins/libm/libm/src/math/exp10f.rs b/library/compiler-builtins/libm/src/math/exp10f.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/exp10f.rs rename to library/compiler-builtins/libm/src/math/exp10f.rs diff --git a/library/compiler-builtins/libm/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/exp2.rs rename to library/compiler-builtins/libm/src/math/exp2.rs diff --git a/library/compiler-builtins/libm/libm/src/math/exp2f.rs b/library/compiler-builtins/libm/src/math/exp2f.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/exp2f.rs rename to library/compiler-builtins/libm/src/math/exp2f.rs diff --git a/library/compiler-builtins/libm/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/expf.rs rename to library/compiler-builtins/libm/src/math/expf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/expm1.rs b/library/compiler-builtins/libm/src/math/expm1.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/expm1.rs rename to library/compiler-builtins/libm/src/math/expm1.rs diff --git a/library/compiler-builtins/libm/libm/src/math/expm1f.rs b/library/compiler-builtins/libm/src/math/expm1f.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/expm1f.rs rename to library/compiler-builtins/libm/src/math/expm1f.rs diff --git a/library/compiler-builtins/libm/libm/src/math/expo2.rs b/library/compiler-builtins/libm/src/math/expo2.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/expo2.rs rename to library/compiler-builtins/libm/src/math/expo2.rs diff --git a/library/compiler-builtins/libm/libm/src/math/fabs.rs b/library/compiler-builtins/libm/src/math/fabs.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/fabs.rs rename to library/compiler-builtins/libm/src/math/fabs.rs diff --git a/library/compiler-builtins/libm/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/fabsf.rs rename to library/compiler-builtins/libm/src/math/fabsf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/fabsf128.rs b/library/compiler-builtins/libm/src/math/fabsf128.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/fabsf128.rs rename to library/compiler-builtins/libm/src/math/fabsf128.rs diff --git a/library/compiler-builtins/libm/libm/src/math/fabsf16.rs b/library/compiler-builtins/libm/src/math/fabsf16.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/fabsf16.rs rename to library/compiler-builtins/libm/src/math/fabsf16.rs diff --git a/library/compiler-builtins/libm/libm/src/math/fdim.rs b/library/compiler-builtins/libm/src/math/fdim.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/fdim.rs rename to library/compiler-builtins/libm/src/math/fdim.rs diff --git a/library/compiler-builtins/libm/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/src/math/fdimf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/fdimf.rs rename to library/compiler-builtins/libm/src/math/fdimf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/fdimf128.rs b/library/compiler-builtins/libm/src/math/fdimf128.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/fdimf128.rs rename to library/compiler-builtins/libm/src/math/fdimf128.rs diff --git a/library/compiler-builtins/libm/libm/src/math/fdimf16.rs b/library/compiler-builtins/libm/src/math/fdimf16.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/fdimf16.rs rename to library/compiler-builtins/libm/src/math/fdimf16.rs diff --git a/library/compiler-builtins/libm/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/floor.rs rename to library/compiler-builtins/libm/src/math/floor.rs diff --git a/library/compiler-builtins/libm/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/floorf.rs rename to library/compiler-builtins/libm/src/math/floorf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/floorf128.rs b/library/compiler-builtins/libm/src/math/floorf128.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/floorf128.rs rename to library/compiler-builtins/libm/src/math/floorf128.rs diff --git a/library/compiler-builtins/libm/libm/src/math/floorf16.rs b/library/compiler-builtins/libm/src/math/floorf16.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/floorf16.rs rename to library/compiler-builtins/libm/src/math/floorf16.rs diff --git a/library/compiler-builtins/libm/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/fma.rs rename to library/compiler-builtins/libm/src/math/fma.rs diff --git a/library/compiler-builtins/libm/libm/src/math/fma_wide.rs b/library/compiler-builtins/libm/src/math/fma_wide.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/fma_wide.rs rename to library/compiler-builtins/libm/src/math/fma_wide.rs diff --git a/library/compiler-builtins/libm/libm/src/math/fmin_fmax.rs b/library/compiler-builtins/libm/src/math/fmin_fmax.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/fmin_fmax.rs rename to library/compiler-builtins/libm/src/math/fmin_fmax.rs diff --git a/library/compiler-builtins/libm/libm/src/math/fminimum_fmaximum.rs b/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/fminimum_fmaximum.rs rename to library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs diff --git a/library/compiler-builtins/libm/libm/src/math/fminimum_fmaximum_num.rs b/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/fminimum_fmaximum_num.rs rename to library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs diff --git a/library/compiler-builtins/libm/libm/src/math/fmod.rs b/library/compiler-builtins/libm/src/math/fmod.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/fmod.rs rename to library/compiler-builtins/libm/src/math/fmod.rs diff --git a/library/compiler-builtins/libm/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/fmodf.rs rename to library/compiler-builtins/libm/src/math/fmodf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/fmodf128.rs b/library/compiler-builtins/libm/src/math/fmodf128.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/fmodf128.rs rename to library/compiler-builtins/libm/src/math/fmodf128.rs diff --git a/library/compiler-builtins/libm/libm/src/math/fmodf16.rs b/library/compiler-builtins/libm/src/math/fmodf16.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/fmodf16.rs rename to library/compiler-builtins/libm/src/math/fmodf16.rs diff --git a/library/compiler-builtins/libm/libm/src/math/frexp.rs b/library/compiler-builtins/libm/src/math/frexp.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/frexp.rs rename to library/compiler-builtins/libm/src/math/frexp.rs diff --git a/library/compiler-builtins/libm/libm/src/math/frexpf.rs b/library/compiler-builtins/libm/src/math/frexpf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/frexpf.rs rename to library/compiler-builtins/libm/src/math/frexpf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/generic/ceil.rs b/library/compiler-builtins/libm/src/math/generic/ceil.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/generic/ceil.rs rename to library/compiler-builtins/libm/src/math/generic/ceil.rs diff --git a/library/compiler-builtins/libm/libm/src/math/generic/copysign.rs b/library/compiler-builtins/libm/src/math/generic/copysign.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/generic/copysign.rs rename to library/compiler-builtins/libm/src/math/generic/copysign.rs diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fabs.rs b/library/compiler-builtins/libm/src/math/generic/fabs.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/generic/fabs.rs rename to library/compiler-builtins/libm/src/math/generic/fabs.rs diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fdim.rs b/library/compiler-builtins/libm/src/math/generic/fdim.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/generic/fdim.rs rename to library/compiler-builtins/libm/src/math/generic/fdim.rs diff --git a/library/compiler-builtins/libm/libm/src/math/generic/floor.rs b/library/compiler-builtins/libm/src/math/generic/floor.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/generic/floor.rs rename to library/compiler-builtins/libm/src/math/generic/floor.rs diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fmax.rs b/library/compiler-builtins/libm/src/math/generic/fmax.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/generic/fmax.rs rename to library/compiler-builtins/libm/src/math/generic/fmax.rs diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fmaximum.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/generic/fmaximum.rs rename to library/compiler-builtins/libm/src/math/generic/fmaximum.rs diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fmaximum_num.rs b/library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/generic/fmaximum_num.rs rename to library/compiler-builtins/libm/src/math/generic/fmaximum_num.rs diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fmin.rs b/library/compiler-builtins/libm/src/math/generic/fmin.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/generic/fmin.rs rename to library/compiler-builtins/libm/src/math/generic/fmin.rs diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fminimum.rs b/library/compiler-builtins/libm/src/math/generic/fminimum.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/generic/fminimum.rs rename to library/compiler-builtins/libm/src/math/generic/fminimum.rs diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fminimum_num.rs b/library/compiler-builtins/libm/src/math/generic/fminimum_num.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/generic/fminimum_num.rs rename to library/compiler-builtins/libm/src/math/generic/fminimum_num.rs diff --git a/library/compiler-builtins/libm/libm/src/math/generic/fmod.rs b/library/compiler-builtins/libm/src/math/generic/fmod.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/generic/fmod.rs rename to library/compiler-builtins/libm/src/math/generic/fmod.rs diff --git a/library/compiler-builtins/libm/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/generic/mod.rs rename to library/compiler-builtins/libm/src/math/generic/mod.rs diff --git a/library/compiler-builtins/libm/libm/src/math/generic/rint.rs b/library/compiler-builtins/libm/src/math/generic/rint.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/generic/rint.rs rename to library/compiler-builtins/libm/src/math/generic/rint.rs diff --git a/library/compiler-builtins/libm/libm/src/math/generic/round.rs b/library/compiler-builtins/libm/src/math/generic/round.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/generic/round.rs rename to library/compiler-builtins/libm/src/math/generic/round.rs diff --git a/library/compiler-builtins/libm/libm/src/math/generic/scalbn.rs b/library/compiler-builtins/libm/src/math/generic/scalbn.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/generic/scalbn.rs rename to library/compiler-builtins/libm/src/math/generic/scalbn.rs diff --git a/library/compiler-builtins/libm/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/src/math/generic/sqrt.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/generic/sqrt.rs rename to library/compiler-builtins/libm/src/math/generic/sqrt.rs diff --git a/library/compiler-builtins/libm/libm/src/math/generic/trunc.rs b/library/compiler-builtins/libm/src/math/generic/trunc.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/generic/trunc.rs rename to library/compiler-builtins/libm/src/math/generic/trunc.rs diff --git a/library/compiler-builtins/libm/libm/src/math/hypot.rs b/library/compiler-builtins/libm/src/math/hypot.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/hypot.rs rename to library/compiler-builtins/libm/src/math/hypot.rs diff --git a/library/compiler-builtins/libm/libm/src/math/hypotf.rs b/library/compiler-builtins/libm/src/math/hypotf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/hypotf.rs rename to library/compiler-builtins/libm/src/math/hypotf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/ilogb.rs b/library/compiler-builtins/libm/src/math/ilogb.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/ilogb.rs rename to library/compiler-builtins/libm/src/math/ilogb.rs diff --git a/library/compiler-builtins/libm/libm/src/math/ilogbf.rs b/library/compiler-builtins/libm/src/math/ilogbf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/ilogbf.rs rename to library/compiler-builtins/libm/src/math/ilogbf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/j0.rs b/library/compiler-builtins/libm/src/math/j0.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/j0.rs rename to library/compiler-builtins/libm/src/math/j0.rs diff --git a/library/compiler-builtins/libm/libm/src/math/j0f.rs b/library/compiler-builtins/libm/src/math/j0f.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/j0f.rs rename to library/compiler-builtins/libm/src/math/j0f.rs diff --git a/library/compiler-builtins/libm/libm/src/math/j1.rs b/library/compiler-builtins/libm/src/math/j1.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/j1.rs rename to library/compiler-builtins/libm/src/math/j1.rs diff --git a/library/compiler-builtins/libm/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/j1f.rs rename to library/compiler-builtins/libm/src/math/j1f.rs diff --git a/library/compiler-builtins/libm/libm/src/math/jn.rs b/library/compiler-builtins/libm/src/math/jn.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/jn.rs rename to library/compiler-builtins/libm/src/math/jn.rs diff --git a/library/compiler-builtins/libm/libm/src/math/jnf.rs b/library/compiler-builtins/libm/src/math/jnf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/jnf.rs rename to library/compiler-builtins/libm/src/math/jnf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/k_cos.rs b/library/compiler-builtins/libm/src/math/k_cos.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/k_cos.rs rename to library/compiler-builtins/libm/src/math/k_cos.rs diff --git a/library/compiler-builtins/libm/libm/src/math/k_cosf.rs b/library/compiler-builtins/libm/src/math/k_cosf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/k_cosf.rs rename to library/compiler-builtins/libm/src/math/k_cosf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/k_expo2.rs b/library/compiler-builtins/libm/src/math/k_expo2.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/k_expo2.rs rename to library/compiler-builtins/libm/src/math/k_expo2.rs diff --git a/library/compiler-builtins/libm/libm/src/math/k_expo2f.rs b/library/compiler-builtins/libm/src/math/k_expo2f.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/k_expo2f.rs rename to library/compiler-builtins/libm/src/math/k_expo2f.rs diff --git a/library/compiler-builtins/libm/libm/src/math/k_sin.rs b/library/compiler-builtins/libm/src/math/k_sin.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/k_sin.rs rename to library/compiler-builtins/libm/src/math/k_sin.rs diff --git a/library/compiler-builtins/libm/libm/src/math/k_sinf.rs b/library/compiler-builtins/libm/src/math/k_sinf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/k_sinf.rs rename to library/compiler-builtins/libm/src/math/k_sinf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/k_tan.rs b/library/compiler-builtins/libm/src/math/k_tan.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/k_tan.rs rename to library/compiler-builtins/libm/src/math/k_tan.rs diff --git a/library/compiler-builtins/libm/libm/src/math/k_tanf.rs b/library/compiler-builtins/libm/src/math/k_tanf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/k_tanf.rs rename to library/compiler-builtins/libm/src/math/k_tanf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/ldexp.rs b/library/compiler-builtins/libm/src/math/ldexp.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/ldexp.rs rename to library/compiler-builtins/libm/src/math/ldexp.rs diff --git a/library/compiler-builtins/libm/libm/src/math/ldexpf.rs b/library/compiler-builtins/libm/src/math/ldexpf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/ldexpf.rs rename to library/compiler-builtins/libm/src/math/ldexpf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/ldexpf128.rs b/library/compiler-builtins/libm/src/math/ldexpf128.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/ldexpf128.rs rename to library/compiler-builtins/libm/src/math/ldexpf128.rs diff --git a/library/compiler-builtins/libm/libm/src/math/ldexpf16.rs b/library/compiler-builtins/libm/src/math/ldexpf16.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/ldexpf16.rs rename to library/compiler-builtins/libm/src/math/ldexpf16.rs diff --git a/library/compiler-builtins/libm/libm/src/math/lgamma.rs b/library/compiler-builtins/libm/src/math/lgamma.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/lgamma.rs rename to library/compiler-builtins/libm/src/math/lgamma.rs diff --git a/library/compiler-builtins/libm/libm/src/math/lgamma_r.rs b/library/compiler-builtins/libm/src/math/lgamma_r.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/lgamma_r.rs rename to library/compiler-builtins/libm/src/math/lgamma_r.rs diff --git a/library/compiler-builtins/libm/libm/src/math/lgammaf.rs b/library/compiler-builtins/libm/src/math/lgammaf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/lgammaf.rs rename to library/compiler-builtins/libm/src/math/lgammaf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/lgammaf_r.rs b/library/compiler-builtins/libm/src/math/lgammaf_r.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/lgammaf_r.rs rename to library/compiler-builtins/libm/src/math/lgammaf_r.rs diff --git a/library/compiler-builtins/libm/libm/src/math/log.rs b/library/compiler-builtins/libm/src/math/log.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/log.rs rename to library/compiler-builtins/libm/src/math/log.rs diff --git a/library/compiler-builtins/libm/libm/src/math/log10.rs b/library/compiler-builtins/libm/src/math/log10.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/log10.rs rename to library/compiler-builtins/libm/src/math/log10.rs diff --git a/library/compiler-builtins/libm/libm/src/math/log10f.rs b/library/compiler-builtins/libm/src/math/log10f.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/log10f.rs rename to library/compiler-builtins/libm/src/math/log10f.rs diff --git a/library/compiler-builtins/libm/libm/src/math/log1p.rs b/library/compiler-builtins/libm/src/math/log1p.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/log1p.rs rename to library/compiler-builtins/libm/src/math/log1p.rs diff --git a/library/compiler-builtins/libm/libm/src/math/log1pf.rs b/library/compiler-builtins/libm/src/math/log1pf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/log1pf.rs rename to library/compiler-builtins/libm/src/math/log1pf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/log2.rs b/library/compiler-builtins/libm/src/math/log2.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/log2.rs rename to library/compiler-builtins/libm/src/math/log2.rs diff --git a/library/compiler-builtins/libm/libm/src/math/log2f.rs b/library/compiler-builtins/libm/src/math/log2f.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/log2f.rs rename to library/compiler-builtins/libm/src/math/log2f.rs diff --git a/library/compiler-builtins/libm/libm/src/math/logf.rs b/library/compiler-builtins/libm/src/math/logf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/logf.rs rename to library/compiler-builtins/libm/src/math/logf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/mod.rs rename to library/compiler-builtins/libm/src/math/mod.rs diff --git a/library/compiler-builtins/libm/libm/src/math/modf.rs b/library/compiler-builtins/libm/src/math/modf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/modf.rs rename to library/compiler-builtins/libm/src/math/modf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/modff.rs b/library/compiler-builtins/libm/src/math/modff.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/modff.rs rename to library/compiler-builtins/libm/src/math/modff.rs diff --git a/library/compiler-builtins/libm/libm/src/math/nextafter.rs b/library/compiler-builtins/libm/src/math/nextafter.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/nextafter.rs rename to library/compiler-builtins/libm/src/math/nextafter.rs diff --git a/library/compiler-builtins/libm/libm/src/math/nextafterf.rs b/library/compiler-builtins/libm/src/math/nextafterf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/nextafterf.rs rename to library/compiler-builtins/libm/src/math/nextafterf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/pow.rs rename to library/compiler-builtins/libm/src/math/pow.rs diff --git a/library/compiler-builtins/libm/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/powf.rs rename to library/compiler-builtins/libm/src/math/powf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/rem_pio2.rs rename to library/compiler-builtins/libm/src/math/rem_pio2.rs diff --git a/library/compiler-builtins/libm/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/rem_pio2_large.rs rename to library/compiler-builtins/libm/src/math/rem_pio2_large.rs diff --git a/library/compiler-builtins/libm/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/rem_pio2f.rs rename to library/compiler-builtins/libm/src/math/rem_pio2f.rs diff --git a/library/compiler-builtins/libm/libm/src/math/remainder.rs b/library/compiler-builtins/libm/src/math/remainder.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/remainder.rs rename to library/compiler-builtins/libm/src/math/remainder.rs diff --git a/library/compiler-builtins/libm/libm/src/math/remainderf.rs b/library/compiler-builtins/libm/src/math/remainderf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/remainderf.rs rename to library/compiler-builtins/libm/src/math/remainderf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/remquo.rs b/library/compiler-builtins/libm/src/math/remquo.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/remquo.rs rename to library/compiler-builtins/libm/src/math/remquo.rs diff --git a/library/compiler-builtins/libm/libm/src/math/remquof.rs b/library/compiler-builtins/libm/src/math/remquof.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/remquof.rs rename to library/compiler-builtins/libm/src/math/remquof.rs diff --git a/library/compiler-builtins/libm/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/rint.rs rename to library/compiler-builtins/libm/src/math/rint.rs diff --git a/library/compiler-builtins/libm/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/round.rs rename to library/compiler-builtins/libm/src/math/round.rs diff --git a/library/compiler-builtins/libm/libm/src/math/roundeven.rs b/library/compiler-builtins/libm/src/math/roundeven.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/roundeven.rs rename to library/compiler-builtins/libm/src/math/roundeven.rs diff --git a/library/compiler-builtins/libm/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/roundf.rs rename to library/compiler-builtins/libm/src/math/roundf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/roundf128.rs b/library/compiler-builtins/libm/src/math/roundf128.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/roundf128.rs rename to library/compiler-builtins/libm/src/math/roundf128.rs diff --git a/library/compiler-builtins/libm/libm/src/math/roundf16.rs b/library/compiler-builtins/libm/src/math/roundf16.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/roundf16.rs rename to library/compiler-builtins/libm/src/math/roundf16.rs diff --git a/library/compiler-builtins/libm/libm/src/math/scalbn.rs b/library/compiler-builtins/libm/src/math/scalbn.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/scalbn.rs rename to library/compiler-builtins/libm/src/math/scalbn.rs diff --git a/library/compiler-builtins/libm/libm/src/math/scalbnf.rs b/library/compiler-builtins/libm/src/math/scalbnf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/scalbnf.rs rename to library/compiler-builtins/libm/src/math/scalbnf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/scalbnf128.rs b/library/compiler-builtins/libm/src/math/scalbnf128.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/scalbnf128.rs rename to library/compiler-builtins/libm/src/math/scalbnf128.rs diff --git a/library/compiler-builtins/libm/libm/src/math/scalbnf16.rs b/library/compiler-builtins/libm/src/math/scalbnf16.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/scalbnf16.rs rename to library/compiler-builtins/libm/src/math/scalbnf16.rs diff --git a/library/compiler-builtins/libm/libm/src/math/sin.rs b/library/compiler-builtins/libm/src/math/sin.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/sin.rs rename to library/compiler-builtins/libm/src/math/sin.rs diff --git a/library/compiler-builtins/libm/libm/src/math/sincos.rs b/library/compiler-builtins/libm/src/math/sincos.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/sincos.rs rename to library/compiler-builtins/libm/src/math/sincos.rs diff --git a/library/compiler-builtins/libm/libm/src/math/sincosf.rs b/library/compiler-builtins/libm/src/math/sincosf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/sincosf.rs rename to library/compiler-builtins/libm/src/math/sincosf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/sinf.rs b/library/compiler-builtins/libm/src/math/sinf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/sinf.rs rename to library/compiler-builtins/libm/src/math/sinf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/sinh.rs b/library/compiler-builtins/libm/src/math/sinh.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/sinh.rs rename to library/compiler-builtins/libm/src/math/sinh.rs diff --git a/library/compiler-builtins/libm/libm/src/math/sinhf.rs b/library/compiler-builtins/libm/src/math/sinhf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/sinhf.rs rename to library/compiler-builtins/libm/src/math/sinhf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/sqrt.rs rename to library/compiler-builtins/libm/src/math/sqrt.rs diff --git a/library/compiler-builtins/libm/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/sqrtf.rs rename to library/compiler-builtins/libm/src/math/sqrtf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/sqrtf128.rs b/library/compiler-builtins/libm/src/math/sqrtf128.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/sqrtf128.rs rename to library/compiler-builtins/libm/src/math/sqrtf128.rs diff --git a/library/compiler-builtins/libm/libm/src/math/sqrtf16.rs b/library/compiler-builtins/libm/src/math/sqrtf16.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/sqrtf16.rs rename to library/compiler-builtins/libm/src/math/sqrtf16.rs diff --git a/library/compiler-builtins/libm/libm/src/math/support/big.rs b/library/compiler-builtins/libm/src/math/support/big.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/support/big.rs rename to library/compiler-builtins/libm/src/math/support/big.rs diff --git a/library/compiler-builtins/libm/libm/src/math/support/big/tests.rs b/library/compiler-builtins/libm/src/math/support/big/tests.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/support/big/tests.rs rename to library/compiler-builtins/libm/src/math/support/big/tests.rs diff --git a/library/compiler-builtins/libm/libm/src/math/support/env.rs b/library/compiler-builtins/libm/src/math/support/env.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/support/env.rs rename to library/compiler-builtins/libm/src/math/support/env.rs diff --git a/library/compiler-builtins/libm/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/support/float_traits.rs rename to library/compiler-builtins/libm/src/math/support/float_traits.rs diff --git a/library/compiler-builtins/libm/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/support/hex_float.rs rename to library/compiler-builtins/libm/src/math/support/hex_float.rs diff --git a/library/compiler-builtins/libm/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/support/int_traits.rs rename to library/compiler-builtins/libm/src/math/support/int_traits.rs diff --git a/library/compiler-builtins/libm/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/support/macros.rs rename to library/compiler-builtins/libm/src/math/support/macros.rs diff --git a/library/compiler-builtins/libm/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/support/mod.rs rename to library/compiler-builtins/libm/src/math/support/mod.rs diff --git a/library/compiler-builtins/libm/libm/src/math/tan.rs b/library/compiler-builtins/libm/src/math/tan.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/tan.rs rename to library/compiler-builtins/libm/src/math/tan.rs diff --git a/library/compiler-builtins/libm/libm/src/math/tanf.rs b/library/compiler-builtins/libm/src/math/tanf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/tanf.rs rename to library/compiler-builtins/libm/src/math/tanf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/tanh.rs b/library/compiler-builtins/libm/src/math/tanh.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/tanh.rs rename to library/compiler-builtins/libm/src/math/tanh.rs diff --git a/library/compiler-builtins/libm/libm/src/math/tanhf.rs b/library/compiler-builtins/libm/src/math/tanhf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/tanhf.rs rename to library/compiler-builtins/libm/src/math/tanhf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/tgamma.rs b/library/compiler-builtins/libm/src/math/tgamma.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/tgamma.rs rename to library/compiler-builtins/libm/src/math/tgamma.rs diff --git a/library/compiler-builtins/libm/libm/src/math/tgammaf.rs b/library/compiler-builtins/libm/src/math/tgammaf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/tgammaf.rs rename to library/compiler-builtins/libm/src/math/tgammaf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/trunc.rs rename to library/compiler-builtins/libm/src/math/trunc.rs diff --git a/library/compiler-builtins/libm/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/truncf.rs rename to library/compiler-builtins/libm/src/math/truncf.rs diff --git a/library/compiler-builtins/libm/libm/src/math/truncf128.rs b/library/compiler-builtins/libm/src/math/truncf128.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/truncf128.rs rename to library/compiler-builtins/libm/src/math/truncf128.rs diff --git a/library/compiler-builtins/libm/libm/src/math/truncf16.rs b/library/compiler-builtins/libm/src/math/truncf16.rs similarity index 100% rename from library/compiler-builtins/libm/libm/src/math/truncf16.rs rename to library/compiler-builtins/libm/src/math/truncf16.rs From ca5c4ed8d7db731470395055d8f438f0abe7a18a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 21:25:19 +0000 Subject: [PATCH 1837/4206] Fix the release-plz job --- .../.github/workflows/publish.yaml | 9 ++----- .../etc/libm/.github/workflows/publish.yaml | 27 ------------------- 2 files changed, 2 insertions(+), 34 deletions(-) delete mode 100644 library/compiler-builtins/etc/libm/.github/workflows/publish.yaml diff --git a/library/compiler-builtins/.github/workflows/publish.yaml b/library/compiler-builtins/.github/workflows/publish.yaml index 7d6a8df030538..85a33c039d2a1 100644 --- a/library/compiler-builtins/.github/workflows/publish.yaml +++ b/library/compiler-builtins/.github/workflows/publish.yaml @@ -5,24 +5,19 @@ permissions: contents: write on: - push: - branches: - - master + push: { branches: [master] } jobs: release-plz: name: Release-plz - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 - submodules: true - name: Install Rust (rustup) run: rustup update nightly --no-self-update && rustup default nightly - - name: Publish `libm` as part of builtins, rather than its own crate - run: rm compiler-builtins/libm/Cargo.toml - name: Run release-plz uses: MarcoIeni/release-plz-action@v0.5 env: diff --git a/library/compiler-builtins/etc/libm/.github/workflows/publish.yaml b/library/compiler-builtins/etc/libm/.github/workflows/publish.yaml deleted file mode 100644 index 15904079d2772..0000000000000 --- a/library/compiler-builtins/etc/libm/.github/workflows/publish.yaml +++ /dev/null @@ -1,27 +0,0 @@ -name: Release-plz - -permissions: - pull-requests: write - contents: write - -on: - push: - branches: - - master - -jobs: - release-plz: - name: Release-plz - runs-on: ubuntu-24.04 - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - 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 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} From cab8700e84dd49d30cf7a4331a7269c36edf6ae9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 22:15:43 +0000 Subject: [PATCH 1838/4206] libm: Fix crate compilation Update paths and submodules to fix `libm-test` and `util` building so we will be able to add them to the workspace. --- library/compiler-builtins/.gitmodules | 4 ++-- library/compiler-builtins/crates/musl-math-sys/musl | 1 + library/compiler-builtins/crates/util/Cargo.toml | 2 +- library/compiler-builtins/libm-test/Cargo.toml | 6 +++--- library/compiler-builtins/libm-test/build.rs | 4 ++-- library/compiler-builtins/libm-test/src/op.rs | 4 ++-- 6 files changed, 11 insertions(+), 10 deletions(-) create mode 160000 library/compiler-builtins/crates/musl-math-sys/musl diff --git a/library/compiler-builtins/.gitmodules b/library/compiler-builtins/.gitmodules index ee941a47e776a..792ed9ab21f06 100644 --- a/library/compiler-builtins/.gitmodules +++ b/library/compiler-builtins/.gitmodules @@ -1,4 +1,4 @@ -[submodule "musl"] - path = libm/crates/musl-math-sys/musl +[submodule "crates/musl-math-sys/musl"] + path = crates/musl-math-sys/musl url = https://git.musl-libc.org/git/musl shallow = true diff --git a/library/compiler-builtins/crates/musl-math-sys/musl b/library/compiler-builtins/crates/musl-math-sys/musl new file mode 160000 index 0000000000000..0784374d56143 --- /dev/null +++ b/library/compiler-builtins/crates/musl-math-sys/musl @@ -0,0 +1 @@ +Subproject commit 0784374d561435f7c787a555aeab8ede699ed298 diff --git a/library/compiler-builtins/crates/util/Cargo.toml b/library/compiler-builtins/crates/util/Cargo.toml index 4bcb9747297a5..ae37a72381686 100644 --- a/library/compiler-builtins/crates/util/Cargo.toml +++ b/library/compiler-builtins/crates/util/Cargo.toml @@ -13,6 +13,6 @@ unstable-float = ["libm/unstable-float", "libm-test/unstable-float", "rug?/night [dependencies] libm = { path = "../../libm", default-features = false } libm-macros = { path = "../libm-macros" } -libm-test = { path = "../libm-test", default-features = false } +libm-test = { path = "../../libm-test", default-features = false } musl-math-sys = { path = "../musl-math-sys", optional = true } rug = { version = "1.27.0", optional = true, default-features = false, features = ["float", "std"] } diff --git a/library/compiler-builtins/libm-test/Cargo.toml b/library/compiler-builtins/libm-test/Cargo.toml index 5d150b4aeaa48..c9b3b79583723 100644 --- a/library/compiler-builtins/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm-test/Cargo.toml @@ -32,9 +32,9 @@ anyhow = "1.0.97" gmp-mpfr-sys = { version = "1.6.4", optional = true, default-features = false } iai-callgrind = { version = "0.14.0", optional = true } indicatif = { version = "0.17.11", default-features = false } -libm = { path = "../../libm", features = ["unstable-public-internals"] } -libm-macros = { path = "../libm-macros" } -musl-math-sys = { path = "../musl-math-sys", optional = true } +libm = { path = "../libm", features = ["unstable-public-internals"] } +libm-macros = { path = "../crates/libm-macros" } +musl-math-sys = { path = "../crates/musl-math-sys", optional = true } paste = "1.0.15" rand = "0.9.0" rand_chacha = "0.9.0" diff --git a/library/compiler-builtins/libm-test/build.rs b/library/compiler-builtins/libm-test/build.rs index f75e3dda5ff1f..510ba842f10ab 100644 --- a/library/compiler-builtins/libm-test/build.rs +++ b/library/compiler-builtins/libm-test/build.rs @@ -1,9 +1,9 @@ -#[path = "../../libm/configure.rs"] +#[path = "../libm/configure.rs"] mod configure; use configure::Config; fn main() { - println!("cargo:rerun-if-changed=../../libm/configure.rs"); + println!("cargo:rerun-if-changed=../libm/configure.rs"); let cfg = Config::from_env(); configure::emit_test_config(&cfg); } diff --git a/library/compiler-builtins/libm-test/src/op.rs b/library/compiler-builtins/libm-test/src/op.rs index 47d72ae58b392..4f251f80df646 100644 --- a/library/compiler-builtins/libm-test/src/op.rs +++ b/library/compiler-builtins/libm-test/src/op.rs @@ -16,12 +16,12 @@ use std::fmt; use std::panic::{RefUnwindSafe, UnwindSafe}; -pub use shared::{ALL_OPERATIONS, FloatTy, MathOpInfo, Ty}; +pub use shared::{FloatTy, MathOpInfo, Ty, ALL_OPERATIONS}; use crate::{CheckOutput, Float, TupleCall}; mod shared { - include!("../../libm-macros/src/shared.rs"); + include!("../../crates/libm-macros/src/shared.rs"); } /// An enum representing each possible symbol name (`sin`, `sinf`, `sinl`, etc). From 66fa4fd265d7896ef5262d8408006633ba1b8586 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 21:33:14 +0000 Subject: [PATCH 1839/4206] Add libm and libm-macros to the workspace These should build and test correctly. `libm-test` and others that depend on it are excluded since the necessary CI is not yet set up. --- library/compiler-builtins/Cargo.toml | 36 ++++++++++++++++-- library/compiler-builtins/etc/libm/Cargo.toml | 37 ------------------- 2 files changed, 33 insertions(+), 40 deletions(-) delete mode 100644 library/compiler-builtins/etc/libm/Cargo.toml diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 2e17c303a5f54..155fb00b195ec 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -7,15 +7,45 @@ members = [ "builtins-test", "builtins-test-intrinsics", "compiler-builtins", + "crates/libm-macros", + "libm", + # FIXME(libm): disabled until tests work in CI + # "libm-test", + # "crates/musl-math-sys", + # "crates/util", ] default-members = [ - "compiler-builtins", "builtins-test", + "compiler-builtins", + "crates/libm-macros", + # FIXME(libm): disabled until tests work in CI + # "crates/libm-test" + "libm", ] [profile.release] -panic = 'abort' +panic = "abort" [profile.dev] -panic = 'abort' +panic = "abort" + +# FIXME(libm): these profiles are needed for testing +# # The default release profile is unchanged. + +# # Release mode with debug assertions +# [profile.release-checked] +# inherits = "release" +# debug-assertions = true +# overflow-checks = true + +# # Release with maximum optimizations, which is very slow to build. This is also +# # what is needed to check `no-panic`. +# [profile.release-opt] +# inherits = "release" +# codegen-units = 1 +# lto = "fat" + +# [profile.bench] +# # Required for iai-callgrind +# debug = true diff --git a/library/compiler-builtins/etc/libm/Cargo.toml b/library/compiler-builtins/etc/libm/Cargo.toml deleted file mode 100644 index 268b6fb0e6dfa..0000000000000 --- a/library/compiler-builtins/etc/libm/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -[workspace] -resolver = "2" -members = [ - "libm", - "crates/libm-macros", - "crates/libm-test", - "crates/musl-math-sys", - "crates/util", -] -default-members = [ - "libm", - "crates/libm-macros", - "crates/libm-test" -] -exclude = [ - # Requires `panic = abort` so can't be a member of the workspace - "crates/compiler-builtins-smoke-test", -] - -# The default release profile is unchanged. - -# Release mode with debug assertions -[profile.release-checked] -inherits = "release" -debug-assertions = true -overflow-checks = true - -# Release with maximum optimizations, which is very slow to build. This is also -# what is needed to check `no-panic`. -[profile.release-opt] -inherits = "release" -codegen-units = 1 -lto = "fat" - -[profile.bench] -# Required for iai-callgrind -debug = true From 569b40209dd83af5decf494541cd96b749813973 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 22:54:23 +0000 Subject: [PATCH 1840/4206] Add a .rustfmt.toml with style edition 2024 Use the 2024 style edition for all crates and enable import sorting. 2024 already applies some smaller heuristics that look good in compiler-builtins, I have dropped `use_small_heuristics` that was set in `libm` because it seems to negatively affect the readibility of anything working with numbers (e.g. collapsing multiple small `if` expressions into a single line). --- library/compiler-builtins/{libm => }/.rustfmt.toml | 1 - 1 file changed, 1 deletion(-) rename library/compiler-builtins/{libm => }/.rustfmt.toml (79%) diff --git a/library/compiler-builtins/libm/.rustfmt.toml b/library/compiler-builtins/.rustfmt.toml similarity index 79% rename from library/compiler-builtins/libm/.rustfmt.toml rename to library/compiler-builtins/.rustfmt.toml index c73bb9301e340..79ac399c1b620 100644 --- a/library/compiler-builtins/libm/.rustfmt.toml +++ b/library/compiler-builtins/.rustfmt.toml @@ -1,5 +1,4 @@ # This matches rustc style_edition = "2024" -use_small_heuristics = "Max" group_imports = "StdExternalCrate" imports_granularity = "Module" From 8d70be87e6e8f88fdad0f469b894a3ec9a87d3ce Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 22:39:00 +0000 Subject: [PATCH 1841/4206] Run `cargo fmt` on all projects Apply the same formatting rules to both `libm` and `compiler-builtins`. --- .../builtins-test-intrinsics/src/main.rs | 1 + .../builtins-test/benches/float_cmp.rs | 3 +- .../builtins-test/benches/mem_icount.rs | 3 +- .../builtins-test/src/bench.rs | 2 +- .../builtins-test/src/lib.rs | 1 - .../builtins-test/tests/cmp.rs | 1 - .../builtins-test/tests/div_rem.rs | 3 +- .../compiler-builtins/build.rs | 7 +- .../compiler-builtins/src/arm_linux.rs | 3 +- .../compiler-builtins/src/float/conv.rs | 3 +- .../compiler-builtins/src/float/div.rs | 7 +- .../compiler-builtins/src/float/mod.rs | 1 - .../compiler-builtins/src/float/pow.rs | 6 +- .../compiler-builtins/src/int/big.rs | 3 +- .../src/int/leading_zeros.rs | 6 +- .../compiler-builtins/src/int/mod.rs | 2 - .../src/int/specialized_div_rem/mod.rs | 1 - .../compiler-builtins/src/int/udiv.rs | 1 - .../compiler-builtins/src/mem/x86_64.rs | 3 +- .../crates/libm-macros/src/enums.rs | 31 +++- .../crates/libm-macros/src/lib.rs | 44 +++-- .../crates/libm-macros/src/parse.rs | 38 +++- .../crates/libm-macros/src/shared.rs | 175 ++++++++++++++---- .../crates/musl-math-sys/build.rs | 57 ++++-- .../compiler-builtins/crates/util/src/main.rs | 6 +- .../libm-test/benches/random.rs | 17 +- .../libm-test/examples/plot_domains.rs | 8 +- .../compiler-builtins/libm-test/src/domain.rs | 73 +++++--- .../libm-test/src/f8_impl.rs | 4 +- .../libm-test/src/generate.rs | 11 +- .../libm-test/src/generate/case_list.rs | 50 ++++- .../libm-test/src/generate/edge_cases.rs | 6 +- .../libm-test/src/generate/random.rs | 5 +- .../libm-test/src/generate/spaced.rs | 11 +- .../compiler-builtins/libm-test/src/lib.rs | 11 +- .../compiler-builtins/libm-test/src/num.rs | 93 ++++++++-- library/compiler-builtins/libm-test/src/op.rs | 2 +- .../libm-test/src/run_cfg.rs | 25 ++- .../libm-test/src/test_traits.rs | 10 +- .../compiler-builtins/libm-test/tests/u256.rs | 12 +- .../libm-test/tests/z_extensive/run.rs | 22 ++- library/compiler-builtins/libm/configure.rs | 10 +- library/compiler-builtins/libm/src/lib.rs | 5 +- .../compiler-builtins/libm/src/math/atanf.rs | 9 +- .../compiler-builtins/libm/src/math/cbrt.rs | 6 +- .../compiler-builtins/libm/src/math/erf.rs | 6 +- .../compiler-builtins/libm/src/math/erff.rs | 6 +- .../compiler-builtins/libm/src/math/exp10f.rs | 5 +- .../compiler-builtins/libm/src/math/expm1f.rs | 6 +- .../compiler-builtins/libm/src/math/fma.rs | 10 +- .../libm/src/math/fma_wide.rs | 11 +- .../libm/src/math/generic/ceil.rs | 9 +- .../libm/src/math/generic/floor.rs | 9 +- .../libm/src/math/generic/rint.rs | 15 +- .../libm/src/math/generic/sqrt.rs | 5 +- .../libm/src/math/generic/trunc.rs | 15 +- .../compiler-builtins/libm/src/math/ilogb.rs | 6 +- .../compiler-builtins/libm/src/math/k_sin.rs | 6 +- .../compiler-builtins/libm/src/math/log1p.rs | 6 +- .../compiler-builtins/libm/src/math/log1pf.rs | 6 +- .../compiler-builtins/libm/src/math/pow.rs | 48 +++-- .../compiler-builtins/libm/src/math/powf.rs | 12 +- .../libm/src/math/rem_pio2.rs | 20 +- .../compiler-builtins/libm/src/math/sinf.rs | 12 +- .../libm/src/math/support/big.rs | 30 ++- .../libm/src/math/support/big/tests.rs | 168 +++++++++++++++-- .../libm/src/math/support/env.rs | 5 +- .../libm/src/math/support/float_traits.rs | 81 +++++++- .../libm/src/math/support/hex_float.rs | 46 ++++- .../compiler-builtins/libm/src/math/tan.rs | 6 +- .../compiler-builtins/libm/src/math/tanf.rs | 6 +- 71 files changed, 1070 insertions(+), 283 deletions(-) diff --git a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs index 21d0a083c71d6..c4c026368e0da 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs +++ b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs @@ -480,6 +480,7 @@ mod intrinsics { fn run() { use core::hint::black_box as bb; + use intrinsics::*; // FIXME(f16_f128): some PPC f128 <-> int conversion functions have the wrong names diff --git a/library/compiler-builtins/builtins-test/benches/float_cmp.rs b/library/compiler-builtins/builtins-test/benches/float_cmp.rs index 4493765ec1bad..42d6652397dcf 100644 --- a/library/compiler-builtins/builtins-test/benches/float_cmp.rs +++ b/library/compiler-builtins/builtins-test/benches/float_cmp.rs @@ -1,9 +1,8 @@ #![cfg_attr(f128_enabled, feature(f128))] use builtins_test::float_bench; -use criterion::{Criterion, criterion_main}; - use compiler_builtins::float::cmp; +use criterion::{Criterion, criterion_main}; /// `gt` symbols are allowed to return differing results, they just get compared /// to 0. diff --git a/library/compiler-builtins/builtins-test/benches/mem_icount.rs b/library/compiler-builtins/builtins-test/benches/mem_icount.rs index 63045f6e1ec60..bd88cf80c7de2 100644 --- a/library/compiler-builtins/builtins-test/benches/mem_icount.rs +++ b/library/compiler-builtins/builtins-test/benches/mem_icount.rs @@ -239,9 +239,10 @@ mod mcmp { } mod mmove { - use super::*; use Spread::{Aligned, Large, Medium, Small}; + use super::*; + struct Cfg { len: usize, spread: Spread, diff --git a/library/compiler-builtins/builtins-test/src/bench.rs b/library/compiler-builtins/builtins-test/src/bench.rs index 45a3a1ad4671f..2348f6bc97379 100644 --- a/library/compiler-builtins/builtins-test/src/bench.rs +++ b/library/compiler-builtins/builtins-test/src/bench.rs @@ -1,6 +1,6 @@ +use alloc::vec::Vec; use core::cell::RefCell; -use alloc::vec::Vec; use compiler_builtins::float::Float; /// Fuzz with these many items to ensure equal functions diff --git a/library/compiler-builtins/builtins-test/src/lib.rs b/library/compiler-builtins/builtins-test/src/lib.rs index a83aea56206b1..c596ac2138076 100644 --- a/library/compiler-builtins/builtins-test/src/lib.rs +++ b/library/compiler-builtins/builtins-test/src/lib.rs @@ -21,7 +21,6 @@ extern crate alloc; use compiler_builtins::float::Float; use compiler_builtins::int::{Int, MinInt}; - use rand_xoshiro::Xoshiro128StarStar; use rand_xoshiro::rand_core::{RngCore, SeedableRng}; diff --git a/library/compiler-builtins/builtins-test/tests/cmp.rs b/library/compiler-builtins/builtins-test/tests/cmp.rs index dbedd213e90e7..a904dc5f7de4d 100644 --- a/library/compiler-builtins/builtins-test/tests/cmp.rs +++ b/library/compiler-builtins/builtins-test/tests/cmp.rs @@ -97,7 +97,6 @@ mod float_comparisons { __eqkf2 as __eqtf2, __gekf2 as __getf2, __gtkf2 as __gttf2, __lekf2 as __letf2, __ltkf2 as __lttf2, __nekf2 as __netf2, __unordkf2 as __unordtf2, }; - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] use compiler_builtins::float::cmp::{ __eqtf2, __getf2, __gttf2, __letf2, __lttf2, __netf2, __unordtf2, diff --git a/library/compiler-builtins/builtins-test/tests/div_rem.rs b/library/compiler-builtins/builtins-test/tests/div_rem.rs index 6c0280a328698..5ae653cc90cc4 100644 --- a/library/compiler-builtins/builtins-test/tests/div_rem.rs +++ b/library/compiler-builtins/builtins-test/tests/div_rem.rs @@ -1,11 +1,10 @@ #![feature(f128)] #![allow(unused_macros)] +use builtins_test::*; use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divmodti4}; use compiler_builtins::int::udiv::{__udivmoddi4, __udivmodsi4, __udivmodti4, u128_divide_sparc}; -use builtins_test::*; - // Division algorithms have by far the nastiest and largest number of edge cases, and experience shows // that sometimes 100_000 iterations of the random fuzzer is needed. diff --git a/library/compiler-builtins/compiler-builtins/build.rs b/library/compiler-builtins/compiler-builtins/build.rs index d627121f348be..04369a4aa4e9f 100644 --- a/library/compiler-builtins/compiler-builtins/build.rs +++ b/library/compiler-builtins/compiler-builtins/build.rs @@ -1,8 +1,11 @@ mod configure; -use std::{collections::BTreeMap, env, path::PathBuf, sync::atomic::Ordering}; +use std::collections::BTreeMap; +use std::env; +use std::path::PathBuf; +use std::sync::atomic::Ordering; -use configure::{configure_aliases, configure_f16_f128, Target}; +use configure::{Target, configure_aliases, configure_f16_f128}; fn main() { println!("cargo::rerun-if-changed=build.rs"); diff --git a/library/compiler-builtins/compiler-builtins/src/arm_linux.rs b/library/compiler-builtins/compiler-builtins/src/arm_linux.rs index aeb3ff3e50693..6ce67ba719c96 100644 --- a/library/compiler-builtins/compiler-builtins/src/arm_linux.rs +++ b/library/compiler-builtins/compiler-builtins/src/arm_linux.rs @@ -1,6 +1,5 @@ -use core::arch; -use core::mem; use core::sync::atomic::{AtomicU32, Ordering}; +use core::{arch, mem}; // Kernel-provided user-mode helper functions: // https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt diff --git a/library/compiler-builtins/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/compiler-builtins/src/float/conv.rs index 42a526bd52410..f5427a11390fc 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/conv.rs @@ -1,8 +1,7 @@ use core::ops::Neg; -use crate::int::{CastFrom, CastInto, Int, MinInt}; - use super::Float; +use crate::int::{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 929f29197872b..5df637c7e0f9b 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/div.rs @@ -79,11 +79,12 @@ //! //! [Newton-Raphson method]: https://en.wikipedia.org/wiki/Newton%27s_method +use core::mem::size_of; +use core::ops; + use super::HalfRep; use crate::float::Float; use crate::int::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; -use core::mem::size_of; -use core::ops; fn div(a: F, b: F) -> F where @@ -487,7 +488,7 @@ where }; residual_lo += abs_result & one; // tie to even - // conditionally turns the below LT comparison into LTE + // conditionally turns the below LT comparison into LTE abs_result += u8::from(residual_lo > b_significand).into(); if F::BITS == 128 || (F::BITS == 32 && half_iterations > 0) { diff --git a/library/compiler-builtins/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/compiler-builtins/src/float/mod.rs index 41b308626b392..f2c543bd2b7d9 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/mod.rs @@ -11,6 +11,5 @@ pub mod trunc; #[cfg(not(feature = "public-test-deps"))] pub(crate) use traits::{Float, HalfRep}; - #[cfg(feature = "public-test-deps")] pub use traits::{Float, HalfRep}; diff --git a/library/compiler-builtins/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/compiler-builtins/src/float/pow.rs index fe76060e0faa8..45a4ad9049de4 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/pow.rs @@ -18,11 +18,7 @@ fn pow(a: F, b: i32) -> F { a *= a; } - if recip { - F::ONE / mul - } else { - mul - } + if recip { F::ONE / mul } else { mul } } intrinsics! { diff --git a/library/compiler-builtins/compiler-builtins/src/int/big.rs b/library/compiler-builtins/compiler-builtins/src/int/big.rs index 0ef3caaedffce..61f1349d9a428 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/big.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/big.rs @@ -2,9 +2,10 @@ #![allow(unused)] -use crate::int::{DInt, HInt, Int, MinInt}; 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; 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 ba735aa74620b..a57f881848d1c 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs @@ -60,11 +60,7 @@ mod implementation { } // the last two bisections are combined into one conditional t = x >> 1; - if t != T::ZERO { - z - 2 - } else { - z - x.cast() - } + if t != T::ZERO { z - 2 } else { z - x.cast() } // We could potentially save a few cycles by using the LUT trick from // "https://embeddedgurus.com/state-space/2014/09/diff%20--git%20a/library/compiler-builtins/compiler-builtins/src/int/mod.rs%20b/library/compiler-builtins/compiler-builtins/src/int/mod.rsindex%201f1be711bbda2..5633510d3c758%20100644---%20a/library/compiler-builtins/compiler-builtins/src/int/mod.rs+++%20b/library/compiler-builtins/compiler-builtins/src/int/mod.rs@@%20-12,9%20+12,7%20@@%20mod%20traits;%20pub%20mod%20udiv;%20%20pub%20use%20big::%7Bi256,%20u256%7D;-%20#[cfg(not(feature%20="public-test-deps"))] pub(crate) use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; - #[cfg(feature = "public-test-deps")] pub use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; 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 a91fe6632eec3..b81f0469813a5 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 @@ -58,7 +58,6 @@ mod delegate; #[allow(unused_imports)] #[cfg(not(feature = "public-test-deps"))] pub(crate) use self::delegate::u128_divide_sparc; - #[cfg(feature = "public-test-deps")] pub use self::delegate::u128_divide_sparc; diff --git a/library/compiler-builtins/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/compiler-builtins/src/int/udiv.rs index f18537b006b0d..4e985ba473936 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/udiv.rs @@ -1,6 +1,5 @@ #[cfg(not(feature = "public-test-deps"))] pub(crate) use crate::int::specialized_div_rem::*; - #[cfg(feature = "public-test-deps")] pub use crate::int::specialized_div_rem::*; diff --git a/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs b/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs index 40b67093f51d5..5cbe83ab1e21d 100644 --- a/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs +++ b/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs @@ -17,8 +17,7 @@ // Note that ERMSB does not enhance the backwards (DF=1) "rep movsb". use core::arch::asm; -use core::intrinsics; -use core::mem; +use core::{intrinsics, mem}; #[inline(always)] #[cfg(target_feature = "ermsb")] diff --git a/library/compiler-builtins/crates/libm-macros/src/enums.rs b/library/compiler-builtins/crates/libm-macros/src/enums.rs index 864b625eab38f..b4646f984d471 100644 --- a/library/compiler-builtins/crates/libm-macros/src/enums.rs +++ b/library/compiler-builtins/crates/libm-macros/src/enums.rs @@ -26,7 +26,10 @@ pub fn function_enum( }; if let Some(tt) = attr.next() { - return Err(syn::Error::new(tt.span(), "unexpected token after identifier")); + return Err(syn::Error::new( + tt.span(), + "unexpected token after identifier", + )); } let enum_name = &item.ident; @@ -46,8 +49,12 @@ pub fn function_enum( // Match arm for `fn base_name(self)` matcher base_arms.push(quote! { Self::#ident => #base_enum::#bname_ident }); - let variant = - Variant { attrs: Vec::new(), ident, fields: Fields::Unit, discriminant: None }; + let variant = Variant { + attrs: Vec::new(), + ident, + fields: Fields::Unit, + discriminant: None, + }; item.variants.push(variant); } @@ -108,7 +115,10 @@ pub fn base_name_enum( return Err(syn::Error::new(sp.span(), "no attributes expected")); } - let mut base_names: Vec<_> = ALL_OPERATIONS.iter().map(|func| base_name(func.name)).collect(); + let mut base_names: Vec<_> = ALL_OPERATIONS + .iter() + .map(|func| base_name(func.name)) + .collect(); base_names.sort_unstable(); base_names.dedup(); @@ -121,8 +131,12 @@ pub fn base_name_enum( // Match arm for `fn as_str(self)` matcher as_str_arms.push(quote! { Self::#ident => #base_name }); - let variant = - Variant { attrs: Vec::new(), ident, fields: Fields::Unit, discriminant: None }; + let variant = Variant { + attrs: Vec::new(), + ident, + fields: Fields::Unit, + discriminant: None, + }; item.variants.push(variant); } @@ -147,7 +161,10 @@ pub fn base_name_enum( /// Verify that an enum is empty, otherwise return an error fn expect_empty_enum(item: &ItemEnum) -> syn::Result<()> { if !item.variants.is_empty() { - Err(syn::Error::new(item.variants.span(), "expected an empty enum")) + Err(syn::Error::new( + item.variants.span(), + "expected an empty enum", + )) } else { Ok(()) } diff --git a/library/compiler-builtins/crates/libm-macros/src/lib.rs b/library/compiler-builtins/crates/libm-macros/src/lib.rs index 3cee5385b62ff..3cdd364e83000 100644 --- a/library/compiler-builtins/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/crates/libm-macros/src/lib.rs @@ -11,7 +11,9 @@ use syn::spanned::Spanned; use syn::visit_mut::VisitMut; use syn::{Ident, ItemEnum}; -const KNOWN_TYPES: &[&str] = &["FTy", "CFn", "CArgs", "CRet", "RustFn", "RustArgs", "RustRet"]; +const KNOWN_TYPES: &[&str] = &[ + "FTy", "CFn", "CArgs", "CRet", "RustFn", "RustArgs", "RustRet", +]; /// Populate an enum with a variant representing function. Names are in upper camel case. /// @@ -142,10 +144,17 @@ fn validate(input: &mut StructuredInput) -> syn::Result .flat_map(|map_list| map_list.iter()) .flat_map(|attr_map| attr_map.names.iter()); let only_mentions = input.only.iter().flat_map(|only_list| only_list.iter()); - let fn_extra_mentions = - input.fn_extra.iter().flat_map(|v| v.keys()).filter(|name| *name != "_"); - let all_mentioned_fns = - input.skip.iter().chain(only_mentions).chain(attr_mentions).chain(fn_extra_mentions); + let fn_extra_mentions = input + .fn_extra + .iter() + .flat_map(|v| v.keys()) + .filter(|name| *name != "_"); + let all_mentioned_fns = input + .skip + .iter() + .chain(only_mentions) + .chain(attr_mentions) + .chain(fn_extra_mentions); // Make sure that every function mentioned is a real function for mentioned in all_mentioned_fns { @@ -171,7 +180,11 @@ fn validate(input: &mut StructuredInput) -> syn::Result for func in ALL_OPERATIONS.iter() { let fn_name = func.name; // If we have an `only` list and it does _not_ contain this function name, skip it - if input.only.as_ref().is_some_and(|only| !only.iter().any(|o| o == fn_name)) { + if input + .only + .as_ref() + .is_some_and(|only| !only.iter().any(|o| o == fn_name)) + { continue; } @@ -296,8 +309,11 @@ fn expand(input: StructuredInput, fn_list: &[&MathOpInfo]) -> syn::Result { - let mut fn_extra = - map.get(&fn_name).or_else(|| map.get(&default_ident)).unwrap().clone(); + let mut fn_extra = map + .get(&fn_name) + .or_else(|| map.get(&default_ident)) + .unwrap() + .clone(); let mut v = MacroReplace::new(func.name); v.visit_expr_mut(&mut fn_extra); @@ -357,7 +373,11 @@ struct MacroReplace { impl MacroReplace { fn new(name: &'static str) -> Self { let norm_name = base_name(name); - Self { fn_name: name, norm_name: norm_name.to_owned(), error: None } + Self { + fn_name: name, + norm_name: norm_name.to_owned(), + error: None, + } } fn finish(self) -> syn::Result<()> { @@ -377,8 +397,10 @@ impl MacroReplace { "MACRO_FN_NAME" => *i = Ident::new(self.fn_name, i.span()), "MACRO_FN_NAME_NORMALIZED" => *i = Ident::new(&self.norm_name, i.span()), _ => { - self.error = - Some(syn::Error::new(i.span(), format!("unrecognized meta expression `{s}`"))); + self.error = Some(syn::Error::new( + i.span(), + format!("unrecognized meta expression `{s}`"), + )); } } } diff --git a/library/compiler-builtins/crates/libm-macros/src/parse.rs b/library/compiler-builtins/crates/libm-macros/src/parse.rs index 369bbae2f4faf..d60d1247a9e34 100644 --- a/library/compiler-builtins/crates/libm-macros/src/parse.rs +++ b/library/compiler-builtins/crates/libm-macros/src/parse.rs @@ -16,7 +16,9 @@ pub struct Invocation { impl Parse for Invocation { fn parse(input: ParseStream) -> syn::Result { - Ok(Self { fields: input.parse_terminated(Mapping::parse, Token![,])? }) + Ok(Self { + fields: input.parse_terminated(Mapping::parse, Token![,])?, + }) } } @@ -30,7 +32,11 @@ struct Mapping { impl Parse for Mapping { fn parse(input: ParseStream) -> syn::Result { - Ok(Self { name: input.parse()?, _sep: input.parse()?, expr: input.parse()? }) + Ok(Self { + name: input.parse()?, + _sep: input.parse()?, + expr: input.parse()?, + }) } } @@ -133,7 +139,13 @@ fn extract_fn_extra_field(expr: Expr) -> syn::Result> { return Err(e); }; - let ExprMatch { attrs, match_token: _, expr, brace_token: _, arms } = mexpr; + let ExprMatch { + attrs, + match_token: _, + expr, + brace_token: _, + arms, + } = mexpr; expect_empty_attrs(&attrs)?; @@ -146,7 +158,14 @@ fn extract_fn_extra_field(expr: Expr) -> syn::Result> { let mut res = BTreeMap::new(); for arm in arms { - let Arm { attrs, pat, guard, fat_arrow_token: _, body, comma: _ } = arm; + let Arm { + attrs, + pat, + guard, + fat_arrow_token: _, + body, + comma: _, + } = arm; expect_empty_attrs(&attrs)?; @@ -177,15 +196,20 @@ fn expect_empty_attrs(attrs: &[Attribute]) -> syn::Result<()> { return Ok(()); } - let e = - syn::Error::new(attrs.first().unwrap().span(), "no attributes allowed in this position"); + let e = syn::Error::new( + attrs.first().unwrap().span(), + "no attributes allowed in this position", + ); Err(e) } /// Extract a named field from a map, raising an error if it doesn't exist. fn expect_field(v: &mut Vec, name: &str) -> syn::Result { let pos = v.iter().position(|v| v.name == name).ok_or_else(|| { - syn::Error::new(Span::call_site(), format!("missing expected field `{name}`")) + syn::Error::new( + Span::call_site(), + format!("missing expected field `{name}`"), + ) })?; Ok(v.remove(pos).expr) diff --git a/library/compiler-builtins/crates/libm-macros/src/shared.rs b/library/compiler-builtins/crates/libm-macros/src/shared.rs index 5e58220eb3984..750ed1afb057a 100644 --- a/library/compiler-builtins/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/crates/libm-macros/src/shared.rs @@ -7,7 +7,10 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] ( // `fn(f16) -> f16` FloatTy::F16, - Signature { args: &[Ty::F16], returns: &[Ty::F16] }, + Signature { + args: &[Ty::F16], + returns: &[Ty::F16], + }, None, &[ "ceilf16", @@ -23,7 +26,10 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] ( // `fn(f32) -> f32` FloatTy::F32, - Signature { args: &[Ty::F32], returns: &[Ty::F32] }, + Signature { + args: &[Ty::F32], + returns: &[Ty::F32], + }, None, &[ "acosf", @@ -68,7 +74,10 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] ( // `(f64) -> f64` FloatTy::F64, - Signature { args: &[Ty::F64], returns: &[Ty::F64] }, + Signature { + args: &[Ty::F64], + returns: &[Ty::F64], + }, None, &[ "acos", @@ -113,7 +122,10 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] ( // `fn(f128) -> f128` FloatTy::F128, - Signature { args: &[Ty::F128], returns: &[Ty::F128] }, + Signature { + args: &[Ty::F128], + returns: &[Ty::F128], + }, None, &[ "ceilf128", @@ -129,7 +141,10 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] ( // `(f16, f16) -> f16` FloatTy::F16, - Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16] }, + Signature { + args: &[Ty::F16, Ty::F16], + returns: &[Ty::F16], + }, None, &[ "copysignf16", @@ -146,7 +161,10 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] ( // `(f32, f32) -> f32` FloatTy::F32, - Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32] }, + Signature { + args: &[Ty::F32, Ty::F32], + returns: &[Ty::F32], + }, None, &[ "atan2f", @@ -168,7 +186,10 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] ( // `(f64, f64) -> f64` FloatTy::F64, - Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64] }, + Signature { + args: &[Ty::F64, Ty::F64], + returns: &[Ty::F64], + }, None, &[ "atan2", @@ -190,7 +211,10 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] ( // `(f128, f128) -> f128` FloatTy::F128, - Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128] }, + Signature { + args: &[Ty::F128, Ty::F128], + returns: &[Ty::F128], + }, None, &[ "copysignf128", @@ -207,134 +231,215 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] ( // `(f32, f32, f32) -> f32` FloatTy::F32, - Signature { args: &[Ty::F32, Ty::F32, Ty::F32], returns: &[Ty::F32] }, + Signature { + args: &[Ty::F32, Ty::F32, Ty::F32], + returns: &[Ty::F32], + }, None, &["fmaf"], ), ( // `(f64, f64, f64) -> f64` FloatTy::F64, - Signature { args: &[Ty::F64, Ty::F64, Ty::F64], returns: &[Ty::F64] }, + Signature { + args: &[Ty::F64, Ty::F64, Ty::F64], + returns: &[Ty::F64], + }, None, &["fma"], ), ( // `(f128, f128, f128) -> f128` FloatTy::F128, - Signature { args: &[Ty::F128, Ty::F128, Ty::F128], returns: &[Ty::F128] }, + Signature { + args: &[Ty::F128, Ty::F128, Ty::F128], + returns: &[Ty::F128], + }, None, &["fmaf128"], ), ( // `(f32) -> i32` FloatTy::F32, - Signature { args: &[Ty::F32], returns: &[Ty::I32] }, + Signature { + args: &[Ty::F32], + returns: &[Ty::I32], + }, None, &["ilogbf"], ), ( // `(f64) -> i32` FloatTy::F64, - Signature { args: &[Ty::F64], returns: &[Ty::I32] }, + Signature { + args: &[Ty::F64], + returns: &[Ty::I32], + }, None, &["ilogb"], ), ( // `(i32, f32) -> f32` FloatTy::F32, - Signature { args: &[Ty::I32, Ty::F32], returns: &[Ty::F32] }, + Signature { + args: &[Ty::I32, Ty::F32], + returns: &[Ty::F32], + }, None, &["jnf", "ynf"], ), ( // `(i32, f64) -> f64` FloatTy::F64, - Signature { args: &[Ty::I32, Ty::F64], returns: &[Ty::F64] }, + Signature { + args: &[Ty::I32, Ty::F64], + returns: &[Ty::F64], + }, None, &["jn", "yn"], ), ( // `(f16, i32) -> f16` FloatTy::F16, - Signature { args: &[Ty::F16, Ty::I32], returns: &[Ty::F16] }, + Signature { + args: &[Ty::F16, Ty::I32], + returns: &[Ty::F16], + }, None, &["ldexpf16", "scalbnf16"], ), ( // `(f32, i32) -> f32` FloatTy::F32, - Signature { args: &[Ty::F32, Ty::I32], returns: &[Ty::F32] }, + Signature { + args: &[Ty::F32, Ty::I32], + returns: &[Ty::F32], + }, None, &["ldexpf", "scalbnf"], ), ( // `(f64, i64) -> f64` FloatTy::F64, - Signature { args: &[Ty::F64, Ty::I32], returns: &[Ty::F64] }, + Signature { + args: &[Ty::F64, Ty::I32], + returns: &[Ty::F64], + }, None, &["ldexp", "scalbn"], ), ( // `(f128, i32) -> f128` FloatTy::F128, - Signature { args: &[Ty::F128, Ty::I32], returns: &[Ty::F128] }, + Signature { + args: &[Ty::F128, Ty::I32], + returns: &[Ty::F128], + }, None, &["ldexpf128", "scalbnf128"], ), ( // `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)` FloatTy::F32, - Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] }, - Some(Signature { args: &[Ty::F32, Ty::MutF32], returns: &[Ty::F32] }), + Signature { + args: &[Ty::F32], + returns: &[Ty::F32, Ty::F32], + }, + Some(Signature { + args: &[Ty::F32, Ty::MutF32], + returns: &[Ty::F32], + }), &["modff"], ), ( // `(f64, &mut f64) -> f64` as `(f64) -> (f64, f64)` FloatTy::F64, - Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] }, - Some(Signature { args: &[Ty::F64, Ty::MutF64], returns: &[Ty::F64] }), + Signature { + args: &[Ty::F64], + returns: &[Ty::F64, Ty::F64], + }, + Some(Signature { + args: &[Ty::F64, Ty::MutF64], + returns: &[Ty::F64], + }), &["modf"], ), ( // `(f32, &mut c_int) -> f32` as `(f32) -> (f32, i32)` FloatTy::F32, - Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::I32] }, - Some(Signature { args: &[Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }), + Signature { + args: &[Ty::F32], + returns: &[Ty::F32, Ty::I32], + }, + Some(Signature { + args: &[Ty::F32, Ty::MutCInt], + returns: &[Ty::F32], + }), &["frexpf", "lgammaf_r"], ), ( // `(f64, &mut c_int) -> f64` as `(f64) -> (f64, i32)` FloatTy::F64, - Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::I32] }, - Some(Signature { args: &[Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }), + Signature { + args: &[Ty::F64], + returns: &[Ty::F64, Ty::I32], + }, + Some(Signature { + args: &[Ty::F64, Ty::MutCInt], + returns: &[Ty::F64], + }), &["frexp", "lgamma_r"], ), ( // `(f32, f32, &mut c_int) -> f32` as `(f32, f32) -> (f32, i32)` FloatTy::F32, - Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32, Ty::I32] }, - Some(Signature { args: &[Ty::F32, Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }), + Signature { + args: &[Ty::F32, Ty::F32], + returns: &[Ty::F32, Ty::I32], + }, + Some(Signature { + args: &[Ty::F32, Ty::F32, Ty::MutCInt], + returns: &[Ty::F32], + }), &["remquof"], ), ( // `(f64, f64, &mut c_int) -> f64` as `(f64, f64) -> (f64, i32)` FloatTy::F64, - Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64, Ty::I32] }, - Some(Signature { args: &[Ty::F64, Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }), + Signature { + args: &[Ty::F64, Ty::F64], + returns: &[Ty::F64, Ty::I32], + }, + Some(Signature { + args: &[Ty::F64, Ty::F64, Ty::MutCInt], + returns: &[Ty::F64], + }), &["remquo"], ), ( // `(f32, &mut f32, &mut f32)` as `(f32) -> (f32, f32)` FloatTy::F32, - Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] }, - Some(Signature { args: &[Ty::F32, Ty::MutF32, Ty::MutF32], returns: &[] }), + Signature { + args: &[Ty::F32], + returns: &[Ty::F32, Ty::F32], + }, + Some(Signature { + args: &[Ty::F32, Ty::MutF32, Ty::MutF32], + returns: &[], + }), &["sincosf"], ), ( // `(f64, &mut f64, &mut f64)` as `(f64) -> (f64, f64)` FloatTy::F64, - Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] }, - Some(Signature { args: &[Ty::F64, Ty::MutF64, Ty::MutF64], returns: &[] }), + Signature { + args: &[Ty::F64], + returns: &[Ty::F64, Ty::F64], + }, + Some(Signature { + args: &[Ty::F64, Ty::MutF64, Ty::MutF64], + returns: &[], + }), &["sincos"], ), ]; diff --git a/library/compiler-builtins/crates/musl-math-sys/build.rs b/library/compiler-builtins/crates/musl-math-sys/build.rs index f06d84ee267e6..b00dbc73e2800 100644 --- a/library/compiler-builtins/crates/musl-math-sys/build.rs +++ b/library/compiler-builtins/crates/musl-math-sys/build.rs @@ -8,7 +8,10 @@ const LIB_NAME: &str = "musl_math_prefixed"; /// Files that have more than one symbol. Map of file names to the symbols defined in that file. const MULTIPLE_SYMBOLS: &[(&str, &[&str])] = &[ - ("__invtrigl", &["__invtrigl", "__invtrigl_R", "__pio2_hi", "__pio2_lo"]), + ( + "__invtrigl", + &["__invtrigl", "__invtrigl_R", "__pio2_hi", "__pio2_lo"], + ), ("__polevll", &["__polevll", "__p1evll"]), ("erf", &["erf", "erfc"]), ("erff", &["erff", "erfcf"]), @@ -82,9 +85,16 @@ impl Config { let musl_dir = manifest_dir.join("musl"); let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); - let musl_arch = if target_arch == "x86" { "i386".to_owned() } else { target_arch.clone() }; + let musl_arch = if target_arch == "x86" { + "i386".to_owned() + } else { + target_arch.clone() + }; - println!("cargo::rerun-if-changed={}/c_patches", manifest_dir.display()); + println!( + "cargo::rerun-if-changed={}/c_patches", + manifest_dir.display() + ); println!("cargo::rerun-if-changed={}", musl_dir.display()); Self { @@ -108,7 +118,10 @@ fn build_musl_math(cfg: &Config) { let musl_dir = &cfg.musl_dir; let math = musl_dir.join("src/math"); let arch_dir = musl_dir.join("arch").join(&cfg.musl_arch); - assert!(math.exists(), "musl source not found. Is the submodule up to date?"); + assert!( + math.exists(), + "musl source not found. Is the submodule up to date?" + ); let source_map = find_math_source(&math, cfg); let out_path = cfg.out_dir.join(format!("lib{LIB_NAME}.a")); @@ -125,7 +138,11 @@ fn build_musl_math(cfg: &Config) { .stderr(Stdio::inherit()) .output() .unwrap(); - assert!(sed_stat.status.success(), "sed command failed: {:?}", sed_stat.status); + assert!( + sed_stat.status.success(), + "sed command failed: {:?}", + sed_stat.status + ); fs::write(obj_include.join("bits/alltypes.h"), sed_stat.stdout).unwrap(); @@ -163,8 +180,9 @@ fn build_musl_math(cfg: &Config) { // Trickery! Redefine the symbol names to have the prefix `musl_`, which allows us to // differentiate these symbols from whatever we provide. - if let Some((_names, syms)) = - MULTIPLE_SYMBOLS.iter().find(|(name, _syms)| *name == sym_name) + if let Some((_names, syms)) = MULTIPLE_SYMBOLS + .iter() + .find(|(name, _syms)| *name == sym_name) { // Handle the occasional file that defines multiple symbols for sym in *syms { @@ -291,21 +309,34 @@ fn validate_archive_symbols(out_path: &Path) { ]; // List global undefined symbols - let out = - Command::new("nm").arg("-guj").arg(out_path).stderr(Stdio::inherit()).output().unwrap(); + let out = Command::new("nm") + .arg("-guj") + .arg(out_path) + .stderr(Stdio::inherit()) + .output() + .unwrap(); let undef = str::from_utf8(&out.stdout).unwrap(); let mut undef = undef.lines().collect::>(); undef.retain(|sym| { // Account for file formats that add a leading `_` - !ALLOWED_UNDEF_PFX.iter().any(|pfx| sym.starts_with(pfx) || sym[1..].starts_with(pfx)) + !ALLOWED_UNDEF_PFX + .iter() + .any(|pfx| sym.starts_with(pfx) || sym[1..].starts_with(pfx)) }); - assert!(undef.is_empty(), "found disallowed undefined symbols: {undef:#?}"); + assert!( + undef.is_empty(), + "found disallowed undefined symbols: {undef:#?}" + ); // Find any symbols that are missing the `_musl_` prefix` - let out = - Command::new("nm").arg("-gUj").arg(out_path).stderr(Stdio::inherit()).output().unwrap(); + let out = Command::new("nm") + .arg("-gUj") + .arg(out_path) + .stderr(Stdio::inherit()) + .output() + .unwrap(); let defined = str::from_utf8(&out.stdout).unwrap(); let mut defined = defined.lines().collect::>(); diff --git a/library/compiler-builtins/crates/util/src/main.rs b/library/compiler-builtins/crates/util/src/main.rs index ef70ec9035b84..e7057869996b0 100644 --- a/library/compiler-builtins/crates/util/src/main.rs +++ b/library/compiler-builtins/crates/util/src/main.rs @@ -221,7 +221,11 @@ macro_rules! impl_parse_tuple_via_rug { impl ParseTuple for ($ty, $ty, $ty) { fn parse(input: &[&str]) -> Self { assert_eq!(input.len(), 3, "expected three arguments, got {input:?}"); - (parse_rug(input, 0), parse_rug(input, 1), parse_rug(input, 2)) + ( + parse_rug(input, 0), + parse_rug(input, 1), + parse_rug(input, 2), + ) } } }; diff --git a/library/compiler-builtins/libm-test/benches/random.rs b/library/compiler-builtins/libm-test/benches/random.rs index 63d7e5c6d2053..81f58e3a6588f 100644 --- a/library/compiler-builtins/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm-test/benches/random.rs @@ -7,7 +7,11 @@ use libm_test::generate::random::RandomInput; use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, TupleCall}; /// Benchmark with this many items to get a variety -const BENCH_ITER_ITEMS: usize = if cfg!(feature = "short-benchmarks") { 50 } else { 500 }; +const BENCH_ITER_ITEMS: usize = if cfg!(feature = "short-benchmarks") { + 50 +} else { + 500 +}; /// Extra parameters we only care about if we are benchmarking against musl. #[allow(dead_code)] @@ -53,8 +57,10 @@ where let name = Op::NAME; let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl, GeneratorKind::Random); - let benchvec: Vec<_> = - random::get_test_cases::(&ctx).0.take(BENCH_ITER_ITEMS).collect(); + let benchvec: Vec<_> = random::get_test_cases::(&ctx) + .0 + .take(BENCH_ITER_ITEMS) + .collect(); // Perform a sanity check that we are benchmarking the same thing // Don't test against musl if it is not available @@ -73,7 +79,10 @@ where let musl_res = input.call(musl_fn); let crate_res = input.call(Op::ROUTINE); - crate_res.validate(musl_res, input, &ctx).context(name).unwrap(); + crate_res + .validate(musl_res, input, &ctx) + .context(name) + .unwrap(); } #[cfg(not(feature = "build-musl"))] diff --git a/library/compiler-builtins/libm-test/examples/plot_domains.rs b/library/compiler-builtins/libm-test/examples/plot_domains.rs index 78524761e2cbc..3563103b8cd7c 100644 --- a/library/compiler-builtins/libm-test/examples/plot_domains.rs +++ b/library/compiler-builtins/libm-test/examples/plot_domains.rs @@ -56,7 +56,13 @@ where Op::RustArgs: SpacedInput, { let mut ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr, GeneratorKind::QuickSpaced); - plot_one_generator(out_dir, &ctx, "logspace", config, spaced::get_test_cases::(&ctx).0); + plot_one_generator( + out_dir, + &ctx, + "logspace", + config, + spaced::get_test_cases::(&ctx).0, + ); ctx.gen_kind = GeneratorKind::EdgeCases; plot_one_generator( out_dir, diff --git a/library/compiler-builtins/libm-test/src/domain.rs b/library/compiler-builtins/libm-test/src/domain.rs index 41e948461634d..94641be9b5483 100644 --- a/library/compiler-builtins/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm-test/src/domain.rs @@ -67,16 +67,25 @@ impl EitherPrim { /// Convenience 1-dimensional float domains. impl Domain { /// x ∈ ℝ - const UNBOUNDED: Self = - Self { start: Bound::Unbounded, end: Bound::Unbounded, check_points: None }; + const UNBOUNDED: Self = Self { + start: Bound::Unbounded, + end: Bound::Unbounded, + check_points: None, + }; /// x ∈ ℝ >= 0 - const POSITIVE: Self = - Self { start: Bound::Included(F::ZERO), end: Bound::Unbounded, check_points: None }; + const POSITIVE: Self = Self { + start: Bound::Included(F::ZERO), + end: Bound::Unbounded, + check_points: None, + }; /// x ∈ ℝ > 0 - const STRICTLY_POSITIVE: Self = - Self { start: Bound::Excluded(F::ZERO), end: Bound::Unbounded, check_points: None }; + const STRICTLY_POSITIVE: Self = Self { + start: Bound::Excluded(F::ZERO), + end: Bound::Unbounded, + check_points: None, + }; /// Wrap in the float variant of [`EitherPrim`]. const fn into_prim_float(self) -> EitherPrim> { @@ -87,8 +96,11 @@ impl Domain { /// Convenience 1-dimensional integer domains. impl Domain { /// x ∈ ℝ - const UNBOUNDED_INT: Self = - Self { start: Bound::Unbounded, end: Bound::Unbounded, check_points: None }; + const UNBOUNDED_INT: Self = Self { + start: Bound::Unbounded, + end: Bound::Unbounded, + check_points: None, + }; /// Wrap in the int variant of [`EitherPrim`]. const fn into_prim_int(self) -> EitherPrim, Self> { @@ -99,13 +111,18 @@ impl Domain { /// Multidimensional domains, represented as an array of 1-D domains. impl EitherPrim, Domain> { /// x ∈ ℝ - const UNBOUNDED1: [Self; 1] = - [Domain { start: Bound::Unbounded, end: Bound::Unbounded, check_points: None } - .into_prim_float()]; + const UNBOUNDED1: [Self; 1] = [Domain { + start: Bound::Unbounded, + end: Bound::Unbounded, + check_points: None, + } + .into_prim_float()]; /// {x1, x2} ∈ ℝ - const UNBOUNDED2: [Self; 2] = - [Domain::UNBOUNDED.into_prim_float(), Domain::UNBOUNDED.into_prim_float()]; + const UNBOUNDED2: [Self; 2] = [ + Domain::UNBOUNDED.into_prim_float(), + Domain::UNBOUNDED.into_prim_float(), + ]; /// {x1, x2, x3} ∈ ℝ const UNBOUNDED3: [Self; 3] = [ @@ -115,8 +132,10 @@ impl EitherPrim, Domain> { ]; /// {x1, x2} ∈ ℝ, one float and one int - const UNBOUNDED_F_I: [Self; 2] = - [Domain::UNBOUNDED.into_prim_float(), Domain::UNBOUNDED_INT.into_prim_int()]; + const UNBOUNDED_F_I: [Self; 2] = [ + Domain::UNBOUNDED.into_prim_float(), + Domain::UNBOUNDED_INT.into_prim_int(), + ]; /// x ∈ ℝ >= 0 const POSITIVE: [Self; 1] = [Domain::POSITIVE.into_prim_float()]; @@ -133,9 +152,12 @@ impl EitherPrim, Domain> { .into_prim_float()]; /// Domain for `acosh` - const ACOSH: [Self; 1] = - [Domain { start: Bound::Included(F::ONE), end: Bound::Unbounded, check_points: None } - .into_prim_float()]; + const ACOSH: [Self; 1] = [Domain { + start: Bound::Included(F::ONE), + end: Bound::Unbounded, + check_points: None, + } + .into_prim_float()]; /// Domain for `atanh` const ATANH: [Self; 1] = [Domain { @@ -157,9 +179,12 @@ impl EitherPrim, Domain> { const LOG: [Self; 1] = Self::STRICTLY_POSITIVE; /// Domain for `log1p` i.e. `log(1 + x)` - const LOG1P: [Self; 1] = - [Domain { start: Bound::Excluded(F::NEG_ONE), end: Bound::Unbounded, check_points: None } - .into_prim_float()]; + const LOG1P: [Self; 1] = [Domain { + start: Bound::Excluded(F::NEG_ONE), + end: Bound::Unbounded, + check_points: None, + } + .into_prim_float()]; /// Domain for `sqrt` const SQRT: [Self; 1] = Self::POSITIVE; @@ -187,8 +212,10 @@ impl EitherPrim, Domain> { /// Domain for `jn` and `yn`. // FIXME: the domain should provide some sort of "reasonable range" so we don't actually test // the entire system unbounded. - const BESSEL_N: [Self; 2] = - [Domain::UNBOUNDED_INT.into_prim_int(), Domain::UNBOUNDED.into_prim_float()]; + const BESSEL_N: [Self; 2] = [ + Domain::UNBOUNDED_INT.into_prim_int(), + Domain::UNBOUNDED.into_prim_float(), + ]; } /// Get the domain for a given function. diff --git a/library/compiler-builtins/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm-test/src/f8_impl.rs index ddb7bf90e7f4a..905c7d7fde92a 100644 --- a/library/compiler-builtins/libm-test/src/f8_impl.rs +++ b/library/compiler-builtins/libm-test/src/f8_impl.rs @@ -498,6 +498,8 @@ impl fmt::LowerHex for f8 { } pub const fn hf8(s: &str) -> f8 { - let Ok(bits) = libm::support::hex_float::parse_hex_exact(s, 8, 3) else { panic!() }; + let Ok(bits) = libm::support::hex_float::parse_hex_exact(s, 8, 3) else { + panic!() + }; f8(bits as u8) } diff --git a/library/compiler-builtins/libm-test/src/generate.rs b/library/compiler-builtins/libm-test/src/generate.rs index 89ca09a7a0b82..da080d23fa79c 100644 --- a/library/compiler-builtins/libm-test/src/generate.rs +++ b/library/compiler-builtins/libm-test/src/generate.rs @@ -16,7 +16,11 @@ pub struct KnownSize { impl KnownSize { pub fn new(iter: I, total: u64) -> Self { - Self { total, current: 0, iter } + Self { + total, + current: 0, + iter, + } } } @@ -30,7 +34,10 @@ impl Iterator for KnownSize { return next; } - assert_eq!(self.current, self.total, "total items did not match expected"); + assert_eq!( + self.current, self.total, + "total items did not match expected" + ); None } 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 e3628d51c9af5..f1e6fcec397d7 100644 --- a/library/compiler-builtins/libm-test/src/generate/case_list.rs +++ b/library/compiler-builtins/libm-test/src/generate/case_list.rs @@ -20,14 +20,21 @@ pub struct TestCase { impl TestCase { #[expect(dead_code)] fn append_inputs(v: &mut Vec, l: &[Op::RustArgs]) { - v.extend(l.iter().copied().map(|input| Self { input, output: None })); + v.extend(l.iter().copied().map(|input| Self { + input, + 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 })); + v.extend( + l.iter() + .copied() + .map(|(input, output)| Self { input, output }), + ); } } @@ -603,9 +610,15 @@ fn rint_cases() -> Vec> { &[ // Known failure on i586 #[cfg(not(x86_no_sse))] - ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff994000p+38"))), + ( + (hf64!("-0x1.e3f13ff995ffcp+38"),), + Some(hf64!("-0x1.e3f13ff994000p+38")), + ), #[cfg(x86_no_sse)] - ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff998000p+38"))), + ( + (hf64!("-0x1.e3f13ff995ffcp+38"),), + Some(hf64!("-0x1.e3f13ff998000p+38")), + ), ], ); v @@ -655,9 +668,15 @@ fn roundeven_cases() -> Vec> { &[ // Known failure on i586 #[cfg(not(x86_no_sse))] - ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff994000p+38"))), + ( + (hf64!("-0x1.e3f13ff995ffcp+38"),), + Some(hf64!("-0x1.e3f13ff994000p+38")), + ), #[cfg(x86_no_sse)] - ((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff998000p+38"))), + ( + (hf64!("-0x1.e3f13ff995ffcp+38"),), + Some(hf64!("-0x1.e3f13ff998000p+38")), + ), ], ); v @@ -832,7 +851,9 @@ where { assert_eq!(ctx.basis, CheckBasis::None); assert_eq!(ctx.gen_kind, GeneratorKind::List); - Op::get_cases().into_iter().filter_map(|x| x.output.map(|o| (x.input, o))) + Op::get_cases() + .into_iter() + .filter_map(|x| x.output.map(|o| (x.input, o))) } /// Opposite of the above; extract only test cases that don't have a known output, to be run @@ -847,7 +868,18 @@ where assert_eq!(ctx.gen_kind, GeneratorKind::List); let cases = Op::get_cases(); - let count: u64 = cases.iter().filter(|case| case.output.is_none()).count().try_into().unwrap(); + let count: u64 = cases + .iter() + .filter(|case| case.output.is_none()) + .count() + .try_into() + .unwrap(); - (cases.into_iter().filter(|x| x.output.is_none()).map(|x| x.input), count) + ( + cases + .into_iter() + .filter(|x| x.output.is_none()) + .map(|x| x.input), + count, + ) } 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 56cc9fa9a70ed..2fb0746388c15 100644 --- a/library/compiler-builtins/libm-test/src/generate/edge_cases.rs +++ b/library/compiler-builtins/libm-test/src/generate/edge_cases.rs @@ -249,7 +249,11 @@ 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 + .checked_mul(steps1) + .unwrap() + .checked_mul(steps2) + .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 e8a7ee9057e34..4ee88946d8eaf 100644 --- a/library/compiler-builtins/libm-test/src/generate/random.rs +++ b/library/compiler-builtins/libm-test/src/generate/random.rs @@ -117,7 +117,10 @@ impl_random_input!(f128); /// Create a test case iterator. pub fn get_test_cases( ctx: &CheckCtx, -) -> (impl Iterator + Send + use<'_, RustArgs>, u64) { +) -> ( + impl Iterator + Send + use<'_, RustArgs>, + u64, +) { let (iter, count) = RustArgs::get_cases(ctx); // Wrap in `KnownSize` so we get an assertion if the cuunt is wrong. diff --git a/library/compiler-builtins/libm-test/src/generate/spaced.rs b/library/compiler-builtins/libm-test/src/generate/spaced.rs index bea3f4c7e1b26..8e6b376ebd1e9 100644 --- a/library/compiler-builtins/libm-test/src/generate/spaced.rs +++ b/library/compiler-builtins/libm-test/src/generate/spaced.rs @@ -70,7 +70,9 @@ fn value_count() -> Option where u64: TryFrom, { - u64::try_from(F::Int::MAX).ok().and_then(|max| max.checked_add(1)) + u64::try_from(F::Int::MAX) + .ok() + .and_then(|max| max.checked_add(1)) } /// Returns an iterator of every possible value of type `F`. @@ -162,8 +164,11 @@ 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 + .checked_mul(steps1) + .unwrap() + .checked_mul(steps2) + .unwrap(); (EitherIter::B(iter), count) } diff --git a/library/compiler-builtins/libm-test/src/lib.rs b/library/compiler-builtins/libm-test/src/lib.rs index 485c01a478222..730318abcbae7 100644 --- a/library/compiler-builtins/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm-test/src/lib.rs @@ -71,7 +71,12 @@ pub fn test_log(s: &str) { return None; }; - PathBuf::from(x).parent().unwrap().parent().unwrap().join("target") + PathBuf::from(x) + .parent() + .unwrap() + .parent() + .unwrap() + .join("target") } }; let outfile = target_dir.join("test-log.txt"); @@ -81,7 +86,9 @@ pub fn test_log(s: &str) { .append(true) .open(outfile) .expect("failed to open logfile"); - let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap(); + let now = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap(); writeln!(f, "\n\nTest run at {}", now.as_secs()).unwrap(); writeln!(f, "arch: {}", env::consts::ARCH).unwrap(); diff --git a/library/compiler-builtins/libm-test/src/num.rs b/library/compiler-builtins/libm-test/src/num.rs index eed941423d3dc..3237c85039d57 100644 --- a/library/compiler-builtins/libm-test/src/num.rs +++ b/library/compiler-builtins/libm-test/src/num.rs @@ -180,8 +180,17 @@ impl Consts { neg_max_snan, } = self; - [pos_nan, neg_nan, max_qnan, min_snan, max_snan, neg_max_qnan, neg_min_snan, neg_max_snan] - .into_iter() + [ + pos_nan, + neg_nan, + max_qnan, + min_snan, + max_snan, + neg_max_qnan, + neg_min_snan, + neg_max_snan, + ] + .into_iter() } } @@ -229,7 +238,9 @@ where assert!(!end.is_nan()); assert!(end >= start); - let steps = steps.checked_sub(F::Int::ONE).expect("`steps` must be at least 2"); + let steps = steps + .checked_sub(F::Int::ONE) + .expect("`steps` must be at least 2"); let between = ulp_between(start, end).expect("`start` or `end` is NaN"); let spacing = (between / steps).max(F::Int::ONE); let steps = steps.min(between); // At maximum, one step per ULP @@ -283,15 +294,22 @@ mod tests { if i == 0 { assert_eq!(down, f8::NEG_INFINITY.to_bits(), "{i} next_down({v:#010b})"); } else { - let expected = - if v == f8::ZERO { 1 | f8::SIGN_MASK } else { f8::ALL[i - 1].to_bits() }; + let expected = if v == f8::ZERO { + 1 | f8::SIGN_MASK + } else { + f8::ALL[i - 1].to_bits() + }; assert_eq!(down, expected, "{i} next_down({v:#010b})"); } if i == f8::ALL_LEN - 1 { assert_eq!(up, f8::INFINITY.to_bits(), "{i} next_up({v:#010b})"); } else { - let expected = if v == f8::NEG_ZERO { 1 } else { f8::ALL[i + 1].to_bits() }; + let expected = if v == f8::NEG_ZERO { + 1 + } else { + f8::ALL[i + 1].to_bits() + }; assert_eq!(up, expected, "{i} next_up({v:#010b})"); } } @@ -300,8 +318,14 @@ mod tests { #[test] fn test_next_up_down_inf_nan() { assert_eq!(f8::NEG_INFINITY.next_up().to_bits(), f8::ALL[0].to_bits(),); - assert_eq!(f8::NEG_INFINITY.next_down().to_bits(), f8::NEG_INFINITY.to_bits(),); - assert_eq!(f8::INFINITY.next_down().to_bits(), f8::ALL[f8::ALL_LEN - 1].to_bits(),); + assert_eq!( + f8::NEG_INFINITY.next_down().to_bits(), + f8::NEG_INFINITY.to_bits(), + ); + assert_eq!( + f8::INFINITY.next_down().to_bits(), + f8::ALL[f8::ALL_LEN - 1].to_bits(), + ); assert_eq!(f8::INFINITY.next_up().to_bits(), f8::INFINITY.to_bits(),); assert_eq!(f8::NAN.next_up().to_bits(), f8::NAN.to_bits(),); assert_eq!(f8::NAN.next_down().to_bits(), f8::NAN.to_bits(),); @@ -321,7 +345,10 @@ mod tests { // Check across zero assert_eq!(f8::from_bits(0b1_0000_111).n_up(8).to_bits(), 0b0_0000_001); - assert_eq!(f8::from_bits(0b0_0000_111).n_down(8).to_bits(), 0b1_0000_001); + assert_eq!( + f8::from_bits(0b0_0000_111).n_down(8).to_bits(), + 0b1_0000_001 + ); } #[test] @@ -337,13 +364,25 @@ mod tests { #[test] fn test_n_up_down_inf_nan_zero() { assert_eq!(f8::NEG_INFINITY.n_up(1).to_bits(), f8::ALL[0].to_bits()); - assert_eq!(f8::NEG_INFINITY.n_up(239).to_bits(), f8::ALL[f8::ALL_LEN - 1].to_bits()); + assert_eq!( + f8::NEG_INFINITY.n_up(239).to_bits(), + f8::ALL[f8::ALL_LEN - 1].to_bits() + ); assert_eq!(f8::NEG_INFINITY.n_up(240).to_bits(), f8::INFINITY.to_bits()); - assert_eq!(f8::NEG_INFINITY.n_down(u8::MAX).to_bits(), f8::NEG_INFINITY.to_bits()); + assert_eq!( + f8::NEG_INFINITY.n_down(u8::MAX).to_bits(), + f8::NEG_INFINITY.to_bits() + ); - assert_eq!(f8::INFINITY.n_down(1).to_bits(), f8::ALL[f8::ALL_LEN - 1].to_bits()); + assert_eq!( + f8::INFINITY.n_down(1).to_bits(), + f8::ALL[f8::ALL_LEN - 1].to_bits() + ); assert_eq!(f8::INFINITY.n_down(239).to_bits(), f8::ALL[0].to_bits()); - assert_eq!(f8::INFINITY.n_down(240).to_bits(), f8::NEG_INFINITY.to_bits()); + assert_eq!( + f8::INFINITY.n_down(240).to_bits(), + f8::NEG_INFINITY.to_bits() + ); assert_eq!(f8::INFINITY.n_up(u8::MAX).to_bits(), f8::INFINITY.to_bits()); assert_eq!(f8::NAN.n_up(u8::MAX).to_bits(), f8::NAN.to_bits()); @@ -381,7 +420,11 @@ mod tests { assert_eq!(down, expected, "{i} {n} n_down({v:#010b})"); } else { // Overflow to -inf - assert_eq!(down, f8::NEG_INFINITY.to_bits(), "{i} {n} n_down({v:#010b})"); + assert_eq!( + down, + f8::NEG_INFINITY.to_bits(), + "{i} {n} n_down({v:#010b})" + ); } let mut up_exp_idx = i + n; @@ -438,13 +481,22 @@ mod tests { #[test] fn test_ulp_between_inf_nan_zero() { - assert_eq!(ulp_between(f8::NEG_INFINITY, f8::INFINITY).unwrap(), f8::ALL_LEN as u8); - assert_eq!(ulp_between(f8::INFINITY, f8::NEG_INFINITY).unwrap(), f8::ALL_LEN as u8); + assert_eq!( + ulp_between(f8::NEG_INFINITY, f8::INFINITY).unwrap(), + f8::ALL_LEN as u8 + ); + assert_eq!( + ulp_between(f8::INFINITY, f8::NEG_INFINITY).unwrap(), + f8::ALL_LEN as u8 + ); assert_eq!( ulp_between(f8::NEG_INFINITY, f8::ALL[f8::ALL_LEN - 1]).unwrap(), f8::ALL_LEN as u8 - 1 ); - assert_eq!(ulp_between(f8::INFINITY, f8::ALL[0]).unwrap(), f8::ALL_LEN as u8 - 1); + assert_eq!( + ulp_between(f8::INFINITY, f8::ALL[0]).unwrap(), + f8::ALL_LEN as u8 - 1 + ); assert_eq!(ulp_between(f8::ZERO, f8::NEG_ZERO).unwrap(), 0); assert_eq!(ulp_between(f8::NAN, f8::ZERO), None); @@ -469,7 +521,12 @@ mod tests { // of steps. let (ls, count) = logspace(f8::from_bits(0x0), f8::from_bits(0x3), 10); let ls: Vec<_> = ls.collect(); - let exp = [f8::from_bits(0x0), f8::from_bits(0x1), f8::from_bits(0x2), f8::from_bits(0x3)]; + let exp = [ + f8::from_bits(0x0), + f8::from_bits(0x1), + f8::from_bits(0x2), + f8::from_bits(0x3), + ]; assert_eq!(ls, exp); assert_eq!(ls.len(), usize::from(count)); } diff --git a/library/compiler-builtins/libm-test/src/op.rs b/library/compiler-builtins/libm-test/src/op.rs index 4f251f80df646..bd17aad7d0352 100644 --- a/library/compiler-builtins/libm-test/src/op.rs +++ b/library/compiler-builtins/libm-test/src/op.rs @@ -16,7 +16,7 @@ use std::fmt; use std::panic::{RefUnwindSafe, UnwindSafe}; -pub use shared::{FloatTy, MathOpInfo, Ty, ALL_OPERATIONS}; +pub use shared::{ALL_OPERATIONS, FloatTy, MathOpInfo, Ty}; use crate::{CheckOutput, Float, TupleCall}; diff --git a/library/compiler-builtins/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm-test/src/run_cfg.rs index b36164b005fde..3345a01d2de79 100644 --- a/library/compiler-builtins/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm-test/src/run_cfg.rs @@ -15,7 +15,9 @@ pub const EXTENSIVE_ITER_ENV: &str = "LIBM_EXTENSIVE_ITERATIONS"; /// The override value, if set by the above environment. static EXTENSIVE_ITER_OVERRIDE: LazyLock> = LazyLock::new(|| { - env::var(EXTENSIVE_ITER_ENV).map(|v| v.parse().expect("failed to parse iteration count")).ok() + env::var(EXTENSIVE_ITER_ENV) + .map(|v| v.parse().expect("failed to parse iteration count")) + .ok() }); /// Specific tests that need to have a reduced amount of iterations to complete in a reasonable @@ -115,7 +117,10 @@ static EXTENSIVE: LazyLock> = LazyLock::new(|| { let mut ret = Vec::new(); let append_ty_ops = |ret: &mut Vec<_>, fty: FloatTy| { - let iter = Identifier::ALL.iter().filter(move |id| id.math_op().float_ty == fty).copied(); + let iter = Identifier::ALL + .iter() + .filter(move |id| id.math_op().float_ty == fty) + .copied(); ret.extend(iter); }; @@ -276,7 +281,10 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { let seed_msg = match ctx.gen_kind { GeneratorKind::QuickSpaced | GeneratorKind::Extensive => String::new(), GeneratorKind::Random => { - format!(" using `{SEED_ENV}={}`", str::from_utf8(SEED.as_slice()).unwrap()) + format!( + " using `{SEED_ENV}={}`", + str::from_utf8(SEED.as_slice()).unwrap() + ) } GeneratorKind::EdgeCases | GeneratorKind::List => unimplemented!(), }; @@ -303,7 +311,10 @@ pub fn int_range(ctx: &CheckCtx, argnum: usize) -> RangeInclusive { return i32::MIN..=i32::MAX; } - assert_eq!(argnum, 0, "For `jn`/`yn`, only the first argument takes an integer"); + assert_eq!( + argnum, 0, + "For `jn`/`yn`, only the first argument takes an integer" + ); // The integer argument to `jn` is an iteration count. Limit this to ensure tests can be // completed in a reasonable amount of time. @@ -331,7 +342,11 @@ pub fn check_point_count(ctx: &CheckCtx) -> usize { "check_point_count is intended for edge case tests" ); let t_env = TestEnv::from_env(ctx); - if t_env.slow_platform || !cfg!(optimizations_enabled) { 4 } else { 10 } + if t_env.slow_platform || !cfg!(optimizations_enabled) { + 4 + } else { + 10 + } } /// When validating points of interest (e.g. asymptotes, inflection points, extremes), also check diff --git a/library/compiler-builtins/libm-test/src/test_traits.rs b/library/compiler-builtins/libm-test/src/test_traits.rs index c560dade8848d..dbb97016153c7 100644 --- a/library/compiler-builtins/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm-test/src/test_traits.rs @@ -328,7 +328,10 @@ where // Check when both are NaNs if actual.is_nan() && expected.is_nan() { if require_biteq && ctx.basis == CheckBasis::None { - ensure!(actual.to_bits() == expected.to_bits(), "mismatched NaN bitpatterns"); + ensure!( + actual.to_bits() == expected.to_bits(), + "mismatched NaN bitpatterns" + ); } // By default, NaNs have nothing special to check. return Ok(()); @@ -340,7 +343,10 @@ where // Make sure that the signs are the same before checing ULP to avoid wraparound let act_sig = actual.signum(); let exp_sig = expected.signum(); - ensure!(act_sig == exp_sig, "mismatched signs {act_sig:?} {exp_sig:?}"); + ensure!( + act_sig == exp_sig, + "mismatched signs {act_sig:?} {exp_sig:?}" + ); if actual.is_infinite() ^ expected.is_infinite() { bail!("mismatched infinities"); diff --git a/library/compiler-builtins/libm-test/tests/u256.rs b/library/compiler-builtins/libm-test/tests/u256.rs index 4444036d0a491..8cbb3ad226f67 100644 --- a/library/compiler-builtins/libm-test/tests/u256.rs +++ b/library/compiler-builtins/libm-test/tests/u256.rs @@ -40,7 +40,10 @@ fn from_bigint(bx: &mut BigInt) -> u256 { let mut bres = [0u128, 0]; bx.write_digits(&mut bres, Order::Lsf); bx.assign(0); - u256 { lo: bres[0], hi: bres[1] } + u256 { + lo: bres[0], + hi: bres[1], + } } fn check_one( @@ -142,6 +145,11 @@ fn mp_u256_widen_mul() { by.assign(y); let actual = x.widen_mul(y); bx *= &by; - check_one(|| format!("{x:#034x}"), || Some(format!("{y:#034x}")), actual, &mut bx); + check_one( + || format!("{x:#034x}"), + || Some(format!("{y:#034x}")), + actual, + &mut bx, + ); } } diff --git a/library/compiler-builtins/libm-test/tests/z_extensive/run.rs b/library/compiler-builtins/libm-test/tests/z_extensive/run.rs index b10c231d18390..59c806ce73e24 100644 --- a/library/compiler-builtins/libm-test/tests/z_extensive/run.rs +++ b/library/compiler-builtins/libm-test/tests/z_extensive/run.rs @@ -28,8 +28,15 @@ pub fn run() { // With default parallelism, the CPU doesn't saturate. We don't need to be nice to // other processes, so do 1.5x to make sure we use all available resources. - let threads = std::thread::available_parallelism().map(Into::into).unwrap_or(0) * 3 / 2; - rayon::ThreadPoolBuilder::new().num_threads(threads).build_global().unwrap(); + let threads = std::thread::available_parallelism() + .map(Into::into) + .unwrap_or(0) + * 3 + / 2; + rayon::ThreadPoolBuilder::new() + .num_threads(threads) + .build_global() + .unwrap(); libtest_mimic::run(&args, tests).exit(); } @@ -134,7 +141,9 @@ where }); // Run the actual tests - let res = chunks.par_bridge().try_for_each_init(Op::new_mp, test_single_chunk); + let res = chunks + .par_bridge() + .try_for_each_init(Op::new_mp, test_single_chunk); let real_total = completed.load(Ordering::Relaxed); pb.complete(real_total); @@ -179,7 +188,12 @@ impl Progress { let pb = ProgressBar::new(total); pb.set_style(initial_style); - Self { pb, final_style, name_padded, is_tty } + Self { + pb, + final_style, + name_padded, + is_tty, + } } fn update(&self, completed: u64, input: impl fmt::Debug) { diff --git a/library/compiler-builtins/libm/configure.rs b/library/compiler-builtins/libm/configure.rs index 8b8ba98156557..2a497c7b11790 100644 --- a/library/compiler-builtins/libm/configure.rs +++ b/library/compiler-builtins/libm/configure.rs @@ -107,9 +107,15 @@ fn emit_cfg_shorthands(cfg: &Config) { /// Reemit config that we make use of for test logging. fn emit_cfg_env(cfg: &Config) { - println!("cargo:rustc-env=CFG_CARGO_FEATURES={:?}", cfg.cargo_features); + 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); + println!( + "cargo:rustc-env=CFG_TARGET_FEATURES={:?}", + cfg.target_features + ); } /// Configure whether or not `f16` and `f128` support should be enabled. diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 7e56bd0796ca4..7df84fe1879b1 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -2,7 +2,10 @@ #![no_std] #![cfg_attr(intrinsics_enabled, allow(internal_features))] #![cfg_attr(intrinsics_enabled, feature(core_intrinsics))] -#![cfg_attr(all(intrinsics_enabled, target_family = "wasm"), feature(wasm_numeric_instr))] +#![cfg_attr( + all(intrinsics_enabled, target_family = "wasm"), + feature(wasm_numeric_instr) +)] #![cfg_attr(f128_enabled, feature(f128))] #![cfg_attr(f16_enabled, feature(f16))] #![allow(clippy::assign_op_pattern)] diff --git a/library/compiler-builtins/libm/src/math/atanf.rs b/library/compiler-builtins/libm/src/math/atanf.rs index eb3d401cd967e..da8daa41a0106 100644 --- a/library/compiler-builtins/libm/src/math/atanf.rs +++ b/library/compiler-builtins/libm/src/math/atanf.rs @@ -29,8 +29,13 @@ const ATAN_LO: [f32; 4] = [ 7.5497894159e-08, /* atan(inf)lo 0x33a22168 */ ]; -const A_T: [f32; 5] = - [3.3333328366e-01, -1.9999158382e-01, 1.4253635705e-01, -1.0648017377e-01, 6.1687607318e-02]; +const A_T: [f32; 5] = [ + 3.3333328366e-01, + -1.9999158382e-01, + 1.4253635705e-01, + -1.0648017377e-01, + 6.1687607318e-02, +]; /// Arctangent (f32) /// diff --git a/library/compiler-builtins/libm/src/math/cbrt.rs b/library/compiler-builtins/libm/src/math/cbrt.rs index 9d3311cd6a87a..cf56f7a9792ae 100644 --- a/library/compiler-builtins/libm/src/math/cbrt.rs +++ b/library/compiler-builtins/libm/src/math/cbrt.rs @@ -171,7 +171,11 @@ pub fn cbrt_round(x: f64, round: Round) -> FpResult { for (a, b) in wlist { if azz == a { - let tmp = if round as u64 + sign == 2 { hf64!("0x1p-52") } else { 0.0 }; + let tmp = if round as u64 + sign == 2 { + hf64!("0x1p-52") + } else { + 0.0 + }; y1 = (b + tmp).copysign(zz); } } diff --git a/library/compiler-builtins/libm/src/math/erf.rs b/library/compiler-builtins/libm/src/math/erf.rs index 1b634abec6bc6..5d82228a05fd0 100644 --- a/library/compiler-builtins/libm/src/math/erf.rs +++ b/library/compiler-builtins/libm/src/math/erf.rs @@ -306,5 +306,9 @@ pub fn erfc(x: f64) -> f64 { } let x1p_1022 = f64::from_bits(0x0010000000000000); - if sign != 0 { 2.0 - x1p_1022 } else { x1p_1022 * x1p_1022 } + if sign != 0 { + 2.0 - x1p_1022 + } else { + x1p_1022 * x1p_1022 + } } diff --git a/library/compiler-builtins/libm/src/math/erff.rs b/library/compiler-builtins/libm/src/math/erff.rs index 2e41183bfc0f7..fe15f01082e4f 100644 --- a/library/compiler-builtins/libm/src/math/erff.rs +++ b/library/compiler-builtins/libm/src/math/erff.rs @@ -218,5 +218,9 @@ pub fn erfcf(x: f32) -> f32 { } let x1p_120 = f32::from_bits(0x03800000); - if sign != 0 { 2.0 - x1p_120 } else { x1p_120 * x1p_120 } + if sign != 0 { + 2.0 - x1p_120 + } else { + x1p_120 * x1p_120 + } } diff --git a/library/compiler-builtins/libm/src/math/exp10f.rs b/library/compiler-builtins/libm/src/math/exp10f.rs index 0520a41f2e97c..303045b331322 100644 --- a/library/compiler-builtins/libm/src/math/exp10f.rs +++ b/library/compiler-builtins/libm/src/math/exp10f.rs @@ -2,8 +2,9 @@ use super::{exp2, exp2f, modff}; const LN10_F32: f32 = 3.32192809488736234787031942948939; const LN10_F64: f64 = 3.32192809488736234787031942948939; -const P10: &[f32] = - &[1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7]; +const P10: &[f32] = &[ + 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, +]; /// Calculates 10 raised to the power of `x` (f32). #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] diff --git a/library/compiler-builtins/libm/src/math/expm1f.rs b/library/compiler-builtins/libm/src/math/expm1f.rs index 12c6f532b96a5..63dc86e37c8ce 100644 --- a/library/compiler-builtins/libm/src/math/expm1f.rs +++ b/library/compiler-builtins/libm/src/math/expm1f.rs @@ -126,5 +126,9 @@ pub fn expm1f(mut x: f32) -> f32 { return y - 1.; } let uf = f32::from_bits(((0x7f - k) << 23) as u32); /* 2^-k */ - if k < 23 { (x - e + (1. - uf)) * twopk } else { (x - (e + uf) + 1.) * twopk } + if k < 23 { + (x - e + (1. - uf)) * twopk + } else { + (x - (e + uf) + 1.) * twopk + } } diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index e0b3347acf853..8856e63f59638 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -387,11 +387,17 @@ mod tests { #[test] fn fma_sbb() { - assert_eq!(fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), -3991680619069439e277); + assert_eq!( + fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), + -3991680619069439e277 + ); } #[test] fn fma_underflow() { - assert_eq!(fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), 0.0,); + assert_eq!( + fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), + 0.0, + ); } } diff --git a/library/compiler-builtins/libm/src/math/fma_wide.rs b/library/compiler-builtins/libm/src/math/fma_wide.rs index 08b78b0226454..f268c2f144ce2 100644 --- a/library/compiler-builtins/libm/src/math/fma_wide.rs +++ b/library/compiler-builtins/libm/src/math/fma_wide.rs @@ -75,11 +75,18 @@ where } } - return FpResult { val: result.narrow(), status }; + return FpResult { + val: result.narrow(), + status, + }; } let neg = ui >> (B::BITS - 1) != IntTy::::ZERO; - let err = if neg == (zb > xy) { xy - result + zb } else { zb - result + xy }; + let err = if neg == (zb > xy) { + xy - result + zb + } else { + zb - result + xy + }; if neg == (err < B::ZERO) { ui += one; } else { diff --git a/library/compiler-builtins/libm/src/math/generic/ceil.rs b/library/compiler-builtins/libm/src/math/generic/ceil.rs index 5c5bb47638fd8..499770c0d6d92 100644 --- a/library/compiler-builtins/libm/src/math/generic/ceil.rs +++ b/library/compiler-builtins/libm/src/math/generic/ceil.rs @@ -75,7 +75,14 @@ mod tests { /// Test against https://en.cppreference.com/w/cpp/numeric/math/ceil fn spec_test(cases: &[(F, F, Status)]) { - let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; + 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 } = ceil_status(x); diff --git a/library/compiler-builtins/libm/src/math/generic/floor.rs b/library/compiler-builtins/libm/src/math/generic/floor.rs index 2438046254fc4..58d1ee4c24759 100644 --- a/library/compiler-builtins/libm/src/math/generic/floor.rs +++ b/library/compiler-builtins/libm/src/math/generic/floor.rs @@ -75,7 +75,14 @@ mod tests { /// Test against https://en.cppreference.com/w/cpp/numeric/math/floor fn spec_test(cases: &[(F, F, Status)]) { - let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; + 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 } = floor_status(x); diff --git a/library/compiler-builtins/libm/src/math/generic/rint.rs b/library/compiler-builtins/libm/src/math/generic/rint.rs index 9cdeb1185a867..7bf38e3235c6b 100644 --- a/library/compiler-builtins/libm/src/math/generic/rint.rs +++ b/library/compiler-builtins/libm/src/math/generic/rint.rs @@ -15,7 +15,11 @@ pub fn rint_round(x: F, _round: Round) -> 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) { force_eval!(x) } else { x } + if cfg!(x86_no_sse) && (F::BITS == 32 || F::BITS == 64) { + force_eval!(x) + } else { + x + } }; let res = if e >= F::EXP_BIAS + F::SIG_BITS { @@ -47,7 +51,14 @@ mod tests { use crate::support::{Hexf, 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]; + 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); diff --git a/library/compiler-builtins/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/src/math/generic/sqrt.rs index ec9ff22df2081..c52560bdb2c97 100644 --- a/library/compiler-builtins/libm/src/math/generic/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/generic/sqrt.rs @@ -521,7 +521,10 @@ mod tests { f128::from_bits(0x400c3880000000000000000000000000), 0x40059000000000000000000000000000_u128, ), - (f128::from_bits(0x0000000f), 0x1fc9efbdeb14f4ed9b17ae807907e1e9_u128), + ( + f128::from_bits(0x0000000f), + 0x1fc9efbdeb14f4ed9b17ae807907e1e9_u128, + ), (f128::INFINITY, f128::INFINITY.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 25414ecf426a3..29a28f47b63af 100644 --- a/library/compiler-builtins/libm/src/math/generic/trunc.rs +++ b/library/compiler-builtins/libm/src/math/generic/trunc.rs @@ -36,7 +36,11 @@ pub fn trunc_status(x: F) -> FpResult { // C5: Otherwise the result is inexact and we will truncate. Raise `FE_INEXACT`, mask the // result, and return. - let status = if xi & F::SIG_MASK == F::Int::ZERO { Status::OK } else { Status::INEXACT }; + let status = if xi & F::SIG_MASK == F::Int::ZERO { + Status::OK + } else { + Status::INEXACT + }; xi &= mask; FpResult::new(F::from_bits(xi), status) } @@ -47,7 +51,14 @@ mod tests { use crate::support::Hexf; fn spec_test(cases: &[(F, F, Status)]) { - let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY]; + 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 } = trunc_status(x); diff --git a/library/compiler-builtins/libm/src/math/ilogb.rs b/library/compiler-builtins/libm/src/math/ilogb.rs index ccc4914be2bf7..5b41f7b1dc0b7 100644 --- a/library/compiler-builtins/libm/src/math/ilogb.rs +++ b/library/compiler-builtins/libm/src/math/ilogb.rs @@ -21,7 +21,11 @@ pub fn ilogb(x: f64) -> i32 { e } else if e == 0x7ff { force_eval!(0.0 / 0.0); - if (i << 12) != 0 { FP_ILOGBNAN } else { i32::MAX } + if (i << 12) != 0 { + FP_ILOGBNAN + } else { + i32::MAX + } } else { e - 0x3ff } diff --git a/library/compiler-builtins/libm/src/math/k_sin.rs b/library/compiler-builtins/libm/src/math/k_sin.rs index 42441455ff32f..9dd96c944744d 100644 --- a/library/compiler-builtins/libm/src/math/k_sin.rs +++ b/library/compiler-builtins/libm/src/math/k_sin.rs @@ -49,5 +49,9 @@ pub(crate) fn k_sin(x: f64, y: f64, iy: i32) -> f64 { let w = z * z; let r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6); let v = z * x; - if iy == 0 { x + v * (S1 + z * r) } else { x - ((z * (0.5 * y - v * r) - y) - v * S1) } + if iy == 0 { + x + v * (S1 + z * r) + } else { + x - ((z * (0.5 * y - v * r) - y) - v * S1) + } } diff --git a/library/compiler-builtins/libm/src/math/log1p.rs b/library/compiler-builtins/libm/src/math/log1p.rs index b7f3fb09e1574..65142c0d622cc 100644 --- a/library/compiler-builtins/libm/src/math/log1p.rs +++ b/library/compiler-builtins/libm/src/math/log1p.rs @@ -118,7 +118,11 @@ pub fn log1p(x: f64) -> f64 { k = (hu >> 20) as i32 - 0x3ff; /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ if k < 54 { - c = if k >= 2 { 1. - (f64::from_bits(ui) - x) } else { x - (f64::from_bits(ui) - 1.) }; + c = if k >= 2 { + 1. - (f64::from_bits(ui) - x) + } else { + x - (f64::from_bits(ui) - 1.) + }; c /= f64::from_bits(ui); } else { c = 0.; diff --git a/library/compiler-builtins/libm/src/math/log1pf.rs b/library/compiler-builtins/libm/src/math/log1pf.rs index bba5b8a2f211c..23978e61c3c4a 100644 --- a/library/compiler-builtins/libm/src/math/log1pf.rs +++ b/library/compiler-builtins/libm/src/math/log1pf.rs @@ -73,7 +73,11 @@ pub fn log1pf(x: f32) -> f32 { k = (iu >> 23) as i32 - 0x7f; /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ if k < 25 { - c = if k >= 2 { 1. - (f32::from_bits(ui) - x) } else { x - (f32::from_bits(ui) - 1.) }; + c = if k >= 2 { + 1. - (f32::from_bits(ui) - x) + } else { + x - (f32::from_bits(ui) - 1.) + }; c /= f32::from_bits(ui); } else { c = 0.; diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 80b2a24999ccd..7e7d049b93071 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -239,10 +239,18 @@ pub fn pow(x: f64, y: f64) -> f64 { /* over/underflow if x is not close to one */ if ix < 0x3fefffff { - return if hy < 0 { s * HUGE * HUGE } else { s * TINY * TINY }; + return if hy < 0 { + s * HUGE * HUGE + } else { + s * TINY * TINY + }; } if ix > 0x3ff00000 { - return if hy > 0 { s * HUGE * HUGE } else { s * TINY * TINY }; + return if hy > 0 { + s * HUGE * HUGE + } else { + s * TINY * TINY + }; } /* now |1-x| is TINY <= 2**-20, suffice to compute @@ -439,7 +447,11 @@ mod tests { fn pow_test(base: f64, exponent: f64, expected: f64) { let res = pow(base, exponent); assert!( - if expected.is_nan() { res.is_nan() } else { pow(base, exponent) == expected }, + if expected.is_nan() { + res.is_nan() + } else { + pow(base, exponent) == expected + }, "{} ** {} was {} instead of {}", base, exponent, @@ -449,11 +461,13 @@ mod tests { } fn test_sets_as_base(sets: &[&[f64]], exponent: f64, expected: f64) { - sets.iter().for_each(|s| s.iter().for_each(|val| pow_test(*val, exponent, expected))); + sets.iter() + .for_each(|s| s.iter().for_each(|val| pow_test(*val, exponent, expected))); } fn test_sets_as_exponent(base: f64, sets: &[&[f64]], expected: f64) { - sets.iter().for_each(|s| s.iter().for_each(|val| pow_test(base, *val, expected))); + sets.iter() + .for_each(|s| s.iter().for_each(|val| pow_test(base, *val, expected))); } fn test_sets(sets: &[&[f64]], computed: &dyn Fn(f64) -> f64, expected: &dyn Fn(f64) -> f64) { @@ -467,7 +481,11 @@ mod tests { #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] let res = force_eval!(res); assert!( - if exp.is_nan() { res.is_nan() } else { exp == res }, + if exp.is_nan() { + res.is_nan() + } else { + exp == res + }, "test for {} was {} instead of {}", val, res, @@ -515,7 +533,9 @@ mod tests { // (-Infinity ^ anything but odd ints should be == -0 ^ (-anything)) // We can lump in pos/neg odd ints here because they don't seem to // cause panics (div by zero) in release mode (I think). - test_sets(ALL, &|v: f64| pow(f64::NEG_INFINITY, v), &|v: f64| pow(-0.0, -v)); + test_sets(ALL, &|v: f64| pow(f64::NEG_INFINITY, v), &|v: f64| { + pow(-0.0, -v) + }); } #[test] @@ -582,11 +602,15 @@ mod tests { // Factoring -1 out: // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer)) - [POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS].iter().for_each(|int_set| { - int_set.iter().for_each(|int| { - test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| pow(-1.0, *int) * pow(v, *int)); - }) - }); + [POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS] + .iter() + .for_each(|int_set| { + int_set.iter().for_each(|int| { + test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| { + pow(-1.0, *int) * pow(v, *int) + }); + }) + }); // Negative base (imaginary results): // (-anything except 0 and Infinity ^ non-integer should be NAN) diff --git a/library/compiler-builtins/libm/src/math/powf.rs b/library/compiler-builtins/libm/src/math/powf.rs index 839c6c23d436d..11c7a7cbd94d1 100644 --- a/library/compiler-builtins/libm/src/math/powf.rs +++ b/library/compiler-builtins/libm/src/math/powf.rs @@ -182,11 +182,19 @@ pub fn powf(x: f32, y: f32) -> f32 { /* if |y| > 2**27 */ /* over/underflow if x is not close to one */ if ix < 0x3f7ffff8 { - return if hy < 0 { sn * HUGE * HUGE } else { sn * TINY * TINY }; + return if hy < 0 { + sn * HUGE * HUGE + } else { + sn * TINY * TINY + }; } if ix > 0x3f800007 { - return if hy > 0 { sn * HUGE * HUGE } else { sn * TINY * TINY }; + return if hy > 0 { + sn * HUGE * HUGE + } else { + sn * TINY * TINY + }; } /* now |1-x| is TINY <= 2**-20, suffice to compute diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 917e90819a50d..d677fd9dcb308 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -199,16 +199,28 @@ mod tests { fn test_near_pi() { let arg = 3.141592025756836; let arg = force_eval!(arg); - assert_eq!(rem_pio2(arg), (2, -6.278329573009626e-7, -2.1125998133974653e-23)); + assert_eq!( + rem_pio2(arg), + (2, -6.278329573009626e-7, -2.1125998133974653e-23) + ); let arg = 3.141592033207416; let arg = force_eval!(arg); - assert_eq!(rem_pio2(arg), (2, -6.20382377148128e-7, -2.1125998133974653e-23)); + assert_eq!( + rem_pio2(arg), + (2, -6.20382377148128e-7, -2.1125998133974653e-23) + ); let arg = 3.141592144966125; let arg = force_eval!(arg); - assert_eq!(rem_pio2(arg), (2, -5.086236681942706e-7, -2.1125998133974653e-23)); + assert_eq!( + rem_pio2(arg), + (2, -5.086236681942706e-7, -2.1125998133974653e-23) + ); let arg = 3.141592979431152; let arg = force_eval!(arg); - assert_eq!(rem_pio2(arg), (2, 3.2584135866119817e-7, -2.1125998133974653e-23)); + assert_eq!( + rem_pio2(arg), + (2, 3.2584135866119817e-7, -2.1125998133974653e-23) + ); } #[test] diff --git a/library/compiler-builtins/libm/src/math/sinf.rs b/library/compiler-builtins/libm/src/math/sinf.rs index b8fae2c980170..709b63fcf297d 100644 --- a/library/compiler-builtins/libm/src/math/sinf.rs +++ b/library/compiler-builtins/libm/src/math/sinf.rs @@ -42,7 +42,11 @@ pub fn sinf(x: f32) -> f32 { if ix < 0x39800000 { /* |x| < 2**-12 */ /* raise inexact if x!=0 and underflow if subnormal */ - force_eval!(if ix < 0x00800000 { x / x1p120 } else { x + x1p120 }); + force_eval!(if ix < 0x00800000 { + x / x1p120 + } else { + x + x1p120 + }); return x; } return k_sinf(x64); @@ -57,7 +61,11 @@ pub fn sinf(x: f32) -> f32 { return k_cosf(x64 - S1_PIO2); } } - return k_sinf(if sign { -(x64 + S2_PIO2) } else { -(x64 - S2_PIO2) }); + return k_sinf(if sign { + -(x64 + S2_PIO2) + } else { + -(x64 - S2_PIO2) + }); } if ix <= 0x40e231d5 { /* |x| ~<= 9*pi/4 */ diff --git a/library/compiler-builtins/libm/src/math/support/big.rs b/library/compiler-builtins/libm/src/math/support/big.rs index eae08238e0997..f24c063cd3456 100644 --- a/library/compiler-builtins/libm/src/math/support/big.rs +++ b/library/compiler-builtins/libm/src/math/support/big.rs @@ -19,11 +19,17 @@ 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 MAX: Self = Self { + lo: u128::MAX, + hi: u128::MAX, + }; /// Reinterpret as a signed integer pub fn signed(self) -> i256 { - i256 { lo: self.lo, hi: self.hi } + i256 { + lo: self.lo, + hi: self.hi, + } } } @@ -39,7 +45,10 @@ impl i256 { /// Reinterpret as an unsigned integer #[cfg(any(test, feature = "unstable-public-internals"))] pub fn unsigned(self) -> u256 { - u256 { lo: self.lo, hi: self.hi } + u256 { + lo: self.lo, + hi: self.hi, + } } } @@ -53,7 +62,10 @@ impl MinInt for u256 { 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 MAX: Self = Self { + lo: u128::MAX, + hi: u128::MAX, + }; } impl MinInt for i256 { @@ -65,8 +77,14 @@ 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: 0, hi: 1 << 127 }; - const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX << 1 }; + const MIN: Self = Self { + lo: 0, + hi: 1 << 127, + }; + const MAX: Self = Self { + lo: u128::MAX, + hi: u128::MAX << 1, + }; } 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 2c71191ba5331..d2010f0216e35 100644 --- a/library/compiler-builtins/libm/src/math/support/big/tests.rs +++ b/library/compiler-builtins/libm/src/math/support/big/tests.rs @@ -13,23 +13,62 @@ fn hexu(v: u256) -> String { #[test] fn widen_u128() { - assert_eq!(u128::MAX.widen(), u256 { lo: u128::MAX, hi: 0 }); - assert_eq!(LOHI_SPLIT.widen(), u256 { lo: LOHI_SPLIT, hi: 0 }); + assert_eq!( + u128::MAX.widen(), + u256 { + lo: u128::MAX, + hi: 0 + } + ); + assert_eq!( + LOHI_SPLIT.widen(), + u256 { + lo: LOHI_SPLIT, + hi: 0 + } + ); } #[test] fn widen_i128() { assert_eq!((-1i128).widen(), u256::MAX.signed()); - assert_eq!((LOHI_SPLIT as i128).widen(), i256 { lo: LOHI_SPLIT, hi: u128::MAX }); + assert_eq!( + (LOHI_SPLIT as i128).widen(), + i256 { + lo: LOHI_SPLIT, + hi: u128::MAX + } + ); assert_eq!((-1i128).zero_widen().unsigned(), (u128::MAX).widen()); } #[test] fn widen_mul_u128() { let tests = [ - (u128::MAX / 2, 2_u128, u256 { lo: u128::MAX - 1, hi: 0 }), - (u128::MAX, 2_u128, u256 { lo: u128::MAX - 1, hi: 1 }), - (u128::MAX, u128::MAX, u256 { lo: 1, hi: u128::MAX - 1 }), + ( + u128::MAX / 2, + 2_u128, + u256 { + lo: u128::MAX - 1, + hi: 0, + }, + ), + ( + u128::MAX, + 2_u128, + u256 { + lo: u128::MAX - 1, + hi: 1, + }, + ), + ( + u128::MAX, + u128::MAX, + u256 { + lo: 1, + hi: u128::MAX - 1, + }, + ), (0, 0, u256::ZERO), (1234u128, 0, u256::ZERO), (0, 1234, u256::ZERO), @@ -68,7 +107,13 @@ fn not_u256() { #[test] fn shr_u256() { - let only_low = [1, u16::MAX.into(), u32::MAX.into(), u64::MAX.into(), u128::MAX]; + let only_low = [ + 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| { @@ -99,23 +144,106 @@ fn shr_u256() { } let check = [ - (u256::MAX, 1, u256 { lo: u128::MAX, hi: u128::MAX >> 1 }), - (u256::MAX, 5, u256 { lo: u128::MAX, hi: u128::MAX >> 5 }), - (u256::MAX, 63, u256 { lo: u128::MAX, hi: u64::MAX as u128 | (1 << 64) }), - (u256::MAX, 64, u256 { lo: u128::MAX, hi: u64::MAX as u128 }), - (u256::MAX, 65, u256 { lo: u128::MAX, hi: (u64::MAX >> 1) as u128 }), - (u256::MAX, 127, u256 { lo: u128::MAX, hi: 1 }), - (u256::MAX, 128, u256 { lo: u128::MAX, hi: 0 }), - (u256::MAX, 129, u256 { lo: u128::MAX >> 1, hi: 0 }), - (u256::MAX, 191, u256 { lo: u64::MAX as u128 | 1 << 64, hi: 0 }), - (u256::MAX, 192, u256 { lo: u64::MAX as u128, hi: 0 }), - (u256::MAX, 193, u256 { lo: u64::MAX as u128 >> 1, hi: 0 }), + ( + u256::MAX, + 1, + u256 { + lo: u128::MAX, + hi: u128::MAX >> 1, + }, + ), + ( + u256::MAX, + 5, + u256 { + lo: u128::MAX, + hi: u128::MAX >> 5, + }, + ), + ( + u256::MAX, + 63, + u256 { + lo: u128::MAX, + hi: u64::MAX as u128 | (1 << 64), + }, + ), + ( + u256::MAX, + 64, + u256 { + lo: u128::MAX, + hi: u64::MAX as u128, + }, + ), + ( + u256::MAX, + 65, + u256 { + lo: u128::MAX, + hi: (u64::MAX >> 1) as u128, + }, + ), + ( + u256::MAX, + 127, + u256 { + lo: u128::MAX, + hi: 1, + }, + ), + ( + u256::MAX, + 128, + u256 { + lo: u128::MAX, + hi: 0, + }, + ), + ( + u256::MAX, + 129, + u256 { + lo: u128::MAX >> 1, + hi: 0, + }, + ), + ( + u256::MAX, + 191, + u256 { + lo: u64::MAX as u128 | 1 << 64, + hi: 0, + }, + ), + ( + u256::MAX, + 192, + u256 { + lo: u64::MAX as u128, + hi: 0, + }, + ), + ( + u256::MAX, + 193, + u256 { + lo: u64::MAX as u128 >> 1, + hi: 0, + }, + ), (u256::MAX, 254, u256 { lo: 0b11, hi: 0 }), (u256::MAX, 255, u256 { lo: 1, hi: 0 }), ( - u256 { hi: LOHI_SPLIT, lo: 0 }, + u256 { + hi: LOHI_SPLIT, + lo: 0, + }, 64, - u256 { lo: 0xffffffffffffffff0000000000000000, hi: 0xaaaaaaaaaaaaaaaa }, + u256 { + lo: 0xffffffffffffffff0000000000000000, + hi: 0xaaaaaaaaaaaaaaaa, + }, ), ]; diff --git a/library/compiler-builtins/libm/src/math/support/env.rs b/library/compiler-builtins/libm/src/math/support/env.rs index 796309372a5c3..53ae32f658dbe 100644 --- a/library/compiler-builtins/libm/src/math/support/env.rs +++ b/library/compiler-builtins/libm/src/math/support/env.rs @@ -25,7 +25,10 @@ impl FpResult { /// Return `val` with `Status::OK`. pub fn ok(val: T) -> Self { - Self { val, status: Status::OK } + Self { + val, + status: Status::OK, + } } } 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 fac1048323765..8094a7b84d550 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -105,7 +105,11 @@ pub trait Float: /// 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) } + if self.is_nan() && rhs.is_nan() { + true + } else { + self.biteq(rhs) + } } /// Returns true if the value is NaN. @@ -149,7 +153,11 @@ pub trait Float: /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. fn from_parts(negative: bool, exponent: u32, significand: Self::Int) -> Self { - let sign = if negative { Self::Int::ONE } else { Self::Int::ZERO }; + let sign = if negative { + Self::Int::ONE + } else { + Self::Int::ZERO + }; Self::from_bits( (sign << (Self::BITS - 1)) | (Self::Int::cast_from(exponent & Self::EXP_SAT) << Self::SIG_BITS) @@ -173,7 +181,11 @@ pub trait Float: /// Returns a number that represents the sign of self. #[allow(dead_code)] fn signum(self) -> Self { - if self.is_nan() { self } else { Self::ONE.copysign(self) } + if self.is_nan() { + self + } else { + Self::ONE.copysign(self) + } } } @@ -273,18 +285,61 @@ macro_rules! float_impl { } 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) + ( + 1i32.wrapping_sub(shift as i32), + significand << shift as Self::Int, + ) } } }; } #[cfg(f16_enabled)] -float_impl!(f16, u16, i16, 16, 10, f16::from_bits, f16::to_bits, fmaf16, fmaf16); -float_impl!(f32, u32, i32, 32, 23, f32_from_bits, f32_to_bits, fmaf, fmaf32); -float_impl!(f64, u64, i64, 64, 52, f64_from_bits, f64_to_bits, fma, fmaf64); +float_impl!( + f16, + u16, + i16, + 16, + 10, + f16::from_bits, + f16::to_bits, + fmaf16, + fmaf16 +); +float_impl!( + f32, + u32, + i32, + 32, + 23, + f32_from_bits, + f32_to_bits, + fmaf, + fmaf32 +); +float_impl!( + f64, + u64, + i64, + 64, + 52, + f64_from_bits, + f64_to_bits, + fma, + fmaf64 +); #[cfg(f128_enabled)] -float_impl!(f128, u128, i128, 128, 112, f128::from_bits, f128::to_bits, fmaf128, fmaf128); +float_impl!( + f128, + u128, + i128, + 128, + 112, + f128::from_bits, + f128::to_bits, + fmaf128, + fmaf128 +); /* FIXME(msrv): vendor some things that are not const stable at our MSRV */ @@ -424,7 +479,10 @@ mod tests { // `from_parts` assert_biteq!(f32::from_parts(true, f32::EXP_BIAS, 0), -1.0f32); - assert_biteq!(f32::from_parts(false, 10 + f32::EXP_BIAS, 0), hf32!("0x1p10")); + assert_biteq!( + f32::from_parts(false, 10 + f32::EXP_BIAS, 0), + hf32!("0x1p10") + ); assert_biteq!(f32::from_parts(false, 0, 1), f32::from_bits(0x1)); } @@ -451,7 +509,10 @@ mod tests { // `from_parts` assert_biteq!(f64::from_parts(true, f64::EXP_BIAS, 0), -1.0f64); - assert_biteq!(f64::from_parts(false, 10 + f64::EXP_BIAS, 0), hf64!("0x1p10")); + assert_biteq!( + f64::from_parts(false, 10 + f64::EXP_BIAS, 0), + hf64!("0x1p10") + ); assert_biteq!(f64::from_parts(false, 0, 1), f64::from_bits(0x1)); } 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 819e2f56e36b2..85569d98aef48 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -234,7 +234,9 @@ const fn parse_hex(mut b: &[u8]) -> Result { match c { b'.' => { if seen_point { - return Err(HexFloatParseError("unexpected '.' parsing fractional digits")); + return Err(HexFloatParseError( + "unexpected '.' parsing fractional digits", + )); } seen_point = true; continue; @@ -294,7 +296,9 @@ const fn parse_hex(mut b: &[u8]) -> Result { } if !some_digits { - return Err(HexFloatParseError("at least one exponent digit is required")); + return Err(HexFloatParseError( + "at least one exponent digit is required", + )); }; { @@ -542,7 +546,11 @@ mod parse_tests { for k in -149..=127 { let s = format!("0x1p{k}"); let x = hf32(&s); - let y = if k < 0 { 0.5f32.powi(-k) } else { 2.0f32.powi(k) }; + let y = if k < 0 { + 0.5f32.powi(-k) + } else { + 2.0f32.powi(k) + }; assert_eq!(x, y); } @@ -613,9 +621,14 @@ mod parse_tests { fn rounding_extreme_underflow() { for k in 1..1000 { let s = format!("0x1p{}", -149 - k); - let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else { unreachable!() }; + let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else { + unreachable!() + }; assert_eq!(bits, 0, "{s} should round to zero, got bits={bits}"); - assert!(status.underflow(), "should indicate underflow when parsing {s}"); + assert!( + status.underflow(), + "should indicate underflow when parsing {s}" + ); assert!(status.inexact(), "should indicate inexact when parsing {s}"); } } @@ -623,11 +636,15 @@ mod parse_tests { fn long_tail() { for k in 1..1000 { let s = format!("0x1.{}p0", "0".repeat(k)); - let Ok(bits) = parse_hex_exact(&s, 32, 23) else { panic!("parsing {s} failed") }; + let Ok(bits) = parse_hex_exact(&s, 32, 23) else { + panic!("parsing {s} failed") + }; assert_eq!(f32::from_bits(bits as u32), 1.0); let s = format!("0x1.{}1p0", "0".repeat(k)); - let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else { unreachable!() }; + let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else { + unreachable!() + }; if status.inexact() { assert!(1.0 == f32::from_bits(bits as u32)); } else { @@ -839,7 +856,10 @@ mod parse_tests { assert_eq!(hf32!("0x1.ffep+8").to_bits(), 0x43fff000_u32); assert_eq!(hf64!("0x1.ffep+8").to_bits(), 0x407ffe0000000000_u64); #[cfg(f128_enabled)] - assert_eq!(hf128!("0x1.ffep+8").to_bits(), 0x4007ffe0000000000000000000000000_u128); + assert_eq!( + hf128!("0x1.ffep+8").to_bits(), + 0x4007ffe0000000000000000000000000_u128 + ); } } @@ -1143,8 +1163,14 @@ mod print_tests { #[cfg(f128_enabled)] { - assert_eq!(Hexf(f128::MAX).to_string(), "0x1.ffffffffffffffffffffffffffffp+16383"); - assert_eq!(Hexf(f128::MIN).to_string(), "-0x1.ffffffffffffffffffffffffffffp+16383"); + assert_eq!( + Hexf(f128::MAX).to_string(), + "0x1.ffffffffffffffffffffffffffffp+16383" + ); + assert_eq!( + Hexf(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(), "NaN"); diff --git a/library/compiler-builtins/libm/src/math/tan.rs b/library/compiler-builtins/libm/src/math/tan.rs index a074ca5540acb..a072bdec56e00 100644 --- a/library/compiler-builtins/libm/src/math/tan.rs +++ b/library/compiler-builtins/libm/src/math/tan.rs @@ -53,7 +53,11 @@ pub fn tan(x: f64) -> f64 { if ix < 0x3e400000 { /* |x| < 2**-27 */ /* raise inexact if x!=0 and underflow if subnormal */ - force_eval!(if ix < 0x00100000 { x / x1p120 as f64 } else { x + x1p120 as f64 }); + force_eval!(if ix < 0x00100000 { + x / x1p120 as f64 + } else { + x + x1p120 as f64 + }); return x; } return k_tan(x, 0.0, 0); diff --git a/library/compiler-builtins/libm/src/math/tanf.rs b/library/compiler-builtins/libm/src/math/tanf.rs index 7586aae4c7e58..8bcf9581ff600 100644 --- a/library/compiler-builtins/libm/src/math/tanf.rs +++ b/library/compiler-builtins/libm/src/math/tanf.rs @@ -42,7 +42,11 @@ pub fn tanf(x: f32) -> f32 { if ix < 0x39800000 { /* |x| < 2**-12 */ /* raise inexact if x!=0 and underflow if subnormal */ - force_eval!(if ix < 0x00800000 { x / x1p120 } else { x + x1p120 }); + force_eval!(if ix < 0x00800000 { + x / x1p120 + } else { + x + x1p120 + }); return x; } return k_tanf(x64, false); From 98acedc9144c3ea6dad685cb6b673631e430c66e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 23:30:12 +0000 Subject: [PATCH 1842/4206] Remove libm CI dockerfiles These are identical to what already exists in compiler-builtins except for some base image changes, so we can eliminate the duplicates. --- .../aarch64-unknown-linux-gnu/Dockerfile | 15 --------------- .../arm-unknown-linux-gnueabi/Dockerfile | 14 -------------- .../arm-unknown-linux-gnueabihf/Dockerfile | 14 -------------- .../armv7-unknown-linux-gnueabihf/Dockerfile | 14 -------------- .../docker/i586-unknown-linux-gnu/Dockerfile | 5 ----- .../docker/i686-unknown-linux-gnu/Dockerfile | 5 ----- .../loongarch64-unknown-linux-gnu/Dockerfile | 13 ------------- .../docker/mips-unknown-linux-gnu/Dockerfile | 15 --------------- .../mips64-unknown-linux-gnuabi64/Dockerfile | 19 ------------------- .../Dockerfile | 18 ------------------ .../mipsel-unknown-linux-gnu/Dockerfile | 15 --------------- .../powerpc-unknown-linux-gnu/Dockerfile | 15 --------------- .../powerpc64-unknown-linux-gnu/Dockerfile | 15 --------------- .../powerpc64le-unknown-linux-gnu/Dockerfile | 16 ---------------- .../riscv64gc-unknown-linux-gnu/Dockerfile | 15 --------------- .../ci/docker/thumbv6m-none-eabi/Dockerfile | 9 --------- .../ci/docker/thumbv7em-none-eabi/Dockerfile | 9 --------- .../docker/thumbv7em-none-eabihf/Dockerfile | 9 --------- .../ci/docker/thumbv7m-none-eabi/Dockerfile | 9 --------- .../x86_64-unknown-linux-gnu/Dockerfile | 5 ----- 20 files changed, 249 deletions(-) delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/thumbv6m-none-eabi/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabi/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/thumbv7m-none-eabi/Dockerfile delete mode 100644 library/compiler-builtins/etc/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile diff --git a/library/compiler-builtins/etc/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 7fa06b2860106..0000000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-aarch64-linux-gnu m4 make libc6-dev-arm64-cross \ - qemu-user-static - -ENV TOOLCHAIN_PREFIX=aarch64-linux-gnu- -ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER=qemu-aarch64-static \ - AR_aarch64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ - CC_aarch64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/aarch64-linux-gnu \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile deleted file mode 100644 index e070a7d936ea1..0000000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabi/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-linux-gnueabi libc6-dev-armel-cross qemu-user-static - -ENV TOOLCHAIN_PREFIX=arm-linux-gnueabi- -ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_RUNNER=qemu-arm-static \ - AR_arm_unknown_linux_gnueabi="$TOOLCHAIN_PREFIX"ar \ - CC_arm_unknown_linux_gnueabi="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/arm-linux-gnueabi \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile deleted file mode 100644 index 29f1e04a9b5b2..0000000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static - -ENV TOOLCHAIN_PREFIX=arm-linux-gnueabihf- -ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \ - AR_arm_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"ar \ - CC_arm_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile deleted file mode 100644 index 0a30801b44deb..0000000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static - -ENV TOOLCHAIN_PREFIX=arm-linux-gnueabihf- -ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER=qemu-arm-static \ - AR_armv7_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"ar \ - CC_armv7_unknown_linux_gnueabihf="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 37e206a84fcb5..0000000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/i586-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc-multilib m4 make libc6-dev ca-certificates diff --git a/library/compiler-builtins/etc/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 37e206a84fcb5..0000000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/i686-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc-multilib m4 make libc6-dev ca-certificates diff --git a/library/compiler-builtins/etc/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile deleted file mode 100644 index a9ce320e8b4ab..0000000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev qemu-user-static ca-certificates \ - gcc-14-loongarch64-linux-gnu libc6-dev-loong64-cross - -ENV CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_LINKER=loongarch64-linux-gnu-gcc-14 \ - CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_RUNNER=qemu-loongarch64-static \ - AR_loongarch64_unknown_linux_gnu=loongarch64-linux-gnu-ar \ - CC_loongarch64_unknown_linux_gnu=loongarch64-linux-gnu-gcc-14 \ - QEMU_LD_PREFIX=/usr/loongarch64-linux-gnu \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 298208c925ac4..0000000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/mips-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-mips-linux-gnu libc6-dev-mips-cross \ - binfmt-support qemu-user-static qemu-system-mips - -ENV TOOLCHAIN_PREFIX=mips-linux-gnu- -ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_RUNNER=qemu-mips-static \ - AR_mips_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ - CC_mips_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/mips-linux-gnu \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile deleted file mode 100644 index 101b3853efee2..0000000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ca-certificates \ - gcc \ - gcc-mips64-linux-gnuabi64 \ - libc6-dev \ - libc6-dev-mips64-cross \ - qemu-user-static \ - qemu-system-mips - -ENV TOOLCHAIN_PREFIX=mips64-linux-gnuabi64- -ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64-static \ - AR_mips64_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"ar \ - CC_mips64_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/mips64-linux-gnuabi64 \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile deleted file mode 100644 index 0eb14f9acf5d8..0000000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ca-certificates \ - gcc \ - gcc-mips64el-linux-gnuabi64 \ - libc6-dev \ - libc6-dev-mips64el-cross \ - qemu-user-static - -ENV TOOLCHAIN_PREFIX=mips64el-linux-gnuabi64- -ENV CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_RUNNER=qemu-mips64el-static \ - AR_mips64el_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"ar \ - CC_mips64el_unknown_linux_gnuabi64="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/mips64el-linux-gnuabi64 \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 1b9817cfef88a..0000000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/mipsel-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-mipsel-linux-gnu libc6-dev-mipsel-cross \ - binfmt-support qemu-user-static - -ENV TOOLCHAIN_PREFIX=mipsel-linux-gnu- -ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_RUNNER=qemu-mipsel-static \ - AR_mipsel_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ - CC_mipsel_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/mipsel-linux-gnu \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 1ea2e30a2429d..0000000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/powerpc-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev qemu-user-static ca-certificates \ - gcc-powerpc-linux-gnu libc6-dev-powerpc-cross \ - qemu-system-ppc - -ENV TOOLCHAIN_PREFIX=powerpc-linux-gnu- -ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc-static \ - AR_powerpc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ - CC_powerpc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/powerpc-linux-gnu \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 373814bcafd7c..0000000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross \ - binfmt-support qemu-user-static qemu-system-ppc - -ENV TOOLCHAIN_PREFIX=powerpc64-linux-gnu- -ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64-static \ - AR_powerpc64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ - CC_powerpc64_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 403bb1d95b2b6..0000000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev qemu-user-static ca-certificates \ - gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross \ - qemu-system-ppc - -ENV TOOLCHAIN_PREFIX=powerpc64le-linux-gnu- -ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc64le-static \ - AR_powerpc64le_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ - CC_powerpc64le_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ - QEMU_CPU=POWER8 \ - QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile deleted file mode 100644 index 5f8a289241148..0000000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev qemu-user-static ca-certificates \ - gcc-riscv64-linux-gnu libc6-dev-riscv64-cross \ - qemu-system-riscv64 - -ENV TOOLCHAIN_PREFIX=riscv64-linux-gnu- -ENV CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ - CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_RUNNER=qemu-riscv64-static \ - AR_riscv64gc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"ar \ - CC_riscv64gc_unknown_linux_gnu="$TOOLCHAIN_PREFIX"gcc \ - QEMU_LD_PREFIX=/usr/riscv64-linux-gnu \ - RUST_TEST_THREADS=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/thumbv6m-none-eabi/Dockerfile deleted file mode 100644 index ad0d4351ea654..0000000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/thumbv6m-none-eabi/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -ARG IMAGE=ubuntu:24.04 -FROM $IMAGE - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-none-eabi \ - libnewlib-arm-none-eabi -ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabi/Dockerfile deleted file mode 100644 index ad0d4351ea654..0000000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabi/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -ARG IMAGE=ubuntu:24.04 -FROM $IMAGE - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-none-eabi \ - libnewlib-arm-none-eabi -ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile deleted file mode 100644 index ad0d4351ea654..0000000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -ARG IMAGE=ubuntu:24.04 -FROM $IMAGE - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-none-eabi \ - libnewlib-arm-none-eabi -ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/thumbv7m-none-eabi/Dockerfile deleted file mode 100644 index ad0d4351ea654..0000000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/thumbv7m-none-eabi/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -ARG IMAGE=ubuntu:24.04 -FROM $IMAGE - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev ca-certificates \ - gcc-arm-none-eabi \ - libnewlib-arm-none-eabi -ENV BUILD_ONLY=1 diff --git a/library/compiler-builtins/etc/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/etc/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile deleted file mode 100644 index c84a31c57a96a..0000000000000 --- a/library/compiler-builtins/etc/libm/ci/docker/x86_64-unknown-linux-gnu/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM ubuntu:24.04 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc m4 make libc6-dev ca-certificates From 9b8065decbddabf399a7d9c73928967c044115f7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 23:34:41 +0000 Subject: [PATCH 1843/4206] Combine the libm .gitignore --- library/compiler-builtins/.gitignore | 13 ++++++++++++- library/compiler-builtins/etc/libm/.gitignore | 11 ----------- 2 files changed, 12 insertions(+), 12 deletions(-) delete mode 100644 library/compiler-builtins/etc/libm/.gitignore diff --git a/library/compiler-builtins/.gitignore b/library/compiler-builtins/.gitignore index 97df30ffaa85e..5287a6c72be41 100644 --- a/library/compiler-builtins/.gitignore +++ b/library/compiler-builtins/.gitignore @@ -1,5 +1,16 @@ -*.rs.bk +# Rust files Cargo.lock target + +# Sources for external files compiler-rt *.tar.gz + +# Benchmark cache +baseline-* +iai-home + +# Temporary files +*.bk +*.rs.bk +.#* diff --git a/library/compiler-builtins/etc/libm/.gitignore b/library/compiler-builtins/etc/libm/.gitignore deleted file mode 100644 index d5caba1a0f33d..0000000000000 --- a/library/compiler-builtins/etc/libm/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -**.bk -.#* -/bin -/math/src -target -Cargo.lock -**.tar.gz - -# Benchmark cache -iai-home -baseline-* From c35cccd6764838330fb12320a33740e15ec8bb35 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 19 Apr 2025 23:35:50 +0000 Subject: [PATCH 1844/4206] Move the libm .editorconfig to root --- library/compiler-builtins/{etc/libm => }/.editorconfig | 5 ----- 1 file changed, 5 deletions(-) rename library/compiler-builtins/{etc/libm => }/.editorconfig (73%) diff --git a/library/compiler-builtins/etc/libm/.editorconfig b/library/compiler-builtins/.editorconfig similarity index 73% rename from library/compiler-builtins/etc/libm/.editorconfig rename to library/compiler-builtins/.editorconfig index ec6e107d547f0..f0735cedfbd6b 100644 --- a/library/compiler-builtins/etc/libm/.editorconfig +++ b/library/compiler-builtins/.editorconfig @@ -12,10 +12,5 @@ insert_final_newline = true indent_style = space indent_size = 4 -[*.md] -# double whitespace at end of line -# denotes a line break in Markdown -trim_trailing_whitespace = false - [*.yml] indent_size = 2 From a48de6950ce784299dd06fc71c015ed48c09a95f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 01:18:08 +0000 Subject: [PATCH 1845/4206] Move builtins-test-intrinsics out of the workspace This crate doesn't need to be a default member since it requires the opposite settings from everything else. Exclude it from the workspace and run it only when explicitly requested. This also makes `cargo t --no-default-features` work without additional qualifiers. `--no-default-features` still needs to be passed to ensure `#![compiler_builtins]` does not get set. compiler-builtins needs doctests disabled in order for everything to work correctly, since this causes an error running rustdoc that is unrelated to features (our `compiler_builtins` is getting into the crate graph before that from the sysroot, but `#![compiler_builtins]` is not set). We can also remove `test = false` and `doctest = false` in `builtins-test` since these no longer cause issues. This is unlikely to be used but it is better to not quietly skip if anything ever gets added by accident. --- library/compiler-builtins/Cargo.toml | 11 +++++++---- .../builtins-test-intrinsics/Cargo.toml | 8 +++++++- library/compiler-builtins/builtins-test/Cargo.toml | 4 ---- library/compiler-builtins/ci/run-docker.sh | 9 ++++++--- library/compiler-builtins/ci/run.sh | 10 +++++----- .../compiler-builtins/compiler-builtins/Cargo.toml | 3 ++- 6 files changed, 27 insertions(+), 18 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 155fb00b195ec..feaeb97915b54 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,11 +1,7 @@ [workspace] resolver = "3" members = [ - # Note that builtins-test-intrinsics cannot be a default member because it - # needs the `mangled-names` feature disabled, while `builtins-test` needs - # it enabled. "builtins-test", - "builtins-test-intrinsics", "compiler-builtins", "crates/libm-macros", "libm", @@ -24,6 +20,13 @@ default-members = [ "libm", ] +exclude = [ + # `builtins-test-intrinsics` needs the feature `compiler-builtins` enabled + # and `mangled-names` disabled, 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", +] + [profile.release] panic = "abort" diff --git a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml index 9dbd3c32f969f..6d88cbec90d3b 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml +++ b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml @@ -6,7 +6,13 @@ publish = false [dependencies] compiler_builtins = { path = "../compiler-builtins", features = ["compiler-builtins"]} -panic-handler = { path = '../crates/panic-handler' } +panic-handler = { path = "../crates/panic-handler" } [features] c = ["compiler_builtins/c"] + +[profile.release] +panic = "abort" + +[profile.dev] +panic = "abort" diff --git a/library/compiler-builtins/builtins-test/Cargo.toml b/library/compiler-builtins/builtins-test/Cargo.toml index 526e9b18af08b..18185d8fe40f0 100644 --- a/library/compiler-builtins/builtins-test/Cargo.toml +++ b/library/compiler-builtins/builtins-test/Cargo.toml @@ -5,10 +5,6 @@ authors = ["Alex Crichton "] edition = "2024" publish = false -[lib] -test = false -doctest = false - [dependencies] # 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/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 2c27ab7955b3f..d07e7784c9a3b 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -19,9 +19,11 @@ run() { echo "target is emulated" fi - # This directory needs to exist before calling docker, otherwise docker will create it but it - # will be owned by root + # Directories and files that do not yet exist need to be created before + # calling docker, otherwise docker will create them but they will be owned + # by root. mkdir -p target + cargo generate-lockfile --manifest-path builtins-test-intrinsics/Cargo.toml run_cmd="HOME=/tmp" @@ -53,7 +55,8 @@ run() { # Use rustc provided by a docker image docker volume create compiler-builtins-cache build_args=( - "--build-arg" "IMAGE=${DOCKER_BASE_IMAGE:-rustlang/rust:nightly}" + "--build-arg" + "IMAGE=${DOCKER_BASE_IMAGE:-rustlang/rust:nightly}" ) run_args=(-v "compiler-builtins-cache:/builtins-target") run_cmd="$run_cmd HOME=/tmp" "USING_CONTAINER_RUSTC=1" diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 49cc1628652cc..96a6e92a9b906 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -122,7 +122,9 @@ done rm -f "${rlib_paths[@]}" build_intrinsics_test() { - cargo build --target "$target" -v --package builtins-test-intrinsics "$@" + cargo build \ + --target "$target" --verbose \ + --manifest-path builtins-test-intrinsics/Cargo.toml "$@" } # Verify that we haven't dropped any intrinsics/symbols @@ -133,10 +135,8 @@ build_intrinsics_test --features c --release # Verify that there are no undefined symbols to `panic` within our # implementations -CARGO_PROFILE_DEV_LTO=true \ - cargo build --target "$target" --package builtins-test-intrinsics -CARGO_PROFILE_RELEASE_LTO=true \ - cargo build --target "$target" --package builtins-test-intrinsics --release +CARGO_PROFILE_DEV_LTO=true build_intrinsics_test +CARGO_PROFILE_RELEASE_LTO=true build_intrinsics_test --release # Ensure no references to any symbols from core update_rlib_paths diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index 3151546ab8dc4..c9503bbce8eb2 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -25,8 +25,9 @@ include = [ links = 'compiler-rt' [lib] -test = false bench = false +doctest = false +test = false [dependencies] # For more information on this dependency see From 141c7b06c416e123ec4c6785c104785987cbe894 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 03:02:47 +0000 Subject: [PATCH 1846/4206] Add remaining `libm` crates to the workspace These are still not yet covered in CI since we always name explicit packages there, but all crates are now part of the workspace. --- library/compiler-builtins/Cargo.toml | 10 ++++------ library/compiler-builtins/ci/run.sh | 16 ++++++++-------- .../libm-test/tests/check_coverage.rs | 4 ++-- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index feaeb97915b54..194a2cdc2f77a 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -4,20 +4,18 @@ members = [ "builtins-test", "compiler-builtins", "crates/libm-macros", + "crates/musl-math-sys", + "crates/util", "libm", - # FIXME(libm): disabled until tests work in CI - # "libm-test", - # "crates/musl-math-sys", - # "crates/util", + "libm-test", ] default-members = [ "builtins-test", "compiler-builtins", "crates/libm-macros", - # FIXME(libm): disabled until tests work in CI - # "crates/libm-test" "libm", + "libm-test", ] exclude = [ diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 96a6e92a9b906..bce90d48d503b 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -58,14 +58,14 @@ update_rlib_paths() { update_rlib_paths rm -f "${rlib_paths[@]}" -cargo build --target "$target" -cargo build --target "$target" --release -cargo build --target "$target" --features c -cargo build --target "$target" --release --features c -cargo build --target "$target" --features no-asm -cargo build --target "$target" --release --features no-asm -cargo build --target "$target" --features no-f16-f128 -cargo build --target "$target" --release --features no-f16-f128 +cargo build -p compiler_builtins --target "$target" +cargo build -p compiler_builtins --target "$target" --release +cargo build -p compiler_builtins --target "$target" --features c +cargo build -p compiler_builtins --target "$target" --release --features c +cargo build -p compiler_builtins --target "$target" --features no-asm +cargo build -p compiler_builtins --target "$target" --release --features no-asm +cargo build -p compiler_builtins --target "$target" --features no-f16-f128 +cargo build -p compiler_builtins --target "$target" --release --features no-f16-f128 PREFIX=${target//unknown-/}- case "$target" in diff --git a/library/compiler-builtins/libm-test/tests/check_coverage.rs b/library/compiler-builtins/libm-test/tests/check_coverage.rs index c23298686fac3..3b445a3de9da1 100644 --- a/library/compiler-builtins/libm-test/tests/check_coverage.rs +++ b/library/compiler-builtins/libm-test/tests/check_coverage.rs @@ -19,7 +19,7 @@ macro_rules! callback { #[test] fn test_for_each_function_all_included() { - let all_functions: HashSet<_> = include_str!("../../../etc/function-list.txt") + let all_functions: HashSet<_> = include_str!("../../etc/function-list.txt") .lines() .filter(|line| !line.starts_with("#")) .collect(); @@ -52,7 +52,7 @@ fn ensure_list_updated() { } let res = Command::new("python3") - .arg(Path::new(env!("CARGO_MANIFEST_DIR")).join("../../etc/update-api-list.py")) + .arg(Path::new(env!("CARGO_MANIFEST_DIR")).join("../etc/update-api-list.py")) .arg("--check") .status() .unwrap(); From 0d0d3172424cfc4386976d35fc1ce7710a07d1eb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 03:28:17 +0000 Subject: [PATCH 1847/4206] Enable icount benchmarks in CI --- .../.github/workflows/main.yaml | 55 ++++++++++++++++++- .../{etc/libm => }/ci/bench-icount.sh | 0 .../{etc/libm => }/ci/ci-util.py | 0 .../compiler-builtins/Cargo.toml | 3 +- 4 files changed, 55 insertions(+), 3 deletions(-) rename library/compiler-builtins/{etc/libm => }/ci/bench-icount.sh (100%) rename library/compiler-builtins/{etc/libm => }/ci/ci-util.py (100%) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index eec747a243638..54cfd506e83d3 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -13,6 +13,7 @@ env: RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings RUST_BACKTRACE: full + BENCHMARK_RUSTC: nightly-2025-01-16 # Pin the toolchain for reproducable results jobs: test: @@ -161,6 +162,55 @@ jobs: - uses: Swatinem/rust-cache@v2 - run: cargo clippy -- -D clippy::all + benchmarks: + name: Benchmarks + runs-on: ubuntu-24.04 + timeout-minutes: 20 + steps: + - uses: actions/checkout@master + with: + submodules: true + - uses: taiki-e/install-action@cargo-binstall + + - name: Set up dependencies + run: | + sudo apt-get update + sudo apt-get install -y valgrind gdb libc6-dbg # Needed for iai-callgrind + rustup update "$BENCHMARK_RUSTC" --no-self-update + rustup default "$BENCHMARK_RUSTC" + # Install the version of iai-callgrind-runner that is specified in Cargo.toml + iai_version="$(cargo metadata --format-version=1 --features icount | + jq -r '.packages[] | select(.name == "iai-callgrind").version')" + cargo binstall -y iai-callgrind-runner --version "$iai_version" + sudo apt-get install valgrind + - uses: Swatinem/rust-cache@v2 + + - name: Run icount benchmarks + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + run: ./ci/bench-icount.sh + + - name: Upload the benchmark baseline + uses: actions/upload-artifact@v4 + with: + name: ${{ env.BASELINE_NAME }} + path: ${{ env.BASELINE_NAME }}.tar.xz + + - name: Run wall time benchmarks + run: | + # Always use the same seed for benchmarks. Ideally we should switch to a + # non-random generator. + export LIBM_SEED=benchesbenchesbenchesbencheswoo! + cargo bench --package libm-test \ + --no-default-features \ + --features short-benchmarks,build-musl,libm/force-soft-floats + + - name: Print test logs if available + if: always() + run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi + shell: bash + miri: name: Miri runs-on: ubuntu-24.04 @@ -189,10 +239,11 @@ jobs: success: needs: - - test - - rustfmt + - benchmarks - clippy - miri + - rustfmt + - test runs-on: ubuntu-24.04 # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency # failed" as success. So we have to do some contortions to ensure the job fails if any of its diff --git a/library/compiler-builtins/etc/libm/ci/bench-icount.sh b/library/compiler-builtins/ci/bench-icount.sh similarity index 100% rename from library/compiler-builtins/etc/libm/ci/bench-icount.sh rename to library/compiler-builtins/ci/bench-icount.sh diff --git a/library/compiler-builtins/etc/libm/ci/ci-util.py b/library/compiler-builtins/ci/ci-util.py similarity index 100% rename from library/compiler-builtins/etc/libm/ci/ci-util.py rename to library/compiler-builtins/ci/ci-util.py diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index c9503bbce8eb2..a014baf040abf 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -73,4 +73,5 @@ rustc-dep-of-std = ['compiler-builtins', 'core'] public-test-deps = [] [lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(bootstrap)'] } +# The cygwin config can be dropped after our benchmark toolchain is bumped +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(bootstrap)', 'cfg(target_os, values("cygwin"))'] } From d02b25fd6e6c8da41f0248333df93a03dc53fec1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 04:48:51 +0000 Subject: [PATCH 1848/4206] Fix the libm-test logfile path This was broken since the crate's location relative to the target directory had changed. --- library/compiler-builtins/libm-test/src/lib.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm-test/src/lib.rs b/library/compiler-builtins/libm-test/src/lib.rs index 730318abcbae7..accb39654d15a 100644 --- a/library/compiler-builtins/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm-test/src/lib.rs @@ -71,12 +71,7 @@ pub fn test_log(s: &str) { return None; }; - PathBuf::from(x) - .parent() - .unwrap() - .parent() - .unwrap() - .join("target") + PathBuf::from(x).join("../target") } }; let outfile = target_dir.join("test-log.txt"); From 9919218493c37d3f7a987f7a6c6e3fceba63c40a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 06:10:45 +0000 Subject: [PATCH 1849/4206] ci: Add a libm MSRV check Add the job from rust-lang/libm --- .../.github/workflows/main.yaml | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 54cfd506e83d3..7ef0074deb2c0 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -226,6 +226,26 @@ jobs: - uses: Swatinem/rust-cache@v2 - run: ./ci/miri.sh + msrv: + name: Check libm MSRV + runs-on: ubuntu-24.04 + timeout-minutes: 10 + env: + RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings` + steps: + - uses: actions/checkout@master + - 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 + - run: | + # FIXME(msrv): Remove the workspace Cargo.toml so 1.63 cargo doesn't see + # `edition = "2024"` and get spooked. + rm Cargo.toml + cargo build --manifest-path libm/Cargo.toml + rustfmt: name: Rustfmt runs-on: ubuntu-24.04 @@ -242,6 +262,7 @@ jobs: - benchmarks - clippy - miri + - msrv - rustfmt - test runs-on: ubuntu-24.04 From d0e0134dc56b764a4f8f0a4971f737e2fbbbef21 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 06:21:44 +0000 Subject: [PATCH 1850/4206] ci: Add extensive tests from rust-lang/libm --- .../.github/workflows/main.yaml | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 7ef0074deb2c0..8f8ac033a1340 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -257,10 +257,78 @@ jobs: run: rustup set profile minimal && rustup default stable && rustup component add rustfmt - run: cargo fmt -- --check + # Determine which extensive tests should be run based on changed files. + calculate_extensive_matrix: + name: Calculate job matrix + runs-on: ubuntu-24.04 + timeout-minutes: 10 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + outputs: + matrix: ${{ steps.script.outputs.matrix }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 100 + - name: Fetch pull request ref + run: git fetch origin "$GITHUB_REF:$GITHUB_REF" + if: github.event_name == 'pull_request' + - run: python3 ci/ci-util.py generate-matrix >> "$GITHUB_OUTPUT" + id: script + + extensive: + name: Extensive tests for ${{ matrix.ty }} + needs: + # Wait on `clippy` so we have some confidence that the crate will build + - clippy + - calculate_extensive_matrix + runs-on: ubuntu-24.04 + timeout-minutes: 240 # 4 hours + strategy: + matrix: + # Use the output from `calculate_extensive_matrix` to calculate the matrix + # FIXME: it would be better to run all jobs (i.e. all types) but mark those that + # didn't change as skipped, rather than completely excluding the job. However, + # this is not currently possible https://github.com/actions/runner/issues/1985. + include: ${{ fromJSON(needs.calculate_extensive_matrix.outputs.matrix).matrix }} + env: + TO_TEST: ${{ matrix.to_test }} + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - name: Install Rust + run: | + rustup update nightly --no-self-update + rustup default nightly + - uses: Swatinem/rust-cache@v2 + - name: Run extensive tests + run: | + echo "Tests to run: '$TO_TEST'" + if [ -z "$TO_TEST" ]; then + echo "No tests to run, exiting." + exit + fi + + set -x + + # Run the non-extensive tests first to catch any easy failures + cargo t --profile release-checked -- "$TO_TEST" + + LIBM_EXTENSIVE_TESTS="$TO_TEST" cargo test \ + --features build-mpfr,unstable,force-soft-floats \ + --profile release-checked \ + -- extensive + - name: Print test logs if available + run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi + shell: bash + success: needs: - benchmarks - clippy + - extensive - miri - msrv - rustfmt From 9c96f245b8e7b40d46653dcc77970a8308c3b012 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 04:40:12 +0000 Subject: [PATCH 1851/4206] ci: Enable testing of `libm` crates Update `run.sh` to start testing `libm`. Currently this is somewhat inefficient because `builtins-test` gets run more than once on some targets; this can be cleaned up later. --- .../.github/workflows/main.yaml | 12 +- library/compiler-builtins/Cargo.toml | 35 ++-- library/compiler-builtins/ci/run.sh | 167 +++++++++++++++--- .../etc/libm/ci/run-docker.sh | 56 ------ library/compiler-builtins/etc/libm/ci/run.sh | 130 -------------- .../compiler-builtins/libm-test/Cargo.toml | 3 + 6 files changed, 176 insertions(+), 227 deletions(-) delete mode 100755 library/compiler-builtins/etc/libm/ci/run-docker.sh delete mode 100755 library/compiler-builtins/etc/libm/ci/run.sh diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 8f8ac033a1340..95ed6a855f3e9 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -97,6 +97,7 @@ jobs: rustup default "$channel" rustup target add "${{ matrix.target }}" rustup component add llvm-tools-preview + - uses: taiki-e/install-action@nextest - uses: Swatinem/rust-cache@v2 with: key: ${{ matrix.target }} @@ -107,7 +108,7 @@ jobs: path: /tmp/.buildx-cache key: ${{ matrix.target }}-buildx-${{ github.sha }} restore-keys: ${{ matrix.target }}-buildx- - + - name: Cache compiler-rt id: cache-compiler-rt uses: actions/cache@v4 @@ -121,6 +122,10 @@ jobs: - run: echo "RUST_COMPILER_RT_ROOT=$(realpath ./compiler-rt)" >> "$GITHUB_ENV" shell: bash + - name: Verify API list + if: matrix.os == 'ubuntu-24.04' + run: python3 etc/update-api-list.py --check + # Non-linux tests just use our raw script - name: Run locally if: matrix.os != 'ubuntu-24.04' @@ -136,6 +141,11 @@ jobs: if: matrix.os == 'ubuntu-24.04' run: cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} + - name: Print test logs if available + if: always() + run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi + shell: bash + # Workaround to keep Docker cache smaller # https://github.com/docker/build-push-action/issues/252 # https://github.com/moby/buildkit/issues/1896 diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 194a2cdc2f77a..c3737a042f5ec 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -31,22 +31,19 @@ panic = "abort" [profile.dev] panic = "abort" -# FIXME(libm): these profiles are needed for testing -# # The default release profile is unchanged. - -# # Release mode with debug assertions -# [profile.release-checked] -# inherits = "release" -# debug-assertions = true -# overflow-checks = true - -# # Release with maximum optimizations, which is very slow to build. This is also -# # what is needed to check `no-panic`. -# [profile.release-opt] -# inherits = "release" -# codegen-units = 1 -# lto = "fat" - -# [profile.bench] -# # Required for iai-callgrind -# debug = true +# Release mode with debug assertions +[profile.release-checked] +inherits = "release" +debug-assertions = true +overflow-checks = true + +# Release with maximum optimizations, which is very slow to build. This is also +# what is needed to check `no-panic`. +[profile.release-opt] +inherits = "release" +codegen-units = 1 +lto = "fat" + +[profile.bench] +# Required for iai-callgrind +debug = true diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index bce90d48d503b..730079be78988 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -13,6 +13,11 @@ if [ -z "$target" ]; then target="$host_target" fi +if [[ "$target" = *"wasm"* ]]; then + # Enable the random backend + export RUSTFLAGS="${RUSTFLAGS:-} --cfg getrandom_backend=\"wasm_js\"" +fi + if [ "${USING_CONTAINER_RUSTC:-}" = 1 ]; then # Install nonstandard components if we have control of the environment rustup target list --installed | @@ -22,27 +27,27 @@ fi # Test our implementation if [ "${BUILD_ONLY:-}" = "1" ]; then - echo "nothing to do for no_std" + echo "no tests to run for build-only targets" else - run="cargo test --package builtins-test --no-fail-fast --target $target" - $run - $run --release - $run --features c - $run --features c --release - $run --features no-asm - $run --features no-asm --release - $run --features no-f16-f128 - $run --features no-f16-f128 --release - $run --benches - $run --benches --release -fi + test_builtins=(cargo test --package builtins-test --no-fail-fast --target "$target") + "${test_builtins[@]}" + "${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[@]}" --features no-f16-f128 + "${test_builtins[@]}" --features no-f16-f128 --release + "${test_builtins[@]}" --benches + "${test_builtins[@]}" --benches --release -if [ "${TEST_VERBATIM:-}" = "1" ]; then - verb_path=$(cmd.exe //C echo \\\\?\\%cd%\\builtins-test\\target2) - cargo build --package builtins-test \ - --target "$target" --target-dir "$verb_path" --features c + if [ "${TEST_VERBATIM:-}" = "1" ]; then + verb_path=$(cmd.exe //C echo \\\\?\\%cd%\\builtins-test\\target2) + "${test_builtins[@]}" --target-dir "$verb_path" --features c + fi fi + declare -a rlib_paths # Set the `rlib_paths` global array to a list of all compiler-builtins rlibs @@ -61,11 +66,11 @@ rm -f "${rlib_paths[@]}" cargo build -p compiler_builtins --target "$target" cargo build -p compiler_builtins --target "$target" --release cargo build -p compiler_builtins --target "$target" --features c -cargo build -p compiler_builtins --target "$target" --release --features c +cargo build -p compiler_builtins --target "$target" --features c --release cargo build -p compiler_builtins --target "$target" --features no-asm -cargo build -p compiler_builtins --target "$target" --release --features no-asm +cargo build -p compiler_builtins --target "$target" --features no-asm --release cargo build -p compiler_builtins --target "$target" --features no-f16-f128 -cargo build -p compiler_builtins --target "$target" --release --features no-f16-f128 +cargo build -p compiler_builtins --target "$target" --features no-f16-f128 --release PREFIX=${target//unknown-/}- case "$target" in @@ -167,4 +172,124 @@ for rlib in "${rlib_paths[@]}"; do fi done -true +# Test libm + +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) + +# 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 + # Can't build at all on MSVC, WASM, or thumb + *windows-msvc*) mflags+=(--exclude musl-math-sys) ;; + *wasm*) mflags+=(--exclude musl-math-sys) ;; + *thumb*) mflags+=(--exclude musl-math-sys) ;; + + # We can build musl on MinGW but running tests gets a stack overflow + *windows-gnu*) ;; + # FIXME(#309): LE PPC crashes calling the musl version of some functions. It + # seems like a qemu bug but should be investigated further at some point. + # See . + *powerpc64le*) ;; + + # Everything else gets musl enabled + *) mflags+=(--features libm-test/build-musl) ;; +esac + + +# Configure which targets test against MPFR +case "$target" in + # MSVC cannot link MPFR + *windows-msvc*) ;; + # FIXME: MinGW should be able to build MPFR, but setup in CI is nontrivial. + *windows-gnu*) ;; + # Targets that aren't cross compiled in CI work fine + aarch64*apple*) mflags+=(--features libm-test/build-mpfr) ;; + aarch64*linux*) mflags+=(--features libm-test/build-mpfr) ;; + i586*) mflags+=(--features libm-test/build-mpfr --features gmp-mpfr-sys/force-cross) ;; + i686*) mflags+=(--features libm-test/build-mpfr) ;; + x86_64*) mflags+=(--features libm-test/build-mpfr) ;; +esac + +# FIXME: `STATUS_DLL_NOT_FOUND` testing macros on CI. +# +case "$target" in + *windows-gnu) mflags+=(--exclude libm-macros) ;; +esac + +# Make sure a simple build works +cargo check -p libm --no-default-features --target "$target" + + +if [ "${BUILD_ONLY:-}" = "1" ]; then + # If we are on targets that can't run tests, verify that we can build. + cmd=(cargo build --target "$target" --package libm) + "${cmd[@]}" + "${cmd[@]}" --features unstable-intrinsics + + echo "can't run tests on $target; skipping" +else + mflags+=(--workspace --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 [ -f /.dockerenv ]; 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 + + cmd+=("${mflags[@]}") + profile_flag="--cargo-profile" + fi + + # Test once without intrinsics + "${cmd[@]}" + + # Run doctests if they were excluded by nextest + [ "$nextest" = "1" ] && cargo test --doc --exclude compiler_builtins "${mflags[@]}" + + # 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) + + # Test once with intrinsics enabled + "${cmd[@]}" --features unstable-intrinsics + "${cmd[@]}" --features 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 + + # Ensure that the routines do not panic. + # + # `--tests` must be passed because no-panic is only enabled as a dev + # dependency. The `release-opt` profile must be used to enable LTO and a + # single CGU. + ENSURE_NO_PANIC=1 cargo build \ + -p libm \ + --target "$target" \ + --no-default-features \ + --features unstable-float \ + --tests \ + --profile release-opt +fi diff --git a/library/compiler-builtins/etc/libm/ci/run-docker.sh b/library/compiler-builtins/etc/libm/ci/run-docker.sh deleted file mode 100755 index 6626e72268578..0000000000000 --- a/library/compiler-builtins/etc/libm/ci/run-docker.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash - -# Small script to run tests for a target (or all targets) inside all the -# respective docker images. - -set -euxo pipefail - -host_arch="$(uname -m | sed 's/arm64/aarch64/')" - -run() { - local target=$1 - - echo "testing target: $target" - - target_arch="$(echo "$target" | cut -d'-' -f1)" - - emulated="" - if [ "$target_arch" != "$host_arch" ]; then - emulated=1 - echo "target is emulated" - fi - - # This directory needs to exist before calling docker, otherwise docker will create it but it - # will be owned by root - mkdir -p target - - set_env="HOME=/tmp PATH=\$PATH:/rust/bin:/cargo/bin" - docker build -t "libm-$target" "ci/docker/$target" - docker run \ - --rm \ - --user "$(id -u):$(id -g)" \ - -e CI \ - -e RUSTFLAGS \ - -e CARGO_TERM_COLOR \ - -e CARGO_HOME=/cargo \ - -e CARGO_TARGET_DIR=/target \ - -e "EMULATED=$emulated" \ - -v "${HOME}/.cargo:/cargo" \ - -v "$(pwd)/target:/target" \ - -v "$(pwd):/checkout:ro" \ - -v "$(rustc --print sysroot):/rust:ro" \ - --init \ - -w /checkout \ - "libm-$target" \ - sh -c "$set_env exec ci/run.sh $target" -} - -if [ -z "$1" ]; then - echo "running tests for all targets" - - for d in ci/docker/*; do - run $d - done -else - run $1 -fi diff --git a/library/compiler-builtins/etc/libm/ci/run.sh b/library/compiler-builtins/etc/libm/ci/run.sh deleted file mode 100755 index a946d325ebd41..0000000000000 --- a/library/compiler-builtins/etc/libm/ci/run.sh +++ /dev/null @@ -1,130 +0,0 @@ -#!/bin/sh - -set -eux - -export RUST_BACKTRACE="${RUST_BACKTRACE:-full}" -export NEXTEST_STATUS_LEVEL=all - -target="${1:-}" -flags="" - -if [ -z "$target" ]; then - host_target=$(rustc -vV | awk '/^host/ { print $2 }') - echo "Defaulted to host target $host_target" - target="$host_target" -fi - -# We enumerate features manually. -flags="$flags --no-default-features" - -# Enable arch-specific routines when available. -flags="$flags --features arch" - -# Always enable `unstable-float` since it expands available API but does not -# change any implementations. -flags="$flags --features unstable-float" - -# 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 - # Can't build at all on MSVC, WASM, or thumb - *windows-msvc*) flags="$flags --exclude musl-math-sys" ;; - *wasm*) flags="$flags --exclude musl-math-sys" ;; - *thumb*) flags="$flags --exclude musl-math-sys" ;; - - # We can build musl on MinGW but running tests gets a stack overflow - *windows-gnu*) ;; - # FIXME(#309): LE PPC crashes calling the musl version of some functions. It - # seems like a qemu bug but should be investigated further at some point. - # See . - *powerpc64le*) ;; - - # Everything else gets musl enabled - *) flags="$flags --features libm-test/build-musl" ;; -esac - -# Configure which targets test against MPFR -case "$target" in - # MSVC cannot link MPFR - *windows-msvc*) ;; - # FIXME: MinGW should be able to build MPFR, but setup in CI is nontrivial. - *windows-gnu*) ;; - # Targets that aren't cross compiled in CI work fine - aarch64*apple*) flags="$flags --features libm-test/build-mpfr" ;; - aarch64*linux*) flags="$flags --features libm-test/build-mpfr" ;; - i586*) flags="$flags --features libm-test/build-mpfr --features gmp-mpfr-sys/force-cross" ;; - i686*) flags="$flags --features libm-test/build-mpfr" ;; - x86_64*) flags="$flags --features libm-test/build-mpfr" ;; -esac - -# FIXME: `STATUS_DLL_NOT_FOUND` testing macros on CI. -# -case "$target" in - *windows-gnu) flags="$flags --exclude libm-macros" ;; -esac - -# Make sure we can build with overriding features. -cargo check -p libm --no-default-features - -if [ "${BUILD_ONLY:-}" = "1" ]; then - # If we are on targets that can't run tests, verify that we can build. - cmd="cargo build --target $target --package libm" - $cmd - $cmd --features unstable-intrinsics - - echo "can't run tests on $target; skipping" - exit -fi - -flags="$flags --all --target $target" -cmd="cargo test $flags" -profile="--profile" - -# If nextest is available, use that -command -v cargo-nextest && nextest=1 || nextest=0 -if [ "$nextest" = "1" ]; then - # Workaround for https://github.com/nextest-rs/nextest/issues/2066 - if [ -f /.dockerenv ]; then - cfg_file="/tmp/nextest-config.toml" - echo "[store]" >> "$cfg_file" - echo "dir = \"$CARGO_TARGET_DIR/nextest\"" >> "$cfg_file" - cfg_flag="--config-file $cfg_file" - fi - - cmd="cargo nextest run ${cfg_flag:-} --max-fail=10 $flags" - profile="--cargo-profile" -fi - -# Test once without intrinsics -$cmd - -# Run doctests if they were excluded by nextest -[ "$nextest" = "1" ] && cargo test --doc $flags - -# 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="$cmd --exclude util --exclude libm-macros" - -# Test once with intrinsics enabled -$cmd --features unstable-intrinsics -$cmd --features unstable-intrinsics --benches - -# Test the same in release mode, which also increases coverage. Also ensure -# the soft float routines are checked. -$cmd "$profile" release-checked -$cmd "$profile" release-checked --features force-soft-floats -$cmd "$profile" release-checked --features unstable-intrinsics -$cmd "$profile" release-checked --features unstable-intrinsics --benches - -# Ensure that the routines do not panic. -# -# `--tests` must be passed because no-panic is only enabled as a dev -# dependency. The `release-opt` profile must be used to enable LTO and a -# single CGU. -ENSURE_NO_PANIC=1 cargo build \ - -p libm \ - --target "$target" \ - --no-default-features \ - --features unstable-float \ - --tests \ - --profile release-opt diff --git a/library/compiler-builtins/libm-test/Cargo.toml b/library/compiler-builtins/libm-test/Cargo.toml index c9b3b79583723..6fd49774e0c34 100644 --- a/library/compiler-builtins/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm-test/Cargo.toml @@ -41,6 +41,9 @@ rand_chacha = "0.9.0" rayon = "1.10.0" rug = { version = "1.27.0", optional = true, default-features = false, features = ["float", "integer", "std"] } +[target.'cfg(target_family = "wasm")'.dependencies] +getrandom = { version = "0.3.2", features = ["wasm_js"] } + [build-dependencies] rand = { version = "0.9.0", optional = true } From 22f44df8bdf6588236ab7523bb3e35b08df5f750 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 05:37:08 +0000 Subject: [PATCH 1852/4206] Set the musl submodule to 61399d4b ("loongarch64: add TLSDESC support") Set the submodule to the same version we had been using in rust-lang/libm. This is a downgrade from the current version but it avoids some new deviations that show up, which can be corrected later. --- library/compiler-builtins/crates/musl-math-sys/musl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/crates/musl-math-sys/musl b/library/compiler-builtins/crates/musl-math-sys/musl index 0784374d56143..61399d4bd02ae 160000 --- a/library/compiler-builtins/crates/musl-math-sys/musl +++ b/library/compiler-builtins/crates/musl-math-sys/musl @@ -1 +1 @@ -Subproject commit 0784374d561435f7c787a555aeab8ede699ed298 +Subproject commit 61399d4bd02ae1ec03068445aa7ffe9174466bfd From a829d916b5555a5ef65d521e98488f32b5476d36 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 07:26:43 +0000 Subject: [PATCH 1853/4206] ci: Add `/cargo/bin` to the path in Docker This makes it possible to use nextest within the container. --- library/compiler-builtins/ci/run-docker.sh | 2 +- library/compiler-builtins/ci/run.sh | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index d07e7784c9a3b..c4d3af55ddced 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -50,7 +50,7 @@ run() { -v "$(pwd)/target:/builtins-target" -v "$(rustc --print sysroot):/rust:ro" ) - run_cmd="$run_cmd PATH=\$PATH:/rust/bin" + run_cmd="$run_cmd PATH=\$PATH:/rust/bin:/cargo/bin" else # Use rustc provided by a docker image docker volume create compiler-builtins-cache diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 730079be78988..0ad99da19f0db 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -229,7 +229,6 @@ esac # Make sure a simple build works cargo check -p libm --no-default-features --target "$target" - if [ "${BUILD_ONLY:-}" = "1" ]; then # If we are on targets that can't run tests, verify that we can build. cmd=(cargo build --target "$target" --package libm) @@ -255,6 +254,9 @@ else 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 From 8902f740da9566061c5b23000899e7908921370b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 07:05:32 +0000 Subject: [PATCH 1854/4206] ci: Skip testing libm in PRs if it did not change Many contributions to compiler-builtins don't have any need to touch libm, and could get by with the few minutes of CI for compiler-builtins rather than the ~30 minutes for libm. We already have some scripts that handle changed file detection, so expand its use to skip libm CI if it doesn't need to run. --- .../.github/workflows/main.yaml | 49 ++++++++++--------- library/compiler-builtins/ci/ci-util.py | 42 +++++++++++----- library/compiler-builtins/ci/run-docker.sh | 1 + library/compiler-builtins/ci/run.sh | 11 +++-- 4 files changed, 66 insertions(+), 37 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 95ed6a855f3e9..690cdc89b1c31 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -16,6 +16,27 @@ env: BENCHMARK_RUSTC: nightly-2025-01-16 # Pin the toolchain for reproducable results jobs: + # Determine which tests should be run based on changed files. + calculate_vars: + name: Calculate workflow variables + runs-on: ubuntu-24.04 + timeout-minutes: 10 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + outputs: + extensive_matrix: ${{ steps.script.outputs.extensive_matrix }} + may_skip_libm_ci: ${{ steps.script.outputs.may_skip_libm_ci }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 500 + - name: Fetch pull request ref + run: git fetch origin "$GITHUB_REF:$GITHUB_REF" + if: github.event_name == 'pull_request' + - run: python3 ci/ci-util.py generate-matrix >> "$GITHUB_OUTPUT" + id: script + test: name: Build and test timeout-minutes: 60 @@ -78,9 +99,11 @@ jobs: os: windows-2025 channel: nightly-x86_64-gnu runs-on: ${{ matrix.os }} + needs: [calculate_vars] env: BUILD_ONLY: ${{ matrix.build_only }} TEST_VERBATIM: ${{ matrix.test_verbatim }} + MAY_SKIP_LIBM_CI: ${{ needs.calculate_vars.outputs.may_skip_libm_ci }} steps: - name: Print runner information run: uname -a @@ -267,41 +290,21 @@ jobs: run: rustup set profile minimal && rustup default stable && rustup component add rustfmt - run: cargo fmt -- --check - # Determine which extensive tests should be run based on changed files. - calculate_extensive_matrix: - name: Calculate job matrix - runs-on: ubuntu-24.04 - timeout-minutes: 10 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_NUMBER: ${{ github.event.pull_request.number }} - outputs: - matrix: ${{ steps.script.outputs.matrix }} - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 100 - - name: Fetch pull request ref - run: git fetch origin "$GITHUB_REF:$GITHUB_REF" - if: github.event_name == 'pull_request' - - run: python3 ci/ci-util.py generate-matrix >> "$GITHUB_OUTPUT" - id: script - extensive: name: Extensive tests for ${{ matrix.ty }} needs: # Wait on `clippy` so we have some confidence that the crate will build - clippy - - calculate_extensive_matrix + - calculate_vars runs-on: ubuntu-24.04 timeout-minutes: 240 # 4 hours strategy: matrix: - # Use the output from `calculate_extensive_matrix` to calculate the matrix + # Use the output from `calculate_vars` to create the matrix # FIXME: it would be better to run all jobs (i.e. all types) but mark those that # didn't change as skipped, rather than completely excluding the job. However, # this is not currently possible https://github.com/actions/runner/issues/1985. - include: ${{ fromJSON(needs.calculate_extensive_matrix.outputs.matrix).matrix }} + include: ${{ fromJSON(needs.calculate_vars.outputs.extensive_matrix).extensive_matrix }} env: TO_TEST: ${{ matrix.to_test }} steps: diff --git a/library/compiler-builtins/ci/ci-util.py b/library/compiler-builtins/ci/ci-util.py index d9e402d6bd711..7486d6b418638 100755 --- a/library/compiler-builtins/ci/ci-util.py +++ b/library/compiler-builtins/ci/ci-util.py @@ -7,6 +7,7 @@ import json import os +import re import subprocess as sp import sys from dataclasses import dataclass @@ -68,6 +69,10 @@ "libm/src/math/arch/intrinsics.rs", ] +# libm PR CI takes a long time and doesn't need to run unless relevant files have been +# changed. Anything matching this regex pattern will trigger a run. +TRIGGER_LIBM_PR_CI = ".*(libm|musl).*" + TYPES = ["f16", "f32", "f64", "f128"] @@ -116,7 +121,6 @@ class FunctionDef(TypedDict): type: str -@dataclass class Context: gh_ref: str | None changed: list[Path] @@ -142,7 +146,7 @@ def _init_change_list(self): # the PR number), and sets this as `GITHUB_REF`. ref = self.gh_ref eprint(f"using ref `{ref}`") - if ref is None or "merge" not in ref: + if not self.is_pr(): # If the ref is not for `merge` then we are not in PR CI eprint("No diff available for ref") return @@ -170,6 +174,10 @@ def _init_change_list(self): ) self.changed = [Path(p) for p in textlist.splitlines()] + def is_pr(self) -> bool: + """Check if we are looking at a PR rather than a push.""" + return self.gh_ref is not None and "merge" in self.gh_ref + @staticmethod def _ignore_file(fname: str) -> bool: return any(fname.startswith(pfx) for pfx in IGNORE_FILES) @@ -196,7 +204,16 @@ def changed_routines(self) -> dict[str, list[str]]: return ret - def make_workflow_output(self) -> str: + def may_skip_libm_ci(self) -> bool: + """If this is a PR and no libm files were changed, allow skipping libm + jobs.""" + + if self.is_pr(): + return all(not re.match(TRIGGER_LIBM_PR_CI, str(f)) for f in self.changed) + + return False + + def emit_workflow_output(self): """Create a JSON object a list items for each type's changed files, if any did change, and the routines that were affected by the change. """ @@ -216,9 +233,10 @@ def make_workflow_output(self) -> str: eprint("Skipping all extensive tests") changed = self.changed_routines() - ret = [] + matrix = [] total_to_test = 0 + # Figure out which extensive tests need to run for ty in TYPES: ty_changed = changed.get(ty, []) ty_to_test = [] if skip_tests else ty_changed @@ -230,9 +248,14 @@ def make_workflow_output(self) -> str: "to_test": ",".join(ty_to_test), } - ret.append(item) - output = json.dumps({"matrix": ret}, separators=(",", ":")) - eprint(f"output: {output}") + matrix.append(item) + + ext_matrix = json.dumps({"extensive_matrix": matrix}, separators=(",", ":")) + may_skip = str(self.may_skip_libm_ci()).lower() + print(f"extensive_matrix={ext_matrix}") + print(f"may_skip_libm_ci={may_skip}") + eprint(f"extensive_matrix={ext_matrix}") + eprint(f"may_skip_libm_ci={may_skip}") eprint(f"total extensive tests: {total_to_test}") if error_on_many_tests and total_to_test > MANY_EXTENSIVE_THRESHOLD: @@ -242,8 +265,6 @@ def make_workflow_output(self) -> str: ) exit(1) - return output - def locate_baseline(flags: list[str]) -> None: """Find the most recent baseline from CI, download it if specified. @@ -398,8 +419,7 @@ def main(): match sys.argv[1:]: case ["generate-matrix"]: ctx = Context() - output = ctx.make_workflow_output() - print(f"matrix={output}") + ctx.emit_workflow_output() case ["locate-baseline", *flags]: locate_baseline(flags) case ["check-regressions", *args]: diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index c4d3af55ddced..58838fadf3cda 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -77,6 +77,7 @@ run() { -e CI \ -e CARGO_TARGET_DIR=/builtins-target \ -e CARGO_TERM_COLOR \ + -e MAY_SKIP_LIBM_CI \ -e RUSTFLAGS \ -e RUST_BACKTRACE \ -e RUST_COMPILER_RT_ROOT \ diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 0ad99da19f0db..68d13c130bcce 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -174,6 +174,14 @@ done # Test libm +# Make sure a simple build works +cargo check -p libm --no-default-features --target "$target" + +if [ "${MAY_SKIP_LIBM_CI:-}" = "true" ]; then + echo "skipping libm PR CI" + exit +fi + mflags=() # We enumerate features manually. @@ -226,9 +234,6 @@ case "$target" in *windows-gnu) mflags+=(--exclude libm-macros) ;; esac -# Make sure a simple build works -cargo check -p libm --no-default-features --target "$target" - if [ "${BUILD_ONLY:-}" = "1" ]; then # If we are on targets that can't run tests, verify that we can build. cmd=(cargo build --target "$target" --package libm) From ee431374eb639598c93753f94125d87b47ed20ae Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 08:26:08 +0000 Subject: [PATCH 1855/4206] ci: Add a timeout for all jobs --- library/compiler-builtins/.github/workflows/main.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 690cdc89b1c31..2b57d7eb3aae8 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -247,6 +247,7 @@ jobs: miri: name: Miri runs-on: ubuntu-24.04 + timeout-minutes: 10 steps: - uses: actions/checkout@v4 with: @@ -282,6 +283,7 @@ jobs: rustfmt: name: Rustfmt runs-on: ubuntu-24.04 + timeout-minutes: 10 steps: - uses: actions/checkout@v4 with: @@ -347,6 +349,7 @@ jobs: - rustfmt - test runs-on: ubuntu-24.04 + timeout-minutes: 10 # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency # failed" as success. So we have to do some contortions to ensure the job fails if any of its # dependencies fails. From 38c55452445fbf9b3abaf7023273e3318e4bd64b Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Sun, 20 Apr 2025 02:13:34 -0700 Subject: [PATCH 1856/4206] Stabilize <[T; N]>::as_mut_slice as const --- library/core/src/array/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index efa7bed7c8e17..0e1806c1ba9dd 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -587,7 +587,7 @@ impl [T; N] { /// Returns a mutable slice containing the entire array. Equivalent to /// `&mut s[..]`. #[stable(feature = "array_as_slice", since = "1.57.0")] - #[rustc_const_unstable(feature = "const_array_as_mut_slice", issue = "133333")] + #[rustc_const_stable(feature = "const_array_as_mut_slice", since = "CURRENT_RUSTC_VERSION")] pub const fn as_mut_slice(&mut self) -> &mut [T] { self } From 88ddf9e203291d085c9fa8bf8b3c574e7f41e174 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 18 Dec 2024 22:05:27 +0100 Subject: [PATCH 1857/4206] stabilize `naked_functions` --- example/mini_core_hello_world.rs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index 0b3a7281d5a06..93ca2e0e42188 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -1,13 +1,4 @@ -#![feature( - no_core, - lang_items, - never_type, - linkage, - extern_types, - naked_functions, - thread_local, - repr_simd -)] +#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local, repr_simd)] #![no_core] #![allow(dead_code, non_camel_case_types, internal_features)] From 13bf5f5bb4115cebe30c8b18935ad017c7fa3de1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 08:34:47 +0000 Subject: [PATCH 1858/4206] ci: Use lowercase for bash locals, fix shellcheck --- library/compiler-builtins/ci/miri.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/ci/miri.sh b/library/compiler-builtins/ci/miri.sh index 79e660bab6295..7b0ea44c690f3 100755 --- a/library/compiler-builtins/ci/miri.sh +++ b/library/compiler-builtins/ci/miri.sh @@ -1,5 +1,5 @@ #!/bin/bash -set -ex +set -eux # We need Tree Borrows as some of our raw pointer patterns are not # compatible with Stacked Borrows. @@ -7,10 +7,12 @@ export MIRIFLAGS="-Zmiri-tree-borrows" # One target that sets `mem-unaligned` and one that does not, # and a big-endian target. -TARGETS=(x86_64-unknown-linux-gnu +targets=( + x86_64-unknown-linux-gnu armv7-unknown-linux-gnueabihf - s390x-unknown-linux-gnu) -for TARGET in "${TARGETS[@]}"; do + s390x-unknown-linux-gnu +) +for target in "${targets[@]}"; do # Only run the `mem` tests to avoid this taking too long. - cargo miri test --manifest-path builtins-test/Cargo.toml --features no-asm --target $TARGET -- mem + cargo miri test --manifest-path builtins-test/Cargo.toml --features no-asm --target "$target" -- mem done From 46bbc3dd88d998c910920c939a032d8f44cc16e9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 08:42:12 +0000 Subject: [PATCH 1859/4206] ci: Clean up workflow file and docker script --- .../compiler-builtins/.github/workflows/main.yaml | 11 +++++------ library/compiler-builtins/ci/run-docker.sh | 13 +++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 2b57d7eb3aae8..f7522a53d9d6c 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -131,6 +131,9 @@ jobs: 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 + if: matrix.os == 'ubuntu-24.04' - name: Cache compiler-rt id: cache-compiler-rt @@ -155,14 +158,10 @@ jobs: shell: bash run: ./ci/run.sh ${{ matrix.target }} - # Configure buildx to use Docker layer caching - - uses: docker/setup-buildx-action@v3 - if: matrix.os == 'ubuntu-24.04' - # Otherwise we use our docker containers to run builds - name: Run in Docker if: matrix.os == 'ubuntu-24.04' - run: cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} + run: ./ci/run-docker.sh ${{ matrix.target }} - name: Print test logs if available if: always() @@ -193,7 +192,7 @@ jobs: rustup default nightly rustup component add clippy - uses: Swatinem/rust-cache@v2 - - run: cargo clippy -- -D clippy::all + - run: cargo clippy --workspace --all-targets benchmarks: name: Benchmarks diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 58838fadf3cda..d0122dee5c89a 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -7,6 +7,13 @@ set -euxo pipefail host_arch="$(uname -m | sed 's/arm64/aarch64/')" +# Directories and files that do not yet exist need to be created before +# calling docker, otherwise docker will create them but they will be owned +# by root. +mkdir -p target +cargo generate-lockfile +cargo generate-lockfile --manifest-path builtins-test-intrinsics/Cargo.toml + run() { local target="$1" @@ -19,12 +26,6 @@ run() { echo "target is emulated" fi - # Directories and files that do not yet exist need to be created before - # calling docker, otherwise docker will create them but they will be owned - # by root. - mkdir -p target - cargo generate-lockfile --manifest-path builtins-test-intrinsics/Cargo.toml - run_cmd="HOME=/tmp" if [ "${GITHUB_ACTIONS:-}" = "true" ]; then From 97e4729525b50533a49e49617ced23c8e692fd5b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 08:22:36 +0000 Subject: [PATCH 1860/4206] ci: Configure release-plz to run semver checks on `libm` --- library/compiler-builtins/.release-plz.toml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.release-plz.toml b/library/compiler-builtins/.release-plz.toml index e32f676108462..95d7517feead2 100644 --- a/library/compiler-builtins/.release-plz.toml +++ b/library/compiler-builtins/.release-plz.toml @@ -1,7 +1,10 @@ -[workspace] +[[package]] +name = "compiler_builtins" semver_check = false - # As part of the release process, we delete `libm/Cargo.toml`. Since # this is only run in CI, we shouldn't need to worry about it. allow_dirty = true publish_allow_dirty = true + +[[package]] +name = "libm" From 66be06a1a7968eaf7d201734eb5fc0e6a6a0d753 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 08:47:02 +0000 Subject: [PATCH 1861/4206] ci: Remove the old libm workflow file All jobs are now run as part of `compiler-builtins`. --- .../etc/libm/.github/workflows/main.yaml | 324 ------------------ 1 file changed, 324 deletions(-) delete mode 100644 library/compiler-builtins/etc/libm/.github/workflows/main.yaml diff --git a/library/compiler-builtins/etc/libm/.github/workflows/main.yaml b/library/compiler-builtins/etc/libm/.github/workflows/main.yaml deleted file mode 100644 index 5ce0dbc26c86d..0000000000000 --- a/library/compiler-builtins/etc/libm/.github/workflows/main.yaml +++ /dev/null @@ -1,324 +0,0 @@ -name: CI -on: - push: - branches: - - master - pull_request: - -concurrency: - # Make sure that new pushes cancel running jobs - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -env: - CARGO_TERM_COLOR: always - RUSTDOCFLAGS: -Dwarnings - RUSTFLAGS: -Dwarnings - RUST_BACKTRACE: full - BENCHMARK_RUSTC: nightly-2025-01-16 # Pin the toolchain for reproducable results - -jobs: - test: - name: Build and test - timeout-minutes: 60 - strategy: - fail-fast: false - matrix: - include: - - target: aarch64-apple-darwin - os: macos-15 - # FIXME: pinned due to https://github.com/llvm/llvm-project/issues/127804 - channel: nightly-2025-02-07 - - target: aarch64-unknown-linux-gnu - os: ubuntu-24.04-arm - # FIXME: pinned due to https://github.com/llvm/llvm-project/issues/127804 - channel: nightly-2025-02-07 - - target: aarch64-pc-windows-msvc - os: windows-2025 - build_only: 1 # Can't run on x86 hosts - - target: arm-unknown-linux-gnueabi - os: ubuntu-24.04 - - target: arm-unknown-linux-gnueabihf - os: ubuntu-24.04 - - target: armv7-unknown-linux-gnueabihf - os: ubuntu-24.04 - - target: i586-unknown-linux-gnu - os: ubuntu-24.04 - - target: i686-unknown-linux-gnu - os: ubuntu-24.04 - - target: loongarch64-unknown-linux-gnu - os: ubuntu-24.04 - - target: powerpc-unknown-linux-gnu - os: ubuntu-24.04 - - target: powerpc64-unknown-linux-gnu - os: ubuntu-24.04 - - target: powerpc64le-unknown-linux-gnu - os: ubuntu-24.04 - - target: riscv64gc-unknown-linux-gnu - os: ubuntu-24.04 - - target: thumbv6m-none-eabi - os: ubuntu-24.04 - - target: thumbv7em-none-eabi - os: ubuntu-24.04 - - target: thumbv7em-none-eabihf - os: ubuntu-24.04 - - target: thumbv7m-none-eabi - os: ubuntu-24.04 - - target: x86_64-unknown-linux-gnu - os: ubuntu-24.04 - - target: x86_64-apple-darwin - os: macos-13 - - target: wasm32-unknown-unknown - os: ubuntu-24.04 - build_only: 1 - - target: i686-pc-windows-msvc - os: windows-2025 - - target: x86_64-pc-windows-msvc - os: windows-2025 - - target: i686-pc-windows-gnu - os: windows-2025 - # FIXME: pinned due to https://github.com/rust-lang/rust/issues/136795 - channel: nightly-2025-02-07-i686-gnu - - target: x86_64-pc-windows-gnu - os: windows-2025 - channel: nightly-x86_64-gnu - runs-on: ${{ matrix.os }} - env: - BUILD_ONLY: ${{ matrix.build_only }} - steps: - - name: Print runner information - run: uname -a - - uses: actions/checkout@v4 - with: - submodules: true - - name: Install Rust (rustup) - shell: bash - run: | - channel="nightly" - # Account for channels that have required components (MinGW) - [ -n "${{ matrix.channel }}" ] && channel="${{ matrix.channel }}" - rustup update "$channel" --no-self-update - rustup default "$channel" - rustup target add "${{ matrix.target }}" - rustup component add clippy llvm-tools-preview - - uses: taiki-e/install-action@nextest - - uses: Swatinem/rust-cache@v2 - with: - key: ${{ matrix.target }} - - - name: Verify API list - if: matrix.os == 'ubuntu-24.04' - run: python3 etc/update-api-list.py --check - - # Non-linux tests just use our raw script - - name: Run locally - if: matrix.os != 'ubuntu-24.04' || contains(matrix.target, 'wasm') - shell: bash - run: ./ci/run.sh ${{ matrix.target }} - - # Otherwise we use our docker containers to run builds - - name: Run in Docker - if: matrix.os == 'ubuntu-24.04' && !contains(matrix.target, 'wasm') - run: | - rustup target add x86_64-unknown-linux-musl - cargo generate-lockfile && ./ci/run-docker.sh ${{ matrix.target }} - - - name: Print test logs if available - if: always() - run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi - shell: bash - - clippy: - name: Clippy - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - uses: actions/checkout@master - with: - submodules: true - - name: Install Rust - run: | - rustup update nightly --no-self-update - rustup default nightly - rustup component add clippy - - uses: Swatinem/rust-cache@v2 - - run: cargo clippy --all --all-features --all-targets - - builtins: - name: Check use with compiler-builtins - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - uses: actions/checkout@master - - name: Install Rust - run: rustup update nightly --no-self-update && rustup default nightly - - uses: Swatinem/rust-cache@v2 - - run: cargo check --manifest-path crates/compiler-builtins-smoke-test/Cargo.toml - - run: cargo test --manifest-path crates/compiler-builtins-smoke-test/Cargo.toml - - benchmarks: - name: Benchmarks - runs-on: ubuntu-24.04 - timeout-minutes: 20 - steps: - - uses: actions/checkout@master - with: - submodules: true - - uses: taiki-e/install-action@cargo-binstall - - - name: Set up dependencies - run: | - sudo apt update - sudo apt install -y valgrind gdb libc6-dbg # Needed for iai-callgrind - rustup update "$BENCHMARK_RUSTC" --no-self-update - rustup default "$BENCHMARK_RUSTC" - # Install the version of iai-callgrind-runner that is specified in Cargo.toml - iai_version="$(cargo metadata --format-version=1 --features icount | - jq -r '.packages[] | select(.name == "iai-callgrind").version')" - cargo binstall -y iai-callgrind-runner --version "$iai_version" - sudo apt-get install valgrind - - - uses: Swatinem/rust-cache@v2 - - - name: Run icount benchmarks - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_NUMBER: ${{ github.event.pull_request.number }} - run: ./ci/bench-icount.sh - - - name: Upload the benchmark baseline - uses: actions/upload-artifact@v4 - with: - name: ${{ env.BASELINE_NAME }} - path: ${{ env.BASELINE_NAME }}.tar.xz - - - name: Run wall time benchmarks - run: | - # Always use the same seed for benchmarks. Ideally we should switch to a - # non-random generator. - export LIBM_SEED=benchesbenchesbenchesbencheswoo! - cargo bench --all --features short-benchmarks,build-musl,force-soft-floats - - - name: Print test logs if available - if: always() - run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi - shell: bash - - msrv: - name: Check MSRV - runs-on: ubuntu-24.04 - timeout-minutes: 10 - env: - RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings` - steps: - - uses: actions/checkout@master - - 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 - - run: | - # FIXME(msrv): Remove the workspace Cargo.toml so 1.63 cargo doesn't see - # `edition = "2024"` and get spooked. - rm Cargo.toml - cargo build --manifest-path libm/Cargo.toml - - rustfmt: - name: Rustfmt - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - uses: actions/checkout@master - - name: Install Rust - run: | - rustup update nightly --no-self-update - rustup default nightly - rustup component add rustfmt - - run: cargo fmt -- --check - - # Determine which extensive tests should be run based on changed files. - calculate_extensive_matrix: - name: Calculate job matrix - runs-on: ubuntu-24.04 - timeout-minutes: 10 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_NUMBER: ${{ github.event.pull_request.number }} - outputs: - matrix: ${{ steps.script.outputs.matrix }} - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 100 - - name: Fetch pull request ref - run: git fetch origin "$GITHUB_REF:$GITHUB_REF" - if: github.event_name == 'pull_request' - - run: python3 ci/ci-util.py generate-matrix >> "$GITHUB_OUTPUT" - id: script - - extensive: - name: Extensive tests for ${{ matrix.ty }} - needs: - # Wait on `clippy` so we have some confidence that the crate will build - - clippy - - calculate_extensive_matrix - runs-on: ubuntu-24.04 - timeout-minutes: 240 # 4 hours - strategy: - matrix: - # Use the output from `calculate_extensive_matrix` to calculate the matrix - # FIXME: it would be better to run all jobs (i.e. all types) but mark those that - # didn't change as skipped, rather than completely excluding the job. However, - # this is not currently possible https://github.com/actions/runner/issues/1985. - include: ${{ fromJSON(needs.calculate_extensive_matrix.outputs.matrix).matrix }} - env: - TO_TEST: ${{ matrix.to_test }} - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Install Rust - run: | - rustup update nightly --no-self-update - rustup default nightly - - uses: Swatinem/rust-cache@v2 - - name: Run extensive tests - run: | - echo "Tests to run: '$TO_TEST'" - if [ -z "$TO_TEST" ]; then - echo "No tests to run, exiting." - exit - fi - - set -x - - # Run the non-extensive tests first to catch any easy failures - cargo t --profile release-checked -- "$TO_TEST" - - LIBM_EXTENSIVE_TESTS="$TO_TEST" cargo t \ - --features build-mpfr,unstable,force-soft-floats \ - --profile release-checked \ - -- extensive - - name: Print test logs if available - run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi - shell: bash - - success: - needs: - - test - - builtins - - benchmarks - - msrv - - rustfmt - - extensive - runs-on: ubuntu-24.04 - timeout-minutes: 10 - # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency - # 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" - 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) }}' From 4e8eea696d8a1777b2f0eed7c58323c478b91b39 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 08:54:11 +0000 Subject: [PATCH 1862/4206] Add panic-handler to the workspace This crate does not interact with features so there isn't any reason it can't become part of the workspace. --- library/compiler-builtins/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index c3737a042f5ec..75bb81ec18772 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -5,6 +5,7 @@ members = [ "compiler-builtins", "crates/libm-macros", "crates/musl-math-sys", + "crates/panic-handler", "crates/util", "libm", "libm-test", From d50c76974f7ff75afe4c4a84cee2934c3074b61a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 3 Apr 2025 10:59:49 +0200 Subject: [PATCH 1863/4206] make abi_unsupported_vector_types a hard error --- example/std_example.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/example/std_example.rs b/example/std_example.rs index ffdc6a7d48491..2d9de2a5b8d6b 100644 --- a/example/std_example.rs +++ b/example/std_example.rs @@ -8,9 +8,6 @@ unboxed_closures )] #![allow(internal_features)] -// FIXME once abi_unsupported_vector_types is a hard error disable the foo test when the respective -// target feature is not enabled. -#![allow(abi_unsupported_vector_types)] #[cfg(target_arch = "x86_64")] use std::arch::x86_64::*; From cf13785636c924ba13ce3f2ae51f5ffe5057b007 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 18:39:53 +0000 Subject: [PATCH 1864/4206] ci: Fix release-plz configuration --- library/compiler-builtins/.release-plz.toml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/.release-plz.toml b/library/compiler-builtins/.release-plz.toml index 95d7517feead2..95e91a46c8d43 100644 --- a/library/compiler-builtins/.release-plz.toml +++ b/library/compiler-builtins/.release-plz.toml @@ -1,10 +1,12 @@ -[[package]] -name = "compiler_builtins" -semver_check = false +[workspace] # As part of the release process, we delete `libm/Cargo.toml`. Since # this is only run in CI, we shouldn't need to worry about it. allow_dirty = true publish_allow_dirty = true +[[package]] +name = "compiler_builtins" +semver_check = false + [[package]] name = "libm" From 97ddaca3565d2720c2ccfe78e02e841dc3872005 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Apr 2025 06:35:12 +0000 Subject: [PATCH 1865/4206] Remove `unsafe` from `naked_asm!` blocks This was changed in a recent nightly so the unsafety is only in the attribute, `#[unsafe(naked)]`. --- .../compiler-builtins/src/aarch64_linux.rs | 16 ++++++++-------- .../compiler-builtins/src/macros.rs | 3 ++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs b/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs index 5515dbfc43af5..e238d0237eb31 100644 --- a/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs +++ b/library/compiler-builtins/compiler-builtins/src/aarch64_linux.rs @@ -136,7 +136,7 @@ macro_rules! compare_and_swap { expected: int_ty!($bytes), desired: int_ty!($bytes), ptr: *mut int_ty!($bytes) ) -> int_ty!($bytes) { // We can't use `AtomicI8::compare_and_swap`; we *are* compare_and_swap. - unsafe { core::arch::naked_asm! { + core::arch::naked_asm! { // UXT s(tmp0), s(0) concat!(uxt!($bytes), " ", reg!($bytes, 16), ", ", reg!($bytes, 0)), "0:", @@ -150,7 +150,7 @@ macro_rules! compare_and_swap { "cbnz w17, 0b", "1:", "ret", - } } + } } } }; @@ -165,7 +165,7 @@ macro_rules! compare_and_swap_i128 { pub unsafe extern "C" fn $name ( expected: i128, desired: i128, ptr: *mut i128 ) -> i128 { - unsafe { core::arch::naked_asm! { + core::arch::naked_asm! { "mov x16, x0", "mov x17, x1", "0:", @@ -179,7 +179,7 @@ macro_rules! compare_and_swap_i128 { "cbnz w15, 0b", "1:", "ret", - } } + } } } }; @@ -194,7 +194,7 @@ macro_rules! swap { pub unsafe extern "C" fn $name ( left: int_ty!($bytes), right_ptr: *mut int_ty!($bytes) ) -> int_ty!($bytes) { - unsafe { core::arch::naked_asm! { + core::arch::naked_asm! { // mov s(tmp0), s(0) concat!("mov ", reg!($bytes, 16), ", ", reg!($bytes, 0)), "0:", @@ -204,7 +204,7 @@ macro_rules! swap { concat!(stxr!($ordering, $bytes), " w17, ", reg!($bytes, 16), ", [x1]"), "cbnz w17, 0b", "ret", - } } + } } } }; @@ -219,7 +219,7 @@ macro_rules! fetch_op { pub unsafe extern "C" fn $name ( val: int_ty!($bytes), ptr: *mut int_ty!($bytes) ) -> int_ty!($bytes) { - unsafe { core::arch::naked_asm! { + core::arch::naked_asm! { // mov s(tmp0), s(0) concat!("mov ", reg!($bytes, 16), ", ", reg!($bytes, 0)), "0:", @@ -231,7 +231,7 @@ macro_rules! fetch_op { concat!(stxr!($ordering, $bytes), " w15, ", reg!($bytes, 17), ", [x1]"), "cbnz w15, 0b", "ret", - } } + } } } } diff --git a/library/compiler-builtins/compiler-builtins/src/macros.rs b/library/compiler-builtins/compiler-builtins/src/macros.rs index b83414ce2b772..4fa53656e5ca3 100644 --- a/library/compiler-builtins/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/compiler-builtins/src/macros.rs @@ -436,11 +436,12 @@ macro_rules! intrinsics { // FIXME: when bootstrap supports `#[unsafe(naked)]` this duplication can be removed #[cfg(bootstrap)] #[naked] + #[allow(unused_unsafe)] $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), 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)* + unsafe { $($body)* } } #[cfg(not(bootstrap))] From e0d07241d06960b248d32fc2d33e5082c5ec8d53 Mon Sep 17 00:00:00 2001 From: Patryk Wychowaniec Date: Sun, 20 Apr 2025 09:05:10 +0200 Subject: [PATCH 1866/4206] avr: Provide `abort()` --- .../compiler-builtins/src/avr.rs | 23 +++++++++++++++++++ .../compiler-builtins/src/lib.rs | 3 +++ 2 files changed, 26 insertions(+) create mode 100644 library/compiler-builtins/compiler-builtins/src/avr.rs diff --git a/library/compiler-builtins/compiler-builtins/src/avr.rs b/library/compiler-builtins/compiler-builtins/src/avr.rs new file mode 100644 index 0000000000000..359a1d1acc1a7 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/avr.rs @@ -0,0 +1,23 @@ +intrinsics! { + pub unsafe extern "C" fn abort() -> ! { + // On AVRs, an architecture that doesn't support traps, unreachable code + // paths get lowered into calls to `abort`: + // + // https://github.com/llvm/llvm-project/blob/cbe8f3ad7621e402b050e768f400ff0d19c3aedd/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp#L4462 + // + // When control gets here, it means that either core::intrinsics::abort() + // was called or an undefined bebavior has occurred, so there's not that + // much we can do to recover - we can't `panic!()`, because for all we + // know the environment is gone now, so panicking might end up with us + // getting back to this very function. + // + // So let's do the next best thing, loop. + // + // Alternatively we could (try to) restart the program, but since + // undefined behavior is undefined, there's really no obligation for us + // to do anything here - for all we care, we could just set the chip on + // fire; but that'd be bad for the environment. + + loop {} + } +} diff --git a/library/compiler-builtins/compiler-builtins/src/lib.rs b/library/compiler-builtins/compiler-builtins/src/lib.rs index 16de96b4da07a..0678556037fde 100644 --- a/library/compiler-builtins/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/compiler-builtins/src/lib.rs @@ -63,6 +63,9 @@ pub mod aarch64_linux; ))] pub mod arm_linux; +#[cfg(target_arch = "avr")] +pub mod avr; + #[cfg(target_arch = "hexagon")] pub mod hexagon; From 013a83acddaa5fba20c3b0a593ce0c81ef0689da Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Apr 2025 07:15:48 +0000 Subject: [PATCH 1867/4206] Update licensing information after repository refactoring In order to disambiguate things now that libm is part of the compiler-builtins repository, do the following: * Mention libm in LICENSE.txt * Clarify the default license for crates other than libm and compiler-builtins * Add an explicit license field to Cargo.toml for all other crates --- library/compiler-builtins/LICENSE.txt | 17 +++++++++++------ .../builtins-test-intrinsics/Cargo.toml | 1 + .../compiler-builtins/builtins-test/Cargo.toml | 1 + .../crates/libm-macros/Cargo.toml | 1 + .../crates/musl-math-sys/Cargo.toml | 1 + .../compiler-builtins/crates/util/Cargo.toml | 1 + library/compiler-builtins/libm-test/Cargo.toml | 1 + 7 files changed, 17 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/LICENSE.txt b/library/compiler-builtins/LICENSE.txt index 367e3538df08f..00ae6140bd54e 100644 --- a/library/compiler-builtins/LICENSE.txt +++ b/library/compiler-builtins/LICENSE.txt @@ -1,10 +1,14 @@ -compiler-builtins as a whole is available for use under both the MIT license +The compiler-builtins crate is available for use under both the MIT license and the Apache-2.0 license with the LLVM exception (MIT AND Apache-2.0 WITH LLVM-exception). -As a contributor, you agree that your code can be used under either the MIT -license, or the Apache-2.0 license, or the Apache-2.0 license with the LLVM -exception. +The libm crate is available for use under the MIT license. + +As a contributor, you agree that your code may be used under any of the +following: the MIT license, the Apache-2.0 license, or the Apache-2.0 license +with the LLVM exception. In other words, original (non-derivative) work is +licensed under MIT OR Apache-2.0 OR Apache-2.0 WITH LLVM-exception. This is +the default license for all other source in this repository. Text of the relevant licenses is provided below: @@ -263,8 +267,9 @@ license: * Work derived from compiler-rt after 2019-01-19 is usable under the Apache-2.0 license with the LLVM exception. -* The bundled `math` module is from rust-lang/libm, usable under the MIT - license. See https://github.com/rust-lang/libm for details. +* The bundled `math` module is from the libm crate, usable under the MIT + license. For further details and copyrights, see see libm/LICENSE.txt at + https://github.com/rust-lang/compiler-builtins. Additionally, some source files may contain comments with specific copyrights or licenses. diff --git a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml index 6d88cbec90d3b..6e10628a41b22 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml +++ b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml @@ -3,6 +3,7 @@ name = "builtins-test-intrinsics" version = "0.1.0" edition = "2021" publish = false +license = "MIT OR Apache-2.0" [dependencies] compiler_builtins = { path = "../compiler-builtins", features = ["compiler-builtins"]} diff --git a/library/compiler-builtins/builtins-test/Cargo.toml b/library/compiler-builtins/builtins-test/Cargo.toml index 18185d8fe40f0..f7bcb52b40f03 100644 --- a/library/compiler-builtins/builtins-test/Cargo.toml +++ b/library/compiler-builtins/builtins-test/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors = ["Alex Crichton "] edition = "2024" publish = false +license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" [dependencies] # For fuzzing tests we want a deterministic seedable RNG. We also eliminate potential diff --git a/library/compiler-builtins/crates/libm-macros/Cargo.toml b/library/compiler-builtins/crates/libm-macros/Cargo.toml index 50c869db7ff6b..3929854f08e65 100644 --- a/library/compiler-builtins/crates/libm-macros/Cargo.toml +++ b/library/compiler-builtins/crates/libm-macros/Cargo.toml @@ -3,6 +3,7 @@ name = "libm-macros" version = "0.1.0" edition = "2024" publish = false +license = "MIT OR Apache-2.0" [lib] proc-macro = true diff --git a/library/compiler-builtins/crates/musl-math-sys/Cargo.toml b/library/compiler-builtins/crates/musl-math-sys/Cargo.toml index 9e866a9704f61..d3fb147e526aa 100644 --- a/library/compiler-builtins/crates/musl-math-sys/Cargo.toml +++ b/library/compiler-builtins/crates/musl-math-sys/Cargo.toml @@ -3,6 +3,7 @@ name = "musl-math-sys" version = "0.1.0" edition = "2024" publish = false +license = "MIT OR Apache-2.0" [dependencies] diff --git a/library/compiler-builtins/crates/util/Cargo.toml b/library/compiler-builtins/crates/util/Cargo.toml index ae37a72381686..614c54bd83557 100644 --- a/library/compiler-builtins/crates/util/Cargo.toml +++ b/library/compiler-builtins/crates/util/Cargo.toml @@ -3,6 +3,7 @@ name = "util" version = "0.1.0" edition = "2024" publish = false +license = "MIT OR Apache-2.0" [features] default = ["build-musl", "build-mpfr", "unstable-float"] diff --git a/library/compiler-builtins/libm-test/Cargo.toml b/library/compiler-builtins/libm-test/Cargo.toml index 6fd49774e0c34..7a306e735577e 100644 --- a/library/compiler-builtins/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm-test/Cargo.toml @@ -3,6 +3,7 @@ name = "libm-test" version = "0.1.0" edition = "2024" publish = false +license = "MIT OR Apache-2.0" [features] default = ["build-mpfr", "build-musl", "unstable-float"] From 8ce02e8ef578880d56e89ff975475c190471db2a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Apr 2025 07:22:24 +0000 Subject: [PATCH 1868/4206] Move README.md to compiler-builtins, CONTRIBUTING.md to root Do this in a commit so git tracks the move; a new README will be introduced in the root, and CONTRIBUTING will be updated to apply to both crates. --- library/compiler-builtins/{libm => }/CONTRIBUTING.md | 0 library/compiler-builtins/compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/{ => compiler-builtins}/README.md | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename library/compiler-builtins/{libm => }/CONTRIBUTING.md (100%) rename library/compiler-builtins/{ => compiler-builtins}/README.md (100%) diff --git a/library/compiler-builtins/libm/CONTRIBUTING.md b/library/compiler-builtins/CONTRIBUTING.md similarity index 100% rename from library/compiler-builtins/libm/CONTRIBUTING.md rename to library/compiler-builtins/CONTRIBUTING.md diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index a014baf040abf..e2a6c0a74bd86 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -18,8 +18,8 @@ include = [ '/configure.rs', '/src/*', '../LICENSE.txt', - '../README.md', '../compiler-rt/*', + 'README.md', 'libm/src/math/*', ] links = 'compiler-rt' diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/compiler-builtins/README.md similarity index 100% rename from library/compiler-builtins/README.md rename to library/compiler-builtins/compiler-builtins/README.md From 94448a6ff6ac1d4af6892086ea1bc67518363e44 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Apr 2025 08:46:19 +0000 Subject: [PATCH 1869/4206] Update README and CONTRIBUTING for the new repository layout --- library/compiler-builtins/CONTRIBUTING.md | 189 +++++++++++++----- library/compiler-builtins/README.md | 27 +++ .../compiler-builtins/Cargo.toml | 23 +-- .../compiler-builtins/README.md | 76 ++----- library/compiler-builtins/libm/Cargo.toml | 2 +- library/compiler-builtins/libm/README.md | 54 ++--- 6 files changed, 213 insertions(+), 158 deletions(-) create mode 100644 library/compiler-builtins/README.md diff --git a/library/compiler-builtins/CONTRIBUTING.md b/library/compiler-builtins/CONTRIBUTING.md index dc40060357c4e..9f67cfc31571d 100644 --- a/library/compiler-builtins/CONTRIBUTING.md +++ b/library/compiler-builtins/CONTRIBUTING.md @@ -1,68 +1,115 @@ # How to contribute -- Pick your favorite math function from the [issue tracker]. -- Look for the C implementation of the function in the [MUSL source code][src]. -- Copy paste the C code into a Rust file in the `src/math` directory and adjust - `src/math/mod.rs` accordingly. Also, uncomment the corresponding trait method - in `src/lib.rs`. -- Write some simple tests in your module (using `#[test]`) -- Run `cargo test` to make sure it works. Full tests are only run when enabling - features, see [Testing](#testing) below. -- Send us a pull request! Make sure to run `cargo fmt` on your code before - sending the PR. Also include "closes #42" in the PR description to close the - corresponding issue. -- :tada: - -[issue tracker]: https://github.com/rust-lang/libm/issues -[src]: https://git.musl-libc.org/cgit/musl/tree/src/math -[`src/math/truncf.rs`]: https://github.com/rust-lang/libm/blob/master/src/math/truncf.rs - -Check [PR #65] for an example. - -[PR #65]: https://github.com/rust-lang/libm/pull/65 +## compiler-builtins + +1. From the [pending list](compiler-builtins/README.md#progress), pick one or + more intrinsics. +2. Port the version from [`compiler-rt`] and, if applicable, their + [tests][rt-tests]. Note that this crate has generic implementations for a lot + of routines, which may be usable without porting the entire implementation. +3. Add a test to `builtins-test`, comparing the behavior of the ported + intrinsic(s) with their implementation on the testing host. +4. Add the intrinsic to `builtins-test-intrinsics/src/main.rs` to verify it can + be linked on all targets. +5. Send a Pull Request (PR) :tada:. + +[`compiler-rt`]: https://github.com/llvm/llvm-project/tree/b6820c35c59a4da3e59c11f657093ffbd79ae1db/compiler-rt/lib/builtins +[rt-tests]: https://github.com/llvm/llvm-project/tree/b6820c35c59a4da3e59c11f657093ffbd79ae1db/compiler-rt/test/builtins + +## Porting Reminders + +1. [Rust][prec-rust] and [C][prec-c] have slightly different operator + precedence. C evaluates comparisons (`== !=`) before bitwise operations + (`& | ^`), while Rust evaluates the other way. +2. C assumes wrapping operations everywhere. Rust panics on overflow when in + debug mode. Consider using the [Wrapping][wrap-ty] type or the explicit + [wrapping_*][wrap-fn] functions where applicable. +3. Note [C implicit casts][casts], especially integer promotion. Rust is much + more explicit about casting, so be sure that any cast which affects the + output is ported to the Rust implementation. +4. Rust has [many functions][i32] for integer or floating point manipulation in + the standard library. Consider using one of these functions rather than + porting a new one. + +[prec-rust]: https://doc.rust-lang.org/reference/expressions.html#expression-precedence +[prec-c]: http://en.cppreference.com/w/c/language/operator_precedence +[wrap-ty]: https://doc.rust-lang.org/core/num/struct.Wrapping.html +[wrap-fn]: https://doc.rust-lang.org/std/primitive.i32.html#method.wrapping_add +[casts]: http://en.cppreference.com/w/cpp/language/implicit_conversion +[i32]: https://doc.rust-lang.org/std/primitive.i32.html ## Tips and tricks -- *IMPORTANT* The code in this crate will end up being used in the `core` crate so it can **not** - have any external dependencies (other than `core` itself). - -- Only use relative imports within the `math` directory / module, e.g. `use self::fabs::fabs` or -`use super::k_cos`. Absolute imports from core are OK, e.g. `use core::u64`. - -- To reinterpret a float as an integer use the `to_bits` method. The MUSL code uses the - `GET_FLOAT_WORD` macro, or a union, to do this operation. - -- To reinterpret an integer as a float use the `f32::from_bits` constructor. The MUSL code uses the - `SET_FLOAT_WORD` macro, or a union, to do this operation. - +- _IMPORTANT_ The code in this crate will end up being used in the `core` crate + so it can **not** have any external dependencies (other than a subset of + `core` itself). +- Only use relative imports within the `math` directory / module, e.g. + `use self::fabs::fabs` or `use super::k_cos`. Absolute imports from core are + OK, e.g. `use core::u64`. +- To reinterpret a float as an integer use the `to_bits` method. The MUSL code + uses the `GET_FLOAT_WORD` macro, or a union, to do this operation. +- To reinterpret an integer as a float use the `f32::from_bits` constructor. The + MUSL code uses the `SET_FLOAT_WORD` macro, or a union, to do this operation. - You may use other methods from core like `f64::is_nan`, etc. as appropriate. - -- If you're implementing one of the private double-underscore functions, take a look at the - "source" name in the comment at the top for an idea for alternate naming. For example, `__sin` - was renamed to `k_sin` after the FreeBSD source code naming. Do `use` these private functions in - `mod.rs`. - -- You may encounter weird literals like `0x1p127f` in the MUSL code. These are hexadecimal floating - point literals. Rust (the language) doesn't support these kind of literals. This crate provides - two macros, `hf32!` and `hf64!`, which convert string literals to floats at compile time. +- Rust does not have hex float literals. This crate provides two `hf16!`, + `hf32!`, `hf64!`, and `hf128!` which convert string literals to floats at + compile time. ```rust assert_eq!(hf32!("0x1.ffep+8").to_bits(), 0x43fff000); assert_eq!(hf64!("0x1.ffep+8").to_bits(), 0x407ffe0000000000); ``` -- Rust code panics on arithmetic overflows when not optimized. You may need to use the [`Wrapping`] - newtype to avoid this problem, or individual methods like [`wrapping_add`]. +- Rust code panics on arithmetic overflows when not optimized. You may need to + use the [`Wrapping`] newtype to avoid this problem, or individual methods like + [`wrapping_add`]. [`Wrapping`]: https://doc.rust-lang.org/std/num/struct.Wrapping.html [`wrapping_add`]: https://doc.rust-lang.org/std/primitive.u32.html#method.wrapping_add ## Testing -Normal tests can be executed with: +Testing for these crates can be somewhat complex, so feel free to rely on CI. + +The easiest way replicate CI testing is using Docker. This can be done by +running `./ci/run-docker.sh [target]`. If no target is specified, all targets +will be run. + +Tests can also be run without Docker: ```sh -# Tests against musl require that the submodule is up to date. +# Run basic tests +# +# --no-default-features always needs to be passed, an unfortunate limitation +# since the `#![compiler_builtins]` feature is enabled by default. +cargo test --workspace --no-default-features + +# Test with all interesting features +cargo test --workspace --no-default-features \ + --features arch,unstable-float,unstable-intrinsics,mem + +# Run with more detailed tests for libm +cargo test --workspace --no-default-features \ + --features arch,unstable-float,unstable-intrinsics,mem \ + --features build-mpfr,build-musl \ + --profile release-checked +``` + +The multiprecision tests use the [`rug`] crate for bindings to MPFR. MPFR can be +difficult to build on non-Unix systems, refer to [`gmp_mpfr_sys`] for help. + +`build-musl` does not build with MSVC, Wasm, or Thumb. + +[`rug`]: https://docs.rs/rug/latest/rug/ +[`gmp_mpfr_sys`]: https://docs.rs/gmp-mpfr-sys/1.6.4/gmp_mpfr_sys/ + +In order to run all tests, some dependencies may be required: + +```sh +# Allow testing compiler-builtins +./ci/download-compiler-rt.sh + +# Optional, initialize musl for `--features build-musl` git submodule init git submodule update @@ -70,13 +117,51 @@ git submodule update cargo test --release ``` -If you are on a system that cannot build musl or MPFR, passing -`--no-default-features` will run some limited tests. +### Extensive tests -The multiprecision tests use the [`rug`] crate for bindings to MPFR. MPFR can -be difficult to build on non-Unix systems, refer to [`gmp_mpfr_sys`] for help. +Libm also has tests that are exhaustive (for single-argument `f32` and 1- or 2- +argument `f16`) or extensive (for all other float and argument combinations). +These take quite a long time to run, but are launched in CI when relevant files +are changed. -`build-musl` does not build with MSVC, Wasm, or Thumb. +Exhaustive tests can be selected by passing an environment variable: -[`rug`]: https://docs.rs/rug/latest/rug/ -[`gmp_mpfr_sys`]: https://docs.rs/gmp-mpfr-sys/1.6.4/gmp_mpfr_sys/ +```sh +LIBM_EXTENSIVE_TESTS=sqrt,sqrtf cargo test --features build-mpfr \ + --test z_extensive \ + --profile release-checked + +# Run all tests for one type +LIBM_EXTENSIVE_TESTS=all_f16 cargo test ... + +# Ensure `f64` tests can run exhaustively. Estimated completion test for a +# single test is 57306 years on my machine so this may be worth skipping. +LIBM_EXTENSIVE_TESTS=all LIBM_EXTENSIVE_ITERATIONS=18446744073709551615 cargo test ... +``` + +## Benchmarking + +Regular walltime benchmarks can be run with `cargo bench`: + +```sh +cargo bench --no-default-features \ + --features arch,unstable-float,unstable-intrinsics,mem \ + --features benchmarking-reports +``` + +There are also benchmarks that check instruction count behind the `icount` +feature. These require [`iai-callgrind-runner`] (via Cargo) and [Valgrind] +to be installed, which means these only run on limited platforms. + +Instruction count benchmarks are run as part of CI to flag performance +regresions. + +```sh +cargo bench --no-default-features \ + --features arch,unstable-float,unstable-intrinsics,mem \ + --features icount \ + --bench icount --bench mem_icount +``` + +[`iai-callgrind-runner`]: https://crates.io/crates/iai-callgrind-runner +[Valgrind]: https://valgrind.org/ diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md new file mode 100644 index 0000000000000..3130ff7b77d9d --- /dev/null +++ b/library/compiler-builtins/README.md @@ -0,0 +1,27 @@ +# `compiler-builtins` and `libm` + +This repository contains two main crates: + +* `compiler-builtins`: symbols that the compiler expects to be available at + link time +* `libm`: a Rust implementation of C math libraries, used to provide + implementations in `ocre`. + +More details are at [compiler-builtins/README.md](compiler-builtins/README.md) +and [libm/README.md](libm/README.md). + +For instructions on contributing, see [CONTRIBUTING.md](CONTRIBUTING.md). + +## License + +* `libm` may be used under the [MIT License] +* `compiler-builtins` may be used under the [MIT License] and the + [Apache License, Version 2.0] with the LLVM exception. +* All original contributions must be under all of: the MIT license, the + Apache-2.0 license, and the Apache-2.0 license with the LLVM exception. + +More details are in [LICENSE.txt](LICENSE.txt) and +[libm/LICENSE.txt](libm/LICENSE.txt). + +[MIT License]: https://opensource.org/license/mit +[Apache License, Version 2.0]: htps://www.apache.org/licenses/LICENSE-2.0 diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index e2a6c0a74bd86..9e23c75a82650 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -3,24 +3,21 @@ authors = ["Jorge Aparicio "] name = "compiler_builtins" version = "0.1.155" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" -readme = "../README.md" +readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" homepage = "https://github.com/rust-lang/compiler-builtins" documentation = "https://docs.rs/compiler_builtins" edition = "2021" -description = """ -Compiler intrinsics used by the Rust compiler. Also available for other targets -if necessary! -""" +description = "Compiler intrinsics used by the Rust compiler." include = [ - '/Cargo.toml', - '/build.rs', - '/configure.rs', - '/src/*', - '../LICENSE.txt', - '../compiler-rt/*', - 'README.md', - 'libm/src/math/*', + "../LICENSE.txt", + "../compiler-rt/*", + "/Cargo.toml", + "/build.rs", + "/configure.rs", + "/src/*", + "README.md", + "libm/src/math/*", ] links = 'compiler-rt' diff --git a/library/compiler-builtins/compiler-builtins/README.md b/library/compiler-builtins/compiler-builtins/README.md index e5350d58c3e3f..387b70c0499a6 100644 --- a/library/compiler-builtins/compiler-builtins/README.md +++ b/library/compiler-builtins/compiler-builtins/README.md @@ -1,64 +1,18 @@ # `compiler-builtins` -This crate provides external symbols that the compiler expects to be available when -building Rust projects, typically software routines for basic operations that do not -have hardware support. It is largely a port of LLVM's [`compiler-rt`]. +This crate provides external symbols that the compiler expects to be available +when building Rust projects, typically software routines for basic operations +that do not have hardware support. It is largely a port of LLVM's +[`compiler-rt`]. -It is distributed as part of Rust's sysroot. +It is distributed as part of Rust's sysroot. `compiler-builtins` does not need +to be added as an explicit dependency in `Cargo.toml`. [`compiler-rt`]: https://github.com/llvm/llvm-project/tree/1b1dc505057322f4fa1110ef4f53c44347f52986/compiler-rt ## Contributing -1. Pick one or more intrinsics from the [pending list](#progress). -2. Fork this repository. -3. Port the intrinsic(s) and their corresponding [unit tests][1] from their - [C implementation][2] to Rust. -4. Add a test to compare the behavior of the ported intrinsic(s) with their - implementation on the testing host. -5. Add the intrinsic to `builtins-test-intrinsics/src/main.rs` to verify it - can be linked on all targets. -6. Send a Pull Request (PR). -7. Once the PR passes our extensive testing infrastructure, we'll merge it! -8. Celebrate :tada: - -[1]: https://github.com/rust-lang/llvm-project/tree/9e3de9490ff580cd484fbfa2908292b4838d56e7/compiler-rt/test/builtins/Unit -[2]: https://github.com/rust-lang/llvm-project/tree/9e3de9490ff580cd484fbfa2908292b4838d56e7/compiler-rt/lib/builtins -[3]: https://github.com/rust-lang/compiler-builtins/actions - -### Porting Reminders - -1. [Rust][5a] and [C][5b] have slightly different operator precedence. C evaluates comparisons (`== !=`) before bitwise operations (`& | ^`), while Rust evaluates the other way. -2. C assumes wrapping operations everywhere. Rust panics on overflow when in debug mode. Consider using the [Wrapping][6] type or the explicit [wrapping_*][7] functions where applicable. -3. Note [C implicit casts][8], especially integer promotion. Rust is much more explicit about casting, so be sure that any cast which affects the output is ported to the Rust implementation. -4. Rust has [many functions][9] for integer or floating point manipulation in the standard library. Consider using one of these functions rather than porting a new one. - -[5a]: https://doc.rust-lang.org/reference/expressions.html#expression-precedence -[5b]: http://en.cppreference.com/w/c/language/operator_precedence -[6]: https://doc.rust-lang.org/core/num/struct.Wrapping.html -[7]: https://doc.rust-lang.org/std/primitive.i32.html#method.wrapping_add -[8]: http://en.cppreference.com/w/cpp/language/implicit_conversion -[9]: https://doc.rust-lang.org/std/primitive.i32.html - -## Testing - -The easiest way to test locally is using Docker. This can be done by running -`./ci/run-docker.sh [target]`. If no target is specified, all targets will be -run. - -In order to run the full test suite, you will also need the C compiler runtime -to test against, located in a directory called `compiler-rt`. This can be -obtained with the following: - -```sh -curl -L -o rustc-llvm-20.1.tar.gz https://github.com/rust-lang/llvm-project/archive/rustc/20.1-2025-02-13.tar.gz -tar xzf rustc-llvm-20.1.tar.gz --strip-components 1 llvm-project-rustc-20.1-2025-02-13/compiler-rt -``` - -Local targets may also be tested with `./ci/run.sh [target]`. - -Note that testing may not work on all hosts, in which cases it is acceptable to -rely on CI. +See [CONTRIBUTING.md](CONTRIBUTING.md). ## Progress @@ -468,9 +422,15 @@ Unsupported in any current target: used on old versions of 32-bit iOS with ARMv5 ## License -The compiler-builtins crate is dual licensed under both the University of -Illinois "BSD-Like" license and the MIT license. As a user of this code you may -choose to use it under either license. As a contributor, you agree to allow -your code to be used under both. +Usage is allowed under the [MIT License] and the [Apache License, Version 2.0] +with the LLVM exception. + +[MIT License]: https://opensource.org/license/mit +[Apache License, Version 2.0]: htps://www.apache.org/licenses/LICENSE-2.0 + +### Contribution + +Contributions are licensed under the MIT License, the Apache License, +Version 2.0, and the Apache-2.0 license with the LLVM exception. -Full text of the relevant licenses is in LICENSE.TXT. +See [LICENSE.txt](../LICENSE.txt) for full details. diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 44154c1a8f5e3..4e3850bbff041 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -7,7 +7,7 @@ keywords = ["libm", "math"] license = "MIT" name = "libm" readme = "README.md" -repository = "https://github.com/rust-lang/libm" +repository = "https://github.com/rust-lang/compiler-builtins" version = "0.2.11" edition = "2021" rust-version = "1.63" diff --git a/library/compiler-builtins/libm/README.md b/library/compiler-builtins/libm/README.md index 52d760a4f1599..349e892dfcf9c 100644 --- a/library/compiler-builtins/libm/README.md +++ b/library/compiler-builtins/libm/README.md @@ -1,38 +1,26 @@ # `libm` -A port of [MUSL]'s libm to Rust. +A Rust implementations of the C math library. -[MUSL]: https://musl.libc.org/ +## Usage -## Goals +`libm` provides fallback implementations for Rust's [float math functions] in +`core`, and the [`core_float_math`] feature. If what is available suits your +needs, there is no need to add `libm` as a dependency. -The short term goal of this library is to [enable math support (e.g. `sin`, `atan2`) for the -`wasm32-unknown-unknown` target][wasm] (cf. [rust-lang/compiler-builtins][pr]). The longer -term goal is to enable [math support in the `core` crate][core]. +If more functionality is needed, this crate can also be used directly: -[wasm]: https://github.com/rust-lang/libm/milestone/1 -[pr]: https://github.com/rust-lang/compiler-builtins/pull/248 -[core]: https://github.com/rust-lang/libm/milestone/2 +```toml +[dependencies] +libm = "0.2.11" +``` -## Already usable - -This crate is [on crates.io] and can be used today in stable `#![no_std]` programs. - -The API documentation can be found [here](https://docs.rs/libm). - -[on crates.io]: https://crates.io/crates/libm - -## Benchmark -[benchmark]: #benchmark - -The benchmarks are located in `crates/libm-bench` and require a nightly Rust toolchain. -To run all benchmarks: - -> cargo +nightly bench --all +[float math functions]: https://doc.rust-lang.org/std/primitive.f32.html +[`core_float_math`]: https://github.com/rust-lang/rust/issues/137578 ## Contributing -Please check [CONTRIBUTING.md](CONTRIBUTING.md) +Please check [CONTRIBUTING.md](../CONTRIBUTING.md) ## Minimum Rust version policy @@ -40,17 +28,15 @@ This crate supports rustc 1.63 and newer. ## License -Usage is licensed under the MIT license ([LICENSE-MIT](LICENSE-MIT) or -https://opensource.org/licenses/MIT). - +Usage is under the MIT license, available at +. ### Contribution Contributions are licensed under both the MIT license and the Apache License, -Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or -https://www.apache.org/licenses/LICENSE-2.0). Unless you explicitly state -otherwise, any contribution intentionally submitted for inclusion in the work -by you, as defined in the Apache-2.0 license, shall be dual licensed as -mentioned, without any additional terms or conditions. +Version 2.0, available at . Unless +you explicitly state otherwise, any contribution intentionally submitted for +inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as mentioned, without any additional terms or conditions. -See `LICENSE.txt` for full details. +See [LICENSE.txt](LICENSE.txt) for full details. From 913796c1c5f7e0afa6c4323e8bd850efd7a646d9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Apr 2025 09:20:37 +0000 Subject: [PATCH 1870/4206] Fix compiler-builtins publish compiler-builtins currently wouldn't publish correctly because of a relative path to `libm` that doesn't get included in the package. Fix this by simlinking `libm` to within the `compiler-builtins` directory. Also symlink LICENSE.txt which lets us drop the `include` array in Cargo.toml. LICENSE.txt and compiler-rt were not being included anyway, since Cargo silently drops items that are not within the crate directory. --- library/compiler-builtins/compiler-builtins/Cargo.toml | 10 ---------- .../compiler-builtins/compiler-builtins/LICENSE.txt | 1 + library/compiler-builtins/compiler-builtins/src/lib.rs | 2 +- .../compiler-builtins/src/math/libm_math | 1 + .../compiler-builtins/src/{math.rs => math/mod.rs} | 9 ++++----- 5 files changed, 7 insertions(+), 16 deletions(-) create mode 120000 library/compiler-builtins/compiler-builtins/LICENSE.txt create mode 120000 library/compiler-builtins/compiler-builtins/src/math/libm_math rename library/compiler-builtins/compiler-builtins/src/{math.rs => math/mod.rs} (96%) diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index 9e23c75a82650..1de37bd8683d8 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -9,16 +9,6 @@ homepage = "https://github.com/rust-lang/compiler-builtins" documentation = "https://docs.rs/compiler_builtins" edition = "2021" description = "Compiler intrinsics used by the Rust compiler." -include = [ - "../LICENSE.txt", - "../compiler-rt/*", - "/Cargo.toml", - "/build.rs", - "/configure.rs", - "/src/*", - "README.md", - "libm/src/math/*", -] links = 'compiler-rt' [lib] diff --git a/library/compiler-builtins/compiler-builtins/LICENSE.txt b/library/compiler-builtins/compiler-builtins/LICENSE.txt new file mode 120000 index 0000000000000..4ab43736a839d --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/LICENSE.txt @@ -0,0 +1 @@ +../LICENSE.txt \ No newline at end of file diff --git a/library/compiler-builtins/compiler-builtins/src/lib.rs b/library/compiler-builtins/compiler-builtins/src/lib.rs index 0678556037fde..7523a00cf9b66 100644 --- a/library/compiler-builtins/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/compiler-builtins/src/lib.rs @@ -45,7 +45,7 @@ pub mod math; pub mod mem; // `libm` expects its `support` module to be available in the crate root. -use math::libm::support; +use math::libm_math::support; #[cfg(target_arch = "arm")] pub mod arm; diff --git a/library/compiler-builtins/compiler-builtins/src/math/libm_math b/library/compiler-builtins/compiler-builtins/src/math/libm_math new file mode 120000 index 0000000000000..4d65313c2324a --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/math/libm_math @@ -0,0 +1 @@ +../../../libm/src/math \ No newline at end of file diff --git a/library/compiler-builtins/compiler-builtins/src/math.rs b/library/compiler-builtins/compiler-builtins/src/math/mod.rs similarity index 96% rename from library/compiler-builtins/compiler-builtins/src/math.rs rename to library/compiler-builtins/compiler-builtins/src/math/mod.rs index 722374f8e4f8f..078feb9ff9e66 100644 --- a/library/compiler-builtins/compiler-builtins/src/math.rs +++ b/library/compiler-builtins/compiler-builtins/src/math/mod.rs @@ -2,15 +2,14 @@ #[allow(dead_code)] #[allow(unused_imports)] #[allow(clippy::all)] -#[path = "../../libm/src/math/mod.rs"] -pub(crate) mod libm; +pub(crate) mod libm_math; macro_rules! libm_intrinsics { ($(fn $fun:ident($($iid:ident : $ity:ty),+) -> $oty:ty;)+) => { intrinsics! { $( pub extern "C" fn $fun($($iid: $ity),+) -> $oty { - $crate::math::libm::$fun($($iid),+) + $crate::math::libm_math::$fun($($iid),+) } )+ } @@ -185,13 +184,13 @@ pub mod partial_availability { // allow for windows (and other targets) intrinsics! { pub extern "C" fn lgamma_r(x: f64, s: &mut i32) -> f64 { - let r = super::libm::lgamma_r(x); + let r = super::libm_math::lgamma_r(x); *s = r.1; r.0 } pub extern "C" fn lgammaf_r(x: f32, s: &mut i32) -> f32 { - let r = super::libm::lgammaf_r(x); + let r = super::libm_math::lgammaf_r(x); *s = r.1; r.0 } From 4cfecfdfa6a432d72f5ee03c5a0904b5fbcca0a3 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 21 Apr 2025 10:37:10 +0000 Subject: [PATCH 1871/4206] Rustup to rustc 1.88.0-nightly (b8c54d635 2025-04-20) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 1789b62917de9..93dfecedb6d6a 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-04-14" +channel = "nightly-2025-04-21" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 91114bd289cf92c7b62b1d2d53f2467024d9cf07 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 21 Apr 2025 10:48:40 +0000 Subject: [PATCH 1872/4206] Fix rustc test suite --- scripts/test_rustc_tests.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 01c8b474a9d11..575467185c8bb 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -96,6 +96,7 @@ rm -r tests/run-make/llvm-location-discriminator-limit-dummy-span # same rm tests/ui/abi/stack-protector.rs # requires stack protector support rm -r tests/run-make/emit-stack-sizes # requires support for -Z emit-stack-sizes rm -r tests/run-make/optimization-remarks-dir # remarks are LLVM specific +rm -r tests/ui/optimization-remark.rs # same rm -r tests/run-make/print-to-output # requires --print relocation-models # requires asm, llvm-ir and/or llvm-bc emit support @@ -129,6 +130,7 @@ rm -r tests/run-make/compiler-builtins # Expects lib/rustlib/src/rust to contain rm -r tests/run-make/translation # same rm -r tests/run-make/missing-unstable-trait-bound # This disables support for unstable features, but running cg_clif needs some unstable features rm -r tests/run-make/const-trait-stable-toolchain # same +rm -r tests/run-make/print-request-help-stable-unstable # same rm -r tests/run-make/incr-add-rust-src-component rm tests/ui/errors/remap-path-prefix-sysroot.rs # different sysroot source path From de372d3fff28d21e48e91b0ec7203d25158ff7fa Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 7 Apr 2025 19:59:49 +0000 Subject: [PATCH 1873/4206] Update to Cranelift 0.119 --- Cargo.lock | 80 +++++++++++++++++++++++++------------------- Cargo.toml | 24 ++++++------- src/unwind_module.rs | 9 +++-- 3 files changed, 61 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e5f1896b9230b..066d5a61adde6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,39 +43,42 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-assembler-x64" -version = "0.118.0" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4b56ebe316895d3fa37775d0a87b0c889cc933f5c8b253dbcc7c7bcb7fe7e4" +checksum = "263cc79b8a23c29720eb596d251698f604546b48c34d0d84f8fd2761e5bf8888" dependencies = [ "cranelift-assembler-x64-meta", ] [[package]] name = "cranelift-assembler-x64-meta" -version = "0.118.0" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95cabbc01dfbd7dcd6c329ca44f0212910309c221797ac736a67a5bc8857fe1b" +checksum = "5b4a113455f8c0e13e3b3222a9c38d6940b958ff22573108be083495c72820e1" +dependencies = [ + "cranelift-srcgen", +] [[package]] name = "cranelift-bforest" -version = "0.118.0" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76ffe46df300a45f1dc6f609dc808ce963f0e3a2e971682c479a2d13e3b9b8ef" +checksum = "58f96dca41c5acf5d4312c1d04b3391e21a312f8d64ce31a2723a3bb8edd5d4d" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.118.0" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b265bed7c51e1921fdae6419791d31af77d33662ee56d7b0fa0704dc8d231cab" +checksum = "7d821ed698dd83d9c012447eb63a5406c1e9c23732a2f674fb5b5015afd42202" [[package]] name = "cranelift-codegen" -version = "0.118.0" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e606230a7e3a6897d603761baee0d19f88d077f17b996bb5089488a29ae96e41" +checksum = "06c52fdec4322cb8d5545a648047819aaeaa04e630f88d3a609c0d3c1a00e9a0" dependencies = [ "bumpalo", "cranelift-assembler-x64", @@ -98,43 +101,44 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.118.0" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a63bffafc23bc60969ad528e138788495999d935f0adcfd6543cb151ca8637d" +checksum = "af2c215e0c9afa8069aafb71d22aa0e0dde1048d9a5c3c72a83cacf9b61fcf4a" dependencies = [ - "cranelift-assembler-x64", + "cranelift-assembler-x64-meta", "cranelift-codegen-shared", + "cranelift-srcgen", ] [[package]] name = "cranelift-codegen-shared" -version = "0.118.0" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af50281b67324b58e843170a6a5943cf6d387c06f7eeacc9f5696e4ab7ae7d7e" +checksum = "97524b2446fc26a78142132d813679dda19f620048ebc9a9fbb0ac9f2d320dcb" [[package]] name = "cranelift-control" -version = "0.118.0" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c20c1b38d1abfbcebb0032e497e71156c0e3b8dcb3f0a92b9863b7bcaec290c" +checksum = "8e32e900aee81f9e3cc493405ef667a7812cb5c79b5fc6b669e0a2795bda4b22" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.118.0" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2c67d95507c51b4a1ff3f3555fe4bfec36b9e13c1b684ccc602736f5d5f4a2" +checksum = "d16a2e28e0fa6b9108d76879d60fe1cc95ba90e1bcf52bac96496371044484ee" dependencies = [ "cranelift-bitset", ] [[package]] name = "cranelift-frontend" -version = "0.118.0" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e002691cc69c38b54fc7ec93e5be5b744f627d027031d991cc845d1d512d0ce" +checksum = "328181a9083d99762d85954a16065d2560394a862b8dc10239f39668df528b95" dependencies = [ "cranelift-codegen", "log", @@ -144,15 +148,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.118.0" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e93588ed1796cbcb0e2ad160403509e2c5d330d80dd6e0014ac6774c7ebac496" +checksum = "e916f36f183e377e9a3ed71769f2721df88b72648831e95bb9fa6b0cd9b1c709" [[package]] name = "cranelift-jit" -version = "0.118.0" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f6682f0b193d6b7873cc8e7ed67e8776a8a26f50eeabf88534e9be618b9a03" +checksum = "d6bb584ac927f1076d552504b0075b833b9d61e2e9178ba55df6b2d966b4375d" dependencies = [ "anyhow", "cranelift-codegen", @@ -170,9 +174,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.118.0" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff19784c6de05116e63e6a34791012bd927b2a4eac56233039c46f1b6a4edac8" +checksum = "40c18ccb8e4861cf49cec79998af73b772a2b47212d12d3d63bf57cc4293a1e3" dependencies = [ "anyhow", "cranelift-codegen", @@ -181,9 +185,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.118.0" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5b09bdd6407bf5d89661b80cf926ce731c9e8cc184bf49102267a2369a8358e" +checksum = "fc852cf04128877047dc2027aa1b85c64f681dc3a6a37ff45dcbfa26e4d52d2f" dependencies = [ "cranelift-codegen", "libc", @@ -192,9 +196,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.118.0" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685e8661a30d1cb69509f589ac643adeee79c5f63c0da316431b9fad29e6d3b4" +checksum = "14f6ad789197bda49f7c98280ee8d7ccd63a5a1cc67283f87798a2d61e089ce4" dependencies = [ "anyhow", "cranelift-codegen", @@ -205,6 +209,12 @@ dependencies = [ "target-lexicon", ] +[[package]] +name = "cranelift-srcgen" +version = "0.119.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1a86340a16e74b4285cc86ac69458fa1c8e7aaff313da4a89d10efd3535ee" + [[package]] name = "crc32fast" version = "1.4.2" @@ -331,9 +341,9 @@ dependencies = [ [[package]] name = "regalloc2" -version = "0.11.1" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145c1c267e14f20fb0f88aa76a1c5ffec42d592c1d28b3cd9148ae35916158d3" +checksum = "6d4c3c15aa088eccea44550bffea9e9a5d0b14a264635323d23c6e6351acca98" dependencies = [ "allocator-api2", "bumpalo", @@ -436,9 +446,9 @@ checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "wasmtime-jit-icache-coherence" -version = "31.0.0" +version = "32.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a54f6c6c7e9d7eeee32dfcc10db7f29d505ee7dd28d00593ea241d5f70698e64" +checksum = "eb399eaabd7594f695e1159d236bf40ef55babcb3af97f97c027864ed2104db6" dependencies = [ "anyhow", "cfg-if", diff --git a/Cargo.toml b/Cargo.toml index 08b60de14c1f8..82fde4b838e13 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,12 +8,12 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.118.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } -cranelift-frontend = { version = "0.118.0" } -cranelift-module = { version = "0.118.0" } -cranelift-native = { version = "0.118.0" } -cranelift-jit = { version = "0.118.0", optional = true } -cranelift-object = { version = "0.118.0" } +cranelift-codegen = { version = "0.119.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } +cranelift-frontend = { version = "0.119.0" } +cranelift-module = { version = "0.119.0" } +cranelift-native = { version = "0.119.0" } +cranelift-jit = { version = "0.119.0", optional = true } +cranelift-object = { version = "0.119.0" } target-lexicon = "0.13" gimli = { version = "0.31", default-features = false, features = ["write"] } object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } @@ -24,12 +24,12 @@ smallvec = "1.8.1" [patch.crates-io] # Uncomment to use an unreleased version of cranelift -#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-31.0.0", version = "0.118.0" } -#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-31.0.0", version = "0.118.0" } -#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-31.0.0", version = "0.118.0" } -#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-31.0.0", version = "0.118.0" } -#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-31.0.0", version = "0.118.0" } -#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-31.0.0", version = "0.118.0" } +#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-32.0.0", version = "0.119.0" } +#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-32.0.0", version = "0.119.0" } +#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-32.0.0", version = "0.119.0" } +#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-32.0.0", version = "0.119.0" } +#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-32.0.0", version = "0.119.0" } +#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-32.0.0", version = "0.119.0" } # Uncomment to use local checkout of cranelift #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" } diff --git a/src/unwind_module.rs b/src/unwind_module.rs index f963dc79fbb5c..0864bd8d84f65 100644 --- a/src/unwind_module.rs +++ b/src/unwind_module.rs @@ -1,10 +1,10 @@ +use cranelift_codegen::Context; use cranelift_codegen::control::ControlPlane; -use cranelift_codegen::ir::{Function, Signature}; +use cranelift_codegen::ir::Signature; use cranelift_codegen::isa::{TargetFrontendConfig, TargetIsa}; -use cranelift_codegen::{Context, FinalizedMachReloc}; use cranelift_module::{ DataDescription, DataId, FuncId, FuncOrDataId, Linkage, Module, ModuleDeclarations, - ModuleResult, + ModuleReloc, ModuleResult, }; use cranelift_object::{ObjectModule, ObjectProduct}; @@ -101,10 +101,9 @@ impl Module for UnwindModule { fn define_function_bytes( &mut self, _func_id: FuncId, - _func: &Function, _alignment: u64, _bytes: &[u8], - _relocs: &[FinalizedMachReloc], + _relocs: &[ModuleReloc], ) -> ModuleResult<()> { unimplemented!() } From 0103c583fa01dd21d49fa9d5b2009e4c217659e2 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 21 Apr 2025 22:19:19 +0200 Subject: [PATCH 1874/4206] support `-Zmin-function-alignment` (#1572) --- src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index b86a549f57b94..6292606aef2e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -280,6 +280,12 @@ fn build_isa(sess: &Session, jit: bool) -> Arc { flags_builder.set("enable_llvm_abi_extensions", "true").unwrap(); + if let Some(align) = sess.opts.unstable_opts.min_function_alignment { + flags_builder + .set("log2_min_function_alignment", &align.bytes().ilog2().to_string()) + .unwrap(); + } + use rustc_session::config::OptLevel; match sess.opts.optimize { OptLevel::No => { From 13b94cf89f3e974fe697f80a5f2742ee4bccc05a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 22 Apr 2025 02:23:44 +0000 Subject: [PATCH 1875/4206] ci: Fix extensive tests Move this to a script and ensure only `libm-test` gets built to avoid default feature issues with `compiler-builtins`. --- .../.github/workflows/main.yaml | 17 +------------ library/compiler-builtins/ci/run-extensive.sh | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 16 deletions(-) create mode 100755 library/compiler-builtins/ci/run-extensive.sh diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index f7522a53d9d6c..d13dd6b0f6462 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -318,22 +318,7 @@ jobs: rustup default nightly - uses: Swatinem/rust-cache@v2 - name: Run extensive tests - run: | - echo "Tests to run: '$TO_TEST'" - if [ -z "$TO_TEST" ]; then - echo "No tests to run, exiting." - exit - fi - - set -x - - # Run the non-extensive tests first to catch any easy failures - cargo t --profile release-checked -- "$TO_TEST" - - LIBM_EXTENSIVE_TESTS="$TO_TEST" cargo test \ - --features build-mpfr,unstable,force-soft-floats \ - --profile release-checked \ - -- extensive + run: ./ci/run-extensive.sh - name: Print test logs if available run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi shell: bash diff --git a/library/compiler-builtins/ci/run-extensive.sh b/library/compiler-builtins/ci/run-extensive.sh new file mode 100755 index 0000000000000..4ba41a026fab6 --- /dev/null +++ b/library/compiler-builtins/ci/run-extensive.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +set -euo pipefail + +echo "Tests to run: '$TO_TEST'" + +if [ -z "$TO_TEST" ]; then + echo "No tests to run, exiting." + exit +fi + +set -x + +test_cmd=( + cargo test + --package libm-test + --features "build-mpfr,libm/unstable,libm/force-soft-floats" + --profile release-checked +) + +# Run the non-extensive tests first to catch any easy failures +"${test_cmd[@]}" -- "$TO_TEST" + +LIBM_EXTENSIVE_TESTS="$TO_TEST" "${test_cmd[@]}" -- extensive From a8652953e4741992865b626cfb10d676bc65b1cb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 22 Apr 2025 03:10:38 +0000 Subject: [PATCH 1876/4206] Rename the `public-test-deps` feature to `unstable-public-internals` `compiler-builtins` uses `public-test-deps`, `libm` uses `unstable-public-internals`. Consolidate these under the `libm` name. Once compiler-builtins is no longer published, this feature can probably be dropped. Also switch to `dep:` syntax for features that enable dependencies. --- library/compiler-builtins/builtins-test/Cargo.toml | 2 +- .../compiler-builtins/compiler-builtins/Cargo.toml | 12 ++++++------ .../compiler-builtins/src/float/mod.rs | 4 ++-- .../compiler-builtins/src/int/leading_zeros.rs | 4 ++-- .../compiler-builtins/src/int/mod.rs | 4 ++-- .../src/int/specialized_div_rem/mod.rs | 4 ++-- .../compiler-builtins/src/int/trailing_zeros.rs | 4 ++-- .../compiler-builtins/src/int/udiv.rs | 4 ++-- 8 files changed, 19 insertions(+), 19 deletions(-) diff --git a/library/compiler-builtins/builtins-test/Cargo.toml b/library/compiler-builtins/builtins-test/Cargo.toml index f7bcb52b40f03..10978c0bb7ed0 100644 --- a/library/compiler-builtins/builtins-test/Cargo.toml +++ b/library/compiler-builtins/builtins-test/Cargo.toml @@ -19,7 +19,7 @@ iai-callgrind = { version = "0.14.0", optional = true } [dependencies.compiler_builtins] path = "../compiler-builtins" default-features = false -features = ["public-test-deps"] +features = ["unstable-public-internals"] [dev-dependencies] criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index 1de37bd8683d8..1ea32c10ce46d 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/rust-lang/compiler-builtins" documentation = "https://docs.rs/compiler_builtins" edition = "2021" description = "Compiler intrinsics used by the Rust compiler." -links = 'compiler-rt' +links = "compiler-rt" [lib] bench = false @@ -19,20 +19,20 @@ test = false [dependencies] # For more information on this dependency see # https://github.com/rust-lang/rust/tree/master/library/rustc-std-workspace-core -core = { version = "1.0.0", optional = true, package = 'rustc-std-workspace-core' } +core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } [build-dependencies] cc = { optional = true, version = "1.0" } [dev-dependencies] -panic-handler = { path = '../crates/panic-handler' } +panic-handler = { path = "../crates/panic-handler" } [features] default = ["compiler-builtins"] # Enable compilation of C code in compiler-rt, filling in some more optimized # implementations and also filling in unimplemented intrinsics -c = ["cc"] +c = ["dep:cc"] # Workaround for the Cranelift codegen backend. Disables any implementations # which use inline assembly and fall back to pure Rust versions (if avalible). @@ -53,11 +53,11 @@ mem = [] mangled-names = [] # Only used in the compiler's build system -rustc-dep-of-std = ['compiler-builtins', 'core'] +rustc-dep-of-std = ["compiler-builtins", "dep:core"] # This makes certain traits and function specializations public that # are not normally public but are required by the `builtins-test` -public-test-deps = [] +unstable-public-internals = [] [lints.rust] # The cygwin config can be dropped after our benchmark toolchain is bumped diff --git a/library/compiler-builtins/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/compiler-builtins/src/float/mod.rs index f2c543bd2b7d9..4a379d0d3575b 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/mod.rs @@ -9,7 +9,7 @@ pub mod sub; pub(crate) mod traits; pub mod trunc; -#[cfg(not(feature = "public-test-deps"))] +#[cfg(not(feature = "unstable-public-internals"))] pub(crate) use traits::{Float, HalfRep}; -#[cfg(feature = "public-test-deps")] +#[cfg(feature = "unstable-public-internals")] pub use traits::{Float, HalfRep}; 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 a57f881848d1c..112f4d0361317 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs @@ -3,9 +3,9 @@ // adding a zero check at the beginning, but `__clzsi2` has a precondition that `x != 0`. // Compilers will insert the check for zero in cases where it is needed. -#[cfg(feature = "public-test-deps")] +#[cfg(feature = "unstable-public-internals")] pub use implementation::{leading_zeros_default, leading_zeros_riscv}; -#[cfg(not(feature = "public-test-deps"))] +#[cfg(not(feature = "unstable-public-internals"))] pub(crate) use implementation::{leading_zeros_default, leading_zeros_riscv}; mod implementation { diff --git a/library/compiler-builtins/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/compiler-builtins/src/int/mod.rs index 5633510d3c758..518ccb23f8009 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/mod.rs @@ -12,7 +12,7 @@ mod traits; pub mod udiv; pub use big::{i256, u256}; -#[cfg(not(feature = "public-test-deps"))] +#[cfg(not(feature = "unstable-public-internals"))] pub(crate) use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; -#[cfg(feature = "public-test-deps")] +#[cfg(feature = "unstable-public-internals")] pub use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; 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 b81f0469813a5..43f466e75ba4a 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 @@ -56,9 +56,9 @@ mod delegate; // used on SPARC #[allow(unused_imports)] -#[cfg(not(feature = "public-test-deps"))] +#[cfg(not(feature = "unstable-public-internals"))] pub(crate) use self::delegate::u128_divide_sparc; -#[cfg(feature = "public-test-deps")] +#[cfg(feature = "unstable-public-internals")] pub use self::delegate::u128_divide_sparc; #[macro_use] 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 dbc0cce9facc9..c45d6b1cfe8d8 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs @@ -1,6 +1,6 @@ -#[cfg(feature = "public-test-deps")] +#[cfg(feature = "unstable-public-internals")] pub use implementation::trailing_zeros; -#[cfg(not(feature = "public-test-deps"))] +#[cfg(not(feature = "unstable-public-internals"))] pub(crate) use implementation::trailing_zeros; mod implementation { diff --git a/library/compiler-builtins/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/compiler-builtins/src/int/udiv.rs index 4e985ba473936..b9dee63c4cc7a 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/udiv.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/udiv.rs @@ -1,6 +1,6 @@ -#[cfg(not(feature = "public-test-deps"))] +#[cfg(not(feature = "unstable-public-internals"))] pub(crate) use crate::int::specialized_div_rem::*; -#[cfg(feature = "public-test-deps")] +#[cfg(feature = "unstable-public-internals")] pub use crate::int::specialized_div_rem::*; intrinsics! { From e075e9fbde213c5fb0232c7a477f4f6dc199fc3d Mon Sep 17 00:00:00 2001 From: quaternic <57393910+quaternic@users.noreply.github.com> Date: Tue, 22 Apr 2025 03:56:51 +0300 Subject: [PATCH 1877/4206] Reimplement the generic fmod --- library/compiler-builtins/libm/src/lib.rs | 1 + .../libm/src/math/generic/fmod.rs | 116 ++++++++---------- .../libm/src/math/support/int_traits.rs | 4 + 3 files changed, 55 insertions(+), 66 deletions(-) diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 7df84fe1879b1..31b12235314cd 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -14,6 +14,7 @@ #![allow(clippy::excessive_precision)] #![allow(clippy::float_cmp)] #![allow(clippy::int_plus_one)] +#![allow(clippy::just_underscores_and_digits)] #![allow(clippy::many_single_char_names)] #![allow(clippy::mixed_case_hex_literals)] #![allow(clippy::needless_late_init)] diff --git a/library/compiler-builtins/libm/src/math/generic/fmod.rs b/library/compiler-builtins/libm/src/math/generic/fmod.rs index 6414bbd250812..e9898012fcc86 100644 --- a/library/compiler-builtins/libm/src/math/generic/fmod.rs +++ b/library/compiler-builtins/libm/src/math/generic/fmod.rs @@ -1,84 +1,68 @@ -/* SPDX-License-Identifier: MIT */ -/* origin: musl src/math/fmod.c. Ported to generic Rust algorithm in 2025, TG. */ - +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ use super::super::{CastFrom, Float, Int, MinInt}; #[inline] pub fn fmod(x: F, y: F) -> F { - let zero = F::Int::ZERO; - let one = F::Int::ONE; - let mut ix = x.to_bits(); - let mut iy = y.to_bits(); - let mut ex = x.ex().signed(); - let mut ey = y.ex().signed(); - let sx = ix & F::SIGN_MASK; + let _1 = F::Int::ONE; + let sx = x.to_bits() & F::SIGN_MASK; + let ux = x.to_bits() & !F::SIGN_MASK; + let uy = y.to_bits() & !F::SIGN_MASK; - if iy << 1 == zero || y.is_nan() || ex == F::EXP_SAT as i32 { + // Cases that return NaN: + // NaN % _ + // Inf % _ + // _ % NaN + // _ % 0 + let x_nan_or_inf = ux & F::EXP_MASK == F::EXP_MASK; + let y_nan_or_zero = uy.wrapping_sub(_1) & F::EXP_MASK == F::EXP_MASK; + if x_nan_or_inf | y_nan_or_zero { return (x * y) / (x * y); } - if ix << 1 <= iy << 1 { - if ix << 1 == iy << 1 { - return F::ZERO * x; - } + if ux < uy { + // |x| < |y| return x; } - /* normalize x and y */ - if ex == 0 { - let i = ix << (F::EXP_BITS + 1); - ex -= i.leading_zeros() as i32; - ix <<= -ex + 1; - } else { - ix &= F::Int::MAX >> F::EXP_BITS; - ix |= one << F::SIG_BITS; - } - - if ey == 0 { - let i = iy << (F::EXP_BITS + 1); - ey -= i.leading_zeros() as i32; - iy <<= -ey + 1; - } else { - iy &= F::Int::MAX >> F::EXP_BITS; - iy |= one << F::SIG_BITS; - } - - /* x mod y */ - while ex > ey { - let i = ix.wrapping_sub(iy); - if i >> (F::BITS - 1) == zero { - if i == zero { - return F::ZERO * x; - } - ix = i; - } + let (num, ex) = into_sig_exp::(ux); + let (div, ey) = into_sig_exp::(uy); - ix <<= 1; - ex -= 1; - } + // To compute `(num << ex) % (div << ey)`, first + // evaluate `rem = (num << (ex - ey)) % div` ... + let rem = reduction(num, ex - ey, div); + // ... so the result will be `rem << ey` - let i = ix.wrapping_sub(iy); - if i >> (F::BITS - 1) == zero { - if i == zero { - return F::ZERO * x; - } + if rem.is_zero() { + // Return zero with the sign of `x` + return F::from_bits(sx); + }; - ix = i; - } + // We would shift `rem` up by `ey`, but have to stop at `F::SIG_BITS` + let shift = ey.min(F::SIG_BITS - rem.ilog2()); + // Anything past that is added to the exponent field + let bits = (rem << shift) + (F::Int::cast_from(ey - shift) << F::SIG_BITS); + F::from_bits(sx + bits) +} - let shift = ix.leading_zeros().saturating_sub(F::EXP_BITS); - ix <<= shift; - ex -= shift as i32; +/// Given the bits of a finite float, return a tuple of +/// - the mantissa with the implicit bit (0 if subnormal, 1 otherwise) +/// - the additional exponent past 1, (0 for subnormal, 0 or more otherwise) +fn into_sig_exp(mut bits: F::Int) -> (F::Int, u32) { + bits &= !F::SIGN_MASK; + // Subtract 1 from the exponent, clamping at 0 + let sat = bits.checked_sub(F::IMPLICIT_BIT).unwrap_or(F::Int::ZERO); + ( + bits - (sat & F::EXP_MASK), + u32::cast_from(sat >> F::SIG_BITS), + ) +} - /* scale result */ - if ex > 0 { - ix -= one << F::SIG_BITS; - ix |= F::Int::cast_from(ex) << F::SIG_BITS; - } else { - ix >>= -ex + 1; +/// Compute the remainder `(x * 2.pow(e)) % y` without overflow. +fn reduction(mut x: I, e: u32, y: I) -> I { + x %= y; + for _ in 0..e { + x <<= 1; + x = x.checked_sub(y).unwrap_or(x); } - - ix |= sx; - - F::from_bits(ix) + x } 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 491adb1f22c35..3ec1faba170cb 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -40,6 +40,9 @@ pub trait Int: + PartialOrd + ops::AddAssign + ops::SubAssign + + ops::MulAssign + + ops::DivAssign + + ops::RemAssign + ops::BitAndAssign + ops::BitOrAssign + ops::BitXorAssign @@ -51,6 +54,7 @@ pub trait Int: + ops::Sub + ops::Mul + ops::Div + + ops::Rem + ops::Shl + ops::Shl + ops::Shr From 1fa9d0fce37a0349bc6eaec7f037b4fc88abd7d5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 21 Apr 2025 07:03:13 +0000 Subject: [PATCH 1878/4206] chore: release builtins 0.1.156 and libm 0.2.12 --- .../compiler-builtins/CHANGELOG.md | 12 +++++++ .../compiler-builtins/Cargo.toml | 2 +- library/compiler-builtins/libm/CHANGELOG.md | 36 +++++++++++++++++++ library/compiler-builtins/libm/Cargo.toml | 2 +- 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/compiler-builtins/CHANGELOG.md index 9916f2986e98c..3450da99202f3 100644 --- a/library/compiler-builtins/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/compiler-builtins/CHANGELOG.md @@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.156](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.155...compiler_builtins-v0.1.156) - 2025-04-21 + +### Other + +- avr: Provide `abort()` +- Remove `unsafe` from `naked_asm!` blocks +- Enable icount benchmarks in CI +- Move builtins-test-intrinsics out of the workspace +- Run `cargo fmt` on all projects +- Flatten the `libm/libm` directory +- Update path to libm after the merge + ## [0.1.155](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.154...compiler_builtins-v0.1.155) - 2025-04-17 ### Other diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index 1ea32c10ce46d..acbace687292f 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.155" +version = "0.1.156" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index 4e5acb899d2b7..c507608ddbc1a 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -8,6 +8,42 @@ and this project adheres to ## [Unreleased] +## [0.2.12](https://github.com/rust-lang/compiler-builtins/compare/libm-v0.2.11...libm-v0.2.12) - 2025-04-21 + +- Mark generic functions `#[inline]` +- Combine the source files for `fmod` +- Ensure all public functions are marked `no_panic` +- Add assembly version of simple operations on aarch64 +- Add `roundeven{,f,f16,f128}` +- Add `fminimum`, `fmaximum`, `fminimum_num`, and `fmaximum_num` +- Eliminate the use of `force_eval!` in `ceil`, `floor`, and `trunc` +- Port the CORE-MATH version of `cbrt` +- Add `fmaf128` +- fma: Ensure zero has the correct sign +- Add `scalbnf16`, `scalbnf128`, `ldexpf16`, and `ldexpf128` +- Specify license as just MIT +- Add `fmodf128` +- Add `fmodf16` using the generic implementation +- Add `fminf16`, `fmaxf16`, `fminf128`, and `fmaxf128` +- Add `roundf16` and `roundf128` +- Add `rintf16` and `rintf128` +- Add `floorf16` and `floorf128` +- Add `ceilf16` and `ceilf128` +- Add `sqrtf16` and `sqrtf128` +- Simplify and optimize `fdim` ([#442](https://github.com/rust-lang/libm/pull/442)) +- Add `fdimf16` and `fdimf128` +- Add `truncf16` and `truncf128` +- Add `fabsf16`, `fabsf128`, `copysignf16`, and `copysignf128` +- Move some numeric trait logic to default implementations +- Add some more basic docstrings ([#352](https://github.com/rust-lang/libm/pull/352)) +- Add support for loongarch64-unknown-linux-gnu +- Add an "arch" Cargo feature that is on by default +- Rename the `special_case` module to `precision` and move default ULP +- Move the existing "unstable" feature to "unstable-intrinsics" + +There are a number of things that changed internally, see the git log for a full +list of changes. + ## [0.2.11](https://github.com/rust-lang/libm/compare/libm-v0.2.10...libm-v0.2.11) - 2024-10-28 ### Fixed diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 4e3850bbff041..dc553ca4aaffa 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -version = "0.2.11" +version = "0.2.12" edition = "2021" rust-version = "1.63" From aec649faae092a09b17991499f142b50f348c91b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 22 Apr 2025 03:43:35 +0000 Subject: [PATCH 1879/4206] chore: Combine CHANGELOG files for compiler-builtins This unintentionally got split when compiler-builtins was moved to a subdirectory. --- library/compiler-builtins/CHANGELOG.md | 108 ------------------ .../compiler-builtins/CHANGELOG.md | 100 ++++++++++++++++ 2 files changed, 100 insertions(+), 108 deletions(-) delete mode 100644 library/compiler-builtins/CHANGELOG.md diff --git a/library/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/CHANGELOG.md deleted file mode 100644 index 763b0e10ed003..0000000000000 --- a/library/compiler-builtins/CHANGELOG.md +++ /dev/null @@ -1,108 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [Unreleased] - -## [0.1.151](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.150...compiler_builtins-v0.1.151) - 2025-03-05 - -### Other - -- Add cygwin support -- Enable `f16` for LoongArch ([#770](https://github.com/rust-lang/compiler-builtins/pull/770)) -- Add __extendhfdf2 and add __truncdfhf2 test -- Remove outdated information from the readme - -## [0.1.150](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.149...compiler_builtins-v0.1.150) - 2025-03-01 - -### Other - -- Disable `f16` on AArch64 without the `neon` feature -- Update LLVM downloads to 20.1-2025-02-13 - -## [0.1.149](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.148...compiler_builtins-v0.1.149) - 2025-02-25 - -### Other - -- Make a subset of `libm` symbols weakly available on all platforms - -## [0.1.148](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.147...compiler_builtins-v0.1.148) - 2025-02-24 - -### Other - -- Update the `libm` submodule -- Enable `f16` for MIPS -- Eliminate the use of `public_test_dep!` for a third time - -## [0.1.147](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.146...compiler_builtins-v0.1.147) - 2025-02-19 - -### Other - -- remove win64_128bit_abi_hack - -## [0.1.146](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.145...compiler_builtins-v0.1.146) - 2025-02-06 - -### Other - -- Expose erf{,c}{,f} from libm - -## [0.1.145](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.144...compiler_builtins-v0.1.145) - 2025-02-04 - -### Other - -- Revert "Eliminate the use of `public_test_dep!`" -- Indentation fix to please clippy -- Don't build out of line atomics support code for uefi -- Add a version to some FIXMEs that will be resolved in LLVM 20 -- Remove use of the `start` feature - -## [0.1.144](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.143...compiler_builtins-v0.1.144) - 2025-01-15 - -### Other - -- Eliminate the use of `public_test_dep!` - -## [0.1.143](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.142...compiler_builtins-v0.1.143) - 2025-01-15 - -### Other - -- Use a C-safe return type for `__rust_[ui]128_*` overflowing intrinsics - -## [0.1.142](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.141...compiler_builtins-v0.1.142) - 2025-01-07 - -### Other - -- Account for optimization levels other than numbers - -## [0.1.141](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.140...compiler_builtins-v0.1.141) - 2025-01-07 - -### Other - -- Update the `libm` submodule -- Fix new `clippy::precedence` errors -- Rename `EXP_MAX` to `EXP_SAT` -- Shorten prefixes for float constants - -## [0.1.140](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.139...compiler_builtins-v0.1.140) - 2024-12-26 - -### Other - -- Disable f128 for amdgpu ([#737](https://github.com/rust-lang/compiler-builtins/pull/737)) -- Fix a bug in `abs_diff` -- Disable `f16` on platforms that have recursion problems - -## [0.1.139](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.138...compiler_builtins-v0.1.139) - 2024-11-03 - -### Other - -- Remove incorrect `sparcv9` match pattern from `configure_f16_f128` - -## [0.1.138](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.137...compiler_builtins-v0.1.138) - 2024-11-01 - -### Other - -- Use `f16_enabled`/`f128_enabled` in `examples/intrinsics.rs` ([#724](https://github.com/rust-lang/compiler-builtins/pull/724)) -- Disable `f16` for LoongArch64 ([#722](https://github.com/rust-lang/compiler-builtins/pull/722)) diff --git a/library/compiler-builtins/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/compiler-builtins/CHANGELOG.md index 3450da99202f3..34b413a86831b 100644 --- a/library/compiler-builtins/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/compiler-builtins/CHANGELOG.md @@ -48,3 +48,103 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Remove use of `atomic_load_unordered` and undefined behaviour from `arm_linux.rs` - Switch repository layout to use a virtual manifest + +## [0.1.151](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.150...compiler_builtins-v0.1.151) - 2025-03-05 + +### Other + +- Add cygwin support +- Enable `f16` for LoongArch ([#770](https://github.com/rust-lang/compiler-builtins/pull/770)) +- Add __extendhfdf2 and add __truncdfhf2 test +- Remove outdated information from the readme + +## [0.1.150](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.149...compiler_builtins-v0.1.150) - 2025-03-01 + +### Other + +- Disable `f16` on AArch64 without the `neon` feature +- Update LLVM downloads to 20.1-2025-02-13 + +## [0.1.149](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.148...compiler_builtins-v0.1.149) - 2025-02-25 + +### Other + +- Make a subset of `libm` symbols weakly available on all platforms + +## [0.1.148](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.147...compiler_builtins-v0.1.148) - 2025-02-24 + +### Other + +- Update the `libm` submodule +- Enable `f16` for MIPS +- Eliminate the use of `public_test_dep!` for a third time + +## [0.1.147](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.146...compiler_builtins-v0.1.147) - 2025-02-19 + +### Other + +- remove win64_128bit_abi_hack + +## [0.1.146](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.145...compiler_builtins-v0.1.146) - 2025-02-06 + +### Other + +- Expose erf{,c}{,f} from libm + +## [0.1.145](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.144...compiler_builtins-v0.1.145) - 2025-02-04 + +### Other + +- Revert "Eliminate the use of `public_test_dep!`" +- Indentation fix to please clippy +- Don't build out of line atomics support code for uefi +- Add a version to some FIXMEs that will be resolved in LLVM 20 +- Remove use of the `start` feature + +## [0.1.144](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.143...compiler_builtins-v0.1.144) - 2025-01-15 + +### Other + +- Eliminate the use of `public_test_dep!` + +## [0.1.143](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.142...compiler_builtins-v0.1.143) - 2025-01-15 + +### Other + +- Use a C-safe return type for `__rust_[ui]128_*` overflowing intrinsics + +## [0.1.142](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.141...compiler_builtins-v0.1.142) - 2025-01-07 + +### Other + +- Account for optimization levels other than numbers + +## [0.1.141](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.140...compiler_builtins-v0.1.141) - 2025-01-07 + +### Other + +- Update the `libm` submodule +- Fix new `clippy::precedence` errors +- Rename `EXP_MAX` to `EXP_SAT` +- Shorten prefixes for float constants + +## [0.1.140](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.139...compiler_builtins-v0.1.140) - 2024-12-26 + +### Other + +- Disable f128 for amdgpu ([#737](https://github.com/rust-lang/compiler-builtins/pull/737)) +- Fix a bug in `abs_diff` +- Disable `f16` on platforms that have recursion problems + +## [0.1.139](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.138...compiler_builtins-v0.1.139) - 2024-11-03 + +### Other + +- Remove incorrect `sparcv9` match pattern from `configure_f16_f128` + +## [0.1.138](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.137...compiler_builtins-v0.1.138) - 2024-11-01 + +### Other + +- Use `f16_enabled`/`f128_enabled` in `examples/intrinsics.rs` ([#724](https://github.com/rust-lang/compiler-builtins/pull/724)) +- Disable `f16` for LoongArch64 ([#722](https://github.com/rust-lang/compiler-builtins/pull/722)) From d30dde73b35da060279ca40409975d50eba1139f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 22 Apr 2025 07:46:09 +0000 Subject: [PATCH 1880/4206] fix: Switch to resolver v2 The published crates fail to build with an edition less than 2024 because they are packaged with `resolver = "3"`, which is a 2024-only option. Revert back to resolver v2 to drop this requirement. Fixes: https://github.com/rust-lang/compiler-builtins/issues/883 --- library/compiler-builtins/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 75bb81ec18772..b39ec8a25dac1 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -resolver = "3" +resolver = "2" members = [ "builtins-test", "compiler-builtins", From 5028ecd025fc051fc191d1fb569cd22932b98f60 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 22 Apr 2025 08:05:23 +0000 Subject: [PATCH 1881/4206] chore: Release libm v0.2.13 --- library/compiler-builtins/libm/CHANGELOG.md | 6 ++++++ library/compiler-builtins/libm/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md index c507608ddbc1a..292561f86ab81 100644 --- a/library/compiler-builtins/libm/CHANGELOG.md +++ b/library/compiler-builtins/libm/CHANGELOG.md @@ -8,6 +8,12 @@ and this project adheres to ## [Unreleased] +## [0.2.13](https://github.com/rust-lang/compiler-builtins/compare/libm-v0.2.12...libm-v0.2.13) - 2025-04-21 + +### Fixed + +- Switch back to workspace resolver v2 to unbreak builds without the 2024 edition + ## [0.2.12](https://github.com/rust-lang/compiler-builtins/compare/libm-v0.2.11...libm-v0.2.12) - 2025-04-21 - Mark generic functions `#[inline]` diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index dc553ca4aaffa..f80715ff6c59d 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT" name = "libm" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -version = "0.2.12" +version = "0.2.13" edition = "2021" rust-version = "1.63" From e7efab9ec95449d6565fec41d94c69abf5d3088a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 22 Apr 2025 09:37:46 +0200 Subject: [PATCH 1882/4206] remove intrinsics::drop_in_place --- library/core/src/intrinsics/mod.rs | 9 --------- .../inline/inline_shims.drop.Inline.panic-abort.diff | 10 +++++----- .../inline_shims.drop.Inline.panic-unwind.diff | 6 +++--- tests/mir-opt/inline/inline_shims.rs | 2 +- ....Test.SimplifyCfg-make_shim.after.panic-abort.mir | 4 ++-- ...Test.SimplifyCfg-make_shim.after.panic-unwind.mir | 4 ++-- ...ace.[String;42].AddMovesForPackedDrops.before.mir | 4 ++-- ..._place.[String].AddMovesForPackedDrops.before.mir | 4 ++-- ..._place.Vec_i32_.AddMovesForPackedDrops.before.mir | 4 ++-- tests/ui/consts/miri_unleashed/assoc_const.stderr | 6 +++--- tests/ui/consts/miri_unleashed/drop.rs | 2 +- tests/ui/consts/miri_unleashed/drop.stderr | 2 +- tests/ui/consts/qualif-indirect-mutation-fail.stderr | 12 ++++++------ .../issue-99286-stable-intrinsics.rs | 3 +-- 14 files changed, 31 insertions(+), 41 deletions(-) diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index a01efb2adebe3..7e052865046bd 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -74,15 +74,6 @@ pub mod simd; #[cfg(all(target_has_atomic = "8", target_has_atomic = "32", target_has_atomic = "ptr"))] use crate::sync::atomic::{self, AtomicBool, AtomicI32, AtomicIsize, AtomicU32, Ordering}; -#[stable(feature = "drop_in_place", since = "1.8.0")] -#[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"] -#[deprecated(note = "no longer an intrinsic - use `ptr::drop_in_place` directly", since = "1.52.0")] -#[inline] -pub unsafe fn drop_in_place(to_drop: *mut T) { - // SAFETY: see `ptr::drop_in_place` - unsafe { crate::ptr::drop_in_place(to_drop) } -} - // N.B., these intrinsics take raw pointers because they mutate aliased // memory, which is not valid for either `&` or `&mut`. diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff index 4337e0da18336..f6c111a2228a9 100644 --- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff @@ -8,7 +8,7 @@ let _3: (); let mut _4: *mut std::vec::Vec
; let mut _5: *mut std::option::Option; -+ scope 1 (inlined std::ptr::drop_in_place::> - shim(Some(Vec))) { ++ scope 1 (inlined drop_in_place::> - shim(Some(Vec))) { + let mut _6: &mut std::vec::Vec; + let mut _7: (); + scope 2 (inlined as Drop>::drop) { @@ -38,14 +38,14 @@ + scope 13 (inlined std::ptr::from_raw_parts_mut::<[A], A>) { + } + } -+ scope 14 (inlined std::ptr::drop_in_place::<[A]> - shim(Some([A]))) { ++ scope 14 (inlined drop_in_place::<[A]> - shim(Some([A]))) { + let mut _12: usize; + let mut _13: *mut A; + let mut _14: bool; + } + } + } -+ scope 15 (inlined std::ptr::drop_in_place::> - shim(Some(Option))) { ++ scope 15 (inlined drop_in_place::> - shim(Some(Option))) { + let mut _15: isize; + let mut _16: isize; + } @@ -54,7 +54,7 @@ StorageLive(_3); StorageLive(_4); _4 = copy _1; -- _3 = std::ptr::drop_in_place::>(move _4) -> [return: bb1, unwind unreachable]; +- _3 = drop_in_place::>(move _4) -> [return: bb1, unwind unreachable]; + StorageLive(_6); + StorageLive(_7); + _6 = &mut (*_4); @@ -82,7 +82,7 @@ StorageDead(_3); StorageLive(_5); _5 = copy _2; -- _0 = std::ptr::drop_in_place::>(move _5) -> [return: bb2, unwind unreachable]; +- _0 = drop_in_place::>(move _5) -> [return: bb2, unwind unreachable]; + StorageLive(_15); + StorageLive(_16); + _15 = discriminant((*_5)); diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff index d89ca003d77b3..1832427642528 100644 --- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff @@ -8,7 +8,7 @@ let _3: (); let mut _4: *mut std::vec::Vec; let mut _5: *mut std::option::Option; -+ scope 1 (inlined std::ptr::drop_in_place::> - shim(Some(Option))) { ++ scope 1 (inlined drop_in_place::> - shim(Some(Option))) { + let mut _6: isize; + let mut _7: isize; + } @@ -17,7 +17,7 @@ StorageLive(_3); StorageLive(_4); _4 = copy _1; - _3 = std::ptr::drop_in_place::>(move _4) -> [return: bb1, unwind continue]; + _3 = drop_in_place::>(move _4) -> [return: bb1, unwind continue]; } bb1: { @@ -25,7 +25,7 @@ StorageDead(_3); StorageLive(_5); _5 = copy _2; -- _0 = std::ptr::drop_in_place::>(move _5) -> [return: bb2, unwind continue]; +- _0 = drop_in_place::>(move _5) -> [return: bb2, unwind continue]; + StorageLive(_6); + StorageLive(_7); + _6 = discriminant((*_5)); diff --git a/tests/mir-opt/inline/inline_shims.rs b/tests/mir-opt/inline/inline_shims.rs index a223c2d2614b1..bd6cdd78157c2 100644 --- a/tests/mir-opt/inline/inline_shims.rs +++ b/tests/mir-opt/inline/inline_shims.rs @@ -11,7 +11,7 @@ pub fn clone(f: fn(A, B)) -> fn(A, B) { // EMIT_MIR inline_shims.drop.Inline.diff pub fn drop(a: *mut Vec, b: *mut Option) { // CHECK-LABEL: fn drop( - // CHECK: (inlined std::ptr::drop_in_place::> - shim(Some(Option))) + // CHECK: (inlined drop_in_place::> - shim(Some(Option))) unsafe { std::ptr::drop_in_place(a) } unsafe { std::ptr::drop_in_place(b) } } diff --git a/tests/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.panic-abort.mir b/tests/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.panic-abort.mir index 146f4240f308a..7be3ab8cbae92 100644 --- a/tests/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.panic-abort.mir +++ b/tests/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.panic-abort.mir @@ -1,6 +1,6 @@ -// MIR for `std::ptr::drop_in_place` after SimplifyCfg-make_shim +// MIR for `drop_in_place` after SimplifyCfg-make_shim -fn std::ptr::drop_in_place(_1: *mut Test) -> () { +fn drop_in_place(_1: *mut Test) -> () { let mut _0: (); let mut _2: &mut Test; let mut _3: &mut Test; diff --git a/tests/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.panic-unwind.mir b/tests/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.panic-unwind.mir index 70c53bafa3737..6c3c1aaa2bd2b 100644 --- a/tests/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.panic-unwind.mir +++ b/tests/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.panic-unwind.mir @@ -1,6 +1,6 @@ -// MIR for `std::ptr::drop_in_place` after SimplifyCfg-make_shim +// MIR for `drop_in_place` after SimplifyCfg-make_shim -fn std::ptr::drop_in_place(_1: *mut Test) -> () { +fn drop_in_place(_1: *mut Test) -> () { let mut _0: (); let mut _2: &mut Test; let mut _3: &mut Test; diff --git a/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String;42].AddMovesForPackedDrops.before.mir b/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String;42].AddMovesForPackedDrops.before.mir index 13df2195ab04d..9d5af8e84e4f1 100644 --- a/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String;42].AddMovesForPackedDrops.before.mir +++ b/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String;42].AddMovesForPackedDrops.before.mir @@ -1,6 +1,6 @@ -// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops +// MIR for `drop_in_place` before AddMovesForPackedDrops -fn std::ptr::drop_in_place(_1: *mut [String; 42]) -> () { +fn drop_in_place(_1: *mut [String; 42]) -> () { let mut _0: (); let mut _2: *mut [std::string::String; 42]; let mut _3: *mut [std::string::String]; diff --git a/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir b/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir index 0633b765644d5..144880d15989c 100644 --- a/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir +++ b/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir @@ -1,6 +1,6 @@ -// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops +// MIR for `drop_in_place` before AddMovesForPackedDrops -fn std::ptr::drop_in_place(_1: *mut [String]) -> () { +fn drop_in_place(_1: *mut [String]) -> () { let mut _0: (); let mut _2: usize; let mut _3: usize; diff --git a/tests/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir b/tests/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir index b587941835515..51ef9f7c068ec 100644 --- a/tests/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir +++ b/tests/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir @@ -1,6 +1,6 @@ -// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops +// MIR for `drop_in_place` before AddMovesForPackedDrops -fn std::ptr::drop_in_place(_1: *mut Vec) -> () { +fn drop_in_place(_1: *mut Vec) -> () { let mut _0: (); let mut _2: &mut std::vec::Vec; let mut _3: (); diff --git a/tests/ui/consts/miri_unleashed/assoc_const.stderr b/tests/ui/consts/miri_unleashed/assoc_const.stderr index f259765f6e57a..758f1a2533990 100644 --- a/tests/ui/consts/miri_unleashed/assoc_const.stderr +++ b/tests/ui/consts/miri_unleashed/assoc_const.stderr @@ -1,12 +1,12 @@ -error[E0080]: evaluation of `std::ptr::drop_in_place::> - shim(Some(Vec))` failed +error[E0080]: evaluation of `drop_in_place::> - shim(Some(Vec))` failed --> $DIR/assoc_const.rs:12:31 | LL | const F: u32 = (U::X, 42).1; | ^ calling non-const function ` as Drop>::drop` | -note: inside `std::ptr::drop_in_place::<(Vec, u32)> - shim(Some((Vec, u32)))` +note: inside `drop_in_place::<(Vec, u32)> - shim(Some((Vec, u32)))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -note: inside `std::ptr::drop_in_place::> - shim(Some(Vec))` +note: inside `drop_in_place::> - shim(Some(Vec))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL note: erroneous constant encountered diff --git a/tests/ui/consts/miri_unleashed/drop.rs b/tests/ui/consts/miri_unleashed/drop.rs index 190072d9c2062..ff9281358d4b3 100644 --- a/tests/ui/consts/miri_unleashed/drop.rs +++ b/tests/ui/consts/miri_unleashed/drop.rs @@ -15,6 +15,6 @@ static TEST_BAD: () = { let _v: Vec = Vec::new(); }; //~ ERROR could not evaluate static initializer //~| NOTE calling non-const function ` as Drop>::drop` - //~| NOTE inside `std::ptr::drop_in_place::> - shim(Some(Vec))` + //~| NOTE inside `drop_in_place::> - shim(Some(Vec))` //~? WARN skipping const checks diff --git a/tests/ui/consts/miri_unleashed/drop.stderr b/tests/ui/consts/miri_unleashed/drop.stderr index f9ff5491ea6c0..0286c43127945 100644 --- a/tests/ui/consts/miri_unleashed/drop.stderr +++ b/tests/ui/consts/miri_unleashed/drop.stderr @@ -4,7 +4,7 @@ error[E0080]: could not evaluate static initializer LL | }; | ^ calling non-const function ` as Drop>::drop` | -note: inside `std::ptr::drop_in_place::> - shim(Some(Vec))` +note: inside `drop_in_place::> - shim(Some(Vec))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL warning: skipping const checks diff --git a/tests/ui/consts/qualif-indirect-mutation-fail.stderr b/tests/ui/consts/qualif-indirect-mutation-fail.stderr index d3bb01af7547e..dd575e07c2013 100644 --- a/tests/ui/consts/qualif-indirect-mutation-fail.stderr +++ b/tests/ui/consts/qualif-indirect-mutation-fail.stderr @@ -13,11 +13,11 @@ error[E0080]: evaluation of constant value failed LL | }; | ^ calling non-const function ` as Drop>::drop` | -note: inside `std::ptr::drop_in_place::> - shim(Some(Option))` +note: inside `drop_in_place::> - shim(Some(Option))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -note: inside `std::ptr::drop_in_place:: - shim(Some(String))` +note: inside `drop_in_place:: - shim(Some(String))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -note: inside `std::ptr::drop_in_place::> - shim(Some(Vec))` +note: inside `drop_in_place::> - shim(Some(Vec))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL error[E0493]: destructor of `Option` cannot be evaluated at compile-time @@ -34,11 +34,11 @@ error[E0080]: evaluation of constant value failed LL | }; | ^ calling non-const function ` as Drop>::drop` | -note: inside `std::ptr::drop_in_place::> - shim(Some(Option))` +note: inside `drop_in_place::> - shim(Some(Option))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -note: inside `std::ptr::drop_in_place:: - shim(Some(String))` +note: inside `drop_in_place:: - shim(Some(String))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -note: inside `std::ptr::drop_in_place::> - shim(Some(Vec))` +note: inside `drop_in_place::> - shim(Some(Vec))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL error[E0493]: destructor of `(u32, Option)` cannot be evaluated at compile-time diff --git a/tests/ui/stability-attribute/issue-99286-stable-intrinsics.rs b/tests/ui/stability-attribute/issue-99286-stable-intrinsics.rs index b76603740ff9b..d9e810362f2e9 100644 --- a/tests/ui/stability-attribute/issue-99286-stable-intrinsics.rs +++ b/tests/ui/stability-attribute/issue-99286-stable-intrinsics.rs @@ -8,10 +8,9 @@ #![allow(unused_imports)] #![allow(deprecated)] -use std::intrinsics::drop_in_place as _; use std::intrinsics::copy_nonoverlapping as _; use std::intrinsics::copy as _; use std::intrinsics::write_bytes as _; -use std::intrinsics::{drop_in_place, copy_nonoverlapping, copy, write_bytes}; +use std::intrinsics::{copy_nonoverlapping, copy, write_bytes}; fn main() {} From b6db36061e83d5e0566331e78d8f80423cf3757e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 22 Apr 2025 16:30:17 -0400 Subject: [PATCH 1883/4206] musl: Update submodule Update the musl submodule to c47ad25ea3 ("iconv: harden UTF-8 output code path against input decoder bugs"). --- library/compiler-builtins/crates/musl-math-sys/musl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/crates/musl-math-sys/musl b/library/compiler-builtins/crates/musl-math-sys/musl index 61399d4bd02ae..c47ad25ea3b48 160000 --- a/library/compiler-builtins/crates/musl-math-sys/musl +++ b/library/compiler-builtins/crates/musl-math-sys/musl @@ -1 +1 @@ -Subproject commit 61399d4bd02ae1ec03068445aa7ffe9174466bfd +Subproject commit c47ad25ea3b484e10326f933e927c0bc8cded3da From 1dd39e27f06d0028bc62452283cf00a2d932d981 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 23 Apr 2025 06:46:31 +0000 Subject: [PATCH 1884/4206] libm-macros: Start tracking which functions are public It would be nice to reuse some of the macro structure for internal functions, like `rem_pio2`. To facilitate this, add a `public` field and make it available in the macro's API. --- .../crates/libm-macros/src/lib.rs | 6 +- .../crates/libm-macros/src/shared.rs | 383 ++++++++++-------- .../crates/libm-macros/tests/basic.rs | 2 + library/compiler-builtins/libm-test/src/op.rs | 10 +- 4 files changed, 226 insertions(+), 175 deletions(-) diff --git a/library/compiler-builtins/crates/libm-macros/src/lib.rs b/library/compiler-builtins/crates/libm-macros/src/lib.rs index 3cdd364e83000..144676c125364 100644 --- a/library/compiler-builtins/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/crates/libm-macros/src/lib.rs @@ -12,7 +12,7 @@ use syn::visit_mut::VisitMut; use syn::{Ident, ItemEnum}; const KNOWN_TYPES: &[&str] = &[ - "FTy", "CFn", "CArgs", "CRet", "RustFn", "RustArgs", "RustRet", + "FTy", "CFn", "CArgs", "CRet", "RustFn", "RustArgs", "RustRet", "public", ]; /// Populate an enum with a variant representing function. Names are in upper camel case. @@ -80,6 +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, /// // Attributes for the current function, if any /// attrs: [$($attr:meta),*], /// // Extra tokens passed directly (if any) @@ -329,6 +331,7 @@ 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"), }; ty_fields.push(field); diff --git a/library/compiler-builtins/crates/libm-macros/src/shared.rs b/library/compiler-builtins/crates/libm-macros/src/shared.rs index 750ed1afb057a..1cefe4e8c7ed4 100644 --- a/library/compiler-builtins/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/crates/libm-macros/src/shared.rs @@ -3,16 +3,26 @@ use std::fmt; use std::sync::LazyLock; -const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] = &[ - ( +struct NestedOp { + float_ty: FloatTy, + rust_sig: Signature, + c_sig: Option, + fn_list: &'static [&'static str], + public: bool, +} + +/// 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] = &[ + NestedOp { // `fn(f16) -> f16` - FloatTy::F16, - Signature { + float_ty: FloatTy::F16, + rust_sig: Signature { args: &[Ty::F16], returns: &[Ty::F16], }, - None, - &[ + c_sig: None, + fn_list: &[ "ceilf16", "fabsf16", "floorf16", @@ -22,16 +32,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "sqrtf16", "truncf16", ], - ), - ( + public: true, + }, + NestedOp { // `fn(f32) -> f32` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::F32], }, - None, - &[ + c_sig: None, + fn_list: &[ "acosf", "acoshf", "asinf", @@ -70,16 +81,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "y0f", "y1f", ], - ), - ( + public: true, + }, + NestedOp { // `(f64) -> f64` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::F64], }, - None, - &[ + c_sig: None, + fn_list: &[ "acos", "acosh", "asin", @@ -118,16 +130,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "y0", "y1", ], - ), - ( + public: true, + }, + NestedOp { // `fn(f128) -> f128` - FloatTy::F128, - Signature { + float_ty: FloatTy::F128, + rust_sig: Signature { args: &[Ty::F128], returns: &[Ty::F128], }, - None, - &[ + c_sig: None, + fn_list: &[ "ceilf128", "fabsf128", "floorf128", @@ -137,16 +150,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "sqrtf128", "truncf128", ], - ), - ( + public: true, + }, + NestedOp { // `(f16, f16) -> f16` - FloatTy::F16, - Signature { + float_ty: FloatTy::F16, + rust_sig: Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16], }, - None, - &[ + c_sig: None, + fn_list: &[ "copysignf16", "fdimf16", "fmaxf16", @@ -157,16 +171,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "fminimumf16", "fmodf16", ], - ), - ( + public: true, + }, + NestedOp { // `(f32, f32) -> f32` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32], }, - None, - &[ + c_sig: None, + fn_list: &[ "atan2f", "copysignf", "fdimf", @@ -182,16 +197,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "powf", "remainderf", ], - ), - ( + public: true, + }, + NestedOp { // `(f64, f64) -> f64` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64], }, - None, - &[ + c_sig: None, + fn_list: &[ "atan2", "copysign", "fdim", @@ -207,16 +223,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "pow", "remainder", ], - ), - ( + public: true, + }, + NestedOp { // `(f128, f128) -> f128` - FloatTy::F128, - Signature { + float_ty: FloatTy::F128, + rust_sig: Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128], }, - None, - &[ + c_sig: None, + fn_list: &[ "copysignf128", "fdimf128", "fmaxf128", @@ -227,221 +244,241 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "fminimumf128", "fmodf128", ], - ), - ( + public: true, + }, + NestedOp { // `(f32, f32, f32) -> f32` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32, Ty::F32, Ty::F32], returns: &[Ty::F32], }, - None, - &["fmaf"], - ), - ( + c_sig: None, + fn_list: &["fmaf"], + public: true, + }, + NestedOp { // `(f64, f64, f64) -> f64` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64, Ty::F64, Ty::F64], returns: &[Ty::F64], }, - None, - &["fma"], - ), - ( + c_sig: None, + fn_list: &["fma"], + public: true, + }, + NestedOp { // `(f128, f128, f128) -> f128` - FloatTy::F128, - Signature { + float_ty: FloatTy::F128, + rust_sig: Signature { args: &[Ty::F128, Ty::F128, Ty::F128], returns: &[Ty::F128], }, - None, - &["fmaf128"], - ), - ( + c_sig: None, + fn_list: &["fmaf128"], + public: true, + }, + NestedOp { // `(f32) -> i32` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::I32], }, - None, - &["ilogbf"], - ), - ( + c_sig: None, + fn_list: &["ilogbf"], + public: true, + }, + NestedOp { // `(f64) -> i32` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::I32], }, - None, - &["ilogb"], - ), - ( + c_sig: None, + fn_list: &["ilogb"], + public: true, + }, + NestedOp { // `(i32, f32) -> f32` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::I32, Ty::F32], returns: &[Ty::F32], }, - None, - &["jnf", "ynf"], - ), - ( + c_sig: None, + fn_list: &["jnf", "ynf"], + public: true, + }, + NestedOp { // `(i32, f64) -> f64` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::I32, Ty::F64], returns: &[Ty::F64], }, - None, - &["jn", "yn"], - ), - ( + c_sig: None, + fn_list: &["jn", "yn"], + public: true, + }, + NestedOp { // `(f16, i32) -> f16` - FloatTy::F16, - Signature { + float_ty: FloatTy::F16, + rust_sig: Signature { args: &[Ty::F16, Ty::I32], returns: &[Ty::F16], }, - None, - &["ldexpf16", "scalbnf16"], - ), - ( + c_sig: None, + fn_list: &["ldexpf16", "scalbnf16"], + public: true, + }, + NestedOp { // `(f32, i32) -> f32` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32, Ty::I32], returns: &[Ty::F32], }, - None, - &["ldexpf", "scalbnf"], - ), - ( + c_sig: None, + fn_list: &["ldexpf", "scalbnf"], + public: true, + }, + NestedOp { // `(f64, i64) -> f64` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64, Ty::I32], returns: &[Ty::F64], }, - None, - &["ldexp", "scalbn"], - ), - ( + c_sig: None, + fn_list: &["ldexp", "scalbn"], + public: true, + }, + NestedOp { // `(f128, i32) -> f128` - FloatTy::F128, - Signature { + float_ty: FloatTy::F128, + rust_sig: Signature { args: &[Ty::F128, Ty::I32], returns: &[Ty::F128], }, - None, - &["ldexpf128", "scalbnf128"], - ), - ( + c_sig: None, + fn_list: &["ldexpf128", "scalbnf128"], + public: true, + }, + NestedOp { // `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32], }, - Some(Signature { + c_sig: Some(Signature { args: &[Ty::F32, Ty::MutF32], returns: &[Ty::F32], }), - &["modff"], - ), - ( + fn_list: &["modff"], + public: true, + }, + NestedOp { // `(f64, &mut f64) -> f64` as `(f64) -> (f64, f64)` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64], }, - Some(Signature { + c_sig: Some(Signature { args: &[Ty::F64, Ty::MutF64], returns: &[Ty::F64], }), - &["modf"], - ), - ( + fn_list: &["modf"], + public: true, + }, + NestedOp { // `(f32, &mut c_int) -> f32` as `(f32) -> (f32, i32)` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::I32], }, - Some(Signature { + c_sig: Some(Signature { args: &[Ty::F32, Ty::MutCInt], returns: &[Ty::F32], }), - &["frexpf", "lgammaf_r"], - ), - ( + fn_list: &["frexpf", "lgammaf_r"], + public: true, + }, + NestedOp { // `(f64, &mut c_int) -> f64` as `(f64) -> (f64, i32)` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::I32], }, - Some(Signature { + c_sig: Some(Signature { args: &[Ty::F64, Ty::MutCInt], returns: &[Ty::F64], }), - &["frexp", "lgamma_r"], - ), - ( + fn_list: &["frexp", "lgamma_r"], + public: true, + }, + NestedOp { // `(f32, f32, &mut c_int) -> f32` as `(f32, f32) -> (f32, i32)` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32, Ty::I32], }, - Some(Signature { + c_sig: Some(Signature { args: &[Ty::F32, Ty::F32, Ty::MutCInt], returns: &[Ty::F32], }), - &["remquof"], - ), - ( + fn_list: &["remquof"], + public: true, + }, + NestedOp { // `(f64, f64, &mut c_int) -> f64` as `(f64, f64) -> (f64, i32)` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64, Ty::I32], }, - Some(Signature { + c_sig: Some(Signature { args: &[Ty::F64, Ty::F64, Ty::MutCInt], returns: &[Ty::F64], }), - &["remquo"], - ), - ( + fn_list: &["remquo"], + public: true, + }, + NestedOp { // `(f32, &mut f32, &mut f32)` as `(f32) -> (f32, f32)` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32], }, - Some(Signature { + c_sig: Some(Signature { args: &[Ty::F32, Ty::MutF32, Ty::MutF32], returns: &[], }), - &["sincosf"], - ), - ( + fn_list: &["sincosf"], + public: true, + }, + NestedOp { // `(f64, &mut f64, &mut f64)` as `(f64) -> (f64, f64)` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64], }, - Some(Signature { + c_sig: Some(Signature { args: &[Ty::F64, Ty::MutF64, Ty::MutF64], returns: &[], }), - &["sincos"], - ), + fn_list: &["sincos"], + public: true, + }, ]; /// A type used in a function signature. @@ -520,27 +557,31 @@ 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, } /// A flat representation of `ALL_FUNCTIONS`. pub static ALL_OPERATIONS: LazyLock> = LazyLock::new(|| { let mut ret = Vec::new(); - for (base_fty, rust_sig, c_sig, names) in ALL_OPERATIONS_NESTED { - for name in *names { + for op in ALL_OPERATIONS_NESTED { + let fn_names = op.fn_list; + for name in fn_names { let api = MathOpInfo { name, - float_ty: *base_fty, - rust_sig: rust_sig.clone(), - c_sig: c_sig.clone().unwrap_or_else(|| rust_sig.clone()), + 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, }; ret.push(api); } - if !names.is_sorted() { - let mut sorted = (*names).to_owned(); + if !fn_names.is_sorted() { + let mut sorted = (*fn_names).to_owned(); sorted.sort_unstable(); - panic!("names list is not sorted: {names:?}\nExpected: {sorted:?}"); + panic!("names list is not sorted: {fn_names:?}\nExpected: {sorted:?}"); } } diff --git a/library/compiler-builtins/crates/libm-macros/tests/basic.rs b/library/compiler-builtins/crates/libm-macros/tests/basic.rs index 5314e84bbb0a1..260350ef254e2 100644 --- a/library/compiler-builtins/crates/libm-macros/tests/basic.rs +++ b/library/compiler-builtins/crates/libm-macros/tests/basic.rs @@ -13,6 +13,7 @@ macro_rules! basic { RustFn: $RustFn:ty, RustArgs: $RustArgs:ty, RustRet: $RustRet:ty, + public: $public:expr, attrs: [$($attr:meta),*], extra: [$($extra_tt:tt)*], fn_extra: $fn_extra:expr, @@ -25,6 +26,7 @@ macro_rules! basic { type RustFnTy = $RustFn; type RustArgsTy = $RustArgs; type RustRetTy = $RustRet; + const PUBLIC: bool = $public; const A: &[&str] = &[$($extra_tt)*]; fn foo(a: f32) -> f32 { $fn_extra(a) diff --git a/library/compiler-builtins/libm-test/src/op.rs b/library/compiler-builtins/libm-test/src/op.rs index bd17aad7d0352..afd445ff9c5ae 100644 --- a/library/compiler-builtins/libm-test/src/op.rs +++ b/library/compiler-builtins/libm-test/src/op.rs @@ -90,6 +90,9 @@ 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). @@ -107,7 +110,7 @@ pub type OpRustArgs = ::RustArgs; /// Access the associated `RustRet` type from an op (helper to avoid ambiguous associated types). pub type OpRustRet = ::RustRet; -macro_rules! do_thing { +macro_rules! create_op_modules { // Matcher for unary functions ( fn_name: $fn_name:ident, @@ -118,8 +121,8 @@ macro_rules! do_thing { RustFn: $RustFn:ty, RustArgs: $RustArgs:ty, RustRet: $RustRet:ty, + public: $public:expr, attrs: [$($attr:meta),*], - ) => { paste::paste! { $(#[$attr])* @@ -138,6 +141,7 @@ macro_rules! do_thing { const IDENTIFIER: Identifier = Identifier::[< $fn_name:camel >]; const ROUTINE: Self::RustFn = libm::$fn_name; + const PUBLIC: bool = $public; } } @@ -146,6 +150,6 @@ macro_rules! do_thing { } libm_macros::for_each_function! { - callback: do_thing, + callback: create_op_modules, emit_types: all, } From 257f68777f469bdd26d4763dc0cbd99c99b74e1d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 19 Mar 2025 17:53:43 +0000 Subject: [PATCH 1885/4206] Use the new solver in the impossible_predicates --- .../rustc_trait_selection/src/traits/mod.rs | 14 +++---- tests/ui/traits/vtable/impossible-method.rs | 38 +++++++++++++++++++ 2 files changed, 43 insertions(+), 9 deletions(-) create mode 100644 tests/ui/traits/vtable/impossible-method.rs diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 0987c5b42d881..7a744dfc2ad8d 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -690,8 +690,11 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( /// used during analysis. pub fn impossible_predicates<'tcx>(tcx: TyCtxt<'tcx>, predicates: Vec>) -> bool { debug!("impossible_predicates(predicates={:?})", predicates); - let (infcx, param_env) = - tcx.infer_ctxt().build_with_typing_env(ty::TypingEnv::fully_monomorphized()); + let (infcx, param_env) = tcx + .infer_ctxt() + .with_next_trait_solver(true) + .build_with_typing_env(ty::TypingEnv::fully_monomorphized()); + let ocx = ObligationCtxt::new(&infcx); let predicates = ocx.normalize(&ObligationCause::dummy(), param_env, predicates); for predicate in predicates { @@ -704,13 +707,6 @@ pub fn impossible_predicates<'tcx>(tcx: TyCtxt<'tcx>, predicates: Vec; +} +impl Id for T { + type This<'a> = T; +} + +trait Trait {} +impl Trait fn(T::This<'a>)> for T {} + +trait Method { + fn call_me(&self) + where + T: Trait fn(T::This<'a>)>; +} + +impl Method for T { + fn call_me(&self) { + println!("method was reachable"); + } +} + +fn generic(x: &dyn Method) { + // Proving `T: Trait fn(T::This<'a>)>` holds. + x.call_me(); +} + +fn main() { + // Proving `u32: Trait` fails due to incompleteness. + // We don't add the method to the vtable of `dyn Method`, so + // calling it causes UB. + generic::(&()); +} From 99202af0758bbeb9909acf848de3cd968a41148f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 23 Apr 2025 07:47:48 +0000 Subject: [PATCH 1886/4206] libm-macros: Allow a way to bulk match f16 and f128 functions These are never available in musl, so introduce easier ways to skip them rather than needing to exclude f16/f128 functions in three different places. --- .../crates/libm-macros/src/lib.rs | 30 ++++++++ .../crates/libm-macros/src/parse.rs | 16 ++++- .../crates/libm-macros/tests/basic.rs | 72 +++++++++++++++++++ .../compiler-builtins/crates/util/src/main.rs | 44 ++---------- .../libm-test/benches/random.rs | 45 ++---------- .../libm-test/tests/compare_built_musl.rs | 43 +---------- 6 files changed, 128 insertions(+), 122 deletions(-) diff --git a/library/compiler-builtins/crates/libm-macros/src/lib.rs b/library/compiler-builtins/crates/libm-macros/src/lib.rs index 144676c125364..e8afe3aad5586 100644 --- a/library/compiler-builtins/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/crates/libm-macros/src/lib.rs @@ -116,6 +116,9 @@ pub fn base_name_enum(attributes: pm::TokenStream, tokens: pm::TokenStream) -> p /// // a simplified match-like syntax. /// fn_extra: match MACRO_FN_NAME { /// hypot | hypotf => |x| x.hypot(), +/// // `ALL_*` magic matchers also work to extract specific types +/// ALL_F64 => |x| x, +/// // The default pattern gets applied to everything that did not match /// _ => |x| x, /// }, /// } @@ -138,6 +141,27 @@ pub fn for_each_function(tokens: pm::TokenStream) -> pm::TokenStream { /// /// Returns the list of function names that we should expand for. 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), + ] { + let Some(k) = map.keys().find(|key| *key == name) else { + continue; + }; + + let key = k.clone(); + let val = map.remove(&key).unwrap(); + + for op in ALL_OPERATIONS.iter().filter(|op| op.float_ty == ty) { + 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, // skip, attributes). let attr_mentions = input @@ -195,6 +219,12 @@ fn validate(input: &mut StructuredInput) -> syn::Result continue; } + // Omit f16 and f128 functions if requested + if input.skip_f16_f128 && (func.float_ty == FloatTy::F16 || func.float_ty == FloatTy::F128) + { + continue; + } + // Run everything else fn_list.push(func); } diff --git a/library/compiler-builtins/crates/libm-macros/src/parse.rs b/library/compiler-builtins/crates/libm-macros/src/parse.rs index d60d1247a9e34..4876f3ef7263a 100644 --- a/library/compiler-builtins/crates/libm-macros/src/parse.rs +++ b/library/compiler-builtins/crates/libm-macros/src/parse.rs @@ -6,7 +6,7 @@ use syn::parse::{Parse, ParseStream, Parser}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::token::{self, Comma}; -use syn::{Arm, Attribute, Expr, ExprMatch, Ident, Meta, Token, bracketed}; +use syn::{Arm, Attribute, Expr, ExprMatch, Ident, LitBool, Meta, Token, bracketed}; /// The input to our macro; just a list of `field: value` items. #[derive(Debug)] @@ -50,6 +50,8 @@ 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. + pub skip_f16_f128: bool, /// Invoke only for these functions pub only: Option>, /// Attributes that get applied to specific functions @@ -70,6 +72,7 @@ impl StructuredInput { let cb_expr = expect_field(&mut map, "callback")?; 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 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(); @@ -93,6 +96,11 @@ impl StructuredInput { None => Vec::new(), }; + let skip_f16_f128 = match skip_f16_f128 { + 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())?), @@ -122,6 +130,7 @@ impl StructuredInput { callback: expect_ident(cb_expr)?, emit_types, skip, + skip_f16_f128, only, only_span, attributes, @@ -220,6 +229,11 @@ fn expect_ident(expr: Expr) -> syn::Result { syn::parse2(expr.into_token_stream()) } +/// Coerce an expression into a simple keyword. +fn expect_litbool(expr: Expr) -> syn::Result { + syn::parse2(expr.into_token_stream()) +} + /// Parse either a single identifier (`foo`) or an array of identifiers (`[foo, bar, baz]`). fn parse_ident_or_array(input: ParseStream) -> syn::Result> { if !input.peek(token::Bracket) { diff --git a/library/compiler-builtins/crates/libm-macros/tests/basic.rs b/library/compiler-builtins/crates/libm-macros/tests/basic.rs index 260350ef254e2..b4276262229fe 100644 --- a/library/compiler-builtins/crates/libm-macros/tests/basic.rs +++ b/library/compiler-builtins/crates/libm-macros/tests/basic.rs @@ -103,3 +103,75 @@ mod test_emit_types { emit_types: [RustFn, RustArgs], } } + +#[test] +fn test_skip_f16_f128() { + macro_rules! skip_f16_f128 { + ( + fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], + extra: $vec:ident, + ) => { + $vec.push(stringify!($fn_name)); + }; + } + + let mut v = Vec::new(); + // Test with no extra, no skip, and no attributes + libm_macros::for_each_function! { + callback: skip_f16_f128, + skip_f16_f128: true, + extra: v, + } + + for name in v { + assert!(!name.contains("f16"), "{name}"); + assert!(!name.contains("f128"), "{name}"); + } +} + +#[test] +fn test_fn_extra_expansion() { + macro_rules! fn_extra_expansion { + ( + fn_name: $fn_name:ident, + attrs: [$($attr:meta),*], + fn_extra: $vec:expr, + ) => { + $vec.push(stringify!($fn_name)); + }; + } + + let mut vf16 = Vec::new(); + let mut vf32 = Vec::new(); + let mut vf64 = Vec::new(); + let mut vf128 = Vec::new(); + + // Test with no extra, no skip, and no attributes + libm_macros::for_each_function! { + callback: fn_extra_expansion, + fn_extra: match MACRO_FN_NAME { + ALL_F16 => vf16, + ALL_F32 => vf32, + ALL_F64 => vf64, + ALL_F128 => vf128, + } + } + + // Skip functions with a suffix after the type spec + vf16.retain(|name| !name.ends_with("_r")); + vf32.retain(|name| !name.ends_with("_r")); + vf64.retain(|name| !name.ends_with("_r")); + vf128.retain(|name| !name.ends_with("_r")); + + for name in vf16 { + assert!(name.ends_with("f16"), "{name}"); + } + for name in vf32 { + assert!(name.ends_with("f"), "{name}"); + } + let _ = vf64; + for name in vf128 { + assert!(name.ends_with("f128"), "{name}"); + } +} diff --git a/library/compiler-builtins/crates/util/src/main.rs b/library/compiler-builtins/crates/util/src/main.rs index e7057869996b0..5972181531b26 100644 --- a/library/compiler-builtins/crates/util/src/main.rs +++ b/library/compiler-builtins/crates/util/src/main.rs @@ -86,55 +86,19 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { emit_types: [CFn, RustFn, RustArgs], extra: (basis, op, inputs), fn_extra: match MACRO_FN_NAME { - ceilf128 - | ceilf16 - | copysignf128 - | copysignf16 - | fabsf128 - | fabsf16 - | fdimf128 - | fdimf16 - | floorf128 - | floorf16 - | fmaf128 - | fmaxf128 - | fmaxf16 - | fmaximum + // Not provided by musl + fmaximum | fmaximum_num | fmaximum_numf - | fmaximum_numf128 - | fmaximum_numf16 | fmaximumf - | fmaximumf128 - | fmaximumf16 - | fminf128 - | fminf16 | fminimum | fminimum_num | fminimum_numf - | fminimum_numf128 - | fminimum_numf16 | fminimumf - | fminimumf128 - | fminimumf16 - | fmodf128 - | fmodf16 - | ldexpf128 - | ldexpf16 - | rintf128 - | rintf16 | roundeven | roundevenf - | roundevenf128 - | roundevenf16 - | roundf128 - | roundf16 - | scalbnf128 - | scalbnf16 - | sqrtf128 - | sqrtf16 - | truncf128 - | truncf16 => None, + | ALL_F16 + | ALL_F128 => None, _ => Some(musl_math_sys::MACRO_FN_NAME) } } diff --git a/library/compiler-builtins/libm-test/benches/random.rs b/library/compiler-builtins/libm-test/benches/random.rs index 81f58e3a6588f..1b17f049ecac2 100644 --- a/library/compiler-builtins/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm-test/benches/random.rs @@ -125,56 +125,19 @@ libm_macros::for_each_function! { // FIXME(correctness): exp functions have the wrong result on i586 exp10 | exp10f | exp2 | exp2f => (true, Some(musl_math_sys::MACRO_FN_NAME)), - // Musl does not provide `f16` and `f128` functions - ceilf128 - | ceilf16 - | copysignf128 - | copysignf16 - | fabsf128 - | fabsf16 - | fdimf128 - | fdimf16 - | floorf128 - | floorf16 - | fmaf128 - | fmaxf128 - | fmaxf16 - | fmaximum + // Musl does not provide `f16` and `f128` functions, as well as a handful of others + fmaximum | fmaximum_num | fmaximum_numf - | fmaximum_numf128 - | fmaximum_numf16 | fmaximumf - | fmaximumf128 - | fmaximumf16 - | fminf128 - | fminf16 | fminimum | fminimum_num | fminimum_numf - | fminimum_numf128 - | fminimum_numf16 | fminimumf - | fminimumf128 - | fminimumf16 - | fmodf128 - | fmodf16 - | ldexpf128 - | ldexpf16 - | rintf128 - | rintf16 | roundeven | roundevenf - | roundevenf128 - | roundevenf16 - | roundf128 - | roundf16 - | scalbnf128 - | scalbnf16 - | sqrtf128 - | sqrtf16 - | truncf128 - | truncf16 => (false, None), + | ALL_F16 + | ALL_F128 => (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/tests/compare_built_musl.rs b/library/compiler-builtins/libm-test/tests/compare_built_musl.rs index cbb4bd49b9c55..6ccbb6f4c51d5 100644 --- a/library/compiler-builtins/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm-test/tests/compare_built_musl.rs @@ -76,6 +76,8 @@ macro_rules! musl_tests { libm_macros::for_each_function! { callback: musl_tests, attributes: [], + // Not provided by musl + skip_f16_f128: true, skip: [ // TODO integer inputs jn, @@ -89,55 +91,16 @@ libm_macros::for_each_function! { // Not provided by musl // verify-sorted-start - ceilf128, - ceilf16, - copysignf128, - copysignf16, - fabsf128, - fabsf16, - fdimf128, - fdimf16, - floorf128, - floorf16, - fmaf128, - fmaxf128, - fmaxf16, fmaximum, fmaximum_num, fmaximum_numf, - fmaximum_numf128, - fmaximum_numf16, fmaximumf, - fmaximumf128, - fmaximumf16, - fminf128, - fminf16, fminimum, fminimum_num, fminimum_numf, - fminimum_numf128, - fminimum_numf16, fminimumf, - fminimumf128, - fminimumf16, - fmodf128, - fmodf16, - ldexpf128, - ldexpf16, - rintf128, - rintf16, roundeven, roundevenf, - roundevenf128, - roundevenf16, - roundf128, - roundf16, - scalbnf128, - scalbnf16, - sqrtf128, - sqrtf16, - truncf128, - truncf16, - // verify-sorted-end + // // verify-sorted-end ], } From 975617e8d4105f30d741ac7a3f5478d3b7b7917c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 19 Mar 2025 00:19:04 +0000 Subject: [PATCH 1887/4206] Warn on `unsafe_op_in_unsafe_fn` by default Edition 2024 requires that we avoid this. There is a lot of code that will need to be adjusted, so start the process here with a warning that will show up in CI. --- .../builtins-test-intrinsics/src/main.rs | 20 +- .../compiler-builtins/src/arm.rs | 181 ++++++++++++++---- .../compiler-builtins/src/lib.rs | 3 + .../compiler-builtins/src/macros.rs | 15 +- .../compiler-builtins/src/mem/mod.rs | 2 + .../compiler-builtins/src/x86_64.rs | 2 +- 6 files changed, 172 insertions(+), 51 deletions(-) diff --git a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs index c4c026368e0da..18f943eff3548 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs +++ b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs @@ -649,14 +649,14 @@ fn something_with_a_dtor(f: &dyn Fn()) { f(); } -#[no_mangle] +#[unsafe(no_mangle)] #[cfg(not(thumb))] fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int { run(); 0 } -#[no_mangle] +#[unsafe(no_mangle)] #[cfg(thumb)] pub fn _start() -> ! { run(); @@ -669,30 +669,30 @@ pub fn _start() -> ! { extern "C" {} // ARM targets need these symbols -#[no_mangle] +#[unsafe(no_mangle)] pub fn __aeabi_unwind_cpp_pr0() {} -#[no_mangle] +#[unsafe(no_mangle)] pub fn __aeabi_unwind_cpp_pr1() {} #[cfg(not(any(windows, target_os = "cygwin")))] #[allow(non_snake_case)] -#[no_mangle] +#[unsafe(no_mangle)] pub fn _Unwind_Resume() {} #[cfg(not(any(windows, target_os = "cygwin")))] #[lang = "eh_personality"] -#[no_mangle] +#[unsafe(no_mangle)] pub extern "C" fn eh_personality() {} #[cfg(any(all(windows, target_env = "gnu"), target_os = "cygwin"))] mod mingw_unwinding { - #[no_mangle] + #[unsafe(no_mangle)] pub fn rust_eh_personality() {} - #[no_mangle] + #[unsafe(no_mangle)] pub fn rust_eh_unwind_resume() {} - #[no_mangle] + #[unsafe(no_mangle)] pub fn rust_eh_register_frames() {} - #[no_mangle] + #[unsafe(no_mangle)] pub fn rust_eh_unregister_frames() {} } diff --git a/library/compiler-builtins/compiler-builtins/src/arm.rs b/library/compiler-builtins/compiler-builtins/src/arm.rs index 7859b51207c6e..a9107e3cdfda4 100644 --- a/library/compiler-builtins/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/compiler-builtins/src/arm.rs @@ -76,90 +76,205 @@ intrinsics! { ); } - // FIXME: The `*4` and `*8` variants should be defined as aliases. + // FIXME(arm): The `*4` and `*8` variants should be defined as aliases. + /// `memcpy` provided with the `aapcs` ABI. + /// + /// # Safety + /// + /// Usual `memcpy` requirements apply. #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) { - crate::mem::memcpy(dest, src, n); + pub unsafe extern "aapcs" fn __aeabi_memcpy(dst: *mut u8, src: *const u8, n: usize) { + // SAFETY: memcpy preconditions apply. + unsafe { crate::mem::memcpy(dst, src, n) }; } + /// `memcpy` for 4-byte alignment. + /// + /// # Safety + /// + /// Usual `memcpy` requirements apply. Additionally, `dest` and `src` must be aligned to + /// four bytes. #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) { + pub unsafe extern "aapcs" fn __aeabi_memcpy4(dst: *mut u8, src: *const u8, n: usize) { // We are guaranteed 4-alignment, so accessing at u32 is okay. - let mut dest = dest as *mut u32; - let mut src = src as *mut u32; + let mut dst = dst.cast::(); + let mut src = src.cast::(); + debug_assert!(dst.is_aligned()); + debug_assert!(src.is_aligned()); let mut n = n; while n >= 4 { - *dest = *src; - dest = dest.offset(1); - src = src.offset(1); + // SAFETY: `dst` and `src` are both valid for at least 4 bytes, from + // `memcpy` preconditions and the loop guard. + unsafe { *dst = *src }; + + // FIXME(addr): if we can make this end-of-address-space safe without losing + // performance, we may want to consider that. + // SAFETY: memcpy is not expected to work at the end of the address space + unsafe { + dst = dst.offset(1); + src = src.offset(1); + } + n -= 4; } - __aeabi_memcpy(dest as *mut u8, src as *const u8, n); + // SAFETY: `dst` and `src` will still be valid for `n` bytes + unsafe { __aeabi_memcpy(dst.cast::(), src.cast::(), n) }; } + /// `memcpy` for 8-byte alignment. + /// + /// # Safety + /// + /// Usual `memcpy` requirements apply. Additionally, `dest` and `src` must be aligned to + /// eight bytes. #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) { - __aeabi_memcpy4(dest, src, n); + pub unsafe extern "aapcs" fn __aeabi_memcpy8(dst: *mut u8, src: *const u8, n: usize) { + debug_assert!(dst.addr() & 7 == 0); + debug_assert!(src.addr() & 7 == 0); + + // SAFETY: memcpy preconditions apply, less strict alignment. + unsafe { __aeabi_memcpy4(dst, src, n) }; } + /// `memmove` provided with the `aapcs` ABI. + /// + /// # Safety + /// + /// Usual `memmove` requirements apply. #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) { - crate::mem::memmove(dest, src, n); + pub unsafe extern "aapcs" fn __aeabi_memmove(dst: *mut u8, src: *const u8, n: usize) { + // SAFETY: memmove preconditions apply. + unsafe { crate::mem::memmove(dst, src, n) }; } + /// `memmove` for 4-byte alignment. + /// + /// # Safety + /// + /// Usual `memmove` requirements apply. Additionally, `dest` and `src` must be aligned to + /// four bytes. #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] - pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) { - __aeabi_memmove(dest, src, n); + pub unsafe extern "aapcs" fn __aeabi_memmove4(dst: *mut u8, src: *const u8, n: usize) { + debug_assert!(dst.addr() & 3 == 0); + debug_assert!(src.addr() & 3 == 0); + + // SAFETY: same preconditions, less strict aligment. + unsafe { __aeabi_memmove(dst, src, n) }; } + /// `memmove` for 8-byte alignment. + /// + /// # Safety + /// + /// Usual `memmove` requirements apply. Additionally, `dst` and `src` must be aligned to + /// eight bytes. #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] - pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) { - __aeabi_memmove(dest, src, n); + pub unsafe extern "aapcs" fn __aeabi_memmove8(dst: *mut u8, src: *const u8, n: usize) { + debug_assert!(dst.addr() & 7 == 0); + debug_assert!(src.addr() & 7 == 0); + + // SAFETY: memmove preconditions apply, less strict alignment. + unsafe { __aeabi_memmove(dst, src, n) }; } + /// `memset` provided with the `aapcs` ABI. + /// + /// # Safety + /// + /// Usual `memset` requirements apply. #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) { + pub unsafe extern "aapcs" fn __aeabi_memset(dst: *mut u8, n: usize, c: i32) { // Note the different argument order - crate::mem::memset(dest, c, n); + // SAFETY: memset preconditions apply. + unsafe { crate::mem::memset(dst, c, n) }; } + /// `memset` for 4-byte alignment. + /// + /// # Safety + /// + /// Usual `memset` requirements apply. Additionally, `dest` and `src` must be aligned to + /// four bytes. #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) { - let mut dest = dest as *mut u32; + pub unsafe extern "aapcs" fn __aeabi_memset4(dst: *mut u8, n: usize, c: i32) { + let mut dst = dst.cast::(); + debug_assert!(dst.is_aligned()); let mut n = n; let byte = (c as u32) & 0xff; let c = (byte << 24) | (byte << 16) | (byte << 8) | byte; while n >= 4 { - *dest = c; - dest = dest.offset(1); + // SAFETY: `dst` is valid for at least 4 bytes, from `memset` preconditions and + // the loop guard. + unsafe { *dst = c }; + + // FIXME(addr): if we can make this end-of-address-space safe without losing + // performance, we may want to consider that. + // SAFETY: memcpy is not expected to work at the end of the address space + unsafe { + dst = dst.offset(1); + } n -= 4; } - __aeabi_memset(dest as *mut u8, n, byte as i32); + // SAFETY: `dst` will still be valid for `n` bytes + unsafe { __aeabi_memset(dst.cast::(), n, byte as i32) }; } + /// `memset` for 8-byte alignment. + /// + /// # Safety + /// + /// Usual `memset` requirements apply. Additionally, `dst` and `src` must be aligned to + /// eight bytes. #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) { - __aeabi_memset4(dest, n, c); + pub unsafe extern "aapcs" fn __aeabi_memset8(dst: *mut u8, n: usize, c: i32) { + debug_assert!(dst.addr() & 7 == 0); + + // SAFETY: memset preconditions apply, less strict alignment. + unsafe { __aeabi_memset4(dst, n, c) }; } + /// `memclr` provided with the `aapcs` ABI. + /// + /// # Safety + /// + /// Usual `memclr` requirements apply. #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) { - __aeabi_memset(dest, n, 0); + pub unsafe extern "aapcs" fn __aeabi_memclr(dst: *mut u8, n: usize) { + // SAFETY: memclr preconditions apply, less strict alignment. + unsafe { __aeabi_memset(dst, n, 0) }; } + /// `memclr` for 4-byte alignment. + /// + /// # Safety + /// + /// Usual `memclr` requirements apply. Additionally, `dest` and `src` must be aligned to + /// four bytes. #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] - pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) { - __aeabi_memset4(dest, n, 0); + pub unsafe extern "aapcs" fn __aeabi_memclr4(dst: *mut u8, n: usize) { + debug_assert!(dst.addr() & 3 == 0); + + // SAFETY: memclr preconditions apply, less strict alignment. + unsafe { __aeabi_memset4(dst, n, 0) }; } + /// `memclr` for 8-byte alignment. + /// + /// # Safety + /// + /// Usual `memclr` requirements apply. Additionally, `dst` and `src` must be aligned to + /// eight bytes. #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] - pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) { - __aeabi_memset4(dest, n, 0); + pub unsafe extern "aapcs" fn __aeabi_memclr8(dst: *mut u8, n: usize) { + debug_assert!(dst.addr() & 7 == 0); + + // SAFETY: memclr preconditions apply, less strict alignment. + unsafe { __aeabi_memset4(dst, n, 0) }; } } diff --git a/library/compiler-builtins/compiler-builtins/src/lib.rs b/library/compiler-builtins/compiler-builtins/src/lib.rs index 7523a00cf9b66..6a6b28067e8c8 100644 --- a/library/compiler-builtins/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/compiler-builtins/src/lib.rs @@ -22,6 +22,9 @@ #![allow(clippy::manual_swap)] // Support compiling on both stage0 and stage1 which may differ in supported stable features. #![allow(stable_features)] +// By default, disallow this as it is forbidden in edition 2024. There is a lot of unsafe code to +// be migrated, however, so exceptions exist. +#![warn(unsafe_op_in_unsafe_fn)] // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. diff --git a/library/compiler-builtins/compiler-builtins/src/macros.rs b/library/compiler-builtins/compiler-builtins/src/macros.rs index 4fa53656e5ca3..dbf7155344030 100644 --- a/library/compiler-builtins/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/compiler-builtins/src/macros.rs @@ -256,7 +256,7 @@ macro_rules! intrinsics { #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"), not(feature = "mangled-names")))] mod $name { - #[no_mangle] + #[unsafe(no_mangle)] #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] $(#[$($attr)*])* extern $abi fn $name( $($argname: u16),* ) $(-> $ret)? { @@ -292,7 +292,7 @@ macro_rules! intrinsics { #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"), not(feature = "mangled-names")))] mod $name { - #[no_mangle] + #[unsafe(no_mangle)] #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] $(#[$($attr)*])* extern $abi fn $name( $($argname: $ty),* ) -> u16 { @@ -333,7 +333,7 @@ macro_rules! intrinsics { #[cfg(all(target_arch = "arm", not(feature = "mangled-names")))] mod $name { - #[no_mangle] + #[unsafe(no_mangle)] #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] $(#[$($attr)*])* extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { @@ -343,7 +343,7 @@ macro_rules! intrinsics { #[cfg(all(target_arch = "arm", not(feature = "mangled-names")))] mod $alias { - #[no_mangle] + #[unsafe(no_mangle)] #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] $(#[$($attr)*])* extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? { @@ -410,7 +410,7 @@ macro_rules! intrinsics { #[cfg(all(feature = "mem", not(feature = "mangled-names")))] mod $name { $(#[$($attr)*])* - #[no_mangle] + #[unsafe(no_mangle)] #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { super::$name($($argname),*) @@ -485,10 +485,11 @@ macro_rules! intrinsics { #[cfg(not(feature = "mangled-names"))] mod $name { $(#[$($attr)*])* - #[no_mangle] + #[unsafe(no_mangle)] #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] $(unsafe $($empty)?)? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { - super::$name($($argname),*) + // SAFETY: same preconditions. + $(unsafe $($empty)?)? { super::$name($($argname),*) } } } diff --git a/library/compiler-builtins/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/compiler-builtins/src/mem/mod.rs index ec160039d0d03..6828f3804e0fe 100644 --- a/library/compiler-builtins/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/compiler-builtins/src/mem/mod.rs @@ -1,5 +1,7 @@ // Trying to satisfy clippy here is hopeless #![allow(clippy::style)] +// FIXME(e2024): this eventually needs to be removed. +#![allow(unsafe_op_in_unsafe_fn)] #[allow(warnings)] #[cfg(target_pointer_width = "16")] diff --git a/library/compiler-builtins/compiler-builtins/src/x86_64.rs b/library/compiler-builtins/compiler-builtins/src/x86_64.rs index af67e66e28d40..fc1190f79b237 100644 --- a/library/compiler-builtins/compiler-builtins/src/x86_64.rs +++ b/library/compiler-builtins/compiler-builtins/src/x86_64.rs @@ -44,7 +44,7 @@ intrinsics! { // HACK(https://github.com/rust-lang/rust/issues/62785): x86_64-unknown-uefi needs special LLVM // support unless we emit the _fltused mod _fltused { - #[no_mangle] + #[unsafe(no_mangle)] #[used] #[cfg(target_os = "uefi")] static _fltused: i32 = 0; From 00417de6b8b07af4d4355f69fef5fb7c5e11d893 Mon Sep 17 00:00:00 2001 From: bendn Date: Mon, 31 Mar 2025 15:50:56 +0700 Subject: [PATCH 1888/4206] Suggest {to,from}_ne_bytes for transmutations between arrays and integers, etc --- example/example.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/example.rs b/example/example.rs index 1ef2aa5dd8ea4..aeb38331edb02 100644 --- a/example/example.rs +++ b/example/example.rs @@ -1,6 +1,6 @@ #![feature(no_core, unboxed_closures)] #![no_core] -#![allow(dead_code)] +#![allow(dead_code, unnecessary_transmutes)] extern crate mini_core; From eef57cb4e290ea44bae26a1320c37c76b13275b6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 24 Apr 2025 13:02:28 +0000 Subject: [PATCH 1889/4206] Pass Option to codegen_unwind_terminate In preparation for unwinding support. --- src/base.rs | 14 +++----------- src/compiler_builtins.rs | 1 - 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/base.rs b/src/base.rs index 6b850a9a6e691..7c02b3f48f9d0 100644 --- a/src/base.rs +++ b/src/base.rs @@ -566,7 +566,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { ); } TerminatorKind::UnwindTerminate(reason) => { - codegen_unwind_terminate(fx, source_info, *reason); + codegen_unwind_terminate(fx, Some(source_info.span), *reason); } TerminatorKind::UnwindResume => { // FIXME implement unwinding @@ -1117,18 +1117,10 @@ pub(crate) fn codegen_panic_nounwind<'tcx>( pub(crate) fn codegen_unwind_terminate<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, - source_info: mir::SourceInfo, + span: Option, reason: UnwindTerminateReason, ) { - let args = []; - - codegen_panic_inner( - fx, - reason.lang_item(), - &args, - UnwindAction::Terminate(UnwindTerminateReason::Abi), - Some(source_info.span), - ); + codegen_panic_inner(fx, reason.lang_item(), &[], UnwindAction::Unreachable, span); } fn codegen_panic_inner<'tcx>( diff --git a/src/compiler_builtins.rs b/src/compiler_builtins.rs index bf16e81a06f9f..5b6d0ef6ddf79 100644 --- a/src/compiler_builtins.rs +++ b/src/compiler_builtins.rs @@ -67,5 +67,4 @@ builtin_functions! { fn malloc(size: size_t) -> *mut c_void; fn realloc(p: *mut c_void, size: size_t) -> *mut c_void; fn free(p: *mut c_void) -> (); - } From 349430c08ecc4c98325f8231d3fafee69cc3ba29 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 24 Apr 2025 13:08:32 +0000 Subject: [PATCH 1890/4206] Avoid creating a second UnwindContext in finalize_definitions Once UnwindContext sets the personality function it will need to define a DW.ref.rust_eh_personality function which would cause a duplicate definition if UnwindContext is called a second time. --- src/driver/jit.rs | 4 ++-- src/unwind_module.rs | 9 +++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/driver/jit.rs b/src/driver/jit.rs index 0e2e1f6fc0a88..6315935a221db 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -84,7 +84,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, jit_args: Vec) -> ! { tcx.dcx().abort_if_errors(); - jit_module.finalize_definitions(); + let mut jit_module = jit_module.finalize_definitions(); println!( "Rustc codegen cranelift will JIT run the executable, because -Cllvm-args=mode=jit was passed" @@ -104,7 +104,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, jit_args: Vec) -> ! { call_conv: jit_module.target_config().default_call_conv, }; let start_func_id = jit_module.declare_function("main", Linkage::Import, &start_sig).unwrap(); - let finalized_start: *const u8 = jit_module.module.get_finalized_function(start_func_id); + let finalized_start: *const u8 = jit_module.get_finalized_function(start_func_id); let f: extern "C" fn(c_int, *const *const c_char) -> c_int = unsafe { ::std::mem::transmute(finalized_start) }; diff --git a/src/unwind_module.rs b/src/unwind_module.rs index 0864bd8d84f65..b4eb939cf2560 100644 --- a/src/unwind_module.rs +++ b/src/unwind_module.rs @@ -33,13 +33,10 @@ impl UnwindModule { #[cfg(feature = "jit")] impl UnwindModule { - pub(crate) fn finalize_definitions(&mut self) { + pub(crate) fn finalize_definitions(mut self) -> cranelift_jit::JITModule { self.module.finalize_definitions().unwrap(); - let prev_unwind_context = std::mem::replace( - &mut self.unwind_context, - UnwindContext::new(&mut self.module, false), - ); - unsafe { prev_unwind_context.register_jit(&self.module) }; + unsafe { self.unwind_context.register_jit(&self.module) }; + self.module } } From b59f697ee989325f16a7c37658780d18d80b1a6d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 24 Apr 2025 13:16:21 +0000 Subject: [PATCH 1891/4206] Relocation improvements for .eh_frame This is necessary to handle LSDA references in the future once unwinding is supported. --- src/debuginfo/emit.rs | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/src/debuginfo/emit.rs b/src/debuginfo/emit.rs index ccdc347af660f..0f4696b9337e7 100644 --- a/src/debuginfo/emit.rs +++ b/src/debuginfo/emit.rs @@ -81,13 +81,36 @@ impl WriterRelocate { /// Perform the collected relocations to be usable for JIT usage. #[cfg(all(feature = "jit", not(windows)))] pub(super) fn relocate_for_jit(mut self, jit_module: &cranelift_jit::JITModule) -> Vec { + use cranelift_module::Module; + for reloc in self.relocs.drain(..) { match reloc.name { super::DebugRelocName::Section(_) => unreachable!(), super::DebugRelocName::Symbol(sym) => { - let addr = jit_module.get_finalized_function( - cranelift_module::FuncId::from_u32(sym.try_into().unwrap()), - ); + let addr = if sym & 1 << 31 == 0 { + let func_id = FuncId::from_u32(sym.try_into().unwrap()); + // FIXME make JITModule::get_address public and use it here instead. + // HACK rust_eh_personality is likely not defined in the same crate, + // so get_finalized_function won't work. Use the rust_eh_personality + // of cg_clif itself, which is likely ABI compatible. + if jit_module.declarations().get_function_decl(func_id).name.as_deref() + == Some("rust_eh_personality") + { + extern "C" { + fn rust_eh_personality() -> !; + } + rust_eh_personality as *const u8 + } else { + jit_module.get_finalized_function(func_id) + } + } else { + jit_module + .get_finalized_data(DataId::from_u32( + u32::try_from(sym).unwrap() & !(1 << 31), + )) + .0 + }; + let val = (addr as u64 as i64 + reloc.addend) as u64; self.writer.write_udata_at(reloc.offset as usize, val, reloc.size).unwrap(); } @@ -196,6 +219,16 @@ impl Writer for WriterRelocate { }); self.write_udata(0, size) } + gimli::DW_EH_PE_absptr => { + self.relocs.push(DebugReloc { + offset: self.len() as u32, + size: size.into(), + name: DebugRelocName::Symbol(symbol), + addend, + kind: object::RelocationKind::Absolute, + }); + self.write_udata(0, size.into()) + } _ => Err(gimli::write::Error::UnsupportedPointerEncoding(eh_pe)), }, } From a71cba709b810ce0b15bcdb12fcc345819589404 Mon Sep 17 00:00:00 2001 From: Henry Jiang Date: Thu, 24 Apr 2025 19:55:03 -0400 Subject: [PATCH 1892/4206] strip underlying xcoff object --- compiler/rustc_codegen_ssa/src/back/link.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 8de68925cabbc..9332edbfd15f0 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1090,11 +1090,11 @@ fn link_natively( match strip { Strip::Debuginfo => { // FIXME: AIX's strip utility only offers option to strip line number information. - strip_with_external_utility(sess, stripcmd, out_filename, &["-X32_64", "-l"]) + strip_with_external_utility(sess, stripcmd, temp_filename, &["-X32_64", "-l"]) } Strip::Symbols => { // Must be noted this option might remove symbol __aix_rust_metadata and thus removes .info section which contains metadata. - strip_with_external_utility(sess, stripcmd, out_filename, &["-X32_64", "-r"]) + strip_with_external_utility(sess, stripcmd, temp_filename, &["-X32_64", "-r"]) } Strip::None => {} } From f6f92a22ba451e42313c90fb8214f5d26ec71dfd Mon Sep 17 00:00:00 2001 From: gohome001 <3156514693@qq.com> Date: Fri, 25 Apr 2025 15:59:11 +0800 Subject: [PATCH 1893/4206] feat: highlight unsafe operations --- .../crates/ide/src/highlight_related.rs | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs index 80624eeae80c7..750ad2302629a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs @@ -89,6 +89,9 @@ pub(crate) fn highlight_related( T![break] | T![loop] | T![while] | T![continue] if config.break_points => { highlight_break_points(sema, token).remove(&file_id) } + T![unsafe] if token.parent_ancestors().find_map(ast::BlockExpr::cast).is_some() => { + highlight_unsafe_points(sema, token).remove(&file_id) + } T![|] if config.closure_captures => { highlight_closure_captures(sema, token, file_id, span_file_id.file_id()) } @@ -706,6 +709,60 @@ impl<'a> WalkExpandedExprCtx<'a> { } } +pub(crate) fn highlight_unsafe_points( + sema: &Semantics<'_, RootDatabase>, + token: SyntaxToken, +) -> FxHashMap> { + fn hl( + sema: &Semantics<'_, RootDatabase>, + unsafe_token: Option, + block_expr: Option, + ) -> Option>> { + let mut highlights: FxHashMap> = FxHashMap::default(); + + let mut push_to_highlights = |file_id, range| { + if let Some(FileRange { file_id, range }) = original_frange(sema.db, file_id, range) { + let hrange = HighlightedRange { category: ReferenceCategory::empty(), range }; + highlights.entry(file_id).or_default().push(hrange); + } + }; + + // highlight unsafe keyword itself + let unsafe_token = unsafe_token?; + let unsafe_token_file_id = sema.hir_file_for(&unsafe_token.parent()?); + push_to_highlights(unsafe_token_file_id, Some(unsafe_token.text_range())); + + if let Some(block) = block_expr { + if let Some(node) = block.syntax().ancestors().find(|n| ast::Fn::can_cast(n.kind())) { + if let Some(function) = ast::Fn::cast(node) { + // highlight unsafe keyword of the function + if let Some(unsafe_token) = function.unsafe_token() { + push_to_highlights(unsafe_token_file_id, Some(unsafe_token.text_range())); + } + // highlight unsafe operations + if let Some(f) = sema.to_def(&function) { + let unsafe_ops = sema.get_unsafe_ops(f.into()); + for unsafe_op in unsafe_ops { + push_to_highlights( + unsafe_op.file_id, + Some(unsafe_op.value.text_range()), + ); + } + } + } + } + } + + Some(highlights) + } + + let Some(block_expr) = token.parent().and_then(ast::BlockExpr::cast) else { + return FxHashMap::default(); + }; + + hl(sema, Some(token), Some(block_expr)).unwrap_or_default() +} + #[cfg(test)] mod tests { use itertools::Itertools; From 9031c86009c4d09cc315670bb3e03b70ef2d5edf Mon Sep 17 00:00:00 2001 From: gohome001 <3156514693@qq.com> Date: Fri, 25 Apr 2025 16:01:20 +0800 Subject: [PATCH 1894/4206] test: add test case for highlight unsafe operations --- .../crates/ide/src/highlight_related.rs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs index 750ad2302629a..2943d60682adc 100644 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs @@ -811,6 +811,34 @@ mod tests { assert_eq!(expected, actual); } + #[test] + fn test_hl_unsafe_block() { + check( + r#" +fn foo() { + unsafe fn this_is_unsafe_function() { + } + + + unsa$0fe { + //^^^^^^ + let raw_ptr = &42 as *const i32; + let val = *raw_ptr; + //^^^^^^^^ + + let mut_ptr = &mut 5 as *mut i32; + *mut_ptr = 10; + //^^^^^^^^ + + this_is_unsafe_function(); + //^^^^^^^^^^^^^^^^^^^^^^^^^ + } + +} +"#, + ); + } + #[test] fn test_hl_tuple_fields() { check( From 2ec065062a2328de40ff29282cbd56f66276a748 Mon Sep 17 00:00:00 2001 From: gohome001 <3156514693@qq.com> Date: Fri, 25 Apr 2025 17:02:08 +0800 Subject: [PATCH 1895/4206] minor: format --- .../rust-analyzer/crates/ide/src/highlight_related.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs index 2943d60682adc..90a7c62d71bbf 100644 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs @@ -816,24 +816,22 @@ mod tests { check( r#" fn foo() { - unsafe fn this_is_unsafe_function() { - } + unsafe fn this_is_unsafe_function() {} - unsa$0fe { //^^^^^^ let raw_ptr = &42 as *const i32; let val = *raw_ptr; //^^^^^^^^ - + let mut_ptr = &mut 5 as *mut i32; *mut_ptr = 10; //^^^^^^^^ - + this_is_unsafe_function(); //^^^^^^^^^^^^^^^^^^^^^^^^^ } - + } "#, ); From 61d1c13b3e90cd8a021a9dc9be3fc4311be7088c Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 25 Apr 2025 10:44:19 -0400 Subject: [PATCH 1896/4206] Merge commit '4f83a4258deb99f3288a7122c0d5a78200931c61' into subtree-update_cg_gcc_2025-04-25 --- rust-toolchain | 2 +- src/asm.rs | 8 ++++---- src/common.rs | 11 +++++------ src/consts.rs | 8 ++++---- src/debuginfo.rs | 17 +++++++++-------- src/gcc_util.rs | 14 ++++++-------- src/lib.rs | 2 +- src/type_of.rs | 14 +++++++------- tests/lang_tests_common.rs | 2 ++ tests/run/ptr_cast.rs | 7 +++++++ 10 files changed, 46 insertions(+), 39 deletions(-) diff --git a/rust-toolchain b/rust-toolchain index fd898c59707b0..452d3f22dc518 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2025-04-17" +channel = "nightly-2025-04-25" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/src/asm.rs b/src/asm.rs index dbdf37ee6c9ef..396c6d5795015 100644 --- a/src/asm.rs +++ b/src/asm.rs @@ -165,10 +165,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { let mut input_registers = vec![]; for op in rust_operands { - if let InlineAsmOperandRef::In { reg, .. } = *op { - if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) { - input_registers.push(reg_name); - } + if let InlineAsmOperandRef::In { reg, .. } = *op + && let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) + { + input_registers.push(reg_name); } } diff --git a/src/common.rs b/src/common.rs index a63da6b6e27d8..918195364ffee 100644 --- a/src/common.rs +++ b/src/common.rs @@ -33,12 +33,11 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } pub fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> { - if value.get_type() == self.bool_type.make_pointer() { - if let Some(pointee) = typ.get_pointee() { - if pointee.dyncast_vector().is_some() { - panic!() - } - } + if value.get_type() == self.bool_type.make_pointer() + && let Some(pointee) = typ.get_pointee() + && pointee.dyncast_vector().is_some() + { + panic!() } // NOTE: since bitcast makes a value non-constant, don't bitcast if not necessary as some // SIMD builtins require a constant value. diff --git a/src/consts.rs b/src/consts.rs index acb3937462857..0a67bd7bc71af 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -242,10 +242,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { let fn_attrs = self.tcx.codegen_fn_attrs(def_id); let global = if def_id.is_local() && !self.tcx.is_foreign_item(def_id) { - if let Some(global) = self.get_declared_value(sym) { - if self.val_ty(global) != self.type_ptr_to(gcc_type) { - span_bug!(self.tcx.def_span(def_id), "Conflicting types for static"); - } + if let Some(global) = self.get_declared_value(sym) + && self.val_ty(global) != self.type_ptr_to(gcc_type) + { + span_bug!(self.tcx.def_span(def_id), "Conflicting types for static"); } let is_tls = fn_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL); diff --git a/src/debuginfo.rs b/src/debuginfo.rs index 55e01687400aa..f3ced86439527 100644 --- a/src/debuginfo.rs +++ b/src/debuginfo.rs @@ -126,14 +126,15 @@ fn make_mir_scope<'gcc, 'tcx>( return; }; - if let Some(ref vars) = *variables { - if !vars.contains(scope) && scope_data.inlined.is_none() { - // Do not create a DIScope if there are no variables defined in this - // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat. - debug_context.scopes[scope] = parent_scope; - instantiated.insert(scope); - return; - } + if let Some(ref vars) = *variables + && !vars.contains(scope) + && scope_data.inlined.is_none() + { + // Do not create a DIScope if there are no variables defined in this + // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat. + debug_context.scopes[scope] = parent_scope; + instantiated.insert(scope); + return; } let loc = cx.lookup_debug_loc(scope_data.span.lo()); diff --git a/src/gcc_util.rs b/src/gcc_util.rs index 202764d564916..955f902023573 100644 --- a/src/gcc_util.rs +++ b/src/gcc_util.rs @@ -136,14 +136,12 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec( let mut name = with_no_trimmed_paths!(layout.ty.to_string()); if let (&ty::Adt(def, _), &Variants::Single { index }) = (layout.ty.kind(), &layout.variants) + && def.is_enum() + && !def.variants().is_empty() { - if def.is_enum() && !def.variants().is_empty() { - write!(&mut name, "::{}", def.variant(index).name).unwrap(); - } + write!(&mut name, "::{}", def.variant(index).name).unwrap(); } if let (&ty::Coroutine(_, _), &Variants::Single { index }) = (layout.ty.kind(), &layout.variants) @@ -264,10 +264,10 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { } fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { - if let BackendRepr::Scalar(ref scalar) = self.backend_repr { - if scalar.is_bool() { - return cx.type_i1(); - } + if let BackendRepr::Scalar(ref scalar) = self.backend_repr + && scalar.is_bool() + { + return cx.type_i1(); } self.gcc_type(cx) } diff --git a/tests/lang_tests_common.rs b/tests/lang_tests_common.rs index 64c932a265819..d5a0d71c4b298 100644 --- a/tests/lang_tests_common.rs +++ b/tests/lang_tests_common.rs @@ -1,5 +1,7 @@ //! The common code for `tests/lang_tests_*.rs` +#![allow(clippy::uninlined_format_args)] + use std::env::{self, current_dir}; use std::path::{Path, PathBuf}; use std::process::Command; diff --git a/tests/run/ptr_cast.rs b/tests/run/ptr_cast.rs index c1254c51ce91d..e627886a9d575 100644 --- a/tests/run/ptr_cast.rs +++ b/tests/run/ptr_cast.rs @@ -5,6 +5,7 @@ // stdout: 10 // 10 // 42 +// 1 #![feature(no_core)] #![no_std] @@ -21,6 +22,8 @@ fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u3 ) } +static mut ONE: usize = 1; + #[no_mangle] extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { let (a, b, c, d, e, f, g, h, i, j) = int_cast(10, 42); @@ -28,6 +31,10 @@ extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { libc::printf(b"%d\n\0" as *const u8 as *const i8, c); libc::printf(b"%ld\n\0" as *const u8 as *const i8, d); libc::printf(b"%ld\n\0" as *const u8 as *const i8, j); + + let ptr = ONE as *mut usize; + let value = ptr as usize; + libc::printf(b"%ld\n\0" as *const u8 as *const i8, value); } 0 } From 565cf5a89e0d197d52cd428b0d78556eb88fc9a0 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Fri, 25 Apr 2025 20:25:51 +0200 Subject: [PATCH 1897/4206] Optimize documentation lints **a lot** (1/2) Turns out that `doc_markdown` uses a non-cheap rustdoc function to convert from markdown ranges into source spans. And it was using it a lot (about once every 18 lines of documentation on `tokio`, which ends up being about 1800 times). This ended up being about 18% of the total Clippy runtime as discovered by lintcheck --perf in docs-heavy crates. This PR optimizes one of the cases in which Clippy calls the function, and a future PR once pulldown-cmark/pulldown-cmark issue number 1034 is merged will be open. Note that not all crates were affected by this crate equally, those with more docs are affected far more than those light ones. --- clippy_lints/src/doc/markdown.rs | 70 +++++++++++++++++++++++++------- clippy_lints/src/doc/mod.rs | 9 ++-- 2 files changed, 60 insertions(+), 19 deletions(-) diff --git a/clippy_lints/src/doc/markdown.rs b/clippy_lints/src/doc/markdown.rs index 7a1c7c675d2ec..e40b4e20ea452 100644 --- a/clippy_lints/src/doc/markdown.rs +++ b/clippy_lints/src/doc/markdown.rs @@ -6,13 +6,15 @@ use rustc_lint::LateContext; use rustc_span::{BytePos, Pos, Span}; use url::Url; -use crate::doc::DOC_MARKDOWN; +use crate::doc::{DOC_MARKDOWN, Fragments}; +use std::ops::{ControlFlow, Range}; pub fn check( cx: &LateContext<'_>, valid_idents: &FxHashSet, text: &str, - span: Span, + fragments: &Fragments<'_>, + fragment_range: Range, code_level: isize, blockquote_level: isize, ) { @@ -64,23 +66,38 @@ pub fn check( close_parens += 1; } - // Adjust for the current word - let offset = word.as_ptr() as usize - text.as_ptr() as usize; - let span = Span::new( - span.lo() + BytePos::from_usize(offset), - span.lo() + BytePos::from_usize(offset + word.len()), - span.ctxt(), - span.parent(), - ); + // We'll use this offset to calculate the span to lint. + let fragment_offset = word.as_ptr() as usize - text.as_ptr() as usize; - check_word(cx, word, span, code_level, blockquote_level); + // Adjust for the current word + if check_word( + cx, + word, + fragments, + &fragment_range, + fragment_offset, + code_level, + blockquote_level, + ) + .is_break() + { + return; + } } } -fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize, blockquote_level: isize) { +fn check_word( + cx: &LateContext<'_>, + word: &str, + fragments: &Fragments<'_>, + range: &Range, + fragment_offset: usize, + code_level: isize, + blockquote_level: isize, +) -> ControlFlow<()> { /// Checks if a string is upper-camel-case, i.e., starts with an uppercase and /// contains at least two uppercase letters (`Clippy` is ok) and one lower-case - /// letter (`NASA` is ok). + /// letter (`NASA` is ok).[ /// Plurals are also excluded (`IDs` is ok). fn is_camel_case(s: &str) -> bool { if s.starts_with(|c: char| c.is_ascii_digit() | c.is_ascii_lowercase()) { @@ -117,6 +134,17 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize, b // try to get around the fact that `foo::bar` parses as a valid URL && !url.cannot_be_a_base() { + let Some(fragment_span) = fragments.span(cx, range.clone()) else { + return ControlFlow::Break(()); + }; + + let span = Span::new( + fragment_span.lo() + BytePos::from_usize(fragment_offset), + fragment_span.lo() + BytePos::from_usize(fragment_offset + word.len()), + fragment_span.ctxt(), + fragment_span.parent(), + ); + span_lint_and_sugg( cx, DOC_MARKDOWN, @@ -126,17 +154,28 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize, b format!("<{word}>"), Applicability::MachineApplicable, ); - return; + return ControlFlow::Continue(()); } // We assume that mixed-case words are not meant to be put inside backticks. (Issue #2343) // // We also assume that backticks are not necessary if inside a quote. (Issue #10262) if code_level > 0 || blockquote_level > 0 || (has_underscore(word) && has_hyphen(word)) { - return; + return ControlFlow::Break(()); } if has_underscore(word) || word.contains("::") || is_camel_case(word) || word.ends_with("()") { + let Some(fragment_span) = fragments.span(cx, range.clone()) else { + return ControlFlow::Break(()); + }; + + let span = Span::new( + fragment_span.lo() + BytePos::from_usize(fragment_offset), + fragment_span.lo() + BytePos::from_usize(fragment_offset + word.len()), + fragment_span.ctxt(), + fragment_span.parent(), + ); + span_lint_and_then( cx, DOC_MARKDOWN, @@ -149,4 +188,5 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize, b }, ); } + ControlFlow::Continue(()) } diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index ab77edf1147cb..5a6c0059e7cd7 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -730,7 +730,10 @@ struct Fragments<'a> { } impl Fragments<'_> { - fn span(self, cx: &LateContext<'_>, range: Range) -> Option { + /// get the span for the markdown range. Note that this function is not cheap, use it with + /// caution. + #[must_use] + fn span(&self, cx: &LateContext<'_>, range: Range) -> Option { source_span_for_markdown_range(cx.tcx, self.doc, &range, self.fragments) } } @@ -1068,9 +1071,7 @@ fn check_doc<'a, Events: Iterator, Range Date: Fri, 25 Apr 2025 22:35:58 +0200 Subject: [PATCH 1898/4206] Enable `[no-mentions]` and `[issue-links]` in `rustbot` --- triagebot.toml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 triagebot.toml diff --git a/triagebot.toml b/triagebot.toml new file mode 100644 index 0000000000000..13da0a87def3c --- /dev/null +++ b/triagebot.toml @@ -0,0 +1,7 @@ +# Documentation at https://forge.rust-lang.org/triagebot/index.html + +# Prevents un-canonicalized issue links (to avoid wrong issues being linked in r-l/rust) +[issue-links] + +# Prevents mentions in commits to avoid users being spammed +[no-mentions] From 3893560e694c28b100b75355622f23b63531d800 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 26 Apr 2025 16:02:17 -0400 Subject: [PATCH 1899/4206] Update to nightly-2025-04-26 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 452d3f22dc518..fbaa22190052e 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2025-04-25" +channel = "nightly-2025-04-26" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] From 5f294f099a4461fc965d9109a79b8da3f96380b9 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Sat, 26 Apr 2025 20:47:43 +0200 Subject: [PATCH 1900/4206] Improve test for FQS tuple struct pat/expr 1. Better explain what the test tests 2. Test slightly more cases --- ...sociated-type-tuple-struct-construction.rs | 24 ------- ...ated-type-tuple-struct-construction.stderr | 19 ------ .../associated-types/tuple-struct-expr-pat.rs | 46 +++++++++++++ .../tuple-struct-expr-pat.stderr | 67 +++++++++++++++++++ 4 files changed, 113 insertions(+), 43 deletions(-) delete mode 100644 tests/ui/associated-types/associated-type-tuple-struct-construction.rs delete mode 100644 tests/ui/associated-types/associated-type-tuple-struct-construction.stderr create mode 100644 tests/ui/associated-types/tuple-struct-expr-pat.rs create mode 100644 tests/ui/associated-types/tuple-struct-expr-pat.stderr diff --git a/tests/ui/associated-types/associated-type-tuple-struct-construction.rs b/tests/ui/associated-types/associated-type-tuple-struct-construction.rs deleted file mode 100644 index d5809ecd55d85..0000000000000 --- a/tests/ui/associated-types/associated-type-tuple-struct-construction.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Users cannot yet construct structs through associated types -// in both expressions and patterns - -#![feature(more_qualified_paths)] - -fn main() { - let ::Assoc(n) = ::Assoc(2); - //~^ ERROR expected method or associated constant, found associated type - //~| ERROR expected method or associated constant, found associated type - assert!(n == 2); -} - -struct TupleStruct(i8); - -struct Foo; - - -trait A { - type Assoc; -} - -impl A for Foo { - type Assoc = TupleStruct; -} diff --git a/tests/ui/associated-types/associated-type-tuple-struct-construction.stderr b/tests/ui/associated-types/associated-type-tuple-struct-construction.stderr deleted file mode 100644 index bca7deeb5128c..0000000000000 --- a/tests/ui/associated-types/associated-type-tuple-struct-construction.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0575]: expected method or associated constant, found associated type `A::Assoc` - --> $DIR/associated-type-tuple-struct-construction.rs:7:32 - | -LL | let ::Assoc(n) = ::Assoc(2); - | ^^^^^^^^^^^^^^^^^ - | - = note: can't use a type alias as a constructor - -error[E0575]: expected method or associated constant, found associated type `A::Assoc` - --> $DIR/associated-type-tuple-struct-construction.rs:7:9 - | -LL | let ::Assoc(n) = ::Assoc(2); - | ^^^^^^^^^^^^^^^^^ - | - = note: can't use a type alias as a constructor - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0575`. diff --git a/tests/ui/associated-types/tuple-struct-expr-pat.rs b/tests/ui/associated-types/tuple-struct-expr-pat.rs new file mode 100644 index 0000000000000..b0676717d6ffc --- /dev/null +++ b/tests/ui/associated-types/tuple-struct-expr-pat.rs @@ -0,0 +1,46 @@ +// Check that fully qualified syntax can **not** be used in tuple struct expressions (calls) and +// patterns. Both tuple struct expressions and patterns are resolved in value namespace and thus +// can't be resolved through associated *types*. + +#![feature(more_qualified_paths)] + +fn main() { + let as Trait>::Assoc() = as Trait>::Assoc(); + //~^ error: expected method or associated constant, found associated type + //~| error: expected method or associated constant, found associated type + let as Trait>::Assoc(_a) = as Trait>::Assoc(0); + //~^ error: expected method or associated constant, found associated type + //~| error: expected method or associated constant, found associated type + let as Trait>::Assoc(_a, _b) = as Trait>::Assoc(0, 1); + //~^ error: expected method or associated constant, found associated type + //~| error: expected method or associated constant, found associated type + let as Trait>::Assoc(ref _a, ref mut _b, mut _c) = as Trait>::Assoc(0, 1, 2); + //~^ error: expected method or associated constant, found associated type + //~| error: expected method or associated constant, found associated type +} + + +struct T; + +struct T0(); +struct T1(u8); +struct T2(u8, u8); +struct T3(u8, u8, u8); + +trait Trait { + type Assoc; +} + +impl Trait for T<0> { + type Assoc = T0; +} + +impl Trait for T<1> { + type Assoc = T1; +} +impl Trait for T<2> { + type Assoc = T2; +} +impl Trait for T<3> { + type Assoc = T3; +} diff --git a/tests/ui/associated-types/tuple-struct-expr-pat.stderr b/tests/ui/associated-types/tuple-struct-expr-pat.stderr new file mode 100644 index 0000000000000..d77fae0730b48 --- /dev/null +++ b/tests/ui/associated-types/tuple-struct-expr-pat.stderr @@ -0,0 +1,67 @@ +error[E0575]: expected method or associated constant, found associated type `Trait::Assoc` + --> $DIR/tuple-struct-expr-pat.rs:8:36 + | +LL | let as Trait>::Assoc() = as Trait>::Assoc(); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: can't use a type alias as a constructor + +error[E0575]: expected method or associated constant, found associated type `Trait::Assoc` + --> $DIR/tuple-struct-expr-pat.rs:8:9 + | +LL | let as Trait>::Assoc() = as Trait>::Assoc(); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: can't use a type alias as a constructor + +error[E0575]: expected method or associated constant, found associated type `Trait::Assoc` + --> $DIR/tuple-struct-expr-pat.rs:11:38 + | +LL | let as Trait>::Assoc(_a) = as Trait>::Assoc(0); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: can't use a type alias as a constructor + +error[E0575]: expected method or associated constant, found associated type `Trait::Assoc` + --> $DIR/tuple-struct-expr-pat.rs:11:9 + | +LL | let as Trait>::Assoc(_a) = as Trait>::Assoc(0); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: can't use a type alias as a constructor + +error[E0575]: expected method or associated constant, found associated type `Trait::Assoc` + --> $DIR/tuple-struct-expr-pat.rs:14:42 + | +LL | let as Trait>::Assoc(_a, _b) = as Trait>::Assoc(0, 1); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: can't use a type alias as a constructor + +error[E0575]: expected method or associated constant, found associated type `Trait::Assoc` + --> $DIR/tuple-struct-expr-pat.rs:14:9 + | +LL | let as Trait>::Assoc(_a, _b) = as Trait>::Assoc(0, 1); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: can't use a type alias as a constructor + +error[E0575]: expected method or associated constant, found associated type `Trait::Assoc` + --> $DIR/tuple-struct-expr-pat.rs:17:62 + | +LL | let as Trait>::Assoc(ref _a, ref mut _b, mut _c) = as Trait>::Assoc(0, 1, 2); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: can't use a type alias as a constructor + +error[E0575]: expected method or associated constant, found associated type `Trait::Assoc` + --> $DIR/tuple-struct-expr-pat.rs:17:9 + | +LL | let as Trait>::Assoc(ref _a, ref mut _b, mut _c) = as Trait>::Assoc(0, 1, 2); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: can't use a type alias as a constructor + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0575`. From bce7fe1818111ed9124412369ff1b36ffe5fdbe1 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Sun, 27 Apr 2025 16:05:44 +0200 Subject: [PATCH 1901/4206] Make error for tuple struct pat/expr w/ FQS clearer 1. Fix "expected" and the note for the pattern case 2. Add suggestions --- compiler/rustc_resolve/src/late.rs | 31 +++-- .../rustc_resolve/src/late/diagnostics.rs | 124 ++++++++++++++---- .../tuple-struct-expr-pat.fixed | 48 +++++++ .../associated-types/tuple-struct-expr-pat.rs | 10 +- .../tuple-struct-expr-pat.stderr | 66 +++++++--- 5 files changed, 222 insertions(+), 57 deletions(-) create mode 100644 tests/ui/associated-types/tuple-struct-expr-pat.fixed diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index bae2fdeecafcc..88818ad128060 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -402,7 +402,7 @@ pub(crate) enum AliasPossibility { } #[derive(Copy, Clone, Debug)] -pub(crate) enum PathSource<'a> { +pub(crate) enum PathSource<'a, 'c> { /// Type paths `Path`. Type, /// Trait paths in bounds or impls. @@ -416,7 +416,10 @@ pub(crate) enum PathSource<'a> { /// Paths in tuple struct patterns `Path(..)`. TupleStruct(Span, &'a [Span]), /// `m::A::B` in `::B::C`. - TraitItem(Namespace), + /// + /// Second field holds the "cause" of this one, i.e. the context within + /// which the trait item is resolved. Used for diagnostics. + TraitItem(Namespace, &'c PathSource<'a, 'c>), /// Paths in delegation item Delegation, /// An arg in a `use<'a, N>` precise-capturing bound. @@ -427,7 +430,7 @@ pub(crate) enum PathSource<'a> { DefineOpaques, } -impl<'a> PathSource<'a> { +impl<'a> PathSource<'a, '_> { fn namespace(self) -> Namespace { match self { PathSource::Type @@ -439,7 +442,7 @@ impl<'a> PathSource<'a> { | PathSource::TupleStruct(..) | PathSource::Delegation | PathSource::ReturnTypeNotation => ValueNS, - PathSource::TraitItem(ns) => ns, + PathSource::TraitItem(ns, _) => ns, PathSource::PreciseCapturingArg(ns) => ns, } } @@ -467,8 +470,9 @@ impl<'a> PathSource<'a> { PathSource::Trait(_) => "trait", PathSource::Pat => "unit struct, unit variant or constant", PathSource::Struct => "struct, variant or union type", - PathSource::TupleStruct(..) => "tuple struct or tuple variant", - PathSource::TraitItem(ns) => match ns { + PathSource::TraitItem(ValueNS, PathSource::TupleStruct(..)) + | PathSource::TupleStruct(..) => "tuple struct or tuple variant", + PathSource::TraitItem(ns, _) => match ns { TypeNS => "associated type", ValueNS => "method or associated constant", MacroNS => bug!("associated macro"), @@ -572,7 +576,7 @@ impl<'a> PathSource<'a> { ) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } ), - PathSource::TraitItem(ns) => match res { + PathSource::TraitItem(ns, _) => match res { Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) if ns == ValueNS => true, Res::Def(DefKind::AssocTy, _) if ns == TypeNS => true, _ => false, @@ -1983,7 +1987,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { &mut self, partial_res: PartialRes, path: &[Segment], - source: PathSource<'_>, + source: PathSource<'_, '_>, path_span: Span, ) { let proj_start = path.len() - partial_res.unresolved_segments(); @@ -4135,7 +4139,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { id: NodeId, qself: &Option>, path: &Path, - source: PathSource<'ast>, + source: PathSource<'ast, '_>, ) { self.smart_resolve_path_fragment( qself, @@ -4152,7 +4156,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { &mut self, qself: &Option>, path: &[Segment], - source: PathSource<'ast>, + source: PathSource<'ast, '_>, finalize: Finalize, record_partial_res: RecordPartialRes, parent_qself: Option<&QSelf>, @@ -4333,6 +4337,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { path_span, source.defer_to_typeck(), finalize, + source, ) { Ok(Some(partial_res)) if let Some(res) = partial_res.full_res() => { // if we also have an associated type that matches the ident, stash a suggestion @@ -4455,12 +4460,13 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { span: Span, defer_to_typeck: bool, finalize: Finalize, + source: PathSource<'ast, '_>, ) -> Result, Spanned>> { let mut fin_res = None; for (i, &ns) in [primary_ns, TypeNS, ValueNS].iter().enumerate() { if i == 0 || ns != primary_ns { - match self.resolve_qpath(qself, path, ns, finalize)? { + match self.resolve_qpath(qself, path, ns, finalize, source)? { Some(partial_res) if partial_res.unresolved_segments() == 0 || defer_to_typeck => { @@ -4497,6 +4503,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { path: &[Segment], ns: Namespace, finalize: Finalize, + source: PathSource<'ast, '_>, ) -> Result, Spanned>> { debug!( "resolve_qpath(qself={:?}, path={:?}, ns={:?}, finalize={:?})", @@ -4544,7 +4551,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let partial_res = self.smart_resolve_path_fragment( &None, &path[..=qself.position], - PathSource::TraitItem(ns), + PathSource::TraitItem(ns, &source), Finalize::with_root_span(finalize.node_id, finalize.path_span, qself.path_span), RecordPartialRes::No, Some(&qself), diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index d4fe446cc9f76..ac1479b152d97 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -174,7 +174,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { &mut self, path: &[Segment], span: Span, - source: PathSource<'_>, + source: PathSource<'_, '_>, res: Option, ) -> BaseError { // Make the base error. @@ -420,7 +420,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { path: &[Segment], following_seg: Option<&Segment>, span: Span, - source: PathSource<'_>, + source: PathSource<'_, '_>, res: Option, qself: Option<&QSelf>, ) -> (Diag<'tcx>, Vec) { @@ -525,12 +525,12 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { path: &[Segment], following_seg: Option<&Segment>, span: Span, - source: PathSource<'_>, + source: PathSource<'_, '_>, res: Option, qself: Option<&QSelf>, ) { if let Some(Res::Def(DefKind::AssocFn, _)) = res - && let PathSource::TraitItem(TypeNS) = source + && let PathSource::TraitItem(TypeNS, _) = source && let None = following_seg && let Some(qself) = qself && let TyKind::Path(None, ty_path) = &qself.ty.kind @@ -636,7 +636,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn try_lookup_name_relaxed( &mut self, err: &mut Diag<'_>, - source: PathSource<'_>, + source: PathSource<'_, '_>, path: &[Segment], following_seg: Option<&Segment>, span: Span, @@ -855,7 +855,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn suggest_trait_and_bounds( &mut self, err: &mut Diag<'_>, - source: PathSource<'_>, + source: PathSource<'_, '_>, res: Option, span: Span, base_error: &BaseError, @@ -932,7 +932,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn suggest_typo( &mut self, err: &mut Diag<'_>, - source: PathSource<'_>, + source: PathSource<'_, '_>, path: &[Segment], following_seg: Option<&Segment>, span: Span, @@ -978,7 +978,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn suggest_shadowed( &mut self, err: &mut Diag<'_>, - source: PathSource<'_>, + source: PathSource<'_, '_>, path: &[Segment], following_seg: Option<&Segment>, span: Span, @@ -1011,7 +1011,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn err_code_special_cases( &mut self, err: &mut Diag<'_>, - source: PathSource<'_>, + source: PathSource<'_, '_>, path: &[Segment], span: Span, ) { @@ -1056,7 +1056,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn suggest_self_ty( &mut self, err: &mut Diag<'_>, - source: PathSource<'_>, + source: PathSource<'_, '_>, path: &[Segment], span: Span, ) -> bool { @@ -1079,7 +1079,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn suggest_self_value( &mut self, err: &mut Diag<'_>, - source: PathSource<'_>, + source: PathSource<'_, '_>, path: &[Segment], span: Span, ) -> bool { @@ -1247,7 +1247,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn suggest_swapping_misplaced_self_ty_and_trait( &mut self, err: &mut Diag<'_>, - source: PathSource<'_>, + source: PathSource<'_, '_>, res: Option, span: Span, ) { @@ -1276,7 +1276,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { &mut self, err: &mut Diag<'_>, res: Option, - source: PathSource<'_>, + source: PathSource<'_, '_>, ) { let PathSource::TupleStruct(_, _) = source else { return }; let Some(Res::Def(DefKind::Fn, _)) = res else { return }; @@ -1288,7 +1288,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { &mut self, err: &mut Diag<'_>, res: Option, - source: PathSource<'_>, + source: PathSource<'_, '_>, span: Span, ) { let PathSource::Trait(_) = source else { return }; @@ -1337,7 +1337,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn suggest_pattern_match_with_let( &mut self, err: &mut Diag<'_>, - source: PathSource<'_>, + source: PathSource<'_, '_>, span: Span, ) -> bool { if let PathSource::Expr(_) = source @@ -1363,10 +1363,10 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn get_single_associated_item( &mut self, path: &[Segment], - source: &PathSource<'_>, + source: &PathSource<'_, '_>, filter_fn: &impl Fn(Res) -> bool, ) -> Option { - if let crate::PathSource::TraitItem(_) = source { + if let crate::PathSource::TraitItem(_, _) = source { let mod_path = &path[..path.len() - 1]; if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.resolve_path(mod_path, None, None) @@ -1471,7 +1471,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { /// Check if the source is call expression and the first argument is `self`. If true, /// return the span of whole call and the span for all arguments expect the first one (`self`). - fn call_has_self_arg(&self, source: PathSource<'_>) -> Option<(Span, Option)> { + fn call_has_self_arg(&self, source: PathSource<'_, '_>) -> Option<(Span, Option)> { let mut has_self_arg = None; if let PathSource::Expr(Some(parent)) = source && let ExprKind::Call(_, args) = &parent.kind @@ -1529,7 +1529,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { &mut self, err: &mut Diag<'_>, span: Span, - source: PathSource<'_>, + source: PathSource<'_, '_>, path: &[Segment], res: Res, path_str: &str, @@ -1581,7 +1581,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } }; - let find_span = |source: &PathSource<'_>, err: &mut Diag<'_>| { + let find_span = |source: &PathSource<'_, '_>, err: &mut Diag<'_>| { match source { PathSource::Expr(Some(Expr { span, kind: ExprKind::Call(_, _), .. })) | PathSource::TupleStruct(span, _) => { @@ -1965,8 +1965,86 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { err.span_label(span, fallback_label.to_string()); err.note("can't use `Self` as a constructor, you must use the implemented struct"); } - (Res::Def(DefKind::TyAlias | DefKind::AssocTy, _), _) if ns == ValueNS => { + ( + Res::Def(DefKind::TyAlias | DefKind::AssocTy, _), + PathSource::TraitItem(ValueNS, PathSource::TupleStruct(whole, args)), + ) => { + err.note("can't use a type alias as tuple pattern"); + + let mut suggestion = Vec::new(); + + if let &&[first, ..] = args + && let &&[.., last] = args + { + suggestion.extend([ + // "0: " has to be included here so that the fix is machine applicable. + // + // If this would only add " { " and then the code below add "0: ", + // rustfix would crash, because end of this suggestion is the same as start + // of the suggestion below. Thus, we have to merge these... + (span.between(first), " { 0: ".to_owned()), + (last.between(whole.shrink_to_hi()), " }".to_owned()), + ]); + + suggestion.extend( + args.iter() + .enumerate() + .skip(1) // See above + .map(|(index, &arg)| (arg.shrink_to_lo(), format!("{index}: "))), + ) + } else { + suggestion.push((span.between(whole.shrink_to_hi()), " {}".to_owned())); + } + + err.multipart_suggestion( + "use struct pattern instead", + suggestion, + Applicability::MachineApplicable, + ); + } + ( + Res::Def(DefKind::TyAlias | DefKind::AssocTy, _), + PathSource::TraitItem( + ValueNS, + PathSource::Expr(Some(ast::Expr { + span: whole, + kind: ast::ExprKind::Call(_, args), + .. + })), + ), + ) => { err.note("can't use a type alias as a constructor"); + + let mut suggestion = Vec::new(); + + if let [first, ..] = &**args + && let [.., last] = &**args + { + suggestion.extend([ + // "0: " has to be included here so that the fix is machine applicable. + // + // If this would only add " { " and then the code below add "0: ", + // rustfix would crash, because end of this suggestion is the same as start + // of the suggestion below. Thus, we have to merge these... + (span.between(first.span), " { 0: ".to_owned()), + (last.span.between(whole.shrink_to_hi()), " }".to_owned()), + ]); + + suggestion.extend( + args.iter() + .enumerate() + .skip(1) // See above + .map(|(index, arg)| (arg.span.shrink_to_lo(), format!("{index}: "))), + ) + } else { + suggestion.push((span.between(whole.shrink_to_hi()), " {}".to_owned())); + } + + err.multipart_suggestion( + "use struct expression instead", + suggestion, + Applicability::MachineApplicable, + ); } _ => return false, } @@ -2535,7 +2613,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn suggest_using_enum_variant( &mut self, err: &mut Diag<'_>, - source: PathSource<'_>, + source: PathSource<'_, '_>, def_id: DefId, span: Span, ) { @@ -2713,7 +2791,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { pub(crate) fn suggest_adding_generic_parameter( &self, path: &[Segment], - source: PathSource<'_>, + source: PathSource<'_, '_>, ) -> Option<(Span, &'static str, String, Applicability)> { let (ident, span) = match path { [segment] diff --git a/tests/ui/associated-types/tuple-struct-expr-pat.fixed b/tests/ui/associated-types/tuple-struct-expr-pat.fixed new file mode 100644 index 0000000000000..d6e2385f82103 --- /dev/null +++ b/tests/ui/associated-types/tuple-struct-expr-pat.fixed @@ -0,0 +1,48 @@ +// Check that fully qualified syntax can **not** be used in tuple struct expressions (calls) and +// patterns. Both tuple struct expressions and patterns are resolved in value namespace and thus +// can't be resolved through associated *types*. +// +//@ run-rustfix + +#![feature(more_qualified_paths)] + +fn main() { + let as Trait>::Assoc {} = as Trait>::Assoc {}; + //~^ error: expected method or associated constant, found associated type + //~| error: expected tuple struct or tuple variant, found associated type + let as Trait>::Assoc { 0: _a } = as Trait>::Assoc { 0: 0 }; + //~^ error: expected method or associated constant, found associated type + //~| error: expected tuple struct or tuple variant, found associated type + let as Trait>::Assoc { 0: _a, 1: _b } = as Trait>::Assoc { 0: 0, 1: 1 }; + //~^ error: expected method or associated constant, found associated type + //~| error: expected tuple struct or tuple variant, found associated type + let as Trait>::Assoc { 0: ref _a, 1: ref mut _b, 2: mut _c } = as Trait>::Assoc { 0: 0, 1: 1, 2: 2 }; + //~^ error: expected method or associated constant, found associated type + //~| error: expected tuple struct or tuple variant, found associated type +} + + +struct T; + +struct T0(); +struct T1(u8); +struct T2(u8, u8); +struct T3(u8, u8, u8); + +trait Trait { + type Assoc; +} + +impl Trait for T<0> { + type Assoc = T0; +} + +impl Trait for T<1> { + type Assoc = T1; +} +impl Trait for T<2> { + type Assoc = T2; +} +impl Trait for T<3> { + type Assoc = T3; +} diff --git a/tests/ui/associated-types/tuple-struct-expr-pat.rs b/tests/ui/associated-types/tuple-struct-expr-pat.rs index b0676717d6ffc..f27a5fe175390 100644 --- a/tests/ui/associated-types/tuple-struct-expr-pat.rs +++ b/tests/ui/associated-types/tuple-struct-expr-pat.rs @@ -1,22 +1,24 @@ // Check that fully qualified syntax can **not** be used in tuple struct expressions (calls) and // patterns. Both tuple struct expressions and patterns are resolved in value namespace and thus // can't be resolved through associated *types*. +// +//@ run-rustfix #![feature(more_qualified_paths)] fn main() { let as Trait>::Assoc() = as Trait>::Assoc(); //~^ error: expected method or associated constant, found associated type - //~| error: expected method or associated constant, found associated type + //~| error: expected tuple struct or tuple variant, found associated type let as Trait>::Assoc(_a) = as Trait>::Assoc(0); //~^ error: expected method or associated constant, found associated type - //~| error: expected method or associated constant, found associated type + //~| error: expected tuple struct or tuple variant, found associated type let as Trait>::Assoc(_a, _b) = as Trait>::Assoc(0, 1); //~^ error: expected method or associated constant, found associated type - //~| error: expected method or associated constant, found associated type + //~| error: expected tuple struct or tuple variant, found associated type let as Trait>::Assoc(ref _a, ref mut _b, mut _c) = as Trait>::Assoc(0, 1, 2); //~^ error: expected method or associated constant, found associated type - //~| error: expected method or associated constant, found associated type + //~| error: expected tuple struct or tuple variant, found associated type } diff --git a/tests/ui/associated-types/tuple-struct-expr-pat.stderr b/tests/ui/associated-types/tuple-struct-expr-pat.stderr index d77fae0730b48..135dfcb3447e5 100644 --- a/tests/ui/associated-types/tuple-struct-expr-pat.stderr +++ b/tests/ui/associated-types/tuple-struct-expr-pat.stderr @@ -1,66 +1,96 @@ error[E0575]: expected method or associated constant, found associated type `Trait::Assoc` - --> $DIR/tuple-struct-expr-pat.rs:8:36 + --> $DIR/tuple-struct-expr-pat.rs:10:36 | LL | let as Trait>::Assoc() = as Trait>::Assoc(); - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^-- help: use struct expression instead: `{}` | = note: can't use a type alias as a constructor -error[E0575]: expected method or associated constant, found associated type `Trait::Assoc` - --> $DIR/tuple-struct-expr-pat.rs:8:9 +error[E0575]: expected tuple struct or tuple variant, found associated type `Trait::Assoc` + --> $DIR/tuple-struct-expr-pat.rs:10:9 | LL | let as Trait>::Assoc() = as Trait>::Assoc(); - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^-- help: use struct pattern instead: `{}` | - = note: can't use a type alias as a constructor + = note: can't use a type alias as tuple pattern error[E0575]: expected method or associated constant, found associated type `Trait::Assoc` - --> $DIR/tuple-struct-expr-pat.rs:11:38 + --> $DIR/tuple-struct-expr-pat.rs:13:38 | LL | let as Trait>::Assoc(_a) = as Trait>::Assoc(0); | ^^^^^^^^^^^^^^^^^^^^^^ | = note: can't use a type alias as a constructor +help: use struct expression instead + | +LL - let as Trait>::Assoc(_a) = as Trait>::Assoc(0); +LL + let as Trait>::Assoc(_a) = as Trait>::Assoc { 0: 0 }; + | -error[E0575]: expected method or associated constant, found associated type `Trait::Assoc` - --> $DIR/tuple-struct-expr-pat.rs:11:9 +error[E0575]: expected tuple struct or tuple variant, found associated type `Trait::Assoc` + --> $DIR/tuple-struct-expr-pat.rs:13:9 | LL | let as Trait>::Assoc(_a) = as Trait>::Assoc(0); | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: can't use a type alias as a constructor + = note: can't use a type alias as tuple pattern +help: use struct pattern instead + | +LL - let as Trait>::Assoc(_a) = as Trait>::Assoc(0); +LL + let as Trait>::Assoc { 0: _a } = as Trait>::Assoc(0); + | error[E0575]: expected method or associated constant, found associated type `Trait::Assoc` - --> $DIR/tuple-struct-expr-pat.rs:14:42 + --> $DIR/tuple-struct-expr-pat.rs:16:42 | LL | let as Trait>::Assoc(_a, _b) = as Trait>::Assoc(0, 1); | ^^^^^^^^^^^^^^^^^^^^^^ | = note: can't use a type alias as a constructor +help: use struct expression instead + | +LL - let as Trait>::Assoc(_a, _b) = as Trait>::Assoc(0, 1); +LL + let as Trait>::Assoc(_a, _b) = as Trait>::Assoc { 0: 0, 1: 1 }; + | -error[E0575]: expected method or associated constant, found associated type `Trait::Assoc` - --> $DIR/tuple-struct-expr-pat.rs:14:9 +error[E0575]: expected tuple struct or tuple variant, found associated type `Trait::Assoc` + --> $DIR/tuple-struct-expr-pat.rs:16:9 | LL | let as Trait>::Assoc(_a, _b) = as Trait>::Assoc(0, 1); | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: can't use a type alias as a constructor + = note: can't use a type alias as tuple pattern +help: use struct pattern instead + | +LL - let as Trait>::Assoc(_a, _b) = as Trait>::Assoc(0, 1); +LL + let as Trait>::Assoc { 0: _a, 1: _b } = as Trait>::Assoc(0, 1); + | error[E0575]: expected method or associated constant, found associated type `Trait::Assoc` - --> $DIR/tuple-struct-expr-pat.rs:17:62 + --> $DIR/tuple-struct-expr-pat.rs:19:62 | LL | let as Trait>::Assoc(ref _a, ref mut _b, mut _c) = as Trait>::Assoc(0, 1, 2); | ^^^^^^^^^^^^^^^^^^^^^^ | = note: can't use a type alias as a constructor +help: use struct expression instead + | +LL - let as Trait>::Assoc(ref _a, ref mut _b, mut _c) = as Trait>::Assoc(0, 1, 2); +LL + let as Trait>::Assoc(ref _a, ref mut _b, mut _c) = as Trait>::Assoc { 0: 0, 1: 1, 2: 2 }; + | -error[E0575]: expected method or associated constant, found associated type `Trait::Assoc` - --> $DIR/tuple-struct-expr-pat.rs:17:9 +error[E0575]: expected tuple struct or tuple variant, found associated type `Trait::Assoc` + --> $DIR/tuple-struct-expr-pat.rs:19:9 | LL | let as Trait>::Assoc(ref _a, ref mut _b, mut _c) = as Trait>::Assoc(0, 1, 2); | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: can't use a type alias as a constructor + = note: can't use a type alias as tuple pattern +help: use struct pattern instead + | +LL - let as Trait>::Assoc(ref _a, ref mut _b, mut _c) = as Trait>::Assoc(0, 1, 2); +LL + let as Trait>::Assoc { 0: ref _a, 1: ref mut _b, 2: mut _c } = as Trait>::Assoc(0, 1, 2); + | error: aborting due to 8 previous errors From 8f765fc7a15b6a2f1de93251b9f65c6156fbfe33 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Sun, 27 Apr 2025 18:11:09 +0200 Subject: [PATCH 1902/4206] bless tests --- .../return-type-notation/path-missing.stderr | 4 +--- tests/ui/delegation/bad-resolve.stderr | 4 +--- tests/ui/delegation/glob-non-fn.stderr | 4 +--- tests/ui/namespace/namespace-mix.stderr | 4 ---- tests/ui/resolve/tuple-struct-alias.stderr | 15 +++++++++++---- tests/ui/ufcs/ufcs-partially-resolved.stderr | 2 -- 6 files changed, 14 insertions(+), 19 deletions(-) diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-missing.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-missing.stderr index edac09db89dae..677fc0e10bbda 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/path-missing.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/path-missing.stderr @@ -8,9 +8,7 @@ error[E0575]: expected method or associated constant, found associated type `A:: --> $DIR/path-missing.rs:12:5 | LL | ::bad(..): Send, - | ^^^^^^^^^^^^^^^^^ - | - = note: can't use a type alias as a constructor + | ^^^^^^^^^^^^^^^^^ not a method or associated constant error[E0220]: associated function `method` not found for `T` --> $DIR/path-missing.rs:19:8 diff --git a/tests/ui/delegation/bad-resolve.stderr b/tests/ui/delegation/bad-resolve.stderr index 966387e1d6164..fc6811292a6ff 100644 --- a/tests/ui/delegation/bad-resolve.stderr +++ b/tests/ui/delegation/bad-resolve.stderr @@ -44,9 +44,7 @@ error[E0575]: expected method or associated constant, found associated type `Tra --> $DIR/bad-resolve.rs:27:11 | LL | reuse ::Type; - | ^^^^^^^^^^^^^^^^^^ - | - = note: can't use a type alias as a constructor + | ^^^^^^^^^^^^^^^^^^ not a method or associated constant error[E0576]: cannot find method or associated constant `baz` in trait `Trait` --> $DIR/bad-resolve.rs:30:25 diff --git a/tests/ui/delegation/glob-non-fn.stderr b/tests/ui/delegation/glob-non-fn.stderr index 4b918c53b8489..f63c8e88c6fae 100644 --- a/tests/ui/delegation/glob-non-fn.stderr +++ b/tests/ui/delegation/glob-non-fn.stderr @@ -38,9 +38,7 @@ error[E0423]: expected function, found associated type `Trait::Type` --> $DIR/glob-non-fn.rs:30:11 | LL | reuse Trait::* { &self.0 } - | ^^^^^ - | - = note: can't use a type alias as a constructor + | ^^^^^ not a function error[E0046]: not all trait items implemented, missing: `CONST`, `Type`, `method` --> $DIR/glob-non-fn.rs:29:1 diff --git a/tests/ui/namespace/namespace-mix.stderr b/tests/ui/namespace/namespace-mix.stderr index 412ea4aba30b8..200d31cc71011 100644 --- a/tests/ui/namespace/namespace-mix.stderr +++ b/tests/ui/namespace/namespace-mix.stderr @@ -7,7 +7,6 @@ LL | pub struct TS(); LL | check(m1::S); | ^^^^^ | - = note: can't use a type alias as a constructor help: a tuple struct with a similar name exists | LL | check(m1::TS); @@ -35,7 +34,6 @@ LL | check(xm1::S); LL | pub struct TS(); | ------------- similarly named tuple struct `TS` defined here | - = note: can't use a type alias as a constructor help: a tuple struct with a similar name exists | LL | check(xm1::TS); @@ -61,7 +59,6 @@ LL | TV(), LL | check(m7::V); | ^^^^^ | - = note: can't use a type alias as a constructor help: a tuple variant with a similar name exists | LL | check(m7::TV); @@ -89,7 +86,6 @@ LL | check(xm7::V); LL | TV(), | -- similarly named tuple variant `TV` defined here | - = note: can't use a type alias as a constructor help: a tuple variant with a similar name exists | LL | check(xm7::TV); diff --git a/tests/ui/resolve/tuple-struct-alias.stderr b/tests/ui/resolve/tuple-struct-alias.stderr index a739ea43eed47..bf026a499b8c2 100644 --- a/tests/ui/resolve/tuple-struct-alias.stderr +++ b/tests/ui/resolve/tuple-struct-alias.stderr @@ -6,8 +6,6 @@ LL | struct S(u8, u16); ... LL | A(..) => {} | ^ help: a tuple struct with a similar name exists: `S` - | - = note: can't use a type alias as a constructor error[E0423]: expected function, tuple struct or tuple variant, found type alias `A` --> $DIR/tuple-struct-alias.rs:5:13 @@ -16,9 +14,18 @@ LL | struct S(u8, u16); | ------------------ similarly named tuple struct `S` defined here ... LL | let s = A(0, 1); - | ^ help: a tuple struct with a similar name exists: `S` + | ^ + | +help: a tuple struct with a similar name exists + | +LL - let s = A(0, 1); +LL + let s = S(0, 1); + | +help: you might have meant to use `:` for type annotation + | +LL - let s = A(0, 1); +LL + let s: A(0, 1); | - = note: can't use a type alias as a constructor error: aborting due to 2 previous errors diff --git a/tests/ui/ufcs/ufcs-partially-resolved.stderr b/tests/ui/ufcs/ufcs-partially-resolved.stderr index 0a9c190cb3561..69d6bd74a736d 100644 --- a/tests/ui/ufcs/ufcs-partially-resolved.stderr +++ b/tests/ui/ufcs/ufcs-partially-resolved.stderr @@ -235,8 +235,6 @@ LL | ::X; | ^^^^^^^^^^^^- | | | help: an associated function with a similar name exists: `Z` - | - = note: can't use a type alias as a constructor error[E0575]: expected associated type, found associated function `Dr::Z` --> $DIR/ufcs-partially-resolved.rs:54:12 From 8858b35c66dc7c07cf7abf0e74ea4370ff0210ef Mon Sep 17 00:00:00 2001 From: Cornelius Roemer Date: Sun, 27 Apr 2025 19:11:35 +0200 Subject: [PATCH 1903/4206] Fix a few more `clippy::version`s --- clippy_lints/src/attrs/mod.rs | 2 +- clippy_lints/src/casts/mod.rs | 2 +- clippy_lints/src/doc/mod.rs | 2 +- clippy_lints/src/implicit_saturating_sub.rs | 2 +- clippy_lints/src/loops/mod.rs | 2 +- clippy_lints/src/manual_abs_diff.rs | 2 +- clippy_lints/src/mem_replace.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/single_option_map.rs | 2 +- clippy_lints/src/types/mod.rs | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index f7f168cb26792..9a1242980418c 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -468,7 +468,7 @@ declare_clippy_lint! { /// #[ignore = "Some good reason"] /// fn test() {} /// ``` - #[clippy::version = "1.85.0"] + #[clippy::version = "1.88.0"] pub IGNORE_WITHOUT_REASON, pedantic, "ignored tests without messages" diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 7e4b435756724..51982c4951c97 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -780,7 +780,7 @@ declare_clippy_lint! { /// let aligned = std::ptr::dangling::(); /// let mut_ptr: *mut i64 = std::ptr::dangling_mut(); /// ``` - #[clippy::version = "1.87.0"] + #[clippy::version = "1.88.0"] pub MANUAL_DANGLING_PTR, style, "casting small constant literals to pointers to create dangling pointers" diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index ab77edf1147cb..87da380e95401 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -93,7 +93,7 @@ declare_clippy_lint! { /// ```no_run /// //! [first](x)second /// ``` - #[clippy::version = "1.86.0"] + #[clippy::version = "1.87.0"] pub DOC_LINK_CODE, nursery, "link with code back-to-back with other code" diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 514e72a48682d..0823ef53ef98a 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -69,7 +69,7 @@ declare_clippy_lint! { /// /// let result = a.saturating_sub(b); /// ``` - #[clippy::version = "1.44.0"] + #[clippy::version = "1.83.0"] pub INVERTED_SATURATING_SUB, correctness, "Check if a variable is smaller than another one and still subtract from it even if smaller" diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 2b66827e82eeb..56d2bef2305a7 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -778,7 +778,7 @@ declare_clippy_lint! { /// let _ = s[idx..]; /// } /// ``` - #[clippy::version = "1.83.0"] + #[clippy::version = "1.88.0"] pub CHAR_INDICES_AS_BYTE_INDICES, correctness, "using the character position yielded by `.chars().enumerate()` in a context where a byte index is expected" diff --git a/clippy_lints/src/manual_abs_diff.rs b/clippy_lints/src/manual_abs_diff.rs index c515e41f242f5..7d92208056eeb 100644 --- a/clippy_lints/src/manual_abs_diff.rs +++ b/clippy_lints/src/manual_abs_diff.rs @@ -36,7 +36,7 @@ declare_clippy_lint! { /// a.abs_diff(b) /// # ; /// ``` - #[clippy::version = "1.86.0"] + #[clippy::version = "1.87.0"] pub MANUAL_ABS_DIFF, complexity, "using an if-else pattern instead of `abs_diff`" diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index a54d835b538c1..28efd2038b387 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -62,7 +62,7 @@ declare_clippy_lint! { /// let mut an_option = Some(0); /// let taken = an_option.replace(1); /// ``` - #[clippy::version = "1.86.0"] + #[clippy::version = "1.87.0"] pub MEM_REPLACE_OPTION_WITH_SOME, style, "replacing an `Option` with `Some` instead of `replace()`" diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index ad374dee516cd..06aa5b6f1d2db 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4454,7 +4454,7 @@ declare_clippy_lint! { /// values.contains(&10) /// } /// ``` - #[clippy::version = "1.86.0"] + #[clippy::version = "1.87.0"] pub MANUAL_CONTAINS, perf, "unnecessary `iter().any()` on slices that can be replaced with `contains()`" diff --git a/clippy_lints/src/single_option_map.rs b/clippy_lints/src/single_option_map.rs index 1fb54950612a5..cc497c97a4725 100644 --- a/clippy_lints/src/single_option_map.rs +++ b/clippy_lints/src/single_option_map.rs @@ -30,7 +30,7 @@ declare_clippy_lint! { /// param * 2 /// } /// ``` - #[clippy::version = "1.86.0"] + #[clippy::version = "1.87.0"] pub SINGLE_OPTION_MAP, nursery, "Checks for functions with method calls to `.map(_)` on an arg of type `Option` as the outermost expression." diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 3147058b4cda0..c1c7cc5165652 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -385,7 +385,7 @@ declare_clippy_lint! { /// ```no_run /// let right: std::borrow::Cow<'_, [u8]>; /// ``` - #[clippy::version = "1.85.0"] + #[clippy::version = "1.87.0"] pub OWNED_COW, style, "needlessly owned Cow type" From c7d3d6d4683ee5d440a51a53e2601ac7bd13ed9f Mon Sep 17 00:00:00 2001 From: Cornelius Roemer Date: Sun, 27 Apr 2025 19:27:21 +0200 Subject: [PATCH 1904/4206] Update clippy_lints/src/manual_abs_diff.rs --- clippy_lints/src/manual_abs_diff.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/manual_abs_diff.rs b/clippy_lints/src/manual_abs_diff.rs index 7d92208056eeb..bac4b3d32f2a5 100644 --- a/clippy_lints/src/manual_abs_diff.rs +++ b/clippy_lints/src/manual_abs_diff.rs @@ -36,7 +36,7 @@ declare_clippy_lint! { /// a.abs_diff(b) /// # ; /// ``` - #[clippy::version = "1.87.0"] + #[clippy::version = "1.88.0"] pub MANUAL_ABS_DIFF, complexity, "using an if-else pattern instead of `abs_diff`" From 6e2490ca9f476d8da0fe519caa8db688a3d3a78f Mon Sep 17 00:00:00 2001 From: Urgau <3616612+Urgau@users.noreply.github.com> Date: Sun, 27 Apr 2025 20:14:46 +0200 Subject: [PATCH 1905/4206] Merge pull request #1576 from Urgau/triagebot-issue-links-no-mentions Enable `[no-mentions]` and `[issue-links]` in `rustbot` --- triagebot.toml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 triagebot.toml diff --git a/triagebot.toml b/triagebot.toml new file mode 100644 index 0000000000000..13da0a87def3c --- /dev/null +++ b/triagebot.toml @@ -0,0 +1,7 @@ +# Documentation at https://forge.rust-lang.org/triagebot/index.html + +# Prevents un-canonicalized issue links (to avoid wrong issues being linked in r-l/rust) +[issue-links] + +# Prevents mentions in commits to avoid users being spammed +[no-mentions] From daaae11f4dd49285ee5cebf8f02586606401c22a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 24 Apr 2025 22:11:23 +0000 Subject: [PATCH 1906/4206] Implement the internal feature `cfg_target_has_reliable_f16_f128` Support for `f16` and `f128` is varied across targets, backends, and backend versions. Eventually we would like to reach a point where all backends support these approximately equally, but until then we have to work around some of these nuances of support being observable. Introduce the `cfg_target_has_reliable_f16_f128` internal feature, which provides the following new configuration gates: * `cfg(target_has_reliable_f16)` * `cfg(target_has_reliable_f16_math)` * `cfg(target_has_reliable_f128)` * `cfg(target_has_reliable_f128_math)` `reliable_f16` and `reliable_f128` indicate that basic arithmetic for the type works correctly. The `_math` versions indicate that anything relying on `libm` works correctly, since sometimes this hits a separate class of codegen bugs. These options match configuration set by the build script at [1]. The logic for LLVM support is duplicated as-is from the same script. There are a few possible updates that will come as a follow up. The config introduced here is not planned to ever become stable, it is only intended to replace the build scripts for `std` tests and `compiler-builtins` that don't have any way to configure based on the codegen backend. MCP: https://github.com/rust-lang/compiler-team/issues/866 Closes: https://github.com/rust-lang/compiler-team/issues/866 [1]: https://github.com/rust-lang/rust/blob/555e1d0386f024a8359645c3217f4b3eae9be042/library/std/build.rs#L84-L186 --- src/lib.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9d9e790289cf6..ab09a6f8b38e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,8 +41,8 @@ use std::sync::Arc; use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::settings::{self, Configurable}; -use rustc_codegen_ssa::CodegenResults; use rustc_codegen_ssa::traits::CodegenBackend; +use rustc_codegen_ssa::{CodegenResults, TargetConfig}; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_session::Session; @@ -178,7 +178,7 @@ impl CodegenBackend for CraneliftCodegenBackend { } } - fn target_features_cfg(&self, sess: &Session) -> (Vec, Vec) { + fn target_config(&self, sess: &Session) -> TargetConfig { // FIXME return the actually used target features. this is necessary for #[cfg(target_feature)] let target_features = if sess.target.arch == "x86_64" && sess.target.os != "none" { // x86_64 mandates SSE2 support and rustc requires the x87 feature to be enabled @@ -197,7 +197,16 @@ impl CodegenBackend for CraneliftCodegenBackend { }; // FIXME do `unstable_target_features` properly let unstable_target_features = target_features.clone(); - (target_features, unstable_target_features) + + TargetConfig { + target_features, + unstable_target_features, + // Cranelift does not yet support f16 or f128 + has_reliable_f16: false, + has_reliable_f16_math: false, + has_reliable_f128: false, + has_reliable_f128_math: false, + } } fn print_version(&self) { From d62fe1e043dae471e6f29648eaddcac876b4e962 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 24 Apr 2025 22:11:23 +0000 Subject: [PATCH 1907/4206] Implement the internal feature `cfg_target_has_reliable_f16_f128` Support for `f16` and `f128` is varied across targets, backends, and backend versions. Eventually we would like to reach a point where all backends support these approximately equally, but until then we have to work around some of these nuances of support being observable. Introduce the `cfg_target_has_reliable_f16_f128` internal feature, which provides the following new configuration gates: * `cfg(target_has_reliable_f16)` * `cfg(target_has_reliable_f16_math)` * `cfg(target_has_reliable_f128)` * `cfg(target_has_reliable_f128_math)` `reliable_f16` and `reliable_f128` indicate that basic arithmetic for the type works correctly. The `_math` versions indicate that anything relying on `libm` works correctly, since sometimes this hits a separate class of codegen bugs. These options match configuration set by the build script at [1]. The logic for LLVM support is duplicated as-is from the same script. There are a few possible updates that will come as a follow up. The config introduced here is not planned to ever become stable, it is only intended to replace the build scripts for `std` tests and `compiler-builtins` that don't have any way to configure based on the codegen backend. MCP: https://github.com/rust-lang/compiler-team/issues/866 Closes: https://github.com/rust-lang/compiler-team/issues/866 [1]: https://github.com/rust-lang/rust/blob/555e1d0386f024a8359645c3217f4b3eae9be042/library/std/build.rs#L84-L186 --- src/gcc_util.rs | 2 +- src/lib.rs | 22 ++++++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/gcc_util.rs b/src/gcc_util.rs index 955f902023573..2b053abdd190a 100644 --- a/src/gcc_util.rs +++ b/src/gcc_util.rs @@ -55,7 +55,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec. all_rust_features.push((false, feature)); } else if !feature.is_empty() && diagnostics { diff --git a/src/lib.rs b/src/lib.rs index 555f164e53fd6..2c5a787168381 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -102,7 +102,7 @@ use rustc_codegen_ssa::back::write::{ }; use rustc_codegen_ssa::base::codegen_crate; use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBackendMethods}; -use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen}; +use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetConfig}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::IntoDynSyncSend; use rustc_errors::DiagCtxtHandle; @@ -260,8 +260,8 @@ impl CodegenBackend for GccCodegenBackend { .join(sess) } - fn target_features_cfg(&self, sess: &Session) -> (Vec, Vec) { - target_features_cfg(sess, &self.target_info) + fn target_config(&self, sess: &Session) -> TargetConfig { + target_config(sess, &self.target_info) } } @@ -485,10 +485,7 @@ fn to_gcc_opt_level(optlevel: Option) -> OptimizationLevel { } /// Returns the features that should be set in `cfg(target_feature)`. -fn target_features_cfg( - sess: &Session, - target_info: &LockedTargetInfo, -) -> (Vec, Vec) { +fn target_config(sess: &Session, target_info: &LockedTargetInfo) -> TargetConfig { // TODO(antoyo): use global_gcc_features. let f = |allow_unstable| { sess.target @@ -523,5 +520,14 @@ fn target_features_cfg( let target_features = f(false); let unstable_target_features = f(true); - (target_features, unstable_target_features) + + TargetConfig { + target_features, + unstable_target_features, + // There are no known bugs with GCC support for f16 or f128 + has_reliable_f16: true, + has_reliable_f16_math: true, + has_reliable_f128: true, + has_reliable_f128_math: true, + } } From c179f96fa923514906361af40a956a5284685822 Mon Sep 17 00:00:00 2001 From: Andrew Zhogin Date: Mon, 26 Aug 2024 16:45:15 +0300 Subject: [PATCH 1908/4206] AsyncDrop implementation using shim codegen of async_drop_in_place::{closure}, scoped async drop added. --- src/abi/mod.rs | 9 +++++---- src/base.rs | 6 +++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/abi/mod.rs b/src/abi/mod.rs index ddd119e0c6108..5f631405a9a4a 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -441,7 +441,9 @@ pub(crate) fn codegen_terminator_call<'tcx>( Err(instance) => Some(instance), } } - InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None) => { + // We don't need AsyncDropGlueCtorShim here because it is not `noop func`, + // it is `func returning noop future` + InstanceKind::DropGlue(_, None) => { // empty drop glue - a nop. let dest = target.expect("Non terminating drop_in_place_real???"); let ret_block = fx.get_block(dest); @@ -707,9 +709,8 @@ pub(crate) fn codegen_drop<'tcx>( let ty = drop_place.layout().ty; let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty); - if let ty::InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None) = - drop_instance.def - { + // AsyncDropGlueCtorShim can't be here + if let ty::InstanceKind::DropGlue(_, None) = drop_instance.def { // we don't actually need to drop anything } else { match ty.kind() { diff --git a/src/base.rs b/src/base.rs index adaa754491e56..e9c7186b03c9f 100644 --- a/src/base.rs +++ b/src/base.rs @@ -565,7 +565,11 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { | TerminatorKind::CoroutineDrop => { bug!("shouldn't exist at codegen {:?}", bb_data.terminator()); } - TerminatorKind::Drop { place, target, unwind: _, replace: _ } => { + TerminatorKind::Drop { place, target, unwind: _, replace: _, drop, async_fut } => { + assert!( + async_fut.is_none() && drop.is_none(), + "Async Drop must be expanded or reset to sync before codegen" + ); let drop_place = codegen_place(fx, *place); crate::abi::codegen_drop(fx, source_info, drop_place, *target); } From fcf198b5391129ca7ff2b8f39bbf51a4ba2416e7 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 28 Apr 2025 15:25:21 +0000 Subject: [PATCH 1909/4206] Rustup to rustc 1.88.0-nightly (cb31a009e 2025-04-27) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 93dfecedb6d6a..acc8cf728d393 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-04-21" +channel = "nightly-2025-04-28" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 17403cd406057139cd12bd7d19b81bbd75a6c41b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 28 Apr 2025 15:15:40 +0000 Subject: [PATCH 1910/4206] Fix rustc test suite --- scripts/test_rustc_tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 575467185c8bb..f449f4b323cb2 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -83,6 +83,7 @@ rm tests/ui/codegen/issue-28950.rs # depends on stack size optimizations rm tests/ui/codegen/init-large-type.rs # same rm -r tests/run-make/fmt-write-bloat/ # tests an optimization rm tests/ui/statics/const_generics.rs # same +rm tests/ui/linking/executable-no-mangle-strip.rs # requires --gc-sections to work for statics # backend specific tests # ====================== @@ -119,7 +120,6 @@ rm tests/ui/mir/mir_raw_fat_ptr.rs # same rm tests/ui/consts/issue-33537.rs # same rm tests/ui/consts/const-mut-refs-crate.rs # same rm tests/ui/abi/large-byval-align.rs # exceeds implementation limit of Cranelift -rm tests/ui/abi/simd-abi-checks-avx.rs # attempts to declare function with two different signatures # doesn't work due to the way the rustc test suite is invoked. # should work when using ./x.py test the way it is intended From 3f4e535e2e9c1c7116242b0fac41ae9d36953cb8 Mon Sep 17 00:00:00 2001 From: apiraino Date: Mon, 28 Apr 2025 16:31:13 +0200 Subject: [PATCH 1911/4206] Add T-compiler backports Zulip notifications --- triagebot.toml | 47 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index 0f17d022fbb84..2503d24b27023 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -606,9 +606,6 @@ message_on_remove = "Issue #{number}'s prioritization request has been removed." message_on_close = "Issue #{number} has been closed while requested for prioritization." message_on_reopen = "Issue #{number} has been reopened." -# FIXME: Patch triagebot to support `notify-zulip.
//! [Struct]
+
//! [foo::Struct]
 //! This is an intra doc injection test for modules
-//! [Struct]
+//! [foo::Struct]
 //! This is an intra doc injection test for modules
 
 pub struct Struct;
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
index dd359326c61d6..a8d9530946677 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
@@ -1072,9 +1072,9 @@ fn test_mod_hl_injection() {
     check_highlighting(
         r##"
 //- /foo.rs
-//! [Struct]
+//! [foo::Struct]
 //! This is an intra doc injection test for modules
-//! [Struct]
+//! [foo::Struct]
 //! This is an intra doc injection test for modules
 
 pub struct Struct;
@@ -1097,9 +1097,9 @@ mod foo;
 /// This is an intra doc injection test for modules
 mod foo;
 //- /foo.rs
-//! [Struct]
+//! [foo::Struct]
 //! This is an intra doc injection test for modules
-//! [Struct]
+//! [foo::Struct]
 //! This is an intra doc injection test for modules
 
 pub struct Struct;

From b9a3e70ccb6f1da30a594ff30833a4b6e0a81e6a Mon Sep 17 00:00:00 2001
From: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com>
Date: Tue, 6 May 2025 16:27:23 +0900
Subject: [PATCH 2002/4206] Update crates/hir-expand/src/attrs.rs

Co-authored-by: Lukas Wirth 
---
 src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
index b350a6f8ac084..9eac5c2c7217d 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
@@ -460,7 +460,7 @@ pub fn collect_attrs(
     owner: &dyn ast::HasAttrs,
 ) -> impl Iterator)> {
     let inner_attrs =
-        inner_attributes(owner.syntax()).into_iter().flatten().map(|attr| (attr, true));
+        inner_attributes(owner.syntax()).into_iter().flatten().zip(iter::repeat(true));
     let outer_attrs = ast::AttrDocCommentIter::from_syntax_node(owner.syntax())
         .filter(|el| match el {
             Either::Left(attr) => attr.kind().is_outer(),

From 674e10e9828ab0701df24c6d5385b6b95e04896f Mon Sep 17 00:00:00 2001
From: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com>
Date: Tue, 6 May 2025 16:27:36 +0900
Subject: [PATCH 2003/4206] Update crates/hir-expand/src/attrs.rs

Co-authored-by: Lukas Wirth 
---
 src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
index 9eac5c2c7217d..5fe95f3043ef4 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
@@ -466,7 +466,7 @@ pub fn collect_attrs(
             Either::Left(attr) => attr.kind().is_outer(),
             Either::Right(comment) => comment.is_outer(),
         })
-        .map(|attr| (attr, false));
+        .zip(iter::repeat(false));
     outer_attrs
         .chain(inner_attrs)
         .enumerate()

From a8b8b2be4781ddab3abd5dff647f34992312c508 Mon Sep 17 00:00:00 2001
From: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com>
Date: Tue, 6 May 2025 17:08:12 +0900
Subject: [PATCH 2004/4206] import std::iter::repeat

Signed-off-by: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com>
---
 src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
index 5fe95f3043ef4..8b9e1c42c1ae8 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
@@ -1,4 +1,5 @@
 //! A higher level attributes based on TokenTree, with also some shortcuts.
+use std::iter;
 use std::{borrow::Cow, fmt, ops};
 
 use base_db::Crate;

From 7bf0c0034ea191d9cb6e3bbff2c58aaaa437cbb3 Mon Sep 17 00:00:00 2001
From: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com>
Date: Tue, 6 May 2025 17:09:28 +0900
Subject: [PATCH 2005/4206] Remove ast index mask

Signed-off-by: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com>
---
 .../crates/hir-expand/src/attrs.rs              | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
index 8b9e1c42c1ae8..4e519452aa69b 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
@@ -175,21 +175,24 @@ pub struct AttrId {
 // FIXME: This only handles a single level of cfg_attr nesting
 // that is `#[cfg_attr(all(), cfg_attr(all(), cfg(any())))]` breaks again
 impl AttrId {
-    const AST_INDEX_MASK: usize = 0x00FF_FFFF;
-    const INNER_ATTR_BIT: usize = 1 << 31;
+    const INNER_ATTR_SET_BIT: usize = 1 << 31;
 
     pub fn new(id: usize, is_inner: bool) -> Self {
-        let id = id & Self::AST_INDEX_MASK;
-        let id = if is_inner { id | Self::INNER_ATTR_BIT } else { id };
-        Self { id: id as u32 }
+        Self {
+            id: if is_inner {
+                id | Self::INNER_ATTR_SET_BIT
+            } else {
+                id & !Self::INNER_ATTR_SET_BIT
+            } as u32,
+        }
     }
 
     pub fn ast_index(&self) -> usize {
-        self.id as usize & Self::AST_INDEX_MASK
+        self.id as usize & !Self::INNER_ATTR_SET_BIT
     }
 
     pub fn is_inner_attr(&self) -> bool {
-        (self.id as usize) & Self::INNER_ATTR_BIT != 0
+        (self.id as usize) & Self::INNER_ATTR_SET_BIT != 0
     }
 }
 

From 6e966d75fd6349d1aee76b9a49dcd7e11206b000 Mon Sep 17 00:00:00 2001
From: Tshepang Mbambo 
Date: Tue, 6 May 2025 14:56:51 +0200
Subject: [PATCH 2006/4206] avoid duplicating commands

The 2 commands do the same thing.
Also, follow style used elsewhere in the guide.
---
 src/doc/rustc-dev-guide/src/tests/intro.md | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/src/doc/rustc-dev-guide/src/tests/intro.md b/src/doc/rustc-dev-guide/src/tests/intro.md
index 7bf30b106b43b..c55d60f4a5c7b 100644
--- a/src/doc/rustc-dev-guide/src/tests/intro.md
+++ b/src/doc/rustc-dev-guide/src/tests/intro.md
@@ -102,11 +102,12 @@ by passing a path to a book to `./x test`.
 
 ### Documentation link checker
 
-Links across all documentation is validated with a link checker tool.
+Links across all documentation is validated with a link checker tool,
+and it can be invoked so:
 
-> Example: `./x test src/tools/linkchecker`
-
-> Example: `./x test linkchecker`
+```console
+./x test linkchecker
+```
 
 This requires building all of the documentation, which might take a while.
 

From 94aa0d9a7538bd8cbf765ba017243bf0aad2b258 Mon Sep 17 00:00:00 2001
From: Alex Macleod 
Date: Tue, 6 May 2025 14:07:14 +0000
Subject: [PATCH 2007/4206] Update clippy_lints_internal to 2024 edition

---
 clippy_lints_internal/Cargo.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clippy_lints_internal/Cargo.toml b/clippy_lints_internal/Cargo.toml
index 2a0ceac27a324..a8293a1ad395d 100644
--- a/clippy_lints_internal/Cargo.toml
+++ b/clippy_lints_internal/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "clippy_lints_internal"
 version = "0.0.1"
-edition = "2021"
+edition = "2024"
 
 [dependencies]
 clippy_config = { path = "../clippy_config" }

From 737d3b3363ec98d90608b9ef3951f785960ea900 Mon Sep 17 00:00:00 2001
From: Alex Macleod 
Date: Tue, 6 May 2025 13:20:01 +0000
Subject: [PATCH 2008/4206] Remove some unused `#![feature]`s

---
 clippy_config/src/lib.rs                      |  2 +-
 clippy_dev/src/lib.rs                         |  1 -
 clippy_lints/src/lib.rs                       |  2 --
 clippy_lints_internal/src/lib.rs              |  2 +-
 clippy_utils/src/lib.rs                       |  3 ---
 lintcheck/src/main.rs                         |  1 -
 src/driver.rs                                 |  1 -
 tests/compile-test.rs                         |  2 +-
 tests/ui/bool_to_int_with_if.fixed            |  1 -
 tests/ui/bool_to_int_with_if.rs               |  1 -
 tests/ui/bool_to_int_with_if.stderr           | 22 ++++++++--------
 tests/ui/comparison_to_empty.fixed            |  1 -
 tests/ui/comparison_to_empty.rs               |  1 -
 tests/ui/comparison_to_empty.stderr           | 26 +++++++++----------
 tests/ui/needless_if.fixed                    |  1 -
 tests/ui/needless_if.rs                       |  1 -
 tests/ui/needless_if.stderr                   | 14 +++++-----
 .../redundant_pattern_matching_option.fixed   |  2 +-
 tests/ui/redundant_pattern_matching_option.rs |  2 +-
 19 files changed, 36 insertions(+), 50 deletions(-)

diff --git a/clippy_config/src/lib.rs b/clippy_config/src/lib.rs
index c227b8900b74a..33608591fc746 100644
--- a/clippy_config/src/lib.rs
+++ b/clippy_config/src/lib.rs
@@ -1,4 +1,4 @@
-#![feature(rustc_private, array_windows, let_chains)]
+#![feature(rustc_private)]
 #![warn(
     trivial_casts,
     trivial_numeric_casts,
diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs
index c1ffaf269c6fe..db4b4d07c1563 100644
--- a/clippy_dev/src/lib.rs
+++ b/clippy_dev/src/lib.rs
@@ -1,4 +1,3 @@
-#![feature(let_chains)]
 #![feature(rustc_private)]
 #![warn(
     trivial_casts,
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 62e2b565b4827..ad8b223b3aadb 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -1,5 +1,4 @@
 #![feature(array_windows)]
-#![feature(binary_heap_into_iter_sorted)]
 #![feature(box_patterns)]
 #![feature(macro_metavar_expr_concat)]
 #![feature(f128)]
@@ -7,7 +6,6 @@
 #![feature(if_let_guard)]
 #![feature(iter_intersperse)]
 #![feature(iter_partition_in_place)]
-#![feature(let_chains)]
 #![feature(never_type)]
 #![feature(round_char_boundary)]
 #![feature(rustc_private)]
diff --git a/clippy_lints_internal/src/lib.rs b/clippy_lints_internal/src/lib.rs
index da37fd3d8271d..308d161b9d6d1 100644
--- a/clippy_lints_internal/src/lib.rs
+++ b/clippy_lints_internal/src/lib.rs
@@ -1,4 +1,4 @@
-#![feature(let_chains, rustc_private)]
+#![feature(rustc_private)]
 #![allow(
     clippy::missing_docs_in_private_items,
     clippy::must_use_candidate,
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index bbd0c262c2460..0a9c39c41bd81 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -1,9 +1,6 @@
-#![feature(array_chunks)]
 #![feature(box_patterns)]
 #![feature(if_let_guard)]
-#![feature(macro_metavar_expr_concat)]
 #![feature(macro_metavar_expr)]
-#![feature(let_chains)]
 #![feature(never_type)]
 #![feature(rustc_private)]
 #![feature(assert_matches)]
diff --git a/lintcheck/src/main.rs b/lintcheck/src/main.rs
index fe488ef89da1f..d4bf6cd48a152 100644
--- a/lintcheck/src/main.rs
+++ b/lintcheck/src/main.rs
@@ -6,7 +6,6 @@
 // positives.
 
 #![feature(iter_collect_into)]
-#![feature(let_chains)]
 #![warn(
     trivial_casts,
     trivial_numeric_casts,
diff --git a/src/driver.rs b/src/driver.rs
index 87ca9c5beddfb..f8acf88cf81c6 100644
--- a/src/driver.rs
+++ b/src/driver.rs
@@ -1,7 +1,6 @@
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
 #![feature(rustc_private)]
-#![feature(let_chains)]
 // warn on lints, that are included in `rust-lang/rust`s bootstrap
 #![warn(rust_2018_idioms, unused_lifetimes)]
 // warn on rustc internal lints
diff --git a/tests/compile-test.rs b/tests/compile-test.rs
index 6d391bd622a8d..78b27e2f61399 100644
--- a/tests/compile-test.rs
+++ b/tests/compile-test.rs
@@ -1,4 +1,4 @@
-#![feature(rustc_private, let_chains)]
+#![feature(rustc_private)]
 #![warn(rust_2018_idioms, unused_lifetimes)]
 #![allow(unused_extern_crates)]
 
diff --git a/tests/ui/bool_to_int_with_if.fixed b/tests/ui/bool_to_int_with_if.fixed
index ed6141244b409..7fa7c016f9351 100644
--- a/tests/ui/bool_to_int_with_if.fixed
+++ b/tests/ui/bool_to_int_with_if.fixed
@@ -1,4 +1,3 @@
-#![feature(let_chains)]
 #![warn(clippy::bool_to_int_with_if)]
 #![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)]
 
diff --git a/tests/ui/bool_to_int_with_if.rs b/tests/ui/bool_to_int_with_if.rs
index 3f1f1c766e460..2295d6f1362d2 100644
--- a/tests/ui/bool_to_int_with_if.rs
+++ b/tests/ui/bool_to_int_with_if.rs
@@ -1,4 +1,3 @@
-#![feature(let_chains)]
 #![warn(clippy::bool_to_int_with_if)]
 #![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)]
 
diff --git a/tests/ui/bool_to_int_with_if.stderr b/tests/ui/bool_to_int_with_if.stderr
index 94089bc6dc8ef..e4ae57304141a 100644
--- a/tests/ui/bool_to_int_with_if.stderr
+++ b/tests/ui/bool_to_int_with_if.stderr
@@ -1,5 +1,5 @@
 error: boolean to int conversion using if
-  --> tests/ui/bool_to_int_with_if.rs:14:5
+  --> tests/ui/bool_to_int_with_if.rs:13:5
    |
 LL | /     if a {
 LL | |
@@ -14,7 +14,7 @@ LL | |     };
    = help: to override `-D warnings` add `#[allow(clippy::bool_to_int_with_if)]`
 
 error: boolean to int conversion using if
-  --> tests/ui/bool_to_int_with_if.rs:20:5
+  --> tests/ui/bool_to_int_with_if.rs:19:5
    |
 LL | /     if a {
 LL | |
@@ -27,7 +27,7 @@ LL | |     };
    = note: `!a as i32` or `(!a).into()` can also be valid options
 
 error: boolean to int conversion using if
-  --> tests/ui/bool_to_int_with_if.rs:26:5
+  --> tests/ui/bool_to_int_with_if.rs:25:5
    |
 LL | /     if !a {
 LL | |
@@ -40,7 +40,7 @@ LL | |     };
    = note: `!a as i32` or `(!a).into()` can also be valid options
 
 error: boolean to int conversion using if
-  --> tests/ui/bool_to_int_with_if.rs:32:5
+  --> tests/ui/bool_to_int_with_if.rs:31:5
    |
 LL | /     if a || b {
 LL | |
@@ -53,7 +53,7 @@ LL | |     };
    = note: `(a || b) as i32` or `(a || b).into()` can also be valid options
 
 error: boolean to int conversion using if
-  --> tests/ui/bool_to_int_with_if.rs:38:5
+  --> tests/ui/bool_to_int_with_if.rs:37:5
    |
 LL | /     if cond(a, b) {
 LL | |
@@ -66,7 +66,7 @@ LL | |     };
    = note: `cond(a, b) as i32` or `cond(a, b).into()` can also be valid options
 
 error: boolean to int conversion using if
-  --> tests/ui/bool_to_int_with_if.rs:44:5
+  --> tests/ui/bool_to_int_with_if.rs:43:5
    |
 LL | /     if x + y < 4 {
 LL | |
@@ -79,7 +79,7 @@ LL | |     };
    = note: `(x + y < 4) as i32` or `(x + y < 4).into()` can also be valid options
 
 error: boolean to int conversion using if
-  --> tests/ui/bool_to_int_with_if.rs:54:12
+  --> tests/ui/bool_to_int_with_if.rs:53:12
    |
 LL |       } else if b {
    |  ____________^
@@ -93,7 +93,7 @@ LL | |     };
    = note: `b as i32` or `b.into()` can also be valid options
 
 error: boolean to int conversion using if
-  --> tests/ui/bool_to_int_with_if.rs:64:12
+  --> tests/ui/bool_to_int_with_if.rs:63:12
    |
 LL |       } else if b {
    |  ____________^
@@ -107,7 +107,7 @@ LL | |     };
    = note: `!b as i32` or `(!b).into()` can also be valid options
 
 error: boolean to int conversion using if
-  --> tests/ui/bool_to_int_with_if.rs:130:5
+  --> tests/ui/bool_to_int_with_if.rs:129:5
    |
 LL |     if a { 1 } else { 0 }
    |     ^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `u8::from(a)`
@@ -115,7 +115,7 @@ LL |     if a { 1 } else { 0 }
    = note: `a as u8` or `a.into()` can also be valid options
 
 error: boolean to int conversion using if
-  --> tests/ui/bool_to_int_with_if.rs:174:13
+  --> tests/ui/bool_to_int_with_if.rs:173:13
    |
 LL |     let _ = if dbg!(4 > 0) { 1 } else { 0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `i32::from(dbg!(4 > 0))`
@@ -123,7 +123,7 @@ LL |     let _ = if dbg!(4 > 0) { 1 } else { 0 };
    = note: `dbg!(4 > 0) as i32` or `dbg!(4 > 0).into()` can also be valid options
 
 error: boolean to int conversion using if
-  --> tests/ui/bool_to_int_with_if.rs:177:18
+  --> tests/ui/bool_to_int_with_if.rs:176:18
    |
 LL |     let _ = dbg!(if 4 > 0 { 1 } else { 0 });
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `i32::from(4 > 0)`
diff --git a/tests/ui/comparison_to_empty.fixed b/tests/ui/comparison_to_empty.fixed
index dfbb616838402..7a71829dd62cc 100644
--- a/tests/ui/comparison_to_empty.fixed
+++ b/tests/ui/comparison_to_empty.fixed
@@ -1,6 +1,5 @@
 #![warn(clippy::comparison_to_empty)]
 #![allow(clippy::borrow_deref_ref, clippy::needless_if, clippy::useless_vec)]
-#![feature(let_chains)]
 
 fn main() {
     // Disallow comparisons to empty
diff --git a/tests/ui/comparison_to_empty.rs b/tests/ui/comparison_to_empty.rs
index 61cdb2bbe9f81..5d213a09e8126 100644
--- a/tests/ui/comparison_to_empty.rs
+++ b/tests/ui/comparison_to_empty.rs
@@ -1,6 +1,5 @@
 #![warn(clippy::comparison_to_empty)]
 #![allow(clippy::borrow_deref_ref, clippy::needless_if, clippy::useless_vec)]
-#![feature(let_chains)]
 
 fn main() {
     // Disallow comparisons to empty
diff --git a/tests/ui/comparison_to_empty.stderr b/tests/ui/comparison_to_empty.stderr
index 00a50430a3eea..deb3e93887846 100644
--- a/tests/ui/comparison_to_empty.stderr
+++ b/tests/ui/comparison_to_empty.stderr
@@ -1,5 +1,5 @@
 error: comparison to empty slice
-  --> tests/ui/comparison_to_empty.rs:8:13
+  --> tests/ui/comparison_to_empty.rs:7:13
    |
 LL |     let _ = s == "";
    |             ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
@@ -8,73 +8,73 @@ LL |     let _ = s == "";
    = help: to override `-D warnings` add `#[allow(clippy::comparison_to_empty)]`
 
 error: comparison to empty slice
-  --> tests/ui/comparison_to_empty.rs:10:13
+  --> tests/ui/comparison_to_empty.rs:9:13
    |
 LL |     let _ = s != "";
    |             ^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!s.is_empty()`
 
 error: comparison to empty slice
-  --> tests/ui/comparison_to_empty.rs:14:13
+  --> tests/ui/comparison_to_empty.rs:13:13
    |
 LL |     let _ = v == [];
    |             ^^^^^^^ help: using `is_empty` is clearer and more explicit: `v.is_empty()`
 
 error: comparison to empty slice
-  --> tests/ui/comparison_to_empty.rs:16:13
+  --> tests/ui/comparison_to_empty.rs:15:13
    |
 LL |     let _ = v != [];
    |             ^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!v.is_empty()`
 
 error: comparison to empty slice using `if let`
-  --> tests/ui/comparison_to_empty.rs:18:8
+  --> tests/ui/comparison_to_empty.rs:17:8
    |
 LL |     if let [] = &*v {}
    |        ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(*v).is_empty()`
 
 error: comparison to empty slice using `if let`
-  --> tests/ui/comparison_to_empty.rs:21:8
+  --> tests/ui/comparison_to_empty.rs:20:8
    |
 LL |     if let [] = s {}
    |        ^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
 
 error: comparison to empty slice using `if let`
-  --> tests/ui/comparison_to_empty.rs:23:8
+  --> tests/ui/comparison_to_empty.rs:22:8
    |
 LL |     if let [] = &*s {}
    |        ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
 
 error: comparison to empty slice using `if let`
-  --> tests/ui/comparison_to_empty.rs:25:8
+  --> tests/ui/comparison_to_empty.rs:24:8
    |
 LL |     if let [] = &*s
    |        ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
 
 error: comparison to empty slice
-  --> tests/ui/comparison_to_empty.rs:27:12
+  --> tests/ui/comparison_to_empty.rs:26:12
    |
 LL |         && s == []
    |            ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
 
 error: comparison to empty slice
-  --> tests/ui/comparison_to_empty.rs:48:13
+  --> tests/ui/comparison_to_empty.rs:47:13
    |
 LL |     let _ = s.eq("");
    |             ^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
 
 error: comparison to empty slice
-  --> tests/ui/comparison_to_empty.rs:50:13
+  --> tests/ui/comparison_to_empty.rs:49:13
    |
 LL |     let _ = s.ne("");
    |             ^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!s.is_empty()`
 
 error: comparison to empty slice
-  --> tests/ui/comparison_to_empty.rs:53:13
+  --> tests/ui/comparison_to_empty.rs:52:13
    |
 LL |     let _ = v.eq(&[]);
    |             ^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `v.is_empty()`
 
 error: comparison to empty slice
-  --> tests/ui/comparison_to_empty.rs:55:13
+  --> tests/ui/comparison_to_empty.rs:54:13
    |
 LL |     let _ = v.ne(&[]);
    |             ^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!v.is_empty()`
diff --git a/tests/ui/needless_if.fixed b/tests/ui/needless_if.fixed
index 347dbff7c595c..c839156bed9bd 100644
--- a/tests/ui/needless_if.fixed
+++ b/tests/ui/needless_if.fixed
@@ -1,5 +1,4 @@
 //@aux-build:proc_macros.rs
-#![feature(let_chains)]
 #![allow(
     clippy::blocks_in_conditions,
     clippy::if_same_then_else,
diff --git a/tests/ui/needless_if.rs b/tests/ui/needless_if.rs
index 5e0f2a14408bc..11103af5c5598 100644
--- a/tests/ui/needless_if.rs
+++ b/tests/ui/needless_if.rs
@@ -1,5 +1,4 @@
 //@aux-build:proc_macros.rs
-#![feature(let_chains)]
 #![allow(
     clippy::blocks_in_conditions,
     clippy::if_same_then_else,
diff --git a/tests/ui/needless_if.stderr b/tests/ui/needless_if.stderr
index 62cdf2459448d..4b56843bd5229 100644
--- a/tests/ui/needless_if.stderr
+++ b/tests/ui/needless_if.stderr
@@ -1,5 +1,5 @@
 error: this `if` branch is empty
-  --> tests/ui/needless_if.rs:27:5
+  --> tests/ui/needless_if.rs:26:5
    |
 LL |     if (true) {}
    |     ^^^^^^^^^^^^ help: you can remove it
@@ -8,13 +8,13 @@ LL |     if (true) {}
    = help: to override `-D warnings` add `#[allow(clippy::needless_if)]`
 
 error: this `if` branch is empty
-  --> tests/ui/needless_if.rs:30:5
+  --> tests/ui/needless_if.rs:29:5
    |
 LL |     if maybe_side_effect() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `maybe_side_effect();`
 
 error: this `if` branch is empty
-  --> tests/ui/needless_if.rs:36:5
+  --> tests/ui/needless_if.rs:35:5
    |
 LL | /     if {
 LL | |
@@ -31,7 +31,7 @@ LL +     });
    |
 
 error: this `if` branch is empty
-  --> tests/ui/needless_if.rs:51:5
+  --> tests/ui/needless_if.rs:50:5
    |
 LL | /     if {
 LL | |
@@ -57,19 +57,19 @@ LL +     } && true);
    |
 
 error: this `if` branch is empty
-  --> tests/ui/needless_if.rs:96:5
+  --> tests/ui/needless_if.rs:95:5
    |
 LL |     if { maybe_side_effect() } {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() });`
 
 error: this `if` branch is empty
-  --> tests/ui/needless_if.rs:99:5
+  --> tests/ui/needless_if.rs:98:5
    |
 LL |     if { maybe_side_effect() } && true {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() } && true);`
 
 error: this `if` branch is empty
-  --> tests/ui/needless_if.rs:104:5
+  --> tests/ui/needless_if.rs:103:5
    |
 LL |     if true {}
    |     ^^^^^^^^^^ help: you can remove it: `true;`
diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed
index 33a5308bd3574..dc9d6491691f3 100644
--- a/tests/ui/redundant_pattern_matching_option.fixed
+++ b/tests/ui/redundant_pattern_matching_option.fixed
@@ -1,4 +1,4 @@
-#![feature(let_chains, if_let_guard)]
+#![feature(if_let_guard)]
 #![warn(clippy::redundant_pattern_matching)]
 #![allow(
     clippy::needless_bool,
diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs
index 60bce2994ea3a..2e9714ad8e75f 100644
--- a/tests/ui/redundant_pattern_matching_option.rs
+++ b/tests/ui/redundant_pattern_matching_option.rs
@@ -1,4 +1,4 @@
-#![feature(let_chains, if_let_guard)]
+#![feature(if_let_guard)]
 #![warn(clippy::redundant_pattern_matching)]
 #![allow(
     clippy::needless_bool,

From 1d9d30f35ab715f1b9fcf0f7ee6ce8d61216b253 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= 
Date: Tue, 22 Apr 2025 18:53:23 +0200
Subject: [PATCH 2009/4206] Consistently use the DiagCtxtHandle of HirTyLowerer
 instead of the one of TyCtxt

They are not the same.
---
 .../src/hir_ty_lowering/bounds.rs              | 18 ++++++++----------
 .../src/hir_ty_lowering/cmse.rs                |  2 +-
 .../src/hir_ty_lowering/dyn_compatibility.rs   |  2 +-
 .../src/hir_ty_lowering/lint.rs                |  2 +-
 .../src/hir_ty_lowering/mod.rs                 |  8 ++++----
 5 files changed, 15 insertions(+), 17 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index bf91eb1b8fdac..f412ac34834d0 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -309,7 +309,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     false => "`?Sized`",
                 };
                 // There was a `?Trait` bound, but it was neither `?Sized` nor `experimental_default_bounds`.
-                tcx.dcx().span_err(
+                self.dcx().span_err(
                     unbound.span,
                     format!(
                         "relaxing a default bound only does something for {}; \
@@ -810,15 +810,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         // `resolve_bound_vars`, since we'd need to introduce those as elided
         // bound vars on the where clause too.
         if bound.has_bound_vars() {
-            return Err(self.tcx().dcx().emit_err(
-                errors::AssociatedItemTraitUninferredGenericParams {
-                    span,
-                    inferred_sugg: Some(span.with_hi(item_segment.ident.span.lo())),
-                    bound: format!("{}::", tcx.anonymize_bound_vars(bound).skip_binder(),),
-                    mpart_sugg: None,
-                    what: "function",
-                },
-            ));
+            return Err(self.dcx().emit_err(errors::AssociatedItemTraitUninferredGenericParams {
+                span,
+                inferred_sugg: Some(span.with_hi(item_segment.ident.span.lo())),
+                bound: format!("{}::", tcx.anonymize_bound_vars(bound).skip_binder(),),
+                mpart_sugg: None,
+                what: "function",
+            }));
         }
 
         let trait_def_id = bound.def_id();
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
index d1ee5a5494c00..ebeb3b58208eb 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
@@ -35,7 +35,7 @@ pub(crate) fn validate_cmse_abi<'tcx>(
                     _ => tcx.hir_span(hir_id),
                 };
                 struct_span_code_err!(
-                    tcx.dcx(),
+                    dcx,
                     span,
                     E0781,
                     "the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers"
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index 88f745892048c..3af439eb2fd52 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -132,7 +132,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     if references_self {
                         // With trait alias and type alias combined, type resolver
                         // may not be able to catch all illegal `Self` usages (issue 139082)
-                        let guar = tcx.dcx().emit_err(SelfInTypeAlias { span });
+                        let guar = self.dcx().emit_err(SelfInTypeAlias { span });
                         b.term = replace_dummy_self_with_error(tcx, b.term, guar);
                     }
                 }
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
index 483b61add3380..1f4692b19f1ad 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
@@ -103,7 +103,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             // In case there is an associated type with the same name
             // Add the suggestion to this error
             if let Some(mut sugg) =
-                tcx.dcx().steal_non_err(self_ty.span, StashKey::AssociatedTypeSuggestion)
+                self.dcx().steal_non_err(self_ty.span, StashKey::AssociatedTypeSuggestion)
                 && let Suggestions::Enabled(ref mut s1) = diag.suggestions
                 && let Suggestions::Enabled(ref mut s2) = sugg.suggestions
             {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 5e79e93201531..4163a2028e40a 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -1202,7 +1202,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         )? {
             LoweredAssoc::Term(def_id, args) => {
                 if !tcx.associated_item(def_id).is_type_const_capable(tcx) {
-                    let mut err = tcx.dcx().struct_span_err(
+                    let mut err = self.dcx().struct_span_err(
                         span,
                         "use of trait associated const without `#[type_const]`",
                     );
@@ -2323,7 +2323,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             if tcx.features().generic_const_parameter_types()
                 && (anon_const_type.has_free_regions() || anon_const_type.has_erased_regions())
             {
-                let e = tcx.dcx().span_err(
+                let e = self.dcx().span_err(
                     const_arg.span(),
                     "anonymous constants with lifetimes in their type are not yet supported",
                 );
@@ -2334,7 +2334,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             // use this type to feed the `type_of` and query results must not contain inference
             // variables otherwise we will ICE.
             if anon_const_type.has_non_region_infer() {
-                let e = tcx.dcx().span_err(
+                let e = self.dcx().span_err(
                     const_arg.span(),
                     "anonymous constants with inferred types are not yet supported",
                 );
@@ -2344,7 +2344,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             // We error when the type contains unsubstituted generics since we do not currently
             // give the anon const any of the generics from the parent.
             if anon_const_type.has_non_region_param() {
-                let e = tcx.dcx().span_err(
+                let e = self.dcx().span_err(
                     const_arg.span(),
                     "anonymous constants referencing generics are not yet supported",
                 );

From 5fdc0de28c0c843dd9a3d107484d044f9c08b969 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= 
Date: Tue, 22 Apr 2025 19:17:28 +0200
Subject: [PATCH 2010/4206] Eliminate unnecessary parameter

---
 compiler/rustc_hir_analysis/messages.ftl           |  2 +-
 compiler/rustc_hir_analysis/src/collect.rs         |  4 +---
 .../src/hir_ty_lowering/bounds.rs                  | 14 +++++++-------
 .../rustc_hir_analysis/src/hir_ty_lowering/mod.rs  | 10 ++--------
 compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs       |  3 +--
 5 files changed, 12 insertions(+), 21 deletions(-)

diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 277bb7bd3e15c..1138e9774d510 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -37,7 +37,7 @@ hir_analysis_assoc_kind_mismatch = expected {$expected}, found {$got}
 
 hir_analysis_assoc_kind_mismatch_wrap_in_braces_sugg = consider adding braces here
 
-hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the associated {$what} of a trait with uninferred generic parameters
+hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the {$what} of a trait with uninferred generic parameters
     .suggestion = use a fully qualified path with inferred lifetimes
 
 hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion = use a fully qualified path with explicit lifetimes
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 4520fbe352cea..14fd265baa6b0 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -44,7 +44,6 @@ use rustc_trait_selection::traits::ObligationCtxt;
 use tracing::{debug, instrument};
 
 use crate::errors;
-use crate::hir_ty_lowering::errors::assoc_tag_str;
 use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason};
 
 pub(crate) mod dump;
@@ -450,7 +449,6 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
         item_def_id: DefId,
         item_segment: &rustc_hir::PathSegment<'tcx>,
         poly_trait_ref: ty::PolyTraitRef<'tcx>,
-        assoc_tag: ty::AssocTag,
     ) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
         if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
             let item_args = self.lowerer().lower_generic_args_of_assoc_item(
@@ -525,7 +523,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
                 inferred_sugg,
                 bound,
                 mpart_sugg,
-                what: assoc_tag_str(assoc_tag),
+                what: self.tcx.def_descr(item_def_id),
             }))
         }
     }
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index f412ac34834d0..800bf5e1b3022 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -803,6 +803,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
         };
 
+        let trait_def_id = bound.def_id();
+        let assoc_fn = self
+            .probe_assoc_item(assoc_ident, ty::AssocTag::Fn, qpath_hir_id, span, trait_def_id)
+            .expect("failed to find associated fn");
+
         // Don't let `T::method` resolve to some `for<'a> >::method`,
         // which may happen via a higher-ranked where clause or supertrait.
         // This is the same restrictions as associated types; even though we could
@@ -815,16 +820,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 inferred_sugg: Some(span.with_hi(item_segment.ident.span.lo())),
                 bound: format!("{}::", tcx.anonymize_bound_vars(bound).skip_binder(),),
                 mpart_sugg: None,
-                what: "function",
+                what: assoc_fn.descr(),
             }));
         }
 
-        let trait_def_id = bound.def_id();
-        let assoc_ty = self
-            .probe_assoc_item(assoc_ident, ty::AssocTag::Fn, qpath_hir_id, span, trait_def_id)
-            .expect("failed to find associated type");
-
-        Ok((bound, assoc_ty.def_id))
+        Ok((bound, assoc_fn.def_id))
     }
 
     /// Do the common parts of lowering an RTN type. This involves extending the
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 4163a2028e40a..533499ed3447a 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -168,7 +168,6 @@ pub trait HirTyLowerer<'tcx> {
         item_def_id: DefId,
         item_segment: &hir::PathSegment<'tcx>,
         poly_trait_ref: ty::PolyTraitRef<'tcx>,
-        assoc_tag: ty::AssocTag,
     ) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed>;
 
     fn lower_fn_sig(
@@ -1433,13 +1432,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let assoc_item = self
             .probe_assoc_item(assoc_ident, mode.assoc_tag(), hir_ref_id, span, trait_did)
             .expect("failed to find associated item");
-        let (def_id, args) = self.lower_assoc_shared(
-            span,
-            assoc_item.def_id,
-            assoc_segment,
-            bound,
-            mode.assoc_tag(),
-        )?;
+        let (def_id, args) =
+            self.lower_assoc_shared(span, assoc_item.def_id, assoc_segment, bound)?;
         let result = LoweredAssoc::Term(def_id, args);
 
         if let Some(variant_def_id) = variant_resolution {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index de189b301092c..fb557555237e5 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -314,11 +314,10 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
         item_def_id: DefId,
         item_segment: &rustc_hir::PathSegment<'tcx>,
         poly_trait_ref: ty::PolyTraitRef<'tcx>,
-        _assoc_tag: ty::AssocTag,
     ) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
         let trait_ref = self.instantiate_binder_with_fresh_vars(
             span,
-            // FIXME(mgca): this should be assoc const if that is the `kind`
+            // FIXME(mgca): `item_def_id` can be an AssocConst; rename this variant.
             infer::BoundRegionConversionTime::AssocTypeProjection(item_def_id),
             poly_trait_ref,
         );

From 3fd047d164c09cc3c0d5a8c6833e6021c5f5934e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= 
Date: Wed, 23 Apr 2025 15:58:20 +0200
Subject: [PATCH 2011/4206] Name methods pertaining to HIR ty lowering of paths
 more appropriately

---
 compiler/rustc_hir_analysis/src/collect.rs    |   2 +-
 .../src/hir_ty_lowering/bounds.rs             |   2 +-
 .../src/hir_ty_lowering/mod.rs                | 280 +++++++++---------
 .../rustc_hir_typeck/src/fn_ctxt/checks.rs    |  17 +-
 compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs  |   2 +-
 5 files changed, 162 insertions(+), 141 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 14fd265baa6b0..350bdc7821d5b 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -443,7 +443,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
         self.tcx.at(span).type_param_predicates((self.item_def_id, def_id, assoc_ident))
     }
 
-    fn lower_assoc_shared(
+    fn lower_assoc_item_path(
         &self,
         span: Span,
         item_def_id: DefId,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index 800bf5e1b3022..9544f9b0c2bd1 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -737,7 +737,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     }
 
     /// Perform type-dependent lookup for a *method* for return type notation.
-    /// This generally mirrors `::lower_assoc_path`.
+    /// This generally mirrors `::lower_type_relative_path`.
     fn resolve_type_relative_return_type_notation(
         &self,
         qself: &'tcx hir::Ty<'tcx>,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 533499ed3447a..5b587bb99ee4d 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -150,7 +150,7 @@ pub trait HirTyLowerer<'tcx> {
         assoc_ident: Ident,
     ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]>;
 
-    /// Lower an associated type/const (from a trait) to a projection.
+    /// Lower a path to an associated item (of a trait) to a projection.
     ///
     /// This method has to be defined by the concrete lowering context because
     /// dealing with higher-ranked trait references depends on its capabilities:
@@ -162,7 +162,7 @@ pub trait HirTyLowerer<'tcx> {
     ///
     /// The canonical example of this is associated type `T::P` where `T` is a type
     /// param constrained by `T: for<'a> Trait<'a>` and where `Trait` defines `P`.
-    fn lower_assoc_shared(
+    fn lower_assoc_item_path(
         &self,
         span: Span,
         item_def_id: DefId,
@@ -244,39 +244,39 @@ pub enum FeedConstTy<'a, 'tcx> {
 }
 
 #[derive(Debug, Clone, Copy)]
-enum LowerAssocMode {
+enum LowerTypeRelativePathMode {
     Type { permit_variants: bool },
     Const,
 }
 
-impl LowerAssocMode {
+impl LowerTypeRelativePathMode {
     fn assoc_tag(self) -> ty::AssocTag {
         match self {
-            LowerAssocMode::Type { .. } => ty::AssocTag::Type,
-            LowerAssocMode::Const => ty::AssocTag::Const,
+            Self::Type { .. } => ty::AssocTag::Type,
+            Self::Const => ty::AssocTag::Const,
         }
     }
 
     fn def_kind(self) -> DefKind {
         match self {
-            LowerAssocMode::Type { .. } => DefKind::AssocTy,
-            LowerAssocMode::Const => DefKind::AssocConst,
+            Self::Type { .. } => DefKind::AssocTy,
+            Self::Const => DefKind::AssocConst,
         }
     }
 
     fn permit_variants(self) -> bool {
         match self {
-            LowerAssocMode::Type { permit_variants } => permit_variants,
+            Self::Type { permit_variants } => permit_variants,
             // FIXME(mgca): Support paths like `Option::::None` or `Option::::Some` which
             // resolve to const ctors/fn items respectively.
-            LowerAssocMode::Const => false,
+            Self::Const => false,
         }
     }
 }
 
 #[derive(Debug, Clone, Copy)]
-enum LoweredAssoc<'tcx> {
-    Term(DefId, GenericArgsRef<'tcx>),
+enum TypeRelativePath<'tcx> {
+    AssocItem(DefId, GenericArgsRef<'tcx>),
     Variant { adt: Ty<'tcx>, variant_did: DefId },
 }
 
@@ -1126,7 +1126,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         Ok(bound)
     }
 
-    /// Lower a [type-relative] path referring to an associated type or to an enum variant.
+    /// Lower a [type-relative](hir::QPath::TypeRelative) path in type position to a type.
     ///
     /// If the path refers to an enum variant and `permit_variants` holds,
     /// the returned type is simply the provided self type `qself_ty`.
@@ -1147,59 +1147,61 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// described in the previous paragraph and their modeling of projections would likely be
     /// very similar in nature.
     ///
-    /// [type-relative]: hir::QPath::TypeRelative
     /// [#22519]: https://github.com/rust-lang/rust/issues/22519
     /// [iat]: https://github.com/rust-lang/rust/issues/8995#issuecomment-1569208403
     //
     // NOTE: When this function starts resolving `Trait::AssocTy` successfully
     // it should also start reporting the `BARE_TRAIT_OBJECTS` lint.
     #[instrument(level = "debug", skip_all, ret)]
-    pub fn lower_assoc_path_ty(
+    pub fn lower_type_relative_ty_path(
         &self,
-        hir_ref_id: HirId,
+        self_ty: Ty<'tcx>,
+        hir_self_ty: &'tcx hir::Ty<'tcx>,
+        segment: &'tcx hir::PathSegment<'tcx>,
+        qpath_hir_id: HirId,
         span: Span,
-        qself_ty: Ty<'tcx>,
-        qself: &'tcx hir::Ty<'tcx>,
-        assoc_segment: &'tcx hir::PathSegment<'tcx>,
         permit_variants: bool,
     ) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
         let tcx = self.tcx();
-        match self.lower_assoc_path_shared(
-            hir_ref_id,
+        match self.lower_type_relative_path(
+            self_ty,
+            hir_self_ty,
+            segment,
+            qpath_hir_id,
             span,
-            qself_ty,
-            qself,
-            assoc_segment,
-            LowerAssocMode::Type { permit_variants },
+            LowerTypeRelativePathMode::Type { permit_variants },
         )? {
-            LoweredAssoc::Term(def_id, args) => {
+            TypeRelativePath::AssocItem(def_id, args) => {
                 let alias_ty = ty::AliasTy::new_from_args(tcx, def_id, args);
                 let ty = Ty::new_alias(tcx, alias_ty.kind(tcx), alias_ty);
                 Ok((ty, tcx.def_kind(def_id), def_id))
             }
-            LoweredAssoc::Variant { adt, variant_did } => Ok((adt, DefKind::Variant, variant_did)),
+            TypeRelativePath::Variant { adt, variant_did } => {
+                Ok((adt, DefKind::Variant, variant_did))
+            }
         }
     }
 
+    /// Lower a [type-relative][hir::QPath::TypeRelative] path to a (type-level) constant.
     #[instrument(level = "debug", skip_all, ret)]
-    fn lower_assoc_path_const(
+    fn lower_type_relative_const_path(
         &self,
-        hir_ref_id: HirId,
+        self_ty: Ty<'tcx>,
+        hir_self_ty: &'tcx hir::Ty<'tcx>,
+        segment: &'tcx hir::PathSegment<'tcx>,
+        qpath_hir_id: HirId,
         span: Span,
-        qself_ty: Ty<'tcx>,
-        qself: &'tcx hir::Ty<'tcx>,
-        assoc_segment: &'tcx hir::PathSegment<'tcx>,
     ) -> Result, ErrorGuaranteed> {
         let tcx = self.tcx();
-        let (def_id, args) = match self.lower_assoc_path_shared(
-            hir_ref_id,
+        let (def_id, args) = match self.lower_type_relative_path(
+            self_ty,
+            hir_self_ty,
+            segment,
+            qpath_hir_id,
             span,
-            qself_ty,
-            qself,
-            assoc_segment,
-            LowerAssocMode::Const,
+            LowerTypeRelativePathMode::Const,
         )? {
-            LoweredAssoc::Term(def_id, args) => {
+            TypeRelativePath::AssocItem(def_id, args) => {
                 if !tcx.associated_item(def_id).is_type_const_capable(tcx) {
                     let mut err = self.dcx().struct_span_err(
                         span,
@@ -1212,75 +1214,78 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
             // FIXME(mgca): implement support for this once ready to support all adt ctor expressions,
             // not just const ctors
-            LoweredAssoc::Variant { .. } => {
+            TypeRelativePath::Variant { .. } => {
                 span_bug!(span, "unexpected variant res for type associated const path")
             }
         };
         Ok(Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(def_id, args)))
     }
 
+    /// Lower a [type-relative][hir::QPath::TypeRelative] (and type-level) path.
     #[instrument(level = "debug", skip_all, ret)]
-    fn lower_assoc_path_shared(
+    fn lower_type_relative_path(
         &self,
-        hir_ref_id: HirId,
+        self_ty: Ty<'tcx>,
+        hir_self_ty: &'tcx hir::Ty<'tcx>,
+        segment: &'tcx hir::PathSegment<'tcx>,
+        qpath_hir_id: HirId,
         span: Span,
-        qself_ty: Ty<'tcx>,
-        qself: &'tcx hir::Ty<'tcx>,
-        assoc_segment: &'tcx hir::PathSegment<'tcx>,
-        mode: LowerAssocMode,
-    ) -> Result, ErrorGuaranteed> {
-        debug!(%qself_ty, ?assoc_segment.ident);
+        mode: LowerTypeRelativePathMode,
+    ) -> Result, ErrorGuaranteed> {
+        debug!(%self_ty, ?segment.ident);
         let tcx = self.tcx();
-
-        let assoc_ident = assoc_segment.ident;
+        let ident = segment.ident;
 
         // Check if we have an enum variant or an inherent associated type.
-        let mut variant_resolution = None;
-        if let Some(adt_def) = self.probe_adt(span, qself_ty) {
+        let mut variant_def_id = None;
+        if let Some(adt_def) = self.probe_adt(span, self_ty) {
             if adt_def.is_enum() {
                 let variant_def = adt_def
                     .variants()
                     .iter()
-                    .find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident(tcx), adt_def.did()));
+                    .find(|vd| tcx.hygienic_eq(ident, vd.ident(tcx), adt_def.did()));
                 if let Some(variant_def) = variant_def {
                     if mode.permit_variants() {
-                        tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
+                        tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None);
                         let _ = self.prohibit_generic_args(
-                            slice::from_ref(assoc_segment).iter(),
-                            GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def },
+                            slice::from_ref(segment).iter(),
+                            GenericsArgsErrExtend::EnumVariant {
+                                qself: hir_self_ty,
+                                assoc_segment: segment,
+                                adt_def,
+                            },
                         );
-                        return Ok(LoweredAssoc::Variant {
-                            adt: qself_ty,
+                        return Ok(TypeRelativePath::Variant {
+                            adt: self_ty,
                             variant_did: variant_def.def_id,
                         });
                     } else {
-                        variant_resolution = Some(variant_def.def_id);
+                        variant_def_id = Some(variant_def.def_id);
                     }
                 }
             }
 
             // FIXME(inherent_associated_types, #106719): Support self types other than ADTs.
-            if let Some((did, args)) = self.probe_inherent_assoc_shared(
-                assoc_segment,
+            if let Some((did, args)) = self.probe_inherent_assoc_item(
+                segment,
                 adt_def.did(),
-                qself_ty,
-                hir_ref_id,
+                self_ty,
+                qpath_hir_id,
                 span,
                 mode.assoc_tag(),
             )? {
-                return Ok(LoweredAssoc::Term(did, args));
+                return Ok(TypeRelativePath::AssocItem(did, args));
             }
         }
 
-        let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
-            path.res
-        } else {
-            Res::Err
+        let self_ty_res = match hir_self_ty.kind {
+            hir::TyKind::Path(hir::QPath::Resolved(_, path)) => path.res,
+            _ => Res::Err,
         };
 
         // Find the type of the associated item, and the trait where the associated
         // item is declared.
-        let bound = match (qself_ty.kind(), qself_res) {
+        let bound = match (self_ty.kind(), self_ty_res) {
             (_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => {
                 // `Self` in an impl of a trait -- we have a concrete self type and a
                 // trait reference.
@@ -1298,7 +1303,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     },
                     AssocItemQSelf::SelfTyAlias,
                     mode.assoc_tag(),
-                    assoc_ident,
+                    ident,
                     span,
                     None,
                 )?
@@ -1308,48 +1313,48 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did),
             ) => self.probe_single_ty_param_bound_for_assoc_item(
                 param_did.expect_local(),
-                qself.span,
+                hir_self_ty.span,
                 mode.assoc_tag(),
-                assoc_ident,
+                ident,
                 span,
             )?,
             _ => {
                 let kind_str = assoc_tag_str(mode.assoc_tag());
-                let reported = if variant_resolution.is_some() {
+                let reported = if variant_def_id.is_some() {
                     // Variant in type position
-                    let msg = format!("expected {kind_str}, found variant `{assoc_ident}`");
+                    let msg = format!("expected {kind_str}, found variant `{ident}`");
                     self.dcx().span_err(span, msg)
-                } else if qself_ty.is_enum() {
+                } else if self_ty.is_enum() {
                     let mut err = self.dcx().create_err(NoVariantNamed {
-                        span: assoc_ident.span,
-                        ident: assoc_ident,
-                        ty: qself_ty,
+                        span: ident.span,
+                        ident,
+                        ty: self_ty,
                     });
 
-                    let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT");
+                    let adt_def = self_ty.ty_adt_def().expect("enum is not an ADT");
                     if let Some(variant_name) = find_best_match_for_name(
                         &adt_def
                             .variants()
                             .iter()
                             .map(|variant| variant.name)
                             .collect::>(),
-                        assoc_ident.name,
+                        ident.name,
                         None,
                     ) && let Some(variant) =
                         adt_def.variants().iter().find(|s| s.name == variant_name)
                     {
-                        let mut suggestion = vec![(assoc_ident.span, variant_name.to_string())];
+                        let mut suggestion = vec![(ident.span, variant_name.to_string())];
                         if let hir::Node::Stmt(&hir::Stmt {
                             kind: hir::StmtKind::Semi(expr), ..
                         })
-                        | hir::Node::Expr(expr) = tcx.parent_hir_node(hir_ref_id)
+                        | hir::Node::Expr(expr) = tcx.parent_hir_node(qpath_hir_id)
                             && let hir::ExprKind::Struct(..) = expr.kind
                         {
                             match variant.ctor {
                                 None => {
                                     // struct
                                     suggestion = vec![(
-                                        assoc_ident.span.with_hi(expr.span.hi()),
+                                        ident.span.with_hi(expr.span.hi()),
                                         if variant.fields.is_empty() {
                                             format!("{variant_name} {{}}")
                                         } else {
@@ -1370,7 +1375,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                                     let fn_sig = tcx.fn_sig(def_id).instantiate_identity();
                                     let inputs = fn_sig.inputs().skip_binder();
                                     suggestion = vec![(
-                                        assoc_ident.span.with_hi(expr.span.hi()),
+                                        ident.span.with_hi(expr.span.hi()),
                                         format!(
                                             "{variant_name}({})",
                                             inputs
@@ -1384,7 +1389,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                                 Some((hir::def::CtorKind::Const, _)) => {
                                     // unit
                                     suggestion = vec![(
-                                        assoc_ident.span.with_hi(expr.span.hi()),
+                                        ident.span.with_hi(expr.span.hi()),
                                         variant_name.to_string(),
                                     )];
                                 }
@@ -1396,31 +1401,27 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                             Applicability::HasPlaceholders,
                         );
                     } else {
-                        err.span_label(
-                            assoc_ident.span,
-                            format!("variant not found in `{qself_ty}`"),
-                        );
+                        err.span_label(ident.span, format!("variant not found in `{self_ty}`"));
                     }
 
                     if let Some(sp) = tcx.hir_span_if_local(adt_def.did()) {
-                        err.span_label(sp, format!("variant `{assoc_ident}` not found here"));
+                        err.span_label(sp, format!("variant `{ident}` not found here"));
                     }
 
                     err.emit()
-                } else if let Err(reported) = qself_ty.error_reported() {
+                } else if let Err(reported) = self_ty.error_reported() {
                     reported
                 } else {
-                    self.maybe_report_similar_assoc_fn(span, qself_ty, qself)?;
+                    self.maybe_report_similar_assoc_fn(span, self_ty, hir_self_ty)?;
 
-                    let traits: Vec<_> =
-                        self.probe_traits_that_match_assoc_ty(qself_ty, assoc_ident);
+                    let traits: Vec<_> = self.probe_traits_that_match_assoc_ty(self_ty, ident);
 
                     // Don't print `ty::Error` to the user.
                     self.report_ambiguous_assoc(
                         span,
-                        &[qself_ty.to_string()],
+                        &[self_ty.to_string()],
                         &traits,
-                        assoc_ident.name,
+                        ident.name,
                         mode.assoc_tag(),
                     )
                 };
@@ -1428,21 +1429,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
         };
 
-        let trait_did = bound.def_id();
+        let trait_def_id = bound.def_id();
         let assoc_item = self
-            .probe_assoc_item(assoc_ident, mode.assoc_tag(), hir_ref_id, span, trait_did)
+            .probe_assoc_item(ident, mode.assoc_tag(), qpath_hir_id, span, trait_def_id)
             .expect("failed to find associated item");
-        let (def_id, args) =
-            self.lower_assoc_shared(span, assoc_item.def_id, assoc_segment, bound)?;
-        let result = LoweredAssoc::Term(def_id, args);
+        let (def_id, args) = self.lower_assoc_item_path(span, assoc_item.def_id, segment, bound)?;
+        let result = TypeRelativePath::AssocItem(def_id, args);
 
-        if let Some(variant_def_id) = variant_resolution {
-            tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| {
+        if let Some(variant_def_id) = variant_def_id {
+            tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, qpath_hir_id, span, |lint| {
                 lint.primary_message("ambiguous associated item");
                 let mut could_refer_to = |kind: DefKind, def_id, also| {
                     let note_msg = format!(
                         "`{}` could{} refer to the {} defined here",
-                        assoc_ident,
+                        ident,
                         also,
                         tcx.def_kind_descr(kind, def_id)
                     );
@@ -1455,7 +1455,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 lint.span_suggestion(
                     span,
                     "use fully-qualified syntax",
-                    format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident),
+                    format!("<{} as {}>::{}", self_ty, tcx.item_name(trait_def_id), ident),
                     Applicability::MachineApplicable,
                 );
             });
@@ -1463,7 +1463,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         Ok(result)
     }
 
-    fn probe_inherent_assoc_shared(
+    /// Search for inherent associated items for use at the type level.
+    fn probe_inherent_assoc_item(
         &self,
         segment: &hir::PathSegment<'tcx>,
         adt_did: DefId,
@@ -1757,9 +1758,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             .collect()
     }
 
-    /// Lower a qualified path to a type.
+    /// Lower a [resolved][hir::QPath::Resolved] associated type path to a projection.
     #[instrument(level = "debug", skip_all)]
-    fn lower_qpath_ty(
+    fn lower_resolved_assoc_ty_path(
         &self,
         span: Span,
         opt_self_ty: Option>,
@@ -1767,7 +1768,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         trait_segment: Option<&hir::PathSegment<'tcx>>,
         item_segment: &hir::PathSegment<'tcx>,
     ) -> Ty<'tcx> {
-        match self.lower_qpath_shared(
+        match self.lower_resolved_assoc_item_path(
             span,
             opt_self_ty,
             item_def_id,
@@ -1782,9 +1783,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
     }
 
-    /// Lower a qualified path to a const.
+    /// Lower a [resolved][hir::QPath::Resolved] associated const path to a (type-level) constant.
     #[instrument(level = "debug", skip_all)]
-    fn lower_qpath_const(
+    fn lower_resolved_assoc_const_path(
         &self,
         span: Span,
         opt_self_ty: Option>,
@@ -1792,7 +1793,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         trait_segment: Option<&hir::PathSegment<'tcx>>,
         item_segment: &hir::PathSegment<'tcx>,
     ) -> Const<'tcx> {
-        match self.lower_qpath_shared(
+        match self.lower_resolved_assoc_item_path(
             span,
             opt_self_ty,
             item_def_id,
@@ -1808,8 +1809,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
     }
 
+    /// Lower a [resolved][hir::QPath::Resolved] (type-level) associated item path.
     #[instrument(level = "debug", skip_all)]
-    fn lower_qpath_shared(
+    fn lower_resolved_assoc_item_path(
         &self,
         span: Span,
         opt_self_ty: Option>,
@@ -2063,9 +2065,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         generic_segments
     }
 
-    /// Lower a type `Path` to a type.
+    /// Lower a [resolved][hir::QPath::Resolved] path to a type.
     #[instrument(level = "debug", skip_all)]
-    pub fn lower_path(
+    pub fn lower_resolved_ty_path(
         &self,
         opt_self_ty: Option>,
         path: &hir::Path<'tcx>,
@@ -2196,7 +2198,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 } else {
                     None
                 };
-                self.lower_qpath_ty(
+                self.lower_resolved_assoc_ty_path(
                     span,
                     opt_self_ty,
                     def_id,
@@ -2292,7 +2294,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
     }
 
-    /// Convert a [`hir::ConstArg`] to a [`ty::Const`](Const).
+    /// Lower a [`hir::ConstArg`] to a (type-level) [`ty::Const`](Const).
     #[instrument(skip(self), level = "debug")]
     pub fn lower_const_arg(
         &self,
@@ -2357,13 +2359,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             hir::ConstArgKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
                 debug!(?maybe_qself, ?path);
                 let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
-                self.lower_const_path_resolved(opt_self_ty, path, hir_id)
+                self.lower_resolved_const_path(opt_self_ty, path, hir_id)
             }
-            hir::ConstArgKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
-                debug!(?qself, ?segment);
-                let ty = self.lower_ty(qself);
-                self.lower_assoc_path_const(hir_id, const_arg.span(), ty, qself, segment)
-                    .unwrap_or_else(|guar| Const::new_error(tcx, guar))
+            hir::ConstArgKind::Path(hir::QPath::TypeRelative(hir_self_ty, segment)) => {
+                debug!(?hir_self_ty, ?segment);
+                let self_ty = self.lower_ty(hir_self_ty);
+                self.lower_type_relative_const_path(
+                    self_ty,
+                    hir_self_ty,
+                    segment,
+                    hir_id,
+                    const_arg.span(),
+                )
+                .unwrap_or_else(|guar| Const::new_error(tcx, guar))
             }
             hir::ConstArgKind::Path(qpath @ hir::QPath::LangItem(..)) => {
                 ty::Const::new_error_with_message(
@@ -2377,7 +2385,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
     }
 
-    fn lower_const_path_resolved(
+    /// Lower a [resolved][hir::QPath::Resolved] path to a (type-level) constant.
+    fn lower_resolved_const_path(
         &self,
         opt_self_ty: Option>,
         path: &hir::Path<'tcx>,
@@ -2414,7 +2423,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 } else {
                     None
                 };
-                self.lower_qpath_const(
+                self.lower_resolved_assoc_const_path(
                     span,
                     opt_self_ty,
                     did,
@@ -2624,7 +2633,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
                 debug!(?maybe_qself, ?path);
                 let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
-                self.lower_path(opt_self_ty, path, hir_ty.hir_id, false)
+                self.lower_resolved_ty_path(opt_self_ty, path, hir_ty.hir_id, false)
             }
             &hir::TyKind::OpaqueDef(opaque_ty) => {
                 // If this is an RPITIT and we are using the new RPITIT lowering scheme, we
@@ -2678,12 +2687,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 let guar = self.dcx().emit_err(BadReturnTypeNotation { span: hir_ty.span });
                 Ty::new_error(tcx, guar)
             }
-            hir::TyKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
-                debug!(?qself, ?segment);
-                let ty = self.lower_ty(qself);
-                self.lower_assoc_path_ty(hir_ty.hir_id, hir_ty.span, ty, qself, segment, false)
-                    .map(|(ty, _, _)| ty)
-                    .unwrap_or_else(|guar| Ty::new_error(tcx, guar))
+            hir::TyKind::Path(hir::QPath::TypeRelative(hir_self_ty, segment)) => {
+                debug!(?hir_self_ty, ?segment);
+                let self_ty = self.lower_ty(hir_self_ty);
+                self.lower_type_relative_ty_path(
+                    self_ty,
+                    hir_self_ty,
+                    segment,
+                    hir_ty.hir_id,
+                    hir_ty.span,
+                    false,
+                )
+                .map(|(ty, _, _)| ty)
+                .unwrap_or_else(|guar| Ty::new_error(tcx, guar))
             }
             &hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => {
                 let def_id = tcx.require_lang_item(lang_item, Some(span));
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 6cc7e82bbf735..05b00f65cfda8 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -2105,15 +2105,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         match *qpath {
             QPath::Resolved(ref maybe_qself, path) => {
                 let self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself).raw);
-                let ty = self.lowerer().lower_path(self_ty, path, hir_id, true);
+                let ty = self.lowerer().lower_resolved_ty_path(self_ty, path, hir_id, true);
                 (path.res, LoweredTy::from_raw(self, path_span, ty))
             }
-            QPath::TypeRelative(qself, segment) => {
-                let ty = self.lower_ty(qself);
+            QPath::TypeRelative(hir_self_ty, segment) => {
+                let self_ty = self.lower_ty(hir_self_ty);
 
-                let result = self
-                    .lowerer()
-                    .lower_assoc_path_ty(hir_id, path_span, ty.raw, qself, segment, true);
+                let result = self.lowerer().lower_type_relative_ty_path(
+                    self_ty.raw,
+                    hir_self_ty,
+                    segment,
+                    hir_id,
+                    path_span,
+                    true,
+                );
                 let ty = result
                     .map(|(ty, _, _)| ty)
                     .unwrap_or_else(|guar| Ty::new_error(self.tcx(), guar));
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index fb557555237e5..ea0adf16b1a36 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -308,7 +308,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
         ))
     }
 
-    fn lower_assoc_shared(
+    fn lower_assoc_item_path(
         &self,
         span: Span,
         item_def_id: DefId,

From bda903ed8ab07fe1e67b138f191a37c1b61a6914 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= 
Date: Wed, 23 Apr 2025 02:40:23 +0200
Subject: [PATCH 2012/4206] Introduce Boolean type `PermitVariants` for
 legibility

---
 .../src/hir_ty_lowering/mod.rs                | 35 ++++++++++++-------
 .../rustc_hir_typeck/src/fn_ctxt/checks.rs    | 11 ++++--
 2 files changed, 30 insertions(+), 16 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 5b587bb99ee4d..06756bd3ee683 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -245,35 +245,42 @@ pub enum FeedConstTy<'a, 'tcx> {
 
 #[derive(Debug, Clone, Copy)]
 enum LowerTypeRelativePathMode {
-    Type { permit_variants: bool },
+    Type(PermitVariants),
     Const,
 }
 
 impl LowerTypeRelativePathMode {
     fn assoc_tag(self) -> ty::AssocTag {
         match self {
-            Self::Type { .. } => ty::AssocTag::Type,
+            Self::Type(_) => ty::AssocTag::Type,
             Self::Const => ty::AssocTag::Const,
         }
     }
 
     fn def_kind(self) -> DefKind {
         match self {
-            Self::Type { .. } => DefKind::AssocTy,
+            Self::Type(_) => DefKind::AssocTy,
             Self::Const => DefKind::AssocConst,
         }
     }
 
-    fn permit_variants(self) -> bool {
+    fn permit_variants(self) -> PermitVariants {
         match self {
-            Self::Type { permit_variants } => permit_variants,
+            Self::Type(permit_variants) => permit_variants,
             // FIXME(mgca): Support paths like `Option::::None` or `Option::::Some` which
             // resolve to const ctors/fn items respectively.
-            Self::Const => false,
+            Self::Const => PermitVariants::No,
         }
     }
 }
 
+/// Whether to permit a path to resolve to an enum variant.
+#[derive(Debug, Clone, Copy)]
+pub enum PermitVariants {
+    Yes,
+    No,
+}
+
 #[derive(Debug, Clone, Copy)]
 enum TypeRelativePath<'tcx> {
     AssocItem(DefId, GenericArgsRef<'tcx>),
@@ -1160,7 +1167,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         segment: &'tcx hir::PathSegment<'tcx>,
         qpath_hir_id: HirId,
         span: Span,
-        permit_variants: bool,
+        permit_variants: PermitVariants,
     ) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
         let tcx = self.tcx();
         match self.lower_type_relative_path(
@@ -1169,7 +1176,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             segment,
             qpath_hir_id,
             span,
-            LowerTypeRelativePathMode::Type { permit_variants },
+            LowerTypeRelativePathMode::Type(permit_variants),
         )? {
             TypeRelativePath::AssocItem(def_id, args) => {
                 let alias_ty = ty::AliasTy::new_from_args(tcx, def_id, args);
@@ -1245,7 +1252,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     .iter()
                     .find(|vd| tcx.hygienic_eq(ident, vd.ident(tcx), adt_def.did()));
                 if let Some(variant_def) = variant_def {
-                    if mode.permit_variants() {
+                    if let PermitVariants::Yes = mode.permit_variants() {
                         tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None);
                         let _ = self.prohibit_generic_args(
                             slice::from_ref(segment).iter(),
@@ -2072,7 +2079,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         opt_self_ty: Option>,
         path: &hir::Path<'tcx>,
         hir_id: HirId,
-        permit_variants: bool,
+        permit_variants: PermitVariants,
     ) -> Ty<'tcx> {
         debug!(?path.res, ?opt_self_ty, ?path.segments);
         let tcx = self.tcx();
@@ -2103,7 +2110,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 );
                 self.lower_path_segment(span, did, path.segments.last().unwrap())
             }
-            Res::Def(kind @ DefKind::Variant, def_id) if permit_variants => {
+            Res::Def(kind @ DefKind::Variant, def_id)
+                if let PermitVariants::Yes = permit_variants =>
+            {
                 // Lower "variant type" as if it were a real type.
                 // The resulting `Ty` is type of the variant's enum for now.
                 assert_eq!(opt_self_ty, None);
@@ -2633,7 +2642,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
                 debug!(?maybe_qself, ?path);
                 let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
-                self.lower_resolved_ty_path(opt_self_ty, path, hir_ty.hir_id, false)
+                self.lower_resolved_ty_path(opt_self_ty, path, hir_ty.hir_id, PermitVariants::No)
             }
             &hir::TyKind::OpaqueDef(opaque_ty) => {
                 // If this is an RPITIT and we are using the new RPITIT lowering scheme, we
@@ -2696,7 +2705,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     segment,
                     hir_ty.hir_id,
                     hir_ty.span,
-                    false,
+                    PermitVariants::No,
                 )
                 .map(|(ty, _, _)| ty)
                 .unwrap_or_else(|guar| Ty::new_error(tcx, guar))
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 05b00f65cfda8..54c7819fc7b13 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -9,7 +9,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::{ExprKind, HirId, Node, QPath};
 use rustc_hir_analysis::check::potentially_plural_count;
-use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
+use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, PermitVariants};
 use rustc_index::IndexVec;
 use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TypeTrace};
 use rustc_middle::ty::adjustment::AllowTwoPhase;
@@ -2105,7 +2105,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         match *qpath {
             QPath::Resolved(ref maybe_qself, path) => {
                 let self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself).raw);
-                let ty = self.lowerer().lower_resolved_ty_path(self_ty, path, hir_id, true);
+                let ty = self.lowerer().lower_resolved_ty_path(
+                    self_ty,
+                    path,
+                    hir_id,
+                    PermitVariants::Yes,
+                );
                 (path.res, LoweredTy::from_raw(self, path_span, ty))
             }
             QPath::TypeRelative(hir_self_ty, segment) => {
@@ -2117,7 +2122,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     segment,
                     hir_id,
                     path_span,
-                    true,
+                    PermitVariants::Yes,
                 );
                 let ty = result
                     .map(|(ty, _, _)| ty)

From 7cd1da4a1646d1db3d409d6c2ff682b8f03ba14b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= 
Date: Wed, 23 Apr 2025 16:16:24 +0200
Subject: [PATCH 2013/4206] Rename and move several error reporting methods

Name them more consistently, descriptively and appropriately.
Move large error reporting methods into the dedicated error module to
make the happy paths in HIR ty lowering more legible.
---
 .../src/hir_ty_lowering/bounds.rs             |   2 +-
 .../src/hir_ty_lowering/dyn_compatibility.rs  |  10 +-
 .../src/hir_ty_lowering/errors.rs             | 195 ++++++++++++++++--
 .../src/hir_ty_lowering/mod.rs                | 190 ++---------------
 4 files changed, 205 insertions(+), 192 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index 9544f9b0c2bd1..6aadefc30274c 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -675,7 +675,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
                 // Good error for `where Trait::method(..): Send`.
                 let Some(self_ty) = opt_self_ty else {
-                    let guar = self.error_missing_qpath_self_ty(
+                    let guar = self.report_missing_self_ty_for_resolved_path(
                         trait_def_id,
                         hir_ty.span,
                         item_segment,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index 3af439eb2fd52..f411bf4d6102d 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -78,15 +78,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         // We  don't support empty trait objects.
         if regular_traits.is_empty() && auto_traits.is_empty() {
-            let guar = self.report_trait_object_with_no_traits_error(
-                span,
-                user_written_bounds.iter().copied(),
-            );
+            let guar =
+                self.report_trait_object_with_no_traits(span, user_written_bounds.iter().copied());
             return Ty::new_error(tcx, guar);
         }
         // We don't support >1 principal
         if regular_traits.len() > 1 {
-            let guar = self.report_trait_object_addition_traits_error(®ular_traits);
+            let guar = self.report_trait_object_addition_traits(®ular_traits);
             return Ty::new_error(tcx, guar);
         }
         // Don't create a dyn trait if we have errors in the principal.
@@ -344,7 +342,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
                         && hir_bound.span.contains(span)
                 });
-                self.complain_about_missing_type_params(
+                self.report_missing_type_params(
                     missing_type_params,
                     trait_ref.def_id,
                     span,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index 3759a224ff75b..60dc84716c73b 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -5,9 +5,9 @@ use rustc_errors::codes::*;
 use rustc_errors::{
     Applicability, Diag, ErrorGuaranteed, MultiSpan, listify, pluralize, struct_span_code_err,
 };
-use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
+use rustc_hir::{self as hir, HirId};
 use rustc_middle::bug;
 use rustc_middle::ty::fast_reject::{TreatParams, simplify_type};
 use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
@@ -23,6 +23,7 @@ use rustc_trait_selection::traits::{
     FulfillmentError, dyn_compatibility_violations_for_assoc_item,
 };
 use smallvec::SmallVec;
+use tracing::debug;
 
 use crate::errors::{
     self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams,
@@ -34,7 +35,7 @@ use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
 impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// On missing type parameters, emit an E0393 error and provide a structured suggestion using
     /// the type parameter's name as a placeholder.
-    pub(crate) fn complain_about_missing_type_params(
+    pub(crate) fn report_missing_type_params(
         &self,
         missing_type_params: Vec,
         def_id: DefId,
@@ -56,7 +57,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
     /// When the code is using the `Fn` traits directly, instead of the `Fn(A) -> B` syntax, emit
     /// an error and attempt to build a reasonable structured suggestion.
-    pub(crate) fn complain_about_internal_fn_trait(
+    pub(crate) fn report_internal_fn_trait(
         &self,
         span: Span,
         trait_def_id: DefId,
@@ -112,7 +113,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
     }
 
-    pub(super) fn complain_about_assoc_item_not_found(
+    pub(super) fn report_unresolved_assoc_item(
         &self,
         all_candidates: impl Fn() -> I,
         qself: AssocItemQSelf,
@@ -132,7 +133,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 .filter_by_name_unhygienic(assoc_ident.name)
                 .find(|item| tcx.hygienic_eq(assoc_ident, item.ident(tcx), r.def_id()))
         }) {
-            return self.complain_about_assoc_kind_mismatch(
+            return self.report_assoc_kind_mismatch(
                 assoc_item,
                 assoc_tag,
                 assoc_ident,
@@ -331,7 +332,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         self.dcx().emit_err(err)
     }
 
-    fn complain_about_assoc_kind_mismatch(
+    fn report_assoc_kind_mismatch(
         &self,
         assoc_item: &ty::AssocItem,
         assoc_tag: ty::AssocTag,
@@ -396,7 +397,173 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         })
     }
 
-    pub(super) fn report_ambiguous_assoc(
+    pub(crate) fn report_missing_self_ty_for_resolved_path(
+        &self,
+        trait_def_id: DefId,
+        span: Span,
+        item_segment: &hir::PathSegment<'tcx>,
+        assoc_tag: ty::AssocTag,
+    ) -> ErrorGuaranteed {
+        let tcx = self.tcx();
+        let path_str = tcx.def_path_str(trait_def_id);
+
+        let def_id = self.item_def_id();
+        debug!(item_def_id = ?def_id);
+
+        // FIXME: document why/how this is different from `tcx.local_parent(def_id)`
+        let parent_def_id = tcx.hir_get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id();
+        debug!(?parent_def_id);
+
+        // If the trait in segment is the same as the trait defining the item,
+        // use the `` syntax in the error.
+        let is_part_of_self_trait_constraints = def_id.to_def_id() == trait_def_id;
+        let is_part_of_fn_in_self_trait = parent_def_id == trait_def_id;
+
+        let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
+            vec!["Self".to_string()]
+        } else {
+            // Find all the types that have an `impl` for the trait.
+            tcx.all_impls(trait_def_id)
+                .filter_map(|impl_def_id| tcx.impl_trait_header(impl_def_id))
+                .filter(|header| {
+                    // Consider only accessible traits
+                    tcx.visibility(trait_def_id).is_accessible_from(self.item_def_id(), tcx)
+                        && header.polarity != ty::ImplPolarity::Negative
+                })
+                .map(|header| header.trait_ref.instantiate_identity().self_ty())
+                // We don't care about blanket impls.
+                .filter(|self_ty| !self_ty.has_non_region_param())
+                .map(|self_ty| tcx.erase_regions(self_ty).to_string())
+                .collect()
+        };
+        // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
+        // references the trait. Relevant for the first case in
+        // `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
+        self.report_ambiguous_assoc_item_path(
+            span,
+            &type_names,
+            &[path_str],
+            item_segment.ident.name,
+            assoc_tag,
+        )
+    }
+
+    pub(super) fn report_unresolved_type_relative_path(
+        &self,
+        self_ty: Ty<'tcx>,
+        hir_self_ty: &hir::Ty<'_>,
+        assoc_tag: ty::AssocTag,
+        ident: Ident,
+        qpath_hir_id: HirId,
+        span: Span,
+        variant_def_id: Option,
+    ) -> ErrorGuaranteed {
+        let tcx = self.tcx();
+        let kind_str = assoc_tag_str(assoc_tag);
+        if variant_def_id.is_some() {
+            // Variant in type position
+            let msg = format!("expected {kind_str}, found variant `{ident}`");
+            self.dcx().span_err(span, msg)
+        } else if self_ty.is_enum() {
+            let mut err = self.dcx().create_err(errors::NoVariantNamed {
+                span: ident.span,
+                ident,
+                ty: self_ty,
+            });
+
+            let adt_def = self_ty.ty_adt_def().expect("enum is not an ADT");
+            if let Some(variant_name) = find_best_match_for_name(
+                &adt_def.variants().iter().map(|variant| variant.name).collect::>(),
+                ident.name,
+                None,
+            ) && let Some(variant) = adt_def.variants().iter().find(|s| s.name == variant_name)
+            {
+                let mut suggestion = vec![(ident.span, variant_name.to_string())];
+                if let hir::Node::Stmt(&hir::Stmt { kind: hir::StmtKind::Semi(expr), .. })
+                | hir::Node::Expr(expr) = tcx.parent_hir_node(qpath_hir_id)
+                    && let hir::ExprKind::Struct(..) = expr.kind
+                {
+                    match variant.ctor {
+                        None => {
+                            // struct
+                            suggestion = vec![(
+                                ident.span.with_hi(expr.span.hi()),
+                                if variant.fields.is_empty() {
+                                    format!("{variant_name} {{}}")
+                                } else {
+                                    format!(
+                                        "{variant_name} {{ {} }}",
+                                        variant
+                                            .fields
+                                            .iter()
+                                            .map(|f| format!("{}: /* value */", f.name))
+                                            .collect::>()
+                                            .join(", ")
+                                    )
+                                },
+                            )];
+                        }
+                        Some((hir::def::CtorKind::Fn, def_id)) => {
+                            // tuple
+                            let fn_sig = tcx.fn_sig(def_id).instantiate_identity();
+                            let inputs = fn_sig.inputs().skip_binder();
+                            suggestion = vec![(
+                                ident.span.with_hi(expr.span.hi()),
+                                format!(
+                                    "{variant_name}({})",
+                                    inputs
+                                        .iter()
+                                        .map(|i| format!("/* {i} */"))
+                                        .collect::>()
+                                        .join(", ")
+                                ),
+                            )];
+                        }
+                        Some((hir::def::CtorKind::Const, _)) => {
+                            // unit
+                            suggestion = vec![(
+                                ident.span.with_hi(expr.span.hi()),
+                                variant_name.to_string(),
+                            )];
+                        }
+                    }
+                }
+                err.multipart_suggestion_verbose(
+                    "there is a variant with a similar name",
+                    suggestion,
+                    Applicability::HasPlaceholders,
+                );
+            } else {
+                err.span_label(ident.span, format!("variant not found in `{self_ty}`"));
+            }
+
+            if let Some(sp) = tcx.hir_span_if_local(adt_def.did()) {
+                err.span_label(sp, format!("variant `{ident}` not found here"));
+            }
+
+            err.emit()
+        } else if let Err(reported) = self_ty.error_reported() {
+            reported
+        } else {
+            match self.maybe_report_similar_assoc_fn(span, self_ty, hir_self_ty) {
+                Ok(()) => {}
+                Err(reported) => return reported,
+            }
+
+            let traits: Vec<_> = self.probe_traits_that_match_assoc_ty(self_ty, ident);
+
+            // Don't print `ty::Error` to the user.
+            self.report_ambiguous_assoc_item_path(
+                span,
+                &[self_ty.to_string()],
+                &traits,
+                ident.name,
+                assoc_tag,
+            )
+        }
+    }
+
+    pub(super) fn report_ambiguous_assoc_item_path(
         &self,
         span: Span,
         types: &[String],
@@ -505,7 +672,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         err.emit()
     }
 
-    pub(crate) fn complain_about_ambiguous_inherent_assoc(
+    pub(crate) fn report_ambiguous_inherent_assoc_item(
         &self,
         name: Ident,
         candidates: Vec,
@@ -518,12 +685,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             "multiple applicable items in scope"
         );
         err.span_label(name.span, format!("multiple `{name}` found"));
-        self.note_ambiguous_inherent_assoc_ty(&mut err, candidates, span);
+        self.note_ambiguous_inherent_assoc_item(&mut err, candidates, span);
         err.emit()
     }
 
     // FIXME(fmease): Heavily adapted from `rustc_hir_typeck::method::suggest`. Deduplicate.
-    fn note_ambiguous_inherent_assoc_ty(
+    fn note_ambiguous_inherent_assoc_item(
         &self,
         err: &mut Diag<'_>,
         candidates: Vec,
@@ -566,7 +733,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     }
 
     // FIXME(inherent_associated_types): Find similarly named associated types and suggest them.
-    pub(crate) fn complain_about_inherent_assoc_not_found(
+    pub(crate) fn report_unresolved_inherent_assoc_item(
         &self,
         name: Ident,
         self_ty: Ty<'tcx>,
@@ -1046,7 +1213,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
     }
 
-    pub fn report_prohibit_generics_error<'a>(
+    pub fn report_prohibited_generic_args<'a>(
         &self,
         segments: impl Iterator> + Clone,
         args_visitors: impl Iterator> + Clone,
@@ -1128,7 +1295,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         err.emit()
     }
 
-    pub fn report_trait_object_addition_traits_error(
+    pub fn report_trait_object_addition_traits(
         &self,
         regular_traits: &Vec<(ty::PolyTraitPredicate<'tcx>, SmallVec<[Span; 1]>)>,
     ) -> ErrorGuaranteed {
@@ -1171,7 +1338,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         err.emit()
     }
 
-    pub fn report_trait_object_with_no_traits_error(
+    pub fn report_trait_object_with_no_traits(
         &self,
         span: Span,
         user_written_clauses: impl IntoIterator, Span)>,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 06756bd3ee683..bb5c1543441dc 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -44,16 +44,14 @@ use rustc_middle::ty::{
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
 use rustc_session::parse::feature_err;
-use rustc_span::edit_distance::find_best_match_for_name;
-use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
+use rustc_span::{DUMMY_SP, Ident, Span, kw, sym};
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::wf::object_region_bounds;
 use rustc_trait_selection::traits::{self, ObligationCtxt};
 use tracing::{debug, instrument};
 
-use self::errors::assoc_tag_str;
 use crate::check::check_abi_fn_ptr;
-use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, NoVariantNamed};
+use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation};
 use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint};
 use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
 use crate::middle::resolve_bound_vars as rbv;
@@ -751,7 +749,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             trait_ref.path.segments.split_last().unwrap().1.iter(),
             GenericsArgsErrExtend::None,
         );
-        self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
+        self.report_internal_fn_trait(span, trait_def_id, trait_segment, false);
 
         let (generic_args, arg_count) = self.lower_generic_args_of_path(
             trait_ref.path.span,
@@ -926,7 +924,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         trait_segment: &hir::PathSegment<'tcx>,
         is_impl: bool,
     ) -> ty::TraitRef<'tcx> {
-        self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
+        self.report_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
 
         let (generic_args, _) =
             self.lower_generic_args_of_path(span, trait_def_id, &[], trait_segment, Some(self_ty));
@@ -1032,15 +1030,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         });
 
         let Some(bound) = matching_candidates.next() else {
-            let reported = self.complain_about_assoc_item_not_found(
+            return Err(self.report_unresolved_assoc_item(
                 all_candidates,
                 qself,
                 assoc_tag,
                 assoc_ident,
                 span,
                 constraint,
-            );
-            return Err(reported);
+            ));
         };
         debug!(?bound);
 
@@ -1326,113 +1323,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 span,
             )?,
             _ => {
-                let kind_str = assoc_tag_str(mode.assoc_tag());
-                let reported = if variant_def_id.is_some() {
-                    // Variant in type position
-                    let msg = format!("expected {kind_str}, found variant `{ident}`");
-                    self.dcx().span_err(span, msg)
-                } else if self_ty.is_enum() {
-                    let mut err = self.dcx().create_err(NoVariantNamed {
-                        span: ident.span,
-                        ident,
-                        ty: self_ty,
-                    });
-
-                    let adt_def = self_ty.ty_adt_def().expect("enum is not an ADT");
-                    if let Some(variant_name) = find_best_match_for_name(
-                        &adt_def
-                            .variants()
-                            .iter()
-                            .map(|variant| variant.name)
-                            .collect::>(),
-                        ident.name,
-                        None,
-                    ) && let Some(variant) =
-                        adt_def.variants().iter().find(|s| s.name == variant_name)
-                    {
-                        let mut suggestion = vec![(ident.span, variant_name.to_string())];
-                        if let hir::Node::Stmt(&hir::Stmt {
-                            kind: hir::StmtKind::Semi(expr), ..
-                        })
-                        | hir::Node::Expr(expr) = tcx.parent_hir_node(qpath_hir_id)
-                            && let hir::ExprKind::Struct(..) = expr.kind
-                        {
-                            match variant.ctor {
-                                None => {
-                                    // struct
-                                    suggestion = vec![(
-                                        ident.span.with_hi(expr.span.hi()),
-                                        if variant.fields.is_empty() {
-                                            format!("{variant_name} {{}}")
-                                        } else {
-                                            format!(
-                                                "{variant_name} {{ {} }}",
-                                                variant
-                                                    .fields
-                                                    .iter()
-                                                    .map(|f| format!("{}: /* value */", f.name))
-                                                    .collect::>()
-                                                    .join(", ")
-                                            )
-                                        },
-                                    )];
-                                }
-                                Some((hir::def::CtorKind::Fn, def_id)) => {
-                                    // tuple
-                                    let fn_sig = tcx.fn_sig(def_id).instantiate_identity();
-                                    let inputs = fn_sig.inputs().skip_binder();
-                                    suggestion = vec![(
-                                        ident.span.with_hi(expr.span.hi()),
-                                        format!(
-                                            "{variant_name}({})",
-                                            inputs
-                                                .iter()
-                                                .map(|i| format!("/* {i} */"))
-                                                .collect::>()
-                                                .join(", ")
-                                        ),
-                                    )];
-                                }
-                                Some((hir::def::CtorKind::Const, _)) => {
-                                    // unit
-                                    suggestion = vec![(
-                                        ident.span.with_hi(expr.span.hi()),
-                                        variant_name.to_string(),
-                                    )];
-                                }
-                            }
-                        }
-                        err.multipart_suggestion_verbose(
-                            "there is a variant with a similar name",
-                            suggestion,
-                            Applicability::HasPlaceholders,
-                        );
-                    } else {
-                        err.span_label(ident.span, format!("variant not found in `{self_ty}`"));
-                    }
-
-                    if let Some(sp) = tcx.hir_span_if_local(adt_def.did()) {
-                        err.span_label(sp, format!("variant `{ident}` not found here"));
-                    }
-
-                    err.emit()
-                } else if let Err(reported) = self_ty.error_reported() {
-                    reported
-                } else {
-                    self.maybe_report_similar_assoc_fn(span, self_ty, hir_self_ty)?;
-
-                    let traits: Vec<_> = self.probe_traits_that_match_assoc_ty(self_ty, ident);
-
-                    // Don't print `ty::Error` to the user.
-                    self.report_ambiguous_assoc(
-                        span,
-                        &[self_ty.to_string()],
-                        &traits,
-                        ident.name,
-                        mode.assoc_tag(),
-                    )
-                };
-                return Err(reported);
+                return Err(self.report_unresolved_type_relative_path(
+                    self_ty,
+                    hir_self_ty,
+                    mode.assoc_tag(),
+                    ident,
+                    qpath_hir_id,
+                    span,
+                    variant_def_id,
+                ));
             }
         };
 
@@ -1626,7 +1525,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             .collect();
 
         match &applicable_candidates[..] {
-            &[] => Err(self.complain_about_inherent_assoc_not_found(
+            &[] => Err(self.report_unresolved_inherent_assoc_item(
                 name,
                 self_ty,
                 candidates,
@@ -1637,7 +1536,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
             &[applicable_candidate] => Ok(applicable_candidate),
 
-            &[_, ..] => Err(self.complain_about_ambiguous_inherent_assoc(
+            &[_, ..] => Err(self.report_ambiguous_inherent_assoc_item(
                 name,
                 applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(),
                 span,
@@ -1833,7 +1732,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         debug!(?trait_def_id);
 
         let Some(self_ty) = opt_self_ty else {
-            return Err(self.error_missing_qpath_self_ty(
+            return Err(self.report_missing_self_ty_for_resolved_path(
                 trait_def_id,
                 span,
                 item_segment,
@@ -1852,57 +1751,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         Ok((item_def_id, item_args))
     }
 
-    fn error_missing_qpath_self_ty(
-        &self,
-        trait_def_id: DefId,
-        span: Span,
-        item_segment: &hir::PathSegment<'tcx>,
-        assoc_tag: ty::AssocTag,
-    ) -> ErrorGuaranteed {
-        let tcx = self.tcx();
-        let path_str = tcx.def_path_str(trait_def_id);
-
-        let def_id = self.item_def_id();
-        debug!(item_def_id = ?def_id);
-
-        // FIXME: document why/how this is different from `tcx.local_parent(def_id)`
-        let parent_def_id = tcx.hir_get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id();
-        debug!(?parent_def_id);
-
-        // If the trait in segment is the same as the trait defining the item,
-        // use the `` syntax in the error.
-        let is_part_of_self_trait_constraints = def_id.to_def_id() == trait_def_id;
-        let is_part_of_fn_in_self_trait = parent_def_id == trait_def_id;
-
-        let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
-            vec!["Self".to_string()]
-        } else {
-            // Find all the types that have an `impl` for the trait.
-            tcx.all_impls(trait_def_id)
-                .filter_map(|impl_def_id| tcx.impl_trait_header(impl_def_id))
-                .filter(|header| {
-                    // Consider only accessible traits
-                    tcx.visibility(trait_def_id).is_accessible_from(self.item_def_id(), tcx)
-                        && header.polarity != ty::ImplPolarity::Negative
-                })
-                .map(|header| header.trait_ref.instantiate_identity().self_ty())
-                // We don't care about blanket impls.
-                .filter(|self_ty| !self_ty.has_non_region_param())
-                .map(|self_ty| tcx.erase_regions(self_ty).to_string())
-                .collect()
-        };
-        // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
-        // references the trait. Relevant for the first case in
-        // `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
-        self.report_ambiguous_assoc(
-            span,
-            &type_names,
-            &[path_str],
-            item_segment.ident.name,
-            assoc_tag,
-        )
-    }
-
     pub fn prohibit_generic_args<'a>(
         &self,
         segments: impl Iterator> + Clone,
@@ -1911,7 +1759,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let args_visitors = segments.clone().flat_map(|segment| segment.args().args);
         let mut result = Ok(());
         if let Some(_) = args_visitors.clone().next() {
-            result = Err(self.report_prohibit_generics_error(
+            result = Err(self.report_prohibited_generic_args(
                 segments.clone(),
                 args_visitors,
                 err_extend,

From 9e1832998d0c47ee11cd28e0458e68d9e7186b0f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= 
Date: Wed, 23 Apr 2025 20:43:59 +0200
Subject: [PATCH 2014/4206] Factor out `resolve_type_relative_path`

IMPORTANT: This leads to a tiny diagnostic regression that will be fixed in the next commit!
---
 .../src/hir_ty_lowering/bounds.rs             | 141 +++++-------------
 .../src/hir_ty_lowering/mod.rs                | 123 +++++++++------
 .../path-non-param-qself.stderr               |  18 +++
 3 files changed, 130 insertions(+), 152 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index 6aadefc30274c..106420faa4c01 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -4,9 +4,9 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::codes::*;
 use rustc_errors::struct_span_code_err;
 use rustc_hir as hir;
+use rustc_hir::AmbigArg;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::{AmbigArg, HirId};
 use rustc_middle::bug;
 use rustc_middle::ty::{
     self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
@@ -713,118 +713,51 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     Err(guar) => Ty::new_error(tcx, guar),
                 }
             }
-            hir::QPath::TypeRelative(qself, item_segment)
-                if item_segment.args.is_some_and(|args| {
+            hir::QPath::TypeRelative(hir_self_ty, segment)
+                if segment.args.is_some_and(|args| {
                     matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation)
                 }) =>
             {
-                match self
-                    .resolve_type_relative_return_type_notation(
-                        qself,
-                        item_segment,
-                        hir_ty.hir_id,
-                        hir_ty.span,
-                    )
-                    .and_then(|(candidate, item_def_id)| {
-                        self.lower_return_type_notation_ty(candidate, item_def_id, hir_ty.span)
-                    }) {
-                    Ok(ty) => Ty::new_alias(tcx, ty::Projection, ty),
-                    Err(guar) => Ty::new_error(tcx, guar),
-                }
-            }
-            _ => self.lower_ty(hir_ty),
-        }
-    }
-
-    /// Perform type-dependent lookup for a *method* for return type notation.
-    /// This generally mirrors `::lower_type_relative_path`.
-    fn resolve_type_relative_return_type_notation(
-        &self,
-        qself: &'tcx hir::Ty<'tcx>,
-        item_segment: &'tcx hir::PathSegment<'tcx>,
-        qpath_hir_id: HirId,
-        span: Span,
-    ) -> Result<(ty::PolyTraitRef<'tcx>, DefId), ErrorGuaranteed> {
-        let tcx = self.tcx();
-        let qself_ty = self.lower_ty(qself);
-        let assoc_ident = item_segment.ident;
-        let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
-            path.res
-        } else {
-            Res::Err
-        };
-
-        let bound = match (qself_ty.kind(), qself_res) {
-            (_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => {
-                // `Self` in an impl of a trait -- we have a concrete self type and a
-                // trait reference.
-                let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else {
-                    // A cycle error occurred, most likely.
-                    self.dcx().span_bug(span, "expected cycle error");
-                };
-
-                self.probe_single_bound_for_assoc_item(
-                    || {
-                        traits::supertraits(
-                            tcx,
-                            ty::Binder::dummy(trait_ref.instantiate_identity()),
-                        )
-                    },
-                    AssocItemQSelf::SelfTyAlias,
+                let self_ty = self.lower_ty(hir_self_ty);
+                let (item_def_id, bound) = match self.resolve_type_relative_path(
+                    self_ty,
+                    hir_self_ty,
                     ty::AssocTag::Fn,
-                    assoc_ident,
-                    span,
+                    segment,
+                    hir_ty.hir_id,
+                    hir_ty.span,
                     None,
-                )?
-            }
-            (
-                &ty::Param(_),
-                Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did),
-            ) => self.probe_single_ty_param_bound_for_assoc_item(
-                param_did.expect_local(),
-                qself.span,
-                ty::AssocTag::Fn,
-                assoc_ident,
-                span,
-            )?,
-            _ => {
-                if let Err(reported) = qself_ty.error_reported() {
-                    return Err(reported);
-                } else {
-                    // FIXME(return_type_notation): Provide some structured suggestion here.
-                    let err = struct_span_code_err!(
-                        self.dcx(),
-                        span,
-                        E0223,
-                        "ambiguous associated function"
+                ) {
+                    Ok(result) => result,
+                    Err(guar) => return Ty::new_error(tcx, guar),
+                };
+
+                // Don't let `T::method` resolve to some `for<'a> >::method`,
+                // which may happen via a higher-ranked where clause or supertrait.
+                // This is the same restrictions as associated types; even though we could
+                // support it, it just makes things a lot more difficult to support in
+                // `resolve_bound_vars`, since we'd need to introduce those as elided
+                // bound vars on the where clause too.
+                if bound.has_bound_vars() {
+                    return Ty::new_error(
+                        tcx,
+                        self.dcx().emit_err(errors::AssociatedItemTraitUninferredGenericParams {
+                            span: hir_ty.span,
+                            inferred_sugg: Some(hir_ty.span.with_hi(segment.ident.span.lo())),
+                            bound: format!("{}::", tcx.anonymize_bound_vars(bound).skip_binder()),
+                            mpart_sugg: None,
+                            what: tcx.def_descr(item_def_id),
+                        }),
                     );
-                    return Err(err.emit());
                 }
-            }
-        };
-
-        let trait_def_id = bound.def_id();
-        let assoc_fn = self
-            .probe_assoc_item(assoc_ident, ty::AssocTag::Fn, qpath_hir_id, span, trait_def_id)
-            .expect("failed to find associated fn");
 
-        // Don't let `T::method` resolve to some `for<'a> >::method`,
-        // which may happen via a higher-ranked where clause or supertrait.
-        // This is the same restrictions as associated types; even though we could
-        // support it, it just makes things a lot more difficult to support in
-        // `resolve_bound_vars`, since we'd need to introduce those as elided
-        // bound vars on the where clause too.
-        if bound.has_bound_vars() {
-            return Err(self.dcx().emit_err(errors::AssociatedItemTraitUninferredGenericParams {
-                span,
-                inferred_sugg: Some(span.with_hi(item_segment.ident.span.lo())),
-                bound: format!("{}::", tcx.anonymize_bound_vars(bound).skip_binder(),),
-                mpart_sugg: None,
-                what: assoc_fn.descr(),
-            }));
+                match self.lower_return_type_notation_ty(bound, item_def_id, hir_ty.span) {
+                    Ok(ty) => Ty::new_alias(tcx, ty::Projection, ty),
+                    Err(guar) => Ty::new_error(tcx, guar),
+                }
+            }
+            _ => self.lower_ty(hir_ty),
         }
-
-        Ok((bound, assoc_fn.def_id))
     }
 
     /// Do the common parts of lowering an RTN type. This involves extending the
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index bb5c1543441dc..6b21bbbfcd809 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -38,8 +38,8 @@ use rustc_middle::middle::stability::AllowUnstable;
 use rustc_middle::mir::interpret::LitToConstInput;
 use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
 use rustc_middle::ty::{
-    self, AssocTag, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty,
-    TyCtxt, TypeVisitableExt, TypingMode, Upcast, fold_regions,
+    self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt,
+    TypeVisitableExt, TypingMode, Upcast, fold_regions,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
@@ -937,7 +937,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     fn probe_trait_that_defines_assoc_item(
         &self,
         trait_def_id: DefId,
-        assoc_tag: AssocTag,
+        assoc_tag: ty::AssocTag,
         assoc_ident: Ident,
     ) -> bool {
         self.tcx()
@@ -980,7 +980,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         &self,
         ty_param_def_id: LocalDefId,
         ty_param_span: Span,
-        assoc_tag: AssocTag,
+        assoc_tag: ty::AssocTag,
         assoc_ident: Ident,
         span: Span,
     ) -> Result, ErrorGuaranteed> {
@@ -1015,7 +1015,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         &self,
         all_candidates: impl Fn() -> I,
         qself: AssocItemQSelf,
-        assoc_tag: AssocTag,
+        assoc_tag: ty::AssocTag,
         assoc_ident: Ident,
         span: Span,
         constraint: Option<&hir::AssocItemConstraint<'tcx>>,
@@ -1238,7 +1238,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     ) -> Result, ErrorGuaranteed> {
         debug!(%self_ty, ?segment.ident);
         let tcx = self.tcx();
-        let ident = segment.ident;
 
         // Check if we have an enum variant or an inherent associated type.
         let mut variant_def_id = None;
@@ -1247,7 +1246,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 let variant_def = adt_def
                     .variants()
                     .iter()
-                    .find(|vd| tcx.hygienic_eq(ident, vd.ident(tcx), adt_def.did()));
+                    .find(|vd| tcx.hygienic_eq(segment.ident, vd.ident(tcx), adt_def.did()));
                 if let Some(variant_def) = variant_def {
                     if let PermitVariants::Yes = mode.permit_variants() {
                         tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None);
@@ -1282,13 +1281,70 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
         }
 
+        let (item_def_id, bound) = self.resolve_type_relative_path(
+            self_ty,
+            hir_self_ty,
+            mode.assoc_tag(),
+            segment,
+            qpath_hir_id,
+            span,
+            variant_def_id,
+        )?;
+
+        let (item_def_id, args) = self.lower_assoc_item_path(span, item_def_id, segment, bound)?;
+
+        if let Some(variant_def_id) = variant_def_id {
+            tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, qpath_hir_id, span, |lint| {
+                lint.primary_message("ambiguous associated item");
+                let mut could_refer_to = |kind: DefKind, def_id, also| {
+                    let note_msg = format!(
+                        "`{}` could{} refer to the {} defined here",
+                        segment.ident,
+                        also,
+                        tcx.def_kind_descr(kind, def_id)
+                    );
+                    lint.span_note(tcx.def_span(def_id), note_msg);
+                };
+
+                could_refer_to(DefKind::Variant, variant_def_id, "");
+                could_refer_to(mode.def_kind(), item_def_id, " also");
+
+                lint.span_suggestion(
+                    span,
+                    "use fully-qualified syntax",
+                    format!(
+                        "<{} as {}>::{}",
+                        self_ty,
+                        tcx.item_name(bound.def_id()),
+                        segment.ident
+                    ),
+                    Applicability::MachineApplicable,
+                );
+            });
+        }
+
+        Ok(TypeRelativePath::AssocItem(item_def_id, args))
+    }
+
+    /// Resolve a [type-relative](hir::QPath::TypeRelative) (and type-level) path.
+    fn resolve_type_relative_path(
+        &self,
+        self_ty: Ty<'tcx>,
+        hir_self_ty: &'tcx hir::Ty<'tcx>,
+        assoc_tag: ty::AssocTag,
+        segment: &'tcx hir::PathSegment<'tcx>,
+        qpath_hir_id: HirId,
+        span: Span,
+        variant_def_id: Option,
+    ) -> Result<(DefId, ty::PolyTraitRef<'tcx>), ErrorGuaranteed> {
+        let tcx = self.tcx();
+
         let self_ty_res = match hir_self_ty.kind {
             hir::TyKind::Path(hir::QPath::Resolved(_, path)) => path.res,
             _ => Res::Err,
         };
 
-        // Find the type of the associated item, and the trait where the associated
-        // item is declared.
+        // Find the type of the assoc item, and the trait where the associated item is declared.
         let bound = match (self_ty.kind(), self_ty_res) {
             (_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => {
                 // `Self` in an impl of a trait -- we have a concrete self type and a
@@ -1300,14 +1356,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
                 self.probe_single_bound_for_assoc_item(
                     || {
-                        traits::supertraits(
-                            tcx,
-                            ty::Binder::dummy(trait_ref.instantiate_identity()),
-                        )
+                        let trait_ref = ty::Binder::dummy(trait_ref.instantiate_identity());
+                        traits::supertraits(tcx, trait_ref)
                     },
                     AssocItemQSelf::SelfTyAlias,
-                    mode.assoc_tag(),
-                    ident,
+                    assoc_tag,
+                    segment.ident,
                     span,
                     None,
                 )?
@@ -1318,16 +1372,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             ) => self.probe_single_ty_param_bound_for_assoc_item(
                 param_did.expect_local(),
                 hir_self_ty.span,
-                mode.assoc_tag(),
-                ident,
+                assoc_tag,
+                segment.ident,
                 span,
             )?,
             _ => {
                 return Err(self.report_unresolved_type_relative_path(
                     self_ty,
                     hir_self_ty,
-                    mode.assoc_tag(),
-                    ident,
+                    assoc_tag,
+                    segment.ident,
                     qpath_hir_id,
                     span,
                     variant_def_id,
@@ -1335,38 +1389,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
         };
 
-        let trait_def_id = bound.def_id();
         let assoc_item = self
-            .probe_assoc_item(ident, mode.assoc_tag(), qpath_hir_id, span, trait_def_id)
+            .probe_assoc_item(segment.ident, assoc_tag, qpath_hir_id, span, bound.def_id())
             .expect("failed to find associated item");
-        let (def_id, args) = self.lower_assoc_item_path(span, assoc_item.def_id, segment, bound)?;
-        let result = TypeRelativePath::AssocItem(def_id, args);
-
-        if let Some(variant_def_id) = variant_def_id {
-            tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, qpath_hir_id, span, |lint| {
-                lint.primary_message("ambiguous associated item");
-                let mut could_refer_to = |kind: DefKind, def_id, also| {
-                    let note_msg = format!(
-                        "`{}` could{} refer to the {} defined here",
-                        ident,
-                        also,
-                        tcx.def_kind_descr(kind, def_id)
-                    );
-                    lint.span_note(tcx.def_span(def_id), note_msg);
-                };
 
-                could_refer_to(DefKind::Variant, variant_def_id, "");
-                could_refer_to(mode.def_kind(), assoc_item.def_id, " also");
-
-                lint.span_suggestion(
-                    span,
-                    "use fully-qualified syntax",
-                    format!("<{} as {}>::{}", self_ty, tcx.item_name(trait_def_id), ident),
-                    Applicability::MachineApplicable,
-                );
-            });
-        }
-        Ok(result)
+        Ok((assoc_item.def_id, bound))
     }
 
     /// Search for inherent associated items for use at the type level.
diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.stderr
index 38202bdbf0727..6b7ded3f28552 100644
--- a/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.stderr
+++ b/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.stderr
@@ -3,18 +3,36 @@ error[E0223]: ambiguous associated function
    |
 LL |     <()>::method(..): Send,
    |     ^^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated function `method` implemented for `()`, you could use the fully-qualified path
+   |
+LL -     <()>::method(..): Send,
+LL +     <() as Example>::method: Send,
+   |
 
 error[E0223]: ambiguous associated function
   --> $DIR/path-non-param-qself.rs:13:5
    |
 LL |     i32::method(..): Send,
    |     ^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated function `method` implemented for `i32`, you could use the fully-qualified path
+   |
+LL -     i32::method(..): Send,
+LL +     ::method: Send,
+   |
 
 error[E0223]: ambiguous associated function
   --> $DIR/path-non-param-qself.rs:15:5
    |
 LL |     Adt::method(..): Send,
    |     ^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated function `method` implemented for `Adt`, you could use the fully-qualified path
+   |
+LL -     Adt::method(..): Send,
+LL +     ::method: Send,
+   |
 
 error: aborting due to 3 previous errors
 

From 8c37c8c3e6133ae431bc4a5aec1c7b21a3134969 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= 
Date: Wed, 23 Apr 2025 21:14:25 +0200
Subject: [PATCH 2015/4206] Preserve generic args in suggestions for ambiguous
 associated items

Most notably, this preserves the `(..)` of ambiguous RTN paths.
---
 .../src/hir_ty_lowering/errors.rs             | 53 ++++++++++---------
 ...fers-shadowing-trait-item.uncovered.stderr |  8 ++-
 ...guous-associated-type-with-generics.stderr |  7 ++-
 .../associated-item-duplicate-names-3.stderr  |  8 ++-
 .../return-type-notation/path-no-qself.stderr |  2 +-
 .../path-non-param-qself.stderr               |  9 ++--
 ...sociated-types-in-ambiguous-context.stderr | 16 +++++-
 tests/ui/error-codes/E0223.stderr             |  8 ++-
 tests/ui/lint/bare-trait-objects-path.stderr  |  8 ++-
 .../qualified/qualified-path-params-2.stderr  |  2 +-
 tests/ui/self/self-impl.stderr                | 16 +++++-
 .../struct-path-associated-type.stderr        | 24 +++++++--
 tests/ui/traits/item-privacy.stderr           | 16 +++++-
 .../ice-unexpected-region-123863.stderr       |  2 +-
 tests/ui/typeck/issue-107087.stderr           |  8 ++-
 15 files changed, 140 insertions(+), 47 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index 60dc84716c73b..45fee0fa4024e 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -3,7 +3,8 @@ use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::unord::UnordMap;
 use rustc_errors::codes::*;
 use rustc_errors::{
-    Applicability, Diag, ErrorGuaranteed, MultiSpan, listify, pluralize, struct_span_code_err,
+    Applicability, Diag, ErrorGuaranteed, MultiSpan, SuggestionStyle, listify, pluralize,
+    struct_span_code_err,
 };
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -443,7 +444,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             span,
             &type_names,
             &[path_str],
-            item_segment.ident.name,
+            item_segment.ident,
             assoc_tag,
         )
     }
@@ -552,12 +553,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
             let traits: Vec<_> = self.probe_traits_that_match_assoc_ty(self_ty, ident);
 
-            // Don't print `ty::Error` to the user.
             self.report_ambiguous_assoc_item_path(
                 span,
                 &[self_ty.to_string()],
                 &traits,
-                ident.name,
+                ident,
                 assoc_tag,
             )
         }
@@ -568,7 +568,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         span: Span,
         types: &[String],
         traits: &[String],
-        name: Symbol,
+        ident: Ident,
         assoc_tag: ty::AssocTag,
     ) -> ErrorGuaranteed {
         let kind_str = assoc_tag_str(assoc_tag);
@@ -588,6 +588,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 Applicability::MachineApplicable,
             );
         } else {
+            let sugg_sp = span.until(ident.span);
+
             let mut types = types.to_vec();
             types.sort();
             let mut traits = traits.to_vec();
@@ -595,76 +597,79 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             match (&types[..], &traits[..]) {
                 ([], []) => {
                     err.span_suggestion_verbose(
-                        span,
+                        sugg_sp,
                         format!(
                             "if there were a type named `Type` that implements a trait named \
-                             `Trait` with associated {kind_str} `{name}`, you could use the \
+                             `Trait` with associated {kind_str} `{ident}`, you could use the \
                              fully-qualified path",
                         ),
-                        format!("::{name}"),
+                        "::",
                         Applicability::HasPlaceholders,
                     );
                 }
                 ([], [trait_str]) => {
                     err.span_suggestion_verbose(
-                        span,
+                        sugg_sp,
                         format!(
                             "if there were a type named `Example` that implemented `{trait_str}`, \
                              you could use the fully-qualified path",
                         ),
-                        format!("::{name}"),
+                        format!("::"),
                         Applicability::HasPlaceholders,
                     );
                 }
                 ([], traits) => {
-                    err.span_suggestions(
-                        span,
+                    err.span_suggestions_with_style(
+                        sugg_sp,
                         format!(
                             "if there were a type named `Example` that implemented one of the \
-                             traits with associated {kind_str} `{name}`, you could use the \
+                             traits with associated {kind_str} `{ident}`, you could use the \
                              fully-qualified path",
                         ),
-                        traits.iter().map(|trait_str| format!("::{name}")),
+                        traits.iter().map(|trait_str| format!("::")),
                         Applicability::HasPlaceholders,
+                        SuggestionStyle::ShowAlways,
                     );
                 }
                 ([type_str], []) => {
                     err.span_suggestion_verbose(
-                        span,
+                        sugg_sp,
                         format!(
-                            "if there were a trait named `Example` with associated {kind_str} `{name}` \
+                            "if there were a trait named `Example` with associated {kind_str} `{ident}` \
                              implemented for `{type_str}`, you could use the fully-qualified path",
                         ),
-                        format!("<{type_str} as Example>::{name}"),
+                        format!("<{type_str} as Example>::"),
                         Applicability::HasPlaceholders,
                     );
                 }
                 (types, []) => {
-                    err.span_suggestions(
-                        span,
+                    err.span_suggestions_with_style(
+                        sugg_sp,
                         format!(
-                            "if there were a trait named `Example` with associated {kind_str} `{name}` \
+                            "if there were a trait named `Example` with associated {kind_str} `{ident}` \
                              implemented for one of the types, you could use the fully-qualified \
                              path",
                         ),
                         types
                             .into_iter()
-                            .map(|type_str| format!("<{type_str} as Example>::{name}")),
+                            .map(|type_str| format!("<{type_str} as Example>::")),
                         Applicability::HasPlaceholders,
+                        SuggestionStyle::ShowAlways,
                     );
                 }
                 (types, traits) => {
                     let mut suggestions = vec![];
                     for type_str in types {
                         for trait_str in traits {
-                            suggestions.push(format!("<{type_str} as {trait_str}>::{name}"));
+                            suggestions.push(format!("<{type_str} as {trait_str}>::"));
                         }
                     }
-                    err.span_suggestions(
-                        span,
+                    err.span_suggestions_with_style(
+                        sugg_sp,
                         "use fully-qualified syntax",
                         suggestions,
                         Applicability::MachineApplicable,
+                        SuggestionStyle::ShowAlways,
                     );
                 }
             }
diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr b/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr
index 978305c2ce355..3e914e0538d0b 100644
--- a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr
+++ b/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr
@@ -2,7 +2,13 @@ error[E0223]: ambiguous associated type
   --> $DIR/not-found-self-type-differs-shadowing-trait-item.rs:28:12
    |
 LL |     let _: S::::Pr = ();
-   |            ^^^^^^^^^^^^^ help: use fully-qualified syntax: ` as Tr>::Pr`
+   |            ^^^^^^^^^^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -     let _: S::::Pr = ();
+LL +     let _:  as Tr>::Pr = ();
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr b/tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr
index 9e1dd73980792..fcf6b4c3e7361 100644
--- a/tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr
+++ b/tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr
@@ -2,7 +2,12 @@ error[E0223]: ambiguous associated type
   --> $DIR/ambiguous-associated-type-with-generics.rs:13:13
    |
 LL |     let _x: >::Ty;
-   |             ^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: ` as Assoc>::Ty`
+   |             ^^^^^^^^^^^^^^^^^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL |     let _x:  as Assoc>::Ty;
+   |                             ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/associated-item/associated-item-duplicate-names-3.stderr b/tests/ui/associated-item/associated-item-duplicate-names-3.stderr
index a2346e292ac40..84a9da0998832 100644
--- a/tests/ui/associated-item/associated-item-duplicate-names-3.stderr
+++ b/tests/ui/associated-item/associated-item-duplicate-names-3.stderr
@@ -13,7 +13,13 @@ error[E0223]: ambiguous associated type
   --> $DIR/associated-item-duplicate-names-3.rs:18:12
    |
 LL |     let x: Baz::Bar = 5;
-   |            ^^^^^^^^ help: use fully-qualified syntax: `::Bar`
+   |            ^^^^^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -     let x: Baz::Bar = 5;
+LL +     let x: ::Bar = 5;
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-no-qself.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-no-qself.stderr
index aad6dfc496b75..a13fdbda1bf7a 100644
--- a/tests/ui/associated-type-bounds/return-type-notation/path-no-qself.stderr
+++ b/tests/ui/associated-type-bounds/return-type-notation/path-no-qself.stderr
@@ -7,7 +7,7 @@ LL |     Trait::method(..): Send,
 help: if there were a type named `Example` that implemented `Trait`, you could use the fully-qualified path
    |
 LL -     Trait::method(..): Send,
-LL +     ::method: Send,
+LL +     ::method(..): Send,
    |
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.stderr
index 6b7ded3f28552..4c4c2c24079be 100644
--- a/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.stderr
+++ b/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.stderr
@@ -6,9 +6,8 @@ LL |     <()>::method(..): Send,
    |
 help: if there were a trait named `Example` with associated function `method` implemented for `()`, you could use the fully-qualified path
    |
-LL -     <()>::method(..): Send,
-LL +     <() as Example>::method: Send,
-   |
+LL |     <() as Example>::method(..): Send,
+   |         ++++++++++
 
 error[E0223]: ambiguous associated function
   --> $DIR/path-non-param-qself.rs:13:5
@@ -19,7 +18,7 @@ LL |     i32::method(..): Send,
 help: if there were a trait named `Example` with associated function `method` implemented for `i32`, you could use the fully-qualified path
    |
 LL -     i32::method(..): Send,
-LL +     ::method: Send,
+LL +     ::method(..): Send,
    |
 
 error[E0223]: ambiguous associated function
@@ -31,7 +30,7 @@ LL |     Adt::method(..): Send,
 help: if there were a trait named `Example` with associated function `method` implemented for `Adt`, you could use the fully-qualified path
    |
 LL -     Adt::method(..): Send,
-LL +     ::method: Send,
+LL +     ::method(..): Send,
    |
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr
index 1be8db5ddf44f..a7647cf26aadf 100644
--- a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr
+++ b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr
@@ -14,7 +14,13 @@ error[E0223]: ambiguous associated type
   --> $DIR/associated-types-in-ambiguous-context.rs:22:17
    |
 LL | trait Foo where Foo::Assoc: Bar {
-   |                 ^^^^^^^^^^ help: use fully-qualified syntax: `::Assoc`
+   |                 ^^^^^^^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL - trait Foo where Foo::Assoc: Bar {
+LL + trait Foo where ::Assoc: Bar {
+   |
 
 error[E0223]: ambiguous associated type
   --> $DIR/associated-types-in-ambiguous-context.rs:27:10
@@ -42,7 +48,13 @@ error[E0223]: ambiguous associated type
   --> $DIR/associated-types-in-ambiguous-context.rs:13:23
    |
 LL |     fn grab(&self) -> Grab::Value;
-   |                       ^^^^^^^^^^^ help: use fully-qualified syntax: `::Value`
+   |                       ^^^^^^^^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -     fn grab(&self) -> Grab::Value;
+LL +     fn grab(&self) -> ::Value;
+   |
 
 error[E0223]: ambiguous associated type
   --> $DIR/associated-types-in-ambiguous-context.rs:16:22
diff --git a/tests/ui/error-codes/E0223.stderr b/tests/ui/error-codes/E0223.stderr
index e985a4c9bf0d9..fbfdce5689a70 100644
--- a/tests/ui/error-codes/E0223.stderr
+++ b/tests/ui/error-codes/E0223.stderr
@@ -2,7 +2,13 @@ error[E0223]: ambiguous associated type
   --> $DIR/E0223.rs:8:14
    |
 LL |     let foo: MyTrait::X;
-   |              ^^^^^^^^^^ help: use fully-qualified syntax: `::X`
+   |              ^^^^^^^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -     let foo: MyTrait::X;
+LL +     let foo: ::X;
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lint/bare-trait-objects-path.stderr b/tests/ui/lint/bare-trait-objects-path.stderr
index fbb647c37c5ae..e611abd31f3b4 100644
--- a/tests/ui/lint/bare-trait-objects-path.stderr
+++ b/tests/ui/lint/bare-trait-objects-path.stderr
@@ -55,7 +55,13 @@ error[E0223]: ambiguous associated type
   --> $DIR/bare-trait-objects-path.rs:23:12
    |
 LL |     let _: Dyn::Ty;
-   |            ^^^^^^^ help: use fully-qualified syntax: `::Ty`
+   |            ^^^^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -     let _: Dyn::Ty;
+LL +     let _: ::Ty;
+   |
 
 error: aborting due to 1 previous error; 4 warnings emitted
 
diff --git a/tests/ui/qualified/qualified-path-params-2.stderr b/tests/ui/qualified/qualified-path-params-2.stderr
index 6641e81013f05..e70cdbdc3f49e 100644
--- a/tests/ui/qualified/qualified-path-params-2.stderr
+++ b/tests/ui/qualified/qualified-path-params-2.stderr
@@ -7,7 +7,7 @@ LL | type A = ::A::f;
 help: if there were a trait named `Example` with associated type `f` implemented for `::A`, you could use the fully-qualified path
    |
 LL - type A = ::A::f;
-LL + type A = <::A as Example>::f;
+LL + type A = <::A as Example>::f;
    |
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/self/self-impl.stderr b/tests/ui/self/self-impl.stderr
index 18ffd15427f81..1bda307d0eb3a 100644
--- a/tests/ui/self/self-impl.stderr
+++ b/tests/ui/self/self-impl.stderr
@@ -2,13 +2,25 @@ error[E0223]: ambiguous associated type
   --> $DIR/self-impl.rs:23:16
    |
 LL |         let _: ::Baz = true;
-   |                ^^^^^^^^^^^ help: use fully-qualified syntax: `::Baz`
+   |                ^^^^^^^^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -         let _: ::Baz = true;
+LL +         let _: ::Baz = true;
+   |
 
 error[E0223]: ambiguous associated type
   --> $DIR/self-impl.rs:25:16
    |
 LL |         let _: Self::Baz = true;
-   |                ^^^^^^^^^ help: use fully-qualified syntax: `::Baz`
+   |                ^^^^^^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -         let _: Self::Baz = true;
+LL +         let _: ::Baz = true;
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/structs/struct-path-associated-type.stderr b/tests/ui/structs/struct-path-associated-type.stderr
index de396e875b0cf..110362293ac32 100644
--- a/tests/ui/structs/struct-path-associated-type.stderr
+++ b/tests/ui/structs/struct-path-associated-type.stderr
@@ -48,19 +48,37 @@ error[E0223]: ambiguous associated type
   --> $DIR/struct-path-associated-type.rs:32:13
    |
 LL |     let s = S::A {};
-   |             ^^^^ help: use fully-qualified syntax: `::A`
+   |             ^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -     let s = S::A {};
+LL +     let s = ::A {};
+   |
 
 error[E0223]: ambiguous associated type
   --> $DIR/struct-path-associated-type.rs:33:13
    |
 LL |     let z = S::A:: {};
-   |             ^^^^ help: use fully-qualified syntax: `::A`
+   |             ^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -     let z = S::A:: {};
+LL +     let z = ::A:: {};
+   |
 
 error[E0223]: ambiguous associated type
   --> $DIR/struct-path-associated-type.rs:35:9
    |
 LL |         S::A {} => {}
-   |         ^^^^ help: use fully-qualified syntax: `::A`
+   |         ^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -         S::A {} => {}
+LL +         ::A {} => {}
+   |
 
 error: aborting due to 8 previous errors
 
diff --git a/tests/ui/traits/item-privacy.stderr b/tests/ui/traits/item-privacy.stderr
index 4fd9ef9119257..1d3d8cb98437c 100644
--- a/tests/ui/traits/item-privacy.stderr
+++ b/tests/ui/traits/item-privacy.stderr
@@ -230,13 +230,25 @@ error[E0223]: ambiguous associated type
   --> $DIR/item-privacy.rs:119:12
    |
 LL |     let _: S::B;
-   |            ^^^^ help: use fully-qualified syntax: `::B`
+   |            ^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -     let _: S::B;
+LL +     let _: ::B;
+   |
 
 error[E0223]: ambiguous associated type
   --> $DIR/item-privacy.rs:120:12
    |
 LL |     let _: S::C;
-   |            ^^^^ help: use fully-qualified syntax: `::C`
+   |            ^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -     let _: S::C;
+LL +     let _: ::C;
+   |
 
 error[E0624]: associated type `A` is private
   --> $DIR/item-privacy.rs:122:12
diff --git a/tests/ui/typeck/ice-unexpected-region-123863.stderr b/tests/ui/typeck/ice-unexpected-region-123863.stderr
index 8a4d767c14350..e5050b4d3167a 100644
--- a/tests/ui/typeck/ice-unexpected-region-123863.stderr
+++ b/tests/ui/typeck/ice-unexpected-region-123863.stderr
@@ -39,7 +39,7 @@ LL |     Inner::concat_strs::<"a">::A
 help: if there were a trait named `Example` with associated type `concat_strs` implemented for `Inner<_>`, you could use the fully-qualified path
    |
 LL -     Inner::concat_strs::<"a">::A
-LL +      as Example>::concat_strs::A
+LL +      as Example>::concat_strs::<"a">::A
    |
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/typeck/issue-107087.stderr b/tests/ui/typeck/issue-107087.stderr
index 289c8d161ae86..157ba5a167219 100644
--- a/tests/ui/typeck/issue-107087.stderr
+++ b/tests/ui/typeck/issue-107087.stderr
@@ -2,7 +2,13 @@ error[E0223]: ambiguous associated type
   --> $DIR/issue-107087.rs:16:5
    |
 LL |     A::B::<>::C
-   |     ^^^^^^^^ help: use fully-qualified syntax: ` as Foo>::B`
+   |     ^^^^^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -     A::B::<>::C
+LL +      as Foo>::B::<>::C
+   |
 
 error: aborting due to 1 previous error
 

From 8935d0bdeae3e5165928ebcb31adf7fd5e2a1355 Mon Sep 17 00:00:00 2001
From: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com>
Date: Wed, 7 May 2025 00:36:17 +0900
Subject: [PATCH 2016/4206] check module path inner or outer

Signed-off-by: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com>
---
 .../rust-analyzer/crates/hir/src/attrs.rs     |  9 +-
 .../rust-analyzer/crates/ide-db/src/defs.rs   | 63 +++++++-----
 .../crates/ide-db/src/documentation.rs        | 83 +++++++++++++---
 .../rust-analyzer/crates/ide/src/doc_links.rs | 96 ++++++++++++-------
 .../crates/ide/src/doc_links/tests.rs         | 56 +++++------
 .../rust-analyzer/crates/ide/src/hover.rs     |  4 +-
 .../crates/ide/src/hover/render.rs            | 46 +++++----
 .../ide/src/syntax_highlighting/inject.rs     | 17 +++-
 .../highlight_module_docs_inline.html         |  4 +-
 .../ide/src/syntax_highlighting/tests.rs      |  8 +-
 10 files changed, 256 insertions(+), 130 deletions(-)

diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs
index 38ba8d6a3199a..b1cf30b98f5b9 100644
--- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs
@@ -108,10 +108,9 @@ pub fn resolve_doc_path_on(
     def: impl HasAttrs + Copy,
     link: &str,
     ns: Option,
+    is_inner_doc: bool,
 ) -> Option {
-    let is_inner =
-        def.attrs(db).by_key(&intern::sym::doc).attrs().all(|attr| attr.id.is_inner_attr());
-    resolve_doc_path_on_(db, link, def.attr_id(), ns, is_inner)
+    resolve_doc_path_on_(db, link, def.attr_id(), ns, is_inner_doc)
 }
 
 fn resolve_doc_path_on_(
@@ -119,11 +118,11 @@ fn resolve_doc_path_on_(
     link: &str,
     attr_id: AttrDefId,
     ns: Option,
-    is_inner: bool,
+    is_inner_doc: bool,
 ) -> Option {
     let resolver = match attr_id {
         AttrDefId::ModuleId(it) => {
-            if is_inner {
+            if is_inner_doc {
                 it.resolver(db)
             } else if let Some(parent) = Module::from(it).parent(db) {
                 parent.id.resolver(db)
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
index bf4f541ff54ca..d5db1c481b691 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -6,7 +6,7 @@
 // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).
 
 use crate::RootDatabase;
-use crate::documentation::{Documentation, HasDocs};
+use crate::documentation::{DocsRangeMap, Documentation, HasDocs};
 use crate::famous_defs::FamousDefs;
 use arrayvec::ArrayVec;
 use either::Either;
@@ -21,7 +21,7 @@ use hir::{
 use span::Edition;
 use stdx::{format_to, impl_from};
 use syntax::{
-    SyntaxKind, SyntaxNode, SyntaxToken,
+    SyntaxKind, SyntaxNode, SyntaxToken, TextSize,
     ast::{self, AstNode},
     match_ast,
 };
@@ -210,29 +210,40 @@ impl Definition {
         famous_defs: Option<&FamousDefs<'_, '_>>,
         display_target: DisplayTarget,
     ) -> Option {
+        self.docs_with_rangemap(db, famous_defs, display_target).map(|(docs, _)| docs)
+    }
+
+    pub fn docs_with_rangemap(
+        &self,
+        db: &RootDatabase,
+        famous_defs: Option<&FamousDefs<'_, '_>>,
+        display_target: DisplayTarget,
+    ) -> Option<(Documentation, Option)> {
         let docs = match self {
-            Definition::Macro(it) => it.docs(db),
-            Definition::Field(it) => it.docs(db),
-            Definition::Module(it) => it.docs(db),
-            Definition::Crate(it) => it.docs(db),
-            Definition::Function(it) => it.docs(db),
-            Definition::Adt(it) => it.docs(db),
-            Definition::Variant(it) => it.docs(db),
-            Definition::Const(it) => it.docs(db),
-            Definition::Static(it) => it.docs(db),
-            Definition::Trait(it) => it.docs(db),
-            Definition::TraitAlias(it) => it.docs(db),
+            Definition::Macro(it) => it.docs_with_rangemap(db),
+            Definition::Field(it) => it.docs_with_rangemap(db),
+            Definition::Module(it) => it.docs_with_rangemap(db),
+            Definition::Crate(it) => it.docs_with_rangemap(db),
+            Definition::Function(it) => it.docs_with_rangemap(db),
+            Definition::Adt(it) => it.docs_with_rangemap(db),
+            Definition::Variant(it) => it.docs_with_rangemap(db),
+            Definition::Const(it) => it.docs_with_rangemap(db),
+            Definition::Static(it) => it.docs_with_rangemap(db),
+            Definition::Trait(it) => it.docs_with_rangemap(db),
+            Definition::TraitAlias(it) => it.docs_with_rangemap(db),
             Definition::TypeAlias(it) => {
-                it.docs(db).or_else(|| {
+                it.docs_with_rangemap(db).or_else(|| {
                     // docs are missing, try to fall back to the docs of the aliased item.
                     let adt = it.ty(db).as_adt()?;
-                    let docs = adt.docs(db)?;
-                    let docs = format!(
-                        "*This is the documentation for* `{}`\n\n{}",
-                        adt.display(db, display_target),
-                        docs.as_str()
+                    let (docs, range_map) = adt.docs_with_rangemap(db)?;
+                    let header_docs = format!(
+                        "*This is the documentation for* `{}`\n\n",
+                        adt.display(db, display_target)
                     );
-                    Some(Documentation::new(docs))
+                    let offset = TextSize::new(header_docs.len() as u32);
+                    let range_map = range_map.shift_docstring_line_range(offset);
+                    let docs = header_docs + docs.as_str();
+                    Some((Documentation::new(docs), range_map))
                 })
             }
             Definition::BuiltinType(it) => {
@@ -241,17 +252,17 @@ impl Definition {
                     let primitive_mod =
                         format!("prim_{}", it.name().display(fd.0.db, display_target.edition));
                     let doc_owner = find_std_module(fd, &primitive_mod, display_target.edition)?;
-                    doc_owner.docs(fd.0.db)
+                    doc_owner.docs_with_rangemap(fd.0.db)
                 })
             }
             Definition::BuiltinLifetime(StaticLifetime) => None,
             Definition::Local(_) => None,
             Definition::SelfType(impl_def) => {
-                impl_def.self_ty(db).as_adt().map(|adt| adt.docs(db))?
+                impl_def.self_ty(db).as_adt().map(|adt| adt.docs_with_rangemap(db))?
             }
             Definition::GenericParam(_) => None,
             Definition::Label(_) => None,
-            Definition::ExternCrateDecl(it) => it.docs(db),
+            Definition::ExternCrateDecl(it) => it.docs_with_rangemap(db),
 
             Definition::BuiltinAttr(it) => {
                 let name = it.name(db);
@@ -276,7 +287,8 @@ impl Definition {
                         name_value_str
                     );
                 }
-                Some(Documentation::new(docs.replace('*', "\\*")))
+
+                return Some((Documentation::new(docs.replace('*', "\\*")), None));
             }
             Definition::ToolModule(_) => None,
             Definition::DeriveHelper(_) => None,
@@ -291,8 +303,9 @@ impl Definition {
             let trait_ = assoc.implemented_trait(db)?;
             let name = Some(assoc.name(db)?);
             let item = trait_.items(db).into_iter().find(|it| it.name(db) == name)?;
-            item.docs(db)
+            item.docs_with_rangemap(db)
         })
+        .map(|(docs, range_map)| (docs, Some(range_map)))
     }
 
     pub fn label(&self, db: &RootDatabase, display_target: DisplayTarget) -> String {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs
index ef2c83992c049..30c355f8b3f93 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs
@@ -34,11 +34,13 @@ impl From for String {
 
 pub trait HasDocs: HasAttrs {
     fn docs(self, db: &dyn HirDatabase) -> Option;
+    fn docs_with_rangemap(self, db: &dyn HirDatabase) -> Option<(Documentation, DocsRangeMap)>;
     fn resolve_doc_path(
         self,
         db: &dyn HirDatabase,
         link: &str,
         ns: Option,
+        is_inner_doc: bool,
     ) -> Option;
 }
 /// A struct to map text ranges from [`Documentation`] back to TextRanges in the syntax tree.
@@ -53,7 +55,7 @@ pub struct DocsRangeMap {
 
 impl DocsRangeMap {
     /// Maps a [`TextRange`] relative to the documentation string back to its AST range
-    pub fn map(&self, range: TextRange) -> Option> {
+    pub fn map(&self, range: TextRange) -> Option<(InFile, AttrId)> {
         let found = self.mapping.binary_search_by(|(probe, ..)| probe.ordering(range)).ok()?;
         let (line_docs_range, idx, original_line_src_range) = self.mapping[found];
         if !line_docs_range.contains_range(range) {
@@ -71,7 +73,7 @@ impl DocsRangeMap {
                     text_range.end() + original_line_src_range.start() + relative_range.start(),
                     string.syntax().text_range().len().min(range.len()),
                 );
-                Some(InFile { file_id, value: range })
+                Some((InFile { file_id, value: range }, idx))
             }
             Either::Right(comment) => {
                 let text_range = comment.syntax().text_range();
@@ -82,10 +84,22 @@ impl DocsRangeMap {
                         + relative_range.start(),
                     text_range.len().min(range.len()),
                 );
-                Some(InFile { file_id, value: range })
+                Some((InFile { file_id, value: range }, idx))
             }
         }
     }
+
+    pub fn shift_docstring_line_range(self, offset: TextSize) -> DocsRangeMap {
+        let mapping = self
+            .mapping
+            .into_iter()
+            .map(|(buf_offset, id, base_offset)| {
+                let buf_offset = buf_offset.checked_add(offset).unwrap();
+                (buf_offset, id, base_offset)
+            })
+            .collect_vec();
+        DocsRangeMap { source_map: self.source_map, mapping }
+    }
 }
 
 pub fn docs_with_rangemap(
@@ -161,13 +175,20 @@ macro_rules! impl_has_docs {
             fn docs(self, db: &dyn HirDatabase) -> Option {
                 docs_from_attrs(&self.attrs(db)).map(Documentation)
             }
+            fn docs_with_rangemap(
+                self,
+                db: &dyn HirDatabase,
+            ) -> Option<(Documentation, DocsRangeMap)> {
+                docs_with_rangemap(db, &self.attrs(db))
+            }
             fn resolve_doc_path(
                 self,
                 db: &dyn HirDatabase,
                 link: &str,
-                ns: Option
+                ns: Option,
+                is_inner_doc: bool,
             ) -> Option {
-                resolve_doc_path_on(db, self, link, ns)
+                resolve_doc_path_on(db, self, link, ns, is_inner_doc)
             }
         }
     )*};
@@ -184,13 +205,21 @@ macro_rules! impl_has_docs_enum {
             fn docs(self, db: &dyn HirDatabase) -> Option {
                 hir::$enum::$variant(self).docs(db)
             }
+
+            fn docs_with_rangemap(
+                self,
+                db: &dyn HirDatabase,
+            ) -> Option<(Documentation, DocsRangeMap)> {
+                hir::$enum::$variant(self).docs_with_rangemap(db)
+            }
             fn resolve_doc_path(
                 self,
                 db: &dyn HirDatabase,
                 link: &str,
-                ns: Option
+                ns: Option,
+                is_inner_doc: bool,
             ) -> Option {
-                hir::$enum::$variant(self).resolve_doc_path(db, link, ns)
+                hir::$enum::$variant(self).resolve_doc_path(db, link, ns, is_inner_doc)
             }
         }
     )*};
@@ -207,16 +236,25 @@ impl HasDocs for hir::AssocItem {
         }
     }
 
+    fn docs_with_rangemap(self, db: &dyn HirDatabase) -> Option<(Documentation, DocsRangeMap)> {
+        match self {
+            hir::AssocItem::Function(it) => it.docs_with_rangemap(db),
+            hir::AssocItem::Const(it) => it.docs_with_rangemap(db),
+            hir::AssocItem::TypeAlias(it) => it.docs_with_rangemap(db),
+        }
+    }
+
     fn resolve_doc_path(
         self,
         db: &dyn HirDatabase,
         link: &str,
         ns: Option,
+        is_inner_doc: bool,
     ) -> Option {
         match self {
-            hir::AssocItem::Function(it) => it.resolve_doc_path(db, link, ns),
-            hir::AssocItem::Const(it) => it.resolve_doc_path(db, link, ns),
-            hir::AssocItem::TypeAlias(it) => it.resolve_doc_path(db, link, ns),
+            hir::AssocItem::Function(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+            hir::AssocItem::Const(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+            hir::AssocItem::TypeAlias(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
         }
     }
 }
@@ -238,13 +276,36 @@ impl HasDocs for hir::ExternCrateDecl {
         }
         .map(Documentation::new)
     }
+
+    fn docs_with_rangemap(self, db: &dyn HirDatabase) -> Option<(Documentation, DocsRangeMap)> {
+        let crate_docs = docs_with_rangemap(db, &self.resolved_crate(db)?.root_module().attrs(db));
+        let decl_docs = docs_with_rangemap(db, &self.attrs(db));
+        match (decl_docs, crate_docs) {
+            (None, None) => None,
+            (Some(decl_docs), None) => Some(decl_docs),
+            (None, Some(crate_docs)) => Some(crate_docs),
+            (
+                Some((Documentation(mut decl_docs), mut decl_range_map)),
+                Some((Documentation(crate_docs), crate_range_map)),
+            ) => {
+                decl_docs.push('\n');
+                decl_docs.push('\n');
+                let offset = TextSize::new(decl_docs.len() as u32);
+                decl_docs += &crate_docs;
+                let crate_range_map = crate_range_map.shift_docstring_line_range(offset);
+                decl_range_map.mapping.extend(crate_range_map.mapping);
+                Some((Documentation(decl_docs), decl_range_map))
+            }
+        }
+    }
     fn resolve_doc_path(
         self,
         db: &dyn HirDatabase,
         link: &str,
         ns: Option,
+        is_inner_doc: bool,
     ) -> Option {
-        resolve_doc_path_on(db, self, link, ns)
+        resolve_doc_path_on(db, self, link, ns, is_inner_doc)
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
index f0247f32d7ec6..2904203460601 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
@@ -5,6 +5,8 @@ mod tests;
 
 mod intra_doc_links;
 
+use std::ops::Range;
+
 use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag};
 use pulldown_cmark_to_cmark::{Options as CMarkOptions, cmark_resume_with_options};
 use stdx::format_to;
@@ -15,7 +17,7 @@ use ide_db::{
     RootDatabase,
     base_db::{CrateOrigin, LangCrateOrigin, ReleaseChannel, RootQueryDb},
     defs::{Definition, NameClass, NameRefClass},
-    documentation::{Documentation, HasDocs, docs_with_rangemap},
+    documentation::{DocsRangeMap, Documentation, HasDocs, docs_with_rangemap},
     helpers::pick_best_token,
 };
 use syntax::{
@@ -46,11 +48,17 @@ const MARKDOWN_OPTIONS: Options =
     Options::ENABLE_FOOTNOTES.union(Options::ENABLE_TABLES).union(Options::ENABLE_TASKLISTS);
 
 /// Rewrite documentation links in markdown to point to an online host (e.g. docs.rs)
-pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: Definition) -> String {
+pub(crate) fn rewrite_links(
+    db: &RootDatabase,
+    markdown: &str,
+    definition: Definition,
+    range_map: Option,
+) -> String {
     let mut cb = broken_link_clone_cb;
-    let doc = Parser::new_with_broken_link_callback(markdown, MARKDOWN_OPTIONS, Some(&mut cb));
+    let doc = Parser::new_with_broken_link_callback(markdown, MARKDOWN_OPTIONS, Some(&mut cb))
+        .into_offset_iter();
 
-    let doc = map_links(doc, |target, title| {
+    let doc = map_links(doc, |target, title, range| {
         // This check is imperfect, there's some overlap between valid intra-doc links
         // and valid URLs so we choose to be too eager to try to resolve what might be
         // a URL.
@@ -60,7 +68,16 @@ pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: Defin
             // Two possibilities:
             // * path-based links: `../../module/struct.MyStruct.html`
             // * module-based links (AKA intra-doc links): `super::super::module::MyStruct`
-            if let Some((target, title)) = rewrite_intra_doc_link(db, definition, target, title) {
+            let text_range =
+                TextRange::new(range.start.try_into().unwrap(), range.end.try_into().unwrap());
+            let is_inner_doc = range_map
+                .as_ref()
+                .and_then(|range_map| range_map.map(text_range))
+                .map(|(_, attr_id)| attr_id.is_inner_attr())
+                .unwrap_or(false);
+            if let Some((target, title)) =
+                rewrite_intra_doc_link(db, definition, target, title, is_inner_doc)
+            {
                 (None, target, title)
             } else if let Some(target) = rewrite_url_link(db, definition, target) {
                 (Some(LinkType::Inline), target, title.to_owned())
@@ -195,22 +212,23 @@ pub(crate) fn resolve_doc_path_for_def(
     def: Definition,
     link: &str,
     ns: Option,
+    is_inner_doc: bool,
 ) -> Option {
     match def {
-        Definition::Module(it) => it.resolve_doc_path(db, link, ns),
-        Definition::Crate(it) => it.resolve_doc_path(db, link, ns),
-        Definition::Function(it) => it.resolve_doc_path(db, link, ns),
-        Definition::Adt(it) => it.resolve_doc_path(db, link, ns),
-        Definition::Variant(it) => it.resolve_doc_path(db, link, ns),
-        Definition::Const(it) => it.resolve_doc_path(db, link, ns),
-        Definition::Static(it) => it.resolve_doc_path(db, link, ns),
-        Definition::Trait(it) => it.resolve_doc_path(db, link, ns),
-        Definition::TraitAlias(it) => it.resolve_doc_path(db, link, ns),
-        Definition::TypeAlias(it) => it.resolve_doc_path(db, link, ns),
-        Definition::Macro(it) => it.resolve_doc_path(db, link, ns),
-        Definition::Field(it) => it.resolve_doc_path(db, link, ns),
-        Definition::SelfType(it) => it.resolve_doc_path(db, link, ns),
-        Definition::ExternCrateDecl(it) => it.resolve_doc_path(db, link, ns),
+        Definition::Module(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::Crate(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::Function(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::Adt(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::Variant(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::Const(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::Static(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::Trait(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::TraitAlias(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::TypeAlias(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::Macro(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::Field(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::SelfType(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::ExternCrateDecl(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
         Definition::BuiltinAttr(_)
         | Definition::BuiltinType(_)
         | Definition::BuiltinLifetime(_)
@@ -289,28 +307,39 @@ impl DocCommentToken {
         let relative_comment_offset = offset - original_start - prefix_len;
 
         sema.descend_into_macros(doc_token).into_iter().find_map(|t| {
-            let (node, descended_prefix_len) = match_ast! {
+            let (node, descended_prefix_len, is_inner) = match_ast!{
                 match t {
-                    ast::Comment(comment) => (t.parent()?, TextSize::try_from(comment.prefix().len()).ok()?),
-                    ast::String(string) => (t.parent_ancestors().skip_while(|n| n.kind() != ATTR).nth(1)?, string.open_quote_text_range()?.len()),
+                    ast::Comment(comment) => {
+                        (t.parent()?, TextSize::try_from(comment.prefix().len()).ok()?, comment.is_inner())
+                    },
+                    ast::String(string) => {
+                        let attr = t.parent_ancestors().find_map(ast::Attr::cast)?;
+                        let attr_is_inner = attr.excl_token().map(|excl| excl.kind() == BANG).unwrap_or(false);
+                        (attr.syntax().parent()?, string.open_quote_text_range()?.len(), attr_is_inner)
+                    },
                     _ => return None,
                 }
             };
             let token_start = t.text_range().start();
             let abs_in_expansion_offset = token_start + relative_comment_offset + descended_prefix_len;
 
-            let (attributes, def) = doc_attributes(sema, &node)?;
+            let (attributes, def) = if is_inner && node.kind() != SOURCE_FILE {
+                let parent = node.parent()?;
+                doc_attributes(sema, &parent).unwrap_or(doc_attributes(sema, &parent.parent()?)?)
+            }else {
+                doc_attributes(sema, &node)?
+            };
             let (docs, doc_mapping) = docs_with_rangemap(sema.db, &attributes)?;
-            let (in_expansion_range, link, ns) =
+            let (in_expansion_range, link, ns, is_inner) =
                 extract_definitions_from_docs(&docs).into_iter().find_map(|(range, link, ns)| {
-                    let mapped = doc_mapping.map(range)?;
-                    (mapped.value.contains(abs_in_expansion_offset)).then_some((mapped.value, link, ns))
+                    let (mapped, idx) = doc_mapping.map(range)?;
+                    (mapped.value.contains(abs_in_expansion_offset)).then_some((mapped.value, link, ns, idx.is_inner_attr()))
                 })?;
             // get the relative range to the doc/attribute in the expansion
             let in_expansion_relative_range = in_expansion_range - descended_prefix_len - token_start;
             // Apply relative range to the original input comment
             let absolute_range = in_expansion_relative_range + original_start + prefix_len;
-            let def = resolve_doc_path_for_def(sema.db, def, &link, ns)?;
+            let def = resolve_doc_path_for_def(sema.db, def, &link, ns, is_inner)?;
             cb(def, node, absolute_range)
         })
     }
@@ -369,6 +398,7 @@ fn rewrite_intra_doc_link(
     def: Definition,
     target: &str,
     title: &str,
+    is_inner_doc: bool,
 ) -> Option<(String, String)> {
     let (link, ns) = parse_intra_doc_link(target);
 
@@ -377,7 +407,7 @@ fn rewrite_intra_doc_link(
         None => (link, None),
     };
 
-    let resolved = resolve_doc_path_for_def(db, def, link, ns)?;
+    let resolved = resolve_doc_path_for_def(db, def, link, ns, is_inner_doc)?;
     let mut url = get_doc_base_urls(db, resolved, None, None).0?;
 
     let (_, file, frag) = filename_and_frag_for_def(db, resolved)?;
@@ -421,8 +451,8 @@ fn mod_path_of_def(db: &RootDatabase, def: Definition) -> Option {
 
 /// Rewrites a markdown document, applying 'callback' to each link.
 fn map_links<'e>(
-    events: impl Iterator>,
-    callback: impl Fn(&str, &str) -> (Option, String, String),
+    events: impl Iterator, Range)>,
+    callback: impl Fn(&str, &str, Range) -> (Option, String, String),
 ) -> impl Iterator> {
     let mut in_link = false;
     // holds the origin link target on start event and the rewritten one on end event
@@ -432,7 +462,7 @@ fn map_links<'e>(
     // `Shortcut` type parsed from Start/End tags doesn't make sense for url links
     let mut end_link_type: Option = None;
 
-    events.map(move |evt| match evt {
+    events.map(move |(evt, range)| match evt {
         Event::Start(Tag::Link(link_type, ref target, _)) => {
             in_link = true;
             end_link_target = Some(target.clone());
@@ -449,7 +479,7 @@ fn map_links<'e>(
         }
         Event::Text(s) if in_link => {
             let (link_type, link_target_s, link_name) =
-                callback(&end_link_target.take().unwrap(), &s);
+                callback(&end_link_target.take().unwrap(), &s, range);
             end_link_target = Some(CowStr::Boxed(link_target_s.into()));
             if !matches!(end_link_type, Some(LinkType::Autolink)) {
                 end_link_type = link_type;
@@ -458,7 +488,7 @@ fn map_links<'e>(
         }
         Event::Code(s) if in_link => {
             let (link_type, link_target_s, link_name) =
-                callback(&end_link_target.take().unwrap(), &s);
+                callback(&end_link_target.take().unwrap(), &s, range);
             end_link_target = Some(CowStr::Boxed(link_target_s.into()));
             if !matches!(end_link_type, Some(LinkType::Autolink)) {
                 end_link_type = link_type;
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
index 6d56b98e57c8b..6af156fa668f5 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
@@ -5,7 +5,7 @@ use hir::Semantics;
 use ide_db::{
     FilePosition, FileRange, RootDatabase,
     defs::Definition,
-    documentation::{Documentation, HasDocs},
+    documentation::{DocsRangeMap, Documentation, HasDocs},
 };
 use itertools::Itertools;
 use syntax::{AstNode, SyntaxNode, ast, match_ast};
@@ -45,8 +45,8 @@ fn check_external_docs(
 fn check_rewrite(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let (analysis, position) = fixture::position(ra_fixture);
     let sema = &Semantics::new(&analysis.db);
-    let (cursor_def, docs) = def_under_cursor(sema, &position);
-    let res = rewrite_links(sema.db, docs.as_str(), cursor_def);
+    let (cursor_def, docs, range) = def_under_cursor(sema, &position);
+    let res = rewrite_links(sema.db, docs.as_str(), cursor_def, Some(range));
     expect.assert_eq(&res)
 }
 
@@ -56,12 +56,14 @@ fn check_doc_links(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
     let (analysis, position, mut expected) = fixture::annotations(ra_fixture);
     expected.sort_by_key(key_fn);
     let sema = &Semantics::new(&analysis.db);
-    let (cursor_def, docs) = def_under_cursor(sema, &position);
+    let (cursor_def, docs, range) = def_under_cursor(sema, &position);
     let defs = extract_definitions_from_docs(&docs);
     let actual: Vec<_> = defs
         .into_iter()
-        .flat_map(|(_, link, ns)| {
-            let def = resolve_doc_path_for_def(sema.db, cursor_def, &link, ns)
+        .flat_map(|(text_range, link, ns)| {
+            let attr = range.map(text_range);
+            let is_inner_attr = attr.map(|(_file, attr)| attr.is_inner_attr()).unwrap_or(false);
+            let def = resolve_doc_path_for_def(sema.db, cursor_def, &link, ns, is_inner_attr)
                 .unwrap_or_else(|| panic!("Failed to resolve {link}"));
             def.try_to_nav(sema.db).unwrap().into_iter().zip(iter::repeat(link))
         })
@@ -78,7 +80,7 @@ fn check_doc_links(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
 fn def_under_cursor(
     sema: &Semantics<'_, RootDatabase>,
     position: &FilePosition,
-) -> (Definition, Documentation) {
+) -> (Definition, Documentation, DocsRangeMap) {
     let (docs, def) = sema
         .parse_guess_edition(position.file_id)
         .syntax()
@@ -89,31 +91,31 @@ fn def_under_cursor(
         .find_map(|it| node_to_def(sema, &it))
         .expect("no def found")
         .unwrap();
-    let docs = docs.expect("no docs found for cursor def");
-    (def, docs)
+    let (docs, range) = docs.expect("no docs found for cursor def");
+    (def, docs, range)
 }
 
 fn node_to_def(
     sema: &Semantics<'_, RootDatabase>,
     node: &SyntaxNode,
-) -> Option, Definition)>> {
+) -> Option, Definition)>> {
     Some(match_ast! {
         match node {
-            ast::SourceFile(it)  => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Module(def))),
-            ast::Module(it)      => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Module(def))),
-            ast::Fn(it)          => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Function(def))),
-            ast::Struct(it)      => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Adt(hir::Adt::Struct(def)))),
-            ast::Union(it)       => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Adt(hir::Adt::Union(def)))),
-            ast::Enum(it)        => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Adt(hir::Adt::Enum(def)))),
-            ast::Variant(it)     => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Variant(def))),
-            ast::Trait(it)       => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Trait(def))),
-            ast::Static(it)      => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Static(def))),
-            ast::Const(it)       => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Const(def))),
-            ast::TypeAlias(it)   => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::TypeAlias(def))),
-            ast::Impl(it)        => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::SelfType(def))),
-            ast::RecordField(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Field(def))),
-            ast::TupleField(it)  => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Field(def))),
-            ast::Macro(it)       => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Macro(def))),
+            ast::SourceFile(it)  => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Module(def))),
+            ast::Module(it)      => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Module(def))),
+            ast::Fn(it)          => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Function(def))),
+            ast::Struct(it)      => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Adt(hir::Adt::Struct(def)))),
+            ast::Union(it)       => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Adt(hir::Adt::Union(def)))),
+            ast::Enum(it)        => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Adt(hir::Adt::Enum(def)))),
+            ast::Variant(it)     => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Variant(def))),
+            ast::Trait(it)       => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Trait(def))),
+            ast::Static(it)      => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Static(def))),
+            ast::Const(it)       => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Const(def))),
+            ast::TypeAlias(it)   => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::TypeAlias(def))),
+            ast::Impl(it)        => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::SelfType(def))),
+            ast::RecordField(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Field(def))),
+            ast::TupleField(it)  => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Field(def))),
+            ast::Macro(it)       => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Macro(def))),
             // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))),
             _ => return None,
         }
@@ -583,12 +585,12 @@ fn doc_links_module() {
 /// [`M::f`]
 mod M$0 {
   //^ M
-  #![doc = "inner_item[`M::S`]"]
+  #![doc = "inner_item[`S`]"]
 
     pub fn f() {}
          //^ M::f
     pub struct S;
-             //^ M::S
+             //^ S
 }
 "#,
     );
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 075afcec019f7..873e31b4a3373 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -456,7 +456,7 @@ pub(crate) fn hover_for_definition(
     let notable_traits = def_ty.map(|ty| notable_traits(db, &ty)).unwrap_or_default();
     let subst_types = subst.map(|subst| subst.types(db));
 
-    let markup = render::definition(
+    let (markup, range_map) = render::definition(
         sema.db,
         def,
         famous_defs.as_ref(),
@@ -469,7 +469,7 @@ pub(crate) fn hover_for_definition(
         display_target,
     );
     HoverResult {
-        markup: render::process_markup(sema.db, def, &markup, config),
+        markup: render::process_markup(sema.db, def, &markup, range_map, config),
         actions: [
             show_fn_references_action(sema.db, def),
             show_implementations_action(sema.db, def),
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
index 69b83f3b12d89..ad720c8a62742 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -11,7 +11,7 @@ use hir::{
 use ide_db::{
     RootDatabase,
     defs::Definition,
-    documentation::HasDocs,
+    documentation::{DocsRangeMap, HasDocs},
     famous_defs::FamousDefs,
     generated::lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES},
     syntax_helpers::prettify_macro_expansion,
@@ -21,7 +21,7 @@ use rustc_apfloat::{
     Float,
     ieee::{Half as f16, Quad as f128},
 };
-use span::Edition;
+use span::{Edition, TextSize};
 use stdx::format_to;
 use syntax::{AstNode, AstToken, Direction, SyntaxToken, T, algo, ast, match_ast};
 
@@ -276,13 +276,10 @@ pub(super) fn keyword(
         keyword_hints(sema, token, parent, edition, display_target);
 
     let doc_owner = find_std_module(&famous_defs, &keyword_mod, edition)?;
-    let docs = doc_owner.docs(sema.db)?;
-    let markup = process_markup(
-        sema.db,
-        Definition::Module(doc_owner),
-        &markup(Some(docs.into()), description, None, None, String::new()),
-        config,
-    );
+    let (docs, range_map) = doc_owner.docs_with_rangemap(sema.db)?;
+    let (markup, range_map) =
+        markup(Some(docs.into()), Some(range_map), description, None, None, String::new());
+    let markup = process_markup(sema.db, Definition::Module(doc_owner), &markup, range_map, config);
     Some(HoverResult { markup, actions })
 }
 
@@ -371,11 +368,15 @@ pub(super) fn process_markup(
     db: &RootDatabase,
     def: Definition,
     markup: &Markup,
+    markup_range_map: Option,
     config: &HoverConfig,
 ) -> Markup {
     let markup = markup.as_str();
-    let markup =
-        if config.links_in_hover { rewrite_links(db, markup, def) } else { remove_links(markup) };
+    let markup = if config.links_in_hover {
+        rewrite_links(db, markup, def, markup_range_map)
+    } else {
+        remove_links(markup)
+    };
     Markup::from(markup)
 }
 
@@ -482,7 +483,7 @@ pub(super) fn definition(
     config: &HoverConfig,
     edition: Edition,
     display_target: DisplayTarget,
-) -> Markup {
+) -> (Markup, Option) {
     let mod_path = definition_path(db, &def, edition);
     let label = match def {
         Definition::Trait(trait_) => trait_
@@ -518,7 +519,12 @@ pub(super) fn definition(
         }
         _ => def.label(db, display_target),
     };
-    let docs = def.docs(db, famous_defs, display_target);
+    let (docs, range_map) =
+        if let Some((docs, doc_range)) = def.docs_with_rangemap(db, famous_defs, display_target) {
+            (Some(docs), doc_range)
+        } else {
+            (None, None)
+        };
     let value = || match def {
         Definition::Variant(it) => {
             if !it.parent_enum(db).is_data_carrying(db) {
@@ -807,6 +813,7 @@ pub(super) fn definition(
 
     markup(
         docs.map(Into::into),
+        range_map,
         desc,
         extra.is_empty().not().then_some(extra),
         mod_path,
@@ -1083,11 +1090,12 @@ fn definition_path(db: &RootDatabase, &def: &Definition, edition: Edition) -> Op
 
 fn markup(
     docs: Option,
+    range_map: Option,
     rust: String,
     extra: Option,
     mod_path: Option,
     subst_types: String,
-) -> Markup {
+) -> (Markup, Option) {
     let mut buf = String::new();
 
     if let Some(mod_path) = mod_path {
@@ -1106,9 +1114,15 @@ fn markup(
     }
 
     if let Some(doc) = docs {
-        format_to!(buf, "\n___\n\n{}", doc);
+        format_to!(buf, "\n___\n\n");
+        let offset = TextSize::new(buf.len() as u32);
+        let buf_range_map = range_map.map(|range_map| range_map.shift_docstring_line_range(offset));
+        format_to!(buf, "{}", doc);
+
+        (buf.into(), buf_range_map)
+    } else {
+        (buf.into(), None)
     }
-    buf.into()
 }
 
 fn find_std_module(
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
index 0998e14c87ba0..7f5c2c1ec849b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
@@ -129,11 +129,18 @@ pub(super) fn doc_comment(
         extract_definitions_from_docs(&docs)
             .into_iter()
             .filter_map(|(range, link, ns)| {
-                doc_mapping.map(range).filter(|mapping| mapping.file_id == src_file_id).and_then(
-                    |InFile { value: mapped_range, .. }| {
-                        Some(mapped_range).zip(resolve_doc_path_for_def(sema.db, def, &link, ns))
-                    },
-                )
+                doc_mapping
+                    .map(range)
+                    .filter(|(mapping, _)| mapping.file_id == src_file_id)
+                    .and_then(|(InFile { value: mapped_range, .. }, attr_id)| {
+                        Some(mapped_range).zip(resolve_doc_path_for_def(
+                            sema.db,
+                            def,
+                            &link,
+                            ns,
+                            attr_id.is_inner_attr(),
+                        ))
+                    })
             })
             .for_each(|(range, def)| {
                 hl.add(HlRange {
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html
index 75d96b422c10b..9996a871580fb 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html
@@ -40,9 +40,9 @@
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 
-
-{% if self.document_union %}
+{% if !self.is_type_alias %}
     {{ self.document()|safe }}
 {% endif %}
 {% if self.fields_iter().peek().is_some() %}

From 4f3dd7b0180b1212aab607202ec6aa0d4fabb323 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Fri, 9 May 2025 18:47:25 +0200
Subject: [PATCH 2748/4206] Tweak attribute rendering depending on wether or
 not it is a type alias

---
 src/librustdoc/clean/types.rs            | 129 ++++++++++++-----------
 src/librustdoc/html/render/mod.rs        |  22 +++-
 src/librustdoc/html/render/print_item.rs | 100 +++++++++++++++---
 tests/rustdoc/type-layout.rs             |   2 +-
 4 files changed, 173 insertions(+), 80 deletions(-)

diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 1766627ce392c..c0bae5971a42e 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -815,67 +815,7 @@ impl Item {
 
     /// Returns a `#[repr(...)]` representation.
     pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Option {
-        use rustc_abi::IntegerType;
-
-        let def_id = self.def_id()?;
-        if !matches!(self.type_(), ItemType::Struct | ItemType::Enum | ItemType::Union) {
-            return None;
-        }
-        let adt = tcx.adt_def(def_id);
-        let repr = adt.repr();
-        let mut out = Vec::new();
-        if repr.c() {
-            out.push("C");
-        }
-        if repr.transparent() {
-            // Render `repr(transparent)` iff the non-1-ZST field is public or at least one
-            // field is public in case all fields are 1-ZST fields.
-            let render_transparent = is_json
-                || cache.document_private
-                || adt
-                    .all_fields()
-                    .find(|field| {
-                        let ty = field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
-                        tcx.layout_of(
-                            ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty),
-                        )
-                        .is_ok_and(|layout| !layout.is_1zst())
-                    })
-                    .map_or_else(
-                        || adt.all_fields().any(|field| field.vis.is_public()),
-                        |field| field.vis.is_public(),
-                    );
-
-            if render_transparent {
-                out.push("transparent");
-            }
-        }
-        if repr.simd() {
-            out.push("simd");
-        }
-        let pack_s;
-        if let Some(pack) = repr.pack {
-            pack_s = format!("packed({})", pack.bytes());
-            out.push(&pack_s);
-        }
-        let align_s;
-        if let Some(align) = repr.align {
-            align_s = format!("align({})", align.bytes());
-            out.push(&align_s);
-        }
-        let int_s;
-        if let Some(int) = repr.int {
-            int_s = match int {
-                IntegerType::Pointer(is_signed) => {
-                    format!("{}size", if is_signed { 'i' } else { 'u' })
-                }
-                IntegerType::Fixed(size, is_signed) => {
-                    format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
-                }
-            };
-            out.push(&int_s);
-        }
-        if !out.is_empty() { Some(format!("#[repr({})]", out.join(", "))) } else { None }
+        repr_attributes(tcx, cache, self.def_id()?, self.type_(), is_json)
     }
 
     pub fn is_doc_hidden(&self) -> bool {
@@ -887,6 +827,73 @@ impl Item {
     }
 }
 
+pub(crate) fn repr_attributes(
+    tcx: TyCtxt<'_>,
+    cache: &Cache,
+    def_id: DefId,
+    item_type: ItemType,
+    is_json: bool,
+) -> Option {
+    use rustc_abi::IntegerType;
+
+    if !matches!(item_type, ItemType::Struct | ItemType::Enum | ItemType::Union) {
+        return None;
+    }
+    let adt = tcx.adt_def(def_id);
+    let repr = adt.repr();
+    let mut out = Vec::new();
+    if repr.c() {
+        out.push("C");
+    }
+    if repr.transparent() {
+        // Render `repr(transparent)` iff the non-1-ZST field is public or at least one
+        // field is public in case all fields are 1-ZST fields.
+        let render_transparent = cache.document_private
+            || is_json
+            || adt
+                .all_fields()
+                .find(|field| {
+                    let ty = field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
+                    tcx.layout_of(ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty))
+                        .is_ok_and(|layout| !layout.is_1zst())
+                })
+                .map_or_else(
+                    || adt.all_fields().any(|field| field.vis.is_public()),
+                    |field| field.vis.is_public(),
+                );
+
+        if render_transparent {
+            out.push("transparent");
+        }
+    }
+    if repr.simd() {
+        out.push("simd");
+    }
+    let pack_s;
+    if let Some(pack) = repr.pack {
+        pack_s = format!("packed({})", pack.bytes());
+        out.push(&pack_s);
+    }
+    let align_s;
+    if let Some(align) = repr.align {
+        align_s = format!("align({})", align.bytes());
+        out.push(&align_s);
+    }
+    let int_s;
+    if let Some(int) = repr.int {
+        int_s = match int {
+            IntegerType::Pointer(is_signed) => {
+                format!("{}size", if is_signed { 'i' } else { 'u' })
+            }
+            IntegerType::Fixed(size, is_signed) => {
+                format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
+            }
+        };
+        out.push(&int_s);
+    }
+    if !out.is_empty() { Some(format!("#[repr({})]", out.join(", "))) } else { None }
+}
+
 #[derive(Clone, Debug)]
 pub(crate) enum ItemKind {
     ExternCrateItem {
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 6b4fd3cd834a9..f155ea52040a1 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1201,11 +1201,31 @@ fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) ->
     })
 }
 
+struct CodeAttribute(String);
+
+impl CodeAttribute {
+    fn render_into(self, w: &mut impl fmt::Write) {
+        write!(w, "
{}
", self.0).unwrap(); + } +} + // When an attribute is rendered inside a tag, it is formatted using // a div to produce a newline after it. fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Context<'_>) { for attr in it.attributes_and_repr(cx.tcx(), cx.cache(), false) { - write!(w, "
{attr}
").unwrap(); + CodeAttribute(attr).render_into(w); + } +} + +/// used for type aliases to only render their `repr` attribute. +fn render_repr_attributes_in_code( + w: &mut impl fmt::Write, + cx: &Context<'_>, + def_id: DefId, + item_type: ItemType, +) { + if let Some(repr) = clean::repr_attributes(cx.tcx(), cx.cache(), def_id, item_type) { + CodeAttribute(repr).render_into(w); } } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 692e11b2689e3..5f81ec68548ff 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -20,7 +20,7 @@ use super::{ collect_paths_for_type, document, ensure_trailing_slash, get_filtered_impls_for_reference, item_ty_to_section, notable_traits_button, notable_traits_json, render_all_impls, render_assoc_item, render_assoc_items, render_attributes_in_code, render_attributes_in_pre, - render_impl, render_rightside, render_stability_since_raw, + render_impl, render_repr_attributes_in_code, render_rightside, render_stability_since_raw, render_stability_since_raw_with_extra, write_section_heading, }; use crate::clean; @@ -1290,12 +1290,30 @@ fn item_type_alias(cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) -> .render_into(cx, it, true, w)?; } clean::TypeAliasInnerType::Union { fields } => { - ItemUnion { cx, it, fields, generics: &t.generics, is_type_alias: true } - .render_into(w)?; + let ty = cx.tcx().type_of(it.def_id().unwrap()).instantiate_identity(); + let union_def_id = ty.ty_adt_def().unwrap().did(); + + ItemUnion { + cx, + it, + fields, + generics: &t.generics, + is_type_alias: true, + def_id: union_def_id, + } + .render_into(w)?; } clean::TypeAliasInnerType::Struct { ctor_kind, fields } => { - DisplayStruct { ctor_kind: *ctor_kind, generics: &t.generics, fields } - .render_into(cx, it, true, w)?; + let ty = cx.tcx().type_of(it.def_id().unwrap()).instantiate_identity(); + let struct_def_id = ty.ty_adt_def().unwrap().did(); + + DisplayStruct { + ctor_kind: *ctor_kind, + generics: &t.generics, + fields, + def_id: struct_def_id, + } + .render_into(cx, it, true, w)?; } } } else { @@ -1417,8 +1435,9 @@ item_template!( fields: &'a [clean::Item], generics: &'a clean::Generics, is_type_alias: bool, + def_id: DefId, }, - methods = [document, document_type_layout, render_attributes_in_pre, render_assoc_items] + methods = [document, document_type_layout, render_assoc_items] ); impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { @@ -1449,13 +1468,41 @@ impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { }) .peekable() } + + fn render_attributes_in_pre(&self) -> impl fmt::Display { + fmt::from_fn(move |f| { + if !self.is_type_alias { + for a in self.it.attributes_and_repr(self.cx.tcx(), self.cx.cache(), false) { + writeln!(f, "{a}")?; + } + } else { + // For now we only render `repr` attributes for type aliases. + if let Some(repr) = clean::repr_attributes( + self.cx.tcx(), + self.cx.cache(), + self.def_id, + ItemType::Union, + ) { + writeln!(f, "{repr}")?; + }; + } + Ok(()) + }) + } } fn item_union(cx: &Context<'_>, it: &clean::Item, s: &clean::Union) -> impl fmt::Display { fmt::from_fn(|w| { - ItemUnion { cx, it, fields: &s.fields, generics: &s.generics, is_type_alias: false } - .render_into(w) - .unwrap(); + ItemUnion { + cx, + it, + fields: &s.fields, + generics: &s.generics, + is_type_alias: false, + def_id: it.def_id().unwrap(), + } + .render_into(w) + .unwrap(); Ok(()) }) } @@ -1502,7 +1549,12 @@ impl<'a> DisplayEnum<'a> { let has_stripped_entries = variants_len != variants_count; wrap_item(w, |w| { - render_attributes_in_code(w, it, cx); + if !is_type_alias { + render_attributes_in_code(w, it, cx); + } else { + // For now we only render `repr` attributes for type aliases. + render_repr_attributes_in_code(w, cx, self.def_id, ItemType::Enum); + } write!( w, "{}enum {}{}{}", @@ -1521,19 +1573,22 @@ impl<'a> DisplayEnum<'a> { ) })?; - if !is_type_alias { + let def_id = it.item_id.expect_def_id(); + let layout_def_id = if !is_type_alias { write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?; - } + def_id + } else { + self.def_id + }; if variants_count != 0 { write!(w, "{}", item_variants(cx, it, self.variants, self.def_id))?; } - let def_id = it.item_id.expect_def_id(); write!( w, "{}{}", render_assoc_items(cx, it, def_id, AssocItemRender::All), - document_type_layout(cx, def_id) + document_type_layout(cx, layout_def_id) ) } } @@ -1938,6 +1993,7 @@ struct DisplayStruct<'a> { ctor_kind: Option, generics: &'a clean::Generics, fields: &'a [clean::Item], + def_id: DefId, } impl<'a> DisplayStruct<'a> { @@ -1949,7 +2005,12 @@ impl<'a> DisplayStruct<'a> { w: &mut W, ) -> fmt::Result { wrap_item(w, |w| { - render_attributes_in_code(w, it, cx); + if !is_type_alias { + render_attributes_in_code(w, it, cx); + } else { + // For now we only render `repr` attributes for type aliases. + render_repr_attributes_in_code(w, cx, self.def_id, ItemType::Struct); + } write!( w, "{}", @@ -1974,8 +2035,13 @@ impl<'a> DisplayStruct<'a> { fn item_struct(cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) -> impl fmt::Display { fmt::from_fn(|w| { - DisplayStruct { ctor_kind: s.ctor_kind, generics: &s.generics, fields: s.fields.as_slice() } - .render_into(cx, it, false, w) + DisplayStruct { + ctor_kind: s.ctor_kind, + generics: &s.generics, + fields: s.fields.as_slice(), + def_id: it.def_id().unwrap(), + } + .render_into(cx, it, false, w) }) } diff --git a/tests/rustdoc/type-layout.rs b/tests/rustdoc/type-layout.rs index 6de435dbcc143..482b8b597dd30 100644 --- a/tests/rustdoc/type-layout.rs +++ b/tests/rustdoc/type-layout.rs @@ -61,7 +61,7 @@ pub type TypeAlias = X; pub type GenericTypeAlias = (Generic<(u32, ())>, Generic); // Regression test for the rustdoc equivalent of #85103. -//@ hasraw type_layout/type.Edges.html 'Encountered an error during type layout; the type failed to be normalized.' +//@ hasraw type_layout/type.Edges.html 'Unable to compute type layout, possibly due to this type having generic parameters. Layout can only be computed for concrete, fully-instantiated types.' pub type Edges<'a, E> = std::borrow::Cow<'a, [E]>; //@ !hasraw type_layout/trait.MyTrait.html 'Size: ' From 2b292d1b78194e0fb702b1271f4322d0b1d5d1bf Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 9 May 2025 18:47:50 +0200 Subject: [PATCH 2749/4206] Add regression test for #140739 --- tests/rustdoc/type-alias/repr.rs | 42 ++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 tests/rustdoc/type-alias/repr.rs diff --git a/tests/rustdoc/type-alias/repr.rs b/tests/rustdoc/type-alias/repr.rs new file mode 100644 index 0000000000000..cf90798036099 --- /dev/null +++ b/tests/rustdoc/type-alias/repr.rs @@ -0,0 +1,42 @@ +// This test ensures that the `repr` attribute is displayed in type aliases. +// +// Regression test for . + +#![crate_name = "foo"] + +/// bla +#[repr(C)] +pub struct Foo1; + +//@ has 'foo/type.Bar1.html' +//@ has - '//*[@class="rust item-decl"]/code' '#[repr(C)]pub struct Bar1;' +// Ensures that we see the doc comment of the type alias and not of the aliased type. +//@ has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' 'bar' +/// bar +pub type Bar1 = Foo1; + +/// bla +#[repr(C)] +pub union Foo2 { + pub a: u8, +} + +//@ has 'foo/type.Bar2.html' +//@ matches - '//*[@class="rust item-decl"]' '#\[repr\(C\)\]\npub union Bar2 \{*' +// Ensures that we see the doc comment of the type alias and not of the aliased type. +//@ has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' 'bar' +/// bar +pub type Bar2 = Foo2; + +/// bla +#[repr(C)] +pub enum Foo3 { + A, +} + +//@ has 'foo/type.Bar3.html' +//@ matches - '//*[@class="rust item-decl"]' '#\[repr\(C\)\]pub enum Bar3 \{*' +// Ensures that we see the doc comment of the type alias and not of the aliased type. +//@ has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' 'bar' +/// bar +pub type Bar3 = Foo3; From 3646a09811bfca55e976117b4c2b8bf0b4cb5aee Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 21 May 2025 22:55:50 +0200 Subject: [PATCH 2750/4206] Improve code --- src/librustdoc/clean/types.rs | 11 +-- src/librustdoc/html/render/mod.rs | 10 +-- src/librustdoc/html/render/print_item.rs | 76 ++++++++++--------- src/librustdoc/html/templates/item_union.html | 2 +- 4 files changed, 50 insertions(+), 49 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index c0bae5971a42e..63533f9fb83a4 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -764,7 +764,7 @@ impl Item { Some(tcx.visibility(def_id)) } - pub(crate) fn attributes_witout_repr(&self, tcx: TyCtxt<'_>, is_json: bool) -> Vec { + pub(crate) fn attributes_without_repr(&self, tcx: TyCtxt<'_>, is_json: bool) -> Vec { const ALLOWED_ATTRIBUTES: &[Symbol] = &[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive]; @@ -805,7 +805,7 @@ impl Item { cache: &Cache, is_json: bool, ) -> Vec { - let mut attrs = self.attributes_witout_repr(tcx, is_json); + let mut attrs = self.attributes_without_repr(tcx, is_json); if let Some(repr_attr) = self.repr(tcx, cache) { attrs.push(repr_attr); @@ -813,7 +813,7 @@ impl Item { attrs } - /// Returns a `#[repr(...)]` representation. + /// Returns a stringified `#[repr(...)]` attribute. pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Option { repr_attributes(tcx, cache, self.def_id()?, self.type_(), is_json) } @@ -2370,8 +2370,9 @@ impl TypeAliasInnerType { fn has_stripped_entries(&self) -> Option { Some(match self { Self::Enum { variants, .. } => variants.iter().any(|v| v.is_stripped()), - Self::Union { fields } => fields.iter().any(|f| f.is_stripped()), - Self::Struct { fields, .. } => fields.iter().any(|f| f.is_stripped()), + Self::Union { fields } | Self::Struct { fields, .. } => { + fields.iter().any(|f| f.is_stripped()) + } }) } } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index f155ea52040a1..14b35d3c39208 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1203,17 +1203,15 @@ fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) -> struct CodeAttribute(String); -impl CodeAttribute { - fn render_into(self, w: &mut impl fmt::Write) { - write!(w, "
{}
", self.0).unwrap(); - } +fn render_code_attribute(code_attr: CodeAttribute, w: &mut impl fmt::Write) { + write!(w, "
{}
", code_attr.0).unwrap(); } // When an attribute is rendered inside a tag, it is formatted using // a div to produce a newline after it. fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Context<'_>) { for attr in it.attributes_and_repr(cx.tcx(), cx.cache(), false) { - CodeAttribute(attr).render_into(w); + render_code_attribute(CodeAttribute(attr), w); } } @@ -1225,7 +1223,7 @@ fn render_repr_attributes_in_code( item_type: ItemType, ) { if let Some(repr) = clean::repr_attributes(cx.tcx(), cx.cache(), def_id, item_type) { - CodeAttribute(repr).render_into(w); + render_code_attribute(CodeAttribute(repr), w); } } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 5f81ec68548ff..3ef578cb03d0e 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1457,26 +1457,23 @@ impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { ty.print(self.cx) } - fn fields_iter( - &self, - ) -> iter::Peekable> { - self.fields - .iter() - .filter_map(|f| match f.kind { - clean::StructFieldItem(ref ty) => Some((f, ty)), - _ => None, - }) - .peekable() + // FIXME (GuillaumeGomez): When is implemented, + // we can replace the returned value with: + // + // `iter::Peekable>` + // + // And update `item_union.html`. + fn fields_iter(&self) -> impl Iterator { + self.fields.iter().filter_map(|f| match f.kind { + clean::StructFieldItem(ref ty) => Some((f, ty)), + _ => None, + }) } fn render_attributes_in_pre(&self) -> impl fmt::Display { fmt::from_fn(move |f| { - if !self.is_type_alias { - for a in self.it.attributes_and_repr(self.cx.tcx(), self.cx.cache(), false) { - writeln!(f, "{a}")?; - } - } else { - // For now we only render `repr` attributes for type aliases. + if self.is_type_alias { + // For now the only attributes we render for type aliases are `repr` attributes. if let Some(repr) = clean::repr_attributes( self.cx.tcx(), self.cx.cache(), @@ -1485,6 +1482,10 @@ impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { ) { writeln!(f, "{repr}")?; }; + } else { + for a in self.it.attributes_and_repr(self.cx.tcx(), self.cx.cache(), false) { + writeln!(f, "{a}")?; + } } Ok(()) }) @@ -1501,8 +1502,7 @@ fn item_union(cx: &Context<'_>, it: &clean::Item, s: &clean::Union) -> impl fmt: is_type_alias: false, def_id: it.def_id().unwrap(), } - .render_into(w) - .unwrap(); + .render_into(w)?; Ok(()) }) } @@ -1529,14 +1529,14 @@ fn print_tuple_struct_fields(cx: &Context<'_>, s: &[clean::Item]) -> impl Displa }) } -struct DisplayEnum<'a> { - variants: &'a IndexVec, - generics: &'a clean::Generics, +struct DisplayEnum<'clean> { + variants: &'clean IndexVec, + generics: &'clean clean::Generics, is_non_exhaustive: bool, def_id: DefId, } -impl<'a> DisplayEnum<'a> { +impl<'clean> DisplayEnum<'clean> { fn render_into( self, cx: &Context<'_>, @@ -1544,16 +1544,16 @@ impl<'a> DisplayEnum<'a> { is_type_alias: bool, w: &mut W, ) -> fmt::Result { - let variants_count = self.variants.iter().filter(|i| !i.is_stripped()).count(); + let non_stripped_variant_count = self.variants.iter().filter(|i| !i.is_stripped()).count(); let variants_len = self.variants.len(); - let has_stripped_entries = variants_len != variants_count; + let has_stripped_entries = variants_len != non_stripped_variant_count; wrap_item(w, |w| { - if !is_type_alias { - render_attributes_in_code(w, it, cx); - } else { - // For now we only render `repr` attributes for type aliases. + if is_type_alias { + // For now the only attributes we render for type aliases are `repr` attributes. render_repr_attributes_in_code(w, cx, self.def_id, ItemType::Enum); + } else { + render_attributes_in_code(w, it, cx); } write!( w, @@ -1565,7 +1565,7 @@ impl<'a> DisplayEnum<'a> { cx, Some(self.generics), self.variants, - variants_count, + non_stripped_variant_count, has_stripped_entries, self.is_non_exhaustive, self.def_id, @@ -1574,14 +1574,16 @@ impl<'a> DisplayEnum<'a> { })?; let def_id = it.item_id.expect_def_id(); - let layout_def_id = if !is_type_alias { + let layout_def_id = if is_type_alias { + self.def_id + } else { write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?; + // We don't return the same `DefId` since the layout size of the type alias might be + // different since we might have more information on the generics. def_id - } else { - self.def_id }; - if variants_count != 0 { + if non_stripped_variant_count != 0 { write!(w, "{}", item_variants(cx, it, self.variants, self.def_id))?; } write!( @@ -2005,11 +2007,11 @@ impl<'a> DisplayStruct<'a> { w: &mut W, ) -> fmt::Result { wrap_item(w, |w| { - if !is_type_alias { - render_attributes_in_code(w, it, cx); - } else { - // For now we only render `repr` attributes for type aliases. + if is_type_alias { + // For now the only attributes we render for type aliases are `repr` attributes. render_repr_attributes_in_code(w, cx, self.def_id, ItemType::Struct); + } else { + render_attributes_in_code(w, it, cx); } write!( w, diff --git a/src/librustdoc/html/templates/item_union.html b/src/librustdoc/html/templates/item_union.html index 99a9bc874dd59..b5d3367a6a10b 100644 --- a/src/librustdoc/html/templates/item_union.html +++ b/src/librustdoc/html/templates/item_union.html @@ -5,7 +5,7 @@ {% if !self.is_type_alias %} {{ self.document()|safe }} {% endif %} -{% if self.fields_iter().peek().is_some() %} +{% if self.fields_iter().next().is_some() %}

{# #} Fields§ {# #}

From ec97b0f0b57376550efa4d144b62955970f22f02 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 25 May 2025 15:27:32 +0200 Subject: [PATCH 2751/4206] Update to new API --- src/librustdoc/clean/types.rs | 2 +- src/librustdoc/html/render/mod.rs | 2 +- src/librustdoc/html/render/print_item.rs | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 63533f9fb83a4..bb3469867d51e 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -807,7 +807,7 @@ impl Item { ) -> Vec { let mut attrs = self.attributes_without_repr(tcx, is_json); - if let Some(repr_attr) = self.repr(tcx, cache) { + if let Some(repr_attr) = self.repr(tcx, cache, is_json) { attrs.push(repr_attr); } attrs diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 14b35d3c39208..5677b13033db5 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1222,7 +1222,7 @@ fn render_repr_attributes_in_code( def_id: DefId, item_type: ItemType, ) { - if let Some(repr) = clean::repr_attributes(cx.tcx(), cx.cache(), def_id, item_type) { + if let Some(repr) = clean::repr_attributes(cx.tcx(), cx.cache(), def_id, item_type, false) { render_code_attribute(CodeAttribute(repr), w); } } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 3ef578cb03d0e..b4663961c1b71 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1479,6 +1479,7 @@ impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { self.cx.cache(), self.def_id, ItemType::Union, + false, ) { writeln!(f, "{repr}")?; }; From 84a3255cc309c9c25e8ed2c16435bb882f364e96 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 24 May 2025 17:24:55 +0000 Subject: [PATCH 2752/4206] Fast path fold_predicate in old canonicalizer --- compiler/rustc_infer/src/infer/canonical/canonicalizer.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 26ecaebe97f2d..0b543f091f730 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -493,6 +493,10 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { ct } } + + fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + if p.flags().intersects(self.needs_canonical_flags) { p.super_fold_with(self) } else { p } + } } impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { From fe1808718cc83aab514a92c7129fe76e122045cf Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 25 May 2025 17:20:20 +0300 Subject: [PATCH 2753/4206] Fix IDE resolution of item macros It wasn't inside the source, because there was no source map. --- .../rust-analyzer/crates/hir-def/src/db.rs | 3 ++ .../crates/hir-def/src/resolver.rs | 9 ++++ .../crates/hir-expand/src/lib.rs | 2 + .../rust-analyzer/crates/hir/src/semantics.rs | 10 ++--- .../crates/hir/src/source_analyzer.rs | 41 ++++++++----------- .../crates/ide-completion/src/tests/item.rs | 38 ++++++++++++++++- 6 files changed, 74 insertions(+), 29 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index 4a9a3b12cfab4..6f9340a0e4d07 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -422,6 +422,7 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { let makro = &item_tree[loc.id.value]; MacroDefId { krate: loc.container.krate, + block: loc.container.block.map(|block| salsa::plumbing::AsId::as_id(&block)), kind: kind(loc.expander, loc.id.file_id(), makro.ast_id.upcast()), local_inner: false, allow_internal_unsafe: loc.allow_internal_unsafe, @@ -435,6 +436,7 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { let makro = &item_tree[loc.id.value]; MacroDefId { krate: loc.container.krate, + block: loc.container.block.map(|block| salsa::plumbing::AsId::as_id(&block)), kind: kind(loc.expander, loc.id.file_id(), makro.ast_id.upcast()), local_inner: loc.flags.contains(MacroRulesLocFlags::LOCAL_INNER), allow_internal_unsafe: loc @@ -450,6 +452,7 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { let makro = &item_tree[loc.id.value]; MacroDefId { krate: loc.container.krate, + block: None, kind: MacroDefKind::ProcMacro( InFile::new(loc.id.file_id(), makro.ast_id), loc.expander, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index 16988ddf04b26..416bcbb096bdc 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -696,6 +696,15 @@ impl<'db> Resolver<'db> { &def_map[local_id].scope } + pub fn item_scopes(&self) -> impl Iterator { + self.scopes() + .filter_map(move |scope| match scope { + Scope::BlockScope(m) => Some(&m.def_map[m.module_id].scope), + _ => None, + }) + .chain(std::iter::once(&self.module_scope.def_map[self.module_scope.module_id].scope)) + } + pub fn krate(&self) -> Crate { self.module_scope.def_map.krate() } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index d844d8f41eeff..19cd0298e93de 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -258,6 +258,8 @@ pub struct MacroCallLoc { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct MacroDefId { pub krate: Crate, + // FIXME: In `hir-expand` we can't refer to `BlockId`. + pub block: Option, pub edition: Edition, pub kind: MacroDefKind, pub local_inner: bool, diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index caa6700de9f94..e479770b47e9e 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -411,7 +411,7 @@ impl<'db> SemanticsImpl<'db> { let sa = self.analyze_no_infer(macro_call.syntax())?; let macro_call = InFile::new(sa.file_id, macro_call); - let file_id = sa.expand(self.db, macro_call)?; + let file_id = sa.expansion(self.db, macro_call)?; let node = self.parse_or_expand(file_id.into()); Some(node) @@ -437,7 +437,7 @@ impl<'db> SemanticsImpl<'db> { let sa = self.analyze_no_infer(macro_call.syntax())?; let macro_call = InFile::new(sa.file_id, macro_call); - let file_id = sa.expand(self.db, macro_call)?; + let file_id = sa.expansion(self.db, macro_call)?; let macro_call = self.db.lookup_intern_macro_call(file_id); let skip = matches!( @@ -576,7 +576,7 @@ impl<'db> SemanticsImpl<'db> { ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> { let analyzer = self.analyze_no_infer(actual_macro_call.syntax())?; let macro_call = InFile::new(analyzer.file_id, actual_macro_call); - let macro_file = analyzer.expansion(macro_call)?; + let macro_file = analyzer.expansion(self.db, macro_call)?; hir_expand::db::expand_speculative( self.db, macro_file, @@ -1120,7 +1120,7 @@ impl<'db> SemanticsImpl<'db> { false, ) })? - .expand(self.db, mcall.as_ref())?; + .expansion(self.db, mcall.as_ref())?; m_cache.insert(mcall, it); it } @@ -1579,7 +1579,7 @@ impl<'db> SemanticsImpl<'db> { let sa = self.analyze(macro_call.syntax())?; self.db .parse_macro_expansion( - sa.expand(self.db, self.wrap_node_infile(macro_call.clone()).as_ref())?, + sa.expansion(self.db, self.wrap_node_infile(macro_call.clone()).as_ref())?, ) .value .1 diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index ea21546f9d764..be581292152d0 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -26,7 +26,7 @@ use hir_def::{ }, hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat}, lang_item::LangItem, - nameres::{MacroSubNs, crate_def_map}, + nameres::{MacroSubNs, block_def_map, crate_def_map}, resolver::{HasResolver, Resolver, TypeNs, ValueNs, resolver_for_scope}, type_ref::{Mutability, TypeRefId}, }; @@ -218,8 +218,16 @@ impl<'db> SourceAnalyzer<'db> { }) } - pub(crate) fn expansion(&self, node: InFile<&ast::MacroCall>) -> Option { - self.store_sm()?.expansion(node) + pub(crate) fn expansion( + &self, + db: &dyn HirDatabase, + macro_call: InFile<&ast::MacroCall>, + ) -> Option { + self.store_sm().and_then(|sm| sm.expansion(macro_call)).or_else(|| { + let ast_id_map = db.ast_id_map(macro_call.file_id); + let call_ast_id = macro_call.with_value(ast_id_map.ast_id(macro_call.value)); + self.resolver.item_scopes().find_map(|scope| scope.macro_invoc(call_ast_id)) + }) } fn trait_environment(&self, db: &'db dyn HirDatabase) -> Arc { @@ -747,17 +755,16 @@ impl<'db> SourceAnalyzer<'db> { pub(crate) fn resolve_macro_call( &self, - db: &'db dyn HirDatabase, + db: &dyn HirDatabase, macro_call: InFile<&ast::MacroCall>, ) -> Option { - let bs = self.store_sm()?; - bs.expansion(macro_call).and_then(|it| { - // FIXME: Block def maps + self.expansion(db, macro_call).and_then(|it| { let def = it.lookup(db).def; - crate_def_map(db, def.krate) - .macro_def_to_macro_id - .get(&def.kind.erased_ast_id()) - .map(|it| (*it).into()) + let def_map = match def.block { + Some(block) => block_def_map(db, base_db::salsa::plumbing::FromId::from_id(block)), + None => crate_def_map(db, def.krate), + }; + def_map.macro_def_to_macro_id.get(&def.kind.erased_ast_id()).map(|it| (*it).into()) }) } @@ -1292,18 +1299,6 @@ impl<'db> SourceAnalyzer<'db> { .collect() } - pub(crate) fn expand( - &self, - db: &'db dyn HirDatabase, - macro_call: InFile<&ast::MacroCall>, - ) -> Option { - self.store_sm().and_then(|bs| bs.expansion(macro_call)).or_else(|| { - self.resolver.item_scope().macro_invoc( - macro_call.with_value(db.ast_id_map(macro_call.file_id).ast_id(macro_call.value)), - ) - }) - } - pub(crate) fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option { let infer = self.infer()?; let expr_id = self.expr_id(record_lit.into())?; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs index 55689034fb478..ed87b339fedf3 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs @@ -4,7 +4,7 @@ //! in [crate::completions::mod_]. use expect_test::expect; -use crate::tests::{check_edit, check_with_base_items}; +use crate::tests::{check, check_edit, check_with_base_items}; #[test] fn target_type_or_trait_in_impl_block() { @@ -308,3 +308,39 @@ fn bar() { "#]], ); } + +#[test] +fn expression_in_item_macro() { + check( + r#" +fn foo() -> u8 { 0 } + +macro_rules! foo { + ($expr:expr) => { + const BAR: u8 = $expr; + }; +} + +foo!(f$0); + "#, + expect![[r#" + ct BAR u8 + fn foo() fn() -> u8 + ma foo!(…) macro_rules! foo + bt u32 u32 + kw const + kw crate:: + kw false + kw for + kw if + kw if let + kw loop + kw match + kw self:: + kw true + kw unsafe + kw while + kw while let + "#]], + ); +} From 77e295c39c6bd4a29d310388219fc31b6cfc7136 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 25 May 2025 11:33:45 +0200 Subject: [PATCH 2754/4206] Improve `ambiguous_wide_pointer_comparisons` lint compare diagnostics --- compiler/rustc_lint/messages.ftl | 2 + compiler/rustc_lint/src/lints.rs | 110 ++++++++----- compiler/rustc_lint/src/types.rs | 52 +++--- tests/ui/lint/wide_pointer_comparisons.stderr | 150 +++++++++++++++--- 4 files changed, 226 insertions(+), 88 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 08180bf8f8b2c..999ae6360edbf 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -13,6 +13,8 @@ lint_ambiguous_negative_literals = `-` has lower precedence than method calls, w lint_ambiguous_wide_pointer_comparisons = ambiguous wide pointer comparison, the comparison includes metadata which may not be expected .addr_metadata_suggestion = use explicit `std::ptr::eq` method to compare metadata and addresses .addr_suggestion = use `std::ptr::addr_eq` or untyped pointers to only compare their addresses + .cast_suggestion = use untyped pointers to only compare their addresses + .expect_suggestion = or expect the lint to compare the pointers metadata and addresses lint_associated_const_elided_lifetime = {$elided -> [true] `&` without an explicit lifetime name cannot be used here diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 7268a7f704fcb..686d4e84fcecb 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1782,13 +1782,20 @@ pub(crate) enum InvalidNanComparisonsSuggestion { #[derive(LintDiagnostic)] pub(crate) enum AmbiguousWidePointerComparisons<'a> { #[diag(lint_ambiguous_wide_pointer_comparisons)] - Spanful { + SpanfulEq { #[subdiagnostic] addr_suggestion: AmbiguousWidePointerComparisonsAddrSuggestion<'a>, #[subdiagnostic] addr_metadata_suggestion: Option>, }, #[diag(lint_ambiguous_wide_pointer_comparisons)] + SpanfulCmp { + #[subdiagnostic] + cast_suggestion: AmbiguousWidePointerComparisonsCastSuggestion<'a>, + #[subdiagnostic] + expect_suggestion: AmbiguousWidePointerComparisonsExpectSuggestion<'a>, + }, + #[diag(lint_ambiguous_wide_pointer_comparisons)] #[help(lint_addr_metadata_suggestion)] #[help(lint_addr_suggestion)] Spanless, @@ -1816,48 +1823,67 @@ pub(crate) struct AmbiguousWidePointerComparisonsAddrMetadataSuggestion<'a> { } #[derive(Subdiagnostic)] -pub(crate) enum AmbiguousWidePointerComparisonsAddrSuggestion<'a> { - #[multipart_suggestion( - lint_addr_suggestion, - style = "verbose", - // FIXME(#53934): make machine-applicable again - applicability = "maybe-incorrect" - )] - AddrEq { - ne: &'a str, - deref_left: &'a str, - deref_right: &'a str, - l_modifiers: &'a str, - r_modifiers: &'a str, - #[suggestion_part(code = "{ne}std::ptr::addr_eq({deref_left}")] - left: Span, - #[suggestion_part(code = "{l_modifiers}, {deref_right}")] - middle: Span, - #[suggestion_part(code = "{r_modifiers})")] - right: Span, - }, - #[multipart_suggestion( - lint_addr_suggestion, - style = "verbose", - // FIXME(#53934): make machine-applicable again - applicability = "maybe-incorrect" +#[multipart_suggestion( + lint_addr_suggestion, + style = "verbose", + // FIXME(#53934): make machine-applicable again + applicability = "maybe-incorrect" +)] +pub(crate) struct AmbiguousWidePointerComparisonsAddrSuggestion<'a> { + pub(crate) ne: &'a str, + pub(crate) deref_left: &'a str, + pub(crate) deref_right: &'a str, + pub(crate) l_modifiers: &'a str, + pub(crate) r_modifiers: &'a str, + #[suggestion_part(code = "{ne}std::ptr::addr_eq({deref_left}")] + pub(crate) left: Span, + #[suggestion_part(code = "{l_modifiers}, {deref_right}")] + pub(crate) middle: Span, + #[suggestion_part(code = "{r_modifiers})")] + pub(crate) right: Span, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + lint_cast_suggestion, + style = "verbose", + // FIXME(#53934): make machine-applicable again + applicability = "maybe-incorrect" +)] +pub(crate) struct AmbiguousWidePointerComparisonsCastSuggestion<'a> { + pub(crate) deref_left: &'a str, + pub(crate) deref_right: &'a str, + pub(crate) paren_left: &'a str, + pub(crate) paren_right: &'a str, + pub(crate) l_modifiers: &'a str, + pub(crate) r_modifiers: &'a str, + #[suggestion_part(code = "({deref_left}")] + pub(crate) left_before: Option, + #[suggestion_part(code = "{l_modifiers}{paren_left}.cast::<()>()")] + pub(crate) left_after: Span, + #[suggestion_part(code = "({deref_right}")] + pub(crate) right_before: Option, + #[suggestion_part(code = "{r_modifiers}{paren_right}.cast::<()>()")] + pub(crate) right_after: Span, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + lint_expect_suggestion, + style = "verbose", + // FIXME(#53934): make machine-applicable again + applicability = "maybe-incorrect" +)] +pub(crate) struct AmbiguousWidePointerComparisonsExpectSuggestion<'a> { + pub(crate) paren_left: &'a str, + pub(crate) paren_right: &'a str, + // FIXME(#127436): Adjust once resolved + #[suggestion_part( + code = r#"{{ #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] {paren_left}"# )] - Cast { - deref_left: &'a str, - deref_right: &'a str, - paren_left: &'a str, - paren_right: &'a str, - l_modifiers: &'a str, - r_modifiers: &'a str, - #[suggestion_part(code = "({deref_left}")] - left_before: Option, - #[suggestion_part(code = "{l_modifiers}{paren_left}.cast::<()>()")] - left_after: Span, - #[suggestion_part(code = "({deref_right}")] - right_before: Option, - #[suggestion_part(code = "{r_modifiers}{paren_right}.cast::<()>()")] - right_after: Span, - }, + pub(crate) before: Span, + #[suggestion_part(code = "{paren_right} }}")] + pub(crate) after: Span, } #[derive(LintDiagnostic)] diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index f1c06dfe6ce0e..af134622d38cb 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -24,7 +24,8 @@ mod improper_ctypes; use crate::lints::{ AmbiguousWidePointerComparisons, AmbiguousWidePointerComparisonsAddrMetadataSuggestion, - AmbiguousWidePointerComparisonsAddrSuggestion, AtomicOrderingFence, AtomicOrderingLoad, + AmbiguousWidePointerComparisonsAddrSuggestion, AmbiguousWidePointerComparisonsCastSuggestion, + AmbiguousWidePointerComparisonsExpectSuggestion, AtomicOrderingFence, AtomicOrderingLoad, AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, InvalidNanComparisons, InvalidNanComparisonsSuggestion, UnpredictableFunctionPointerComparisons, UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons, UsesPowerAlignment, @@ -362,6 +363,7 @@ fn lint_wide_pointer<'tcx>( let ne = if cmpop == ComparisonOp::BinOp(hir::BinOpKind::Ne) { "!" } else { "" }; let is_eq_ne = matches!(cmpop, ComparisonOp::BinOp(hir::BinOpKind::Eq | hir::BinOpKind::Ne)); let is_dyn_comparison = l_inner_ty_is_dyn && r_inner_ty_is_dyn; + let via_method_call = matches!(&e.kind, ExprKind::MethodCall(..) | ExprKind::Call(..)); let left = e.span.shrink_to_lo().until(l_span.shrink_to_lo()); let middle = l_span.shrink_to_hi().until(r_span.shrink_to_lo()); @@ -376,21 +378,21 @@ fn lint_wide_pointer<'tcx>( cx.emit_span_lint( AMBIGUOUS_WIDE_POINTER_COMPARISONS, e.span, - AmbiguousWidePointerComparisons::Spanful { - addr_metadata_suggestion: (is_eq_ne && !is_dyn_comparison).then(|| { - AmbiguousWidePointerComparisonsAddrMetadataSuggestion { - ne, - deref_left, - deref_right, - l_modifiers, - r_modifiers, - left, - middle, - right, - } - }), - addr_suggestion: if is_eq_ne { - AmbiguousWidePointerComparisonsAddrSuggestion::AddrEq { + if is_eq_ne { + AmbiguousWidePointerComparisons::SpanfulEq { + addr_metadata_suggestion: (!is_dyn_comparison).then(|| { + AmbiguousWidePointerComparisonsAddrMetadataSuggestion { + ne, + deref_left, + deref_right, + l_modifiers, + r_modifiers, + left, + middle, + right, + } + }), + addr_suggestion: AmbiguousWidePointerComparisonsAddrSuggestion { ne, deref_left, deref_right, @@ -399,9 +401,11 @@ fn lint_wide_pointer<'tcx>( left, middle, right, - } - } else { - AmbiguousWidePointerComparisonsAddrSuggestion::Cast { + }, + } + } else { + AmbiguousWidePointerComparisons::SpanfulCmp { + cast_suggestion: AmbiguousWidePointerComparisonsCastSuggestion { deref_left, deref_right, l_modifiers, @@ -412,8 +416,14 @@ fn lint_wide_pointer<'tcx>( left_after: l_span.shrink_to_hi(), right_before: (r_ty_refs != 0).then_some(r_span.shrink_to_lo()), right_after: r_span.shrink_to_hi(), - } - }, + }, + expect_suggestion: AmbiguousWidePointerComparisonsExpectSuggestion { + paren_left: if via_method_call { "" } else { "(" }, + paren_right: if via_method_call { "" } else { ")" }, + before: e.span.shrink_to_lo(), + after: e.span.shrink_to_hi(), + }, + } }, ); } diff --git a/tests/ui/lint/wide_pointer_comparisons.stderr b/tests/ui/lint/wide_pointer_comparisons.stderr index 5a0b914d8320e..4f5238e8252f5 100644 --- a/tests/ui/lint/wide_pointer_comparisons.stderr +++ b/tests/ui/lint/wide_pointer_comparisons.stderr @@ -29,10 +29,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a < b; | ^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = a.cast::<()>() < b.cast::<()>(); | +++++++++++++ +++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] (a < b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:26:13 @@ -40,10 +44,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a <= b; | ^^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = a.cast::<()>() <= b.cast::<()>(); | +++++++++++++ +++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] (a <= b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:28:13 @@ -51,10 +59,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a > b; | ^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = a.cast::<()>() > b.cast::<()>(); | +++++++++++++ +++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] (a > b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:30:13 @@ -62,10 +74,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a >= b; | ^^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = a.cast::<()>() >= b.cast::<()>(); | +++++++++++++ +++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] (a >= b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:33:13 @@ -121,10 +137,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a.cmp(&b); | ^^^^^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = a.cast::<()>().cmp(&b.cast::<()>()); | +++++++++++++ +++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] a.cmp(&b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:43:13 @@ -132,10 +152,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a.partial_cmp(&b); | ^^^^^^^^^^^^^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = a.cast::<()>().partial_cmp(&b.cast::<()>()); | +++++++++++++ +++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] a.partial_cmp(&b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:45:13 @@ -143,10 +167,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a.le(&b); | ^^^^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = a.cast::<()>().le(&b.cast::<()>()); | +++++++++++++ +++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] a.le(&b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:47:13 @@ -154,10 +182,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a.lt(&b); | ^^^^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = a.cast::<()>().lt(&b.cast::<()>()); | +++++++++++++ +++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] a.lt(&b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:49:13 @@ -165,10 +197,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a.ge(&b); | ^^^^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = a.cast::<()>().ge(&b.cast::<()>()); | +++++++++++++ +++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] a.ge(&b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:51:13 @@ -176,10 +212,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a.gt(&b); | ^^^^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = a.cast::<()>().gt(&b.cast::<()>()); | +++++++++++++ +++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] a.gt(&b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:57:17 @@ -199,10 +239,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a >= b; | ^^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = a.as_ptr().cast::<()>() >= b.as_ptr().cast::<()>(); | ++++++++++++++++++++++ ++++++++++++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] (a >= b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:61:17 @@ -246,10 +290,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a < b; | ^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = (*a).cast::<()>() < (*b).cast::<()>(); | ++ ++++++++++++++ ++ ++++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] (a < b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:76:17 @@ -257,10 +305,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a <= b; | ^^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = (*a).cast::<()>() <= (*b).cast::<()>(); | ++ ++++++++++++++ ++ ++++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] (a <= b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:78:17 @@ -268,10 +320,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a > b; | ^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = (*a).cast::<()>() > (*b).cast::<()>(); | ++ ++++++++++++++ ++ ++++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] (a > b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:80:17 @@ -279,10 +335,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a >= b; | ^^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = (*a).cast::<()>() >= (*b).cast::<()>(); | ++ ++++++++++++++ ++ ++++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] (a >= b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:83:17 @@ -362,10 +422,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a.cmp(&b); | ^^^^^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = (*a).cast::<()>().cmp(&(*b).cast::<()>()); | ++ ++++++++++++++ ++ ++++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] a.cmp(&b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:97:17 @@ -373,10 +437,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a.partial_cmp(&b); | ^^^^^^^^^^^^^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = (*a).cast::<()>().partial_cmp(&(*b).cast::<()>()); | ++ ++++++++++++++ ++ ++++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] a.partial_cmp(&b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:99:17 @@ -384,10 +452,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a.le(&b); | ^^^^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = (*a).cast::<()>().le(&(*b).cast::<()>()); | ++ ++++++++++++++ ++ ++++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] a.le(&b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:101:17 @@ -395,10 +467,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a.lt(&b); | ^^^^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = (*a).cast::<()>().lt(&(*b).cast::<()>()); | ++ ++++++++++++++ ++ ++++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] a.lt(&b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:103:17 @@ -406,10 +482,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a.ge(&b); | ^^^^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = (*a).cast::<()>().ge(&(*b).cast::<()>()); | ++ ++++++++++++++ ++ ++++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] a.ge(&b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:105:17 @@ -417,10 +497,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a.gt(&b); | ^^^^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = (*a).cast::<()>().gt(&(*b).cast::<()>()); | ++ ++++++++++++++ ++ ++++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] a.gt(&b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:110:13 @@ -496,10 +580,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a < b; | ^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = a.cast::<()>() < b.cast::<()>(); | +++++++++++++ +++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] (a < b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:124:17 @@ -507,10 +595,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a <= b; | ^^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = a.cast::<()>() <= b.cast::<()>(); | +++++++++++++ +++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] (a <= b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:126:17 @@ -518,10 +610,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a > b; | ^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = a.cast::<()>() > b.cast::<()>(); | +++++++++++++ +++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] (a > b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:128:17 @@ -529,10 +625,14 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi LL | let _ = a >= b; | ^^^^^^ | -help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses +help: use untyped pointers to only compare their addresses | LL | let _ = a.cast::<()>() >= b.cast::<()>(); | +++++++++++++ +++++++++++++ +help: or expect the lint to compare the pointers metadata and addresses + | +LL | let _ = { #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] (a >= b) }; + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected --> $DIR/wide_pointer_comparisons.rs:131:17 From a8ae2af9670635a9138429ccba1ffb76787afbb1 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 25 May 2025 14:32:47 +0000 Subject: [PATCH 2755/4206] hir_body_const_context should take LocalDefId --- compiler/rustc_middle/src/hir/map.rs | 2 +- compiler/rustc_middle/src/mir/pretty.rs | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index fee707f7b4c90..9c8f1c9eccf30 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -310,7 +310,7 @@ impl<'tcx> TyCtxt<'tcx> { /// This should only be used for determining the context of a body, a return /// value of `Some` does not always suggest that the owner of the body is `const`, /// just that it has to be checked as if it were. - pub fn hir_body_const_context(self, def_id: impl Into) -> Option { + pub fn hir_body_const_context(self, def_id: LocalDefId) -> Option { let def_id = def_id.into(); let ccx = match self.hir_body_owner_kind(def_id) { BodyOwnerKind::Const { inline } => ConstContext::Const { inline }, diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 57ae7dc55c5c8..6b262a2750059 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1624,7 +1624,11 @@ pub fn write_allocations<'tcx>( Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => { write!(w, " (static: {}", tcx.def_path_str(did))?; if body.phase <= MirPhase::Runtime(RuntimePhase::PostCleanup) - && tcx.hir_body_const_context(body.source.def_id()).is_some() + && body + .source + .def_id() + .as_local() + .is_some_and(|def_id| tcx.hir_body_const_context(def_id).is_some()) { // Statics may be cyclic and evaluating them too early // in the MIR pipeline may cause cycle errors even though From 5370c5753f3f769d27832f81ceefd4141ba1ee0c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 25 May 2025 15:05:22 +0000 Subject: [PATCH 2756/4206] Make PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS into a HIR lint --- compiler/rustc_lint/messages.ftl | 5 + compiler/rustc_lint/src/lib.rs | 3 + compiler/rustc_lint/src/transmute.rs | 102 ++++++++++++++++++ compiler/rustc_lint_defs/src/builtin.rs | 35 ------ compiler/rustc_mir_transform/messages.ftl | 5 - .../src/check_undefined_transmutes.rs | 77 ------------- compiler/rustc_mir_transform/src/errors.rs | 7 -- compiler/rustc_mir_transform/src/lib.rs | 2 - ...-to-int-transmute-in-consts-issue-87525.rs | 25 ++--- ...int-transmute-in-consts-issue-87525.stderr | 40 +++---- 10 files changed, 136 insertions(+), 165 deletions(-) create mode 100644 compiler/rustc_lint/src/transmute.rs delete mode 100644 compiler/rustc_mir_transform/src/check_undefined_transmutes.rs diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 7fdf26bf3af99..9bef1c5b877b3 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -805,6 +805,11 @@ lint_type_ir_inherent_usage = do not use `rustc_type_ir::inherent` unless you're lint_type_ir_trait_usage = do not use `rustc_type_ir::Interner` or `rustc_type_ir::InferCtxtLike` unless you're inside of the trait solver .note = the method or struct you're looking for is likely defined somewhere else downstream in the compiler +lint_undefined_transmute = pointers cannot be transmuted to integers during const eval + .note = at compile-time, pointers do not have an integer value + .note2 = avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior + .help = for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html + lint_undropped_manually_drops = calls to `std::mem::drop` with `std::mem::ManuallyDrop` instead of the inner value does nothing .label = argument has type `{$arg_ty}` .suggestion = use `std::mem::ManuallyDrop::into_inner` to get the inner value diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 4ff586a79a6ec..e1c981b09e609 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -75,6 +75,7 @@ mod reference_casting; mod shadowed_into_iter; mod static_mut_refs; mod traits; +mod transmute; mod types; mod unit_bindings; mod unqualified_local_imports; @@ -118,6 +119,7 @@ use shadowed_into_iter::ShadowedIntoIter; pub use shadowed_into_iter::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER}; use static_mut_refs::*; use traits::*; +use transmute::CheckTransmutes; use types::*; use unit_bindings::*; use unqualified_local_imports::*; @@ -245,6 +247,7 @@ late_lint_methods!( IfLetRescope: IfLetRescope::default(), StaticMutRefs: StaticMutRefs, UnqualifiedLocalImports: UnqualifiedLocalImports, + CheckTransmutes: CheckTransmutes, ] ] ); diff --git a/compiler/rustc_lint/src/transmute.rs b/compiler/rustc_lint/src/transmute.rs new file mode 100644 index 0000000000000..8395bcf7cad68 --- /dev/null +++ b/compiler/rustc_lint/src/transmute.rs @@ -0,0 +1,102 @@ +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{self as hir}; +use rustc_macros::LintDiagnostic; +use rustc_session::{declare_lint, impl_lint_pass}; +use rustc_span::sym; + +use crate::{LateContext, LateLintPass}; + +declare_lint! { + /// The `ptr_to_integer_transmute_in_consts` lint detects pointer to integer + /// transmute in const functions and associated constants. + /// + /// ### Example + /// + /// ```rust + /// const fn foo(ptr: *const u8) -> usize { + /// unsafe { + /// std::mem::transmute::<*const u8, usize>(ptr) + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Transmuting pointers to integers in a `const` context is undefined behavior. + /// Any attempt to use the resulting integer will abort const-evaluation. + /// + /// But sometimes the compiler might not emit an error for pointer to integer transmutes + /// inside const functions and associated consts because they are evaluated only when referenced. + /// Therefore, this lint serves as an extra layer of defense to prevent any undefined behavior + /// from compiling without any warnings or errors. + /// + /// See [std::mem::transmute] in the reference for more details. + /// + /// [std::mem::transmute]: https://doc.rust-lang.org/std/mem/fn.transmute.html + pub PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS, + Warn, + "detects pointer to integer transmutes in const functions and associated constants", +} + +pub(crate) struct CheckTransmutes; + +impl_lint_pass!(CheckTransmutes => [PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS]); + +impl<'tcx> LateLintPass<'tcx> for CheckTransmutes { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { + let hir::ExprKind::Call(callee, _) = expr.kind else { + return; + }; + let hir::ExprKind::Path(qpath) = callee.kind else { + return; + }; + let Res::Def(DefKind::Fn, def_id) = cx.qpath_res(&qpath, callee.hir_id) else { + return; + }; + if !cx.tcx.is_intrinsic(def_id, sym::transmute) { + return; + }; + let body_owner_def_id = cx.tcx.hir_enclosing_body_owner(expr.hir_id); + let Some(context) = cx.tcx.hir_body_const_context(body_owner_def_id) else { + return; + }; + let args = cx.typeck_results().node_args(callee.hir_id); + + let src = args.type_at(0); + let dst = args.type_at(1); + + // Check for transmutes that exhibit undefined behavior. + // For example, transmuting pointers to integers in a const context. + // + // Why do we consider const functions and associated constants only? + // + // Generally, undefined behavior in const items are handled by the evaluator. + // But, const functions and associated constants are evaluated only when referenced. + // This can result in undefined behavior in a library going unnoticed until + // the function or constant is actually used. + // + // Therefore, we only consider const functions and associated constants here and leave + // other const items to be handled by the evaluator. + if matches!(context, hir::ConstContext::ConstFn) + || matches!(cx.tcx.def_kind(body_owner_def_id), DefKind::AssocConst) + { + if src.is_raw_ptr() && dst.is_integral() { + cx.tcx.emit_node_span_lint( + PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS, + expr.hir_id, + expr.span, + UndefinedTransmuteLint, + ); + } + } + } +} + +#[derive(LintDiagnostic)] +#[diag(lint_undefined_transmute)] +#[note] +#[note(lint_note2)] +#[help] +pub(crate) struct UndefinedTransmuteLint; diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index b8d242bad86ac..2e1aaeedba1b2 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -79,7 +79,6 @@ declare_lint_pass! { PRIVATE_BOUNDS, PRIVATE_INTERFACES, PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, - PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, REDUNDANT_IMPORTS, REDUNDANT_LIFETIMES, @@ -4851,40 +4850,6 @@ declare_lint! { @feature_gate = supertrait_item_shadowing; } -declare_lint! { - /// The `ptr_to_integer_transmute_in_consts` lint detects pointer to integer - /// transmute in const functions and associated constants. - /// - /// ### Example - /// - /// ```rust - /// const fn foo(ptr: *const u8) -> usize { - /// unsafe { - /// std::mem::transmute::<*const u8, usize>(ptr) - /// } - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// Transmuting pointers to integers in a `const` context is undefined behavior. - /// Any attempt to use the resulting integer will abort const-evaluation. - /// - /// But sometimes the compiler might not emit an error for pointer to integer transmutes - /// inside const functions and associated consts because they are evaluated only when referenced. - /// Therefore, this lint serves as an extra layer of defense to prevent any undefined behavior - /// from compiling without any warnings or errors. - /// - /// See [std::mem::transmute] in the reference for more details. - /// - /// [std::mem::transmute]: https://doc.rust-lang.org/std/mem/fn.transmute.html - pub PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS, - Warn, - "detects pointer to integer transmutes in const functions and associated constants", -} - declare_lint! { /// The `unnecessary_transmutes` lint detects transmutations that have safer alternatives. /// diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl index a1264471a2df5..ada705a5163da 100644 --- a/compiler/rustc_mir_transform/messages.ftl +++ b/compiler/rustc_mir_transform/messages.ftl @@ -78,10 +78,5 @@ mir_transform_unconditional_recursion = function cannot return without recursing mir_transform_unconditional_recursion_call_site_label = recursive call site -mir_transform_undefined_transmute = pointers cannot be transmuted to integers during const eval - .note = at compile-time, pointers do not have an integer value - .note2 = avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior - .help = for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html - mir_transform_unknown_pass_name = MIR pass `{$name}` is unknown and will be ignored mir_transform_unnecessary_transmute = unnecessary transmute diff --git a/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs b/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs deleted file mode 100644 index daddb5dedbcf9..0000000000000 --- a/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs +++ /dev/null @@ -1,77 +0,0 @@ -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{Body, Location, Operand, Terminator, TerminatorKind}; -use rustc_middle::ty::{AssocItem, AssocKind, TyCtxt}; -use rustc_session::lint::builtin::PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS; -use rustc_span::sym; - -use crate::errors; - -/// Check for transmutes that exhibit undefined behavior. -/// For example, transmuting pointers to integers in a const context. -pub(super) struct CheckUndefinedTransmutes; - -impl<'tcx> crate::MirLint<'tcx> for CheckUndefinedTransmutes { - fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { - let mut checker = UndefinedTransmutesChecker { body, tcx }; - checker.visit_body(body); - } -} - -struct UndefinedTransmutesChecker<'a, 'tcx> { - body: &'a Body<'tcx>, - tcx: TyCtxt<'tcx>, -} - -impl<'a, 'tcx> UndefinedTransmutesChecker<'a, 'tcx> { - // This functions checks two things: - // 1. `function` takes a raw pointer as input and returns an integer as output. - // 2. `function` is called from a const function or an associated constant. - // - // Why do we consider const functions and associated constants only? - // - // Generally, undefined behavior in const items are handled by the evaluator. - // But, const functions and associated constants are evaluated only when referenced. - // This can result in undefined behavior in a library going unnoticed until - // the function or constant is actually used. - // - // Therefore, we only consider const functions and associated constants here and leave - // other const items to be handled by the evaluator. - fn is_ptr_to_int_in_const(&self, function: &Operand<'tcx>) -> bool { - let def_id = self.body.source.def_id(); - - if self.tcx.is_const_fn(def_id) - || matches!( - self.tcx.opt_associated_item(def_id), - Some(AssocItem { kind: AssocKind::Const { .. }, .. }) - ) - { - let fn_sig = function.ty(self.body, self.tcx).fn_sig(self.tcx).skip_binder(); - if let [input] = fn_sig.inputs() { - return input.is_raw_ptr() && fn_sig.output().is_integral(); - } - } - false - } -} - -impl<'tcx> Visitor<'tcx> for UndefinedTransmutesChecker<'_, 'tcx> { - // Check each block's terminator for calls to pointer to integer transmutes - // in const functions or associated constants and emit a lint. - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - if let TerminatorKind::Call { func, .. } = &terminator.kind - && let Some((func_def_id, _)) = func.const_fn_def() - && self.tcx.is_intrinsic(func_def_id, sym::transmute) - && self.is_ptr_to_int_in_const(func) - && let Some(call_id) = self.body.source.def_id().as_local() - { - let hir_id = self.tcx.local_def_id_to_hir_id(call_id); - let span = self.body.source_info(location).span; - self.tcx.emit_node_span_lint( - PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS, - hir_id, - span, - errors::UndefinedTransmute, - ); - } - } -} diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 5b03a4987ed71..9777cb56f13a1 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -178,13 +178,6 @@ impl<'a> LintDiagnostic<'a, ()> for UnnecessaryTransmute { } } -#[derive(LintDiagnostic)] -#[diag(mir_transform_undefined_transmute)] -#[note] -#[note(mir_transform_note2)] -#[help] -pub(crate) struct UndefinedTransmute; - #[derive(Diagnostic)] #[diag(mir_transform_force_inline)] #[note] diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 10dbb3437dcbf..8d4e9e30f4fae 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -123,7 +123,6 @@ declare_passes! { mod check_const_item_mutation : CheckConstItemMutation; mod check_null : CheckNull; mod check_packed_ref : CheckPackedRef; - mod check_undefined_transmutes : CheckUndefinedTransmutes; mod check_unnecessary_transmutes: CheckUnnecessaryTransmutes; // This pass is public to allow external drivers to perform MIR cleanup pub mod cleanup_post_borrowck : CleanupPostBorrowck; @@ -390,7 +389,6 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal> { &Lint(check_packed_ref::CheckPackedRef), &Lint(check_const_item_mutation::CheckConstItemMutation), &Lint(function_item_references::FunctionItemReferences), - &Lint(check_undefined_transmutes::CheckUndefinedTransmutes), &Lint(check_unnecessary_transmutes::CheckUnnecessaryTransmutes), // What we need to do constant evaluation. &simplify::SimplifyCfg::Initial, diff --git a/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.rs b/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.rs index 19c78f019aab7..5fab075785aab 100644 --- a/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.rs +++ b/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.rs @@ -1,7 +1,9 @@ +#![deny(ptr_to_integer_transmute_in_consts)] + const fn foo(ptr: *const u8) -> usize { unsafe { std::mem::transmute(ptr) - //~^ WARN pointers cannot be transmuted to integers + //~^ ERROR pointers cannot be transmuted to integers } } @@ -11,7 +13,7 @@ trait Human { let ptr: *const usize = &value; unsafe { std::mem::transmute(ptr) - //~^ WARN pointers cannot be transmuted to integers + //~^ ERROR pointers cannot be transmuted to integers } }; @@ -28,7 +30,7 @@ impl Type { let ptr: *const usize = &value; unsafe { std::mem::transmute(ptr) - //~^ WARN pointers cannot be transmuted to integers + //~^ ERROR pointers cannot be transmuted to integers } }; @@ -38,9 +40,7 @@ impl Type { } fn control(ptr: *const u8) -> usize { - unsafe { - std::mem::transmute(ptr) - } + unsafe { std::mem::transmute(ptr) } } struct ControlStruct; @@ -49,22 +49,15 @@ impl ControlStruct { fn new() -> usize { let value = 10; let ptr: *const i32 = &value; - unsafe { - std::mem::transmute(ptr) - } + unsafe { std::mem::transmute(ptr) } } } - const fn zoom(ptr: *const u8) -> usize { unsafe { std::mem::transmute(ptr) - //~^ WARN pointers cannot be transmuted to integers + //~^ ERROR pointers cannot be transmuted to integers } } -fn main() { - const a: u8 = 10; - const value: usize = zoom(&a); - //~^ ERROR evaluation of constant value failed -} +fn main() {} diff --git a/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.stderr b/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.stderr index ca6ad9408ab91..2a9d9b5cb9629 100644 --- a/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.stderr +++ b/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.stderr @@ -1,5 +1,5 @@ -warning: pointers cannot be transmuted to integers during const eval - --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:61:9 +error: pointers cannot be transmuted to integers during const eval + --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:5:9 | LL | std::mem::transmute(ptr) | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,29 +7,24 @@ LL | std::mem::transmute(ptr) = note: at compile-time, pointers do not have an integer value = note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior = help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html - = note: `#[warn(ptr_to_integer_transmute_in_consts)]` on by default - -error[E0080]: evaluation of constant value failed - --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:68:26 - | -LL | const value: usize = zoom(&a); - | ^^^^^^^^ unable to turn pointer into integer +note: the lint level is defined here + --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:1:9 | - = help: this code performed an operation that depends on the underlying bytes representing a pointer - = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported +LL | #![deny(ptr_to_integer_transmute_in_consts)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: pointers cannot be transmuted to integers during const eval - --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:3:9 +error: pointers cannot be transmuted to integers during const eval + --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:15:13 | -LL | std::mem::transmute(ptr) - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | std::mem::transmute(ptr) + | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: at compile-time, pointers do not have an integer value = note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior = help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html -warning: pointers cannot be transmuted to integers during const eval - --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:13:13 +error: pointers cannot be transmuted to integers during const eval + --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:32:13 | LL | std::mem::transmute(ptr) | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -38,16 +33,15 @@ LL | std::mem::transmute(ptr) = note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior = help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html -warning: pointers cannot be transmuted to integers during const eval - --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:30:13 +error: pointers cannot be transmuted to integers during const eval + --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:58:9 | -LL | std::mem::transmute(ptr) - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | std::mem::transmute(ptr) + | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: at compile-time, pointers do not have an integer value = note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior = help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html -error: aborting due to 1 previous error; 4 warnings emitted +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0080`. From 295a8d56f5a7d200599d587fb52bf217b9aee363 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 25 May 2025 15:57:10 +0000 Subject: [PATCH 2757/4206] Make UNNECESSARY_TRANSMUTES into a HIR lint --- compiler/rustc_lint/src/transmute.rs | 232 +++++++++++++++--- compiler/rustc_lint_defs/src/builtin.rs | 25 -- compiler/rustc_mir_transform/messages.ftl | 1 - .../src/check_unnecessary_transmutes.rs | 136 ---------- compiler/rustc_mir_transform/src/errors.rs | 20 -- compiler/rustc_mir_transform/src/lib.rs | 2 - .../unnecessary-transmutation.stderr | 226 ++++++++++++----- 7 files changed, 374 insertions(+), 268 deletions(-) delete mode 100644 compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs diff --git a/compiler/rustc_lint/src/transmute.rs b/compiler/rustc_lint/src/transmute.rs index 8395bcf7cad68..bc1d4587d076e 100644 --- a/compiler/rustc_lint/src/transmute.rs +++ b/compiler/rustc_lint/src/transmute.rs @@ -1,6 +1,9 @@ +use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def_id::LocalDefId; use rustc_hir::{self as hir}; use rustc_macros::LintDiagnostic; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint, impl_lint_pass}; use rustc_span::sym; @@ -40,13 +43,37 @@ declare_lint! { "detects pointer to integer transmutes in const functions and associated constants", } +declare_lint! { + /// The `unnecessary_transmutes` lint detects transmutations that have safer alternatives. + /// + /// ### Example + /// + /// ```rust + /// fn bytes_at_home(x: [u8; 4]) -> u32 { + /// unsafe { std::mem::transmute(x) } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Using an explicit method is preferable over calls to + /// [`transmute`](https://doc.rust-lang.org/std/mem/fn.transmute.html) as + /// they more clearly communicate the intent, are easier to review, and + /// are less likely to accidentally result in unsoundness. + pub UNNECESSARY_TRANSMUTES, + Warn, + "detects transmutes that can also be achieved by other operations" +} + pub(crate) struct CheckTransmutes; -impl_lint_pass!(CheckTransmutes => [PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS]); +impl_lint_pass!(CheckTransmutes => [PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS, UNNECESSARY_TRANSMUTES]); impl<'tcx> LateLintPass<'tcx> for CheckTransmutes { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { - let hir::ExprKind::Call(callee, _) = expr.kind else { + let hir::ExprKind::Call(callee, [arg]) = expr.kind else { return; }; let hir::ExprKind::Path(qpath) = callee.kind else { @@ -59,41 +86,190 @@ impl<'tcx> LateLintPass<'tcx> for CheckTransmutes { return; }; let body_owner_def_id = cx.tcx.hir_enclosing_body_owner(expr.hir_id); - let Some(context) = cx.tcx.hir_body_const_context(body_owner_def_id) else { - return; - }; + let const_context = cx.tcx.hir_body_const_context(body_owner_def_id); let args = cx.typeck_results().node_args(callee.hir_id); let src = args.type_at(0); let dst = args.type_at(1); - // Check for transmutes that exhibit undefined behavior. - // For example, transmuting pointers to integers in a const context. - // - // Why do we consider const functions and associated constants only? - // - // Generally, undefined behavior in const items are handled by the evaluator. - // But, const functions and associated constants are evaluated only when referenced. - // This can result in undefined behavior in a library going unnoticed until - // the function or constant is actually used. - // - // Therefore, we only consider const functions and associated constants here and leave - // other const items to be handled by the evaluator. - if matches!(context, hir::ConstContext::ConstFn) - || matches!(cx.tcx.def_kind(body_owner_def_id), DefKind::AssocConst) - { - if src.is_raw_ptr() && dst.is_integral() { - cx.tcx.emit_node_span_lint( - PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS, - expr.hir_id, - expr.span, - UndefinedTransmuteLint, - ); - } + check_ptr_transmute_in_const(cx, expr, body_owner_def_id, const_context, src, dst); + check_unnecessary_transmute(cx, expr, callee, arg, const_context, src, dst); + } +} + +/// Check for transmutes that exhibit undefined behavior. +/// For example, transmuting pointers to integers in a const context. +/// +/// Why do we consider const functions and associated constants only? +/// +/// Generally, undefined behavior in const items are handled by the evaluator. +/// But, const functions and associated constants are evaluated only when referenced. +/// This can result in undefined behavior in a library going unnoticed until +/// the function or constant is actually used. +/// +/// Therefore, we only consider const functions and associated constants here and leave +/// other const items to be handled by the evaluator. +fn check_ptr_transmute_in_const<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + body_owner_def_id: LocalDefId, + const_context: Option, + src: Ty<'tcx>, + dst: Ty<'tcx>, +) { + if matches!(const_context, Some(hir::ConstContext::ConstFn)) + || matches!(cx.tcx.def_kind(body_owner_def_id), DefKind::AssocConst) + { + if src.is_raw_ptr() && dst.is_integral() { + cx.tcx.emit_node_span_lint( + PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS, + expr.hir_id, + expr.span, + UndefinedTransmuteLint, + ); } } } +/// Check for transmutes that overlap with stdlib methods. +/// For example, transmuting `[u8; 4]` to `u32`. +/// +/// We chose not to lint u8 -> bool transmutes, see #140431. +fn check_unnecessary_transmute<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + callee: &'tcx hir::Expr<'tcx>, + arg: &'tcx hir::Expr<'tcx>, + const_context: Option, + src: Ty<'tcx>, + dst: Ty<'tcx>, +) { + let callee_span = callee.span.find_ancestor_inside(expr.span).unwrap_or(callee.span); + let (sugg, help) = match (src.kind(), dst.kind()) { + // dont check the length; transmute does that for us. + // [u8; _] => primitive + (ty::Array(t, _), ty::Uint(_) | ty::Float(_) | ty::Int(_)) + if *t.kind() == ty::Uint(ty::UintTy::U8) => + { + ( + Some(vec![(callee_span, format!("{dst}::from_ne_bytes"))]), + Some( + "there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order", + ), + ) + } + // primitive => [u8; _] + (ty::Uint(_) | ty::Float(_) | ty::Int(_), ty::Array(t, _)) + if *t.kind() == ty::Uint(ty::UintTy::U8) => + { + ( + Some(vec![(callee_span, format!("{src}::to_ne_bytes"))]), + Some( + "there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order", + ), + ) + } + // char → u32 + (ty::Char, ty::Uint(ty::UintTy::U32)) => { + (Some(vec![(callee_span, "u32::from".to_string())]), None) + } + // char (→ u32) → i32 + (ty::Char, ty::Int(ty::IntTy::I32)) => ( + Some(vec![ + (callee_span, "u32::from".to_string()), + (expr.span.shrink_to_hi(), ".cast_signed()".to_string()), + ]), + None, + ), + // u32 → char + (ty::Uint(ty::UintTy::U32), ty::Char) => ( + Some(vec![(callee_span, "char::from_u32_unchecked".to_string())]), + Some("consider using `char::from_u32(…).unwrap()`"), + ), + // i32 → char + (ty::Int(ty::IntTy::I32), ty::Char) => ( + Some(vec![ + (callee_span, "char::from_u32_unchecked(i32::cast_unsigned".to_string()), + (expr.span.shrink_to_hi(), ")".to_string()), + ]), + Some("consider using `char::from_u32(i32::cast_unsigned(…)).unwrap()`"), + ), + // uNN → iNN + (ty::Uint(_), ty::Int(_)) => { + (Some(vec![(callee_span, format!("{src}::cast_signed"))]), None) + } + // iNN → uNN + (ty::Int(_), ty::Uint(_)) => { + (Some(vec![(callee_span, format!("{src}::cast_unsigned"))]), None) + } + // fNN → usize, isize + (ty::Float(_), ty::Uint(ty::UintTy::Usize) | ty::Int(ty::IntTy::Isize)) => ( + Some(vec![ + (callee_span, format!("{src}::to_bits")), + (expr.span.shrink_to_hi(), format!(" as {dst}")), + ]), + None, + ), + // fNN (→ uNN) → iNN + (ty::Float(_), ty::Int(..)) => ( + Some(vec![ + (callee_span, format!("{src}::to_bits")), + (expr.span.shrink_to_hi(), ".cast_signed()".to_string()), + ]), + None, + ), + // fNN → uNN + (ty::Float(_), ty::Uint(..)) => { + (Some(vec![(callee_span, format!("{src}::to_bits"))]), None) + } + // xsize → fNN + (ty::Uint(ty::UintTy::Usize) | ty::Int(ty::IntTy::Isize), ty::Float(_)) => ( + Some(vec![ + (callee_span, format!("{dst}::from_bits")), + (arg.span.shrink_to_hi(), " as _".to_string()), + ]), + None, + ), + // iNN (→ uNN) → fNN + (ty::Int(_), ty::Float(_)) => ( + Some(vec![ + (callee_span, format!("{dst}::from_bits({src}::cast_unsigned")), + (expr.span.shrink_to_hi(), ")".to_string()), + ]), + None, + ), + // uNN → fNN + (ty::Uint(_), ty::Float(_)) => { + (Some(vec![(callee_span, format!("{dst}::from_bits"))]), None) + } + // bool → x8 in const context since `From::from` is not const yet + // FIXME: Consider arg expr's precedence to avoid parentheses. + // FIXME(const_traits): Remove this when `From::from` is constified. + (ty::Bool, ty::Int(..) | ty::Uint(..)) if const_context.is_some() => ( + Some(vec![ + (callee_span, "".to_string()), + (expr.span.shrink_to_hi(), format!(" as {dst}")), + ]), + None, + ), + // bool → x8 using `x8::from` + (ty::Bool, ty::Int(..) | ty::Uint(..)) => { + (Some(vec![(callee_span, format!("{dst}::from"))]), None) + } + _ => return, + }; + + cx.tcx.node_span_lint(UNNECESSARY_TRANSMUTES, expr.hir_id, expr.span, |diag| { + diag.primary_message("unnecessary transmute"); + if let Some(sugg) = sugg { + diag.multipart_suggestion("replace this with", sugg, Applicability::MachineApplicable); + } + if let Some(help) = help { + diag.help(help); + } + }); +} + #[derive(LintDiagnostic)] #[diag(lint_undefined_transmute)] #[note] diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 2e1aaeedba1b2..abf4840a026cc 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -117,7 +117,6 @@ declare_lint_pass! { UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNNAMEABLE_TEST_ITEMS, UNNAMEABLE_TYPES, - UNNECESSARY_TRANSMUTES, UNREACHABLE_CODE, UNREACHABLE_PATTERNS, UNSAFE_ATTR_OUTSIDE_UNSAFE, @@ -4850,30 +4849,6 @@ declare_lint! { @feature_gate = supertrait_item_shadowing; } -declare_lint! { - /// The `unnecessary_transmutes` lint detects transmutations that have safer alternatives. - /// - /// ### Example - /// - /// ```rust - /// fn bytes_at_home(x: [u8; 4]) -> u32 { - /// unsafe { std::mem::transmute(x) } - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// Using an explicit method is preferable over calls to - /// [`transmute`](https://doc.rust-lang.org/std/mem/fn.transmute.html) as - /// they more clearly communicate the intent, are easier to review, and - /// are less likely to accidentally result in unsoundness. - pub UNNECESSARY_TRANSMUTES, - Warn, - "detects transmutes that are shadowed by std methods" -} - declare_lint! { /// The `tail_expr_drop_order` lint looks for those values generated at the tail expression location, /// that runs a custom `Drop` destructor. diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl index ada705a5163da..ae3062f07de9c 100644 --- a/compiler/rustc_mir_transform/messages.ftl +++ b/compiler/rustc_mir_transform/messages.ftl @@ -79,4 +79,3 @@ mir_transform_unconditional_recursion = function cannot return without recursing mir_transform_unconditional_recursion_call_site_label = recursive call site mir_transform_unknown_pass_name = MIR pass `{$name}` is unknown and will be ignored -mir_transform_unnecessary_transmute = unnecessary transmute diff --git a/compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs b/compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs deleted file mode 100644 index 1a3715465ad4e..0000000000000 --- a/compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs +++ /dev/null @@ -1,136 +0,0 @@ -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{Body, Location, Operand, Terminator, TerminatorKind}; -use rustc_middle::ty::*; -use rustc_session::lint::builtin::UNNECESSARY_TRANSMUTES; -use rustc_span::source_map::Spanned; -use rustc_span::{Span, sym}; - -use crate::errors::UnnecessaryTransmute as Error; - -/// Check for transmutes that overlap with stdlib methods. -/// For example, transmuting `[u8; 4]` to `u32`. -/// We chose not to lint u8 -> bool transmutes, see #140431 -pub(super) struct CheckUnnecessaryTransmutes; - -impl<'tcx> crate::MirLint<'tcx> for CheckUnnecessaryTransmutes { - fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { - let mut checker = UnnecessaryTransmuteChecker { body, tcx }; - checker.visit_body(body); - } -} - -struct UnnecessaryTransmuteChecker<'a, 'tcx> { - body: &'a Body<'tcx>, - tcx: TyCtxt<'tcx>, -} - -impl<'a, 'tcx> UnnecessaryTransmuteChecker<'a, 'tcx> { - fn is_unnecessary_transmute( - &self, - function: &Operand<'tcx>, - arg: String, - span: Span, - is_in_const: bool, - ) -> Option { - let fn_sig = function.ty(self.body, self.tcx).fn_sig(self.tcx).skip_binder(); - let [input] = fn_sig.inputs() else { return None }; - - let err = |sugg| Error { span, sugg, help: None }; - - Some(match (input.kind(), fn_sig.output().kind()) { - // dont check the length; transmute does that for us. - // [u8; _] => primitive - (Array(t, _), Uint(_) | Float(_) | Int(_)) if *t.kind() == Uint(UintTy::U8) => Error { - sugg: format!("{}::from_ne_bytes({arg})", fn_sig.output()), - help: Some( - "there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order", - ), - span, - }, - // primitive => [u8; _] - (Uint(_) | Float(_) | Int(_), Array(t, _)) if *t.kind() == Uint(UintTy::U8) => Error { - sugg: format!("{input}::to_ne_bytes({arg})"), - help: Some( - "there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order", - ), - span, - }, - // char → u32 - (Char, Uint(UintTy::U32)) => err(format!("u32::from({arg})")), - // char (→ u32) → i32 - (Char, Int(IntTy::I32)) => err(format!("u32::from({arg}).cast_signed()")), - // u32 → char - (Uint(UintTy::U32), Char) => Error { - sugg: format!("char::from_u32_unchecked({arg})"), - help: Some("consider `char::from_u32(…).unwrap()`"), - span, - }, - // i32 → char - (Int(IntTy::I32), Char) => Error { - sugg: format!("char::from_u32_unchecked(i32::cast_unsigned({arg}))"), - help: Some("consider `char::from_u32(i32::cast_unsigned(…)).unwrap()`"), - span, - }, - // uNN → iNN - (Uint(ty), Int(_)) => err(format!("{}::cast_signed({arg})", ty.name_str())), - // iNN → uNN - (Int(ty), Uint(_)) => err(format!("{}::cast_unsigned({arg})", ty.name_str())), - // fNN → xsize - (Float(ty), Uint(UintTy::Usize)) => { - err(format!("{}::to_bits({arg}) as usize", ty.name_str())) - } - (Float(ty), Int(IntTy::Isize)) => { - err(format!("{}::to_bits({arg}) as isize", ty.name_str())) - } - // fNN (→ uNN) → iNN - (Float(ty), Int(..)) => err(format!("{}::to_bits({arg}).cast_signed()", ty.name_str())), - // fNN → uNN - (Float(ty), Uint(..)) => err(format!("{}::to_bits({arg})", ty.name_str())), - // xsize → fNN - (Uint(UintTy::Usize) | Int(IntTy::Isize), Float(ty)) => { - err(format!("{}::from_bits({arg} as _)", ty.name_str(),)) - } - // iNN (→ uNN) → fNN - (Int(int_ty), Float(ty)) => err(format!( - "{}::from_bits({}::cast_unsigned({arg}))", - ty.name_str(), - int_ty.name_str() - )), - // uNN → fNN - (Uint(_), Float(ty)) => err(format!("{}::from_bits({arg})", ty.name_str())), - // bool → { x8 } in const context since `From::from` is not const yet - // FIXME: is it possible to know when the parentheses arent necessary? - // FIXME(const_traits): Remove this when From::from is constified? - (Bool, Int(..) | Uint(..)) if is_in_const => { - err(format!("({arg}) as {}", fn_sig.output())) - } - // " using `x8::from` - (Bool, Int(..) | Uint(..)) => err(format!("{}::from({arg})", fn_sig.output())), - _ => return None, - }) - } -} - -impl<'tcx> Visitor<'tcx> for UnnecessaryTransmuteChecker<'_, 'tcx> { - // Check each block's terminator for calls to pointer to integer transmutes - // in const functions or associated constants and emit a lint. - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - if let TerminatorKind::Call { func, args, .. } = &terminator.kind - && let [Spanned { span: arg, .. }] = **args - && let Some((func_def_id, _)) = func.const_fn_def() - && self.tcx.is_intrinsic(func_def_id, sym::transmute) - && let span = self.body.source_info(location).span - && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(arg) - && let def_id = self.body.source.def_id() - && let Some(lint) = self.is_unnecessary_transmute( - func, - snippet, - span, - self.tcx.hir_body_const_context(def_id.expect_local()).is_some(), - ) - && let Some(hir_id) = terminator.source_info.scope.lint_root(&self.body.source_scopes) - { - self.tcx.emit_node_span_lint(UNNECESSARY_TRANSMUTES, hir_id, span, lint); - } - } -} diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 9777cb56f13a1..cffa0183fa7a5 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -158,26 +158,6 @@ pub(crate) struct MustNotSuspendReason { pub reason: String, } -pub(crate) struct UnnecessaryTransmute { - pub span: Span, - pub sugg: String, - pub help: Option<&'static str>, -} - -// Needed for def_path_str -impl<'a> LintDiagnostic<'a, ()> for UnnecessaryTransmute { - fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::Diag<'a, ()>) { - diag.primary_message(fluent::mir_transform_unnecessary_transmute); - diag.span_suggestion( - self.span, - "replace this with", - self.sugg, - lint::Applicability::MachineApplicable, - ); - self.help.map(|help| diag.help(help)); - } -} - #[derive(Diagnostic)] #[diag(mir_transform_force_inline)] #[note] diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 8d4e9e30f4fae..d26e44687157b 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -123,7 +123,6 @@ declare_passes! { mod check_const_item_mutation : CheckConstItemMutation; mod check_null : CheckNull; mod check_packed_ref : CheckPackedRef; - mod check_unnecessary_transmutes: CheckUnnecessaryTransmutes; // This pass is public to allow external drivers to perform MIR cleanup pub mod cleanup_post_borrowck : CleanupPostBorrowck; @@ -389,7 +388,6 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal> { &Lint(check_packed_ref::CheckPackedRef), &Lint(check_const_item_mutation::CheckConstItemMutation), &Lint(function_item_references::FunctionItemReferences), - &Lint(check_unnecessary_transmutes::CheckUnnecessaryTransmutes), // What we need to do constant evaluation. &simplify::SimplifyCfg::Initial, &Lint(sanity_check::SanityCheck), diff --git a/tests/ui/transmute/unnecessary-transmutation.stderr b/tests/ui/transmute/unnecessary-transmutation.stderr index 602e964f5b2bd..0132ac4776be7 100644 --- a/tests/ui/transmute/unnecessary-transmutation.stderr +++ b/tests/ui/transmute/unnecessary-transmutation.stderr @@ -1,9 +1,12 @@ error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:16:29 + --> $DIR/unnecessary-transmutation.rs:7:14 | -LL | pub static X: u8 = unsafe { transmute(true) }; - | ^^^^^^^^^^^^^^^ help: replace this with: `(true) as u8` +LL | unsafe { transmute(x) } + | ---------^^^ + | | + | help: replace this with: `u32::to_ne_bytes` | + = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order note: the lint level is defined here --> $DIR/unnecessary-transmutation.rs:2:9 | @@ -11,36 +14,72 @@ LL | #![deny(unnecessary_transmutes)] | ^^^^^^^^^^^^^^^^^^^^^^ error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:18:28 + --> $DIR/unnecessary-transmutation.rs:12:14 + | +LL | unsafe { transmute(from) } + | ^^^^^^^^^^^^^^^ + | +help: replace this with + | +LL - unsafe { transmute(from) } +LL + unsafe { (from) as u8 } | -LL | pub const Y: u8 = unsafe { transmute(true) }; - | ^^^^^^^^^^^^^^^ help: replace this with: `(true) as u8` error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:7:14 + --> $DIR/unnecessary-transmutation.rs:16:29 | -LL | unsafe { transmute(x) } - | ^^^^^^^^^^^^ help: replace this with: `u32::to_ne_bytes(x)` +LL | pub static X: u8 = unsafe { transmute(true) }; + | ^^^^^^^^^^^^^^^ + | +help: replace this with + | +LL - pub static X: u8 = unsafe { transmute(true) }; +LL + pub static X: u8 = unsafe { (true) as u8 }; | - = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:12:14 + --> $DIR/unnecessary-transmutation.rs:18:28 + | +LL | pub const Y: u8 = unsafe { transmute(true) }; + | ^^^^^^^^^^^^^^^ + | +help: replace this with + | +LL - pub const Y: u8 = unsafe { transmute(true) }; +LL + pub const Y: u8 = unsafe { (true) as u8 }; | -LL | unsafe { transmute(from) } - | ^^^^^^^^^^^^^^^ help: replace this with: `(from) as u8` error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:24:18 | LL | unsafe { transmute(x) } - | ^^^^^^^^^^^^ help: replace this with: `(x) as u8` + | ^^^^^^^^^^^^ + | +help: replace this with + | +LL - unsafe { transmute(x) } +LL + unsafe { (x) as u8 } + | + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:30:22 + | +LL | const { unsafe { transmute::<_, u8>(true) } }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace this with + | +LL - const { unsafe { transmute::<_, u8>(true) } }; +LL + const { unsafe { (true) as u8 } }; + | error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:33:22 | LL | let x: u16 = transmute(*b"01"); - | ^^^^^^^^^^^^^^^^^ help: replace this with: `u16::from_ne_bytes(*b"01")` + | ---------^^^^^^^^ + | | + | help: replace this with: `u16::from_ne_bytes` | = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order @@ -48,7 +87,9 @@ error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:35:26 | LL | let x: [u8; 2] = transmute(x); - | ^^^^^^^^^^^^ help: replace this with: `u16::to_ne_bytes(x)` + | ---------^^^ + | | + | help: replace this with: `u16::to_ne_bytes` | = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order @@ -56,7 +97,9 @@ error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:37:22 | LL | let x: u32 = transmute(*b"0123"); - | ^^^^^^^^^^^^^^^^^^^ help: replace this with: `u32::from_ne_bytes(*b"0123")` + | ---------^^^^^^^^^^ + | | + | help: replace this with: `u32::from_ne_bytes` | = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order @@ -64,7 +107,9 @@ error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:39:26 | LL | let x: [u8; 4] = transmute(x); - | ^^^^^^^^^^^^ help: replace this with: `u32::to_ne_bytes(x)` + | ---------^^^ + | | + | help: replace this with: `u32::to_ne_bytes` | = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order @@ -72,7 +117,9 @@ error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:41:22 | LL | let x: u64 = transmute(*b"feriscat"); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `u64::from_ne_bytes(*b"feriscat")` + | ---------^^^^^^^^^^^^^^ + | | + | help: replace this with: `u64::from_ne_bytes` | = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order @@ -80,7 +127,9 @@ error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:43:26 | LL | let x: [u8; 8] = transmute(x); - | ^^^^^^^^^^^^ help: replace this with: `u64::to_ne_bytes(x)` + | ---------^^^ + | | + | help: replace this with: `u64::to_ne_bytes` | = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order @@ -88,7 +137,9 @@ error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:46:22 | LL | let y: i16 = transmute(*b"01"); - | ^^^^^^^^^^^^^^^^^ help: replace this with: `i16::from_ne_bytes(*b"01")` + | ---------^^^^^^^^ + | | + | help: replace this with: `i16::from_ne_bytes` | = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order @@ -96,7 +147,9 @@ error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:48:26 | LL | let y: [u8; 2] = transmute(y); - | ^^^^^^^^^^^^ help: replace this with: `i16::to_ne_bytes(y)` + | ---------^^^ + | | + | help: replace this with: `i16::to_ne_bytes` | = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order @@ -104,7 +157,9 @@ error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:50:22 | LL | let y: i32 = transmute(*b"0123"); - | ^^^^^^^^^^^^^^^^^^^ help: replace this with: `i32::from_ne_bytes(*b"0123")` + | ---------^^^^^^^^^^ + | | + | help: replace this with: `i32::from_ne_bytes` | = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order @@ -112,7 +167,9 @@ error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:52:26 | LL | let y: [u8; 4] = transmute(y); - | ^^^^^^^^^^^^ help: replace this with: `i32::to_ne_bytes(y)` + | ---------^^^ + | | + | help: replace this with: `i32::to_ne_bytes` | = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order @@ -120,7 +177,9 @@ error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:54:22 | LL | let y: i64 = transmute(*b"feriscat"); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `i64::from_ne_bytes(*b"feriscat")` + | ---------^^^^^^^^^^^^^^ + | | + | help: replace this with: `i64::from_ne_bytes` | = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order @@ -128,7 +187,9 @@ error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:56:26 | LL | let y: [u8; 8] = transmute(y); - | ^^^^^^^^^^^^ help: replace this with: `i64::to_ne_bytes(y)` + | ---------^^^ + | | + | help: replace this with: `i64::to_ne_bytes` | = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order @@ -136,7 +197,9 @@ error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:59:22 | LL | let z: f32 = transmute(*b"0123"); - | ^^^^^^^^^^^^^^^^^^^ help: replace this with: `f32::from_ne_bytes(*b"0123")` + | ---------^^^^^^^^^^ + | | + | help: replace this with: `f32::from_ne_bytes` | = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order @@ -144,7 +207,9 @@ error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:61:26 | LL | let z: [u8; 4] = transmute(z); - | ^^^^^^^^^^^^ help: replace this with: `f32::to_ne_bytes(z)` + | ---------^^^ + | | + | help: replace this with: `f32::to_ne_bytes` | = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order @@ -152,7 +217,9 @@ error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:63:22 | LL | let z: f64 = transmute(*b"feriscat"); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `f64::from_ne_bytes(*b"feriscat")` + | ---------^^^^^^^^^^^^^^ + | | + | help: replace this with: `f64::from_ne_bytes` | = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order @@ -160,7 +227,9 @@ error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:65:26 | LL | let z: [u8; 8] = transmute(z); - | ^^^^^^^^^^^^ help: replace this with: `f64::to_ne_bytes(z)` + | ---------^^^ + | | + | help: replace this with: `f64::to_ne_bytes` | = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order @@ -168,119 +237,164 @@ error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:68:22 | LL | let y: u32 = transmute('🦀'); - | ^^^^^^^^^^^^^^^ help: replace this with: `u32::from('🦀')` + | ---------^^^^^^ + | | + | help: replace this with: `u32::from` error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:70:23 | LL | let y: char = transmute(y); - | ^^^^^^^^^^^^ help: replace this with: `char::from_u32_unchecked(y)` + | ---------^^^ + | | + | help: replace this with: `char::from_u32_unchecked` | - = help: consider `char::from_u32(…).unwrap()` + = help: consider using `char::from_u32(…).unwrap()` error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:72:22 | LL | let y: i32 = transmute('🐱'); - | ^^^^^^^^^^^^^^^ help: replace this with: `u32::from('🐱').cast_signed()` + | ^^^^^^^^^^^^^^^ + | +help: replace this with + | +LL - let y: i32 = transmute('🐱'); +LL + let y: i32 = u32::from('🐱').cast_signed(); + | error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:74:23 | LL | let y: char = transmute(y); - | ^^^^^^^^^^^^ help: replace this with: `char::from_u32_unchecked(i32::cast_unsigned(y))` + | ^^^^^^^^^^^^ + | + = help: consider using `char::from_u32(i32::cast_unsigned(…)).unwrap()` +help: replace this with + | +LL - let y: char = transmute(y); +LL + let y: char = char::from_u32_unchecked(i32::cast_unsigned(y)); | - = help: consider `char::from_u32(i32::cast_unsigned(…)).unwrap()` error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:77:22 | LL | let x: u16 = transmute(8i16); - | ^^^^^^^^^^^^^^^ help: replace this with: `i16::cast_unsigned(8i16)` + | ---------^^^^^^ + | | + | help: replace this with: `i16::cast_unsigned` error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:79:22 | LL | let x: i16 = transmute(x); - | ^^^^^^^^^^^^ help: replace this with: `u16::cast_signed(x)` + | ---------^^^ + | | + | help: replace this with: `u16::cast_signed` error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:81:22 | LL | let x: u32 = transmute(4i32); - | ^^^^^^^^^^^^^^^ help: replace this with: `i32::cast_unsigned(4i32)` + | ---------^^^^^^ + | | + | help: replace this with: `i32::cast_unsigned` error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:83:22 | LL | let x: i32 = transmute(x); - | ^^^^^^^^^^^^ help: replace this with: `u32::cast_signed(x)` + | ---------^^^ + | | + | help: replace this with: `u32::cast_signed` error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:85:22 | LL | let x: u64 = transmute(7i64); - | ^^^^^^^^^^^^^^^ help: replace this with: `i64::cast_unsigned(7i64)` + | ---------^^^^^^ + | | + | help: replace this with: `i64::cast_unsigned` error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:87:22 | LL | let x: i64 = transmute(x); - | ^^^^^^^^^^^^ help: replace this with: `u64::cast_signed(x)` + | ---------^^^ + | | + | help: replace this with: `u64::cast_signed` error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:90:22 | LL | let y: f32 = transmute(1u32); - | ^^^^^^^^^^^^^^^ help: replace this with: `f32::from_bits(1u32)` + | ---------^^^^^^ + | | + | help: replace this with: `f32::from_bits` error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:92:22 | LL | let y: u32 = transmute(y); - | ^^^^^^^^^^^^ help: replace this with: `f32::to_bits(y)` + | ---------^^^ + | | + | help: replace this with: `f32::to_bits` error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:94:22 | LL | let y: f64 = transmute(3u64); - | ^^^^^^^^^^^^^^^ help: replace this with: `f64::from_bits(3u64)` + | ---------^^^^^^ + | | + | help: replace this with: `f64::from_bits` error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:96:22 | LL | let y: u64 = transmute(2.0); - | ^^^^^^^^^^^^^^ help: replace this with: `f64::to_bits(2.0)` + | ---------^^^^^ + | | + | help: replace this with: `f64::to_bits` error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:99:22 | LL | let y: f64 = transmute(1i64); - | ^^^^^^^^^^^^^^^ help: replace this with: `f64::from_bits(i64::cast_unsigned(1i64))` + | ^^^^^^^^^^^^^^^ + | +help: replace this with + | +LL - let y: f64 = transmute(1i64); +LL + let y: f64 = f64::from_bits(i64::cast_unsigned(1i64)); + | error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:101:22 | LL | let y: i64 = transmute(1f64); - | ^^^^^^^^^^^^^^^ help: replace this with: `f64::to_bits(1f64).cast_signed()` + | ^^^^^^^^^^^^^^^ + | +help: replace this with + | +LL - let y: i64 = transmute(1f64); +LL + let y: i64 = f64::to_bits(1f64).cast_signed(); + | error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:106:21 | LL | let z: u8 = transmute(z); - | ^^^^^^^^^^^^ help: replace this with: `u8::from(z)` + | ---------^^^ + | | + | help: replace this with: `u8::from` error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:111:21 | LL | let z: i8 = transmute(z); - | ^^^^^^^^^^^^ help: replace this with: `i8::from(z)` - -error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:30:22 - | -LL | const { unsafe { transmute::<_, u8>(true) } }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `(true) as u8` + | ---------^^^ + | | + | help: replace this with: `i8::from` error: aborting due to 40 previous errors From 4765fd6b76835058044bed2a25acd1c6335332e4 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 25 May 2025 17:58:44 +0200 Subject: [PATCH 2758/4206] Fix `unused_braces` lint suggestion when encountering attributes --- compiler/rustc_lint/src/unused.rs | 35 ++++++++++--------- .../unused-braces-attrs-issue-141549.fixed | 15 ++++++++ .../unused-braces-attrs-issue-141549.rs | 15 ++++++++ .../unused-braces-attrs-issue-141549.stderr | 19 ++++++++++ 4 files changed, 68 insertions(+), 16 deletions(-) create mode 100644 tests/ui/lint/unused/unused-braces-attrs-issue-141549.fixed create mode 100644 tests/ui/lint/unused/unused-braces-attrs-issue-141549.rs create mode 100644 tests/ui/lint/unused/unused-braces-attrs-issue-141549.stderr diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 50a27d7e84f58..1620f425794f2 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1,8 +1,7 @@ use std::iter; -use rustc_ast as ast; use rustc_ast::util::{classify, parser}; -use rustc_ast::{ExprKind, StmtKind}; +use rustc_ast::{self as ast, ExprKind, HasAttrs as _, StmtKind}; use rustc_errors::{MultiSpan, pluralize}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -780,26 +779,30 @@ trait UnusedDelimLint { right_pos: Option, is_kw: bool, ) { - let spans = match value.kind { - ast::ExprKind::Block(ref block, None) if let [stmt] = block.stmts.as_slice() => stmt - .span - .find_ancestor_inside(value.span) - .map(|span| (value.span.with_hi(span.lo()), value.span.with_lo(span.hi()))), + let span_with_attrs = match value.kind { + ast::ExprKind::Block(ref block, None) if let [stmt] = block.stmts.as_slice() => { + // For the statements with attributes, like `{ #[allow()] println!("Hello!") }`, + // the span should contains the attributes, or the suggestion will remove them. + if let Some(attr_lo) = stmt.attrs().iter().map(|attr| attr.span.lo()).min() { + stmt.span.with_lo(attr_lo) + } else { + stmt.span + } + } ast::ExprKind::Paren(ref expr) => { // For the expr with attributes, like `let _ = (#[inline] || println!("Hello!"));`, // the span should contains the attributes, or the suggestion will remove them. - let expr_span_with_attrs = - if let Some(attr_lo) = expr.attrs.iter().map(|attr| attr.span.lo()).min() { - expr.span.with_lo(attr_lo) - } else { - expr.span - }; - expr_span_with_attrs.find_ancestor_inside(value.span).map(|expr_span| { - (value.span.with_hi(expr_span.lo()), value.span.with_lo(expr_span.hi())) - }) + if let Some(attr_lo) = expr.attrs.iter().map(|attr| attr.span.lo()).min() { + expr.span.with_lo(attr_lo) + } else { + expr.span + } } _ => return, }; + let spans = span_with_attrs + .find_ancestor_inside(value.span) + .map(|span| (value.span.with_hi(span.lo()), value.span.with_lo(span.hi()))); let keep_space = ( left_pos.is_some_and(|s| s >= value.span.lo()), right_pos.is_some_and(|s| s <= value.span.hi()), diff --git a/tests/ui/lint/unused/unused-braces-attrs-issue-141549.fixed b/tests/ui/lint/unused/unused-braces-attrs-issue-141549.fixed new file mode 100644 index 0000000000000..6129da3067661 --- /dev/null +++ b/tests/ui/lint/unused/unused-braces-attrs-issue-141549.fixed @@ -0,0 +1,15 @@ +//@ check-pass +//@ run-rustfix + +#![allow(dead_code)] +#![warn(unused_braces)] + +use std::cmp::Ordering; + +#[rustfmt::skip] +fn ptr_cmp(p1: *const T, p2: *const T) -> Ordering { + #[expect(ambiguous_wide_pointer_comparisons)] p1.cmp(&p2) + //~^ WARN unnecessary braces around block return value +} + +fn main() {} diff --git a/tests/ui/lint/unused/unused-braces-attrs-issue-141549.rs b/tests/ui/lint/unused/unused-braces-attrs-issue-141549.rs new file mode 100644 index 0000000000000..a550ebc497375 --- /dev/null +++ b/tests/ui/lint/unused/unused-braces-attrs-issue-141549.rs @@ -0,0 +1,15 @@ +//@ check-pass +//@ run-rustfix + +#![allow(dead_code)] +#![warn(unused_braces)] + +use std::cmp::Ordering; + +#[rustfmt::skip] +fn ptr_cmp(p1: *const T, p2: *const T) -> Ordering { + { #[expect(ambiguous_wide_pointer_comparisons)] p1.cmp(&p2) } + //~^ WARN unnecessary braces around block return value +} + +fn main() {} diff --git a/tests/ui/lint/unused/unused-braces-attrs-issue-141549.stderr b/tests/ui/lint/unused/unused-braces-attrs-issue-141549.stderr new file mode 100644 index 0000000000000..0b2b6211ab944 --- /dev/null +++ b/tests/ui/lint/unused/unused-braces-attrs-issue-141549.stderr @@ -0,0 +1,19 @@ +warning: unnecessary braces around block return value + --> $DIR/unused-braces-attrs-issue-141549.rs:11:5 + | +LL | { #[expect(ambiguous_wide_pointer_comparisons)] p1.cmp(&p2) } + | ^^ ^^ + | +note: the lint level is defined here + --> $DIR/unused-braces-attrs-issue-141549.rs:5:9 + | +LL | #![warn(unused_braces)] + | ^^^^^^^^^^^^^ +help: remove these braces + | +LL - { #[expect(ambiguous_wide_pointer_comparisons)] p1.cmp(&p2) } +LL + #[expect(ambiguous_wide_pointer_comparisons)] p1.cmp(&p2) + | + +warning: 1 warning emitted + From 45ed022d636ec72dfbb22269196007b0e71a9c7d Mon Sep 17 00:00:00 2001 From: quininer Date: Mon, 19 May 2025 10:44:00 +0800 Subject: [PATCH 2759/4206] Add compiler tests for xray --- tests/assembly/aarch64-xray.rs | 25 +++++++++++++++++ tests/assembly/x86_64-xray.rs | 25 +++++++++++++++++ tests/ui/instrument-xray/platform-support.rs | 27 +++++++++++++++++++ ...rr => platform-support.unsupported.stderr} | 0 .../instrument-xray/target-not-supported.rs | 10 ------- 5 files changed, 77 insertions(+), 10 deletions(-) create mode 100644 tests/assembly/aarch64-xray.rs create mode 100644 tests/assembly/x86_64-xray.rs create mode 100644 tests/ui/instrument-xray/platform-support.rs rename tests/ui/instrument-xray/{target-not-supported.stderr => platform-support.unsupported.stderr} (100%) delete mode 100644 tests/ui/instrument-xray/target-not-supported.rs diff --git a/tests/assembly/aarch64-xray.rs b/tests/assembly/aarch64-xray.rs new file mode 100644 index 0000000000000..d5ee011184394 --- /dev/null +++ b/tests/assembly/aarch64-xray.rs @@ -0,0 +1,25 @@ +//@ assembly-output: emit-asm +//@ compile-flags: -Zinstrument-xray=always + +//@ revisions: aarch64-linux +//@[aarch64-linux] compile-flags: --target=aarch64-unknown-linux-gnu +//@[aarch64-linux] needs-llvm-components: aarch64 +//@[aarch64-linux] only-aarch64-unknown-linux-gnu + +//@ revisions: aarch64-darwin +//@[aarch64-darwin] compile-flags: --target=aarch64-apple-darwin +//@[aarch64-darwin] needs-llvm-components: aarch64 +//@[aarch64-darwin] only-aarch64-apple-darwin + +#![crate_type = "lib"] + +// CHECK-LABEL: xray_func: +#[no_mangle] +pub fn xray_func() { + // CHECK: nop + + std::hint::black_box(()); + + // CHECK: b #32 + // CHECK-NEXT: nop +} diff --git a/tests/assembly/x86_64-xray.rs b/tests/assembly/x86_64-xray.rs new file mode 100644 index 0000000000000..4cf3e8cda13c0 --- /dev/null +++ b/tests/assembly/x86_64-xray.rs @@ -0,0 +1,25 @@ +//@ assembly-output: emit-asm +//@ compile-flags: -Zinstrument-xray=always -Cllvm-args=-x86-asm-syntax=intel + +//@ revisions: x86_64-linux +//@[x86_64-linux] compile-flags: --target=x86_64-unknown-linux-gnu +//@[x86_64-linux] needs-llvm-components: x86 +//@[x86_64-linux] only-x86_64-unknown-linux-gnu + +//@ revisions: x86_64-darwin +//@[x86_64-darwin] compile-flags: --target=x86_64-apple-darwin +//@[x86_64-darwin] needs-llvm-components: x86 +//@[x86_64-darwin] only-x86_64-apple-darwin + +#![crate_type = "lib"] + +// CHECK-LABEL: xray_func: +#[no_mangle] +pub fn xray_func() { + // CHECK: nop word ptr [rax + rax + 512] + + std::hint::black_box(()); + + // CHECK: ret + // CHECK-NEXT: nop word ptr cs:[rax + rax + 512] +} diff --git a/tests/ui/instrument-xray/platform-support.rs b/tests/ui/instrument-xray/platform-support.rs new file mode 100644 index 0000000000000..238018b348dee --- /dev/null +++ b/tests/ui/instrument-xray/platform-support.rs @@ -0,0 +1,27 @@ +//@ only-nightly (flag is still unstable) +//@ needs-xray + +//@ revisions: unsupported +//@[unsupported] needs-llvm-components: x86 +//@[unsupported] compile-flags: -Z instrument-xray --target=x86_64-pc-windows-msvc + +//@ revisions: x86_64-linux +//@[x86_64-linux] needs-llvm-components: x86 +//@[x86_64-linux] compile-flags: -Z instrument-xray --target=x86_64-unknown-linux-gnu +//@[x86_64-linux] check-pass + +//@ revisions: x86_64-darwin +//@[x86_64-darwin] needs-llvm-components: x86 +//@[x86_64-darwin] compile-flags: -Z instrument-xray --target=x86_64-apple-darwin +//@[x86_64-darwin] check-pass + +//@ revisions: aarch64-darwin +//@[aarch64-darwin] needs-llvm-components: aarch64 +//@[aarch64-darwin] compile-flags: -Z instrument-xray --target=aarch64-apple-darwin +//@[aarch64-darwin] check-pass + +#![feature(no_core)] +#![no_core] +#![no_main] + +//[unsupported]~? ERROR XRay instrumentation is not supported for this target diff --git a/tests/ui/instrument-xray/target-not-supported.stderr b/tests/ui/instrument-xray/platform-support.unsupported.stderr similarity index 100% rename from tests/ui/instrument-xray/target-not-supported.stderr rename to tests/ui/instrument-xray/platform-support.unsupported.stderr diff --git a/tests/ui/instrument-xray/target-not-supported.rs b/tests/ui/instrument-xray/target-not-supported.rs deleted file mode 100644 index 697db6bd4b747..0000000000000 --- a/tests/ui/instrument-xray/target-not-supported.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Verifies that `-Z instrument-xray` cannot be used with unsupported targets, -// -//@ needs-llvm-components: x86 -//@ compile-flags: -Z instrument-xray --target x86_64-pc-windows-msvc - -#![feature(no_core)] -#![no_core] -#![no_main] - -//~? ERROR XRay instrumentation is not supported for this target From 753c62c8899abe05abcb7bc3cde8535f925e35bb Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 25 May 2025 20:15:58 +0300 Subject: [PATCH 2760/4206] Properly implement `might_be_inside_macro_call()` using semantic information instead of syntactical hacks And rename it to `is_inside_macro_call()` accordingly. --- .../rust-analyzer/crates/hir/src/semantics.rs | 72 ++++++++----------- .../crates/ide-completion/src/context.rs | 6 +- .../ide-completion/src/context/analysis.rs | 33 +++++---- .../ide-completion/src/tests/expression.rs | 50 +++++++++++++ .../rust-analyzer/crates/ide-db/src/search.rs | 34 +++++---- .../rust-analyzer/crates/ide-ssr/src/lib.rs | 2 +- .../crates/ide-ssr/src/search.rs | 2 +- .../crates/ide/src/expand_macro.rs | 9 +-- .../crates/ide/src/highlight_related.rs | 2 +- 9 files changed, 125 insertions(+), 85 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index caa6700de9f94..d855b6aab8a89 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -407,14 +407,14 @@ impl<'db> SemanticsImpl<'db> { res } - pub fn expand_macro_call(&self, macro_call: &ast::MacroCall) -> Option { + pub fn expand_macro_call(&self, macro_call: &ast::MacroCall) -> Option> { let sa = self.analyze_no_infer(macro_call.syntax())?; let macro_call = InFile::new(sa.file_id, macro_call); let file_id = sa.expand(self.db, macro_call)?; let node = self.parse_or_expand(file_id.into()); - Some(node) + Some(InFile::new(file_id.into(), node)) } pub fn check_cfg_attr(&self, attr: &ast::TokenTree) -> Option { @@ -468,10 +468,10 @@ impl<'db> SemanticsImpl<'db> { } /// If `item` has an attribute macro attached to it, expands it. - pub fn expand_attr_macro(&self, item: &ast::Item) -> Option> { + pub fn expand_attr_macro(&self, item: &ast::Item) -> Option>> { let src = self.wrap_node_infile(item.clone()); let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src.as_ref()))?; - Some(self.expand(macro_call_id)) + Some(self.expand(macro_call_id).map(|it| InFile::new(macro_call_id.into(), it))) } pub fn expand_derive_as_pseudo_attr_macro(&self, attr: &ast::Attr) -> Option { @@ -846,49 +846,35 @@ impl<'db> SemanticsImpl<'db> { res } - // FIXME: This isn't quite right wrt to inner attributes - /// Does a syntactic traversal to check whether this token might be inside a macro call - pub fn might_be_inside_macro_call(&self, token: &SyntaxToken) -> bool { - token.parent_ancestors().any(|ancestor| { + pub fn is_inside_macro_call(&self, token: InFile<&SyntaxToken>) -> bool { + // FIXME: Maybe `ancestors_with_macros()` is more suitable here? Currently + // this is only used on real (not macro) files so this is not a problem. + token.value.parent_ancestors().any(|ancestor| { if ast::MacroCall::can_cast(ancestor.kind()) { return true; } - // Check if it is an item (only items can have macro attributes) that has a non-builtin attribute. - let Some(item) = ast::Item::cast(ancestor) else { return false }; - item.attrs().any(|attr| { - let Some(meta) = attr.meta() else { return false }; - let Some(path) = meta.path() else { return false }; - if let Some(attr_name) = path.as_single_name_ref() { - let attr_name = attr_name.text(); - let attr_name = Symbol::intern(attr_name.as_str()); - if attr_name == sym::derive { - return true; - } - // We ignore `#[test]` and friends in the def map, so we cannot expand them. - // FIXME: We match by text. This is both hacky and incorrect (people can, and do, create - // other macros named `test`). We cannot fix that unfortunately because we use this method - // for speculative expansion in completion, which we cannot analyze. Fortunately, most macros - // named `test` are test-like, meaning their expansion is not terribly important for IDE. - if attr_name == sym::test - || attr_name == sym::bench - || attr_name == sym::test_case - || find_builtin_attr_idx(&attr_name).is_some() - { - return false; - } - } - let mut segments = path.segments(); - let mut next_segment_text = || segments.next().and_then(|it| it.name_ref()); - // `#[core::prelude::rust_2024::test]` or `#[std::prelude::rust_2024::test]`. - if next_segment_text().is_some_and(|it| matches!(&*it.text(), "core" | "std")) - && next_segment_text().is_some_and(|it| it.text() == "prelude") - && next_segment_text().is_some() - && next_segment_text() - .is_some_and(|it| matches!(&*it.text(), "test" | "bench" | "test_case")) - { - return false; + + let Some(item) = ast::Item::cast(ancestor) else { + return false; + }; + // Optimization to skip the semantic check. + if item.attrs().all(|attr| { + attr.simple_name() + .is_some_and(|attr| find_builtin_attr_idx(&Symbol::intern(&attr)).is_some()) + }) { + return false; + } + self.with_ctx(|ctx| { + if ctx.item_to_macro_call(token.with_value(&item)).is_some() { + return true; } - true + let adt = match item { + ast::Item::Struct(it) => it.into(), + ast::Item::Enum(it) => it.into(), + ast::Item::Union(it) => it.into(), + _ => return false, + }; + ctx.has_derives(token.with_value(&adt)) }) }) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs index 3baf1f3de6109..5287627790ae0 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -8,8 +8,8 @@ use std::{iter, ops::ControlFlow}; use base_db::RootQueryDb as _; use hir::{ - DisplayTarget, HasAttrs, Local, ModuleDef, ModuleSource, Name, PathResolution, ScopeDef, - Semantics, SemanticsScope, Symbol, Type, TypeInfo, + DisplayTarget, HasAttrs, InFile, Local, ModuleDef, ModuleSource, Name, PathResolution, + ScopeDef, Semantics, SemanticsScope, Symbol, Type, TypeInfo, }; use ide_db::{ FilePosition, FxHashMap, FxHashSet, RootDatabase, famous_defs::FamousDefs, @@ -751,7 +751,7 @@ impl<'a> CompletionContext<'a> { original_offset, } = expand_and_analyze( &sema, - original_file.syntax().clone(), + InFile::new(editioned_file_id.into(), original_file.syntax().clone()), file_with_fake_ident.syntax().clone(), offset, &original_token, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index 284876ffc8858..7a2230b3e3615 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -1,7 +1,7 @@ //! Module responsible for analyzing the code surrounding the cursor for completion. use std::iter; -use hir::{ExpandResult, Semantics, Type, TypeInfo, Variant}; +use hir::{ExpandResult, InFile, Semantics, Type, TypeInfo, Variant}; use ide_db::{RootDatabase, active_parameter::ActiveParameter}; use itertools::Either; use syntax::{ @@ -50,7 +50,7 @@ pub(super) struct AnalysisResult { pub(super) fn expand_and_analyze( sema: &Semantics<'_, RootDatabase>, - original_file: SyntaxNode, + original_file: InFile, speculative_file: SyntaxNode, offset: TextSize, original_token: &SyntaxToken, @@ -72,7 +72,7 @@ pub(super) fn expand_and_analyze( relative_offset, ) .unwrap_or(ExpansionResult { - original_file, + original_file: original_file.value, speculative_file, original_offset: offset, speculative_offset: fake_ident_token.text_range().start(), @@ -125,7 +125,7 @@ fn token_at_offset_ignore_whitespace(file: &SyntaxNode, offset: TextSize) -> Opt /// the best we can do. fn expand_maybe_stop( sema: &Semantics<'_, RootDatabase>, - original_file: SyntaxNode, + original_file: InFile, speculative_file: SyntaxNode, original_offset: TextSize, fake_ident_token: SyntaxToken, @@ -142,17 +142,16 @@ fn expand_maybe_stop( return result; } - // This needs to come after the recursive call, because our "inside macro" detection is subtly wrong - // with regard to attribute macros named `test` that are not std's test. So hopefully we will expand - // them successfully above and be able to analyze. - // Left biased since there may already be an identifier token there, and we appended to it. - if !sema.might_be_inside_macro_call(&fake_ident_token) - && token_at_offset_ignore_whitespace(&original_file, original_offset + relative_offset) - .is_some_and(|original_token| !sema.might_be_inside_macro_call(&original_token)) + // We can't check whether the fake expansion is inside macro call, because that requires semantic info. + // But hopefully checking just the real one should be enough. + if token_at_offset_ignore_whitespace(&original_file.value, original_offset + relative_offset) + .is_some_and(|original_token| { + !sema.is_inside_macro_call(original_file.with_value(&original_token)) + }) { // Recursion base case. Some(ExpansionResult { - original_file, + original_file: original_file.value, speculative_file, original_offset, speculative_offset: fake_ident_token.text_range().start(), @@ -166,7 +165,7 @@ fn expand_maybe_stop( fn expand( sema: &Semantics<'_, RootDatabase>, - original_file: SyntaxNode, + original_file: InFile, speculative_file: SyntaxNode, original_offset: TextSize, fake_ident_token: SyntaxToken, @@ -176,7 +175,7 @@ fn expand( let parent_item = |item: &ast::Item| item.syntax().ancestors().skip(1).find_map(ast::Item::cast); - let original_node = token_at_offset_ignore_whitespace(&original_file, original_offset) + let original_node = token_at_offset_ignore_whitespace(&original_file.value, original_offset) .and_then(|token| token.parent_ancestors().find_map(ast::Item::cast)); let ancestor_items = iter::successors( Option::zip( @@ -249,7 +248,7 @@ fn expand( } // No attributes have been expanded, so look for macro_call! token trees or derive token trees - let orig_tt = ancestors_at_offset(&original_file, original_offset) + let orig_tt = ancestors_at_offset(&original_file.value, original_offset) .map_while(Either::::cast) .last()?; let spec_tt = ancestors_at_offset(&speculative_file, fake_ident_token.text_range().start()) @@ -292,7 +291,7 @@ fn expand( fake_mapped_tokens.into_iter().min_by_key(|(_, rank)| *rank) { return Some(ExpansionResult { - original_file, + original_file: original_file.value, speculative_file, original_offset, speculative_offset: fake_ident_token.text_range().start(), @@ -349,7 +348,7 @@ fn expand( } let result = expand_maybe_stop( sema, - actual_expansion.clone(), + InFile::new(file.into(), actual_expansion.clone()), fake_expansion.clone(), new_offset, fake_mapped_token, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs index e5467767d42ca..b46e4c32061b4 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs @@ -2111,6 +2111,56 @@ fn foo() { ); } +#[test] +fn cfg_attr_attr_macro() { + check( + r#" +//- proc_macros: identity +#[cfg_attr(test, proc_macros::identity)] +fn foo() { + $0 +} + "#, + expect![[r#" + fn foo() fn() + md proc_macros + bt u32 u32 + kw async + kw const + kw crate:: + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); +} + #[test] fn escaped_label() { check( diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs index 30be5bc21b498..d4ab75929279d 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs @@ -524,6 +524,7 @@ impl<'a> FindUsages<'a> { fn find_nodes<'b>( sema: &'b Semantics<'_, RootDatabase>, name: &str, + file_id: EditionedFileId, node: &syntax::SyntaxNode, offset: TextSize, ) -> impl Iterator + 'b { @@ -534,7 +535,7 @@ impl<'a> FindUsages<'a> { }) .into_iter() .flat_map(move |token| { - if sema.might_be_inside_macro_call(&token) { + if sema.is_inside_macro_call(InFile::new(file_id.into(), &token)) { sema.descend_into_macros_exact(token) } else { <_>::from([token]) @@ -654,11 +655,14 @@ impl<'a> FindUsages<'a> { let tree = LazyCell::new(move || sema.parse(file_id).syntax().clone()); for offset in FindUsages::match_indices(&file_text, &finder, search_range) { - let usages = - FindUsages::find_nodes(sema, ¤t_to_process, &tree, offset) - .filter(|it| { - matches!(it.kind(), SyntaxKind::NAME | SyntaxKind::NAME_REF) - }); + let usages = FindUsages::find_nodes( + sema, + ¤t_to_process, + file_id, + &tree, + offset, + ) + .filter(|it| matches!(it.kind(), SyntaxKind::NAME | SyntaxKind::NAME_REF)); for usage in usages { if let Some(alias) = usage.parent().and_then(|it| { let path = ast::PathSegment::cast(it)?.parent_path(); @@ -813,7 +817,7 @@ impl<'a> FindUsages<'a> { let tree = LazyCell::new(move || this.sema.parse(file_id).syntax().clone()); for offset in FindUsages::match_indices(&file_text, finder, search_range) { - let usages = FindUsages::find_nodes(this.sema, name, &tree, offset) + let usages = FindUsages::find_nodes(this.sema, name, file_id, &tree, offset) .filter_map(ast::NameRef::cast); for usage in usages { let found_usage = usage @@ -970,8 +974,8 @@ impl<'a> FindUsages<'a> { return; } - for name in - Self::find_nodes(sema, name, &tree, offset).filter_map(ast::NameLike::cast) + for name in Self::find_nodes(sema, name, file_id, &tree, offset) + .filter_map(ast::NameLike::cast) { if match name { ast::NameLike::NameRef(name_ref) => self.found_name_ref(&name_ref, sink), @@ -985,8 +989,8 @@ impl<'a> FindUsages<'a> { // Search for occurrences of the `Self` referring to our type if let Some((self_ty, finder)) = &include_self_kw_refs { for offset in Self::match_indices(&text, finder, search_range) { - for name_ref in - Self::find_nodes(sema, "Self", &tree, offset).filter_map(ast::NameRef::cast) + for name_ref in Self::find_nodes(sema, "Self", file_id, &tree, offset) + .filter_map(ast::NameRef::cast) { if self.found_self_ty_name_ref(self_ty, &name_ref, sink) { return; @@ -1010,7 +1014,7 @@ impl<'a> FindUsages<'a> { let tree = LazyCell::new(move || sema.parse(file_id).syntax().clone()); for offset in Self::match_indices(&text, finder, search_range) { - for name_ref in Self::find_nodes(sema, "super", &tree, offset) + for name_ref in Self::find_nodes(sema, "super", file_id, &tree, offset) .filter_map(ast::NameRef::cast) { if self.found_name_ref(&name_ref, sink) { @@ -1020,7 +1024,7 @@ impl<'a> FindUsages<'a> { } if let Some(finder) = &is_crate_root { for offset in Self::match_indices(&text, finder, search_range) { - for name_ref in Self::find_nodes(sema, "crate", &tree, offset) + for name_ref in Self::find_nodes(sema, "crate", file_id, &tree, offset) .filter_map(ast::NameRef::cast) { if self.found_name_ref(&name_ref, sink) { @@ -1064,8 +1068,8 @@ impl<'a> FindUsages<'a> { let finder = &Finder::new("self"); for offset in Self::match_indices(&text, finder, search_range) { - for name_ref in - Self::find_nodes(sema, "self", &tree, offset).filter_map(ast::NameRef::cast) + for name_ref in Self::find_nodes(sema, "self", file_id, &tree, offset) + .filter_map(ast::NameRef::cast) { if self.found_self_module_name_ref(&name_ref, sink) { return; diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs index 339c199ec29ac..43c56ac8bec56 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs @@ -287,7 +287,7 @@ impl<'db> MatchFinder<'db> { if let Some(expanded) = self.sema.expand_macro_call(¯o_call) { if let Some(tt) = macro_call.token_tree() { self.output_debug_for_nodes_at_range( - &expanded, + &expanded.value, range, &Some(self.sema.original_range(tt.syntax())), out, diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs index d89911fca403d..9afbedbb1ab46 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs @@ -194,7 +194,7 @@ impl MatchFinder<'_> { // nodes that originated entirely from within the token tree of the macro call. // i.e. we don't want to match something that came from the macro itself. if let Some(range) = self.sema.original_range_opt(tt.syntax()) { - self.slow_scan_node(&expanded, rule, &Some(range), matches_out); + self.slow_scan_node(&expanded.value, rule, &Some(range), matches_out); } } } diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs index 241a702038da4..9beed2cac134d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs +++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs @@ -146,10 +146,11 @@ fn expand_macro_recur( offset_in_original_node: TextSize, ) -> Option { let ExpandResult { value: expanded, err } = match macro_call { - item @ ast::Item::MacroCall(macro_call) => { - sema.expand_attr_macro(item).or_else(|| sema.expand_allowed_builtins(macro_call))? - } - item => sema.expand_attr_macro(item)?, + item @ ast::Item::MacroCall(macro_call) => sema + .expand_attr_macro(item) + .map(|it| it.map(|it| it.value)) + .or_else(|| sema.expand_allowed_builtins(macro_call))?, + item => sema.expand_attr_macro(item)?.map(|it| it.value), }; let expanded = expanded.clone_for_update(); if let Some(err) = err { diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs index fb8dbcfc73543..520ba39a238b7 100644 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs @@ -653,7 +653,7 @@ impl<'a> WalkExpandedExprCtx<'a> { expr.macro_call().and_then(|call| self.sema.expand_macro_call(&call)) { match_ast! { - match expanded { + match (expanded.value) { ast::MacroStmts(it) => { self.handle_expanded(it, cb); }, From 979dcf8e2f213e4f4b645cb62e7fe9f4f2c0c785 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 25 May 2025 18:39:17 +0000 Subject: [PATCH 2761/4206] Rustup to rustc 1.89.0-nightly (5e16c6620 2025-05-24) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 4b6ed82762bed..af4bd6dc6b851 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-05-20" +channel = "nightly-2025-05-25" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 245bf503e2a948ac98170516d11df632e85a948b Mon Sep 17 00:00:00 2001 From: bendn Date: Sun, 25 May 2025 02:01:04 +0700 Subject: [PATCH 2762/4206] increase perf of charsearcher for single ascii characters --- library/core/src/str/iter.rs | 2 +- library/core/src/str/pattern.rs | 32 +++++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 425c4eaee28ee..49c581f352eb3 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -656,7 +656,7 @@ impl<'a, P: Pattern> SplitInternal<'a, P> { None } - #[inline] + #[inline(always)] fn next(&mut self) -> Option<&'a str> { if self.finished { return None; diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs index bcbbb11c83b2f..e8189a2187b63 100644 --- a/library/core/src/str/pattern.rs +++ b/library/core/src/str/pattern.rs @@ -429,8 +429,23 @@ unsafe impl<'a> Searcher<'a> for CharSearcher<'a> { SearchStep::Done } } - #[inline] + #[inline(always)] fn next_match(&mut self) -> Option<(usize, usize)> { + if self.utf8_size == 1 { + return match self + .haystack + .as_bytes() + .get(self.finger..self.finger_back)? + .iter() + .position(|x| *x == self.utf8_encoded[0]) + { + Some(x) => { + self.finger += x + 1; + Some((self.finger - 1, self.finger)) + } + None => None, + }; + } loop { // get the haystack after the last character found let bytes = self.haystack.as_bytes().get(self.finger..self.finger_back)?; @@ -498,6 +513,21 @@ unsafe impl<'a> ReverseSearcher<'a> for CharSearcher<'a> { } #[inline] fn next_match_back(&mut self) -> Option<(usize, usize)> { + if self.utf8_size == 1 { + return match self + .haystack + .get(self.finger..self.finger_back)? + .as_bytes() + .iter() + .rposition(|&x| x == self.utf8_encoded[0]) + { + Some(x) => { + self.finger_back = self.finger + x; + Some((self.finger_back, self.finger_back + 1)) + } + None => None, + }; + } let haystack = self.haystack.as_bytes(); loop { // get the haystack up to but not including the last character searched From 4aed799d34480f2f9f959ec285e4a0481037f9d3 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 25 May 2025 18:58:21 +0000 Subject: [PATCH 2763/4206] Update tidy exceptions --- src/tools/tidy/src/deps.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 9bb06c31c5c06..9f333cc43cf8c 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -200,6 +200,7 @@ const EXCEPTIONS_CRANELIFT: ExceptionList = &[ ("cranelift-module", "Apache-2.0 WITH LLVM-exception"), ("cranelift-native", "Apache-2.0 WITH LLVM-exception"), ("cranelift-object", "Apache-2.0 WITH LLVM-exception"), + ("cranelift-srcgen", "Apache-2.0 WITH LLVM-exception"), ("foldhash", "Zlib"), ("mach2", "BSD-2-Clause OR MIT OR Apache-2.0"), ("regalloc2", "Apache-2.0 WITH LLVM-exception"), @@ -525,6 +526,7 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ "cranelift-module", "cranelift-native", "cranelift-object", + "cranelift-srcgen", "crc32fast", "equivalent", "fallible-iterator", From ade24354f4bc344db9b1647d949d97dec19bdd77 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 24 May 2025 17:24:59 +0000 Subject: [PATCH 2764/4206] Do not canonicalize in new solver if it has nothing to canonicalize --- .../src/canonicalizer.rs | 59 ++++++++++++++++--- .../rustc_next_trait_solver/src/resolve.rs | 4 ++ 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 93b8940ee37d8..addeb3e2b78e0 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -4,12 +4,22 @@ use rustc_type_ir::data_structures::{HashMap, ensure_sufficient_stack}; use rustc_type_ir::inherent::*; use rustc_type_ir::solve::{Goal, QueryInput}; use rustc_type_ir::{ - self as ty, Canonical, CanonicalTyVarKind, CanonicalVarKind, InferCtxtLike, Interner, - TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, + self as ty, Canonical, CanonicalTyVarKind, CanonicalVarKind, Flags, InferCtxtLike, Interner, + TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; use crate::delegate::SolverDelegate; +/// Does this have infer/placeholder/param, free regions or ReErased? +const NEEDS_CANONICAL: TypeFlags = TypeFlags::from_bits( + TypeFlags::HAS_INFER.bits() + | TypeFlags::HAS_PLACEHOLDER.bits() + | TypeFlags::HAS_PARAM.bits() + | TypeFlags::HAS_FREE_REGIONS.bits() + | TypeFlags::HAS_RE_ERASED.bits(), +) +.unwrap(); + /// Whether we're canonicalizing a query input or the query response. /// /// When canonicalizing an input we're in the context of the caller @@ -79,7 +89,11 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { cache: Default::default(), }; - let value = value.fold_with(&mut canonicalizer); + let value = if value.has_type_flags(NEEDS_CANONICAL) { + value.fold_with(&mut canonicalizer) + } else { + value + }; assert!(!value.has_infer(), "unexpected infer in {value:?}"); assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}"); let (max_universe, variables) = canonicalizer.finalize(); @@ -111,7 +125,14 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { cache: Default::default(), }; - let param_env = input.goal.param_env.fold_with(&mut env_canonicalizer); + + let param_env = input.goal.param_env; + let param_env = if param_env.has_type_flags(NEEDS_CANONICAL) { + param_env.fold_with(&mut env_canonicalizer) + } else { + param_env + }; + debug_assert_eq!(env_canonicalizer.binder_index, ty::INNERMOST); // Then canonicalize the rest of the input without keeping `'static` // while *mostly* reusing the canonicalizer from above. @@ -134,10 +155,22 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { cache: Default::default(), }; - let predicate = input.goal.predicate.fold_with(&mut rest_canonicalizer); + let predicate = input.goal.predicate; + let predicate = if predicate.has_type_flags(NEEDS_CANONICAL) { + predicate.fold_with(&mut rest_canonicalizer) + } else { + predicate + }; let goal = Goal { param_env, predicate }; + + let predefined_opaques_in_body = input.predefined_opaques_in_body; let predefined_opaques_in_body = - input.predefined_opaques_in_body.fold_with(&mut rest_canonicalizer); + if input.predefined_opaques_in_body.has_type_flags(NEEDS_CANONICAL) { + predefined_opaques_in_body.fold_with(&mut rest_canonicalizer) + } else { + predefined_opaques_in_body + }; + let value = QueryInput { goal, predefined_opaques_in_body }; assert!(!value.has_infer(), "unexpected infer in {value:?}"); @@ -387,7 +420,11 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { | ty::Alias(_, _) | ty::Bound(_, _) | ty::Error(_) => { - return ensure_sufficient_stack(|| t.super_fold_with(self)); + return if t.has_type_flags(NEEDS_CANONICAL) { + ensure_sufficient_stack(|| t.super_fold_with(self)) + } else { + t + }; } }; @@ -522,11 +559,17 @@ impl, I: Interner> TypeFolder for Canonicaliz | ty::ConstKind::Unevaluated(_) | ty::ConstKind::Value(_) | ty::ConstKind::Error(_) - | ty::ConstKind::Expr(_) => return c.super_fold_with(self), + | ty::ConstKind::Expr(_) => { + return if c.has_type_flags(NEEDS_CANONICAL) { c.super_fold_with(self) } else { c }; + } }; let var = self.get_or_insert_bound_var(c, kind); Const::new_anon_bound(self.cx(), self.binder_index, var) } + + fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { + if p.flags().intersects(NEEDS_CANONICAL) { p.super_fold_with(self) } else { p } + } } diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs index 992c5ddf504ef..39abec2d7d8db 100644 --- a/compiler/rustc_next_trait_solver/src/resolve.rs +++ b/compiler/rustc_next_trait_solver/src/resolve.rs @@ -86,4 +86,8 @@ impl, I: Interner> TypeFolder for EagerResolv } } } + + fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { + if p.has_infer() { p.super_fold_with(self) } else { p } + } } From cf9ac0eec16bb863add283b58de5a25a131b142d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 May 2025 22:16:10 +0200 Subject: [PATCH 2765/4206] const-check: stop recommending the use of rustc_allow_const_fn_unstable --- compiler/rustc_const_eval/messages.ftl | 3 +- compiler/rustc_const_eval/src/errors.rs | 5 - .../dont_promote_unstable_const_fn.stderr | 7 +- .../ui/consts/const-unstable-intrinsic.stderr | 21 +-- .../min_const_fn_libstd_stability.stderr | 49 +------ ...in_const_unsafe_fn_libstd_stability.stderr | 21 +-- ...n_const_unsafe_fn_libstd_stability2.stderr | 21 +-- ...e_const_stab_unmarked_crate_imports.stderr | 7 +- ...ive_const_stab_unstable_if_unmarked.stderr | 14 +- .../const-eval-select-stability.stderr | 7 +- .../ui/traits/const-traits/staged-api.stderr | 133 +++--------------- 11 files changed, 41 insertions(+), 247 deletions(-) diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index f4defd2aa1343..7d4afc9d3d952 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -424,8 +424,7 @@ const_eval_unstable_in_stable_exposed = .unstable_sugg = if the {$is_function_call2 -> [true] caller *[false] function - } is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) - .bypass_sugg = otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + } is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` const_eval_unstable_intrinsic = `{$name}` is not yet stable as a const intrinsic const_eval_unstable_intrinsic_suggestion = add `#![feature({$feature})]` to the crate attributes to enable diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 826ea0e58ecca..7c35e47bbf805 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -58,11 +58,6 @@ pub(crate) struct UnstableInStableExposed { code = "#[rustc_const_unstable(feature = \"...\", issue = \"...\")]\n", applicability = "has-placeholders" )] - #[suggestion( - const_eval_bypass_sugg, - code = "#[rustc_allow_const_fn_unstable({gate})]\n", - applicability = "has-placeholders" - )] pub attr_span: Span, } diff --git a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr index a506f2a282bbb..b505b76a6abfa 100644 --- a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr +++ b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr @@ -5,14 +5,9 @@ LL | const fn bar() -> u32 { foo() } | ^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn bar() -> u32 { foo() } - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo)] LL | const fn bar() -> u32 { foo() } | diff --git a/tests/ui/consts/const-unstable-intrinsic.stderr b/tests/ui/consts/const-unstable-intrinsic.stderr index 308b02386f5c9..7e7ba966cee17 100644 --- a/tests/ui/consts/const-unstable-intrinsic.stderr +++ b/tests/ui/consts/const-unstable-intrinsic.stderr @@ -46,14 +46,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | size_of_val(&x); | ^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn const_main() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(local)] LL | const fn const_main() { | @@ -63,14 +58,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | min_align_of_val(&x); | ^^^^^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn const_main() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(local)] LL | const fn const_main() { | @@ -88,14 +78,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | super::size_of_val(src); | ^^^^^^^^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const unsafe fn copy(src: *const T, _dst: *mut T, _count: usize) { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(local)] LL | const unsafe fn copy(src: *const T, _dst: *mut T, _count: usize) { | diff --git a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr index 26dedc49a3928..9efc252ce6b09 100644 --- a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr +++ b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr @@ -5,14 +5,9 @@ LL | const fn bar() -> u32 { foo() } | ^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn bar() -> u32 { foo() } - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo)] LL | const fn bar() -> u32 { foo() } | @@ -23,14 +18,9 @@ LL | const fn bar2() -> u32 { foo2() } | ^^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn bar2() -> u32 { foo2() } - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo2)] LL | const fn bar2() -> u32 { foo2() } | @@ -40,14 +30,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | let x = async { 13 }; | ^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn bar3() -> u32 { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_async_blocks)] LL | const fn bar3() -> u32 { | @@ -58,14 +43,9 @@ LL | foo() | ^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn bar3() -> u32 { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo)] LL | const fn bar3() -> u32 { | @@ -76,14 +56,9 @@ LL | const fn bar2_gated() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn bar2_gated() -> u32 { foo2_gated() } - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo2)] LL | const fn bar2_gated() -> u32 { foo2_gated() } | @@ -94,14 +69,9 @@ LL | pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_g | ^^^^^^^^^^^^^^^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() } - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo2)] LL | pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() } | @@ -112,14 +82,9 @@ LL | const fn stable_indirect() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn stable_indirect() -> u32 { foo2_gated() } - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo2)] LL | const fn stable_indirect() -> u32 { foo2_gated() } | diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr index b61f7db6f43b7..0712a790955a8 100644 --- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr +++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr @@ -5,14 +5,9 @@ LL | const unsafe fn bar() -> u32 { unsafe { foo() } } | ^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const unsafe fn bar() -> u32 { unsafe { foo() } } - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo)] LL | const unsafe fn bar() -> u32 { unsafe { foo() } } | @@ -23,14 +18,9 @@ LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } | ^^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo2)] LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } | @@ -41,14 +31,9 @@ LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } | ^^^^^^^^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo2)] LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } | diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr index fad8e396e9ab5..618b9a16dd468 100644 --- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr +++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr @@ -5,14 +5,9 @@ LL | const unsafe fn bar() -> u32 { foo() } | ^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const unsafe fn bar() -> u32 { foo() } - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo)] LL | const unsafe fn bar() -> u32 { foo() } | @@ -23,14 +18,9 @@ LL | const unsafe fn bar2() -> u32 { foo2() } | ^^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const unsafe fn bar2() -> u32 { foo2() } - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo2)] LL | const unsafe fn bar2() -> u32 { foo2() } | @@ -41,14 +31,9 @@ LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo2)] LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } | diff --git a/tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.stderr b/tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.stderr index bbe749f595893..04804cb6d339b 100644 --- a/tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.stderr +++ b/tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.stderr @@ -5,14 +5,9 @@ LL | unstable_if_unmarked_const_fn_crate::not_stably_const(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn stable_fn() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(rustc_private)] LL | const fn stable_fn() { | diff --git a/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.stderr b/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.stderr index 9d7b81c822bd1..14940ae93f894 100644 --- a/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.stderr +++ b/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.stderr @@ -5,14 +5,9 @@ LL | not_stably_const(); | ^^^^^^^^^^^^^^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | pub const fn expose_on_stable() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(rustc_private)] LL | pub const fn expose_on_stable() { | @@ -22,14 +17,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | let _x = async { 15 }; | ^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | pub const fn expose_on_stable() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_async_blocks)] LL | pub const fn expose_on_stable() { | diff --git a/tests/ui/intrinsics/const-eval-select-stability.stderr b/tests/ui/intrinsics/const-eval-select-stability.stderr index 5f443b1d4ff7b..513c19cbb5b71 100644 --- a/tests/ui/intrinsics/const-eval-select-stability.stderr +++ b/tests/ui/intrinsics/const-eval-select-stability.stderr @@ -4,14 +4,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | const_eval_select((), nothing, log); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | pub const fn hey() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_eval_select)] LL | pub const fn hey() { | diff --git a/tests/ui/traits/const-traits/staged-api.stderr b/tests/ui/traits/const-traits/staged-api.stderr index cdf577287eec5..4756c490cb10a 100644 --- a/tests/ui/traits/const-traits/staged-api.stderr +++ b/tests/ui/traits/const-traits/staged-api.stderr @@ -71,14 +71,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Unstable::func(); | ^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn const_context() { | @@ -88,14 +83,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Unstable::func(); | ^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(unstable)] LL | const fn const_context() { | @@ -105,14 +95,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Foo::func(); | ^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn const_context() { | @@ -122,14 +107,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Foo::func(); | ^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(unstable)] LL | const fn const_context() { | @@ -139,14 +119,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Unstable2::func(); | ^^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn const_context() { | @@ -156,14 +131,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Unstable2::func(); | ^^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(unstable)] LL | const fn const_context() { | @@ -173,14 +143,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | conditionally_const::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn const_context() { | @@ -190,14 +155,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Unstable::func(); | ^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn stable_const_context() { | @@ -207,14 +167,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Unstable::func(); | ^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(unstable)] LL | const fn stable_const_context() { | @@ -224,14 +179,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Foo::func(); | ^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn stable_const_context() { | @@ -241,14 +191,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Foo::func(); | ^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(unstable)] LL | const fn stable_const_context() { | @@ -259,14 +204,9 @@ LL | const_context_not_const_stable(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(local_feature)] LL | const fn stable_const_context() { | @@ -276,14 +216,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | conditionally_const::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn stable_const_context() { | @@ -293,14 +228,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Unstable::func(); | ^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn implicitly_stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn implicitly_stable_const_context() { | @@ -310,14 +240,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Unstable::func(); | ^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn implicitly_stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(unstable)] LL | const fn implicitly_stable_const_context() { | @@ -327,14 +252,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Foo::func(); | ^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn implicitly_stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn implicitly_stable_const_context() { | @@ -344,14 +264,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Foo::func(); | ^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn implicitly_stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(unstable)] LL | const fn implicitly_stable_const_context() { | @@ -362,14 +277,9 @@ LL | const_context_not_const_stable(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn implicitly_stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(local_feature)] LL | const fn implicitly_stable_const_context() { | @@ -379,14 +289,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | conditionally_const::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn implicitly_stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn implicitly_stable_const_context() { | From e388a3e40538519c89908190baaefbc69a9c985f Mon Sep 17 00:00:00 2001 From: Nia Espera Date: Sat, 24 May 2025 23:18:32 +0200 Subject: [PATCH 2766/4206] extend allocbytes with associated type --- .../src/const_eval/dummy_machine.rs | 5 ++ .../src/const_eval/machine.rs | 3 + .../src/interpret/intrinsics.rs | 2 +- .../rustc_const_eval/src/interpret/machine.rs | 4 ++ .../rustc_const_eval/src/interpret/memory.rs | 8 ++- .../rustc_const_eval/src/interpret/util.rs | 2 +- .../src/mir/interpret/allocation.rs | 58 +++++++++++++------ compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_middle/src/ty/vtable.rs | 2 +- .../src/builder/expr/as_constant.rs | 6 +- .../rustc_mir_transform/src/large_enums.rs | 1 + compiler/rustc_smir/src/rustc_smir/alloc.rs | 2 + src/tools/miri/src/alloc_addresses/mod.rs | 6 +- src/tools/miri/src/alloc_bytes.rs | 9 ++- src/tools/miri/src/concurrency/thread.rs | 2 +- src/tools/miri/src/machine.rs | 3 + 16 files changed, 81 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs index 46dcebc46e9c8..ba1d074133dfb 100644 --- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs @@ -197,4 +197,9 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine { ) -> &'a mut Vec> { unimplemented!() } + + fn get_default_alloc_params( + &self, + ) -> ::AllocParams { + } } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 7c7daed525b2d..14c00553076a1 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -735,6 +735,9 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { Cow::Owned(compute_range()) } } + + fn get_default_alloc_params(&self) -> ::AllocParams { + } } // Please do not add any code below the above `Machine` trait impl. I (oli-obk) plan more cleanups diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 090b2a692cfc3..3343f48cdd997 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -26,7 +26,7 @@ use crate::fluent_generated as fluent; /// Directly returns an `Allocation` containing an absolute path representation of the given type. pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAllocation<'tcx> { let path = crate::util::type_name(tcx, ty); - let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes()); + let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes(), ()); tcx.mk_const_alloc(alloc) } diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index d13e17a481a46..9f215eca2fd46 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -628,6 +628,10 @@ pub trait Machine<'tcx>: Sized { // Default to no caching. Cow::Owned(compute_range()) } + + /// Compute the value passed to the constructors of the `AllocBytes` type for + /// abstract machine allocations. + fn get_default_alloc_params(&self) -> ::AllocParams; } /// A lot of the flexibility above is just needed for `Miri`, but all "compile-time" machines diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 43bf48a9b9612..99a4bc1b7d6e8 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -233,10 +233,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { kind: MemoryKind, init: AllocInit, ) -> InterpResult<'tcx, Pointer> { + let params = self.machine.get_default_alloc_params(); let alloc = if M::PANIC_ON_ALLOC_FAIL { - Allocation::new(size, align, init) + Allocation::new(size, align, init, params) } else { - Allocation::try_new(size, align, init)? + Allocation::try_new(size, align, init, params)? }; self.insert_allocation(alloc, kind) } @@ -248,7 +249,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { kind: MemoryKind, mutability: Mutability, ) -> InterpResult<'tcx, Pointer> { - let alloc = Allocation::from_bytes(bytes, align, mutability); + let params = self.machine.get_default_alloc_params(); + let alloc = Allocation::from_bytes(bytes, align, mutability, params); self.insert_allocation(alloc, kind) } diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 847905e834310..83a170926191b 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -38,7 +38,7 @@ pub(crate) fn create_static_alloc<'tcx>( static_def_id: LocalDefId, layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { - let alloc = Allocation::try_new(layout.size, layout.align.abi, AllocInit::Uninit)?; + let alloc = Allocation::try_new(layout.size, layout.align.abi, AllocInit::Uninit, ())?; let alloc_id = ecx.tcx.reserve_and_set_static_alloc(static_def_id.into()); assert_eq!(ecx.machine.static_root_ids, None); ecx.machine.static_root_ids = Some((alloc_id, static_def_id)); diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 57aafbb26bc8b..f17747558fc55 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -27,12 +27,21 @@ use crate::ty; /// Functionality required for the bytes of an `Allocation`. pub trait AllocBytes: Clone + fmt::Debug + Deref + DerefMut { + /// The type of extra parameters passed in when creating an allocation. + /// Can be used by `interpret::Machine` instances to make runtime-configuration-dependent + /// decisions about the allocation strategy. + type AllocParams; + /// Create an `AllocBytes` from a slice of `u8`. - fn from_bytes<'a>(slice: impl Into>, _align: Align) -> Self; + fn from_bytes<'a>( + slice: impl Into>, + _align: Align, + _params: Self::AllocParams, + ) -> Self; /// Create a zeroed `AllocBytes` of the specified size and alignment. /// Returns `None` if we ran out of memory on the host. - fn zeroed(size: Size, _align: Align) -> Option; + fn zeroed(size: Size, _align: Align, _params: Self::AllocParams) -> Option; /// Gives direct access to the raw underlying storage. /// @@ -51,11 +60,13 @@ pub trait AllocBytes: Clone + fmt::Debug + Deref + DerefMut`. impl AllocBytes for Box<[u8]> { - fn from_bytes<'a>(slice: impl Into>, _align: Align) -> Self { + type AllocParams = (); + + fn from_bytes<'a>(slice: impl Into>, _align: Align, _params: ()) -> Self { Box::<[u8]>::from(slice.into()) } - fn zeroed(size: Size, _align: Align) -> Option { + fn zeroed(size: Size, _align: Align, _params: ()) -> Option { let bytes = Box::<[u8]>::try_new_zeroed_slice(size.bytes().try_into().ok()?).ok()?; // SAFETY: the box was zero-allocated, which is a valid initial value for Box<[u8]> let bytes = unsafe { bytes.assume_init() }; @@ -172,9 +183,8 @@ fn all_zero(buf: &[u8]) -> bool { } /// Custom encoder for [`Allocation`] to more efficiently represent the case where all bytes are 0. -impl Encodable for Allocation +impl Encodable for Allocation> where - Bytes: AllocBytes, ProvenanceMap: Encodable, Extra: Encodable, { @@ -192,9 +202,8 @@ where } } -impl Decodable for Allocation +impl Decodable for Allocation> where - Bytes: AllocBytes, ProvenanceMap: Decodable, Extra: Decodable, { @@ -203,7 +212,7 @@ where let len = decoder.read_usize(); let bytes = if all_zero { vec![0u8; len] } else { decoder.read_raw_bytes(len).to_vec() }; - let bytes = Bytes::from_bytes(bytes, align); + let bytes = as AllocBytes>::from_bytes(bytes, align, ()); let provenance = Decodable::decode(decoder); let init_mask = Decodable::decode(decoder); @@ -395,8 +404,9 @@ impl Allocation { slice: impl Into>, align: Align, mutability: Mutability, + params: ::AllocParams, ) -> Self { - let bytes = Bytes::from_bytes(slice, align); + let bytes = Bytes::from_bytes(slice, align, params); let size = Size::from_bytes(bytes.len()); Self { bytes, @@ -408,14 +418,18 @@ impl Allocation { } } - pub fn from_bytes_byte_aligned_immutable<'a>(slice: impl Into>) -> Self { - Allocation::from_bytes(slice, Align::ONE, Mutability::Not) + pub fn from_bytes_byte_aligned_immutable<'a>( + slice: impl Into>, + params: ::AllocParams, + ) -> Self { + Allocation::from_bytes(slice, Align::ONE, Mutability::Not, params) } fn new_inner( size: Size, align: Align, init: AllocInit, + params: ::AllocParams, fail: impl FnOnce() -> R, ) -> Result { // We raise an error if we cannot create the allocation on the host. @@ -424,7 +438,7 @@ impl Allocation { // deterministic. However, we can be non-deterministic here because all uses of const // evaluation (including ConstProp!) will make compilation fail (via hard error // or ICE) upon encountering a `MemoryExhausted` error. - let bytes = Bytes::zeroed(size, align).ok_or_else(fail)?; + let bytes = Bytes::zeroed(size, align, params).ok_or_else(fail)?; Ok(Allocation { bytes, @@ -444,8 +458,13 @@ impl Allocation { /// Try to create an Allocation of `size` bytes, failing if there is not enough memory /// available to the compiler to do so. - pub fn try_new<'tcx>(size: Size, align: Align, init: AllocInit) -> InterpResult<'tcx, Self> { - Self::new_inner(size, align, init, || { + pub fn try_new<'tcx>( + size: Size, + align: Align, + init: AllocInit, + params: ::AllocParams, + ) -> InterpResult<'tcx, Self> { + Self::new_inner(size, align, init, params, || { ty::tls::with(|tcx| tcx.dcx().delayed_bug("exhausted memory during interpretation")); InterpErrorKind::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted) }) @@ -457,8 +476,13 @@ impl Allocation { /// /// Example use case: To obtain an Allocation filled with specific data, /// first call this function and then call write_scalar to fill in the right data. - pub fn new(size: Size, align: Align, init: AllocInit) -> Self { - match Self::new_inner(size, align, init, || { + pub fn new( + size: Size, + align: Align, + init: AllocInit, + params: ::AllocParams, + ) -> Self { + match Self::new_inner(size, align, init, params, || { panic!( "interpreter ran out of memory: cannot create allocation of {} bytes", size.bytes() diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 8c915fea950a4..70172e55e541c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1582,7 +1582,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns the same `AllocId` if called again with the same bytes. pub fn allocate_bytes_dedup(self, bytes: &[u8], salt: usize) -> interpret::AllocId { // Create an allocation that just contains these bytes. - let alloc = interpret::Allocation::from_bytes_byte_aligned_immutable(bytes); + let alloc = interpret::Allocation::from_bytes_byte_aligned_immutable(bytes, ()); let alloc = self.mk_const_alloc(alloc); self.reserve_and_set_memory_dedup(alloc, salt) } diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index 6c9e0e7c0eb8a..74b6a840a2e77 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -110,7 +110,7 @@ pub(super) fn vtable_allocation_provider<'tcx>( let ptr_align = tcx.data_layout.pointer_align.abi; let vtable_size = ptr_size * u64::try_from(vtable_entries.len()).unwrap(); - let mut vtable = Allocation::new(vtable_size, ptr_align, AllocInit::Uninit); + let mut vtable = Allocation::new(vtable_size, ptr_align, AllocInit::Uninit, ()); // No need to do any alignment checks on the memory accesses below, because we know the // allocation is correctly aligned as we created it above. Also we're only offsetting by diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs index 64d092e035451..eb8e98ec3644d 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs @@ -121,14 +121,14 @@ fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx> let value = match (lit, lit_ty.kind()) { (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => { let s = s.as_str(); - let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes()); + let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes(), ()); let allocation = tcx.mk_const_alloc(allocation); ConstValue::Slice { data: allocation, meta: allocation.inner().size().bytes() } } (ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Slice(_)) => { - let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]); + let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8], ()); let allocation = tcx.mk_const_alloc(allocation); ConstValue::Slice { data: allocation, meta: allocation.inner().size().bytes() } } @@ -138,7 +138,7 @@ fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx> } (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) => { - let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]); + let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8], ()); let allocation = tcx.mk_const_alloc(allocation); ConstValue::Slice { data: allocation, meta: allocation.inner().size().bytes() } } diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs index 47cb478fe33ee..1a91d6bd7da98 100644 --- a/compiler/rustc_mir_transform/src/large_enums.rs +++ b/compiler/rustc_mir_transform/src/large_enums.rs @@ -241,6 +241,7 @@ impl EnumSizeOpt { data, tcx.data_layout.ptr_sized_integer().align(&tcx.data_layout).abi, Mutability::Not, + (), ); let alloc = tcx.reserve_and_set_memory_alloc(tcx.mk_const_alloc(alloc)); Some((*adt_def, num_discrs, *alloc_cache.entry(ty).or_insert(alloc))) diff --git a/compiler/rustc_smir/src/rustc_smir/alloc.rs b/compiler/rustc_smir/src/rustc_smir/alloc.rs index 9cb89634c52e5..a6d31ac4e13dd 100644 --- a/compiler/rustc_smir/src/rustc_smir/alloc.rs +++ b/compiler/rustc_smir/src/rustc_smir/alloc.rs @@ -48,6 +48,7 @@ pub(crate) fn try_new_allocation<'tcx>( size, layout.align.abi, AllocInit::Uninit, + (), ); allocation .write_scalar(&tables.tcx, alloc_range(Size::ZERO, size), scalar) @@ -65,6 +66,7 @@ pub(crate) fn try_new_allocation<'tcx>( layout.size, layout.align.abi, AllocInit::Uninit, + (), ); allocation .write_scalar( diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 21bd7fb54c6cd..d2977a55e465f 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -139,7 +139,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { AllocKind::LiveData => { if memory_kind == MiriMemoryKind::Global.into() { // For new global allocations, we always pre-allocate the memory to be able use the machine address directly. - let prepared_bytes = MiriAllocBytes::zeroed(info.size, info.align) + let prepared_bytes = MiriAllocBytes::zeroed(info.size, info.align, ()) .unwrap_or_else(|| { panic!("Miri ran out of memory: cannot create allocation of {size:?} bytes", size = info.size) }); @@ -159,7 +159,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { AllocKind::Function | AllocKind::VTable => { // Allocate some dummy memory to get a unique address for this function/vtable. let alloc_bytes = - MiriAllocBytes::from_bytes(&[0u8; 1], Align::from_bytes(1).unwrap()); + MiriAllocBytes::from_bytes(&[0u8; 1], Align::from_bytes(1).unwrap(), ()); let ptr = alloc_bytes.as_ptr(); // Leak the underlying memory to ensure it remains unique. std::mem::forget(alloc_bytes); @@ -429,7 +429,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { prepared_alloc_bytes.copy_from_slice(bytes); interp_ok(prepared_alloc_bytes) } else { - interp_ok(MiriAllocBytes::from_bytes(std::borrow::Cow::Borrowed(bytes), align)) + interp_ok(MiriAllocBytes::from_bytes(std::borrow::Cow::Borrowed(bytes), align, ())) } } diff --git a/src/tools/miri/src/alloc_bytes.rs b/src/tools/miri/src/alloc_bytes.rs index 6788494c01cce..2bac2659ec09b 100644 --- a/src/tools/miri/src/alloc_bytes.rs +++ b/src/tools/miri/src/alloc_bytes.rs @@ -24,7 +24,7 @@ impl Clone for MiriAllocBytes { fn clone(&self) -> Self { let bytes: Cow<'_, [u8]> = Cow::Borrowed(self); let align = Align::from_bytes(self.layout.align().to_u64()).unwrap(); - MiriAllocBytes::from_bytes(bytes, align) + MiriAllocBytes::from_bytes(bytes, align, ()) } } @@ -86,7 +86,10 @@ impl MiriAllocBytes { } impl AllocBytes for MiriAllocBytes { - fn from_bytes<'a>(slice: impl Into>, align: Align) -> Self { + /// Placeholder! + type AllocParams = (); + + fn from_bytes<'a>(slice: impl Into>, align: Align, _params: ()) -> Self { let slice = slice.into(); let size = slice.len(); let align = align.bytes(); @@ -102,7 +105,7 @@ impl AllocBytes for MiriAllocBytes { alloc_bytes } - fn zeroed(size: Size, align: Align) -> Option { + fn zeroed(size: Size, align: Align, _params: ()) -> Option { let size = size.bytes(); let align = align.bytes(); // SAFETY: `alloc_fn` will only be used with `size != 0`. diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 8aa65e6cb612b..36fd20ee0a6fc 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -899,7 +899,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let mut alloc = alloc.inner().adjust_from_tcx( &this.tcx, |bytes, align| { - interp_ok(MiriAllocBytes::from_bytes(std::borrow::Cow::Borrowed(bytes), align)) + interp_ok(MiriAllocBytes::from_bytes(std::borrow::Cow::Borrowed(bytes), align, ())) }, |ptr| this.global_root_pointer(ptr), )?; diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index f75adffd9508e..131ecf2d0b910 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1804,6 +1804,9 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { ) -> Cow<'e, RangeSet> { Cow::Borrowed(ecx.machine.union_data_ranges.entry(ty).or_insert_with(compute_range)) } + + /// Placeholder! + fn get_default_alloc_params(&self) -> ::AllocParams { () } } /// Trait for callbacks handling asynchronous machine operations. From 93a509fca3071f50fae92e51dfcbccecb3c96e94 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Mon, 26 May 2025 00:21:04 +0200 Subject: [PATCH 2767/4206] exhaustive match instead of returns --- .../src/operators/modulo_arithmetic.rs | 29 +++++++------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/clippy_lints/src/operators/modulo_arithmetic.rs b/clippy_lints/src/operators/modulo_arithmetic.rs index 691d7b904eff5..8f28b7bb39039 100644 --- a/clippy_lints/src/operators/modulo_arithmetic.rs +++ b/clippy_lints/src/operators/modulo_arithmetic.rs @@ -60,31 +60,24 @@ fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_>, expr: &Expr<'_>) -> Some(Constant::Int(v)) => match *cx.typeck_results().expr_ty(expr).kind() { ty::Int(ity) => { let value = sext(cx.tcx, v, ity); - return Some(OperandInfo { + Some(OperandInfo { string_representation: Some(value.to_string()), is_negative: value < 0, is_integral: true, - }); + }) }, - ty::Uint(_) => { - return Some(OperandInfo { - string_representation: None, - is_negative: false, - is_integral: true, - }); - }, - _ => {}, + ty::Uint(_) => Some(OperandInfo { + string_representation: None, + is_negative: false, + is_integral: true, + }), + _ => None, }, // FIXME(f16_f128): add when casting is available on all platforms - Some(Constant::F32(f)) => { - return Some(floating_point_operand_info(&f)); - }, - Some(Constant::F64(f)) => { - return Some(floating_point_operand_info(&f)); - }, - _ => {}, + Some(Constant::F32(f)) => Some(floating_point_operand_info(&f)), + Some(Constant::F64(f)) => Some(floating_point_operand_info(&f)), + _ => None, } - None } fn floating_point_operand_info>(f: &T) -> OperandInfo { From b72cb4847b340d90d73c825b6e0a03f634b45efd Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Mon, 26 May 2025 00:24:38 +0200 Subject: [PATCH 2768/4206] use ? --- clippy_lints/src/operators/modulo_arithmetic.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/operators/modulo_arithmetic.rs b/clippy_lints/src/operators/modulo_arithmetic.rs index 8f28b7bb39039..d4c6f5a2e12ae 100644 --- a/clippy_lints/src/operators/modulo_arithmetic.rs +++ b/clippy_lints/src/operators/modulo_arithmetic.rs @@ -56,8 +56,8 @@ struct OperandInfo { } fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { - match ConstEvalCtxt::new(cx).eval(operand) { - Some(Constant::Int(v)) => match *cx.typeck_results().expr_ty(expr).kind() { + match ConstEvalCtxt::new(cx).eval(operand)? { + Constant::Int(v) => match *cx.typeck_results().expr_ty(expr).kind() { ty::Int(ity) => { let value = sext(cx.tcx, v, ity); Some(OperandInfo { @@ -74,8 +74,8 @@ fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_>, expr: &Expr<'_>) -> _ => None, }, // FIXME(f16_f128): add when casting is available on all platforms - Some(Constant::F32(f)) => Some(floating_point_operand_info(&f)), - Some(Constant::F64(f)) => Some(floating_point_operand_info(&f)), + Constant::F32(f) => Some(floating_point_operand_info(&f)), + Constant::F64(f) => Some(floating_point_operand_info(&f)), _ => None, } } From f04eb5984e779b9c5df79a26b8f94ab590409a9f Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Mon, 26 May 2025 00:21:20 +0200 Subject: [PATCH 2769/4206] use if-let --- clippy_lints/src/operators/modulo_arithmetic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/operators/modulo_arithmetic.rs b/clippy_lints/src/operators/modulo_arithmetic.rs index d4c6f5a2e12ae..44ac2a17e7e70 100644 --- a/clippy_lints/src/operators/modulo_arithmetic.rs +++ b/clippy_lints/src/operators/modulo_arithmetic.rs @@ -41,7 +41,7 @@ fn used_in_comparison_with_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { return false; }; - if op.node == BinOpKind::Eq || op.node == BinOpKind::Ne { + if let BinOpKind::Eq | BinOpKind::Ne = op.node { let ecx = ConstEvalCtxt::new(cx); matches!(ecx.eval(lhs), Some(Constant::Int(0))) || matches!(ecx.eval(rhs), Some(Constant::Int(0))) } else { From 028e1c28c90e6ac5294306a5ec97f698b5311107 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Mon, 26 May 2025 00:23:51 +0200 Subject: [PATCH 2770/4206] use let-chains --- clippy_lints/src/operators/modulo_arithmetic.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/operators/modulo_arithmetic.rs b/clippy_lints/src/operators/modulo_arithmetic.rs index 44ac2a17e7e70..b79461663d7bf 100644 --- a/clippy_lints/src/operators/modulo_arithmetic.rs +++ b/clippy_lints/src/operators/modulo_arithmetic.rs @@ -34,14 +34,10 @@ pub(super) fn check<'tcx>( } fn used_in_comparison_with_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - let Node::Expr(parent_expr) = cx.tcx.parent_hir_node(expr.hir_id) else { - return false; - }; - let ExprKind::Binary(op, lhs, rhs) = parent_expr.kind else { - return false; - }; - - if let BinOpKind::Eq | BinOpKind::Ne = op.node { + if let Node::Expr(parent_expr) = cx.tcx.parent_hir_node(expr.hir_id) + && let ExprKind::Binary(op, lhs, rhs) = parent_expr.kind + && let BinOpKind::Eq | BinOpKind::Ne = op.node + { let ecx = ConstEvalCtxt::new(cx); matches!(ecx.eval(lhs), Some(Constant::Int(0))) || matches!(ecx.eval(rhs), Some(Constant::Int(0))) } else { From 581fd271f6adc97999a73f2f06abde7db70f4abb Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 23 May 2025 05:21:42 +1000 Subject: [PATCH 2771/4206] Avoid `Box` in `href_relative_parts`. This reverts part of #91948, going back to returning a `UrlPartsBuilder`. It makes the code simpler, and also avoids some allocations. --- src/librustdoc/html/format.rs | 22 +++++++++------------- src/librustdoc/html/tests.rs | 22 +++++++++++----------- src/librustdoc/html/url_parts_builder.rs | 1 - 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 486d4ae932d97..1650a56bffb51 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -510,7 +510,7 @@ fn url_parts( builder.extend(module_fqp.iter().copied()); Ok(builder) } - ExternalLocation::Local => Ok(href_relative_parts(module_fqp, relative_to).collect()), + ExternalLocation::Local => Ok(href_relative_parts(module_fqp, relative_to)), ExternalLocation::Unknown => Err(HrefError::DocumentationNotBuilt), } } @@ -587,7 +587,7 @@ pub(crate) fn href_with_root_path( Some(&(ref fqp, shortty)) => (fqp, shortty, { let module_fqp = to_module_fqp(shortty, fqp.as_slice()); debug!(?fqp, ?shortty, ?module_fqp); - href_relative_parts(module_fqp, relative_to).collect() + href_relative_parts(module_fqp, relative_to) }), None => { // Associated items are handled differently with "jump to def". The anchor is generated @@ -619,34 +619,30 @@ pub(crate) fn href( /// Both paths should only be modules. /// This is because modules get their own directories; that is, `std::vec` and `std::vec::Vec` will /// both need `../iter/trait.Iterator.html` to get at the iterator trait. -pub(crate) fn href_relative_parts<'fqp>( - fqp: &'fqp [Symbol], - relative_to_fqp: &[Symbol], -) -> Box + 'fqp> { +pub(crate) fn href_relative_parts(fqp: &[Symbol], relative_to_fqp: &[Symbol]) -> UrlPartsBuilder { for (i, (f, r)) in fqp.iter().zip(relative_to_fqp.iter()).enumerate() { // e.g. linking to std::iter from std::vec (`dissimilar_part_count` will be 1) if f != r { let dissimilar_part_count = relative_to_fqp.len() - i; let fqp_module = &fqp[i..]; - return Box::new( - iter::repeat_n(sym::dotdot, dissimilar_part_count) - .chain(fqp_module.iter().copied()), - ); + return iter::repeat_n(sym::dotdot, dissimilar_part_count) + .chain(fqp_module.iter().copied()) + .collect(); } } match relative_to_fqp.len().cmp(&fqp.len()) { Ordering::Less => { // e.g. linking to std::sync::atomic from std::sync - Box::new(fqp[relative_to_fqp.len()..fqp.len()].iter().copied()) + fqp[relative_to_fqp.len()..fqp.len()].iter().copied().collect() } Ordering::Greater => { // e.g. linking to std::sync from std::sync::atomic let dissimilar_part_count = relative_to_fqp.len() - fqp.len(); - Box::new(iter::repeat_n(sym::dotdot, dissimilar_part_count)) + iter::repeat_n(sym::dotdot, dissimilar_part_count).collect() } Ordering::Equal => { // linking to the same module - Box::new(iter::empty()) + UrlPartsBuilder::new() } } } diff --git a/src/librustdoc/html/tests.rs b/src/librustdoc/html/tests.rs index b568942bbcb9b..873462bbeba8f 100644 --- a/src/librustdoc/html/tests.rs +++ b/src/librustdoc/html/tests.rs @@ -1,51 +1,51 @@ -use rustc_span::{Symbol, sym}; +use rustc_span::{Symbol, create_default_session_globals_then, sym}; use crate::html::format::href_relative_parts; -fn assert_relative_path(expected: &[Symbol], relative_to_fqp: &[Symbol], fqp: &[Symbol]) { - // No `create_default_session_globals_then` call is needed here because all - // the symbols used are static, and no `Symbol::intern` calls occur. - assert_eq!(expected, href_relative_parts(&fqp, &relative_to_fqp).collect::>()); +fn assert_relative_path(expected: &str, relative_to_fqp: &[Symbol], fqp: &[Symbol]) { + create_default_session_globals_then(|| { + assert_eq!(expected, href_relative_parts(&fqp, &relative_to_fqp).finish()); + }); } #[test] fn href_relative_parts_basic() { let relative_to_fqp = &[sym::std, sym::vec]; let fqp = &[sym::std, sym::iter]; - assert_relative_path(&[sym::dotdot, sym::iter], relative_to_fqp, fqp); + assert_relative_path("../iter", relative_to_fqp, fqp); } #[test] fn href_relative_parts_parent_module() { let relative_to_fqp = &[sym::std, sym::vec]; let fqp = &[sym::std]; - assert_relative_path(&[sym::dotdot], relative_to_fqp, fqp); + assert_relative_path("..", relative_to_fqp, fqp); } #[test] fn href_relative_parts_different_crate() { let relative_to_fqp = &[sym::std, sym::vec]; let fqp = &[sym::core, sym::iter]; - assert_relative_path(&[sym::dotdot, sym::dotdot, sym::core, sym::iter], relative_to_fqp, fqp); + assert_relative_path("../../core/iter", relative_to_fqp, fqp); } #[test] fn href_relative_parts_same_module() { let relative_to_fqp = &[sym::std, sym::vec]; let fqp = &[sym::std, sym::vec]; - assert_relative_path(&[], relative_to_fqp, fqp); + assert_relative_path("", relative_to_fqp, fqp); } #[test] fn href_relative_parts_child_module() { let relative_to_fqp = &[sym::std]; let fqp = &[sym::std, sym::vec]; - assert_relative_path(&[sym::vec], relative_to_fqp, fqp); + assert_relative_path("vec", relative_to_fqp, fqp); } #[test] fn href_relative_parts_root() { let relative_to_fqp = &[]; let fqp = &[sym::std]; - assert_relative_path(&[sym::std], relative_to_fqp, fqp); + assert_relative_path("std", relative_to_fqp, fqp); } diff --git a/src/librustdoc/html/url_parts_builder.rs b/src/librustdoc/html/url_parts_builder.rs index 1e6af6af63cc4..9a53382744154 100644 --- a/src/librustdoc/html/url_parts_builder.rs +++ b/src/librustdoc/html/url_parts_builder.rs @@ -14,7 +14,6 @@ pub(crate) struct UrlPartsBuilder { impl UrlPartsBuilder { /// Create an empty buffer. - #[allow(dead_code)] pub(crate) fn new() -> Self { Self { buf: String::new() } } From fa8e910ed915a207f58531b3bb5f3236a5836c4d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 26 May 2025 09:10:04 +1000 Subject: [PATCH 2772/4206] Simplify `make_href`. Currently it is passed an `fqp` slice which it calls `to_vec` on and returns. This is a bit odd. It's better to let the call site clone if necessary. (One call site does, one does not). --- src/librustdoc/html/format.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 1650a56bffb51..efd74d74f2c06 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -483,7 +483,7 @@ fn generate_item_def_id_path( let mut is_remote = false; let url_parts = url_parts(cx.cache(), def_id, module_fqp, &cx.current, &mut is_remote)?; - let (url_parts, shortty, fqp) = make_href(root_path, shortty, url_parts, &fqp, is_remote)?; + let (url_parts, shortty) = make_href(root_path, shortty, url_parts, &fqp, is_remote)?; if def_id == original_def_id { return Ok((url_parts, shortty, fqp)); } @@ -521,7 +521,7 @@ fn make_href( mut url_parts: UrlPartsBuilder, fqp: &[Symbol], is_remote: bool, -) -> Result<(String, ItemType, Vec), HrefError> { +) -> Result<(String, ItemType), HrefError> { if !is_remote && let Some(root_path) = root_path { let root = root_path.trim_end_matches('/'); url_parts.push_front(root); @@ -536,7 +536,7 @@ fn make_href( url_parts.push_fmt(format_args!("{shortty}.{last}.html")); } } - Ok((url_parts.finish(), shortty, fqp.to_vec())) + Ok((url_parts.finish(), shortty)) } pub(crate) fn href_with_root_path( @@ -607,6 +607,7 @@ pub(crate) fn href_with_root_path( } }; make_href(root_path, shortty, url_parts, fqp, is_remote) + .map(|(url_parts, short_ty)| (url_parts, short_ty, fqp.clone())) } pub(crate) fn href( From b8ce85391441701d73d42d593b81da178d239081 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 26 May 2025 09:15:57 +1000 Subject: [PATCH 2773/4206] Refactor the end of `generate_item_def_id_path`. To avoids the early return and duplication of `Ok((url_parts, shortty, fqp))`. --- src/librustdoc/html/format.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index efd74d74f2c06..88e90dfd2d324 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -483,12 +483,12 @@ fn generate_item_def_id_path( let mut is_remote = false; let url_parts = url_parts(cx.cache(), def_id, module_fqp, &cx.current, &mut is_remote)?; - let (url_parts, shortty) = make_href(root_path, shortty, url_parts, &fqp, is_remote)?; - if def_id == original_def_id { - return Ok((url_parts, shortty, fqp)); - } - let kind = ItemType::from_def_kind(original_def_kind, Some(def_kind)); - Ok((format!("{url_parts}#{kind}.{}", tcx.item_name(original_def_id)), shortty, fqp)) + let (mut url_parts, shortty) = make_href(root_path, shortty, url_parts, &fqp, is_remote)?; + if def_id != original_def_id { + let kind = ItemType::from_def_kind(original_def_kind, Some(def_kind)); + url_parts = format!("{url_parts}#{kind}.{}", tcx.item_name(original_def_id)) + }; + Ok((url_parts, shortty, fqp)) } fn to_module_fqp(shortty: ItemType, fqp: &[Symbol]) -> &[Symbol] { From f19d40a3d6f3344db34020ade05fc232aeae370a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 23 May 2025 07:07:29 +1000 Subject: [PATCH 2774/4206] Rename some methods. Most of the methods returning `impl Display` have `print` in their name. This commit renames a few that didn't follow that convention. --- src/librustdoc/html/format.rs | 16 +++++----- src/librustdoc/html/render/context.rs | 8 ++--- src/librustdoc/html/render/print_item.rs | 37 +++++++++++++++--------- 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 88e90dfd2d324..e64d339fabcae 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -705,13 +705,13 @@ fn resolved_path( f, "{path}::{anchor}", path = join_with_double_colon(&fqp[..fqp.len() - 1]), - anchor = anchor(did, *fqp.last().unwrap(), cx) + anchor = print_anchor(did, *fqp.last().unwrap(), cx) ) } else { write!(f, "{}", last.name) } } else { - write!(f, "{}", anchor(did, last.name, cx)) + write!(f, "{}", print_anchor(did, last.name, cx)) } }); write!(w, "{path}{args}", args = last.args.print(cx))?; @@ -797,7 +797,7 @@ fn primitive_link_fragment( Ok(()) } -fn tybounds( +fn print_tybounds( bounds: &[clean::PolyTrait], lt: &Option, cx: &Context<'_>, @@ -829,7 +829,7 @@ fn print_higher_ranked_params_with_space( }) } -pub(crate) fn anchor(did: DefId, text: Symbol, cx: &Context<'_>) -> impl Display { +pub(crate) fn print_anchor(did: DefId, text: Symbol, cx: &Context<'_>) -> impl Display { fmt::from_fn(move |f| { let parts = href(did, cx); if let Ok((url, short_ty, fqp)) = parts { @@ -863,7 +863,7 @@ fn fmt_type( } clean::DynTrait(bounds, lt) => { f.write_str("dyn ")?; - tybounds(bounds, lt, cx).fmt(f) + print_tybounds(bounds, lt, cx).fmt(f) } clean::Infer => write!(f, "_"), clean::Primitive(clean::PrimitiveType::Never) => { @@ -1128,7 +1128,7 @@ impl clean::Impl { self.print_type(inner_type, f, use_absolute, cx)?; write!(f, ">")?; } else { - write!(f, "{}<", anchor(ty.def_id(), last, cx))?; + write!(f, "{}<", print_anchor(ty.def_id(), last, cx))?; self.print_type(inner_type, f, use_absolute, cx)?; write!(f, ">")?; } @@ -1203,7 +1203,7 @@ impl clean::Impl { && self.kind.is_fake_variadic() { let ty = generics[0]; - let wrapper = anchor(path.def_id(), path.last(), cx); + let wrapper = print_anchor(path.def_id(), path.last(), cx); if f.alternate() { write!(f, "{wrapper:#}<")?; } else { @@ -1416,7 +1416,7 @@ pub(crate) fn visibility_print_with_space(item: &clean::Item, cx: &Context<'_>) debug!("path={path:?}"); // modified from `resolved_path()` to work with `DefPathData` let last_name = path.data.last().unwrap().data.get_opt_name().unwrap(); - let anchor = anchor(vis_did, last_name, cx); + let anchor = print_anchor(vis_did, last_name, cx); let mut s = "pub(in ".to_owned(); for seg in &path.data[..path.data.len() - 1] { diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 1f7201b8ca8b2..5984dcd74caf9 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -14,7 +14,7 @@ use rustc_span::edition::Edition; use rustc_span::{FileName, Symbol, sym}; use tracing::info; -use super::print_item::{full_path, item_path, print_item}; +use super::print_item::{full_path, print_item, print_item_path}; use super::sidebar::{ModuleLike, Sidebar, print_sidebar, sidebar_module_like}; use super::{AllTypes, LinkFromSrc, StylePath, collect_spans_and_sources, scrape_examples_help}; use crate::clean::types::ExternalLocation; @@ -266,7 +266,7 @@ impl<'tcx> Context<'tcx> { for name in &names[..names.len() - 1] { write!(f, "{name}/")?; } - write!(f, "{}", item_path(ty, names.last().unwrap().as_str())) + write!(f, "{}", print_item_path(ty, names.last().unwrap().as_str())) }); match self.shared.redirections { Some(ref redirections) => { @@ -278,7 +278,7 @@ impl<'tcx> Context<'tcx> { let _ = write!( current_path, "{}", - item_path(ty, names.last().unwrap().as_str()) + print_item_path(ty, names.last().unwrap().as_str()) ); redirections.borrow_mut().insert(current_path, path.to_string()); } @@ -847,7 +847,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { if !buf.is_empty() { let name = item.name.as_ref().unwrap(); let item_type = item.type_(); - let file_name = item_path(item_type, name.as_str()).to_string(); + let file_name = print_item_path(item_type, name.as_str()).to_string(); self.shared.ensure_dir(&self.dst)?; let joint_dst = self.dst.join(&file_name); self.shared.fs.write(joint_dst, buf)?; diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 39a631b637bd4..32f535e8e8cc0 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -413,7 +413,7 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i match myitem.kind { clean::ExternCrateItem { ref src } => { - use crate::html::format::anchor; + use crate::html::format::print_anchor; match *src { Some(src) => { @@ -421,7 +421,7 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i w, "
{}extern crate {} as {};", visibility_print_with_space(myitem, cx), - anchor(myitem.item_id.expect_def_id(), src, cx), + print_anchor(myitem.item_id.expect_def_id(), src, cx), EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()) )?; } @@ -430,7 +430,11 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i w, "
{}extern crate {};", visibility_print_with_space(myitem, cx), - anchor(myitem.item_id.expect_def_id(), myitem.name.unwrap(), cx) + print_anchor( + myitem.item_id.expect_def_id(), + myitem.name.unwrap(), + cx + ) )?; } } @@ -439,7 +443,7 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i clean::ImportItem(ref import) => { let stab_tags = import.source.did.map_or_else(String::new, |import_def_id| { - extra_info_tags(tcx, myitem, item, Some(import_def_id)).to_string() + print_extra_info_tags(tcx, myitem, item, Some(import_def_id)).to_string() }); let id = match import.kind { @@ -497,7 +501,9 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i write!( w, "
\ - {name}\ + \ + {name}\ + \ {visibility_and_hidden}\ {unsafety_flag}\ {stab_tags}\ @@ -505,11 +511,12 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i {docs_before}{docs}{docs_after}", name = EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()), visibility_and_hidden = visibility_and_hidden, - stab_tags = extra_info_tags(tcx, myitem, item, None), + stab_tags = print_extra_info_tags(tcx, myitem, item, None), class = myitem.type_(), unsafety_flag = unsafety_flag, - href = item_path(myitem.type_(), myitem.name.unwrap().as_str()), - title = format_args!("{} {}", myitem.type_(), full_path(cx, myitem)), + href = print_item_path(myitem.type_(), myitem.name.unwrap().as_str()), + title1 = myitem.type_(), + title2 = full_path(cx, myitem), )?; } } @@ -524,7 +531,7 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i /// Render the stability, deprecation and portability tags that are displayed in the item's summary /// at the module level. -fn extra_info_tags( +fn print_extra_info_tags( tcx: TyCtxt<'_>, item: &clean::Item, parent: &clean::Item, @@ -639,7 +646,7 @@ fn item_function(cx: &Context<'_>, it: &clean::Item, f: &clean::Function) -> imp fn item_trait(cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) -> impl fmt::Display { fmt::from_fn(|w| { let tcx = cx.tcx(); - let bounds = bounds(&t.bounds, false, cx); + let bounds = print_bounds(&t.bounds, false, cx); let required_types = t.items.iter().filter(|m| m.is_required_associated_type()).collect::>(); let provided_types = t.items.iter().filter(|m| m.is_associated_type()).collect::>(); @@ -1236,7 +1243,7 @@ fn item_trait_alias( attrs = render_attributes_in_pre(it, "", cx), name = it.name.unwrap(), generics = t.generics.print(cx), - bounds = bounds(&t.bounds, true, cx), + bounds = print_bounds(&t.bounds, true, cx), where_clause = print_where_clause(&t.generics, cx, 0, Ending::NoNewline).maybe_display(), ) @@ -2185,14 +2192,18 @@ pub(super) fn full_path(cx: &Context<'_>, item: &clean::Item) -> String { s } -pub(super) fn item_path(ty: ItemType, name: &str) -> impl Display { +pub(super) fn print_item_path(ty: ItemType, name: &str) -> impl Display { fmt::from_fn(move |f| match ty { ItemType::Module => write!(f, "{}index.html", ensure_trailing_slash(name)), _ => write!(f, "{ty}.{name}.html"), }) } -fn bounds(bounds: &[clean::GenericBound], trait_alias: bool, cx: &Context<'_>) -> impl Display { +fn print_bounds( + bounds: &[clean::GenericBound], + trait_alias: bool, + cx: &Context<'_>, +) -> impl Display { (!bounds.is_empty()) .then_some(fmt::from_fn(move |f| { let has_lots_of_bounds = bounds.len() > 2; From b71a1279a1a0238c8d4875c569721465823645a8 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 26 May 2025 08:08:50 +0300 Subject: [PATCH 2775/4206] dist: make sure llvm-project submodule is present Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/dist.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 253fa224152cc..7b5393a115a7b 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -2282,6 +2282,10 @@ impl Step for LlvmTools { } } + if !builder.config.dry_run() { + builder.require_submodule("src/llvm-project", None); + } + builder.ensure(crate::core::build_steps::llvm::Llvm { target }); let mut tarball = Tarball::new(builder, "llvm-tools", &target.triple); @@ -2400,6 +2404,10 @@ impl Step for RustDev { } } + if !builder.config.dry_run() { + builder.require_submodule("src/llvm-project", None); + } + let mut tarball = Tarball::new(builder, "rust-dev", &target.triple); tarball.set_overlay(OverlayKind::Llvm); // LLVM requires a shared object symlink to exist on some platforms. From b9b482e9d9ea18fa5dcb276c704fb9bec57b9e59 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 23 May 2025 11:55:47 +1000 Subject: [PATCH 2776/4206] Simplify `make_href`. It never fails, so it doesn't need to return `Result`. And the `ItemType` in the result is just a copy of the one passed in via the `shortty` arg, so it can also be removed. --- src/librustdoc/html/format.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index e64d339fabcae..1cb6e89218afe 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -483,7 +483,7 @@ fn generate_item_def_id_path( let mut is_remote = false; let url_parts = url_parts(cx.cache(), def_id, module_fqp, &cx.current, &mut is_remote)?; - let (mut url_parts, shortty) = make_href(root_path, shortty, url_parts, &fqp, is_remote)?; + let mut url_parts = make_href(root_path, shortty, url_parts, &fqp, is_remote); if def_id != original_def_id { let kind = ItemType::from_def_kind(original_def_kind, Some(def_kind)); url_parts = format!("{url_parts}#{kind}.{}", tcx.item_name(original_def_id)) @@ -521,7 +521,7 @@ fn make_href( mut url_parts: UrlPartsBuilder, fqp: &[Symbol], is_remote: bool, -) -> Result<(String, ItemType), HrefError> { +) -> String { if !is_remote && let Some(root_path) = root_path { let root = root_path.trim_end_matches('/'); url_parts.push_front(root); @@ -536,7 +536,7 @@ fn make_href( url_parts.push_fmt(format_args!("{shortty}.{last}.html")); } } - Ok((url_parts.finish(), shortty)) + url_parts.finish() } pub(crate) fn href_with_root_path( @@ -606,8 +606,8 @@ pub(crate) fn href_with_root_path( } } }; - make_href(root_path, shortty, url_parts, fqp, is_remote) - .map(|(url_parts, short_ty)| (url_parts, short_ty, fqp.clone())) + let url_parts = make_href(root_path, shortty, url_parts, &fqp, is_remote); + Ok((url_parts, shortty, fqp.clone())) } pub(crate) fn href( From 750f57fafe43a07758ecf8e2622ebba2967966ae Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 23 May 2025 13:42:10 +1000 Subject: [PATCH 2777/4206] Make `{Type,Path}::generics` return iterators. Instead of a `Vec`, to avoid some allocations. --- src/librustdoc/clean/types.rs | 20 +++++++------------- src/librustdoc/html/format.rs | 9 ++++----- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 07ecd98f77596..bfc02b6b1d428 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1601,9 +1601,7 @@ impl Type { a.def_id() == b.def_id() && a.generics() .zip(b.generics()) - .map(|(ag, bg)| { - ag.iter().zip(bg.iter()).all(|(at, bt)| at.is_doc_subtype_of(bt, cache)) - }) + .map(|(ag, bg)| ag.zip(bg).all(|(at, bt)| at.is_doc_subtype_of(bt, cache))) .unwrap_or(true) } // Other cases, such as primitives, just use recursion. @@ -1676,7 +1674,7 @@ impl Type { } } - pub(crate) fn generics(&self) -> Option> { + pub(crate) fn generics<'a>(&'a self) -> Option> { match self { Type::Path { path, .. } => path.generics(), _ => None, @@ -2234,17 +2232,13 @@ impl Path { self.segments.last().map(|seg| &seg.args) } - pub(crate) fn generics(&self) -> Option> { + pub(crate) fn generics<'a>(&'a self) -> Option> { self.segments.last().and_then(|seg| { if let GenericArgs::AngleBracketed { ref args, .. } = seg.args { - Some( - args.iter() - .filter_map(|arg| match arg { - GenericArg::Type(ty) => Some(ty), - _ => None, - }) - .collect(), - ) + Some(args.iter().filter_map(|arg| match arg { + GenericArg::Type(ty) => Some(ty), + _ => None, + })) } else { None } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 1cb6e89218afe..0d7a409d481a2 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1119,8 +1119,8 @@ impl clean::Impl { write!(f, "!")?; } if self.kind.is_fake_variadic() - && let generics = ty.generics() - && let &[inner_type] = generics.as_ref().map_or(&[][..], |v| &v[..]) + && let Some(mut generics) = ty.generics() + && let (Some(inner_type), None) = (generics.next(), generics.next()) { let last = ty.last(); if f.alternate() { @@ -1198,11 +1198,10 @@ impl clean::Impl { fmt_type(&bare_fn.decl.output, f, use_absolute, cx)?; } } else if let clean::Type::Path { path } = type_ - && let Some(generics) = path.generics() - && generics.len() == 1 + && let Some(mut generics) = path.generics() + && let (Some(ty), None) = (generics.next(), generics.next()) && self.kind.is_fake_variadic() { - let ty = generics[0]; let wrapper = print_anchor(path.def_id(), path.last(), cx); if f.alternate() { write!(f, "{wrapper:#}<")?; From 6b5b97a4df3331e82ee7f57f2c33818b997f98d0 Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 26 May 2025 13:47:53 +0800 Subject: [PATCH 2778/4206] Fix incorrect eq_unspanned in TokenStream --- compiler/rustc_ast/src/tokenstream.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 636c26bcde04b..7f2ba28f81bd8 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -696,14 +696,8 @@ impl TokenStream { /// Compares two `TokenStream`s, checking equality without regarding span information. pub fn eq_unspanned(&self, other: &TokenStream) -> bool { - let mut iter1 = self.iter(); - let mut iter2 = other.iter(); - for (tt1, tt2) in iter::zip(&mut iter1, &mut iter2) { - if !tt1.eq_unspanned(tt2) { - return false; - } - } - iter1.next().is_none() && iter2.next().is_none() + self.len() == other.len() + && self.iter().zip(other.iter()).all(|(tt1, tt2)| tt1.eq_unspanned(tt2)) } /// Create a token stream containing a single token with alone spacing. The From 4f1f1a2b57ae9dccca4af131def547bf1106f582 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 23 May 2025 16:22:07 +1000 Subject: [PATCH 2779/4206] Avoid some unnecessary cloning. --- src/librustdoc/clean/types.rs | 2 +- src/librustdoc/html/layout.rs | 1 - src/librustdoc/html/markdown.rs | 2 +- src/librustdoc/html/render/mod.rs | 12 ++++++------ src/librustdoc/html/render/print_item.rs | 4 ++-- src/librustdoc/html/render/write_shared.rs | 2 +- 6 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index bfc02b6b1d428..d27f0b9d00675 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -106,7 +106,7 @@ impl From for ItemId { } /// The crate currently being documented. -#[derive(Clone, Debug)] +#[derive(Debug)] pub(crate) struct Crate { pub(crate) module: Item, /// Only here so that they can be filtered through the rustdoc passes. diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 3b5f9b5a45897..50320cb231d2f 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -8,7 +8,6 @@ use super::static_files::{STATIC_FILES, StaticFiles}; use crate::externalfiles::ExternalHtml; use crate::html::render::{StylePath, ensure_trailing_slash}; -#[derive(Clone)] pub(crate) struct Layout { pub(crate) logo: String, pub(crate) favicon: String, diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index ad7dfafd90c7d..d6ad3545b6951 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -195,7 +195,7 @@ fn slugify(c: char) -> Option { } } -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct Playground { pub crate_name: Option, pub url: String, diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 06cb9269cc87f..dd6b58adf5212 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2530,7 +2530,7 @@ fn item_ty_to_section(ty: ItemType) -> ItemSection { /// types are re-exported, we don't use the corresponding /// entry from the js file, as inlining will have already /// picked up the impl -fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec { +fn collect_paths_for_type(first_ty: &clean::Type, cache: &Cache) -> Vec { let mut out = Vec::new(); let mut visited = FxHashSet::default(); let mut work = VecDeque::new(); @@ -2547,7 +2547,7 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec { work.push_back(first_ty); while let Some(ty) = work.pop_front() { - if !visited.insert(ty.clone()) { + if !visited.insert(ty) { continue; } @@ -2557,16 +2557,16 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec { work.extend(tys.into_iter()); } clean::Type::Slice(ty) => { - work.push_back(*ty); + work.push_back(ty); } clean::Type::Array(ty, _) => { - work.push_back(*ty); + work.push_back(ty); } clean::Type::RawPointer(_, ty) => { - work.push_back(*ty); + work.push_back(ty); } clean::Type::BorrowedRef { type_, .. } => { - work.push_back(*type_); + work.push_back(type_); } clean::Type::QPath(box clean::QPathData { self_type, trait_, .. }) => { work.push_back(self_type); diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 32f535e8e8cc0..fa3347c65d3fc 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -659,7 +659,7 @@ fn item_trait(cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) -> impl fmt: let count_types = required_types.len() + provided_types.len(); let count_consts = required_consts.len() + provided_consts.len(); let count_methods = required_methods.len() + provided_methods.len(); - let must_implement_one_of_functions = tcx.trait_def(t.def_id).must_implement_one_of.clone(); + let must_implement_one_of_functions = &tcx.trait_def(t.def_id).must_implement_one_of; // Output the trait definition wrap_item(w, |mut w| { @@ -1095,7 +1095,7 @@ fn item_trait(cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) -> impl fmt: it, &implementor_dups, &collect_paths_for_type( - implementor.inner_impl().for_.clone(), + &implementor.inner_impl().for_, &cx.shared.cache, ), ) diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 4f6e9abdbca06..76f52206b9916 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -760,7 +760,7 @@ impl TraitAliasPart { Some(Implementor { text: imp.inner_impl().print(false, cx).to_string(), synthetic: imp.inner_impl().kind.is_auto(), - types: collect_paths_for_type(imp.inner_impl().for_.clone(), cache), + types: collect_paths_for_type(&imp.inner_impl().for_, cache), }) } }) From 62435f922a0b0b100f217f13047d4741c14ec1c5 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Mon, 26 May 2025 15:20:59 +0800 Subject: [PATCH 2780/4206] impl `Default` for `array::IntoIter` --- library/core/src/array/iter.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index 90f76d6d4c7be..a59b2f05305d2 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -224,6 +224,13 @@ impl IntoIter { } } +#[stable(feature = "array_value_iter_default", since = "CURRENT_RUSTC_VERSION")] +impl Default for IntoIter { + fn default() -> Self { + IntoIter::empty() + } +} + #[stable(feature = "array_value_iter_impls", since = "1.40.0")] impl Iterator for IntoIter { type Item = T; From 3efd885927958ec8af33fbd1fa2da3d62bbae108 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 22 May 2025 18:55:49 +0000 Subject: [PATCH 2781/4206] Avoid obligation construction dance with query region constraints --- .../rustc_hir_analysis/src/check/wfcheck.rs | 2 +- .../src/infer/canonical/query_response.rs | 62 +++---------------- compiler/rustc_infer/src/infer/context.rs | 2 +- compiler/rustc_infer/src/infer/mod.rs | 13 ---- .../src/infer/outlives/obligations.rs | 34 +++++++++- .../src/solve/delegate.rs | 2 +- .../src/traits/auto_trait.rs | 8 ++- .../src/traits/fulfill.rs | 4 +- .../src/traits/outlives_bounds.rs | 21 +------ 9 files changed, 52 insertions(+), 96 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 2ec14b2f018c3..248af02f86dec 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -742,7 +742,7 @@ fn ty_known_to_outlive<'tcx>( region: ty::Region<'tcx>, ) -> bool { test_region_obligations(tcx, id, param_env, wf_tys, |infcx| { - infcx.register_region_obligation(infer::RegionObligation { + infcx.type_outlives_predicate(infer::RegionObligation { sub_region: region, sup_type: ty, origin: infer::RelateParamBound(DUMMY_SP, ty, None), diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index e9cfc96ba508a..c7cb1c39a9c53 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -12,23 +12,20 @@ use std::iter; use rustc_index::{Idx, IndexVec}; use rustc_middle::arena::ArenaAllocatable; +use rustc_middle::bug; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::{self, BoundVar, GenericArg, GenericArgKind, Ty, TyCtxt, TypeFoldable}; -use rustc_middle::{bug, span_bug}; use tracing::{debug, instrument}; use crate::infer::canonical::instantiate::{CanonicalExt, instantiate_value}; use crate::infer::canonical::{ Canonical, CanonicalQueryResponse, CanonicalVarValues, Certainty, OriginalQueryValues, - QueryOutlivesConstraint, QueryRegionConstraints, QueryResponse, + QueryRegionConstraints, QueryResponse, }; use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult, SubregionOrigin}; use crate::traits::query::NoSolution; -use crate::traits::{ - Obligation, ObligationCause, PredicateObligation, PredicateObligations, ScrubbedTraitError, - TraitEngine, -}; +use crate::traits::{ObligationCause, PredicateObligations, ScrubbedTraitError, TraitEngine}; impl<'tcx> InferCtxt<'tcx> { /// This method is meant to be invoked as the final step of a canonical query @@ -169,15 +166,13 @@ impl<'tcx> InferCtxt<'tcx> { where R: Debug + TypeFoldable>, { - let InferOk { value: result_args, mut obligations } = + let InferOk { value: result_args, obligations } = self.query_response_instantiation(cause, param_env, original_values, query_response)?; - obligations.extend(self.query_outlives_constraints_into_obligations( - cause, - param_env, - &query_response.value.region_constraints.outlives, - &result_args, - )); + for (predicate, _category) in &query_response.value.region_constraints.outlives { + let predicate = instantiate_value(self.tcx, &result_args, *predicate); + self.outlives_predicate_with_cause(predicate, cause); + } let user_result: R = query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone()); @@ -525,47 +520,6 @@ impl<'tcx> InferCtxt<'tcx> { self.unify_canonical_vars(cause, param_env, original_values, instantiated_query_response) } - /// Converts the region constraints resulting from a query into an - /// iterator of obligations. - fn query_outlives_constraints_into_obligations( - &self, - cause: &ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - uninstantiated_region_constraints: &[QueryOutlivesConstraint<'tcx>], - result_args: &CanonicalVarValues<'tcx>, - ) -> impl Iterator> { - uninstantiated_region_constraints.iter().map(move |&constraint| { - let predicate = instantiate_value(self.tcx, result_args, constraint); - self.query_outlives_constraint_to_obligation(predicate, cause.clone(), param_env) - }) - } - - pub fn query_outlives_constraint_to_obligation( - &self, - (predicate, _): QueryOutlivesConstraint<'tcx>, - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> Obligation<'tcx, ty::Predicate<'tcx>> { - let ty::OutlivesPredicate(k1, r2) = predicate; - - let atom = match k1.unpack() { - GenericArgKind::Lifetime(r1) => ty::PredicateKind::Clause( - ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2)), - ), - GenericArgKind::Type(t1) => ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives( - ty::OutlivesPredicate(t1, r2), - )), - GenericArgKind::Const(..) => { - // Consts cannot outlive one another, so we don't expect to - // encounter this branch. - span_bug!(cause.span, "unexpected const outlives {:?}", predicate); - } - }; - let predicate = ty::Binder::dummy(atom); - - Obligation::new(self.tcx, cause, param_env, predicate) - } - /// Given two sets of values for the same set of canonical variables, unify them. /// The second set is produced lazily by supplying indices from the first set. fn unify_canonical_vars( diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 359b9da11ced6..c151fee2cd52e 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -214,7 +214,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { } fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>, span: Span) { - self.register_region_obligation_with_cause(ty, r, &ObligationCause::dummy_with_span(span)); + self.type_outlives_predicate_with_cause(ty, r, &ObligationCause::dummy_with_span(span)); } type OpaqueTypeStorageEntries = OpaqueTypeStorageEntries; diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index b408d76010d7b..30ac033328758 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -738,19 +738,6 @@ impl<'tcx> InferCtxt<'tcx> { }) } - pub fn region_outlives_predicate( - &self, - cause: &traits::ObligationCause<'tcx>, - predicate: ty::PolyRegionOutlivesPredicate<'tcx>, - ) { - self.enter_forall(predicate, |ty::OutlivesPredicate(r_a, r_b)| { - let origin = SubregionOrigin::from_obligation_cause(cause, || { - RelateRegionParamBound(cause.span, None) - }); - self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b` - }) - } - /// Number of type variables created so far. pub fn num_ty_vars(&self) -> usize { self.inner.borrow_mut().type_variables().num_vars() diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 5fd98e35e5ce8..3786a36c9fdbb 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -80,19 +80,47 @@ use crate::infer::{self, GenericKind, InferCtxt, RegionObligation, SubregionOrig use crate::traits::{ObligationCause, ObligationCauseCode}; impl<'tcx> InferCtxt<'tcx> { + pub fn outlives_predicate_with_cause( + &self, + ty::OutlivesPredicate(arg, r2): ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, + cause: &ObligationCause<'tcx>, + ) { + match arg.unpack() { + ty::GenericArgKind::Lifetime(r1) => { + self.region_outlives_predicate(ty::OutlivesPredicate(r1, r2), cause); + } + ty::GenericArgKind::Type(ty1) => { + self.type_outlives_predicate_with_cause(ty1, r2, cause); + } + ty::GenericArgKind::Const(_) => unreachable!(), + } + } + + pub fn region_outlives_predicate( + &self, + ty::OutlivesPredicate(r_a, r_b): ty::RegionOutlivesPredicate<'tcx>, + cause: &ObligationCause<'tcx>, + ) { + let origin = SubregionOrigin::from_obligation_cause(cause, || { + SubregionOrigin::RelateRegionParamBound(cause.span, None) + }); + // `b : a` ==> `a <= b` + self.sub_regions(origin, r_b, r_a); + } + /// Registers that the given region obligation must be resolved /// from within the scope of `body_id`. These regions are enqueued /// and later processed by regionck, when full type information is /// available (see `region_obligations` field for more /// information). #[instrument(level = "debug", skip(self))] - pub fn register_region_obligation(&self, obligation: RegionObligation<'tcx>) { + pub fn type_outlives_predicate(&self, obligation: RegionObligation<'tcx>) { let mut inner = self.inner.borrow_mut(); inner.undo_log.push(UndoLog::PushRegionObligation); inner.region_obligations.push(obligation); } - pub fn register_region_obligation_with_cause( + pub fn type_outlives_predicate_with_cause( &self, sup_type: Ty<'tcx>, sub_region: Region<'tcx>, @@ -124,7 +152,7 @@ impl<'tcx> InferCtxt<'tcx> { ) }); - self.register_region_obligation(RegionObligation { sup_type, sub_region, origin }); + self.type_outlives_predicate(RegionObligation { sup_type, sub_region, origin }); } /// Trait queries just want to pass back type obligations "as is" diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index b68a784536604..e66d1c0412720 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -76,7 +76,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< Some(HasChanged::No) } ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => { - self.0.register_region_obligation_with_cause( + self.0.type_outlives_predicate_with_cause( outlives.0, outlives.1, &ObligationCause::dummy_with_span(span), diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 02521c9453d98..620c15917377d 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -726,7 +726,9 @@ impl<'tcx> AutoTraitFinder<'tcx> { } ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(binder)) => { let binder = bound_predicate.rebind(binder); - selcx.infcx.region_outlives_predicate(&dummy_cause, binder) + selcx.infcx.enter_forall(binder, |pred| { + selcx.infcx.region_outlives_predicate(pred, &dummy_cause); + }); } ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(binder)) => { let binder = bound_predicate.rebind(binder); @@ -735,14 +737,14 @@ impl<'tcx> AutoTraitFinder<'tcx> { binder.map_bound_ref(|pred| pred.0).no_bound_vars(), ) { (None, Some(t_a)) => { - selcx.infcx.register_region_obligation_with_cause( + selcx.infcx.type_outlives_predicate_with_cause( t_a, selcx.infcx.tcx.lifetimes.re_static, &dummy_cause, ); } (Some(ty::OutlivesPredicate(t_a, r_b)), _) => { - selcx.infcx.register_region_obligation_with_cause( + selcx.infcx.type_outlives_predicate_with_cause( t_a, r_b, &dummy_cause, diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 34c3c905bd977..e210bfbefba2d 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -428,7 +428,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(data)) => { if infcx.considering_regions { - infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data)); + infcx.region_outlives_predicate(data, &obligation.cause); } ProcessResult::Changed(Default::default()) @@ -439,7 +439,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { r_b, ))) => { if infcx.considering_regions { - infcx.register_region_obligation_with_cause(t_a, r_b, &obligation.cause); + infcx.type_outlives_predicate_with_cause(t_a, r_b, &obligation.cause); } ProcessResult::Changed(Default::default()) } diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 68983ef80fa48..8641206abb9cd 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -9,7 +9,7 @@ use rustc_span::def_id::LocalDefId; use tracing::instrument; use crate::infer::InferCtxt; -use crate::traits::{ObligationCause, ObligationCtxt}; +use crate::traits::ObligationCause; /// Implied bounds are region relationships that we deduce /// automatically. The idea is that (e.g.) a caller must check that a @@ -79,24 +79,9 @@ fn implied_outlives_bounds<'a, 'tcx>( if !constraints.is_empty() { let QueryRegionConstraints { outlives } = constraints; - // Instantiation may have produced new inference variables and constraints on those - // variables. Process these constraints. - let ocx = ObligationCtxt::new(infcx); let cause = ObligationCause::misc(span, body_id); - for &constraint in &outlives { - ocx.register_obligation(infcx.query_outlives_constraint_to_obligation( - constraint, - cause.clone(), - param_env, - )); - } - - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { - infcx.dcx().span_bug( - span, - "implied_outlives_bounds failed to solve obligations from instantiation", - ); + for &(predicate, _) in &outlives { + infcx.outlives_predicate_with_cause(predicate, &cause); } }; From 4d783c3c193129350425a08fcdb0921b1e0d74a8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 25 May 2025 11:06:14 +0000 Subject: [PATCH 2782/4206] Don't retry in pred_known_to_hold_modulo_regions in new solver, since new solver is more complete Just a totally unrelated nitpick I'm folding into the PR, since it's code I'd like for us to prune when the new solver lands. --- compiler/rustc_trait_selection/src/traits/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index a9bdb909bdcf7..999ef97683ca8 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -221,7 +221,7 @@ fn pred_known_to_hold_modulo_regions<'tcx>( if result.must_apply_modulo_regions() { true - } else if result.may_apply() { + } else if result.may_apply() && !infcx.next_trait_solver() { // Sometimes obligations are ambiguous because the recursive evaluator // is not smart enough, so we fall back to fulfillment when we're not certain // that an obligation holds or not. Even still, we must make sure that From 9d742eea252f25a7b6719618cc154074dba16063 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 26 May 2025 08:36:17 +0000 Subject: [PATCH 2783/4206] Rename --- .../rustc_hir_analysis/src/check/wfcheck.rs | 2 +- .../src/infer/canonical/query_response.rs | 2 +- compiler/rustc_infer/src/infer/context.rs | 2 +- compiler/rustc_infer/src/infer/mod.rs | 6 ++-- .../src/infer/outlives/obligations.rs | 33 ++++++++++++------- .../src/infer/snapshot/undo_log.rs | 4 +-- .../src/solve/eval_ctxt/mod.rs | 2 +- .../src/solve/delegate.rs | 2 +- .../src/traits/auto_trait.rs | 6 ++-- .../src/traits/fulfill.rs | 4 +-- .../src/traits/outlives_bounds.rs | 2 +- .../query/type_op/implied_outlives_bounds.rs | 4 +-- 12 files changed, 39 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 248af02f86dec..06c5e518fc646 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -742,7 +742,7 @@ fn ty_known_to_outlive<'tcx>( region: ty::Region<'tcx>, ) -> bool { test_region_obligations(tcx, id, param_env, wf_tys, |infcx| { - infcx.type_outlives_predicate(infer::RegionObligation { + infcx.register_type_outlives_constraint_inner(infer::TypeOutlivesConstraint { sub_region: region, sup_type: ty, origin: infer::RelateParamBound(DUMMY_SP, ty, None), diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index c7cb1c39a9c53..bda33f3f455b0 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -171,7 +171,7 @@ impl<'tcx> InferCtxt<'tcx> { for (predicate, _category) in &query_response.value.region_constraints.outlives { let predicate = instantiate_value(self.tcx, &result_args, *predicate); - self.outlives_predicate_with_cause(predicate, cause); + self.register_outlives_constraint(predicate, cause); } let user_result: R = diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index c151fee2cd52e..f7fe32a06e63e 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -214,7 +214,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { } fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>, span: Span) { - self.type_outlives_predicate_with_cause(ty, r, &ObligationCause::dummy_with_span(span)); + self.register_type_outlives_constraint(ty, r, &ObligationCause::dummy_with_span(span)); } type OpaqueTypeStorageEntries = OpaqueTypeStorageEntries; diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 30ac033328758..8fb25cb9b32fa 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -150,7 +150,7 @@ pub struct InferCtxtInner<'tcx> { /// for each body-id in this map, which will process the /// obligations within. This is expected to be done 'late enough' /// that all type inference variables have been bound and so forth. - region_obligations: Vec>, + region_obligations: Vec>, /// Caches for opaque type inference. opaque_type_storage: OpaqueTypeStorage<'tcx>, @@ -173,7 +173,7 @@ impl<'tcx> InferCtxtInner<'tcx> { } #[inline] - pub fn region_obligations(&self) -> &[RegionObligation<'tcx>] { + pub fn region_obligations(&self) -> &[TypeOutlivesConstraint<'tcx>] { &self.region_obligations } @@ -488,7 +488,7 @@ impl fmt::Display for FixupError { /// See the `region_obligations` field for more information. #[derive(Clone, Debug)] -pub struct RegionObligation<'tcx> { +pub struct TypeOutlivesConstraint<'tcx> { pub sub_region: ty::Region<'tcx>, pub sup_type: Ty<'tcx>, pub origin: SubregionOrigin<'tcx>, diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 3786a36c9fdbb..890902af02bc6 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -76,27 +76,29 @@ use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::outlives::verify::VerifyBoundCx; use crate::infer::resolve::OpportunisticRegionResolver; use crate::infer::snapshot::undo_log::UndoLog; -use crate::infer::{self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, VerifyBound}; +use crate::infer::{ + self, GenericKind, InferCtxt, SubregionOrigin, TypeOutlivesConstraint, VerifyBound, +}; use crate::traits::{ObligationCause, ObligationCauseCode}; impl<'tcx> InferCtxt<'tcx> { - pub fn outlives_predicate_with_cause( + pub fn register_outlives_constraint( &self, ty::OutlivesPredicate(arg, r2): ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, cause: &ObligationCause<'tcx>, ) { match arg.unpack() { ty::GenericArgKind::Lifetime(r1) => { - self.region_outlives_predicate(ty::OutlivesPredicate(r1, r2), cause); + self.register_region_outlives_constraint(ty::OutlivesPredicate(r1, r2), cause); } ty::GenericArgKind::Type(ty1) => { - self.type_outlives_predicate_with_cause(ty1, r2, cause); + self.register_type_outlives_constraint(ty1, r2, cause); } ty::GenericArgKind::Const(_) => unreachable!(), } } - pub fn region_outlives_predicate( + pub fn register_region_outlives_constraint( &self, ty::OutlivesPredicate(r_a, r_b): ty::RegionOutlivesPredicate<'tcx>, cause: &ObligationCause<'tcx>, @@ -104,7 +106,7 @@ impl<'tcx> InferCtxt<'tcx> { let origin = SubregionOrigin::from_obligation_cause(cause, || { SubregionOrigin::RelateRegionParamBound(cause.span, None) }); - // `b : a` ==> `a <= b` + // `'a: 'b` ==> `'b <= 'a` self.sub_regions(origin, r_b, r_a); } @@ -114,13 +116,16 @@ impl<'tcx> InferCtxt<'tcx> { /// available (see `region_obligations` field for more /// information). #[instrument(level = "debug", skip(self))] - pub fn type_outlives_predicate(&self, obligation: RegionObligation<'tcx>) { + pub fn register_type_outlives_constraint_inner( + &self, + obligation: TypeOutlivesConstraint<'tcx>, + ) { let mut inner = self.inner.borrow_mut(); - inner.undo_log.push(UndoLog::PushRegionObligation); + inner.undo_log.push(UndoLog::PushTypeOutlivesConstraint); inner.region_obligations.push(obligation); } - pub fn type_outlives_predicate_with_cause( + pub fn register_type_outlives_constraint( &self, sup_type: Ty<'tcx>, sub_region: Region<'tcx>, @@ -152,11 +157,15 @@ impl<'tcx> InferCtxt<'tcx> { ) }); - self.type_outlives_predicate(RegionObligation { sup_type, sub_region, origin }); + self.register_type_outlives_constraint_inner(TypeOutlivesConstraint { + sup_type, + sub_region, + origin, + }); } /// Trait queries just want to pass back type obligations "as is" - pub fn take_registered_region_obligations(&self) -> Vec> { + pub fn take_registered_region_obligations(&self) -> Vec> { std::mem::take(&mut self.inner.borrow_mut().region_obligations) } @@ -194,7 +203,7 @@ impl<'tcx> InferCtxt<'tcx> { ); } - for RegionObligation { sup_type, sub_region, origin } in my_region_obligations { + for TypeOutlivesConstraint { sup_type, sub_region, origin } in my_region_obligations { let outlives = ty::Binder::dummy(ty::OutlivesPredicate(sup_type, sub_region)); let ty::OutlivesPredicate(sup_type, sub_region) = deeply_normalize_ty(outlives, origin.clone()) diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs index b7412d3d6a6da..6193f35f3eb60 100644 --- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs +++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs @@ -26,7 +26,7 @@ pub(crate) enum UndoLog<'tcx> { RegionConstraintCollector(region_constraints::UndoLog<'tcx>), RegionUnificationTable(sv::UndoLog>>), ProjectionCache(traits::UndoLog<'tcx>), - PushRegionObligation, + PushTypeOutlivesConstraint, } macro_rules! impl_from { @@ -72,7 +72,7 @@ impl<'tcx> Rollback> for InferCtxtInner<'tcx> { self.region_constraint_storage.as_mut().unwrap().unification_table.reverse(undo) } UndoLog::ProjectionCache(undo) => self.projection_cache.reverse(undo), - UndoLog::PushRegionObligation => { + UndoLog::PushTypeOutlivesConstraint => { self.region_obligations.pop(); } } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index dfabb94ebfc60..ef955410247fc 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -1024,7 +1024,7 @@ where } pub(super) fn register_region_outlives(&self, a: I::Region, b: I::Region) { - // `b : a` ==> `a <= b` + // `'a: 'b` ==> `'b <= 'a` self.delegate.sub_regions(b, a, self.origin_span); } diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index e66d1c0412720..eea311fe66ebb 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -76,7 +76,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< Some(HasChanged::No) } ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => { - self.0.type_outlives_predicate_with_cause( + self.0.register_type_outlives_constraint( outlives.0, outlives.1, &ObligationCause::dummy_with_span(span), diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 620c15917377d..3ae908ec16b8e 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -727,7 +727,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(binder)) => { let binder = bound_predicate.rebind(binder); selcx.infcx.enter_forall(binder, |pred| { - selcx.infcx.region_outlives_predicate(pred, &dummy_cause); + selcx.infcx.register_region_outlives_constraint(pred, &dummy_cause); }); } ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(binder)) => { @@ -737,14 +737,14 @@ impl<'tcx> AutoTraitFinder<'tcx> { binder.map_bound_ref(|pred| pred.0).no_bound_vars(), ) { (None, Some(t_a)) => { - selcx.infcx.type_outlives_predicate_with_cause( + selcx.infcx.register_type_outlives_constraint( t_a, selcx.infcx.tcx.lifetimes.re_static, &dummy_cause, ); } (Some(ty::OutlivesPredicate(t_a, r_b)), _) => { - selcx.infcx.type_outlives_predicate_with_cause( + selcx.infcx.register_type_outlives_constraint( t_a, r_b, &dummy_cause, diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index e210bfbefba2d..951dfb879aed7 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -428,7 +428,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(data)) => { if infcx.considering_regions { - infcx.region_outlives_predicate(data, &obligation.cause); + infcx.register_region_outlives_constraint(data, &obligation.cause); } ProcessResult::Changed(Default::default()) @@ -439,7 +439,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { r_b, ))) => { if infcx.considering_regions { - infcx.type_outlives_predicate_with_cause(t_a, r_b, &obligation.cause); + infcx.register_type_outlives_constraint(t_a, r_b, &obligation.cause); } ProcessResult::Changed(Default::default()) } diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 8641206abb9cd..59d3ac21387f5 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -81,7 +81,7 @@ fn implied_outlives_bounds<'a, 'tcx>( let QueryRegionConstraints { outlives } = constraints; let cause = ObligationCause::misc(span, body_id); for &(predicate, _) in &outlives { - infcx.outlives_predicate_with_cause(predicate, &cause); + infcx.register_outlives_constraint(predicate, &cause); } }; diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index d9b57f0c67d14..e294f7839aac7 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -1,6 +1,6 @@ use std::ops::ControlFlow; -use rustc_infer::infer::RegionObligation; +use rustc_infer::infer::TypeOutlivesConstraint; use rustc_infer::infer::canonical::CanonicalQueryInput; use rustc_infer::traits::query::OutlivesBound; use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds; @@ -141,7 +141,7 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( && !ocx.infcx.tcx.sess.opts.unstable_opts.no_implied_bounds_compat && ty.visit_with(&mut ContainsBevyParamSet { tcx: ocx.infcx.tcx }).is_break() { - for RegionObligation { sup_type, sub_region, .. } in + for TypeOutlivesConstraint { sup_type, sub_region, .. } in ocx.infcx.take_registered_region_obligations() { let mut components = smallvec![]; From 44612c5f9cbd21ebe60dab93f3c536084c4bf495 Mon Sep 17 00:00:00 2001 From: vremyavnikuda Date: Sun, 25 May 2025 15:28:07 +0700 Subject: [PATCH 2784/4206] docs: add documentation for find_all_refs constructor search (#10725) --- src/tools/rust-analyzer/crates/ide/src/lib.rs | 71 ++++++++++++++- .../crates/ide/src/references.rs | 90 ++++++++++++++++++- 2 files changed, 158 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index d649dffbd90c2..6e35084ceb3fb 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -514,7 +514,76 @@ impl Analysis { self.with_db(|db| goto_type_definition::goto_type_definition(db, position)) } - /// Finds all usages of the reference at point. + /// Find all references to the item at the cursor position. + /// + /// # Examples + /// + /// Basic struct reference search: + /// ```rust + /// struct S { + /// pub x: usize, + /// } + /// + /// fn print_s(s: S) { + /// println!("{}", s.x) + /// } + /// + /// fn main() { + /// let s = S { x: 42 }; // This is a constructor usage + /// print_s(s); // This is a type reference + /// } + /// ``` + /// + /// To find only constructor/initialization usages: + /// 1. Position cursor on special tokens in struct/enum definition: + /// ```rust + /// // On '{' - finds record struct initializations + /// struct Point { // <- cursor here on '{' + /// x: i32, + /// y: i32, + /// } + /// + /// // On '(' - finds tuple struct initializations + /// struct Tuple(i32, i32); // <- cursor here on '(' + /// + /// // On ';' - finds unit struct initializations + /// struct Unit; // <- cursor here on ';' + /// ``` + /// + /// 2. Examples of what will be found: + /// ```rust + /// struct Point{x: i32, y: i32}; + /// struct Tuple(i32, i32); + /// struct Unit; + /// + /// + /// let p1 = Point { x: 0, y: 0 }; // Found when cursor on '{' + /// let p2 = Tuple(1, 2); // Found when cursor on '(' + /// let u = Unit; // Found when cursor on ';' + /// ``` + /// + /// 3. For enum variants: + /// ```rust + /// enum E { + /// Struct { // <- cursor here on '{' + /// x: i32 + /// }, + /// Tuple(i32), // <- cursor here on '(' + /// Unit // <- cursor here on identifier + /// } + /// + /// let e1 = E::Struct { x: 0 }; // Found for Struct variant + /// let e2 = E::Tuple(1); // Found for Tuple variant + /// let e3 = E::Unit; // Found for Unit variant + /// ``` + /// + /// # Parameters + /// * `position` - The position in the file to find references for + /// * `search_scope` - Optional scope to limit the search + /// + /// # Returns + /// Returns a vector of reference search results if references are found, + /// or None if no valid item is found at the position. pub fn find_all_refs( &self, position: FilePosition, diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index 4fa116444b7ff..91f4d752c8d59 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -8,6 +8,14 @@ //! for text occurrences of the identifier. If there's an `ast::NameRef` //! at the index that the match starts at and its tree parent is //! resolved to the search element definition, we get a reference. +//! +//! Special handling for constructors/initializations: +//! When searching for references to a struct/enum/variant, if the cursor is positioned on: +//! - `{` after a struct/enum/variant definition +//! - `(` for tuple structs/variants +//! - `;` for unit structs +//! - The type name in a struct/enum/variant definition +//! Then only constructor/initialization usages will be shown, filtering out other references. use hir::{PathResolution, Semantics}; use ide_db::{ @@ -28,27 +36,76 @@ use syntax::{ use crate::{FilePosition, HighlightedRange, NavigationTarget, TryToNav, highlight_related}; +/// Result of a reference search operation. #[derive(Debug, Clone)] pub struct ReferenceSearchResult { + /// Information about the declaration site of the searched item. + /// For ADTs (structs/enums), this points to the type definition. + /// May be None for primitives or items without clear declaration sites. pub declaration: Option, + /// All references found, grouped by file. + /// For ADTs when searching from a constructor position (e.g. on '{', '(', ';'), + /// this only includes constructor/initialization usages. + /// The map key is the file ID, and the value is a vector of (range, category) pairs. + /// - range: The text range of the reference in the file + /// - category: Metadata about how the reference is used (read/write/etc) pub references: IntMap>, } +/// Information about the declaration site of a searched item. #[derive(Debug, Clone)] pub struct Declaration { + /// Navigation information to jump to the declaration pub nav: NavigationTarget, + /// Whether the declared item is mutable (relevant for variables) pub is_mut: bool, } // Feature: Find All References // -// Shows all references of the item at the cursor location +// Shows all references of the item at the cursor location. This includes: +// - Direct references to variables, functions, types, etc. +// - Constructor/initialization references when cursor is on struct/enum definition tokens +// - References in patterns and type contexts +// - References through dereferencing and borrowing +// - References in macro expansions +// +// Special handling for constructors: +// - When the cursor is on `{`, `(`, or `;` in a struct/enum definition +// - When the cursor is on the type name in a struct/enum definition +// These cases will show only constructor/initialization usages of the type // // | Editor | Shortcut | // |---------|----------| // | VS Code | Shift+Alt+F12 | // // ![Find All References](https://user-images.githubusercontent.com/48062697/113020670-b7c34f00-917a-11eb-8003-370ac5f2b3cb.gif) + +/// Find all references to the item at the given position. +/// +/// # Arguments +/// * `sema` - Semantic analysis context +/// * `position` - Position in the file where to look for the item +/// * `search_scope` - Optional scope to limit the search (e.g. current crate only) +/// +/// # Returns +/// Returns `None` if no valid item is found at the position. +/// Otherwise returns a vector of `ReferenceSearchResult`, usually with one element. +/// Multiple results can occur in case of ambiguity or when searching for trait items. +/// +/// # Special cases +/// - Control flow keywords (break, continue, etc): Shows all related jump points +/// - Constructor search: When on struct/enum definition tokens (`{`, `(`, `;`), shows only initialization sites +/// - Format string arguments: Shows template parameter usages +/// - Lifetime parameters: Shows lifetime constraint usages +/// +/// # Constructor search +/// When the cursor is on specific tokens in a struct/enum definition: +/// - `{` after struct/enum/variant: Shows record literal initializations +/// - `(` after tuple struct/variant: Shows tuple literal initializations +/// - `;` after unit struct: Shows unit literal initializations +/// - Type name in definition: Shows all initialization usages +/// In these cases, other kinds of references (like type references) are filtered out. pub(crate) fn find_all_refs( sema: &Semantics<'_, RootDatabase>, position: FilePosition, @@ -219,7 +276,19 @@ fn retain_adt_literal_usages( } } -/// Returns `Some` if the cursor is at a position for an item to search for all its constructor/literal usages +/// Returns `Some` if the cursor is at a position where we should search for constructor/initialization usages. +/// This is used to implement the special constructor search behavior when the cursor is on specific tokens +/// in a struct/enum/variant definition. +/// +/// # Returns +/// - `Some(name)` if the cursor is on: +/// - `{` after a struct/enum/variant definition +/// - `(` for tuple structs/variants +/// - `;` for unit structs +/// - The type name in a struct/enum/variant definition +/// - `None` otherwise +/// +/// The returned name is the name of the type whose constructor usages should be searched for. fn name_for_constructor_search(syntax: &SyntaxNode, position: FilePosition) -> Option { let token = syntax.token_at_offset(position.offset).right_biased()?; let token_parent = token.parent()?; @@ -257,6 +326,16 @@ fn name_for_constructor_search(syntax: &SyntaxNode, position: FilePosition) -> O } } +/// Checks if a name reference is part of an enum variant literal expression. +/// Used to filter references when searching for enum variant constructors. +/// +/// # Arguments +/// * `sema` - Semantic analysis context +/// * `enum_` - The enum type to check against +/// * `name_ref` - The name reference to check +/// +/// # Returns +/// `true` if the name reference is used as part of constructing a variant of the given enum. fn is_enum_lit_name_ref( sema: &Semantics<'_, RootDatabase>, enum_: hir::Enum, @@ -284,12 +363,19 @@ fn is_enum_lit_name_ref( .unwrap_or(false) } +/// Checks if a path ends with the given name reference. +/// Helper function for checking constructor usage patterns. fn path_ends_with(path: Option, name_ref: &ast::NameRef) -> bool { path.and_then(|path| path.segment()) .and_then(|segment| segment.name_ref()) .map_or(false, |segment| segment == *name_ref) } +/// Checks if a name reference is used in a literal (constructor) context. +/// Used to filter references when searching for struct/variant constructors. +/// +/// # Returns +/// `true` if the name reference is used as part of a struct/variant literal expression. fn is_lit_name_ref(name_ref: &ast::NameRef) -> bool { name_ref.syntax().ancestors().find_map(|ancestor| { match_ast! { From 1e8eacd192022cd0bd8c90101569b32397722122 Mon Sep 17 00:00:00 2001 From: vremyavnikuda Date: Sun, 25 May 2025 15:55:58 +0700 Subject: [PATCH 2785/4206] fix: the lines are formatted according to clippy --- src/tools/rust-analyzer/crates/ide/src/references.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index 91f4d752c8d59..f7f00cf8317c6 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -15,7 +15,7 @@ //! - `(` for tuple structs/variants //! - `;` for unit structs //! - The type name in a struct/enum/variant definition -//! Then only constructor/initialization usages will be shown, filtering out other references. +//! Then only constructor/initialization usages will be shown, filtering out other references. use hir::{PathResolution, Semantics}; use ide_db::{ @@ -105,7 +105,7 @@ pub struct Declaration { /// - `(` after tuple struct/variant: Shows tuple literal initializations /// - `;` after unit struct: Shows unit literal initializations /// - Type name in definition: Shows all initialization usages -/// In these cases, other kinds of references (like type references) are filtered out. +/// In these cases, other kinds of references (like type references) are filtered out. pub(crate) fn find_all_refs( sema: &Semantics<'_, RootDatabase>, position: FilePosition, From 693ff34702c2eb06bca073f2f7d3073da36c297b Mon Sep 17 00:00:00 2001 From: vremyavnikuda Date: Sun, 25 May 2025 15:55:58 +0700 Subject: [PATCH 2786/4206] fix: the lines are formatted according to clippy --- src/tools/rust-analyzer/crates/ide/src/references.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index f7f00cf8317c6..d9882d1221020 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -105,7 +105,7 @@ pub struct Declaration { /// - `(` after tuple struct/variant: Shows tuple literal initializations /// - `;` after unit struct: Shows unit literal initializations /// - Type name in definition: Shows all initialization usages -/// In these cases, other kinds of references (like type references) are filtered out. +/// In these cases, other kinds of references (like type references) are filtered out. pub(crate) fn find_all_refs( sema: &Semantics<'_, RootDatabase>, position: FilePosition, From d3347bb32b01e73db96d75579ec7ca16320d4317 Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 26 May 2025 14:11:02 +0800 Subject: [PATCH 2787/4206] remove eq_unspanned from TokenStream --- compiler/rustc_ast/src/tokenstream.rs | 10 +++------- compiler/rustc_parse/src/parser/tokenstream/tests.rs | 8 ++++++-- src/tools/clippy/clippy_utils/src/ast_utils/mod.rs | 4 +++- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 7f2ba28f81bd8..3c231be20dce5 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -57,7 +57,9 @@ impl TokenTree { match (self, other) { (TokenTree::Token(token, _), TokenTree::Token(token2, _)) => token.kind == token2.kind, (TokenTree::Delimited(.., delim, tts), TokenTree::Delimited(.., delim2, tts2)) => { - delim == delim2 && tts.eq_unspanned(tts2) + delim == delim2 + && tts.len() == tts2.len() + && tts.iter().zip(tts2.iter()).all(|(a, b)| a.eq_unspanned(b)) } _ => false, } @@ -694,12 +696,6 @@ impl TokenStream { TokenStreamIter::new(self) } - /// Compares two `TokenStream`s, checking equality without regarding span information. - pub fn eq_unspanned(&self, other: &TokenStream) -> bool { - self.len() == other.len() - && self.iter().zip(other.iter()).all(|(tt1, tt2)| tt1.eq_unspanned(tt2)) - } - /// Create a token stream containing a single token with alone spacing. The /// spacing used for the final token in a constructed stream doesn't matter /// because it's never used. In practice we arbitrarily use diff --git a/compiler/rustc_parse/src/parser/tokenstream/tests.rs b/compiler/rustc_parse/src/parser/tokenstream/tests.rs index aac75323ff3d2..19b2c98f5af82 100644 --- a/compiler/rustc_parse/src/parser/tokenstream/tests.rs +++ b/compiler/rustc_parse/src/parser/tokenstream/tests.rs @@ -14,6 +14,10 @@ fn sp(a: u32, b: u32) -> Span { Span::with_root_ctxt(BytePos(a), BytePos(b)) } +fn cmp_token_stream(a: &TokenStream, b: &TokenStream) -> bool { + a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| x.eq_unspanned(y)) +} + #[test] fn test_concat() { create_default_session_globals_then(|| { @@ -25,7 +29,7 @@ fn test_concat() { eq_res.push_stream(test_snd); assert_eq!(test_res.iter().count(), 5); assert_eq!(eq_res.iter().count(), 5); - assert_eq!(test_res.eq_unspanned(&eq_res), true); + assert_eq!(cmp_token_stream(&test_res, &eq_res), true); }) } @@ -104,7 +108,7 @@ fn test_dotdotdot() { stream.push_tree(TokenTree::token_joint(token::Dot, sp(0, 1))); stream.push_tree(TokenTree::token_joint(token::Dot, sp(1, 2))); stream.push_tree(TokenTree::token_alone(token::Dot, sp(2, 3))); - assert!(stream.eq_unspanned(&string_to_ts("..."))); + assert!(cmp_token_stream(&stream, &string_to_ts("..."))); assert_eq!(stream.iter().count(), 1); }) } diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 8996b694ed8f7..01e916fb5353b 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -960,5 +960,7 @@ pub fn eq_attr_args(l: &AttrArgs, r: &AttrArgs) -> bool { } pub fn eq_delim_args(l: &DelimArgs, r: &DelimArgs) -> bool { - l.delim == r.delim && l.tokens.eq_unspanned(&r.tokens) + l.delim == r.delim + && l.tokens.len() == r.tokens.len() + && l.tokens.iter().zip(r.tokens.iter()).all(|(a, b)| a.eq_unspanned(b)) } From f6e5fa20bf30477d582746dc5189fbabf8509c15 Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 26 May 2025 14:11:02 +0800 Subject: [PATCH 2788/4206] remove eq_unspanned from TokenStream --- clippy_utils/src/ast_utils/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clippy_utils/src/ast_utils/mod.rs b/clippy_utils/src/ast_utils/mod.rs index 8996b694ed8f7..01e916fb5353b 100644 --- a/clippy_utils/src/ast_utils/mod.rs +++ b/clippy_utils/src/ast_utils/mod.rs @@ -960,5 +960,7 @@ pub fn eq_attr_args(l: &AttrArgs, r: &AttrArgs) -> bool { } pub fn eq_delim_args(l: &DelimArgs, r: &DelimArgs) -> bool { - l.delim == r.delim && l.tokens.eq_unspanned(&r.tokens) + l.delim == r.delim + && l.tokens.len() == r.tokens.len() + && l.tokens.iter().zip(r.tokens.iter()).all(|(a, b)| a.eq_unspanned(b)) } From 57707c22872c5518791905927153e0ff583f8ee8 Mon Sep 17 00:00:00 2001 From: vremyavnikuda Date: Mon, 26 May 2025 16:15:45 +0700 Subject: [PATCH 2789/4206] fix: formated to clippy --- src/tools/rust-analyzer/crates/ide/src/references.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index d9882d1221020..f7f00cf8317c6 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -105,7 +105,7 @@ pub struct Declaration { /// - `(` after tuple struct/variant: Shows tuple literal initializations /// - `;` after unit struct: Shows unit literal initializations /// - Type name in definition: Shows all initialization usages -/// In these cases, other kinds of references (like type references) are filtered out. +/// In these cases, other kinds of references (like type references) are filtered out. pub(crate) fn find_all_refs( sema: &Semantics<'_, RootDatabase>, position: FilePosition, From c256bcc0573fc9ffe254d1ce298a6aef9d4305d0 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Sun, 25 May 2025 02:16:22 +0200 Subject: [PATCH 2790/4206] refactor(mut_reference): replace `match` with `if-let` to reduce nesting --- clippy_lints/src/mut_reference.rs | 32 +++++++++++++------------------ 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 2fd1049f42e10..2f1ab3d2652ae 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -79,25 +79,19 @@ fn check_arguments<'tcx>( name: &str, fn_kind: &str, ) { - match type_definition.kind() { - ty::FnDef(..) | ty::FnPtr(..) => { - let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs(); - for (argument, parameter) in iter::zip(arguments, parameters) { - match parameter.kind() { - ty::Ref(_, _, Mutability::Not) | ty::RawPtr(_, Mutability::Not) => { - if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) = argument.kind { - span_lint( - cx, - UNNECESSARY_MUT_PASSED, - argument.span, - format!("the {fn_kind} `{name}` doesn't need a mutable reference"), - ); - } - }, - _ => (), - } + if let ty::FnDef(..) | ty::FnPtr(..) = type_definition.kind() { + let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs(); + for (argument, parameter) in iter::zip(arguments, parameters) { + if let ty::Ref(_, _, Mutability::Not) | ty::RawPtr(_, Mutability::Not) = parameter.kind() + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) = argument.kind + { + span_lint( + cx, + UNNECESSARY_MUT_PASSED, + argument.span, + format!("the {fn_kind} `{name}` doesn't need a mutable reference"), + ); } - }, - _ => (), + } } } From e2215a8ad9099c35df2de789efd9262c3fd59c65 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 25 May 2025 10:17:33 +0000 Subject: [PATCH 2791/4206] Don't rerun goals if none of its vars have changed --- compiler/rustc_infer/src/infer/context.rs | 51 +++++++ .../src/infer/opaque_types/table.rs | 6 + .../src/solve/eval_ctxt/canonical.rs | 15 +- .../src/solve/eval_ctxt/mod.rs | 129 ++++++++++++++---- .../rustc_next_trait_solver/src/solve/mod.rs | 19 +++ .../src/solve/fulfill.rs | 112 +++++++++------ .../src/solve/fulfill/derive_errors.rs | 24 ++-- .../src/solve/inspect/analyse.rs | 7 +- compiler/rustc_type_ir/src/infer_ctxt.rs | 7 +- compiler/rustc_type_ir/src/inherent.rs | 8 ++ 10 files changed, 290 insertions(+), 88 deletions(-) diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 359b9da11ced6..173d47493c56e 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -89,6 +89,57 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid) } + fn is_changed_arg(&self, arg: ty::GenericArg<'tcx>) -> bool { + match arg.unpack() { + ty::GenericArgKind::Lifetime(_) => { + // Lifetimes should not change affect trait selection. + false + } + ty::GenericArgKind::Type(ty) => { + if let ty::Infer(infer_ty) = *ty.kind() { + match infer_ty { + ty::InferTy::TyVar(vid) => { + !self.probe_ty_var(vid).is_err_and(|_| self.root_var(vid) == vid) + } + ty::InferTy::IntVar(vid) => { + let mut inner = self.inner.borrow_mut(); + !matches!( + inner.int_unification_table().probe_value(vid), + ty::IntVarValue::Unknown + if inner.int_unification_table().find(vid) == vid + ) + } + ty::InferTy::FloatVar(vid) => { + let mut inner = self.inner.borrow_mut(); + !matches!( + inner.float_unification_table().probe_value(vid), + ty::FloatVarValue::Unknown + if inner.float_unification_table().find(vid) == vid + ) + } + ty::InferTy::FreshTy(_) + | ty::InferTy::FreshIntTy(_) + | ty::InferTy::FreshFloatTy(_) => true, + } + } else { + true + } + } + ty::GenericArgKind::Const(ct) => { + if let ty::ConstKind::Infer(infer_ct) = ct.kind() { + match infer_ct { + ty::InferConst::Var(vid) => !self + .probe_const_var(vid) + .is_err_and(|_| self.root_const_var(vid) == vid), + ty::InferConst::Fresh(_) => true, + } + } else { + true + } + } + } + } + fn next_region_infer(&self) -> ty::Region<'tcx> { self.next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP)) } diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index 46752840e1bab..ab65da3913da1 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -24,6 +24,12 @@ pub struct OpaqueTypeStorageEntries { duplicate_entries: usize, } +impl rustc_type_ir::inherent::OpaqueTypeStorageEntries for OpaqueTypeStorageEntries { + fn needs_reevaluation(self, canonicalized: usize) -> bool { + self.opaque_types != canonicalized + } +} + impl<'tcx> OpaqueTypeStorage<'tcx> { #[instrument(level = "debug")] pub(crate) fn remove( diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index 455a178595b29..66d4cd23112dc 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -53,10 +53,10 @@ where { /// Canonicalizes the goal remembering the original values /// for each bound variable. - pub(super) fn canonicalize_goal>( + pub(super) fn canonicalize_goal( &self, - goal: Goal, - ) -> (Vec, CanonicalInput) { + goal: Goal, + ) -> (Vec, CanonicalInput) { // We only care about one entry per `OpaqueTypeKey` here, // so we only canonicalize the lookup table and ignore // duplicate entries. @@ -130,7 +130,12 @@ where if goals.is_empty() { assert!(matches!(goals_certainty, Certainty::Yes)); } - (Certainty::Yes, NestedNormalizationGoals(goals)) + ( + Certainty::Yes, + NestedNormalizationGoals( + goals.into_iter().map(|(s, g, _)| (s, g)).collect(), + ), + ) } _ => { let certainty = shallow_certainty.and(goals_certainty); @@ -272,7 +277,7 @@ where pub(super) fn instantiate_and_apply_query_response( &mut self, param_env: I::ParamEnv, - original_values: Vec, + original_values: &[I::GenericArg], response: CanonicalResponse, ) -> (NestedNormalizationGoals, Certainty) { let instantiation = Self::compute_query_response_instantiation_values( diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index dfabb94ebfc60..d8a97724e8164 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -22,8 +22,9 @@ use crate::delegate::SolverDelegate; use crate::solve::inspect::{self, ProofTreeBuilder}; use crate::solve::search_graph::SearchGraph; use crate::solve::{ - CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluationKind, GoalSource, - HasChanged, NestedNormalizationGoals, NoSolution, QueryInput, QueryResult, + CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluation, GoalEvaluationKind, + GoalSource, GoalStalledOn, HasChanged, NestedNormalizationGoals, NoSolution, QueryInput, + QueryResult, }; pub(super) mod canonical; @@ -115,7 +116,7 @@ where pub(super) search_graph: &'a mut SearchGraph, - nested_goals: Vec<(GoalSource, Goal)>, + nested_goals: Vec<(GoalSource, Goal, Option>)>, pub(super) origin_span: I::Span, @@ -147,8 +148,9 @@ pub trait SolverDelegateEvalExt: SolverDelegate { goal: Goal::Predicate>, generate_proof_tree: GenerateProofTree, span: ::Span, + stalled_on: Option>, ) -> ( - Result<(HasChanged, Certainty), NoSolution>, + Result, NoSolution>, Option>, ); @@ -171,8 +173,12 @@ pub trait SolverDelegateEvalExt: SolverDelegate { &self, goal: Goal::Predicate>, generate_proof_tree: GenerateProofTree, + stalled_on: Option>, ) -> ( - Result<(NestedNormalizationGoals, HasChanged, Certainty), NoSolution>, + Result< + (NestedNormalizationGoals, GoalEvaluation), + NoSolution, + >, Option>, ); } @@ -188,9 +194,10 @@ where goal: Goal, generate_proof_tree: GenerateProofTree, span: I::Span, - ) -> (Result<(HasChanged, Certainty), NoSolution>, Option>) { + stalled_on: Option>, + ) -> (Result, NoSolution>, Option>) { EvalCtxt::enter_root(self, self.cx().recursion_limit(), generate_proof_tree, span, |ecx| { - ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal) + ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal, stalled_on) }) } @@ -201,7 +208,7 @@ where ) -> bool { self.probe(|| { EvalCtxt::enter_root(self, root_depth, GenerateProofTree::No, I::Span::dummy(), |ecx| { - ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal) + ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal, None) }) .0 }) @@ -213,8 +220,9 @@ where &self, goal: Goal, generate_proof_tree: GenerateProofTree, + stalled_on: Option>, ) -> ( - Result<(NestedNormalizationGoals, HasChanged, Certainty), NoSolution>, + Result<(NestedNormalizationGoals, GoalEvaluation), NoSolution>, Option>, ) { EvalCtxt::enter_root( @@ -222,7 +230,9 @@ where self.cx().recursion_limit(), generate_proof_tree, I::Span::dummy(), - |ecx| ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal), + |ecx| { + ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal, stalled_on) + }, ) } } @@ -447,11 +457,12 @@ where goal_evaluation_kind: GoalEvaluationKind, source: GoalSource, goal: Goal, - ) -> Result<(HasChanged, Certainty), NoSolution> { - let (normalization_nested_goals, has_changed, certainty) = - self.evaluate_goal_raw(goal_evaluation_kind, source, goal)?; + stalled_on: Option>, + ) -> Result, NoSolution> { + let (normalization_nested_goals, goal_evaluation) = + self.evaluate_goal_raw(goal_evaluation_kind, source, goal, stalled_on)?; assert!(normalization_nested_goals.is_empty()); - Ok((has_changed, certainty)) + Ok(goal_evaluation) } /// Recursively evaluates `goal`, returning the nested goals in case @@ -466,7 +477,29 @@ where goal_evaluation_kind: GoalEvaluationKind, source: GoalSource, goal: Goal, - ) -> Result<(NestedNormalizationGoals, HasChanged, Certainty), NoSolution> { + stalled_on: Option>, + ) -> Result<(NestedNormalizationGoals, GoalEvaluation), NoSolution> { + // If we have run this goal before, and it was stalled, check that any of the goal's + // args have changed. Otherwise, we don't need to re-run the goal because it'll remain + // stalled, since it'll canonicalize the same way and evaluation is pure. + if let Some(stalled_on) = stalled_on { + if !stalled_on.stalled_vars.iter().any(|value| self.delegate.is_changed_arg(*value)) + && !self + .delegate + .opaque_types_storage_num_entries() + .needs_reevaluation(stalled_on.num_opaques) + { + return Ok(( + NestedNormalizationGoals::empty(), + GoalEvaluation { + certainty: Certainty::Maybe(stalled_on.stalled_cause), + has_changed: HasChanged::No, + stalled_on: Some(stalled_on), + }, + )); + } + } + let (orig_values, canonical_goal) = self.canonicalize_goal(goal); let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind); @@ -489,7 +522,7 @@ where if !has_only_region_constraints(response) { HasChanged::Yes } else { HasChanged::No }; let (normalization_nested_goals, certainty) = - self.instantiate_and_apply_query_response(goal.param_env, orig_values, response); + self.instantiate_and_apply_query_response(goal.param_env, &orig_values, response); self.inspect.goal_evaluation(goal_evaluation); // FIXME: We previously had an assert here that checked that recomputing @@ -502,7 +535,42 @@ where // Once we have decided on how to handle trait-system-refactor-initiative#75, // we should re-add an assert here. - Ok((normalization_nested_goals, has_changed, certainty)) + let stalled_on = match certainty { + Certainty::Yes => None, + Certainty::Maybe(stalled_cause) => match has_changed { + // FIXME: We could recompute a *new* set of stalled variables by walking + // through the orig values, resolving, and computing the root vars of anything + // that is not resolved. Only when *these* have changed is it meaningful + // to recompute this goal. + HasChanged::Yes => None, + HasChanged::No => { + // Remove the unconstrained RHS arg, which is expected to have changed. + let mut stalled_vars = orig_values; + if let Some(normalizes_to) = goal.predicate.as_normalizes_to() { + let normalizes_to = normalizes_to.skip_binder(); + let rhs_arg: I::GenericArg = normalizes_to.term.into(); + let idx = stalled_vars + .iter() + .rposition(|arg| *arg == rhs_arg) + .expect("expected unconstrained arg"); + stalled_vars.swap_remove(idx); + } + + Some(GoalStalledOn { + num_opaques: canonical_goal + .canonical + .value + .predefined_opaques_in_body + .opaque_types + .len(), + stalled_vars, + stalled_cause, + }) + } + }, + }; + + Ok((normalization_nested_goals, GoalEvaluation { certainty, has_changed, stalled_on })) } fn compute_goal(&mut self, goal: Goal) -> QueryResult { @@ -602,7 +670,7 @@ where let cx = self.cx(); // If this loop did not result in any progress, what's our final certainty. let mut unchanged_certainty = Some(Certainty::Yes); - for (source, goal) in mem::take(&mut self.nested_goals) { + for (source, goal, stalled_on) in mem::take(&mut self.nested_goals) { if let Some(has_changed) = self.delegate.compute_goal_fast_path(goal, self.origin_span) { if matches!(has_changed, HasChanged::Yes) { @@ -630,11 +698,18 @@ where let unconstrained_goal = goal.with(cx, ty::NormalizesTo { alias: pred.alias, term: unconstrained_rhs }); - let (NestedNormalizationGoals(nested_goals), _, certainty) = - self.evaluate_goal_raw(GoalEvaluationKind::Nested, source, unconstrained_goal)?; + let ( + NestedNormalizationGoals(nested_goals), + GoalEvaluation { certainty, stalled_on, has_changed: _ }, + ) = self.evaluate_goal_raw( + GoalEvaluationKind::Nested, + source, + unconstrained_goal, + stalled_on, + )?; // Add the nested goals from normalization to our own nested goals. trace!(?nested_goals); - self.nested_goals.extend(nested_goals); + self.nested_goals.extend(nested_goals.into_iter().map(|(s, g)| (s, g, None))); // Finally, equate the goal's RHS with the unconstrained var. // @@ -660,6 +735,8 @@ where // looking at the "has changed" return from evaluate_goal, // because we expect the `unconstrained_rhs` part of the predicate // to have changed -- that means we actually normalized successfully! + // FIXME: Do we need to eagerly resolve here? Or should we check + // if the cache key has any changed vars? let with_resolved_vars = self.resolve_vars_if_possible(goal); if pred.alias != goal.predicate.as_normalizes_to().unwrap().skip_binder().alias { unchanged_certainty = None; @@ -668,13 +745,13 @@ where match certainty { Certainty::Yes => {} Certainty::Maybe(_) => { - self.nested_goals.push((source, with_resolved_vars)); + self.nested_goals.push((source, with_resolved_vars, stalled_on)); unchanged_certainty = unchanged_certainty.map(|c| c.and(certainty)); } } } else { - let (has_changed, certainty) = - self.evaluate_goal(GoalEvaluationKind::Nested, source, goal)?; + let GoalEvaluation { certainty, has_changed, stalled_on } = + self.evaluate_goal(GoalEvaluationKind::Nested, source, goal, stalled_on)?; if has_changed == HasChanged::Yes { unchanged_certainty = None; } @@ -682,7 +759,7 @@ where match certainty { Certainty::Yes => {} Certainty::Maybe(_) => { - self.nested_goals.push((source, goal)); + self.nested_goals.push((source, goal, stalled_on)); unchanged_certainty = unchanged_certainty.map(|c| c.and(certainty)); } } @@ -706,7 +783,7 @@ where goal.predicate = goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(self, source, goal.param_env)); self.inspect.add_goal(self.delegate, self.max_input_universe, source, goal); - self.nested_goals.push((source, goal)); + self.nested_goals.push((source, goal, None)); } #[instrument(level = "trace", skip(self, goals))] diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 2a64180715411..a7a984181d7f0 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -21,6 +21,7 @@ mod project_goals; mod search_graph; mod trait_goals; +use derive_where::derive_where; use rustc_type_ir::inherent::*; pub use rustc_type_ir::solve::*; use rustc_type_ir::{self as ty, Interner, TypingMode}; @@ -369,3 +370,21 @@ fn response_no_constraints_raw( }, } } + +/// The result of evaluating a goal. +pub struct GoalEvaluation { + pub certainty: Certainty, + pub has_changed: HasChanged, + /// If the [`Certainty`] was `Maybe`, then keep track of whether the goal has changed + /// before rerunning it. + pub stalled_on: Option>, +} + +/// The conditions that must change for a goal to warrant +#[derive_where(Clone, Debug; I: Interner)] +pub struct GoalStalledOn { + pub num_opaques: usize, + pub stalled_vars: Vec, + /// The cause that will be returned on subsequent evaluations if this goal remains stalled. + pub stalled_cause: MaybeCause, +} diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index aa3be43fcd16b..d273703a9b121 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -13,8 +13,11 @@ use rustc_middle::ty::{ self, DelayedSet, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, TypingMode, }; use rustc_next_trait_solver::delegate::SolverDelegate as _; -use rustc_next_trait_solver::solve::{GenerateProofTree, HasChanged, SolverDelegateEvalExt as _}; +use rustc_next_trait_solver::solve::{ + GenerateProofTree, GoalEvaluation, GoalStalledOn, HasChanged, SolverDelegateEvalExt as _, +}; use rustc_span::Span; +use thin_vec::ThinVec; use tracing::instrument; use self::derive_errors::*; @@ -25,6 +28,10 @@ use crate::traits::{FulfillmentError, ScrubbedTraitError}; mod derive_errors; +// FIXME: Do we need to use a `ThinVec` here? +type PendingObligations<'tcx> = + ThinVec<(PredicateObligation<'tcx>, Option>>)>; + /// A trait engine using the new trait solver. /// /// This is mostly identical to how `evaluate_all` works inside of the @@ -54,13 +61,17 @@ struct ObligationStorage<'tcx> { /// We cannot eagerly return these as error so we instead store them here /// to avoid recomputing them each time `select_where_possible` is called. /// This also allows us to return the correct `FulfillmentError` for them. - overflowed: PredicateObligations<'tcx>, - pending: PredicateObligations<'tcx>, + overflowed: Vec>, + pending: PendingObligations<'tcx>, } impl<'tcx> ObligationStorage<'tcx> { - fn register(&mut self, obligation: PredicateObligation<'tcx>) { - self.pending.push(obligation); + fn register( + &mut self, + obligation: PredicateObligation<'tcx>, + stalled_on: Option>>, + ) { + self.pending.push((obligation, stalled_on)); } fn has_pending_obligations(&self) -> bool { @@ -68,7 +79,8 @@ impl<'tcx> ObligationStorage<'tcx> { } fn clone_pending(&self) -> PredicateObligations<'tcx> { - let mut obligations = self.pending.clone(); + let mut obligations: PredicateObligations<'tcx> = + self.pending.iter().map(|(o, _)| o.clone()).collect(); obligations.extend(self.overflowed.iter().cloned()); obligations } @@ -76,8 +88,9 @@ impl<'tcx> ObligationStorage<'tcx> { fn drain_pending( &mut self, cond: impl Fn(&PredicateObligation<'tcx>) -> bool, - ) -> PredicateObligations<'tcx> { - let (unstalled, pending) = mem::take(&mut self.pending).into_iter().partition(cond); + ) -> PendingObligations<'tcx> { + let (unstalled, pending) = + mem::take(&mut self.pending).into_iter().partition(|(o, _)| cond(o)); self.pending = pending; unstalled } @@ -90,13 +103,21 @@ impl<'tcx> ObligationStorage<'tcx> { // we were to do another step of `select_where_possible`, which goals would // change. // FIXME: is merged, this can be removed. - self.overflowed.extend(ExtractIf::new(&mut self.pending, |o| { - let goal = o.as_goal(); - let result = <&SolverDelegate<'tcx>>::from(infcx) - .evaluate_root_goal(goal, GenerateProofTree::No, o.cause.span) - .0; - matches!(result, Ok((HasChanged::Yes, _))) - })); + self.overflowed.extend( + ExtractIf::new(&mut self.pending, |(o, stalled_on)| { + let goal = o.as_goal(); + let result = <&SolverDelegate<'tcx>>::from(infcx) + .evaluate_root_goal( + goal, + GenerateProofTree::No, + o.cause.span, + stalled_on.take(), + ) + .0; + matches!(result, Ok(GoalEvaluation { has_changed: HasChanged::Yes, .. })) + }) + .map(|(o, _)| o), + ); }) } } @@ -119,11 +140,11 @@ impl<'tcx, E: 'tcx> FulfillmentCtxt<'tcx, E> { &self, infcx: &InferCtxt<'tcx>, obligation: &PredicateObligation<'tcx>, - result: &Result<(HasChanged, Certainty), NoSolution>, + result: &Result>, NoSolution>, ) { if let Some(inspector) = infcx.obligation_inspector.get() { let result = match result { - Ok((_, c)) => Ok(*c), + Ok(GoalEvaluation { certainty, .. }) => Ok(*certainty), Err(NoSolution) => Err(NoSolution), }; (inspector)(infcx, &obligation, result); @@ -142,14 +163,14 @@ where obligation: PredicateObligation<'tcx>, ) { assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots()); - self.obligations.register(obligation); + self.obligations.register(obligation, None); } fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec { self.obligations .pending .drain(..) - .map(|obligation| NextSolverError::Ambiguity(obligation)) + .map(|(obligation, _)| NextSolverError::Ambiguity(obligation)) .chain( self.obligations .overflowed @@ -164,8 +185,8 @@ where assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots()); let mut errors = Vec::new(); loop { - let mut has_changed = false; - for mut obligation in self.obligations.drain_pending(|_| true) { + let mut any_changed = false; + for (mut obligation, stalled_on) in self.obligations.drain_pending(|_| true) { if !infcx.tcx.recursion_limit().value_within_limit(obligation.recursion_depth) { self.obligations.on_fulfillment_overflow(infcx); // Only return true errors that we have accumulated while processing. @@ -177,15 +198,20 @@ where if let Some(fast_path_has_changed) = delegate.compute_goal_fast_path(goal, obligation.cause.span) { - has_changed |= matches!(fast_path_has_changed, HasChanged::Yes); + any_changed |= matches!(fast_path_has_changed, HasChanged::Yes); continue; } let result = delegate - .evaluate_root_goal(goal, GenerateProofTree::No, obligation.cause.span) + .evaluate_root_goal( + goal, + GenerateProofTree::No, + obligation.cause.span, + stalled_on, + ) .0; self.inspect_evaluated_obligation(infcx, &obligation, &result); - let (changed, certainty) = match result { + let GoalEvaluation { certainty, has_changed, stalled_on } = match result { Ok(result) => result, Err(NoSolution) => { errors.push(E::from_solver_error( @@ -196,7 +222,7 @@ where } }; - if changed == HasChanged::Yes { + if has_changed == HasChanged::Yes { // We increment the recursion depth here to track the number of times // this goal has resulted in inference progress. This doesn't precisely // model the way that we track recursion depth in the old solver due @@ -204,16 +230,16 @@ where // approximation and should only result in fulfillment overflow in // pathological cases. obligation.recursion_depth += 1; - has_changed = true; + any_changed = true; } match certainty { Certainty::Yes => {} - Certainty::Maybe(_) => self.obligations.register(obligation), + Certainty::Maybe(_) => self.obligations.register(obligation, stalled_on), } } - if !has_changed { + if !any_changed { break; } } @@ -247,20 +273,24 @@ where return Default::default(); } - self.obligations.drain_pending(|obl| { - infcx.probe(|_| { - infcx - .visit_proof_tree( - obl.as_goal(), - &mut StalledOnCoroutines { - stalled_generators, - span: obl.cause.span, - cache: Default::default(), - }, - ) - .is_break() + self.obligations + .drain_pending(|obl| { + infcx.probe(|_| { + infcx + .visit_proof_tree( + obl.as_goal(), + &mut StalledOnCoroutines { + stalled_generators, + span: obl.cause.span, + cache: Default::default(), + }, + ) + .is_break() + }) }) - }) + .into_iter() + .map(|(o, _)| o) + .collect() } } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index f64cd5ffebe3d..1c9d69da32280 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -11,7 +11,9 @@ use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; -use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as _}; +use rustc_next_trait_solver::solve::{ + GenerateProofTree, GoalEvaluation, SolverDelegateEvalExt as _, +}; use tracing::{instrument, trace}; use crate::solve::delegate::SolverDelegate; @@ -93,19 +95,21 @@ pub(super) fn fulfillment_error_for_stalled<'tcx>( root_obligation.as_goal(), GenerateProofTree::No, root_obligation.cause.span, + None, ) .0 { - Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => { + Ok(GoalEvaluation { certainty: Certainty::Maybe(MaybeCause::Ambiguity), .. }) => { (FulfillmentErrorCode::Ambiguity { overflow: None }, true) } - Ok(( - _, - Certainty::Maybe(MaybeCause::Overflow { - suggest_increasing_limit, - keep_constraints: _, - }), - )) => ( + Ok(GoalEvaluation { + certainty: + Certainty::Maybe(MaybeCause::Overflow { + suggest_increasing_limit, + keep_constraints: _, + }), + .. + }) => ( FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) }, // Don't look into overflows because we treat overflows weirdly anyways. // We discard the inference constraints from overflowing goals, so @@ -115,7 +119,7 @@ pub(super) fn fulfillment_error_for_stalled<'tcx>( // FIXME: We should probably just look into overflows here. false, ), - Ok((_, Certainty::Yes)) => { + Ok(GoalEvaluation { certainty: Certainty::Yes, .. }) => { bug!( "did not expect successful goal when collecting ambiguity errors for `{:?}`", infcx.resolve_vars_if_possible(root_obligation.predicate), diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 9795655e84222..49a8b363b0aba 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -219,8 +219,8 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { // building their proof tree, the expected term was unconstrained, but when // instantiating the candidate it is already constrained to the result of another // candidate. - let proof_tree = - infcx.probe(|_| infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes).1); + let proof_tree = infcx + .probe(|_| infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes, None).1); InspectGoal::new( infcx, self.goal.depth + 1, @@ -236,7 +236,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { // constraints, we get an ICE if we already applied the constraints // from the chosen candidate. let proof_tree = infcx - .probe(|_| infcx.evaluate_root_goal(goal, GenerateProofTree::Yes, span).1) + .probe(|_| infcx.evaluate_root_goal(goal, GenerateProofTree::Yes, span, None).1) .unwrap(); InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, None, source) } @@ -442,6 +442,7 @@ impl<'tcx> InferCtxt<'tcx> { goal, GenerateProofTree::Yes, visitor.span(), + None, ); let proof_tree = proof_tree.unwrap(); visitor.visit_goal(&InspectGoal::new(self, depth, proof_tree, None, GoalSource::Misc)) diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index c149076211739..2bc12d0a23bfe 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -1,11 +1,10 @@ -use std::fmt::Debug; - use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use crate::fold::TypeFoldable; +use crate::inherent::*; use crate::relate::RelateResult; use crate::relate::combine::PredicateEmittingRelation; use crate::{self as ty, Interner}; @@ -168,6 +167,8 @@ pub trait InferCtxtLike: Sized { vid: ty::RegionVid, ) -> ::Region; + fn is_changed_arg(&self, arg: ::GenericArg) -> bool; + fn next_region_infer(&self) -> ::Region; fn next_ty_infer(&self) -> ::Ty; fn next_const_infer(&self) -> ::Const; @@ -248,7 +249,7 @@ pub trait InferCtxtLike: Sized { span: ::Span, ); - type OpaqueTypeStorageEntries: Debug + Copy + Default; + type OpaqueTypeStorageEntries: OpaqueTypeStorageEntries; fn opaque_types_storage_num_entries(&self) -> Self::OpaqueTypeStorageEntries; fn clone_opaque_types_lookup_table( &self, diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index ee4a8096462a0..dde55effc3d0d 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -297,6 +297,7 @@ pub trait GenericArg>: + From + From + From + + From { fn as_term(&self) -> Option { match self.kind() { @@ -596,6 +597,13 @@ pub trait Span: Copy + Debug + Hash + Eq + TypeFoldable { fn dummy() -> Self; } +pub trait OpaqueTypeStorageEntries: Debug + Copy + Default { + /// Whether the number of opaques has changed in a way that necessitates + /// reevaluating a goal. For now, this is only when the number of non-duplicated + /// entries changed. + fn needs_reevaluation(self, canonicalized: usize) -> bool; +} + pub trait SliceLike: Sized + Copy { type Item: Copy; type IntoIter: Iterator + DoubleEndedIterator; From 1e9e17704adfc6bd6b01a0031b73fbc1682a0f1f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 21 May 2025 15:34:15 +0000 Subject: [PATCH 2792/4206] Move some code around in codegen_call_terminator --- compiler/rustc_codegen_ssa/src/mir/block.rs | 202 ++++++++++---------- 1 file changed, 103 insertions(+), 99 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 922b8a5824bec..de827a475c418 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -8,7 +8,7 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::mir::{self, AssertKind, InlineAsmMacro, SwitchTargets, UnwindTerminateReason}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; -use rustc_middle::ty::{self, Instance, Ty}; +use rustc_middle::ty::{self, Instance, List, Ty}; use rustc_middle::{bug, span_bug}; use rustc_session::config::OptLevel; use rustc_span::source_map::Spanned; @@ -827,7 +827,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { helper: &TerminatorCodegenHelper<'tcx>, bx: &mut Bx, intrinsic: ty::IntrinsicDef, - instance: Option>, + instance: Instance<'tcx>, source_info: mir::SourceInfo, target: Option, unwind: mir::UnwindAction, @@ -837,7 +837,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // These are intrinsics that compile to panics so that we can get a message // which mentions the offending type, even from a const context. if let Some(requirement) = ValidityRequirement::from_intrinsic(intrinsic.name) { - let ty = instance.unwrap().args.type_at(0); + let ty = instance.args.type_at(0); let do_panic = !bx .tcx() @@ -910,35 +910,116 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let callee = self.codegen_operand(bx, func); let (instance, mut llfn) = match *callee.layout.ty.kind() { - ty::FnDef(def_id, args) => ( - Some(ty::Instance::expect_resolve( + ty::FnDef(def_id, generic_args) => { + let instance = ty::Instance::expect_resolve( bx.tcx(), bx.typing_env(), def_id, - args, + generic_args, fn_span, - )), - None, - ), + ); + + let instance = match instance.def { + // We don't need AsyncDropGlueCtorShim here because it is not `noop func`, + // it is `func returning noop future` + ty::InstanceKind::DropGlue(_, None) => { + // Empty drop glue; a no-op. + let target = target.unwrap(); + return helper.funclet_br(self, bx, target, mergeable_succ); + } + ty::InstanceKind::Intrinsic(def_id) => { + let intrinsic = bx.tcx().intrinsic(def_id).unwrap(); + if let Some(merging_succ) = self.codegen_panic_intrinsic( + &helper, + bx, + intrinsic, + instance, + source_info, + target, + unwind, + mergeable_succ, + ) { + return merging_succ; + } + + let fn_abi = bx.fn_abi_of_instance(instance, List::empty()); + + let mut llargs = Vec::with_capacity(1); + let ret_dest = self.make_return_dest( + bx, + destination, + &fn_abi.ret, + &mut llargs, + Some(intrinsic), + ); + let dest = match ret_dest { + _ if fn_abi.ret.is_indirect() => llargs[0], + ReturnDest::Nothing => bx.const_undef(bx.type_ptr()), + ReturnDest::IndirectOperand(dst, _) | ReturnDest::Store(dst) => { + dst.val.llval + } + ReturnDest::DirectOperand(_) => { + bug!("Cannot use direct operand with an intrinsic call") + } + }; + + let args: Vec<_> = + args.iter().map(|arg| self.codegen_operand(bx, &arg.node)).collect(); + + if matches!(intrinsic, ty::IntrinsicDef { name: sym::caller_location, .. }) + { + let location = self.get_caller_location( + bx, + mir::SourceInfo { span: fn_span, ..source_info }, + ); + + assert_eq!(llargs, []); + if let ReturnDest::IndirectOperand(tmp, _) = ret_dest { + location.val.store(bx, tmp); + } + self.store_return(bx, ret_dest, &fn_abi.ret, location.immediate()); + return helper.funclet_br(self, bx, target.unwrap(), mergeable_succ); + } + + match Self::codegen_intrinsic_call(bx, instance, fn_abi, &args, dest, span) + { + Ok(()) => { + if let ReturnDest::IndirectOperand(dst, _) = ret_dest { + self.store_return(bx, ret_dest, &fn_abi.ret, dst.val.llval); + } + + return if let Some(target) = target { + helper.funclet_br(self, bx, target, mergeable_succ) + } else { + bx.unreachable(); + MergingSucc::False + }; + } + Err(instance) => { + if intrinsic.must_be_overridden { + span_bug!( + span, + "intrinsic {} must be overridden by codegen backend, but isn't", + intrinsic.name, + ); + } + instance + } + } + } + _ => instance, + }; + + (Some(instance), None) + } ty::FnPtr(..) => (None, Some(callee.immediate())), _ => bug!("{} is not callable", callee.layout.ty), }; - let def = instance.map(|i| i.def); - - // We don't need AsyncDropGlueCtorShim here because it is not `noop func`, - // it is `func returning noop future` - if let Some(ty::InstanceKind::DropGlue(_, None)) = def { - // Empty drop glue; a no-op. - let target = target.unwrap(); - return helper.funclet_br(self, bx, target, mergeable_succ); - } - // FIXME(eddyb) avoid computing this if possible, when `instance` is // available - right now `sig` is only needed for getting the `abi` // and figuring out how many extra args were passed to a C-variadic `fn`. let sig = callee.layout.ty.fn_sig(bx.tcx()); - let abi = sig.abi(); let extra_args = &args[sig.inputs().skip_binder().len()..]; let extra_args = bx.tcx().mk_type_list_from_iter(extra_args.iter().map(|op_arg| { @@ -954,83 +1035,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // The arguments we'll be passing. Plus one to account for outptr, if used. let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize; - let instance = match def { - Some(ty::InstanceKind::Intrinsic(def_id)) => { - let intrinsic = bx.tcx().intrinsic(def_id).unwrap(); - if let Some(merging_succ) = self.codegen_panic_intrinsic( - &helper, - bx, - intrinsic, - instance, - source_info, - target, - unwind, - mergeable_succ, - ) { - return merging_succ; - } - - let mut llargs = Vec::with_capacity(1); - let ret_dest = self.make_return_dest( - bx, - destination, - &fn_abi.ret, - &mut llargs, - Some(intrinsic), - ); - let dest = match ret_dest { - _ if fn_abi.ret.is_indirect() => llargs[0], - ReturnDest::Nothing => bx.const_undef(bx.type_ptr()), - ReturnDest::IndirectOperand(dst, _) | ReturnDest::Store(dst) => dst.val.llval, - ReturnDest::DirectOperand(_) => { - bug!("Cannot use direct operand with an intrinsic call") - } - }; - - let args: Vec<_> = - args.iter().map(|arg| self.codegen_operand(bx, &arg.node)).collect(); - - if matches!(intrinsic, ty::IntrinsicDef { name: sym::caller_location, .. }) { - let location = self - .get_caller_location(bx, mir::SourceInfo { span: fn_span, ..source_info }); - - assert_eq!(llargs, []); - if let ReturnDest::IndirectOperand(tmp, _) = ret_dest { - location.val.store(bx, tmp); - } - self.store_return(bx, ret_dest, &fn_abi.ret, location.immediate()); - return helper.funclet_br(self, bx, target.unwrap(), mergeable_succ); - } - - let instance = *instance.as_ref().unwrap(); - match Self::codegen_intrinsic_call(bx, instance, fn_abi, &args, dest, span) { - Ok(()) => { - if let ReturnDest::IndirectOperand(dst, _) = ret_dest { - self.store_return(bx, ret_dest, &fn_abi.ret, dst.val.llval); - } - - return if let Some(target) = target { - helper.funclet_br(self, bx, target, mergeable_succ) - } else { - bx.unreachable(); - MergingSucc::False - }; - } - Err(instance) => { - if intrinsic.must_be_overridden { - span_bug!( - span, - "intrinsic {} must be overridden by codegen backend, but isn't", - intrinsic.name, - ); - } - Some(instance) - } - } - } - _ => instance, - }; - let mut llargs = Vec::with_capacity(arg_count); // We still need to call `make_return_dest` even if there's no `target`, since @@ -1040,7 +1044,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let destination = target.map(|target| (return_dest, target)); // Split the rust-call tupled arguments off. - let (first_args, untuple) = if abi == ExternAbi::RustCall + let (first_args, untuple) = if sig.abi() == ExternAbi::RustCall && let Some((tup, args)) = args.split_last() { (args, Some(tup)) @@ -1055,7 +1059,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { 'make_args: for (i, arg) in first_args.iter().enumerate() { let mut op = self.codegen_operand(bx, &arg.node); - if let (0, Some(ty::InstanceKind::Virtual(_, idx))) = (i, def) { + if let (0, Some(ty::InstanceKind::Virtual(_, idx))) = (i, instance.map(|i| i.def)) { match op.val { Pair(data_ptr, meta) => { // In the case of Rc, we need to explicitly pass a From e4700e76d83428a99f2c7a8b19d3bf50606cf7e1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 22 May 2025 11:17:51 +0000 Subject: [PATCH 2793/4206] Always use fn_span in codegen_call_terminator --- compiler/rustc_codegen_ssa/src/mir/block.rs | 26 +++++++++------------ 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index de827a475c418..beb13ba28bc31 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -903,8 +903,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { fn_span: Span, mergeable_succ: bool, ) -> MergingSucc { - let source_info = terminator.source_info; - let span = source_info.span; + let source_info = mir::SourceInfo { span: fn_span, ..terminator.source_info }; // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar. let callee = self.codegen_operand(bx, func); @@ -968,10 +967,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if matches!(intrinsic, ty::IntrinsicDef { name: sym::caller_location, .. }) { - let location = self.get_caller_location( - bx, - mir::SourceInfo { span: fn_span, ..source_info }, - ); + let location = self.get_caller_location(bx, source_info); assert_eq!(llargs, []); if let ReturnDest::IndirectOperand(tmp, _) = ret_dest { @@ -981,8 +977,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return helper.funclet_br(self, bx, target.unwrap(), mergeable_succ); } - match Self::codegen_intrinsic_call(bx, instance, fn_abi, &args, dest, span) - { + match Self::codegen_intrinsic_call( + bx, instance, fn_abi, &args, dest, fn_span, + ) { Ok(()) => { if let ReturnDest::IndirectOperand(dst, _) = ret_dest { self.store_return(bx, ret_dest, &fn_abi.ret, dst.val.llval); @@ -998,7 +995,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { Err(instance) => { if intrinsic.must_be_overridden { span_bug!( - span, + fn_span, "intrinsic {} must be overridden by codegen backend, but isn't", intrinsic.name, ); @@ -1113,7 +1110,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Make sure that we've actually unwrapped the rcvr down // to a pointer or ref to `dyn* Trait`. if !op.layout.ty.builtin_deref(true).unwrap().is_dyn_star() { - span_bug!(span, "can't codegen a virtual call on {:#?}", op); + span_bug!(fn_span, "can't codegen a virtual call on {:#?}", op); } let place = op.deref(bx.cx()); let data_place = place.project_field(bx, 0); @@ -1129,7 +1126,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { continue; } _ => { - span_bug!(span, "can't codegen a virtual call on {:#?}", op); + span_bug!(fn_span, "can't codegen a virtual call on {:#?}", op); } } } @@ -1179,8 +1176,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir_args + 1, "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR: {instance:?} {fn_span:?} {fn_abi:?}", ); - let location = - self.get_caller_location(bx, mir::SourceInfo { span: fn_span, ..source_info }); + let location = self.get_caller_location(bx, source_info); debug!( "codegen_call_terminator({:?}): location={:?} (fn_span {:?})", terminator, location, fn_span @@ -1199,9 +1195,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let fn_ptr = match (instance, llfn) { (Some(instance), None) => bx.get_fn_addr(instance), (_, Some(llfn)) => llfn, - _ => span_bug!(span, "no instance or llfn for call"), + _ => span_bug!(fn_span, "no instance or llfn for call"), }; - self.set_debug_loc(bx, mir::SourceInfo { span: fn_span, ..source_info }); + self.set_debug_loc(bx, source_info); helper.do_call( self, bx, From c83358beb5f40a8b1c6e422f229ca4db1f927599 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 22 May 2025 13:50:47 +0000 Subject: [PATCH 2794/4206] Move caller_location handling into codegen_intrinsic_call --- compiler/rustc_codegen_ssa/src/mir/block.rs | 25 +++++++------------ .../rustc_codegen_ssa/src/mir/intrinsic.rs | 13 ++++++++-- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index beb13ba28bc31..1d11b907e9081 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -11,8 +11,8 @@ use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Instance, List, Ty}; use rustc_middle::{bug, span_bug}; use rustc_session::config::OptLevel; +use rustc_span::Span; use rustc_span::source_map::Spanned; -use rustc_span::{Span, sym}; use rustc_target::callconv::{ArgAbi, FnAbi, PassMode}; use tracing::{debug, info}; @@ -965,20 +965,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let args: Vec<_> = args.iter().map(|arg| self.codegen_operand(bx, &arg.node)).collect(); - if matches!(intrinsic, ty::IntrinsicDef { name: sym::caller_location, .. }) - { - let location = self.get_caller_location(bx, source_info); - - assert_eq!(llargs, []); - if let ReturnDest::IndirectOperand(tmp, _) = ret_dest { - location.val.store(bx, tmp); - } - self.store_return(bx, ret_dest, &fn_abi.ret, location.immediate()); - return helper.funclet_br(self, bx, target.unwrap(), mergeable_succ); - } - - match Self::codegen_intrinsic_call( - bx, instance, fn_abi, &args, dest, fn_span, + match self.codegen_intrinsic_call( + bx, + instance, + fn_abi, + &args, + dest, + source_info, ) { Ok(()) => { if let ReturnDest::IndirectOperand(dst, _) = ret_dest { @@ -1667,7 +1660,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { tuple.layout.fields.count() } - fn get_caller_location( + pub(super) fn get_caller_location( &mut self, bx: &mut Bx, source_info: mir::SourceInfo, diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index b0fcfee2adf5f..6cdd8480cbe31 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -1,8 +1,9 @@ use rustc_abi::WrappingRange; +use rustc_middle::mir::SourceInfo; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::config::OptLevel; -use rustc_span::{Span, sym}; +use rustc_span::sym; use rustc_target::callconv::{FnAbi, PassMode}; use super::FunctionCx; @@ -52,13 +53,15 @@ fn memset_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { /// In the `Err` case, returns the instance that should be called instead. pub fn codegen_intrinsic_call( + &mut self, bx: &mut Bx, instance: ty::Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, Bx::Value>], llresult: Bx::Value, - span: Span, + source_info: SourceInfo, ) -> Result<(), ty::Instance<'tcx>> { + let span = source_info.span; let callee_ty = instance.ty(bx.tcx(), bx.typing_env()); let ty::FnDef(def_id, fn_args) = *callee_ty.kind() else { @@ -105,6 +108,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return Ok(()); } + sym::caller_location => { + let location = self.get_caller_location(bx, source_info); + location.val.store(bx, result); + return Ok(()); + } + sym::va_start => bx.va_start(args[0].immediate()), sym::va_end => bx.va_end(args[0].immediate()), sym::size_of_val => { From 6016f84e716c443f64c491a26f5ec1dfd42f2491 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 22 May 2025 14:15:41 +0000 Subject: [PATCH 2795/4206] Pass PlaceRef rather than Bx::Value to codegen_intrinsic_call --- .../rustc_codegen_gcc/src/intrinsic/mod.rs | 21 ++++---- compiler/rustc_codegen_llvm/src/intrinsic.rs | 50 ++++++++----------- compiler/rustc_codegen_ssa/src/mir/block.rs | 4 +- .../rustc_codegen_ssa/src/mir/intrinsic.rs | 5 +- .../rustc_codegen_ssa/src/traits/intrinsic.rs | 3 +- 5 files changed, 38 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index ba65c8205a500..18dabe9ea16c2 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -22,7 +22,7 @@ use rustc_codegen_ssa::traits::{ }; use rustc_middle::bug; #[cfg(feature = "master")] -use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; +use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; use rustc_middle::ty::{self, Instance, Ty}; use rustc_span::{Span, Symbol, sym}; @@ -202,7 +202,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc instance: Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, RValue<'gcc>>], - llresult: RValue<'gcc>, + result: PlaceRef<'tcx, RValue<'gcc>>, span: Span, ) -> Result<(), Instance<'tcx>> { let tcx = self.tcx; @@ -221,7 +221,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc let name_str = name.as_str(); let llret_ty = self.layout_of(ret_ty).gcc_type(self); - let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); let simple = get_simple_intrinsic(self, name); let simple_func = get_simple_function(self, name); @@ -271,7 +270,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc args[0].immediate(), args[1].immediate(), args[2].immediate(), - llresult, + result, ); return Ok(()); } @@ -1230,14 +1229,13 @@ fn try_intrinsic<'a, 'b, 'gcc, 'tcx>( try_func: RValue<'gcc>, data: RValue<'gcc>, _catch_func: RValue<'gcc>, - dest: RValue<'gcc>, + dest: PlaceRef<'tcx, RValue<'gcc>>, ) { if bx.sess().panic_strategy() == PanicStrategy::Abort { bx.call(bx.type_void(), None, None, try_func, &[data], None, None); // Return 0 unconditionally from the intrinsic call; // we can never unwind. - let ret_align = bx.tcx.data_layout.i32_align.abi; - bx.store(bx.const_i32(0), dest, ret_align); + OperandValue::Immediate(bx.const_i32(0)).store(bx, dest); } else { if wants_msvc_seh(bx.sess()) { unimplemented!(); @@ -1261,12 +1259,12 @@ fn try_intrinsic<'a, 'b, 'gcc, 'tcx>( // functions in play. By calling a shim we're guaranteed that our shim will have // the right personality function. #[cfg(feature = "master")] -fn codegen_gnu_try<'gcc>( - bx: &mut Builder<'_, 'gcc, '_>, +fn codegen_gnu_try<'gcc, 'tcx>( + bx: &mut Builder<'_, 'gcc, 'tcx>, try_func: RValue<'gcc>, data: RValue<'gcc>, catch_func: RValue<'gcc>, - dest: RValue<'gcc>, + dest: PlaceRef<'tcx, RValue<'gcc>>, ) { let cx: &CodegenCx<'gcc, '_> = bx.cx; let (llty, func) = get_rust_try_fn(cx, &mut |mut bx| { @@ -1322,8 +1320,7 @@ fn codegen_gnu_try<'gcc>( // Note that no invoke is used here because by definition this function // can't panic (that's what it's catching). let ret = bx.call(llty, None, None, func, &[try_func, data, catch_func], None, None); - let i32_align = bx.tcx().data_layout.i32_align.abi; - bx.store(ret, dest, i32_align); + OperandValue::Immediate(ret).store(bx, dest); } // Helper function used to get a handle to the `__rust_try` function used to diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 5ca5737529229..067dd9b1681f2 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -167,7 +167,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { instance: ty::Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, &'ll Value>], - llresult: &'ll Value, + result: PlaceRef<'tcx, &'ll Value>, span: Span, ) -> Result<(), ty::Instance<'tcx>> { let tcx = self.tcx; @@ -184,7 +184,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { let name = tcx.item_name(def_id); let llret_ty = self.layout_of(ret_ty).llvm_type(self); - let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); let simple = get_simple_intrinsic(self, name); let llval = match name { @@ -255,7 +254,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { args[0].immediate(), args[1].immediate(), args[2].immediate(), - llresult, + result, ); return Ok(()); } @@ -688,20 +687,19 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } } -fn catch_unwind_intrinsic<'ll>( - bx: &mut Builder<'_, 'll, '_>, +fn catch_unwind_intrinsic<'ll, 'tcx>( + bx: &mut Builder<'_, 'll, 'tcx>, try_func: &'ll Value, data: &'ll Value, catch_func: &'ll Value, - dest: &'ll Value, + dest: PlaceRef<'tcx, &'ll Value>, ) { if bx.sess().panic_strategy() == PanicStrategy::Abort { let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void()); bx.call(try_func_ty, None, None, try_func, &[data], None, None); // Return 0 unconditionally from the intrinsic call; // we can never unwind. - let ret_align = bx.tcx().data_layout.i32_align.abi; - bx.store(bx.const_i32(0), dest, ret_align); + OperandValue::Immediate(bx.const_i32(0)).store(bx, dest); } else if wants_msvc_seh(bx.sess()) { codegen_msvc_try(bx, try_func, data, catch_func, dest); } else if wants_wasm_eh(bx.sess()) { @@ -720,12 +718,12 @@ fn catch_unwind_intrinsic<'ll>( // instructions are meant to work for all targets, as of the time of this // writing, however, LLVM does not recommend the usage of these new instructions // as the old ones are still more optimized. -fn codegen_msvc_try<'ll>( - bx: &mut Builder<'_, 'll, '_>, +fn codegen_msvc_try<'ll, 'tcx>( + bx: &mut Builder<'_, 'll, 'tcx>, try_func: &'ll Value, data: &'ll Value, catch_func: &'ll Value, - dest: &'ll Value, + dest: PlaceRef<'tcx, &'ll Value>, ) { let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| { bx.set_personality_fn(bx.eh_personality()); @@ -865,17 +863,16 @@ fn codegen_msvc_try<'ll>( // Note that no invoke is used here because by definition this function // can't panic (that's what it's catching). let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None); - let i32_align = bx.tcx().data_layout.i32_align.abi; - bx.store(ret, dest, i32_align); + OperandValue::Immediate(ret).store(bx, dest); } // WASM's definition of the `rust_try` function. -fn codegen_wasm_try<'ll>( - bx: &mut Builder<'_, 'll, '_>, +fn codegen_wasm_try<'ll, 'tcx>( + bx: &mut Builder<'_, 'll, 'tcx>, try_func: &'ll Value, data: &'ll Value, catch_func: &'ll Value, - dest: &'ll Value, + dest: PlaceRef<'tcx, &'ll Value>, ) { let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| { bx.set_personality_fn(bx.eh_personality()); @@ -939,8 +936,7 @@ fn codegen_wasm_try<'ll>( // Note that no invoke is used here because by definition this function // can't panic (that's what it's catching). let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None); - let i32_align = bx.tcx().data_layout.i32_align.abi; - bx.store(ret, dest, i32_align); + OperandValue::Immediate(ret).store(bx, dest); } // Definition of the standard `try` function for Rust using the GNU-like model @@ -954,12 +950,12 @@ fn codegen_wasm_try<'ll>( // function calling it, and that function may already have other personality // functions in play. By calling a shim we're guaranteed that our shim will have // the right personality function. -fn codegen_gnu_try<'ll>( - bx: &mut Builder<'_, 'll, '_>, +fn codegen_gnu_try<'ll, 'tcx>( + bx: &mut Builder<'_, 'll, 'tcx>, try_func: &'ll Value, data: &'ll Value, catch_func: &'ll Value, - dest: &'ll Value, + dest: PlaceRef<'tcx, &'ll Value>, ) { let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| { // Codegens the shims described above: @@ -1006,19 +1002,18 @@ fn codegen_gnu_try<'ll>( // Note that no invoke is used here because by definition this function // can't panic (that's what it's catching). let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None); - let i32_align = bx.tcx().data_layout.i32_align.abi; - bx.store(ret, dest, i32_align); + OperandValue::Immediate(ret).store(bx, dest); } // Variant of codegen_gnu_try used for emscripten where Rust panics are // implemented using C++ exceptions. Here we use exceptions of a specific type // (`struct rust_panic`) to represent Rust panics. -fn codegen_emcc_try<'ll>( - bx: &mut Builder<'_, 'll, '_>, +fn codegen_emcc_try<'ll, 'tcx>( + bx: &mut Builder<'_, 'll, 'tcx>, try_func: &'ll Value, data: &'ll Value, catch_func: &'ll Value, - dest: &'ll Value, + dest: PlaceRef<'tcx, &'ll Value>, ) { let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| { // Codegens the shims described above: @@ -1089,8 +1084,7 @@ fn codegen_emcc_try<'ll>( // Note that no invoke is used here because by definition this function // can't panic (that's what it's catching). let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None); - let i32_align = bx.tcx().data_layout.i32_align.abi; - bx.store(ret, dest, i32_align); + OperandValue::Immediate(ret).store(bx, dest); } // Helper function to give a Block to a closure to codegen a shim function. diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 1d11b907e9081..1a291b17886cc 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -965,12 +965,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let args: Vec<_> = args.iter().map(|arg| self.codegen_operand(bx, &arg.node)).collect(); + let result = PlaceRef::new_sized(dest, fn_abi.ret.layout); + match self.codegen_intrinsic_call( bx, instance, fn_abi, &args, - dest, + result, source_info, ) { Ok(()) => { diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 6cdd8480cbe31..6a0778832981b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -58,7 +58,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { instance: ty::Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, Bx::Value>], - llresult: Bx::Value, + result: PlaceRef<'tcx, Bx::Value>, source_info: SourceInfo, ) -> Result<(), ty::Instance<'tcx>> { let span = source_info.span; @@ -100,7 +100,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } let llret_ty = bx.backend_type(bx.layout_of(ret_ty)); - let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); let llval = match name { sym::abort => { @@ -537,7 +536,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { _ => { // Need to use backend-specific things in the implementation. - return bx.codegen_intrinsic_call(instance, fn_abi, args, llresult, span); + return bx.codegen_intrinsic_call(instance, fn_abi, args, result, span); } }; diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs index 88cf8dbf0c5c8..f9d6dab6fafc3 100644 --- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs @@ -4,6 +4,7 @@ use rustc_target::callconv::FnAbi; use super::BackendTypes; use crate::mir::operand::OperandRef; +use crate::mir::place::PlaceRef; pub trait IntrinsicCallBuilderMethods<'tcx>: BackendTypes { /// Remember to add all intrinsics here, in `compiler/rustc_hir_analysis/src/check/mod.rs`, @@ -16,7 +17,7 @@ pub trait IntrinsicCallBuilderMethods<'tcx>: BackendTypes { instance: ty::Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, Self::Value>], - llresult: Self::Value, + result: PlaceRef<'tcx, Self::Value>, span: Span, ) -> Result<(), ty::Instance<'tcx>>; From 0a14e1b2e7483179fa74f44d3c198c33325f6d29 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 22 May 2025 14:58:58 +0000 Subject: [PATCH 2796/4206] Remove usage of FnAbi in codegen_intrinsic_call --- .../rustc_codegen_gcc/src/intrinsic/mod.rs | 32 +++++++------------ compiler/rustc_codegen_llvm/src/intrinsic.rs | 30 ++++++----------- compiler/rustc_codegen_ssa/src/mir/block.rs | 10 ++---- .../rustc_codegen_ssa/src/mir/intrinsic.rs | 18 ++++------- .../rustc_codegen_ssa/src/traits/intrinsic.rs | 4 +-- 5 files changed, 31 insertions(+), 63 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 18dabe9ea16c2..1bcb891a2504a 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -26,7 +26,7 @@ use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; use rustc_middle::ty::{self, Instance, Ty}; use rustc_span::{Span, Symbol, sym}; -use rustc_target::callconv::{ArgAbi, FnAbi, PassMode}; +use rustc_target::callconv::{ArgAbi, PassMode}; use rustc_target::spec::PanicStrategy; #[cfg(feature = "master")] @@ -200,7 +200,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc fn codegen_intrinsic_call( &mut self, instance: Instance<'tcx>, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, RValue<'gcc>>], result: PlaceRef<'tcx, RValue<'gcc>>, span: Span, @@ -285,17 +284,10 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc } sym::volatile_load | sym::unaligned_volatile_load => { - let tp_ty = fn_args.type_at(0); let ptr = args[0].immediate(); - let layout = self.layout_of(tp_ty); - let load = if let PassMode::Cast { cast: ref ty, pad_i32: _ } = fn_abi.ret.mode { - let gcc_ty = ty.gcc_type(self); - self.volatile_load(gcc_ty, ptr) - } else { - self.volatile_load(layout.gcc_type(self), ptr) - }; + let load = self.volatile_load(result.layout.gcc_type(self), ptr); // TODO(antoyo): set alignment. - if let BackendRepr::Scalar(scalar) = layout.backend_repr { + if let BackendRepr::Scalar(scalar) = result.layout.backend_repr { self.to_immediate_scalar(load, scalar) } else { load @@ -510,16 +502,14 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc _ => return Err(Instance::new_raw(instance.def_id(), instance.args)), }; - if !fn_abi.ret.is_ignore() { - if let PassMode::Cast { cast: ref ty, .. } = fn_abi.ret.mode { - let ptr_llty = self.type_ptr_to(ty.gcc_type(self)); - let ptr = self.pointercast(result.val.llval, ptr_llty); - self.store(value, ptr, result.val.align); - } else { - OperandRef::from_immediate_or_packed_pair(self, value, result.layout) - .val - .store(self, result); - } + if result.layout.ty.is_bool() { + OperandRef::from_immediate_or_packed_pair(self, value, result.layout) + .val + .store(self, result); + } else if !result.layout.ty.is_unit() { + let ptr_llty = self.type_ptr_to(result.layout.gcc_type(self)); + let ptr = self.pointercast(result.val.llval, ptr_llty); + self.store(value, ptr, result.val.align); } Ok(()) } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 067dd9b1681f2..e8629aeebb95a 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -15,11 +15,10 @@ use rustc_middle::ty::{self, GenericArgsRef, Ty}; use rustc_middle::{bug, span_bug}; use rustc_span::{Span, Symbol, sym}; use rustc_symbol_mangling::mangle_internal_symbol; -use rustc_target::callconv::{FnAbi, PassMode}; use rustc_target::spec::{HasTargetSpec, PanicStrategy}; use tracing::debug; -use crate::abi::{FnAbiLlvmExt, LlvmType}; +use crate::abi::FnAbiLlvmExt; use crate::builder::Builder; use crate::context::CodegenCx; use crate::llvm::{self, Metadata}; @@ -165,7 +164,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { fn codegen_intrinsic_call( &mut self, instance: ty::Instance<'tcx>, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, &'ll Value>], result: PlaceRef<'tcx, &'ll Value>, span: Span, @@ -263,7 +261,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { self.call_intrinsic("llvm.va_copy", &[args[0].immediate(), args[1].immediate()]) } sym::va_arg => { - match fn_abi.ret.layout.backend_repr { + match result.layout.backend_repr { BackendRepr::Scalar(scalar) => { match scalar.primitive() { Primitive::Int(..) => { @@ -298,18 +296,12 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } sym::volatile_load | sym::unaligned_volatile_load => { - let tp_ty = fn_args.type_at(0); let ptr = args[0].immediate(); - let load = if let PassMode::Cast { cast: ty, pad_i32: _ } = &fn_abi.ret.mode { - let llty = ty.llvm_type(self); - self.volatile_load(llty, ptr) - } else { - self.volatile_load(self.layout_of(tp_ty).llvm_type(self), ptr) - }; + let load = self.volatile_load(result.layout.llvm_type(self), ptr); let align = if name == sym::unaligned_volatile_load { 1 } else { - self.align_of(tp_ty).bytes() as u32 + result.layout.align.abi.bytes() as u32 }; unsafe { llvm::LLVMSetAlignment(load, align); @@ -628,14 +620,12 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } }; - if !fn_abi.ret.is_ignore() { - if let PassMode::Cast { .. } = &fn_abi.ret.mode { - self.store(llval, result.val.llval, result.val.align); - } else { - OperandRef::from_immediate_or_packed_pair(self, llval, result.layout) - .val - .store(self, result); - } + if result.layout.ty.is_bool() { + OperandRef::from_immediate_or_packed_pair(self, llval, result.layout) + .val + .store(self, result); + } else if !result.layout.ty.is_unit() { + self.store_to_place(llval, result.val); } Ok(()) } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 1a291b17886cc..a2565c4f69d3a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -967,14 +967,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let result = PlaceRef::new_sized(dest, fn_abi.ret.layout); - match self.codegen_intrinsic_call( - bx, - instance, - fn_abi, - &args, - result, - source_info, - ) { + match self.codegen_intrinsic_call(bx, instance, &args, result, source_info) + { Ok(()) => { if let ReturnDest::IndirectOperand(dst, _) = ret_dest { self.store_return(bx, ret_dest, &fn_abi.ret, dst.val.llval); diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 6a0778832981b..a6d159c51e132 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -4,7 +4,6 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::config::OptLevel; use rustc_span::sym; -use rustc_target::callconv::{FnAbi, PassMode}; use super::FunctionCx; use super::operand::OperandRef; @@ -56,7 +55,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &mut self, bx: &mut Bx, instance: ty::Instance<'tcx>, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, Bx::Value>], result: PlaceRef<'tcx, Bx::Value>, source_info: SourceInfo, @@ -536,18 +534,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { _ => { // Need to use backend-specific things in the implementation. - return bx.codegen_intrinsic_call(instance, fn_abi, args, result, span); + return bx.codegen_intrinsic_call(instance, args, result, span); } }; - if !fn_abi.ret.is_ignore() { - if let PassMode::Cast { .. } = &fn_abi.ret.mode { - bx.store_to_place(llval, result.val); - } else { - OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout) - .val - .store(bx, result); - } + if result.layout.ty.is_bool() { + OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout) + .val + .store(bx, result); + } else if !result.layout.ty.is_unit() { + bx.store_to_place(llval, result.val); } Ok(()) } diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs index f9d6dab6fafc3..a07c569a03237 100644 --- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs @@ -1,6 +1,5 @@ -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty; use rustc_span::Span; -use rustc_target::callconv::FnAbi; use super::BackendTypes; use crate::mir::operand::OperandRef; @@ -15,7 +14,6 @@ pub trait IntrinsicCallBuilderMethods<'tcx>: BackendTypes { fn codegen_intrinsic_call( &mut self, instance: ty::Instance<'tcx>, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, Self::Value>], result: PlaceRef<'tcx, Self::Value>, span: Span, From 7122648e3403bbbd471cd2667d5960a109bb9bd7 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 22 May 2025 17:49:28 +0000 Subject: [PATCH 2797/4206] Don't depend on FnAbi for intrinsics Intrinsics are not real functions and as such don't have any calling convention. Trying to compute a calling convention for an intrinsic anyway is a nonsensical operation. --- compiler/rustc_codegen_ssa/src/mir/block.rs | 74 ++++++++++++--------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index a2565c4f69d3a..cb8088e9efba7 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -8,7 +8,7 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::mir::{self, AssertKind, InlineAsmMacro, SwitchTargets, UnwindTerminateReason}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; -use rustc_middle::ty::{self, Instance, List, Ty}; +use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::{bug, span_bug}; use rustc_session::config::OptLevel; use rustc_span::Span; @@ -941,37 +941,55 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return merging_succ; } - let fn_abi = bx.fn_abi_of_instance(instance, List::empty()); + let result_layout = + self.cx.layout_of(self.monomorphized_place_ty(destination.as_ref())); - let mut llargs = Vec::with_capacity(1); - let ret_dest = self.make_return_dest( - bx, - destination, - &fn_abi.ret, - &mut llargs, - Some(intrinsic), - ); - let dest = match ret_dest { - _ if fn_abi.ret.is_indirect() => llargs[0], - ReturnDest::Nothing => bx.const_undef(bx.type_ptr()), - ReturnDest::IndirectOperand(dst, _) | ReturnDest::Store(dst) => { - dst.val.llval - } - ReturnDest::DirectOperand(_) => { - bug!("Cannot use direct operand with an intrinsic call") + let (result, store_in_local) = if result_layout.is_zst() { + ( + PlaceRef::new_sized(bx.const_undef(bx.type_ptr()), result_layout), + None, + ) + } else if let Some(local) = destination.as_local() { + match self.locals[local] { + LocalRef::Place(dest) => (dest, None), + LocalRef::UnsizedPlace(_) => bug!("return type must be sized"), + LocalRef::PendingOperand => { + // Currently, intrinsics always need a location to store + // the result, so we create a temporary `alloca` for the + // result. + let tmp = PlaceRef::alloca(bx, result_layout); + tmp.storage_live(bx); + (tmp, Some(local)) + } + LocalRef::Operand(_) => { + bug!("place local already assigned to"); + } } + } else { + (self.codegen_place(bx, destination.as_ref()), None) }; + if result.val.align < result.layout.align.abi { + // Currently, MIR code generation does not create calls + // that store directly to fields of packed structs (in + // fact, the calls it creates write only to temps). + // + // If someone changes that, please update this code path + // to create a temporary. + span_bug!(self.mir.span, "can't directly store to unaligned value"); + } + let args: Vec<_> = args.iter().map(|arg| self.codegen_operand(bx, &arg.node)).collect(); - let result = PlaceRef::new_sized(dest, fn_abi.ret.layout); - match self.codegen_intrinsic_call(bx, instance, &args, result, source_info) { Ok(()) => { - if let ReturnDest::IndirectOperand(dst, _) = ret_dest { - self.store_return(bx, ret_dest, &fn_abi.ret, dst.val.llval); + if let Some(local) = store_in_local { + let op = bx.load_operand(result); + result.storage_dead(bx); + self.overwrite_local(local, LocalRef::Operand(op)); + self.debug_introduce_local(bx, local); } return if let Some(target) = target { @@ -1026,7 +1044,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // We still need to call `make_return_dest` even if there's no `target`, since // `fn_abi.ret` could be `PassMode::Indirect`, even if it is uninhabited, // and `make_return_dest` adds the return-place indirect pointer to `llargs`. - let return_dest = self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs, None); + let return_dest = self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs); let destination = target.map(|target| (return_dest, target)); // Split the rust-call tupled arguments off. @@ -1857,7 +1875,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { dest: mir::Place<'tcx>, fn_ret: &ArgAbi<'tcx, Ty<'tcx>>, llargs: &mut Vec, - intrinsic: Option, ) -> ReturnDest<'tcx, Bx::Value> { // If the return is ignored, we can just return a do-nothing `ReturnDest`. if fn_ret.is_ignore() { @@ -1877,13 +1894,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { tmp.storage_live(bx); llargs.push(tmp.val.llval); ReturnDest::IndirectOperand(tmp, index) - } else if intrinsic.is_some() { - // Currently, intrinsics always need a location to store - // the result, so we create a temporary `alloca` for the - // result. - let tmp = PlaceRef::alloca(bx, fn_ret.layout); - tmp.storage_live(bx); - ReturnDest::IndirectOperand(tmp, index) } else { ReturnDest::DirectOperand(index) }; @@ -1893,7 +1903,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } } else { - self.codegen_place(bx, mir::PlaceRef { local: dest.local, projection: dest.projection }) + self.codegen_place(bx, dest.as_ref()) }; if fn_ret.is_indirect() { if dest.val.align < dest.layout.align.abi { From 165fb988499b771afb7c2ddb60f05e9e337afb6a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 23 May 2025 08:30:58 +0000 Subject: [PATCH 2798/4206] Reduce indentation in codegen_panic_intrinsic --- compiler/rustc_codegen_ssa/src/mir/block.rs | 96 ++++++++++----------- 1 file changed, 47 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index cb8088e9efba7..1baab62ae43ac 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -836,58 +836,56 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Emit a panic or a no-op for `assert_*` intrinsics. // These are intrinsics that compile to panics so that we can get a message // which mentions the offending type, even from a const context. - if let Some(requirement) = ValidityRequirement::from_intrinsic(intrinsic.name) { - let ty = instance.args.type_at(0); - - let do_panic = !bx - .tcx() - .check_validity_requirement((requirement, bx.typing_env().as_query_input(ty))) - .expect("expect to have layout during codegen"); - - let layout = bx.layout_of(ty); - - Some(if do_panic { - let msg_str = with_no_visible_paths!({ - with_no_trimmed_paths!({ - if layout.is_uninhabited() { - // Use this error even for the other intrinsics as it is more precise. - format!("attempted to instantiate uninhabited type `{ty}`") - } else if requirement == ValidityRequirement::Zero { - format!("attempted to zero-initialize type `{ty}`, which is invalid") - } else { - format!( - "attempted to leave type `{ty}` uninitialized, which is invalid" - ) - } - }) - }); - let msg = bx.const_str(&msg_str); + let Some(requirement) = ValidityRequirement::from_intrinsic(intrinsic.name) else { + return None; + }; - // Obtain the panic entry point. - let (fn_abi, llfn, instance) = - common::build_langcall(bx, Some(source_info.span), LangItem::PanicNounwind); + let ty = instance.args.type_at(0); - // Codegen the actual panic invoke/call. - helper.do_call( - self, - bx, - fn_abi, - llfn, - &[msg.0, msg.1], - target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)), - unwind, - &[], - Some(instance), - mergeable_succ, - ) - } else { - // a NOP - let target = target.unwrap(); - helper.funclet_br(self, bx, target, mergeable_succ) - }) - } else { - None + let is_valid = bx + .tcx() + .check_validity_requirement((requirement, bx.typing_env().as_query_input(ty))) + .expect("expect to have layout during codegen"); + + if is_valid { + // a NOP + let target = target.unwrap(); + return Some(helper.funclet_br(self, bx, target, mergeable_succ)); } + + let layout = bx.layout_of(ty); + + let msg_str = with_no_visible_paths!({ + with_no_trimmed_paths!({ + if layout.is_uninhabited() { + // Use this error even for the other intrinsics as it is more precise. + format!("attempted to instantiate uninhabited type `{ty}`") + } else if requirement == ValidityRequirement::Zero { + format!("attempted to zero-initialize type `{ty}`, which is invalid") + } else { + format!("attempted to leave type `{ty}` uninitialized, which is invalid") + } + }) + }); + let msg = bx.const_str(&msg_str); + + // Obtain the panic entry point. + let (fn_abi, llfn, instance) = + common::build_langcall(bx, Some(source_info.span), LangItem::PanicNounwind); + + // Codegen the actual panic invoke/call. + Some(helper.do_call( + self, + bx, + fn_abi, + llfn, + &[msg.0, msg.1], + target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)), + unwind, + &[], + Some(instance), + mergeable_succ, + )) } fn codegen_call_terminator( From 457f8ba447a2f2d3fc20ad2b0d779d49c9883485 Mon Sep 17 00:00:00 2001 From: dianqk Date: Sat, 24 May 2025 19:43:26 +0800 Subject: [PATCH 2799/4206] mir-opt: Do not transform non-int type in match_branches --- .../rustc_mir_transform/src/match_branches.rs | 6 ++-- ..._int_failed.MatchBranchSimplification.diff | 29 +++++++++++++++++ tests/mir-opt/matches_reduce_branches.rs | 32 +++++++++++++++++++ 3 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 tests/mir-opt/matches_reduce_branches.match_non_int_failed.MatchBranchSimplification.diff diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index 8c0c309689902..5e511f1a418b6 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -284,12 +284,14 @@ fn can_cast( let v = match src_layout.ty.kind() { ty::Uint(_) => from_scalar.to_uint(src_layout.size), ty::Int(_) => from_scalar.to_int(src_layout.size) as u128, - _ => unreachable!("invalid int"), + // We can also transform the values of other integer representations (such as char), + // although this may not be practical in real-world scenarios. + _ => return false, }; let size = match *cast_ty.kind() { ty::Int(t) => Integer::from_int_ty(&tcx, t).size(), ty::Uint(t) => Integer::from_uint_ty(&tcx, t).size(), - _ => unreachable!("invalid int"), + _ => return false, }; let v = size.truncate(v); let cast_scalar = ScalarInt::try_from_uint(v, size).unwrap(); diff --git a/tests/mir-opt/matches_reduce_branches.match_non_int_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_non_int_failed.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..81e900a34c087 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_non_int_failed.MatchBranchSimplification.diff @@ -0,0 +1,29 @@ +- // MIR for `match_non_int_failed` before MatchBranchSimplification ++ // MIR for `match_non_int_failed` after MatchBranchSimplification + + fn match_non_int_failed(_1: char) -> u8 { + let mut _0: u8; + + bb0: { + switchInt(copy _1) -> [97: bb1, 98: bb2, otherwise: bb3]; + } + + bb1: { + _0 = const 97_u8; + goto -> bb4; + } + + bb2: { + _0 = const 98_u8; + goto -> bb4; + } + + bb3: { + unreachable; + } + + bb4: { + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.rs b/tests/mir-opt/matches_reduce_branches.rs index 3372ae2f2a614..19611a843c663 100644 --- a/tests/mir-opt/matches_reduce_branches.rs +++ b/tests/mir-opt/matches_reduce_branches.rs @@ -628,6 +628,37 @@ fn match_i128_u128(i: EnumAi128) -> u128 { } } +// EMIT_MIR matches_reduce_branches.match_non_int_failed.MatchBranchSimplification.diff +#[custom_mir(dialect = "runtime")] +fn match_non_int_failed(i: char) -> u8 { + // CHECK-LABEL: fn match_non_int_failed( + // CHECK: switchInt + // CHECK: return + mir! { + { + match i { + 'a' => bb1, + 'b' => bb2, + _ => unreachable_bb, + } + } + bb1 = { + RET = 97; + Goto(ret) + } + bb2 = { + RET = 98; + Goto(ret) + } + unreachable_bb = { + Unreachable() + } + ret = { + Return() + } + } +} + fn main() { let _ = foo(None); let _ = foo(Some(())); @@ -665,4 +696,5 @@ fn main() { let _ = match_i128_u128(EnumAi128::A); let _ = my_is_some(None); + let _ = match_non_int_failed('a'); } From a59c86ab449ddb83f824b12f87c1e2c6a38399be Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 23 May 2025 11:47:02 +0000 Subject: [PATCH 2800/4206] Deduplicate dyn compatibility violations due to coercion --- compiler/rustc_hir_typeck/src/coercion.rs | 18 +++++- .../dyn/mut-is-pointer-like.stderr | 20 +------ tests/ui/async-await/dyn/works.stderr | 20 +------ tests/ui/async-await/dyn/wrong-size.stderr | 20 +------ .../almost-supertrait-associated-type.rs | 1 - .../almost-supertrait-associated-type.stderr | 26 ++------ .../ui/dyn-compatibility/associated-consts.rs | 1 - .../associated-consts.stderr | 19 +----- tests/ui/dyn-compatibility/generics.rs | 2 - tests/ui/dyn-compatibility/generics.stderr | 40 +------------ .../mention-correct-dyn-incompatible-trait.rs | 1 - ...tion-correct-dyn-incompatible-trait.stderr | 21 +------ tests/ui/dyn-compatibility/mentions-Self.rs | 2 - .../ui/dyn-compatibility/mentions-Self.stderr | 38 +----------- tests/ui/dyn-compatibility/no-static.rs | 1 - tests/ui/dyn-compatibility/no-static.stderr | 27 +-------- tests/ui/dyn-compatibility/sized-2.rs | 1 - tests/ui/dyn-compatibility/sized-2.stderr | 18 +----- tests/ui/dyn-compatibility/sized.rs | 1 - tests/ui/dyn-compatibility/sized.stderr | 18 +----- .../ui/dyn-compatibility/taint-const-eval.rs | 1 - .../dyn-compatibility/taint-const-eval.stderr | 26 +------- ...ure-gate-dispatch-from-dyn-missing-impl.rs | 1 - ...gate-dispatch-from-dyn-missing-impl.stderr | 22 +------ .../gat-in-trait-path.rs | 1 - .../gat-in-trait-path.stderr | 19 +----- .../generic-associated-types/issue-71176.rs | 1 - .../issue-71176.stderr | 20 +------ .../generic-associated-types/issue-76535.rs | 1 - .../issue-76535.stderr | 21 +------ .../generic-associated-types/issue-79422.rs | 14 +++-- .../issue-79422.stderr | 27 ++------- .../trait-bounds/span-bug-issue-121597.rs | 1 - .../trait-bounds/span-bug-issue-121597.stderr | 20 +------ ...ible-trait-in-return-position-dyn-trait.rs | 4 +- ...-trait-in-return-position-dyn-trait.stderr | 60 +------------------ .../impl-trait/in-trait/dyn-compatibility.rs | 1 - .../in-trait/dyn-compatibility.stderr | 20 +------ tests/ui/issues/issue-18959.rs | 1 - tests/ui/issues/issue-18959.stderr | 19 +----- tests/ui/issues/issue-19380.rs | 1 - tests/ui/issues/issue-19380.stderr | 27 +-------- tests/ui/issues/issue-50781.rs | 1 - tests/ui/issues/issue-50781.stderr | 20 +------ .../ui/kindck/kindck-inherited-copy-bound.rs | 1 - .../kindck/kindck-inherited-copy-bound.stderr | 18 +----- .../arbitrary-self-types-dyn-incompatible.rs | 1 - ...bitrary-self-types-dyn-incompatible.stderr | 22 +------ .../statics/unsizing-wfcheck-issue-127299.rs | 1 - .../unsizing-wfcheck-issue-127299.stderr | 26 +------- tests/ui/traits/issue-20692.rs | 1 - tests/ui/traits/issue-20692.stderr | 21 +------ tests/ui/traits/issue-38604.rs | 2 +- tests/ui/traits/issue-38604.stderr | 19 +----- .../supertrait-dyn-compatibility.rs | 1 - .../supertrait-dyn-compatibility.stderr | 21 +------ ...onicalize-fresh-infer-vars-issue-103626.rs | 1 - ...alize-fresh-infer-vars-issue-103626.stderr | 26 +------- tests/ui/traits/object/safety.rs | 1 - tests/ui/traits/object/safety.stderr | 27 +-------- tests/ui/traits/test-2.rs | 1 - tests/ui/traits/test-2.stderr | 26 +------- 62 files changed, 73 insertions(+), 767 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 4f77594deca6b..ddc80fab2ce18 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -47,7 +47,7 @@ use rustc_infer::infer::relate::RelateResult; use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult}; use rustc_infer::traits::{ IfExpressionCause, MatchExpressionArmCause, Obligation, PredicateObligation, - PredicateObligations, + PredicateObligations, SelectionError, }; use rustc_middle::span_bug; use rustc_middle::ty::adjustment::{ @@ -677,7 +677,21 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { return Err(TypeError::Mismatch); } - // Dyn-compatibility violations or miscellaneous. + Err(SelectionError::TraitDynIncompatible(_)) => { + // Dyn compatibility errors in coercion will *always* be due to the + // fact that the RHS of the coercion is a non-dyn compatible `dyn Trait` + // writen in source somewhere (otherwise we will never have lowered + // the dyn trait from HIR to middle). + // + // There's no reason to emit yet another dyn compatibility error, + // especially since the span will differ slightly and thus not be + // deduplicated at all! + self.fcx.set_tainted_by_errors( + self.fcx + .dcx() + .span_delayed_bug(self.cause.span, "dyn compatibility during coercion"), + ); + } Err(err) => { let guar = self.err_ctxt().report_selection_error( obligation.clone(), diff --git a/tests/ui/async-await/dyn/mut-is-pointer-like.stderr b/tests/ui/async-await/dyn/mut-is-pointer-like.stderr index 07c3fd3527f28..9b818a15c29ce 100644 --- a/tests/ui/async-await/dyn/mut-is-pointer-like.stderr +++ b/tests/ui/async-await/dyn/mut-is-pointer-like.stderr @@ -24,24 +24,6 @@ LL | async fn async_dispatch(self: Pin<&mut Self>) -> Self::Output; | ^^^^^^^^^^^^^^ ...because method `async_dispatch` is `async` = help: consider moving `async_dispatch` to another trait -error[E0038]: the trait `AsyncTrait` is not dyn compatible - --> $DIR/mut-is-pointer-like.rs:35:56 - | -LL | let x: Pin<&mut dyn AsyncTrait> = f; - | ^ `AsyncTrait` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/mut-is-pointer-like.rs:16:14 - | -LL | trait AsyncTrait { - | ---------- this trait is not dyn compatible... -... -LL | async fn async_dispatch(self: Pin<&mut Self>) -> Self::Output; - | ^^^^^^^^^^^^^^ ...because method `async_dispatch` is `async` - = help: consider moving `async_dispatch` to another trait - = note: required for the cast from `Pin<&mut {async block@$DIR/mut-is-pointer-like.rs:32:32: 32:37}>` to `Pin<&mut dyn AsyncTrait>` - -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 1 previous error; 1 warning emitted For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/async-await/dyn/works.stderr b/tests/ui/async-await/dyn/works.stderr index 1fe2b28eca82f..5d2cc385cbd64 100644 --- a/tests/ui/async-await/dyn/works.stderr +++ b/tests/ui/async-await/dyn/works.stderr @@ -7,24 +7,6 @@ LL | #![feature(async_fn_in_dyn_trait)] = note: see issue #133119 for more information = note: `#[warn(incomplete_features)]` on by default -error[E0038]: the trait `AsyncTrait` is not dyn compatible - --> $DIR/works.rs:27:34 - | -LL | let x: &dyn AsyncTrait = &"hello, world!"; - | ^^^^^^^^^^^^^^^^ `AsyncTrait` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/works.rs:14:14 - | -LL | trait AsyncTrait { - | ---------- this trait is not dyn compatible... -LL | async fn async_dispatch(&self); - | ^^^^^^^^^^^^^^ ...because method `async_dispatch` is `async` - = help: consider moving `async_dispatch` to another trait - = help: only type `&'static str` implements `AsyncTrait`; consider using it directly instead. - = note: required for the cast from `&&'static str` to `&dyn AsyncTrait` - error[E0038]: the trait `AsyncTrait` is not dyn compatible --> $DIR/works.rs:27:16 | @@ -42,6 +24,6 @@ LL | async fn async_dispatch(&self); = help: consider moving `async_dispatch` to another trait = help: only type `&'static str` implements `AsyncTrait`; consider using it directly instead. -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 1 previous error; 1 warning emitted For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/async-await/dyn/wrong-size.stderr b/tests/ui/async-await/dyn/wrong-size.stderr index b4684f4fc174a..930ca571417d7 100644 --- a/tests/ui/async-await/dyn/wrong-size.stderr +++ b/tests/ui/async-await/dyn/wrong-size.stderr @@ -7,24 +7,6 @@ LL | #![feature(async_fn_in_dyn_trait)] = note: see issue #133119 for more information = note: `#[warn(incomplete_features)]` on by default -error[E0038]: the trait `AsyncTrait` is not dyn compatible - --> $DIR/wrong-size.rs:21:30 - | -LL | let x: &dyn AsyncTrait = &"hello, world!"; - | ^^^^^^^^^^^^^^^^ `AsyncTrait` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/wrong-size.rs:9:14 - | -LL | trait AsyncTrait { - | ---------- this trait is not dyn compatible... -LL | async fn async_dispatch(&self); - | ^^^^^^^^^^^^^^ ...because method `async_dispatch` is `async` - = help: consider moving `async_dispatch` to another trait - = help: only type `&'static str` implements `AsyncTrait`; consider using it directly instead. - = note: required for the cast from `&&'static str` to `&dyn AsyncTrait` - error[E0038]: the trait `AsyncTrait` is not dyn compatible --> $DIR/wrong-size.rs:21:12 | @@ -42,6 +24,6 @@ LL | async fn async_dispatch(&self); = help: consider moving `async_dispatch` to another trait = help: only type `&'static str` implements `AsyncTrait`; consider using it directly instead. -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 1 previous error; 1 warning emitted For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/dyn-compatibility/almost-supertrait-associated-type.rs b/tests/ui/dyn-compatibility/almost-supertrait-associated-type.rs index 1b1b8bcf03dc0..d73b67dc0809a 100644 --- a/tests/ui/dyn-compatibility/almost-supertrait-associated-type.rs +++ b/tests/ui/dyn-compatibility/almost-supertrait-associated-type.rs @@ -6,7 +6,6 @@ use std::marker::PhantomData; fn transmute(t: T) -> U { (&PhantomData:: as &dyn Foo).transmute(t) //~^ ERROR the trait `Foo` is not dyn compatible - //~| ERROR the trait `Foo` is not dyn compatible } struct ActuallySuper; diff --git a/tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr b/tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr index a384697ee083f..d3022b5d8cd4a 100644 --- a/tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr +++ b/tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr @@ -1,12 +1,12 @@ error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/almost-supertrait-associated-type.rs:21:20 + --> $DIR/almost-supertrait-associated-type.rs:20:20 | LL | impl Dyn for dyn Foo + '_ { | ^^^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit - --> $DIR/almost-supertrait-associated-type.rs:33:34 + --> $DIR/almost-supertrait-associated-type.rs:32:34 | LL | trait Foo: Super | --- this trait is not dyn compatible... @@ -23,7 +23,7 @@ LL | (&PhantomData:: as &dyn Foo).transmute(t) | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit - --> $DIR/almost-supertrait-associated-type.rs:33:34 + --> $DIR/almost-supertrait-associated-type.rs:32:34 | LL | trait Foo: Super | --- this trait is not dyn compatible... @@ -32,24 +32,6 @@ LL | fn transmute(&self, t: T) -> >::Assoc; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `transmute` references the `Self` type in its return type = help: consider moving `transmute` to another trait -error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/almost-supertrait-associated-type.rs:7:6 - | -LL | (&PhantomData:: as &dyn Foo).transmute(t) - | ^^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/almost-supertrait-associated-type.rs:33:34 - | -LL | trait Foo: Super - | --- this trait is not dyn compatible... -... -LL | fn transmute(&self, t: T) -> >::Assoc; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `transmute` references the `Self` type in its return type - = help: consider moving `transmute` to another trait - = note: required for the cast from `&PhantomData` to `&dyn Foo` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/dyn-compatibility/associated-consts.rs b/tests/ui/dyn-compatibility/associated-consts.rs index 10d151d9a8b59..69fff81b28146 100644 --- a/tests/ui/dyn-compatibility/associated-consts.rs +++ b/tests/ui/dyn-compatibility/associated-consts.rs @@ -8,7 +8,6 @@ trait Bar { fn make_bar(t: &T) -> &dyn Bar { //~^ ERROR E0038 t - //~^ ERROR E0038 } fn main() { diff --git a/tests/ui/dyn-compatibility/associated-consts.stderr b/tests/ui/dyn-compatibility/associated-consts.stderr index beaf263af07e8..dc64c93a577ec 100644 --- a/tests/ui/dyn-compatibility/associated-consts.stderr +++ b/tests/ui/dyn-compatibility/associated-consts.stderr @@ -14,23 +14,6 @@ LL | const X: usize; | ^ ...because it contains this associated `const` = help: consider moving `X` to another trait -error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/associated-consts.rs:10:5 - | -LL | t - | ^ `Bar` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/associated-consts.rs:5:11 - | -LL | trait Bar { - | --- this trait is not dyn compatible... -LL | const X: usize; - | ^ ...because it contains this associated `const` - = help: consider moving `X` to another trait - = note: required for the cast from `&T` to `&dyn Bar` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/dyn-compatibility/generics.rs b/tests/ui/dyn-compatibility/generics.rs index dcce17f925bc8..c25bdab361bae 100644 --- a/tests/ui/dyn-compatibility/generics.rs +++ b/tests/ui/dyn-compatibility/generics.rs @@ -15,14 +15,12 @@ trait Quux { fn make_bar(t: &T) -> &dyn Bar { //~^ ERROR E0038 t - //~^ ERROR E0038 } fn make_bar_explicit(t: &T) -> &dyn Bar { //~^ ERROR E0038 t as &dyn Bar //~^ ERROR E0038 - //~| ERROR E0038 } fn make_quux(t: &T) -> &dyn Quux { diff --git a/tests/ui/dyn-compatibility/generics.stderr b/tests/ui/dyn-compatibility/generics.stderr index c019301054193..aec51970ebb17 100644 --- a/tests/ui/dyn-compatibility/generics.stderr +++ b/tests/ui/dyn-compatibility/generics.stderr @@ -15,7 +15,7 @@ LL | fn bar(&self, t: T); = help: consider moving `bar` to another trait error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/generics.rs:21:40 + --> $DIR/generics.rs:20:40 | LL | fn make_bar_explicit(t: &T) -> &dyn Bar { | ^^^^^^^ `Bar` is not dyn compatible @@ -31,24 +31,7 @@ LL | fn bar(&self, t: T); = help: consider moving `bar` to another trait error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/generics.rs:17:5 - | -LL | t - | ^ `Bar` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/generics.rs:7:8 - | -LL | trait Bar { - | --- this trait is not dyn compatible... -LL | fn bar(&self, t: T); - | ^^^ ...because method `bar` has generic type parameters - = help: consider moving `bar` to another trait - = note: required for the cast from `&T` to `&dyn Bar` - -error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/generics.rs:23:10 + --> $DIR/generics.rs:22:10 | LL | t as &dyn Bar | ^^^^^^^^ `Bar` is not dyn compatible @@ -63,23 +46,6 @@ LL | fn bar(&self, t: T); | ^^^ ...because method `bar` has generic type parameters = help: consider moving `bar` to another trait -error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/generics.rs:23:5 - | -LL | t as &dyn Bar - | ^ `Bar` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/generics.rs:7:8 - | -LL | trait Bar { - | --- this trait is not dyn compatible... -LL | fn bar(&self, t: T); - | ^^^ ...because method `bar` has generic type parameters - = help: consider moving `bar` to another trait - = note: required for the cast from `&T` to `&dyn Bar` - -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.rs b/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.rs index 1289d2d7874aa..d8b1bc5b71777 100644 --- a/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.rs +++ b/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.rs @@ -18,5 +18,4 @@ fn main() { let mut thing = Thing; let test: &mut dyn Bar = &mut thing; //~^ ERROR E0038 - //~| ERROR E0038 } diff --git a/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr b/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr index c1e93ccb83ca9..5bc1847ebde5e 100644 --- a/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr +++ b/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr @@ -1,22 +1,3 @@ -error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/mention-correct-dyn-incompatible-trait.rs:19:30 - | -LL | let test: &mut dyn Bar = &mut thing; - | ^^^^^^^^^^ `Bar` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/mention-correct-dyn-incompatible-trait.rs:4:8 - | -LL | fn foo(&self, val: T); - | ^^^ ...because method `foo` has generic type parameters -... -LL | trait Bar: Foo { } - | --- this trait is not dyn compatible... - = help: consider moving `foo` to another trait - = help: only type `Thing` implements `Bar`; consider using it directly instead. - = note: required for the cast from `&mut Thing` to `&mut dyn Bar` - error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/mention-correct-dyn-incompatible-trait.rs:19:15 | @@ -35,6 +16,6 @@ LL | trait Bar: Foo { } = help: consider moving `foo` to another trait = help: only type `Thing` implements `Bar`; consider using it directly instead. -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/dyn-compatibility/mentions-Self.rs b/tests/ui/dyn-compatibility/mentions-Self.rs index ce210f4776f7b..8b0d5ec6604a0 100644 --- a/tests/ui/dyn-compatibility/mentions-Self.rs +++ b/tests/ui/dyn-compatibility/mentions-Self.rs @@ -18,13 +18,11 @@ trait Quux { fn make_bar(t: &T) -> &dyn Bar { //~^ ERROR E0038 t - //~^ ERROR E0038 } fn make_baz(t: &T) -> &dyn Baz { //~^ ERROR E0038 t - //~^ ERROR E0038 } fn make_quux(t: &T) -> &dyn Quux { diff --git a/tests/ui/dyn-compatibility/mentions-Self.stderr b/tests/ui/dyn-compatibility/mentions-Self.stderr index 6d1ae90152e64..9d41e1d92ddf7 100644 --- a/tests/ui/dyn-compatibility/mentions-Self.stderr +++ b/tests/ui/dyn-compatibility/mentions-Self.stderr @@ -15,7 +15,7 @@ LL | fn bar(&self, x: &Self); = help: consider moving `bar` to another trait error[E0038]: the trait `Baz` is not dyn compatible - --> $DIR/mentions-Self.rs:24:31 + --> $DIR/mentions-Self.rs:23:31 | LL | fn make_baz(t: &T) -> &dyn Baz { | ^^^^^^^ `Baz` is not dyn compatible @@ -30,40 +30,6 @@ LL | fn baz(&self) -> Self; | ^^^^ ...because method `baz` references the `Self` type in its return type = help: consider moving `baz` to another trait -error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/mentions-Self.rs:20:5 - | -LL | t - | ^ `Bar` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/mentions-Self.rs:7:22 - | -LL | trait Bar { - | --- this trait is not dyn compatible... -LL | fn bar(&self, x: &Self); - | ^^^^^ ...because method `bar` references the `Self` type in this parameter - = help: consider moving `bar` to another trait - = note: required for the cast from `&T` to `&dyn Bar` - -error[E0038]: the trait `Baz` is not dyn compatible - --> $DIR/mentions-Self.rs:26:5 - | -LL | t - | ^ `Baz` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/mentions-Self.rs:11:22 - | -LL | trait Baz { - | --- this trait is not dyn compatible... -LL | fn baz(&self) -> Self; - | ^^^^ ...because method `baz` references the `Self` type in its return type - = help: consider moving `baz` to another trait - = note: required for the cast from `&T` to `&dyn Baz` - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/dyn-compatibility/no-static.rs b/tests/ui/dyn-compatibility/no-static.rs index 9bd8716197285..2d5954afffdaa 100644 --- a/tests/ui/dyn-compatibility/no-static.rs +++ b/tests/ui/dyn-compatibility/no-static.rs @@ -17,5 +17,4 @@ impl Foo for Bar {} fn main() { let b: Box = Box::new(Bar); //~^ ERROR E0038 - //~| ERROR E0038 } diff --git a/tests/ui/dyn-compatibility/no-static.stderr b/tests/ui/dyn-compatibility/no-static.stderr index 814ab0d53c3fc..8e4f109c97db3 100644 --- a/tests/ui/dyn-compatibility/no-static.stderr +++ b/tests/ui/dyn-compatibility/no-static.stderr @@ -46,31 +46,6 @@ help: alternatively, consider constraining `foo` so it does not apply to trait o LL | fn foo() where Self: Sized {} | +++++++++++++++++ -error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/no-static.rs:18:27 - | -LL | let b: Box = Box::new(Bar); - | ^^^^^^^^^^^^^ `Foo` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/no-static.rs:5:8 - | -LL | trait Foo { - | --- this trait is not dyn compatible... -LL | fn foo() {} - | ^^^ ...because associated function `foo` has no `self` parameter - = help: only type `Bar` implements `Foo`; consider using it directly instead. - = note: required for the cast from `Box` to `Box` -help: consider turning `foo` into a method by giving it a `&self` argument - | -LL | fn foo(&self) {} - | +++++ -help: alternatively, consider constraining `foo` so it does not apply to trait objects - | -LL | fn foo() where Self: Sized {} - | +++++++++++++++++ - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/dyn-compatibility/sized-2.rs b/tests/ui/dyn-compatibility/sized-2.rs index f61d49ee8dff3..c99dcce46b2c1 100644 --- a/tests/ui/dyn-compatibility/sized-2.rs +++ b/tests/ui/dyn-compatibility/sized-2.rs @@ -10,7 +10,6 @@ trait Bar fn make_bar(t: &T) -> &dyn Bar { //~^ ERROR E0038 t - //~^ ERROR E0038 } fn main() { diff --git a/tests/ui/dyn-compatibility/sized-2.stderr b/tests/ui/dyn-compatibility/sized-2.stderr index 1834d906bb89d..70bd5f6dd36cf 100644 --- a/tests/ui/dyn-compatibility/sized-2.stderr +++ b/tests/ui/dyn-compatibility/sized-2.stderr @@ -13,22 +13,6 @@ LL | trait Bar LL | where Self : Sized | ^^^^^ ...because it requires `Self: Sized` -error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/sized-2.rs:12:5 - | -LL | t - | ^ `Bar` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/sized-2.rs:5:18 - | -LL | trait Bar - | --- this trait is not dyn compatible... -LL | where Self : Sized - | ^^^^^ ...because it requires `Self: Sized` - = note: required for the cast from `&T` to `&dyn Bar` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/dyn-compatibility/sized.rs b/tests/ui/dyn-compatibility/sized.rs index eb5279c17e62d..b5a8a4be766af 100644 --- a/tests/ui/dyn-compatibility/sized.rs +++ b/tests/ui/dyn-compatibility/sized.rs @@ -8,7 +8,6 @@ trait Bar: Sized { fn make_bar(t: &T) -> &dyn Bar { //~^ ERROR E0038 t - //~^ ERROR E0038 } fn main() {} diff --git a/tests/ui/dyn-compatibility/sized.stderr b/tests/ui/dyn-compatibility/sized.stderr index c66e299cf6f5c..0cc41179d9a84 100644 --- a/tests/ui/dyn-compatibility/sized.stderr +++ b/tests/ui/dyn-compatibility/sized.stderr @@ -13,22 +13,6 @@ LL | trait Bar: Sized { | | | this trait is not dyn compatible... -error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/sized.rs:10:5 - | -LL | t - | ^ `Bar` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/sized.rs:4:12 - | -LL | trait Bar: Sized { - | --- ^^^^^ ...because it requires `Self: Sized` - | | - | this trait is not dyn compatible... - = note: required for the cast from `&T` to `&dyn Bar` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/dyn-compatibility/taint-const-eval.rs b/tests/ui/dyn-compatibility/taint-const-eval.rs index 64c4df611e658..a5c01e1791e74 100644 --- a/tests/ui/dyn-compatibility/taint-const-eval.rs +++ b/tests/ui/dyn-compatibility/taint-const-eval.rs @@ -7,6 +7,5 @@ trait Qux { static FOO: &(dyn Qux + Sync) = "desc"; //~^ ERROR the trait `Qux` is not dyn compatible //~| ERROR the trait `Qux` is not dyn compatible -//~| ERROR the trait `Qux` is not dyn compatible fn main() {} diff --git a/tests/ui/dyn-compatibility/taint-const-eval.stderr b/tests/ui/dyn-compatibility/taint-const-eval.stderr index 942c20db6ce0f..585c1f012c785 100644 --- a/tests/ui/dyn-compatibility/taint-const-eval.stderr +++ b/tests/ui/dyn-compatibility/taint-const-eval.stderr @@ -21,30 +21,6 @@ help: alternatively, consider constraining `bar` so it does not apply to trait o LL | fn bar() where Self: Sized; | +++++++++++++++++ -error[E0038]: the trait `Qux` is not dyn compatible - --> $DIR/taint-const-eval.rs:7:33 - | -LL | static FOO: &(dyn Qux + Sync) = "desc"; - | ^^^^^^ `Qux` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/taint-const-eval.rs:4:8 - | -LL | trait Qux { - | --- this trait is not dyn compatible... -LL | fn bar(); - | ^^^ ...because associated function `bar` has no `self` parameter - = note: required for the cast from `&'static str` to `&'static (dyn Qux + Sync + 'static)` -help: consider turning `bar` into a method by giving it a `&self` argument - | -LL | fn bar(&self); - | +++++ -help: alternatively, consider constraining `bar` so it does not apply to trait objects - | -LL | fn bar() where Self: Sized; - | +++++++++++++++++ - error[E0038]: the trait `Qux` is not dyn compatible --> $DIR/taint-const-eval.rs:7:15 | @@ -69,6 +45,6 @@ help: alternatively, consider constraining `bar` so it does not apply to trait o LL | fn bar() where Self: Sized; | +++++++++++++++++ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs index 37eabbf160220..8d7ccea9e6477 100644 --- a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs +++ b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs @@ -31,5 +31,4 @@ impl Trait for i32 { fn main() { Ptr(Box::new(4)) as Ptr; //~^ ERROR the trait `Trait` is not dyn compatible - //~^^ ERROR the trait `Trait` is not dyn compatible } diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr index 6634ce1211867..18b99d24083b7 100644 --- a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr +++ b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr @@ -17,26 +17,6 @@ LL | fn ptr(self: Ptr); | ^^^^^^^^^ ...because method `ptr`'s `self` parameter cannot be dispatched on = help: only type `i32` implements `Trait`; consider using it directly instead. -error[E0038]: the trait `Trait` is not dyn compatible - --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:32:5 - | -LL | fn ptr(self: Ptr); - | --------- help: consider changing method `ptr`'s `self` parameter to be `&self`: `&Self` -... -LL | Ptr(Box::new(4)) as Ptr; - | ^^^^^^^^^^^^^^^^ `Trait` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:25:18 - | -LL | trait Trait { - | ----- this trait is not dyn compatible... -LL | fn ptr(self: Ptr); - | ^^^^^^^^^ ...because method `ptr`'s `self` parameter cannot be dispatched on - = help: only type `i32` implements `Trait`; consider using it directly instead. - = note: required for the cast from `Ptr<{integer}>` to `Ptr` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/generic-associated-types/gat-in-trait-path.rs b/tests/ui/generic-associated-types/gat-in-trait-path.rs index 7523803eacff8..774e16d84c504 100644 --- a/tests/ui/generic-associated-types/gat-in-trait-path.rs +++ b/tests/ui/generic-associated-types/gat-in-trait-path.rs @@ -26,5 +26,4 @@ fn main() { let foo = Fooer(5); f(Box::new(foo)); //~^ ERROR the trait `Foo` is not dyn compatible - //~| ERROR the trait `Foo` is not dyn compatible } diff --git a/tests/ui/generic-associated-types/gat-in-trait-path.stderr b/tests/ui/generic-associated-types/gat-in-trait-path.stderr index e57f6b48401fc..d4ccd80f14658 100644 --- a/tests/ui/generic-associated-types/gat-in-trait-path.stderr +++ b/tests/ui/generic-associated-types/gat-in-trait-path.stderr @@ -30,23 +30,6 @@ LL | type A<'a> where Self: 'a; | ^ ...because it contains the generic associated type `A` = help: consider moving `A` to another trait -error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/gat-in-trait-path.rs:27:5 - | -LL | f(Box::new(foo)); - | ^^^^^^^^^^^^^ `Foo` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/gat-in-trait-path.rs:6:10 - | -LL | trait Foo { - | --- this trait is not dyn compatible... -LL | type A<'a> where Self: 'a; - | ^ ...because it contains the generic associated type `A` - = help: consider moving `A` to another trait - = note: required for the cast from `Box>` to `Box<(dyn Foo = &'a ()> + 'static)>` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/generic-associated-types/issue-71176.rs b/tests/ui/generic-associated-types/issue-71176.rs index d3a0caffec1e7..8ecfa93750d48 100644 --- a/tests/ui/generic-associated-types/issue-71176.rs +++ b/tests/ui/generic-associated-types/issue-71176.rs @@ -18,6 +18,5 @@ fn main() { Holder { inner: Box::new(()), //~^ ERROR: the trait `Provider` is not dyn compatible - //~| ERROR: the trait `Provider` is not dyn compatible }; } diff --git a/tests/ui/generic-associated-types/issue-71176.stderr b/tests/ui/generic-associated-types/issue-71176.stderr index 56439f6dfea84..f231056a2eed8 100644 --- a/tests/ui/generic-associated-types/issue-71176.stderr +++ b/tests/ui/generic-associated-types/issue-71176.stderr @@ -82,25 +82,7 @@ LL | type A<'a>; = help: consider moving `A` to another trait = help: only type `()` implements `Provider`; consider using it directly instead. -error[E0038]: the trait `Provider` is not dyn compatible - --> $DIR/issue-71176.rs:19:16 - | -LL | inner: Box::new(()), - | ^^^^^^^^^^^^ `Provider` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/issue-71176.rs:2:10 - | -LL | trait Provider { - | -------- this trait is not dyn compatible... -LL | type A<'a>; - | ^ ...because it contains the generic associated type `A` - = help: consider moving `A` to another trait - = help: only type `()` implements `Provider`; consider using it directly instead. - = note: required for the cast from `Box<()>` to `Box<(dyn Provider = _> + 'static), {type error}>` - -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0038, E0107. For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/generic-associated-types/issue-76535.rs b/tests/ui/generic-associated-types/issue-76535.rs index 9e18c82c7f1ce..dc697401a58c9 100644 --- a/tests/ui/generic-associated-types/issue-76535.rs +++ b/tests/ui/generic-associated-types/issue-76535.rs @@ -33,6 +33,5 @@ impl SuperTrait for SuperStruct { fn main() { let sub: Box> = Box::new(SuperStruct::new(0)); //~^ ERROR missing generics for associated type - //~^^ ERROR the trait //~| ERROR the trait } diff --git a/tests/ui/generic-associated-types/issue-76535.stderr b/tests/ui/generic-associated-types/issue-76535.stderr index b828234afa126..9bac3318948c0 100644 --- a/tests/ui/generic-associated-types/issue-76535.stderr +++ b/tests/ui/generic-associated-types/issue-76535.stderr @@ -32,26 +32,7 @@ LL | type SubType<'a>: SubTrait where Self: 'a; = help: only type `SuperStruct` implements `SuperTrait` within this crate; consider using it directly instead. = note: `SuperTrait` may be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type -error[E0038]: the trait `SuperTrait` is not dyn compatible - --> $DIR/issue-76535.rs:34:57 - | -LL | let sub: Box> = Box::new(SuperStruct::new(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/issue-76535.rs:4:10 - | -LL | pub trait SuperTrait { - | ---------- this trait is not dyn compatible... -LL | type SubType<'a>: SubTrait where Self: 'a; - | ^^^^^^^ ...because it contains the generic associated type `SubType` - = help: consider moving `SubType` to another trait - = help: only type `SuperStruct` implements `SuperTrait` within this crate; consider using it directly instead. - = note: `SuperTrait` may be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type - = note: required for the cast from `Box` to `Box = SubStruct<'_>>>` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0038, E0107. For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/generic-associated-types/issue-79422.rs b/tests/ui/generic-associated-types/issue-79422.rs index fba7a86990ece..462614b36127a 100644 --- a/tests/ui/generic-associated-types/issue-79422.rs +++ b/tests/ui/generic-associated-types/issue-79422.rs @@ -15,12 +15,17 @@ impl<'a, T> RefCont<'a, T> for Box { } trait MapLike { - type VRefCont<'a>: RefCont<'a, V> where Self: 'a; + type VRefCont<'a>: RefCont<'a, V> + where + Self: 'a; fn get<'a>(&'a self, key: &K) -> Option>; } impl MapLike for std::collections::BTreeMap { - type VRefCont<'a> = &'a V where Self: 'a; + type VRefCont<'a> + = &'a V + where + Self: 'a; fn get<'a>(&'a self, key: &K) -> Option<&'a V> { std::collections::BTreeMap::get(self, key) } @@ -37,8 +42,7 @@ impl MapLike for Source { fn main() { let m = Box::new(std::collections::BTreeMap::::new()) - //~^ ERROR the trait as Box>>; - //~^ ERROR missing generics for associated type - //~| ERROR the trait + //~^ ERROR the trait + //~| ERROR missing generics for associated type } diff --git a/tests/ui/generic-associated-types/issue-79422.stderr b/tests/ui/generic-associated-types/issue-79422.stderr index 6311e4de272d9..403cb67adb414 100644 --- a/tests/ui/generic-associated-types/issue-79422.stderr +++ b/tests/ui/generic-associated-types/issue-79422.stderr @@ -1,5 +1,5 @@ error[E0107]: missing generics for associated type `MapLike::VRefCont` - --> $DIR/issue-79422.rs:41:36 + --> $DIR/issue-79422.rs:45:36 | LL | as Box>>; | ^^^^^^^^ expected 1 lifetime argument @@ -7,7 +7,7 @@ LL | as Box>>; note: associated type defined here, with 1 lifetime parameter: `'a` --> $DIR/issue-79422.rs:18:10 | -LL | type VRefCont<'a>: RefCont<'a, V> where Self: 'a; +LL | type VRefCont<'a>: RefCont<'a, V> | ^^^^^^^^ -- help: add missing lifetime argument | @@ -15,7 +15,7 @@ LL | as Box = dyn RefCont<'_, u8>>>; | ++++ error[E0038]: the trait `MapLike` is not dyn compatible - --> $DIR/issue-79422.rs:41:12 + --> $DIR/issue-79422.rs:45:12 | LL | as Box>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` is not dyn compatible @@ -26,28 +26,11 @@ note: for a trait to be dyn compatible it needs to allow building a vtable | LL | trait MapLike { | ------- this trait is not dyn compatible... -LL | type VRefCont<'a>: RefCont<'a, V> where Self: 'a; +LL | type VRefCont<'a>: RefCont<'a, V> | ^^^^^^^^ ...because it contains the generic associated type `VRefCont` = help: consider moving `VRefCont` to another trait -error[E0038]: the trait `MapLike` is not dyn compatible - --> $DIR/issue-79422.rs:39:13 - | -LL | let m = Box::new(std::collections::BTreeMap::::new()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/issue-79422.rs:18:10 - | -LL | trait MapLike { - | ------- this trait is not dyn compatible... -LL | type VRefCont<'a>: RefCont<'a, V> where Self: 'a; - | ^^^^^^^^ ...because it contains the generic associated type `VRefCont` - = help: consider moving `VRefCont` to another trait - = note: required for the cast from `Box>` to `Box = (dyn RefCont<'_, u8> + 'static)>>` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0038, E0107. For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.rs b/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.rs index 5d039cd5dc656..949c49a820b79 100644 --- a/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.rs +++ b/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.rs @@ -13,7 +13,6 @@ fn needs_bar(_: *mut Type2) {} fn main() { let x: &dyn Foo = &(); //~^ ERROR the trait `Foo` is not dyn compatible - //~| ERROR the trait `Foo` is not dyn compatible needs_bar(x); //~^ ERROR mismatched types diff --git a/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr b/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr index 183ee678d7a46..10a9e2c8d24b3 100644 --- a/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr +++ b/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr @@ -1,19 +1,3 @@ -error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/span-bug-issue-121597.rs:14:23 - | -LL | let x: &dyn Foo = &(); - | ^^^ `Foo` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/span-bug-issue-121597.rs:4:12 - | -LL | trait Foo: for Bar {} - | --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables - | | - | this trait is not dyn compatible... - = note: required for the cast from `&()` to `&dyn Foo` - error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/span-bug-issue-121597.rs:14:12 | @@ -30,7 +14,7 @@ LL | trait Foo: for Bar {} | this trait is not dyn compatible... error[E0308]: mismatched types - --> $DIR/span-bug-issue-121597.rs:18:15 + --> $DIR/span-bug-issue-121597.rs:17:15 | LL | needs_bar(x); | --------- ^ types differ in mutability @@ -45,7 +29,7 @@ note: function defined here LL | fn needs_bar(_: *mut Type2) {} | ^^^^^^^^^ ------------- -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0038, E0308. For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.rs b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.rs index 901d4b39cf360..c3dc417b18730 100644 --- a/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.rs +++ b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.rs @@ -29,9 +29,9 @@ fn car() -> dyn DynIncompatible { //~ ERROR the trait `DynIncompatible` is not d fn cat() -> Box { //~ ERROR the trait `DynIncompatible` is not dyn compatible if true { - return Box::new(A); //~ ERROR is not dyn compatible + return Box::new(A); } - Box::new(B) //~ ERROR is not dyn compatible + Box::new(B) } fn main() {} diff --git a/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr index 2c314b07bcee9..a230090eb00e2 100644 --- a/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr +++ b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr @@ -75,65 +75,7 @@ help: alternatively, consider constraining `foo` so it does not apply to trait o LL | fn foo() -> Self where Self: Sized; | +++++++++++++++++ -error[E0038]: the trait `DynIncompatible` is not dyn compatible - --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:32:16 - | -LL | return Box::new(A); - | ^^^^^^^^^^^ `DynIncompatible` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:4:8 - | -LL | trait DynIncompatible { - | --------------- this trait is not dyn compatible... -LL | fn foo() -> Self; - | ^^^ ...because associated function `foo` has no `self` parameter - = help: the following types implement `DynIncompatible`: - A - B - consider defining an enum where each variant holds one of these types, - implementing `DynIncompatible` for this new enum and using it instead - = note: required for the cast from `Box` to `Box<(dyn DynIncompatible + 'static)>` -help: consider turning `foo` into a method by giving it a `&self` argument - | -LL | fn foo(&self) -> Self; - | +++++ -help: alternatively, consider constraining `foo` so it does not apply to trait objects - | -LL | fn foo() -> Self where Self: Sized; - | +++++++++++++++++ - -error[E0038]: the trait `DynIncompatible` is not dyn compatible - --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:34:5 - | -LL | Box::new(B) - | ^^^^^^^^^^^ `DynIncompatible` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:4:8 - | -LL | trait DynIncompatible { - | --------------- this trait is not dyn compatible... -LL | fn foo() -> Self; - | ^^^ ...because associated function `foo` has no `self` parameter - = help: the following types implement `DynIncompatible`: - A - B - consider defining an enum where each variant holds one of these types, - implementing `DynIncompatible` for this new enum and using it instead - = note: required for the cast from `Box` to `Box<(dyn DynIncompatible + 'static)>` -help: consider turning `foo` into a method by giving it a `&self` argument - | -LL | fn foo(&self) -> Self; - | +++++ -help: alternatively, consider constraining `foo` so it does not apply to trait objects - | -LL | fn foo() -> Self where Self: Sized; - | +++++++++++++++++ - -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0038, E0746. For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/impl-trait/in-trait/dyn-compatibility.rs b/tests/ui/impl-trait/in-trait/dyn-compatibility.rs index 92203c470bba5..45b431f6d3068 100644 --- a/tests/ui/impl-trait/in-trait/dyn-compatibility.rs +++ b/tests/ui/impl-trait/in-trait/dyn-compatibility.rs @@ -13,6 +13,5 @@ impl Foo for u32 { fn main() { let i = Box::new(42_u32) as Box; //~^ ERROR the trait `Foo` is not dyn compatible - //~| ERROR the trait `Foo` is not dyn compatible let s = i.baz(); } diff --git a/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr b/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr index 5c498548affdf..d65ed6bbcdac5 100644 --- a/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr +++ b/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr @@ -15,24 +15,6 @@ LL | fn baz(&self) -> impl Debug; = help: consider moving `baz` to another trait = help: only type `u32` implements `Foo`; consider using it directly instead. -error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/dyn-compatibility.rs:14:13 - | -LL | let i = Box::new(42_u32) as Box; - | ^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/dyn-compatibility.rs:4:22 - | -LL | trait Foo { - | --- this trait is not dyn compatible... -LL | fn baz(&self) -> impl Debug; - | ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type - = help: consider moving `baz` to another trait - = help: only type `u32` implements `Foo`; consider using it directly instead. - = note: required for the cast from `Box` to `Box` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/issues/issue-18959.rs b/tests/ui/issues/issue-18959.rs index dbc73bafce9e5..4fe669adcdaf8 100644 --- a/tests/ui/issues/issue-18959.rs +++ b/tests/ui/issues/issue-18959.rs @@ -17,6 +17,5 @@ fn main() { let mut thing = Thing; let test: &dyn Bar = &mut thing; //~^ ERROR E0038 - //~| ERROR E0038 foo(test); } diff --git a/tests/ui/issues/issue-18959.stderr b/tests/ui/issues/issue-18959.stderr index 7ddfdb49d9594..5345046ba6d3c 100644 --- a/tests/ui/issues/issue-18959.stderr +++ b/tests/ui/issues/issue-18959.stderr @@ -14,23 +14,6 @@ LL | pub trait Bar: Foo { } | --- this trait is not dyn compatible... = help: consider moving `foo` to another trait -error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/issue-18959.rs:18:26 - | -LL | let test: &dyn Bar = &mut thing; - | ^^^^^^^^^^ `Bar` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/issue-18959.rs:1:20 - | -LL | pub trait Foo { fn foo(&self, ext_thing: &T); } - | ^^^ ...because method `foo` has generic type parameters -LL | pub trait Bar: Foo { } - | --- this trait is not dyn compatible... - = help: consider moving `foo` to another trait - = note: required for the cast from `&mut Thing` to `&dyn Bar` - error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/issue-18959.rs:18:15 | @@ -47,6 +30,6 @@ LL | pub trait Bar: Foo { } | --- this trait is not dyn compatible... = help: consider moving `foo` to another trait -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/issues/issue-19380.rs b/tests/ui/issues/issue-19380.rs index 8b3fe4d2b099b..fce737cba18d2 100644 --- a/tests/ui/issues/issue-19380.rs +++ b/tests/ui/issues/issue-19380.rs @@ -15,6 +15,5 @@ struct Bar { const FOO : Foo = Foo; const BAR : Bar = Bar { foos: &[&FOO]}; //~^ ERROR E0038 -//~| ERROR E0038 fn main() { } diff --git a/tests/ui/issues/issue-19380.stderr b/tests/ui/issues/issue-19380.stderr index f8509891d3abb..4c41d41ae3792 100644 --- a/tests/ui/issues/issue-19380.stderr +++ b/tests/ui/issues/issue-19380.stderr @@ -22,31 +22,6 @@ help: alternatively, consider constraining `qiz` so it does not apply to trait o LL | fn qiz() where Self: Sized; | +++++++++++++++++ -error[E0038]: the trait `Qiz` is not dyn compatible - --> $DIR/issue-19380.rs:16:33 - | -LL | const BAR : Bar = Bar { foos: &[&FOO]}; - | ^^^^ `Qiz` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/issue-19380.rs:2:6 - | -LL | trait Qiz { - | --- this trait is not dyn compatible... -LL | fn qiz(); - | ^^^ ...because associated function `qiz` has no `self` parameter - = help: only type `Foo` implements `Qiz`; consider using it directly instead. - = note: required for the cast from `&Foo` to `&'static (dyn Qiz + 'static)` -help: consider turning `qiz` into a method by giving it a `&self` argument - | -LL | fn qiz(&self); - | +++++ -help: alternatively, consider constraining `qiz` so it does not apply to trait objects - | -LL | fn qiz() where Self: Sized; - | +++++++++++++++++ - error[E0038]: the trait `Qiz` is not dyn compatible --> $DIR/issue-19380.rs:16:31 | @@ -71,6 +46,6 @@ help: alternatively, consider constraining `qiz` so it does not apply to trait o LL | fn qiz() where Self: Sized; | +++++++++++++++++ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/issues/issue-50781.rs b/tests/ui/issues/issue-50781.rs index ab90db1cadcf2..d837b848591f2 100644 --- a/tests/ui/issues/issue-50781.rs +++ b/tests/ui/issues/issue-50781.rs @@ -15,5 +15,4 @@ pub fn main() { // Check that this does not segfault. ::foo(&()); //~^ ERROR the trait `X` is not dyn compatible - //~| ERROR the trait `X` is not dyn compatible } diff --git a/tests/ui/issues/issue-50781.stderr b/tests/ui/issues/issue-50781.stderr index 88b83a83e0cfa..be6519429a515 100644 --- a/tests/ui/issues/issue-50781.stderr +++ b/tests/ui/issues/issue-50781.stderr @@ -15,24 +15,6 @@ LL | fn foo(&self) where Self: Trait; = help: consider moving `foo` to another trait = help: only type `()` implements `X`; consider using it directly instead. -error[E0038]: the trait `X` is not dyn compatible - --> $DIR/issue-50781.rs:16:23 - | -LL | ::foo(&()); - | ^^^ `X` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/issue-50781.rs:4:8 - | -LL | trait X { - | - this trait is not dyn compatible... -LL | fn foo(&self) where Self: Trait; - | ^^^ ...because method `foo` references the `Self` type in its `where` clause - = help: consider moving `foo` to another trait - = help: only type `()` implements `X`; consider using it directly instead. - = note: required for the cast from `&()` to `&dyn X` - error[E0038]: the trait `X` is not dyn compatible --> $DIR/issue-50781.rs:16:6 | @@ -50,6 +32,6 @@ LL | fn foo(&self) where Self: Trait; = help: consider moving `foo` to another trait = help: only type `()` implements `X`; consider using it directly instead. -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.rs b/tests/ui/kindck/kindck-inherited-copy-bound.rs index 20d54a3fb106d..92c2b273c2c15 100644 --- a/tests/ui/kindck/kindck-inherited-copy-bound.rs +++ b/tests/ui/kindck/kindck-inherited-copy-bound.rs @@ -22,7 +22,6 @@ fn b() { let y = &x; let z = &x as &dyn Foo; //~^ ERROR E0038 - //~| ERROR E0038 } fn main() { } diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.stderr index edfa7ae7769db..05d31f48f47a4 100644 --- a/tests/ui/kindck/kindck-inherited-copy-bound.stderr +++ b/tests/ui/kindck/kindck-inherited-copy-bound.stderr @@ -34,23 +34,7 @@ LL | trait Foo : Copy { | | | this trait is not dyn compatible... -error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/kindck-inherited-copy-bound.rs:23:13 - | -LL | let z = &x as &dyn Foo; - | ^^ `Foo` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/kindck-inherited-copy-bound.rs:6:13 - | -LL | trait Foo : Copy { - | --- ^^^^ ...because it requires `Self: Sized` - | | - | this trait is not dyn compatible... - = note: required for the cast from `&Box<{integer}>` to `&dyn Foo` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0038, E0277. For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/self/arbitrary-self-types-dyn-incompatible.rs b/tests/ui/self/arbitrary-self-types-dyn-incompatible.rs index 0477d9d79c779..b223f18327b18 100644 --- a/tests/ui/self/arbitrary-self-types-dyn-incompatible.rs +++ b/tests/ui/self/arbitrary-self-types-dyn-incompatible.rs @@ -28,7 +28,6 @@ impl Bar for usize { fn make_foo() { let x = Rc::new(5usize) as Rc; //~^ ERROR E0038 - //~| ERROR E0038 } fn make_bar() { diff --git a/tests/ui/self/arbitrary-self-types-dyn-incompatible.stderr b/tests/ui/self/arbitrary-self-types-dyn-incompatible.stderr index 9fb4c80329d58..977ccecea0641 100644 --- a/tests/ui/self/arbitrary-self-types-dyn-incompatible.stderr +++ b/tests/ui/self/arbitrary-self-types-dyn-incompatible.stderr @@ -17,26 +17,6 @@ LL | fn foo(self: &Rc) -> usize; | ^^^^^^^^^ ...because method `foo`'s `self` parameter cannot be dispatched on = help: only type `usize` implements `Foo`; consider using it directly instead. -error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/arbitrary-self-types-dyn-incompatible.rs:29:13 - | -LL | fn foo(self: &Rc) -> usize; - | --------- help: consider changing method `foo`'s `self` parameter to be `&self`: `&Self` -... -LL | let x = Rc::new(5usize) as Rc; - | ^^^^^^^^^^^^^^^ `Foo` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/arbitrary-self-types-dyn-incompatible.rs:4:18 - | -LL | trait Foo { - | --- this trait is not dyn compatible... -LL | fn foo(self: &Rc) -> usize; - | ^^^^^^^^^ ...because method `foo`'s `self` parameter cannot be dispatched on - = help: only type `usize` implements `Foo`; consider using it directly instead. - = note: required for the cast from `Rc` to `Rc` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/statics/unsizing-wfcheck-issue-127299.rs b/tests/ui/statics/unsizing-wfcheck-issue-127299.rs index fd07937d90f24..14ba38d75356f 100644 --- a/tests/ui/statics/unsizing-wfcheck-issue-127299.rs +++ b/tests/ui/statics/unsizing-wfcheck-issue-127299.rs @@ -12,6 +12,5 @@ pub struct Lint { static FOO: &Lint = &Lint { desc: "desc" }; //~^ ERROR cannot be shared between threads safely //~| ERROR is not dyn compatible -//~| ERROR is not dyn compatible fn main() {} diff --git a/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr b/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr index 28427161e870c..e401277a0209f 100644 --- a/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr +++ b/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr @@ -51,7 +51,6 @@ LL | trait Qux { | --- this trait is not dyn compatible... LL | fn bar() -> i32; | ^^^ ...because associated function `bar` has no `self` parameter - = note: required for the cast from `&'static str` to `&'static (dyn Qux + 'static)` help: consider turning `bar` into a method by giving it a `&self` argument | LL | fn bar(&self) -> i32; @@ -61,30 +60,7 @@ help: alternatively, consider constraining `bar` so it does not apply to trait o LL | fn bar() -> i32 where Self: Sized; | +++++++++++++++++ -error[E0038]: the trait `Qux` is not dyn compatible - --> $DIR/unsizing-wfcheck-issue-127299.rs:12:35 - | -LL | static FOO: &Lint = &Lint { desc: "desc" }; - | ^^^^^^ `Qux` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/unsizing-wfcheck-issue-127299.rs:4:8 - | -LL | trait Qux { - | --- this trait is not dyn compatible... -LL | fn bar() -> i32; - | ^^^ ...because associated function `bar` has no `self` parameter -help: consider turning `bar` into a method by giving it a `&self` argument - | -LL | fn bar(&self) -> i32; - | +++++ -help: alternatively, consider constraining `bar` so it does not apply to trait objects - | -LL | fn bar() -> i32 where Self: Sized; - | +++++++++++++++++ - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0038, E0277. For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/traits/issue-20692.rs b/tests/ui/traits/issue-20692.rs index 10611a232f71c..79edc389ec4af 100644 --- a/tests/ui/traits/issue-20692.rs +++ b/tests/ui/traits/issue-20692.rs @@ -2,7 +2,6 @@ trait Array: Sized + Copy {} fn f(x: &T) { let _ = x - //~^ ERROR `Array` is not dyn compatible as &dyn Array; //~^ ERROR `Array` is not dyn compatible diff --git a/tests/ui/traits/issue-20692.stderr b/tests/ui/traits/issue-20692.stderr index 32e29de49a113..e902a582cc70f 100644 --- a/tests/ui/traits/issue-20692.stderr +++ b/tests/ui/traits/issue-20692.stderr @@ -1,5 +1,5 @@ error[E0038]: the trait `Array` is not dyn compatible - --> $DIR/issue-20692.rs:7:5 + --> $DIR/issue-20692.rs:6:5 | LL | &dyn Array; | ^^^^^^^^^^ `Array` is not dyn compatible @@ -14,23 +14,6 @@ LL | trait Array: Sized + Copy {} | | ...because it requires `Self: Sized` | this trait is not dyn compatible... -error[E0038]: the trait `Array` is not dyn compatible - --> $DIR/issue-20692.rs:4:13 - | -LL | let _ = x - | ^ `Array` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/issue-20692.rs:1:14 - | -LL | trait Array: Sized + Copy {} - | ----- ^^^^^ ^^^^ ...because it requires `Self: Sized` - | | | - | | ...because it requires `Self: Sized` - | this trait is not dyn compatible... - = note: required for the cast from `&T` to `&dyn Array` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/traits/issue-38604.rs b/tests/ui/traits/issue-38604.rs index d90aa61ef9f33..70f0ef0cb9cbf 100644 --- a/tests/ui/traits/issue-38604.rs +++ b/tests/ui/traits/issue-38604.rs @@ -12,5 +12,5 @@ impl Foo for () { fn main() { let _f: Box = //~ ERROR `Foo` is not dyn compatible - Box::new(()); //~ ERROR `Foo` is not dyn compatible + Box::new(()); } diff --git a/tests/ui/traits/issue-38604.stderr b/tests/ui/traits/issue-38604.stderr index e6a6b44e7304d..0455230b1aa3c 100644 --- a/tests/ui/traits/issue-38604.stderr +++ b/tests/ui/traits/issue-38604.stderr @@ -14,23 +14,6 @@ LL | trait Foo where u32: Q { | this trait is not dyn compatible... = help: only type `()` implements `Foo`; consider using it directly instead. -error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/issue-38604.rs:15:9 - | -LL | Box::new(()); - | ^^^^^^^^^^^^ `Foo` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/issue-38604.rs:2:22 - | -LL | trait Foo where u32: Q { - | --- ^^^^^^^ ...because it uses `Self` as a type parameter - | | - | this trait is not dyn compatible... - = help: only type `()` implements `Foo`; consider using it directly instead. - = note: required for the cast from `Box<()>` to `Box` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.rs b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.rs index 28785ae3dea14..2945b28eec36e 100644 --- a/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.rs +++ b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.rs @@ -18,7 +18,6 @@ impl Bar for () {} fn main() { let x: &dyn Foo = &(); //~^ ERROR the trait `Foo` is not dyn compatible - //~| ERROR the trait `Foo` is not dyn compatible needs_bar(x); //~^ ERROR the trait `Foo` is not dyn compatible } diff --git a/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr index 43b69d0b50e48..2cf6329d0a101 100644 --- a/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr +++ b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr @@ -7,23 +7,6 @@ LL | #![feature(non_lifetime_binders)] = note: see issue #108185 for more information = note: `#[warn(incomplete_features)]` on by default -error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/supertrait-dyn-compatibility.rs:19:23 - | -LL | let x: &dyn Foo = &(); - | ^^^ `Foo` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/supertrait-dyn-compatibility.rs:4:12 - | -LL | trait Foo: for Bar {} - | --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables - | | - | this trait is not dyn compatible... - = help: only type `()` implements `Foo`; consider using it directly instead. - = note: required for the cast from `&()` to `&dyn Foo` - error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/supertrait-dyn-compatibility.rs:19:12 | @@ -41,7 +24,7 @@ LL | trait Foo: for Bar {} = help: only type `()` implements `Foo`; consider using it directly instead. error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/supertrait-dyn-compatibility.rs:22:5 + --> $DIR/supertrait-dyn-compatibility.rs:21:5 | LL | needs_bar(x); | ^^^^^^^^^ `Foo` is not dyn compatible @@ -56,6 +39,6 @@ LL | trait Foo: for Bar {} | this trait is not dyn compatible... = help: only type `()` implements `Foo`; consider using it directly instead. -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs index 6fcd67b4950f7..415b050b9d69d 100644 --- a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs +++ b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs @@ -9,7 +9,6 @@ trait Try { fn w<'a, T: 'a, F: Fn(&'a T)>() { let b: &dyn FromResidual = &(); //~^ ERROR: the trait `FromResidual` is not dyn compatible - //~| ERROR: the trait `FromResidual` is not dyn compatible //~| ERROR the type parameter `R` must be explicitly specified } diff --git a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr index b4bbd65b2f47c..0f872dfba5d55 100644 --- a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr +++ b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr @@ -13,30 +13,6 @@ help: set the type parameter to the desired type LL | let b: &dyn FromResidual = &(); | +++ -error[E0038]: the trait `FromResidual` is not dyn compatible - --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:10:32 - | -LL | let b: &dyn FromResidual = &(); - | ^^^ `FromResidual` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:2:8 - | -LL | trait FromResidual::Residual> { - | ------------ this trait is not dyn compatible... -LL | fn from_residual(residual: R) -> Self; - | ^^^^^^^^^^^^^ ...because associated function `from_residual` has no `self` parameter - = note: required for the cast from `&()` to `&dyn FromResidual<{type error}>` -help: consider turning `from_residual` into a method by giving it a `&self` argument - | -LL | fn from_residual(&self, residual: R) -> Self; - | ++++++ -help: alternatively, consider constraining `from_residual` so it does not apply to trait objects - | -LL | fn from_residual(residual: R) -> Self where Self: Sized; - | +++++++++++++++++ - error[E0038]: the trait `FromResidual` is not dyn compatible --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:10:12 | @@ -60,7 +36,7 @@ help: alternatively, consider constraining `from_residual` so it does not apply LL | fn from_residual(residual: R) -> Self where Self: Sized; | +++++++++++++++++ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0038, E0393. For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/traits/object/safety.rs b/tests/ui/traits/object/safety.rs index f4abcf8542e5f..ec039557b6358 100644 --- a/tests/ui/traits/object/safety.rs +++ b/tests/ui/traits/object/safety.rs @@ -13,5 +13,4 @@ impl Tr for St { fn main() { let _: &dyn Tr = &St; //~ ERROR E0038 - //~^ ERROR E0038 } diff --git a/tests/ui/traits/object/safety.stderr b/tests/ui/traits/object/safety.stderr index 593e42619f412..a3671d90d2837 100644 --- a/tests/ui/traits/object/safety.stderr +++ b/tests/ui/traits/object/safety.stderr @@ -1,28 +1,3 @@ -error[E0038]: the trait `Tr` is not dyn compatible - --> $DIR/safety.rs:15:22 - | -LL | let _: &dyn Tr = &St; - | ^^^ `Tr` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/safety.rs:4:8 - | -LL | trait Tr { - | -- this trait is not dyn compatible... -LL | fn foo(); - | ^^^ ...because associated function `foo` has no `self` parameter - = help: only type `St` implements `Tr`; consider using it directly instead. - = note: required for the cast from `&St` to `&dyn Tr` -help: consider turning `foo` into a method by giving it a `&self` argument - | -LL | fn foo(&self); - | +++++ -help: alternatively, consider constraining `foo` so it does not apply to trait objects - | -LL | fn foo() where Self: Sized; - | +++++++++++++++++ - error[E0038]: the trait `Tr` is not dyn compatible --> $DIR/safety.rs:15:12 | @@ -47,6 +22,6 @@ help: alternatively, consider constraining `foo` so it does not apply to trait o LL | fn foo() where Self: Sized; | +++++++++++++++++ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/traits/test-2.rs b/tests/ui/traits/test-2.rs index 4ee880da87ad6..1b7fc55b99a8d 100644 --- a/tests/ui/traits/test-2.rs +++ b/tests/ui/traits/test-2.rs @@ -12,5 +12,4 @@ fn main() { //~^ ERROR method takes 1 generic argument but 2 (Box::new(10) as Box).dup(); //~^ ERROR E0038 - //~| ERROR E0038 } diff --git a/tests/ui/traits/test-2.stderr b/tests/ui/traits/test-2.stderr index b52839c300ef7..e4e39e9194ca2 100644 --- a/tests/ui/traits/test-2.stderr +++ b/tests/ui/traits/test-2.stderr @@ -49,31 +49,7 @@ LL | trait bar { fn dup(&self) -> Self; fn blah(&self); } consider defining an enum where each variant holds one of these types, implementing `bar` for this new enum and using it instead -error[E0038]: the trait `bar` is not dyn compatible - --> $DIR/test-2.rs:13:6 - | -LL | (Box::new(10) as Box).dup(); - | ^^^^^^^^^^^^ `bar` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/test-2.rs:4:30 - | -LL | trait bar { fn dup(&self) -> Self; fn blah(&self); } - | --- ^^^^ ^^^^ ...because method `blah` has generic type parameters - | | | - | | ...because method `dup` references the `Self` type in its return type - | this trait is not dyn compatible... - = help: consider moving `dup` to another trait - = help: consider moving `blah` to another trait - = help: the following types implement `bar`: - i32 - u32 - consider defining an enum where each variant holds one of these types, - implementing `bar` for this new enum and using it instead - = note: required for the cast from `Box<{integer}>` to `Box` - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0038, E0107. For more information about an error, try `rustc --explain E0038`. From 8d1337bf6ad1cd34118d70c1952f30b763f291d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Mon, 26 May 2025 13:47:28 +0200 Subject: [PATCH 2801/4206] Flesh out sections about crashes tests and update mentions of glacier --- src/doc/rustc-dev-guide/src/fuzzing.md | 22 ++++++++++++++----- .../rustc-dev-guide/src/getting-started.md | 2 +- .../rustc-dev-guide/src/tests/compiletest.md | 13 +++++++---- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/fuzzing.md b/src/doc/rustc-dev-guide/src/fuzzing.md index b588ca104cb8c..66c50ce252754 100644 --- a/src/doc/rustc-dev-guide/src/fuzzing.md +++ b/src/doc/rustc-dev-guide/src/fuzzing.md @@ -74,20 +74,31 @@ To build a corpus, you may want to use: - The rustc/rust-analyzer/clippy test suites (or even source code) --- though avoid tests that are already known to cause failures, which often begin with comments like `// failure-status: 101` or `// known-bug: #NNN`. -- The already-fixed ICEs in [Glacier][glacier] --- though avoid the unfixed - ones in `ices/`! +- The already-fixed ICEs in the archived [Glacier][glacier] repository --- though + avoid the unfixed ones in `ices/`! + +[glacier]: https://github.com/rust-lang/glacier ## Extra credit Here are a few things you can do to help the Rust project after filing an ICE. -- [Bisect][bisect] the bug to figure out when it was introduced +- [Bisect][bisect] the bug to figure out when it was introduced. + If you find the regressing PR / commit, you can mark the issue with the label + `S-has-bisection`. If not, consider applying `E-needs-bisection` instead. - Fix "distractions": problems with the test case that don't contribute to triggering the ICE, such as syntax errors or borrow-checking errors -- Minimize the test case (see below) -- Add the minimal test case to [Glacier][glacier] +- Minimize the test case (see below). If successful, you can label the + issue with `S-has-mcve`. Otherwise, you can apply `E-needs-mcve`. +- Add the minimal test case to the rust-lang/rust repo as a [crashes test]. + While you're at it, consider including other "untracked" crashes in your PR. + Please don't forget to mark your issue with `S-bug-has-test` afterwards. + +See also [applying and removing labels][labeling]. [bisect]: https://rust-lang.github.io/cargo-bisect-rustc/ +[crashes test]: tests/compiletest.html#crashes-tests +[labeling]: https://forge.rust-lang.org/release/issue-triaging.html#applying-and-removing-labels ## Minimization @@ -143,7 +154,6 @@ ICEs that require debug assertions to reproduce should be tagged - [tree-splicer][tree-splicer] generates new source files by combining existing ones while maintaining correct syntax -[glacier]: https://github.com/rust-lang/glacier [fuzz-rustc]: https://github.com/dwrensha/fuzz-rustc [icemaker]: https://github.com/matthiaskrgr/icemaker/ [tree-splicer]: https://github.com/langston-barrett/tree-splicer/ diff --git a/src/doc/rustc-dev-guide/src/getting-started.md b/src/doc/rustc-dev-guide/src/getting-started.md index 0e5b32a06f898..4ee2692638c19 100644 --- a/src/doc/rustc-dev-guide/src/getting-started.md +++ b/src/doc/rustc-dev-guide/src/getting-started.md @@ -89,7 +89,7 @@ filtering the search to areas you're interested in. For example: Not all important or beginner work has issue labels. See below for how to find work that isn't labelled. -[help-wanted-search]: https://github.com/issues?q=is%3Aopen+is%3Aissue+org%3Arust-lang+no%3Aassignee+label%3AE-easy%2C%22good+first+issue%22%2Cgood-first-issue%2CE-medium%2CEasy%2CE-help-wanted%2CE-mentor+-label%3AS-blocked+-linked:pr+ +[help-wanted-search]: https://github.com/issues?q=is%3Aopen+is%3Aissue+org%3Arust-lang+no%3Aassignee+label%3AE-easy%2C%22good+first+issue%22%2Cgood-first-issue%2CE-medium%2CEasy%2CE-help-wanted%2CE-mentor+-label%3AS-blocked+-linked%3Apr+ [Triage]: ./contributing.md#issue-triage ### Recurring work diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index 50982f3bbdfb7..b68ec036dcee7 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md @@ -546,7 +546,7 @@ only running the main `coverage` suite. [`tests/crashes`] serve as a collection of tests that are expected to cause the compiler to ICE, panic or crash in some other way, so that accidental fixes are -tracked. This was formally done at but +tracked. Formerly, this was done at but doing it inside the rust-lang/rust testsuite is more convenient. It is imperative that a test in the suite causes rustc to ICE, panic, or @@ -560,9 +560,12 @@ If you want to see verbose stdout/stderr, you need to set $ COMPILETEST_VERBOSE_CRASHES=1 ./x test tests/crashes/999999.rs --stage 1 ``` -When adding crashes from , the issue -number should be noted in the file name (`12345.rs` should suffice) and also -inside the file include a `//@ known-bug: #4321` directive. +Anyone can add ["untracked" crashes] from the issue tracker. It's strongly +recommended to include test cases from several issues in a single PR. +When you do so, each issue number should be noted in the file name (`12345.rs` +should suffice) and also inside the file by means of a `//@ known-bug: #12345` +directive. Please [label][labeling] the relevant issues with `S-bug-has-test` +afterwards. If you happen to fix one of the crashes, please move it to a fitting subdirectory in `tests/ui` and give it a meaningful name. Please add a doc @@ -585,6 +588,8 @@ a subset first. The issue numbers can be found in the file name or the `//@ known-bug` directive inside the test file. [`tests/crashes`]: https://github.com/rust-lang/rust/tree/master/tests/crashes +["untracked" crashes]: https://github.com/rust-lang/rust/issues?q=is%3Aissue+state%3Aopen+label%3AI-ICE%2CI-crash+label%3AT-compiler+label%3AS-has-mcve+-label%3AS-bug-has-test +[labeling]: https://forge.rust-lang.org/release/issue-triaging.html#applying-and-removing-labels ## Building auxiliary crates From 0ea12c3c5fd218671ae42a99757a332fba8597cc Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Mon, 26 May 2025 00:04:20 +0800 Subject: [PATCH 2802/4206] cfg_version: pull out dedicated syntax test from feature gate test The feature gate test was dual-purposing causing feature gate errors to distract from syntax exercises. --- tests/ui/cfg/cfg-version/syntax.rs | 152 +++++++++++++ tests/ui/cfg/cfg-version/syntax.stderr | 188 ++++++++++++++++ .../feature-gates/feature-gate-cfg-version.rs | 49 +---- .../feature-gate-cfg-version.stderr | 204 +----------------- 4 files changed, 350 insertions(+), 243 deletions(-) create mode 100644 tests/ui/cfg/cfg-version/syntax.rs create mode 100644 tests/ui/cfg/cfg-version/syntax.stderr diff --git a/tests/ui/cfg/cfg-version/syntax.rs b/tests/ui/cfg/cfg-version/syntax.rs new file mode 100644 index 0000000000000..22aab47e1ecdf --- /dev/null +++ b/tests/ui/cfg/cfg-version/syntax.rs @@ -0,0 +1,152 @@ +//! Check `#[cfg(version(..))]` parsing. + +#![feature(cfg_version)] + +// Overall grammar +// =============== +// +// `#[cfg(version(..))]` accepts only the `version(VERSION_STRING_LITERAL)` predicate form, where +// only a single string literal is permitted. + +#[cfg(version(42))] +//~^ ERROR expected a version literal +fn not_a_string_literal_simple() {} + +#[cfg(version(1.20))] +//~^ ERROR expected a version literal +fn not_a_string_literal_semver_like() {} + +#[cfg(version(false))] +//~^ ERROR expected a version literal +fn not_a_string_literal_other() {} + +#[cfg(version("1.43", "1.44", "1.45"))] +//~^ ERROR expected single version literal +fn multiple_version_literals() {} + +// The key-value form `cfg(version = "..")` is not considered a valid `cfg(version(..))` usage, but +// it will only trigger the `unexpected_cfgs` lint and not a hard error. + +#[cfg(version = "1.43")] +//~^ WARN unexpected `cfg` condition name: `version` +fn key_value_form() {} + +// Additional version string literal constraints +// ============================================= +// +// The `VERSION_STRING_LITERAL` ("version literal") has additional constraints on its syntactical +// well-formedness. + +// 1. A valid version literal can only constitute of numbers and periods (a "simple" semver version +// string). Non-semver strings or "complex" semver strings (such as build metadata) are not +// considered valid version literals, and will emit a non-lint warning "unknown version literal +// format". + +#[cfg(version("1.43.0"))] +fn valid_major_minor_patch() {} + +#[cfg(version("0.0.0"))] +fn valid_zero_zero_zero_major_minor_patch() {} + +#[cfg(version("foo"))] +//~^ WARN unknown version literal format, assuming it refers to a future version +fn not_numbers_or_periods() {} + +#[cfg(version("1.20.0-stable"))] +//~^ WARN unknown version literal format, assuming it refers to a future version +fn complex_semver_with_metadata() {} + +// 2. "Shortened" version strings are permitted but *only* for the omission of the patch number. + +#[cfg(version("1.0"))] +fn valid_major_minor_1() {} + +#[cfg(version("1.43"))] +fn valid_major_minor_2() {} + +#[cfg(not(version("1.44")))] +fn valid_major_minor_negated_smoke_test() {} + +#[cfg(version("0.0"))] +fn valid_zero_zero_major_minor() {} + +#[cfg(version("0.7"))] +fn valid_zero_major_minor() {} + +// 3. Major-only, or other non-Semver-like strings are not permitted. + +#[cfg(version("1"))] +//~^ WARN unknown version literal format, assuming it refers to a future version +fn invalid_major_only() {} + +#[cfg(version("0"))] +//~^ WARN unknown version literal format, assuming it refers to a future version +fn invalid_major_only_zero() {} + +#[cfg(version(".7"))] +//~^ WARN unknown version literal format, assuming it refers to a future version +fn invalid_decimal_like() {} + +// Misc parsing overflow/underflow edge cases +// ========================================== +// +// Check that we report "unknown version literal format" user-facing warnings and not ICEs. + +#[cfg(version("-1"))] +//~^ WARN unknown version literal format, assuming it refers to a future version +fn invalid_major_only_negative() {} + +// Implementation detail: we store rustc version as `{ major: u16, minor: u16, patch: u16 }`. + +#[cfg(version("65536"))] +//~^ WARN unknown version literal format, assuming it refers to a future version +fn exceed_u16_major() {} + +#[cfg(version("1.65536.0"))] +//~^ WARN unknown version literal format, assuming it refers to a future version +fn exceed_u16_minor() {} + +#[cfg(version("1.0.65536"))] +//~^ WARN unknown version literal format, assuming it refers to a future version +fn exceed_u16_patch() {} + +#[cfg(version("65536.0.65536"))] +//~^ WARN unknown version literal format, assuming it refers to a future version +fn exceed_u16_mixed() {} + +// Usage as `cfg!()` +// ================= + +fn cfg_usage() { + assert!(cfg!(version("1.0"))); + assert!(cfg!(version("1.43"))); + assert!(cfg!(version("1.43.0"))); + + assert!(cfg!(version("foo"))); + //~^ WARN unknown version literal format, assuming it refers to a future version + assert!(cfg!(version("1.20.0-stable"))); + //~^ WARN unknown version literal format, assuming it refers to a future version + + assert!(cfg!(version = "1.43")); + //~^ WARN unexpected `cfg` condition name: `version` +} + +fn main() { + cfg_usage(); + + // `cfg(version = "..")` is not a valid `cfg_version` form, but it only triggers + // `unexpected_cfgs` lint, and `cfg(version = "..")` eval to `false`. + key_value_form(); //~ ERROR cannot find function + + // Invalid version literal formats within valid `cfg(version(..))` form should also cause + // `cfg(version(..))` eval to `false`. + not_numbers_or_periods(); //~ ERROR cannot find function + complex_semver_with_metadata(); //~ ERROR cannot find function + invalid_major_only(); //~ ERROR cannot find function + invalid_major_only_zero(); //~ ERROR cannot find function + invalid_major_only_negative(); //~ ERROR cannot find function + exceed_u16_major(); //~ ERROR cannot find function + exceed_u16_minor(); //~ ERROR cannot find function + exceed_u16_patch(); //~ ERROR cannot find function + exceed_u16_mixed(); //~ ERROR cannot find function +} diff --git a/tests/ui/cfg/cfg-version/syntax.stderr b/tests/ui/cfg/cfg-version/syntax.stderr new file mode 100644 index 0000000000000..2facd96076317 --- /dev/null +++ b/tests/ui/cfg/cfg-version/syntax.stderr @@ -0,0 +1,188 @@ +error: expected a version literal + --> $DIR/syntax.rs:11:15 + | +LL | #[cfg(version(42))] + | ^^ + +error: expected a version literal + --> $DIR/syntax.rs:15:15 + | +LL | #[cfg(version(1.20))] + | ^^^^ + +error: expected a version literal + --> $DIR/syntax.rs:19:15 + | +LL | #[cfg(version(false))] + | ^^^^^ + +error: expected single version literal + --> $DIR/syntax.rs:23:7 + | +LL | #[cfg(version("1.43", "1.44", "1.45"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: unknown version literal format, assuming it refers to a future version + --> $DIR/syntax.rs:51:15 + | +LL | #[cfg(version("foo"))] + | ^^^^^ + +warning: unknown version literal format, assuming it refers to a future version + --> $DIR/syntax.rs:55:15 + | +LL | #[cfg(version("1.20.0-stable"))] + | ^^^^^^^^^^^^^^^ + +warning: unknown version literal format, assuming it refers to a future version + --> $DIR/syntax.rs:78:15 + | +LL | #[cfg(version("1"))] + | ^^^ + +warning: unknown version literal format, assuming it refers to a future version + --> $DIR/syntax.rs:82:15 + | +LL | #[cfg(version("0"))] + | ^^^ + +warning: unknown version literal format, assuming it refers to a future version + --> $DIR/syntax.rs:86:15 + | +LL | #[cfg(version(".7"))] + | ^^^^ + +warning: unknown version literal format, assuming it refers to a future version + --> $DIR/syntax.rs:95:15 + | +LL | #[cfg(version("-1"))] + | ^^^^ + +warning: unknown version literal format, assuming it refers to a future version + --> $DIR/syntax.rs:101:15 + | +LL | #[cfg(version("65536"))] + | ^^^^^^^ + +warning: unknown version literal format, assuming it refers to a future version + --> $DIR/syntax.rs:105:15 + | +LL | #[cfg(version("1.65536.0"))] + | ^^^^^^^^^^^ + +warning: unknown version literal format, assuming it refers to a future version + --> $DIR/syntax.rs:109:15 + | +LL | #[cfg(version("1.0.65536"))] + | ^^^^^^^^^^^ + +warning: unknown version literal format, assuming it refers to a future version + --> $DIR/syntax.rs:113:15 + | +LL | #[cfg(version("65536.0.65536"))] + | ^^^^^^^^^^^^^^^ + +warning: unknown version literal format, assuming it refers to a future version + --> $DIR/syntax.rs:125:26 + | +LL | assert!(cfg!(version("foo"))); + | ^^^^^ + +warning: unknown version literal format, assuming it refers to a future version + --> $DIR/syntax.rs:127:26 + | +LL | assert!(cfg!(version("1.20.0-stable"))); + | ^^^^^^^^^^^^^^^ + +warning: unexpected `cfg` condition name: `version` + --> $DIR/syntax.rs:30:7 + | +LL | #[cfg(version = "1.43")] + | ^^^^^^^^^^^^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(version, values("1.43"))` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default +help: there is a similar config predicate: `version("..")` + | +LL - #[cfg(version = "1.43")] +LL + #[cfg(version("1.43"))] + | + +warning: unexpected `cfg` condition name: `version` + --> $DIR/syntax.rs:130:18 + | +LL | assert!(cfg!(version = "1.43")); + | ^^^^^^^^^^^^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(version, values("1.43"))` + = note: see for more information about checking conditional configuration +help: there is a similar config predicate: `version("..")` + | +LL - assert!(cfg!(version = "1.43")); +LL + assert!(cfg!(version("1.43"))); + | + +error[E0425]: cannot find function `key_value_form` in this scope + --> $DIR/syntax.rs:139:5 + | +LL | key_value_form(); + | ^^^^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find function `not_numbers_or_periods` in this scope + --> $DIR/syntax.rs:143:5 + | +LL | not_numbers_or_periods(); + | ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find function `complex_semver_with_metadata` in this scope + --> $DIR/syntax.rs:144:5 + | +LL | complex_semver_with_metadata(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find function `invalid_major_only` in this scope + --> $DIR/syntax.rs:145:5 + | +LL | invalid_major_only(); + | ^^^^^^^^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find function `invalid_major_only_zero` in this scope + --> $DIR/syntax.rs:146:5 + | +LL | invalid_major_only_zero(); + | ^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find function `invalid_major_only_negative` in this scope + --> $DIR/syntax.rs:147:5 + | +LL | invalid_major_only_negative(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find function `exceed_u16_major` in this scope + --> $DIR/syntax.rs:148:5 + | +LL | exceed_u16_major(); + | ^^^^^^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find function `exceed_u16_minor` in this scope + --> $DIR/syntax.rs:149:5 + | +LL | exceed_u16_minor(); + | ^^^^^^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find function `exceed_u16_patch` in this scope + --> $DIR/syntax.rs:150:5 + | +LL | exceed_u16_patch(); + | ^^^^^^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find function `exceed_u16_mixed` in this scope + --> $DIR/syntax.rs:151:5 + | +LL | exceed_u16_mixed(); + | ^^^^^^^^^^^^^^^^ not found in this scope + +error: aborting due to 14 previous errors; 14 warnings emitted + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/feature-gates/feature-gate-cfg-version.rs b/tests/ui/feature-gates/feature-gate-cfg-version.rs index e35784a68d101..ec2446cc14648 100644 --- a/tests/ui/feature-gates/feature-gate-cfg-version.rs +++ b/tests/ui/feature-gates/feature-gate-cfg-version.rs @@ -1,49 +1,12 @@ -#[cfg(version(42))] //~ ERROR: expected a version literal -//~^ ERROR `cfg(version)` is experimental and subject to change -fn foo() {} -#[cfg(version(1.20))] //~ ERROR: expected a version literal -//~^ ERROR `cfg(version)` is experimental and subject to change -fn foo() -> bool { true } -#[cfg(version("1.44"))] -//~^ ERROR `cfg(version)` is experimental and subject to change -fn foo() -> bool { true } -#[cfg(not(version("1.44")))] -//~^ ERROR `cfg(version)` is experimental and subject to change -fn foo() -> bool { false } +//! Feature gate test for `cfg_version`. +//! +//! Tracking issue: #64796. -#[cfg(version("1.43", "1.44", "1.45"))] //~ ERROR: expected single version literal -//~^ ERROR `cfg(version)` is experimental and subject to change -fn bar() -> bool { false } -#[cfg(version(false))] //~ ERROR: expected a version literal -//~^ ERROR `cfg(version)` is experimental and subject to change -fn bar() -> bool { false } -#[cfg(version("foo"))] //~ WARNING: unknown version literal format -//~^ ERROR `cfg(version)` is experimental and subject to change -fn bar() -> bool { false } -#[cfg(version("999"))] //~ WARNING: unknown version literal format -//~^ ERROR `cfg(version)` is experimental and subject to change -fn bar() -> bool { false } -#[cfg(version("-1"))] //~ WARNING: unknown version literal format -//~^ ERROR `cfg(version)` is experimental and subject to change -fn bar() -> bool { false } -#[cfg(version("65536"))] //~ WARNING: unknown version literal format -//~^ ERROR `cfg(version)` is experimental and subject to change -fn bar() -> bool { false } -#[cfg(version("0"))] //~ WARNING: unknown version literal format -//~^ ERROR `cfg(version)` is experimental and subject to change -fn bar() -> bool { true } -#[cfg(version("1.0"))] -//~^ ERROR `cfg(version)` is experimental and subject to change -fn bar() -> bool { true } -#[cfg(version("1.65536.2"))] //~ WARNING: unknown version literal format -//~^ ERROR `cfg(version)` is experimental and subject to change -fn bar() -> bool { false } -#[cfg(version("1.20.0-stable"))] //~ WARNING: unknown version literal format +#[cfg(version("1.42"))] //~^ ERROR `cfg(version)` is experimental and subject to change fn bar() {} fn main() { - assert!(foo()); - assert!(bar()); - assert!(cfg!(version("1.42"))); //~ ERROR `cfg(version)` is experimental and subject to change + assert!(cfg!(version("1.42"))); + //~^ ERROR `cfg(version)` is experimental and subject to change } diff --git a/tests/ui/feature-gates/feature-gate-cfg-version.stderr b/tests/ui/feature-gates/feature-gate-cfg-version.stderr index c1c3e8e5897a6..7cb2f1e07afe6 100644 --- a/tests/ui/feature-gates/feature-gate-cfg-version.stderr +++ b/tests/ui/feature-gates/feature-gate-cfg-version.stderr @@ -1,39 +1,7 @@ error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:1:7 + --> $DIR/feature-gate-cfg-version.rs:5:7 | -LL | #[cfg(version(42))] - | ^^^^^^^^^^^ - | - = note: see issue #64796 for more information - = help: add `#![feature(cfg_version)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: expected a version literal - --> $DIR/feature-gate-cfg-version.rs:1:15 - | -LL | #[cfg(version(42))] - | ^^ - -error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:4:7 - | -LL | #[cfg(version(1.20))] - | ^^^^^^^^^^^^^ - | - = note: see issue #64796 for more information - = help: add `#![feature(cfg_version)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: expected a version literal - --> $DIR/feature-gate-cfg-version.rs:4:15 - | -LL | #[cfg(version(1.20))] - | ^^^^ - -error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:7:7 - | -LL | #[cfg(version("1.44"))] +LL | #[cfg(version("1.42"))] | ^^^^^^^^^^^^^^^ | = note: see issue #64796 for more information @@ -41,171 +9,7 @@ LL | #[cfg(version("1.44"))] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:10:11 - | -LL | #[cfg(not(version("1.44")))] - | ^^^^^^^^^^^^^^^ - | - = note: see issue #64796 for more information - = help: add `#![feature(cfg_version)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:14:7 - | -LL | #[cfg(version("1.43", "1.44", "1.45"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #64796 for more information - = help: add `#![feature(cfg_version)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: expected single version literal - --> $DIR/feature-gate-cfg-version.rs:14:7 - | -LL | #[cfg(version("1.43", "1.44", "1.45"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:17:7 - | -LL | #[cfg(version(false))] - | ^^^^^^^^^^^^^^ - | - = note: see issue #64796 for more information - = help: add `#![feature(cfg_version)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: expected a version literal - --> $DIR/feature-gate-cfg-version.rs:17:15 - | -LL | #[cfg(version(false))] - | ^^^^^ - -error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:20:7 - | -LL | #[cfg(version("foo"))] - | ^^^^^^^^^^^^^^ - | - = note: see issue #64796 for more information - = help: add `#![feature(cfg_version)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -warning: unknown version literal format, assuming it refers to a future version - --> $DIR/feature-gate-cfg-version.rs:20:15 - | -LL | #[cfg(version("foo"))] - | ^^^^^ - -error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:23:7 - | -LL | #[cfg(version("999"))] - | ^^^^^^^^^^^^^^ - | - = note: see issue #64796 for more information - = help: add `#![feature(cfg_version)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -warning: unknown version literal format, assuming it refers to a future version - --> $DIR/feature-gate-cfg-version.rs:23:15 - | -LL | #[cfg(version("999"))] - | ^^^^^ - -error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:26:7 - | -LL | #[cfg(version("-1"))] - | ^^^^^^^^^^^^^ - | - = note: see issue #64796 for more information - = help: add `#![feature(cfg_version)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -warning: unknown version literal format, assuming it refers to a future version - --> $DIR/feature-gate-cfg-version.rs:26:15 - | -LL | #[cfg(version("-1"))] - | ^^^^ - -error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:29:7 - | -LL | #[cfg(version("65536"))] - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #64796 for more information - = help: add `#![feature(cfg_version)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -warning: unknown version literal format, assuming it refers to a future version - --> $DIR/feature-gate-cfg-version.rs:29:15 - | -LL | #[cfg(version("65536"))] - | ^^^^^^^ - -error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:32:7 - | -LL | #[cfg(version("0"))] - | ^^^^^^^^^^^^ - | - = note: see issue #64796 for more information - = help: add `#![feature(cfg_version)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -warning: unknown version literal format, assuming it refers to a future version - --> $DIR/feature-gate-cfg-version.rs:32:15 - | -LL | #[cfg(version("0"))] - | ^^^ - -error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:35:7 - | -LL | #[cfg(version("1.0"))] - | ^^^^^^^^^^^^^^ - | - = note: see issue #64796 for more information - = help: add `#![feature(cfg_version)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:38:7 - | -LL | #[cfg(version("1.65536.2"))] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #64796 for more information - = help: add `#![feature(cfg_version)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -warning: unknown version literal format, assuming it refers to a future version - --> $DIR/feature-gate-cfg-version.rs:38:15 - | -LL | #[cfg(version("1.65536.2"))] - | ^^^^^^^^^^^ - -error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:41:7 - | -LL | #[cfg(version("1.20.0-stable"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #64796 for more information - = help: add `#![feature(cfg_version)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -warning: unknown version literal format, assuming it refers to a future version - --> $DIR/feature-gate-cfg-version.rs:41:15 - | -LL | #[cfg(version("1.20.0-stable"))] - | ^^^^^^^^^^^^^^^ - -error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:48:18 + --> $DIR/feature-gate-cfg-version.rs:10:18 | LL | assert!(cfg!(version("1.42"))); | ^^^^^^^^^^^^^^^ @@ -214,6 +18,6 @@ LL | assert!(cfg!(version("1.42"))); = help: add `#![feature(cfg_version)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 19 previous errors; 7 warnings emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. From 5e31cd30aae245aaa1374e12521667b8c728402d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 26 May 2025 12:19:34 +0000 Subject: [PATCH 2803/4206] Support opaque_types_defined_by for SyntheticCoroutineBody --- compiler/rustc_ty_utils/src/opaque_types.rs | 8 +++++--- .../async-await/async-closures/promote-in-body.rs | 13 +++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 tests/ui/async-await/async-closures/promote-in-body.rs diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 841f602d985cd..3b4482146d4f1 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -321,7 +321,10 @@ fn opaque_types_defined_by<'tcx>( collector.collect_taits_declared_in_body(); } // Closures and coroutines are type checked with their parent - DefKind::Closure | DefKind::InlineConst => { + // Note that we also support `SyntheticCoroutineBody` since we create + // a MIR body for the def kind, and some MIR passes (like promotion) + // may require doing analysis using its typing env. + DefKind::Closure | DefKind::InlineConst | DefKind::SyntheticCoroutineBody => { collector.opaques.extend(tcx.opaque_types_defined_by(tcx.local_parent(item))); } DefKind::AssocTy | DefKind::TyAlias | DefKind::GlobalAsm => {} @@ -343,8 +346,7 @@ fn opaque_types_defined_by<'tcx>( | DefKind::ForeignMod | DefKind::Field | DefKind::LifetimeParam - | DefKind::Impl { .. } - | DefKind::SyntheticCoroutineBody => { + | DefKind::Impl { .. } => { span_bug!( tcx.def_span(item), "`opaque_types_defined_by` not defined for {} `{item:?}`", diff --git a/tests/ui/async-await/async-closures/promote-in-body.rs b/tests/ui/async-await/async-closures/promote-in-body.rs new file mode 100644 index 0000000000000..ea95d680987e0 --- /dev/null +++ b/tests/ui/async-await/async-closures/promote-in-body.rs @@ -0,0 +1,13 @@ +//@ build-pass +//@ compile-flags: --crate-type=lib +//@ edition: 2024 + +union U { + f: i32, +} + +fn foo() { + async || { + &U { f: 1 } + }; +} From b73dfdfbd350052e8a45046ad25b1c97a1825146 Mon Sep 17 00:00:00 2001 From: Stan Manilov Date: Mon, 26 May 2025 15:39:25 +0300 Subject: [PATCH 2804/4206] Link normalization chapter --- src/doc/rustc-dev-guide/src/typing_parameter_envs.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/typing_parameter_envs.md b/src/doc/rustc-dev-guide/src/typing_parameter_envs.md index a8f4059827f95..e21bc5155da15 100644 --- a/src/doc/rustc-dev-guide/src/typing_parameter_envs.md +++ b/src/doc/rustc-dev-guide/src/typing_parameter_envs.md @@ -32,7 +32,7 @@ where ::Assoc: Clone, {} ``` -If we were conceptually inside of `foo` (for example, type-checking or linting it) we would use this `ParamEnv` everywhere that we interact with the type system. This would allow things such as normalization (TODO: write a chapter about normalization and link it), evaluating generic constants, and proving where clauses/goals, to rely on `T` being sized, implementing `Trait`, etc. +If we were conceptually inside of `foo` (for example, type-checking or linting it) we would use this `ParamEnv` everywhere that we interact with the type system. This would allow things such as [normalization], evaluating generic constants, and proving where clauses/goals, to rely on `T` being sized, implementing `Trait`, etc. A more concrete example: ```rust @@ -70,6 +70,7 @@ fn foo2(a: T) { [predicates_of]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/collect/predicates_of/fn.predicates_of.html [method_pred_entailment]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/check/compare_impl_item/fn.compare_method_predicate_entailment.html [query]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.param_env +[normalization]: normalization.md ### Acquiring a `ParamEnv` From 740aaf7ed9501743781b238a28daa177d05b21b6 Mon Sep 17 00:00:00 2001 From: Stan Manilov Date: Fri, 23 May 2025 18:28:40 +0300 Subject: [PATCH 2805/4206] Add time reference and tracking info for trait system refactor --- src/doc/rustc-dev-guide/src/normalization.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/normalization.md b/src/doc/rustc-dev-guide/src/normalization.md index ef530ccc5ed95..9705b1a244a3d 100644 --- a/src/doc/rustc-dev-guide/src/normalization.md +++ b/src/doc/rustc-dev-guide/src/normalization.md @@ -166,7 +166,10 @@ In this example: When interfacing with the type system it will often be the case that it's necessary to request a type be normalized. There are a number of different entry points to the underlying normalization logic and each entry point should only be used in specific parts of the compiler. -An additional complication is that the compiler is currently undergoing a transition from the old trait solver to the new trait solver. As part of this transition our approach to normalization in the compiler has changed somewhat significantly, resulting in some normalization entry points being "old solver only" slated for removal in the long-term once the new solver has stabilized. + +An additional complication is that the compiler is currently undergoing a transition from the old trait solver to the new trait solver. +As part of this transition our approach to normalization in the compiler has changed somewhat significantly, resulting in some normalization entry points being "old solver only" slated for removal in the long-term once the new solver has stabilized. +The transition can be tracked via the [WG-trait-system-refactor](https://github.com/rust-lang/rust/labels/WG-trait-system-refactor) label in Github. Here is a rough overview of the different entry points to normalization in the compiler: - `infcx.at.structurally_normalize` @@ -306,4 +309,4 @@ Const aliases differ from type aliases a bit here; well formedness of const alia [^5]: Const aliases certainly wouldn't be *less* sound than type aliases if we stopped doing this -[const_evaluatable]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ClauseKind.html#variant.ConstEvaluatable \ No newline at end of file +[const_evaluatable]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ClauseKind.html#variant.ConstEvaluatable From 1d35ac9ce0e5e5265fae1b2a4754013c1e479960 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 26 May 2025 14:47:19 +0200 Subject: [PATCH 2806/4206] Add missing edition directives for async-await tests --- .../async-fn/edition-2015-not-async-bound.rs | 1 + tests/ui/async-await/async-fn/edition-2015.rs | 1 + .../async-await/async-fn/edition-2015.stderr | 8 +++---- .../2015-edition-error-various-positions.rs | 1 + ...015-edition-error-various-positions.stderr | 22 +++++++++---------- .../await-keyword/2015-edition-warning.fixed | 1 + .../await-keyword/2015-edition-warning.rs | 1 + .../await-keyword/2015-edition-warning.stderr | 14 ++++++------ tests/ui/async-await/for-await-2015.rs | 1 + ...34-raw-ident-suggestion.edition2015.stderr | 6 ++--- ...34-raw-ident-suggestion.edition2018.stderr | 6 ++--- .../issue-65634-raw-ident-suggestion.rs | 1 + ...uggest-switching-edition-on-await-cargo.rs | 1 + ...st-switching-edition-on-await-cargo.stderr | 8 +++---- .../suggest-switching-edition-on-await.rs | 1 + .../suggest-switching-edition-on-await.stderr | 8 +++---- 16 files changed, 45 insertions(+), 36 deletions(-) diff --git a/tests/ui/async-await/async-fn/edition-2015-not-async-bound.rs b/tests/ui/async-await/async-fn/edition-2015-not-async-bound.rs index d222ddc081eff..60a7dff7d499a 100644 --- a/tests/ui/async-await/async-fn/edition-2015-not-async-bound.rs +++ b/tests/ui/async-await/async-fn/edition-2015-not-async-bound.rs @@ -1,3 +1,4 @@ +//@ edition:2015 //@ check-pass // Make sure that we don't eagerly recover `async ::Bound` in edition 2015. diff --git a/tests/ui/async-await/async-fn/edition-2015.rs b/tests/ui/async-await/async-fn/edition-2015.rs index 341b9b10e6711..5a81df3a4e4d9 100644 --- a/tests/ui/async-await/async-fn/edition-2015.rs +++ b/tests/ui/async-await/async-fn/edition-2015.rs @@ -1,3 +1,4 @@ +//@ edition:2015 fn foo(x: impl async Fn()) -> impl async Fn() { x } //~^ ERROR `async` trait bounds are only allowed in Rust 2018 or later //~| ERROR `async` trait bounds are only allowed in Rust 2018 or later diff --git a/tests/ui/async-await/async-fn/edition-2015.stderr b/tests/ui/async-await/async-fn/edition-2015.stderr index ca9e64cd1bb08..0bec00c162c9d 100644 --- a/tests/ui/async-await/async-fn/edition-2015.stderr +++ b/tests/ui/async-await/async-fn/edition-2015.stderr @@ -1,5 +1,5 @@ error: `async` trait bounds are only allowed in Rust 2018 or later - --> $DIR/edition-2015.rs:1:16 + --> $DIR/edition-2015.rs:2:16 | LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } | ^^^^^ @@ -8,7 +8,7 @@ LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } = note: for more on editions, read https://doc.rust-lang.org/edition-guide error: `async` trait bounds are only allowed in Rust 2018 or later - --> $DIR/edition-2015.rs:1:36 + --> $DIR/edition-2015.rs:2:36 | LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } | ^^^^^ @@ -17,7 +17,7 @@ LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0658]: `async` trait bounds are unstable - --> $DIR/edition-2015.rs:1:16 + --> $DIR/edition-2015.rs:2:16 | LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } | ^^^^^ @@ -28,7 +28,7 @@ LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } = help: use the desugared name of the async trait, such as `AsyncFn` error[E0658]: `async` trait bounds are unstable - --> $DIR/edition-2015.rs:1:36 + --> $DIR/edition-2015.rs:2:36 | LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } | ^^^^^ diff --git a/tests/ui/async-await/await-keyword/2015-edition-error-various-positions.rs b/tests/ui/async-await/await-keyword/2015-edition-error-various-positions.rs index 50c1639996ee5..714a3328ecf68 100644 --- a/tests/ui/async-await/await-keyword/2015-edition-error-various-positions.rs +++ b/tests/ui/async-await/await-keyword/2015-edition-error-various-positions.rs @@ -1,3 +1,4 @@ +//@ edition:2015 #![allow(non_camel_case_types)] #![deny(keyword_idents)] diff --git a/tests/ui/async-await/await-keyword/2015-edition-error-various-positions.stderr b/tests/ui/async-await/await-keyword/2015-edition-error-various-positions.stderr index 8cea73f865148..70900e612f483 100644 --- a/tests/ui/async-await/await-keyword/2015-edition-error-various-positions.stderr +++ b/tests/ui/async-await/await-keyword/2015-edition-error-various-positions.stderr @@ -1,5 +1,5 @@ error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-error-various-positions.rs:5:13 + --> $DIR/2015-edition-error-various-positions.rs:6:13 | LL | pub mod await { | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` @@ -7,14 +7,14 @@ LL | pub mod await { = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! = note: for more information, see issue #49716 note: the lint level is defined here - --> $DIR/2015-edition-error-various-positions.rs:2:9 + --> $DIR/2015-edition-error-various-positions.rs:3:9 | LL | #![deny(keyword_idents)] | ^^^^^^^^^^^^^^ = note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]` error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-error-various-positions.rs:7:20 + --> $DIR/2015-edition-error-various-positions.rs:8:20 | LL | pub struct await; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` @@ -23,7 +23,7 @@ LL | pub struct await; = note: for more information, see issue #49716 error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-error-various-positions.rs:11:16 + --> $DIR/2015-edition-error-various-positions.rs:12:16 | LL | use outer_mod::await::await; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` @@ -32,7 +32,7 @@ LL | use outer_mod::await::await; = note: for more information, see issue #49716 error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-error-various-positions.rs:11:23 + --> $DIR/2015-edition-error-various-positions.rs:12:23 | LL | use outer_mod::await::await; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` @@ -41,7 +41,7 @@ LL | use outer_mod::await::await; = note: for more information, see issue #49716 error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-error-various-positions.rs:16:14 + --> $DIR/2015-edition-error-various-positions.rs:17:14 | LL | struct Foo { await: () } | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` @@ -50,7 +50,7 @@ LL | struct Foo { await: () } = note: for more information, see issue #49716 error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-error-various-positions.rs:20:15 + --> $DIR/2015-edition-error-various-positions.rs:21:15 | LL | impl Foo { fn await() {} } | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` @@ -59,7 +59,7 @@ LL | impl Foo { fn await() {} } = note: for more information, see issue #49716 error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-error-various-positions.rs:24:14 + --> $DIR/2015-edition-error-various-positions.rs:25:14 | LL | macro_rules! await { | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` @@ -68,7 +68,7 @@ LL | macro_rules! await { = note: for more information, see issue #49716 error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-error-various-positions.rs:31:5 + --> $DIR/2015-edition-error-various-positions.rs:32:5 | LL | await!(); | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` @@ -77,7 +77,7 @@ LL | await!(); = note: for more information, see issue #49716 error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-error-various-positions.rs:34:11 + --> $DIR/2015-edition-error-various-positions.rs:35:11 | LL | match await { await => {} } | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` @@ -86,7 +86,7 @@ LL | match await { await => {} } = note: for more information, see issue #49716 error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-error-various-positions.rs:34:19 + --> $DIR/2015-edition-error-various-positions.rs:35:19 | LL | match await { await => {} } | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` diff --git a/tests/ui/async-await/await-keyword/2015-edition-warning.fixed b/tests/ui/async-await/await-keyword/2015-edition-warning.fixed index 4cb8017c7ee36..45758cb10391d 100644 --- a/tests/ui/async-await/await-keyword/2015-edition-warning.fixed +++ b/tests/ui/async-await/await-keyword/2015-edition-warning.fixed @@ -1,3 +1,4 @@ +//@ edition:2015 //@ run-rustfix #![allow(non_camel_case_types)] diff --git a/tests/ui/async-await/await-keyword/2015-edition-warning.rs b/tests/ui/async-await/await-keyword/2015-edition-warning.rs index d591a5af8218c..ea26abe072b37 100644 --- a/tests/ui/async-await/await-keyword/2015-edition-warning.rs +++ b/tests/ui/async-await/await-keyword/2015-edition-warning.rs @@ -1,3 +1,4 @@ +//@ edition:2015 //@ run-rustfix #![allow(non_camel_case_types)] diff --git a/tests/ui/async-await/await-keyword/2015-edition-warning.stderr b/tests/ui/async-await/await-keyword/2015-edition-warning.stderr index 70b7fa52a19c7..9d19a09092b94 100644 --- a/tests/ui/async-await/await-keyword/2015-edition-warning.stderr +++ b/tests/ui/async-await/await-keyword/2015-edition-warning.stderr @@ -1,5 +1,5 @@ error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-warning.rs:7:13 + --> $DIR/2015-edition-warning.rs:8:13 | LL | pub mod await { | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` @@ -7,14 +7,14 @@ LL | pub mod await { = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! = note: for more information, see issue #49716 note: the lint level is defined here - --> $DIR/2015-edition-warning.rs:4:9 + --> $DIR/2015-edition-warning.rs:5:9 | LL | #![deny(keyword_idents)] | ^^^^^^^^^^^^^^ = note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]` error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-warning.rs:10:20 + --> $DIR/2015-edition-warning.rs:11:20 | LL | pub struct await; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` @@ -23,7 +23,7 @@ LL | pub struct await; = note: for more information, see issue #49716 error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-warning.rs:15:16 + --> $DIR/2015-edition-warning.rs:16:16 | LL | use outer_mod::await::await; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` @@ -32,7 +32,7 @@ LL | use outer_mod::await::await; = note: for more information, see issue #49716 error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-warning.rs:15:23 + --> $DIR/2015-edition-warning.rs:16:23 | LL | use outer_mod::await::await; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` @@ -41,7 +41,7 @@ LL | use outer_mod::await::await; = note: for more information, see issue #49716 error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-warning.rs:22:11 + --> $DIR/2015-edition-warning.rs:23:11 | LL | match await { await => {} } | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` @@ -50,7 +50,7 @@ LL | match await { await => {} } = note: for more information, see issue #49716 error: `await` is a keyword in the 2018 edition - --> $DIR/2015-edition-warning.rs:22:19 + --> $DIR/2015-edition-warning.rs:23:19 | LL | match await { await => {} } | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` diff --git a/tests/ui/async-await/for-await-2015.rs b/tests/ui/async-await/for-await-2015.rs index 89ff256da1ddf..c2bd39c844663 100644 --- a/tests/ui/async-await/for-await-2015.rs +++ b/tests/ui/async-await/for-await-2015.rs @@ -1,3 +1,4 @@ +//@ edition:2015 //@ check-pass #![feature(async_for_loop)] diff --git a/tests/ui/async-await/issue-65634-raw-ident-suggestion.edition2015.stderr b/tests/ui/async-await/issue-65634-raw-ident-suggestion.edition2015.stderr index 2bdc1347c815d..8ce4d4ea06ac8 100644 --- a/tests/ui/async-await/issue-65634-raw-ident-suggestion.edition2015.stderr +++ b/tests/ui/async-await/issue-65634-raw-ident-suggestion.edition2015.stderr @@ -1,16 +1,16 @@ error[E0034]: multiple applicable items in scope - --> $DIR/issue-65634-raw-ident-suggestion.rs:24:13 + --> $DIR/issue-65634-raw-ident-suggestion.rs:25:13 | LL | r#fn {}.r#struct(); | ^^^^^^^^ multiple `r#struct` found | note: candidate #1 is defined in an impl of the trait `async` for the type `r#fn` - --> $DIR/issue-65634-raw-ident-suggestion.rs:7:5 + --> $DIR/issue-65634-raw-ident-suggestion.rs:8:5 | LL | fn r#struct(&self) { | ^^^^^^^^^^^^^^^^^^ note: candidate #2 is defined in an impl of the trait `await` for the type `r#fn` - --> $DIR/issue-65634-raw-ident-suggestion.rs:13:5 + --> $DIR/issue-65634-raw-ident-suggestion.rs:14:5 | LL | fn r#struct(&self) { | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/issue-65634-raw-ident-suggestion.edition2018.stderr b/tests/ui/async-await/issue-65634-raw-ident-suggestion.edition2018.stderr index ab10ab749fedf..d910ef9872cdb 100644 --- a/tests/ui/async-await/issue-65634-raw-ident-suggestion.edition2018.stderr +++ b/tests/ui/async-await/issue-65634-raw-ident-suggestion.edition2018.stderr @@ -1,16 +1,16 @@ error[E0034]: multiple applicable items in scope - --> $DIR/issue-65634-raw-ident-suggestion.rs:24:13 + --> $DIR/issue-65634-raw-ident-suggestion.rs:25:13 | LL | r#fn {}.r#struct(); | ^^^^^^^^ multiple `r#struct` found | note: candidate #1 is defined in an impl of the trait `r#async` for the type `r#fn` - --> $DIR/issue-65634-raw-ident-suggestion.rs:7:5 + --> $DIR/issue-65634-raw-ident-suggestion.rs:8:5 | LL | fn r#struct(&self) { | ^^^^^^^^^^^^^^^^^^ note: candidate #2 is defined in an impl of the trait `r#await` for the type `r#fn` - --> $DIR/issue-65634-raw-ident-suggestion.rs:13:5 + --> $DIR/issue-65634-raw-ident-suggestion.rs:14:5 | LL | fn r#struct(&self) { | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/issue-65634-raw-ident-suggestion.rs b/tests/ui/async-await/issue-65634-raw-ident-suggestion.rs index ef5760f4846b7..98f5b6dd9f98e 100644 --- a/tests/ui/async-await/issue-65634-raw-ident-suggestion.rs +++ b/tests/ui/async-await/issue-65634-raw-ident-suggestion.rs @@ -1,4 +1,5 @@ //@ revisions: edition2015 edition2018 +//@[edition2015]edition:2015 //@[edition2018]edition:2018 #![allow(non_camel_case_types)] diff --git a/tests/ui/async-await/suggest-switching-edition-on-await-cargo.rs b/tests/ui/async-await/suggest-switching-edition-on-await-cargo.rs index bcb5cb94b77c8..555b011052158 100644 --- a/tests/ui/async-await/suggest-switching-edition-on-await-cargo.rs +++ b/tests/ui/async-await/suggest-switching-edition-on-await-cargo.rs @@ -1,3 +1,4 @@ +//@ edition:2015 //@ rustc-env:CARGO_CRATE_NAME=foo use std::pin::Pin; diff --git a/tests/ui/async-await/suggest-switching-edition-on-await-cargo.stderr b/tests/ui/async-await/suggest-switching-edition-on-await-cargo.stderr index 11f5825c232ea..c5f1793731ea4 100644 --- a/tests/ui/async-await/suggest-switching-edition-on-await-cargo.stderr +++ b/tests/ui/async-await/suggest-switching-edition-on-await-cargo.stderr @@ -1,5 +1,5 @@ error[E0609]: no field `await` on type `await_on_struct_missing::S` - --> $DIR/suggest-switching-edition-on-await-cargo.rs:11:7 + --> $DIR/suggest-switching-edition-on-await-cargo.rs:12:7 | LL | x.await; | ^^^^^ unknown field @@ -9,7 +9,7 @@ LL | x.await; = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0609]: no field `await` on type `await_on_struct_similar::S` - --> $DIR/suggest-switching-edition-on-await-cargo.rs:24:7 + --> $DIR/suggest-switching-edition-on-await-cargo.rs:25:7 | LL | x.await; | ^^^^^ unknown field @@ -24,7 +24,7 @@ LL + x.awai; | error[E0609]: no field `await` on type `Pin<&mut dyn Future>` - --> $DIR/suggest-switching-edition-on-await-cargo.rs:34:7 + --> $DIR/suggest-switching-edition-on-await-cargo.rs:35:7 | LL | x.await; | ^^^^^ unknown field @@ -34,7 +34,7 @@ LL | x.await; = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0609]: no field `await` on type `impl Future` - --> $DIR/suggest-switching-edition-on-await-cargo.rs:43:7 + --> $DIR/suggest-switching-edition-on-await-cargo.rs:44:7 | LL | x.await; | ^^^^^ unknown field diff --git a/tests/ui/async-await/suggest-switching-edition-on-await.rs b/tests/ui/async-await/suggest-switching-edition-on-await.rs index 0907a87e02cf3..6b639fa0b4ea5 100644 --- a/tests/ui/async-await/suggest-switching-edition-on-await.rs +++ b/tests/ui/async-await/suggest-switching-edition-on-await.rs @@ -1,3 +1,4 @@ +//@ edition:2015 use std::pin::Pin; use std::future::Future; diff --git a/tests/ui/async-await/suggest-switching-edition-on-await.stderr b/tests/ui/async-await/suggest-switching-edition-on-await.stderr index 2ede8d5b7f42e..bf03016222eaf 100644 --- a/tests/ui/async-await/suggest-switching-edition-on-await.stderr +++ b/tests/ui/async-await/suggest-switching-edition-on-await.stderr @@ -1,5 +1,5 @@ error[E0609]: no field `await` on type `await_on_struct_missing::S` - --> $DIR/suggest-switching-edition-on-await.rs:9:7 + --> $DIR/suggest-switching-edition-on-await.rs:10:7 | LL | x.await; | ^^^^^ unknown field @@ -9,7 +9,7 @@ LL | x.await; = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0609]: no field `await` on type `await_on_struct_similar::S` - --> $DIR/suggest-switching-edition-on-await.rs:22:7 + --> $DIR/suggest-switching-edition-on-await.rs:23:7 | LL | x.await; | ^^^^^ unknown field @@ -24,7 +24,7 @@ LL + x.awai; | error[E0609]: no field `await` on type `Pin<&mut dyn Future>` - --> $DIR/suggest-switching-edition-on-await.rs:32:7 + --> $DIR/suggest-switching-edition-on-await.rs:33:7 | LL | x.await; | ^^^^^ unknown field @@ -34,7 +34,7 @@ LL | x.await; = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0609]: no field `await` on type `impl Future` - --> $DIR/suggest-switching-edition-on-await.rs:41:7 + --> $DIR/suggest-switching-edition-on-await.rs:42:7 | LL | x.await; | ^^^^^ unknown field From 1e7c4377de7d80786151b355307e104709904b31 Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Mon, 26 May 2025 15:37:45 +0200 Subject: [PATCH 2807/4206] ci: move dist-x86_64-linux job to codebuild --- src/ci/github-actions/jobs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 1d175bd97e6a1..f444e09c3112f 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -132,7 +132,7 @@ try: - name: dist-x86_64-linux env: CODEGEN_BACKENDS: llvm,cranelift - <<: *job-linux-16c + <<: *job-linux-36c-codebuild # Main CI jobs that have to be green to merge a commit into master # These jobs automatically inherit envs.auto, to avoid repeating @@ -228,7 +228,7 @@ auto: - name: dist-x86_64-linux env: CODEGEN_BACKENDS: llvm,cranelift - <<: *job-linux-16c + <<: *job-linux-36c-codebuild - name: dist-x86_64-linux-alt env: From 6ec41a79501cb29ef45f62b123cf097cec9eb3dd Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Mon, 26 May 2025 16:52:24 +0200 Subject: [PATCH 2808/4206] ci: fix llvm test coverage --- src/ci/github-actions/jobs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 1d175bd97e6a1..e257f231184d7 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -332,7 +332,7 @@ auto: env: RUST_BACKTRACE: 1 IMAGE: x86_64-gnu-llvm-20 - DOCKER_SCRIPT: stage_2_test_set1.sh + DOCKER_SCRIPT: stage_2_test_set2.sh <<: *job-linux-4c # Skip tests that run in x86_64-gnu-llvm-20-{1,3} @@ -357,7 +357,7 @@ auto: env: RUST_BACKTRACE: 1 IMAGE: x86_64-gnu-llvm-19 - DOCKER_SCRIPT: stage_2_test_set1.sh + DOCKER_SCRIPT: stage_2_test_set2.sh <<: *job-linux-4c # Skip tests that run in x86_64-gnu-llvm-19-{1,3} From c27aff35caad45093b52988994c2bc9b5631b544 Mon Sep 17 00:00:00 2001 From: Boxy Date: Mon, 26 May 2025 16:35:36 +0100 Subject: [PATCH 2809/4206] Add test --- .../copy-check-when-count-inferred-later.rs | 11 +++++++++++ .../copy-check-when-count-inferred-later.stderr | 14 ++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 tests/ui/repeat-expr/copy-check-when-count-inferred-later.rs create mode 100644 tests/ui/repeat-expr/copy-check-when-count-inferred-later.stderr diff --git a/tests/ui/repeat-expr/copy-check-when-count-inferred-later.rs b/tests/ui/repeat-expr/copy-check-when-count-inferred-later.rs new file mode 100644 index 0000000000000..b9d123cbefae6 --- /dev/null +++ b/tests/ui/repeat-expr/copy-check-when-count-inferred-later.rs @@ -0,0 +1,11 @@ +#![feature(generic_arg_infer)] + +// Test that we enforce repeat expr element types are `Copy` even +// when the repeat count is only inferred at a later point in type +// checking. + +fn main() { + let a = [String::new(); _]; + //~^ ERROR: the trait bound `String: Copy` is not satisfied + let b: [_; 2] = a; +} diff --git a/tests/ui/repeat-expr/copy-check-when-count-inferred-later.stderr b/tests/ui/repeat-expr/copy-check-when-count-inferred-later.stderr new file mode 100644 index 0000000000000..d974f5add5052 --- /dev/null +++ b/tests/ui/repeat-expr/copy-check-when-count-inferred-later.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/copy-check-when-count-inferred-later.rs:8:14 + | +LL | let a = [String::new(); _]; + | ^^^^^^^^^^^^^ + | | + | the trait `Copy` is not implemented for `String` + | help: create an inline `const` block: `const { String::new() }` + | + = note: the `Copy` trait is required because this value will be copied for each element of the array + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From 8e581e31a2191392461210f3f7a168910da5bf49 Mon Sep 17 00:00:00 2001 From: Dan Johnson Date: Thu, 15 May 2025 01:08:47 -0700 Subject: [PATCH 2810/4206] add lint infallible_try_from Looks for `TryFrom` implementations with uninhabited error types and suggests to implement `From` instead. --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/infallible_try_from.rs | 76 +++++++++++++++++++++++++ clippy_lints/src/lib.rs | 2 + tests/ui/crashes/ice-rust-107877.rs | 1 + tests/ui/infallible_try_from.rs | 33 +++++++++++ tests/ui/infallible_try_from.stderr | 23 ++++++++ 7 files changed, 137 insertions(+) create mode 100644 clippy_lints/src/infallible_try_from.rs create mode 100644 tests/ui/infallible_try_from.rs create mode 100644 tests/ui/infallible_try_from.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 28147dfbea3e0..9c06562e18e7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5862,6 +5862,7 @@ Released 2018-09-13 [`ineffective_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_open_options [`inefficient_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inefficient_to_string [`infallible_destructuring_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#infallible_destructuring_match +[`infallible_try_from`]: https://rust-lang.github.io/rust-clippy/master/index.html#infallible_try_from [`infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#infinite_iter [`infinite_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#infinite_loop [`inherent_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index bb825c7655f87..12dd407711ca9 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -211,6 +211,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::indexing_slicing::INDEXING_SLICING_INFO, crate::indexing_slicing::OUT_OF_BOUNDS_INDEXING_INFO, crate::ineffective_open_options::INEFFECTIVE_OPEN_OPTIONS_INFO, + crate::infallible_try_from::INFALLIBLE_TRY_FROM_INFO, crate::infinite_iter::INFINITE_ITER_INFO, crate::infinite_iter::MAYBE_INFINITE_ITER_INFO, crate::inherent_impl::MULTIPLE_INHERENT_IMPL_INFO, diff --git a/clippy_lints/src/infallible_try_from.rs b/clippy_lints/src/infallible_try_from.rs new file mode 100644 index 0000000000000..b54c289fa7e13 --- /dev/null +++ b/clippy_lints/src/infallible_try_from.rs @@ -0,0 +1,76 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::sym; +use rustc_errors::MultiSpan; +use rustc_hir::{AssocItemKind, Item, ItemKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// + /// Finds manual impls of `TryFrom` with infallible error types. + /// + /// ### Why is this bad? + /// + /// Infalliable conversions should be implemented via `From` with the blanket conversion. + /// + /// ### Example + /// ```no_run + /// use std::convert::Infallible; + /// struct MyStruct(i16); + /// impl TryFrom for MyStruct { + /// type Error = Infallible; + /// fn try_from(other: i16) -> Result { + /// Ok(Self(other.into())) + /// } + /// } + /// ``` + /// Use instead: + /// ```no_run + /// struct MyStruct(i16); + /// impl From for MyStruct { + /// fn from(other: i16) -> Self { + /// Self(other) + /// } + /// } + /// ``` + #[clippy::version = "1.88.0"] + pub INFALLIBLE_TRY_FROM, + suspicious, + "TryFrom with infallible Error type" +} +declare_lint_pass!(InfallibleTryFrom => [INFALLIBLE_TRY_FROM]); + +impl<'tcx> LateLintPass<'tcx> for InfallibleTryFrom { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + let ItemKind::Impl(imp) = item.kind else { return }; + let Some(r#trait) = imp.of_trait else { return }; + let Some(trait_def_id) = r#trait.trait_def_id() else { + return; + }; + if !cx.tcx.is_diagnostic_item(sym::TryFrom, trait_def_id) { + return; + } + for ii in imp.items { + if ii.kind == AssocItemKind::Type { + let ii = cx.tcx.hir_impl_item(ii.id); + if ii.ident.name != sym::Error { + continue; + } + let ii_ty = ii.expect_type(); + let ii_ty_span = ii_ty.span; + let ii_ty = clippy_utils::ty::ty_from_hir_ty(cx, ii_ty); + if !ii_ty.is_inhabited_from(cx.tcx, ii.owner_id.to_def_id(), cx.typing_env()) { + let mut span = MultiSpan::from_span(cx.tcx.def_span(item.owner_id.to_def_id())); + span.push_span_label(ii_ty_span, "infallible error type"); + span_lint( + cx, + INFALLIBLE_TRY_FROM, + span, + "infallible TryFrom impl; consider implementing From, instead", + ); + } + } + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 006145cc623c3..0f60c62ed094b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -169,6 +169,7 @@ mod inconsistent_struct_constructor; mod index_refutable_slice; mod indexing_slicing; mod ineffective_open_options; +mod infallible_try_from; mod infinite_iter; mod inherent_impl; mod inherent_to_string; @@ -944,5 +945,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(single_option_map::SingleOptionMap)); store.register_late_pass(move |_| Box::new(redundant_test_prefix::RedundantTestPrefix)); store.register_late_pass(|_| Box::new(cloned_ref_to_slice_refs::ClonedRefToSliceRefs::new(conf))); + store.register_late_pass(|_| Box::new(infallible_try_from::InfallibleTryFrom)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/tests/ui/crashes/ice-rust-107877.rs b/tests/ui/crashes/ice-rust-107877.rs index 55fe418bed123..dccb0cf8ac152 100644 --- a/tests/ui/crashes/ice-rust-107877.rs +++ b/tests/ui/crashes/ice-rust-107877.rs @@ -4,6 +4,7 @@ struct Foo; +#[allow(clippy::infallible_try_from)] impl<'a> std::convert::TryFrom<&'a String> for Foo { type Error = std::convert::Infallible; diff --git a/tests/ui/infallible_try_from.rs b/tests/ui/infallible_try_from.rs new file mode 100644 index 0000000000000..6a1f12f824f55 --- /dev/null +++ b/tests/ui/infallible_try_from.rs @@ -0,0 +1,33 @@ +#![feature(never_type)] +#![warn(clippy::infallible_try_from)] + +use std::convert::Infallible; + +struct MyStruct(i32); + +impl TryFrom for MyStruct { + //~^ infallible_try_from + type Error = !; + fn try_from(other: i8) -> Result { + Ok(Self(other.into())) + } +} + +impl TryFrom for MyStruct { + //~^ infallible_try_from + type Error = Infallible; + fn try_from(other: i16) -> Result { + Ok(Self(other.into())) + } +} + +impl TryFrom for MyStruct { + type Error = i64; + fn try_from(other: i64) -> Result { + Ok(Self(i32::try_from(other).map_err(|_| other)?)) + } +} + +fn main() { + // test code goes here +} diff --git a/tests/ui/infallible_try_from.stderr b/tests/ui/infallible_try_from.stderr new file mode 100644 index 0000000000000..705b1188489c2 --- /dev/null +++ b/tests/ui/infallible_try_from.stderr @@ -0,0 +1,23 @@ +error: infallible TryFrom impl; consider implementing From, instead + --> tests/ui/infallible_try_from.rs:8:1 + | +LL | impl TryFrom for MyStruct { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | type Error = !; + | - infallible error type + | + = note: `-D clippy::infallible-try-from` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::infallible_try_from)]` + +error: infallible TryFrom impl; consider implementing From, instead + --> tests/ui/infallible_try_from.rs:16:1 + | +LL | impl TryFrom for MyStruct { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | type Error = Infallible; + | ---------- infallible error type + +error: aborting due to 2 previous errors + From 0497f31122e0c5908bf68d83f3e8ba5b559ae3d6 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 26 May 2025 17:55:03 +0200 Subject: [PATCH 2811/4206] rustc book: fix erratic sentence by making it more simple --- src/doc/rustc/src/check-cfg/cargo-specifics.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc/src/check-cfg/cargo-specifics.md b/src/doc/rustc/src/check-cfg/cargo-specifics.md index 371bbd26e943f..62a4dd1a3901d 100644 --- a/src/doc/rustc/src/check-cfg/cargo-specifics.md +++ b/src/doc/rustc/src/check-cfg/cargo-specifics.md @@ -9,8 +9,8 @@ rustc, not Cargo. --> This document is intended to summarize the principal ways Cargo interacts with -the `unexpected_cfgs` lint and `--check-cfg` flag. It is not intended to provide -individual details, for that refer to the [`--check-cfg` documentation](../check-cfg.md) and +the `unexpected_cfgs` lint and `--check-cfg` flag. +For individual details, refer to the [`--check-cfg` documentation](../check-cfg.md) and to the [Cargo book](../../cargo/index.html). > The full list of well known cfgs (aka builtins) can be found under [Checking conditional configurations / Well known names and values](../check-cfg.md#well-known-names-and-values). From 19802e8e9cf2732768c89dcfe1c5fa0eb88cd558 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 27 May 2025 02:06:40 +1000 Subject: [PATCH 2812/4206] Remove an unnecessary use of `Box::into_inner`. --- compiler/rustc_errors/src/diagnostic.rs | 2 +- compiler/rustc_errors/src/lib.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 539ecfbb42e2c..a11f81b55bb84 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -1325,7 +1325,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { )); self.note("consider using `--verbose` to print the full type name to the console"); } - Box::into_inner(self.diag.take().unwrap()) + *self.diag.take().unwrap() } /// This method allows us to access the path of the file where "long types" are written to. diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index f8e19e5077893..bd421a441f95c 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -12,7 +12,6 @@ #![feature(array_windows)] #![feature(assert_matches)] #![feature(associated_type_defaults)] -#![feature(box_into_inner)] #![feature(box_patterns)] #![feature(default_field_values)] #![feature(error_reporter)] From a35675d38f10cf19c9512d5d621338fc00530ad3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 27 May 2025 01:57:43 +1000 Subject: [PATCH 2813/4206] Remove `'static` bounds on `P`. These date back to 2014. I don't think they're needed any more. --- compiler/rustc_ast/src/ptr.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs index dd923305cdfd9..1e6a5e91f2320 100644 --- a/compiler/rustc_ast/src/ptr.rs +++ b/compiler/rustc_ast/src/ptr.rs @@ -32,11 +32,11 @@ pub struct P { /// Construct a `P` from a `T` value. #[allow(non_snake_case)] -pub fn P(value: T) -> P { +pub fn P(value: T) -> P { P { ptr: Box::new(value) } } -impl P { +impl P { /// Move out of the pointer. /// Intended for chaining transformations not covered by `map`. pub fn and_then(self, f: F) -> U @@ -86,7 +86,7 @@ impl DerefMut for P { } } -impl Clone for P { +impl Clone for P { fn clone(&self) -> P { P((**self).clone()) } @@ -110,7 +110,7 @@ impl fmt::Pointer for P { } } -impl> Decodable for P { +impl> Decodable for P { fn decode(d: &mut D) -> P { P(Decodable::decode(d)) } From 6973fa08a3a4044c87b9da9e66cb1ca17f89b889 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 27 May 2025 01:42:51 +1000 Subject: [PATCH 2814/4206] Remove `P::map`. It's barely used, and the places that use it are better if they don't. --- compiler/rustc_ast/src/ast.rs | 7 ++-- compiler/rustc_ast/src/ptr.rs | 11 ------ .../src/proc_macro_harness.rs | 36 +++++++++---------- compiler/rustc_builtin_macros/src/test.rs | 5 +-- 4 files changed, 21 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index a16219361c051..c4be07ba06816 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1123,10 +1123,9 @@ impl Stmt { pub fn add_trailing_semicolon(mut self) -> Self { self.kind = match self.kind { StmtKind::Expr(expr) => StmtKind::Semi(expr), - StmtKind::MacCall(mac) => { - StmtKind::MacCall(mac.map(|MacCallStmt { mac, style: _, attrs, tokens }| { - MacCallStmt { mac, style: MacStmtStyle::Semicolon, attrs, tokens } - })) + StmtKind::MacCall(mut mac) => { + mac.style = MacStmtStyle::Semicolon; + StmtKind::MacCall(mac) } kind => kind, }; diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs index 1e6a5e91f2320..a1b265cf0a949 100644 --- a/compiler/rustc_ast/src/ptr.rs +++ b/compiler/rustc_ast/src/ptr.rs @@ -51,17 +51,6 @@ impl P { *self.ptr } - /// Produce a new `P` from `self` without reallocating. - pub fn map(mut self, f: F) -> P - where - F: FnOnce(T) -> T, - { - let x = f(*self.ptr); - *self.ptr = x; - - self - } - /// Optionally produce a new `P` from `self` without reallocating. pub fn filter_map(mut self, f: F) -> Option> where diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index a91f2d38a93ae..daf480a9ce472 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -354,30 +354,28 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P { }) .collect(); - let decls_static = cx - .item_static( + let mut decls_static = cx.item_static( + span, + Ident::new(sym::_DECLS, span), + cx.ty_ref( span, - Ident::new(sym::_DECLS, span), - cx.ty_ref( + cx.ty( span, - cx.ty( - span, - ast::TyKind::Slice( - cx.ty_path(cx.path(span, vec![proc_macro, bridge, client, proc_macro_ty])), - ), + ast::TyKind::Slice( + cx.ty_path(cx.path(span, vec![proc_macro, bridge, client, proc_macro_ty])), ), - None, - ast::Mutability::Not, ), + None, ast::Mutability::Not, - cx.expr_array_ref(span, decls), - ) - .map(|mut i| { - i.attrs.push(cx.attr_word(sym::rustc_proc_macro_decls, span)); - i.attrs.push(cx.attr_word(sym::used, span)); - i.attrs.push(cx.attr_nested_word(sym::allow, sym::deprecated, span)); - i - }); + ), + ast::Mutability::Not, + cx.expr_array_ref(span, decls), + ); + decls_static.attrs.extend([ + cx.attr_word(sym::rustc_proc_macro_decls, span), + cx.attr_word(sym::used, span), + cx.attr_nested_word(sym::allow, sym::deprecated, span), + ]); let block = cx.expr_block( cx.block(span, thin_vec![cx.stmt_item(span, krate), cx.stmt_item(span, decls_static)]), diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 1cef4f9514cd7..fbe91531e5a33 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -381,10 +381,7 @@ pub(crate) fn expand_test_or_bench( .into(), ), ); - test_const = test_const.map(|mut tc| { - tc.vis.kind = ast::VisibilityKind::Public; - tc - }); + test_const.vis.kind = ast::VisibilityKind::Public; // extern crate test let test_extern = From f9931d198cb92b72a0a8f893c380fdf07ebb4800 Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 26 May 2025 11:35:45 -0500 Subject: [PATCH 2815/4206] rustdoc: refactor Tooltip rendering logic --- src/librustdoc/html/highlight.rs | 64 +++++++++++--------------------- 1 file changed, 21 insertions(+), 43 deletions(-) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index f9d355cc0386d..b2feee36c939c 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -81,51 +81,29 @@ fn write_header( ); if tooltip != Tooltip::None { - // variable for extending lifetimes of temporaries - let tmp; - write_str( - out, - format_args!( - "", - match tooltip { - Tooltip::IgnoreAll => "This example is not tested", - Tooltip::IgnoreSome(platforms) => { - tmp = format!( - "This example is not tested on {}", - fmt::from_fn(|f| { - match platforms.len() { - 0 => unreachable!(), - 1 => f.write_str(&platforms[0]), - 2 => write!(f, "{} or {}", &platforms[0], &platforms[1]), - _ => { - for (i, plat) in platforms.iter().enumerate() { - match (platforms.len() - 2).cmp(&i) { - std::cmp::Ordering::Greater => { - write!(f, "{}, ", plat)? - } - std::cmp::Ordering::Equal => { - write!(f, "{}, or ", plat)? - } - std::cmp::Ordering::Less => f.write_str(&plat)?, - } - } - Ok(()) - } - } - }) - ); - &tmp - } - Tooltip::CompileFail => "This example deliberately fails to compile", - Tooltip::ShouldPanic => "This example panics", - Tooltip::Edition(edition) => { - tmp = format!("This example runs with edition {edition}"); - &tmp + let tooltip = fmt::from_fn(|f| match &tooltip { + Tooltip::IgnoreAll => f.write_str("This example is not tested"), + Tooltip::IgnoreSome(platforms) => { + f.write_str("This example is not tested on ")?; + match &platforms[..] { + [] => unreachable!(), + [platform] => f.write_str(platform)?, + [first, second] => write!(f, "{first} or {second}")?, + [platforms @ .., last] => { + for platform in platforms { + write!(f, "{platform}, ")?; + } + write!(f, "or {last}")?; } - Tooltip::None => unreachable!(), } - ), - ); + Ok(()) + } + Tooltip::CompileFail => f.write_str("This example deliberately fails to compile"), + Tooltip::ShouldPanic => f.write_str("This example panics"), + Tooltip::Edition(edition) => write!(f, "This example runs with edition {edition}"), + Tooltip::None => unreachable!(), + }); + write_str(out, format_args!("")); } if let Some(extra) = extra_content { From 8cced0fd6fd9c2b434ac08c09c160b026ed6b691 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 26 May 2025 21:30:20 +0500 Subject: [PATCH 2816/4206] Show total count lints --- util/gh-pages/index_template.html | 2 +- util/gh-pages/script.js | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/util/gh-pages/index_template.html b/util/gh-pages/index_template.html index 19dc1ec0b0cc6..865b9523c39e7 100644 --- a/util/gh-pages/index_template.html +++ b/util/gh-pages/index_template.html @@ -50,7 +50,7 @@
{# #} {# #}
//! [foo::Struct]
+
//! [Struct]
 //! This is an intra doc injection test for modules
-//! [foo::Struct]
+//! [Struct]
 //! This is an intra doc injection test for modules
 
 pub struct Struct;
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
index a8d9530946677..dd359326c61d6 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
@@ -1072,9 +1072,9 @@ fn test_mod_hl_injection() {
     check_highlighting(
         r##"
 //- /foo.rs
-//! [foo::Struct]
+//! [Struct]
 //! This is an intra doc injection test for modules
-//! [foo::Struct]
+//! [Struct]
 //! This is an intra doc injection test for modules
 
 pub struct Struct;
@@ -1097,9 +1097,9 @@ mod foo;
 /// This is an intra doc injection test for modules
 mod foo;
 //- /foo.rs
-//! [foo::Struct]
+//! [Struct]
 //! This is an intra doc injection test for modules
-//! [foo::Struct]
+//! [Struct]
 //! This is an intra doc injection test for modules
 
 pub struct Struct;

From ecb59e185a8c7170bd77ea7161bd7881be64e5ec Mon Sep 17 00:00:00 2001
From: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com>
Date: Wed, 7 May 2025 00:36:42 +0900
Subject: [PATCH 2017/4206] add doc link test for goto def

Signed-off-by: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com>
---
 .../crates/ide/src/goto_definition.rs         | 68 +++++++++++++++++++
 1 file changed, 68 insertions(+)

diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
index b894e857522f9..c60ca3562f663 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -1922,6 +1922,74 @@ pub fn foo() { }
         )
     }
 
+    #[test]
+    fn goto_def_for_intra_doc_link_outer_same_file() {
+        check(
+            r#"
+/// [`S$0`]
+mod m {
+    //! [`super::S`]
+}
+struct S;
+     //^
+            "#,
+        );
+
+        check(
+            r#"
+/// [`S$0`]
+mod m {}
+struct S;
+     //^
+            "#,
+        );
+
+        check(
+            r#"
+/// [`S$0`]
+fn f() {
+    //! [`S`]
+}
+struct S;
+     //^
+            "#,
+        );
+    }
+
+    #[test]
+    fn goto_def_for_intra_doc_link_inner_same_file() {
+        check(
+            r#"
+/// [`S`]
+mod m {
+    //! [`super::S$0`]
+}
+struct S;
+     //^
+            "#,
+        );
+
+        check(
+            r#"
+mod m {
+    //! [`super::S$0`]
+}
+struct S;
+     //^
+            "#,
+        );
+
+        check(
+            r#"
+fn f() {
+    //! [`S$0`]
+}
+struct S;
+     //^
+            "#,
+        );
+    }
+
     #[test]
     fn goto_def_for_intra_doc_link_inner() {
         check(

From 449d720651381cd5ad46c6e89130baea83de61d2 Mon Sep 17 00:00:00 2001
From: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com>
Date: Wed, 7 May 2025 00:36:52 +0900
Subject: [PATCH 2018/4206] add doc link test for hover

Signed-off-by: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com>
---
 .../crates/ide/src/hover/tests.rs             | 122 ++++++++++++++++++
 1 file changed, 122 insertions(+)

diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
index 7b7eef9d57936..06ca24c3ec35b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -7374,6 +7374,128 @@ pub struct Foo(i32);
     );
 }
 
+#[test]
+fn hover_intra_inner_attr() {
+    check(
+        r#"
+/// outer comment for [`Foo`]
+#[doc = "Doc outer comment for [`Foo`]"]
+pub fn Foo {
+    //! inner comment for [`Foo$0`]
+    #![doc = "Doc inner comment for [`Foo`]"]
+}
+"#,
+        expect![[r#"
+            *[`Foo`]*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            pub fn Foo()
+            ```
+
+            ---
+
+            outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html)
+            Doc outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html)
+            inner comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html)
+            Doc inner comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html)
+        "#]],
+    );
+
+    check(
+        r#"
+/// outer comment for [`Foo`]
+#[doc = "Doc outer comment for [`Foo`]"]
+pub mod Foo {
+    //! inner comment for [`super::Foo$0`]
+    #![doc = "Doc inner comment for [`super::Foo`]"]
+}
+"#,
+        expect![[r#"
+            *[`super::Foo`]*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            pub mod Foo
+            ```
+
+            ---
+
+            outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html)
+            Doc outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html)
+            inner comment for [`super::Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html)
+            Doc inner comment for [`super::Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html)
+        "#]],
+    );
+}
+
+#[test]
+fn hover_intra_outer_attr() {
+    check(
+        r#"
+/// outer comment for [`Foo$0`]
+#[doc = "Doc outer comment for [`Foo`]"]
+pub fn Foo() {
+    //! inner comment for [`Foo`]
+    #![doc = "Doc inner comment for [`Foo`]"]
+}
+"#,
+        expect![[r#"
+            *[`Foo`]*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            pub fn Foo()
+            ```
+
+            ---
+
+            outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html)
+            Doc outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html)
+            inner comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html)
+            Doc inner comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html)
+        "#]],
+    );
+
+    check(
+        r#"
+/// outer comment for [`Foo$0`]
+#[doc = "Doc outer comment for [`Foo`]"]
+pub mod Foo {
+    //! inner comment for [`super::Foo`]
+    #![doc = "Doc inner comment for [`super::Foo`]"]
+}
+"#,
+        expect![[r#"
+            *[`Foo`]*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            pub mod Foo
+            ```
+
+            ---
+
+            outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html)
+            Doc outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html)
+            inner comment for [`super::Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html)
+            Doc inner comment for [`super::Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html)
+        "#]],
+    );
+}
+
 #[test]
 fn hover_intra_generics() {
     check(

From 627fedb423343d3a26147986fdda1d8b18474597 Mon Sep 17 00:00:00 2001
From: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com>
Date: Wed, 7 May 2025 02:56:03 +0900
Subject: [PATCH 2019/4206] extract function: `doc_attributes` to find def from
 inner doc

Signed-off-by: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com>
---
 .../rust-analyzer/crates/ide/src/doc_links.rs | 34 ++++++++++++++-----
 1 file changed, 26 insertions(+), 8 deletions(-)

diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
index 2904203460601..2c983287d89c3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
@@ -12,7 +12,9 @@ use pulldown_cmark_to_cmark::{Options as CMarkOptions, cmark_resume_with_options
 use stdx::format_to;
 use url::Url;
 
-use hir::{Adt, AsAssocItem, AssocItem, AssocItemContainer, HasAttrs, db::HirDatabase, sym};
+use hir::{
+    Adt, AsAssocItem, AssocItem, AssocItemContainer, AttrsWithOwner, HasAttrs, db::HirDatabase, sym,
+};
 use ide_db::{
     RootDatabase,
     base_db::{CrateOrigin, LangCrateOrigin, ReleaseChannel, RootQueryDb},
@@ -322,13 +324,7 @@ impl DocCommentToken {
             };
             let token_start = t.text_range().start();
             let abs_in_expansion_offset = token_start + relative_comment_offset + descended_prefix_len;
-
-            let (attributes, def) = if is_inner && node.kind() != SOURCE_FILE {
-                let parent = node.parent()?;
-                doc_attributes(sema, &parent).unwrap_or(doc_attributes(sema, &parent.parent()?)?)
-            }else {
-                doc_attributes(sema, &node)?
-            };
+            let (attributes, def) = Self::doc_attributes(sema, &node, is_inner)?;
             let (docs, doc_mapping) = docs_with_rangemap(sema.db, &attributes)?;
             let (in_expansion_range, link, ns, is_inner) =
                 extract_definitions_from_docs(&docs).into_iter().find_map(|(range, link, ns)| {
@@ -343,6 +339,28 @@ impl DocCommentToken {
             cb(def, node, absolute_range)
         })
     }
+
+    /// When we hover a inner doc item, this find a attached definition.
+    /// ```
+    /// // node == ITEM_LIST
+    /// // node.parent == EXPR_BLOCK
+    /// // node.parent().parent() == FN
+    /// fn f() {
+    ///    //! [`S$0`]
+    /// }
+    /// ```
+    fn doc_attributes(
+        sema: &Semantics<'_, RootDatabase>,
+        node: &SyntaxNode,
+        is_inner_doc: bool,
+    ) -> Option<(AttrsWithOwner, Definition)> {
+        if is_inner_doc && node.kind() != SOURCE_FILE {
+            let parent = node.parent()?;
+            doc_attributes(sema, &parent).or(doc_attributes(sema, &parent.parent()?))
+        } else {
+            doc_attributes(sema, node)
+        }
+    }
 }
 
 fn broken_link_clone_cb(link: BrokenLink<'_>) -> Option<(CowStr<'_>, CowStr<'_>)> {

From cc5d1a5ab5c551ec763e2e32d1737ef7cddf9669 Mon Sep 17 00:00:00 2001
From: Samuel Tardieu 
Date: Tue, 6 May 2025 22:01:47 +0200
Subject: [PATCH 2020/4206] Post `non_std_lazy_statics` type warnings onto the
 right node

When a `non_std_lazy_statics` warning is generated about an item type which
can be replaced by a standard library one, ensure that the lint happens on
the item HIR node so that it can be expected.
---
 clippy_lints/src/non_std_lazy_statics.rs               | 10 +++++++---
 .../non_std_lazy_static_fixable.fixed                  |  7 +++++++
 .../non_std_lazy_static/non_std_lazy_static_fixable.rs |  7 +++++++
 3 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/clippy_lints/src/non_std_lazy_statics.rs b/clippy_lints/src/non_std_lazy_statics.rs
index 370ded99a4d0d..f66b9519317be 100644
--- a/clippy_lints/src/non_std_lazy_statics.rs
+++ b/clippy_lints/src/non_std_lazy_statics.rs
@@ -1,5 +1,5 @@
 use clippy_config::Conf;
-use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
+use clippy_utils::diagnostics::{span_lint, span_lint_hir_and_then};
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::paths::{self, PathNS, find_crates, lookup_path_str};
 use clippy_utils::visitors::for_each_expr;
@@ -8,7 +8,7 @@ use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId};
-use rustc_hir::{self as hir, BodyId, Expr, ExprKind, Item, ItemKind};
+use rustc_hir::{self as hir, BodyId, Expr, ExprKind, HirId, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
@@ -173,6 +173,8 @@ struct LazyInfo {
     /// //          ^^^^
     /// ```
     ty_span_no_args: Span,
+    /// Item on which the lint must be generated.
+    item_hir_id: HirId,
     /// `Span` and `DefId` of calls on `Lazy` type.
     /// i.e.:
     /// ```ignore
@@ -206,6 +208,7 @@ impl LazyInfo {
 
             Some(LazyInfo {
                 ty_span_no_args,
+                item_hir_id: item.hir_id(),
                 calls_span_and_id: new_fn_calls,
             })
         } else {
@@ -229,9 +232,10 @@ impl LazyInfo {
             }
         }
 
-        span_lint_and_then(
+        span_lint_hir_and_then(
             cx,
             NON_STD_LAZY_STATICS,
+            self.item_hir_id,
             self.ty_span_no_args,
             "this type has been superseded by `LazyLock` in the standard library",
             |diag| {
diff --git a/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.fixed b/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.fixed
index 2b30c8f984ebe..d6c35d8097c51 100644
--- a/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.fixed
+++ b/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.fixed
@@ -70,3 +70,10 @@ mod external_macros {
     once_cell::external!();
     lazy_static::external!();
 }
+
+mod issue14729 {
+    use once_cell::sync::Lazy;
+
+    #[expect(clippy::non_std_lazy_statics)]
+    static LAZY_FOO: Lazy = Lazy::new(|| "foo".to_uppercase());
+}
diff --git a/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs b/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs
index c52338eee83cb..996ef050d6915 100644
--- a/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs
+++ b/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs
@@ -70,3 +70,10 @@ mod external_macros {
     once_cell::external!();
     lazy_static::external!();
 }
+
+mod issue14729 {
+    use once_cell::sync::Lazy;
+
+    #[expect(clippy::non_std_lazy_statics)]
+    static LAZY_FOO: Lazy = Lazy::new(|| "foo".to_uppercase());
+}

From e608520b12b3f6521312287831156e1ba309c5f2 Mon Sep 17 00:00:00 2001
From: Antoni Boucher 
Date: Tue, 6 May 2025 17:58:21 -0400
Subject: [PATCH 2021/4206] Stop ignoring the feature -sse

---
 src/attributes.rs | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/src/attributes.rs b/src/attributes.rs
index 69b04dd579693..8bc1b77024307 100644
--- a/src/attributes.rs
+++ b/src/attributes.rs
@@ -88,14 +88,8 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
     let target_features = function_features
         .iter()
         .filter_map(|feature| {
-            // FIXME(antoyo): for some reasons, disabling SSE results in the following error when
-            // compiling Rust for Linux:
-            // SSE register return with SSE disabled
-            // TODO(antoyo): support soft-float and retpoline-external-thunk.
-            if feature.contains("soft-float")
-                || feature.contains("retpoline-external-thunk")
-                || *feature == "-sse"
-            {
+            // TODO(antoyo): support soft-float.
+            if feature.contains("soft-float") {
                 return None;
             }
 

From 61a14fcea05f8e9a544a5557b98633f7ace65109 Mon Sep 17 00:00:00 2001
From: Trevor Gross 
Date: Tue, 6 May 2025 20:11:48 +0000
Subject: [PATCH 2022/4206] Require `target_has_atomic = "ptr"` for runtime
 feature detection

The `feature_detect` module is currently being built on all targets, but
the use of `AtomicU32` causes a problem if atomics are not available
(such as with `bpfel-unknown-none`). Gate this module behind
`target_has_atomic = "ptr"`.

The below now completes successfully:

    cargo build -p compiler_builtins --target=bpfel-unknown-none -Z build-std=core

Fixes: https://github.com/rust-lang/compiler-builtins/issues/908
---
 library/compiler-builtins/libm/src/math/arch/x86/detect.rs | 7 +++++--
 library/compiler-builtins/libm/src/math/arch/x86/fma.rs    | 3 ++-
 .../libm/src/math/support/feature_detect.rs                | 5 +++++
 library/compiler-builtins/libm/src/math/support/mod.rs     | 6 +++---
 4 files changed, 15 insertions(+), 6 deletions(-)

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 71c3281dc5509..e6d9b040bfaff 100644
--- a/library/compiler-builtins/libm/src/math/arch/x86/detect.rs
+++ b/library/compiler-builtins/libm/src/math/arch/x86/detect.rs
@@ -1,13 +1,16 @@
+// 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};
 #[cfg(target_arch = "x86_64")]
 use core::arch::x86_64::{__cpuid, __cpuid_count, _xgetbv, CpuidResult};
 
-use crate::support::{Flags, get_or_init_flags_cache};
+use crate::support::feature_detect::{Flags, get_or_init_flags_cache, unique_masks};
 
 /// CPU features that get cached (doesn't correlate to anything on the CPU).
 pub mod cpu_flags {
-    use crate::support::unique_masks;
+    use super::unique_masks;
 
     unique_masks! {
         u32,
diff --git a/library/compiler-builtins/libm/src/math/arch/x86/fma.rs b/library/compiler-builtins/libm/src/math/arch/x86/fma.rs
index eb43f4696d775..43ac187792d84 100644
--- a/library/compiler-builtins/libm/src/math/arch/x86/fma.rs
+++ b/library/compiler-builtins/libm/src/math/arch/x86/fma.rs
@@ -4,7 +4,8 @@ use core::arch::asm;
 
 use super::super::super::generic;
 use super::detect::{cpu_flags, get_cpu_features};
-use crate::support::{Round, select_once};
+use crate::support::Round;
+use crate::support::feature_detect::select_once;
 
 pub fn fma(x: f64, y: f64, z: f64) -> f64 {
     select_once! {
diff --git a/library/compiler-builtins/libm/src/math/support/feature_detect.rs b/library/compiler-builtins/libm/src/math/support/feature_detect.rs
index cb669b07332dd..9ebd434a5f857 100644
--- a/library/compiler-builtins/libm/src/math/support/feature_detect.rs
+++ b/library/compiler-builtins/libm/src/math/support/feature_detect.rs
@@ -1,5 +1,9 @@
 //! Helpers for runtime target feature detection that are shared across architectures.
 
+// `AtomicU32` is preferred for a consistent size across targets.
+#[cfg(all(target_has_atomic = "ptr", not(target_has_atomic = "32")))]
+compile_error!("currently all targets that support `AtomicPtr` also support `AtomicU32`");
+
 use core::sync::atomic::{AtomicU32, Ordering};
 
 /// Given a list of identifiers, assign each one a unique sequential single-bit mask.
@@ -72,6 +76,7 @@ macro_rules! select_once {
     }}
 }
 
+#[allow(unused_imports)]
 pub(crate) use {select_once, unique_masks};
 
 use crate::support::cold_path;
diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs
index 727b9a360e23b..a4f596ab8442f 100644
--- a/library/compiler-builtins/libm/src/math/support/mod.rs
+++ b/library/compiler-builtins/libm/src/math/support/mod.rs
@@ -2,7 +2,9 @@
 pub mod macros;
 mod big;
 mod env;
-mod feature_detect;
+// Runtime feature detection requires atomics.
+#[cfg(target_has_atomic = "ptr")]
+pub(crate) mod feature_detect;
 mod float_traits;
 pub mod hex_float;
 mod int_traits;
@@ -11,8 +13,6 @@ mod int_traits;
 pub use big::{i256, u256};
 pub use env::{FpResult, Round, Status};
 #[allow(unused_imports)]
-pub(crate) use feature_detect::{Flags, get_or_init_flags_cache, select_once, unique_masks};
-#[allow(unused_imports)]
 pub use float_traits::{DFloat, Float, HFloat, IntTy};
 pub(crate) use float_traits::{f32_from_bits, f64_from_bits};
 #[cfg(f16_enabled)]

From 0d63b9979941305447f49bd1dcd2bd007e7e426e Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Tue, 6 May 2025 21:59:33 +0000
Subject: [PATCH 2023/4206] chore: release

---
 library/compiler-builtins/compiler-builtins/CHANGELOG.md | 6 ++++++
 library/compiler-builtins/compiler-builtins/Cargo.toml   | 2 +-
 library/compiler-builtins/libm/CHANGELOG.md              | 6 ++++++
 library/compiler-builtins/libm/Cargo.toml                | 2 +-
 4 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/library/compiler-builtins/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/compiler-builtins/CHANGELOG.md
index f152c2c2c8c4b..f0af37ba0b238 100644
--- a/library/compiler-builtins/compiler-builtins/CHANGELOG.md
+++ b/library/compiler-builtins/compiler-builtins/CHANGELOG.md
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Unreleased]
 
+## [0.1.158](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.157...compiler_builtins-v0.1.158) - 2025-05-06
+
+### Other
+
+- Require `target_has_atomic = "ptr"` for runtime feature detection
+
 ## [0.1.157](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.156...compiler_builtins-v0.1.157) - 2025-05-03
 
 ### Other
diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml
index d9eebcfc8a1dc..81f708c48e646 100644
--- a/library/compiler-builtins/compiler-builtins/Cargo.toml
+++ b/library/compiler-builtins/compiler-builtins/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 authors = ["Jorge Aparicio "]
 name = "compiler_builtins"
-version = "0.1.157"
+version = "0.1.158"
 license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)"
 readme = "README.md"
 repository = "https://github.com/rust-lang/compiler-builtins"
diff --git a/library/compiler-builtins/libm/CHANGELOG.md b/library/compiler-builtins/libm/CHANGELOG.md
index a0217af09e2e1..33fec06aa2379 100644
--- a/library/compiler-builtins/libm/CHANGELOG.md
+++ b/library/compiler-builtins/libm/CHANGELOG.md
@@ -8,6 +8,12 @@ and this project adheres to
 
 ## [Unreleased]
 
+## [0.2.15](https://github.com/rust-lang/compiler-builtins/compare/libm-v0.2.14...libm-v0.2.15) - 2025-05-06
+
+### Other
+
+- Require `target_has_atomic = "ptr"` for runtime feature detection
+
 ## [0.2.14](https://github.com/rust-lang/compiler-builtins/compare/libm-v0.2.13...libm-v0.2.14) - 2025-05-03
 
 ### Other
diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml
index 76c9a73bc6ee0..b6fb5efcf76e5 100644
--- a/library/compiler-builtins/libm/Cargo.toml
+++ b/library/compiler-builtins/libm/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT"
 name = "libm"
 readme = "README.md"
 repository = "https://github.com/rust-lang/compiler-builtins"
-version = "0.2.14"
+version = "0.2.15"
 edition = "2021"
 rust-version = "1.63"
 

From 1768cb17317a038f812d1159f2e002b92c3fbb2c Mon Sep 17 00:00:00 2001
From: Trevor Gross 
Date: Tue, 6 May 2025 23:00:46 +0000
Subject: [PATCH 2024/4206] release-plz: Include the libm changelog in
 compiler-builtins

---
 library/compiler-builtins/.release-plz.toml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/library/compiler-builtins/.release-plz.toml b/library/compiler-builtins/.release-plz.toml
index 95e91a46c8d43..8023ade9bfd2f 100644
--- a/library/compiler-builtins/.release-plz.toml
+++ b/library/compiler-builtins/.release-plz.toml
@@ -7,6 +7,7 @@ publish_allow_dirty = true
 [[package]]
 name = "compiler_builtins"
 semver_check = false
+changelog_include = ["libm"] # libm is included as part of builtins
 
 [[package]]
 name = "libm"

From a25c195101fe9ef75f0f6cc0092ca2e8054efea3 Mon Sep 17 00:00:00 2001
From: Jason Newcomb 
Date: Mon, 28 Apr 2025 08:53:11 -0400
Subject: [PATCH 2025/4206] Remove redundant work in `trait_ref_of_method`.

---
 clippy_lints/src/extra_unused_type_parameters.rs | 2 +-
 clippy_lints/src/functions/must_use.rs           | 2 +-
 clippy_lints/src/functions/result.rs             | 2 +-
 clippy_lints/src/inherent_to_string.rs           | 2 +-
 clippy_lints/src/lifetimes.rs                    | 2 +-
 clippy_lints/src/missing_const_for_fn.rs         | 4 ++--
 clippy_lints/src/mut_key.rs                      | 2 +-
 clippy_lints/src/operators/assign_op_pattern.rs  | 2 +-
 clippy_lints/src/suspicious_trait_impl.rs        | 2 +-
 clippy_utils/src/lib.rs                          | 8 ++------
 10 files changed, 12 insertions(+), 16 deletions(-)

diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs
index 6a217b6182ce7..c0b0fd88d9e16 100644
--- a/clippy_lints/src/extra_unused_type_parameters.rs
+++ b/clippy_lints/src/extra_unused_type_parameters.rs
@@ -273,7 +273,7 @@ impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
         // Only lint on inherent methods, not trait methods.
         if let ImplItemKind::Fn(.., body_id) = item.kind
             && !item.generics.params.is_empty()
-            && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
+            && trait_ref_of_method(cx, item.owner_id).is_none()
             && !is_empty_body(cx, body_id)
             && (!self.avoid_breaking_exported_api || !cx.effective_visibilities.is_exported(item.owner_id.def_id))
             && !item.span.in_external_macro(cx.sess().source_map())
diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs
index c3e0d5e8b694d..70655838b6af0 100644
--- a/clippy_lints/src/functions/must_use.rs
+++ b/clippy_lints/src/functions/must_use.rs
@@ -55,7 +55,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
         let attr = cx.tcx.get_attr(item.owner_id, sym::must_use);
         if let Some(attr) = attr {
             check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig);
-        } else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id.def_id).is_none() {
+        } else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id).is_none() {
             check_must_use_candidate(
                 cx,
                 sig.decl,
diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs
index 07a92a4ed70c6..00ce4cfcc5266 100644
--- a/clippy_lints/src/functions/result.rs
+++ b/clippy_lints/src/functions/result.rs
@@ -55,7 +55,7 @@ pub(super) fn check_impl_item<'tcx>(
     // Don't lint if method is a trait's implementation, we can't do anything about those
     if let hir::ImplItemKind::Fn(ref sig, _) = item.kind
         && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.owner_id.def_id, item.span)
-        && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
+        && trait_ref_of_method(cx, item.owner_id).is_none()
     {
         if cx.effective_visibilities.is_exported(item.owner_id.def_id) {
             let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs
index 1d582fb0223e1..7f2e25367a6a4 100644
--- a/clippy_lints/src/inherent_to_string.rs
+++ b/clippy_lints/src/inherent_to_string.rs
@@ -106,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
             // Check if return type is String
             && is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String)
             // Filters instances of to_string which are required by a trait
-            && trait_ref_of_method(cx, impl_item.owner_id.def_id).is_none()
+            && trait_ref_of_method(cx, impl_item.owner_id).is_none()
         {
             show_lint(cx, impl_item);
         }
diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs
index 5ef5e3a44f85f..525a8659bdaf0 100644
--- a/clippy_lints/src/lifetimes.rs
+++ b/clippy_lints/src/lifetimes.rs
@@ -159,7 +159,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
         if let ImplItemKind::Fn(ref sig, id) = item.kind {
-            let report_extra_lifetimes = trait_ref_of_method(cx, item.owner_id.def_id).is_none();
+            let report_extra_lifetimes = trait_ref_of_method(cx, item.owner_id).is_none();
             check_fn_inner(
                 cx,
                 sig,
diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs
index 1f142bc3ba63c..a053c35f211ff 100644
--- a/clippy_lints/src/missing_const_for_fn.rs
+++ b/clippy_lints/src/missing_const_for_fn.rs
@@ -7,7 +7,7 @@ use rustc_abi::ExternAbi;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{self as hir, Body, Constness, FnDecl, GenericParamKind};
+use rustc_hir::{self as hir, Body, Constness, FnDecl, GenericParamKind, OwnerId};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
@@ -125,7 +125,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
                 }
             },
             FnKind::Method(_, sig, ..) => {
-                if already_const(sig.header) || trait_ref_of_method(cx, def_id).is_some() {
+                if already_const(sig.header) || trait_ref_of_method(cx, OwnerId { def_id }).is_some() {
                     return;
                 }
             },
diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs
index a45031ce22b91..98a9a98d281af 100644
--- a/clippy_lints/src/mut_key.rs
+++ b/clippy_lints/src/mut_key.rs
@@ -83,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType<'tcx> {
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'tcx>) {
         if let hir::ImplItemKind::Fn(ref sig, ..) = item.kind
-            && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
+            && trait_ref_of_method(cx, item.owner_id).is_none()
         {
             self.check_sig(cx, item.owner_id.def_id, sig.decl);
         }
diff --git a/clippy_lints/src/operators/assign_op_pattern.rs b/clippy_lints/src/operators/assign_op_pattern.rs
index 03b907ebdf4d8..4be42267b14b3 100644
--- a/clippy_lints/src/operators/assign_op_pattern.rs
+++ b/clippy_lints/src/operators/assign_op_pattern.rs
@@ -26,7 +26,7 @@ pub(super) fn check<'tcx>(
             let rty = cx.typeck_results().expr_ty(rhs);
             if let Some((_, lang_item)) = binop_traits(op.node)
                 && let Some(trait_id) = cx.tcx.lang_items().get(lang_item)
-                && let parent_fn = cx.tcx.hir_get_parent_item(e.hir_id).def_id
+                && let parent_fn = cx.tcx.hir_get_parent_item(e.hir_id)
                 && trait_ref_of_method(cx, parent_fn).is_none_or(|t| t.path.res.def_id() != trait_id)
                 && implements_trait(cx, ty, trait_id, &[rty.into()])
             {
diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs
index 83241f97a99ac..edb7600b7c067 100644
--- a/clippy_lints/src/suspicious_trait_impl.rs
+++ b/clippy_lints/src/suspicious_trait_impl.rs
@@ -80,7 +80,7 @@ fn check_expr_inner<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, bin
             && let hir::Node::ImplItem(impl_item) = cx.tcx.hir_node_by_def_id(parent_fn)
             && let hir::ImplItemKind::Fn(_, body_id) = impl_item.kind
             && let body = cx.tcx.hir_body(body_id)
-            && let parent_fn = cx.tcx.hir_get_parent_item(expr.hir_id).def_id
+            && let parent_fn = cx.tcx.hir_get_parent_item(expr.hir_id)
             && let Some(trait_ref) = trait_ref_of_method(cx, parent_fn)
             && let trait_id = trait_ref.path.res.def_id()
             && ![binop_trait_id, op_assign_trait_id].contains(&trait_id)
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index 0a9c39c41bd81..523ed1c8fe74d 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -523,12 +523,8 @@ pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>
 ///     }
 /// }
 /// ```
-pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, def_id: LocalDefId) -> Option<&'tcx TraitRef<'tcx>> {
-    // Get the implemented trait for the current function
-    let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
-    let parent_impl = cx.tcx.hir_get_parent_item(hir_id);
-    if parent_impl != hir::CRATE_OWNER_ID
-        && let Node::Item(item) = cx.tcx.hir_node_by_def_id(parent_impl.def_id)
+pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, owner: OwnerId) -> Option<&'tcx TraitRef<'tcx>> {
+    if let Node::Item(item) = cx.tcx.hir_node(cx.tcx.hir_owner_parent(owner))
         && let ItemKind::Impl(impl_) = &item.kind
     {
         return impl_.of_trait.as_ref();

From 77157f59887f8711311ff6049d744abea4eb7d0f Mon Sep 17 00:00:00 2001
From: Jason Newcomb 
Date: Mon, 28 Apr 2025 11:22:14 -0400
Subject: [PATCH 2026/4206] Actually check for a problematic line comment in
 `with_leading_whitespace`

---
 clippy_lints/src/cognitive_complexity.rs      |  2 +-
 clippy_lints/src/copies.rs                    |  2 +-
 clippy_lints/src/implicit_hasher.rs           | 13 +--
 clippy_lints/src/methods/manual_inspect.rs    |  2 +-
 clippy_utils/src/source.rs                    | 86 +++++++++++++------
 .../collapsible_if/collapsible_if.fixed       |  4 +-
 .../collapsible_if/collapsible_if.stderr      |  4 +-
 tests/ui/manual_inspect.fixed                 |  2 +-
 tests/ui/manual_inspect.stderr                |  2 +-
 9 files changed, 78 insertions(+), 39 deletions(-)

diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs
index 1d44c7e9c88b0..aeb53a52cf3d5 100644
--- a/clippy_lints/src/cognitive_complexity.rs
+++ b/clippy_lints/src/cognitive_complexity.rs
@@ -104,7 +104,7 @@ impl CognitiveComplexity {
                 FnKind::Closure => {
                     let header_span = body_span.with_hi(decl.output.span().lo());
                     #[expect(clippy::range_plus_one)]
-                    if let Some(range) = header_span.map_range(cx, |src, range| {
+                    if let Some(range) = header_span.map_range(cx, |_, src, range| {
                         let mut idxs = src.get(range.clone())?.match_indices('|');
                         Some(range.start + idxs.next()?.0..range.start + idxs.next()?.0 + 1)
                     }) {
diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs
index 42fbe6438d4ea..4a609c27f3f7d 100644
--- a/clippy_lints/src/copies.rs
+++ b/clippy_lints/src/copies.rs
@@ -258,7 +258,7 @@ fn lint_branches_sharing_code<'tcx>(
         let span = span.with_hi(last_block.span.hi());
         // Improve formatting if the inner block has indentation (i.e. normal Rust formatting)
         let span = span
-            .map_range(cx, |src, range| {
+            .map_range(cx, |_, src, range| {
                 (range.start > 4 && src.get(range.start - 4..range.start)? == "    ")
                     .then_some(range.start - 4..range.end)
             })
diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs
index 4c17834c3adf9..cab7a9fb70990 100644
--- a/clippy_lints/src/implicit_hasher.rs
+++ b/clippy_lints/src/implicit_hasher.rs
@@ -119,7 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
                     }
 
                     let generics_suggestion_span = impl_.generics.span.substitute_dummy({
-                        let range = (item.span.lo()..target.span().lo()).map_range(cx, |src, range| {
+                        let range = (item.span.lo()..target.span().lo()).map_range(cx, |_, src, range| {
                             Some(src.get(range.clone())?.find("impl")? + 4..range.end)
                         });
                         if let Some(range) = range {
@@ -165,11 +165,12 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
                             continue;
                         }
                         let generics_suggestion_span = generics.span.substitute_dummy({
-                            let range = (item.span.lo()..body.params[0].pat.span.lo()).map_range(cx, |src, range| {
-                                let (pre, post) = src.get(range.clone())?.split_once("fn")?;
-                                let pos = post.find('(')? + pre.len() + 2;
-                                Some(pos..pos)
-                            });
+                            let range =
+                                (item.span.lo()..body.params[0].pat.span.lo()).map_range(cx, |_, src, range| {
+                                    let (pre, post) = src.get(range.clone())?.split_once("fn")?;
+                                    let pos = post.find('(')? + pre.len() + 2;
+                                    Some(pos..pos)
+                                });
                             if let Some(range) = range {
                                 range.with_ctxt(item.span.ctxt())
                             } else {
diff --git a/clippy_lints/src/methods/manual_inspect.rs b/clippy_lints/src/methods/manual_inspect.rs
index 173ebcb7020b7..c47879442fc9f 100644
--- a/clippy_lints/src/methods/manual_inspect.rs
+++ b/clippy_lints/src/methods/manual_inspect.rs
@@ -101,7 +101,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
                 UseKind::Return(s) => edits.push((s.with_leading_whitespace(cx).with_ctxt(s.ctxt()), String::new())),
                 UseKind::Borrowed(s) => {
                     #[expect(clippy::range_plus_one)]
-                    let range = s.map_range(cx, |src, range| {
+                    let range = s.map_range(cx, |_, src, range| {
                         let src = src.get(range.clone())?;
                         let trimmed = src.trim_start_matches([' ', '\t', '\n', '\r', '(']);
                         trimmed.starts_with('&').then(|| {
diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs
index 8645d5730fedb..7f2bf99daff20 100644
--- a/clippy_utils/src/source.rs
+++ b/clippy_utils/src/source.rs
@@ -7,13 +7,14 @@ use std::sync::Arc;
 use rustc_ast::{LitKind, StrStyle};
 use rustc_errors::Applicability;
 use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource};
+use rustc_lexer::{LiteralKind, TokenKind, tokenize};
 use rustc_lint::{EarlyContext, LateContext};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::source_map::{SourceMap, original_sp};
 use rustc_span::{
-    BytePos, DUMMY_SP, FileNameDisplayPreference, Pos, SourceFile, SourceFileAndLine, Span, SpanData, SyntaxContext,
-    hygiene,
+    BytePos, DUMMY_SP, FileNameDisplayPreference, Pos, RelativeBytePos, SourceFile, SourceFileAndLine, Span, SpanData,
+    SyntaxContext, hygiene,
 };
 use std::borrow::Cow;
 use std::fmt;
@@ -137,25 +138,25 @@ pub trait SpanRangeExt: SpanRange {
     fn map_range(
         self,
         cx: &impl HasSession,
-        f: impl for<'a> FnOnce(&'a str, Range) -> Option>,
+        f: impl for<'a> FnOnce(&'a SourceFile, &'a str, Range) -> Option>,
     ) -> Option> {
         map_range(cx.sess().source_map(), self.into_range(), f)
     }
 
     #[allow(rustdoc::invalid_rust_codeblocks, reason = "The codeblock is intentionally broken")]
-    /// Extends the range to include all preceding whitespace characters, unless there
-    /// are non-whitespace characters left on the same line after `self`.
+    /// Extends the range to include all preceding whitespace characters.
+    ///
+    /// The range will not be expanded if it would cross a line boundary, the line the range would
+    /// be extended to ends with a line comment and the text after the range contains a
+    /// non-whitespace character on the same line. e.g.
     ///
-    /// This extra condition prevents a problem when removing the '}' in:
     /// ```ignore
-    ///   ( // There was an opening bracket after the parenthesis, which has been removed
-    ///     // This is a comment
-    ///    })
+    /// ( // Some comment
+    /// foo)
     /// ```
-    /// Removing the whitespaces, including the linefeed, before the '}', would put the
-    /// closing parenthesis at the end of the `// This is a comment` line, which would
-    /// make it part of the comment as well. In this case, it is best to keep the span
-    /// on the '}' alone.
+    ///
+    /// When the range points to `foo`, suggesting to remove the range after it's been extended will
+    /// cause the `)` to be placed inside the line comment as `( // Some comment)`.
     fn with_leading_whitespace(self, cx: &impl HasSession) -> Range {
         with_leading_whitespace(cx.sess().source_map(), self.into_range())
     }
@@ -254,11 +255,11 @@ fn with_source_text_and_range(
 fn map_range(
     sm: &SourceMap,
     sp: Range,
-    f: impl for<'a> FnOnce(&'a str, Range) -> Option>,
+    f: impl for<'a> FnOnce(&'a SourceFile, &'a str, Range) -> Option>,
 ) -> Option> {
     if let Some(src) = get_source_range(sm, sp.clone())
         && let Some(text) = &src.sf.src
-        && let Some(range) = f(text, src.range.clone())
+        && let Some(range) = f(&src.sf, text, src.range.clone())
     {
         debug_assert!(
             range.start <= text.len() && range.end <= text.len(),
@@ -275,20 +276,57 @@ fn map_range(
     }
 }
 
+fn ends_with_line_comment_or_broken(text: &str) -> bool {
+    let Some(last) = tokenize(text).last() else {
+        return false;
+    };
+    match last.kind {
+        // Will give the wrong result on text like `" // "` where the first quote ends a string
+        // started earlier. The only workaround is to lex the whole file which we don't really want
+        // to do.
+        TokenKind::LineComment { .. } | TokenKind::BlockComment { terminated: false, .. } => true,
+        TokenKind::Literal { kind, .. } => matches!(
+            kind,
+            LiteralKind::Byte { terminated: false }
+                | LiteralKind::ByteStr { terminated: false }
+                | LiteralKind::CStr { terminated: false }
+                | LiteralKind::Char { terminated: false }
+                | LiteralKind::RawByteStr { n_hashes: None }
+                | LiteralKind::RawCStr { n_hashes: None }
+                | LiteralKind::RawStr { n_hashes: None }
+        ),
+        _ => false,
+    }
+}
+
+fn with_leading_whitespace_inner(lines: &[RelativeBytePos], src: &str, range: Range) -> Option {
+    debug_assert!(lines.is_empty() || lines[0].to_u32() == 0);
+
+    let start = src.get(..range.start)?.trim_end();
+    let next_line = lines.partition_point(|&pos| pos.to_usize() <= start.len());
+    if let Some(line_end) = lines.get(next_line)
+        && line_end.to_usize() <= range.start
+        && let prev_start = lines.get(next_line - 1).map_or(0, |&x| x.to_usize())
+        && ends_with_line_comment_or_broken(&start[prev_start..])
+        && let next_line = lines.partition_point(|&pos| pos.to_usize() < range.end)
+        && let next_start = lines.get(next_line).map_or(src.len(), |&x| x.to_usize())
+        && tokenize(src.get(range.end..next_start)?).any(|t| !matches!(t.kind, TokenKind::Whitespace))
+    {
+        Some(range.start)
+    } else {
+        Some(start.len())
+    }
+}
+
 fn with_leading_whitespace(sm: &SourceMap, sp: Range) -> Range {
-    map_range(sm, sp, |src, range| {
-        let non_blank_after = src.len() - src.get(range.end..)?.trim_start().len();
-        if src.get(range.end..non_blank_after)?.contains(['\r', '\n']) {
-            Some(src.get(..range.start)?.trim_end().len()..range.end)
-        } else {
-            Some(range)
-        }
+    map_range(sm, sp.clone(), |sf, src, range| {
+        Some(with_leading_whitespace_inner(sf.lines(), src, range.clone())?..range.end)
     })
-    .unwrap()
+    .unwrap_or(sp)
 }
 
 fn trim_start(sm: &SourceMap, sp: Range) -> Range {
-    map_range(sm, sp.clone(), |src, range| {
+    map_range(sm, sp.clone(), |_, src, range| {
         let src = src.get(range.clone())?;
         Some(range.start + (src.len() - src.trim_start().len())..range.end)
     })
diff --git a/tests/ui-toml/collapsible_if/collapsible_if.fixed b/tests/ui-toml/collapsible_if/collapsible_if.fixed
index 6f5cc47ba6c75..f695f9804d59c 100644
--- a/tests/ui-toml/collapsible_if/collapsible_if.fixed
+++ b/tests/ui-toml/collapsible_if/collapsible_if.fixed
@@ -13,7 +13,7 @@ fn main() {
     //~^^^^^^ collapsible_if
 
     // The following tests check for the fix of https://github.com/rust-lang/rust-clippy/issues/798
-    if x == "hello"  // Inner comment
+    if x == "hello" // Inner comment
         && y == "world" {
             println!("Hello world!");
         }
@@ -26,7 +26,7 @@ fn main() {
         }
     //~^^^^^^ collapsible_if
 
-    if x == "hello"  /* Inner comment */
+    if x == "hello" /* Inner comment */
         && y == "world" {
             println!("Hello world!");
         }
diff --git a/tests/ui-toml/collapsible_if/collapsible_if.stderr b/tests/ui-toml/collapsible_if/collapsible_if.stderr
index 357ce4ad32deb..a12c2112f5877 100644
--- a/tests/ui-toml/collapsible_if/collapsible_if.stderr
+++ b/tests/ui-toml/collapsible_if/collapsible_if.stderr
@@ -32,7 +32,7 @@ LL | |     }
    |
 help: collapse nested if block
    |
-LL ~     if x == "hello"  // Inner comment
+LL ~     if x == "hello" // Inner comment
 LL ~         && y == "world" {
 LL |             println!("Hello world!");
 LL ~         }
@@ -70,7 +70,7 @@ LL | |     }
    |
 help: collapse nested if block
    |
-LL ~     if x == "hello"  /* Inner comment */
+LL ~     if x == "hello" /* Inner comment */
 LL ~         && y == "world" {
 LL |             println!("Hello world!");
 LL ~         }
diff --git a/tests/ui/manual_inspect.fixed b/tests/ui/manual_inspect.fixed
index ec87fe217aee6..9b768dbad700c 100644
--- a/tests/ui/manual_inspect.fixed
+++ b/tests/ui/manual_inspect.fixed
@@ -107,7 +107,7 @@ fn main() {
             let _ = || {
                 let _x = x;
             };
-            return ;
+            return;
         }
         println!("test");
     });
diff --git a/tests/ui/manual_inspect.stderr b/tests/ui/manual_inspect.stderr
index eb98f9f5995a3..78b085fdfca30 100644
--- a/tests/ui/manual_inspect.stderr
+++ b/tests/ui/manual_inspect.stderr
@@ -98,7 +98,7 @@ LL |         if x.is_empty() {
 LL |             let _ = || {
 LL ~                 let _x = x;
 LL |             };
-LL ~             return ;
+LL ~             return;
 LL |         }
 LL ~         println!("test");
    |

From 3007433e2c65e289aa02155debf500d836539890 Mon Sep 17 00:00:00 2001
From: dianne 
Date: Wed, 7 May 2025 00:52:58 -0700
Subject: [PATCH 2027/4206] add a type alias for the pattern bindings stack

I'll be modifying it in future commits, so I think it's cleanest to
abstract it out. Possibly a newtype would be ideal, but for now this is
least disruptive.
---
 compiler/rustc_resolve/src/late.rs | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index faee0e7dd5ff9..1da1bfeaf607c 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -111,6 +111,17 @@ enum PatBoundCtx {
     Or,
 }
 
+/// Tracks bindings resolved within a pattern. This serves two purposes:
+///
+/// - This tracks when identifiers are bound multiple times within a pattern. In a product context,
+///   this is an error. In an or-pattern, this lets us reuse the same resolution for each instance.
+///   See `fresh_binding` and `resolve_pattern_inner` for more information.
+///
+/// - The guard expression of a guard pattern may use bindings from within the guard pattern, but
+///   not from elsewhere in the pattern containing it. This allows us to isolate the bindings in the
+///   subpattern to construct the scope for the guard.
+type PatternBindings = SmallVec<[(PatBoundCtx, FxHashSet); 1]>;
+
 /// Does this the item (from the item rib scope) allow generic parameters?
 #[derive(Copy, Clone, Debug)]
 pub(crate) enum HasGenericParams {
@@ -3857,7 +3868,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         &mut self,
         pat: &'ast Pat,
         pat_src: PatternSource,
-        bindings: &mut SmallVec<[(PatBoundCtx, FxHashSet); 1]>,
+        bindings: &mut PatternBindings,
     ) {
         // We walk the pattern before declaring the pattern's inner bindings,
         // so that we avoid resolving a literal expression to a binding defined
@@ -3892,7 +3903,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         &mut self,
         pat: &Pat,
         pat_src: PatternSource,
-        bindings: &mut SmallVec<[(PatBoundCtx, FxHashSet); 1]>,
+        bindings: &mut PatternBindings,
     ) {
         // Visit all direct subpatterns of this pattern.
         pat.walk(&mut |pat| {
@@ -3988,7 +3999,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         ident: Ident,
         pat_id: NodeId,
         pat_src: PatternSource,
-        bindings: &mut SmallVec<[(PatBoundCtx, FxHashSet); 1]>,
+        bindings: &mut PatternBindings,
     ) -> Res {
         // Add the binding to the local ribs, if it doesn't already exist in the bindings map.
         // (We must not add it if it's in the bindings map because that breaks the assumptions

From 999db5cdc66f017e4219c56536e7f7f32c6d10e7 Mon Sep 17 00:00:00 2001
From: Samuel Tardieu 
Date: Wed, 9 Apr 2025 12:37:44 +0200
Subject: [PATCH 2028/4206] `unwrap_used`, `expect_used`: accept macro result
 as receiver

---
 clippy_lints/src/methods/mod.rs    | 98 +++++++++++++++++-------------
 tests/ui/unwrap_expect_used.rs     | 17 ++++++
 tests/ui/unwrap_expect_used.stderr | 34 ++++++++++-
 3 files changed, 105 insertions(+), 44 deletions(-)

diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index 7e2ce157c737b..6c55c27989c76 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -4661,6 +4661,8 @@ impl_lint_pass!(Methods => [
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
+/// This ensures that neither the receiver nor any of the arguments
+/// come from expansion.
 pub fn method_call<'tcx>(
     recv: &'tcx Expr<'tcx>,
 ) -> Option<(&'tcx str, &'tcx Expr<'tcx>, &'tcx [Expr<'tcx>], Span, Span)> {
@@ -4858,6 +4860,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
 impl Methods {
     #[allow(clippy::too_many_lines)]
     fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // Handle method calls whose receiver and arguments may not come from expansion
         if let Some((name, recv, args, span, call_span)) = method_call(expr) {
             match (name, args) {
                 ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
@@ -5000,29 +5003,12 @@ impl Methods {
                         Some(("err", recv, [], err_span, _)) => {
                             err_expect::check(cx, expr, recv, span, err_span, self.msrv);
                         },
-                        _ => unwrap_expect_used::check(
-                            cx,
-                            expr,
-                            recv,
-                            false,
-                            self.allow_expect_in_consts,
-                            self.allow_expect_in_tests,
-                            unwrap_expect_used::Variant::Expect,
-                        ),
+                        _ => {},
                     }
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                 },
-                ("expect_err", [_]) => {
+                ("expect_err", [_]) | ("unwrap_err" | "unwrap_unchecked" | "unwrap_err_unchecked", []) => {
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
-                    unwrap_expect_used::check(
-                        cx,
-                        expr,
-                        recv,
-                        true,
-                        self.allow_expect_in_consts,
-                        self.allow_expect_in_tests,
-                        unwrap_expect_used::Variant::Expect,
-                    );
                 },
                 ("extend", [arg]) => {
                     string_extend_chars::check(cx, expr, recv, arg);
@@ -5388,27 +5374,6 @@ impl Methods {
                         _ => {},
                     }
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
-                    unwrap_expect_used::check(
-                        cx,
-                        expr,
-                        recv,
-                        false,
-                        self.allow_unwrap_in_consts,
-                        self.allow_unwrap_in_tests,
-                        unwrap_expect_used::Variant::Unwrap,
-                    );
-                },
-                ("unwrap_err", []) => {
-                    unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
-                    unwrap_expect_used::check(
-                        cx,
-                        expr,
-                        recv,
-                        true,
-                        self.allow_unwrap_in_consts,
-                        self.allow_unwrap_in_tests,
-                        unwrap_expect_used::Variant::Unwrap,
-                    );
                 },
                 ("unwrap_or", [u_arg]) => {
                     match method_call(recv) {
@@ -5437,9 +5402,6 @@ impl Methods {
                     }
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                 },
-                ("unwrap_unchecked" | "unwrap_err_unchecked", []) => {
-                    unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
-                },
                 ("unwrap_or_else", [u_arg]) => {
                     match method_call(recv) {
                         Some(("map", recv, [map_arg], _, _))
@@ -5477,6 +5439,56 @@ impl Methods {
                 _ => {},
             }
         }
+        // Handle method calls whose receiver and arguments may come from expansion
+        if let ExprKind::MethodCall(path, recv, args, _call_span) = expr.kind {
+            match (path.ident.name.as_str(), args) {
+                ("expect", [_]) if !matches!(method_call(recv), Some(("ok" | "err", _, [], _, _))) => {
+                    unwrap_expect_used::check(
+                        cx,
+                        expr,
+                        recv,
+                        false,
+                        self.allow_expect_in_consts,
+                        self.allow_expect_in_tests,
+                        unwrap_expect_used::Variant::Expect,
+                    );
+                },
+                ("expect_err", [_]) => {
+                    unwrap_expect_used::check(
+                        cx,
+                        expr,
+                        recv,
+                        true,
+                        self.allow_expect_in_consts,
+                        self.allow_expect_in_tests,
+                        unwrap_expect_used::Variant::Expect,
+                    );
+                },
+                ("unwrap", []) => {
+                    unwrap_expect_used::check(
+                        cx,
+                        expr,
+                        recv,
+                        false,
+                        self.allow_unwrap_in_consts,
+                        self.allow_unwrap_in_tests,
+                        unwrap_expect_used::Variant::Unwrap,
+                    );
+                },
+                ("unwrap_err", []) => {
+                    unwrap_expect_used::check(
+                        cx,
+                        expr,
+                        recv,
+                        true,
+                        self.allow_unwrap_in_consts,
+                        self.allow_unwrap_in_tests,
+                        unwrap_expect_used::Variant::Unwrap,
+                    );
+                },
+                _ => {},
+            }
+        }
     }
 }
 
diff --git a/tests/ui/unwrap_expect_used.rs b/tests/ui/unwrap_expect_used.rs
index d0bb571273b5a..b429f3a8a0bb9 100644
--- a/tests/ui/unwrap_expect_used.rs
+++ b/tests/ui/unwrap_expect_used.rs
@@ -66,3 +66,20 @@ fn main() {
         SOME.expect("Still not three?");
     }
 }
+
+mod with_expansion {
+    macro_rules! open {
+        ($file:expr) => {
+            std::fs::File::open($file)
+        };
+    }
+
+    fn test(file: &str) {
+        use std::io::Read;
+        let mut s = String::new();
+        let _ = open!(file).unwrap(); //~ unwrap_used
+        let _ = open!(file).expect("can open"); //~ expect_used
+        let _ = open!(file).unwrap_err(); //~ unwrap_used
+        let _ = open!(file).expect_err("can open"); //~ expect_used
+    }
+}
diff --git a/tests/ui/unwrap_expect_used.stderr b/tests/ui/unwrap_expect_used.stderr
index 79eac3f58ccb2..6fd1b84d81231 100644
--- a/tests/ui/unwrap_expect_used.stderr
+++ b/tests/ui/unwrap_expect_used.stderr
@@ -50,5 +50,37 @@ LL |     a.expect_err("Hello error!");
    |
    = note: if this value is an `Ok`, it will panic
 
-error: aborting due to 6 previous errors
+error: used `unwrap()` on a `Result` value
+  --> tests/ui/unwrap_expect_used.rs:80:17
+   |
+LL |         let _ = open!(file).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: if this value is an `Err`, it will panic
+
+error: used `expect()` on a `Result` value
+  --> tests/ui/unwrap_expect_used.rs:81:17
+   |
+LL |         let _ = open!(file).expect("can open");
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: if this value is an `Err`, it will panic
+
+error: used `unwrap_err()` on a `Result` value
+  --> tests/ui/unwrap_expect_used.rs:82:17
+   |
+LL |         let _ = open!(file).unwrap_err();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: if this value is an `Ok`, it will panic
+
+error: used `expect_err()` on a `Result` value
+  --> tests/ui/unwrap_expect_used.rs:83:17
+   |
+LL |         let _ = open!(file).expect_err("can open");
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: if this value is an `Ok`, it will panic
+
+error: aborting due to 10 previous errors
 

From 0d5df707f51891b28f62e9264f02e45739731bde Mon Sep 17 00:00:00 2001
From: Ralf Jung 
Date: Wed, 7 May 2025 10:45:25 +0200
Subject: [PATCH 2029/4206] test suite: use CARGO_TARGET_TMPDIR for temporary
 build artifacts

---
 src/tools/miri/tests/ui.rs | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs
index c37cf15d40ab0..a7b889d966c4a 100644
--- a/src/tools/miri/tests/ui.rs
+++ b/src/tools/miri/tests/ui.rs
@@ -44,8 +44,7 @@ pub fn flagsplit(flags: &str) -> Vec {
 fn build_native_lib() -> PathBuf {
     let cc = env::var("CC").unwrap_or_else(|_| "cc".into());
     // Target directory that we can write to.
-    let so_target_dir =
-        Path::new(&env::var_os("CARGO_TARGET_DIR").unwrap()).join("miri-native-lib");
+    let so_target_dir = Path::new(env!("CARGO_TARGET_TMPDIR")).join("miri-native-lib");
     // Create the directory if it does not already exist.
     std::fs::create_dir_all(&so_target_dir)
         .expect("Failed to create directory for shared object file");
@@ -101,7 +100,7 @@ fn miri_config(
     let mut config = Config {
         target: Some(target.to_owned()),
         program,
-        out_dir: PathBuf::from(std::env::var_os("CARGO_TARGET_DIR").unwrap()).join("miri_ui"),
+        out_dir: PathBuf::from(env!("CARGO_TARGET_TMPDIR")).join("miri_ui"),
         threads: std::env::var("MIRI_TEST_THREADS")
             .ok()
             .map(|threads| NonZero::new(threads.parse().unwrap()).unwrap()),

From fe059c1c548752c9022471e68b6d583a8347d085 Mon Sep 17 00:00:00 2001
From: bjorn3 <17426603+bjorn3@users.noreply.github.com>
Date: Fri, 2 May 2025 20:18:04 +0000
Subject: [PATCH 2030/4206] Clif ir comment improvements

---
 src/abi/mod.rs         | 5 ++---
 src/base.rs            | 6 +-----
 src/value_and_place.rs | 8 ++------
 3 files changed, 5 insertions(+), 14 deletions(-)

diff --git a/src/abi/mod.rs b/src/abi/mod.rs
index 39d04c2f2d787..57ac2d18d494d 100644
--- a/src/abi/mod.rs
+++ b/src/abi/mod.rs
@@ -187,11 +187,10 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
         let func_ref = self.module.declare_func_in_func(func_id, &mut self.bcx.func);
         if self.clif_comments.enabled() {
             self.add_comment(func_ref, format!("{:?}", name));
+            let inst = self.bcx.func.layout.last_inst(self.bcx.current_block().unwrap()).unwrap();
+            self.add_comment(inst, format!("lib_call {}", name));
         }
         let call_inst = self.bcx.ins().call(func_ref, args);
-        if self.clif_comments.enabled() {
-            self.add_comment(call_inst, format!("lib_call {}", name));
-        }
         let results = self.bcx.inst_results(call_inst);
         assert!(results.len() <= 2, "{}", results.len());
         results
diff --git a/src/base.rs b/src/base.rs
index b3a96aa909ac0..f46535966f1c8 100644
--- a/src/base.rs
+++ b/src/base.rs
@@ -559,11 +559,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
     }
 }
 
-fn codegen_stmt<'tcx>(
-    fx: &mut FunctionCx<'_, '_, 'tcx>,
-    #[allow(unused_variables)] cur_block: Block,
-    stmt: &Statement<'tcx>,
-) {
+fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: &Statement<'tcx>) {
     let _print_guard = crate::PrintOnPanic(|| format!("stmt {:?}", stmt));
 
     fx.set_debug_loc(stmt.source_info);
diff --git a/src/value_and_place.rs b/src/value_and_place.rs
index 4874a4ad9e0db..1168701f10323 100644
--- a/src/value_and_place.rs
+++ b/src/value_and_place.rs
@@ -592,13 +592,9 @@ impl<'tcx> CPlace<'tcx> {
         assert_eq!(self.layout().size, from.layout().size);
 
         if fx.clif_comments.enabled() {
-            use cranelift_codegen::cursor::{Cursor, CursorPosition};
-            let cur_block = match fx.bcx.cursor().position() {
-                CursorPosition::After(block) => block,
-                _ => unreachable!(),
-            };
+            let inst = fx.bcx.func.layout.last_inst(fx.bcx.current_block().unwrap()).unwrap();
             fx.add_comment(
-                fx.bcx.func.layout.last_inst(cur_block).unwrap(),
+                inst,
                 format!(
                     "{}: {:?}: {:?} <- {:?}: {:?}",
                     method,

From 9196eb3dd1506048dcbbfd8504e26ac2b130940b Mon Sep 17 00:00:00 2001
From: bjorn3 <17426603+bjorn3@users.noreply.github.com>
Date: Wed, 7 May 2025 13:05:47 +0000
Subject: [PATCH 2031/4206] Fix mini_core for panic=unwind

---
 example/mini_core.rs | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/example/mini_core.rs b/example/mini_core.rs
index 6e345b2a6fdf0..832135568f379 100644
--- a/example/mini_core.rs
+++ b/example/mini_core.rs
@@ -521,10 +521,27 @@ fn panic_cannot_unwind() -> ! {
 }
 
 #[lang = "eh_personality"]
-fn eh_personality() -> ! {
+// FIXME personality signature depends on target
+fn eh_personality(
+    _version: i32,
+    _actions: i32,
+    _exception_class: u64,
+    _exception_object: *mut (),
+    _context: *mut (),
+) -> i32 {
     loop {}
 }
 
+#[lang = "panic_in_cleanup"]
+fn panic_in_cleanup() -> ! {
+    loop {}
+}
+
+#[link(name = "gcc_s")]
+extern "C" {
+    fn _Unwind_Resume(exc: *mut ()) -> !;
+}
+
 #[lang = "drop_in_place"]
 #[allow(unconditional_recursion)]
 pub unsafe fn drop_in_place(to_drop: *mut T) {

From ca42f15f96ea966b7eb15e75dbdf0702d352ebcf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20Kr=C3=B6ning?=
 
Date: Wed, 7 May 2025 15:40:02 +0200
Subject: [PATCH 2032/4206] update hermit-abi to 0.5.1

---
 library/Cargo.lock | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/library/Cargo.lock b/library/Cargo.lock
index 5100b4d8176dc..93e9a8b7e8b4a 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -139,9 +139,9 @@ dependencies = [
 
 [[package]]
 name = "hermit-abi"
-version = "0.5.0"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e"
+checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-alloc",

From 30a0ac66dbb15ee8dd3951499b34df48e1d758a0 Mon Sep 17 00:00:00 2001
From: dianne 
Date: Wed, 7 May 2025 02:59:18 -0700
Subject: [PATCH 2033/4206] delay introducing pattern bindings into scope

This splits introduction of bindings into scope
(`apply_pattern_bindings`) apart from manipulation of the pattern's
binding map (`fresh_binding`). By delaying the latter, we can keep
bindings from appearing in-scope in guards.

Since `fresh_binding` is now specifically for manipulating a pattern's
bindings map, this commit also inlines a use of `fresh_binding` that was
only adding to the innermost rib.
---
 compiler/rustc_resolve/src/late.rs | 82 +++++++++++++++++++-----------
 1 file changed, 52 insertions(+), 30 deletions(-)

diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 1da1bfeaf607c..aa211a8f3c292 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -120,7 +120,9 @@ enum PatBoundCtx {
 /// - The guard expression of a guard pattern may use bindings from within the guard pattern, but
 ///   not from elsewhere in the pattern containing it. This allows us to isolate the bindings in the
 ///   subpattern to construct the scope for the guard.
-type PatternBindings = SmallVec<[(PatBoundCtx, FxHashSet); 1]>;
+///
+/// Each identifier must map to at most one distinct [`Res`].
+type PatternBindings = SmallVec<[(PatBoundCtx, FxIndexMap); 1]>;
 
 /// Does this the item (from the item rib scope) allow generic parameters?
 #[derive(Copy, Clone, Debug)]
@@ -2308,7 +2310,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
     fn resolve_fn_params(
         &mut self,
         has_self: bool,
-        inputs: impl Iterator, &'ast Ty)>,
+        inputs: impl Iterator, &'ast Ty)> + Clone,
     ) -> Result, Vec)> {
         enum Elision {
             /// We have not found any candidate.
@@ -2330,15 +2332,20 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         let mut parameter_info = Vec::new();
         let mut all_candidates = Vec::new();
 
+        // Resolve and apply bindings first so diagnostics can see if they're used in types.
         let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
-        for (index, (pat, ty)) in inputs.enumerate() {
-            debug!(?pat, ?ty);
+        for (pat, _) in inputs.clone() {
+            debug!("resolving bindings in pat = {pat:?}");
             self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
                 if let Some(pat) = pat {
                     this.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
                 }
             });
+        }
+        self.apply_pattern_bindings(bindings);
 
+        for (index, (pat, ty)) in inputs.enumerate() {
+            debug!("resolving type for pat = {pat:?}, ty = {ty:?}");
             // Record elision candidates only for this parameter.
             debug_assert_matches!(self.lifetime_elision_candidates, None);
             self.lifetime_elision_candidates = Some(Default::default());
@@ -3626,16 +3633,10 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         self.visit_path(&delegation.path, delegation.id);
         let Some(body) = &delegation.body else { return };
         self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| {
-            // `PatBoundCtx` is not necessary in this context
-            let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
-
             let span = delegation.path.segments.last().unwrap().ident.span;
-            this.fresh_binding(
-                Ident::new(kw::SelfLower, span),
-                delegation.id,
-                PatternSource::FnParam,
-                &mut bindings,
-            );
+            let ident = Ident::new(kw::SelfLower, span.normalize_to_macro_rules());
+            let res = Res::Local(delegation.id);
+            this.innermost_rib_bindings(ValueNS).insert(ident, res);
             this.visit_block(body);
         });
     }
@@ -3646,6 +3647,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
             for Param { pat, .. } in params {
                 this.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
             }
+            this.apply_pattern_bindings(bindings);
         });
         for Param { ty, .. } in params {
             self.visit_ty(ty);
@@ -3862,8 +3864,27 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
     fn resolve_pattern_top(&mut self, pat: &'ast Pat, pat_src: PatternSource) {
         let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
         self.resolve_pattern(pat, pat_src, &mut bindings);
+        self.apply_pattern_bindings(bindings);
     }
 
+    /// Apply the bindings from a pattern to the innermost rib of the current scope.
+    fn apply_pattern_bindings(&mut self, mut pat_bindings: PatternBindings) {
+        let rib_bindings = self.innermost_rib_bindings(ValueNS);
+        let Some((_, pat_bindings)) = pat_bindings.pop() else {
+            bug!("tried applying nonexistent bindings from pattern");
+        };
+
+        if rib_bindings.is_empty() {
+            // Often, such as for match arms, the bindings are introduced into a new rib.
+            // In this case, we can move the bindings over directly.
+            *rib_bindings = pat_bindings;
+        } else {
+            rib_bindings.extend(pat_bindings);
+        }
+    }
+
+    /// Resolve bindings in a pattern. `apply_pattern_bindings` must be called after to introduce
+    /// the bindings into scope.
     fn resolve_pattern(
         &mut self,
         pat: &'ast Pat,
@@ -4001,18 +4022,15 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         pat_src: PatternSource,
         bindings: &mut PatternBindings,
     ) -> Res {
-        // Add the binding to the local ribs, if it doesn't already exist in the bindings map.
+        // Add the binding to the bindings map, if it doesn't already exist.
         // (We must not add it if it's in the bindings map because that breaks the assumptions
         // later passes make about or-patterns.)
         let ident = ident.normalize_to_macro_rules();
 
-        let mut bound_iter = bindings.iter().filter(|(_, set)| set.contains(&ident));
         // Already bound in a product pattern? e.g. `(a, a)` which is not allowed.
-        let already_bound_and = bound_iter.clone().any(|(ctx, _)| *ctx == PatBoundCtx::Product);
-        // Already bound in an or-pattern? e.g. `V1(a) | V2(a)`.
-        // This is *required* for consistency which is checked later.
-        let already_bound_or = bound_iter.any(|(ctx, _)| *ctx == PatBoundCtx::Or);
-
+        let already_bound_and = bindings
+            .iter()
+            .any(|(ctx, map)| *ctx == PatBoundCtx::Product && map.contains_key(&ident));
         if already_bound_and {
             // Overlap in a product pattern somewhere; report an error.
             use ResolutionError::*;
@@ -4025,19 +4043,23 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
             self.report_error(ident.span, error(ident));
         }
 
-        // Record as bound.
-        bindings.last_mut().unwrap().1.insert(ident);
-
-        if already_bound_or {
+        // Already bound in an or-pattern? e.g. `V1(a) | V2(a)`.
+        // This is *required* for consistency which is checked later.
+        let already_bound_or = bindings
+            .iter()
+            .find_map(|(ctx, map)| if *ctx == PatBoundCtx::Or { map.get(&ident) } else { None });
+        let res = if let Some(&res) = already_bound_or {
             // `Variant1(a) | Variant2(a)`, ok
             // Reuse definition from the first `a`.
-            self.innermost_rib_bindings(ValueNS)[&ident]
-        } else {
-            // A completely fresh binding is added to the set.
-            let res = Res::Local(pat_id);
-            self.innermost_rib_bindings(ValueNS).insert(ident, res);
             res
-        }
+        } else {
+            // A completely fresh binding is added to the map.
+            Res::Local(pat_id)
+        };
+
+        // Record as bound.
+        bindings.last_mut().unwrap().1.insert(ident, res);
+        res
     }
 
     fn innermost_rib_bindings(&mut self, ns: Namespace) -> &mut FxIndexMap {

From 5aac7083985bbb4e595edcdfdbc63f65b4543297 Mon Sep 17 00:00:00 2001
From: Alex Macleod 
Date: Wed, 7 May 2025 13:52:11 +0000
Subject: [PATCH 2034/4206] Replace `Symbol::as_str` usage in `match`
 expressions

---
 clippy_lints/src/attrs/useless_attribute.rs   |  40 +++---
 clippy_lints/src/bool_assert_comparison.rs    |   9 +-
 clippy_lints/src/floating_point_arithmetic.rs |  12 +-
 clippy_lints/src/manual_ignore_case_cmp.rs    |   9 +-
 clippy_lints/src/manual_option_as_slice.rs    |  12 +-
 ...se_sensitive_file_extension_comparisons.rs |   5 +-
 .../src/methods/manual_c_str_literals.rs      |  16 +--
 clippy_lints/src/methods/needless_collect.rs  |  10 +-
 clippy_lints/src/mutable_debug_assertion.rs   |  11 +-
 clippy_lints/src/operators/eq_op.rs           |  15 +--
 clippy_lints/src/panic_in_result_fn.rs        |  11 +-
 clippy_lints/src/panic_unimplemented.rs       |   8 +-
 clippy_lints/src/returns.rs                   |   8 +-
 clippy_lints/src/strings.rs                   |   2 +-
 clippy_lints/src/unit_types/unit_cmp.rs       |  17 ++-
 clippy_lints/src/unused_io_amount.rs          |   2 +-
 clippy_lints/src/write.rs                     |   6 +-
 clippy_lints_internal/src/symbols.rs          | 119 ++++++++++++------
 clippy_utils/src/sym.rs                       |  35 ++++++
 tests/ui-internal/interning_literals.stderr   |  15 ++-
 .../interning_literals_unfixable.stderr       |   9 +-
 tests/ui-internal/symbol_as_str.fixed         |   7 ++
 tests/ui-internal/symbol_as_str.rs            |   7 ++
 tests/ui-internal/symbol_as_str.stderr        |  35 ++++--
 .../symbol_as_str_unfixable.stderr            |   9 +-
 25 files changed, 281 insertions(+), 148 deletions(-)

diff --git a/clippy_lints/src/attrs/useless_attribute.rs b/clippy_lints/src/attrs/useless_attribute.rs
index d75b73280e632..4059f9603c33c 100644
--- a/clippy_lints/src/attrs/useless_attribute.rs
+++ b/clippy_lints/src/attrs/useless_attribute.rs
@@ -26,16 +26,16 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) {
 
                         if namespace.is_none()
                             && matches!(
-                                name.as_str(),
-                                "ambiguous_glob_reexports"
-                                    | "dead_code"
-                                    | "deprecated"
-                                    | "hidden_glob_reexports"
-                                    | "unreachable_pub"
-                                    | "unused"
-                                    | "unused_braces"
-                                    | "unused_import_braces"
-                                    | "unused_imports"
+                                name,
+                                sym::ambiguous_glob_reexports
+                                    | sym::dead_code
+                                    | sym::deprecated
+                                    | sym::hidden_glob_reexports
+                                    | sym::unreachable_pub
+                                    | sym::unused
+                                    | sym::unused_braces
+                                    | sym::unused_import_braces
+                                    | sym::unused_imports
                             )
                         {
                             return;
@@ -43,16 +43,16 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) {
 
                         if namespace == Some(sym::clippy)
                             && matches!(
-                                name.as_str(),
-                                "wildcard_imports"
-                                    | "enum_glob_use"
-                                    | "redundant_pub_crate"
-                                    | "macro_use_imports"
-                                    | "unsafe_removed_from_name"
-                                    | "module_name_repetitions"
-                                    | "single_component_path_imports"
-                                    | "disallowed_types"
-                                    | "unused_trait_names"
+                                name,
+                                sym::wildcard_imports
+                                    | sym::enum_glob_use
+                                    | sym::redundant_pub_crate
+                                    | sym::macro_use_imports
+                                    | sym::unsafe_removed_from_name
+                                    | sym::module_name_repetitions
+                                    | sym::single_component_path_imports
+                                    | sym::disallowed_types
+                                    | sym::unused_trait_names
                             )
                         {
                             return;
diff --git a/clippy_lints/src/bool_assert_comparison.rs b/clippy_lints/src/bool_assert_comparison.rs
index 4a876b854165e..ae36bb76117d7 100644
--- a/clippy_lints/src/bool_assert_comparison.rs
+++ b/clippy_lints/src/bool_assert_comparison.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node};
 use clippy_utils::sugg::Sugg;
+use clippy_utils::sym;
 use clippy_utils::ty::{implements_trait, is_copy};
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
@@ -73,10 +74,9 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
         let Some(macro_call) = root_macro_call_first_node(cx, expr) else {
             return;
         };
-        let macro_name = cx.tcx.item_name(macro_call.def_id);
-        let eq_macro = match macro_name.as_str() {
-            "assert_eq" | "debug_assert_eq" => true,
-            "assert_ne" | "debug_assert_ne" => false,
+        let eq_macro = match cx.tcx.get_diagnostic_name(macro_call.def_id) {
+            Some(sym::assert_eq_macro | sym::debug_assert_eq_macro) => true,
+            Some(sym::assert_ne_macro | sym::debug_assert_ne_macro) => false,
             _ => return,
         };
         let Some((a, b, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else {
@@ -115,6 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
             return;
         }
 
+        let macro_name = cx.tcx.item_name(macro_call.def_id);
         let macro_name = macro_name.as_str();
         let non_eq_mac = ¯o_name[..macro_name.len() - 3];
         span_lint_and_then(
diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs
index 553a00ed868d5..e653a57196d61 100644
--- a/clippy_lints/src/floating_point_arithmetic.rs
+++ b/clippy_lints/src/floating_point_arithmetic.rs
@@ -759,12 +759,12 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
             let recv_ty = cx.typeck_results().expr_ty(receiver);
 
             if recv_ty.is_floating_point() && !is_no_std_crate(cx) && is_inherent_method_call(cx, expr) {
-                match path.ident.name.as_str() {
-                    "ln" => check_ln1p(cx, expr, receiver),
-                    "log" => check_log_base(cx, expr, receiver, args),
-                    "powf" => check_powf(cx, expr, receiver, args),
-                    "powi" => check_powi(cx, expr, receiver, args),
-                    "sqrt" => check_hypot(cx, expr, receiver),
+                match path.ident.name {
+                    sym::ln => check_ln1p(cx, expr, receiver),
+                    sym::log => check_log_base(cx, expr, receiver, args),
+                    sym::powf => check_powf(cx, expr, receiver, args),
+                    sym::powi => check_powi(cx, expr, receiver, args),
+                    sym::sqrt => check_hypot(cx, expr, receiver),
                     _ => {},
                 }
             }
diff --git a/clippy_lints/src/manual_ignore_case_cmp.rs b/clippy_lints/src/manual_ignore_case_cmp.rs
index d92069edb6d00..57c03fbb2ed2b 100644
--- a/clippy_lints/src/manual_ignore_case_cmp.rs
+++ b/clippy_lints/src/manual_ignore_case_cmp.rs
@@ -1,6 +1,7 @@
 use crate::manual_ignore_case_cmp::MatchType::{Literal, ToAscii};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::sym;
 use clippy_utils::ty::{get_type_diagnostic_name, is_type_diagnostic_item, is_type_lang_item};
 use rustc_ast::LitKind;
 use rustc_errors::Applicability;
@@ -10,7 +11,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_middle::ty::{Ty, UintTy};
 use rustc_session::declare_lint_pass;
-use rustc_span::{Span, sym};
+use rustc_span::Span;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -47,9 +48,9 @@ enum MatchType<'a, 'b> {
 
 fn get_ascii_type<'a, 'b>(cx: &LateContext<'a>, kind: rustc_hir::ExprKind<'b>) -> Option<(Span, MatchType<'a, 'b>)> {
     if let MethodCall(path, expr, _, _) = kind {
-        let is_lower = match path.ident.name.as_str() {
-            "to_ascii_lowercase" => true,
-            "to_ascii_uppercase" => false,
+        let is_lower = match path.ident.name {
+            sym::to_ascii_lowercase => true,
+            sym::to_ascii_uppercase => false,
             _ => return None,
         };
         let ty_raw = cx.typeck_results().expr_ty(expr);
diff --git a/clippy_lints/src/manual_option_as_slice.rs b/clippy_lints/src/manual_option_as_slice.rs
index 04e00f841035a..b55c11f2d5b69 100644
--- a/clippy_lints/src/manual_option_as_slice.rs
+++ b/clippy_lints/src/manual_option_as_slice.rs
@@ -80,26 +80,26 @@ impl LateLintPass<'_> for ManualOptionAsSlice {
                     check_map(cx, callee, span, self.msrv);
                 }
             },
-            ExprKind::MethodCall(seg, callee, [or], _) => match seg.ident.name.as_str() {
-                "unwrap_or" => {
+            ExprKind::MethodCall(seg, callee, [or], _) => match seg.ident.name {
+                sym::unwrap_or => {
                     if is_empty_slice(cx, or) {
                         check_map(cx, callee, span, self.msrv);
                     }
                 },
-                "unwrap_or_else" => {
+                sym::unwrap_or_else => {
                     if returns_empty_slice(cx, or) {
                         check_map(cx, callee, span, self.msrv);
                     }
                 },
                 _ => {},
             },
-            ExprKind::MethodCall(seg, callee, [or_else, map], _) => match seg.ident.name.as_str() {
-                "map_or" => {
+            ExprKind::MethodCall(seg, callee, [or_else, map], _) => match seg.ident.name {
+                sym::map_or => {
                     if is_empty_slice(cx, or_else) && is_slice_from_ref(cx, map) {
                         check_as_ref(cx, callee, span, self.msrv);
                     }
                 },
-                "map_or_else" => {
+                sym::map_or_else => {
                     if returns_empty_slice(cx, or_else) && is_slice_from_ref(cx, map) {
                         check_as_ref(cx, callee, span, self.msrv);
                     }
diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
index d07870d4951e0..292fa08b59843 100644
--- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
+++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline};
+use clippy_utils::sym;
 use clippy_utils::ty::is_type_lang_item;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
@@ -21,8 +22,8 @@ pub(super) fn check<'tcx>(
 ) {
     if let ExprKind::MethodCall(path_segment, ..) = recv.kind
         && matches!(
-            path_segment.ident.name.as_str(),
-            "to_lowercase" | "to_uppercase" | "to_ascii_lowercase" | "to_ascii_uppercase"
+            path_segment.ident.name,
+            sym::to_lowercase | sym::to_uppercase | sym::to_ascii_lowercase | sym::to_ascii_uppercase
         )
     {
         return;
diff --git a/clippy_lints/src/methods/manual_c_str_literals.rs b/clippy_lints/src/methods/manual_c_str_literals.rs
index 0274e31b4c338..3fa83cd39d1d2 100644
--- a/clippy_lints/src/methods/manual_c_str_literals.rs
+++ b/clippy_lints/src/methods/manual_c_str_literals.rs
@@ -1,13 +1,13 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::get_parent_expr;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet;
+use clippy_utils::{get_parent_expr, sym};
 use rustc_ast::{LitKind, StrStyle};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Node, QPath, TyKind};
 use rustc_lint::LateContext;
 use rustc_span::edition::Edition::Edition2021;
-use rustc_span::{Span, Symbol, sym};
+use rustc_span::{Span, Symbol};
 
 use super::MANUAL_C_STR_LITERALS;
 
@@ -71,15 +71,15 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, func: &Expr<'_>, args
         && cx.tcx.sess.edition() >= Edition2021
         && msrv.meets(cx, msrvs::C_STR_LITERALS)
     {
-        match fn_name.as_str() {
-            name @ ("from_bytes_with_nul" | "from_bytes_with_nul_unchecked")
+        match fn_name {
+            sym::from_bytes_with_nul | sym::from_bytes_with_nul_unchecked
                 if !arg.span.from_expansion()
                     && let ExprKind::Lit(lit) = arg.kind
                     && let LitKind::ByteStr(_, StrStyle::Cooked) | LitKind::Str(_, StrStyle::Cooked) = lit.node =>
             {
-                check_from_bytes(cx, expr, arg, name);
+                check_from_bytes(cx, expr, arg, fn_name);
             },
-            "from_ptr" => check_from_ptr(cx, expr, arg),
+            sym::from_ptr => check_from_ptr(cx, expr, arg),
             _ => {},
         }
     }
@@ -106,13 +106,13 @@ fn check_from_ptr(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>) {
     }
 }
 /// Checks `CStr::from_bytes_with_nul(b"foo\0")`
-fn check_from_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, method: &str) {
+fn check_from_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, method: Symbol) {
     let (span, applicability) = if let Some(parent) = get_parent_expr(cx, expr)
         && let ExprKind::MethodCall(method, ..) = parent.kind
         && [sym::unwrap, sym::expect].contains(&method.ident.name)
     {
         (parent.span, Applicability::MachineApplicable)
-    } else if method == "from_bytes_with_nul_unchecked" {
+    } else if method == sym::from_bytes_with_nul_unchecked {
         // `*_unchecked` returns `&CStr` directly, nothing needs to be changed
         (expr.span, Applicability::MachineApplicable)
     } else {
diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs
index cd22583b8a253..4c1ed6a1d833e 100644
--- a/clippy_lints/src/methods/needless_collect.rs
+++ b/clippy_lints/src/methods/needless_collect.rs
@@ -357,20 +357,20 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> {
                     if let Some(hir_id) = self.current_statement_hir_id {
                         self.hir_id_uses_map.insert(hir_id, self.uses.len());
                     }
-                    match method_name.ident.name.as_str() {
-                        "into_iter" => self.uses.push(Some(IterFunction {
+                    match method_name.ident.name {
+                        sym::into_iter => self.uses.push(Some(IterFunction {
                             func: IterFunctionKind::IntoIter(expr.hir_id),
                             span: expr.span,
                         })),
-                        "len" => self.uses.push(Some(IterFunction {
+                        sym::len => self.uses.push(Some(IterFunction {
                             func: IterFunctionKind::Len,
                             span: expr.span,
                         })),
-                        "is_empty" => self.uses.push(Some(IterFunction {
+                        sym::is_empty => self.uses.push(Some(IterFunction {
                             func: IterFunctionKind::IsEmpty,
                             span: expr.span,
                         })),
-                        "contains" => self.uses.push(Some(IterFunction {
+                        sym::contains => self.uses.push(Some(IterFunction {
                             func: IterFunctionKind::Contains(args[0].span),
                             span: expr.span,
                         })),
diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs
index d5bed54f0be2f..9b327955608ae 100644
--- a/clippy_lints/src/mutable_debug_assertion.rs
+++ b/clippy_lints/src/mutable_debug_assertion.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node};
+use clippy_utils::sym;
 use rustc_hir::intravisit::{Visitor, walk_expr};
 use rustc_hir::{BorrowKind, Expr, ExprKind, MatchSource, Mutability};
 use rustc_lint::{LateContext, LateLintPass};
@@ -42,10 +43,9 @@ impl<'tcx> LateLintPass<'tcx> for DebugAssertWithMutCall {
         let Some(macro_call) = root_macro_call_first_node(cx, e) else {
             return;
         };
-        let macro_name = cx.tcx.item_name(macro_call.def_id);
         if !matches!(
-            macro_name.as_str(),
-            "debug_assert" | "debug_assert_eq" | "debug_assert_ne"
+            cx.tcx.get_diagnostic_name(macro_call.def_id),
+            Some(sym::debug_assert_macro | sym::debug_assert_eq_macro | sym::debug_assert_ne_macro)
         ) {
             return;
         }
@@ -60,7 +60,10 @@ impl<'tcx> LateLintPass<'tcx> for DebugAssertWithMutCall {
                     cx,
                     DEBUG_ASSERT_WITH_MUT_CALL,
                     span,
-                    format!("do not call a function with mutable arguments inside of `{macro_name}!`"),
+                    format!(
+                        "do not call a function with mutable arguments inside of `{}!`",
+                        cx.tcx.item_name(macro_call.def_id)
+                    ),
                 );
             }
         }
diff --git a/clippy_lints/src/operators/eq_op.rs b/clippy_lints/src/operators/eq_op.rs
index 1421893274f5a..d79101a687df4 100644
--- a/clippy_lints/src/operators/eq_op.rs
+++ b/clippy_lints/src/operators/eq_op.rs
@@ -1,20 +1,18 @@
 use clippy_utils::ast_utils::is_useless_with_eq_exprs;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace};
-use clippy_utils::{eq_expr_value, is_in_test_function};
+use clippy_utils::{eq_expr_value, is_in_test_function, sym};
 use rustc_hir::{BinOpKind, Expr};
 use rustc_lint::LateContext;
 
 use super::EQ_OP;
 
 pub(crate) fn check_assert<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-    if let Some((macro_call, macro_name)) = first_node_macro_backtrace(cx, e).find_map(|macro_call| {
-        let name = cx.tcx.item_name(macro_call.def_id);
+    if let Some(macro_call) = first_node_macro_backtrace(cx, e).find(|macro_call| {
         matches!(
-            name.as_str(),
-            "assert_eq" | "assert_ne" | "debug_assert_eq" | "debug_assert_ne"
+            cx.tcx.get_diagnostic_name(macro_call.def_id),
+            Some(sym::assert_eq_macro | sym::assert_ne_macro | sym::debug_assert_eq_macro | sym::debug_assert_ne_macro)
         )
-        .then(|| (macro_call, name))
     }) && let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn)
         && eq_expr_value(cx, lhs, rhs)
         && macro_call.is_local()
@@ -24,7 +22,10 @@ pub(crate) fn check_assert<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
             cx,
             EQ_OP,
             lhs.span.to(rhs.span),
-            format!("identical args used in this `{macro_name}!` macro call"),
+            format!(
+                "identical args used in this `{}!` macro call",
+                cx.tcx.item_name(macro_call.def_id)
+            ),
         );
     }
 }
diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs
index eebc62e2a5a96..ee1d59490ce9f 100644
--- a/clippy_lints/src/panic_in_result_fn.rs
+++ b/clippy_lints/src/panic_in_result_fn.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::macros::root_macro_call_first_node;
+use clippy_utils::macros::{is_panic, root_macro_call_first_node};
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::{Descend, for_each_expr};
 use clippy_utils::{is_inside_always_const_context, return_ty};
@@ -69,10 +69,11 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir
             return ControlFlow::Continue(Descend::Yes);
         };
         if !is_inside_always_const_context(cx.tcx, e.hir_id)
-            && matches!(
-                cx.tcx.item_name(macro_call.def_id).as_str(),
-                "panic" | "assert" | "assert_eq" | "assert_ne"
-            )
+            && (is_panic(cx, macro_call.def_id)
+                || matches!(
+                    cx.tcx.get_diagnostic_name(macro_call.def_id),
+                    Some(sym::assert_macro | sym::assert_eq_macro | sym::assert_ne_macro)
+                ))
         {
             panics.push(macro_call.span);
             ControlFlow::Continue(Descend::No)
diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs
index 39ae9967e0166..8962f36db1e69 100644
--- a/clippy_lints/src/panic_unimplemented.rs
+++ b/clippy_lints/src/panic_unimplemented.rs
@@ -113,8 +113,8 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented {
                 );
                 return;
             }
-            match cx.tcx.item_name(macro_call.def_id).as_str() {
-                "todo" => {
+            match cx.tcx.get_diagnostic_name(macro_call.def_id) {
+                Some(sym::todo_macro) => {
                     span_lint(
                         cx,
                         TODO,
@@ -122,7 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented {
                         "`todo` should not be present in production code",
                     );
                 },
-                "unimplemented" => {
+                Some(sym::unimplemented_macro) => {
                     span_lint(
                         cx,
                         UNIMPLEMENTED,
@@ -130,7 +130,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented {
                         "`unimplemented` should not be present in production code",
                     );
                 },
-                "unreachable" => {
+                Some(sym::unreachable_macro) => {
                     span_lint(cx, UNREACHABLE, macro_call.span, "usage of the `unreachable!` macro");
                 },
                 _ => {},
diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs
index d8e8ead291288..122d97fdf8193 100644
--- a/clippy_lints/src/returns.rs
+++ b/clippy_lints/src/returns.rs
@@ -5,7 +5,7 @@ use clippy_utils::visitors::for_each_expr;
 use clippy_utils::{
     binary_expr_needs_parentheses, fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor,
     leaks_droppable_temporary_with_limited_lifetime, path_res, path_to_local_id, span_contains_cfg,
-    span_find_starting_semi,
+    span_find_starting_semi, sym,
 };
 use core::ops::ControlFlow;
 use rustc_ast::MetaItemInner;
@@ -22,7 +22,7 @@ use rustc_middle::ty::{self, GenericArgKind, Ty};
 use rustc_session::declare_lint_pass;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::edition::Edition;
-use rustc_span::{BytePos, Pos, Span, sym};
+use rustc_span::{BytePos, Pos, Span};
 use std::borrow::Cow;
 use std::fmt::Display;
 
@@ -411,8 +411,8 @@ fn check_final_expr<'tcx>(
                         && let [tool, lint_name] = meta_item.path.segments.as_slice()
                         && tool.ident.name == sym::clippy
                         && matches!(
-                            lint_name.ident.name.as_str(),
-                            "needless_return" | "style" | "all" | "warnings"
+                            lint_name.ident.name,
+                            sym::needless_return | sym::style | sym::all | sym::warnings
                         )
                     {
                         // This is an expectation of the `needless_return` lint
diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs
index af4d0d541f176..73a9fe71e0018 100644
--- a/clippy_lints/src/strings.rs
+++ b/clippy_lints/src/strings.rs
@@ -334,7 +334,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
         if let ExprKind::MethodCall(path, recv, [], _) = &e.kind
             && path.ident.name == sym::into_bytes
             && let ExprKind::MethodCall(path, recv, [], _) = &recv.kind
-            && matches!(path.ident.name.as_str(), "to_owned" | "to_string")
+            && matches!(path.ident.name, sym::to_owned | sym::to_string)
             && let ExprKind::Lit(lit) = &recv.kind
             && let LitKind::Str(lit_content, _) = &lit.node
             && lit_content.as_str().is_ascii()
diff --git a/clippy_lints/src/unit_types/unit_cmp.rs b/clippy_lints/src/unit_types/unit_cmp.rs
index 6dcc1195a7051..48b532968cb57 100644
--- a/clippy_lints/src/unit_types/unit_cmp.rs
+++ b/clippy_lints/src/unit_types/unit_cmp.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node};
+use clippy_utils::sym;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::LateContext;
 
@@ -7,11 +8,12 @@ use super::UNIT_CMP;
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if expr.span.from_expansion() {
-        if let Some(macro_call) = root_macro_call_first_node(cx, expr) {
-            let macro_name = cx.tcx.item_name(macro_call.def_id);
-            let result = match macro_name.as_str() {
-                "assert_eq" | "debug_assert_eq" => "succeed",
-                "assert_ne" | "debug_assert_ne" => "fail",
+        if let Some(macro_call) = root_macro_call_first_node(cx, expr)
+            && let Some(diag_name) = cx.tcx.get_diagnostic_name(macro_call.def_id)
+        {
+            let result = match diag_name {
+                sym::assert_eq_macro | sym::debug_assert_eq_macro => "succeed",
+                sym::assert_ne_macro | sym::debug_assert_ne_macro => "fail",
                 _ => return,
             };
             let Some((left, _, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else {
@@ -24,7 +26,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
                 cx,
                 UNIT_CMP,
                 macro_call.span,
-                format!("`{macro_name}` of unit values detected. This will always {result}"),
+                format!(
+                    "`{}` of unit values detected. This will always {result}",
+                    cx.tcx.item_name(macro_call.def_id)
+                ),
             );
         }
         return;
diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs
index e3f28908ff830..5e1cb9e54f57a 100644
--- a/clippy_lints/src/unused_io_amount.rs
+++ b/clippy_lints/src/unused_io_amount.rs
@@ -226,7 +226,7 @@ fn is_unreachable_or_panic(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
     if is_panic(cx, macro_call.def_id) {
         return !cx.tcx.hir_is_inside_const_context(expr.hir_id);
     }
-    matches!(cx.tcx.item_name(macro_call.def_id).as_str(), "unreachable")
+    cx.tcx.is_diagnostic_item(sym::unreachable_macro, macro_call.def_id)
 }
 
 fn unpack_call_chain<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs
index f24c127c4521d..a8758b65c9192 100644
--- a/clippy_lints/src/write.rs
+++ b/clippy_lints/src/write.rs
@@ -498,9 +498,9 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
                     None => return,
                 },
                 LitKind::Char => (
-                    match lit.symbol.as_str() {
-                        "\"" => "\\\"",
-                        "\\'" => "'",
+                    match lit.symbol {
+                        sym::DOUBLE_QUOTE => "\\\"",
+                        sym::BACKSLASH_SINGLE_QUOTE => "'",
                         _ => match value_string.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) {
                             Some(stripped) => stripped,
                             None => return,
diff --git a/clippy_lints_internal/src/symbols.rs b/clippy_lints_internal/src/symbols.rs
index bf166988a0c7f..5aee545fb0f5b 100644
--- a/clippy_lints_internal/src/symbols.rs
+++ b/clippy_lints_internal/src/symbols.rs
@@ -4,7 +4,7 @@ use rustc_ast::LitKind;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{Expr, ExprKind};
+use rustc_hir::{Expr, ExprKind, Lit, Node, Pat, PatExprKind, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_lint_defs::declare_tool_lint;
 use rustc_middle::mir::ConstValue;
@@ -65,6 +65,39 @@ pub struct Symbols {
 
 impl_lint_pass!(Symbols => [INTERNING_LITERALS, SYMBOL_AS_STR]);
 
+impl Symbols {
+    fn lit_suggestion(&self, lit: &Lit) -> Option<(Span, String)> {
+        if let LitKind::Str(name, _) = lit.node {
+            let sugg = if let Some((prefix, name)) = self.symbol_map.get(&name.as_u32()) {
+                format!("{prefix}::{name}")
+            } else {
+                format!("sym::{}", name.as_str().replace(|ch: char| !ch.is_alphanumeric(), "_"))
+            };
+            Some((lit.span, sugg))
+        } else {
+            None
+        }
+    }
+
+    fn expr_suggestion(&self, expr: &Expr<'_>) -> Option<(Span, String)> {
+        if let ExprKind::Lit(lit) = expr.kind {
+            self.lit_suggestion(lit)
+        } else {
+            None
+        }
+    }
+
+    fn pat_suggestions(&self, pat: &Pat<'_>, suggestions: &mut Vec<(Span, String)>) {
+        pat.walk_always(|pat| {
+            if let PatKind::Expr(pat_expr) = pat.kind
+                && let PatExprKind::Lit { lit, .. } = pat_expr.kind
+            {
+                suggestions.extend(self.lit_suggestion(lit));
+            }
+        });
+    }
+}
+
 impl<'tcx> LateLintPass<'tcx> for Symbols {
     fn check_crate(&mut self, cx: &LateContext<'_>) {
         let modules = [
@@ -75,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for Symbols {
         for (prefix, module) in modules {
             for def_id in module.get(cx) {
                 // When linting `clippy_utils` itself we can't use `module_children` as it's a local def id. It will
-                // still lint but the suggestion will say to add it to `sym.rs` even if it's already there
+                // still lint but the suggestion may suggest the incorrect name for symbols such as `sym::CRLF`
                 if def_id.is_local() {
                     continue;
                 }
@@ -98,8 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for Symbols {
         if let ExprKind::Call(func, [arg]) = &expr.kind
             && let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind()
             && cx.tcx.is_diagnostic_item(sym::SymbolIntern, *def_id)
-            && let ExprKind::Lit(lit) = arg.kind
-            && let LitKind::Str(name, _) = lit.node
+            && let Some((_, sugg)) = self.expr_suggestion(arg)
         {
             span_lint_and_then(
                 cx,
@@ -107,48 +139,55 @@ impl<'tcx> LateLintPass<'tcx> for Symbols {
                 expr.span,
                 "interning a string literal",
                 |diag| {
-                    let (message, path) = suggestion(&mut self.symbol_map, name);
-                    diag.span_suggestion_verbose(expr.span, message, path, Applicability::MaybeIncorrect);
+                    diag.span_suggestion_verbose(
+                        expr.span,
+                        "use a preinterned symbol instead",
+                        sugg,
+                        Applicability::MaybeIncorrect,
+                    );
+                    diag.help("add the symbol to `clippy_utils/src/sym.rs` if needed");
                 },
             );
         }
 
-        if let ExprKind::Binary(_, lhs, rhs) = expr.kind {
-            check_binary(cx, lhs, rhs, &mut self.symbol_map);
-            check_binary(cx, rhs, lhs, &mut self.symbol_map);
-        }
-    }
-}
+        if let Some(as_str) = as_str_span(cx, expr)
+            && let Node::Expr(parent) = cx.tcx.parent_hir_node(expr.hir_id)
+        {
+            let mut suggestions = Vec::new();
 
-fn check_binary(
-    cx: &LateContext<'_>,
-    lhs: &Expr<'_>,
-    rhs: &Expr<'_>,
-    symbols: &mut FxHashMap,
-) {
-    if let Some(removal_span) = as_str_span(cx, lhs)
-        && let ExprKind::Lit(lit) = rhs.kind
-        && let LitKind::Str(name, _) = lit.node
-    {
-        span_lint_and_then(cx, SYMBOL_AS_STR, lhs.span, "converting a Symbol to a string", |diag| {
-            let (message, path) = suggestion(symbols, name);
-            diag.multipart_suggestion_verbose(
-                message,
-                vec![(removal_span, String::new()), (rhs.span, path)],
-                Applicability::MachineApplicable,
-            );
-        });
-    }
-}
+            match parent.kind {
+                ExprKind::Binary(_, lhs, rhs) => {
+                    suggestions.extend(self.expr_suggestion(lhs));
+                    suggestions.extend(self.expr_suggestion(rhs));
+                },
+                ExprKind::Match(_, arms, _) => {
+                    for arm in arms {
+                        self.pat_suggestions(arm.pat, &mut suggestions);
+                    }
+                },
+                _ => {},
+            }
 
-fn suggestion(symbols: &mut FxHashMap, name: Symbol) -> (&'static str, String) {
-    if let Some((prefix, name)) = symbols.get(&name.as_u32()) {
-        ("use the preinterned symbol", format!("{prefix}::{name}"))
-    } else {
-        (
-            "add the symbol to `clippy_utils/src/sym.rs` and use it",
-            format!("sym::{}", name.as_str().replace(|ch: char| !ch.is_alphanumeric(), "_")),
-        )
+            if suggestions.is_empty() {
+                return;
+            }
+
+            span_lint_and_then(
+                cx,
+                SYMBOL_AS_STR,
+                expr.span,
+                "converting a Symbol to a string",
+                |diag| {
+                    suggestions.push((as_str, String::new()));
+                    diag.multipart_suggestion(
+                        "use preinterned symbols instead",
+                        suggestions,
+                        Applicability::MaybeIncorrect,
+                    );
+                    diag.help("add the symbols to `clippy_utils/src/sym.rs` if needed");
+                },
+            );
+        }
     }
 }
 
diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs
index 94b73f37269f1..9428262b99aa7 100644
--- a/clippy_utils/src/sym.rs
+++ b/clippy_utils/src/sym.rs
@@ -32,12 +32,14 @@ macro_rules! generate {
 generate! {
     abs,
     align_of,
+    ambiguous_glob_reexports,
     as_bytes,
     as_deref_mut,
     as_deref,
     as_mut,
     AsyncReadExt,
     AsyncWriteExt,
+    BACKSLASH_SINGLE_QUOTE: r"\'",
     Binary,
     build_hasher,
     bytes,
@@ -59,8 +61,11 @@ generate! {
     de,
     Deserialize,
     diagnostics,
+    disallowed_types,
+    DOUBLE_QUOTE: "\"",
     EarlyLintPass,
     ends_with,
+    enum_glob_use,
     error,
     ErrorKind,
     exp,
@@ -69,12 +74,16 @@ generate! {
     finish,
     flat_map,
     for_each,
+    from_bytes_with_nul_unchecked,
+    from_bytes_with_nul,
+    from_ptr,
     from_raw,
     from_ref,
     from_str_radix,
     fs,
     futures_util,
     get,
+    hidden_glob_reexports,
     hygiene,
     insert,
     int_roundings,
@@ -96,20 +105,27 @@ generate! {
     Lazy,
     LF: "\n",
     Lint,
+    ln,
     lock_api,
+    log,
     LowerExp,
     LowerHex,
+    macro_use_imports,
+    map_or_else,
+    map_or,
     max,
     MAX,
     mem,
     min,
     MIN,
     mode,
+    module_name_repetitions,
     msrv,
     msrvs,
     MsrvStack,
     mut_ptr,
     mutex,
+    needless_return,
     next_tuple,
     Octal,
     once_cell,
@@ -119,7 +135,10 @@ generate! {
     parse,
     PathLookup,
     paths,
+    powf,
+    powi,
     push,
+    redundant_pub_crate,
     regex,
     Regex,
     RegexBuilder,
@@ -137,29 +156,45 @@ generate! {
     set_mode,
     set_readonly,
     signum,
+    single_component_path_imports,
     span_lint_and_then,
     split_whitespace,
     split,
+    sqrt,
     Start,
     Step,
+    style,
     symbol,
     Symbol,
     SyntaxContext,
     take,
     TBD,
     then_some,
+    to_ascii_lowercase,
+    to_ascii_uppercase,
     to_digit,
+    to_lowercase,
     to_owned,
+    to_uppercase,
     tokio,
+    unreachable_pub,
+    unsafe_removed_from_name,
+    unused_braces,
     unused_extern_crates,
+    unused_import_braces,
+    unused_trait_names,
+    unused,
     unwrap_err,
     unwrap_or_default,
+    unwrap_or_else,
     UpperExp,
     UpperHex,
     V4,
     V6,
     Visitor,
+    warnings,
     Weak,
+    wildcard_imports,
     with_capacity,
     wrapping_offset,
 }
diff --git a/tests/ui-internal/interning_literals.stderr b/tests/ui-internal/interning_literals.stderr
index 628b97eff84da..9ff4194e542bb 100644
--- a/tests/ui-internal/interning_literals.stderr
+++ b/tests/ui-internal/interning_literals.stderr
@@ -4,9 +4,10 @@ error: interning a string literal
 LL |     let _ = Symbol::intern("f32");
    |             ^^^^^^^^^^^^^^^^^^^^^
    |
+   = help: add the symbol to `clippy_utils/src/sym.rs` if needed
    = note: `-D clippy::interning-literals` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::interning_literals)]`
-help: use the preinterned symbol
+help: use a preinterned symbol instead
    |
 LL -     let _ = Symbol::intern("f32");
 LL +     let _ = sym::f32;
@@ -18,7 +19,8 @@ error: interning a string literal
 LL |     let _ = Symbol::intern("proc-macro");
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: use the preinterned symbol
+   = help: add the symbol to `clippy_utils/src/sym.rs` if needed
+help: use a preinterned symbol instead
    |
 LL -     let _ = Symbol::intern("proc-macro");
 LL +     let _ = sym::proc_dash_macro;
@@ -30,7 +32,8 @@ error: interning a string literal
 LL |     let _ = Symbol::intern("self");
    |             ^^^^^^^^^^^^^^^^^^^^^^
    |
-help: use the preinterned symbol
+   = help: add the symbol to `clippy_utils/src/sym.rs` if needed
+help: use a preinterned symbol instead
    |
 LL -     let _ = Symbol::intern("self");
 LL +     let _ = kw::SelfLower;
@@ -42,7 +45,8 @@ error: interning a string literal
 LL |     let _ = Symbol::intern("msrv");
    |             ^^^^^^^^^^^^^^^^^^^^^^
    |
-help: use the preinterned symbol
+   = help: add the symbol to `clippy_utils/src/sym.rs` if needed
+help: use a preinterned symbol instead
    |
 LL -     let _ = Symbol::intern("msrv");
 LL +     let _ = sym::msrv;
@@ -54,7 +58,8 @@ error: interning a string literal
 LL |     let _ = Symbol::intern("Cargo.toml");
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: use the preinterned symbol
+   = help: add the symbol to `clippy_utils/src/sym.rs` if needed
+help: use a preinterned symbol instead
    |
 LL -     let _ = Symbol::intern("Cargo.toml");
 LL +     let _ = sym::Cargo_toml;
diff --git a/tests/ui-internal/interning_literals_unfixable.stderr b/tests/ui-internal/interning_literals_unfixable.stderr
index 8294453a8f945..879d9e633c23d 100644
--- a/tests/ui-internal/interning_literals_unfixable.stderr
+++ b/tests/ui-internal/interning_literals_unfixable.stderr
@@ -4,9 +4,10 @@ error: interning a string literal
 LL |     let _ = Symbol::intern("xyz123");
    |             ^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = help: add the symbol to `clippy_utils/src/sym.rs` if needed
    = note: `-D clippy::interning-literals` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::interning_literals)]`
-help: add the symbol to `clippy_utils/src/sym.rs` and use it
+help: use a preinterned symbol instead
    |
 LL -     let _ = Symbol::intern("xyz123");
 LL +     let _ = sym::xyz123;
@@ -18,7 +19,8 @@ error: interning a string literal
 LL |     let _ = Symbol::intern("with-dash");
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: add the symbol to `clippy_utils/src/sym.rs` and use it
+   = help: add the symbol to `clippy_utils/src/sym.rs` if needed
+help: use a preinterned symbol instead
    |
 LL -     let _ = Symbol::intern("with-dash");
 LL +     let _ = sym::with_dash;
@@ -30,7 +32,8 @@ error: interning a string literal
 LL |     let _ = Symbol::intern("with.dot");
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: add the symbol to `clippy_utils/src/sym.rs` and use it
+   = help: add the symbol to `clippy_utils/src/sym.rs` if needed
+help: use a preinterned symbol instead
    |
 LL -     let _ = Symbol::intern("with.dot");
 LL +     let _ = sym::with_dot;
diff --git a/tests/ui-internal/symbol_as_str.fixed b/tests/ui-internal/symbol_as_str.fixed
index 3e26732836ca8..6a71b16c60494 100644
--- a/tests/ui-internal/symbol_as_str.fixed
+++ b/tests/ui-internal/symbol_as_str.fixed
@@ -18,4 +18,11 @@ fn f(s: Symbol) {
     //~^ symbol_as_str
     sym::get == s;
     //~^ symbol_as_str
+
+    let _ = match s {
+        //~^ symbol_as_str
+        sym::unwrap_err => 1,
+        sym::unwrap_or_default | sym::unwrap_or_else => 2,
+        _ => 3,
+    };
 }
diff --git a/tests/ui-internal/symbol_as_str.rs b/tests/ui-internal/symbol_as_str.rs
index 334c32d189837..43136504bf1af 100644
--- a/tests/ui-internal/symbol_as_str.rs
+++ b/tests/ui-internal/symbol_as_str.rs
@@ -18,4 +18,11 @@ fn f(s: Symbol) {
     //~^ symbol_as_str
     "get" == s.as_str();
     //~^ symbol_as_str
+
+    let _ = match s.as_str() {
+        //~^ symbol_as_str
+        "unwrap_err" => 1,
+        "unwrap_or_default" | "unwrap_or_else" => 2,
+        _ => 3,
+    };
 }
diff --git a/tests/ui-internal/symbol_as_str.stderr b/tests/ui-internal/symbol_as_str.stderr
index 39f81f3833c49..3eeead4aa8c14 100644
--- a/tests/ui-internal/symbol_as_str.stderr
+++ b/tests/ui-internal/symbol_as_str.stderr
@@ -4,9 +4,10 @@ error: converting a Symbol to a string
 LL |     s.as_str() == "f32";
    |     ^^^^^^^^^^
    |
+   = help: add the symbols to `clippy_utils/src/sym.rs` if needed
    = note: `-D clippy::symbol-as-str` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::symbol_as_str)]`
-help: use the preinterned symbol
+help: use preinterned symbols instead
    |
 LL -     s.as_str() == "f32";
 LL +     s == sym::f32;
@@ -18,7 +19,8 @@ error: converting a Symbol to a string
 LL |     s.as_str() == "proc-macro";
    |     ^^^^^^^^^^
    |
-help: use the preinterned symbol
+   = help: add the symbols to `clippy_utils/src/sym.rs` if needed
+help: use preinterned symbols instead
    |
 LL -     s.as_str() == "proc-macro";
 LL +     s == sym::proc_dash_macro;
@@ -30,7 +32,8 @@ error: converting a Symbol to a string
 LL |     s.as_str() == "self";
    |     ^^^^^^^^^^
    |
-help: use the preinterned symbol
+   = help: add the symbols to `clippy_utils/src/sym.rs` if needed
+help: use preinterned symbols instead
    |
 LL -     s.as_str() == "self";
 LL +     s == kw::SelfLower;
@@ -42,7 +45,8 @@ error: converting a Symbol to a string
 LL |     s.as_str() == "msrv";
    |     ^^^^^^^^^^
    |
-help: use the preinterned symbol
+   = help: add the symbols to `clippy_utils/src/sym.rs` if needed
+help: use preinterned symbols instead
    |
 LL -     s.as_str() == "msrv";
 LL +     s == sym::msrv;
@@ -54,7 +58,8 @@ error: converting a Symbol to a string
 LL |     s.as_str() == "Cargo.toml";
    |     ^^^^^^^^^^
    |
-help: use the preinterned symbol
+   = help: add the symbols to `clippy_utils/src/sym.rs` if needed
+help: use preinterned symbols instead
    |
 LL -     s.as_str() == "Cargo.toml";
 LL +     s == sym::Cargo_toml;
@@ -66,11 +71,27 @@ error: converting a Symbol to a string
 LL |     "get" == s.as_str();
    |              ^^^^^^^^^^
    |
-help: use the preinterned symbol
+   = help: add the symbols to `clippy_utils/src/sym.rs` if needed
+help: use preinterned symbols instead
    |
 LL -     "get" == s.as_str();
 LL +     sym::get == s;
    |
 
-error: aborting due to 6 previous errors
+error: converting a Symbol to a string
+  --> tests/ui-internal/symbol_as_str.rs:22:19
+   |
+LL |     let _ = match s.as_str() {
+   |                   ^^^^^^^^^^
+   |
+   = help: add the symbols to `clippy_utils/src/sym.rs` if needed
+help: use preinterned symbols instead
+   |
+LL ~     let _ = match s {
+LL |
+LL ~         sym::unwrap_err => 1,
+LL ~         sym::unwrap_or_default | sym::unwrap_or_else => 2,
+   |
+
+error: aborting due to 7 previous errors
 
diff --git a/tests/ui-internal/symbol_as_str_unfixable.stderr b/tests/ui-internal/symbol_as_str_unfixable.stderr
index 5349983ca5196..65664ebb451ae 100644
--- a/tests/ui-internal/symbol_as_str_unfixable.stderr
+++ b/tests/ui-internal/symbol_as_str_unfixable.stderr
@@ -4,9 +4,10 @@ error: converting a Symbol to a string
 LL |     s.as_str() == "xyz123";
    |     ^^^^^^^^^^
    |
+   = help: add the symbols to `clippy_utils/src/sym.rs` if needed
    = note: `-D clippy::symbol-as-str` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::symbol_as_str)]`
-help: add the symbol to `clippy_utils/src/sym.rs` and use it
+help: use preinterned symbols instead
    |
 LL -     s.as_str() == "xyz123";
 LL +     s == sym::xyz123;
@@ -18,7 +19,8 @@ error: converting a Symbol to a string
 LL |     s.as_str() == "with-dash";
    |     ^^^^^^^^^^
    |
-help: add the symbol to `clippy_utils/src/sym.rs` and use it
+   = help: add the symbols to `clippy_utils/src/sym.rs` if needed
+help: use preinterned symbols instead
    |
 LL -     s.as_str() == "with-dash";
 LL +     s == sym::with_dash;
@@ -30,7 +32,8 @@ error: converting a Symbol to a string
 LL |     s.as_str() == "with.dot";
    |     ^^^^^^^^^^
    |
-help: add the symbol to `clippy_utils/src/sym.rs` and use it
+   = help: add the symbols to `clippy_utils/src/sym.rs` if needed
+help: use preinterned symbols instead
    |
 LL -     s.as_str() == "with.dot";
 LL +     s == sym::with_dot;

From 2f8f4643900301caa2984fd97f6c20347ea9936e Mon Sep 17 00:00:00 2001
From: bjorn3 <17426603+bjorn3@users.noreply.github.com>
Date: Wed, 7 May 2025 14:08:11 +0000
Subject: [PATCH 2035/4206] Fix mini_core on Windows and macOS

---
 example/mini_core.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/example/mini_core.rs b/example/mini_core.rs
index 832135568f379..1dc799c0aeea8 100644
--- a/example/mini_core.rs
+++ b/example/mini_core.rs
@@ -537,6 +537,7 @@ fn panic_in_cleanup() -> ! {
     loop {}
 }
 
+#[cfg(all(unix, not(target_vendor = "apple")))]
 #[link(name = "gcc_s")]
 extern "C" {
     fn _Unwind_Resume(exc: *mut ()) -> !;

From 772ea35935c8201abaa8c21387c9eda323d9184f Mon Sep 17 00:00:00 2001
From: Alex Macleod 
Date: Wed, 7 May 2025 14:32:23 +0000
Subject: [PATCH 2036/4206] Fix diagnostic paths printed by dogfood test

---
 tests/dogfood.rs | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/tests/dogfood.rs b/tests/dogfood.rs
index 16a1a415102c4..4ac2bd532851e 100644
--- a/tests/dogfood.rs
+++ b/tests/dogfood.rs
@@ -44,8 +44,8 @@ fn dogfood() {
         "rustc_tools_util",
     ] {
         println!("linting {package}");
-        if !run_clippy_for_package(package, &["-D", "clippy::all", "-D", "clippy::pedantic"]) {
-            failed_packages.push(if package.is_empty() { "root" } else { package });
+        if !run_clippy_for_package(package) {
+            failed_packages.push(package);
         }
     }
 
@@ -57,7 +57,7 @@ fn dogfood() {
 }
 
 #[must_use]
-fn run_clippy_for_package(project: &str, args: &[&str]) -> bool {
+fn run_clippy_for_package(project: &str) -> bool {
     let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
 
     let mut command = Command::new(&*test_utils::CARGO_CLIPPY_PATH);
@@ -79,15 +79,17 @@ fn run_clippy_for_package(project: &str, args: &[&str]) -> bool {
         }
     }
 
-    command.arg("--").args(args);
+    command.arg("--");
     command.arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir
-    command.args(["-D", "clippy::dbg_macro"]);
-
+    command.args(["-D", "clippy::all", "-D", "clippy::pedantic", "-D", "clippy::dbg_macro"]);
     if !cfg!(feature = "internal") {
         // running a clippy built without internal lints on the clippy source
-        // that contains e.g. `allow(clippy::invalid_paths)`
+        // that contains e.g. `allow(clippy::symbol_as_str)`
         command.args(["-A", "unknown_lints"]);
     }
 
+    // Workaround for not being a workspace, add the crate's directory back to the path
+    command.args(["--remap-path-prefix", &format!("={project}")]);
+
     command.status().unwrap().success()
 }

From 3278cb554578fadd03a606b45690cc68a8661cfd Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Wed, 7 May 2025 16:34:32 +0200
Subject: [PATCH 2037/4206] Migrate to 2024 edition

---
 Cargo.toml | 2 +-
 src/lib.rs | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 717eaf9e05807..c692a90f0a4a4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,7 +2,7 @@
 name = "rustc_codegen_gcc"
 version = "0.1.0"
 authors = ["Antoni Boucher "]
-edition = "2018"
+edition = "2024"
 license = "MIT OR Apache-2.0"
 
 [lib]
diff --git a/src/lib.rs b/src/lib.rs
index 555f164e53fd6..9bbf40d4b34a5 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -413,7 +413,7 @@ impl WriteBackendMethods for GccCodegenBackend {
         cgcx: &CodegenContext,
         thin: ThinModule,
     ) -> Result, FatalError> {
-        back::lto::optimize_thin_module(thin, cgcx)
+        unsafe { back::lto::optimize_thin_module(thin, cgcx) }
     }
 
     unsafe fn codegen(
@@ -422,7 +422,7 @@ impl WriteBackendMethods for GccCodegenBackend {
         module: ModuleCodegen,
         config: &ModuleConfig,
     ) -> Result {
-        back::write::codegen(cgcx, dcx, module, config)
+        unsafe { back::write::codegen(cgcx, dcx, module, config) }
     }
 
     fn prepare_thin(
@@ -454,7 +454,7 @@ impl WriteBackendMethods for GccCodegenBackend {
 }
 
 /// This is the entrypoint for a hot plugged rustc_codegen_gccjit
-#[no_mangle]
+#[unsafe(no_mangle)]
 pub fn __rustc_codegen_backend() -> Box {
     #[cfg(feature = "master")]
     let info = {

From 8e9a84011d24e99e3741664143c727f9c8e61964 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Wed, 7 May 2025 16:37:50 +0200
Subject: [PATCH 2038/4206] Migrate build system to 2024 edition

---
 build_system/Cargo.toml   | 2 +-
 build_system/src/main.rs  | 4 +++-
 build_system/src/utils.rs | 2 +-
 3 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/build_system/Cargo.toml b/build_system/Cargo.toml
index d2600ed5a0314..540d82369fdf7 100644
--- a/build_system/Cargo.toml
+++ b/build_system/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "y"
 version = "0.1.0"
-edition = "2021"
+edition = "2024"
 
 [dependencies]
 boml = "0.3.1"
diff --git a/build_system/src/main.rs b/build_system/src/main.rs
index 393617183061b..c70b00e09ae70 100644
--- a/build_system/src/main.rs
+++ b/build_system/src/main.rs
@@ -60,7 +60,9 @@ pub enum Command {
 
 fn main() {
     if env::var("RUST_BACKTRACE").is_err() {
-        env::set_var("RUST_BACKTRACE", "1");
+        unsafe {
+            env::set_var("RUST_BACKTRACE", "1");
+        }
     }
 
     let command = match env::args().nth(1).as_deref() {
diff --git a/build_system/src/utils.rs b/build_system/src/utils.rs
index 401c23948e5d3..ca177a5feb86a 100644
--- a/build_system/src/utils.rs
+++ b/build_system/src/utils.rs
@@ -10,7 +10,7 @@ use std::path::{Path, PathBuf};
 use std::process::{Command, ExitStatus, Output};
 
 #[cfg(unix)]
-extern "C" {
+unsafe extern "C" {
     fn raise(signal: c_int) -> c_int;
 }
 

From dcfd5c30d4bd81b08f893ca245e02359b9210d25 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Wed, 7 May 2025 16:45:18 +0200
Subject: [PATCH 2039/4206] Remove unneeded `let_chains` feature

---
 src/lib.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/lib.rs b/src/lib.rs
index 9bbf40d4b34a5..7ef7d4daf461f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -16,7 +16,7 @@
 #![allow(internal_features)]
 #![doc(rust_logo)]
 #![feature(rustdoc_internals)]
-#![feature(rustc_private, decl_macro, never_type, trusted_len, let_chains)]
+#![feature(rustc_private, decl_macro, never_type, trusted_len)]
 #![allow(broken_intra_doc_links)]
 #![recursion_limit = "256"]
 #![warn(rust_2018_idioms)]

From 7f2f0d2ec13f22eb3057b309d39de134d0fd2848 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Wed, 7 May 2025 16:50:47 +0200
Subject: [PATCH 2040/4206] Update tests to 2024 edition

---
 tests/lang_tests_common.rs | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/tests/lang_tests_common.rs b/tests/lang_tests_common.rs
index d5a0d71c4b298..f0a9e72f2ea2b 100644
--- a/tests/lang_tests_common.rs
+++ b/tests/lang_tests_common.rs
@@ -42,7 +42,9 @@ pub fn main_inner(profile: Profile) {
         .expect("failed to get absolute path of `gcc-path`")
         .display()
         .to_string();
-    env::set_var("LD_LIBRARY_PATH", gcc_path);
+    unsafe {
+        env::set_var("LD_LIBRARY_PATH", gcc_path);
+    }
 
     fn rust_filter(path: &Path) -> bool {
         path.is_file() && path.extension().expect("extension").to_str().expect("to_str") == "rs"

From 8c045221b59adfb5197f2900a82b496efa5d4740 Mon Sep 17 00:00:00 2001
From: Alex Macleod 
Date: Wed, 7 May 2025 15:16:32 +0000
Subject: [PATCH 2041/4206] Make `let_with_type_underscore` help message into a
 suggestion

---
 clippy_lints/src/let_with_type_underscore.rs | 15 +++++--
 tests/ui/let_with_type_underscore.fixed      | 47 ++++++++++++++++++++
 tests/ui/let_with_type_underscore.stderr     | 34 +++++++-------
 3 files changed, 75 insertions(+), 21 deletions(-)
 create mode 100644 tests/ui/let_with_type_underscore.fixed

diff --git a/clippy_lints/src/let_with_type_underscore.rs b/clippy_lints/src/let_with_type_underscore.rs
index 9c8488ff381b3..1917ca24a05bd 100644
--- a/clippy_lints/src/let_with_type_underscore.rs
+++ b/clippy_lints/src/let_with_type_underscore.rs
@@ -1,5 +1,6 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_from_proc_macro;
+use rustc_errors::Applicability;
 use rustc_hir::{LetStmt, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -32,13 +33,19 @@ impl<'tcx> LateLintPass<'tcx> for UnderscoreTyped {
             && !local.span.in_external_macro(cx.tcx.sess.source_map())
             && !is_from_proc_macro(cx, ty)
         {
-            span_lint_and_help(
+            span_lint_and_then(
                 cx,
                 LET_WITH_TYPE_UNDERSCORE,
                 local.span,
                 "variable declared with type underscore",
-                Some(ty.span.with_lo(local.pat.span.hi())),
-                "remove the explicit type `_` declaration",
+                |diag| {
+                    diag.span_suggestion_verbose(
+                        ty.span.with_lo(local.pat.span.hi()),
+                        "remove the explicit type `_` declaration",
+                        "",
+                        Applicability::MachineApplicable,
+                    );
+                },
             );
         }
     }
diff --git a/tests/ui/let_with_type_underscore.fixed b/tests/ui/let_with_type_underscore.fixed
new file mode 100644
index 0000000000000..7a4af4e3d1e7f
--- /dev/null
+++ b/tests/ui/let_with_type_underscore.fixed
@@ -0,0 +1,47 @@
+//@aux-build: proc_macros.rs
+#![allow(unused)]
+#![warn(clippy::let_with_type_underscore)]
+#![allow(clippy::let_unit_value, clippy::needless_late_init)]
+
+extern crate proc_macros;
+
+fn func() -> &'static str {
+    ""
+}
+
+#[rustfmt::skip]
+fn main() {
+    // Will lint
+    let x = 1;
+    //~^ let_with_type_underscore
+    let _ = 2;
+    //~^ let_with_type_underscore
+    let x = func();
+    //~^ let_with_type_underscore
+    let x;
+    //~^ let_with_type_underscore
+    x = ();
+
+    let x = 1; // Will not lint, Rust infers this to an integer before Clippy
+    let x = func();
+    let x: Vec<_> = Vec::::new();
+    let x: [_; 1] = [1];
+    let x = 1;
+    //~^ let_with_type_underscore
+
+    // Do not lint from procedural macros
+    proc_macros::with_span! {
+        span
+        let x: _ = ();
+        // Late initialization
+        let x: _;
+        x = ();
+        // Ensure weird formatting will not break it (hopefully)
+        let x : _ = 1;
+        let x
+: _ = 1;
+        let                   x :              
+        _;
+        x = ();
+    };
+}
diff --git a/tests/ui/let_with_type_underscore.stderr b/tests/ui/let_with_type_underscore.stderr
index 2284d1fe2e48a..9179f99220718 100644
--- a/tests/ui/let_with_type_underscore.stderr
+++ b/tests/ui/let_with_type_underscore.stderr
@@ -4,13 +4,13 @@ error: variable declared with type underscore
 LL |     let x: _ = 1;
    |     ^^^^^^^^^^^^^
    |
-help: remove the explicit type `_` declaration
-  --> tests/ui/let_with_type_underscore.rs:15:10
-   |
-LL |     let x: _ = 1;
-   |          ^^^
    = note: `-D clippy::let-with-type-underscore` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::let_with_type_underscore)]`
+help: remove the explicit type `_` declaration
+   |
+LL -     let x: _ = 1;
+LL +     let x = 1;
+   |
 
 error: variable declared with type underscore
   --> tests/ui/let_with_type_underscore.rs:17:5
@@ -19,10 +19,10 @@ LL |     let _: _ = 2;
    |     ^^^^^^^^^^^^^
    |
 help: remove the explicit type `_` declaration
-  --> tests/ui/let_with_type_underscore.rs:17:10
    |
-LL |     let _: _ = 2;
-   |          ^^^
+LL -     let _: _ = 2;
+LL +     let _ = 2;
+   |
 
 error: variable declared with type underscore
   --> tests/ui/let_with_type_underscore.rs:19:5
@@ -31,10 +31,10 @@ LL |     let x: _ = func();
    |     ^^^^^^^^^^^^^^^^^^
    |
 help: remove the explicit type `_` declaration
-  --> tests/ui/let_with_type_underscore.rs:19:10
    |
-LL |     let x: _ = func();
-   |          ^^^
+LL -     let x: _ = func();
+LL +     let x = func();
+   |
 
 error: variable declared with type underscore
   --> tests/ui/let_with_type_underscore.rs:21:5
@@ -43,10 +43,10 @@ LL |     let x: _;
    |     ^^^^^^^^^
    |
 help: remove the explicit type `_` declaration
-  --> tests/ui/let_with_type_underscore.rs:21:10
    |
-LL |     let x: _;
-   |          ^^^
+LL -     let x: _;
+LL +     let x;
+   |
 
 error: variable declared with type underscore
   --> tests/ui/let_with_type_underscore.rs:29:5
@@ -55,10 +55,10 @@ LL |     let x : _ = 1;
    |     ^^^^^^^^^^^^^^
    |
 help: remove the explicit type `_` declaration
-  --> tests/ui/let_with_type_underscore.rs:29:10
    |
-LL |     let x : _ = 1;
-   |          ^^^^
+LL -     let x : _ = 1;
+LL +     let x = 1;
+   |
 
 error: aborting due to 5 previous errors
 

From 0bdf0726cf77c95937aea1df408c9b18fe33f010 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Wed, 7 May 2025 17:20:25 +0200
Subject: [PATCH 2042/4206] Mark back::lto::optimize_thin_module` and
 `back::write::codegen` functions as safe

---
 src/back/lto.rs   | 2 +-
 src/back/write.rs | 2 +-
 src/lib.rs        | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/back/lto.rs b/src/back/lto.rs
index e5221c7da3197..62bb58d44fe03 100644
--- a/src/back/lto.rs
+++ b/src/back/lto.rs
@@ -589,7 +589,7 @@ fn thin_lto(
     Ok((opt_jobs, copy_jobs))
 }
 
-pub unsafe fn optimize_thin_module(
+pub fn optimize_thin_module(
     thin_module: ThinModule,
     _cgcx: &CodegenContext,
 ) -> Result, FatalError> {
diff --git a/src/back/write.rs b/src/back/write.rs
index 16c895322e88a..09e955acf3900 100644
--- a/src/back/write.rs
+++ b/src/back/write.rs
@@ -14,7 +14,7 @@ use crate::base::add_pic_option;
 use crate::errors::CopyBitcode;
 use crate::{GccCodegenBackend, GccContext};
 
-pub(crate) unsafe fn codegen(
+pub(crate) fn codegen(
     cgcx: &CodegenContext,
     dcx: DiagCtxtHandle<'_>,
     module: ModuleCodegen,
diff --git a/src/lib.rs b/src/lib.rs
index 7ef7d4daf461f..688487304612d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -413,7 +413,7 @@ impl WriteBackendMethods for GccCodegenBackend {
         cgcx: &CodegenContext,
         thin: ThinModule,
     ) -> Result, FatalError> {
-        unsafe { back::lto::optimize_thin_module(thin, cgcx) }
+        back::lto::optimize_thin_module(thin, cgcx)
     }
 
     unsafe fn codegen(
@@ -422,7 +422,7 @@ impl WriteBackendMethods for GccCodegenBackend {
         module: ModuleCodegen,
         config: &ModuleConfig,
     ) -> Result {
-        unsafe { back::write::codegen(cgcx, dcx, module, config) }
+        back::write::codegen(cgcx, dcx, module, config)
     }
 
     fn prepare_thin(

From 390fc73ae737ef99fa109add85bbf60e53f1a983 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Wed, 7 May 2025 17:32:31 +0200
Subject: [PATCH 2043/4206] Fix new clippy lints

---
 src/consts.rs              | 6 ++----
 src/debuginfo.rs           | 5 ++---
 src/declare.rs             | 1 +
 tests/lang_tests_common.rs | 5 ++---
 4 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/src/consts.rs b/src/consts.rs
index 0a67bd7bc71af..033afc0f8fbf4 100644
--- a/src/consts.rs
+++ b/src/consts.rs
@@ -191,13 +191,11 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
                 // TODO(antoyo): check if it's okay that no link_section is set.
 
                 let typ = self.val_ty(cv).get_aligned(align.bytes());
-                let global = self.declare_private_global(&name[..], typ);
-                global
+                self.declare_private_global(&name[..], typ)
             }
             _ => {
                 let typ = self.val_ty(cv).get_aligned(align.bytes());
-                let global = self.declare_unnamed_global(typ);
-                global
+                self.declare_unnamed_global(typ)
             }
         };
         global.global_set_initializer_rvalue(cv);
diff --git a/src/debuginfo.rs b/src/debuginfo.rs
index f3ced86439527..e0597d0030d57 100644
--- a/src/debuginfo.rs
+++ b/src/debuginfo.rs
@@ -289,7 +289,7 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
     ) -> Self::DILocation {
         let pos = span.lo();
         let DebugLoc { file, line, col } = self.lookup_debug_loc(pos);
-        let loc = match file.name {
+        match file.name {
             rustc_span::FileName::Real(ref name) => match *name {
                 rustc_span::RealFileName::LocalPath(ref name) => {
                     if let Some(name) = name.to_str() {
@@ -314,7 +314,6 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
                 }
             },
             _ => Location::null(),
-        };
-        loc
+        }
     }
 }
diff --git a/src/declare.rs b/src/declare.rs
index c1ca3eb849e88..bed82073e2c41 100644
--- a/src/declare.rs
+++ b/src/declare.rs
@@ -157,6 +157,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
 ///
 /// If there’s a value with the same name already declared, the function will
 /// update the declaration and return existing Value instead.
+#[allow(clippy::let_and_return)]
 fn declare_raw_fn<'gcc>(
     cx: &CodegenCx<'gcc, '_>,
     name: &str,
diff --git a/tests/lang_tests_common.rs b/tests/lang_tests_common.rs
index f0a9e72f2ea2b..bdcf14b4b26d4 100644
--- a/tests/lang_tests_common.rs
+++ b/tests/lang_tests_common.rs
@@ -69,15 +69,14 @@ pub fn main_inner(profile: Profile) {
         .test_dir("tests/run")
         .test_path_filter(filter)
         .test_extract(|path| {
-            let lines = std::fs::read_to_string(path)
+            std::fs::read_to_string(path)
                 .expect("read file")
                 .lines()
                 .skip_while(|l| !l.starts_with("//"))
                 .take_while(|l| l.starts_with("//"))
                 .map(|l| &l[2..])
                 .collect::>()
-                .join("\n");
-            lines
+                .join("\n")
         })
         .test_cmds(move |path| {
             // Test command 1: Compile `x.rs` into `tempdir/x`.

From 303c4ecfdd0c571d80c5bc151243aee1900cebfd Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Wed, 23 Apr 2025 16:03:55 +0000
Subject: [PATCH 2044/4206] Require T: TypeFoldable in Binder visit

---
 clippy_utils/src/ty/mod.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clippy_utils/src/ty/mod.rs b/clippy_utils/src/ty/mod.rs
index 8db9cd593b335..da09edd7f7c03 100644
--- a/clippy_utils/src/ty/mod.rs
+++ b/clippy_utils/src/ty/mod.rs
@@ -20,8 +20,8 @@ use rustc_middle::traits::EvaluationResult;
 use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::{
     self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
-    GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
-    TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
+    GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
+    TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
 };
 use rustc_span::symbol::Ident;
 use rustc_span::{DUMMY_SP, Span, Symbol, sym};
@@ -915,7 +915,7 @@ pub fn for_each_top_level_late_bound_region(
                 ControlFlow::Continue(())
             }
         }
-        fn visit_binder>>(&mut self, t: &Binder<'tcx, T>) -> Self::Result {
+        fn visit_binder>>(&mut self, t: &Binder<'tcx, T>) -> Self::Result {
             self.index += 1;
             let res = t.super_visit_with(self);
             self.index -= 1;

From be405344570f68138ecce86f19f3908d6f481ba9 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Fri, 10 Jan 2025 17:44:47 +0100
Subject: [PATCH 2045/4206] Add `primitive_method_to_numeric_cast` lint

---
 CHANGELOG.md                                  |  1 +
 clippy_lints/src/casts/mod.rs                 | 29 ++++++++++
 .../casts/primitive_method_to_numeric_cast.rs | 57 +++++++++++++++++++
 clippy_lints/src/declared_lints.rs            |  1 +
 4 files changed, 88 insertions(+)
 create mode 100644 clippy_lints/src/casts/primitive_method_to_numeric_cast.rs

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2b62c9a59aa5d..ca2e738979030 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6068,6 +6068,7 @@ Released 2018-09-13
 [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
 [`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence
 [`precedence_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence_bits
+[`primitive_method_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#primitive_method_to_numeric_cast
 [`print_in_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_in_format_impl
 [`print_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_literal
 [`print_stderr`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_stderr
diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs
index 76931fce209e5..7c8fa0b4d9211 100644
--- a/clippy_lints/src/casts/mod.rs
+++ b/clippy_lints/src/casts/mod.rs
@@ -18,6 +18,7 @@ mod fn_to_numeric_cast;
 mod fn_to_numeric_cast_any;
 mod fn_to_numeric_cast_with_truncation;
 mod manual_dangling_ptr;
+mod primitive_method_to_numeric_cast;
 mod ptr_as_ptr;
 mod ptr_cast_constness;
 mod ref_as_ptr;
@@ -786,6 +787,32 @@ declare_clippy_lint! {
     "casting small constant literals to pointers to create dangling pointers"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for casts of a primitive method pointer to any integer type.
+    ///
+    /// ### Why restrict this?
+    /// Casting a function pointer to an integer can have surprising results and can occur
+    /// accidentally if parentheses are omitted from a function call. If you aren't doing anything
+    /// low-level with function pointers then you can opt out of casting functions to integers in
+    /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function
+    /// pointer casts in your code.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let _ = u16::max as usize;
+    /// ```
+    ///
+    /// Use instead:
+    /// ```no_run
+    /// let _ = u16::MAX as usize;
+    /// ```
+    #[clippy::version = "1.86.0"]
+    pub PRIMITIVE_METHOD_TO_NUMERIC_CAST,
+    suspicious,
+    "casting a primitive method pointer to any integer type"
+}
+
 pub struct Casts {
     msrv: Msrv,
 }
@@ -823,6 +850,7 @@ impl_lint_pass!(Casts => [
     REF_AS_PTR,
     AS_POINTER_UNDERSCORE,
     MANUAL_DANGLING_PTR,
+    PRIMITIVE_METHOD_TO_NUMERIC_CAST,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Casts {
@@ -847,6 +875,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
             ptr_cast_constness::check(cx, expr, cast_from_expr, cast_from, cast_to, self.msrv);
             as_ptr_cast_mut::check(cx, expr, cast_from_expr, cast_to);
             fn_to_numeric_cast_any::check(cx, expr, cast_from_expr, cast_from, cast_to);
+            primitive_method_to_numeric_cast::check(cx, expr, cast_from_expr, cast_from, cast_to);
             fn_to_numeric_cast::check(cx, expr, cast_from_expr, cast_from, cast_to);
             fn_to_numeric_cast_with_truncation::check(cx, expr, cast_from_expr, cast_from, cast_to);
             zero_ptr::check(cx, expr, cast_from_expr, cast_to_hir);
diff --git a/clippy_lints/src/casts/primitive_method_to_numeric_cast.rs b/clippy_lints/src/casts/primitive_method_to_numeric_cast.rs
new file mode 100644
index 0000000000000..380fa98cd15f1
--- /dev/null
+++ b/clippy_lints/src/casts/primitive_method_to_numeric_cast.rs
@@ -0,0 +1,57 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::match_def_path;
+use clippy_utils::source::snippet_with_applicability;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, Ty};
+
+use super::PRIMITIVE_METHOD_TO_NUMERIC_CAST;
+
+fn get_primitive_ty_name(ty: Ty<'_>) -> Option<&'static str> {
+    match ty.kind() {
+        ty::Char => Some("char"),
+        ty::Int(int) => Some(int.name_str()),
+        ty::Uint(uint) => Some(uint.name_str()),
+        ty::Float(float) => Some(float.name_str()),
+        _ => None,
+    }
+}
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
+    // We allow casts from any function type to any function type.
+    match cast_to.kind() {
+        ty::FnDef(..) | ty::FnPtr(..) => return,
+        _ => { /* continue to checks */ },
+    }
+
+    if let ty::FnDef(def_id, generics) = cast_from.kind()
+        && let Some(method_name) = cx.tcx.opt_item_name(*def_id)
+        && let method_name = method_name.as_str()
+        && (method_name == "min" || method_name == "max")
+        // We get the type on which the `min`/`max` method of the `Ord` trait is implemented.
+        && let [ty] = generics.as_slice()
+        && let Some(ty) = ty.as_type()
+        // We get its name in case it's a primitive with an associated MIN/MAX constant.
+        && let Some(ty_name) = get_primitive_ty_name(ty)
+        && match_def_path(cx, *def_id, &["core", "cmp", "Ord", method_name])
+    {
+        let mut applicability = Applicability::MaybeIncorrect;
+        let from_snippet = snippet_with_applicability(cx, cast_expr.span, "..", &mut applicability);
+
+        span_lint_and_then(
+            cx,
+            PRIMITIVE_METHOD_TO_NUMERIC_CAST,
+            expr.span,
+            format!("casting function pointer `{from_snippet}` to `{cast_to}`"),
+            |diag| {
+                diag.span_suggestion_verbose(
+                    expr.span,
+                    "did you mean to use the associated constant?",
+                    format!("{ty_name}::{} as {cast_to}", method_name.to_ascii_uppercase()),
+                    applicability,
+                );
+            },
+        );
+    }
+}
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 2cccd6ba27027..1d4c75dafa317 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -68,6 +68,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::casts::FN_TO_NUMERIC_CAST_ANY_INFO,
     crate::casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION_INFO,
     crate::casts::MANUAL_DANGLING_PTR_INFO,
+    crate::casts::PRIMITIVE_METHOD_TO_NUMERIC_CAST_INFO,
     crate::casts::PTR_AS_PTR_INFO,
     crate::casts::PTR_CAST_CONSTNESS_INFO,
     crate::casts::REF_AS_PTR_INFO,

From c680419425b736f238fa0142f43c400b3ec26d27 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Fri, 10 Jan 2025 17:44:58 +0100
Subject: [PATCH 2046/4206] Add UI test for `primitive_method_to_numeric_cast`

---
 tests/ui/primitive_method_to_numeric_cast.fixed  |  5 +++++
 tests/ui/primitive_method_to_numeric_cast.rs     |  5 +++++
 tests/ui/primitive_method_to_numeric_cast.stderr | 15 +++++++++++++++
 3 files changed, 25 insertions(+)
 create mode 100644 tests/ui/primitive_method_to_numeric_cast.fixed
 create mode 100644 tests/ui/primitive_method_to_numeric_cast.rs
 create mode 100644 tests/ui/primitive_method_to_numeric_cast.stderr

diff --git a/tests/ui/primitive_method_to_numeric_cast.fixed b/tests/ui/primitive_method_to_numeric_cast.fixed
new file mode 100644
index 0000000000000..1ebb52618f137
--- /dev/null
+++ b/tests/ui/primitive_method_to_numeric_cast.fixed
@@ -0,0 +1,5 @@
+#![warn(clippy::primitive_method_to_numeric_cast)]
+
+fn main() {
+    let _ = u16::MAX as usize; //~ primitive_method_to_numeric_cast
+}
diff --git a/tests/ui/primitive_method_to_numeric_cast.rs b/tests/ui/primitive_method_to_numeric_cast.rs
new file mode 100644
index 0000000000000..89b0bfa84fee8
--- /dev/null
+++ b/tests/ui/primitive_method_to_numeric_cast.rs
@@ -0,0 +1,5 @@
+#![warn(clippy::primitive_method_to_numeric_cast)]
+
+fn main() {
+    let _ = u16::max as usize; //~ primitive_method_to_numeric_cast
+}
diff --git a/tests/ui/primitive_method_to_numeric_cast.stderr b/tests/ui/primitive_method_to_numeric_cast.stderr
new file mode 100644
index 0000000000000..5515dc646ce71
--- /dev/null
+++ b/tests/ui/primitive_method_to_numeric_cast.stderr
@@ -0,0 +1,15 @@
+error: casting function pointer `u16::max` to `usize`
+  --> tests/ui/primitive_method_to_numeric_cast.rs:4:13
+   |
+LL |     let _ = u16::max as usize;
+   |             ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::primitive-method-to-numeric-cast` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::primitive_method_to_numeric_cast)]`
+help: did you mean to use the associated constant?
+   |
+LL |     let _ = u16::MAX as usize;
+   |             ~~~~~~~~~~~~~~~~~
+
+error: aborting due to 1 previous error
+

From df479588945119d2e356fdfef21a5d2094ce9499 Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Thu, 1 May 2025 16:31:47 +0000
Subject: [PATCH 2047/4206] Remove manual WF hack

---
 .../src/check/compare_impl_item.rs            | 65 +++----------------
 .../issue-88022.rs                            |  6 +-
 .../dropck/explicit-drop-bounds.bad1.stderr   | 18 ++++-
 .../dropck/explicit-drop-bounds.bad2.stderr   | 22 ++++++-
 tests/ui/dropck/explicit-drop-bounds.rs       |  2 +
 .../rust-call-abi-not-a-tuple-ice-81974.rs    |  4 +-
 ...rust-call-abi-not-a-tuple-ice-81974.stderr | 44 ++++++++++---
 7 files changed, 89 insertions(+), 72 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index bbf36fef1ddbe..2a70c711e0513 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -3,7 +3,7 @@ use std::borrow::Cow;
 use std::iter;
 
 use hir::def_id::{DefId, DefIdMap, LocalDefId};
-use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::codes::*;
 use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err};
 use rustc_hir::def::{DefKind, Res};
@@ -356,61 +356,14 @@ fn compare_method_predicate_entailment<'tcx>(
     }
 
     if !(impl_sig, trait_sig).references_error() {
-        // Select obligations to make progress on inference before processing
-        // the wf obligation below.
-        // FIXME(-Znext-solver): Not needed when the hack below is removed.
-        let errors = ocx.select_where_possible();
-        if !errors.is_empty() {
-            let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
-            return Err(reported);
-        }
-
-        // See #108544. Annoying, we can end up in cases where, because of winnowing,
-        // we pick param env candidates over a more general impl, leading to more
-        // stricter lifetime requirements than we would otherwise need. This can
-        // trigger the lint. Instead, let's only consider type outlives and
-        // region outlives obligations.
-        //
-        // FIXME(-Znext-solver): Try removing this hack again once the new
-        // solver is stable. We should just be able to register a WF pred for
-        // the fn sig.
-        let mut wf_args: smallvec::SmallVec<[_; 4]> =
-            unnormalized_impl_sig.inputs_and_output.iter().map(|ty| ty.into()).collect();
-        // Annoyingly, asking for the WF predicates of an array (with an unevaluated const (only?))
-        // will give back the well-formed predicate of the same array.
-        let mut wf_args_seen: FxHashSet<_> = wf_args.iter().copied().collect();
-        while let Some(term) = wf_args.pop() {
-            let Some(obligations) = rustc_trait_selection::traits::wf::obligations(
-                infcx,
-                param_env,
-                impl_m_def_id,
-                0,
-                term,
-                impl_m_span,
-            ) else {
-                continue;
-            };
-            for obligation in obligations {
-                debug!(?obligation);
-                match obligation.predicate.kind().skip_binder() {
-                    // We need to register Projection oblgiations too, because we may end up with
-                    // an implied `X::Item: 'a`, which gets desugared into `X::Item = ?0`, `?0: 'a`.
-                    // If we only register the region outlives obligation, this leads to an unconstrained var.
-                    // See `implied_bounds_entailment_alias_var.rs` test.
-                    ty::PredicateKind::Clause(
-                        ty::ClauseKind::RegionOutlives(..)
-                        | ty::ClauseKind::TypeOutlives(..)
-                        | ty::ClauseKind::Projection(..),
-                    ) => ocx.register_obligation(obligation),
-                    ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
-                        if wf_args_seen.insert(term) {
-                            wf_args.push(term)
-                        }
-                    }
-                    _ => {}
-                }
-            }
-        }
+        ocx.register_obligation(traits::Obligation::new(
+            infcx.tcx,
+            cause,
+            param_env,
+            ty::ClauseKind::WellFormed(
+                Ty::new_fn_ptr(tcx, ty::Binder::dummy(unnormalized_impl_sig)).into(),
+            ),
+        ));
     }
 
     // Check that all obligations are satisfied by the implementation's
diff --git a/tests/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-88022.rs b/tests/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-88022.rs
index 99eb92f432c27..76f6aaee6dcee 100644
--- a/tests/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-88022.rs
+++ b/tests/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-88022.rs
@@ -15,12 +15,14 @@ where
 
 impl<'a, T, const S: usize> Iterator for BufferIter<'a, T, S> {
     //~^ error: the trait bound
-    //~^^ error: unconstrained generic constant
+    //~| error: unconstrained generic constant
     type Item = &'a T;
 
     fn next(&mut self) -> Option {
         //~^ error: the trait bound
-        //~^^ error: unconstrained generic constant
+        //~| error: unconstrained generic constant
+        //~| error: the trait bound
+        //~| error: unconstrained generic constant
         None
     }
 }
diff --git a/tests/ui/dropck/explicit-drop-bounds.bad1.stderr b/tests/ui/dropck/explicit-drop-bounds.bad1.stderr
index 12d7f5b6cd301..28d7546d0c9bb 100644
--- a/tests/ui/dropck/explicit-drop-bounds.bad1.stderr
+++ b/tests/ui/dropck/explicit-drop-bounds.bad1.stderr
@@ -14,6 +14,22 @@ help: consider further restricting type parameter `T` with trait `Copy`
 LL |     [T; 1]: Copy, T: std::marker::Copy // But `[T; 1]: Copy` does not imply `T: Copy`
    |                   ++++++++++++++++++++
 
+error[E0277]: the trait bound `T: Copy` is not satisfied
+  --> $DIR/explicit-drop-bounds.rs:32:5
+   |
+LL |     fn drop(&mut self) {}
+   |     ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
+   |
+note: required by a bound in `DropMe`
+  --> $DIR/explicit-drop-bounds.rs:7:18
+   |
+LL | struct DropMe(T);
+   |                  ^^^^ required by this bound in `DropMe`
+help: consider further restricting type parameter `T` with trait `Copy`
+   |
+LL |     [T; 1]: Copy, T: std::marker::Copy // But `[T; 1]: Copy` does not imply `T: Copy`
+   |                   ++++++++++++++++++++
+
 error[E0277]: the trait bound `T: Copy` is not satisfied
   --> $DIR/explicit-drop-bounds.rs:32:18
    |
@@ -30,6 +46,6 @@ help: consider further restricting type parameter `T` with trait `Copy`
 LL |     [T; 1]: Copy, T: std::marker::Copy // But `[T; 1]: Copy` does not imply `T: Copy`
    |                   ++++++++++++++++++++
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/dropck/explicit-drop-bounds.bad2.stderr b/tests/ui/dropck/explicit-drop-bounds.bad2.stderr
index 5851731e83461..c363676edea3e 100644
--- a/tests/ui/dropck/explicit-drop-bounds.bad2.stderr
+++ b/tests/ui/dropck/explicit-drop-bounds.bad2.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/explicit-drop-bounds.rs:37:18
+  --> $DIR/explicit-drop-bounds.rs:38:18
    |
 LL | impl Drop for DropMe
    |                  ^^^^^^^^^ the trait `Copy` is not implemented for `T`
@@ -15,7 +15,23 @@ LL | impl Drop for DropMe
    |       +++++++++++++++++++
 
 error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/explicit-drop-bounds.rs:40:18
+  --> $DIR/explicit-drop-bounds.rs:41:5
+   |
+LL |     fn drop(&mut self) {}
+   |     ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
+   |
+note: required by a bound in `DropMe`
+  --> $DIR/explicit-drop-bounds.rs:7:18
+   |
+LL | struct DropMe(T);
+   |                  ^^^^ required by this bound in `DropMe`
+help: consider restricting type parameter `T` with trait `Copy`
+   |
+LL | impl Drop for DropMe
+   |       +++++++++++++++++++
+
+error[E0277]: the trait bound `T: Copy` is not satisfied
+  --> $DIR/explicit-drop-bounds.rs:41:18
    |
 LL |     fn drop(&mut self) {}
    |                  ^^^^ the trait `Copy` is not implemented for `T`
@@ -30,6 +46,6 @@ help: consider restricting type parameter `T` with trait `Copy`
 LL | impl Drop for DropMe
    |       +++++++++++++++++++
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/dropck/explicit-drop-bounds.rs b/tests/ui/dropck/explicit-drop-bounds.rs
index 6ddac4d314f41..cd1d89ed9dbd1 100644
--- a/tests/ui/dropck/explicit-drop-bounds.rs
+++ b/tests/ui/dropck/explicit-drop-bounds.rs
@@ -31,6 +31,7 @@ where
 {
     fn drop(&mut self) {}
     //[bad1]~^ ERROR the trait bound `T: Copy` is not satisfied
+    //[bad1]~| ERROR the trait bound `T: Copy` is not satisfied
 }
 
 #[cfg(bad2)]
@@ -39,6 +40,7 @@ impl Drop for DropMe
 {
     fn drop(&mut self) {}
     //[bad2]~^ ERROR the trait bound `T: Copy` is not satisfied
+    //[bad2]~| ERROR the trait bound `T: Copy` is not satisfied
 }
 
 fn main() {}
diff --git a/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.rs b/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.rs
index 6380449124ffb..3b297a9a66293 100644
--- a/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.rs
+++ b/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.rs
@@ -30,7 +30,8 @@ where
     type Output = B;
     extern "rust-call" fn call_once(mut self, a: A) -> Self::Output {
     //~^ ERROR functions with the "rust-call" ABI must take a single non-self tuple argument
-        self.call_mut(a)
+    //~| ERROR type parameter to bare `FnOnce` trait must be a tuple
+    self.call_mut(a)
         //~^ ERROR `A` is not a tuple
     }
 }
@@ -43,6 +44,7 @@ where
 {
     extern "rust-call" fn call_mut(&mut self, a: A) -> Self::Output {
     //~^ ERROR functions with the "rust-call" ABI must take a single non-self tuple argument
+    //~| ERROR type parameter to bare `FnOnce` trait must be a tuple
         self.cache.get(&a).map(|a| a.clone()).unwrap_or_else(|| {
             let b = (self.fun)(self, a.clone());
             self.cache.insert(a, b.clone());
diff --git a/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.stderr b/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.stderr
index 3b051ef9a8823..32a564e466be1 100644
--- a/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.stderr
+++ b/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.stderr
@@ -11,8 +11,21 @@ help: consider further restricting type parameter `A` with unstable trait `Tuple
 LL |     A: Eq + Hash + Clone + std::marker::Tuple,
    |                          ++++++++++++++++++++
 
+error[E0059]: type parameter to bare `FnOnce` trait must be a tuple
+  --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:31:5
+   |
+LL |     extern "rust-call" fn call_once(mut self, a: A) -> Self::Output {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `A`
+   |
+note: required by a bound in `FnOnce`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+help: consider further restricting type parameter `A` with unstable trait `Tuple`
+   |
+LL |     A: Eq + Hash + Clone + std::marker::Tuple,
+   |                          ++++++++++++++++++++
+
 error[E0059]: type parameter to bare `FnMut` trait must be a tuple
-  --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:38:12
+  --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:39:12
    |
 LL | impl FnMut for CachedFun
    |            ^^^^^^^^ the trait `Tuple` is not implemented for `A`
@@ -24,6 +37,19 @@ help: consider further restricting type parameter `A` with unstable trait `Tuple
 LL |     A: Eq + Hash + Clone + std::marker::Tuple,
    |                          ++++++++++++++++++++
 
+error[E0059]: type parameter to bare `FnOnce` trait must be a tuple
+  --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:45:5
+   |
+LL |     extern "rust-call" fn call_mut(&mut self, a: A) -> Self::Output {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `A`
+   |
+note: required by a bound in `FnOnce`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+help: consider further restricting type parameter `A` with unstable trait `Tuple`
+   |
+LL |     A: Eq + Hash + Clone + std::marker::Tuple,
+   |                          ++++++++++++++++++++
+
 error[E0277]: functions with the "rust-call" ABI must take a single non-self tuple argument
   --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:31:5
    |
@@ -36,7 +62,7 @@ LL |     A: Eq + Hash + Clone + std::marker::Tuple,
    |                          ++++++++++++++++++++
 
 error[E0277]: functions with the "rust-call" ABI must take a single non-self tuple argument
-  --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:44:5
+  --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:45:5
    |
 LL |     extern "rust-call" fn call_mut(&mut self, a: A) -> Self::Output {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `A`
@@ -47,12 +73,12 @@ LL |     A: Eq + Hash + Clone + std::marker::Tuple,
    |                          ++++++++++++++++++++
 
 error[E0277]: `A` is not a tuple
-  --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:33:23
+  --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:34:19
    |
-LL |         self.call_mut(a)
-   |              -------- ^ the trait `Tuple` is not implemented for `A`
-   |              |
-   |              required by a bound introduced by this call
+LL |     self.call_mut(a)
+   |          -------- ^ the trait `Tuple` is not implemented for `A`
+   |          |
+   |          required by a bound introduced by this call
    |
 note: required by a bound in `call_mut`
   --> $SRC_DIR/core/src/ops/function.rs:LL:COL
@@ -62,7 +88,7 @@ LL |     A: Eq + Hash + Clone + std::marker::Tuple,
    |                          ++++++++++++++++++++
 
 error[E0277]: `i32` is not a tuple
-  --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:57:26
+  --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:59:26
    |
 LL |     cachedcoso.call_once(1);
    |                --------- ^ the trait `Tuple` is not implemented for `i32`
@@ -76,7 +102,7 @@ help: use a unary tuple instead
 LL |     cachedcoso.call_once((1,));
    |                          + ++
 
-error: aborting due to 6 previous errors
+error: aborting due to 8 previous errors
 
 Some errors have detailed explanations: E0059, E0277.
 For more information about an error, try `rustc --explain E0059`.

From 3cd065d3d358c0124368f21a7deb0e75712c286b Mon Sep 17 00:00:00 2001
From: Kivooeo 
Date: Fri, 2 May 2025 21:28:11 +0500
Subject: [PATCH 2048/4206] macro expansion issue

---
 .../rustc_hir_typeck/src/fn_ctxt/checks.rs    | 27 +++---
 tests/ui/auxiliary/delegate_macro.rs          |  6 ++
 tests/ui/not-enough-arguments.rs              | 52 +++++++---
 tests/ui/not-enough-arguments.stderr          | 94 ++++++++++++++-----
 4 files changed, 124 insertions(+), 55 deletions(-)
 create mode 100644 tests/ui/auxiliary/delegate_macro.rs

diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 8b2d9ab297905..0a0967941aab3 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1546,25 +1546,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             SuggestionText::Reorder => Some("reorder these arguments".to_string()),
             SuggestionText::DidYouMean => Some("did you mean".to_string()),
         };
-        if let Some(suggestion_text) = suggestion_text {
+        if let Some(suggestion_text) = suggestion_text
+            && !full_call_span.in_external_macro(self.sess().source_map())
+        {
             let source_map = self.sess().source_map();
-            let (mut suggestion, suggestion_span) = if let Some(call_span) =
-                full_call_span.find_ancestor_inside_same_ctxt(error_span)
-            {
-                ("(".to_string(), call_span.shrink_to_hi().to(error_span.shrink_to_hi()))
+            let suggestion_span = if let Some(args_span) = error_span.trim_start(full_call_span) {
+                // Span of the braces, e.g. `(a, b, c)`.
+                args_span
             } else {
-                (
-                    format!(
-                        "{}(",
-                        source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| {
-                            fn_def_id.map_or("".to_string(), |fn_def_id| {
-                                tcx.item_name(fn_def_id).to_string()
-                            })
-                        })
-                    ),
-                    error_span,
-                )
+                // The arg span of a function call that wasn't even given braces
+                // like what might happen with delegation reuse.
+                // e.g. `reuse HasSelf::method;` should suggest `reuse HasSelf::method($args);`.
+                full_call_span.shrink_to_hi()
             };
+            let mut suggestion = "(".to_owned();
             let mut needs_comma = false;
             for (expected_idx, provided_idx) in matched_inputs.iter_enumerated() {
                 if needs_comma {
diff --git a/tests/ui/auxiliary/delegate_macro.rs b/tests/ui/auxiliary/delegate_macro.rs
new file mode 100644
index 0000000000000..0d752e1203955
--- /dev/null
+++ b/tests/ui/auxiliary/delegate_macro.rs
@@ -0,0 +1,6 @@
+#[macro_export]
+macro_rules! delegate {
+    ($method:ident) => {
+        ::$method(8)
+    };
+}
diff --git a/tests/ui/not-enough-arguments.rs b/tests/ui/not-enough-arguments.rs
index 4a2ea5e44c71a..ec660a1de81be 100644
--- a/tests/ui/not-enough-arguments.rs
+++ b/tests/ui/not-enough-arguments.rs
@@ -1,20 +1,16 @@
+//@ aux-build: delegate_macro.rs
+extern crate delegate_macro;
+use delegate_macro::delegate;
+
 // Check that the only error msg we report is the
 // mismatch between the # of params, and not other
 // unrelated errors.
-
-fn foo(a: isize, b: isize, c: isize, d:isize) {
-  panic!();
+fn foo(a: isize, b: isize, c: isize, d: isize) {
+    panic!();
 }
 
 // Check that all arguments are shown in the error message, even if they're across multiple lines.
-fn bar(
-    a: i32,
-    b: i32,
-    c: i32,
-    d: i32,
-    e: i32,
-    f: i32,
-) {
+fn bar(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32) {
     println!("{}", a);
     println!("{}", b);
     println!("{}", c);
@@ -23,9 +19,35 @@ fn bar(
     println!("{}", f);
 }
 
+macro_rules! delegate_local {
+    ($method:ident) => {
+        ::$method(8)
+        //~^ ERROR function takes 2 arguments but 1
+    };
+}
+
+macro_rules! delegate_from {
+    ($from:ident, $method:ident) => {
+        <$from>::$method(8)
+        //~^ ERROR function takes 2 arguments but 1
+    };
+}
+
+struct Bar;
+
+impl Bar {
+    fn foo(a: u8, b: u8) {}
+    fn bar() {
+        delegate_local!(foo);
+        delegate!(foo);
+        //~^ ERROR function takes 2 arguments but 1
+        delegate_from!(Bar, foo);
+    }
+}
+
 fn main() {
-  foo(1, 2, 3);
-  //~^ ERROR function takes 4 arguments but 3
-  bar(1, 2, 3);
-  //~^ ERROR function takes 6 arguments but 3
+    foo(1, 2, 3);
+    //~^ ERROR function takes 4 arguments but 3
+    bar(1, 2, 3);
+    //~^ ERROR function takes 6 arguments but 3
 }
diff --git a/tests/ui/not-enough-arguments.stderr b/tests/ui/not-enough-arguments.stderr
index 099d82eb93552..908d0273bbecd 100644
--- a/tests/ui/not-enough-arguments.stderr
+++ b/tests/ui/not-enough-arguments.stderr
@@ -1,42 +1,88 @@
+error[E0061]: this function takes 2 arguments but 1 argument was supplied
+  --> $DIR/not-enough-arguments.rs:24:9
+   |
+LL |         ::$method(8)
+   |         ^^^^^^^^^^^^^^^--- argument #2 of type `u8` is missing
+...
+LL |         delegate_local!(foo);
+   |         -------------------- in this macro invocation
+   |
+note: associated function defined here
+  --> $DIR/not-enough-arguments.rs:39:8
+   |
+LL |     fn foo(a: u8, b: u8) {}
+   |        ^^^        -----
+   = note: this error originates in the macro `delegate_local` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: provide the argument
+   |
+LL |         ::$method(8, /* u8 */)
+   |                          ++++++++++
+
+error[E0061]: this function takes 2 arguments but 1 argument was supplied
+  --> $DIR/not-enough-arguments.rs:42:9
+   |
+LL |         delegate!(foo);
+   |         ^^^^^^^^^^^^^^ argument #2 of type `u8` is missing
+   |
+note: associated function defined here
+  --> $DIR/not-enough-arguments.rs:39:8
+   |
+LL |     fn foo(a: u8, b: u8) {}
+   |        ^^^        -----
+   = note: this error originates in the macro `delegate` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0061]: this function takes 2 arguments but 1 argument was supplied
+  --> $DIR/not-enough-arguments.rs:31:9
+   |
+LL |         <$from>::$method(8)
+   |         ^^^^^^^^^^^^^^^^--- argument #2 of type `u8` is missing
+...
+LL |         delegate_from!(Bar, foo);
+   |         ------------------------ in this macro invocation
+   |
+note: associated function defined here
+  --> $DIR/not-enough-arguments.rs:39:8
+   |
+LL |     fn foo(a: u8, b: u8) {}
+   |        ^^^        -----
+   = note: this error originates in the macro `delegate_from` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: provide the argument
+   |
+LL |         <$from>::$method(8, /* u8 */)
+   |                           ++++++++++
+
 error[E0061]: this function takes 4 arguments but 3 arguments were supplied
-  --> $DIR/not-enough-arguments.rs:27:3
+  --> $DIR/not-enough-arguments.rs:49:5
    |
-LL |   foo(1, 2, 3);
-   |   ^^^--------- argument #4 of type `isize` is missing
+LL |     foo(1, 2, 3);
+   |     ^^^--------- argument #4 of type `isize` is missing
    |
 note: function defined here
-  --> $DIR/not-enough-arguments.rs:5:4
+  --> $DIR/not-enough-arguments.rs:8:4
    |
-LL | fn foo(a: isize, b: isize, c: isize, d:isize) {
-   |    ^^^                               -------
+LL | fn foo(a: isize, b: isize, c: isize, d: isize) {
+   |    ^^^                               --------
 help: provide the argument
    |
-LL |   foo(1, 2, 3, /* isize */);
-   |              +++++++++++++
+LL |     foo(1, 2, 3, /* isize */);
+   |                +++++++++++++
 
 error[E0061]: this function takes 6 arguments but 3 arguments were supplied
-  --> $DIR/not-enough-arguments.rs:29:3
+  --> $DIR/not-enough-arguments.rs:51:5
    |
-LL |   bar(1, 2, 3);
-   |   ^^^--------- three arguments of type `i32`, `i32`, and `i32` are missing
+LL |     bar(1, 2, 3);
+   |     ^^^--------- three arguments of type `i32`, `i32`, and `i32` are missing
    |
 note: function defined here
-  --> $DIR/not-enough-arguments.rs:10:4
+  --> $DIR/not-enough-arguments.rs:13:4
    |
-LL | fn bar(
-   |    ^^^
-...
-LL |     d: i32,
-   |     ------
-LL |     e: i32,
-   |     ------
-LL |     f: i32,
-   |     ------
+LL | fn bar(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32) {
+   |    ^^^                         ------  ------  ------
 help: provide the arguments
    |
-LL |   bar(1, 2, 3, /* i32 */, /* i32 */, /* i32 */);
-   |              +++++++++++++++++++++++++++++++++
+LL |     bar(1, 2, 3, /* i32 */, /* i32 */, /* i32 */);
+   |                +++++++++++++++++++++++++++++++++
 
-error: aborting due to 2 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0061`.

From 036b5fcb0241c3dc28823c43b52a80376a4c040a Mon Sep 17 00:00:00 2001
From: Daniel Paoliello 
Date: Wed, 7 May 2025 11:02:37 -0700
Subject: [PATCH 2049/4206] [win] Update LLVM toolchain used to build LLVM to
 20

---
 src/ci/scripts/install-clang.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/ci/scripts/install-clang.sh b/src/ci/scripts/install-clang.sh
index 5522095e3049b..a9528e9291595 100755
--- a/src/ci/scripts/install-clang.sh
+++ b/src/ci/scripts/install-clang.sh
@@ -10,8 +10,8 @@ IFS=$'\n\t'
 source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
 
 # Update both macOS's and Windows's tarballs when bumping the version here.
-# Try to keep this in sync with src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh
-LLVM_VERSION="18.1.4"
+# Try to keep this in sync with src/ci/docker/scripts/build-clang.sh
+LLVM_VERSION="20.1.3"
 
 if isMacOS; then
     # FIXME: This is the latest pre-built version of LLVM that's available for

From 06fa0452eb62f675a4e43bde3a4754195e942e23 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Sat, 11 Jan 2025 00:43:04 +0100
Subject: [PATCH 2050/4206] Rename lint into `confusing_method_to_numeric_cast`

---
 CHANGELOG.md                                  |   2 +-
 ...rs => confusing_method_to_numeric_cast.rs} |  51 ++++++---
 clippy_lints/src/casts/mod.rs                 |   8 +-
 clippy_lints/src/declared_lints.rs            |   2 +-
 .../ui/confusing_method_to_numeric_cast.fixed |  14 +++
 tests/ui/confusing_method_to_numeric_cast.rs  |  14 +++
 .../confusing_method_to_numeric_cast.stderr   | 100 ++++++++++++++++++
 .../ui/primitive_method_to_numeric_cast.fixed |   5 -
 tests/ui/primitive_method_to_numeric_cast.rs  |   5 -
 .../primitive_method_to_numeric_cast.stderr   |  15 ---
 10 files changed, 172 insertions(+), 44 deletions(-)
 rename clippy_lints/src/casts/{primitive_method_to_numeric_cast.rs => confusing_method_to_numeric_cast.rs} (52%)
 create mode 100644 tests/ui/confusing_method_to_numeric_cast.fixed
 create mode 100644 tests/ui/confusing_method_to_numeric_cast.rs
 create mode 100644 tests/ui/confusing_method_to_numeric_cast.stderr
 delete mode 100644 tests/ui/primitive_method_to_numeric_cast.fixed
 delete mode 100644 tests/ui/primitive_method_to_numeric_cast.rs
 delete mode 100644 tests/ui/primitive_method_to_numeric_cast.stderr

diff --git a/CHANGELOG.md b/CHANGELOG.md
index ca2e738979030..6ab4cffb0cd3d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5594,6 +5594,7 @@ Released 2018-09-13
 [`collection_is_never_read`]: https://rust-lang.github.io/rust-clippy/master/index.html#collection_is_never_read
 [`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain
 [`comparison_to_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty
+[`confusing_method_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#confusing_method_to_numeric_cast
 [`const_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_is_empty
 [`const_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_static_lifetime
 [`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator
@@ -6068,7 +6069,6 @@ Released 2018-09-13
 [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
 [`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence
 [`precedence_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence_bits
-[`primitive_method_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#primitive_method_to_numeric_cast
 [`print_in_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_in_format_impl
 [`print_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_literal
 [`print_stderr`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_stderr
diff --git a/clippy_lints/src/casts/primitive_method_to_numeric_cast.rs b/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs
similarity index 52%
rename from clippy_lints/src/casts/primitive_method_to_numeric_cast.rs
rename to clippy_lints/src/casts/confusing_method_to_numeric_cast.rs
index 380fa98cd15f1..31cdd078f45a0 100644
--- a/clippy_lints/src/casts/primitive_method_to_numeric_cast.rs
+++ b/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs
@@ -1,12 +1,13 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::match_def_path;
 use clippy_utils::source::snippet_with_applicability;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, GenericArg, Ty};
+use rustc_span::def_id::DefId;
+use rustc_span::{Symbol, sym};
 
-use super::PRIMITIVE_METHOD_TO_NUMERIC_CAST;
+use super::CONFUSING_METHOD_TO_NUMERIC_CAST;
 
 fn get_primitive_ty_name(ty: Ty<'_>) -> Option<&'static str> {
     match ty.kind() {
@@ -18,6 +19,37 @@ fn get_primitive_ty_name(ty: Ty<'_>) -> Option<&'static str> {
     }
 }
 
+fn get_const_name_and_ty_name(
+    cx: &LateContext<'_>,
+    method_name: Symbol,
+    method_def_id: DefId,
+    generics: &[GenericArg<'_>],
+) -> Option<(&'static str, &'static str)> {
+    let method_name = method_name.as_str();
+    let diagnostic_name = cx.tcx.get_diagnostic_name(method_def_id);
+
+    let ty_name = if diagnostic_name.is_some_and(|diag| diag == sym::cmp_ord_min || diag == sym::cmp_ord_max) {
+        // We get the type on which the `min`/`max` method of the `Ord` trait is implemented.
+        if let [ty] = generics
+            && let Some(ty) = ty.as_type()
+        {
+            get_primitive_ty_name(ty)?
+        } else {
+            return None;
+        }
+    } else if let Some(impl_id) = cx.tcx.impl_of_method(method_def_id)
+        && let Some(ty_name) = get_primitive_ty_name(cx.tcx.type_of(impl_id).instantiate_identity())
+        && ["min", "max", "minimum", "maximum", "min_value", "max_value"].contains(&method_name)
+    {
+        ty_name
+    } else {
+        return None;
+    };
+
+    let const_name = if method_name.starts_with("max") { "MAX" } else { "MIN" };
+    Some((const_name, ty_name))
+}
+
 pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
     // We allow casts from any function type to any function type.
     match cast_to.kind() {
@@ -27,28 +59,21 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
 
     if let ty::FnDef(def_id, generics) = cast_from.kind()
         && let Some(method_name) = cx.tcx.opt_item_name(*def_id)
-        && let method_name = method_name.as_str()
-        && (method_name == "min" || method_name == "max")
-        // We get the type on which the `min`/`max` method of the `Ord` trait is implemented.
-        && let [ty] = generics.as_slice()
-        && let Some(ty) = ty.as_type()
-        // We get its name in case it's a primitive with an associated MIN/MAX constant.
-        && let Some(ty_name) = get_primitive_ty_name(ty)
-        && match_def_path(cx, *def_id, &["core", "cmp", "Ord", method_name])
+        && let Some((const_name, ty_name)) = get_const_name_and_ty_name(cx, method_name, *def_id, generics.as_slice())
     {
         let mut applicability = Applicability::MaybeIncorrect;
         let from_snippet = snippet_with_applicability(cx, cast_expr.span, "..", &mut applicability);
 
         span_lint_and_then(
             cx,
-            PRIMITIVE_METHOD_TO_NUMERIC_CAST,
+            CONFUSING_METHOD_TO_NUMERIC_CAST,
             expr.span,
             format!("casting function pointer `{from_snippet}` to `{cast_to}`"),
             |diag| {
                 diag.span_suggestion_verbose(
                     expr.span,
                     "did you mean to use the associated constant?",
-                    format!("{ty_name}::{} as {cast_to}", method_name.to_ascii_uppercase()),
+                    format!("{ty_name}::{const_name} as {cast_to}"),
                     applicability,
                 );
             },
diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs
index 7c8fa0b4d9211..6eac7ad438bd6 100644
--- a/clippy_lints/src/casts/mod.rs
+++ b/clippy_lints/src/casts/mod.rs
@@ -14,11 +14,11 @@ mod cast_sign_loss;
 mod cast_slice_different_sizes;
 mod cast_slice_from_raw_parts;
 mod char_lit_as_u8;
+mod confusing_method_to_numeric_cast;
 mod fn_to_numeric_cast;
 mod fn_to_numeric_cast_any;
 mod fn_to_numeric_cast_with_truncation;
 mod manual_dangling_ptr;
-mod primitive_method_to_numeric_cast;
 mod ptr_as_ptr;
 mod ptr_cast_constness;
 mod ref_as_ptr;
@@ -808,7 +808,7 @@ declare_clippy_lint! {
     /// let _ = u16::MAX as usize;
     /// ```
     #[clippy::version = "1.86.0"]
-    pub PRIMITIVE_METHOD_TO_NUMERIC_CAST,
+    pub CONFUSING_METHOD_TO_NUMERIC_CAST,
     suspicious,
     "casting a primitive method pointer to any integer type"
 }
@@ -850,7 +850,7 @@ impl_lint_pass!(Casts => [
     REF_AS_PTR,
     AS_POINTER_UNDERSCORE,
     MANUAL_DANGLING_PTR,
-    PRIMITIVE_METHOD_TO_NUMERIC_CAST,
+    CONFUSING_METHOD_TO_NUMERIC_CAST,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Casts {
@@ -875,7 +875,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
             ptr_cast_constness::check(cx, expr, cast_from_expr, cast_from, cast_to, self.msrv);
             as_ptr_cast_mut::check(cx, expr, cast_from_expr, cast_to);
             fn_to_numeric_cast_any::check(cx, expr, cast_from_expr, cast_from, cast_to);
-            primitive_method_to_numeric_cast::check(cx, expr, cast_from_expr, cast_from, cast_to);
+            confusing_method_to_numeric_cast::check(cx, expr, cast_from_expr, cast_from, cast_to);
             fn_to_numeric_cast::check(cx, expr, cast_from_expr, cast_from, cast_to);
             fn_to_numeric_cast_with_truncation::check(cx, expr, cast_from_expr, cast_from, cast_to);
             zero_ptr::check(cx, expr, cast_from_expr, cast_to_hir);
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 1d4c75dafa317..472d0f732ac09 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -64,11 +64,11 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::casts::CAST_SLICE_DIFFERENT_SIZES_INFO,
     crate::casts::CAST_SLICE_FROM_RAW_PARTS_INFO,
     crate::casts::CHAR_LIT_AS_U8_INFO,
+    crate::casts::CONFUSING_METHOD_TO_NUMERIC_CAST_INFO,
     crate::casts::FN_TO_NUMERIC_CAST_INFO,
     crate::casts::FN_TO_NUMERIC_CAST_ANY_INFO,
     crate::casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION_INFO,
     crate::casts::MANUAL_DANGLING_PTR_INFO,
-    crate::casts::PRIMITIVE_METHOD_TO_NUMERIC_CAST_INFO,
     crate::casts::PTR_AS_PTR_INFO,
     crate::casts::PTR_CAST_CONSTNESS_INFO,
     crate::casts::REF_AS_PTR_INFO,
diff --git a/tests/ui/confusing_method_to_numeric_cast.fixed b/tests/ui/confusing_method_to_numeric_cast.fixed
new file mode 100644
index 0000000000000..e698b99edd5c0
--- /dev/null
+++ b/tests/ui/confusing_method_to_numeric_cast.fixed
@@ -0,0 +1,14 @@
+#![feature(float_minimum_maximum)]
+#![warn(clippy::confusing_method_to_numeric_cast)]
+
+fn main() {
+    let _ = u16::MAX as usize; //~ confusing_method_to_numeric_cast
+    let _ = u16::MIN as usize; //~ confusing_method_to_numeric_cast
+    let _ = u16::MAX as usize; //~ confusing_method_to_numeric_cast
+    let _ = u16::MIN as usize; //~ confusing_method_to_numeric_cast
+
+    let _ = f32::MAX as usize; //~ confusing_method_to_numeric_cast
+    let _ = f32::MAX as usize; //~ confusing_method_to_numeric_cast
+    let _ = f32::MIN as usize; //~ confusing_method_to_numeric_cast
+    let _ = f32::MIN as usize; //~ confusing_method_to_numeric_cast
+}
diff --git a/tests/ui/confusing_method_to_numeric_cast.rs b/tests/ui/confusing_method_to_numeric_cast.rs
new file mode 100644
index 0000000000000..ef65c21563d98
--- /dev/null
+++ b/tests/ui/confusing_method_to_numeric_cast.rs
@@ -0,0 +1,14 @@
+#![feature(float_minimum_maximum)]
+#![warn(clippy::confusing_method_to_numeric_cast)]
+
+fn main() {
+    let _ = u16::max as usize; //~ confusing_method_to_numeric_cast
+    let _ = u16::min as usize; //~ confusing_method_to_numeric_cast
+    let _ = u16::max_value as usize; //~ confusing_method_to_numeric_cast
+    let _ = u16::min_value as usize; //~ confusing_method_to_numeric_cast
+
+    let _ = f32::maximum as usize; //~ confusing_method_to_numeric_cast
+    let _ = f32::max as usize; //~ confusing_method_to_numeric_cast
+    let _ = f32::minimum as usize; //~ confusing_method_to_numeric_cast
+    let _ = f32::min as usize; //~ confusing_method_to_numeric_cast
+}
diff --git a/tests/ui/confusing_method_to_numeric_cast.stderr b/tests/ui/confusing_method_to_numeric_cast.stderr
new file mode 100644
index 0000000000000..ba90df2059af6
--- /dev/null
+++ b/tests/ui/confusing_method_to_numeric_cast.stderr
@@ -0,0 +1,100 @@
+error: casting function pointer `u16::max` to `usize`
+  --> tests/ui/confusing_method_to_numeric_cast.rs:5:13
+   |
+LL |     let _ = u16::max as usize;
+   |             ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::confusing-method-to-numeric-cast` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::confusing_method_to_numeric_cast)]`
+help: did you mean to use the associated constant?
+   |
+LL -     let _ = u16::max as usize;
+LL +     let _ = u16::MAX as usize;
+   |
+
+error: casting function pointer `u16::min` to `usize`
+  --> tests/ui/confusing_method_to_numeric_cast.rs:6:13
+   |
+LL |     let _ = u16::min as usize;
+   |             ^^^^^^^^^^^^^^^^^
+   |
+help: did you mean to use the associated constant?
+   |
+LL -     let _ = u16::min as usize;
+LL +     let _ = u16::MIN as usize;
+   |
+
+error: casting function pointer `u16::max_value` to `usize`
+  --> tests/ui/confusing_method_to_numeric_cast.rs:7:13
+   |
+LL |     let _ = u16::max_value as usize;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: did you mean to use the associated constant?
+   |
+LL -     let _ = u16::max_value as usize;
+LL +     let _ = u16::MAX as usize;
+   |
+
+error: casting function pointer `u16::min_value` to `usize`
+  --> tests/ui/confusing_method_to_numeric_cast.rs:8:13
+   |
+LL |     let _ = u16::min_value as usize;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: did you mean to use the associated constant?
+   |
+LL -     let _ = u16::min_value as usize;
+LL +     let _ = u16::MIN as usize;
+   |
+
+error: casting function pointer `f32::maximum` to `usize`
+  --> tests/ui/confusing_method_to_numeric_cast.rs:10:13
+   |
+LL |     let _ = f32::maximum as usize;
+   |             ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: did you mean to use the associated constant?
+   |
+LL -     let _ = f32::maximum as usize;
+LL +     let _ = f32::MAX as usize;
+   |
+
+error: casting function pointer `f32::max` to `usize`
+  --> tests/ui/confusing_method_to_numeric_cast.rs:11:13
+   |
+LL |     let _ = f32::max as usize;
+   |             ^^^^^^^^^^^^^^^^^
+   |
+help: did you mean to use the associated constant?
+   |
+LL -     let _ = f32::max as usize;
+LL +     let _ = f32::MAX as usize;
+   |
+
+error: casting function pointer `f32::minimum` to `usize`
+  --> tests/ui/confusing_method_to_numeric_cast.rs:12:13
+   |
+LL |     let _ = f32::minimum as usize;
+   |             ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: did you mean to use the associated constant?
+   |
+LL -     let _ = f32::minimum as usize;
+LL +     let _ = f32::MIN as usize;
+   |
+
+error: casting function pointer `f32::min` to `usize`
+  --> tests/ui/confusing_method_to_numeric_cast.rs:13:13
+   |
+LL |     let _ = f32::min as usize;
+   |             ^^^^^^^^^^^^^^^^^
+   |
+help: did you mean to use the associated constant?
+   |
+LL -     let _ = f32::min as usize;
+LL +     let _ = f32::MIN as usize;
+   |
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/primitive_method_to_numeric_cast.fixed b/tests/ui/primitive_method_to_numeric_cast.fixed
deleted file mode 100644
index 1ebb52618f137..0000000000000
--- a/tests/ui/primitive_method_to_numeric_cast.fixed
+++ /dev/null
@@ -1,5 +0,0 @@
-#![warn(clippy::primitive_method_to_numeric_cast)]
-
-fn main() {
-    let _ = u16::MAX as usize; //~ primitive_method_to_numeric_cast
-}
diff --git a/tests/ui/primitive_method_to_numeric_cast.rs b/tests/ui/primitive_method_to_numeric_cast.rs
deleted file mode 100644
index 89b0bfa84fee8..0000000000000
--- a/tests/ui/primitive_method_to_numeric_cast.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-#![warn(clippy::primitive_method_to_numeric_cast)]
-
-fn main() {
-    let _ = u16::max as usize; //~ primitive_method_to_numeric_cast
-}
diff --git a/tests/ui/primitive_method_to_numeric_cast.stderr b/tests/ui/primitive_method_to_numeric_cast.stderr
deleted file mode 100644
index 5515dc646ce71..0000000000000
--- a/tests/ui/primitive_method_to_numeric_cast.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: casting function pointer `u16::max` to `usize`
-  --> tests/ui/primitive_method_to_numeric_cast.rs:4:13
-   |
-LL |     let _ = u16::max as usize;
-   |             ^^^^^^^^^^^^^^^^^
-   |
-   = note: `-D clippy::primitive-method-to-numeric-cast` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::primitive_method_to_numeric_cast)]`
-help: did you mean to use the associated constant?
-   |
-LL |     let _ = u16::MAX as usize;
-   |             ~~~~~~~~~~~~~~~~~
-
-error: aborting due to 1 previous error
-

From a94abae9118f004365a2c6b4ec2ae4b0f1ac43ce Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Wed, 7 May 2025 21:42:21 +0200
Subject: [PATCH 2051/4206] Clarify docs of `CONFUSING_METHOD_TO_NUMERIC_CAST`

---
 clippy_lints/src/casts/mod.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs
index 6eac7ad438bd6..16a1552c5eea1 100644
--- a/clippy_lints/src/casts/mod.rs
+++ b/clippy_lints/src/casts/mod.rs
@@ -789,7 +789,7 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts of a primitive method pointer to any integer type.
+    /// Checks for casts of a primitive method pointer like `max`/`min` to any integer type.
     ///
     /// ### Why restrict this?
     /// Casting a function pointer to an integer can have surprising results and can occur

From d17eeb5d8307455d02d23a514c600343747a2c34 Mon Sep 17 00:00:00 2001
From: Samuel Tardieu 
Date: Thu, 8 May 2025 00:01:45 +0200
Subject: [PATCH 2052/4206] =?UTF-8?q?triagebot:=20`canonicalize-issue-link?=
 =?UTF-8?q?s`=20=E2=86=92=20`issue-links`?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The feature has been renamed in triagebot
(https://forge.rust-lang.org/triagebot/canonicalize-issue-links.html).
---
 triagebot.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/triagebot.toml b/triagebot.toml
index b2a2a85f61a04..fe558e0ef8f39 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -13,7 +13,7 @@ allow-unauthenticated = [
 
 [note]
 
-[canonicalize-issue-links]
+[issue-links]
 
 # Prevents mentions in commits to avoid users being spammed
 [no-mentions]

From 046bfb3e8c7ff64ee4f9d1df515d39696dd999a1 Mon Sep 17 00:00:00 2001
From: The rustc-dev-guide Cronjob Bot 
Date: Thu, 8 May 2025 07:16:18 +0000
Subject: [PATCH 2053/4206] Preparing for merge from rustc

---
 src/doc/rustc-dev-guide/rust-version | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version
index 66b4fe2bf3bf0..ec1602280955d 100644
--- a/src/doc/rustc-dev-guide/rust-version
+++ b/src/doc/rustc-dev-guide/rust-version
@@ -1 +1 @@
-0c33fe2c3d3eecadd17a84b110bb067288a64f1c
+7e552b46af72df390ed233b58a7f51650515b2a8

From ae25c39f2216ea1f6f062faac71761cd3f1bdd16 Mon Sep 17 00:00:00 2001
From: Luca Versari 
Date: Thu, 8 May 2025 09:33:38 +0200
Subject: [PATCH 2054/4206] Update documentation of OnceLock::get_or_init.

Explicitly point out that if the function panics the init function might
be called multiple times.
---
 library/std/src/sync/once_lock.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs
index ffb90b1469584..324b5451873bf 100644
--- a/library/std/src/sync/once_lock.rs
+++ b/library/std/src/sync/once_lock.rs
@@ -279,7 +279,7 @@ impl OnceLock {
     ///
     /// Many threads may call `get_or_init` concurrently with different
     /// initializing functions, but it is guaranteed that only one function
-    /// will be executed.
+    /// will be executed if the function doesn't panic.
     ///
     /// # Panics
     ///

From db9c18e44ee14c2e54f8dffad7c345e2bf25e24e Mon Sep 17 00:00:00 2001
From: Chayim Refael Friedman 
Date: Thu, 8 May 2025 11:05:39 +0300
Subject: [PATCH 2055/4206] Still complete parentheses & method call arguments
 if there are existing parentheses, but they are after a newline

---
 .../ide-completion/src/context/analysis.rs    | 31 ++++++++++--
 .../ide-completion/src/tests/expression.rs    | 48 +++++++++++++++++++
 2 files changed, 76 insertions(+), 3 deletions(-)

diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
index 391e2379dcd51..284876ffc8858 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
@@ -883,9 +883,10 @@ fn classify_name_ref(
             },
             ast::MethodCallExpr(method) => {
                 let receiver = find_opt_node_in_file(original_file, method.receiver());
+                let has_parens = has_parens(&method);
                 let kind = NameRefKind::DotAccess(DotAccess {
                     receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)),
-                    kind: DotAccessKind::Method { has_parens: method.arg_list().is_some_and(|it| it.l_paren_token().is_some()) },
+                    kind: DotAccessKind::Method { has_parens },
                     receiver,
                     ctx: DotAccessExprCtx { in_block_expr: is_in_block(method.syntax()), in_breakable: is_in_breakable(method.syntax()) }
                 });
@@ -1372,7 +1373,7 @@ fn classify_name_ref(
                         }
                     }
 
-                    path_ctx.has_call_parens = it.syntax().parent().is_some_and(|it| ast::CallExpr::can_cast(it.kind()));
+                    path_ctx.has_call_parens = it.syntax().parent().is_some_and(|it| ast::CallExpr::cast(it).is_some_and(|it| has_parens(&it)));
 
                     make_path_kind_expr(it.into())
                 },
@@ -1401,7 +1402,7 @@ fn classify_name_ref(
                         match parent {
                             ast::PathType(it) => make_path_kind_type(it.into()),
                             ast::PathExpr(it) => {
-                                path_ctx.has_call_parens = it.syntax().parent().is_some_and(|it| ast::CallExpr::can_cast(it.kind()));
+                                path_ctx.has_call_parens = it.syntax().parent().is_some_and(|it| ast::CallExpr::cast(it).is_some_and(|it| has_parens(&it)));
 
                                 make_path_kind_expr(it.into())
                             },
@@ -1559,6 +1560,30 @@ fn classify_name_ref(
     Some((NameRefContext { nameref, kind: NameRefKind::Path(path_ctx) }, qualifier_ctx))
 }
 
+/// When writing in the middle of some code the following situation commonly occurs (`|` denotes the cursor):
+/// ```ignore
+/// value.method|
+/// (1, 2, 3)
+/// ```
+/// Here, we want to complete the method parentheses & arguments (if the corresponding settings are on),
+/// but the thing is parsed as a method call with parentheses. Therefore we use heuristics: if the parentheses
+/// are on the next line, consider them non-existent.
+fn has_parens(node: &dyn HasArgList) -> bool {
+    let Some(arg_list) = node.arg_list() else { return false };
+    if arg_list.l_paren_token().is_none() {
+        return false;
+    }
+    let prev_siblings = iter::successors(arg_list.syntax().prev_sibling_or_token(), |it| {
+        it.prev_sibling_or_token()
+    });
+    prev_siblings
+        .take_while(|syntax| syntax.kind().is_trivia())
+        .filter_map(|syntax| {
+            syntax.into_token().filter(|token| token.kind() == SyntaxKind::WHITESPACE)
+        })
+        .all(|whitespace| !whitespace.text().contains('\n'))
+}
+
 fn pattern_context_for(
     sema: &Semantics<'_, RootDatabase>,
     original_file: &SyntaxNode,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
index d5137949d42f7..3750ad72c8bdf 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
@@ -2126,3 +2126,51 @@ fn main() {
         "#]],
     );
 }
+
+#[test]
+fn call_parens_with_newline() {
+    check_edit(
+        "foo",
+        r#"
+fn foo(v: i32) {}
+
+fn bar() {
+    foo$0
+    ()
+}
+    "#,
+        r#"
+fn foo(v: i32) {}
+
+fn bar() {
+    foo(${1:v});$0
+    ()
+}
+    "#,
+    );
+    check_edit(
+        "foo",
+        r#"
+struct Foo;
+impl Foo {
+    fn foo(&self, v: i32) {}
+}
+
+fn bar() {
+    Foo.foo$0
+    ()
+}
+    "#,
+        r#"
+struct Foo;
+impl Foo {
+    fn foo(&self, v: i32) {}
+}
+
+fn bar() {
+    Foo.foo(${1:v});$0
+    ()
+}
+    "#,
+    );
+}

From 47cd0e733c3498dab7fc775d04475b23dd0e172c Mon Sep 17 00:00:00 2001
From: Stan Manilov 
Date: Thu, 8 May 2025 11:13:50 +0300
Subject: [PATCH 2056/4206] Fix minor typo in serialization.md

---
 src/doc/rustc-dev-guide/src/serialization.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/doc/rustc-dev-guide/src/serialization.md b/src/doc/rustc-dev-guide/src/serialization.md
index 670a37ffb0a97..47667061edaed 100644
--- a/src/doc/rustc-dev-guide/src/serialization.md
+++ b/src/doc/rustc-dev-guide/src/serialization.md
@@ -169,7 +169,7 @@ The `LazyArray<[T]>` and `LazyTable` types provide some functionality over
   than the one being read.
 
 **note**: `LazyValue` does not cache its value after being deserialized the
-first time. Instead the query system its self is the main way of caching these
+first time. Instead the query system itself is the main way of caching these
 results.
 
 [`LazyArray`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/rmeta/struct.LazyValue.html

From 99be5d4d8e896fd878be3ba14d3184fed2e3f6f8 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Wed, 7 May 2025 08:44:54 +0200
Subject: [PATCH 2057/4206] perf: Request cancellation while processing changed
 files

---
 src/tools/rust-analyzer/Cargo.lock            |   1 +
 .../crates/rust-analyzer/src/global_state.rs  | 163 ++++++++++--------
 .../rust-analyzer/crates/stdx/Cargo.toml      |   1 +
 .../crates/stdx/src/thread/pool.rs            |  51 +++++-
 4 files changed, 136 insertions(+), 80 deletions(-)

diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 8d6c8284e44ef..34469656dcec7 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -2228,6 +2228,7 @@ version = "0.0.0"
 dependencies = [
  "backtrace",
  "crossbeam-channel",
+ "crossbeam-utils",
  "itertools 0.14.0",
  "jod-thread",
  "libc",
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
index 3b3b9c879754a..1a31525b46a8d 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
@@ -3,7 +3,7 @@
 //!
 //! Each tick provides an immutable snapshot of the state as `WorldSnapshot`.
 
-use std::{ops::Not as _, time::Instant};
+use std::{ops::Not as _, panic::AssertUnwindSafe, time::Instant};
 
 use crossbeam_channel::{Receiver, Sender, unbounded};
 use hir::ChangeWithProcMacros;
@@ -19,6 +19,7 @@ use parking_lot::{
 use proc_macro_api::ProcMacroClient;
 use project_model::{ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, WorkspaceBuildScripts};
 use rustc_hash::{FxHashMap, FxHashSet};
+use stdx::thread;
 use tracing::{Level, span, trace};
 use triomphe::Arc;
 use vfs::{AbsPathBuf, AnchoredPathBuf, ChangeKind, Vfs, VfsPath};
@@ -78,6 +79,7 @@ pub(crate) struct GlobalState {
 
     pub(crate) task_pool: Handle, Receiver>,
     pub(crate) fmt_pool: Handle, Receiver>,
+    pub(crate) cancellation_pool: thread::Pool,
 
     pub(crate) config: Arc,
     pub(crate) config_errors: Option,
@@ -210,6 +212,7 @@ impl GlobalState {
             let handle = TaskPool::new_with_threads(sender, 1);
             Handle { handle, receiver }
         };
+        let cancellation_pool = thread::Pool::new(1);
 
         let task_queue = {
             let (sender, receiver) = unbounded();
@@ -230,6 +233,7 @@ impl GlobalState {
             req_queue: ReqQueue::default(),
             task_pool,
             fmt_pool,
+            cancellation_pool,
             loader,
             config: Arc::new(config.clone()),
             analysis_host,
@@ -290,7 +294,6 @@ impl GlobalState {
 
     pub(crate) fn process_changes(&mut self) -> bool {
         let _p = span!(Level::INFO, "GlobalState::process_changes").entered();
-
         // We cannot directly resolve a change in a ratoml file to a format
         // that can be used by the config module because config talks
         // in `SourceRootId`s instead of `FileId`s and `FileId` -> `SourceRootId`
@@ -298,66 +301,75 @@ impl GlobalState {
         let mut modified_ratoml_files: FxHashMap =
             FxHashMap::default();
 
-        let (change, modified_rust_files, workspace_structure_change) = {
-            let mut change = ChangeWithProcMacros::default();
-            let mut guard = self.vfs.write();
-            let changed_files = guard.0.take_changes();
-            if changed_files.is_empty() {
-                return false;
-            }
+        let mut change = ChangeWithProcMacros::default();
+        let mut guard = self.vfs.write();
+        let changed_files = guard.0.take_changes();
+        if changed_files.is_empty() {
+            return false;
+        }
 
-            // downgrade to read lock to allow more readers while we are normalizing text
-            let guard = RwLockWriteGuard::downgrade_to_upgradable(guard);
-            let vfs: &Vfs = &guard.0;
-
-            let mut workspace_structure_change = None;
-            // A file was added or deleted
-            let mut has_structure_changes = false;
-            let mut bytes = vec![];
-            let mut modified_rust_files = vec![];
-            for file in changed_files.into_values() {
-                let vfs_path = vfs.file_path(file.file_id);
-                if let Some(("rust-analyzer", Some("toml"))) = vfs_path.name_and_extension() {
-                    // Remember ids to use them after `apply_changes`
-                    modified_ratoml_files.insert(file.file_id, (file.kind(), vfs_path.clone()));
-                }
+        let (change, modified_rust_files, workspace_structure_change) =
+            self.cancellation_pool.scoped(|s| {
+                // start cancellation in parallel, this will kick off lru eviction
+                // allowing us to do meaningful work while waiting
+                let analysis_host = AssertUnwindSafe(&mut self.analysis_host);
+                s.spawn(thread::ThreadIntent::LatencySensitive, || {
+                    { analysis_host }.0.request_cancellation()
+                });
+
+                // downgrade to read lock to allow more readers while we are normalizing text
+                let guard = RwLockWriteGuard::downgrade_to_upgradable(guard);
+                let vfs: &Vfs = &guard.0;
+
+                let mut workspace_structure_change = None;
+                // A file was added or deleted
+                let mut has_structure_changes = false;
+                let mut bytes = vec![];
+                let mut modified_rust_files = vec![];
+                for file in changed_files.into_values() {
+                    let vfs_path = vfs.file_path(file.file_id);
+                    if let Some(("rust-analyzer", Some("toml"))) = vfs_path.name_and_extension() {
+                        // Remember ids to use them after `apply_changes`
+                        modified_ratoml_files.insert(file.file_id, (file.kind(), vfs_path.clone()));
+                    }
 
-                if let Some(path) = vfs_path.as_path() {
-                    has_structure_changes |= file.is_created_or_deleted();
+                    if let Some(path) = vfs_path.as_path() {
+                        has_structure_changes |= file.is_created_or_deleted();
 
-                    if file.is_modified() && path.extension() == Some("rs") {
-                        modified_rust_files.push(file.file_id);
-                    }
+                        if file.is_modified() && path.extension() == Some("rs") {
+                            modified_rust_files.push(file.file_id);
+                        }
 
-                    let additional_files = self
-                        .config
-                        .discover_workspace_config()
-                        .map(|cfg| {
-                            cfg.files_to_watch.iter().map(String::as_str).collect::>()
-                        })
-                        .unwrap_or_default();
-
-                    let path = path.to_path_buf();
-                    if file.is_created_or_deleted() {
-                        workspace_structure_change.get_or_insert((path, false)).1 |=
-                            self.crate_graph_file_dependencies.contains(vfs_path);
-                    } else if reload::should_refresh_for_change(
-                        &path,
-                        file.kind(),
-                        &additional_files,
-                    ) {
-                        trace!(?path, kind = ?file.kind(), "refreshing for a change");
-                        workspace_structure_change.get_or_insert((path.clone(), false));
+                        let additional_files = self
+                            .config
+                            .discover_workspace_config()
+                            .map(|cfg| {
+                                cfg.files_to_watch.iter().map(String::as_str).collect::>()
+                            })
+                            .unwrap_or_default();
+
+                        let path = path.to_path_buf();
+                        if file.is_created_or_deleted() {
+                            workspace_structure_change.get_or_insert((path, false)).1 |=
+                                self.crate_graph_file_dependencies.contains(vfs_path);
+                        } else if reload::should_refresh_for_change(
+                            &path,
+                            file.kind(),
+                            &additional_files,
+                        ) {
+                            trace!(?path, kind = ?file.kind(), "refreshing for a change");
+                            workspace_structure_change.get_or_insert((path.clone(), false));
+                        }
                     }
-                }
 
-                // Clear native diagnostics when their file gets deleted
-                if !file.exists() {
-                    self.diagnostics.clear_native_for(file.file_id);
-                }
+                    // Clear native diagnostics when their file gets deleted
+                    if !file.exists() {
+                        self.diagnostics.clear_native_for(file.file_id);
+                    }
 
-                let text =
-                    if let vfs::Change::Create(v, _) | vfs::Change::Modify(v, _) = file.change {
+                    let text = if let vfs::Change::Create(v, _) | vfs::Change::Modify(v, _) =
+                        file.change
+                    {
                         String::from_utf8(v).ok().map(|text| {
                             // FIXME: Consider doing normalization in the `vfs` instead? That allows
                             // getting rid of some locking
@@ -367,29 +379,28 @@ impl GlobalState {
                     } else {
                         None
                     };
-                // delay `line_endings_map` changes until we are done normalizing the text
-                // this allows delaying the re-acquisition of the write lock
-                bytes.push((file.file_id, text));
-            }
-            let (vfs, line_endings_map) = &mut *RwLockUpgradableReadGuard::upgrade(guard);
-            bytes.into_iter().for_each(|(file_id, text)| {
-                let text = match text {
-                    None => None,
-                    Some((text, line_endings)) => {
-                        line_endings_map.insert(file_id, line_endings);
-                        Some(text)
-                    }
-                };
-                change.change_file(file_id, text);
+                    // delay `line_endings_map` changes until we are done normalizing the text
+                    // this allows delaying the re-acquisition of the write lock
+                    bytes.push((file.file_id, text));
+                }
+                let (vfs, line_endings_map) = &mut *RwLockUpgradableReadGuard::upgrade(guard);
+                bytes.into_iter().for_each(|(file_id, text)| {
+                    let text = match text {
+                        None => None,
+                        Some((text, line_endings)) => {
+                            line_endings_map.insert(file_id, line_endings);
+                            Some(text)
+                        }
+                    };
+                    change.change_file(file_id, text);
+                });
+                if has_structure_changes {
+                    let roots = self.source_root_config.partition(vfs);
+                    change.set_roots(roots);
+                }
+                (change, modified_rust_files, workspace_structure_change)
             });
-            if has_structure_changes {
-                let roots = self.source_root_config.partition(vfs);
-                change.set_roots(roots);
-            }
-            (change, modified_rust_files, workspace_structure_change)
-        };
 
-        let _p = span!(Level::INFO, "GlobalState::process_changes/apply_change").entered();
         self.analysis_host.apply_change(change);
         if !modified_ratoml_files.is_empty()
             || !self.config.same_source_root_parent_map(&self.local_roots_parent_map)
diff --git a/src/tools/rust-analyzer/crates/stdx/Cargo.toml b/src/tools/rust-analyzer/crates/stdx/Cargo.toml
index 7bda106764b9f..b37aded6f68c2 100644
--- a/src/tools/rust-analyzer/crates/stdx/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/stdx/Cargo.toml
@@ -17,6 +17,7 @@ jod-thread = "1.0.0"
 crossbeam-channel.workspace = true
 itertools.workspace = true
 tracing.workspace = true
+crossbeam-utils = "0.8.21"
 # Think twice before adding anything here
 
 [target.'cfg(unix)'.dependencies]
diff --git a/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs b/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs
index a8de4db624f12..8d76c5fd1fb36 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs
@@ -8,6 +8,7 @@
 //! the threading utilities in [`crate::thread`].
 
 use std::{
+    marker::PhantomData,
     panic::{self, UnwindSafe},
     sync::{
         Arc,
@@ -16,8 +17,9 @@ use std::{
 };
 
 use crossbeam_channel::{Receiver, Sender};
+use crossbeam_utils::sync::WaitGroup;
 
-use super::{Builder, JoinHandle, ThreadIntent};
+use crate::thread::{Builder, JoinHandle, ThreadIntent};
 
 pub struct Pool {
     // `_handles` is never read: the field is present
@@ -79,9 +81,6 @@ impl Pool {
         Self { _handles: handles.into_boxed_slice(), extant_tasks, job_sender }
     }
 
-    /// # Panics
-    ///
-    /// Panics if job panics
     pub fn spawn(&self, intent: ThreadIntent, f: F)
     where
         F: FnOnce() + Send + UnwindSafe + 'static,
@@ -97,6 +96,17 @@ impl Pool {
         self.job_sender.send(job).unwrap();
     }
 
+    pub fn scoped<'pool, 'scope, F, R>(&'pool self, f: F) -> R
+    where
+        F: FnOnce(&Scope<'pool, 'scope>) -> R,
+    {
+        let wg = WaitGroup::new();
+        let scope = Scope { pool: self, wg, _marker: PhantomData };
+        let r = f(&scope);
+        scope.wg.wait();
+        r
+    }
+
     #[must_use]
     pub fn len(&self) -> usize {
         self.extant_tasks.load(Ordering::SeqCst)
@@ -107,3 +117,36 @@ impl Pool {
         self.len() == 0
     }
 }
+
+pub struct Scope<'pool, 'scope> {
+    pool: &'pool Pool,
+    wg: WaitGroup,
+    _marker: PhantomData &'scope ()>,
+}
+
+impl<'scope> Scope<'_, 'scope> {
+    pub fn spawn(&self, intent: ThreadIntent, f: F)
+    where
+        F: 'scope + FnOnce() + Send + UnwindSafe,
+    {
+        let wg = self.wg.clone();
+        let f = Box::new(move || {
+            if cfg!(debug_assertions) {
+                intent.assert_is_used_on_current_thread();
+            }
+            f();
+            drop(wg);
+        });
+
+        let job = Job {
+            requested_intent: intent,
+            f: unsafe {
+                std::mem::transmute::<
+                    Box,
+                    Box,
+                >(f)
+            },
+        };
+        self.pool.job_sender.send(job).unwrap();
+    }
+}

From 322451c7d22167c1ba4c5f34b5fba07b4ed5a8ee Mon Sep 17 00:00:00 2001
From: Chayim Refael Friedman 
Date: Thu, 8 May 2025 11:43:47 +0300
Subject: [PATCH 2058/4206] Fix postfix snippets duplicating derefs

---
 .../ide-completion/src/completions/postfix.rs | 27 ++++++++++---------
 .../ide-completion/src/tests/expression.rs    | 19 +++++++++++++
 2 files changed, 33 insertions(+), 13 deletions(-)

diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
index 54be7d2fbc33f..3cdf2112835d9 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
@@ -311,6 +311,8 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, String) {
 
     let mut prefix = String::new();
 
+    let mut found_ref_or_deref = false;
+
     while let Some(parent_deref_element) =
         resulting_element.syntax().parent().and_then(ast::PrefixExpr::cast)
     {
@@ -318,27 +320,26 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, String) {
             break;
         }
 
+        found_ref_or_deref = true;
         resulting_element = ast::Expr::from(parent_deref_element);
 
         prefix.insert(0, '*');
     }
 
-    if let Some(first_ref_expr) = resulting_element.syntax().parent().and_then(ast::RefExpr::cast) {
-        if let Some(expr) = first_ref_expr.expr() {
-            resulting_element = expr;
-        }
+    while let Some(parent_ref_element) =
+        resulting_element.syntax().parent().and_then(ast::RefExpr::cast)
+    {
+        found_ref_or_deref = true;
+        let exclusive = parent_ref_element.mut_token().is_some();
+        resulting_element = ast::Expr::from(parent_ref_element);
 
-        while let Some(parent_ref_element) =
-            resulting_element.syntax().parent().and_then(ast::RefExpr::cast)
-        {
-            let exclusive = parent_ref_element.mut_token().is_some();
-            resulting_element = ast::Expr::from(parent_ref_element);
+        prefix.insert_str(0, if exclusive { "&mut " } else { "&" });
+    }
 
-            prefix.insert_str(0, if exclusive { "&mut " } else { "&" });
-        }
-    } else {
-        // If we do not find any ref expressions, restore
+    if !found_ref_or_deref {
+        // If we do not find any ref/deref expressions, restore
         // all the progress of tree climbing
+        prefix.clear();
         resulting_element = initial_element.clone();
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
index 3750ad72c8bdf..e5467767d42ca 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
@@ -2174,3 +2174,22 @@ fn bar() {
     "#,
     );
 }
+
+#[test]
+fn dbg_too_many_asterisks() {
+    check_edit(
+        "dbg",
+        r#"
+fn main() {
+    let x = &42;
+    let y = *x.$0;
+}
+    "#,
+        r#"
+fn main() {
+    let x = &42;
+    let y = dbg!(*x);
+}
+    "#,
+    );
+}

From d22461c9b7ce9417a0ba8d8d4d415ed6f853cda8 Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote 
Date: Thu, 8 May 2025 19:59:48 +1000
Subject: [PATCH 2059/4206] Remove associated type
 `InvocationCollectorNode::AttrsTy`

It's always equal to `ast::AttrVec`, so just use that directly.
---
 compiler/rustc_expand/src/expand.rs | 30 ++++++++++++-----------------
 1 file changed, 12 insertions(+), 18 deletions(-)

diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index d4853d1357f30..81d4d59ee0451 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1,4 +1,3 @@
-use std::ops::Deref;
 use std::path::PathBuf;
 use std::rc::Rc;
 use std::sync::Arc;
@@ -1117,7 +1116,6 @@ enum AddSemicolon {
 /// of functionality used by `InvocationCollector`.
 trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
     type OutputTy = SmallVec<[Self; 1]>;
-    type AttrsTy: Deref = ast::AttrVec;
     type ItemKind = ItemKind;
     const KIND: AstFragmentKind;
     fn to_annotatable(self) -> Annotatable;
@@ -1134,7 +1132,7 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
     fn is_mac_call(&self) -> bool {
         false
     }
-    fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) {
+    fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) {
         unreachable!()
     }
     fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item)> {
@@ -1189,7 +1187,7 @@ impl InvocationCollectorNode for P {
     fn is_mac_call(&self) -> bool {
         matches!(self.kind, ItemKind::MacCall(..))
     }
-    fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) {
+    fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) {
         let node = self.into_inner();
         match node.kind {
             ItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
@@ -1345,7 +1343,7 @@ impl InvocationCollectorNode for AstNodeWrapper, TraitItemTag>
     fn is_mac_call(&self) -> bool {
         matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
     }
-    fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) {
+    fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) {
         let item = self.wrapped.into_inner();
         match item.kind {
             AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No),
@@ -1386,7 +1384,7 @@ impl InvocationCollectorNode for AstNodeWrapper, ImplItemTag>
     fn is_mac_call(&self) -> bool {
         matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
     }
-    fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) {
+    fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) {
         let item = self.wrapped.into_inner();
         match item.kind {
             AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No),
@@ -1427,7 +1425,7 @@ impl InvocationCollectorNode for AstNodeWrapper, TraitImplItem
     fn is_mac_call(&self) -> bool {
         matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
     }
-    fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) {
+    fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) {
         let item = self.wrapped.into_inner();
         match item.kind {
             AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No),
@@ -1465,7 +1463,7 @@ impl InvocationCollectorNode for P {
     fn is_mac_call(&self) -> bool {
         matches!(self.kind, ForeignItemKind::MacCall(..))
     }
-    fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) {
+    fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) {
         let node = self.into_inner();
         match node.kind {
             ForeignItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
@@ -1579,7 +1577,6 @@ impl InvocationCollectorNode for ast::Arm {
 }
 
 impl InvocationCollectorNode for ast::Stmt {
-    type AttrsTy = ast::AttrVec;
     const KIND: AstFragmentKind = AstFragmentKind::Stmts;
     fn to_annotatable(self) -> Annotatable {
         Annotatable::Stmt(P(self))
@@ -1599,7 +1596,7 @@ impl InvocationCollectorNode for ast::Stmt {
             StmtKind::Let(..) | StmtKind::Empty => false,
         }
     }
-    fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) {
+    fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) {
         // We pull macro invocations (both attributes and fn-like macro calls) out of their
         // `StmtKind`s and treat them as statement macro invocations, not as items or expressions.
         let (add_semicolon, mac, attrs) = match self.kind {
@@ -1693,7 +1690,7 @@ impl InvocationCollectorNode for P {
     fn is_mac_call(&self) -> bool {
         matches!(self.kind, ast::TyKind::MacCall(..))
     }
-    fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) {
+    fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) {
         let node = self.into_inner();
         match node.kind {
             TyKind::MacCall(mac) => (mac, AttrVec::new(), AddSemicolon::No),
@@ -1717,7 +1714,7 @@ impl InvocationCollectorNode for P {
     fn is_mac_call(&self) -> bool {
         matches!(self.kind, PatKind::MacCall(..))
     }
-    fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) {
+    fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) {
         let node = self.into_inner();
         match node.kind {
             PatKind::MacCall(mac) => (mac, AttrVec::new(), AddSemicolon::No),
@@ -1728,7 +1725,6 @@ impl InvocationCollectorNode for P {
 
 impl InvocationCollectorNode for P {
     type OutputTy = P;
-    type AttrsTy = ast::AttrVec;
     const KIND: AstFragmentKind = AstFragmentKind::Expr;
     fn to_annotatable(self) -> Annotatable {
         Annotatable::Expr(self)
@@ -1745,7 +1741,7 @@ impl InvocationCollectorNode for P {
     fn is_mac_call(&self) -> bool {
         matches!(self.kind, ExprKind::MacCall(..))
     }
-    fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) {
+    fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) {
         let node = self.into_inner();
         match node.kind {
             ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
@@ -1757,7 +1753,6 @@ impl InvocationCollectorNode for P {
 struct OptExprTag;
 impl InvocationCollectorNode for AstNodeWrapper, OptExprTag> {
     type OutputTy = Option>;
-    type AttrsTy = ast::AttrVec;
     const KIND: AstFragmentKind = AstFragmentKind::OptExpr;
     fn to_annotatable(self) -> Annotatable {
         Annotatable::Expr(self.wrapped)
@@ -1772,7 +1767,7 @@ impl InvocationCollectorNode for AstNodeWrapper, OptExprTag> {
     fn is_mac_call(&self) -> bool {
         matches!(self.wrapped.kind, ast::ExprKind::MacCall(..))
     }
-    fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) {
+    fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) {
         let node = self.wrapped.into_inner();
         match node.kind {
             ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
@@ -1794,7 +1789,6 @@ impl DummyAstNode for MethodReceiverTag {
 }
 impl InvocationCollectorNode for AstNodeWrapper, MethodReceiverTag> {
     type OutputTy = Self;
-    type AttrsTy = ast::AttrVec;
     const KIND: AstFragmentKind = AstFragmentKind::MethodReceiverExpr;
     fn descr() -> &'static str {
         "an expression"
@@ -1811,7 +1805,7 @@ impl InvocationCollectorNode for AstNodeWrapper, MethodReceiverTag>
     fn is_mac_call(&self) -> bool {
         matches!(self.wrapped.kind, ast::ExprKind::MacCall(..))
     }
-    fn take_mac_call(self) -> (P, Self::AttrsTy, AddSemicolon) {
+    fn take_mac_call(self) -> (P, ast::AttrVec, AddSemicolon) {
         let node = self.wrapped.into_inner();
         match node.kind {
             ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),

From b6c2a429efd85cbfa5f592c66faac6955729c6ea Mon Sep 17 00:00:00 2001
From: xizheyin 
Date: Thu, 8 May 2025 18:09:29 +0800
Subject: [PATCH 2060/4206] std: Make consistence between `From` and `Into`

Signed-off-by: xizheyin 
---
 library/core/src/convert/mod.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs
index e1b10e1074d27..ef184e1ceb4f1 100644
--- a/library/core/src/convert/mod.rs
+++ b/library/core/src/convert/mod.rs
@@ -464,8 +464,8 @@ pub trait Into: Sized {
 /// orphaning rules.
 /// See [`Into`] for more details.
 ///
-/// Prefer using [`Into`] over using `From` when specifying trait bounds on a generic function.
-/// This way, types that directly implement [`Into`] can be used as arguments as well.
+/// Prefer using [`Into`] over [`From`] when specifying trait bounds on a generic function
+/// to ensure that types that only implement [`Into`] can be used as well.
 ///
 /// The `From` trait is also very useful when performing error handling. When constructing a function
 /// that is capable of failing, the return type will generally be of the form `Result`.

From 4101d90818b7e5574d5366e24c995980fa2de866 Mon Sep 17 00:00:00 2001
From: xizheyin 
Date: Thu, 8 May 2025 18:12:05 +0800
Subject: [PATCH 2061/4206] std: Explain prefer `TryInto` over `TryFrom` when
 specifying traits bounds on generic function

Signed-off-by: xizheyin 
---
 library/core/src/convert/mod.rs | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs
index ef184e1ceb4f1..c542a28beb87c 100644
--- a/library/core/src/convert/mod.rs
+++ b/library/core/src/convert/mod.rs
@@ -597,6 +597,9 @@ pub trait From: Sized {
 /// standard library. For more information on this, see the
 /// documentation for [`Into`].
 ///
+/// Prefer using [`TryInto`] over [`TryFrom`] when specifying trait bounds on a generic function
+/// to ensure that types that only implement [`TryInto`] can be used as well.
+///
 /// # Implementing `TryInto`
 ///
 /// This suffers the same restrictions and reasoning as implementing
@@ -636,6 +639,9 @@ pub trait TryInto: Sized {
 /// When the [`!`] type is stabilized [`Infallible`] and [`!`] will be
 /// equivalent.
 ///
+/// Prefer using [`TryInto`] over [`TryFrom`] when specifying trait bounds on a generic function
+/// to ensure that types that only implement [`TryInto`] can be used as well.
+///
 /// `TryFrom` can be implemented as follows:
 ///
 /// ```

From d87763dc4f98e2dcec5c819a678242a0142b80d7 Mon Sep 17 00:00:00 2001
From: Stan Manilov 
Date: Thu, 8 May 2025 14:03:14 +0300
Subject: [PATCH 2062/4206] Remark test naming exception

---
 src/doc/rustc-dev-guide/src/tests/best-practices.md | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/doc/rustc-dev-guide/src/tests/best-practices.md b/src/doc/rustc-dev-guide/src/tests/best-practices.md
index 2bdc7f3a2431b..be00207e3fb93 100644
--- a/src/doc/rustc-dev-guide/src/tests/best-practices.md
+++ b/src/doc/rustc-dev-guide/src/tests/best-practices.md
@@ -70,6 +70,11 @@ related tests.
 > //!
 > //! Regression test for .
 > ```
+>
+> One exception to this rule is [crashes tests]: there it is canonical that
+> tests are named only after issue numbers because its purpose is to track
+> snippets from which issues no longer ICE/crash, and they would either be
+> removed or converted into proper ui/other tests in the fix PRs.
 
 ## Test organization
 
@@ -194,3 +199,4 @@ See [LLVM FileCheck guide][FileCheck] for details.
 [compiletest directives]: ./directives.md
 [`run-make`]: ./compiletest.md#run-make-tests
 [FileCheck]: https://llvm.org/docs/CommandGuide/FileCheck.html
+[crashes tests]: ./compiletest.md#crashes-tests

From 1fbfbb59e9409022ae3b6ddb497ee7b4ca6d725e Mon Sep 17 00:00:00 2001
From: Alexey Semenyuk 
Date: Mon, 21 Apr 2025 21:29:26 +0500
Subject: [PATCH 2063/4206] Fix integer_division false negative for NonZero
 denominators

---
 clippy_lints/src/operators/integer_division.rs |  5 ++++-
 tests/ui/integer_division.rs                   |  8 ++++++++
 tests/ui/integer_division.stderr               | 16 ++++++++++++----
 3 files changed, 24 insertions(+), 5 deletions(-)

diff --git a/clippy_lints/src/operators/integer_division.rs b/clippy_lints/src/operators/integer_division.rs
index 76eba7327cff6..7b98afa9b40bd 100644
--- a/clippy_lints/src/operators/integer_division.rs
+++ b/clippy_lints/src/operators/integer_division.rs
@@ -1,6 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
+use rustc_span::symbol::sym;
 
 use super::INTEGER_DIVISION;
 
@@ -13,7 +15,8 @@ pub(crate) fn check<'tcx>(
 ) {
     if op == hir::BinOpKind::Div
         && cx.typeck_results().expr_ty(left).is_integral()
-        && cx.typeck_results().expr_ty(right).is_integral()
+        && let right_ty = cx.typeck_results().expr_ty(right)
+        && (right_ty.is_integral() || is_type_diagnostic_item(cx, right_ty, sym::NonZero))
     {
         #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
         span_lint_and_then(cx, INTEGER_DIVISION, expr.span, "integer division", |diag| {
diff --git a/tests/ui/integer_division.rs b/tests/ui/integer_division.rs
index 632fedc9e8fe3..a40956e2672e3 100644
--- a/tests/ui/integer_division.rs
+++ b/tests/ui/integer_division.rs
@@ -1,5 +1,9 @@
 #![warn(clippy::integer_division)]
 
+use std::num::NonZeroU32;
+
+const TWO: NonZeroU32 = NonZeroU32::new(2).unwrap();
+
 fn main() {
     let two = 2;
     let n = 1 / 2;
@@ -12,4 +16,8 @@ fn main() {
     //~^ integer_division
 
     let x = 1. / 2.0;
+
+    let a = 1;
+    let s = a / TWO;
+    //~^ integer_division
 }
diff --git a/tests/ui/integer_division.stderr b/tests/ui/integer_division.stderr
index 0fe2021a1a9ca..c0e34a562f652 100644
--- a/tests/ui/integer_division.stderr
+++ b/tests/ui/integer_division.stderr
@@ -1,5 +1,5 @@
 error: integer division
-  --> tests/ui/integer_division.rs:5:13
+  --> tests/ui/integer_division.rs:9:13
    |
 LL |     let n = 1 / 2;
    |             ^^^^^
@@ -9,7 +9,7 @@ LL |     let n = 1 / 2;
    = help: to override `-D warnings` add `#[allow(clippy::integer_division)]`
 
 error: integer division
-  --> tests/ui/integer_division.rs:8:13
+  --> tests/ui/integer_division.rs:12:13
    |
 LL |     let o = 1 / two;
    |             ^^^^^^^
@@ -17,12 +17,20 @@ LL |     let o = 1 / two;
    = help: division of integers may cause loss of precision. consider using floats
 
 error: integer division
-  --> tests/ui/integer_division.rs:11:13
+  --> tests/ui/integer_division.rs:15:13
    |
 LL |     let p = two / 4;
    |             ^^^^^^^
    |
    = help: division of integers may cause loss of precision. consider using floats
 
-error: aborting due to 3 previous errors
+error: integer division
+  --> tests/ui/integer_division.rs:21:13
+   |
+LL |     let s = a / TWO;
+   |             ^^^^^^^
+   |
+   = help: division of integers may cause loss of precision. consider using floats
+
+error: aborting due to 4 previous errors
 

From 38d2387f691df3554a7ac6de2645711c85becb85 Mon Sep 17 00:00:00 2001
From: Samuel Tardieu 
Date: Thu, 8 May 2025 11:23:46 +0200
Subject: [PATCH 2064/4206] Simplify `is_simple_break_expr`

This is shorter, and also avoids overloading the `peel_blocks()` from
`clippy_utils` with different semantics.
---
 clippy_lints/src/loops/while_let_loop.rs | 22 ++++++----------------
 1 file changed, 6 insertions(+), 16 deletions(-)

diff --git a/clippy_lints/src/loops/while_let_loop.rs b/clippy_lints/src/loops/while_let_loop.rs
index bd04827a1f0ea..0032dc3d7a48e 100644
--- a/clippy_lints/src/loops/while_let_loop.rs
+++ b/clippy_lints/src/loops/while_let_loop.rs
@@ -42,27 +42,17 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_blo
     }
 }
 
-/// Returns `true` if expr contains a single break expression without a label or eub-expression.
+/// Returns `true` if expr contains a single break expression without a label or sub-expression,
+/// possibly embedded in blocks.
 fn is_simple_break_expr(e: &Expr<'_>) -> bool {
-    matches!(peel_blocks(e).kind, ExprKind::Break(dest, None) if dest.label.is_none())
-}
-
-/// Removes any blocks containing only a single expression.
-fn peel_blocks<'tcx>(e: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
     if let ExprKind::Block(b, _) = e.kind {
         match (b.stmts, b.expr) {
-            ([s], None) => {
-                if let StmtKind::Expr(e) | StmtKind::Semi(e) = s.kind {
-                    peel_blocks(e)
-                } else {
-                    e
-                }
-            },
-            ([], Some(e)) => peel_blocks(e),
-            _ => e,
+            ([s], None) => matches!(s.kind, StmtKind::Expr(e) | StmtKind::Semi(e) if is_simple_break_expr(e)),
+            ([], Some(e)) => is_simple_break_expr(e),
+            _ => false,
         }
     } else {
-        e
+        matches!(e.kind, ExprKind::Break(dest, None) if dest.label.is_none())
     }
 }
 

From a07c71d77303330c10069d545652ed299a805a69 Mon Sep 17 00:00:00 2001
From: Stan Manilov 
Date: Thu, 8 May 2025 16:36:53 +0300
Subject: [PATCH 2065/4206] Fix minor typo in installation.md

---
 src/doc/rustc-dev-guide/src/autodiff/installation.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/doc/rustc-dev-guide/src/autodiff/installation.md b/src/doc/rustc-dev-guide/src/autodiff/installation.md
index f3c11395523bf..971d07bfa39a4 100644
--- a/src/doc/rustc-dev-guide/src/autodiff/installation.md
+++ b/src/doc/rustc-dev-guide/src/autodiff/installation.md
@@ -1,6 +1,6 @@
 # Installation
 
-In the near future, `std::autodiff` should become available in nightly builds for users. As a contribute however, you will still need to build rustc from source. Please be aware that the msvc target is not supported at the moment, all other tier 1 targets should work. Please open an issue if you encounter any problems on a supported tier 1 target, or if you succesfully build this project on a tier2/tier3 target.
+In the near future, `std::autodiff` should become available in nightly builds for users. As a contributor however, you will still need to build rustc from source. Please be aware that the msvc target is not supported at the moment, all other tier 1 targets should work. Please open an issue if you encounter any problems on a supported tier 1 target, or if you succesfully build this project on a tier2/tier3 target.
 
 ## Build instructions
 

From 82f8b1ccd09e94a6f3cb880de0d4ca99fd7bb9aa Mon Sep 17 00:00:00 2001
From: Samuel Tardieu 
Date: Thu, 8 May 2025 15:55:02 +0200
Subject: [PATCH 2066/4206] Do not pretend that `return` is not significant

A `return` in an expression makes it divergent and cannot be removed
blindly. While this stripping might have been introduced as a way to
catch more cases, it was improperly used, and no tests exhibit a
failure when this special handling is removed.
---
 clippy_lints/src/matches/needless_match.rs | 18 ++++--------------
 tests/ui/needless_match.fixed              | 12 ++++++++++++
 tests/ui/needless_match.rs                 | 15 +++++++++++++++
 tests/ui/needless_match.stderr             | 12 +++++++++++-
 4 files changed, 42 insertions(+), 15 deletions(-)

diff --git a/clippy_lints/src/matches/needless_match.rs b/clippy_lints/src/matches/needless_match.rs
index 6c5d7cab2036e..b04db03f8d2e7 100644
--- a/clippy_lints/src/matches/needless_match.rs
+++ b/clippy_lints/src/matches/needless_match.rs
@@ -74,7 +74,7 @@ fn check_all_arms(cx: &LateContext<'_>, match_expr: &Expr<'_>, arms: &[Arm<'_>])
         }
 
         if let PatKind::Wild = arm.pat.kind {
-            if !eq_expr_value(cx, match_expr, strip_return(arm_expr)) {
+            if !eq_expr_value(cx, match_expr, arm_expr) {
                 return false;
             }
         } else if !pat_same_as_expr(arm.pat, arm_expr) {
@@ -103,27 +103,18 @@ fn check_if_let_inner(cx: &LateContext<'_>, if_let: &higher::IfLet<'_>) -> bool
             if matches!(else_expr.kind, ExprKind::Block(..)) {
                 return false;
             }
-            let ret = strip_return(else_expr);
             let let_expr_ty = cx.typeck_results().expr_ty(if_let.let_expr);
             if is_type_diagnostic_item(cx, let_expr_ty, sym::Option) {
-                return is_res_lang_ctor(cx, path_res(cx, ret), OptionNone) || eq_expr_value(cx, if_let.let_expr, ret);
+                return is_res_lang_ctor(cx, path_res(cx, else_expr), OptionNone)
+                    || eq_expr_value(cx, if_let.let_expr, else_expr);
             }
-            return eq_expr_value(cx, if_let.let_expr, ret);
+            return eq_expr_value(cx, if_let.let_expr, else_expr);
         }
     }
 
     false
 }
 
-/// Strip `return` keyword if the expression type is `ExprKind::Ret`.
-fn strip_return<'hir>(expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
-    if let ExprKind::Ret(Some(ret)) = expr.kind {
-        ret
-    } else {
-        expr
-    }
-}
-
 /// Manually check for coercion casting by checking if the type of the match operand or let expr
 /// differs with the assigned local variable or the function return type.
 fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_>) -> bool {
@@ -161,7 +152,6 @@ fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_>
 }
 
 fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
-    let expr = strip_return(expr);
     match (&pat.kind, &expr.kind) {
         // Example: `Some(val) => Some(val)`
         (PatKind::TupleStruct(QPath::Resolved(_, path), tuple_params, _), ExprKind::Call(call_expr, call_params)) => {
diff --git a/tests/ui/needless_match.fixed b/tests/ui/needless_match.fixed
index b2c2bbfaa3613..41acf44023f63 100644
--- a/tests/ui/needless_match.fixed
+++ b/tests/ui/needless_match.fixed
@@ -301,4 +301,16 @@ pub fn issue13574() -> Option<()> {
     None
 }
 
+fn issue14754(t: Result) -> Result {
+    let _ = match t {
+        Ok(v) => Ok::<_, &'static str>(v),
+        err @ Err(_) => return err,
+    };
+    println!("Still here");
+    let x = t;
+    //~^^^^ needless_match
+    println!("Still here");
+    x
+}
+
 fn main() {}
diff --git a/tests/ui/needless_match.rs b/tests/ui/needless_match.rs
index 1cb670edc60fb..936653b961bbb 100644
--- a/tests/ui/needless_match.rs
+++ b/tests/ui/needless_match.rs
@@ -364,4 +364,19 @@ pub fn issue13574() -> Option<()> {
     None
 }
 
+fn issue14754(t: Result) -> Result {
+    let _ = match t {
+        Ok(v) => Ok::<_, &'static str>(v),
+        err @ Err(_) => return err,
+    };
+    println!("Still here");
+    let x = match t {
+        Ok(v) => Ok::<_, &'static str>(v),
+        err @ Err(_) => err,
+    };
+    //~^^^^ needless_match
+    println!("Still here");
+    x
+}
+
 fn main() {}
diff --git a/tests/ui/needless_match.stderr b/tests/ui/needless_match.stderr
index 719b0ef884696..5195ecdfa555e 100644
--- a/tests/ui/needless_match.stderr
+++ b/tests/ui/needless_match.stderr
@@ -151,5 +151,15 @@ LL | |             None
 LL | |         }
    | |_________^ help: replace it with: `A`
 
-error: aborting due to 14 previous errors
+error: this match expression is unnecessary
+  --> tests/ui/needless_match.rs:373:13
+   |
+LL |       let x = match t {
+   |  _____________^
+LL | |         Ok(v) => Ok::<_, &'static str>(v),
+LL | |         err @ Err(_) => err,
+LL | |     };
+   | |_____^ help: replace it with: `t`
+
+error: aborting due to 15 previous errors
 

From c70dc4554c1866584ad637863750600d6864826d Mon Sep 17 00:00:00 2001
From: Ralf Jung 
Date: Thu, 8 May 2025 16:13:41 +0200
Subject: [PATCH 2067/4206] remove stray stderr file

---
 .../fail/weak_memory/racing_mixed_size.stderr | 22 -------------------
 1 file changed, 22 deletions(-)
 delete mode 100644 src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr

diff --git a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr
deleted file mode 100644
index a437ca3425853..0000000000000
--- a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error: Undefined Behavior: Race condition detected between (1) 4-byte atomic store on thread `unnamed-ID` and (2) 2-byte atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here
-  --> tests/fail/weak_memory/racing_mixed_size.rs:LL:CC
-   |
-LL |             std::intrinsics::atomic_load_relaxed(hi);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 4-byte atomic store on thread `unnamed-ID` and (2) 2-byte atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here
-   |
-help: and (1) occurred earlier here
-  --> tests/fail/weak_memory/racing_mixed_size.rs:LL:CC
-   |
-LL |         x.store(1, Relaxed);
-   |         ^^^^^^^^^^^^^^^^^^^
-   = help: overlapping unsynchronized atomic accesses must use the same access size
-   = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model
-   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
-   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
-   = note: BACKTRACE (of the first span) on thread `unnamed-ID`:
-   = note: inside closure at tests/fail/weak_memory/racing_mixed_size.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-

From 8930c41034176644eaede7ecb65f2c31111b9b2e Mon Sep 17 00:00:00 2001
From: Ralf Jung 
Date: Thu, 8 May 2025 16:14:13 +0200
Subject: [PATCH 2068/4206] remove commented-out test leftover

---
 src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs b/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs
index c2b6a7e68be50..c76e7f2eebd2c 100644
--- a/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs
+++ b/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs
@@ -12,7 +12,6 @@ fn main() {
     mut_raw_mut();
     partially_invalidate_mut();
     drop_after_sharing();
-    // direct_mut_to_const_raw();
     two_raw();
     shr_and_raw();
     disjoint_mutable_subborrows();

From 656a59e40f792233be25e310d5d533d1d12ed1fd Mon Sep 17 00:00:00 2001
From: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com>
Date: Thu, 8 May 2025 23:37:47 +0900
Subject: [PATCH 2069/4206] add assert to check ast_index smaller than
 INNER_ATTR_SET_BIT

Signed-off-by: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com>
---
 .../crates/hir-expand/src/attrs.rs            | 22 ++++++++-----------
 1 file changed, 9 insertions(+), 13 deletions(-)

diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
index 4e519452aa69b..94c97713f0650 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
@@ -123,15 +123,15 @@ impl RawAttrs {
             (None, entries @ Some(_)) => Self { entries },
             (Some(entries), None) => Self { entries: Some(entries.clone()) },
             (Some(a), Some(b)) => {
-                let last_ast_index = a.slice.last().map_or(0, |it| it.id.ast_index() + 1) as u32;
+                let last_ast_index = a.slice.last().map_or(0, |it| it.id.ast_index() + 1);
                 let items = a
                     .slice
                     .iter()
                     .cloned()
                     .chain(b.slice.iter().map(|it| {
                         let mut it = it.clone();
-                        let id = it.id.ast_index() as u32 + last_ast_index;
-                        it.id = AttrId::new(id as usize, it.id.is_inner_attr());
+                        let id = it.id.ast_index() + last_ast_index;
+                        it.id = AttrId::new(id, it.id.is_inner_attr());
                         it
                     }))
                     .collect::>();
@@ -175,24 +175,20 @@ pub struct AttrId {
 // FIXME: This only handles a single level of cfg_attr nesting
 // that is `#[cfg_attr(all(), cfg_attr(all(), cfg(any())))]` breaks again
 impl AttrId {
-    const INNER_ATTR_SET_BIT: usize = 1 << 31;
+    const INNER_ATTR_SET_BIT: u32 = 1 << 31;
 
     pub fn new(id: usize, is_inner: bool) -> Self {
-        Self {
-            id: if is_inner {
-                id | Self::INNER_ATTR_SET_BIT
-            } else {
-                id & !Self::INNER_ATTR_SET_BIT
-            } as u32,
-        }
+        assert!(id <= !Self::INNER_ATTR_SET_BIT as usize);
+        let id = id as u32;
+        Self { id: if is_inner { id | Self::INNER_ATTR_SET_BIT } else { id } }
     }
 
     pub fn ast_index(&self) -> usize {
-        self.id as usize & !Self::INNER_ATTR_SET_BIT
+        (self.id & !Self::INNER_ATTR_SET_BIT) as usize
     }
 
     pub fn is_inner_attr(&self) -> bool {
-        (self.id as usize) & Self::INNER_ATTR_SET_BIT != 0
+        self.id & Self::INNER_ATTR_SET_BIT != 0
     }
 }
 

From 31ebe11f61dc56018c3919dae140d9e89b2238a5 Mon Sep 17 00:00:00 2001
From: lcnr 
Date: Tue, 6 May 2025 18:39:07 +0000
Subject: [PATCH 2070/4206] normalization: avoid incompletely constraining GAT
 args

---
 .../src/solve/assembly/mod.rs                 | 23 +++++------
 .../src/solve/effect_goals.rs                 |  5 ++-
 .../src/solve/normalizes_to/mod.rs            | 38 +++++++++++++++++--
 .../src/solve/trait_goals.rs                  |  7 ++--
 .../src/traits/select/mod.rs                  |  7 ++--
 compiler/rustc_type_ir/src/inherent.rs        |  8 ++++
 compiler/rustc_type_ir/src/predicate.rs       |  7 ++++
 .../guide-inference-in-gat-arg-deeper.rs      |  6 ++-
 .../no-incomplete-gat-arg-inference.rs        | 33 ++++++++++++++++
 9 files changed, 111 insertions(+), 23 deletions(-)
 create mode 100644 tests/ui/generic-associated-types/no-incomplete-gat-arg-inference.rs

diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index 345a272895d39..579be70fccf17 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -117,6 +117,8 @@ where
     ) -> Result, NoSolution> {
         Self::fast_reject_assumption(ecx, goal, assumption)?;
 
+        // Dealing with `ParamEnv` candidates is a bit of a mess as we need to lazily
+        // check whether the candidate is global.
         ecx.probe(|candidate: &Result, NoSolution>| match candidate {
             Ok(candidate) => inspect::ProbeKind::TraitCandidate {
                 source: candidate.source,
@@ -128,12 +130,12 @@ where
             },
         })
         .enter(|ecx| {
-            Self::match_assumption(ecx, goal, assumption)?;
-            let source = ecx.characterize_param_env_assumption(goal.param_env, assumption)?;
-            Ok(Candidate {
-                source,
-                result: ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)?,
-            })
+            let mut source = CandidateSource::ParamEnv(ParamEnvSource::Global);
+            let result = Self::match_assumption(ecx, goal, assumption, |ecx| {
+                source = ecx.characterize_param_env_assumption(goal.param_env, assumption)?;
+                ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+            })?;
+            Ok(Candidate { source, result })
         })
     }
 
@@ -150,10 +152,8 @@ where
     ) -> Result, NoSolution> {
         Self::fast_reject_assumption(ecx, goal, assumption)?;
 
-        ecx.probe_trait_candidate(source).enter(|ecx| {
-            Self::match_assumption(ecx, goal, assumption)?;
-            then(ecx)
-        })
+        ecx.probe_trait_candidate(source)
+            .enter(|ecx| Self::match_assumption(ecx, goal, assumption, then))
     }
 
     /// Try to reject the assumption based off of simple heuristics, such as [`ty::ClauseKind`]
@@ -169,7 +169,8 @@ where
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal,
         assumption: I::Clause,
-    ) -> Result<(), NoSolution>;
+        then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult,
+    ) -> QueryResult;
 
     fn consider_impl_candidate(
         ecx: &mut EvalCtxt<'_, D>,
diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
index 84a83d79cf046..8413c2abbb969 100644
--- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
@@ -61,13 +61,14 @@ where
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal,
         assumption: I::Clause,
-    ) -> Result<(), NoSolution> {
+        then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult,
+    ) -> QueryResult {
         let host_clause = assumption.as_host_effect_clause().unwrap();
 
         let assumption_trait_pred = ecx.instantiate_binder_with_infer(host_clause);
         ecx.eq(goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref)?;
 
-        Ok(())
+        then(ecx)
     }
 
     /// Register additional assumptions for aliases corresponding to `~const` item bounds.
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
index b90e34e78101c..2fddc0044cb9e 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
@@ -129,7 +129,40 @@ where
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal,
         assumption: I::Clause,
-    ) -> Result<(), NoSolution> {
+        then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult,
+    ) -> QueryResult {
+        let cx = ecx.cx();
+        // FIXME(generic_associated_types): Addresses aggressive inference in #92917.
+        //
+        // If this type is a GAT with currently unconstrained arguments, we do not
+        // want to normalize it via a candidate which only applies for a specific
+        // instantiation. We could otherwise keep the GAT as rigid and succeed this way.
+        // See tests/ui/generic-associated-types/no-incomplete-gat-arg-inference.rs.
+        //
+        // This only avoids normalization if the GAT arguments are fully unconstrained.
+        // This is quite arbitrary but fixing it causes some ambiguity, see #125196.
+        match goal.predicate.alias.kind(cx) {
+            ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => {
+                for arg in goal.predicate.alias.own_args(cx).iter() {
+                    let Some(term) = arg.as_term() else {
+                        continue;
+                    };
+                    let term = ecx.structurally_normalize_term(goal.param_env, term)?;
+                    if term.is_infer() {
+                        return ecx.evaluate_added_goals_and_make_canonical_response(
+                            Certainty::AMBIGUOUS,
+                        );
+                    }
+                }
+            }
+            ty::AliasTermKind::OpaqueTy
+            | ty::AliasTermKind::InherentTy
+            | ty::AliasTermKind::InherentConst
+            | ty::AliasTermKind::FreeTy
+            | ty::AliasTermKind::FreeConst
+            | ty::AliasTermKind::UnevaluatedConst => {}
+        }
+
         let projection_pred = assumption.as_projection_clause().unwrap();
 
         let assumption_projection_pred = ecx.instantiate_binder_with_infer(projection_pred);
@@ -139,7 +172,6 @@ where
 
         // Add GAT where clauses from the trait's definition
         // FIXME: We don't need these, since these are the type's own WF obligations.
-        let cx = ecx.cx();
         ecx.add_goals(
             GoalSource::AliasWellFormed,
             cx.own_predicates_of(goal.predicate.def_id())
@@ -147,7 +179,7 @@ where
                 .map(|pred| goal.with(cx, pred)),
         );
 
-        Ok(())
+        then(ecx)
     }
 
     fn consider_additional_alias_assumptions(
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index e3addf8bf93fc..966d5422fbb7b 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -17,7 +17,7 @@ use crate::solve::assembly::{self, AllowInferenceConstraints, AssembleCandidates
 use crate::solve::inspect::ProbeKind;
 use crate::solve::{
     BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
-    NoSolution, ParamEnvSource,
+    NoSolution, ParamEnvSource, QueryResult,
 };
 
 impl assembly::GoalKind for TraitPredicate
@@ -150,13 +150,14 @@ where
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal,
         assumption: I::Clause,
-    ) -> Result<(), NoSolution> {
+        then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult,
+    ) -> QueryResult {
         let trait_clause = assumption.as_trait_clause().unwrap();
 
         let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause);
         ecx.eq(goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref)?;
 
-        Ok(())
+        then(ecx)
     }
 
     fn consider_auto_trait_candidate(
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 4ce37db428002..77c24adabe3a5 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1760,12 +1760,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         if is_match {
             let generics = self.tcx().generics_of(obligation.predicate.def_id);
-            // FIXME(generic-associated-types): Addresses aggressive inference in #92917.
+            // FIXME(generic_associated_types): Addresses aggressive inference in #92917.
             // If this type is a GAT, and of the GAT args resolve to something new,
             // that means that we must have newly inferred something about the GAT.
             // We should give up in that case.
-            // FIXME(generic-associated-types): This only detects one layer of inference,
-            // which is probably not what we actually want, but fixing it causes some ambiguity:
+            //
+            // This only detects one layer of inference, which is probably not what we actually
+            // want, but fixing it causes some ambiguity:
             // .
             if !generics.is_own_empty()
                 && obligation.predicate.args[generics.parent_count..].iter().any(|&p| {
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index e6e6466766beb..ee4a8096462a0 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -298,6 +298,14 @@ pub trait GenericArg>:
     + From
     + From
 {
+    fn as_term(&self) -> Option {
+        match self.kind() {
+            ty::GenericArgKind::Lifetime(_) => None,
+            ty::GenericArgKind::Type(ty) => Some(ty.into()),
+            ty::GenericArgKind::Const(ct) => Some(ct.into()),
+        }
+    }
+
     fn as_type(&self) -> Option {
         if let ty::GenericArgKind::Type(ty) = self.kind() { Some(ty) } else { None }
     }
diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs
index b59495b93c836..f02d9c988c8de 100644
--- a/compiler/rustc_type_ir/src/predicate.rs
+++ b/compiler/rustc_type_ir/src/predicate.rs
@@ -682,6 +682,13 @@ impl AliasTerm {
     pub fn trait_ref(self, interner: I) -> TraitRef {
         self.trait_ref_and_own_args(interner).0
     }
+
+    /// Extract the own args from this projection.
+    /// For example, if this is a projection of `::Item<'a>`,
+    /// then this function would return the slice `['a]` as the own args.
+    pub fn own_args(self, interner: I) -> I::GenericArgsSlice {
+        self.trait_ref_and_own_args(interner).1
+    }
 }
 
 /// The following methods work only with inherent associated term projections.
diff --git a/tests/ui/generic-associated-types/guide-inference-in-gat-arg-deeper.rs b/tests/ui/generic-associated-types/guide-inference-in-gat-arg-deeper.rs
index 96a0f2f40bf49..82ffa0221b997 100644
--- a/tests/ui/generic-associated-types/guide-inference-in-gat-arg-deeper.rs
+++ b/tests/ui/generic-associated-types/guide-inference-in-gat-arg-deeper.rs
@@ -1,5 +1,9 @@
-// Fix for .
 //@ check-pass
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+// Fix for .
 
 trait Tr {
     type Gat;
diff --git a/tests/ui/generic-associated-types/no-incomplete-gat-arg-inference.rs b/tests/ui/generic-associated-types/no-incomplete-gat-arg-inference.rs
new file mode 100644
index 0000000000000..0c25c64224b1d
--- /dev/null
+++ b/tests/ui/generic-associated-types/no-incomplete-gat-arg-inference.rs
@@ -0,0 +1,33 @@
+//@ check-pass
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+// Regression test for trait-system-refactor-initiative#202. We have
+// to make sure we don't constrain ambiguous GAT args when normalizing
+// via where bounds or item bounds.
+
+trait Trait {
+    type Assoc;
+}
+
+fn ret(x: U) -> ::Assoc {
+    loop {}
+}
+
+fn where_bound = u32>>() {
+    let inf = Default::default();
+    let x = ret::(inf);
+    let _: i32 = inf;
+}
+
+trait ItemBound {
+    type Bound: Trait = u32>;
+}
+fn item_bound() {
+    let inf = Default::default();
+    let x = ret::(inf);
+    let _: i32 = inf;
+}
+
+fn main() {}

From 01854845bcf4aea41ddb5da889708ca53e025537 Mon Sep 17 00:00:00 2001
From: lcnr 
Date: Thu, 8 May 2025 14:49:52 +0000
Subject: [PATCH 2071/4206] refactor `probe_and_consider_param_env_candidate`

---
 .../src/solve/assembly/mod.rs                 | 29 +++++++++----------
 1 file changed, 14 insertions(+), 15 deletions(-)

diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index 579be70fccf17..542e212e1bfb1 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -2,6 +2,7 @@
 
 pub(super) mod structural_traits;
 
+use std::cell::Cell;
 use std::ops::ControlFlow;
 
 use derive_where::derive_where;
@@ -118,25 +119,23 @@ where
         Self::fast_reject_assumption(ecx, goal, assumption)?;
 
         // Dealing with `ParamEnv` candidates is a bit of a mess as we need to lazily
-        // check whether the candidate is global.
-        ecx.probe(|candidate: &Result, NoSolution>| match candidate {
-            Ok(candidate) => inspect::ProbeKind::TraitCandidate {
-                source: candidate.source,
-                result: Ok(candidate.result),
-            },
-            Err(NoSolution) => inspect::ProbeKind::TraitCandidate {
-                source: CandidateSource::ParamEnv(ParamEnvSource::Global),
-                result: Err(NoSolution),
-            },
+        // check whether the candidate is global while considering normalization.
+        //
+        // We need to write into `source` inside of `match_assumption`, but need to access it
+        // in `probe` even if the candidate does not apply before we get there. We handle this
+        // by using a `Cell` here. We only ever write into it inside of `match_assumption`.
+        let source = Cell::new(CandidateSource::ParamEnv(ParamEnvSource::Global));
+        ecx.probe(|result: &QueryResult| inspect::ProbeKind::TraitCandidate {
+            source: source.get(),
+            result: *result,
         })
         .enter(|ecx| {
-            let mut source = CandidateSource::ParamEnv(ParamEnvSource::Global);
-            let result = Self::match_assumption(ecx, goal, assumption, |ecx| {
-                source = ecx.characterize_param_env_assumption(goal.param_env, assumption)?;
+            Self::match_assumption(ecx, goal, assumption, |ecx| {
+                source.set(ecx.characterize_param_env_assumption(goal.param_env, assumption)?);
                 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-            })?;
-            Ok(Candidate { source, result })
+            })
         })
+        .map(|result| Candidate { source: source.get(), result })
     }
 
     /// Try equating an assumption predicate against a goal's predicate. If it

From 070fee2df3edadbf580bf4fc8dcbc0bafe20ac97 Mon Sep 17 00:00:00 2001
From: est31 
Date: Wed, 7 May 2025 01:52:09 +0200
Subject: [PATCH 2072/4206] Update miri, cargo-miri and miri-cript to edition
 2024

Also update the format edition to 2024
---
 src/tools/miri/Cargo.toml                                 | 2 +-
 src/tools/miri/cargo-miri/Cargo.toml                      | 2 +-
 src/tools/miri/miri-script/Cargo.toml                     | 2 +-
 src/tools/miri/miri-script/src/util.rs                    | 2 +-
 src/tools/miri/src/bin/miri.rs                            | 2 +-
 .../miri/src/borrow_tracker/tree_borrows/diagnostics.rs   | 2 +-
 src/tools/miri/src/diagnostics.rs                         | 3 +--
 src/tools/miri/tests/pass/coroutine.rs                    | 8 ++++----
 8 files changed, 11 insertions(+), 12 deletions(-)

diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml
index 7b7be97aa518f..e4d7abdb0f73e 100644
--- a/src/tools/miri/Cargo.toml
+++ b/src/tools/miri/Cargo.toml
@@ -6,7 +6,7 @@ name = "miri"
 repository = "https://github.com/rust-lang/miri"
 version = "0.1.0"
 default-run = "miri"
-edition = "2021"
+edition = "2024"
 
 [lib]
 test = true     # we have unit tests
diff --git a/src/tools/miri/cargo-miri/Cargo.toml b/src/tools/miri/cargo-miri/Cargo.toml
index ed142b0e2114d..23048914af18e 100644
--- a/src/tools/miri/cargo-miri/Cargo.toml
+++ b/src/tools/miri/cargo-miri/Cargo.toml
@@ -5,7 +5,7 @@ license = "MIT OR Apache-2.0"
 name = "cargo-miri"
 repository = "https://github.com/rust-lang/miri"
 version = "0.1.0"
-edition = "2021"
+edition = "2024"
 
 [[bin]]
 name = "cargo-miri"
diff --git a/src/tools/miri/miri-script/Cargo.toml b/src/tools/miri/miri-script/Cargo.toml
index a04898de6abab..462a9cc62bff0 100644
--- a/src/tools/miri/miri-script/Cargo.toml
+++ b/src/tools/miri/miri-script/Cargo.toml
@@ -6,7 +6,7 @@ name = "miri-script"
 repository = "https://github.com/rust-lang/miri"
 version = "0.1.0"
 default-run = "miri-script"
-edition = "2021"
+edition = "2024"
 
 [workspace]
 # We make this a workspace root so that cargo does not go looking in ../Cargo.toml for the workspace root.
diff --git a/src/tools/miri/miri-script/src/util.rs b/src/tools/miri/miri-script/src/util.rs
index c039b4827ee34..5c2a055990fdd 100644
--- a/src/tools/miri/miri-script/src/util.rs
+++ b/src/tools/miri/miri-script/src/util.rs
@@ -213,7 +213,7 @@ impl MiriEnv {
             let toolchain = &self.toolchain;
             let mut cmd = cmd!(
                 self.sh,
-                "rustfmt +{toolchain} --edition=2021 --config-path {config_path} --unstable-features --skip-children {flags...}"
+                "rustfmt +{toolchain} --edition=2024 --config-path {config_path} --unstable-features --skip-children {flags...}"
             );
             if first {
                 // Log an abbreviating command, and only once.
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 69aa035fdc3df..eb5111774a001 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -459,7 +459,7 @@ fn jemalloc_magic() {
     // linking, so we need to explicitly depend on the function.
     #[cfg(target_os = "macos")]
     {
-        extern "C" {
+        unsafe extern "C" {
             fn _rjem_je_zone_register();
         }
 
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
index b2fd9b2bf054a..f5a0013047aae 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
@@ -179,7 +179,7 @@ impl NodeDebugInfo {
     /// Add a name to the tag. If a same tag is associated to several pointers,
     /// it can have several names which will be separated by commas.
     pub fn add_name(&mut self, name: &str) {
-        if let Some(ref mut prev_name) = &mut self.name {
+        if let Some(prev_name) = &mut self.name {
             prev_name.push_str(", ");
             prev_name.push_str(name);
         } else {
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 89768077d8780..10570a37e5d86 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -648,8 +648,7 @@ impl<'tcx> MiriMachine<'tcx> {
             AccessedAlloc(AllocId(id), access_kind) =>
                 format!("{access_kind} to allocation with id {id}"),
             FreedAlloc(AllocId(id)) => format!("freed allocation with id {id}"),
-            RejectedIsolatedOp(ref op) =>
-                format!("{op} was made to return an error due to isolation"),
+            RejectedIsolatedOp(op) => format!("{op} was made to return an error due to isolation"),
             ProgressReport { .. } =>
                 format!("progress report: current operation being executed is here"),
             Int2Ptr { .. } => format!("integer-to-pointer cast"),
diff --git a/src/tools/miri/tests/pass/coroutine.rs b/src/tools/miri/tests/pass/coroutine.rs
index 9ec9b1fc5bc48..96b60b515cb6d 100644
--- a/src/tools/miri/tests/pass/coroutine.rs
+++ b/src/tools/miri/tests/pass/coroutine.rs
@@ -183,18 +183,18 @@ fn basic() {
 
 fn smoke_resume_arg() {
     fn drain + Unpin, R, Y>(
-        gen: &mut G,
+        gen_: &mut G,
         inout: Vec<(R, CoroutineState)>,
     ) where
         Y: Debug + PartialEq,
         G::Return: Debug + PartialEq,
     {
-        let mut gen = Pin::new(gen);
+        let mut gen_ = Pin::new(gen_);
 
         for (input, out) in inout {
-            assert_eq!(gen.as_mut().resume(input), out);
+            assert_eq!(gen_.as_mut().resume(input), out);
             // Test if the coroutine is valid (according to type invariants).
-            let _ = unsafe { ManuallyDrop::new(ptr::read(gen.as_mut().get_unchecked_mut())) };
+            let _ = unsafe { ManuallyDrop::new(ptr::read(gen_.as_mut().get_unchecked_mut())) };
         }
     }
 

From 292ecd52429c337156601449fc67daccdd82ae9f Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Thu, 8 May 2025 16:18:40 +0000
Subject: [PATCH 2073/4206] Remove some unnecessary erases

---
 compiler/rustc_hir_typeck/src/cast.rs                         | 4 ----
 compiler/rustc_middle/src/ty/print/pretty.rs                  | 2 --
 compiler/rustc_mir_transform/src/add_subtyping_projections.rs | 2 +-
 3 files changed, 1 insertion(+), 7 deletions(-)

diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 5bfc3e810d9fd..c044c4f7c37de 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -490,11 +490,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                         && let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::From)
                     {
                         let ty = fcx.resolve_vars_if_possible(self.cast_ty);
-                        // Erase regions to avoid panic in `prove_value` when calling
-                        // `type_implements_trait`.
-                        let ty = fcx.tcx.erase_regions(ty);
                         let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
-                        let expr_ty = fcx.tcx.erase_regions(expr_ty);
                         if fcx
                             .infcx
                             .type_implements_trait(from_trait, [ty, expr_ty], fcx.param_env)
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 0250c777faf79..6fd6aff0e2b23 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1453,9 +1453,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                                 // contain named regions. So we erase and anonymize everything
                                 // here to compare the types modulo regions below.
                                 let proj = cx.tcx().erase_regions(proj);
-                                let proj = cx.tcx().anonymize_bound_vars(proj);
                                 let super_proj = cx.tcx().erase_regions(super_proj);
-                                let super_proj = cx.tcx().anonymize_bound_vars(super_proj);
 
                                 proj == super_proj
                             });
diff --git a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs
index b5cd41334598b..92ee80eaa353e 100644
--- a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs
+++ b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs
@@ -32,7 +32,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeChecker<'a, 'tcx> {
         let mut rval_ty = rvalue.ty(self.local_decls, self.tcx);
         // Not erasing this causes `Free Regions` errors in validator,
         // when rval is `ReStatic`.
-        rval_ty = self.tcx.erase_regions_ty(rval_ty);
+        rval_ty = self.tcx.erase_regions(rval_ty);
         place_ty = self.tcx.erase_regions(place_ty);
         if place_ty != rval_ty {
             let temp = self

From a1234d3b5edd156a77f2747587b838c740004e2a Mon Sep 17 00:00:00 2001
From: est31 
Date: Thu, 8 May 2025 19:08:31 +0200
Subject: [PATCH 2074/4206] Remove let_chains feature as it is stable

---
 src/tools/miri/src/lib.rs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 58b93ae82a1e4..0b7a067058b99 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -9,7 +9,6 @@
 #![feature(variant_count)]
 #![feature(yeet_expr)]
 #![feature(nonzero_ops)]
-#![feature(let_chains)]
 #![feature(strict_overflow_ops)]
 #![feature(pointer_is_aligned_to)]
 #![feature(unqualified_local_imports)]

From b73d3b4384e65ab3d0d7af0e2d2f6c07ef1620aa Mon Sep 17 00:00:00 2001
From: relaxcn 
Date: Fri, 9 May 2025 01:21:14 +0800
Subject: [PATCH 2075/4206] fix issue-14725

---
 clippy_lints/src/unwrap.rs                    |  6 ++-
 .../ui/checked_unwrap/simple_conditionals.rs  | 52 +++++++++++++++++++
 .../checked_unwrap/simple_conditionals.stderr | 37 ++++++++++++-
 3 files changed, 92 insertions(+), 3 deletions(-)

diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs
index ba140788bb54e..f152d62bf4950 100644
--- a/clippy_lints/src/unwrap.rs
+++ b/clippy_lints/src/unwrap.rs
@@ -224,8 +224,10 @@ impl<'tcx> Delegate<'tcx> for MutationVisitor<'tcx> {
         }
     }
 
-    fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {
-        self.is_mutated = true;
+    fn mutate(&mut self, cat: &PlaceWithHirId<'tcx>, _: HirId) {
+        if is_potentially_local_place(self.local_id, &cat.place) {
+            self.is_mutated = true;
+        }
     }
 
     fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
diff --git a/tests/ui/checked_unwrap/simple_conditionals.rs b/tests/ui/checked_unwrap/simple_conditionals.rs
index 4101897d38004..5589d8cc429ca 100644
--- a/tests/ui/checked_unwrap/simple_conditionals.rs
+++ b/tests/ui/checked_unwrap/simple_conditionals.rs
@@ -188,6 +188,58 @@ fn issue11371() {
     }
 }
 
+fn gen_option() -> Option<()> {
+    Some(())
+    // Or None
+}
+
+fn gen_result() -> Result<(), ()> {
+    Ok(())
+    // Or Err(())
+}
+
+fn issue14725() {
+    let option = Some(());
+
+    if option.is_some() {
+        let _ = option.as_ref().unwrap();
+        //~^ unnecessary_unwrap
+    } else {
+        let _ = option.as_ref().unwrap();
+        //~^ panicking_unwrap
+    }
+
+    let result = Ok::<(), ()>(());
+
+    if result.is_ok() {
+        let _y = 1;
+        result.as_ref().unwrap();
+        //~^ unnecessary_unwrap
+    } else {
+        let _y = 1;
+        result.as_ref().unwrap();
+        //~^ panicking_unwrap
+    }
+
+    let mut option = Some(());
+    if option.is_some() {
+        option = gen_option();
+        option.as_mut().unwrap();
+    } else {
+        option = gen_option();
+        option.as_mut().unwrap();
+    }
+
+    let mut result = Ok::<(), ()>(());
+    if result.is_ok() {
+        result = gen_result();
+        result.as_mut().unwrap();
+    } else {
+        result = gen_result();
+        result.as_mut().unwrap();
+    }
+}
+
 fn check_expect() {
     let x = Some(());
     if x.is_some() {
diff --git a/tests/ui/checked_unwrap/simple_conditionals.stderr b/tests/ui/checked_unwrap/simple_conditionals.stderr
index ad3c420270c14..82a36aa5029fe 100644
--- a/tests/ui/checked_unwrap/simple_conditionals.stderr
+++ b/tests/ui/checked_unwrap/simple_conditionals.stderr
@@ -236,6 +236,41 @@ LL |     if result.is_ok() {
 LL |         result.as_mut().unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
+error: called `unwrap` on `option` after checking its variant with `is_some`
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:205:17
+   |
+LL |     if option.is_some() {
+   |     ------------------- help: try: `if let Some() = &option`
+LL |         let _ = option.as_ref().unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this call to `unwrap()` will always panic
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:208:17
+   |
+LL |     if option.is_some() {
+   |        ---------------- because of this check
+...
+LL |         let _ = option.as_ref().unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: called `unwrap` on `result` after checking its variant with `is_ok`
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:216:9
+   |
+LL |     if result.is_ok() {
+   |     ----------------- help: try: `if let Ok() = &result`
+LL |         let _y = 1;
+LL |         result.as_ref().unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this call to `unwrap()` will always panic
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:220:9
+   |
+LL |     if result.is_ok() {
+   |        -------------- because of this check
+...
+LL |         result.as_ref().unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
 error: creating a shared reference to mutable static
   --> tests/ui/checked_unwrap/simple_conditionals.rs:183:12
    |
@@ -246,5 +281,5 @@ LL |         if X.is_some() {
    = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
    = note: `#[deny(static_mut_refs)]` on by default
 
-error: aborting due to 26 previous errors
+error: aborting due to 30 previous errors
 

From 71e767f3405ed454ad14d9b339f5a44f064e49d2 Mon Sep 17 00:00:00 2001
From: Jane Losare-Lusby 
Date: Thu, 8 May 2025 09:40:34 -0700
Subject: [PATCH 2076/4206] also export metrics from librustdoc

---
 src/librustdoc/lib.rs | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index bca40b8117bdb..59ea2b1e3a415 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -73,9 +73,11 @@ extern crate tikv_jemalloc_sys as jemalloc_sys;
 
 use std::env::{self, VarError};
 use std::io::{self, IsTerminal};
+use std::path::Path;
 use std::process;
 
 use rustc_errors::DiagCtxtHandle;
+use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_interface::interface;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{ErrorOutputType, RustcOptGroup, make_crate_type_option};
@@ -904,6 +906,10 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
                 rustc_interface::passes::write_dep_info(tcx);
             }
 
+            if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir {
+                dump_feature_usage_metrics(tcx, metrics_dir);
+            }
+
             if run_check {
                 // Since we're in "check" mode, no need to generate anything beyond this point.
                 return;
@@ -923,3 +929,16 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
         })
     })
 }
+
+fn dump_feature_usage_metrics(tcxt: TyCtxt<'_>, metrics_dir: &Path) {
+    let hash = tcxt.crate_hash(LOCAL_CRATE);
+    let crate_name = tcxt.crate_name(LOCAL_CRATE);
+    let metrics_file_name = format!("unstable_feature_usage_metrics-{crate_name}-{hash}.json");
+    let metrics_path = metrics_dir.join(metrics_file_name);
+    if let Err(error) = tcxt.features().dump_feature_usage_metrics(metrics_path) {
+        // FIXME(yaahc): once metrics can be enabled by default we will want "failure to emit
+        // default metrics" to only produce a warning when metrics are enabled by default and emit
+        // an error only when the user manually enables metrics
+        tcxt.dcx().err(format!("cannot emit feature usage metrics: {error}"));
+    }
+}

From b67549edd3535bf6d7fb62fce206466db78fa926 Mon Sep 17 00:00:00 2001
From: reddevilmidzy 
Date: Fri, 9 May 2025 02:26:01 +0900
Subject: [PATCH 2077/4206] Add regression test for 125877

---
 .../const-trait-impl-parameter-mismatch.rs    | 32 +++++++++++++++++++
 ...const-trait-impl-parameter-mismatch.stderr | 21 ++++++++++++
 2 files changed, 53 insertions(+)
 create mode 100644 tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs
 create mode 100644 tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.stderr

diff --git a/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs b/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs
new file mode 100644
index 0000000000000..f90ff91aff4bb
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs
@@ -0,0 +1,32 @@
+// This test demonstrates an ICE that may occur when we try to resolve the instance
+// of a impl that has different generics than the trait it's implementing. This ensures
+// we first check that the args are compatible before resolving the body, just like
+// we do in projection before substituting a GAT.
+//
+// Regression test for issue #125877.
+
+//@ compile-flags: -Znext-solver
+
+#![feature(const_trait_impl, effects)]
+//~^ ERROR feature has been removed
+
+#[const_trait]
+trait Main {
+    fn compute() -> u32;
+}
+
+impl const Main for () {
+    fn compute<'x>() -> u32 {
+        //~^ ERROR associated function `compute` has 0 type parameters but its trait declaration has 1 type parameter
+        0
+    }
+}
+
+#[const_trait]
+trait Aux {}
+
+impl const Aux for () {}
+
+fn main() {
+    const _: u32 = <()>::compute::<()>();
+}
diff --git a/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.stderr b/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.stderr
new file mode 100644
index 0000000000000..d45c4cba1f8b5
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.stderr
@@ -0,0 +1,21 @@
+error[E0557]: feature has been removed
+  --> $DIR/const-trait-impl-parameter-mismatch.rs:10:30
+   |
+LL | #![feature(const_trait_impl, effects)]
+   |                              ^^^^^^^ feature has been removed
+   |
+   = note: removed, redundant with `#![feature(const_trait_impl)]`
+
+error[E0049]: associated function `compute` has 0 type parameters but its trait declaration has 1 type parameter
+  --> $DIR/const-trait-impl-parameter-mismatch.rs:19:16
+   |
+LL |     fn compute() -> u32;
+   |                - expected 1 type parameter
+...
+LL |     fn compute<'x>() -> u32 {
+   |                ^^ found 0 type parameters
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0049, E0557.
+For more information about an error, try `rustc --explain E0049`.

From 668a292ca33b340590631c426553265fd19339b5 Mon Sep 17 00:00:00 2001
From: Samuel Tardieu 
Date: Thu, 8 May 2025 20:42:32 +0200
Subject: [PATCH 2078/4206] `unwrap.rs`: replace some strings usage by interned
 symbols

---
 clippy_lints/src/unwrap.rs | 27 +++++++++++----------------
 1 file changed, 11 insertions(+), 16 deletions(-)

diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs
index ba140788bb54e..85330c20d38ea 100644
--- a/clippy_lints/src/unwrap.rs
+++ b/clippy_lints/src/unwrap.rs
@@ -4,15 +4,15 @@ use clippy_utils::usage::is_potentially_local_place;
 use clippy_utils::{higher, path_to_local, sym};
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn};
-use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Node, PathSegment, UnOp};
+use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Node, UnOp};
 use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceWithHirId};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::declare_lint_pass;
-use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
+use rustc_span::{Span, Symbol};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -111,7 +111,7 @@ struct UnwrapInfo<'tcx> {
     /// The check, like `x.is_ok()`
     check: &'tcx Expr<'tcx>,
     /// The check's name, like `is_ok`
-    check_name: &'tcx PathSegment<'tcx>,
+    check_name: Symbol,
     /// The branch where the check takes place, like `if x.is_ok() { .. }`
     branch: &'tcx Expr<'tcx>,
     /// Whether `is_some()` or `is_ok()` was called (as opposed to `is_err()` or `is_none()`).
@@ -133,12 +133,12 @@ fn collect_unwrap_info<'tcx>(
     invert: bool,
     is_entire_condition: bool,
 ) -> Vec> {
-    fn is_relevant_option_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: &str) -> bool {
-        is_type_diagnostic_item(cx, ty, sym::Option) && ["is_some", "is_none"].contains(&method_name)
+    fn is_relevant_option_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool {
+        is_type_diagnostic_item(cx, ty, sym::Option) && matches!(method_name, sym::is_none | sym::is_some)
     }
 
-    fn is_relevant_result_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: &str) -> bool {
-        is_type_diagnostic_item(cx, ty, sym::Result) && ["is_ok", "is_err"].contains(&method_name)
+    fn is_relevant_result_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool {
+        is_type_diagnostic_item(cx, ty, sym::Result) && matches!(method_name, sym::is_err | sym::is_ok)
     }
 
     if let ExprKind::Binary(op, left, right) = &expr.kind {
@@ -155,14 +155,10 @@ fn collect_unwrap_info<'tcx>(
     } else if let ExprKind::MethodCall(method_name, receiver, [], _) = &expr.kind
         && let Some(local_id) = path_to_local(receiver)
         && let ty = cx.typeck_results().expr_ty(receiver)
-        && let name = method_name.ident.as_str()
+        && let name = method_name.ident.name
         && (is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name))
     {
-        let unwrappable = match name {
-            "is_some" | "is_ok" => true,
-            "is_err" | "is_none" => false,
-            _ => unreachable!(),
-        };
+        let unwrappable = matches!(name, sym::is_some | sym::is_ok);
         let safe_to_unwrap = unwrappable != invert;
         let kind = if is_type_diagnostic_item(cx, ty, sym::Option) {
             UnwrappableKind::Option
@@ -174,7 +170,7 @@ fn collect_unwrap_info<'tcx>(
             local_id,
             if_expr,
             check: expr,
-            check_name: method_name,
+            check_name: name,
             branch,
             safe_to_unwrap,
             kind,
@@ -332,8 +328,7 @@ impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> {
                         expr.span,
                         format!(
                             "called `{}` on `{unwrappable_variable_name}` after checking its variant with `{}`",
-                            method_name.ident.name,
-                            unwrappable.check_name.ident.as_str(),
+                            method_name.ident.name, unwrappable.check_name,
                         ),
                         |diag| {
                             if is_entire_condition {

From 4cbd116460c795f77956f5a98891551a34ff06a6 Mon Sep 17 00:00:00 2001
From: Samuel Tardieu 
Date: Thu, 8 May 2025 20:50:51 +0200
Subject: [PATCH 2079/4206] `unwrap.rs`: internal naming cleanup

Since its conception, the lint has been extended from `Option`
only to `Option` and `Result`, but some function names and comment still
references only `Option`.

Also, one cascaded `if` was replaced by a shorter `match`.
---
 clippy_lints/src/unwrap.rs | 24 +++++++++++-------------
 1 file changed, 11 insertions(+), 13 deletions(-)

diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs
index 85330c20d38ea..44ca289577341 100644
--- a/clippy_lints/src/unwrap.rs
+++ b/clippy_lints/src/unwrap.rs
@@ -180,12 +180,12 @@ fn collect_unwrap_info<'tcx>(
     Vec::new()
 }
 
-/// A HIR visitor delegate that checks if a local variable of type `Option<_>` is mutated,
-/// *except* for if `Option::as_mut` is called.
+/// A HIR visitor delegate that checks if a local variable of type `Option` or `Result` is mutated,
+/// *except* for if `.as_mut()` is called.
 /// The reason for why we allow that one specifically is that `.as_mut()` cannot change
-/// the option to `None`, and that is important because this lint relies on the fact that
+/// the variant, and that is important because this lint relies on the fact that
 /// `is_some` + `unwrap` is equivalent to `if let Some(..) = ..`, which it would not be if
-/// the option is changed to None between `is_some` and `unwrap`.
+/// the option is changed to None between `is_some` and `unwrap`, ditto for `Result`.
 /// (And also `.as_mut()` is a somewhat common method that is still worth linting on.)
 struct MutationVisitor<'tcx> {
     is_mutated: bool,
@@ -194,13 +194,13 @@ struct MutationVisitor<'tcx> {
 }
 
 /// Checks if the parent of the expression pointed at by the given `HirId` is a call to
-/// `Option::as_mut`.
+/// `.as_mut()`.
 ///
 /// Used by the mutation visitor to specifically allow `.as_mut()` calls.
 /// In particular, the `HirId` that the visitor receives is the id of the local expression
 /// (i.e. the `x` in `x.as_mut()`), and that is the reason for why we care about its parent
 /// expression: that will be where the actual method call is.
-fn is_option_as_mut_use(tcx: TyCtxt<'_>, expr_id: HirId) -> bool {
+fn is_as_mut_use(tcx: TyCtxt<'_>, expr_id: HirId) -> bool {
     if let Node::Expr(mutating_expr) = tcx.parent_hir_node(expr_id)
         && let ExprKind::MethodCall(path, _, [], _) = mutating_expr.kind
     {
@@ -214,7 +214,7 @@ impl<'tcx> Delegate<'tcx> for MutationVisitor<'tcx> {
     fn borrow(&mut self, cat: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::BorrowKind) {
         if let ty::BorrowKind::Mutable = bk
             && is_potentially_local_place(self.local_id, &cat.place)
-            && !is_option_as_mut_use(self.tcx, diag_expr_id)
+            && !is_as_mut_use(self.tcx, diag_expr_id)
         {
             self.is_mutated = true;
         }
@@ -272,12 +272,10 @@ enum AsRefKind {
 /// If it isn't, the expression itself is returned.
 fn consume_option_as_ref<'tcx>(expr: &'tcx Expr<'tcx>) -> (&'tcx Expr<'tcx>, Option) {
     if let ExprKind::MethodCall(path, recv, [], _) = expr.kind {
-        if path.ident.name == sym::as_ref {
-            (recv, Some(AsRefKind::AsRef))
-        } else if path.ident.name == sym::as_mut {
-            (recv, Some(AsRefKind::AsMut))
-        } else {
-            (expr, None)
+        match path.ident.name {
+            sym::as_ref => (recv, Some(AsRefKind::AsRef)),
+            sym::as_mut => (recv, Some(AsRefKind::AsMut)),
+            _ => (expr, None),
         }
     } else {
         (expr, None)

From 1044e5bbcc73fb581ec1801e66ad8deb9aebf237 Mon Sep 17 00:00:00 2001
From: Samuel Tardieu 
Date: Thu, 8 May 2025 21:39:35 +0200
Subject: [PATCH 2080/4206] Set Manish in vacation mode

---
 triagebot.toml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/triagebot.toml b/triagebot.toml
index fe558e0ef8f39..e3d4507202abb 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -42,6 +42,7 @@ new_pr = true
 contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md"
 users_on_vacation = [
     "matthiaskrgr",
+    "Manishearth",
 ]
 
 [assign.owners]

From d4862eb690a759565ab64bf0142cf2e13084116c Mon Sep 17 00:00:00 2001
From: Christian Legnitto 
Date: Tue, 6 May 2025 12:15:02 -0400
Subject: [PATCH 2081/4206] Update `backtrace` in Cargo.lock

Ran `cargo update -p backtrace`. This is needed to forward port the rust-gpu compiler backend.

Subsumes https://github.com/rust-lang/rust/pull/140631. Was supposed
to be fixed by https://github.com/rust-lang/rust/pull/140353, but there
were test failures and the fix was backed out.
---
 Cargo.lock | 49 +++++++++++++++++--------------------------------
 1 file changed, 17 insertions(+), 32 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 83d7a6a9ab134..5041fa0bad02e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4,11 +4,11 @@ version = 4
 
 [[package]]
 name = "addr2line"
-version = "0.21.0"
+version = "0.24.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
+checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
 dependencies = [
- "gimli 0.28.1",
+ "gimli",
 ]
 
 [[package]]
@@ -168,7 +168,7 @@ version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "01667f6f40216b9a0b2945e05fed5f1ad0ab6470e69cb9378001e37b1c0668e4"
 dependencies = [
- "object 0.36.7",
+ "object",
 ]
 
 [[package]]
@@ -233,17 +233,17 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
 
 [[package]]
 name = "backtrace"
-version = "0.3.71"
+version = "0.3.75"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
+checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
 dependencies = [
  "addr2line",
- "cc",
  "cfg-if",
  "libc",
- "miniz_oxide 0.7.4",
- "object 0.32.2",
+ "miniz_oxide 0.8.8",
+ "object",
  "rustc-demangle",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -1453,12 +1453,6 @@ dependencies = [
  "wasi 0.14.2+wasi-0.2.4",
 ]
 
-[[package]]
-name = "gimli"
-version = "0.28.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
-
 [[package]]
 name = "gimli"
 version = "0.31.1"
@@ -2483,15 +2477,6 @@ dependencies = [
  "objc2-core-foundation",
 ]
 
-[[package]]
-name = "object"
-version = "0.32.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
-dependencies = [
- "memchr",
-]
-
 [[package]]
 name = "object"
 version = "0.36.7"
@@ -3094,9 +3079,9 @@ version = "0.2.0"
 dependencies = [
  "bstr",
  "build_helper",
- "gimli 0.31.1",
+ "gimli",
  "libc",
- "object 0.36.7",
+ "object",
  "regex",
  "serde_json",
  "similar",
@@ -3403,11 +3388,11 @@ name = "rustc_codegen_llvm"
 version = "0.0.0"
 dependencies = [
  "bitflags",
- "gimli 0.31.1",
+ "gimli",
  "itertools",
  "libc",
  "measureme",
- "object 0.36.7",
+ "object",
  "rustc-demangle",
  "rustc_abi",
  "rustc_ast",
@@ -3448,7 +3433,7 @@ dependencies = [
  "either",
  "itertools",
  "libc",
- "object 0.36.7",
+ "object",
  "pathdiff",
  "regex",
  "rustc_abi",
@@ -4465,7 +4450,7 @@ name = "rustc_target"
 version = "0.0.0"
 dependencies = [
  "bitflags",
- "object 0.36.7",
+ "object",
  "rustc_abi",
  "rustc_data_structures",
  "rustc_fs_util",
@@ -5229,9 +5214,9 @@ version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9e9c1e705f82a260173f3eec93f2ff6d7807f23ad5a8cc2e7316a891733ea7a1"
 dependencies = [
- "gimli 0.31.1",
+ "gimli",
  "hashbrown",
- "object 0.36.7",
+ "object",
  "tracing",
 ]
 

From 3a6fcd2170aef2f8096f8521870d7a655690bf80 Mon Sep 17 00:00:00 2001
From: Samuel Tardieu 
Date: Fri, 9 May 2025 01:06:00 +0200
Subject: [PATCH 2082/4206] Allow any rust-lang team member to close an issue

---
 triagebot.toml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/triagebot.toml b/triagebot.toml
index e3d4507202abb..eb2f9f9dd61f5 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -13,6 +13,8 @@ allow-unauthenticated = [
 
 [note]
 
+[close]
+
 [issue-links]
 
 # Prevents mentions in commits to avoid users being spammed

From 33f81c08aaa5701e66cad9aa3d527a683c929adc Mon Sep 17 00:00:00 2001
From: Alex Macleod 
Date: Fri, 9 May 2025 01:36:46 +0000
Subject: [PATCH 2083/4206] Use `cargo dev setup toolchain` in install from
 source docs

---
 book/src/development/basics.md | 28 +++++++++-------------------
 1 file changed, 9 insertions(+), 19 deletions(-)

diff --git a/book/src/development/basics.md b/book/src/development/basics.md
index 4219724ed5df9..cdbbe76bdb08e 100644
--- a/book/src/development/basics.md
+++ b/book/src/development/basics.md
@@ -145,42 +145,32 @@ unclear to you.
 If you are hacking on Clippy and want to install it from source, do the
 following:
 
-First, take note of the toolchain
-[override](https://rust-lang.github.io/rustup/overrides.html) in
-`/rust-toolchain.toml`. We will use this override to install Clippy into the right
-toolchain.
-
-> Tip: You can view the active toolchain for the current directory with `rustup
-> show active-toolchain`.
-
 From the Clippy project root, run the following command to build the Clippy
-binaries and copy them into the toolchain directory. This will override the
-currently installed Clippy component.
+binaries and copy them into the toolchain directory. This will create a new
+toolchain called `clippy` by default, see `cargo dev setup toolchain --help`
+for other options.
 
 ```terminal
-cargo build --release --bin cargo-clippy --bin clippy-driver -Zunstable-options --out-dir "$(rustc --print=sysroot)/bin"
+cargo dev setup toolcahin
 ```
 
-Now you may run `cargo clippy` in any project, using the toolchain where you
-just installed Clippy.
+Now you may run `cargo +clippy clippy` in any project using the new toolchain.
 
 ```terminal
 cd my-project
-cargo +nightly-2021-07-01 clippy
+cargo +clippy clippy
 ```
 
 ...or `clippy-driver`
 
 ```terminal
-clippy-driver +nightly-2021-07-01 
+clippy-driver +clippy 
 ```
 
-If you need to restore the default Clippy installation, run the following (from
-the Clippy project root).
+If you no longer need the toolchain it can be uninstalled using `rustup`:
 
 ```terminal
-rustup component remove clippy
-rustup component add clippy
+rustup toolchain uninstall clippy
 ```
 
 > **DO NOT** install using `cargo install --path . --force` since this will

From 9eac7a3e04a727bcbdb14826c6520210b3ca1d2e Mon Sep 17 00:00:00 2001
From: lcnr 
Date: Fri, 9 May 2025 02:35:18 +0000
Subject: [PATCH 2084/4206] move (and remove) impl Trait tests

---
 src/tools/tidy/src/issues.txt                 | 60 +++++++++----------
 .../arg-position-impl-trait-too-long.rs       |  0
 .../arg-position-impl-trait-too-long.stderr   |  0
 .../{ => apit}/impl-generic-mismatch-ab.rs    |  0
 .../impl-generic-mismatch-ab.stderr           |  0
 .../can-return-unconstrained-closure.rs       | 23 -------
 .../impl-trait/{ => issues}/issue-100075-2.rs |  0
 .../{ => issues}/issue-100075-2.stderr        |  0
 .../impl-trait/{ => issues}/issue-100075.rs   |  0
 .../{ => issues}/issue-100075.stderr          |  0
 .../impl-trait/{ => issues}/issue-100187.rs   |  0
 .../impl-trait/{ => issues}/issue-102605.rs   |  0
 .../{ => issues}/issue-102605.stderr          |  0
 .../issue-103181-1.current.stderr             |  0
 .../{ => issues}/issue-103181-1.next.stderr   |  0
 .../impl-trait/{ => issues}/issue-103181-1.rs |  0
 .../impl-trait/{ => issues}/issue-103181-2.rs |  0
 .../{ => issues}/issue-103181-2.stderr        |  0
 .../impl-trait/{ => issues}/issue-103599.rs   |  0
 .../{ => issues}/issue-103599.stderr          |  0
 .../impl-trait/{ => issues}/issue-108591.rs   |  0
 .../impl-trait/{ => issues}/issue-108592.rs   |  0
 .../ui/impl-trait/{ => issues}/issue-35668.rs |  0
 .../{ => issues}/issue-35668.stderr           |  0
 .../ui/impl-trait/{ => issues}/issue-36792.rs |  0
 .../ui/impl-trait/{ => issues}/issue-46959.rs |  0
 .../ui/impl-trait/{ => issues}/issue-49556.rs |  0
 .../ui/impl-trait/{ => issues}/issue-49579.rs |  0
 .../ui/impl-trait/{ => issues}/issue-49685.rs |  0
 .../ui/impl-trait/{ => issues}/issue-51185.rs |  0
 .../ui/impl-trait/{ => issues}/issue-54966.rs |  0
 .../{ => issues}/issue-54966.stderr           |  0
 .../impl-trait/{ => issues}/issue-55872-1.rs  |  0
 .../{ => issues}/issue-55872-1.stderr         |  0
 .../impl-trait/{ => issues}/issue-55872-2.rs  |  0
 .../{ => issues}/issue-55872-2.stderr         |  0
 .../impl-trait/{ => issues}/issue-55872-3.rs  |  0
 .../{ => issues}/issue-55872-3.stderr         |  0
 .../ui/impl-trait/{ => issues}/issue-55872.rs |  0
 .../{ => issues}/issue-55872.stderr           |  0
 .../ui/impl-trait/{ => issues}/issue-56445.rs |  0
 .../ui/impl-trait/{ => issues}/issue-68532.rs |  0
 .../ui/impl-trait/{ => issues}/issue-72911.rs |  0
 .../{ => issues}/issue-72911.stderr           |  0
 .../ui/impl-trait/{ => issues}/issue-87450.rs |  0
 .../{ => issues}/issue-87450.stderr           |  0
 .../impl-trait/{ => issues}/issue-99073-2.rs  |  0
 .../{ => issues}/issue-99073-2.stderr         |  0
 .../ui/impl-trait/{ => issues}/issue-99073.rs |  0
 .../{ => issues}/issue-99073.stderr           |  0
 .../impl-trait/{ => issues}/issue-99642-2.rs  |  0
 .../ui/impl-trait/{ => issues}/issue-99642.rs |  0
 .../ui/impl-trait/{ => issues}/issue-99914.rs |  0
 .../{ => issues}/issue-99914.stderr           |  0
 tests/ui/impl-trait/lifetimes2.rs             | 10 ----
 .../coherence}/coherence-treats-tait-ambig.rs |  0
 .../coherence-treats-tait-ambig.stderr        |  0
 .../method-suggestion-no-duplication.rs       |  0
 .../method-suggestion-no-duplication.stderr   |  0
 59 files changed, 30 insertions(+), 63 deletions(-)
 rename tests/ui/impl-trait/{ => apit}/arg-position-impl-trait-too-long.rs (100%)
 rename tests/ui/impl-trait/{ => apit}/arg-position-impl-trait-too-long.stderr (100%)
 rename tests/ui/impl-trait/{ => apit}/impl-generic-mismatch-ab.rs (100%)
 rename tests/ui/impl-trait/{ => apit}/impl-generic-mismatch-ab.stderr (100%)
 delete mode 100644 tests/ui/impl-trait/can-return-unconstrained-closure.rs
 rename tests/ui/impl-trait/{ => issues}/issue-100075-2.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-100075-2.stderr (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-100075.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-100075.stderr (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-100187.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-102605.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-102605.stderr (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-103181-1.current.stderr (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-103181-1.next.stderr (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-103181-1.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-103181-2.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-103181-2.stderr (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-103599.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-103599.stderr (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-108591.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-108592.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-35668.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-35668.stderr (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-36792.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-46959.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-49556.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-49579.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-49685.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-51185.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-54966.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-54966.stderr (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-55872-1.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-55872-1.stderr (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-55872-2.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-55872-2.stderr (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-55872-3.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-55872-3.stderr (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-55872.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-55872.stderr (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-56445.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-68532.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-72911.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-72911.stderr (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-87450.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-87450.stderr (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-99073-2.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-99073-2.stderr (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-99073.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-99073.stderr (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-99642-2.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-99642.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-99914.rs (100%)
 rename tests/ui/impl-trait/{ => issues}/issue-99914.stderr (100%)
 delete mode 100644 tests/ui/impl-trait/lifetimes2.rs
 rename tests/ui/{impl-trait => type-alias-impl-trait/coherence}/coherence-treats-tait-ambig.rs (100%)
 rename tests/ui/{impl-trait => type-alias-impl-trait/coherence}/coherence-treats-tait-ambig.stderr (100%)
 rename tests/ui/{impl-trait => where-clauses}/method-suggestion-no-duplication.rs (100%)
 rename tests/ui/{impl-trait => where-clauses}/method-suggestion-no-duplication.stderr (100%)

diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index 2f0158609e088..7608261453044 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -1183,47 +1183,39 @@ ui/impl-trait/explicit-generic-args-with-impl-trait/issue-87718.rs
 ui/impl-trait/in-trait/issue-102140.rs
 ui/impl-trait/in-trait/issue-102301.rs
 ui/impl-trait/in-trait/issue-102571.rs
-ui/impl-trait/issue-100075-2.rs
-ui/impl-trait/issue-100075.rs
-ui/impl-trait/issue-100187.rs
-ui/impl-trait/issue-102605.rs
-ui/impl-trait/issue-103181-1.rs
-ui/impl-trait/issue-103181-2.rs
-ui/impl-trait/issue-103599.rs
-ui/impl-trait/issue-108591.rs
-ui/impl-trait/issue-108592.rs
-ui/impl-trait/issue-35668.rs
-ui/impl-trait/issue-36792.rs
-ui/impl-trait/issue-46959.rs
-ui/impl-trait/issue-49556.rs
-ui/impl-trait/issue-49579.rs
-ui/impl-trait/issue-49685.rs
-ui/impl-trait/issue-51185.rs
-ui/impl-trait/issue-54966.rs
-ui/impl-trait/issue-55872-1.rs
-ui/impl-trait/issue-55872-2.rs
-ui/impl-trait/issue-55872-3.rs
-ui/impl-trait/issue-55872.rs
-ui/impl-trait/issue-56445.rs
-ui/impl-trait/issue-68532.rs
-ui/impl-trait/issue-72911.rs
-ui/impl-trait/issue-87450.rs
-ui/impl-trait/issue-99073-2.rs
-ui/impl-trait/issue-99073.rs
-ui/impl-trait/issue-99642-2.rs
-ui/impl-trait/issue-99642.rs
-ui/impl-trait/issue-99914.rs
+ui/impl-trait/issues/issue-100075-2.rs
+ui/impl-trait/issues/issue-100075.rs
+ui/impl-trait/issues/issue-100187.rs
+ui/impl-trait/issues/issue-102605.rs
+ui/impl-trait/issues/issue-103181-1.rs
+ui/impl-trait/issues/issue-103181-2.rs
+ui/impl-trait/issues/issue-103599.rs
 ui/impl-trait/issues/issue-104815.rs
 ui/impl-trait/issues/issue-105826.rs
+ui/impl-trait/issues/issue-108591.rs
+ui/impl-trait/issues/issue-108592.rs
 ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.rs
+ui/impl-trait/issues/issue-35668.rs
+ui/impl-trait/issues/issue-36792.rs
 ui/impl-trait/issues/issue-42479.rs
+ui/impl-trait/issues/issue-46959.rs
 ui/impl-trait/issues/issue-49376.rs
+ui/impl-trait/issues/issue-49556.rs
+ui/impl-trait/issues/issue-49579.rs
+ui/impl-trait/issues/issue-49685.rs
+ui/impl-trait/issues/issue-51185.rs
 ui/impl-trait/issues/issue-52128.rs
 ui/impl-trait/issues/issue-53457.rs
 ui/impl-trait/issues/issue-54600.rs
 ui/impl-trait/issues/issue-54840.rs
 ui/impl-trait/issues/issue-54895.rs
+ui/impl-trait/issues/issue-54966.rs
 ui/impl-trait/issues/issue-55608-captures-empty-region.rs
+ui/impl-trait/issues/issue-55872-1.rs
+ui/impl-trait/issues/issue-55872-2.rs
+ui/impl-trait/issues/issue-55872-3.rs
+ui/impl-trait/issues/issue-55872.rs
+ui/impl-trait/issues/issue-56445.rs
 ui/impl-trait/issues/issue-57464-unexpected-regions.rs
 ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs
 ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs
@@ -1233,8 +1225,10 @@ ui/impl-trait/issues/issue-58956.rs
 ui/impl-trait/issues/issue-62742.rs
 ui/impl-trait/issues/issue-65581.rs
 ui/impl-trait/issues/issue-67830.rs
+ui/impl-trait/issues/issue-68532.rs
 ui/impl-trait/issues/issue-70877.rs
 ui/impl-trait/issues/issue-70971.rs
+ui/impl-trait/issues/issue-72911.rs
 ui/impl-trait/issues/issue-74282.rs
 ui/impl-trait/issues/issue-77987.rs
 ui/impl-trait/issues/issue-78722-2.rs
@@ -1251,12 +1245,18 @@ ui/impl-trait/issues/issue-86719.rs
 ui/impl-trait/issues/issue-86800.rs
 ui/impl-trait/issues/issue-87295.rs
 ui/impl-trait/issues/issue-87340.rs
+ui/impl-trait/issues/issue-87450.rs
 ui/impl-trait/issues/issue-88236-2.rs
 ui/impl-trait/issues/issue-88236.rs
 ui/impl-trait/issues/issue-89312.rs
 ui/impl-trait/issues/issue-92305.rs
 ui/impl-trait/issues/issue-93788.rs
+ui/impl-trait/issues/issue-99073-2.rs
+ui/impl-trait/issues/issue-99073.rs
 ui/impl-trait/issues/issue-99348-impl-compatibility.rs
+ui/impl-trait/issues/issue-99642-2.rs
+ui/impl-trait/issues/issue-99642.rs
+ui/impl-trait/issues/issue-99914.rs
 ui/implied-bounds/issue-100690.rs
 ui/implied-bounds/issue-101951.rs
 ui/implied-bounds/issue-110161.rs
diff --git a/tests/ui/impl-trait/arg-position-impl-trait-too-long.rs b/tests/ui/impl-trait/apit/arg-position-impl-trait-too-long.rs
similarity index 100%
rename from tests/ui/impl-trait/arg-position-impl-trait-too-long.rs
rename to tests/ui/impl-trait/apit/arg-position-impl-trait-too-long.rs
diff --git a/tests/ui/impl-trait/arg-position-impl-trait-too-long.stderr b/tests/ui/impl-trait/apit/arg-position-impl-trait-too-long.stderr
similarity index 100%
rename from tests/ui/impl-trait/arg-position-impl-trait-too-long.stderr
rename to tests/ui/impl-trait/apit/arg-position-impl-trait-too-long.stderr
diff --git a/tests/ui/impl-trait/impl-generic-mismatch-ab.rs b/tests/ui/impl-trait/apit/impl-generic-mismatch-ab.rs
similarity index 100%
rename from tests/ui/impl-trait/impl-generic-mismatch-ab.rs
rename to tests/ui/impl-trait/apit/impl-generic-mismatch-ab.rs
diff --git a/tests/ui/impl-trait/impl-generic-mismatch-ab.stderr b/tests/ui/impl-trait/apit/impl-generic-mismatch-ab.stderr
similarity index 100%
rename from tests/ui/impl-trait/impl-generic-mismatch-ab.stderr
rename to tests/ui/impl-trait/apit/impl-generic-mismatch-ab.stderr
diff --git a/tests/ui/impl-trait/can-return-unconstrained-closure.rs b/tests/ui/impl-trait/can-return-unconstrained-closure.rs
deleted file mode 100644
index 1f8bdbc5054d8..0000000000000
--- a/tests/ui/impl-trait/can-return-unconstrained-closure.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Test that we are special casing "outlives" for opaque types.
-//
-// The return type of a closure is not required to outlive the closure. As such
-// the following code would not compile if we used a standard outlives check
-// when checking the return type, because the return type of the closure would
-// be `&ReEmpty i32`, and we don't allow `ReEmpty` to occur in the concrete
-// type used for an opaque type.
-//
-// However, opaque types are special cased to include check all regions in the
-// concrete type against the bound, which forces the return type to be
-// `&'static i32` here.
-
-//@ build-pass (FIXME(62277): could be check-pass?)
-
-fn make_identity() -> impl Sized {
-    |x: &'static i32| x
-}
-
-fn make_identity_static() -> impl Sized + 'static {
-    |x: &'static i32| x
-}
-
-fn main() {}
diff --git a/tests/ui/impl-trait/issue-100075-2.rs b/tests/ui/impl-trait/issues/issue-100075-2.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-100075-2.rs
rename to tests/ui/impl-trait/issues/issue-100075-2.rs
diff --git a/tests/ui/impl-trait/issue-100075-2.stderr b/tests/ui/impl-trait/issues/issue-100075-2.stderr
similarity index 100%
rename from tests/ui/impl-trait/issue-100075-2.stderr
rename to tests/ui/impl-trait/issues/issue-100075-2.stderr
diff --git a/tests/ui/impl-trait/issue-100075.rs b/tests/ui/impl-trait/issues/issue-100075.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-100075.rs
rename to tests/ui/impl-trait/issues/issue-100075.rs
diff --git a/tests/ui/impl-trait/issue-100075.stderr b/tests/ui/impl-trait/issues/issue-100075.stderr
similarity index 100%
rename from tests/ui/impl-trait/issue-100075.stderr
rename to tests/ui/impl-trait/issues/issue-100075.stderr
diff --git a/tests/ui/impl-trait/issue-100187.rs b/tests/ui/impl-trait/issues/issue-100187.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-100187.rs
rename to tests/ui/impl-trait/issues/issue-100187.rs
diff --git a/tests/ui/impl-trait/issue-102605.rs b/tests/ui/impl-trait/issues/issue-102605.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-102605.rs
rename to tests/ui/impl-trait/issues/issue-102605.rs
diff --git a/tests/ui/impl-trait/issue-102605.stderr b/tests/ui/impl-trait/issues/issue-102605.stderr
similarity index 100%
rename from tests/ui/impl-trait/issue-102605.stderr
rename to tests/ui/impl-trait/issues/issue-102605.stderr
diff --git a/tests/ui/impl-trait/issue-103181-1.current.stderr b/tests/ui/impl-trait/issues/issue-103181-1.current.stderr
similarity index 100%
rename from tests/ui/impl-trait/issue-103181-1.current.stderr
rename to tests/ui/impl-trait/issues/issue-103181-1.current.stderr
diff --git a/tests/ui/impl-trait/issue-103181-1.next.stderr b/tests/ui/impl-trait/issues/issue-103181-1.next.stderr
similarity index 100%
rename from tests/ui/impl-trait/issue-103181-1.next.stderr
rename to tests/ui/impl-trait/issues/issue-103181-1.next.stderr
diff --git a/tests/ui/impl-trait/issue-103181-1.rs b/tests/ui/impl-trait/issues/issue-103181-1.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-103181-1.rs
rename to tests/ui/impl-trait/issues/issue-103181-1.rs
diff --git a/tests/ui/impl-trait/issue-103181-2.rs b/tests/ui/impl-trait/issues/issue-103181-2.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-103181-2.rs
rename to tests/ui/impl-trait/issues/issue-103181-2.rs
diff --git a/tests/ui/impl-trait/issue-103181-2.stderr b/tests/ui/impl-trait/issues/issue-103181-2.stderr
similarity index 100%
rename from tests/ui/impl-trait/issue-103181-2.stderr
rename to tests/ui/impl-trait/issues/issue-103181-2.stderr
diff --git a/tests/ui/impl-trait/issue-103599.rs b/tests/ui/impl-trait/issues/issue-103599.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-103599.rs
rename to tests/ui/impl-trait/issues/issue-103599.rs
diff --git a/tests/ui/impl-trait/issue-103599.stderr b/tests/ui/impl-trait/issues/issue-103599.stderr
similarity index 100%
rename from tests/ui/impl-trait/issue-103599.stderr
rename to tests/ui/impl-trait/issues/issue-103599.stderr
diff --git a/tests/ui/impl-trait/issue-108591.rs b/tests/ui/impl-trait/issues/issue-108591.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-108591.rs
rename to tests/ui/impl-trait/issues/issue-108591.rs
diff --git a/tests/ui/impl-trait/issue-108592.rs b/tests/ui/impl-trait/issues/issue-108592.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-108592.rs
rename to tests/ui/impl-trait/issues/issue-108592.rs
diff --git a/tests/ui/impl-trait/issue-35668.rs b/tests/ui/impl-trait/issues/issue-35668.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-35668.rs
rename to tests/ui/impl-trait/issues/issue-35668.rs
diff --git a/tests/ui/impl-trait/issue-35668.stderr b/tests/ui/impl-trait/issues/issue-35668.stderr
similarity index 100%
rename from tests/ui/impl-trait/issue-35668.stderr
rename to tests/ui/impl-trait/issues/issue-35668.stderr
diff --git a/tests/ui/impl-trait/issue-36792.rs b/tests/ui/impl-trait/issues/issue-36792.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-36792.rs
rename to tests/ui/impl-trait/issues/issue-36792.rs
diff --git a/tests/ui/impl-trait/issue-46959.rs b/tests/ui/impl-trait/issues/issue-46959.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-46959.rs
rename to tests/ui/impl-trait/issues/issue-46959.rs
diff --git a/tests/ui/impl-trait/issue-49556.rs b/tests/ui/impl-trait/issues/issue-49556.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-49556.rs
rename to tests/ui/impl-trait/issues/issue-49556.rs
diff --git a/tests/ui/impl-trait/issue-49579.rs b/tests/ui/impl-trait/issues/issue-49579.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-49579.rs
rename to tests/ui/impl-trait/issues/issue-49579.rs
diff --git a/tests/ui/impl-trait/issue-49685.rs b/tests/ui/impl-trait/issues/issue-49685.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-49685.rs
rename to tests/ui/impl-trait/issues/issue-49685.rs
diff --git a/tests/ui/impl-trait/issue-51185.rs b/tests/ui/impl-trait/issues/issue-51185.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-51185.rs
rename to tests/ui/impl-trait/issues/issue-51185.rs
diff --git a/tests/ui/impl-trait/issue-54966.rs b/tests/ui/impl-trait/issues/issue-54966.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-54966.rs
rename to tests/ui/impl-trait/issues/issue-54966.rs
diff --git a/tests/ui/impl-trait/issue-54966.stderr b/tests/ui/impl-trait/issues/issue-54966.stderr
similarity index 100%
rename from tests/ui/impl-trait/issue-54966.stderr
rename to tests/ui/impl-trait/issues/issue-54966.stderr
diff --git a/tests/ui/impl-trait/issue-55872-1.rs b/tests/ui/impl-trait/issues/issue-55872-1.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-55872-1.rs
rename to tests/ui/impl-trait/issues/issue-55872-1.rs
diff --git a/tests/ui/impl-trait/issue-55872-1.stderr b/tests/ui/impl-trait/issues/issue-55872-1.stderr
similarity index 100%
rename from tests/ui/impl-trait/issue-55872-1.stderr
rename to tests/ui/impl-trait/issues/issue-55872-1.stderr
diff --git a/tests/ui/impl-trait/issue-55872-2.rs b/tests/ui/impl-trait/issues/issue-55872-2.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-55872-2.rs
rename to tests/ui/impl-trait/issues/issue-55872-2.rs
diff --git a/tests/ui/impl-trait/issue-55872-2.stderr b/tests/ui/impl-trait/issues/issue-55872-2.stderr
similarity index 100%
rename from tests/ui/impl-trait/issue-55872-2.stderr
rename to tests/ui/impl-trait/issues/issue-55872-2.stderr
diff --git a/tests/ui/impl-trait/issue-55872-3.rs b/tests/ui/impl-trait/issues/issue-55872-3.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-55872-3.rs
rename to tests/ui/impl-trait/issues/issue-55872-3.rs
diff --git a/tests/ui/impl-trait/issue-55872-3.stderr b/tests/ui/impl-trait/issues/issue-55872-3.stderr
similarity index 100%
rename from tests/ui/impl-trait/issue-55872-3.stderr
rename to tests/ui/impl-trait/issues/issue-55872-3.stderr
diff --git a/tests/ui/impl-trait/issue-55872.rs b/tests/ui/impl-trait/issues/issue-55872.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-55872.rs
rename to tests/ui/impl-trait/issues/issue-55872.rs
diff --git a/tests/ui/impl-trait/issue-55872.stderr b/tests/ui/impl-trait/issues/issue-55872.stderr
similarity index 100%
rename from tests/ui/impl-trait/issue-55872.stderr
rename to tests/ui/impl-trait/issues/issue-55872.stderr
diff --git a/tests/ui/impl-trait/issue-56445.rs b/tests/ui/impl-trait/issues/issue-56445.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-56445.rs
rename to tests/ui/impl-trait/issues/issue-56445.rs
diff --git a/tests/ui/impl-trait/issue-68532.rs b/tests/ui/impl-trait/issues/issue-68532.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-68532.rs
rename to tests/ui/impl-trait/issues/issue-68532.rs
diff --git a/tests/ui/impl-trait/issue-72911.rs b/tests/ui/impl-trait/issues/issue-72911.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-72911.rs
rename to tests/ui/impl-trait/issues/issue-72911.rs
diff --git a/tests/ui/impl-trait/issue-72911.stderr b/tests/ui/impl-trait/issues/issue-72911.stderr
similarity index 100%
rename from tests/ui/impl-trait/issue-72911.stderr
rename to tests/ui/impl-trait/issues/issue-72911.stderr
diff --git a/tests/ui/impl-trait/issue-87450.rs b/tests/ui/impl-trait/issues/issue-87450.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-87450.rs
rename to tests/ui/impl-trait/issues/issue-87450.rs
diff --git a/tests/ui/impl-trait/issue-87450.stderr b/tests/ui/impl-trait/issues/issue-87450.stderr
similarity index 100%
rename from tests/ui/impl-trait/issue-87450.stderr
rename to tests/ui/impl-trait/issues/issue-87450.stderr
diff --git a/tests/ui/impl-trait/issue-99073-2.rs b/tests/ui/impl-trait/issues/issue-99073-2.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-99073-2.rs
rename to tests/ui/impl-trait/issues/issue-99073-2.rs
diff --git a/tests/ui/impl-trait/issue-99073-2.stderr b/tests/ui/impl-trait/issues/issue-99073-2.stderr
similarity index 100%
rename from tests/ui/impl-trait/issue-99073-2.stderr
rename to tests/ui/impl-trait/issues/issue-99073-2.stderr
diff --git a/tests/ui/impl-trait/issue-99073.rs b/tests/ui/impl-trait/issues/issue-99073.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-99073.rs
rename to tests/ui/impl-trait/issues/issue-99073.rs
diff --git a/tests/ui/impl-trait/issue-99073.stderr b/tests/ui/impl-trait/issues/issue-99073.stderr
similarity index 100%
rename from tests/ui/impl-trait/issue-99073.stderr
rename to tests/ui/impl-trait/issues/issue-99073.stderr
diff --git a/tests/ui/impl-trait/issue-99642-2.rs b/tests/ui/impl-trait/issues/issue-99642-2.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-99642-2.rs
rename to tests/ui/impl-trait/issues/issue-99642-2.rs
diff --git a/tests/ui/impl-trait/issue-99642.rs b/tests/ui/impl-trait/issues/issue-99642.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-99642.rs
rename to tests/ui/impl-trait/issues/issue-99642.rs
diff --git a/tests/ui/impl-trait/issue-99914.rs b/tests/ui/impl-trait/issues/issue-99914.rs
similarity index 100%
rename from tests/ui/impl-trait/issue-99914.rs
rename to tests/ui/impl-trait/issues/issue-99914.rs
diff --git a/tests/ui/impl-trait/issue-99914.stderr b/tests/ui/impl-trait/issues/issue-99914.stderr
similarity index 100%
rename from tests/ui/impl-trait/issue-99914.stderr
rename to tests/ui/impl-trait/issues/issue-99914.stderr
diff --git a/tests/ui/impl-trait/lifetimes2.rs b/tests/ui/impl-trait/lifetimes2.rs
deleted file mode 100644
index facf2f75bc4d0..0000000000000
--- a/tests/ui/impl-trait/lifetimes2.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-//@ check-pass
-
-pub fn keys<'a>(x: &'a Result) -> impl std::fmt::Debug + 'a {
-    match x {
-        Ok(map) => Ok(map),
-        Err(map) => Err(map),
-    }
-}
-
-fn main() {}
diff --git a/tests/ui/impl-trait/coherence-treats-tait-ambig.rs b/tests/ui/type-alias-impl-trait/coherence/coherence-treats-tait-ambig.rs
similarity index 100%
rename from tests/ui/impl-trait/coherence-treats-tait-ambig.rs
rename to tests/ui/type-alias-impl-trait/coherence/coherence-treats-tait-ambig.rs
diff --git a/tests/ui/impl-trait/coherence-treats-tait-ambig.stderr b/tests/ui/type-alias-impl-trait/coherence/coherence-treats-tait-ambig.stderr
similarity index 100%
rename from tests/ui/impl-trait/coherence-treats-tait-ambig.stderr
rename to tests/ui/type-alias-impl-trait/coherence/coherence-treats-tait-ambig.stderr
diff --git a/tests/ui/impl-trait/method-suggestion-no-duplication.rs b/tests/ui/where-clauses/method-suggestion-no-duplication.rs
similarity index 100%
rename from tests/ui/impl-trait/method-suggestion-no-duplication.rs
rename to tests/ui/where-clauses/method-suggestion-no-duplication.rs
diff --git a/tests/ui/impl-trait/method-suggestion-no-duplication.stderr b/tests/ui/where-clauses/method-suggestion-no-duplication.stderr
similarity index 100%
rename from tests/ui/impl-trait/method-suggestion-no-duplication.stderr
rename to tests/ui/where-clauses/method-suggestion-no-duplication.stderr

From 72393a672d5ffc6f02bd10d71c37715bded3dbfd Mon Sep 17 00:00:00 2001
From: WANG Rui 
Date: Tue, 18 Mar 2025 13:37:40 +0800
Subject: [PATCH 2085/4206] Partially stabilize LoongArch target features

---
 compiler/rustc_target/src/target_features.rs | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 5a21925ba04e7..5428aa4cf7085 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -693,17 +693,17 @@ static CSKY_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
 
 static LOONGARCH_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("d", Unstable(sym::loongarch_target_feature), &["f"]),
+    ("d", Stable, &["f"]),
     ("div32", Unstable(sym::loongarch_target_feature), &[]),
-    ("f", Unstable(sym::loongarch_target_feature), &[]),
-    ("frecipe", Unstable(sym::loongarch_target_feature), &[]),
+    ("f", Stable, &[]),
+    ("frecipe", Stable, &[]),
     ("lam-bh", Unstable(sym::loongarch_target_feature), &[]),
     ("lamcas", Unstable(sym::loongarch_target_feature), &[]),
-    ("lasx", Unstable(sym::loongarch_target_feature), &["lsx"]),
-    ("lbt", Unstable(sym::loongarch_target_feature), &[]),
+    ("lasx", Stable, &["lsx"]),
+    ("lbt", Stable, &[]),
     ("ld-seq-sa", Unstable(sym::loongarch_target_feature), &[]),
-    ("lsx", Unstable(sym::loongarch_target_feature), &["d"]),
-    ("lvz", Unstable(sym::loongarch_target_feature), &[]),
+    ("lsx", Stable, &["d"]),
+    ("lvz", Stable, &[]),
     ("relax", Unstable(sym::loongarch_target_feature), &[]),
     ("scq", Unstable(sym::loongarch_target_feature), &[]),
     ("ual", Unstable(sym::loongarch_target_feature), &[]),

From 4a662c25dc0715a2ab5ef91dfb8cb869d1ae0d7c Mon Sep 17 00:00:00 2001
From: WANG Rui 
Date: Fri, 9 May 2025 11:26:08 +0800
Subject: [PATCH 2086/4206] Update target feature tests

---
 ...bi-required-target-feature-flag-disable.loongarch.stderr | 6 +-----
 .../abi-required-target-feature-flag-disable.rs             | 2 +-
 2 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/tests/ui/target-feature/abi-required-target-feature-flag-disable.loongarch.stderr b/tests/ui/target-feature/abi-required-target-feature-flag-disable.loongarch.stderr
index 35102e0571f43..a69544a34c9af 100644
--- a/tests/ui/target-feature/abi-required-target-feature-flag-disable.loongarch.stderr
+++ b/tests/ui/target-feature/abi-required-target-feature-flag-disable.loongarch.stderr
@@ -3,9 +3,5 @@ warning: target feature `d` must be enabled to ensure that the ABI of the curren
    = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #116344 
 
-warning: unstable feature specified for `-Ctarget-feature`: `d`
-   |
-   = note: this feature is not stably supported; its behavior can change in the future
-
-warning: 2 warnings emitted
+warning: 1 warning emitted
 
diff --git a/tests/ui/target-feature/abi-required-target-feature-flag-disable.rs b/tests/ui/target-feature/abi-required-target-feature-flag-disable.rs
index c3ce05baa64b9..98723e99c36e3 100644
--- a/tests/ui/target-feature/abi-required-target-feature-flag-disable.rs
+++ b/tests/ui/target-feature/abi-required-target-feature-flag-disable.rs
@@ -24,4 +24,4 @@
 pub trait Sized {}
 
 //~? WARN must be enabled to ensure that the ABI of the current target can be implemented correctly
-//[x86,riscv,loongarch]~? WARN unstable feature specified for `-Ctarget-feature`
+//[x86,riscv]~? WARN unstable feature specified for `-Ctarget-feature`

From 767d64da45cef73a2241630da9ddfbc29bd525be Mon Sep 17 00:00:00 2001
From: Pietro Albini 
Date: Fri, 9 May 2025 11:13:08 +0200
Subject: [PATCH 2087/4206] bump version number to 1.89.0

---
 src/version | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/version b/src/version
index 59be592144c28..636ea711ad968 100644
--- a/src/version
+++ b/src/version
@@ -1 +1 @@
-1.88.0
+1.89.0

From 7dae31828baaeb26f913dcad6c83bbed5a8700b4 Mon Sep 17 00:00:00 2001
From: Jieyou Xu 
Date: Wed, 20 Nov 2024 20:29:01 +0800
Subject: [PATCH 2088/4206] Disarm `time` bomb (diagnostics)

Revert "Rollup merge of #129343 - estebank:time-version, r=jieyouxu"

This reverts commit 26f75a65d70773e4520634b9f6599ddf08c499e6, reversing
changes made to 2572e0e8c9d5d671eccb1d5791e55c929c4720f4.

Imports are modified to fix merge conflicts and remove unused ones.
---
 compiler/rustc_span/src/symbol.rs             |  1 -
 compiler/rustc_trait_selection/messages.ftl   |  2 -
 .../error_reporting/infer/need_type_info.rs   | 46 +------------------
 compiler/rustc_trait_selection/src/errors.rs  |  2 -
 ...d-time-version-format_description-parse.rs | 13 ------
 ...me-version-format_description-parse.stderr | 14 ------
 6 files changed, 2 insertions(+), 76 deletions(-)
 delete mode 100644 tests/ui/inference/detect-old-time-version-format_description-parse.rs
 delete mode 100644 tests/ui/inference/detect-old-time-version-format_description-parse.stderr

diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index f2f6d1a3bcf83..b6cb6113f9fc3 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -2099,7 +2099,6 @@ symbols! {
         three_way_compare,
         thumb2,
         thumb_mode: "thumb-mode",
-        time,
         tmm_reg,
         to_owned_method,
         to_string,
diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl
index cf6dd40718b3d..00922c6038eee 100644
--- a/compiler/rustc_trait_selection/messages.ftl
+++ b/compiler/rustc_trait_selection/messages.ftl
@@ -452,8 +452,6 @@ trait_selection_type_annotations_needed = {$source_kind ->
 }
     .label = type must be known at this point
 
-trait_selection_type_annotations_needed_error_time = this is an inference error on crate `time` caused by an API change in Rust 1.80.0; update `time` to version `>=0.3.35` by calling `cargo update`
-
 trait_selection_types_declared_different = these two types are declared with different lifetimes...
 
 trait_selection_unable_to_construct_constant_value = unable to construct a constant value for the unevaluated constant {$unevaluated}
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
index de9a50f196234..cb1c9c7536903 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
@@ -6,7 +6,7 @@ use rustc_errors::codes::*;
 use rustc_errors::{Diag, IntoDiagArg};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
-use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, LetStmt, LocalSource};
 use rustc_middle::bug;
@@ -17,7 +17,7 @@ use rustc_middle::ty::{
     self, GenericArg, GenericArgKind, GenericArgsRef, InferConst, IsSuggestable, Term, TermKind,
     Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, TypeckResults,
 };
-use rustc_span::{BytePos, DUMMY_SP, FileName, Ident, Span, sym};
+use rustc_span::{BytePos, DUMMY_SP, Ident, Span, sym};
 use tracing::{debug, instrument, warn};
 
 use super::nice_region_error::placeholder_error::Highlighted;
@@ -438,7 +438,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 bad_label,
                 was_written: false,
                 path: Default::default(),
-                time_version: false,
             }),
             TypeAnnotationNeeded::E0283 => self.dcx().create_err(AmbiguousImpl {
                 span,
@@ -630,10 +629,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 }
             }
         }
-
-        let time_version =
-            self.detect_old_time_crate_version(failure_span, &kind, &mut infer_subdiags);
-
         match error_code {
             TypeAnnotationNeeded::E0282 => self.dcx().create_err(AnnotationRequired {
                 span,
@@ -645,7 +640,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 bad_label: None,
                 was_written: path.is_some(),
                 path: path.unwrap_or_default(),
-                time_version,
             }),
             TypeAnnotationNeeded::E0283 => self.dcx().create_err(AmbiguousImpl {
                 span,
@@ -671,42 +665,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }),
         }
     }
-
-    /// Detect the inference regression on crate `time` <= 0.3.35 and emit a more targeted error.
-    /// 
-    // FIXME: we should figure out a more generic version of doing this, ideally in cargo itself.
-    fn detect_old_time_crate_version(
-        &self,
-        span: Option,
-        kind: &InferSourceKind<'_>,
-        // We will clear the non-actionable suggestion from the error to reduce noise.
-        infer_subdiags: &mut Vec>,
-    ) -> bool {
-        // FIXME(#129461): We are time-boxing this code in the compiler. It'll start failing
-        // compilation once we promote 1.89 to beta, which will happen in 9 months from now.
-        #[cfg(not(version("1.89")))]
-        const fn version_check() {}
-        #[cfg(version("1.89"))]
-        const fn version_check() {
-            panic!("remove this check as presumably the ecosystem has moved from needing it");
-        }
-        const { version_check() };
-        // Only relevant when building the `time` crate.
-        if self.infcx.tcx.crate_name(LOCAL_CRATE) == sym::time
-            && let Some(span) = span
-            && let InferSourceKind::LetBinding { pattern_name, .. } = kind
-            && let Some(name) = pattern_name
-            && name.as_str() == "items"
-            && let FileName::Real(file) = self.infcx.tcx.sess.source_map().span_to_filename(span)
-        {
-            let path = file.local_path_if_available().to_string_lossy();
-            if path.contains("format_description") && path.contains("parse") {
-                infer_subdiags.clear();
-                return true;
-            }
-        }
-        false
-    }
 }
 
 #[derive(Debug)]
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index 04cae1c9b6419..8ab4d795c4597 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -219,8 +219,6 @@ pub struct AnnotationRequired<'a> {
     #[note(trait_selection_full_type_written)]
     pub was_written: bool,
     pub path: PathBuf,
-    #[note(trait_selection_type_annotations_needed_error_time)]
-    pub time_version: bool,
 }
 
 // Copy of `AnnotationRequired` for E0283
diff --git a/tests/ui/inference/detect-old-time-version-format_description-parse.rs b/tests/ui/inference/detect-old-time-version-format_description-parse.rs
deleted file mode 100644
index 386b2a3bf3c8a..0000000000000
--- a/tests/ui/inference/detect-old-time-version-format_description-parse.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-#![crate_name = "time"]
-#![crate_type = "lib"]
-
-// This code compiled without error in Rust 1.79, but started failing in 1.80
-// after the addition of several `impl FromIterator<_> for Box`.
-
-pub fn parse() -> Option> {
-    let iter = std::iter::once(Some(())).map(|o| o.map(Into::into));
-    let items = iter.collect::>>()?; //~ ERROR E0282
-    //~^ NOTE this is an inference error on crate `time` caused by an API change in Rust 1.80.0; update `time` to version `>=0.3.35`
-    Some(items.into())
-    //~^ NOTE type must be known at this point
-}
diff --git a/tests/ui/inference/detect-old-time-version-format_description-parse.stderr b/tests/ui/inference/detect-old-time-version-format_description-parse.stderr
deleted file mode 100644
index a70ce9dd2681c..0000000000000
--- a/tests/ui/inference/detect-old-time-version-format_description-parse.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0282]: type annotations needed for `Box<_>`
-  --> $DIR/detect-old-time-version-format_description-parse.rs:9:9
-   |
-LL |     let items = iter.collect::>>()?;
-   |         ^^^^^
-LL |
-LL |     Some(items.into())
-   |                ---- type must be known at this point
-   |
-   = note: this is an inference error on crate `time` caused by an API change in Rust 1.80.0; update `time` to version `>=0.3.35` by calling `cargo update`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0282`.

From 8c8225afe8777a93aa635a252fb6a785d30d0527 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= 
Date: Fri, 9 May 2025 10:36:07 +0200
Subject: [PATCH 2089/4206] Remove mono item collection strategy override from
 -Zprint-mono-items

Previously `-Zprint-mono-items` would override the mono item collection
strategy. When debugging one doesn't want to change the behaviour, so
this was counter productive. Additionally, the produced behaviour was
artificial and might never arise without using the option in the first
place (`-Zprint-mono-items=eager` without `-Clink-dead-code`).  Finally,
the option was incorrectly marked as `UNTRACKED`.

Resolve those issues, by turning `-Zprint-mono-items` into a boolean
flag that prints results of mono item collection without changing the
behaviour of mono item collection.

For codegen-units test incorporate `-Zprint-mono-items` flag directly
into compiletest tool.

Test changes are mechanical. `-Zprint-mono-items=lazy` was removed
without additional changes, and `-Zprint-mono-items=eager` was turned
into `-Clink-dead-code`.  Linking dead code disables internalization, so
tests have been updated accordingly.
---
 compiler/rustc_interface/src/tests.rs         |  2 +-
 compiler/rustc_monomorphize/messages.ftl      |  3 --
 compiler/rustc_monomorphize/src/errors.rs     |  6 ----
 .../rustc_monomorphize/src/partitioning.rs    | 29 ++++---------------
 compiler/rustc_session/src/options.rs         |  6 ++--
 .../rustc-dev-guide/src/tests/compiletest.md  |  8 ++---
 src/tools/compiletest/src/runtest.rs          |  5 +++-
 .../codegen-units/item-collection/asm-sym.rs  |  2 +-
 .../codegen-units/item-collection/closures.rs |  2 +-
 .../item-collection/cross-crate-closures.rs   | 10 +++----
 .../cross-crate-generic-functions.rs          |  2 +-
 .../cross-crate-trait-method.rs               |  2 +-
 .../item-collection/drop-glue-eager.rs        |  2 +-
 .../drop_in_place_intrinsic.rs                |  2 +-
 .../item-collection/function-as-argument.rs   |  2 +-
 .../item-collection/generic-drop-glue.rs      |  2 +-
 .../item-collection/generic-functions.rs      |  2 +-
 .../item-collection/generic-impl.rs           |  2 +-
 .../impl-in-non-instantiated-generic.rs       |  2 +-
 .../item-collection/implicit-panic-call.rs    |  2 --
 .../instantiation-through-vtable.rs           |  6 ++--
 .../items-within-generic-items.rs             |  2 +-
 .../item-collection/non-generic-closures.rs   | 24 +++++++--------
 .../item-collection/non-generic-drop-glue.rs  |  2 +-
 .../item-collection/non-generic-functions.rs  |  2 +-
 .../item-collection/overloaded-operators.rs   |  2 +-
 .../item-collection/static-init.rs            |  2 +-
 .../item-collection/statics-and-consts.rs     |  2 +-
 .../item-collection/trait-implementations.rs  |  2 +-
 .../trait-method-as-argument.rs               |  2 +-
 .../trait-method-default-impl.rs              |  2 +-
 .../item-collection/transitive-drop-glue.rs   |  2 +-
 .../item-collection/tuple-drop-glue.rs        |  2 +-
 .../item-collection/unreferenced-const-fn.rs  |  2 --
 .../unreferenced-inline-function.rs           |  2 --
 .../codegen-units/item-collection/unsizing.rs |  1 -
 .../unused-traits-and-generics.rs             |  2 +-
 tests/codegen-units/partitioning/README.md    |  3 +-
 .../partitioning/extern-drop-glue.rs          |  2 +-
 .../partitioning/extern-generic.rs            |  2 +-
 .../partitioning/incremental-merging.rs       |  2 +-
 .../partitioning/inline-always.rs             |  2 +-
 .../inlining-from-extern-crate.rs             |  2 +-
 .../partitioning/local-drop-glue.rs           |  2 +-
 .../partitioning/local-generic.rs             |  2 +-
 .../partitioning/local-transitive-inlining.rs |  2 +-
 .../methods-are-with-self-type.rs             |  2 +-
 .../partitioning/regular-modules.rs           |  2 +-
 .../partitioning/shared-generics.rs           |  2 +-
 tests/codegen-units/partitioning/statics.rs   |  2 +-
 .../partitioning/vtable-through-const.rs      |  2 +-
 tests/crashes/114198-2.rs                     |  2 +-
 tests/crashes/114198.rs                       |  2 +-
 53 files changed, 74 insertions(+), 111 deletions(-)

diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 0ceda2201344e..068d96c860f57 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -720,7 +720,7 @@ fn test_unstable_options_tracking_hash() {
     untracked!(pre_link_args, vec![String::from("abc"), String::from("def")]);
     untracked!(print_codegen_stats, true);
     untracked!(print_llvm_passes, true);
-    untracked!(print_mono_items, Some(String::from("abc")));
+    untracked!(print_mono_items, true);
     untracked!(print_type_sizes, true);
     untracked!(proc_macro_backtrace, true);
     untracked!(proc_macro_execution_strategy, ProcMacroExecutionStrategy::CrossThread);
diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl
index 6b6653e7de021..35bedf4318ffa 100644
--- a/compiler/rustc_monomorphize/messages.ftl
+++ b/compiler/rustc_monomorphize/messages.ftl
@@ -60,9 +60,6 @@ monomorphize_start_not_found = using `fn main` requires the standard library
 
 monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined
 
-monomorphize_unknown_cgu_collection_mode =
-    unknown codegen-item collection mode '{$mode}', falling back to 'lazy' mode
-
 monomorphize_wasm_c_abi_transition =
     this function {$is_call ->
       [true] call
diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs
index 0dd20bbb35f8a..acf77b5916e4c 100644
--- a/compiler/rustc_monomorphize/src/errors.rs
+++ b/compiler/rustc_monomorphize/src/errors.rs
@@ -64,12 +64,6 @@ pub(crate) struct EncounteredErrorWhileInstantiating {
 #[help]
 pub(crate) struct StartNotFound;
 
-#[derive(Diagnostic)]
-#[diag(monomorphize_unknown_cgu_collection_mode)]
-pub(crate) struct UnknownCguCollectionMode<'a> {
-    pub mode: &'a str,
-}
-
 #[derive(Diagnostic)]
 #[diag(monomorphize_abi_error_disabled_vector_type)]
 #[help]
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index 6948dceddf904..c3a4152979401 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -124,7 +124,7 @@ use rustc_target::spec::SymbolVisibility;
 use tracing::debug;
 
 use crate::collector::{self, MonoItemCollectionStrategy, UsageMap};
-use crate::errors::{CouldntDumpMonoStats, SymbolAlreadyDefined, UnknownCguCollectionMode};
+use crate::errors::{CouldntDumpMonoStats, SymbolAlreadyDefined};
 
 struct PartitioningCx<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
@@ -1127,27 +1127,10 @@ where
 }
 
 fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> MonoItemPartitions<'_> {
-    let collection_strategy = match tcx.sess.opts.unstable_opts.print_mono_items {
-        Some(ref s) => {
-            let mode = s.to_lowercase();
-            let mode = mode.trim();
-            if mode == "eager" {
-                MonoItemCollectionStrategy::Eager
-            } else {
-                if mode != "lazy" {
-                    tcx.dcx().emit_warn(UnknownCguCollectionMode { mode });
-                }
-
-                MonoItemCollectionStrategy::Lazy
-            }
-        }
-        None => {
-            if tcx.sess.link_dead_code() {
-                MonoItemCollectionStrategy::Eager
-            } else {
-                MonoItemCollectionStrategy::Lazy
-            }
-        }
+    let collection_strategy = if tcx.sess.link_dead_code() {
+        MonoItemCollectionStrategy::Eager
+    } else {
+        MonoItemCollectionStrategy::Lazy
     };
 
     let (items, usage_map) = collector::collect_crate_mono_items(tcx, collection_strategy);
@@ -1209,7 +1192,7 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> MonoItemPartitio
         }
     }
 
-    if tcx.sess.opts.unstable_opts.print_mono_items.is_some() {
+    if tcx.sess.opts.unstable_opts.print_mono_items {
         let mut item_to_cgus: UnordMap<_, Vec<_>> = Default::default();
 
         for cgu in codegen_units {
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index b95ebfbe89f24..5b4068740a159 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -2408,10 +2408,8 @@ options! {
         "print codegen statistics (default: no)"),
     print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
         "print the LLVM optimization passes being run (default: no)"),
-    print_mono_items: Option = (None, parse_opt_string, [UNTRACKED],
-        "print the result of the monomorphization collection pass. \
-         Value `lazy` means to use normal collection; `eager` means to collect all items.
-         Note that this overwrites the effect `-Clink-dead-code` has on collection!"),
+    print_mono_items: bool = (false, parse_bool, [UNTRACKED],
+        "print the result of the monomorphization collection pass (default: no)"),
     print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
         "print layout information for each type encountered (default: no)"),
     proc_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md
index 2c35381eadfb5..0ba078f0b49e7 100644
--- a/src/doc/rustc-dev-guide/src/tests/compiletest.md
+++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md
@@ -325,12 +325,8 @@ The tests in [`tests/codegen-units`] test the
 [monomorphization](../backend/monomorph.md) collector and CGU partitioning.
 
 These tests work by running `rustc` with a flag to print the result of the
-monomorphization collection pass, and then special annotations in the file are
-used to compare against that.
-
-Each test should be annotated with the `//@
-compile-flags:-Zprint-mono-items=VAL` directive with the appropriate `VAL` to
-instruct `rustc` to print the monomorphization information.
+monomorphization collection pass, i.e., `-Zprint-mono-items`, and then special
+annotations in the file are used to compare against that.
 
 Then, the test should be annotated with comments of the form `//~ MONO_ITEM
 name` where `name` is the monomorphized string printed by rustc like `fn  TestCx<'test> {
             Crashes => {
                 set_mir_dump_dir(&mut rustc);
             }
-            Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake | CodegenUnits | RustdocJs => {
+            CodegenUnits => {
+                rustc.arg("-Zprint-mono-items");
+            }
+            Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake | RustdocJs => {
                 // do not use JSON output
             }
         }
diff --git a/tests/codegen-units/item-collection/asm-sym.rs b/tests/codegen-units/item-collection/asm-sym.rs
index 948c98d5a3c87..d39dc216cfdc0 100644
--- a/tests/codegen-units/item-collection/asm-sym.rs
+++ b/tests/codegen-units/item-collection/asm-sym.rs
@@ -1,5 +1,5 @@
 //@ needs-asm-support
-//@ compile-flags: -Ccodegen-units=1 -Zprint-mono-items=lazy --crate-type=lib
+//@ compile-flags: -Ccodegen-units=1 --crate-type=lib
 
 #[inline(always)]
 pub unsafe fn f() {
diff --git a/tests/codegen-units/item-collection/closures.rs b/tests/codegen-units/item-collection/closures.rs
index 864f98817a874..9d537814baf64 100644
--- a/tests/codegen-units/item-collection/closures.rs
+++ b/tests/codegen-units/item-collection/closures.rs
@@ -1,5 +1,5 @@
 //@ edition: 2021
-//@ compile-flags: -Zprint-mono-items=eager --crate-type=lib
+//@ compile-flags: -Clink-dead-code --crate-type=lib
 
 //~ MONO_ITEM fn async_fn @@
 //~ MONO_ITEM fn async_fn::{closure#0} @@
diff --git a/tests/codegen-units/item-collection/cross-crate-closures.rs b/tests/codegen-units/item-collection/cross-crate-closures.rs
index 75a77cc2671dc..0a1b85cec4e78 100644
--- a/tests/codegen-units/item-collection/cross-crate-closures.rs
+++ b/tests/codegen-units/item-collection/cross-crate-closures.rs
@@ -1,6 +1,6 @@
 // We need to disable MIR inlining in both this and its aux-build crate. The MIR inliner
 // will just inline everything into our start function if we let it. As it should.
-//@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
+//@ compile-flags:-Clink-dead-code -Zinline-mir=no
 
 #![deny(dead_code)]
 #![no_main]
@@ -11,12 +11,12 @@ extern crate cgu_extern_closures;
 //~ MONO_ITEM fn main @@ cross_crate_closures-cgu.0[External]
 #[no_mangle]
 extern "C" fn main(_: core::ffi::c_int, _: *const *const u8) -> core::ffi::c_int {
-    //~ MONO_ITEM fn cgu_extern_closures::inlined_fn @@ cross_crate_closures-cgu.0[Internal]
-    //~ MONO_ITEM fn cgu_extern_closures::inlined_fn::{closure#0} @@ cross_crate_closures-cgu.0[Internal]
+    //~ MONO_ITEM fn cgu_extern_closures::inlined_fn @@ cross_crate_closures-cgu.0[External]
+    //~ MONO_ITEM fn cgu_extern_closures::inlined_fn::{closure#0} @@ cross_crate_closures-cgu.0[External]
     let _ = cgu_extern_closures::inlined_fn(1, 2);
 
-    //~ MONO_ITEM fn cgu_extern_closures::inlined_fn_generic:: @@ cross_crate_closures-cgu.0[Internal]
-    //~ MONO_ITEM fn cgu_extern_closures::inlined_fn_generic::::{closure#0} @@ cross_crate_closures-cgu.0[Internal]
+    //~ MONO_ITEM fn cgu_extern_closures::inlined_fn_generic:: @@ cross_crate_closures-cgu.0[External]
+    //~ MONO_ITEM fn cgu_extern_closures::inlined_fn_generic::::{closure#0} @@ cross_crate_closures-cgu.0[External]
     let _ = cgu_extern_closures::inlined_fn_generic(3, 4, 5i32);
 
     // Nothing should be generated for this call, we just link to the instance
diff --git a/tests/codegen-units/item-collection/cross-crate-generic-functions.rs b/tests/codegen-units/item-collection/cross-crate-generic-functions.rs
index 4382bfdf8d81d..aa27ce3bdb542 100644
--- a/tests/codegen-units/item-collection/cross-crate-generic-functions.rs
+++ b/tests/codegen-units/item-collection/cross-crate-generic-functions.rs
@@ -1,4 +1,4 @@
-//@ compile-flags:-Zprint-mono-items=eager
+//@ compile-flags:-Clink-dead-code
 
 #![deny(dead_code)]
 #![crate_type = "lib"]
diff --git a/tests/codegen-units/item-collection/cross-crate-trait-method.rs b/tests/codegen-units/item-collection/cross-crate-trait-method.rs
index 917354166f54e..10482956a5a12 100644
--- a/tests/codegen-units/item-collection/cross-crate-trait-method.rs
+++ b/tests/codegen-units/item-collection/cross-crate-trait-method.rs
@@ -1,4 +1,4 @@
-//@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no -Copt-level=0
+//@ compile-flags:-Clink-dead-code -Zinline-mir=no -Copt-level=0
 
 #![deny(dead_code)]
 #![crate_type = "lib"]
diff --git a/tests/codegen-units/item-collection/drop-glue-eager.rs b/tests/codegen-units/item-collection/drop-glue-eager.rs
index c81074de49040..cc0ea701e66f3 100644
--- a/tests/codegen-units/item-collection/drop-glue-eager.rs
+++ b/tests/codegen-units/item-collection/drop-glue-eager.rs
@@ -1,6 +1,6 @@
 // Ensure that we *eagerly* monomorphize drop instances for structs with lifetimes.
 
-//@ compile-flags:-Zprint-mono-items=eager
+//@ compile-flags:-Clink-dead-code
 //@ compile-flags:--crate-type=lib
 
 //~ MONO_ITEM fn std::ptr::drop_in_place:: - shim(Some(StructWithDrop))
diff --git a/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs b/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs
index a57b102a5fd21..ef8f916539395 100644
--- a/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs
+++ b/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs
@@ -1,4 +1,4 @@
-//@ compile-flags:-Zprint-mono-items=eager
+//@ compile-flags:-Clink-dead-code
 //@ compile-flags:-Zinline-mir=no
 //@ compile-flags: -O
 
diff --git a/tests/codegen-units/item-collection/function-as-argument.rs b/tests/codegen-units/item-collection/function-as-argument.rs
index 146a53bb9119d..21d9de07efc0f 100644
--- a/tests/codegen-units/item-collection/function-as-argument.rs
+++ b/tests/codegen-units/item-collection/function-as-argument.rs
@@ -1,4 +1,4 @@
-//@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
+//@ compile-flags:-Clink-dead-code -Zinline-mir=no
 
 #![deny(dead_code)]
 #![crate_type = "lib"]
diff --git a/tests/codegen-units/item-collection/generic-drop-glue.rs b/tests/codegen-units/item-collection/generic-drop-glue.rs
index c0d2e899bbc86..b4c6c231e3d62 100644
--- a/tests/codegen-units/item-collection/generic-drop-glue.rs
+++ b/tests/codegen-units/item-collection/generic-drop-glue.rs
@@ -1,4 +1,4 @@
-//@ compile-flags:-Zprint-mono-items=eager
+//@ compile-flags:-Clink-dead-code
 //@ compile-flags: -O
 
 #![deny(dead_code)]
diff --git a/tests/codegen-units/item-collection/generic-functions.rs b/tests/codegen-units/item-collection/generic-functions.rs
index 4a890790702ad..56b4260eeb821 100644
--- a/tests/codegen-units/item-collection/generic-functions.rs
+++ b/tests/codegen-units/item-collection/generic-functions.rs
@@ -1,4 +1,4 @@
-//@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
+//@ compile-flags:-Clink-dead-code -Zinline-mir=no
 
 #![deny(dead_code)]
 #![crate_type = "lib"]
diff --git a/tests/codegen-units/item-collection/generic-impl.rs b/tests/codegen-units/item-collection/generic-impl.rs
index 5a43bd64b2ac6..deebb9cd35116 100644
--- a/tests/codegen-units/item-collection/generic-impl.rs
+++ b/tests/codegen-units/item-collection/generic-impl.rs
@@ -1,4 +1,4 @@
-//@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
+//@ compile-flags:-Clink-dead-code -Zinline-mir=no
 
 #![deny(dead_code)]
 #![crate_type = "lib"]
diff --git a/tests/codegen-units/item-collection/impl-in-non-instantiated-generic.rs b/tests/codegen-units/item-collection/impl-in-non-instantiated-generic.rs
index d916fa6a8254c..5c8318f6b37bb 100644
--- a/tests/codegen-units/item-collection/impl-in-non-instantiated-generic.rs
+++ b/tests/codegen-units/item-collection/impl-in-non-instantiated-generic.rs
@@ -1,4 +1,4 @@
-//@ compile-flags:-Zprint-mono-items=eager
+//@ compile-flags:-Clink-dead-code
 
 #![deny(dead_code)]
 #![crate_type = "lib"]
diff --git a/tests/codegen-units/item-collection/implicit-panic-call.rs b/tests/codegen-units/item-collection/implicit-panic-call.rs
index b348b4acc2486..6d3a17d8d4a50 100644
--- a/tests/codegen-units/item-collection/implicit-panic-call.rs
+++ b/tests/codegen-units/item-collection/implicit-panic-call.rs
@@ -1,5 +1,3 @@
-//@ compile-flags:-Zprint-mono-items=lazy
-
 // rust-lang/rust#90405
 // Ensure implicit panic calls are collected
 
diff --git a/tests/codegen-units/item-collection/instantiation-through-vtable.rs b/tests/codegen-units/item-collection/instantiation-through-vtable.rs
index ee0b5dc1dd2cb..8f13fd558083c 100644
--- a/tests/codegen-units/item-collection/instantiation-through-vtable.rs
+++ b/tests/codegen-units/item-collection/instantiation-through-vtable.rs
@@ -1,4 +1,4 @@
-//@ compile-flags:-Zprint-mono-items=eager -Zmir-opt-level=0
+//@ compile-flags:-Clink-dead-code -Zmir-opt-level=0
 
 #![deny(dead_code)]
 #![crate_type = "lib"]
@@ -24,7 +24,7 @@ impl Trait for Struct {
 pub fn start(_: isize, _: *const *const u8) -> isize {
     let s1 = Struct { _a: 0u32 };
 
-    //~ MONO_ITEM fn std::ptr::drop_in_place::> - shim(None) @@ instantiation_through_vtable-cgu.0[Internal]
+    //~ MONO_ITEM fn std::ptr::drop_in_place::> - shim(None) @@ instantiation_through_vtable-cgu.0[External]
     //~ MONO_ITEM fn  as Trait>::foo
     //~ MONO_ITEM fn  as Trait>::bar
     let r1 = &s1 as &Trait;
@@ -32,7 +32,7 @@ pub fn start(_: isize, _: *const *const u8) -> isize {
     r1.bar();
 
     let s1 = Struct { _a: 0u64 };
-    //~ MONO_ITEM fn std::ptr::drop_in_place::> - shim(None) @@ instantiation_through_vtable-cgu.0[Internal]
+    //~ MONO_ITEM fn std::ptr::drop_in_place::> - shim(None) @@ instantiation_through_vtable-cgu.0[External]
     //~ MONO_ITEM fn  as Trait>::foo
     //~ MONO_ITEM fn  as Trait>::bar
     let _ = &s1 as &Trait;
diff --git a/tests/codegen-units/item-collection/items-within-generic-items.rs b/tests/codegen-units/item-collection/items-within-generic-items.rs
index 56d21d5895c83..a685072a96bc8 100644
--- a/tests/codegen-units/item-collection/items-within-generic-items.rs
+++ b/tests/codegen-units/item-collection/items-within-generic-items.rs
@@ -1,4 +1,4 @@
-//@ compile-flags:-Zprint-mono-items=eager -Copt-level=0
+//@ compile-flags:-Clink-dead-code -Copt-level=0
 
 #![deny(dead_code)]
 #![crate_type = "lib"]
diff --git a/tests/codegen-units/item-collection/non-generic-closures.rs b/tests/codegen-units/item-collection/non-generic-closures.rs
index 4dbc0b62b9785..124fe7e3b69a0 100644
--- a/tests/codegen-units/item-collection/non-generic-closures.rs
+++ b/tests/codegen-units/item-collection/non-generic-closures.rs
@@ -1,17 +1,17 @@
-//@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
+//@ compile-flags:-Clink-dead-code -Zinline-mir=no
 
 #![deny(dead_code)]
 #![crate_type = "lib"]
 
-//~ MONO_ITEM fn temporary @@ non_generic_closures-cgu.0[Internal]
+//~ MONO_ITEM fn temporary @@ non_generic_closures-cgu.0[External]
 fn temporary() {
-    //~ MONO_ITEM fn temporary::{closure#0} @@ non_generic_closures-cgu.0[Internal]
+    //~ MONO_ITEM fn temporary::{closure#0} @@ non_generic_closures-cgu.0[External]
     (|a: u32| {
         let _ = a;
     })(4);
 }
 
-//~ MONO_ITEM fn assigned_to_variable_but_not_executed @@ non_generic_closures-cgu.0[Internal]
+//~ MONO_ITEM fn assigned_to_variable_but_not_executed @@ non_generic_closures-cgu.0[External]
 fn assigned_to_variable_but_not_executed() {
     //~ MONO_ITEM fn assigned_to_variable_but_not_executed::{closure#0}
     let _x = |a: i16| {
@@ -19,21 +19,21 @@ fn assigned_to_variable_but_not_executed() {
     };
 }
 
-//~ MONO_ITEM fn assigned_to_variable_executed_indirectly @@ non_generic_closures-cgu.0[Internal]
+//~ MONO_ITEM fn assigned_to_variable_executed_indirectly @@ non_generic_closures-cgu.0[External]
 fn assigned_to_variable_executed_indirectly() {
-    //~ MONO_ITEM fn assigned_to_variable_executed_indirectly::{closure#0} @@ non_generic_closures-cgu.0[Internal]
-    //~ MONO_ITEM fn <{closure@TEST_PATH:28:13: 28:21} as std::ops::FnOnce<(i32,)>>::call_once - shim @@ non_generic_closures-cgu.0[Internal]
-    //~ MONO_ITEM fn <{closure@TEST_PATH:28:13: 28:21} as std::ops::FnOnce<(i32,)>>::call_once - shim(vtable) @@ non_generic_closures-cgu.0[Internal]
-    //~ MONO_ITEM fn std::ptr::drop_in_place::<{closure@TEST_PATH:28:13: 28:21}> - shim(None) @@ non_generic_closures-cgu.0[Internal]
+    //~ MONO_ITEM fn assigned_to_variable_executed_indirectly::{closure#0} @@ non_generic_closures-cgu.0[External]
+    //~ MONO_ITEM fn <{closure@TEST_PATH:28:13: 28:21} as std::ops::FnOnce<(i32,)>>::call_once - shim @@ non_generic_closures-cgu.0[External]
+    //~ MONO_ITEM fn <{closure@TEST_PATH:28:13: 28:21} as std::ops::FnOnce<(i32,)>>::call_once - shim(vtable) @@ non_generic_closures-cgu.0[External]
+    //~ MONO_ITEM fn std::ptr::drop_in_place::<{closure@TEST_PATH:28:13: 28:21}> - shim(None) @@ non_generic_closures-cgu.0[External]
     let f = |a: i32| {
         let _ = a + 2;
     };
     run_closure(&f);
 }
 
-//~ MONO_ITEM fn assigned_to_variable_executed_directly @@ non_generic_closures-cgu.0[Internal]
+//~ MONO_ITEM fn assigned_to_variable_executed_directly @@ non_generic_closures-cgu.0[External]
 fn assigned_to_variable_executed_directly() {
-    //~ MONO_ITEM fn assigned_to_variable_executed_directly::{closure#0} @@ non_generic_closures-cgu.0[Internal]
+    //~ MONO_ITEM fn assigned_to_variable_executed_directly::{closure#0} @@ non_generic_closures-cgu.0[External]
     let f = |a: i64| {
         let _ = a + 3;
     };
@@ -51,7 +51,7 @@ pub fn start(_: isize, _: *const *const u8) -> isize {
     0
 }
 
-//~ MONO_ITEM fn run_closure @@ non_generic_closures-cgu.0[Internal]
+//~ MONO_ITEM fn run_closure @@ non_generic_closures-cgu.0[External]
 fn run_closure(f: &Fn(i32)) {
     f(3);
 }
diff --git a/tests/codegen-units/item-collection/non-generic-drop-glue.rs b/tests/codegen-units/item-collection/non-generic-drop-glue.rs
index 2eeccd2e99f2d..d83336f4d78d9 100644
--- a/tests/codegen-units/item-collection/non-generic-drop-glue.rs
+++ b/tests/codegen-units/item-collection/non-generic-drop-glue.rs
@@ -1,4 +1,4 @@
-//@ compile-flags:-Zprint-mono-items=eager
+//@ compile-flags:-Clink-dead-code
 //@ compile-flags: -O
 
 #![deny(dead_code)]
diff --git a/tests/codegen-units/item-collection/non-generic-functions.rs b/tests/codegen-units/item-collection/non-generic-functions.rs
index 4b86b1088f1ba..3f2bc7e58c90c 100644
--- a/tests/codegen-units/item-collection/non-generic-functions.rs
+++ b/tests/codegen-units/item-collection/non-generic-functions.rs
@@ -1,4 +1,4 @@
-//@ compile-flags:-Zprint-mono-items=eager
+//@ compile-flags:-Clink-dead-code
 
 #![deny(dead_code)]
 #![crate_type = "lib"]
diff --git a/tests/codegen-units/item-collection/overloaded-operators.rs b/tests/codegen-units/item-collection/overloaded-operators.rs
index 69b55695d3d30..a4db80bc8fc51 100644
--- a/tests/codegen-units/item-collection/overloaded-operators.rs
+++ b/tests/codegen-units/item-collection/overloaded-operators.rs
@@ -1,4 +1,4 @@
-//@ compile-flags:-Zprint-mono-items=eager
+//@ compile-flags:-Clink-dead-code
 
 #![deny(dead_code)]
 #![crate_type = "lib"]
diff --git a/tests/codegen-units/item-collection/static-init.rs b/tests/codegen-units/item-collection/static-init.rs
index 5e3d06790a2d6..df5eb830bf387 100644
--- a/tests/codegen-units/item-collection/static-init.rs
+++ b/tests/codegen-units/item-collection/static-init.rs
@@ -1,4 +1,4 @@
-//@ compile-flags:-Zprint-mono-items=eager
+//@ compile-flags:-Clink-dead-code
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-units/item-collection/statics-and-consts.rs b/tests/codegen-units/item-collection/statics-and-consts.rs
index 54297a4085131..597f9ddc11862 100644
--- a/tests/codegen-units/item-collection/statics-and-consts.rs
+++ b/tests/codegen-units/item-collection/statics-and-consts.rs
@@ -1,4 +1,4 @@
-//@ compile-flags:-Zprint-mono-items=eager
+//@ compile-flags:-Clink-dead-code
 
 #![deny(dead_code)]
 #![crate_type = "lib"]
diff --git a/tests/codegen-units/item-collection/trait-implementations.rs b/tests/codegen-units/item-collection/trait-implementations.rs
index 3b67d4f22bd2a..41e81b9d4ff22 100644
--- a/tests/codegen-units/item-collection/trait-implementations.rs
+++ b/tests/codegen-units/item-collection/trait-implementations.rs
@@ -1,4 +1,4 @@
-//@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
+//@ compile-flags:-Clink-dead-code -Zinline-mir=no
 
 #![deny(dead_code)]
 #![crate_type = "lib"]
diff --git a/tests/codegen-units/item-collection/trait-method-as-argument.rs b/tests/codegen-units/item-collection/trait-method-as-argument.rs
index d425ea199888a..8f76cfeb1290f 100644
--- a/tests/codegen-units/item-collection/trait-method-as-argument.rs
+++ b/tests/codegen-units/item-collection/trait-method-as-argument.rs
@@ -1,4 +1,4 @@
-//@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
+//@ compile-flags:-Clink-dead-code -Zinline-mir=no
 
 #![deny(dead_code)]
 #![crate_type = "lib"]
diff --git a/tests/codegen-units/item-collection/trait-method-default-impl.rs b/tests/codegen-units/item-collection/trait-method-default-impl.rs
index cd0a4b8903171..4e078831be4b6 100644
--- a/tests/codegen-units/item-collection/trait-method-default-impl.rs
+++ b/tests/codegen-units/item-collection/trait-method-default-impl.rs
@@ -1,4 +1,4 @@
-//@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
+//@ compile-flags:-Clink-dead-code -Zinline-mir=no
 
 #![deny(dead_code)]
 #![crate_type = "lib"]
diff --git a/tests/codegen-units/item-collection/transitive-drop-glue.rs b/tests/codegen-units/item-collection/transitive-drop-glue.rs
index b999e466d54b7..844d74526f413 100644
--- a/tests/codegen-units/item-collection/transitive-drop-glue.rs
+++ b/tests/codegen-units/item-collection/transitive-drop-glue.rs
@@ -1,4 +1,4 @@
-//@ compile-flags:-Zprint-mono-items=eager
+//@ compile-flags:-Clink-dead-code
 //@ compile-flags: -O
 
 #![deny(dead_code)]
diff --git a/tests/codegen-units/item-collection/tuple-drop-glue.rs b/tests/codegen-units/item-collection/tuple-drop-glue.rs
index 5e97fbb43368a..4380735597a4e 100644
--- a/tests/codegen-units/item-collection/tuple-drop-glue.rs
+++ b/tests/codegen-units/item-collection/tuple-drop-glue.rs
@@ -1,4 +1,4 @@
-//@ compile-flags:-Zprint-mono-items=eager
+//@ compile-flags:-Clink-dead-code
 //@ compile-flags: -O
 
 #![deny(dead_code)]
diff --git a/tests/codegen-units/item-collection/unreferenced-const-fn.rs b/tests/codegen-units/item-collection/unreferenced-const-fn.rs
index 8b37570a1be58..294de9c3a31bd 100644
--- a/tests/codegen-units/item-collection/unreferenced-const-fn.rs
+++ b/tests/codegen-units/item-collection/unreferenced-const-fn.rs
@@ -1,5 +1,3 @@
-//@ compile-flags:-Zprint-mono-items=lazy
-
 #![deny(dead_code)]
 #![crate_type = "rlib"]
 
diff --git a/tests/codegen-units/item-collection/unreferenced-inline-function.rs b/tests/codegen-units/item-collection/unreferenced-inline-function.rs
index f725cce90d61a..22d34adfbeee1 100644
--- a/tests/codegen-units/item-collection/unreferenced-inline-function.rs
+++ b/tests/codegen-units/item-collection/unreferenced-inline-function.rs
@@ -1,5 +1,3 @@
-//@ compile-flags:-Zprint-mono-items=lazy
-
 // N.B., we do not expect *any* monomorphization to be generated here.
 
 #![deny(dead_code)]
diff --git a/tests/codegen-units/item-collection/unsizing.rs b/tests/codegen-units/item-collection/unsizing.rs
index 97adf72ce2c9b..15e42bce2495d 100644
--- a/tests/codegen-units/item-collection/unsizing.rs
+++ b/tests/codegen-units/item-collection/unsizing.rs
@@ -1,4 +1,3 @@
-//@ compile-flags:-Zprint-mono-items=eager
 //@ compile-flags:-Zmir-opt-level=0
 
 #![deny(dead_code)]
diff --git a/tests/codegen-units/item-collection/unused-traits-and-generics.rs b/tests/codegen-units/item-collection/unused-traits-and-generics.rs
index d5088d3f8937c..819a065bac5db 100644
--- a/tests/codegen-units/item-collection/unused-traits-and-generics.rs
+++ b/tests/codegen-units/item-collection/unused-traits-and-generics.rs
@@ -1,4 +1,4 @@
-//@ compile-flags:-Zprint-mono-items=eager
+//@ compile-flags:-Clink-dead-code
 
 #![crate_type = "lib"]
 #![deny(dead_code)]
diff --git a/tests/codegen-units/partitioning/README.md b/tests/codegen-units/partitioning/README.md
index 5dd6b1281fd9d..4240a27bd2a80 100644
--- a/tests/codegen-units/partitioning/README.md
+++ b/tests/codegen-units/partitioning/README.md
@@ -3,11 +3,10 @@
 This test suite is designed to test that codegen unit partitioning works as intended.
 Note that it does not evaluate whether CGU partitioning is *good*. That is the job of the compiler benchmark suite.
 
-All tests in this suite use the flag `-Zprint-mono-items=lazy`, which makes the compiler print a machine-readable summary of all MonoItems that were collected, which CGUs they were assigned to, and the linkage in each CGU. The output looks like:
+All tests in this suite use the flag `-Zprint-mono-items`, which makes the compiler print a machine-readable summary of all MonoItems that were collected, which CGUs they were assigned to, and the linkage in each CGU. The output looks like:
 ```
 MONO_ITEM  @@ [] []
 ```
-DO NOT add tests to this suite that use `-Zprint-mono-items=eager`. That flag changes the way that MonoItem collection works in rather fundamental ways that are otherwise only used by `-Clink-dead-code`, and thus the MonoItems collected and their linkage under `-Zprint-mono-items=eager` does not correlate very well with normal compilation behavior.
 
 The current CGU partitioning algorithm essentially groups MonoItems by which module they are defined in, then merges small CGUs. There are a lot of inline modules in this test suite because that's the only way to observe the partitioning.
 
diff --git a/tests/codegen-units/partitioning/extern-drop-glue.rs b/tests/codegen-units/partitioning/extern-drop-glue.rs
index ca78c175dbf34..45e5393b33d8c 100644
--- a/tests/codegen-units/partitioning/extern-drop-glue.rs
+++ b/tests/codegen-units/partitioning/extern-drop-glue.rs
@@ -1,5 +1,5 @@
 //@ incremental
-//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0
+//@ compile-flags: -Copt-level=0
 
 #![crate_type = "rlib"]
 
diff --git a/tests/codegen-units/partitioning/extern-generic.rs b/tests/codegen-units/partitioning/extern-generic.rs
index 875ebb3098e56..5c34a768954fd 100644
--- a/tests/codegen-units/partitioning/extern-generic.rs
+++ b/tests/codegen-units/partitioning/extern-generic.rs
@@ -1,5 +1,5 @@
 //@ incremental
-//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0
+//@ compile-flags: -Copt-level=0
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-units/partitioning/incremental-merging.rs b/tests/codegen-units/partitioning/incremental-merging.rs
index 68eee803e5f22..d7ce77e60fee0 100644
--- a/tests/codegen-units/partitioning/incremental-merging.rs
+++ b/tests/codegen-units/partitioning/incremental-merging.rs
@@ -1,5 +1,5 @@
 //@ incremental
-//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0 -Ccodegen-units=3
+//@ compile-flags: -Copt-level=0 -Ccodegen-units=3
 
 #![crate_type = "rlib"]
 
diff --git a/tests/codegen-units/partitioning/inline-always.rs b/tests/codegen-units/partitioning/inline-always.rs
index 5e8cce0ac337b..02b789d3f29af 100644
--- a/tests/codegen-units/partitioning/inline-always.rs
+++ b/tests/codegen-units/partitioning/inline-always.rs
@@ -1,5 +1,5 @@
 //@ incremental
-//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0
+//@ compile-flags: -Copt-level=0
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-units/partitioning/inlining-from-extern-crate.rs b/tests/codegen-units/partitioning/inlining-from-extern-crate.rs
index d321c88d03a6e..8f2eea0dac18a 100644
--- a/tests/codegen-units/partitioning/inlining-from-extern-crate.rs
+++ b/tests/codegen-units/partitioning/inlining-from-extern-crate.rs
@@ -1,5 +1,5 @@
 //@ incremental
-//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=1
+//@ compile-flags: -Copt-level=1
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-units/partitioning/local-drop-glue.rs b/tests/codegen-units/partitioning/local-drop-glue.rs
index 240f64e4f7021..2ece7f0fa204a 100644
--- a/tests/codegen-units/partitioning/local-drop-glue.rs
+++ b/tests/codegen-units/partitioning/local-drop-glue.rs
@@ -1,5 +1,5 @@
 //@ incremental
-//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0
+//@ compile-flags: -Copt-level=0
 
 #![crate_type = "rlib"]
 
diff --git a/tests/codegen-units/partitioning/local-generic.rs b/tests/codegen-units/partitioning/local-generic.rs
index 177eb2632f640..93ef274bb8e62 100644
--- a/tests/codegen-units/partitioning/local-generic.rs
+++ b/tests/codegen-units/partitioning/local-generic.rs
@@ -1,5 +1,5 @@
 //@ incremental
-//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0
+//@ compile-flags: -Copt-level=0
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-units/partitioning/local-transitive-inlining.rs b/tests/codegen-units/partitioning/local-transitive-inlining.rs
index bcd32bd2e264e..cc9f1a74cb287 100644
--- a/tests/codegen-units/partitioning/local-transitive-inlining.rs
+++ b/tests/codegen-units/partitioning/local-transitive-inlining.rs
@@ -1,5 +1,5 @@
 //@ incremental
-//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0
+//@ compile-flags: -Copt-level=0
 
 #![crate_type = "rlib"]
 
diff --git a/tests/codegen-units/partitioning/methods-are-with-self-type.rs b/tests/codegen-units/partitioning/methods-are-with-self-type.rs
index 4d3f946fd9538..5ad45836c01b0 100644
--- a/tests/codegen-units/partitioning/methods-are-with-self-type.rs
+++ b/tests/codegen-units/partitioning/methods-are-with-self-type.rs
@@ -1,5 +1,5 @@
 //@ incremental
-//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0
+//@ compile-flags: -Copt-level=0
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-units/partitioning/regular-modules.rs b/tests/codegen-units/partitioning/regular-modules.rs
index d59074e7e3471..0876fb427ba46 100644
--- a/tests/codegen-units/partitioning/regular-modules.rs
+++ b/tests/codegen-units/partitioning/regular-modules.rs
@@ -1,5 +1,5 @@
 //@ incremental
-//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0
+//@ compile-flags: -Copt-level=0
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen-units/partitioning/shared-generics.rs b/tests/codegen-units/partitioning/shared-generics.rs
index b5bf376a6134a..4de7b1623ea39 100644
--- a/tests/codegen-units/partitioning/shared-generics.rs
+++ b/tests/codegen-units/partitioning/shared-generics.rs
@@ -2,7 +2,7 @@
 // NOTE: We always compile this test with -Copt-level=0 because higher opt-levels
 //       prevent drop-glue from participating in share-generics.
 //@ incremental
-//@ compile-flags: -Zprint-mono-items=lazy -Zshare-generics=yes -Copt-level=0
+//@ compile-flags: -Zshare-generics=yes -Copt-level=0
 
 #![crate_type = "rlib"]
 
diff --git a/tests/codegen-units/partitioning/statics.rs b/tests/codegen-units/partitioning/statics.rs
index 72bca4c5ed36a..bfa004d0e2623 100644
--- a/tests/codegen-units/partitioning/statics.rs
+++ b/tests/codegen-units/partitioning/statics.rs
@@ -1,5 +1,5 @@
 //@ incremental
-//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0
+//@ compile-flags: -Copt-level=0
 
 #![crate_type = "rlib"]
 
diff --git a/tests/codegen-units/partitioning/vtable-through-const.rs b/tests/codegen-units/partitioning/vtable-through-const.rs
index fd73e3fe9238d..aad9ccb634b02 100644
--- a/tests/codegen-units/partitioning/vtable-through-const.rs
+++ b/tests/codegen-units/partitioning/vtable-through-const.rs
@@ -1,6 +1,6 @@
 //@ incremental
 // Need to disable optimizations to ensure consistent output across all CI runners.
-//@ compile-flags: -Zprint-mono-items=lazy -Copt-level=0
+//@ compile-flags: -Copt-level=0
 
 #![crate_type = "rlib"]
 
diff --git a/tests/crashes/114198-2.rs b/tests/crashes/114198-2.rs
index de9d61ae1b99a..56cb7d76e02d3 100644
--- a/tests/crashes/114198-2.rs
+++ b/tests/crashes/114198-2.rs
@@ -1,5 +1,5 @@
 //@ known-bug: #114198
-//@ compile-flags: -Zprint-mono-items=eager
+//@ compile-flags: -Zprint-mono-items -Clink-dead-code
 
 impl Trait for ::Struct {}
 trait Trait {
diff --git a/tests/crashes/114198.rs b/tests/crashes/114198.rs
index 1ec8cdd424e1d..0f479b3615fb0 100644
--- a/tests/crashes/114198.rs
+++ b/tests/crashes/114198.rs
@@ -1,5 +1,5 @@
 //@ known-bug: #114198
-//@ compile-flags: -Zprint-mono-items=eager
+//@ compile-flags: -Zprint-mono-items -Clink-dead-code
 
 #![feature(lazy_type_alias)]
 

From d9f513f0dafd6a5bc9340c77d3f86f727ff52824 Mon Sep 17 00:00:00 2001
From: Jieyou Xu 
Date: Fri, 9 May 2025 19:51:03 +0800
Subject: [PATCH 2090/4206] run-make-support: support "ejecting" the underlying
 std command

In rare cases, the test may need access to the underlying
`std::process::Command` (e.g. for non-trivial process spawning).

Co-authored-by: Jesus Checa Hidalgo 
---
 src/tools/run-make-support/src/command.rs            |  6 ++++++
 .../run-make-support/src/external_deps/rustdoc.rs    |  4 ++--
 src/tools/run-make-support/src/macros.rs             | 12 ++++++++++++
 3 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs
index 70a72bd1abebe..b46ddd1d3154b 100644
--- a/src/tools/run-make-support/src/command.rs
+++ b/src/tools/run-make-support/src/command.rs
@@ -63,6 +63,12 @@ impl Command {
         }
     }
 
+    // Internal-only.
+    pub(crate) fn into_raw_command(mut self) -> std::process::Command {
+        self.drop_bomb.defuse();
+        self.cmd
+    }
+
     /// Specify a stdin input buffer. This is a convenience helper,
     pub fn stdin_buf>(&mut self, input: I) -> &mut Self {
         self.stdin_buf = Some(input.as_ref().to_vec().into_boxed_slice());
diff --git a/src/tools/run-make-support/src/external_deps/rustdoc.rs b/src/tools/run-make-support/src/external_deps/rustdoc.rs
index 433a57cd9fa65..7040fb667cfcc 100644
--- a/src/tools/run-make-support/src/external_deps/rustdoc.rs
+++ b/src/tools/run-make-support/src/external_deps/rustdoc.rs
@@ -5,7 +5,7 @@ use crate::command::Command;
 use crate::env::env_var;
 use crate::util::set_host_compiler_dylib_path;
 
-/// Construct a new `rustdoc` invocation.
+/// Construct a new `rustdoc` invocation. This will configure the host compiler runtime libs.
 #[track_caller]
 pub fn rustdoc() -> Rustdoc {
     Rustdoc::new()
@@ -28,7 +28,7 @@ fn setup_common() -> Command {
 }
 
 impl Rustdoc {
-    /// Construct a bare `rustdoc` invocation.
+    /// Construct a bare `rustdoc` invocation. This will configure the host compiler runtime libs.
     #[track_caller]
     pub fn new() -> Self {
         let cmd = setup_common();
diff --git a/src/tools/run-make-support/src/macros.rs b/src/tools/run-make-support/src/macros.rs
index 94955aefe57aa..9d5cc4e5876df 100644
--- a/src/tools/run-make-support/src/macros.rs
+++ b/src/tools/run-make-support/src/macros.rs
@@ -28,6 +28,18 @@
 macro_rules! impl_common_helpers {
     ($wrapper: ident) => {
         impl $wrapper {
+            /// In very rare circumstances, you may need a e.g. `bare_rustc()` or `bare_rustdoc()`
+            /// with host runtime libs configured, but want the underlying raw
+            /// [`std::process::Command`] (e.g. for manipulating pipes or whatever). This function
+            /// will consume the command wrapper and extract the underlying
+            /// [`std::process::Command`].
+            ///
+            /// Caution: this will mean that you can no longer use the convenience methods on the
+            /// command wrapper. Use as a last resort.
+            pub fn into_raw_command(self) -> ::std::process::Command {
+                self.cmd.into_raw_command()
+            }
+
             /// Specify an environment variable.
             pub fn env(&mut self, key: K, value: V) -> &mut Self
             where

From 84ed40dc38cff2a25f0d6e6be1f11b3c1a12133d Mon Sep 17 00:00:00 2001
From: Jieyou Xu 
Date: Fri, 9 May 2025 19:52:36 +0800
Subject: [PATCH 2091/4206] tests: fix `broken-pipe-no-ice` to use
 `bare_rustc`/`rustc`

Where host compiler runtime libs are properly configured, instead of raw
`RUSTC`/`RUSTDOC` commands.

Co-authored-by: Jesus Checa Hidalgo 
---
 tests/run-make/broken-pipe-no-ice/rmake.rs | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/tests/run-make/broken-pipe-no-ice/rmake.rs b/tests/run-make/broken-pipe-no-ice/rmake.rs
index 0521b3950207d..b0a28b6c899da 100644
--- a/tests/run-make/broken-pipe-no-ice/rmake.rs
+++ b/tests/run-make/broken-pipe-no-ice/rmake.rs
@@ -14,7 +14,7 @@
 use std::io::Read;
 use std::process::{Command, Stdio};
 
-use run_make_support::env_var;
+use run_make_support::{bare_rustc, rustdoc};
 
 #[derive(Debug, PartialEq)]
 enum Binary {
@@ -67,11 +67,13 @@ fn check_broken_pipe_handled_gracefully(bin: Binary, mut cmd: Command) {
 }
 
 fn main() {
-    let mut rustc = Command::new(env_var("RUSTC"));
+    let mut rustc = bare_rustc();
     rustc.arg("--print=sysroot");
+    let rustc = rustc.into_raw_command();
     check_broken_pipe_handled_gracefully(Binary::Rustc, rustc);
 
-    let mut rustdoc = Command::new(env_var("RUSTDOC"));
+    let mut rustdoc = rustdoc();
     rustdoc.arg("--version");
+    let rustdoc = rustdoc.into_raw_command();
     check_broken_pipe_handled_gracefully(Binary::Rustdoc, rustdoc);
 }

From 35bdd25e328554a466fd2d7286122208369e5eba Mon Sep 17 00:00:00 2001
From: bendn 
Date: Mon, 28 Apr 2025 23:03:35 +0700
Subject: [PATCH 2092/4206] remove superseded lints

---
 clippy_lints/src/declared_lints.rs            |   4 -
 clippy_lints/src/deprecated_lints.rs          |   8 +
 clippy_lints/src/transmute/mod.rs             | 115 ---------
 .../src/transmute/transmute_float_to_int.rs   |  66 -----
 .../src/transmute/transmute_int_to_char.rs    |  47 ----
 .../src/transmute/transmute_int_to_float.rs   |  50 ----
 .../src/transmute/transmute_num_to_bytes.rs   |  50 ----
 tests/ui/rename.fixed                         |   5 +
 tests/ui/rename.rs                            |   5 +
 tests/ui/rename.stderr                        | 164 +++++++------
 tests/ui/transmute.rs                         | 132 ----------
 tests/ui/transmute.stderr                     | 230 +-----------------
 tests/ui/transmute_float_to_int.fixed         |  60 -----
 tests/ui/transmute_float_to_int.rs            |  60 -----
 tests/ui/transmute_float_to_int.stderr        |  89 -------
 tests/ui/transmute_int_to_char.fixed          |  16 --
 tests/ui/transmute_int_to_char.rs             |  16 --
 tests/ui/transmute_int_to_char.stderr         |  17 --
 tests/ui/transmute_int_to_char_no_std.fixed   |  28 ---
 tests/ui/transmute_int_to_char_no_std.rs      |  28 ---
 tests/ui/transmute_int_to_char_no_std.stderr  |  17 --
 21 files changed, 116 insertions(+), 1091 deletions(-)
 delete mode 100644 clippy_lints/src/transmute/transmute_float_to_int.rs
 delete mode 100644 clippy_lints/src/transmute/transmute_int_to_char.rs
 delete mode 100644 clippy_lints/src/transmute/transmute_int_to_float.rs
 delete mode 100644 clippy_lints/src/transmute/transmute_num_to_bytes.rs
 delete mode 100644 tests/ui/transmute_float_to_int.fixed
 delete mode 100644 tests/ui/transmute_float_to_int.rs
 delete mode 100644 tests/ui/transmute_float_to_int.stderr
 delete mode 100644 tests/ui/transmute_int_to_char.fixed
 delete mode 100644 tests/ui/transmute_int_to_char.rs
 delete mode 100644 tests/ui/transmute_int_to_char.stderr
 delete mode 100644 tests/ui/transmute_int_to_char_no_std.fixed
 delete mode 100644 tests/ui/transmute_int_to_char_no_std.rs
 delete mode 100644 tests/ui/transmute_int_to_char_no_std.stderr

diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 2cccd6ba27027..e046ab0b42bb7 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -705,13 +705,9 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::transmute::MISSING_TRANSMUTE_ANNOTATIONS_INFO,
     crate::transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS_INFO,
     crate::transmute::TRANSMUTE_BYTES_TO_STR_INFO,
-    crate::transmute::TRANSMUTE_FLOAT_TO_INT_INFO,
     crate::transmute::TRANSMUTE_INT_TO_BOOL_INFO,
-    crate::transmute::TRANSMUTE_INT_TO_CHAR_INFO,
-    crate::transmute::TRANSMUTE_INT_TO_FLOAT_INFO,
     crate::transmute::TRANSMUTE_INT_TO_NON_ZERO_INFO,
     crate::transmute::TRANSMUTE_NULL_TO_FN_INFO,
-    crate::transmute::TRANSMUTE_NUM_TO_BYTES_INFO,
     crate::transmute::TRANSMUTE_PTR_TO_PTR_INFO,
     crate::transmute::TRANSMUTE_PTR_TO_REF_INFO,
     crate::transmute::TRANSMUTE_UNDEFINED_REPR_INFO,
diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs
index b60c11d79d48f..a1909c5363ff0 100644
--- a/clippy_lints/src/deprecated_lints.rs
+++ b/clippy_lints/src/deprecated_lints.rs
@@ -187,5 +187,13 @@ declare_with_version! { RENAMED(RENAMED_VERSION): &[(&str, &str)] = &[
     ("clippy::vtable_address_comparisons", "ambiguous_wide_pointer_comparisons"),
     #[clippy::version = ""]
     ("clippy::reverse_range_loop", "clippy::reversed_empty_ranges"),
+    #[clippy::version = "1.88.0"]
+    ("clippy::transmute_int_to_float", "unnecessary_transmutes"),
+    #[clippy::version = "1.88.0"]
+    ("clippy::transmute_int_to_char", "unnecessary_transmutes"),
+    #[clippy::version = "1.88.0"]
+    ("clippy::transmute_float_to_int", "unnecessary_transmutes"),
+    #[clippy::version = "1.88.0"]
+    ("clippy::transmute_num_to_bytes", "unnecessary_transmutes"),
     // end renamed lints. used by `cargo dev rename_lint`
 ]}
diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs
index f2da8d35cb4fc..d5112e2c3f97a 100644
--- a/clippy_lints/src/transmute/mod.rs
+++ b/clippy_lints/src/transmute/mod.rs
@@ -1,13 +1,9 @@
 mod crosspointer_transmute;
 mod eager_transmute;
 mod missing_transmute_annotations;
-mod transmute_float_to_int;
 mod transmute_int_to_bool;
-mod transmute_int_to_char;
-mod transmute_int_to_float;
 mod transmute_int_to_non_zero;
 mod transmute_null_to_fn;
-mod transmute_num_to_bytes;
 mod transmute_ptr_to_ptr;
 mod transmute_ptr_to_ref;
 mod transmute_ref_to_ref;
@@ -141,40 +137,6 @@ declare_clippy_lint! {
     "transmutes from a pointer to a reference type"
 }
 
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for transmutes from an integer to a `char`.
-    ///
-    /// ### Why is this bad?
-    /// Not every integer is a Unicode scalar value.
-    ///
-    /// ### Known problems
-    /// - [`from_u32`] which this lint suggests using is slower than `transmute`
-    /// as it needs to validate the input.
-    /// If you are certain that the input is always a valid Unicode scalar value,
-    /// use [`from_u32_unchecked`] which is as fast as `transmute`
-    /// but has a semantically meaningful name.
-    /// - You might want to handle `None` returned from [`from_u32`] instead of calling `unwrap`.
-    ///
-    /// [`from_u32`]: https://doc.rust-lang.org/std/char/fn.from_u32.html
-    /// [`from_u32_unchecked`]: https://doc.rust-lang.org/std/char/fn.from_u32_unchecked.html
-    ///
-    /// ### Example
-    /// ```no_run
-    /// let x = 1_u32;
-    /// unsafe {
-    ///     let _: char = std::mem::transmute(x); // where x: u32
-    /// }
-    ///
-    /// // should be:
-    /// let _ = std::char::from_u32(x).unwrap();
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub TRANSMUTE_INT_TO_CHAR,
-    complexity,
-    "transmutes from an integer to a `char`"
-}
-
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for transmutes from a `&[u8]` to a `&str`.
@@ -232,29 +194,6 @@ declare_clippy_lint! {
     "transmutes from an integer to a `bool`"
 }
 
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for transmutes from an integer to a float.
-    ///
-    /// ### Why is this bad?
-    /// Transmutes are dangerous and error-prone, whereas `from_bits` is intuitive
-    /// and safe.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// unsafe {
-    ///     let _: f32 = std::mem::transmute(1_u32); // where x: u32
-    /// }
-    ///
-    /// // should be:
-    /// let _: f32 = f32::from_bits(1_u32);
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub TRANSMUTE_INT_TO_FLOAT,
-    complexity,
-    "transmutes from an integer to a float"
-}
-
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for transmutes from `T` to `NonZero`, and suggests the `new_unchecked`
@@ -280,52 +219,6 @@ declare_clippy_lint! {
     "transmutes from an integer to a non-zero wrapper"
 }
 
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for transmutes from a float to an integer.
-    ///
-    /// ### Why is this bad?
-    /// Transmutes are dangerous and error-prone, whereas `to_bits` is intuitive
-    /// and safe.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// unsafe {
-    ///     let _: u32 = std::mem::transmute(1f32);
-    /// }
-    ///
-    /// // should be:
-    /// let _: u32 = 1f32.to_bits();
-    /// ```
-    #[clippy::version = "1.41.0"]
-    pub TRANSMUTE_FLOAT_TO_INT,
-    complexity,
-    "transmutes from a float to an integer"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for transmutes from a number to an array of `u8`
-    ///
-    /// ### Why this is bad?
-    /// Transmutes are dangerous and error-prone, whereas `to_ne_bytes`
-    /// is intuitive and safe.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// unsafe {
-    ///     let x: [u8; 8] = std::mem::transmute(1i64);
-    /// }
-    ///
-    /// // should be
-    /// let x: [u8; 8] = 0i64.to_ne_bytes();
-    /// ```
-    #[clippy::version = "1.58.0"]
-    pub TRANSMUTE_NUM_TO_BYTES,
-    complexity,
-    "transmutes from a number to an array of `u8`"
-}
-
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for transmutes from a pointer to a pointer, or
@@ -581,13 +474,9 @@ impl_lint_pass!(Transmute => [
     TRANSMUTE_PTR_TO_PTR,
     USELESS_TRANSMUTE,
     WRONG_TRANSMUTE,
-    TRANSMUTE_INT_TO_CHAR,
     TRANSMUTE_BYTES_TO_STR,
     TRANSMUTE_INT_TO_BOOL,
-    TRANSMUTE_INT_TO_FLOAT,
     TRANSMUTE_INT_TO_NON_ZERO,
-    TRANSMUTE_FLOAT_TO_INT,
-    TRANSMUTE_NUM_TO_BYTES,
     UNSOUND_COLLECTION_TRANSMUTE,
     TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
     TRANSMUTE_UNDEFINED_REPR,
@@ -632,14 +521,10 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
                 | transmute_null_to_fn::check(cx, e, arg, to_ty)
                 | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, self.msrv)
                 | missing_transmute_annotations::check(cx, path, from_ty, to_ty, e.hir_id)
-                | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context)
                 | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
                 | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg, self.msrv)
                 | transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg)
-                | transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context, self.msrv)
                 | transmute_int_to_non_zero::check(cx, e, from_ty, to_ty, arg)
-                | transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context, self.msrv)
-                | transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context, self.msrv)
                 | (unsound_collection_transmute::check(cx, e, from_ty, to_ty)
                     || transmute_undefined_repr::check(cx, e, from_ty, to_ty))
                 | (eager_transmute::check(cx, e, arg, from_ty, to_ty));
diff --git a/clippy_lints/src/transmute/transmute_float_to_int.rs b/clippy_lints/src/transmute/transmute_float_to_int.rs
deleted file mode 100644
index df2f681a16291..0000000000000
--- a/clippy_lints/src/transmute/transmute_float_to_int.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-use super::TRANSMUTE_FLOAT_TO_INT;
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::sugg;
-use rustc_ast as ast;
-use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, UnOp};
-use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty};
-
-/// Checks for `transmute_float_to_int` lint.
-/// Returns `true` if it's triggered, otherwise returns `false`.
-pub(super) fn check<'tcx>(
-    cx: &LateContext<'tcx>,
-    e: &'tcx Expr<'_>,
-    from_ty: Ty<'tcx>,
-    to_ty: Ty<'tcx>,
-    mut arg: &'tcx Expr<'_>,
-    const_context: bool,
-    msrv: Msrv,
-) -> bool {
-    match (&from_ty.kind(), &to_ty.kind()) {
-        (ty::Float(float_ty), ty::Int(_) | ty::Uint(_))
-            if !const_context || msrv.meets(cx, msrvs::CONST_FLOAT_BITS_CONV) =>
-        {
-            span_lint_and_then(
-                cx,
-                TRANSMUTE_FLOAT_TO_INT,
-                e.span,
-                format!("transmute from a `{from_ty}` to a `{to_ty}`"),
-                |diag| {
-                    let mut sugg = sugg::Sugg::hir(cx, arg, "..");
-
-                    if let ExprKind::Unary(UnOp::Neg, inner_expr) = &arg.kind {
-                        arg = inner_expr;
-                    }
-
-                    if let ExprKind::Lit(lit) = &arg.kind
-                        // if the expression is a float literal and it is unsuffixed then
-                        // add a suffix so the suggestion is valid and unambiguous
-                        && let ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) = lit.node
-                    {
-                        let op = format!("{sugg}{}", float_ty.name_str()).into();
-                        match sugg {
-                            sugg::Sugg::MaybeParen(_) => sugg = sugg::Sugg::MaybeParen(op),
-                            _ => sugg = sugg::Sugg::NonParen(op),
-                        }
-                    }
-
-                    sugg = sugg::Sugg::NonParen(format!("{}.to_bits()", sugg.maybe_paren()).into());
-
-                    // cast the result of `to_bits` if `to_ty` is signed
-                    sugg = if let ty::Int(int_ty) = to_ty.kind() {
-                        sugg.as_ty(int_ty.name_str().to_string())
-                    } else {
-                        sugg
-                    };
-
-                    diag.span_suggestion(e.span, "consider using", sugg, Applicability::Unspecified);
-                },
-            );
-            true
-        },
-        _ => false,
-    }
-}
diff --git a/clippy_lints/src/transmute/transmute_int_to_char.rs b/clippy_lints/src/transmute/transmute_int_to_char.rs
deleted file mode 100644
index 81d10a7d5bde4..0000000000000
--- a/clippy_lints/src/transmute/transmute_int_to_char.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-use super::TRANSMUTE_INT_TO_CHAR;
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{std_or_core, sugg};
-use rustc_ast as ast;
-use rustc_errors::Applicability;
-use rustc_hir::Expr;
-use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty};
-
-/// Checks for `transmute_int_to_char` lint.
-/// Returns `true` if it's triggered, otherwise returns `false`.
-pub(super) fn check<'tcx>(
-    cx: &LateContext<'tcx>,
-    e: &'tcx Expr<'_>,
-    from_ty: Ty<'tcx>,
-    to_ty: Ty<'tcx>,
-    arg: &'tcx Expr<'_>,
-    const_context: bool,
-) -> bool {
-    match (&from_ty.kind(), &to_ty.kind()) {
-        (ty::Int(ty::IntTy::I32) | ty::Uint(ty::UintTy::U32), &ty::Char) if !const_context => {
-            span_lint_and_then(
-                cx,
-                TRANSMUTE_INT_TO_CHAR,
-                e.span,
-                format!("transmute from a `{from_ty}` to a `char`"),
-                |diag| {
-                    let Some(top_crate) = std_or_core(cx) else { return };
-                    let arg = sugg::Sugg::hir(cx, arg, "..");
-                    let arg = if let ty::Int(_) = from_ty.kind() {
-                        arg.as_ty(ast::UintTy::U32.name_str())
-                    } else {
-                        arg
-                    };
-                    diag.span_suggestion(
-                        e.span,
-                        "consider using",
-                        format!("{top_crate}::char::from_u32({arg}).unwrap()"),
-                        Applicability::Unspecified,
-                    );
-                },
-            );
-            true
-        },
-        _ => false,
-    }
-}
diff --git a/clippy_lints/src/transmute/transmute_int_to_float.rs b/clippy_lints/src/transmute/transmute_int_to_float.rs
deleted file mode 100644
index aaa95396b4b4b..0000000000000
--- a/clippy_lints/src/transmute/transmute_int_to_float.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-use super::TRANSMUTE_INT_TO_FLOAT;
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::sugg;
-use rustc_errors::Applicability;
-use rustc_hir::Expr;
-use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty};
-
-/// Checks for `transmute_int_to_float` lint.
-/// Returns `true` if it's triggered, otherwise returns `false`.
-pub(super) fn check<'tcx>(
-    cx: &LateContext<'tcx>,
-    e: &'tcx Expr<'_>,
-    from_ty: Ty<'tcx>,
-    to_ty: Ty<'tcx>,
-    arg: &'tcx Expr<'_>,
-    const_context: bool,
-    msrv: Msrv,
-) -> bool {
-    match (&from_ty.kind(), &to_ty.kind()) {
-        (ty::Int(_) | ty::Uint(_), ty::Float(_)) if !const_context || msrv.meets(cx, msrvs::CONST_FLOAT_BITS_CONV) => {
-            span_lint_and_then(
-                cx,
-                TRANSMUTE_INT_TO_FLOAT,
-                e.span,
-                format!("transmute from a `{from_ty}` to a `{to_ty}`"),
-                |diag| {
-                    let arg = sugg::Sugg::hir(cx, arg, "..");
-                    let arg = if let ty::Int(int_ty) = from_ty.kind() {
-                        arg.as_ty(format!(
-                            "u{}",
-                            int_ty.bit_width().map_or_else(|| "size".to_string(), |v| v.to_string())
-                        ))
-                    } else {
-                        arg
-                    };
-                    diag.span_suggestion(
-                        e.span,
-                        "consider using",
-                        format!("{to_ty}::from_bits({arg})"),
-                        Applicability::Unspecified,
-                    );
-                },
-            );
-            true
-        },
-        _ => false,
-    }
-}
diff --git a/clippy_lints/src/transmute/transmute_num_to_bytes.rs b/clippy_lints/src/transmute/transmute_num_to_bytes.rs
deleted file mode 100644
index d72be270b731f..0000000000000
--- a/clippy_lints/src/transmute/transmute_num_to_bytes.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-use super::TRANSMUTE_NUM_TO_BYTES;
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::sugg;
-use rustc_errors::Applicability;
-use rustc_hir::Expr;
-use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty, UintTy};
-
-/// Checks for `transmute_int_to_float` lint.
-/// Returns `true` if it's triggered, otherwise returns `false`.
-pub(super) fn check<'tcx>(
-    cx: &LateContext<'tcx>,
-    e: &'tcx Expr<'_>,
-    from_ty: Ty<'tcx>,
-    to_ty: Ty<'tcx>,
-    arg: &'tcx Expr<'_>,
-    const_context: bool,
-    msrv: Msrv,
-) -> bool {
-    match (&from_ty.kind(), &to_ty.kind()) {
-        (ty::Int(_) | ty::Uint(_) | ty::Float(_), ty::Array(arr_ty, _)) => {
-            if !matches!(arr_ty.kind(), ty::Uint(UintTy::U8)) {
-                return false;
-            }
-            if matches!(from_ty.kind(), ty::Float(_)) && const_context && !msrv.meets(cx, msrvs::CONST_FLOAT_BITS_CONV)
-            {
-                return false;
-            }
-
-            span_lint_and_then(
-                cx,
-                TRANSMUTE_NUM_TO_BYTES,
-                e.span,
-                format!("transmute from a `{from_ty}` to a `{to_ty}`"),
-                |diag| {
-                    let arg = sugg::Sugg::hir(cx, arg, "..");
-                    diag.span_suggestion(
-                        e.span,
-                        "consider using `to_ne_bytes()`",
-                        format!("{arg}.to_ne_bytes()"),
-                        Applicability::Unspecified,
-                    );
-                },
-            );
-            true
-        },
-        _ => false,
-    }
-}
diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed
index acf7914d25365..55e287b91596d 100644
--- a/tests/ui/rename.fixed
+++ b/tests/ui/rename.fixed
@@ -63,6 +63,7 @@
 #![allow(unused_labels)]
 #![allow(ambiguous_wide_pointer_comparisons)]
 #![allow(clippy::reversed_empty_ranges)]
+#![allow(unnecessary_transmutes)]
 #![warn(clippy::almost_complete_range)] //~ ERROR: lint `clippy::almost_complete_letter_range`
 #![warn(clippy::disallowed_names)] //~ ERROR: lint `clippy::blacklisted_name`
 #![warn(clippy::blocks_in_conditions)] //~ ERROR: lint `clippy::block_in_if_condition_expr`
@@ -132,5 +133,9 @@
 #![warn(unused_labels)] //~ ERROR: lint `clippy::unused_label`
 #![warn(ambiguous_wide_pointer_comparisons)] //~ ERROR: lint `clippy::vtable_address_comparisons`
 #![warn(clippy::reversed_empty_ranges)] //~ ERROR: lint `clippy::reverse_range_loop`
+#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_int_to_float`
+#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_int_to_char`
+#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_float_to_int`
+#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_num_to_bytes`
 
 fn main() {}
diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs
index 32641a684a44b..31dcd2cea0818 100644
--- a/tests/ui/rename.rs
+++ b/tests/ui/rename.rs
@@ -63,6 +63,7 @@
 #![allow(unused_labels)]
 #![allow(ambiguous_wide_pointer_comparisons)]
 #![allow(clippy::reversed_empty_ranges)]
+#![allow(unnecessary_transmutes)]
 #![warn(clippy::almost_complete_letter_range)] //~ ERROR: lint `clippy::almost_complete_letter_range`
 #![warn(clippy::blacklisted_name)] //~ ERROR: lint `clippy::blacklisted_name`
 #![warn(clippy::block_in_if_condition_expr)] //~ ERROR: lint `clippy::block_in_if_condition_expr`
@@ -132,5 +133,9 @@
 #![warn(clippy::unused_label)] //~ ERROR: lint `clippy::unused_label`
 #![warn(clippy::vtable_address_comparisons)] //~ ERROR: lint `clippy::vtable_address_comparisons`
 #![warn(clippy::reverse_range_loop)] //~ ERROR: lint `clippy::reverse_range_loop`
+#![warn(clippy::transmute_int_to_float)] //~ ERROR: lint `clippy::transmute_int_to_float`
+#![warn(clippy::transmute_int_to_char)] //~ ERROR: lint `clippy::transmute_int_to_char`
+#![warn(clippy::transmute_float_to_int)] //~ ERROR: lint `clippy::transmute_float_to_int`
+#![warn(clippy::transmute_num_to_bytes)] //~ ERROR: lint `clippy::transmute_num_to_bytes`
 
 fn main() {}
diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr
index e9d2debff91a3..a8d5c96acc3a7 100644
--- a/tests/ui/rename.stderr
+++ b/tests/ui/rename.stderr
@@ -1,5 +1,5 @@
 error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
-  --> tests/ui/rename.rs:66:9
+  --> tests/ui/rename.rs:67:9
    |
 LL | #![warn(clippy::almost_complete_letter_range)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@@ -8,412 +8,436 @@ LL | #![warn(clippy::almost_complete_letter_range)]
    = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
 
 error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
-  --> tests/ui/rename.rs:67:9
+  --> tests/ui/rename.rs:68:9
    |
 LL | #![warn(clippy::blacklisted_name)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
 
 error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_conditions`
-  --> tests/ui/rename.rs:68:9
+  --> tests/ui/rename.rs:69:9
    |
 LL | #![warn(clippy::block_in_if_condition_expr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
 
 error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_conditions`
-  --> tests/ui/rename.rs:69:9
+  --> tests/ui/rename.rs:70:9
    |
 LL | #![warn(clippy::block_in_if_condition_stmt)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
 
 error: lint `clippy::blocks_in_if_conditions` has been renamed to `clippy::blocks_in_conditions`
-  --> tests/ui/rename.rs:70:9
+  --> tests/ui/rename.rs:71:9
    |
 LL | #![warn(clippy::blocks_in_if_conditions)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
 
 error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
-  --> tests/ui/rename.rs:71:9
+  --> tests/ui/rename.rs:72:9
    |
 LL | #![warn(clippy::box_vec)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 
 error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
-  --> tests/ui/rename.rs:72:9
+  --> tests/ui/rename.rs:73:9
    |
 LL | #![warn(clippy::const_static_lifetime)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> tests/ui/rename.rs:73:9
+  --> tests/ui/rename.rs:74:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
 error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
-  --> tests/ui/rename.rs:74:9
+  --> tests/ui/rename.rs:75:9
    |
 LL | #![warn(clippy::derive_hash_xor_eq)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
 
 error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-  --> tests/ui/rename.rs:75:9
+  --> tests/ui/rename.rs:76:9
    |
 LL | #![warn(clippy::disallowed_method)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
 error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
-  --> tests/ui/rename.rs:76:9
+  --> tests/ui/rename.rs:77:9
    |
 LL | #![warn(clippy::disallowed_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
 
 error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
-  --> tests/ui/rename.rs:77:9
+  --> tests/ui/rename.rs:78:9
    |
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
 error: lint `clippy::find_map` has been renamed to `clippy::manual_find_map`
-  --> tests/ui/rename.rs:78:9
+  --> tests/ui/rename.rs:79:9
    |
 LL | #![warn(clippy::find_map)]
    |         ^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_find_map`
 
 error: lint `clippy::filter_map` has been renamed to `clippy::manual_filter_map`
-  --> tests/ui/rename.rs:79:9
+  --> tests/ui/rename.rs:80:9
    |
 LL | #![warn(clippy::filter_map)]
    |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_filter_map`
 
 error: lint `clippy::fn_address_comparisons` has been renamed to `unpredictable_function_pointer_comparisons`
-  --> tests/ui/rename.rs:80:9
+  --> tests/ui/rename.rs:81:9
    |
 LL | #![warn(clippy::fn_address_comparisons)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unpredictable_function_pointer_comparisons`
 
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> tests/ui/rename.rs:81:9
+  --> tests/ui/rename.rs:82:9
    |
 LL | #![warn(clippy::identity_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
 error: lint `clippy::if_let_redundant_pattern_matching` has been renamed to `clippy::redundant_pattern_matching`
-  --> tests/ui/rename.rs:82:9
+  --> tests/ui/rename.rs:83:9
    |
 LL | #![warn(clippy::if_let_redundant_pattern_matching)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_pattern_matching`
 
 error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
-  --> tests/ui/rename.rs:83:9
+  --> tests/ui/rename.rs:84:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
 error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl`
-  --> tests/ui/rename.rs:84:9
+  --> tests/ui/rename.rs:85:9
    |
 LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl`
 
 error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl`
-  --> tests/ui/rename.rs:85:9
+  --> tests/ui/rename.rs:86:9
    |
 LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl`
 
 error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects`
-  --> tests/ui/rename.rs:86:9
+  --> tests/ui/rename.rs:87:9
    |
 LL | #![warn(clippy::integer_arithmetic)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects`
 
 error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
-  --> tests/ui/rename.rs:87:9
+  --> tests/ui/rename.rs:88:9
    |
 LL | #![warn(clippy::logic_bug)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
 
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> tests/ui/rename.rs:88:9
+  --> tests/ui/rename.rs:89:9
    |
 LL | #![warn(clippy::new_without_default_derive)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
 error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
-  --> tests/ui/rename.rs:89:9
+  --> tests/ui/rename.rs:90:9
    |
 LL | #![warn(clippy::option_and_then_some)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
 error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
-  --> tests/ui/rename.rs:90:9
+  --> tests/ui/rename.rs:91:9
    |
 LL | #![warn(clippy::option_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
-  --> tests/ui/rename.rs:91:9
+  --> tests/ui/rename.rs:92:9
    |
 LL | #![warn(clippy::option_map_unwrap_or)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> tests/ui/rename.rs:92:9
+  --> tests/ui/rename.rs:93:9
    |
 LL | #![warn(clippy::option_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> tests/ui/rename.rs:93:9
+  --> tests/ui/rename.rs:94:9
    |
 LL | #![warn(clippy::option_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::overflow_check_conditional` has been renamed to `clippy::panicking_overflow_checks`
-  --> tests/ui/rename.rs:94:9
+  --> tests/ui/rename.rs:95:9
    |
 LL | #![warn(clippy::overflow_check_conditional)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::panicking_overflow_checks`
 
 error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
-  --> tests/ui/rename.rs:95:9
+  --> tests/ui/rename.rs:96:9
    |
 LL | #![warn(clippy::ref_in_deref)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
 error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
-  --> tests/ui/rename.rs:96:9
+  --> tests/ui/rename.rs:97:9
    |
 LL | #![warn(clippy::result_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> tests/ui/rename.rs:97:9
+  --> tests/ui/rename.rs:98:9
    |
 LL | #![warn(clippy::result_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> tests/ui/rename.rs:98:9
+  --> tests/ui/rename.rs:99:9
    |
 LL | #![warn(clippy::result_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
-  --> tests/ui/rename.rs:99:9
+  --> tests/ui/rename.rs:100:9
    |
 LL | #![warn(clippy::single_char_push_str)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
 error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-  --> tests/ui/rename.rs:100:9
+  --> tests/ui/rename.rs:101:9
    |
 LL | #![warn(clippy::stutter)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
 error: lint `clippy::thread_local_initializer_can_be_made_const` has been renamed to `clippy::missing_const_for_thread_local`
-  --> tests/ui/rename.rs:101:9
+  --> tests/ui/rename.rs:102:9
    |
 LL | #![warn(clippy::thread_local_initializer_can_be_made_const)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::missing_const_for_thread_local`
 
 error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
-  --> tests/ui/rename.rs:102:9
+  --> tests/ui/rename.rs:103:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
 error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default`
-  --> tests/ui/rename.rs:103:9
+  --> tests/ui/rename.rs:104:9
    |
 LL | #![warn(clippy::unwrap_or_else_default)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default`
 
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> tests/ui/rename.rs:104:9
+  --> tests/ui/rename.rs:105:9
    |
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting`
-  --> tests/ui/rename.rs:105:9
+  --> tests/ui/rename.rs:106:9
    |
 LL | #![warn(clippy::cast_ref_to_mut)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting`
 
 error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
-  --> tests/ui/rename.rs:106:9
+  --> tests/ui/rename.rs:107:9
    |
 LL | #![warn(clippy::clone_double_ref)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
 
 error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons`
-  --> tests/ui/rename.rs:107:9
+  --> tests/ui/rename.rs:108:9
    |
 LL | #![warn(clippy::cmp_nan)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons`
 
 error: lint `clippy::invalid_null_ptr_usage` has been renamed to `invalid_null_arguments`
-  --> tests/ui/rename.rs:108:9
+  --> tests/ui/rename.rs:109:9
    |
 LL | #![warn(clippy::invalid_null_ptr_usage)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_null_arguments`
 
 error: lint `clippy::double_neg` has been renamed to `double_negations`
-  --> tests/ui/rename.rs:109:9
+  --> tests/ui/rename.rs:110:9
    |
 LL | #![warn(clippy::double_neg)]
    |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `double_negations`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> tests/ui/rename.rs:110:9
+  --> tests/ui/rename.rs:111:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types`
-  --> tests/ui/rename.rs:111:9
+  --> tests/ui/rename.rs:112:9
    |
 LL | #![warn(clippy::drop_copy)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types`
 
 error: lint `clippy::drop_ref` has been renamed to `dropping_references`
-  --> tests/ui/rename.rs:112:9
+  --> tests/ui/rename.rs:113:9
    |
 LL | #![warn(clippy::drop_ref)]
    |         ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references`
 
 error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks`
-  --> tests/ui/rename.rs:113:9
+  --> tests/ui/rename.rs:114:9
    |
 LL | #![warn(clippy::fn_null_check)]
    |         ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks`
 
 error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
-  --> tests/ui/rename.rs:114:9
+  --> tests/ui/rename.rs:115:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
-  --> tests/ui/rename.rs:115:9
+  --> tests/ui/rename.rs:116:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
-  --> tests/ui/rename.rs:116:9
+  --> tests/ui/rename.rs:117:9
    |
 LL | #![warn(clippy::for_loops_over_fallibles)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types`
-  --> tests/ui/rename.rs:117:9
+  --> tests/ui/rename.rs:118:9
    |
 LL | #![warn(clippy::forget_copy)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types`
 
 error: lint `clippy::forget_ref` has been renamed to `forgetting_references`
-  --> tests/ui/rename.rs:118:9
+  --> tests/ui/rename.rs:119:9
    |
 LL | #![warn(clippy::forget_ref)]
    |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> tests/ui/rename.rs:119:9
+  --> tests/ui/rename.rs:120:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> tests/ui/rename.rs:120:9
+  --> tests/ui/rename.rs:121:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> tests/ui/rename.rs:121:9
+  --> tests/ui/rename.rs:122:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked`
-  --> tests/ui/rename.rs:122:9
+  --> tests/ui/rename.rs:123:9
    |
 LL | #![warn(clippy::invalid_utf8_in_unchecked)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked`
 
 error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
-  --> tests/ui/rename.rs:123:9
+  --> tests/ui/rename.rs:124:9
    |
 LL | #![warn(clippy::let_underscore_drop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
 error: lint `clippy::maybe_misused_cfg` has been renamed to `unexpected_cfgs`
-  --> tests/ui/rename.rs:124:9
+  --> tests/ui/rename.rs:125:9
    |
 LL | #![warn(clippy::maybe_misused_cfg)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> tests/ui/rename.rs:125:9
+  --> tests/ui/rename.rs:126:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
 error: lint `clippy::mismatched_target_os` has been renamed to `unexpected_cfgs`
-  --> tests/ui/rename.rs:126:9
+  --> tests/ui/rename.rs:127:9
    |
 LL | #![warn(clippy::mismatched_target_os)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs`
 
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> tests/ui/rename.rs:127:9
+  --> tests/ui/rename.rs:128:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
-  --> tests/ui/rename.rs:128:9
+  --> tests/ui/rename.rs:129:9
    |
 LL | #![warn(clippy::positional_named_format_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
-  --> tests/ui/rename.rs:129:9
+  --> tests/ui/rename.rs:130:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
 
 error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
-  --> tests/ui/rename.rs:130:9
+  --> tests/ui/rename.rs:131:9
    |
 LL | #![warn(clippy::undropped_manually_drops)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> tests/ui/rename.rs:131:9
+  --> tests/ui/rename.rs:132:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> tests/ui/rename.rs:132:9
+  --> tests/ui/rename.rs:133:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
 error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons`
-  --> tests/ui/rename.rs:133:9
+  --> tests/ui/rename.rs:134:9
    |
 LL | #![warn(clippy::vtable_address_comparisons)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons`
 
 error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_empty_ranges`
-  --> tests/ui/rename.rs:134:9
+  --> tests/ui/rename.rs:135:9
    |
 LL | #![warn(clippy::reverse_range_loop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges`
 
-error: aborting due to 69 previous errors
+error: lint `clippy::transmute_int_to_float` has been renamed to `unnecessary_transmutes`
+  --> tests/ui/rename.rs:136:9
+   |
+LL | #![warn(clippy::transmute_int_to_float)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes`
+
+error: lint `clippy::transmute_int_to_char` has been renamed to `unnecessary_transmutes`
+  --> tests/ui/rename.rs:137:9
+   |
+LL | #![warn(clippy::transmute_int_to_char)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes`
+
+error: lint `clippy::transmute_float_to_int` has been renamed to `unnecessary_transmutes`
+  --> tests/ui/rename.rs:138:9
+   |
+LL | #![warn(clippy::transmute_float_to_int)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes`
+
+error: lint `clippy::transmute_num_to_bytes` has been renamed to `unnecessary_transmutes`
+  --> tests/ui/rename.rs:139:9
+   |
+LL | #![warn(clippy::transmute_num_to_bytes)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes`
+
+error: aborting due to 73 previous errors
 
diff --git a/tests/ui/transmute.rs b/tests/ui/transmute.rs
index 2b8b6c539ad3c..e968e7a59244d 100644
--- a/tests/ui/transmute.rs
+++ b/tests/ui/transmute.rs
@@ -116,138 +116,6 @@ fn int_to_bool() {
     //~^ transmute_int_to_bool
 }
 
-#[warn(clippy::transmute_int_to_float)]
-mod int_to_float {
-    fn test() {
-        let _: f16 = unsafe { std::mem::transmute(0_u16) };
-        //~^ transmute_int_to_float
-
-        let _: f16 = unsafe { std::mem::transmute(0_i16) };
-        //~^ transmute_int_to_float
-
-        let _: f32 = unsafe { std::mem::transmute(0_u32) };
-        //~^ transmute_int_to_float
-
-        let _: f32 = unsafe { std::mem::transmute(0_i32) };
-        //~^ transmute_int_to_float
-
-        let _: f64 = unsafe { std::mem::transmute(0_u64) };
-        //~^ transmute_int_to_float
-
-        let _: f64 = unsafe { std::mem::transmute(0_i64) };
-        //~^ transmute_int_to_float
-
-        let _: f128 = unsafe { std::mem::transmute(0_u128) };
-        //~^ transmute_int_to_float
-
-        let _: f128 = unsafe { std::mem::transmute(0_i128) };
-        //~^ transmute_int_to_float
-    }
-
-    mod issue_5747 {
-        const VALUE16: f16 = unsafe { std::mem::transmute(0_u16) };
-        //~^ transmute_int_to_float
-
-        const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) };
-        //~^ transmute_int_to_float
-
-        const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) };
-        //~^ transmute_int_to_float
-
-        const VALUE128: f128 = unsafe { std::mem::transmute(0_i128) };
-        //~^ transmute_int_to_float
-
-        const fn from_bits_16(v: i16) -> f16 {
-            unsafe { std::mem::transmute(v) }
-            //~^ transmute_int_to_float
-        }
-
-        const fn from_bits_32(v: i32) -> f32 {
-            unsafe { std::mem::transmute(v) }
-            //~^ transmute_int_to_float
-        }
-
-        const fn from_bits_64(v: u64) -> f64 {
-            unsafe { std::mem::transmute(v) }
-            //~^ transmute_int_to_float
-        }
-
-        const fn from_bits_128(v: u128) -> f128 {
-            unsafe { std::mem::transmute(v) }
-            //~^ transmute_int_to_float
-        }
-    }
-}
-
-mod num_to_bytes {
-    fn test() {
-        unsafe {
-            let _: [u8; 1] = std::mem::transmute(0u8);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 4] = std::mem::transmute(0u32);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 16] = std::mem::transmute(0u128);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 1] = std::mem::transmute(0i8);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 4] = std::mem::transmute(0i32);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 16] = std::mem::transmute(0i128);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 2] = std::mem::transmute(0.0f16);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 4] = std::mem::transmute(0.0f32);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 8] = std::mem::transmute(0.0f64);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 16] = std::mem::transmute(0.0f128);
-            //~^ transmute_num_to_bytes
-        }
-    }
-    const fn test_const() {
-        unsafe {
-            let _: [u8; 1] = std::mem::transmute(0u8);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 4] = std::mem::transmute(0u32);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 16] = std::mem::transmute(0u128);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 1] = std::mem::transmute(0i8);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 4] = std::mem::transmute(0i32);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 16] = std::mem::transmute(0i128);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 2] = std::mem::transmute(0.0f16);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 4] = std::mem::transmute(0.0f32);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 8] = std::mem::transmute(0.0f64);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 16] = std::mem::transmute(0.0f128);
-            //~^ transmute_num_to_bytes
-        }
-    }
-}
-
 fn bytes_to_str(mb: &mut [u8]) {
     const B: &[u8] = b"";
 
diff --git a/tests/ui/transmute.stderr b/tests/ui/transmute.stderr
index 1bb70151965cd..79528ec06f1bf 100644
--- a/tests/ui/transmute.stderr
+++ b/tests/ui/transmute.stderr
@@ -97,230 +97,8 @@ LL |     let _: bool = unsafe { std::mem::transmute(0_u8) };
    = note: `-D clippy::transmute-int-to-bool` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_bool)]`
 
-error: transmute from a `u16` to a `f16`
-  --> tests/ui/transmute.rs:122:31
-   |
-LL |         let _: f16 = unsafe { std::mem::transmute(0_u16) };
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_u16)`
-   |
-   = note: `-D clippy::transmute-int-to-float` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_float)]`
-
-error: transmute from a `i16` to a `f16`
-  --> tests/ui/transmute.rs:125:31
-   |
-LL |         let _: f16 = unsafe { std::mem::transmute(0_i16) };
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_i16 as u16)`
-
-error: transmute from a `u32` to a `f32`
-  --> tests/ui/transmute.rs:128:31
-   |
-LL |         let _: f32 = unsafe { std::mem::transmute(0_u32) };
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)`
-
-error: transmute from a `i32` to a `f32`
-  --> tests/ui/transmute.rs:131:31
-   |
-LL |         let _: f32 = unsafe { std::mem::transmute(0_i32) };
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)`
-
-error: transmute from a `u64` to a `f64`
-  --> tests/ui/transmute.rs:134:31
-   |
-LL |         let _: f64 = unsafe { std::mem::transmute(0_u64) };
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_u64)`
-
-error: transmute from a `i64` to a `f64`
-  --> tests/ui/transmute.rs:137:31
-   |
-LL |         let _: f64 = unsafe { std::mem::transmute(0_i64) };
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)`
-
-error: transmute from a `u128` to a `f128`
-  --> tests/ui/transmute.rs:140:32
-   |
-LL |         let _: f128 = unsafe { std::mem::transmute(0_u128) };
-   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_u128)`
-
-error: transmute from a `i128` to a `f128`
-  --> tests/ui/transmute.rs:143:32
-   |
-LL |         let _: f128 = unsafe { std::mem::transmute(0_i128) };
-   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)`
-
-error: transmute from a `u16` to a `f16`
-  --> tests/ui/transmute.rs:148:39
-   |
-LL |         const VALUE16: f16 = unsafe { std::mem::transmute(0_u16) };
-   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_u16)`
-
-error: transmute from a `u32` to a `f32`
-  --> tests/ui/transmute.rs:151:39
-   |
-LL |         const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) };
-   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)`
-
-error: transmute from a `i64` to a `f64`
-  --> tests/ui/transmute.rs:154:39
-   |
-LL |         const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) };
-   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)`
-
-error: transmute from a `i128` to a `f128`
-  --> tests/ui/transmute.rs:157:41
-   |
-LL |         const VALUE128: f128 = unsafe { std::mem::transmute(0_i128) };
-   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)`
-
-error: transmute from a `i16` to a `f16`
-  --> tests/ui/transmute.rs:161:22
-   |
-LL |             unsafe { std::mem::transmute(v) }
-   |                      ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(v as u16)`
-
-error: transmute from a `i32` to a `f32`
-  --> tests/ui/transmute.rs:166:22
-   |
-LL |             unsafe { std::mem::transmute(v) }
-   |                      ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(v as u32)`
-
-error: transmute from a `u64` to a `f64`
-  --> tests/ui/transmute.rs:171:22
-   |
-LL |             unsafe { std::mem::transmute(v) }
-   |                      ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(v)`
-
-error: transmute from a `u128` to a `f128`
-  --> tests/ui/transmute.rs:176:22
-   |
-LL |             unsafe { std::mem::transmute(v) }
-   |                      ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(v)`
-
-error: transmute from a `u8` to a `[u8; 1]`
-  --> tests/ui/transmute.rs:185:30
-   |
-LL |             let _: [u8; 1] = std::mem::transmute(0u8);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
-   |
-   = note: `-D clippy::transmute-num-to-bytes` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::transmute_num_to_bytes)]`
-
-error: transmute from a `u32` to a `[u8; 4]`
-  --> tests/ui/transmute.rs:188:30
-   |
-LL |             let _: [u8; 4] = std::mem::transmute(0u32);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
-
-error: transmute from a `u128` to a `[u8; 16]`
-  --> tests/ui/transmute.rs:191:31
-   |
-LL |             let _: [u8; 16] = std::mem::transmute(0u128);
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
-
-error: transmute from a `i8` to a `[u8; 1]`
-  --> tests/ui/transmute.rs:194:30
-   |
-LL |             let _: [u8; 1] = std::mem::transmute(0i8);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
-
-error: transmute from a `i32` to a `[u8; 4]`
-  --> tests/ui/transmute.rs:197:30
-   |
-LL |             let _: [u8; 4] = std::mem::transmute(0i32);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
-
-error: transmute from a `i128` to a `[u8; 16]`
-  --> tests/ui/transmute.rs:200:31
-   |
-LL |             let _: [u8; 16] = std::mem::transmute(0i128);
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
-
-error: transmute from a `f16` to a `[u8; 2]`
-  --> tests/ui/transmute.rs:203:30
-   |
-LL |             let _: [u8; 2] = std::mem::transmute(0.0f16);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()`
-
-error: transmute from a `f32` to a `[u8; 4]`
-  --> tests/ui/transmute.rs:206:30
-   |
-LL |             let _: [u8; 4] = std::mem::transmute(0.0f32);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()`
-
-error: transmute from a `f64` to a `[u8; 8]`
-  --> tests/ui/transmute.rs:209:30
-   |
-LL |             let _: [u8; 8] = std::mem::transmute(0.0f64);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()`
-
-error: transmute from a `f128` to a `[u8; 16]`
-  --> tests/ui/transmute.rs:212:31
-   |
-LL |             let _: [u8; 16] = std::mem::transmute(0.0f128);
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()`
-
-error: transmute from a `u8` to a `[u8; 1]`
-  --> tests/ui/transmute.rs:218:30
-   |
-LL |             let _: [u8; 1] = std::mem::transmute(0u8);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
-
-error: transmute from a `u32` to a `[u8; 4]`
-  --> tests/ui/transmute.rs:221:30
-   |
-LL |             let _: [u8; 4] = std::mem::transmute(0u32);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
-
-error: transmute from a `u128` to a `[u8; 16]`
-  --> tests/ui/transmute.rs:224:31
-   |
-LL |             let _: [u8; 16] = std::mem::transmute(0u128);
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
-
-error: transmute from a `i8` to a `[u8; 1]`
-  --> tests/ui/transmute.rs:227:30
-   |
-LL |             let _: [u8; 1] = std::mem::transmute(0i8);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
-
-error: transmute from a `i32` to a `[u8; 4]`
-  --> tests/ui/transmute.rs:230:30
-   |
-LL |             let _: [u8; 4] = std::mem::transmute(0i32);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
-
-error: transmute from a `i128` to a `[u8; 16]`
-  --> tests/ui/transmute.rs:233:31
-   |
-LL |             let _: [u8; 16] = std::mem::transmute(0i128);
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
-
-error: transmute from a `f16` to a `[u8; 2]`
-  --> tests/ui/transmute.rs:236:30
-   |
-LL |             let _: [u8; 2] = std::mem::transmute(0.0f16);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()`
-
-error: transmute from a `f32` to a `[u8; 4]`
-  --> tests/ui/transmute.rs:239:30
-   |
-LL |             let _: [u8; 4] = std::mem::transmute(0.0f32);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()`
-
-error: transmute from a `f64` to a `[u8; 8]`
-  --> tests/ui/transmute.rs:242:30
-   |
-LL |             let _: [u8; 8] = std::mem::transmute(0.0f64);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()`
-
-error: transmute from a `f128` to a `[u8; 16]`
-  --> tests/ui/transmute.rs:245:31
-   |
-LL |             let _: [u8; 16] = std::mem::transmute(0.0f128);
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()`
-
 error: transmute from a `&[u8]` to a `&str`
-  --> tests/ui/transmute.rs:254:28
+  --> tests/ui/transmute.rs:122:28
    |
 LL |     let _: &str = unsafe { std::mem::transmute(B) };
    |                            ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()`
@@ -329,16 +107,16 @@ LL |     let _: &str = unsafe { std::mem::transmute(B) };
    = help: to override `-D warnings` add `#[allow(clippy::transmute_bytes_to_str)]`
 
 error: transmute from a `&mut [u8]` to a `&mut str`
-  --> tests/ui/transmute.rs:257:32
+  --> tests/ui/transmute.rs:125:32
    |
 LL |     let _: &mut str = unsafe { std::mem::transmute(mb) };
    |                                ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()`
 
 error: transmute from a `&[u8]` to a `&str`
-  --> tests/ui/transmute.rs:260:30
+  --> tests/ui/transmute.rs:128:30
    |
 LL |     const _: &str = unsafe { std::mem::transmute(B) };
    |                              ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)`
 
-error: aborting due to 54 previous errors
+error: aborting due to 18 previous errors
 
diff --git a/tests/ui/transmute_float_to_int.fixed b/tests/ui/transmute_float_to_int.fixed
deleted file mode 100644
index 844445907d7c2..0000000000000
--- a/tests/ui/transmute_float_to_int.fixed
+++ /dev/null
@@ -1,60 +0,0 @@
-#![warn(clippy::transmute_float_to_int)]
-#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]
-#![feature(f128)]
-#![feature(f16)]
-
-fn float_to_int() {
-    let _: u32 = unsafe { 1f32.to_bits() };
-    //~^ transmute_float_to_int
-
-    let _: i32 = unsafe { 1f32.to_bits() as i32 };
-    //~^ transmute_float_to_int
-
-    let _: u64 = unsafe { 1f64.to_bits() };
-    //~^ transmute_float_to_int
-
-    let _: i64 = unsafe { 1f64.to_bits() as i64 };
-    //~^ transmute_float_to_int
-
-    let _: u64 = unsafe { 1.0f64.to_bits() };
-    //~^ transmute_float_to_int
-
-    let _: u64 = unsafe { (-1.0f64).to_bits() };
-    //~^ transmute_float_to_int
-}
-
-mod issue_5747 {
-    const VALUE16: i16 = unsafe { 1f16.to_bits() as i16 };
-    //~^ transmute_float_to_int
-
-    const VALUE32: i32 = unsafe { 1f32.to_bits() as i32 };
-    //~^ transmute_float_to_int
-
-    const VALUE64: u64 = unsafe { 1f64.to_bits() };
-    //~^ transmute_float_to_int
-
-    const VALUE128: u128 = unsafe { 1f128.to_bits() };
-    //~^ transmute_float_to_int
-
-    const fn to_bits_16(v: f16) -> u16 {
-        unsafe { v.to_bits() }
-        //~^ transmute_float_to_int
-    }
-
-    const fn to_bits_32(v: f32) -> u32 {
-        unsafe { v.to_bits() }
-        //~^ transmute_float_to_int
-    }
-
-    const fn to_bits_64(v: f64) -> i64 {
-        unsafe { v.to_bits() as i64 }
-        //~^ transmute_float_to_int
-    }
-
-    const fn to_bits_128(v: f128) -> i128 {
-        unsafe { v.to_bits() as i128 }
-        //~^ transmute_float_to_int
-    }
-}
-
-fn main() {}
diff --git a/tests/ui/transmute_float_to_int.rs b/tests/ui/transmute_float_to_int.rs
deleted file mode 100644
index a1f3b15bbfee4..0000000000000
--- a/tests/ui/transmute_float_to_int.rs
+++ /dev/null
@@ -1,60 +0,0 @@
-#![warn(clippy::transmute_float_to_int)]
-#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]
-#![feature(f128)]
-#![feature(f16)]
-
-fn float_to_int() {
-    let _: u32 = unsafe { std::mem::transmute(1f32) };
-    //~^ transmute_float_to_int
-
-    let _: i32 = unsafe { std::mem::transmute(1f32) };
-    //~^ transmute_float_to_int
-
-    let _: u64 = unsafe { std::mem::transmute(1f64) };
-    //~^ transmute_float_to_int
-
-    let _: i64 = unsafe { std::mem::transmute(1f64) };
-    //~^ transmute_float_to_int
-
-    let _: u64 = unsafe { std::mem::transmute(1.0) };
-    //~^ transmute_float_to_int
-
-    let _: u64 = unsafe { std::mem::transmute(-1.0) };
-    //~^ transmute_float_to_int
-}
-
-mod issue_5747 {
-    const VALUE16: i16 = unsafe { std::mem::transmute(1f16) };
-    //~^ transmute_float_to_int
-
-    const VALUE32: i32 = unsafe { std::mem::transmute(1f32) };
-    //~^ transmute_float_to_int
-
-    const VALUE64: u64 = unsafe { std::mem::transmute(1f64) };
-    //~^ transmute_float_to_int
-
-    const VALUE128: u128 = unsafe { std::mem::transmute(1f128) };
-    //~^ transmute_float_to_int
-
-    const fn to_bits_16(v: f16) -> u16 {
-        unsafe { std::mem::transmute(v) }
-        //~^ transmute_float_to_int
-    }
-
-    const fn to_bits_32(v: f32) -> u32 {
-        unsafe { std::mem::transmute(v) }
-        //~^ transmute_float_to_int
-    }
-
-    const fn to_bits_64(v: f64) -> i64 {
-        unsafe { std::mem::transmute(v) }
-        //~^ transmute_float_to_int
-    }
-
-    const fn to_bits_128(v: f128) -> i128 {
-        unsafe { std::mem::transmute(v) }
-        //~^ transmute_float_to_int
-    }
-}
-
-fn main() {}
diff --git a/tests/ui/transmute_float_to_int.stderr b/tests/ui/transmute_float_to_int.stderr
deleted file mode 100644
index 223cbc4e90c07..0000000000000
--- a/tests/ui/transmute_float_to_int.stderr
+++ /dev/null
@@ -1,89 +0,0 @@
-error: transmute from a `f32` to a `u32`
-  --> tests/ui/transmute_float_to_int.rs:7:27
-   |
-LL |     let _: u32 = unsafe { std::mem::transmute(1f32) };
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits()`
-   |
-   = note: `-D clippy::transmute-float-to-int` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::transmute_float_to_int)]`
-
-error: transmute from a `f32` to a `i32`
-  --> tests/ui/transmute_float_to_int.rs:10:27
-   |
-LL |     let _: i32 = unsafe { std::mem::transmute(1f32) };
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits() as i32`
-
-error: transmute from a `f64` to a `u64`
-  --> tests/ui/transmute_float_to_int.rs:13:27
-   |
-LL |     let _: u64 = unsafe { std::mem::transmute(1f64) };
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits()`
-
-error: transmute from a `f64` to a `i64`
-  --> tests/ui/transmute_float_to_int.rs:16:27
-   |
-LL |     let _: i64 = unsafe { std::mem::transmute(1f64) };
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits() as i64`
-
-error: transmute from a `f64` to a `u64`
-  --> tests/ui/transmute_float_to_int.rs:19:27
-   |
-LL |     let _: u64 = unsafe { std::mem::transmute(1.0) };
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.0f64.to_bits()`
-
-error: transmute from a `f64` to a `u64`
-  --> tests/ui/transmute_float_to_int.rs:22:27
-   |
-LL |     let _: u64 = unsafe { std::mem::transmute(-1.0) };
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-1.0f64).to_bits()`
-
-error: transmute from a `f16` to a `i16`
-  --> tests/ui/transmute_float_to_int.rs:27:35
-   |
-LL |     const VALUE16: i16 = unsafe { std::mem::transmute(1f16) };
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f16.to_bits() as i16`
-
-error: transmute from a `f32` to a `i32`
-  --> tests/ui/transmute_float_to_int.rs:30:35
-   |
-LL |     const VALUE32: i32 = unsafe { std::mem::transmute(1f32) };
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits() as i32`
-
-error: transmute from a `f64` to a `u64`
-  --> tests/ui/transmute_float_to_int.rs:33:35
-   |
-LL |     const VALUE64: u64 = unsafe { std::mem::transmute(1f64) };
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits()`
-
-error: transmute from a `f128` to a `u128`
-  --> tests/ui/transmute_float_to_int.rs:36:37
-   |
-LL |     const VALUE128: u128 = unsafe { std::mem::transmute(1f128) };
-   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f128.to_bits()`
-
-error: transmute from a `f16` to a `u16`
-  --> tests/ui/transmute_float_to_int.rs:40:18
-   |
-LL |         unsafe { std::mem::transmute(v) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits()`
-
-error: transmute from a `f32` to a `u32`
-  --> tests/ui/transmute_float_to_int.rs:45:18
-   |
-LL |         unsafe { std::mem::transmute(v) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits()`
-
-error: transmute from a `f64` to a `i64`
-  --> tests/ui/transmute_float_to_int.rs:50:18
-   |
-LL |         unsafe { std::mem::transmute(v) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits() as i64`
-
-error: transmute from a `f128` to a `i128`
-  --> tests/ui/transmute_float_to_int.rs:55:18
-   |
-LL |         unsafe { std::mem::transmute(v) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits() as i128`
-
-error: aborting due to 14 previous errors
-
diff --git a/tests/ui/transmute_int_to_char.fixed b/tests/ui/transmute_int_to_char.fixed
deleted file mode 100644
index 28644aa9ebbb7..0000000000000
--- a/tests/ui/transmute_int_to_char.fixed
+++ /dev/null
@@ -1,16 +0,0 @@
-#![warn(clippy::transmute_int_to_char)]
-#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]
-
-fn int_to_char() {
-    let _: char = unsafe { std::char::from_u32(0_u32).unwrap() };
-    //~^ transmute_int_to_char
-
-    let _: char = unsafe { std::char::from_u32(0_i32 as u32).unwrap() };
-    //~^ transmute_int_to_char
-
-    // These shouldn't warn
-    const _: char = unsafe { std::mem::transmute(0_u32) };
-    const _: char = unsafe { std::mem::transmute(0_i32) };
-}
-
-fn main() {}
diff --git a/tests/ui/transmute_int_to_char.rs b/tests/ui/transmute_int_to_char.rs
deleted file mode 100644
index 8c83ecc8914b6..0000000000000
--- a/tests/ui/transmute_int_to_char.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-#![warn(clippy::transmute_int_to_char)]
-#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]
-
-fn int_to_char() {
-    let _: char = unsafe { std::mem::transmute(0_u32) };
-    //~^ transmute_int_to_char
-
-    let _: char = unsafe { std::mem::transmute(0_i32) };
-    //~^ transmute_int_to_char
-
-    // These shouldn't warn
-    const _: char = unsafe { std::mem::transmute(0_u32) };
-    const _: char = unsafe { std::mem::transmute(0_i32) };
-}
-
-fn main() {}
diff --git a/tests/ui/transmute_int_to_char.stderr b/tests/ui/transmute_int_to_char.stderr
deleted file mode 100644
index e3a3620f28b75..0000000000000
--- a/tests/ui/transmute_int_to_char.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-error: transmute from a `u32` to a `char`
-  --> tests/ui/transmute_int_to_char.rs:5:28
-   |
-LL |     let _: char = unsafe { std::mem::transmute(0_u32) };
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_u32).unwrap()`
-   |
-   = note: `-D clippy::transmute-int-to-char` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_char)]`
-
-error: transmute from a `i32` to a `char`
-  --> tests/ui/transmute_int_to_char.rs:8:28
-   |
-LL |     let _: char = unsafe { std::mem::transmute(0_i32) };
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_i32 as u32).unwrap()`
-
-error: aborting due to 2 previous errors
-
diff --git a/tests/ui/transmute_int_to_char_no_std.fixed b/tests/ui/transmute_int_to_char_no_std.fixed
deleted file mode 100644
index e6e09a2be4bf5..0000000000000
--- a/tests/ui/transmute_int_to_char_no_std.fixed
+++ /dev/null
@@ -1,28 +0,0 @@
-#![no_std]
-#![feature(lang_items)]
-#![warn(clippy::transmute_int_to_char)]
-#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]
-
-use core::panic::PanicInfo;
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
-
-#[panic_handler]
-fn panic(info: &PanicInfo) -> ! {
-    loop {}
-}
-
-fn int_to_char() {
-    let _: char = unsafe { core::char::from_u32(0_u32).unwrap() };
-    //~^ transmute_int_to_char
-
-    let _: char = unsafe { core::char::from_u32(0_i32 as u32).unwrap() };
-    //~^ transmute_int_to_char
-
-    // These shouldn't warn
-    const _: char = unsafe { core::mem::transmute(0_u32) };
-    const _: char = unsafe { core::mem::transmute(0_i32) };
-}
-
-fn main() {}
diff --git a/tests/ui/transmute_int_to_char_no_std.rs b/tests/ui/transmute_int_to_char_no_std.rs
deleted file mode 100644
index 0f2106df00e6c..0000000000000
--- a/tests/ui/transmute_int_to_char_no_std.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-#![no_std]
-#![feature(lang_items)]
-#![warn(clippy::transmute_int_to_char)]
-#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]
-
-use core::panic::PanicInfo;
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
-
-#[panic_handler]
-fn panic(info: &PanicInfo) -> ! {
-    loop {}
-}
-
-fn int_to_char() {
-    let _: char = unsafe { core::mem::transmute(0_u32) };
-    //~^ transmute_int_to_char
-
-    let _: char = unsafe { core::mem::transmute(0_i32) };
-    //~^ transmute_int_to_char
-
-    // These shouldn't warn
-    const _: char = unsafe { core::mem::transmute(0_u32) };
-    const _: char = unsafe { core::mem::transmute(0_i32) };
-}
-
-fn main() {}
diff --git a/tests/ui/transmute_int_to_char_no_std.stderr b/tests/ui/transmute_int_to_char_no_std.stderr
deleted file mode 100644
index d94580a84d7a4..0000000000000
--- a/tests/ui/transmute_int_to_char_no_std.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-error: transmute from a `u32` to a `char`
-  --> tests/ui/transmute_int_to_char_no_std.rs:17:28
-   |
-LL |     let _: char = unsafe { core::mem::transmute(0_u32) };
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::char::from_u32(0_u32).unwrap()`
-   |
-   = note: `-D clippy::transmute-int-to-char` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_char)]`
-
-error: transmute from a `i32` to a `char`
-  --> tests/ui/transmute_int_to_char_no_std.rs:20:28
-   |
-LL |     let _: char = unsafe { core::mem::transmute(0_i32) };
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::char::from_u32(0_i32 as u32).unwrap()`
-
-error: aborting due to 2 previous errors
-

From 30526830bbf403bd20b4f354557f2f822cf4d227 Mon Sep 17 00:00:00 2001
From: Stan Manilov 
Date: Thu, 8 May 2025 14:39:30 +0300
Subject: [PATCH 2093/4206] Fix minor typo in rustdoc-internals.md

---
 src/doc/rustc-dev-guide/src/rustdoc-internals.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/doc/rustc-dev-guide/src/rustdoc-internals.md b/src/doc/rustc-dev-guide/src/rustdoc-internals.md
index 7f1c83e00f98d..80421b85bf055 100644
--- a/src/doc/rustc-dev-guide/src/rustdoc-internals.md
+++ b/src/doc/rustc-dev-guide/src/rustdoc-internals.md
@@ -55,8 +55,8 @@ The first step in [`clean::utils::krate`][ck1] is to invoke
   * inlining public `use` exports of private items, or showing a "Reexport"
     line in the module page
   * inlining items with `#[doc(hidden)]` if the base item is hidden but the
-  * showing `#[macro_export]`-ed macros at the crate root, regardless of where
-    they're defined reexport is not
+  * showing `#[macro_export]`-ed macros at the crate root, regardless of whether
+    they're defined as a reexport or not
 
 After this step, `clean::krate` invokes [`clean_doc_module`], which actually
 converts the `HIR` items to the cleaned [`AST`][ast]. This is also the step where cross-

From fc20650c6a9aedbea9155b04fb1a4bcc29220480 Mon Sep 17 00:00:00 2001
From: Kornel 
Date: Fri, 9 May 2025 18:57:07 +0900
Subject: [PATCH 2094/4206] Error message for top-level or-patterns suggesting
 a solution

---
 compiler/rustc_parse/messages.ftl                      |  4 ++--
 tests/ui/or-patterns/fn-param-wrap-parens.fixed        |  2 +-
 tests/ui/or-patterns/fn-param-wrap-parens.rs           |  2 +-
 tests/ui/or-patterns/fn-param-wrap-parens.stderr       |  2 +-
 tests/ui/or-patterns/nested-undelimited-precedence.rs  | 10 +++++-----
 .../or-patterns/nested-undelimited-precedence.stderr   | 10 +++++-----
 tests/ui/or-patterns/or-patterns-syntactic-fail.rs     |  8 ++++----
 tests/ui/or-patterns/or-patterns-syntactic-fail.stderr |  8 ++++----
 tests/ui/or-patterns/remove-leading-vert.fixed         |  2 +-
 tests/ui/or-patterns/remove-leading-vert.rs            |  2 +-
 tests/ui/or-patterns/remove-leading-vert.stderr        |  2 +-
 tests/ui/rfcs/rfc-0000-never_patterns/parse.rs         |  2 +-
 tests/ui/rfcs/rfc-0000-never_patterns/parse.stderr     |  2 +-
 13 files changed, 28 insertions(+), 28 deletions(-)

diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 3d7e0fcc30869..f88c15785d336 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -690,8 +690,8 @@ parse_nul_in_c_str = null characters in C string literals are not supported
 
 parse_or_in_let_chain = `||` operators are not supported in let chain conditions
 
-parse_or_pattern_not_allowed_in_fn_parameters = top-level or-patterns are not allowed in function parameters
-parse_or_pattern_not_allowed_in_let_binding = top-level or-patterns are not allowed in `let` bindings
+parse_or_pattern_not_allowed_in_fn_parameters = function parameters require top-level or-patterns in parentheses
+parse_or_pattern_not_allowed_in_let_binding = `let` bindings require top-level or-patterns in parentheses
 parse_out_of_range_hex_escape = out of range hex escape
     .label = must be a character in the range [\x00-\x7f]
 
diff --git a/tests/ui/or-patterns/fn-param-wrap-parens.fixed b/tests/ui/or-patterns/fn-param-wrap-parens.fixed
index fbf60069c7d42..608f826390da6 100644
--- a/tests/ui/or-patterns/fn-param-wrap-parens.fixed
+++ b/tests/ui/or-patterns/fn-param-wrap-parens.fixed
@@ -10,4 +10,4 @@ enum E { A, B }
 use E::*;
 
 #[cfg(false)]
-fn fun1((A | B): E) {} //~ ERROR top-level or-patterns are not allowed
+fn fun1((A | B): E) {} //~ ERROR function parameters require top-level or-patterns in parentheses
diff --git a/tests/ui/or-patterns/fn-param-wrap-parens.rs b/tests/ui/or-patterns/fn-param-wrap-parens.rs
index d796f998e97c7..d6fe7e9bf5860 100644
--- a/tests/ui/or-patterns/fn-param-wrap-parens.rs
+++ b/tests/ui/or-patterns/fn-param-wrap-parens.rs
@@ -10,4 +10,4 @@ enum E { A, B }
 use E::*;
 
 #[cfg(false)]
-fn fun1(A | B: E) {} //~ ERROR top-level or-patterns are not allowed
+fn fun1(A | B: E) {} //~ ERROR function parameters require top-level or-patterns in parentheses
diff --git a/tests/ui/or-patterns/fn-param-wrap-parens.stderr b/tests/ui/or-patterns/fn-param-wrap-parens.stderr
index da2832ef1ae41..e0307b44e8386 100644
--- a/tests/ui/or-patterns/fn-param-wrap-parens.stderr
+++ b/tests/ui/or-patterns/fn-param-wrap-parens.stderr
@@ -1,4 +1,4 @@
-error: top-level or-patterns are not allowed in function parameters
+error: function parameters require top-level or-patterns in parentheses
   --> $DIR/fn-param-wrap-parens.rs:13:9
    |
 LL | fn fun1(A | B: E) {}
diff --git a/tests/ui/or-patterns/nested-undelimited-precedence.rs b/tests/ui/or-patterns/nested-undelimited-precedence.rs
index 047836203575f..73f72cb3f8616 100644
--- a/tests/ui/or-patterns/nested-undelimited-precedence.rs
+++ b/tests/ui/or-patterns/nested-undelimited-precedence.rs
@@ -17,7 +17,7 @@ fn foo() {
     let b @ (A | B): E = A;
 
     let b @ A | B: E = A; //~ERROR `b` is not bound in all patterns
-    //~^ ERROR top-level or-patterns are not allowed
+    //~^ ERROR `let` bindings require top-level or-patterns in parentheses
 }
 
 enum F {
@@ -32,13 +32,13 @@ fn bar() {
     let (A(x) | B(x)): F = A(3);
 
     let &A(_) | B(_): F = A(3); //~ERROR mismatched types
-    //~^ ERROR top-level or-patterns are not allowed
+    //~^ ERROR `let` bindings require top-level or-patterns in parentheses
     let &&A(_) | B(_): F = A(3); //~ERROR mismatched types
-    //~^ ERROR top-level or-patterns are not allowed
+    //~^ ERROR `let` bindings require top-level or-patterns in parentheses
     let &mut A(_) | B(_): F = A(3); //~ERROR mismatched types
-    //~^ ERROR top-level or-patterns are not allowed
+    //~^ ERROR `let` bindings require top-level or-patterns in parentheses
     let &&mut A(_) | B(_): F = A(3); //~ERROR mismatched types
-    //~^ ERROR top-level or-patterns are not allowed
+    //~^ ERROR `let` bindings require top-level or-patterns in parentheses
 }
 
 fn main() {}
diff --git a/tests/ui/or-patterns/nested-undelimited-precedence.stderr b/tests/ui/or-patterns/nested-undelimited-precedence.stderr
index f16d83ecaea93..0835ca1929f15 100644
--- a/tests/ui/or-patterns/nested-undelimited-precedence.stderr
+++ b/tests/ui/or-patterns/nested-undelimited-precedence.stderr
@@ -1,4 +1,4 @@
-error: top-level or-patterns are not allowed in `let` bindings
+error: `let` bindings require top-level or-patterns in parentheses
   --> $DIR/nested-undelimited-precedence.rs:19:9
    |
 LL |     let b @ A | B: E = A;
@@ -9,7 +9,7 @@ help: wrap the pattern in parentheses
 LL |     let (b @ A | B): E = A;
    |         +         +
 
-error: top-level or-patterns are not allowed in `let` bindings
+error: `let` bindings require top-level or-patterns in parentheses
   --> $DIR/nested-undelimited-precedence.rs:34:9
    |
 LL |     let &A(_) | B(_): F = A(3);
@@ -20,7 +20,7 @@ help: wrap the pattern in parentheses
 LL |     let (&A(_) | B(_)): F = A(3);
    |         +            +
 
-error: top-level or-patterns are not allowed in `let` bindings
+error: `let` bindings require top-level or-patterns in parentheses
   --> $DIR/nested-undelimited-precedence.rs:36:9
    |
 LL |     let &&A(_) | B(_): F = A(3);
@@ -31,7 +31,7 @@ help: wrap the pattern in parentheses
 LL |     let (&&A(_) | B(_)): F = A(3);
    |         +             +
 
-error: top-level or-patterns are not allowed in `let` bindings
+error: `let` bindings require top-level or-patterns in parentheses
   --> $DIR/nested-undelimited-precedence.rs:38:9
    |
 LL |     let &mut A(_) | B(_): F = A(3);
@@ -42,7 +42,7 @@ help: wrap the pattern in parentheses
 LL |     let (&mut A(_) | B(_)): F = A(3);
    |         +                +
 
-error: top-level or-patterns are not allowed in `let` bindings
+error: `let` bindings require top-level or-patterns in parentheses
   --> $DIR/nested-undelimited-precedence.rs:40:9
    |
 LL |     let &&mut A(_) | B(_): F = A(3);
diff --git a/tests/ui/or-patterns/or-patterns-syntactic-fail.rs b/tests/ui/or-patterns/or-patterns-syntactic-fail.rs
index 23dbb57cbcf0f..bc4babe709b70 100644
--- a/tests/ui/or-patterns/or-patterns-syntactic-fail.rs
+++ b/tests/ui/or-patterns/or-patterns-syntactic-fail.rs
@@ -16,18 +16,18 @@ fn no_top_level_or_patterns() {
 fn no_top_level_or_patterns_2() {
     // ...and for now neither do we allow or-patterns at the top level of functions.
     fn fun1(A | B: E) {}
-    //~^ ERROR top-level or-patterns are not allowed
+    //~^ ERROR function parameters require top-level or-patterns in parentheses
 
     fn fun2(| A | B: E) {}
-    //~^ ERROR top-level or-patterns are not allowed
+    //~^ ERROR function parameters require top-level or-patterns in parentheses
 
     // We don't allow top-level or-patterns before type annotation in let-statements because we
     // want to reserve this syntactic space for possible future type ascription.
     let A | B: E = A;
-    //~^ ERROR top-level or-patterns are not allowed
+    //~^ ERROR `let` bindings require top-level or-patterns in parentheses
 
     let | A | B: E = A;
-    //~^ ERROR top-level or-patterns are not allowed
+    //~^ ERROR `let` bindings require top-level or-patterns in parentheses
 
     let (A | B): E = A; // ok -- wrapped in parens
 }
diff --git a/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr b/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr
index 74e4ceab80e88..f6b7d427bd60e 100644
--- a/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr
+++ b/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr
@@ -11,7 +11,7 @@ help: you might have meant to open the body of the closure
 LL |     let _ = |A | { B: E| ();
    |                  +
 
-error: top-level or-patterns are not allowed in function parameters
+error: function parameters require top-level or-patterns in parentheses
   --> $DIR/or-patterns-syntactic-fail.rs:18:13
    |
 LL |     fn fun1(A | B: E) {}
@@ -22,7 +22,7 @@ help: wrap the pattern in parentheses
 LL |     fn fun1((A | B): E) {}
    |             +     +
 
-error: top-level or-patterns are not allowed in function parameters
+error: function parameters require top-level or-patterns in parentheses
   --> $DIR/or-patterns-syntactic-fail.rs:21:13
    |
 LL |     fn fun2(| A | B: E) {}
@@ -33,7 +33,7 @@ help: wrap the pattern in parentheses
 LL |     fn fun2((| A | B): E) {}
    |             +       +
 
-error: top-level or-patterns are not allowed in `let` bindings
+error: `let` bindings require top-level or-patterns in parentheses
   --> $DIR/or-patterns-syntactic-fail.rs:26:9
    |
 LL |     let A | B: E = A;
@@ -44,7 +44,7 @@ help: wrap the pattern in parentheses
 LL |     let (A | B): E = A;
    |         +     +
 
-error: top-level or-patterns are not allowed in `let` bindings
+error: `let` bindings require top-level or-patterns in parentheses
   --> $DIR/or-patterns-syntactic-fail.rs:29:9
    |
 LL |     let | A | B: E = A;
diff --git a/tests/ui/or-patterns/remove-leading-vert.fixed b/tests/ui/or-patterns/remove-leading-vert.fixed
index 136ca5765b7e2..2851b8f18c54a 100644
--- a/tests/ui/or-patterns/remove-leading-vert.fixed
+++ b/tests/ui/or-patterns/remove-leading-vert.fixed
@@ -8,7 +8,7 @@ fn main() {}
 
 #[cfg(false)]
 fn leading() {
-    fn fun1(  A: E) {} //~ ERROR top-level or-patterns are not allowed
+    fn fun1(  A: E) {} //~ ERROR function parameters require top-level or-patterns in parentheses
     fn fun2(  A: E) {} //~ ERROR unexpected `||` before function parameter
     let ( | A): E;
     let ( | A): (E); //~ ERROR unexpected token `||` in pattern
diff --git a/tests/ui/or-patterns/remove-leading-vert.rs b/tests/ui/or-patterns/remove-leading-vert.rs
index d9e9c9fe4d2f8..1e1dbfbc6e665 100644
--- a/tests/ui/or-patterns/remove-leading-vert.rs
+++ b/tests/ui/or-patterns/remove-leading-vert.rs
@@ -8,7 +8,7 @@ fn main() {}
 
 #[cfg(false)]
 fn leading() {
-    fn fun1( | A: E) {} //~ ERROR top-level or-patterns are not allowed
+    fn fun1( | A: E) {} //~ ERROR function parameters require top-level or-patterns in parentheses
     fn fun2( || A: E) {} //~ ERROR unexpected `||` before function parameter
     let ( | A): E;
     let ( || A): (E); //~ ERROR unexpected token `||` in pattern
diff --git a/tests/ui/or-patterns/remove-leading-vert.stderr b/tests/ui/or-patterns/remove-leading-vert.stderr
index b92fcb89a404e..0323c64f04231 100644
--- a/tests/ui/or-patterns/remove-leading-vert.stderr
+++ b/tests/ui/or-patterns/remove-leading-vert.stderr
@@ -1,4 +1,4 @@
-error: top-level or-patterns are not allowed in function parameters
+error: function parameters require top-level or-patterns in parentheses
   --> $DIR/remove-leading-vert.rs:11:14
    |
 LL |     fn fun1( | A: E) {}
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/parse.rs b/tests/ui/rfcs/rfc-0000-never_patterns/parse.rs
index 566bb07164640..e004e6612107a 100644
--- a/tests/ui/rfcs/rfc-0000-never_patterns/parse.rs
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/parse.rs
@@ -65,7 +65,7 @@ fn parse(x: Void) {
     let res: Result = Ok(false);
     let Ok(_) = res;
     let Ok(_) | Err(!) = &res; // Disallowed; see #82048.
-    //~^ ERROR top-level or-patterns are not allowed in `let` bindings
+    //~^ ERROR `let` bindings require top-level or-patterns in parentheses
     let (Ok(_) | Err(!)) = &res;
     let (Ok(_) | Err(&!)) = res.as_ref();
 
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/parse.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/parse.stderr
index 05980510f1cde..320e157f71724 100644
--- a/tests/ui/rfcs/rfc-0000-never_patterns/parse.stderr
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/parse.stderr
@@ -26,7 +26,7 @@ error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `<=`
 LL |         Some(!) <=
    |                 ^^ expected one of `,`, `=>`, `if`, `|`, or `}`
 
-error: top-level or-patterns are not allowed in `let` bindings
+error: `let` bindings require top-level or-patterns in parentheses
   --> $DIR/parse.rs:67:9
    |
 LL |     let Ok(_) | Err(!) = &res; // Disallowed; see #82048.

From 7c253ac504004d3749a35a167e702c084989b27b Mon Sep 17 00:00:00 2001
From: mu001999 
Date: Thu, 8 May 2025 18:18:18 +0800
Subject: [PATCH 2095/4206] Suggest stable candidates rather than unstable ones

---
 Cargo.lock                                    |  1 +
 compiler/rustc_resolve/Cargo.toml             |  1 +
 compiler/rustc_resolve/src/diagnostics.rs     | 74 +++++++++++++++++--
 .../rustc_resolve/src/late/diagnostics.rs     |  1 +
 .../sugg-stable-import-first-issue-140240.rs  |  3 +
 ...gg-stable-import-first-issue-140240.stderr | 20 +++++
 6 files changed, 94 insertions(+), 6 deletions(-)
 create mode 100644 tests/ui/did_you_mean/sugg-stable-import-first-issue-140240.rs
 create mode 100644 tests/ui/did_you_mean/sugg-stable-import-first-issue-140240.stderr

diff --git a/Cargo.lock b/Cargo.lock
index 83d7a6a9ab134..21b2e7831adca 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4330,6 +4330,7 @@ dependencies = [
  "rustc_arena",
  "rustc_ast",
  "rustc_ast_pretty",
+ "rustc_attr_data_structures",
  "rustc_attr_parsing",
  "rustc_data_structures",
  "rustc_errors",
diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml
index 0fcc3d8f6b3aa..a97e0eaa9c631 100644
--- a/compiler/rustc_resolve/Cargo.toml
+++ b/compiler/rustc_resolve/Cargo.toml
@@ -11,6 +11,7 @@ pulldown-cmark = { version = "0.11", features = ["html"], default-features = fal
 rustc_arena = { path = "../rustc_arena" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
+rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
 rustc_attr_parsing = { path = "../rustc_attr_parsing" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 74daad0839469..0b16983c2c794 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -5,6 +5,7 @@ use rustc_ast::{
     self as ast, CRATE_NODE_ID, Crate, ItemKind, MetaItemInner, MetaItemKind, ModKind, NodeId, Path,
 };
 use rustc_ast_pretty::pprust;
+use rustc_attr_data_structures::{self as attr, Stability};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::codes::*;
@@ -110,6 +111,7 @@ pub(crate) struct ImportSuggestion {
     pub via_import: bool,
     /// An extra note that should be issued if this item is suggested
     pub note: Option,
+    pub is_stable: bool,
 }
 
 /// Adjust the impl span so that just the `impl` keyword is taken by removing
@@ -1172,13 +1174,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             ThinVec::::new(),
             true,
             start_did.is_local() || !self.tcx.is_doc_hidden(start_did),
+            true,
         )];
         let mut worklist_via_import = vec![];
 
-        while let Some((in_module, path_segments, accessible, doc_visible)) = match worklist.pop() {
-            None => worklist_via_import.pop(),
-            Some(x) => Some(x),
-        } {
+        while let Some((in_module, path_segments, accessible, doc_visible, is_stable)) =
+            match worklist.pop() {
+                None => worklist_via_import.pop(),
+                Some(x) => Some(x),
+            }
+        {
             let in_module_is_extern = !in_module.def_id().is_local();
             in_module.for_each_child(self, |this, ident, ns, name_binding| {
                 // Avoid non-importable candidates.
@@ -1258,6 +1263,27 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         candidates.remove(idx);
                     }
 
+                    let is_stable = if is_stable
+                        && let Some(did) = did
+                        && this.is_stable(did, path.span)
+                    {
+                        true
+                    } else {
+                        false
+                    };
+
+                    // Rreplace unstable suggestions if we meet a new stable one,
+                    // and do nothing if any other situation. For example, if we
+                    // meet `std::ops::Range` after `std::range::legacy::Range`,
+                    // we will remove the latter and then insert the former.
+                    if is_stable
+                        && let Some(idx) = candidates
+                            .iter()
+                            .position(|v: &ImportSuggestion| v.did == did && !v.is_stable)
+                    {
+                        candidates.remove(idx);
+                    }
+
                     if candidates.iter().all(|v: &ImportSuggestion| v.did != did) {
                         // See if we're recommending TryFrom, TryInto, or FromIterator and add
                         // a note about editions
@@ -1289,6 +1315,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                             doc_visible: child_doc_visible,
                             note,
                             via_import,
+                            is_stable,
                         });
                     }
                 }
@@ -1315,8 +1342,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     if !is_extern_crate_that_also_appears_in_prelude || alias_import {
                         // add the module to the lookup
                         if seen_modules.insert(module.def_id()) {
-                            if via_import { &mut worklist_via_import } else { &mut worklist }
-                                .push((module, path_segments, child_accessible, child_doc_visible));
+                            if via_import { &mut worklist_via_import } else { &mut worklist }.push(
+                                (
+                                    module,
+                                    path_segments,
+                                    child_accessible,
+                                    child_doc_visible,
+                                    is_stable && this.is_stable(module.def_id(), name_binding.span),
+                                ),
+                            );
                         }
                     }
                 }
@@ -1326,6 +1360,34 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         candidates
     }
 
+    fn is_stable(&self, did: DefId, span: Span) -> bool {
+        if did.is_local() {
+            return true;
+        }
+
+        match self.tcx.lookup_stability(did) {
+            Some(Stability {
+                level: attr::StabilityLevel::Unstable { implied_by, .. },
+                feature,
+                ..
+            }) => {
+                if span.allows_unstable(feature) {
+                    true
+                } else if self.tcx.features().enabled(feature) {
+                    true
+                } else if let Some(implied_by) = implied_by
+                    && self.tcx.features().enabled(implied_by)
+                {
+                    true
+                } else {
+                    false
+                }
+            }
+            Some(_) => true,
+            None => false,
+        }
+    }
+
     /// When name resolution fails, this method can be used to look up candidate
     /// entities with the expected name. It allows filtering them using the
     /// supplied predicate (which should be used to only accept the types of
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index d4fe446cc9f76..b538be34f31f1 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -2501,6 +2501,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                                 doc_visible,
                                 note: None,
                                 via_import: false,
+                                is_stable: true,
                             },
                         ));
                     } else {
diff --git a/tests/ui/did_you_mean/sugg-stable-import-first-issue-140240.rs b/tests/ui/did_you_mean/sugg-stable-import-first-issue-140240.rs
new file mode 100644
index 0000000000000..aa7178271a792
--- /dev/null
+++ b/tests/ui/did_you_mean/sugg-stable-import-first-issue-140240.rs
@@ -0,0 +1,3 @@
+fn main() {
+    const _: Range = 0..1; //~ ERROR cannot find type `Range` in this scope
+}
diff --git a/tests/ui/did_you_mean/sugg-stable-import-first-issue-140240.stderr b/tests/ui/did_you_mean/sugg-stable-import-first-issue-140240.stderr
new file mode 100644
index 0000000000000..9e4314a0699d8
--- /dev/null
+++ b/tests/ui/did_you_mean/sugg-stable-import-first-issue-140240.stderr
@@ -0,0 +1,20 @@
+error[E0412]: cannot find type `Range` in this scope
+  --> $DIR/sugg-stable-import-first-issue-140240.rs:2:14
+   |
+LL |     const _: Range = 0..1;
+   |              ^^^^^ not found in this scope
+   |
+help: consider importing one of these structs
+   |
+LL + use std::collections::btree_map::Range;
+   |
+LL + use std::collections::btree_set::Range;
+   |
+LL + use std::ops::Range;
+   |
+LL + use std::range::Range;
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0412`.

From 1c53e272142b430e5566bbd069dbf82427c07b8c Mon Sep 17 00:00:00 2001
From: Florian Diebold 
Date: Fri, 9 May 2025 16:15:28 +0200
Subject: [PATCH 2096/4206] Make diagnostics experimental by default

---
 .../src/handlers/await_outside_of_async.rs      |  1 +
 .../ide-diagnostics/src/handlers/bad_rtn.rs     |  1 +
 .../src/handlers/break_outside_of_loop.rs       |  1 +
 .../src/handlers/elided_lifetimes_in_path.rs    |  2 --
 .../src/handlers/expected_function.rs           |  1 -
 .../src/handlers/generic_args_prohibited.rs     |  1 +
 .../src/handlers/inactive_code.rs               |  1 +
 .../src/handlers/incoherent_impl.rs             |  1 +
 .../src/handlers/incorrect_case.rs              |  1 +
 .../src/handlers/incorrect_generics_len.rs      |  1 -
 .../src/handlers/incorrect_generics_order.rs    |  1 +
 .../src/handlers/invalid_cast.rs                |  3 ++-
 .../src/handlers/invalid_derive_target.rs       |  1 +
 .../ide-diagnostics/src/handlers/macro_error.rs |  2 ++
 .../src/handlers/malformed_derive.rs            |  1 +
 .../src/handlers/mismatched_arg_count.rs        |  2 ++
 .../src/handlers/missing_fields.rs              |  1 +
 .../src/handlers/missing_lifetime.rs            |  1 -
 .../src/handlers/missing_match_arms.rs          |  1 +
 .../src/handlers/missing_unsafe.rs              |  1 +
 .../src/handlers/moved_out_of_ref.rs            |  2 +-
 .../src/handlers/mutability_errors.rs           |  3 ++-
 .../src/handlers/no_such_field.rs               |  2 ++
 .../src/handlers/non_exhaustive_let.rs          |  1 +
 ...renthesized_generic_args_without_fn_trait.rs |  1 +
 .../src/handlers/private_assoc_item.rs          |  1 +
 .../src/handlers/private_field.rs               |  1 +
 .../src/handlers/remove_trailing_return.rs      |  1 +
 .../src/handlers/remove_unnecessary_else.rs     |  1 -
 .../replace_filter_map_next_with_find_map.rs    |  1 +
 .../src/handlers/trait_impl_incorrect_safety.rs |  1 +
 .../handlers/trait_impl_missing_assoc_item.rs   |  1 +
 .../src/handlers/trait_impl_orphan.rs           |  2 --
 .../handlers/trait_impl_redundant_assoc_item.rs |  1 +
 .../src/handlers/type_mismatch.rs               |  4 ++--
 .../ide-diagnostics/src/handlers/typed_hole.rs  |  1 +
 .../src/handlers/undeclared_label.rs            |  1 +
 .../src/handlers/unimplemented_builtin_macro.rs |  1 +
 .../src/handlers/unreachable_label.rs           |  1 +
 .../src/handlers/unresolved_assoc_item.rs       |  1 -
 .../src/handlers/unresolved_extern_crate.rs     |  1 +
 .../src/handlers/unresolved_field.rs            |  1 -
 .../src/handlers/unresolved_ident.rs            |  1 -
 .../src/handlers/unresolved_import.rs           |  1 -
 .../src/handlers/unresolved_macro_call.rs       |  1 -
 .../src/handlers/unresolved_method.rs           |  1 -
 .../src/handlers/unresolved_module.rs           |  1 +
 .../src/handlers/unused_variables.rs            |  3 +--
 .../crates/ide-diagnostics/src/lib.rs           | 17 +++++------------
 49 files changed, 47 insertions(+), 33 deletions(-)

diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/await_outside_of_async.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/await_outside_of_async.rs
index 92ca7a74184fb..2a7b0098edfd9 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/await_outside_of_async.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/await_outside_of_async.rs
@@ -14,6 +14,7 @@ pub(crate) fn await_outside_of_async(
         format!("`await` is used inside {}, which is not an `async` context", d.location),
         display_range,
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/bad_rtn.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/bad_rtn.rs
index 9ed85f9f208e8..ae42a88c313ce 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/bad_rtn.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/bad_rtn.rs
@@ -12,6 +12,7 @@ pub(crate) fn bad_rtn(ctx: &DiagnosticsContext<'_>, d: &hir::BadRtn) -> Diagnost
         "return type notation not allowed in this position yet",
         d.rtn.map(Into::into),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
index c25b0a7bf7d5a..cbcaab6c74777 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
@@ -19,6 +19,7 @@ pub(crate) fn break_outside_of_loop(
         message,
         d.expr.map(|it| it.into()),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/elided_lifetimes_in_path.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/elided_lifetimes_in_path.rs
index 438dd2fdcb6c0..b284d9b351031 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/elided_lifetimes_in_path.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/elided_lifetimes_in_path.rs
@@ -15,7 +15,6 @@ pub(crate) fn elided_lifetimes_in_path(
             "implicit elided lifetime not allowed here",
             d.generics_or_segment.map(Into::into),
         )
-        .experimental()
     } else {
         Diagnostic::new_with_syntax_node_ptr(
             ctx,
@@ -23,7 +22,6 @@ pub(crate) fn elided_lifetimes_in_path(
             "hidden lifetime parameters in types are deprecated",
             d.generics_or_segment.map(Into::into),
         )
-        .experimental()
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs
index a6da0fd9c5e31..7d2ac373dc08d 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs
@@ -15,7 +15,6 @@ pub(crate) fn expected_function(
         format!("expected function, found {}", d.found.display(ctx.sema.db, ctx.display_target)),
         d.call.map(|it| it.into()),
     )
-    .experimental()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs
index b617c09498393..9ae6f013c70d5 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs
@@ -21,6 +21,7 @@ pub(crate) fn generic_args_prohibited(
         describe_reason(d.reason),
         d.args.map(Into::into),
     )
+    .stable()
     .with_fixes(fixes(ctx, d))
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
index 47e1c84fecd0a..8611ef653b02d 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
@@ -33,6 +33,7 @@ pub(crate) fn inactive_code(
         message,
         ctx.sema.diagnostics_display_range(d.node),
     )
+    .stable()
     .with_unused(true);
     Some(res)
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs
index 0b9a2ec9db3dd..a0c364b00108e 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs
@@ -19,6 +19,7 @@ pub(crate) fn incoherent_impl(ctx: &DiagnosticsContext<'_>, d: &hir::IncoherentI
         "cannot define inherent `impl` for foreign type".to_owned(),
         display_range,
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
index 289a076573252..38f10c778d69e 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
@@ -29,6 +29,7 @@ pub(crate) fn incorrect_case(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCas
         ),
         InFile::new(d.file, d.ident.into()),
     )
+    .stable()
     .with_fixes(fixes(ctx, d))
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs
index 17c7f75880c90..06f3575942004 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs
@@ -28,7 +28,6 @@ pub(crate) fn incorrect_generics_len(
         message,
         d.generics_or_segment.map(Into::into),
     )
-    .experimental()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_order.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_order.rs
index 84496df2d7cfb..b71586d6be0b6 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_order.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_order.rs
@@ -28,6 +28,7 @@ pub(crate) fn incorrect_generics_order(
         message,
         d.provided_arg.map(Into::into),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs
index d72b21099ce35..7a6e98fe1b540 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs
@@ -100,7 +100,7 @@ pub(crate) fn invalid_cast(ctx: &DiagnosticsContext<'_>, d: &hir::InvalidCast) -
         //     "cannot cast to a pointer of an unknown kind".to_owned(),
         // ),
     };
-    Diagnostic::new(code, message, display_range)
+    Diagnostic::new(code, message, display_range).stable()
 }
 
 // Diagnostic: cast-to-unsized
@@ -113,6 +113,7 @@ pub(crate) fn cast_to_unsized(ctx: &DiagnosticsContext<'_>, d: &hir::CastToUnsiz
         format_ty!(ctx, "cast to unsized type: `{}`", d.cast_ty),
         display_range,
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_derive_target.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_derive_target.rs
index ab0f5139f1078..8b708f229d009 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_derive_target.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_derive_target.rs
@@ -15,6 +15,7 @@ pub(crate) fn invalid_derive_target(
         "`derive` may only be applied to `struct`s, `enum`s and `union`s",
         display_range,
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
index a2648a1995d7f..546512a6cf926 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
@@ -19,6 +19,7 @@ pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) ->
         d.message.clone(),
         display_range,
     )
+    .stable()
 }
 
 // Diagnostic: macro-def-error
@@ -33,6 +34,7 @@ pub(crate) fn macro_def_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroDefErr
         d.message.clone(),
         display_range,
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/malformed_derive.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/malformed_derive.rs
index 0e47fff6f93bb..701b30b9b593d 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/malformed_derive.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/malformed_derive.rs
@@ -14,6 +14,7 @@ pub(crate) fn malformed_derive(
         "malformed derive input, derive attributes are of the form `#[derive(Derive1, Derive2, ...)]`",
         display_range,
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
index 63fd9b4e3f06b..25c1e633ba3b7 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
@@ -26,6 +26,7 @@ pub(crate) fn mismatched_tuple_struct_pat_arg_count(
         message,
         invalid_args_range(ctx, d.expr_or_pat, d.expected, d.found),
     )
+    .stable()
 }
 
 // Diagnostic: mismatched-arg-count
@@ -42,6 +43,7 @@ pub(crate) fn mismatched_arg_count(
         message,
         invalid_args_range(ctx, d.call_expr, d.expected, d.found),
     )
+    .stable()
 }
 
 fn invalid_args_range(
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
index a354d123f5ab3..2b76efb1965bd 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -47,6 +47,7 @@ pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingField
     );
 
     Diagnostic::new_with_syntax_node_ptr(ctx, DiagnosticCode::RustcHardError("E0063"), message, ptr)
+        .stable()
         .with_fixes(fixes(ctx, d))
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs
index 8cdbb6384ff5a..76b30745a04d1 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs
@@ -13,7 +13,6 @@ pub(crate) fn missing_lifetime(
         "missing lifetime specifier",
         d.generics_or_segment.map(Into::into),
     )
-    .experimental()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
index d3d3c3aa38dc2..1fc96b78eda27 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
@@ -13,6 +13,7 @@ pub(crate) fn missing_match_arms(
         format!("missing match arm: {}", d.uncovered_patterns),
         d.scrutinee_expr.map(Into::into),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
index 3c36b455ca9d9..ff041e183b140 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
@@ -23,6 +23,7 @@ pub(crate) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsaf
         format!("{operation} is unsafe and requires an unsafe function or block"),
         d.node.map(|it| it.into()),
     )
+    .stable()
     .with_fixes(fixes(ctx, d))
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
index 780271361d722..01cf5e8fa522c 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
@@ -11,7 +11,7 @@ pub(crate) fn moved_out_of_ref(ctx: &DiagnosticsContext<'_>, d: &hir::MovedOutOf
         format!("cannot move `{}` out of reference", d.ty.display(ctx.sema.db, ctx.display_target)),
         d.span,
     )
-    .experimental() // spans are broken, and I'm not sure how precise we can detect copy types
+    // spans are broken, and I'm not sure how precise we can detect copy types
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
index 5d25f2c6a90fd..8831efa311720 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
@@ -55,6 +55,7 @@ pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Option
             ),
             span,
         )
+        .stable()
         .with_fixes(fixes),
     )
 }
@@ -94,7 +95,7 @@ pub(crate) fn unused_mut(ctx: &DiagnosticsContext<'_>, d: &hir::UnusedMut) -> Op
             "variable does not need to be mutable",
             ast,
         )
-        .experimental() // Not supporting `#[allow(unused_mut)]` in proc macros leads to false positive.
+        // Not supporting `#[allow(unused_mut)]` in proc macros leads to false positive, hence not stable.
         .with_fixes(fixes),
     )
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
index fa3347aa12e62..84fb467a5ce11 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
@@ -22,6 +22,7 @@ pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField)
             "field is private",
             node,
         )
+        .stable()
     } else {
         Diagnostic::new_with_syntax_node_ptr(
             ctx,
@@ -32,6 +33,7 @@ pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField)
             "no such field",
             node,
         )
+        .stable()
         .with_fixes(fixes(ctx, d))
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
index ff1eeb0516a9e..35cefd2397529 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
@@ -14,6 +14,7 @@ pub(crate) fn non_exhaustive_let(
         format!("non-exhaustive pattern: {}", d.uncovered_patterns),
         d.pat.map(Into::into),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/parenthesized_generic_args_without_fn_trait.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/parenthesized_generic_args_without_fn_trait.rs
index ccf5172341836..68f2b1965702c 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/parenthesized_generic_args_without_fn_trait.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/parenthesized_generic_args_without_fn_trait.rs
@@ -14,6 +14,7 @@ pub(crate) fn parenthesized_generic_args_without_fn_trait(
         "parenthesized type parameters may only be used with a `Fn` trait",
         d.args.map(Into::into),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs
index fe32c590492d1..6d33ae0cf9bea 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs
@@ -28,6 +28,7 @@ pub(crate) fn private_assoc_item(
         ),
         d.expr_or_pat.map(Into::into),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs
index 237a9b87871c9..5b4273a5a627b 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs
@@ -15,6 +15,7 @@ pub(crate) fn private_field(ctx: &DiagnosticsContext<'_>, d: &hir::PrivateField)
         ),
         d.expr.map(|it| it.into()),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
index 6b78645002617..dec7be8b74275 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
@@ -31,6 +31,7 @@ pub(crate) fn remove_trailing_return(
             "replace return ; with ",
             display_range,
         )
+        .stable()
         .with_fixes(fixes(ctx, d)),
     )
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
index 8d717b9093b92..7dc5b5b45e5f4 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
@@ -36,7 +36,6 @@ pub(crate) fn remove_unnecessary_else(
             "remove unnecessary else block",
             display_range,
         )
-        .experimental()
         .with_fixes(fixes(ctx, d)),
     )
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
index 6b335c52de75c..37ce5f583f93a 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
@@ -21,6 +21,7 @@ pub(crate) fn replace_filter_map_next_with_find_map(
         "replace filter_map(..).next() with find_map(..)",
         InFile::new(d.file, d.next_expr.into()),
     )
+    .stable()
     .with_fixes(fixes(ctx, d))
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs
index 19ee1caa3e6a9..dd142db8590fb 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs
@@ -33,6 +33,7 @@ pub(crate) fn trait_impl_incorrect_safety(
             },
         ),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs
index 2d7d78f5d7bdf..fa7ba90a756b1 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs
@@ -29,6 +29,7 @@ pub(crate) fn trait_impl_missing_assoc_item(
             &|impl_| impl_.trait_().map(|t| t.syntax().text_range()),
         ),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs
index 35dc9b0fac8a3..96911d4781b8a 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs
@@ -16,8 +16,6 @@ pub(crate) fn trait_impl_orphan(
             .to_owned(),
         InFile::new(d.file_id, d.impl_.into()),
     )
-    // Not yet checked for false positives
-    .experimental()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
index d5c4bcf768adb..4327b12dce706 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
@@ -61,6 +61,7 @@ pub(crate) fn trait_impl_redundant_assoc_item(
         format!("{redundant_item_name} is not a member of trait `{trait_name}`"),
         ide_db::FileRange { file_id: file_id.file_id(ctx.sema.db), range },
     )
+    .stable()
     .with_fixes(quickfix_for_redundant_assoc_item(
         ctx,
         d,
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 500c5de791dc8..5253734867e88 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -53,8 +53,8 @@ pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch)
         display_range,
     )
     .with_fixes(fixes(ctx, d));
-    if diag.fixes.is_none() {
-        diag.experimental = true;
+    if diag.fixes.is_some() {
+        diag.experimental = false;
     }
     diag
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
index a933f1b426118..1915a88dd002d 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
@@ -37,6 +37,7 @@ pub(crate) fn typed_hole(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Di
     };
 
     Diagnostic::new(DiagnosticCode::RustcHardError("typed-hole"), message, display_range)
+        .stable()
         .with_fixes(fixes)
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs
index d16bfb8002403..f81d34377da49 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs
@@ -12,6 +12,7 @@ pub(crate) fn undeclared_label(
         format!("use of undeclared label `{}`", name.display(ctx.sema.db, ctx.edition)),
         d.node.map(|it| it.into()),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs
index 06f176f86f4e4..5627393f31818 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs
@@ -13,4 +13,5 @@ pub(crate) fn unimplemented_builtin_macro(
         "unimplemented built-in macro".to_owned(),
         d.node,
     )
+    .stable()
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs
index bdff2417ca114..0c9e0d6ce440c 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs
@@ -12,6 +12,7 @@ pub(crate) fn unreachable_label(
         format!("use of unreachable label `{}`", name.display(ctx.sema.db, ctx.edition)),
         d.node.map(|it| it.into()),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs
index 614057ab52bfd..4ae528bf9f284 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs
@@ -13,7 +13,6 @@ pub(crate) fn unresolved_assoc_item(
         "no such associated item",
         d.expr_or_pat.map(Into::into),
     )
-    .experimental()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs
index 4cd73d46d5f1f..7c3eacf7e3ad4 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs
@@ -13,6 +13,7 @@ pub(crate) fn unresolved_extern_crate(
         "unresolved extern crate",
         d.decl.map(|it| it.into()),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
index a4f4813cf5b07..0649c97f82059 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
@@ -52,7 +52,6 @@ pub(crate) fn unresolved_field(
         }),
     )
     .with_fixes(fixes(ctx, d))
-    .experimental()
 }
 
 fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option> {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs
index 4f64dabeb52fc..801023dabd96f 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs
@@ -13,7 +13,6 @@ pub(crate) fn unresolved_ident(
         range.range = in_node_range + range.range.start();
     }
     Diagnostic::new(DiagnosticCode::RustcHardError("E0425"), "no such value in this scope", range)
-        .experimental()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_import.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_import.rs
index 67c7e76a3bc11..0da535d11b4fe 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_import.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_import.rs
@@ -18,7 +18,6 @@ pub(crate) fn unresolved_import(
     // - `cfg_if!`-generated code in libstd (we don't load the sysroot correctly)
     // - `core::arch` (we don't handle `#[path = "../"]` correctly)
     // - proc macros and/or proc macro generated code
-    .experimental()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs
index 0d1c977506276..a87b8c42ac1d0 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs
@@ -16,7 +16,6 @@ pub(crate) fn unresolved_macro_call(
         format!("unresolved macro `{}{bang}`", d.path.display(ctx.sema.db, ctx.edition)),
         display_range,
     )
-    .experimental()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
index 7f07009dc5616..00c2a8c4c468c 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
@@ -47,7 +47,6 @@ pub(crate) fn unresolved_method(
         }),
     )
     .with_fixes(fixes(ctx, d))
-    .experimental()
 }
 
 fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) -> Option> {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs
index 599cabe3e4f20..1a409d7e76a2f 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs
@@ -28,6 +28,7 @@ pub(crate) fn unresolved_module(
         },
         d.decl.map(|it| it.into()),
     )
+    .stable()
     .with_fixes(fixes(ctx, d))
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
index 77b1075ea5325..e6bbff05f7e8c 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
@@ -50,8 +50,7 @@ pub(crate) fn unused_variables(
                 ast.file_id.is_macro(),
                 ctx.edition,
             )
-        }))
-        .experimental(),
+        })),
     )
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
index 607721d611d7d..2af14ca949bf2 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -182,7 +182,7 @@ impl Diagnostic {
                 DiagnosticCode::Ra(_, s) => s,
             },
             unused: false,
-            experimental: false,
+            experimental: true,
             fixes: None,
             main_node: None,
         }
@@ -198,8 +198,8 @@ impl Diagnostic {
             .with_main_node(node)
     }
 
-    fn experimental(mut self) -> Diagnostic {
-        self.experimental = true;
+    fn stable(mut self) -> Diagnostic {
+        self.experimental = false;
         self
     }
 
@@ -424,14 +424,11 @@ pub fn semantic_diagnostics(
             AnyDiagnostic::MacroExpansionParseError(d) => {
                 // FIXME: Point to the correct error span here, not just the macro-call name
                 res.extend(d.errors.iter().take(16).map(|err| {
-                    {
                         Diagnostic::new(
                             DiagnosticCode::SyntaxError,
                             format!("Syntax Error in Expansion: {err}"),
                             ctx.resolve_precise_location(&d.node.clone(), d.precise_location),
                         )
-                    }
-                    .experimental()
                 }));
                 continue;
             },
@@ -485,12 +482,8 @@ pub fn semantic_diagnostics(
                 Some(it) => it,
                 None => continue,
             },
-            AnyDiagnostic::GenericArgsProhibited(d) => {
-                handlers::generic_args_prohibited::generic_args_prohibited(&ctx, &d)
-            }
-            AnyDiagnostic::ParenthesizedGenericArgsWithoutFnTrait(d) => {
-                handlers::parenthesized_generic_args_without_fn_trait::parenthesized_generic_args_without_fn_trait(&ctx, &d)
-            }
+            AnyDiagnostic::GenericArgsProhibited(d) => handlers::generic_args_prohibited::generic_args_prohibited(&ctx, &d),
+            AnyDiagnostic::ParenthesizedGenericArgsWithoutFnTrait(d) => handlers::parenthesized_generic_args_without_fn_trait::parenthesized_generic_args_without_fn_trait(&ctx, &d),
             AnyDiagnostic::BadRtn(d) => handlers::bad_rtn::bad_rtn(&ctx, &d),
             AnyDiagnostic::IncorrectGenericsLen(d) => handlers::incorrect_generics_len::incorrect_generics_len(&ctx, &d),
             AnyDiagnostic::IncorrectGenericsOrder(d) => handlers::incorrect_generics_order::incorrect_generics_order(&ctx, &d),

From 339556eb026e6d1a0a18313f9c3cfe0ab87fe738 Mon Sep 17 00:00:00 2001
From: Zalathar 
Date: Sun, 4 May 2025 14:09:52 +1000
Subject: [PATCH 2097/4206] coverage: Enlarge empty spans during MIR
 instrumentation, not codegen

This allows us to assume that coverage spans will only be discarded during
codegen in very unusual situations.
---
 .../src/coverageinfo/mapgen/spans.rs          | 28 ++------------
 .../rustc_mir_transform/src/coverage/spans.rs | 38 ++++++++++++++++++-
 tests/coverage/async_closure.cov-map          | 21 +++++-----
 ...ch_match_arms.main.InstrumentCoverage.diff |  2 +-
 ...ument_coverage.bar.InstrumentCoverage.diff |  2 +-
 ...ment_coverage.main.InstrumentCoverage.diff |  4 +-
 ...rage_cleanup.main.CleanupPostBorrowck.diff |  4 +-
 ...erage_cleanup.main.InstrumentCoverage.diff |  4 +-
 8 files changed, 57 insertions(+), 46 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs
index 39a59560c9d3e..574463be7ffe0 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs
@@ -39,7 +39,10 @@ impl Coords {
 /// or other expansions), and if it does happen then skipping a span or function is
 /// better than an ICE or `llvm-cov` failure that the user might have no way to avoid.
 pub(crate) fn make_coords(source_map: &SourceMap, file: &SourceFile, span: Span) -> Option {
-    let span = ensure_non_empty_span(source_map, span)?;
+    if span.is_empty() {
+        debug_assert!(false, "can't make coords from empty span: {span:?}");
+        return None;
+    }
 
     let lo = span.lo();
     let hi = span.hi();
@@ -70,29 +73,6 @@ pub(crate) fn make_coords(source_map: &SourceMap, file: &SourceFile, span: Span)
     })
 }
 
-fn ensure_non_empty_span(source_map: &SourceMap, span: Span) -> Option {
-    if !span.is_empty() {
-        return Some(span);
-    }
-
-    // The span is empty, so try to enlarge it to cover an adjacent '{' or '}'.
-    source_map
-        .span_to_source(span, |src, start, end| try {
-            // Adjusting span endpoints by `BytePos(1)` is normally a bug,
-            // but in this case we have specifically checked that the character
-            // we're skipping over is one of two specific ASCII characters, so
-            // adjusting by exactly 1 byte is correct.
-            if src.as_bytes().get(end).copied() == Some(b'{') {
-                Some(span.with_hi(span.hi() + BytePos(1)))
-            } else if start > 0 && src.as_bytes()[start - 1] == b'}' {
-                Some(span.with_lo(span.lo() - BytePos(1)))
-            } else {
-                None
-            }
-        })
-        .ok()?
-}
-
 /// If `llvm-cov` sees a source region that is improperly ordered (end < start),
 /// it will immediately exit with a fatal error. To prevent that from happening,
 /// discard regions that are improperly ordered, or might be interpreted in a
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index ec76076020eb7..ddeae093df5b7 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -1,7 +1,8 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::mir;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::{DesugaringKind, ExpnKind, MacroKind, Span};
+use rustc_span::source_map::SourceMap;
+use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span};
 use tracing::instrument;
 
 use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
@@ -83,8 +84,18 @@ pub(super) fn extract_refined_covspans<'tcx>(
     // Discard any span that overlaps with a hole.
     discard_spans_overlapping_holes(&mut covspans, &holes);
 
-    // Perform more refinement steps after holes have been dealt with.
+    // Discard spans that overlap in unwanted ways.
     let mut covspans = remove_unwanted_overlapping_spans(covspans);
+
+    // For all empty spans, either enlarge them to be non-empty, or discard them.
+    let source_map = tcx.sess.source_map();
+    covspans.retain_mut(|covspan| {
+        let Some(span) = ensure_non_empty_span(source_map, covspan.span) else { return false };
+        covspan.span = span;
+        true
+    });
+
+    // Merge covspans that can be merged.
     covspans.dedup_by(|b, a| a.merge_if_eligible(b));
 
     code_mappings.extend(covspans.into_iter().map(|Covspan { span, bcb }| {
@@ -230,3 +241,26 @@ fn compare_spans(a: Span, b: Span) -> std::cmp::Ordering {
         // - Both have the same start and span A extends further right
         .then_with(|| Ord::cmp(&a.hi(), &b.hi()).reverse())
 }
+
+fn ensure_non_empty_span(source_map: &SourceMap, span: Span) -> Option {
+    if !span.is_empty() {
+        return Some(span);
+    }
+
+    // The span is empty, so try to enlarge it to cover an adjacent '{' or '}'.
+    source_map
+        .span_to_source(span, |src, start, end| try {
+            // Adjusting span endpoints by `BytePos(1)` is normally a bug,
+            // but in this case we have specifically checked that the character
+            // we're skipping over is one of two specific ASCII characters, so
+            // adjusting by exactly 1 byte is correct.
+            if src.as_bytes().get(end).copied() == Some(b'{') {
+                Some(span.with_hi(span.hi() + BytePos(1)))
+            } else if start > 0 && src.as_bytes()[start - 1] == b'}' {
+                Some(span.with_lo(span.lo() - BytePos(1)))
+            } else {
+                None
+            }
+        })
+        .ok()?
+}
diff --git a/tests/coverage/async_closure.cov-map b/tests/coverage/async_closure.cov-map
index 9f8dc8d6cbbae..53128dd7a48b0 100644
--- a/tests/coverage/async_closure.cov-map
+++ b/tests/coverage/async_closure.cov-map
@@ -37,32 +37,29 @@ Number of file 0 mappings: 8
 Highest counter ID seen: c0
 
 Function name: async_closure::main::{closure#0}
-Raw bytes (14): 0x[01, 01, 00, 02, 01, 0b, 22, 00, 23, 01, 00, 23, 00, 24]
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 22, 00, 24]
 Number of files: 1
 - file 0 => $DIR/async_closure.rs
 Number of expressions: 0
-Number of file 0 mappings: 2
-- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 35)
-- Code(Counter(0)) at (prev + 0, 35) to (start + 0, 36)
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 36)
 Highest counter ID seen: c0
 
 Function name: async_closure::main::{closure#0}
-Raw bytes (14): 0x[01, 01, 00, 02, 01, 0b, 22, 00, 23, 01, 00, 23, 00, 24]
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 22, 00, 24]
 Number of files: 1
 - file 0 => $DIR/async_closure.rs
 Number of expressions: 0
-Number of file 0 mappings: 2
-- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 35)
-- Code(Counter(0)) at (prev + 0, 35) to (start + 0, 36)
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 36)
 Highest counter ID seen: c0
 
 Function name: async_closure::main::{closure#0}::{closure#0}::
-Raw bytes (14): 0x[01, 01, 00, 02, 01, 0b, 22, 00, 23, 01, 00, 23, 00, 24]
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 22, 00, 24]
 Number of files: 1
 - file 0 => $DIR/async_closure.rs
 Number of expressions: 0
-Number of file 0 mappings: 2
-- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 35)
-- Code(Counter(0)) at (prev + 0, 35) to (start + 0, 36)
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 36)
 Highest counter ID seen: c0
 
diff --git a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff
index d465b8bded22f..fa88211383a04 100644
--- a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff
+++ b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff
@@ -40,7 +40,7 @@
 +     coverage Code { bcb: bcb5 } => $DIR/branch_match_arms.rs:19:17: 19:18 (#0);
 +     coverage Code { bcb: bcb5 } => $DIR/branch_match_arms.rs:19:23: 19:30 (#0);
 +     coverage Code { bcb: bcb5 } => $DIR/branch_match_arms.rs:19:31: 19:32 (#0);
-+     coverage Code { bcb: bcb2 } => $DIR/branch_match_arms.rs:21:2: 21:2 (#0);
++     coverage Code { bcb: bcb2 } => $DIR/branch_match_arms.rs:21:1: 21:2 (#0);
 + 
       bb0: {
 +         Coverage::VirtualCounter(bcb0);
diff --git a/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff
index cf6d85abd80ef..9b6d2b22087b6 100644
--- a/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff
+++ b/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff
@@ -6,7 +6,7 @@
   
 +     coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:27:1: 27:17 (#0);
 +     coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:28:5: 28:9 (#0);
-+     coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:29:2: 29:2 (#0);
++     coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:29:1: 29:2 (#0);
 + 
       bb0: {
 +         Coverage::VirtualCounter(bcb0);
diff --git a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff
index 980c5e202ffd8..b2bb2375aee60 100644
--- a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff
+++ b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff
@@ -10,8 +10,8 @@
 +     coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:13:1: 13:10 (#0);
 +     coverage Code { bcb: bcb1 } => $DIR/instrument_coverage.rs:15:12: 15:15 (#0);
 +     coverage Code { bcb: bcb2 } => $DIR/instrument_coverage.rs:16:13: 16:18 (#0);
-+     coverage Code { bcb: bcb3 } => $DIR/instrument_coverage.rs:17:10: 17:10 (#0);
-+     coverage Code { bcb: bcb2 } => $DIR/instrument_coverage.rs:19:2: 19:2 (#0);
++     coverage Code { bcb: bcb3 } => $DIR/instrument_coverage.rs:17:9: 17:10 (#0);
++     coverage Code { bcb: bcb2 } => $DIR/instrument_coverage.rs:19:1: 19:2 (#0);
 + 
       bb0: {
 +         Coverage::VirtualCounter(bcb0);
diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff
index b707cd41788ac..2eb78c08ee800 100644
--- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff
+++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff
@@ -10,8 +10,8 @@
       coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:13:1: 13:10 (#0);
       coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0);
       coverage Code { bcb: bcb3 } => $DIR/instrument_coverage_cleanup.rs:14:37: 14:39 (#0);
-      coverage Code { bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:39: 14:39 (#0);
-      coverage Code { bcb: bcb2 } => $DIR/instrument_coverage_cleanup.rs:15:2: 15:2 (#0);
+      coverage Code { bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:38: 14:39 (#0);
+      coverage Code { bcb: bcb2 } => $DIR/instrument_coverage_cleanup.rs:15:1: 15:2 (#0);
       coverage Branch { true_bcb: bcb3, false_bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0);
   
       bb0: {
diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff
index 239b845c2311e..0c1bc24b6dc19 100644
--- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff
+++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff
@@ -10,8 +10,8 @@
 +     coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:13:1: 13:10 (#0);
 +     coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0);
 +     coverage Code { bcb: bcb3 } => $DIR/instrument_coverage_cleanup.rs:14:37: 14:39 (#0);
-+     coverage Code { bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:39: 14:39 (#0);
-+     coverage Code { bcb: bcb2 } => $DIR/instrument_coverage_cleanup.rs:15:2: 15:2 (#0);
++     coverage Code { bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:38: 14:39 (#0);
++     coverage Code { bcb: bcb2 } => $DIR/instrument_coverage_cleanup.rs:15:1: 15:2 (#0);
 +     coverage Branch { true_bcb: bcb3, false_bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0);
 + 
       bb0: {

From 8cd8b23b9e4b1f05373831644b005b21a13a9c69 Mon Sep 17 00:00:00 2001
From: Zalathar 
Date: Fri, 9 May 2025 21:27:27 +1000
Subject: [PATCH 2098/4206] coverage: Hoist `counter_for_bcb` out of its loop

Having this helper function in the loop was confusing, because it doesn't rely
on anything that changes between loop iterations.
---
 .../src/coverageinfo/mapgen/covfun.rs         | 20 +++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
index 7bdbc68595290..6c2ea71799adf 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
@@ -104,6 +104,16 @@ fn fill_region_tables<'tcx>(
     ids_info: &'tcx CoverageIdsInfo,
     covfun: &mut CovfunRecord<'tcx>,
 ) {
+    // If this function is unused, replace all counters with zero.
+    let counter_for_bcb = |bcb: BasicCoverageBlock| -> ffi::Counter {
+        let term = if covfun.is_used {
+            ids_info.term_for_bcb[bcb].expect("every BCB in a mapping was given a term")
+        } else {
+            CovTerm::Zero
+        };
+        ffi::Counter::from_term(term)
+    };
+
     // Currently a function's mappings must all be in the same file, so use the
     // first mapping's span to determine the file.
     let source_map = tcx.sess.source_map();
@@ -135,16 +145,6 @@ fn fill_region_tables<'tcx>(
     // For each counter/region pair in this function+file, convert it to a
     // form suitable for FFI.
     for &Mapping { ref kind, span } in &fn_cov_info.mappings {
-        // If this function is unused, replace all counters with zero.
-        let counter_for_bcb = |bcb: BasicCoverageBlock| -> ffi::Counter {
-            let term = if covfun.is_used {
-                ids_info.term_for_bcb[bcb].expect("every BCB in a mapping was given a term")
-            } else {
-                CovTerm::Zero
-            };
-            ffi::Counter::from_term(term)
-        };
-
         let Some(coords) = make_coords(span) else { continue };
         let cov_span = coords.make_coverage_span(local_file_id);
 

From 078144fdfa7ae627d43cd919d660a71bef1e4658 Mon Sep 17 00:00:00 2001
From: Zalathar 
Date: Fri, 9 May 2025 20:57:17 +1000
Subject: [PATCH 2099/4206] coverage: Detect unused local file IDs to avoid an
 LLVM assertion

This case can't actually happen yet (other than via a testing flag), because
currently all of a function's spans must belong to the same file and expansion.
But this will be an important edge case when adding expansion region support.
---
 .../src/coverageinfo/ffi.rs                   | 26 +++++++++++++++----
 .../src/coverageinfo/mapgen/covfun.rs         | 24 +++++++++++++++++
 compiler/rustc_interface/src/tests.rs         |  3 ++-
 compiler/rustc_session/src/config.rs          |  5 ++++
 compiler/rustc_session/src/options.rs         |  1 +
 compiler/rustc_session/src/session.rs         |  5 ++++
 tests/coverage/unused-local-file.coverage     |  7 +++++
 tests/coverage/unused-local-file.rs           | 22 ++++++++++++++++
 8 files changed, 87 insertions(+), 6 deletions(-)
 create mode 100644 tests/coverage/unused-local-file.coverage
 create mode 100644 tests/coverage/unused-local-file.rs

diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
index f6000e7284002..c207df2fb0b45 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
@@ -155,6 +155,20 @@ pub(crate) struct Regions {
 impl Regions {
     /// Returns true if none of this structure's tables contain any regions.
     pub(crate) fn has_no_regions(&self) -> bool {
+        // Every region has a span, so if there are no spans then there are no regions.
+        self.all_cov_spans().next().is_none()
+    }
+
+    pub(crate) fn all_cov_spans(&self) -> impl Iterator {
+        macro_rules! iter_cov_spans {
+            ( $( $regions:expr ),* $(,)? ) => {
+                std::iter::empty()
+                $(
+                    .chain( $regions.iter().map(|region| ®ion.cov_span) )
+                )*
+            }
+        }
+
         let Self {
             code_regions,
             expansion_regions,
@@ -163,11 +177,13 @@ impl Regions {
             mcdc_decision_regions,
         } = self;
 
-        code_regions.is_empty()
-            && expansion_regions.is_empty()
-            && branch_regions.is_empty()
-            && mcdc_branch_regions.is_empty()
-            && mcdc_decision_regions.is_empty()
+        iter_cov_spans!(
+            code_regions,
+            expansion_regions,
+            branch_regions,
+            mcdc_branch_regions,
+            mcdc_decision_regions,
+        )
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
index 6c2ea71799adf..d3a815fabe7a9 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
@@ -11,6 +11,7 @@ use rustc_abi::Align;
 use rustc_codegen_ssa::traits::{
     BaseTypeCodegenMethods as _, ConstCodegenMethods, StaticCodegenMethods,
 };
+use rustc_index::IndexVec;
 use rustc_middle::mir::coverage::{
     BasicCoverageBlock, CovTerm, CoverageIdsInfo, Expression, FunctionCoverageInfo, Mapping,
     MappingKind, Op,
@@ -125,6 +126,12 @@ fn fill_region_tables<'tcx>(
 
     let local_file_id = covfun.virtual_file_mapping.push_file(&source_file);
 
+    // If this testing flag is set, add an extra unused entry to the local
+    // file table, to help test the code for detecting unused file IDs.
+    if tcx.sess.coverage_inject_unused_local_file() {
+        covfun.virtual_file_mapping.push_file(&source_file);
+    }
+
     // In rare cases, _all_ of a function's spans are discarded, and coverage
     // codegen needs to handle that gracefully to avoid #133606.
     // It's hard for tests to trigger this organically, so instead we set
@@ -177,6 +184,19 @@ fn fill_region_tables<'tcx>(
     }
 }
 
+/// LLVM requires all local file IDs to have at least one mapping region.
+/// If that's not the case, skip this function, to avoid an assertion failure
+/// (or worse) in LLVM.
+fn check_local_file_table(covfun: &CovfunRecord<'_>) -> bool {
+    let mut local_file_id_seen =
+        IndexVec::::from_elem_n(false, covfun.virtual_file_mapping.local_file_table.len());
+    for cov_span in covfun.regions.all_cov_spans() {
+        local_file_id_seen[cov_span.file_id] = true;
+    }
+
+    local_file_id_seen.into_iter().all(|seen| seen)
+}
+
 /// Generates the contents of the covfun record for this function, which
 /// contains the function's coverage mapping data. The record is then stored
 /// as a global variable in the `__llvm_covfun` section.
@@ -185,6 +205,10 @@ pub(crate) fn generate_covfun_record<'tcx>(
     global_file_table: &GlobalFileTable,
     covfun: &CovfunRecord<'tcx>,
 ) {
+    if !check_local_file_table(covfun) {
+        return;
+    }
+
     let &CovfunRecord {
         mangled_function_name,
         source_hash,
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 0ceda2201344e..8bcd04536243c 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -776,7 +776,8 @@ fn test_unstable_options_tracking_hash() {
         CoverageOptions {
             level: CoverageLevel::Mcdc,
             no_mir_spans: true,
-            discard_all_spans_in_codegen: true
+            discard_all_spans_in_codegen: true,
+            inject_unused_local_file: true,
         }
     );
     tracked!(crate_attr, vec!["abc".to_string()]);
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 60e1b465ba96d..144aeb5c369cc 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -195,6 +195,11 @@ pub struct CoverageOptions {
     /// regression tests for #133606, because we don't have an easy way to
     /// reproduce it from actual source code.
     pub discard_all_spans_in_codegen: bool,
+
+    /// `-Zcoverage-options=inject-unused-local-file`: During codegen, add an
+    /// extra dummy entry to each function's local file table, to exercise the
+    /// code that checks for local file IDs with no mapping regions.
+    pub inject_unused_local_file: bool,
 }
 
 /// Controls whether branch coverage or MC/DC coverage is enabled.
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index b95ebfbe89f24..1f783c59c7926 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1413,6 +1413,7 @@ pub mod parse {
                 "mcdc" => slot.level = CoverageLevel::Mcdc,
                 "no-mir-spans" => slot.no_mir_spans = true,
                 "discard-all-spans-in-codegen" => slot.discard_all_spans_in_codegen = true,
+                "inject-unused-local-file" => slot.inject_unused_local_file = true,
                 _ => return false,
             }
         }
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 010ae42c2802d..34ac37d63787d 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -371,6 +371,11 @@ impl Session {
         self.opts.unstable_opts.coverage_options.discard_all_spans_in_codegen
     }
 
+    /// True if testing flag `-Zcoverage-options=inject-unused-local-file` was passed.
+    pub fn coverage_inject_unused_local_file(&self) -> bool {
+        self.opts.unstable_opts.coverage_options.inject_unused_local_file
+    }
+
     pub fn is_sanitizer_cfi_enabled(&self) -> bool {
         self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI)
     }
diff --git a/tests/coverage/unused-local-file.coverage b/tests/coverage/unused-local-file.coverage
new file mode 100644
index 0000000000000..8f5a32f6d7080
--- /dev/null
+++ b/tests/coverage/unused-local-file.coverage
@@ -0,0 +1,7 @@
+   LL|       |//@ edition: 2021
+   LL|       |
+   LL|       |// Force this function to be generated in its home crate, so that it ends up
+   LL|       |// with normal coverage metadata.
+   LL|       |#[inline(never)]
+   LL|      1|pub fn external_function() {}
+
diff --git a/tests/coverage/unused-local-file.rs b/tests/coverage/unused-local-file.rs
new file mode 100644
index 0000000000000..cf43c62d70305
--- /dev/null
+++ b/tests/coverage/unused-local-file.rs
@@ -0,0 +1,22 @@
+//! If we give LLVM a local file table for a function, but some of the entries
+//! in that table have no associated mapping regions, then an assertion failure
+//! will occur in LLVM. We therefore need to detect and skip any function that
+//! would trigger that assertion.
+//!
+//! To test that this case is handled, even before adding code that could allow
+//! it to happen organically (for expansion region support), we use a special
+//! testing-only flag to force it to occur.
+
+//@ edition: 2024
+//@ compile-flags: -Zcoverage-options=inject-unused-local-file
+
+// The `llvm-cov` tool will complain if the test binary ends up having no
+// coverage metadata at all. To prevent that, we also link to instrumented
+// code in an auxiliary crate that doesn't have the special flag set.
+
+//@ aux-build: discard_all_helper.rs
+extern crate discard_all_helper;
+
+fn main() {
+    discard_all_helper::external_function();
+}

From a4707a4f3b38bd6aae7a452300ef5c65da19e524 Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Thu, 8 May 2025 19:43:33 +0000
Subject: [PATCH 2100/4206] Do not ICE when reassigning in GatherLocalsVisitor
 on the bad path

---
 .../rustc_hir_typeck/src/gather_locals.rs     | 14 +++++++++++--
 tests/ui/typeck/gather-locals-twice.rs        |  7 +++++++
 tests/ui/typeck/gather-locals-twice.stderr    | 20 +++++++++++++++++++
 3 files changed, 39 insertions(+), 2 deletions(-)
 create mode 100644 tests/ui/typeck/gather-locals-twice.rs
 create mode 100644 tests/ui/typeck/gather-locals-twice.stderr

diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs
index a8bbc89dbded5..956671fc66ed2 100644
--- a/compiler/rustc_hir_typeck/src/gather_locals.rs
+++ b/compiler/rustc_hir_typeck/src/gather_locals.rs
@@ -105,16 +105,26 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
     }
 
     fn assign(&mut self, span: Span, nid: HirId, ty_opt: Option>) -> Ty<'tcx> {
+        // We evaluate expressions twice occasionally in diagnostics for better
+        // type information or because it needs type information out-of-order.
+        // In order to not ICE and not lead to knock-on ambiguity errors, if we
+        // try to re-assign a type to a local, then just take out the previous
+        // type and delay a bug.
+        if let Some(&local) = self.fcx.locals.borrow_mut().get(&nid) {
+            self.fcx.dcx().span_delayed_bug(span, "evaluated expression more than once");
+            return local;
+        }
+
         match ty_opt {
             None => {
                 // Infer the variable's type.
                 let var_ty = self.fcx.next_ty_var(span);
-                assert_eq!(self.fcx.locals.borrow_mut().insert(nid, var_ty), None);
+                self.fcx.locals.borrow_mut().insert(nid, var_ty);
                 var_ty
             }
             Some(typ) => {
                 // Take type that the user specified.
-                assert_eq!(self.fcx.locals.borrow_mut().insert(nid, typ), None);
+                self.fcx.locals.borrow_mut().insert(nid, typ);
                 typ
             }
         }
diff --git a/tests/ui/typeck/gather-locals-twice.rs b/tests/ui/typeck/gather-locals-twice.rs
new file mode 100644
index 0000000000000..e9351146f4564
--- /dev/null
+++ b/tests/ui/typeck/gather-locals-twice.rs
@@ -0,0 +1,7 @@
+// Regression test for .
+
+fn main() {
+    () += { let x; };
+    //~^ ERROR binary assignment operation `+=` cannot be applied to type `()`
+    //~| ERROR invalid left-hand side of assignment
+}
diff --git a/tests/ui/typeck/gather-locals-twice.stderr b/tests/ui/typeck/gather-locals-twice.stderr
new file mode 100644
index 0000000000000..7598ef8e7ea4c
--- /dev/null
+++ b/tests/ui/typeck/gather-locals-twice.stderr
@@ -0,0 +1,20 @@
+error[E0368]: binary assignment operation `+=` cannot be applied to type `()`
+  --> $DIR/gather-locals-twice.rs:4:5
+   |
+LL |     () += { let x; };
+   |     --^^^^^^^^^^^^^^
+   |     |
+   |     cannot use `+=` on type `()`
+
+error[E0067]: invalid left-hand side of assignment
+  --> $DIR/gather-locals-twice.rs:4:8
+   |
+LL |     () += { let x; };
+   |     -- ^^
+   |     |
+   |     cannot assign to this expression
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0067, E0368.
+For more information about an error, try `rustc --explain E0067`.

From 0533ff7d4169692e05d11d219c287a477a5471bb Mon Sep 17 00:00:00 2001
From: lcnr 
Date: Fri, 9 May 2025 15:05:11 +0000
Subject: [PATCH 2101/4206] more moved tests

---
 .../{ => coherence}/auxiliary/coherence_cross_crate_trait_decl.rs | 0
 .../{ => coherence}/auxiliary/foreign-crate.rs                    | 0
 .../{ => coherence}/coherence.classic.stderr                      | 0
 .../type-alias-impl-trait/{ => coherence}/coherence.next.stderr   | 0
 tests/ui/type-alias-impl-trait/{ => coherence}/coherence.rs       | 0
 .../{ => coherence}/coherence_cross_crate.rs                      | 0
 .../{ => coherence}/coherence_cross_crate.stderr                  | 0
 .../{ => coherence}/coherence_different_hidden_ty.rs              | 0
 .../{ => coherence}/coherence_different_hidden_ty.stderr          | 0
 .../{ => coherence}/coherence_generalization.rs                   | 0
 10 files changed, 0 insertions(+), 0 deletions(-)
 rename tests/ui/type-alias-impl-trait/{ => coherence}/auxiliary/coherence_cross_crate_trait_decl.rs (100%)
 rename tests/ui/type-alias-impl-trait/{ => coherence}/auxiliary/foreign-crate.rs (100%)
 rename tests/ui/type-alias-impl-trait/{ => coherence}/coherence.classic.stderr (100%)
 rename tests/ui/type-alias-impl-trait/{ => coherence}/coherence.next.stderr (100%)
 rename tests/ui/type-alias-impl-trait/{ => coherence}/coherence.rs (100%)
 rename tests/ui/type-alias-impl-trait/{ => coherence}/coherence_cross_crate.rs (100%)
 rename tests/ui/type-alias-impl-trait/{ => coherence}/coherence_cross_crate.stderr (100%)
 rename tests/ui/type-alias-impl-trait/{ => coherence}/coherence_different_hidden_ty.rs (100%)
 rename tests/ui/type-alias-impl-trait/{ => coherence}/coherence_different_hidden_ty.stderr (100%)
 rename tests/ui/type-alias-impl-trait/{ => coherence}/coherence_generalization.rs (100%)

diff --git a/tests/ui/type-alias-impl-trait/auxiliary/coherence_cross_crate_trait_decl.rs b/tests/ui/type-alias-impl-trait/coherence/auxiliary/coherence_cross_crate_trait_decl.rs
similarity index 100%
rename from tests/ui/type-alias-impl-trait/auxiliary/coherence_cross_crate_trait_decl.rs
rename to tests/ui/type-alias-impl-trait/coherence/auxiliary/coherence_cross_crate_trait_decl.rs
diff --git a/tests/ui/type-alias-impl-trait/auxiliary/foreign-crate.rs b/tests/ui/type-alias-impl-trait/coherence/auxiliary/foreign-crate.rs
similarity index 100%
rename from tests/ui/type-alias-impl-trait/auxiliary/foreign-crate.rs
rename to tests/ui/type-alias-impl-trait/coherence/auxiliary/foreign-crate.rs
diff --git a/tests/ui/type-alias-impl-trait/coherence.classic.stderr b/tests/ui/type-alias-impl-trait/coherence/coherence.classic.stderr
similarity index 100%
rename from tests/ui/type-alias-impl-trait/coherence.classic.stderr
rename to tests/ui/type-alias-impl-trait/coherence/coherence.classic.stderr
diff --git a/tests/ui/type-alias-impl-trait/coherence.next.stderr b/tests/ui/type-alias-impl-trait/coherence/coherence.next.stderr
similarity index 100%
rename from tests/ui/type-alias-impl-trait/coherence.next.stderr
rename to tests/ui/type-alias-impl-trait/coherence/coherence.next.stderr
diff --git a/tests/ui/type-alias-impl-trait/coherence.rs b/tests/ui/type-alias-impl-trait/coherence/coherence.rs
similarity index 100%
rename from tests/ui/type-alias-impl-trait/coherence.rs
rename to tests/ui/type-alias-impl-trait/coherence/coherence.rs
diff --git a/tests/ui/type-alias-impl-trait/coherence_cross_crate.rs b/tests/ui/type-alias-impl-trait/coherence/coherence_cross_crate.rs
similarity index 100%
rename from tests/ui/type-alias-impl-trait/coherence_cross_crate.rs
rename to tests/ui/type-alias-impl-trait/coherence/coherence_cross_crate.rs
diff --git a/tests/ui/type-alias-impl-trait/coherence_cross_crate.stderr b/tests/ui/type-alias-impl-trait/coherence/coherence_cross_crate.stderr
similarity index 100%
rename from tests/ui/type-alias-impl-trait/coherence_cross_crate.stderr
rename to tests/ui/type-alias-impl-trait/coherence/coherence_cross_crate.stderr
diff --git a/tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.rs b/tests/ui/type-alias-impl-trait/coherence/coherence_different_hidden_ty.rs
similarity index 100%
rename from tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.rs
rename to tests/ui/type-alias-impl-trait/coherence/coherence_different_hidden_ty.rs
diff --git a/tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.stderr b/tests/ui/type-alias-impl-trait/coherence/coherence_different_hidden_ty.stderr
similarity index 100%
rename from tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.stderr
rename to tests/ui/type-alias-impl-trait/coherence/coherence_different_hidden_ty.stderr
diff --git a/tests/ui/type-alias-impl-trait/coherence_generalization.rs b/tests/ui/type-alias-impl-trait/coherence/coherence_generalization.rs
similarity index 100%
rename from tests/ui/type-alias-impl-trait/coherence_generalization.rs
rename to tests/ui/type-alias-impl-trait/coherence/coherence_generalization.rs

From e7247df590831b6429b3e8aa520d04b8458ac531 Mon Sep 17 00:00:00 2001
From: Urgau 
Date: Thu, 8 May 2025 12:43:10 +0200
Subject: [PATCH 2102/4206] Use intrinsics for
 `{f16,f32,f64,f128}::{minimum,maximum}` operations

---
 .../src/intrinsics/mod.rs                     |  37 +++++++
 .../rustc_codegen_gcc/src/intrinsic/mod.rs    |  36 ++++++
 compiler/rustc_codegen_llvm/src/context.rs    |  10 ++
 compiler/rustc_codegen_llvm/src/intrinsic.rs  |  10 ++
 .../src/interpret/intrinsics.rs               |  42 +++++++
 .../rustc_hir_analysis/src/check/intrinsic.rs |  18 +++
 compiler/rustc_span/src/symbol.rs             |   8 ++
 library/core/src/intrinsics/mod.rs            | 104 ++++++++++++++++--
 library/core/src/num/f128.rs                  |  50 ++++++---
 library/core/src/num/f16.rs                   |  50 ++++++---
 library/core/src/num/f32.rs                   |  50 ++++++---
 library/core/src/num/f64.rs                   |  50 ++++++---
 12 files changed, 389 insertions(+), 76 deletions(-)

diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index e866b8962551a..9018d78b00aeb 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -1109,6 +1109,43 @@ fn codegen_regular_intrinsic_call<'tcx>(
             ret.write_cvalue(fx, old);
         }
 
+        sym::minimumf32 => {
+            intrinsic_args!(fx, args => (a, b); intrinsic);
+            let a = a.load_scalar(fx);
+            let b = b.load_scalar(fx);
+
+            let val = fx.bcx.ins().fmin(a, b);
+            let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32));
+            ret.write_cvalue(fx, val);
+        }
+        sym::minimumf64 => {
+            intrinsic_args!(fx, args => (a, b); intrinsic);
+            let a = a.load_scalar(fx);
+            let b = b.load_scalar(fx);
+
+            let val = fx.bcx.ins().fmin(a, b);
+            let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64));
+            ret.write_cvalue(fx, val);
+        }
+        sym::maximumf32 => {
+            intrinsic_args!(fx, args => (a, b); intrinsic);
+            let a = a.load_scalar(fx);
+            let b = b.load_scalar(fx);
+
+            let val = fx.bcx.ins().fmax(a, b);
+            let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32));
+            ret.write_cvalue(fx, val);
+        }
+        sym::maximumf64 => {
+            intrinsic_args!(fx, args => (a, b); intrinsic);
+            let a = a.load_scalar(fx);
+            let b = b.load_scalar(fx);
+
+            let val = fx.bcx.ins().fmax(a, b);
+            let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64));
+            ret.write_cvalue(fx, val);
+        }
+
         sym::minnumf32 => {
             intrinsic_args!(fx, args => (a, b); intrinsic);
             let a = a.load_scalar(fx);
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index 2ed5ec4381edf..9caceca92957a 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -74,8 +74,44 @@ fn get_simple_intrinsic<'gcc, 'tcx>(
         sym::fabsf64 => "fabs",
         sym::minnumf32 => "fminf",
         sym::minnumf64 => "fmin",
+        sym::minimumf32 => "fminimumf",
+        sym::minimumf64 => "fminimum",
+        sym::minimumf128 => {
+            // GCC doesn't have the intrinsic we want so we use the compiler-builtins one
+            // https://docs.rs/compiler_builtins/latest/compiler_builtins/math/full_availability/fn.fminimumf128.html
+            let f128_type = cx.type_f128();
+            return Some(cx.context.new_function(
+                None,
+                FunctionType::Extern,
+                f128_type,
+                &[
+                    cx.context.new_parameter(None, f128_type, "a"),
+                    cx.context.new_parameter(None, f128_type, "b"),
+                ],
+                "fminimumf128",
+                false,
+            ));
+        }
         sym::maxnumf32 => "fmaxf",
         sym::maxnumf64 => "fmax",
+        sym::maximumf32 => "fmaximumf",
+        sym::maximumf64 => "fmaximum",
+        sym::maximumf128 => {
+            // GCC doesn't have the intrinsic we want so we use the compiler-builtins one
+            // https://docs.rs/compiler_builtins/latest/compiler_builtins/math/full_availability/fn.fmaximumf128.html
+            let f128_type = cx.type_f128();
+            return Some(cx.context.new_function(
+                None,
+                FunctionType::Extern,
+                f128_type,
+                &[
+                    cx.context.new_parameter(None, f128_type, "a"),
+                    cx.context.new_parameter(None, f128_type, "b"),
+                ],
+                "fmaximumf128",
+                false,
+            ));
+        }
         sym::copysignf32 => "copysignf",
         sym::copysignf64 => "copysign",
         sym::copysignf128 => "copysignl",
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index ed50515b70716..0c6006fbc6acb 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -1009,11 +1009,21 @@ impl<'ll> CodegenCx<'ll, '_> {
         ifn!("llvm.minnum.f64", fn(t_f64, t_f64) -> t_f64);
         ifn!("llvm.minnum.f128", fn(t_f128, t_f128) -> t_f128);
 
+        ifn!("llvm.minimum.f16", fn(t_f16, t_f16) -> t_f16);
+        ifn!("llvm.minimum.f32", fn(t_f32, t_f32) -> t_f32);
+        ifn!("llvm.minimum.f64", fn(t_f64, t_f64) -> t_f64);
+        ifn!("llvm.minimum.f128", fn(t_f128, t_f128) -> t_f128);
+
         ifn!("llvm.maxnum.f16", fn(t_f16, t_f16) -> t_f16);
         ifn!("llvm.maxnum.f32", fn(t_f32, t_f32) -> t_f32);
         ifn!("llvm.maxnum.f64", fn(t_f64, t_f64) -> t_f64);
         ifn!("llvm.maxnum.f128", fn(t_f128, t_f128) -> t_f128);
 
+        ifn!("llvm.maximum.f16", fn(t_f16, t_f16) -> t_f16);
+        ifn!("llvm.maximum.f32", fn(t_f32, t_f32) -> t_f32);
+        ifn!("llvm.maximum.f64", fn(t_f64, t_f64) -> t_f64);
+        ifn!("llvm.maximum.f128", fn(t_f128, t_f128) -> t_f128);
+
         ifn!("llvm.floor.f16", fn(t_f16) -> t_f16);
         ifn!("llvm.floor.f32", fn(t_f32) -> t_f32);
         ifn!("llvm.floor.f64", fn(t_f64) -> t_f64);
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index bfaad8f2f1ef0..c68e0036d6efa 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -103,11 +103,21 @@ fn get_simple_intrinsic<'ll>(
         sym::minnumf64 => "llvm.minnum.f64",
         sym::minnumf128 => "llvm.minnum.f128",
 
+        sym::minimumf16 => "llvm.minimum.f16",
+        sym::minimumf32 => "llvm.minimum.f32",
+        sym::minimumf64 => "llvm.minimum.f64",
+        sym::minimumf128 => "llvm.minimum.f128",
+
         sym::maxnumf16 => "llvm.maxnum.f16",
         sym::maxnumf32 => "llvm.maxnum.f32",
         sym::maxnumf64 => "llvm.maxnum.f64",
         sym::maxnumf128 => "llvm.maxnum.f128",
 
+        sym::maximumf16 => "llvm.maximum.f16",
+        sym::maximumf32 => "llvm.maximum.f32",
+        sym::maximumf64 => "llvm.maximum.f64",
+        sym::maximumf128 => "llvm.maximum.f128",
+
         sym::copysignf16 => "llvm.copysign.f16",
         sym::copysignf32 => "llvm.copysign.f32",
         sym::copysignf64 => "llvm.copysign.f64",
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 04a8ed1e0f1e9..090b2a692cfc3 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -493,11 +493,21 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             sym::minnumf64 => self.float_min_intrinsic::(args, dest)?,
             sym::minnumf128 => self.float_min_intrinsic::(args, dest)?,
 
+            sym::minimumf16 => self.float_minimum_intrinsic::(args, dest)?,
+            sym::minimumf32 => self.float_minimum_intrinsic::(args, dest)?,
+            sym::minimumf64 => self.float_minimum_intrinsic::(args, dest)?,
+            sym::minimumf128 => self.float_minimum_intrinsic::(args, dest)?,
+
             sym::maxnumf16 => self.float_max_intrinsic::(args, dest)?,
             sym::maxnumf32 => self.float_max_intrinsic::(args, dest)?,
             sym::maxnumf64 => self.float_max_intrinsic::(args, dest)?,
             sym::maxnumf128 => self.float_max_intrinsic::(args, dest)?,
 
+            sym::maximumf16 => self.float_maximum_intrinsic::(args, dest)?,
+            sym::maximumf32 => self.float_maximum_intrinsic::(args, dest)?,
+            sym::maximumf64 => self.float_maximum_intrinsic::(args, dest)?,
+            sym::maximumf128 => self.float_maximum_intrinsic::(args, dest)?,
+
             sym::copysignf16 => self.float_copysign_intrinsic::(args, dest)?,
             sym::copysignf32 => self.float_copysign_intrinsic::(args, dest)?,
             sym::copysignf64 => self.float_copysign_intrinsic::(args, dest)?,
@@ -830,6 +840,38 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         interp_ok(())
     }
 
+    fn float_minimum_intrinsic(
+        &mut self,
+        args: &[OpTy<'tcx, M::Provenance>],
+        dest: &MPlaceTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, ()>
+    where
+        F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>,
+    {
+        let a: F = self.read_scalar(&args[0])?.to_float()?;
+        let b: F = self.read_scalar(&args[1])?.to_float()?;
+        let res = a.minimum(b);
+        let res = self.adjust_nan(res, &[a, b]);
+        self.write_scalar(res, dest)?;
+        interp_ok(())
+    }
+
+    fn float_maximum_intrinsic(
+        &mut self,
+        args: &[OpTy<'tcx, M::Provenance>],
+        dest: &MPlaceTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, ()>
+    where
+        F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>,
+    {
+        let a: F = self.read_scalar(&args[0])?.to_float()?;
+        let b: F = self.read_scalar(&args[1])?.to_float()?;
+        let res = a.maximum(b);
+        let res = self.adjust_nan(res, &[a, b]);
+        self.write_scalar(res, dest)?;
+        interp_ok(())
+    }
+
     fn float_copysign_intrinsic(
         &mut self,
         args: &[OpTy<'tcx, M::Provenance>],
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 692784bf1714d..9fd158ad154d8 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -103,10 +103,18 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
         | sym::minnumf32
         | sym::minnumf64
         | sym::minnumf128
+        | sym::minimumf16
+        | sym::minimumf32
+        | sym::minimumf64
+        | sym::minimumf128
         | sym::maxnumf16
         | sym::maxnumf32
         | sym::maxnumf64
         | sym::maxnumf128
+        | sym::maximumf16
+        | sym::maximumf32
+        | sym::maximumf64
+        | sym::maximumf128
         | sym::rustc_peek
         | sym::type_name
         | sym::forget
@@ -374,11 +382,21 @@ pub(crate) fn check_intrinsic_type(
             sym::minnumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
             sym::minnumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128),
 
+            sym::minimumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16),
+            sym::minimumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
+            sym::minimumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
+            sym::minimumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128),
+
             sym::maxnumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16),
             sym::maxnumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
             sym::maxnumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
             sym::maxnumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128),
 
+            sym::maximumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16),
+            sym::maximumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
+            sym::maximumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
+            sym::maximumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128),
+
             sym::copysignf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16),
             sym::copysignf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
             sym::copysignf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 40cec4083089a..a0420eccfb000 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1301,6 +1301,10 @@ symbols! {
         match_beginning_vert,
         match_default_bindings,
         matches_macro,
+        maximumf128,
+        maximumf16,
+        maximumf32,
+        maximumf64,
         maxnumf128,
         maxnumf16,
         maxnumf32,
@@ -1335,6 +1339,10 @@ symbols! {
         min_generic_const_args,
         min_specialization,
         min_type_alias_impl_trait,
+        minimumf128,
+        minimumf16,
+        minimumf32,
+        minimumf64,
         minnumf128,
         minnumf16,
         minnumf32,
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index 5649736e40492..002ef418ae237 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -3928,7 +3928,7 @@ pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) {
     }
 }
 
-/// Returns the minimum of two `f16` values.
+/// Returns the minimum (IEEE 754-2008 minNum) of two `f16` values.
 ///
 /// Note that, unlike most intrinsics, this is safe to call;
 /// it does not require an `unsafe` block.
@@ -3941,7 +3941,7 @@ pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) {
 #[rustc_intrinsic]
 pub const fn minnumf16(x: f16, y: f16) -> f16;
 
-/// Returns the minimum of two `f32` values.
+/// Returns the minimum (IEEE 754-2008 minNum) of two `f32` values.
 ///
 /// Note that, unlike most intrinsics, this is safe to call;
 /// it does not require an `unsafe` block.
@@ -3955,7 +3955,7 @@ pub const fn minnumf16(x: f16, y: f16) -> f16;
 #[rustc_intrinsic]
 pub const fn minnumf32(x: f32, y: f32) -> f32;
 
-/// Returns the minimum of two `f64` values.
+/// Returns the minimum (IEEE 754-2008 minNum) of two `f64` values.
 ///
 /// Note that, unlike most intrinsics, this is safe to call;
 /// it does not require an `unsafe` block.
@@ -3969,7 +3969,7 @@ pub const fn minnumf32(x: f32, y: f32) -> f32;
 #[rustc_intrinsic]
 pub const fn minnumf64(x: f64, y: f64) -> f64;
 
-/// Returns the minimum of two `f128` values.
+/// Returns the minimum (IEEE 754-2008 minNum) of two `f128` values.
 ///
 /// Note that, unlike most intrinsics, this is safe to call;
 /// it does not require an `unsafe` block.
@@ -3982,7 +3982,51 @@ pub const fn minnumf64(x: f64, y: f64) -> f64;
 #[rustc_intrinsic]
 pub const fn minnumf128(x: f128, y: f128) -> f128;
 
-/// Returns the maximum of two `f16` values.
+/// Returns the minimum (IEEE 754-2019 minimum) of two `f16` values.
+///
+/// Note that, unlike most intrinsics, this is safe to call;
+/// it does not require an `unsafe` block.
+/// Therefore, implementations must not require the user to uphold
+/// any safety invariants.
+#[rustc_nounwind]
+#[rustc_intrinsic]
+#[cfg(not(bootstrap))]
+pub const fn minimumf16(x: f16, y: f16) -> f16;
+
+/// Returns the minimum (IEEE 754-2019 minimum) of two `f32` values.
+///
+/// Note that, unlike most intrinsics, this is safe to call;
+/// it does not require an `unsafe` block.
+/// Therefore, implementations must not require the user to uphold
+/// any safety invariants.
+#[rustc_nounwind]
+#[rustc_intrinsic]
+#[cfg(not(bootstrap))]
+pub const fn minimumf32(x: f32, y: f32) -> f32;
+
+/// Returns the minimum (IEEE 754-2019 minimum) of two `f64` values.
+///
+/// Note that, unlike most intrinsics, this is safe to call;
+/// it does not require an `unsafe` block.
+/// Therefore, implementations must not require the user to uphold
+/// any safety invariants.
+#[rustc_nounwind]
+#[rustc_intrinsic]
+#[cfg(not(bootstrap))]
+pub const fn minimumf64(x: f64, y: f64) -> f64;
+
+/// Returns the minimum (IEEE 754-2019 minimum) of two `f128` values.
+///
+/// Note that, unlike most intrinsics, this is safe to call;
+/// it does not require an `unsafe` block.
+/// Therefore, implementations must not require the user to uphold
+/// any safety invariants.
+#[rustc_nounwind]
+#[rustc_intrinsic]
+#[cfg(not(bootstrap))]
+pub const fn minimumf128(x: f128, y: f128) -> f128;
+
+/// Returns the maximum (IEEE 754-2008 maxNum) of two `f16` values.
 ///
 /// Note that, unlike most intrinsics, this is safe to call;
 /// it does not require an `unsafe` block.
@@ -3995,7 +4039,7 @@ pub const fn minnumf128(x: f128, y: f128) -> f128;
 #[rustc_intrinsic]
 pub const fn maxnumf16(x: f16, y: f16) -> f16;
 
-/// Returns the maximum of two `f32` values.
+/// Returns the maximum (IEEE 754-2008 maxNum) of two `f32` values.
 ///
 /// Note that, unlike most intrinsics, this is safe to call;
 /// it does not require an `unsafe` block.
@@ -4009,7 +4053,7 @@ pub const fn maxnumf16(x: f16, y: f16) -> f16;
 #[rustc_intrinsic]
 pub const fn maxnumf32(x: f32, y: f32) -> f32;
 
-/// Returns the maximum of two `f64` values.
+/// Returns the maximum (IEEE 754-2008 maxNum) of two `f64` values.
 ///
 /// Note that, unlike most intrinsics, this is safe to call;
 /// it does not require an `unsafe` block.
@@ -4023,7 +4067,7 @@ pub const fn maxnumf32(x: f32, y: f32) -> f32;
 #[rustc_intrinsic]
 pub const fn maxnumf64(x: f64, y: f64) -> f64;
 
-/// Returns the maximum of two `f128` values.
+/// Returns the maximum (IEEE 754-2008 maxNum) of two `f128` values.
 ///
 /// Note that, unlike most intrinsics, this is safe to call;
 /// it does not require an `unsafe` block.
@@ -4036,6 +4080,50 @@ pub const fn maxnumf64(x: f64, y: f64) -> f64;
 #[rustc_intrinsic]
 pub const fn maxnumf128(x: f128, y: f128) -> f128;
 
+/// Returns the maximum (IEEE 754-2019 maximum) of two `f16` values.
+///
+/// Note that, unlike most intrinsics, this is safe to call;
+/// it does not require an `unsafe` block.
+/// Therefore, implementations must not require the user to uphold
+/// any safety invariants.
+#[rustc_nounwind]
+#[rustc_intrinsic]
+#[cfg(not(bootstrap))]
+pub const fn maximumf16(x: f16, y: f16) -> f16;
+
+/// Returns the maximum (IEEE 754-2019 maximum) of two `f32` values.
+///
+/// Note that, unlike most intrinsics, this is safe to call;
+/// it does not require an `unsafe` block.
+/// Therefore, implementations must not require the user to uphold
+/// any safety invariants.
+#[rustc_nounwind]
+#[rustc_intrinsic]
+#[cfg(not(bootstrap))]
+pub const fn maximumf32(x: f32, y: f32) -> f32;
+
+/// Returns the maximum (IEEE 754-2019 maximum) of two `f64` values.
+///
+/// Note that, unlike most intrinsics, this is safe to call;
+/// it does not require an `unsafe` block.
+/// Therefore, implementations must not require the user to uphold
+/// any safety invariants.
+#[rustc_nounwind]
+#[rustc_intrinsic]
+#[cfg(not(bootstrap))]
+pub const fn maximumf64(x: f64, y: f64) -> f64;
+
+/// Returns the maximum (IEEE 754-2019 maximum) of two `f128` values.
+///
+/// Note that, unlike most intrinsics, this is safe to call;
+/// it does not require an `unsafe` block.
+/// Therefore, implementations must not require the user to uphold
+/// any safety invariants.
+#[rustc_nounwind]
+#[rustc_intrinsic]
+#[cfg(not(bootstrap))]
+pub const fn maximumf128(x: f128, y: f128) -> f128;
+
 /// Returns the absolute value of an `f16`.
 ///
 /// The stabilized version of this intrinsic is
diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs
index b1119d4899bab..97e24a19ea614 100644
--- a/library/core/src/num/f128.rs
+++ b/library/core/src/num/f128.rs
@@ -755,16 +755,24 @@ impl f128 {
     #[inline]
     #[unstable(feature = "f128", issue = "116909")]
     // #[unstable(feature = "float_minimum_maximum", issue = "91079")]
+    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     pub const fn maximum(self, other: f128) -> f128 {
-        if self > other {
-            self
-        } else if other > self {
-            other
-        } else if self == other {
-            if self.is_sign_positive() && other.is_sign_negative() { self } else { other }
-        } else {
-            self + other
+        #[cfg(not(bootstrap))]
+        {
+            intrinsics::maximumf128(self, other)
+        }
+        #[cfg(bootstrap)]
+        {
+            if self > other {
+                self
+            } else if other > self {
+                other
+            } else if self == other {
+                if self.is_sign_positive() && other.is_sign_negative() { self } else { other }
+            } else {
+                self + other
+            }
         }
     }
 
@@ -796,17 +804,25 @@ impl f128 {
     #[inline]
     #[unstable(feature = "f128", issue = "116909")]
     // #[unstable(feature = "float_minimum_maximum", issue = "91079")]
+    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     pub const fn minimum(self, other: f128) -> f128 {
-        if self < other {
-            self
-        } else if other < self {
-            other
-        } else if self == other {
-            if self.is_sign_negative() && other.is_sign_positive() { self } else { other }
-        } else {
-            // At least one input is NaN. Use `+` to perform NaN propagation and quieting.
-            self + other
+        #[cfg(not(bootstrap))]
+        {
+            intrinsics::minimumf128(self, other)
+        }
+        #[cfg(bootstrap)]
+        {
+            if self < other {
+                self
+            } else if other < self {
+                other
+            } else if self == other {
+                if self.is_sign_negative() && other.is_sign_positive() { self } else { other }
+            } else {
+                // At least one input is NaN. Use `+` to perform NaN propagation and quieting.
+                self + other
+            }
         }
     }
 
diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs
index 54e38d9e1a6f1..d3af78123c84e 100644
--- a/library/core/src/num/f16.rs
+++ b/library/core/src/num/f16.rs
@@ -744,16 +744,24 @@ impl f16 {
     #[inline]
     #[unstable(feature = "f16", issue = "116909")]
     // #[unstable(feature = "float_minimum_maximum", issue = "91079")]
+    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     pub const fn maximum(self, other: f16) -> f16 {
-        if self > other {
-            self
-        } else if other > self {
-            other
-        } else if self == other {
-            if self.is_sign_positive() && other.is_sign_negative() { self } else { other }
-        } else {
-            self + other
+        #[cfg(not(bootstrap))]
+        {
+            intrinsics::maximumf16(self, other)
+        }
+        #[cfg(bootstrap)]
+        {
+            if self > other {
+                self
+            } else if other > self {
+                other
+            } else if self == other {
+                if self.is_sign_positive() && other.is_sign_negative() { self } else { other }
+            } else {
+                self + other
+            }
         }
     }
 
@@ -784,17 +792,25 @@ impl f16 {
     #[inline]
     #[unstable(feature = "f16", issue = "116909")]
     // #[unstable(feature = "float_minimum_maximum", issue = "91079")]
+    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     pub const fn minimum(self, other: f16) -> f16 {
-        if self < other {
-            self
-        } else if other < self {
-            other
-        } else if self == other {
-            if self.is_sign_negative() && other.is_sign_positive() { self } else { other }
-        } else {
-            // At least one input is NaN. Use `+` to perform NaN propagation and quieting.
-            self + other
+        #[cfg(not(bootstrap))]
+        {
+            intrinsics::minimumf16(self, other)
+        }
+        #[cfg(bootstrap)]
+        {
+            if self < other {
+                self
+            } else if other < self {
+                other
+            } else if self == other {
+                if self.is_sign_negative() && other.is_sign_positive() { self } else { other }
+            } else {
+                // At least one input is NaN. Use `+` to perform NaN propagation and quieting.
+                self + other
+            }
         }
     }
 
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index e66fd3bb52b86..9ee6c3f5f990e 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -942,16 +942,24 @@ impl f32 {
     /// operand is conserved; see the [specification of NaN bit patterns](f32#nan-bit-patterns) for more info.
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[unstable(feature = "float_minimum_maximum", issue = "91079")]
+    #[rustc_const_unstable(feature = "float_minimum_maximum", issue = "91079")]
     #[inline]
     pub const fn maximum(self, other: f32) -> f32 {
-        if self > other {
-            self
-        } else if other > self {
-            other
-        } else if self == other {
-            if self.is_sign_positive() && other.is_sign_negative() { self } else { other }
-        } else {
-            self + other
+        #[cfg(not(bootstrap))]
+        {
+            intrinsics::maximumf32(self, other)
+        }
+        #[cfg(bootstrap)]
+        {
+            if self > other {
+                self
+            } else if other > self {
+                other
+            } else if self == other {
+                if self.is_sign_positive() && other.is_sign_negative() { self } else { other }
+            } else {
+                self + other
+            }
         }
     }
 
@@ -977,17 +985,25 @@ impl f32 {
     /// operand is conserved; see the [specification of NaN bit patterns](f32#nan-bit-patterns) for more info.
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[unstable(feature = "float_minimum_maximum", issue = "91079")]
+    #[rustc_const_unstable(feature = "float_minimum_maximum", issue = "91079")]
     #[inline]
     pub const fn minimum(self, other: f32) -> f32 {
-        if self < other {
-            self
-        } else if other < self {
-            other
-        } else if self == other {
-            if self.is_sign_negative() && other.is_sign_positive() { self } else { other }
-        } else {
-            // At least one input is NaN. Use `+` to perform NaN propagation and quieting.
-            self + other
+        #[cfg(not(bootstrap))]
+        {
+            intrinsics::minimumf32(self, other)
+        }
+        #[cfg(bootstrap)]
+        {
+            if self < other {
+                self
+            } else if other < self {
+                other
+            } else if self == other {
+                if self.is_sign_negative() && other.is_sign_positive() { self } else { other }
+            } else {
+                // At least one input is NaN. Use `+` to perform NaN propagation and quieting.
+                self + other
+            }
         }
     }
 
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index 2d791437b2825..900b936268a5b 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -960,16 +960,24 @@ impl f64 {
     /// operand is conserved; see the [specification of NaN bit patterns](f32#nan-bit-patterns) for more info.
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[unstable(feature = "float_minimum_maximum", issue = "91079")]
+    #[rustc_const_unstable(feature = "float_minimum_maximum", issue = "91079")]
     #[inline]
     pub const fn maximum(self, other: f64) -> f64 {
-        if self > other {
-            self
-        } else if other > self {
-            other
-        } else if self == other {
-            if self.is_sign_positive() && other.is_sign_negative() { self } else { other }
-        } else {
-            self + other
+        #[cfg(not(bootstrap))]
+        {
+            intrinsics::maximumf64(self, other)
+        }
+        #[cfg(bootstrap)]
+        {
+            if self > other {
+                self
+            } else if other > self {
+                other
+            } else if self == other {
+                if self.is_sign_positive() && other.is_sign_negative() { self } else { other }
+            } else {
+                self + other
+            }
         }
     }
 
@@ -995,17 +1003,25 @@ impl f64 {
     /// operand is conserved; see the [specification of NaN bit patterns](f32#nan-bit-patterns) for more info.
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[unstable(feature = "float_minimum_maximum", issue = "91079")]
+    #[rustc_const_unstable(feature = "float_minimum_maximum", issue = "91079")]
     #[inline]
     pub const fn minimum(self, other: f64) -> f64 {
-        if self < other {
-            self
-        } else if other < self {
-            other
-        } else if self == other {
-            if self.is_sign_negative() && other.is_sign_positive() { self } else { other }
-        } else {
-            // At least one input is NaN. Use `+` to perform NaN propagation and quieting.
-            self + other
+        #[cfg(not(bootstrap))]
+        {
+            intrinsics::minimumf64(self, other)
+        }
+        #[cfg(bootstrap)]
+        {
+            if self < other {
+                self
+            } else if other < self {
+                other
+            } else if self == other {
+                if self.is_sign_negative() && other.is_sign_positive() { self } else { other }
+            } else {
+                // At least one input is NaN. Use `+` to perform NaN propagation and quieting.
+                self + other
+            }
         }
     }
 

From 1ac228397d5ea1d84ad20c3d5e2ecca957af6146 Mon Sep 17 00:00:00 2001
From: Urgau 
Date: Thu, 8 May 2025 12:43:10 +0200
Subject: [PATCH 2103/4206] Use intrinsics for
 `{f16,f32,f64,f128}::{minimum,maximum}` operations

---
 src/intrinsic/mod.rs | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs
index 2ed5ec4381edf..9caceca92957a 100644
--- a/src/intrinsic/mod.rs
+++ b/src/intrinsic/mod.rs
@@ -74,8 +74,44 @@ fn get_simple_intrinsic<'gcc, 'tcx>(
         sym::fabsf64 => "fabs",
         sym::minnumf32 => "fminf",
         sym::minnumf64 => "fmin",
+        sym::minimumf32 => "fminimumf",
+        sym::minimumf64 => "fminimum",
+        sym::minimumf128 => {
+            // GCC doesn't have the intrinsic we want so we use the compiler-builtins one
+            // https://docs.rs/compiler_builtins/latest/compiler_builtins/math/full_availability/fn.fminimumf128.html
+            let f128_type = cx.type_f128();
+            return Some(cx.context.new_function(
+                None,
+                FunctionType::Extern,
+                f128_type,
+                &[
+                    cx.context.new_parameter(None, f128_type, "a"),
+                    cx.context.new_parameter(None, f128_type, "b"),
+                ],
+                "fminimumf128",
+                false,
+            ));
+        }
         sym::maxnumf32 => "fmaxf",
         sym::maxnumf64 => "fmax",
+        sym::maximumf32 => "fmaximumf",
+        sym::maximumf64 => "fmaximum",
+        sym::maximumf128 => {
+            // GCC doesn't have the intrinsic we want so we use the compiler-builtins one
+            // https://docs.rs/compiler_builtins/latest/compiler_builtins/math/full_availability/fn.fmaximumf128.html
+            let f128_type = cx.type_f128();
+            return Some(cx.context.new_function(
+                None,
+                FunctionType::Extern,
+                f128_type,
+                &[
+                    cx.context.new_parameter(None, f128_type, "a"),
+                    cx.context.new_parameter(None, f128_type, "b"),
+                ],
+                "fmaximumf128",
+                false,
+            ));
+        }
         sym::copysignf32 => "copysignf",
         sym::copysignf64 => "copysign",
         sym::copysignf128 => "copysignl",

From e6d288ba17962c1f7e3ded3cb13e1ad596f9a813 Mon Sep 17 00:00:00 2001
From: Urgau 
Date: Thu, 8 May 2025 12:43:10 +0200
Subject: [PATCH 2104/4206] Use intrinsics for
 `{f16,f32,f64,f128}::{minimum,maximum}` operations

---
 src/intrinsics/mod.rs | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs
index e866b8962551a..9018d78b00aeb 100644
--- a/src/intrinsics/mod.rs
+++ b/src/intrinsics/mod.rs
@@ -1109,6 +1109,43 @@ fn codegen_regular_intrinsic_call<'tcx>(
             ret.write_cvalue(fx, old);
         }
 
+        sym::minimumf32 => {
+            intrinsic_args!(fx, args => (a, b); intrinsic);
+            let a = a.load_scalar(fx);
+            let b = b.load_scalar(fx);
+
+            let val = fx.bcx.ins().fmin(a, b);
+            let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32));
+            ret.write_cvalue(fx, val);
+        }
+        sym::minimumf64 => {
+            intrinsic_args!(fx, args => (a, b); intrinsic);
+            let a = a.load_scalar(fx);
+            let b = b.load_scalar(fx);
+
+            let val = fx.bcx.ins().fmin(a, b);
+            let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64));
+            ret.write_cvalue(fx, val);
+        }
+        sym::maximumf32 => {
+            intrinsic_args!(fx, args => (a, b); intrinsic);
+            let a = a.load_scalar(fx);
+            let b = b.load_scalar(fx);
+
+            let val = fx.bcx.ins().fmax(a, b);
+            let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32));
+            ret.write_cvalue(fx, val);
+        }
+        sym::maximumf64 => {
+            intrinsic_args!(fx, args => (a, b); intrinsic);
+            let a = a.load_scalar(fx);
+            let b = b.load_scalar(fx);
+
+            let val = fx.bcx.ins().fmax(a, b);
+            let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64));
+            ret.write_cvalue(fx, val);
+        }
+
         sym::minnumf32 => {
             intrinsic_args!(fx, args => (a, b); intrinsic);
             let a = a.load_scalar(fx);

From 577e82f71b07b11c6a6f74ac788c65cbd2674a2a Mon Sep 17 00:00:00 2001
From: est31 
Date: Fri, 9 May 2025 17:11:29 +0200
Subject: [PATCH 2105/4206] Update the edition guide for let chains

---
 src/doc/edition-guide | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/doc/edition-guide b/src/doc/edition-guide
index 467f45637b73e..1b1bb49babd65 160000
--- a/src/doc/edition-guide
+++ b/src/doc/edition-guide
@@ -1 +1 @@
-Subproject commit 467f45637b73ec6aa70fb36bc3054bb50b8967ea
+Subproject commit 1b1bb49babd65c732468cfa515b0c009bd1d26bc

From 0b6e493515d92d4b269eb07c05bf706b64fa5db8 Mon Sep 17 00:00:00 2001
From: Oli Scherer 
Date: Fri, 9 May 2025 15:16:26 +0000
Subject: [PATCH 2106/4206] Merge typeck loop with static/const item eval loop

---
 compiler/rustc_hir_analysis/src/lib.rs        |  4 ---
 .../closure-return-type-mismatch.stderr       | 16 ++++-----
 .../coercion/coerce-loop-issue-122561.stderr  | 30 ++++++++--------
 tests/ui/consts/effect_param.stderr           | 24 ++++++-------
 .../dont-suggest-hygienic-fields.stderr       | 30 ++++++++--------
 .../impl-trait/normalize-tait-in-const.stderr | 16 ++++-----
 tests/ui/parser/pat-lt-bracket-6.stderr       | 12 +++----
 tests/ui/proc-macro/bad-projection.stderr     | 26 +++++++-------
 .../dont-suggest-through-inner-const.stderr   | 12 +++----
 .../no-explicit-const-params.stderr           | 36 +++++++++----------
 tests/ui/transmutability/uninhabited.stderr   | 36 +++++++++----------
 11 files changed, 119 insertions(+), 123 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 91dde13be550e..d010f1fc85164 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -223,10 +223,6 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
             }
             _ => (),
         }
-    });
-
-    tcx.par_hir_body_owners(|item_def_id| {
-        let def_kind = tcx.def_kind(item_def_id);
         // Skip `AnonConst`s because we feed their `type_of`.
         if !matches!(def_kind, DefKind::AnonConst) {
             tcx.ensure_ok().typeck(item_def_id);
diff --git a/tests/ui/closures/closure-return-type-mismatch.stderr b/tests/ui/closures/closure-return-type-mismatch.stderr
index 052bbbb5ed579..f9587d8dad1de 100644
--- a/tests/ui/closures/closure-return-type-mismatch.stderr
+++ b/tests/ui/closures/closure-return-type-mismatch.stderr
@@ -1,11 +1,3 @@
-error[E0308]: mismatched types
-  --> $DIR/closure-return-type-mismatch.rs:20:41
-   |
-LL | static FOO: fn() -> bool = || -> bool { 1 };
-   |                                  ----   ^ expected `bool`, found integer
-   |                                  |
-   |                                  expected `bool` because of return type
-
 error[E0308]: mismatched types
   --> $DIR/closure-return-type-mismatch.rs:7:9
    |
@@ -27,6 +19,14 @@ LL |         if false {
 LL |             return "hello"
    |                    ^^^^^^^ expected `bool`, found `&str`
 
+error[E0308]: mismatched types
+  --> $DIR/closure-return-type-mismatch.rs:20:41
+   |
+LL | static FOO: fn() -> bool = || -> bool { 1 };
+   |                                  ----   ^ expected `bool`, found integer
+   |                                  |
+   |                                  expected `bool` because of return type
+
 error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/coercion/coerce-loop-issue-122561.stderr b/tests/ui/coercion/coerce-loop-issue-122561.stderr
index 3af7e7cddb31d..6415fd554cba9 100644
--- a/tests/ui/coercion/coerce-loop-issue-122561.stderr
+++ b/tests/ui/coercion/coerce-loop-issue-122561.stderr
@@ -24,21 +24,6 @@ help: consider returning a value here
 LL | fn for_in_arg(a: &[(); for x in 0..2 {} /* `usize` value */]) -> bool {
    |                                         +++++++++++++++++++
 
-error[E0308]: mismatched types
-  --> $DIR/coerce-loop-issue-122561.rs:85:5
-   |
-LL | /     for i in 0.. {
-LL | |
-LL | |     }
-   | |_____^ expected `i32`, found `()`
-   |
-   = note: `for` loops evaluate to unit type `()`
-help: consider returning a value here
-   |
-LL ~     }
-LL +     /* `i32` value */
-   |
-
 error[E0308]: mismatched types
   --> $DIR/coerce-loop-issue-122561.rs:4:5
    |
@@ -202,6 +187,21 @@ LL ~     }
 LL +     /* `loop {}` or `panic!("...")` */
    |
 
+error[E0308]: mismatched types
+  --> $DIR/coerce-loop-issue-122561.rs:85:5
+   |
+LL | /     for i in 0.. {
+LL | |
+LL | |     }
+   | |_____^ expected `i32`, found `()`
+   |
+   = note: `for` loops evaluate to unit type `()`
+help: consider returning a value here
+   |
+LL ~     }
+LL +     /* `i32` value */
+   |
+
 error[E0308]: mismatched types
   --> $DIR/coerce-loop-issue-122561.rs:92:9
    |
diff --git a/tests/ui/consts/effect_param.stderr b/tests/ui/consts/effect_param.stderr
index c63be8035f30f..a20092dbf047a 100644
--- a/tests/ui/consts/effect_param.stderr
+++ b/tests/ui/consts/effect_param.stderr
@@ -1,32 +1,32 @@
 error[E0107]: method takes 0 generic arguments but 1 generic argument was supplied
-  --> $DIR/effect_param.rs:11:9
+  --> $DIR/effect_param.rs:4:9
    |
-LL |     i8::checked_sub::(42, 43);
-   |         ^^^^^^^^^^^--------- help: remove the unnecessary generics
+LL |     i8::checked_sub::(42, 43);
+   |         ^^^^^^^^^^^-------- help: remove the unnecessary generics
    |         |
    |         expected 0 generic arguments
 
 error[E0107]: method takes 0 generic arguments but 1 generic argument was supplied
-  --> $DIR/effect_param.rs:13:9
+  --> $DIR/effect_param.rs:6:9
    |
-LL |     i8::checked_sub::(42, 43);
-   |         ^^^^^^^^^^^-------- help: remove the unnecessary generics
+LL |     i8::checked_sub::(42, 43);
+   |         ^^^^^^^^^^^--------- help: remove the unnecessary generics
    |         |
    |         expected 0 generic arguments
 
 error[E0107]: method takes 0 generic arguments but 1 generic argument was supplied
-  --> $DIR/effect_param.rs:4:9
+  --> $DIR/effect_param.rs:11:9
    |
-LL |     i8::checked_sub::(42, 43);
-   |         ^^^^^^^^^^^-------- help: remove the unnecessary generics
+LL |     i8::checked_sub::(42, 43);
+   |         ^^^^^^^^^^^--------- help: remove the unnecessary generics
    |         |
    |         expected 0 generic arguments
 
 error[E0107]: method takes 0 generic arguments but 1 generic argument was supplied
-  --> $DIR/effect_param.rs:6:9
+  --> $DIR/effect_param.rs:13:9
    |
-LL |     i8::checked_sub::(42, 43);
-   |         ^^^^^^^^^^^--------- help: remove the unnecessary generics
+LL |     i8::checked_sub::(42, 43);
+   |         ^^^^^^^^^^^-------- help: remove the unnecessary generics
    |         |
    |         expected 0 generic arguments
 
diff --git a/tests/ui/did_you_mean/dont-suggest-hygienic-fields.stderr b/tests/ui/did_you_mean/dont-suggest-hygienic-fields.stderr
index 411eec8496339..08166355748b5 100644
--- a/tests/ui/did_you_mean/dont-suggest-hygienic-fields.stderr
+++ b/tests/ui/did_you_mean/dont-suggest-hygienic-fields.stderr
@@ -1,18 +1,3 @@
-error[E0560]: struct `Crate` has no field named `fiel`
-  --> $DIR/dont-suggest-hygienic-fields.rs:44:34
-   |
-LL | environment!();
-   | -------------- in this macro invocation
-...
-LL |     const CRATE: Crate = Crate { fiel: () };
-   |                                  ^^^^ unknown field
-   |
-   = note: this error originates in the macro `environment` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: a field with a similar name exists
-   |
-LL |     const CRATE: Crate = Crate { field: () };
-   |                                      +
-
 error[E0609]: no field `field` on type `Compound`
   --> $DIR/dont-suggest-hygienic-fields.rs:24:16
    |
@@ -48,6 +33,21 @@ error[E0609]: no field `0` on type `Component`
 LL |     let _ = ty.0;
    |                ^ unknown field
 
+error[E0560]: struct `Crate` has no field named `fiel`
+  --> $DIR/dont-suggest-hygienic-fields.rs:44:34
+   |
+LL | environment!();
+   | -------------- in this macro invocation
+...
+LL |     const CRATE: Crate = Crate { fiel: () };
+   |                                  ^^^^ unknown field
+   |
+   = note: this error originates in the macro `environment` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: a field with a similar name exists
+   |
+LL |     const CRATE: Crate = Crate { field: () };
+   |                                      +
+
 error: aborting due to 6 previous errors
 
 Some errors have detailed explanations: E0026, E0560, E0609.
diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr
index d4ba9a3117022..2b6825b1ac672 100644
--- a/tests/ui/impl-trait/normalize-tait-in-const.stderr
+++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr
@@ -25,14 +25,6 @@ LL |     pub type Alias<'a> = impl T;
    |
    = note: `Alias` must be used in combination with a concrete type within the same crate
 
-error[E0015]: cannot call non-const closure in constant functions
-  --> $DIR/normalize-tait-in-const.rs:28:5
-   |
-LL |     fun(filter_positive());
-   |     ^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-
 error[E0308]: mismatched types
   --> $DIR/normalize-tait-in-const.rs:22:9
    |
@@ -52,6 +44,14 @@ note: this item must have a `#[define_opaque(foo::Alias)]` attribute to be able
 LL |     pub const fn filter_positive<'a>() -> &'a Alias<'a> {
    |                  ^^^^^^^^^^^^^^^
 
+error[E0015]: cannot call non-const closure in constant functions
+  --> $DIR/normalize-tait-in-const.rs:28:5
+   |
+LL |     fun(filter_positive());
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
 error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0015, E0308.
diff --git a/tests/ui/parser/pat-lt-bracket-6.stderr b/tests/ui/parser/pat-lt-bracket-6.stderr
index 0274809f800c5..83c88d1085ef8 100644
--- a/tests/ui/parser/pat-lt-bracket-6.stderr
+++ b/tests/ui/parser/pat-lt-bracket-6.stderr
@@ -6,12 +6,6 @@ LL |     let Test(&desc[..]) = x;
    |
    = note: arbitrary expressions are not allowed in patterns: 
 
-error[E0308]: mismatched types
-  --> $DIR/pat-lt-bracket-6.rs:10:30
-   |
-LL | const RECOVERY_WITNESS: () = 0;
-   |                              ^ expected `()`, found integer
-
 error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields
   --> $DIR/pat-lt-bracket-6.rs:5:14
    |
@@ -26,6 +20,12 @@ help: use `_` to explicitly ignore each field
 LL |     let Test(&desc[..], _) = x;
    |                       +++
 
+error[E0308]: mismatched types
+  --> $DIR/pat-lt-bracket-6.rs:10:30
+   |
+LL | const RECOVERY_WITNESS: () = 0;
+   |                              ^ expected `()`, found integer
+
 error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0023, E0308.
diff --git a/tests/ui/proc-macro/bad-projection.stderr b/tests/ui/proc-macro/bad-projection.stderr
index aa6b3da6da995..f2981499367b8 100644
--- a/tests/ui/proc-macro/bad-projection.stderr
+++ b/tests/ui/proc-macro/bad-projection.stderr
@@ -10,6 +10,19 @@ help: this trait has no implementations, consider adding one
 LL | trait Project {
    | ^^^^^^^^^^^^^
 
+error[E0277]: the trait bound `(): Project` is not satisfied
+  --> $DIR/bad-projection.rs:14:17
+   |
+LL | pub fn uwu() -> <() as Project>::Assoc {}
+   |                 ^^^^^^^^^^^^^^^^^^^^^^ the trait `Project` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/bad-projection.rs:9:1
+   |
+LL | trait Project {
+   | ^^^^^^^^^^^^^
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
 error[E0593]: function is expected to take 1 argument, but it takes 0 arguments
   --> $DIR/bad-projection.rs:14:1
    |
@@ -47,19 +60,6 @@ help: this trait has no implementations, consider adding one
 LL | trait Project {
    | ^^^^^^^^^^^^^
 
-error[E0277]: the trait bound `(): Project` is not satisfied
-  --> $DIR/bad-projection.rs:14:17
-   |
-LL | pub fn uwu() -> <() as Project>::Assoc {}
-   |                 ^^^^^^^^^^^^^^^^^^^^^^ the trait `Project` is not implemented for `()`
-   |
-help: this trait has no implementations, consider adding one
-  --> $DIR/bad-projection.rs:9:1
-   |
-LL | trait Project {
-   | ^^^^^^^^^^^^^
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
 error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0277, E0593.
diff --git a/tests/ui/return/dont-suggest-through-inner-const.stderr b/tests/ui/return/dont-suggest-through-inner-const.stderr
index 6aeee74b0adf9..fc98b7373754e 100644
--- a/tests/ui/return/dont-suggest-through-inner-const.stderr
+++ b/tests/ui/return/dont-suggest-through-inner-const.stderr
@@ -1,9 +1,3 @@
-error[E0308]: mismatched types
-  --> $DIR/dont-suggest-through-inner-const.rs:4:9
-   |
-LL |         0
-   |         ^ expected `()`, found integer
-
 error[E0308]: mismatched types
   --> $DIR/dont-suggest-through-inner-const.rs:1:17
    |
@@ -12,6 +6,12 @@ LL | const fn f() -> usize {
    |          |
    |          implicitly returns `()` as its body has no tail or `return` expression
 
+error[E0308]: mismatched types
+  --> $DIR/dont-suggest-through-inner-const.rs:4:9
+   |
+LL |         0
+   |         ^ expected `()`, found integer
+
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/const-traits/no-explicit-const-params.stderr b/tests/ui/traits/const-traits/no-explicit-const-params.stderr
index 9bd2c2cb8da2a..6955e9ab2985d 100644
--- a/tests/ui/traits/const-traits/no-explicit-const-params.stderr
+++ b/tests/ui/traits/const-traits/no-explicit-const-params.stderr
@@ -1,8 +1,8 @@
 error[E0107]: function takes 0 generic arguments but 1 generic argument was supplied
-  --> $DIR/no-explicit-const-params.rs:22:5
+  --> $DIR/no-explicit-const-params.rs:15:5
    |
-LL |     foo::();
-   |     ^^^--------- help: remove the unnecessary generics
+LL |     foo::();
+   |     ^^^-------- help: remove the unnecessary generics
    |     |
    |     expected 0 generic arguments
    |
@@ -13,10 +13,10 @@ LL | const fn foo() {}
    |          ^^^
 
 error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
-  --> $DIR/no-explicit-const-params.rs:24:12
+  --> $DIR/no-explicit-const-params.rs:17:12
    |
-LL |     <() as Bar>::bar();
-   |            ^^^------- help: remove the unnecessary generics
+LL |     <() as Bar>::bar();
+   |            ^^^------ help: remove the unnecessary generics
    |            |
    |            expected 0 generic arguments
    |
@@ -26,17 +26,11 @@ note: trait defined here, with 0 generic parameters
 LL | trait Bar {
    |       ^^^
 
-error[E0277]: the trait bound `(): const Bar` is not satisfied
-  --> $DIR/no-explicit-const-params.rs:24:6
-   |
-LL |     <() as Bar>::bar();
-   |      ^^
-
 error[E0107]: function takes 0 generic arguments but 1 generic argument was supplied
-  --> $DIR/no-explicit-const-params.rs:15:5
+  --> $DIR/no-explicit-const-params.rs:22:5
    |
-LL |     foo::();
-   |     ^^^-------- help: remove the unnecessary generics
+LL |     foo::();
+   |     ^^^--------- help: remove the unnecessary generics
    |     |
    |     expected 0 generic arguments
    |
@@ -47,10 +41,10 @@ LL | const fn foo() {}
    |          ^^^
 
 error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
-  --> $DIR/no-explicit-const-params.rs:17:12
+  --> $DIR/no-explicit-const-params.rs:24:12
    |
-LL |     <() as Bar>::bar();
-   |            ^^^------ help: remove the unnecessary generics
+LL |     <() as Bar>::bar();
+   |            ^^^------- help: remove the unnecessary generics
    |            |
    |            expected 0 generic arguments
    |
@@ -60,6 +54,12 @@ note: trait defined here, with 0 generic parameters
 LL | trait Bar {
    |       ^^^
 
+error[E0277]: the trait bound `(): const Bar` is not satisfied
+  --> $DIR/no-explicit-const-params.rs:24:6
+   |
+LL |     <() as Bar>::bar();
+   |      ^^
+
 error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0107, E0277.
diff --git a/tests/ui/transmutability/uninhabited.stderr b/tests/ui/transmutability/uninhabited.stderr
index 4c5c4107a852a..3044b502d3146 100644
--- a/tests/ui/transmutability/uninhabited.stderr
+++ b/tests/ui/transmutability/uninhabited.stderr
@@ -1,21 +1,3 @@
-error[E0080]: evaluation of constant value failed
-  --> $DIR/uninhabited.rs:41:9
-   |
-LL |         assert!(false);
-   |         ^^^^^^^^^^^^^^ evaluation panicked: assertion failed: false
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/uninhabited.rs:63:9
-   |
-LL |         assert!(false);
-   |         ^^^^^^^^^^^^^^ evaluation panicked: assertion failed: false
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/uninhabited.rs:87:9
-   |
-LL |         assert!(false);
-   |         ^^^^^^^^^^^^^^ evaluation panicked: assertion failed: false
-
 error[E0277]: `()` cannot be safely transmuted into `void::Void`
   --> $DIR/uninhabited.rs:29:41
    |
@@ -58,6 +40,12 @@ LL | |                 lifetimes: true,
 LL | |         }>
    | |__________^ required by this bound in `is_maybe_transmutable`
 
+error[E0080]: evaluation of constant value failed
+  --> $DIR/uninhabited.rs:41:9
+   |
+LL |         assert!(false);
+   |         ^^^^^^^^^^^^^^ evaluation panicked: assertion failed: false
+
 error[E0277]: `()` cannot be safely transmuted into `yawning_void_enum::Void`
   --> $DIR/uninhabited.rs:71:41
    |
@@ -79,6 +67,12 @@ LL | |                 lifetimes: true,
 LL | |         }>
    | |__________^ required by this bound in `is_maybe_transmutable`
 
+error[E0080]: evaluation of constant value failed
+  --> $DIR/uninhabited.rs:63:9
+   |
+LL |         assert!(false);
+   |         ^^^^^^^^^^^^^^ evaluation panicked: assertion failed: false
+
 error[E0277]: `u128` cannot be safely transmuted into `DistantVoid`
   --> $DIR/uninhabited.rs:92:43
    |
@@ -100,6 +94,12 @@ LL | |                 lifetimes: true,
 LL | |         }>
    | |__________^ required by this bound in `is_maybe_transmutable`
 
+error[E0080]: evaluation of constant value failed
+  --> $DIR/uninhabited.rs:87:9
+   |
+LL |         assert!(false);
+   |         ^^^^^^^^^^^^^^ evaluation panicked: assertion failed: false
+
 error[E0277]: `Src` cannot be safely transmuted into `issue_126267::Error`
   --> $DIR/uninhabited.rs:108:42
    |

From 79dfd0a472c7a994bfe090cc95034b36d38e6b53 Mon Sep 17 00:00:00 2001
From: Ralf Jung 
Date: Mon, 5 May 2025 15:26:06 +0200
Subject: [PATCH 2107/4206] remove 'unordered' atomic intrinsics

---
 compiler/rustc_codegen_gcc/src/builder.rs       |  1 -
 compiler/rustc_codegen_llvm/src/llvm/ffi.rs     |  2 +-
 compiler/rustc_codegen_ssa/src/common.rs        |  1 -
 compiler/rustc_codegen_ssa/src/mir/intrinsic.rs |  1 -
 library/core/src/intrinsics/mod.rs              | 12 ------------
 5 files changed, 1 insertion(+), 16 deletions(-)

diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index 6720f6186d16e..9e5ebf3a9a40b 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -2454,7 +2454,6 @@ impl ToGccOrdering for AtomicOrdering {
         use MemOrdering::*;
 
         let ordering = match self {
-            AtomicOrdering::Unordered => __ATOMIC_RELAXED,
             AtomicOrdering::Relaxed => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same.
             AtomicOrdering::Acquire => __ATOMIC_ACQUIRE,
             AtomicOrdering::Release => __ATOMIC_RELEASE,
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index ffb490dcdc22b..a249cb86ed42e 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -415,6 +415,7 @@ impl AtomicRmwBinOp {
 pub(crate) enum AtomicOrdering {
     #[allow(dead_code)]
     NotAtomic = 0,
+    #[allow(dead_code)]
     Unordered = 1,
     Monotonic = 2,
     // Consume = 3,  // Not specified yet.
@@ -428,7 +429,6 @@ impl AtomicOrdering {
     pub(crate) fn from_generic(ao: rustc_codegen_ssa::common::AtomicOrdering) -> Self {
         use rustc_codegen_ssa::common::AtomicOrdering as Common;
         match ao {
-            Common::Unordered => Self::Unordered,
             Common::Relaxed => Self::Monotonic,
             Common::Acquire => Self::Acquire,
             Common::Release => Self::Release,
diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs
index 965bd34ac147b..6d0c9d8d06645 100644
--- a/compiler/rustc_codegen_ssa/src/common.rs
+++ b/compiler/rustc_codegen_ssa/src/common.rs
@@ -61,7 +61,6 @@ pub enum AtomicRmwBinOp {
 
 #[derive(Copy, Clone, Debug)]
 pub enum AtomicOrdering {
-    Unordered,
     Relaxed,
     Acquire,
     Release,
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 63025a4574fca..b0fcfee2adf5f 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -336,7 +336,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 };
 
                 let parse_ordering = |bx: &Bx, s| match s {
-                    "unordered" => Unordered,
                     "relaxed" => Relaxed,
                     "acquire" => Acquire,
                     "release" => Release,
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index 5649736e40492..53db7795b8aaa 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -439,12 +439,6 @@ pub unsafe fn atomic_load_acquire(src: *const T) -> T;
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub unsafe fn atomic_load_relaxed(src: *const T) -> T;
-/// Do NOT use this intrinsic; "unordered" operations do not exist in our memory model!
-/// In terms of the Rust Abstract Machine, this operation is equivalent to `src.read()`,
-/// i.e., it performs a non-atomic read.
-#[rustc_intrinsic]
-#[rustc_nounwind]
-pub unsafe fn atomic_load_unordered(src: *const T) -> T;
 
 /// Stores the value at the specified memory location.
 /// `T` must be an integer or pointer type.
@@ -473,12 +467,6 @@ pub unsafe fn atomic_store_release(dst: *mut T, val: T);
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub unsafe fn atomic_store_relaxed(dst: *mut T, val: T);
-/// Do NOT use this intrinsic; "unordered" operations do not exist in our memory model!
-/// In terms of the Rust Abstract Machine, this operation is equivalent to `dst.write(val)`,
-/// i.e., it performs a non-atomic write.
-#[rustc_intrinsic]
-#[rustc_nounwind]
-pub unsafe fn atomic_store_unordered(dst: *mut T, val: T);
 
 /// Stores the value at the specified memory location, returning the old value.
 /// `T` must be an integer or pointer type.

From 7e5fa896a210b205c48a2a8922d21fd680afd39c Mon Sep 17 00:00:00 2001
From: Ralf Jung 
Date: Mon, 5 May 2025 15:26:06 +0200
Subject: [PATCH 2108/4206] remove 'unordered' atomic intrinsics

---
 src/builder.rs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/builder.rs b/src/builder.rs
index 6720f6186d16e..9e5ebf3a9a40b 100644
--- a/src/builder.rs
+++ b/src/builder.rs
@@ -2454,7 +2454,6 @@ impl ToGccOrdering for AtomicOrdering {
         use MemOrdering::*;
 
         let ordering = match self {
-            AtomicOrdering::Unordered => __ATOMIC_RELAXED,
             AtomicOrdering::Relaxed => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same.
             AtomicOrdering::Acquire => __ATOMIC_ACQUIRE,
             AtomicOrdering::Release => __ATOMIC_RELEASE,

From 3caca6dc4ec7a5fdd1a24dc3fa9ef676d8e3c34f Mon Sep 17 00:00:00 2001
From: Pietro Albini 
Date: Fri, 9 May 2025 18:57:57 +0200
Subject: [PATCH 2109/4206] fix new apis being marked as becoming const this
 release

---
 RELEASES.md | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/RELEASES.md b/RELEASES.md
index 1a77c33b9957d..c1529dc04a2b4 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -70,9 +70,6 @@ Stabilized APIs
 - [`impl From for OwnedFd`](https://doc.rust-lang.org/nightly/std/os/fd/struct.OwnedFd.html#impl-From%3CPipeWriter%3E-for-OwnedFd)
 - [`Box>::write`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.write)
 - [`impl TryFrom> for String`](https://doc.rust-lang.org/nightly/std/string/struct.String.html#impl-TryFrom%3CVec%3Cu8%3E%3E-for-String)
-
-These APIs are now stable in const contexts:
-
 - [`<*const T>::offset_from_unsigned`](https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.offset_from_unsigned)
 - [`<*const T>::byte_offset_from_unsigned`](https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.byte_offset_from_unsigned)
 - [`<*mut T>::offset_from_unsigned`](https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.offset_from_unsigned-1)
@@ -81,17 +78,21 @@ These APIs are now stable in const contexts:
 - [`NonNull::byte_offset_from_unsigned`](https://doc.rust-lang.org/nightly/std/ptr/struct.NonNull.html#method.byte_offset_from_unsigned)
 - [`::cast_signed`](https://doc.rust-lang.org/nightly/std/primitive.usize.html#method.cast_signed)
 - [`NonZero::::cast_signed`](https://doc.rust-lang.org/nightly/std/num/struct.NonZero.html#method.cast_signed-5).
-- [`::cast_signed`](https://doc.rust-lang.org/nightly/std/primitive.isize.html#method.cast_signed).
+- [`::cast_unsigned`](https://doc.rust-lang.org/nightly/std/primitive.isize.html#method.cast_unsigned).
 - [`NonZero::::cast_unsigned`](https://doc.rust-lang.org/nightly/std/num/struct.NonZero.html#method.cast_unsigned-5).
 - [`::is_multiple_of`](https://doc.rust-lang.org/nightly/std/primitive.usize.html#method.is_multiple_of)
 - [`::unbounded_shl`](https://doc.rust-lang.org/nightly/std/primitive.usize.html#method.unbounded_shl)
 - [`::unbounded_shr`](https://doc.rust-lang.org/nightly/std/primitive.usize.html#method.unbounded_shr)
 - [`::unbounded_shl`](https://doc.rust-lang.org/nightly/std/primitive.isize.html#method.unbounded_shl)
 - [`::unbounded_shr`](https://doc.rust-lang.org/nightly/std/primitive.isize.html#method.unbounded_shr)
+- [`::midpoint`](https://doc.rust-lang.org/nightly/std/primitive.isize.html#method.midpoint)
 - [`::from_utf8`](https://doc.rust-lang.org/nightly/std/primitive.str.html#method.from_utf8)
 - [`::from_utf8_mut`](https://doc.rust-lang.org/nightly/std/primitive.str.html#method.from_utf8_mut)
 - [`::from_utf8_unchecked`](https://doc.rust-lang.org/nightly/std/primitive.str.html#method.from_utf8_unchecked)
 - [`::from_utf8_unchecked_mut`](https://doc.rust-lang.org/nightly/std/primitive.str.html#method.from_utf8_unchecked_mut)
+
+These APIs are now stable in const contexts:
+
 - [`core::str::from_utf8_mut`](https://doc.rust-lang.org/nightly/std/str/fn.from_utf8_mut.html)
 - [`<[T]>::copy_from_slice`](https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.copy_from_slice)
 - [`SocketAddr::set_ip`](https://doc.rust-lang.org/nightly/std/net/enum.SocketAddr.html#method.set_ip)
@@ -104,7 +105,6 @@ These APIs are now stable in const contexts:
 - [`SocketAddrV6::set_scope_id`](https://doc.rust-lang.org/nightly/std/net/struct.SocketAddrV6.html#method.set_scope_id)
 - [`char::is_digit`](https://doc.rust-lang.org/nightly/std/primitive.char.html#method.is_digit)
 - [`char::is_whitespace`](https://doc.rust-lang.org/nightly/std/primitive.char.html#method.is_whitespace)
-- [`::midpoint`](https://doc.rust-lang.org/std/primitive.isize.html#method.midpoint)
 - [`<[[T; N]]>::as_flattened`](https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.as_flattened)
 - [`<[[T; N]]>::as_flattened_mut`](https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.as_flattened_mut) 
 - [`String::into_bytes`](https://doc.rust-lang.org/nightly/std/string/struct.String.html#method.into_bytes)

From cb253490c3f18abb59b98c9f01c036b28e7deccc Mon Sep 17 00:00:00 2001
From: Pietro Albini 
Date: Fri, 9 May 2025 18:59:54 +0200
Subject: [PATCH 2110/4206] update links to point to stable

---
 RELEASES.md | 146 ++++++++++++++++++++++++++--------------------------
 1 file changed, 73 insertions(+), 73 deletions(-)

diff --git a/RELEASES.md b/RELEASES.md
index c1529dc04a2b4..412a8d9c2d63a 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -45,83 +45,83 @@ Libraries
 Stabilized APIs
 ---------------
 
-- [`Vec::extract_if`](https://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#method.extract_if)
-- [`vec::ExtractIf`](https://doc.rust-lang.org/nightly/std/vec/struct.ExtractIf.html)
-- [`LinkedList::extract_if`](https://doc.rust-lang.org/nightly/std/collections/struct.LinkedList.html#method.extract_if)
-- [`linked_list::ExtractIf`](https://doc.rust-lang.org/nightly/std/collections/linked_list/struct.ExtractIf.html)
-- [`<[T]>::split_off`](https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.split_off)
-- [`<[T]>::split_off_mut`](https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.split_off_mut)
-- [`<[T]>::split_off_first`](https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.split_off_first)
-- [`<[T]>::split_off_first_mut`](https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.split_off_first_mut)
-- [`<[T]>::split_off_last`](https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.split_off_last)
-- [`<[T]>::split_off_last_mut`](https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.split_off_last_mut)
+- [`Vec::extract_if`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.extract_if)
+- [`vec::ExtractIf`](https://doc.rust-lang.org/stable/std/vec/struct.ExtractIf.html)
+- [`LinkedList::extract_if`](https://doc.rust-lang.org/stable/std/collections/struct.LinkedList.html#method.extract_if)
+- [`linked_list::ExtractIf`](https://doc.rust-lang.org/stable/std/collections/linked_list/struct.ExtractIf.html)
+- [`<[T]>::split_off`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_off)
+- [`<[T]>::split_off_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_off_mut)
+- [`<[T]>::split_off_first`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_off_first)
+- [`<[T]>::split_off_first_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_off_first_mut)
+- [`<[T]>::split_off_last`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_off_last)
+- [`<[T]>::split_off_last_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_off_last_mut)
 - [`String::extend_from_within`](https://doc.rust-lang.org/stable/alloc/string/struct.String.html#method.extend_from_within)
-- [`os_str::Display`](https://doc.rust-lang.org/nightly/std/ffi/os_str/struct.Display.html)
-- [`OsString::display`](https://doc.rust-lang.org/nightly/std/ffi/struct.OsString.html#method.display)
-- [`OsStr::display`](https://doc.rust-lang.org/nightly/std/ffi/struct.OsStr.html#method.display)
-- [`io::pipe`](https://doc.rust-lang.org/nightly/std/io/fn.pipe.html)
-- [`io::PipeReader`](https://doc.rust-lang.org/nightly/std/io/struct.PipeReader.html)
-- [`io::PipeWriter`](https://doc.rust-lang.org/nightly/std/io/struct.PipeWriter.html)
-- [`impl From for OwnedHandle`](https://doc.rust-lang.org/nightly/std/os/windows/io/struct.OwnedHandle.html#impl-From%3CPipeReader%3E-for-OwnedHandle)
-- [`impl From for OwnedHandle`](https://doc.rust-lang.org/nightly/std/os/windows/io/struct.OwnedHandle.html#impl-From%3CPipeWriter%3E-for-OwnedHandle)
-- [`impl From for Stdio`](https://doc.rust-lang.org/nightly/std/process/struct.Stdio.html)
-- [`impl From for Stdio`](https://doc.rust-lang.org/nightly/std/process/struct.Stdio.html#impl-From%3CPipeWriter%3E-for-Stdio)
-- [`impl From for OwnedFd`](https://doc.rust-lang.org/nightly/std/os/fd/struct.OwnedFd.html#impl-From%3CPipeReader%3E-for-OwnedFd)
-- [`impl From for OwnedFd`](https://doc.rust-lang.org/nightly/std/os/fd/struct.OwnedFd.html#impl-From%3CPipeWriter%3E-for-OwnedFd)
-- [`Box>::write`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.write)
-- [`impl TryFrom> for String`](https://doc.rust-lang.org/nightly/std/string/struct.String.html#impl-TryFrom%3CVec%3Cu8%3E%3E-for-String)
-- [`<*const T>::offset_from_unsigned`](https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.offset_from_unsigned)
-- [`<*const T>::byte_offset_from_unsigned`](https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.byte_offset_from_unsigned)
-- [`<*mut T>::offset_from_unsigned`](https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.offset_from_unsigned-1)
-- [`<*mut T>::byte_offset_from_unsigned`](https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.byte_offset_from_unsigned-1)
-- [`NonNull::offset_from_unsigned`](https://doc.rust-lang.org/nightly/std/ptr/struct.NonNull.html#method.offset_from_unsigned)
-- [`NonNull::byte_offset_from_unsigned`](https://doc.rust-lang.org/nightly/std/ptr/struct.NonNull.html#method.byte_offset_from_unsigned)
-- [`::cast_signed`](https://doc.rust-lang.org/nightly/std/primitive.usize.html#method.cast_signed)
-- [`NonZero::::cast_signed`](https://doc.rust-lang.org/nightly/std/num/struct.NonZero.html#method.cast_signed-5).
-- [`::cast_unsigned`](https://doc.rust-lang.org/nightly/std/primitive.isize.html#method.cast_unsigned).
-- [`NonZero::::cast_unsigned`](https://doc.rust-lang.org/nightly/std/num/struct.NonZero.html#method.cast_unsigned-5).
-- [`::is_multiple_of`](https://doc.rust-lang.org/nightly/std/primitive.usize.html#method.is_multiple_of)
-- [`::unbounded_shl`](https://doc.rust-lang.org/nightly/std/primitive.usize.html#method.unbounded_shl)
-- [`::unbounded_shr`](https://doc.rust-lang.org/nightly/std/primitive.usize.html#method.unbounded_shr)
-- [`::unbounded_shl`](https://doc.rust-lang.org/nightly/std/primitive.isize.html#method.unbounded_shl)
-- [`::unbounded_shr`](https://doc.rust-lang.org/nightly/std/primitive.isize.html#method.unbounded_shr)
-- [`::midpoint`](https://doc.rust-lang.org/nightly/std/primitive.isize.html#method.midpoint)
-- [`::from_utf8`](https://doc.rust-lang.org/nightly/std/primitive.str.html#method.from_utf8)
-- [`::from_utf8_mut`](https://doc.rust-lang.org/nightly/std/primitive.str.html#method.from_utf8_mut)
-- [`::from_utf8_unchecked`](https://doc.rust-lang.org/nightly/std/primitive.str.html#method.from_utf8_unchecked)
-- [`::from_utf8_unchecked_mut`](https://doc.rust-lang.org/nightly/std/primitive.str.html#method.from_utf8_unchecked_mut)
+- [`os_str::Display`](https://doc.rust-lang.org/stable/std/ffi/os_str/struct.Display.html)
+- [`OsString::display`](https://doc.rust-lang.org/stable/std/ffi/struct.OsString.html#method.display)
+- [`OsStr::display`](https://doc.rust-lang.org/stable/std/ffi/struct.OsStr.html#method.display)
+- [`io::pipe`](https://doc.rust-lang.org/stable/std/io/fn.pipe.html)
+- [`io::PipeReader`](https://doc.rust-lang.org/stable/std/io/struct.PipeReader.html)
+- [`io::PipeWriter`](https://doc.rust-lang.org/stable/std/io/struct.PipeWriter.html)
+- [`impl From for OwnedHandle`](https://doc.rust-lang.org/stable/std/os/windows/io/struct.OwnedHandle.html#impl-From%3CPipeReader%3E-for-OwnedHandle)
+- [`impl From for OwnedHandle`](https://doc.rust-lang.org/stable/std/os/windows/io/struct.OwnedHandle.html#impl-From%3CPipeWriter%3E-for-OwnedHandle)
+- [`impl From for Stdio`](https://doc.rust-lang.org/stable/std/process/struct.Stdio.html)
+- [`impl From for Stdio`](https://doc.rust-lang.org/stable/std/process/struct.Stdio.html#impl-From%3CPipeWriter%3E-for-Stdio)
+- [`impl From for OwnedFd`](https://doc.rust-lang.org/stable/std/os/fd/struct.OwnedFd.html#impl-From%3CPipeReader%3E-for-OwnedFd)
+- [`impl From for OwnedFd`](https://doc.rust-lang.org/stable/std/os/fd/struct.OwnedFd.html#impl-From%3CPipeWriter%3E-for-OwnedFd)
+- [`Box>::write`](https://doc.rust-lang.org/stable/std/boxed/struct.Box.html#method.write)
+- [`impl TryFrom> for String`](https://doc.rust-lang.org/stable/std/string/struct.String.html#impl-TryFrom%3CVec%3Cu8%3E%3E-for-String)
+- [`<*const T>::offset_from_unsigned`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset_from_unsigned)
+- [`<*const T>::byte_offset_from_unsigned`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.byte_offset_from_unsigned)
+- [`<*mut T>::offset_from_unsigned`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset_from_unsigned-1)
+- [`<*mut T>::byte_offset_from_unsigned`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.byte_offset_from_unsigned-1)
+- [`NonNull::offset_from_unsigned`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.offset_from_unsigned)
+- [`NonNull::byte_offset_from_unsigned`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.byte_offset_from_unsigned)
+- [`::cast_signed`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.cast_signed)
+- [`NonZero::::cast_signed`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html#method.cast_signed-5).
+- [`::cast_unsigned`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.cast_unsigned).
+- [`NonZero::::cast_unsigned`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html#method.cast_unsigned-5).
+- [`::is_multiple_of`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.is_multiple_of)
+- [`::unbounded_shl`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.unbounded_shl)
+- [`::unbounded_shr`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.unbounded_shr)
+- [`::unbounded_shl`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.unbounded_shl)
+- [`::unbounded_shr`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.unbounded_shr)
+- [`::midpoint`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.midpoint)
+- [`::from_utf8`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.from_utf8)
+- [`::from_utf8_mut`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.from_utf8_mut)
+- [`::from_utf8_unchecked`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.from_utf8_unchecked)
+- [`::from_utf8_unchecked_mut`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.from_utf8_unchecked_mut)
 
 These APIs are now stable in const contexts:
 
-- [`core::str::from_utf8_mut`](https://doc.rust-lang.org/nightly/std/str/fn.from_utf8_mut.html)
-- [`<[T]>::copy_from_slice`](https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.copy_from_slice)
-- [`SocketAddr::set_ip`](https://doc.rust-lang.org/nightly/std/net/enum.SocketAddr.html#method.set_ip)
-- [`SocketAddr::set_port`](https://doc.rust-lang.org/nightly/std/net/enum.SocketAddr.html#method.set_port),
-- [`SocketAddrV4::set_ip`](https://doc.rust-lang.org/nightly/std/net/struct.SocketAddrV4.html#method.set_ip)
-- [`SocketAddrV4::set_port`](https://doc.rust-lang.org/nightly/std/net/struct.SocketAddrV4.html#method.set_port),
-- [`SocketAddrV6::set_ip`](https://doc.rust-lang.org/nightly/std/net/struct.SocketAddrV6.html#method.set_ip)
-- [`SocketAddrV6::set_port`](https://doc.rust-lang.org/nightly/std/net/struct.SocketAddrV6.html#method.set_port)
-- [`SocketAddrV6::set_flowinfo`](https://doc.rust-lang.org/nightly/std/net/struct.SocketAddrV6.html#method.set_flowinfo)
-- [`SocketAddrV6::set_scope_id`](https://doc.rust-lang.org/nightly/std/net/struct.SocketAddrV6.html#method.set_scope_id)
-- [`char::is_digit`](https://doc.rust-lang.org/nightly/std/primitive.char.html#method.is_digit)
-- [`char::is_whitespace`](https://doc.rust-lang.org/nightly/std/primitive.char.html#method.is_whitespace)
-- [`<[[T; N]]>::as_flattened`](https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.as_flattened)
-- [`<[[T; N]]>::as_flattened_mut`](https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.as_flattened_mut) 
-- [`String::into_bytes`](https://doc.rust-lang.org/nightly/std/string/struct.String.html#method.into_bytes)
-- [`String::as_str`](https://doc.rust-lang.org/nightly/std/string/struct.String.html#method.as_str)
-- [`String::capacity`](https://doc.rust-lang.org/nightly/std/string/struct.String.html#method.capacity)
-- [`String::as_bytes`](https://doc.rust-lang.org/nightly/std/string/struct.String.html#method.as_bytes)
-- [`String::len`](https://doc.rust-lang.org/nightly/std/string/struct.String.html#method.len)
-- [`String::is_empty`](https://doc.rust-lang.org/nightly/std/string/struct.String.html#method.is_empty)
-- [`String::as_mut_str`](https://doc.rust-lang.org/nightly/std/string/struct.String.html#method.as_mut_str)
-- [`String::as_mut_vec`](https://doc.rust-lang.org/nightly/std/string/struct.String.html#method.as_mut_vec)
-- [`Vec::as_ptr`](https://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#method.as_ptr)
-- [`Vec::as_slice`](https://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#method.as_slice)
-- [`Vec::capacity`](https://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#method.capacity)
-- [`Vec::len`](https://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#method.len)
-- [`Vec::is_empty`](https://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#method.is_empty)
-- [`Vec::as_mut_slice`](https://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#method.as_mut_slice)
-- [`Vec::as_mut_ptr`](https://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#method.as_mut_ptr)
+- [`core::str::from_utf8_mut`](https://doc.rust-lang.org/stable/std/str/fn.from_utf8_mut.html)
+- [`<[T]>::copy_from_slice`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.copy_from_slice)
+- [`SocketAddr::set_ip`](https://doc.rust-lang.org/stable/std/net/enum.SocketAddr.html#method.set_ip)
+- [`SocketAddr::set_port`](https://doc.rust-lang.org/stable/std/net/enum.SocketAddr.html#method.set_port),
+- [`SocketAddrV4::set_ip`](https://doc.rust-lang.org/stable/std/net/struct.SocketAddrV4.html#method.set_ip)
+- [`SocketAddrV4::set_port`](https://doc.rust-lang.org/stable/std/net/struct.SocketAddrV4.html#method.set_port),
+- [`SocketAddrV6::set_ip`](https://doc.rust-lang.org/stable/std/net/struct.SocketAddrV6.html#method.set_ip)
+- [`SocketAddrV6::set_port`](https://doc.rust-lang.org/stable/std/net/struct.SocketAddrV6.html#method.set_port)
+- [`SocketAddrV6::set_flowinfo`](https://doc.rust-lang.org/stable/std/net/struct.SocketAddrV6.html#method.set_flowinfo)
+- [`SocketAddrV6::set_scope_id`](https://doc.rust-lang.org/stable/std/net/struct.SocketAddrV6.html#method.set_scope_id)
+- [`char::is_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_digit)
+- [`char::is_whitespace`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_whitespace)
+- [`<[[T; N]]>::as_flattened`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_flattened)
+- [`<[[T; N]]>::as_flattened_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_flattened_mut) 
+- [`String::into_bytes`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.into_bytes)
+- [`String::as_str`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.as_str)
+- [`String::capacity`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.capacity)
+- [`String::as_bytes`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.as_bytes)
+- [`String::len`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.len)
+- [`String::is_empty`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.is_empty)
+- [`String::as_mut_str`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.as_mut_str)
+- [`String::as_mut_vec`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.as_mut_vec)
+- [`Vec::as_ptr`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.as_ptr)
+- [`Vec::as_slice`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.as_slice)
+- [`Vec::capacity`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.capacity)
+- [`Vec::len`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.len)
+- [`Vec::is_empty`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.is_empty)
+- [`Vec::as_mut_slice`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.as_mut_slice)
+- [`Vec::as_mut_ptr`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.as_mut_ptr)
 
 
 

From 3c8efb57bd04532c629909deef3ba6881f9b9e15 Mon Sep 17 00:00:00 2001
From: Pietro Albini 
Date: Fri, 9 May 2025 19:11:17 +0200
Subject: [PATCH 2111/4206] update wording

---
 RELEASES.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/RELEASES.md b/RELEASES.md
index 412a8d9c2d63a..83eb49a3fe64c 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -91,7 +91,7 @@ Stabilized APIs
 - [`::from_utf8_unchecked`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.from_utf8_unchecked)
 - [`::from_utf8_unchecked_mut`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.from_utf8_unchecked_mut)
 
-These APIs are now stable in const contexts:
+These previously stable APIs are now stable in const contexts:
 
 - [`core::str::from_utf8_mut`](https://doc.rust-lang.org/stable/std/str/fn.from_utf8_mut.html)
 - [`<[T]>::copy_from_slice`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.copy_from_slice)

From 4314d19e31235467b94e360bdf3951cef74e66e1 Mon Sep 17 00:00:00 2001
From: Kivooeo 
Date: Fri, 9 May 2025 22:21:35 +0500
Subject: [PATCH 2112/4206] make t looks like lowercase

---
 tests/ui/weird-exprs.rs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/tests/ui/weird-exprs.rs b/tests/ui/weird-exprs.rs
index 55a8d580a8b7b..b24e754a4ec98 100644
--- a/tests/ui/weird-exprs.rs
+++ b/tests/ui/weird-exprs.rs
@@ -127,13 +127,13 @@ fn special_characters() {
 }
 
 fn punch_card() -> impl std::fmt::Debug {
-    ..=..=.. ..    .. .. .. ..    .. .. .. ..    .. ..=.. ..
-    ..=.. ..=..    .. .. .. ..    .. .. .. ..    ..=..=..=..
-    ..=.. ..=..    ..=.. ..=..    .. ..=..=..    .. ..=.. ..
+    ..=..=.. ..    .. .. .. ..    .. .. .. ..    .. .. .. ..
+    ..=.. ..=..    .. .. .. ..    .. .. .. ..    .. ..=.. ..
+    ..=.. ..=..    ..=.. ..=..    .. ..=..=..    ..=..=..=..
     ..=..=.. ..    ..=.. ..=..    ..=.. .. ..    .. ..=.. ..
     ..=.. ..=..    ..=.. ..=..    .. ..=.. ..    .. ..=.. ..
     ..=.. ..=..    ..=.. ..=..    .. .. ..=..    .. ..=.. ..
-    ..=.. ..=..    .. ..=..=..    ..=..=.. ..    .. ..=.. ..
+    ..=.. ..=..    .. ..=..=..    ..=..=.. ..    .. ..=..=..
 }
 
 fn r#match() {

From 35679bad981e1551138a8b367c0571b0a5928a27 Mon Sep 17 00:00:00 2001
From: Daniel Paoliello 
Date: Fri, 9 May 2025 09:36:33 -0700
Subject: [PATCH 2113/4206] Enable non-leaf Frame Pointers for Arm64EC Windows

---
 .../src/spec/targets/arm64ec_pc_windows_msvc.rs           | 8 +++++++-
 tests/assembly/asm/aarch64-types.rs                       | 6 ++++--
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs
index bb3e3e544cba4..8f93523909e37 100644
--- a/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Lld, Target, TargetMetadata, add_link_args, base};
+use crate::spec::{FramePointer, LinkerFlavor, Lld, Target, TargetMetadata, add_link_args, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::windows_msvc::opts();
@@ -10,6 +10,12 @@ pub(crate) fn target() -> Target {
         &["/machine:arm64ec", "softintrin.lib"],
     );
 
+    // Microsoft recommends enabling frame pointers on Arm64 Windows.
+    // From https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170#integer-registers
+    // "The frame pointer (x29) is required for compatibility with fast stack walking used by ETW
+    // and other services. It must point to the previous {x29, x30} pair on the stack."
+    base.frame_pointer = FramePointer::NonLeaf;
+
     Target {
         llvm_target: "arm64ec-pc-windows-msvc".into(),
         metadata: TargetMetadata {
diff --git a/tests/assembly/asm/aarch64-types.rs b/tests/assembly/asm/aarch64-types.rs
index 8e4e085032534..ad2770d43e37d 100644
--- a/tests/assembly/asm/aarch64-types.rs
+++ b/tests/assembly/asm/aarch64-types.rs
@@ -86,10 +86,12 @@ pub unsafe fn sym_static() {
 
 // Regression test for #75761
 // CHECK-LABEL: {{("#)?}}issue_75761{{"?}}
-// CHECK: str {{.*}}x30
+// aarch64: str {{.*}}x30
+// arm64ec: stp {{.*}}x30
 // CHECK: //APP
 // CHECK: //NO_APP
-// CHECK: ldr {{.*}}x30
+// aarch64: ldr {{.*}}x30
+// arm64ec: ldp {{.*}}x30
 #[no_mangle]
 pub unsafe fn issue_75761() {
     asm!("", out("v0") _, out("x30") _);

From dc69020aa49914ced62bcaf2371068e2c44bc46c Mon Sep 17 00:00:00 2001
From: Urgau 
Date: Thu, 8 May 2025 22:13:13 +0200
Subject: [PATCH 2114/4206] Add intrinsic fallback for
 `{minimum,maximum}{16,32,64,128}`

---
 library/core/src/intrinsics/mod.rs | 124 +++++++++++++++++++++++------
 library/core/src/num/f128.rs       |  37 +--------
 library/core/src/num/f16.rs        |  37 +--------
 library/core/src/num/f32.rs        |  37 +--------
 library/core/src/num/f64.rs        |  37 +--------
 5 files changed, 108 insertions(+), 164 deletions(-)

diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index 002ef418ae237..d070892358360 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -3989,9 +3989,19 @@ pub const fn minnumf128(x: f128, y: f128) -> f128;
 /// Therefore, implementations must not require the user to uphold
 /// any safety invariants.
 #[rustc_nounwind]
-#[rustc_intrinsic]
-#[cfg(not(bootstrap))]
-pub const fn minimumf16(x: f16, y: f16) -> f16;
+#[cfg_attr(not(bootstrap), rustc_intrinsic)]
+pub const fn minimumf16(x: f16, y: f16) -> f16 {
+    if x < y {
+        x
+    } else if y < x {
+        y
+    } else if x == y {
+        if x.is_sign_negative() && y.is_sign_positive() { x } else { y }
+    } else {
+        // At least one input is NaN. Use `+` to perform NaN propagation and quieting.
+        x + y
+    }
+}
 
 /// Returns the minimum (IEEE 754-2019 minimum) of two `f32` values.
 ///
@@ -4000,9 +4010,19 @@ pub const fn minimumf16(x: f16, y: f16) -> f16;
 /// Therefore, implementations must not require the user to uphold
 /// any safety invariants.
 #[rustc_nounwind]
-#[rustc_intrinsic]
-#[cfg(not(bootstrap))]
-pub const fn minimumf32(x: f32, y: f32) -> f32;
+#[cfg_attr(not(bootstrap), rustc_intrinsic)]
+pub const fn minimumf32(x: f32, y: f32) -> f32 {
+    if x < y {
+        x
+    } else if y < x {
+        y
+    } else if x == y {
+        if x.is_sign_negative() && y.is_sign_positive() { x } else { y }
+    } else {
+        // At least one input is NaN. Use `+` to perform NaN propagation and quieting.
+        x + y
+    }
+}
 
 /// Returns the minimum (IEEE 754-2019 minimum) of two `f64` values.
 ///
@@ -4011,9 +4031,19 @@ pub const fn minimumf32(x: f32, y: f32) -> f32;
 /// Therefore, implementations must not require the user to uphold
 /// any safety invariants.
 #[rustc_nounwind]
-#[rustc_intrinsic]
-#[cfg(not(bootstrap))]
-pub const fn minimumf64(x: f64, y: f64) -> f64;
+#[cfg_attr(not(bootstrap), rustc_intrinsic)]
+pub const fn minimumf64(x: f64, y: f64) -> f64 {
+    if x < y {
+        x
+    } else if y < x {
+        y
+    } else if x == y {
+        if x.is_sign_negative() && y.is_sign_positive() { x } else { y }
+    } else {
+        // At least one input is NaN. Use `+` to perform NaN propagation and quieting.
+        x + y
+    }
+}
 
 /// Returns the minimum (IEEE 754-2019 minimum) of two `f128` values.
 ///
@@ -4022,9 +4052,19 @@ pub const fn minimumf64(x: f64, y: f64) -> f64;
 /// Therefore, implementations must not require the user to uphold
 /// any safety invariants.
 #[rustc_nounwind]
-#[rustc_intrinsic]
-#[cfg(not(bootstrap))]
-pub const fn minimumf128(x: f128, y: f128) -> f128;
+#[cfg_attr(not(bootstrap), rustc_intrinsic)]
+pub const fn minimumf128(x: f128, y: f128) -> f128 {
+    if x < y {
+        x
+    } else if y < x {
+        y
+    } else if x == y {
+        if x.is_sign_negative() && y.is_sign_positive() { x } else { y }
+    } else {
+        // At least one input is NaN. Use `+` to perform NaN propagation and quieting.
+        x + y
+    }
+}
 
 /// Returns the maximum (IEEE 754-2008 maxNum) of two `f16` values.
 ///
@@ -4087,9 +4127,18 @@ pub const fn maxnumf128(x: f128, y: f128) -> f128;
 /// Therefore, implementations must not require the user to uphold
 /// any safety invariants.
 #[rustc_nounwind]
-#[rustc_intrinsic]
-#[cfg(not(bootstrap))]
-pub const fn maximumf16(x: f16, y: f16) -> f16;
+#[cfg_attr(not(bootstrap), rustc_intrinsic)]
+pub const fn maximumf16(x: f16, y: f16) -> f16 {
+    if x > y {
+        x
+    } else if y > x {
+        y
+    } else if x == y {
+        if x.is_sign_positive() && y.is_sign_negative() { x } else { y }
+    } else {
+        x + y
+    }
+}
 
 /// Returns the maximum (IEEE 754-2019 maximum) of two `f32` values.
 ///
@@ -4098,9 +4147,18 @@ pub const fn maximumf16(x: f16, y: f16) -> f16;
 /// Therefore, implementations must not require the user to uphold
 /// any safety invariants.
 #[rustc_nounwind]
-#[rustc_intrinsic]
-#[cfg(not(bootstrap))]
-pub const fn maximumf32(x: f32, y: f32) -> f32;
+#[cfg_attr(not(bootstrap), rustc_intrinsic)]
+pub const fn maximumf32(x: f32, y: f32) -> f32 {
+    if x > y {
+        x
+    } else if y > x {
+        y
+    } else if x == y {
+        if x.is_sign_positive() && y.is_sign_negative() { x } else { y }
+    } else {
+        x + y
+    }
+}
 
 /// Returns the maximum (IEEE 754-2019 maximum) of two `f64` values.
 ///
@@ -4109,9 +4167,18 @@ pub const fn maximumf32(x: f32, y: f32) -> f32;
 /// Therefore, implementations must not require the user to uphold
 /// any safety invariants.
 #[rustc_nounwind]
-#[rustc_intrinsic]
-#[cfg(not(bootstrap))]
-pub const fn maximumf64(x: f64, y: f64) -> f64;
+#[cfg_attr(not(bootstrap), rustc_intrinsic)]
+pub const fn maximumf64(x: f64, y: f64) -> f64 {
+    if x > y {
+        x
+    } else if y > x {
+        y
+    } else if x == y {
+        if x.is_sign_positive() && y.is_sign_negative() { x } else { y }
+    } else {
+        x + y
+    }
+}
 
 /// Returns the maximum (IEEE 754-2019 maximum) of two `f128` values.
 ///
@@ -4120,9 +4187,18 @@ pub const fn maximumf64(x: f64, y: f64) -> f64;
 /// Therefore, implementations must not require the user to uphold
 /// any safety invariants.
 #[rustc_nounwind]
-#[rustc_intrinsic]
-#[cfg(not(bootstrap))]
-pub const fn maximumf128(x: f128, y: f128) -> f128;
+#[cfg_attr(not(bootstrap), rustc_intrinsic)]
+pub const fn maximumf128(x: f128, y: f128) -> f128 {
+    if x > y {
+        x
+    } else if y > x {
+        y
+    } else if x == y {
+        if x.is_sign_positive() && y.is_sign_negative() { x } else { y }
+    } else {
+        x + y
+    }
+}
 
 /// Returns the absolute value of an `f16`.
 ///
diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs
index 97e24a19ea614..8020b36c6fa6e 100644
--- a/library/core/src/num/f128.rs
+++ b/library/core/src/num/f128.rs
@@ -755,25 +755,9 @@ impl f128 {
     #[inline]
     #[unstable(feature = "f128", issue = "116909")]
     // #[unstable(feature = "float_minimum_maximum", issue = "91079")]
-    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     pub const fn maximum(self, other: f128) -> f128 {
-        #[cfg(not(bootstrap))]
-        {
-            intrinsics::maximumf128(self, other)
-        }
-        #[cfg(bootstrap)]
-        {
-            if self > other {
-                self
-            } else if other > self {
-                other
-            } else if self == other {
-                if self.is_sign_positive() && other.is_sign_negative() { self } else { other }
-            } else {
-                self + other
-            }
-        }
+        intrinsics::maximumf128(self, other)
     }
 
     /// Returns the minimum of the two numbers, propagating NaN.
@@ -804,26 +788,9 @@ impl f128 {
     #[inline]
     #[unstable(feature = "f128", issue = "116909")]
     // #[unstable(feature = "float_minimum_maximum", issue = "91079")]
-    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     pub const fn minimum(self, other: f128) -> f128 {
-        #[cfg(not(bootstrap))]
-        {
-            intrinsics::minimumf128(self, other)
-        }
-        #[cfg(bootstrap)]
-        {
-            if self < other {
-                self
-            } else if other < self {
-                other
-            } else if self == other {
-                if self.is_sign_negative() && other.is_sign_positive() { self } else { other }
-            } else {
-                // At least one input is NaN. Use `+` to perform NaN propagation and quieting.
-                self + other
-            }
-        }
+        intrinsics::minimumf128(self, other)
     }
 
     /// Calculates the midpoint (average) between `self` and `rhs`.
diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs
index d3af78123c84e..68201400a1d5d 100644
--- a/library/core/src/num/f16.rs
+++ b/library/core/src/num/f16.rs
@@ -744,25 +744,9 @@ impl f16 {
     #[inline]
     #[unstable(feature = "f16", issue = "116909")]
     // #[unstable(feature = "float_minimum_maximum", issue = "91079")]
-    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     pub const fn maximum(self, other: f16) -> f16 {
-        #[cfg(not(bootstrap))]
-        {
-            intrinsics::maximumf16(self, other)
-        }
-        #[cfg(bootstrap)]
-        {
-            if self > other {
-                self
-            } else if other > self {
-                other
-            } else if self == other {
-                if self.is_sign_positive() && other.is_sign_negative() { self } else { other }
-            } else {
-                self + other
-            }
-        }
+        intrinsics::maximumf16(self, other)
     }
 
     /// Returns the minimum of the two numbers, propagating NaN.
@@ -792,26 +776,9 @@ impl f16 {
     #[inline]
     #[unstable(feature = "f16", issue = "116909")]
     // #[unstable(feature = "float_minimum_maximum", issue = "91079")]
-    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     pub const fn minimum(self, other: f16) -> f16 {
-        #[cfg(not(bootstrap))]
-        {
-            intrinsics::minimumf16(self, other)
-        }
-        #[cfg(bootstrap)]
-        {
-            if self < other {
-                self
-            } else if other < self {
-                other
-            } else if self == other {
-                if self.is_sign_negative() && other.is_sign_positive() { self } else { other }
-            } else {
-                // At least one input is NaN. Use `+` to perform NaN propagation and quieting.
-                self + other
-            }
-        }
+        intrinsics::minimumf16(self, other)
     }
 
     /// Calculates the midpoint (average) between `self` and `rhs`.
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index 9ee6c3f5f990e..da241785d6427 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -942,25 +942,9 @@ impl f32 {
     /// operand is conserved; see the [specification of NaN bit patterns](f32#nan-bit-patterns) for more info.
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[unstable(feature = "float_minimum_maximum", issue = "91079")]
-    #[rustc_const_unstable(feature = "float_minimum_maximum", issue = "91079")]
     #[inline]
     pub const fn maximum(self, other: f32) -> f32 {
-        #[cfg(not(bootstrap))]
-        {
-            intrinsics::maximumf32(self, other)
-        }
-        #[cfg(bootstrap)]
-        {
-            if self > other {
-                self
-            } else if other > self {
-                other
-            } else if self == other {
-                if self.is_sign_positive() && other.is_sign_negative() { self } else { other }
-            } else {
-                self + other
-            }
-        }
+        intrinsics::maximumf32(self, other)
     }
 
     /// Returns the minimum of the two numbers, propagating NaN.
@@ -985,26 +969,9 @@ impl f32 {
     /// operand is conserved; see the [specification of NaN bit patterns](f32#nan-bit-patterns) for more info.
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[unstable(feature = "float_minimum_maximum", issue = "91079")]
-    #[rustc_const_unstable(feature = "float_minimum_maximum", issue = "91079")]
     #[inline]
     pub const fn minimum(self, other: f32) -> f32 {
-        #[cfg(not(bootstrap))]
-        {
-            intrinsics::minimumf32(self, other)
-        }
-        #[cfg(bootstrap)]
-        {
-            if self < other {
-                self
-            } else if other < self {
-                other
-            } else if self == other {
-                if self.is_sign_negative() && other.is_sign_positive() { self } else { other }
-            } else {
-                // At least one input is NaN. Use `+` to perform NaN propagation and quieting.
-                self + other
-            }
-        }
+        intrinsics::minimumf32(self, other)
     }
 
     /// Calculates the midpoint (average) between `self` and `rhs`.
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index 900b936268a5b..c8544771a9047 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -960,25 +960,9 @@ impl f64 {
     /// operand is conserved; see the [specification of NaN bit patterns](f32#nan-bit-patterns) for more info.
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[unstable(feature = "float_minimum_maximum", issue = "91079")]
-    #[rustc_const_unstable(feature = "float_minimum_maximum", issue = "91079")]
     #[inline]
     pub const fn maximum(self, other: f64) -> f64 {
-        #[cfg(not(bootstrap))]
-        {
-            intrinsics::maximumf64(self, other)
-        }
-        #[cfg(bootstrap)]
-        {
-            if self > other {
-                self
-            } else if other > self {
-                other
-            } else if self == other {
-                if self.is_sign_positive() && other.is_sign_negative() { self } else { other }
-            } else {
-                self + other
-            }
-        }
+        intrinsics::maximumf64(self, other)
     }
 
     /// Returns the minimum of the two numbers, propagating NaN.
@@ -1003,26 +987,9 @@ impl f64 {
     /// operand is conserved; see the [specification of NaN bit patterns](f32#nan-bit-patterns) for more info.
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[unstable(feature = "float_minimum_maximum", issue = "91079")]
-    #[rustc_const_unstable(feature = "float_minimum_maximum", issue = "91079")]
     #[inline]
     pub const fn minimum(self, other: f64) -> f64 {
-        #[cfg(not(bootstrap))]
-        {
-            intrinsics::minimumf64(self, other)
-        }
-        #[cfg(bootstrap)]
-        {
-            if self < other {
-                self
-            } else if other < self {
-                other
-            } else if self == other {
-                if self.is_sign_negative() && other.is_sign_positive() { self } else { other }
-            } else {
-                // At least one input is NaN. Use `+` to perform NaN propagation and quieting.
-                self + other
-            }
-        }
+        intrinsics::minimumf64(self, other)
     }
 
     /// Calculates the midpoint (average) between `self` and `rhs`.

From 3fa98a1507b3ec7586b1c1fbdb51b5b55c71e0ed Mon Sep 17 00:00:00 2001
From: Michael Howell 
Date: Tue, 8 Apr 2025 11:18:08 -0700
Subject: [PATCH 2115/4206] rustdoc: add a handle that makes sidebar resizing
 more obvious

This change is based on some discussion on [lolbinarycat's idea],
but with a more "traditional" design. Specifically, this is the
closest thing I could find to a consensus across many systems I
looked at for inspiration:

- In Jira, resizable sidebars have a stack of four dots.
- In The GIMP, resizable sidebars have a stack of three dots.
- In [old Windows], "panes" are defined to have the same border
  style as a window, which has a raised appearance.
- In [NeXT], a drag point usually had an innie, whether the line in a
  slider or the circle in a scroller; I can also hide and show the
  favorites bar in Workspace by dragging on a circular "grip spot"
- In [old Mac], drag handles for things usually had a "grip track"
  of parallel lines.
- [OSX] kept that, but the "Source List" part of the Finder still had
  the circle grip for a time the same way Workspace did

[lolbinarycat's idea]: https://github.com/rust-lang/rust/pull/139420
[old Windows]: https://archive.org/details/windowsinterface00micr/page/n9/mode/2up
[old Mac]: https://archive.org/details/apple-hig/1996_Human_Interface_Guidelines_for_Mac_OS_8_%28WWDC_Release%29/page/16/mode/2up
[NeXT]: https://archive.org/details/apple-hig/1993%20NeXTSTEP%20User%20Interface%20Guidelines%20-%20Release%203/page/145/mode/2up
[OSX]: https://dn721903.ca.archive.org/0/items/apple-hig/MacOSX_HIG_2005_09_08.pdf#page=267
---
 src/librustdoc/html/static/css/noscript.css   |  6 +++
 src/librustdoc/html/static/css/rustdoc.css    | 54 ++++++++++++++++---
 .../sidebar-resize-close-popover.goml         |  4 +-
 tests/rustdoc-gui/sidebar-resize-setting.goml |  2 +-
 tests/rustdoc-gui/sidebar-resize.goml         |  6 +--
 tests/rustdoc-gui/sidebar.goml                | 18 +++----
 6 files changed, 68 insertions(+), 22 deletions(-)

diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css
index 477a79d63e948..03201336cde85 100644
--- a/src/librustdoc/html/static/css/noscript.css
+++ b/src/librustdoc/html/static/css/noscript.css
@@ -43,6 +43,7 @@ nav.sub {
 	--settings-button-border-focus: #717171;
 	--sidebar-background-color: #f5f5f5;
 	--sidebar-background-color-hover: #e0e0e0;
+	--sidebar-border-color: #ddd;
 	--code-block-background-color: #f5f5f5;
 	--scrollbar-track-background-color: #dcdcdc;
 	--scrollbar-thumb-background-color: rgba(36, 37, 39, 0.6);
@@ -135,6 +136,8 @@ nav.sub {
 	--scrape-example-code-wrapper-background-end: rgba(255, 255, 255, 0);
 	--sidebar-resizer-hover: hsl(207, 90%, 66%);
 	--sidebar-resizer-active: hsl(207, 90%, 54%);
+	--sidebar-resizer-img-filter: opacity(66%);
+	--sidebar-resizer-img-hover-filter: none;
 }
 /* End theme: light */
 
@@ -149,6 +152,7 @@ nav.sub {
 		--settings-button-border-focus: #ffb900;
 		--sidebar-background-color: #505050;
 		--sidebar-background-color-hover: #676767;
+		--sidebar-border-color: #2A2A2A;
 		--code-block-background-color: #2A2A2A;
 		--scrollbar-track-background-color: #717171;
 		--scrollbar-thumb-background-color: rgba(32, 34, 37, .6);
@@ -244,6 +248,8 @@ nav.sub {
 		--scrape-example-code-wrapper-background-end: rgba(53, 53, 53, 0);
 		--sidebar-resizer-hover: hsl(207, 30%, 54%);
 		--sidebar-resizer-active: hsl(207, 90%, 54%);
+		--sidebar-resizer-img-filter: opacity(66%);
+		--sidebar-resizer-img-hover-filter: none;
 	}
 /* End theme: dark */
 }
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index f838f3f1106fd..a874b87dfe1f8 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -1,4 +1,6 @@
-/* When static files are updated, their suffixes need to be updated.
+/*
+// ignore-tidy-filelength
+	When static files are updated, their suffixes need to be updated.
 	1. In the top directory run:
 		./x.py doc --stage 1 library/core
 	2. Find the directory containing files named with updated suffixes:
@@ -496,12 +498,13 @@ img {
 	top: 0;
 	left: 0;
 	z-index: var(--desktop-sidebar-z-index);
+	/* resize indicator: hide this when on touch or mobile */
+	border-right: solid 1px var(--sidebar-border-color);
 }
 
 .rustdoc.src .sidebar {
 	flex-basis: 50px;
 	width: 50px;
-	border-right: 1px solid;
 	overflow-x: hidden;
 	/* The sidebar is by default hidden  */
 	overflow-y: hidden;
@@ -515,12 +518,32 @@ img {
 .sidebar-resizer {
 	touch-action: none;
 	width: 9px;
-	cursor: col-resize;
+	cursor: ew-resize;
 	z-index: calc(var(--desktop-sidebar-z-index) + 1);
 	position: fixed;
 	height: 100%;
-	/* make sure there's a 1px gap between the scrollbar and resize handle */
-	left: calc(var(--desktop-sidebar-width) + 1px);
+	left: var(--desktop-sidebar-width);
+	display: flex;
+	align-items: center;
+	justify-content: center;
+}
+
+.sidebar-resizer::after {
+	content: url('data:image/svg+xml,\
+		 \
+		 \
+		 \
+		 \
+		 \
+		 \
+		 \
+		');
+	width: 8px;
+	height: 24px;
+	filter: var(--sidebar-resizer-img-filter);
+}
+.sidebar-resizer:hover::after {
+	filter: var(--sidebar-resizer-img-hover-filter);
 }
 
 .rustdoc.src .sidebar-resizer {
@@ -543,7 +566,7 @@ img {
 }
 
 .sidebar-resizing * {
-	cursor: col-resize !important;
+	cursor: ew-resize !important;
 }
 
 .sidebar-resizing .sidebar {
@@ -561,7 +584,7 @@ img {
 	margin: 0;
 	/* when active or hovered, place resizer glow on top of the sidebar (right next to, or even
 	   on top of, the scrollbar) */
-	left: var(--desktop-sidebar-width);
+	left: calc(var(--desktop-sidebar-width) - 1px);
 	border-left: solid 1px var(--sidebar-resizer-hover);
 }
 
@@ -578,6 +601,10 @@ img {
 		/* too easy to hit the resizer while trying to hit the [-] toggle */
 		display: none !important;
 	}
+	.sidebar {
+		/* resize indicator: hide this when on touch or mobile */
+		border-right: none;
+	}
 }
 
 .sidebar-resizer.active {
@@ -590,6 +617,8 @@ img {
 }
 .sidebar-resizer.active::before {
 	border-left: solid 2px var(--sidebar-resizer-active);
+	margin-left: 8px;
+	padding-left: 1px;
 	display: block;
 	height: 100%;
 	content: "";
@@ -2509,6 +2538,8 @@ in src-script.js and main.js
 		/* Reduce height slightly to account for mobile topbar. */
 		height: calc(100vh - 45px);
 		width: 200px;
+		/* resize indicator: hide this when on touch or mobile */
+		border-right: none;
 	}
 
 	/* The source view uses a different design for the sidebar toggle, and doesn't have a topbar,
@@ -2897,6 +2928,7 @@ by default.
 	--settings-button-border-focus: #717171;
 	--sidebar-background-color: #f5f5f5;
 	--sidebar-background-color-hover: #e0e0e0;
+	--sidebar-border-color: #ddd;
 	--code-block-background-color: #f5f5f5;
 	--scrollbar-track-background-color: #dcdcdc;
 	--scrollbar-thumb-background-color: rgba(36, 37, 39, 0.6);
@@ -2989,6 +3021,8 @@ by default.
 	--scrape-example-code-wrapper-background-end: rgba(255, 255, 255, 0);
 	--sidebar-resizer-hover: hsl(207, 90%, 66%);
 	--sidebar-resizer-active: hsl(207, 90%, 54%);
+	--sidebar-resizer-img-filter: opacity(66%);
+	--sidebar-resizer-img-hover-filter: none;
 }
 /* End theme: light */
 
@@ -3002,6 +3036,7 @@ by default.
 	--settings-button-border-focus: #ffb900;
 	--sidebar-background-color: #505050;
 	--sidebar-background-color-hover: #676767;
+	--sidebar-border-color: #2A2A2A;
 	--code-block-background-color: #2A2A2A;
 	--scrollbar-track-background-color: #717171;
 	--scrollbar-thumb-background-color: rgba(32, 34, 37, .6);
@@ -3097,6 +3132,8 @@ by default.
 	--scrape-example-code-wrapper-background-end: rgba(53, 53, 53, 0);
 	--sidebar-resizer-hover: hsl(207, 30%, 54%);
 	--sidebar-resizer-active: hsl(207, 90%, 54%);
+	--sidebar-resizer-img-filter: opacity(66%);
+	--sidebar-resizer-img-hover-filter: none;
 }
 /* End theme: dark */
 
@@ -3114,6 +3151,7 @@ Original by Dempfi (https://github.com/dempfi/ayu)
 	--settings-button-border-focus: #e0e0e0;
 	--sidebar-background-color: #14191f;
 	--sidebar-background-color-hover: rgba(70, 70, 70, 0.33);
+	--sidebar-border-color: #000;
 	--code-block-background-color: #191f26;
 	--scrollbar-track-background-color: transparent;
 	--scrollbar-thumb-background-color: #5c6773;
@@ -3209,6 +3247,8 @@ Original by Dempfi (https://github.com/dempfi/ayu)
 	--scrape-example-code-wrapper-background-end: rgba(15, 20, 25, 0);
 	--sidebar-resizer-hover: hsl(34, 50%, 33%);
 	--sidebar-resizer-active: hsl(34, 100%, 66%);
+	--sidebar-resizer-img-filter: opacity(66%);
+	--sidebar-resizer-img-hover-filter: none;
 }
 
 :root[data-theme="ayu"] h1,
diff --git a/tests/rustdoc-gui/sidebar-resize-close-popover.goml b/tests/rustdoc-gui/sidebar-resize-close-popover.goml
index 2a8fbac855e97..2d26caf1a39ef 100644
--- a/tests/rustdoc-gui/sidebar-resize-close-popover.goml
+++ b/tests/rustdoc-gui/sidebar-resize-close-popover.goml
@@ -1,13 +1,13 @@
 // Checks sidebar resizing close the Settings popover
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-assert-property: (".sidebar", {"clientWidth": "200"})
+assert-property: (".sidebar", {"clientWidth": "199"})
 show-text: true
 click: "#settings-menu"
 wait-for: "#settings"
 assert-css: ("#settings", {"display": "block"})
 // normal resizing
 drag-and-drop: ((205, 100), (185, 100))
-assert-property: (".sidebar", {"clientWidth": "182"})
+assert-property: (".sidebar", {"clientWidth": "181"})
 assert-css: ("#settings", {"display": "none"})
 
 // Now same thing, but for source code
diff --git a/tests/rustdoc-gui/sidebar-resize-setting.goml b/tests/rustdoc-gui/sidebar-resize-setting.goml
index 32471f9db4e26..e346fe6aeac0b 100644
--- a/tests/rustdoc-gui/sidebar-resize-setting.goml
+++ b/tests/rustdoc-gui/sidebar-resize-setting.goml
@@ -1,6 +1,6 @@
 // Checks sidebar resizing stays synced with the setting
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-assert-property: (".sidebar", {"clientWidth": "200"})
+assert-property: (".sidebar", {"clientWidth": "199"})
 show-text: true
 
 // Verify that the "hide" option is unchecked
diff --git a/tests/rustdoc-gui/sidebar-resize.goml b/tests/rustdoc-gui/sidebar-resize.goml
index 543d5d390c720..64b0a23757ac3 100644
--- a/tests/rustdoc-gui/sidebar-resize.goml
+++ b/tests/rustdoc-gui/sidebar-resize.goml
@@ -1,13 +1,13 @@
 // Checks sidebar resizing
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-assert-property: (".sidebar", {"clientWidth": "200"})
+assert-property: (".sidebar", {"clientWidth": "199"})
 show-text: true
 // normal resizing
 drag-and-drop: ((205, 100), (185, 100))
-assert-property: (".sidebar", {"clientWidth": "182"})
+assert-property: (".sidebar", {"clientWidth": "181"})
 // resize past maximum (don't grow past 500)
 drag-and-drop: ((185, 100), (600, 100))
-assert-property: (".sidebar", {"clientWidth": "500"})
+assert-property: (".sidebar", {"clientWidth": "499"})
 // resize past minimum (hide sidebar)
 drag-and-drop: ((501, 100), (5, 100))
 assert-property: (".sidebar", {"clientWidth": "0"})
diff --git a/tests/rustdoc-gui/sidebar.goml b/tests/rustdoc-gui/sidebar.goml
index 9c66b84165f88..c0fe240e2bed2 100644
--- a/tests/rustdoc-gui/sidebar.goml
+++ b/tests/rustdoc-gui/sidebar.goml
@@ -1,7 +1,7 @@
 // Checks multiple things on the sidebar display (width of its elements, colors, etc).
 include: "utils.goml"
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-assert-property: (".sidebar", {"clientWidth": "200"})
+assert-property: (".sidebar", {"clientWidth": "199"})
 show-text: true
 
 // First, check the sidebar colors.
@@ -84,13 +84,13 @@ assert-property: ("html", {"scrollTop": "0"})
 
 // We now go back to the crate page to click on the "lib2" crate link.
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-assert-property: (".sidebar", {"clientWidth": "200"})
+assert-property: (".sidebar", {"clientWidth": "199"})
 assert-css: (".sidebar-elems ul.crate > li:first-child > a", {"color": "#356da4"})
 click: ".sidebar-elems ul.crate > li:first-child > a"
 
 // PAGE: lib2/index.html
 go-to: "file://" + |DOC_PATH| + "/lib2/index.html"
-assert-property: (".sidebar", {"clientWidth": "200"})
+assert-property: (".sidebar", {"clientWidth": "199"})
 assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2")
 assert-count: (".sidebar .location", 0)
 // We check that we have the crates list and that the "current" on is now "lib2".
@@ -116,7 +116,7 @@ assert-text: (".sidebar-elems ul.block > li.current > a", "foobar")
 assert-false: ".sidebar-elems > .crate"
 
 go-to: "./module/index.html"
-assert-property: (".sidebar", {"clientWidth": "200"})
+assert-property: (".sidebar", {"clientWidth": "199"})
 assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2")
 assert-text: (".sidebar .location", "Module module")
 assert-count: (".sidebar .location", 1)
@@ -134,7 +134,7 @@ assert-property: (".sidebar > .sidebar-elems > #rustdoc-modnav > h2 > a", {
 assert-false: ".sidebar-elems > .crate"
 
 go-to: "./sub_module/sub_sub_module/index.html"
-assert-property: (".sidebar", {"clientWidth": "200"})
+assert-property: (".sidebar", {"clientWidth": "199"})
 assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2")
 assert-text: (".sidebar .location", "Module sub_sub_module")
 assert-text: (".sidebar > .sidebar-elems > #rustdoc-modnav > h2", "In lib2::module::sub_module")
@@ -149,13 +149,13 @@ assert-text: ("#functions + .item-table dt > a", "foo")
 
 // Links to trait implementations in the sidebar should not wrap even if they are long.
 go-to: "file://" + |DOC_PATH| + "/lib2/struct.HasALongTraitWithParams.html"
-assert-property: (".sidebar", {"clientWidth": "200"})
+assert-property: (".sidebar", {"clientWidth": "199"})
 assert-property: (".sidebar-elems section .block li > a", {"offsetHeight": 29})
 
 // Test that clicking on of the "In " headings in the sidebar links to the
 // appropriate anchor in index.html.
 go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
-assert-property: (".sidebar", {"clientWidth": "200"})
+assert-property: (".sidebar", {"clientWidth": "199"})
 click: "//ul[@class='block mod']/preceding-sibling::h3/a"
 // PAGE: index.html
 assert-css: ("#modules", {"background-color": "#fdffd3"})
@@ -163,10 +163,10 @@ assert-css: ("#modules", {"background-color": "#fdffd3"})
 // Finally, assert that the Summary toggle doesn't affect sidebar width.
 click: "#toggle-all-docs"
 assert-text: ("#toggle-all-docs", "Show all")
-assert-property: (".sidebar", {"clientWidth": "200"})
+assert-property: (".sidebar", {"clientWidth": "199"})
 click: "#toggle-all-docs"
 assert-text: ("#toggle-all-docs", "Summary")
-assert-property: (".sidebar", {"clientWidth": "200"})
+assert-property: (".sidebar", {"clientWidth": "199"})
 
 // Checks that all.html and index.html have their sidebar link in the same place.
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"

From 3c9e1f97b5e1a8c55adf7968194b9ce69c4c125a Mon Sep 17 00:00:00 2001
From: Michael Howell 
Date: Tue, 8 Apr 2025 18:01:23 -0700
Subject: [PATCH 2116/4206] rustdoc: add tooltip to resize track

---
 src/librustdoc/html/templates/page.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index 5ef376f4acbc9..7af99e7097c37 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -114,7 +114,7 @@ 

Files

{# #} {% endif %} {{ sidebar|safe }} {# #} - {# #} + {# #}
{% if page.css_class != "src" %}
{% endif %} {# defined in storage.js to avoid duplicating complex UI across every page #} From e6e52063dfb23a16a0217689613e83888b18ccf9 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 10 Apr 2025 21:44:35 -0700 Subject: [PATCH 2117/4206] rustdoc: use a different style of grip track --- src/librustdoc/html/static/css/noscript.css | 4 -- src/librustdoc/html/static/css/rustdoc.css | 54 ++++++++------------- 2 files changed, 19 insertions(+), 39 deletions(-) diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css index 03201336cde85..a3c6bf9816169 100644 --- a/src/librustdoc/html/static/css/noscript.css +++ b/src/librustdoc/html/static/css/noscript.css @@ -136,8 +136,6 @@ nav.sub { --scrape-example-code-wrapper-background-end: rgba(255, 255, 255, 0); --sidebar-resizer-hover: hsl(207, 90%, 66%); --sidebar-resizer-active: hsl(207, 90%, 54%); - --sidebar-resizer-img-filter: opacity(66%); - --sidebar-resizer-img-hover-filter: none; } /* End theme: light */ @@ -248,8 +246,6 @@ nav.sub { --scrape-example-code-wrapper-background-end: rgba(53, 53, 53, 0); --sidebar-resizer-hover: hsl(207, 30%, 54%); --sidebar-resizer-active: hsl(207, 90%, 54%); - --sidebar-resizer-img-filter: opacity(66%); - --sidebar-resizer-img-hover-filter: none; } /* End theme: dark */ } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index a874b87dfe1f8..a81d5c9c49b4b 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1,5 +1,5 @@ +/* ignore-tidy-filelength */ /* -// ignore-tidy-filelength When static files are updated, their suffixes need to be updated. 1. In the top directory run: ./x.py doc --stage 1 library/core @@ -525,25 +525,20 @@ img { left: var(--desktop-sidebar-width); display: flex; align-items: center; - justify-content: center; + justify-content: flex-start; + color: var(--right-side-color); } - -.sidebar-resizer::after { - content: url('data:image/svg+xml,\ - \ - \ - \ - \ - \ - \ - \ - '); - width: 8px; - height: 24px; - filter: var(--sidebar-resizer-img-filter); +.sidebar-resizer::before { + content: ""; + border-right: dotted 2px currentColor; + width: 2px; + height: 12px; } -.sidebar-resizer:hover::after { - filter: var(--sidebar-resizer-img-hover-filter); +.sidebar-resizer::after { + content: ""; + border-right: dotted 2px currentColor; + width: 2px; + height: 16px; } .rustdoc.src .sidebar-resizer { @@ -571,6 +566,7 @@ img { .sidebar-resizing .sidebar { position: fixed; + border-right: solid 2px var(--sidebar-resizer-active); } .sidebar-resizing > body { padding-left: var(--resizing-sidebar-width); @@ -586,6 +582,7 @@ img { on top of, the scrollbar) */ left: calc(var(--desktop-sidebar-width) - 1px); border-left: solid 1px var(--sidebar-resizer-hover); + color: var(--sidebar-resizer-hover); } .src-sidebar-expanded .rustdoc.src .sidebar-resizer:hover, @@ -611,17 +608,10 @@ img { /* make the resize tool bigger when actually resizing, to avoid :hover styles on other stuff while resizing */ padding: 0 140px; - width: 2px; + width: calc(140px + 140px + 9px + 2px); margin-left: -140px; border-left: none; -} -.sidebar-resizer.active::before { - border-left: solid 2px var(--sidebar-resizer-active); - margin-left: 8px; - padding-left: 1px; - display: block; - height: 100%; - content: ""; + color: var(--sidebar-resizer-active); } .sidebar, .mobile-topbar, .sidebar-menu-toggle, @@ -3021,8 +3011,6 @@ by default. --scrape-example-code-wrapper-background-end: rgba(255, 255, 255, 0); --sidebar-resizer-hover: hsl(207, 90%, 66%); --sidebar-resizer-active: hsl(207, 90%, 54%); - --sidebar-resizer-img-filter: opacity(66%); - --sidebar-resizer-img-hover-filter: none; } /* End theme: light */ @@ -3036,7 +3024,7 @@ by default. --settings-button-border-focus: #ffb900; --sidebar-background-color: #505050; --sidebar-background-color-hover: #676767; - --sidebar-border-color: #2A2A2A; + --sidebar-border-color: #999; --code-block-background-color: #2A2A2A; --scrollbar-track-background-color: #717171; --scrollbar-thumb-background-color: rgba(32, 34, 37, .6); @@ -3132,8 +3120,6 @@ by default. --scrape-example-code-wrapper-background-end: rgba(53, 53, 53, 0); --sidebar-resizer-hover: hsl(207, 30%, 54%); --sidebar-resizer-active: hsl(207, 90%, 54%); - --sidebar-resizer-img-filter: opacity(66%); - --sidebar-resizer-img-hover-filter: none; } /* End theme: dark */ @@ -3151,7 +3137,7 @@ Original by Dempfi (https://github.com/dempfi/ayu) --settings-button-border-focus: #e0e0e0; --sidebar-background-color: #14191f; --sidebar-background-color-hover: rgba(70, 70, 70, 0.33); - --sidebar-border-color: #000; + --sidebar-border-color: #5c6773; --code-block-background-color: #191f26; --scrollbar-track-background-color: transparent; --scrollbar-thumb-background-color: #5c6773; @@ -3247,8 +3233,6 @@ Original by Dempfi (https://github.com/dempfi/ayu) --scrape-example-code-wrapper-background-end: rgba(15, 20, 25, 0); --sidebar-resizer-hover: hsl(34, 50%, 33%); --sidebar-resizer-active: hsl(34, 100%, 66%); - --sidebar-resizer-img-filter: opacity(66%); - --sidebar-resizer-img-hover-filter: none; } :root[data-theme="ayu"] h1, From 684b7b70f4940a0abfecd3d95fe339960d6048d4 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Fri, 9 May 2025 23:16:55 +0200 Subject: [PATCH 2118/4206] don't depend on rustc_attr_parsing if rustc_data_structures will do --- Cargo.lock | 16 ++++++------- compiler/rustc_codegen_llvm/Cargo.toml | 2 +- compiler/rustc_codegen_llvm/src/attributes.rs | 2 +- compiler/rustc_codegen_llvm/src/callee.rs | 2 +- compiler/rustc_const_eval/Cargo.toml | 2 +- .../src/check_consts/check.rs | 17 +++++++------ .../rustc_const_eval/src/check_consts/mod.rs | 5 ++-- compiler/rustc_hir_analysis/Cargo.toml | 2 +- .../rustc_hir_analysis/src/check/check.rs | 11 ++++----- compiler/rustc_hir_typeck/Cargo.toml | 2 +- compiler/rustc_hir_typeck/src/coercion.rs | 2 +- .../rustc_hir_typeck/src/method/suggest.rs | 2 +- compiler/rustc_mir_transform/Cargo.toml | 2 +- .../rustc_mir_transform/src/check_inline.rs | 2 +- .../src/cross_crate_inline.rs | 2 +- compiler/rustc_mir_transform/src/inline.rs | 2 +- compiler/rustc_mir_transform/src/validate.rs | 2 +- compiler/rustc_monomorphize/Cargo.toml | 2 +- compiler/rustc_monomorphize/src/collector.rs | 2 +- .../rustc_monomorphize/src/partitioning.rs | 7 +++--- compiler/rustc_passes/Cargo.toml | 2 +- compiler/rustc_passes/src/check_attr.rs | 2 +- compiler/rustc_passes/src/lib_features.rs | 2 +- compiler/rustc_passes/src/stability.rs | 24 +++++++++---------- compiler/rustc_privacy/Cargo.toml | 2 +- compiler/rustc_privacy/src/lib.rs | 5 ++-- 26 files changed, 61 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fa0fa33ea75ac..e3ef0189c1205 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3410,7 +3410,7 @@ dependencies = [ "rustc-demangle", "rustc_abi", "rustc_ast", - "rustc_attr_parsing", + "rustc_attr_data_structures", "rustc_codegen_ssa", "rustc_data_structures", "rustc_errors", @@ -3490,7 +3490,7 @@ dependencies = [ "rustc_abi", "rustc_apfloat", "rustc_ast", - "rustc_attr_parsing", + "rustc_attr_data_structures", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", @@ -3754,7 +3754,7 @@ dependencies = [ "rustc_abi", "rustc_arena", "rustc_ast", - "rustc_attr_parsing", + "rustc_attr_data_structures", "rustc_data_structures", "rustc_errors", "rustc_feature", @@ -3791,7 +3791,7 @@ dependencies = [ "itertools", "rustc_abi", "rustc_ast", - "rustc_attr_parsing", + "rustc_attr_data_structures", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", @@ -4122,7 +4122,7 @@ dependencies = [ "rustc_abi", "rustc_arena", "rustc_ast", - "rustc_attr_parsing", + "rustc_attr_data_structures", "rustc_const_eval", "rustc_data_structures", "rustc_errors", @@ -4148,7 +4148,7 @@ version = "0.0.0" dependencies = [ "rustc_abi", "rustc_ast", - "rustc_attr_parsing", + "rustc_attr_data_structures", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", @@ -4218,7 +4218,7 @@ dependencies = [ "rustc_ast", "rustc_ast_lowering", "rustc_ast_pretty", - "rustc_attr_parsing", + "rustc_attr_data_structures", "rustc_data_structures", "rustc_errors", "rustc_expand", @@ -4264,7 +4264,7 @@ name = "rustc_privacy" version = "0.0.0" dependencies = [ "rustc_ast", - "rustc_attr_parsing", + "rustc_attr_data_structures", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 3185993c20767..bf8ec8c3b9158 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -19,7 +19,7 @@ object = { version = "0.36.3", default-features = false, features = ["std", "rea rustc-demangle = "0.1.21" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_parsing = { path = "../rustc_attr_parsing" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 176fb72dfdc5e..443c2eace554d 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -1,5 +1,5 @@ //! Set and unset common attributes on LLVM values. -use rustc_attr_parsing::{InlineAttr, InstructionSetAttr, OptimizeAttr}; +use rustc_attr_data_structures::{InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_codegen_ssa::traits::*; use rustc_hir::def_id::DefId; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFunctionEntry}; diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index ea9ab5c02bd6c..6d68eca60afc1 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -103,7 +103,7 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t // This is a monomorphization of a generic function. if !(cx.tcx.sess.opts.share_generics() || tcx.codegen_fn_attrs(instance_def_id).inline - == rustc_attr_parsing::InlineAttr::Never) + == rustc_attr_data_structures::InlineAttr::Never) { // When not sharing generics, all instances are in the same // crate and have hidden visibility. diff --git a/compiler/rustc_const_eval/Cargo.toml b/compiler/rustc_const_eval/Cargo.toml index 02be8762d6f85..93d0d5b9a71e6 100644 --- a/compiler/rustc_const_eval/Cargo.toml +++ b/compiler/rustc_const_eval/Cargo.toml @@ -9,7 +9,7 @@ either = "1" rustc_abi = { path = "../rustc_abi" } rustc_apfloat = "0.2.0" rustc_ast = { path = "../rustc_ast" } -rustc_attr_parsing = { path = "../rustc_attr_parsing" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index b600b8918dd01..b67a3ce03a945 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -6,7 +6,7 @@ use std::mem; use std::num::NonZero; use std::ops::Deref; -use rustc_attr_parsing::{ConstStability, StabilityLevel}; +use rustc_attr_data_structures as attrs; use rustc_errors::{Diag, ErrorGuaranteed}; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; @@ -475,7 +475,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { /// Check the const stability of the given item (fn or trait). fn check_callee_stability(&mut self, def_id: DefId) { match self.tcx.lookup_const_stability(def_id) { - Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => { + Some(attrs::ConstStability { level: attrs::StabilityLevel::Stable { .. }, .. }) => { // All good. } None => { @@ -491,8 +491,8 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { }); } } - Some(ConstStability { - level: StabilityLevel::Unstable { implied_by: implied_feature, issue, .. }, + Some(attrs::ConstStability { + level: attrs::StabilityLevel::Unstable { implied_by: implied_feature, issue, .. }, feature, .. }) => { @@ -918,8 +918,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { }); } } - Some(ConstStability { - level: StabilityLevel::Unstable { .. }, + Some(attrs::ConstStability { + level: attrs::StabilityLevel::Unstable { .. }, feature, .. }) => { @@ -930,7 +930,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { suggestion: self.crate_inject_span(), }); } - Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => { + Some(attrs::ConstStability { + level: attrs::StabilityLevel::Stable { .. }, + .. + }) => { // All good. Note that a `#[rustc_const_stable]` intrinsic (meaning it // can be *directly* invoked from stable const code) does not always // have the `#[rustc_intrinsic_const_stable_indirect]` attribute (which controls diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs index 06ee7075170ff..d84214152255c 100644 --- a/compiler/rustc_const_eval/src/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/check_consts/mod.rs @@ -4,13 +4,12 @@ //! has interior mutability or needs to be dropped, as well as the visitor that emits errors when //! it finds operations that are invalid in a certain context. -use rustc_attr_parsing::{AttributeKind, find_attr}; use rustc_errors::DiagCtxtHandle; -use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::{self, PolyFnSig, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_span::Symbol; +use {rustc_attr_data_structures as attrs, rustc_hir as hir}; pub use self::qualifs::Qualif; @@ -83,7 +82,7 @@ pub fn rustc_allow_const_fn_unstable( ) -> bool { let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); - find_attr!(attrs, AttributeKind::AllowConstFnUnstable(syms) if syms.contains(&feature_gate)) + attrs::find_attr!(attrs, attrs::AttributeKind::AllowConstFnUnstable(syms) if syms.contains(&feature_gate)) } /// Returns `true` if the given `def_id` (trait or function) is "safe to expose on stable". diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index 58213c4f4e462..f2b82c679b933 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -13,7 +13,7 @@ itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_parsing = { path = "../rustc_attr_parsing" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index f92b2aea160a1..17628de2e8dbb 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -2,8 +2,7 @@ use std::cell::LazyCell; use std::ops::ControlFlow; use rustc_abi::FieldIdx; -use rustc_attr_parsing::AttributeKind; -use rustc_attr_parsing::ReprAttr::ReprPacked; +use rustc_attr_data_structures::ReprAttr::ReprPacked; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::MultiSpan; use rustc_errors::codes::*; @@ -31,7 +30,7 @@ use rustc_trait_selection::traits; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use tracing::{debug, instrument}; use ty::TypingMode; -use {rustc_attr_parsing as attr, rustc_hir as hir}; +use {rustc_attr_data_structures as attrs, rustc_hir as hir}; use super::compare_impl_item::check_type_bounds; use super::*; @@ -1154,7 +1153,7 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { let repr = def.repr(); if repr.packed() { if let Some(reprs) = - attr::find_attr!(tcx.get_all_attrs(def.did()), AttributeKind::Repr(r) => r) + attrs::find_attr!(tcx.get_all_attrs(def.did()), attrs::AttributeKind::Repr(r) => r) { for (r, _) in reprs { if let ReprPacked(pack) = r @@ -1371,9 +1370,9 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) { def.destructor(tcx); // force the destructor to be evaluated if def.variants().is_empty() { - attr::find_attr!( + attrs::find_attr!( tcx.get_all_attrs(def_id), - AttributeKind::Repr(rs) => { + attrs::AttributeKind::Repr(rs) => { struct_span_code_err!( tcx.dcx(), rs.first().unwrap().1, diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml index f00125c3e090a..40fb2d6a106fa 100644 --- a/compiler/rustc_hir_typeck/Cargo.toml +++ b/compiler/rustc_hir_typeck/Cargo.toml @@ -8,7 +8,7 @@ edition = "2024" itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_parsing = { path = "../rustc_attr_parsing" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index fd899425f62d2..d2fc5ae05434a 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -37,7 +37,7 @@ use std::ops::Deref; -use rustc_attr_parsing::InlineAttr; +use rustc_attr_data_structures::InlineAttr; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, struct_span_code_err}; use rustc_hir as hir; diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 6a9fd7cdd483b..342eed751a589 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -9,7 +9,7 @@ use std::path::PathBuf; use hir::Expr; use rustc_ast::ast::Mutability; -use rustc_attr_parsing::{AttributeKind, find_attr}; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::unord::UnordSet; diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml index 9e4b4534dcc54..a7d0b3acbe494 100644 --- a/compiler/rustc_mir_transform/Cargo.toml +++ b/compiler/rustc_mir_transform/Cargo.toml @@ -10,7 +10,7 @@ itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_parsing = { path = "../rustc_attr_parsing" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_const_eval = { path = "../rustc_const_eval" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_mir_transform/src/check_inline.rs b/compiler/rustc_mir_transform/src/check_inline.rs index 83c3cda5a5059..14d9532894fd4 100644 --- a/compiler/rustc_mir_transform/src/check_inline.rs +++ b/compiler/rustc_mir_transform/src/check_inline.rs @@ -1,7 +1,7 @@ //! Check that a body annotated with `#[rustc_force_inline]` will not fail to inline based on its //! definition alone (irrespective of any specific caller). -use rustc_attr_parsing::InlineAttr; +use rustc_attr_data_structures::InlineAttr; use rustc_hir::def_id::DefId; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::{Body, TerminatorKind}; diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs index 4f45d9588a890..727d4a126d21e 100644 --- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs +++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs @@ -1,4 +1,4 @@ -use rustc_attr_parsing::InlineAttr; +use rustc_attr_data_structures::InlineAttr; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_middle::mir::visit::Visitor; diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 9785c039d539b..f48dba9663a52 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -5,7 +5,7 @@ use std::iter; use std::ops::{Range, RangeFrom}; use rustc_abi::{ExternAbi, FieldIdx}; -use rustc_attr_parsing::{InlineAttr, OptimizeAttr}; +use rustc_attr_data_structures::{InlineAttr, OptimizeAttr}; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_index::Idx; diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index f541a32cd2645..f1e8ac01afd69 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1,7 +1,7 @@ //! Validates the MIR to ensure that invariants are upheld. use rustc_abi::{ExternAbi, FIRST_VARIANT, Size}; -use rustc_attr_parsing::InlineAttr; +use rustc_attr_data_structures::InlineAttr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::LangItem; use rustc_index::IndexVec; diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml index 36b76d261de68..063fc8f1c7494 100644 --- a/compiler/rustc_monomorphize/Cargo.toml +++ b/compiler/rustc_monomorphize/Cargo.toml @@ -7,7 +7,7 @@ edition = "2024" # tidy-alphabetical-start rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_parsing = { path = "../rustc_attr_parsing" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index c6a81e60b2b52..b3d7eaf332b25 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -208,7 +208,7 @@ use std::cell::OnceCell; use std::path::PathBuf; -use rustc_attr_parsing::InlineAttr; +use rustc_attr_data_structures::InlineAttr; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::{MTLock, par_for_each_in}; use rustc_data_structures::unord::{UnordMap, UnordSet}; diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 6948dceddf904..48575619e84d1 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -100,6 +100,7 @@ use std::fs::{self, File}; use std::io::Write; use std::path::{Path, PathBuf}; +use rustc_attr_data_structures::InlineAttr; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sync; use rustc_data_structures::unord::{UnordMap, UnordSet}; @@ -845,8 +846,7 @@ fn mono_item_visibility<'tcx>( return if is_generic && (always_export_generics || (can_export_generics - && tcx.codegen_fn_attrs(def_id).inline - == rustc_attr_parsing::InlineAttr::Never)) + && tcx.codegen_fn_attrs(def_id).inline == InlineAttr::Never)) { // If it is an upstream monomorphization and we export generics, we must make // it available to downstream crates. @@ -859,8 +859,7 @@ fn mono_item_visibility<'tcx>( if is_generic { if always_export_generics - || (can_export_generics - && tcx.codegen_fn_attrs(def_id).inline == rustc_attr_parsing::InlineAttr::Never) + || (can_export_generics && tcx.codegen_fn_attrs(def_id).inline == InlineAttr::Never) { if tcx.is_unreachable_local_definition(def_id) { // This instance cannot be used from another crate. diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml index ba81ef3103bd9..b91674890765a 100644 --- a/compiler/rustc_passes/Cargo.toml +++ b/compiler/rustc_passes/Cargo.toml @@ -9,7 +9,7 @@ rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_lowering = { path = "../rustc_ast_lowering" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } -rustc_attr_parsing = { path = "../rustc_attr_parsing" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_expand = { path = "../rustc_expand" } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c68f8df49fc70..5c0d0cf47969a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -10,7 +10,7 @@ use std::collections::hash_map::Entry; use rustc_abi::{Align, ExternAbi, Size}; use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast}; -use rustc_attr_parsing::{AttributeKind, ReprAttr, find_attr}; +use rustc_attr_data_structures::{AttributeKind, ReprAttr, find_attr}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index 7353c1ead5a78..b3e6ee9512c85 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -4,7 +4,7 @@ //! but are not declared in one single location (unlike lang features), which means we need to //! collect them instead. -use rustc_attr_parsing::{AttributeKind, StabilityLevel, StableSince}; +use rustc_attr_data_structures::{AttributeKind, StabilityLevel, StableSince}; use rustc_hir::Attribute; use rustc_hir::intravisit::Visitor; use rustc_middle::hir::nested_filter; diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index d7baad69c7861..9884386d68f8c 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -5,9 +5,9 @@ use std::mem::replace; use std::num::NonZero; use rustc_ast_lowering::stability::extern_abi_stability; -use rustc_attr_parsing::{ - self as attr, AttributeKind, ConstStability, DeprecatedSince, PartialConstStability, Stability, - StabilityLevel, StableSince, UnstableReason, VERSION_PLACEHOLDER, find_attr, +use rustc_attr_data_structures::{ + self as attrs, AttributeKind, ConstStability, DeprecatedSince, PartialConstStability, + Stability, StabilityLevel, StableSince, UnstableReason, VERSION_PLACEHOLDER, find_attr, }; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; @@ -121,7 +121,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id)); debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs); - let depr = attr::find_attr!(attrs, AttributeKind::Deprecation{deprecation, span} => (*deprecation, *span)); + let depr = attrs::find_attr!(attrs, AttributeKind::Deprecation{deprecation, span} => (*deprecation, *span)); let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect); let mut is_deprecated = false; @@ -174,9 +174,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } // # Regular and body stability - let stab = attr::find_attr!(attrs, AttributeKind::Stability { stability, span } => (*stability, *span)); + let stab = attrs::find_attr!(attrs, AttributeKind::Stability { stability, span } => (*stability, *span)); let body_stab = - attr::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability); + attrs::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability); if let Some((depr, span)) = &depr && depr.is_since_rustc_version() @@ -206,7 +206,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { // this is *almost surely* an accident. if let ( &Some(DeprecatedSince::RustcVersion(dep_since)), - &attr::StabilityLevel::Stable { since: stab_since, .. }, + &attrs::StabilityLevel::Stable { since: stab_since, .. }, ) = (&depr.as_ref().map(|(d, _)| d.since), &stab.level) { match stab_since { @@ -263,7 +263,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { // # Const stability - let const_stab = attr::find_attr!(attrs, AttributeKind::ConstStability { stability, span } => (*stability, *span)); + let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability { stability, span } => (*stability, *span)); // If the current node is a function with const stability attributes (directly given or // implied), check if the function/method is const or the parent impl block is const. @@ -713,7 +713,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { // by default and are unable to be used. if tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { let stability = Stability { - level: attr::StabilityLevel::Unstable { + level: attrs::StabilityLevel::Unstable { reason: UnstableReason::Default, issue: NonZero::new(27812), is_soft: false, @@ -796,17 +796,17 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { let features = self.tcx.features(); if features.staged_api() { let attrs = self.tcx.hir_attrs(item.hir_id()); - let stab = attr::find_attr!(attrs, AttributeKind::Stability{stability, span} => (*stability, *span)); + let stab = attrs::find_attr!(attrs, AttributeKind::Stability{stability, span} => (*stability, *span)); // FIXME(jdonszelmann): make it impossible to miss the or_else in the typesystem - let const_stab = attr::find_attr!(attrs, AttributeKind::ConstStability{stability, ..} => *stability); + let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability{stability, ..} => *stability); // If this impl block has an #[unstable] attribute, give an // error if all involved types and traits are stable, because // it will have no effect. // See: https://github.com/rust-lang/rust/issues/55436 if let Some(( - Stability { level: attr::StabilityLevel::Unstable { .. }, .. }, + Stability { level: attrs::StabilityLevel::Unstable { .. }, .. }, span, )) = stab { diff --git a/compiler/rustc_privacy/Cargo.toml b/compiler/rustc_privacy/Cargo.toml index 242c67d732aff..109a7bf49fe65 100644 --- a/compiler/rustc_privacy/Cargo.toml +++ b/compiler/rustc_privacy/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start rustc_ast = { path = "../rustc_ast" } -rustc_attr_parsing = { path = "../rustc_attr_parsing" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index a3b479fdb7a98..f89e5744db134 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -21,7 +21,6 @@ use errors::{ }; use rustc_ast::MacroDef; use rustc_ast::visit::{VisitorResult, try_visit}; -use rustc_attr_parsing::AttributeKind; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::intern::Interned; use rustc_errors::{MultiSpan, listify}; @@ -41,7 +40,7 @@ use rustc_session::lint; use rustc_span::hygiene::Transparency; use rustc_span::{Ident, Span, Symbol, sym}; use tracing::debug; -use {rustc_attr_parsing as attr, rustc_hir as hir}; +use {rustc_attr_data_structures as attrs, rustc_hir as hir}; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } @@ -498,7 +497,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { let hir_id = self.tcx.local_def_id_to_hir_id(local_def_id); let attrs = self.tcx.hir_attrs(hir_id); - if attr::find_attr!(attrs, AttributeKind::MacroTransparency(x) => *x) + if attrs::find_attr!(attrs, attrs::AttributeKind::MacroTransparency(x) => *x) .unwrap_or(Transparency::fallback(md.macro_rules)) != Transparency::Opaque { From 88781bc5f62290f5fe8e3b8f2287640fcedddc79 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Fri, 9 May 2025 17:33:16 -0400 Subject: [PATCH 2119/4206] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 7918c7eb59614..056f5f4f3c100 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 7918c7eb59614c39f1c4e27e99d557720976bdd7 +Subproject commit 056f5f4f3c100cb36b5e9aed2d20b9ea70aae295 From e4d82aefd95ee2cf035b02f6dcf15b0ea49b0171 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Fri, 9 May 2025 22:03:49 +0000 Subject: [PATCH 2120/4206] Resolve through local re-exports in `lookup_path` --- clippy_utils/src/paths.rs | 19 +++++++-- .../toml_disallowed_methods/clippy.toml | 3 ++ .../conf_disallowed_methods.rs | 8 ++++ .../conf_disallowed_methods.stderr | 42 ++++++++++++------- 4 files changed, 53 insertions(+), 19 deletions(-) diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 795fb502c9cc2..e5179e479ccd9 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -8,9 +8,9 @@ use crate::{MaybePath, path_def_id, sym}; use rustc_ast::Mutability; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::Namespace::{MacroNS, TypeNS, ValueNS}; -use rustc_hir::def::{DefKind, Namespace}; +use rustc_hir::def::{DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; -use rustc_hir::{ImplItemRef, ItemKind, Node, OwnerId, TraitItemRef}; +use rustc_hir::{ImplItemRef, ItemKind, Node, OwnerId, TraitItemRef, UseKind}; use rustc_lint::LateContext; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::{FloatTy, IntTy, Ty, TyCtxt, UintTy}; @@ -302,8 +302,19 @@ fn local_item_child_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, ns: PathNS, n match item_kind { ItemKind::Mod(_, r#mod) => r#mod.item_ids.iter().find_map(|&item_id| { - let ident = tcx.hir_item(item_id).kind.ident()?; - res(ident, item_id.owner_id) + let item = tcx.hir_item(item_id); + if let ItemKind::Use(path, UseKind::Single(ident)) = item.kind { + if ident.name == name { + path.res + .iter() + .find(|res| ns.matches(res.ns())) + .and_then(Res::opt_def_id) + } else { + None + } + } else { + res(item.kind.ident()?, item_id.owner_id) + } }), ItemKind::Impl(r#impl) => r#impl .items diff --git a/tests/ui-toml/toml_disallowed_methods/clippy.toml b/tests/ui-toml/toml_disallowed_methods/clippy.toml index 41dbd5068479b..c7a326f282951 100644 --- a/tests/ui-toml/toml_disallowed_methods/clippy.toml +++ b/tests/ui-toml/toml_disallowed_methods/clippy.toml @@ -14,4 +14,7 @@ disallowed-methods = [ "conf_disallowed_methods::Struct::method", "conf_disallowed_methods::Trait::provided_method", "conf_disallowed_methods::Trait::implemented_method", + # re-exports + "conf_disallowed_methods::identity", + "conf_disallowed_methods::renamed", ] diff --git a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs index dd170d6baf857..2dac01649a0fd 100644 --- a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs +++ b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs @@ -8,6 +8,9 @@ extern crate regex; use futures::stream::{empty, select_all}; use regex::Regex; +use std::convert::identity; +use std::hint::black_box as renamed; + fn local_fn() {} struct Struct; @@ -71,4 +74,9 @@ fn main() { //~^ disallowed_methods s.implemented_method(); //~^ disallowed_methods + + identity(()); + //~^ disallowed_methods + renamed(1); + //~^ disallowed_methods } diff --git a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr index f7dda81eb936e..20474ad6e9270 100644 --- a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr +++ b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr @@ -1,5 +1,5 @@ error: use of a disallowed method `regex::Regex::new` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:33:14 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:36:14 | LL | let re = Regex::new(r"ab.*c").unwrap(); | ^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let re = Regex::new(r"ab.*c").unwrap(); = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]` error: use of a disallowed method `regex::Regex::is_match` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:35:8 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:38:8 | LL | re.is_match("abc"); | ^^^^^^^^ @@ -16,76 +16,88 @@ LL | re.is_match("abc"); = note: no matching allowed error: use of a disallowed method `std::iter::Iterator::sum` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:39:14 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:42:14 | LL | a.iter().sum::(); | ^^^ error: use of a disallowed method `slice::sort_unstable` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:42:7 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:45:7 | LL | a.sort_unstable(); | ^^^^^^^^^^^^^ error: use of a disallowed method `f32::clamp` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:46:20 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:49:20 | LL | let _ = 2.0f32.clamp(3.0f32, 4.0f32); | ^^^^^ error: use of a disallowed method `regex::Regex::new` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:50:61 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:53:61 | LL | let indirect: fn(&str) -> Result = Regex::new; | ^^^^^^^^^^ error: use of a disallowed method `f32::clamp` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:54:28 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:57:28 | LL | let in_call = Box::new(f32::clamp); | ^^^^^^^^^^ error: use of a disallowed method `regex::Regex::new` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:56:53 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:59:53 | LL | let in_method_call = ["^", "$"].into_iter().map(Regex::new); | ^^^^^^^^^^ error: use of a disallowed method `futures::stream::select_all` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:60:31 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:63:31 | LL | let same_name_as_module = select_all(vec![empty::<()>()]); | ^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::local_fn` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:63:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:66:5 | LL | local_fn(); | ^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::local_mod::f` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:65:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:68:5 | LL | local_mod::f(); | ^^^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::Struct::method` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:68:7 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:71:7 | LL | s.method(); | ^^^^^^ error: use of a disallowed method `conf_disallowed_methods::Trait::provided_method` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:70:7 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:73:7 | LL | s.provided_method(); | ^^^^^^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::Trait::implemented_method` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:72:7 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:75:7 | LL | s.implemented_method(); | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 14 previous errors +error: use of a disallowed method `conf_disallowed_methods::identity` + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:78:5 + | +LL | identity(()); + | ^^^^^^^^ + +error: use of a disallowed method `conf_disallowed_methods::renamed` + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:80:5 + | +LL | renamed(1); + | ^^^^^^^ + +error: aborting due to 16 previous errors From bde939058b21dabcbd56b2fc55dacd36d1f97d49 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Fri, 9 May 2025 23:48:17 +0200 Subject: [PATCH 2121/4206] `char::is_digit()` is const-stable only since Rust 1.87 The `to_digit_is_some()` lint suggests using `char::is_digit()`. It should not trigger in const contexts before Rust 1.87. --- book/src/lint_configuration.md | 1 + clippy_config/src/conf.rs | 1 + clippy_lints/src/lib.rs | 2 +- clippy_lints/src/to_digit_is_some.rs | 22 ++++++++++++++++++---- clippy_utils/src/msrvs.rs | 2 +- tests/ui/to_digit_is_some.fixed | 17 +++++++++++++++++ tests/ui/to_digit_is_some.rs | 17 +++++++++++++++++ tests/ui/to_digit_is_some.stderr | 14 +++++++++++++- 8 files changed, 69 insertions(+), 7 deletions(-) diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 58c79c119ccf0..282d892951cfc 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -849,6 +849,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`same_item_push`](https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push) * [`seek_from_current`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current) * [`seek_rewind`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_rewind) +* [`to_digit_is_some`](https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some) * [`transmute_ptr_to_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref) * [`tuple_array_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions) * [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds) diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index aef0516b75be0..8a1d38ed600eb 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -759,6 +759,7 @@ define_Conf! { same_item_push, seek_from_current, seek_rewind, + to_digit_is_some, transmute_ptr_to_ref, tuple_array_conversions, type_repetition_in_bounds, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ad8b223b3aadb..64fbc0252e2a2 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -746,7 +746,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| Box::new(unused_self::UnusedSelf::new(conf))); store.register_late_pass(|_| Box::new(mutable_debug_assertion::DebugAssertWithMutCall)); store.register_late_pass(|_| Box::new(exit::Exit)); - store.register_late_pass(|_| Box::new(to_digit_is_some::ToDigitIsSome)); + store.register_late_pass(move |_| Box::new(to_digit_is_some::ToDigitIsSome::new(conf))); store.register_late_pass(move |_| Box::new(large_stack_arrays::LargeStackArrays::new(conf))); store.register_late_pass(move |_| Box::new(large_const_arrays::LargeConstArrays::new(conf))); store.register_late_pass(|_| Box::new(floating_point_arithmetic::FloatingPointArithmetic)); diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs index c8a6a41d6d8d2..7d7d74f27b3c2 100644 --- a/clippy_lints/src/to_digit_is_some.rs +++ b/clippy_lints/src/to_digit_is_some.rs @@ -1,10 +1,12 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{paths, sym}; +use clippy_utils::{is_in_const_context, paths, sym}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does @@ -32,7 +34,17 @@ declare_clippy_lint! { "`char.is_digit()` is clearer" } -declare_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]); +impl_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]); + +pub(crate) struct ToDigitIsSome { + msrv: Msrv, +} + +impl ToDigitIsSome { + pub(crate) fn new(conf: &'static Conf) -> Self { + Self { msrv: conf.msrv } + } +} impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { @@ -59,7 +71,9 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome { _ => None, }; - if let Some((is_method_call, char_arg, radix_arg)) = match_result { + if let Some((is_method_call, char_arg, radix_arg)) = match_result + && (!is_in_const_context(cx) || self.msrv.meets(cx, msrvs::CONST_CHAR_IS_DIGIT)) + { let mut applicability = Applicability::MachineApplicable; let char_arg_snip = snippet_with_applicability(cx, char_arg.span, "_", &mut applicability); let radix_snip = snippet_with_applicability(cx, radix_arg.span, "_", &mut applicability); diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 71985cb4b0919..434e43167d6b0 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -23,7 +23,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { 1,88,0 { LET_CHAINS } - 1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT } + 1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT } 1,85,0 { UINT_FLOAT_MIDPOINT } 1,84,0 { CONST_OPTION_AS_SLICE, MANUAL_DANGLING_PTR } 1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP } diff --git a/tests/ui/to_digit_is_some.fixed b/tests/ui/to_digit_is_some.fixed index 627d54c5f7384..ff6b32e6bd182 100644 --- a/tests/ui/to_digit_is_some.fixed +++ b/tests/ui/to_digit_is_some.fixed @@ -9,3 +9,20 @@ fn main() { let _ = char::is_digit(c, 8); //~^ to_digit_is_some } + +#[clippy::msrv = "1.86"] +mod cannot_lint_in_const_context { + fn without_const(c: char) -> bool { + c.is_digit(8) + //~^ to_digit_is_some + } + const fn with_const(c: char) -> bool { + c.to_digit(8).is_some() + } +} + +#[clippy::msrv = "1.87"] +const fn with_const(c: char) -> bool { + c.is_digit(8) + //~^ to_digit_is_some +} diff --git a/tests/ui/to_digit_is_some.rs b/tests/ui/to_digit_is_some.rs index d4eccc9931f17..5ba0861743318 100644 --- a/tests/ui/to_digit_is_some.rs +++ b/tests/ui/to_digit_is_some.rs @@ -9,3 +9,20 @@ fn main() { let _ = char::to_digit(c, 8).is_some(); //~^ to_digit_is_some } + +#[clippy::msrv = "1.86"] +mod cannot_lint_in_const_context { + fn without_const(c: char) -> bool { + c.to_digit(8).is_some() + //~^ to_digit_is_some + } + const fn with_const(c: char) -> bool { + c.to_digit(8).is_some() + } +} + +#[clippy::msrv = "1.87"] +const fn with_const(c: char) -> bool { + c.to_digit(8).is_some() + //~^ to_digit_is_some +} diff --git a/tests/ui/to_digit_is_some.stderr b/tests/ui/to_digit_is_some.stderr index f41382a60d53f..5ffedb4683f17 100644 --- a/tests/ui/to_digit_is_some.stderr +++ b/tests/ui/to_digit_is_some.stderr @@ -13,5 +13,17 @@ error: use of `.to_digit(..).is_some()` LL | let _ = char::to_digit(c, 8).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `char::is_digit(c, 8)` -error: aborting due to 2 previous errors +error: use of `.to_digit(..).is_some()` + --> tests/ui/to_digit_is_some.rs:16:9 + | +LL | c.to_digit(8).is_some() + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `c.is_digit(8)` + +error: use of `.to_digit(..).is_some()` + --> tests/ui/to_digit_is_some.rs:26:5 + | +LL | c.to_digit(8).is_some() + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `c.is_digit(8)` + +error: aborting due to 4 previous errors From 33966ccbb6570c83b9fc1dd0942f83ae2d56f47c Mon Sep 17 00:00:00 2001 From: michal kostrubiec Date: Fri, 9 May 2025 21:22:33 +0200 Subject: [PATCH 2122/4206] Add a workaround for 128 bit switches --- example/mini_core.rs | 54 ++++++++++++++++++++++++----------- src/builder.rs | 25 +++++++++++++--- tests/run/switchint_128bit.rs | 37 ++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 20 deletions(-) create mode 100644 tests/run/switchint_128bit.rs diff --git a/example/mini_core.rs b/example/mini_core.rs index c554a87b8256c..d1d8e8fd5bc45 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -1,6 +1,14 @@ #![feature( - no_core, lang_items, intrinsics, unboxed_closures, extern_types, - decl_macro, rustc_attrs, transparent_unions, auto_traits, freeze_impls, + no_core, + lang_items, + intrinsics, + unboxed_closures, + extern_types, + decl_macro, + rustc_attrs, + transparent_unions, + auto_traits, + freeze_impls, thread_local )] #![no_core] @@ -35,13 +43,13 @@ impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} pub trait DispatchFromDyn {} // &T -> &U -impl<'a, T: ?Sized+Unsize, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {} +impl<'a, T: ?Sized + Unsize, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {} // &mut T -> &mut U -impl<'a, T: ?Sized+Unsize, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {} +impl<'a, T: ?Sized + Unsize, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {} // *const T -> *const U -impl, U: ?Sized> DispatchFromDyn<*const U> for *const T {} +impl, U: ?Sized> DispatchFromDyn<*const U> for *const T {} // *mut T -> *mut U -impl, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {} +impl, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {} impl, U: ?Sized> DispatchFromDyn> for Box {} #[lang = "legacy_receiver"] @@ -52,8 +60,7 @@ impl LegacyReceiver for &mut T {} impl LegacyReceiver for Box {} #[lang = "receiver"] -trait Receiver { -} +trait Receiver {} #[lang = "copy"] pub trait Copy {} @@ -67,10 +74,13 @@ impl Copy for u16 {} impl Copy for u32 {} impl Copy for u64 {} impl Copy for usize {} +impl Copy for u128 {} impl Copy for i8 {} impl Copy for i16 {} impl Copy for i32 {} +impl Copy for i64 {} impl Copy for isize {} +impl Copy for i128 {} impl Copy for f32 {} impl Copy for f64 {} impl Copy for char {} @@ -336,7 +346,6 @@ impl PartialEq for u32 { } } - impl PartialEq for u64 { fn eq(&self, other: &u64) -> bool { (*self) == (*other) @@ -523,7 +532,11 @@ fn panic_in_cleanup() -> ! { #[track_caller] fn panic_bounds_check(index: usize, len: usize) -> ! { unsafe { - libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index); + libc::printf( + "index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, + len, + index, + ); intrinsics::abort(); } } @@ -551,8 +564,7 @@ pub trait Deref { fn deref(&self) -> &Self::Target; } -pub trait Allocator { -} +pub trait Allocator {} impl Allocator for () {} @@ -634,6 +646,8 @@ pub union MaybeUninit { } pub mod intrinsics { + #[rustc_intrinsic] + pub const fn black_box(_dummy: T) -> T; #[rustc_intrinsic] pub fn abort() -> !; #[rustc_intrinsic] @@ -711,19 +725,27 @@ pub struct VaList<'a>(&'a mut VaListImpl); #[rustc_builtin_macro] #[rustc_macro_transparency = "semitransparent"] -pub macro stringify($($t:tt)*) { /* compiler built-in */ } +pub macro stringify($($t:tt)*) { + /* compiler built-in */ +} #[rustc_builtin_macro] #[rustc_macro_transparency = "semitransparent"] -pub macro file() { /* compiler built-in */ } +pub macro file() { + /* compiler built-in */ +} #[rustc_builtin_macro] #[rustc_macro_transparency = "semitransparent"] -pub macro line() { /* compiler built-in */ } +pub macro line() { + /* compiler built-in */ +} #[rustc_builtin_macro] #[rustc_macro_transparency = "semitransparent"] -pub macro cfg() { /* compiler built-in */ } +pub macro cfg() { + /* compiler built-in */ +} pub static A_STATIC: u8 = 42; diff --git a/src/builder.rs b/src/builder.rs index 5c70f4a7df93c..557f7da0db846 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -568,11 +568,28 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { ) { let mut gcc_cases = vec![]; let typ = self.val_ty(value); - for (on_val, dest) in cases { - let on_val = self.const_uint_big(typ, on_val); - gcc_cases.push(self.context.new_case(on_val, on_val, dest)); + // FIXME(FractalFir): This is a workaround for a libgccjit limitation. + // Currently, libgccjit can't directly create 128 bit integers. + // Since switch cases must be values, and casts are not constant, we can't use 128 bit switch cases. + // In such a case, we will simply fall back to an if-ladder. + // This *may* be slower than a native switch, but a slow working solution is better than none at all. + if typ.is_i128(self) || typ.is_u128(self) { + for (on_val, dest) in cases { + let on_val = self.const_uint_big(typ, on_val); + let is_case = + self.context.new_comparison(self.location, ComparisonOp::Equals, value, on_val); + let next_block = self.current_func().new_block("case"); + self.block.end_with_conditional(self.location, is_case, dest, next_block); + self.block = next_block; + } + self.block.end_with_jump(self.location, default_block); + } else { + for (on_val, dest) in cases { + let on_val = self.const_uint_big(typ, on_val); + gcc_cases.push(self.context.new_case(on_val, on_val, dest)); + } + self.block.end_with_switch(self.location, value, default_block, &gcc_cases); } - self.block.end_with_switch(self.location, value, default_block, &gcc_cases); } #[cfg(feature = "master")] diff --git a/tests/run/switchint_128bit.rs b/tests/run/switchint_128bit.rs new file mode 100644 index 0000000000000..decae5bfcd78d --- /dev/null +++ b/tests/run/switchint_128bit.rs @@ -0,0 +1,37 @@ +// Compiler: +// +// Run-time: +// status: 0 + +#![feature(no_core)] +#![no_std] +#![no_core] +#![no_main] + +extern crate mini_core; +use intrinsics::black_box; +use mini_core::*; + +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { + // 1st. Check that small 128 bit values work. + let val = black_box(64_u128); + match val { + 0 => return 1, + 1 => return 2, + 64 => (), + _ => return 3, + } + // 2nd check that *large* values work. + const BIG: u128 = 0xDEAD_C0FE_BEEF_DECAF_BADD_DECAF_BEEF_u128; + let val = black_box(BIG); + match val { + 0 => return 4, + 1 => return 5, + // Check that we will not match on the lower u64, if the upper qword is different! + 0xcafbadddecafbeef => return 6, + 0xDEAD_C0FE_BEEF_DECAF_BADD_DECAF_BEEF_u128 => (), + _ => return 7, + } + 0 +} From 5ebcbfc1e132ad0d3584c23e5cf526698f0a44b3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 9 May 2025 13:18:19 +1000 Subject: [PATCH 2123/4206] Remove `AstDeref`. It's a "utility trait to reduce boilerplate" implemented for `P` and `AstNodeWrapper`, but removing it gives a net reduction of twenty lines of code. It's also simpler to just implement `HasNodeId`/`HasAttrs`/`HasTokens` directly on types instead of via `AstDeref`. (I decided to make this change when doing some related refactoring and the error messages involving `AstDeref` and `HasAttrs` were hard to understand; removing it helped a lot.) --- compiler/rustc_ast/src/ast.rs | 3 +- compiler/rustc_ast/src/ast_traits.rs | 75 +++++++++--------------- compiler/rustc_ast/src/lib.rs | 2 +- compiler/rustc_builtin_macros/src/env.rs | 6 +- 4 files changed, 33 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 114b9835b98cf..4ace80a73444b 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -308,7 +308,6 @@ impl ParenthesizedArgs { } } -use crate::AstDeref; pub use crate::node_id::{CRATE_NODE_ID, DUMMY_NODE_ID, NodeId}; /// Modifiers on a trait bound like `~const`, `?` and `!`. @@ -2349,7 +2348,7 @@ impl Ty { pub fn is_maybe_parenthesised_infer(&self) -> bool { match &self.kind { TyKind::Infer => true, - TyKind::Paren(inner) => inner.ast_deref().is_maybe_parenthesised_infer(), + TyKind::Paren(inner) => inner.is_maybe_parenthesised_infer(), _ => false, } } diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 7f98e7ba8a615..21de7ff7719b6 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -13,34 +13,6 @@ use crate::{ Ty, Variant, Visibility, WherePredicate, }; -/// A utility trait to reduce boilerplate. -/// Standard `Deref(Mut)` cannot be reused due to coherence. -pub trait AstDeref { - type Target; - fn ast_deref(&self) -> &Self::Target; - fn ast_deref_mut(&mut self) -> &mut Self::Target; -} - -macro_rules! impl_not_ast_deref { - ($($T:ty),+ $(,)?) => { - $( - impl !AstDeref for $T {} - )+ - }; -} - -impl_not_ast_deref!(AssocItem, Expr, ForeignItem, Item, Stmt); - -impl AstDeref for P { - type Target = T; - fn ast_deref(&self) -> &Self::Target { - self - } - fn ast_deref_mut(&mut self) -> &mut Self::Target { - self - } -} - /// A trait for AST nodes having an ID. pub trait HasNodeId { fn node_id(&self) -> NodeId; @@ -81,12 +53,12 @@ impl_has_node_id!( WherePredicate, ); -impl> HasNodeId for T { +impl HasNodeId for P { fn node_id(&self) -> NodeId { - self.ast_deref().node_id() + (**self).node_id() } fn node_id_mut(&mut self) -> &mut NodeId { - self.ast_deref_mut().node_id_mut() + (**self).node_id_mut() } } @@ -138,21 +110,21 @@ impl_has_tokens_none!( WherePredicate ); -impl> HasTokens for T { +impl HasTokens for Option { fn tokens(&self) -> Option<&LazyAttrTokenStream> { - self.ast_deref().tokens() + self.as_ref().and_then(|inner| inner.tokens()) } fn tokens_mut(&mut self) -> Option<&mut Option> { - self.ast_deref_mut().tokens_mut() + self.as_mut().and_then(|inner| inner.tokens_mut()) } } -impl HasTokens for Option { +impl HasTokens for P { fn tokens(&self) -> Option<&LazyAttrTokenStream> { - self.as_ref().and_then(|inner| inner.tokens()) + (**self).tokens() } fn tokens_mut(&mut self) -> Option<&mut Option> { - self.as_mut().and_then(|inner| inner.tokens_mut()) + (**self).tokens_mut() } } @@ -273,13 +245,13 @@ impl_has_attrs!( ); impl_has_attrs_none!(Attribute, AttrItem, Block, Pat, Path, Ty, Visibility); -impl> HasAttrs for T { - const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::Target::SUPPORTS_CUSTOM_INNER_ATTRS; +impl HasAttrs for P { + const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS; fn attrs(&self) -> &[Attribute] { - self.ast_deref().attrs() + (**self).attrs() } fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) { - self.ast_deref_mut().visit_attrs(f) + (**self).visit_attrs(f); } } @@ -343,13 +315,22 @@ impl AstNodeWrapper { } } -impl AstDeref for AstNodeWrapper { - type Target = Wrapped; - fn ast_deref(&self) -> &Self::Target { - &self.wrapped +impl HasNodeId for AstNodeWrapper { + fn node_id(&self) -> NodeId { + self.wrapped.node_id() + } + fn node_id_mut(&mut self) -> &mut NodeId { + self.wrapped.node_id_mut() + } +} + +impl HasAttrs for AstNodeWrapper { + const SUPPORTS_CUSTOM_INNER_ATTRS: bool = Wrapped::SUPPORTS_CUSTOM_INNER_ATTRS; + fn attrs(&self) -> &[Attribute] { + self.wrapped.attrs() } - fn ast_deref_mut(&mut self) -> &mut Self::Target { - &mut self.wrapped + fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) { + self.wrapped.visit_attrs(f); } } diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index e572ec99dabf3..c08622cac864a 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -46,7 +46,7 @@ pub mod tokenstream; pub mod visit; pub use self::ast::*; -pub use self::ast_traits::{AstDeref, AstNodeWrapper, HasAttrs, HasNodeId, HasTokens}; +pub use self::ast_traits::{AstNodeWrapper, HasAttrs, HasNodeId, HasTokens}; /// Requirements for a `StableHashingContext` to be used in this crate. /// This is a hack to allow using the `HashStable_Generic` derive macro diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index 0913dc91a5342..f3ac932e1b7e9 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -8,7 +8,7 @@ use std::env::VarError; use rustc_ast::token::{self, LitKind}; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{AstDeref, ExprKind, GenericArg, Mutability}; +use rustc_ast::{ExprKind, GenericArg, Mutability}; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; use rustc_span::{Ident, Span, Symbol, kw, sym}; use thin_vec::thin_vec; @@ -148,13 +148,13 @@ pub(crate) fn expand_env<'cx>( cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVar { span, var: *symbol, - var_expr: var_expr.ast_deref(), + var_expr: &var_expr, }) } else { cx.dcx().emit_err(errors::EnvNotDefined::CustomEnvVar { span, var: *symbol, - var_expr: var_expr.ast_deref(), + var_expr: &var_expr, }) } } From e61886a6d9e510079582cbd11cb00a1c88941cca Mon Sep 17 00:00:00 2001 From: relaxcn Date: Sat, 10 May 2025 01:49:22 +0800 Subject: [PATCH 2124/4206] fix `unnecessary_unwrap` emitted twice in closure --- clippy_lints/src/unwrap.rs | 4 ++ .../ui/checked_unwrap/simple_conditionals.rs | 33 ++++++++++++ .../checked_unwrap/simple_conditionals.stderr | 53 ++++++++++++++++++- 3 files changed, 89 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index a6a9187634680..c641d4e55b940 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -292,6 +292,10 @@ impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> { if expr.span.in_external_macro(self.cx.tcx.sess.source_map()) { return; } + // Skip checking inside closures since they are visited through `Unwrap::check_fn()` already. + if matches!(expr.kind, ExprKind::Closure(_)) { + return; + } if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr) { walk_expr(self, cond); self.visit_branch(expr, cond, then, false); diff --git a/tests/ui/checked_unwrap/simple_conditionals.rs b/tests/ui/checked_unwrap/simple_conditionals.rs index 5589d8cc429ca..ba0d36d85fe54 100644 --- a/tests/ui/checked_unwrap/simple_conditionals.rs +++ b/tests/ui/checked_unwrap/simple_conditionals.rs @@ -240,6 +240,39 @@ fn issue14725() { } } +fn issue14763(x: Option, r: Result<(), ()>) { + _ = || { + if x.is_some() { + _ = x.unwrap(); + //~^ unnecessary_unwrap + } else { + _ = x.unwrap(); + //~^ panicking_unwrap + } + }; + _ = || { + if r.is_ok() { + _ = r.as_ref().unwrap(); + //~^ unnecessary_unwrap + } else { + _ = r.as_ref().unwrap(); + //~^ panicking_unwrap + } + }; +} + +const ISSUE14763: fn(Option) = |x| { + _ = || { + if x.is_some() { + _ = x.unwrap(); + //~^ unnecessary_unwrap + } else { + _ = x.unwrap(); + //~^ panicking_unwrap + } + } +}; + fn check_expect() { let x = Some(()); if x.is_some() { diff --git a/tests/ui/checked_unwrap/simple_conditionals.stderr b/tests/ui/checked_unwrap/simple_conditionals.stderr index 82a36aa5029fe..a4bf00992445e 100644 --- a/tests/ui/checked_unwrap/simple_conditionals.stderr +++ b/tests/ui/checked_unwrap/simple_conditionals.stderr @@ -271,6 +271,57 @@ LL | if result.is_ok() { LL | result.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ +error: called `unwrap` on `x` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:246:17 + | +LL | if x.is_some() { + | -------------- help: try: `if let Some() = x` +LL | _ = x.unwrap(); + | ^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:249:17 + | +LL | if x.is_some() { + | ----------- because of this check +... +LL | _ = x.unwrap(); + | ^^^^^^^^^^ + +error: called `unwrap` on `r` after checking its variant with `is_ok` + --> tests/ui/checked_unwrap/simple_conditionals.rs:255:17 + | +LL | if r.is_ok() { + | ------------ help: try: `if let Ok() = &r` +LL | _ = r.as_ref().unwrap(); + | ^^^^^^^^^^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:258:17 + | +LL | if r.is_ok() { + | --------- because of this check +... +LL | _ = r.as_ref().unwrap(); + | ^^^^^^^^^^^^^^^^^^^ + +error: called `unwrap` on `x` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:267:17 + | +LL | if x.is_some() { + | -------------- help: try: `if let Some() = x` +LL | _ = x.unwrap(); + | ^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:270:17 + | +LL | if x.is_some() { + | ----------- because of this check +... +LL | _ = x.unwrap(); + | ^^^^^^^^^^ + error: creating a shared reference to mutable static --> tests/ui/checked_unwrap/simple_conditionals.rs:183:12 | @@ -281,5 +332,5 @@ LL | if X.is_some() { = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives = note: `#[deny(static_mut_refs)]` on by default -error: aborting due to 30 previous errors +error: aborting due to 36 previous errors From 10980be12eb166a9f87f2ca241d78cf6d4f97bd7 Mon Sep 17 00:00:00 2001 From: Laine Taffin Altman Date: Fri, 9 May 2025 16:26:22 -0700 Subject: [PATCH 2125/4206] RELEASES.md: fix nonsensical ~ operator There is no `~` unary prefix operator, and it definitely shouldn't be in the release notes for a feature whose introducing PR doesn't test for it (because it doesn't exist). --- RELEASES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 1a77c33b9957d..18eaa7bf81345 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -6,7 +6,7 @@ Version 1.87.0 (2025-05-15) Language -------- - [Stabilize `asm_goto` feature](https://github.com/rust-lang/rust/pull/133870) -- [Allow parsing open beginning ranges (`..EXPR`) after unary operators `!`, `~`, `-`, and `*`}](https://github.com/rust-lang/rust/pull/134900). +- [Allow parsing open beginning ranges (`..EXPR`) after unary operators `!`, `-`, and `*`}](https://github.com/rust-lang/rust/pull/134900). - [Don't require method impls for methods with `Self: Sized` bounds in `impl`s for unsized types](https://github.com/rust-lang/rust/pull/135480) - [Stabilize `feature(precise_capturing_in_traits)` allowing `use<...>` bounds on return position `impl Trait` in `trait`s](https://github.com/rust-lang/rust/pull/138128) From 2c5f64d55aef4a2e64350e73243ee5a92ec3a2ea Mon Sep 17 00:00:00 2001 From: Laine Taffin Altman Date: Fri, 9 May 2025 16:28:26 -0700 Subject: [PATCH 2126/4206] RELEASES.md: fix unbalanced and unneeded `}` --- RELEASES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 18eaa7bf81345..5f42fa2a01d0c 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -6,7 +6,7 @@ Version 1.87.0 (2025-05-15) Language -------- - [Stabilize `asm_goto` feature](https://github.com/rust-lang/rust/pull/133870) -- [Allow parsing open beginning ranges (`..EXPR`) after unary operators `!`, `-`, and `*`}](https://github.com/rust-lang/rust/pull/134900). +- [Allow parsing open beginning ranges (`..EXPR`) after unary operators `!`, `-`, and `*`](https://github.com/rust-lang/rust/pull/134900). - [Don't require method impls for methods with `Self: Sized` bounds in `impl`s for unsized types](https://github.com/rust-lang/rust/pull/135480) - [Stabilize `feature(precise_capturing_in_traits)` allowing `use<...>` bounds on return position `impl Trait` in `trait`s](https://github.com/rust-lang/rust/pull/138128) From 4cb9f0309d6e85e6d4bef42321b06ad299e3ef27 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sat, 10 May 2025 09:39:04 +1000 Subject: [PATCH 2127/4206] Make the assertion in `Ident::new` debug-only. This fixes a perf regression introduced in #140252. --- compiler/rustc_span/src/symbol.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index b6cb6113f9fc3..8df211b0840ec 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2352,7 +2352,7 @@ impl Ident { #[inline] /// Constructs a new identifier from a symbol and a span. pub fn new(name: Symbol, span: Span) -> Ident { - assert_ne!(name, kw::Empty); + debug_assert_ne!(name, kw::Empty); Ident { name, span } } From ed799c20195f182159429358e64f1ee1cecac2dc Mon Sep 17 00:00:00 2001 From: Dietrich Daroch Date: Fri, 9 May 2025 19:53:23 -0400 Subject: [PATCH 2128/4206] Split duration_constructors to get non-controversial bits out faster. --- library/core/src/time.rs | 8 ++++---- library/coretests/tests/lib.rs | 1 + library/coretests/tests/time.rs | 11 ++++++++++- .../library-features/duration-constructors-lite.md | 11 +++++++++++ .../src/library-features/duration-constructors.md | 3 ++- .../crates/ide-db/src/generated/lints.rs | 2 +- 6 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 src/doc/unstable-book/src/library-features/duration-constructors-lite.md diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 18c03b4a6f89c..0fb5c0bac7562 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -373,7 +373,7 @@ impl Duration { /// # Examples /// /// ``` - /// #![feature(duration_constructors)] + /// #![feature(duration_constructors_lite)] /// use std::time::Duration; /// /// let duration = Duration::from_hours(6); @@ -381,7 +381,7 @@ impl Duration { /// assert_eq!(6 * 60 * 60, duration.as_secs()); /// assert_eq!(0, duration.subsec_nanos()); /// ``` - #[unstable(feature = "duration_constructors", issue = "120301")] + #[unstable(feature = "duration_constructors_lite", issue = "140881")] #[must_use] #[inline] pub const fn from_hours(hours: u64) -> Duration { @@ -401,7 +401,7 @@ impl Duration { /// # Examples /// /// ``` - /// #![feature(duration_constructors)] + /// #![feature(duration_constructors_lite)] /// use std::time::Duration; /// /// let duration = Duration::from_mins(10); @@ -409,7 +409,7 @@ impl Duration { /// assert_eq!(10 * 60, duration.as_secs()); /// assert_eq!(0, duration.subsec_nanos()); /// ``` - #[unstable(feature = "duration_constructors", issue = "120301")] + #[unstable(feature = "duration_constructors_lite", issue = "140881")] #[must_use] #[inline] pub const fn from_mins(mins: u64) -> Duration { diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index a71c4139308aa..0575375cf4f08 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -24,6 +24,7 @@ #![feature(dec2flt)] #![feature(duration_constants)] #![feature(duration_constructors)] +#![feature(duration_constructors_lite)] #![feature(error_generic_member_access)] #![feature(exact_size_is_empty)] #![feature(extend_one)] diff --git a/library/coretests/tests/time.rs b/library/coretests/tests/time.rs index fe7bb11c67589..bb98e59bf5a2b 100644 --- a/library/coretests/tests/time.rs +++ b/library/coretests/tests/time.rs @@ -46,16 +46,25 @@ fn from_weeks_overflow() { } #[test] -fn constructors() { +fn constructor_weeks() { assert_eq!(Duration::from_weeks(1), Duration::from_secs(7 * 24 * 60 * 60)); assert_eq!(Duration::from_weeks(0), Duration::ZERO); +} +#[test] +fn constructor_days() { assert_eq!(Duration::from_days(1), Duration::from_secs(86_400)); assert_eq!(Duration::from_days(0), Duration::ZERO); +} +#[test] +fn constructor_hours() { assert_eq!(Duration::from_hours(1), Duration::from_secs(3_600)); assert_eq!(Duration::from_hours(0), Duration::ZERO); +} +#[test] +fn constructor_minutes() { assert_eq!(Duration::from_mins(1), Duration::from_secs(60)); assert_eq!(Duration::from_mins(0), Duration::ZERO); } diff --git a/src/doc/unstable-book/src/library-features/duration-constructors-lite.md b/src/doc/unstable-book/src/library-features/duration-constructors-lite.md new file mode 100644 index 0000000000000..5238b84f77646 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/duration-constructors-lite.md @@ -0,0 +1,11 @@ +# `duration_constructors_lite` + +The tracking issue for this feature is: [#140881] + +[#140881]: https://github.com/rust-lang/rust/issues/140881 + +------------------------ + +Add the methods `from_mins`, `from_hours` to `Duration`. + +For `from_days` and `from_weeks` see [`duration_constructors`](https://github.com/rust-lang/rust/issues/120301). diff --git a/src/doc/unstable-book/src/library-features/duration-constructors.md b/src/doc/unstable-book/src/library-features/duration-constructors.md index 098519c7c9037..49ad78d196138 100644 --- a/src/doc/unstable-book/src/library-features/duration-constructors.md +++ b/src/doc/unstable-book/src/library-features/duration-constructors.md @@ -6,4 +6,5 @@ The tracking issue for this feature is: [#120301] ------------------------ -Add the methods `from_mins`, `from_hours` and `from_days` to `Duration`. +Add the methods `from_days` and `from_weeks` to `Duration`. +For `from_mins` and `from_hours` see [duration-constructors-lite.md](./duration-constructors-lite.md) diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs index 706d04484f6fe..f9ff392126616 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs @@ -5789,7 +5789,7 @@ The tracking issue for this feature is: [#120301] ------------------------ -Add the methods `from_mins`, `from_hours` and `from_days` to `Duration`. +Add the methods `from_days` and `from_weeks` to `Duration`. "##, default_severity: Severity::Allow, warn_since: None, From 6e5d6473aaa21d6fae3eb7afdacdfaf93391bfc7 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sat, 10 May 2025 04:53:58 +0000 Subject: [PATCH 2129/4206] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 97bc826b57a40..9afbd3aa63579 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -2ad5f8607d0e192b60b130e5cc416b477b351c18 +fd9fad6dbcc1bae3cba2a8634339ffa620a49f28 From 0092abd9d7a99432b4d54f91f75b7f17c1543fcc Mon Sep 17 00:00:00 2001 From: gohome001 <3156514693@qq.com> Date: Sat, 10 May 2025 13:16:34 +0800 Subject: [PATCH 2130/4206] minor: code review tweak --- .../crates/ide/src/highlight_related.rs | 32 +++++-------------- 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs index 90a7c62d71bbf..fb8dbcfc73543 100644 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs @@ -89,7 +89,7 @@ pub(crate) fn highlight_related( T![break] | T![loop] | T![while] | T![continue] if config.break_points => { highlight_break_points(sema, token).remove(&file_id) } - T![unsafe] if token.parent_ancestors().find_map(ast::BlockExpr::cast).is_some() => { + T![unsafe] if token.parent().and_then(ast::BlockExpr::cast).is_some() => { highlight_unsafe_points(sema, token).remove(&file_id) } T![|] if config.closure_captures => { @@ -715,7 +715,7 @@ pub(crate) fn highlight_unsafe_points( ) -> FxHashMap> { fn hl( sema: &Semantics<'_, RootDatabase>, - unsafe_token: Option, + unsafe_token: &SyntaxToken, block_expr: Option, ) -> Option>> { let mut highlights: FxHashMap> = FxHashMap::default(); @@ -728,27 +728,15 @@ pub(crate) fn highlight_unsafe_points( }; // highlight unsafe keyword itself - let unsafe_token = unsafe_token?; let unsafe_token_file_id = sema.hir_file_for(&unsafe_token.parent()?); push_to_highlights(unsafe_token_file_id, Some(unsafe_token.text_range())); + // highlight unsafe operations if let Some(block) = block_expr { - if let Some(node) = block.syntax().ancestors().find(|n| ast::Fn::can_cast(n.kind())) { - if let Some(function) = ast::Fn::cast(node) { - // highlight unsafe keyword of the function - if let Some(unsafe_token) = function.unsafe_token() { - push_to_highlights(unsafe_token_file_id, Some(unsafe_token.text_range())); - } - // highlight unsafe operations - if let Some(f) = sema.to_def(&function) { - let unsafe_ops = sema.get_unsafe_ops(f.into()); - for unsafe_op in unsafe_ops { - push_to_highlights( - unsafe_op.file_id, - Some(unsafe_op.value.text_range()), - ); - } - } + if let Some(body) = sema.body_for(InFile::new(unsafe_token_file_id, block.syntax())) { + let unsafe_ops = sema.get_unsafe_ops(body); + for unsafe_op in unsafe_ops { + push_to_highlights(unsafe_op.file_id, Some(unsafe_op.value.text_range())); } } } @@ -756,11 +744,7 @@ pub(crate) fn highlight_unsafe_points( Some(highlights) } - let Some(block_expr) = token.parent().and_then(ast::BlockExpr::cast) else { - return FxHashMap::default(); - }; - - hl(sema, Some(token), Some(block_expr)).unwrap_or_default() + hl(sema, &token, token.parent().and_then(ast::BlockExpr::cast)).unwrap_or_default() } #[cfg(test)] From 5fc88de1e2917804731798344f49bb3eddee0200 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Sat, 10 May 2025 16:15:44 +0800 Subject: [PATCH 2131/4206] Update deps of bootstrap for Cygwin --- src/bootstrap/Cargo.lock | 46 ++++++++++++---------------------------- 1 file changed, 13 insertions(+), 33 deletions(-) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index cdad3bd46fab6..05ab1b6eddefb 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -220,9 +220,9 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", "windows-sys 0.59.0", @@ -236,13 +236,13 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fd-lock" -version = "4.0.2" +version = "4.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947" +checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" dependencies = [ "cfg-if", - "rustix 0.38.40", - "windows-sys 0.52.0", + "rustix", + "windows-sys 0.59.0", ] [[package]] @@ -347,9 +347,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.171" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libredox" @@ -362,12 +362,6 @@ dependencies = [ "redox_syscall", ] -[[package]] -name = "linux-raw-sys" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" - [[package]] name = "linux-raw-sys" version = "0.9.3" @@ -583,19 +577,6 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" -[[package]] -name = "rustix" -version = "0.38.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys 0.4.14", - "windows-sys 0.52.0", -] - [[package]] name = "rustix" version = "1.0.2" @@ -605,7 +586,7 @@ dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys 0.9.3", + "linux-raw-sys", "windows-sys 0.59.0", ] @@ -745,7 +726,7 @@ dependencies = [ "fastrand", "getrandom", "once_cell", - "rustix 1.0.2", + "rustix", "windows-sys 0.59.0", ] @@ -1182,13 +1163,12 @@ dependencies = [ [[package]] name = "xattr" -version = "1.3.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e" dependencies = [ "libc", - "linux-raw-sys 0.4.14", - "rustix 0.38.40", + "rustix", ] [[package]] From c1de624605a72979bc927fefbfd558b76b299446 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 10 May 2025 12:21:56 +0200 Subject: [PATCH 2132/4206] link to chapter referred to This made it look the the topic was covered in the chapter just before the current one. --- src/doc/rustc-dev-guide/src/ty-fold.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/ty-fold.md b/src/doc/rustc-dev-guide/src/ty-fold.md index d4d0952fcc340..ecb961cf16b0f 100644 --- a/src/doc/rustc-dev-guide/src/ty-fold.md +++ b/src/doc/rustc-dev-guide/src/ty-fold.md @@ -1,6 +1,6 @@ # `TypeFoldable` and `TypeFolder` -In the previous chapter we discussed instantiating binders. This must involves looking at everything inside of a `Early/Binder` +In [a previous chapter], we discussed instantiating binders. This must involves looking at everything inside of a `Early/Binder` to find any usages of the bound vars in order to replace them. Binders can wrap an arbitrary rust type `T` not just a `Ty` so how do we implement the `instantiate` methods on the `Early/Binder` types. @@ -102,3 +102,4 @@ calls [ty_for_param](https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L552-L587) and all that does is index into the list of substitutions with the index of the `Param`. +[a previous chapter]: ty_module/instantiating_binders.md From 8c6c97d0e22e4a2ff3c8b3b368494c1bfa05d32b Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 10 May 2025 12:32:59 +0200 Subject: [PATCH 2133/4206] use the right case --- src/doc/rustc-dev-guide/src/ty-fold.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/ty-fold.md b/src/doc/rustc-dev-guide/src/ty-fold.md index ecb961cf16b0f..da9564d407756 100644 --- a/src/doc/rustc-dev-guide/src/ty-fold.md +++ b/src/doc/rustc-dev-guide/src/ty-fold.md @@ -1,7 +1,7 @@ # `TypeFoldable` and `TypeFolder` -In [a previous chapter], we discussed instantiating binders. This must involves looking at everything inside of a `Early/Binder` -to find any usages of the bound vars in order to replace them. Binders can wrap an arbitrary rust type `T` not just a `Ty` so +In [a previous chapter], we discussed instantiating binders. This involves looking at everything inside of a `Early/Binder` +to find any usages of the bound vars in order to replace them. Binders can wrap an arbitrary Rust type `T` not just a `Ty` so how do we implement the `instantiate` methods on the `Early/Binder` types. The answer is a couple of traits: @@ -20,7 +20,7 @@ that takes a type as input and returns a new type as a result. `TypeFoldable` in `TypeFolder` `fold_foo` methods on itself, giving the `TypeFolder` access to its contents (the types, regions, etc that are contained within). -You can think of it with this analogy to the iterator combinators we have come to love in rust: +You can think of it with this analogy to the iterator combinators we have come to love in Rust: ```rust,ignore vec.iter().map(|e1| foo(e2)).collect() From 4e684a997740688f4831b512a9c31f644822b67e Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 10 May 2025 12:33:45 +0200 Subject: [PATCH 2134/4206] make more clear what is meant --- src/doc/rustc-dev-guide/src/ty-fold.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/ty-fold.md b/src/doc/rustc-dev-guide/src/ty-fold.md index da9564d407756..dcc565b31cda7 100644 --- a/src/doc/rustc-dev-guide/src/ty-fold.md +++ b/src/doc/rustc-dev-guide/src/ty-fold.md @@ -1,6 +1,6 @@ # `TypeFoldable` and `TypeFolder` -In [a previous chapter], we discussed instantiating binders. This involves looking at everything inside of a `Early/Binder` +In [a previous chapter], we discussed instantiating binders. This involves looking at everything inside of a `Early(Binder)` to find any usages of the bound vars in order to replace them. Binders can wrap an arbitrary Rust type `T` not just a `Ty` so how do we implement the `instantiate` methods on the `Early/Binder` types. From 9f07c1ef93142e7fe8ffd1fdd7b458163f3d5623 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 10 May 2025 12:34:43 +0200 Subject: [PATCH 2135/4206] make more readable --- src/doc/rustc-dev-guide/src/ty-fold.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/ty-fold.md b/src/doc/rustc-dev-guide/src/ty-fold.md index dcc565b31cda7..f659612e816df 100644 --- a/src/doc/rustc-dev-guide/src/ty-fold.md +++ b/src/doc/rustc-dev-guide/src/ty-fold.md @@ -1,7 +1,7 @@ # `TypeFoldable` and `TypeFolder` In [a previous chapter], we discussed instantiating binders. This involves looking at everything inside of a `Early(Binder)` -to find any usages of the bound vars in order to replace them. Binders can wrap an arbitrary Rust type `T` not just a `Ty` so +to find any usages of the bound vars in order to replace them. Binders can wrap an arbitrary Rust type `T`, not just a `Ty`. So, how do we implement the `instantiate` methods on the `Early/Binder` types. The answer is a couple of traits: From 2efa4e61153fca183d2098fecf6342e0a81f4559 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 10 May 2025 12:35:40 +0200 Subject: [PATCH 2136/4206] sembr --- src/doc/rustc-dev-guide/src/ty-fold.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/ty-fold.md b/src/doc/rustc-dev-guide/src/ty-fold.md index f659612e816df..d413e5038cefc 100644 --- a/src/doc/rustc-dev-guide/src/ty-fold.md +++ b/src/doc/rustc-dev-guide/src/ty-fold.md @@ -1,8 +1,10 @@ # `TypeFoldable` and `TypeFolder` -In [a previous chapter], we discussed instantiating binders. This involves looking at everything inside of a `Early(Binder)` -to find any usages of the bound vars in order to replace them. Binders can wrap an arbitrary Rust type `T`, not just a `Ty`. So, -how do we implement the `instantiate` methods on the `Early/Binder` types. +In [a previous chapter], we discussed instantiating binders. +This involves looking at everything inside of a `Early(Binder)` +to find any usages of the bound vars in order to replace them. +Binders can wrap an arbitrary Rust type `T`, not just a `Ty`. +So, how do we implement the `instantiate` methods on the `Early/Binder` types. The answer is a couple of traits: [`TypeFoldable`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/fold/trait.TypeFoldable.html) From eb6749c02efff855b4b906f4227577d36c514ec4 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 10 May 2025 12:35:50 +0200 Subject: [PATCH 2137/4206] is a question --- src/doc/rustc-dev-guide/src/ty-fold.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/ty-fold.md b/src/doc/rustc-dev-guide/src/ty-fold.md index d413e5038cefc..a1a9dcf77718f 100644 --- a/src/doc/rustc-dev-guide/src/ty-fold.md +++ b/src/doc/rustc-dev-guide/src/ty-fold.md @@ -4,7 +4,7 @@ In [a previous chapter], we discussed instantiating binders. This involves looking at everything inside of a `Early(Binder)` to find any usages of the bound vars in order to replace them. Binders can wrap an arbitrary Rust type `T`, not just a `Ty`. -So, how do we implement the `instantiate` methods on the `Early/Binder` types. +So, how do we implement the `instantiate` methods on the `Early/Binder` types? The answer is a couple of traits: [`TypeFoldable`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/fold/trait.TypeFoldable.html) From a82a32980ebee5531abaa4bf1eb8643fdf0da71b Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 10 May 2025 12:43:59 +0200 Subject: [PATCH 2138/4206] fix broken links --- src/doc/rustc-dev-guide/src/ty-fold.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/ty-fold.md b/src/doc/rustc-dev-guide/src/ty-fold.md index a1a9dcf77718f..6de9b96a100a7 100644 --- a/src/doc/rustc-dev-guide/src/ty-fold.md +++ b/src/doc/rustc-dev-guide/src/ty-fold.md @@ -7,9 +7,9 @@ Binders can wrap an arbitrary Rust type `T`, not just a `Ty`. So, how do we implement the `instantiate` methods on the `Early/Binder` types? The answer is a couple of traits: -[`TypeFoldable`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/fold/trait.TypeFoldable.html) +[`TypeFoldable`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/trait.TypeFoldable.html) and -[`TypeFolder`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/fold/trait.TypeFolder.html). +[`TypeFolder`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/trait.TypeFolder.html). - `TypeFoldable` is implemented by types that embed type information. It allows you to recursively process the contents of the `TypeFoldable` and do stuff to them. @@ -17,7 +17,7 @@ and `TypeFoldable`. For example, the `TypeFolder` trait has a method -[`fold_ty`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/fold/trait.TypeFolder.html#method.fold_ty) +[`fold_ty`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/trait.TypeFolder.html#method.fold_ty) that takes a type as input and returns a new type as a result. `TypeFoldable` invokes the `TypeFolder` `fold_foo` methods on itself, giving the `TypeFolder` access to its contents (the types, regions, etc that are contained within). From 0de994a368e9225fab812a7295f9350285cd55d3 Mon Sep 17 00:00:00 2001 From: Mu001999 Date: Sat, 10 May 2025 09:55:50 +0800 Subject: [PATCH 2139/4206] Warn when #[export_name] is used with generic functions --- compiler/rustc_lint/src/builtin.rs | 27 +-- .../ui/generics/export-name-on-generics.fixed | 157 +++++++++++++++++ tests/ui/generics/export-name-on-generics.rs | 159 ++++++++++++++++++ .../generics/export-name-on-generics.stderr | 144 ++++++++++++++++ 4 files changed, 477 insertions(+), 10 deletions(-) create mode 100644 tests/ui/generics/export-name-on-generics.fixed create mode 100644 tests/ui/generics/export-name-on-generics.rs create mode 100644 tests/ui/generics/export-name-on-generics.stderr diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 41b43f6479867..95e31e4af1e39 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -976,6 +976,9 @@ declare_lint! { /// ```rust /// #[unsafe(no_mangle)] /// fn foo(t: T) {} + /// + /// #[unsafe(export_name = "bar")] + /// fn bar(t: T) {} /// ``` /// /// {{produces}} @@ -983,10 +986,11 @@ declare_lint! { /// ### Explanation /// /// A function with generics must have its symbol mangled to accommodate - /// the generic parameter. The [`no_mangle` attribute] has no effect in - /// this situation, and should be removed. + /// the generic parameter. The [`no_mangle`] and [`export_name`] attributes + /// have no effect in this situation, and should be removed. /// - /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute + /// [`no_mangle`]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute + /// [`export_name`]: https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute NO_MANGLE_GENERIC_ITEMS, Warn, "generic items must be mangled" @@ -997,7 +1001,7 @@ declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GEN impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { let attrs = cx.tcx.hir_attrs(it.hir_id()); - let check_no_mangle_on_generic_fn = |no_mangle_attr: &hir::Attribute, + let check_no_mangle_on_generic_fn = |attr: &hir::Attribute, impl_generics: Option<&hir::Generics<'_>>, generics: &hir::Generics<'_>, span| { @@ -1010,7 +1014,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { cx.emit_span_lint( NO_MANGLE_GENERIC_ITEMS, span, - BuiltinNoMangleGeneric { suggestion: no_mangle_attr.span() }, + BuiltinNoMangleGeneric { suggestion: attr.span() }, ); break; } @@ -1019,8 +1023,10 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { }; match it.kind { hir::ItemKind::Fn { generics, .. } => { - if let Some(no_mangle_attr) = attr::find_by_name(attrs, sym::no_mangle) { - check_no_mangle_on_generic_fn(no_mangle_attr, None, generics, it.span); + if let Some(attr) = attr::find_by_name(attrs, sym::export_name) + .or_else(|| attr::find_by_name(attrs, sym::no_mangle)) + { + check_no_mangle_on_generic_fn(attr, None, generics, it.span); } } hir::ItemKind::Const(..) => { @@ -1048,11 +1054,12 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => { for it in *items { if let hir::AssocItemKind::Fn { .. } = it.kind { - if let Some(no_mangle_attr) = - attr::find_by_name(cx.tcx.hir_attrs(it.id.hir_id()), sym::no_mangle) + let attrs = cx.tcx.hir_attrs(it.id.hir_id()); + if let Some(attr) = attr::find_by_name(attrs, sym::export_name) + .or_else(|| attr::find_by_name(attrs, sym::no_mangle)) { check_no_mangle_on_generic_fn( - no_mangle_attr, + attr, Some(generics), cx.tcx.hir_get_generics(it.id.owner_id.def_id).unwrap(), it.span, diff --git a/tests/ui/generics/export-name-on-generics.fixed b/tests/ui/generics/export-name-on-generics.fixed new file mode 100644 index 0000000000000..4430cd9a2998a --- /dev/null +++ b/tests/ui/generics/export-name-on-generics.fixed @@ -0,0 +1,157 @@ +//@ run-rustfix +#![allow(dead_code, elided_named_lifetimes)] +#![deny(no_mangle_generic_items)] + +pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled + +pub extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + +#[export_name = "baz"] +pub fn baz(x: &i32) -> &i32 { x } + +#[export_name = "qux"] +pub fn qux<'a>(x: &'a i32) -> &i32 { x } + +pub struct Foo; + +impl Foo { + + pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + + pub extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "baz"] + pub fn baz(x: &i32) -> &i32 { x } + + #[export_name = "qux"] + pub fn qux<'a>(x: &'a i32) -> &i32 { x } +} + +trait Trait1 { + fn foo(); + extern "C" fn bar(); + fn baz(x: &i32) -> &i32; + fn qux<'a>(x: &'a i32) -> &i32; +} + +impl Trait1 for Foo { + + fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + + extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "baz"] + fn baz(x: &i32) -> &i32 { x } + + #[export_name = "qux"] + fn qux<'a>(x: &'a i32) -> &i32 { x } +} + +trait Trait2 { + fn foo(); + fn foo2(); + extern "C" fn bar(); + fn baz(x: &i32) -> &i32; + fn qux<'a>(x: &'a i32) -> &i32; +} + +impl Trait2 for Foo { + + fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + + fn foo2() {} //~ ERROR functions generic over types or consts must be mangled + + + extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + + fn baz(x: &i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled + + + fn qux<'a>(x: &'a i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled +} + +pub struct Bar(#[allow(dead_code)] T); + +impl Bar { + + pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + + pub extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + + pub fn baz() {} //~ ERROR functions generic over types or consts must be mangled +} + +impl Bar { + #[export_name = "qux"] + pub fn qux() {} +} + +trait Trait3 { + fn foo(); + extern "C" fn bar(); + fn baz(); +} + +impl Trait3 for Bar { + + fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + + extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + + fn baz() {} //~ ERROR functions generic over types or consts must be mangled +} + +pub struct Baz<'a>(#[allow(dead_code)] &'a i32); + +impl<'a> Baz<'a> { + #[export_name = "foo"] + pub fn foo() {} + + #[export_name = "bar"] + pub fn bar<'b>(x: &'b i32) -> &i32 { x } +} + +trait Trait4 { + fn foo(); + fn bar<'a>(x: &'a i32) -> &i32; +} + +impl Trait4 for Bar { + #[export_name = "foo"] + fn foo() {} + + #[export_name = "bar"] + fn bar<'b>(x: &'b i32) -> &i32 { x } +} + +impl<'a> Trait4 for Baz<'a> { + #[export_name = "foo"] + fn foo() {} + + #[export_name = "bar"] + fn bar<'b>(x: &'b i32) -> &i32 { x } +} + +trait Trait5 { + fn foo(); +} + +impl Trait5 for Foo { + #[export_name = "foo"] + fn foo() {} +} + +impl Trait5 for Bar { + #[export_name = "foo"] + fn foo() {} +} + +fn main() {} diff --git a/tests/ui/generics/export-name-on-generics.rs b/tests/ui/generics/export-name-on-generics.rs new file mode 100644 index 0000000000000..cbf1102196052 --- /dev/null +++ b/tests/ui/generics/export-name-on-generics.rs @@ -0,0 +1,159 @@ +//@ run-rustfix +#![allow(dead_code, elided_named_lifetimes)] +#![deny(no_mangle_generic_items)] + +#[export_name = "foo"] +pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled + +#[export_name = "bar"] +pub extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + +#[export_name = "baz"] +pub fn baz(x: &i32) -> &i32 { x } + +#[export_name = "qux"] +pub fn qux<'a>(x: &'a i32) -> &i32 { x } + +pub struct Foo; + +impl Foo { + #[export_name = "foo"] + pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "bar"] + pub extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "baz"] + pub fn baz(x: &i32) -> &i32 { x } + + #[export_name = "qux"] + pub fn qux<'a>(x: &'a i32) -> &i32 { x } +} + +trait Trait1 { + fn foo(); + extern "C" fn bar(); + fn baz(x: &i32) -> &i32; + fn qux<'a>(x: &'a i32) -> &i32; +} + +impl Trait1 for Foo { + #[export_name = "foo"] + fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "bar"] + extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "baz"] + fn baz(x: &i32) -> &i32 { x } + + #[export_name = "qux"] + fn qux<'a>(x: &'a i32) -> &i32 { x } +} + +trait Trait2 { + fn foo(); + fn foo2(); + extern "C" fn bar(); + fn baz(x: &i32) -> &i32; + fn qux<'a>(x: &'a i32) -> &i32; +} + +impl Trait2 for Foo { + #[export_name = "foo"] + fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "foo2"] + fn foo2() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "baz"] + extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "baz"] + fn baz(x: &i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "qux"] + fn qux<'a>(x: &'a i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled +} + +pub struct Bar(#[allow(dead_code)] T); + +impl Bar { + #[export_name = "foo"] + pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "bar"] + pub extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "baz"] + pub fn baz() {} //~ ERROR functions generic over types or consts must be mangled +} + +impl Bar { + #[export_name = "qux"] + pub fn qux() {} +} + +trait Trait3 { + fn foo(); + extern "C" fn bar(); + fn baz(); +} + +impl Trait3 for Bar { + #[export_name = "foo"] + fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "bar"] + extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "baz"] + fn baz() {} //~ ERROR functions generic over types or consts must be mangled +} + +pub struct Baz<'a>(#[allow(dead_code)] &'a i32); + +impl<'a> Baz<'a> { + #[export_name = "foo"] + pub fn foo() {} + + #[export_name = "bar"] + pub fn bar<'b>(x: &'b i32) -> &i32 { x } +} + +trait Trait4 { + fn foo(); + fn bar<'a>(x: &'a i32) -> &i32; +} + +impl Trait4 for Bar { + #[export_name = "foo"] + fn foo() {} + + #[export_name = "bar"] + fn bar<'b>(x: &'b i32) -> &i32 { x } +} + +impl<'a> Trait4 for Baz<'a> { + #[export_name = "foo"] + fn foo() {} + + #[export_name = "bar"] + fn bar<'b>(x: &'b i32) -> &i32 { x } +} + +trait Trait5 { + fn foo(); +} + +impl Trait5 for Foo { + #[export_name = "foo"] + fn foo() {} +} + +impl Trait5 for Bar { + #[export_name = "foo"] + fn foo() {} +} + +fn main() {} diff --git a/tests/ui/generics/export-name-on-generics.stderr b/tests/ui/generics/export-name-on-generics.stderr new file mode 100644 index 0000000000000..7bc7b8ca55931 --- /dev/null +++ b/tests/ui/generics/export-name-on-generics.stderr @@ -0,0 +1,144 @@ +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:6:1 + | +LL | #[export_name = "foo"] + | ---------------------- help: remove this attribute +LL | pub fn foo() {} + | ^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/export-name-on-generics.rs:3:9 + | +LL | #![deny(no_mangle_generic_items)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:9:1 + | +LL | #[export_name = "bar"] + | ---------------------- help: remove this attribute +LL | pub extern "C" fn bar() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:21:5 + | +LL | #[export_name = "foo"] + | ---------------------- help: remove this attribute +LL | pub fn foo() {} + | ^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:24:5 + | +LL | #[export_name = "bar"] + | ---------------------- help: remove this attribute +LL | pub extern "C" fn bar() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:42:5 + | +LL | #[export_name = "foo"] + | ---------------------- help: remove this attribute +LL | fn foo() {} + | ^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:45:5 + | +LL | #[export_name = "bar"] + | ---------------------- help: remove this attribute +LL | extern "C" fn bar() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:64:5 + | +LL | #[export_name = "foo"] + | ---------------------- help: remove this attribute +LL | fn foo() {} + | ^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:67:5 + | +LL | #[export_name = "foo2"] + | ----------------------- help: remove this attribute +LL | fn foo2() {} + | ^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:70:5 + | +LL | #[export_name = "baz"] + | ---------------------- help: remove this attribute +LL | extern "C" fn bar() {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:73:5 + | +LL | #[export_name = "baz"] + | ---------------------- help: remove this attribute +LL | fn baz(x: &i32) -> &i32 { x } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:76:5 + | +LL | #[export_name = "qux"] + | ---------------------- help: remove this attribute +LL | fn qux<'a>(x: &'a i32) -> &i32 { x } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:83:5 + | +LL | #[export_name = "foo"] + | ---------------------- help: remove this attribute +LL | pub fn foo() {} + | ^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:86:5 + | +LL | #[export_name = "bar"] + | ---------------------- help: remove this attribute +LL | pub extern "C" fn bar() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:89:5 + | +LL | #[export_name = "baz"] + | ---------------------- help: remove this attribute +LL | pub fn baz() {} + | ^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:105:5 + | +LL | #[export_name = "foo"] + | ---------------------- help: remove this attribute +LL | fn foo() {} + | ^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:108:5 + | +LL | #[export_name = "bar"] + | ---------------------- help: remove this attribute +LL | extern "C" fn bar() {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:111:5 + | +LL | #[export_name = "baz"] + | ---------------------- help: remove this attribute +LL | fn baz() {} + | ^^^^^^^^^^^^^^ + +error: aborting due to 17 previous errors + From 5d8e19fd152979a887db97a904ac181b6ca5886b Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 10 May 2025 12:56:03 +0200 Subject: [PATCH 2140/4206] reduce clutter when reading source --- src/doc/rustc-dev-guide/src/ty-fold.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/ty-fold.md b/src/doc/rustc-dev-guide/src/ty-fold.md index 6de9b96a100a7..c43523cacd8c2 100644 --- a/src/doc/rustc-dev-guide/src/ty-fold.md +++ b/src/doc/rustc-dev-guide/src/ty-fold.md @@ -7,9 +7,9 @@ Binders can wrap an arbitrary Rust type `T`, not just a `Ty`. So, how do we implement the `instantiate` methods on the `Early/Binder` types? The answer is a couple of traits: -[`TypeFoldable`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/trait.TypeFoldable.html) +[`TypeFoldable`] and -[`TypeFolder`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/trait.TypeFolder.html). +[`TypeFolder`]. - `TypeFoldable` is implemented by types that embed type information. It allows you to recursively process the contents of the `TypeFoldable` and do stuff to them. @@ -17,7 +17,7 @@ and `TypeFoldable`. For example, the `TypeFolder` trait has a method -[`fold_ty`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/trait.TypeFolder.html#method.fold_ty) +[`fold_ty`] that takes a type as input and returns a new type as a result. `TypeFoldable` invokes the `TypeFolder` `fold_foo` methods on itself, giving the `TypeFolder` access to its contents (the types, regions, etc that are contained within). @@ -36,7 +36,7 @@ So to reiterate: - `TypeFoldable` is a trait that is implemented by things that embed types. In the case of `subst`, we can see that it is implemented as a `TypeFolder`: -[`ArgFolder`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/binder/struct.ArgFolder.html). +[`ArgFolder`]. Looking at its implementation, we see where the actual substitutions are happening. However, you might also notice that the implementation calls this `super_fold_with` method. What is @@ -91,17 +91,25 @@ things. We only want to do something when we reach a type. That means there may implementations. Such implementations of `TypeFoldable` tend to be pretty tedious to write by hand. For this reason, there is a `derive` macro that allows you to `#![derive(TypeFoldable)]`. It is defined -[here](https://github.com/rust-lang/rust/blob/master/compiler/rustc_macros/src/type_foldable.rs). +[here]. **`subst`** In the case of substitutions the [actual -folder](https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L440-L451) +folder] is going to be doing the indexing we’ve already mentioned. There we define a `Folder` and call `fold_with` on the `TypeFoldable` to process yourself. Then -[fold_ty](https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L512-L536) +[fold_ty] the method that process each type it looks for a `ty::Param` and for those it replaces it for something from the list of substitutions, otherwise recursively process the type. To replace it, calls -[ty_for_param](https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L552-L587) +[ty_for_param] and all that does is index into the list of substitutions with the index of the `Param`. [a previous chapter]: ty_module/instantiating_binders.md +[`TypeFoldable`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/trait.TypeFoldable.html +[`TypeFolder`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/trait.TypeFolder.html +[`fold_ty`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/trait.TypeFolder.html#method.fold_ty +[`ArgFolder`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/binder/struct.ArgFolder.html +[here]: https://github.com/rust-lang/rust/blob/master/compiler/rustc_macros/src/type_foldable.rs +[actual folder]: https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L440-L451 +[fold_ty]: https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L512-L536 +[ty_for_param]: https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L552-L587 From 7b9d7fc2d438cb405648210b63f263d4ba3d5a61 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 10 May 2025 12:59:37 +0200 Subject: [PATCH 2141/4206] sembr --- src/doc/rustc-dev-guide/src/ty-fold.md | 32 +++++++++++--------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/ty-fold.md b/src/doc/rustc-dev-guide/src/ty-fold.md index c43523cacd8c2..8e5fe6ccbac6c 100644 --- a/src/doc/rustc-dev-guide/src/ty-fold.md +++ b/src/doc/rustc-dev-guide/src/ty-fold.md @@ -16,11 +16,10 @@ and - `TypeFolder` defines what you want to do with the types you encounter while processing the `TypeFoldable`. -For example, the `TypeFolder` trait has a method -[`fold_ty`] -that takes a type as input and returns a new type as a result. `TypeFoldable` invokes the -`TypeFolder` `fold_foo` methods on itself, giving the `TypeFolder` access to its contents (the -types, regions, etc that are contained within). +For example, the `TypeFolder` trait has a method [`fold_ty`] +that takes a type as input and returns a new type as a result. +`TypeFoldable` invokes the `TypeFolder` `fold_foo` methods on itself, +giving the `TypeFolder` access to its contents (the types, regions, etc that are contained within). You can think of it with this analogy to the iterator combinators we have come to love in Rust: @@ -35,8 +34,7 @@ So to reiterate: - `TypeFolder` is a trait that defines a “map” operation. - `TypeFoldable` is a trait that is implemented by things that embed types. -In the case of `subst`, we can see that it is implemented as a `TypeFolder`: -[`ArgFolder`]. +In the case of `subst`, we can see that it is implemented as a `TypeFolder`: [`ArgFolder`]. Looking at its implementation, we see where the actual substitutions are happening. However, you might also notice that the implementation calls this `super_fold_with` method. What is @@ -90,18 +88,14 @@ things. We only want to do something when we reach a type. That means there may `TypeFoldable` types whose implementations basically just forward to their fields’ `TypeFoldable` implementations. Such implementations of `TypeFoldable` tend to be pretty tedious to write by hand. For this reason, there is a `derive` macro that allows you to `#![derive(TypeFoldable)]`. It is -defined -[here]. - -**`subst`** In the case of substitutions the [actual -folder] -is going to be doing the indexing we’ve already mentioned. There we define a `Folder` and call -`fold_with` on the `TypeFoldable` to process yourself. Then -[fold_ty] -the method that process each type it looks for a `ty::Param` and for those it replaces it for -something from the list of substitutions, otherwise recursively process the type. To replace it, -calls -[ty_for_param] +defined [here]. + +**`subst`** In the case of substitutions the [actual folder] +is going to be doing the indexing we’ve already mentioned. +There we define a `Folder` and call `fold_with` on the `TypeFoldable` to process yourself. +Then [fold_ty] the method that process each type it looks for a `ty::Param` and for those +it replaces it for something from the list of substitutions, otherwise recursively process the type. +To replace it, calls [ty_for_param] and all that does is index into the list of substitutions with the index of the `Param`. [a previous chapter]: ty_module/instantiating_binders.md From f1d1ebc1e9fa72ef50ed34abf717bc0136d0fab4 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 10 May 2025 13:07:34 +0200 Subject: [PATCH 2142/4206] last updated a year ago --- src/doc/rustc-dev-guide/src/ty-fold.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/rustc-dev-guide/src/ty-fold.md b/src/doc/rustc-dev-guide/src/ty-fold.md index 8e5fe6ccbac6c..23253022ffe27 100644 --- a/src/doc/rustc-dev-guide/src/ty-fold.md +++ b/src/doc/rustc-dev-guide/src/ty-fold.md @@ -1,3 +1,4 @@ + # `TypeFoldable` and `TypeFolder` In [a previous chapter], we discussed instantiating binders. From 52e4b4a588fde422b8a0b245b053b50aafad9454 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 10 May 2025 13:14:38 +0200 Subject: [PATCH 2143/4206] add missing word --- src/doc/rustc-dev-guide/ci/date-check/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/ci/date-check/src/main.rs b/src/doc/rustc-dev-guide/ci/date-check/src/main.rs index 9af69dbbf3f5c..0a32f4e9b7b66 100644 --- a/src/doc/rustc-dev-guide/ci/date-check/src/main.rs +++ b/src/doc/rustc-dev-guide/ci/date-check/src/main.rs @@ -114,7 +114,7 @@ fn filter_dates( fn main() { let mut args = env::args(); if args.len() == 1 { - eprintln!("error: expected root Markdown directory as CLI argument"); + eprintln!("error: expected root of Markdown directory as CLI argument"); process::exit(1); } let root_dir = args.nth(1).unwrap(); From 927343ee47f256caaebe1bf8963fb175a1b88075 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 10 May 2025 13:15:12 +0200 Subject: [PATCH 2144/4206] no point versioning these They are internal tools. --- .../rustc-dev-guide/ci/date-check/Cargo.lock | 207 +++++++++--------- .../rustc-dev-guide/ci/date-check/Cargo.toml | 1 - src/doc/rustc-dev-guide/josh-sync/Cargo.lock | 2 +- src/doc/rustc-dev-guide/josh-sync/Cargo.toml | 1 - 4 files changed, 108 insertions(+), 103 deletions(-) diff --git a/src/doc/rustc-dev-guide/ci/date-check/Cargo.lock b/src/doc/rustc-dev-guide/ci/date-check/Cargo.lock index 6326b2daf12c0..7107547332f13 100644 --- a/src/doc/rustc-dev-guide/ci/date-check/Cargo.lock +++ b/src/doc/rustc-dev-guide/ci/date-check/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -28,21 +28,24 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "cc" -version = "1.0.106" +version = "1.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "066fce287b1d4eafef758e89e09d724a24808a9196fe9756b8ca90e86d0719a2" +checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -52,27 +55,27 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", - "windows-targets", + "windows-link", ] [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "date-check" -version = "0.1.0" +version = "0.0.0" dependencies = [ "chrono", "glob", @@ -81,20 +84,21 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", "windows-core", ] @@ -110,24 +114,25 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] [[package]] name = "libc" -version = "0.2.155" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "log" -version = "0.4.22" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "memchr" @@ -146,33 +151,33 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] [[package]] name = "regex" -version = "1.10.5" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -182,9 +187,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -193,15 +198,27 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "syn" -version = "2.0.70" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", @@ -210,29 +227,30 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", + "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", "syn", @@ -241,9 +259,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -251,9 +269,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", @@ -264,79 +282,68 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "windows-core" -version = "0.52.0" +version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" dependencies = [ - "windows-targets", + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] -name = "windows-targets" -version = "0.52.6" +name = "windows-implement" +version = "0.60.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ - "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", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" +name = "windows-interface" +version = "0.59.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" +name = "windows-link" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" [[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" +name = "windows-result" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +dependencies = [ + "windows-link", +] [[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" +name = "windows-strings" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +dependencies = [ + "windows-link", +] diff --git a/src/doc/rustc-dev-guide/ci/date-check/Cargo.toml b/src/doc/rustc-dev-guide/ci/date-check/Cargo.toml index 472529511d062..9a28087acd74c 100644 --- a/src/doc/rustc-dev-guide/ci/date-check/Cargo.toml +++ b/src/doc/rustc-dev-guide/ci/date-check/Cargo.toml @@ -1,6 +1,5 @@ [package] name = "date-check" -version = "0.1.0" authors = ["Noah Lev "] edition = "2021" diff --git a/src/doc/rustc-dev-guide/josh-sync/Cargo.lock b/src/doc/rustc-dev-guide/josh-sync/Cargo.lock index 844518628c437..a8183a740db3b 100644 --- a/src/doc/rustc-dev-guide/josh-sync/Cargo.lock +++ b/src/doc/rustc-dev-guide/josh-sync/Cargo.lock @@ -161,7 +161,7 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "josh-sync" -version = "0.1.0" +version = "0.0.0" dependencies = [ "anyhow", "clap", diff --git a/src/doc/rustc-dev-guide/josh-sync/Cargo.toml b/src/doc/rustc-dev-guide/josh-sync/Cargo.toml index 81d0d1ebd22d8..7cfa4a14c19cd 100644 --- a/src/doc/rustc-dev-guide/josh-sync/Cargo.toml +++ b/src/doc/rustc-dev-guide/josh-sync/Cargo.toml @@ -1,6 +1,5 @@ [package] name = "josh-sync" -version = "0.1.0" edition = "2021" [dependencies] From a9d655179f9e514860ae34f6b7e8448e142f0222 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 10 May 2025 13:29:41 +0200 Subject: [PATCH 2145/4206] bump edition --- src/doc/rustc-dev-guide/ci/date-check/Cargo.toml | 2 +- src/doc/rustc-dev-guide/josh-sync/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/ci/date-check/Cargo.toml b/src/doc/rustc-dev-guide/ci/date-check/Cargo.toml index 9a28087acd74c..6101a4bcfba5c 100644 --- a/src/doc/rustc-dev-guide/ci/date-check/Cargo.toml +++ b/src/doc/rustc-dev-guide/ci/date-check/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "date-check" authors = ["Noah Lev "] -edition = "2021" +edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/doc/rustc-dev-guide/josh-sync/Cargo.toml b/src/doc/rustc-dev-guide/josh-sync/Cargo.toml index 7cfa4a14c19cd..1f8bf2a009333 100644 --- a/src/doc/rustc-dev-guide/josh-sync/Cargo.toml +++ b/src/doc/rustc-dev-guide/josh-sync/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "josh-sync" -edition = "2021" +edition = "2024" [dependencies] anyhow = "1.0.95" From 63b3bf99afe22c299ed6ca332674cf2a63966e8e Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 10 May 2025 13:35:33 +0200 Subject: [PATCH 2146/4206] "cargo fmt" --- src/doc/rustc-dev-guide/josh-sync/src/main.rs | 6 +-- src/doc/rustc-dev-guide/josh-sync/src/sync.rs | 40 ++++++++++++------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/doc/rustc-dev-guide/josh-sync/src/main.rs b/src/doc/rustc-dev-guide/josh-sync/src/main.rs index 175f016f73907..aeedee5be22d1 100644 --- a/src/doc/rustc-dev-guide/josh-sync/src/main.rs +++ b/src/doc/rustc-dev-guide/josh-sync/src/main.rs @@ -1,4 +1,5 @@ use clap::Parser; + use crate::sync::{GitSync, RustcPullError}; mod sync; @@ -11,10 +12,7 @@ enum Args { /// Push changes from `rustc-dev-guide` to the given `branch` of a `rustc` fork under the given /// GitHub `username`. /// The pushed branch should then be merged into the `rustc` repository. - RustcPush { - branch: String, - github_username: String - } + RustcPush { branch: String, github_username: String }, } fn main() -> anyhow::Result<()> { diff --git a/src/doc/rustc-dev-guide/josh-sync/src/sync.rs b/src/doc/rustc-dev-guide/josh-sync/src/sync.rs index 41d96397faaba..ed38d1403a02b 100644 --- a/src/doc/rustc-dev-guide/josh-sync/src/sync.rs +++ b/src/doc/rustc-dev-guide/josh-sync/src/sync.rs @@ -1,10 +1,11 @@ +use std::io::Write; use std::ops::Not; use std::path::PathBuf; -use std::{env, net, process}; -use std::io::Write; use std::time::Duration; -use anyhow::{anyhow, bail, Context}; -use xshell::{cmd, Shell}; +use std::{env, net, process}; + +use anyhow::{Context, anyhow, bail}; +use xshell::{Shell, cmd}; /// Used for rustc syncs. const JOSH_FILTER: &str = ":/src/doc/rustc-dev-guide"; @@ -15,10 +16,13 @@ pub enum RustcPullError { /// No changes are available to be pulled. NothingToPull, /// A rustc-pull has failed, probably a git operation error has occurred. - PullFailed(anyhow::Error) + PullFailed(anyhow::Error), } -impl From for RustcPullError where E: Into { +impl From for RustcPullError +where + E: Into, +{ fn from(error: E) -> Self { Self::PullFailed(error.into()) } @@ -32,9 +36,7 @@ pub struct GitSync { /// (https://github.com/rust-lang/miri/blob/6a68a79f38064c3bc30617cca4bdbfb2c336b140/miri-script/src/commands.rs#L236). impl GitSync { pub fn from_current_dir() -> anyhow::Result { - Ok(Self { - dir: std::env::current_dir()? - }) + Ok(Self { dir: std::env::current_dir()? }) } pub fn rustc_pull(&self, commit: Option) -> Result<(), RustcPullError> { @@ -51,7 +53,10 @@ impl GitSync { })?; // Make sure the repo is clean. if cmd!(sh, "git status --untracked-files=no --porcelain").read()?.is_empty().not() { - return Err(anyhow::anyhow!("working directory must be clean before performing rustc pull").into()); + return Err(anyhow::anyhow!( + "working directory must be clean before performing rustc pull" + ) + .into()); } // Make sure josh is running. let josh = Self::start_josh()?; @@ -94,7 +99,8 @@ impl GitSync { }; let num_roots_before = num_roots()?; - let sha = cmd!(sh, "git rev-parse HEAD").output().context("FAILED to get current commit")?.stdout; + let sha = + cmd!(sh, "git rev-parse HEAD").output().context("FAILED to get current commit")?.stdout; // Merge the fetched commit. const MERGE_COMMIT_MESSAGE: &str = "Merge from rustc"; @@ -102,18 +108,24 @@ impl GitSync { .run() .context("FAILED to merge new commits, something went wrong")?; - let current_sha = cmd!(sh, "git rev-parse HEAD").output().context("FAILED to get current commit")?.stdout; + let current_sha = + cmd!(sh, "git rev-parse HEAD").output().context("FAILED to get current commit")?.stdout; if current_sha == sha { cmd!(sh, "git reset --hard HEAD^") .run() .expect("FAILED to clean up after creating the preparation commit"); - eprintln!("No merge was performed, no changes to pull were found. Rolled back the preparation commit."); + eprintln!( + "No merge was performed, no changes to pull were found. Rolled back the preparation commit." + ); return Err(RustcPullError::NothingToPull); } // Check that the number of roots did not increase. if num_roots()? != num_roots_before { - return Err(anyhow::anyhow!("Josh created a new root commit. This is probably not the history you want.").into()); + return Err(anyhow::anyhow!( + "Josh created a new root commit. This is probably not the history you want." + ) + .into()); } drop(josh); From 58fa975a15a8a74f6cc97bbe8503fbed67412d99 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 10 May 2025 13:48:35 +0200 Subject: [PATCH 2147/4206] we are a collective --- src/doc/rustc-dev-guide/ci/date-check/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/ci/date-check/Cargo.toml b/src/doc/rustc-dev-guide/ci/date-check/Cargo.toml index 6101a4bcfba5c..1ffa13bc00810 100644 --- a/src/doc/rustc-dev-guide/ci/date-check/Cargo.toml +++ b/src/doc/rustc-dev-guide/ci/date-check/Cargo.toml @@ -1,6 +1,5 @@ [package] name = "date-check" -authors = ["Noah Lev "] edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 5a406be039cd22ff52ef14c7b169fbb36f8f0553 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 10 May 2025 13:48:45 +0200 Subject: [PATCH 2148/4206] noise --- src/doc/rustc-dev-guide/ci/date-check/Cargo.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/ci/date-check/Cargo.toml b/src/doc/rustc-dev-guide/ci/date-check/Cargo.toml index 1ffa13bc00810..f49e6d0db940e 100644 --- a/src/doc/rustc-dev-guide/ci/date-check/Cargo.toml +++ b/src/doc/rustc-dev-guide/ci/date-check/Cargo.toml @@ -2,8 +2,6 @@ name = "date-check" edition = "2024" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] glob = "0.3" regex = "1" From 7f0ae5e3ad427a2e8a26635ed2377b98b5888f8a Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 10 May 2025 17:34:54 +0200 Subject: [PATCH 2149/4206] Use the fallback body for `{minimum,maximum}f128` on LLVM as well. --- compiler/rustc_codegen_llvm/src/context.rs | 10 ++++++++-- compiler/rustc_codegen_llvm/src/intrinsic.rs | 10 ++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 0c6006fbc6acb..b0d8e11d1fb57 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -1012,7 +1012,10 @@ impl<'ll> CodegenCx<'ll, '_> { ifn!("llvm.minimum.f16", fn(t_f16, t_f16) -> t_f16); ifn!("llvm.minimum.f32", fn(t_f32, t_f32) -> t_f32); ifn!("llvm.minimum.f64", fn(t_f64, t_f64) -> t_f64); - ifn!("llvm.minimum.f128", fn(t_f128, t_f128) -> t_f128); + // There are issues on x86_64 and aarch64 with the f128 variant. + // - https://github.com/llvm/llvm-project/issues/139380 + // - https://github.com/llvm/llvm-project/issues/139381 + // ifn!("llvm.minimum.f128", fn(t_f128, t_f128) -> t_f128); ifn!("llvm.maxnum.f16", fn(t_f16, t_f16) -> t_f16); ifn!("llvm.maxnum.f32", fn(t_f32, t_f32) -> t_f32); @@ -1022,7 +1025,10 @@ impl<'ll> CodegenCx<'ll, '_> { ifn!("llvm.maximum.f16", fn(t_f16, t_f16) -> t_f16); ifn!("llvm.maximum.f32", fn(t_f32, t_f32) -> t_f32); ifn!("llvm.maximum.f64", fn(t_f64, t_f64) -> t_f64); - ifn!("llvm.maximum.f128", fn(t_f128, t_f128) -> t_f128); + // There are issues on x86_64 and aarch64 with the f128 variant. + // - https://github.com/llvm/llvm-project/issues/139380 + // - https://github.com/llvm/llvm-project/issues/139381 + // ifn!("llvm.maximum.f128", fn(t_f128, t_f128) -> t_f128); ifn!("llvm.floor.f16", fn(t_f16) -> t_f16); ifn!("llvm.floor.f32", fn(t_f32) -> t_f32); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index c68e0036d6efa..5ca5737529229 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -106,8 +106,9 @@ fn get_simple_intrinsic<'ll>( sym::minimumf16 => "llvm.minimum.f16", sym::minimumf32 => "llvm.minimum.f32", sym::minimumf64 => "llvm.minimum.f64", - sym::minimumf128 => "llvm.minimum.f128", - + // There are issues on x86_64 and aarch64 with the f128 variant, + // let's instead use the instrinsic fallback body. + // sym::minimumf128 => "llvm.minimum.f128", sym::maxnumf16 => "llvm.maxnum.f16", sym::maxnumf32 => "llvm.maxnum.f32", sym::maxnumf64 => "llvm.maxnum.f64", @@ -116,8 +117,9 @@ fn get_simple_intrinsic<'ll>( sym::maximumf16 => "llvm.maximum.f16", sym::maximumf32 => "llvm.maximum.f32", sym::maximumf64 => "llvm.maximum.f64", - sym::maximumf128 => "llvm.maximum.f128", - + // There are issues on x86_64 and aarch64 with the f128 variant, + // let's instead use the instrinsic fallback body. + // sym::maximumf128 => "llvm.maximum.f128", sym::copysignf16 => "llvm.copysign.f16", sym::copysignf32 => "llvm.copysign.f32", sym::copysignf64 => "llvm.copysign.f64", From 25dd45f7bdbc13b2c3d9fea8f1cdb65187840879 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 10 May 2025 18:02:47 +0200 Subject: [PATCH 2150/4206] Correctly handle branches when updating repository --- tools/generate_intrinsics.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/generate_intrinsics.py b/tools/generate_intrinsics.py index 8efed3e43af85..181f1e501a40a 100644 --- a/tools/generate_intrinsics.py +++ b/tools/generate_intrinsics.py @@ -12,7 +12,7 @@ def run_command(command, cwd=None): sys.exit(1) -def clone_repository(repo_name, path, repo_url, sub_paths=None): +def clone_repository(repo_name, path, repo_url, branch="master", sub_paths=None): if os.path.exists(path): while True: choice = input("There is already a `{}` folder, do you want to update it? [y/N]".format(path)) @@ -21,7 +21,7 @@ def clone_repository(repo_name, path, repo_url, sub_paths=None): return elif choice.lower() == "y": print("Updating repository...") - run_command(["git", "pull", "origin"], cwd=path) + run_command(["git", "pull", "origin", branch], cwd=path) return else: print("Didn't understand answer...") @@ -209,6 +209,7 @@ def main(): "llvm-project", llvm_path, "https://github.com/llvm/llvm-project", + branch="main", sub_paths=["llvm/include/llvm/IR", "llvm/include/llvm/CodeGen/"], ) clone_repository( From 43b95881f0ef12e61713fa2c8ed57d4e8ac59b71 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 10 May 2025 18:02:54 +0200 Subject: [PATCH 2151/4206] Regenerate intrinsics --- src/intrinsic/archs.rs | 554 +++++++++++++++++++++++++++++++---------- 1 file changed, 418 insertions(+), 136 deletions(-) diff --git a/src/intrinsic/archs.rs b/src/intrinsic/archs.rs index b8d1cde1d5dda..5ada535aa41d6 100644 --- a/src/intrinsic/archs.rs +++ b/src/intrinsic/archs.rs @@ -38,6 +38,7 @@ match name { "llvm.aarch64.gcsss" => "__builtin_arm_gcsss", "llvm.aarch64.isb" => "__builtin_arm_isb", "llvm.aarch64.prefetch" => "__builtin_arm_prefetch", + "llvm.aarch64.sme.in.streaming.mode" => "__builtin_arm_in_streaming_mode", "llvm.aarch64.sve.aesd" => "__builtin_sve_svaesd_u8", "llvm.aarch64.sve.aese" => "__builtin_sve_svaese_u8", "llvm.aarch64.sve.aesimc" => "__builtin_sve_svaesimc_u8", @@ -55,6 +56,8 @@ match name { "llvm.aarch64.ttest" => "__builtin_arm_ttest", // amdgcn "llvm.amdgcn.alignbyte" => "__builtin_amdgcn_alignbyte", + "llvm.amdgcn.ashr.pk.i8.i32" => "__builtin_amdgcn_ashr_pk_i8_i32", + "llvm.amdgcn.ashr.pk.u8.i32" => "__builtin_amdgcn_ashr_pk_u8_i32", "llvm.amdgcn.buffer.wbinvl1" => "__builtin_amdgcn_buffer_wbinvl1", "llvm.amdgcn.buffer.wbinvl1.sc" => "__builtin_amdgcn_buffer_wbinvl1_sc", "llvm.amdgcn.buffer.wbinvl1.vol" => "__builtin_amdgcn_buffer_wbinvl1_vol", @@ -64,6 +67,7 @@ match name { "llvm.amdgcn.cubetc" => "__builtin_amdgcn_cubetc", "llvm.amdgcn.cvt.f32.bf8" => "__builtin_amdgcn_cvt_f32_bf8", "llvm.amdgcn.cvt.f32.fp8" => "__builtin_amdgcn_cvt_f32_fp8", + "llvm.amdgcn.cvt.off.f32.i4" => "__builtin_amdgcn_cvt_off_f32_i4", "llvm.amdgcn.cvt.pk.bf8.f32" => "__builtin_amdgcn_cvt_pk_bf8_f32", "llvm.amdgcn.cvt.pk.f32.bf8" => "__builtin_amdgcn_cvt_pk_f32_bf8", "llvm.amdgcn.cvt.pk.f32.fp8" => "__builtin_amdgcn_cvt_pk_f32_fp8", @@ -74,7 +78,58 @@ match name { "llvm.amdgcn.cvt.pknorm.i16" => "__builtin_amdgcn_cvt_pknorm_i16", "llvm.amdgcn.cvt.pknorm.u16" => "__builtin_amdgcn_cvt_pknorm_u16", "llvm.amdgcn.cvt.pkrtz" => "__builtin_amdgcn_cvt_pkrtz", + "llvm.amdgcn.cvt.scalef32.2xpk16.bf6.f32" => "__builtin_amdgcn_cvt_scalef32_2xpk16_bf6_f32", + "llvm.amdgcn.cvt.scalef32.2xpk16.fp6.f32" => "__builtin_amdgcn_cvt_scalef32_2xpk16_fp6_f32", + "llvm.amdgcn.cvt.scalef32.f16.bf8" => "__builtin_amdgcn_cvt_scalef32_f16_bf8", + "llvm.amdgcn.cvt.scalef32.f16.fp8" => "__builtin_amdgcn_cvt_scalef32_f16_fp8", + "llvm.amdgcn.cvt.scalef32.f32.bf8" => "__builtin_amdgcn_cvt_scalef32_f32_bf8", + "llvm.amdgcn.cvt.scalef32.f32.fp8" => "__builtin_amdgcn_cvt_scalef32_f32_fp8", + "llvm.amdgcn.cvt.scalef32.pk.bf16.bf8" => "__builtin_amdgcn_cvt_scalef32_pk_bf16_bf8", + "llvm.amdgcn.cvt.scalef32.pk.bf16.fp4" => "__builtin_amdgcn_cvt_scalef32_pk_bf16_fp4", + "llvm.amdgcn.cvt.scalef32.pk.bf16.fp8" => "__builtin_amdgcn_cvt_scalef32_pk_bf16_fp8", + "llvm.amdgcn.cvt.scalef32.pk.bf8.bf16" => "__builtin_amdgcn_cvt_scalef32_pk_bf8_bf16", + "llvm.amdgcn.cvt.scalef32.pk.bf8.f16" => "__builtin_amdgcn_cvt_scalef32_pk_bf8_f16", + "llvm.amdgcn.cvt.scalef32.pk.bf8.f32" => "__builtin_amdgcn_cvt_scalef32_pk_bf8_f32", + "llvm.amdgcn.cvt.scalef32.pk.f16.bf8" => "__builtin_amdgcn_cvt_scalef32_pk_f16_bf8", + "llvm.amdgcn.cvt.scalef32.pk.f16.fp4" => "__builtin_amdgcn_cvt_scalef32_pk_f16_fp4", + "llvm.amdgcn.cvt.scalef32.pk.f16.fp8" => "__builtin_amdgcn_cvt_scalef32_pk_f16_fp8", + "llvm.amdgcn.cvt.scalef32.pk.f32.bf8" => "__builtin_amdgcn_cvt_scalef32_pk_f32_bf8", + "llvm.amdgcn.cvt.scalef32.pk.f32.fp4" => "__builtin_amdgcn_cvt_scalef32_pk_f32_fp4", + "llvm.amdgcn.cvt.scalef32.pk.f32.fp8" => "__builtin_amdgcn_cvt_scalef32_pk_f32_fp8", + "llvm.amdgcn.cvt.scalef32.pk.fp4.bf16" => "__builtin_amdgcn_cvt_scalef32_pk_fp4_bf16", + "llvm.amdgcn.cvt.scalef32.pk.fp4.f16" => "__builtin_amdgcn_cvt_scalef32_pk_fp4_f16", + "llvm.amdgcn.cvt.scalef32.pk.fp4.f32" => "__builtin_amdgcn_cvt_scalef32_pk_fp4_f32", + "llvm.amdgcn.cvt.scalef32.pk.fp8.bf16" => "__builtin_amdgcn_cvt_scalef32_pk_fp8_bf16", + "llvm.amdgcn.cvt.scalef32.pk.fp8.f16" => "__builtin_amdgcn_cvt_scalef32_pk_fp8_f16", + "llvm.amdgcn.cvt.scalef32.pk.fp8.f32" => "__builtin_amdgcn_cvt_scalef32_pk_fp8_f32", + "llvm.amdgcn.cvt.scalef32.pk32.bf16.bf6" => "__builtin_amdgcn_cvt_scalef32_pk32_bf16_bf6", + "llvm.amdgcn.cvt.scalef32.pk32.bf16.fp6" => "__builtin_amdgcn_cvt_scalef32_pk32_bf16_fp6", + "llvm.amdgcn.cvt.scalef32.pk32.bf6.bf16" => "__builtin_amdgcn_cvt_scalef32_pk32_bf6_bf16", + "llvm.amdgcn.cvt.scalef32.pk32.bf6.f16" => "__builtin_amdgcn_cvt_scalef32_pk32_bf6_f16", + "llvm.amdgcn.cvt.scalef32.pk32.f16.bf6" => "__builtin_amdgcn_cvt_scalef32_pk32_f16_bf6", + "llvm.amdgcn.cvt.scalef32.pk32.f16.fp6" => "__builtin_amdgcn_cvt_scalef32_pk32_f16_fp6", + "llvm.amdgcn.cvt.scalef32.pk32.f32.bf6" => "__builtin_amdgcn_cvt_scalef32_pk32_f32_bf6", + "llvm.amdgcn.cvt.scalef32.pk32.f32.fp6" => "__builtin_amdgcn_cvt_scalef32_pk32_f32_fp6", + "llvm.amdgcn.cvt.scalef32.pk32.fp6.bf16" => "__builtin_amdgcn_cvt_scalef32_pk32_fp6_bf16", + "llvm.amdgcn.cvt.scalef32.pk32.fp6.f16" => "__builtin_amdgcn_cvt_scalef32_pk32_fp6_f16", + "llvm.amdgcn.cvt.scalef32.sr.bf8.bf16" => "__builtin_amdgcn_cvt_scalef32_sr_bf8_bf16", + "llvm.amdgcn.cvt.scalef32.sr.bf8.f16" => "__builtin_amdgcn_cvt_scalef32_sr_bf8_f16", + "llvm.amdgcn.cvt.scalef32.sr.bf8.f32" => "__builtin_amdgcn_cvt_scalef32_sr_bf8_f32", + "llvm.amdgcn.cvt.scalef32.sr.fp8.bf16" => "__builtin_amdgcn_cvt_scalef32_sr_fp8_bf16", + "llvm.amdgcn.cvt.scalef32.sr.fp8.f16" => "__builtin_amdgcn_cvt_scalef32_sr_fp8_f16", + "llvm.amdgcn.cvt.scalef32.sr.fp8.f32" => "__builtin_amdgcn_cvt_scalef32_sr_fp8_f32", + "llvm.amdgcn.cvt.scalef32.sr.pk.fp4.bf16" => "__builtin_amdgcn_cvt_scalef32_sr_pk_fp4_bf16", + "llvm.amdgcn.cvt.scalef32.sr.pk.fp4.f16" => "__builtin_amdgcn_cvt_scalef32_sr_pk_fp4_f16", + "llvm.amdgcn.cvt.scalef32.sr.pk.fp4.f32" => "__builtin_amdgcn_cvt_scalef32_sr_pk_fp4_f32", + "llvm.amdgcn.cvt.scalef32.sr.pk32.bf6.bf16" => "__builtin_amdgcn_cvt_scalef32_sr_pk32_bf6_bf16", + "llvm.amdgcn.cvt.scalef32.sr.pk32.bf6.f16" => "__builtin_amdgcn_cvt_scalef32_sr_pk32_bf6_f16", + "llvm.amdgcn.cvt.scalef32.sr.pk32.bf6.f32" => "__builtin_amdgcn_cvt_scalef32_sr_pk32_bf6_f32", + "llvm.amdgcn.cvt.scalef32.sr.pk32.fp6.bf16" => "__builtin_amdgcn_cvt_scalef32_sr_pk32_fp6_bf16", + "llvm.amdgcn.cvt.scalef32.sr.pk32.fp6.f16" => "__builtin_amdgcn_cvt_scalef32_sr_pk32_fp6_f16", + "llvm.amdgcn.cvt.scalef32.sr.pk32.fp6.f32" => "__builtin_amdgcn_cvt_scalef32_sr_pk32_fp6_f32", + "llvm.amdgcn.cvt.sr.bf16.f32" => "__builtin_amdgcn_cvt_sr_bf16_f32", "llvm.amdgcn.cvt.sr.bf8.f32" => "__builtin_amdgcn_cvt_sr_bf8_f32", + "llvm.amdgcn.cvt.sr.f16.f32" => "__builtin_amdgcn_cvt_sr_f16_f32", "llvm.amdgcn.cvt.sr.fp8.f32" => "__builtin_amdgcn_cvt_sr_fp8_f32", "llvm.amdgcn.dispatch.id" => "__builtin_amdgcn_dispatch_id", "llvm.amdgcn.dot4.f32.bf8.bf8" => "__builtin_amdgcn_dot4_f32_bf8_bf8", @@ -83,6 +138,7 @@ match name { "llvm.amdgcn.dot4.f32.fp8.fp8" => "__builtin_amdgcn_dot4_f32_fp8_fp8", "llvm.amdgcn.ds.add.gs.reg.rtn" => "__builtin_amdgcn_ds_add_gs_reg_rtn", "llvm.amdgcn.ds.bpermute" => "__builtin_amdgcn_ds_bpermute", + "llvm.amdgcn.ds.bpermute.fi.b32" => "__builtin_amdgcn_ds_bpermute_fi_b32", "llvm.amdgcn.ds.gws.barrier" => "__builtin_amdgcn_ds_gws_barrier", "llvm.amdgcn.ds.gws.init" => "__builtin_amdgcn_ds_gws_init", "llvm.amdgcn.ds.gws.sema.br" => "__builtin_amdgcn_ds_gws_sema_br", @@ -97,6 +153,7 @@ match name { "llvm.amdgcn.fdot2.bf16.bf16" => "__builtin_amdgcn_fdot2_bf16_bf16", "llvm.amdgcn.fdot2.f16.f16" => "__builtin_amdgcn_fdot2_f16_f16", "llvm.amdgcn.fdot2.f32.bf16" => "__builtin_amdgcn_fdot2_f32_bf16", + "llvm.amdgcn.fdot2c.f32.bf16" => "__builtin_amdgcn_fdot2c_f32_bf16", "llvm.amdgcn.fmul.legacy" => "__builtin_amdgcn_fmul_legacy", "llvm.amdgcn.global.load.lds" => "__builtin_amdgcn_global_load_lds", "llvm.amdgcn.groupstaticsize" => "__builtin_amdgcn_groupstaticsize", @@ -118,8 +175,10 @@ match name { "llvm.amdgcn.mfma.f32.16x16x16f16" => "__builtin_amdgcn_mfma_f32_16x16x16f16", "llvm.amdgcn.mfma.f32.16x16x1f32" => "__builtin_amdgcn_mfma_f32_16x16x1f32", "llvm.amdgcn.mfma.f32.16x16x2bf16" => "__builtin_amdgcn_mfma_f32_16x16x2bf16", + "llvm.amdgcn.mfma.f32.16x16x32.bf16" => "__builtin_amdgcn_mfma_f32_16x16x32_bf16", "llvm.amdgcn.mfma.f32.16x16x32.bf8.bf8" => "__builtin_amdgcn_mfma_f32_16x16x32_bf8_bf8", "llvm.amdgcn.mfma.f32.16x16x32.bf8.fp8" => "__builtin_amdgcn_mfma_f32_16x16x32_bf8_fp8", + "llvm.amdgcn.mfma.f32.16x16x32.f16" => "__builtin_amdgcn_mfma_f32_16x16x32_f16", "llvm.amdgcn.mfma.f32.16x16x32.fp8.bf8" => "__builtin_amdgcn_mfma_f32_16x16x32_fp8_bf8", "llvm.amdgcn.mfma.f32.16x16x32.fp8.fp8" => "__builtin_amdgcn_mfma_f32_16x16x32_fp8_fp8", "llvm.amdgcn.mfma.f32.16x16x4bf16.1k" => "__builtin_amdgcn_mfma_f32_16x16x4bf16_1k", @@ -127,8 +186,10 @@ match name { "llvm.amdgcn.mfma.f32.16x16x4f32" => "__builtin_amdgcn_mfma_f32_16x16x4f32", "llvm.amdgcn.mfma.f32.16x16x8.xf32" => "__builtin_amdgcn_mfma_f32_16x16x8_xf32", "llvm.amdgcn.mfma.f32.16x16x8bf16" => "__builtin_amdgcn_mfma_f32_16x16x8bf16", + "llvm.amdgcn.mfma.f32.32x32x16.bf16" => "__builtin_amdgcn_mfma_f32_32x32x16_bf16", "llvm.amdgcn.mfma.f32.32x32x16.bf8.bf8" => "__builtin_amdgcn_mfma_f32_32x32x16_bf8_bf8", "llvm.amdgcn.mfma.f32.32x32x16.bf8.fp8" => "__builtin_amdgcn_mfma_f32_32x32x16_bf8_fp8", + "llvm.amdgcn.mfma.f32.32x32x16.f16" => "__builtin_amdgcn_mfma_f32_32x32x16_f16", "llvm.amdgcn.mfma.f32.32x32x16.fp8.bf8" => "__builtin_amdgcn_mfma_f32_32x32x16_fp8_bf8", "llvm.amdgcn.mfma.f32.32x32x16.fp8.fp8" => "__builtin_amdgcn_mfma_f32_32x32x16_fp8_fp8", "llvm.amdgcn.mfma.f32.32x32x1f32" => "__builtin_amdgcn_mfma_f32_32x32x1f32", @@ -149,7 +210,9 @@ match name { "llvm.amdgcn.mfma.i32.16x16x16i8" => "__builtin_amdgcn_mfma_i32_16x16x16i8", "llvm.amdgcn.mfma.i32.16x16x32.i8" => "__builtin_amdgcn_mfma_i32_16x16x32_i8", "llvm.amdgcn.mfma.i32.16x16x4i8" => "__builtin_amdgcn_mfma_i32_16x16x4i8", + "llvm.amdgcn.mfma.i32.16x16x64.i8" => "__builtin_amdgcn_mfma_i32_16x16x64_i8", "llvm.amdgcn.mfma.i32.32x32x16.i8" => "__builtin_amdgcn_mfma_i32_32x32x16_i8", + "llvm.amdgcn.mfma.i32.32x32x32.i8" => "__builtin_amdgcn_mfma_i32_32x32x32_i8", "llvm.amdgcn.mfma.i32.32x32x4i8" => "__builtin_amdgcn_mfma_i32_32x32x4i8", "llvm.amdgcn.mfma.i32.32x32x8i8" => "__builtin_amdgcn_mfma_i32_32x32x8i8", "llvm.amdgcn.mfma.i32.4x4x4i8" => "__builtin_amdgcn_mfma_i32_4x4x4i8", @@ -159,25 +222,25 @@ match name { "llvm.amdgcn.perm" => "__builtin_amdgcn_perm", "llvm.amdgcn.permlane16.var" => "__builtin_amdgcn_permlane16_var", "llvm.amdgcn.permlanex16.var" => "__builtin_amdgcn_permlanex16_var", + "llvm.amdgcn.prng.b32" => "__builtin_amdgcn_prng_b32", "llvm.amdgcn.qsad.pk.u16.u8" => "__builtin_amdgcn_qsad_pk_u16_u8", "llvm.amdgcn.queue.ptr" => "__builtin_amdgcn_queue_ptr", + "llvm.amdgcn.raw.ptr.buffer.load.lds" => "__builtin_amdgcn_raw_ptr_buffer_load_lds", "llvm.amdgcn.rcp.legacy" => "__builtin_amdgcn_rcp_legacy", "llvm.amdgcn.rsq.legacy" => "__builtin_amdgcn_rsq_legacy", "llvm.amdgcn.s.barrier" => "__builtin_amdgcn_s_barrier", - "llvm.amdgcn.s.barrier.init" => "__builtin_amdgcn_s_barrier_init", - "llvm.amdgcn.s.barrier.join" => "__builtin_amdgcn_s_barrier_join", - "llvm.amdgcn.s.barrier.leave" => "__builtin_amdgcn_s_barrier_leave", "llvm.amdgcn.s.barrier.signal" => "__builtin_amdgcn_s_barrier_signal", "llvm.amdgcn.s.barrier.signal.isfirst" => "__builtin_amdgcn_s_barrier_signal_isfirst", - "llvm.amdgcn.s.barrier.signal.isfirst.var" => "__builtin_amdgcn_s_barrier_signal_isfirst_var", "llvm.amdgcn.s.barrier.signal.var" => "__builtin_amdgcn_s_barrier_signal_var", "llvm.amdgcn.s.barrier.wait" => "__builtin_amdgcn_s_barrier_wait", + "llvm.amdgcn.s.buffer.prefetch.data" => "__builtin_amdgcn_s_buffer_prefetch_data", "llvm.amdgcn.s.dcache.inv" => "__builtin_amdgcn_s_dcache_inv", "llvm.amdgcn.s.dcache.inv.vol" => "__builtin_amdgcn_s_dcache_inv_vol", "llvm.amdgcn.s.dcache.wb" => "__builtin_amdgcn_s_dcache_wb", "llvm.amdgcn.s.dcache.wb.vol" => "__builtin_amdgcn_s_dcache_wb_vol", "llvm.amdgcn.s.decperflevel" => "__builtin_amdgcn_s_decperflevel", "llvm.amdgcn.s.get.barrier.state" => "__builtin_amdgcn_s_get_barrier_state", + "llvm.amdgcn.s.get.named.barrier.state" => "__builtin_amdgcn_s_get_named_barrier_state", "llvm.amdgcn.s.get.waveid.in.workgroup" => "__builtin_amdgcn_s_get_waveid_in_workgroup", "llvm.amdgcn.s.getpc" => "__builtin_amdgcn_s_getpc", "llvm.amdgcn.s.getreg" => "__builtin_amdgcn_s_getreg", @@ -194,7 +257,6 @@ match name { "llvm.amdgcn.s.ttracedata.imm" => "__builtin_amdgcn_s_ttracedata_imm", "llvm.amdgcn.s.wait.event.export.ready" => "__builtin_amdgcn_s_wait_event_export_ready", "llvm.amdgcn.s.waitcnt" => "__builtin_amdgcn_s_waitcnt", - "llvm.amdgcn.s.wakeup.barrier" => "__builtin_amdgcn_s_wakeup_barrier", "llvm.amdgcn.sad.hi.u8" => "__builtin_amdgcn_sad_hi_u8", "llvm.amdgcn.sad.u16" => "__builtin_amdgcn_sad_u16", "llvm.amdgcn.sad.u8" => "__builtin_amdgcn_sad_u8", @@ -203,20 +265,34 @@ match name { "llvm.amdgcn.sdot2" => "__builtin_amdgcn_sdot2", "llvm.amdgcn.sdot4" => "__builtin_amdgcn_sdot4", "llvm.amdgcn.sdot8" => "__builtin_amdgcn_sdot8", + "llvm.amdgcn.smfmac.f32.16x16x128.bf8.bf8" => "__builtin_amdgcn_smfmac_f32_16x16x128_bf8_bf8", + "llvm.amdgcn.smfmac.f32.16x16x128.bf8.fp8" => "__builtin_amdgcn_smfmac_f32_16x16x128_bf8_fp8", + "llvm.amdgcn.smfmac.f32.16x16x128.fp8.bf8" => "__builtin_amdgcn_smfmac_f32_16x16x128_fp8_bf8", + "llvm.amdgcn.smfmac.f32.16x16x128.fp8.fp8" => "__builtin_amdgcn_smfmac_f32_16x16x128_fp8_fp8", "llvm.amdgcn.smfmac.f32.16x16x32.bf16" => "__builtin_amdgcn_smfmac_f32_16x16x32_bf16", "llvm.amdgcn.smfmac.f32.16x16x32.f16" => "__builtin_amdgcn_smfmac_f32_16x16x32_f16", + "llvm.amdgcn.smfmac.f32.16x16x64.bf16" => "__builtin_amdgcn_smfmac_f32_16x16x64_bf16", "llvm.amdgcn.smfmac.f32.16x16x64.bf8.bf8" => "__builtin_amdgcn_smfmac_f32_16x16x64_bf8_bf8", "llvm.amdgcn.smfmac.f32.16x16x64.bf8.fp8" => "__builtin_amdgcn_smfmac_f32_16x16x64_bf8_fp8", + "llvm.amdgcn.smfmac.f32.16x16x64.f16" => "__builtin_amdgcn_smfmac_f32_16x16x64_f16", "llvm.amdgcn.smfmac.f32.16x16x64.fp8.bf8" => "__builtin_amdgcn_smfmac_f32_16x16x64_fp8_bf8", "llvm.amdgcn.smfmac.f32.16x16x64.fp8.fp8" => "__builtin_amdgcn_smfmac_f32_16x16x64_fp8_fp8", "llvm.amdgcn.smfmac.f32.32x32x16.bf16" => "__builtin_amdgcn_smfmac_f32_32x32x16_bf16", "llvm.amdgcn.smfmac.f32.32x32x16.f16" => "__builtin_amdgcn_smfmac_f32_32x32x16_f16", + "llvm.amdgcn.smfmac.f32.32x32x32.bf16" => "__builtin_amdgcn_smfmac_f32_32x32x32_bf16", "llvm.amdgcn.smfmac.f32.32x32x32.bf8.bf8" => "__builtin_amdgcn_smfmac_f32_32x32x32_bf8_bf8", "llvm.amdgcn.smfmac.f32.32x32x32.bf8.fp8" => "__builtin_amdgcn_smfmac_f32_32x32x32_bf8_fp8", + "llvm.amdgcn.smfmac.f32.32x32x32.f16" => "__builtin_amdgcn_smfmac_f32_32x32x32_f16", "llvm.amdgcn.smfmac.f32.32x32x32.fp8.bf8" => "__builtin_amdgcn_smfmac_f32_32x32x32_fp8_bf8", "llvm.amdgcn.smfmac.f32.32x32x32.fp8.fp8" => "__builtin_amdgcn_smfmac_f32_32x32x32_fp8_fp8", + "llvm.amdgcn.smfmac.f32.32x32x64.bf8.bf8" => "__builtin_amdgcn_smfmac_f32_32x32x64_bf8_bf8", + "llvm.amdgcn.smfmac.f32.32x32x64.bf8.fp8" => "__builtin_amdgcn_smfmac_f32_32x32x64_bf8_fp8", + "llvm.amdgcn.smfmac.f32.32x32x64.fp8.bf8" => "__builtin_amdgcn_smfmac_f32_32x32x64_fp8_bf8", + "llvm.amdgcn.smfmac.f32.32x32x64.fp8.fp8" => "__builtin_amdgcn_smfmac_f32_32x32x64_fp8_fp8", + "llvm.amdgcn.smfmac.i32.16x16x128.i8" => "__builtin_amdgcn_smfmac_i32_16x16x128_i8", "llvm.amdgcn.smfmac.i32.16x16x64.i8" => "__builtin_amdgcn_smfmac_i32_16x16x64_i8", "llvm.amdgcn.smfmac.i32.32x32x32.i8" => "__builtin_amdgcn_smfmac_i32_32x32x32_i8", + "llvm.amdgcn.smfmac.i32.32x32x64.i8" => "__builtin_amdgcn_smfmac_i32_32x32x64_i8", "llvm.amdgcn.sudot4" => "__builtin_amdgcn_sudot4", "llvm.amdgcn.sudot8" => "__builtin_amdgcn_sudot8", "llvm.amdgcn.udot2" => "__builtin_amdgcn_udot2", @@ -227,6 +303,9 @@ match name { "llvm.amdgcn.workgroup.id.x" => "__builtin_amdgcn_workgroup_id_x", "llvm.amdgcn.workgroup.id.y" => "__builtin_amdgcn_workgroup_id_y", "llvm.amdgcn.workgroup.id.z" => "__builtin_amdgcn_workgroup_id_z", + "llvm.amdgcn.workitem.id.x" => "__builtin_amdgcn_workitem_id_x", + "llvm.amdgcn.workitem.id.y" => "__builtin_amdgcn_workitem_id_y", + "llvm.amdgcn.workitem.id.z" => "__builtin_amdgcn_workitem_id_z", // arm "llvm.arm.cdp" => "__builtin_arm_cdp", "llvm.arm.cdp2" => "__builtin_arm_cdp2", @@ -342,8 +421,6 @@ match name { "llvm.bpf.pseudo" => "__builtin_bpf_pseudo", // cuda "llvm.cuda.syncthreads" => "__syncthreads", - // dx - "llvm.dx.create.handle" => "__builtin_hlsl_create_handle", // hexagon "llvm.hexagon.A2.abs" => "__builtin_HEXAGON_A2_abs", "llvm.hexagon.A2.absp" => "__builtin_HEXAGON_A2_absp", @@ -1255,6 +1332,10 @@ match name { "llvm.hexagon.SI.to.SXTHI.asrh" => "__builtin_SI_to_SXTHI_asrh", "llvm.hexagon.V6.extractw" => "__builtin_HEXAGON_V6_extractw", "llvm.hexagon.V6.extractw.128B" => "__builtin_HEXAGON_V6_extractw_128B", + "llvm.hexagon.V6.get.qfext" => "__builtin_HEXAGON_V6_get_qfext", + "llvm.hexagon.V6.get.qfext.128B" => "__builtin_HEXAGON_V6_get_qfext_128B", + "llvm.hexagon.V6.get.qfext.oracc" => "__builtin_HEXAGON_V6_get_qfext_oracc", + "llvm.hexagon.V6.get.qfext.oracc.128B" => "__builtin_HEXAGON_V6_get_qfext_oracc_128B", "llvm.hexagon.V6.hi" => "__builtin_HEXAGON_V6_hi", "llvm.hexagon.V6.hi.128B" => "__builtin_HEXAGON_V6_hi_128B", "llvm.hexagon.V6.lo" => "__builtin_HEXAGON_V6_lo", @@ -1281,6 +1362,8 @@ match name { "llvm.hexagon.V6.pred.scalar2v2.128B" => "__builtin_HEXAGON_V6_pred_scalar2v2_128B", "llvm.hexagon.V6.pred.xor" => "__builtin_HEXAGON_V6_pred_xor", "llvm.hexagon.V6.pred.xor.128B" => "__builtin_HEXAGON_V6_pred_xor_128B", + "llvm.hexagon.V6.set.qfext" => "__builtin_HEXAGON_V6_set_qfext", + "llvm.hexagon.V6.set.qfext.128B" => "__builtin_HEXAGON_V6_set_qfext_128B", "llvm.hexagon.V6.shuffeqh" => "__builtin_HEXAGON_V6_shuffeqh", "llvm.hexagon.V6.shuffeqh.128B" => "__builtin_HEXAGON_V6_shuffeqh_128B", "llvm.hexagon.V6.shuffeqw" => "__builtin_HEXAGON_V6_shuffeqw", @@ -1301,6 +1384,8 @@ match name { "llvm.hexagon.V6.vS32b.nt.qpred.ai.128B" => "__builtin_HEXAGON_V6_vS32b_nt_qpred_ai_128B", "llvm.hexagon.V6.vS32b.qpred.ai" => "__builtin_HEXAGON_V6_vS32b_qpred_ai", "llvm.hexagon.V6.vS32b.qpred.ai.128B" => "__builtin_HEXAGON_V6_vS32b_qpred_ai_128B", + "llvm.hexagon.V6.vabs.f8" => "__builtin_HEXAGON_V6_vabs_f8", + "llvm.hexagon.V6.vabs.f8.128B" => "__builtin_HEXAGON_V6_vabs_f8_128B", "llvm.hexagon.V6.vabs.hf" => "__builtin_HEXAGON_V6_vabs_hf", "llvm.hexagon.V6.vabs.hf.128B" => "__builtin_HEXAGON_V6_vabs_hf_128B", "llvm.hexagon.V6.vabs.sf" => "__builtin_HEXAGON_V6_vabs_sf", @@ -1327,6 +1412,8 @@ match name { "llvm.hexagon.V6.vabsw.sat.128B" => "__builtin_HEXAGON_V6_vabsw_sat_128B", "llvm.hexagon.V6.vadd.hf" => "__builtin_HEXAGON_V6_vadd_hf", "llvm.hexagon.V6.vadd.hf.128B" => "__builtin_HEXAGON_V6_vadd_hf_128B", + "llvm.hexagon.V6.vadd.hf.f8" => "__builtin_HEXAGON_V6_vadd_hf_f8", + "llvm.hexagon.V6.vadd.hf.f8.128B" => "__builtin_HEXAGON_V6_vadd_hf_f8_128B", "llvm.hexagon.V6.vadd.hf.hf" => "__builtin_HEXAGON_V6_vadd_hf_hf", "llvm.hexagon.V6.vadd.hf.hf.128B" => "__builtin_HEXAGON_V6_vadd_hf_hf_128B", "llvm.hexagon.V6.vadd.qf16" => "__builtin_HEXAGON_V6_vadd_qf16", @@ -1549,10 +1636,14 @@ match name { "llvm.hexagon.V6.vcvt.b.hf.128B" => "__builtin_HEXAGON_V6_vcvt_b_hf_128B", "llvm.hexagon.V6.vcvt.bf.sf" => "__builtin_HEXAGON_V6_vcvt_bf_sf", "llvm.hexagon.V6.vcvt.bf.sf.128B" => "__builtin_HEXAGON_V6_vcvt_bf_sf_128B", + "llvm.hexagon.V6.vcvt.f8.hf" => "__builtin_HEXAGON_V6_vcvt_f8_hf", + "llvm.hexagon.V6.vcvt.f8.hf.128B" => "__builtin_HEXAGON_V6_vcvt_f8_hf_128B", "llvm.hexagon.V6.vcvt.h.hf" => "__builtin_HEXAGON_V6_vcvt_h_hf", "llvm.hexagon.V6.vcvt.h.hf.128B" => "__builtin_HEXAGON_V6_vcvt_h_hf_128B", "llvm.hexagon.V6.vcvt.hf.b" => "__builtin_HEXAGON_V6_vcvt_hf_b", "llvm.hexagon.V6.vcvt.hf.b.128B" => "__builtin_HEXAGON_V6_vcvt_hf_b_128B", + "llvm.hexagon.V6.vcvt.hf.f8" => "__builtin_HEXAGON_V6_vcvt_hf_f8", + "llvm.hexagon.V6.vcvt.hf.f8.128B" => "__builtin_HEXAGON_V6_vcvt_hf_f8_128B", "llvm.hexagon.V6.vcvt.hf.h" => "__builtin_HEXAGON_V6_vcvt_hf_h", "llvm.hexagon.V6.vcvt.hf.h.128B" => "__builtin_HEXAGON_V6_vcvt_hf_h_128B", "llvm.hexagon.V6.vcvt.hf.sf" => "__builtin_HEXAGON_V6_vcvt_hf_sf", @@ -1567,6 +1658,14 @@ match name { "llvm.hexagon.V6.vcvt.ub.hf.128B" => "__builtin_HEXAGON_V6_vcvt_ub_hf_128B", "llvm.hexagon.V6.vcvt.uh.hf" => "__builtin_HEXAGON_V6_vcvt_uh_hf", "llvm.hexagon.V6.vcvt.uh.hf.128B" => "__builtin_HEXAGON_V6_vcvt_uh_hf_128B", + "llvm.hexagon.V6.vcvt2.b.hf" => "__builtin_HEXAGON_V6_vcvt2_b_hf", + "llvm.hexagon.V6.vcvt2.b.hf.128B" => "__builtin_HEXAGON_V6_vcvt2_b_hf_128B", + "llvm.hexagon.V6.vcvt2.hf.b" => "__builtin_HEXAGON_V6_vcvt2_hf_b", + "llvm.hexagon.V6.vcvt2.hf.b.128B" => "__builtin_HEXAGON_V6_vcvt2_hf_b_128B", + "llvm.hexagon.V6.vcvt2.hf.ub" => "__builtin_HEXAGON_V6_vcvt2_hf_ub", + "llvm.hexagon.V6.vcvt2.hf.ub.128B" => "__builtin_HEXAGON_V6_vcvt2_hf_ub_128B", + "llvm.hexagon.V6.vcvt2.ub.hf" => "__builtin_HEXAGON_V6_vcvt2_ub_hf", + "llvm.hexagon.V6.vcvt2.ub.hf.128B" => "__builtin_HEXAGON_V6_vcvt2_ub_hf_128B", "llvm.hexagon.V6.vd0" => "__builtin_HEXAGON_V6_vd0", "llvm.hexagon.V6.vd0.128B" => "__builtin_HEXAGON_V6_vd0_128B", "llvm.hexagon.V6.vdd0" => "__builtin_HEXAGON_V6_vdd0", @@ -1649,14 +1748,20 @@ match name { "llvm.hexagon.V6.veqw.or.128B" => "__builtin_HEXAGON_V6_veqw_or_128B", "llvm.hexagon.V6.veqw.xor" => "__builtin_HEXAGON_V6_veqw_xor", "llvm.hexagon.V6.veqw.xor.128B" => "__builtin_HEXAGON_V6_veqw_xor_128B", + "llvm.hexagon.V6.vfmax.f8" => "__builtin_HEXAGON_V6_vfmax_f8", + "llvm.hexagon.V6.vfmax.f8.128B" => "__builtin_HEXAGON_V6_vfmax_f8_128B", "llvm.hexagon.V6.vfmax.hf" => "__builtin_HEXAGON_V6_vfmax_hf", "llvm.hexagon.V6.vfmax.hf.128B" => "__builtin_HEXAGON_V6_vfmax_hf_128B", "llvm.hexagon.V6.vfmax.sf" => "__builtin_HEXAGON_V6_vfmax_sf", "llvm.hexagon.V6.vfmax.sf.128B" => "__builtin_HEXAGON_V6_vfmax_sf_128B", + "llvm.hexagon.V6.vfmin.f8" => "__builtin_HEXAGON_V6_vfmin_f8", + "llvm.hexagon.V6.vfmin.f8.128B" => "__builtin_HEXAGON_V6_vfmin_f8_128B", "llvm.hexagon.V6.vfmin.hf" => "__builtin_HEXAGON_V6_vfmin_hf", "llvm.hexagon.V6.vfmin.hf.128B" => "__builtin_HEXAGON_V6_vfmin_hf_128B", "llvm.hexagon.V6.vfmin.sf" => "__builtin_HEXAGON_V6_vfmin_sf", "llvm.hexagon.V6.vfmin.sf.128B" => "__builtin_HEXAGON_V6_vfmin_sf_128B", + "llvm.hexagon.V6.vfneg.f8" => "__builtin_HEXAGON_V6_vfneg_f8", + "llvm.hexagon.V6.vfneg.f8.128B" => "__builtin_HEXAGON_V6_vfneg_f8_128B", "llvm.hexagon.V6.vfneg.hf" => "__builtin_HEXAGON_V6_vfneg_hf", "llvm.hexagon.V6.vfneg.hf.128B" => "__builtin_HEXAGON_V6_vfneg_hf_128B", "llvm.hexagon.V6.vfneg.sf" => "__builtin_HEXAGON_V6_vfneg_sf", @@ -1807,6 +1912,8 @@ match name { "llvm.hexagon.V6.vmaxuh.128B" => "__builtin_HEXAGON_V6_vmaxuh_128B", "llvm.hexagon.V6.vmaxw" => "__builtin_HEXAGON_V6_vmaxw", "llvm.hexagon.V6.vmaxw.128B" => "__builtin_HEXAGON_V6_vmaxw_128B", + "llvm.hexagon.V6.vmerge.qf" => "__builtin_HEXAGON_V6_vmerge_qf", + "llvm.hexagon.V6.vmerge.qf.128B" => "__builtin_HEXAGON_V6_vmerge_qf_128B", "llvm.hexagon.V6.vmin.bf" => "__builtin_HEXAGON_V6_vmin_bf", "llvm.hexagon.V6.vmin.bf.128B" => "__builtin_HEXAGON_V6_vmin_bf_128B", "llvm.hexagon.V6.vmin.hf" => "__builtin_HEXAGON_V6_vmin_hf", @@ -1849,6 +1956,10 @@ match name { "llvm.hexagon.V6.vmpauhuhsat.128B" => "__builtin_HEXAGON_V6_vmpauhuhsat_128B", "llvm.hexagon.V6.vmpsuhuhsat" => "__builtin_HEXAGON_V6_vmpsuhuhsat", "llvm.hexagon.V6.vmpsuhuhsat.128B" => "__builtin_HEXAGON_V6_vmpsuhuhsat_128B", + "llvm.hexagon.V6.vmpy.hf.f8" => "__builtin_HEXAGON_V6_vmpy_hf_f8", + "llvm.hexagon.V6.vmpy.hf.f8.128B" => "__builtin_HEXAGON_V6_vmpy_hf_f8_128B", + "llvm.hexagon.V6.vmpy.hf.f8.acc" => "__builtin_HEXAGON_V6_vmpy_hf_f8_acc", + "llvm.hexagon.V6.vmpy.hf.f8.acc.128B" => "__builtin_HEXAGON_V6_vmpy_hf_f8_acc_128B", "llvm.hexagon.V6.vmpy.hf.hf" => "__builtin_HEXAGON_V6_vmpy_hf_hf", "llvm.hexagon.V6.vmpy.hf.hf.128B" => "__builtin_HEXAGON_V6_vmpy_hf_hf_128B", "llvm.hexagon.V6.vmpy.hf.hf.acc" => "__builtin_HEXAGON_V6_vmpy_hf_hf_acc", @@ -1869,6 +1980,12 @@ match name { "llvm.hexagon.V6.vmpy.qf32.qf16.128B" => "__builtin_HEXAGON_V6_vmpy_qf32_qf16_128B", "llvm.hexagon.V6.vmpy.qf32.sf" => "__builtin_HEXAGON_V6_vmpy_qf32_sf", "llvm.hexagon.V6.vmpy.qf32.sf.128B" => "__builtin_HEXAGON_V6_vmpy_qf32_sf_128B", + "llvm.hexagon.V6.vmpy.rt.hf" => "__builtin_HEXAGON_V6_vmpy_rt_hf", + "llvm.hexagon.V6.vmpy.rt.hf.128B" => "__builtin_HEXAGON_V6_vmpy_rt_hf_128B", + "llvm.hexagon.V6.vmpy.rt.qf16" => "__builtin_HEXAGON_V6_vmpy_rt_qf16", + "llvm.hexagon.V6.vmpy.rt.qf16.128B" => "__builtin_HEXAGON_V6_vmpy_rt_qf16_128B", + "llvm.hexagon.V6.vmpy.rt.sf" => "__builtin_HEXAGON_V6_vmpy_rt_sf", + "llvm.hexagon.V6.vmpy.rt.sf.128B" => "__builtin_HEXAGON_V6_vmpy_rt_sf_128B", "llvm.hexagon.V6.vmpy.sf.bf" => "__builtin_HEXAGON_V6_vmpy_sf_bf", "llvm.hexagon.V6.vmpy.sf.bf.128B" => "__builtin_HEXAGON_V6_vmpy_sf_bf_128B", "llvm.hexagon.V6.vmpy.sf.bf.acc" => "__builtin_HEXAGON_V6_vmpy_sf_bf_acc", @@ -2127,6 +2244,8 @@ match name { "llvm.hexagon.V6.vshufoh.128B" => "__builtin_HEXAGON_V6_vshufoh_128B", "llvm.hexagon.V6.vsub.hf" => "__builtin_HEXAGON_V6_vsub_hf", "llvm.hexagon.V6.vsub.hf.128B" => "__builtin_HEXAGON_V6_vsub_hf_128B", + "llvm.hexagon.V6.vsub.hf.f8" => "__builtin_HEXAGON_V6_vsub_hf_f8", + "llvm.hexagon.V6.vsub.hf.f8.128B" => "__builtin_HEXAGON_V6_vsub_hf_f8_128B", "llvm.hexagon.V6.vsub.hf.hf" => "__builtin_HEXAGON_V6_vsub_hf_hf", "llvm.hexagon.V6.vsub.hf.hf.128B" => "__builtin_HEXAGON_V6_vsub_hf_hf_128B", "llvm.hexagon.V6.vsub.qf16" => "__builtin_HEXAGON_V6_vsub_qf16", @@ -4445,8 +4564,6 @@ match name { "llvm.mips.xor.v" => "__builtin_msa_xor_v", "llvm.mips.xori.b" => "__builtin_msa_xori_b", // nvvm - "llvm.nvvm.abs.bf16" => "__nvvm_abs_bf16", - "llvm.nvvm.abs.bf16x2" => "__nvvm_abs_bf16x2", "llvm.nvvm.abs.i" => "__nvvm_abs_i", "llvm.nvvm.abs.ll" => "__nvvm_abs_ll", "llvm.nvvm.activemask" => "__nvvm_activemask", @@ -4473,6 +4590,10 @@ match name { "llvm.nvvm.barrier0.and" => "__nvvm_bar0_and", "llvm.nvvm.barrier0.or" => "__nvvm_bar0_or", "llvm.nvvm.barrier0.popc" => "__nvvm_bar0_popc", + "llvm.nvvm.bf16x2.to.ue8m0x2.rp" => "__nvvm_bf16x2_to_ue8m0x2_rp", + "llvm.nvvm.bf16x2.to.ue8m0x2.rp.satfinite" => "__nvvm_bf16x2_to_ue8m0x2_rp_satfinite", + "llvm.nvvm.bf16x2.to.ue8m0x2.rz" => "__nvvm_bf16x2_to_ue8m0x2_rz", + "llvm.nvvm.bf16x2.to.ue8m0x2.rz.satfinite" => "__nvvm_bf16x2_to_ue8m0x2_rz_satfinite", "llvm.nvvm.bf2h.rn" => "__nvvm_bf2h_rn", "llvm.nvvm.bf2h.rn.ftz" => "__nvvm_bf2h_rn_ftz", "llvm.nvvm.bitcast.d2ll" => "__nvvm_bitcast_d2ll", @@ -4523,6 +4644,8 @@ match name { "llvm.nvvm.d2ull.rz" => "__nvvm_d2ull_rz", "llvm.nvvm.div.approx.f" => "__nvvm_div_approx_f", "llvm.nvvm.div.approx.ftz.f" => "__nvvm_div_approx_ftz_f", + "llvm.nvvm.div.full" => "__nvvm_div_full", + "llvm.nvvm.div.full.ftz" => "__nvvm_div_full_ftz", "llvm.nvvm.div.rm.d" => "__nvvm_div_rm_d", "llvm.nvvm.div.rm.f" => "__nvvm_div_rm_f", "llvm.nvvm.div.rm.ftz.f" => "__nvvm_div_rm_ftz_f", @@ -4535,6 +4658,10 @@ match name { "llvm.nvvm.div.rz.d" => "__nvvm_div_rz_d", "llvm.nvvm.div.rz.f" => "__nvvm_div_rz_f", "llvm.nvvm.div.rz.ftz.f" => "__nvvm_div_rz_ftz_f", + "llvm.nvvm.e2m3x2.to.f16x2.rn" => "__nvvm_e2m3x2_to_f16x2_rn", + "llvm.nvvm.e2m3x2.to.f16x2.rn.relu" => "__nvvm_e2m3x2_to_f16x2_rn_relu", + "llvm.nvvm.e3m2x2.to.f16x2.rn" => "__nvvm_e3m2x2_to_f16x2_rn", + "llvm.nvvm.e3m2x2.to.f16x2.rn.relu" => "__nvvm_e3m2x2_to_f16x2_rn_relu", "llvm.nvvm.e4m3x2.to.f16x2.rn" => "__nvvm_e4m3x2_to_f16x2_rn", "llvm.nvvm.e4m3x2.to.f16x2.rn.relu" => "__nvvm_e4m3x2_to_f16x2_rn_relu", "llvm.nvvm.e5m2x2.to.f16x2.rn" => "__nvvm_e5m2x2_to_f16x2_rn", @@ -4569,7 +4696,16 @@ match name { "llvm.nvvm.f2ll.rp.ftz" => "__nvvm_f2ll_rp_ftz", "llvm.nvvm.f2ll.rz" => "__nvvm_f2ll_rz", "llvm.nvvm.f2ll.rz.ftz" => "__nvvm_f2ll_rz_ftz", + "llvm.nvvm.f2tf32.rn" => "__nvvm_f2tf32_rn", + "llvm.nvvm.f2tf32.rn.relu" => "__nvvm_f2tf32_rn_relu", + "llvm.nvvm.f2tf32.rn.relu.satfinite" => "__nvvm_f2tf32_rn_relu_satfinite", + "llvm.nvvm.f2tf32.rn.satfinite" => "__nvvm_f2tf32_rn_satfinite", "llvm.nvvm.f2tf32.rna" => "__nvvm_f2tf32_rna", + "llvm.nvvm.f2tf32.rna.satfinite" => "__nvvm_f2tf32_rna_satfinite", + "llvm.nvvm.f2tf32.rz" => "__nvvm_f2tf32_rz", + "llvm.nvvm.f2tf32.rz.relu" => "__nvvm_f2tf32_rz_relu", + "llvm.nvvm.f2tf32.rz.relu.satfinite" => "__nvvm_f2tf32_rz_relu_satfinite", + "llvm.nvvm.f2tf32.rz.satfinite" => "__nvvm_f2tf32_rz_satfinite", "llvm.nvvm.f2ui.rm" => "__nvvm_f2ui_rm", "llvm.nvvm.f2ui.rm.ftz" => "__nvvm_f2ui_rm_ftz", "llvm.nvvm.f2ui.rn" => "__nvvm_f2ui_rn", @@ -4589,10 +4725,18 @@ match name { "llvm.nvvm.fabs.d" => "__nvvm_fabs_d", "llvm.nvvm.fabs.f" => "__nvvm_fabs_f", "llvm.nvvm.fabs.ftz.f" => "__nvvm_fabs_ftz_f", + "llvm.nvvm.ff.to.e2m3x2.rn.relu.satfinite" => "__nvvm_ff_to_e2m3x2_rn_relu_satfinite", + "llvm.nvvm.ff.to.e2m3x2.rn.satfinite" => "__nvvm_ff_to_e2m3x2_rn_satfinite", + "llvm.nvvm.ff.to.e3m2x2.rn.relu.satfinite" => "__nvvm_ff_to_e3m2x2_rn_relu_satfinite", + "llvm.nvvm.ff.to.e3m2x2.rn.satfinite" => "__nvvm_ff_to_e3m2x2_rn_satfinite", "llvm.nvvm.ff.to.e4m3x2.rn" => "__nvvm_ff_to_e4m3x2_rn", "llvm.nvvm.ff.to.e4m3x2.rn.relu" => "__nvvm_ff_to_e4m3x2_rn_relu", "llvm.nvvm.ff.to.e5m2x2.rn" => "__nvvm_ff_to_e5m2x2_rn", "llvm.nvvm.ff.to.e5m2x2.rn.relu" => "__nvvm_ff_to_e5m2x2_rn_relu", + "llvm.nvvm.ff.to.ue8m0x2.rp" => "__nvvm_ff_to_ue8m0x2_rp", + "llvm.nvvm.ff.to.ue8m0x2.rp.satfinite" => "__nvvm_ff_to_ue8m0x2_rp_satfinite", + "llvm.nvvm.ff.to.ue8m0x2.rz" => "__nvvm_ff_to_ue8m0x2_rz", + "llvm.nvvm.ff.to.ue8m0x2.rz.satfinite" => "__nvvm_ff_to_ue8m0x2_rz_satfinite", "llvm.nvvm.ff2bf16x2.rn" => "__nvvm_ff2bf16x2_rn", "llvm.nvvm.ff2bf16x2.rn.relu" => "__nvvm_ff2bf16x2_rn_relu", "llvm.nvvm.ff2bf16x2.rz" => "__nvvm_ff2bf16x2_rz", @@ -4862,6 +5006,14 @@ match name { // [DUPLICATE]: "llvm.nvvm.read.ptx.sreg.warpsize" => "__nvvm_read_ptx_sreg_", "llvm.nvvm.redux.sync.add" => "__nvvm_redux_sync_add", "llvm.nvvm.redux.sync.and" => "__nvvm_redux_sync_and", + "llvm.nvvm.redux.sync.fmax" => "__nvvm_redux_sync_fmax", + "llvm.nvvm.redux.sync.fmax.NaN" => "__nvvm_redux_sync_fmax_NaN", + "llvm.nvvm.redux.sync.fmax.abs" => "__nvvm_redux_sync_fmax_abs", + "llvm.nvvm.redux.sync.fmax.abs.NaN" => "__nvvm_redux_sync_fmax_abs_NaN", + "llvm.nvvm.redux.sync.fmin" => "__nvvm_redux_sync_fmin", + "llvm.nvvm.redux.sync.fmin.NaN" => "__nvvm_redux_sync_fmin_NaN", + "llvm.nvvm.redux.sync.fmin.abs" => "__nvvm_redux_sync_fmin_abs", + "llvm.nvvm.redux.sync.fmin.abs.NaN" => "__nvvm_redux_sync_fmin_abs_NaN", "llvm.nvvm.redux.sync.max" => "__nvvm_redux_sync_max", "llvm.nvvm.redux.sync.min" => "__nvvm_redux_sync_min", "llvm.nvvm.redux.sync.or" => "__nvvm_redux_sync_or", @@ -5149,6 +5301,7 @@ match name { "llvm.nvvm.txq.num.mipmap.levels" => "__nvvm_txq_num_mipmap_levels", "llvm.nvvm.txq.num.samples" => "__nvvm_txq_num_samples", "llvm.nvvm.txq.width" => "__nvvm_txq_width", + "llvm.nvvm.ue8m0x2.to.bf16x2" => "__nvvm_ue8m0x2_to_bf16x2", "llvm.nvvm.ui2d.rm" => "__nvvm_ui2d_rm", "llvm.nvvm.ui2d.rn" => "__nvvm_ui2d_rn", "llvm.nvvm.ui2d.rp" => "__nvvm_ui2d_rp", @@ -5783,6 +5936,9 @@ match name { "llvm.r600.read.tgid.x" => "__builtin_r600_read_tgid_x", "llvm.r600.read.tgid.y" => "__builtin_r600_read_tgid_y", "llvm.r600.read.tgid.z" => "__builtin_r600_read_tgid_z", + "llvm.r600.read.tidig.x" => "__builtin_r600_read_tidig_x", + "llvm.r600.read.tidig.y" => "__builtin_r600_read_tidig_y", + "llvm.r600.read.tidig.z" => "__builtin_r600_read_tidig_z", // riscv "llvm.riscv.aes32dsi" => "__builtin_riscv_aes32dsi", "llvm.riscv.aes32dsmi" => "__builtin_riscv_aes32dsmi", @@ -5806,6 +5962,8 @@ match name { "llvm.riscv.sha512sum1" => "__builtin_riscv_sha512sum1", "llvm.riscv.sha512sum1r" => "__builtin_riscv_sha512sum1r", // s390 + "llvm.s390.bdepg" => "__builtin_s390_bdepg", + "llvm.s390.bextg" => "__builtin_s390_bextg", "llvm.s390.efpc" => "__builtin_s390_efpc", "llvm.s390.etnd" => "__builtin_tx_nesting_depth", "llvm.s390.lcbb" => "__builtin_s390_lcbb", @@ -5828,6 +5986,8 @@ match name { "llvm.s390.vavglf" => "__builtin_s390_vavglf", "llvm.s390.vavglg" => "__builtin_s390_vavglg", "llvm.s390.vavglh" => "__builtin_s390_vavglh", + "llvm.s390.vavglq" => "__builtin_s390_vavglq", + "llvm.s390.vavgq" => "__builtin_s390_vavgq", "llvm.s390.vbperm" => "__builtin_s390_vbperm", "llvm.s390.vcfn" => "__builtin_s390_vcfn", "llvm.s390.vcksm" => "__builtin_s390_vcksm", @@ -5839,6 +5999,7 @@ match name { "llvm.s390.verimf" => "__builtin_s390_verimf", "llvm.s390.verimg" => "__builtin_s390_verimg", "llvm.s390.verimh" => "__builtin_s390_verimh", + "llvm.s390.veval" => "__builtin_s390_veval", "llvm.s390.vfaeb" => "__builtin_s390_vfaeb", "llvm.s390.vfaef" => "__builtin_s390_vfaef", "llvm.s390.vfaeh" => "__builtin_s390_vfaeh", @@ -5857,6 +6018,11 @@ match name { "llvm.s390.vfenezb" => "__builtin_s390_vfenezb", "llvm.s390.vfenezf" => "__builtin_s390_vfenezf", "llvm.s390.vfenezh" => "__builtin_s390_vfenezh", + "llvm.s390.vgemb" => "__builtin_s390_vgemb", + "llvm.s390.vgemf" => "__builtin_s390_vgemf", + "llvm.s390.vgemg" => "__builtin_s390_vgemg", + "llvm.s390.vgemh" => "__builtin_s390_vgemh", + "llvm.s390.vgemq" => "__builtin_s390_vgemq", "llvm.s390.vgfmab" => "__builtin_s390_vgfmab", "llvm.s390.vgfmaf" => "__builtin_s390_vgfmaf", "llvm.s390.vgfmag" => "__builtin_s390_vgfmag", @@ -5873,39 +6039,55 @@ match name { "llvm.s390.vlrl" => "__builtin_s390_vlrlr", "llvm.s390.vmaeb" => "__builtin_s390_vmaeb", "llvm.s390.vmaef" => "__builtin_s390_vmaef", + "llvm.s390.vmaeg" => "__builtin_s390_vmaeg", "llvm.s390.vmaeh" => "__builtin_s390_vmaeh", "llvm.s390.vmahb" => "__builtin_s390_vmahb", "llvm.s390.vmahf" => "__builtin_s390_vmahf", + "llvm.s390.vmahg" => "__builtin_s390_vmahg", "llvm.s390.vmahh" => "__builtin_s390_vmahh", + "llvm.s390.vmahq" => "__builtin_s390_vmahq", "llvm.s390.vmaleb" => "__builtin_s390_vmaleb", "llvm.s390.vmalef" => "__builtin_s390_vmalef", + "llvm.s390.vmaleg" => "__builtin_s390_vmaleg", "llvm.s390.vmaleh" => "__builtin_s390_vmaleh", "llvm.s390.vmalhb" => "__builtin_s390_vmalhb", "llvm.s390.vmalhf" => "__builtin_s390_vmalhf", + "llvm.s390.vmalhg" => "__builtin_s390_vmalhg", "llvm.s390.vmalhh" => "__builtin_s390_vmalhh", + "llvm.s390.vmalhq" => "__builtin_s390_vmalhq", "llvm.s390.vmalob" => "__builtin_s390_vmalob", "llvm.s390.vmalof" => "__builtin_s390_vmalof", + "llvm.s390.vmalog" => "__builtin_s390_vmalog", "llvm.s390.vmaloh" => "__builtin_s390_vmaloh", "llvm.s390.vmaob" => "__builtin_s390_vmaob", "llvm.s390.vmaof" => "__builtin_s390_vmaof", + "llvm.s390.vmaog" => "__builtin_s390_vmaog", "llvm.s390.vmaoh" => "__builtin_s390_vmaoh", "llvm.s390.vmeb" => "__builtin_s390_vmeb", "llvm.s390.vmef" => "__builtin_s390_vmef", + "llvm.s390.vmeg" => "__builtin_s390_vmeg", "llvm.s390.vmeh" => "__builtin_s390_vmeh", "llvm.s390.vmhb" => "__builtin_s390_vmhb", "llvm.s390.vmhf" => "__builtin_s390_vmhf", + "llvm.s390.vmhg" => "__builtin_s390_vmhg", "llvm.s390.vmhh" => "__builtin_s390_vmhh", + "llvm.s390.vmhq" => "__builtin_s390_vmhq", "llvm.s390.vmleb" => "__builtin_s390_vmleb", "llvm.s390.vmlef" => "__builtin_s390_vmlef", + "llvm.s390.vmleg" => "__builtin_s390_vmleg", "llvm.s390.vmleh" => "__builtin_s390_vmleh", "llvm.s390.vmlhb" => "__builtin_s390_vmlhb", "llvm.s390.vmlhf" => "__builtin_s390_vmlhf", + "llvm.s390.vmlhg" => "__builtin_s390_vmlhg", "llvm.s390.vmlhh" => "__builtin_s390_vmlhh", + "llvm.s390.vmlhq" => "__builtin_s390_vmlhq", "llvm.s390.vmlob" => "__builtin_s390_vmlob", "llvm.s390.vmlof" => "__builtin_s390_vmlof", + "llvm.s390.vmlog" => "__builtin_s390_vmlog", "llvm.s390.vmloh" => "__builtin_s390_vmloh", "llvm.s390.vmob" => "__builtin_s390_vmob", "llvm.s390.vmof" => "__builtin_s390_vmof", + "llvm.s390.vmog" => "__builtin_s390_vmog", "llvm.s390.vmoh" => "__builtin_s390_vmoh", "llvm.s390.vmslg" => "__builtin_s390_vmslg", "llvm.s390.vpdi" => "__builtin_s390_vpdi", @@ -5950,18 +6132,20 @@ match name { "llvm.s390.vtm" => "__builtin_s390_vtm", "llvm.s390.vuphb" => "__builtin_s390_vuphb", "llvm.s390.vuphf" => "__builtin_s390_vuphf", + "llvm.s390.vuphg" => "__builtin_s390_vuphg", "llvm.s390.vuphh" => "__builtin_s390_vuphh", "llvm.s390.vuplb" => "__builtin_s390_vuplb", "llvm.s390.vuplf" => "__builtin_s390_vuplf", + "llvm.s390.vuplg" => "__builtin_s390_vuplg", "llvm.s390.vuplhb" => "__builtin_s390_vuplhb", "llvm.s390.vuplhf" => "__builtin_s390_vuplhf", + "llvm.s390.vuplhg" => "__builtin_s390_vuplhg", "llvm.s390.vuplhh" => "__builtin_s390_vuplhh", "llvm.s390.vuplhw" => "__builtin_s390_vuplhw", "llvm.s390.vupllb" => "__builtin_s390_vupllb", "llvm.s390.vupllf" => "__builtin_s390_vupllf", + "llvm.s390.vupllg" => "__builtin_s390_vupllg", "llvm.s390.vupllh" => "__builtin_s390_vupllh", - // spv - "llvm.spv.create.handle" => "__builtin_hlsl_create_handle", // ve "llvm.ve.vl.andm.MMM" => "__builtin_ve_vl_andm_MMM", "llvm.ve.vl.andm.mmm" => "__builtin_ve_vl_andm_mmm", @@ -7328,6 +7512,27 @@ match name { "llvm.x86.avx.vtestz.ps.256" => "__builtin_ia32_vtestzps256", "llvm.x86.avx.vzeroall" => "__builtin_ia32_vzeroall", "llvm.x86.avx.vzeroupper" => "__builtin_ia32_vzeroupper", + "llvm.x86.avx10.mask.getexp.bf16.128" => "__builtin_ia32_vgetexpbf16128_mask", + "llvm.x86.avx10.mask.getexp.bf16.256" => "__builtin_ia32_vgetexpbf16256_mask", + "llvm.x86.avx10.mask.getexp.bf16.512" => "__builtin_ia32_vgetexpbf16512_mask", + "llvm.x86.avx10.mask.getmant.bf16.128" => "__builtin_ia32_vgetmantbf16128_mask", + "llvm.x86.avx10.mask.getmant.bf16.256" => "__builtin_ia32_vgetmantbf16256_mask", + "llvm.x86.avx10.mask.getmant.bf16.512" => "__builtin_ia32_vgetmantbf16512_mask", + "llvm.x86.avx10.mask.rcp.bf16.128" => "__builtin_ia32_vrcpbf16128_mask", + "llvm.x86.avx10.mask.rcp.bf16.256" => "__builtin_ia32_vrcpbf16256_mask", + "llvm.x86.avx10.mask.rcp.bf16.512" => "__builtin_ia32_vrcpbf16512_mask", + "llvm.x86.avx10.mask.reduce.bf16.128" => "__builtin_ia32_vreducebf16128_mask", + "llvm.x86.avx10.mask.reduce.bf16.256" => "__builtin_ia32_vreducebf16256_mask", + "llvm.x86.avx10.mask.reduce.bf16.512" => "__builtin_ia32_vreducebf16512_mask", + "llvm.x86.avx10.mask.rndscale.bf16.128" => "__builtin_ia32_vrndscalebf16_128_mask", + "llvm.x86.avx10.mask.rndscale.bf16.256" => "__builtin_ia32_vrndscalebf16_256_mask", + "llvm.x86.avx10.mask.rndscale.bf16.512" => "__builtin_ia32_vrndscalebf16_mask", + "llvm.x86.avx10.mask.rsqrt.bf16.128" => "__builtin_ia32_vrsqrtbf16128_mask", + "llvm.x86.avx10.mask.rsqrt.bf16.256" => "__builtin_ia32_vrsqrtbf16256_mask", + "llvm.x86.avx10.mask.rsqrt.bf16.512" => "__builtin_ia32_vrsqrtbf16512_mask", + "llvm.x86.avx10.mask.scalef.bf16.128" => "__builtin_ia32_vscalefbf16128_mask", + "llvm.x86.avx10.mask.scalef.bf16.256" => "__builtin_ia32_vscalefbf16256_mask", + "llvm.x86.avx10.mask.scalef.bf16.512" => "__builtin_ia32_vscalefbf16512_mask", "llvm.x86.avx10.mask.vcvt2ps2phx.128" => "__builtin_ia32_vcvt2ps2phx128_mask", "llvm.x86.avx10.mask.vcvt2ps2phx.256" => "__builtin_ia32_vcvt2ps2phx256_mask", "llvm.x86.avx10.mask.vcvt2ps2phx.512" => "__builtin_ia32_vcvt2ps2phx512_mask", @@ -7346,171 +7551,194 @@ match name { "llvm.x86.avx10.mask.vcvthf82ph128" => "__builtin_ia32_vcvthf8_2ph128_mask", "llvm.x86.avx10.mask.vcvthf82ph256" => "__builtin_ia32_vcvthf8_2ph256_mask", "llvm.x86.avx10.mask.vcvthf82ph512" => "__builtin_ia32_vcvthf8_2ph512_mask", - "llvm.x86.avx10.mask.vcvtneph2bf8128" => "__builtin_ia32_vcvtneph2bf8_128_mask", - "llvm.x86.avx10.mask.vcvtneph2bf8256" => "__builtin_ia32_vcvtneph2bf8_256_mask", - "llvm.x86.avx10.mask.vcvtneph2bf8512" => "__builtin_ia32_vcvtneph2bf8_512_mask", - "llvm.x86.avx10.mask.vcvtneph2bf8s128" => "__builtin_ia32_vcvtneph2bf8s_128_mask", - "llvm.x86.avx10.mask.vcvtneph2bf8s256" => "__builtin_ia32_vcvtneph2bf8s_256_mask", - "llvm.x86.avx10.mask.vcvtneph2bf8s512" => "__builtin_ia32_vcvtneph2bf8s_512_mask", - "llvm.x86.avx10.mask.vcvtneph2hf8128" => "__builtin_ia32_vcvtneph2hf8_128_mask", - "llvm.x86.avx10.mask.vcvtneph2hf8256" => "__builtin_ia32_vcvtneph2hf8_256_mask", - "llvm.x86.avx10.mask.vcvtneph2hf8512" => "__builtin_ia32_vcvtneph2hf8_512_mask", - "llvm.x86.avx10.mask.vcvtneph2hf8s128" => "__builtin_ia32_vcvtneph2hf8s_128_mask", - "llvm.x86.avx10.mask.vcvtneph2hf8s256" => "__builtin_ia32_vcvtneph2hf8s_256_mask", - "llvm.x86.avx10.mask.vcvtneph2hf8s512" => "__builtin_ia32_vcvtneph2hf8s_512_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtpd2dq256" => "__builtin_ia32_vcvtpd2dq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtpd2ph256" => "__builtin_ia32_vcvtpd2ph256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtpd2ps256" => "__builtin_ia32_vcvtpd2ps256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtpd2qq256" => "__builtin_ia32_vcvtpd2qq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtpd2udq256" => "__builtin_ia32_vcvtpd2udq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtpd2uqq256" => "__builtin_ia32_vcvtpd2uqq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2dq256" => "__builtin_ia32_vcvtph2dq256_round_mask", + "llvm.x86.avx10.mask.vcvtph2bf8128" => "__builtin_ia32_vcvtph2bf8_128_mask", + "llvm.x86.avx10.mask.vcvtph2bf8256" => "__builtin_ia32_vcvtph2bf8_256_mask", + "llvm.x86.avx10.mask.vcvtph2bf8512" => "__builtin_ia32_vcvtph2bf8_512_mask", + "llvm.x86.avx10.mask.vcvtph2bf8s128" => "__builtin_ia32_vcvtph2bf8s_128_mask", + "llvm.x86.avx10.mask.vcvtph2bf8s256" => "__builtin_ia32_vcvtph2bf8s_256_mask", + "llvm.x86.avx10.mask.vcvtph2bf8s512" => "__builtin_ia32_vcvtph2bf8s_512_mask", + "llvm.x86.avx10.mask.vcvtph2hf8128" => "__builtin_ia32_vcvtph2hf8_128_mask", + "llvm.x86.avx10.mask.vcvtph2hf8256" => "__builtin_ia32_vcvtph2hf8_256_mask", + "llvm.x86.avx10.mask.vcvtph2hf8512" => "__builtin_ia32_vcvtph2hf8_512_mask", + "llvm.x86.avx10.mask.vcvtph2hf8s128" => "__builtin_ia32_vcvtph2hf8s_128_mask", + "llvm.x86.avx10.mask.vcvtph2hf8s256" => "__builtin_ia32_vcvtph2hf8s_256_mask", + "llvm.x86.avx10.mask.vcvtph2hf8s512" => "__builtin_ia32_vcvtph2hf8s_512_mask", "llvm.x86.avx10.mask.vcvtph2ibs128" => "__builtin_ia32_vcvtph2ibs128_mask", "llvm.x86.avx10.mask.vcvtph2ibs256" => "__builtin_ia32_vcvtph2ibs256_mask", "llvm.x86.avx10.mask.vcvtph2ibs512" => "__builtin_ia32_vcvtph2ibs512_mask", "llvm.x86.avx10.mask.vcvtph2iubs128" => "__builtin_ia32_vcvtph2iubs128_mask", "llvm.x86.avx10.mask.vcvtph2iubs256" => "__builtin_ia32_vcvtph2iubs256_mask", "llvm.x86.avx10.mask.vcvtph2iubs512" => "__builtin_ia32_vcvtph2iubs512_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2pd256" => "__builtin_ia32_vcvtph2pd256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2psx256" => "__builtin_ia32_vcvtph2psx256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2qq256" => "__builtin_ia32_vcvtph2qq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2udq256" => "__builtin_ia32_vcvtph2udq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2uqq256" => "__builtin_ia32_vcvtph2uqq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2uw256" => "__builtin_ia32_vcvtph2uw256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2w256" => "__builtin_ia32_vcvtph2w256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2dq256" => "__builtin_ia32_vcvtps2dq256_round_mask", "llvm.x86.avx10.mask.vcvtps2ibs128" => "__builtin_ia32_vcvtps2ibs128_mask", "llvm.x86.avx10.mask.vcvtps2ibs256" => "__builtin_ia32_vcvtps2ibs256_mask", "llvm.x86.avx10.mask.vcvtps2ibs512" => "__builtin_ia32_vcvtps2ibs512_mask", "llvm.x86.avx10.mask.vcvtps2iubs128" => "__builtin_ia32_vcvtps2iubs128_mask", "llvm.x86.avx10.mask.vcvtps2iubs256" => "__builtin_ia32_vcvtps2iubs256_mask", "llvm.x86.avx10.mask.vcvtps2iubs512" => "__builtin_ia32_vcvtps2iubs512_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2pd256" => "__builtin_ia32_vcvtps2pd256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2ph256" => "__builtin_ia32_vcvtps2ph256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2phx256" => "__builtin_ia32_vcvtps2phx256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2qq256" => "__builtin_ia32_vcvtps2qq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2udq256" => "__builtin_ia32_vcvtps2udq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2uqq256" => "__builtin_ia32_vcvtps2uqq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttpd2dq256" => "__builtin_ia32_vcvttpd2dq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttpd2qq256" => "__builtin_ia32_vcvttpd2qq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttpd2udq256" => "__builtin_ia32_vcvttpd2udq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttpd2uqq256" => "__builtin_ia32_vcvttpd2uqq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttph2dq256" => "__builtin_ia32_vcvttph2dq256_round_mask", + "llvm.x86.avx10.mask.vcvttpd2dqs.128" => "__builtin_ia32_vcvttpd2dqs128_mask", + "llvm.x86.avx10.mask.vcvttpd2dqs.256" => "__builtin_ia32_vcvttpd2dqs256_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttpd2dqs.round.512" => "__builtin_ia32_vcvttpd2dqs512_round_mask", + "llvm.x86.avx10.mask.vcvttpd2qqs.128" => "__builtin_ia32_vcvttpd2qqs128_mask", + "llvm.x86.avx10.mask.vcvttpd2qqs.256" => "__builtin_ia32_vcvttpd2qqs256_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttpd2qqs.round.512" => "__builtin_ia32_vcvttpd2qqs512_round_mask", + "llvm.x86.avx10.mask.vcvttpd2udqs.128" => "__builtin_ia32_vcvttpd2udqs128_mask", + "llvm.x86.avx10.mask.vcvttpd2udqs.256" => "__builtin_ia32_vcvttpd2udqs256_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttpd2udqs.round.512" => "__builtin_ia32_vcvttpd2udqs512_round_mask", + "llvm.x86.avx10.mask.vcvttpd2uqqs.128" => "__builtin_ia32_vcvttpd2uqqs128_mask", + "llvm.x86.avx10.mask.vcvttpd2uqqs.256" => "__builtin_ia32_vcvttpd2uqqs256_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttpd2uqqs.round.512" => "__builtin_ia32_vcvttpd2uqqs512_round_mask", "llvm.x86.avx10.mask.vcvttph2ibs128" => "__builtin_ia32_vcvttph2ibs128_mask", "llvm.x86.avx10.mask.vcvttph2ibs256" => "__builtin_ia32_vcvttph2ibs256_mask", "llvm.x86.avx10.mask.vcvttph2ibs512" => "__builtin_ia32_vcvttph2ibs512_mask", "llvm.x86.avx10.mask.vcvttph2iubs128" => "__builtin_ia32_vcvttph2iubs128_mask", "llvm.x86.avx10.mask.vcvttph2iubs256" => "__builtin_ia32_vcvttph2iubs256_mask", "llvm.x86.avx10.mask.vcvttph2iubs512" => "__builtin_ia32_vcvttph2iubs512_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttph2qq256" => "__builtin_ia32_vcvttph2qq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttph2udq256" => "__builtin_ia32_vcvttph2udq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttph2uqq256" => "__builtin_ia32_vcvttph2uqq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttph2uw256" => "__builtin_ia32_vcvttph2uw256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttph2w256" => "__builtin_ia32_vcvttph2w256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttps2dq256" => "__builtin_ia32_vcvttps2dq256_round_mask", + "llvm.x86.avx10.mask.vcvttps2dqs.128" => "__builtin_ia32_vcvttps2dqs128_mask", + "llvm.x86.avx10.mask.vcvttps2dqs.256" => "__builtin_ia32_vcvttps2dqs256_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttps2dqs.round.512" => "__builtin_ia32_vcvttps2dqs512_round_mask", "llvm.x86.avx10.mask.vcvttps2ibs128" => "__builtin_ia32_vcvttps2ibs128_mask", "llvm.x86.avx10.mask.vcvttps2ibs256" => "__builtin_ia32_vcvttps2ibs256_mask", "llvm.x86.avx10.mask.vcvttps2ibs512" => "__builtin_ia32_vcvttps2ibs512_mask", "llvm.x86.avx10.mask.vcvttps2iubs128" => "__builtin_ia32_vcvttps2iubs128_mask", "llvm.x86.avx10.mask.vcvttps2iubs256" => "__builtin_ia32_vcvttps2iubs256_mask", "llvm.x86.avx10.mask.vcvttps2iubs512" => "__builtin_ia32_vcvttps2iubs512_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttps2qq256" => "__builtin_ia32_vcvttps2qq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttps2udq256" => "__builtin_ia32_vcvttps2udq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttps2uqq256" => "__builtin_ia32_vcvttps2uqq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vfcmaddcph256" => "__builtin_ia32_vfcmaddcph256_round_mask3", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vfcmulcph256" => "__builtin_ia32_vfcmulcph256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vfixupimmpd256" => "__builtin_ia32_vfixupimmpd256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vfixupimmps256" => "__builtin_ia32_vfixupimmps256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vfmaddcph256" => "__builtin_ia32_vfmaddcph256_round_mask3", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vfmulcph256" => "__builtin_ia32_vfmulcph256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vgetexppd256" => "__builtin_ia32_vgetexppd256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vgetexpph256" => "__builtin_ia32_vgetexpph256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vgetexpps256" => "__builtin_ia32_vgetexpps256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vgetmantpd256" => "__builtin_ia32_vgetmantpd256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vgetmantph256" => "__builtin_ia32_vgetmantph256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vgetmantps256" => "__builtin_ia32_vgetmantps256_round_mask", + "llvm.x86.avx10.mask.vcvttps2qqs.128" => "__builtin_ia32_vcvttps2qqs128_mask", + "llvm.x86.avx10.mask.vcvttps2qqs.256" => "__builtin_ia32_vcvttps2qqs256_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttps2qqs.round.512" => "__builtin_ia32_vcvttps2qqs512_round_mask", + "llvm.x86.avx10.mask.vcvttps2udqs.128" => "__builtin_ia32_vcvttps2udqs128_mask", + "llvm.x86.avx10.mask.vcvttps2udqs.256" => "__builtin_ia32_vcvttps2udqs256_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttps2udqs.round.512" => "__builtin_ia32_vcvttps2udqs512_round_mask", + "llvm.x86.avx10.mask.vcvttps2uqqs.128" => "__builtin_ia32_vcvttps2uqqs128_mask", + "llvm.x86.avx10.mask.vcvttps2uqqs.256" => "__builtin_ia32_vcvttps2uqqs256_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttps2uqqs.round.512" => "__builtin_ia32_vcvttps2uqqs512_round_mask", // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxpd.round" => "__builtin_ia32_vminmaxpd512_round_mask", "llvm.x86.avx10.mask.vminmaxpd128" => "__builtin_ia32_vminmaxpd128_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxpd256.round" => "__builtin_ia32_vminmaxpd256_round_mask", + "llvm.x86.avx10.mask.vminmaxpd256" => "__builtin_ia32_vminmaxpd256_mask", // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxph.round" => "__builtin_ia32_vminmaxph512_round_mask", "llvm.x86.avx10.mask.vminmaxph128" => "__builtin_ia32_vminmaxph128_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxph256.round" => "__builtin_ia32_vminmaxph256_round_mask", + "llvm.x86.avx10.mask.vminmaxph256" => "__builtin_ia32_vminmaxph256_mask", // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxps.round" => "__builtin_ia32_vminmaxps512_round_mask", "llvm.x86.avx10.mask.vminmaxps128" => "__builtin_ia32_vminmaxps128_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxps256.round" => "__builtin_ia32_vminmaxps256_round_mask", + "llvm.x86.avx10.mask.vminmaxps256" => "__builtin_ia32_vminmaxps256_mask", // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxsd.round" => "__builtin_ia32_vminmaxsd_round_mask", // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxsh.round" => "__builtin_ia32_vminmaxsh_round_mask", // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxss.round" => "__builtin_ia32_vminmaxss_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vrangepd256" => "__builtin_ia32_vrangepd256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vrangeps256" => "__builtin_ia32_vrangeps256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vreducepd256" => "__builtin_ia32_vreducepd256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vreduceph256" => "__builtin_ia32_vreduceph256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vreduceps256" => "__builtin_ia32_vreduceps256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vrndscalepd256" => "__builtin_ia32_vrndscalepd256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vrndscaleph256" => "__builtin_ia32_vrndscaleph256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vrndscaleps256" => "__builtin_ia32_vrndscaleps256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vscalefpd256" => "__builtin_ia32_vscalefpd256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vscalefph256" => "__builtin_ia32_vscalefph256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vscalefps256" => "__builtin_ia32_vscalefps256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.maskz.vfcmaddcph256" => "__builtin_ia32_vfcmaddcph256_round_maskz", - // [INVALID CONVERSION]: "llvm.x86.avx10.maskz.vfixupimmpd256" => "__builtin_ia32_vfixupimmpd256_round_maskz", - // [INVALID CONVERSION]: "llvm.x86.avx10.maskz.vfixupimmps256" => "__builtin_ia32_vfixupimmps256_round_maskz", - // [INVALID CONVERSION]: "llvm.x86.avx10.maskz.vfmaddcph256" => "__builtin_ia32_vfmaddcph256_round_maskz", + "llvm.x86.avx10.vaddbf16128" => "__builtin_ia32_vaddbf16128", + "llvm.x86.avx10.vaddbf16256" => "__builtin_ia32_vaddbf16256", + "llvm.x86.avx10.vaddbf16512" => "__builtin_ia32_vaddbf16512", "llvm.x86.avx10.vaddpd256" => "__builtin_ia32_vaddpd256_round", "llvm.x86.avx10.vaddph256" => "__builtin_ia32_vaddph256_round", "llvm.x86.avx10.vaddps256" => "__builtin_ia32_vaddps256_round", - "llvm.x86.avx10.vcvtne2ph2bf8128" => "__builtin_ia32_vcvtne2ph2bf8_128", - "llvm.x86.avx10.vcvtne2ph2bf8256" => "__builtin_ia32_vcvtne2ph2bf8_256", - "llvm.x86.avx10.vcvtne2ph2bf8512" => "__builtin_ia32_vcvtne2ph2bf8_512", - "llvm.x86.avx10.vcvtne2ph2bf8s128" => "__builtin_ia32_vcvtne2ph2bf8s_128", - "llvm.x86.avx10.vcvtne2ph2bf8s256" => "__builtin_ia32_vcvtne2ph2bf8s_256", - "llvm.x86.avx10.vcvtne2ph2bf8s512" => "__builtin_ia32_vcvtne2ph2bf8s_512", - "llvm.x86.avx10.vcvtne2ph2hf8128" => "__builtin_ia32_vcvtne2ph2hf8_128", - "llvm.x86.avx10.vcvtne2ph2hf8256" => "__builtin_ia32_vcvtne2ph2hf8_256", - "llvm.x86.avx10.vcvtne2ph2hf8512" => "__builtin_ia32_vcvtne2ph2hf8_512", - "llvm.x86.avx10.vcvtne2ph2hf8s128" => "__builtin_ia32_vcvtne2ph2hf8s_128", - "llvm.x86.avx10.vcvtne2ph2hf8s256" => "__builtin_ia32_vcvtne2ph2hf8s_256", - "llvm.x86.avx10.vcvtne2ph2hf8s512" => "__builtin_ia32_vcvtne2ph2hf8s_512", - "llvm.x86.avx10.vcvtnebf162ibs128" => "__builtin_ia32_vcvtnebf162ibs128", - "llvm.x86.avx10.vcvtnebf162ibs256" => "__builtin_ia32_vcvtnebf162ibs256", - "llvm.x86.avx10.vcvtnebf162ibs512" => "__builtin_ia32_vcvtnebf162ibs512", - "llvm.x86.avx10.vcvtnebf162iubs128" => "__builtin_ia32_vcvtnebf162iubs128", - "llvm.x86.avx10.vcvtnebf162iubs256" => "__builtin_ia32_vcvtnebf162iubs256", - "llvm.x86.avx10.vcvtnebf162iubs512" => "__builtin_ia32_vcvtnebf162iubs512", - "llvm.x86.avx10.vcvttnebf162ibs128" => "__builtin_ia32_vcvttnebf162ibs128", - "llvm.x86.avx10.vcvttnebf162ibs256" => "__builtin_ia32_vcvttnebf162ibs256", - "llvm.x86.avx10.vcvttnebf162ibs512" => "__builtin_ia32_vcvttnebf162ibs512", - "llvm.x86.avx10.vcvttnebf162iubs128" => "__builtin_ia32_vcvttnebf162iubs128", - "llvm.x86.avx10.vcvttnebf162iubs256" => "__builtin_ia32_vcvttnebf162iubs256", - "llvm.x86.avx10.vcvttnebf162iubs512" => "__builtin_ia32_vcvttnebf162iubs512", - "llvm.x86.avx10.vdivpd256" => "__builtin_ia32_vdivpd256_round", - "llvm.x86.avx10.vdivph256" => "__builtin_ia32_vdivph256_round", - "llvm.x86.avx10.vdivps256" => "__builtin_ia32_vdivps256_round", + "llvm.x86.avx10.vcomisbf16eq" => "__builtin_ia32_vcomisbf16eq", + "llvm.x86.avx10.vcomisbf16ge" => "__builtin_ia32_vcomisbf16ge", + "llvm.x86.avx10.vcomisbf16gt" => "__builtin_ia32_vcomisbf16gt", + "llvm.x86.avx10.vcomisbf16le" => "__builtin_ia32_vcomisbf16le", + "llvm.x86.avx10.vcomisbf16lt" => "__builtin_ia32_vcomisbf16lt", + "llvm.x86.avx10.vcomisbf16neq" => "__builtin_ia32_vcomisbf16neq", + "llvm.x86.avx10.vcvt2ph2bf8128" => "__builtin_ia32_vcvt2ph2bf8_128", + "llvm.x86.avx10.vcvt2ph2bf8256" => "__builtin_ia32_vcvt2ph2bf8_256", + "llvm.x86.avx10.vcvt2ph2bf8512" => "__builtin_ia32_vcvt2ph2bf8_512", + "llvm.x86.avx10.vcvt2ph2bf8s128" => "__builtin_ia32_vcvt2ph2bf8s_128", + "llvm.x86.avx10.vcvt2ph2bf8s256" => "__builtin_ia32_vcvt2ph2bf8s_256", + "llvm.x86.avx10.vcvt2ph2bf8s512" => "__builtin_ia32_vcvt2ph2bf8s_512", + "llvm.x86.avx10.vcvt2ph2hf8128" => "__builtin_ia32_vcvt2ph2hf8_128", + "llvm.x86.avx10.vcvt2ph2hf8256" => "__builtin_ia32_vcvt2ph2hf8_256", + "llvm.x86.avx10.vcvt2ph2hf8512" => "__builtin_ia32_vcvt2ph2hf8_512", + "llvm.x86.avx10.vcvt2ph2hf8s128" => "__builtin_ia32_vcvt2ph2hf8s_128", + "llvm.x86.avx10.vcvt2ph2hf8s256" => "__builtin_ia32_vcvt2ph2hf8s_256", + "llvm.x86.avx10.vcvt2ph2hf8s512" => "__builtin_ia32_vcvt2ph2hf8s_512", + "llvm.x86.avx10.vcvtbf162ibs128" => "__builtin_ia32_vcvtbf162ibs128", + "llvm.x86.avx10.vcvtbf162ibs256" => "__builtin_ia32_vcvtbf162ibs256", + "llvm.x86.avx10.vcvtbf162ibs512" => "__builtin_ia32_vcvtbf162ibs512", + "llvm.x86.avx10.vcvtbf162iubs128" => "__builtin_ia32_vcvtbf162iubs128", + "llvm.x86.avx10.vcvtbf162iubs256" => "__builtin_ia32_vcvtbf162iubs256", + "llvm.x86.avx10.vcvtbf162iubs512" => "__builtin_ia32_vcvtbf162iubs512", + "llvm.x86.avx10.vcvttbf162ibs128" => "__builtin_ia32_vcvttbf162ibs128", + "llvm.x86.avx10.vcvttbf162ibs256" => "__builtin_ia32_vcvttbf162ibs256", + "llvm.x86.avx10.vcvttbf162ibs512" => "__builtin_ia32_vcvttbf162ibs512", + "llvm.x86.avx10.vcvttbf162iubs128" => "__builtin_ia32_vcvttbf162iubs128", + "llvm.x86.avx10.vcvttbf162iubs256" => "__builtin_ia32_vcvttbf162iubs256", + "llvm.x86.avx10.vcvttbf162iubs512" => "__builtin_ia32_vcvttbf162iubs512", + "llvm.x86.avx10.vcvttsd2sis" => "__builtin_ia32_vcvttsd2sis32", + "llvm.x86.avx10.vcvttsd2sis64" => "__builtin_ia32_vcvttsd2sis64", + "llvm.x86.avx10.vcvttsd2usis" => "__builtin_ia32_vcvttsd2usis32", + "llvm.x86.avx10.vcvttsd2usis64" => "__builtin_ia32_vcvttsd2usis64", + "llvm.x86.avx10.vcvttss2sis" => "__builtin_ia32_vcvttss2sis32", + "llvm.x86.avx10.vcvttss2sis64" => "__builtin_ia32_vcvttss2sis64", + "llvm.x86.avx10.vcvttss2usis" => "__builtin_ia32_vcvttss2usis32", + "llvm.x86.avx10.vcvttss2usis64" => "__builtin_ia32_vcvttss2usis64", + "llvm.x86.avx10.vdivbf16128" => "__builtin_ia32_vdivbf16128", + "llvm.x86.avx10.vdivbf16256" => "__builtin_ia32_vdivbf16256", + "llvm.x86.avx10.vdivbf16512" => "__builtin_ia32_vdivbf16512", "llvm.x86.avx10.vdpphps.128" => "__builtin_ia32_vdpphps128", "llvm.x86.avx10.vdpphps.256" => "__builtin_ia32_vdpphps256", "llvm.x86.avx10.vdpphps.512" => "__builtin_ia32_vdpphps512", - "llvm.x86.avx10.vfmaddsubpd256" => "__builtin_ia32_vfmaddsubpd256_round", - "llvm.x86.avx10.vfmaddsubph256" => "__builtin_ia32_vfmaddsubph256_round", - "llvm.x86.avx10.vfmaddsubps256" => "__builtin_ia32_vfmaddsubps256_round", - "llvm.x86.avx10.vmaxpd256" => "__builtin_ia32_vmaxpd256_round", - "llvm.x86.avx10.vmaxph256" => "__builtin_ia32_vmaxph256_round", - "llvm.x86.avx10.vmaxps256" => "__builtin_ia32_vmaxps256_round", - "llvm.x86.avx10.vminmaxnepbf16128" => "__builtin_ia32_vminmaxnepbf16128", - "llvm.x86.avx10.vminmaxnepbf16256" => "__builtin_ia32_vminmaxnepbf16256", - "llvm.x86.avx10.vminmaxnepbf16512" => "__builtin_ia32_vminmaxnepbf16512", + "llvm.x86.avx10.vfmadd132bf16128" => "__builtin_ia32_vfmadd132bf16128", + "llvm.x86.avx10.vfmadd132bf16256" => "__builtin_ia32_vfmadd132bf16256", + "llvm.x86.avx10.vfmadd132bf16512" => "__builtin_ia32_vfmadd132bf16512", + "llvm.x86.avx10.vfmadd213bf16128" => "__builtin_ia32_vfmadd213bf16128", + "llvm.x86.avx10.vfmadd213bf16256" => "__builtin_ia32_vfmadd213bf16256", + "llvm.x86.avx10.vfmadd231bf16128" => "__builtin_ia32_vfmadd231bf16128", + "llvm.x86.avx10.vfmadd231bf16256" => "__builtin_ia32_vfmadd231bf16256", + "llvm.x86.avx10.vfmadd231bf16512" => "__builtin_ia32_vfmadd231bf16512", + "llvm.x86.avx10.vfmsub132bf16128" => "__builtin_ia32_vfmsub132bf16128", + "llvm.x86.avx10.vfmsub132bf16256" => "__builtin_ia32_vfmsub132bf16256", + "llvm.x86.avx10.vfmsub132bf16512" => "__builtin_ia32_vfmsub132bf16512", + "llvm.x86.avx10.vfmsub213bf16128" => "__builtin_ia32_vfmsub213bf16128", + "llvm.x86.avx10.vfmsub213bf16256" => "__builtin_ia32_vfmsub213bf16256", + "llvm.x86.avx10.vfmsub213bf16512" => "__builtin_ia32_vfmsub213bf16512", + "llvm.x86.avx10.vfmsub231bf16128" => "__builtin_ia32_vfmsub231bf16128", + "llvm.x86.avx10.vfmsub231bf16256" => "__builtin_ia32_vfmsub231bf16256", + "llvm.x86.avx10.vfmsub231bf16512" => "__builtin_ia32_vfmsub231bf16512", + "llvm.x86.avx10.vfnmadd132bf16128" => "__builtin_ia32_vfnmadd132bf16128", + "llvm.x86.avx10.vfnmadd132bf16256" => "__builtin_ia32_vfnmadd132bf16256", + "llvm.x86.avx10.vfnmadd132bf16512" => "__builtin_ia32_vfnmadd132bf16512", + "llvm.x86.avx10.vfnmadd213bf16128" => "__builtin_ia32_vfnmadd213bf16128", + "llvm.x86.avx10.vfnmadd213bf16256" => "__builtin_ia32_vfnmadd213bf16256", + "llvm.x86.avx10.vfnmadd213bf16512" => "__builtin_ia32_vfnmadd213bf16512", + "llvm.x86.avx10.vfnmadd231bf16128" => "__builtin_ia32_vfnmadd231bf16128", + "llvm.x86.avx10.vfnmadd231bf16256" => "__builtin_ia32_vfnmadd231bf16256", + "llvm.x86.avx10.vfnmadd231bf16512" => "__builtin_ia32_vfnmadd231bf16512", + "llvm.x86.avx10.vfnmsub132bf16128" => "__builtin_ia32_vfnmsub132bf16128", + "llvm.x86.avx10.vfnmsub132bf16256" => "__builtin_ia32_vfnmsub132bf16256", + "llvm.x86.avx10.vfnmsub132bf16512" => "__builtin_ia32_vfnmsub132bf16512", + "llvm.x86.avx10.vfnmsub213bf16128" => "__builtin_ia32_vfnmsub213bf16128", + "llvm.x86.avx10.vfnmsub213bf16256" => "__builtin_ia32_vfnmsub213bf16256", + "llvm.x86.avx10.vfnmsub213bf16512" => "__builtin_ia32_vfnmsub213bf16512", + "llvm.x86.avx10.vfnmsub231bf16128" => "__builtin_ia32_vfnmsub231bf16128", + "llvm.x86.avx10.vfnmsub231bf16256" => "__builtin_ia32_vfnmsub231bf16256", + "llvm.x86.avx10.vfnmsub231bf16512" => "__builtin_ia32_vfnmsub231bf16512", + "llvm.x86.avx10.vmaxbf16128" => "__builtin_ia32_vmaxbf16128", + "llvm.x86.avx10.vmaxbf16256" => "__builtin_ia32_vmaxbf16256", + "llvm.x86.avx10.vmaxbf16512" => "__builtin_ia32_vmaxbf16512", + "llvm.x86.avx10.vminbf16128" => "__builtin_ia32_vminbf16128", + "llvm.x86.avx10.vminbf16256" => "__builtin_ia32_vminbf16256", + "llvm.x86.avx10.vminbf16512" => "__builtin_ia32_vminbf16512", + "llvm.x86.avx10.vminmaxbf16128" => "__builtin_ia32_vminmaxbf16128", + "llvm.x86.avx10.vminmaxbf16256" => "__builtin_ia32_vminmaxbf16256", + "llvm.x86.avx10.vminmaxbf16512" => "__builtin_ia32_vminmaxbf16512", "llvm.x86.avx10.vminmaxpd128" => "__builtin_ia32_vminmaxpd128", "llvm.x86.avx10.vminmaxpd256" => "__builtin_ia32_vminmaxpd256", "llvm.x86.avx10.vminmaxph128" => "__builtin_ia32_vminmaxph128", "llvm.x86.avx10.vminmaxph256" => "__builtin_ia32_vminmaxph256", "llvm.x86.avx10.vminmaxps128" => "__builtin_ia32_vminmaxps128", "llvm.x86.avx10.vminmaxps256" => "__builtin_ia32_vminmaxps256", - "llvm.x86.avx10.vminpd256" => "__builtin_ia32_vminpd256_round", - "llvm.x86.avx10.vminph256" => "__builtin_ia32_vminph256_round", - "llvm.x86.avx10.vminps256" => "__builtin_ia32_vminps256_round", + "llvm.x86.avx10.vmovrsb128" => "__builtin_ia32_vmovrsb128", + "llvm.x86.avx10.vmovrsb256" => "__builtin_ia32_vmovrsb256", + "llvm.x86.avx10.vmovrsb512" => "__builtin_ia32_vmovrsb512", + "llvm.x86.avx10.vmovrsd128" => "__builtin_ia32_vmovrsd128", + "llvm.x86.avx10.vmovrsd256" => "__builtin_ia32_vmovrsd256", + "llvm.x86.avx10.vmovrsd512" => "__builtin_ia32_vmovrsd512", + "llvm.x86.avx10.vmovrsq128" => "__builtin_ia32_vmovrsq128", + "llvm.x86.avx10.vmovrsq256" => "__builtin_ia32_vmovrsq256", + "llvm.x86.avx10.vmovrsq512" => "__builtin_ia32_vmovrsq512", + "llvm.x86.avx10.vmovrsw128" => "__builtin_ia32_vmovrsw128", + "llvm.x86.avx10.vmovrsw256" => "__builtin_ia32_vmovrsw256", + "llvm.x86.avx10.vmovrsw512" => "__builtin_ia32_vmovrsw512", "llvm.x86.avx10.vmpsadbw.512" => "__builtin_ia32_mpsadbw512", - "llvm.x86.avx10.vmulpd256" => "__builtin_ia32_vmulpd256_round", - "llvm.x86.avx10.vmulph256" => "__builtin_ia32_vmulph256_round", - "llvm.x86.avx10.vmulps256" => "__builtin_ia32_vmulps256_round", + "llvm.x86.avx10.vmulbf16128" => "__builtin_ia32_vmulbf16128", + "llvm.x86.avx10.vmulbf16256" => "__builtin_ia32_vmulbf16256", + "llvm.x86.avx10.vmulbf16512" => "__builtin_ia32_vmulbf16512", "llvm.x86.avx10.vpdpbssd.512" => "__builtin_ia32_vpdpbssd512", "llvm.x86.avx10.vpdpbssds.512" => "__builtin_ia32_vpdpbssds512", "llvm.x86.avx10.vpdpbsud.512" => "__builtin_ia32_vpdpbsud512", @@ -7523,12 +7751,9 @@ match name { "llvm.x86.avx10.vpdpwusds.512" => "__builtin_ia32_vpdpwusds512", "llvm.x86.avx10.vpdpwuud.512" => "__builtin_ia32_vpdpwuud512", "llvm.x86.avx10.vpdpwuuds.512" => "__builtin_ia32_vpdpwuuds512", - "llvm.x86.avx10.vsqrtpd256" => "__builtin_ia32_vsqrtpd256_round", - "llvm.x86.avx10.vsqrtph256" => "__builtin_ia32_vsqrtph256_round", - "llvm.x86.avx10.vsqrtps256" => "__builtin_ia32_vsqrtps256_round", - "llvm.x86.avx10.vsubpd256" => "__builtin_ia32_vsubpd256_round", - "llvm.x86.avx10.vsubph256" => "__builtin_ia32_vsubph256_round", - "llvm.x86.avx10.vsubps256" => "__builtin_ia32_vsubps256_round", + "llvm.x86.avx10.vsubbf16128" => "__builtin_ia32_vsubbf16128", + "llvm.x86.avx10.vsubbf16256" => "__builtin_ia32_vsubbf16256", + "llvm.x86.avx10.vsubbf16512" => "__builtin_ia32_vsubbf16512", "llvm.x86.avx2.gather.d.d" => "__builtin_ia32_gatherd_d", "llvm.x86.avx2.gather.d.d.256" => "__builtin_ia32_gatherd_d256", "llvm.x86.avx2.gather.d.pd" => "__builtin_ia32_gatherd_pd", @@ -9279,10 +9504,15 @@ match name { "llvm.x86.mmx.femms" => "__builtin_ia32_femms", "llvm.x86.monitorx" => "__builtin_ia32_monitorx", "llvm.x86.movdir64b" => "__builtin_ia32_movdir64b", + "llvm.x86.movrsdi" => "__builtin_ia32_movrsdi", + "llvm.x86.movrshi" => "__builtin_ia32_movrshi", + "llvm.x86.movrsqi" => "__builtin_ia32_movrsqi", + "llvm.x86.movrssi" => "__builtin_ia32_movrssi", "llvm.x86.mwaitx" => "__builtin_ia32_mwaitx", "llvm.x86.pclmulqdq" => "__builtin_ia32_pclmulqdq128", "llvm.x86.pclmulqdq.256" => "__builtin_ia32_pclmulqdq256", "llvm.x86.pclmulqdq.512" => "__builtin_ia32_pclmulqdq512", + "llvm.x86.prefetchrs" => "__builtin_ia32_prefetchrs", "llvm.x86.ptwrite32" => "__builtin_ia32_ptwrite32", "llvm.x86.ptwrite64" => "__builtin_ia32_ptwrite64", "llvm.x86.rdfsbase.32" => "__builtin_ia32_rdfsbase32", @@ -9536,14 +9766,40 @@ match name { "llvm.x86.stui" => "__builtin_ia32_stui", "llvm.x86.subborrow.u32" => "__builtin_ia32_subborrow_u32", "llvm.x86.subborrow.u64" => "__builtin_ia32_subborrow_u64", + "llvm.x86.t2rpntlvwz0" => "__builtin_ia32_t2rpntlvwz0", + "llvm.x86.t2rpntlvwz0rs" => "__builtin_ia32_t2rpntlvwz0rs", + "llvm.x86.t2rpntlvwz0rst1" => "__builtin_ia32_t2rpntlvwz0rst1", + "llvm.x86.t2rpntlvwz0t1" => "__builtin_ia32_t2rpntlvwz0t1", + "llvm.x86.t2rpntlvwz1" => "__builtin_ia32_t2rpntlvwz1", + "llvm.x86.t2rpntlvwz1rs" => "__builtin_ia32_t2rpntlvwz1rs", + "llvm.x86.t2rpntlvwz1rst1" => "__builtin_ia32_t2rpntlvwz1rst1", + "llvm.x86.t2rpntlvwz1t1" => "__builtin_ia32_t2rpntlvwz1t1", "llvm.x86.tbm.bextri.u32" => "__builtin_ia32_bextri_u32", "llvm.x86.tbm.bextri.u64" => "__builtin_ia32_bextri_u64", "llvm.x86.tcmmimfp16ps" => "__builtin_ia32_tcmmimfp16ps", "llvm.x86.tcmmimfp16ps.internal" => "__builtin_ia32_tcmmimfp16ps_internal", "llvm.x86.tcmmrlfp16ps" => "__builtin_ia32_tcmmrlfp16ps", "llvm.x86.tcmmrlfp16ps.internal" => "__builtin_ia32_tcmmrlfp16ps_internal", + "llvm.x86.tconjtcmmimfp16ps" => "__builtin_ia32_tconjtcmmimfp16ps", + "llvm.x86.tconjtcmmimfp16ps.internal" => "__builtin_ia32_tconjtcmmimfp16ps_internal", + "llvm.x86.tconjtfp16" => "__builtin_ia32_tconjtfp16", + "llvm.x86.tconjtfp16.internal" => "__builtin_ia32_tconjtfp16_internal", + "llvm.x86.tcvtrowd2ps" => "__builtin_ia32_tcvtrowd2ps", + "llvm.x86.tcvtrowd2ps.internal" => "__builtin_ia32_tcvtrowd2ps_internal", + "llvm.x86.tcvtrowps2bf16h" => "__builtin_ia32_tcvtrowps2bf16h", + "llvm.x86.tcvtrowps2bf16h.internal" => "__builtin_ia32_tcvtrowps2bf16h_internal", + "llvm.x86.tcvtrowps2bf16l" => "__builtin_ia32_tcvtrowps2bf16l", + "llvm.x86.tcvtrowps2bf16l.internal" => "__builtin_ia32_tcvtrowps2bf16l_internal", + "llvm.x86.tcvtrowps2phh" => "__builtin_ia32_tcvtrowps2phh", + "llvm.x86.tcvtrowps2phh.internal" => "__builtin_ia32_tcvtrowps2phh_internal", + "llvm.x86.tcvtrowps2phl" => "__builtin_ia32_tcvtrowps2phl", + "llvm.x86.tcvtrowps2phl.internal" => "__builtin_ia32_tcvtrowps2phl_internal", "llvm.x86.tdpbf16ps" => "__builtin_ia32_tdpbf16ps", "llvm.x86.tdpbf16ps.internal" => "__builtin_ia32_tdpbf16ps_internal", + "llvm.x86.tdpbf8ps" => "__builtin_ia32_tdpbf8ps", + "llvm.x86.tdpbf8ps.internal" => "__builtin_ia32_tdpbf8ps_internal", + "llvm.x86.tdpbhf8ps" => "__builtin_ia32_tdpbhf8ps", + "llvm.x86.tdpbhf8ps.internal" => "__builtin_ia32_tdpbhf8ps_internal", "llvm.x86.tdpbssd" => "__builtin_ia32_tdpbssd", "llvm.x86.tdpbssd.internal" => "__builtin_ia32_tdpbssd_internal", "llvm.x86.tdpbsud" => "__builtin_ia32_tdpbsud", @@ -9554,17 +9810,41 @@ match name { "llvm.x86.tdpbuud.internal" => "__builtin_ia32_tdpbuud_internal", "llvm.x86.tdpfp16ps" => "__builtin_ia32_tdpfp16ps", "llvm.x86.tdpfp16ps.internal" => "__builtin_ia32_tdpfp16ps_internal", + "llvm.x86.tdphbf8ps" => "__builtin_ia32_tdphbf8ps", + "llvm.x86.tdphbf8ps.internal" => "__builtin_ia32_tdphbf8ps_internal", + "llvm.x86.tdphf8ps" => "__builtin_ia32_tdphf8ps", + "llvm.x86.tdphf8ps.internal" => "__builtin_ia32_tdphf8ps_internal", "llvm.x86.testui" => "__builtin_ia32_testui", "llvm.x86.tileloadd64" => "__builtin_ia32_tileloadd64", "llvm.x86.tileloadd64.internal" => "__builtin_ia32_tileloadd64_internal", + "llvm.x86.tileloaddrs64" => "__builtin_ia32_tileloaddrs64", + "llvm.x86.tileloaddrs64.internal" => "__builtin_ia32_tileloaddrs64_internal", + "llvm.x86.tileloaddrst164" => "__builtin_ia32_tileloaddrst164", + "llvm.x86.tileloaddrst164.internal" => "__builtin_ia32_tileloaddrst164_internal", "llvm.x86.tileloaddt164" => "__builtin_ia32_tileloaddt164", "llvm.x86.tileloaddt164.internal" => "__builtin_ia32_tileloaddt164_internal", + "llvm.x86.tilemovrow" => "__builtin_ia32_tilemovrow", + "llvm.x86.tilemovrow.internal" => "__builtin_ia32_tilemovrow_internal", "llvm.x86.tilerelease" => "__builtin_ia32_tilerelease", "llvm.x86.tilestored64" => "__builtin_ia32_tilestored64", "llvm.x86.tilestored64.internal" => "__builtin_ia32_tilestored64_internal", "llvm.x86.tilezero" => "__builtin_ia32_tilezero", "llvm.x86.tilezero.internal" => "__builtin_ia32_tilezero_internal", + "llvm.x86.tmmultf32ps" => "__builtin_ia32_tmmultf32ps", + "llvm.x86.tmmultf32ps.internal" => "__builtin_ia32_tmmultf32ps_internal", "llvm.x86.tpause" => "__builtin_ia32_tpause", + "llvm.x86.ttcmmimfp16ps" => "__builtin_ia32_ttcmmimfp16ps", + "llvm.x86.ttcmmimfp16ps.internal" => "__builtin_ia32_ttcmmimfp16ps_internal", + "llvm.x86.ttcmmrlfp16ps" => "__builtin_ia32_ttcmmrlfp16ps", + "llvm.x86.ttcmmrlfp16ps.internal" => "__builtin_ia32_ttcmmrlfp16ps_internal", + "llvm.x86.ttdpbf16ps" => "__builtin_ia32_ttdpbf16ps", + "llvm.x86.ttdpbf16ps.internal" => "__builtin_ia32_ttdpbf16ps_internal", + "llvm.x86.ttdpfp16ps" => "__builtin_ia32_ttdpfp16ps", + "llvm.x86.ttdpfp16ps.internal" => "__builtin_ia32_ttdpfp16ps_internal", + "llvm.x86.ttmmultf32ps" => "__builtin_ia32_ttmmultf32ps", + "llvm.x86.ttmmultf32ps.internal" => "__builtin_ia32_ttmmultf32ps_internal", + "llvm.x86.ttransposed" => "__builtin_ia32_ttransposed", + "llvm.x86.ttransposed.internal" => "__builtin_ia32_ttransposed_internal", "llvm.x86.umonitor" => "__builtin_ia32_umonitor", "llvm.x86.umwait" => "__builtin_ia32_umwait", "llvm.x86.urdmsr" => "__builtin_ia32_urdmsr", @@ -9604,8 +9884,10 @@ match name { "llvm.x86.vsm3rnds2" => "__builtin_ia32_vsm3rnds2", "llvm.x86.vsm4key4128" => "__builtin_ia32_vsm4key4128", "llvm.x86.vsm4key4256" => "__builtin_ia32_vsm4key4256", + "llvm.x86.vsm4key4512" => "__builtin_ia32_vsm4key4512", "llvm.x86.vsm4rnds4128" => "__builtin_ia32_vsm4rnds4128", "llvm.x86.vsm4rnds4256" => "__builtin_ia32_vsm4rnds4256", + "llvm.x86.vsm4rnds4512" => "__builtin_ia32_vsm4rnds4512", "llvm.x86.wbinvd" => "__builtin_ia32_wbinvd", "llvm.x86.wbnoinvd" => "__builtin_ia32_wbnoinvd", "llvm.x86.wrfsbase.32" => "__builtin_ia32_wrfsbase32", From 5bd3d0e99da2d79cafd73e7f174b99fe8349fa75 Mon Sep 17 00:00:00 2001 From: oyvindln Date: Sat, 10 May 2025 18:35:20 +0200 Subject: [PATCH 2152/4206] Update miniz_oxide dependency of coverage_dump --- Cargo.lock | 21 +++------------------ src/tools/coverage-dump/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 624a4226bd69a..fa6879f1d9b65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,12 +11,6 @@ dependencies = [ "gimli", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler2" version = "2.0.0" @@ -240,7 +234,7 @@ dependencies = [ "addr2line", "cfg-if", "libc", - "miniz_oxide 0.8.8", + "miniz_oxide", "object", "rustc-demangle", "windows-targets 0.52.6", @@ -780,7 +774,7 @@ dependencies = [ "itertools", "leb128", "md-5", - "miniz_oxide 0.7.4", + "miniz_oxide", "regex", "rustc-demangle", ] @@ -1220,7 +1214,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", - "miniz_oxide 0.8.8", + "miniz_oxide", ] [[package]] @@ -2257,15 +2251,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.8.8" diff --git a/src/tools/coverage-dump/Cargo.toml b/src/tools/coverage-dump/Cargo.toml index 6f92ac50d963c..36a66f16030ec 100644 --- a/src/tools/coverage-dump/Cargo.toml +++ b/src/tools/coverage-dump/Cargo.toml @@ -10,6 +10,6 @@ anyhow = "1.0.71" itertools = "0.12" leb128 = "0.2.5" md5 = { package = "md-5" , version = "0.10.5" } -miniz_oxide = "0.7.1" +miniz_oxide = "0.8.8" regex = "1.8.4" rustc-demangle = "0.1.23" From 838e742ea49648d63461b41ea330a9a1ed086c02 Mon Sep 17 00:00:00 2001 From: SpecificProtagonist Date: Fri, 9 May 2025 20:28:51 +0200 Subject: [PATCH 2153/4206] rustdoc: Fix links in trait impl docs --- src/librustdoc/html/static/js/main.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index a7ce2bf9048bf..7b1a61a3ffa45 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1179,8 +1179,10 @@ function preLoadCss(cssUrl) { onEachLazy(document.querySelectorAll(".toggle > summary:not(.hideme)"), el => { // @ts-expect-error + // Clicking on the summary's contents should not collapse it, + // but links within should still fire. el.addEventListener("click", e => { - if (e.target.tagName !== "SUMMARY" && e.target.tagName !== "A") { + if (!e.target.matches("summary, a, a *")) { e.preventDefault(); } }); From 31ae60d30d96b32c35a3dd5239a68997c9d4a27d Mon Sep 17 00:00:00 2001 From: SpecificProtagonist Date: Sat, 10 May 2025 19:24:59 +0200 Subject: [PATCH 2154/4206] gui test --- tests/rustdoc-gui/collapse-trait-impl.goml | 23 ++++++++++++++++++++++ tests/rustdoc-gui/src/test_docs/lib.rs | 1 + 2 files changed, 24 insertions(+) create mode 100644 tests/rustdoc-gui/collapse-trait-impl.goml diff --git a/tests/rustdoc-gui/collapse-trait-impl.goml b/tests/rustdoc-gui/collapse-trait-impl.goml new file mode 100644 index 0000000000000..dc1170a831aef --- /dev/null +++ b/tests/rustdoc-gui/collapse-trait-impl.goml @@ -0,0 +1,23 @@ +// Checks that individual trait impls can only be collapsed via clicking directly on the summary element +include: "utils.goml" + +go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" +assert-attribute: ("details:has(#trait-impl-link-in-summary)", {"open": ""}) + +// Collapse the trait impl doc. The actual clickable area is outside the element, hence offset. +click-with-offset: ("summary:has(#trait-impl-link-in-summary)", {"x": -15, "y": 5}) +assert-attribute-false: ("details:has(#trait-impl-link-in-summary)", {"open": ""}) + +// Clicks on the text should be ignored +click: "summary:has(#trait-impl-link-in-summary) > .impl" +assert-window-property: ({"pageYOffset": "0"}) + +// But links should still work +click: "#trait-impl-link-in-summary" +assert-window-property-false: ({"pageYOffset": "0"}) + +// As well as clicks on elements within links +go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" +assert-window-property: ({"pageYOffset": "0"}) +click: "#trait-impl-link-in-summary" +assert-window-property-false: ({"pageYOffset": "0"}) diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs index bb0015b8f9c43..e8afe8b568727 100644 --- a/tests/rustdoc-gui/src/test_docs/lib.rs +++ b/tests/rustdoc-gui/src/test_docs/lib.rs @@ -79,6 +79,7 @@ impl Foo { pub fn warning2() {} } +/// A collapsible trait impl with a link impl AsRef for Foo { fn as_ref(&self) -> &str { "hello" From bd23ee2382ae8f940771dc08be5e234f6963ba72 Mon Sep 17 00:00:00 2001 From: SpecificProtagonist Date: Sat, 10 May 2025 19:48:13 +0200 Subject: [PATCH 2155/4206] gui test different link --- tests/rustdoc-gui/collapse-trait-impl.goml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/rustdoc-gui/collapse-trait-impl.goml b/tests/rustdoc-gui/collapse-trait-impl.goml index dc1170a831aef..5f95dcc01c11c 100644 --- a/tests/rustdoc-gui/collapse-trait-impl.goml +++ b/tests/rustdoc-gui/collapse-trait-impl.goml @@ -13,7 +13,7 @@ click: "summary:has(#trait-impl-link-in-summary) > .impl" assert-window-property: ({"pageYOffset": "0"}) // But links should still work -click: "#trait-impl-link-in-summary" +click: "summary:has(#trait-impl-link-in-summary) a:has(#trait-impl-link-in-summary)" assert-window-property-false: ({"pageYOffset": "0"}) // As well as clicks on elements within links From 448b7afb32e4fd55af8c0592227b16fcc5b64308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 10 May 2025 21:39:08 +0200 Subject: [PATCH 2156/4206] Fix download of GCC from CI on non-nightly channels --- src/bootstrap/src/core/download.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index b95d07356c1b9..da305fb18fa9e 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -852,7 +852,8 @@ download-rustc = false t!(fs::create_dir_all(&gcc_cache)); } let base = &self.stage0_metadata.config.artifacts_server; - let filename = format!("gcc-nightly-{}.tar.xz", self.build.triple); + let version = self.artifact_version_part(gcc_sha); + let filename = format!("gcc-{version}-{}.tar.xz", self.build.triple); let tarball = gcc_cache.join(&filename); if !tarball.exists() { let help_on_error = "ERROR: failed to download gcc from ci From 6814c38da20ddfb887b7763475edb3ac0ed55a64 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 May 2025 21:40:23 +0200 Subject: [PATCH 2157/4206] test intrinsic fallback bodies with Miri --- .../x86_64-gnu-tools/checktools.sh | 8 ++++++ src/tools/miri/README.md | 3 +++ src/tools/miri/src/bin/miri.rs | 2 ++ src/tools/miri/src/eval.rs | 3 +++ src/tools/miri/src/intrinsics/mod.rs | 10 +++++++ src/tools/miri/src/machine.rs | 5 ++++ .../miri/tests/pass/intrinsics/intrinsics.rs | 26 +++++++++++-------- 7 files changed, 46 insertions(+), 11 deletions(-) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh index 28c035daa5d50..9ed5b519b6ea4 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh @@ -40,6 +40,14 @@ if [ -z "${PR_CI_JOB:-}" ]; then else python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri fi +# We re-run the test suite for a chance to find bugs in the intrinsic fallback bodies and in MIR +# optimizations. This can miss UB, so we only run the "pass" tests. We need to enable debug +# assertions as `-O` disables them but some tests rely on them. We also set a cfg flag so tests can +# adjust their expectations if needed. This can change the output of the tests so we ignore that, +# we only ensure that all assertions still pass. +MIRIFLAGS="-Zmiri-force-intrinsic-fallback --cfg force_intrinsic_fallback -O -Zmir-opt-level=4 -Cdebug-assertions=yes" \ + MIRI_SKIP_UI_CHECKS=1 \ + python3 "$X_PY" test --stage 2 src/tools/miri -- tests/{pass,panic} # We natively run this script on x86_64-unknown-linux-gnu and x86_64-pc-windows-msvc. # Also cover some other targets via cross-testing, in particular all tier 1 targets. case $HOST_TARGET in diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index a78cc9d931980..b692ddab4ffc8 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -393,6 +393,9 @@ to Miri failing to detect cases of undefined behavior in a program. disables the randomization of the next thread to be picked, instead fixing a round-robin schedule. Note however that other aspects of Miri's concurrency behavior are still randomize; use `-Zmiri-deterministic-concurrency` to disable them all. +* `-Zmiri-force-intrinsic-fallback` forces the use of the "fallback" body for all intrinsics that + have one. This is useful to test the fallback bodies, but should not be used otherwise. It is + **unsound** since the fallback body might not be checking for all UB. * `-Zmiri-native-lib=` is an experimental flag for providing support for calling native functions from inside the interpreter via FFI. The flag is supported only on Unix systems. Functions not provided by that file are still executed via the usual Miri shims. diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 69aa035fdc3df..f249b58aeb663 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -584,6 +584,8 @@ fn main() { } else if arg == "-Zmiri-ignore-leaks" { miri_config.ignore_leaks = true; miri_config.collect_leak_backtraces = false; + } else if arg == "-Zmiri-force-intrinsic-fallback" { + miri_config.force_intrinsic_fallback = true; } else if arg == "-Zmiri-strict-provenance" { miri_config.provenance_mode = ProvenanceMode::Strict; } else if arg == "-Zmiri-permissive-provenance" { diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index bb5e5d7ee8146..a90c6ab9d40e9 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -165,6 +165,8 @@ pub struct MiriConfig { pub address_reuse_cross_thread_rate: f64, /// Round Robin scheduling with no preemption. pub fixed_scheduling: bool, + /// Always prefer the intrinsic fallback body over the native Miri implementation. + pub force_intrinsic_fallback: bool, } impl Default for MiriConfig { @@ -203,6 +205,7 @@ impl Default for MiriConfig { address_reuse_rate: 0.5, address_reuse_cross_thread_rate: 0.1, fixed_scheduling: false, + force_intrinsic_fallback: false, } } } diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 3334c0b5edf96..982fbc318110e 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -28,6 +28,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, Option>> { let this = self.eval_context_mut(); + // Force use of fallback body, if available. + if this.machine.force_intrinsic_fallback + && !this.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden + { + return interp_ok(Some(ty::Instance { + def: ty::InstanceKind::Item(instance.def_id()), + args: instance.args, + })); + } + // See if the core engine can handle this intrinsic. if this.eval_intrinsic(instance, args, dest, ret)? { return interp_ok(None); diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 6060d41dac594..dbde415170c31 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -614,6 +614,9 @@ pub struct MiriMachine<'tcx> { /// Cache for `mangle_internal_symbol`. pub(crate) mangle_internal_symbol_cache: FxHashMap<&'static str, String>, + + /// Always prefer the intrinsic fallback body over the native Miri implementation. + pub force_intrinsic_fallback: bool, } impl<'tcx> MiriMachine<'tcx> { @@ -770,6 +773,7 @@ impl<'tcx> MiriMachine<'tcx> { reject_in_isolation_warned: Default::default(), int2ptr_warned: Default::default(), mangle_internal_symbol_cache: Default::default(), + force_intrinsic_fallback: config.force_intrinsic_fallback, } } @@ -946,6 +950,7 @@ impl VisitProvenance for MiriMachine<'_> { reject_in_isolation_warned: _, int2ptr_warned: _, mangle_internal_symbol_cache: _, + force_intrinsic_fallback: _, } = self; threads.visit_provenance(visit); diff --git a/src/tools/miri/tests/pass/intrinsics/intrinsics.rs b/src/tools/miri/tests/pass/intrinsics/intrinsics.rs index 89289a25d50a3..913c3cde272d8 100644 --- a/src/tools/miri/tests/pass/intrinsics/intrinsics.rs +++ b/src/tools/miri/tests/pass/intrinsics/intrinsics.rs @@ -33,20 +33,24 @@ fn main() { assert_eq!(intrinsics::likely(false), false); assert_eq!(intrinsics::unlikely(true), true); - let mut saw_true = false; - let mut saw_false = false; + // Skip this test when we use the fallback bodies, as that one is deterministic. + // (CI sets `--cfg force_intrinsic_fallback` together with `-Zmiri-force-intrinsic-fallback`.) + if !cfg!(force_intrinsic_fallback) { + let mut saw_true = false; + let mut saw_false = false; - for _ in 0..50 { - if intrinsics::is_val_statically_known(0) { - saw_true = true; - } else { - saw_false = true; + for _ in 0..50 { + if intrinsics::is_val_statically_known(0) { + saw_true = true; + } else { + saw_false = true; + } } + assert!( + saw_true && saw_false, + "`is_val_statically_known` failed to return both true and false. Congrats, you won the lottery!" + ); } - assert!( - saw_true && saw_false, - "`is_val_statically_known` failed to return both true and false. Congrats, you won the lottery!" - ); intrinsics::forget(Bomb); From 9ed53b85b7ebb52badbc8676e40725a55331c214 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 10 May 2025 21:53:56 +0200 Subject: [PATCH 2158/4206] Fix ICE in `missing_const_for_fn` The `mir_drops_elaborated_and_const_checked` query result has been stolen already and cannot be borrowed again. Use the `optimized_mir` query result instead. --- clippy_lints/src/missing_const_for_fn.rs | 4 ++-- .../ui/crashes/missing_const_for_fn_14774.fixed | 13 +++++++++++++ tests/ui/crashes/missing_const_for_fn_14774.rs | 13 +++++++++++++ .../crashes/missing_const_for_fn_14774.stderr | 17 +++++++++++++++++ 4 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 tests/ui/crashes/missing_const_for_fn_14774.fixed create mode 100644 tests/ui/crashes/missing_const_for_fn_14774.rs create mode 100644 tests/ui/crashes/missing_const_for_fn_14774.stderr diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 1f142bc3ba63c..f3e24044fb6c2 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -155,9 +155,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { return; } - let mir = cx.tcx.mir_drops_elaborated_and_const_checked(def_id); + let mir = cx.tcx.optimized_mir(def_id); - if let Ok(()) = is_min_const_fn(cx, &mir.borrow(), self.msrv) + if let Ok(()) = is_min_const_fn(cx, mir, self.msrv) && let hir::Node::Item(hir::Item { vis_span, .. }) | hir::Node::ImplItem(hir::ImplItem { vis_span, .. }) = cx.tcx.hir_node_by_def_id(def_id) { diff --git a/tests/ui/crashes/missing_const_for_fn_14774.fixed b/tests/ui/crashes/missing_const_for_fn_14774.fixed new file mode 100644 index 0000000000000..9c85c4b846489 --- /dev/null +++ b/tests/ui/crashes/missing_const_for_fn_14774.fixed @@ -0,0 +1,13 @@ +//@compile-flags: -Z validate-mir +#![warn(clippy::missing_const_for_fn)] + +static BLOCK_FN_DEF: fn(usize) -> usize = { + //~v missing_const_for_fn + const fn foo(a: usize) -> usize { + a + 10 + } + foo +}; +struct X; + +fn main() {} diff --git a/tests/ui/crashes/missing_const_for_fn_14774.rs b/tests/ui/crashes/missing_const_for_fn_14774.rs new file mode 100644 index 0000000000000..6519be61256e6 --- /dev/null +++ b/tests/ui/crashes/missing_const_for_fn_14774.rs @@ -0,0 +1,13 @@ +//@compile-flags: -Z validate-mir +#![warn(clippy::missing_const_for_fn)] + +static BLOCK_FN_DEF: fn(usize) -> usize = { + //~v missing_const_for_fn + fn foo(a: usize) -> usize { + a + 10 + } + foo +}; +struct X; + +fn main() {} diff --git a/tests/ui/crashes/missing_const_for_fn_14774.stderr b/tests/ui/crashes/missing_const_for_fn_14774.stderr new file mode 100644 index 0000000000000..a407376d0b9d9 --- /dev/null +++ b/tests/ui/crashes/missing_const_for_fn_14774.stderr @@ -0,0 +1,17 @@ +error: this could be a `const fn` + --> tests/ui/crashes/missing_const_for_fn_14774.rs:6:5 + | +LL | / fn foo(a: usize) -> usize { +LL | | a + 10 +LL | | } + | |_____^ + | + = note: `-D clippy::missing-const-for-fn` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_const_for_fn)]` +help: make the function `const` + | +LL | const fn foo(a: usize) -> usize { + | +++++ + +error: aborting due to 1 previous error + From f111416e43a36a1ee062a2194eae37c39d0f0be1 Mon Sep 17 00:00:00 2001 From: michal kostrubiec Date: Fri, 9 May 2025 16:41:46 +0200 Subject: [PATCH 2159/4206] Fixed a recursive inling bug, added a test for it --- src/attributes.rs | 53 +++++++++++++++++++++++++++++++++++--- tests/run/always_inline.rs | 53 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 tests/run/always_inline.rs diff --git a/src/attributes.rs b/src/attributes.rs index 8bc1b77024307..f933119d0ba09 100644 --- a/src/attributes.rs +++ b/src/attributes.rs @@ -6,21 +6,68 @@ use rustc_attr_parsing::InlineAttr; use rustc_attr_parsing::InstructionSetAttr; #[cfg(feature = "master")] use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::mir::TerminatorKind; use rustc_middle::ty; use crate::context::CodegenCx; use crate::gcc_util::to_gcc_features; -/// Get GCC attribute for the provided inline heuristic. +/// Checks if the function `instance` is recursively inline. +/// Returns `false` if a functions is guaranteed to be non-recursive, and `true` if it *might* be recursive. +#[cfg(feature = "master")] +fn resursively_inline<'gcc, 'tcx>( + cx: &CodegenCx<'gcc, 'tcx>, + instance: ty::Instance<'tcx>, +) -> bool { + // No body, so we can't check if this is recursively inline, so we assume it is. + if !cx.tcx.is_mir_available(instance.def_id()) { + return true; + } + // `expect_local` ought to never fail: we should be checking a function within this codegen unit. + let body = cx.tcx.optimized_mir(instance.def_id()); + for block in body.basic_blocks.iter() { + let Some(ref terminator) = block.terminator else { continue }; + // I assume that the recursive-inline issue applies only to functions, and not to drops. + // In principle, a recursive, `#[inline(always)]` drop could(?) exist, but I don't think it does. + let TerminatorKind::Call { ref func, .. } = terminator.kind else { continue }; + let Some((def, _args)) = func.const_fn_def() else { continue }; + // Check if the called function is recursively inline. + if matches!( + cx.tcx.codegen_fn_attrs(def).inline, + InlineAttr::Always | InlineAttr::Force { .. } + ) { + return true; + } + } + false +} + +/// Get GCC attribute for the provided inline heuristic, attached to `instance`. #[cfg(feature = "master")] #[inline] fn inline_attr<'gcc, 'tcx>( cx: &CodegenCx<'gcc, 'tcx>, inline: InlineAttr, + instance: ty::Instance<'tcx>, ) -> Option> { match inline { + InlineAttr::Always => { + // We can't simply always return `always_inline` unconditionally. + // It is *NOT A HINT* and does not work for recursive functions. + // + // So, it can only be applied *if*: + // The current function does not call any functions marked `#[inline(always)]`. + // + // That prevents issues steming from recursive `#[inline(always)]` at a *relatively* small cost. + // We *only* need to check all the terminators of a function marked with this attribute. + if resursively_inline(cx, instance) { + Some(FnAttribute::Inline) + } else { + Some(FnAttribute::AlwaysInline) + } + } InlineAttr::Hint => Some(FnAttribute::Inline), - InlineAttr::Always | InlineAttr::Force { .. } => Some(FnAttribute::AlwaysInline), + InlineAttr::Force { .. } => Some(FnAttribute::AlwaysInline), InlineAttr::Never => { if cx.sess().target.arch != "amdgpu" { Some(FnAttribute::NoInline) @@ -52,7 +99,7 @@ pub fn from_fn_attrs<'gcc, 'tcx>( } else { codegen_fn_attrs.inline }; - if let Some(attr) = inline_attr(cx, inline) { + if let Some(attr) = inline_attr(cx, inline, instance) { if let FnAttribute::AlwaysInline = attr { func.add_attribute(FnAttribute::Inline); } diff --git a/tests/run/always_inline.rs b/tests/run/always_inline.rs new file mode 100644 index 0000000000000..ebd741ee090c8 --- /dev/null +++ b/tests/run/always_inline.rs @@ -0,0 +1,53 @@ +// Compiler: +// +// Run-time: +// status: 0 + +#![feature(no_core)] +#![no_std] +#![no_core] +#![no_main] + +extern crate mini_core; +use mini_core::*; + +#[inline(always)] +fn fib(n: u8) -> u8 { + if n == 0 { + return 1; + } + if n == 1 { + return 1; + } + fib(n - 1) + fib(n - 2) +} + +#[inline(always)] +fn fib_b(n: u8) -> u8 { + if n == 0 { + return 1; + } + if n == 1 { + return 1; + } + fib_a(n - 1) + fib_a(n - 2) +} + +#[inline(always)] +fn fib_a(n: u8) -> u8 { + if n == 0 { + return 1; + } + if n == 1 { + return 1; + } + fib_b(n - 1) + fib_b(n - 2) +} + +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { + if fib(2) != fib_a(2) { + intrinsics::abort(); + } + 0 +} From 13178c75cea866d3a84a570b9ae984508c2127db Mon Sep 17 00:00:00 2001 From: Andrew Zhogin Date: Sun, 11 May 2025 02:21:56 +0700 Subject: [PATCH 2160/4206] Async drop fix for async_drop_in_place layout calculated for unspecified T --- compiler/rustc_middle/src/ty/mod.rs | 3 +++ .../async-await/async-drop/open-drop-error.rs | 21 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 tests/ui/async-await/async-drop/open-drop-error.rs diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 2d69a1c2b553e..dda0faa3afedd 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1924,6 +1924,9 @@ impl<'tcx> TyCtxt<'tcx> { def_id: DefId, args: GenericArgsRef<'tcx>, ) -> Option<&'tcx CoroutineLayout<'tcx>> { + if args[0].has_placeholders() || args[0].has_non_region_param() { + return None; + } let instance = InstanceKind::AsyncDropGlue(def_id, Ty::new_coroutine(self, def_id, args)); self.mir_shims(instance).coroutine_layout_raw() } diff --git a/tests/ui/async-await/async-drop/open-drop-error.rs b/tests/ui/async-await/async-drop/open-drop-error.rs new file mode 100644 index 0000000000000..1d97eee521094 --- /dev/null +++ b/tests/ui/async-await/async-drop/open-drop-error.rs @@ -0,0 +1,21 @@ +//@ compile-flags: -Zmir-enable-passes=+DataflowConstProp +//@ edition: 2021 +//@ build-pass +#![feature(async_drop)] +#![allow(incomplete_features)] + +use std::mem::ManuallyDrop; +use std::{ + future::async_drop_in_place, + pin::{pin, Pin}, +}; +fn main() { + a(b) +} +fn b() {} +fn a(d: C) { + let e = pin!(ManuallyDrop::new(d)); + let f = unsafe { Pin::map_unchecked_mut(e, |g| &mut **g) }; + let h = unsafe { async_drop_in_place(f.get_unchecked_mut()) }; + h; +} From aeea4727a4a00030fa888eccb10bcc372c4b7d2d Mon Sep 17 00:00:00 2001 From: Paolo Barbolini Date: Sat, 10 May 2025 23:46:43 +0000 Subject: [PATCH 2161/4206] Remove `stable` attribute from wasi fs (read_exact|write_all)_at --- library/std/src/os/wasi/fs.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs index 34f0e89f2f1ee..5ea91dd6521ad 100644 --- a/library/std/src/os/wasi/fs.rs +++ b/library/std/src/os/wasi/fs.rs @@ -72,7 +72,6 @@ pub trait FileExt { /// If this function returns an error, it is unspecified how many bytes it /// has read, but it will never read more than would be necessary to /// completely fill the buffer. - #[stable(feature = "rw_exact_all_at", since = "1.33.0")] fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> { while !buf.is_empty() { match self.read_at(buf, offset) { @@ -144,7 +143,6 @@ pub trait FileExt { /// non-[`io::ErrorKind::Interrupted`] kind that [`write_at`] returns. /// /// [`write_at`]: FileExt::write_at - #[stable(feature = "rw_exact_all_at", since = "1.33.0")] fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> { while !buf.is_empty() { match self.write_at(buf, offset) { From 8764ecd0c14f9f3f083b84de893ab8e6f71100bc Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 10 May 2025 21:09:16 +1000 Subject: [PATCH 2162/4206] Add a searchable tag `PTR_LEN_STR` to explain `*const c_uchar` bindings This module comment describes why it's OK for LLVM bindings to declare a parameter type of `*const c_uchar` for pointer/length strings, even though the corresponding parameter on the C/C++ side uses `const char *`. Adding a searchable term to each such parameter should make it easier for future maintainers to understand why `*const c_uchar` is being used instead of `*const c_char`. --- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index a249cb86ed42e..feaae19f0cd1c 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1,7 +1,7 @@ //! Bindings to the LLVM-C API (`LLVM*`), and to our own `extern "C"` wrapper //! functions around the unstable LLVM C++ API (`LLVMRust*`). //! -//! ## Passing pointer/length strings as `*const c_uchar` +//! ## Passing pointer/length strings as `*const c_uchar` (PTR_LEN_STR) //! //! Normally it's a good idea for Rust-side bindings to match the corresponding //! C-side function declarations as closely as possible. But when passing `&str` @@ -1766,7 +1766,7 @@ unsafe extern "C" { pub(crate) fn LLVMDIBuilderCreateNameSpace<'ll>( Builder: &DIBuilder<'ll>, ParentScope: Option<&'ll Metadata>, - Name: *const c_uchar, + Name: *const c_uchar, // See "PTR_LEN_STR". NameLen: size_t, ExportSymbols: llvm::Bool, ) -> &'ll Metadata; From d1bb310a7aa54b4bfc68c6960e1de0976ff447a5 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 10 May 2025 18:54:45 +1000 Subject: [PATCH 2163/4206] Use `LLVMGetInlineAsm` This LLVM-C binding replaces the existing `LLVMRustInlineAsm` function. --- compiler/rustc_codegen_llvm/src/asm.rs | 6 ++--- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 27 ++++++++++--------- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 27 ------------------- 3 files changed, 17 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index e481b99afcc67..c3851dc7762b5 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -488,11 +488,11 @@ pub(crate) fn inline_asm_call<'ll>( debug!("constraint verification result: {:?}", constraints_ok); if constraints_ok { let v = unsafe { - llvm::LLVMRustInlineAsm( + llvm::LLVMGetInlineAsm( fty, - asm.as_c_char_ptr(), + asm.as_ptr(), asm.len(), - cons.as_c_char_ptr(), + cons.as_ptr(), cons.len(), volatile, alignstack, diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index feaae19f0cd1c..2b71e8954bbda 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -471,7 +471,7 @@ pub(crate) enum MetadataType { MD_kcfi_type = 36, } -/// LLVMRustAsmDialect +/// Must match the layout of `LLVMInlineAsmDialect`. #[derive(Copy, Clone, PartialEq)] #[repr(C)] pub(crate) enum AsmDialect { @@ -1017,6 +1017,19 @@ unsafe extern "C" { /// See Module::setModuleInlineAsm. pub(crate) fn LLVMAppendModuleInlineAsm(M: &Module, Asm: *const c_char, Len: size_t); + /// Create the specified uniqued inline asm string. See `InlineAsm::get()`. + pub(crate) fn LLVMGetInlineAsm<'ll>( + Ty: &'ll Type, + AsmString: *const c_uchar, // See "PTR_LEN_STR". + AsmStringSize: size_t, + Constraints: *const c_uchar, // See "PTR_LEN_STR". + ConstraintsSize: size_t, + HasSideEffects: llvm::Bool, + IsAlignStack: llvm::Bool, + Dialect: AsmDialect, + CanThrow: llvm::Bool, + ) -> &'ll Value; + // Operations on integer types pub(crate) fn LLVMInt1TypeInContext(C: &Context) -> &Type; pub(crate) fn LLVMInt8TypeInContext(C: &Context) -> &Type; @@ -1994,18 +2007,6 @@ unsafe extern "C" { /// Prints the statistics collected by `-Zprint-codegen-stats`. pub(crate) fn LLVMRustPrintStatistics(OutStr: &RustString); - /// Prepares inline assembly. - pub(crate) fn LLVMRustInlineAsm( - Ty: &Type, - AsmString: *const c_char, - AsmStringLen: size_t, - Constraints: *const c_char, - ConstraintsLen: size_t, - SideEffects: Bool, - AlignStack: Bool, - Dialect: AsmDialect, - CanThrow: Bool, - ) -> &Value; pub(crate) fn LLVMRustInlineAsmVerify( Ty: &Type, Constraints: *const c_char, diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 72369ab7b692a..90aa9188c8300 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -622,37 +622,10 @@ extern "C" LLVMValueRef LLVMRustBuildAtomicStore(LLVMBuilderRef B, return wrap(SI); } -enum class LLVMRustAsmDialect { - Att, - Intel, -}; - -static InlineAsm::AsmDialect fromRust(LLVMRustAsmDialect Dialect) { - switch (Dialect) { - case LLVMRustAsmDialect::Att: - return InlineAsm::AD_ATT; - case LLVMRustAsmDialect::Intel: - return InlineAsm::AD_Intel; - default: - report_fatal_error("bad AsmDialect."); - } -} - extern "C" uint64_t LLVMRustGetArrayNumElements(LLVMTypeRef Ty) { return unwrap(Ty)->getArrayNumElements(); } -extern "C" LLVMValueRef -LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString, size_t AsmStringLen, - char *Constraints, size_t ConstraintsLen, - LLVMBool HasSideEffects, LLVMBool IsAlignStack, - LLVMRustAsmDialect Dialect, LLVMBool CanThrow) { - return wrap(InlineAsm::get( - unwrap(Ty), StringRef(AsmString, AsmStringLen), - StringRef(Constraints, ConstraintsLen), HasSideEffects, IsAlignStack, - fromRust(Dialect), CanThrow)); -} - extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty, char *Constraints, size_t ConstraintsLen) { // llvm::Error converts to true if it is an error. From b1094f6a0a489bb1bc2be6ca17d2bec269bd9364 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 10 May 2025 18:26:57 +1000 Subject: [PATCH 2164/4206] Add a safe wrapper for `LLVMAppendModuleInlineAsm` This patch also changes the Rust-side declaration to take `*const c_uchar` instead of `*const c_char`, to avoid the need for `AsCCharPtr`. --- compiler/rustc_codegen_llvm/src/asm.rs | 8 +------- compiler/rustc_codegen_llvm/src/back/write.rs | 4 ++-- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 8 ++++++-- compiler/rustc_codegen_llvm/src/llvm/mod.rs | 8 ++++++++ 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index c3851dc7762b5..15bd1f6901dc6 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -435,13 +435,7 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { template_str.push_str("\n.att_syntax\n"); } - unsafe { - llvm::LLVMAppendModuleInlineAsm( - self.llmod, - template_str.as_c_char_ptr(), - template_str.len(), - ); - } + llvm::append_module_inline_asm(self.llmod, template_str.as_bytes()); } fn mangled_name(&self, instance: Instance<'tcx>) -> String { diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 4ac77c8f7f165..20721c7460878 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -1148,9 +1148,9 @@ unsafe fn embed_bitcode( // We need custom section flags, so emit module-level inline assembly. let section_flags = if cgcx.is_pe_coff { "n" } else { "e" }; let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode); - llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_c_char_ptr(), asm.len()); + llvm::append_module_inline_asm(llmod, &asm); let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes()); - llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_c_char_ptr(), asm.len()); + llvm::append_module_inline_asm(llmod, &asm); } } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 2b71e8954bbda..507a29c15c8d0 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1014,8 +1014,12 @@ unsafe extern "C" { pub(crate) fn LLVMGetDataLayoutStr(M: &Module) -> *const c_char; pub(crate) fn LLVMSetDataLayout(M: &Module, Triple: *const c_char); - /// See Module::setModuleInlineAsm. - pub(crate) fn LLVMAppendModuleInlineAsm(M: &Module, Asm: *const c_char, Len: size_t); + /// Append inline assembly to a module. See `Module::appendModuleInlineAsm`. + pub(crate) fn LLVMAppendModuleInlineAsm( + M: &Module, + Asm: *const c_uchar, // See "PTR_LEN_STR". + Len: size_t, + ); /// Create the specified uniqued inline asm string. See `InlineAsm::get()`. pub(crate) fn LLVMGetInlineAsm<'ll>( diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index d14aab060731a..7dbcfb508cefc 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -440,3 +440,11 @@ pub(crate) fn set_dso_local<'ll>(v: &'ll Value) { LLVMRustSetDSOLocal(v, true); } } + +/// Safe wrapper for `LLVMAppendModuleInlineAsm`, which delegates to +/// `Module::appendModuleInlineAsm`. +pub(crate) fn append_module_inline_asm<'ll>(llmod: &'ll Module, asm: &[u8]) { + unsafe { + LLVMAppendModuleInlineAsm(llmod, asm.as_ptr(), asm.len()); + } +} From b6300294a852f9a14ab9eb1f706d4a966aeb18ed Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 11 May 2025 14:09:50 +1000 Subject: [PATCH 2165/4206] Make `LLVMRustInlineAsmVerify` take `*const c_uchar` This avoids the need for an explicit `as_c_char_ptr` conversion. --- compiler/rustc_codegen_llvm/src/asm.rs | 5 ++--- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 15bd1f6901dc6..c0b75fa43b724 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -14,7 +14,7 @@ use smallvec::SmallVec; use tracing::debug; use crate::builder::Builder; -use crate::common::{AsCCharPtr, Funclet}; +use crate::common::Funclet; use crate::context::CodegenCx; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; @@ -477,8 +477,7 @@ pub(crate) fn inline_asm_call<'ll>( debug!("Asm Output Type: {:?}", output); let fty = bx.cx.type_func(&argtys, output); // Ask LLVM to verify that the constraints are well-formed. - let constraints_ok = - unsafe { llvm::LLVMRustInlineAsmVerify(fty, cons.as_c_char_ptr(), cons.len()) }; + let constraints_ok = unsafe { llvm::LLVMRustInlineAsmVerify(fty, cons.as_ptr(), cons.len()) }; debug!("constraint verification result: {:?}", constraints_ok); if constraints_ok { let v = unsafe { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 507a29c15c8d0..67a66e6ec795f 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2013,7 +2013,7 @@ unsafe extern "C" { pub(crate) fn LLVMRustInlineAsmVerify( Ty: &Type, - Constraints: *const c_char, + Constraints: *const c_uchar, // See "PTR_LEN_STR". ConstraintsLen: size_t, ) -> bool; From eccf0647d3dfcef826a40fdcc7cde279ea154eaf Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 10 May 2025 21:25:17 +1000 Subject: [PATCH 2166/4206] Flatten control-flow in `inline_asm_call` after verification --- compiler/rustc_codegen_llvm/src/asm.rs | 105 +++++++++++++------------ 1 file changed, 53 insertions(+), 52 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index c0b75fa43b724..9e3893d5314ae 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -476,66 +476,67 @@ pub(crate) fn inline_asm_call<'ll>( debug!("Asm Output Type: {:?}", output); let fty = bx.cx.type_func(&argtys, output); + // Ask LLVM to verify that the constraints are well-formed. let constraints_ok = unsafe { llvm::LLVMRustInlineAsmVerify(fty, cons.as_ptr(), cons.len()) }; debug!("constraint verification result: {:?}", constraints_ok); - if constraints_ok { - let v = unsafe { - llvm::LLVMGetInlineAsm( - fty, - asm.as_ptr(), - asm.len(), - cons.as_ptr(), - cons.len(), - volatile, - alignstack, - dia, - can_throw, - ) - }; + if !constraints_ok { + // LLVM has detected an issue with our constraints, so bail out. + return None; + } - let call = if !labels.is_empty() { - assert!(catch_funclet.is_none()); - bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None, None) - } else if let Some((catch, funclet)) = catch_funclet { - bx.invoke(fty, None, None, v, inputs, dest.unwrap(), catch, funclet, None) - } else { - bx.call(fty, None, None, v, inputs, None, None) - }; + let v = unsafe { + llvm::LLVMGetInlineAsm( + fty, + asm.as_ptr(), + asm.len(), + cons.as_ptr(), + cons.len(), + volatile, + alignstack, + dia, + can_throw, + ) + }; - // Store mark in a metadata node so we can map LLVM errors - // back to source locations. See #17552. - let key = "srcloc"; - let kind = bx.get_md_kind_id(key); + let call = if !labels.is_empty() { + assert!(catch_funclet.is_none()); + bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None, None) + } else if let Some((catch, funclet)) = catch_funclet { + bx.invoke(fty, None, None, v, inputs, dest.unwrap(), catch, funclet, None) + } else { + bx.call(fty, None, None, v, inputs, None, None) + }; - // `srcloc` contains one 64-bit integer for each line of assembly code, - // where the lower 32 bits hold the lo byte position and the upper 32 bits - // hold the hi byte position. - let mut srcloc = vec![]; - if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 { - // LLVM inserts an extra line to add the ".intel_syntax", so add - // a dummy srcloc entry for it. - // - // Don't do this if we only have 1 line span since that may be - // due to the asm template string coming from a macro. LLVM will - // default to the first srcloc for lines that don't have an - // associated srcloc. - srcloc.push(llvm::LLVMValueAsMetadata(bx.const_u64(0))); - } - srcloc.extend(line_spans.iter().map(|span| { - llvm::LLVMValueAsMetadata( - bx.const_u64(u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32)), - ) - })); - let md = unsafe { llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len()) }; - let md = bx.get_metadata_value(md); - llvm::LLVMSetMetadata(call, kind, md); + // Store mark in a metadata node so we can map LLVM errors + // back to source locations. See #17552. + let key = "srcloc"; + let kind = bx.get_md_kind_id(key); - Some(call) - } else { - // LLVM has detected an issue with our constraints, bail out - None + // `srcloc` contains one 64-bit integer for each line of assembly code, + // where the lower 32 bits hold the lo byte position and the upper 32 bits + // hold the hi byte position. + let mut srcloc = vec![]; + if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 { + // LLVM inserts an extra line to add the ".intel_syntax", so add + // a dummy srcloc entry for it. + // + // Don't do this if we only have 1 line span since that may be + // due to the asm template string coming from a macro. LLVM will + // default to the first srcloc for lines that don't have an + // associated srcloc. + srcloc.push(llvm::LLVMValueAsMetadata(bx.const_u64(0))); } + srcloc.extend(line_spans.iter().map(|span| { + llvm::LLVMValueAsMetadata( + bx.const_u64(u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32)), + ) + })); + let md = unsafe { llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len()) }; + let md = bx.get_metadata_value(md); + llvm::LLVMSetMetadata(call, kind, md); + + Some(call) } /// If the register is an xmm/ymm/zmm register then return its index. From b8d55544c5442a3d556c54af9a1956e1578da0e4 Mon Sep 17 00:00:00 2001 From: SpecificProtagonist Date: Sun, 11 May 2025 07:58:18 +0200 Subject: [PATCH 2167/4206] remove superfluous import --- tests/rustdoc-gui/collapse-trait-impl.goml | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/rustdoc-gui/collapse-trait-impl.goml b/tests/rustdoc-gui/collapse-trait-impl.goml index 5f95dcc01c11c..9b2e76a3ef912 100644 --- a/tests/rustdoc-gui/collapse-trait-impl.goml +++ b/tests/rustdoc-gui/collapse-trait-impl.goml @@ -1,5 +1,4 @@ // Checks that individual trait impls can only be collapsed via clicking directly on the summary element -include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" assert-attribute: ("details:has(#trait-impl-link-in-summary)", {"open": ""}) From 4516a5b96bbf8ba39dd74913aac7297c0c0f2ab6 Mon Sep 17 00:00:00 2001 From: SpecificProtagonist Date: Sun, 11 May 2025 08:02:19 +0200 Subject: [PATCH 2168/4206] better checks --- tests/rustdoc-gui/collapse-trait-impl.goml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/rustdoc-gui/collapse-trait-impl.goml b/tests/rustdoc-gui/collapse-trait-impl.goml index 9b2e76a3ef912..4db02e5239b5e 100644 --- a/tests/rustdoc-gui/collapse-trait-impl.goml +++ b/tests/rustdoc-gui/collapse-trait-impl.goml @@ -6,17 +6,21 @@ assert-attribute: ("details:has(#trait-impl-link-in-summary)", {"open": ""}) // Collapse the trait impl doc. The actual clickable area is outside the element, hence offset. click-with-offset: ("summary:has(#trait-impl-link-in-summary)", {"x": -15, "y": 5}) assert-attribute-false: ("details:has(#trait-impl-link-in-summary)", {"open": ""}) +click-with-offset: ("summary:has(#trait-impl-link-in-summary)", {"x": -15, "y": 5}) +assert-attribute: ("details:has(#trait-impl-link-in-summary)", {"open": ""}) // Clicks on the text should be ignored click: "summary:has(#trait-impl-link-in-summary) > .impl" -assert-window-property: ({"pageYOffset": "0"}) +assert-attribute: ("details:has(#trait-impl-link-in-summary)", {"open": ""}) // But links should still work click: "summary:has(#trait-impl-link-in-summary) a:has(#trait-impl-link-in-summary)" assert-window-property-false: ({"pageYOffset": "0"}) +assert-attribute: ("details:has(#trait-impl-link-in-summary)", {"open": ""}) // As well as clicks on elements within links go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" assert-window-property: ({"pageYOffset": "0"}) click: "#trait-impl-link-in-summary" assert-window-property-false: ({"pageYOffset": "0"}) +assert-attribute: ("details:has(#trait-impl-link-in-summary)", {"open": ""}) From 18eb2934357d253da68503716ea0bd21dcb61310 Mon Sep 17 00:00:00 2001 From: Kazuki Obata Date: Sun, 11 May 2025 16:05:31 +0900 Subject: [PATCH 2169/4206] update dev doc: update FnKind::Fn matching Ident was moved to the struct Fn in https://github.com/rust-lang/rust/pull/138740 --- book/src/development/adding_lints.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index e5e82ede4fdf9..2b89e94cf8f4f 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -416,7 +416,7 @@ In our example, `is_foo_fn` looks like: fn is_foo_fn(fn_kind: FnKind<'_>) -> bool { match fn_kind { - FnKind::Fn(_, ident, ..) => { + FnKind::Fn(_, _, Fn { ident, .. }) => { // check if `fn` name is `foo` ident.name.as_str() == "foo" } From f96fb61e4b87f9b2a90df2ee58c8a99d0dc0f83a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 May 2025 09:28:47 +0200 Subject: [PATCH 2170/4206] checktools.sh: fix bashism --- src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh index 9ed5b519b6ea4..9222710b84376 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh @@ -47,7 +47,7 @@ fi # we only ensure that all assertions still pass. MIRIFLAGS="-Zmiri-force-intrinsic-fallback --cfg force_intrinsic_fallback -O -Zmir-opt-level=4 -Cdebug-assertions=yes" \ MIRI_SKIP_UI_CHECKS=1 \ - python3 "$X_PY" test --stage 2 src/tools/miri -- tests/{pass,panic} + python3 "$X_PY" test --stage 2 src/tools/miri -- tests/pass tests/panic # We natively run this script on x86_64-unknown-linux-gnu and x86_64-pc-windows-msvc. # Also cover some other targets via cross-testing, in particular all tier 1 targets. case $HOST_TARGET in From 7727a45725ced7cf039dada4b40ecfa831c6c17b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Sun, 11 May 2025 17:42:48 +0800 Subject: [PATCH 2171/4206] Update ctrlc & libloading for rustc --- Cargo.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 624a4226bd69a..e3fbb0027b400 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -849,9 +849,9 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.6" +version = "3.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "697b5419f348fd5ae2478e8018cb016c00a5881c7f46c717de98ffd135a5651c" +checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73" dependencies = [ "nix", "windows-sys 0.59.0", @@ -2058,12 +2058,12 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.53.0", ] [[package]] @@ -2321,9 +2321,9 @@ checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "nix" -version = "0.29.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ "bitflags", "cfg-if", From dbdbde2a72ae26b9aaad8eae5d81635b36031f7b Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 11 May 2025 20:48:41 +1000 Subject: [PATCH 2172/4206] Rename `OperandBundleOwned` to `OperandBundleBox` As with `DIBuilderBox`, the "Box" suffix does a better job of communicating that this is an owning pointer to some borrowable resource. This also renames the `raw` method to `as_ref`, which is what it would have been named originally if the `Deref` problem had been known at the time. --- compiler/rustc_codegen_llvm/src/builder.rs | 10 +++++----- compiler/rustc_codegen_llvm/src/common.rs | 6 +++--- compiler/rustc_codegen_llvm/src/llvm/mod.rs | 19 ++++++++++--------- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 04c8118b6160c..5238755c8eb94 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -361,7 +361,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // Emit KCFI operand bundle let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn); - if let Some(kcfi_bundle) = kcfi_bundle.as_ref().map(|b| b.raw()) { + if let Some(kcfi_bundle) = kcfi_bundle.as_ref().map(|b| b.as_ref()) { bundles.push(kcfi_bundle); } @@ -1416,7 +1416,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // Emit KCFI operand bundle let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn); - if let Some(kcfi_bundle) = kcfi_bundle.as_ref().map(|b| b.raw()) { + if let Some(kcfi_bundle) = kcfi_bundle.as_ref().map(|b| b.as_ref()) { bundles.push(kcfi_bundle); } @@ -1749,7 +1749,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { // Emit KCFI operand bundle let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn); - if let Some(kcfi_bundle) = kcfi_bundle.as_ref().map(|b| b.raw()) { + if let Some(kcfi_bundle) = kcfi_bundle.as_ref().map(|b| b.as_ref()) { bundles.push(kcfi_bundle); } @@ -1836,7 +1836,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, instance: Option>, llfn: &'ll Value, - ) -> Option> { + ) -> Option> { let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) }; let kcfi_bundle = if self.tcx.sess.is_sanitizer_kcfi_enabled() && let Some(fn_abi) = fn_abi @@ -1862,7 +1862,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { kcfi::typeid_for_fnabi(self.tcx, fn_abi, options) }; - Some(llvm::OperandBundleOwned::new("kcfi", &[self.const_u32(kcfi_typeid)])) + Some(llvm::OperandBundleBox::new("kcfi", &[self.const_u32(kcfi_typeid)])) } else { None }; diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index a6f277e4455b9..3cfa96393e920 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -67,12 +67,12 @@ use crate::value::Value; /// the `OperandBundleDef` value created for MSVC landing pads. pub(crate) struct Funclet<'ll> { cleanuppad: &'ll Value, - operand: llvm::OperandBundleOwned<'ll>, + operand: llvm::OperandBundleBox<'ll>, } impl<'ll> Funclet<'ll> { pub(crate) fn new(cleanuppad: &'ll Value) -> Self { - Funclet { cleanuppad, operand: llvm::OperandBundleOwned::new("funclet", &[cleanuppad]) } + Funclet { cleanuppad, operand: llvm::OperandBundleBox::new("funclet", &[cleanuppad]) } } pub(crate) fn cleanuppad(&self) -> &'ll Value { @@ -80,7 +80,7 @@ impl<'ll> Funclet<'ll> { } pub(crate) fn bundle(&self) -> &llvm::OperandBundle<'ll> { - self.operand.raw() + self.operand.as_ref() } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index d14aab060731a..606d97619a09a 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -363,12 +363,13 @@ pub(crate) fn last_error() -> Option { } } -/// Owns an [`OperandBundle`], and will dispose of it when dropped. -pub(crate) struct OperandBundleOwned<'a> { +/// Owning pointer to an [`OperandBundle`] that will dispose of the bundle +/// when dropped. +pub(crate) struct OperandBundleBox<'a> { raw: ptr::NonNull>, } -impl<'a> OperandBundleOwned<'a> { +impl<'a> OperandBundleBox<'a> { pub(crate) fn new(name: &str, vals: &[&'a Value]) -> Self { let raw = unsafe { LLVMCreateOperandBundle( @@ -378,21 +379,21 @@ impl<'a> OperandBundleOwned<'a> { vals.len() as c_uint, ) }; - OperandBundleOwned { raw: ptr::NonNull::new(raw).unwrap() } + Self { raw: ptr::NonNull::new(raw).unwrap() } } - /// Returns inner `OperandBundle` type. + /// Dereferences to the underlying `&OperandBundle`. /// - /// This could be a `Deref` implementation, but `OperandBundle` contains an extern type and - /// `Deref::Target: ?Sized`. - pub(crate) fn raw(&self) -> &OperandBundle<'a> { + /// This can't be a `Deref` implementation because `OperandBundle` transitively + /// contains an extern type, which is incompatible with `Deref::Target: ?Sized`. + pub(crate) fn as_ref(&self) -> &OperandBundle<'a> { // SAFETY: The returned reference is opaque and can only used for FFI. // It is valid for as long as `&self` is. unsafe { self.raw.as_ref() } } } -impl Drop for OperandBundleOwned<'_> { +impl Drop for OperandBundleBox<'_> { fn drop(&mut self) { unsafe { LLVMDisposeOperandBundle(self.raw); From 9ccabd5390375972f3e4d0d2c5299cd7bb77a421 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 11 May 2025 14:00:16 +0200 Subject: [PATCH 2173/4206] Make some `f32`/`f64` tests also run in const-context --- library/coretests/tests/num/mod.rs | 332 ++++++++++++++++------------- 1 file changed, 189 insertions(+), 143 deletions(-) diff --git a/library/coretests/tests/num/mod.rs b/library/coretests/tests/num/mod.rs index 0add9a01e682d..a6b75f7026604 100644 --- a/library/coretests/tests/num/mod.rs +++ b/library/coretests/tests/num/mod.rs @@ -732,157 +732,157 @@ assume_usize_width! { } macro_rules! test_float { - ($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr, $min: expr, $max: expr, $min_pos: expr, $max_exp:expr) => { + ($modname: ident, $fassert: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr, $min: expr, $max: expr, $min_pos: expr, $max_exp:expr) => { mod $modname { #[test] fn min() { - assert_eq!((0.0 as $fty).min(0.0), 0.0); - assert!((0.0 as $fty).min(0.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).min(-0.0), -0.0); - assert!((-0.0 as $fty).min(-0.0).is_sign_negative()); - assert_eq!((9.0 as $fty).min(9.0), 9.0); - assert_eq!((-9.0 as $fty).min(0.0), -9.0); - assert_eq!((0.0 as $fty).min(9.0), 0.0); - assert!((0.0 as $fty).min(9.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).min(9.0), -0.0); - assert!((-0.0 as $fty).min(9.0).is_sign_negative()); - assert_eq!((-0.0 as $fty).min(-9.0), -9.0); - assert_eq!(($inf as $fty).min(9.0), 9.0); - assert_eq!((9.0 as $fty).min($inf), 9.0); - assert_eq!(($inf as $fty).min(-9.0), -9.0); - assert_eq!((-9.0 as $fty).min($inf), -9.0); - assert_eq!(($neginf as $fty).min(9.0), $neginf); - assert_eq!((9.0 as $fty).min($neginf), $neginf); - assert_eq!(($neginf as $fty).min(-9.0), $neginf); - assert_eq!((-9.0 as $fty).min($neginf), $neginf); - assert_eq!(($nan as $fty).min(9.0), 9.0); - assert_eq!(($nan as $fty).min(-9.0), -9.0); - assert_eq!((9.0 as $fty).min($nan), 9.0); - assert_eq!((-9.0 as $fty).min($nan), -9.0); - assert!(($nan as $fty).min($nan).is_nan()); + $fassert!((0.0 as $fty).min(0.0), 0.0); + $fassert!((0.0 as $fty).min(0.0).is_sign_positive()); + $fassert!((-0.0 as $fty).min(-0.0), -0.0); + $fassert!((-0.0 as $fty).min(-0.0).is_sign_negative()); + $fassert!((9.0 as $fty).min(9.0), 9.0); + $fassert!((-9.0 as $fty).min(0.0), -9.0); + $fassert!((0.0 as $fty).min(9.0), 0.0); + $fassert!((0.0 as $fty).min(9.0).is_sign_positive()); + $fassert!((-0.0 as $fty).min(9.0), -0.0); + $fassert!((-0.0 as $fty).min(9.0).is_sign_negative()); + $fassert!((-0.0 as $fty).min(-9.0), -9.0); + $fassert!(($inf as $fty).min(9.0), 9.0); + $fassert!((9.0 as $fty).min($inf), 9.0); + $fassert!(($inf as $fty).min(-9.0), -9.0); + $fassert!((-9.0 as $fty).min($inf), -9.0); + $fassert!(($neginf as $fty).min(9.0), $neginf); + $fassert!((9.0 as $fty).min($neginf), $neginf); + $fassert!(($neginf as $fty).min(-9.0), $neginf); + $fassert!((-9.0 as $fty).min($neginf), $neginf); + $fassert!(($nan as $fty).min(9.0), 9.0); + $fassert!(($nan as $fty).min(-9.0), -9.0); + $fassert!((9.0 as $fty).min($nan), 9.0); + $fassert!((-9.0 as $fty).min($nan), -9.0); + $fassert!(($nan as $fty).min($nan).is_nan()); } #[test] fn max() { - assert_eq!((0.0 as $fty).max(0.0), 0.0); - assert!((0.0 as $fty).max(0.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).max(-0.0), -0.0); - assert!((-0.0 as $fty).max(-0.0).is_sign_negative()); - assert_eq!((9.0 as $fty).max(9.0), 9.0); - assert_eq!((-9.0 as $fty).max(0.0), 0.0); - assert!((-9.0 as $fty).max(0.0).is_sign_positive()); - assert_eq!((-9.0 as $fty).max(-0.0), -0.0); - assert!((-9.0 as $fty).max(-0.0).is_sign_negative()); - assert_eq!((0.0 as $fty).max(9.0), 9.0); - assert_eq!((0.0 as $fty).max(-9.0), 0.0); - assert!((0.0 as $fty).max(-9.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).max(-9.0), -0.0); - assert!((-0.0 as $fty).max(-9.0).is_sign_negative()); - assert_eq!(($inf as $fty).max(9.0), $inf); - assert_eq!((9.0 as $fty).max($inf), $inf); - assert_eq!(($inf as $fty).max(-9.0), $inf); - assert_eq!((-9.0 as $fty).max($inf), $inf); - assert_eq!(($neginf as $fty).max(9.0), 9.0); - assert_eq!((9.0 as $fty).max($neginf), 9.0); - assert_eq!(($neginf as $fty).max(-9.0), -9.0); - assert_eq!((-9.0 as $fty).max($neginf), -9.0); - assert_eq!(($nan as $fty).max(9.0), 9.0); - assert_eq!(($nan as $fty).max(-9.0), -9.0); - assert_eq!((9.0 as $fty).max($nan), 9.0); - assert_eq!((-9.0 as $fty).max($nan), -9.0); - assert!(($nan as $fty).max($nan).is_nan()); + $fassert!((0.0 as $fty).max(0.0), 0.0); + $fassert!((0.0 as $fty).max(0.0).is_sign_positive()); + $fassert!((-0.0 as $fty).max(-0.0), -0.0); + $fassert!((-0.0 as $fty).max(-0.0).is_sign_negative()); + $fassert!((9.0 as $fty).max(9.0), 9.0); + $fassert!((-9.0 as $fty).max(0.0), 0.0); + $fassert!((-9.0 as $fty).max(0.0).is_sign_positive()); + $fassert!((-9.0 as $fty).max(-0.0), -0.0); + $fassert!((-9.0 as $fty).max(-0.0).is_sign_negative()); + $fassert!((0.0 as $fty).max(9.0), 9.0); + $fassert!((0.0 as $fty).max(-9.0), 0.0); + $fassert!((0.0 as $fty).max(-9.0).is_sign_positive()); + $fassert!((-0.0 as $fty).max(-9.0), -0.0); + $fassert!((-0.0 as $fty).max(-9.0).is_sign_negative()); + $fassert!(($inf as $fty).max(9.0), $inf); + $fassert!((9.0 as $fty).max($inf), $inf); + $fassert!(($inf as $fty).max(-9.0), $inf); + $fassert!((-9.0 as $fty).max($inf), $inf); + $fassert!(($neginf as $fty).max(9.0), 9.0); + $fassert!((9.0 as $fty).max($neginf), 9.0); + $fassert!(($neginf as $fty).max(-9.0), -9.0); + $fassert!((-9.0 as $fty).max($neginf), -9.0); + $fassert!(($nan as $fty).max(9.0), 9.0); + $fassert!(($nan as $fty).max(-9.0), -9.0); + $fassert!((9.0 as $fty).max($nan), 9.0); + $fassert!((-9.0 as $fty).max($nan), -9.0); + $fassert!(($nan as $fty).max($nan).is_nan()); } #[test] fn minimum() { - assert_eq!((0.0 as $fty).minimum(0.0), 0.0); - assert!((0.0 as $fty).minimum(0.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).minimum(0.0), -0.0); - assert!((-0.0 as $fty).minimum(0.0).is_sign_negative()); - assert_eq!((-0.0 as $fty).minimum(-0.0), -0.0); - assert!((-0.0 as $fty).minimum(-0.0).is_sign_negative()); - assert_eq!((9.0 as $fty).minimum(9.0), 9.0); - assert_eq!((-9.0 as $fty).minimum(0.0), -9.0); - assert_eq!((0.0 as $fty).minimum(9.0), 0.0); - assert!((0.0 as $fty).minimum(9.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).minimum(9.0), -0.0); - assert!((-0.0 as $fty).minimum(9.0).is_sign_negative()); - assert_eq!((-0.0 as $fty).minimum(-9.0), -9.0); - assert_eq!(($inf as $fty).minimum(9.0), 9.0); - assert_eq!((9.0 as $fty).minimum($inf), 9.0); - assert_eq!(($inf as $fty).minimum(-9.0), -9.0); - assert_eq!((-9.0 as $fty).minimum($inf), -9.0); - assert_eq!(($neginf as $fty).minimum(9.0), $neginf); - assert_eq!((9.0 as $fty).minimum($neginf), $neginf); - assert_eq!(($neginf as $fty).minimum(-9.0), $neginf); - assert_eq!((-9.0 as $fty).minimum($neginf), $neginf); - assert!(($nan as $fty).minimum(9.0).is_nan()); - assert!(($nan as $fty).minimum(-9.0).is_nan()); - assert!((9.0 as $fty).minimum($nan).is_nan()); - assert!((-9.0 as $fty).minimum($nan).is_nan()); - assert!(($nan as $fty).minimum($nan).is_nan()); + $fassert!((0.0 as $fty).minimum(0.0), 0.0); + $fassert!((0.0 as $fty).minimum(0.0).is_sign_positive()); + $fassert!((-0.0 as $fty).minimum(0.0), -0.0); + $fassert!((-0.0 as $fty).minimum(0.0).is_sign_negative()); + $fassert!((-0.0 as $fty).minimum(-0.0), -0.0); + $fassert!((-0.0 as $fty).minimum(-0.0).is_sign_negative()); + $fassert!((9.0 as $fty).minimum(9.0), 9.0); + $fassert!((-9.0 as $fty).minimum(0.0), -9.0); + $fassert!((0.0 as $fty).minimum(9.0), 0.0); + $fassert!((0.0 as $fty).minimum(9.0).is_sign_positive()); + $fassert!((-0.0 as $fty).minimum(9.0), -0.0); + $fassert!((-0.0 as $fty).minimum(9.0).is_sign_negative()); + $fassert!((-0.0 as $fty).minimum(-9.0), -9.0); + $fassert!(($inf as $fty).minimum(9.0), 9.0); + $fassert!((9.0 as $fty).minimum($inf), 9.0); + $fassert!(($inf as $fty).minimum(-9.0), -9.0); + $fassert!((-9.0 as $fty).minimum($inf), -9.0); + $fassert!(($neginf as $fty).minimum(9.0), $neginf); + $fassert!((9.0 as $fty).minimum($neginf), $neginf); + $fassert!(($neginf as $fty).minimum(-9.0), $neginf); + $fassert!((-9.0 as $fty).minimum($neginf), $neginf); + $fassert!(($nan as $fty).minimum(9.0).is_nan()); + $fassert!(($nan as $fty).minimum(-9.0).is_nan()); + $fassert!((9.0 as $fty).minimum($nan).is_nan()); + $fassert!((-9.0 as $fty).minimum($nan).is_nan()); + $fassert!(($nan as $fty).minimum($nan).is_nan()); } #[test] fn maximum() { - assert_eq!((0.0 as $fty).maximum(0.0), 0.0); - assert!((0.0 as $fty).maximum(0.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).maximum(0.0), 0.0); - assert!((-0.0 as $fty).maximum(0.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).maximum(-0.0), -0.0); - assert!((-0.0 as $fty).maximum(-0.0).is_sign_negative()); - assert_eq!((9.0 as $fty).maximum(9.0), 9.0); - assert_eq!((-9.0 as $fty).maximum(0.0), 0.0); - assert!((-9.0 as $fty).maximum(0.0).is_sign_positive()); - assert_eq!((-9.0 as $fty).maximum(-0.0), -0.0); - assert!((-9.0 as $fty).maximum(-0.0).is_sign_negative()); - assert_eq!((0.0 as $fty).maximum(9.0), 9.0); - assert_eq!((0.0 as $fty).maximum(-9.0), 0.0); - assert!((0.0 as $fty).maximum(-9.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).maximum(-9.0), -0.0); - assert!((-0.0 as $fty).maximum(-9.0).is_sign_negative()); - assert_eq!(($inf as $fty).maximum(9.0), $inf); - assert_eq!((9.0 as $fty).maximum($inf), $inf); - assert_eq!(($inf as $fty).maximum(-9.0), $inf); - assert_eq!((-9.0 as $fty).maximum($inf), $inf); - assert_eq!(($neginf as $fty).maximum(9.0), 9.0); - assert_eq!((9.0 as $fty).maximum($neginf), 9.0); - assert_eq!(($neginf as $fty).maximum(-9.0), -9.0); - assert_eq!((-9.0 as $fty).maximum($neginf), -9.0); - assert!(($nan as $fty).maximum(9.0).is_nan()); - assert!(($nan as $fty).maximum(-9.0).is_nan()); - assert!((9.0 as $fty).maximum($nan).is_nan()); - assert!((-9.0 as $fty).maximum($nan).is_nan()); - assert!(($nan as $fty).maximum($nan).is_nan()); + $fassert!((0.0 as $fty).maximum(0.0), 0.0); + $fassert!((0.0 as $fty).maximum(0.0).is_sign_positive()); + $fassert!((-0.0 as $fty).maximum(0.0), 0.0); + $fassert!((-0.0 as $fty).maximum(0.0).is_sign_positive()); + $fassert!((-0.0 as $fty).maximum(-0.0), -0.0); + $fassert!((-0.0 as $fty).maximum(-0.0).is_sign_negative()); + $fassert!((9.0 as $fty).maximum(9.0), 9.0); + $fassert!((-9.0 as $fty).maximum(0.0), 0.0); + $fassert!((-9.0 as $fty).maximum(0.0).is_sign_positive()); + $fassert!((-9.0 as $fty).maximum(-0.0), -0.0); + $fassert!((-9.0 as $fty).maximum(-0.0).is_sign_negative()); + $fassert!((0.0 as $fty).maximum(9.0), 9.0); + $fassert!((0.0 as $fty).maximum(-9.0), 0.0); + $fassert!((0.0 as $fty).maximum(-9.0).is_sign_positive()); + $fassert!((-0.0 as $fty).maximum(-9.0), -0.0); + $fassert!((-0.0 as $fty).maximum(-9.0).is_sign_negative()); + $fassert!(($inf as $fty).maximum(9.0), $inf); + $fassert!((9.0 as $fty).maximum($inf), $inf); + $fassert!(($inf as $fty).maximum(-9.0), $inf); + $fassert!((-9.0 as $fty).maximum($inf), $inf); + $fassert!(($neginf as $fty).maximum(9.0), 9.0); + $fassert!((9.0 as $fty).maximum($neginf), 9.0); + $fassert!(($neginf as $fty).maximum(-9.0), -9.0); + $fassert!((-9.0 as $fty).maximum($neginf), -9.0); + $fassert!(($nan as $fty).maximum(9.0).is_nan()); + $fassert!(($nan as $fty).maximum(-9.0).is_nan()); + $fassert!((9.0 as $fty).maximum($nan).is_nan()); + $fassert!((-9.0 as $fty).maximum($nan).is_nan()); + $fassert!(($nan as $fty).maximum($nan).is_nan()); } #[test] fn midpoint() { - assert_eq!((0.5 as $fty).midpoint(0.5), 0.5); - assert_eq!((0.5 as $fty).midpoint(2.5), 1.5); - assert_eq!((3.0 as $fty).midpoint(4.0), 3.5); - assert_eq!((-3.0 as $fty).midpoint(4.0), 0.5); - assert_eq!((3.0 as $fty).midpoint(-4.0), -0.5); - assert_eq!((-3.0 as $fty).midpoint(-4.0), -3.5); - assert_eq!((0.0 as $fty).midpoint(0.0), 0.0); - assert_eq!((-0.0 as $fty).midpoint(-0.0), -0.0); - assert_eq!((-5.0 as $fty).midpoint(5.0), 0.0); - assert_eq!(($max as $fty).midpoint($min), 0.0); - assert_eq!(($min as $fty).midpoint($max), -0.0); - assert_eq!(($max as $fty).midpoint($min_pos), $max / 2.); - assert_eq!((-$max as $fty).midpoint($min_pos), -$max / 2.); - assert_eq!(($max as $fty).midpoint(-$min_pos), $max / 2.); - assert_eq!((-$max as $fty).midpoint(-$min_pos), -$max / 2.); - assert_eq!(($min_pos as $fty).midpoint($max), $max / 2.); - assert_eq!(($min_pos as $fty).midpoint(-$max), -$max / 2.); - assert_eq!((-$min_pos as $fty).midpoint($max), $max / 2.); - assert_eq!((-$min_pos as $fty).midpoint(-$max), -$max / 2.); - assert_eq!(($max as $fty).midpoint($max), $max); - assert_eq!(($min_pos as $fty).midpoint($min_pos), $min_pos); - assert_eq!((-$min_pos as $fty).midpoint(-$min_pos), -$min_pos); - assert_eq!(($max as $fty).midpoint(5.0), $max / 2.0 + 2.5); - assert_eq!(($max as $fty).midpoint(-5.0), $max / 2.0 - 2.5); - assert_eq!(($inf as $fty).midpoint($inf), $inf); - assert_eq!(($neginf as $fty).midpoint($neginf), $neginf); - assert!(($nan as $fty).midpoint(1.0).is_nan()); - assert!((1.0 as $fty).midpoint($nan).is_nan()); - assert!(($nan as $fty).midpoint($nan).is_nan()); + $fassert!((0.5 as $fty).midpoint(0.5), 0.5); + $fassert!((0.5 as $fty).midpoint(2.5), 1.5); + $fassert!((3.0 as $fty).midpoint(4.0), 3.5); + $fassert!((-3.0 as $fty).midpoint(4.0), 0.5); + $fassert!((3.0 as $fty).midpoint(-4.0), -0.5); + $fassert!((-3.0 as $fty).midpoint(-4.0), -3.5); + $fassert!((0.0 as $fty).midpoint(0.0), 0.0); + $fassert!((-0.0 as $fty).midpoint(-0.0), -0.0); + $fassert!((-5.0 as $fty).midpoint(5.0), 0.0); + $fassert!(($max as $fty).midpoint($min), 0.0); + $fassert!(($min as $fty).midpoint($max), -0.0); + $fassert!(($max as $fty).midpoint($min_pos), $max / 2.); + $fassert!((-$max as $fty).midpoint($min_pos), -$max / 2.); + $fassert!(($max as $fty).midpoint(-$min_pos), $max / 2.); + $fassert!((-$max as $fty).midpoint(-$min_pos), -$max / 2.); + $fassert!(($min_pos as $fty).midpoint($max), $max / 2.); + $fassert!(($min_pos as $fty).midpoint(-$max), -$max / 2.); + $fassert!((-$min_pos as $fty).midpoint($max), $max / 2.); + $fassert!((-$min_pos as $fty).midpoint(-$max), -$max / 2.); + $fassert!(($max as $fty).midpoint($max), $max); + $fassert!(($min_pos as $fty).midpoint($min_pos), $min_pos); + $fassert!((-$min_pos as $fty).midpoint(-$min_pos), -$min_pos); + $fassert!(($max as $fty).midpoint(5.0), $max / 2.0 + 2.5); + $fassert!(($max as $fty).midpoint(-5.0), $max / 2.0 - 2.5); + $fassert!(($inf as $fty).midpoint($inf), $inf); + $fassert!(($neginf as $fty).midpoint($neginf), $neginf); + $fassert!(($nan as $fty).midpoint(1.0).is_nan()); + $fassert!((1.0 as $fty).midpoint($nan).is_nan()); + $fassert!(($nan as $fty).midpoint($nan).is_nan()); // test if large differences in magnitude are still correctly computed. // NOTE: that because of how small x and y are, x + y can never overflow @@ -907,19 +907,19 @@ macro_rules! test_float { } #[test] fn rem_euclid() { - let a: $fty = 42.0; - assert!($inf.rem_euclid(a).is_nan()); - assert_eq!(a.rem_euclid($inf), a); - assert!(a.rem_euclid($nan).is_nan()); + // FIXME: Use $fassert when rem_euclid becomes const + assert!($inf.rem_euclid((42.0 as $fty)).is_nan()); + assert_eq!((42.0 as $fty).rem_euclid($inf), (42.0 as $fty)); + assert!((42.0 as $fty).rem_euclid($nan).is_nan()); assert!($inf.rem_euclid($inf).is_nan()); assert!($inf.rem_euclid($nan).is_nan()); assert!($nan.rem_euclid($inf).is_nan()); } #[test] fn div_euclid() { - let a: $fty = 42.0; - assert_eq!(a.div_euclid($inf), 0.0); - assert!(a.div_euclid($nan).is_nan()); + // FIXME: Use $fassert when div_euclid becomes const + assert_eq!((42.0 as $fty).div_euclid($inf), 0.0); + assert!((42.0 as $fty).div_euclid($nan).is_nan()); assert!($inf.div_euclid($inf).is_nan()); assert!($inf.div_euclid($nan).is_nan()); assert!($nan.div_euclid($inf).is_nan()); @@ -928,8 +928,41 @@ macro_rules! test_float { }; } +// Custom assert macro that distribute between assert! and assert_eq! in a non-const context +macro_rules! float_assert { + ($b:expr) => { + assert!($b); + }; + ($left:expr, $right:expr) => { + assert_eq!($left, $right); + }; +} + +// Custom assert macro that only uses assert! in a const context +macro_rules! float_const_assert { + ($b:expr) => { + assert!(const { $b }); + }; + ($left:expr, $right:expr) => { + assert!(const { $left == $right }); + }; +} + test_float!( f32, + float_assert, + f32, + f32::INFINITY, + f32::NEG_INFINITY, + f32::NAN, + f32::MIN, + f32::MAX, + f32::MIN_POSITIVE, + f32::MAX_EXP +); +test_float!( + f32_const, + float_const_assert, f32, f32::INFINITY, f32::NEG_INFINITY, @@ -941,6 +974,19 @@ test_float!( ); test_float!( f64, + float_assert, + f64, + f64::INFINITY, + f64::NEG_INFINITY, + f64::NAN, + f64::MIN, + f64::MAX, + f64::MIN_POSITIVE, + f64::MAX_EXP +); +test_float!( + f64_const, + float_const_assert, f64, f64::INFINITY, f64::NEG_INFINITY, From 632630086e99bc165f997ec0a17134e716489b9e Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sun, 11 May 2025 14:29:24 +0200 Subject: [PATCH 2174/4206] add regression test for 140207 --- tests/assembly/libs/issue-140207-slice-min-simd.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/assembly/libs/issue-140207-slice-min-simd.rs diff --git a/tests/assembly/libs/issue-140207-slice-min-simd.rs b/tests/assembly/libs/issue-140207-slice-min-simd.rs new file mode 100644 index 0000000000000..86f067cac08a8 --- /dev/null +++ b/tests/assembly/libs/issue-140207-slice-min-simd.rs @@ -0,0 +1,13 @@ +//@ assembly-output: emit-asm +// # avx has a dedicated instruction for this +//@ compile-flags: --crate-type=lib -Ctarget-cpu=znver2 -Copt-level=3 +//@ only-x86_64 +//@ ignore-sgx +// https://github.com/rust-lang/rust/issues/140207 + +#[unsafe(no_mangle)] +pub fn array_min(a: &[u16; 8]) -> u16 { + // CHECK: vphminposuw + // CHECK: ret + a.iter().copied().min().unwrap() +} From f6aeef3d9b4962fbcab5546704dfc094ff156b07 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 10 May 2025 12:42:21 -0700 Subject: [PATCH 2175/4206] Add an issue template for future-incompatible lints --- .../ISSUE_TEMPLATE/tracking_issue_future.md | 54 +++++++++++++++++++ .../rustc-dev-guide/src/bug-fix-procedure.md | 36 ++----------- 2 files changed, 57 insertions(+), 33 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/tracking_issue_future.md diff --git a/.github/ISSUE_TEMPLATE/tracking_issue_future.md b/.github/ISSUE_TEMPLATE/tracking_issue_future.md new file mode 100644 index 0000000000000..f04a458d8a5aa --- /dev/null +++ b/.github/ISSUE_TEMPLATE/tracking_issue_future.md @@ -0,0 +1,54 @@ +--- +name: Future Incompatibility Tracking Issue +about: A tracking issue for a future-incompatible lint +title: Tracking Issue for future-incompatibility lint XXX +labels: C-tracking-issue C-future-incompatibility T-compiler A-lints +--- + + +This is the **tracking issue** for the `YOUR_LINT_NAME_HERE` future-compatibility warning and other related errors. The goal of this page is describe why this change was made and how you can fix code that is affected by it. It also provides a place to ask questions or register a complaint if you feel the change should not be made. For more information on the policy around future-compatibility warnings, see our [breaking change policy guidelines][guidelines]. + +[guidelines]: https://rustc-dev-guide.rust-lang.org/bug-fix-procedure.html + +### What is the warning for? + +*Describe the conditions that trigger the warning.* + +### Why was this change made? + +*Explain why this change was made. If there is additional context, like an MCP, link it here.* + +### Example + +```rust +// Include an example here. +``` + +### Recommendations + +*Give some recommendations on how a user can avoid the lint.* + +### When will this warning become a hard error? + +*If known, describe the future plans. For example, how long you anticipate this being a warning, or if there are other factors that will influence the anticipated closure.* + +### Steps + +- [ ] Implement the lint +- [ ] Raise lint level to deny +- [ ] Make lint report in dependencies +- [ ] Switch to a hard error + +### Implementation history + + diff --git a/src/doc/rustc-dev-guide/src/bug-fix-procedure.md b/src/doc/rustc-dev-guide/src/bug-fix-procedure.md index 8e6725c54efac..55436261fdefa 100644 --- a/src/doc/rustc-dev-guide/src/bug-fix-procedure.md +++ b/src/doc/rustc-dev-guide/src/bug-fix-procedure.md @@ -80,41 +80,11 @@ approachable and practical; it may make sense to direct users to an RFC or some other issue for the full details. The issue also serves as a place where users can comment with questions or other concerns. -A template for these breaking-change tracking issues can be found below. An -example of how such an issue should look can be [found +A template for these breaking-change tracking issues can be found +[here][template]. An example of how such an issue should look can be [found here][breaking-change-issue]. -The issue should be tagged with (at least) `B-unstable` and `T-compiler`. - -### Tracking issue template - -This is a template to use for tracking issues: - -``` -This is the **summary issue** for the `YOUR_LINT_NAME_HERE` -future-compatibility warning and other related errors. The goal of -this page is describe why this change was made and how you can fix -code that is affected by it. It also provides a place to ask questions -or register a complaint if you feel the change should not be made. For -more information on the policy around future-compatibility warnings, -see our [breaking change policy guidelines][guidelines]. - -[guidelines]: LINK_TO_THIS_RFC - -#### What is the warning for? - -*Describe the conditions that trigger the warning and how they can be -fixed. Also explain why the change was made.** - -#### When will this warning become a hard error? - -At the beginning of each 6-week release cycle, the Rust compiler team -will review the set of outstanding future compatibility warnings and -nominate some of them for **Final Comment Period**. Toward the end of -the cycle, we will review any comments and make a final determination -whether to convert the warning into a hard error or remove it -entirely. -``` +[template]: https://github.com/rust-lang/rust/issues/new?template=tracking_issue_future.md ### Issuing future compatibility warnings From 56a0c7dfea60a721948e29458fc714b6303e8e4a Mon Sep 17 00:00:00 2001 From: HaeNoe Date: Sat, 19 Apr 2025 19:17:22 +0200 Subject: [PATCH 2176/4206] feat: propagate generics to generated function --- compiler/rustc_builtin_macros/src/autodiff.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 8c5c20c7af48c..36f84c5d74b2d 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -73,10 +73,10 @@ mod llvm_enzyme { } // Get information about the function the macro is applied to - fn extract_item_info(iitem: &P) -> Option<(Visibility, FnSig, Ident)> { + fn extract_item_info(iitem: &P) -> Option<(Visibility, FnSig, Ident, Generics)> { match &iitem.kind { - ItemKind::Fn(box ast::Fn { sig, ident, .. }) => { - Some((iitem.vis.clone(), sig.clone(), ident.clone())) + ItemKind::Fn(box ast::Fn { sig, ident, generics, .. }) => { + Some((iitem.vis.clone(), sig.clone(), ident.clone(), generics.clone())) } _ => None, } @@ -210,16 +210,18 @@ mod llvm_enzyme { } let dcx = ecx.sess.dcx(); - // first get information about the annotable item: - let Some((vis, sig, primal)) = (match &item { + // first get information about the annotable item: visibility, signature, name and generic + // parameters. + // these will be used to generate the differentiated version of the function + let Some((vis, sig, primal, generics)) = (match &item { Annotatable::Item(iitem) => extract_item_info(iitem), Annotatable::Stmt(stmt) => match &stmt.kind { ast::StmtKind::Item(iitem) => extract_item_info(iitem), _ => None, }, Annotatable::AssocItem(assoc_item, Impl { .. }) => match &assoc_item.kind { - ast::AssocItemKind::Fn(box ast::Fn { sig, ident, .. }) => { - Some((assoc_item.vis.clone(), sig.clone(), ident.clone())) + ast::AssocItemKind::Fn(box ast::Fn { sig, ident, generics, .. }) => { + Some((assoc_item.vis.clone(), sig.clone(), ident.clone(), generics.clone())) } _ => None, }, @@ -310,7 +312,7 @@ mod llvm_enzyme { defaultness: ast::Defaultness::Final, sig: d_sig, ident: first_ident(&meta_item_vec[0]), - generics: Generics::default(), + generics, contract: None, body: Some(d_body), define_opaque: None, From 8b3228233e079b8d5f02484c1e9a06183e855a6d Mon Sep 17 00:00:00 2001 From: HaeNoe Date: Sat, 19 Apr 2025 19:28:33 +0200 Subject: [PATCH 2177/4206] feat: add test for generics in generated function --- tests/pretty/autodiff/autodiff_forward.pp | 14 ++++++++++++++ tests/pretty/autodiff/autodiff_forward.rs | 6 ++++++ 2 files changed, 20 insertions(+) diff --git a/tests/pretty/autodiff/autodiff_forward.pp b/tests/pretty/autodiff/autodiff_forward.pp index 713b8f541ae0d..2fa122a618d66 100644 --- a/tests/pretty/autodiff/autodiff_forward.pp +++ b/tests/pretty/autodiff/autodiff_forward.pp @@ -31,6 +31,8 @@ // We want to make sure that we can use the macro for functions defined inside of functions + // Make sure we can handle generics + ::core::panicking::panic("not implemented") } #[rustc_autodiff(Forward, 1, Dual, Const, Dual)] @@ -181,4 +183,16 @@ ::core::hint::black_box(::default()) } } +#[rustc_autodiff] +#[inline(never)] +pub fn f10 + Copy>(x: &T) -> T { *x * *x } +#[rustc_autodiff(Reverse, 1, Duplicated, Active)] +#[inline(never)] +pub fn d_square + + Copy>(x: &T, dx_0: &mut T, dret: T) -> T { + unsafe { asm!("NOP", options(pure, nomem)); }; + ::core::hint::black_box(f10(x)); + ::core::hint::black_box((dx_0, dret)); + ::core::hint::black_box(f10(x)) +} fn main() {} diff --git a/tests/pretty/autodiff/autodiff_forward.rs b/tests/pretty/autodiff/autodiff_forward.rs index 5a0660a08e526..ae974f9b4dbf9 100644 --- a/tests/pretty/autodiff/autodiff_forward.rs +++ b/tests/pretty/autodiff/autodiff_forward.rs @@ -63,4 +63,10 @@ pub fn f9() { } } +// Make sure we can handle generics +#[autodiff(d_square, Reverse, Duplicated, Active)] +pub fn f10 + Copy>(x: &T) -> T { + *x * *x +} + fn main() {} From e2b7278942642b550d3fe1fdbf08640157df60ef Mon Sep 17 00:00:00 2001 From: HaeNoe Date: Sun, 20 Apr 2025 01:10:50 +0200 Subject: [PATCH 2178/4206] feat: add generated parameters to generated function - update pretty printing tests - only add generic parameters when function is actually generic (no empty turbofish) --- compiler/rustc_builtin_macros/src/autodiff.rs | 55 ++++++++++++++++++- tests/pretty/autodiff/autodiff_forward.pp | 4 +- 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 36f84c5d74b2d..1ff4fc6aaab22 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -305,6 +305,7 @@ mod llvm_enzyme { let (d_sig, new_args, idents, errored) = gen_enzyme_decl(ecx, &sig, &x, span); let d_body = gen_enzyme_body( ecx, &x, n_active, &sig, &d_sig, primal, &new_args, span, sig_span, idents, errored, + &generics, ); // The first element of it is the name of the function to be generated @@ -477,6 +478,7 @@ mod llvm_enzyme { new_decl_span: Span, idents: &[Ident], errored: bool, + generics: &Generics, ) -> (P, P, P, P) { let blackbox_path = ecx.std_path(&[sym::hint, sym::black_box]); let noop = ast::InlineAsm { @@ -499,7 +501,7 @@ mod llvm_enzyme { }; let unsf_expr = ecx.expr_block(P(unsf_block)); let blackbox_call_expr = ecx.expr_path(ecx.path(span, blackbox_path)); - let primal_call = gen_primal_call(ecx, span, primal, idents); + let primal_call = gen_primal_call(ecx, span, primal, idents, generics); let black_box_primal_call = ecx.expr_call( new_decl_span, blackbox_call_expr.clone(), @@ -548,6 +550,7 @@ mod llvm_enzyme { sig_span: Span, idents: Vec, errored: bool, + generics: &Generics, ) -> P { let new_decl_span = d_sig.span; @@ -568,6 +571,7 @@ mod llvm_enzyme { new_decl_span, &idents, errored, + generics, ); if !has_ret(&d_sig.decl.output) { @@ -610,7 +614,6 @@ mod llvm_enzyme { panic!("Did not expect Default ret ty: {:?}", span); } }; - if x.mode.is_fwd() { // Fwd mode is easy. If the return activity is Const, we support arbitrary types. // Otherwise, we only support a scalar, a pair of scalars, or an array of scalars. @@ -670,8 +673,10 @@ mod llvm_enzyme { span: Span, primal: Ident, idents: &[Ident], + generics: &Generics, ) -> P { let has_self = idents.len() > 0 && idents[0].name == kw::SelfLower; + if has_self { let args: ThinVec<_> = idents[1..].iter().map(|arg| ecx.expr_path(ecx.path_ident(span, *arg))).collect(); @@ -680,7 +685,51 @@ mod llvm_enzyme { } else { let args: ThinVec<_> = idents.iter().map(|arg| ecx.expr_path(ecx.path_ident(span, *arg))).collect(); - let primal_call_expr = ecx.expr_path(ecx.path_ident(span, primal)); + let mut primal_path = ecx.path_ident(span, primal); + + let is_generic = !generics.params.is_empty(); + + match (is_generic, primal_path.segments.last_mut()) { + (true, Some(function_path)) => { + let primal_generic_types = generics + .params + .iter() + .filter(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })); + + let generated_generic_types = primal_generic_types + .map(|type_param| { + let generic_param = TyKind::Path( + None, + ast::Path { + span, + segments: thin_vec![ast::PathSegment { + ident: type_param.ident, + args: None, + id: ast::DUMMY_NODE_ID, + }], + tokens: None, + }, + ); + + ast::AngleBracketedArg::Arg(ast::GenericArg::Type(P(ast::Ty { + id: type_param.id, + span, + kind: generic_param, + tokens: None, + }))) + }) + .collect(); + + function_path.args = + Some(P(ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs { + span, + args: generated_generic_types, + }))); + } + _ => {} + } + + let primal_call_expr = ecx.expr_path(primal_path); ecx.expr_call(span, primal_call_expr, args) } } diff --git a/tests/pretty/autodiff/autodiff_forward.pp b/tests/pretty/autodiff/autodiff_forward.pp index 2fa122a618d66..8253603e8079c 100644 --- a/tests/pretty/autodiff/autodiff_forward.pp +++ b/tests/pretty/autodiff/autodiff_forward.pp @@ -191,8 +191,8 @@ pub fn d_square + Copy>(x: &T, dx_0: &mut T, dret: T) -> T { unsafe { asm!("NOP", options(pure, nomem)); }; - ::core::hint::black_box(f10(x)); + ::core::hint::black_box(f10::(x)); ::core::hint::black_box((dx_0, dret)); - ::core::hint::black_box(f10(x)) + ::core::hint::black_box(f10::(x)) } fn main() {} From a504759afd3aa8338ebcb4ddc7b042de14a29642 Mon Sep 17 00:00:00 2001 From: HaeNoe Date: Wed, 23 Apr 2025 11:48:37 +0200 Subject: [PATCH 2179/4206] feat: add codegen test Ensure that code for generic `d_primal::` is generated even if `primal::` is never used. - incorporate feedback from @ZuseZ4 --- tests/codegen/autodiff/generic.rs | 42 +++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 tests/codegen/autodiff/generic.rs diff --git a/tests/codegen/autodiff/generic.rs b/tests/codegen/autodiff/generic.rs new file mode 100644 index 0000000000000..15e7d8a495745 --- /dev/null +++ b/tests/codegen/autodiff/generic.rs @@ -0,0 +1,42 @@ +//@ compile-flags: -Zautodiff=Enable -Zautodiff=NoPostopt -C opt-level=3 -Clto=fat +//@ no-prefer-dynamic +//@ needs-enzyme +#![feature(autodiff)] + +use std::autodiff::autodiff; + +#[autodiff(d_square, Reverse, Duplicated, Active)] +fn square + Copy>(x: &T) -> T { + *x * *x +} + +// Ensure that `d_square::` code is generated even if `square::` was never called +// +// CHECK: ; generic::square +// CHECK-NEXT: ; Function Attrs: +// CHECK-NEXT: define internal {{.*}} double +// CHECK-NEXT: start: +// CHECK-NOT: ret +// CHECK: fmul double + +// Ensure that `d_square::` code is generated +// +// CHECK: ; generic::square +// CHECK-NEXT: ; Function Attrs: {{.*}} +// CHECK-NEXT: define internal {{.*}} float +// CHECK-NEXT: start: +// CHECK-NOT: ret +// CHECK: fmul float + +fn main() { + let xf32: f32 = std::hint::black_box(3.0); + let xf64: f64 = std::hint::black_box(3.0); + + let outputf32 = square::(&xf32); + assert_eq!(9.0, outputf32); + + let mut df_dxf64: f64 = std::hint::black_box(0.0); + + let output_f64 = d_square::(&xf64, &mut df_dxf64, 1.0); + assert_eq!(6.0, df_dxf64); +} From c040e9f6fc51f9198cab65f021cd80a14fae5f52 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sun, 11 May 2025 17:33:20 +0200 Subject: [PATCH 2180/4206] `return_and_then`: only lint returning expressions If an expression is not going to return from the current function of closure, it should not get linted. This also allows `return` expression to be linted, in addition to the final expression. Those require blockification and proper indentation. --- clippy_lints/src/methods/return_and_then.rs | 28 +++++++---- tests/ui/return_and_then.fixed | 52 +++++++++++++++++++++ tests/ui/return_and_then.rs | 47 +++++++++++++++++++ tests/ui/return_and_then.stderr | 47 ++++++++++++++++++- 4 files changed, 165 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/methods/return_and_then.rs b/clippy_lints/src/methods/return_and_then.rs index 91643b0dfefde..df8544f92203e 100644 --- a/clippy_lints/src/methods/return_and_then.rs +++ b/clippy_lints/src/methods/return_and_then.rs @@ -9,7 +9,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline, snippet_with_applicability}; use clippy_utils::ty::get_type_diagnostic_name; use clippy_utils::visitors::for_each_unconsumed_temporary; -use clippy_utils::{is_expr_final_block_expr, peel_blocks}; +use clippy_utils::{get_parent_expr, peel_blocks}; use super::RETURN_AND_THEN; @@ -21,7 +21,7 @@ pub(super) fn check<'tcx>( recv: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'_>, ) { - if !is_expr_final_block_expr(cx.tcx, expr) { + if cx.tcx.hir_get_fn_id_for_return_block(expr.hir_id).is_none() { return; } @@ -55,12 +55,24 @@ pub(super) fn check<'tcx>( None => &body_snip, }; - let sugg = format!( - "let {} = {}?;\n{}", - arg_snip, - recv_snip, - reindent_multiline(inner, false, indent_of(cx, expr.span)) - ); + // If suggestion is going to get inserted as part of a `return` expression, it must be blockified. + let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr) { + let base_indent = indent_of(cx, parent_expr.span); + let inner_indent = base_indent.map(|i| i + 4); + format!( + "{}\n{}\n{}", + reindent_multiline(&format!("{{\nlet {arg_snip} = {recv_snip}?;"), true, inner_indent), + reindent_multiline(inner, false, inner_indent), + reindent_multiline("}", false, base_indent), + ) + } else { + format!( + "let {} = {}?;\n{}", + arg_snip, + recv_snip, + reindent_multiline(inner, false, indent_of(cx, expr.span)) + ) + }; span_lint_and_sugg( cx, diff --git a/tests/ui/return_and_then.fixed b/tests/ui/return_and_then.fixed index 74efa14eeec81..8d9481d159512 100644 --- a/tests/ui/return_and_then.fixed +++ b/tests/ui/return_and_then.fixed @@ -67,8 +67,60 @@ fn main() { .first() // creates temporary reference .and_then(|x| test_opt_block(Some(*x))) } + + fn in_closure() -> bool { + let _ = || { + let x = Some("")?; + if x.len() > 2 { Some(3) } else { None } + //~^ return_and_then + }; + true + } + + fn with_return(shortcut: bool) -> Option { + if shortcut { + return { + let x = Some("")?; + if x.len() > 2 { Some(3) } else { None } + }; + //~^ return_and_then + }; + None + } + + fn with_return_multiline(shortcut: bool) -> Option { + if shortcut { + return { + let mut x = Some("")?; + let x = format!("{x}."); + if x.len() > 2 { Some(3) } else { None } + }; + //~^^^^ return_and_then + }; + None + } } fn gen_option(n: i32) -> Option { Some(n) } + +mod issue14781 { + fn foo(_: &str, _: (u32, u32)) -> Result<(u32, u32), ()> { + Ok((1, 1)) + } + + fn bug(_: Option<&str>) -> Result<(), ()> { + let year: Option<&str> = None; + let month: Option<&str> = None; + let day: Option<&str> = None; + + let _day = if let (Some(year), Some(month)) = (year, month) { + day.and_then(|day| foo(day, (1, 31)).ok()) + } else { + None + }; + + Ok(()) + } +} diff --git a/tests/ui/return_and_then.rs b/tests/ui/return_and_then.rs index 188dc57e588cf..beada921a9187 100644 --- a/tests/ui/return_and_then.rs +++ b/tests/ui/return_and_then.rs @@ -63,8 +63,55 @@ fn main() { .first() // creates temporary reference .and_then(|x| test_opt_block(Some(*x))) } + + fn in_closure() -> bool { + let _ = || { + Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None }) + //~^ return_and_then + }; + true + } + + fn with_return(shortcut: bool) -> Option { + if shortcut { + return Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None }); + //~^ return_and_then + }; + None + } + + fn with_return_multiline(shortcut: bool) -> Option { + if shortcut { + return Some("").and_then(|mut x| { + let x = format!("{x}."); + if x.len() > 2 { Some(3) } else { None } + }); + //~^^^^ return_and_then + }; + None + } } fn gen_option(n: i32) -> Option { Some(n) } + +mod issue14781 { + fn foo(_: &str, _: (u32, u32)) -> Result<(u32, u32), ()> { + Ok((1, 1)) + } + + fn bug(_: Option<&str>) -> Result<(), ()> { + let year: Option<&str> = None; + let month: Option<&str> = None; + let day: Option<&str> = None; + + let _day = if let (Some(year), Some(month)) = (year, month) { + day.and_then(|day| foo(day, (1, 31)).ok()) + } else { + None + }; + + Ok(()) + } +} diff --git a/tests/ui/return_and_then.stderr b/tests/ui/return_and_then.stderr index a7acbe7b3401c..5feca88286057 100644 --- a/tests/ui/return_and_then.stderr +++ b/tests/ui/return_and_then.stderr @@ -101,5 +101,50 @@ LL + })?; LL + if x.len() > 2 { Some(3) } else { None } | -error: aborting due to 7 previous errors +error: use the `?` operator instead of an `and_then` call + --> tests/ui/return_and_then.rs:69:13 + | +LL | Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None }) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL ~ let x = Some("")?; +LL + if x.len() > 2 { Some(3) } else { None } + | + +error: use the `?` operator instead of an `and_then` call + --> tests/ui/return_and_then.rs:77:20 + | +LL | return Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL ~ return { +LL + let x = Some("")?; +LL + if x.len() > 2 { Some(3) } else { None } +LL ~ }; + | + +error: use the `?` operator instead of an `and_then` call + --> tests/ui/return_and_then.rs:85:20 + | +LL | return Some("").and_then(|mut x| { + | ____________________^ +LL | | let x = format!("{x}."); +LL | | if x.len() > 2 { Some(3) } else { None } +LL | | }); + | |______________^ + | +help: try + | +LL ~ return { +LL + let mut x = Some("")?; +LL + let x = format!("{x}."); +LL + if x.len() > 2 { Some(3) } else { None } +LL ~ }; + | + +error: aborting due to 10 previous errors From ba80d820e5b4fb975f12eabac19e2a9c264a3afb Mon Sep 17 00:00:00 2001 From: Andrew Zhogin Date: Sun, 11 May 2025 20:58:52 +0700 Subject: [PATCH 2181/4206] Return value of coroutine_layout fn changed to Result with LayoutError --- compiler/rustc_middle/src/ty/mod.rs | 31 ++++++++++++++------ compiler/rustc_mir_transform/src/validate.rs | 4 +-- compiler/rustc_ty_utils/src/layout.rs | 4 +-- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index dda0faa3afedd..4ba5d8f3ce33b 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -120,6 +120,7 @@ use crate::ty; use crate::ty::codec::{TyDecoder, TyEncoder}; pub use crate::ty::diagnostics::*; use crate::ty::fast_reject::SimplifiedType; +use crate::ty::layout::LayoutError; use crate::ty::util::Discr; use crate::ty::walk::TypeWalker; @@ -1877,6 +1878,11 @@ impl<'tcx> TyCtxt<'tcx> { self.def_kind(trait_def_id) == DefKind::TraitAlias } + /// Arena-alloc of LayoutError for coroutine layout + fn layout_error(self, err: LayoutError<'tcx>) -> &'tcx LayoutError<'tcx> { + self.arena.alloc(err) + } + /// Returns layout of a non-async-drop coroutine. Layout might be unavailable if the /// coroutine is tainted by errors. /// @@ -1885,12 +1891,14 @@ impl<'tcx> TyCtxt<'tcx> { fn ordinary_coroutine_layout( self, def_id: DefId, - coroutine_kind_ty: Ty<'tcx>, - ) -> Option<&'tcx CoroutineLayout<'tcx>> { + args: GenericArgsRef<'tcx>, + ) -> Result<&'tcx CoroutineLayout<'tcx>, &'tcx LayoutError<'tcx>> { + let coroutine_kind_ty = args.as_coroutine().kind_ty(); let mir = self.optimized_mir(def_id); + let ty = || Ty::new_coroutine(self, def_id, args); // Regular coroutine if coroutine_kind_ty.is_unit() { - mir.coroutine_layout_raw() + mir.coroutine_layout_raw().ok_or_else(|| self.layout_error(LayoutError::Unknown(ty()))) } else { // If we have a `Coroutine` that comes from an coroutine-closure, // then it may be a by-move or by-ref body. @@ -1904,6 +1912,7 @@ impl<'tcx> TyCtxt<'tcx> { // a by-ref coroutine. if identity_kind_ty == coroutine_kind_ty { mir.coroutine_layout_raw() + .ok_or_else(|| self.layout_error(LayoutError::Unknown(ty()))) } else { assert_matches!(coroutine_kind_ty.to_opt_closure_kind(), Some(ClosureKind::FnOnce)); assert_matches!( @@ -1912,6 +1921,7 @@ impl<'tcx> TyCtxt<'tcx> { ); self.optimized_mir(self.coroutine_by_move_body_def_id(def_id)) .coroutine_layout_raw() + .ok_or_else(|| self.layout_error(LayoutError::Unknown(ty()))) } } } @@ -1923,12 +1933,15 @@ impl<'tcx> TyCtxt<'tcx> { self, def_id: DefId, args: GenericArgsRef<'tcx>, - ) -> Option<&'tcx CoroutineLayout<'tcx>> { + ) -> Result<&'tcx CoroutineLayout<'tcx>, &'tcx LayoutError<'tcx>> { + let ty = || Ty::new_coroutine(self, def_id, args); if args[0].has_placeholders() || args[0].has_non_region_param() { - return None; + return Err(self.layout_error(LayoutError::TooGeneric(ty()))); } let instance = InstanceKind::AsyncDropGlue(def_id, Ty::new_coroutine(self, def_id, args)); - self.mir_shims(instance).coroutine_layout_raw() + self.mir_shims(instance) + .coroutine_layout_raw() + .ok_or_else(|| self.layout_error(LayoutError::Unknown(ty()))) } /// Returns layout of a coroutine. Layout might be unavailable if the @@ -1937,7 +1950,7 @@ impl<'tcx> TyCtxt<'tcx> { self, def_id: DefId, args: GenericArgsRef<'tcx>, - ) -> Option<&'tcx CoroutineLayout<'tcx>> { + ) -> Result<&'tcx CoroutineLayout<'tcx>, &'tcx LayoutError<'tcx>> { if self.is_async_drop_in_place_coroutine(def_id) { // layout of `async_drop_in_place::{closure}` in case, // when T is a coroutine, contains this internal coroutine's ptr in upvars @@ -1959,12 +1972,12 @@ impl<'tcx> TyCtxt<'tcx> { variant_source_info, storage_conflicts: BitMatrix::new(0, 0), }; - return Some(self.arena.alloc(proxy_layout)); + return Ok(self.arena.alloc(proxy_layout)); } else { self.async_drop_coroutine_layout(def_id, args) } } else { - self.ordinary_coroutine_layout(def_id, args.as_coroutine().kind_ty()) + self.ordinary_coroutine_layout(def_id, args) } } diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index f541a32cd2645..f8d1629b0e266 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -752,7 +752,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let layout = if def_id == self.caller_body.source.def_id() { self.caller_body .coroutine_layout_raw() - .or_else(|| self.tcx.coroutine_layout(def_id, args)) + .or_else(|| self.tcx.coroutine_layout(def_id, args).ok()) } else if self.tcx.needs_coroutine_by_move_body_def_id(def_id) && let ty::ClosureKind::FnOnce = args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap() @@ -762,7 +762,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { // Same if this is the by-move body of a coroutine-closure. self.caller_body.coroutine_layout_raw() } else { - self.tcx.coroutine_layout(def_id, args) + self.tcx.coroutine_layout(def_id, args).ok() }; let Some(layout) = layout else { diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 908fcb14cb2fc..ad57555bd24d3 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -492,9 +492,7 @@ fn layout_of_uncached<'tcx>( ty::Coroutine(def_id, args) => { use rustc_middle::ty::layout::PrimitiveExt as _; - let Some(info) = tcx.coroutine_layout(def_id, args) else { - return Err(error(cx, LayoutError::Unknown(ty))); - }; + let info = tcx.coroutine_layout(def_id, args)?; let local_layouts = info .field_tys From acbc79c8da33d7e38c52e48c83eb967af63ac8f3 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 11 May 2025 19:29:18 +0000 Subject: [PATCH 2182/4206] cargo update compiler & tools dependencies: Locking 40 packages to latest compatible versions Updating clap v4.5.37 -> v4.5.38 Updating clap_builder v4.5.37 -> v4.5.38 Updating ctrlc v3.4.6 -> v3.4.7 Updating derive_setters v0.1.6 -> v0.1.7 Updating getrandom v0.3.2 -> v0.3.3 Updating icu_collections v1.5.0 -> v2.0.0 Adding icu_locale_core v2.0.0 Updating icu_normalizer v1.5.0 -> v2.0.0 Updating icu_normalizer_data v1.5.1 -> v2.0.0 Updating icu_properties v1.5.1 -> v2.0.0 Updating icu_properties_data v1.5.1 -> v2.0.0 Adding icu_provider v2.0.0 Updating idna_adapter v1.2.0 -> v1.2.1 Updating jiff v0.2.12 -> v0.2.13 Updating jiff-static v0.2.12 -> v0.2.13 Updating libffi v4.0.0 -> v4.1.0 Updating libffi-sys v3.2.0 -> v3.3.1 Updating libloading v0.8.6 -> v0.8.7 Updating libm v0.2.13 -> v0.2.15 Adding litemap v0.8.0 Updating nix v0.29.0 -> v0.30.1 Adding potential_utf v0.1.2 Updating rustc-build-sysroot v0.5.4 -> v0.5.5 Adding tinystr v0.8.1 Updating tokio v1.44.2 -> v1.45.0 Updating unic-langid v0.9.5 -> v0.9.6 Updating unic-langid-impl v0.9.5 -> v0.9.6 Updating unic-langid-macros v0.9.5 -> v0.9.6 Updating unic-langid-macros-impl v0.9.5 -> v0.9.6 Removing utf16_iter v1.0.5 Adding wasm-encoder v0.230.0 Adding wasmparser v0.230.0 Updating wast v229.0.0 -> v230.0.0 Updating wat v1.229.0 -> v1.230.0 Updating winnow v0.7.9 -> v0.7.10 Removing write16 v1.0.0 Adding writeable v0.6.1 Adding yoke v0.8.0 Adding yoke-derive v0.8.0 Adding zerotrie v0.2.2 Adding zerovec v0.11.2 Adding zerovec-derive v0.11.1 note: pass `--verbose` to see 36 unchanged dependencies behind latest library dependencies: Locking 0 packages to latest compatible versions note: pass `--verbose` to see 3 unchanged dependencies behind latest rustbook dependencies: Locking 26 packages to latest compatible versions Updating cc v1.2.21 -> v1.2.22 Updating clap v4.5.37 -> v4.5.38 Updating clap_builder v4.5.37 -> v4.5.38 Updating clap_complete v4.5.48 -> v4.5.50 Updating getrandom v0.3.2 -> v0.3.3 Updating icu_collections v1.5.0 -> v2.0.0 Adding icu_locale_core v2.0.0 Removing icu_locid v1.5.0 Removing icu_locid_transform v1.5.0 Removing icu_locid_transform_data v1.5.1 Updating icu_normalizer v1.5.0 -> v2.0.0 Updating icu_normalizer_data v1.5.1 -> v2.0.0 Updating icu_properties v1.5.1 -> v2.0.0 Updating icu_properties_data v1.5.1 -> v2.0.0 Updating icu_provider v1.5.0 -> v2.0.0 Removing icu_provider_macros v1.5.0 Updating idna_adapter v1.2.0 -> v1.2.1 Updating jiff v0.2.12 -> v0.2.13 Updating jiff-static v0.2.12 -> v0.2.13 Updating litemap v0.7.5 -> v0.8.0 Adding potential_utf v0.1.2 Updating tinystr v0.7.6 -> v0.8.1 Removing utf16_iter v1.0.5 Updating web_atoms v0.1.1 -> v0.1.2 Updating winnow v0.7.9 -> v0.7.10 Removing write16 v1.0.0 Updating writeable v0.5.5 -> v0.6.1 Updating yoke v0.7.5 -> v0.8.0 Updating yoke-derive v0.7.5 -> v0.8.0 Adding zerotrie v0.2.2 Updating zerovec v0.10.4 -> v0.11.2 Updating zerovec-derive v0.10.3 -> v0.11.1 --- Cargo.lock | 342 +++++++++++++++++++++++----------- src/tools/rustbook/Cargo.lock | 174 ++++++++--------- 2 files changed, 309 insertions(+), 207 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fd6fa99881b9a..cbea8c6f08ac2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -222,7 +222,7 @@ dependencies = [ "memchr", "serde", "serde_derive", - "winnow 0.7.9", + "winnow 0.7.10", ] [[package]] @@ -493,9 +493,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.37" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" +checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000" dependencies = [ "clap_builder", "clap_derive", @@ -513,9 +513,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.37" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" +checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120" dependencies = [ "anstream", "anstyle", @@ -849,9 +849,9 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.6" +version = "3.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "697b5419f348fd5ae2478e8018cb016c00a5881c7f46c717de98ffd135a5651c" +checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73" dependencies = [ "nix", "windows-sys 0.59.0", @@ -983,9 +983,9 @@ dependencies = [ [[package]] name = "derive_setters" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e8ef033054e131169b8f0f9a7af8f5533a9436fadf3c500ed547f730f07090d" +checksum = "d9c848e86c87e5cc305313041c5677d4d95d60baa71cf95e5f6ea2554bb629ff" dependencies = [ "darling", "proc-macro2", @@ -1443,9 +1443,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", @@ -1607,14 +1607,15 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", - "yoke", + "potential_utf", + "yoke 0.8.0", "zerofrom", - "zerovec", + "zerovec 0.11.2", ] [[package]] @@ -1626,9 +1627,9 @@ dependencies = [ "displaydoc", "icu_list_data", "icu_locid_transform", - "icu_provider", + "icu_provider 1.5.0", "regex-automata 0.2.0", - "writeable", + "writeable 0.5.5", ] [[package]] @@ -1637,6 +1638,19 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52b1a7fbdbf3958f1be8354cb59ac73f165b7b7082d447ff2090355c9a069120" +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap 0.8.0", + "tinystr 0.8.1", + "writeable 0.6.1", + "zerovec 0.11.2", +] + [[package]] name = "icu_locid" version = "1.5.0" @@ -1644,10 +1658,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" dependencies = [ "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", + "litemap 0.7.5", + "tinystr 0.7.6", + "writeable 0.5.5", + "zerovec 0.10.4", ] [[package]] @@ -1659,9 +1673,9 @@ dependencies = [ "displaydoc", "icu_locid", "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", + "icu_provider 1.5.0", + "tinystr 0.7.6", + "zerovec 0.10.4", ] [[package]] @@ -1672,48 +1686,46 @@ checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", - "icu_provider", + "icu_provider 2.0.0", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", - "zerovec", + "zerovec 0.11.2", ] [[package]] name = "icu_normalizer_data" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a" dependencies = [ "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", - "icu_provider", - "tinystr", - "zerovec", + "icu_provider 2.0.0", + "potential_utf", + "zerotrie", + "zerovec 0.11.2", ] [[package]] name = "icu_properties_data" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" +checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04" [[package]] name = "icu_provider" @@ -1725,11 +1737,28 @@ dependencies = [ "icu_locid", "icu_provider_macros", "stable_deref_trait", - "tinystr", - "writeable", - "yoke", + "tinystr 0.7.6", + "writeable 0.5.5", + "yoke 0.7.5", "zerofrom", - "zerovec", + "zerovec 0.10.4", +] + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr 0.8.1", + "writeable 0.6.1", + "yoke 0.8.0", + "zerofrom", + "zerotrie", + "zerovec 0.11.2", ] [[package]] @@ -1740,9 +1769,9 @@ checksum = "d6324dfd08348a8e0374a447ebd334044d766b1839bb8d5ccf2482a99a77c0bc" dependencies = [ "icu_locid", "icu_locid_transform", - "icu_provider", - "tinystr", - "zerovec", + "icu_provider 1.5.0", + "tinystr 0.7.6", + "zerovec 0.10.4", ] [[package]] @@ -1781,9 +1810,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -1911,9 +1940,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07d8d955d798e7a4d6f9c58cd1f1916e790b42b092758a9ef6e16fef9f1b3fd" +checksum = "f02000660d30638906021176af16b17498bd0d12813dbfe7b276d8bc7f3c0806" dependencies = [ "jiff-static", "log", @@ -1924,9 +1953,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f244cfe006d98d26f859c7abd1318d85327e1882dc9cef80f62daeeb0adcf300" +checksum = "f3c30758ddd7188629c6713fc45d1188af4f44c90582311d0c8d8c9907f60c48" dependencies = [ "proc-macro2", "quote", @@ -1939,7 +1968,7 @@ version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", "libc", ] @@ -2039,9 +2068,9 @@ dependencies = [ [[package]] name = "libffi" -version = "4.0.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9434b6fc77375fb624698d5f8c49d7e80b10d59eb1219afda27d1f824d4074" +checksum = "ebfd30a67b482a08116e753d0656cb626548cf4242543e5cc005be7639d99838" dependencies = [ "libc", "libffi-sys", @@ -2049,28 +2078,28 @@ dependencies = [ [[package]] name = "libffi-sys" -version = "3.2.0" +version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ead36a2496acfc8edd6cc32352110e9478ac5b9b5f5b9856ebd3d28019addb84" +checksum = "f003aa318c9f0ee69eb0ada7c78f5c9d2fedd2ceb274173b5c7ff475eee584a3" dependencies = [ "cc", ] [[package]] name = "libloading" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.53.0", ] [[package]] name = "libm" -version = "0.2.13" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9627da5196e5d8ed0b0495e61e518847578da83483c37288316d9b2e03a7f72" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libredox" @@ -2124,6 +2153,12 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + [[package]] name = "lld-wrapper" version = "0.1.0" @@ -2294,7 +2329,7 @@ dependencies = [ "chrono-tz", "colored", "directories", - "getrandom 0.3.2", + "getrandom 0.3.3", "libc", "libffi", "libloading", @@ -2321,9 +2356,9 @@ checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "nix" -version = "0.29.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ "bitflags", "cfg-if", @@ -2784,6 +2819,15 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec 0.11.2", +] + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -2934,7 +2978,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", ] [[package]] @@ -3089,9 +3133,9 @@ dependencies = [ [[package]] name = "rustc-build-sysroot" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6d984a9db43148467059309bd1e5ad577085162f695d9fe2cf3543aeb25cd38" +checksum = "fb332121f7845c6bd016f9655cf22f03c2999df936694b624a88669a78667d98" dependencies = [ "anyhow", "rustc_version", @@ -3324,8 +3368,8 @@ dependencies = [ "icu_list", "icu_locid", "icu_locid_transform", - "icu_provider", - "zerovec", + "icu_provider 1.5.0", + "zerovec 0.10.4", ] [[package]] @@ -5104,7 +5148,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" dependencies = [ "fastrand", - "getrandom 0.3.2", + "getrandom 0.3.3", "once_cell", "rustix", "windows-sys 0.59.0", @@ -5279,7 +5323,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ "displaydoc", - "zerovec", + "zerovec 0.10.4", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec 0.11.2", ] [[package]] @@ -5299,9 +5353,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.44.2" +version = "1.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" +checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" dependencies = [ "backtrace", "bytes", @@ -5505,9 +5559,9 @@ dependencies = [ [[package]] name = "unic-langid" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dd9d1e72a73b25e07123a80776aae3e7b0ec461ef94f9151eed6ec88005a44" +checksum = "a28ba52c9b05311f4f6e62d5d9d46f094bd6e84cb8df7b3ef952748d752a7d05" dependencies = [ "unic-langid-impl", "unic-langid-macros", @@ -5515,30 +5569,30 @@ dependencies = [ [[package]] name = "unic-langid-impl" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a5422c1f65949306c99240b81de9f3f15929f5a8bfe05bb44b034cc8bf593e5" +checksum = "dce1bf08044d4b7a94028c93786f8566047edc11110595914de93362559bc658" dependencies = [ - "tinystr", + "tinystr 0.8.1", ] [[package]] name = "unic-langid-macros" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da1cd2c042d3c7569a1008806b02039e7a4a2bdf8f8e96bd3c792434a0e275e" +checksum = "d5957eb82e346d7add14182a3315a7e298f04e1ba4baac36f7f0dbfedba5fc25" dependencies = [ "proc-macro-hack", - "tinystr", + "tinystr 0.8.1", "unic-langid-impl", "unic-langid-macros-impl", ] [[package]] name = "unic-langid-macros-impl" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b" +checksum = "a1249a628de3ad34b821ecb1001355bca3940bcb2f88558f1a8bd82e977f75b5" dependencies = [ "proc-macro-hack", "quote", @@ -5654,12 +5708,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8-width" version = "0.1.7" @@ -5684,7 +5732,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", ] [[package]] @@ -5841,6 +5889,16 @@ dependencies = [ "wasmparser 0.229.0", ] +[[package]] +name = "wasm-encoder" +version = "0.230.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4349d0943718e6e434b51b9639e876293093dca4b96384fb136ab5bd5ce6660" +dependencies = [ + "leb128fmt", + "wasmparser 0.230.0", +] + [[package]] name = "wasm-metadata" version = "0.229.0" @@ -5885,24 +5943,35 @@ dependencies = [ "serde", ] +[[package]] +name = "wasmparser" +version = "0.230.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808198a69b5a0535583370a51d459baa14261dfab04800c4864ee9e1a14346ed" +dependencies = [ + "bitflags", + "indexmap", + "semver", +] + [[package]] name = "wast" -version = "229.0.0" +version = "230.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63fcaff613c12225696bb163f79ca38ffb40e9300eff0ff4b8aa8b2f7eadf0d9" +checksum = "b8edac03c5fa691551531533928443faf3dc61a44f814a235c7ec5d17b7b34f1" dependencies = [ "bumpalo", "leb128fmt", "memchr", "unicode-width 0.2.0", - "wasm-encoder 0.229.0", + "wasm-encoder 0.230.0", ] [[package]] name = "wat" -version = "1.229.0" +version = "1.230.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4189bad08b70455a9e9e67dc126d2dcf91fac143a80f1046747a5dde6d4c33e0" +checksum = "0d77d62229e38db83eac32bacb5f61ebb952366ab0dae90cf2b3c07a65eea894" dependencies = [ "wast", ] @@ -6326,9 +6395,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" dependencies = [ "memchr", ] @@ -6386,16 +6455,16 @@ dependencies = [ ] [[package]] -name = "write16" -version = "1.0.0" +name = "writeable" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "x" @@ -6437,7 +6506,19 @@ checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ "serde", "stable_deref_trait", - "yoke-derive", + "yoke-derive 0.7.5", + "zerofrom", +] + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive 0.8.0", "zerofrom", ] @@ -6453,6 +6534,18 @@ dependencies = [ "synstructure", ] +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.8.25" @@ -6494,15 +6587,37 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke 0.8.0", + "zerofrom", +] + [[package]] name = "zerovec" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" dependencies = [ - "yoke", + "yoke 0.7.5", "zerofrom", - "zerovec-derive", + "zerovec-derive 0.10.3", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +dependencies = [ + "yoke 0.8.0", + "zerofrom", + "zerovec-derive 0.11.1", ] [[package]] @@ -6515,3 +6630,14 @@ dependencies = [ "quote", "syn 2.0.101", ] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index 3b5b31bed14a5..0b38937701117 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -156,9 +156,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "cc" -version = "1.2.21" +version = "1.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0" +checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1" dependencies = [ "shlex", ] @@ -185,9 +185,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.37" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" +checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000" dependencies = [ "clap_builder", "clap_derive", @@ -195,9 +195,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.37" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" +checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120" dependencies = [ "anstream", "anstyle", @@ -208,9 +208,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.48" +version = "4.5.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be8c97f3a6f02b9e24cadc12aaba75201d18754b53ea0a9d99642f806ccdb4c9" +checksum = "c91d3baa3bcd889d60e6ef28874126a0b384fd225ab83aa6d8a801c519194ce1" dependencies = [ "clap", ] @@ -547,9 +547,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", @@ -644,21 +644,22 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", + "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale_core" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ "displaydoc", "litemap", @@ -667,31 +668,11 @@ dependencies = [ "zerovec", ] -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ "displaydoc", "icu_collections", @@ -699,67 +680,54 @@ dependencies = [ "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a" dependencies = [ "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", + "potential_utf", + "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" +checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", + "icu_locale_core", "stable_deref_trait", "tinystr", "writeable", "yoke", "zerofrom", + "zerotrie", "zerovec", ] -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "ident_case" version = "1.0.1" @@ -779,9 +747,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -811,9 +779,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07d8d955d798e7a4d6f9c58cd1f1916e790b42b092758a9ef6e16fef9f1b3fd" +checksum = "f02000660d30638906021176af16b17498bd0d12813dbfe7b276d8bc7f3c0806" dependencies = [ "jiff-static", "log", @@ -824,9 +792,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f244cfe006d98d26f859c7abd1318d85327e1882dc9cef80f62daeeb0adcf300" +checksum = "f3c30758ddd7188629c6713fc45d1188af4f44c90582311d0c8d8c9907f60c48" dependencies = [ "proc-macro2", "quote", @@ -882,9 +850,9 @@ checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litemap" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" @@ -1274,6 +1242,15 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + [[package]] name = "precomputed-hash" version = "0.1.1" @@ -1710,9 +1687,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.7.6" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", "zerovec", @@ -1821,12 +1798,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -1924,9 +1895,9 @@ dependencies = [ [[package]] name = "web_atoms" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bcbdcad8fb2e316072ba6bbe09419afdb550285668ac2534f4230a6f2da0ee" +checksum = "0b9c5f0bc545ea3b20b423e33b9b457764de0b3730cd957f6c6aa6c301785f6e" dependencies = [ "phf", "phf_codegen", @@ -2099,9 +2070,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" dependencies = [ "memchr", ] @@ -2115,23 +2086,17 @@ dependencies = [ "bitflags 2.9.0", ] -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "yoke" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ "serde", "stable_deref_trait", @@ -2141,9 +2106,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", @@ -2172,11 +2137,22 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + [[package]] name = "zerovec" -version = "0.10.4" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" dependencies = [ "yoke", "zerofrom", @@ -2185,9 +2161,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", From 30eca8ba9160bf18c4f0a3c9bb760d270f012240 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Mon, 12 May 2025 04:53:41 +0000 Subject: [PATCH 2183/4206] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 9afbd3aa63579..801f78ba85cb2 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -fd9fad6dbcc1bae3cba2a8634339ffa620a49f28 +718ddf660e6a1802c39b4962cf7eaa4db57025ef From 63de63e8a4ac6cd5fa3c89a58d84c3b8537ebe6e Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 12 May 2025 06:33:11 +0000 Subject: [PATCH 2184/4206] update llvm-tools copying logic for dist step Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/compile.rs | 23 +++++++++++-------- src/bootstrap/src/core/build_steps/dist.rs | 10 ++++++-- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 2e5865e509695..c29e0694f49c8 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1984,17 +1984,20 @@ impl Step for Assemble { trace!("installing `{tool}`"); let tool_exe = exe(tool, target_compiler.host); let src_path = llvm_bin_dir.join(&tool_exe); - // When using `download-ci-llvm`, some of the tools - // may not exist, so skip trying to copy them. - if src_path.exists() { - // There is a chance that these tools are being installed from an external LLVM. - // Use `Builder::resolve_symlink_and_copy` instead of `Builder::copy_link` to ensure - // we are copying the original file not the symlinked path, which causes issues for - // tarball distribution. - // - // See https://github.com/rust-lang/rust/issues/135554. - builder.resolve_symlink_and_copy(&src_path, &libdir_bin.join(&tool_exe)); + + // When using `download-ci-llvm`, some of the tools may not exist, so skip trying to copy them. + if !src_path.exists() && builder.config.llvm_from_ci { + eprintln!("{} does not exist; skipping copy", src_path.display()); + continue; } + + // There is a chance that these tools are being installed from an external LLVM. + // Use `Builder::resolve_symlink_and_copy` instead of `Builder::copy_link` to ensure + // we are copying the original file not the symlinked path, which causes issues for + // tarball distribution. + // + // See https://github.com/rust-lang/rust/issues/135554. + builder.resolve_symlink_and_copy(&src_path, &libdir_bin.join(&tool_exe)); } } } diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 3c412683b9492..9750e4c77d167 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -2274,9 +2274,9 @@ impl Step for LlvmTools { let target = self.target; - /* run only if llvm-config isn't used */ + // Run only if a custom llvm-config is not used if let Some(config) = builder.config.target_config.get(&target) { - if let Some(ref _s) = config.llvm_config { + if !builder.config.llvm_from_ci && config.llvm_config.is_some() { builder.info(&format!("Skipping LlvmTools ({target}): external LLVM")); return None; } @@ -2294,6 +2294,12 @@ impl Step for LlvmTools { let dst_bindir = format!("lib/rustlib/{}/bin", target.triple); for tool in tools_to_install(&builder.paths) { let exe = src_bindir.join(exe(tool, target)); + // When using `download-ci-llvm`, some of the tools may not exist, so skip trying to copy them. + if !exe.exists() && builder.config.llvm_from_ci { + eprintln!("{} does not exist; skipping copy", exe.display()); + continue; + } + tarball.add_file(&exe, &dst_bindir, FileType::Executable); } } From 475e743e89840b8df61adec7b0bf07c5f74e568c Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 12 May 2025 06:33:41 +0000 Subject: [PATCH 2185/4206] update default condition of llvm-tools for install step Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/install.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index 3e5069225d2bb..174b7ec3be895 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -244,7 +244,7 @@ install!((self, builder, _config), ); } }; - LlvmTools, alias = "llvm-tools", Self::should_build(_config), only_hosts: true, { + LlvmTools, alias = "llvm-tools", _config.llvm_tools_enabled && _config.llvm_enabled(_config.build), only_hosts: true, { if let Some(tarball) = builder.ensure(dist::LlvmTools { target: self.target }) { install_sh(builder, "llvm-tools", self.compiler.stage, Some(self.target), &tarball); } else { From 8f5dc85f37fb1dc1830e11f387c6eed6b4713c23 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Mon, 12 May 2025 08:48:36 +0200 Subject: [PATCH 2186/4206] Use `tempfile::TempDir::keep()` instead of deprecated `into_path()` `tempfile` has deprecated `TempDir::into_path()` (replacing it by `TempDir::keep()`) between version `3.3` which Clippy required and version `3.20.0` which is the latest semver-compatible version. Since Clippy doesn't use a `Cargo.lock` file, the latest version of `tempfile` is used which leads to CI failure. --- Cargo.toml | 2 +- tests/integration.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 603169f72b61e..92c4db845000a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ clippy_lints = { path = "clippy_lints" } clippy_utils = { path = "clippy_utils" } rustc_tools_util = { path = "rustc_tools_util", version = "0.4.2" } clippy_lints_internal = { path = "clippy_lints_internal", optional = true } -tempfile = { version = "3.3", optional = true } +tempfile = { version = "3.20", optional = true } termize = "0.1" color-print = "0.3.4" anstream = "0.6.18" diff --git a/tests/integration.rs b/tests/integration.rs index 13cf36823c5e4..cb7d61eee24ad 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -30,7 +30,7 @@ fn integration_test() { let repo_dir = tempfile::tempdir() .expect("couldn't create temp dir") - .into_path() + .keep() .join(crate_name); let st = Command::new("git") From 41a2260bc7d7388a6ef2b0dfa7a980c977e26081 Mon Sep 17 00:00:00 2001 From: tiif Date: Mon, 12 May 2025 09:23:30 +0200 Subject: [PATCH 2187/4206] Use unreachable instead of panic Co-authored-by: bjorn3 <17426603+bjorn3@users.noreply.github.com> --- compiler/rustc_target/src/callconv/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 6aae8bc755602..a141accb73802 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -919,7 +919,7 @@ fn conv_to_externabi(conv: &Conv) -> ExternAbi { Conv::AvrNonBlockingInterrupt => ExternAbi::AvrNonBlockingInterrupt, Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine } => ExternAbi::RiscvInterruptM, Conv::RiscvInterrupt { kind: RiscvInterruptKind::Supervisor } => ExternAbi::RiscvInterruptS, - Conv::Cold | Conv::PreserveAll => panic!("This is deadcode"), + Conv::Cold | Conv::PreserveAll => unreachable!(), } } From 551a49df59a0985e0cfe3d29a33c6b60bb9afd64 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Mon, 12 May 2025 07:53:28 +0000 Subject: [PATCH 2188/4206] Silence warning in default compiler bootstrap settings --- src/bootstrap/defaults/bootstrap.compiler.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/bootstrap/defaults/bootstrap.compiler.toml b/src/bootstrap/defaults/bootstrap.compiler.toml index 269b90106e3aa..9dcb20ed48323 100644 --- a/src/bootstrap/defaults/bootstrap.compiler.toml +++ b/src/bootstrap/defaults/bootstrap.compiler.toml @@ -30,8 +30,6 @@ download-rustc = false # Having this set to true disrupts compiler development workflows for people who use `llvm.download-ci-llvm = true` # because we don't provide ci-llvm on the `rustc-alt-builds` server. Therefore, it is kept off by default. assertions = false -# Enable warnings during the LLVM compilation (when LLVM is changed, causing a compilation) -enable-warnings = true # Will download LLVM from CI if available on your platform. # If you intend to modify `src/llvm-project`, use `"if-unchanged"` or `false` instead. download-ci-llvm = true From 2a0c72e3a9dc1c4a8009e748900bdc6816bc640a Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 12 May 2025 18:08:15 +1000 Subject: [PATCH 2189/4206] Remove obsolete reference to `unsized_tuple_coercion` --- src/doc/rustc-dev-guide/src/traits/unsize.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/traits/unsize.md b/src/doc/rustc-dev-guide/src/traits/unsize.md index dd57a1b079673..98a4452574817 100644 --- a/src/doc/rustc-dev-guide/src/traits/unsize.md +++ b/src/doc/rustc-dev-guide/src/traits/unsize.md @@ -32,21 +32,21 @@ Built-in implementations are provided for: ## Structural implementations -There are two implementations of `Unsize` which can be thought of as +There is one implementation of `Unsize` which can be thought of as structural: -* `(A1, A2, .., An): Unsize<(A1, A2, .., U)>` given `An: Unsize`, which - allows the tail field of a tuple to be unsized. This is gated behind the - [`unsized_tuple_coercion`] feature. * `Struct<.., Pi, .., Pj, ..>: Unsize>` given `TailField: Unsize`, which allows the tail field of a struct to be unsized if it is the only field that mentions generic parameters `Pi`, .., `Pj` (which don't need to be contiguous). -The rules for the latter implementation are slightly complicated, since they +The rules for struct unsizing are slightly complicated, since they may allow more than one parameter to be changed (not necessarily unsized) and are best stated in terms of the tail field of the struct. -[`unsized_tuple_coercion`]: https://doc.rust-lang.org/beta/unstable-book/language-features/unsized-tuple-coercion.html +(Tuple unsizing was previously implemented behind the feature gate +`unsized_tuple_coercion`, but the implementation was removed by [#137728].) + +[#137728]: https://github.com/rust-lang/rust/pull/137728 ## Upcasting implementations From 55b5c835c57ce88d8499b281ead008ff54908b00 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 7 May 2025 17:10:02 +0500 Subject: [PATCH 2190/4206] Changelog for Clippy 1.87 --- CHANGELOG.md | 100 +++++++++++++++++++++++++- clippy_lints/src/lifetimes.rs | 2 +- clippy_lints/src/mem_replace.rs | 2 +- clippy_lints/src/methods/mod.rs | 4 +- clippy_lints/src/single_option_map.rs | 2 +- clippy_lints/src/types/mod.rs | 2 +- 6 files changed, 105 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b62c9a59aa5d..a3c6cba487631 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,105 @@ document. ## Unreleased / Beta / In Rust Nightly -[3e3715c3...master](https://github.com/rust-lang/rust-clippy/compare/3e3715c3...master) +[1e5237f4...master](https://github.com/rust-lang/rust-clippy/compare/1e5237f4...master) + +## Rust 1.87 + +Current stable, released 2025-05-15 + +[View all 127 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2025-02-06T14%3A54%3A28Z..2025-03-20T20%3A07%3A53Z+base%3Amaster) + +### New Lints + +* Added [`doc_comment_double_space_linebreaks`] to `pedantic` [#12876](https://github.com/rust-lang/rust-clippy/pull/12876) +* Added [`manual_midpoint`] to `pedantic` [#13851](https://github.com/rust-lang/rust-clippy/pull/13851) +* Added [`io_other_error`] to `style` [#14022](https://github.com/rust-lang/rust-clippy/pull/14022) +* Added [`owned_cow`] to `pedantic` [#13948](https://github.com/rust-lang/rust-clippy/pull/13948) +* Added [`manual_contains`] to `perf` [#13817](https://github.com/rust-lang/rust-clippy/pull/13817) +* Added [`unnecessary_debug_formatting`] to `pedantic` [#13893](https://github.com/rust-lang/rust-clippy/pull/13893) +* Added [`elidable_lifetime_names`] to `pedantic` [#13960](https://github.com/rust-lang/rust-clippy/pull/13960) +* Added [`mem_replace_option_with_some`] to `style` [#14197](https://github.com/rust-lang/rust-clippy/pull/14197) +* Added [`unbuffered_bytes`] to `perf` [#14089](https://github.com/rust-lang/rust-clippy/pull/14089) +* Added [`single_option_map`] to `nursery` [#14033](https://github.com/rust-lang/rust-clippy/pull/14033) + +### Moves and Deprecations + +* Moved [`comparison_chain`] to `pedantic` (from `style`) + [#14219](https://github.com/rust-lang/rust-clippy/pull/14219) +* Moved [`manual_ok_or`] to `style` (from `pedantic`) + [#14027](https://github.com/rust-lang/rust-clippy/pull/14027) +* Deprecated [`option_map_or_err_ok`] in favor of [`manual_ok_or`] + [#14027](https://github.com/rust-lang/rust-clippy/pull/14027) + +### Enhancements + +* Add `allow_expect_in_consts` and `allow_unwrap_in_consts` configuration options to [`unwrap_used`], [`expect_used`] + [#14200](https://github.com/rust-lang/rust-clippy/pull/14200) +* Add `check-incompatible-msrv-in-tests` configuration option to [`incompatible_msrv`] + [#14279](https://github.com/rust-lang/rust-clippy/pull/14279) +* [`len_zero`] now also triggers if deref target implements `is_empty()` + [#13871](https://github.com/rust-lang/rust-clippy/pull/13871) +* [`ptr_eq`] now handles more cases, including `!=` in addition to `==` + [#14339](https://github.com/rust-lang/rust-clippy/pull/14339) +* [`struct_field_names`] now also checks private fields of public structs + [#14076](https://github.com/rust-lang/rust-clippy/pull/14076) +* [`needless_pass_by_value`] suggests using a reference on the innermost `Option` content + [#14392](https://github.com/rust-lang/rust-clippy/pull/14392) +* [`obfuscated_if_else`] now supports `then().unwrap_or_else()` and `then_some().unwrap_or_else()` + [#14165](https://github.com/rust-lang/rust-clippy/pull/14165) +* Format macros: all format-handling lints now validate `todo!` and `unimplemented!` macros + [#14266](https://github.com/rust-lang/rust-clippy/pull/14266) +* [`disallowed_methods`] now supports replacements + [#13669](https://github.com/rust-lang/rust-clippy/pull/13669) +* Added MSRV checks for several lints: + * [`question_mark`] [#14436](https://github.com/rust-lang/rust-clippy/pull/14436) + * [`repeat_vec_with_capacity`] [#14126](https://github.com/rust-lang/rust-clippy/pull/14126) + * [`manual_flatten`] [#14086](https://github.com/rust-lang/rust-clippy/pull/14086) + * [`lines_filter_map_ok`] [#14130](https://github.com/rust-lang/rust-clippy/pull/14130) + +### False Positive Fixes + +* [`missing_const_for_fn`] no longer triggers on unstable const traits [#14294](https://github.com/rust-lang/rust-clippy/pull/14294) +* [`unnecessary_to_owned`] now avoids suggesting to call `iter()` on a temporary object [#14243](https://github.com/rust-lang/rust-clippy/pull/14243) +* [`unnecessary_debug_formatting`] no longer triggers in tests [#14347](https://github.com/rust-lang/rust-clippy/pull/14347) +* [`option_if_let_else`] now handles cases when value is partially moved [#14209](https://github.com/rust-lang/rust-clippy/pull/14209) +* [`blocks_in_conditions`] no longer triggers when the condition contains a `return` [#14338](https://github.com/rust-lang/rust-clippy/pull/14338) +* [`undocumented_unsafe_blocks`] no longer triggers on trait/impl items [#13888](https://github.com/rust-lang/rust-clippy/pull/13888) +* [`manual_slice_fill`] no longer triggers due to missing index checks [#14193](https://github.com/rust-lang/rust-clippy/pull/14193) +* [`useless_asref`] no longer suggests using `.clone()` if the target type doesn't implement `Clone` [#14174](https://github.com/rust-lang/rust-clippy/pull/14174) +* [`unnecessary_safety_comment`] no longer triggers on desugared assign [#14371](https://github.com/rust-lang/rust-clippy/pull/14371) +* [`unnecessary_map_or`] no longer consumes the comparison value if it does not implement `Copy` [#14207](https://github.com/rust-lang/rust-clippy/pull/14207) +* [`let_and_return`] no longer triggers involving short-lived block temporary variables [#14180](https://github.com/rust-lang/rust-clippy/pull/14180) +* [`manual_async_fn`] no longer emits suggestions inside macros [#14142](https://github.com/rust-lang/rust-clippy/pull/14142) +* [`use_self`] skips analysis inside macro expansions of a `impl Self` block [#13128](https://github.com/rust-lang/rust-clippy/pull/13128) +* [`double_ended_iterator_last`] no longer triggers on non-reference immutable receiver [#14140](https://github.com/rust-lang/rust-clippy/pull/14140) + +### ICE Fixes + +* [`macro_use_imports`] Fix ICE when checking attributes + [#14317](https://github.com/rust-lang/rust-clippy/pull/14317) +* [`doc_nested_refdefs`] Fix ICE by avoiding invalid ranges + [#14308](https://github.com/rust-lang/rust-clippy/pull/14308) +* [`just_underscores_and_digits`] Fix ICE in error recovery scenario + [#14168](https://github.com/rust-lang/rust-clippy/pull/14168) +* [`declare_interior_mutable_const`], [`borrow_interior_mutable_const`] Fix ICE by properly resolving `::AssocT` projections + [#14125](https://github.com/rust-lang/rust-clippy/pull/14125) + +### Documentation Improvements + +* [`struct_excessive_bools`] Documentation improved with rationale + [#14351](https://github.com/rust-lang/rust-clippy/pull/14351) + +### Others + +* Use edition=2021 in `rustc_tools_util` + [#14211](https://github.com/rust-lang/rust-clippy/pull/14211) +* Fix rustc_tools_util's `version.host_compiler` release channel, expose the rustc version, and add tests + [#14123](https://github.com/rust-lang/rust-clippy/pull/14123) +* Make UI test annotations mandatory + [#11421](https://github.com/rust-lang/rust-clippy/pull/11421) + [#14388](https://github.com/rust-lang/rust-clippy/pull/14388) + [#14393](https://github.com/rust-lang/rust-clippy/pull/14393) ## Rust 1.86 diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 5ef5e3a44f85f..9a64226b1ed96 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -88,7 +88,7 @@ declare_clippy_lint! { /// x.chars() /// } /// ``` - #[clippy::version = "1.84.0"] + #[clippy::version = "1.87.0"] pub ELIDABLE_LIFETIME_NAMES, pedantic, "lifetime name that can be replaced with the anonymous lifetime" diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index a54d835b538c1..28efd2038b387 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -62,7 +62,7 @@ declare_clippy_lint! { /// let mut an_option = Some(0); /// let taken = an_option.replace(1); /// ``` - #[clippy::version = "1.86.0"] + #[clippy::version = "1.87.0"] pub MEM_REPLACE_OPTION_WITH_SOME, style, "replacing an `Option` with `Some` instead of `replace()`" diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 10f4637d08f66..45c61c5cb3281 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4428,7 +4428,7 @@ declare_clippy_lint! { /// let file = BufReader::new(std::fs::File::open("./bytes.txt").unwrap()); /// file.bytes(); /// ``` - #[clippy::version = "1.86.0"] + #[clippy::version = "1.87.0"] pub UNBUFFERED_BYTES, perf, "calling .bytes() is very inefficient when data is not in memory" @@ -4453,7 +4453,7 @@ declare_clippy_lint! { /// values.contains(&10) /// } /// ``` - #[clippy::version = "1.86.0"] + #[clippy::version = "1.87.0"] pub MANUAL_CONTAINS, perf, "unnecessary `iter().any()` on slices that can be replaced with `contains()`" diff --git a/clippy_lints/src/single_option_map.rs b/clippy_lints/src/single_option_map.rs index 1fb54950612a5..cc497c97a4725 100644 --- a/clippy_lints/src/single_option_map.rs +++ b/clippy_lints/src/single_option_map.rs @@ -30,7 +30,7 @@ declare_clippy_lint! { /// param * 2 /// } /// ``` - #[clippy::version = "1.86.0"] + #[clippy::version = "1.87.0"] pub SINGLE_OPTION_MAP, nursery, "Checks for functions with method calls to `.map(_)` on an arg of type `Option` as the outermost expression." diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 3147058b4cda0..c1c7cc5165652 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -385,7 +385,7 @@ declare_clippy_lint! { /// ```no_run /// let right: std::borrow::Cow<'_, [u8]>; /// ``` - #[clippy::version = "1.85.0"] + #[clippy::version = "1.87.0"] pub OWNED_COW, style, "needlessly owned Cow type" From 436c3631006585d125af10b31ad3ee69eab4fc5e Mon Sep 17 00:00:00 2001 From: Stan Manilov Date: Fri, 9 May 2025 16:42:35 +0300 Subject: [PATCH 2191/4206] Remove n.b. about parser refactoring Discussed in PR 2378; the note was outdated. --- src/doc/rustc-dev-guide/src/macro-expansion.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/macro-expansion.md b/src/doc/rustc-dev-guide/src/macro-expansion.md index ebab56ad20af0..76b4f2c617df5 100644 --- a/src/doc/rustc-dev-guide/src/macro-expansion.md +++ b/src/doc/rustc-dev-guide/src/macro-expansion.md @@ -2,9 +2,6 @@ -> N.B. [`rustc_ast`], [`rustc_expand`], and [`rustc_builtin_macros`] are all -> undergoing refactoring, so some of the links in this chapter may be broken. - Rust has a very powerful macro system. In the previous chapter, we saw how the parser sets aside macros to be expanded (using temporary [placeholders]). This chapter is about the process of expanding those macros iteratively until From 42d3ba786ee7ac8c8a410a72546ebbda9fdf5aee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sun, 11 May 2025 01:10:59 +0200 Subject: [PATCH 2192/4206] Use new form for T-rustdoc's {beta,stable}-{nominated,accepted} notify-Zulip triggers --- triagebot.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index 6f3ca493335ef..9dcdbcecbeca6 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -611,7 +611,7 @@ message_on_remove = "Issue #{number}'s prioritization request has been removed." message_on_close = "Issue #{number} has been closed while requested for prioritization." message_on_reopen = "Issue #{number} has been reopened." -[notify-zulip."beta-nominated"] +[notify-zulip."beta-nominated".rustdoc] required_labels = ["T-rustdoc"] zulip_stream = 266220 # #t-rustdoc topic = "beta-nominated: #{number}" @@ -632,7 +632,7 @@ message_on_remove = "PR #{number}'s beta-nomination has been removed." message_on_close = "PR #{number} has been closed. Thanks for participating!" message_on_reopen = "PR #{number} has been reopened. Pinging @*T-rustdoc*." -[notify-zulip."beta-accepted"] +[notify-zulip."beta-accepted".rustdoc] required_labels = ["T-rustdoc"] zulip_stream = 266220 # #t-rustdoc # Put it in the same thread as beta-nominated. @@ -642,7 +642,7 @@ message_on_remove = "PR #{number}'s beta-acceptance has been **removed**." message_on_close = "PR #{number} has been closed. Thanks for participating!" message_on_reopen = "PR #{number} has been reopened. Pinging @*T-rustdoc*." -[notify-zulip."stable-nominated"] +[notify-zulip."stable-nominated".rustdoc] required_labels = ["T-rustdoc"] zulip_stream = 266220 # #t-rustdoc topic = "stable-nominated: #{number}" @@ -664,7 +664,7 @@ message_on_remove = "PR #{number}'s stable-nomination has been removed." message_on_close = "PR #{number} has been closed. Thanks for participating!" message_on_reopen = "PR #{number} has been reopened. Pinging @*T-rustdoc*." -[notify-zulip."stable-accepted"] +[notify-zulip."stable-accepted".rustdoc] required_labels = ["T-rustdoc"] zulip_stream = 266220 # #t-rustdoc # Put it in the same thread as stable-nominated. From 2fdf3d98205abfbf1a034ef1f04369a6342645ec Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 12 May 2025 13:49:17 +0200 Subject: [PATCH 2193/4206] ui/async-drop-initial: factor in panic strategy in destructor size check the size of `AsyncStruct`'s destructor depends on whether the configured panic strategy is 'unwind' or 'abort' so factor that into the test using conditional compilation fixes rust-lang/rust#140939 --- tests/ui/async-await/async-drop/async-drop-initial.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/ui/async-await/async-drop/async-drop-initial.rs b/tests/ui/async-await/async-drop/async-drop-initial.rs index 80b34840c8bef..263b70699f5eb 100644 --- a/tests/ui/async-await/async-drop/async-drop-initial.rs +++ b/tests/ui/async-await/async-drop/async-drop-initial.rs @@ -60,7 +60,10 @@ fn main() { let j = 42; test_async_drop(&i, 16).await; test_async_drop(&j, 16).await; - test_async_drop(AsyncStruct { b: AsyncInt(8), a: AsyncInt(7), i: 6 }, 168).await; + test_async_drop( + AsyncStruct { b: AsyncInt(8), a: AsyncInt(7), i: 6 }, + if cfg!(panic = "unwind") { 168 } else { 136 }, + ).await; test_async_drop(ManuallyDrop::new(AsyncInt(9)), 16).await; let foo = AsyncInt(10); From a8679816dc33567d811f743d52586b0aa29754a2 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 14 Dec 2024 23:40:38 +0100 Subject: [PATCH 2194/4206] Add new `useless_concat` lint --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/useless_concat.rs | 108 +++++++++++++++++++++++++++++ 4 files changed, 112 insertions(+) create mode 100644 clippy_lints/src/useless_concat.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 68c03a8133738..84378f3f1c450 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6438,6 +6438,7 @@ Released 2018-09-13 [`used_underscore_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#used_underscore_items [`useless_asref`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_asref [`useless_attribute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_attribute +[`useless_concat`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_concat [`useless_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion [`useless_format`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_format [`useless_let_if_seq`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_let_if_seq diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index e046ab0b42bb7..69ef3d69bb8c3 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -762,6 +762,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::unwrap_in_result::UNWRAP_IN_RESULT_INFO, crate::upper_case_acronyms::UPPER_CASE_ACRONYMS_INFO, crate::use_self::USE_SELF_INFO, + crate::useless_concat::USELESS_CONCAT_INFO, crate::useless_conversion::USELESS_CONVERSION_INFO, crate::vec::USELESS_VEC_INFO, crate::vec_init_then_push::VEC_INIT_THEN_PUSH_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 64fbc0252e2a2..a51e45bff7a3b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -392,6 +392,7 @@ mod unwrap; mod unwrap_in_result; mod upper_case_acronyms; mod use_self; +mod useless_concat; mod useless_conversion; mod vec; mod vec_init_then_push; @@ -936,6 +937,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(unnecessary_literal_bound::UnnecessaryLiteralBound)); store.register_early_pass(|| Box::new(empty_line_after::EmptyLineAfter::new())); store.register_late_pass(move |_| Box::new(arbitrary_source_item_ordering::ArbitrarySourceItemOrdering::new(conf))); + store.register_late_pass(|_| Box::new(useless_concat::UselessConcat)); store.register_late_pass(|_| Box::new(unneeded_struct_pattern::UnneededStructPattern)); store.register_late_pass(|_| Box::::default()); store.register_late_pass(move |_| Box::new(non_std_lazy_statics::NonStdLazyStatic::new(conf))); diff --git a/clippy_lints/src/useless_concat.rs b/clippy_lints/src/useless_concat.rs new file mode 100644 index 0000000000000..3f68b93d4f575 --- /dev/null +++ b/clippy_lints/src/useless_concat.rs @@ -0,0 +1,108 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::macros::macro_backtrace; +use clippy_utils::source::snippet_opt; +use clippy_utils::{match_def_path, tokenize_with_text}; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lexer::TokenKind; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// Checks that the `concat!` macro has at least two arguments. + /// + /// ### Why is this bad? + /// If there are less than 2 arguments, then calling the macro is doing nothing. + /// + /// ### Example + /// ```no_run + /// let x = concat!("a"); + /// ``` + /// Use instead: + /// ```no_run + /// let x = "a"; + /// ``` + #[clippy::version = "1.85.0"] + pub USELESS_CONCAT, + complexity, + "checks that the `concat` macro has at least two arguments" +} + +declare_lint_pass!(UselessConcat => [USELESS_CONCAT]); + +impl LateLintPass<'_> for UselessConcat { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + // Check that the expression is generated by a macro. + if expr.span.from_expansion() + // Check that it's a string literal. + && let ExprKind::Lit(lit) = expr.kind + && let LitKind::Str(_, _) = lit.node + // Get the direct parent of the expression. + && let Some(macro_call) = macro_backtrace(expr.span).next() + // Check if the `concat` macro from the `core` library. + && match_def_path(cx, macro_call.def_id, &["core", "macros", "builtin", "concat"]) + // We get the original code to parse it. + && let Some(original_code) = snippet_opt(cx, macro_call.span) + // This check allows us to ensure that the code snippet: + // 1. Doesn't come from proc-macro expansion. + // 2. Doesn't come from foreign macro expansion. + // + // It works as follows: if the snippet we get doesn't contain `concat!(`, then it + // means it's not code written in the current crate so we shouldn't lint. + && let mut parts = original_code.split('!') + && parts.next().is_some_and(|p| p.trim() == "concat") + && parts.next().is_some_and(|p| p.trim().starts_with('(')) + { + let mut literal = None; + let mut nb_commas = 0; + let mut nb_idents = 0; + for (token_kind, token_s, _) in tokenize_with_text(&original_code) { + match token_kind { + TokenKind::Eof => break, + TokenKind::Literal { .. } => { + if literal.is_some() { + return; + } + literal = Some(token_s); + }, + TokenKind::Ident => nb_idents += 1, + TokenKind::Comma => { + nb_commas += 1; + if nb_commas > 1 { + return; + } + }, + // We're inside a macro definition and we are manipulating something we likely + // shouldn't, so aborting. + TokenKind::Dollar => return, + _ => {}, + } + } + let literal = match literal { + Some(lit) => { + // Literals can also be number, so we need to check this case too. + if lit.starts_with('"') { + lit.to_string() + } else { + format!("\"{lit}\"") + } + }, + None => "\"\"".to_string(), + }; + // There should always be the ident of the `concat` macro. + if nb_idents == 1 { + span_lint_and_sugg( + cx, + USELESS_CONCAT, + macro_call.span, + "unneeded use of `concat!` macro", + "replace with", + literal, + Applicability::MachineApplicable, + ); + } + } + } +} From 126fb00585a426d36586c4e4f6e4b891ccfd332e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 14 Dec 2024 23:40:55 +0100 Subject: [PATCH 2195/4206] Add ui test for `useless_concat` lint --- tests/ui/useless_concat.fixed | 20 ++++++++++++++++++++ tests/ui/useless_concat.rs | 20 ++++++++++++++++++++ tests/ui/useless_concat.stderr | 29 +++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 tests/ui/useless_concat.fixed create mode 100644 tests/ui/useless_concat.rs create mode 100644 tests/ui/useless_concat.stderr diff --git a/tests/ui/useless_concat.fixed b/tests/ui/useless_concat.fixed new file mode 100644 index 0000000000000..0400b1fcd6db9 --- /dev/null +++ b/tests/ui/useless_concat.fixed @@ -0,0 +1,20 @@ +#![warn(clippy::useless_concat)] +#![allow(clippy::print_literal)] + +macro_rules! my_concat { + ($fmt:literal $(, $e:expr)*) => { + println!(concat!("ERROR: ", $fmt), $($e,)*); + } +} + +fn main() { + let x = ""; //~ useless_concat + let x = "a"; //~ useless_concat + let x = "1"; //~ useless_concat + println!("b: {}", "a"); //~ useless_concat + // Should not lint. + let x = concat!("a", "b"); + let local_i32 = 1; + my_concat!("{}", local_i32); + let x = concat!(file!(), "#L", line!()); +} diff --git a/tests/ui/useless_concat.rs b/tests/ui/useless_concat.rs new file mode 100644 index 0000000000000..02e68568c103b --- /dev/null +++ b/tests/ui/useless_concat.rs @@ -0,0 +1,20 @@ +#![warn(clippy::useless_concat)] +#![allow(clippy::print_literal)] + +macro_rules! my_concat { + ($fmt:literal $(, $e:expr)*) => { + println!(concat!("ERROR: ", $fmt), $($e,)*); + } +} + +fn main() { + let x = concat!(); //~ useless_concat + let x = concat!("a"); //~ useless_concat + let x = concat!(1); //~ useless_concat + println!("b: {}", concat!("a")); //~ useless_concat + // Should not lint. + let x = concat!("a", "b"); + let local_i32 = 1; + my_concat!("{}", local_i32); + let x = concat!(file!(), "#L", line!()); +} diff --git a/tests/ui/useless_concat.stderr b/tests/ui/useless_concat.stderr new file mode 100644 index 0000000000000..63038b6660b12 --- /dev/null +++ b/tests/ui/useless_concat.stderr @@ -0,0 +1,29 @@ +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:11:13 + | +LL | let x = concat!(); + | ^^^^^^^^^ help: replace with: `""` + | + = note: `-D clippy::useless-concat` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::useless_concat)]` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:12:13 + | +LL | let x = concat!("a"); + | ^^^^^^^^^^^^ help: replace with: `"a"` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:13:13 + | +LL | let x = concat!(1); + | ^^^^^^^^^^ help: replace with: `"1"` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:14:23 + | +LL | println!("b: {}", concat!("a")); + | ^^^^^^^^^^^^ help: replace with: `"a"` + +error: aborting due to 4 previous errors + From 7b06d2b776c401f66190509bd61804956426f9b0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 29 Dec 2024 20:10:51 +0100 Subject: [PATCH 2196/4206] Move `concat` macro path into `clippy_utils::paths` --- clippy_lints/src/useless_concat.rs | 3 ++- clippy_utils/src/paths.rs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/useless_concat.rs b/clippy_lints/src/useless_concat.rs index 3f68b93d4f575..4a818532f177a 100644 --- a/clippy_lints/src/useless_concat.rs +++ b/clippy_lints/src/useless_concat.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::macro_backtrace; +use clippy_utils::paths::CONCAT; use clippy_utils::source::snippet_opt; use clippy_utils::{match_def_path, tokenize_with_text}; use rustc_ast::LitKind; @@ -42,7 +43,7 @@ impl LateLintPass<'_> for UselessConcat { // Get the direct parent of the expression. && let Some(macro_call) = macro_backtrace(expr.span).next() // Check if the `concat` macro from the `core` library. - && match_def_path(cx, macro_call.def_id, &["core", "macros", "builtin", "concat"]) + && match_def_path(cx, macro_call.def_id, &CONCAT) // We get the original code to parse it. && let Some(original_code) = snippet_opt(cx, macro_call.span) // This check allows us to ensure that the code snippet: diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index e5179e479ccd9..9c909033447d0 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -129,6 +129,7 @@ path_macros! { // Paths in `core`/`alloc`/`std`. This should be avoided and cleaned up by adding diagnostic items. pub static ALIGN_OF: PathLookup = value_path!(core::mem::align_of); pub static CHAR_TO_DIGIT: PathLookup = value_path!(char::to_digit); +pub static CONCAT: PathLookup = value_path!(core::macros::builtin::concat); pub static IO_ERROR_NEW: PathLookup = value_path!(std::io::Error::new); pub static IO_ERRORKIND_OTHER_CTOR: PathLookup = value_path!(std::io::ErrorKind::Other); pub static ITER_STEP: PathLookup = type_path!(core::iter::Step); From a360940ac90cfbc6dbdab1f30ca5d5196551b1c3 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 9 May 2025 18:20:01 +0200 Subject: [PATCH 2197/4206] update version placeholders --- compiler/rustc_feature/src/accepted.rs | 4 ++-- compiler/rustc_feature/src/removed.rs | 2 +- compiler/rustc_feature/src/unstable.rs | 20 ++++++++-------- library/alloc/src/ffi/mod.rs | 2 +- library/core/src/arch.rs | 2 +- library/core/src/cell.rs | 12 +++++----- library/core/src/ffi/mod.rs | 2 +- library/core/src/hint.rs | 2 +- library/core/src/ptr/const_ptr.rs | 2 +- library/core/src/ptr/mod.rs | 2 +- library/core/src/ptr/mut_ptr.rs | 4 ++-- library/core/src/ptr/non_null.rs | 2 +- library/core/src/slice/mod.rs | 24 +++++++++---------- library/proc_macro/src/lib.rs | 12 +++++----- library/std/src/collections/hash/map.rs | 10 ++++---- library/std/src/collections/hash/set.rs | 10 ++++---- library/std/src/ffi/mod.rs | 2 +- .../documentation-tests.md | 2 +- 18 files changed, 58 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index e3e4eefe5e10a..809d1630ddec1 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -96,7 +96,7 @@ declare_features! ( /// Allows `#[cfg_attr(predicate, multiple, attributes, here)]`. (accepted, cfg_attr_multi, "1.33.0", Some(54881)), /// Allows the use of `#[cfg()]`. - (accepted, cfg_boolean_literals, "CURRENT_RUSTC_VERSION", Some(131204)), + (accepted, cfg_boolean_literals, "1.88.0", Some(131204)), /// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests. (accepted, cfg_doctest, "1.40.0", Some(62210)), /// Enables `#[cfg(panic = "...")]` config key. @@ -301,7 +301,7 @@ declare_features! ( /// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref. (accepted, move_ref_pattern, "1.49.0", Some(68354)), /// Allows using `#[naked]` on functions. - (accepted, naked_functions, "CURRENT_RUSTC_VERSION", Some(90957)), + (accepted, naked_functions, "1.88.0", Some(90957)), /// Allows specifying modifiers in the link attribute: `#[link(modifiers = "...")]` (accepted, native_link_modifiers, "1.61.0", Some(81490)), /// Allows specifying the bundle link modifier diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 402e18c5d1482..687d859df5359 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -143,7 +143,7 @@ declare_features! ( (removed, infer_static_outlives_requirements, "1.63.0", Some(54185), Some("removed as it caused some confusion and discussion was inactive for years")), /// Allow anonymous constants from an inline `const` block in pattern position - (removed, inline_const_pat, "CURRENT_RUSTC_VERSION", Some(76001), + (removed, inline_const_pat, "1.88.0", Some(76001), Some("removed due to implementation concerns as it requires significant refactorings")), /// Lazily evaluate constants. This allows constants to depend on type parameters. (removed, lazy_normalization_consts, "1.46.0", Some(72219), Some("superseded by `generic_const_exprs`")), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index a5f89b7a076ae..8fb10736539a3 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -206,7 +206,7 @@ declare_features! ( /// Allows access to the emscripten_wasm_eh config, used by panic_unwind and unwind (internal, cfg_emscripten_wasm_eh, "1.86.0", None), /// Allows checking whether or not the backend correctly supports unstable float types. - (internal, cfg_target_has_reliable_f16_f128, "CURRENT_RUSTC_VERSION", None), + (internal, cfg_target_has_reliable_f16_f128, "1.88.0", None), /// Allows identifying the `compiler_builtins` crate. (internal, compiler_builtins, "1.13.0", None), /// Allows writing custom MIR @@ -316,7 +316,7 @@ declare_features! ( // Unstable `#[target_feature]` directives. (unstable, aarch64_unstable_target_feature, "1.82.0", Some(44839)), (unstable, aarch64_ver_target_feature, "1.27.0", Some(44839)), - (unstable, apx_target_feature, "CURRENT_RUSTC_VERSION", Some(139284)), + (unstable, apx_target_feature, "1.88.0", Some(139284)), (unstable, arm_target_feature, "1.27.0", Some(44839)), (unstable, avx512_target_feature, "1.27.0", Some(44839)), (unstable, bpf_target_feature, "1.54.0", Some(44839)), @@ -327,7 +327,7 @@ declare_features! ( (unstable, loongarch_target_feature, "1.73.0", Some(44839)), (unstable, m68k_target_feature, "1.85.0", Some(134328)), (unstable, mips_target_feature, "1.27.0", Some(44839)), - (unstable, movrs_target_feature, "CURRENT_RUSTC_VERSION", Some(137976)), + (unstable, movrs_target_feature, "1.88.0", Some(137976)), (unstable, powerpc_target_feature, "1.27.0", Some(44839)), (unstable, prfchw_target_feature, "1.78.0", Some(44839)), (unstable, riscv_target_feature, "1.45.0", Some(44839)), @@ -385,7 +385,7 @@ declare_features! ( /// Allows associated type defaults. (unstable, associated_type_defaults, "1.2.0", Some(29661)), /// Allows implementing `AsyncDrop`. - (incomplete, async_drop, "CURRENT_RUSTC_VERSION", Some(126482)), + (incomplete, async_drop, "1.88.0", Some(126482)), /// Allows async functions to be called from `dyn Trait`. (incomplete, async_fn_in_dyn_trait, "1.85.0", Some(133119)), /// Allows `#[track_caller]` on async functions. @@ -395,7 +395,7 @@ declare_features! ( /// Allows `async` trait bound modifier. (unstable, async_trait_bounds, "1.85.0", Some(62290)), /// Allows using Intel AVX10 target features and intrinsics - (unstable, avx10_target_feature, "CURRENT_RUSTC_VERSION", Some(138843)), + (unstable, avx10_target_feature, "1.88.0", Some(138843)), /// Allows using C-variadics. (unstable, c_variadic, "1.34.0", Some(44930)), /// Allows the use of `#[cfg(contract_checks)` to check if contract checks are enabled. @@ -483,11 +483,11 @@ declare_features! ( /// Allows exhaustive pattern matching on types that contain uninhabited types. (unstable, exhaustive_patterns, "1.13.0", Some(51085)), /// Disallows `extern` without an explicit ABI. - (unstable, explicit_extern_abis, "CURRENT_RUSTC_VERSION", Some(134986)), + (unstable, explicit_extern_abis, "1.88.0", Some(134986)), /// Allows explicit tail calls via `become` expression. (incomplete, explicit_tail_calls, "1.72.0", Some(112788)), /// Allows using `#[export_stable]` which indicates that an item is exportable. - (incomplete, export_stable, "CURRENT_RUSTC_VERSION", Some(139939)), + (incomplete, export_stable, "1.88.0", Some(139939)), /// Allows using `aapcs`, `efiapi`, `sysv64` and `win64` as calling conventions /// for functions with varargs. (unstable, extended_varargs_abi_support, "1.65.0", Some(100189)), @@ -512,7 +512,7 @@ declare_features! ( /// Allows impls for the Freeze trait. (internal, freeze_impls, "1.78.0", Some(121675)), /// Frontmatter `---` blocks for use by external tools. - (unstable, frontmatter, "CURRENT_RUSTC_VERSION", Some(136889)), + (unstable, frontmatter, "1.88.0", Some(136889)), /// Allows defining gen blocks and `gen fn`. (unstable, gen_blocks, "1.75.0", Some(117078)), /// Infer generic args for both consts and types. @@ -575,7 +575,7 @@ declare_features! ( /// Allows `mut ref` and `mut ref mut` identifier patterns. (incomplete, mut_ref, "1.79.0", Some(123076)), /// Allows using `#[naked]` on `extern "Rust"` functions. - (unstable, naked_functions_rustic_abi, "CURRENT_RUSTC_VERSION", Some(138997)), + (unstable, naked_functions_rustic_abi, "1.88.0", Some(138997)), /// Allows using `#[target_feature(enable = "...")]` on `#[naked]` on functions. (unstable, naked_functions_target_feature, "1.86.0", Some(138568)), /// Allows specifying the as-needed link modifier @@ -641,7 +641,7 @@ declare_features! ( /// Allows string patterns to dereference values to match them. (unstable, string_deref_patterns, "1.67.0", Some(87121)), /// Allows `super let` statements. - (unstable, super_let, "CURRENT_RUSTC_VERSION", Some(139076)), + (unstable, super_let, "1.88.0", Some(139076)), /// Allows subtrait items to shadow supertrait items. (unstable, supertrait_item_shadowing, "1.86.0", Some(89151)), /// Allows using `#[thread_local]` on `static` items. diff --git a/library/alloc/src/ffi/mod.rs b/library/alloc/src/ffi/mod.rs index 05a2763a22596..1c408ace33613 100644 --- a/library/alloc/src/ffi/mod.rs +++ b/library/alloc/src/ffi/mod.rs @@ -87,5 +87,5 @@ pub use self::c_str::CString; #[stable(feature = "alloc_c_string", since = "1.64.0")] pub use self::c_str::{FromVecWithNulError, IntoStringError, NulError}; -#[stable(feature = "c_str_module", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "c_str_module", since = "1.88.0")] pub mod c_str; diff --git a/library/core/src/arch.rs b/library/core/src/arch.rs index f19fde2b4c733..e5078a45c6d9c 100644 --- a/library/core/src/arch.rs +++ b/library/core/src/arch.rs @@ -32,7 +32,7 @@ pub macro asm("assembly template", $(operands,)* $(options($(option),*))?) { /// /// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html /// [reference]: https://doc.rust-lang.org/nightly/reference/inline-assembly.html -#[stable(feature = "naked_functions", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "naked_functions", since = "1.88.0")] #[rustc_builtin_macro] pub macro naked_asm("assembly template", $(operands,)* $(options($(option),*))?) { /* compiler built-in */ diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index c7657350a0d9a..ed523920e42b5 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -495,7 +495,7 @@ impl Cell { /// ``` #[inline] #[stable(feature = "move_cell", since = "1.17.0")] - #[rustc_const_stable(feature = "const_cell", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_cell", since = "1.88.0")] #[rustc_confusables("swap")] pub const fn replace(&self, val: T) -> T { // SAFETY: This can cause data races if called from a separate thread, @@ -537,7 +537,7 @@ impl Cell { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_cell", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_cell", since = "1.88.0")] pub const fn get(&self) -> T { // SAFETY: This can cause data races if called from a separate thread, // but `Cell` is `!Sync` so this won't happen. @@ -556,7 +556,7 @@ impl Cell { /// assert_eq!(c.get(), 6); /// ``` #[inline] - #[stable(feature = "cell_update", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "cell_update", since = "1.88.0")] pub fn update(&self, f: impl FnOnce(T) -> T) { let old = self.get(); self.set(f(old)); @@ -608,7 +608,7 @@ impl Cell { /// ``` #[inline] #[stable(feature = "cell_get_mut", since = "1.11.0")] - #[rustc_const_stable(feature = "const_cell", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_cell", since = "1.88.0")] pub const fn get_mut(&mut self) -> &mut T { self.value.get_mut() } @@ -628,7 +628,7 @@ impl Cell { /// ``` #[inline] #[stable(feature = "as_cell", since = "1.37.0")] - #[rustc_const_stable(feature = "const_cell", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_cell", since = "1.88.0")] pub const fn from_mut(t: &mut T) -> &Cell { // SAFETY: `&mut` ensures unique access. unsafe { &*(t as *mut T as *const Cell) } @@ -686,7 +686,7 @@ impl Cell<[T]> { /// assert_eq!(slice_cell.len(), 3); /// ``` #[stable(feature = "as_cell", since = "1.37.0")] - #[rustc_const_stable(feature = "const_cell", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_cell", since = "1.88.0")] pub const fn as_slice_of_cells(&self) -> &[Cell] { // SAFETY: `Cell` has the same memory layout as `T`. unsafe { &*(self as *const Cell<[T]> as *const [Cell]) } diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index c9c73a25d899e..288d0df0d05bb 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -20,7 +20,7 @@ pub use self::c_str::FromBytesUntilNulError; pub use self::c_str::FromBytesWithNulError; use crate::fmt; -#[stable(feature = "c_str_module", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "c_str_module", since = "1.88.0")] pub mod c_str; #[unstable( diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index cb83540c4eaf7..6eefb30468931 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -782,7 +782,7 @@ pub const fn cold_path() { /// # assert_eq!(bucket_one.len() + bucket_two.len(), 1); /// ``` #[inline(always)] -#[stable(feature = "select_unpredictable", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "select_unpredictable", since = "1.88.0")] pub fn select_unpredictable(condition: bool, true_val: T, false_val: T) -> T { // FIXME(https://github.com/rust-lang/unsafe-code-guidelines/issues/245): // Change this to use ManuallyDrop instead. diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 5234fb83eb67c..35089b4853d7f 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1741,7 +1741,7 @@ impl PartialOrd for *const T { } } -#[stable(feature = "raw_ptr_default", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "raw_ptr_default", since = "1.88.0")] impl Default for *const T { /// Returns the default value of [`null()`][crate::ptr::null]. fn default() -> Self { diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index aa103af93ffcb..bd6c4daa509d9 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -1101,7 +1101,7 @@ pub const unsafe fn swap(x: *mut T, y: *mut T) { /// ``` #[inline] #[stable(feature = "swap_nonoverlapping", since = "1.27.0")] -#[rustc_const_stable(feature = "const_swap_nonoverlapping", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "const_swap_nonoverlapping", since = "1.88.0")] #[rustc_diagnostic_item = "ptr_swap_nonoverlapping"] #[rustc_allow_const_fn_unstable(const_eval_select)] // both implementations behave the same pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 31b8d3b572c0b..9cf251742d427 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1576,7 +1576,7 @@ impl *mut T { /// /// [`ptr::replace`]: crate::ptr::replace() #[stable(feature = "pointer_methods", since = "1.26.0")] - #[rustc_const_stable(feature = "const_inherent_ptr_replace", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_inherent_ptr_replace", since = "1.88.0")] #[inline(always)] pub const unsafe fn replace(self, src: T) -> T where @@ -2159,7 +2159,7 @@ impl PartialOrd for *mut T { } } -#[stable(feature = "raw_ptr_default", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "raw_ptr_default", since = "1.88.0")] impl Default for *mut T { /// Returns the default value of [`null_mut()`][crate::ptr::null_mut]. fn default() -> Self { diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 0864cc457b658..d05fb6a6d3199 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1166,7 +1166,7 @@ impl NonNull { /// [`ptr::replace`]: crate::ptr::replace() #[inline(always)] #[stable(feature = "non_null_convenience", since = "1.80.0")] - #[rustc_const_stable(feature = "const_inherent_ptr_replace", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_inherent_ptr_replace", since = "1.88.0")] pub const unsafe fn replace(self, src: T) -> T where T: Sized, diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 81fe0166fd77b..88b6674d4cccc 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1303,8 +1303,8 @@ impl [T] { /// // let chunks: &[[_; 5]] = slice.as_chunks_unchecked() // The slice length is not a multiple of 5 /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked() // Zero-length chunks are never allowed /// ``` - #[stable(feature = "slice_as_chunks", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "slice_as_chunks", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] #[inline] #[must_use] pub const unsafe fn as_chunks_unchecked(&self) -> &[[T; N]] { @@ -1360,8 +1360,8 @@ impl [T] { /// }; /// assert_eq!(chunks, &[['R', 'u'], ['s', 't']]); /// ``` - #[stable(feature = "slice_as_chunks", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "slice_as_chunks", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] #[inline] #[track_caller] #[must_use] @@ -1407,8 +1407,8 @@ impl [T] { /// assert_eq!(remainder, &['l']); /// assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]); /// ``` - #[stable(feature = "slice_as_chunks", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "slice_as_chunks", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] #[inline] #[track_caller] #[must_use] @@ -1498,8 +1498,8 @@ impl [T] { /// // let chunks: &[[_; 5]] = slice.as_chunks_unchecked_mut() // The slice length is not a multiple of 5 /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked_mut() // Zero-length chunks are never allowed /// ``` - #[stable(feature = "slice_as_chunks", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "slice_as_chunks", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] #[inline] #[must_use] pub const unsafe fn as_chunks_unchecked_mut(&mut self) -> &mut [[T; N]] { @@ -1551,8 +1551,8 @@ impl [T] { /// } /// assert_eq!(v, &[1, 1, 2, 2, 9]); /// ``` - #[stable(feature = "slice_as_chunks", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "slice_as_chunks", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] #[inline] #[track_caller] #[must_use] @@ -1604,8 +1604,8 @@ impl [T] { /// } /// assert_eq!(v, &[9, 1, 1, 2, 2]); /// ``` - #[stable(feature = "slice_as_chunks", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "slice_as_chunks", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "slice_as_chunks", since = "1.88.0")] + #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] #[inline] #[track_caller] #[must_use] diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 79e9b8430b8d5..b4fd20c0c176a 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -513,13 +513,13 @@ impl Span { } /// Creates an empty span pointing to directly before this span. - #[stable(feature = "proc_macro_span_location", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "proc_macro_span_location", since = "1.88.0")] pub fn start(&self) -> Span { Span(self.0.start()) } /// Creates an empty span pointing to directly after this span. - #[stable(feature = "proc_macro_span_location", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "proc_macro_span_location", since = "1.88.0")] pub fn end(&self) -> Span { Span(self.0.end()) } @@ -527,7 +527,7 @@ impl Span { /// The one-indexed line of the source file where the span starts. /// /// To obtain the line of the span's end, use `span.end().line()`. - #[stable(feature = "proc_macro_span_location", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "proc_macro_span_location", since = "1.88.0")] pub fn line(&self) -> usize { self.0.line() } @@ -535,7 +535,7 @@ impl Span { /// The one-indexed column of the source file where the span starts. /// /// To obtain the column of the span's end, use `span.end().column()`. - #[stable(feature = "proc_macro_span_location", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "proc_macro_span_location", since = "1.88.0")] pub fn column(&self) -> usize { self.0.column() } @@ -544,7 +544,7 @@ impl Span { /// /// This might not correspond to a valid file system path. /// It might be remapped (e.g. `"/src/lib.rs"`) or an artificial path (e.g. `""`). - #[stable(feature = "proc_macro_span_file", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "proc_macro_span_file", since = "1.88.0")] pub fn file(&self) -> String { self.0.file() } @@ -554,7 +554,7 @@ impl Span { /// This is the actual path on disk. It is unaffected by path remapping. /// /// This path should not be embedded in the output of the macro; prefer `file()` instead. - #[stable(feature = "proc_macro_span_file", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "proc_macro_span_file", since = "1.88.0")] pub fn local_file(&self) -> Option { self.0.local_file().map(|s| PathBuf::from(s)) } diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 961d6ee0665c1..3530f890f5294 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -683,7 +683,7 @@ impl HashMap { /// ``` #[inline] #[rustc_lint_query_instability] - #[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "hash_extract_if", since = "1.88.0")] pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool, @@ -1680,7 +1680,7 @@ impl<'a, K, V> Drain<'a, K, V> { /// ]); /// let iter = map.extract_if(|_k, v| *v % 2 == 0); /// ``` -#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "hash_extract_if", since = "1.88.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ExtractIf<'a, K, V, F> { base: base::ExtractIf<'a, K, V, F>, @@ -2294,7 +2294,7 @@ where } } -#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "hash_extract_if", since = "1.88.0")] impl Iterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool, @@ -2311,10 +2311,10 @@ where } } -#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "hash_extract_if", since = "1.88.0")] impl FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} -#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "hash_extract_if", since = "1.88.0")] impl fmt::Debug for ExtractIf<'_, K, V, F> where K: fmt::Debug, diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index fa2f4f0a58fec..8514dfd9a984d 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -308,7 +308,7 @@ impl HashSet { /// ``` #[inline] #[rustc_lint_query_instability] - #[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "hash_extract_if", since = "1.88.0")] pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, T, F> where F: FnMut(&T) -> bool, @@ -1390,7 +1390,7 @@ pub struct Drain<'a, K: 'a> { /// /// let mut extract_ifed = a.extract_if(|v| v % 2 == 0); /// ``` -#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "hash_extract_if", since = "1.88.0")] pub struct ExtractIf<'a, K, F> { base: base::ExtractIf<'a, K, F>, } @@ -1670,7 +1670,7 @@ impl fmt::Debug for Drain<'_, K> { } } -#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "hash_extract_if", since = "1.88.0")] impl Iterator for ExtractIf<'_, K, F> where F: FnMut(&K) -> bool, @@ -1687,10 +1687,10 @@ where } } -#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "hash_extract_if", since = "1.88.0")] impl FusedIterator for ExtractIf<'_, K, F> where F: FnMut(&K) -> bool {} -#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "hash_extract_if", since = "1.88.0")] impl fmt::Debug for ExtractIf<'_, K, F> where K: fmt::Debug, diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index bd9446f5aba51..567916099101b 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -161,7 +161,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -#[stable(feature = "c_str_module", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "c_str_module", since = "1.88.0")] pub mod c_str; #[stable(feature = "core_c_void", since = "1.30.0")] diff --git a/src/doc/rustdoc/src/write-documentation/documentation-tests.md b/src/doc/rustdoc/src/write-documentation/documentation-tests.md index 077b02d603d0f..e6b15e0dbd325 100644 --- a/src/doc/rustdoc/src/write-documentation/documentation-tests.md +++ b/src/doc/rustdoc/src/write-documentation/documentation-tests.md @@ -462,7 +462,7 @@ struct Foo; ``` In older versions, this will be ignored on all targets, but starting with -version CURRENT_RUSTC_VERSION, `ignore-x86_64` will override `ignore`. +version 1.88.0, `ignore-x86_64` will override `ignore`. ### Custom CSS classes for code blocks From 2b7c13e7786db66605b0a1de017c1fe4aa888206 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Sat, 10 May 2025 10:37:02 +0200 Subject: [PATCH 2198/4206] update stage0 compiler --- src/stage0 | 920 ++++++++++++++++++++++++++--------------------------- 1 file changed, 460 insertions(+), 460 deletions(-) diff --git a/src/stage0 b/src/stage0 index 06080e3a8c161..8ca6860490ca5 100644 --- a/src/stage0 +++ b/src/stage0 @@ -13,466 +13,466 @@ nightly_branch=master # All changes below this comment will be overridden the next time the # tool is executed. -compiler_date=2025-04-02 +compiler_date=2025-05-12 compiler_version=beta -rustfmt_date=2025-04-02 +rustfmt_date=2025-05-12 rustfmt_version=nightly -dist/2025-04-02/rustc-beta-aarch64-apple-darwin.tar.gz=42fbc48c6f9034c1d47029491e0adc7aaa1adecf429e22ea9eb6d36225ed13e7 -dist/2025-04-02/rustc-beta-aarch64-apple-darwin.tar.xz=08f88363fd42d66d537c0a296502f94c3a3fecf59a004613c9acff33eb0b0207 -dist/2025-04-02/rustc-beta-aarch64-pc-windows-msvc.tar.gz=ea47adaa63abd18bf0c11cdb381eefb2874994527005cbccc0dcace33191f9c6 -dist/2025-04-02/rustc-beta-aarch64-pc-windows-msvc.tar.xz=cefea68c789907a45f0bd4233da2e3406287ac55d1c33f8612ec1aa006b853f0 -dist/2025-04-02/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=38fa4ce395641a988247ee58c334389eda62fc1d3c0fb45157f24578319925d8 -dist/2025-04-02/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=d8d0b459acdff2a32f8c40707bf5a17b71ce86fb5ee9ad61690cba8f8227bbfc -dist/2025-04-02/rustc-beta-aarch64-unknown-linux-musl.tar.gz=41f01647a80a7f21b85fe660af9e7964ad34f0e909d1e58c9e28e102a796791f -dist/2025-04-02/rustc-beta-aarch64-unknown-linux-musl.tar.xz=8436eddf40ad5bf61153f24c887fb0f0e878bcc403095719b35f3147328d6406 -dist/2025-04-02/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=07ee5588005a18477a7de89321e6527ee5f10af00e9c4eeb2a8c666f79d3d606 -dist/2025-04-02/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=8a95664cef49c1e45b2ae61ec464a5be976e4cecd2b502a050f95b9eb25dd4c7 -dist/2025-04-02/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=b9b186ea9bee58a646ce8c4c384fc4cb528c73c1fee3ea3f5028fd4b3fddab3a -dist/2025-04-02/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=9f62c2ea5b67c14ab804267d449ded07c8b551536886099b02b942ce2d641790 -dist/2025-04-02/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=f07363ad0dff8b965dc10543f27cfd923266dea6284ebbb1d1b59b77f5ae2b61 -dist/2025-04-02/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=a31afc234645a7dc5dc47f05bb5321fea12931278433df834def303cdea9f52d -dist/2025-04-02/rustc-beta-i686-pc-windows-gnu.tar.gz=f396061e8faaf66edea34b0855e2d3760fc0fd5c75e99696b50b2d4f310e11e0 -dist/2025-04-02/rustc-beta-i686-pc-windows-gnu.tar.xz=0f95f9170c5b211db29c3baac9341ef61de83511fe0000b8aae65aaf90041ae6 -dist/2025-04-02/rustc-beta-i686-pc-windows-msvc.tar.gz=82b7d1136d1b6f3d229fc77eac19d2cbfb3a46de472345b0ec3ebc152872164f -dist/2025-04-02/rustc-beta-i686-pc-windows-msvc.tar.xz=565bde72132e77617059da66edf9262f728336a2cc2c3c7cf4d61e0a4b5e681a -dist/2025-04-02/rustc-beta-i686-unknown-linux-gnu.tar.gz=8a3abc2a8aee8fa30699f51a216b29b41b2242143646d0f560f89bf72a0e285c -dist/2025-04-02/rustc-beta-i686-unknown-linux-gnu.tar.xz=7d47cf99aa5fd3b5bc2caa918b4eaba793b6d38252a72fa7be631c8db27c8525 -dist/2025-04-02/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=0654cf14bd3302d001fa00fe73cb7c597206c6897978b3aeefd00e9325a8bdad -dist/2025-04-02/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=6cd5c3ccb643a912d738239c0ad7464ee755cd81f45a26a9d3aa5ceeff569ba3 -dist/2025-04-02/rustc-beta-loongarch64-unknown-linux-musl.tar.gz=e3c0c5c52b04dd060f3a70b0c936dfb5c70ac29256361a491df9c898259dd551 -dist/2025-04-02/rustc-beta-loongarch64-unknown-linux-musl.tar.xz=83a9bc8f9a61b2a7fedddbdfb253aa078bc9896f179ec9b1d1bd918e7de34663 -dist/2025-04-02/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=21efa7a67647df8aa99e40317c798895321d09c48b8453e51eef1635c20e9c47 -dist/2025-04-02/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=56203ed9d3bbbab33e2825db7c72cfbe4f857f68dc98072cc98280cc4f1110d6 -dist/2025-04-02/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=76c343aa3f5c74e1419e3f2f79dd3a2091fad8f6db644cf14f7aef036c8369d0 -dist/2025-04-02/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=e9c7b97a407127e51fa49ca94c5f22c59f2f325848d55e6160d6dcf7ff690f91 -dist/2025-04-02/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=27935ff4136141519b4e7b37b55253960b7fa16f5cd751d731ed85019432247b -dist/2025-04-02/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=fd37c12a55055bc4a2f0e002b3126e6396df8d49254b2a8a7a45354aac46bb2c -dist/2025-04-02/rustc-beta-powerpc64le-unknown-linux-musl.tar.gz=cbeba9993d03c6c0c2c508414bee04665abb9c084c736b39c5b8d38c8f63402d -dist/2025-04-02/rustc-beta-powerpc64le-unknown-linux-musl.tar.xz=e92f69d85929c81e3c91b2ab45eec418afc65edf6f8bf9383148a98b052353df -dist/2025-04-02/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=31a8ae1e64fb86a499518d7711595d653db56527aaedea06bc2bbcb912568844 -dist/2025-04-02/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=7d001ad6c4825d5323813ed19747cc3e3d2dcbbe76317329a52127b3de37ee88 -dist/2025-04-02/rustc-beta-s390x-unknown-linux-gnu.tar.gz=c69d15e75d51caa0cf77fbe149d43b62c327896bdeb0c6c73fa7240404289862 -dist/2025-04-02/rustc-beta-s390x-unknown-linux-gnu.tar.xz=cf80772ba9eed4885a28aab38323f0ed24ab220339a3b8a148b7c27860c48c19 -dist/2025-04-02/rustc-beta-x86_64-apple-darwin.tar.gz=be22d207f8fd4722d69f6fdc56c57618ec01c54c5b6f3a8506c62583259d433a -dist/2025-04-02/rustc-beta-x86_64-apple-darwin.tar.xz=04feea9824748ae01b4f4f85d15adc5baee23c996c22de86041888466ae69512 -dist/2025-04-02/rustc-beta-x86_64-pc-windows-gnu.tar.gz=8c75005f0309d30e7c272adce173adb253874ce881b347946b6ffe5a07067439 -dist/2025-04-02/rustc-beta-x86_64-pc-windows-gnu.tar.xz=7b87c4ab5291d9ad3670f4e9ee98fe9f6f877ab8d4952109d7e5e9d20181a700 -dist/2025-04-02/rustc-beta-x86_64-pc-windows-msvc.tar.gz=a96d89ba655db5317dd51ffa2ebb81b7bdb76b19cf12de36e9d0aba2c5877ae2 -dist/2025-04-02/rustc-beta-x86_64-pc-windows-msvc.tar.xz=84bcfd763eba610c78223697393ea97f1f70e567a44b8cfe22db79f1cade4201 -dist/2025-04-02/rustc-beta-x86_64-unknown-freebsd.tar.gz=95ff7349cf12e49028256c06c8517719cada2720d4db80bfe7531289bbcdbde9 -dist/2025-04-02/rustc-beta-x86_64-unknown-freebsd.tar.xz=c8d0147c625faa5ce0e75c2509827bc4b190ad286e41411bce92023e00eb7a1d -dist/2025-04-02/rustc-beta-x86_64-unknown-illumos.tar.gz=4be80235a110028d64404e532eb20af37e46db72a7ac3a0cf7c94ddf463c461f -dist/2025-04-02/rustc-beta-x86_64-unknown-illumos.tar.xz=b18ea9a5c262c2f7505305110473cc15bd2c4ed9d583f07c15635406c050be08 -dist/2025-04-02/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=234027a0075224ea157efaf39173ece43f9ca7d69d86e4790a2a038f7e6d98a6 -dist/2025-04-02/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=308a8ee2855a6471db3b3b64cb06e355e31d0d617ebc9f30757bb7db5f6fc7c0 -dist/2025-04-02/rustc-beta-x86_64-unknown-linux-musl.tar.gz=10f39cc94f39bcf17d0fa3b8efeb4db72408fba694e5eb0f175e7465f6d2de49 -dist/2025-04-02/rustc-beta-x86_64-unknown-linux-musl.tar.xz=6b0d16b46347fdbcddfafad8209df19515059eddce1e048ecf1585341fa1e586 -dist/2025-04-02/rustc-beta-x86_64-unknown-netbsd.tar.gz=09f482425c92396f7e4ae3baf625dbcad1d886d82ecfb605b50393abdc23ce15 -dist/2025-04-02/rustc-beta-x86_64-unknown-netbsd.tar.xz=bac2f1a493bc2c5fa6cab1f58ff536cbeba55f77141b34636bfded9e3ff167b5 -dist/2025-04-02/rust-std-beta-aarch64-apple-darwin.tar.gz=8875ade1dd8ba0bca0c12860a076df1f089195a52adc546679025c405bef4dd1 -dist/2025-04-02/rust-std-beta-aarch64-apple-darwin.tar.xz=0a0593ab4c95802b0ed810c0442e13ad9304712c2f7c30a30c734523a7448d8a -dist/2025-04-02/rust-std-beta-aarch64-apple-ios.tar.gz=839086e20098c305adcdf9103cdf3f29a14c4140b4c1b728723e7aedad966883 -dist/2025-04-02/rust-std-beta-aarch64-apple-ios.tar.xz=70f1832193e77a2018088943b531bdbacbe5404d5d7a34393e03f40329e742ce -dist/2025-04-02/rust-std-beta-aarch64-apple-ios-macabi.tar.gz=94adeb2e63a91c09001facbc554678227a3717748104424e4fea71db3d5a16be -dist/2025-04-02/rust-std-beta-aarch64-apple-ios-macabi.tar.xz=73c9bb75eb6fa4cf613c7a2b0e237472e144a1469cb043194ad7802052149fee -dist/2025-04-02/rust-std-beta-aarch64-apple-ios-sim.tar.gz=0e01ed2620887b893687758d62422f661429e3c4566ff52d967463eca89f54c5 -dist/2025-04-02/rust-std-beta-aarch64-apple-ios-sim.tar.xz=c26beb8ea9f11845ce79d4f0ec2616ce82dfbc4fefadfc7f94a1df17f4d5bec2 -dist/2025-04-02/rust-std-beta-aarch64-linux-android.tar.gz=64047673efa9d9bad660e2a44f82e6f929c881fe205523bff10a549505d12b72 -dist/2025-04-02/rust-std-beta-aarch64-linux-android.tar.xz=0e4c6b76e8d92023533aef6fe377c9bd45ef9c1da517eda7bfefec85b966780b -dist/2025-04-02/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=a25c50a86e5d674600cec5bd9e7939bf36b0afa766445b0d71673431388d285c -dist/2025-04-02/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=8060a4c5337fa6c34b3f08ddb8886beeb5bafd2b02544b08a7cfcb466a27a972 -dist/2025-04-02/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=efd76703934ae0187308eec9b3439abea0dd4437ac353d5dc07d92f9440ab9ee -dist/2025-04-02/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=007462f554b0c6d2b165d727bf72b1ad4347a53869d672fcbf48db2c1dcf128d -dist/2025-04-02/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=e0dc54be7890edef123d2dc31f0dcddd1c807cc060a34f475093cab79100d9fd -dist/2025-04-02/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=01c06c1d61c512a034a109f50f957e4496639549837b63464acb4fb24ff65e09 -dist/2025-04-02/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=2042d37b09618379dd91125d20803e2d97d5f3f3794e01ed27597a0f3b27c102 -dist/2025-04-02/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=568f0b8da190daf78cd8573b0408db2ecc2c07b1cb1fa463239581963738e9de -dist/2025-04-02/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=386b1e4786dbfe342626cde4c3708abd04d9862d69717c7acd5dfe82427e38f9 -dist/2025-04-02/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=781d0f9417e1b3d33d95e3c5b82ba7e481a610dc468345119e09a52b1d170045 -dist/2025-04-02/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=8673d059524ac141a8907decfda36c8afac81fd36dd75f78df750a6d52ada221 -dist/2025-04-02/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=8e8afe45e9bb84ebc3e02f0b4b71dbcec7c844128329d31067303b86113c3439 -dist/2025-04-02/rust-std-beta-aarch64-unknown-none.tar.gz=72e1dce3c1f821b6018ec155bff250b941afcfcf1697b440a69822b10e929b94 -dist/2025-04-02/rust-std-beta-aarch64-unknown-none.tar.xz=7030883ad3ca170a061972707c488fc25d4dc8ab0f60a1b9b54240e42ca713ba -dist/2025-04-02/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=28f87a505ca4e2c33015338d73cfdf5c2fdb1f5775f82ec432d033a36880351d -dist/2025-04-02/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=45669a09671c183d702a31b6ecf095e8f422797c4e242063c7864180c6f657a4 -dist/2025-04-02/rust-std-beta-aarch64-unknown-uefi.tar.gz=1ad54cabda8bfabfd93e16c564c0950c26e1502662d5f4ce3b33b4ee265b9a2d -dist/2025-04-02/rust-std-beta-aarch64-unknown-uefi.tar.xz=a79f9d7eb4297994b2e87d48106a959c82bc4387433e5e86dc8caddde29a8a4e -dist/2025-04-02/rust-std-beta-arm-linux-androideabi.tar.gz=75192092fa7a40051a70a843cf75513de2c50d66927f16b122f7417c1d4f25e7 -dist/2025-04-02/rust-std-beta-arm-linux-androideabi.tar.xz=843dde45dfa49b5cc97266c61d8e58dfb22dbf2288e6e8baaef769eaf59675cc -dist/2025-04-02/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=03ccaa5e246502fc61fea1e0b33f5c60b5895cd0b5b932bf640d62e97164b457 -dist/2025-04-02/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=a73525dcab3a0f3bc7064c8a6cdeb9b0e5b359501cb7e8fe20075a0e97b2a5ba -dist/2025-04-02/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=8c851fc122d14beee962e15fdb95c2873769805180be30723f418d84cbc0a8b8 -dist/2025-04-02/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=8524ad1b7723a4a5898837d5b526fb11ffcd039b2c4835a2e139071f6cfd4e9f -dist/2025-04-02/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=b108ec4460d4f6ca79813e6d2d4cb7061fa522a990333fb9f4f927b0fc659624 -dist/2025-04-02/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=0bdb617dfa833c62c03f5bfd2f06ed3ca1479908d860f888d661794188bd57d6 -dist/2025-04-02/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=19f9fff71344f7a42f958c3efec720e4b2e0d67ba36a5fd66946e74811259f2b -dist/2025-04-02/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=0cdfe9b4a8bc4b63637cfd9766c3e0e1d3dcd6d2e82fe35f57973a0081e630ec -dist/2025-04-02/rust-std-beta-arm64ec-pc-windows-msvc.tar.gz=a8490374598bbfa42931bbfba51ecc0186c476217eb79408ae6b80a4ba6de9f2 -dist/2025-04-02/rust-std-beta-arm64ec-pc-windows-msvc.tar.xz=2bc2838320667f060c140345d1c26aedf90bf5efb1f72e6722b74d32f876901c -dist/2025-04-02/rust-std-beta-armebv7r-none-eabi.tar.gz=9a237e1dbd2e3b555aa3932351d1c20a0f9f2f06e810abd254b5ca152aace687 -dist/2025-04-02/rust-std-beta-armebv7r-none-eabi.tar.xz=f4978bf9af719f0b6e8300ea862fe617e983e5443a46c769d60d5e8c4d556ba8 -dist/2025-04-02/rust-std-beta-armebv7r-none-eabihf.tar.gz=c1476718625d5d5d42b60faa9ade845272b0b71e91d77a9cdd271c4682c900d2 -dist/2025-04-02/rust-std-beta-armebv7r-none-eabihf.tar.xz=f8ab07e99983fc7395841cc9ed7ce7cfaedd87bfb91214bd83508ad96aef0c0b -dist/2025-04-02/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=649071a7de4792ff75da59ca421ea1cb364c011db97e73c480982a5f9f06b8aa -dist/2025-04-02/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=529aac0b0a385fa5ddb76a88eb6923bcc981679caab2d1c374d443383c99f52a -dist/2025-04-02/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=8bdf3412b0b557485099db86afcdf58293bfd4c09c4b360c2d9733788b612122 -dist/2025-04-02/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=5d5a4ebed984a0930b214ec0b11e20fd9a7b8d5dc2d00985b75a77c8febcf441 -dist/2025-04-02/rust-std-beta-armv7-linux-androideabi.tar.gz=2c03cbb393641876bebad9b76465ac7f96adb82c14dcc9b5bc01a82e5110b892 -dist/2025-04-02/rust-std-beta-armv7-linux-androideabi.tar.xz=67d86fa728178c30cd7a33e0c488c32f58ae0caeb9a982370e080ea38853830b -dist/2025-04-02/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=3737dd5f80f35f3fecf5cd8324c9226f45bb0bfd040998d91509a2c6fd8967f1 -dist/2025-04-02/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=8f9f710c92af058d5a07c93b4cfd45b7d30e63ab79bea7f79530537aae2dd836 -dist/2025-04-02/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=6ecb3e238e125e88851dba9711b2b32f4de1da55de36a62373bfcc42d001fa0b -dist/2025-04-02/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=7d6807d24afe4825b77c1cb74c1412b814cf2508f5b40debb55b3f264e02eb6a -dist/2025-04-02/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=a15fccced78065f748a5c4f66763b8940ae3e52b5048b5ee1fab6b0b7b40c701 -dist/2025-04-02/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=20bc43c1b5742a9c7a97ade055441ca1ca153dab9602db3ffaf1ac518713568e -dist/2025-04-02/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=b01929a0f18b1a41b65307a04d1273d2197df83b3c124f80659ef8fa4f8c4577 -dist/2025-04-02/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=2a13350da7c632d3878ca8da8a7d0bda60c850df8e5d824956082b524eb136fe -dist/2025-04-02/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=11bc9fd437be07cb454182b0d7b287ec030f7d8904f096b73beda6480ba33285 -dist/2025-04-02/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=31e06feb45173fec8e58cf92216e44d556587fe2ed866102206e23514c73d3f0 -dist/2025-04-02/rust-std-beta-armv7a-none-eabi.tar.gz=aebbae792c070adea3f10135c02b2cf5d623b84e765ec3a72c89275f53a85384 -dist/2025-04-02/rust-std-beta-armv7a-none-eabi.tar.xz=e80dcb152e7a8337fbbff6a5c8dfcd9c6da4b753da6b14e63fe7c15cc0836359 -dist/2025-04-02/rust-std-beta-armv7r-none-eabi.tar.gz=e79846c1203d5d375c7c1cff1c843cb6fcd4e33bbc71b2363e12fc900bbd72bd -dist/2025-04-02/rust-std-beta-armv7r-none-eabi.tar.xz=0e24e48461cc46edef0237e38480ac806d0521c73ea366668e731f29b638d7c9 -dist/2025-04-02/rust-std-beta-armv7r-none-eabihf.tar.gz=fd2a9b48ea203b44567cfdcfcfb21d5d803896fdfdc5f3aa191e3fa7472b98db -dist/2025-04-02/rust-std-beta-armv7r-none-eabihf.tar.xz=2b85d461bed34a97cf832a7c0e1d4179d7800ef47523a8e31d635b8de5dd44a7 -dist/2025-04-02/rust-std-beta-i586-unknown-linux-gnu.tar.gz=cab412c30b27060cdcb29adb947dc070875813726707dff121c4a1aa8615646d -dist/2025-04-02/rust-std-beta-i586-unknown-linux-gnu.tar.xz=1b8d469fbb8903a5f4f5eb6ccee7bdf28cc56137b6b212fdfa1aed647f4c347b -dist/2025-04-02/rust-std-beta-i586-unknown-linux-musl.tar.gz=93fa0383e32f18567c3c156f3cddde1fa4296003f98cdd22b0b5628d69d5208a -dist/2025-04-02/rust-std-beta-i586-unknown-linux-musl.tar.xz=71ae00b01ffbfdc6654d0fd14df204adb7d499ac71e59c93affff91d58833d88 -dist/2025-04-02/rust-std-beta-i686-linux-android.tar.gz=4c6f4764e284ff29958417295ddc5d3316072fc9eac87dfed8b694c237aa4f88 -dist/2025-04-02/rust-std-beta-i686-linux-android.tar.xz=f471a7abb2d447f668f01973be4712e20c6dd29b210a96517b277e62c6d7de07 -dist/2025-04-02/rust-std-beta-i686-pc-windows-gnu.tar.gz=0c5efb9792502fc08174b2556f5c91f3edbad6e02de5e230f39c5fa011fc935c -dist/2025-04-02/rust-std-beta-i686-pc-windows-gnu.tar.xz=b6a87360e7be832288e59239d41e809db01710ccae5ef37bcbe7b0eb1d311e66 -dist/2025-04-02/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=0429745cd95a198a7a42a1ce0c7ab2d502f3ff3eee81104fe6d5d4d5dab9447e -dist/2025-04-02/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=bcb43c9e2d4a49c18d39e041d28021f2302707ae9ac20ef37f4d467fd2cd3975 -dist/2025-04-02/rust-std-beta-i686-pc-windows-msvc.tar.gz=e1d8c40e61701c6bfd519125169cc1ab1d60e9a58238351bbeda0ccc5522cc49 -dist/2025-04-02/rust-std-beta-i686-pc-windows-msvc.tar.xz=1f87f343a90f6e88cb3173d52f4f88d8abdb0c1a613681c92675c1acc340aa54 -dist/2025-04-02/rust-std-beta-i686-unknown-freebsd.tar.gz=5862f33548bef1aa21b3d63caefa12ee34775cb378f89c4dc161e081a773d11e -dist/2025-04-02/rust-std-beta-i686-unknown-freebsd.tar.xz=ed3460948031d0c4e97f7b1b77062f388d133db2b2212518eabd3198e72c031c -dist/2025-04-02/rust-std-beta-i686-unknown-linux-gnu.tar.gz=3a6edd9f412a274e372c9555b6758d540d06ac08efd21ce95df1ed4d30418afd -dist/2025-04-02/rust-std-beta-i686-unknown-linux-gnu.tar.xz=8338baaa50b9cb08a28f7bb21a22deef849f8809282c661e48c486a168b6249e -dist/2025-04-02/rust-std-beta-i686-unknown-linux-musl.tar.gz=56ab80fc6cb75a0d66c477e76f87918645bc3b616cf704306820832681022768 -dist/2025-04-02/rust-std-beta-i686-unknown-linux-musl.tar.xz=94efb810dbee977ecb3ff5a42a5a620d720c237da58d974ba1f376c99947baf5 -dist/2025-04-02/rust-std-beta-i686-unknown-uefi.tar.gz=64cb107065bde9b30c78b9b342211c4e6cd2c3ed726155dacfcf5958ba869a82 -dist/2025-04-02/rust-std-beta-i686-unknown-uefi.tar.xz=ff1bc215b4aba25f59eeee8285967e24b78f6965473ea8bb30186ab55804f88a -dist/2025-04-02/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=da1d33b266e1dd277f97f63228843765706f26c9f75c4b5171f49c2762fed870 -dist/2025-04-02/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=8309c9c4a03df90eb53116b5c5c4870d103911227848919580a48e5e85954709 -dist/2025-04-02/rust-std-beta-loongarch64-unknown-linux-musl.tar.gz=26a3115d5354f878f80bef1c83a44af185e2780882e17143ca57aff078d123a0 -dist/2025-04-02/rust-std-beta-loongarch64-unknown-linux-musl.tar.xz=12431c3b50276f352a3ea71c74db279cd03c2edfb3edf743f81774d4274f7ef9 -dist/2025-04-02/rust-std-beta-loongarch64-unknown-none.tar.gz=ac67b23f84d09ab17d26f30deb38a128ccf812a561738327effe48ecd0caa319 -dist/2025-04-02/rust-std-beta-loongarch64-unknown-none.tar.xz=5508b02465d3dbb40512a142eabb27817807d2af153089f7d05a0af355fdb245 -dist/2025-04-02/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=a79a59139e13166cb1121d703cee113bf92821f937d433cb9a2c00567280a4e2 -dist/2025-04-02/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=8c3b5501050f57125cc89e6525b780ca0e18d2d5318f779894ab97efef761fb3 -dist/2025-04-02/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=84a48148eb313f236f85a4907af615b7af4c3ce3d9065ffe0db54458852690ab -dist/2025-04-02/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=26281622332b438bc43b8f46921153a45c6236a4c0939c76fdb4d9fb3d29cbbb -dist/2025-04-02/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=0eef233c871404b913c6458d8005d362e3c24fcb0670ac49a7e67b1a503b4b29 -dist/2025-04-02/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=b96422b0f33446abee203160a22e9bac8861e1c7988b2cef463276743001fc7c -dist/2025-04-02/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=18db97406a6e644734c7890991cb3006fabe1e1a185f89d108d28a992ed7c17c -dist/2025-04-02/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=eea42655b5335643905acaa3d8ff1774e2c1a39ffde363c2073a8636c153087a -dist/2025-04-02/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=5feaf6f3859204979fb4dab03fc93428abd103d61822d6e4e9a2f5d6d155213a -dist/2025-04-02/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=98f8e695253c9dad3d82638bd69c084a3e7a96d17eb1dba0f90a42df993de864 -dist/2025-04-02/rust-std-beta-powerpc64le-unknown-linux-musl.tar.gz=e028f2ec967ecee5d9e7b48058209428ed220c5da2c00f2753f8d4e98951e168 -dist/2025-04-02/rust-std-beta-powerpc64le-unknown-linux-musl.tar.xz=69f508ffcb55347dbb773cfa22a1f7a6362f3aff6a48296b50945422ea82c7b5 -dist/2025-04-02/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=ea30bf48fcb3873db4019ae3d248e1db868e1f7fc49e4549737aae58b3b49b22 -dist/2025-04-02/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=c3724aaa58f812dc8283622f27e215546d8522b6ecdf1d191010dde3a1ba3344 -dist/2025-04-02/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=9d24eb785b66796309c2f03944719fb6b6980ae8fb7ca97084fcfdea0094bcce -dist/2025-04-02/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=f6b2233474eb64d041e6bd8f1b6dee3eaf775b6b5a7ddec703689352cf88f6a2 -dist/2025-04-02/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=8a5c94055180b9a1226a23c5992a622062ac52cddf91651a91a5d236be46d0c8 -dist/2025-04-02/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=7ea826d6c58fe1ef1c9374aef0cbfec5495daddcda581b231d18397330d9e248 -dist/2025-04-02/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=811881bd5b514c89c316453ea1214fbeccf5388f18468cc83676a879d58f53ab -dist/2025-04-02/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=9448b7bad586237faa4f090ce8c3de83b62d19fbe37104ae32032d9df709d2e6 -dist/2025-04-02/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=dd9252a03b0a888ee7598a84c20aac721739c2caf9c5b585274d2a30d7fcbcb6 -dist/2025-04-02/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=d1f134647fe0c3efcce80351cf9e4786ca8e3e336c0316b7c28ff07b78907c73 -dist/2025-04-02/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=4f688c40457ba71542438fbc100b62b5f081435567f965512481ccf3d002826d -dist/2025-04-02/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=a474fddf29c6979e0870c397c19f64de00650893a781eb51d9e136802bfabbfd -dist/2025-04-02/rust-std-beta-riscv64gc-unknown-linux-musl.tar.gz=7071209fdf0d2605b623ef96c934ed039d1dd95a68c438a8c563530ed48fb4e2 -dist/2025-04-02/rust-std-beta-riscv64gc-unknown-linux-musl.tar.xz=1328504e895dc9bbc36ac697bd5031e0034b2468fc66a91e42b39a4d35d4ea8b -dist/2025-04-02/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=e7878c1137279790205e62f9c363a6f45e2a8cd9c30702a53478a8104dc87a6b -dist/2025-04-02/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=f373b1d79547c385a01c2b36951eb3750a4cf3bcaaa213587af9a6b4274dc924 -dist/2025-04-02/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=4832338ebc25d088e30952605b3f6491d96003790df5b10c5c56e29ec69ac646 -dist/2025-04-02/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=d782dac690b3da2b96206809512f1ae82fb4a73ee387d91128ae0d98bf51ef3a -dist/2025-04-02/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=faccf22845e31101a420796d9065b350092cbee29d755c2369ee36cc7172866f -dist/2025-04-02/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=f296c5726380b1f2b8603a079e8dfdfa7e4a97a499b1e86874753c312768ab15 -dist/2025-04-02/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=b8a8fd8fda8b99d96d6f890bcd0c9073393441e85a4cda169b6fc7dbb7296984 -dist/2025-04-02/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=923a0530224f0631162f7b86bef79be85f45071f62ca4f5de0588fb5ca6affa8 -dist/2025-04-02/rust-std-beta-sparcv9-sun-solaris.tar.gz=944a83365d3c46313e28b1d3a5b0e52e57ce88b3eaaf0f7f53234d4423ce9ca7 -dist/2025-04-02/rust-std-beta-sparcv9-sun-solaris.tar.xz=be0c983c443f05feb4614d97336755894b3ffc5083d852bd84ee7cd9e5edfa03 -dist/2025-04-02/rust-std-beta-thumbv6m-none-eabi.tar.gz=08905a766352dd259be919aeb366e965dbbd4066c398dc4d26efa333b0ac46b8 -dist/2025-04-02/rust-std-beta-thumbv6m-none-eabi.tar.xz=4fa005107c3d1addb242179c03a804a27d34ca68bd76c092a41a197da56abce1 -dist/2025-04-02/rust-std-beta-thumbv7em-none-eabi.tar.gz=e6ccc1004004ed759b1814daae0b50a3a0adca9786688ef9cc601a0a19edc72a -dist/2025-04-02/rust-std-beta-thumbv7em-none-eabi.tar.xz=fc23abf9c086a34264bfcfe7c4876ec65ce54f8ca73a98020bb8eab6d2c51d57 -dist/2025-04-02/rust-std-beta-thumbv7em-none-eabihf.tar.gz=e8121551c0529f73796bc157bf916e3608685454a02a81d170a258a7465b5b7c -dist/2025-04-02/rust-std-beta-thumbv7em-none-eabihf.tar.xz=2695f76447ff5d70aa3cc6b6690267b31b9aa4ddc7c45205e529f92d234483a0 -dist/2025-04-02/rust-std-beta-thumbv7m-none-eabi.tar.gz=36d7fb4edd572c7d73501aab7c89737ee0036d606700c728f430142e91649eb0 -dist/2025-04-02/rust-std-beta-thumbv7m-none-eabi.tar.xz=a6e59eaed0ab3e310852d9a75fc43600c7c2eee0c808224b87bcb8c18df4ada6 -dist/2025-04-02/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=6bc70be43929b77f3508b1872e5b09227aebce1c7c9c943995b5df92cf6d9181 -dist/2025-04-02/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=37b956924534aed1ae7ef9908d38bf724c6903591269136d23e293e17a0d333f -dist/2025-04-02/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=041562edada0caeea67fe7f3ffb5b9f8c1b506c0d5ee7b657c5ee2afbefba7fa -dist/2025-04-02/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=8980372a7e9a072b1e0b954569e59df260583a3371daf005c5a83576688562d1 -dist/2025-04-02/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=83f461ac0ebcc05d5cbf67a6585b49dc7b245c8788dc3a75e08a93be41e2615f -dist/2025-04-02/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=6ac8847ce601c8dfeffff07915de06a605b3c685f81b90f87b092897c2afb973 -dist/2025-04-02/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=bfcd9ff7dc9bb5e95bd563d750240efcbc3bfa1a21a9f9a2786ef37f665b7e43 -dist/2025-04-02/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=4507383395a26d41abd71041b162dfc5e9471a4c624d9fd6ad310e184ef15d01 -dist/2025-04-02/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=b4d1940ea5e24cd6a0ba3906c98d2b03e4a18927619152b43e91832733316258 -dist/2025-04-02/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=45eec7770344beb84cf418cf7818216d123136465785f4742127f6f5a8c5ce27 -dist/2025-04-02/rust-std-beta-wasm32-unknown-emscripten.tar.gz=19bf2f4bf64f874ccfd84b820b7200e83e896c96a396edd7bd10301d2bc89d98 -dist/2025-04-02/rust-std-beta-wasm32-unknown-emscripten.tar.xz=4c616b7bd972c09461f0bccf5009bc574dcfa8bdce2dd97d17fcffd64542e496 -dist/2025-04-02/rust-std-beta-wasm32-unknown-unknown.tar.gz=69bcb61fd0f8bd7d2da225a4525a877cce003afd7fc3d789c385f164959cd41a -dist/2025-04-02/rust-std-beta-wasm32-unknown-unknown.tar.xz=0372a64eda0c7249ce5fbcbbbf29e145e969b383a73b7c470f0b583720fcdbe2 -dist/2025-04-02/rust-std-beta-wasm32-wasip1.tar.gz=f76a2a3f4702eb781a680ebd4346afb4c26ca2235e62bad144b057860c09b8a8 -dist/2025-04-02/rust-std-beta-wasm32-wasip1.tar.xz=173bc3317b59a01036a9c8e0bccc570fd6f5174d15f94634f53d81dec3d2cd68 -dist/2025-04-02/rust-std-beta-wasm32-wasip1-threads.tar.gz=18e05380478ed0b3f76d9062fade2be2e66c039dcc470ffb01be3c8dffc79995 -dist/2025-04-02/rust-std-beta-wasm32-wasip1-threads.tar.xz=3d477eb85308f73d1081d6dd3e54577be4bd84f291a50af0e3be15fa8aa36db6 -dist/2025-04-02/rust-std-beta-wasm32-wasip2.tar.gz=3444883960a9f8b831d1f26ee17ef082a2029cdc2e9b45ce5af4d6565d3a526e -dist/2025-04-02/rust-std-beta-wasm32-wasip2.tar.xz=867361c7ba912b404c426807a60625a1f830707a172f7da139c1a892aa85bf35 -dist/2025-04-02/rust-std-beta-wasm32v1-none.tar.gz=d15017a323c662a1e8c65f51e66151138c2255cd8842a67e990000606dac839f -dist/2025-04-02/rust-std-beta-wasm32v1-none.tar.xz=f3b32484ef287317187ca0bd5245b1793ae40d50290a2882419da8503b8243f3 -dist/2025-04-02/rust-std-beta-x86_64-apple-darwin.tar.gz=179be6a29fcf16b4c18775208569a051f2f5a38558e751d2dda0a42027868843 -dist/2025-04-02/rust-std-beta-x86_64-apple-darwin.tar.xz=912f7f8d7117a5cac85dffee5ffd9f2c1cf237477bb0f9e1127afff1f0cd4757 -dist/2025-04-02/rust-std-beta-x86_64-apple-ios.tar.gz=9d2f3230bd82ba9d45e572b45ec63c63cfb592dba6311b6a16de075f18c86999 -dist/2025-04-02/rust-std-beta-x86_64-apple-ios.tar.xz=c8ff77db2d081444ab5167764465beb33046cc81cf2e8dbbd8e9a7328306762c -dist/2025-04-02/rust-std-beta-x86_64-apple-ios-macabi.tar.gz=76c9b2ae710fed611a2294a5e4bb6597b07d78f0bbd3a5a0d15c3320f38a0017 -dist/2025-04-02/rust-std-beta-x86_64-apple-ios-macabi.tar.xz=b9c485a3824c971a42c10af26cf06c539c34fa429e92601a1978280867029e62 -dist/2025-04-02/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=a223c08b88c768d97bf9f071c74d9548acf00bbb097b8c8427c2ec87ca205597 -dist/2025-04-02/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=34ddb3db8a71edabb4d0fd8d52a164dbca5a5cd96d6ba131e7d439c333726f78 -dist/2025-04-02/rust-std-beta-x86_64-linux-android.tar.gz=9ba28bf95c75ca0d69461d1c044902443053b64678b540967a97c7cd2eb7cc4c -dist/2025-04-02/rust-std-beta-x86_64-linux-android.tar.xz=09e35188a801371a55abeb9e2ee455ebd26d41b8eb561b8016ecacfc7ba20c90 -dist/2025-04-02/rust-std-beta-x86_64-pc-solaris.tar.gz=c1f2fb4b90cf258dfa1a52167ba925b583dc889ec1c3c48958560ff3b7b79b13 -dist/2025-04-02/rust-std-beta-x86_64-pc-solaris.tar.xz=d71f2bade21f751d9592e865ce3722b5d3b9abc49e55ca9d04c02d658360b6ad -dist/2025-04-02/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=691c23504582e6db1cf883f52b5378aad3c42da7e2d2237e54601be9c8d16cac -dist/2025-04-02/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=22e7327c5ba22863cb62cc5331862b8c2b4b10a732637729b5e1504034aa2cf1 -dist/2025-04-02/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=81b7dda817a7dbc8b33542c356e0c5e5605b7c60a2fee13f4a266c8d970a3f54 -dist/2025-04-02/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=09e4c9804f7489b337ccf66426e18e7522dcba24234b289a39eb63c8242353d0 -dist/2025-04-02/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=a8188567321462309fb63af38f652c6a7448ebaae1425b9ec20d2fe2a12e8896 -dist/2025-04-02/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=5284f85dce61b2b021888b6b82995aa7b4a14a979b42b83499a810c261fc183e -dist/2025-04-02/rust-std-beta-x86_64-unknown-freebsd.tar.gz=eb57c8ca7f515386d60a88e56443e377aae70e185ac52a62869e115c636a2bcc -dist/2025-04-02/rust-std-beta-x86_64-unknown-freebsd.tar.xz=8bef59b74196fa9f7839bb491f6b32d0761a45c8d7178980ee3afd80231b836e -dist/2025-04-02/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=f43f402881f4558e3df4a7ace68ba80caa9354cfa5a8b1efac89f95e38386253 -dist/2025-04-02/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=ea7d09c015c057591ff51b808cca9c8c1d973de3a9033fe42c1bf34d748d03a6 -dist/2025-04-02/rust-std-beta-x86_64-unknown-illumos.tar.gz=a4835455348bc5b154b1bba63aa03d2294713589214b50d3babae3e0f9918a3c -dist/2025-04-02/rust-std-beta-x86_64-unknown-illumos.tar.xz=711920e7491332251fb672abdc7685fa940f863d8e182e2ae9d9347d7fa6a725 -dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=1b8324839c0e10e410f29bd471f6c49eb4710adbe172d6bef3e619ae95d47d02 -dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=223b41f16a80b9c404f5af9a194b7414ef354681f911839353f24b44eed91494 -dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=6d8d8d9fd6336de0ebcb58fa85aa0d11e62a60d6c6ca01d71da0bdf668d216c1 -dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=033df93011b4461cde64c4230c495bad1523b9b38f5b0de56dd928c1da85b577 -dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=70a441c0cf8ca25abc1f722c1db5dde8b5fd3b90c767895b7518fc58c2678390 -dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=b5584d6d0031f8230a40f5ed76570ab1396c8997c3e957ca159d72a5dc201a2d -dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=2596cdc3708d82aa93a8a1f595238fe9fd7b5b05a4886e7e390ca3b86d352e7e -dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=c03901c0c8434b5db244c22145870e7d933b9060af3b23f24a765c755098a3a1 -dist/2025-04-02/rust-std-beta-x86_64-unknown-netbsd.tar.gz=82bc22594dc602b27edf8233bd9c4fbf0323999ce99ff2a7ddd0ce9268647eb1 -dist/2025-04-02/rust-std-beta-x86_64-unknown-netbsd.tar.xz=86f674f5e19a1b1780f06a6d5add06fd4240430233b7c3f5203a4daa5f444673 -dist/2025-04-02/rust-std-beta-x86_64-unknown-none.tar.gz=ca7882354f4274dc405034aa6edbda685b9d76bc6e5905074d2aaf8c35b35a95 -dist/2025-04-02/rust-std-beta-x86_64-unknown-none.tar.xz=ed6c828fdafcf87a68f522379f11c44eff1a4be1bf027d9888d1f17f22e9ca61 -dist/2025-04-02/rust-std-beta-x86_64-unknown-redox.tar.gz=6f8ab182274e2f5b0fa82fdc5c6e3776ba969e6ee6f6098ce6d170f6685f55c2 -dist/2025-04-02/rust-std-beta-x86_64-unknown-redox.tar.xz=ee061d725f657a2e52114f282be0cab1a6e542a0270b11782c36e8737ed84f32 -dist/2025-04-02/rust-std-beta-x86_64-unknown-uefi.tar.gz=0324f537f463738bbdbf40b92423df6c6068f76c583872d6070d6a41c5169dac -dist/2025-04-02/rust-std-beta-x86_64-unknown-uefi.tar.xz=2cd2727f71b14c06eb0a14fa532e5b3bc66f8b983c021f3201c327606b04511e -dist/2025-04-02/cargo-beta-aarch64-apple-darwin.tar.gz=76010b5a9f8dff0102a18de75e818c51b915a3bcff428fc48973728577c2ecd3 -dist/2025-04-02/cargo-beta-aarch64-apple-darwin.tar.xz=f0f03ece675cfaa9dd0f00204d7ddd4086a45357f09cac9d800d37bef8d0db33 -dist/2025-04-02/cargo-beta-aarch64-pc-windows-msvc.tar.gz=bf4ab12afcea7911ab973177de83b7bbdfd0000e3090331f31a595d57819ed6d -dist/2025-04-02/cargo-beta-aarch64-pc-windows-msvc.tar.xz=156fc94166e5f2af91fd9a36c67b545c0eff63dad51fcd81571cce01447c1c1b -dist/2025-04-02/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=c86bbf8091188ab9f7d41e566ef628a657d66683884333c3851e99edaea6e279 -dist/2025-04-02/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=610383a4efb93ab53cc747ba038888742346499407c982b7bc8c0c41689cf453 -dist/2025-04-02/cargo-beta-aarch64-unknown-linux-musl.tar.gz=7d427779360c9cba5903c2a0183be1c1759cb2c2f2b77bd2f64b409821fabb64 -dist/2025-04-02/cargo-beta-aarch64-unknown-linux-musl.tar.xz=29bda8bd7dcee65315b8c14a527f4e4b4dd678b35dd430591f7c71712ecbd2f9 -dist/2025-04-02/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=ef6d6a810eecb3a38940634b653257070dcfcff52c2d8321fa3a933d41c7ed73 -dist/2025-04-02/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=79796d83949811776aaedc7e6db6d32374c07b8f8d256d9b871de335bf5e7074 -dist/2025-04-02/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=fa93a1285a97453e2aaaf9cf392abb4ff9a419451e925959470166522e54b1dc -dist/2025-04-02/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=acb69df00475904faccf18729030a70e8ce21543189d48c7102330a98a12edf1 -dist/2025-04-02/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=7141bf32c173d26f34571b2dfb890187d866f113e28b63908841377e48dbc6ab -dist/2025-04-02/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=249f3c535805fb2510d13338401e9ae96f16e6996e58551025b35676a1147ab5 -dist/2025-04-02/cargo-beta-i686-pc-windows-gnu.tar.gz=fe4f5f35ecac25bc3726ffecbe3e650d51adb9ea13dc5153a0699ea8d8776d13 -dist/2025-04-02/cargo-beta-i686-pc-windows-gnu.tar.xz=b7b8432464eb793e9a651c4c38ee8abe76421a9be7f75e96237a4ef938f927f9 -dist/2025-04-02/cargo-beta-i686-pc-windows-msvc.tar.gz=a283da65d3a75435ff3d05441fd0337472fd16325531086e90b01cc5d5bd221a -dist/2025-04-02/cargo-beta-i686-pc-windows-msvc.tar.xz=ae19f98c901228ae5c7573cebde4816517bdb8d03dbdc7b92d95518d27d93531 -dist/2025-04-02/cargo-beta-i686-unknown-linux-gnu.tar.gz=e3c5b2560f64c8056ef82ed0cd659d35fda5181f19fa670b962228142398efbc -dist/2025-04-02/cargo-beta-i686-unknown-linux-gnu.tar.xz=3fc435b8a186f6ec1b7ebc38c92c2e23e1bd786415fc33e7743ef95c37c69b45 -dist/2025-04-02/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=bcab46663be61e979b7a89792d164e182d5482ad9b444a969dbb304c5dad8c8c -dist/2025-04-02/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=9e2ecb90d85a4aca95211892a6a41fde09ce1e4f44a60caab9aeb61833191d36 -dist/2025-04-02/cargo-beta-loongarch64-unknown-linux-musl.tar.gz=3c5c40f61e85663d03fe51f63d505d8dca73f94bfb3eed29f6e1396b31e0a554 -dist/2025-04-02/cargo-beta-loongarch64-unknown-linux-musl.tar.xz=775c56ce638e0923758ab5f82a87c15b7a1500d10e0be2433af40364a0455d58 -dist/2025-04-02/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=c1a144dc83b673e0375e8f718cde6672ca276dbab9161d7f3e002c6273352c1b -dist/2025-04-02/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=1b41b3396340c97c122661c95fe54265036e721f1750bad3a8fe4920f6f52b34 -dist/2025-04-02/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=2a43a7682ea3da8b911b09a7bb4a3a75fc3facb64fc952e51ff35c63e6630b75 -dist/2025-04-02/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=73a3383196527e63716de1b1cab233226519873556a755a7e47279f799936116 -dist/2025-04-02/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=d5f521839bd4b258454097cf97b056508e6f9103f7312c93b632ae44ac9f7dc0 -dist/2025-04-02/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=c4fc5ff91bc1054e8497efa53ee6a9a9eb7f06927cd314a681e16b6d46b08440 -dist/2025-04-02/cargo-beta-powerpc64le-unknown-linux-musl.tar.gz=5b0d569fe4ec84d6e7526af9d9794b440e8f1b5fc1b09e951678b09fd3ff97fb -dist/2025-04-02/cargo-beta-powerpc64le-unknown-linux-musl.tar.xz=e9c68eee5763c624cbe312bc1b50b6c3172eb7997e209371692e7f897d13b03b -dist/2025-04-02/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=96962461e7f6744a46f18a557a4701d35d6fa3b6d960d854f4c3effe6f2636f8 -dist/2025-04-02/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=4d6029204f930543afeeaf44d9e635692c86c9daaaac6301cccbe076c7facbe5 -dist/2025-04-02/cargo-beta-s390x-unknown-linux-gnu.tar.gz=f40421ea02804c3089420e5ca13838f94fb89c114de9a9e596e9a1207d2166d7 -dist/2025-04-02/cargo-beta-s390x-unknown-linux-gnu.tar.xz=77521eb215cded6886267644661b3357590f20368383f314da8f310197e9679e -dist/2025-04-02/cargo-beta-x86_64-apple-darwin.tar.gz=0357ed5c9c8ccbe71f89695bffe1604dbd2f451472fc6ea8d8d2dfc93a703b30 -dist/2025-04-02/cargo-beta-x86_64-apple-darwin.tar.xz=6ce4f66b60609f58046138831ae3828ad1d58f8d0b2f515f153c96b690a0134f -dist/2025-04-02/cargo-beta-x86_64-pc-windows-gnu.tar.gz=8fbf8506fc0c47bb30043c026107c51d6b548fa91320b5bbd2c608e191bdc007 -dist/2025-04-02/cargo-beta-x86_64-pc-windows-gnu.tar.xz=bb57df35e6d73b0b0bba58801d66febfed03f0b3f74085eb50ef8b5ea3fdbb40 -dist/2025-04-02/cargo-beta-x86_64-pc-windows-msvc.tar.gz=0bec5e9059c4b3035f636017c1586653d372f03969bcd4d80c0eaee52f01a2ac -dist/2025-04-02/cargo-beta-x86_64-pc-windows-msvc.tar.xz=3f836d3027d7ed25655f43262b126311bf014629dadc4a860f00302bc468e752 -dist/2025-04-02/cargo-beta-x86_64-unknown-freebsd.tar.gz=0f60566416471c38350c12f066bb512eca65a66319f5ee7fdbb60464d70661fa -dist/2025-04-02/cargo-beta-x86_64-unknown-freebsd.tar.xz=eae168df54ddfe95db669c205ae97baa902056722856fa174758ebd058168a95 -dist/2025-04-02/cargo-beta-x86_64-unknown-illumos.tar.gz=816eb91ac3858043f58075fc48fc2e90d0427c58b6283be589d337a7f0ddc9df -dist/2025-04-02/cargo-beta-x86_64-unknown-illumos.tar.xz=faba548d376309b71bcdae49f7089705be951f72a84ef68362aa6d865d40ebf9 -dist/2025-04-02/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=1fe7e9d2c5a733acdaed418011c1fc31c3036e5299e8f9288ddeac43780fa35e -dist/2025-04-02/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=7a39bd08e46d3e19da81c02ea3bb46bd1750a3ac1d1db8fb5db852cde14cdd72 -dist/2025-04-02/cargo-beta-x86_64-unknown-linux-musl.tar.gz=00df62b75e1811fd4fcc827b531e7ad94a73fcc37318d0aed28796d902b33568 -dist/2025-04-02/cargo-beta-x86_64-unknown-linux-musl.tar.xz=874084ab37814ddf50ef423e22f0721e5c24acd953ed02cf83432d2372606a5f -dist/2025-04-02/cargo-beta-x86_64-unknown-netbsd.tar.gz=7b4467e398bd34f94912c56863ae83b45415bbf612b3be15624a6a410c27ff2a -dist/2025-04-02/cargo-beta-x86_64-unknown-netbsd.tar.xz=75e7ac498a8e617bb907c26f2a3bba9a1e9a22af1c0946f88c7bd53c28790ffb -dist/2025-04-02/clippy-beta-aarch64-apple-darwin.tar.gz=0f5a8a6a96b8785beae1fc9476374d060632dcc4c17a4335031425ee8e2dec48 -dist/2025-04-02/clippy-beta-aarch64-apple-darwin.tar.xz=aed266be1799ae3e95099d491c3b20b731b2094bc8388c6ac3e782667b58ca6f -dist/2025-04-02/clippy-beta-aarch64-pc-windows-msvc.tar.gz=0ca97501432918d43aa9bed9b58cd4f1d0d738970e09d6c037ce967519b2b13f -dist/2025-04-02/clippy-beta-aarch64-pc-windows-msvc.tar.xz=c64edd87358c1ecb9e01b204977edaf0307cc939a3dd3ae62f151c153ac2019b -dist/2025-04-02/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=7bfdd371ed44a32e50ecd6baf107796d5a77ca3cce0bd58bc5882afd98ca0edf -dist/2025-04-02/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=cf49acab8153fb65867a9c44eabb7f156f85e9818b6f49453067ce0764036919 -dist/2025-04-02/clippy-beta-aarch64-unknown-linux-musl.tar.gz=bfb20f832ba30a4840f0d4898d27cf69b5717a78bd71b20270f8ddd66c48bc69 -dist/2025-04-02/clippy-beta-aarch64-unknown-linux-musl.tar.xz=54081690d35c39267a49d991e5e0c16043261b6969c49f23c2be44e46c3bfcdf -dist/2025-04-02/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=3d88b69d6c67c58b09be9d679cfbe8ee449b9de419e950edcffd4637ded46cac -dist/2025-04-02/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=67843ea0aeaab167029818669074e8bdc46a7e1c269a15580cdfe44a7d2ba96b -dist/2025-04-02/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=46e9efe50418a035ddabf9a6467b6b0ef20453816c4b6dfd46fa1342bdc42167 -dist/2025-04-02/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=3b27dc434e88280bbc89f5c5ba6eb68ec5332b549b73f7f8d79feda9cbb49628 -dist/2025-04-02/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=670a6ce01ee6e5225b152a1357eba9a41cb47f04d08cdc8a0828eded4132aba1 -dist/2025-04-02/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=cf92bed8c784e9579c09305fd227df3992950c227bc844a9b09995828d62e2cc -dist/2025-04-02/clippy-beta-i686-pc-windows-gnu.tar.gz=58238b6f4f8ad957a39c0eb63b45007d1c3f8c79e98307c7e5a531b7309a30f4 -dist/2025-04-02/clippy-beta-i686-pc-windows-gnu.tar.xz=e77c5215b3e96c59fa150330cb5144db66dac377fdad3be9c28f9fa07d9fb7cc -dist/2025-04-02/clippy-beta-i686-pc-windows-msvc.tar.gz=7c65df8af1f6f4102ffbd7fdaec50c24f89f2631edd06642732f1b5c74558ab4 -dist/2025-04-02/clippy-beta-i686-pc-windows-msvc.tar.xz=eeb119d26e1e2ddd3ef72741158d75d0db254f6420fd729d34abe5d172c7d765 -dist/2025-04-02/clippy-beta-i686-unknown-linux-gnu.tar.gz=c43518b27adce17f06f89c70ab52ae4c94f1f7129a182c16f9bb28fbc8a5f40b -dist/2025-04-02/clippy-beta-i686-unknown-linux-gnu.tar.xz=1d972c55d89cc01b7e408b4e24e8975bca29ff28578f224024a00f00d17c28b8 -dist/2025-04-02/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=0d779bd9fcc5ed8e1db81a3a385bc0158c3903e5b0f0e4c99d172eee106a4f3e -dist/2025-04-02/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=5515e0678c081ddae45f3f0c3c7ae58cc2f7b1141e1557a39826bf1aa58a2480 -dist/2025-04-02/clippy-beta-loongarch64-unknown-linux-musl.tar.gz=e99599c1fd0cab2eb0e89dd8e37e90ee2106d602a3edb3473fd65768bb8f7b27 -dist/2025-04-02/clippy-beta-loongarch64-unknown-linux-musl.tar.xz=f346a801dee3734461eab4303469d31faaf3e8f0d733b854470722ed48c66276 -dist/2025-04-02/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=cd7b58e507d6695ada446ef9fa113a9588501832f4627b3e7cc0000a77c9265f -dist/2025-04-02/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=0a7073874663b4ce8eb47a0257ac0cf8049acb34703241466f1208489c4dbee0 -dist/2025-04-02/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=78d0b9581a7d79549bbb6a7e8984bf923a7b80bf6bb3979a90e90ceed8e66d33 -dist/2025-04-02/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=79069a26ed617a2a07eef7cf098d028cb0c172fc4a6dc99115a51862b1b8bea8 -dist/2025-04-02/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=23c58421839105c88937ad90a92603b7fcd6d9e21f291ab8c419fce1663a20a5 -dist/2025-04-02/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=b546706d28c46f5bd3799d6b42201962ec2e9d6baf8df2b66cfcf1bc42789036 -dist/2025-04-02/clippy-beta-powerpc64le-unknown-linux-musl.tar.gz=31cf0d973eb3f0ca341a8d64c26b8b3b045b44b3c00d2497893dac6e44ebdeb4 -dist/2025-04-02/clippy-beta-powerpc64le-unknown-linux-musl.tar.xz=8afd89866c41631d4f4ac4d8a06d943473af7a96b043f6112216a04863817820 -dist/2025-04-02/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=f08bf4ed1519e7c47f354a0d0b750933342314bacd4be761746666cf455cf74b -dist/2025-04-02/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=e502f83f811c35e43df0a5e158d9eb61f60c9e1aacc75b588b2ba85022ca4b3e -dist/2025-04-02/clippy-beta-s390x-unknown-linux-gnu.tar.gz=21bede57083544028238ef6c9d24cbf9194a35c88500f2d0c5d50e6f0ae79616 -dist/2025-04-02/clippy-beta-s390x-unknown-linux-gnu.tar.xz=670c0a293e1b01f331c2645b648c1df087da4c1b5d689f608279b1ba524cbaef -dist/2025-04-02/clippy-beta-x86_64-apple-darwin.tar.gz=a6552e032c047203d5a9f5b767945c7a556be35468c42631c0c84cd049e24a8a -dist/2025-04-02/clippy-beta-x86_64-apple-darwin.tar.xz=17a9e9ea8e0d6140080b7fa4e3c77ad1a7fde3c3179f26b0aabe34c3af73b58a -dist/2025-04-02/clippy-beta-x86_64-pc-windows-gnu.tar.gz=2ffa8663502f4c6bba049318c70e79c174fd717d45ab4427103fc11563be678f -dist/2025-04-02/clippy-beta-x86_64-pc-windows-gnu.tar.xz=8c0a71f226b229f30a9acfbc1ab7c6bbedf692ef7b26737721a0518d3f1972ab -dist/2025-04-02/clippy-beta-x86_64-pc-windows-msvc.tar.gz=463c7a5d2a11beaeb1e63bc769db89fb9996a0558da15b4e091befe982893711 -dist/2025-04-02/clippy-beta-x86_64-pc-windows-msvc.tar.xz=40241fa6e463df734096e0e910b414c83d8a4dc8706b7c712cc170844e59e3c6 -dist/2025-04-02/clippy-beta-x86_64-unknown-freebsd.tar.gz=6464044b05b326d8ea594a963e38a52a1e27e0f028704427c41ec5e93e3772d9 -dist/2025-04-02/clippy-beta-x86_64-unknown-freebsd.tar.xz=77cdeb1e838c3da1d01252481f7c06149b0b8e7df48c2a2ee5961f4550d7b662 -dist/2025-04-02/clippy-beta-x86_64-unknown-illumos.tar.gz=d51238e1ad2329b9309e94b40f3374788e2fda9bf47466841a841392835e8a5e -dist/2025-04-02/clippy-beta-x86_64-unknown-illumos.tar.xz=6ad33945045790946fae843f63a805e60c09157e106ff342d3b99a201cd221e1 -dist/2025-04-02/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=64b4f85d9eb75172928b46540090128ce9eec00e275d9027f74d0d5d4106bd76 -dist/2025-04-02/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=b090383b4ebeae96fb340f0a363ee0276eb1f17a4f2a0f2ed81aff039f21bf78 -dist/2025-04-02/clippy-beta-x86_64-unknown-linux-musl.tar.gz=8d8025922c563bb1c872111722a4de298a8f85cd5be3e4cf753d44d6b8304de6 -dist/2025-04-02/clippy-beta-x86_64-unknown-linux-musl.tar.xz=ecf15ae9eb7dafe97afd69133f13364dac09d5e6edc35ddab91fb4ac32e17d42 -dist/2025-04-02/clippy-beta-x86_64-unknown-netbsd.tar.gz=c802af6a6f454b771046bd4a5207bdbe538cb6827becc9174dc229de5f874426 -dist/2025-04-02/clippy-beta-x86_64-unknown-netbsd.tar.xz=03d1e16eaf6f83f80e4cef8c7beebee97498135dd3138b97f97186b545edfb86 -dist/2025-04-02/rustfmt-nightly-aarch64-apple-darwin.tar.gz=c02047132bc7b48bbe930dfddb3afd31349eb042cb101a19d6e4360ea6e586ad -dist/2025-04-02/rustfmt-nightly-aarch64-apple-darwin.tar.xz=cf825dfaeb4d97eb2819ff8e46360192f480960f6b516e328ef8a9493d413a9f -dist/2025-04-02/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=588551cbfb62eb4ed4e5755fe6eb3e1499a79e24a8a75f448b10d9a2237c63db -dist/2025-04-02/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=df666f179fcfccb316aeb1a5eb4c17710b23198176edb34ba8b98c88cb369098 -dist/2025-04-02/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=b06f4aefa01300ef1827a29c9fcd2e4da0c13f3aad92b4c929f6e8811d53ab71 -dist/2025-04-02/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=059a888b8db76f5a3054a9a78a131d79c49060deaf70b2e2f03a4fcab44ab536 -dist/2025-04-02/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=f0117a7be9eefe70fbd2f0d3fc05c51f3a97d069dc99500520a5d0973178fc6a -dist/2025-04-02/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=f2fa87f1e814d0fb163146cf6a47d9375fec2c3778f76c33988acaa1665dacf7 -dist/2025-04-02/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=fa53d4a6fb2ee3e1607d825afcc05063c0fa0dda1a3ede9a57e1ccc72cece8c4 -dist/2025-04-02/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=3d785d982878f9bda4778cca0f9365947665849d5f7d2ee4794d8c28df3ab8c8 -dist/2025-04-02/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=affb343357cd4c677cdeaf3b24698f20cfa15062cb63257aaa9bca3bd7baeeae -dist/2025-04-02/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=6eb95c2021571a0c1ad3e3edf58fa4daa7711a9085e2ab61bc75799252183358 -dist/2025-04-02/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=1dffc39afb9210c77e6d45b68cb801247f00afdf33107963c82a83bd94d2225e -dist/2025-04-02/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=2da28dd8ec76744a7629619f527196689eb35e9bc60f3a5965ed69486e44235d -dist/2025-04-02/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=5b1b39125106cdcbf12be9d5786900852f54eaa1429cabf28eeb68f96a008f90 -dist/2025-04-02/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=3f2ecb3787c82a8dae89929aca4f2f3af790f1ab3c698adf21dde21c919a4052 -dist/2025-04-02/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=eeb8b3f10f1cd75fac4e9e13dd1aee5941f38f1ff7fcfcaa69fcc3a42ea7c49a -dist/2025-04-02/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=afd81cfd8d5fb37427c7eb2a1429c3b06d8daa1f42002c7230718fc56e132c47 -dist/2025-04-02/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=5eb0f065a5403645ebb6c01d7f27a763f9446b8a48db5b6ff962b6f7c0f3ea3b -dist/2025-04-02/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=3576e2e8ecc563cfbc4b3f464d80f8e27f412b5eb267656dc5f0316a11a2d299 -dist/2025-04-02/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=5e69db53a1161ad7616f9e50d1a7fef785840bdf0ba81757d0b6811078692921 -dist/2025-04-02/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=ba9d18dd2d63bad1e2863c9e14bbc4bd282d03cb806d03011d2d61ce701d934f -dist/2025-04-02/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.gz=b112f8c2e6ec011382c02a40ca07f30e1885a1396a7f2c30f099e56d756f2f54 -dist/2025-04-02/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.xz=42af68aa0b77306187d13ef881ee4327856f505a8a518f46244ffb17037f7e4e -dist/2025-04-02/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=ed4277c9c8a27fdb97911bb9fbb46385b5fd807ac9338d31eecc3240bb0bc5c2 -dist/2025-04-02/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=4cf3a7a64edd09b5d8ad72af545c15013842072e70789d1741f845f27c60566d -dist/2025-04-02/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=65d49556ac1abd1da9cb7c41e518f85213ee2b1f05559c917614937d4c0cada9 -dist/2025-04-02/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=535ea938d888ea12c139740e5d25ac4b82135b3274b8d86c3c59e36928922ec6 -dist/2025-04-02/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=9776e0c641ae8a229453fe1fbdaaae05ea0caf37bb4893a00fe86e5d63d1241a -dist/2025-04-02/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=bf73cfd35802b2706d0db96c854e8a4c45398297a59aef92226ac28d8bb69417 -dist/2025-04-02/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.gz=307012d0741898b3a2840ba3535832943ab6127f27323e587e1918b2023b37a2 -dist/2025-04-02/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.xz=79912529a393cb77c604f5a16d5b22611e938971656efd57fc5ef1980ffad35a -dist/2025-04-02/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=854280cb3eeac146196ba30c8f3a010d568bf5bf9613d1870bd052a2aa3a03c0 -dist/2025-04-02/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=36e6cfc2b333cf077e3e1bf651acab4e6845330fa151848926d7b33fafa016f3 -dist/2025-04-02/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=19409bf4daa2e4d76c99659d7348f9a7dd4eb640c8bc81d93dc9170a1e51b7ba -dist/2025-04-02/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=999346ff469e15507ec43c0b265a94b98ee99a0096d68ea0307a2280d138838f -dist/2025-04-02/rustfmt-nightly-x86_64-apple-darwin.tar.gz=6a52a943d59edb9e6ed97643b01a2ca2f51abb6fba1b4c9b73f59646372aac01 -dist/2025-04-02/rustfmt-nightly-x86_64-apple-darwin.tar.xz=3701a72b39a31e31c9fe65afa660a507088dfe6039867a2019bfb69970872bad -dist/2025-04-02/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=c0dbe39a6dc72d96446312584055cfd75a4304c4859016ec7590d52813f0736c -dist/2025-04-02/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=f9e8814cf2e0241bbe40bfafc62bb961d87060dd94c84fba8ea00b2992eafe2a -dist/2025-04-02/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=b9a2c923b6794b3462882a9f5b1579e2463024a72ff34cdf4bdfd8b0f51ee528 -dist/2025-04-02/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=c5e8272c451a3d685842e07a996e8bdc305ccb02a02d39f7f4cc764be4b2adce -dist/2025-04-02/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=d47cb1e290f09795a04652f33afba39f80f3b6dcc4b570c14c75b1d945c78f0a -dist/2025-04-02/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=389ea9f755623dd3d887bbff71189f86d7397c82e2f8fe660c27784cf7c68a94 -dist/2025-04-02/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=b49f6c211c51a50309ddd2bcb4c886ebeef47e5413e6399778157bc90a37ed0e -dist/2025-04-02/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=d53f55b6dba14bb2e2f90510c3e432781a8aad1f871d8f38795edf866ed4a4f3 -dist/2025-04-02/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=2b8d77937298b23522ab9bd2f64a829f6faf1dccb87033f6006aa8c324474b47 -dist/2025-04-02/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=0579d2a7c17cd585c49a42efe062466db777c1e7890f21b319234ee81c86ea39 -dist/2025-04-02/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=65bc50db8fbe283e876b9ae7d6c15ff0461c1db8b3327f2992a99d21bcc3266c -dist/2025-04-02/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=120505da1a8cddfb3f549438a52b2c73c76a9f1c2f25709db13d61efd214d732 -dist/2025-04-02/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=d19004b3f6b9fa446e23f540b21a8f314d3bbcca11f753c9a6fdaf4c7ae7a2de -dist/2025-04-02/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=e7facb66daed07789015c2d5b092afde5dbb1349d06cd0f80ae8319437587723 -dist/2025-04-02/rustc-nightly-aarch64-apple-darwin.tar.gz=3783e0aa4450a6bb913fc9a9799950892e65c7af9a2c895419090072999a2305 -dist/2025-04-02/rustc-nightly-aarch64-apple-darwin.tar.xz=4d3a72db4cfcd7663803f1a0b193326e37c7faecc0c97c3903a17fbc0f7c8848 -dist/2025-04-02/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=c253308683fd394b1287a4eb9ca00cb8557bd7f7f91af8b087adccf9153a94eb -dist/2025-04-02/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=63c30a1e523266dd6f8d6bb1525484f51fc6462bd7946900e0590b219f2a8b47 -dist/2025-04-02/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=74d2313a732fc8401d62b9a8610bd9a25502f0372921c0e99d9d20f0cf8e3b19 -dist/2025-04-02/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=a96db92f8c7cebe6e0d140a1853ecaa038e04975d62f17950e141d8ac2452536 -dist/2025-04-02/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=250e2c21af9d4b284c7455668ebcc3d1e408c20cda1abf0ee69acac4c873e5ed -dist/2025-04-02/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=931714cf51d93fee5cc9465e9a0e9d34c771fe2aaae46994f3b00da4c95a8f54 -dist/2025-04-02/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=28f993889175ba3feb78b458be5282b2564a7c9b96117fed071835ff7b47f43f -dist/2025-04-02/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=8645d1a7510cc13e2cd9abeffa71cbfb5f3a99990d27da2b05c336801a51c7f0 -dist/2025-04-02/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=a86525223d8c5d67b0a92382b6ebce65761cdb83629e11bf29d625d688908d38 -dist/2025-04-02/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=06a57a2c6298bb6e477d1e04922c626142bf96b2072684aecbbbf876bb4296f1 -dist/2025-04-02/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=a7fb3babdc244ea1f025f3033d13088c50696db8d6db29efcc6a78474a06769e -dist/2025-04-02/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=b130a7efa1c2bdfa5ef51237d5233ab6bd8feade7dc596d120b6501b4766a569 -dist/2025-04-02/rustc-nightly-i686-pc-windows-gnu.tar.gz=ebb4dda0d1ced3ec5aa14b1ef38227628db92a87f45b817d4ce41ff026a687ec -dist/2025-04-02/rustc-nightly-i686-pc-windows-gnu.tar.xz=43a69c9382b20249495824c149ffb5b5dae2ff7407c0c431859bc3e1f1ca4a7c -dist/2025-04-02/rustc-nightly-i686-pc-windows-msvc.tar.gz=bf3eb550e148e89e7ff17be5e72ad0462d57f3c452bfdc46b80a1812ec2fe457 -dist/2025-04-02/rustc-nightly-i686-pc-windows-msvc.tar.xz=b2dde774c1ef573c6a889c2d78bbb98f535f22be4b20896797be2f10781f0eb4 -dist/2025-04-02/rustc-nightly-i686-unknown-linux-gnu.tar.gz=96d130960b0dc1d8fa54f53d22a8fa8cf5aa35d0b213071404122e4e714feab0 -dist/2025-04-02/rustc-nightly-i686-unknown-linux-gnu.tar.xz=d743c6126151dd18624382a4228bf90af1239fc7fd97e763009b31666fb860fb -dist/2025-04-02/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=090ec673f24758b8a4d0ce7b8c58fc6015585bd8392e37760283ffbe6045298c -dist/2025-04-02/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=c71ad975a15c440890a7358b5459b7ca6b9d5e1842dd353071467c2a3f841605 -dist/2025-04-02/rustc-nightly-loongarch64-unknown-linux-musl.tar.gz=8806875cee039409632e8baf5433227af04bd07d015329d9512cc4f4879f687c -dist/2025-04-02/rustc-nightly-loongarch64-unknown-linux-musl.tar.xz=cebc3a4f1eb71e86e4e63f78e1c2f86fc98f7d23db1a3cb7e4c4d385e5591d51 -dist/2025-04-02/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=643dc0fe347a78a82321b5f47b41b09025856b6383ef67274ba3324879aae75e -dist/2025-04-02/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=955018b90daf3797497dfc423aec731e8d0320b96dcf42db1705b761e1e0dd58 -dist/2025-04-02/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=aed278e57ffe0eb54328a9536607bc179806e0c2de9fccb9779a4517752899e5 -dist/2025-04-02/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=0b6e0305b13d867c677243b16613f62b07352038f5e7ad7e1865cc2d00168283 -dist/2025-04-02/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=e10d8eee30be690aa2e6ff58ca554d47173086d5df8f0ea8581b3fd10d4cee0a -dist/2025-04-02/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=3ca3c258404dd8718321ed8a50aa6512fea9d810120db225a3fcfe56d7b83064 -dist/2025-04-02/rustc-nightly-powerpc64le-unknown-linux-musl.tar.gz=ddfc329b8932ad796c0eb7618632f9ae0c5ffb7a6093ea7d5cc4185fc0537f22 -dist/2025-04-02/rustc-nightly-powerpc64le-unknown-linux-musl.tar.xz=b4e82b64f2e934e17fc9b270295554a8bf0bd3d38ffffc66b367aad5bee3ad6f -dist/2025-04-02/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=116d290065bd9e8ff2ca57440e94f773f68adf79aedba767159dfb92fe1a42b0 -dist/2025-04-02/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=6e1deb0c47bba4b56bbf1d04344e45f0490938455aee421629f2fcfd309eff64 -dist/2025-04-02/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=445f8a0ca579153b449fa0d36460227af68399c4227be76e4cbb3d65cef9055c -dist/2025-04-02/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=d87bcac173e9800dc1c1b28e668a1b4c3616029d0ca53adfa4ac382733610193 -dist/2025-04-02/rustc-nightly-x86_64-apple-darwin.tar.gz=4342b89aed19f409df56bfac3d6ac071a02cb6839a52d19fdff9d10cc1d9f540 -dist/2025-04-02/rustc-nightly-x86_64-apple-darwin.tar.xz=cb787327895f275e6f9025bb38c6337492c839310931b8c7ba39743813621701 -dist/2025-04-02/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=6cddd0d3cf18780b36776fd0324643a36b3294923531a741cc763516c8238caf -dist/2025-04-02/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=cefc15752bd84b290f50b958b96feb0134d420a10c6f36791424c762cda08abc -dist/2025-04-02/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=731e968787044081453a559a95579435654b47f91a9b7f94579ac007ed3e4cf9 -dist/2025-04-02/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=3d9b173043aed73aa3ab1fa0b14d0ce2149a4943f4bb10aa1e31af619afe0eed -dist/2025-04-02/rustc-nightly-x86_64-unknown-freebsd.tar.gz=c0df2f0a354d2d657d8ec8091bc094060321b343c8e7bb8e4315cfe042dacfc3 -dist/2025-04-02/rustc-nightly-x86_64-unknown-freebsd.tar.xz=8933bc0361484ac7c6b226defaea73eda5c4e10462e7ea54052c7e1d370e48c0 -dist/2025-04-02/rustc-nightly-x86_64-unknown-illumos.tar.gz=5887f913ac80dfe9826619227c66eb234a2b4848e6bc4f41c6fdd8102bf981e9 -dist/2025-04-02/rustc-nightly-x86_64-unknown-illumos.tar.xz=4a54b8b09eba43df0d99fb6e03177cf8ba2214a5810be52ac33ee3d9d33e98bc -dist/2025-04-02/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=1c0bb76acd7944804d52c3139f4dcf154d3221cdeb300bb6b9bca726cd6ad30f -dist/2025-04-02/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=e67a33440c3e021ff2dd41add0fb05db6c0e8ae68bd30d33e8b3185b0bb7191b -dist/2025-04-02/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=0ea7e17d7bb67d6a6c4b2f864aaffcd96512f15f17f0acc63751eb1df6c486a7 -dist/2025-04-02/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=b73d37b704ab58921172cc561f5598db6a504dcd4d7980966f7c26caaf6d3594 -dist/2025-04-02/rustc-nightly-x86_64-unknown-netbsd.tar.gz=986f6c594d37bcbd3833e053640ba8775f68d26a65c5618386654ef55d7b3542 -dist/2025-04-02/rustc-nightly-x86_64-unknown-netbsd.tar.xz=c0d9a88c30d2ab38ec3a11fabb5515ed9bc3ac1a8e35a438d68bf7ff82f6b843 +dist/2025-05-12/rustc-beta-aarch64-apple-darwin.tar.gz=e5ec8453efc1f51d37d5031d87d45a327647614b00993d1b7f477c7d2e6c7b16 +dist/2025-05-12/rustc-beta-aarch64-apple-darwin.tar.xz=6711902d59079cd57d6f93e951d3028acb5cef0f59a2ab87e1688edee96f6471 +dist/2025-05-12/rustc-beta-aarch64-pc-windows-msvc.tar.gz=7168682081144b8eacab42efe6c9ddb9ee6964712d271988345e63d2d6faac9c +dist/2025-05-12/rustc-beta-aarch64-pc-windows-msvc.tar.xz=5794e0d6bed097d349e138c7602a083f4025604f711328c0a4548e27f191444b +dist/2025-05-12/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=c4d31776d1b74dcc6184c2ed6064667b1ade59c68fb355bee812a805f61234f9 +dist/2025-05-12/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=970b0c910f8ba2b5b470ffa7959466526b0f99211578f7d8ceca8d0aaa23fe1d +dist/2025-05-12/rustc-beta-aarch64-unknown-linux-musl.tar.gz=8e9c80f826b4571136f082d3cadbb4668167f19688a3da91fc732464b5a604b5 +dist/2025-05-12/rustc-beta-aarch64-unknown-linux-musl.tar.xz=09731185aeb15263cfed5786ccc78fee0db70f82aeb5409f8bd8b03b0566d491 +dist/2025-05-12/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=4ae8dec81d8f2d1aff7710a357e3c56323cae56bacd6b014fdb4058c06bb75f0 +dist/2025-05-12/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=4767de7ea81913c6ed33907d93dfb56664d9bce0d095f33f0ca5662b284a94d7 +dist/2025-05-12/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=d2233f4e687bb1bd407593f6d7a8c288581b7209d758be49f0681e1f556083e4 +dist/2025-05-12/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=a8f9778a765d9fa8a0651b7d6fac8fdebcbaa61e903a32e7cbcd88bcd9418bd3 +dist/2025-05-12/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=bd2ee7918df85f24a34911b91a233663b4cf706e7c54784c78fea8e58c12ca91 +dist/2025-05-12/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=9b1a1c4eb35d3c1ec97132e33fc6551ffb280d6b2c9d049bf0392441674d338c +dist/2025-05-12/rustc-beta-i686-pc-windows-gnu.tar.gz=729e4d7a116d8ee2a42489484429b138bafc14b43c87adfedaad442515e61c15 +dist/2025-05-12/rustc-beta-i686-pc-windows-gnu.tar.xz=8272b95f1d99dff28f22161d0181ac0e64e1909d51448f9ba4bcbe09690e79a9 +dist/2025-05-12/rustc-beta-i686-pc-windows-msvc.tar.gz=13a7327d08d26ba1911071c798d520b74422e320f5cc1c41d4e215a5615e692e +dist/2025-05-12/rustc-beta-i686-pc-windows-msvc.tar.xz=0f9ce8fb06bb1ae460ee82601c269b885c109729df342e5b6b05b9dd9b51560a +dist/2025-05-12/rustc-beta-i686-unknown-linux-gnu.tar.gz=82b54be8042baa56e1e6c0346f2044a84c4a50b3df6fe813d45eab21e1fe8935 +dist/2025-05-12/rustc-beta-i686-unknown-linux-gnu.tar.xz=48c9a8181b6ac7b7b6fb4535391c0498965127f5b5ac694de7eb1dba7ed8e9d5 +dist/2025-05-12/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=768156149054211735ec45d0091a8e7dfac16a39c44e122af5b28b316a45fd00 +dist/2025-05-12/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=50a38f72a253bfb8005a9cdd49621289f8b4a2373247957f520f5c5d1f12db29 +dist/2025-05-12/rustc-beta-loongarch64-unknown-linux-musl.tar.gz=f79bb58d8e2c80270a4c9d7076ce8645b2ea3f64db5077b085cb4cc6763f5e17 +dist/2025-05-12/rustc-beta-loongarch64-unknown-linux-musl.tar.xz=eafeaea2813e34ef0606a9f935fe1a104417604686ef9144b899fe97de53aa67 +dist/2025-05-12/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=f557e00500071835712afdc9d91161a95b1cca5cc4e32abebcf5d35a9147eb2b +dist/2025-05-12/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=72fc4d26e06d74349e65415da211429ec92cd479aae78f82e223f3f760b0e63a +dist/2025-05-12/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=a67b7e5e0b30227b07a41829c5e88180d9c404c2ce37fcb10d8df702c2b3c222 +dist/2025-05-12/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=0c4cfeb6555283e58b75533930783e7cc3c838f9c8eb34938fa60656b15568a1 +dist/2025-05-12/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=7e6f02eede8d87cd5bbcd8dcf8235ebabd1237fb294cf1d0dcfaf961f3628d95 +dist/2025-05-12/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=a5e9612d42f999a7b0fe22b2d5d5def21162aeb604c4625fc70259c5ec2b669e +dist/2025-05-12/rustc-beta-powerpc64le-unknown-linux-musl.tar.gz=8fc92b9e35110a53458e08b49db1809a23060f8d05e742561cd746fd206085f2 +dist/2025-05-12/rustc-beta-powerpc64le-unknown-linux-musl.tar.xz=8b3fc4ac4423bc71b7402554436d1e6e62ff06b36c69f7be724e8ec5ebf96352 +dist/2025-05-12/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=d0777e5ea794a9d19a2a1744acff649a1bac8fc616f6df41410553ac0b3c275d +dist/2025-05-12/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=849039740272c91141862a028f45889d4874ddc83842a66b906df37b7a30f9de +dist/2025-05-12/rustc-beta-s390x-unknown-linux-gnu.tar.gz=3230ab1516a19cf803952138ef7f815ce321d7123539539249b76f6afadcf9ed +dist/2025-05-12/rustc-beta-s390x-unknown-linux-gnu.tar.xz=12c8e476a73d71d58d5438ce94bb2fa822a8d043015b0961af14096d68c52daf +dist/2025-05-12/rustc-beta-x86_64-apple-darwin.tar.gz=01717cd3b5141d29896caeab17ad61a27b8b7af6460745f245d67dd066a09924 +dist/2025-05-12/rustc-beta-x86_64-apple-darwin.tar.xz=fceb7e0f431f84621a22ae50ec9694cd0ecdf90801f953295b1975b0aedb4fff +dist/2025-05-12/rustc-beta-x86_64-pc-windows-gnu.tar.gz=1f7abd7650cab64cd09848ac8de9b7e0047f6c77eb433140fbae8ae8b522c019 +dist/2025-05-12/rustc-beta-x86_64-pc-windows-gnu.tar.xz=4e3e07967e44907cb2b2ccb733b969014ee6efedb82412dc81f95533d2d473be +dist/2025-05-12/rustc-beta-x86_64-pc-windows-msvc.tar.gz=3cc10eb4187e09a48efa5351250e09c83edda4296d605dcb886eb81f9d6580af +dist/2025-05-12/rustc-beta-x86_64-pc-windows-msvc.tar.xz=9ce5c89a9b2e7360c7991c3f976bbbe9bf9685854d1019aa6dc1cc5b9d13eb88 +dist/2025-05-12/rustc-beta-x86_64-unknown-freebsd.tar.gz=3a9e92319e91c0498a3e54ff5ae00f4e1ecfac9b0d4f291885c9feef89d356df +dist/2025-05-12/rustc-beta-x86_64-unknown-freebsd.tar.xz=6930ccd83b6b63d0a876eb5ac52c32a8449fd4cea8666b919494ce6358c6122c +dist/2025-05-12/rustc-beta-x86_64-unknown-illumos.tar.gz=c1a4ad2cfa4b7c3181ea0facc3b18baea7f4138d089825915eb41630e5bac500 +dist/2025-05-12/rustc-beta-x86_64-unknown-illumos.tar.xz=44ae303a09cbc8a198c0cd947f958229b0e605842666a3b0aadb0f1f69f34ffc +dist/2025-05-12/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=fc55fe3f5b2d206417452de880a177f59004762e58fbfa4404f0b59fdd7075dd +dist/2025-05-12/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=a5ce304c4798bbacc998b2350d6ef79e9845a7ffb28bdf0af6066869667a0c86 +dist/2025-05-12/rustc-beta-x86_64-unknown-linux-musl.tar.gz=391cb81e61589377ab0a6780289628a805a5b1d842adc29e66ee5731f36372af +dist/2025-05-12/rustc-beta-x86_64-unknown-linux-musl.tar.xz=7c3ac5df14b28b99e3e2d0072b5aacc59acc08621731fdebaa3199059ccbeb76 +dist/2025-05-12/rustc-beta-x86_64-unknown-netbsd.tar.gz=670beaf2ec21118fb099a1b034b33665e360b8f1920b9cbd5fb58271a8aab9ca +dist/2025-05-12/rustc-beta-x86_64-unknown-netbsd.tar.xz=e4982c3e4b9f757485ff9aee183d973e31b2c485dbb39387c1afe4bee0fdbc30 +dist/2025-05-12/rust-std-beta-aarch64-apple-darwin.tar.gz=c2786d9e874eecea00935c62c58e2e3ddfbe11b4c99f9ce807e2251640c8f7f8 +dist/2025-05-12/rust-std-beta-aarch64-apple-darwin.tar.xz=0f2a6b28befa7d44055f32683d7b9c4de19ffd39c02fe6ce44aeffbdd1d13ea8 +dist/2025-05-12/rust-std-beta-aarch64-apple-ios.tar.gz=3cccf751678cc229a7ca3b39cbee4467230bec235e16b48acc576c825e0be15c +dist/2025-05-12/rust-std-beta-aarch64-apple-ios.tar.xz=9ed9b7f1672d887fac4a0386027440651ef99c682ff21b1bd9c1ddd850934613 +dist/2025-05-12/rust-std-beta-aarch64-apple-ios-macabi.tar.gz=e7e6c0c7d9fa99f268d7601a127c6ce07df620fb27462dbaf933124a5786ef8a +dist/2025-05-12/rust-std-beta-aarch64-apple-ios-macabi.tar.xz=abcecf3ecdb72714f35981847a91190c3f038dd5dce23a68253c7129fa6abf3b +dist/2025-05-12/rust-std-beta-aarch64-apple-ios-sim.tar.gz=c50ac5245e87b5e251fce3ff847ddf7d62df4490843e8a5f592515517b04d406 +dist/2025-05-12/rust-std-beta-aarch64-apple-ios-sim.tar.xz=1c913535759d008327eef49e47870d3afcf609c29aab4a188209c3cfea954682 +dist/2025-05-12/rust-std-beta-aarch64-linux-android.tar.gz=6120c1b159fa4f0279f8952aebf8cf1513f5b843905d64d1efaccaceac79c1f1 +dist/2025-05-12/rust-std-beta-aarch64-linux-android.tar.xz=57ab4652b879df33556cf04596f0f9ad9b0eee832b67e33c8c8cdf812c229a6e +dist/2025-05-12/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=7afcbb49691f8286ac21107598a7a44363a8e385eaa648ab2e7711f87ddedfca +dist/2025-05-12/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=ea8af597e49e924f1e04eb3435afa09720c81f43dc467461de1058265d36dd64 +dist/2025-05-12/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=2d8791f8ebff5f5f679c8b1735fdd1f0a4d7968983a5c2ddc5e036ad35b31f1e +dist/2025-05-12/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=a7f7bb3269dd7312edea5c6fef81d373499a670804259cf7853ef346fff42ee0 +dist/2025-05-12/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=9469cb7871dc724148489180df240dd51c0388cd9bb478adf272934e38916b73 +dist/2025-05-12/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=315f3dea48c50819f925bd32a3a5181591d4370eee4def8e37448828e622ab06 +dist/2025-05-12/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=abfaa164202c7d5d3c7e956b10a5ea612b092ee45d6c05d5c19a097617cfd703 +dist/2025-05-12/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=71ef1275726f6c61113bf1d23099a7557461205b6be243a952fa806ef15d9413 +dist/2025-05-12/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=d651e5e46e1251952e719237dde30ed7ecdb6b95a7cc0398fc635a76b94c552a +dist/2025-05-12/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=0a67ebf159539bc7f5a4e5698a0c74550da3c5e2cb0b5e1dd694ad29e1f35834 +dist/2025-05-12/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=c0f1ecbbdd5234230d2439620c0ebe9b1c3d331388cd174cdeaf48d724172aab +dist/2025-05-12/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=e2ba0a2853d685679422c065f266ee57f269bb5a231c5af5a791559a3609fb25 +dist/2025-05-12/rust-std-beta-aarch64-unknown-none.tar.gz=04b4eaf5910e662364b5ac3ee08ddffc2eda3957892ba99c8c945f5e1a18747a +dist/2025-05-12/rust-std-beta-aarch64-unknown-none.tar.xz=065751b346f9c3d76e164a9edc123f277492ebfaf1d00db61027e4fb17d50f79 +dist/2025-05-12/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=056a135278dfdafb5b22c8f01bfc77b17396511d67b55c1404693d801e584262 +dist/2025-05-12/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=fc086ae7ca3a5c05790cb41dfc382fc65f929c669efd540c07131b851b78a743 +dist/2025-05-12/rust-std-beta-aarch64-unknown-uefi.tar.gz=97a6301cdd34da68d5c6b243cc125f7e34215853e405d9b34bc715aeda3223ab +dist/2025-05-12/rust-std-beta-aarch64-unknown-uefi.tar.xz=3f2055ce638671316dc074595a35b893eea7be596cff218ec1416f3259ff86cb +dist/2025-05-12/rust-std-beta-arm-linux-androideabi.tar.gz=299158c865df15424564be4d72921b8b25993b0671e4d462ff69f49ea29367db +dist/2025-05-12/rust-std-beta-arm-linux-androideabi.tar.xz=6e71d518bf5f4a29b91938ee28b3c9b22509f3d97d4331ddd8ae0c1069192310 +dist/2025-05-12/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=0a00703833d46720e470ed90f81a08d9c20f63932d852e379fe63df955e61c9b +dist/2025-05-12/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=57be85e4c2d4eeb4cbb19f48150693d4e6dd2969d380b1d55feb431c858e4c35 +dist/2025-05-12/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=7b96461125b04d98a550bac5a7c3dad9c1df65ce849758d867c72ffc0b475012 +dist/2025-05-12/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=a66602af671667fe5686c7a4e395d3dca8374ddae10cc9260e23e20f65022549 +dist/2025-05-12/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=deaf5c7ed339c8a7bc2af94888841b647f8118854f698ece4ddbf900df921bd9 +dist/2025-05-12/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=eac2d4d330a5300ee297c2eb61914b86efded3d494c5a73e2f91d989cb2896c4 +dist/2025-05-12/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=479a5941193d14e2d4d50fcdbecb31103f6a143bcd3afae887d068c2ebe14163 +dist/2025-05-12/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=2483258323175c1e338be84ce52d44e15177096643beabba9d806c69cbed23dd +dist/2025-05-12/rust-std-beta-arm64ec-pc-windows-msvc.tar.gz=528803fac28b0a0025dc50324a6980a4b561e7e3b99d7428b8ed0a73fd3dd462 +dist/2025-05-12/rust-std-beta-arm64ec-pc-windows-msvc.tar.xz=6603b9aa82cfd563d7c462ebe50058c36aff403aa9e3a1d6a305780126aee481 +dist/2025-05-12/rust-std-beta-armebv7r-none-eabi.tar.gz=6ae7f3e39e974e20e9cbfae276fd4995063c5702c41085c2b764f3c37cbbfdec +dist/2025-05-12/rust-std-beta-armebv7r-none-eabi.tar.xz=404ae1fc0f5a6995ced2f66fa863cfff17c863096e99b5a04c841b97e6f0e28f +dist/2025-05-12/rust-std-beta-armebv7r-none-eabihf.tar.gz=bf6aaeeba558ac148b693c4e4d231415f6e72506b50ee06b0a1f987374a08df7 +dist/2025-05-12/rust-std-beta-armebv7r-none-eabihf.tar.xz=ed3f8767f5e824c5b81178e56c6084c45c67653793128d2c08146533333cc0ba +dist/2025-05-12/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=7d2fae89c459d65fe2cd28acaa225f0ccc35b3f49c84ce6aa86e2c40dba38e03 +dist/2025-05-12/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=fc05ce5ee26be4a233181b9841975c0975fc45ad5466d1001a24a01e2a31123b +dist/2025-05-12/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=0335813546a1f905e274135b2bd97c3a0c95f2e0d992d7396bc110b800d3ca8c +dist/2025-05-12/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=7031aeca445d4f8fa351c7ad2e0e06df0386ed11f91080ea65968f1716006bd3 +dist/2025-05-12/rust-std-beta-armv7-linux-androideabi.tar.gz=9abd7fe0b7163a141d758ccdca422bd32ed4ad3618066ac022671b082f4641f9 +dist/2025-05-12/rust-std-beta-armv7-linux-androideabi.tar.xz=2bcdeb652d42755528a17b86a3b64b13b32d1ba9207cd2c9ccb43fa0d7a1c6bc +dist/2025-05-12/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=1bad15b2e9806e7858d5d4d58f6b2864c3f04e65d4ecb1cc448efdbf0e0030b0 +dist/2025-05-12/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=f2d9039c903e5c309bbd17c7567462d4663665cbb7e1d98154022d98a9883719 +dist/2025-05-12/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=13aa4a3ef68a87de259726c7c2a3906cbf013836f753b707a453bf91879f023b +dist/2025-05-12/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=8c4f8c044aa4ec6813cec1fed11326f67b0f2db3f20e4b441aba5656af7f0ae3 +dist/2025-05-12/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=4c2e5ae8c903577e963af32fdbb39de6180db52907c3f508064a87a21feb9390 +dist/2025-05-12/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=c1a12c15792f6b0de81a6e24317d7bea9af023a977ae0558ee3b4598539aa7cb +dist/2025-05-12/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=f789db5aebd9395daf198d5248323fee1eec27533f6d95d0f454339cbc997950 +dist/2025-05-12/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=0376d2f2ad8f82719eabb378de3404e066da7d603e27ae4e1620509ccd6eb5b6 +dist/2025-05-12/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=9312a8d530c6ca1e72ed35ef82700853e1fba8a1f39bcaad61277a86a974ab18 +dist/2025-05-12/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=8c7d99202e5468bbd6fcd818cb832376c00a7c4b09973e5d00b84aa4964b7ff6 +dist/2025-05-12/rust-std-beta-armv7a-none-eabi.tar.gz=c4fb94b25d21802136bc36289eea9b95e50b101f64de925a1e9d8ad8ee70aef6 +dist/2025-05-12/rust-std-beta-armv7a-none-eabi.tar.xz=6ac88ec457fd554268da3307d40664d2926174cf8e89eb173112c7248776e060 +dist/2025-05-12/rust-std-beta-armv7r-none-eabi.tar.gz=c436c2c58d224e1f9bea4703f8ab57cd3f427c60432cca50eb294dde65994002 +dist/2025-05-12/rust-std-beta-armv7r-none-eabi.tar.xz=220906e1eca686d6e4a76a80417f527d37b0659adbec940566570292496715f8 +dist/2025-05-12/rust-std-beta-armv7r-none-eabihf.tar.gz=eee1788aec77c48c76bc5ba807d42d4bbb7c8f3e9220ba1135764061a9ddf3d9 +dist/2025-05-12/rust-std-beta-armv7r-none-eabihf.tar.xz=136f3486bdd8a7e91d738a3f8c1c3b96b853aa054a76c4e83e427ea56d3eea0d +dist/2025-05-12/rust-std-beta-i586-unknown-linux-gnu.tar.gz=72e3c031fa55d131a206d5815899a48ff7bcb19c9ac4b3dbaeab38a3cc4a3630 +dist/2025-05-12/rust-std-beta-i586-unknown-linux-gnu.tar.xz=91ca56a1e5a07e1c147a8906d366985548bd961af2aa31dfba60938e457ddece +dist/2025-05-12/rust-std-beta-i586-unknown-linux-musl.tar.gz=839ece94670a9295148231c77573f5b2d8ec5fb9727ab6aa45b8f320201f40d5 +dist/2025-05-12/rust-std-beta-i586-unknown-linux-musl.tar.xz=27ec97a6e24184edf4a51de5500d5bb4d4833ad2b7bc771a4506589ce2190062 +dist/2025-05-12/rust-std-beta-i686-linux-android.tar.gz=d8f529a63a46bba2bd358e491d7fe0be10fee6dabf0075c40177402aeeb49721 +dist/2025-05-12/rust-std-beta-i686-linux-android.tar.xz=a061a703858aa0770d51c6c8bcdfca048efe96b561c460464b835b4ccfdca387 +dist/2025-05-12/rust-std-beta-i686-pc-windows-gnu.tar.gz=8b7eb90ad7edb050599dd477c520455ad7e02696426692a0a72094381e189285 +dist/2025-05-12/rust-std-beta-i686-pc-windows-gnu.tar.xz=f99e1d82a3cfaef05e6f088e766932a3860e7df60e1f392162746bb08eb72ddc +dist/2025-05-12/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=5d57965f2a6ffff01619e84acdc0f7d9b2afe3c361e5094eecccfa9893eaa501 +dist/2025-05-12/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=c1b218aac6370cef9564043c98f361a2938c6ebc7784cb49b361aad3a1bfb6f1 +dist/2025-05-12/rust-std-beta-i686-pc-windows-msvc.tar.gz=fdcd4b6f391338fc0f7b72d11fc8dad9df903fb4639b893b57e729de387a9cf9 +dist/2025-05-12/rust-std-beta-i686-pc-windows-msvc.tar.xz=c8faa9123c9df0d764cac59e10e94f1562ec7bc7a792f5c63f9a9decd48a3280 +dist/2025-05-12/rust-std-beta-i686-unknown-freebsd.tar.gz=e8882425b127d01afcf6269e820bb8c4b813619b6d10f0422fea17c87d5921bf +dist/2025-05-12/rust-std-beta-i686-unknown-freebsd.tar.xz=dabd3bb2560a7949f8984e1dcab35aa46f8e46b09e68c7f2ff32894370ed80b7 +dist/2025-05-12/rust-std-beta-i686-unknown-linux-gnu.tar.gz=dd296784ed2199b4c2d85053bce686e01cf867851b175b24781e7e8e6f6ef8bb +dist/2025-05-12/rust-std-beta-i686-unknown-linux-gnu.tar.xz=3bb9069b4456de27cc9fba5dd2b350e5e8215f0460ce9ee375f65856958e4a82 +dist/2025-05-12/rust-std-beta-i686-unknown-linux-musl.tar.gz=008ea77ae8d982461c65c25bfcc0c41642ca51a33007a4c8d1ede8612df8f20f +dist/2025-05-12/rust-std-beta-i686-unknown-linux-musl.tar.xz=fdfeb6df04afe1f4e414ad8292a7b75191c2507d020e69f402f97ee9ab3ccf90 +dist/2025-05-12/rust-std-beta-i686-unknown-uefi.tar.gz=dbca5a983d2eb2bd84aa7779fc54562bccf9043b31a7f52a3043f1e1e59695c8 +dist/2025-05-12/rust-std-beta-i686-unknown-uefi.tar.xz=c0d9abf38ba7b1847fc70b9dbe68f4c27d5a1adb9726dbbee77911f1d271b6aa +dist/2025-05-12/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=c923562d0a1d2830d41212ba140225b9c36087087dde6753e7a891383a095a10 +dist/2025-05-12/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=5ca633c2e218939983d77cbf5738ab7d5fc4aa89093a0d1fb701ab06ed7ecf51 +dist/2025-05-12/rust-std-beta-loongarch64-unknown-linux-musl.tar.gz=a38b4748085b3c06f2154376cdda41fcee2154f1fb409ac5137b63034cfe8cab +dist/2025-05-12/rust-std-beta-loongarch64-unknown-linux-musl.tar.xz=43601e0aecb02535ee46b0ddd076867248cd8654be302ae6580a81af33660faa +dist/2025-05-12/rust-std-beta-loongarch64-unknown-none.tar.gz=04dc49b516a638589d907f885aeafa19170683b023d0ee1bf5d78f0d91d0b94a +dist/2025-05-12/rust-std-beta-loongarch64-unknown-none.tar.xz=123f388b208842b3ee46a01ae8efab900c0b5b01b97eb896d26b12bb3aecdeaf +dist/2025-05-12/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=a57452e86c5b768f1feb7f903e4ef8e76518e625c09b5f555885e1d9aaf9b76f +dist/2025-05-12/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=e9d8b99bc4686e199f3aeda5cbfd99d49416a7ba104b494c18ae67a8d1133d9d +dist/2025-05-12/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=3a9f4744fc128be61877967586e6c163cd6ef4e017e04578cb9101c8a9a60cdc +dist/2025-05-12/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=0e693f7c27a34876728565152f7b6b407e1773a187742792ea2ac3f53d6c9839 +dist/2025-05-12/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=9d0f6d9cc2b7d1ceff5934a00c780337d2fa77cd9a81cbe9e041e5b18adb43ff +dist/2025-05-12/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=afcd5c9d2e67d6c514630443d9e50d37d36722712e9275e3eaf4f460f7eb779f +dist/2025-05-12/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=9c02e0eb75361a024d25863456c3906b845314481cd9173a6708104a21265e88 +dist/2025-05-12/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=5b0628ca22f762796c9215606314babc1237baea075c990e146ee9f9ba1ed834 +dist/2025-05-12/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=9e12bd3f2b61b8753aca3a1ed117cae0b4bae2267634a6e24afc0c642d998784 +dist/2025-05-12/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=70a6cf1d3e6767656657e5f76e8dd35049bd20a30517f85832c35847c9f63bf7 +dist/2025-05-12/rust-std-beta-powerpc64le-unknown-linux-musl.tar.gz=e2feb3c8bf2390281c71f3b76f07a5a9700e454236bdd2c8f75403cb2247b252 +dist/2025-05-12/rust-std-beta-powerpc64le-unknown-linux-musl.tar.xz=0b533328ff7dfffdfb11826811fa9474c36faebe909f176d60898477d5b9d23b +dist/2025-05-12/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=42b46c1d8ebec202131d08aa21fb6ead760a630199822b4fe88c94a5447f0491 +dist/2025-05-12/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=24bb2a24d41bfdb76dfb8817e99759dfd314ce52309d51b294db7a558114f936 +dist/2025-05-12/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=5d50c5a766344cacc6e7ebdabddfe720199fca74d1d4284a80ff5625150d7bcc +dist/2025-05-12/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=f6f6e68c0d495b2833566deacac8a6154a220fe1f92deacd031e6b649a63a04f +dist/2025-05-12/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=a80d128b4d0b3b5bb9316da1297b0c1cfee026eea3e9e23c546d62dda9cebd3d +dist/2025-05-12/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=03e27d02bf685f6eb1281fc48d417dcf9f934587fbc743d6e7aac6e0c3691d5c +dist/2025-05-12/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=67185b764c3423704af10318f44f0f310349191d62785bd8cb85ca2bac7f935a +dist/2025-05-12/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=8ef88ac6044c84815bbbcd2b5ce4128349633addf40bb8c439b9a0a07fc5e179 +dist/2025-05-12/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=2ab3bbb6de6a5281f8aa586e5fc15d575a34b17b4f44908347d7a776c924add2 +dist/2025-05-12/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=321b0167c9481ab88ff44bf920fa15bdb4e07c864a90b6777f3c8dfd0e5c5ec6 +dist/2025-05-12/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=bede2674247df8ff2153808f499ee1c1a7a909ff87600513ebc2998f43c7c1ea +dist/2025-05-12/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=b903c9ca2344fd1323695052f74b9562f6dd3cdde4872f935bcba6c0fb988dce +dist/2025-05-12/rust-std-beta-riscv64gc-unknown-linux-musl.tar.gz=ad90fed7ed9137d04aa8c41d1c7e856dd8cc57a0f4b7836b22c9b1932a24a769 +dist/2025-05-12/rust-std-beta-riscv64gc-unknown-linux-musl.tar.xz=78372e3e32174a2cfa12dcd426e36fe29ff76779d8815944e6f6c7be4a3c55fe +dist/2025-05-12/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=a781d0ee95ae3012e3d016ae1b029ca8507ff549a6b1e0a6f052bca6d4afbc7b +dist/2025-05-12/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=23b1cf7192f044a0f46ccedd654aa203dc0e9fad47c5ffc2a1e6717bf6598d69 +dist/2025-05-12/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=dfb15324b8047bd26a58a26d373af441182808203c06a3d4e595d79bca21b757 +dist/2025-05-12/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=432dfeb9231b67537dc5c77941ee26fd73404ea16dc1be4071b98c13680ddcaf +dist/2025-05-12/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=cff18fbbbe323c67779651dd6e3b94a76a573567720985d59a091c26a3c33110 +dist/2025-05-12/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=c5f25038ba5be3ffddb6966e89017de862a0d9f267a57eeaae81b3b2a44d5690 +dist/2025-05-12/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=104d762d5a45fea227880d2395068824f9202e5a7fbd30bea478bb1ee6899ee2 +dist/2025-05-12/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=de1f15d6cfafc275108c4584a294128962dabe54bf5a1f6e81da3508ea9e8a14 +dist/2025-05-12/rust-std-beta-sparcv9-sun-solaris.tar.gz=531562c65d558a993128054fcfb29f0d408a40318ecd5623b5b24636bd7b0a07 +dist/2025-05-12/rust-std-beta-sparcv9-sun-solaris.tar.xz=af866deae0c10ce2b11c0ebe37fdafef79285bc694eaba75213316ab125b198d +dist/2025-05-12/rust-std-beta-thumbv6m-none-eabi.tar.gz=ff623d437bda1c0b8cd8affd2a6bc165b8224a5467894aa54dee63b1b6939fc6 +dist/2025-05-12/rust-std-beta-thumbv6m-none-eabi.tar.xz=d8743e42057014ef2742cec5b93e34d5cde5a658d3ed9e7e738276387985122e +dist/2025-05-12/rust-std-beta-thumbv7em-none-eabi.tar.gz=0b097cef25dfe72f692cd6d9dd2df85a2fc5ea9db87b8c06b8f310c239c74624 +dist/2025-05-12/rust-std-beta-thumbv7em-none-eabi.tar.xz=e7fd61ad7660c7f8c62ae6dbbd238305d997fe7539dfffb8fd0df2205656b5a9 +dist/2025-05-12/rust-std-beta-thumbv7em-none-eabihf.tar.gz=d6b3c40bd84fe352c1a88dfbc3c0f9012dcc1d82b860ce68c1d21a8d452fa662 +dist/2025-05-12/rust-std-beta-thumbv7em-none-eabihf.tar.xz=b2be1305ae382359f81e0bff16341719b6ea7731ff833205dc3fd99e7e978fb9 +dist/2025-05-12/rust-std-beta-thumbv7m-none-eabi.tar.gz=5452dc0f152065e887178423e324bf3082885b922ac57ff22c156cf7c432e184 +dist/2025-05-12/rust-std-beta-thumbv7m-none-eabi.tar.xz=5331de420a79f521351a1ea3dd501cb00b21e1979eb23dfc871ce33abca68dd7 +dist/2025-05-12/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=0b2ffb463dca747f00cf063d8fb07971df80882d3890c34ba82fbf1b77655dd0 +dist/2025-05-12/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=2f7c2bde8ae4b911889dc24a8fbe2d1539685d46c71689e5e8362cf46c391019 +dist/2025-05-12/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=1d29e86aa77e277ce1598313d6851f2f077b023217f1712d59eb76305fc773fb +dist/2025-05-12/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=73dc975b217329d6ad44b8e8b3f72a3396597a207df7d7222d983a155ca05758 +dist/2025-05-12/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=c34c686a62afb45b9e57b3d487dcc1f66396bd7804a9c0d9696def0936a2ba1f +dist/2025-05-12/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=1527843f87588ee28aaedbb0590bb809c24cbde6a5264151ce5fe01baf70176d +dist/2025-05-12/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=8225d6b35a55d7937bbcb7f2e74ab8ec0f23fcd69a48c59391e9016d9863151f +dist/2025-05-12/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=8c59ed4aa0a62ff8999570b60a6b9c468ea52c45642ecfdc515d6f2722fd821b +dist/2025-05-12/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=6a5804a7dc199f696867e4612d1381910ff9a13b5516b2906e651451d8ec23e8 +dist/2025-05-12/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=11205a43892169cd0aad2764f5d7604a52d13292978e7e851cef2d8e65ae6fe5 +dist/2025-05-12/rust-std-beta-wasm32-unknown-emscripten.tar.gz=962e092960bd3074dc966c1928a4adfdc16d6d811060e719dc1a84061132566c +dist/2025-05-12/rust-std-beta-wasm32-unknown-emscripten.tar.xz=5d7fe7b3fe3b022c95d96e4027767b44a7e7980ca5c894839868919a0bb4b5bc +dist/2025-05-12/rust-std-beta-wasm32-unknown-unknown.tar.gz=38afbfef695bad377ac9d3a4d7d9037b500795c3a75f907bf60acd4cac2b4cd4 +dist/2025-05-12/rust-std-beta-wasm32-unknown-unknown.tar.xz=f5f670d35a843cda6f5213ae02a99c3c6d1e30f3ab651be0087bf8e4de0911f2 +dist/2025-05-12/rust-std-beta-wasm32-wasip1.tar.gz=e7faeb24fac65f565e0145166d67a30b02b26f0df20791f3bdc31169846a0e2b +dist/2025-05-12/rust-std-beta-wasm32-wasip1.tar.xz=0136f4434e8a0edbbe050899a17ae2b2825aeb4b98c4fb80f8eb25c9ea6623ab +dist/2025-05-12/rust-std-beta-wasm32-wasip1-threads.tar.gz=2ed823ff5c3704f91048300fa31624cddeea8086cfc654fa2fea4adff58fd901 +dist/2025-05-12/rust-std-beta-wasm32-wasip1-threads.tar.xz=6f156a460db83c271b43c37709ce5724fb8059c44b29e08c2b2da27c32c06e5c +dist/2025-05-12/rust-std-beta-wasm32-wasip2.tar.gz=ecd1ba1fec2e1e87b5f30b341e8228ca98545143adb8acd6ba53c7503f581e34 +dist/2025-05-12/rust-std-beta-wasm32-wasip2.tar.xz=593976f715c77796cecf6f7f2b79fbd4f49c10ded0349762e8312052497f1e28 +dist/2025-05-12/rust-std-beta-wasm32v1-none.tar.gz=396eb4c1e4cd930f045b092bbc8203315f494ea32c836d62e84f63ead124d886 +dist/2025-05-12/rust-std-beta-wasm32v1-none.tar.xz=9b827d1941a1d67a32a255342b476a19f57de06e53a9e6798bf00688b86eb2e0 +dist/2025-05-12/rust-std-beta-x86_64-apple-darwin.tar.gz=2796de44843d68141c6330f0e09fbabb5c3a8f34470d2948f1ed93b1b9dac088 +dist/2025-05-12/rust-std-beta-x86_64-apple-darwin.tar.xz=881e98599e5b2475e8c9f6b81e0ad6a51e8058cb2c7fc893ab57c19cdcc80804 +dist/2025-05-12/rust-std-beta-x86_64-apple-ios.tar.gz=8203faeaf21dc2c86b35d4362413c12d01de33da4524008c6261d3c87be9e51d +dist/2025-05-12/rust-std-beta-x86_64-apple-ios.tar.xz=13a59816008d3d4b0fb20680bfe2f1c2ae8ca7eed0bdf717817e03693724eb25 +dist/2025-05-12/rust-std-beta-x86_64-apple-ios-macabi.tar.gz=5b906fe2d801c572696cd93564723338385eb574587769f79506cb3e6c87452d +dist/2025-05-12/rust-std-beta-x86_64-apple-ios-macabi.tar.xz=1624a408800a895d8fe71bfc71876e52349c3508e9ddabd46d89d3274ede2dd7 +dist/2025-05-12/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=6722e76457289c6551f77fd462058862d7fb8597e1714cf66925b21e5af75c7b +dist/2025-05-12/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=8097f509383cab4e8e444ccbf7f5d91fe35bcd2cd2017ab78bcc692c9fd1ecf4 +dist/2025-05-12/rust-std-beta-x86_64-linux-android.tar.gz=eb3124653c908003185b36aa9829ea983f4b44e11a96da69c2585664a67bfeaf +dist/2025-05-12/rust-std-beta-x86_64-linux-android.tar.xz=4f29c6a0458ed5e37ee7a17643ff7854bd6ed029c46cdd0707019d01523a7a62 +dist/2025-05-12/rust-std-beta-x86_64-pc-solaris.tar.gz=319663b24b449df3f8063f64bd849969999a441b9376c86e6eea15cf3b872e5b +dist/2025-05-12/rust-std-beta-x86_64-pc-solaris.tar.xz=13280470aa4c84ed6ca200664ebf3a6aa084550a82c06505b3178caefe3072ef +dist/2025-05-12/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=d97cf2b52f013b5cfdd9c5a3885ea70accdf52e2f957e086018d88731c8c1964 +dist/2025-05-12/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=a2685ab1c204823b19809e47b00f2c48c5f2cc2faea05ac2df935732a7412441 +dist/2025-05-12/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=50c0f770a938123f704837bd3313dcb12842aba75b687282a9aca6c11b11ba8e +dist/2025-05-12/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=8f0d04c8d55f23235f8dec94c5d5035405afd513b082f00b257bbb86cd481240 +dist/2025-05-12/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=e633aebc178d4846a3d26f796405dde13115560c23bd2955c82afea8ab7c8d7b +dist/2025-05-12/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=8125d5bb9a9205ffab43d0dcd56402320643101169a49098a98ee6ae785c0ed3 +dist/2025-05-12/rust-std-beta-x86_64-unknown-freebsd.tar.gz=c089415c86c9f74a454b82955911e84c9138ad66757e4da689381a1bfbd4cee5 +dist/2025-05-12/rust-std-beta-x86_64-unknown-freebsd.tar.xz=a930b94bc005ce2b09b4d67abf47bfeafad8c7ab6ca5c15acc10e023818e7b25 +dist/2025-05-12/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=f74e77eb803d1ca244e1e97272578ec008e9c373af92887318d9281204a798fa +dist/2025-05-12/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=2fa583fcde17c1ab2f2d148af9467fa65f6bf6a0a1801e957fa15a79e6de4f78 +dist/2025-05-12/rust-std-beta-x86_64-unknown-illumos.tar.gz=20d16ce11adf468da51b30c0b55a46ce3bd030eea9f9fdb3f65f36aa442a3d71 +dist/2025-05-12/rust-std-beta-x86_64-unknown-illumos.tar.xz=dc1f2d3c1a0ae59cbfaa09b2d646645cb4fabb151edbf92975e4c8a0bfa54eba +dist/2025-05-12/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=05b2e5ded14501cbdc86c0510faecbf873e30d2d70724013bbb176b6f4039b44 +dist/2025-05-12/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=a18281579cb61ea26ae0062428f7a49e51c4a928102a5eba7ff96b0ca38490c0 +dist/2025-05-12/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=a5285ae02217d64c7bbddaa3dd1f68c361f2849479a6d75edf1d551751886f7d +dist/2025-05-12/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=4c41edc4f4cd1f24107b1b003a1713af3b456ff3e933781c5d4ef21a490df5e7 +dist/2025-05-12/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=2d4c1666d456e810353f8b386d0d331812f84d9a17344953e5f4f4370bdccb0f +dist/2025-05-12/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=287f51dbc6e4273208869140b9c2e0de2896c0cd40f7492396ec0bbb8989a82b +dist/2025-05-12/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=e20af62d1900a5e10cf766ddcda9550176ab5f41111e09d57167e4e23e68d005 +dist/2025-05-12/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=7837f4880ce5d5251213d17867a6c61977504840678388fe245e0433086f409e +dist/2025-05-12/rust-std-beta-x86_64-unknown-netbsd.tar.gz=17d2a43bc24e4e49d54315c7eb0e4952c3118b278b0a564fd588ea4ce0e8d90e +dist/2025-05-12/rust-std-beta-x86_64-unknown-netbsd.tar.xz=ab34b5b10273c639805956665cd6543749cff2748c53980f80342facb9171b2d +dist/2025-05-12/rust-std-beta-x86_64-unknown-none.tar.gz=d8387a8478f6a937944d684f852dee18d584344ab84425d228489dee324c318c +dist/2025-05-12/rust-std-beta-x86_64-unknown-none.tar.xz=6ed8c2c72d547c7cc6b32a6080c346915de02a1ac02f032b6320fc7e3d45e330 +dist/2025-05-12/rust-std-beta-x86_64-unknown-redox.tar.gz=7f3a62578694121ef90fd08ab7a82a8fb27d86f164d7f73edb56a2e360198f41 +dist/2025-05-12/rust-std-beta-x86_64-unknown-redox.tar.xz=44f7ba0ca447050ad3eb7be0a0e41fee304dad2ce359c854848b7430c42b22d8 +dist/2025-05-12/rust-std-beta-x86_64-unknown-uefi.tar.gz=f78e6eca6ff517571480a6bbe20099d170f6a6b2ff0e64544c41dc77588ed890 +dist/2025-05-12/rust-std-beta-x86_64-unknown-uefi.tar.xz=d2a733aad6929be6135676307bd4576eb168e11192c24051e0be4a713b5733c5 +dist/2025-05-12/cargo-beta-aarch64-apple-darwin.tar.gz=43afffa0c5f7287e205a63871b555be144e900f8d8d67e4ed0654b50809b7338 +dist/2025-05-12/cargo-beta-aarch64-apple-darwin.tar.xz=705f051543ed8cc7011d7a866f345c3aa22c9d24f5325bffb9d9676e3c26142b +dist/2025-05-12/cargo-beta-aarch64-pc-windows-msvc.tar.gz=c0911e84ca85de5e8c9550e2be08dd85458ba31516e282044c9149bf8bb56fa1 +dist/2025-05-12/cargo-beta-aarch64-pc-windows-msvc.tar.xz=7335470fc1338b95edc81777eb0975cd5cf5cdcdcaefc7658f356ef3e0c54fda +dist/2025-05-12/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=99071e036041b47f78b71f1ff2ef5699b96a126ea84010ac031ee8d52d7c5873 +dist/2025-05-12/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=a9be2eeeed37905e83beb4265f4f45086675a0f5ff25db0e6bc0c5164257e1e1 +dist/2025-05-12/cargo-beta-aarch64-unknown-linux-musl.tar.gz=b38fa8d68c27b4989b1dc94caaf6bec833cc8e6d4464b859451d495b081c5b1b +dist/2025-05-12/cargo-beta-aarch64-unknown-linux-musl.tar.xz=95a839bd2f928afafbe1058cb185b95e0099ae15d5d3030a3493724f40300ae9 +dist/2025-05-12/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=34cef4599ece9c218c3841ccff9a627a69909eb733c19441c19de5b68841845b +dist/2025-05-12/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=cedfde42e95a0e86c3be841965c20f1c8bcebd20d88f38b2e694017a8afa745e +dist/2025-05-12/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=b8f1a0fca9b32362da6169b41fd58d53af6b02992ac5666cdeed03aa6150dd0c +dist/2025-05-12/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=8f5b040e4099a03418b72b5975419089e7fa15a947b04ce6dd18f450cc21f2b4 +dist/2025-05-12/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=2f526034ad1280d152861e700fad2aef95759eaf17780a3a00d71e8fc6d8520a +dist/2025-05-12/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=b6fdc7a08740d06e29aa678f4f9cb2dfb57fb863605fba1cce67d71ae1c1ace7 +dist/2025-05-12/cargo-beta-i686-pc-windows-gnu.tar.gz=f8b1e0227f5c1c2334cbcf53ebe5e94e01215ce21de2c5c9846e0ea7dce8e777 +dist/2025-05-12/cargo-beta-i686-pc-windows-gnu.tar.xz=149bc0d8cba9924db3b882795b6dd17f3d0a01bedfa75143dfdb7623cc7c4684 +dist/2025-05-12/cargo-beta-i686-pc-windows-msvc.tar.gz=b8462286bb1746bb789f580a14f1c5c37b108037633d9e8fbc5e2e6638e12a5c +dist/2025-05-12/cargo-beta-i686-pc-windows-msvc.tar.xz=f07104b3439e4cfcf5c96dbf6bf4428f677f45449ce2a5595551884ab0a6870a +dist/2025-05-12/cargo-beta-i686-unknown-linux-gnu.tar.gz=f68dece61dc087622d9e622944c4c13cdfb056eecdd93c9527c71637c73a708a +dist/2025-05-12/cargo-beta-i686-unknown-linux-gnu.tar.xz=3272d868a2bc44b80d0ab11d133f66ed7a40b75d00fbb7a341adbee083dfd8c0 +dist/2025-05-12/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=2fa7ef9b0f5247a650c1cf649e7f5514989a22b6c7927fa1df809e54466bc18f +dist/2025-05-12/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=3eddae3525cd8b446a4b31ea933cb859d335b0309900379868230d4a63979afe +dist/2025-05-12/cargo-beta-loongarch64-unknown-linux-musl.tar.gz=88d56208387b4aa9707729f0b9337c32a0516dacc4c891b3c80140874dec6043 +dist/2025-05-12/cargo-beta-loongarch64-unknown-linux-musl.tar.xz=8e4ceefb3d64560d989bf69f3d58cc07ab2e6a68d1f761ef92cb1826351834bb +dist/2025-05-12/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=ed5705fb6dba34981727e4af215d8875de2c39d41b1c3e8653a93cdc06873975 +dist/2025-05-12/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=be618816cd7706709fc13ab268249a74f7b905e7ae6abe6ca1fda336dd38baa2 +dist/2025-05-12/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=8b53a21201661914e3291ebc6912083e1cd86ed5d202d6940c2be15724371bc7 +dist/2025-05-12/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=546260a68ec029f228f280fc439e93dc1f64b3e597cf615ff3915548ab67b435 +dist/2025-05-12/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=343a00f2cc571ac779fd7647560b215650a01e877c9b15f95668cfc33c67ec77 +dist/2025-05-12/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=efc6a23ffb467e1459f3fe5932e8303d0ee550853ad13b3ace12c9aa6514f24c +dist/2025-05-12/cargo-beta-powerpc64le-unknown-linux-musl.tar.gz=5c4e53aca46fcfb7d669b74872130fa2b8bf05b09d14bdce34f0322030450e47 +dist/2025-05-12/cargo-beta-powerpc64le-unknown-linux-musl.tar.xz=c2e33c9522924cbfde1109f87d12d27225ceb23c7ad801d3a5559a72715ca402 +dist/2025-05-12/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=91d578317c8fa147c22e81728da411fd01c1fcb0bdf2e054948537476b8371e8 +dist/2025-05-12/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=83fc425704b7673943583e38c31a944695984ffabcdaa4ab79b43aea03cef48e +dist/2025-05-12/cargo-beta-s390x-unknown-linux-gnu.tar.gz=dac65289a906a32908ff0af9e9b829111295b49099fd5d9f90b2e454b4ecb422 +dist/2025-05-12/cargo-beta-s390x-unknown-linux-gnu.tar.xz=02a3972bfd62d4097da252fed278d741193f2c4face2e35ce8e84974e42cb1e1 +dist/2025-05-12/cargo-beta-x86_64-apple-darwin.tar.gz=148d0410ec2d3e540cfc27b6756e50d98b7ed214c2e5a702a9f2326e75ec249c +dist/2025-05-12/cargo-beta-x86_64-apple-darwin.tar.xz=65e993adfc14eb7a9c3946a3d1ce35f5aa9767ece65cd759669bb82deda0adc8 +dist/2025-05-12/cargo-beta-x86_64-pc-windows-gnu.tar.gz=a69c23bfe9ec73737c22d0b6ce308a4f19625aab2f1846bc223ec6974cdd9163 +dist/2025-05-12/cargo-beta-x86_64-pc-windows-gnu.tar.xz=56b33a8c9e0bcbbdb2c6be13d7b84d077a896b21d800a3c6da64aa2ef64ecada +dist/2025-05-12/cargo-beta-x86_64-pc-windows-msvc.tar.gz=cfd22dda3987642606f9e869264fa709d87b8ac5894547f809f60abce268ff76 +dist/2025-05-12/cargo-beta-x86_64-pc-windows-msvc.tar.xz=7075d67ef2dbf1e0d3889039d4db66042db538304c53cacd3e983eb9aa9d0275 +dist/2025-05-12/cargo-beta-x86_64-unknown-freebsd.tar.gz=419ce0f856113509f58f2fbccf9e5f864aa56c3c1a2c4029ecdb546464393214 +dist/2025-05-12/cargo-beta-x86_64-unknown-freebsd.tar.xz=d8f73cb808471883a5f6ee8db3dd5165fff5084ae744f4ffdca89fb545faaba8 +dist/2025-05-12/cargo-beta-x86_64-unknown-illumos.tar.gz=69e63b33c7f8d469232504c373a4e35df97016735be633a818023ea21de8f0be +dist/2025-05-12/cargo-beta-x86_64-unknown-illumos.tar.xz=aa86cbf46dd2e35c10bb5725c627dc40ecb33329a866c2b0c5c274728f384ed3 +dist/2025-05-12/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=f77e6d762e13eb95d6369a26971e4108de448eb23690554914f650fadd2898de +dist/2025-05-12/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=8e4b379bd88e8f18e5b6efe6058bad4ee60fb6c2e734ec165fee188f893f948d +dist/2025-05-12/cargo-beta-x86_64-unknown-linux-musl.tar.gz=a04b711f9a07eee991b1ab13ab56e0f9e2c2ba2a16186be6c0d04529ca68af59 +dist/2025-05-12/cargo-beta-x86_64-unknown-linux-musl.tar.xz=587b214ddf5b85697b78d8baa9164a4b81604b8dccc969a03b1bf06ae7c11240 +dist/2025-05-12/cargo-beta-x86_64-unknown-netbsd.tar.gz=81a468f1db3cbdaddf6a1785297457d4780fbec472d0bdfda64fb7a398782a78 +dist/2025-05-12/cargo-beta-x86_64-unknown-netbsd.tar.xz=32212f4273171d78e10170c4a863d6f9990e29e26fdf6857dd3d134eb803161d +dist/2025-05-12/clippy-beta-aarch64-apple-darwin.tar.gz=e5de69a84edb22eeaaeea2d94aafb07ed408508f68fc0989268e6dec8bae6a8e +dist/2025-05-12/clippy-beta-aarch64-apple-darwin.tar.xz=03a9ebedbf11cf151d19f46b9eeb3f8ea765ac779b55356b51db21e83195c610 +dist/2025-05-12/clippy-beta-aarch64-pc-windows-msvc.tar.gz=5a9e27ab31a382ba91f9621508cf28fb4f5d0f2521452369ea2441598d34b2bf +dist/2025-05-12/clippy-beta-aarch64-pc-windows-msvc.tar.xz=951c9f03a6fe0de1e94ab8f064cfc1b29b06606c38e891c2f9f1c550e9d94678 +dist/2025-05-12/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=1a241694ef544259a3c87bf271b1248ebb6fd32ac35b3ac16154e509b80c6e47 +dist/2025-05-12/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=679c8ed606c22490fb0a5a8503d898e61199e3cd17d9dd7a34c121781ca7306a +dist/2025-05-12/clippy-beta-aarch64-unknown-linux-musl.tar.gz=26ba8ec943e4f8cfa27afcde06fd34dcf546c3a5c7668acf703a9b962a1977c8 +dist/2025-05-12/clippy-beta-aarch64-unknown-linux-musl.tar.xz=051112fc6bd906c62cf14d2fa9c7f1505540a6aa86ee0b1889e11b1925274c23 +dist/2025-05-12/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=a44d29c794e49742417de03a955922ff3634ad45a5e6b5799c767f3feb2ae7ea +dist/2025-05-12/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=1650c464df6d87fcf3cea65722a515a1f1625d9e1ad6d27359455ecab849a592 +dist/2025-05-12/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=1c4f6c22361665705334faf35a0a7c17d55fb3fbd2622721e8cd7c76418cfc41 +dist/2025-05-12/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=f75400fc72fd358be80cbedefc53a9002fe6cc22637687e941835acb8c5eced0 +dist/2025-05-12/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=f1a2db6029e9d881dbfe7c6589873b323358d8317865824705c0cd358fa3ef49 +dist/2025-05-12/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=9cc0a2212a36bfb39379008b781304da67c74ab4ce0909da18f8cad50fcbbfd0 +dist/2025-05-12/clippy-beta-i686-pc-windows-gnu.tar.gz=06051eca41cbd1b570725847b4d8b79f29bd20ac06878ef5689167626fd4b137 +dist/2025-05-12/clippy-beta-i686-pc-windows-gnu.tar.xz=857d43d424e718e04714562132802aa5fc9028945a3c40c34508abd165a909c1 +dist/2025-05-12/clippy-beta-i686-pc-windows-msvc.tar.gz=58bf660a2f3ecf4671de4624b12b5a35f1e530d3c16f47eb7e114d1deb1891ad +dist/2025-05-12/clippy-beta-i686-pc-windows-msvc.tar.xz=5a36ec9ff4e35f1a49775e6657ea4f65543b47ebbb776fa1c60fa7898666de62 +dist/2025-05-12/clippy-beta-i686-unknown-linux-gnu.tar.gz=30df536f3cf6fbea2cf745ca8177f88831ed5b5e25d8fbdeee5f300fb35b97fe +dist/2025-05-12/clippy-beta-i686-unknown-linux-gnu.tar.xz=a491efcade35834adcbcfa8f08004b6a181a8d8fbe36f6a1bfd8e092443a82ad +dist/2025-05-12/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=a16579fb92973f609f0eb215d81e1125ad9dfa9e22d5d869236bbe0a7bf8050c +dist/2025-05-12/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=45ff10aa52e6162b015b1a927dd23ef7404fbbec554e5a1b655c085d59a378e7 +dist/2025-05-12/clippy-beta-loongarch64-unknown-linux-musl.tar.gz=37e4ca4776fb278cac2ac05ece43ae569780503d0b122545eebc7a746dca69f3 +dist/2025-05-12/clippy-beta-loongarch64-unknown-linux-musl.tar.xz=9c33b12b9c0a6d94b16a52066e3a1a8a2581db1c7549de002f0d6f4670021f0f +dist/2025-05-12/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=a7939ed010f6cef23e23e17c7ad905c6c0f4e549c85a8ae38d743232fe8de321 +dist/2025-05-12/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=21046d6fe31c0930e4611a18dcd48f5cacdcf3b64b5d035b4449b8b5af417254 +dist/2025-05-12/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=a03df872f97472d9a4310c8097042ef80ca859485fdb95ed9bcd853de3cbe9ec +dist/2025-05-12/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=925ff3b371f6c4ec871920c5e9fa5ab046f203c0af95f10f0996a750bd125582 +dist/2025-05-12/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=5f159a1913f6a5d10b5d5140093c9af4277d8a632db5cc116065a08fc0ff8bb6 +dist/2025-05-12/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=a2385ac96c42af4d77eb84ca70931e005aff1dc0e1ba272483ee82a837d96709 +dist/2025-05-12/clippy-beta-powerpc64le-unknown-linux-musl.tar.gz=9c289ed719cd18c8e5b883aeecc03e46f35b6b90d191b4fb0d0b4b6c7fc5073c +dist/2025-05-12/clippy-beta-powerpc64le-unknown-linux-musl.tar.xz=1a62cf477d5ad2ce4904a4438ab5756f75b894288a7449ae70c9f63d3b7badda +dist/2025-05-12/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=c1abab08e81632db27613f3ac7036d8ffdeaf92e345b345bf2c3535f4d9c16f0 +dist/2025-05-12/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=611252f8b142af9a86e511ae783f41cc97104d2e5ec5835c7d5006421ff6207c +dist/2025-05-12/clippy-beta-s390x-unknown-linux-gnu.tar.gz=d436be0f0f72db3c4933e8e34fcbb71e33b90ddcca58bc4b4360fe22e7a89404 +dist/2025-05-12/clippy-beta-s390x-unknown-linux-gnu.tar.xz=9f8086f13b6f53d44f03bc53fa3d750a9f4dc13b3612b10dba48958f4b61706d +dist/2025-05-12/clippy-beta-x86_64-apple-darwin.tar.gz=1b4a51c42bcc9e3241ceaceab3fb22bbf8060e9f4c2c55357603c1bf2fbf75f2 +dist/2025-05-12/clippy-beta-x86_64-apple-darwin.tar.xz=42556126bad0e0554dc5464396383c75a1fcb76257249c62ca4e40971129c458 +dist/2025-05-12/clippy-beta-x86_64-pc-windows-gnu.tar.gz=59a2a00a0c4e05cd0900fd119f43d4354b9f6b9df9dd9a9b44a1cfee9c674eb3 +dist/2025-05-12/clippy-beta-x86_64-pc-windows-gnu.tar.xz=35290a11740a2fc0c02d534375ca4ac0392de41f281383d7396179f670ddf309 +dist/2025-05-12/clippy-beta-x86_64-pc-windows-msvc.tar.gz=db01970a436b89d5fe3cb5eb65ea075f7dfd15b649958b35ea8d88835d8fe1c3 +dist/2025-05-12/clippy-beta-x86_64-pc-windows-msvc.tar.xz=9df8c8ed117b2e975bcb0520601c9b4e19e0440b14d9e510d09c9b54b872379f +dist/2025-05-12/clippy-beta-x86_64-unknown-freebsd.tar.gz=736361d62d33e969bda4cb98ea592ee7128e88c047f05b77cc025c982c27acb6 +dist/2025-05-12/clippy-beta-x86_64-unknown-freebsd.tar.xz=72f50e46dd2697c32b20ac2d0ae9ae2ea10485225dfd41dc9fa4e24d3b61a26e +dist/2025-05-12/clippy-beta-x86_64-unknown-illumos.tar.gz=4c856630844d01f655dc9855efb3685c2c30fcf199edfe665d9cf4230774ae0d +dist/2025-05-12/clippy-beta-x86_64-unknown-illumos.tar.xz=70bad50bffa518c4658e44dda7b6723558d68a545511228b97e18efc37a3ad0b +dist/2025-05-12/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=4c1e0fc35732f19effc50e67f637c57699ed7e846e4201db3897740c1e34a43a +dist/2025-05-12/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=fe53a5340c93485ac496453752a15222d323755cb20427b29b952b49f317a4bc +dist/2025-05-12/clippy-beta-x86_64-unknown-linux-musl.tar.gz=c56f80644373fbe9bb87310d26876a86325fccb1756716db30a5bf70293d328c +dist/2025-05-12/clippy-beta-x86_64-unknown-linux-musl.tar.xz=f4597f7ed6d0def07a32e952330cc964e49d42f84d65eead84192a29978c1a41 +dist/2025-05-12/clippy-beta-x86_64-unknown-netbsd.tar.gz=ecbc80189d470c1cc221360b94964fbd26d52b7583ea065cdd52795a48bf6271 +dist/2025-05-12/clippy-beta-x86_64-unknown-netbsd.tar.xz=f08204b9216fcb127934f2ceefeb7abe4338bb2ab79576a3a2e2077201f521e6 +dist/2025-05-12/rustfmt-nightly-aarch64-apple-darwin.tar.gz=269b22b568f60889c4841feff1c11d9c151d2655d134e966f7344f7affc6db57 +dist/2025-05-12/rustfmt-nightly-aarch64-apple-darwin.tar.xz=474f13aa57c73f4f9e3c63edb9a126ca845e63a376b7b8e35b5c6aa8fb0d9573 +dist/2025-05-12/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=9f24753d7abc9aa196a72ac54bb574f5eb375ecd5b2da42d0ed34bf0fb8eb947 +dist/2025-05-12/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=daae34864734810ff8ea563db7bf691f6c0fa56b9087fe285f7a3060247ef6e3 +dist/2025-05-12/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=c21f59bc03b8097f066be7bd3a7d0febe873f321583a4c7a9a0cdf5448d92ced +dist/2025-05-12/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=574fce0d0ff06850db47da008fdc6c6551f2cc459f63f69dcf8edae5e5ff51eb +dist/2025-05-12/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=6379365fb729e0f5d57873ad028f0c2641d60bc19ac5c905a2d1772b6730cb93 +dist/2025-05-12/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=a274c20436d31f74b4144f165a2b383297316f1f96b0d89b2b86bbf38e57be98 +dist/2025-05-12/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=03c3270a78c5d62517ec1b5c61414634ad58e5d4afb914f31bdc12ee0893ff2b +dist/2025-05-12/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=b309c052cdae48b23c2e89dcd7362af97f50181745191dee596ac176c2ade8a0 +dist/2025-05-12/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=300baf318827928f0c824e20ccc8966d3fe9e5b5f62a0d1aeba5feae1d183a11 +dist/2025-05-12/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=09b764e2038499d23b28b8cbdb01c9480f2100a01d864b7f03905bc78412fa00 +dist/2025-05-12/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=47c087899d4155750e71a261a0c93c9f736530d991dfa7e34c1a7bb7f2aedd8b +dist/2025-05-12/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=7e589aaaac2ab2c1211e5f5e1090b2ce1633f8b8682425aff01afd4dbd25e088 +dist/2025-05-12/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=0169fb75018dd644d7ed842472c04a5c82d46f3bfebe6d49931839809d1824b7 +dist/2025-05-12/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=96f3e288c8ccf073b1ea983ba382e341c8f6664135ad9aed7168bc05cf06ac4e +dist/2025-05-12/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=29b1f7a4b1454bb1c6af1e720e05bda846725a8e866266a147335920e99e66a9 +dist/2025-05-12/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=71a2f81ff29fd7e4c8dbdb2ce85bebf5e8ea5889cbb41f98fd3c3816918a6a3d +dist/2025-05-12/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=ae5458b4c0d58bc3e307c289aa44daf82218aaafc7911dadd4a09f4ca7cf6e12 +dist/2025-05-12/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=cf19b582a8336aa3f3959803cb24ad4499bc529bd58cd0766e668af5083de93b +dist/2025-05-12/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=474a34a9566402e313f5fcfaefe29188a6db1c0bd17caa20f186787267ac8e5d +dist/2025-05-12/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=c02f75eaa71f6c4d613a80dc7092d57cd4f6ef8a7de7511711fa818c0612da24 +dist/2025-05-12/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.gz=95b47139ab6e9c16acee5ac78744c3e9ac917a5e811f45adfec4fddd45e98cf3 +dist/2025-05-12/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.xz=fe13340e51d7d81629e03019d375a72874b80f19420c77ea083292a22a9be589 +dist/2025-05-12/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=a95ed14a5bc2f926c2ffb5dfe49813817638154edef7f29522661c57ec2dec09 +dist/2025-05-12/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=d9060c0aa08e0ade2fb54fb5381f0f69dc94166741200b2ed35a46b5d9885036 +dist/2025-05-12/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=060213e707c6b8911517e786b21515e169e062bbbf96302e012a442d260789e1 +dist/2025-05-12/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=f1d4dd54017937490f559a472893fb8a00236b46bf0f57ef9222ec3bbd191004 +dist/2025-05-12/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=38a57b7fac63608992995b3b983643ae213f6fa3d6a1021691334d84a5491542 +dist/2025-05-12/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=f26658ea60a6424707a027b1e36488f99490bce045978c3919c7320638f60d68 +dist/2025-05-12/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.gz=07fbca58abf5fc57560e20fe7aede77137dd3f2f4cf2a6da11a80eaf6672bed3 +dist/2025-05-12/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.xz=f56f7bb1091fbb1a8d1583beb586194e5dd526f7a0268b4ebe997e0ce7c9d9cb +dist/2025-05-12/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=3ec40438a95a086a1c4c522c6ae018393469f605b03d392562fca4926bdf0631 +dist/2025-05-12/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=d7c342edbefe3fc22631961c2aca53cb808bc8f1df17673ec5cafcc56eaf0475 +dist/2025-05-12/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=4c1a2aa84e8e1c67a111b9a622b2c6ed96eebcec9752ccc5e940460ce048f22e +dist/2025-05-12/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=e26a0359223ca793d34ac9e4e5731923c4531dcdbf32aa8789bc9d1bda17013f +dist/2025-05-12/rustfmt-nightly-x86_64-apple-darwin.tar.gz=dbf20af35cbe11baab7ead72ec254717642b01fdf30140589510413058af3e49 +dist/2025-05-12/rustfmt-nightly-x86_64-apple-darwin.tar.xz=7beb25f2df0877ee74231abe03e74a09c6e41a356d0cea27956b2091382dbf47 +dist/2025-05-12/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=527d2d68bfd519d49936fd8941a04d787df1edf8c2c3ecc39103d55d1683a970 +dist/2025-05-12/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=8744bef9d00d6f7397ef2b1b36971ad7af6389e93b5286ca60feb6137c4f6b10 +dist/2025-05-12/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=50f8f2db4f410e60a6cd4ad03a762ea636076d85af05d511f40d2d2ea98bc833 +dist/2025-05-12/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=183f8742c505ab1d0488ca915509c1b0558166c6d19d8dc864d0a1686d66a791 +dist/2025-05-12/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=f042a8c4ef96911b2cc6cc2228ff832229196b4ab5b1b04b05b22b5b9a90649d +dist/2025-05-12/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=9b93acd9cb8c8e062f3e47f5415adb8eae67479318b6201bf66119d467b81e11 +dist/2025-05-12/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=fe9073a3bbd3b6513ba0fc38005b8ab1d44052e1bb10c1976bc98a62f8df5934 +dist/2025-05-12/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=4c99f67e351758fe0db0bc7cdfe177018083b9ada2feeee952180b420e2c6ac9 +dist/2025-05-12/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=c5a5702c66ae7de6b7a10d1c8c39af6c973c6eeebbc1fdba3b427c1ec9588756 +dist/2025-05-12/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=8da51f6150fa5c53dead4c3db2c2d7493cc46b36d64b978e605a9d5755dfd779 +dist/2025-05-12/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=3d77d2579fcb53a9bb6d942d44353f7b818b10504b64b790ecc3630d8b17a565 +dist/2025-05-12/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=7e75748bcb8b25bebeb1b5aeb2afc2fc1c48f38ccff9c624cd002a8e051424b7 +dist/2025-05-12/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=9c05c902b0db8fd8f8b44d83a95bc8722bb714d333d2a61a2e1ef140092b6d83 +dist/2025-05-12/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=d614cb69e1484f3653bc148280e7518640ec830ab8f02ddf512206ac265d6746 +dist/2025-05-12/rustc-nightly-aarch64-apple-darwin.tar.gz=ac2c35cd19b85e6356bcdb987031314afbb7e41f26418ddb0d943fc3482245c6 +dist/2025-05-12/rustc-nightly-aarch64-apple-darwin.tar.xz=a3c53f15d7b6f7c7e5f1e55c107663ef102cdb123394bcbe8a8c9c32a7e715f5 +dist/2025-05-12/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=29e3bae16967111ce72d00b931d32410ab526617bf1c88bbf90e4d32825ea7dd +dist/2025-05-12/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=116103ab4251b366644239f8ef8d7129ae3d9588d768b8e66671497b1fa36c95 +dist/2025-05-12/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=911acda80c362dd7690e5a4596e166b8ea49425f6dbbfd78ef697e69dc826c85 +dist/2025-05-12/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=9cabea351ef05117d8cdfae0df334c98b12a99c4191d3e4f382c336c326520dc +dist/2025-05-12/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=81c9ed04939e8d363e060ef2808bee8dbd63435b111f37325bc8fd2891726560 +dist/2025-05-12/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=a44b2f887aeafd5ff57ff67d8c4eeaa94cb4edd2f7d5912618ee186a4d609c73 +dist/2025-05-12/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=7a4047a85297d3012c00377241f3daa50b34ddc54d68d67787d76eb45f5db616 +dist/2025-05-12/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=09acd09fbfa3c43738c43c8c423d3fce6dc4451ca4ee8650ab3392279cfc288a +dist/2025-05-12/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=88ffa28a612cfb661a731dd4feeb6d6fae88d7236469ded88ee74a06a1576a8f +dist/2025-05-12/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=7c5747fb16062a786ffba5d00e1bc0e3c81ccf6154f09e21a6aa5b87c2fc9594 +dist/2025-05-12/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=c1bd5074d4664f0ac8019151aea13e051cf2d89b8bd8fa77b9ed3831a1b7c217 +dist/2025-05-12/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=20fa9e5531e4be0e54af97c8d033722c68d54ef984be3619ad84be6b579d0c73 +dist/2025-05-12/rustc-nightly-i686-pc-windows-gnu.tar.gz=fe7511b5bf7830efeec083d3414e389286ec117b53db0501d5c314eba24e3bdd +dist/2025-05-12/rustc-nightly-i686-pc-windows-gnu.tar.xz=95677d845a5c7677b951300f17d810301397df022145f16674a58ebb1cd52a56 +dist/2025-05-12/rustc-nightly-i686-pc-windows-msvc.tar.gz=a8f1e4852ffab09aeab1ccc09fff930444871fd3b490e68a1f9ae504c0dce6ed +dist/2025-05-12/rustc-nightly-i686-pc-windows-msvc.tar.xz=11fd3093a95e379d6472f063bfdccf6f3cf6c44956d68d121adcd1c927812eba +dist/2025-05-12/rustc-nightly-i686-unknown-linux-gnu.tar.gz=d95876f9a84ebcc97033c81dd07fe8852f0f472db94c074f5029458fec512d2e +dist/2025-05-12/rustc-nightly-i686-unknown-linux-gnu.tar.xz=766182f4d375138f4871abba6a8b50c3ca342edb7842b6d4bf7162e466cb32fe +dist/2025-05-12/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=58e41cb37fb5b974a78e7891c7aca2786bdf8153ac9cd134b713fc73771017b3 +dist/2025-05-12/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=ec6990871579f86c0587a6f7262bb53dd7de3a79a39ca55b994475ad96f20f4f +dist/2025-05-12/rustc-nightly-loongarch64-unknown-linux-musl.tar.gz=39b7b026e95bdee7eba78804d2f8f3703a141ff37c24ac636deb755fc669f081 +dist/2025-05-12/rustc-nightly-loongarch64-unknown-linux-musl.tar.xz=0b066061a1a55836b3b81667c0c35d864055578370f00365db7226fc41f0f11c +dist/2025-05-12/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=040b0718e4f460bb6136628ce24dca390608671b609d8e222e4ccbfedff43d6e +dist/2025-05-12/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=f9206ff2fad2acaab1b3a30e1d7a634384533329f71ceed5ef2fce0bd288bd43 +dist/2025-05-12/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=9c6c12d9d5486c4d26d1f7d9a61625a20e3e7703af79195ec4cb7e7e22358f4e +dist/2025-05-12/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=2cace3cec2973aa8f93f1d5bbe8cdcb36134fc2313b0131c51d2d4885bb18492 +dist/2025-05-12/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=60adf24efc4a8207709ccb39bf45ff5fb08c4a853de816c239a2aec795c22e46 +dist/2025-05-12/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=038e9220451a497885e7886a293986b37b83979a4a6f70b112d42245f9e4a924 +dist/2025-05-12/rustc-nightly-powerpc64le-unknown-linux-musl.tar.gz=66d700e4a734f1a1a4f2c5d9125fee2c20e400b85a4a72ec4d6963f7d438a591 +dist/2025-05-12/rustc-nightly-powerpc64le-unknown-linux-musl.tar.xz=1198a73d12b6f556a5016a2181e1c95adf929f24df1be5a17b1ff8cf6635656f +dist/2025-05-12/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=e1b12d459eeed0496a93db5ca6962bd15bd307a400e8bb870623d20479d75aa0 +dist/2025-05-12/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=2339af50b563056c4ad58cff24b1d59198e71e06c85f1860461e9384a0aeac0a +dist/2025-05-12/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=4977999e15a893215a7f86ad55e195249f63c416b7a0bee3423950575a952d1e +dist/2025-05-12/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=5745e2dd22c39abd35b19117b5514ba383058c057265b3003cda3da4aadfa18b +dist/2025-05-12/rustc-nightly-x86_64-apple-darwin.tar.gz=008b5b604e3fb66026eca67f29ed65262f85a2e305286a5ad11642edc8eaee2a +dist/2025-05-12/rustc-nightly-x86_64-apple-darwin.tar.xz=b2c071998e209e6b4989eae799938268dee9d8ada531956d41147e747128f328 +dist/2025-05-12/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=8791712c5513a077d2936dd26c7157b12fd8b4bfc93180f97273eb534461837f +dist/2025-05-12/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=02fd232fa95660aa19665089a191fe350d0dfc44fcee4436be28fad82324fd00 +dist/2025-05-12/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=9f7d67cadca7abf25c5445a9f7c911a3e0a2db2e52c088cc6833e40b52bef0de +dist/2025-05-12/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=ef2853ac4f2a5c6932f16768fb1df277b9edb8d91615869b8cfa574d6bda026a +dist/2025-05-12/rustc-nightly-x86_64-unknown-freebsd.tar.gz=117efae53fc69e481498c1f268bbb12e382f479dc6859ad04fdfc4a84659d677 +dist/2025-05-12/rustc-nightly-x86_64-unknown-freebsd.tar.xz=14b67230c06ed6ec7597e31c6b7385782ab6a1f6bc723c5d2f171defa02c669d +dist/2025-05-12/rustc-nightly-x86_64-unknown-illumos.tar.gz=881a6c5ff0222eaca1fa278fb517963b30f51714c3724956bb2d29c142af0add +dist/2025-05-12/rustc-nightly-x86_64-unknown-illumos.tar.xz=3e708bcafdf8da1ceb92ad0e27407ea210144d91e30ba2486bd6758085153caf +dist/2025-05-12/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=b264a719d90f6842e3cbc8dc7d74ec356328f0a94cca279795ada5f4b22c54ed +dist/2025-05-12/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=fbe22ac8c9995feac7b13f92b8d4c16fc1cdfb4a15c06e127420762db0198443 +dist/2025-05-12/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=48cf6d33fdba4e38dcc19710efd24eb863fe13bbca634e0ca02fc1647255bd6a +dist/2025-05-12/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=7767dd1b6baf7065dfc74b4e9ce4c200616294ecd664243c6fe756522fb4a328 +dist/2025-05-12/rustc-nightly-x86_64-unknown-netbsd.tar.gz=bde7b39870fbce418257278ae56159af3f80f1688efd01d6d52b16127fd0b64a +dist/2025-05-12/rustc-nightly-x86_64-unknown-netbsd.tar.xz=6018c06dda8f5a0ff5ef7754bf2e8692b2dfd48be525d896261aea27d682f4e5 From 2ce08ca5d6046600ff641bfa4018247f3b9451c5 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Sat, 10 May 2025 10:51:12 +0200 Subject: [PATCH 2199/4206] update cfg(bootstrap) --- compiler/rustc_ast/src/lib.rs | 1 - compiler/rustc_ast_lowering/src/lib.rs | 1 - compiler/rustc_ast_passes/src/lib.rs | 1 - .../rustc_attr_data_structures/src/lib.rs | 1 - compiler/rustc_attr_parsing/src/lib.rs | 1 - compiler/rustc_borrowck/src/lib.rs | 1 - compiler/rustc_builtin_macros/src/lib.rs | 1 - compiler/rustc_codegen_llvm/src/lib.rs | 1 - compiler/rustc_codegen_ssa/src/lib.rs | 1 - compiler/rustc_const_eval/src/lib.rs | 1 - compiler/rustc_driver_impl/src/lib.rs | 1 - compiler/rustc_errors/src/lib.rs | 1 - compiler/rustc_expand/src/lib.rs | 1 - compiler/rustc_fluent_macro/src/fluent.rs | 3 - compiler/rustc_hir/src/lib.rs | 1 - compiler/rustc_hir_analysis/src/lib.rs | 1 - compiler/rustc_hir_pretty/src/lib.rs | 1 - compiler/rustc_hir_typeck/src/lib.rs | 1 - compiler/rustc_infer/src/lib.rs | 1 - compiler/rustc_interface/src/lib.rs | 1 - compiler/rustc_lint/src/lib.rs | 1 - compiler/rustc_macros/src/lib.rs | 1 - compiler/rustc_metadata/src/lib.rs | 1 - compiler/rustc_middle/src/lib.rs | 1 - compiler/rustc_mir_build/src/lib.rs | 1 - compiler/rustc_mir_dataflow/src/lib.rs | 1 - compiler/rustc_mir_transform/src/lib.rs | 1 - compiler/rustc_monomorphize/src/lib.rs | 1 - compiler/rustc_parse/src/lib.rs | 1 - compiler/rustc_passes/src/lib.rs | 1 - compiler/rustc_privacy/src/lib.rs | 1 - compiler/rustc_query_system/src/lib.rs | 1 - compiler/rustc_resolve/src/lib.rs | 1 - compiler/rustc_sanitizers/src/lib.rs | 1 - compiler/rustc_session/src/lib.rs | 1 - compiler/rustc_span/src/lib.rs | 1 - compiler/rustc_symbol_mangling/src/lib.rs | 1 - compiler/rustc_target/src/lib.rs | 1 - compiler/rustc_trait_selection/src/lib.rs | 1 - compiler/rustc_ty_utils/src/lib.rs | 1 - library/alloc/src/string.rs | 4 +- library/alloctests/tests/fmt.rs | 2 +- library/core/src/char/convert.rs | 4 +- library/core/src/fmt/rt.rs | 8 - library/core/src/future/async_drop.rs | 2 - library/core/src/future/mod.rs | 1 - library/core/src/intrinsics/mod.rs | 13 +- library/core/src/intrinsics/simd.rs | 4 +- library/core/src/marker.rs | 3 +- library/core/src/num/f128.rs | 4 +- library/core/src/num/f16.rs | 4 +- library/core/src/num/f32.rs | 4 +- library/core/src/num/f64.rs | 4 +- library/core/src/num/int_macros.rs | 4 +- library/core/src/num/uint_macros.rs | 4 +- library/core/src/ops/index.rs | 4 +- library/core/src/panicking.rs | 1 - library/core/src/pin.rs | 12 - library/core/src/pin/unsafe_pinned.rs | 2 +- library/core/src/prelude/v1.rs | 1 - library/core/src/slice/mod.rs | 12 +- library/core/src/str/mod.rs | 4 +- library/coretests/tests/pin_macro.rs | 1 - library/std/src/f128.rs | 225 +++++++----------- library/std/src/f16.rs | 225 +++++++----------- library/std/src/io/error.rs | 2 +- library/std/src/lib.rs | 1 - library/std/src/prelude/v1.rs | 1 - library/std/src/thread/mod.rs | 2 +- library/std/tests/floats/f128.rs | 32 --- library/std/tests/floats/f16.rs | 30 --- library/std/tests/floats/lib.rs | 4 +- .../crates/proc-macro-srv/src/tests/mod.rs | 2 - 73 files changed, 216 insertions(+), 452 deletions(-) diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index c08622cac864a..89a5a67eb5342 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -6,7 +6,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc( html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(attr(deny(warnings))) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 8597820073a56..f8e59ac81c24d 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -32,7 +32,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index 7956057f88ee7..6517fdb55bd3f 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -4,7 +4,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(rust_logo)] #![feature(box_patterns)] #![feature(if_let_guard)] diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs index 679fe935484e8..dbfc95b047ae4 100644 --- a/compiler/rustc_attr_data_structures/src/lib.rs +++ b/compiler/rustc_attr_data_structures/src/lib.rs @@ -1,6 +1,5 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(rust_logo)] #![feature(rustdoc_internals)] // tidy-alphabetical-end diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 874fccf7ff6da..177df3567420e 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -77,7 +77,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(rust_logo)] #![feature(rustdoc_internals)] #![recursion_limit = "256"] diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 3e075d420a3a9..676cb618b725b 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2,7 +2,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index c2f5bf0f4571f..9cd4d17059a0f 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -5,7 +5,6 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index e8010ec9fc495..5736314b96a36 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -6,7 +6,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 4f9757f198b84..0e410be5a0627 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -2,7 +2,6 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 7a0c2543c3002..bf7a79dcb20f0 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -1,7 +1,6 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 95cfe221d3fe1..056c476d5e120 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -7,7 +7,6 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(decl_macro)] diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 6f37bad9bb462..f8e19e5077893 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -7,7 +7,6 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 79f838e2e33f2..cd744977bb323 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -1,7 +1,6 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(rust_logo)] #![feature(array_windows)] #![feature(associated_type_defaults)] diff --git a/compiler/rustc_fluent_macro/src/fluent.rs b/compiler/rustc_fluent_macro/src/fluent.rs index c96bb48a0368c..d58c70674f6aa 100644 --- a/compiler/rustc_fluent_macro/src/fluent.rs +++ b/compiler/rustc_fluent_macro/src/fluent.rs @@ -25,9 +25,6 @@ fn invocation_relative_path_to_absolute(span: Span, path: &str) -> PathBuf { path.to_path_buf() } else { // `/a/b/c/foo/bar.rs` contains the current macro invocation - #[cfg(bootstrap)] - let mut source_file_path = span.source_file().path(); - #[cfg(not(bootstrap))] let mut source_file_path = span.local_file().unwrap(); // `/a/b/c/foo/` source_file_path.pop(); diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 5533920aee4ab..7a5ff8906896e 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -4,7 +4,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(bootstrap, feature(let_chains))] #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(closure_track_caller)] diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index d010f1fc85164..4937eb73a8be5 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -59,7 +59,6 @@ This API is completely unstable and subject to change. #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 09bf84ab64fbe..04f9c831b0ac0 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -2,7 +2,6 @@ //! the definitions in this file have equivalents in `rustc_ast_pretty`. // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(let_chains))] #![recursion_limit = "256"] // tidy-alphabetical-end diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 60187abd55897..161f5e981d430 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -1,7 +1,6 @@ // tidy-alphabetical-start #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(bootstrap, feature(let_chains))] #![feature(array_windows)] #![feature(box_patterns)] #![feature(if_let_guard)] diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 8b2aab4204228..ab7b7060c0922 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -16,7 +16,6 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index 4128070718308..ce2398fab9197 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -1,5 +1,4 @@ // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(let_chains))] #![feature(decl_macro)] #![feature(file_buffered)] #![feature(iter_intersperse)] diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index b910d6a138e11..4ff586a79a6ec 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -21,7 +21,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 62ca7ce3ca995..81817018cb14d 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -1,6 +1,5 @@ // tidy-alphabetical-start #![allow(rustc::default_hash_types)] -#![cfg_attr(bootstrap, feature(let_chains))] #![feature(if_let_guard)] #![feature(never_type)] #![feature(proc_macro_diagnostic)] diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 3931be1654a35..97b67140fa2d4 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -1,6 +1,5 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(coroutines)] diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 979608df79c08..cb3fdd4d3f76e 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -28,7 +28,6 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(allocator_api)] diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index a051cf570b7d1..8c7003b778761 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -3,7 +3,6 @@ // tidy-alphabetical-start #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(bootstrap, feature(let_chains))] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(if_let_guard)] diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index 658fbf505e446..2e8c916544160 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -1,5 +1,4 @@ // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(let_chains))] #![feature(assert_matches)] #![feature(associated_type_defaults)] #![feature(box_patterns)] diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index dc0eacd36130b..10dbb3437dcbf 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -1,5 +1,4 @@ // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(let_chains))] #![feature(array_windows)] #![feature(assert_matches)] #![feature(box_patterns)] diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 1b484da698aab..5c66017bc6113 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -1,5 +1,4 @@ // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(let_chains))] #![feature(array_windows)] #![feature(file_buffered)] #![feature(if_let_guard)] diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index d06922f1e0479..3ab726d9d9d64 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -4,7 +4,6 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(bootstrap, feature(let_chains))] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(debug_closure_helpers)] diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 001725e28827d..f9445485f6054 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -6,7 +6,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(box_patterns)] diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index a3b479fdb7a98..9c2921cd5b22c 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1,6 +1,5 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(associated_type_defaults)] diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index b159b876c7e63..eba7378b475ef 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -1,6 +1,5 @@ // tidy-alphabetical-start #![allow(rustc::potential_query_instability, internal_features)] -#![cfg_attr(bootstrap, feature(let_chains))] #![feature(assert_matches)] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 4c47e9ed6992c..9ba70abd4d933 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -10,7 +10,6 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] diff --git a/compiler/rustc_sanitizers/src/lib.rs b/compiler/rustc_sanitizers/src/lib.rs index 729c921450ea0..7d7c1c8284db6 100644 --- a/compiler/rustc_sanitizers/src/lib.rs +++ b/compiler/rustc_sanitizers/src/lib.rs @@ -4,7 +4,6 @@ //! compiler. // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(let_chains))] // tidy-alphabetical-end pub mod cfi; diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index ec8e9898dc71e..5e5872ee06815 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -1,6 +1,5 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(bootstrap, feature(let_chains))] #![feature(default_field_values)] #![feature(iter_intersperse)] #![feature(rustc_attrs)] diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 61c96e67c17f8..22ca8accf9fde 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -17,7 +17,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index a51d7da878a29..a9bf5eae445e4 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -89,7 +89,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index 922c18448d51a..566bee75c7f3c 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -9,7 +9,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 7613a0cef52a7..67328defe36b5 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -14,7 +14,6 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index f79b6d44bfdfd..929cc074bdac7 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -6,7 +6,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index cd9e04a915aa2..4e42a5da7eacb 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1832,7 +1832,7 @@ impl String { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] #[rustc_confusables("length", "size")] - #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] + #[rustc_no_implicit_autorefs] pub const fn len(&self) -> usize { self.vec.len() } @@ -1852,7 +1852,7 @@ impl String { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] - #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] + #[rustc_no_implicit_autorefs] pub const fn is_empty(&self) -> bool { self.len() == 0 } diff --git a/library/alloctests/tests/fmt.rs b/library/alloctests/tests/fmt.rs index a20e8c623360f..dbcf0c3a11410 100644 --- a/library/alloctests/tests/fmt.rs +++ b/library/alloctests/tests/fmt.rs @@ -1,7 +1,7 @@ #![deny(warnings)] // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint #![allow(static_mut_refs)] -#![cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] +#![allow(unnecessary_transmutes)] use std::cell::RefCell; use std::fmt::{self, Write}; diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs index d820965a7463e..fd17f92f7be08 100644 --- a/library/core/src/char/convert.rs +++ b/library/core/src/char/convert.rs @@ -21,7 +21,7 @@ pub(super) const fn from_u32(i: u32) -> Option { /// Converts a `u32` to a `char`, ignoring validity. See [`char::from_u32_unchecked`]. #[inline] #[must_use] -#[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] +#[allow(unnecessary_transmutes)] pub(super) const unsafe fn from_u32_unchecked(i: u32) -> char { // SAFETY: the caller must guarantee that `i` is a valid char value. unsafe { @@ -222,7 +222,7 @@ impl FromStr for char { } #[inline] -#[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] +#[allow(unnecessary_transmutes)] const fn char_try_from_u32(i: u32) -> Result { // This is an optimized version of the check // (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF), diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index c2a8a39bcac8f..7fd8d3e5b5319 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -19,14 +19,6 @@ pub struct Placeholder { pub width: Count, } -#[cfg(bootstrap)] -impl Placeholder { - #[inline] - pub const fn new(position: usize, flags: u32, precision: Count, width: Count) -> Self { - Self { position, flags, precision, width } - } -} - /// Used by [width](https://doc.rust-lang.org/std/fmt/#width) /// and [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers. #[lang = "format_count"] diff --git a/library/core/src/future/async_drop.rs b/library/core/src/future/async_drop.rs index fc4f95a98b42d..c48c3f2ba281e 100644 --- a/library/core/src/future/async_drop.rs +++ b/library/core/src/future/async_drop.rs @@ -24,7 +24,6 @@ use crate::task::{Context, Poll}; /// are `Copy` get implicitly duplicated by the compiler, making it very /// hard to predict when, and how often destructors will be executed. As such, /// these types cannot have destructors. -#[cfg(not(bootstrap))] #[unstable(feature = "async_drop", issue = "126482")] #[lang = "async_drop"] pub trait AsyncDrop { @@ -42,7 +41,6 @@ pub trait AsyncDrop { } /// Async drop. -#[cfg(not(bootstrap))] #[unstable(feature = "async_drop", issue = "126482")] #[lang = "async_drop_in_place"] pub async unsafe fn async_drop_in_place(_to_drop: *mut T) { diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs index 4b5a2f34d3f3e..2b16a568b4031 100644 --- a/library/core/src/future/mod.rs +++ b/library/core/src/future/mod.rs @@ -20,7 +20,6 @@ mod pending; mod poll_fn; mod ready; -#[cfg(not(bootstrap))] #[unstable(feature = "async_drop", issue = "126482")] pub use async_drop::{AsyncDrop, async_drop_in_place}; #[stable(feature = "into_future", since = "1.64.0")] diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index c7220fe7c4acf..effdc3c63eeaa 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -1476,7 +1476,7 @@ pub const fn forget(_: T); /// Turning raw bytes (`[u8; SZ]`) into `u32`, `f64`, etc.: /// /// ``` -/// # #![cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] +/// # #![allow(unnecessary_transmutes)] /// let raw_bytes = [0x78, 0x56, 0x34, 0x12]; /// /// let num = unsafe { @@ -3413,7 +3413,6 @@ pub const fn contract_check_requires bool + Copy>(cond: C) { /// returns false. /// /// Note that this function is a no-op during constant evaluation. -#[cfg(not(bootstrap))] #[unstable(feature = "contracts_internals", issue = "128044")] // Similar to `contract_check_requires`, we need to use the user-facing // `contracts` feature rather than the perma-unstable `contracts_internals`. @@ -3437,16 +3436,6 @@ pub const fn contract_check_ensures bool + Copy, Ret>(cond: C, re ) } -/// This is the old version of contract_check_ensures kept here for bootstrap only. -#[cfg(bootstrap)] -#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)] -#[rustc_intrinsic] -pub fn contract_check_ensures<'a, Ret, C: Fn(&'a Ret) -> bool>(ret: &'a Ret, cond: C) { - if contract_checks() && !cond(ret) { - crate::panicking::panic_nounwind("failed ensures check"); - } -} - /// The intrinsic will return the size stored in that vtable. /// /// # Safety diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index 86e3f8509ee29..40efc2630689b 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -34,7 +34,7 @@ pub const unsafe fn simd_extract(x: T, idx: u32) -> U; /// /// `idx` must be in-bounds of the vector. #[rustc_nounwind] -#[cfg_attr(not(bootstrap), rustc_intrinsic)] +#[rustc_intrinsic] pub unsafe fn simd_insert_dyn(mut x: T, idx: u32, val: U) -> T { // SAFETY: `idx` must be in-bounds unsafe { (&raw mut x).cast::().add(idx as usize).write(val) } @@ -51,7 +51,7 @@ pub unsafe fn simd_insert_dyn(mut x: T, idx: u32, val: U) -> T { /// /// `idx` must be in-bounds of the vector. #[rustc_nounwind] -#[cfg_attr(not(bootstrap), rustc_intrinsic)] +#[rustc_intrinsic] pub unsafe fn simd_extract_dyn(x: T, idx: u32) -> U { // SAFETY: `idx` must be in-bounds unsafe { (&raw const x).cast::().add(idx as usize).read() } diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 9dc20beda6c64..f33b8d188d86c 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -885,8 +885,7 @@ marker_impls! { /// /// This is part of [RFC 3467](https://rust-lang.github.io/rfcs/3467-unsafe-pinned.html), and is /// tracked by [#125735](https://github.com/rust-lang/rust/issues/125735). -#[cfg_attr(not(bootstrap), lang = "unsafe_unpin")] -#[cfg_attr(bootstrap, allow(dead_code))] +#[lang = "unsafe_unpin"] pub(crate) unsafe auto trait UnsafeUnpin {} impl !UnsafeUnpin for UnsafePinned {} diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 8020b36c6fa6e..7e470185c86d1 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -893,7 +893,7 @@ impl f128 { #[inline] #[unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] - #[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] + #[allow(unnecessary_transmutes)] pub const fn to_bits(self) -> u128 { // SAFETY: `u128` is a plain old datatype so we can always transmute to it. unsafe { mem::transmute(self) } @@ -941,7 +941,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] + #[allow(unnecessary_transmutes)] pub const fn from_bits(v: u128) -> Self { // It turns out the safety issues with sNaN were overblown! Hooray! // SAFETY: `u128` is a plain old datatype so we can always transmute from it. diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 68201400a1d5d..e47900cba550a 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -881,7 +881,7 @@ impl f16 { #[inline] #[unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] - #[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] + #[allow(unnecessary_transmutes)] pub const fn to_bits(self) -> u16 { // SAFETY: `u16` is a plain old datatype so we can always transmute to it. unsafe { mem::transmute(self) } @@ -928,7 +928,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] + #[allow(unnecessary_transmutes)] pub const fn from_bits(v: u16) -> Self { // It turns out the safety issues with sNaN were overblown! Hooray! // SAFETY: `u16` is a plain old datatype so we can always transmute from it. diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index da241785d6427..5fbc6eb33f170 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1085,7 +1085,7 @@ impl f32 { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[rustc_const_stable(feature = "const_float_bits_conv", since = "1.83.0")] #[inline] - #[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] + #[allow(unnecessary_transmutes)] pub const fn to_bits(self) -> u32 { // SAFETY: `u32` is a plain old datatype so we can always transmute to it. unsafe { mem::transmute(self) } @@ -1131,7 +1131,7 @@ impl f32 { #[rustc_const_stable(feature = "const_float_bits_conv", since = "1.83.0")] #[must_use] #[inline] - #[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] + #[allow(unnecessary_transmutes)] pub const fn from_bits(v: u32) -> Self { // It turns out the safety issues with sNaN were overblown! Hooray! // SAFETY: `u32` is a plain old datatype so we can always transmute from it. diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index c8544771a9047..81ab0f14c2bc3 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1083,7 +1083,7 @@ impl f64 { without modifying the original"] #[stable(feature = "float_bits_conv", since = "1.20.0")] #[rustc_const_stable(feature = "const_float_bits_conv", since = "1.83.0")] - #[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] + #[allow(unnecessary_transmutes)] #[inline] pub const fn to_bits(self) -> u64 { // SAFETY: `u64` is a plain old datatype so we can always transmute to it. @@ -1130,7 +1130,7 @@ impl f64 { #[rustc_const_stable(feature = "const_float_bits_conv", since = "1.83.0")] #[must_use] #[inline] - #[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] + #[allow(unnecessary_transmutes)] pub const fn from_bits(v: u64) -> Self { // It turns out the safety issues with sNaN were overblown! Hooray! // SAFETY: `u64` is a plain old datatype so we can always transmute from it. diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 8d31a7b697a80..84e1482ed31db 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -3675,7 +3675,7 @@ macro_rules! int_impl { /// ``` #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] + #[allow(unnecessary_transmutes)] // SAFETY: const sound because integers are plain old datatypes so we can always // transmute them to arrays of bytes #[must_use = "this returns the result of the operation, \ @@ -3779,7 +3779,7 @@ macro_rules! int_impl { /// ``` #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] + #[allow(unnecessary_transmutes)] #[must_use] // SAFETY: const sound because integers are plain old datatypes so we can always // transmute to them diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index bc6cb9508167d..f38d809c1544b 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -3523,7 +3523,7 @@ macro_rules! uint_impl { #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] + #[allow(unnecessary_transmutes)] // SAFETY: const sound because integers are plain old datatypes so we can always // transmute them to arrays of bytes #[inline] @@ -3625,7 +3625,7 @@ macro_rules! uint_impl { /// ``` #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[cfg_attr(not(bootstrap), allow(unnecessary_transmutes))] + #[allow(unnecessary_transmutes)] #[must_use] // SAFETY: const sound because integers are plain old datatypes so we can always // transmute to them diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs index 8106c088f0ba2..46e19bed43aba 100644 --- a/library/core/src/ops/index.rs +++ b/library/core/src/ops/index.rs @@ -67,7 +67,7 @@ pub trait Index { /// /// May panic if the index is out of bounds. #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] + #[rustc_no_implicit_autorefs] #[track_caller] fn index(&self, index: Idx) -> &Self::Output; } @@ -172,7 +172,7 @@ pub trait IndexMut: Index { /// /// May panic if the index is out of bounds. #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] + #[rustc_no_implicit_autorefs] #[track_caller] fn index_mut(&mut self, index: Idx) -> &mut Self::Output; } diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 83a45436b3050..d87f4814f0218 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -206,7 +206,6 @@ pub mod panic_const { } // Separated panic constants list for async drop feature // (May be joined when the corresponding lang items will be in the bootstrap) - #[cfg(not(bootstrap))] panic_const! { panic_const_coroutine_resumed_drop = "coroutine resumed after async drop", panic_const_async_fn_resumed_drop = "`async fn` resumed after async drop", diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index dd1c2f2c28513..aa8207f8ff40e 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1093,9 +1093,6 @@ pub use self::unsafe_pinned::UnsafePinned; #[derive(Copy, Clone)] pub struct Pin { /// Only public for bootstrap. - #[cfg(bootstrap)] - pub pointer: Ptr, - #[cfg(not(bootstrap))] pointer: Ptr, } @@ -1936,7 +1933,6 @@ unsafe impl PinCoerceUnsized for *mut T {} /// constructor. /// /// [`Box::pin`]: ../../std/boxed/struct.Box.html#method.pin -#[cfg(not(bootstrap))] #[stable(feature = "pin_macro", since = "1.68.0")] #[rustc_macro_transparency = "semitransparent"] #[allow_internal_unstable(super_let)] @@ -1947,11 +1943,3 @@ pub macro pin($value:expr $(,)?) { unsafe { $crate::pin::Pin::new_unchecked(&mut pinned) } } } - -/// Only for bootstrap. -#[cfg(bootstrap)] -#[stable(feature = "pin_macro", since = "1.68.0")] -#[rustc_macro_transparency = "semitransparent"] -pub macro pin($value:expr $(,)?) { - $crate::pin::Pin::<&mut _> { pointer: &mut { $value } } -} diff --git a/library/core/src/pin/unsafe_pinned.rs b/library/core/src/pin/unsafe_pinned.rs index 5fb628c8adbc5..f65e83662fef8 100644 --- a/library/core/src/pin/unsafe_pinned.rs +++ b/library/core/src/pin/unsafe_pinned.rs @@ -21,7 +21,7 @@ use crate::{fmt, ptr}; /// Use `UnsafeCell` for that. /// /// This type blocks niches the same way `UnsafeCell` does. -#[cfg_attr(not(bootstrap), lang = "unsafe_pinned")] +#[lang = "unsafe_pinned"] #[repr(transparent)] #[unstable(feature = "unsafe_pinned", issue = "125735")] pub struct UnsafePinned { diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index 9737d0baec7ca..8f1b5275871e6 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -59,7 +59,6 @@ pub use crate::hash::macros::Hash; #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow(deprecated)] -#[cfg_attr(bootstrap, allow(deprecated_in_future))] #[doc(no_inline)] pub use crate::{ assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args, diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 88b6674d4cccc..058491b53a16f 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -109,7 +109,7 @@ impl [T] { #[lang = "slice_len_fn"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_slice_len", since = "1.39.0")] - #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] + #[rustc_no_implicit_autorefs] #[inline] #[must_use] pub const fn len(&self) -> usize { @@ -129,7 +129,7 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_slice_is_empty", since = "1.39.0")] - #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] + #[rustc_no_implicit_autorefs] #[inline] #[must_use] pub const fn is_empty(&self) -> bool { @@ -564,7 +564,7 @@ impl [T] { /// assert_eq!(None, v.get(0..4)); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] + #[rustc_no_implicit_autorefs] #[inline] #[must_use] pub fn get(&self, index: I) -> Option<&I::Output> @@ -590,7 +590,7 @@ impl [T] { /// assert_eq!(x, &[0, 42, 2]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] + #[rustc_no_implicit_autorefs] #[inline] #[must_use] pub fn get_mut(&mut self, index: I) -> Option<&mut I::Output> @@ -628,7 +628,7 @@ impl [T] { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] + #[rustc_no_implicit_autorefs] #[inline] #[must_use] pub unsafe fn get_unchecked(&self, index: I) -> &I::Output @@ -671,7 +671,7 @@ impl [T] { /// assert_eq!(x, &[1, 13, 4]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] + #[rustc_no_implicit_autorefs] #[inline] #[must_use] pub unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index dafabba645c61..9e7e949b722d7 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -134,7 +134,7 @@ impl str { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_len", since = "1.39.0")] #[rustc_diagnostic_item = "str_len"] - #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] + #[rustc_no_implicit_autorefs] #[must_use] #[inline] pub const fn len(&self) -> usize { @@ -154,7 +154,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_is_empty", since = "1.39.0")] - #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] + #[rustc_no_implicit_autorefs] #[must_use] #[inline] pub const fn is_empty(&self) -> bool { diff --git a/library/coretests/tests/pin_macro.rs b/library/coretests/tests/pin_macro.rs index 3174c91a6498b..bfbfa8d280fa1 100644 --- a/library/coretests/tests/pin_macro.rs +++ b/library/coretests/tests/pin_macro.rs @@ -38,7 +38,6 @@ fn rust_2024_expr() { } #[test] -#[cfg(not(bootstrap))] fn temp_lifetime() { // Check that temporary lifetimes work as in Rust 2021. // Regression test for https://github.com/rust-lang/rust/issues/138596 diff --git a/library/std/src/f128.rs b/library/std/src/f128.rs index 2b416b13fa59c..6b2ba2e714c9b 100644 --- a/library/std/src/f128.rs +++ b/library/std/src/f128.rs @@ -22,10 +22,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let f = 3.7_f128; @@ -53,10 +52,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let f = 3.01_f128; @@ -84,10 +82,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let f = 3.3_f128; @@ -120,10 +117,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let f = 3.3_f128; @@ -154,10 +150,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let f = 3.7_f128; @@ -186,10 +181,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = 3.6_f128; @@ -227,10 +221,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let m = 10.0_f128; @@ -275,10 +268,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let a: f128 = 7.0; @@ -321,10 +313,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let a: f128 = 7.0; @@ -362,10 +353,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = 2.0_f128; @@ -394,10 +384,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = 2.0_f128; @@ -430,10 +419,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let positive = 4.0_f128; @@ -465,10 +453,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let one = 1.0f128; @@ -500,10 +487,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let f = 2.0f128; @@ -535,10 +521,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let one = 1.0f128; @@ -555,10 +540,9 @@ impl f128 { /// Non-positive values: /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// assert_eq!(0_f128.ln(), f128::NEG_INFINITY); @@ -590,10 +574,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let five = 5.0f128; @@ -608,10 +591,9 @@ impl f128 { /// Non-positive values: /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// assert_eq!(0_f128.log(10.0), f128::NEG_INFINITY); @@ -639,10 +621,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let two = 2.0f128; @@ -657,10 +638,9 @@ impl f128 { /// Non-positive values: /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// assert_eq!(0_f128.log2(), f128::NEG_INFINITY); @@ -688,10 +668,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let ten = 10.0f128; @@ -706,10 +685,9 @@ impl f128 { /// Non-positive values: /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// assert_eq!(0_f128.log10(), f128::NEG_INFINITY); @@ -739,10 +717,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = 8.0f128; @@ -779,10 +756,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = 2.0f128; @@ -813,10 +789,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = std::f128::consts::FRAC_PI_2; @@ -845,10 +820,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = 2.0 * std::f128::consts::PI; @@ -880,10 +854,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = std::f128::consts::FRAC_PI_4; @@ -916,10 +889,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let f = std::f128::consts::FRAC_PI_2; @@ -955,10 +927,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let f = std::f128::consts::FRAC_PI_4; @@ -993,10 +964,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let f = 1.0f128; @@ -1035,10 +1005,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// // Positive angles measured counter-clockwise @@ -1081,10 +1050,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = std::f128::consts::FRAC_PI_4; @@ -1120,10 +1088,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = 1e-8_f128; @@ -1160,10 +1127,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = 1e-8_f128; @@ -1179,10 +1145,9 @@ impl f128 { /// Out-of-range values: /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// assert_eq!((-1.0_f128).ln_1p(), f128::NEG_INFINITY); @@ -1212,10 +1177,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let e = std::f128::consts::E; @@ -1251,10 +1215,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let e = std::f128::consts::E; @@ -1290,10 +1253,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let e = std::f128::consts::E; @@ -1326,10 +1288,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = 1.0f128; @@ -1362,10 +1323,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = 1.0f128; @@ -1400,10 +1360,9 @@ impl f128 { /// /// ``` /// #![feature(f128)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let e = std::f128::consts::E; @@ -1438,10 +1397,9 @@ impl f128 { /// ``` /// #![feature(f128)] /// #![feature(float_gamma)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = 5.0f128; @@ -1477,10 +1435,9 @@ impl f128 { /// ``` /// #![feature(f128)] /// #![feature(float_gamma)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// let x = 2.0f128; @@ -1516,10 +1473,9 @@ impl f128 { /// ``` /// #![feature(f128)] /// #![feature(float_erf)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// /// The error function relates what percent of a normal distribution lies /// /// within `x` standard deviations (scaled by `1/sqrt(2)`). @@ -1559,10 +1515,9 @@ impl f128 { /// ``` /// #![feature(f128)] /// #![feature(float_erf)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f128_math)] { /// let x: f128 = 0.123; /// diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs index 3f88ab2d400e9..d6bc1d3118aed 100644 --- a/library/std/src/f16.rs +++ b/library/std/src/f16.rs @@ -22,10 +22,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let f = 3.7_f16; @@ -53,10 +52,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let f = 3.01_f16; @@ -84,10 +82,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let f = 3.3_f16; @@ -120,10 +117,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let f = 3.3_f16; @@ -154,10 +150,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let f = 3.7_f16; @@ -186,10 +181,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = 3.6_f16; @@ -227,10 +221,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let m = 10.0_f16; @@ -275,10 +268,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let a: f16 = 7.0; @@ -321,10 +313,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let a: f16 = 7.0; @@ -362,10 +353,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = 2.0_f16; @@ -394,10 +384,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = 2.0_f16; @@ -430,10 +419,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let positive = 4.0_f16; @@ -465,10 +453,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let one = 1.0f16; @@ -500,10 +487,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let f = 2.0f16; @@ -535,10 +521,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let one = 1.0f16; @@ -555,10 +540,9 @@ impl f16 { /// Non-positive values: /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// assert_eq!(0_f16.ln(), f16::NEG_INFINITY); @@ -590,10 +574,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let five = 5.0f16; @@ -608,10 +591,9 @@ impl f16 { /// Non-positive values: /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// assert_eq!(0_f16.log(10.0), f16::NEG_INFINITY); @@ -639,10 +621,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let two = 2.0f16; @@ -657,10 +638,9 @@ impl f16 { /// Non-positive values: /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// assert_eq!(0_f16.log2(), f16::NEG_INFINITY); @@ -688,10 +668,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let ten = 10.0f16; @@ -706,10 +685,9 @@ impl f16 { /// Non-positive values: /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// assert_eq!(0_f16.log10(), f16::NEG_INFINITY); @@ -738,10 +716,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = 8.0f16; @@ -777,10 +754,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = 2.0f16; @@ -811,10 +787,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = std::f16::consts::FRAC_PI_2; @@ -843,10 +818,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = 2.0 * std::f16::consts::PI; @@ -878,10 +852,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = std::f16::consts::FRAC_PI_4; @@ -914,10 +887,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let f = std::f16::consts::FRAC_PI_2; @@ -953,10 +925,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let f = std::f16::consts::FRAC_PI_4; @@ -991,10 +962,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let f = 1.0f16; @@ -1033,10 +1003,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// // Positive angles measured counter-clockwise @@ -1079,10 +1048,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = std::f16::consts::FRAC_PI_4; @@ -1118,10 +1086,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = 1e-4_f16; @@ -1158,10 +1125,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = 1e-4_f16; @@ -1177,10 +1143,9 @@ impl f16 { /// Out-of-range values: /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// assert_eq!((-1.0_f16).ln_1p(), f16::NEG_INFINITY); @@ -1210,10 +1175,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let e = std::f16::consts::E; @@ -1249,10 +1213,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let e = std::f16::consts::E; @@ -1288,10 +1251,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let e = std::f16::consts::E; @@ -1324,10 +1286,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = 1.0f16; @@ -1360,10 +1321,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = 1.0f16; @@ -1398,10 +1358,9 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let e = std::f16::consts::E; @@ -1436,10 +1395,9 @@ impl f16 { /// ``` /// #![feature(f16)] /// #![feature(float_gamma)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = 5.0f16; @@ -1475,10 +1433,9 @@ impl f16 { /// ``` /// #![feature(f16)] /// #![feature(float_gamma)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// let x = 2.0f16; @@ -1514,10 +1471,9 @@ impl f16 { /// ``` /// #![feature(f16)] /// #![feature(float_erf)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// /// The error function relates what percent of a normal distribution lies /// /// within `x` standard deviations (scaled by `1/sqrt(2)`). @@ -1557,10 +1513,9 @@ impl f16 { /// ``` /// #![feature(f16)] /// #![feature(float_erf)] - /// # #![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] - /// # #![cfg_attr(not(bootstrap), expect(internal_features))] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] /// # #[cfg(not(miri))] - /// # #[cfg(not(bootstrap))] /// # #[cfg(target_has_reliable_f16_math)] { /// let x: f16 = 0.123; /// diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index cf3778bd29071..ba765a6203f2f 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -48,7 +48,7 @@ use crate::{error, fmt, result, sys}; /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), doc(search_unbox))] +#[doc(search_unbox)] pub type Result = result::Result; /// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index c011f9661ae7a..0bb40ee4b3177 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -718,7 +718,6 @@ pub use core::todo; // Re-export built-in macros defined through core. #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow(deprecated)] -#[cfg_attr(bootstrap, allow(deprecated_in_future))] pub use core::{ assert, assert_matches, cfg, column, compile_error, concat, concat_idents, const_format_args, env, file, format_args, format_args_nl, include, include_bytes, include_str, line, log_syntax, diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 68c9ac1e41463..c15d8c40085a5 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -46,7 +46,6 @@ pub use crate::result::Result::{self, Err, Ok}; // Re-exported built-in macros #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow(deprecated)] -#[cfg_attr(bootstrap, allow(deprecated_in_future))] #[doc(no_inline)] pub use core::prelude::v1::{ assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args, diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 6838f15e1748d..26b2fb4472436 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -1676,7 +1676,7 @@ impl fmt::Debug for Thread { /// [`Result`]: crate::result::Result /// [`std::panic::resume_unwind`]: crate::panic::resume_unwind #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), doc(search_unbox))] +#[doc(search_unbox)] pub type Result = crate::result::Result>; // This packet is used to communicate the return value between the spawned diff --git a/library/std/tests/floats/f128.rs b/library/std/tests/floats/f128.rs index 8b13d6e65587a..c2618f3b315e9 100644 --- a/library/std/tests/floats/f128.rs +++ b/library/std/tests/floats/f128.rs @@ -1,11 +1,9 @@ // FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy -#![cfg(not(bootstrap))] #![cfg(target_has_reliable_f128)] use std::f128::consts; use std::num::FpCategory as Fp; #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] use std::ops::Rem; use std::ops::{Add, Div, Mul, Sub}; @@ -23,7 +21,6 @@ const TOL: f128 = 1e-12; /// Tolerances for math that is allowed to be imprecise, usually due to multiple chained /// operations. #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] const TOL_IMPR: f128 = 1e-10; @@ -76,7 +73,6 @@ fn test_num_f128() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_num_f128_rem() { let ten = 10f128; @@ -86,7 +82,6 @@ fn test_num_f128_rem() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_min_nan() { assert_eq!(f128::NAN.min(2.0), 2.0); @@ -95,7 +90,6 @@ fn test_min_nan() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_max_nan() { assert_eq!(f128::NAN.max(2.0), 2.0); @@ -104,7 +98,6 @@ fn test_max_nan() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_minimum() { assert!(f128::NAN.minimum(2.0).is_nan()); @@ -113,7 +106,6 @@ fn test_minimum() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_maximum() { assert!(f128::NAN.maximum(2.0).is_nan()); @@ -272,7 +264,6 @@ fn test_classify() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_floor() { assert_approx_eq!(1.0f128.floor(), 1.0f128, TOL_PRECISE); @@ -289,7 +280,6 @@ fn test_floor() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_ceil() { assert_approx_eq!(1.0f128.ceil(), 1.0f128, TOL_PRECISE); @@ -306,7 +296,6 @@ fn test_ceil() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_round() { assert_approx_eq!(2.5f128.round(), 3.0f128, TOL_PRECISE); @@ -324,7 +313,6 @@ fn test_round() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_round_ties_even() { assert_approx_eq!(2.5f128.round_ties_even(), 2.0f128, TOL_PRECISE); @@ -342,7 +330,6 @@ fn test_round_ties_even() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_trunc() { assert_approx_eq!(1.0f128.trunc(), 1.0f128, TOL_PRECISE); @@ -359,7 +346,6 @@ fn test_trunc() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_fract() { assert_approx_eq!(1.0f128.fract(), 0.0f128, TOL_PRECISE); @@ -376,7 +362,6 @@ fn test_fract() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_abs() { assert_eq!(f128::INFINITY.abs(), f128::INFINITY); @@ -478,7 +463,6 @@ fn test_next_down() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_mul_add() { let nan: f128 = f128::NAN; @@ -497,7 +481,6 @@ fn test_mul_add() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_recip() { let nan: f128 = f128::NAN; @@ -521,7 +504,6 @@ fn test_recip() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_powi() { let nan: f128 = f128::NAN; @@ -538,7 +520,6 @@ fn test_powi() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_powf() { let nan: f128 = f128::NAN; @@ -557,7 +538,6 @@ fn test_powf() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_sqrt_domain() { assert!(f128::NAN.sqrt().is_nan()); @@ -571,7 +551,6 @@ fn test_sqrt_domain() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_exp() { assert_eq!(1.0, 0.0f128.exp()); @@ -588,7 +567,6 @@ fn test_exp() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_exp2() { assert_eq!(32.0, 5.0f128.exp2()); @@ -604,7 +582,6 @@ fn test_exp2() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_ln() { let nan: f128 = f128::NAN; @@ -622,7 +599,6 @@ fn test_ln() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_log() { let nan: f128 = f128::NAN; @@ -643,7 +619,6 @@ fn test_log() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_log2() { let nan: f128 = f128::NAN; @@ -662,7 +637,6 @@ fn test_log2() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_log10() { let nan: f128 = f128::NAN; @@ -714,7 +688,6 @@ fn test_to_radians() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_asinh() { // Lower accuracy results are allowed, use increased tolerances @@ -747,7 +720,6 @@ fn test_asinh() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_acosh() { assert_eq!(1.0f128.acosh(), 0.0f128); @@ -768,7 +740,6 @@ fn test_acosh() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_atanh() { assert_eq!(0.0f128.atanh(), 0.0f128); @@ -790,7 +761,6 @@ fn test_atanh() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_gamma() { // precision can differ among platforms @@ -813,7 +783,6 @@ fn test_gamma() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] fn test_ln_gamma() { assert_approx_eq!(1.0f128.ln_gamma().0, 0.0f128, TOL_IMPR); @@ -846,7 +815,6 @@ fn test_real_consts() { assert_approx_eq!(frac_2_pi, 2f128 / pi, TOL_PRECISE); #[cfg(not(miri))] - #[cfg(not(bootstrap))] #[cfg(target_has_reliable_f128_math)] { let frac_2_sqrtpi: f128 = consts::FRAC_2_SQRT_PI; diff --git a/library/std/tests/floats/f16.rs b/library/std/tests/floats/f16.rs index 8b3b344dd467b..70bbcd07160e6 100644 --- a/library/std/tests/floats/f16.rs +++ b/library/std/tests/floats/f16.rs @@ -1,5 +1,4 @@ // FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy -#![cfg(not(bootstrap))] #![cfg(target_has_reliable_f16)] use std::f16::consts; @@ -63,7 +62,6 @@ fn test_num_f16() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_min_nan() { assert_eq!(f16::NAN.min(2.0), 2.0); @@ -72,7 +70,6 @@ fn test_min_nan() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_max_nan() { assert_eq!(f16::NAN.max(2.0), 2.0); @@ -81,7 +78,6 @@ fn test_max_nan() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_minimum() { assert!(f16::NAN.minimum(2.0).is_nan()); @@ -90,7 +86,6 @@ fn test_minimum() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_maximum() { assert!(f16::NAN.maximum(2.0).is_nan()); @@ -249,7 +244,6 @@ fn test_classify() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_floor() { assert_approx_eq!(1.0f16.floor(), 1.0f16, TOL_0); @@ -266,7 +260,6 @@ fn test_floor() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_ceil() { assert_approx_eq!(1.0f16.ceil(), 1.0f16, TOL_0); @@ -283,7 +276,6 @@ fn test_ceil() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_round() { assert_approx_eq!(2.5f16.round(), 3.0f16, TOL_0); @@ -301,7 +293,6 @@ fn test_round() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_round_ties_even() { assert_approx_eq!(2.5f16.round_ties_even(), 2.0f16, TOL_0); @@ -319,7 +310,6 @@ fn test_round_ties_even() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_trunc() { assert_approx_eq!(1.0f16.trunc(), 1.0f16, TOL_0); @@ -336,7 +326,6 @@ fn test_trunc() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_fract() { assert_approx_eq!(1.0f16.fract(), 0.0f16, TOL_0); @@ -353,7 +342,6 @@ fn test_fract() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_abs() { assert_eq!(f16::INFINITY.abs(), f16::INFINITY); @@ -455,7 +443,6 @@ fn test_next_down() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_mul_add() { let nan: f16 = f16::NAN; @@ -474,7 +461,6 @@ fn test_mul_add() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_recip() { let nan: f16 = f16::NAN; @@ -492,7 +478,6 @@ fn test_recip() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_powi() { let nan: f16 = f16::NAN; @@ -509,7 +494,6 @@ fn test_powi() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_powf() { let nan: f16 = f16::NAN; @@ -528,7 +512,6 @@ fn test_powf() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_sqrt_domain() { assert!(f16::NAN.sqrt().is_nan()); @@ -542,7 +525,6 @@ fn test_sqrt_domain() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_exp() { assert_eq!(1.0, 0.0f16.exp()); @@ -559,7 +541,6 @@ fn test_exp() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_exp2() { assert_eq!(32.0, 5.0f16.exp2()); @@ -575,7 +556,6 @@ fn test_exp2() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_ln() { let nan: f16 = f16::NAN; @@ -593,7 +573,6 @@ fn test_ln() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_log() { let nan: f16 = f16::NAN; @@ -614,7 +593,6 @@ fn test_log() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_log2() { let nan: f16 = f16::NAN; @@ -633,7 +611,6 @@ fn test_log2() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_log10() { let nan: f16 = f16::NAN; @@ -683,7 +660,6 @@ fn test_to_radians() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_asinh() { assert_eq!(0.0f16.asinh(), 0.0f16); @@ -710,7 +686,6 @@ fn test_asinh() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_acosh() { assert_eq!(1.0f16.acosh(), 0.0f16); @@ -731,7 +706,6 @@ fn test_acosh() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_atanh() { assert_eq!(0.0f16.atanh(), 0.0f16); @@ -753,7 +727,6 @@ fn test_atanh() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_gamma() { // precision can differ among platforms @@ -776,7 +749,6 @@ fn test_gamma() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_ln_gamma() { assert_approx_eq!(1.0f16.ln_gamma().0, 0.0f16, TOL_0); @@ -811,7 +783,6 @@ fn test_real_consts() { assert_approx_eq!(frac_2_pi, 2f16 / pi, TOL_0); #[cfg(not(miri))] - #[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] { let frac_2_sqrtpi: f16 = consts::FRAC_2_SQRT_PI; @@ -874,7 +845,6 @@ fn test_clamp_max_is_nan() { #[test] #[cfg(not(miri))] -#[cfg(not(bootstrap))] #[cfg(target_has_reliable_f16_math)] fn test_total_cmp() { use core::cmp::Ordering; diff --git a/library/std/tests/floats/lib.rs b/library/std/tests/floats/lib.rs index 7884fc9239e20..453a2d533ab8a 100644 --- a/library/std/tests/floats/lib.rs +++ b/library/std/tests/floats/lib.rs @@ -1,6 +1,6 @@ #![feature(f16, f128, float_algebraic, float_gamma, float_minimum_maximum)] -#![cfg_attr(not(bootstrap), feature(cfg_target_has_reliable_f16_f128))] -#![cfg_attr(not(bootstrap), expect(internal_features))] // for reliable_f16_f128 +#![feature(cfg_target_has_reliable_f16_f128)] +#![expect(internal_features)] // for reliable_f16_f128 use std::fmt; use std::ops::{Add, Div, Mul, Rem, Sub}; diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs index 011221459657a..a81fea7bec695 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs @@ -97,7 +97,6 @@ fn test_fn_like_macro_clone_raw_ident() { } #[test] -#[cfg(not(bootstrap))] fn test_fn_like_fn_like_span_join() { assert_expand( "fn_like_span_join", @@ -112,7 +111,6 @@ fn test_fn_like_fn_like_span_join() { } #[test] -#[cfg(not(bootstrap))] fn test_fn_like_fn_like_span_ops() { assert_expand( "fn_like_span_ops", From 27cca0db9b00bf6e8451a146b46e168cda13c8ef Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Sat, 10 May 2025 10:52:34 +0200 Subject: [PATCH 2200/4206] x86_64-lynx-lynxos178 is now present in the stage0 --- src/bootstrap/src/core/sanity.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index eb0bf1d166a16..4b020a7edb7ba 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -34,7 +34,6 @@ pub struct Finder { // Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap). const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined - "x86_64-lynx-lynxos178", ]; /// Minimum version threshold for libstdc++ required when using prebuilt LLVM From 8e4b1c89f4515415244c623489b820eeed08edf4 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Sat, 10 May 2025 10:55:10 +0200 Subject: [PATCH 2201/4206] ./x clippy ci --fix --- src/bootstrap/src/bin/rustc.rs | 4 ++-- src/bootstrap/src/core/build_steps/clean.rs | 2 +- src/bootstrap/src/core/build_steps/clippy.rs | 2 +- src/bootstrap/src/core/build_steps/compile.rs | 2 +- src/bootstrap/src/core/build_steps/dist.rs | 10 ++++----- src/bootstrap/src/core/build_steps/install.rs | 2 +- src/bootstrap/src/core/build_steps/llvm.rs | 22 +++++++++---------- src/bootstrap/src/core/build_steps/setup.rs | 4 ++-- src/bootstrap/src/core/build_steps/test.rs | 4 ++-- src/bootstrap/src/core/builder/cargo.rs | 2 +- src/bootstrap/src/core/builder/mod.rs | 7 +++--- src/bootstrap/src/core/config/config.rs | 4 ++-- src/bootstrap/src/core/download.rs | 4 ++-- src/bootstrap/src/core/sanity.rs | 4 ++-- src/bootstrap/src/utils/helpers.rs | 4 ++-- src/bootstrap/src/utils/shared_helpers.rs | 2 +- 16 files changed, 39 insertions(+), 40 deletions(-) diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs index d8cae02456c0e..85c682a46c5d1 100644 --- a/src/bootstrap/src/bin/rustc.rs +++ b/src/bootstrap/src/bin/rustc.rs @@ -58,8 +58,8 @@ fn main() { let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set"); let on_fail = env::var_os("RUSTC_ON_FAIL").map(Command::new); - let rustc_real = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc)); - let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir)); + let rustc_real = env::var_os(rustc).unwrap_or_else(|| panic!("{rustc:?} was not set")); + let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{libdir:?} was not set")); let mut dylib_path = dylib_path(); dylib_path.insert(0, PathBuf::from(&libdir)); diff --git a/src/bootstrap/src/core/build_steps/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs index 21e9fea936387..882fcd087800b 100644 --- a/src/bootstrap/src/core/build_steps/clean.rs +++ b/src/bootstrap/src/core/build_steps/clean.rs @@ -129,7 +129,7 @@ fn clean_specific_stage(build: &Build, stage: u32) { for entry in entries { let entry = t!(entry); - let stage_prefix = format!("stage{}", stage); + let stage_prefix = format!("stage{stage}"); // if current entry is not related with the target stage, continue if !entry.file_name().to_str().unwrap_or("").contains(&stage_prefix) { diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index d3ab215d1b527..07fd51919d44f 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -59,7 +59,7 @@ fn lint_args(builder: &Builder<'_>, config: &LintConfig, ignored_rules: &[&str]) let all_args = std::env::args().collect::>(); args.extend(get_clippy_rules_in_order(&all_args, config)); - args.extend(ignored_rules.iter().map(|lint| format!("-Aclippy::{}", lint))); + args.extend(ignored_rules.iter().map(|lint| format!("-Aclippy::{lint}"))); args.extend(builder.config.free_args.clone()); args } diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 2e5865e509695..67daf81ee543f 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1771,7 +1771,7 @@ impl Step for Sysroot { } else if builder.download_rustc() && compiler.stage != builder.top_stage { host_dir.join("ci-rustc-sysroot") } else { - host_dir.join(format!("stage{}", stage)) + host_dir.join(format!("stage{stage}")) } }; let sysroot = sysroot_dir(compiler.stage); diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 3c412683b9492..aa2c7509c2a45 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1403,14 +1403,14 @@ impl Step for CodegenBackend { let backend = self.backend; let mut tarball = - Tarball::new(builder, &format!("rustc-codegen-{}", backend), &compiler.host.triple); + Tarball::new(builder, &format!("rustc-codegen-{backend}"), &compiler.host.triple); if backend == "cranelift" { tarball.set_overlay(OverlayKind::RustcCodegenCranelift); } else { - panic!("Unknown backend rustc_codegen_{}", backend); + panic!("Unknown backend rustc_codegen_{backend}"); } tarball.is_preview(true); - tarball.add_legal_and_readme_to(format!("share/doc/rustc_codegen_{}", backend)); + tarball.add_legal_and_readme_to(format!("share/doc/rustc_codegen_{backend}")); let src = builder.sysroot(compiler); let backends_src = builder.sysroot_codegen_backends(compiler); @@ -1422,7 +1422,7 @@ impl Step for CodegenBackend { // Don't use custom libdir here because ^lib/ will be resolved again with installer let backends_dst = PathBuf::from("lib").join(backends_rel); - let backend_name = format!("rustc_codegen_{}", backend); + let backend_name = format!("rustc_codegen_{backend}"); let mut found_backend = false; for backend in fs::read_dir(&backends_src).unwrap() { let file_name = backend.unwrap().file_name(); @@ -1623,7 +1623,7 @@ impl Step for Extended { let pkgbuild = |component: &str| { let mut cmd = command("pkgbuild"); cmd.arg("--identifier") - .arg(format!("org.rust-lang.{}", component)) + .arg(format!("org.rust-lang.{component}")) .arg("--scripts") .arg(pkg.join(component)) .arg("--nopayload") diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index 3e5069225d2bb..c31c40e846b0d 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -53,7 +53,7 @@ fn is_dir_writable_for_user(dir: &Path) -> bool { if e.kind() == std::io::ErrorKind::PermissionDenied { false } else { - panic!("Failed the write access check for the current user. {}", e); + panic!("Failed the write access check for the current user. {e}"); } } } diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 86af956535e5e..33a35372d1810 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -870,8 +870,8 @@ fn get_var(var_base: &str, host: &str, target: &str) -> Option { let kind = if host == target { "HOST" } else { "TARGET" }; let target_u = target.replace('-', "_"); env::var_os(format!("{var_base}_{target}")) - .or_else(|| env::var_os(format!("{}_{}", var_base, target_u))) - .or_else(|| env::var_os(format!("{}_{}", kind, var_base))) + .or_else(|| env::var_os(format!("{var_base}_{target_u}"))) + .or_else(|| env::var_os(format!("{kind}_{var_base}"))) .or_else(|| env::var_os(var_base)) } @@ -944,7 +944,7 @@ impl Step for Enzyme { } trace!(?target, "(re)building enzyme artifacts"); - builder.info(&format!("Building Enzyme for {}", target)); + builder.info(&format!("Building Enzyme for {target}")); t!(stamp.remove()); let _time = helpers::timeit(builder); t!(fs::create_dir_all(&out_dir)); @@ -1229,10 +1229,10 @@ fn supported_sanitizers( components .iter() .map(move |c| SanitizerRuntime { - cmake_target: format!("clang_rt.{}_{}_dynamic", c, os), + cmake_target: format!("clang_rt.{c}_{os}_dynamic"), path: out_dir - .join(format!("build/lib/darwin/libclang_rt.{}_{}_dynamic.dylib", c, os)), - name: format!("librustc-{}_rt.{}.dylib", channel, c), + .join(format!("build/lib/darwin/libclang_rt.{c}_{os}_dynamic.dylib")), + name: format!("librustc-{channel}_rt.{c}.dylib"), }) .collect() }; @@ -1241,9 +1241,9 @@ fn supported_sanitizers( components .iter() .map(move |c| SanitizerRuntime { - cmake_target: format!("clang_rt.{}-{}", c, arch), - path: out_dir.join(format!("build/lib/{}/libclang_rt.{}-{}.a", os, c, arch)), - name: format!("librustc-{}_rt.{}.a", channel, c), + cmake_target: format!("clang_rt.{c}-{arch}"), + path: out_dir.join(format!("build/lib/{os}/libclang_rt.{c}-{arch}.a")), + name: format!("librustc-{channel}_rt.{c}.a"), }) .collect() }; @@ -1362,8 +1362,8 @@ impl Step for CrtBeginEnd { for obj in objs { let base_name = unhashed_basename(&obj); assert!(base_name == "crtbegin" || base_name == "crtend"); - t!(fs::copy(&obj, out_dir.join(format!("{}S.o", base_name)))); - t!(fs::rename(&obj, out_dir.join(format!("{}.o", base_name)))); + t!(fs::copy(&obj, out_dir.join(format!("{base_name}S.o")))); + t!(fs::rename(&obj, out_dir.join(format!("{base_name}.o")))); } out_dir diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 9d07babe5196b..31ec462134d5d 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -552,7 +552,7 @@ Select which editor you would like to set up [default: None]: "; let mut input = String::new(); loop { - print!("{}", prompt_str); + print!("{prompt_str}"); io::stdout().flush()?; io::stdin().read_line(&mut input)?; @@ -764,7 +764,7 @@ fn create_editor_settings_maybe(config: &Config, editor: &EditorKind) -> io::Res _ => "Created", }; fs::write(&settings_path, editor.settings_template())?; - println!("{verb} `{}`", settings_filename); + println!("{verb} `{settings_filename}`"); } else { println!("\n{}", editor.settings_template()); } diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 29fb576f5740a..f708b6e9fd699 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1593,10 +1593,10 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the let build = builder.build.build; compiler = builder.compiler(compiler.stage - 1, build); let test_stage = compiler.stage + 1; - (test_stage, format!("stage{}-{}", test_stage, build)) + (test_stage, format!("stage{test_stage}-{build}")) } else { let stage = compiler.stage; - (stage, format!("stage{}-{}", stage, target)) + (stage, format!("stage{stage}-{target}")) }; if suite.ends_with("fulldeps") { diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index d625c2ef5847f..e41f6f16b0232 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -1278,5 +1278,5 @@ impl Builder<'_> { pub fn cargo_profile_var(name: &str, config: &Config) -> String { let profile = if config.rust_optimize.is_release() { "RELEASE" } else { "DEV" }; - format!("CARGO_PROFILE_{}_{}", profile, name) + format!("CARGO_PROFILE_{profile}_{name}") } diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 75cc5d3986b88..cc4fa953ddc5c 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -504,8 +504,8 @@ impl StepDescription { match std::path::absolute(p) { Ok(p) => p.strip_prefix(&builder.src).unwrap_or(&p).to_path_buf(), Err(e) => { - eprintln!("ERROR: {:?}", e); - panic!("Due to the above error, failed to resolve path: {:?}", p); + eprintln!("ERROR: {e:?}"); + panic!("Due to the above error, failed to resolve path: {p:?}"); } } }) @@ -694,8 +694,7 @@ impl<'a> ShouldRun<'a> { if !submodules_paths.iter().any(|sm_p| p.contains(sm_p)) { assert!( self.builder.src.join(p).exists(), - "`should_run.paths` should correspond to real on-disk paths - use `alias` if there is no relevant path: {}", - p + "`should_run.paths` should correspond to real on-disk paths - use `alias` if there is no relevant path: {p}" ); } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 65a3e7667e7f0..c8beca25bccc5 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -3042,7 +3042,7 @@ impl Config { let actual_hash = recorded .split_whitespace() .nth(2) - .unwrap_or_else(|| panic!("unexpected output `{}`", recorded)); + .unwrap_or_else(|| panic!("unexpected output `{recorded}`")); if actual_hash == checked_out_hash { // already checked out @@ -3297,7 +3297,7 @@ impl Config { } StringOrBool::String(s) if s == "if-unchanged" => if_unchanged(), StringOrBool::String(other) => { - panic!("unrecognized option for download-ci-llvm: {:?}", other) + panic!("unrecognized option for download-ci-llvm: {other:?}") } } } diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index da305fb18fa9e..64298964dad54 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -57,7 +57,7 @@ impl Config { if self.dry_run() { return; } - fs::remove_file(f).unwrap_or_else(|_| panic!("failed to remove {:?}", f)); + fs::remove_file(f).unwrap_or_else(|_| panic!("failed to remove {f:?}")); } /// Create a temporary directory in `out` and return its path. @@ -112,7 +112,7 @@ impl Config { // The latter one does not exist on NixOS when using tmpfs as root. let is_nixos = match File::open("/etc/os-release") { Err(e) if e.kind() == ErrorKind::NotFound => false, - Err(e) => panic!("failed to access /etc/os-release: {}", e), + Err(e) => panic!("failed to access /etc/os-release: {e}"), Ok(os_release) => BufReader::new(os_release).lines().any(|l| { let l = l.expect("reading /etc/os-release"); matches!(l.trim(), "ID=nixos" | "ID='nixos'" | "ID=\"nixos\"") diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 4b020a7edb7ba..eb7e3799a688d 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -117,8 +117,8 @@ pub fn check(build: &mut Build) { eprintln!( "\nYour system's libstdc++ version is too old for the `llvm.download-ci-llvm` option." ); - eprintln!("Current version detected: '{}'", version); - eprintln!("Minimum required version: '{}'", LIBSTDCXX_MIN_VERSION_THRESHOLD); + eprintln!("Current version detected: '{version}'"); + eprintln!("Minimum required version: '{LIBSTDCXX_MIN_VERSION_THRESHOLD}'"); eprintln!( "Consider upgrading libstdc++ or disabling the `llvm.download-ci-llvm` option." ); diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index b31b2757767c3..b29c1fb3889c2 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -329,7 +329,7 @@ pub fn start_process(cmd: &mut Command) -> impl FnOnce() -> String + use<> { Err(e) => fail(&format!("failed to execute command: {cmd:?}\nERROR: {e}")), }; - let command = format!("{:?}", cmd); + let command = format!("{cmd:?}"); move || { let output = child.wait_with_output().unwrap(); @@ -540,7 +540,7 @@ where use std::fmt::Write; input.as_ref().iter().fold(String::with_capacity(input.as_ref().len() * 2), |mut acc, &byte| { - write!(&mut acc, "{:02x}", byte).expect("Failed to write byte to the hex String."); + write!(&mut acc, "{byte:02x}").expect("Failed to write byte to the hex String."); acc }) } diff --git a/src/bootstrap/src/utils/shared_helpers.rs b/src/bootstrap/src/utils/shared_helpers.rs index 7b206c3ffe826..1297a53d48804 100644 --- a/src/bootstrap/src/utils/shared_helpers.rs +++ b/src/bootstrap/src/utils/shared_helpers.rs @@ -90,7 +90,7 @@ pub fn maybe_dump(dump_name: String, cmd: &Command) { let mut file = OpenOptions::new().create(true).append(true).open(dump_file).unwrap(); - let cmd_dump = format!("{:?}\n", cmd); + let cmd_dump = format!("{cmd:?}\n"); let cmd_dump = cmd_dump.replace(&env::var("BUILD_OUT").unwrap(), "${BUILD_OUT}"); let cmd_dump = cmd_dump.replace(&env::var("CARGO_HOME").unwrap(), "${CARGO_HOME}"); From 779dd35649c42b0f57a2338d4ccd344e8ba6ebe3 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Sat, 10 May 2025 10:58:23 +0200 Subject: [PATCH 2202/4206] manual clippy fixes --- library/proc_macro/src/bridge/arena.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/proc_macro/src/bridge/arena.rs b/library/proc_macro/src/bridge/arena.rs index 29636e793f614..bf5a5b5a81821 100644 --- a/library/proc_macro/src/bridge/arena.rs +++ b/library/proc_macro/src/bridge/arena.rs @@ -68,6 +68,7 @@ impl Arena { /// Allocates a byte slice with specified size from the current memory /// chunk. Returns `None` if there is no free space left to satisfy the /// request. + #[allow(clippy::mut_from_ref)] fn alloc_raw_without_grow(&self, bytes: usize) -> Option<&mut [MaybeUninit]> { let start = self.start.get().addr(); let old_end = self.end.get(); From c4c7f25c4cbf2615c59ee45343d05b0cf5046a6d Mon Sep 17 00:00:00 2001 From: nora <48135649+Noratrieb@users.noreply.github.com> Date: Mon, 12 May 2025 16:15:24 +0200 Subject: [PATCH 2203/4206] Remove cfg(bootstrap) Foe the bootstrap bump --- .../compiler-builtins/src/macros.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/src/macros.rs b/library/compiler-builtins/compiler-builtins/src/macros.rs index dbf7155344030..22e0dd27f2f5a 100644 --- a/library/compiler-builtins/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/compiler-builtins/src/macros.rs @@ -433,18 +433,6 @@ macro_rules! intrinsics { ) => ( // `#[naked]` definitions are referenced by other places, so we can't use `cfg` like the others pub mod $name { - // FIXME: when bootstrap supports `#[unsafe(naked)]` this duplication can be removed - #[cfg(bootstrap)] - #[naked] - #[allow(unused_unsafe)] - $(#[$($attr)*])* - #[cfg_attr(not(feature = "mangled-names"), 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)? { - unsafe { $($body)* } - } - - #[cfg(not(bootstrap))] #[unsafe(naked)] $(#[$($attr)*])* #[cfg_attr(not(feature = "mangled-names"), no_mangle)] From 60c32f61aeb5a22c1bd956b64fb9dfc24dd94fe5 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Mon, 12 May 2025 16:35:09 +0200 Subject: [PATCH 2204/4206] Move more tests/ui tests --- src/tools/tidy/src/issues.txt | 1 - src/tools/tidy/src/ui_tests.rs | 2 +- tests/ui/{ => attributes/positions}/used.rs | 9 ++++++++- .../ui/{ => attributes/positions}/used.stderr | 18 +++++++++++++----- tests/ui/attributes/used-issue-126789.rs | 6 ------ tests/ui/attributes/used-issue-126789.stderr | 10 ---------- .../attributes/used/used-not-dead-code-lint.rs | 10 ++++++++++ tests/ui/{ => codemap_tests}/utf8-bom.rs | 0 tests/ui/issues/issue-41628.rs | 7 ------- .../rfc-2457-non-ascii-idents}/utf8_idents.rs | 9 ++++----- 10 files changed, 36 insertions(+), 36 deletions(-) rename tests/ui/{ => attributes/positions}/used.rs (57%) rename tests/ui/{ => attributes/positions}/used.stderr (71%) delete mode 100644 tests/ui/attributes/used-issue-126789.rs delete mode 100644 tests/ui/attributes/used-issue-126789.stderr create mode 100644 tests/ui/attributes/used/used-not-dead-code-lint.rs rename tests/ui/{ => codemap_tests}/utf8-bom.rs (100%) delete mode 100644 tests/ui/issues/issue-41628.rs rename tests/ui/{ => rfcs/rfc-2457-non-ascii-idents}/utf8_idents.rs (62%) diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 2f0158609e088..2c20e21f451ab 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -2212,7 +2212,6 @@ ui/issues/issue-41479.rs ui/issues/issue-41498.rs ui/issues/issue-41549.rs ui/issues/issue-41604.rs -ui/issues/issue-41628.rs ui/issues/issue-41652/auxiliary/issue-41652-b.rs ui/issues/issue-41652/issue-41652.rs ui/issues/issue-41677.rs diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 44dd1e50f5b04..8f9b07c49acbe 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -17,7 +17,7 @@ use ignore::Walk; const ENTRY_LIMIT: u32 = 901; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: u32 = 1624; +const ISSUES_ENTRY_LIMIT: u32 = 1623; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/ui/used.rs b/tests/ui/attributes/positions/used.rs similarity index 57% rename from tests/ui/used.rs rename to tests/ui/attributes/positions/used.rs index f008724f428b3..7950fa773a109 100644 --- a/tests/ui/used.rs +++ b/tests/ui/attributes/positions/used.rs @@ -1,3 +1,6 @@ +//! Checks that `#[used]` cannot be used on invalid positions. +#![crate_type = "lib"] + #[used] static FOO: u32 = 0; // OK @@ -13,4 +16,8 @@ trait Bar {} #[used] //~ ERROR attribute must be applied to a `static` variable impl Bar for Foo {} -fn main() {} +// Regression test for . +extern "C" { + #[used] //~ ERROR attribute must be applied to a `static` variable + static BAR: i32; +} diff --git a/tests/ui/used.stderr b/tests/ui/attributes/positions/used.stderr similarity index 71% rename from tests/ui/used.stderr rename to tests/ui/attributes/positions/used.stderr index c586dc722932f..96dd43a3a937f 100644 --- a/tests/ui/used.stderr +++ b/tests/ui/attributes/positions/used.stderr @@ -1,5 +1,5 @@ error: attribute must be applied to a `static` variable - --> $DIR/used.rs:4:1 + --> $DIR/used.rs:7:1 | LL | #[used] | ^^^^^^^ @@ -7,7 +7,7 @@ LL | fn foo() {} | ----------- but this is a function error: attribute must be applied to a `static` variable - --> $DIR/used.rs:7:1 + --> $DIR/used.rs:10:1 | LL | #[used] | ^^^^^^^ @@ -15,7 +15,7 @@ LL | struct Foo {} | ------------- but this is a struct error: attribute must be applied to a `static` variable - --> $DIR/used.rs:10:1 + --> $DIR/used.rs:13:1 | LL | #[used] | ^^^^^^^ @@ -23,12 +23,20 @@ LL | trait Bar {} | ------------ but this is a trait error: attribute must be applied to a `static` variable - --> $DIR/used.rs:13:1 + --> $DIR/used.rs:16:1 | LL | #[used] | ^^^^^^^ LL | impl Bar for Foo {} | ------------------- but this is a implementation block -error: aborting due to 4 previous errors +error: attribute must be applied to a `static` variable + --> $DIR/used.rs:21:5 + | +LL | #[used] + | ^^^^^^^ +LL | static BAR: i32; + | ---------------- but this is a foreign static item + +error: aborting due to 5 previous errors diff --git a/tests/ui/attributes/used-issue-126789.rs b/tests/ui/attributes/used-issue-126789.rs deleted file mode 100644 index 90a1aa8d5cc3d..0000000000000 --- a/tests/ui/attributes/used-issue-126789.rs +++ /dev/null @@ -1,6 +0,0 @@ -extern "C" { - #[used] //~ ERROR attribute must be applied to a `static` variable - static FOO: i32; -} - -fn main() {} diff --git a/tests/ui/attributes/used-issue-126789.stderr b/tests/ui/attributes/used-issue-126789.stderr deleted file mode 100644 index 6014f7af95c55..0000000000000 --- a/tests/ui/attributes/used-issue-126789.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: attribute must be applied to a `static` variable - --> $DIR/used-issue-126789.rs:2:5 - | -LL | #[used] - | ^^^^^^^ -LL | static FOO: i32; - | ---------------- but this is a foreign static item - -error: aborting due to 1 previous error - diff --git a/tests/ui/attributes/used/used-not-dead-code-lint.rs b/tests/ui/attributes/used/used-not-dead-code-lint.rs new file mode 100644 index 0000000000000..ece40ed219d4a --- /dev/null +++ b/tests/ui/attributes/used/used-not-dead-code-lint.rs @@ -0,0 +1,10 @@ +//! Checks that the `dead_code` lint does not consider `#[used]` items unused. +//! Regression test for . + +//@ check-pass +#![deny(dead_code)] + +#[used] +static FOO: u32 = 0; + +fn main() {} diff --git a/tests/ui/utf8-bom.rs b/tests/ui/codemap_tests/utf8-bom.rs similarity index 100% rename from tests/ui/utf8-bom.rs rename to tests/ui/codemap_tests/utf8-bom.rs diff --git a/tests/ui/issues/issue-41628.rs b/tests/ui/issues/issue-41628.rs deleted file mode 100644 index 255e4243e0119..0000000000000 --- a/tests/ui/issues/issue-41628.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ check-pass -#![deny(dead_code)] - -#[used] -static FOO: u32 = 0; - -fn main() {} diff --git a/tests/ui/utf8_idents.rs b/tests/ui/rfcs/rfc-2457-non-ascii-idents/utf8_idents.rs similarity index 62% rename from tests/ui/utf8_idents.rs rename to tests/ui/rfcs/rfc-2457-non-ascii-idents/utf8_idents.rs index 0c34529d2de43..3997e27bc9f99 100644 --- a/tests/ui/utf8_idents.rs +++ b/tests/ui/rfcs/rfc-2457-non-ascii-idents/utf8_idents.rs @@ -1,14 +1,13 @@ +//! Check that non-ascii-idents are allowed. + //@ check-pass // #![allow(mixed_script_confusables, non_camel_case_types)] -fn foo< - 'β, - γ ->() {} +fn foo<'β, γ>() {} struct X { - δ: usize + δ: usize, } pub fn main() { From 65663b538fd8c3a593b0470b1d966100ac968a77 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 12 May 2025 14:26:59 +0000 Subject: [PATCH 2205/4206] chore(compiler_builtins): release v0.1.159 --- library/compiler-builtins/compiler-builtins/CHANGELOG.md | 6 ++++++ library/compiler-builtins/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-builtins/CHANGELOG.md b/library/compiler-builtins/compiler-builtins/CHANGELOG.md index f0af37ba0b238..a7c01c463ca68 100644 --- a/library/compiler-builtins/compiler-builtins/CHANGELOG.md +++ b/library/compiler-builtins/compiler-builtins/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.159](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.158...compiler_builtins-v0.1.159) - 2025-05-12 + +### Other + +- Remove cfg(bootstrap) + ## [0.1.158](https://github.com/rust-lang/compiler-builtins/compare/compiler_builtins-v0.1.157...compiler_builtins-v0.1.158) - 2025-05-06 ### Other diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index 81f708c48e646..d65a22152ef94 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Jorge Aparicio "] name = "compiler_builtins" -version = "0.1.158" +version = "0.1.159" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" From bebcb9da216ab439a8628219f8021b1770134a35 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 12 May 2025 14:49:12 +0000 Subject: [PATCH 2206/4206] Add test for Ord impl for Option::NonZero --- tests/codegen/option-niche-eq.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/codegen/option-niche-eq.rs b/tests/codegen/option-niche-eq.rs index 9c5ed9ce57a5e..2be9e2bc48927 100644 --- a/tests/codegen/option-niche-eq.rs +++ b/tests/codegen/option-niche-eq.rs @@ -24,6 +24,18 @@ pub fn non_zero_signed_eq(l: Option>, r: Option>) -> b l == r } +// Test for #49892 +// This currently relies on a manual implementation of `PartialOrd`/`Ord` for `Option` +// Once LLVM is better able to optimize this pattern, we can return to using a derive. +// CHECK-LABEL: @non_zero_ord +#[no_mangle] +pub fn non_zero_ord(a: Option>, b: Option>) -> bool { + // CHECK: start: + // CHECK-NEXT: icmp ult i32 + // CHECK-NEXT: ret i1 + a < b +} + // CHECK-LABEL: @non_null_eq #[no_mangle] pub fn non_null_eq(l: Option>, r: Option>) -> bool { From c12d12b1bb64abd3b694c7af703989ef3d8c1426 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 9 May 2025 09:28:42 -0400 Subject: [PATCH 2207/4206] Fix for renamed/removed UI tests --- tests/failing-ui-tests.txt | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/tests/failing-ui-tests.txt b/tests/failing-ui-tests.txt index 499c1a962311c..0a01a661c3577 100644 --- a/tests/failing-ui-tests.txt +++ b/tests/failing-ui-tests.txt @@ -10,7 +10,7 @@ tests/ui/sepcomp/sepcomp-fns-backwards.rs tests/ui/sepcomp/sepcomp-fns.rs tests/ui/sepcomp/sepcomp-statics.rs tests/ui/asm/x86_64/may_unwind.rs -tests/ui/catch-unwind-bang.rs +tests/ui/panics/catch-unwind-bang.rs tests/ui/drop/dynamic-drop-async.rs tests/ui/cfg/cfg-panic-abort.rs tests/ui/drop/repeat-drop.rs @@ -94,23 +94,14 @@ tests/ui/simd/intrinsic/generic-as.rs tests/ui/backtrace/backtrace.rs tests/ui/lifetimes/tail-expr-lock-poisoning.rs tests/ui/runtime/rt-explody-panic-payloads.rs -tests/ui/codegen/equal-pointers-unequal/as-cast/function.rs -tests/ui/codegen/equal-pointers-unequal/as-cast/basic.rs tests/ui/codegen/equal-pointers-unequal/as-cast/inline1.rs -tests/ui/codegen/equal-pointers-unequal/as-cast/print.rs tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.rs tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.rs -tests/ui/codegen/equal-pointers-unequal/exposed-provenance/function.rs -tests/ui/codegen/equal-pointers-unequal/exposed-provenance/basic.rs tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline1.rs -tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print.rs tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.rs tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.rs tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs -tests/ui/codegen/equal-pointers-unequal/strict-provenance/basic.rs -tests/ui/codegen/equal-pointers-unequal/strict-provenance/function.rs -tests/ui/codegen/equal-pointers-unequal/strict-provenance/print.rs tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline1.rs tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs From bef68d04d9be557d954dd89667da97c5565b21a1 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Mon, 12 May 2025 11:05:47 -0400 Subject: [PATCH 2208/4206] Update to nightly-2025-05-12 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index fbaa22190052e..a8cda28688c84 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2025-04-26" +channel = "nightly-2025-05-12" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] From 57011501d5c907b89d2854ebfb889d652024b4fc Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Mon, 12 May 2025 11:13:34 -0400 Subject: [PATCH 2209/4206] Fix for libgccjit 12 --- src/attributes.rs | 1 + src/intrinsic/mod.rs | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/attributes.rs b/src/attributes.rs index f933119d0ba09..e63091c6082a7 100644 --- a/src/attributes.rs +++ b/src/attributes.rs @@ -6,6 +6,7 @@ use rustc_attr_parsing::InlineAttr; use rustc_attr_parsing::InstructionSetAttr; #[cfg(feature = "master")] use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +#[cfg(feature = "master")] use rustc_middle::mir::TerminatorKind; use rustc_middle::ty; diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index 9caceca92957a..f292c467418f1 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -4,9 +4,7 @@ mod simd; #[cfg(feature = "master")] use std::iter; -#[cfg(feature = "master")] -use gccjit::FunctionType; -use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp}; +use gccjit::{ComparisonOp, Function, FunctionType, RValue, ToRValue, Type, UnaryOp}; #[cfg(feature = "master")] use rustc_abi::ExternAbi; use rustc_abi::{BackendRepr, HasDataLayout}; From 26316b86bce966336f2219305efbeb5f4e00a61e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 12 May 2025 15:30:48 +0000 Subject: [PATCH 2210/4206] Do not remove super keyword from super-let --- src/tools/rustfmt/src/items.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index 5c3be769f9e0d..e79b7803c6072 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -63,6 +63,11 @@ impl Rewrite for ast::Local { return Err(RewriteError::SkipFormatting); } + // FIXME(super_let): Implement formatting + if self.super_.is_some() { + return Err(RewriteError::SkipFormatting); + } + let attrs_str = self.attrs.rewrite_result(context, shape)?; let mut result = if attrs_str.is_empty() { "let ".to_owned() From 01e08a4c5ba414fe852467efeb90204477aa9d23 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Mon, 12 May 2025 18:23:44 +0200 Subject: [PATCH 2211/4206] Do not use `clippy_utils` from UI tests --- Cargo.toml | 1 - tests/ui/let_underscore_untyped.rs | 1 - tests/ui/let_underscore_untyped.stderr | 20 ++++++++++---------- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 92c4db845000a..0df9f2e555987 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,6 @@ pulldown-cmark = { version = "0.11", default-features = false, features = ["html askama = { version = "0.13", default-features = false, features = ["alloc", "config", "derive"] } # UI test dependencies -clippy_utils = { path = "clippy_utils" } if_chain = "1.0" quote = "1.0.25" syn = { version = "2.0", features = ["full"] } diff --git a/tests/ui/let_underscore_untyped.rs b/tests/ui/let_underscore_untyped.rs index 26ba8682dc2d5..7f74ab035bda8 100644 --- a/tests/ui/let_underscore_untyped.rs +++ b/tests/ui/let_underscore_untyped.rs @@ -6,7 +6,6 @@ extern crate proc_macros; use proc_macros::with_span; -use clippy_utils::is_from_proc_macro; use std::boxed::Box; use std::fmt::Display; use std::future::Future; diff --git a/tests/ui/let_underscore_untyped.stderr b/tests/ui/let_underscore_untyped.stderr index 86cdd5c662cc1..54b955ac3a561 100644 --- a/tests/ui/let_underscore_untyped.stderr +++ b/tests/ui/let_underscore_untyped.stderr @@ -1,11 +1,11 @@ error: non-binding `let` without a type annotation - --> tests/ui/let_underscore_untyped.rs:51:5 + --> tests/ui/let_underscore_untyped.rs:50:5 | LL | let _ = a(); | ^^^^^^^^^^^^ | help: consider adding a type annotation - --> tests/ui/let_underscore_untyped.rs:51:10 + --> tests/ui/let_underscore_untyped.rs:50:10 | LL | let _ = a(); | ^ @@ -13,49 +13,49 @@ LL | let _ = a(); = help: to override `-D warnings` add `#[allow(clippy::let_underscore_untyped)]` error: non-binding `let` without a type annotation - --> tests/ui/let_underscore_untyped.rs:53:5 + --> tests/ui/let_underscore_untyped.rs:52:5 | LL | let _ = b(1); | ^^^^^^^^^^^^^ | help: consider adding a type annotation - --> tests/ui/let_underscore_untyped.rs:53:10 + --> tests/ui/let_underscore_untyped.rs:52:10 | LL | let _ = b(1); | ^ error: non-binding `let` without a type annotation - --> tests/ui/let_underscore_untyped.rs:56:5 + --> tests/ui/let_underscore_untyped.rs:55:5 | LL | let _ = d(&1); | ^^^^^^^^^^^^^^ | help: consider adding a type annotation - --> tests/ui/let_underscore_untyped.rs:56:10 + --> tests/ui/let_underscore_untyped.rs:55:10 | LL | let _ = d(&1); | ^ error: non-binding `let` without a type annotation - --> tests/ui/let_underscore_untyped.rs:58:5 + --> tests/ui/let_underscore_untyped.rs:57:5 | LL | let _ = e(); | ^^^^^^^^^^^^ | help: consider adding a type annotation - --> tests/ui/let_underscore_untyped.rs:58:10 + --> tests/ui/let_underscore_untyped.rs:57:10 | LL | let _ = e(); | ^ error: non-binding `let` without a type annotation - --> tests/ui/let_underscore_untyped.rs:60:5 + --> tests/ui/let_underscore_untyped.rs:59:5 | LL | let _ = f(); | ^^^^^^^^^^^^ | help: consider adding a type annotation - --> tests/ui/let_underscore_untyped.rs:60:10 + --> tests/ui/let_underscore_untyped.rs:59:10 | LL | let _ = f(); | ^ From c6a23f8fbdc2e356209eac58cad09fab700bfc8c Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Thu, 8 May 2025 00:17:13 +0200 Subject: [PATCH 2212/4206] Include all bounds in bounds consolidation Also, include the type name in the lint message, and simplify the span computation. --- clippy_lints/src/trait_bounds.rs | 18 ++++------- .../ui-toml/type_repetition_in_bounds/main.rs | 2 +- .../type_repetition_in_bounds/main.stderr | 2 +- tests/ui/type_repetition_in_bounds.rs | 27 +++++++++++++---- tests/ui/type_repetition_in_bounds.stderr | 30 ++++++++++++++----- 5 files changed, 52 insertions(+), 27 deletions(-) diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 8aac3a5910294..45e54302e32c9 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -15,7 +15,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::{BytePos, Span}; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -282,18 +282,18 @@ impl TraitBounds { .iter() .copied() .chain(p.bounds.iter()) - .filter_map(get_trait_info_from_bound) - .map(|(_, _, span)| snippet_with_applicability(cx, span, "..", &mut applicability)) + .map(|bound| snippet_with_applicability(cx, bound.span(), "_", &mut applicability)) .join(" + "); let hint_string = format!( "consider combining the bounds: `{}: {trait_bounds}`", snippet(cx, p.bounded_ty.span, "_"), ); + let ty_name = snippet(cx, p.bounded_ty.span, "_"); span_lint_and_help( cx, TYPE_REPETITION_IN_BOUNDS, bound.span, - "this type has already been used as a bound predicate", + format!("type `{ty_name}` has already been used as a bound predicate"), None, hint_string, ); @@ -395,15 +395,7 @@ impl Hash for ComparableTraitRef<'_, '_> { fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &'a [PathSegment<'a>], Span)> { if let GenericBound::Trait(t) = bound { let trait_path = t.trait_ref.path; - let trait_span = { - let path_span = trait_path.span; - if let BoundPolarity::Maybe(_) = t.modifiers.polarity { - path_span.with_lo(path_span.lo() - BytePos(1)) // include the `?` - } else { - path_span - } - }; - Some((trait_path.res, trait_path.segments, trait_span)) + Some((trait_path.res, trait_path.segments, t.span)) } else { None } diff --git a/tests/ui-toml/type_repetition_in_bounds/main.rs b/tests/ui-toml/type_repetition_in_bounds/main.rs index 7f93d2071c9db..b60cb7632e201 100644 --- a/tests/ui-toml/type_repetition_in_bounds/main.rs +++ b/tests/ui-toml/type_repetition_in_bounds/main.rs @@ -12,7 +12,7 @@ fn f2() where T: Copy + Clone + Sync + Send + ?Sized, T: Unpin + PartialEq, - //~^ ERROR: this type has already been used as a bound predicate + //~^ type_repetition_in_bounds { } diff --git a/tests/ui-toml/type_repetition_in_bounds/main.stderr b/tests/ui-toml/type_repetition_in_bounds/main.stderr index c5102c39d1cff..ba0f41167a00f 100644 --- a/tests/ui-toml/type_repetition_in_bounds/main.stderr +++ b/tests/ui-toml/type_repetition_in_bounds/main.stderr @@ -1,4 +1,4 @@ -error: this type has already been used as a bound predicate +error: type `T` has already been used as a bound predicate --> tests/ui-toml/type_repetition_in_bounds/main.rs:14:5 | LL | T: Unpin + PartialEq, diff --git a/tests/ui/type_repetition_in_bounds.rs b/tests/ui/type_repetition_in_bounds.rs index d325887bfba3f..e75678d5fd93e 100644 --- a/tests/ui/type_repetition_in_bounds.rs +++ b/tests/ui/type_repetition_in_bounds.rs @@ -12,7 +12,7 @@ pub fn foo(_t: T) where T: Copy, T: Clone, - //~^ ERROR: this type has already been used as a bound predicate + //~^ type_repetition_in_bounds { unimplemented!(); } @@ -30,7 +30,7 @@ trait LintBounds where Self: Clone, Self: Copy + Default + Ord, - //~^ ERROR: this type has already been used as a bound predicate + //~^ type_repetition_in_bounds Self: Add + AddAssign + Sub + SubAssign, Self: Mul + MulAssign + Div + DivAssign, { @@ -105,13 +105,13 @@ where pub fn f() where T: Clone, - //~^ ERROR: this type has already been used as a bound predicate + //~^ type_repetition_in_bounds { } pub fn g() where T: ?Sized, - //~^ ERROR: this type has already been used as a bound predicate + //~^ type_repetition_in_bounds { } @@ -137,10 +137,27 @@ mod issue8772_pass { pub fn f(arg: usize) where T: Trait, Box<[String]>, bool> + 'static, - //~^ ERROR: this type has already been used as a bound predicate + //~^ type_repetition_in_bounds U: Clone + Sync + 'static, { } } +struct Issue14744<'a, K: 'a> +where + K: Clone, +{ + phantom: std::marker::PhantomData<&'a K>, +} +//~^^^^ type_repetition_in_bounds + +struct ComplexType +where + Vec: Clone, + Vec: Clone, +{ + t: T, +} +//~^^^^ type_repetition_in_bounds + fn main() {} diff --git a/tests/ui/type_repetition_in_bounds.stderr b/tests/ui/type_repetition_in_bounds.stderr index 77944c9504579..de1b14da1985f 100644 --- a/tests/ui/type_repetition_in_bounds.stderr +++ b/tests/ui/type_repetition_in_bounds.stderr @@ -1,4 +1,4 @@ -error: this type has already been used as a bound predicate +error: type `T` has already been used as a bound predicate --> tests/ui/type_repetition_in_bounds.rs:14:5 | LL | T: Clone, @@ -11,7 +11,7 @@ note: the lint level is defined here LL | #![deny(clippy::type_repetition_in_bounds)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: this type has already been used as a bound predicate +error: type `Self` has already been used as a bound predicate --> tests/ui/type_repetition_in_bounds.rs:32:5 | LL | Self: Copy + Default + Ord, @@ -19,7 +19,7 @@ LL | Self: Copy + Default + Ord, | = help: consider combining the bounds: `Self: Clone + Copy + Default + Ord` -error: this type has already been used as a bound predicate +error: type `T` has already been used as a bound predicate --> tests/ui/type_repetition_in_bounds.rs:107:5 | LL | T: Clone, @@ -27,7 +27,7 @@ LL | T: Clone, | = help: consider combining the bounds: `T: ?Sized + Clone` -error: this type has already been used as a bound predicate +error: type `T` has already been used as a bound predicate --> tests/ui/type_repetition_in_bounds.rs:113:5 | LL | T: ?Sized, @@ -35,13 +35,29 @@ LL | T: ?Sized, | = help: consider combining the bounds: `T: Clone + ?Sized` -error: this type has already been used as a bound predicate +error: type `T` has already been used as a bound predicate --> tests/ui/type_repetition_in_bounds.rs:139:9 | LL | T: Trait, Box<[String]>, bool> + 'static, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider combining the bounds: `T: ?Sized + Trait, Box<[String]>, bool>` + = help: consider combining the bounds: `T: ?Sized + Trait, Box<[String]>, bool> + 'static` -error: aborting due to 5 previous errors +error: type `K` has already been used as a bound predicate + --> tests/ui/type_repetition_in_bounds.rs:148:5 + | +LL | K: Clone, + | ^^^^^^^^ + | + = help: consider combining the bounds: `K: 'a + Clone` + +error: type `Vec` has already been used as a bound predicate + --> tests/ui/type_repetition_in_bounds.rs:157:5 + | +LL | Vec: Clone, + | ^^^^^^^^^^^^^ + | + = help: consider combining the bounds: `Vec: Clone + Clone` + +error: aborting due to 7 previous errors From 5eb47eeb851d4428642197cea3a566bcfa5f726a Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 12 May 2025 15:09:32 +0000 Subject: [PATCH 2213/4206] Add failing tests for some Option optimizations --- tests/codegen/option-niche-eq.rs | 13 ++-------- .../option-niche-unfixed/option-bool-eq.rs | 15 ++++++++++++ .../option-niche-unfixed/option-nonzero-eq.rs | 24 +++++++++++++++++++ 3 files changed, 41 insertions(+), 11 deletions(-) create mode 100644 tests/codegen/option-niche-unfixed/option-bool-eq.rs create mode 100644 tests/codegen/option-niche-unfixed/option-nonzero-eq.rs diff --git a/tests/codegen/option-niche-eq.rs b/tests/codegen/option-niche-eq.rs index 2be9e2bc48927..a39e2870a0f4f 100644 --- a/tests/codegen/option-niche-eq.rs +++ b/tests/codegen/option-niche-eq.rs @@ -1,3 +1,4 @@ +//@ min-llvm-version: 20 //@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled #![crate_type = "lib"] @@ -24,7 +25,7 @@ pub fn non_zero_signed_eq(l: Option>, r: Option>) -> b l == r } -// Test for #49892 +// FIXME(#49892) // This currently relies on a manual implementation of `PartialOrd`/`Ord` for `Option` // Once LLVM is better able to optimize this pattern, we can return to using a derive. // CHECK-LABEL: @non_zero_ord @@ -73,13 +74,3 @@ pub fn niche_eq(l: Option, r: Option) -> bool { // CHECK-NEXT: ret i1 l == r } - -// FIXME: This should work too -// // FIXME-CHECK-LABEL: @bool_eq -// #[no_mangle] -// pub fn bool_eq(l: Option, r: Option) -> bool { -// // FIXME-CHECK: start: -// // FIXME-CHECK-NEXT: icmp eq i8 -// // FIXME-CHECK-NEXT: ret i1 -// l == r -// } diff --git a/tests/codegen/option-niche-unfixed/option-bool-eq.rs b/tests/codegen/option-niche-unfixed/option-bool-eq.rs new file mode 100644 index 0000000000000..fa0e7836afb9e --- /dev/null +++ b/tests/codegen/option-niche-unfixed/option-bool-eq.rs @@ -0,0 +1,15 @@ +//@ should-fail +//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled +//! FIXME(#49892) +//! Tests that LLVM does not fully optimize comparisons of `Option`. +//! If this starts passing, it can be moved to `tests/codegen/option-niche-eq.rs` +#![crate_type = "lib"] + +// CHECK-LABEL: @bool_eq +#[no_mangle] +pub fn bool_eq(l: Option, r: Option) -> bool { + // CHECK: start: + // CHECK-NEXT: icmp eq i8 + // CHECK-NEXT: ret i1 + l == r +} diff --git a/tests/codegen/option-niche-unfixed/option-nonzero-eq.rs b/tests/codegen/option-niche-unfixed/option-nonzero-eq.rs new file mode 100644 index 0000000000000..308856cfb7e9d --- /dev/null +++ b/tests/codegen/option-niche-unfixed/option-nonzero-eq.rs @@ -0,0 +1,24 @@ +//@ should-fail +//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled +//! FIXME(#49892) +//! Test that the derived implementation of `PartialEq` for `Option` is not fully +//! optimized by LLVM. If this starts passing, the test and manual impl should +//! be removed. +#![crate_type = "lib"] + +use std::num::NonZero; + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum Option { + None, + Some(T), +} + +// CHECK-LABEL: @non_zero_eq +#[no_mangle] +pub fn non_zero_eq(l: Option>, r: Option>) -> bool { + // CHECK: start: + // CHECK-NEXT: icmp eq i32 + // CHECK-NEXT: ret i1 + l == r +} From 9a0c85655c7b60c5b6f595e98f72275e8052058b Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 12 May 2025 18:43:00 +0200 Subject: [PATCH 2214/4206] Specify that split_ascii_whitespace uses the same definition as is_ascii_whitespace --- library/core/src/str/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index dafabba645c61..0123e52f5470c 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -1172,6 +1172,7 @@ impl str { /// The iterator returned will return string slices that are sub-slices of /// the original string slice, separated by any amount of ASCII whitespace. /// + /// This uses the same definition as [`char::is_ascii_whitespace`]. /// To split by Unicode `Whitespace` instead, use [`split_whitespace`]. /// /// [`split_whitespace`]: str::split_whitespace @@ -1190,7 +1191,8 @@ impl str { /// assert_eq!(None, iter.next()); /// ``` /// - /// All kinds of ASCII whitespace are considered: + /// Various kinds of ASCII whitespace are considered + /// (see [`char::is_ascii_whitespace`]): /// /// ``` /// let mut iter = " Mary had\ta little \n\t lamb".split_ascii_whitespace(); From 82fbbc0882e64847e60934dba64188c07207b345 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Mon, 12 May 2025 16:18:27 +0000 Subject: [PATCH 2215/4206] compiletest: fix "blessing" message It was showing compare mode instead of test name. --- src/tools/compiletest/src/runtest.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 3c87bcb205fc6..75f24adb70fa5 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2609,18 +2609,19 @@ impl<'test> TestCx<'test> { (expected, actual) }; - // Write the actual output to a file in build/ - let test_name = self.config.compare_mode.as_ref().map_or("", |m| m.to_str()); + // Write the actual output to a file in build directory. let actual_path = self .output_base_name() .with_extra_extension(self.revision.unwrap_or("")) - .with_extra_extension(test_name) + .with_extra_extension( + self.config.compare_mode.as_ref().map(|cm| cm.to_str()).unwrap_or(""), + ) .with_extra_extension(stream); if let Err(err) = fs::write(&actual_path, &actual) { - self.fatal(&format!("failed to write {stream} to `{actual_path:?}`: {err}",)); + self.fatal(&format!("failed to write {stream} to `{actual_path}`: {err}",)); } - println!("Saved the actual {stream} to {actual_path:?}"); + println!("Saved the actual {stream} to `{actual_path}`"); if !self.config.bless { if expected.is_empty() { @@ -2646,13 +2647,16 @@ impl<'test> TestCx<'test> { if !actual.is_empty() { if let Err(err) = fs::write(&expected_path, &actual) { - self.fatal(&format!("failed to write {stream} to `{expected_path:?}`: {err}")); + self.fatal(&format!("failed to write {stream} to `{expected_path}`: {err}")); } - println!("Blessing the {stream} of {test_name} in {expected_path:?}"); + println!( + "Blessing the {stream} of `{test_name}` as `{expected_path}`", + test_name = self.testpaths.file + ); } } - println!("\nThe actual {0} differed from the expected {0}.", stream); + println!("\nThe actual {stream} differed from the expected {stream}"); if self.config.bless { CompareOutcome::Blessed } else { CompareOutcome::Differed } } From 2215282fa40b2bf0e727633f9c7025b1ca1fc373 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 11 May 2025 18:54:05 +0500 Subject: [PATCH 2216/4206] Update Changelog update walkthrough docs section --- .../infrastructure/changelog_update.md | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/book/src/development/infrastructure/changelog_update.md b/book/src/development/infrastructure/changelog_update.md index 2b2c096b0496f..eede6b78d9216 100644 --- a/book/src/development/infrastructure/changelog_update.md +++ b/book/src/development/infrastructure/changelog_update.md @@ -51,7 +51,9 @@ Once you've got the correct commit range, run util/fetch_prs_between.sh commit1 commit2 > changes.txt ``` -and open that file in your editor of choice. +where `commit2` is the commit hash from the previous command and `commit1` +is the commit hash from the current CHANGELOG file. +Open `changes.txt` file in your editor of choice. When updating the changelog it's also a good idea to make sure that `commit1` is already correct in the current changelog. @@ -60,8 +62,8 @@ already correct in the current changelog. The above script should have dumped all the relevant PRs to the file you specified. It should have filtered out most of the irrelevant PRs already, but -it's a good idea to do a manual cleanup pass where you look for more irrelevant -PRs. If you're not sure about some PRs, just leave them in for the review and +it's a good idea to do a manual cleanup pass and choose valuable PRs. +If you're not sure about some PRs, just leave them in for the review and ask for feedback. With the PRs filtered, you can start to take each PR and move the `changelog: ` @@ -74,10 +76,9 @@ The order should roughly be: 2. Moves or deprecations of lints 3. Changes that expand what code existing lints cover 4. False positive fixes -5. Suggestion fixes/improvements -6. ICE fixes -7. Documentation improvements -8. Others +5. ICE fixes +6. Documentation improvements +7. Others As section headers, we use: @@ -91,7 +92,6 @@ As section headers, we use: ### Enhancements ### False Positive Fixes -### Suggestion Fixes/Improvements ### ICE Fixes ### Documentation Improvements ### Others @@ -112,7 +112,16 @@ that label in the changelog. If you can, remove the `beta-accepted` labels ### 4. Update `clippy::version` attributes Next, make sure to check that the `#[clippy::version]` attributes for the added -lints contain the correct version. +lints contain the correct version. +In order to find lints that need a version update, go through the lints in the +"New Lints" section and run the following command for each lint name: + +``` +grep -rB1 "pub $LINT_NAME" . +``` + +The version shown should match the version of the release the changelog is +written for. If not, update the version to the changelog version. [changelog]: https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md [forge]: https://forge.rust-lang.org/ From 1caaa887003ed84b5c7022ded53ff50e699af666 Mon Sep 17 00:00:00 2001 From: omahs <73983677+omahs@users.noreply.github.com> Date: Mon, 12 May 2025 11:15:46 +0200 Subject: [PATCH 2217/4206] Fix typos --- compiler/rustc_ast_lowering/src/lib.rs | 2 +- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 2 +- compiler/rustc_codegen_ssa/src/errors.rs | 2 +- compiler/rustc_hir_analysis/messages.ftl | 2 +- compiler/rustc_hir_analysis/src/errors.rs | 2 +- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 2 +- compiler/rustc_interface/src/passes.rs | 2 +- compiler/rustc_macros/src/symbols.rs | 2 +- compiler/rustc_mir_build/src/builder/scope.rs | 2 +- .../src/solve/assembly/structural_traits.rs | 2 +- .../src/error_reporting/traits/on_unimplemented_format.rs | 2 +- src/doc/rustc-dev-guide/src/autodiff/installation.md | 2 +- .../src/rustdoc-internals/rustdoc-test-suite.md | 8 ++++---- src/doc/rustc-dev-guide/src/type-checking.md | 2 +- src/doc/rustc-dev-guide/src/type-inference.md | 2 +- src/doc/rustc-dev-guide/src/typing_parameter_envs.md | 8 ++++---- src/doc/rustc/src/platform-support/xtensa.md | 2 +- 17 files changed, 23 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 8597820073a56..e9eebd2adebf7 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -896,7 +896,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let ret = self.arena.alloc_from_iter(lowered_attrs); // this is possible if an item contained syntactical attribute, - // but none of them parse succesfully or all of them were ignored + // but none of them parse successfully or all of them were ignored // for not being built-in attributes at all. They could be remaining // unexpanded attributes used as markers in proc-macro derives for example. // This will have emitted some diagnostics for the misparse, but will then diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 5d09e62f2742d..835ffb7d4fc6b 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -387,7 +387,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { [sym::arm, sym::a32 | sym::t32] if !tcx.sess.target.has_thumb_interworking => { - tcx.dcx().emit_err(errors::UnsuportedInstructionSet { + tcx.dcx().emit_err(errors::UnsupportedInstructionSet { span: attr.span(), }); None diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index c2064397855f0..d49aac75d0582 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -149,7 +149,7 @@ pub(crate) struct NullOnExport { #[derive(Diagnostic)] #[diag(codegen_ssa_unsupported_instruction_set, code = E0779)] -pub(crate) struct UnsuportedInstructionSet { +pub(crate) struct UnsupportedInstructionSet { #[primary_span] pub span: Span, } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 277bb7bd3e15c..f7f2b78f05207 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -522,7 +522,7 @@ hir_analysis_trait_object_declared_with_no_traits = at least one trait is required for an object type .alias_span = this alias does not contain a trait -hir_analysis_traits_with_defualt_impl = traits with a default impl, like `{$traits}`, cannot be implemented for {$problematic_kind} `{$self_ty}` +hir_analysis_traits_with_default_impl = traits with a default impl, like `{$traits}`, cannot be implemented for {$problematic_kind} `{$self_ty}` .note = a trait object implements `{$traits}` if and only if `{$traits}` is one of the trait object's trait bounds hir_analysis_transparent_enum_variant = transparent enum needs exactly one variant, but has {$number} diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 2b1661aaac8f0..152714b340731 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1327,7 +1327,7 @@ pub(crate) struct ImplForTyRequires { } #[derive(Diagnostic)] -#[diag(hir_analysis_traits_with_defualt_impl, code = E0321)] +#[diag(hir_analysis_traits_with_default_impl, code = E0321)] #[note] pub(crate) struct TraitsWithDefaultImpl<'a> { #[primary_span] diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 6cc7e82bbf735..d2cdfe22a3ad0 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -2339,7 +2339,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if !mismatched_params.is_empty() { - // For each mismatched paramter, create a two-way link to each matched parameter + // For each mismatched parameter, create a two-way link to each matched parameter // of the same type. let mut dependants = IndexVec::::from_fn_n( |_| SmallVec::<[u32; 4]>::new(), diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index f4d11a7c0be2d..7ed32d559c3a6 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -907,7 +907,7 @@ pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( feed.output_filenames(Arc::new(outputs)); let res = f(tcx); - // FIXME maybe run finish even when a fatal error occured? or at least tcx.alloc_self_profile_query_strings()? + // FIXME maybe run finish even when a fatal error occurred? or at least tcx.alloc_self_profile_query_strings()? tcx.finish(); res }, diff --git a/compiler/rustc_macros/src/symbols.rs b/compiler/rustc_macros/src/symbols.rs index 0400de622740e..2b00b7dd27aaf 100644 --- a/compiler/rustc_macros/src/symbols.rs +++ b/compiler/rustc_macros/src/symbols.rs @@ -299,7 +299,7 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec) { let output = quote! { const SYMBOL_DIGITS_BASE: u32 = #symbol_digits_base; - /// The number of predefined symbols; this is the the first index for + /// The number of predefined symbols; this is the first index for /// extra pre-interned symbols in an Interner created via /// [`Interner::with_extra_symbols`]. pub const PREDEFINED_SYMBOLS_COUNT: u32 = #predefined_symbols_count; diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index 7c2871298203d..2a30777e98c4f 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -1485,7 +1485,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// panic occurred (a subset of the drops in `scope`, since we sometimes elide StorageDead and other /// instructions on unwinding) /// * `dropline_to`, describes the drops that would occur at this point in the code if a -/// coroutine drop occured. +/// coroutine drop occurred. /// * `storage_dead_on_unwind`, if true, then we should emit `StorageDead` even when unwinding /// * `arg_count`, number of MIR local variables corresponding to fn arguments (used to assert that we don't drop those) fn build_scope_drops<'tcx, F>( diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index b16f74cd8e431..2a2b462a36cbd 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -945,7 +945,7 @@ where // This is quite similar to the `projection_may_match` we use in unsizing, // but here we want to unify a projection predicate against an alias term - // so we can replace it with the the projection predicate's term. + // so we can replace it with the projection predicate's term. let mut matching_projections = replacements .iter() .filter(|source_projection| self.projection_may_match(**source_projection, alias_term)); diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs index d8b90844b7d2f..ce170f820e12f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs @@ -20,7 +20,7 @@ pub struct FormatString { input: Symbol, span: Span, pieces: Vec, - /// The formatting string was parsed succesfully but with warnings + /// The formatting string was parsed successfully but with warnings pub warnings: Vec, } diff --git a/src/doc/rustc-dev-guide/src/autodiff/installation.md b/src/doc/rustc-dev-guide/src/autodiff/installation.md index f3c11395523bf..c9b28dc43a6d1 100644 --- a/src/doc/rustc-dev-guide/src/autodiff/installation.md +++ b/src/doc/rustc-dev-guide/src/autodiff/installation.md @@ -1,6 +1,6 @@ # Installation -In the near future, `std::autodiff` should become available in nightly builds for users. As a contribute however, you will still need to build rustc from source. Please be aware that the msvc target is not supported at the moment, all other tier 1 targets should work. Please open an issue if you encounter any problems on a supported tier 1 target, or if you succesfully build this project on a tier2/tier3 target. +In the near future, `std::autodiff` should become available in nightly builds for users. As a contributor however, you will still need to build rustc from source. Please be aware that the msvc target is not supported at the moment, all other tier 1 targets should work. Please open an issue if you encounter any problems on a supported tier 1 target, or if you successfully build this project on a tier2/tier3 target. ## Build instructions diff --git a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-test-suite.md b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-test-suite.md index 169b95a7e1adc..bad7ac19da2cb 100644 --- a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-test-suite.md +++ b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-test-suite.md @@ -16,10 +16,10 @@ In addition to the directives listed here, `rustdoc` tests also support most [compiletest directives](../tests/directives.html). -All `PATH`s in directives are relative to the the rustdoc output directory (`build/TARGET/test/rustdoc/TESTNAME`), +All `PATH`s in directives are relative to the rustdoc output directory (`build/TARGET/test/rustdoc/TESTNAME`), so it is conventional to use a `#![crate_name = "foo"]` attribute to avoid having to write a long crate name multiple times. -To avoid repetion, `-` can be used in any `PATH` argument to re-use the previous `PATH` argument. +To avoid repetition, `-` can be used in any `PATH` argument to re-use the previous `PATH` argument. All arguments take the form of quoted strings (both single and double quotes are supported), @@ -87,7 +87,7 @@ compiletest's `--bless` flag is forwarded to htmldocck. Usage: `//@ has-dir PATH` -Checks for the existance of directory `PATH`. +Checks for the existence of directory `PATH`. ### `files` @@ -106,7 +106,7 @@ Example: `//@ files "foo/bar" '["index.html", "sidebar-items.js"]'` ## Limitations `htmldocck.py` uses the xpath implementation from the standard library. This leads to several limitations: -* All `XPATH` arguments must start with `//` due to a flaw in the implemention. +* All `XPATH` arguments must start with `//` due to a flaw in the implementation. * Many XPath features (functions, axies, etc.) are not supported. * Only well-formed HTML can be parsed (hopefully rustdoc doesn't output mismatched tags). diff --git a/src/doc/rustc-dev-guide/src/type-checking.md b/src/doc/rustc-dev-guide/src/type-checking.md index b60694201f388..4e8b30b19fc7b 100644 --- a/src/doc/rustc-dev-guide/src/type-checking.md +++ b/src/doc/rustc-dev-guide/src/type-checking.md @@ -17,7 +17,7 @@ Type "collection" is the process of converting the types found in the HIR **internal representation** used by the compiler (`Ty<'tcx>`) – we also do similar conversions for where-clauses and other bits of the function signature. -To try and get a sense for the difference, consider this function: +To try and get a sense of the difference, consider this function: ```rust,ignore struct Foo { } diff --git a/src/doc/rustc-dev-guide/src/type-inference.md b/src/doc/rustc-dev-guide/src/type-inference.md index c03fa36d79d11..888eb2439c5bc 100644 --- a/src/doc/rustc-dev-guide/src/type-inference.md +++ b/src/doc/rustc-dev-guide/src/type-inference.md @@ -19,7 +19,7 @@ Here, the type of `things` is *inferred* to be `Vec<&str>` because of the value we push into `things`. The type inference is based on the standard Hindley-Milner (HM) type inference -algorithm, but extended in various way to accommodate subtyping, region +algorithm, but extended in various ways to accommodate subtyping, region inference, and higher-ranked types. ## A note on terminology diff --git a/src/doc/rustc-dev-guide/src/typing_parameter_envs.md b/src/doc/rustc-dev-guide/src/typing_parameter_envs.md index 757296d1f6529..67eaf51bf2985 100644 --- a/src/doc/rustc-dev-guide/src/typing_parameter_envs.md +++ b/src/doc/rustc-dev-guide/src/typing_parameter_envs.md @@ -4,7 +4,7 @@ ## Typing Environments -When interacting with the type system there are a few variables to consider that can affect the results of trait solving. The the set of in-scope where clauses, and what phase of the compiler type system operations are being performed in (the [`ParamEnv`][penv] and [`TypingMode`][tmode] structs respectively). +When interacting with the type system there are a few variables to consider that can affect the results of trait solving. The set of in-scope where clauses, and what phase of the compiler type system operations are being performed in (the [`ParamEnv`][penv] and [`TypingMode`][tmode] structs respectively). When an environment to perform type system operations in has not yet been created, the [`TypingEnv`][tenv] can be used to bundle all of the external context required into a single type. @@ -13,11 +13,11 @@ Once a context to perform type system operations in has been created (e.g. an [` [ocx]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/struct.ObligationCtxt.html [fnctxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/fn_ctxt/struct.FnCtxt.html -## Parameter Environemnts +## Parameter Environments ### What is a `ParamEnv` -The [`ParamEnv`][penv] is a list of in-scope where-clauses, it typically corresponds to a specific item's where clauses. Some clauses are not explicitly written but are instead are implicitly added in the [`predicates_of`][predicates_of] query, such as `ConstArgHasType` or (some) implied bounds. +The [`ParamEnv`][penv] is a list of in-scope where-clauses, it typically corresponds to a specific item's where clauses. Some clauses are not explicitly written but are instead implicitly added in the [`predicates_of`][predicates_of] query, such as `ConstArgHasType` or (some) implied bounds. In most cases `ParamEnv`s are initially created via the [`param_env` query][query] which returns a `ParamEnv` derived from the provided item's where clauses. A `ParamEnv` can also be created with arbitrary sets of clauses that are not derived from a specific item, such as in [`compare_method_predicate_entailment`][method_pred_entailment] where we create a hybrid `ParamEnv` consisting of the impl's where clauses and the trait definition's function's where clauses. @@ -73,7 +73,7 @@ fn foo2(a: T) { ### Acquiring a `ParamEnv` -Using the wrong [`ParamEnv`][penv] when interacting with the type system can lead to ICEs, illformed programs compiling, or erroing when we shouldn't. See [#82159](https://github.com/rust-lang/rust/pull/82159) and [#82067](https://github.com/rust-lang/rust/pull/82067) as examples of PRs that modified the compiler to use the correct param env and in the process fixed ICEs. +Using the wrong [`ParamEnv`][penv] when interacting with the type system can lead to ICEs, illformed programs compiling, or erroring when we shouldn't. See [#82159](https://github.com/rust-lang/rust/pull/82159) and [#82067](https://github.com/rust-lang/rust/pull/82067) as examples of PRs that modified the compiler to use the correct param env and in the process fixed ICEs. In the large majority of cases, when a `ParamEnv` is required it either already exists somewhere in scope, or above in the call stack and should be passed down. A non exhaustive list of places where you might find an existing `ParamEnv`: - During typeck `FnCtxt` has a [`param_env` field][fnctxt_param_env] diff --git a/src/doc/rustc/src/platform-support/xtensa.md b/src/doc/rustc/src/platform-support/xtensa.md index 1189d27c95d84..994b3adb92e68 100644 --- a/src/doc/rustc/src/platform-support/xtensa.md +++ b/src/doc/rustc/src/platform-support/xtensa.md @@ -24,4 +24,4 @@ Xtensa targets that support `std` are documented in the [ESP-IDF platform suppor ## Building the targets -The targets can be built by installing the [Xtensa enabled Rust channel](https://github.com/esp-rs/rust/). See instructions in the [RISC-V and Xtensa Targets section of the The Rust on ESP Book](https://docs.esp-rs.org/book/installation/riscv-and-xtensa.html). +The targets can be built by installing the [Xtensa enabled Rust channel](https://github.com/esp-rs/rust/). See instructions in the [RISC-V and Xtensa Targets section of The Rust on ESP Book](https://docs.esp-rs.org/book/installation/riscv-and-xtensa.html). From df1da673f75937a1a8ebd4ad09b5ffb244df6927 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 12 May 2025 14:22:48 +0000 Subject: [PATCH 2218/4206] Flush errors before deep normalize in dropck_outlives --- .../src/traits/query/dropck_outlives.rs | 8 ++ tests/ui/drop/dropck-normalize-errors.rs | 31 ++++++++ tests/ui/drop/dropck-normalize-errors.stderr | 76 +++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 tests/ui/drop/dropck-normalize-errors.rs create mode 100644 tests/ui/drop/dropck-normalize-errors.stderr diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index f04a5feba3011..c82d5ca59efca 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -196,6 +196,14 @@ where debug!("dropck_outlives: ty from dtorck_types = {:?}", ty); ty } else { + // Flush errors b/c `deeply_normalize` doesn't expect pending + // obligations, and we may have pending obligations from the + // branch above (from other types). + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + return Err(errors); + } + ocx.deeply_normalize(&cause, param_env, ty)?; let errors = ocx.select_where_possible(); diff --git a/tests/ui/drop/dropck-normalize-errors.rs b/tests/ui/drop/dropck-normalize-errors.rs new file mode 100644 index 0000000000000..793122bd33d4b --- /dev/null +++ b/tests/ui/drop/dropck-normalize-errors.rs @@ -0,0 +1,31 @@ +// Test that we don't ICE when computing the drop types for + +trait Decode<'a> { + type Decoder; +} + +trait NonImplementedTrait { + type Assoc; +} +struct NonImplementedStruct; + +pub struct ADecoder<'a> { + b: >::Decoder, +} +fn make_a_decoder<'a>() -> ADecoder<'a> { + //~^ ERROR the trait bound + //~| ERROR the trait bound + panic!() +} + +struct B; +impl<'a> Decode<'a> for B { + type Decoder = BDecoder; + //~^ ERROR the trait bound +} +pub struct BDecoder { + non_implemented: ::Assoc, + //~^ ERROR the trait bound +} + +fn main() {} diff --git a/tests/ui/drop/dropck-normalize-errors.stderr b/tests/ui/drop/dropck-normalize-errors.stderr new file mode 100644 index 0000000000000..2bb5909c6b226 --- /dev/null +++ b/tests/ui/drop/dropck-normalize-errors.stderr @@ -0,0 +1,76 @@ +error[E0277]: the trait bound `NonImplementedStruct: NonImplementedTrait` is not satisfied in `ADecoder<'a>` + --> $DIR/dropck-normalize-errors.rs:15:28 + | +LL | fn make_a_decoder<'a>() -> ADecoder<'a> { + | ^^^^^^^^^^^^ within `ADecoder<'a>`, the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` + | +help: this trait has no implementations, consider adding one + --> $DIR/dropck-normalize-errors.rs:7:1 + | +LL | trait NonImplementedTrait { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required because it appears within the type `BDecoder` + --> $DIR/dropck-normalize-errors.rs:26:12 + | +LL | pub struct BDecoder { + | ^^^^^^^^ +note: required because it appears within the type `ADecoder<'a>` + --> $DIR/dropck-normalize-errors.rs:12:12 + | +LL | pub struct ADecoder<'a> { + | ^^^^^^^^ + = note: the return type of a function must have a statically known size + +error[E0277]: the trait bound `NonImplementedStruct: NonImplementedTrait` is not satisfied in `BDecoder` + --> $DIR/dropck-normalize-errors.rs:23:20 + | +LL | type Decoder = BDecoder; + | ^^^^^^^^ within `BDecoder`, the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` + | +help: this trait has no implementations, consider adding one + --> $DIR/dropck-normalize-errors.rs:7:1 + | +LL | trait NonImplementedTrait { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required because it appears within the type `BDecoder` + --> $DIR/dropck-normalize-errors.rs:26:12 + | +LL | pub struct BDecoder { + | ^^^^^^^^ +note: required by a bound in `Decode::Decoder` + --> $DIR/dropck-normalize-errors.rs:4:5 + | +LL | type Decoder; + | ^^^^^^^^^^^^^ required by this bound in `Decode::Decoder` +help: consider relaxing the implicit `Sized` restriction + | +LL | type Decoder: ?Sized; + | ++++++++ + +error[E0277]: the trait bound `NonImplementedStruct: NonImplementedTrait` is not satisfied + --> $DIR/dropck-normalize-errors.rs:27:22 + | +LL | non_implemented: ::Assoc, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` + | +help: this trait has no implementations, consider adding one + --> $DIR/dropck-normalize-errors.rs:7:1 + | +LL | trait NonImplementedTrait { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `NonImplementedStruct: NonImplementedTrait` is not satisfied + --> $DIR/dropck-normalize-errors.rs:15:28 + | +LL | fn make_a_decoder<'a>() -> ADecoder<'a> { + | ^^^^^^^^^^^^ the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` + | +help: this trait has no implementations, consider adding one + --> $DIR/dropck-normalize-errors.rs:7:1 + | +LL | trait NonImplementedTrait { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. From 2f39264d00eef5e5990438a5c23cb670500548d9 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 13 Apr 2025 07:05:29 -0400 Subject: [PATCH 2219/4206] clippy_dev: Set the current directory to clippy's root path. --- clippy_dev/src/dogfood.rs | 5 +- clippy_dev/src/fmt.rs | 32 ++--- clippy_dev/src/lib.rs | 2 +- clippy_dev/src/main.rs | 18 ++- clippy_dev/src/new_lint.rs | 46 +++++--- clippy_dev/src/release.rs | 14 +-- clippy_dev/src/update_lints.rs | 67 +++++------ clippy_dev/src/utils.rs | 207 +++++++++++++++++++++++++++------ 8 files changed, 264 insertions(+), 127 deletions(-) diff --git a/clippy_dev/src/dogfood.rs b/clippy_dev/src/dogfood.rs index 05fa24d8d4ee5..7e9d92458d057 100644 --- a/clippy_dev/src/dogfood.rs +++ b/clippy_dev/src/dogfood.rs @@ -1,4 +1,4 @@ -use crate::utils::{clippy_project_root, exit_if_err}; +use crate::utils::exit_if_err; use std::process::Command; /// # Panics @@ -8,8 +8,7 @@ use std::process::Command; pub fn dogfood(fix: bool, allow_dirty: bool, allow_staged: bool, allow_no_vcs: bool) { let mut cmd = Command::new("cargo"); - cmd.current_dir(clippy_project_root()) - .args(["test", "--test", "dogfood"]) + cmd.args(["test", "--test", "dogfood"]) .args(["--features", "internal"]) .args(["--", "dogfood_clippy", "--nocapture"]); diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index bdddf46a2cb19..b4c13213f552a 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -1,4 +1,3 @@ -use crate::utils::clippy_project_root; use itertools::Itertools; use rustc_lexer::{TokenKind, tokenize}; use shell_escape::escape; @@ -104,15 +103,8 @@ fn fmt_conf(check: bool) -> Result<(), Error> { Field, } - let path: PathBuf = [ - clippy_project_root().as_path(), - "clippy_config".as_ref(), - "src".as_ref(), - "conf.rs".as_ref(), - ] - .into_iter() - .collect(); - let text = fs::read_to_string(&path)?; + let path = "clippy_config/src/conf.rs"; + let text = fs::read_to_string(path)?; let (pre, conf) = text .split_once("define_Conf! {\n") @@ -203,7 +195,7 @@ fn fmt_conf(check: bool) -> Result<(), Error> { | (State::Lints, TokenKind::Comma | TokenKind::OpenParen | TokenKind::CloseParen) => {}, _ => { return Err(Error::Parse( - path, + PathBuf::from(path), offset_to_line(&text, conf_offset + i), format!("unexpected token `{}`", &conf[i..i + t.len as usize]), )); @@ -213,7 +205,7 @@ fn fmt_conf(check: bool) -> Result<(), Error> { if !matches!(state, State::Field) { return Err(Error::Parse( - path, + PathBuf::from(path), offset_to_line(&text, conf_offset + conf.len()), "incomplete field".into(), )); @@ -260,18 +252,16 @@ fn fmt_conf(check: bool) -> Result<(), Error> { if check { return Err(Error::CheckFailed); } - fs::write(&path, new_text.as_bytes())?; + fs::write(path, new_text.as_bytes())?; } Ok(()) } fn run_rustfmt(context: &FmtContext) -> Result<(), Error> { - let project_root = clippy_project_root(); - // if we added a local rustc repo as path dependency to clippy for rust analyzer, we do NOT want to // format because rustfmt would also format the entire rustc repo as it is a local // dependency - if fs::read_to_string(project_root.join("Cargo.toml")) + if fs::read_to_string("Cargo.toml") .expect("Failed to read clippy Cargo.toml") .contains("[target.'cfg(NOT_A_PLATFORM)'.dependencies]") { @@ -280,12 +270,12 @@ fn run_rustfmt(context: &FmtContext) -> Result<(), Error> { check_for_rustfmt(context)?; - cargo_fmt(context, project_root.as_path())?; - cargo_fmt(context, &project_root.join("clippy_dev"))?; - cargo_fmt(context, &project_root.join("rustc_tools_util"))?; - cargo_fmt(context, &project_root.join("lintcheck"))?; + cargo_fmt(context, ".".as_ref())?; + cargo_fmt(context, "clippy_dev".as_ref())?; + cargo_fmt(context, "rustc_tools_util".as_ref())?; + cargo_fmt(context, "lintcheck".as_ref())?; - let chunks = WalkDir::new(project_root.join("tests")) + let chunks = WalkDir::new("tests") .into_iter() .filter_map(|entry| { let entry = entry.expect("failed to find tests"); diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index db4b4d07c1563..70e57fcfc26ee 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private)] +#![feature(rustc_private, if_let_guard, let_chains)] #![warn( trivial_casts, trivial_numeric_casts, diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 83f8e66b33476..bd87e980c2220 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -5,9 +5,14 @@ use clap::{Args, Parser, Subcommand}; use clippy_dev::{dogfood, fmt, lint, new_lint, release, serve, setup, sync, update_lints, utils}; use std::convert::Infallible; +use std::env; fn main() { let dev = Dev::parse(); + let clippy = utils::ClippyInfo::search_for_manifest(); + if let Err(e) = env::set_current_dir(&clippy.path) { + panic!("error setting current directory to `{}`: {e}", clippy.path.display()); + } match dev.command { DevCommand::Bless => { @@ -35,7 +40,7 @@ fn main() { category, r#type, msrv, - } => match new_lint::create(pass, &name, &category, r#type.as_deref(), msrv) { + } => match new_lint::create(clippy.version, pass, &name, &category, r#type.as_deref(), msrv) { Ok(()) => update_lints::update(utils::UpdateMode::Change), Err(e) => eprintln!("Unable to create lint: {e}"), }, @@ -79,13 +84,18 @@ fn main() { old_name, new_name, uplift, - } => update_lints::rename(&old_name, new_name.as_ref().unwrap_or(&old_name), uplift), - DevCommand::Deprecate { name, reason } => update_lints::deprecate(&name, &reason), + } => update_lints::rename( + clippy.version, + &old_name, + new_name.as_ref().unwrap_or(&old_name), + uplift, + ), + DevCommand::Deprecate { name, reason } => update_lints::deprecate(clippy.version, &name, &reason), DevCommand::Sync(SyncCommand { subcommand }) => match subcommand { SyncSubcommand::UpdateNightly => sync::update_nightly(), }, DevCommand::Release(ReleaseCommand { subcommand }) => match subcommand { - ReleaseSubcommand::BumpVersion => release::bump_version(), + ReleaseSubcommand::BumpVersion => release::bump_version(clippy.version), }, } } diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 771f48b3f8b11..a6e8c3ac3249f 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -1,4 +1,4 @@ -use crate::utils::{clippy_project_root, clippy_version}; +use crate::utils::Version; use clap::ValueEnum; use indoc::{formatdoc, writedoc}; use std::fmt::{self, Write as _}; @@ -22,11 +22,11 @@ impl fmt::Display for Pass { } struct LintData<'a> { + clippy_version: Version, pass: Pass, name: &'a str, category: &'a str, ty: Option<&'a str>, - project_root: PathBuf, } trait Context { @@ -50,18 +50,25 @@ impl Context for io::Result { /// # Errors /// /// This function errors out if the files couldn't be created or written to. -pub fn create(pass: Pass, name: &str, category: &str, mut ty: Option<&str>, msrv: bool) -> io::Result<()> { +pub fn create( + clippy_version: Version, + pass: Pass, + name: &str, + category: &str, + mut ty: Option<&str>, + msrv: bool, +) -> io::Result<()> { if category == "cargo" && ty.is_none() { // `cargo` is a special category, these lints should always be in `clippy_lints/src/cargo` ty = Some("cargo"); } let lint = LintData { + clippy_version, pass, name, category, ty, - project_root: clippy_project_root(), }; create_lint(&lint, msrv).context("Unable to create lint implementation")?; @@ -88,7 +95,7 @@ fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { } else { let lint_contents = get_lint_file_contents(lint, enable_msrv); let lint_path = format!("clippy_lints/src/{}.rs", lint.name); - write_file(lint.project_root.join(&lint_path), lint_contents.as_bytes())?; + write_file(&lint_path, lint_contents.as_bytes())?; println!("Generated lint file: `{lint_path}`"); Ok(()) @@ -115,8 +122,7 @@ fn create_test(lint: &LintData<'_>, msrv: bool) -> io::Result<()> { } if lint.category == "cargo" { - let relative_test_dir = format!("tests/ui-cargo/{}", lint.name); - let test_dir = lint.project_root.join(&relative_test_dir); + let test_dir = format!("tests/ui-cargo/{}", lint.name); fs::create_dir(&test_dir)?; create_project_layout( @@ -134,11 +140,11 @@ fn create_test(lint: &LintData<'_>, msrv: bool) -> io::Result<()> { false, )?; - println!("Generated test directories: `{relative_test_dir}/pass`, `{relative_test_dir}/fail`"); + println!("Generated test directories: `{test_dir}/pass`, `{test_dir}/fail`"); } else { let test_path = format!("tests/ui/{}.rs", lint.name); let test_contents = get_test_file_contents(lint.name, msrv); - write_file(lint.project_root.join(&test_path), test_contents)?; + write_file(&test_path, test_contents)?; println!("Generated test file: `{test_path}`"); } @@ -193,11 +199,6 @@ fn to_camel_case(name: &str) -> String { .collect() } -pub(crate) fn get_stabilization_version() -> String { - let (minor, patch) = clippy_version(); - format!("{minor}.{patch}.0") -} - fn get_test_file_contents(lint_name: &str, msrv: bool) -> String { let mut test = formatdoc!( r" @@ -292,7 +293,11 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { ); } - let _: fmt::Result = writeln!(result, "{}", get_lint_declaration(&name_upper, category)); + let _: fmt::Result = writeln!( + result, + "{}", + get_lint_declaration(lint.clippy_version, &name_upper, category) + ); if enable_msrv { let _: fmt::Result = writedoc!( @@ -330,7 +335,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { result } -fn get_lint_declaration(name_upper: &str, category: &str) -> String { +fn get_lint_declaration(version: Version, name_upper: &str, category: &str) -> String { let justification_heading = if category == "restriction" { "Why restrict this?" } else { @@ -357,7 +362,7 @@ fn get_lint_declaration(name_upper: &str, category: &str) -> String { "default lint description" }} "#, - get_stabilization_version(), + version.rust_display(), ) } @@ -371,7 +376,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R _ => {}, } - let ty_dir = lint.project_root.join(format!("clippy_lints/src/{ty}")); + let ty_dir = PathBuf::from(format!("clippy_lints/src/{ty}")); assert!( ty_dir.exists() && ty_dir.is_dir(), "Directory `{}` does not exist!", @@ -529,7 +534,10 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str> file_contents.replace_range( // Remove the trailing newline, which should always be present last_decl_curly_offset..=last_decl_curly_offset, - &format!("\n\n{}", get_lint_declaration(&lint_name_upper, lint.category)), + &format!( + "\n\n{}", + get_lint_declaration(lint.clippy_version, &lint_name_upper, lint.category) + ), ); // Add the lint to `impl_lint_pass`/`declare_lint_pass` diff --git a/clippy_dev/src/release.rs b/clippy_dev/src/release.rs index ac75516870103..34f81e10a393b 100644 --- a/clippy_dev/src/release.rs +++ b/clippy_dev/src/release.rs @@ -1,7 +1,6 @@ use std::fmt::Write; -use std::path::Path; -use crate::utils::{UpdateMode, clippy_version, replace_region_in_file}; +use crate::utils::{UpdateMode, Version, replace_region_in_file}; const CARGO_TOML_FILES: [&str; 4] = [ "clippy_config/Cargo.toml", @@ -10,17 +9,16 @@ const CARGO_TOML_FILES: [&str; 4] = [ "Cargo.toml", ]; -pub fn bump_version() { - let (minor, mut patch) = clippy_version(); - patch += 1; - for file in &CARGO_TOML_FILES { +pub fn bump_version(mut version: Version) { + version.minor += 1; + for &file in &CARGO_TOML_FILES { replace_region_in_file( UpdateMode::Change, - Path::new(file), + file.as_ref(), "# begin autogenerated version\n", "# end autogenerated version", |res| { - writeln!(res, "version = \"0.{minor}.{patch}\"").unwrap(); + writeln!(res, "version = \"{}\"", version.toml_display()).unwrap(); }, ); } diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index d848a97f86d2f..e53c454be7a23 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -1,4 +1,4 @@ -use crate::utils::{UpdateMode, clippy_project_root, exit_with_failure, replace_region_in_file}; +use crate::utils::{UpdateMode, Version, exit_with_failure, replace_region_in_file}; use aho_corasick::AhoCorasickBuilder; use itertools::Itertools; use rustc_lexer::{LiteralKind, TokenKind, tokenize}; @@ -139,7 +139,7 @@ pub fn print_lints() { /// * If `old_name` doesn't name an existing lint. /// * If `old_name` names a deprecated or renamed lint. #[allow(clippy::too_many_lines)] -pub fn rename(old_name: &str, new_name: &str, uplift: bool) { +pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: bool) { if let Some((prefix, _)) = old_name.split_once("::") { panic!("`{old_name}` should not contain the `{prefix}` prefix"); } @@ -180,31 +180,28 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) { ); // Update all lint level attributes. (`clippy::lint_name`) - for file in WalkDir::new(clippy_project_root()) - .into_iter() - .map(Result::unwrap) - .filter(|f| { - let name = f.path().file_name(); - let ext = f.path().extension(); - (ext == Some(OsStr::new("rs")) || ext == Some(OsStr::new("fixed"))) - && name != Some(OsStr::new("rename.rs")) - && name != Some(OsStr::new("deprecated_lints.rs")) - }) - { + for file in WalkDir::new(".").into_iter().map(Result::unwrap).filter(|f| { + let name = f.path().file_name(); + let ext = f.path().extension(); + (ext == Some(OsStr::new("rs")) || ext == Some(OsStr::new("fixed"))) + && name != Some(OsStr::new("rename.rs")) + && name != Some(OsStr::new("deprecated_lints.rs")) + }) { rewrite_file(file.path(), |s| { replace_ident_like(s, &[(&lint.old_name, &lint.new_name)]) }); } - let version = crate::new_lint::get_stabilization_version(); rewrite_file(Path::new("clippy_lints/src/deprecated_lints.rs"), |s| { insert_at_marker( s, "// end renamed lints. used by `cargo dev rename_lint`", &format!( - "#[clippy::version = \"{version}\"]\n \ + "#[clippy::version = \"{}\"]\n \ (\"{}\", \"{}\"),\n ", - lint.old_name, lint.new_name, + clippy_version.rust_display(), + lint.old_name, + lint.new_name, ), ) }); @@ -284,9 +281,15 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) { // Don't change `clippy_utils/src/renamed_lints.rs` here as it would try to edit the lint being // renamed. - for (_, file) in clippy_lints_src_files().filter(|(rel_path, _)| rel_path != OsStr::new("deprecated_lints.rs")) - { - rewrite_file(file.path(), |s| replace_ident_like(s, replacements)); + for file in clippy_lints_src_files() { + if file + .path() + .as_os_str() + .to_str() + .is_none_or(|x| x["clippy_lints/src/".len()..] != *"deprecated_lints.rs") + { + rewrite_file(file.path(), |s| replace_ident_like(s, replacements)); + } } generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); @@ -305,7 +308,7 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) { /// # Panics /// /// If a file path could not read from or written to -pub fn deprecate(name: &str, reason: &str) { +pub fn deprecate(clippy_version: Version, name: &str, reason: &str) { let prefixed_name = if name.starts_with("clippy::") { name.to_owned() } else { @@ -329,15 +332,15 @@ pub fn deprecate(name: &str, reason: &str) { mod_path }; - let deprecated_lints_path = &*clippy_project_root().join("clippy_lints/src/deprecated_lints.rs"); - if remove_lint_declaration(stripped_name, &mod_path, &mut lints).unwrap_or(false) { - let version = crate::new_lint::get_stabilization_version(); - rewrite_file(deprecated_lints_path, |s| { + rewrite_file("clippy_lints/src/deprecated_lints.rs".as_ref(), |s| { insert_at_marker( s, "// end deprecated lints. used by `cargo dev deprecate_lint`", - &format!("#[clippy::version = \"{version}\"]\n (\"{prefixed_name}\", \"{reason}\"),\n ",), + &format!( + "#[clippy::version = \"{}\"]\n (\"{prefixed_name}\", \"{reason}\"),\n ", + clippy_version.rust_display(), + ), ) }); @@ -612,15 +615,11 @@ fn gather_all() -> (Vec, Vec, Vec) { let mut deprecated_lints = Vec::with_capacity(50); let mut renamed_lints = Vec::with_capacity(50); - for (rel_path, file) in clippy_lints_src_files() { + for file in clippy_lints_src_files() { let path = file.path(); let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {e}", path.display())); - let module = rel_path - .components() - .map(|c| c.as_os_str().to_str().unwrap()) - .collect::>() - .join("::"); + let module = path.as_os_str().to_str().unwrap()["clippy_lints/src/".len()..].replace(['/', '\\'], "::"); // If the lints are stored in mod.rs, we get the module name from // the containing directory: @@ -639,12 +638,10 @@ fn gather_all() -> (Vec, Vec, Vec) { (lints, deprecated_lints, renamed_lints) } -fn clippy_lints_src_files() -> impl Iterator { - let root_path = clippy_project_root().join("clippy_lints/src"); - let iter = WalkDir::new(&root_path).into_iter(); +fn clippy_lints_src_files() -> impl Iterator { + let iter = WalkDir::new("clippy_lints/src").into_iter(); iter.map(Result::unwrap) .filter(|f| f.path().extension() == Some(OsStr::new("rs"))) - .map(move |f| (f.path().strip_prefix(&root_path).unwrap().to_path_buf(), f)) } macro_rules! match_tokens { diff --git a/clippy_dev/src/utils.rs b/clippy_dev/src/utils.rs index 206816398f50f..2b199d96fcdec 100644 --- a/clippy_dev/src/utils.rs +++ b/clippy_dev/src/utils.rs @@ -1,12 +1,90 @@ +use core::fmt::{self, Display}; +use core::str::FromStr; +use std::env; +use std::fs::{self, OpenOptions}; +use std::io::{self, Read as _, Seek as _, SeekFrom, Write}; use std::path::{Path, PathBuf}; use std::process::{self, ExitStatus}; -use std::{fs, io}; #[cfg(not(windows))] static CARGO_CLIPPY_EXE: &str = "cargo-clippy"; #[cfg(windows)] static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe"; +#[cold] +#[track_caller] +fn panic_io(e: &io::Error, action: &str, path: &Path) -> ! { + panic!("error {action} `{}`: {}", path.display(), *e) +} + +/// Wrapper around `std::fs::File` which panics with a path on failure. +pub struct File<'a> { + pub inner: fs::File, + pub path: &'a Path, +} +impl<'a> File<'a> { + /// Opens a file panicking on failure. + #[track_caller] + pub fn open(path: &'a (impl AsRef + ?Sized), options: &mut OpenOptions) -> Self { + let path = path.as_ref(); + match options.open(path) { + Ok(inner) => Self { inner, path }, + Err(e) => panic_io(&e, "opening", path), + } + } + + /// Opens a file if it exists, panicking on any other failure. + #[track_caller] + pub fn open_if_exists(path: &'a (impl AsRef + ?Sized), options: &mut OpenOptions) -> Option { + let path = path.as_ref(); + match options.open(path) { + Ok(inner) => Some(Self { inner, path }), + Err(e) if e.kind() == io::ErrorKind::NotFound => None, + Err(e) => panic_io(&e, "opening", path), + } + } + + /// Opens and reads a file into a string, panicking of failure. + #[track_caller] + pub fn open_read_to_cleared_string<'dst>( + path: &'a (impl AsRef + ?Sized), + dst: &'dst mut String, + ) -> &'dst mut String { + Self::open(path, OpenOptions::new().read(true)).read_to_cleared_string(dst) + } + + /// Read the entire contents of a file to the given buffer. + #[track_caller] + pub fn read_append_to_string<'dst>(&mut self, dst: &'dst mut String) -> &'dst mut String { + match self.inner.read_to_string(dst) { + Ok(_) => {}, + Err(e) => panic_io(&e, "reading", self.path), + } + dst + } + + #[track_caller] + pub fn read_to_cleared_string<'dst>(&mut self, dst: &'dst mut String) -> &'dst mut String { + dst.clear(); + self.read_append_to_string(dst) + } + + /// Replaces the entire contents of a file. + #[track_caller] + pub fn replace_contents(&mut self, data: &[u8]) { + let res = match self.inner.seek(SeekFrom::Start(0)) { + Ok(_) => match self.inner.write_all(data) { + Ok(()) => self.inner.set_len(data.len() as u64), + Err(e) => Err(e), + }, + Err(e) => Err(e), + }; + if let Err(e) = res { + panic_io(&e, "writing", self.path); + } + } +} + /// Returns the path to the `cargo-clippy` binary /// /// # Panics @@ -14,34 +92,107 @@ static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe"; /// Panics if the path of current executable could not be retrieved. #[must_use] pub fn cargo_clippy_path() -> PathBuf { - let mut path = std::env::current_exe().expect("failed to get current executable name"); + let mut path = env::current_exe().expect("failed to get current executable name"); path.set_file_name(CARGO_CLIPPY_EXE); path } -/// Returns the path to the Clippy project directory -/// -/// # Panics -/// -/// Panics if the current directory could not be retrieved, there was an error reading any of the -/// Cargo.toml files or ancestor directory is the clippy root directory -#[must_use] -pub fn clippy_project_root() -> PathBuf { - let current_dir = std::env::current_dir().unwrap(); - for path in current_dir.ancestors() { - let result = fs::read_to_string(path.join("Cargo.toml")); - if let Err(err) = &result - && err.kind() == io::ErrorKind::NotFound +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct Version { + pub major: u16, + pub minor: u16, +} +impl FromStr for Version { + type Err = (); + fn from_str(s: &str) -> Result { + if let Some(s) = s.strip_prefix("0.") + && let Some((major, minor)) = s.split_once('.') + && let Ok(major) = major.parse() + && let Ok(minor) = minor.parse() { - continue; + Ok(Self { major, minor }) + } else { + Err(()) + } + } +} +impl Version { + /// Displays the version as a rust version. i.e. `x.y.0` + #[must_use] + pub fn rust_display(self) -> impl Display { + struct X(Version); + impl Display for X { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}.{}.0", self.0.major, self.0.minor) + } + } + X(self) + } + + /// Displays the version as it should appear in clippy's toml files. i.e. `0.x.y` + #[must_use] + pub fn toml_display(self) -> impl Display { + struct X(Version); + impl Display for X { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "0.{}.{}", self.0.major, self.0.minor) + } } + X(self) + } +} + +pub struct ClippyInfo { + pub path: PathBuf, + pub version: Version, +} +impl ClippyInfo { + #[must_use] + pub fn search_for_manifest() -> Self { + let mut path = env::current_dir().expect("error reading the working directory"); + let mut buf = String::new(); + loop { + path.push("Cargo.toml"); + if let Some(mut file) = File::open_if_exists(&path, OpenOptions::new().read(true)) { + let mut in_package = false; + let mut is_clippy = false; + let mut version: Option = None; + + // Ad-hoc parsing to avoid dependencies. We control all the file so this + // isn't actually a problem + for line in file.read_to_cleared_string(&mut buf).lines() { + if line.starts_with('[') { + in_package = line.starts_with("[package]"); + } else if in_package && let Some((name, value)) = line.split_once('=') { + match name.trim() { + "name" => is_clippy = value.trim() == "\"clippy\"", + "version" + if let Some(value) = value.trim().strip_prefix('"') + && let Some(value) = value.strip_suffix('"') => + { + version = value.parse().ok(); + }, + _ => {}, + } + } + } - let content = result.unwrap(); - if content.contains("[package]\nname = \"clippy\"") { - return path.to_path_buf(); + if is_clippy { + let Some(version) = version else { + panic!("error reading clippy version from {}", file.path.display()); + }; + path.pop(); + return ClippyInfo { path, version }; + } + } + + path.pop(); + assert!( + path.pop(), + "error finding project root, please run from inside the clippy directory" + ); } } - panic!("error: Can't determine root of project. Please run inside a Clippy working dir."); } /// # Panics @@ -57,22 +208,6 @@ pub fn exit_if_err(status: io::Result) { } } -pub(crate) fn clippy_version() -> (u32, u32) { - fn parse_manifest(contents: &str) -> Option<(u32, u32)> { - let version = contents - .lines() - .filter_map(|l| l.split_once('=')) - .find_map(|(k, v)| (k.trim() == "version").then(|| v.trim()))?; - let Some(("0", version)) = version.get(1..version.len() - 1)?.split_once('.') else { - return None; - }; - let (minor, patch) = version.split_once('.')?; - Some((minor.parse().ok()?, patch.parse().ok()?)) - } - let contents = fs::read_to_string("Cargo.toml").expect("Unable to read `Cargo.toml`"); - parse_manifest(&contents).expect("Unable to find package version in `Cargo.toml`") -} - #[derive(Clone, Copy, PartialEq, Eq)] pub enum UpdateMode { Check, From 3fe5fb296786e9396c1e91280360d9f029367b44 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Mon, 14 Apr 2025 08:09:24 -0400 Subject: [PATCH 2220/4206] clippy_dev: Split `rename` and `deprecate` out of `update_lints` --- clippy_dev/src/deprecate_lint.rs | 162 +++++++++++ clippy_dev/src/lib.rs | 2 + clippy_dev/src/main.rs | 8 +- clippy_dev/src/rename_lint.rs | 185 +++++++++++++ clippy_dev/src/update_lints.rs | 460 ++----------------------------- clippy_dev/src/utils.rs | 85 ++++++ 6 files changed, 460 insertions(+), 442 deletions(-) create mode 100644 clippy_dev/src/deprecate_lint.rs create mode 100644 clippy_dev/src/rename_lint.rs diff --git a/clippy_dev/src/deprecate_lint.rs b/clippy_dev/src/deprecate_lint.rs new file mode 100644 index 0000000000000..2c4286b325db3 --- /dev/null +++ b/clippy_dev/src/deprecate_lint.rs @@ -0,0 +1,162 @@ +use crate::update_lints::{DeprecatedLint, Lint, gather_all, generate_lint_files}; +use crate::utils::{UpdateMode, Version, insert_at_marker, rewrite_file}; +use std::ffi::OsStr; +use std::path::{Path, PathBuf}; +use std::{fs, io}; + +/// Runs the `deprecate` command +/// +/// This does the following: +/// * Adds an entry to `deprecated_lints.rs`. +/// * Removes the lint declaration (and the entire file if applicable) +/// +/// # Panics +/// +/// If a file path could not read from or written to +pub fn deprecate(clippy_version: Version, name: &str, reason: &str) { + let prefixed_name = if name.starts_with("clippy::") { + name.to_owned() + } else { + format!("clippy::{name}") + }; + let stripped_name = &prefixed_name[8..]; + + let (mut lints, mut deprecated_lints, renamed_lints) = gather_all(); + let Some(lint) = lints.iter().find(|l| l.name == stripped_name) else { + eprintln!("error: failed to find lint `{name}`"); + return; + }; + + let mod_path = { + let mut mod_path = PathBuf::from(format!("clippy_lints/src/{}", lint.module)); + if mod_path.is_dir() { + mod_path = mod_path.join("mod"); + } + + mod_path.set_extension("rs"); + mod_path + }; + + if remove_lint_declaration(stripped_name, &mod_path, &mut lints).unwrap_or(false) { + rewrite_file("clippy_lints/src/deprecated_lints.rs".as_ref(), |s| { + insert_at_marker( + s, + "// end deprecated lints. used by `cargo dev deprecate_lint`", + &format!( + "#[clippy::version = \"{}\"]\n (\"{prefixed_name}\", \"{reason}\"),\n ", + clippy_version.rust_display(), + ), + ) + }); + + deprecated_lints.push(DeprecatedLint { + name: prefixed_name, + reason: reason.into(), + }); + + generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); + println!("info: `{name}` has successfully been deprecated"); + println!("note: you must run `cargo uitest` to update the test results"); + } else { + eprintln!("error: lint not found"); + } +} + +fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec) -> io::Result { + fn remove_lint(name: &str, lints: &mut Vec) { + lints.iter().position(|l| l.name == name).map(|pos| lints.remove(pos)); + } + + fn remove_test_assets(name: &str) { + let test_file_stem = format!("tests/ui/{name}"); + let path = Path::new(&test_file_stem); + + // Some lints have their own directories, delete them + if path.is_dir() { + let _ = fs::remove_dir_all(path); + return; + } + + // Remove all related test files + let _ = fs::remove_file(path.with_extension("rs")); + let _ = fs::remove_file(path.with_extension("stderr")); + let _ = fs::remove_file(path.with_extension("fixed")); + } + + fn remove_impl_lint_pass(lint_name_upper: &str, content: &mut String) { + let impl_lint_pass_start = content.find("impl_lint_pass!").unwrap_or_else(|| { + content + .find("declare_lint_pass!") + .unwrap_or_else(|| panic!("failed to find `impl_lint_pass`")) + }); + let mut impl_lint_pass_end = content[impl_lint_pass_start..] + .find(']') + .expect("failed to find `impl_lint_pass` terminator"); + + impl_lint_pass_end += impl_lint_pass_start; + if let Some(lint_name_pos) = content[impl_lint_pass_start..impl_lint_pass_end].find(lint_name_upper) { + let mut lint_name_end = impl_lint_pass_start + (lint_name_pos + lint_name_upper.len()); + for c in content[lint_name_end..impl_lint_pass_end].chars() { + // Remove trailing whitespace + if c == ',' || c.is_whitespace() { + lint_name_end += 1; + } else { + break; + } + } + + content.replace_range(impl_lint_pass_start + lint_name_pos..lint_name_end, ""); + } + } + + if path.exists() + && let Some(lint) = lints.iter().find(|l| l.name == name) + { + if lint.module == name { + // The lint name is the same as the file, we can just delete the entire file + fs::remove_file(path)?; + } else { + // We can't delete the entire file, just remove the declaration + + if let Some(Some("mod.rs")) = path.file_name().map(OsStr::to_str) { + // Remove clippy_lints/src/some_mod/some_lint.rs + let mut lint_mod_path = path.to_path_buf(); + lint_mod_path.set_file_name(name); + lint_mod_path.set_extension("rs"); + + let _ = fs::remove_file(lint_mod_path); + } + + let mut content = + fs::read_to_string(path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy())); + + eprintln!( + "warn: you will have to manually remove any code related to `{name}` from `{}`", + path.display() + ); + + assert!( + content[lint.declaration_range.clone()].contains(&name.to_uppercase()), + "error: `{}` does not contain lint `{}`'s declaration", + path.display(), + lint.name + ); + + // Remove lint declaration (declare_clippy_lint!) + content.replace_range(lint.declaration_range.clone(), ""); + + // Remove the module declaration (mod xyz;) + let mod_decl = format!("\nmod {name};"); + content = content.replacen(&mod_decl, "", 1); + + remove_impl_lint_pass(&lint.name.to_uppercase(), &mut content); + fs::write(path, content).unwrap_or_else(|_| panic!("failed to write to `{}`", path.to_string_lossy())); + } + + remove_test_assets(name); + remove_lint(name, lints); + return Ok(true); + } + + Ok(false) +} diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 70e57fcfc26ee..e237a05b2530e 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -14,11 +14,13 @@ extern crate rustc_driver; extern crate rustc_lexer; extern crate rustc_literal_escaper; +pub mod deprecate_lint; pub mod dogfood; pub mod fmt; pub mod lint; pub mod new_lint; pub mod release; +pub mod rename_lint; pub mod serve; pub mod setup; pub mod sync; diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index bd87e980c2220..565416572a955 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -3,7 +3,9 @@ #![warn(rust_2018_idioms, unused_lifetimes)] use clap::{Args, Parser, Subcommand}; -use clippy_dev::{dogfood, fmt, lint, new_lint, release, serve, setup, sync, update_lints, utils}; +use clippy_dev::{ + deprecate_lint, dogfood, fmt, lint, new_lint, release, rename_lint, serve, setup, sync, update_lints, utils, +}; use std::convert::Infallible; use std::env; @@ -84,13 +86,13 @@ fn main() { old_name, new_name, uplift, - } => update_lints::rename( + } => rename_lint::rename( clippy.version, &old_name, new_name.as_ref().unwrap_or(&old_name), uplift, ), - DevCommand::Deprecate { name, reason } => update_lints::deprecate(clippy.version, &name, &reason), + DevCommand::Deprecate { name, reason } => deprecate_lint::deprecate(clippy.version, &name, &reason), DevCommand::Sync(SyncCommand { subcommand }) => match subcommand { SyncSubcommand::UpdateNightly => sync::update_nightly(), }, diff --git a/clippy_dev/src/rename_lint.rs b/clippy_dev/src/rename_lint.rs new file mode 100644 index 0000000000000..045e1f83e13e7 --- /dev/null +++ b/clippy_dev/src/rename_lint.rs @@ -0,0 +1,185 @@ +use crate::update_lints::{ + RenamedLint, clippy_lints_src_files, gather_all, gen_renamed_lints_test, generate_lint_files, +}; +use crate::utils::{ + UpdateMode, Version, insert_at_marker, replace_ident_like, rewrite_file, try_rename_file, write_file, +}; +use std::ffi::OsStr; +use std::path::Path; +use walkdir::WalkDir; + +/// Runs the `rename_lint` command. +/// +/// This does the following: +/// * Adds an entry to `renamed_lints.rs`. +/// * Renames all lint attributes to the new name (e.g. `#[allow(clippy::lint_name)]`). +/// * Renames the lint struct to the new name. +/// * Renames the module containing the lint struct to the new name if it shares a name with the +/// lint. +/// +/// # Panics +/// Panics for the following conditions: +/// * If a file path could not read from or then written to +/// * If either lint name has a prefix +/// * If `old_name` doesn't name an existing lint. +/// * If `old_name` names a deprecated or renamed lint. +#[allow(clippy::too_many_lines)] +pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: bool) { + if let Some((prefix, _)) = old_name.split_once("::") { + panic!("`{old_name}` should not contain the `{prefix}` prefix"); + } + if let Some((prefix, _)) = new_name.split_once("::") { + panic!("`{new_name}` should not contain the `{prefix}` prefix"); + } + + let (mut lints, deprecated_lints, mut renamed_lints) = gather_all(); + let mut old_lint_index = None; + let mut found_new_name = false; + for (i, lint) in lints.iter().enumerate() { + if lint.name == old_name { + old_lint_index = Some(i); + } else if lint.name == new_name { + found_new_name = true; + } + } + let old_lint_index = old_lint_index.unwrap_or_else(|| panic!("could not find lint `{old_name}`")); + + let lint = RenamedLint { + old_name: format!("clippy::{old_name}"), + new_name: if uplift { + new_name.into() + } else { + format!("clippy::{new_name}") + }, + }; + + // Renamed lints and deprecated lints shouldn't have been found in the lint list, but check just in + // case. + assert!( + !renamed_lints.iter().any(|l| lint.old_name == l.old_name), + "`{old_name}` has already been renamed" + ); + assert!( + !deprecated_lints.iter().any(|l| lint.old_name == l.name), + "`{old_name}` has already been deprecated" + ); + + // Update all lint level attributes. (`clippy::lint_name`) + for file in WalkDir::new(".").into_iter().map(Result::unwrap).filter(|f| { + let name = f.path().file_name(); + let ext = f.path().extension(); + (ext == Some(OsStr::new("rs")) || ext == Some(OsStr::new("fixed"))) + && name != Some(OsStr::new("rename.rs")) + && name != Some(OsStr::new("deprecated_lints.rs")) + }) { + rewrite_file(file.path(), |s| { + replace_ident_like(s, &[(&lint.old_name, &lint.new_name)]) + }); + } + + rewrite_file(Path::new("clippy_lints/src/deprecated_lints.rs"), |s| { + insert_at_marker( + s, + "// end renamed lints. used by `cargo dev rename_lint`", + &format!( + "#[clippy::version = \"{}\"]\n \ + (\"{}\", \"{}\"),\n ", + clippy_version.rust_display(), + lint.old_name, + lint.new_name, + ), + ) + }); + + renamed_lints.push(lint); + renamed_lints.sort_by(|lhs, rhs| { + lhs.new_name + .starts_with("clippy::") + .cmp(&rhs.new_name.starts_with("clippy::")) + .reverse() + .then_with(|| lhs.old_name.cmp(&rhs.old_name)) + }); + + if uplift { + write_file(Path::new("tests/ui/rename.rs"), &gen_renamed_lints_test(&renamed_lints)); + println!( + "`{old_name}` has be uplifted. All the code inside `clippy_lints` related to it needs to be removed manually." + ); + } else if found_new_name { + write_file(Path::new("tests/ui/rename.rs"), &gen_renamed_lints_test(&renamed_lints)); + println!( + "`{new_name}` is already defined. The old linting code inside `clippy_lints` needs to be updated/removed manually." + ); + } else { + // Rename the lint struct and source files sharing a name with the lint. + let lint = &mut lints[old_lint_index]; + let old_name_upper = old_name.to_uppercase(); + let new_name_upper = new_name.to_uppercase(); + lint.name = new_name.into(); + + // Rename test files. only rename `.stderr` and `.fixed` files if the new test name doesn't exist. + if try_rename_file( + Path::new(&format!("tests/ui/{old_name}.rs")), + Path::new(&format!("tests/ui/{new_name}.rs")), + ) { + try_rename_file( + Path::new(&format!("tests/ui/{old_name}.stderr")), + Path::new(&format!("tests/ui/{new_name}.stderr")), + ); + try_rename_file( + Path::new(&format!("tests/ui/{old_name}.fixed")), + Path::new(&format!("tests/ui/{new_name}.fixed")), + ); + } + + // Try to rename the file containing the lint if the file name matches the lint's name. + let replacements; + let replacements = if lint.module == old_name + && try_rename_file( + Path::new(&format!("clippy_lints/src/{old_name}.rs")), + Path::new(&format!("clippy_lints/src/{new_name}.rs")), + ) { + // Edit the module name in the lint list. Note there could be multiple lints. + for lint in lints.iter_mut().filter(|l| l.module == old_name) { + lint.module = new_name.into(); + } + replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)]; + replacements.as_slice() + } else if !lint.module.contains("::") + // Catch cases like `methods/lint_name.rs` where the lint is stored in `methods/mod.rs` + && try_rename_file( + Path::new(&format!("clippy_lints/src/{}/{old_name}.rs", lint.module)), + Path::new(&format!("clippy_lints/src/{}/{new_name}.rs", lint.module)), + ) + { + // Edit the module name in the lint list. Note there could be multiple lints, or none. + let renamed_mod = format!("{}::{old_name}", lint.module); + for lint in lints.iter_mut().filter(|l| l.module == renamed_mod) { + lint.module = format!("{}::{new_name}", lint.module); + } + replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)]; + replacements.as_slice() + } else { + replacements = [(&*old_name_upper, &*new_name_upper), ("", "")]; + &replacements[0..1] + }; + + // Don't change `clippy_utils/src/renamed_lints.rs` here as it would try to edit the lint being + // renamed. + for file in clippy_lints_src_files() { + if file + .path() + .as_os_str() + .to_str() + .is_none_or(|x| x["clippy_lints/src/".len()..] != *"deprecated_lints.rs") + { + rewrite_file(file.path(), |s| replace_ident_like(s, replacements)); + } + } + + generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); + println!("{old_name} has been successfully renamed"); + } + + println!("note: `cargo uitest` still needs to be run to update the test results"); +} diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index e53c454be7a23..2f450b7d9ea67 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -1,15 +1,13 @@ -use crate::utils::{UpdateMode, Version, exit_with_failure, replace_region_in_file}; -use aho_corasick::AhoCorasickBuilder; +use crate::utils::{UpdateMode, exit_with_failure, replace_region_in_file}; use itertools::Itertools; use rustc_lexer::{LiteralKind, TokenKind, tokenize}; use rustc_literal_escaper::{Mode, unescape_unicode}; use std::collections::{HashMap, HashSet}; use std::ffi::OsStr; use std::fmt::{self, Write}; -use std::fs::{self, OpenOptions}; -use std::io::{self, Read, Seek, Write as _}; +use std::fs; use std::ops::Range; -use std::path::{Path, PathBuf}; +use std::path::Path; use walkdir::{DirEntry, WalkDir}; const GENERATED_FILE_COMMENT: &str = "// This file was generated by `cargo dev update_lints`.\n\ @@ -32,7 +30,7 @@ pub fn update(update_mode: UpdateMode) { generate_lint_files(update_mode, &lints, &deprecated_lints, &renamed_lints); } -fn generate_lint_files( +pub fn generate_lint_files( update_mode: UpdateMode, lints: &[Lint], deprecated_lints: &[DeprecatedLint], @@ -123,373 +121,6 @@ pub fn print_lints() { println!("there are {lint_count} lints"); } -/// Runs the `rename_lint` command. -/// -/// This does the following: -/// * Adds an entry to `renamed_lints.rs`. -/// * Renames all lint attributes to the new name (e.g. `#[allow(clippy::lint_name)]`). -/// * Renames the lint struct to the new name. -/// * Renames the module containing the lint struct to the new name if it shares a name with the -/// lint. -/// -/// # Panics -/// Panics for the following conditions: -/// * If a file path could not read from or then written to -/// * If either lint name has a prefix -/// * If `old_name` doesn't name an existing lint. -/// * If `old_name` names a deprecated or renamed lint. -#[allow(clippy::too_many_lines)] -pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: bool) { - if let Some((prefix, _)) = old_name.split_once("::") { - panic!("`{old_name}` should not contain the `{prefix}` prefix"); - } - if let Some((prefix, _)) = new_name.split_once("::") { - panic!("`{new_name}` should not contain the `{prefix}` prefix"); - } - - let (mut lints, deprecated_lints, mut renamed_lints) = gather_all(); - let mut old_lint_index = None; - let mut found_new_name = false; - for (i, lint) in lints.iter().enumerate() { - if lint.name == old_name { - old_lint_index = Some(i); - } else if lint.name == new_name { - found_new_name = true; - } - } - let old_lint_index = old_lint_index.unwrap_or_else(|| panic!("could not find lint `{old_name}`")); - - let lint = RenamedLint { - old_name: format!("clippy::{old_name}"), - new_name: if uplift { - new_name.into() - } else { - format!("clippy::{new_name}") - }, - }; - - // Renamed lints and deprecated lints shouldn't have been found in the lint list, but check just in - // case. - assert!( - !renamed_lints.iter().any(|l| lint.old_name == l.old_name), - "`{old_name}` has already been renamed" - ); - assert!( - !deprecated_lints.iter().any(|l| lint.old_name == l.name), - "`{old_name}` has already been deprecated" - ); - - // Update all lint level attributes. (`clippy::lint_name`) - for file in WalkDir::new(".").into_iter().map(Result::unwrap).filter(|f| { - let name = f.path().file_name(); - let ext = f.path().extension(); - (ext == Some(OsStr::new("rs")) || ext == Some(OsStr::new("fixed"))) - && name != Some(OsStr::new("rename.rs")) - && name != Some(OsStr::new("deprecated_lints.rs")) - }) { - rewrite_file(file.path(), |s| { - replace_ident_like(s, &[(&lint.old_name, &lint.new_name)]) - }); - } - - rewrite_file(Path::new("clippy_lints/src/deprecated_lints.rs"), |s| { - insert_at_marker( - s, - "// end renamed lints. used by `cargo dev rename_lint`", - &format!( - "#[clippy::version = \"{}\"]\n \ - (\"{}\", \"{}\"),\n ", - clippy_version.rust_display(), - lint.old_name, - lint.new_name, - ), - ) - }); - - renamed_lints.push(lint); - renamed_lints.sort_by(|lhs, rhs| { - lhs.new_name - .starts_with("clippy::") - .cmp(&rhs.new_name.starts_with("clippy::")) - .reverse() - .then_with(|| lhs.old_name.cmp(&rhs.old_name)) - }); - - if uplift { - write_file(Path::new("tests/ui/rename.rs"), &gen_renamed_lints_test(&renamed_lints)); - println!( - "`{old_name}` has be uplifted. All the code inside `clippy_lints` related to it needs to be removed manually." - ); - } else if found_new_name { - write_file(Path::new("tests/ui/rename.rs"), &gen_renamed_lints_test(&renamed_lints)); - println!( - "`{new_name}` is already defined. The old linting code inside `clippy_lints` needs to be updated/removed manually." - ); - } else { - // Rename the lint struct and source files sharing a name with the lint. - let lint = &mut lints[old_lint_index]; - let old_name_upper = old_name.to_uppercase(); - let new_name_upper = new_name.to_uppercase(); - lint.name = new_name.into(); - - // Rename test files. only rename `.stderr` and `.fixed` files if the new test name doesn't exist. - if try_rename_file( - Path::new(&format!("tests/ui/{old_name}.rs")), - Path::new(&format!("tests/ui/{new_name}.rs")), - ) { - try_rename_file( - Path::new(&format!("tests/ui/{old_name}.stderr")), - Path::new(&format!("tests/ui/{new_name}.stderr")), - ); - try_rename_file( - Path::new(&format!("tests/ui/{old_name}.fixed")), - Path::new(&format!("tests/ui/{new_name}.fixed")), - ); - } - - // Try to rename the file containing the lint if the file name matches the lint's name. - let replacements; - let replacements = if lint.module == old_name - && try_rename_file( - Path::new(&format!("clippy_lints/src/{old_name}.rs")), - Path::new(&format!("clippy_lints/src/{new_name}.rs")), - ) { - // Edit the module name in the lint list. Note there could be multiple lints. - for lint in lints.iter_mut().filter(|l| l.module == old_name) { - lint.module = new_name.into(); - } - replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)]; - replacements.as_slice() - } else if !lint.module.contains("::") - // Catch cases like `methods/lint_name.rs` where the lint is stored in `methods/mod.rs` - && try_rename_file( - Path::new(&format!("clippy_lints/src/{}/{old_name}.rs", lint.module)), - Path::new(&format!("clippy_lints/src/{}/{new_name}.rs", lint.module)), - ) - { - // Edit the module name in the lint list. Note there could be multiple lints, or none. - let renamed_mod = format!("{}::{old_name}", lint.module); - for lint in lints.iter_mut().filter(|l| l.module == renamed_mod) { - lint.module = format!("{}::{new_name}", lint.module); - } - replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)]; - replacements.as_slice() - } else { - replacements = [(&*old_name_upper, &*new_name_upper), ("", "")]; - &replacements[0..1] - }; - - // Don't change `clippy_utils/src/renamed_lints.rs` here as it would try to edit the lint being - // renamed. - for file in clippy_lints_src_files() { - if file - .path() - .as_os_str() - .to_str() - .is_none_or(|x| x["clippy_lints/src/".len()..] != *"deprecated_lints.rs") - { - rewrite_file(file.path(), |s| replace_ident_like(s, replacements)); - } - } - - generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); - println!("{old_name} has been successfully renamed"); - } - - println!("note: `cargo uitest` still needs to be run to update the test results"); -} - -/// Runs the `deprecate` command -/// -/// This does the following: -/// * Adds an entry to `deprecated_lints.rs`. -/// * Removes the lint declaration (and the entire file if applicable) -/// -/// # Panics -/// -/// If a file path could not read from or written to -pub fn deprecate(clippy_version: Version, name: &str, reason: &str) { - let prefixed_name = if name.starts_with("clippy::") { - name.to_owned() - } else { - format!("clippy::{name}") - }; - let stripped_name = &prefixed_name[8..]; - - let (mut lints, mut deprecated_lints, renamed_lints) = gather_all(); - let Some(lint) = lints.iter().find(|l| l.name == stripped_name) else { - eprintln!("error: failed to find lint `{name}`"); - return; - }; - - let mod_path = { - let mut mod_path = PathBuf::from(format!("clippy_lints/src/{}", lint.module)); - if mod_path.is_dir() { - mod_path = mod_path.join("mod"); - } - - mod_path.set_extension("rs"); - mod_path - }; - - if remove_lint_declaration(stripped_name, &mod_path, &mut lints).unwrap_or(false) { - rewrite_file("clippy_lints/src/deprecated_lints.rs".as_ref(), |s| { - insert_at_marker( - s, - "// end deprecated lints. used by `cargo dev deprecate_lint`", - &format!( - "#[clippy::version = \"{}\"]\n (\"{prefixed_name}\", \"{reason}\"),\n ", - clippy_version.rust_display(), - ), - ) - }); - - deprecated_lints.push(DeprecatedLint { - name: prefixed_name, - reason: reason.into(), - }); - - generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); - println!("info: `{name}` has successfully been deprecated"); - println!("note: you must run `cargo uitest` to update the test results"); - } else { - eprintln!("error: lint not found"); - } -} - -fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec) -> io::Result { - fn remove_lint(name: &str, lints: &mut Vec) { - lints.iter().position(|l| l.name == name).map(|pos| lints.remove(pos)); - } - - fn remove_test_assets(name: &str) { - let test_file_stem = format!("tests/ui/{name}"); - let path = Path::new(&test_file_stem); - - // Some lints have their own directories, delete them - if path.is_dir() { - let _ = fs::remove_dir_all(path); - return; - } - - // Remove all related test files - let _ = fs::remove_file(path.with_extension("rs")); - let _ = fs::remove_file(path.with_extension("stderr")); - let _ = fs::remove_file(path.with_extension("fixed")); - } - - fn remove_impl_lint_pass(lint_name_upper: &str, content: &mut String) { - let impl_lint_pass_start = content.find("impl_lint_pass!").unwrap_or_else(|| { - content - .find("declare_lint_pass!") - .unwrap_or_else(|| panic!("failed to find `impl_lint_pass`")) - }); - let mut impl_lint_pass_end = content[impl_lint_pass_start..] - .find(']') - .expect("failed to find `impl_lint_pass` terminator"); - - impl_lint_pass_end += impl_lint_pass_start; - if let Some(lint_name_pos) = content[impl_lint_pass_start..impl_lint_pass_end].find(lint_name_upper) { - let mut lint_name_end = impl_lint_pass_start + (lint_name_pos + lint_name_upper.len()); - for c in content[lint_name_end..impl_lint_pass_end].chars() { - // Remove trailing whitespace - if c == ',' || c.is_whitespace() { - lint_name_end += 1; - } else { - break; - } - } - - content.replace_range(impl_lint_pass_start + lint_name_pos..lint_name_end, ""); - } - } - - if path.exists() - && let Some(lint) = lints.iter().find(|l| l.name == name) - { - if lint.module == name { - // The lint name is the same as the file, we can just delete the entire file - fs::remove_file(path)?; - } else { - // We can't delete the entire file, just remove the declaration - - if let Some(Some("mod.rs")) = path.file_name().map(OsStr::to_str) { - // Remove clippy_lints/src/some_mod/some_lint.rs - let mut lint_mod_path = path.to_path_buf(); - lint_mod_path.set_file_name(name); - lint_mod_path.set_extension("rs"); - - let _ = fs::remove_file(lint_mod_path); - } - - let mut content = - fs::read_to_string(path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy())); - - eprintln!( - "warn: you will have to manually remove any code related to `{name}` from `{}`", - path.display() - ); - - assert!( - content[lint.declaration_range.clone()].contains(&name.to_uppercase()), - "error: `{}` does not contain lint `{}`'s declaration", - path.display(), - lint.name - ); - - // Remove lint declaration (declare_clippy_lint!) - content.replace_range(lint.declaration_range.clone(), ""); - - // Remove the module declaration (mod xyz;) - let mod_decl = format!("\nmod {name};"); - content = content.replacen(&mod_decl, "", 1); - - remove_impl_lint_pass(&lint.name.to_uppercase(), &mut content); - fs::write(path, content).unwrap_or_else(|_| panic!("failed to write to `{}`", path.to_string_lossy())); - } - - remove_test_assets(name); - remove_lint(name, lints); - return Ok(true); - } - - Ok(false) -} - -/// Replace substrings if they aren't bordered by identifier characters. Returns `None` if there -/// were no replacements. -fn replace_ident_like(contents: &str, replacements: &[(&str, &str)]) -> Option { - fn is_ident_char(c: u8) -> bool { - matches!(c, b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_') - } - - let searcher = AhoCorasickBuilder::new() - .match_kind(aho_corasick::MatchKind::LeftmostLongest) - .build(replacements.iter().map(|&(x, _)| x.as_bytes())) - .unwrap(); - - let mut result = String::with_capacity(contents.len() + 1024); - let mut pos = 0; - let mut edited = false; - for m in searcher.find_iter(contents) { - let (old, new) = replacements[m.pattern()]; - result.push_str(&contents[pos..m.start()]); - result.push_str( - if !is_ident_char(contents.as_bytes().get(m.start().wrapping_sub(1)).copied().unwrap_or(0)) - && !is_ident_char(contents.as_bytes().get(m.end()).copied().unwrap_or(0)) - { - edited = true; - new - } else { - old - }, - ); - pos = m.end(); - } - result.push_str(&contents[pos..]); - edited.then_some(result) -} - fn round_to_fifty(count: usize) -> usize { count / 50 * 50 } @@ -509,12 +140,12 @@ fn process_file(path: impl AsRef, update_mode: UpdateMode, content: &str) /// Lint data parsed from the Clippy source code. #[derive(Clone, PartialEq, Eq, Debug)] -struct Lint { - name: String, - group: String, - desc: String, - module: String, - declaration_range: Range, +pub struct Lint { + pub name: String, + pub group: String, + pub desc: String, + pub module: String, + pub declaration_range: Range, } impl Lint { @@ -537,9 +168,9 @@ impl Lint { } #[derive(Clone, PartialEq, Eq, Debug)] -struct DeprecatedLint { - name: String, - reason: String, +pub struct DeprecatedLint { + pub name: String, + pub reason: String, } impl DeprecatedLint { fn new(name: &str, reason: &str) -> Self { @@ -550,9 +181,9 @@ impl DeprecatedLint { } } -struct RenamedLint { - old_name: String, - new_name: String, +pub struct RenamedLint { + pub old_name: String, + pub new_name: String, } impl RenamedLint { fn new(old_name: &str, new_name: &str) -> Self { @@ -589,7 +220,8 @@ fn gen_deprecated_lints_test(lints: &[DeprecatedLint]) -> String { res } -fn gen_renamed_lints_test(lints: &[RenamedLint]) -> String { +#[must_use] +pub fn gen_renamed_lints_test(lints: &[RenamedLint]) -> String { let mut seen_lints = HashSet::new(); let mut res: String = GENERATED_FILE_COMMENT.into(); @@ -610,7 +242,8 @@ fn gen_renamed_lints_test(lints: &[RenamedLint]) -> String { } /// Gathers all lints defined in `clippy_lints/src` -fn gather_all() -> (Vec, Vec, Vec) { +#[must_use] +pub fn gather_all() -> (Vec, Vec, Vec) { let mut lints = Vec::with_capacity(1000); let mut deprecated_lints = Vec::with_capacity(50); let mut renamed_lints = Vec::with_capacity(50); @@ -638,7 +271,7 @@ fn gather_all() -> (Vec, Vec, Vec) { (lints, deprecated_lints, renamed_lints) } -fn clippy_lints_src_files() -> impl Iterator { +pub fn clippy_lints_src_files() -> impl Iterator { let iter = WalkDir::new("clippy_lints/src").into_iter(); iter.map(Result::unwrap) .filter(|f| f.path().extension() == Some(OsStr::new("rs"))) @@ -808,57 +441,6 @@ fn remove_line_splices(s: &str) -> String { }); res } -fn try_rename_file(old_name: &Path, new_name: &Path) -> bool { - match OpenOptions::new().create_new(true).write(true).open(new_name) { - Ok(file) => drop(file), - Err(e) if matches!(e.kind(), io::ErrorKind::AlreadyExists | io::ErrorKind::NotFound) => return false, - Err(e) => panic_file(e, new_name, "create"), - } - match fs::rename(old_name, new_name) { - Ok(()) => true, - Err(e) => { - drop(fs::remove_file(new_name)); - if e.kind() == io::ErrorKind::NotFound { - false - } else { - panic_file(e, old_name, "rename"); - } - }, - } -} - -#[allow(clippy::needless_pass_by_value)] -fn panic_file(error: io::Error, name: &Path, action: &str) -> ! { - panic!("failed to {action} file `{}`: {error}", name.display()) -} - -fn insert_at_marker(text: &str, marker: &str, new_text: &str) -> Option { - let i = text.find(marker)?; - let (pre, post) = text.split_at(i); - Some([pre, new_text, post].into_iter().collect()) -} - -fn rewrite_file(path: &Path, f: impl FnOnce(&str) -> Option) { - let mut file = OpenOptions::new() - .write(true) - .read(true) - .open(path) - .unwrap_or_else(|e| panic_file(e, path, "open")); - let mut buf = String::new(); - file.read_to_string(&mut buf) - .unwrap_or_else(|e| panic_file(e, path, "read")); - if let Some(new_contents) = f(&buf) { - file.rewind().unwrap_or_else(|e| panic_file(e, path, "write")); - file.write_all(new_contents.as_bytes()) - .unwrap_or_else(|e| panic_file(e, path, "write")); - file.set_len(new_contents.len() as u64) - .unwrap_or_else(|e| panic_file(e, path, "write")); - } -} - -fn write_file(path: &Path, contents: &str) { - fs::write(path, contents).unwrap_or_else(|e| panic_file(e, path, "write")); -} #[cfg(test)] mod tests { diff --git a/clippy_dev/src/utils.rs b/clippy_dev/src/utils.rs index 2b199d96fcdec..38a839c16a75d 100644 --- a/clippy_dev/src/utils.rs +++ b/clippy_dev/src/utils.rs @@ -1,3 +1,4 @@ +use aho_corasick::AhoCorasickBuilder; use core::fmt::{self, Display}; use core::str::FromStr; use std::env; @@ -275,3 +276,87 @@ pub(crate) fn replace_region_in_text<'a>( Ok(res) } + +/// Replace substrings if they aren't bordered by identifier characters. Returns `None` if there +/// were no replacements. +#[must_use] +pub fn replace_ident_like(contents: &str, replacements: &[(&str, &str)]) -> Option { + fn is_ident_char(c: u8) -> bool { + matches!(c, b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_') + } + + let searcher = AhoCorasickBuilder::new() + .match_kind(aho_corasick::MatchKind::LeftmostLongest) + .build(replacements.iter().map(|&(x, _)| x.as_bytes())) + .unwrap(); + + let mut result = String::with_capacity(contents.len() + 1024); + let mut pos = 0; + let mut edited = false; + for m in searcher.find_iter(contents) { + let (old, new) = replacements[m.pattern()]; + result.push_str(&contents[pos..m.start()]); + result.push_str( + if !is_ident_char(contents.as_bytes().get(m.start().wrapping_sub(1)).copied().unwrap_or(0)) + && !is_ident_char(contents.as_bytes().get(m.end()).copied().unwrap_or(0)) + { + edited = true; + new + } else { + old + }, + ); + pos = m.end(); + } + result.push_str(&contents[pos..]); + edited.then_some(result) +} + +#[expect(clippy::must_use_candidate)] +pub fn try_rename_file(old_name: &Path, new_name: &Path) -> bool { + match OpenOptions::new().create_new(true).write(true).open(new_name) { + Ok(file) => drop(file), + Err(e) if matches!(e.kind(), io::ErrorKind::AlreadyExists | io::ErrorKind::NotFound) => return false, + Err(e) => panic_io(&e, "creating", new_name), + } + match fs::rename(old_name, new_name) { + Ok(()) => true, + Err(e) => { + drop(fs::remove_file(new_name)); + if e.kind() == io::ErrorKind::NotFound { + false + } else { + panic_io(&e, "renaming", old_name); + } + }, + } +} + +#[must_use] +pub fn insert_at_marker(text: &str, marker: &str, new_text: &str) -> Option { + let i = text.find(marker)?; + let (pre, post) = text.split_at(i); + Some([pre, new_text, post].into_iter().collect()) +} + +pub fn rewrite_file(path: &Path, f: impl FnOnce(&str) -> Option) { + let mut file = OpenOptions::new() + .write(true) + .read(true) + .open(path) + .unwrap_or_else(|e| panic_io(&e, "opening", path)); + let mut buf = String::new(); + file.read_to_string(&mut buf) + .unwrap_or_else(|e| panic_io(&e, "reading", path)); + if let Some(new_contents) = f(&buf) { + file.rewind().unwrap_or_else(|e| panic_io(&e, "writing", path)); + file.write_all(new_contents.as_bytes()) + .unwrap_or_else(|e| panic_io(&e, "writing", path)); + file.set_len(new_contents.len() as u64) + .unwrap_or_else(|e| panic_io(&e, "writing", path)); + } +} + +pub fn write_file(path: &Path, contents: &str) { + fs::write(path, contents).unwrap_or_else(|e| panic_io(&e, "writing", path)); +} From 98cb92f3235c4c963d1c17e8a833f37091b5b487 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Mon, 14 Apr 2025 13:40:05 -0400 Subject: [PATCH 2221/4206] clippy_dev: Reuse buffers when updating files and don't write unchanged files in `clippy_dev` --- clippy_dev/src/main.rs | 4 +- clippy_dev/src/release.rs | 26 +++-- clippy_dev/src/rename_lint.rs | 17 +-- clippy_dev/src/sync.rs | 31 ++--- clippy_dev/src/update_lints.rs | 206 ++++++++++++++------------------ clippy_dev/src/utils.rs | 207 +++++++++++++++++++++------------ 6 files changed, 252 insertions(+), 239 deletions(-) diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 565416572a955..73248d72d04a0 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -30,10 +30,8 @@ fn main() { DevCommand::UpdateLints { print_only, check } => { if print_only { update_lints::print_lints(); - } else if check { - update_lints::update(utils::UpdateMode::Check); } else { - update_lints::update(utils::UpdateMode::Change); + update_lints::update(utils::UpdateMode::from_check(check)); } }, DevCommand::NewLint { diff --git a/clippy_dev/src/release.rs b/clippy_dev/src/release.rs index 34f81e10a393b..d3b1a7ff3201f 100644 --- a/clippy_dev/src/release.rs +++ b/clippy_dev/src/release.rs @@ -1,8 +1,7 @@ +use crate::utils::{FileUpdater, Version, update_text_region_fn}; use std::fmt::Write; -use crate::utils::{UpdateMode, Version, replace_region_in_file}; - -const CARGO_TOML_FILES: [&str; 4] = [ +static CARGO_TOML_FILES: &[&str] = &[ "clippy_config/Cargo.toml", "clippy_lints/Cargo.toml", "clippy_utils/Cargo.toml", @@ -11,15 +10,18 @@ const CARGO_TOML_FILES: [&str; 4] = [ pub fn bump_version(mut version: Version) { version.minor += 1; - for &file in &CARGO_TOML_FILES { - replace_region_in_file( - UpdateMode::Change, - file.as_ref(), - "# begin autogenerated version\n", - "# end autogenerated version", - |res| { - writeln!(res, "version = \"{}\"", version.toml_display()).unwrap(); - }, + + let mut updater = FileUpdater::default(); + for file in CARGO_TOML_FILES { + updater.update_file( + file, + &mut update_text_region_fn( + "# begin autogenerated version\n", + "# end autogenerated version", + |dst| { + writeln!(dst, "version = \"{}\"", version.toml_display()).unwrap(); + }, + ), ); } } diff --git a/clippy_dev/src/rename_lint.rs b/clippy_dev/src/rename_lint.rs index 045e1f83e13e7..25db95a44893e 100644 --- a/clippy_dev/src/rename_lint.rs +++ b/clippy_dev/src/rename_lint.rs @@ -1,8 +1,8 @@ use crate::update_lints::{ - RenamedLint, clippy_lints_src_files, gather_all, gen_renamed_lints_test, generate_lint_files, + RenamedLint, clippy_lints_src_files, gather_all, gen_renamed_lints_test_fn, generate_lint_files, }; use crate::utils::{ - UpdateMode, Version, insert_at_marker, replace_ident_like, rewrite_file, try_rename_file, write_file, + FileUpdater, UpdateMode, Version, insert_at_marker, replace_ident_like, rewrite_file, try_rename_file, }; use std::ffi::OsStr; use std::path::Path; @@ -32,6 +32,7 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b panic!("`{new_name}` should not contain the `{prefix}` prefix"); } + let mut updater = FileUpdater::default(); let (mut lints, deprecated_lints, mut renamed_lints) = gather_all(); let mut old_lint_index = None; let mut found_new_name = false; @@ -72,8 +73,8 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b && name != Some(OsStr::new("rename.rs")) && name != Some(OsStr::new("deprecated_lints.rs")) }) { - rewrite_file(file.path(), |s| { - replace_ident_like(s, &[(&lint.old_name, &lint.new_name)]) + updater.update_file(file.path(), &mut |_, src, dst| { + replace_ident_like(&[(&lint.old_name, &lint.new_name)], src, dst) }); } @@ -101,12 +102,12 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b }); if uplift { - write_file(Path::new("tests/ui/rename.rs"), &gen_renamed_lints_test(&renamed_lints)); + updater.update_file("tests/ui/rename.rs", &mut gen_renamed_lints_test_fn(&renamed_lints)); println!( "`{old_name}` has be uplifted. All the code inside `clippy_lints` related to it needs to be removed manually." ); } else if found_new_name { - write_file(Path::new("tests/ui/rename.rs"), &gen_renamed_lints_test(&renamed_lints)); + updater.update_file("tests/ui/rename.rs", &mut gen_renamed_lints_test_fn(&renamed_lints)); println!( "`{new_name}` is already defined. The old linting code inside `clippy_lints` needs to be updated/removed manually." ); @@ -173,7 +174,9 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b .to_str() .is_none_or(|x| x["clippy_lints/src/".len()..] != *"deprecated_lints.rs") { - rewrite_file(file.path(), |s| replace_ident_like(s, replacements)); + updater.update_file(file.path(), &mut |_, src, dst| { + replace_ident_like(replacements, src, dst) + }); } } diff --git a/clippy_dev/src/sync.rs b/clippy_dev/src/sync.rs index a6b65e561c223..c699b0d7b959c 100644 --- a/clippy_dev/src/sync.rs +++ b/clippy_dev/src/sync.rs @@ -1,33 +1,18 @@ -use std::fmt::Write; -use std::path::Path; - +use crate::utils::{FileUpdater, update_text_region_fn}; use chrono::offset::Utc; - -use crate::utils::{UpdateMode, replace_region_in_file}; +use std::fmt::Write; pub fn update_nightly() { - // Update rust-toolchain nightly version let date = Utc::now().format("%Y-%m-%d").to_string(); - replace_region_in_file( - UpdateMode::Change, - Path::new("rust-toolchain.toml"), + let update = &mut update_text_region_fn( "# begin autogenerated nightly\n", "# end autogenerated nightly", - |res| { - writeln!(res, "channel = \"nightly-{date}\"").unwrap(); + |dst| { + writeln!(dst, "channel = \"nightly-{date}\"").unwrap(); }, ); - // Update clippy_utils nightly version - replace_region_in_file( - UpdateMode::Change, - Path::new("clippy_utils/README.md"), - "\n", - "", - |res| { - writeln!(res, "```").unwrap(); - writeln!(res, "nightly-{date}").unwrap(); - writeln!(res, "```").unwrap(); - }, - ); + let mut updater = FileUpdater::default(); + updater.update_file("rust-toolchain.toml", update); + updater.update_file("clippy_utils/README.md", update); } diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 2f450b7d9ea67..ad995f5e4c2c5 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -1,10 +1,10 @@ -use crate::utils::{UpdateMode, exit_with_failure, replace_region_in_file}; +use crate::utils::{FileUpdater, UpdateMode, UpdateStatus, update_text_region_fn}; use itertools::Itertools; use rustc_lexer::{LiteralKind, TokenKind, tokenize}; use rustc_literal_escaper::{Mode, unescape_unicode}; use std::collections::{HashMap, HashSet}; use std::ffi::OsStr; -use std::fmt::{self, Write}; +use std::fmt::Write; use std::fs; use std::ops::Range; use std::path::Path; @@ -33,74 +33,77 @@ pub fn update(update_mode: UpdateMode) { pub fn generate_lint_files( update_mode: UpdateMode, lints: &[Lint], - deprecated_lints: &[DeprecatedLint], - renamed_lints: &[RenamedLint], + deprecated: &[DeprecatedLint], + renamed: &[RenamedLint], ) { let mut lints = lints.to_owned(); - lints.sort_by_key(|lint| lint.name.clone()); - - replace_region_in_file( - update_mode, - Path::new("README.md"), - "[There are over ", - " lints included in this crate!]", - |res| { - write!(res, "{}", round_to_fifty(lints.len())).unwrap(); - }, - ); - - replace_region_in_file( - update_mode, - Path::new("book/src/README.md"), - "[There are over ", - " lints included in this crate!]", - |res| { - write!(res, "{}", round_to_fifty(lints.len())).unwrap(); - }, - ); - - replace_region_in_file( - update_mode, - Path::new("CHANGELOG.md"), - "\n", - "", - |res| { - for lint in lints - .iter() - .map(|l| &*l.name) - .chain(deprecated_lints.iter().filter_map(|l| l.name.strip_prefix("clippy::"))) - .chain(renamed_lints.iter().filter_map(|l| l.old_name.strip_prefix("clippy::"))) - .sorted() - { - writeln!(res, "[`{lint}`]: {DOCS_LINK}#{lint}").unwrap(); - } - }, - ); - - // This has to be in lib.rs, otherwise rustfmt doesn't work - replace_region_in_file( - update_mode, - Path::new("clippy_lints/src/lib.rs"), - "// begin lints modules, do not remove this comment, it’s used in `update_lints`\n", - "// end lints modules, do not remove this comment, it’s used in `update_lints`", - |res| { - for lint_mod in lints.iter().map(|l| &l.module).unique().sorted() { - writeln!(res, "mod {lint_mod};").unwrap(); - } - }, - ); - - process_file( - "clippy_lints/src/declared_lints.rs", + lints.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name)); + FileUpdater::default().update_files_checked( + "cargo dev update_lints", update_mode, - &gen_declared_lints(lints.iter()), + &mut [ + ( + "README.md", + &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| { + write!(dst, "{}", round_to_fifty(lints.len())).unwrap(); + }), + ), + ( + "book/src/README.md", + &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| { + write!(dst, "{}", round_to_fifty(lints.len())).unwrap(); + }), + ), + ( + "CHANGELOG.md", + &mut update_text_region_fn( + "\n", + "", + |dst| { + for lint in lints + .iter() + .map(|l| &*l.name) + .chain(deprecated.iter().filter_map(|l| l.name.strip_prefix("clippy::"))) + .chain(renamed.iter().filter_map(|l| l.old_name.strip_prefix("clippy::"))) + .sorted() + { + writeln!(dst, "[`{lint}`]: {DOCS_LINK}#{lint}").unwrap(); + } + }, + ), + ), + ( + "clippy_lints/src/lib.rs", + &mut update_text_region_fn( + "// begin lints modules, do not remove this comment, it’s used in `update_lints`\n", + "// end lints modules, do not remove this comment, it’s used in `update_lints`", + |dst| { + for lint_mod in lints.iter().map(|l| &l.module).sorted().dedup() { + writeln!(dst, "mod {lint_mod};").unwrap(); + } + }, + ), + ), + ("clippy_lints/src/declared_lints.rs", &mut |_, src, dst| { + dst.push_str(GENERATED_FILE_COMMENT); + dst.push_str("pub static LINTS: &[&crate::LintInfo] = &[\n"); + for (module_name, lint_name) in lints.iter().map(|l| (&l.module, l.name.to_uppercase())).sorted() { + writeln!(dst, " crate::{module_name}::{lint_name}_INFO,").unwrap(); + } + dst.push_str("];\n"); + UpdateStatus::from_changed(src != dst) + }), + ("tests/ui/deprecated.rs", &mut |_, src, dst| { + dst.push_str(GENERATED_FILE_COMMENT); + for lint in deprecated { + writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.name, lint.name).unwrap(); + } + dst.push_str("\nfn main() {}\n"); + UpdateStatus::from_changed(src != dst) + }), + ("tests/ui/rename.rs", &mut gen_renamed_lints_test_fn(renamed)), + ], ); - - let content = gen_deprecated_lints_test(deprecated_lints); - process_file("tests/ui/deprecated.rs", update_mode, &content); - - let content = gen_renamed_lints_test(renamed_lints); - process_file("tests/ui/rename.rs", update_mode, &content); } pub fn print_lints() { @@ -125,19 +128,6 @@ fn round_to_fifty(count: usize) -> usize { count / 50 * 50 } -fn process_file(path: impl AsRef, update_mode: UpdateMode, content: &str) { - if update_mode == UpdateMode::Check { - let old_content = - fs::read_to_string(&path).unwrap_or_else(|e| panic!("Cannot read from {}: {e}", path.as_ref().display())); - if content != old_content { - exit_with_failure(); - } - } else { - fs::write(&path, content.as_bytes()) - .unwrap_or_else(|e| panic!("Cannot write to {}: {e}", path.as_ref().display())); - } -} - /// Lint data parsed from the Clippy source code. #[derive(Clone, PartialEq, Eq, Debug)] pub struct Lint { @@ -194,51 +184,25 @@ impl RenamedLint { } } -/// Generates the code for registering lints -#[must_use] -fn gen_declared_lints<'a>(lints: impl Iterator) -> String { - let mut details: Vec<_> = lints.map(|l| (&l.module, l.name.to_uppercase())).collect(); - details.sort_unstable(); - - let mut output = GENERATED_FILE_COMMENT.to_string(); - output.push_str("pub static LINTS: &[&crate::LintInfo] = &[\n"); - - for (module_name, lint_name) in details { - let _: fmt::Result = writeln!(output, " crate::{module_name}::{lint_name}_INFO,"); - } - output.push_str("];\n"); - - output -} - -fn gen_deprecated_lints_test(lints: &[DeprecatedLint]) -> String { - let mut res: String = GENERATED_FILE_COMMENT.into(); - for lint in lints { - writeln!(res, "#![warn({})] //~ ERROR: lint `{}`", lint.name, lint.name).unwrap(); - } - res.push_str("\nfn main() {}\n"); - res -} - -#[must_use] -pub fn gen_renamed_lints_test(lints: &[RenamedLint]) -> String { - let mut seen_lints = HashSet::new(); - let mut res: String = GENERATED_FILE_COMMENT.into(); - - res.push_str("#![allow(clippy::duplicated_attributes)]\n"); - for lint in lints { - if seen_lints.insert(&lint.new_name) { - writeln!(res, "#![allow({})]", lint.new_name).unwrap(); +pub fn gen_renamed_lints_test_fn(lints: &[RenamedLint]) -> impl Fn(&Path, &str, &mut String) -> UpdateStatus { + move |_, src, dst| { + let mut seen_lints = HashSet::new(); + dst.push_str(GENERATED_FILE_COMMENT); + dst.push_str("#![allow(clippy::duplicated_attributes)]\n"); + for lint in lints { + if seen_lints.insert(&lint.new_name) { + writeln!(dst, "#![allow({})]", lint.new_name).unwrap(); + } } - } - seen_lints.clear(); - for lint in lints { - if seen_lints.insert(&lint.old_name) { - writeln!(res, "#![warn({})] //~ ERROR: lint `{}`", lint.old_name, lint.old_name).unwrap(); + seen_lints.clear(); + for lint in lints { + if seen_lints.insert(&lint.old_name) { + writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.old_name, lint.old_name).unwrap(); + } } + dst.push_str("\nfn main() {}\n"); + UpdateStatus::from_changed(src != dst) } - res.push_str("\nfn main() {}\n"); - res } /// Gathers all lints defined in `clippy_lints/src` diff --git a/clippy_dev/src/utils.rs b/clippy_dev/src/utils.rs index 38a839c16a75d..aaacdcf65c168 100644 --- a/clippy_dev/src/utils.rs +++ b/clippy_dev/src/utils.rs @@ -209,78 +209,145 @@ pub fn exit_if_err(status: io::Result) { } } -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy)] +pub enum UpdateStatus { + Unchanged, + Changed, +} +impl UpdateStatus { + #[must_use] + pub fn from_changed(value: bool) -> Self { + if value { Self::Changed } else { Self::Unchanged } + } + + #[must_use] + pub fn is_changed(self) -> bool { + matches!(self, Self::Changed) + } +} + +#[derive(Clone, Copy)] pub enum UpdateMode { - Check, Change, + Check, +} +impl UpdateMode { + #[must_use] + pub fn from_check(check: bool) -> Self { + if check { Self::Check } else { Self::Change } + } } -pub(crate) fn exit_with_failure() { - println!( - "Not all lints defined properly. \ - Please run `cargo dev update_lints` to make sure all lints are defined properly." - ); - process::exit(1); +#[derive(Default)] +pub struct FileUpdater { + src_buf: String, + dst_buf: String, } +impl FileUpdater { + fn update_file_checked_inner( + &mut self, + tool: &str, + mode: UpdateMode, + path: &Path, + update: &mut dyn FnMut(&Path, &str, &mut String) -> UpdateStatus, + ) { + let mut file = File::open(path, OpenOptions::new().read(true).write(true)); + file.read_to_cleared_string(&mut self.src_buf); + self.dst_buf.clear(); + match (mode, update(path, &self.src_buf, &mut self.dst_buf)) { + (UpdateMode::Check, UpdateStatus::Changed) => { + eprintln!( + "the contents of `{}` are out of date\nplease run `{tool}` to update", + path.display() + ); + process::exit(1); + }, + (UpdateMode::Change, UpdateStatus::Changed) => file.replace_contents(self.dst_buf.as_bytes()), + (UpdateMode::Check | UpdateMode::Change, UpdateStatus::Unchanged) => {}, + } + } -/// Replaces a region in a file delimited by two lines matching regexes. -/// -/// `path` is the relative path to the file on which you want to perform the replacement. -/// -/// See `replace_region_in_text` for documentation of the other options. -/// -/// # Panics -/// -/// Panics if the path could not read or then written -pub(crate) fn replace_region_in_file( - update_mode: UpdateMode, - path: &Path, - start: &str, - end: &str, - write_replacement: impl FnMut(&mut String), -) { - let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {e}", path.display())); - let new_contents = match replace_region_in_text(&contents, start, end, write_replacement) { - Ok(x) => x, - Err(delim) => panic!("Couldn't find `{delim}` in file `{}`", path.display()), - }; + fn update_file_inner(&mut self, path: &Path, update: &mut dyn FnMut(&Path, &str, &mut String) -> UpdateStatus) { + let mut file = File::open(path, OpenOptions::new().read(true).write(true)); + file.read_to_cleared_string(&mut self.src_buf); + self.dst_buf.clear(); + if update(path, &self.src_buf, &mut self.dst_buf).is_changed() { + file.replace_contents(self.dst_buf.as_bytes()); + } + } - match update_mode { - UpdateMode::Check if contents != new_contents => exit_with_failure(), - UpdateMode::Check => (), - UpdateMode::Change => { - if let Err(e) = fs::write(path, new_contents.as_bytes()) { - panic!("Cannot write to `{}`: {e}", path.display()); - } - }, + pub fn update_file_checked( + &mut self, + tool: &str, + mode: UpdateMode, + path: impl AsRef, + update: &mut dyn FnMut(&Path, &str, &mut String) -> UpdateStatus, + ) { + self.update_file_checked_inner(tool, mode, path.as_ref(), update); + } + + #[expect(clippy::type_complexity)] + pub fn update_files_checked( + &mut self, + tool: &str, + mode: UpdateMode, + files: &mut [( + impl AsRef, + &mut dyn FnMut(&Path, &str, &mut String) -> UpdateStatus, + )], + ) { + for (path, update) in files { + self.update_file_checked_inner(tool, mode, path.as_ref(), update); + } + } + + pub fn update_file( + &mut self, + path: impl AsRef, + update: &mut dyn FnMut(&Path, &str, &mut String) -> UpdateStatus, + ) { + self.update_file_inner(path.as_ref(), update); } } /// Replaces a region in a text delimited by two strings. Returns the new text if both delimiters /// were found, or the missing delimiter if not. -pub(crate) fn replace_region_in_text<'a>( - text: &str, - start: &'a str, - end: &'a str, - mut write_replacement: impl FnMut(&mut String), -) -> Result { - let (text_start, rest) = text.split_once(start).ok_or(start)?; - let (_, text_end) = rest.split_once(end).ok_or(end)?; - - let mut res = String::with_capacity(text.len() + 4096); - res.push_str(text_start); - res.push_str(start); - write_replacement(&mut res); - res.push_str(end); - res.push_str(text_end); - - Ok(res) +pub fn update_text_region( + path: &Path, + start: &str, + end: &str, + src: &str, + dst: &mut String, + insert: &mut impl FnMut(&mut String), +) -> UpdateStatus { + let Some((src_start, src_end)) = src.split_once(start) else { + panic!("`{}` does not contain `{start}`", path.display()); + }; + let Some((replaced_text, src_end)) = src_end.split_once(end) else { + panic!("`{}` does not contain `{end}`", path.display()); + }; + dst.push_str(src_start); + dst.push_str(start); + let new_start = dst.len(); + insert(dst); + let changed = dst[new_start..] != *replaced_text; + dst.push_str(end); + dst.push_str(src_end); + UpdateStatus::from_changed(changed) +} + +pub fn update_text_region_fn( + start: &str, + end: &str, + mut insert: impl FnMut(&mut String), +) -> impl FnMut(&Path, &str, &mut String) -> UpdateStatus { + move |path, src, dst| update_text_region(path, start, end, src, dst, &mut insert) } /// Replace substrings if they aren't bordered by identifier characters. Returns `None` if there /// were no replacements. #[must_use] -pub fn replace_ident_like(contents: &str, replacements: &[(&str, &str)]) -> Option { +pub fn replace_ident_like(replacements: &[(&str, &str)], src: &str, dst: &mut String) -> UpdateStatus { fn is_ident_char(c: u8) -> bool { matches!(c, b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_') } @@ -290,26 +357,20 @@ pub fn replace_ident_like(contents: &str, replacements: &[(&str, &str)]) -> Opti .build(replacements.iter().map(|&(x, _)| x.as_bytes())) .unwrap(); - let mut result = String::with_capacity(contents.len() + 1024); let mut pos = 0; - let mut edited = false; - for m in searcher.find_iter(contents) { - let (old, new) = replacements[m.pattern()]; - result.push_str(&contents[pos..m.start()]); - result.push_str( - if !is_ident_char(contents.as_bytes().get(m.start().wrapping_sub(1)).copied().unwrap_or(0)) - && !is_ident_char(contents.as_bytes().get(m.end()).copied().unwrap_or(0)) - { - edited = true; - new - } else { - old - }, - ); - pos = m.end(); + let mut changed = false; + for m in searcher.find_iter(src) { + if !is_ident_char(src.as_bytes().get(m.start().wrapping_sub(1)).copied().unwrap_or(0)) + && !is_ident_char(src.as_bytes().get(m.end()).copied().unwrap_or(0)) + { + dst.push_str(&src[pos..m.start()]); + dst.push_str(replacements[m.pattern()].1); + pos = m.end(); + changed = true; + } } - result.push_str(&contents[pos..]); - edited.then_some(result) + dst.push_str(&src[pos..]); + UpdateStatus::from_changed(changed) } #[expect(clippy::must_use_candidate)] From 2c85cb0371ca0e8980a4225714ed3407f1670e12 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Mon, 14 Apr 2025 14:14:03 -0400 Subject: [PATCH 2222/4206] clippy_dev: Only build `AhoCorasick` searcher once for multiple files. --- clippy_dev/src/rename_lint.rs | 15 ++++----- clippy_dev/src/utils.rs | 59 +++++++++++++++++++++-------------- 2 files changed, 42 insertions(+), 32 deletions(-) diff --git a/clippy_dev/src/rename_lint.rs b/clippy_dev/src/rename_lint.rs index 25db95a44893e..c78ec98c1aa88 100644 --- a/clippy_dev/src/rename_lint.rs +++ b/clippy_dev/src/rename_lint.rs @@ -1,9 +1,7 @@ use crate::update_lints::{ RenamedLint, clippy_lints_src_files, gather_all, gen_renamed_lints_test_fn, generate_lint_files, }; -use crate::utils::{ - FileUpdater, UpdateMode, Version, insert_at_marker, replace_ident_like, rewrite_file, try_rename_file, -}; +use crate::utils::{FileUpdater, StringReplacer, UpdateMode, Version, insert_at_marker, rewrite_file, try_rename_file}; use std::ffi::OsStr; use std::path::Path; use walkdir::WalkDir; @@ -66,6 +64,8 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b ); // Update all lint level attributes. (`clippy::lint_name`) + let replacements = &[(&*lint.old_name, &*lint.new_name)]; + let replacer = StringReplacer::new(replacements); for file in WalkDir::new(".").into_iter().map(Result::unwrap).filter(|f| { let name = f.path().file_name(); let ext = f.path().extension(); @@ -73,9 +73,7 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b && name != Some(OsStr::new("rename.rs")) && name != Some(OsStr::new("deprecated_lints.rs")) }) { - updater.update_file(file.path(), &mut |_, src, dst| { - replace_ident_like(&[(&lint.old_name, &lint.new_name)], src, dst) - }); + updater.update_file(file.path(), &mut replacer.replace_ident_fn()); } rewrite_file(Path::new("clippy_lints/src/deprecated_lints.rs"), |s| { @@ -167,6 +165,7 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b // Don't change `clippy_utils/src/renamed_lints.rs` here as it would try to edit the lint being // renamed. + let replacer = StringReplacer::new(replacements); for file in clippy_lints_src_files() { if file .path() @@ -174,9 +173,7 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b .to_str() .is_none_or(|x| x["clippy_lints/src/".len()..] != *"deprecated_lints.rs") { - updater.update_file(file.path(), &mut |_, src, dst| { - replace_ident_like(replacements, src, dst) - }); + updater.update_file(file.path(), &mut replacer.replace_ident_fn()); } } diff --git a/clippy_dev/src/utils.rs b/clippy_dev/src/utils.rs index aaacdcf65c168..9f48832af006f 100644 --- a/clippy_dev/src/utils.rs +++ b/clippy_dev/src/utils.rs @@ -1,4 +1,4 @@ -use aho_corasick::AhoCorasickBuilder; +use aho_corasick::{AhoCorasick, AhoCorasickBuilder}; use core::fmt::{self, Display}; use core::str::FromStr; use std::env; @@ -344,33 +344,46 @@ pub fn update_text_region_fn( move |path, src, dst| update_text_region(path, start, end, src, dst, &mut insert) } -/// Replace substrings if they aren't bordered by identifier characters. Returns `None` if there -/// were no replacements. #[must_use] -pub fn replace_ident_like(replacements: &[(&str, &str)], src: &str, dst: &mut String) -> UpdateStatus { - fn is_ident_char(c: u8) -> bool { - matches!(c, b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_') - } +pub fn is_ident_char(c: u8) -> bool { + matches!(c, b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_') +} - let searcher = AhoCorasickBuilder::new() - .match_kind(aho_corasick::MatchKind::LeftmostLongest) - .build(replacements.iter().map(|&(x, _)| x.as_bytes())) - .unwrap(); +pub struct StringReplacer<'a> { + searcher: AhoCorasick, + replacements: &'a [(&'a str, &'a str)], +} +impl<'a> StringReplacer<'a> { + #[must_use] + pub fn new(replacements: &'a [(&'a str, &'a str)]) -> Self { + Self { + searcher: AhoCorasickBuilder::new() + .match_kind(aho_corasick::MatchKind::LeftmostLongest) + .build(replacements.iter().map(|&(x, _)| x)) + .unwrap(), + replacements, + } + } - let mut pos = 0; - let mut changed = false; - for m in searcher.find_iter(src) { - if !is_ident_char(src.as_bytes().get(m.start().wrapping_sub(1)).copied().unwrap_or(0)) - && !is_ident_char(src.as_bytes().get(m.end()).copied().unwrap_or(0)) - { - dst.push_str(&src[pos..m.start()]); - dst.push_str(replacements[m.pattern()].1); - pos = m.end(); - changed = true; + /// Replace substrings if they aren't bordered by identifier characters. + pub fn replace_ident_fn(&self) -> impl Fn(&Path, &str, &mut String) -> UpdateStatus { + move |_, src, dst| { + let mut pos = 0; + let mut changed = false; + for m in self.searcher.find_iter(src) { + if !is_ident_char(src.as_bytes().get(m.start().wrapping_sub(1)).copied().unwrap_or(0)) + && !is_ident_char(src.as_bytes().get(m.end()).copied().unwrap_or(0)) + { + changed = true; + dst.push_str(&src[pos..m.start()]); + dst.push_str(self.replacements[m.pattern()].1); + pos = m.end(); + } + } + dst.push_str(&src[pos..]); + UpdateStatus::from_changed(changed) } } - dst.push_str(&src[pos..]); - UpdateStatus::from_changed(changed) } #[expect(clippy::must_use_candidate)] From 97abf33fa0f8eec35d162d8eab1673e29ecbba29 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 15 Apr 2025 00:27:55 -0400 Subject: [PATCH 2223/4206] clippy_dev: Split gathering lint decls from parsing deprecated lints. --- clippy_dev/src/deprecate_lint.rs | 38 +++++--- clippy_dev/src/rename_lint.rs | 45 +++++---- clippy_dev/src/update_lints.rs | 140 +++++++++++++++++---------- clippy_dev/src/utils.rs | 63 ++++++------ clippy_lints/src/deprecated_lints.rs | 2 - 5 files changed, 172 insertions(+), 116 deletions(-) diff --git a/clippy_dev/src/deprecate_lint.rs b/clippy_dev/src/deprecate_lint.rs index 2c4286b325db3..bf0e777104698 100644 --- a/clippy_dev/src/deprecate_lint.rs +++ b/clippy_dev/src/deprecate_lint.rs @@ -1,5 +1,7 @@ -use crate::update_lints::{DeprecatedLint, Lint, gather_all, generate_lint_files}; -use crate::utils::{UpdateMode, Version, insert_at_marker, rewrite_file}; +use crate::update_lints::{ + DeprecatedLint, DeprecatedLints, Lint, find_lint_decls, generate_lint_files, read_deprecated_lints, +}; +use crate::utils::{UpdateMode, Version}; use std::ffi::OsStr; use std::path::{Path, PathBuf}; use std::{fs, io}; @@ -21,7 +23,16 @@ pub fn deprecate(clippy_version: Version, name: &str, reason: &str) { }; let stripped_name = &prefixed_name[8..]; - let (mut lints, mut deprecated_lints, renamed_lints) = gather_all(); + let mut lints = find_lint_decls(); + let DeprecatedLints { + renamed: renamed_lints, + deprecated: mut deprecated_lints, + file: mut deprecated_file, + contents: mut deprecated_contents, + deprecated_end, + .. + } = read_deprecated_lints(); + let Some(lint) = lints.iter().find(|l| l.name == stripped_name) else { eprintln!("error: failed to find lint `{name}`"); return; @@ -38,16 +49,17 @@ pub fn deprecate(clippy_version: Version, name: &str, reason: &str) { }; if remove_lint_declaration(stripped_name, &mod_path, &mut lints).unwrap_or(false) { - rewrite_file("clippy_lints/src/deprecated_lints.rs".as_ref(), |s| { - insert_at_marker( - s, - "// end deprecated lints. used by `cargo dev deprecate_lint`", - &format!( - "#[clippy::version = \"{}\"]\n (\"{prefixed_name}\", \"{reason}\"),\n ", - clippy_version.rust_display(), - ), - ) - }); + deprecated_contents.insert_str( + deprecated_end as usize, + &format!( + " #[clippy::version = \"{}\"]\n (\"{}\", \"{}\"),\n", + clippy_version.rust_display(), + prefixed_name, + reason, + ), + ); + deprecated_file.replace_contents(deprecated_contents.as_bytes()); + drop(deprecated_file); deprecated_lints.push(DeprecatedLint { name: prefixed_name, diff --git a/clippy_dev/src/rename_lint.rs b/clippy_dev/src/rename_lint.rs index c78ec98c1aa88..9e7e5d97f0219 100644 --- a/clippy_dev/src/rename_lint.rs +++ b/clippy_dev/src/rename_lint.rs @@ -1,7 +1,8 @@ use crate::update_lints::{ - RenamedLint, clippy_lints_src_files, gather_all, gen_renamed_lints_test_fn, generate_lint_files, + DeprecatedLints, RenamedLint, find_lint_decls, gen_renamed_lints_test_fn, generate_lint_files, + read_deprecated_lints, }; -use crate::utils::{FileUpdater, StringReplacer, UpdateMode, Version, insert_at_marker, rewrite_file, try_rename_file}; +use crate::utils::{FileUpdater, StringReplacer, UpdateMode, Version, try_rename_file}; use std::ffi::OsStr; use std::path::Path; use walkdir::WalkDir; @@ -31,7 +32,16 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b } let mut updater = FileUpdater::default(); - let (mut lints, deprecated_lints, mut renamed_lints) = gather_all(); + let mut lints = find_lint_decls(); + let DeprecatedLints { + renamed: mut renamed_lints, + deprecated: deprecated_lints, + file: mut deprecated_file, + contents: mut deprecated_contents, + renamed_end, + .. + } = read_deprecated_lints(); + let mut old_lint_index = None; let mut found_new_name = false; for (i, lint) in lints.iter().enumerate() { @@ -76,19 +86,17 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b updater.update_file(file.path(), &mut replacer.replace_ident_fn()); } - rewrite_file(Path::new("clippy_lints/src/deprecated_lints.rs"), |s| { - insert_at_marker( - s, - "// end renamed lints. used by `cargo dev rename_lint`", - &format!( - "#[clippy::version = \"{}\"]\n \ - (\"{}\", \"{}\"),\n ", - clippy_version.rust_display(), - lint.old_name, - lint.new_name, - ), - ) - }); + deprecated_contents.insert_str( + renamed_end as usize, + &format!( + " #[clippy::version = \"{}\"]\n (\"{}\", \"{}\"),\n", + clippy_version.rust_display(), + lint.old_name, + lint.new_name, + ), + ); + deprecated_file.replace_contents(deprecated_contents.as_bytes()); + drop(deprecated_file); renamed_lints.push(lint); renamed_lints.sort_by(|lhs, rhs| { @@ -166,12 +174,13 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b // Don't change `clippy_utils/src/renamed_lints.rs` here as it would try to edit the lint being // renamed. let replacer = StringReplacer::new(replacements); - for file in clippy_lints_src_files() { + for file in WalkDir::new("clippy_lints/src") { + let file = file.expect("error reading `clippy_lints/src`"); if file .path() .as_os_str() .to_str() - .is_none_or(|x| x["clippy_lints/src/".len()..] != *"deprecated_lints.rs") + .is_some_and(|x| x.ends_with("*.rs") && x["clippy_lints/src/".len()..] != *"deprecated_lints.rs") { updater.update_file(file.path(), &mut replacer.replace_ident_fn()); } diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index ad995f5e4c2c5..28c988bc19ff2 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -1,11 +1,11 @@ -use crate::utils::{FileUpdater, UpdateMode, UpdateStatus, update_text_region_fn}; +use crate::utils::{File, FileAction, FileUpdater, UpdateMode, UpdateStatus, panic_file, update_text_region_fn}; +use core::str; use itertools::Itertools; use rustc_lexer::{LiteralKind, TokenKind, tokenize}; use rustc_literal_escaper::{Mode, unescape_unicode}; use std::collections::{HashMap, HashSet}; -use std::ffi::OsStr; use std::fmt::Write; -use std::fs; +use std::fs::OpenOptions; use std::ops::Range; use std::path::Path; use walkdir::{DirEntry, WalkDir}; @@ -26,8 +26,11 @@ const DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.ht%20///%20///%20Panics%20if%20a%20file%20path%20could%20not%20read%20from%20or%20then%20written%20to%20pub%20fn%20update(update_mode:%20UpdateMode)%20%7B-%20%20%20%20let%20(lints,%20deprecated_lints,%20renamed_lints)%20=%20gather_all();-%20%20%20%20generate_lint_files(update_mode,%20&lints,%20&deprecated_lints,%20&renamed_lints);+%20%20%20%20let%20lints%20=%20find_lint_decls();+%20%20%20%20let%20DeprecatedLints%20%7B+%20%20%20%20%20%20%20%20renamed,%20deprecated,%20..+%20%20%20%20%7D%20=%20read_deprecated_lints();+%20%20%20%20generate_lint_files(update_mode,%20&lints,%20&deprecated,%20&renamed);%20%7D%20%20pub%20fn%20generate_lint_files(@@%20-36,8%20+39,6%20@@%20pub%20fn%20generate_lint_files(%20%20%20%20%20deprecated:%20&[DeprecatedLint],%20%20%20%20%20renamed:%20&[RenamedLint],%20)%20%7B-%20%20%20%20let%20mut%20lints%20=%20lints.to_owned();-%20%20%20%20lints.sort_by(|lhs,%20rhs|%20lhs.name.cmp(&rhs.name));%20%20%20%20%20FileUpdater::default().update_files_checked("cargo dev update_lints", update_mode, @@ -107,7 +108,7 @@ pub fn generate_lint_files( } pub fn print_lints() { - let (lints, _, _) = gather_all(); + let lints = find_lint_decls(); let lint_count = lints.len(); let grouped_by_lint_group = Lint::by_lint_group(lints.into_iter()); @@ -205,40 +206,54 @@ pub fn gen_renamed_lints_test_fn(lints: &[RenamedLint]) -> impl Fn(&Path, &str, } } -/// Gathers all lints defined in `clippy_lints/src` +/// Finds all lint declarations (`declare_clippy_lint!`) #[must_use] -pub fn gather_all() -> (Vec, Vec, Vec) { +pub fn find_lint_decls() -> Vec { let mut lints = Vec::with_capacity(1000); - let mut deprecated_lints = Vec::with_capacity(50); - let mut renamed_lints = Vec::with_capacity(50); - - for file in clippy_lints_src_files() { - let path = file.path(); - let contents = - fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {e}", path.display())); - let module = path.as_os_str().to_str().unwrap()["clippy_lints/src/".len()..].replace(['/', '\\'], "::"); - - // If the lints are stored in mod.rs, we get the module name from - // the containing directory: - let module = if let Some(module) = module.strip_suffix("::mod.rs") { - module - } else { - module.strip_suffix(".rs").unwrap_or(&module) - }; - - if module == "deprecated_lints" { - parse_deprecated_contents(&contents, &mut deprecated_lints, &mut renamed_lints); - } else { - parse_contents(&contents, module, &mut lints); - } + let mut contents = String::new(); + for (file, module) in read_src_with_module("clippy_lints/src".as_ref()) { + parse_clippy_lint_decls( + File::open_read_to_cleared_string(file.path(), &mut contents), + &module, + &mut lints, + ); } - (lints, deprecated_lints, renamed_lints) + lints.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name)); + lints } -pub fn clippy_lints_src_files() -> impl Iterator { - let iter = WalkDir::new("clippy_lints/src").into_iter(); - iter.map(Result::unwrap) - .filter(|f| f.path().extension() == Some(OsStr::new("rs"))) +/// Reads the source files from the given root directory +fn read_src_with_module(src_root: &Path) -> impl use<'_> + Iterator { + WalkDir::new(src_root).into_iter().filter_map(move |e| { + let e = match e { + Ok(e) => e, + Err(ref e) => panic_file(e, FileAction::Read, src_root), + }; + let path = e.path().as_os_str().as_encoded_bytes(); + if let Some(path) = path.strip_suffix(b".rs") + && let Some(path) = path.get("clippy_lints/src/".len()..) + { + if path == b"lib" { + Some((e, String::new())) + } else { + let path = if let Some(path) = path.strip_suffix(b"mod") + && let Some(path) = path.strip_suffix(b"/").or_else(|| path.strip_suffix(b"\\")) + { + path + } else { + path + }; + if let Ok(path) = str::from_utf8(path) { + let path = path.replace(['/', '\\'], "::"); + Some((e, path)) + } else { + None + } + } + } else { + None + } + }) } macro_rules! match_tokens { @@ -266,7 +281,7 @@ pub(crate) struct LintDeclSearchResult<'a> { } /// Parse a source file looking for `declare_clippy_lint` macro invocations. -fn parse_contents(contents: &str, module: &str, lints: &mut Vec) { +fn parse_clippy_lint_decls(contents: &str, module: &str, lints: &mut Vec) { let mut offset = 0usize; let mut iter = tokenize(contents).map(|t| { let range = offset..offset + t.len as usize; @@ -333,15 +348,40 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec) { } } -/// Parse a source file looking for `declare_deprecated_lint` macro invocations. -fn parse_deprecated_contents(contents: &str, deprecated: &mut Vec, renamed: &mut Vec) { - let Some((_, contents)) = contents.split_once("\ndeclare_with_version! { DEPRECATED") else { - return; - }; - let Some((deprecated_src, renamed_src)) = contents.split_once("\ndeclare_with_version! { RENAMED") else { - return; +pub struct DeprecatedLints { + pub file: File<'static>, + pub contents: String, + pub deprecated: Vec, + pub renamed: Vec, + pub deprecated_end: u32, + pub renamed_end: u32, +} + +#[must_use] +#[expect(clippy::cast_possible_truncation)] +pub fn read_deprecated_lints() -> DeprecatedLints { + let mut res = DeprecatedLints { + file: File::open( + "clippy_lints/src/deprecated_lints.rs", + OpenOptions::new().read(true).write(true), + ), + contents: String::new(), + deprecated: Vec::with_capacity(30), + renamed: Vec::with_capacity(80), + deprecated_end: 0, + renamed_end: 0, }; + res.file.read_append_to_string(&mut res.contents); + + let (_, contents) = res.contents.split_once("\ndeclare_with_version! { DEPRECATED").unwrap(); + let (deprecated_src, contents) = contents.split_once("\n]}").unwrap(); + res.deprecated_end = (res.contents.len() - contents.len() - 2) as u32; + + let (_, contents) = contents.split_once("\ndeclare_with_version! { RENAMED").unwrap(); + let (renamed_src, contents) = contents.split_once("\n]}").unwrap(); + res.renamed_end = (res.contents.len() - contents.len() - 2) as u32; + for line in deprecated_src.lines() { let mut offset = 0usize; let mut iter = tokenize(line).map(|t| { @@ -362,7 +402,7 @@ fn parse_deprecated_contents(contents: &str, deprecated: &mut Vec &'static str { + match self { + Self::Open => "opening", + Self::Read => "reading", + Self::Write => "writing", + Self::Create => "creating", + Self::Rename => "renaming", + } + } +} + #[cold] #[track_caller] -fn panic_io(e: &io::Error, action: &str, path: &Path) -> ! { - panic!("error {action} `{}`: {}", path.display(), *e) +pub fn panic_file(err: &impl Display, action: FileAction, path: &Path) -> ! { + panic!("error {} `{}`: {}", action.as_str(), path.display(), *err) } /// Wrapper around `std::fs::File` which panics with a path on failure. @@ -30,7 +50,7 @@ impl<'a> File<'a> { let path = path.as_ref(); match options.open(path) { Ok(inner) => Self { inner, path }, - Err(e) => panic_io(&e, "opening", path), + Err(e) => panic_file(&e, FileAction::Open, path), } } @@ -41,7 +61,7 @@ impl<'a> File<'a> { match options.open(path) { Ok(inner) => Some(Self { inner, path }), Err(e) if e.kind() == io::ErrorKind::NotFound => None, - Err(e) => panic_io(&e, "opening", path), + Err(e) => panic_file(&e, FileAction::Open, path), } } @@ -59,7 +79,7 @@ impl<'a> File<'a> { pub fn read_append_to_string<'dst>(&mut self, dst: &'dst mut String) -> &'dst mut String { match self.inner.read_to_string(dst) { Ok(_) => {}, - Err(e) => panic_io(&e, "reading", self.path), + Err(e) => panic_file(&e, FileAction::Read, self.path), } dst } @@ -81,7 +101,7 @@ impl<'a> File<'a> { Err(e) => Err(e), }; if let Err(e) = res { - panic_io(&e, "writing", self.path); + panic_file(&e, FileAction::Write, self.path); } } } @@ -391,7 +411,7 @@ pub fn try_rename_file(old_name: &Path, new_name: &Path) -> bool { match OpenOptions::new().create_new(true).write(true).open(new_name) { Ok(file) => drop(file), Err(e) if matches!(e.kind(), io::ErrorKind::AlreadyExists | io::ErrorKind::NotFound) => return false, - Err(e) => panic_io(&e, "creating", new_name), + Err(e) => panic_file(&e, FileAction::Create, new_name), } match fs::rename(old_name, new_name) { Ok(()) => true, @@ -400,37 +420,12 @@ pub fn try_rename_file(old_name: &Path, new_name: &Path) -> bool { if e.kind() == io::ErrorKind::NotFound { false } else { - panic_io(&e, "renaming", old_name); + panic_file(&e, FileAction::Rename, old_name); } }, } } -#[must_use] -pub fn insert_at_marker(text: &str, marker: &str, new_text: &str) -> Option { - let i = text.find(marker)?; - let (pre, post) = text.split_at(i); - Some([pre, new_text, post].into_iter().collect()) -} - -pub fn rewrite_file(path: &Path, f: impl FnOnce(&str) -> Option) { - let mut file = OpenOptions::new() - .write(true) - .read(true) - .open(path) - .unwrap_or_else(|e| panic_io(&e, "opening", path)); - let mut buf = String::new(); - file.read_to_string(&mut buf) - .unwrap_or_else(|e| panic_io(&e, "reading", path)); - if let Some(new_contents) = f(&buf) { - file.rewind().unwrap_or_else(|e| panic_io(&e, "writing", path)); - file.write_all(new_contents.as_bytes()) - .unwrap_or_else(|e| panic_io(&e, "writing", path)); - file.set_len(new_contents.len() as u64) - .unwrap_or_else(|e| panic_io(&e, "writing", path)); - } -} - pub fn write_file(path: &Path, contents: &str) { - fs::write(path, contents).unwrap_or_else(|e| panic_io(&e, "writing", path)); + fs::write(path, contents).unwrap_or_else(|e| panic_file(&e, FileAction::Write, path)); } diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index a1909c5363ff0..d37b0efd35d1a 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -44,7 +44,6 @@ declare_with_version! { DEPRECATED(DEPRECATED_VERSION): &[(&str, &str)] = &[ ("clippy::option_map_or_err_ok", "`clippy::manual_ok_or` covers this case"), #[clippy::version = "1.86.0"] ("clippy::match_on_vec_items", "`clippy::indexing_slicing` covers indexing and slicing on `Vec<_>`"), - // end deprecated lints. used by `cargo dev deprecate_lint` ]} #[rustfmt::skip] @@ -195,5 +194,4 @@ declare_with_version! { RENAMED(RENAMED_VERSION): &[(&str, &str)] = &[ ("clippy::transmute_float_to_int", "unnecessary_transmutes"), #[clippy::version = "1.88.0"] ("clippy::transmute_num_to_bytes", "unnecessary_transmutes"), - // end renamed lints. used by `cargo dev rename_lint` ]} From a9beb8b68d5bc7e66636fdab0ecf21af793e4b7f Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 15 Apr 2025 00:58:31 -0400 Subject: [PATCH 2224/4206] clippy_dev: Refactor token parsing to avoid macros. --- clippy_dev/src/new_lint.rs | 119 ++++------- clippy_dev/src/update_lints.rs | 286 ++++++++++----------------- clippy_dev/src/utils.rs | 195 ++++++++++++++++++ clippy_lints/src/deprecated_lints.rs | 8 +- 4 files changed, 345 insertions(+), 263 deletions(-) diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index a6e8c3ac3249f..4121daa85e6d7 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -1,4 +1,4 @@ -use crate::utils::Version; +use crate::utils::{RustSearcher, Token, Version}; use clap::ValueEnum; use indoc::{formatdoc, writedoc}; use std::fmt::{self, Write as _}; @@ -360,8 +360,7 @@ fn get_lint_declaration(version: Version, name_upper: &str, category: &str) -> S pub {name_upper}, {category}, "default lint description" - }} - "#, + }}"#, version.rust_display(), ) } @@ -446,9 +445,6 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R #[allow(clippy::too_many_lines)] fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str> { - use super::update_lints::{LintDeclSearchResult, match_tokens}; - use rustc_lexer::TokenKind; - let lint_name_upper = lint.name.to_uppercase(); let mut file_contents = fs::read_to_string(path)?; @@ -459,81 +455,11 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str> path.display() ); - let mut offset = 0usize; - let mut last_decl_curly_offset = None; - let mut lint_context = None; - - let mut iter = rustc_lexer::tokenize(&file_contents).map(|t| { - let range = offset..offset + t.len as usize; - offset = range.end; - - LintDeclSearchResult { - token_kind: t.kind, - content: &file_contents[range.clone()], - range, - } - }); - - // Find both the last lint declaration (declare_clippy_lint!) and the lint pass impl - while let Some(LintDeclSearchResult { content, .. }) = iter.find(|result| result.token_kind == TokenKind::Ident) { - let mut iter = iter - .by_ref() - .filter(|t| !matches!(t.token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. })); - - match content { - "declare_clippy_lint" => { - // matches `!{` - match_tokens!(iter, Bang OpenBrace); - if let Some(LintDeclSearchResult { range, .. }) = - iter.find(|result| result.token_kind == TokenKind::CloseBrace) - { - last_decl_curly_offset = Some(range.end); - } - }, - "impl" => { - let mut token = iter.next(); - match token { - // matches <'foo> - Some(LintDeclSearchResult { - token_kind: TokenKind::Lt, - .. - }) => { - match_tokens!(iter, Lifetime { .. } Gt); - token = iter.next(); - }, - None => break, - _ => {}, - } - - if let Some(LintDeclSearchResult { - token_kind: TokenKind::Ident, - content, - .. - }) = token - { - // Get the appropriate lint context struct - lint_context = match content { - "LateLintPass" => Some("LateContext"), - "EarlyLintPass" => Some("EarlyContext"), - _ => continue, - }; - } - }, - _ => {}, - } - } - - drop(iter); - - let last_decl_curly_offset = - last_decl_curly_offset.unwrap_or_else(|| panic!("No lint declarations found in `{}`", path.display())); - let lint_context = - lint_context.unwrap_or_else(|| panic!("No lint pass implementation found in `{}`", path.display())); + let (lint_context, lint_decl_end) = parse_mod_file(path, &file_contents); // Add the lint declaration to `mod.rs` - file_contents.replace_range( - // Remove the trailing newline, which should always be present - last_decl_curly_offset..=last_decl_curly_offset, + file_contents.insert_str( + lint_decl_end, &format!( "\n\n{}", get_lint_declaration(lint.clippy_version, &lint_name_upper, lint.category) @@ -588,6 +514,41 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str> Ok(lint_context) } +// Find both the last lint declaration (declare_clippy_lint!) and the lint pass impl +fn parse_mod_file(path: &Path, contents: &str) -> (&'static str, usize) { + #[allow(clippy::enum_glob_use)] + use Token::*; + + let mut context = None; + let mut decl_end = None; + let mut searcher = RustSearcher::new(contents); + while let Some(name) = searcher.find_capture_token(CaptureIdent) { + match name { + "declare_clippy_lint" => { + if searcher.match_tokens(&[Bang, OpenBrace], &mut []) && searcher.find_token(CloseBrace) { + decl_end = Some(searcher.pos()); + } + }, + "impl" => { + let mut capture = ""; + if searcher.match_tokens(&[Lt, Lifetime, Gt, CaptureIdent], &mut [&mut capture]) { + match capture { + "LateLintPass" => context = Some("LateContext"), + "EarlyLintPass" => context = Some("EarlyContext"), + _ => {}, + } + } + }, + _ => {}, + } + } + + ( + context.unwrap_or_else(|| panic!("No lint pass implementation found in `{}`", path.display())), + decl_end.unwrap_or_else(|| panic!("No lint declarations found in `{}`", path.display())) as usize, + ) +} + #[test] fn test_camel_case() { let s = "a_lint"; diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 28c988bc19ff2..09e97491c510d 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -1,8 +1,7 @@ -use crate::utils::{File, FileAction, FileUpdater, UpdateMode, UpdateStatus, panic_file, update_text_region_fn}; -use core::str; +use crate::utils::{ + File, FileAction, FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, panic_file, update_text_region_fn, +}; use itertools::Itertools; -use rustc_lexer::{LiteralKind, TokenKind, tokenize}; -use rustc_literal_escaper::{Mode, unescape_unicode}; use std::collections::{HashMap, HashSet}; use std::fmt::Write; use std::fs::OpenOptions; @@ -140,17 +139,6 @@ pub struct Lint { } impl Lint { - #[must_use] - fn new(name: &str, group: &str, desc: &str, module: &str, declaration_range: Range) -> Self { - Self { - name: name.to_lowercase(), - group: group.into(), - desc: remove_line_splices(desc), - module: module.into(), - declaration_range, - } - } - /// Returns the lints in a `HashMap`, grouped by the different lint groups #[must_use] fn by_lint_group(lints: impl Iterator) -> HashMap> { @@ -163,27 +151,11 @@ pub struct DeprecatedLint { pub name: String, pub reason: String, } -impl DeprecatedLint { - fn new(name: &str, reason: &str) -> Self { - Self { - name: remove_line_splices(name), - reason: remove_line_splices(reason), - } - } -} pub struct RenamedLint { pub old_name: String, pub new_name: String, } -impl RenamedLint { - fn new(old_name: &str, new_name: &str) -> Self { - Self { - old_name: remove_line_splices(old_name), - new_name: remove_line_splices(new_name), - } - } -} pub fn gen_renamed_lints_test_fn(lints: &[RenamedLint]) -> impl Fn(&Path, &str, &mut String) -> UpdateStatus { move |_, src, dst| { @@ -213,6 +185,7 @@ pub fn find_lint_decls() -> Vec { let mut contents = String::new(); for (file, module) in read_src_with_module("clippy_lints/src".as_ref()) { parse_clippy_lint_decls( + file.path(), File::open_read_to_cleared_string(file.path(), &mut contents), &module, &mut lints, @@ -256,94 +229,34 @@ fn read_src_with_module(src_root: &Path) -> impl use<'_> + Iterator { - { - $(#[allow(clippy::redundant_pattern)] let Some(LintDeclSearchResult { - token_kind: TokenKind::$token $({$($fields)*})?, - content: $($capture @)? _, - .. - }) = $iter.next() else { - continue; - };)* - #[allow(clippy::unused_unit)] - { ($($($capture,)?)*) } - } - } -} - -pub(crate) use match_tokens; - -pub(crate) struct LintDeclSearchResult<'a> { - pub token_kind: TokenKind, - pub content: &'a str, - pub range: Range, -} - /// Parse a source file looking for `declare_clippy_lint` macro invocations. -fn parse_clippy_lint_decls(contents: &str, module: &str, lints: &mut Vec) { - let mut offset = 0usize; - let mut iter = tokenize(contents).map(|t| { - let range = offset..offset + t.len as usize; - offset = range.end; - - LintDeclSearchResult { - token_kind: t.kind, - content: &contents[range.clone()], - range, - } - }); - - while let Some(LintDeclSearchResult { range, .. }) = iter.find( - |LintDeclSearchResult { - token_kind, content, .. - }| token_kind == &TokenKind::Ident && *content == "declare_clippy_lint", - ) { - let start = range.start; - let mut iter = iter - .by_ref() - .filter(|t| !matches!(t.token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. })); - // matches `!{` - match_tokens!(iter, Bang OpenBrace); - match iter.next() { - // #[clippy::version = "version"] pub - Some(LintDeclSearchResult { - token_kind: TokenKind::Pound, - .. - }) => { - match_tokens!(iter, OpenBracket Ident Colon Colon Ident Eq Literal{..} CloseBracket Ident); - }, - // pub - Some(LintDeclSearchResult { - token_kind: TokenKind::Ident, - .. - }) => (), - _ => continue, - } - - let (name, group, desc) = match_tokens!( - iter, - // LINT_NAME - Ident(name) Comma - // group, - Ident(group) Comma - // "description" - Literal{..}(desc) - ); - - if let Some(end) = iter.find_map(|t| { - if let LintDeclSearchResult { - token_kind: TokenKind::CloseBrace, - range, - .. - } = t - { - Some(range.end) - } else { - None - } - }) { - lints.push(Lint::new(name, group, desc, module, start..end)); +fn parse_clippy_lint_decls(path: &Path, contents: &str, module: &str, lints: &mut Vec) { + #[allow(clippy::enum_glob_use)] + use Token::*; + #[rustfmt::skip] + static DECL_TOKENS: &[Token] = &[ + // !{ /// docs + Bang, OpenBrace, AnyDoc, + // #[clippy::version = "version"] + Pound, OpenBracket, Ident("clippy"), DoubleColon, Ident("version"), Eq, LitStr, CloseBracket, + // pub NAME, GROUP, "description" + Ident("pub"), CaptureIdent, Comma, CaptureIdent, Comma, CaptureLitStr, + ]; + + let mut searcher = RustSearcher::new(contents); + while searcher.find_token(Ident("declare_clippy_lint")) { + let start = searcher.pos() as usize - "declare_clippy_lint".len(); + let (mut name, mut group, mut desc) = ("", "", ""); + if searcher.match_tokens(DECL_TOKENS, &mut [&mut name, &mut group, &mut desc]) + && searcher.find_token(CloseBrace) + { + lints.push(Lint { + name: name.to_lowercase(), + group: group.into(), + desc: parse_str_single_line(path, desc), + module: module.into(), + declaration_range: start..searcher.pos() as usize, + }); } } } @@ -358,13 +271,30 @@ pub struct DeprecatedLints { } #[must_use] -#[expect(clippy::cast_possible_truncation)] pub fn read_deprecated_lints() -> DeprecatedLints { + #[allow(clippy::enum_glob_use)] + use Token::*; + #[rustfmt::skip] + static DECL_TOKENS: &[Token] = &[ + // #[clippy::version = "version"] + Pound, OpenBracket, Ident("clippy"), DoubleColon, Ident("version"), Eq, LitStr, CloseBracket, + // ("first", "second"), + OpenParen, CaptureLitStr, Comma, CaptureLitStr, CloseParen, Comma, + ]; + #[rustfmt::skip] + static DEPRECATED_TOKENS: &[Token] = &[ + // !{ DEPRECATED(DEPRECATED_VERSION) = [ + Bang, OpenBrace, Ident("DEPRECATED"), OpenParen, Ident("DEPRECATED_VERSION"), CloseParen, Eq, OpenBracket, + ]; + #[rustfmt::skip] + static RENAMED_TOKENS: &[Token] = &[ + // !{ RENAMED(RENAMED_VERSION) = [ + Bang, OpenBrace, Ident("RENAMED"), OpenParen, Ident("RENAMED_VERSION"), CloseParen, Eq, OpenBracket, + ]; + + let path = "clippy_lints/src/deprecated_lints.rs"; let mut res = DeprecatedLints { - file: File::open( - "clippy_lints/src/deprecated_lints.rs", - OpenOptions::new().read(true).write(true), - ), + file: File::open(path, OpenOptions::new().read(true).write(true)), contents: String::new(), deprecated: Vec::with_capacity(30), renamed: Vec::with_capacity(80), @@ -373,81 +303,77 @@ pub fn read_deprecated_lints() -> DeprecatedLints { }; res.file.read_append_to_string(&mut res.contents); + let mut searcher = RustSearcher::new(&res.contents); - let (_, contents) = res.contents.split_once("\ndeclare_with_version! { DEPRECATED").unwrap(); - let (deprecated_src, contents) = contents.split_once("\n]}").unwrap(); - res.deprecated_end = (res.contents.len() - contents.len() - 2) as u32; - - let (_, contents) = contents.split_once("\ndeclare_with_version! { RENAMED").unwrap(); - let (renamed_src, contents) = contents.split_once("\n]}").unwrap(); - res.renamed_end = (res.contents.len() - contents.len() - 2) as u32; - - for line in deprecated_src.lines() { - let mut offset = 0usize; - let mut iter = tokenize(line).map(|t| { - let range = offset..offset + t.len as usize; - offset = range.end; + // First instance is the macro definition. + assert!( + searcher.find_token(Ident("declare_with_version")), + "error reading deprecated lints" + ); - LintDeclSearchResult { - token_kind: t.kind, - content: &line[range.clone()], - range, - } - }); - - let (name, reason) = match_tokens!( - iter, - // ("old_name", - Whitespace OpenParen Literal{kind: LiteralKind::Str{..},..}(name) Comma - // "new_name"), - Whitespace Literal{kind: LiteralKind::Str{..},..}(reason) CloseParen Comma - ); - res.deprecated.push(DeprecatedLint::new(name, reason)); + if searcher.find_token(Ident("declare_with_version")) && searcher.match_tokens(DEPRECATED_TOKENS, &mut []) { + let mut name = ""; + let mut reason = ""; + while searcher.match_tokens(DECL_TOKENS, &mut [&mut name, &mut reason]) { + res.deprecated.push(DeprecatedLint { + name: parse_str_single_line(path.as_ref(), name), + reason: parse_str_single_line(path.as_ref(), reason), + }); + } + } else { + panic!("error reading deprecated lints"); } - for line in renamed_src.lines() { - let mut offset = 0usize; - let mut iter = tokenize(line).map(|t| { - let range = offset..offset + t.len as usize; - offset = range.end; - - LintDeclSearchResult { - token_kind: t.kind, - content: &line[range.clone()], - range, - } - }); - - let (old_name, new_name) = match_tokens!( - iter, - // ("old_name", - Whitespace OpenParen Literal{kind: LiteralKind::Str{..},..}(old_name) Comma - // "new_name"), - Whitespace Literal{kind: LiteralKind::Str{..},..}(new_name) CloseParen Comma - ); - res.renamed.push(RenamedLint::new(old_name, new_name)); + // position of the closing `]}` of `declare_with_version` + res.deprecated_end = searcher.pos(); + + if searcher.find_token(Ident("declare_with_version")) && searcher.match_tokens(RENAMED_TOKENS, &mut []) { + let mut old_name = ""; + let mut new_name = ""; + while searcher.match_tokens(DECL_TOKENS, &mut [&mut old_name, &mut new_name]) { + res.renamed.push(RenamedLint { + old_name: parse_str_single_line(path.as_ref(), old_name), + new_name: parse_str_single_line(path.as_ref(), new_name), + }); + } + } else { + panic!("error reading renamed lints"); } + // position of the closing `]}` of `declare_with_version` + res.renamed_end = searcher.pos(); res } /// Removes the line splices and surrounding quotes from a string literal -fn remove_line_splices(s: &str) -> String { +fn parse_str_lit(s: &str) -> String { + let (s, mode) = if let Some(s) = s.strip_prefix("r") { + (s.trim_matches('#'), rustc_literal_escaper::Mode::RawStr) + } else { + (s, rustc_literal_escaper::Mode::Str) + }; let s = s - .strip_prefix('r') - .unwrap_or(s) - .trim_matches('#') .strip_prefix('"') .and_then(|s| s.strip_suffix('"')) .unwrap_or_else(|| panic!("expected quoted string, found `{s}`")); let mut res = String::with_capacity(s.len()); - unescape_unicode(s, Mode::Str, &mut |range, ch| { - if ch.is_ok() { - res.push_str(&s[range]); + rustc_literal_escaper::unescape_unicode(s, mode, &mut |_, ch| { + if let Ok(ch) = ch { + res.push(ch); } }); res } +fn parse_str_single_line(path: &Path, s: &str) -> String { + let value = parse_str_lit(s); + assert!( + !value.contains('\n'), + "error parsing `{}`: `{s}` should be a single line string", + path.display(), + ); + value +} + #[cfg(test)] mod tests { use super::*; @@ -471,7 +397,7 @@ mod tests { } "#; let mut result = Vec::new(); - parse_clippy_lint_decls(CONTENTS, "module_name", &mut result); + parse_clippy_lint_decls("".as_ref(), CONTENTS, "module_name", &mut result); for r in &mut result { r.declaration_range = Range::default(); } diff --git a/clippy_dev/src/utils.rs b/clippy_dev/src/utils.rs index 87645aff6742b..1fb338d39cc9c 100644 --- a/clippy_dev/src/utils.rs +++ b/clippy_dev/src/utils.rs @@ -1,6 +1,8 @@ use aho_corasick::{AhoCorasick, AhoCorasickBuilder}; use core::fmt::{self, Display}; +use core::slice; use core::str::FromStr; +use rustc_lexer as lexer; use std::env; use std::fs::{self, OpenOptions}; use std::io::{self, Read as _, Seek as _, SeekFrom, Write}; @@ -406,6 +408,199 @@ impl<'a> StringReplacer<'a> { } } +#[derive(Clone, Copy)] +pub enum Token { + /// Matches any number of doc comments. + AnyDoc, + Ident(&'static str), + CaptureIdent, + LitStr, + CaptureLitStr, + Bang, + CloseBrace, + CloseBracket, + CloseParen, + /// This will consume the first colon even if the second doesn't exist. + DoubleColon, + Comma, + Eq, + Lifetime, + Lt, + Gt, + OpenBrace, + OpenBracket, + OpenParen, + Pound, +} + +pub struct RustSearcher<'txt> { + text: &'txt str, + cursor: lexer::Cursor<'txt>, + pos: u32, + + // Either the next token or a zero-sized whitespace sentinel. + next_token: lexer::Token, +} +impl<'txt> RustSearcher<'txt> { + #[must_use] + pub fn new(text: &'txt str) -> Self { + Self { + text, + cursor: lexer::Cursor::new(text), + pos: 0, + + // Sentinel value indicating there is no read token. + next_token: lexer::Token { + len: 0, + kind: lexer::TokenKind::Whitespace, + }, + } + } + + #[must_use] + pub fn peek_text(&self) -> &'txt str { + &self.text[self.pos as usize..(self.pos + self.next_token.len) as usize] + } + + #[must_use] + pub fn peek(&self) -> lexer::TokenKind { + self.next_token.kind + } + + #[must_use] + pub fn pos(&self) -> u32 { + self.pos + } + + #[must_use] + pub fn at_end(&self) -> bool { + self.next_token.kind == lexer::TokenKind::Eof + } + + pub fn step(&mut self) { + // `next_len` is zero for the sentinel value and the eof marker. + self.pos += self.next_token.len; + self.next_token = self.cursor.advance_token(); + } + + /// Consumes the next token if it matches the requested value and captures the value if + /// requested. Returns true if a token was matched. + fn read_token(&mut self, token: Token, captures: &mut slice::IterMut<'_, &mut &'txt str>) -> bool { + loop { + match (token, self.next_token.kind) { + // Has to be the first match arm so the empty sentinel token will be handled. + // This will also skip all whitespace/comments preceding any tokens. + ( + _, + lexer::TokenKind::Whitespace + | lexer::TokenKind::LineComment { doc_style: None } + | lexer::TokenKind::BlockComment { + doc_style: None, + terminated: true, + }, + ) => { + self.step(); + if self.at_end() { + // `AnyDoc` always matches. + return matches!(token, Token::AnyDoc); + } + }, + ( + Token::AnyDoc, + lexer::TokenKind::BlockComment { terminated: true, .. } | lexer::TokenKind::LineComment { .. }, + ) => { + self.step(); + if self.at_end() { + // `AnyDoc` always matches. + return true; + } + }, + (Token::AnyDoc, _) => return true, + (Token::Bang, lexer::TokenKind::Bang) + | (Token::CloseBrace, lexer::TokenKind::CloseBrace) + | (Token::CloseBracket, lexer::TokenKind::CloseBracket) + | (Token::CloseParen, lexer::TokenKind::CloseParen) + | (Token::Comma, lexer::TokenKind::Comma) + | (Token::Eq, lexer::TokenKind::Eq) + | (Token::Lifetime, lexer::TokenKind::Lifetime { .. }) + | (Token::Lt, lexer::TokenKind::Lt) + | (Token::Gt, lexer::TokenKind::Gt) + | (Token::OpenBrace, lexer::TokenKind::OpenBrace) + | (Token::OpenBracket, lexer::TokenKind::OpenBracket) + | (Token::OpenParen, lexer::TokenKind::OpenParen) + | (Token::Pound, lexer::TokenKind::Pound) + | ( + Token::LitStr, + lexer::TokenKind::Literal { + kind: lexer::LiteralKind::Str { terminated: true } | lexer::LiteralKind::RawStr { .. }, + .. + }, + ) => { + self.step(); + return true; + }, + (Token::Ident(x), lexer::TokenKind::Ident) if x == self.peek_text() => { + self.step(); + return true; + }, + (Token::DoubleColon, lexer::TokenKind::Colon) => { + self.step(); + if !self.at_end() && matches!(self.next_token.kind, lexer::TokenKind::Colon) { + self.step(); + return true; + } + return false; + }, + ( + Token::CaptureLitStr, + lexer::TokenKind::Literal { + kind: lexer::LiteralKind::Str { terminated: true } | lexer::LiteralKind::RawStr { .. }, + .. + }, + ) + | (Token::CaptureIdent, lexer::TokenKind::Ident) => { + **captures.next().unwrap() = self.peek_text(); + self.step(); + return true; + }, + _ => return false, + } + } + } + + #[must_use] + pub fn find_token(&mut self, token: Token) -> bool { + let mut capture = [].iter_mut(); + while !self.read_token(token, &mut capture) { + self.step(); + if self.at_end() { + return false; + } + } + true + } + + #[must_use] + pub fn find_capture_token(&mut self, token: Token) -> Option<&'txt str> { + let mut res = ""; + let mut capture = &mut res; + let mut capture = slice::from_mut(&mut capture).iter_mut(); + while !self.read_token(token, &mut capture) { + self.step(); + if self.at_end() { + return None; + } + } + Some(res) + } + + #[must_use] + pub fn match_tokens(&mut self, tokens: &[Token], captures: &mut [&mut &'txt str]) -> bool { + let mut captures = captures.iter_mut(); + tokens.iter().all(|&t| self.read_token(t, &mut captures)) + } +} + #[expect(clippy::must_use_candidate)] pub fn try_rename_file(old_name: &Path, new_name: &Path) -> bool { match OpenOptions::new().create_new(true).write(true).open(new_name) { diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index d37b0efd35d1a..946515386690c 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -2,18 +2,18 @@ // Prefer to use those when possible. macro_rules! declare_with_version { - ($name:ident($name_version:ident): &[$ty:ty] = &[$( + ($name:ident($name_version:ident) = [$( #[clippy::version = $version:literal] $e:expr, )*]) => { - pub static $name: &[$ty] = &[$($e),*]; + pub static $name: &[(&str, &str)] = &[$($e),*]; #[allow(unused)] pub static $name_version: &[&str] = &[$($version),*]; }; } #[rustfmt::skip] -declare_with_version! { DEPRECATED(DEPRECATED_VERSION): &[(&str, &str)] = &[ +declare_with_version! { DEPRECATED(DEPRECATED_VERSION) = [ #[clippy::version = "pre 1.29.0"] ("clippy::should_assert_eq", "`assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can"), #[clippy::version = "pre 1.29.0"] @@ -47,7 +47,7 @@ declare_with_version! { DEPRECATED(DEPRECATED_VERSION): &[(&str, &str)] = &[ ]} #[rustfmt::skip] -declare_with_version! { RENAMED(RENAMED_VERSION): &[(&str, &str)] = &[ +declare_with_version! { RENAMED(RENAMED_VERSION) = [ #[clippy::version = ""] ("clippy::almost_complete_letter_range", "clippy::almost_complete_range"), #[clippy::version = ""] From 063612196416cb437650cd4d706996046157997c Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 15 Apr 2025 13:25:46 -0400 Subject: [PATCH 2225/4206] clippy_dev: Remove print option from `update_lints` --- clippy_dev/src/main.rs | 13 +--- clippy_dev/src/update_lints.rs | 105 ++++++--------------------------- 2 files changed, 20 insertions(+), 98 deletions(-) diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 73248d72d04a0..5dce0be742b26 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -27,13 +27,7 @@ fn main() { allow_no_vcs, } => dogfood::dogfood(fix, allow_dirty, allow_staged, allow_no_vcs), DevCommand::Fmt { check, verbose } => fmt::run(check, verbose), - DevCommand::UpdateLints { print_only, check } => { - if print_only { - update_lints::print_lints(); - } else { - update_lints::update(utils::UpdateMode::from_check(check)); - } - }, + DevCommand::UpdateLints { check } => update_lints::update(utils::UpdateMode::from_check(check)), DevCommand::NewLint { pass, name, @@ -145,11 +139,6 @@ enum DevCommand { /// * lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod` {n} /// * all lints are registered in the lint store UpdateLints { - #[arg(long)] - /// Print a table of lints to STDOUT - /// - /// This does not include deprecated and internal lints. (Does not modify any files) - print_only: bool, #[arg(long)] /// Checks that `cargo dev update_lints` has been run. Used on CI. check: bool, diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 09e97491c510d..0c861b7293562 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -2,7 +2,7 @@ use crate::utils::{ File, FileAction, FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, panic_file, update_text_region_fn, }; use itertools::Itertools; -use std::collections::{HashMap, HashSet}; +use std::collections::HashSet; use std::fmt::Write; use std::fs::OpenOptions; use std::ops::Range; @@ -106,24 +106,6 @@ pub fn generate_lint_files( ); } -pub fn print_lints() { - let lints = find_lint_decls(); - let lint_count = lints.len(); - let grouped_by_lint_group = Lint::by_lint_group(lints.into_iter()); - - for (lint_group, mut lints) in grouped_by_lint_group { - println!("\n## {lint_group}"); - - lints.sort_by_key(|l| l.name.clone()); - - for lint in lints { - println!("* [{}]({DOCS_LINK}#{}) ({})", lint.name, lint.name, lint.desc); - } - } - - println!("there are {lint_count} lints"); -} - fn round_to_fifty(count: usize) -> usize { count / 50 * 50 } @@ -133,19 +115,10 @@ fn round_to_fifty(count: usize) -> usize { pub struct Lint { pub name: String, pub group: String, - pub desc: String, pub module: String, pub declaration_range: Range, } -impl Lint { - /// Returns the lints in a `HashMap`, grouped by the different lint groups - #[must_use] - fn by_lint_group(lints: impl Iterator) -> HashMap> { - lints.map(|lint| (lint.group.to_string(), lint)).into_group_map() - } -} - #[derive(Clone, PartialEq, Eq, Debug)] pub struct DeprecatedLint { pub name: String, @@ -185,7 +158,6 @@ pub fn find_lint_decls() -> Vec { let mut contents = String::new(); for (file, module) in read_src_with_module("clippy_lints/src".as_ref()) { parse_clippy_lint_decls( - file.path(), File::open_read_to_cleared_string(file.path(), &mut contents), &module, &mut lints, @@ -230,7 +202,7 @@ fn read_src_with_module(src_root: &Path) -> impl use<'_> + Iterator) { +fn parse_clippy_lint_decls(contents: &str, module: &str, lints: &mut Vec) { #[allow(clippy::enum_glob_use)] use Token::*; #[rustfmt::skip] @@ -239,21 +211,18 @@ fn parse_clippy_lint_decls(path: &Path, contents: &str, module: &str, lints: &mu Bang, OpenBrace, AnyDoc, // #[clippy::version = "version"] Pound, OpenBracket, Ident("clippy"), DoubleColon, Ident("version"), Eq, LitStr, CloseBracket, - // pub NAME, GROUP, "description" - Ident("pub"), CaptureIdent, Comma, CaptureIdent, Comma, CaptureLitStr, + // pub NAME, GROUP, + Ident("pub"), CaptureIdent, Comma, CaptureIdent, Comma, ]; let mut searcher = RustSearcher::new(contents); while searcher.find_token(Ident("declare_clippy_lint")) { let start = searcher.pos() as usize - "declare_clippy_lint".len(); - let (mut name, mut group, mut desc) = ("", "", ""); - if searcher.match_tokens(DECL_TOKENS, &mut [&mut name, &mut group, &mut desc]) - && searcher.find_token(CloseBrace) - { + let (mut name, mut group) = ("", ""); + if searcher.match_tokens(DECL_TOKENS, &mut [&mut name, &mut group]) && searcher.find_token(CloseBrace) { lints.push(Lint { name: name.to_lowercase(), group: group.into(), - desc: parse_str_single_line(path, desc), module: module.into(), declaration_range: start..searcher.pos() as usize, }); @@ -397,61 +366,25 @@ mod tests { } "#; let mut result = Vec::new(); - parse_clippy_lint_decls("".as_ref(), CONTENTS, "module_name", &mut result); + parse_clippy_lint_decls(CONTENTS, "module_name", &mut result); for r in &mut result { r.declaration_range = Range::default(); } let expected = vec![ - Lint::new( - "ptr_arg", - "style", - "\"really long text\"", - "module_name", - Range::default(), - ), - Lint::new( - "doc_markdown", - "pedantic", - "\"single line\"", - "module_name", - Range::default(), - ), + Lint { + name: "ptr_arg".into(), + group: "style".into(), + module: "module_name".into(), + declaration_range: Range::default(), + }, + Lint { + name: "doc_markdown".into(), + group: "pedantic".into(), + module: "module_name".into(), + declaration_range: Range::default(), + }, ]; assert_eq!(expected, result); } - - #[test] - fn test_by_lint_group() { - let lints = vec![ - Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()), - Lint::new( - "should_assert_eq2", - "group2", - "\"abc\"", - "module_name", - Range::default(), - ), - Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()), - ]; - let mut expected: HashMap> = HashMap::new(); - expected.insert( - "group1".to_string(), - vec![ - Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()), - Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()), - ], - ); - expected.insert( - "group2".to_string(), - vec![Lint::new( - "should_assert_eq2", - "group2", - "\"abc\"", - "module_name", - Range::default(), - )], - ); - assert_eq!(expected, Lint::by_lint_group(lints.into_iter())); - } } From 73a19a0c6767d5a92ba70354534b5b16051c68a1 Mon Sep 17 00:00:00 2001 From: Barun Parruck Date: Mon, 12 May 2025 22:59:07 +0100 Subject: [PATCH 2226/4206] Make lint span smaller for needless return --- clippy_lints/src/returns.rs | 12 +++++- tests/ui/needless_return.fixed | 18 ++++---- tests/ui/needless_return.rs | 18 ++++---- tests/ui/needless_return.stderr | 76 +++++++++++++-------------------- 4 files changed, 57 insertions(+), 67 deletions(-) diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 122d97fdf8193..ab9b0f88f936c 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -423,7 +423,14 @@ fn check_final_expr<'tcx>( _ => return, } - emit_return_lint(cx, ret_span, semi_spans, &replacement, expr.hir_id); + emit_return_lint( + cx, + peeled_drop_expr.span, + ret_span, + semi_spans, + &replacement, + expr.hir_id, + ); }, ExprKind::If(_, then, else_clause_opt) => { check_block_return(cx, &then.kind, peeled_drop_expr.span, semi_spans.clone()); @@ -448,6 +455,7 @@ fn check_final_expr<'tcx>( fn emit_return_lint( cx: &LateContext<'_>, + lint_span: Span, ret_span: Span, semi_spans: Vec, replacement: &RetReplacement<'_>, @@ -457,7 +465,7 @@ fn emit_return_lint( cx, NEEDLESS_RETURN, at, - ret_span, + lint_span, "unneeded `return` statement", |diag| { let suggestions = std::iter::once((ret_span, replacement.to_string())) diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index ad625ad6d5076..17d3862cd8668 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -84,14 +84,14 @@ fn test_macro_call() -> i32 { } fn test_void_fun() { - //~^^ needless_return + //~^ needless_return } fn test_void_if_fun(b: bool) { if b { - //~^^ needless_return + //~^ needless_return } else { - //~^^ needless_return + //~^ needless_return } } @@ -108,7 +108,7 @@ fn test_nested_match(x: u32) { 0 => (), 1 => { let _ = 42; - //~^^ needless_return + //~^ needless_return }, _ => (), //~^ needless_return @@ -156,7 +156,7 @@ mod issue6501 { fn test_closure() { let _ = || { - //~^^ needless_return + //~^ needless_return }; let _ = || {}; //~^ needless_return @@ -220,14 +220,14 @@ async fn async_test_macro_call() -> i32 { } async fn async_test_void_fun() { - //~^^ needless_return + //~^ needless_return } async fn async_test_void_if_fun(b: bool) { if b { - //~^^ needless_return + //~^ needless_return } else { - //~^^ needless_return + //~^ needless_return } } @@ -354,7 +354,7 @@ fn issue9503(x: usize) -> isize { mod issue9416 { pub fn with_newline() { let _ = 42; - //~^^ needless_return + //~^ needless_return } #[rustfmt::skip] diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index 41d7e5bdd5065..1c6e7ffa1ee8c 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -85,16 +85,16 @@ fn test_macro_call() -> i32 { fn test_void_fun() { return; - //~^^ needless_return + //~^ needless_return } fn test_void_if_fun(b: bool) { if b { return; - //~^^ needless_return + //~^ needless_return } else { return; - //~^^ needless_return + //~^ needless_return } } @@ -112,7 +112,7 @@ fn test_nested_match(x: u32) { 1 => { let _ = 42; return; - //~^^ needless_return + //~^ needless_return }, _ => return, //~^ needless_return @@ -161,7 +161,7 @@ mod issue6501 { fn test_closure() { let _ = || { return; - //~^^ needless_return + //~^ needless_return }; let _ = || return; //~^ needless_return @@ -226,16 +226,16 @@ async fn async_test_macro_call() -> i32 { async fn async_test_void_fun() { return; - //~^^ needless_return + //~^ needless_return } async fn async_test_void_if_fun(b: bool) { if b { return; - //~^^ needless_return + //~^ needless_return } else { return; - //~^^ needless_return + //~^ needless_return } } @@ -363,7 +363,7 @@ mod issue9416 { pub fn with_newline() { let _ = 42; return; - //~^^ needless_return + //~^ needless_return } #[rustfmt::skip] diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index 80863b9b62b20..26dd265379be0 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -133,12 +133,10 @@ LL + the_answer!() | error: unneeded `return` statement - --> tests/ui/needless_return.rs:86:21 + --> tests/ui/needless_return.rs:87:5 | -LL | fn test_void_fun() { - | _____________________^ -LL | | return; - | |__________^ +LL | return; + | ^^^^^^ | help: remove `return` | @@ -148,12 +146,10 @@ LL + fn test_void_fun() { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:92:11 + --> tests/ui/needless_return.rs:93:9 | -LL | if b { - | ___________^ -LL | | return; - | |______________^ +LL | return; + | ^^^^^^ | help: remove `return` | @@ -163,12 +159,10 @@ LL + if b { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:95:13 + --> tests/ui/needless_return.rs:96:9 | -LL | } else { - | _____________^ -LL | | return; - | |______________^ +LL | return; + | ^^^^^^ | help: remove `return` | @@ -190,12 +184,10 @@ LL + _ => (), | error: unneeded `return` statement - --> tests/ui/needless_return.rs:113:24 + --> tests/ui/needless_return.rs:114:13 | -LL | let _ = 42; - | ________________________^ -LL | | return; - | |__________________^ +LL | return; + | ^^^^^^ | help: remove `return` | @@ -253,12 +245,10 @@ LL + bar.unwrap_or_else(|_| {}) | error: unneeded `return` statement - --> tests/ui/needless_return.rs:162:21 + --> tests/ui/needless_return.rs:163:13 | -LL | let _ = || { - | _____________________^ -LL | | return; - | |__________________^ +LL | return; + | ^^^^^^ | help: remove `return` | @@ -400,12 +390,10 @@ LL + the_answer!() | error: unneeded `return` statement - --> tests/ui/needless_return.rs:227:33 + --> tests/ui/needless_return.rs:228:5 | -LL | async fn async_test_void_fun() { - | _________________________________^ -LL | | return; - | |__________^ +LL | return; + | ^^^^^^ | help: remove `return` | @@ -415,12 +403,10 @@ LL + async fn async_test_void_fun() { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:233:11 + --> tests/ui/needless_return.rs:234:9 | -LL | if b { - | ___________^ -LL | | return; - | |______________^ +LL | return; + | ^^^^^^ | help: remove `return` | @@ -430,12 +416,10 @@ LL + if b { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:236:13 + --> tests/ui/needless_return.rs:237:9 | -LL | } else { - | _____________^ -LL | | return; - | |______________^ +LL | return; + | ^^^^^^ | help: remove `return` | @@ -593,12 +577,10 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:364:20 + --> tests/ui/needless_return.rs:365:9 | -LL | let _ = 42; - | ____________________^ -LL | | return; - | |______________^ +LL | return; + | ^^^^^^ | help: remove `return` | @@ -608,10 +590,10 @@ LL + let _ = 42; | error: unneeded `return` statement - --> tests/ui/needless_return.rs:371:20 + --> tests/ui/needless_return.rs:371:21 | LL | let _ = 42; return; - | ^^^^^^^ + | ^^^^^^ | help: remove `return` | From b255ae2cdb6b06fca12142a5287ddab58901fe10 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 May 2025 23:59:55 +0200 Subject: [PATCH 2227/4206] remove dangling references --- src/doc/rustc-dev-guide/src/macro-expansion.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/macro-expansion.md b/src/doc/rustc-dev-guide/src/macro-expansion.md index 76b4f2c617df5..a90f717004f0b 100644 --- a/src/doc/rustc-dev-guide/src/macro-expansion.md +++ b/src/doc/rustc-dev-guide/src/macro-expansion.md @@ -9,9 +9,6 @@ we have a complete [*Abstract Syntax Tree* (AST)][ast] for our crate with no unexpanded macros (or a compile error). [ast]: ./ast-validation.md -[`rustc_ast`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/index.html -[`rustc_expand`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_expand/index.html -[`rustc_builtin_macros`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_builtin_macros/index.html [placeholders]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_expand/placeholders/index.html First, we discuss the algorithm that expands and integrates macro output into From 40e1b0ed00878f3229f053398a8d7a49d8b68bcc Mon Sep 17 00:00:00 2001 From: asdfish Date: Sun, 16 Mar 2025 18:13:31 -0400 Subject: [PATCH 2228/4206] add lint `cloned_ref_to_slice_refs` remove merge removed false positive and improved tests clarify known problems for `cloned_ref_to_slice_refs` --- CHANGELOG.md | 1 + clippy_lints/src/cloned_ref_to_slice_refs.rs | 100 +++++++++++++++++++ clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_utils/src/msrvs.rs | 4 +- tests/ui/cloned_ref_to_slice_refs.fixed | 64 ++++++++++++ tests/ui/cloned_ref_to_slice_refs.rs | 64 ++++++++++++ tests/ui/cloned_ref_to_slice_refs.stderr | 23 +++++ 8 files changed, 257 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/cloned_ref_to_slice_refs.rs create mode 100644 tests/ui/cloned_ref_to_slice_refs.fixed create mode 100644 tests/ui/cloned_ref_to_slice_refs.rs create mode 100644 tests/ui/cloned_ref_to_slice_refs.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b62c9a59aa5d..956e31489f12f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5583,6 +5583,7 @@ Released 2018-09-13 [`clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy [`clone_on_ref_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_ref_ptr [`cloned_instead_of_copied`]: https://rust-lang.github.io/rust-clippy/master/index.html#cloned_instead_of_copied +[`cloned_ref_to_slice_refs`]: https://rust-lang.github.io/rust-clippy/master/index.html#cloned_ref_to_slice_refs [`cmp_nan`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_nan [`cmp_null`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_null [`cmp_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_owned diff --git a/clippy_lints/src/cloned_ref_to_slice_refs.rs b/clippy_lints/src/cloned_ref_to_slice_refs.rs new file mode 100644 index 0000000000000..6b239a1541b0d --- /dev/null +++ b/clippy_lints/src/cloned_ref_to_slice_refs.rs @@ -0,0 +1,100 @@ +use clippy_config::Conf; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::sugg::Sugg; +use clippy_utils::visitors::is_const_evaluatable; +use clippy_utils::{is_in_const_context, is_mutable, is_trait_method}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::impl_lint_pass; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for slice references with cloned references such as `&[f.clone()]`. + /// + /// ### Why is this bad + /// + /// A reference does not need to be owned in order to used as a slice. + /// + /// ### Known problems + /// + /// This lint does not know whether or not a clone implementation has side effects. + /// + /// ### Example + /// + /// ```ignore + /// let data = 10; + /// let data_ref = &data; + /// take_slice(&[data_ref.clone()]); + /// ``` + /// Use instead: + /// ```ignore + /// use std::slice; + /// let data = 10; + /// let data_ref = &data; + /// take_slice(slice::from_ref(data_ref)); + /// ``` + #[clippy::version = "1.87.0"] + pub CLONED_REF_TO_SLICE_REFS, + perf, + "cloning a reference for slice references" +} + +pub struct ClonedRefToSliceRefs<'a> { + msrv: &'a Msrv, +} +impl<'a> ClonedRefToSliceRefs<'a> { + pub fn new(conf: &'a Conf) -> Self { + Self { msrv: &conf.msrv } + } +} + +impl_lint_pass!(ClonedRefToSliceRefs<'_> => [CLONED_REF_TO_SLICE_REFS]); + +impl<'tcx> LateLintPass<'tcx> for ClonedRefToSliceRefs<'_> { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + if self.msrv.meets(cx, { + if is_in_const_context(cx) { + msrvs::CONST_SLICE_FROM_REF + } else { + msrvs::SLICE_FROM_REF + } + }) + // `&[foo.clone()]` expressions + && let ExprKind::AddrOf(_, mutability, arr) = &expr.kind + // mutable references would have a different meaning + && mutability.is_not() + + // check for single item arrays + && let ExprKind::Array([item]) = &arr.kind + + // check for clones + && let ExprKind::MethodCall(_, val, _, _) = item.kind + && is_trait_method(cx, item, sym::Clone) + + // check for immutability or purity + && (!is_mutable(cx, val) || is_const_evaluatable(cx, val)) + + // get appropriate crate for `slice::from_ref` + && let Some(builtin_crate) = clippy_utils::std_or_core(cx) + { + let mut sugg = Sugg::hir(cx, val, "_"); + if !cx.typeck_results().expr_ty(val).is_ref() { + sugg = sugg.addr(); + } + + span_lint_and_sugg( + cx, + CLONED_REF_TO_SLICE_REFS, + expr.span, + format!("this call to `clone` can be replaced with `{builtin_crate}::slice::from_ref`"), + "try", + format!("{builtin_crate}::slice::from_ref({sugg})"), + Applicability::MaybeIncorrect, + ); + } + } +} diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 2cccd6ba27027..fbce468141bf0 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -75,6 +75,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::casts::ZERO_PTR_INFO, crate::cfg_not_test::CFG_NOT_TEST_INFO, crate::checked_conversions::CHECKED_CONVERSIONS_INFO, + crate::cloned_ref_to_slice_refs::CLONED_REF_TO_SLICE_REFS_INFO, crate::cognitive_complexity::COGNITIVE_COMPLEXITY_INFO, crate::collapsible_if::COLLAPSIBLE_ELSE_IF_INFO, crate::collapsible_if::COLLAPSIBLE_IF_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 5fa8f6f4bf3d4..37669a90eb425 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -96,6 +96,7 @@ mod cargo; mod casts; mod cfg_not_test; mod checked_conversions; +mod cloned_ref_to_slice_refs; mod cognitive_complexity; mod collapsible_if; mod collection_is_never_read; @@ -943,5 +944,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(manual_option_as_slice::ManualOptionAsSlice::new(conf))); store.register_late_pass(|_| Box::new(single_option_map::SingleOptionMap)); store.register_late_pass(move |_| Box::new(redundant_test_prefix::RedundantTestPrefix)); + store.register_late_pass(|_| Box::new(cloned_ref_to_slice_refs::ClonedRefToSliceRefs::new(conf))); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index c2aca5ee53906..e6f46f0d1de0b 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -38,7 +38,7 @@ msrv_aliases! { 1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN } 1,68,0 { PATH_MAIN_SEPARATOR_STR } 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } - 1,63,0 { CLONE_INTO } + 1,63,0 { CLONE_INTO, CONST_SLICE_FROM_REF } 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE, CONST_EXTERN_C_FN } 1,60,0 { ABS_DIFF } 1,59,0 { THREAD_LOCAL_CONST_INIT } @@ -68,7 +68,7 @@ msrv_aliases! { 1,31,0 { OPTION_REPLACE } 1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES } 1,29,0 { ITER_FLATTEN } - 1,28,0 { FROM_BOOL, REPEAT_WITH } + 1,28,0 { FROM_BOOL, REPEAT_WITH, SLICE_FROM_REF } 1,27,0 { ITERATOR_TRY_FOLD } 1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN } 1,24,0 { IS_ASCII_DIGIT } diff --git a/tests/ui/cloned_ref_to_slice_refs.fixed b/tests/ui/cloned_ref_to_slice_refs.fixed new file mode 100644 index 0000000000000..818c6e23259e3 --- /dev/null +++ b/tests/ui/cloned_ref_to_slice_refs.fixed @@ -0,0 +1,64 @@ +#![warn(clippy::cloned_ref_to_slice_refs)] + +#[derive(Clone)] +struct Data; + +fn main() { + { + let data = Data; + let data_ref = &data; + let _ = std::slice::from_ref(data_ref); //~ ERROR: this call to `clone` can be replaced with `std::slice::from_ref` + } + + { + let _ = std::slice::from_ref(&Data); //~ ERROR: this call to `clone` can be replaced with `std::slice::from_ref` + } + + { + #[derive(Clone)] + struct Point(i32, i32); + + let _ = std::slice::from_ref(&Point(0, 0)); //~ ERROR: this call to `clone` can be replaced with `std::slice::from_ref` + } + + // the string was cloned with the intention to not mutate + { + struct BetterString(String); + + let mut message = String::from("good"); + let sender = BetterString(message.clone()); + + message.push_str("bye!"); + + println!("{} {}", message, sender.0) + } + + // the string was cloned with the intention to not mutate + { + let mut x = String::from("Hello"); + let r = &[x.clone()]; + x.push('!'); + println!("r = `{}', x = `{x}'", r[0]); + } + + // mutable borrows may have the intention to clone + { + let data = Data; + let data_ref = &data; + let _ = &mut [data_ref.clone()]; + } + + // `T::clone` is used to denote a clone with side effects + { + use std::sync::Arc; + let data = Arc::new(Data); + let _ = &[Arc::clone(&data)]; + } + + // slices with multiple members can only be made from a singular reference + { + let data_1 = Data; + let data_2 = Data; + let _ = &[data_1.clone(), data_2.clone()]; + } +} diff --git a/tests/ui/cloned_ref_to_slice_refs.rs b/tests/ui/cloned_ref_to_slice_refs.rs new file mode 100644 index 0000000000000..9517dbfd1569c --- /dev/null +++ b/tests/ui/cloned_ref_to_slice_refs.rs @@ -0,0 +1,64 @@ +#![warn(clippy::cloned_ref_to_slice_refs)] + +#[derive(Clone)] +struct Data; + +fn main() { + { + let data = Data; + let data_ref = &data; + let _ = &[data_ref.clone()]; //~ ERROR: this call to `clone` can be replaced with `std::slice::from_ref` + } + + { + let _ = &[Data.clone()]; //~ ERROR: this call to `clone` can be replaced with `std::slice::from_ref` + } + + { + #[derive(Clone)] + struct Point(i32, i32); + + let _ = &[Point(0, 0).clone()]; //~ ERROR: this call to `clone` can be replaced with `std::slice::from_ref` + } + + // the string was cloned with the intention to not mutate + { + struct BetterString(String); + + let mut message = String::from("good"); + let sender = BetterString(message.clone()); + + message.push_str("bye!"); + + println!("{} {}", message, sender.0) + } + + // the string was cloned with the intention to not mutate + { + let mut x = String::from("Hello"); + let r = &[x.clone()]; + x.push('!'); + println!("r = `{}', x = `{x}'", r[0]); + } + + // mutable borrows may have the intention to clone + { + let data = Data; + let data_ref = &data; + let _ = &mut [data_ref.clone()]; + } + + // `T::clone` is used to denote a clone with side effects + { + use std::sync::Arc; + let data = Arc::new(Data); + let _ = &[Arc::clone(&data)]; + } + + // slices with multiple members can only be made from a singular reference + { + let data_1 = Data; + let data_2 = Data; + let _ = &[data_1.clone(), data_2.clone()]; + } +} diff --git a/tests/ui/cloned_ref_to_slice_refs.stderr b/tests/ui/cloned_ref_to_slice_refs.stderr new file mode 100644 index 0000000000000..6a31d87823955 --- /dev/null +++ b/tests/ui/cloned_ref_to_slice_refs.stderr @@ -0,0 +1,23 @@ +error: this call to `clone` can be replaced with `std::slice::from_ref` + --> tests/ui/cloned_ref_to_slice_refs.rs:10:17 + | +LL | let _ = &[data_ref.clone()]; + | ^^^^^^^^^^^^^^^^^^^ help: try: `std::slice::from_ref(data_ref)` + | + = note: `-D clippy::cloned-ref-to-slice-refs` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cloned_ref_to_slice_refs)]` + +error: this call to `clone` can be replaced with `std::slice::from_ref` + --> tests/ui/cloned_ref_to_slice_refs.rs:14:17 + | +LL | let _ = &[Data.clone()]; + | ^^^^^^^^^^^^^^^ help: try: `std::slice::from_ref(&Data)` + +error: this call to `clone` can be replaced with `std::slice::from_ref` + --> tests/ui/cloned_ref_to_slice_refs.rs:21:17 + | +LL | let _ = &[Point(0, 0).clone()]; + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::slice::from_ref(&Point(0, 0))` + +error: aborting due to 3 previous errors + From ab1c49a7facad5083c20407a2b1fd0b2104e174e Mon Sep 17 00:00:00 2001 From: Julian Knodt Date: Tue, 13 May 2025 11:17:09 +0900 Subject: [PATCH 2229/4206] Add `#[must_use]` to Array::map The output of Array::map is intended to be an array of the same size, and does not modify the original in place nor is it intended for side-effects. Thus, under normal circumstances it should be consumed. See [discussion](https://internals.rust-lang.org/t/array-map-annotate-with-must-use/22813/26). Attaching to tracking issue #75243 --- library/core/src/array/mod.rs | 1 + library/coretests/tests/array.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index efa7bed7c8e17..4476e3f79238d 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -531,6 +531,7 @@ impl [T; N] { /// let y = x.map(|v| v.len()); /// assert_eq!(y, [6, 9, 3, 3]); /// ``` + #[must_use] #[stable(feature = "array_map", since = "1.55.0")] pub fn map(self, f: F) -> [U; N] where diff --git a/library/coretests/tests/array.rs b/library/coretests/tests/array.rs index b6d18f1ec3822..30ccbbc320318 100644 --- a/library/coretests/tests/array.rs +++ b/library/coretests/tests/array.rs @@ -325,7 +325,7 @@ fn array_map_drop_safety() { let success = std::panic::catch_unwind(|| { let items = [0; 10]; let mut nth = 0; - items.map(|_| { + let _ = items.map(|_| { assert!(nth < num_to_create); nth += 1; DropCounter From a5e1dba0cda0db75106ea6c5022e874c7ee116b5 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 13 May 2025 07:33:51 +0000 Subject: [PATCH 2230/4206] trait_sel: deep reject `match_normalize_trait_ref` Spotted during an in-person review of unrelated changes, `match_normalize_trait_ref` could be using `DeepRejectCtxt` to exit early as an optimisation for prejection candidates, like is done in param candidates. --- compiler/rustc_middle/src/ty/mod.rs | 1 + .../rustc_trait_selection/src/traits/select/mod.rs | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index dda0faa3afedd..83b318435f994 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -52,6 +52,7 @@ pub use rustc_session::lint::RegisteredTools; use rustc_span::hygiene::MacroKind; use rustc_span::{DUMMY_SP, ExpnId, ExpnKind, Ident, Span, Symbol, kw, sym}; pub use rustc_type_ir::data_structures::{DelayedMap, DelayedSet}; +pub use rustc_type_ir::fast_reject::DeepRejectCtxt; #[allow( hidden_glob_reexports, rustc::usage_of_type_ir_inherent, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 4ce37db428002..9513d2107edba 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -27,8 +27,8 @@ use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths}; use rustc_middle::ty::{ - self, GenericArgsRef, PolyProjectionPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, - TypingMode, Upcast, elaborate, + self, DeepRejectCtxt, GenericArgsRef, PolyProjectionPredicate, Ty, TyCtxt, TypeFoldable, + TypeVisitableExt, TypingMode, Upcast, elaborate, }; use rustc_span::{Symbol, sym}; use tracing::{debug, instrument, trace}; @@ -1669,6 +1669,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Err(()); } + let drcx = DeepRejectCtxt::relate_rigid_rigid(self.infcx.tcx); + let obligation_args = obligation.predicate.skip_binder().trait_ref.args; + if !drcx.args_may_unify(obligation_args, trait_bound.skip_binder().args) { + return Err(()); + } + let trait_bound = self.infcx.instantiate_binder_with_fresh_vars( obligation.cause.span, HigherRankedType, From bd587005fb5aad184e0ee133efea65615c6fa6bc Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 9 May 2025 09:30:01 +0000 Subject: [PATCH 2231/4206] Some require_lang_item -> is_lang_item replacements --- compiler/rustc_hir_analysis/src/coherence/builtin.rs | 6 ++---- compiler/rustc_hir_typeck/src/closure.rs | 5 ++--- compiler/rustc_middle/src/ty/sty.rs | 3 +-- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 52656fc2d9001..b92d1d7104f0a 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -214,11 +214,9 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() let span = tcx.def_span(impl_did); let trait_name = "DispatchFromDyn"; - let dispatch_from_dyn_trait = tcx.require_lang_item(LangItem::DispatchFromDyn, Some(span)); - let source = trait_ref.self_ty(); let target = { - assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait); + assert!(tcx.is_lang_item(trait_ref.def_id, LangItem::DispatchFromDyn)); trait_ref.args.type_at(1) }; @@ -339,7 +337,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() tcx, cause.clone(), param_env, - ty::TraitRef::new(tcx, dispatch_from_dyn_trait, [ty_a, ty_b]), + ty::TraitRef::new(tcx, trait_ref.def_id, [ty_a, ty_b]), )); let errors = ocx.select_all_or_error(); if !errors.is_empty() { diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 8fd59999fce5e..b1cb3ef4d7967 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -1080,15 +1080,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Check that this is a projection from the `Future` trait. let trait_def_id = predicate.projection_term.trait_def_id(self.tcx); - let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(cause_span)); - if trait_def_id != future_trait { + if !self.tcx.is_lang_item(trait_def_id, LangItem::Future) { debug!("deduce_future_output_from_projection: not a future"); return None; } // The `Future` trait has only one associated item, `Output`, // so check that this is what we see. - let output_assoc_item = self.tcx.associated_item_def_ids(future_trait)[0]; + let output_assoc_item = self.tcx.associated_item_def_ids(trait_def_id)[0]; if output_assoc_item != predicate.projection_term.def_id { span_bug!( cause_span, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index c31ce1bc63070..ab1f3d6099fcf 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1260,8 +1260,7 @@ impl<'tcx> Ty<'tcx> { return true; }; alloc.expect_ty().ty_adt_def().is_some_and(|alloc_adt| { - let global_alloc = tcx.require_lang_item(LangItem::GlobalAlloc, None); - alloc_adt.did() == global_alloc + tcx.is_lang_item(alloc_adt.did(), LangItem::GlobalAlloc) }) } _ => false, From c86e33b77108ae2842b93f4d158280bcd7346147 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 9 May 2025 15:20:23 +0000 Subject: [PATCH 2232/4206] Run rustc_attrs dumps after typeck --- compiler/rustc_hir_analysis/src/lib.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index d010f1fc85164..fcbd1edf17fe1 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -195,17 +195,6 @@ pub fn check_crate(tcx: TyCtxt<'_>) { let _: R = tcx.ensure_ok().crate_inherent_impls_overlap_check(()); }); - if tcx.features().rustc_attrs() { - tcx.sess.time("dumping_rustc_attr_data", || { - outlives::dump::inferred_outlives(tcx); - variance::dump::variances(tcx); - collect::dump::opaque_hidden_types(tcx); - collect::dump::predicates_and_item_bounds(tcx); - collect::dump::def_parents(tcx); - collect::dump::vtables(tcx); - }); - } - // Make sure we evaluate all static and (non-associated) const items, even if unused. // If any of these fail to evaluate, we do not want this crate to pass compilation. tcx.par_hir_body_owners(|item_def_id| { @@ -229,6 +218,17 @@ pub fn check_crate(tcx: TyCtxt<'_>) { } }); + if tcx.features().rustc_attrs() { + tcx.sess.time("dumping_rustc_attr_data", || { + outlives::dump::inferred_outlives(tcx); + variance::dump::variances(tcx); + collect::dump::opaque_hidden_types(tcx); + collect::dump::predicates_and_item_bounds(tcx); + collect::dump::def_parents(tcx); + collect::dump::vtables(tcx); + }); + } + tcx.ensure_ok().check_unused_traits(()); } From 34976ac9fe6bd46ca02631512a27cb8995b2c1ac Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 13 May 2025 08:49:32 +0000 Subject: [PATCH 2233/4206] Invoke a query only when it doesn't return immediately anyway --- compiler/rustc_interface/src/passes.rs | 5 ++--- compiler/rustc_mir_build/src/check_unsafety.rs | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 7ed32d559c3a6..b554cc715feea 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -996,10 +996,9 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { sess.time("MIR_borrow_checking", || { tcx.par_hir_body_owners(|def_id| { - // Run unsafety check because it's responsible for stealing and - // deallocating THIR. - tcx.ensure_ok().check_unsafety(def_id); if !tcx.is_typeck_child(def_id.to_def_id()) { + // Child unsafety and borrowck happens together with the parent + tcx.ensure_ok().check_unsafety(def_id); tcx.ensure_ok().mir_borrowck(def_id) } }); diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index adfce99a9b537..9d0681b19b9d5 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -1148,8 +1148,9 @@ impl UnsafeOpKind { pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) { // Closures and inline consts are handled by their owner, if it has a body + assert!(!tcx.is_typeck_child(def.to_def_id())); // Also, don't safety check custom MIR - if tcx.is_typeck_child(def.to_def_id()) || tcx.has_attr(def, sym::custom_mir) { + if tcx.has_attr(def, sym::custom_mir) { return; } From a508011b1f0ae84930e2bcd0f6261f7e8843db6d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 12 May 2025 21:04:32 +0000 Subject: [PATCH 2234/4206] Expect deep norm to fail if query norm failed --- .../src/type_check/liveness/trace.rs | 8 +------ .../src/traits/query/dropck_outlives.rs | 22 ++++++++++++++----- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 7718644b9a9a8..512288a0f7d85 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -621,13 +621,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { &ocx, op, span, ) { Ok(_) => ocx.select_all_or_error(), - Err(e) => { - if e.is_empty() { - ocx.select_all_or_error() - } else { - e - } - } + Err(e) => e, }; // Could have no errors if a type lowering error, say, caused the query diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index c82d5ca59efca..38cfdcdc22d33 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -204,11 +204,23 @@ where return Err(errors); } - ocx.deeply_normalize(&cause, param_env, ty)?; - - let errors = ocx.select_where_possible(); - debug!("normalize errors: {ty} ~> {errors:#?}"); - return Err(errors); + // When query normalization fails, we don't get back an interesting + // reason that we could use to report an error in borrowck. In order to turn + // this into a reportable error, we deeply normalize again. We don't expect + // this to succeed, so delay a bug if it does. + match ocx.deeply_normalize(&cause, param_env, ty) { + Ok(_) => { + tcx.dcx().span_delayed_bug( + span, + format!( + "query normalize succeeded of {ty}, \ + but deep normalize failed", + ), + ); + ty + } + Err(errors) => return Err(errors), + } }; match ty.kind() { From ce6e29679cbfa08e46b64a5ad78974bbb852ee2b Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Mon, 12 May 2025 16:41:26 +0200 Subject: [PATCH 2235/4206] bump compiler_builtins --- library/Cargo.lock | 4 ++-- library/alloc/Cargo.toml | 2 +- library/std/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/Cargo.lock b/library/Cargo.lock index 93e9a8b7e8b4a..97ca3cb06b243 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -61,9 +61,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.158" +version = "0.1.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "164cdc689e4c6d69417f77a5f48be240c291e84fbef0b1281755dc754b19c809" +checksum = "448068da8f2326b2a0472353cb401dd8795a89c007ef30fff90f50706e862e72" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 51ddc9bf9fc9d..9d0d957226d2e 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -16,7 +16,7 @@ bench = false [dependencies] core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.158", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "=0.1.159", features = ['rustc-dep-of-std'] } [features] compiler-builtins-mem = ['compiler_builtins/mem'] diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 7915196e8e899..4ff4895ecde7a 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -18,7 +18,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.158" } +compiler_builtins = { version = "=0.1.159" } unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', From 8ce7783c7cfff1f60134a7754db32ea86855dd89 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 12 May 2025 15:26:28 +0000 Subject: [PATCH 2236/4206] Format and skip formatting for pin --- library/core/src/pin.rs | 2 ++ src/bootstrap/src/core/build_steps/llvm.rs | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index aa8207f8ff40e..ecfa723722d05 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1936,6 +1936,8 @@ unsafe impl PinCoerceUnsized for *mut T {} #[stable(feature = "pin_macro", since = "1.68.0")] #[rustc_macro_transparency = "semitransparent"] #[allow_internal_unstable(super_let)] +// `super` gets removed by rustfmt +#[rustfmt::skip] pub macro pin($value:expr $(,)?) { { super let mut pinned = $value; diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 33a35372d1810..a378819747164 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -1230,8 +1230,7 @@ fn supported_sanitizers( .iter() .map(move |c| SanitizerRuntime { cmake_target: format!("clang_rt.{c}_{os}_dynamic"), - path: out_dir - .join(format!("build/lib/darwin/libclang_rt.{c}_{os}_dynamic.dylib")), + path: out_dir.join(format!("build/lib/darwin/libclang_rt.{c}_{os}_dynamic.dylib")), name: format!("librustc-{channel}_rt.{c}.dylib"), }) .collect() From d16c82dba15f4aaf61874f6668417856002d32a6 Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Thu, 8 May 2025 15:00:59 +0200 Subject: [PATCH 2237/4206] Fix `i256::MAX` --- library/compiler-builtins/compiler-builtins/src/int/big.rs | 2 +- library/compiler-builtins/libm/src/math/support/big.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/src/int/big.rs b/library/compiler-builtins/compiler-builtins/src/int/big.rs index 61f1349d9a428..1402efb8ed419 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/big.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/big.rs @@ -65,7 +65,7 @@ impl MinInt for i256 { 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]); + const MAX: Self = Self([u64::MAX, u64::MAX, u64::MAX, u64::MAX >> 1]); } macro_rules! impl_common { diff --git a/library/compiler-builtins/libm/src/math/support/big.rs b/library/compiler-builtins/libm/src/math/support/big.rs index f24c063cd3456..8a52d86cc9827 100644 --- a/library/compiler-builtins/libm/src/math/support/big.rs +++ b/library/compiler-builtins/libm/src/math/support/big.rs @@ -83,7 +83,7 @@ impl MinInt for i256 { }; const MAX: Self = Self { lo: u128::MAX, - hi: u128::MAX << 1, + hi: u128::MAX >> 1, }; } From dcd2736fcc76017726ad15db55a5fac179c9842e Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 13 May 2025 16:22:48 +0200 Subject: [PATCH 2238/4206] Add match guard chains to drop-order-comparisons.rs --- .../drop/drop-order-comparisons.e2021.fixed | 41 ++++++++ .../drop/drop-order-comparisons.e2021.stderr | 96 +++++++++---------- tests/ui/drop/drop-order-comparisons.rs | 41 ++++++++ 3 files changed, 130 insertions(+), 48 deletions(-) diff --git a/tests/ui/drop/drop-order-comparisons.e2021.fixed b/tests/ui/drop/drop-order-comparisons.e2021.fixed index 71158cb806213..6c8d2d3fa9c12 100644 --- a/tests/ui/drop/drop-order-comparisons.e2021.fixed +++ b/tests/ui/drop/drop-order-comparisons.e2021.fixed @@ -24,6 +24,7 @@ //@ [e2024] edition: 2024 //@ run-pass +#![feature(if_let_guard)] #![cfg_attr(e2021, feature(let_chains))] #![cfg_attr(e2021, warn(rust_2024_compatibility))] @@ -344,6 +345,25 @@ fn t_if_let_chains_then() { e.assert(9); } +#[rustfmt::skip] +fn t_guard_if_let_chains_then() { + let e = Events::new(); + _ = match () { + () if e.ok(1).is_ok() + && let true = e.ok(9).is_ok() + && let Ok(_v) = e.ok(8) + && let Ok(_) = e.ok(7) + && let Ok(_) = e.ok(6).as_ref() + && e.ok(2).is_ok() + && let Ok(_v) = e.ok(5) + && let Ok(_) = e.ok(4).as_ref() => { + e.mark(3); + } + _ => {} + }; + e.assert(9); +} + #[cfg(e2021)] #[rustfmt::skip] fn t_if_let_nested_else() { @@ -484,6 +504,25 @@ fn t_if_let_chains_then_else() { e.assert(9); } +#[rustfmt::skip] +fn t_guard_if_let_chains_then_else() { + let e = Events::new(); + _ = match () { + () if e.ok(1).is_ok() + && let true = e.ok(8).is_ok() + && let Ok(_v) = e.ok(7) + && let Ok(_) = e.ok(6) + && let Ok(_) = e.ok(5).as_ref() + && e.ok(2).is_ok() + && let Ok(_v) = e.ok(4) + && let Ok(_) = e.err(3) => {} + _ => { + e.mark(9); + } + }; + e.assert(9); +} + fn main() { t_bindings(); t_tuples(); @@ -502,10 +541,12 @@ fn main() { t_if_let_nested_then(); t_let_else_chained_then(); t_if_let_chains_then(); + t_guard_if_let_chains_then(); t_if_let_nested_else(); t_if_let_nested_then_else(); t_let_else_chained_then_else(); t_if_let_chains_then_else(); + t_guard_if_let_chains_then_else(); } // # Test scaffolding diff --git a/tests/ui/drop/drop-order-comparisons.e2021.stderr b/tests/ui/drop/drop-order-comparisons.e2021.stderr index 0717a8c1b9b94..8b93376cc0d05 100644 --- a/tests/ui/drop/drop-order-comparisons.e2021.stderr +++ b/tests/ui/drop/drop-order-comparisons.e2021.stderr @@ -1,5 +1,5 @@ warning: relative drop order changing in Rust 2024 - --> $DIR/drop-order-comparisons.rs:76:9 + --> $DIR/drop-order-comparisons.rs:77:9 | LL | _ = ({ | _________- @@ -29,35 +29,35 @@ LL | | }, e.mark(3), e.ok(4)); = warning: this changes meaning in Rust 2024 = note: for more information, see note: `#3` invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:571:1 + --> $DIR/drop-order-comparisons.rs:612:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `#1` invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:571:1 + --> $DIR/drop-order-comparisons.rs:612:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `_v` invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:571:1 + --> $DIR/drop-order-comparisons.rs:612:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `#2` invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:571:1 + --> $DIR/drop-order-comparisons.rs:612:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages note: the lint level is defined here - --> $DIR/drop-order-comparisons.rs:28:25 + --> $DIR/drop-order-comparisons.rs:29:25 | LL | #![cfg_attr(e2021, warn(rust_2024_compatibility))] | ^^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(tail_expr_drop_order)]` implied by `#[warn(rust_2024_compatibility)]` warning: relative drop order changing in Rust 2024 - --> $DIR/drop-order-comparisons.rs:100:45 + --> $DIR/drop-order-comparisons.rs:101:45 | LL | _ = ({ | _________- @@ -77,19 +77,19 @@ LL | | }, e.mark(1), e.ok(4)); = warning: this changes meaning in Rust 2024 = note: for more information, see note: `#2` invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:571:1 + --> $DIR/drop-order-comparisons.rs:612:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `#1` invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:571:1 + --> $DIR/drop-order-comparisons.rs:612:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages warning: relative drop order changing in Rust 2024 - --> $DIR/drop-order-comparisons.rs:100:19 + --> $DIR/drop-order-comparisons.rs:101:19 | LL | _ = ({ | _________- @@ -109,19 +109,19 @@ LL | | }, e.mark(1), e.ok(4)); = warning: this changes meaning in Rust 2024 = note: for more information, see note: `#2` invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:571:1 + --> $DIR/drop-order-comparisons.rs:612:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `#1` invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:571:1 + --> $DIR/drop-order-comparisons.rs:612:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages warning: relative drop order changing in Rust 2024 - --> $DIR/drop-order-comparisons.rs:221:24 + --> $DIR/drop-order-comparisons.rs:222:24 | LL | _ = ({ | _________- @@ -141,19 +141,19 @@ LL | | }, e.mark(2), e.ok(3)); = warning: this changes meaning in Rust 2024 = note: for more information, see note: `#2` invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:571:1 + --> $DIR/drop-order-comparisons.rs:612:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `#1` invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:571:1 + --> $DIR/drop-order-comparisons.rs:612:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages warning: relative drop order changing in Rust 2024 - --> $DIR/drop-order-comparisons.rs:247:24 + --> $DIR/drop-order-comparisons.rs:248:24 | LL | _ = ({ | _________- @@ -173,19 +173,19 @@ LL | | }, e.mark(2), e.ok(3)); = warning: this changes meaning in Rust 2024 = note: for more information, see note: `#2` invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:571:1 + --> $DIR/drop-order-comparisons.rs:612:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `#1` invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:571:1 + --> $DIR/drop-order-comparisons.rs:612:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages warning: `if let` assigns a shorter lifetime since Edition 2024 - --> $DIR/drop-order-comparisons.rs:123:13 + --> $DIR/drop-order-comparisons.rs:124:13 | LL | _ = (if let Ok(_) = e.ok(4).as_ref() { | ^^^^^^^^^^^^-------^^^^^^^^^ @@ -195,12 +195,12 @@ LL | _ = (if let Ok(_) = e.ok(4).as_ref() { = warning: this changes meaning in Rust 2024 = note: for more information, see note: value invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:571:1 + --> $DIR/drop-order-comparisons.rs:612:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 - --> $DIR/drop-order-comparisons.rs:127:5 + --> $DIR/drop-order-comparisons.rs:128:5 | LL | }, e.mark(2), e.ok(3)); | ^ @@ -215,7 +215,7 @@ LL ~ } _ => {}}, e.mark(2), e.ok(3)); | warning: `if let` assigns a shorter lifetime since Edition 2024 - --> $DIR/drop-order-comparisons.rs:145:13 + --> $DIR/drop-order-comparisons.rs:146:13 | LL | _ = (if let Ok(_) = e.err(4).as_ref() {} else { | ^^^^^^^^^^^^--------^^^^^^^^^ @@ -225,12 +225,12 @@ LL | _ = (if let Ok(_) = e.err(4).as_ref() {} else { = warning: this changes meaning in Rust 2024 = note: for more information, see note: value invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:571:1 + --> $DIR/drop-order-comparisons.rs:612:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 - --> $DIR/drop-order-comparisons.rs:145:44 + --> $DIR/drop-order-comparisons.rs:146:44 | LL | _ = (if let Ok(_) = e.err(4).as_ref() {} else { | ^ @@ -244,7 +244,7 @@ LL ~ }}, e.mark(2), e.ok(3)); | warning: `if let` assigns a shorter lifetime since Edition 2024 - --> $DIR/drop-order-comparisons.rs:247:12 + --> $DIR/drop-order-comparisons.rs:248:12 | LL | if let Ok(_) = e.err(4).as_ref() {} else { | ^^^^^^^^^^^^--------^^^^^^^^^ @@ -254,12 +254,12 @@ LL | if let Ok(_) = e.err(4).as_ref() {} else { = warning: this changes meaning in Rust 2024 = note: for more information, see note: value invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:571:1 + --> $DIR/drop-order-comparisons.rs:612:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 - --> $DIR/drop-order-comparisons.rs:247:43 + --> $DIR/drop-order-comparisons.rs:248:43 | LL | if let Ok(_) = e.err(4).as_ref() {} else { | ^ @@ -273,7 +273,7 @@ LL ~ }} | warning: `if let` assigns a shorter lifetime since Edition 2024 - --> $DIR/drop-order-comparisons.rs:352:12 + --> $DIR/drop-order-comparisons.rs:372:12 | LL | if let true = e.err(9).is_ok() {} else { | ^^^^^^^^^^^--------^^^^^^^^ @@ -283,12 +283,12 @@ LL | if let true = e.err(9).is_ok() {} else { = warning: this changes meaning in Rust 2024 = note: for more information, see note: value invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:571:1 + --> $DIR/drop-order-comparisons.rs:612:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 - --> $DIR/drop-order-comparisons.rs:352:41 + --> $DIR/drop-order-comparisons.rs:372:41 | LL | if let true = e.err(9).is_ok() {} else { | ^ @@ -302,7 +302,7 @@ LL ~ }}}}}}}}}; | warning: `if let` assigns a shorter lifetime since Edition 2024 - --> $DIR/drop-order-comparisons.rs:355:12 + --> $DIR/drop-order-comparisons.rs:375:12 | LL | if let Ok(_v) = e.err(8) {} else { | ^^^^^^^^^^^^^-------- @@ -312,12 +312,12 @@ LL | if let Ok(_v) = e.err(8) {} else { = warning: this changes meaning in Rust 2024 = note: for more information, see note: value invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:571:1 + --> $DIR/drop-order-comparisons.rs:612:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 - --> $DIR/drop-order-comparisons.rs:355:35 + --> $DIR/drop-order-comparisons.rs:375:35 | LL | if let Ok(_v) = e.err(8) {} else { | ^ @@ -331,7 +331,7 @@ LL ~ }}}}}}}}}; | warning: `if let` assigns a shorter lifetime since Edition 2024 - --> $DIR/drop-order-comparisons.rs:358:12 + --> $DIR/drop-order-comparisons.rs:378:12 | LL | if let Ok(_) = e.err(7) {} else { | ^^^^^^^^^^^^-------- @@ -341,12 +341,12 @@ LL | if let Ok(_) = e.err(7) {} else { = warning: this changes meaning in Rust 2024 = note: for more information, see note: value invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:571:1 + --> $DIR/drop-order-comparisons.rs:612:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 - --> $DIR/drop-order-comparisons.rs:358:34 + --> $DIR/drop-order-comparisons.rs:378:34 | LL | if let Ok(_) = e.err(7) {} else { | ^ @@ -360,7 +360,7 @@ LL ~ }}}}}}}}}; | warning: `if let` assigns a shorter lifetime since Edition 2024 - --> $DIR/drop-order-comparisons.rs:361:12 + --> $DIR/drop-order-comparisons.rs:381:12 | LL | if let Ok(_) = e.err(6).as_ref() {} else { | ^^^^^^^^^^^^--------^^^^^^^^^ @@ -370,12 +370,12 @@ LL | if let Ok(_) = e.err(6).as_ref() {} else { = warning: this changes meaning in Rust 2024 = note: for more information, see note: value invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:571:1 + --> $DIR/drop-order-comparisons.rs:612:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 - --> $DIR/drop-order-comparisons.rs:361:43 + --> $DIR/drop-order-comparisons.rs:381:43 | LL | if let Ok(_) = e.err(6).as_ref() {} else { | ^ @@ -389,7 +389,7 @@ LL ~ }}}}}}}}}; | warning: `if let` assigns a shorter lifetime since Edition 2024 - --> $DIR/drop-order-comparisons.rs:365:12 + --> $DIR/drop-order-comparisons.rs:385:12 | LL | if let Ok(_v) = e.err(5) {} else { | ^^^^^^^^^^^^^-------- @@ -399,12 +399,12 @@ LL | if let Ok(_v) = e.err(5) {} else { = warning: this changes meaning in Rust 2024 = note: for more information, see note: value invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:571:1 + --> $DIR/drop-order-comparisons.rs:612:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 - --> $DIR/drop-order-comparisons.rs:365:35 + --> $DIR/drop-order-comparisons.rs:385:35 | LL | if let Ok(_v) = e.err(5) {} else { | ^ @@ -418,7 +418,7 @@ LL ~ }}}}}}}}}; | warning: `if let` assigns a shorter lifetime since Edition 2024 - --> $DIR/drop-order-comparisons.rs:368:12 + --> $DIR/drop-order-comparisons.rs:388:12 | LL | if let Ok(_) = e.err(4) {} else { | ^^^^^^^^^^^^-------- @@ -428,12 +428,12 @@ LL | if let Ok(_) = e.err(4) {} else { = warning: this changes meaning in Rust 2024 = note: for more information, see note: value invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:571:1 + --> $DIR/drop-order-comparisons.rs:612:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 - --> $DIR/drop-order-comparisons.rs:368:34 + --> $DIR/drop-order-comparisons.rs:388:34 | LL | if let Ok(_) = e.err(4) {} else { | ^ @@ -447,7 +447,7 @@ LL ~ }}}}}}}}}; | warning: `if let` assigns a shorter lifetime since Edition 2024 - --> $DIR/drop-order-comparisons.rs:404:12 + --> $DIR/drop-order-comparisons.rs:424:12 | LL | if let Ok(_) = e.err(4).as_ref() {} else { | ^^^^^^^^^^^^--------^^^^^^^^^ @@ -457,12 +457,12 @@ LL | if let Ok(_) = e.err(4).as_ref() {} else { = warning: this changes meaning in Rust 2024 = note: for more information, see note: value invokes this custom destructor - --> $DIR/drop-order-comparisons.rs:571:1 + --> $DIR/drop-order-comparisons.rs:612:1 | LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: the value is now dropped here in Edition 2024 - --> $DIR/drop-order-comparisons.rs:404:43 + --> $DIR/drop-order-comparisons.rs:424:43 | LL | if let Ok(_) = e.err(4).as_ref() {} else { | ^ diff --git a/tests/ui/drop/drop-order-comparisons.rs b/tests/ui/drop/drop-order-comparisons.rs index 0492b3a4db7f9..9a10a08a3ff74 100644 --- a/tests/ui/drop/drop-order-comparisons.rs +++ b/tests/ui/drop/drop-order-comparisons.rs @@ -24,6 +24,7 @@ //@ [e2024] edition: 2024 //@ run-pass +#![feature(if_let_guard)] #![cfg_attr(e2021, feature(let_chains))] #![cfg_attr(e2021, warn(rust_2024_compatibility))] @@ -344,6 +345,25 @@ fn t_if_let_chains_then() { e.assert(9); } +#[rustfmt::skip] +fn t_guard_if_let_chains_then() { + let e = Events::new(); + _ = match () { + () if e.ok(1).is_ok() + && let true = e.ok(9).is_ok() + && let Ok(_v) = e.ok(8) + && let Ok(_) = e.ok(7) + && let Ok(_) = e.ok(6).as_ref() + && e.ok(2).is_ok() + && let Ok(_v) = e.ok(5) + && let Ok(_) = e.ok(4).as_ref() => { + e.mark(3); + } + _ => {} + }; + e.assert(9); +} + #[cfg(e2021)] #[rustfmt::skip] fn t_if_let_nested_else() { @@ -484,6 +504,25 @@ fn t_if_let_chains_then_else() { e.assert(9); } +#[rustfmt::skip] +fn t_guard_if_let_chains_then_else() { + let e = Events::new(); + _ = match () { + () if e.ok(1).is_ok() + && let true = e.ok(8).is_ok() + && let Ok(_v) = e.ok(7) + && let Ok(_) = e.ok(6) + && let Ok(_) = e.ok(5).as_ref() + && e.ok(2).is_ok() + && let Ok(_v) = e.ok(4) + && let Ok(_) = e.err(3) => {} + _ => { + e.mark(9); + } + }; + e.assert(9); +} + fn main() { t_bindings(); t_tuples(); @@ -502,10 +541,12 @@ fn main() { t_if_let_nested_then(); t_let_else_chained_then(); t_if_let_chains_then(); + t_guard_if_let_chains_then(); t_if_let_nested_else(); t_if_let_nested_then_else(); t_let_else_chained_then_else(); t_if_let_chains_then_else(); + t_guard_if_let_chains_then_else(); } // # Test scaffolding From 5c2677d01761b159df99e2e381761ae770411746 Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 13 May 2025 16:22:52 +0200 Subject: [PATCH 2239/4206] Add match guard chains test, based on mir_let_chains_drop_order.rs --- .../mir_match_guard_let_chains_drop_order.rs | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 tests/ui/mir/mir_match_guard_let_chains_drop_order.rs diff --git a/tests/ui/mir/mir_match_guard_let_chains_drop_order.rs b/tests/ui/mir/mir_match_guard_let_chains_drop_order.rs new file mode 100644 index 0000000000000..e98d57d1154c4 --- /dev/null +++ b/tests/ui/mir/mir_match_guard_let_chains_drop_order.rs @@ -0,0 +1,110 @@ +//@ run-pass +//@ needs-unwind +//@ revisions: edition2021 edition2024 +//@ [edition2021] edition: 2021 +//@ [edition2024] edition: 2024 + +// See `mir_drop_order.rs` for more information + +#![feature(if_let_guard)] +#![allow(irrefutable_let_patterns)] + +use std::cell::RefCell; +use std::panic; + +pub struct DropLogger<'a, T> { + extra: T, + id: usize, + log: &'a panic::AssertUnwindSafe>>, +} + +impl<'a, T> Drop for DropLogger<'a, T> { + fn drop(&mut self) { + self.log.0.borrow_mut().push(self.id); + } +} + +struct InjectedFailure; + +#[allow(unreachable_code)] +fn main() { + let log = panic::AssertUnwindSafe(RefCell::new(vec![])); + let d = |id, extra| DropLogger { extra, id: id, log: &log }; + let get = || -> Vec<_> { + let mut m = log.0.borrow_mut(); + let n = m.drain(..); + n.collect() + }; + + { + let _x = ( + d( + 0, + d( + 1, + match () { () if let Some(_) = d(2, Some(true)).extra + && let DropLogger { .. } = d(3, None) => { + None + } + _ => { + Some(true) + } + } + ) + .extra, + ), + d(4, None), + &d(5, None), + d(6, None), + match () { + () if let DropLogger { .. } = d(7, None) + && let DropLogger { .. } = d(8, None) => { + d(9, None) + } + _ => { + // 10 is not constructed + d(10, None) + } + }, + ); + assert_eq!(get(), vec![3, 2, 8, 7, 1]); + } + assert_eq!(get(), vec![0, 4, 6, 9, 5]); + + let _ = std::panic::catch_unwind(|| { + ( + d( + 11, + d( + 12, + match () { + () if let Some(_) = d(13, Some(true)).extra + && let DropLogger { .. } = d(14, None) => { + None + } + _ => { + Some(true) + } + } + ) + .extra, + ), + d(15, None), + &d(16, None), + d(17, None), + match () { + () if let DropLogger { .. } = d(18, None) + && let DropLogger { .. } = d(19, None) + => { + d(20, None) + } + _ => { + // 10 is not constructed + d(21, None) + } + }, + panic::panic_any(InjectedFailure), + ); + }); + assert_eq!(get(), vec![14, 13, 19, 18, 20, 17, 15, 11, 16, 12]); +} From 9f4ecea24269f6a6c7cd54b4648a1ccd23a58d90 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Thu, 6 Mar 2025 06:05:03 -0500 Subject: [PATCH 2240/4206] Add internal lint `derive_deserialize_allowing_unknown` --- clippy_config/src/lib.rs | 1 + clippy_config/src/types.rs | 3 +- .../derive_deserialize_allowing_unknown.rs | 164 ++++++++++++++++++ clippy_lints_internal/src/lib.rs | 3 + .../derive_deserialize_allowing_unknown.rs | 60 +++++++ ...derive_deserialize_allowing_unknown.stderr | 23 +++ .../clippy.toml | 4 + .../toml_unknown_config_struct_field.rs | 5 + .../toml_unknown_config_struct_field.stderr | 8 + 9 files changed, 270 insertions(+), 1 deletion(-) create mode 100644 clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs create mode 100644 tests/ui-internal/derive_deserialize_allowing_unknown.rs create mode 100644 tests/ui-internal/derive_deserialize_allowing_unknown.stderr create mode 100644 tests/ui-toml/toml_unknown_config_struct_field/clippy.toml create mode 100644 tests/ui-toml/toml_unknown_config_struct_field/toml_unknown_config_struct_field.rs create mode 100644 tests/ui-toml/toml_unknown_config_struct_field/toml_unknown_config_struct_field.stderr diff --git a/clippy_config/src/lib.rs b/clippy_config/src/lib.rs index 33608591fc746..67904b4fcdc85 100644 --- a/clippy_config/src/lib.rs +++ b/clippy_config/src/lib.rs @@ -12,6 +12,7 @@ rustc::diagnostic_outside_of_impl, rustc::untranslatable_diagnostic )] +#![deny(clippy::derive_deserialize_allowing_unknown)] extern crate rustc_data_structures; extern crate rustc_errors; diff --git a/clippy_config/src/types.rs b/clippy_config/src/types.rs index 2cb5493f1a98a..f64eefa0c232d 100644 --- a/clippy_config/src/types.rs +++ b/clippy_config/src/types.rs @@ -12,6 +12,7 @@ use std::collections::HashMap; use std::fmt; #[derive(Debug, Deserialize)] +#[serde(deny_unknown_fields)] pub struct Rename { pub path: String, pub rename: String, @@ -59,7 +60,7 @@ impl<'de, const REPLACEMENT_ALLOWED: bool> Deserialize<'de> for DisallowedPath, + /// replacement: Option, + /// } + /// ``` + /// + /// Use instead: + /// ```rust + /// #[derive(serde::Deserialize)] + /// #[serde(deny_unknown_fields)] + /// pub struct DisallowedPath { + /// path: String, + /// reason: Option, + /// replacement: Option, + /// } + /// ``` + pub clippy::DERIVE_DESERIALIZE_ALLOWING_UNKNOWN, + Allow, + "`#[derive(serde::Deserialize)]` without `#[serde(deny_unknown_fields)]`", + report_in_external_macro: true +} + +declare_lint_pass!(DeriveDeserializeAllowingUnknown => [DERIVE_DESERIALIZE_ALLOWING_UNKNOWN]); + +impl<'tcx> LateLintPass<'tcx> for DeriveDeserializeAllowingUnknown { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + // Is this an `impl` (of a certain form)? + let ItemKind::Impl(Impl { + of_trait: + Some(TraitRef { + path: + Path { + res: Res::Def(_, trait_def_id), + .. + }, + .. + }), + self_ty: + Ty { + kind: + TyKind::Path(QPath::Resolved( + None, + Path { + res: Res::Def(_, self_ty_def_id), + .. + }, + )), + .. + }, + .. + }) = item.kind + else { + return; + }; + + // Is it an `impl` of the trait `serde::Deserialize`? + if !paths::SERDE_DESERIALIZE.get(cx).contains(trait_def_id) { + return; + } + + // Is it derived? + if !cx.tcx.has_attr(item.owner_id, sym::automatically_derived) { + return; + } + + // Is `self_ty` local? + let Some(local_def_id) = self_ty_def_id.as_local() else { + return; + }; + + // Does `self_ty` have a variant with named fields? + if !has_variant_with_named_fields(cx.tcx, local_def_id) { + return; + } + + let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id); + + // Does `self_ty` have `#[serde(deny_unknown_fields)]`? + if let Some(tokens) = find_serde_attr_item(cx.tcx, hir_id) + && tokens.iter().any(is_deny_unknown_fields_token) + { + return; + } + + span_lint( + cx, + DERIVE_DESERIALIZE_ALLOWING_UNKNOWN, + item.span, + "`#[derive(serde::Deserialize)]` without `#[serde(deny_unknown_fields)]`", + ); + } +} + +// Determines whether `def_id` corresponds to an ADT with at least one variant with named fields. A +// variant has named fields if its `ctor` field is `None`. +fn has_variant_with_named_fields(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + let ty = tcx.type_of(def_id).skip_binder(); + + let rustc_middle::ty::Adt(adt_def, _) = ty.kind() else { + return false; + }; + + adt_def.variants().iter().any(|variant_def| variant_def.ctor.is_none()) +} + +fn find_serde_attr_item(tcx: TyCtxt<'_>, hir_id: HirId) -> Option<&TokenStream> { + tcx.hir_attrs(hir_id).iter().find_map(|attribute| { + if let Attribute::Unparsed(attr_item) = attribute + && let AttrItem { + path: AttrPath { segments, .. }, + args: AttrArgs::Delimited(DelimArgs { tokens, .. }), + style: AttrStyle::Outer, + .. + } = &**attr_item + && segments.len() == 1 + && segments[0].as_str() == "serde" + { + Some(tokens) + } else { + None + } + }) +} + +fn is_deny_unknown_fields_token(tt: &TokenTree) -> bool { + if let TokenTree::Token(token, _) = tt + && token + .ident() + .is_some_and(|(token, _)| token.as_str() == "deny_unknown_fields") + { + true + } else { + false + } +} diff --git a/clippy_lints_internal/src/lib.rs b/clippy_lints_internal/src/lib.rs index 308d161b9d6d1..43cde86504f5c 100644 --- a/clippy_lints_internal/src/lib.rs +++ b/clippy_lints_internal/src/lib.rs @@ -32,6 +32,7 @@ extern crate rustc_span; mod almost_standard_lint_formulation; mod collapsible_calls; +mod derive_deserialize_allowing_unknown; mod internal_paths; mod lint_without_lint_pass; mod msrv_attr_impl; @@ -46,6 +47,7 @@ use rustc_lint::{Lint, LintStore}; static LINTS: &[&Lint] = &[ almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION, collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS, + derive_deserialize_allowing_unknown::DERIVE_DESERIALIZE_ALLOWING_UNKNOWN, lint_without_lint_pass::DEFAULT_LINT, lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE, lint_without_lint_pass::LINT_WITHOUT_LINT_PASS, @@ -65,6 +67,7 @@ pub fn register_lints(store: &mut LintStore) { store.register_early_pass(|| Box::new(unsorted_clippy_utils_paths::UnsortedClippyUtilsPaths)); store.register_early_pass(|| Box::new(produce_ice::ProduceIce)); store.register_late_pass(|_| Box::new(collapsible_calls::CollapsibleCalls)); + store.register_late_pass(|_| Box::new(derive_deserialize_allowing_unknown::DeriveDeserializeAllowingUnknown)); store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::new(unnecessary_def_path::UnnecessaryDefPath)); diff --git a/tests/ui-internal/derive_deserialize_allowing_unknown.rs b/tests/ui-internal/derive_deserialize_allowing_unknown.rs new file mode 100644 index 0000000000000..9dc8e9e8f4c16 --- /dev/null +++ b/tests/ui-internal/derive_deserialize_allowing_unknown.rs @@ -0,0 +1,60 @@ +#![deny(clippy::derive_deserialize_allowing_unknown)] + +use serde::{Deserialize, Deserializer}; + +#[derive(Deserialize)] //~ derive_deserialize_allowing_unknown +struct Struct { + flag: bool, + limit: u64, +} + +#[derive(Deserialize)] //~ derive_deserialize_allowing_unknown +enum Enum { + A(bool), + B { limit: u64 }, +} + +// negative tests + +#[derive(Deserialize)] +#[serde(deny_unknown_fields)] +struct StructWithDenyUnknownFields { + flag: bool, + limit: u64, +} + +#[derive(Deserialize)] +#[serde(deny_unknown_fields)] +enum EnumWithDenyUnknownFields { + A(bool), + B { limit: u64 }, +} + +#[derive(Deserialize)] +#[serde(untagged, deny_unknown_fields)] +enum MultipleSerdeAttributes { + A(bool), + B { limit: u64 }, +} + +#[derive(Deserialize)] +struct TupleStruct(u64, bool); + +#[derive(Deserialize)] +#[serde(deny_unknown_fields)] +enum EnumWithOnlyTupleVariants { + A(bool), + B(u64), +} + +struct ManualSerdeImplementation; + +impl<'de> Deserialize<'de> for ManualSerdeImplementation { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let () = <() as Deserialize>::deserialize(deserializer)?; + Ok(ManualSerdeImplementation) + } +} diff --git a/tests/ui-internal/derive_deserialize_allowing_unknown.stderr b/tests/ui-internal/derive_deserialize_allowing_unknown.stderr new file mode 100644 index 0000000000000..93d64826c9935 --- /dev/null +++ b/tests/ui-internal/derive_deserialize_allowing_unknown.stderr @@ -0,0 +1,23 @@ +error: `#[derive(serde::Deserialize)]` without `#[serde(deny_unknown_fields)]` + --> tests/ui-internal/derive_deserialize_allowing_unknown.rs:5:10 + | +LL | #[derive(Deserialize)] + | ^^^^^^^^^^^ + | +note: the lint level is defined here + --> tests/ui-internal/derive_deserialize_allowing_unknown.rs:1:9 + | +LL | #![deny(clippy::derive_deserialize_allowing_unknown)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `#[derive(serde::Deserialize)]` without `#[serde(deny_unknown_fields)]` + --> tests/ui-internal/derive_deserialize_allowing_unknown.rs:11:10 + | +LL | #[derive(Deserialize)] + | ^^^^^^^^^^^ + | + = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + diff --git a/tests/ui-toml/toml_unknown_config_struct_field/clippy.toml b/tests/ui-toml/toml_unknown_config_struct_field/clippy.toml new file mode 100644 index 0000000000000..82560cfd5e2a4 --- /dev/null +++ b/tests/ui-toml/toml_unknown_config_struct_field/clippy.toml @@ -0,0 +1,4 @@ +# In the following configuration, "recommendation" should be "reason" or "replacement". +disallowed-macros = [ + { path = "std::panic", recommendation = "return a `std::result::Result::Error` instead" }, +] diff --git a/tests/ui-toml/toml_unknown_config_struct_field/toml_unknown_config_struct_field.rs b/tests/ui-toml/toml_unknown_config_struct_field/toml_unknown_config_struct_field.rs new file mode 100644 index 0000000000000..9c770c31f6f8d --- /dev/null +++ b/tests/ui-toml/toml_unknown_config_struct_field/toml_unknown_config_struct_field.rs @@ -0,0 +1,5 @@ +#[rustfmt::skip] +//@error-in-other-file: error reading Clippy's configuration file: data did not match any variant of untagged enum DisallowedPathEnum +fn main() { + panic!(); +} diff --git a/tests/ui-toml/toml_unknown_config_struct_field/toml_unknown_config_struct_field.stderr b/tests/ui-toml/toml_unknown_config_struct_field/toml_unknown_config_struct_field.stderr new file mode 100644 index 0000000000000..b564709721d5c --- /dev/null +++ b/tests/ui-toml/toml_unknown_config_struct_field/toml_unknown_config_struct_field.stderr @@ -0,0 +1,8 @@ +error: error reading Clippy's configuration file: data did not match any variant of untagged enum DisallowedPathEnum + --> $DIR/tests/ui-toml/toml_unknown_config_struct_field/clippy.toml:3:5 + | +LL | { path = "std::panic", recommendation = "return a `std::result::Result::Error` instead" }, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + From f4bc4cd1fdb39203740929a6ec2cfc42f8b1e86d Mon Sep 17 00:00:00 2001 From: Stypox Date: Mon, 12 May 2025 16:40:46 +0200 Subject: [PATCH 2241/4206] Add TRACING_ENABLED to Machine trait --- compiler/rustc_const_eval/src/interpret/machine.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index a1386b4e1be49..d13e17a481a46 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -147,6 +147,12 @@ pub trait Machine<'tcx>: Sized { /// already been checked before. const ALL_CONSTS_ARE_PRECHECKED: bool = true; + /// Determines whether rustc_const_eval functions that make use of the [Machine] should make + /// tracing calls (to the `tracing` library). By default this is `false`, meaning the tracing + /// calls will supposedly be optimized out. This flag is set to `true` inside Miri, to allow + /// tracing the interpretation steps, among other things. + const TRACING_ENABLED: bool = false; + /// Whether memory accesses should be alignment-checked. fn enforce_alignment(ecx: &InterpCx<'tcx, Self>) -> bool; From 4fcd33c3185a969127c532e06aaffac0a8761207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Wed, 14 May 2025 00:45:55 +0800 Subject: [PATCH 2242/4206] Update rustix to 1.0.7 for bootstrap --- src/bootstrap/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 05ab1b6eddefb..ff63b8c62d3a0 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -579,9 +579,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rustix" -version = "1.0.2" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7178faa4b75a30e269c71e61c353ce2748cf3d76f0c44c393f4e60abf49b825" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ "bitflags", "errno", From febb16a40fe2c3722f6e4202ee6783bf6b79b29c Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 13 May 2025 16:47:10 +0000 Subject: [PATCH 2243/4206] type_ir: add faster exit for `types_may_unify` --- compiler/rustc_type_ir/src/fast_reject.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs index 11ec1f0a9fb0e..34502f4955003 100644 --- a/compiler/rustc_type_ir/src/fast_reject.rs +++ b/compiler/rustc_type_ir/src/fast_reject.rs @@ -232,6 +232,9 @@ impl bool { + if lhs == rhs { + return true; + } self.types_may_unify_inner(lhs, rhs, Self::STARTING_DEPTH) } From 36790d28810ac188a8bca7fc9e95fe0869ae9a11 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 24 Feb 2025 22:29:37 -0500 Subject: [PATCH 2244/4206] Initial implementation of `core_float_math` Since [1], `compiler-builtins` makes a certain set of math symbols weakly available on all platforms. This means we can begin exposing some of the related functions in `core`, so begin this process here. It is not possible to provide inherent methods in both `core` and `std` while giving them different stability gates, so standalone functions are added instead. This provides a way to experiment with the functionality while unstable; once it is time to stabilize, they can be converted to inherent. For `f16` and `f128`, everything is unstable so we can move the inherent methods. The following are included to start: * floor * ceil * round * round_ties_even * trunc * fract * mul_add * div_euclid * rem_euclid * powi * sqrt * abs_sub * cbrt These mirror the set of functions that we have in `compiler-builtins` since [1]. Tracking issue: https://github.com/rust-lang/rust/issues/137578 [1]: https://github.com/rust-lang/compiler-builtins/pull/763 --- library/core/Cargo.toml | 6 + library/core/src/num/f128.rs | 410 ++++++++++++++++++++++++++++++++ library/core/src/num/f16.rs | 445 +++++++++++++++++++++++++++++++++++ library/core/src/num/f32.rs | 410 +++++++++++++++++++++++++++++++- library/core/src/num/f64.rs | 403 ++++++++++++++++++++++++++++++- library/core/src/num/libm.rs | 11 + library/core/src/num/mod.rs | 1 + library/std/src/f128.rs | 396 ------------------------------- library/std/src/f16.rs | 431 --------------------------------- library/std/src/f32.rs | 32 ++- library/std/src/f64.rs | 32 ++- library/std/src/lib.rs | 1 + library/std/src/sys/cmath.rs | 4 - 13 files changed, 1713 insertions(+), 869 deletions(-) create mode 100644 library/core/src/num/libm.rs diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml index 99e52d0ada0a6..83ba17b93f519 100644 --- a/library/core/Cargo.toml +++ b/library/core/Cargo.toml @@ -35,4 +35,10 @@ check-cfg = [ # and to stdarch `core_arch` crate which messes-up with Cargo list # of declared features, we therefor expect any feature cfg 'cfg(feature, values(any()))', + # Internal features aren't marked known config by default, we use these to + # gate tests. + 'cfg(target_has_reliable_f16)', + 'cfg(target_has_reliable_f16_math)', + 'cfg(target_has_reliable_f128)', + 'cfg(target_has_reliable_f128_math)', ] diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 7e470185c86d1..0c2c4155d66ce 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -1415,3 +1415,413 @@ impl f128 { intrinsics::frem_algebraic(self, rhs) } } + +// Functions in this module fall into `core_float_math` +// FIXME(f16_f128): all doctests must be gated to platforms that have `long double` === `_Float128` +// due to https://github.com/llvm/llvm-project/issues/44744. aarch64 linux matches this. +// #[unstable(feature = "core_float_math", issue = "137578")] +#[cfg(not(test))] +impl f128 { + /// Returns the largest integer less than or equal to `self`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f128_math)] { + /// + /// let f = 3.7_f128; + /// let g = 3.0_f128; + /// let h = -3.7_f128; + /// + /// assert_eq!(f.floor(), 3.0); + /// assert_eq!(g.floor(), 3.0); + /// assert_eq!(h.floor(), -4.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn floor(self) -> f128 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::floorf128(self) } + } + + /// Returns the smallest integer greater than or equal to `self`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f128_math)] { + /// + /// let f = 3.01_f128; + /// let g = 4.0_f128; + /// + /// assert_eq!(f.ceil(), 4.0); + /// assert_eq!(g.ceil(), 4.0); + /// # } + /// ``` + #[inline] + #[doc(alias = "ceiling")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn ceil(self) -> f128 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::ceilf128(self) } + } + + /// Returns the nearest integer to `self`. If a value is half-way between two + /// integers, round away from `0.0`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f128_math)] { + /// + /// let f = 3.3_f128; + /// let g = -3.3_f128; + /// let h = -3.7_f128; + /// let i = 3.5_f128; + /// let j = 4.5_f128; + /// + /// assert_eq!(f.round(), 3.0); + /// assert_eq!(g.round(), -3.0); + /// assert_eq!(h.round(), -4.0); + /// assert_eq!(i.round(), 4.0); + /// assert_eq!(j.round(), 5.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn round(self) -> f128 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::roundf128(self) } + } + + /// Returns the nearest integer to a number. Rounds half-way cases to the number + /// with an even least significant digit. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f128_math)] { + /// + /// let f = 3.3_f128; + /// let g = -3.3_f128; + /// let h = 3.5_f128; + /// let i = 4.5_f128; + /// + /// assert_eq!(f.round_ties_even(), 3.0); + /// assert_eq!(g.round_ties_even(), -3.0); + /// assert_eq!(h.round_ties_even(), 4.0); + /// assert_eq!(i.round_ties_even(), 4.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn round_ties_even(self) -> f128 { + intrinsics::round_ties_even_f128(self) + } + + /// Returns the integer part of `self`. + /// This means that non-integer numbers are always truncated towards zero. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f128_math)] { + /// + /// let f = 3.7_f128; + /// let g = 3.0_f128; + /// let h = -3.7_f128; + /// + /// assert_eq!(f.trunc(), 3.0); + /// assert_eq!(g.trunc(), 3.0); + /// assert_eq!(h.trunc(), -3.0); + /// # } + /// ``` + #[inline] + #[doc(alias = "truncate")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn trunc(self) -> f128 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::truncf128(self) } + } + + /// Returns the fractional part of `self`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f128_math)] { + /// + /// let x = 3.6_f128; + /// let y = -3.6_f128; + /// let abs_difference_x = (x.fract() - 0.6).abs(); + /// let abs_difference_y = (y.fract() - (-0.6)).abs(); + /// + /// assert!(abs_difference_x <= f128::EPSILON); + /// assert!(abs_difference_y <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn fract(self) -> f128 { + self - self.trunc() + } + + /// Fused multiply-add. Computes `(self * a) + b` with only one rounding + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` *may* be more performant than an unfused multiply-add if + /// the target architecture has a dedicated `fma` CPU instruction. However, + /// this is not always true, and will be heavily dependant on designing + /// algorithms with specific target hardware in mind. + /// + /// # Precision + /// + /// The result of this operation is guaranteed to be the rounded + /// infinite-precision result. It is specified by IEEE 754 as + /// `fusedMultiplyAdd` and guaranteed not to change. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f128_math)] { + /// + /// let m = 10.0_f128; + /// let x = 4.0_f128; + /// let b = 60.0_f128; + /// + /// assert_eq!(m.mul_add(x, b), 100.0); + /// assert_eq!(m * x + b, 100.0); + /// + /// let one_plus_eps = 1.0_f128 + f128::EPSILON; + /// let one_minus_eps = 1.0_f128 - f128::EPSILON; + /// let minus_one = -1.0_f128; + /// + /// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps. + /// assert_eq!(one_plus_eps.mul_add(one_minus_eps, minus_one), -f128::EPSILON * f128::EPSILON); + /// // Different rounding with the non-fused multiply and add. + /// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[doc(alias = "fmaf128", alias = "fusedMultiplyAdd")] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn mul_add(self, a: f128, b: f128) -> f128 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::fmaf128(self, a, b) } + } + + /// Calculates Euclidean division, the matching method for `rem_euclid`. + /// + /// This computes the integer `n` such that + /// `self = n * rhs + self.rem_euclid(rhs)`. + /// In other words, the result is `self / rhs` rounded to the integer `n` + /// such that `self >= n * rhs`. + /// + /// # Precision + /// + /// The result of this operation is guaranteed to be the rounded + /// infinite-precision result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f128_math)] { + /// + /// let a: f128 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.div_euclid(b), 1.0); // 7.0 > 4.0 * 1.0 + /// assert_eq!((-a).div_euclid(b), -2.0); // -7.0 >= 4.0 * -2.0 + /// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0 + /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0 + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn div_euclid(self, rhs: f128) -> f128 { + let q = (self / rhs).trunc(); + if self % rhs < 0.0 { + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; + } + q + } + + /// Calculates the least nonnegative remainder of `self (mod rhs)`. + /// + /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in + /// most cases. However, due to a floating point round-off error it can + /// result in `r == rhs.abs()`, violating the mathematical definition, if + /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`. + /// This result is not an element of the function's codomain, but it is the + /// closest floating point number in the real numbers and thus fulfills the + /// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)` + /// approximately. + /// + /// # Precision + /// + /// The result of this operation is guaranteed to be the rounded + /// infinite-precision result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f128_math)] { + /// + /// let a: f128 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.rem_euclid(b), 3.0); + /// assert_eq!((-a).rem_euclid(b), 1.0); + /// assert_eq!(a.rem_euclid(-b), 3.0); + /// assert_eq!((-a).rem_euclid(-b), 1.0); + /// // limitation due to round-off error + /// assert!((-f128::EPSILON).rem_euclid(3.0) != 0.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[doc(alias = "modulo", alias = "mod")] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn rem_euclid(self, rhs: f128) -> f128 { + let r = self % rhs; + if r < 0.0 { r + rhs.abs() } else { r } + } + + /// Raises a number to an integer power. + /// + /// Using this function is generally faster than using `powf`. + /// It might have a different sequence of rounding operations than `powf`, + /// so the results are not guaranteed to agree. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f128_math)] { + /// + /// let x = 2.0_f128; + /// let abs_difference = (x.powi(2) - (x * x)).abs(); + /// assert!(abs_difference <= f128::EPSILON); + /// + /// assert_eq!(f128::powi(f128::NAN, 0), 1.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn powi(self, n: i32) -> f128 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::powif128(self, n) } + } + + /// Returns the square root of a number. + /// + /// Returns NaN if `self` is a negative number other than `-0.0`. + /// + /// # Precision + /// + /// The result of this operation is guaranteed to be the rounded + /// infinite-precision result. It is specified by IEEE 754 as `squareRoot` + /// and guaranteed not to change. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f128_math)] { + /// + /// let positive = 4.0_f128; + /// let negative = -4.0_f128; + /// let negative_zero = -0.0_f128; + /// + /// assert_eq!(positive.sqrt(), 2.0); + /// assert!(negative.sqrt().is_nan()); + /// assert!(negative_zero.sqrt() == negative_zero); + /// # } + /// ``` + #[inline] + #[doc(alias = "squareRoot")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn sqrt(self) -> f128 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::sqrtf128(self) } + } +} diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index e47900cba550a..1a859f2277ff3 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -13,6 +13,8 @@ use crate::convert::FloatToInt; use crate::num::FpCategory; +#[cfg(not(test))] +use crate::num::libm; use crate::panic::const_assert; use crate::{intrinsics, mem}; @@ -1391,3 +1393,446 @@ impl f16 { intrinsics::frem_algebraic(self, rhs) } } + +// Functions in this module fall into `core_float_math` +// #[unstable(feature = "core_float_math", issue = "137578")] +#[cfg(not(test))] +impl f16 { + /// Returns the largest integer less than or equal to `self`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f16_math)] { + /// + /// let f = 3.7_f16; + /// let g = 3.0_f16; + /// let h = -3.7_f16; + /// + /// assert_eq!(f.floor(), 3.0); + /// assert_eq!(g.floor(), 3.0); + /// assert_eq!(h.floor(), -4.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn floor(self) -> f16 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::floorf16(self) } + } + + /// Returns the smallest integer greater than or equal to `self`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f16_math)] { + /// + /// let f = 3.01_f16; + /// let g = 4.0_f16; + /// + /// assert_eq!(f.ceil(), 4.0); + /// assert_eq!(g.ceil(), 4.0); + /// # } + /// ``` + #[inline] + #[doc(alias = "ceiling")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn ceil(self) -> f16 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::ceilf16(self) } + } + + /// Returns the nearest integer to `self`. If a value is half-way between two + /// integers, round away from `0.0`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f16_math)] { + /// + /// let f = 3.3_f16; + /// let g = -3.3_f16; + /// let h = -3.7_f16; + /// let i = 3.5_f16; + /// let j = 4.5_f16; + /// + /// assert_eq!(f.round(), 3.0); + /// assert_eq!(g.round(), -3.0); + /// assert_eq!(h.round(), -4.0); + /// assert_eq!(i.round(), 4.0); + /// assert_eq!(j.round(), 5.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn round(self) -> f16 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::roundf16(self) } + } + + /// Returns the nearest integer to a number. Rounds half-way cases to the number + /// with an even least significant digit. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f16_math)] { + /// + /// let f = 3.3_f16; + /// let g = -3.3_f16; + /// let h = 3.5_f16; + /// let i = 4.5_f16; + /// + /// assert_eq!(f.round_ties_even(), 3.0); + /// assert_eq!(g.round_ties_even(), -3.0); + /// assert_eq!(h.round_ties_even(), 4.0); + /// assert_eq!(i.round_ties_even(), 4.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn round_ties_even(self) -> f16 { + intrinsics::round_ties_even_f16(self) + } + + /// Returns the integer part of `self`. + /// This means that non-integer numbers are always truncated towards zero. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f16_math)] { + /// + /// let f = 3.7_f16; + /// let g = 3.0_f16; + /// let h = -3.7_f16; + /// + /// assert_eq!(f.trunc(), 3.0); + /// assert_eq!(g.trunc(), 3.0); + /// assert_eq!(h.trunc(), -3.0); + /// # } + /// ``` + #[inline] + #[doc(alias = "truncate")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn trunc(self) -> f16 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::truncf16(self) } + } + + /// Returns the fractional part of `self`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f16_math)] { + /// + /// let x = 3.6_f16; + /// let y = -3.6_f16; + /// let abs_difference_x = (x.fract() - 0.6).abs(); + /// let abs_difference_y = (y.fract() - (-0.6)).abs(); + /// + /// assert!(abs_difference_x <= f16::EPSILON); + /// assert!(abs_difference_y <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn fract(self) -> f16 { + self - self.trunc() + } + + /// Fused multiply-add. Computes `(self * a) + b` with only one rounding + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` *may* be more performant than an unfused multiply-add if + /// the target architecture has a dedicated `fma` CPU instruction. However, + /// this is not always true, and will be heavily dependant on designing + /// algorithms with specific target hardware in mind. + /// + /// # Precision + /// + /// The result of this operation is guaranteed to be the rounded + /// infinite-precision result. It is specified by IEEE 754 as + /// `fusedMultiplyAdd` and guaranteed not to change. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f16_math)] { + /// + /// let m = 10.0_f16; + /// let x = 4.0_f16; + /// let b = 60.0_f16; + /// + /// assert_eq!(m.mul_add(x, b), 100.0); + /// assert_eq!(m * x + b, 100.0); + /// + /// let one_plus_eps = 1.0_f16 + f16::EPSILON; + /// let one_minus_eps = 1.0_f16 - f16::EPSILON; + /// let minus_one = -1.0_f16; + /// + /// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps. + /// assert_eq!(one_plus_eps.mul_add(one_minus_eps, minus_one), -f16::EPSILON * f16::EPSILON); + /// // Different rounding with the non-fused multiply and add. + /// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[doc(alias = "fmaf16", alias = "fusedMultiplyAdd")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn mul_add(self, a: f16, b: f16) -> f16 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::fmaf16(self, a, b) } + } + + /// Calculates Euclidean division, the matching method for `rem_euclid`. + /// + /// This computes the integer `n` such that + /// `self = n * rhs + self.rem_euclid(rhs)`. + /// In other words, the result is `self / rhs` rounded to the integer `n` + /// such that `self >= n * rhs`. + /// + /// # Precision + /// + /// The result of this operation is guaranteed to be the rounded + /// infinite-precision result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f16_math)] { + /// + /// let a: f16 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.div_euclid(b), 1.0); // 7.0 > 4.0 * 1.0 + /// assert_eq!((-a).div_euclid(b), -2.0); // -7.0 >= 4.0 * -2.0 + /// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0 + /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0 + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn div_euclid(self, rhs: f16) -> f16 { + let q = (self / rhs).trunc(); + if self % rhs < 0.0 { + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; + } + q + } + + /// Calculates the least nonnegative remainder of `self (mod rhs)`. + /// + /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in + /// most cases. However, due to a floating point round-off error it can + /// result in `r == rhs.abs()`, violating the mathematical definition, if + /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`. + /// This result is not an element of the function's codomain, but it is the + /// closest floating point number in the real numbers and thus fulfills the + /// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)` + /// approximately. + /// + /// # Precision + /// + /// The result of this operation is guaranteed to be the rounded + /// infinite-precision result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f16_math)] { + /// + /// let a: f16 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.rem_euclid(b), 3.0); + /// assert_eq!((-a).rem_euclid(b), 1.0); + /// assert_eq!(a.rem_euclid(-b), 3.0); + /// assert_eq!((-a).rem_euclid(-b), 1.0); + /// // limitation due to round-off error + /// assert!((-f16::EPSILON).rem_euclid(3.0) != 0.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[doc(alias = "modulo", alias = "mod")] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn rem_euclid(self, rhs: f16) -> f16 { + let r = self % rhs; + if r < 0.0 { r + rhs.abs() } else { r } + } + + /// Raises a number to an integer power. + /// + /// Using this function is generally faster than using `powf`. + /// It might have a different sequence of rounding operations than `powf`, + /// so the results are not guaranteed to agree. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f16_math)] { + /// + /// let x = 2.0_f16; + /// let abs_difference = (x.powi(2) - (x * x)).abs(); + /// assert!(abs_difference <= f16::EPSILON); + /// + /// assert_eq!(f16::powi(f16::NAN, 0), 1.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn powi(self, n: i32) -> f16 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::powif16(self, n) } + } + + /// Returns the square root of a number. + /// + /// Returns NaN if `self` is a negative number other than `-0.0`. + /// + /// # Precision + /// + /// The result of this operation is guaranteed to be the rounded + /// infinite-precision result. It is specified by IEEE 754 as `squareRoot` + /// and guaranteed not to change. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f16_math)] { + /// + /// let positive = 4.0_f16; + /// let negative = -4.0_f16; + /// let negative_zero = -0.0_f16; + /// + /// assert_eq!(positive.sqrt(), 2.0); + /// assert!(negative.sqrt().is_nan()); + /// assert!(negative_zero.sqrt() == negative_zero); + /// # } + /// ``` + #[inline] + #[doc(alias = "squareRoot")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn sqrt(self) -> f16 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::sqrtf16(self) } + } + + /// Returns the cube root of a number. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `cbrtf` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f16_math)] { + /// + /// let x = 8.0f16; + /// + /// // x^(1/3) - 2 == 0 + /// let abs_difference = (x.cbrt() - 2.0).abs(); + /// + /// assert!(abs_difference <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn cbrt(self) -> f16 { + libm::cbrtf(self as f32) as f16 + } +} diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 5fbc6eb33f170..326ccd517ced5 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -12,7 +12,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::convert::FloatToInt; -use crate::num::FpCategory; +use crate::num::{FpCategory, libm}; use crate::panic::const_assert; use crate::{cfg_match, intrinsics, mem}; @@ -1556,3 +1556,411 @@ impl f32 { intrinsics::frem_algebraic(self, rhs) } } + +/// Experimental version of `floor` in `core`. See [`f32::floor`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let f = 3.7_f32; +/// let g = 3.0_f32; +/// let h = -3.7_f32; +/// +/// assert_eq!(f32::floor(f), 3.0); +/// assert_eq!(f32::floor(g), 3.0); +/// assert_eq!(f32::floor(h), -4.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::floor`]: ../../std/primitive.f32.html#method.floor +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn floor(x: f32) -> f32 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::floorf32(x) } +} + +/// Experimental version of `ceil` in `core`. See [`f32::ceil`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let f = 3.01_f32; +/// let g = 4.0_f32; +/// +/// assert_eq!(f32::ceil(f), 4.0); +/// assert_eq!(f32::ceil(g), 4.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::ceil`]: ../../std/primitive.f32.html#method.ceil +#[inline] +#[doc(alias = "ceiling")] +#[must_use = "method returns a new number and does not mutate the original value"] +#[unstable(feature = "core_float_math", issue = "137578")] +pub fn ceil(x: f32) -> f32 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::ceilf32(x) } +} + +/// Experimental version of `round` in `core`. See [`f32::round`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let f = 3.3_f32; +/// let g = -3.3_f32; +/// let h = -3.7_f32; +/// let i = 3.5_f32; +/// let j = 4.5_f32; +/// +/// assert_eq!(f32::round(f), 3.0); +/// assert_eq!(f32::round(g), -3.0); +/// assert_eq!(f32::round(h), -4.0); +/// assert_eq!(f32::round(i), 4.0); +/// assert_eq!(f32::round(j), 5.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::round`]: ../../std/primitive.f32.html#method.round +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn round(x: f32) -> f32 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::roundf32(x) } +} + +/// Experimental version of `round_ties_even` in `core`. See [`f32::round_ties_even`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let f = 3.3_f32; +/// let g = -3.3_f32; +/// let h = 3.5_f32; +/// let i = 4.5_f32; +/// +/// assert_eq!(f32::round_ties_even(f), 3.0); +/// assert_eq!(f32::round_ties_even(g), -3.0); +/// assert_eq!(f32::round_ties_even(h), 4.0); +/// assert_eq!(f32::round_ties_even(i), 4.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::round_ties_even`]: ../../std/primitive.f32.html#method.round_ties_even +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn round_ties_even(x: f32) -> f32 { + intrinsics::round_ties_even_f32(x) +} + +/// Experimental version of `trunc` in `core`. See [`f32::trunc`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let f = 3.7_f32; +/// let g = 3.0_f32; +/// let h = -3.7_f32; +/// +/// assert_eq!(f32::trunc(f), 3.0); +/// assert_eq!(f32::trunc(g), 3.0); +/// assert_eq!(f32::trunc(h), -3.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::trunc`]: ../../std/primitive.f32.html#method.trunc +#[inline] +#[doc(alias = "truncate")] +#[must_use = "method returns a new number and does not mutate the original value"] +#[unstable(feature = "core_float_math", issue = "137578")] +pub fn trunc(x: f32) -> f32 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::truncf32(x) } +} + +/// Experimental version of `fract` in `core`. See [`f32::fract`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let x = 3.6_f32; +/// let y = -3.6_f32; +/// let abs_difference_x = (f32::fract(x) - 0.6).abs(); +/// let abs_difference_y = (f32::fract(y) - (-0.6)).abs(); +/// +/// assert!(abs_difference_x <= f32::EPSILON); +/// assert!(abs_difference_y <= f32::EPSILON); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::fract`]: ../../std/primitive.f32.html#method.fract +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn fract(x: f32) -> f32 { + x - trunc(x) +} + +/// Experimental version of `mul_add` in `core`. See [`f32::mul_add`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let m = 10.0_f32; +/// let x = 4.0_f32; +/// let b = 60.0_f32; +/// +/// assert_eq!(f32::mul_add(m, x, b), 100.0); +/// assert_eq!(m * x + b, 100.0); +/// +/// let one_plus_eps = 1.0_f32 + f32::EPSILON; +/// let one_minus_eps = 1.0_f32 - f32::EPSILON; +/// let minus_one = -1.0_f32; +/// +/// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps. +/// assert_eq!(f32::mul_add(one_plus_eps, one_minus_eps, minus_one), -f32::EPSILON * f32::EPSILON); +/// // Different rounding with the non-fused multiply and add. +/// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::mul_add`]: ../../std/primitive.f32.html#method.mul_add +#[inline] +#[doc(alias = "fmaf", alias = "fusedMultiplyAdd")] +#[must_use = "method returns a new number and does not mutate the original value"] +#[unstable(feature = "core_float_math", issue = "137578")] +pub fn mul_add(x: f32, y: f32, z: f32) -> f32 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::fmaf32(x, y, z) } +} + +/// Experimental version of `div_euclid` in `core`. See [`f32::div_euclid`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let a: f32 = 7.0; +/// let b = 4.0; +/// assert_eq!(f32::div_euclid(a, b), 1.0); // 7.0 > 4.0 * 1.0 +/// assert_eq!(f32::div_euclid(-a, b), -2.0); // -7.0 >= 4.0 * -2.0 +/// assert_eq!(f32::div_euclid(a, -b), -1.0); // 7.0 >= -4.0 * -1.0 +/// assert_eq!(f32::div_euclid(-a, -b), 2.0); // -7.0 >= -4.0 * 2.0 +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::div_euclid`]: ../../std/primitive.f32.html#method.div_euclid +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn div_euclid(x: f32, rhs: f32) -> f32 { + let q = trunc(x / rhs); + if x % rhs < 0.0 { + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; + } + q +} + +/// Experimental version of `rem_euclid` in `core`. See [`f32::rem_euclid`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let a: f32 = 7.0; +/// let b = 4.0; +/// assert_eq!(f32::rem_euclid(a, b), 3.0); +/// assert_eq!(f32::rem_euclid(-a, b), 1.0); +/// assert_eq!(f32::rem_euclid(a, -b), 3.0); +/// assert_eq!(f32::rem_euclid(-a, -b), 1.0); +/// // limitation due to round-off error +/// assert!(f32::rem_euclid(-f32::EPSILON, 3.0) != 0.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::rem_euclid`]: ../../std/primitive.f32.html#method.rem_euclid +#[inline] +#[doc(alias = "modulo", alias = "mod")] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn rem_euclid(x: f32, rhs: f32) -> f32 { + let r = x % rhs; + if r < 0.0 { r + rhs.abs() } else { r } +} + +/// Experimental version of `powi` in `core`. See [`f32::powi`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let x = 2.0_f32; +/// let abs_difference = (f32::powi(x, 2) - (x * x)).abs(); +/// assert!(abs_difference <= f32::EPSILON); +/// +/// assert_eq!(f32::powi(f32::NAN, 0), 1.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::powi`]: ../../std/primitive.f32.html#method.powi +#[inline] +#[must_use = "method returns a new number and does not mutate the original value"] +#[unstable(feature = "core_float_math", issue = "137578")] +pub fn powi(x: f32, n: i32) -> f32 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::powif32(x, n) } +} + +/// Experimental version of `sqrt` in `core`. See [`f32::sqrt`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let positive = 4.0_f32; +/// let negative = -4.0_f32; +/// let negative_zero = -0.0_f32; +/// +/// assert_eq!(f32::sqrt(positive), 2.0); +/// assert!(f32::sqrt(negative).is_nan()); +/// assert_eq!(f32::sqrt(negative_zero), negative_zero); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::sqrt`]: ../../std/primitive.f32.html#method.sqrt +#[inline] +#[doc(alias = "squareRoot")] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn sqrt(x: f32) -> f32 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::sqrtf32(x) } +} + +/// Experimental version of `abs_sub` in `core`. See [`f32::abs_sub`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let x = 3.0f32; +/// let y = -3.0f32; +/// +/// let abs_difference_x = (f32::abs_sub(x, 1.0) - 2.0).abs(); +/// let abs_difference_y = (f32::abs_sub(y, 1.0) - 0.0).abs(); +/// +/// assert!(abs_difference_x <= f32::EPSILON); +/// assert!(abs_difference_y <= f32::EPSILON); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::abs_sub`]: ../../std/primitive.f32.html#method.abs_sub +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +#[deprecated( + since = "1.10.0", + note = "you probably meant `(self - other).abs()`: \ + this operation is `(self - other).max(0.0)` \ + except that `abs_sub` also propagates NaNs (also \ + known as `fdimf` in C). If you truly need the positive \ + difference, consider using that expression or the C function \ + `fdimf`, depending on how you wish to handle NaN (please consider \ + filing an issue describing your use-case too)." +)] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn abs_sub(x: f32, other: f32) -> f32 { + libm::fdimf(x, other) +} + +/// Experimental version of `cbrt` in `core`. See [`f32::cbrt`] for details. +/// +/// # Unspecified precision +/// +/// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and +/// can even differ within the same execution from one invocation to the next. +/// This function currently corresponds to the `cbrtf` from libc on Unix +/// and Windows. Note that this might change in the future. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let x = 8.0f32; +/// +/// // x^(1/3) - 2 == 0 +/// let abs_difference = (f32::cbrt(x) - 2.0).abs(); +/// +/// assert!(abs_difference <= f32::EPSILON); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::cbrt`]: ../../std/primitive.f32.html#method.cbrt +#[inline] +#[must_use = "method returns a new number and does not mutate the original value"] +#[unstable(feature = "core_float_math", issue = "137578")] +pub fn cbrt(x: f32) -> f32 { + libm::cbrtf(x) +} diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 81ab0f14c2bc3..66aba73aec10d 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -12,7 +12,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::convert::FloatToInt; -use crate::num::FpCategory; +use crate::num::{FpCategory, libm}; use crate::panic::const_assert; use crate::{intrinsics, mem}; @@ -1555,3 +1555,404 @@ impl f64 { intrinsics::frem_algebraic(self, rhs) } } + +/// Experimental version of `floor` in `core`. See [`f64::floor`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let f = 3.7_f64; +/// let g = 3.0_f64; +/// let h = -3.7_f64; +/// +/// assert_eq!(f64::floor(f), 3.0); +/// assert_eq!(f64::floor(g), 3.0); +/// assert_eq!(f64::floor(h), -4.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::floor`]: ../../std/primitive.f64.html#method.floor +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn floor(x: f64) -> f64 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::floorf64(x) } +} + +/// Experimental version of `ceil` in `core`. See [`f64::ceil`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let f = 3.01_f64; +/// let g = 4.0_f64; +/// +/// assert_eq!(f64::ceil(f), 4.0); +/// assert_eq!(f64::ceil(g), 4.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::ceil`]: ../../std/primitive.f64.html#method.ceil +#[inline] +#[doc(alias = "ceiling")] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn ceil(x: f64) -> f64 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::ceilf64(x) } +} + +/// Experimental version of `round` in `core`. See [`f64::round`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let f = 3.3_f64; +/// let g = -3.3_f64; +/// let h = -3.7_f64; +/// let i = 3.5_f64; +/// let j = 4.5_f64; +/// +/// assert_eq!(f64::round(f), 3.0); +/// assert_eq!(f64::round(g), -3.0); +/// assert_eq!(f64::round(h), -4.0); +/// assert_eq!(f64::round(i), 4.0); +/// assert_eq!(f64::round(j), 5.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::round`]: ../../std/primitive.f64.html#method.round +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn round(x: f64) -> f64 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::roundf64(x) } +} + +/// Experimental version of `round_ties_even` in `core`. See [`f64::round_ties_even`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let f = 3.3_f64; +/// let g = -3.3_f64; +/// let h = 3.5_f64; +/// let i = 4.5_f64; +/// +/// assert_eq!(f64::round_ties_even(f), 3.0); +/// assert_eq!(f64::round_ties_even(g), -3.0); +/// assert_eq!(f64::round_ties_even(h), 4.0); +/// assert_eq!(f64::round_ties_even(i), 4.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::round_ties_even`]: ../../std/primitive.f64.html#method.round_ties_even +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn round_ties_even(x: f64) -> f64 { + intrinsics::round_ties_even_f64(x) +} + +/// Experimental version of `trunc` in `core`. See [`f64::trunc`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let f = 3.7_f64; +/// let g = 3.0_f64; +/// let h = -3.7_f64; +/// +/// assert_eq!(f64::trunc(f), 3.0); +/// assert_eq!(f64::trunc(g), 3.0); +/// assert_eq!(f64::trunc(h), -3.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::trunc`]: ../../std/primitive.f64.html#method.trunc +#[inline] +#[doc(alias = "truncate")] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn trunc(x: f64) -> f64 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::truncf64(x) } +} + +/// Experimental version of `fract` in `core`. See [`f64::fract`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let x = 3.6_f64; +/// let y = -3.6_f64; +/// let abs_difference_x = (f64::fract(x) - 0.6).abs(); +/// let abs_difference_y = (f64::fract(y) - (-0.6)).abs(); +/// +/// assert!(abs_difference_x < 1e-10); +/// assert!(abs_difference_y < 1e-10); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::fract`]: ../../std/primitive.f64.html#method.fract +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn fract(x: f64) -> f64 { + x - trunc(x) +} + +/// Experimental version of `mul_add` in `core`. See [`f64::mul_add`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let m = 10.0_f64; +/// let x = 4.0_f64; +/// let b = 60.0_f64; +/// +/// assert_eq!(f64::mul_add(m, x, b), 100.0); +/// assert_eq!(m * x + b, 100.0); +/// +/// let one_plus_eps = 1.0_f64 + f64::EPSILON; +/// let one_minus_eps = 1.0_f64 - f64::EPSILON; +/// let minus_one = -1.0_f64; +/// +/// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps. +/// assert_eq!(f64::mul_add(one_plus_eps, one_minus_eps, minus_one), -f64::EPSILON * f64::EPSILON); +/// // Different rounding with the non-fused multiply and add. +/// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::mul_add`]: ../../std/primitive.f64.html#method.mul_add +#[inline] +#[doc(alias = "fma", alias = "fusedMultiplyAdd")] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn mul_add(x: f64, a: f64, b: f64) -> f64 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::fmaf64(x, a, b) } +} + +/// Experimental version of `div_euclid` in `core`. See [`f64::div_euclid`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let a: f64 = 7.0; +/// let b = 4.0; +/// assert_eq!(f64::div_euclid(a, b), 1.0); // 7.0 > 4.0 * 1.0 +/// assert_eq!(f64::div_euclid(-a, b), -2.0); // -7.0 >= 4.0 * -2.0 +/// assert_eq!(f64::div_euclid(a, -b), -1.0); // 7.0 >= -4.0 * -1.0 +/// assert_eq!(f64::div_euclid(-a, -b), 2.0); // -7.0 >= -4.0 * 2.0 +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::div_euclid`]: ../../std/primitive.f64.html#method.div_euclid +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn div_euclid(x: f64, rhs: f64) -> f64 { + let q = trunc(x / rhs); + if x % rhs < 0.0 { + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; + } + q +} + +/// Experimental version of `rem_euclid` in `core`. See [`f64::rem_euclid`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let a: f64 = 7.0; +/// let b = 4.0; +/// assert_eq!(f64::rem_euclid(a, b), 3.0); +/// assert_eq!(f64::rem_euclid(-a, b), 1.0); +/// assert_eq!(f64::rem_euclid(a, -b), 3.0); +/// assert_eq!(f64::rem_euclid(-a, -b), 1.0); +/// // limitation due to round-off error +/// assert!(f64::rem_euclid(-f64::EPSILON, 3.0) != 0.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::rem_euclid`]: ../../std/primitive.f64.html#method.rem_euclid +#[inline] +#[doc(alias = "modulo", alias = "mod")] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn rem_euclid(x: f64, rhs: f64) -> f64 { + let r = x % rhs; + if r < 0.0 { r + rhs.abs() } else { r } +} + +/// Experimental version of `powi` in `core`. See [`f64::powi`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let x = 2.0_f64; +/// let abs_difference = (f64::powi(x, 2) - (x * x)).abs(); +/// assert!(abs_difference <= f64::EPSILON); +/// +/// assert_eq!(f64::powi(f64::NAN, 0), 1.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::powi`]: ../../std/primitive.f64.html#method.powi +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn powi(x: f64, n: i32) -> f64 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::powif64(x, n) } +} + +/// Experimental version of `sqrt` in `core`. See [`f64::sqrt`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let positive = 4.0_f64; +/// let negative = -4.0_f64; +/// let negative_zero = -0.0_f64; +/// +/// assert_eq!(f64::sqrt(positive), 2.0); +/// assert!(f64::sqrt(negative).is_nan()); +/// assert_eq!(f64::sqrt(negative_zero), negative_zero); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::sqrt`]: ../../std/primitive.f64.html#method.sqrt +#[inline] +#[doc(alias = "squareRoot")] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn sqrt(x: f64) -> f64 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::sqrtf64(x) } +} + +/// Experimental version of `abs_sub` in `core`. See [`f64::abs_sub`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let x = 3.0_f64; +/// let y = -3.0_f64; +/// +/// let abs_difference_x = (f64::abs_sub(x, 1.0) - 2.0).abs(); +/// let abs_difference_y = (f64::abs_sub(y, 1.0) - 0.0).abs(); +/// +/// assert!(abs_difference_x < 1e-10); +/// assert!(abs_difference_y < 1e-10); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::abs_sub`]: ../../std/primitive.f64.html#method.abs_sub +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[deprecated( + since = "1.10.0", + note = "you probably meant `(self - other).abs()`: \ + this operation is `(self - other).max(0.0)` \ + except that `abs_sub` also propagates NaNs (also \ + known as `fdim` in C). If you truly need the positive \ + difference, consider using that expression or the C function \ + `fdim`, depending on how you wish to handle NaN (please consider \ + filing an issue describing your use-case too)." +)] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn abs_sub(x: f64, other: f64) -> f64 { + libm::fdim(x, other) +} + +/// Experimental version of `cbrt` in `core`. See [`f64::cbrt`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let x = 8.0_f64; +/// +/// // x^(1/3) - 2 == 0 +/// let abs_difference = (f64::cbrt(x) - 2.0).abs(); +/// +/// assert!(abs_difference < 1e-10); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::cbrt`]: ../../std/primitive.f64.html#method.cbrt +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn cbrt(x: f64) -> f64 { + libm::cbrt(x) +} diff --git a/library/core/src/num/libm.rs b/library/core/src/num/libm.rs new file mode 100644 index 0000000000000..aeabb08723095 --- /dev/null +++ b/library/core/src/num/libm.rs @@ -0,0 +1,11 @@ +//! Bindings to math functions provided by the system `libm` or by the `libm` crate, exposed +//! via `compiler-builtins`. + +// SAFETY: These symbols have standard interfaces in C and are defined by `libm`, or are +// provided by `compiler-builtins` on unsupported platforms. +unsafe extern "C" { + pub(crate) safe fn cbrt(n: f64) -> f64; + pub(crate) safe fn cbrtf(n: f32) -> f32; + pub(crate) safe fn fdim(a: f64, b: f64) -> f64; + pub(crate) safe fn fdimf(a: f32, b: f32) -> f32; +} diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index ecc1c7bf9021d..3bb0c4c52fc6e 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -46,6 +46,7 @@ mod uint_macros; // import uint_impl! mod error; mod int_log10; mod int_sqrt; +pub(crate) mod libm; mod nonzero; mod overflow_panic; mod saturating; diff --git a/library/std/src/f128.rs b/library/std/src/f128.rs index 6b2ba2e714c9b..bb4acde48224c 100644 --- a/library/std/src/f128.rs +++ b/library/std/src/f128.rs @@ -14,365 +14,6 @@ use crate::sys::cmath; #[cfg(not(test))] impl f128 { - /// Returns the largest integer less than or equal to `self`. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f128_math)] { - /// - /// let f = 3.7_f128; - /// let g = 3.0_f128; - /// let h = -3.7_f128; - /// - /// assert_eq!(f.floor(), 3.0); - /// assert_eq!(g.floor(), 3.0); - /// assert_eq!(h.floor(), -4.0); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f128", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn floor(self) -> f128 { - unsafe { intrinsics::floorf128(self) } - } - - /// Returns the smallest integer greater than or equal to `self`. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f128_math)] { - /// - /// let f = 3.01_f128; - /// let g = 4.0_f128; - /// - /// assert_eq!(f.ceil(), 4.0); - /// assert_eq!(g.ceil(), 4.0); - /// # } - /// ``` - #[inline] - #[doc(alias = "ceiling")] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f128", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn ceil(self) -> f128 { - unsafe { intrinsics::ceilf128(self) } - } - - /// Returns the nearest integer to `self`. If a value is half-way between two - /// integers, round away from `0.0`. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f128_math)] { - /// - /// let f = 3.3_f128; - /// let g = -3.3_f128; - /// let h = -3.7_f128; - /// let i = 3.5_f128; - /// let j = 4.5_f128; - /// - /// assert_eq!(f.round(), 3.0); - /// assert_eq!(g.round(), -3.0); - /// assert_eq!(h.round(), -4.0); - /// assert_eq!(i.round(), 4.0); - /// assert_eq!(j.round(), 5.0); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f128", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn round(self) -> f128 { - unsafe { intrinsics::roundf128(self) } - } - - /// Returns the nearest integer to a number. Rounds half-way cases to the number - /// with an even least significant digit. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f128_math)] { - /// - /// let f = 3.3_f128; - /// let g = -3.3_f128; - /// let h = 3.5_f128; - /// let i = 4.5_f128; - /// - /// assert_eq!(f.round_ties_even(), 3.0); - /// assert_eq!(g.round_ties_even(), -3.0); - /// assert_eq!(h.round_ties_even(), 4.0); - /// assert_eq!(i.round_ties_even(), 4.0); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f128", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn round_ties_even(self) -> f128 { - intrinsics::round_ties_even_f128(self) - } - - /// Returns the integer part of `self`. - /// This means that non-integer numbers are always truncated towards zero. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f128_math)] { - /// - /// let f = 3.7_f128; - /// let g = 3.0_f128; - /// let h = -3.7_f128; - /// - /// assert_eq!(f.trunc(), 3.0); - /// assert_eq!(g.trunc(), 3.0); - /// assert_eq!(h.trunc(), -3.0); - /// # } - /// ``` - #[inline] - #[doc(alias = "truncate")] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f128", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn trunc(self) -> f128 { - unsafe { intrinsics::truncf128(self) } - } - - /// Returns the fractional part of `self`. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f128_math)] { - /// - /// let x = 3.6_f128; - /// let y = -3.6_f128; - /// let abs_difference_x = (x.fract() - 0.6).abs(); - /// let abs_difference_y = (y.fract() - (-0.6)).abs(); - /// - /// assert!(abs_difference_x <= f128::EPSILON); - /// assert!(abs_difference_y <= f128::EPSILON); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f128", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn fract(self) -> f128 { - self - self.trunc() - } - - /// Fused multiply-add. Computes `(self * a) + b` with only one rounding - /// error, yielding a more accurate result than an unfused multiply-add. - /// - /// Using `mul_add` *may* be more performant than an unfused multiply-add if - /// the target architecture has a dedicated `fma` CPU instruction. However, - /// this is not always true, and will be heavily dependant on designing - /// algorithms with specific target hardware in mind. - /// - /// # Precision - /// - /// The result of this operation is guaranteed to be the rounded - /// infinite-precision result. It is specified by IEEE 754 as - /// `fusedMultiplyAdd` and guaranteed not to change. - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f128_math)] { - /// - /// let m = 10.0_f128; - /// let x = 4.0_f128; - /// let b = 60.0_f128; - /// - /// assert_eq!(m.mul_add(x, b), 100.0); - /// assert_eq!(m * x + b, 100.0); - /// - /// let one_plus_eps = 1.0_f128 + f128::EPSILON; - /// let one_minus_eps = 1.0_f128 - f128::EPSILON; - /// let minus_one = -1.0_f128; - /// - /// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps. - /// assert_eq!(one_plus_eps.mul_add(one_minus_eps, minus_one), -f128::EPSILON * f128::EPSILON); - /// // Different rounding with the non-fused multiply and add. - /// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[doc(alias = "fmaf128", alias = "fusedMultiplyAdd")] - #[unstable(feature = "f128", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn mul_add(self, a: f128, b: f128) -> f128 { - unsafe { intrinsics::fmaf128(self, a, b) } - } - - /// Calculates Euclidean division, the matching method for `rem_euclid`. - /// - /// This computes the integer `n` such that - /// `self = n * rhs + self.rem_euclid(rhs)`. - /// In other words, the result is `self / rhs` rounded to the integer `n` - /// such that `self >= n * rhs`. - /// - /// # Precision - /// - /// The result of this operation is guaranteed to be the rounded - /// infinite-precision result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f128_math)] { - /// - /// let a: f128 = 7.0; - /// let b = 4.0; - /// assert_eq!(a.div_euclid(b), 1.0); // 7.0 > 4.0 * 1.0 - /// assert_eq!((-a).div_euclid(b), -2.0); // -7.0 >= 4.0 * -2.0 - /// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0 - /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0 - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f128", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn div_euclid(self, rhs: f128) -> f128 { - let q = (self / rhs).trunc(); - if self % rhs < 0.0 { - return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; - } - q - } - - /// Calculates the least nonnegative remainder of `self (mod rhs)`. - /// - /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in - /// most cases. However, due to a floating point round-off error it can - /// result in `r == rhs.abs()`, violating the mathematical definition, if - /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`. - /// This result is not an element of the function's codomain, but it is the - /// closest floating point number in the real numbers and thus fulfills the - /// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)` - /// approximately. - /// - /// # Precision - /// - /// The result of this operation is guaranteed to be the rounded - /// infinite-precision result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f128_math)] { - /// - /// let a: f128 = 7.0; - /// let b = 4.0; - /// assert_eq!(a.rem_euclid(b), 3.0); - /// assert_eq!((-a).rem_euclid(b), 1.0); - /// assert_eq!(a.rem_euclid(-b), 3.0); - /// assert_eq!((-a).rem_euclid(-b), 1.0); - /// // limitation due to round-off error - /// assert!((-f128::EPSILON).rem_euclid(3.0) != 0.0); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[doc(alias = "modulo", alias = "mod")] - #[unstable(feature = "f128", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn rem_euclid(self, rhs: f128) -> f128 { - let r = self % rhs; - if r < 0.0 { r + rhs.abs() } else { r } - } - - /// Raises a number to an integer power. - /// - /// Using this function is generally faster than using `powf`. - /// It might have a different sequence of rounding operations than `powf`, - /// so the results are not guaranteed to agree. - /// - /// # Unspecified precision - /// - /// The precision of this function is non-deterministic. This means it varies by platform, - /// Rust version, and can even differ within the same execution from one invocation to the next. - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f128_math)] { - /// - /// let x = 2.0_f128; - /// let abs_difference = (x.powi(2) - (x * x)).abs(); - /// assert!(abs_difference <= f128::EPSILON); - /// - /// assert_eq!(f128::powi(f128::NAN, 0), 1.0); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f128", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn powi(self, n: i32) -> f128 { - unsafe { intrinsics::powif128(self, n) } - } - /// Raises a number to a floating point power. /// /// # Unspecified precision @@ -405,43 +46,6 @@ impl f128 { unsafe { intrinsics::powf128(self, n) } } - /// Returns the square root of a number. - /// - /// Returns NaN if `self` is a negative number other than `-0.0`. - /// - /// # Precision - /// - /// The result of this operation is guaranteed to be the rounded - /// infinite-precision result. It is specified by IEEE 754 as `squareRoot` - /// and guaranteed not to change. - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f128_math)] { - /// - /// let positive = 4.0_f128; - /// let negative = -4.0_f128; - /// let negative_zero = -0.0_f128; - /// - /// assert_eq!(positive.sqrt(), 2.0); - /// assert!(negative.sqrt().is_nan()); - /// assert!(negative_zero.sqrt() == negative_zero); - /// # } - /// ``` - #[inline] - #[doc(alias = "squareRoot")] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f128", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn sqrt(self) -> f128 { - unsafe { intrinsics::sqrtf128(self) } - } - /// Returns `e^(self)`, (the exponential function). /// /// # Unspecified precision diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs index d6bc1d3118aed..4792eac1f9e28 100644 --- a/library/std/src/f16.rs +++ b/library/std/src/f16.rs @@ -14,365 +14,6 @@ use crate::sys::cmath; #[cfg(not(test))] impl f16 { - /// Returns the largest integer less than or equal to `self`. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f16_math)] { - /// - /// let f = 3.7_f16; - /// let g = 3.0_f16; - /// let h = -3.7_f16; - /// - /// assert_eq!(f.floor(), 3.0); - /// assert_eq!(g.floor(), 3.0); - /// assert_eq!(h.floor(), -4.0); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn floor(self) -> f16 { - unsafe { intrinsics::floorf16(self) } - } - - /// Returns the smallest integer greater than or equal to `self`. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f16_math)] { - /// - /// let f = 3.01_f16; - /// let g = 4.0_f16; - /// - /// assert_eq!(f.ceil(), 4.0); - /// assert_eq!(g.ceil(), 4.0); - /// # } - /// ``` - #[inline] - #[doc(alias = "ceiling")] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn ceil(self) -> f16 { - unsafe { intrinsics::ceilf16(self) } - } - - /// Returns the nearest integer to `self`. If a value is half-way between two - /// integers, round away from `0.0`. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f16_math)] { - /// - /// let f = 3.3_f16; - /// let g = -3.3_f16; - /// let h = -3.7_f16; - /// let i = 3.5_f16; - /// let j = 4.5_f16; - /// - /// assert_eq!(f.round(), 3.0); - /// assert_eq!(g.round(), -3.0); - /// assert_eq!(h.round(), -4.0); - /// assert_eq!(i.round(), 4.0); - /// assert_eq!(j.round(), 5.0); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn round(self) -> f16 { - unsafe { intrinsics::roundf16(self) } - } - - /// Returns the nearest integer to a number. Rounds half-way cases to the number - /// with an even least significant digit. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f16_math)] { - /// - /// let f = 3.3_f16; - /// let g = -3.3_f16; - /// let h = 3.5_f16; - /// let i = 4.5_f16; - /// - /// assert_eq!(f.round_ties_even(), 3.0); - /// assert_eq!(g.round_ties_even(), -3.0); - /// assert_eq!(h.round_ties_even(), 4.0); - /// assert_eq!(i.round_ties_even(), 4.0); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn round_ties_even(self) -> f16 { - intrinsics::round_ties_even_f16(self) - } - - /// Returns the integer part of `self`. - /// This means that non-integer numbers are always truncated towards zero. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f16_math)] { - /// - /// let f = 3.7_f16; - /// let g = 3.0_f16; - /// let h = -3.7_f16; - /// - /// assert_eq!(f.trunc(), 3.0); - /// assert_eq!(g.trunc(), 3.0); - /// assert_eq!(h.trunc(), -3.0); - /// # } - /// ``` - #[inline] - #[doc(alias = "truncate")] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn trunc(self) -> f16 { - unsafe { intrinsics::truncf16(self) } - } - - /// Returns the fractional part of `self`. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f16_math)] { - /// - /// let x = 3.6_f16; - /// let y = -3.6_f16; - /// let abs_difference_x = (x.fract() - 0.6).abs(); - /// let abs_difference_y = (y.fract() - (-0.6)).abs(); - /// - /// assert!(abs_difference_x <= f16::EPSILON); - /// assert!(abs_difference_y <= f16::EPSILON); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn fract(self) -> f16 { - self - self.trunc() - } - - /// Fused multiply-add. Computes `(self * a) + b` with only one rounding - /// error, yielding a more accurate result than an unfused multiply-add. - /// - /// Using `mul_add` *may* be more performant than an unfused multiply-add if - /// the target architecture has a dedicated `fma` CPU instruction. However, - /// this is not always true, and will be heavily dependant on designing - /// algorithms with specific target hardware in mind. - /// - /// # Precision - /// - /// The result of this operation is guaranteed to be the rounded - /// infinite-precision result. It is specified by IEEE 754 as - /// `fusedMultiplyAdd` and guaranteed not to change. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f16_math)] { - /// - /// let m = 10.0_f16; - /// let x = 4.0_f16; - /// let b = 60.0_f16; - /// - /// assert_eq!(m.mul_add(x, b), 100.0); - /// assert_eq!(m * x + b, 100.0); - /// - /// let one_plus_eps = 1.0_f16 + f16::EPSILON; - /// let one_minus_eps = 1.0_f16 - f16::EPSILON; - /// let minus_one = -1.0_f16; - /// - /// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps. - /// assert_eq!(one_plus_eps.mul_add(one_minus_eps, minus_one), -f16::EPSILON * f16::EPSILON); - /// // Different rounding with the non-fused multiply and add. - /// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[doc(alias = "fmaf16", alias = "fusedMultiplyAdd")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn mul_add(self, a: f16, b: f16) -> f16 { - unsafe { intrinsics::fmaf16(self, a, b) } - } - - /// Calculates Euclidean division, the matching method for `rem_euclid`. - /// - /// This computes the integer `n` such that - /// `self = n * rhs + self.rem_euclid(rhs)`. - /// In other words, the result is `self / rhs` rounded to the integer `n` - /// such that `self >= n * rhs`. - /// - /// # Precision - /// - /// The result of this operation is guaranteed to be the rounded - /// infinite-precision result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f16_math)] { - /// - /// let a: f16 = 7.0; - /// let b = 4.0; - /// assert_eq!(a.div_euclid(b), 1.0); // 7.0 > 4.0 * 1.0 - /// assert_eq!((-a).div_euclid(b), -2.0); // -7.0 >= 4.0 * -2.0 - /// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0 - /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0 - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn div_euclid(self, rhs: f16) -> f16 { - let q = (self / rhs).trunc(); - if self % rhs < 0.0 { - return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; - } - q - } - - /// Calculates the least nonnegative remainder of `self (mod rhs)`. - /// - /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in - /// most cases. However, due to a floating point round-off error it can - /// result in `r == rhs.abs()`, violating the mathematical definition, if - /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`. - /// This result is not an element of the function's codomain, but it is the - /// closest floating point number in the real numbers and thus fulfills the - /// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)` - /// approximately. - /// - /// # Precision - /// - /// The result of this operation is guaranteed to be the rounded - /// infinite-precision result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f16_math)] { - /// - /// let a: f16 = 7.0; - /// let b = 4.0; - /// assert_eq!(a.rem_euclid(b), 3.0); - /// assert_eq!((-a).rem_euclid(b), 1.0); - /// assert_eq!(a.rem_euclid(-b), 3.0); - /// assert_eq!((-a).rem_euclid(-b), 1.0); - /// // limitation due to round-off error - /// assert!((-f16::EPSILON).rem_euclid(3.0) != 0.0); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[doc(alias = "modulo", alias = "mod")] - #[unstable(feature = "f16", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn rem_euclid(self, rhs: f16) -> f16 { - let r = self % rhs; - if r < 0.0 { r + rhs.abs() } else { r } - } - - /// Raises a number to an integer power. - /// - /// Using this function is generally faster than using `powf`. - /// It might have a different sequence of rounding operations than `powf`, - /// so the results are not guaranteed to agree. - /// - /// # Unspecified precision - /// - /// The precision of this function is non-deterministic. This means it varies by platform, - /// Rust version, and can even differ within the same execution from one invocation to the next. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f16_math)] { - /// - /// let x = 2.0_f16; - /// let abs_difference = (x.powi(2) - (x * x)).abs(); - /// assert!(abs_difference <= f16::EPSILON); - /// - /// assert_eq!(f16::powi(f16::NAN, 0), 1.0); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn powi(self, n: i32) -> f16 { - unsafe { intrinsics::powif16(self, n) } - } - /// Raises a number to a floating point power. /// /// # Unspecified precision @@ -405,43 +46,6 @@ impl f16 { unsafe { intrinsics::powf16(self, n) } } - /// Returns the square root of a number. - /// - /// Returns NaN if `self` is a negative number other than `-0.0`. - /// - /// # Precision - /// - /// The result of this operation is guaranteed to be the rounded - /// infinite-precision result. It is specified by IEEE 754 as `squareRoot` - /// and guaranteed not to change. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f16_math)] { - /// - /// let positive = 4.0_f16; - /// let negative = -4.0_f16; - /// let negative_zero = -0.0_f16; - /// - /// assert_eq!(positive.sqrt(), 2.0); - /// assert!(negative.sqrt().is_nan()); - /// assert!(negative_zero.sqrt() == negative_zero); - /// # } - /// ``` - #[inline] - #[doc(alias = "squareRoot")] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn sqrt(self) -> f16 { - unsafe { intrinsics::sqrtf16(self) } - } - /// Returns `e^(self)`, (the exponential function). /// /// # Unspecified precision @@ -702,41 +306,6 @@ impl f16 { unsafe { intrinsics::log10f16(self) } } - /// Returns the cube root of a number. - /// - /// # Unspecified precision - /// - /// The precision of this function is non-deterministic. This means it varies by platform, - /// Rust version, and can even differ within the same execution from one invocation to the next. - /// - /// This function currently corresponds to the `cbrtf` from libc on Unix - /// and Windows. Note that this might change in the future. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f16_math)] { - /// - /// let x = 8.0f16; - /// - /// // x^(1/3) - 2 == 0 - /// let abs_difference = (x.cbrt() - 2.0).abs(); - /// - /// assert!(abs_difference <= f16::EPSILON); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn cbrt(self) -> f16 { - cmath::cbrtf(self as f32) as f16 - } - /// Compute the distance between the origin and a point (`x`, `y`) on the /// Euclidean plane. Equivalently, compute the length of the hypotenuse of a /// right-angle triangle with other sides having length `x.abs()` and diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index baf7002f3803c..94140d01d8b7e 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -46,7 +46,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn floor(self) -> f32 { - unsafe { intrinsics::floorf32(self) } + core::f32::floor(self) } /// Returns the smallest integer greater than or equal to `self`. @@ -68,7 +68,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn ceil(self) -> f32 { - unsafe { intrinsics::ceilf32(self) } + core::f32::ceil(self) } /// Returns the nearest integer to `self`. If a value is half-way between two @@ -96,7 +96,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn round(self) -> f32 { - unsafe { intrinsics::roundf32(self) } + core::f32::round(self) } /// Returns the nearest integer to a number. Rounds half-way cases to the number @@ -122,7 +122,7 @@ impl f32 { #[stable(feature = "round_ties_even", since = "1.77.0")] #[inline] pub fn round_ties_even(self) -> f32 { - intrinsics::round_ties_even_f32(self) + core::f32::round_ties_even(self) } /// Returns the integer part of `self`. @@ -147,7 +147,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn trunc(self) -> f32 { - unsafe { intrinsics::truncf32(self) } + core::f32::trunc(self) } /// Returns the fractional part of `self`. @@ -170,7 +170,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn fract(self) -> f32 { - self - self.trunc() + core::f32::fract(self) } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding @@ -212,7 +212,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn mul_add(self, a: f32, b: f32) -> f32 { - unsafe { intrinsics::fmaf32(self, a, b) } + core::f32::mul_add(self, a, b) } /// Calculates Euclidean division, the matching method for `rem_euclid`. @@ -242,11 +242,7 @@ impl f32 { #[inline] #[stable(feature = "euclidean_division", since = "1.38.0")] pub fn div_euclid(self, rhs: f32) -> f32 { - let q = (self / rhs).trunc(); - if self % rhs < 0.0 { - return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; - } - q + core::f32::div_euclid(self, rhs) } /// Calculates the least nonnegative remainder of `self (mod rhs)`. @@ -283,8 +279,7 @@ impl f32 { #[inline] #[stable(feature = "euclidean_division", since = "1.38.0")] pub fn rem_euclid(self, rhs: f32) -> f32 { - let r = self % rhs; - if r < 0.0 { r + rhs.abs() } else { r } + core::f32::rem_euclid(self, rhs) } /// Raises a number to an integer power. @@ -312,7 +307,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn powi(self, n: i32) -> f32 { - unsafe { intrinsics::powif32(self, n) } + core::f32::powi(self, n) } /// Raises a number to a floating point power. @@ -367,7 +362,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn sqrt(self) -> f32 { - unsafe { intrinsics::sqrtf32(self) } + core::f32::sqrt(self) } /// Returns `e^(self)`, (the exponential function). @@ -599,7 +594,8 @@ impl f32 { filing an issue describing your use-case too)." )] pub fn abs_sub(self, other: f32) -> f32 { - cmath::fdimf(self, other) + #[allow(deprecated)] + core::f32::abs_sub(self, other) } /// Returns the cube root of a number. @@ -626,7 +622,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cbrt(self) -> f32 { - cmath::cbrtf(self) + core::f32::cbrt(self) } /// Compute the distance between the origin and a point (`x`, `y`) on the diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index 84fd9bfb7b680..051061ae60555 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -46,7 +46,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn floor(self) -> f64 { - unsafe { intrinsics::floorf64(self) } + core::f64::floor(self) } /// Returns the smallest integer greater than or equal to `self`. @@ -68,7 +68,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn ceil(self) -> f64 { - unsafe { intrinsics::ceilf64(self) } + core::f64::ceil(self) } /// Returns the nearest integer to `self`. If a value is half-way between two @@ -96,7 +96,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn round(self) -> f64 { - unsafe { intrinsics::roundf64(self) } + core::f64::round(self) } /// Returns the nearest integer to a number. Rounds half-way cases to the number @@ -122,7 +122,7 @@ impl f64 { #[stable(feature = "round_ties_even", since = "1.77.0")] #[inline] pub fn round_ties_even(self) -> f64 { - intrinsics::round_ties_even_f64(self) + core::f64::round_ties_even(self) } /// Returns the integer part of `self`. @@ -147,7 +147,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn trunc(self) -> f64 { - unsafe { intrinsics::truncf64(self) } + core::f64::trunc(self) } /// Returns the fractional part of `self`. @@ -170,7 +170,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn fract(self) -> f64 { - self - self.trunc() + core::f64::fract(self) } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding @@ -212,7 +212,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn mul_add(self, a: f64, b: f64) -> f64 { - unsafe { intrinsics::fmaf64(self, a, b) } + core::f64::mul_add(self, a, b) } /// Calculates Euclidean division, the matching method for `rem_euclid`. @@ -242,11 +242,7 @@ impl f64 { #[inline] #[stable(feature = "euclidean_division", since = "1.38.0")] pub fn div_euclid(self, rhs: f64) -> f64 { - let q = (self / rhs).trunc(); - if self % rhs < 0.0 { - return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; - } - q + core::f64::div_euclid(self, rhs) } /// Calculates the least nonnegative remainder of `self (mod rhs)`. @@ -283,8 +279,7 @@ impl f64 { #[inline] #[stable(feature = "euclidean_division", since = "1.38.0")] pub fn rem_euclid(self, rhs: f64) -> f64 { - let r = self % rhs; - if r < 0.0 { r + rhs.abs() } else { r } + core::f64::rem_euclid(self, rhs) } /// Raises a number to an integer power. @@ -312,7 +307,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn powi(self, n: i32) -> f64 { - unsafe { intrinsics::powif64(self, n) } + core::f64::powi(self, n) } /// Raises a number to a floating point power. @@ -367,7 +362,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn sqrt(self) -> f64 { - unsafe { intrinsics::sqrtf64(self) } + core::f64::sqrt(self) } /// Returns `e^(self)`, (the exponential function). @@ -599,7 +594,8 @@ impl f64 { filing an issue describing your use-case too)." )] pub fn abs_sub(self, other: f64) -> f64 { - cmath::fdim(self, other) + #[allow(deprecated)] + core::f64::abs_sub(self, other) } /// Returns the cube root of a number. @@ -626,7 +622,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cbrt(self) -> f64 { - cmath::cbrt(self) + core::f64::cbrt(self) } /// Compute the distance between the origin and a point (`x`, `y`) on the diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 0bb40ee4b3177..5c1d2deb4811a 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -287,6 +287,7 @@ #![feature(cfi_encoding)] #![feature(char_max_len)] #![feature(concat_idents)] +#![feature(core_float_math)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] #![feature(doc_cfg)] diff --git a/library/std/src/sys/cmath.rs b/library/std/src/sys/cmath.rs index 668fd92853400..299ce1a6ff063 100644 --- a/library/std/src/sys/cmath.rs +++ b/library/std/src/sys/cmath.rs @@ -7,13 +7,9 @@ unsafe extern "C" { pub safe fn asin(n: f64) -> f64; pub safe fn atan(n: f64) -> f64; pub safe fn atan2(a: f64, b: f64) -> f64; - pub safe fn cbrt(n: f64) -> f64; - pub safe fn cbrtf(n: f32) -> f32; pub safe fn cosh(n: f64) -> f64; pub safe fn expm1(n: f64) -> f64; pub safe fn expm1f(n: f32) -> f32; - pub safe fn fdim(a: f64, b: f64) -> f64; - pub safe fn fdimf(a: f32, b: f32) -> f32; #[cfg_attr(target_env = "msvc", link_name = "_hypot")] pub safe fn hypot(x: f64, y: f64) -> f64; #[cfg_attr(target_env = "msvc", link_name = "_hypotf")] From 48f3e63f709ec4a19fa2bdce33893fdc45006e46 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 25 Feb 2025 06:09:33 +0000 Subject: [PATCH 2245/4206] Move float tests from std to core Many float-related tests in `std` only depend on `core`, so move the tests there. This also allows us to verify functions from `core_float_math`. Since the majority of test files need to be moved to `coretests`, move the files here without any cleanup; this is done in a followup commit. This makes git history slightly cleaner, but coretests will not build immediately after this commit. --- library/coretests/Cargo.toml | 11 +++++++++++ library/{std => coretests}/tests/floats/f128.rs | 0 library/{std => coretests}/tests/floats/f16.rs | 0 library/{std => coretests}/tests/floats/f32.rs | 0 library/{std => coretests}/tests/floats/f64.rs | 0 .../floats/lib.rs => coretests/tests/floats/mod.rs} | 0 library/coretests/tests/lib.rs | 1 + 7 files changed, 12 insertions(+) rename library/{std => coretests}/tests/floats/f128.rs (100%) rename library/{std => coretests}/tests/floats/f16.rs (100%) rename library/{std => coretests}/tests/floats/f32.rs (100%) rename library/{std => coretests}/tests/floats/f64.rs (100%) rename library/{std/tests/floats/lib.rs => coretests/tests/floats/mod.rs} (100%) diff --git a/library/coretests/Cargo.toml b/library/coretests/Cargo.toml index 7656388d24bee..e0ddcd466aea5 100644 --- a/library/coretests/Cargo.toml +++ b/library/coretests/Cargo.toml @@ -26,3 +26,14 @@ test = true [dev-dependencies] rand = { version = "0.9.0", default-features = false } rand_xorshift = { version = "0.4.0", default-features = false } + +[lints.rust.unexpected_cfgs] +level = "warn" +check-cfg = [ + # Internal features aren't marked known config by default, we use these to + # gate tests. + 'cfg(target_has_reliable_f16)', + 'cfg(target_has_reliable_f16_math)', + 'cfg(target_has_reliable_f128)', + 'cfg(target_has_reliable_f128_math)', +] diff --git a/library/std/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs similarity index 100% rename from library/std/tests/floats/f128.rs rename to library/coretests/tests/floats/f128.rs diff --git a/library/std/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs similarity index 100% rename from library/std/tests/floats/f16.rs rename to library/coretests/tests/floats/f16.rs diff --git a/library/std/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs similarity index 100% rename from library/std/tests/floats/f32.rs rename to library/coretests/tests/floats/f32.rs diff --git a/library/std/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs similarity index 100% rename from library/std/tests/floats/f64.rs rename to library/coretests/tests/floats/f64.rs diff --git a/library/std/tests/floats/lib.rs b/library/coretests/tests/floats/mod.rs similarity index 100% rename from library/std/tests/floats/lib.rs rename to library/coretests/tests/floats/mod.rs diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 0575375cf4f08..acea0b2a0356f 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -144,6 +144,7 @@ mod cmp; mod const_ptr; mod convert; mod ffi; +mod floats; mod fmt; mod future; mod hash; From 7b45c59d40bf9136916eb487183999bfda18c99c Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 14 May 2025 00:45:28 +0200 Subject: [PATCH 2246/4206] Add match guard chains test for absence of compilation error based on tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs --- .../temporary-early-drop.rs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 tests/ui/rfcs/rfc-2294-if-let-guard/temporary-early-drop.rs diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/temporary-early-drop.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/temporary-early-drop.rs new file mode 100644 index 0000000000000..9edbc3243c716 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/temporary-early-drop.rs @@ -0,0 +1,29 @@ +// issue-103476 +//@ revisions: edition2021 edition2024 +//@ [edition2021] edition: 2021 +//@ [edition2024] edition: 2024 +//@ check-pass + +#![feature(if_let_guard)] +#![allow(irrefutable_let_patterns)] + +struct Pd; + +impl Pd { + fn it(&self) -> It { + todo!() + } +} + +pub struct It<'a>(Box>); + +trait Tr<'a> {} + +fn f(m: Option) { + match () { + () if let Some(n) = m && let it = n.it() => {} + _ => {} + } +} + +fn main() {} From b9f4350fbc8198f4805557d9b0c5367ebc2390d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20=C5=81owicki?= Date: Tue, 13 May 2025 22:00:56 -0400 Subject: [PATCH 2247/4206] fix doc for UnixStream --- library/std/src/os/unix/net/stream.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index 1cab04a454dc0..1bd3bab5e3738 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -307,11 +307,11 @@ impl UnixStream { /// /// ```no_run /// use std::io; - /// use std::net::UdpSocket; + /// use std::os::unix::net::UnixStream; /// use std::time::Duration; /// /// fn main() -> std::io::Result<()> { - /// let socket = UdpSocket::bind("127.0.0.1:34254")?; + /// let socket = UnixStream::connect("/tmp/sock")?; /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); /// let err = result.unwrap_err(); /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); From 85efae7302e9249bb29a6098f342ab176d0d63aa Mon Sep 17 00:00:00 2001 From: ismailarilik Date: Mon, 5 May 2025 19:06:15 +0300 Subject: [PATCH 2248/4206] Handle `rustc_query_system` cases of `rustc::potential_query_instability` lint --- compiler/rustc_query_system/src/dep_graph/graph.rs | 2 ++ compiler/rustc_query_system/src/dep_graph/serialized.rs | 2 ++ compiler/rustc_query_system/src/lib.rs | 2 +- compiler/rustc_query_system/src/query/job.rs | 4 ++++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 3ae56cef2c421..d4217e0aa5499 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -1433,6 +1433,8 @@ fn panic_on_forbidden_read(data: &DepGraphData, dep_node_index: DepN && let Some(nodes) = &data.current.nodes_in_current_session { // Try to find it among the nodes allocated so far in this session + // This is OK, there's only ever one node result possible so this is deterministic. + #[allow(rustc::potential_query_instability)] if let Some((node, _)) = nodes.lock().iter().find(|&(_, index)| *index == dep_node_index) { dep_node = Some(*node); } diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index f1b609a3ca906..79b99c52d0c01 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -784,6 +784,8 @@ impl EncoderState { ) { if let Some(record_stats) = &self.stats { let record_stats = record_stats.lock(); + // `stats` is sorted below so we can allow this lint here. + #[allow(rustc::potential_query_instability)] let mut stats: Vec<_> = record_stats.values().collect(); stats.sort_by_key(|s| -(s.node_counter as i64)); diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index eba7378b475ef..d36cb6f0e5b17 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -1,5 +1,5 @@ // tidy-alphabetical-start -#![allow(rustc::potential_query_instability, internal_features)] +#![allow(internal_features)] #![feature(assert_matches)] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 6321abc5087f5..1e79bd461d2a4 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -510,6 +510,10 @@ pub fn break_query_cycles( registry: &rayon_core::Registry, ) { let mut wakelist = Vec::new(); + // It is OK per the comments: + // - https://github.com/rust-lang/rust/pull/131200#issuecomment-2798854932 + // - https://github.com/rust-lang/rust/pull/131200#issuecomment-2798866392 + #[allow(rustc::potential_query_instability)] let mut jobs: Vec = query_map.keys().cloned().collect(); let mut found_cycle = false; From c610177558bc62c40bacc105c7eb4130ea66db72 Mon Sep 17 00:00:00 2001 From: Mathis Bottinelli Date: Wed, 14 May 2025 09:02:22 +0200 Subject: [PATCH 2249/4206] MaybeUninit::write: fix doc --- library/core/src/mem/maybe_uninit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index d0be82adb6b16..63a479ed8dd4e 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -391,7 +391,7 @@ impl MaybeUninit { /// For your convenience, this also returns a mutable reference to the /// (now safely initialized) contents of `self`. /// - /// As the content is stored inside a `MaybeUninit`, the destructor is not + /// As the content is stored inside a `ManuallyDrop`, the destructor is not /// run for the inner data if the MaybeUninit leaves scope without a call to /// [`assume_init`], [`assume_init_drop`], or similar. Code that receives /// the mutable reference returned by this function needs to keep this in From dca57c6714a03fe7c7b71604c51f9b4c06ae699a Mon Sep 17 00:00:00 2001 From: xizheyin Date: Wed, 14 May 2025 15:08:17 +0800 Subject: [PATCH 2250/4206] Add ui test suggest-box-for-expr-field-issue-139631 Signed-off-by: xizheyin --- ...suggest-box-for-expr-field-issue-139631.rs | 14 ++++++ ...est-box-for-expr-field-issue-139631.stderr | 44 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 tests/ui/box/suggest-box-for-expr-field-issue-139631.rs create mode 100644 tests/ui/box/suggest-box-for-expr-field-issue-139631.stderr diff --git a/tests/ui/box/suggest-box-for-expr-field-issue-139631.rs b/tests/ui/box/suggest-box-for-expr-field-issue-139631.rs new file mode 100644 index 0000000000000..8d040da1ef7cc --- /dev/null +++ b/tests/ui/box/suggest-box-for-expr-field-issue-139631.rs @@ -0,0 +1,14 @@ +struct X { + a: Box, +} + +struct Y { + y: Box, +} + +fn main() { + let a = 8; + let v2 = X { a }; //~ ERROR mismatched types [E0308] + let v3 = Y { y: a }; //~ ERROR mismatched types [E0308] + let v4 = Y { a }; //~ ERROR struct `Y` has no field named `a` [E0560] +} diff --git a/tests/ui/box/suggest-box-for-expr-field-issue-139631.stderr b/tests/ui/box/suggest-box-for-expr-field-issue-139631.stderr new file mode 100644 index 0000000000000..167e892d11a82 --- /dev/null +++ b/tests/ui/box/suggest-box-for-expr-field-issue-139631.stderr @@ -0,0 +1,44 @@ +error[E0308]: mismatched types + --> $DIR/suggest-box-for-expr-field-issue-139631.rs:11:18 + | +LL | let v2 = X { a }; + | ^ expected `Box`, found integer + | + = note: expected struct `Box` + found type `{integer}` + = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html +help: store this in the heap by calling `Box::new` + | +LL | let v2 = X { Box::new(a) }; + | +++++++++ + + +error[E0308]: mismatched types + --> $DIR/suggest-box-for-expr-field-issue-139631.rs:12:21 + | +LL | let v3 = Y { y: a }; + | ^ expected `Box`, found integer + | + = note: expected struct `Box` + found type `{integer}` + = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html +help: store this in the heap by calling `Box::new` + | +LL | let v3 = Y { y: Box::new(a) }; + | +++++++++ + + +error[E0560]: struct `Y` has no field named `a` + --> $DIR/suggest-box-for-expr-field-issue-139631.rs:13:18 + | +LL | let v4 = Y { a }; + | ^ unknown field + | +help: a field with a similar name exists + | +LL - let v4 = Y { a }; +LL + let v4 = Y { y }; + | + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0308, E0560. +For more information about an error, try `rustc --explain E0308`. From 32be4599090d62cd7f70767e27c289583fd6501d Mon Sep 17 00:00:00 2001 From: xizheyin Date: Wed, 14 May 2025 15:14:07 +0800 Subject: [PATCH 2251/4206] Suggest replace `f` with `f: Box` when expr field is short hand Signed-off-by: xizheyin --- compiler/rustc_hir_typeck/src/errors.rs | 12 ++++++++++++ compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 9 +++++++++ .../suggest-box-for-expr-field-issue-139631.stderr | 4 ++-- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 732795535087e..06103fe1c91bc 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -680,6 +680,18 @@ pub(crate) enum SuggestBoxing { hir_typeck_suggest_boxing_when_appropriate, applicability = "machine-applicable" )] + ExprFieldShorthand { + #[suggestion_part(code = "{ident}: Box::new(")] + start: Span, + #[suggestion_part(code = ")")] + end: Span, + ident: Ident, + }, + #[note(hir_typeck_suggest_boxing_note)] + #[multipart_suggestion( + hir_typeck_suggest_boxing_when_appropriate, + applicability = "machine-applicable" + )] Other { #[suggestion_part(code = "Box::new(")] start: Span, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 91eb1989864ff..251801f479efb 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -585,6 +585,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { errors::SuggestBoxing::AsyncBody } + _ if let Node::ExprField(expr_field) = self.tcx.parent_hir_node(hir_id) + && expr_field.is_shorthand => + { + errors::SuggestBoxing::ExprFieldShorthand { + start: span.shrink_to_lo(), + end: span.shrink_to_hi(), + ident: expr_field.ident, + } + } _ => errors::SuggestBoxing::Other { start: span.shrink_to_lo(), end: span.shrink_to_hi(), diff --git a/tests/ui/box/suggest-box-for-expr-field-issue-139631.stderr b/tests/ui/box/suggest-box-for-expr-field-issue-139631.stderr index 167e892d11a82..01bd0523a162d 100644 --- a/tests/ui/box/suggest-box-for-expr-field-issue-139631.stderr +++ b/tests/ui/box/suggest-box-for-expr-field-issue-139631.stderr @@ -9,8 +9,8 @@ LL | let v2 = X { a }; = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html help: store this in the heap by calling `Box::new` | -LL | let v2 = X { Box::new(a) }; - | +++++++++ + +LL | let v2 = X { a: Box::new(a) }; + | ++++++++++++ + error[E0308]: mismatched types --> $DIR/suggest-box-for-expr-field-issue-139631.rs:12:21 From e0421f8f61cbc6e84c3cabf22999424f4eb0e9f4 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 14 May 2025 07:31:56 +0000 Subject: [PATCH 2252/4206] replace `cc_detect::cc2ar` with `cc::try_get_archiver` Signed-off-by: onur-ozkan --- src/bootstrap/src/utils/cc_detect.rs | 34 +------ src/bootstrap/src/utils/cc_detect/tests.rs | 113 --------------------- 2 files changed, 2 insertions(+), 145 deletions(-) diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index ceac24d4315c7..5c9e30706ee0d 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -22,43 +22,13 @@ //! everything. use std::collections::HashSet; +use std::iter; use std::path::{Path, PathBuf}; -use std::{env, iter}; use crate::core::config::TargetSelection; use crate::utils::exec::{BootstrapCommand, command}; use crate::{Build, CLang, GitRepo}; -/// Finds archiver tool for the given target if possible. -/// FIXME(onur-ozkan): This logic should be replaced by calling into the `cc` crate. -fn cc2ar(cc: &Path, target: TargetSelection, default_ar: PathBuf) -> Option { - if let Some(ar) = env::var_os(format!("AR_{}", target.triple.replace('-', "_"))) { - Some(PathBuf::from(ar)) - } else if let Some(ar) = env::var_os("AR") { - Some(PathBuf::from(ar)) - } else if target.is_msvc() { - None - } else if target.contains("musl") || target.contains("openbsd") { - Some(PathBuf::from("ar")) - } else if target.contains("vxworks") { - Some(PathBuf::from("wr-ar")) - } else if target.contains("-nto-") { - if target.starts_with("i586") { - Some(PathBuf::from("ntox86-ar")) - } else if target.starts_with("aarch64") { - Some(PathBuf::from("ntoaarch64-ar")) - } else if target.starts_with("x86_64") { - Some(PathBuf::from("ntox86_64-ar")) - } else { - panic!("Unknown architecture, cannot determine archiver for Neutrino QNX"); - } - } else if target.contains("android") || target.contains("-wasi") { - Some(cc.parent().unwrap().join(PathBuf::from("llvm-ar"))) - } else { - Some(default_ar) - } -} - /// Creates and configures a new [`cc::Build`] instance for the given target. fn new_cc_build(build: &Build, target: TargetSelection) -> cc::Build { let mut cfg = cc::Build::new(); @@ -140,7 +110,7 @@ pub fn find_target(build: &Build, target: TargetSelection) { let ar = if let ar @ Some(..) = config.and_then(|c| c.ar.clone()) { ar } else { - cc2ar(compiler.path(), target, PathBuf::from(cfg.get_archiver().get_program())) + cfg.try_get_archiver().map(|c| PathBuf::from(c.get_program())).ok() }; build.cc.borrow_mut().insert(target, compiler.clone()); diff --git a/src/bootstrap/src/utils/cc_detect/tests.rs b/src/bootstrap/src/utils/cc_detect/tests.rs index 43d61ce02c5af..225fb7619b55a 100644 --- a/src/bootstrap/src/utils/cc_detect/tests.rs +++ b/src/bootstrap/src/utils/cc_detect/tests.rs @@ -5,119 +5,6 @@ use super::*; use crate::core::config::{Target, TargetSelection}; use crate::{Build, Config, Flags}; -#[test] -fn test_cc2ar_env_specific() { - let triple = "x86_64-unknown-linux-gnu"; - let key = "AR_x86_64_unknown_linux_gnu"; - // SAFETY: bootstrap tests run on a single thread - unsafe { env::set_var(key, "custom-ar") }; - let target = TargetSelection::from_user(triple); - let cc = Path::new("/usr/bin/clang"); - let default_ar = PathBuf::from("default-ar"); - let result = cc2ar(cc, target, default_ar); - // SAFETY: bootstrap tests run on a single thread - unsafe { env::remove_var(key) }; - assert_eq!(result, Some(PathBuf::from("custom-ar"))); -} - -#[test] -fn test_cc2ar_musl() { - let triple = "x86_64-unknown-linux-musl"; - // SAFETY: bootstrap tests run on a single thread - unsafe { env::remove_var("AR_x86_64_unknown_linux_musl") }; - // SAFETY: bootstrap tests run on a single thread - unsafe { env::remove_var("AR") }; - let target = TargetSelection::from_user(triple); - let cc = Path::new("/usr/bin/clang"); - let default_ar = PathBuf::from("default-ar"); - let result = cc2ar(cc, target, default_ar); - assert_eq!(result, Some(PathBuf::from("ar"))); -} - -#[test] -fn test_cc2ar_openbsd() { - let triple = "x86_64-unknown-openbsd"; - // SAFETY: bootstrap tests run on a single thread - unsafe { env::remove_var("AR_x86_64_unknown_openbsd") }; - // SAFETY: bootstrap tests run on a single thread - unsafe { env::remove_var("AR") }; - let target = TargetSelection::from_user(triple); - let cc = Path::new("/usr/bin/cc"); - let default_ar = PathBuf::from("default-ar"); - let result = cc2ar(cc, target, default_ar); - assert_eq!(result, Some(PathBuf::from("ar"))); -} - -#[test] -fn test_cc2ar_vxworks() { - let triple = "armv7-wrs-vxworks"; - // SAFETY: bootstrap tests run on a single thread - unsafe { env::remove_var("AR_armv7_wrs_vxworks") }; - // SAFETY: bootstrap tests run on a single thread - unsafe { env::remove_var("AR") }; - let target = TargetSelection::from_user(triple); - let cc = Path::new("/usr/bin/clang"); - let default_ar = PathBuf::from("default-ar"); - let result = cc2ar(cc, target, default_ar); - assert_eq!(result, Some(PathBuf::from("wr-ar"))); -} - -#[test] -fn test_cc2ar_nto_i586() { - let triple = "i586-unknown-nto-something"; - // SAFETY: bootstrap tests run on a single thread - unsafe { env::remove_var("AR_i586_unknown_nto_something") }; - // SAFETY: bootstrap tests run on a single thread - unsafe { env::remove_var("AR") }; - let target = TargetSelection::from_user(triple); - let cc = Path::new("/usr/bin/clang"); - let default_ar = PathBuf::from("default-ar"); - let result = cc2ar(cc, target, default_ar); - assert_eq!(result, Some(PathBuf::from("ntox86-ar"))); -} - -#[test] -fn test_cc2ar_nto_aarch64() { - let triple = "aarch64-unknown-nto-something"; - // SAFETY: bootstrap tests run on a single thread - unsafe { env::remove_var("AR_aarch64_unknown_nto_something") }; - // SAFETY: bootstrap tests run on a single thread - unsafe { env::remove_var("AR") }; - let target = TargetSelection::from_user(triple); - let cc = Path::new("/usr/bin/clang"); - let default_ar = PathBuf::from("default-ar"); - let result = cc2ar(cc, target, default_ar); - assert_eq!(result, Some(PathBuf::from("ntoaarch64-ar"))); -} - -#[test] -fn test_cc2ar_nto_x86_64() { - let triple = "x86_64-unknown-nto-something"; - // SAFETY: bootstrap tests run on a single thread - unsafe { env::remove_var("AR_x86_64_unknown_nto_something") }; - // SAFETY: bootstrap tests run on a single thread - unsafe { env::remove_var("AR") }; - let target = TargetSelection::from_user(triple); - let cc = Path::new("/usr/bin/clang"); - let default_ar = PathBuf::from("default-ar"); - let result = cc2ar(cc, target, default_ar); - assert_eq!(result, Some(PathBuf::from("ntox86_64-ar"))); -} - -#[test] -#[should_panic(expected = "Unknown architecture, cannot determine archiver for Neutrino QNX")] -fn test_cc2ar_nto_unknown() { - let triple = "powerpc-unknown-nto-something"; - // SAFETY: bootstrap tests run on a single thread - unsafe { env::remove_var("AR_powerpc_unknown_nto_something") }; - // SAFETY: bootstrap tests run on a single thread - unsafe { env::remove_var("AR") }; - let target = TargetSelection::from_user(triple); - let cc = Path::new("/usr/bin/clang"); - let default_ar = PathBuf::from("default-ar"); - let _ = cc2ar(cc, target, default_ar); -} - #[test] fn test_ndk_compiler_c() { let ndk_path = PathBuf::from("/ndk"); From 7b1ba425e7b29e81b0d9d2e8354fc0164b134de3 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Tue, 13 May 2025 21:22:45 +0200 Subject: [PATCH 2253/4206] Add `Ipv4Addr` and `Ipv6Addr` diagnostic items They will be used in Clippy to detect runtime parsing of known-valid IP addresses. --- compiler/rustc_span/src/symbol.rs | 2 ++ library/core/src/net/ip_addr.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 3a95447308a90..efae6250b0720 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -280,6 +280,8 @@ symbols! { IoSeek, IoWrite, IpAddr, + Ipv4Addr, + Ipv6Addr, IrTyKind, Is, Item, diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index 2f027be692860..aaa68e8d7d1ad 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -68,6 +68,7 @@ pub enum IpAddr { /// assert!("0000000.0.0.0".parse::().is_err()); // first octet is a zero in octal /// assert!("0xcb.0x0.0x71.0x00".parse::().is_err()); // all octets are in hex /// ``` +#[rustc_diagnostic_item = "Ipv4Addr"] #[derive(Copy, Clone, PartialEq, Eq)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Ipv4Addr { @@ -160,6 +161,7 @@ impl Hash for Ipv4Addr { /// assert_eq!("::1".parse(), Ok(localhost)); /// assert_eq!(localhost.is_loopback(), true); /// ``` +#[rustc_diagnostic_item = "Ipv6Addr"] #[derive(Copy, Clone, PartialEq, Eq)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Ipv6Addr { From e011c43bcf3bc01e04738b47b7d8dc9affda8659 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 9 May 2025 15:36:22 +0000 Subject: [PATCH 2254/4206] Merge mir query analysis invocations The reasons I'm doing it is that * merging those blocks allows for more parallelism as you don't run parallel blocks in sequence * merging blocks allows merging analysis queries shrinking the dep graph * should allow us to do more early aborting in case of errors and/or moving query calls from the analysis query into others that allow early aborting the others (and doing more tainting and stuff) --- compiler/rustc_interface/src/passes.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 7ed32d559c3a6..6932b09f0cdac 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1002,10 +1002,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { if !tcx.is_typeck_child(def_id.to_def_id()) { tcx.ensure_ok().mir_borrowck(def_id) } - }); - }); - sess.time("MIR_effect_checking", || { - tcx.par_hir_body_owners(|def_id| { tcx.ensure_ok().has_ffi_unwind_calls(def_id); // If we need to codegen, ensure that we emit all errors from From e1f1878da550408e800742217881730c2b06d1ec Mon Sep 17 00:00:00 2001 From: B I Mohammed Abbas Date: Wed, 14 May 2025 13:52:04 +0530 Subject: [PATCH 2255/4206] Fix set_name for vxworks. Length of name should be truncated to VX_TASK_RENAME_LENGTH-1 --- library/std/src/sys/pal/unix/thread.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index afda7c65e1084..d8b189413f4a3 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -222,16 +222,8 @@ impl Thread { #[cfg(target_os = "vxworks")] pub fn set_name(name: &CStr) { - // FIXME(libc): adding real STATUS, ERROR type eventually. - unsafe extern "C" { - fn taskNameSet(task_id: libc::TASK_ID, task_name: *mut libc::c_char) -> libc::c_int; - } - - // VX_TASK_NAME_LEN is 31 in VxWorks 7. - const VX_TASK_NAME_LEN: usize = 31; - - let mut name = truncate_cstr::<{ VX_TASK_NAME_LEN }>(name); - let res = unsafe { taskNameSet(libc::taskIdSelf(), name.as_mut_ptr()) }; + let mut name = truncate_cstr::<{ libc::VX_TASK_RENAME_LENGTH - 1 }>(name); + let res = unsafe { libc::taskNameSet(libc::taskIdSelf(), name.as_mut_ptr()) }; debug_assert_eq!(res, libc::OK); } From 544c8ce535c834d726b5dd252046aa5eeb1bf5ec Mon Sep 17 00:00:00 2001 From: B I Mohammed Abbas Date: Wed, 14 May 2025 13:52:23 +0530 Subject: [PATCH 2256/4206] Fix settimes for vxworks --- library/std/src/sys/fs/unix.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 863358596c199..a3e520fdeef43 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -1498,11 +1498,10 @@ impl File { None => Ok(libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT as _ }), }; cfg_if::cfg_if! { - if #[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "vxworks", target_os = "nuttx"))] { + if #[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "nuttx"))] { // Redox doesn't appear to support `UTIME_OMIT`. // ESP-IDF and HorizonOS do not support `futimens` at all and the behavior for those OS is therefore // the same as for Redox. - // `futimens` and `UTIME_OMIT` are a work in progress for vxworks. let _ = times; Err(io::const_error!( io::ErrorKind::Unsupported, From 488e4e53d25b01b01e09fbf8b2745fd32db2c6ab Mon Sep 17 00:00:00 2001 From: SLUCHABLUB <81807027+SLUCHABLUB@users.noreply.github.com> Date: Wed, 14 May 2025 10:49:01 +0200 Subject: [PATCH 2257/4206] Add the `allow_exact_repetitions` option to the `module_name_repetitions` lint. --- CHANGELOG.md | 1 + book/src/lint_configuration.md | 10 +++++++++ clippy_config/src/conf.rs | 3 +++ clippy_lints/src/item_name_repetitions.rs | 22 ++++++++++++++----- .../allow_exact_repetitions/clippy.toml | 1 + .../item_name_repetitions.rs | 13 +++++++++++ .../item_name_repetitions.stderr | 11 ++++++++++ .../toml_unknown_key/conf_unknown_key.stderr | 3 +++ 8 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 tests/ui-toml/item_name_repetitions/allow_exact_repetitions/clippy.toml create mode 100644 tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.rs create mode 100644 tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index d707afb019972..28147dfbea3e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6483,6 +6483,7 @@ Released 2018-09-13 [`accept-comment-above-statement`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-statement [`allow-comparison-to-zero`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-comparison-to-zero [`allow-dbg-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-dbg-in-tests +[`allow-exact-repetitions`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-exact-repetitions [`allow-expect-in-consts`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-expect-in-consts [`allow-expect-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-expect-in-tests [`allow-indexing-slicing-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-indexing-slicing-in-tests diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 282d892951cfc..0db4182dbcdbd 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -71,6 +71,16 @@ Whether `dbg!` should be allowed in test functions or `#[cfg(test)]` * [`dbg_macro`](https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro) +## `allow-exact-repetitions` +Whether an item should be allowed to have the same name as its containing module + +**Default Value:** `true` + +--- +**Affected lints:** +* [`module_name_repetitions`](https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions) + + ## `allow-expect-in-consts` Whether `expect` should be allowed in code always evaluated at compile time diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 8a1d38ed600eb..ad0aea39d41a2 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -360,6 +360,9 @@ define_Conf! { /// Whether `dbg!` should be allowed in test functions or `#[cfg(test)]` #[lints(dbg_macro)] allow_dbg_in_tests: bool = false, + /// Whether an item should be allowed to have the same name as its containing module + #[lints(module_name_repetitions)] + allow_exact_repetitions: bool = true, /// Whether `expect` should be allowed in code always evaluated at compile time #[lints(expect_used)] allow_expect_in_consts: bool = true, diff --git a/clippy_lints/src/item_name_repetitions.rs b/clippy_lints/src/item_name_repetitions.rs index 30f61af29e59e..3d4dcd0207023 100644 --- a/clippy_lints/src/item_name_repetitions.rs +++ b/clippy_lints/src/item_name_repetitions.rs @@ -162,6 +162,7 @@ pub struct ItemNameRepetitions { enum_threshold: u64, struct_threshold: u64, avoid_breaking_exported_api: bool, + allow_exact_repetitions: bool, allow_private_module_inception: bool, allowed_prefixes: FxHashSet, } @@ -173,6 +174,7 @@ impl ItemNameRepetitions { enum_threshold: conf.enum_variant_name_threshold, struct_threshold: conf.struct_field_name_threshold, avoid_breaking_exported_api: conf.avoid_breaking_exported_api, + allow_exact_repetitions: conf.allow_exact_repetitions, allow_private_module_inception: conf.allow_private_module_inception, allowed_prefixes: conf.allowed_prefixes.iter().map(|s| to_camel_case(s)).collect(), } @@ -486,11 +488,21 @@ impl LateLintPass<'_> for ItemNameRepetitions { } // The `module_name_repetitions` lint should only trigger if the item has the module in its - // name. Having the same name is accepted. - if cx.tcx.visibility(item.owner_id).is_public() - && cx.tcx.visibility(mod_owner_id.def_id).is_public() - && item_camel.len() > mod_camel.len() - { + // name. Having the same name is only accepted if `allow_exact_repetition` is set to `true`. + + let both_are_public = + cx.tcx.visibility(item.owner_id).is_public() && cx.tcx.visibility(mod_owner_id.def_id).is_public(); + + if both_are_public && !self.allow_exact_repetitions && item_camel == *mod_camel { + span_lint( + cx, + MODULE_NAME_REPETITIONS, + ident.span, + "item name is the same as its containing module's name", + ); + } + + if both_are_public && item_camel.len() > mod_camel.len() { let matching = count_match_start(mod_camel, &item_camel); let rmatching = count_match_end(mod_camel, &item_camel); let nchars = mod_camel.chars().count(); diff --git a/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/clippy.toml b/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/clippy.toml new file mode 100644 index 0000000000000..3ed7cedbd147d --- /dev/null +++ b/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/clippy.toml @@ -0,0 +1 @@ +allow-exact-repetitions = false diff --git a/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.rs b/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.rs new file mode 100644 index 0000000000000..20603766624c7 --- /dev/null +++ b/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.rs @@ -0,0 +1,13 @@ +#![warn(clippy::module_name_repetitions)] +#![allow(dead_code)] + +pub mod foo { + // this line should produce a warning: + pub fn foo() {} + //~^ module_name_repetitions + + // but this line shouldn't + pub fn to_foo() {} +} + +fn main() {} diff --git a/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.stderr b/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.stderr new file mode 100644 index 0000000000000..8e6f726d02c01 --- /dev/null +++ b/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.stderr @@ -0,0 +1,11 @@ +error: item name is the same as its containing module's name + --> tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.rs:6:12 + | +LL | pub fn foo() {} + | ^^^ + | + = note: `-D clippy::module-name-repetitions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::module_name_repetitions)]` + +error: aborting due to 1 previous error + diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 0a36cd3cf26d9..6ee77ebd8ece2 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -5,6 +5,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect accept-comment-above-statement allow-comparison-to-zero allow-dbg-in-tests + allow-exact-repetitions allow-expect-in-consts allow-expect-in-tests allow-indexing-slicing-in-tests @@ -98,6 +99,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect accept-comment-above-statement allow-comparison-to-zero allow-dbg-in-tests + allow-exact-repetitions allow-expect-in-consts allow-expect-in-tests allow-indexing-slicing-in-tests @@ -191,6 +193,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni accept-comment-above-statement allow-comparison-to-zero allow-dbg-in-tests + allow-exact-repetitions allow-expect-in-consts allow-expect-in-tests allow-indexing-slicing-in-tests From 878a1732bc14e33f14ae2350d4a4ba75f7992035 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Mon, 12 May 2025 11:52:18 -0400 Subject: [PATCH 2258/4206] Fix for the fminimum intrinsics --- src/intrinsic/mod.rs | 113 +++++++++++++++++++++++++++++-------------- 1 file changed, 76 insertions(+), 37 deletions(-) diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index f292c467418f1..4e5018ae01181 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -72,44 +72,8 @@ fn get_simple_intrinsic<'gcc, 'tcx>( sym::fabsf64 => "fabs", sym::minnumf32 => "fminf", sym::minnumf64 => "fmin", - sym::minimumf32 => "fminimumf", - sym::minimumf64 => "fminimum", - sym::minimumf128 => { - // GCC doesn't have the intrinsic we want so we use the compiler-builtins one - // https://docs.rs/compiler_builtins/latest/compiler_builtins/math/full_availability/fn.fminimumf128.html - let f128_type = cx.type_f128(); - return Some(cx.context.new_function( - None, - FunctionType::Extern, - f128_type, - &[ - cx.context.new_parameter(None, f128_type, "a"), - cx.context.new_parameter(None, f128_type, "b"), - ], - "fminimumf128", - false, - )); - } sym::maxnumf32 => "fmaxf", sym::maxnumf64 => "fmax", - sym::maximumf32 => "fmaximumf", - sym::maximumf64 => "fmaximum", - sym::maximumf128 => { - // GCC doesn't have the intrinsic we want so we use the compiler-builtins one - // https://docs.rs/compiler_builtins/latest/compiler_builtins/math/full_availability/fn.fmaximumf128.html - let f128_type = cx.type_f128(); - return Some(cx.context.new_function( - None, - FunctionType::Extern, - f128_type, - &[ - cx.context.new_parameter(None, f128_type, "a"), - cx.context.new_parameter(None, f128_type, "b"), - ], - "fmaximumf128", - false, - )); - } sym::copysignf32 => "copysignf", sym::copysignf64 => "copysign", sym::copysignf128 => "copysignl", @@ -130,6 +94,72 @@ fn get_simple_intrinsic<'gcc, 'tcx>( Some(cx.context.get_builtin_function(gcc_name)) } +// TODO(antoyo): We can probably remove these and use the fallback intrinsic implementation. +fn get_simple_function<'gcc, 'tcx>( + cx: &CodegenCx<'gcc, 'tcx>, + name: Symbol, +) -> Option> { + let (return_type, parameters, func_name) = match name { + sym::minimumf32 => { + let parameters = [ + cx.context.new_parameter(None, cx.float_type, "a"), + cx.context.new_parameter(None, cx.float_type, "b"), + ]; + (cx.float_type, parameters, "fminimumf") + } + sym::minimumf64 => { + let parameters = [ + cx.context.new_parameter(None, cx.double_type, "a"), + cx.context.new_parameter(None, cx.double_type, "b"), + ]; + (cx.double_type, parameters, "fminimum") + } + sym::minimumf128 => { + let f128_type = cx.type_f128(); + // GCC doesn't have the intrinsic we want so we use the compiler-builtins one + // https://docs.rs/compiler_builtins/latest/compiler_builtins/math/full_availability/fn.fminimumf128.html + let parameters = [ + cx.context.new_parameter(None, f128_type, "a"), + cx.context.new_parameter(None, f128_type, "b"), + ]; + (f128_type, parameters, "fminimumf128") + } + sym::maximumf32 => { + let parameters = [ + cx.context.new_parameter(None, cx.float_type, "a"), + cx.context.new_parameter(None, cx.float_type, "b"), + ]; + (cx.float_type, parameters, "fmaximumf") + } + sym::maximumf64 => { + let parameters = [ + cx.context.new_parameter(None, cx.double_type, "a"), + cx.context.new_parameter(None, cx.double_type, "b"), + ]; + (cx.double_type, parameters, "fmaximum") + } + sym::maximumf128 => { + let f128_type = cx.type_f128(); + // GCC doesn't have the intrinsic we want so we use the compiler-builtins one + // https://docs.rs/compiler_builtins/latest/compiler_builtins/math/full_availability/fn.fmaximumf128.html + let parameters = [ + cx.context.new_parameter(None, f128_type, "a"), + cx.context.new_parameter(None, f128_type, "b"), + ]; + (f128_type, parameters, "fmaximumf128") + } + _ => return None, + }; + Some(cx.context.new_function( + None, + FunctionType::Extern, + return_type, + ¶meters, + func_name, + false, + )) +} + impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { fn codegen_intrinsic_call( &mut self, @@ -158,6 +188,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); let simple = get_simple_intrinsic(self, name); + let simple_func = get_simple_function(self, name); // FIXME(tempdragon): Re-enable `clippy::suspicious_else_formatting` if the following issue is solved: // https://github.com/rust-lang/rust-clippy/issues/12497 @@ -165,7 +196,15 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc #[allow(clippy::suspicious_else_formatting)] let value = match name { _ if simple.is_some() => { - let func = simple.expect("simple function"); + let func = simple.expect("simple intrinsic function"); + self.cx.context.new_call( + self.location, + func, + &args.iter().map(|arg| arg.immediate()).collect::>(), + ) + } + _ if simple_func.is_some() => { + let func = simple_func.expect("simple function"); self.cx.context.new_call( self.location, func, From 44af0a8b6c7be8bc9411ec8539729cf94f2b1a20 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 14 May 2025 04:59:23 -0400 Subject: [PATCH 2259/4206] Stop ignoring test_mm512_stream_ps stdarch test --- .github/workflows/stdarch.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/stdarch.yml b/.github/workflows/stdarch.yml index 4b9f48e7b1835..0d92a6a37ff8e 100644 --- a/.github/workflows/stdarch.yml +++ b/.github/workflows/stdarch.yml @@ -101,9 +101,8 @@ jobs: if: ${{ matrix.cargo_runner }} run: | # FIXME: these tests fail when the sysroot is compiled with LTO because of a missing symbol in proc-macro. - # TODO: remove --skip test_mm512_stream_ps when stdarch is updated in rustc. # TODO: remove --skip test_tile_ when it's implemented. - STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu CG_RUSTFLAGS="-Ainternal_features --cfg stdarch_intel_sde" ./y.sh cargo test --manifest-path build/build_sysroot/sysroot_src/library/stdarch/Cargo.toml -- --skip rtm --skip tbm --skip sse4a --skip test_mm512_stream_ps --skip test_tile_ + STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu CG_RUSTFLAGS="-Ainternal_features --cfg stdarch_intel_sde" ./y.sh cargo test --manifest-path build/build_sysroot/sysroot_src/library/stdarch/Cargo.toml -- --skip rtm --skip tbm --skip sse4a --skip test_tile_ # Summary job for the merge queue. # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! From f38d6d0a8fdeee797a6e32a04bd0895bc4f7b322 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 14 May 2025 04:59:02 -0400 Subject: [PATCH 2260/4206] Fix for xsave test on Intel SDE --- .github/workflows/stdarch.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stdarch.yml b/.github/workflows/stdarch.yml index 0d92a6a37ff8e..f26ac3b755fb2 100644 --- a/.github/workflows/stdarch.yml +++ b/.github/workflows/stdarch.yml @@ -102,7 +102,7 @@ jobs: run: | # FIXME: these tests fail when the sysroot is compiled with LTO because of a missing symbol in proc-macro. # TODO: remove --skip test_tile_ when it's implemented. - STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu CG_RUSTFLAGS="-Ainternal_features --cfg stdarch_intel_sde" ./y.sh cargo test --manifest-path build/build_sysroot/sysroot_src/library/stdarch/Cargo.toml -- --skip rtm --skip tbm --skip sse4a --skip test_tile_ + STDARCH_TEST_SKIP_FUNCTION="xsave,xsaveopt,xsave64,xsaveopt64" STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu CG_RUSTFLAGS="-Ainternal_features" ./y.sh cargo test --manifest-path build/build_sysroot/sysroot_src/library/stdarch/Cargo.toml -- --skip rtm --skip tbm --skip sse4a --skip test_tile_ # Summary job for the merge queue. # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! From 66b2bf150c899de069be288d41db2428ac3bde00 Mon Sep 17 00:00:00 2001 From: Li-yao Xia Date: Wed, 14 May 2025 11:36:00 +0200 Subject: [PATCH 2261/4206] Fix link to GatherBorrows --- src/doc/rustc-dev-guide/src/borrow_check/two_phase_borrows.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/borrow_check/two_phase_borrows.md b/src/doc/rustc-dev-guide/src/borrow_check/two_phase_borrows.md index bcd48782110a2..b77ae09465ca9 100644 --- a/src/doc/rustc-dev-guide/src/borrow_check/two_phase_borrows.md +++ b/src/doc/rustc-dev-guide/src/borrow_check/two_phase_borrows.md @@ -76,7 +76,7 @@ borrow. [`AutoBorrow`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/adjustment/enum.AutoBorrow.html [converted]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_build/thir/cx/expr/trait.ToBorrowKind.html#method.to_borrow_kind [`BorrowKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.BorrowKind.html -[`GatherBorrows`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/visit/trait.Visitor.html#method.visit_local +[`GatherBorrows`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/borrow_set/struct.GatherBorrows.html [`BorrowData`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/borrow_set/struct.BorrowData.html ## Checking two-phase borrows From 06da7b31ac227edb12fbf9e3760d2fb42fe7084c Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Mon, 12 May 2025 23:08:54 +0800 Subject: [PATCH 2262/4206] fixes: ide-assists, generate_new indent loses --- .../ide-assists/src/handlers/generate_new.rs | 137 +++++++++++++++++- 1 file changed, 136 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs index f963f48d62ab6..4837f92f93453 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs @@ -129,17 +129,23 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option // Get the mutable version of the impl to modify let impl_def = if let Some(impl_def) = impl_def { + fn_.indent(impl_def.indent_level()); builder.make_mut(impl_def) } else { // Generate a new impl to add the method to let impl_def = generate_impl(&ast::Adt::Struct(strukt.clone())); + let indent_level = strukt.indent_level(); + fn_.indent(indent_level); // Insert it after the adt let strukt = builder.make_mut(strukt.clone()); ted::insert_all_raw( ted::Position::after(strukt.syntax()), - vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()], + vec![ + make::tokens::whitespace(&format!("\n\n{indent_level}")).into(), + impl_def.syntax().clone().into(), + ], ); impl_def @@ -425,6 +431,135 @@ impl Foo { ); } + #[test] + fn non_zero_indent() { + check_assist( + generate_new, + r#" +mod foo { + struct $0Foo {} +} +"#, + r#" +mod foo { + struct Foo {} + + impl Foo { + fn $0new() -> Self { + Self { } + } + } +} +"#, + ); + check_assist( + generate_new, + r#" +mod foo { + mod bar { + struct $0Foo {} + } +} +"#, + r#" +mod foo { + mod bar { + struct Foo {} + + impl Foo { + fn $0new() -> Self { + Self { } + } + } + } +} +"#, + ); + check_assist( + generate_new, + r#" +mod foo { + struct $0Foo {} + + impl Foo { + fn some() {} + } +} +"#, + r#" +mod foo { + struct Foo {} + + impl Foo { + fn $0new() -> Self { + Self { } + } + + fn some() {} + } +} +"#, + ); + check_assist( + generate_new, + r#" +mod foo { + mod bar { + struct $0Foo {} + + impl Foo { + fn some() {} + } + } +} +"#, + r#" +mod foo { + mod bar { + struct Foo {} + + impl Foo { + fn $0new() -> Self { + Self { } + } + + fn some() {} + } + } +} +"#, + ); + check_assist( + generate_new, + r#" +mod foo { + mod bar { +struct $0Foo {} + + impl Foo { + fn some() {} + } + } +} +"#, + r#" +mod foo { + mod bar { +struct Foo {} + + impl Foo { + fn $0new() -> Self { + Self { } + } + + fn some() {} + } + } +} +"#, + ); + } + #[test] fn check_visibility_of_new_fn_based_on_struct() { check_assist( From d52b5e6df586ceb3bc10aef79940fa21f2ce1341 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 14 May 2025 13:51:02 +0200 Subject: [PATCH 2263/4206] Merge commit '6ba33f5e1189a5ae58fb96ce3546e76b13d090f5' into subtree-update_cg_gcc_2025-05-14 --- .gitattributes | 1 + .github/workflows/stdarch.yml | 3 +- CONTRIBUTING.md | 101 +++++++ Cargo.lock | 8 +- Cargo.toml | 4 +- Readme.md | 44 ++- build_system/Cargo.toml | 2 +- build_system/src/main.rs | 4 +- build_system/src/utils.rs | 2 +- example/mini_core.rs | 54 +++- libgccjit.version | 2 +- rust-toolchain | 2 +- src/abi.rs | 65 ++-- src/attributes.rs | 64 +++- src/back/lto.rs | 2 +- src/back/write.rs | 2 +- src/builder.rs | 25 +- src/consts.rs | 6 +- src/debuginfo.rs | 5 +- src/declare.rs | 1 + src/intrinsic/archs.rs | 554 +++++++++++++++++++++++++--------- src/intrinsic/mod.rs | 81 ++++- src/lib.rs | 4 +- tests/failing-ui-tests.txt | 11 +- tests/lang_tests_common.rs | 9 +- tests/run/always_inline.rs | 53 ++++ tests/run/switchint_128bit.rs | 37 +++ tools/generate_intrinsics.py | 5 +- triagebot.toml | 7 + 29 files changed, 910 insertions(+), 248 deletions(-) create mode 100644 .gitattributes create mode 100644 CONTRIBUTING.md create mode 100644 tests/run/always_inline.rs create mode 100644 tests/run/switchint_128bit.rs create mode 100644 triagebot.toml diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000000..b9cd1111c8d05 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +Cargo.lock linguist-generated=false \ No newline at end of file diff --git a/.github/workflows/stdarch.yml b/.github/workflows/stdarch.yml index 4b9f48e7b1835..f26ac3b755fb2 100644 --- a/.github/workflows/stdarch.yml +++ b/.github/workflows/stdarch.yml @@ -101,9 +101,8 @@ jobs: if: ${{ matrix.cargo_runner }} run: | # FIXME: these tests fail when the sysroot is compiled with LTO because of a missing symbol in proc-macro. - # TODO: remove --skip test_mm512_stream_ps when stdarch is updated in rustc. # TODO: remove --skip test_tile_ when it's implemented. - STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu CG_RUSTFLAGS="-Ainternal_features --cfg stdarch_intel_sde" ./y.sh cargo test --manifest-path build/build_sysroot/sysroot_src/library/stdarch/Cargo.toml -- --skip rtm --skip tbm --skip sse4a --skip test_mm512_stream_ps --skip test_tile_ + STDARCH_TEST_SKIP_FUNCTION="xsave,xsaveopt,xsave64,xsaveopt64" STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu CG_RUSTFLAGS="-Ainternal_features" ./y.sh cargo test --manifest-path build/build_sysroot/sysroot_src/library/stdarch/Cargo.toml -- --skip rtm --skip tbm --skip sse4a --skip test_tile_ # Summary job for the merge queue. # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000000..8e313ab08b59d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,101 @@ +# Contributing to rustc_codegen_gcc + +Welcome to the `rustc_codegen_gcc` project! This guide will help you get started as a contributor. The project aims to provide a GCC codegen backend for rustc, allowing Rust compilation on platforms unsupported by LLVM and potentially improving runtime performance through GCC's optimizations. + +## Getting Started + +### Setting Up Your Development Environment + +For detailed setup instructions including dependencies, build steps, and initial testing, please refer to our [README](Readme.md). The README contains the most up-to-date information on: + +- Required dependencies and system packages +- Repository setup and configuration +- Build process +- Basic test verification + +Once you've completed the setup process outlined in the README, you can proceed with the contributor-specific information below. + +## Communication Channels + +- Matrix: Join our [Matrix channel](https://matrix.to/#/#rustc_codegen_gcc:matrix.org) +- IRC: Join us on [IRC](https://web.libera.chat/#rustc_codegen_gcc) +- [GitHub Issues](https://github.com/rust-lang/rustc_codegen_gcc/issues): For bug reports and feature discussions + +We encourage new contributors to join our communication channels and introduce themselves. Feel free to ask questions about where to start or discuss potential contributions. + +## Understanding Core Concepts + +### Common Development Tasks + +#### Running Specific Tests + +To run specific tests, use appropriate flags such as: + +- `./y.sh test --test-libcore` +- `./y.sh test --std-tests` +- `cargo test -- ` + +Additionally, you can run the tests of `libgccjit`: + +```bash +# libgccjit tests +cd gcc-build/gcc +make check-jit +# For a specific test: +make check-jit RUNTESTFLAGS="-v -v -v jit.exp=jit.dg/test-asm.cc" +``` + +#### Debugging Tools + +The project provides several environment variables for debugging: + +- `CG_GCCJIT_DUMP_GIMPLE`: Dumps the GIMPLE IR +- `CG_RUSTFLAGS`: Additional Rust flags +- `CG_GCCJIT_DUMP_MODULE`: Dumps a specific module +- `CG_GCCJIT_DUMP_TO_FILE`: Creates C-like representation + +Full list of debugging options can be found in the [README](Readme.md#env-vars). + +## Making Contributions + +### Finding Issues to Work On + +1. Look for issues labeled with [`good first issue`](https://github.com/rust-lang/rustc_codegen_gcc/issues?q=is%3Aissue%20state%3Aopen%20label%3A"good%20first%20issue") or [`help wanted`](https://github.com/rust-lang/rustc_codegen_gcc/issues?q=is%3Aissue%20state%3Aopen%20label%3A"help%20wanted") +2. Check the [progress report](https://blog.antoyo.xyz/rustc_codegen_gcc-progress-report-34#state_of_rustc_codegen_gcc) for larger initiatives +3. Consider improving documentation or investigating [failing tests](https://github.com/rust-lang/rustc_codegen_gcc/tree/master/tests) (except `failing-ui-tests12.txt`) + +### Pull Request Process + +1. Fork the repository and create a new branch +2. Make your changes with clear commit messages +3. Add tests for new functionality +4. Update documentation as needed +5. Submit a PR with a description of your changes + +### Code Style Guidelines + +- Follow Rust standard coding conventions +- Ensure your code passes `rustfmt` and `clippy` +- Add comments explaining complex logic, especially in GCC interface code + +## Additional Resources + +- [Rustc Dev Guide](https://rustc-dev-guide.rust-lang.org/) +- [GCC Internals Documentation](https://gcc.gnu.org/onlinedocs/gccint/) +- Project-specific documentation in the `doc/` directory: + - [Common errors](doc/errors.md) + - [Debugging](doc/debugging.md) + - [Debugging libgccjit](doc/debugging-libgccjit.md) + - [Git subtree sync](doc/subtree.md) + - [List of useful commands](doc/tips.md) + - [Send a patch to GCC](doc/sending-gcc-patch.md) + +## Getting Help + +If you're stuck or unsure about anything: +1. Check the existing documentation in the `doc/` directory +2. Ask in the IRC or Matrix channels +3. Open a GitHub issue for technical problems +4. Comment on the issue you're working on if you need guidance + +Remember that all contributions, including documentation improvements, bug reports, and feature requests, are valuable to the project. diff --git a/Cargo.lock b/Cargo.lock index 832603aa79252..967a51a1cc64b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -56,18 +56,18 @@ dependencies = [ [[package]] name = "gccjit" -version = "2.5.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2895ddec764de7ac76fe6c056050c4801a80109c066f177a00a9cc8dee02b29b" +checksum = "ae99a89184220d967dd300139f2d2ae7d52c1a69d632b24aacc57c54625254ce" dependencies = [ "gccjit_sys", ] [[package]] name = "gccjit_sys" -version = "0.6.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac133db68db8a6a8b2c51ef4b18d8ea16682d5814c4641272fe37bbbc223d5f3" +checksum = "24edb7bfe2b7b27c6d09ed23eebfcab0b359c8fe978433f902943e6f127a0f1b" dependencies = [ "libc", ] diff --git a/Cargo.toml b/Cargo.toml index b50f2a626d57c..c692a90f0a4a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "rustc_codegen_gcc" version = "0.1.0" authors = ["Antoni Boucher "] -edition = "2018" +edition = "2024" license = "MIT OR Apache-2.0" [lib] @@ -22,7 +22,7 @@ master = ["gccjit/master"] default = ["master"] [dependencies] -gccjit = "2.5" +gccjit = "2.7" #gccjit = { git = "https://github.com/rust-lang/gccjit.rs" } # Local copy. diff --git a/Readme.md b/Readme.md index d0e4dbba6d355..859bb1568f4eb 100644 --- a/Readme.md +++ b/Readme.md @@ -12,22 +12,38 @@ This is a GCC codegen for rustc, which means it can be loaded by the existing ru The primary goal of this project is to be able to compile Rust code on platforms unsupported by LLVM. A secondary goal is to check if using the gcc backend will provide any run-time speed improvement for the programs compiled using rustc. -### Dependencies - -**rustup:** Follow the instructions on the official [website](https://www.rust-lang.org/tools/install) - -**DejaGnu:** Consider to install DejaGnu which is necessary for running the libgccjit test suite. [website](https://www.gnu.org/software/dejagnu/#downloading) - - +## Getting Started -## Building - -**This requires a patched libgccjit in order to work. +Note: **This requires a patched libgccjit in order to work. You need to use my [fork of gcc](https://github.com/rust-lang/gcc) which already includes these patches.** +The default configuration (see below in the [Quick start](#quick-start) section) will download a `libgccjit` built in the CI that already contains these patches, so you don't need to build this fork yourself if you use the default configuration. -```bash -$ cp config.example.toml config.toml -``` +### Dependencies + +- rustup: follow instructions on the [official website](https://rustup.rs) +- consider to install DejaGnu which is necessary for running the libgccjit test suite. [website](https://www.gnu.org/software/dejagnu/#downloading) +- additional packages: `flex`, `libmpfr-dev`, `libgmp-dev`, `libmpc3`, `libmpc-dev` + +### Quick start + +1. Clone and configure the repository: + ```bash + git clone https://github.com/rust-lang/rustc_codegen_gcc + cd rustc_codegen_gcc + cp config.example.toml config.toml + ``` + +2. Build and test: + ```bash + ./y.sh prepare # downloads and patches sysroot + ./y.sh build --sysroot --release + + # Verify setup with a simple test + ./y.sh cargo build --manifest-path tests/hello-world/Cargo.toml + + # Run full test suite (expect ~100 failing UI tests) + ./y.sh test --release + ``` If don't need to test GCC patches you wrote in our GCC fork, then the default configuration should be all you need. You can update the `rustc_codegen_gcc` without worrying about GCC. @@ -143,7 +159,7 @@ You can do the same manually (although we don't recommend it): $ LIBRARY_PATH="[gcc-path value]" LD_LIBRARY_PATH="[gcc-path value]" rustc +$(cat $CG_GCCJIT_DIR/rust-toolchain | grep 'channel' | cut -d '=' -f 2 | sed 's/"//g' | sed 's/ //g') -Cpanic=abort -Zcodegen-backend=$CG_GCCJIT_DIR/target/release/librustc_codegen_gcc.so --sysroot $CG_GCCJIT_DIR/build_sysroot/sysroot my_crate.rs ``` -## Env vars +## Environment variables * _**CG_GCCJIT_DUMP_ALL_MODULES**_: Enables dumping of all compilation modules. When set to "1", a dump is created for each module during compilation and stored in `/tmp/reproducers/`. * _**CG_GCCJIT_DUMP_MODULE**_: Enables dumping of a specific module. When set with the module name, e.g., `CG_GCCJIT_DUMP_MODULE=module_name`, a dump of that specific module is created in `/tmp/reproducers/`. diff --git a/build_system/Cargo.toml b/build_system/Cargo.toml index d2600ed5a0314..540d82369fdf7 100644 --- a/build_system/Cargo.toml +++ b/build_system/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "y" version = "0.1.0" -edition = "2021" +edition = "2024" [dependencies] boml = "0.3.1" diff --git a/build_system/src/main.rs b/build_system/src/main.rs index 393617183061b..c70b00e09ae70 100644 --- a/build_system/src/main.rs +++ b/build_system/src/main.rs @@ -60,7 +60,9 @@ pub enum Command { fn main() { if env::var("RUST_BACKTRACE").is_err() { - env::set_var("RUST_BACKTRACE", "1"); + unsafe { + env::set_var("RUST_BACKTRACE", "1"); + } } let command = match env::args().nth(1).as_deref() { diff --git a/build_system/src/utils.rs b/build_system/src/utils.rs index 401c23948e5d3..ca177a5feb86a 100644 --- a/build_system/src/utils.rs +++ b/build_system/src/utils.rs @@ -10,7 +10,7 @@ use std::path::{Path, PathBuf}; use std::process::{Command, ExitStatus, Output}; #[cfg(unix)] -extern "C" { +unsafe extern "C" { fn raise(signal: c_int) -> c_int; } diff --git a/example/mini_core.rs b/example/mini_core.rs index c554a87b8256c..d1d8e8fd5bc45 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -1,6 +1,14 @@ #![feature( - no_core, lang_items, intrinsics, unboxed_closures, extern_types, - decl_macro, rustc_attrs, transparent_unions, auto_traits, freeze_impls, + no_core, + lang_items, + intrinsics, + unboxed_closures, + extern_types, + decl_macro, + rustc_attrs, + transparent_unions, + auto_traits, + freeze_impls, thread_local )] #![no_core] @@ -35,13 +43,13 @@ impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} pub trait DispatchFromDyn {} // &T -> &U -impl<'a, T: ?Sized+Unsize, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {} +impl<'a, T: ?Sized + Unsize, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {} // &mut T -> &mut U -impl<'a, T: ?Sized+Unsize, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {} +impl<'a, T: ?Sized + Unsize, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {} // *const T -> *const U -impl, U: ?Sized> DispatchFromDyn<*const U> for *const T {} +impl, U: ?Sized> DispatchFromDyn<*const U> for *const T {} // *mut T -> *mut U -impl, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {} +impl, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {} impl, U: ?Sized> DispatchFromDyn> for Box {} #[lang = "legacy_receiver"] @@ -52,8 +60,7 @@ impl LegacyReceiver for &mut T {} impl LegacyReceiver for Box {} #[lang = "receiver"] -trait Receiver { -} +trait Receiver {} #[lang = "copy"] pub trait Copy {} @@ -67,10 +74,13 @@ impl Copy for u16 {} impl Copy for u32 {} impl Copy for u64 {} impl Copy for usize {} +impl Copy for u128 {} impl Copy for i8 {} impl Copy for i16 {} impl Copy for i32 {} +impl Copy for i64 {} impl Copy for isize {} +impl Copy for i128 {} impl Copy for f32 {} impl Copy for f64 {} impl Copy for char {} @@ -336,7 +346,6 @@ impl PartialEq for u32 { } } - impl PartialEq for u64 { fn eq(&self, other: &u64) -> bool { (*self) == (*other) @@ -523,7 +532,11 @@ fn panic_in_cleanup() -> ! { #[track_caller] fn panic_bounds_check(index: usize, len: usize) -> ! { unsafe { - libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index); + libc::printf( + "index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, + len, + index, + ); intrinsics::abort(); } } @@ -551,8 +564,7 @@ pub trait Deref { fn deref(&self) -> &Self::Target; } -pub trait Allocator { -} +pub trait Allocator {} impl Allocator for () {} @@ -634,6 +646,8 @@ pub union MaybeUninit { } pub mod intrinsics { + #[rustc_intrinsic] + pub const fn black_box(_dummy: T) -> T; #[rustc_intrinsic] pub fn abort() -> !; #[rustc_intrinsic] @@ -711,19 +725,27 @@ pub struct VaList<'a>(&'a mut VaListImpl); #[rustc_builtin_macro] #[rustc_macro_transparency = "semitransparent"] -pub macro stringify($($t:tt)*) { /* compiler built-in */ } +pub macro stringify($($t:tt)*) { + /* compiler built-in */ +} #[rustc_builtin_macro] #[rustc_macro_transparency = "semitransparent"] -pub macro file() { /* compiler built-in */ } +pub macro file() { + /* compiler built-in */ +} #[rustc_builtin_macro] #[rustc_macro_transparency = "semitransparent"] -pub macro line() { /* compiler built-in */ } +pub macro line() { + /* compiler built-in */ +} #[rustc_builtin_macro] #[rustc_macro_transparency = "semitransparent"] -pub macro cfg() { /* compiler built-in */ } +pub macro cfg() { + /* compiler built-in */ +} pub static A_STATIC: u8 = 42; diff --git a/libgccjit.version b/libgccjit.version index 125b04004b07f..d06646dacc342 100644 --- a/libgccjit.version +++ b/libgccjit.version @@ -1 +1 @@ -0ea98a1365b81f7488073512c850e8ee951a4afd +8b194529188f9d3a98cc211caa805a5355bfa8f0 diff --git a/rust-toolchain b/rust-toolchain index 452d3f22dc518..a8cda28688c84 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2025-04-25" +channel = "nightly-2025-05-12" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/src/abi.rs b/src/abi.rs index a96b18e01c087..d882d3eecf49a 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -9,9 +9,9 @@ use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf; #[cfg(feature = "master")] use rustc_session::config; -#[cfg(feature = "master")] -use rustc_target::callconv::Conv; use rustc_target::callconv::{ArgAttributes, CastTarget, FnAbi, PassMode}; +#[cfg(feature = "master")] +use rustc_target::callconv::{Conv, RiscvInterruptKind}; use crate::builder::Builder; use crate::context::CodegenCx; @@ -240,38 +240,57 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { #[cfg(feature = "master")] pub fn conv_to_fn_attribute<'gcc>(conv: Conv, arch: &str) -> Option> { - // TODO: handle the calling conventions returning None. let attribute = match conv { - Conv::C - | Conv::Rust - | Conv::CCmseNonSecureCall - | Conv::CCmseNonSecureEntry - | Conv::RiscvInterrupt { .. } => return None, - Conv::Cold => return None, + Conv::C | Conv::Rust => return None, + Conv::CCmseNonSecureCall => { + if arch == "arm" { + FnAttribute::ArmCmseNonsecureCall + } else { + return None; + } + } + Conv::CCmseNonSecureEntry => { + if arch == "arm" { + FnAttribute::ArmCmseNonsecureEntry + } else { + return None; + } + } + Conv::Cold => FnAttribute::Cold, + // NOTE: the preserve attributes are not yet implemented in GCC: + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110899 Conv::PreserveMost => return None, Conv::PreserveAll => return None, Conv::GpuKernel => { - // TODO(antoyo): remove clippy allow attribute when this is implemented. - #[allow(clippy::if_same_then_else)] if arch == "amdgpu" { - return None; + FnAttribute::GcnAmdGpuHsaKernel } else if arch == "nvptx64" { - return None; + FnAttribute::NvptxKernel } else { panic!("Architecture {} does not support GpuKernel calling convention", arch); } } - Conv::AvrInterrupt => return None, - Conv::AvrNonBlockingInterrupt => return None, - Conv::ArmAapcs => return None, - Conv::Msp430Intr => return None, - Conv::X86Fastcall => return None, - Conv::X86Intr => return None, - Conv::X86Stdcall => return None, - Conv::X86ThisCall => return None, + // TODO(antoyo): check if those AVR attributes are mapped correctly. + Conv::AvrInterrupt => FnAttribute::AvrSignal, + Conv::AvrNonBlockingInterrupt => FnAttribute::AvrInterrupt, + Conv::ArmAapcs => FnAttribute::ArmPcs("aapcs"), + Conv::Msp430Intr => FnAttribute::Msp430Interrupt, + Conv::RiscvInterrupt { kind } => { + let kind = match kind { + RiscvInterruptKind::Machine => "machine", + RiscvInterruptKind::Supervisor => "supervisor", + }; + FnAttribute::RiscvInterrupt(kind) + } + Conv::X86Fastcall => FnAttribute::X86FastCall, + Conv::X86Intr => FnAttribute::X86Interrupt, + Conv::X86Stdcall => FnAttribute::X86Stdcall, + Conv::X86ThisCall => FnAttribute::X86ThisCall, + // NOTE: the vectorcall calling convention is not yet implemented in GCC: + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89485 Conv::X86VectorCall => return None, - Conv::X86_64SysV => FnAttribute::SysvAbi, - Conv::X86_64Win64 => FnAttribute::MsAbi, + Conv::X86_64SysV => FnAttribute::X86SysvAbi, + Conv::X86_64Win64 => FnAttribute::X86MsAbi, }; Some(attribute) } diff --git a/src/attributes.rs b/src/attributes.rs index 69b04dd579693..e63091c6082a7 100644 --- a/src/attributes.rs +++ b/src/attributes.rs @@ -6,21 +6,69 @@ use rustc_attr_parsing::InlineAttr; use rustc_attr_parsing::InstructionSetAttr; #[cfg(feature = "master")] use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +#[cfg(feature = "master")] +use rustc_middle::mir::TerminatorKind; use rustc_middle::ty; use crate::context::CodegenCx; use crate::gcc_util::to_gcc_features; -/// Get GCC attribute for the provided inline heuristic. +/// Checks if the function `instance` is recursively inline. +/// Returns `false` if a functions is guaranteed to be non-recursive, and `true` if it *might* be recursive. +#[cfg(feature = "master")] +fn resursively_inline<'gcc, 'tcx>( + cx: &CodegenCx<'gcc, 'tcx>, + instance: ty::Instance<'tcx>, +) -> bool { + // No body, so we can't check if this is recursively inline, so we assume it is. + if !cx.tcx.is_mir_available(instance.def_id()) { + return true; + } + // `expect_local` ought to never fail: we should be checking a function within this codegen unit. + let body = cx.tcx.optimized_mir(instance.def_id()); + for block in body.basic_blocks.iter() { + let Some(ref terminator) = block.terminator else { continue }; + // I assume that the recursive-inline issue applies only to functions, and not to drops. + // In principle, a recursive, `#[inline(always)]` drop could(?) exist, but I don't think it does. + let TerminatorKind::Call { ref func, .. } = terminator.kind else { continue }; + let Some((def, _args)) = func.const_fn_def() else { continue }; + // Check if the called function is recursively inline. + if matches!( + cx.tcx.codegen_fn_attrs(def).inline, + InlineAttr::Always | InlineAttr::Force { .. } + ) { + return true; + } + } + false +} + +/// Get GCC attribute for the provided inline heuristic, attached to `instance`. #[cfg(feature = "master")] #[inline] fn inline_attr<'gcc, 'tcx>( cx: &CodegenCx<'gcc, 'tcx>, inline: InlineAttr, + instance: ty::Instance<'tcx>, ) -> Option> { match inline { + InlineAttr::Always => { + // We can't simply always return `always_inline` unconditionally. + // It is *NOT A HINT* and does not work for recursive functions. + // + // So, it can only be applied *if*: + // The current function does not call any functions marked `#[inline(always)]`. + // + // That prevents issues steming from recursive `#[inline(always)]` at a *relatively* small cost. + // We *only* need to check all the terminators of a function marked with this attribute. + if resursively_inline(cx, instance) { + Some(FnAttribute::Inline) + } else { + Some(FnAttribute::AlwaysInline) + } + } InlineAttr::Hint => Some(FnAttribute::Inline), - InlineAttr::Always | InlineAttr::Force { .. } => Some(FnAttribute::AlwaysInline), + InlineAttr::Force { .. } => Some(FnAttribute::AlwaysInline), InlineAttr::Never => { if cx.sess().target.arch != "amdgpu" { Some(FnAttribute::NoInline) @@ -52,7 +100,7 @@ pub fn from_fn_attrs<'gcc, 'tcx>( } else { codegen_fn_attrs.inline }; - if let Some(attr) = inline_attr(cx, inline) { + if let Some(attr) = inline_attr(cx, inline, instance) { if let FnAttribute::AlwaysInline = attr { func.add_attribute(FnAttribute::Inline); } @@ -88,14 +136,8 @@ pub fn from_fn_attrs<'gcc, 'tcx>( let target_features = function_features .iter() .filter_map(|feature| { - // FIXME(antoyo): for some reasons, disabling SSE results in the following error when - // compiling Rust for Linux: - // SSE register return with SSE disabled - // TODO(antoyo): support soft-float and retpoline-external-thunk. - if feature.contains("soft-float") - || feature.contains("retpoline-external-thunk") - || *feature == "-sse" - { + // TODO(antoyo): support soft-float. + if feature.contains("soft-float") { return None; } diff --git a/src/back/lto.rs b/src/back/lto.rs index faeb2643ecb88..e9c87f357793c 100644 --- a/src/back/lto.rs +++ b/src/back/lto.rs @@ -593,7 +593,7 @@ fn thin_lto( Ok((opt_jobs, copy_jobs)) } -pub unsafe fn optimize_thin_module( +pub fn optimize_thin_module( thin_module: ThinModule, _cgcx: &CodegenContext, ) -> Result, FatalError> { diff --git a/src/back/write.rs b/src/back/write.rs index 16c895322e88a..09e955acf3900 100644 --- a/src/back/write.rs +++ b/src/back/write.rs @@ -14,7 +14,7 @@ use crate::base::add_pic_option; use crate::errors::CopyBitcode; use crate::{GccCodegenBackend, GccContext}; -pub(crate) unsafe fn codegen( +pub(crate) fn codegen( cgcx: &CodegenContext, dcx: DiagCtxtHandle<'_>, module: ModuleCodegen, diff --git a/src/builder.rs b/src/builder.rs index 9e5ebf3a9a40b..4e2163201fd01 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -568,11 +568,28 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { ) { let mut gcc_cases = vec![]; let typ = self.val_ty(value); - for (on_val, dest) in cases { - let on_val = self.const_uint_big(typ, on_val); - gcc_cases.push(self.context.new_case(on_val, on_val, dest)); + // FIXME(FractalFir): This is a workaround for a libgccjit limitation. + // Currently, libgccjit can't directly create 128 bit integers. + // Since switch cases must be values, and casts are not constant, we can't use 128 bit switch cases. + // In such a case, we will simply fall back to an if-ladder. + // This *may* be slower than a native switch, but a slow working solution is better than none at all. + if typ.is_i128(self) || typ.is_u128(self) { + for (on_val, dest) in cases { + let on_val = self.const_uint_big(typ, on_val); + let is_case = + self.context.new_comparison(self.location, ComparisonOp::Equals, value, on_val); + let next_block = self.current_func().new_block("case"); + self.block.end_with_conditional(self.location, is_case, dest, next_block); + self.block = next_block; + } + self.block.end_with_jump(self.location, default_block); + } else { + for (on_val, dest) in cases { + let on_val = self.const_uint_big(typ, on_val); + gcc_cases.push(self.context.new_case(on_val, on_val, dest)); + } + self.block.end_with_switch(self.location, value, default_block, &gcc_cases); } - self.block.end_with_switch(self.location, value, default_block, &gcc_cases); } #[cfg(feature = "master")] diff --git a/src/consts.rs b/src/consts.rs index 0a67bd7bc71af..033afc0f8fbf4 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -191,13 +191,11 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { // TODO(antoyo): check if it's okay that no link_section is set. let typ = self.val_ty(cv).get_aligned(align.bytes()); - let global = self.declare_private_global(&name[..], typ); - global + self.declare_private_global(&name[..], typ) } _ => { let typ = self.val_ty(cv).get_aligned(align.bytes()); - let global = self.declare_unnamed_global(typ); - global + self.declare_unnamed_global(typ) } }; global.global_set_initializer_rvalue(cv); diff --git a/src/debuginfo.rs b/src/debuginfo.rs index f3ced86439527..e0597d0030d57 100644 --- a/src/debuginfo.rs +++ b/src/debuginfo.rs @@ -289,7 +289,7 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { ) -> Self::DILocation { let pos = span.lo(); let DebugLoc { file, line, col } = self.lookup_debug_loc(pos); - let loc = match file.name { + match file.name { rustc_span::FileName::Real(ref name) => match *name { rustc_span::RealFileName::LocalPath(ref name) => { if let Some(name) = name.to_str() { @@ -314,7 +314,6 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } }, _ => Location::null(), - }; - loc + } } } diff --git a/src/declare.rs b/src/declare.rs index c1ca3eb849e88..bed82073e2c41 100644 --- a/src/declare.rs +++ b/src/declare.rs @@ -157,6 +157,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { /// /// If there’s a value with the same name already declared, the function will /// update the declaration and return existing Value instead. +#[allow(clippy::let_and_return)] fn declare_raw_fn<'gcc>( cx: &CodegenCx<'gcc, '_>, name: &str, diff --git a/src/intrinsic/archs.rs b/src/intrinsic/archs.rs index b8d1cde1d5dda..5ada535aa41d6 100644 --- a/src/intrinsic/archs.rs +++ b/src/intrinsic/archs.rs @@ -38,6 +38,7 @@ match name { "llvm.aarch64.gcsss" => "__builtin_arm_gcsss", "llvm.aarch64.isb" => "__builtin_arm_isb", "llvm.aarch64.prefetch" => "__builtin_arm_prefetch", + "llvm.aarch64.sme.in.streaming.mode" => "__builtin_arm_in_streaming_mode", "llvm.aarch64.sve.aesd" => "__builtin_sve_svaesd_u8", "llvm.aarch64.sve.aese" => "__builtin_sve_svaese_u8", "llvm.aarch64.sve.aesimc" => "__builtin_sve_svaesimc_u8", @@ -55,6 +56,8 @@ match name { "llvm.aarch64.ttest" => "__builtin_arm_ttest", // amdgcn "llvm.amdgcn.alignbyte" => "__builtin_amdgcn_alignbyte", + "llvm.amdgcn.ashr.pk.i8.i32" => "__builtin_amdgcn_ashr_pk_i8_i32", + "llvm.amdgcn.ashr.pk.u8.i32" => "__builtin_amdgcn_ashr_pk_u8_i32", "llvm.amdgcn.buffer.wbinvl1" => "__builtin_amdgcn_buffer_wbinvl1", "llvm.amdgcn.buffer.wbinvl1.sc" => "__builtin_amdgcn_buffer_wbinvl1_sc", "llvm.amdgcn.buffer.wbinvl1.vol" => "__builtin_amdgcn_buffer_wbinvl1_vol", @@ -64,6 +67,7 @@ match name { "llvm.amdgcn.cubetc" => "__builtin_amdgcn_cubetc", "llvm.amdgcn.cvt.f32.bf8" => "__builtin_amdgcn_cvt_f32_bf8", "llvm.amdgcn.cvt.f32.fp8" => "__builtin_amdgcn_cvt_f32_fp8", + "llvm.amdgcn.cvt.off.f32.i4" => "__builtin_amdgcn_cvt_off_f32_i4", "llvm.amdgcn.cvt.pk.bf8.f32" => "__builtin_amdgcn_cvt_pk_bf8_f32", "llvm.amdgcn.cvt.pk.f32.bf8" => "__builtin_amdgcn_cvt_pk_f32_bf8", "llvm.amdgcn.cvt.pk.f32.fp8" => "__builtin_amdgcn_cvt_pk_f32_fp8", @@ -74,7 +78,58 @@ match name { "llvm.amdgcn.cvt.pknorm.i16" => "__builtin_amdgcn_cvt_pknorm_i16", "llvm.amdgcn.cvt.pknorm.u16" => "__builtin_amdgcn_cvt_pknorm_u16", "llvm.amdgcn.cvt.pkrtz" => "__builtin_amdgcn_cvt_pkrtz", + "llvm.amdgcn.cvt.scalef32.2xpk16.bf6.f32" => "__builtin_amdgcn_cvt_scalef32_2xpk16_bf6_f32", + "llvm.amdgcn.cvt.scalef32.2xpk16.fp6.f32" => "__builtin_amdgcn_cvt_scalef32_2xpk16_fp6_f32", + "llvm.amdgcn.cvt.scalef32.f16.bf8" => "__builtin_amdgcn_cvt_scalef32_f16_bf8", + "llvm.amdgcn.cvt.scalef32.f16.fp8" => "__builtin_amdgcn_cvt_scalef32_f16_fp8", + "llvm.amdgcn.cvt.scalef32.f32.bf8" => "__builtin_amdgcn_cvt_scalef32_f32_bf8", + "llvm.amdgcn.cvt.scalef32.f32.fp8" => "__builtin_amdgcn_cvt_scalef32_f32_fp8", + "llvm.amdgcn.cvt.scalef32.pk.bf16.bf8" => "__builtin_amdgcn_cvt_scalef32_pk_bf16_bf8", + "llvm.amdgcn.cvt.scalef32.pk.bf16.fp4" => "__builtin_amdgcn_cvt_scalef32_pk_bf16_fp4", + "llvm.amdgcn.cvt.scalef32.pk.bf16.fp8" => "__builtin_amdgcn_cvt_scalef32_pk_bf16_fp8", + "llvm.amdgcn.cvt.scalef32.pk.bf8.bf16" => "__builtin_amdgcn_cvt_scalef32_pk_bf8_bf16", + "llvm.amdgcn.cvt.scalef32.pk.bf8.f16" => "__builtin_amdgcn_cvt_scalef32_pk_bf8_f16", + "llvm.amdgcn.cvt.scalef32.pk.bf8.f32" => "__builtin_amdgcn_cvt_scalef32_pk_bf8_f32", + "llvm.amdgcn.cvt.scalef32.pk.f16.bf8" => "__builtin_amdgcn_cvt_scalef32_pk_f16_bf8", + "llvm.amdgcn.cvt.scalef32.pk.f16.fp4" => "__builtin_amdgcn_cvt_scalef32_pk_f16_fp4", + "llvm.amdgcn.cvt.scalef32.pk.f16.fp8" => "__builtin_amdgcn_cvt_scalef32_pk_f16_fp8", + "llvm.amdgcn.cvt.scalef32.pk.f32.bf8" => "__builtin_amdgcn_cvt_scalef32_pk_f32_bf8", + "llvm.amdgcn.cvt.scalef32.pk.f32.fp4" => "__builtin_amdgcn_cvt_scalef32_pk_f32_fp4", + "llvm.amdgcn.cvt.scalef32.pk.f32.fp8" => "__builtin_amdgcn_cvt_scalef32_pk_f32_fp8", + "llvm.amdgcn.cvt.scalef32.pk.fp4.bf16" => "__builtin_amdgcn_cvt_scalef32_pk_fp4_bf16", + "llvm.amdgcn.cvt.scalef32.pk.fp4.f16" => "__builtin_amdgcn_cvt_scalef32_pk_fp4_f16", + "llvm.amdgcn.cvt.scalef32.pk.fp4.f32" => "__builtin_amdgcn_cvt_scalef32_pk_fp4_f32", + "llvm.amdgcn.cvt.scalef32.pk.fp8.bf16" => "__builtin_amdgcn_cvt_scalef32_pk_fp8_bf16", + "llvm.amdgcn.cvt.scalef32.pk.fp8.f16" => "__builtin_amdgcn_cvt_scalef32_pk_fp8_f16", + "llvm.amdgcn.cvt.scalef32.pk.fp8.f32" => "__builtin_amdgcn_cvt_scalef32_pk_fp8_f32", + "llvm.amdgcn.cvt.scalef32.pk32.bf16.bf6" => "__builtin_amdgcn_cvt_scalef32_pk32_bf16_bf6", + "llvm.amdgcn.cvt.scalef32.pk32.bf16.fp6" => "__builtin_amdgcn_cvt_scalef32_pk32_bf16_fp6", + "llvm.amdgcn.cvt.scalef32.pk32.bf6.bf16" => "__builtin_amdgcn_cvt_scalef32_pk32_bf6_bf16", + "llvm.amdgcn.cvt.scalef32.pk32.bf6.f16" => "__builtin_amdgcn_cvt_scalef32_pk32_bf6_f16", + "llvm.amdgcn.cvt.scalef32.pk32.f16.bf6" => "__builtin_amdgcn_cvt_scalef32_pk32_f16_bf6", + "llvm.amdgcn.cvt.scalef32.pk32.f16.fp6" => "__builtin_amdgcn_cvt_scalef32_pk32_f16_fp6", + "llvm.amdgcn.cvt.scalef32.pk32.f32.bf6" => "__builtin_amdgcn_cvt_scalef32_pk32_f32_bf6", + "llvm.amdgcn.cvt.scalef32.pk32.f32.fp6" => "__builtin_amdgcn_cvt_scalef32_pk32_f32_fp6", + "llvm.amdgcn.cvt.scalef32.pk32.fp6.bf16" => "__builtin_amdgcn_cvt_scalef32_pk32_fp6_bf16", + "llvm.amdgcn.cvt.scalef32.pk32.fp6.f16" => "__builtin_amdgcn_cvt_scalef32_pk32_fp6_f16", + "llvm.amdgcn.cvt.scalef32.sr.bf8.bf16" => "__builtin_amdgcn_cvt_scalef32_sr_bf8_bf16", + "llvm.amdgcn.cvt.scalef32.sr.bf8.f16" => "__builtin_amdgcn_cvt_scalef32_sr_bf8_f16", + "llvm.amdgcn.cvt.scalef32.sr.bf8.f32" => "__builtin_amdgcn_cvt_scalef32_sr_bf8_f32", + "llvm.amdgcn.cvt.scalef32.sr.fp8.bf16" => "__builtin_amdgcn_cvt_scalef32_sr_fp8_bf16", + "llvm.amdgcn.cvt.scalef32.sr.fp8.f16" => "__builtin_amdgcn_cvt_scalef32_sr_fp8_f16", + "llvm.amdgcn.cvt.scalef32.sr.fp8.f32" => "__builtin_amdgcn_cvt_scalef32_sr_fp8_f32", + "llvm.amdgcn.cvt.scalef32.sr.pk.fp4.bf16" => "__builtin_amdgcn_cvt_scalef32_sr_pk_fp4_bf16", + "llvm.amdgcn.cvt.scalef32.sr.pk.fp4.f16" => "__builtin_amdgcn_cvt_scalef32_sr_pk_fp4_f16", + "llvm.amdgcn.cvt.scalef32.sr.pk.fp4.f32" => "__builtin_amdgcn_cvt_scalef32_sr_pk_fp4_f32", + "llvm.amdgcn.cvt.scalef32.sr.pk32.bf6.bf16" => "__builtin_amdgcn_cvt_scalef32_sr_pk32_bf6_bf16", + "llvm.amdgcn.cvt.scalef32.sr.pk32.bf6.f16" => "__builtin_amdgcn_cvt_scalef32_sr_pk32_bf6_f16", + "llvm.amdgcn.cvt.scalef32.sr.pk32.bf6.f32" => "__builtin_amdgcn_cvt_scalef32_sr_pk32_bf6_f32", + "llvm.amdgcn.cvt.scalef32.sr.pk32.fp6.bf16" => "__builtin_amdgcn_cvt_scalef32_sr_pk32_fp6_bf16", + "llvm.amdgcn.cvt.scalef32.sr.pk32.fp6.f16" => "__builtin_amdgcn_cvt_scalef32_sr_pk32_fp6_f16", + "llvm.amdgcn.cvt.scalef32.sr.pk32.fp6.f32" => "__builtin_amdgcn_cvt_scalef32_sr_pk32_fp6_f32", + "llvm.amdgcn.cvt.sr.bf16.f32" => "__builtin_amdgcn_cvt_sr_bf16_f32", "llvm.amdgcn.cvt.sr.bf8.f32" => "__builtin_amdgcn_cvt_sr_bf8_f32", + "llvm.amdgcn.cvt.sr.f16.f32" => "__builtin_amdgcn_cvt_sr_f16_f32", "llvm.amdgcn.cvt.sr.fp8.f32" => "__builtin_amdgcn_cvt_sr_fp8_f32", "llvm.amdgcn.dispatch.id" => "__builtin_amdgcn_dispatch_id", "llvm.amdgcn.dot4.f32.bf8.bf8" => "__builtin_amdgcn_dot4_f32_bf8_bf8", @@ -83,6 +138,7 @@ match name { "llvm.amdgcn.dot4.f32.fp8.fp8" => "__builtin_amdgcn_dot4_f32_fp8_fp8", "llvm.amdgcn.ds.add.gs.reg.rtn" => "__builtin_amdgcn_ds_add_gs_reg_rtn", "llvm.amdgcn.ds.bpermute" => "__builtin_amdgcn_ds_bpermute", + "llvm.amdgcn.ds.bpermute.fi.b32" => "__builtin_amdgcn_ds_bpermute_fi_b32", "llvm.amdgcn.ds.gws.barrier" => "__builtin_amdgcn_ds_gws_barrier", "llvm.amdgcn.ds.gws.init" => "__builtin_amdgcn_ds_gws_init", "llvm.amdgcn.ds.gws.sema.br" => "__builtin_amdgcn_ds_gws_sema_br", @@ -97,6 +153,7 @@ match name { "llvm.amdgcn.fdot2.bf16.bf16" => "__builtin_amdgcn_fdot2_bf16_bf16", "llvm.amdgcn.fdot2.f16.f16" => "__builtin_amdgcn_fdot2_f16_f16", "llvm.amdgcn.fdot2.f32.bf16" => "__builtin_amdgcn_fdot2_f32_bf16", + "llvm.amdgcn.fdot2c.f32.bf16" => "__builtin_amdgcn_fdot2c_f32_bf16", "llvm.amdgcn.fmul.legacy" => "__builtin_amdgcn_fmul_legacy", "llvm.amdgcn.global.load.lds" => "__builtin_amdgcn_global_load_lds", "llvm.amdgcn.groupstaticsize" => "__builtin_amdgcn_groupstaticsize", @@ -118,8 +175,10 @@ match name { "llvm.amdgcn.mfma.f32.16x16x16f16" => "__builtin_amdgcn_mfma_f32_16x16x16f16", "llvm.amdgcn.mfma.f32.16x16x1f32" => "__builtin_amdgcn_mfma_f32_16x16x1f32", "llvm.amdgcn.mfma.f32.16x16x2bf16" => "__builtin_amdgcn_mfma_f32_16x16x2bf16", + "llvm.amdgcn.mfma.f32.16x16x32.bf16" => "__builtin_amdgcn_mfma_f32_16x16x32_bf16", "llvm.amdgcn.mfma.f32.16x16x32.bf8.bf8" => "__builtin_amdgcn_mfma_f32_16x16x32_bf8_bf8", "llvm.amdgcn.mfma.f32.16x16x32.bf8.fp8" => "__builtin_amdgcn_mfma_f32_16x16x32_bf8_fp8", + "llvm.amdgcn.mfma.f32.16x16x32.f16" => "__builtin_amdgcn_mfma_f32_16x16x32_f16", "llvm.amdgcn.mfma.f32.16x16x32.fp8.bf8" => "__builtin_amdgcn_mfma_f32_16x16x32_fp8_bf8", "llvm.amdgcn.mfma.f32.16x16x32.fp8.fp8" => "__builtin_amdgcn_mfma_f32_16x16x32_fp8_fp8", "llvm.amdgcn.mfma.f32.16x16x4bf16.1k" => "__builtin_amdgcn_mfma_f32_16x16x4bf16_1k", @@ -127,8 +186,10 @@ match name { "llvm.amdgcn.mfma.f32.16x16x4f32" => "__builtin_amdgcn_mfma_f32_16x16x4f32", "llvm.amdgcn.mfma.f32.16x16x8.xf32" => "__builtin_amdgcn_mfma_f32_16x16x8_xf32", "llvm.amdgcn.mfma.f32.16x16x8bf16" => "__builtin_amdgcn_mfma_f32_16x16x8bf16", + "llvm.amdgcn.mfma.f32.32x32x16.bf16" => "__builtin_amdgcn_mfma_f32_32x32x16_bf16", "llvm.amdgcn.mfma.f32.32x32x16.bf8.bf8" => "__builtin_amdgcn_mfma_f32_32x32x16_bf8_bf8", "llvm.amdgcn.mfma.f32.32x32x16.bf8.fp8" => "__builtin_amdgcn_mfma_f32_32x32x16_bf8_fp8", + "llvm.amdgcn.mfma.f32.32x32x16.f16" => "__builtin_amdgcn_mfma_f32_32x32x16_f16", "llvm.amdgcn.mfma.f32.32x32x16.fp8.bf8" => "__builtin_amdgcn_mfma_f32_32x32x16_fp8_bf8", "llvm.amdgcn.mfma.f32.32x32x16.fp8.fp8" => "__builtin_amdgcn_mfma_f32_32x32x16_fp8_fp8", "llvm.amdgcn.mfma.f32.32x32x1f32" => "__builtin_amdgcn_mfma_f32_32x32x1f32", @@ -149,7 +210,9 @@ match name { "llvm.amdgcn.mfma.i32.16x16x16i8" => "__builtin_amdgcn_mfma_i32_16x16x16i8", "llvm.amdgcn.mfma.i32.16x16x32.i8" => "__builtin_amdgcn_mfma_i32_16x16x32_i8", "llvm.amdgcn.mfma.i32.16x16x4i8" => "__builtin_amdgcn_mfma_i32_16x16x4i8", + "llvm.amdgcn.mfma.i32.16x16x64.i8" => "__builtin_amdgcn_mfma_i32_16x16x64_i8", "llvm.amdgcn.mfma.i32.32x32x16.i8" => "__builtin_amdgcn_mfma_i32_32x32x16_i8", + "llvm.amdgcn.mfma.i32.32x32x32.i8" => "__builtin_amdgcn_mfma_i32_32x32x32_i8", "llvm.amdgcn.mfma.i32.32x32x4i8" => "__builtin_amdgcn_mfma_i32_32x32x4i8", "llvm.amdgcn.mfma.i32.32x32x8i8" => "__builtin_amdgcn_mfma_i32_32x32x8i8", "llvm.amdgcn.mfma.i32.4x4x4i8" => "__builtin_amdgcn_mfma_i32_4x4x4i8", @@ -159,25 +222,25 @@ match name { "llvm.amdgcn.perm" => "__builtin_amdgcn_perm", "llvm.amdgcn.permlane16.var" => "__builtin_amdgcn_permlane16_var", "llvm.amdgcn.permlanex16.var" => "__builtin_amdgcn_permlanex16_var", + "llvm.amdgcn.prng.b32" => "__builtin_amdgcn_prng_b32", "llvm.amdgcn.qsad.pk.u16.u8" => "__builtin_amdgcn_qsad_pk_u16_u8", "llvm.amdgcn.queue.ptr" => "__builtin_amdgcn_queue_ptr", + "llvm.amdgcn.raw.ptr.buffer.load.lds" => "__builtin_amdgcn_raw_ptr_buffer_load_lds", "llvm.amdgcn.rcp.legacy" => "__builtin_amdgcn_rcp_legacy", "llvm.amdgcn.rsq.legacy" => "__builtin_amdgcn_rsq_legacy", "llvm.amdgcn.s.barrier" => "__builtin_amdgcn_s_barrier", - "llvm.amdgcn.s.barrier.init" => "__builtin_amdgcn_s_barrier_init", - "llvm.amdgcn.s.barrier.join" => "__builtin_amdgcn_s_barrier_join", - "llvm.amdgcn.s.barrier.leave" => "__builtin_amdgcn_s_barrier_leave", "llvm.amdgcn.s.barrier.signal" => "__builtin_amdgcn_s_barrier_signal", "llvm.amdgcn.s.barrier.signal.isfirst" => "__builtin_amdgcn_s_barrier_signal_isfirst", - "llvm.amdgcn.s.barrier.signal.isfirst.var" => "__builtin_amdgcn_s_barrier_signal_isfirst_var", "llvm.amdgcn.s.barrier.signal.var" => "__builtin_amdgcn_s_barrier_signal_var", "llvm.amdgcn.s.barrier.wait" => "__builtin_amdgcn_s_barrier_wait", + "llvm.amdgcn.s.buffer.prefetch.data" => "__builtin_amdgcn_s_buffer_prefetch_data", "llvm.amdgcn.s.dcache.inv" => "__builtin_amdgcn_s_dcache_inv", "llvm.amdgcn.s.dcache.inv.vol" => "__builtin_amdgcn_s_dcache_inv_vol", "llvm.amdgcn.s.dcache.wb" => "__builtin_amdgcn_s_dcache_wb", "llvm.amdgcn.s.dcache.wb.vol" => "__builtin_amdgcn_s_dcache_wb_vol", "llvm.amdgcn.s.decperflevel" => "__builtin_amdgcn_s_decperflevel", "llvm.amdgcn.s.get.barrier.state" => "__builtin_amdgcn_s_get_barrier_state", + "llvm.amdgcn.s.get.named.barrier.state" => "__builtin_amdgcn_s_get_named_barrier_state", "llvm.amdgcn.s.get.waveid.in.workgroup" => "__builtin_amdgcn_s_get_waveid_in_workgroup", "llvm.amdgcn.s.getpc" => "__builtin_amdgcn_s_getpc", "llvm.amdgcn.s.getreg" => "__builtin_amdgcn_s_getreg", @@ -194,7 +257,6 @@ match name { "llvm.amdgcn.s.ttracedata.imm" => "__builtin_amdgcn_s_ttracedata_imm", "llvm.amdgcn.s.wait.event.export.ready" => "__builtin_amdgcn_s_wait_event_export_ready", "llvm.amdgcn.s.waitcnt" => "__builtin_amdgcn_s_waitcnt", - "llvm.amdgcn.s.wakeup.barrier" => "__builtin_amdgcn_s_wakeup_barrier", "llvm.amdgcn.sad.hi.u8" => "__builtin_amdgcn_sad_hi_u8", "llvm.amdgcn.sad.u16" => "__builtin_amdgcn_sad_u16", "llvm.amdgcn.sad.u8" => "__builtin_amdgcn_sad_u8", @@ -203,20 +265,34 @@ match name { "llvm.amdgcn.sdot2" => "__builtin_amdgcn_sdot2", "llvm.amdgcn.sdot4" => "__builtin_amdgcn_sdot4", "llvm.amdgcn.sdot8" => "__builtin_amdgcn_sdot8", + "llvm.amdgcn.smfmac.f32.16x16x128.bf8.bf8" => "__builtin_amdgcn_smfmac_f32_16x16x128_bf8_bf8", + "llvm.amdgcn.smfmac.f32.16x16x128.bf8.fp8" => "__builtin_amdgcn_smfmac_f32_16x16x128_bf8_fp8", + "llvm.amdgcn.smfmac.f32.16x16x128.fp8.bf8" => "__builtin_amdgcn_smfmac_f32_16x16x128_fp8_bf8", + "llvm.amdgcn.smfmac.f32.16x16x128.fp8.fp8" => "__builtin_amdgcn_smfmac_f32_16x16x128_fp8_fp8", "llvm.amdgcn.smfmac.f32.16x16x32.bf16" => "__builtin_amdgcn_smfmac_f32_16x16x32_bf16", "llvm.amdgcn.smfmac.f32.16x16x32.f16" => "__builtin_amdgcn_smfmac_f32_16x16x32_f16", + "llvm.amdgcn.smfmac.f32.16x16x64.bf16" => "__builtin_amdgcn_smfmac_f32_16x16x64_bf16", "llvm.amdgcn.smfmac.f32.16x16x64.bf8.bf8" => "__builtin_amdgcn_smfmac_f32_16x16x64_bf8_bf8", "llvm.amdgcn.smfmac.f32.16x16x64.bf8.fp8" => "__builtin_amdgcn_smfmac_f32_16x16x64_bf8_fp8", + "llvm.amdgcn.smfmac.f32.16x16x64.f16" => "__builtin_amdgcn_smfmac_f32_16x16x64_f16", "llvm.amdgcn.smfmac.f32.16x16x64.fp8.bf8" => "__builtin_amdgcn_smfmac_f32_16x16x64_fp8_bf8", "llvm.amdgcn.smfmac.f32.16x16x64.fp8.fp8" => "__builtin_amdgcn_smfmac_f32_16x16x64_fp8_fp8", "llvm.amdgcn.smfmac.f32.32x32x16.bf16" => "__builtin_amdgcn_smfmac_f32_32x32x16_bf16", "llvm.amdgcn.smfmac.f32.32x32x16.f16" => "__builtin_amdgcn_smfmac_f32_32x32x16_f16", + "llvm.amdgcn.smfmac.f32.32x32x32.bf16" => "__builtin_amdgcn_smfmac_f32_32x32x32_bf16", "llvm.amdgcn.smfmac.f32.32x32x32.bf8.bf8" => "__builtin_amdgcn_smfmac_f32_32x32x32_bf8_bf8", "llvm.amdgcn.smfmac.f32.32x32x32.bf8.fp8" => "__builtin_amdgcn_smfmac_f32_32x32x32_bf8_fp8", + "llvm.amdgcn.smfmac.f32.32x32x32.f16" => "__builtin_amdgcn_smfmac_f32_32x32x32_f16", "llvm.amdgcn.smfmac.f32.32x32x32.fp8.bf8" => "__builtin_amdgcn_smfmac_f32_32x32x32_fp8_bf8", "llvm.amdgcn.smfmac.f32.32x32x32.fp8.fp8" => "__builtin_amdgcn_smfmac_f32_32x32x32_fp8_fp8", + "llvm.amdgcn.smfmac.f32.32x32x64.bf8.bf8" => "__builtin_amdgcn_smfmac_f32_32x32x64_bf8_bf8", + "llvm.amdgcn.smfmac.f32.32x32x64.bf8.fp8" => "__builtin_amdgcn_smfmac_f32_32x32x64_bf8_fp8", + "llvm.amdgcn.smfmac.f32.32x32x64.fp8.bf8" => "__builtin_amdgcn_smfmac_f32_32x32x64_fp8_bf8", + "llvm.amdgcn.smfmac.f32.32x32x64.fp8.fp8" => "__builtin_amdgcn_smfmac_f32_32x32x64_fp8_fp8", + "llvm.amdgcn.smfmac.i32.16x16x128.i8" => "__builtin_amdgcn_smfmac_i32_16x16x128_i8", "llvm.amdgcn.smfmac.i32.16x16x64.i8" => "__builtin_amdgcn_smfmac_i32_16x16x64_i8", "llvm.amdgcn.smfmac.i32.32x32x32.i8" => "__builtin_amdgcn_smfmac_i32_32x32x32_i8", + "llvm.amdgcn.smfmac.i32.32x32x64.i8" => "__builtin_amdgcn_smfmac_i32_32x32x64_i8", "llvm.amdgcn.sudot4" => "__builtin_amdgcn_sudot4", "llvm.amdgcn.sudot8" => "__builtin_amdgcn_sudot8", "llvm.amdgcn.udot2" => "__builtin_amdgcn_udot2", @@ -227,6 +303,9 @@ match name { "llvm.amdgcn.workgroup.id.x" => "__builtin_amdgcn_workgroup_id_x", "llvm.amdgcn.workgroup.id.y" => "__builtin_amdgcn_workgroup_id_y", "llvm.amdgcn.workgroup.id.z" => "__builtin_amdgcn_workgroup_id_z", + "llvm.amdgcn.workitem.id.x" => "__builtin_amdgcn_workitem_id_x", + "llvm.amdgcn.workitem.id.y" => "__builtin_amdgcn_workitem_id_y", + "llvm.amdgcn.workitem.id.z" => "__builtin_amdgcn_workitem_id_z", // arm "llvm.arm.cdp" => "__builtin_arm_cdp", "llvm.arm.cdp2" => "__builtin_arm_cdp2", @@ -342,8 +421,6 @@ match name { "llvm.bpf.pseudo" => "__builtin_bpf_pseudo", // cuda "llvm.cuda.syncthreads" => "__syncthreads", - // dx - "llvm.dx.create.handle" => "__builtin_hlsl_create_handle", // hexagon "llvm.hexagon.A2.abs" => "__builtin_HEXAGON_A2_abs", "llvm.hexagon.A2.absp" => "__builtin_HEXAGON_A2_absp", @@ -1255,6 +1332,10 @@ match name { "llvm.hexagon.SI.to.SXTHI.asrh" => "__builtin_SI_to_SXTHI_asrh", "llvm.hexagon.V6.extractw" => "__builtin_HEXAGON_V6_extractw", "llvm.hexagon.V6.extractw.128B" => "__builtin_HEXAGON_V6_extractw_128B", + "llvm.hexagon.V6.get.qfext" => "__builtin_HEXAGON_V6_get_qfext", + "llvm.hexagon.V6.get.qfext.128B" => "__builtin_HEXAGON_V6_get_qfext_128B", + "llvm.hexagon.V6.get.qfext.oracc" => "__builtin_HEXAGON_V6_get_qfext_oracc", + "llvm.hexagon.V6.get.qfext.oracc.128B" => "__builtin_HEXAGON_V6_get_qfext_oracc_128B", "llvm.hexagon.V6.hi" => "__builtin_HEXAGON_V6_hi", "llvm.hexagon.V6.hi.128B" => "__builtin_HEXAGON_V6_hi_128B", "llvm.hexagon.V6.lo" => "__builtin_HEXAGON_V6_lo", @@ -1281,6 +1362,8 @@ match name { "llvm.hexagon.V6.pred.scalar2v2.128B" => "__builtin_HEXAGON_V6_pred_scalar2v2_128B", "llvm.hexagon.V6.pred.xor" => "__builtin_HEXAGON_V6_pred_xor", "llvm.hexagon.V6.pred.xor.128B" => "__builtin_HEXAGON_V6_pred_xor_128B", + "llvm.hexagon.V6.set.qfext" => "__builtin_HEXAGON_V6_set_qfext", + "llvm.hexagon.V6.set.qfext.128B" => "__builtin_HEXAGON_V6_set_qfext_128B", "llvm.hexagon.V6.shuffeqh" => "__builtin_HEXAGON_V6_shuffeqh", "llvm.hexagon.V6.shuffeqh.128B" => "__builtin_HEXAGON_V6_shuffeqh_128B", "llvm.hexagon.V6.shuffeqw" => "__builtin_HEXAGON_V6_shuffeqw", @@ -1301,6 +1384,8 @@ match name { "llvm.hexagon.V6.vS32b.nt.qpred.ai.128B" => "__builtin_HEXAGON_V6_vS32b_nt_qpred_ai_128B", "llvm.hexagon.V6.vS32b.qpred.ai" => "__builtin_HEXAGON_V6_vS32b_qpred_ai", "llvm.hexagon.V6.vS32b.qpred.ai.128B" => "__builtin_HEXAGON_V6_vS32b_qpred_ai_128B", + "llvm.hexagon.V6.vabs.f8" => "__builtin_HEXAGON_V6_vabs_f8", + "llvm.hexagon.V6.vabs.f8.128B" => "__builtin_HEXAGON_V6_vabs_f8_128B", "llvm.hexagon.V6.vabs.hf" => "__builtin_HEXAGON_V6_vabs_hf", "llvm.hexagon.V6.vabs.hf.128B" => "__builtin_HEXAGON_V6_vabs_hf_128B", "llvm.hexagon.V6.vabs.sf" => "__builtin_HEXAGON_V6_vabs_sf", @@ -1327,6 +1412,8 @@ match name { "llvm.hexagon.V6.vabsw.sat.128B" => "__builtin_HEXAGON_V6_vabsw_sat_128B", "llvm.hexagon.V6.vadd.hf" => "__builtin_HEXAGON_V6_vadd_hf", "llvm.hexagon.V6.vadd.hf.128B" => "__builtin_HEXAGON_V6_vadd_hf_128B", + "llvm.hexagon.V6.vadd.hf.f8" => "__builtin_HEXAGON_V6_vadd_hf_f8", + "llvm.hexagon.V6.vadd.hf.f8.128B" => "__builtin_HEXAGON_V6_vadd_hf_f8_128B", "llvm.hexagon.V6.vadd.hf.hf" => "__builtin_HEXAGON_V6_vadd_hf_hf", "llvm.hexagon.V6.vadd.hf.hf.128B" => "__builtin_HEXAGON_V6_vadd_hf_hf_128B", "llvm.hexagon.V6.vadd.qf16" => "__builtin_HEXAGON_V6_vadd_qf16", @@ -1549,10 +1636,14 @@ match name { "llvm.hexagon.V6.vcvt.b.hf.128B" => "__builtin_HEXAGON_V6_vcvt_b_hf_128B", "llvm.hexagon.V6.vcvt.bf.sf" => "__builtin_HEXAGON_V6_vcvt_bf_sf", "llvm.hexagon.V6.vcvt.bf.sf.128B" => "__builtin_HEXAGON_V6_vcvt_bf_sf_128B", + "llvm.hexagon.V6.vcvt.f8.hf" => "__builtin_HEXAGON_V6_vcvt_f8_hf", + "llvm.hexagon.V6.vcvt.f8.hf.128B" => "__builtin_HEXAGON_V6_vcvt_f8_hf_128B", "llvm.hexagon.V6.vcvt.h.hf" => "__builtin_HEXAGON_V6_vcvt_h_hf", "llvm.hexagon.V6.vcvt.h.hf.128B" => "__builtin_HEXAGON_V6_vcvt_h_hf_128B", "llvm.hexagon.V6.vcvt.hf.b" => "__builtin_HEXAGON_V6_vcvt_hf_b", "llvm.hexagon.V6.vcvt.hf.b.128B" => "__builtin_HEXAGON_V6_vcvt_hf_b_128B", + "llvm.hexagon.V6.vcvt.hf.f8" => "__builtin_HEXAGON_V6_vcvt_hf_f8", + "llvm.hexagon.V6.vcvt.hf.f8.128B" => "__builtin_HEXAGON_V6_vcvt_hf_f8_128B", "llvm.hexagon.V6.vcvt.hf.h" => "__builtin_HEXAGON_V6_vcvt_hf_h", "llvm.hexagon.V6.vcvt.hf.h.128B" => "__builtin_HEXAGON_V6_vcvt_hf_h_128B", "llvm.hexagon.V6.vcvt.hf.sf" => "__builtin_HEXAGON_V6_vcvt_hf_sf", @@ -1567,6 +1658,14 @@ match name { "llvm.hexagon.V6.vcvt.ub.hf.128B" => "__builtin_HEXAGON_V6_vcvt_ub_hf_128B", "llvm.hexagon.V6.vcvt.uh.hf" => "__builtin_HEXAGON_V6_vcvt_uh_hf", "llvm.hexagon.V6.vcvt.uh.hf.128B" => "__builtin_HEXAGON_V6_vcvt_uh_hf_128B", + "llvm.hexagon.V6.vcvt2.b.hf" => "__builtin_HEXAGON_V6_vcvt2_b_hf", + "llvm.hexagon.V6.vcvt2.b.hf.128B" => "__builtin_HEXAGON_V6_vcvt2_b_hf_128B", + "llvm.hexagon.V6.vcvt2.hf.b" => "__builtin_HEXAGON_V6_vcvt2_hf_b", + "llvm.hexagon.V6.vcvt2.hf.b.128B" => "__builtin_HEXAGON_V6_vcvt2_hf_b_128B", + "llvm.hexagon.V6.vcvt2.hf.ub" => "__builtin_HEXAGON_V6_vcvt2_hf_ub", + "llvm.hexagon.V6.vcvt2.hf.ub.128B" => "__builtin_HEXAGON_V6_vcvt2_hf_ub_128B", + "llvm.hexagon.V6.vcvt2.ub.hf" => "__builtin_HEXAGON_V6_vcvt2_ub_hf", + "llvm.hexagon.V6.vcvt2.ub.hf.128B" => "__builtin_HEXAGON_V6_vcvt2_ub_hf_128B", "llvm.hexagon.V6.vd0" => "__builtin_HEXAGON_V6_vd0", "llvm.hexagon.V6.vd0.128B" => "__builtin_HEXAGON_V6_vd0_128B", "llvm.hexagon.V6.vdd0" => "__builtin_HEXAGON_V6_vdd0", @@ -1649,14 +1748,20 @@ match name { "llvm.hexagon.V6.veqw.or.128B" => "__builtin_HEXAGON_V6_veqw_or_128B", "llvm.hexagon.V6.veqw.xor" => "__builtin_HEXAGON_V6_veqw_xor", "llvm.hexagon.V6.veqw.xor.128B" => "__builtin_HEXAGON_V6_veqw_xor_128B", + "llvm.hexagon.V6.vfmax.f8" => "__builtin_HEXAGON_V6_vfmax_f8", + "llvm.hexagon.V6.vfmax.f8.128B" => "__builtin_HEXAGON_V6_vfmax_f8_128B", "llvm.hexagon.V6.vfmax.hf" => "__builtin_HEXAGON_V6_vfmax_hf", "llvm.hexagon.V6.vfmax.hf.128B" => "__builtin_HEXAGON_V6_vfmax_hf_128B", "llvm.hexagon.V6.vfmax.sf" => "__builtin_HEXAGON_V6_vfmax_sf", "llvm.hexagon.V6.vfmax.sf.128B" => "__builtin_HEXAGON_V6_vfmax_sf_128B", + "llvm.hexagon.V6.vfmin.f8" => "__builtin_HEXAGON_V6_vfmin_f8", + "llvm.hexagon.V6.vfmin.f8.128B" => "__builtin_HEXAGON_V6_vfmin_f8_128B", "llvm.hexagon.V6.vfmin.hf" => "__builtin_HEXAGON_V6_vfmin_hf", "llvm.hexagon.V6.vfmin.hf.128B" => "__builtin_HEXAGON_V6_vfmin_hf_128B", "llvm.hexagon.V6.vfmin.sf" => "__builtin_HEXAGON_V6_vfmin_sf", "llvm.hexagon.V6.vfmin.sf.128B" => "__builtin_HEXAGON_V6_vfmin_sf_128B", + "llvm.hexagon.V6.vfneg.f8" => "__builtin_HEXAGON_V6_vfneg_f8", + "llvm.hexagon.V6.vfneg.f8.128B" => "__builtin_HEXAGON_V6_vfneg_f8_128B", "llvm.hexagon.V6.vfneg.hf" => "__builtin_HEXAGON_V6_vfneg_hf", "llvm.hexagon.V6.vfneg.hf.128B" => "__builtin_HEXAGON_V6_vfneg_hf_128B", "llvm.hexagon.V6.vfneg.sf" => "__builtin_HEXAGON_V6_vfneg_sf", @@ -1807,6 +1912,8 @@ match name { "llvm.hexagon.V6.vmaxuh.128B" => "__builtin_HEXAGON_V6_vmaxuh_128B", "llvm.hexagon.V6.vmaxw" => "__builtin_HEXAGON_V6_vmaxw", "llvm.hexagon.V6.vmaxw.128B" => "__builtin_HEXAGON_V6_vmaxw_128B", + "llvm.hexagon.V6.vmerge.qf" => "__builtin_HEXAGON_V6_vmerge_qf", + "llvm.hexagon.V6.vmerge.qf.128B" => "__builtin_HEXAGON_V6_vmerge_qf_128B", "llvm.hexagon.V6.vmin.bf" => "__builtin_HEXAGON_V6_vmin_bf", "llvm.hexagon.V6.vmin.bf.128B" => "__builtin_HEXAGON_V6_vmin_bf_128B", "llvm.hexagon.V6.vmin.hf" => "__builtin_HEXAGON_V6_vmin_hf", @@ -1849,6 +1956,10 @@ match name { "llvm.hexagon.V6.vmpauhuhsat.128B" => "__builtin_HEXAGON_V6_vmpauhuhsat_128B", "llvm.hexagon.V6.vmpsuhuhsat" => "__builtin_HEXAGON_V6_vmpsuhuhsat", "llvm.hexagon.V6.vmpsuhuhsat.128B" => "__builtin_HEXAGON_V6_vmpsuhuhsat_128B", + "llvm.hexagon.V6.vmpy.hf.f8" => "__builtin_HEXAGON_V6_vmpy_hf_f8", + "llvm.hexagon.V6.vmpy.hf.f8.128B" => "__builtin_HEXAGON_V6_vmpy_hf_f8_128B", + "llvm.hexagon.V6.vmpy.hf.f8.acc" => "__builtin_HEXAGON_V6_vmpy_hf_f8_acc", + "llvm.hexagon.V6.vmpy.hf.f8.acc.128B" => "__builtin_HEXAGON_V6_vmpy_hf_f8_acc_128B", "llvm.hexagon.V6.vmpy.hf.hf" => "__builtin_HEXAGON_V6_vmpy_hf_hf", "llvm.hexagon.V6.vmpy.hf.hf.128B" => "__builtin_HEXAGON_V6_vmpy_hf_hf_128B", "llvm.hexagon.V6.vmpy.hf.hf.acc" => "__builtin_HEXAGON_V6_vmpy_hf_hf_acc", @@ -1869,6 +1980,12 @@ match name { "llvm.hexagon.V6.vmpy.qf32.qf16.128B" => "__builtin_HEXAGON_V6_vmpy_qf32_qf16_128B", "llvm.hexagon.V6.vmpy.qf32.sf" => "__builtin_HEXAGON_V6_vmpy_qf32_sf", "llvm.hexagon.V6.vmpy.qf32.sf.128B" => "__builtin_HEXAGON_V6_vmpy_qf32_sf_128B", + "llvm.hexagon.V6.vmpy.rt.hf" => "__builtin_HEXAGON_V6_vmpy_rt_hf", + "llvm.hexagon.V6.vmpy.rt.hf.128B" => "__builtin_HEXAGON_V6_vmpy_rt_hf_128B", + "llvm.hexagon.V6.vmpy.rt.qf16" => "__builtin_HEXAGON_V6_vmpy_rt_qf16", + "llvm.hexagon.V6.vmpy.rt.qf16.128B" => "__builtin_HEXAGON_V6_vmpy_rt_qf16_128B", + "llvm.hexagon.V6.vmpy.rt.sf" => "__builtin_HEXAGON_V6_vmpy_rt_sf", + "llvm.hexagon.V6.vmpy.rt.sf.128B" => "__builtin_HEXAGON_V6_vmpy_rt_sf_128B", "llvm.hexagon.V6.vmpy.sf.bf" => "__builtin_HEXAGON_V6_vmpy_sf_bf", "llvm.hexagon.V6.vmpy.sf.bf.128B" => "__builtin_HEXAGON_V6_vmpy_sf_bf_128B", "llvm.hexagon.V6.vmpy.sf.bf.acc" => "__builtin_HEXAGON_V6_vmpy_sf_bf_acc", @@ -2127,6 +2244,8 @@ match name { "llvm.hexagon.V6.vshufoh.128B" => "__builtin_HEXAGON_V6_vshufoh_128B", "llvm.hexagon.V6.vsub.hf" => "__builtin_HEXAGON_V6_vsub_hf", "llvm.hexagon.V6.vsub.hf.128B" => "__builtin_HEXAGON_V6_vsub_hf_128B", + "llvm.hexagon.V6.vsub.hf.f8" => "__builtin_HEXAGON_V6_vsub_hf_f8", + "llvm.hexagon.V6.vsub.hf.f8.128B" => "__builtin_HEXAGON_V6_vsub_hf_f8_128B", "llvm.hexagon.V6.vsub.hf.hf" => "__builtin_HEXAGON_V6_vsub_hf_hf", "llvm.hexagon.V6.vsub.hf.hf.128B" => "__builtin_HEXAGON_V6_vsub_hf_hf_128B", "llvm.hexagon.V6.vsub.qf16" => "__builtin_HEXAGON_V6_vsub_qf16", @@ -4445,8 +4564,6 @@ match name { "llvm.mips.xor.v" => "__builtin_msa_xor_v", "llvm.mips.xori.b" => "__builtin_msa_xori_b", // nvvm - "llvm.nvvm.abs.bf16" => "__nvvm_abs_bf16", - "llvm.nvvm.abs.bf16x2" => "__nvvm_abs_bf16x2", "llvm.nvvm.abs.i" => "__nvvm_abs_i", "llvm.nvvm.abs.ll" => "__nvvm_abs_ll", "llvm.nvvm.activemask" => "__nvvm_activemask", @@ -4473,6 +4590,10 @@ match name { "llvm.nvvm.barrier0.and" => "__nvvm_bar0_and", "llvm.nvvm.barrier0.or" => "__nvvm_bar0_or", "llvm.nvvm.barrier0.popc" => "__nvvm_bar0_popc", + "llvm.nvvm.bf16x2.to.ue8m0x2.rp" => "__nvvm_bf16x2_to_ue8m0x2_rp", + "llvm.nvvm.bf16x2.to.ue8m0x2.rp.satfinite" => "__nvvm_bf16x2_to_ue8m0x2_rp_satfinite", + "llvm.nvvm.bf16x2.to.ue8m0x2.rz" => "__nvvm_bf16x2_to_ue8m0x2_rz", + "llvm.nvvm.bf16x2.to.ue8m0x2.rz.satfinite" => "__nvvm_bf16x2_to_ue8m0x2_rz_satfinite", "llvm.nvvm.bf2h.rn" => "__nvvm_bf2h_rn", "llvm.nvvm.bf2h.rn.ftz" => "__nvvm_bf2h_rn_ftz", "llvm.nvvm.bitcast.d2ll" => "__nvvm_bitcast_d2ll", @@ -4523,6 +4644,8 @@ match name { "llvm.nvvm.d2ull.rz" => "__nvvm_d2ull_rz", "llvm.nvvm.div.approx.f" => "__nvvm_div_approx_f", "llvm.nvvm.div.approx.ftz.f" => "__nvvm_div_approx_ftz_f", + "llvm.nvvm.div.full" => "__nvvm_div_full", + "llvm.nvvm.div.full.ftz" => "__nvvm_div_full_ftz", "llvm.nvvm.div.rm.d" => "__nvvm_div_rm_d", "llvm.nvvm.div.rm.f" => "__nvvm_div_rm_f", "llvm.nvvm.div.rm.ftz.f" => "__nvvm_div_rm_ftz_f", @@ -4535,6 +4658,10 @@ match name { "llvm.nvvm.div.rz.d" => "__nvvm_div_rz_d", "llvm.nvvm.div.rz.f" => "__nvvm_div_rz_f", "llvm.nvvm.div.rz.ftz.f" => "__nvvm_div_rz_ftz_f", + "llvm.nvvm.e2m3x2.to.f16x2.rn" => "__nvvm_e2m3x2_to_f16x2_rn", + "llvm.nvvm.e2m3x2.to.f16x2.rn.relu" => "__nvvm_e2m3x2_to_f16x2_rn_relu", + "llvm.nvvm.e3m2x2.to.f16x2.rn" => "__nvvm_e3m2x2_to_f16x2_rn", + "llvm.nvvm.e3m2x2.to.f16x2.rn.relu" => "__nvvm_e3m2x2_to_f16x2_rn_relu", "llvm.nvvm.e4m3x2.to.f16x2.rn" => "__nvvm_e4m3x2_to_f16x2_rn", "llvm.nvvm.e4m3x2.to.f16x2.rn.relu" => "__nvvm_e4m3x2_to_f16x2_rn_relu", "llvm.nvvm.e5m2x2.to.f16x2.rn" => "__nvvm_e5m2x2_to_f16x2_rn", @@ -4569,7 +4696,16 @@ match name { "llvm.nvvm.f2ll.rp.ftz" => "__nvvm_f2ll_rp_ftz", "llvm.nvvm.f2ll.rz" => "__nvvm_f2ll_rz", "llvm.nvvm.f2ll.rz.ftz" => "__nvvm_f2ll_rz_ftz", + "llvm.nvvm.f2tf32.rn" => "__nvvm_f2tf32_rn", + "llvm.nvvm.f2tf32.rn.relu" => "__nvvm_f2tf32_rn_relu", + "llvm.nvvm.f2tf32.rn.relu.satfinite" => "__nvvm_f2tf32_rn_relu_satfinite", + "llvm.nvvm.f2tf32.rn.satfinite" => "__nvvm_f2tf32_rn_satfinite", "llvm.nvvm.f2tf32.rna" => "__nvvm_f2tf32_rna", + "llvm.nvvm.f2tf32.rna.satfinite" => "__nvvm_f2tf32_rna_satfinite", + "llvm.nvvm.f2tf32.rz" => "__nvvm_f2tf32_rz", + "llvm.nvvm.f2tf32.rz.relu" => "__nvvm_f2tf32_rz_relu", + "llvm.nvvm.f2tf32.rz.relu.satfinite" => "__nvvm_f2tf32_rz_relu_satfinite", + "llvm.nvvm.f2tf32.rz.satfinite" => "__nvvm_f2tf32_rz_satfinite", "llvm.nvvm.f2ui.rm" => "__nvvm_f2ui_rm", "llvm.nvvm.f2ui.rm.ftz" => "__nvvm_f2ui_rm_ftz", "llvm.nvvm.f2ui.rn" => "__nvvm_f2ui_rn", @@ -4589,10 +4725,18 @@ match name { "llvm.nvvm.fabs.d" => "__nvvm_fabs_d", "llvm.nvvm.fabs.f" => "__nvvm_fabs_f", "llvm.nvvm.fabs.ftz.f" => "__nvvm_fabs_ftz_f", + "llvm.nvvm.ff.to.e2m3x2.rn.relu.satfinite" => "__nvvm_ff_to_e2m3x2_rn_relu_satfinite", + "llvm.nvvm.ff.to.e2m3x2.rn.satfinite" => "__nvvm_ff_to_e2m3x2_rn_satfinite", + "llvm.nvvm.ff.to.e3m2x2.rn.relu.satfinite" => "__nvvm_ff_to_e3m2x2_rn_relu_satfinite", + "llvm.nvvm.ff.to.e3m2x2.rn.satfinite" => "__nvvm_ff_to_e3m2x2_rn_satfinite", "llvm.nvvm.ff.to.e4m3x2.rn" => "__nvvm_ff_to_e4m3x2_rn", "llvm.nvvm.ff.to.e4m3x2.rn.relu" => "__nvvm_ff_to_e4m3x2_rn_relu", "llvm.nvvm.ff.to.e5m2x2.rn" => "__nvvm_ff_to_e5m2x2_rn", "llvm.nvvm.ff.to.e5m2x2.rn.relu" => "__nvvm_ff_to_e5m2x2_rn_relu", + "llvm.nvvm.ff.to.ue8m0x2.rp" => "__nvvm_ff_to_ue8m0x2_rp", + "llvm.nvvm.ff.to.ue8m0x2.rp.satfinite" => "__nvvm_ff_to_ue8m0x2_rp_satfinite", + "llvm.nvvm.ff.to.ue8m0x2.rz" => "__nvvm_ff_to_ue8m0x2_rz", + "llvm.nvvm.ff.to.ue8m0x2.rz.satfinite" => "__nvvm_ff_to_ue8m0x2_rz_satfinite", "llvm.nvvm.ff2bf16x2.rn" => "__nvvm_ff2bf16x2_rn", "llvm.nvvm.ff2bf16x2.rn.relu" => "__nvvm_ff2bf16x2_rn_relu", "llvm.nvvm.ff2bf16x2.rz" => "__nvvm_ff2bf16x2_rz", @@ -4862,6 +5006,14 @@ match name { // [DUPLICATE]: "llvm.nvvm.read.ptx.sreg.warpsize" => "__nvvm_read_ptx_sreg_", "llvm.nvvm.redux.sync.add" => "__nvvm_redux_sync_add", "llvm.nvvm.redux.sync.and" => "__nvvm_redux_sync_and", + "llvm.nvvm.redux.sync.fmax" => "__nvvm_redux_sync_fmax", + "llvm.nvvm.redux.sync.fmax.NaN" => "__nvvm_redux_sync_fmax_NaN", + "llvm.nvvm.redux.sync.fmax.abs" => "__nvvm_redux_sync_fmax_abs", + "llvm.nvvm.redux.sync.fmax.abs.NaN" => "__nvvm_redux_sync_fmax_abs_NaN", + "llvm.nvvm.redux.sync.fmin" => "__nvvm_redux_sync_fmin", + "llvm.nvvm.redux.sync.fmin.NaN" => "__nvvm_redux_sync_fmin_NaN", + "llvm.nvvm.redux.sync.fmin.abs" => "__nvvm_redux_sync_fmin_abs", + "llvm.nvvm.redux.sync.fmin.abs.NaN" => "__nvvm_redux_sync_fmin_abs_NaN", "llvm.nvvm.redux.sync.max" => "__nvvm_redux_sync_max", "llvm.nvvm.redux.sync.min" => "__nvvm_redux_sync_min", "llvm.nvvm.redux.sync.or" => "__nvvm_redux_sync_or", @@ -5149,6 +5301,7 @@ match name { "llvm.nvvm.txq.num.mipmap.levels" => "__nvvm_txq_num_mipmap_levels", "llvm.nvvm.txq.num.samples" => "__nvvm_txq_num_samples", "llvm.nvvm.txq.width" => "__nvvm_txq_width", + "llvm.nvvm.ue8m0x2.to.bf16x2" => "__nvvm_ue8m0x2_to_bf16x2", "llvm.nvvm.ui2d.rm" => "__nvvm_ui2d_rm", "llvm.nvvm.ui2d.rn" => "__nvvm_ui2d_rn", "llvm.nvvm.ui2d.rp" => "__nvvm_ui2d_rp", @@ -5783,6 +5936,9 @@ match name { "llvm.r600.read.tgid.x" => "__builtin_r600_read_tgid_x", "llvm.r600.read.tgid.y" => "__builtin_r600_read_tgid_y", "llvm.r600.read.tgid.z" => "__builtin_r600_read_tgid_z", + "llvm.r600.read.tidig.x" => "__builtin_r600_read_tidig_x", + "llvm.r600.read.tidig.y" => "__builtin_r600_read_tidig_y", + "llvm.r600.read.tidig.z" => "__builtin_r600_read_tidig_z", // riscv "llvm.riscv.aes32dsi" => "__builtin_riscv_aes32dsi", "llvm.riscv.aes32dsmi" => "__builtin_riscv_aes32dsmi", @@ -5806,6 +5962,8 @@ match name { "llvm.riscv.sha512sum1" => "__builtin_riscv_sha512sum1", "llvm.riscv.sha512sum1r" => "__builtin_riscv_sha512sum1r", // s390 + "llvm.s390.bdepg" => "__builtin_s390_bdepg", + "llvm.s390.bextg" => "__builtin_s390_bextg", "llvm.s390.efpc" => "__builtin_s390_efpc", "llvm.s390.etnd" => "__builtin_tx_nesting_depth", "llvm.s390.lcbb" => "__builtin_s390_lcbb", @@ -5828,6 +5986,8 @@ match name { "llvm.s390.vavglf" => "__builtin_s390_vavglf", "llvm.s390.vavglg" => "__builtin_s390_vavglg", "llvm.s390.vavglh" => "__builtin_s390_vavglh", + "llvm.s390.vavglq" => "__builtin_s390_vavglq", + "llvm.s390.vavgq" => "__builtin_s390_vavgq", "llvm.s390.vbperm" => "__builtin_s390_vbperm", "llvm.s390.vcfn" => "__builtin_s390_vcfn", "llvm.s390.vcksm" => "__builtin_s390_vcksm", @@ -5839,6 +5999,7 @@ match name { "llvm.s390.verimf" => "__builtin_s390_verimf", "llvm.s390.verimg" => "__builtin_s390_verimg", "llvm.s390.verimh" => "__builtin_s390_verimh", + "llvm.s390.veval" => "__builtin_s390_veval", "llvm.s390.vfaeb" => "__builtin_s390_vfaeb", "llvm.s390.vfaef" => "__builtin_s390_vfaef", "llvm.s390.vfaeh" => "__builtin_s390_vfaeh", @@ -5857,6 +6018,11 @@ match name { "llvm.s390.vfenezb" => "__builtin_s390_vfenezb", "llvm.s390.vfenezf" => "__builtin_s390_vfenezf", "llvm.s390.vfenezh" => "__builtin_s390_vfenezh", + "llvm.s390.vgemb" => "__builtin_s390_vgemb", + "llvm.s390.vgemf" => "__builtin_s390_vgemf", + "llvm.s390.vgemg" => "__builtin_s390_vgemg", + "llvm.s390.vgemh" => "__builtin_s390_vgemh", + "llvm.s390.vgemq" => "__builtin_s390_vgemq", "llvm.s390.vgfmab" => "__builtin_s390_vgfmab", "llvm.s390.vgfmaf" => "__builtin_s390_vgfmaf", "llvm.s390.vgfmag" => "__builtin_s390_vgfmag", @@ -5873,39 +6039,55 @@ match name { "llvm.s390.vlrl" => "__builtin_s390_vlrlr", "llvm.s390.vmaeb" => "__builtin_s390_vmaeb", "llvm.s390.vmaef" => "__builtin_s390_vmaef", + "llvm.s390.vmaeg" => "__builtin_s390_vmaeg", "llvm.s390.vmaeh" => "__builtin_s390_vmaeh", "llvm.s390.vmahb" => "__builtin_s390_vmahb", "llvm.s390.vmahf" => "__builtin_s390_vmahf", + "llvm.s390.vmahg" => "__builtin_s390_vmahg", "llvm.s390.vmahh" => "__builtin_s390_vmahh", + "llvm.s390.vmahq" => "__builtin_s390_vmahq", "llvm.s390.vmaleb" => "__builtin_s390_vmaleb", "llvm.s390.vmalef" => "__builtin_s390_vmalef", + "llvm.s390.vmaleg" => "__builtin_s390_vmaleg", "llvm.s390.vmaleh" => "__builtin_s390_vmaleh", "llvm.s390.vmalhb" => "__builtin_s390_vmalhb", "llvm.s390.vmalhf" => "__builtin_s390_vmalhf", + "llvm.s390.vmalhg" => "__builtin_s390_vmalhg", "llvm.s390.vmalhh" => "__builtin_s390_vmalhh", + "llvm.s390.vmalhq" => "__builtin_s390_vmalhq", "llvm.s390.vmalob" => "__builtin_s390_vmalob", "llvm.s390.vmalof" => "__builtin_s390_vmalof", + "llvm.s390.vmalog" => "__builtin_s390_vmalog", "llvm.s390.vmaloh" => "__builtin_s390_vmaloh", "llvm.s390.vmaob" => "__builtin_s390_vmaob", "llvm.s390.vmaof" => "__builtin_s390_vmaof", + "llvm.s390.vmaog" => "__builtin_s390_vmaog", "llvm.s390.vmaoh" => "__builtin_s390_vmaoh", "llvm.s390.vmeb" => "__builtin_s390_vmeb", "llvm.s390.vmef" => "__builtin_s390_vmef", + "llvm.s390.vmeg" => "__builtin_s390_vmeg", "llvm.s390.vmeh" => "__builtin_s390_vmeh", "llvm.s390.vmhb" => "__builtin_s390_vmhb", "llvm.s390.vmhf" => "__builtin_s390_vmhf", + "llvm.s390.vmhg" => "__builtin_s390_vmhg", "llvm.s390.vmhh" => "__builtin_s390_vmhh", + "llvm.s390.vmhq" => "__builtin_s390_vmhq", "llvm.s390.vmleb" => "__builtin_s390_vmleb", "llvm.s390.vmlef" => "__builtin_s390_vmlef", + "llvm.s390.vmleg" => "__builtin_s390_vmleg", "llvm.s390.vmleh" => "__builtin_s390_vmleh", "llvm.s390.vmlhb" => "__builtin_s390_vmlhb", "llvm.s390.vmlhf" => "__builtin_s390_vmlhf", + "llvm.s390.vmlhg" => "__builtin_s390_vmlhg", "llvm.s390.vmlhh" => "__builtin_s390_vmlhh", + "llvm.s390.vmlhq" => "__builtin_s390_vmlhq", "llvm.s390.vmlob" => "__builtin_s390_vmlob", "llvm.s390.vmlof" => "__builtin_s390_vmlof", + "llvm.s390.vmlog" => "__builtin_s390_vmlog", "llvm.s390.vmloh" => "__builtin_s390_vmloh", "llvm.s390.vmob" => "__builtin_s390_vmob", "llvm.s390.vmof" => "__builtin_s390_vmof", + "llvm.s390.vmog" => "__builtin_s390_vmog", "llvm.s390.vmoh" => "__builtin_s390_vmoh", "llvm.s390.vmslg" => "__builtin_s390_vmslg", "llvm.s390.vpdi" => "__builtin_s390_vpdi", @@ -5950,18 +6132,20 @@ match name { "llvm.s390.vtm" => "__builtin_s390_vtm", "llvm.s390.vuphb" => "__builtin_s390_vuphb", "llvm.s390.vuphf" => "__builtin_s390_vuphf", + "llvm.s390.vuphg" => "__builtin_s390_vuphg", "llvm.s390.vuphh" => "__builtin_s390_vuphh", "llvm.s390.vuplb" => "__builtin_s390_vuplb", "llvm.s390.vuplf" => "__builtin_s390_vuplf", + "llvm.s390.vuplg" => "__builtin_s390_vuplg", "llvm.s390.vuplhb" => "__builtin_s390_vuplhb", "llvm.s390.vuplhf" => "__builtin_s390_vuplhf", + "llvm.s390.vuplhg" => "__builtin_s390_vuplhg", "llvm.s390.vuplhh" => "__builtin_s390_vuplhh", "llvm.s390.vuplhw" => "__builtin_s390_vuplhw", "llvm.s390.vupllb" => "__builtin_s390_vupllb", "llvm.s390.vupllf" => "__builtin_s390_vupllf", + "llvm.s390.vupllg" => "__builtin_s390_vupllg", "llvm.s390.vupllh" => "__builtin_s390_vupllh", - // spv - "llvm.spv.create.handle" => "__builtin_hlsl_create_handle", // ve "llvm.ve.vl.andm.MMM" => "__builtin_ve_vl_andm_MMM", "llvm.ve.vl.andm.mmm" => "__builtin_ve_vl_andm_mmm", @@ -7328,6 +7512,27 @@ match name { "llvm.x86.avx.vtestz.ps.256" => "__builtin_ia32_vtestzps256", "llvm.x86.avx.vzeroall" => "__builtin_ia32_vzeroall", "llvm.x86.avx.vzeroupper" => "__builtin_ia32_vzeroupper", + "llvm.x86.avx10.mask.getexp.bf16.128" => "__builtin_ia32_vgetexpbf16128_mask", + "llvm.x86.avx10.mask.getexp.bf16.256" => "__builtin_ia32_vgetexpbf16256_mask", + "llvm.x86.avx10.mask.getexp.bf16.512" => "__builtin_ia32_vgetexpbf16512_mask", + "llvm.x86.avx10.mask.getmant.bf16.128" => "__builtin_ia32_vgetmantbf16128_mask", + "llvm.x86.avx10.mask.getmant.bf16.256" => "__builtin_ia32_vgetmantbf16256_mask", + "llvm.x86.avx10.mask.getmant.bf16.512" => "__builtin_ia32_vgetmantbf16512_mask", + "llvm.x86.avx10.mask.rcp.bf16.128" => "__builtin_ia32_vrcpbf16128_mask", + "llvm.x86.avx10.mask.rcp.bf16.256" => "__builtin_ia32_vrcpbf16256_mask", + "llvm.x86.avx10.mask.rcp.bf16.512" => "__builtin_ia32_vrcpbf16512_mask", + "llvm.x86.avx10.mask.reduce.bf16.128" => "__builtin_ia32_vreducebf16128_mask", + "llvm.x86.avx10.mask.reduce.bf16.256" => "__builtin_ia32_vreducebf16256_mask", + "llvm.x86.avx10.mask.reduce.bf16.512" => "__builtin_ia32_vreducebf16512_mask", + "llvm.x86.avx10.mask.rndscale.bf16.128" => "__builtin_ia32_vrndscalebf16_128_mask", + "llvm.x86.avx10.mask.rndscale.bf16.256" => "__builtin_ia32_vrndscalebf16_256_mask", + "llvm.x86.avx10.mask.rndscale.bf16.512" => "__builtin_ia32_vrndscalebf16_mask", + "llvm.x86.avx10.mask.rsqrt.bf16.128" => "__builtin_ia32_vrsqrtbf16128_mask", + "llvm.x86.avx10.mask.rsqrt.bf16.256" => "__builtin_ia32_vrsqrtbf16256_mask", + "llvm.x86.avx10.mask.rsqrt.bf16.512" => "__builtin_ia32_vrsqrtbf16512_mask", + "llvm.x86.avx10.mask.scalef.bf16.128" => "__builtin_ia32_vscalefbf16128_mask", + "llvm.x86.avx10.mask.scalef.bf16.256" => "__builtin_ia32_vscalefbf16256_mask", + "llvm.x86.avx10.mask.scalef.bf16.512" => "__builtin_ia32_vscalefbf16512_mask", "llvm.x86.avx10.mask.vcvt2ps2phx.128" => "__builtin_ia32_vcvt2ps2phx128_mask", "llvm.x86.avx10.mask.vcvt2ps2phx.256" => "__builtin_ia32_vcvt2ps2phx256_mask", "llvm.x86.avx10.mask.vcvt2ps2phx.512" => "__builtin_ia32_vcvt2ps2phx512_mask", @@ -7346,171 +7551,194 @@ match name { "llvm.x86.avx10.mask.vcvthf82ph128" => "__builtin_ia32_vcvthf8_2ph128_mask", "llvm.x86.avx10.mask.vcvthf82ph256" => "__builtin_ia32_vcvthf8_2ph256_mask", "llvm.x86.avx10.mask.vcvthf82ph512" => "__builtin_ia32_vcvthf8_2ph512_mask", - "llvm.x86.avx10.mask.vcvtneph2bf8128" => "__builtin_ia32_vcvtneph2bf8_128_mask", - "llvm.x86.avx10.mask.vcvtneph2bf8256" => "__builtin_ia32_vcvtneph2bf8_256_mask", - "llvm.x86.avx10.mask.vcvtneph2bf8512" => "__builtin_ia32_vcvtneph2bf8_512_mask", - "llvm.x86.avx10.mask.vcvtneph2bf8s128" => "__builtin_ia32_vcvtneph2bf8s_128_mask", - "llvm.x86.avx10.mask.vcvtneph2bf8s256" => "__builtin_ia32_vcvtneph2bf8s_256_mask", - "llvm.x86.avx10.mask.vcvtneph2bf8s512" => "__builtin_ia32_vcvtneph2bf8s_512_mask", - "llvm.x86.avx10.mask.vcvtneph2hf8128" => "__builtin_ia32_vcvtneph2hf8_128_mask", - "llvm.x86.avx10.mask.vcvtneph2hf8256" => "__builtin_ia32_vcvtneph2hf8_256_mask", - "llvm.x86.avx10.mask.vcvtneph2hf8512" => "__builtin_ia32_vcvtneph2hf8_512_mask", - "llvm.x86.avx10.mask.vcvtneph2hf8s128" => "__builtin_ia32_vcvtneph2hf8s_128_mask", - "llvm.x86.avx10.mask.vcvtneph2hf8s256" => "__builtin_ia32_vcvtneph2hf8s_256_mask", - "llvm.x86.avx10.mask.vcvtneph2hf8s512" => "__builtin_ia32_vcvtneph2hf8s_512_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtpd2dq256" => "__builtin_ia32_vcvtpd2dq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtpd2ph256" => "__builtin_ia32_vcvtpd2ph256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtpd2ps256" => "__builtin_ia32_vcvtpd2ps256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtpd2qq256" => "__builtin_ia32_vcvtpd2qq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtpd2udq256" => "__builtin_ia32_vcvtpd2udq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtpd2uqq256" => "__builtin_ia32_vcvtpd2uqq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2dq256" => "__builtin_ia32_vcvtph2dq256_round_mask", + "llvm.x86.avx10.mask.vcvtph2bf8128" => "__builtin_ia32_vcvtph2bf8_128_mask", + "llvm.x86.avx10.mask.vcvtph2bf8256" => "__builtin_ia32_vcvtph2bf8_256_mask", + "llvm.x86.avx10.mask.vcvtph2bf8512" => "__builtin_ia32_vcvtph2bf8_512_mask", + "llvm.x86.avx10.mask.vcvtph2bf8s128" => "__builtin_ia32_vcvtph2bf8s_128_mask", + "llvm.x86.avx10.mask.vcvtph2bf8s256" => "__builtin_ia32_vcvtph2bf8s_256_mask", + "llvm.x86.avx10.mask.vcvtph2bf8s512" => "__builtin_ia32_vcvtph2bf8s_512_mask", + "llvm.x86.avx10.mask.vcvtph2hf8128" => "__builtin_ia32_vcvtph2hf8_128_mask", + "llvm.x86.avx10.mask.vcvtph2hf8256" => "__builtin_ia32_vcvtph2hf8_256_mask", + "llvm.x86.avx10.mask.vcvtph2hf8512" => "__builtin_ia32_vcvtph2hf8_512_mask", + "llvm.x86.avx10.mask.vcvtph2hf8s128" => "__builtin_ia32_vcvtph2hf8s_128_mask", + "llvm.x86.avx10.mask.vcvtph2hf8s256" => "__builtin_ia32_vcvtph2hf8s_256_mask", + "llvm.x86.avx10.mask.vcvtph2hf8s512" => "__builtin_ia32_vcvtph2hf8s_512_mask", "llvm.x86.avx10.mask.vcvtph2ibs128" => "__builtin_ia32_vcvtph2ibs128_mask", "llvm.x86.avx10.mask.vcvtph2ibs256" => "__builtin_ia32_vcvtph2ibs256_mask", "llvm.x86.avx10.mask.vcvtph2ibs512" => "__builtin_ia32_vcvtph2ibs512_mask", "llvm.x86.avx10.mask.vcvtph2iubs128" => "__builtin_ia32_vcvtph2iubs128_mask", "llvm.x86.avx10.mask.vcvtph2iubs256" => "__builtin_ia32_vcvtph2iubs256_mask", "llvm.x86.avx10.mask.vcvtph2iubs512" => "__builtin_ia32_vcvtph2iubs512_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2pd256" => "__builtin_ia32_vcvtph2pd256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2psx256" => "__builtin_ia32_vcvtph2psx256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2qq256" => "__builtin_ia32_vcvtph2qq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2udq256" => "__builtin_ia32_vcvtph2udq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2uqq256" => "__builtin_ia32_vcvtph2uqq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2uw256" => "__builtin_ia32_vcvtph2uw256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2w256" => "__builtin_ia32_vcvtph2w256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2dq256" => "__builtin_ia32_vcvtps2dq256_round_mask", "llvm.x86.avx10.mask.vcvtps2ibs128" => "__builtin_ia32_vcvtps2ibs128_mask", "llvm.x86.avx10.mask.vcvtps2ibs256" => "__builtin_ia32_vcvtps2ibs256_mask", "llvm.x86.avx10.mask.vcvtps2ibs512" => "__builtin_ia32_vcvtps2ibs512_mask", "llvm.x86.avx10.mask.vcvtps2iubs128" => "__builtin_ia32_vcvtps2iubs128_mask", "llvm.x86.avx10.mask.vcvtps2iubs256" => "__builtin_ia32_vcvtps2iubs256_mask", "llvm.x86.avx10.mask.vcvtps2iubs512" => "__builtin_ia32_vcvtps2iubs512_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2pd256" => "__builtin_ia32_vcvtps2pd256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2ph256" => "__builtin_ia32_vcvtps2ph256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2phx256" => "__builtin_ia32_vcvtps2phx256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2qq256" => "__builtin_ia32_vcvtps2qq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2udq256" => "__builtin_ia32_vcvtps2udq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2uqq256" => "__builtin_ia32_vcvtps2uqq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttpd2dq256" => "__builtin_ia32_vcvttpd2dq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttpd2qq256" => "__builtin_ia32_vcvttpd2qq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttpd2udq256" => "__builtin_ia32_vcvttpd2udq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttpd2uqq256" => "__builtin_ia32_vcvttpd2uqq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttph2dq256" => "__builtin_ia32_vcvttph2dq256_round_mask", + "llvm.x86.avx10.mask.vcvttpd2dqs.128" => "__builtin_ia32_vcvttpd2dqs128_mask", + "llvm.x86.avx10.mask.vcvttpd2dqs.256" => "__builtin_ia32_vcvttpd2dqs256_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttpd2dqs.round.512" => "__builtin_ia32_vcvttpd2dqs512_round_mask", + "llvm.x86.avx10.mask.vcvttpd2qqs.128" => "__builtin_ia32_vcvttpd2qqs128_mask", + "llvm.x86.avx10.mask.vcvttpd2qqs.256" => "__builtin_ia32_vcvttpd2qqs256_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttpd2qqs.round.512" => "__builtin_ia32_vcvttpd2qqs512_round_mask", + "llvm.x86.avx10.mask.vcvttpd2udqs.128" => "__builtin_ia32_vcvttpd2udqs128_mask", + "llvm.x86.avx10.mask.vcvttpd2udqs.256" => "__builtin_ia32_vcvttpd2udqs256_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttpd2udqs.round.512" => "__builtin_ia32_vcvttpd2udqs512_round_mask", + "llvm.x86.avx10.mask.vcvttpd2uqqs.128" => "__builtin_ia32_vcvttpd2uqqs128_mask", + "llvm.x86.avx10.mask.vcvttpd2uqqs.256" => "__builtin_ia32_vcvttpd2uqqs256_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttpd2uqqs.round.512" => "__builtin_ia32_vcvttpd2uqqs512_round_mask", "llvm.x86.avx10.mask.vcvttph2ibs128" => "__builtin_ia32_vcvttph2ibs128_mask", "llvm.x86.avx10.mask.vcvttph2ibs256" => "__builtin_ia32_vcvttph2ibs256_mask", "llvm.x86.avx10.mask.vcvttph2ibs512" => "__builtin_ia32_vcvttph2ibs512_mask", "llvm.x86.avx10.mask.vcvttph2iubs128" => "__builtin_ia32_vcvttph2iubs128_mask", "llvm.x86.avx10.mask.vcvttph2iubs256" => "__builtin_ia32_vcvttph2iubs256_mask", "llvm.x86.avx10.mask.vcvttph2iubs512" => "__builtin_ia32_vcvttph2iubs512_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttph2qq256" => "__builtin_ia32_vcvttph2qq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttph2udq256" => "__builtin_ia32_vcvttph2udq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttph2uqq256" => "__builtin_ia32_vcvttph2uqq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttph2uw256" => "__builtin_ia32_vcvttph2uw256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttph2w256" => "__builtin_ia32_vcvttph2w256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttps2dq256" => "__builtin_ia32_vcvttps2dq256_round_mask", + "llvm.x86.avx10.mask.vcvttps2dqs.128" => "__builtin_ia32_vcvttps2dqs128_mask", + "llvm.x86.avx10.mask.vcvttps2dqs.256" => "__builtin_ia32_vcvttps2dqs256_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttps2dqs.round.512" => "__builtin_ia32_vcvttps2dqs512_round_mask", "llvm.x86.avx10.mask.vcvttps2ibs128" => "__builtin_ia32_vcvttps2ibs128_mask", "llvm.x86.avx10.mask.vcvttps2ibs256" => "__builtin_ia32_vcvttps2ibs256_mask", "llvm.x86.avx10.mask.vcvttps2ibs512" => "__builtin_ia32_vcvttps2ibs512_mask", "llvm.x86.avx10.mask.vcvttps2iubs128" => "__builtin_ia32_vcvttps2iubs128_mask", "llvm.x86.avx10.mask.vcvttps2iubs256" => "__builtin_ia32_vcvttps2iubs256_mask", "llvm.x86.avx10.mask.vcvttps2iubs512" => "__builtin_ia32_vcvttps2iubs512_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttps2qq256" => "__builtin_ia32_vcvttps2qq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttps2udq256" => "__builtin_ia32_vcvttps2udq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttps2uqq256" => "__builtin_ia32_vcvttps2uqq256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vfcmaddcph256" => "__builtin_ia32_vfcmaddcph256_round_mask3", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vfcmulcph256" => "__builtin_ia32_vfcmulcph256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vfixupimmpd256" => "__builtin_ia32_vfixupimmpd256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vfixupimmps256" => "__builtin_ia32_vfixupimmps256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vfmaddcph256" => "__builtin_ia32_vfmaddcph256_round_mask3", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vfmulcph256" => "__builtin_ia32_vfmulcph256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vgetexppd256" => "__builtin_ia32_vgetexppd256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vgetexpph256" => "__builtin_ia32_vgetexpph256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vgetexpps256" => "__builtin_ia32_vgetexpps256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vgetmantpd256" => "__builtin_ia32_vgetmantpd256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vgetmantph256" => "__builtin_ia32_vgetmantph256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vgetmantps256" => "__builtin_ia32_vgetmantps256_round_mask", + "llvm.x86.avx10.mask.vcvttps2qqs.128" => "__builtin_ia32_vcvttps2qqs128_mask", + "llvm.x86.avx10.mask.vcvttps2qqs.256" => "__builtin_ia32_vcvttps2qqs256_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttps2qqs.round.512" => "__builtin_ia32_vcvttps2qqs512_round_mask", + "llvm.x86.avx10.mask.vcvttps2udqs.128" => "__builtin_ia32_vcvttps2udqs128_mask", + "llvm.x86.avx10.mask.vcvttps2udqs.256" => "__builtin_ia32_vcvttps2udqs256_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttps2udqs.round.512" => "__builtin_ia32_vcvttps2udqs512_round_mask", + "llvm.x86.avx10.mask.vcvttps2uqqs.128" => "__builtin_ia32_vcvttps2uqqs128_mask", + "llvm.x86.avx10.mask.vcvttps2uqqs.256" => "__builtin_ia32_vcvttps2uqqs256_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttps2uqqs.round.512" => "__builtin_ia32_vcvttps2uqqs512_round_mask", // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxpd.round" => "__builtin_ia32_vminmaxpd512_round_mask", "llvm.x86.avx10.mask.vminmaxpd128" => "__builtin_ia32_vminmaxpd128_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxpd256.round" => "__builtin_ia32_vminmaxpd256_round_mask", + "llvm.x86.avx10.mask.vminmaxpd256" => "__builtin_ia32_vminmaxpd256_mask", // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxph.round" => "__builtin_ia32_vminmaxph512_round_mask", "llvm.x86.avx10.mask.vminmaxph128" => "__builtin_ia32_vminmaxph128_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxph256.round" => "__builtin_ia32_vminmaxph256_round_mask", + "llvm.x86.avx10.mask.vminmaxph256" => "__builtin_ia32_vminmaxph256_mask", // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxps.round" => "__builtin_ia32_vminmaxps512_round_mask", "llvm.x86.avx10.mask.vminmaxps128" => "__builtin_ia32_vminmaxps128_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxps256.round" => "__builtin_ia32_vminmaxps256_round_mask", + "llvm.x86.avx10.mask.vminmaxps256" => "__builtin_ia32_vminmaxps256_mask", // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxsd.round" => "__builtin_ia32_vminmaxsd_round_mask", // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxsh.round" => "__builtin_ia32_vminmaxsh_round_mask", // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxss.round" => "__builtin_ia32_vminmaxss_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vrangepd256" => "__builtin_ia32_vrangepd256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vrangeps256" => "__builtin_ia32_vrangeps256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vreducepd256" => "__builtin_ia32_vreducepd256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vreduceph256" => "__builtin_ia32_vreduceph256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vreduceps256" => "__builtin_ia32_vreduceps256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vrndscalepd256" => "__builtin_ia32_vrndscalepd256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vrndscaleph256" => "__builtin_ia32_vrndscaleph256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vrndscaleps256" => "__builtin_ia32_vrndscaleps256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vscalefpd256" => "__builtin_ia32_vscalefpd256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vscalefph256" => "__builtin_ia32_vscalefph256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vscalefps256" => "__builtin_ia32_vscalefps256_round_mask", - // [INVALID CONVERSION]: "llvm.x86.avx10.maskz.vfcmaddcph256" => "__builtin_ia32_vfcmaddcph256_round_maskz", - // [INVALID CONVERSION]: "llvm.x86.avx10.maskz.vfixupimmpd256" => "__builtin_ia32_vfixupimmpd256_round_maskz", - // [INVALID CONVERSION]: "llvm.x86.avx10.maskz.vfixupimmps256" => "__builtin_ia32_vfixupimmps256_round_maskz", - // [INVALID CONVERSION]: "llvm.x86.avx10.maskz.vfmaddcph256" => "__builtin_ia32_vfmaddcph256_round_maskz", + "llvm.x86.avx10.vaddbf16128" => "__builtin_ia32_vaddbf16128", + "llvm.x86.avx10.vaddbf16256" => "__builtin_ia32_vaddbf16256", + "llvm.x86.avx10.vaddbf16512" => "__builtin_ia32_vaddbf16512", "llvm.x86.avx10.vaddpd256" => "__builtin_ia32_vaddpd256_round", "llvm.x86.avx10.vaddph256" => "__builtin_ia32_vaddph256_round", "llvm.x86.avx10.vaddps256" => "__builtin_ia32_vaddps256_round", - "llvm.x86.avx10.vcvtne2ph2bf8128" => "__builtin_ia32_vcvtne2ph2bf8_128", - "llvm.x86.avx10.vcvtne2ph2bf8256" => "__builtin_ia32_vcvtne2ph2bf8_256", - "llvm.x86.avx10.vcvtne2ph2bf8512" => "__builtin_ia32_vcvtne2ph2bf8_512", - "llvm.x86.avx10.vcvtne2ph2bf8s128" => "__builtin_ia32_vcvtne2ph2bf8s_128", - "llvm.x86.avx10.vcvtne2ph2bf8s256" => "__builtin_ia32_vcvtne2ph2bf8s_256", - "llvm.x86.avx10.vcvtne2ph2bf8s512" => "__builtin_ia32_vcvtne2ph2bf8s_512", - "llvm.x86.avx10.vcvtne2ph2hf8128" => "__builtin_ia32_vcvtne2ph2hf8_128", - "llvm.x86.avx10.vcvtne2ph2hf8256" => "__builtin_ia32_vcvtne2ph2hf8_256", - "llvm.x86.avx10.vcvtne2ph2hf8512" => "__builtin_ia32_vcvtne2ph2hf8_512", - "llvm.x86.avx10.vcvtne2ph2hf8s128" => "__builtin_ia32_vcvtne2ph2hf8s_128", - "llvm.x86.avx10.vcvtne2ph2hf8s256" => "__builtin_ia32_vcvtne2ph2hf8s_256", - "llvm.x86.avx10.vcvtne2ph2hf8s512" => "__builtin_ia32_vcvtne2ph2hf8s_512", - "llvm.x86.avx10.vcvtnebf162ibs128" => "__builtin_ia32_vcvtnebf162ibs128", - "llvm.x86.avx10.vcvtnebf162ibs256" => "__builtin_ia32_vcvtnebf162ibs256", - "llvm.x86.avx10.vcvtnebf162ibs512" => "__builtin_ia32_vcvtnebf162ibs512", - "llvm.x86.avx10.vcvtnebf162iubs128" => "__builtin_ia32_vcvtnebf162iubs128", - "llvm.x86.avx10.vcvtnebf162iubs256" => "__builtin_ia32_vcvtnebf162iubs256", - "llvm.x86.avx10.vcvtnebf162iubs512" => "__builtin_ia32_vcvtnebf162iubs512", - "llvm.x86.avx10.vcvttnebf162ibs128" => "__builtin_ia32_vcvttnebf162ibs128", - "llvm.x86.avx10.vcvttnebf162ibs256" => "__builtin_ia32_vcvttnebf162ibs256", - "llvm.x86.avx10.vcvttnebf162ibs512" => "__builtin_ia32_vcvttnebf162ibs512", - "llvm.x86.avx10.vcvttnebf162iubs128" => "__builtin_ia32_vcvttnebf162iubs128", - "llvm.x86.avx10.vcvttnebf162iubs256" => "__builtin_ia32_vcvttnebf162iubs256", - "llvm.x86.avx10.vcvttnebf162iubs512" => "__builtin_ia32_vcvttnebf162iubs512", - "llvm.x86.avx10.vdivpd256" => "__builtin_ia32_vdivpd256_round", - "llvm.x86.avx10.vdivph256" => "__builtin_ia32_vdivph256_round", - "llvm.x86.avx10.vdivps256" => "__builtin_ia32_vdivps256_round", + "llvm.x86.avx10.vcomisbf16eq" => "__builtin_ia32_vcomisbf16eq", + "llvm.x86.avx10.vcomisbf16ge" => "__builtin_ia32_vcomisbf16ge", + "llvm.x86.avx10.vcomisbf16gt" => "__builtin_ia32_vcomisbf16gt", + "llvm.x86.avx10.vcomisbf16le" => "__builtin_ia32_vcomisbf16le", + "llvm.x86.avx10.vcomisbf16lt" => "__builtin_ia32_vcomisbf16lt", + "llvm.x86.avx10.vcomisbf16neq" => "__builtin_ia32_vcomisbf16neq", + "llvm.x86.avx10.vcvt2ph2bf8128" => "__builtin_ia32_vcvt2ph2bf8_128", + "llvm.x86.avx10.vcvt2ph2bf8256" => "__builtin_ia32_vcvt2ph2bf8_256", + "llvm.x86.avx10.vcvt2ph2bf8512" => "__builtin_ia32_vcvt2ph2bf8_512", + "llvm.x86.avx10.vcvt2ph2bf8s128" => "__builtin_ia32_vcvt2ph2bf8s_128", + "llvm.x86.avx10.vcvt2ph2bf8s256" => "__builtin_ia32_vcvt2ph2bf8s_256", + "llvm.x86.avx10.vcvt2ph2bf8s512" => "__builtin_ia32_vcvt2ph2bf8s_512", + "llvm.x86.avx10.vcvt2ph2hf8128" => "__builtin_ia32_vcvt2ph2hf8_128", + "llvm.x86.avx10.vcvt2ph2hf8256" => "__builtin_ia32_vcvt2ph2hf8_256", + "llvm.x86.avx10.vcvt2ph2hf8512" => "__builtin_ia32_vcvt2ph2hf8_512", + "llvm.x86.avx10.vcvt2ph2hf8s128" => "__builtin_ia32_vcvt2ph2hf8s_128", + "llvm.x86.avx10.vcvt2ph2hf8s256" => "__builtin_ia32_vcvt2ph2hf8s_256", + "llvm.x86.avx10.vcvt2ph2hf8s512" => "__builtin_ia32_vcvt2ph2hf8s_512", + "llvm.x86.avx10.vcvtbf162ibs128" => "__builtin_ia32_vcvtbf162ibs128", + "llvm.x86.avx10.vcvtbf162ibs256" => "__builtin_ia32_vcvtbf162ibs256", + "llvm.x86.avx10.vcvtbf162ibs512" => "__builtin_ia32_vcvtbf162ibs512", + "llvm.x86.avx10.vcvtbf162iubs128" => "__builtin_ia32_vcvtbf162iubs128", + "llvm.x86.avx10.vcvtbf162iubs256" => "__builtin_ia32_vcvtbf162iubs256", + "llvm.x86.avx10.vcvtbf162iubs512" => "__builtin_ia32_vcvtbf162iubs512", + "llvm.x86.avx10.vcvttbf162ibs128" => "__builtin_ia32_vcvttbf162ibs128", + "llvm.x86.avx10.vcvttbf162ibs256" => "__builtin_ia32_vcvttbf162ibs256", + "llvm.x86.avx10.vcvttbf162ibs512" => "__builtin_ia32_vcvttbf162ibs512", + "llvm.x86.avx10.vcvttbf162iubs128" => "__builtin_ia32_vcvttbf162iubs128", + "llvm.x86.avx10.vcvttbf162iubs256" => "__builtin_ia32_vcvttbf162iubs256", + "llvm.x86.avx10.vcvttbf162iubs512" => "__builtin_ia32_vcvttbf162iubs512", + "llvm.x86.avx10.vcvttsd2sis" => "__builtin_ia32_vcvttsd2sis32", + "llvm.x86.avx10.vcvttsd2sis64" => "__builtin_ia32_vcvttsd2sis64", + "llvm.x86.avx10.vcvttsd2usis" => "__builtin_ia32_vcvttsd2usis32", + "llvm.x86.avx10.vcvttsd2usis64" => "__builtin_ia32_vcvttsd2usis64", + "llvm.x86.avx10.vcvttss2sis" => "__builtin_ia32_vcvttss2sis32", + "llvm.x86.avx10.vcvttss2sis64" => "__builtin_ia32_vcvttss2sis64", + "llvm.x86.avx10.vcvttss2usis" => "__builtin_ia32_vcvttss2usis32", + "llvm.x86.avx10.vcvttss2usis64" => "__builtin_ia32_vcvttss2usis64", + "llvm.x86.avx10.vdivbf16128" => "__builtin_ia32_vdivbf16128", + "llvm.x86.avx10.vdivbf16256" => "__builtin_ia32_vdivbf16256", + "llvm.x86.avx10.vdivbf16512" => "__builtin_ia32_vdivbf16512", "llvm.x86.avx10.vdpphps.128" => "__builtin_ia32_vdpphps128", "llvm.x86.avx10.vdpphps.256" => "__builtin_ia32_vdpphps256", "llvm.x86.avx10.vdpphps.512" => "__builtin_ia32_vdpphps512", - "llvm.x86.avx10.vfmaddsubpd256" => "__builtin_ia32_vfmaddsubpd256_round", - "llvm.x86.avx10.vfmaddsubph256" => "__builtin_ia32_vfmaddsubph256_round", - "llvm.x86.avx10.vfmaddsubps256" => "__builtin_ia32_vfmaddsubps256_round", - "llvm.x86.avx10.vmaxpd256" => "__builtin_ia32_vmaxpd256_round", - "llvm.x86.avx10.vmaxph256" => "__builtin_ia32_vmaxph256_round", - "llvm.x86.avx10.vmaxps256" => "__builtin_ia32_vmaxps256_round", - "llvm.x86.avx10.vminmaxnepbf16128" => "__builtin_ia32_vminmaxnepbf16128", - "llvm.x86.avx10.vminmaxnepbf16256" => "__builtin_ia32_vminmaxnepbf16256", - "llvm.x86.avx10.vminmaxnepbf16512" => "__builtin_ia32_vminmaxnepbf16512", + "llvm.x86.avx10.vfmadd132bf16128" => "__builtin_ia32_vfmadd132bf16128", + "llvm.x86.avx10.vfmadd132bf16256" => "__builtin_ia32_vfmadd132bf16256", + "llvm.x86.avx10.vfmadd132bf16512" => "__builtin_ia32_vfmadd132bf16512", + "llvm.x86.avx10.vfmadd213bf16128" => "__builtin_ia32_vfmadd213bf16128", + "llvm.x86.avx10.vfmadd213bf16256" => "__builtin_ia32_vfmadd213bf16256", + "llvm.x86.avx10.vfmadd231bf16128" => "__builtin_ia32_vfmadd231bf16128", + "llvm.x86.avx10.vfmadd231bf16256" => "__builtin_ia32_vfmadd231bf16256", + "llvm.x86.avx10.vfmadd231bf16512" => "__builtin_ia32_vfmadd231bf16512", + "llvm.x86.avx10.vfmsub132bf16128" => "__builtin_ia32_vfmsub132bf16128", + "llvm.x86.avx10.vfmsub132bf16256" => "__builtin_ia32_vfmsub132bf16256", + "llvm.x86.avx10.vfmsub132bf16512" => "__builtin_ia32_vfmsub132bf16512", + "llvm.x86.avx10.vfmsub213bf16128" => "__builtin_ia32_vfmsub213bf16128", + "llvm.x86.avx10.vfmsub213bf16256" => "__builtin_ia32_vfmsub213bf16256", + "llvm.x86.avx10.vfmsub213bf16512" => "__builtin_ia32_vfmsub213bf16512", + "llvm.x86.avx10.vfmsub231bf16128" => "__builtin_ia32_vfmsub231bf16128", + "llvm.x86.avx10.vfmsub231bf16256" => "__builtin_ia32_vfmsub231bf16256", + "llvm.x86.avx10.vfmsub231bf16512" => "__builtin_ia32_vfmsub231bf16512", + "llvm.x86.avx10.vfnmadd132bf16128" => "__builtin_ia32_vfnmadd132bf16128", + "llvm.x86.avx10.vfnmadd132bf16256" => "__builtin_ia32_vfnmadd132bf16256", + "llvm.x86.avx10.vfnmadd132bf16512" => "__builtin_ia32_vfnmadd132bf16512", + "llvm.x86.avx10.vfnmadd213bf16128" => "__builtin_ia32_vfnmadd213bf16128", + "llvm.x86.avx10.vfnmadd213bf16256" => "__builtin_ia32_vfnmadd213bf16256", + "llvm.x86.avx10.vfnmadd213bf16512" => "__builtin_ia32_vfnmadd213bf16512", + "llvm.x86.avx10.vfnmadd231bf16128" => "__builtin_ia32_vfnmadd231bf16128", + "llvm.x86.avx10.vfnmadd231bf16256" => "__builtin_ia32_vfnmadd231bf16256", + "llvm.x86.avx10.vfnmadd231bf16512" => "__builtin_ia32_vfnmadd231bf16512", + "llvm.x86.avx10.vfnmsub132bf16128" => "__builtin_ia32_vfnmsub132bf16128", + "llvm.x86.avx10.vfnmsub132bf16256" => "__builtin_ia32_vfnmsub132bf16256", + "llvm.x86.avx10.vfnmsub132bf16512" => "__builtin_ia32_vfnmsub132bf16512", + "llvm.x86.avx10.vfnmsub213bf16128" => "__builtin_ia32_vfnmsub213bf16128", + "llvm.x86.avx10.vfnmsub213bf16256" => "__builtin_ia32_vfnmsub213bf16256", + "llvm.x86.avx10.vfnmsub213bf16512" => "__builtin_ia32_vfnmsub213bf16512", + "llvm.x86.avx10.vfnmsub231bf16128" => "__builtin_ia32_vfnmsub231bf16128", + "llvm.x86.avx10.vfnmsub231bf16256" => "__builtin_ia32_vfnmsub231bf16256", + "llvm.x86.avx10.vfnmsub231bf16512" => "__builtin_ia32_vfnmsub231bf16512", + "llvm.x86.avx10.vmaxbf16128" => "__builtin_ia32_vmaxbf16128", + "llvm.x86.avx10.vmaxbf16256" => "__builtin_ia32_vmaxbf16256", + "llvm.x86.avx10.vmaxbf16512" => "__builtin_ia32_vmaxbf16512", + "llvm.x86.avx10.vminbf16128" => "__builtin_ia32_vminbf16128", + "llvm.x86.avx10.vminbf16256" => "__builtin_ia32_vminbf16256", + "llvm.x86.avx10.vminbf16512" => "__builtin_ia32_vminbf16512", + "llvm.x86.avx10.vminmaxbf16128" => "__builtin_ia32_vminmaxbf16128", + "llvm.x86.avx10.vminmaxbf16256" => "__builtin_ia32_vminmaxbf16256", + "llvm.x86.avx10.vminmaxbf16512" => "__builtin_ia32_vminmaxbf16512", "llvm.x86.avx10.vminmaxpd128" => "__builtin_ia32_vminmaxpd128", "llvm.x86.avx10.vminmaxpd256" => "__builtin_ia32_vminmaxpd256", "llvm.x86.avx10.vminmaxph128" => "__builtin_ia32_vminmaxph128", "llvm.x86.avx10.vminmaxph256" => "__builtin_ia32_vminmaxph256", "llvm.x86.avx10.vminmaxps128" => "__builtin_ia32_vminmaxps128", "llvm.x86.avx10.vminmaxps256" => "__builtin_ia32_vminmaxps256", - "llvm.x86.avx10.vminpd256" => "__builtin_ia32_vminpd256_round", - "llvm.x86.avx10.vminph256" => "__builtin_ia32_vminph256_round", - "llvm.x86.avx10.vminps256" => "__builtin_ia32_vminps256_round", + "llvm.x86.avx10.vmovrsb128" => "__builtin_ia32_vmovrsb128", + "llvm.x86.avx10.vmovrsb256" => "__builtin_ia32_vmovrsb256", + "llvm.x86.avx10.vmovrsb512" => "__builtin_ia32_vmovrsb512", + "llvm.x86.avx10.vmovrsd128" => "__builtin_ia32_vmovrsd128", + "llvm.x86.avx10.vmovrsd256" => "__builtin_ia32_vmovrsd256", + "llvm.x86.avx10.vmovrsd512" => "__builtin_ia32_vmovrsd512", + "llvm.x86.avx10.vmovrsq128" => "__builtin_ia32_vmovrsq128", + "llvm.x86.avx10.vmovrsq256" => "__builtin_ia32_vmovrsq256", + "llvm.x86.avx10.vmovrsq512" => "__builtin_ia32_vmovrsq512", + "llvm.x86.avx10.vmovrsw128" => "__builtin_ia32_vmovrsw128", + "llvm.x86.avx10.vmovrsw256" => "__builtin_ia32_vmovrsw256", + "llvm.x86.avx10.vmovrsw512" => "__builtin_ia32_vmovrsw512", "llvm.x86.avx10.vmpsadbw.512" => "__builtin_ia32_mpsadbw512", - "llvm.x86.avx10.vmulpd256" => "__builtin_ia32_vmulpd256_round", - "llvm.x86.avx10.vmulph256" => "__builtin_ia32_vmulph256_round", - "llvm.x86.avx10.vmulps256" => "__builtin_ia32_vmulps256_round", + "llvm.x86.avx10.vmulbf16128" => "__builtin_ia32_vmulbf16128", + "llvm.x86.avx10.vmulbf16256" => "__builtin_ia32_vmulbf16256", + "llvm.x86.avx10.vmulbf16512" => "__builtin_ia32_vmulbf16512", "llvm.x86.avx10.vpdpbssd.512" => "__builtin_ia32_vpdpbssd512", "llvm.x86.avx10.vpdpbssds.512" => "__builtin_ia32_vpdpbssds512", "llvm.x86.avx10.vpdpbsud.512" => "__builtin_ia32_vpdpbsud512", @@ -7523,12 +7751,9 @@ match name { "llvm.x86.avx10.vpdpwusds.512" => "__builtin_ia32_vpdpwusds512", "llvm.x86.avx10.vpdpwuud.512" => "__builtin_ia32_vpdpwuud512", "llvm.x86.avx10.vpdpwuuds.512" => "__builtin_ia32_vpdpwuuds512", - "llvm.x86.avx10.vsqrtpd256" => "__builtin_ia32_vsqrtpd256_round", - "llvm.x86.avx10.vsqrtph256" => "__builtin_ia32_vsqrtph256_round", - "llvm.x86.avx10.vsqrtps256" => "__builtin_ia32_vsqrtps256_round", - "llvm.x86.avx10.vsubpd256" => "__builtin_ia32_vsubpd256_round", - "llvm.x86.avx10.vsubph256" => "__builtin_ia32_vsubph256_round", - "llvm.x86.avx10.vsubps256" => "__builtin_ia32_vsubps256_round", + "llvm.x86.avx10.vsubbf16128" => "__builtin_ia32_vsubbf16128", + "llvm.x86.avx10.vsubbf16256" => "__builtin_ia32_vsubbf16256", + "llvm.x86.avx10.vsubbf16512" => "__builtin_ia32_vsubbf16512", "llvm.x86.avx2.gather.d.d" => "__builtin_ia32_gatherd_d", "llvm.x86.avx2.gather.d.d.256" => "__builtin_ia32_gatherd_d256", "llvm.x86.avx2.gather.d.pd" => "__builtin_ia32_gatherd_pd", @@ -9279,10 +9504,15 @@ match name { "llvm.x86.mmx.femms" => "__builtin_ia32_femms", "llvm.x86.monitorx" => "__builtin_ia32_monitorx", "llvm.x86.movdir64b" => "__builtin_ia32_movdir64b", + "llvm.x86.movrsdi" => "__builtin_ia32_movrsdi", + "llvm.x86.movrshi" => "__builtin_ia32_movrshi", + "llvm.x86.movrsqi" => "__builtin_ia32_movrsqi", + "llvm.x86.movrssi" => "__builtin_ia32_movrssi", "llvm.x86.mwaitx" => "__builtin_ia32_mwaitx", "llvm.x86.pclmulqdq" => "__builtin_ia32_pclmulqdq128", "llvm.x86.pclmulqdq.256" => "__builtin_ia32_pclmulqdq256", "llvm.x86.pclmulqdq.512" => "__builtin_ia32_pclmulqdq512", + "llvm.x86.prefetchrs" => "__builtin_ia32_prefetchrs", "llvm.x86.ptwrite32" => "__builtin_ia32_ptwrite32", "llvm.x86.ptwrite64" => "__builtin_ia32_ptwrite64", "llvm.x86.rdfsbase.32" => "__builtin_ia32_rdfsbase32", @@ -9536,14 +9766,40 @@ match name { "llvm.x86.stui" => "__builtin_ia32_stui", "llvm.x86.subborrow.u32" => "__builtin_ia32_subborrow_u32", "llvm.x86.subborrow.u64" => "__builtin_ia32_subborrow_u64", + "llvm.x86.t2rpntlvwz0" => "__builtin_ia32_t2rpntlvwz0", + "llvm.x86.t2rpntlvwz0rs" => "__builtin_ia32_t2rpntlvwz0rs", + "llvm.x86.t2rpntlvwz0rst1" => "__builtin_ia32_t2rpntlvwz0rst1", + "llvm.x86.t2rpntlvwz0t1" => "__builtin_ia32_t2rpntlvwz0t1", + "llvm.x86.t2rpntlvwz1" => "__builtin_ia32_t2rpntlvwz1", + "llvm.x86.t2rpntlvwz1rs" => "__builtin_ia32_t2rpntlvwz1rs", + "llvm.x86.t2rpntlvwz1rst1" => "__builtin_ia32_t2rpntlvwz1rst1", + "llvm.x86.t2rpntlvwz1t1" => "__builtin_ia32_t2rpntlvwz1t1", "llvm.x86.tbm.bextri.u32" => "__builtin_ia32_bextri_u32", "llvm.x86.tbm.bextri.u64" => "__builtin_ia32_bextri_u64", "llvm.x86.tcmmimfp16ps" => "__builtin_ia32_tcmmimfp16ps", "llvm.x86.tcmmimfp16ps.internal" => "__builtin_ia32_tcmmimfp16ps_internal", "llvm.x86.tcmmrlfp16ps" => "__builtin_ia32_tcmmrlfp16ps", "llvm.x86.tcmmrlfp16ps.internal" => "__builtin_ia32_tcmmrlfp16ps_internal", + "llvm.x86.tconjtcmmimfp16ps" => "__builtin_ia32_tconjtcmmimfp16ps", + "llvm.x86.tconjtcmmimfp16ps.internal" => "__builtin_ia32_tconjtcmmimfp16ps_internal", + "llvm.x86.tconjtfp16" => "__builtin_ia32_tconjtfp16", + "llvm.x86.tconjtfp16.internal" => "__builtin_ia32_tconjtfp16_internal", + "llvm.x86.tcvtrowd2ps" => "__builtin_ia32_tcvtrowd2ps", + "llvm.x86.tcvtrowd2ps.internal" => "__builtin_ia32_tcvtrowd2ps_internal", + "llvm.x86.tcvtrowps2bf16h" => "__builtin_ia32_tcvtrowps2bf16h", + "llvm.x86.tcvtrowps2bf16h.internal" => "__builtin_ia32_tcvtrowps2bf16h_internal", + "llvm.x86.tcvtrowps2bf16l" => "__builtin_ia32_tcvtrowps2bf16l", + "llvm.x86.tcvtrowps2bf16l.internal" => "__builtin_ia32_tcvtrowps2bf16l_internal", + "llvm.x86.tcvtrowps2phh" => "__builtin_ia32_tcvtrowps2phh", + "llvm.x86.tcvtrowps2phh.internal" => "__builtin_ia32_tcvtrowps2phh_internal", + "llvm.x86.tcvtrowps2phl" => "__builtin_ia32_tcvtrowps2phl", + "llvm.x86.tcvtrowps2phl.internal" => "__builtin_ia32_tcvtrowps2phl_internal", "llvm.x86.tdpbf16ps" => "__builtin_ia32_tdpbf16ps", "llvm.x86.tdpbf16ps.internal" => "__builtin_ia32_tdpbf16ps_internal", + "llvm.x86.tdpbf8ps" => "__builtin_ia32_tdpbf8ps", + "llvm.x86.tdpbf8ps.internal" => "__builtin_ia32_tdpbf8ps_internal", + "llvm.x86.tdpbhf8ps" => "__builtin_ia32_tdpbhf8ps", + "llvm.x86.tdpbhf8ps.internal" => "__builtin_ia32_tdpbhf8ps_internal", "llvm.x86.tdpbssd" => "__builtin_ia32_tdpbssd", "llvm.x86.tdpbssd.internal" => "__builtin_ia32_tdpbssd_internal", "llvm.x86.tdpbsud" => "__builtin_ia32_tdpbsud", @@ -9554,17 +9810,41 @@ match name { "llvm.x86.tdpbuud.internal" => "__builtin_ia32_tdpbuud_internal", "llvm.x86.tdpfp16ps" => "__builtin_ia32_tdpfp16ps", "llvm.x86.tdpfp16ps.internal" => "__builtin_ia32_tdpfp16ps_internal", + "llvm.x86.tdphbf8ps" => "__builtin_ia32_tdphbf8ps", + "llvm.x86.tdphbf8ps.internal" => "__builtin_ia32_tdphbf8ps_internal", + "llvm.x86.tdphf8ps" => "__builtin_ia32_tdphf8ps", + "llvm.x86.tdphf8ps.internal" => "__builtin_ia32_tdphf8ps_internal", "llvm.x86.testui" => "__builtin_ia32_testui", "llvm.x86.tileloadd64" => "__builtin_ia32_tileloadd64", "llvm.x86.tileloadd64.internal" => "__builtin_ia32_tileloadd64_internal", + "llvm.x86.tileloaddrs64" => "__builtin_ia32_tileloaddrs64", + "llvm.x86.tileloaddrs64.internal" => "__builtin_ia32_tileloaddrs64_internal", + "llvm.x86.tileloaddrst164" => "__builtin_ia32_tileloaddrst164", + "llvm.x86.tileloaddrst164.internal" => "__builtin_ia32_tileloaddrst164_internal", "llvm.x86.tileloaddt164" => "__builtin_ia32_tileloaddt164", "llvm.x86.tileloaddt164.internal" => "__builtin_ia32_tileloaddt164_internal", + "llvm.x86.tilemovrow" => "__builtin_ia32_tilemovrow", + "llvm.x86.tilemovrow.internal" => "__builtin_ia32_tilemovrow_internal", "llvm.x86.tilerelease" => "__builtin_ia32_tilerelease", "llvm.x86.tilestored64" => "__builtin_ia32_tilestored64", "llvm.x86.tilestored64.internal" => "__builtin_ia32_tilestored64_internal", "llvm.x86.tilezero" => "__builtin_ia32_tilezero", "llvm.x86.tilezero.internal" => "__builtin_ia32_tilezero_internal", + "llvm.x86.tmmultf32ps" => "__builtin_ia32_tmmultf32ps", + "llvm.x86.tmmultf32ps.internal" => "__builtin_ia32_tmmultf32ps_internal", "llvm.x86.tpause" => "__builtin_ia32_tpause", + "llvm.x86.ttcmmimfp16ps" => "__builtin_ia32_ttcmmimfp16ps", + "llvm.x86.ttcmmimfp16ps.internal" => "__builtin_ia32_ttcmmimfp16ps_internal", + "llvm.x86.ttcmmrlfp16ps" => "__builtin_ia32_ttcmmrlfp16ps", + "llvm.x86.ttcmmrlfp16ps.internal" => "__builtin_ia32_ttcmmrlfp16ps_internal", + "llvm.x86.ttdpbf16ps" => "__builtin_ia32_ttdpbf16ps", + "llvm.x86.ttdpbf16ps.internal" => "__builtin_ia32_ttdpbf16ps_internal", + "llvm.x86.ttdpfp16ps" => "__builtin_ia32_ttdpfp16ps", + "llvm.x86.ttdpfp16ps.internal" => "__builtin_ia32_ttdpfp16ps_internal", + "llvm.x86.ttmmultf32ps" => "__builtin_ia32_ttmmultf32ps", + "llvm.x86.ttmmultf32ps.internal" => "__builtin_ia32_ttmmultf32ps_internal", + "llvm.x86.ttransposed" => "__builtin_ia32_ttransposed", + "llvm.x86.ttransposed.internal" => "__builtin_ia32_ttransposed_internal", "llvm.x86.umonitor" => "__builtin_ia32_umonitor", "llvm.x86.umwait" => "__builtin_ia32_umwait", "llvm.x86.urdmsr" => "__builtin_ia32_urdmsr", @@ -9604,8 +9884,10 @@ match name { "llvm.x86.vsm3rnds2" => "__builtin_ia32_vsm3rnds2", "llvm.x86.vsm4key4128" => "__builtin_ia32_vsm4key4128", "llvm.x86.vsm4key4256" => "__builtin_ia32_vsm4key4256", + "llvm.x86.vsm4key4512" => "__builtin_ia32_vsm4key4512", "llvm.x86.vsm4rnds4128" => "__builtin_ia32_vsm4rnds4128", "llvm.x86.vsm4rnds4256" => "__builtin_ia32_vsm4rnds4256", + "llvm.x86.vsm4rnds4512" => "__builtin_ia32_vsm4rnds4512", "llvm.x86.wbinvd" => "__builtin_ia32_wbinvd", "llvm.x86.wbnoinvd" => "__builtin_ia32_wbnoinvd", "llvm.x86.wrfsbase.32" => "__builtin_ia32_wrfsbase32", diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index 9caceca92957a..ba65c8205a500 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -4,9 +4,7 @@ mod simd; #[cfg(feature = "master")] use std::iter; -#[cfg(feature = "master")] -use gccjit::FunctionType; -use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp}; +use gccjit::{ComparisonOp, Function, FunctionType, RValue, ToRValue, Type, UnaryOp}; #[cfg(feature = "master")] use rustc_abi::ExternAbi; use rustc_abi::{BackendRepr, HasDataLayout}; @@ -132,6 +130,72 @@ fn get_simple_intrinsic<'gcc, 'tcx>( Some(cx.context.get_builtin_function(gcc_name)) } +// TODO(antoyo): We can probably remove these and use the fallback intrinsic implementation. +fn get_simple_function<'gcc, 'tcx>( + cx: &CodegenCx<'gcc, 'tcx>, + name: Symbol, +) -> Option> { + let (return_type, parameters, func_name) = match name { + sym::minimumf32 => { + let parameters = [ + cx.context.new_parameter(None, cx.float_type, "a"), + cx.context.new_parameter(None, cx.float_type, "b"), + ]; + (cx.float_type, parameters, "fminimumf") + } + sym::minimumf64 => { + let parameters = [ + cx.context.new_parameter(None, cx.double_type, "a"), + cx.context.new_parameter(None, cx.double_type, "b"), + ]; + (cx.double_type, parameters, "fminimum") + } + sym::minimumf128 => { + let f128_type = cx.type_f128(); + // GCC doesn't have the intrinsic we want so we use the compiler-builtins one + // https://docs.rs/compiler_builtins/latest/compiler_builtins/math/full_availability/fn.fminimumf128.html + let parameters = [ + cx.context.new_parameter(None, f128_type, "a"), + cx.context.new_parameter(None, f128_type, "b"), + ]; + (f128_type, parameters, "fminimumf128") + } + sym::maximumf32 => { + let parameters = [ + cx.context.new_parameter(None, cx.float_type, "a"), + cx.context.new_parameter(None, cx.float_type, "b"), + ]; + (cx.float_type, parameters, "fmaximumf") + } + sym::maximumf64 => { + let parameters = [ + cx.context.new_parameter(None, cx.double_type, "a"), + cx.context.new_parameter(None, cx.double_type, "b"), + ]; + (cx.double_type, parameters, "fmaximum") + } + sym::maximumf128 => { + let f128_type = cx.type_f128(); + // GCC doesn't have the intrinsic we want so we use the compiler-builtins one + // https://docs.rs/compiler_builtins/latest/compiler_builtins/math/full_availability/fn.fmaximumf128.html + let parameters = [ + cx.context.new_parameter(None, f128_type, "a"), + cx.context.new_parameter(None, f128_type, "b"), + ]; + (f128_type, parameters, "fmaximumf128") + } + _ => return None, + }; + Some(cx.context.new_function( + None, + FunctionType::Extern, + return_type, + ¶meters, + func_name, + false, + )) +} + impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { fn codegen_intrinsic_call( &mut self, @@ -160,6 +224,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); let simple = get_simple_intrinsic(self, name); + let simple_func = get_simple_function(self, name); // FIXME(tempdragon): Re-enable `clippy::suspicious_else_formatting` if the following issue is solved: // https://github.com/rust-lang/rust-clippy/issues/12497 @@ -167,7 +232,15 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc #[allow(clippy::suspicious_else_formatting)] let value = match name { _ if simple.is_some() => { - let func = simple.expect("simple function"); + let func = simple.expect("simple intrinsic function"); + self.cx.context.new_call( + self.location, + func, + &args.iter().map(|arg| arg.immediate()).collect::>(), + ) + } + _ if simple_func.is_some() => { + let func = simple_func.expect("simple function"); self.cx.context.new_call( self.location, func, diff --git a/src/lib.rs b/src/lib.rs index 2c5a787168381..6e2a50d745a4e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,7 @@ #![allow(internal_features)] #![doc(rust_logo)] #![feature(rustdoc_internals)] -#![feature(rustc_private, decl_macro, never_type, trusted_len, let_chains)] +#![feature(rustc_private, decl_macro, never_type, trusted_len)] #![allow(broken_intra_doc_links)] #![recursion_limit = "256"] #![warn(rust_2018_idioms)] @@ -454,7 +454,7 @@ impl WriteBackendMethods for GccCodegenBackend { } /// This is the entrypoint for a hot plugged rustc_codegen_gccjit -#[no_mangle] +#[unsafe(no_mangle)] pub fn __rustc_codegen_backend() -> Box { #[cfg(feature = "master")] let info = { diff --git a/tests/failing-ui-tests.txt b/tests/failing-ui-tests.txt index 499c1a962311c..0a01a661c3577 100644 --- a/tests/failing-ui-tests.txt +++ b/tests/failing-ui-tests.txt @@ -10,7 +10,7 @@ tests/ui/sepcomp/sepcomp-fns-backwards.rs tests/ui/sepcomp/sepcomp-fns.rs tests/ui/sepcomp/sepcomp-statics.rs tests/ui/asm/x86_64/may_unwind.rs -tests/ui/catch-unwind-bang.rs +tests/ui/panics/catch-unwind-bang.rs tests/ui/drop/dynamic-drop-async.rs tests/ui/cfg/cfg-panic-abort.rs tests/ui/drop/repeat-drop.rs @@ -94,23 +94,14 @@ tests/ui/simd/intrinsic/generic-as.rs tests/ui/backtrace/backtrace.rs tests/ui/lifetimes/tail-expr-lock-poisoning.rs tests/ui/runtime/rt-explody-panic-payloads.rs -tests/ui/codegen/equal-pointers-unequal/as-cast/function.rs -tests/ui/codegen/equal-pointers-unequal/as-cast/basic.rs tests/ui/codegen/equal-pointers-unequal/as-cast/inline1.rs -tests/ui/codegen/equal-pointers-unequal/as-cast/print.rs tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.rs tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.rs -tests/ui/codegen/equal-pointers-unequal/exposed-provenance/function.rs -tests/ui/codegen/equal-pointers-unequal/exposed-provenance/basic.rs tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline1.rs -tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print.rs tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.rs tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.rs tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs -tests/ui/codegen/equal-pointers-unequal/strict-provenance/basic.rs -tests/ui/codegen/equal-pointers-unequal/strict-provenance/function.rs -tests/ui/codegen/equal-pointers-unequal/strict-provenance/print.rs tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline1.rs tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs diff --git a/tests/lang_tests_common.rs b/tests/lang_tests_common.rs index d5a0d71c4b298..bdcf14b4b26d4 100644 --- a/tests/lang_tests_common.rs +++ b/tests/lang_tests_common.rs @@ -42,7 +42,9 @@ pub fn main_inner(profile: Profile) { .expect("failed to get absolute path of `gcc-path`") .display() .to_string(); - env::set_var("LD_LIBRARY_PATH", gcc_path); + unsafe { + env::set_var("LD_LIBRARY_PATH", gcc_path); + } fn rust_filter(path: &Path) -> bool { path.is_file() && path.extension().expect("extension").to_str().expect("to_str") == "rs" @@ -67,15 +69,14 @@ pub fn main_inner(profile: Profile) { .test_dir("tests/run") .test_path_filter(filter) .test_extract(|path| { - let lines = std::fs::read_to_string(path) + std::fs::read_to_string(path) .expect("read file") .lines() .skip_while(|l| !l.starts_with("//")) .take_while(|l| l.starts_with("//")) .map(|l| &l[2..]) .collect::>() - .join("\n"); - lines + .join("\n") }) .test_cmds(move |path| { // Test command 1: Compile `x.rs` into `tempdir/x`. diff --git a/tests/run/always_inline.rs b/tests/run/always_inline.rs new file mode 100644 index 0000000000000..ebd741ee090c8 --- /dev/null +++ b/tests/run/always_inline.rs @@ -0,0 +1,53 @@ +// Compiler: +// +// Run-time: +// status: 0 + +#![feature(no_core)] +#![no_std] +#![no_core] +#![no_main] + +extern crate mini_core; +use mini_core::*; + +#[inline(always)] +fn fib(n: u8) -> u8 { + if n == 0 { + return 1; + } + if n == 1 { + return 1; + } + fib(n - 1) + fib(n - 2) +} + +#[inline(always)] +fn fib_b(n: u8) -> u8 { + if n == 0 { + return 1; + } + if n == 1 { + return 1; + } + fib_a(n - 1) + fib_a(n - 2) +} + +#[inline(always)] +fn fib_a(n: u8) -> u8 { + if n == 0 { + return 1; + } + if n == 1 { + return 1; + } + fib_b(n - 1) + fib_b(n - 2) +} + +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { + if fib(2) != fib_a(2) { + intrinsics::abort(); + } + 0 +} diff --git a/tests/run/switchint_128bit.rs b/tests/run/switchint_128bit.rs new file mode 100644 index 0000000000000..decae5bfcd78d --- /dev/null +++ b/tests/run/switchint_128bit.rs @@ -0,0 +1,37 @@ +// Compiler: +// +// Run-time: +// status: 0 + +#![feature(no_core)] +#![no_std] +#![no_core] +#![no_main] + +extern crate mini_core; +use intrinsics::black_box; +use mini_core::*; + +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { + // 1st. Check that small 128 bit values work. + let val = black_box(64_u128); + match val { + 0 => return 1, + 1 => return 2, + 64 => (), + _ => return 3, + } + // 2nd check that *large* values work. + const BIG: u128 = 0xDEAD_C0FE_BEEF_DECAF_BADD_DECAF_BEEF_u128; + let val = black_box(BIG); + match val { + 0 => return 4, + 1 => return 5, + // Check that we will not match on the lower u64, if the upper qword is different! + 0xcafbadddecafbeef => return 6, + 0xDEAD_C0FE_BEEF_DECAF_BADD_DECAF_BEEF_u128 => (), + _ => return 7, + } + 0 +} diff --git a/tools/generate_intrinsics.py b/tools/generate_intrinsics.py index 8efed3e43af85..181f1e501a40a 100644 --- a/tools/generate_intrinsics.py +++ b/tools/generate_intrinsics.py @@ -12,7 +12,7 @@ def run_command(command, cwd=None): sys.exit(1) -def clone_repository(repo_name, path, repo_url, sub_paths=None): +def clone_repository(repo_name, path, repo_url, branch="master", sub_paths=None): if os.path.exists(path): while True: choice = input("There is already a `{}` folder, do you want to update it? [y/N]".format(path)) @@ -21,7 +21,7 @@ def clone_repository(repo_name, path, repo_url, sub_paths=None): return elif choice.lower() == "y": print("Updating repository...") - run_command(["git", "pull", "origin"], cwd=path) + run_command(["git", "pull", "origin", branch], cwd=path) return else: print("Didn't understand answer...") @@ -209,6 +209,7 @@ def main(): "llvm-project", llvm_path, "https://github.com/llvm/llvm-project", + branch="main", sub_paths=["llvm/include/llvm/IR", "llvm/include/llvm/CodeGen/"], ) clone_repository( diff --git a/triagebot.toml b/triagebot.toml new file mode 100644 index 0000000000000..13da0a87def3c --- /dev/null +++ b/triagebot.toml @@ -0,0 +1,7 @@ +# Documentation at https://forge.rust-lang.org/triagebot/index.html + +# Prevents un-canonicalized issue links (to avoid wrong issues being linked in r-l/rust) +[issue-links] + +# Prevents mentions in commits to avoid users being spammed +[no-mentions] From 1267333ef102d854cf0cefef877ba0d9adb07107 Mon Sep 17 00:00:00 2001 From: Jamie Date: Wed, 14 May 2025 13:32:41 +0100 Subject: [PATCH 2264/4206] Improve ternary operator recovery --- compiler/rustc_parse/messages.ftl | 3 +- compiler/rustc_parse/src/errors.rs | 20 ++++++++++- .../rustc_parse/src/parser/diagnostics.rs | 34 ++++++++++++++----- compiler/rustc_parse/src/parser/stmt.rs | 7 +++- tests/ui/parser/ternary_operator.rs | 6 ++++ tests/ui/parser/ternary_operator.stderr | 22 +++++++++--- 6 files changed, 75 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index f88c15785d336..a6919afef12cf 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -815,7 +815,6 @@ parse_switch_ref_box_order = switch the order of `ref` and `box` .suggestion = swap them parse_ternary_operator = Rust has no ternary operator - .help = use an `if-else` expression instead parse_tilde_is_not_unary_operator = `~` cannot be used as a unary operator .suggestion = use `!` to perform bitwise not @@ -963,6 +962,8 @@ parse_use_empty_block_not_semi = expected { "`{}`" }, found `;` parse_use_eq_instead = unexpected `==` .suggestion = try using `=` instead +parse_use_if_else = use an `if-else` expression instead + parse_use_let_not_auto = write `let` instead of `auto` to introduce a new variable parse_use_let_not_var = write `let` instead of `var` to introduce a new variable diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 766baf6f80c75..31a48b22cfee1 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -436,10 +436,28 @@ pub(crate) enum IfExpressionMissingThenBlockSub { #[derive(Diagnostic)] #[diag(parse_ternary_operator)] -#[help] pub(crate) struct TernaryOperator { #[primary_span] pub span: Span, + /// If we have a span for the condition expression, suggest the if/else + #[subdiagnostic] + pub sugg: Option, + /// Otherwise, just print the suggestion message + #[help(parse_use_if_else)] + pub no_sugg: bool, +} + +#[derive(Subdiagnostic, Copy, Clone)] +#[multipart_suggestion(parse_use_if_else, applicability = "maybe-incorrect", style = "verbose")] +pub(crate) struct TernaryOperatorSuggestion { + #[suggestion_part(code = "if ")] + pub before_cond: Span, + #[suggestion_part(code = "{{")] + pub question: Span, + #[suggestion_part(code = "}} else {{")] + pub colon: Span, + #[suggestion_part(code = " }}")] + pub end: Span, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 23c8db7bca784..6277dde7c974c 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -41,8 +41,9 @@ use crate::errors::{ IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, - TernaryOperator, UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, - UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType, + TernaryOperator, TernaryOperatorSuggestion, UnexpectedConstInGenericParam, + UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, + UseEqInstead, WrapType, }; use crate::parser::attr::InnerAttrPolicy; use crate::{exp, fluent_generated as fluent}; @@ -497,7 +498,7 @@ impl<'a> Parser<'a> { // If the user is trying to write a ternary expression, recover it and // return an Err to prevent a cascade of irrelevant diagnostics. if self.prev_token == token::Question - && let Err(e) = self.maybe_recover_from_ternary_operator() + && let Err(e) = self.maybe_recover_from_ternary_operator(None) { return Err(e); } @@ -1602,12 +1603,18 @@ impl<'a> Parser<'a> { /// Rust has no ternary operator (`cond ? then : else`). Parse it and try /// to recover from it if `then` and `else` are valid expressions. Returns /// an err if this appears to be a ternary expression. - pub(super) fn maybe_recover_from_ternary_operator(&mut self) -> PResult<'a, ()> { + /// If we have the span of the condition, we can provide a better error span + /// and code suggestion. + pub(super) fn maybe_recover_from_ternary_operator( + &mut self, + cond: Option, + ) -> PResult<'a, ()> { if self.prev_token != token::Question { return PResult::Ok(()); } - let lo = self.prev_token.span.lo(); + let question = self.prev_token.span; + let lo = cond.unwrap_or(question).lo(); let snapshot = self.create_snapshot_for_diagnostic(); if match self.parse_expr() { @@ -1620,11 +1627,20 @@ impl<'a> Parser<'a> { } } { if self.eat_noexpect(&token::Colon) { + let colon = self.prev_token.span; match self.parse_expr() { - Ok(_) => { - return Err(self - .dcx() - .create_err(TernaryOperator { span: self.token.span.with_lo(lo) })); + Ok(expr) => { + let sugg = cond.map(|cond| TernaryOperatorSuggestion { + before_cond: cond.shrink_to_lo(), + question, + colon, + end: expr.span.shrink_to_hi(), + }); + return Err(self.dcx().create_err(TernaryOperator { + span: self.prev_token.span.with_lo(lo), + sugg, + no_sugg: sugg.is_none(), + })); } Err(err) => { err.cancel(); diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 885a65d4de7a1..396ded96bde13 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -879,7 +879,12 @@ impl<'a> Parser<'a> { { // Just check for errors and recover; do not eat semicolon yet. - let expect_result = self.expect_one_of(&[], &[exp!(Semi), exp!(CloseBrace)]); + let expect_result = + if let Err(e) = self.maybe_recover_from_ternary_operator(Some(expr.span)) { + Err(e) + } else { + self.expect_one_of(&[], &[exp!(Semi), exp!(CloseBrace)]) + }; // Try to both emit a better diagnostic, and avoid further errors by replacing // the `expr` with `ExprKind::Err`. diff --git a/tests/ui/parser/ternary_operator.rs b/tests/ui/parser/ternary_operator.rs index c8810781b3d84..08f6a4b2a244f 100644 --- a/tests/ui/parser/ternary_operator.rs +++ b/tests/ui/parser/ternary_operator.rs @@ -28,3 +28,9 @@ fn main() { //~| HELP use an `if-else` expression instead //~| ERROR expected one of `.`, `;`, `?`, `else`, or an operator, found `:` } + +fn expr(a: u64, b: u64) -> u64 { + a > b ? a : b + //~^ ERROR Rust has no ternary operator + //~| HELP use an `if-else` expression instead +} diff --git a/tests/ui/parser/ternary_operator.stderr b/tests/ui/parser/ternary_operator.stderr index e12a7ff3718e0..d4a633e5e5571 100644 --- a/tests/ui/parser/ternary_operator.stderr +++ b/tests/ui/parser/ternary_operator.stderr @@ -2,7 +2,7 @@ error: Rust has no ternary operator --> $DIR/ternary_operator.rs:2:19 | LL | let x = 5 > 2 ? true : false; - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ | = help: use an `if-else` expression instead @@ -10,7 +10,7 @@ error: Rust has no ternary operator --> $DIR/ternary_operator.rs:8:19 | LL | let x = 5 > 2 ? { true } : { false }; - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ | = help: use an `if-else` expression instead @@ -18,7 +18,7 @@ error: Rust has no ternary operator --> $DIR/ternary_operator.rs:14:19 | LL | let x = 5 > 2 ? f32::MAX : f32::MIN; - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ | = help: use an `if-else` expression instead @@ -38,9 +38,21 @@ error: Rust has no ternary operator --> $DIR/ternary_operator.rs:26:19 | LL | let x = 5 > 2 ? { let x = vec![]: Vec; x } : { false }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use an `if-else` expression instead -error: aborting due to 6 previous errors +error: Rust has no ternary operator + --> $DIR/ternary_operator.rs:33:5 + | +LL | a > b ? a : b + | ^^^^^^^^^^^^^ + | +help: use an `if-else` expression instead + | +LL - a > b ? a : b +LL + if a > b { a } else { b } + | + +error: aborting due to 7 previous errors From 2b9256e1c8454255441983446ca6bb63a6d8a199 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 25 Feb 2025 06:06:18 +0000 Subject: [PATCH 2265/4206] Move applicable float tests from `coretests` back to `std` The previous commit moved all test files from `std` to `core` so git understands the move. Not all functionality is actually testable in `core`, however, so perform move the relevant portions back. Changes from inherent to module methods is also done since this is the form of math operations available in `core` (as `core_float_math`). --- library/coretests/tests/floats/f128.rs | 287 +----------------- library/coretests/tests/floats/f16.rs | 271 +---------------- library/coretests/tests/floats/f32.rs | 390 +++++-------------------- library/coretests/tests/floats/f64.rs | 363 ++++------------------- library/coretests/tests/floats/mod.rs | 4 - library/coretests/tests/lib.rs | 6 + library/std/tests/floats/f128.rs | 321 ++++++++++++++++++++ library/std/tests/floats/f16.rs | 300 +++++++++++++++++++ library/std/tests/floats/f32.rs | 253 ++++++++++++++++ library/std/tests/floats/f64.rs | 249 ++++++++++++++++ library/std/tests/floats/lib.rs | 43 +++ 11 files changed, 1314 insertions(+), 1173 deletions(-) create mode 100644 library/std/tests/floats/f128.rs create mode 100644 library/std/tests/floats/f16.rs create mode 100644 library/std/tests/floats/f32.rs create mode 100644 library/std/tests/floats/f64.rs create mode 100644 library/std/tests/floats/lib.rs diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index c2618f3b315e9..12cf651f03f46 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -10,19 +10,13 @@ use std::ops::{Add, Div, Mul, Sub}; // Note these tolerances make sense around zero, but not for more extreme exponents. -/// For operations that are near exact, usually not involving math of different -/// signs. -const TOL_PRECISE: f128 = 1e-28; - /// Default tolerances. Works for values that should be near precise but not exact. Roughly /// the precision carried by `100 * 100`. const TOL: f128 = 1e-12; -/// Tolerances for math that is allowed to be imprecise, usually due to multiple chained -/// operations. -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -const TOL_IMPR: f128 = 1e-10; +/// For operations that are near exact, usually not involving math of different +/// signs. +const TOL_PRECISE: f128 = 1e-28; /// Smallest number const TINY_BITS: u128 = 0x1; @@ -500,8 +494,6 @@ fn test_recip() { assert_eq!(neg_inf.recip(), 0.0); } -// Many math functions allow for less accurate results, so the next tolerance up is used - #[test] #[cfg(not(miri))] #[cfg(target_has_reliable_f128_math)] @@ -518,24 +510,6 @@ fn test_powi() { assert_eq!(neg_inf.powi(2), inf); } -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_powf() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_eq!(1.0f128.powf(1.0), 1.0); - assert_approx_eq!(3.4f128.powf(4.5), 246.40818323761892815995637964326426756, TOL_IMPR); - assert_approx_eq!(2.7f128.powf(-3.2), 0.041652009108526178281070304373500889273, TOL_IMPR); - assert_approx_eq!((-3.1f128).powf(2.0), 9.6100000000000005506706202140776519387, TOL_IMPR); - assert_approx_eq!(5.9f128.powf(-2.0), 0.028727377190462507313100483690639638451, TOL_IMPR); - assert_eq!(8.3f128.powf(0.0), 1.0); - assert!(nan.powf(2.0).is_nan()); - assert_eq!(inf.powf(2.0), inf); - assert_eq!(neg_inf.powf(3.0), neg_inf); -} - #[test] #[cfg(not(miri))] #[cfg(target_has_reliable_f128_math)] @@ -549,111 +523,6 @@ fn test_sqrt_domain() { assert_eq!(f128::INFINITY.sqrt(), f128::INFINITY); } -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_exp() { - assert_eq!(1.0, 0.0f128.exp()); - assert_approx_eq!(consts::E, 1.0f128.exp(), TOL); - assert_approx_eq!(148.41315910257660342111558004055227962348775, 5.0f128.exp(), TOL); - - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - let nan: f128 = f128::NAN; - assert_eq!(inf, inf.exp()); - assert_eq!(0.0, neg_inf.exp()); - assert!(nan.exp().is_nan()); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_exp2() { - assert_eq!(32.0, 5.0f128.exp2()); - assert_eq!(1.0, 0.0f128.exp2()); - - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - let nan: f128 = f128::NAN; - assert_eq!(inf, inf.exp2()); - assert_eq!(0.0, neg_inf.exp2()); - assert!(nan.exp2().is_nan()); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_ln() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_approx_eq!(1.0f128.exp().ln(), 1.0, TOL); - assert!(nan.ln().is_nan()); - assert_eq!(inf.ln(), inf); - assert!(neg_inf.ln().is_nan()); - assert!((-2.3f128).ln().is_nan()); - assert_eq!((-0.0f128).ln(), neg_inf); - assert_eq!(0.0f128.ln(), neg_inf); - assert_approx_eq!(4.0f128.ln(), 1.3862943611198906188344642429163531366, TOL); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_log() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_eq!(10.0f128.log(10.0), 1.0); - assert_approx_eq!(2.3f128.log(3.5), 0.66485771361478710036766645911922010272, TOL); - assert_eq!(1.0f128.exp().log(1.0f128.exp()), 1.0); - assert!(1.0f128.log(1.0).is_nan()); - assert!(1.0f128.log(-13.9).is_nan()); - assert!(nan.log(2.3).is_nan()); - assert_eq!(inf.log(10.0), inf); - assert!(neg_inf.log(8.8).is_nan()); - assert!((-2.3f128).log(0.1).is_nan()); - assert_eq!((-0.0f128).log(2.0), neg_inf); - assert_eq!(0.0f128.log(7.0), neg_inf); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_log2() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_approx_eq!(10.0f128.log2(), 3.32192809488736234787031942948939017, TOL); - assert_approx_eq!(2.3f128.log2(), 1.2016338611696504130002982471978765921, TOL); - assert_approx_eq!(1.0f128.exp().log2(), 1.4426950408889634073599246810018921381, TOL); - assert!(nan.log2().is_nan()); - assert_eq!(inf.log2(), inf); - assert!(neg_inf.log2().is_nan()); - assert!((-2.3f128).log2().is_nan()); - assert_eq!((-0.0f128).log2(), neg_inf); - assert_eq!(0.0f128.log2(), neg_inf); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_log10() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_eq!(10.0f128.log10(), 1.0); - assert_approx_eq!(2.3f128.log10(), 0.36172783601759284532595218865859309898, TOL); - assert_approx_eq!(1.0f128.exp().log10(), 0.43429448190325182765112891891660508222, TOL); - assert_eq!(1.0f128.log10(), 0.0); - assert!(nan.log10().is_nan()); - assert_eq!(inf.log10(), inf); - assert!(neg_inf.log10().is_nan()); - assert!((-2.3f128).log10().is_nan()); - assert_eq!((-0.0f128).log10(), neg_inf); - assert_eq!(0.0f128.log10(), neg_inf); -} - #[test] fn test_to_degrees() { let pi: f128 = consts::PI; @@ -686,156 +555,6 @@ fn test_to_radians() { assert_eq!(neg_inf.to_radians(), neg_inf); } -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_asinh() { - // Lower accuracy results are allowed, use increased tolerances - assert_eq!(0.0f128.asinh(), 0.0f128); - assert_eq!((-0.0f128).asinh(), -0.0f128); - - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - let nan: f128 = f128::NAN; - assert_eq!(inf.asinh(), inf); - assert_eq!(neg_inf.asinh(), neg_inf); - assert!(nan.asinh().is_nan()); - assert!((-0.0f128).asinh().is_sign_negative()); - - // issue 63271 - assert_approx_eq!(2.0f128.asinh(), 1.443635475178810342493276740273105f128, TOL_IMPR); - assert_approx_eq!((-2.0f128).asinh(), -1.443635475178810342493276740273105f128, TOL_IMPR); - // regression test for the catastrophic cancellation fixed in 72486 - assert_approx_eq!( - (-67452098.07139316f128).asinh(), - -18.720075426274544393985484294000831757220, - TOL_IMPR - ); - - // test for low accuracy from issue 104548 - assert_approx_eq!(60.0f128, 60.0f128.sinh().asinh(), TOL_IMPR); - // mul needed for approximate comparison to be meaningful - assert_approx_eq!(1.0f128, 1e-15f128.sinh().asinh() * 1e15f128, TOL_IMPR); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_acosh() { - assert_eq!(1.0f128.acosh(), 0.0f128); - assert!(0.999f128.acosh().is_nan()); - - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - let nan: f128 = f128::NAN; - assert_eq!(inf.acosh(), inf); - assert!(neg_inf.acosh().is_nan()); - assert!(nan.acosh().is_nan()); - assert_approx_eq!(2.0f128.acosh(), 1.31695789692481670862504634730796844f128, TOL_IMPR); - assert_approx_eq!(3.0f128.acosh(), 1.76274717403908605046521864995958461f128, TOL_IMPR); - - // test for low accuracy from issue 104548 - assert_approx_eq!(60.0f128, 60.0f128.cosh().acosh(), TOL_IMPR); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_atanh() { - assert_eq!(0.0f128.atanh(), 0.0f128); - assert_eq!((-0.0f128).atanh(), -0.0f128); - - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - let nan: f128 = f128::NAN; - assert_eq!(1.0f128.atanh(), inf); - assert_eq!((-1.0f128).atanh(), neg_inf); - assert!(2f128.atanh().atanh().is_nan()); - assert!((-2f128).atanh().atanh().is_nan()); - assert!(inf.atanh().is_nan()); - assert!(neg_inf.atanh().is_nan()); - assert!(nan.atanh().is_nan()); - assert_approx_eq!(0.5f128.atanh(), 0.54930614433405484569762261846126285f128, TOL_IMPR); - assert_approx_eq!((-0.5f128).atanh(), -0.54930614433405484569762261846126285f128, TOL_IMPR); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_gamma() { - // precision can differ among platforms - assert_approx_eq!(1.0f128.gamma(), 1.0f128, TOL_IMPR); - assert_approx_eq!(2.0f128.gamma(), 1.0f128, TOL_IMPR); - assert_approx_eq!(3.0f128.gamma(), 2.0f128, TOL_IMPR); - assert_approx_eq!(4.0f128.gamma(), 6.0f128, TOL_IMPR); - assert_approx_eq!(5.0f128.gamma(), 24.0f128, TOL_IMPR); - assert_approx_eq!(0.5f128.gamma(), consts::PI.sqrt(), TOL_IMPR); - assert_approx_eq!((-0.5f128).gamma(), -2.0 * consts::PI.sqrt(), TOL_IMPR); - assert_eq!(0.0f128.gamma(), f128::INFINITY); - assert_eq!((-0.0f128).gamma(), f128::NEG_INFINITY); - assert!((-1.0f128).gamma().is_nan()); - assert!((-2.0f128).gamma().is_nan()); - assert!(f128::NAN.gamma().is_nan()); - assert!(f128::NEG_INFINITY.gamma().is_nan()); - assert_eq!(f128::INFINITY.gamma(), f128::INFINITY); - assert_eq!(1760.9f128.gamma(), f128::INFINITY); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_ln_gamma() { - assert_approx_eq!(1.0f128.ln_gamma().0, 0.0f128, TOL_IMPR); - assert_eq!(1.0f128.ln_gamma().1, 1); - assert_approx_eq!(2.0f128.ln_gamma().0, 0.0f128, TOL_IMPR); - assert_eq!(2.0f128.ln_gamma().1, 1); - assert_approx_eq!(3.0f128.ln_gamma().0, 2.0f128.ln(), TOL_IMPR); - assert_eq!(3.0f128.ln_gamma().1, 1); - assert_approx_eq!((-0.5f128).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln(), TOL_IMPR); - assert_eq!((-0.5f128).ln_gamma().1, -1); -} - -#[test] -fn test_real_consts() { - let pi: f128 = consts::PI; - let frac_pi_2: f128 = consts::FRAC_PI_2; - let frac_pi_3: f128 = consts::FRAC_PI_3; - let frac_pi_4: f128 = consts::FRAC_PI_4; - let frac_pi_6: f128 = consts::FRAC_PI_6; - let frac_pi_8: f128 = consts::FRAC_PI_8; - let frac_1_pi: f128 = consts::FRAC_1_PI; - let frac_2_pi: f128 = consts::FRAC_2_PI; - - assert_approx_eq!(frac_pi_2, pi / 2f128, TOL_PRECISE); - assert_approx_eq!(frac_pi_3, pi / 3f128, TOL_PRECISE); - assert_approx_eq!(frac_pi_4, pi / 4f128, TOL_PRECISE); - assert_approx_eq!(frac_pi_6, pi / 6f128, TOL_PRECISE); - assert_approx_eq!(frac_pi_8, pi / 8f128, TOL_PRECISE); - assert_approx_eq!(frac_1_pi, 1f128 / pi, TOL_PRECISE); - assert_approx_eq!(frac_2_pi, 2f128 / pi, TOL_PRECISE); - - #[cfg(not(miri))] - #[cfg(target_has_reliable_f128_math)] - { - let frac_2_sqrtpi: f128 = consts::FRAC_2_SQRT_PI; - let sqrt2: f128 = consts::SQRT_2; - let frac_1_sqrt2: f128 = consts::FRAC_1_SQRT_2; - let e: f128 = consts::E; - let log2_e: f128 = consts::LOG2_E; - let log10_e: f128 = consts::LOG10_E; - let ln_2: f128 = consts::LN_2; - let ln_10: f128 = consts::LN_10; - - assert_approx_eq!(frac_2_sqrtpi, 2f128 / pi.sqrt(), TOL_PRECISE); - assert_approx_eq!(sqrt2, 2f128.sqrt(), TOL_PRECISE); - assert_approx_eq!(frac_1_sqrt2, 1f128 / 2f128.sqrt(), TOL_PRECISE); - assert_approx_eq!(log2_e, e.log2(), TOL_PRECISE); - assert_approx_eq!(log10_e, e.log10(), TOL_PRECISE); - assert_approx_eq!(ln_2, 2f128.ln(), TOL_PRECISE); - assert_approx_eq!(ln_10, 10f128.ln(), TOL_PRECISE); - } -} - #[test] fn test_float_bits_conv() { assert_eq!((1f128).to_bits(), 0x3fff0000000000000000000000000000); diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index 70bbcd07160e6..db98181226c85 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -54,7 +54,7 @@ macro_rules! assert_f16_biteq { #[test] fn test_num_f16() { - crate::test_num(10f16, 2f16); + super::test_num(10f16, 2f16); } // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support @@ -492,24 +492,6 @@ fn test_powi() { assert_eq!(neg_inf.powi(2), inf); } -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_powf() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_eq!(1.0f16.powf(1.0), 1.0); - assert_approx_eq!(3.4f16.powf(4.5), 246.408183, TOL_P2); - assert_approx_eq!(2.7f16.powf(-3.2), 0.041652, TOL_N2); - assert_approx_eq!((-3.1f16).powf(2.0), 9.61, TOL_P2); - assert_approx_eq!(5.9f16.powf(-2.0), 0.028727, TOL_N2); - assert_eq!(8.3f16.powf(0.0), 1.0); - assert!(nan.powf(2.0).is_nan()); - assert_eq!(inf.powf(2.0), inf); - assert_eq!(neg_inf.powf(3.0), neg_inf); -} - #[test] #[cfg(not(miri))] #[cfg(target_has_reliable_f16_math)] @@ -523,111 +505,6 @@ fn test_sqrt_domain() { assert_eq!(f16::INFINITY.sqrt(), f16::INFINITY); } -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_exp() { - assert_eq!(1.0, 0.0f16.exp()); - assert_approx_eq!(2.718282, 1.0f16.exp(), TOL_0); - assert_approx_eq!(148.413159, 5.0f16.exp(), TOL_0); - - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - let nan: f16 = f16::NAN; - assert_eq!(inf, inf.exp()); - assert_eq!(0.0, neg_inf.exp()); - assert!(nan.exp().is_nan()); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_exp2() { - assert_eq!(32.0, 5.0f16.exp2()); - assert_eq!(1.0, 0.0f16.exp2()); - - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - let nan: f16 = f16::NAN; - assert_eq!(inf, inf.exp2()); - assert_eq!(0.0, neg_inf.exp2()); - assert!(nan.exp2().is_nan()); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_ln() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_approx_eq!(1.0f16.exp().ln(), 1.0, TOL_0); - assert!(nan.ln().is_nan()); - assert_eq!(inf.ln(), inf); - assert!(neg_inf.ln().is_nan()); - assert!((-2.3f16).ln().is_nan()); - assert_eq!((-0.0f16).ln(), neg_inf); - assert_eq!(0.0f16.ln(), neg_inf); - assert_approx_eq!(4.0f16.ln(), 1.386294, TOL_0); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_log() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_eq!(10.0f16.log(10.0), 1.0); - assert_approx_eq!(2.3f16.log(3.5), 0.664858, TOL_0); - assert_eq!(1.0f16.exp().log(1.0f16.exp()), 1.0); - assert!(1.0f16.log(1.0).is_nan()); - assert!(1.0f16.log(-13.9).is_nan()); - assert!(nan.log(2.3).is_nan()); - assert_eq!(inf.log(10.0), inf); - assert!(neg_inf.log(8.8).is_nan()); - assert!((-2.3f16).log(0.1).is_nan()); - assert_eq!((-0.0f16).log(2.0), neg_inf); - assert_eq!(0.0f16.log(7.0), neg_inf); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_log2() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_approx_eq!(10.0f16.log2(), 3.321928, TOL_0); - assert_approx_eq!(2.3f16.log2(), 1.201634, TOL_0); - assert_approx_eq!(1.0f16.exp().log2(), 1.442695, TOL_0); - assert!(nan.log2().is_nan()); - assert_eq!(inf.log2(), inf); - assert!(neg_inf.log2().is_nan()); - assert!((-2.3f16).log2().is_nan()); - assert_eq!((-0.0f16).log2(), neg_inf); - assert_eq!(0.0f16.log2(), neg_inf); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_log10() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_eq!(10.0f16.log10(), 1.0); - assert_approx_eq!(2.3f16.log10(), 0.361728, TOL_0); - assert_approx_eq!(1.0f16.exp().log10(), 0.434294, TOL_0); - assert_eq!(1.0f16.log10(), 0.0); - assert!(nan.log10().is_nan()); - assert_eq!(inf.log10(), inf); - assert!(neg_inf.log10().is_nan()); - assert!((-2.3f16).log10().is_nan()); - assert_eq!((-0.0f16).log10(), neg_inf); - assert_eq!(0.0f16.log10(), neg_inf); -} - #[test] fn test_to_degrees() { let pi: f16 = consts::PI; @@ -658,152 +535,6 @@ fn test_to_radians() { assert_eq!(neg_inf.to_radians(), neg_inf); } -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_asinh() { - assert_eq!(0.0f16.asinh(), 0.0f16); - assert_eq!((-0.0f16).asinh(), -0.0f16); - - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - let nan: f16 = f16::NAN; - assert_eq!(inf.asinh(), inf); - assert_eq!(neg_inf.asinh(), neg_inf); - assert!(nan.asinh().is_nan()); - assert!((-0.0f16).asinh().is_sign_negative()); - // issue 63271 - assert_approx_eq!(2.0f16.asinh(), 1.443635475178810342493276740273105f16, TOL_0); - assert_approx_eq!((-2.0f16).asinh(), -1.443635475178810342493276740273105f16, TOL_0); - // regression test for the catastrophic cancellation fixed in 72486 - assert_approx_eq!((-200.0f16).asinh(), -5.991470797049389, TOL_0); - - // test for low accuracy from issue 104548 - assert_approx_eq!(10.0f16, 10.0f16.sinh().asinh(), TOL_0); - // mul needed for approximate comparison to be meaningful - assert_approx_eq!(1.0f16, 1e-3f16.sinh().asinh() * 1e3f16, TOL_0); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_acosh() { - assert_eq!(1.0f16.acosh(), 0.0f16); - assert!(0.999f16.acosh().is_nan()); - - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - let nan: f16 = f16::NAN; - assert_eq!(inf.acosh(), inf); - assert!(neg_inf.acosh().is_nan()); - assert!(nan.acosh().is_nan()); - assert_approx_eq!(2.0f16.acosh(), 1.31695789692481670862504634730796844f16, TOL_0); - assert_approx_eq!(3.0f16.acosh(), 1.76274717403908605046521864995958461f16, TOL_0); - - // test for low accuracy from issue 104548 - assert_approx_eq!(10.0f16, 10.0f16.cosh().acosh(), TOL_P2); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_atanh() { - assert_eq!(0.0f16.atanh(), 0.0f16); - assert_eq!((-0.0f16).atanh(), -0.0f16); - - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - let nan: f16 = f16::NAN; - assert_eq!(1.0f16.atanh(), inf); - assert_eq!((-1.0f16).atanh(), neg_inf); - assert!(2f16.atanh().atanh().is_nan()); - assert!((-2f16).atanh().atanh().is_nan()); - assert!(inf.atanh().is_nan()); - assert!(neg_inf.atanh().is_nan()); - assert!(nan.atanh().is_nan()); - assert_approx_eq!(0.5f16.atanh(), 0.54930614433405484569762261846126285f16, TOL_0); - assert_approx_eq!((-0.5f16).atanh(), -0.54930614433405484569762261846126285f16, TOL_0); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_gamma() { - // precision can differ among platforms - assert_approx_eq!(1.0f16.gamma(), 1.0f16, TOL_0); - assert_approx_eq!(2.0f16.gamma(), 1.0f16, TOL_0); - assert_approx_eq!(3.0f16.gamma(), 2.0f16, TOL_0); - assert_approx_eq!(4.0f16.gamma(), 6.0f16, TOL_0); - assert_approx_eq!(5.0f16.gamma(), 24.0f16, TOL_0); - assert_approx_eq!(0.5f16.gamma(), consts::PI.sqrt(), TOL_0); - assert_approx_eq!((-0.5f16).gamma(), -2.0 * consts::PI.sqrt(), TOL_0); - assert_eq!(0.0f16.gamma(), f16::INFINITY); - assert_eq!((-0.0f16).gamma(), f16::NEG_INFINITY); - assert!((-1.0f16).gamma().is_nan()); - assert!((-2.0f16).gamma().is_nan()); - assert!(f16::NAN.gamma().is_nan()); - assert!(f16::NEG_INFINITY.gamma().is_nan()); - assert_eq!(f16::INFINITY.gamma(), f16::INFINITY); - assert_eq!(171.71f16.gamma(), f16::INFINITY); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_ln_gamma() { - assert_approx_eq!(1.0f16.ln_gamma().0, 0.0f16, TOL_0); - assert_eq!(1.0f16.ln_gamma().1, 1); - assert_approx_eq!(2.0f16.ln_gamma().0, 0.0f16, TOL_0); - assert_eq!(2.0f16.ln_gamma().1, 1); - assert_approx_eq!(3.0f16.ln_gamma().0, 2.0f16.ln(), TOL_0); - assert_eq!(3.0f16.ln_gamma().1, 1); - assert_approx_eq!((-0.5f16).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln(), TOL_0); - assert_eq!((-0.5f16).ln_gamma().1, -1); -} - -#[test] -fn test_real_consts() { - // FIXME(f16_f128): add math tests when available - - let pi: f16 = consts::PI; - let frac_pi_2: f16 = consts::FRAC_PI_2; - let frac_pi_3: f16 = consts::FRAC_PI_3; - let frac_pi_4: f16 = consts::FRAC_PI_4; - let frac_pi_6: f16 = consts::FRAC_PI_6; - let frac_pi_8: f16 = consts::FRAC_PI_8; - let frac_1_pi: f16 = consts::FRAC_1_PI; - let frac_2_pi: f16 = consts::FRAC_2_PI; - - assert_approx_eq!(frac_pi_2, pi / 2f16, TOL_0); - assert_approx_eq!(frac_pi_3, pi / 3f16, TOL_0); - assert_approx_eq!(frac_pi_4, pi / 4f16, TOL_0); - assert_approx_eq!(frac_pi_6, pi / 6f16, TOL_0); - assert_approx_eq!(frac_pi_8, pi / 8f16, TOL_0); - assert_approx_eq!(frac_1_pi, 1f16 / pi, TOL_0); - assert_approx_eq!(frac_2_pi, 2f16 / pi, TOL_0); - - #[cfg(not(miri))] - #[cfg(target_has_reliable_f16_math)] - { - let frac_2_sqrtpi: f16 = consts::FRAC_2_SQRT_PI; - let sqrt2: f16 = consts::SQRT_2; - let frac_1_sqrt2: f16 = consts::FRAC_1_SQRT_2; - let e: f16 = consts::E; - let log2_e: f16 = consts::LOG2_E; - let log10_e: f16 = consts::LOG10_E; - let ln_2: f16 = consts::LN_2; - let ln_10: f16 = consts::LN_10; - - assert_approx_eq!(frac_2_sqrtpi, 2f16 / pi.sqrt(), TOL_0); - assert_approx_eq!(sqrt2, 2f16.sqrt(), TOL_0); - assert_approx_eq!(frac_1_sqrt2, 1f16 / 2f16.sqrt(), TOL_0); - assert_approx_eq!(log2_e, e.log2(), TOL_0); - assert_approx_eq!(log10_e, e.log10(), TOL_0); - assert_approx_eq!(ln_2, 2f16.ln(), TOL_0); - assert_approx_eq!(ln_10, 10f16.ln(), TOL_0); - } -} - #[test] fn test_float_bits_conv() { assert_eq!((1f16).to_bits(), 0x3c00); diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 9af23afc5bbfc..1c018a5e7b52f 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -1,5 +1,6 @@ -use std::f32::consts; -use std::num::FpCategory as Fp; +use core::f32; +use core::f32::consts; +use core::num::FpCategory as Fp; /// Smallest number const TINY_BITS: u32 = 0x1; @@ -35,7 +36,7 @@ macro_rules! assert_f32_biteq { #[test] fn test_num_f32() { - crate::test_num(10f32, 2f32); + super::test_num(10f32, 2f32); } #[test] @@ -214,88 +215,88 @@ fn test_classify() { #[test] fn test_floor() { - assert_approx_eq!(1.0f32.floor(), 1.0f32); - assert_approx_eq!(1.3f32.floor(), 1.0f32); - assert_approx_eq!(1.5f32.floor(), 1.0f32); - assert_approx_eq!(1.7f32.floor(), 1.0f32); - assert_approx_eq!(0.0f32.floor(), 0.0f32); - assert_approx_eq!((-0.0f32).floor(), -0.0f32); - assert_approx_eq!((-1.0f32).floor(), -1.0f32); - assert_approx_eq!((-1.3f32).floor(), -2.0f32); - assert_approx_eq!((-1.5f32).floor(), -2.0f32); - assert_approx_eq!((-1.7f32).floor(), -2.0f32); + assert_approx_eq!(f32::floor(1.0f32), 1.0f32); + assert_approx_eq!(f32::floor(1.3f32), 1.0f32); + assert_approx_eq!(f32::floor(1.5f32), 1.0f32); + assert_approx_eq!(f32::floor(1.7f32), 1.0f32); + assert_approx_eq!(f32::floor(0.0f32), 0.0f32); + assert_approx_eq!(f32::floor(-0.0f32), -0.0f32); + assert_approx_eq!(f32::floor(-1.0f32), -1.0f32); + assert_approx_eq!(f32::floor(-1.3f32), -2.0f32); + assert_approx_eq!(f32::floor(-1.5f32), -2.0f32); + assert_approx_eq!(f32::floor(-1.7f32), -2.0f32); } #[test] fn test_ceil() { - assert_approx_eq!(1.0f32.ceil(), 1.0f32); - assert_approx_eq!(1.3f32.ceil(), 2.0f32); - assert_approx_eq!(1.5f32.ceil(), 2.0f32); - assert_approx_eq!(1.7f32.ceil(), 2.0f32); - assert_approx_eq!(0.0f32.ceil(), 0.0f32); - assert_approx_eq!((-0.0f32).ceil(), -0.0f32); - assert_approx_eq!((-1.0f32).ceil(), -1.0f32); - assert_approx_eq!((-1.3f32).ceil(), -1.0f32); - assert_approx_eq!((-1.5f32).ceil(), -1.0f32); - assert_approx_eq!((-1.7f32).ceil(), -1.0f32); + assert_approx_eq!(f32::ceil(1.0f32), 1.0f32); + assert_approx_eq!(f32::ceil(1.3f32), 2.0f32); + assert_approx_eq!(f32::ceil(1.5f32), 2.0f32); + assert_approx_eq!(f32::ceil(1.7f32), 2.0f32); + assert_approx_eq!(f32::ceil(0.0f32), 0.0f32); + assert_approx_eq!(f32::ceil(-0.0f32), -0.0f32); + assert_approx_eq!(f32::ceil(-1.0f32), -1.0f32); + assert_approx_eq!(f32::ceil(-1.3f32), -1.0f32); + assert_approx_eq!(f32::ceil(-1.5f32), -1.0f32); + assert_approx_eq!(f32::ceil(-1.7f32), -1.0f32); } #[test] fn test_round() { - assert_approx_eq!(2.5f32.round(), 3.0f32); - assert_approx_eq!(1.0f32.round(), 1.0f32); - assert_approx_eq!(1.3f32.round(), 1.0f32); - assert_approx_eq!(1.5f32.round(), 2.0f32); - assert_approx_eq!(1.7f32.round(), 2.0f32); - assert_approx_eq!(0.0f32.round(), 0.0f32); - assert_approx_eq!((-0.0f32).round(), -0.0f32); - assert_approx_eq!((-1.0f32).round(), -1.0f32); - assert_approx_eq!((-1.3f32).round(), -1.0f32); - assert_approx_eq!((-1.5f32).round(), -2.0f32); - assert_approx_eq!((-1.7f32).round(), -2.0f32); + assert_approx_eq!(f32::round(2.5f32), 3.0f32); + assert_approx_eq!(f32::round(1.0f32), 1.0f32); + assert_approx_eq!(f32::round(1.3f32), 1.0f32); + assert_approx_eq!(f32::round(1.5f32), 2.0f32); + assert_approx_eq!(f32::round(1.7f32), 2.0f32); + assert_approx_eq!(f32::round(0.0f32), 0.0f32); + assert_approx_eq!(f32::round(-0.0f32), -0.0f32); + assert_approx_eq!(f32::round(-1.0f32), -1.0f32); + assert_approx_eq!(f32::round(-1.3f32), -1.0f32); + assert_approx_eq!(f32::round(-1.5f32), -2.0f32); + assert_approx_eq!(f32::round(-1.7f32), -2.0f32); } #[test] fn test_round_ties_even() { - assert_approx_eq!(2.5f32.round_ties_even(), 2.0f32); - assert_approx_eq!(1.0f32.round_ties_even(), 1.0f32); - assert_approx_eq!(1.3f32.round_ties_even(), 1.0f32); - assert_approx_eq!(1.5f32.round_ties_even(), 2.0f32); - assert_approx_eq!(1.7f32.round_ties_even(), 2.0f32); - assert_approx_eq!(0.0f32.round_ties_even(), 0.0f32); - assert_approx_eq!((-0.0f32).round_ties_even(), -0.0f32); - assert_approx_eq!((-1.0f32).round_ties_even(), -1.0f32); - assert_approx_eq!((-1.3f32).round_ties_even(), -1.0f32); - assert_approx_eq!((-1.5f32).round_ties_even(), -2.0f32); - assert_approx_eq!((-1.7f32).round_ties_even(), -2.0f32); + assert_approx_eq!(f32::round_ties_even(2.5f32), 2.0f32); + assert_approx_eq!(f32::round_ties_even(1.0f32), 1.0f32); + assert_approx_eq!(f32::round_ties_even(1.3f32), 1.0f32); + assert_approx_eq!(f32::round_ties_even(1.5f32), 2.0f32); + assert_approx_eq!(f32::round_ties_even(1.7f32), 2.0f32); + assert_approx_eq!(f32::round_ties_even(0.0f32), 0.0f32); + assert_approx_eq!(f32::round_ties_even(-0.0f32), -0.0f32); + assert_approx_eq!(f32::round_ties_even(-1.0f32), -1.0f32); + assert_approx_eq!(f32::round_ties_even(-1.3f32), -1.0f32); + assert_approx_eq!(f32::round_ties_even(-1.5f32), -2.0f32); + assert_approx_eq!(f32::round_ties_even(-1.7f32), -2.0f32); } #[test] fn test_trunc() { - assert_approx_eq!(1.0f32.trunc(), 1.0f32); - assert_approx_eq!(1.3f32.trunc(), 1.0f32); - assert_approx_eq!(1.5f32.trunc(), 1.0f32); - assert_approx_eq!(1.7f32.trunc(), 1.0f32); - assert_approx_eq!(0.0f32.trunc(), 0.0f32); - assert_approx_eq!((-0.0f32).trunc(), -0.0f32); - assert_approx_eq!((-1.0f32).trunc(), -1.0f32); - assert_approx_eq!((-1.3f32).trunc(), -1.0f32); - assert_approx_eq!((-1.5f32).trunc(), -1.0f32); - assert_approx_eq!((-1.7f32).trunc(), -1.0f32); + assert_approx_eq!(f32::trunc(1.0f32), 1.0f32); + assert_approx_eq!(f32::trunc(1.3f32), 1.0f32); + assert_approx_eq!(f32::trunc(1.5f32), 1.0f32); + assert_approx_eq!(f32::trunc(1.7f32), 1.0f32); + assert_approx_eq!(f32::trunc(0.0f32), 0.0f32); + assert_approx_eq!(f32::trunc(-0.0f32), -0.0f32); + assert_approx_eq!(f32::trunc(-1.0f32), -1.0f32); + assert_approx_eq!(f32::trunc(-1.3f32), -1.0f32); + assert_approx_eq!(f32::trunc(-1.5f32), -1.0f32); + assert_approx_eq!(f32::trunc(-1.7f32), -1.0f32); } #[test] fn test_fract() { - assert_approx_eq!(1.0f32.fract(), 0.0f32); - assert_approx_eq!(1.3f32.fract(), 0.3f32); - assert_approx_eq!(1.5f32.fract(), 0.5f32); - assert_approx_eq!(1.7f32.fract(), 0.7f32); - assert_approx_eq!(0.0f32.fract(), 0.0f32); - assert_approx_eq!((-0.0f32).fract(), -0.0f32); - assert_approx_eq!((-1.0f32).fract(), -0.0f32); - assert_approx_eq!((-1.3f32).fract(), -0.3f32); - assert_approx_eq!((-1.5f32).fract(), -0.5f32); - assert_approx_eq!((-1.7f32).fract(), -0.7f32); + assert_approx_eq!(f32::fract(1.0f32), 0.0f32); + assert_approx_eq!(f32::fract(1.3f32), 0.3f32); + assert_approx_eq!(f32::fract(1.5f32), 0.5f32); + assert_approx_eq!(f32::fract(1.7f32), 0.7f32); + assert_approx_eq!(f32::fract(0.0f32), 0.0f32); + assert_approx_eq!(f32::fract(-0.0f32), -0.0f32); + assert_approx_eq!(f32::fract(-1.0f32), -0.0f32); + assert_approx_eq!(f32::fract(-1.3f32), -0.3f32); + assert_approx_eq!(f32::fract(-1.5f32), -0.5f32); + assert_approx_eq!(f32::fract(-1.7f32), -0.7f32); } #[test] @@ -414,15 +415,15 @@ fn test_mul_add() { let nan: f32 = f32::NAN; let inf: f32 = f32::INFINITY; let neg_inf: f32 = f32::NEG_INFINITY; - assert_approx_eq!(12.3f32.mul_add(4.5, 6.7), 62.05); - assert_approx_eq!((-12.3f32).mul_add(-4.5, -6.7), 48.65); - assert_approx_eq!(0.0f32.mul_add(8.9, 1.2), 1.2); - assert_approx_eq!(3.4f32.mul_add(-0.0, 5.6), 5.6); - assert!(nan.mul_add(7.8, 9.0).is_nan()); - assert_eq!(inf.mul_add(7.8, 9.0), inf); - assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf); - assert_eq!(8.9f32.mul_add(inf, 3.2), inf); - assert_eq!((-3.2f32).mul_add(2.4, neg_inf), neg_inf); + assert_approx_eq!(f32::mul_add(12.3f32, 4.5, 6.7), 62.05); + assert_approx_eq!(f32::mul_add(-12.3f32, -4.5, -6.7), 48.65); + assert_approx_eq!(f32::mul_add(0.0f32, 8.9, 1.2), 1.2); + assert_approx_eq!(f32::mul_add(3.4f32, -0.0, 5.6), 5.6); + assert!(f32::mul_add(nan, 7.8, 9.0).is_nan()); + assert_eq!(f32::mul_add(inf, 7.8, 9.0), inf); + assert_eq!(f32::mul_add(neg_inf, 7.8, 9.0), neg_inf); + assert_eq!(f32::mul_add(8.9f32, inf, 3.2), inf); + assert_eq!(f32::mul_add(-3.2f32, 2.4, neg_inf), neg_inf); } #[test] @@ -453,22 +454,6 @@ fn test_powi() { assert_eq!(neg_inf.powi(2), inf); } -#[test] -fn test_powf() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(1.0f32.powf(1.0), 1.0); - assert_approx_eq!(3.4f32.powf(4.5), 246.408218); - assert_approx_eq!(2.7f32.powf(-3.2), 0.041652); - assert_approx_eq!((-3.1f32).powf(2.0), 9.61); - assert_approx_eq!(5.9f32.powf(-2.0), 0.028727); - assert_eq!(8.3f32.powf(0.0), 1.0); - assert!(nan.powf(2.0).is_nan()); - assert_eq!(inf.powf(2.0), inf); - assert_eq!(neg_inf.powf(3.0), neg_inf); -} - #[test] fn test_sqrt_domain() { assert!(f32::NAN.sqrt().is_nan()); @@ -480,99 +465,6 @@ fn test_sqrt_domain() { assert_eq!(f32::INFINITY.sqrt(), f32::INFINITY); } -#[test] -fn test_exp() { - assert_eq!(1.0, 0.0f32.exp()); - assert_approx_eq!(2.718282, 1.0f32.exp()); - assert_approx_eq!(148.413162, 5.0f32.exp()); - - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let nan: f32 = f32::NAN; - assert_eq!(inf, inf.exp()); - assert_eq!(0.0, neg_inf.exp()); - assert!(nan.exp().is_nan()); -} - -#[test] -fn test_exp2() { - assert_eq!(32.0, 5.0f32.exp2()); - assert_eq!(1.0, 0.0f32.exp2()); - - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let nan: f32 = f32::NAN; - assert_eq!(inf, inf.exp2()); - assert_eq!(0.0, neg_inf.exp2()); - assert!(nan.exp2().is_nan()); -} - -#[test] -fn test_ln() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_approx_eq!(1.0f32.exp().ln(), 1.0); - assert!(nan.ln().is_nan()); - assert_eq!(inf.ln(), inf); - assert!(neg_inf.ln().is_nan()); - assert!((-2.3f32).ln().is_nan()); - assert_eq!((-0.0f32).ln(), neg_inf); - assert_eq!(0.0f32.ln(), neg_inf); - assert_approx_eq!(4.0f32.ln(), 1.386294); -} - -#[test] -fn test_log() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(10.0f32.log(10.0), 1.0); - assert_approx_eq!(2.3f32.log(3.5), 0.664858); - assert_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0); - assert!(1.0f32.log(1.0).is_nan()); - assert!(1.0f32.log(-13.9).is_nan()); - assert!(nan.log(2.3).is_nan()); - assert_eq!(inf.log(10.0), inf); - assert!(neg_inf.log(8.8).is_nan()); - assert!((-2.3f32).log(0.1).is_nan()); - assert_eq!((-0.0f32).log(2.0), neg_inf); - assert_eq!(0.0f32.log(7.0), neg_inf); -} - -#[test] -fn test_log2() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_approx_eq!(10.0f32.log2(), 3.321928); - assert_approx_eq!(2.3f32.log2(), 1.201634); - assert_approx_eq!(1.0f32.exp().log2(), 1.442695); - assert!(nan.log2().is_nan()); - assert_eq!(inf.log2(), inf); - assert!(neg_inf.log2().is_nan()); - assert!((-2.3f32).log2().is_nan()); - assert_eq!((-0.0f32).log2(), neg_inf); - assert_eq!(0.0f32.log2(), neg_inf); -} - -#[test] -fn test_log10() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(10.0f32.log10(), 1.0); - assert_approx_eq!(2.3f32.log10(), 0.361728); - assert_approx_eq!(1.0f32.exp().log10(), 0.434294); - assert_eq!(1.0f32.log10(), 0.0); - assert!(nan.log10().is_nan()); - assert_eq!(inf.log10(), inf); - assert!(neg_inf.log10().is_nan()); - assert!((-2.3f32).log10().is_nan()); - assert_eq!((-0.0f32).log10(), neg_inf); - assert_eq!(0.0f32.log10(), neg_inf); -} - #[test] fn test_to_degrees() { let pi: f32 = consts::PI; @@ -603,138 +495,6 @@ fn test_to_radians() { assert_eq!(neg_inf.to_radians(), neg_inf); } -#[test] -fn test_asinh() { - assert_eq!(0.0f32.asinh(), 0.0f32); - assert_eq!((-0.0f32).asinh(), -0.0f32); - - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let nan: f32 = f32::NAN; - assert_eq!(inf.asinh(), inf); - assert_eq!(neg_inf.asinh(), neg_inf); - assert!(nan.asinh().is_nan()); - assert!((-0.0f32).asinh().is_sign_negative()); // issue 63271 - assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32); - assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32); - // regression test for the catastrophic cancellation fixed in 72486 - assert_approx_eq!((-3000.0f32).asinh(), -8.699514775987968673236893537700647f32); - - // test for low accuracy from issue 104548 - assert_approx_eq!(60.0f32, 60.0f32.sinh().asinh()); - // mul needed for approximate comparison to be meaningful - assert_approx_eq!(1.0f32, 1e-15f32.sinh().asinh() * 1e15f32); -} - -#[test] -fn test_acosh() { - assert_eq!(1.0f32.acosh(), 0.0f32); - assert!(0.999f32.acosh().is_nan()); - - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let nan: f32 = f32::NAN; - assert_eq!(inf.acosh(), inf); - assert!(neg_inf.acosh().is_nan()); - assert!(nan.acosh().is_nan()); - assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32); - assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32); - - // test for low accuracy from issue 104548 - assert_approx_eq!(60.0f32, 60.0f32.cosh().acosh()); -} - -#[test] -fn test_atanh() { - assert_eq!(0.0f32.atanh(), 0.0f32); - assert_eq!((-0.0f32).atanh(), -0.0f32); - - let inf32: f32 = f32::INFINITY; - let neg_inf32: f32 = f32::NEG_INFINITY; - assert_eq!(1.0f32.atanh(), inf32); - assert_eq!((-1.0f32).atanh(), neg_inf32); - - assert!(2f64.atanh().atanh().is_nan()); - assert!((-2f64).atanh().atanh().is_nan()); - - let inf64: f32 = f32::INFINITY; - let neg_inf64: f32 = f32::NEG_INFINITY; - let nan32: f32 = f32::NAN; - assert!(inf64.atanh().is_nan()); - assert!(neg_inf64.atanh().is_nan()); - assert!(nan32.atanh().is_nan()); - - assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32); - assert_approx_eq!((-0.5f32).atanh(), -0.54930614433405484569762261846126285f32); -} - -#[test] -fn test_gamma() { - // precision can differ between platforms - assert_approx_eq!(1.0f32.gamma(), 1.0f32); - assert_approx_eq!(2.0f32.gamma(), 1.0f32); - assert_approx_eq!(3.0f32.gamma(), 2.0f32); - assert_approx_eq!(4.0f32.gamma(), 6.0f32); - assert_approx_eq!(5.0f32.gamma(), 24.0f32); - assert_approx_eq!(0.5f32.gamma(), consts::PI.sqrt()); - assert_approx_eq!((-0.5f32).gamma(), -2.0 * consts::PI.sqrt()); - assert_eq!(0.0f32.gamma(), f32::INFINITY); - assert_eq!((-0.0f32).gamma(), f32::NEG_INFINITY); - assert!((-1.0f32).gamma().is_nan()); - assert!((-2.0f32).gamma().is_nan()); - assert!(f32::NAN.gamma().is_nan()); - assert!(f32::NEG_INFINITY.gamma().is_nan()); - assert_eq!(f32::INFINITY.gamma(), f32::INFINITY); - assert_eq!(171.71f32.gamma(), f32::INFINITY); -} - -#[test] -fn test_ln_gamma() { - assert_approx_eq!(1.0f32.ln_gamma().0, 0.0f32); - assert_eq!(1.0f32.ln_gamma().1, 1); - assert_approx_eq!(2.0f32.ln_gamma().0, 0.0f32); - assert_eq!(2.0f32.ln_gamma().1, 1); - assert_approx_eq!(3.0f32.ln_gamma().0, 2.0f32.ln()); - assert_eq!(3.0f32.ln_gamma().1, 1); - assert_approx_eq!((-0.5f32).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln()); - assert_eq!((-0.5f32).ln_gamma().1, -1); -} - -#[test] -fn test_real_consts() { - let pi: f32 = consts::PI; - let frac_pi_2: f32 = consts::FRAC_PI_2; - let frac_pi_3: f32 = consts::FRAC_PI_3; - let frac_pi_4: f32 = consts::FRAC_PI_4; - let frac_pi_6: f32 = consts::FRAC_PI_6; - let frac_pi_8: f32 = consts::FRAC_PI_8; - let frac_1_pi: f32 = consts::FRAC_1_PI; - let frac_2_pi: f32 = consts::FRAC_2_PI; - let frac_2_sqrtpi: f32 = consts::FRAC_2_SQRT_PI; - let sqrt2: f32 = consts::SQRT_2; - let frac_1_sqrt2: f32 = consts::FRAC_1_SQRT_2; - let e: f32 = consts::E; - let log2_e: f32 = consts::LOG2_E; - let log10_e: f32 = consts::LOG10_E; - let ln_2: f32 = consts::LN_2; - let ln_10: f32 = consts::LN_10; - - assert_approx_eq!(frac_pi_2, pi / 2f32); - assert_approx_eq!(frac_pi_3, pi / 3f32); - assert_approx_eq!(frac_pi_4, pi / 4f32); - assert_approx_eq!(frac_pi_6, pi / 6f32); - assert_approx_eq!(frac_pi_8, pi / 8f32); - assert_approx_eq!(frac_1_pi, 1f32 / pi); - assert_approx_eq!(frac_2_pi, 2f32 / pi); - assert_approx_eq!(frac_2_sqrtpi, 2f32 / pi.sqrt()); - assert_approx_eq!(sqrt2, 2f32.sqrt()); - assert_approx_eq!(frac_1_sqrt2, 1f32 / 2f32.sqrt()); - assert_approx_eq!(log2_e, e.log2()); - assert_approx_eq!(log10_e, e.log10()); - assert_approx_eq!(ln_2, 2f32.ln()); - assert_approx_eq!(ln_10, 10f32.ln()); -} - #[test] fn test_float_bits_conv() { assert_eq!((1f32).to_bits(), 0x3f800000); diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index de9c27eb33d39..4a79a31853ec8 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -35,7 +35,7 @@ macro_rules! assert_f64_biteq { #[test] fn test_num_f64() { - crate::test_num(10f64, 2f64); + super::test_num(10f64, 2f64); } #[test] @@ -201,88 +201,88 @@ fn test_classify() { #[test] fn test_floor() { - assert_approx_eq!(1.0f64.floor(), 1.0f64); - assert_approx_eq!(1.3f64.floor(), 1.0f64); - assert_approx_eq!(1.5f64.floor(), 1.0f64); - assert_approx_eq!(1.7f64.floor(), 1.0f64); - assert_approx_eq!(0.0f64.floor(), 0.0f64); - assert_approx_eq!((-0.0f64).floor(), -0.0f64); - assert_approx_eq!((-1.0f64).floor(), -1.0f64); - assert_approx_eq!((-1.3f64).floor(), -2.0f64); - assert_approx_eq!((-1.5f64).floor(), -2.0f64); - assert_approx_eq!((-1.7f64).floor(), -2.0f64); + assert_approx_eq!(f64::floor(1.0f64), 1.0f64); + assert_approx_eq!(f64::floor(1.3f64), 1.0f64); + assert_approx_eq!(f64::floor(1.5f64), 1.0f64); + assert_approx_eq!(f64::floor(1.7f64), 1.0f64); + assert_approx_eq!(f64::floor(0.0f64), 0.0f64); + assert_approx_eq!(f64::floor(-0.0f64), -0.0f64); + assert_approx_eq!(f64::floor(-1.0f64), -1.0f64); + assert_approx_eq!(f64::floor(-1.3f64), -2.0f64); + assert_approx_eq!(f64::floor(-1.5f64), -2.0f64); + assert_approx_eq!(f64::floor(-1.7f64), -2.0f64); } #[test] fn test_ceil() { - assert_approx_eq!(1.0f64.ceil(), 1.0f64); - assert_approx_eq!(1.3f64.ceil(), 2.0f64); - assert_approx_eq!(1.5f64.ceil(), 2.0f64); - assert_approx_eq!(1.7f64.ceil(), 2.0f64); - assert_approx_eq!(0.0f64.ceil(), 0.0f64); - assert_approx_eq!((-0.0f64).ceil(), -0.0f64); - assert_approx_eq!((-1.0f64).ceil(), -1.0f64); - assert_approx_eq!((-1.3f64).ceil(), -1.0f64); - assert_approx_eq!((-1.5f64).ceil(), -1.0f64); - assert_approx_eq!((-1.7f64).ceil(), -1.0f64); + assert_approx_eq!(f64::ceil(1.0f64), 1.0f64); + assert_approx_eq!(f64::ceil(1.3f64), 2.0f64); + assert_approx_eq!(f64::ceil(1.5f64), 2.0f64); + assert_approx_eq!(f64::ceil(1.7f64), 2.0f64); + assert_approx_eq!(f64::ceil(0.0f64), 0.0f64); + assert_approx_eq!(f64::ceil(-0.0f64), -0.0f64); + assert_approx_eq!(f64::ceil(-1.0f64), -1.0f64); + assert_approx_eq!(f64::ceil(-1.3f64), -1.0f64); + assert_approx_eq!(f64::ceil(-1.5f64), -1.0f64); + assert_approx_eq!(f64::ceil(-1.7f64), -1.0f64); } #[test] fn test_round() { - assert_approx_eq!(2.5f64.round(), 3.0f64); - assert_approx_eq!(1.0f64.round(), 1.0f64); - assert_approx_eq!(1.3f64.round(), 1.0f64); - assert_approx_eq!(1.5f64.round(), 2.0f64); - assert_approx_eq!(1.7f64.round(), 2.0f64); - assert_approx_eq!(0.0f64.round(), 0.0f64); - assert_approx_eq!((-0.0f64).round(), -0.0f64); - assert_approx_eq!((-1.0f64).round(), -1.0f64); - assert_approx_eq!((-1.3f64).round(), -1.0f64); - assert_approx_eq!((-1.5f64).round(), -2.0f64); - assert_approx_eq!((-1.7f64).round(), -2.0f64); + assert_approx_eq!(f64::round(2.5f64), 3.0f64); + assert_approx_eq!(f64::round(1.0f64), 1.0f64); + assert_approx_eq!(f64::round(1.3f64), 1.0f64); + assert_approx_eq!(f64::round(1.5f64), 2.0f64); + assert_approx_eq!(f64::round(1.7f64), 2.0f64); + assert_approx_eq!(f64::round(0.0f64), 0.0f64); + assert_approx_eq!(f64::round(-0.0f64), -0.0f64); + assert_approx_eq!(f64::round(-1.0f64), -1.0f64); + assert_approx_eq!(f64::round(-1.3f64), -1.0f64); + assert_approx_eq!(f64::round(-1.5f64), -2.0f64); + assert_approx_eq!(f64::round(-1.7f64), -2.0f64); } #[test] fn test_round_ties_even() { - assert_approx_eq!(2.5f64.round_ties_even(), 2.0f64); - assert_approx_eq!(1.0f64.round_ties_even(), 1.0f64); - assert_approx_eq!(1.3f64.round_ties_even(), 1.0f64); - assert_approx_eq!(1.5f64.round_ties_even(), 2.0f64); - assert_approx_eq!(1.7f64.round_ties_even(), 2.0f64); - assert_approx_eq!(0.0f64.round_ties_even(), 0.0f64); - assert_approx_eq!((-0.0f64).round_ties_even(), -0.0f64); - assert_approx_eq!((-1.0f64).round_ties_even(), -1.0f64); - assert_approx_eq!((-1.3f64).round_ties_even(), -1.0f64); - assert_approx_eq!((-1.5f64).round_ties_even(), -2.0f64); - assert_approx_eq!((-1.7f64).round_ties_even(), -2.0f64); + assert_approx_eq!(f64::round_ties_even(2.5f64), 2.0f64); + assert_approx_eq!(f64::round_ties_even(1.0f64), 1.0f64); + assert_approx_eq!(f64::round_ties_even(1.3f64), 1.0f64); + assert_approx_eq!(f64::round_ties_even(1.5f64), 2.0f64); + assert_approx_eq!(f64::round_ties_even(1.7f64), 2.0f64); + assert_approx_eq!(f64::round_ties_even(0.0f64), 0.0f64); + assert_approx_eq!(f64::round_ties_even(-0.0f64), -0.0f64); + assert_approx_eq!(f64::round_ties_even(-1.0f64), -1.0f64); + assert_approx_eq!(f64::round_ties_even(-1.3f64), -1.0f64); + assert_approx_eq!(f64::round_ties_even(-1.5f64), -2.0f64); + assert_approx_eq!(f64::round_ties_even(-1.7f64), -2.0f64); } #[test] fn test_trunc() { - assert_approx_eq!(1.0f64.trunc(), 1.0f64); - assert_approx_eq!(1.3f64.trunc(), 1.0f64); - assert_approx_eq!(1.5f64.trunc(), 1.0f64); - assert_approx_eq!(1.7f64.trunc(), 1.0f64); - assert_approx_eq!(0.0f64.trunc(), 0.0f64); - assert_approx_eq!((-0.0f64).trunc(), -0.0f64); - assert_approx_eq!((-1.0f64).trunc(), -1.0f64); - assert_approx_eq!((-1.3f64).trunc(), -1.0f64); - assert_approx_eq!((-1.5f64).trunc(), -1.0f64); - assert_approx_eq!((-1.7f64).trunc(), -1.0f64); + assert_approx_eq!(f64::trunc(1.0f64), 1.0f64); + assert_approx_eq!(f64::trunc(1.3f64), 1.0f64); + assert_approx_eq!(f64::trunc(1.5f64), 1.0f64); + assert_approx_eq!(f64::trunc(1.7f64), 1.0f64); + assert_approx_eq!(f64::trunc(0.0f64), 0.0f64); + assert_approx_eq!(f64::trunc(-0.0f64), -0.0f64); + assert_approx_eq!(f64::trunc(-1.0f64), -1.0f64); + assert_approx_eq!(f64::trunc(-1.3f64), -1.0f64); + assert_approx_eq!(f64::trunc(-1.5f64), -1.0f64); + assert_approx_eq!(f64::trunc(-1.7f64), -1.0f64); } #[test] fn test_fract() { - assert_approx_eq!(1.0f64.fract(), 0.0f64); - assert_approx_eq!(1.3f64.fract(), 0.3f64); - assert_approx_eq!(1.5f64.fract(), 0.5f64); - assert_approx_eq!(1.7f64.fract(), 0.7f64); - assert_approx_eq!(0.0f64.fract(), 0.0f64); - assert_approx_eq!((-0.0f64).fract(), -0.0f64); - assert_approx_eq!((-1.0f64).fract(), -0.0f64); - assert_approx_eq!((-1.3f64).fract(), -0.3f64); - assert_approx_eq!((-1.5f64).fract(), -0.5f64); - assert_approx_eq!((-1.7f64).fract(), -0.7f64); + assert_approx_eq!(f64::fract(1.0f64), 0.0f64); + assert_approx_eq!(f64::fract(1.3f64), 0.3f64); + assert_approx_eq!(f64::fract(1.5f64), 0.5f64); + assert_approx_eq!(f64::fract(1.7f64), 0.7f64); + assert_approx_eq!(f64::fract(0.0f64), 0.0f64); + assert_approx_eq!(f64::fract(-0.0f64), -0.0f64); + assert_approx_eq!(f64::fract(-1.0f64), -0.0f64); + assert_approx_eq!(f64::fract(-1.3f64), -0.3f64); + assert_approx_eq!(f64::fract(-1.5f64), -0.5f64); + assert_approx_eq!(f64::fract(-1.7f64), -0.7f64); } #[test] @@ -438,22 +438,6 @@ fn test_powi() { assert_eq!(neg_inf.powi(2), inf); } -#[test] -fn test_powf() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_eq!(1.0f64.powf(1.0), 1.0); - assert_approx_eq!(3.4f64.powf(4.5), 246.408183); - assert_approx_eq!(2.7f64.powf(-3.2), 0.041652); - assert_approx_eq!((-3.1f64).powf(2.0), 9.61); - assert_approx_eq!(5.9f64.powf(-2.0), 0.028727); - assert_eq!(8.3f64.powf(0.0), 1.0); - assert!(nan.powf(2.0).is_nan()); - assert_eq!(inf.powf(2.0), inf); - assert_eq!(neg_inf.powf(3.0), neg_inf); -} - #[test] fn test_sqrt_domain() { assert!(f64::NAN.sqrt().is_nan()); @@ -465,99 +449,6 @@ fn test_sqrt_domain() { assert_eq!(f64::INFINITY.sqrt(), f64::INFINITY); } -#[test] -fn test_exp() { - assert_eq!(1.0, 0.0f64.exp()); - assert_approx_eq!(2.718282, 1.0f64.exp()); - assert_approx_eq!(148.413159, 5.0f64.exp()); - - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let nan: f64 = f64::NAN; - assert_eq!(inf, inf.exp()); - assert_eq!(0.0, neg_inf.exp()); - assert!(nan.exp().is_nan()); -} - -#[test] -fn test_exp2() { - assert_eq!(32.0, 5.0f64.exp2()); - assert_eq!(1.0, 0.0f64.exp2()); - - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let nan: f64 = f64::NAN; - assert_eq!(inf, inf.exp2()); - assert_eq!(0.0, neg_inf.exp2()); - assert!(nan.exp2().is_nan()); -} - -#[test] -fn test_ln() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_approx_eq!(1.0f64.exp().ln(), 1.0); - assert!(nan.ln().is_nan()); - assert_eq!(inf.ln(), inf); - assert!(neg_inf.ln().is_nan()); - assert!((-2.3f64).ln().is_nan()); - assert_eq!((-0.0f64).ln(), neg_inf); - assert_eq!(0.0f64.ln(), neg_inf); - assert_approx_eq!(4.0f64.ln(), 1.386294); -} - -#[test] -fn test_log() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_eq!(10.0f64.log(10.0), 1.0); - assert_approx_eq!(2.3f64.log(3.5), 0.664858); - assert_eq!(1.0f64.exp().log(1.0f64.exp()), 1.0); - assert!(1.0f64.log(1.0).is_nan()); - assert!(1.0f64.log(-13.9).is_nan()); - assert!(nan.log(2.3).is_nan()); - assert_eq!(inf.log(10.0), inf); - assert!(neg_inf.log(8.8).is_nan()); - assert!((-2.3f64).log(0.1).is_nan()); - assert_eq!((-0.0f64).log(2.0), neg_inf); - assert_eq!(0.0f64.log(7.0), neg_inf); -} - -#[test] -fn test_log2() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_approx_eq!(10.0f64.log2(), 3.321928); - assert_approx_eq!(2.3f64.log2(), 1.201634); - assert_approx_eq!(1.0f64.exp().log2(), 1.442695); - assert!(nan.log2().is_nan()); - assert_eq!(inf.log2(), inf); - assert!(neg_inf.log2().is_nan()); - assert!((-2.3f64).log2().is_nan()); - assert_eq!((-0.0f64).log2(), neg_inf); - assert_eq!(0.0f64.log2(), neg_inf); -} - -#[test] -fn test_log10() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_eq!(10.0f64.log10(), 1.0); - assert_approx_eq!(2.3f64.log10(), 0.361728); - assert_approx_eq!(1.0f64.exp().log10(), 0.434294); - assert_eq!(1.0f64.log10(), 0.0); - assert!(nan.log10().is_nan()); - assert_eq!(inf.log10(), inf); - assert!(neg_inf.log10().is_nan()); - assert!((-2.3f64).log10().is_nan()); - assert_eq!((-0.0f64).log10(), neg_inf); - assert_eq!(0.0f64.log10(), neg_inf); -} - #[test] fn test_to_degrees() { let pi: f64 = consts::PI; @@ -587,134 +478,6 @@ fn test_to_radians() { assert_eq!(neg_inf.to_radians(), neg_inf); } -#[test] -fn test_asinh() { - assert_eq!(0.0f64.asinh(), 0.0f64); - assert_eq!((-0.0f64).asinh(), -0.0f64); - - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let nan: f64 = f64::NAN; - assert_eq!(inf.asinh(), inf); - assert_eq!(neg_inf.asinh(), neg_inf); - assert!(nan.asinh().is_nan()); - assert!((-0.0f64).asinh().is_sign_negative()); - // issue 63271 - assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64); - assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64); - // regression test for the catastrophic cancellation fixed in 72486 - assert_approx_eq!((-67452098.07139316f64).asinh(), -18.72007542627454439398548429400083); - - // test for low accuracy from issue 104548 - assert_approx_eq!(60.0f64, 60.0f64.sinh().asinh()); - // mul needed for approximate comparison to be meaningful - assert_approx_eq!(1.0f64, 1e-15f64.sinh().asinh() * 1e15f64); -} - -#[test] -fn test_acosh() { - assert_eq!(1.0f64.acosh(), 0.0f64); - assert!(0.999f64.acosh().is_nan()); - - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let nan: f64 = f64::NAN; - assert_eq!(inf.acosh(), inf); - assert!(neg_inf.acosh().is_nan()); - assert!(nan.acosh().is_nan()); - assert_approx_eq!(2.0f64.acosh(), 1.31695789692481670862504634730796844f64); - assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64); - - // test for low accuracy from issue 104548 - assert_approx_eq!(60.0f64, 60.0f64.cosh().acosh()); -} - -#[test] -fn test_atanh() { - assert_eq!(0.0f64.atanh(), 0.0f64); - assert_eq!((-0.0f64).atanh(), -0.0f64); - - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let nan: f64 = f64::NAN; - assert_eq!(1.0f64.atanh(), inf); - assert_eq!((-1.0f64).atanh(), neg_inf); - assert!(2f64.atanh().atanh().is_nan()); - assert!((-2f64).atanh().atanh().is_nan()); - assert!(inf.atanh().is_nan()); - assert!(neg_inf.atanh().is_nan()); - assert!(nan.atanh().is_nan()); - assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64); - assert_approx_eq!((-0.5f64).atanh(), -0.54930614433405484569762261846126285f64); -} - -#[test] -fn test_gamma() { - // precision can differ between platforms - assert_approx_eq!(1.0f64.gamma(), 1.0f64); - assert_approx_eq!(2.0f64.gamma(), 1.0f64); - assert_approx_eq!(3.0f64.gamma(), 2.0f64); - assert_approx_eq!(4.0f64.gamma(), 6.0f64); - assert_approx_eq!(5.0f64.gamma(), 24.0f64); - assert_approx_eq!(0.5f64.gamma(), consts::PI.sqrt()); - assert_approx_eq!((-0.5f64).gamma(), -2.0 * consts::PI.sqrt()); - assert_eq!(0.0f64.gamma(), f64::INFINITY); - assert_eq!((-0.0f64).gamma(), f64::NEG_INFINITY); - assert!((-1.0f64).gamma().is_nan()); - assert!((-2.0f64).gamma().is_nan()); - assert!(f64::NAN.gamma().is_nan()); - assert!(f64::NEG_INFINITY.gamma().is_nan()); - assert_eq!(f64::INFINITY.gamma(), f64::INFINITY); - assert_eq!(171.71f64.gamma(), f64::INFINITY); -} - -#[test] -fn test_ln_gamma() { - assert_approx_eq!(1.0f64.ln_gamma().0, 0.0f64); - assert_eq!(1.0f64.ln_gamma().1, 1); - assert_approx_eq!(2.0f64.ln_gamma().0, 0.0f64); - assert_eq!(2.0f64.ln_gamma().1, 1); - assert_approx_eq!(3.0f64.ln_gamma().0, 2.0f64.ln()); - assert_eq!(3.0f64.ln_gamma().1, 1); - assert_approx_eq!((-0.5f64).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln()); - assert_eq!((-0.5f64).ln_gamma().1, -1); -} - -#[test] -fn test_real_consts() { - let pi: f64 = consts::PI; - let frac_pi_2: f64 = consts::FRAC_PI_2; - let frac_pi_3: f64 = consts::FRAC_PI_3; - let frac_pi_4: f64 = consts::FRAC_PI_4; - let frac_pi_6: f64 = consts::FRAC_PI_6; - let frac_pi_8: f64 = consts::FRAC_PI_8; - let frac_1_pi: f64 = consts::FRAC_1_PI; - let frac_2_pi: f64 = consts::FRAC_2_PI; - let frac_2_sqrtpi: f64 = consts::FRAC_2_SQRT_PI; - let sqrt2: f64 = consts::SQRT_2; - let frac_1_sqrt2: f64 = consts::FRAC_1_SQRT_2; - let e: f64 = consts::E; - let log2_e: f64 = consts::LOG2_E; - let log10_e: f64 = consts::LOG10_E; - let ln_2: f64 = consts::LN_2; - let ln_10: f64 = consts::LN_10; - - assert_approx_eq!(frac_pi_2, pi / 2f64); - assert_approx_eq!(frac_pi_3, pi / 3f64); - assert_approx_eq!(frac_pi_4, pi / 4f64); - assert_approx_eq!(frac_pi_6, pi / 6f64); - assert_approx_eq!(frac_pi_8, pi / 8f64); - assert_approx_eq!(frac_1_pi, 1f64 / pi); - assert_approx_eq!(frac_2_pi, 2f64 / pi); - assert_approx_eq!(frac_2_sqrtpi, 2f64 / pi.sqrt()); - assert_approx_eq!(sqrt2, 2f64.sqrt()); - assert_approx_eq!(frac_1_sqrt2, 1f64 / 2f64.sqrt()); - assert_approx_eq!(log2_e, e.log2()); - assert_approx_eq!(log10_e, e.log10()); - assert_approx_eq!(ln_2, 2f64.ln()); - assert_approx_eq!(ln_10, 10f64.ln()); -} - #[test] fn test_float_bits_conv() { assert_eq!((1f64).to_bits(), 0x3ff0000000000000); diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 453a2d533ab8a..7de34271ad05e 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -1,7 +1,3 @@ -#![feature(f16, f128, float_algebraic, float_gamma, float_minimum_maximum)] -#![feature(cfg_target_has_reliable_f16_f128)] -#![expect(internal_features)] // for reliable_f16_f128 - use std::fmt; use std::ops::{Add, Div, Mul, Rem, Sub}; diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index acea0b2a0356f..b98e52718f60b 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -12,10 +12,12 @@ #![feature(async_iterator)] #![feature(bigint_helper_methods)] #![feature(bstr)] +#![feature(cfg_target_has_reliable_f16_f128)] #![feature(char_max_len)] #![feature(clone_to_uninit)] #![feature(const_eval_select)] #![feature(const_trait_impl)] +#![feature(core_float_math)] #![feature(core_intrinsics)] #![feature(core_intrinsics_fallbacks)] #![feature(core_io_borrowed_buf)] @@ -29,6 +31,10 @@ #![feature(exact_size_is_empty)] #![feature(extend_one)] #![feature(extern_types)] +#![feature(f128)] +#![feature(f16)] +#![feature(float_algebraic)] +#![feature(float_gamma)] #![feature(float_minimum_maximum)] #![feature(flt2dec)] #![feature(fmt_internals)] diff --git a/library/std/tests/floats/f128.rs b/library/std/tests/floats/f128.rs new file mode 100644 index 0000000000000..e7c90faa05c23 --- /dev/null +++ b/library/std/tests/floats/f128.rs @@ -0,0 +1,321 @@ +// FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy +#![cfg(target_has_reliable_f128)] + +use std::f128::consts; +use std::ops::{Add, Div, Mul, Sub}; + +// Note these tolerances make sense around zero, but not for more extreme exponents. + +/// Default tolerances. Works for values that should be near precise but not exact. Roughly +/// the precision carried by `100 * 100`. +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +const TOL: f128 = 1e-12; + +/// For operations that are near exact, usually not involving math of different +/// signs. +const TOL_PRECISE: f128 = 1e-28; + +/// Tolerances for math that is allowed to be imprecise, usually due to multiple chained +/// operations. +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +const TOL_IMPR: f128 = 1e-10; + +/// Compare by representation +#[allow(unused_macros)] +macro_rules! assert_f128_biteq { + ($a:expr, $b:expr) => { + let (l, r): (&f128, &f128) = (&$a, &$b); + let lb = l.to_bits(); + let rb = r.to_bits(); + assert_eq!(lb, rb, "float {l:?} is not bitequal to {r:?}.\na: {lb:#034x}\nb: {rb:#034x}"); + }; +} + +#[test] +fn test_num_f128() { + // FIXME(f16_f128): replace with a `test_num` call once the required `fmodl`/`fmodf128` + // function is available on all platforms. + let ten = 10f128; + let two = 2f128; + assert_eq!(ten.add(two), ten + two); + assert_eq!(ten.sub(two), ten - two); + assert_eq!(ten.mul(two), ten * two); + assert_eq!(ten.div(two), ten / two); +} + +// Many math functions allow for less accurate results, so the next tolerance up is used + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_powf() { + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + assert_eq!(1.0f128.powf(1.0), 1.0); + assert_approx_eq!(3.4f128.powf(4.5), 246.40818323761892815995637964326426756, TOL_IMPR); + assert_approx_eq!(2.7f128.powf(-3.2), 0.041652009108526178281070304373500889273, TOL_IMPR); + assert_approx_eq!((-3.1f128).powf(2.0), 9.6100000000000005506706202140776519387, TOL_IMPR); + assert_approx_eq!(5.9f128.powf(-2.0), 0.028727377190462507313100483690639638451, TOL_IMPR); + assert_eq!(8.3f128.powf(0.0), 1.0); + assert!(nan.powf(2.0).is_nan()); + assert_eq!(inf.powf(2.0), inf); + assert_eq!(neg_inf.powf(3.0), neg_inf); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_exp() { + assert_eq!(1.0, 0.0f128.exp()); + assert_approx_eq!(consts::E, 1.0f128.exp(), TOL); + assert_approx_eq!(148.41315910257660342111558004055227962348775, 5.0f128.exp(), TOL); + + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + let nan: f128 = f128::NAN; + assert_eq!(inf, inf.exp()); + assert_eq!(0.0, neg_inf.exp()); + assert!(nan.exp().is_nan()); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_exp2() { + assert_eq!(32.0, 5.0f128.exp2()); + assert_eq!(1.0, 0.0f128.exp2()); + + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + let nan: f128 = f128::NAN; + assert_eq!(inf, inf.exp2()); + assert_eq!(0.0, neg_inf.exp2()); + assert!(nan.exp2().is_nan()); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_ln() { + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + assert_approx_eq!(1.0f128.exp().ln(), 1.0, TOL); + assert!(nan.ln().is_nan()); + assert_eq!(inf.ln(), inf); + assert!(neg_inf.ln().is_nan()); + assert!((-2.3f128).ln().is_nan()); + assert_eq!((-0.0f128).ln(), neg_inf); + assert_eq!(0.0f128.ln(), neg_inf); + assert_approx_eq!(4.0f128.ln(), 1.3862943611198906188344642429163531366, TOL); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_log() { + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + assert_eq!(10.0f128.log(10.0), 1.0); + assert_approx_eq!(2.3f128.log(3.5), 0.66485771361478710036766645911922010272, TOL); + assert_eq!(1.0f128.exp().log(1.0f128.exp()), 1.0); + assert!(1.0f128.log(1.0).is_nan()); + assert!(1.0f128.log(-13.9).is_nan()); + assert!(nan.log(2.3).is_nan()); + assert_eq!(inf.log(10.0), inf); + assert!(neg_inf.log(8.8).is_nan()); + assert!((-2.3f128).log(0.1).is_nan()); + assert_eq!((-0.0f128).log(2.0), neg_inf); + assert_eq!(0.0f128.log(7.0), neg_inf); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_log2() { + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + assert_approx_eq!(10.0f128.log2(), 3.32192809488736234787031942948939017, TOL); + assert_approx_eq!(2.3f128.log2(), 1.2016338611696504130002982471978765921, TOL); + assert_approx_eq!(1.0f128.exp().log2(), 1.4426950408889634073599246810018921381, TOL); + assert!(nan.log2().is_nan()); + assert_eq!(inf.log2(), inf); + assert!(neg_inf.log2().is_nan()); + assert!((-2.3f128).log2().is_nan()); + assert_eq!((-0.0f128).log2(), neg_inf); + assert_eq!(0.0f128.log2(), neg_inf); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_log10() { + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + assert_eq!(10.0f128.log10(), 1.0); + assert_approx_eq!(2.3f128.log10(), 0.36172783601759284532595218865859309898, TOL); + assert_approx_eq!(1.0f128.exp().log10(), 0.43429448190325182765112891891660508222, TOL); + assert_eq!(1.0f128.log10(), 0.0); + assert!(nan.log10().is_nan()); + assert_eq!(inf.log10(), inf); + assert!(neg_inf.log10().is_nan()); + assert!((-2.3f128).log10().is_nan()); + assert_eq!((-0.0f128).log10(), neg_inf); + assert_eq!(0.0f128.log10(), neg_inf); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_asinh() { + // Lower accuracy results are allowed, use increased tolerances + assert_eq!(0.0f128.asinh(), 0.0f128); + assert_eq!((-0.0f128).asinh(), -0.0f128); + + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + let nan: f128 = f128::NAN; + assert_eq!(inf.asinh(), inf); + assert_eq!(neg_inf.asinh(), neg_inf); + assert!(nan.asinh().is_nan()); + assert!((-0.0f128).asinh().is_sign_negative()); + + // issue 63271 + assert_approx_eq!(2.0f128.asinh(), 1.443635475178810342493276740273105f128, TOL_IMPR); + assert_approx_eq!((-2.0f128).asinh(), -1.443635475178810342493276740273105f128, TOL_IMPR); + // regression test for the catastrophic cancellation fixed in 72486 + assert_approx_eq!( + (-67452098.07139316f128).asinh(), + -18.720075426274544393985484294000831757220, + TOL_IMPR + ); + + // test for low accuracy from issue 104548 + assert_approx_eq!(60.0f128, 60.0f128.sinh().asinh(), TOL_IMPR); + // mul needed for approximate comparison to be meaningful + assert_approx_eq!(1.0f128, 1e-15f128.sinh().asinh() * 1e15f128, TOL_IMPR); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_acosh() { + assert_eq!(1.0f128.acosh(), 0.0f128); + assert!(0.999f128.acosh().is_nan()); + + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + let nan: f128 = f128::NAN; + assert_eq!(inf.acosh(), inf); + assert!(neg_inf.acosh().is_nan()); + assert!(nan.acosh().is_nan()); + assert_approx_eq!(2.0f128.acosh(), 1.31695789692481670862504634730796844f128, TOL_IMPR); + assert_approx_eq!(3.0f128.acosh(), 1.76274717403908605046521864995958461f128, TOL_IMPR); + + // test for low accuracy from issue 104548 + assert_approx_eq!(60.0f128, 60.0f128.cosh().acosh(), TOL_IMPR); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_atanh() { + assert_eq!(0.0f128.atanh(), 0.0f128); + assert_eq!((-0.0f128).atanh(), -0.0f128); + + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + let nan: f128 = f128::NAN; + assert_eq!(1.0f128.atanh(), inf); + assert_eq!((-1.0f128).atanh(), neg_inf); + assert!(2f128.atanh().atanh().is_nan()); + assert!((-2f128).atanh().atanh().is_nan()); + assert!(inf.atanh().is_nan()); + assert!(neg_inf.atanh().is_nan()); + assert!(nan.atanh().is_nan()); + assert_approx_eq!(0.5f128.atanh(), 0.54930614433405484569762261846126285f128, TOL_IMPR); + assert_approx_eq!((-0.5f128).atanh(), -0.54930614433405484569762261846126285f128, TOL_IMPR); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_gamma() { + // precision can differ among platforms + assert_approx_eq!(1.0f128.gamma(), 1.0f128, TOL_IMPR); + assert_approx_eq!(2.0f128.gamma(), 1.0f128, TOL_IMPR); + assert_approx_eq!(3.0f128.gamma(), 2.0f128, TOL_IMPR); + assert_approx_eq!(4.0f128.gamma(), 6.0f128, TOL_IMPR); + assert_approx_eq!(5.0f128.gamma(), 24.0f128, TOL_IMPR); + assert_approx_eq!(0.5f128.gamma(), consts::PI.sqrt(), TOL_IMPR); + assert_approx_eq!((-0.5f128).gamma(), -2.0 * consts::PI.sqrt(), TOL_IMPR); + assert_eq!(0.0f128.gamma(), f128::INFINITY); + assert_eq!((-0.0f128).gamma(), f128::NEG_INFINITY); + assert!((-1.0f128).gamma().is_nan()); + assert!((-2.0f128).gamma().is_nan()); + assert!(f128::NAN.gamma().is_nan()); + assert!(f128::NEG_INFINITY.gamma().is_nan()); + assert_eq!(f128::INFINITY.gamma(), f128::INFINITY); + assert_eq!(1760.9f128.gamma(), f128::INFINITY); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_ln_gamma() { + assert_approx_eq!(1.0f128.ln_gamma().0, 0.0f128, TOL_IMPR); + assert_eq!(1.0f128.ln_gamma().1, 1); + assert_approx_eq!(2.0f128.ln_gamma().0, 0.0f128, TOL_IMPR); + assert_eq!(2.0f128.ln_gamma().1, 1); + assert_approx_eq!(3.0f128.ln_gamma().0, 2.0f128.ln(), TOL_IMPR); + assert_eq!(3.0f128.ln_gamma().1, 1); + assert_approx_eq!((-0.5f128).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln(), TOL_IMPR); + assert_eq!((-0.5f128).ln_gamma().1, -1); +} + +#[test] +fn test_real_consts() { + let pi: f128 = consts::PI; + let frac_pi_2: f128 = consts::FRAC_PI_2; + let frac_pi_3: f128 = consts::FRAC_PI_3; + let frac_pi_4: f128 = consts::FRAC_PI_4; + let frac_pi_6: f128 = consts::FRAC_PI_6; + let frac_pi_8: f128 = consts::FRAC_PI_8; + let frac_1_pi: f128 = consts::FRAC_1_PI; + let frac_2_pi: f128 = consts::FRAC_2_PI; + + assert_approx_eq!(frac_pi_2, pi / 2f128, TOL_PRECISE); + assert_approx_eq!(frac_pi_3, pi / 3f128, TOL_PRECISE); + assert_approx_eq!(frac_pi_4, pi / 4f128, TOL_PRECISE); + assert_approx_eq!(frac_pi_6, pi / 6f128, TOL_PRECISE); + assert_approx_eq!(frac_pi_8, pi / 8f128, TOL_PRECISE); + assert_approx_eq!(frac_1_pi, 1f128 / pi, TOL_PRECISE); + assert_approx_eq!(frac_2_pi, 2f128 / pi, TOL_PRECISE); + + #[cfg(not(miri))] + #[cfg(target_has_reliable_f128_math)] + { + let frac_2_sqrtpi: f128 = consts::FRAC_2_SQRT_PI; + let sqrt2: f128 = consts::SQRT_2; + let frac_1_sqrt2: f128 = consts::FRAC_1_SQRT_2; + let e: f128 = consts::E; + let log2_e: f128 = consts::LOG2_E; + let log10_e: f128 = consts::LOG10_E; + let ln_2: f128 = consts::LN_2; + let ln_10: f128 = consts::LN_10; + + assert_approx_eq!(frac_2_sqrtpi, 2f128 / pi.sqrt(), TOL_PRECISE); + assert_approx_eq!(sqrt2, 2f128.sqrt(), TOL_PRECISE); + assert_approx_eq!(frac_1_sqrt2, 1f128 / 2f128.sqrt(), TOL_PRECISE); + assert_approx_eq!(log2_e, e.log2(), TOL_PRECISE); + assert_approx_eq!(log10_e, e.log10(), TOL_PRECISE); + assert_approx_eq!(ln_2, 2f128.ln(), TOL_PRECISE); + assert_approx_eq!(ln_10, 10f128.ln(), TOL_PRECISE); + } +} diff --git a/library/std/tests/floats/f16.rs b/library/std/tests/floats/f16.rs new file mode 100644 index 0000000000000..0f8b4138d2266 --- /dev/null +++ b/library/std/tests/floats/f16.rs @@ -0,0 +1,300 @@ +// FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy +#![cfg(target_has_reliable_f16)] + +use std::f16::consts; + +/// Tolerance for results on the order of 10.0e-2 +#[allow(unused)] +const TOL_N2: f16 = 0.0001; + +/// Tolerance for results on the order of 10.0e+0 +#[allow(unused)] +const TOL_0: f16 = 0.01; + +/// Tolerance for results on the order of 10.0e+2 +#[allow(unused)] +const TOL_P2: f16 = 0.5; + +/// Tolerance for results on the order of 10.0e+4 +#[allow(unused)] +const TOL_P4: f16 = 10.0; + +/// Compare by representation +#[allow(unused_macros)] +macro_rules! assert_f16_biteq { + ($a:expr, $b:expr) => { + let (l, r): (&f16, &f16) = (&$a, &$b); + let lb = l.to_bits(); + let rb = r.to_bits(); + assert_eq!(lb, rb, "float {l:?} ({lb:#04x}) is not bitequal to {r:?} ({rb:#04x})"); + }; +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_powf() { + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + assert_eq!(1.0f16.powf(1.0), 1.0); + assert_approx_eq!(3.4f16.powf(4.5), 246.408183, TOL_P2); + assert_approx_eq!(2.7f16.powf(-3.2), 0.041652, TOL_N2); + assert_approx_eq!((-3.1f16).powf(2.0), 9.61, TOL_P2); + assert_approx_eq!(5.9f16.powf(-2.0), 0.028727, TOL_N2); + assert_eq!(8.3f16.powf(0.0), 1.0); + assert!(nan.powf(2.0).is_nan()); + assert_eq!(inf.powf(2.0), inf); + assert_eq!(neg_inf.powf(3.0), neg_inf); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_exp() { + assert_eq!(1.0, 0.0f16.exp()); + assert_approx_eq!(2.718282, 1.0f16.exp(), TOL_0); + assert_approx_eq!(148.413159, 5.0f16.exp(), TOL_0); + + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + let nan: f16 = f16::NAN; + assert_eq!(inf, inf.exp()); + assert_eq!(0.0, neg_inf.exp()); + assert!(nan.exp().is_nan()); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_exp2() { + assert_eq!(32.0, 5.0f16.exp2()); + assert_eq!(1.0, 0.0f16.exp2()); + + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + let nan: f16 = f16::NAN; + assert_eq!(inf, inf.exp2()); + assert_eq!(0.0, neg_inf.exp2()); + assert!(nan.exp2().is_nan()); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_ln() { + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + assert_approx_eq!(1.0f16.exp().ln(), 1.0, TOL_0); + assert!(nan.ln().is_nan()); + assert_eq!(inf.ln(), inf); + assert!(neg_inf.ln().is_nan()); + assert!((-2.3f16).ln().is_nan()); + assert_eq!((-0.0f16).ln(), neg_inf); + assert_eq!(0.0f16.ln(), neg_inf); + assert_approx_eq!(4.0f16.ln(), 1.386294, TOL_0); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_log() { + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + assert_eq!(10.0f16.log(10.0), 1.0); + assert_approx_eq!(2.3f16.log(3.5), 0.664858, TOL_0); + assert_eq!(1.0f16.exp().log(1.0f16.exp()), 1.0); + assert!(1.0f16.log(1.0).is_nan()); + assert!(1.0f16.log(-13.9).is_nan()); + assert!(nan.log(2.3).is_nan()); + assert_eq!(inf.log(10.0), inf); + assert!(neg_inf.log(8.8).is_nan()); + assert!((-2.3f16).log(0.1).is_nan()); + assert_eq!((-0.0f16).log(2.0), neg_inf); + assert_eq!(0.0f16.log(7.0), neg_inf); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_log2() { + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + assert_approx_eq!(10.0f16.log2(), 3.321928, TOL_0); + assert_approx_eq!(2.3f16.log2(), 1.201634, TOL_0); + assert_approx_eq!(1.0f16.exp().log2(), 1.442695, TOL_0); + assert!(nan.log2().is_nan()); + assert_eq!(inf.log2(), inf); + assert!(neg_inf.log2().is_nan()); + assert!((-2.3f16).log2().is_nan()); + assert_eq!((-0.0f16).log2(), neg_inf); + assert_eq!(0.0f16.log2(), neg_inf); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_log10() { + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + assert_eq!(10.0f16.log10(), 1.0); + assert_approx_eq!(2.3f16.log10(), 0.361728, TOL_0); + assert_approx_eq!(1.0f16.exp().log10(), 0.434294, TOL_0); + assert_eq!(1.0f16.log10(), 0.0); + assert!(nan.log10().is_nan()); + assert_eq!(inf.log10(), inf); + assert!(neg_inf.log10().is_nan()); + assert!((-2.3f16).log10().is_nan()); + assert_eq!((-0.0f16).log10(), neg_inf); + assert_eq!(0.0f16.log10(), neg_inf); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_asinh() { + assert_eq!(0.0f16.asinh(), 0.0f16); + assert_eq!((-0.0f16).asinh(), -0.0f16); + + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + let nan: f16 = f16::NAN; + assert_eq!(inf.asinh(), inf); + assert_eq!(neg_inf.asinh(), neg_inf); + assert!(nan.asinh().is_nan()); + assert!((-0.0f16).asinh().is_sign_negative()); + // issue 63271 + assert_approx_eq!(2.0f16.asinh(), 1.443635475178810342493276740273105f16, TOL_0); + assert_approx_eq!((-2.0f16).asinh(), -1.443635475178810342493276740273105f16, TOL_0); + // regression test for the catastrophic cancellation fixed in 72486 + assert_approx_eq!((-200.0f16).asinh(), -5.991470797049389, TOL_0); + + // test for low accuracy from issue 104548 + assert_approx_eq!(10.0f16, 10.0f16.sinh().asinh(), TOL_0); + // mul needed for approximate comparison to be meaningful + assert_approx_eq!(1.0f16, 1e-3f16.sinh().asinh() * 1e3f16, TOL_0); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_acosh() { + assert_eq!(1.0f16.acosh(), 0.0f16); + assert!(0.999f16.acosh().is_nan()); + + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + let nan: f16 = f16::NAN; + assert_eq!(inf.acosh(), inf); + assert!(neg_inf.acosh().is_nan()); + assert!(nan.acosh().is_nan()); + assert_approx_eq!(2.0f16.acosh(), 1.31695789692481670862504634730796844f16, TOL_0); + assert_approx_eq!(3.0f16.acosh(), 1.76274717403908605046521864995958461f16, TOL_0); + + // test for low accuracy from issue 104548 + assert_approx_eq!(10.0f16, 10.0f16.cosh().acosh(), TOL_P2); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_atanh() { + assert_eq!(0.0f16.atanh(), 0.0f16); + assert_eq!((-0.0f16).atanh(), -0.0f16); + + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + let nan: f16 = f16::NAN; + assert_eq!(1.0f16.atanh(), inf); + assert_eq!((-1.0f16).atanh(), neg_inf); + assert!(2f16.atanh().atanh().is_nan()); + assert!((-2f16).atanh().atanh().is_nan()); + assert!(inf.atanh().is_nan()); + assert!(neg_inf.atanh().is_nan()); + assert!(nan.atanh().is_nan()); + assert_approx_eq!(0.5f16.atanh(), 0.54930614433405484569762261846126285f16, TOL_0); + assert_approx_eq!((-0.5f16).atanh(), -0.54930614433405484569762261846126285f16, TOL_0); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_gamma() { + // precision can differ among platforms + assert_approx_eq!(1.0f16.gamma(), 1.0f16, TOL_0); + assert_approx_eq!(2.0f16.gamma(), 1.0f16, TOL_0); + assert_approx_eq!(3.0f16.gamma(), 2.0f16, TOL_0); + assert_approx_eq!(4.0f16.gamma(), 6.0f16, TOL_0); + assert_approx_eq!(5.0f16.gamma(), 24.0f16, TOL_0); + assert_approx_eq!(0.5f16.gamma(), consts::PI.sqrt(), TOL_0); + assert_approx_eq!((-0.5f16).gamma(), -2.0 * consts::PI.sqrt(), TOL_0); + assert_eq!(0.0f16.gamma(), f16::INFINITY); + assert_eq!((-0.0f16).gamma(), f16::NEG_INFINITY); + assert!((-1.0f16).gamma().is_nan()); + assert!((-2.0f16).gamma().is_nan()); + assert!(f16::NAN.gamma().is_nan()); + assert!(f16::NEG_INFINITY.gamma().is_nan()); + assert_eq!(f16::INFINITY.gamma(), f16::INFINITY); + assert_eq!(171.71f16.gamma(), f16::INFINITY); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_ln_gamma() { + assert_approx_eq!(1.0f16.ln_gamma().0, 0.0f16, TOL_0); + assert_eq!(1.0f16.ln_gamma().1, 1); + assert_approx_eq!(2.0f16.ln_gamma().0, 0.0f16, TOL_0); + assert_eq!(2.0f16.ln_gamma().1, 1); + assert_approx_eq!(3.0f16.ln_gamma().0, 2.0f16.ln(), TOL_0); + assert_eq!(3.0f16.ln_gamma().1, 1); + assert_approx_eq!((-0.5f16).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln(), TOL_0); + assert_eq!((-0.5f16).ln_gamma().1, -1); +} + +#[test] +fn test_real_consts() { + // FIXME(f16_f128): add math tests when available + + let pi: f16 = consts::PI; + let frac_pi_2: f16 = consts::FRAC_PI_2; + let frac_pi_3: f16 = consts::FRAC_PI_3; + let frac_pi_4: f16 = consts::FRAC_PI_4; + let frac_pi_6: f16 = consts::FRAC_PI_6; + let frac_pi_8: f16 = consts::FRAC_PI_8; + let frac_1_pi: f16 = consts::FRAC_1_PI; + let frac_2_pi: f16 = consts::FRAC_2_PI; + + assert_approx_eq!(frac_pi_2, pi / 2f16, TOL_0); + assert_approx_eq!(frac_pi_3, pi / 3f16, TOL_0); + assert_approx_eq!(frac_pi_4, pi / 4f16, TOL_0); + assert_approx_eq!(frac_pi_6, pi / 6f16, TOL_0); + assert_approx_eq!(frac_pi_8, pi / 8f16, TOL_0); + assert_approx_eq!(frac_1_pi, 1f16 / pi, TOL_0); + assert_approx_eq!(frac_2_pi, 2f16 / pi, TOL_0); + + #[cfg(not(miri))] + #[cfg(target_has_reliable_f16_math)] + { + let frac_2_sqrtpi: f16 = consts::FRAC_2_SQRT_PI; + let sqrt2: f16 = consts::SQRT_2; + let frac_1_sqrt2: f16 = consts::FRAC_1_SQRT_2; + let e: f16 = consts::E; + let log2_e: f16 = consts::LOG2_E; + let log10_e: f16 = consts::LOG10_E; + let ln_2: f16 = consts::LN_2; + let ln_10: f16 = consts::LN_10; + + assert_approx_eq!(frac_2_sqrtpi, 2f16 / pi.sqrt(), TOL_0); + assert_approx_eq!(sqrt2, 2f16.sqrt(), TOL_0); + assert_approx_eq!(frac_1_sqrt2, 1f16 / 2f16.sqrt(), TOL_0); + assert_approx_eq!(log2_e, e.log2(), TOL_0); + assert_approx_eq!(log10_e, e.log10(), TOL_0); + assert_approx_eq!(ln_2, 2f16.ln(), TOL_0); + assert_approx_eq!(ln_10, 10f16.ln(), TOL_0); + } +} diff --git a/library/std/tests/floats/f32.rs b/library/std/tests/floats/f32.rs new file mode 100644 index 0000000000000..e54f227bb774b --- /dev/null +++ b/library/std/tests/floats/f32.rs @@ -0,0 +1,253 @@ +use std::f32::consts; + +#[allow(unused_macros)] +macro_rules! assert_f32_biteq { + ($left : expr, $right : expr) => { + let l: &f32 = &$left; + let r: &f32 = &$right; + let lb = l.to_bits(); + let rb = r.to_bits(); + assert_eq!(lb, rb, "float {l} ({lb:#010x}) is not bitequal to {r} ({rb:#010x})"); + }; +} + +#[test] +fn test_powf() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(1.0f32.powf(1.0), 1.0); + assert_approx_eq!(3.4f32.powf(4.5), 246.408218); + assert_approx_eq!(2.7f32.powf(-3.2), 0.041652); + assert_approx_eq!((-3.1f32).powf(2.0), 9.61); + assert_approx_eq!(5.9f32.powf(-2.0), 0.028727); + assert_eq!(8.3f32.powf(0.0), 1.0); + assert!(nan.powf(2.0).is_nan()); + assert_eq!(inf.powf(2.0), inf); + assert_eq!(neg_inf.powf(3.0), neg_inf); +} + +#[test] +fn test_exp() { + assert_eq!(1.0, 0.0f32.exp()); + assert_approx_eq!(2.718282, 1.0f32.exp()); + assert_approx_eq!(148.413162, 5.0f32.exp()); + + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let nan: f32 = f32::NAN; + assert_eq!(inf, inf.exp()); + assert_eq!(0.0, neg_inf.exp()); + assert!(nan.exp().is_nan()); +} + +#[test] +fn test_exp2() { + assert_eq!(32.0, 5.0f32.exp2()); + assert_eq!(1.0, 0.0f32.exp2()); + + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let nan: f32 = f32::NAN; + assert_eq!(inf, inf.exp2()); + assert_eq!(0.0, neg_inf.exp2()); + assert!(nan.exp2().is_nan()); +} + +#[test] +fn test_ln() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_approx_eq!(1.0f32.exp().ln(), 1.0); + assert!(nan.ln().is_nan()); + assert_eq!(inf.ln(), inf); + assert!(neg_inf.ln().is_nan()); + assert!((-2.3f32).ln().is_nan()); + assert_eq!((-0.0f32).ln(), neg_inf); + assert_eq!(0.0f32.ln(), neg_inf); + assert_approx_eq!(4.0f32.ln(), 1.386294); +} + +#[test] +fn test_log() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(10.0f32.log(10.0), 1.0); + assert_approx_eq!(2.3f32.log(3.5), 0.664858); + assert_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0); + assert!(1.0f32.log(1.0).is_nan()); + assert!(1.0f32.log(-13.9).is_nan()); + assert!(nan.log(2.3).is_nan()); + assert_eq!(inf.log(10.0), inf); + assert!(neg_inf.log(8.8).is_nan()); + assert!((-2.3f32).log(0.1).is_nan()); + assert_eq!((-0.0f32).log(2.0), neg_inf); + assert_eq!(0.0f32.log(7.0), neg_inf); +} + +#[test] +fn test_log2() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_approx_eq!(10.0f32.log2(), 3.321928); + assert_approx_eq!(2.3f32.log2(), 1.201634); + assert_approx_eq!(1.0f32.exp().log2(), 1.442695); + assert!(nan.log2().is_nan()); + assert_eq!(inf.log2(), inf); + assert!(neg_inf.log2().is_nan()); + assert!((-2.3f32).log2().is_nan()); + assert_eq!((-0.0f32).log2(), neg_inf); + assert_eq!(0.0f32.log2(), neg_inf); +} + +#[test] +fn test_log10() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(10.0f32.log10(), 1.0); + assert_approx_eq!(2.3f32.log10(), 0.361728); + assert_approx_eq!(1.0f32.exp().log10(), 0.434294); + assert_eq!(1.0f32.log10(), 0.0); + assert!(nan.log10().is_nan()); + assert_eq!(inf.log10(), inf); + assert!(neg_inf.log10().is_nan()); + assert!((-2.3f32).log10().is_nan()); + assert_eq!((-0.0f32).log10(), neg_inf); + assert_eq!(0.0f32.log10(), neg_inf); +} + +#[test] +fn test_asinh() { + assert_eq!(0.0f32.asinh(), 0.0f32); + assert_eq!((-0.0f32).asinh(), -0.0f32); + + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let nan: f32 = f32::NAN; + assert_eq!(inf.asinh(), inf); + assert_eq!(neg_inf.asinh(), neg_inf); + assert!(nan.asinh().is_nan()); + assert!((-0.0f32).asinh().is_sign_negative()); // issue 63271 + assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32); + assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32); + // regression test for the catastrophic cancellation fixed in 72486 + assert_approx_eq!((-3000.0f32).asinh(), -8.699514775987968673236893537700647f32); + + // test for low accuracy from issue 104548 + assert_approx_eq!(60.0f32, 60.0f32.sinh().asinh()); + // mul needed for approximate comparison to be meaningful + assert_approx_eq!(1.0f32, 1e-15f32.sinh().asinh() * 1e15f32); +} + +#[test] +fn test_acosh() { + assert_eq!(1.0f32.acosh(), 0.0f32); + assert!(0.999f32.acosh().is_nan()); + + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let nan: f32 = f32::NAN; + assert_eq!(inf.acosh(), inf); + assert!(neg_inf.acosh().is_nan()); + assert!(nan.acosh().is_nan()); + assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32); + assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32); + + // test for low accuracy from issue 104548 + assert_approx_eq!(60.0f32, 60.0f32.cosh().acosh()); +} + +#[test] +fn test_atanh() { + assert_eq!(0.0f32.atanh(), 0.0f32); + assert_eq!((-0.0f32).atanh(), -0.0f32); + + let inf32: f32 = f32::INFINITY; + let neg_inf32: f32 = f32::NEG_INFINITY; + assert_eq!(1.0f32.atanh(), inf32); + assert_eq!((-1.0f32).atanh(), neg_inf32); + + assert!(2f64.atanh().atanh().is_nan()); + assert!((-2f64).atanh().atanh().is_nan()); + + let inf64: f32 = f32::INFINITY; + let neg_inf64: f32 = f32::NEG_INFINITY; + let nan32: f32 = f32::NAN; + assert!(inf64.atanh().is_nan()); + assert!(neg_inf64.atanh().is_nan()); + assert!(nan32.atanh().is_nan()); + + assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32); + assert_approx_eq!((-0.5f32).atanh(), -0.54930614433405484569762261846126285f32); +} + +#[test] +fn test_gamma() { + // precision can differ between platforms + assert_approx_eq!(1.0f32.gamma(), 1.0f32); + assert_approx_eq!(2.0f32.gamma(), 1.0f32); + assert_approx_eq!(3.0f32.gamma(), 2.0f32); + assert_approx_eq!(4.0f32.gamma(), 6.0f32); + assert_approx_eq!(5.0f32.gamma(), 24.0f32); + assert_approx_eq!(0.5f32.gamma(), consts::PI.sqrt()); + assert_approx_eq!((-0.5f32).gamma(), -2.0 * consts::PI.sqrt()); + assert_eq!(0.0f32.gamma(), f32::INFINITY); + assert_eq!((-0.0f32).gamma(), f32::NEG_INFINITY); + assert!((-1.0f32).gamma().is_nan()); + assert!((-2.0f32).gamma().is_nan()); + assert!(f32::NAN.gamma().is_nan()); + assert!(f32::NEG_INFINITY.gamma().is_nan()); + assert_eq!(f32::INFINITY.gamma(), f32::INFINITY); + assert_eq!(171.71f32.gamma(), f32::INFINITY); +} + +#[test] +fn test_ln_gamma() { + assert_approx_eq!(1.0f32.ln_gamma().0, 0.0f32); + assert_eq!(1.0f32.ln_gamma().1, 1); + assert_approx_eq!(2.0f32.ln_gamma().0, 0.0f32); + assert_eq!(2.0f32.ln_gamma().1, 1); + assert_approx_eq!(3.0f32.ln_gamma().0, 2.0f32.ln()); + assert_eq!(3.0f32.ln_gamma().1, 1); + assert_approx_eq!((-0.5f32).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln()); + assert_eq!((-0.5f32).ln_gamma().1, -1); +} + +#[test] +fn test_real_consts() { + let pi: f32 = consts::PI; + let frac_pi_2: f32 = consts::FRAC_PI_2; + let frac_pi_3: f32 = consts::FRAC_PI_3; + let frac_pi_4: f32 = consts::FRAC_PI_4; + let frac_pi_6: f32 = consts::FRAC_PI_6; + let frac_pi_8: f32 = consts::FRAC_PI_8; + let frac_1_pi: f32 = consts::FRAC_1_PI; + let frac_2_pi: f32 = consts::FRAC_2_PI; + let frac_2_sqrtpi: f32 = consts::FRAC_2_SQRT_PI; + let sqrt2: f32 = consts::SQRT_2; + let frac_1_sqrt2: f32 = consts::FRAC_1_SQRT_2; + let e: f32 = consts::E; + let log2_e: f32 = consts::LOG2_E; + let log10_e: f32 = consts::LOG10_E; + let ln_2: f32 = consts::LN_2; + let ln_10: f32 = consts::LN_10; + + assert_approx_eq!(frac_pi_2, pi / 2f32); + assert_approx_eq!(frac_pi_3, pi / 3f32); + assert_approx_eq!(frac_pi_4, pi / 4f32); + assert_approx_eq!(frac_pi_6, pi / 6f32); + assert_approx_eq!(frac_pi_8, pi / 8f32); + assert_approx_eq!(frac_1_pi, 1f32 / pi); + assert_approx_eq!(frac_2_pi, 2f32 / pi); + assert_approx_eq!(frac_2_sqrtpi, 2f32 / pi.sqrt()); + assert_approx_eq!(sqrt2, 2f32.sqrt()); + assert_approx_eq!(frac_1_sqrt2, 1f32 / 2f32.sqrt()); + assert_approx_eq!(log2_e, e.log2()); + assert_approx_eq!(log10_e, e.log10()); + assert_approx_eq!(ln_2, 2f32.ln()); + assert_approx_eq!(ln_10, 10f32.ln()); +} diff --git a/library/std/tests/floats/f64.rs b/library/std/tests/floats/f64.rs new file mode 100644 index 0000000000000..2d8dd1cf0915b --- /dev/null +++ b/library/std/tests/floats/f64.rs @@ -0,0 +1,249 @@ +use std::f64::consts; + +#[allow(unused_macros)] +macro_rules! assert_f64_biteq { + ($left : expr, $right : expr) => { + let l: &f64 = &$left; + let r: &f64 = &$right; + let lb = l.to_bits(); + let rb = r.to_bits(); + assert_eq!(lb, rb, "float {l} ({lb:#018x}) is not bitequal to {r} ({rb:#018x})"); + }; +} + +#[test] +fn test_powf() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_eq!(1.0f64.powf(1.0), 1.0); + assert_approx_eq!(3.4f64.powf(4.5), 246.408183); + assert_approx_eq!(2.7f64.powf(-3.2), 0.041652); + assert_approx_eq!((-3.1f64).powf(2.0), 9.61); + assert_approx_eq!(5.9f64.powf(-2.0), 0.028727); + assert_eq!(8.3f64.powf(0.0), 1.0); + assert!(nan.powf(2.0).is_nan()); + assert_eq!(inf.powf(2.0), inf); + assert_eq!(neg_inf.powf(3.0), neg_inf); +} + +#[test] +fn test_exp() { + assert_eq!(1.0, 0.0f64.exp()); + assert_approx_eq!(2.718282, 1.0f64.exp()); + assert_approx_eq!(148.413159, 5.0f64.exp()); + + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let nan: f64 = f64::NAN; + assert_eq!(inf, inf.exp()); + assert_eq!(0.0, neg_inf.exp()); + assert!(nan.exp().is_nan()); +} + +#[test] +fn test_exp2() { + assert_eq!(32.0, 5.0f64.exp2()); + assert_eq!(1.0, 0.0f64.exp2()); + + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let nan: f64 = f64::NAN; + assert_eq!(inf, inf.exp2()); + assert_eq!(0.0, neg_inf.exp2()); + assert!(nan.exp2().is_nan()); +} + +#[test] +fn test_ln() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_approx_eq!(1.0f64.exp().ln(), 1.0); + assert!(nan.ln().is_nan()); + assert_eq!(inf.ln(), inf); + assert!(neg_inf.ln().is_nan()); + assert!((-2.3f64).ln().is_nan()); + assert_eq!((-0.0f64).ln(), neg_inf); + assert_eq!(0.0f64.ln(), neg_inf); + assert_approx_eq!(4.0f64.ln(), 1.386294); +} + +#[test] +fn test_log() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_eq!(10.0f64.log(10.0), 1.0); + assert_approx_eq!(2.3f64.log(3.5), 0.664858); + assert_eq!(1.0f64.exp().log(1.0f64.exp()), 1.0); + assert!(1.0f64.log(1.0).is_nan()); + assert!(1.0f64.log(-13.9).is_nan()); + assert!(nan.log(2.3).is_nan()); + assert_eq!(inf.log(10.0), inf); + assert!(neg_inf.log(8.8).is_nan()); + assert!((-2.3f64).log(0.1).is_nan()); + assert_eq!((-0.0f64).log(2.0), neg_inf); + assert_eq!(0.0f64.log(7.0), neg_inf); +} + +#[test] +fn test_log2() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_approx_eq!(10.0f64.log2(), 3.321928); + assert_approx_eq!(2.3f64.log2(), 1.201634); + assert_approx_eq!(1.0f64.exp().log2(), 1.442695); + assert!(nan.log2().is_nan()); + assert_eq!(inf.log2(), inf); + assert!(neg_inf.log2().is_nan()); + assert!((-2.3f64).log2().is_nan()); + assert_eq!((-0.0f64).log2(), neg_inf); + assert_eq!(0.0f64.log2(), neg_inf); +} + +#[test] +fn test_log10() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_eq!(10.0f64.log10(), 1.0); + assert_approx_eq!(2.3f64.log10(), 0.361728); + assert_approx_eq!(1.0f64.exp().log10(), 0.434294); + assert_eq!(1.0f64.log10(), 0.0); + assert!(nan.log10().is_nan()); + assert_eq!(inf.log10(), inf); + assert!(neg_inf.log10().is_nan()); + assert!((-2.3f64).log10().is_nan()); + assert_eq!((-0.0f64).log10(), neg_inf); + assert_eq!(0.0f64.log10(), neg_inf); +} + +#[test] +fn test_asinh() { + assert_eq!(0.0f64.asinh(), 0.0f64); + assert_eq!((-0.0f64).asinh(), -0.0f64); + + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let nan: f64 = f64::NAN; + assert_eq!(inf.asinh(), inf); + assert_eq!(neg_inf.asinh(), neg_inf); + assert!(nan.asinh().is_nan()); + assert!((-0.0f64).asinh().is_sign_negative()); + // issue 63271 + assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64); + assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64); + // regression test for the catastrophic cancellation fixed in 72486 + assert_approx_eq!((-67452098.07139316f64).asinh(), -18.72007542627454439398548429400083); + + // test for low accuracy from issue 104548 + assert_approx_eq!(60.0f64, 60.0f64.sinh().asinh()); + // mul needed for approximate comparison to be meaningful + assert_approx_eq!(1.0f64, 1e-15f64.sinh().asinh() * 1e15f64); +} + +#[test] +fn test_acosh() { + assert_eq!(1.0f64.acosh(), 0.0f64); + assert!(0.999f64.acosh().is_nan()); + + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let nan: f64 = f64::NAN; + assert_eq!(inf.acosh(), inf); + assert!(neg_inf.acosh().is_nan()); + assert!(nan.acosh().is_nan()); + assert_approx_eq!(2.0f64.acosh(), 1.31695789692481670862504634730796844f64); + assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64); + + // test for low accuracy from issue 104548 + assert_approx_eq!(60.0f64, 60.0f64.cosh().acosh()); +} + +#[test] +fn test_atanh() { + assert_eq!(0.0f64.atanh(), 0.0f64); + assert_eq!((-0.0f64).atanh(), -0.0f64); + + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let nan: f64 = f64::NAN; + assert_eq!(1.0f64.atanh(), inf); + assert_eq!((-1.0f64).atanh(), neg_inf); + assert!(2f64.atanh().atanh().is_nan()); + assert!((-2f64).atanh().atanh().is_nan()); + assert!(inf.atanh().is_nan()); + assert!(neg_inf.atanh().is_nan()); + assert!(nan.atanh().is_nan()); + assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64); + assert_approx_eq!((-0.5f64).atanh(), -0.54930614433405484569762261846126285f64); +} + +#[test] +fn test_gamma() { + // precision can differ between platforms + assert_approx_eq!(1.0f64.gamma(), 1.0f64); + assert_approx_eq!(2.0f64.gamma(), 1.0f64); + assert_approx_eq!(3.0f64.gamma(), 2.0f64); + assert_approx_eq!(4.0f64.gamma(), 6.0f64); + assert_approx_eq!(5.0f64.gamma(), 24.0f64); + assert_approx_eq!(0.5f64.gamma(), consts::PI.sqrt()); + assert_approx_eq!((-0.5f64).gamma(), -2.0 * consts::PI.sqrt()); + assert_eq!(0.0f64.gamma(), f64::INFINITY); + assert_eq!((-0.0f64).gamma(), f64::NEG_INFINITY); + assert!((-1.0f64).gamma().is_nan()); + assert!((-2.0f64).gamma().is_nan()); + assert!(f64::NAN.gamma().is_nan()); + assert!(f64::NEG_INFINITY.gamma().is_nan()); + assert_eq!(f64::INFINITY.gamma(), f64::INFINITY); + assert_eq!(171.71f64.gamma(), f64::INFINITY); +} + +#[test] +fn test_ln_gamma() { + assert_approx_eq!(1.0f64.ln_gamma().0, 0.0f64); + assert_eq!(1.0f64.ln_gamma().1, 1); + assert_approx_eq!(2.0f64.ln_gamma().0, 0.0f64); + assert_eq!(2.0f64.ln_gamma().1, 1); + assert_approx_eq!(3.0f64.ln_gamma().0, 2.0f64.ln()); + assert_eq!(3.0f64.ln_gamma().1, 1); + assert_approx_eq!((-0.5f64).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln()); + assert_eq!((-0.5f64).ln_gamma().1, -1); +} + +#[test] +fn test_real_consts() { + let pi: f64 = consts::PI; + let frac_pi_2: f64 = consts::FRAC_PI_2; + let frac_pi_3: f64 = consts::FRAC_PI_3; + let frac_pi_4: f64 = consts::FRAC_PI_4; + let frac_pi_6: f64 = consts::FRAC_PI_6; + let frac_pi_8: f64 = consts::FRAC_PI_8; + let frac_1_pi: f64 = consts::FRAC_1_PI; + let frac_2_pi: f64 = consts::FRAC_2_PI; + let frac_2_sqrtpi: f64 = consts::FRAC_2_SQRT_PI; + let sqrt2: f64 = consts::SQRT_2; + let frac_1_sqrt2: f64 = consts::FRAC_1_SQRT_2; + let e: f64 = consts::E; + let log2_e: f64 = consts::LOG2_E; + let log10_e: f64 = consts::LOG10_E; + let ln_2: f64 = consts::LN_2; + let ln_10: f64 = consts::LN_10; + + assert_approx_eq!(frac_pi_2, pi / 2f64); + assert_approx_eq!(frac_pi_3, pi / 3f64); + assert_approx_eq!(frac_pi_4, pi / 4f64); + assert_approx_eq!(frac_pi_6, pi / 6f64); + assert_approx_eq!(frac_pi_8, pi / 8f64); + assert_approx_eq!(frac_1_pi, 1f64 / pi); + assert_approx_eq!(frac_2_pi, 2f64 / pi); + assert_approx_eq!(frac_2_sqrtpi, 2f64 / pi.sqrt()); + assert_approx_eq!(sqrt2, 2f64.sqrt()); + assert_approx_eq!(frac_1_sqrt2, 1f64 / 2f64.sqrt()); + assert_approx_eq!(log2_e, e.log2()); + assert_approx_eq!(log10_e, e.log10()); + assert_approx_eq!(ln_2, 2f64.ln()); + assert_approx_eq!(ln_10, 10f64.ln()); +} diff --git a/library/std/tests/floats/lib.rs b/library/std/tests/floats/lib.rs new file mode 100644 index 0000000000000..8bb8eb4bfc1ae --- /dev/null +++ b/library/std/tests/floats/lib.rs @@ -0,0 +1,43 @@ +#![feature(f16, f128, float_gamma, float_minimum_maximum, cfg_target_has_reliable_f16_f128)] +#![expect(internal_features)] // for reliable_f16_f128 + +use std::fmt; +use std::ops::{Add, Div, Mul, Rem, Sub}; + +/// Verify that floats are within a tolerance of each other, 1.0e-6 by default. +macro_rules! assert_approx_eq { + ($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, 1.0e-6) }}; + ($a:expr, $b:expr, $lim:expr) => {{ + let (a, b) = (&$a, &$b); + let diff = (*a - *b).abs(); + assert!( + diff <= $lim, + "{a:?} is not approximately equal to {b:?} (threshold {lim:?}, difference {diff:?})", + lim = $lim + ); + }}; +} + +/// Helper function for testing numeric operations +pub fn test_num(ten: T, two: T) +where + T: PartialEq + + Add + + Sub + + Mul + + Div + + Rem + + fmt::Debug + + Copy, +{ + assert_eq!(ten.add(two), ten + two); + assert_eq!(ten.sub(two), ten - two); + assert_eq!(ten.mul(two), ten * two); + assert_eq!(ten.div(two), ten / two); + assert_eq!(ten.rem(two), ten % two); +} + +mod f128; +mod f16; +mod f32; +mod f64; From 65117eeda8dd672fe1420538d8cf228ee41e13f7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 30 Apr 2025 18:02:24 -0400 Subject: [PATCH 2266/4206] Skip {f32,f64}::mul_add tests on MinGW Per [1], MinGW has an incorrect fma implementation. This showed up in tests run with cranelift after adding float math operations to `core`. Presumably we hadn't noticed this when running tests with LLVM because LLVM was constant folding the result away. Rust issue: https://github.com/rust-lang/rust/issues/140515 [1]: https://sourceforge.net/p/mingw-w64/bugs/848/ --- library/core/src/num/f32.rs | 3 +++ library/core/src/num/f64.rs | 3 +++ library/coretests/tests/floats/f32.rs | 2 ++ library/coretests/tests/floats/f64.rs | 2 ++ 4 files changed, 10 insertions(+) diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 326ccd517ced5..9525bdb6762a2 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1742,6 +1742,8 @@ pub fn fract(x: f32) -> f32 { /// ``` /// #![feature(core_float_math)] /// +/// # // FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/ +/// # #[cfg(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")))] { /// use core::f32; /// /// let m = 10.0_f32; @@ -1759,6 +1761,7 @@ pub fn fract(x: f32) -> f32 { /// assert_eq!(f32::mul_add(one_plus_eps, one_minus_eps, minus_one), -f32::EPSILON * f32::EPSILON); /// // Different rounding with the non-fused multiply and add. /// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0); +/// # } /// ``` /// /// _This standalone function is for testing only. It will be stabilized as an inherent method._ diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 66aba73aec10d..76c4e5d1a6f78 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1741,6 +1741,8 @@ pub fn fract(x: f64) -> f64 { /// ``` /// #![feature(core_float_math)] /// +/// # // FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/ +/// # #[cfg(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")))] { /// use core::f64; /// /// let m = 10.0_f64; @@ -1758,6 +1760,7 @@ pub fn fract(x: f64) -> f64 { /// assert_eq!(f64::mul_add(one_plus_eps, one_minus_eps, minus_one), -f64::EPSILON * f64::EPSILON); /// // Different rounding with the non-fused multiply and add. /// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0); +/// # } /// ``` /// /// _This standalone function is for testing only. It will be stabilized as an inherent method._ diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 1c018a5e7b52f..9b551643bae24 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -410,6 +410,8 @@ fn test_next_down() { assert_f32_biteq!(nan2.next_down(), nan2); } +// FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/ +#[cfg_attr(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")), ignore)] #[test] fn test_mul_add() { let nan: f32 = f32::NAN; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 4a79a31853ec8..988108371d731 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -394,6 +394,8 @@ fn test_next_down() { assert_f64_biteq!(nan2.next_down(), nan2); } +// FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/ +#[cfg_attr(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")), ignore)] #[test] fn test_mul_add() { let nan: f64 = f64::NAN; From 6274d461cf3005ff1e22afa77c1a96090f63b40f Mon Sep 17 00:00:00 2001 From: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com> Date: Wed, 14 May 2025 09:59:20 +0900 Subject: [PATCH 2267/4206] fix: Removing all unused imports removes used imports for imports used for Derive macros Signed-off-by: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com> --- src/tools/rust-analyzer/crates/hir/src/lib.rs | 3 +- .../rust-analyzer/crates/hir/src/semantics.rs | 24 ++ .../crates/hir/src/source_analyzer.rs | 61 ++++- .../src/handlers/remove_unused_imports.rs | 215 ++++++++++++++---- 4 files changed, 257 insertions(+), 46 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index c5d37cafd9898..3a91050d15fad 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -97,7 +97,8 @@ pub use crate::{ diagnostics::*, has_source::HasSource, semantics::{ - PathResolution, Semantics, SemanticsImpl, SemanticsScope, TypeInfo, VisibleTraits, + PathResolution, PathResolutionPerNs, Semantics, SemanticsImpl, SemanticsScope, TypeInfo, + VisibleTraits, }, }; diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 327fe8a758391..7ee72614e2206 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -103,6 +103,26 @@ impl PathResolution { } } +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct PathResolutionPerNs { + pub type_ns: Option, + pub value_ns: Option, + pub macro_ns: Option, +} + +impl PathResolutionPerNs { + pub fn new( + type_ns: Option, + value_ns: Option, + macro_ns: Option, + ) -> Self { + PathResolutionPerNs { type_ns, value_ns, macro_ns } + } + pub fn take_path(&self) -> Option { + self.type_ns.or(self.value_ns).or(self.macro_ns) + } +} + #[derive(Debug)] pub struct TypeInfo { /// The original type of the expression or pattern. @@ -1606,6 +1626,10 @@ impl<'db> SemanticsImpl<'db> { self.resolve_path_with_subst(path).map(|(it, _)| it) } + pub fn resolve_path_per_ns(&self, path: &ast::Path) -> Option { + self.analyze(path.syntax())?.resolve_hir_path_per_ns(self.db, path) + } + pub fn resolve_path_with_subst( &self, path: &ast::Path, diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 42da7b942c73a..610770d0f31e3 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -10,7 +10,9 @@ use std::iter::{self, once}; use crate::{ Adt, AssocItem, BindingMode, BuiltinAttr, BuiltinType, Callable, Const, DeriveHelper, Field, Function, GenericSubstitution, Local, Macro, ModuleDef, Static, Struct, ToolModule, Trait, - TraitAlias, TupleField, Type, TypeAlias, Variant, db::HirDatabase, semantics::PathResolution, + TraitAlias, TupleField, Type, TypeAlias, Variant, + db::HirDatabase, + semantics::{PathResolution, PathResolutionPerNs}, }; use either::Either; use hir_def::{ @@ -1159,7 +1161,9 @@ impl<'db> SourceAnalyzer<'db> { prefer_value_ns, name_hygiene(db, InFile::new(self.file_id, path.syntax())), Some(&store), - )?; + false, + ) + .take_path()?; let subst = (|| { let parent = parent()?; let ty = if let Some(expr) = ast::Expr::cast(parent.clone()) { @@ -1209,6 +1213,26 @@ impl<'db> SourceAnalyzer<'db> { } } + pub(crate) fn resolve_hir_path_per_ns( + &self, + db: &dyn HirDatabase, + path: &ast::Path, + ) -> Option { + let mut collector = ExprCollector::new(db, self.resolver.module(), self.file_id); + let hir_path = + collector.lower_path(path.clone(), &mut ExprCollector::impl_trait_error_allocator)?; + let store = collector.store.finish(); + Some(resolve_hir_path_( + db, + &self.resolver, + &hir_path, + false, + name_hygiene(db, InFile::new(self.file_id, path.syntax())), + Some(&store), + true, + )) + } + pub(crate) fn record_literal_missing_fields( &self, db: &'db dyn HirDatabase, @@ -1532,7 +1556,7 @@ pub(crate) fn resolve_hir_path( hygiene: HygieneId, store: Option<&ExpressionStore>, ) -> Option { - resolve_hir_path_(db, resolver, path, false, hygiene, store) + resolve_hir_path_(db, resolver, path, false, hygiene, store, false).take_path() } #[inline] @@ -1554,7 +1578,8 @@ fn resolve_hir_path_( prefer_value_ns: bool, hygiene: HygieneId, store: Option<&ExpressionStore>, -) -> Option { + resolve_per_ns: bool, +) -> PathResolutionPerNs { let types = || { let (ty, unresolved) = match path.type_anchor() { Some(type_ref) => resolver.generic_def().and_then(|def| { @@ -1635,9 +1660,31 @@ fn resolve_hir_path_( .map(|(def, _)| PathResolution::Def(ModuleDef::Macro(def.into()))) }; - if prefer_value_ns { values().or_else(types) } else { types().or_else(values) } - .or_else(items) - .or_else(macros) + if resolve_per_ns { + PathResolutionPerNs { + type_ns: types().or_else(items), + value_ns: values(), + macro_ns: macros(), + } + } else { + let res = if prefer_value_ns { + values() + .map(|value_ns| PathResolutionPerNs::new(None, Some(value_ns), None)) + .unwrap_or_else(|| PathResolutionPerNs::new(types(), None, None)) + } else { + types() + .map(|type_ns| PathResolutionPerNs::new(Some(type_ns), None, None)) + .unwrap_or_else(|| PathResolutionPerNs::new(None, values(), None)) + }; + + if res.take_path().is_some() { + res + } else if let Some(type_ns) = items() { + PathResolutionPerNs::new(Some(type_ns), None, None) + } else { + PathResolutionPerNs::new(None, None, macros()) + } + } } fn resolve_hir_value_path( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs index 1baf814ca6826..fb96882ed428e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs @@ -1,6 +1,9 @@ use std::collections::hash_map::Entry; -use hir::{FileRange, InFile, InRealFile, Module, ModuleSource}; +use hir::{ + FileRange, InFile, InRealFile, Module, ModuleDef, ModuleSource, PathResolution, + PathResolutionPerNs, +}; use ide_db::text_edit::TextRange; use ide_db::{ FxHashMap, RootDatabase, @@ -77,49 +80,52 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>) }; // Get the actual definition associated with this use item. - let res = match ctx.sema.resolve_path(&path) { - Some(x) => x, - None => { + let res = match ctx.sema.resolve_path_per_ns(&path) { + Some(x) if x.take_path().is_some() => x, + Some(_) | None => { return None; } }; - - let def = match res { - hir::PathResolution::Def(d) => Definition::from(d), - _ => return None, - }; - - if u.star_token().is_some() { - // Check if any of the children of this module are used - let def_mod = match def { - Definition::Module(module) => module, - _ => return None, - }; - - if !def_mod - .scope(ctx.db(), Some(use_module)) - .iter() - .filter_map(|(_, x)| match x { - hir::ScopeDef::ModuleDef(d) => Some(Definition::from(*d)), - _ => None, - }) - .any(|d| used_once_in_scope(ctx, d, u.rename(), scope)) - { - return Some(u); + match res { + PathResolutionPerNs { type_ns: Some(type_ns), .. } if u.star_token().is_some() => { + // Check if any of the children of this module are used + let def_mod = match type_ns { + PathResolution::Def(ModuleDef::Module(module)) => module, + _ => return None, + }; + + if !def_mod + .scope(ctx.db(), Some(use_module)) + .iter() + .filter_map(|(_, x)| match x { + hir::ScopeDef::ModuleDef(d) => Some(Definition::from(*d)), + _ => None, + }) + .any(|d| used_once_in_scope(ctx, d, u.rename(), scope)) + { + Some(u) + } else { + None + } } - } else if let Definition::Trait(ref t) = def { - // If the trait or any item is used. - if !std::iter::once((def, u.rename())) - .chain(t.items(ctx.db()).into_iter().map(|item| (item.into(), None))) - .any(|(d, rename)| used_once_in_scope(ctx, d, rename, scope)) - { - return Some(u); + PathResolutionPerNs { + type_ns: Some(PathResolution::Def(ModuleDef::Trait(ref t))), + value_ns, + macro_ns, + } => { + // If the trait or any item is used. + if is_trait_unused_in_scope(ctx, &u, scope, t) { + let path = [value_ns, macro_ns]; + is_path_unused_in_scope(ctx, &u, scope, &path).then_some(u) + } else { + None + } + } + PathResolutionPerNs { type_ns, value_ns, macro_ns } => { + let path = [type_ns, value_ns, macro_ns]; + is_path_unused_in_scope(ctx, &u, scope, &path).then_some(u) } - } else if !used_once_in_scope(ctx, def, u.rename(), scope) { - return Some(u); } - - None }) .peekable(); @@ -141,6 +147,33 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>) } } +fn is_path_unused_in_scope( + ctx: &AssistContext<'_>, + u: &ast::UseTree, + scope: &mut Vec, + path: &[Option], +) -> bool { + !path + .iter() + .filter_map(|path| *path) + .filter_map(|res| match res { + PathResolution::Def(d) => Some(Definition::from(d)), + _ => None, + }) + .any(|def| used_once_in_scope(ctx, def, u.rename(), scope)) +} + +fn is_trait_unused_in_scope( + ctx: &AssistContext<'_>, + u: &ast::UseTree, + scope: &mut Vec, + t: &hir::Trait, +) -> bool { + !std::iter::once((Definition::Trait(*t), u.rename())) + .chain(t.items(ctx.db()).into_iter().map(|item| (item.into(), None))) + .any(|(d, rename)| used_once_in_scope(ctx, d, rename, scope)) +} + fn used_once_in_scope( ctx: &AssistContext<'_>, def: Definition, @@ -1009,6 +1042,112 @@ fn test(_: Bar) { let a = (); a.quxx(); } +"#, + ); + } + + #[test] + fn test_unused_macro() { + check_assist( + remove_unused_imports, + r#" +//- /foo.rs crate:foo +#[macro_export] +macro_rules! m { () => {} } + +//- /main.rs crate:main deps:foo +use foo::m;$0 +fn main() {} +"#, + r#" +fn main() {} +"#, + ); + + check_assist_not_applicable( + remove_unused_imports, + r#" +//- /foo.rs crate:foo +#[macro_export] +macro_rules! m { () => {} } + +//- /main.rs crate:main deps:foo +use foo::m;$0 +fn main() { + m!(); +} +"#, + ); + + check_assist_not_applicable( + remove_unused_imports, + r#" +//- /foo.rs crate:foo +#[macro_export] +macro_rules! m { () => {} } + +//- /bar.rs crate:bar deps:foo +pub use foo::m; +fn m() {} + + +//- /main.rs crate:main deps:bar +use bar::m;$0 +fn main() { + m!(); +} +"#, + ); + } + + #[test] + fn test_conflict_derive_macro() { + check_assist_not_applicable( + remove_unused_imports, + r#" +//- proc_macros: derive_identity +//- minicore: derive +//- /bar.rs crate:bar +pub use proc_macros::DeriveIdentity; +pub trait DeriveIdentity {} + +//- /main.rs crate:main deps:bar +$0use bar::DeriveIdentity;$0 +#[derive(DeriveIdentity)] +struct S; +"#, + ); + + check_assist_not_applicable( + remove_unused_imports, + r#" +//- proc_macros: derive_identity +//- minicore: derive +//- /bar.rs crate:bar +pub use proc_macros::DeriveIdentity; +pub fn DeriveIdentity() {} + +//- /main.rs crate:main deps:bar +$0use bar::DeriveIdentity;$0 +#[derive(DeriveIdentity)] +struct S; +"#, + ); + + check_assist_not_applicable( + remove_unused_imports, + r#" +//- proc_macros: derive_identity +//- minicore: derive +//- /bar.rs crate:bar +pub use proc_macros::DeriveIdentity; +pub fn DeriveIdentity() {} + +//- /main.rs crate:main deps:bar +$0use bar::DeriveIdentity;$0 +fn main() { + DeriveIdentity(); +} "#, ); } From 754b06f97869253968e0d6abf8105d047c327b62 Mon Sep 17 00:00:00 2001 From: Emmanuel Ferdman Date: Wed, 14 May 2025 08:41:30 -0700 Subject: [PATCH 2268/4206] Migrate to modern datetime API Signed-off-by: Emmanuel Ferdman --- src/ci/cpu-usage-over-time.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/cpu-usage-over-time.py b/src/ci/cpu-usage-over-time.py index 3d9dc86734fcc..19a39f349532c 100755 --- a/src/ci/cpu-usage-over-time.py +++ b/src/ci/cpu-usage-over-time.py @@ -170,7 +170,7 @@ def idle_since(self, prev): while True: time.sleep(1) next_state = State() - now = datetime.datetime.utcnow().isoformat() + now = datetime.datetime.now(datetime.timezone.utc).replace(tzinfo=None).isoformat() idle = next_state.idle_since(cur_state) print("%s,%s" % (now, idle)) sys.stdout.flush() From 7a47a6a9c7b6a320ce18b45e39da5249a78e867a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 14 May 2025 18:00:19 +0200 Subject: [PATCH 2269/4206] Update gcc version used in rustc_codegen_version --- compiler/rustc_codegen_gcc/libgccjit.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_gcc/libgccjit.version b/compiler/rustc_codegen_gcc/libgccjit.version index d06646dacc342..f62154968d3de 100644 --- a/compiler/rustc_codegen_gcc/libgccjit.version +++ b/compiler/rustc_codegen_gcc/libgccjit.version @@ -1 +1 @@ -8b194529188f9d3a98cc211caa805a5355bfa8f0 +04ce66d8c918de9273bd7101638ad8724edf5e21 From 3cec08a47ecf18d90d65c9dbd1927082f2af36d3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 14 May 2025 18:00:19 +0200 Subject: [PATCH 2270/4206] Update gcc version used in rustc_codegen_version --- libgccjit.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libgccjit.version b/libgccjit.version index d06646dacc342..f62154968d3de 100644 --- a/libgccjit.version +++ b/libgccjit.version @@ -1 +1 @@ -8b194529188f9d3a98cc211caa805a5355bfa8f0 +04ce66d8c918de9273bd7101638ad8724edf5e21 From d5c5a8251d0a9477ff6383638d5a8fdb2e109819 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 14 May 2025 18:02:02 +0200 Subject: [PATCH 2271/4206] Update `src/gcc` submodule to `04ce66d8c918de9273bd7101638ad8724edf5e21` --- src/gcc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gcc b/src/gcc index 0ea98a1365b81..04ce66d8c918d 160000 --- a/src/gcc +++ b/src/gcc @@ -1 +1 @@ -Subproject commit 0ea98a1365b81f7488073512c850e8ee951a4afd +Subproject commit 04ce66d8c918de9273bd7101638ad8724edf5e21 From ac1df15f86a911cd0f2fd54dd5df6fc58f6d4eb5 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 7 May 2025 22:16:51 +0200 Subject: [PATCH 2272/4206] Improve `dangerous_implicit_aurorefs` diagnostic output --- compiler/rustc_lint/messages.ftl | 4 + compiler/rustc_lint/src/autorefs.rs | 27 +-- compiler/rustc_lint/src/lints.rs | 13 +- tests/ui/lint/implicit_autorefs.fixed | 6 + tests/ui/lint/implicit_autorefs.rs | 6 + tests/ui/lint/implicit_autorefs.stderr | 228 ++++++++++++++++++++++--- 6 files changed, 253 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 99b42ee548029..baa017f3084a5 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -362,6 +362,10 @@ lint_impl_trait_redundant_captures = all possible in-scope parameters are alread lint_implicit_unsafe_autorefs = implicit autoref creates a reference to the dereference of a raw pointer .note = creating a reference requires the pointer target to be valid and imposes aliasing requirements + .raw_ptr = this raw pointer has type `{$raw_ptr_ty}` + .autoref = autoref is being applied to this expression, resulting in: `{$autoref_ty}` + .through_overloaded_deref = reference(s) created through call(s) to overloaded `Deref(Mut)::deref(_mut)` implementation + .method_def = method calls to `{$method_name}` require a reference .suggestion = try using a raw pointer method instead; or if this reference is intentional, make it explicit lint_improper_ctypes = `extern` {$desc} uses type `{$ty}`, which is not FFI-safe diff --git a/compiler/rustc_lint/src/autorefs.rs b/compiler/rustc_lint/src/autorefs.rs index 91d58d92466ac..9bb235263625d 100644 --- a/compiler/rustc_lint/src/autorefs.rs +++ b/compiler/rustc_lint/src/autorefs.rs @@ -2,7 +2,7 @@ use rustc_ast::{BorrowKind, UnOp}; use rustc_hir::{Expr, ExprKind, Mutability}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref}; use rustc_session::{declare_lint, declare_lint_pass}; -use rustc_span::sym; +use rustc_span::{kw, sym}; use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion}; use crate::{LateContext, LateLintPass, LintContext}; @@ -92,25 +92,30 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs { && let adjustments = peel_derefs_adjustments(&**adjustments) // 3. An automatically inserted reference (might come from a deref). && let [adjustment] = adjustments - && let Some(borrow_mutbl) = has_implicit_borrow(adjustment) + && let Some((borrow_mutbl, through_overloaded_deref)) = has_implicit_borrow(adjustment) && let ExprKind::Unary(UnOp::Deref, dereferenced) = // 2. Any number of place projections. peel_place_mappers(inner).kind // 1. Deref of a raw pointer. && typeck.expr_ty(dereferenced).is_raw_ptr() // PERF: 5. b. A method call annotated with `#[rustc_no_implicit_refs]` - && match expr.kind { - ExprKind::MethodCall(..) => matches!( - cx.typeck_results().type_dependent_def_id(expr.hir_id), - Some(def_id) if cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) - ), - _ => true, + && let method_did = match expr.kind { + ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id), + _ => None, } + && method_did.map(|did| cx.tcx.has_attr(did, sym::rustc_no_implicit_autorefs)).unwrap_or(true) { cx.emit_span_lint( DANGEROUS_IMPLICIT_AUTOREFS, expr.span.source_callsite(), ImplicitUnsafeAutorefsDiag { + raw_ptr_span: dereferenced.span, + raw_ptr_ty: typeck.expr_ty(dereferenced), + autoref_span: inner.span, + autoref_ty: typeck.expr_ty_adjusted(inner), + method_def_span: method_did.map(|did| cx.tcx.def_span(did)), + method_name: method_did.map(|did| cx.tcx.item_name(did)).unwrap_or(kw::Empty), + through_overloaded_deref, suggestion: ImplicitUnsafeAutorefsSuggestion { mutbl: borrow_mutbl.ref_prefix_str(), deref: if is_coming_from_deref { "*" } else { "" }, @@ -147,10 +152,10 @@ fn peel_derefs_adjustments<'a>(mut adjs: &'a [Adjustment<'a>]) -> &'a [Adjustmen /// Test if some adjustment has some implicit borrow. /// /// Returns `Some(mutability)` if the argument adjustment has implicit borrow in it. -fn has_implicit_borrow(Adjustment { kind, .. }: &Adjustment<'_>) -> Option { +fn has_implicit_borrow(Adjustment { kind, .. }: &Adjustment<'_>) -> Option<(Mutability, bool)> { match kind { - &Adjust::Deref(Some(OverloadedDeref { mutbl, .. })) => Some(mutbl), - &Adjust::Borrow(AutoBorrow::Ref(mutbl)) => Some(mutbl.into()), + &Adjust::Deref(Some(OverloadedDeref { mutbl, .. })) => Some((mutbl, true)), + &Adjust::Borrow(AutoBorrow::Ref(mutbl)) => Some((mutbl.into(), false)), Adjust::NeverToAny | Adjust::Pointer(..) | Adjust::ReborrowPin(..) diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 487184b836a43..978bb6d08d5ae 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -59,7 +59,18 @@ pub(crate) enum ShadowedIntoIterDiagSub { #[derive(LintDiagnostic)] #[diag(lint_implicit_unsafe_autorefs)] #[note] -pub(crate) struct ImplicitUnsafeAutorefsDiag { +pub(crate) struct ImplicitUnsafeAutorefsDiag<'a> { + #[label(lint_raw_ptr)] + pub raw_ptr_span: Span, + pub raw_ptr_ty: Ty<'a>, + #[note(lint_autoref)] + pub autoref_span: Span, + pub autoref_ty: Ty<'a>, + #[note(lint_method_def)] + pub method_def_span: Option, + pub method_name: Symbol, + #[note(lint_through_overloaded_deref)] + pub through_overloaded_deref: bool, #[subdiagnostic] pub suggestion: ImplicitUnsafeAutorefsSuggestion, } diff --git a/tests/ui/lint/implicit_autorefs.fixed b/tests/ui/lint/implicit_autorefs.fixed index 96a617b20c918..454dfe7637261 100644 --- a/tests/ui/lint/implicit_autorefs.fixed +++ b/tests/ui/lint/implicit_autorefs.fixed @@ -96,4 +96,10 @@ unsafe fn test_string(ptr: *mut String) { //~^ WARN implicit autoref } +unsafe fn slice_ptr_len_because_of_msrv(slice: *const [T]) { + let _ = (&(&(*slice))[..]).len(); + //~^ WARN implicit autoref + //~^^ WARN implicit autoref +} + fn main() {} diff --git a/tests/ui/lint/implicit_autorefs.rs b/tests/ui/lint/implicit_autorefs.rs index 61dd0ac50ce75..507d653682839 100644 --- a/tests/ui/lint/implicit_autorefs.rs +++ b/tests/ui/lint/implicit_autorefs.rs @@ -96,4 +96,10 @@ unsafe fn test_string(ptr: *mut String) { //~^ WARN implicit autoref } +unsafe fn slice_ptr_len_because_of_msrv(slice: *const [T]) { + let _ = (*slice)[..].len(); + //~^ WARN implicit autoref + //~^^ WARN implicit autoref +} + fn main() {} diff --git a/tests/ui/lint/implicit_autorefs.stderr b/tests/ui/lint/implicit_autorefs.stderr index 6dd1ac65ada98..29279a268eb42 100644 --- a/tests/ui/lint/implicit_autorefs.stderr +++ b/tests/ui/lint/implicit_autorefs.stderr @@ -2,9 +2,16 @@ warning: implicit autoref creates a reference to the dereference of a raw pointe --> $DIR/implicit_autorefs.rs:10:13 | LL | let _ = (*ptr)[..16]; - | ^^^^^^^^^^^^ + | ^^---^^^^^^^ + | | + | this raw pointer has type `*const [u8]` | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +note: autoref is being applied to this expression, resulting in: `&[u8]` + --> $DIR/implicit_autorefs.rs:10:13 + | +LL | let _ = (*ptr)[..16]; + | ^^^^^^ = note: `#[warn(dangerous_implicit_autorefs)]` on by default help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | @@ -15,9 +22,18 @@ warning: implicit autoref creates a reference to the dereference of a raw pointe --> $DIR/implicit_autorefs.rs:19:13 | LL | let l = (*ptr).field.len(); - | ^^^^^^^^^^^^^^^^^^ + | ^^---^^^^^^^^^^^^^ + | | + | this raw pointer has type `*const Test` | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +note: autoref is being applied to this expression, resulting in: `&[u8]` + --> $DIR/implicit_autorefs.rs:19:13 + | +LL | let l = (*ptr).field.len(); + | ^^^^^^^^^^^^ +note: method calls to `len` require a reference + --> $SRC_DIR/core/src/slice/mod.rs:LL:COL help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | let l = (&(*ptr).field).len(); @@ -27,9 +43,16 @@ warning: implicit autoref creates a reference to the dereference of a raw pointe --> $DIR/implicit_autorefs.rs:22:16 | LL | &raw const (*ptr).field[..l - 1] - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^---^^^^^^^^^^^^^^^^ + | | + | this raw pointer has type `*const Test` | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +note: autoref is being applied to this expression, resulting in: `&[u8]` + --> $DIR/implicit_autorefs.rs:22:16 + | +LL | &raw const (*ptr).field[..l - 1] + | ^^^^^^^^^^^^ help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | &raw const (&(*ptr).field)[..l - 1] @@ -39,9 +62,18 @@ warning: implicit autoref creates a reference to the dereference of a raw pointe --> $DIR/implicit_autorefs.rs:27:9 | LL | _ = (*a)[0].len(); - | ^^^^^^^^^^^^^ + | ^^-^^^^^^^^^^ + | | + | this raw pointer has type `*mut [String]` | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +note: autoref is being applied to this expression, resulting in: `&String` + --> $DIR/implicit_autorefs.rs:27:9 + | +LL | _ = (*a)[0].len(); + | ^^^^^^^ +note: method calls to `len` require a reference + --> $SRC_DIR/alloc/src/string.rs:LL:COL help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | _ = (&(*a)[0]).len(); @@ -51,9 +83,18 @@ warning: implicit autoref creates a reference to the dereference of a raw pointe --> $DIR/implicit_autorefs.rs:30:9 | LL | _ = (*a)[..1][0].len(); - | ^^^^^^^^^^^^^^^^^^ + | ^^-^^^^^^^^^^^^^^^ + | | + | this raw pointer has type `*mut [String]` | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +note: autoref is being applied to this expression, resulting in: `&String` + --> $DIR/implicit_autorefs.rs:30:9 + | +LL | _ = (*a)[..1][0].len(); + | ^^^^^^^^^^^^ +note: method calls to `len` require a reference + --> $SRC_DIR/alloc/src/string.rs:LL:COL help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | _ = (&(*a)[..1][0]).len(); @@ -63,9 +104,16 @@ warning: implicit autoref creates a reference to the dereference of a raw pointe --> $DIR/implicit_autorefs.rs:30:9 | LL | _ = (*a)[..1][0].len(); - | ^^^^^^^^^ + | ^^-^^^^^^ + | | + | this raw pointer has type `*mut [String]` | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +note: autoref is being applied to this expression, resulting in: `&[String]` + --> $DIR/implicit_autorefs.rs:30:9 + | +LL | _ = (*a)[..1][0].len(); + | ^^^^ help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | _ = (&(*a))[..1][0].len(); @@ -75,9 +123,17 @@ warning: implicit autoref creates a reference to the dereference of a raw pointe --> $DIR/implicit_autorefs.rs:36:13 | LL | let _ = (*ptr).field; - | ^^^^^^^^^^^^ + | ^^---^^^^^^^ + | | + | this raw pointer has type `*const ManuallyDrop` | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +note: autoref is being applied to this expression, resulting in: `Test` + --> $DIR/implicit_autorefs.rs:36:13 + | +LL | let _ = (*ptr).field; + | ^^^^^^ + = note: reference(s) created through call(s) to overloaded `Deref(Mut)::deref(_mut)` implementation help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | let _ = (&(*ptr)).field; @@ -87,9 +143,17 @@ warning: implicit autoref creates a reference to the dereference of a raw pointe --> $DIR/implicit_autorefs.rs:38:24 | LL | let _ = &raw const (*ptr).field; - | ^^^^^^^^^^^^ + | ^^---^^^^^^^ + | | + | this raw pointer has type `*const ManuallyDrop` | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +note: autoref is being applied to this expression, resulting in: `Test` + --> $DIR/implicit_autorefs.rs:38:24 + | +LL | let _ = &raw const (*ptr).field; + | ^^^^^^ + = note: reference(s) created through call(s) to overloaded `Deref(Mut)::deref(_mut)` implementation help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | let _ = &raw const (&(*ptr)).field; @@ -99,9 +163,17 @@ warning: implicit autoref creates a reference to the dereference of a raw pointe --> $DIR/implicit_autorefs.rs:43:13 | LL | let _ = (*ptr).field; - | ^^^^^^^^^^^^ + | ^^---^^^^^^^ + | | + | this raw pointer has type `*mut ManuallyDrop` | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +note: autoref is being applied to this expression, resulting in: `Test` + --> $DIR/implicit_autorefs.rs:43:13 + | +LL | let _ = (*ptr).field; + | ^^^^^^ + = note: reference(s) created through call(s) to overloaded `Deref(Mut)::deref(_mut)` implementation help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | let _ = (&(*ptr)).field; @@ -111,9 +183,17 @@ warning: implicit autoref creates a reference to the dereference of a raw pointe --> $DIR/implicit_autorefs.rs:48:13 | LL | let _ = (*ptr).field; - | ^^^^^^^^^^^^ + | ^^---^^^^^^^ + | | + | this raw pointer has type `*const ManuallyDrop>` | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +note: autoref is being applied to this expression, resulting in: `Test` + --> $DIR/implicit_autorefs.rs:48:13 + | +LL | let _ = (*ptr).field; + | ^^^^^^ + = note: reference(s) created through call(s) to overloaded `Deref(Mut)::deref(_mut)` implementation help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | let _ = (&(*ptr)).field; @@ -123,9 +203,16 @@ warning: implicit autoref creates a reference to the dereference of a raw pointe --> $DIR/implicit_autorefs.rs:62:26 | LL | let _p: *const i32 = &raw const **w; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^- + | | + | this raw pointer has type `*const W` | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +note: autoref is being applied to this expression, resulting in: `&W` + --> $DIR/implicit_autorefs.rs:62:38 + | +LL | let _p: *const i32 = &raw const **w; + | ^^ help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | let _p: *const i32 = &raw const *(&**w); @@ -135,9 +222,18 @@ warning: implicit autoref creates a reference to the dereference of a raw pointe --> $DIR/implicit_autorefs.rs:72:14 | LL | unsafe { (*ptr).field.len() } - | ^^^^^^^^^^^^^^^^^^ + | ^^---^^^^^^^^^^^^^ + | | + | this raw pointer has type `*const Test2` | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +note: autoref is being applied to this expression, resulting in: `&[u8]` + --> $DIR/implicit_autorefs.rs:72:14 + | +LL | unsafe { (*ptr).field.len() } + | ^^^^^^^^^^^^ +note: method calls to `len` require a reference + --> $SRC_DIR/core/src/slice/mod.rs:LL:COL help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | unsafe { (&(*ptr).field).len() } @@ -147,9 +243,18 @@ warning: implicit autoref creates a reference to the dereference of a raw pointe --> $DIR/implicit_autorefs.rs:82:13 | LL | let _ = (*ptr).get(0); - | ^^^^^^^^^^^^^ + | ^^---^^^^^^^^ + | | + | this raw pointer has type `*mut Vec` | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +note: autoref is being applied to this expression, resulting in: `&[u8]` + --> $DIR/implicit_autorefs.rs:82:13 + | +LL | let _ = (*ptr).get(0); + | ^^^^^^ +note: method calls to `get` require a reference + --> $SRC_DIR/core/src/slice/mod.rs:LL:COL help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | let _ = (&(*ptr)).get(0); @@ -159,9 +264,18 @@ warning: implicit autoref creates a reference to the dereference of a raw pointe --> $DIR/implicit_autorefs.rs:84:13 | LL | let _ = (*ptr).get_unchecked(0); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^---^^^^^^^^^^^^^^^^^^ + | | + | this raw pointer has type `*mut Vec` | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +note: autoref is being applied to this expression, resulting in: `&[u8]` + --> $DIR/implicit_autorefs.rs:84:13 + | +LL | let _ = (*ptr).get_unchecked(0); + | ^^^^^^ +note: method calls to `get_unchecked` require a reference + --> $SRC_DIR/core/src/slice/mod.rs:LL:COL help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | let _ = (&(*ptr)).get_unchecked(0); @@ -171,9 +285,18 @@ warning: implicit autoref creates a reference to the dereference of a raw pointe --> $DIR/implicit_autorefs.rs:86:13 | LL | let _ = (*ptr).get_mut(0); - | ^^^^^^^^^^^^^^^^^ + | ^^---^^^^^^^^^^^^ + | | + | this raw pointer has type `*mut Vec` | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +note: autoref is being applied to this expression, resulting in: `&mut [u8]` + --> $DIR/implicit_autorefs.rs:86:13 + | +LL | let _ = (*ptr).get_mut(0); + | ^^^^^^ +note: method calls to `get_mut` require a reference + --> $SRC_DIR/core/src/slice/mod.rs:LL:COL help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | let _ = (&mut (*ptr)).get_mut(0); @@ -183,9 +306,18 @@ warning: implicit autoref creates a reference to the dereference of a raw pointe --> $DIR/implicit_autorefs.rs:88:13 | LL | let _ = (*ptr).get_unchecked_mut(0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^---^^^^^^^^^^^^^^^^^^^^^^ + | | + | this raw pointer has type `*mut Vec` | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +note: autoref is being applied to this expression, resulting in: `&mut [u8]` + --> $DIR/implicit_autorefs.rs:88:13 + | +LL | let _ = (*ptr).get_unchecked_mut(0); + | ^^^^^^ +note: method calls to `get_unchecked_mut` require a reference + --> $SRC_DIR/core/src/slice/mod.rs:LL:COL help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | let _ = (&mut (*ptr)).get_unchecked_mut(0); @@ -195,9 +327,18 @@ warning: implicit autoref creates a reference to the dereference of a raw pointe --> $DIR/implicit_autorefs.rs:93:13 | LL | let _ = (*ptr).len(); - | ^^^^^^^^^^^^ + | ^^---^^^^^^^ + | | + | this raw pointer has type `*mut String` | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +note: autoref is being applied to this expression, resulting in: `&String` + --> $DIR/implicit_autorefs.rs:93:13 + | +LL | let _ = (*ptr).len(); + | ^^^^^^ +note: method calls to `len` require a reference + --> $SRC_DIR/alloc/src/string.rs:LL:COL help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | let _ = (&(*ptr)).len(); @@ -207,13 +348,62 @@ warning: implicit autoref creates a reference to the dereference of a raw pointe --> $DIR/implicit_autorefs.rs:95:13 | LL | let _ = (*ptr).is_empty(); - | ^^^^^^^^^^^^^^^^^ + | ^^---^^^^^^^^^^^^ + | | + | this raw pointer has type `*mut String` | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +note: autoref is being applied to this expression, resulting in: `&String` + --> $DIR/implicit_autorefs.rs:95:13 + | +LL | let _ = (*ptr).is_empty(); + | ^^^^^^ +note: method calls to `is_empty` require a reference + --> $SRC_DIR/alloc/src/string.rs:LL:COL help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | let _ = (&(*ptr)).is_empty(); | ++ + -warning: 18 warnings emitted +warning: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:100:13 + | +LL | let _ = (*slice)[..].len(); + | ^^-----^^^^^^^^^^^ + | | + | this raw pointer has type `*const [T]` + | + = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +note: autoref is being applied to this expression, resulting in: `&[T]` + --> $DIR/implicit_autorefs.rs:100:13 + | +LL | let _ = (*slice)[..].len(); + | ^^^^^^^^^^^^ +note: method calls to `len` require a reference + --> $SRC_DIR/core/src/slice/mod.rs:LL:COL +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | let _ = (&(*slice)[..]).len(); + | ++ + + +warning: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:100:13 + | +LL | let _ = (*slice)[..].len(); + | ^^-----^^^^^ + | | + | this raw pointer has type `*const [T]` + | + = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +note: autoref is being applied to this expression, resulting in: `&[T]` + --> $DIR/implicit_autorefs.rs:100:13 + | +LL | let _ = (*slice)[..].len(); + | ^^^^^^^^ +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | let _ = (&(*slice))[..].len(); + | ++ + + +warning: 20 warnings emitted From e0b6363974c7894d61addc96e677166173a01e5f Mon Sep 17 00:00:00 2001 From: Federico Terzi Date: Wed, 14 May 2025 19:00:56 +0200 Subject: [PATCH 2273/4206] wire up startupinfo methods --- library/std/src/os/windows/process.rs | 36 ++++++++++++++++++++++++++ library/std/src/sys/process/windows.rs | 36 ++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs index a084f452e55d0..c223eee95b5f5 100644 --- a/library/std/src/os/windows/process.rs +++ b/library/std/src/os/windows/process.rs @@ -344,6 +344,27 @@ pub trait CommandExt: Sealed { &mut self, attribute_list: &ProcThreadAttributeList<'_>, ) -> io::Result; + + /// When true, sets the `STARTF_RUNFULLSCREEN` flag on the [STARTUPINFO][1] struct before passing it to `CreateProcess`. + /// + /// [1]: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa + #[unstable(feature = "windows_process_extensions_startupinfo", issue = "141010")] + fn startupinfo_fullscreen(&mut self, enabled: bool) -> &mut process::Command; + + /// When true, sets the `STARTF_UNTRUSTEDSOURCE` flag on the [STARTUPINFO][1] struct before passing it to `CreateProcess`. + /// + /// [1]: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa + #[unstable(feature = "windows_process_extensions_startupinfo", issue = "141010")] + fn startupinfo_untrusted_source(&mut self, enabled: bool) -> &mut process::Command; + + /// When specified, sets the following flags on the [STARTUPINFO][1] struct before passing it to `CreateProcess`: + /// - If `Some(true)`, sets `STARTF_FORCEONFEEDBACK` + /// - If `Some(false)`, sets `STARTF_FORCEOFFFEEDBACK` + /// - If `None`, does not set any flags + /// + /// [1]: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa + #[unstable(feature = "windows_process_extensions_startupinfo", issue = "141010")] + fn startupinfo_force_feedback(&mut self, enabled: Option) -> &mut process::Command; } #[stable(feature = "windows_process_extensions", since = "1.16.0")] @@ -385,6 +406,21 @@ impl CommandExt for process::Command { .spawn_with_attributes(sys::process::Stdio::Inherit, true, Some(attribute_list)) .map(process::Child::from_inner) } + + fn startupinfo_fullscreen(&mut self, enabled: bool) -> &mut process::Command { + self.as_inner_mut().startupinfo_fullscreen(enabled); + self + } + + fn startupinfo_untrusted_source(&mut self, enabled: bool) -> &mut process::Command { + self.as_inner_mut().startupinfo_untrusted_source(enabled); + self + } + + fn startupinfo_force_feedback(&mut self, enabled: Option) -> &mut process::Command { + self.as_inner_mut().startupinfo_force_feedback(enabled); + self + } } #[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")] diff --git a/library/std/src/sys/process/windows.rs b/library/std/src/sys/process/windows.rs index 4acd753eec915..1ee3fbd285f52 100644 --- a/library/std/src/sys/process/windows.rs +++ b/library/std/src/sys/process/windows.rs @@ -155,6 +155,9 @@ pub struct Command { stdout: Option, stderr: Option, force_quotes_enabled: bool, + startupinfo_fullscreen: bool, + startupinfo_untrusted_source: bool, + startupinfo_force_feedback: Option, } pub enum Stdio { @@ -186,6 +189,9 @@ impl Command { stdout: None, stderr: None, force_quotes_enabled: false, + startupinfo_fullscreen: false, + startupinfo_untrusted_source: false, + startupinfo_force_feedback: None, } } @@ -222,6 +228,18 @@ impl Command { self.args.push(Arg::Raw(command_str_to_append.to_os_string())) } + pub fn startupinfo_fullscreen(&mut self, enabled: bool) { + self.startupinfo_fullscreen = enabled; + } + + pub fn startupinfo_untrusted_source(&mut self, enabled: bool) { + self.startupinfo_untrusted_source = enabled; + } + + pub fn startupinfo_force_feedback(&mut self, enabled: Option) { + self.startupinfo_force_feedback = enabled; + } + pub fn get_program(&self) -> &OsStr { &self.program } @@ -343,6 +361,24 @@ impl Command { si.wShowWindow = cmd_show; } + if self.startupinfo_fullscreen { + si.dwFlags |= c::STARTF_RUNFULLSCREEN; + } + + if self.startupinfo_untrusted_source { + si.dwFlags |= c::STARTF_UNTRUSTEDSOURCE; + } + + match self.startupinfo_force_feedback { + Some(true) => { + si.dwFlags |= c::STARTF_FORCEONFEEDBACK; + } + Some(false) => { + si.dwFlags |= c::STARTF_FORCEOFFFEEDBACK; + } + None => {} + } + let si_ptr: *mut c::STARTUPINFOW; let mut si_ex; From 0d25090d262cd506d4c4809f3a534d4d8b318870 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 2 May 2025 17:32:48 +0200 Subject: [PATCH 2274/4206] Improve code and apply suggestions --- clippy_lints/src/useless_concat.rs | 29 +++++------- clippy_utils/src/paths.rs | 2 +- tests/ui/useless_concat.fixed | 21 +++++++++ tests/ui/useless_concat.rs | 23 +++++++++- tests/ui/useless_concat.stderr | 74 +++++++++++++++++++++++++++--- 5 files changed, 123 insertions(+), 26 deletions(-) diff --git a/clippy_lints/src/useless_concat.rs b/clippy_lints/src/useless_concat.rs index 4a818532f177a..1ed1fbb3b9c69 100644 --- a/clippy_lints/src/useless_concat.rs +++ b/clippy_lints/src/useless_concat.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::macro_backtrace; use clippy_utils::paths::CONCAT; use clippy_utils::source::snippet_opt; -use clippy_utils::{match_def_path, tokenize_with_text}; +use clippy_utils::tokenize_with_text; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; @@ -25,7 +25,7 @@ declare_clippy_lint! { /// ```no_run /// let x = "a"; /// ``` - #[clippy::version = "1.85.0"] + #[clippy::version = "1.89.0"] pub USELESS_CONCAT, complexity, "checks that the `concat` macro has at least two arguments" @@ -39,11 +39,11 @@ impl LateLintPass<'_> for UselessConcat { if expr.span.from_expansion() // Check that it's a string literal. && let ExprKind::Lit(lit) = expr.kind - && let LitKind::Str(_, _) = lit.node + && let LitKind::Str(lit_s, _) = lit.node // Get the direct parent of the expression. && let Some(macro_call) = macro_backtrace(expr.span).next() // Check if the `concat` macro from the `core` library. - && match_def_path(cx, macro_call.def_id, &CONCAT) + && CONCAT.matches(cx, macro_call.def_id) // We get the original code to parse it. && let Some(original_code) = snippet_opt(cx, macro_call.span) // This check allows us to ensure that the code snippet: @@ -68,7 +68,13 @@ impl LateLintPass<'_> for UselessConcat { } literal = Some(token_s); }, - TokenKind::Ident => nb_idents += 1, + TokenKind::Ident => { + if token_s == "true" || token_s == "false" { + literal = Some(token_s); + } else { + nb_idents += 1; + } + }, TokenKind::Comma => { nb_commas += 1; if nb_commas > 1 { @@ -81,17 +87,6 @@ impl LateLintPass<'_> for UselessConcat { _ => {}, } } - let literal = match literal { - Some(lit) => { - // Literals can also be number, so we need to check this case too. - if lit.starts_with('"') { - lit.to_string() - } else { - format!("\"{lit}\"") - } - }, - None => "\"\"".to_string(), - }; // There should always be the ident of the `concat` macro. if nb_idents == 1 { span_lint_and_sugg( @@ -100,7 +95,7 @@ impl LateLintPass<'_> for UselessConcat { macro_call.span, "unneeded use of `concat!` macro", "replace with", - literal, + format!("{lit_s:?}"), Applicability::MachineApplicable, ); } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 9c909033447d0..9d7f3086b05fa 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -129,7 +129,7 @@ path_macros! { // Paths in `core`/`alloc`/`std`. This should be avoided and cleaned up by adding diagnostic items. pub static ALIGN_OF: PathLookup = value_path!(core::mem::align_of); pub static CHAR_TO_DIGIT: PathLookup = value_path!(char::to_digit); -pub static CONCAT: PathLookup = value_path!(core::macros::builtin::concat); +pub static CONCAT: PathLookup = macro_path!(core::concat); pub static IO_ERROR_NEW: PathLookup = value_path!(std::io::Error::new); pub static IO_ERRORKIND_OTHER_CTOR: PathLookup = value_path!(std::io::ErrorKind::Other); pub static ITER_STEP: PathLookup = type_path!(core::iter::Step); diff --git a/tests/ui/useless_concat.fixed b/tests/ui/useless_concat.fixed index 0400b1fcd6db9..360b6f6ce82ee 100644 --- a/tests/ui/useless_concat.fixed +++ b/tests/ui/useless_concat.fixed @@ -1,6 +1,11 @@ +//@aux-build:proc_macros.rs + #![warn(clippy::useless_concat)] #![allow(clippy::print_literal)] +extern crate proc_macros; +use proc_macros::{external, with_span}; + macro_rules! my_concat { ($fmt:literal $(, $e:expr)*) => { println!(concat!("ERROR: ", $fmt), $($e,)*); @@ -9,6 +14,16 @@ macro_rules! my_concat { fn main() { let x = ""; //~ useless_concat + let x = "c"; //~ useless_concat + let x = "\""; //~ useless_concat + let x = "true"; //~ useless_concat + let x = "1"; //~ useless_concat + let x = "1.0000"; //~ useless_concat + let x = "1"; //~ useless_concat + let x = "1"; //~ useless_concat + let x = "1.0000"; //~ useless_concat + let x = "1.0000"; //~ useless_concat + let x = "a😀\n"; //~ useless_concat let x = "a"; //~ useless_concat let x = "1"; //~ useless_concat println!("b: {}", "a"); //~ useless_concat @@ -17,4 +32,10 @@ fn main() { let local_i32 = 1; my_concat!("{}", local_i32); let x = concat!(file!(), "#L", line!()); + + external! { concat!(); } + with_span! { + span + concat!(); + } } diff --git a/tests/ui/useless_concat.rs b/tests/ui/useless_concat.rs index 02e68568c103b..338d20a48ae96 100644 --- a/tests/ui/useless_concat.rs +++ b/tests/ui/useless_concat.rs @@ -1,6 +1,11 @@ +//@aux-build:proc_macros.rs + #![warn(clippy::useless_concat)] #![allow(clippy::print_literal)] +extern crate proc_macros; +use proc_macros::{external, with_span}; + macro_rules! my_concat { ($fmt:literal $(, $e:expr)*) => { println!(concat!("ERROR: ", $fmt), $($e,)*); @@ -9,7 +14,17 @@ macro_rules! my_concat { fn main() { let x = concat!(); //~ useless_concat - let x = concat!("a"); //~ useless_concat + let x = concat!('c'); //~ useless_concat + let x = concat!('"'); //~ useless_concat + let x = concat!(true); //~ useless_concat + let x = concat!(1f32); //~ useless_concat + let x = concat!(1.0000f32); //~ useless_concat + let x = concat!(1_f32); //~ useless_concat + let x = concat!(1_); //~ useless_concat + let x = concat!(1.0000_f32); //~ useless_concat + let x = concat!(1.0000_); //~ useless_concat + let x = concat!("a\u{1f600}\n"); //~ useless_concat + let x = concat!(r##"a"##); //~ useless_concat let x = concat!(1); //~ useless_concat println!("b: {}", concat!("a")); //~ useless_concat // Should not lint. @@ -17,4 +32,10 @@ fn main() { let local_i32 = 1; my_concat!("{}", local_i32); let x = concat!(file!(), "#L", line!()); + + external! { concat!(); } + with_span! { + span + concat!(); + } } diff --git a/tests/ui/useless_concat.stderr b/tests/ui/useless_concat.stderr index 63038b6660b12..43d6d9ff5799d 100644 --- a/tests/ui/useless_concat.stderr +++ b/tests/ui/useless_concat.stderr @@ -1,5 +1,5 @@ error: unneeded use of `concat!` macro - --> tests/ui/useless_concat.rs:11:13 + --> tests/ui/useless_concat.rs:16:13 | LL | let x = concat!(); | ^^^^^^^^^ help: replace with: `""` @@ -8,22 +8,82 @@ LL | let x = concat!(); = help: to override `-D warnings` add `#[allow(clippy::useless_concat)]` error: unneeded use of `concat!` macro - --> tests/ui/useless_concat.rs:12:13 + --> tests/ui/useless_concat.rs:17:13 | -LL | let x = concat!("a"); - | ^^^^^^^^^^^^ help: replace with: `"a"` +LL | let x = concat!('c'); + | ^^^^^^^^^^^^ help: replace with: `"c"` error: unneeded use of `concat!` macro - --> tests/ui/useless_concat.rs:13:13 + --> tests/ui/useless_concat.rs:18:13 + | +LL | let x = concat!('"'); + | ^^^^^^^^^^^^ help: replace with: `"\""` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:19:13 + | +LL | let x = concat!(true); + | ^^^^^^^^^^^^^ help: replace with: `"true"` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:20:13 + | +LL | let x = concat!(1f32); + | ^^^^^^^^^^^^^ help: replace with: `"1"` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:21:13 + | +LL | let x = concat!(1.0000f32); + | ^^^^^^^^^^^^^^^^^^ help: replace with: `"1.0000"` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:22:13 + | +LL | let x = concat!(1_f32); + | ^^^^^^^^^^^^^^ help: replace with: `"1"` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:23:13 + | +LL | let x = concat!(1_); + | ^^^^^^^^^^^ help: replace with: `"1"` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:24:13 + | +LL | let x = concat!(1.0000_f32); + | ^^^^^^^^^^^^^^^^^^^ help: replace with: `"1.0000"` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:25:13 + | +LL | let x = concat!(1.0000_); + | ^^^^^^^^^^^^^^^^ help: replace with: `"1.0000"` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:26:13 + | +LL | let x = concat!("a\u{1f600}\n"); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `"a😀\n"` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:27:13 + | +LL | let x = concat!(r##"a"##); + | ^^^^^^^^^^^^^^^^^ help: replace with: `"a"` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:28:13 | LL | let x = concat!(1); | ^^^^^^^^^^ help: replace with: `"1"` error: unneeded use of `concat!` macro - --> tests/ui/useless_concat.rs:14:23 + --> tests/ui/useless_concat.rs:29:23 | LL | println!("b: {}", concat!("a")); | ^^^^^^^^^^^^ help: replace with: `"a"` -error: aborting due to 4 previous errors +error: aborting due to 14 previous errors From de51196bb183ff6bb7ebfdb3bc8093876d5078b8 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 14 May 2025 21:38:40 +0300 Subject: [PATCH 2275/4206] Don't allow duplicate crates in the all_crates list For some reason we had them in some projects, I'm not sure why. But this caused cache priming to appear stuck - because it uses a set of crate IDs for the actual work, but for the number of crates to index it just uses `db.all_crates().len()`. --- src/tools/rust-analyzer/Cargo.lock | 1 + .../rust-analyzer/crates/base-db/Cargo.toml | 1 + .../rust-analyzer/crates/base-db/src/input.rs | 18 ++++++++++++------ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 8d6c8284e44ef..b35a67c661759 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -80,6 +80,7 @@ version = "0.0.0" dependencies = [ "cfg", "dashmap", + "indexmap", "intern", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "query-group-macro", diff --git a/src/tools/rust-analyzer/crates/base-db/Cargo.toml b/src/tools/rust-analyzer/crates/base-db/Cargo.toml index e2e3253773fe3..3b423a86f97af 100644 --- a/src/tools/rust-analyzer/crates/base-db/Cargo.toml +++ b/src/tools/rust-analyzer/crates/base-db/Cargo.toml @@ -21,6 +21,7 @@ rustc-hash.workspace = true triomphe.workspace = true semver.workspace = true tracing.workspace = true +indexmap.workspace = true # local deps cfg.workspace = true diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs index 9660e6e87cca8..d42d7e5707d34 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/input.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs @@ -14,7 +14,7 @@ use dashmap::DashMap; use dashmap::mapref::entry::Entry; use intern::Symbol; use la_arena::{Arena, Idx, RawIdx}; -use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; +use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet, FxHasher}; use salsa::{Durability, Setter}; use span::Edition; use triomphe::Arc; @@ -24,6 +24,8 @@ use crate::{CrateWorkspaceData, EditionedFileId, RootQueryDb}; pub type ProcMacroPaths = FxHashMap>; +type FxIndexSet = indexmap::IndexSet; + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct SourceRootId(pub u32); @@ -474,7 +476,9 @@ impl CrateGraphBuilder { } pub fn set_in_db(self, db: &mut dyn RootQueryDb) -> CratesIdMap { - let mut all_crates = Vec::with_capacity(self.arena.len()); + // For some reason in some repositories we have duplicate crates, so we use a set and not `Vec`. + // We use an `IndexSet` because the list needs to be topologically sorted. + let mut all_crates = FxIndexSet::with_capacity_and_hasher(self.arena.len(), FxBuildHasher); let mut visited = FxHashMap::default(); let mut visited_root_files = FxHashSet::default(); @@ -494,9 +498,11 @@ impl CrateGraphBuilder { ); } - if **old_all_crates != *all_crates { + if old_all_crates.len() != all_crates.len() + || old_all_crates.iter().any(|&krate| !all_crates.contains(&krate)) + { db.set_all_crates_with_durability( - Arc::new(all_crates.into_boxed_slice()), + Arc::new(Vec::from_iter(all_crates).into_boxed_slice()), Durability::MEDIUM, ); } @@ -509,7 +515,7 @@ impl CrateGraphBuilder { crates_map: &CratesMap, visited: &mut FxHashMap, visited_root_files: &mut FxHashSet, - all_crates: &mut Vec, + all_crates: &mut FxIndexSet, source: CrateBuilderId, ) -> Crate { if let Some(&crate_id) = visited.get(&source) { @@ -597,7 +603,7 @@ impl CrateGraphBuilder { input } }; - all_crates.push(crate_input); + all_crates.insert(crate_input); visited.insert(source, crate_input); crate_input } From 4ec219393a48eff84c8c08b854d50a454b8f422c Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Wed, 14 May 2025 23:17:56 +0200 Subject: [PATCH 2276/4206] Fix size computation when element is a slice In this case, a dereference is needed before using `mem::size_of_val()`. --- clippy_lints/src/manual_slice_size_calculation.rs | 6 +++++- tests/ui/manual_slice_size_calculation.fixed | 13 +++++++++++++ tests/ui/manual_slice_size_calculation.rs | 13 +++++++++++++ tests/ui/manual_slice_size_calculation.stderr | 8 +++++++- 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/manual_slice_size_calculation.rs b/clippy_lints/src/manual_slice_size_calculation.rs index 2dad0fa4925e7..b6a4f44b0e490 100644 --- a/clippy_lints/src/manual_slice_size_calculation.rs +++ b/clippy_lints/src/manual_slice_size_calculation.rs @@ -49,7 +49,11 @@ impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation { { let ctxt = expr.span.ctxt(); let mut app = Applicability::MachineApplicable; - let deref = "*".repeat(refs_count - 1); + let deref = if refs_count > 0 { + "*".repeat(refs_count - 1) + } else { + "&".into() + }; let val_name = snippet_with_context(cx, receiver.span, ctxt, "slice", &mut app).0; let Some(sugg) = std_or_core(cx) else { return }; diff --git a/tests/ui/manual_slice_size_calculation.fixed b/tests/ui/manual_slice_size_calculation.fixed index 294d1e1506dec..9df5a2ac5cd59 100644 --- a/tests/ui/manual_slice_size_calculation.fixed +++ b/tests/ui/manual_slice_size_calculation.fixed @@ -64,3 +64,16 @@ const fn _const(s_i32: &[i32]) { // True negative: let _ = s_i32.len() * size_of::(); // Ok, can't use size_of_val in const } + +fn issue_14802() { + struct IcedSlice { + dst: [u8], + } + + impl IcedSlice { + fn get_len(&self) -> usize { + std::mem::size_of_val(&self.dst) + //~^ manual_slice_size_calculation + } + } +} diff --git a/tests/ui/manual_slice_size_calculation.rs b/tests/ui/manual_slice_size_calculation.rs index ae5225663139b..db14d891c80b8 100644 --- a/tests/ui/manual_slice_size_calculation.rs +++ b/tests/ui/manual_slice_size_calculation.rs @@ -64,3 +64,16 @@ const fn _const(s_i32: &[i32]) { // True negative: let _ = s_i32.len() * size_of::(); // Ok, can't use size_of_val in const } + +fn issue_14802() { + struct IcedSlice { + dst: [u8], + } + + impl IcedSlice { + fn get_len(&self) -> usize { + self.dst.len() * size_of::() + //~^ manual_slice_size_calculation + } + } +} diff --git a/tests/ui/manual_slice_size_calculation.stderr b/tests/ui/manual_slice_size_calculation.stderr index f07e97a1c8638..00eb32b3e1c3a 100644 --- a/tests/ui/manual_slice_size_calculation.stderr +++ b/tests/ui/manual_slice_size_calculation.stderr @@ -55,5 +55,11 @@ error: manual slice size calculation LL | let _ = external!(&[1u64][..]).len() * size_of::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(external!(&[1u64][..]))` -error: aborting due to 9 previous errors +error: manual slice size calculation + --> tests/ui/manual_slice_size_calculation.rs:75:13 + | +LL | self.dst.len() * size_of::() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(&self.dst)` + +error: aborting due to 10 previous errors From fe4b4e832941b554b802b5ea2bbbe95806c093fe Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Wed, 14 May 2025 23:29:17 +0200 Subject: [PATCH 2277/4206] `mem::size_of_val` is const-stable since Rust 1.85 --- book/src/lint_configuration.md | 1 + clippy_config/src/conf.rs | 1 + clippy_lints/src/lib.rs | 2 +- .../src/manual_slice_size_calculation.rs | 19 +++++++++++++++---- clippy_utils/src/msrvs.rs | 2 +- tests/ui/manual_slice_size_calculation.fixed | 12 +++++++++--- tests/ui/manual_slice_size_calculation.rs | 12 +++++++++--- tests/ui/manual_slice_size_calculation.stderr | 10 ++++++++-- 8 files changed, 45 insertions(+), 14 deletions(-) diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 0db4182dbcdbd..9809e32de8a44 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -836,6 +836,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`manual_repeat_n`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_repeat_n) * [`manual_retain`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain) * [`manual_slice_fill`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_slice_fill) +* [`manual_slice_size_calculation`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_slice_size_calculation) * [`manual_split_once`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once) * [`manual_str_repeat`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat) * [`manual_strip`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip) diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index ad0aea39d41a2..4ce8d001c2f00 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -739,6 +739,7 @@ define_Conf! { manual_repeat_n, manual_retain, manual_slice_fill, + manual_slice_size_calculation, manual_split_once, manual_str_repeat, manual_strip, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 006145cc623c3..ec5227018cea4 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -866,7 +866,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| Box::new(unnecessary_box_returns::UnnecessaryBoxReturns::new(conf))); store.register_late_pass(move |_| Box::new(lines_filter_map_ok::LinesFilterMapOk::new(conf))); store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule)); - store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation)); + store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation::new(conf))); store.register_early_pass(move || Box::new(excessive_nesting::ExcessiveNesting::new(conf))); store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule)); store.register_early_pass(|| Box::new(ref_patterns::RefPatterns)); diff --git a/clippy_lints/src/manual_slice_size_calculation.rs b/clippy_lints/src/manual_slice_size_calculation.rs index b6a4f44b0e490..0c09a47c96518 100644 --- a/clippy_lints/src/manual_slice_size_calculation.rs +++ b/clippy_lints/src/manual_slice_size_calculation.rs @@ -1,11 +1,13 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use clippy_utils::{expr_or_init, is_in_const_context, std_or_core}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { @@ -36,16 +38,25 @@ declare_clippy_lint! { complexity, "manual slice size calculation" } -declare_lint_pass!(ManualSliceSizeCalculation => [MANUAL_SLICE_SIZE_CALCULATION]); +impl_lint_pass!(ManualSliceSizeCalculation => [MANUAL_SLICE_SIZE_CALCULATION]); + +pub struct ManualSliceSizeCalculation { + msrv: Msrv, +} + +impl ManualSliceSizeCalculation { + pub fn new(conf: &Conf) -> Self { + Self { msrv: conf.msrv } + } +} impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let ExprKind::Binary(ref op, left, right) = expr.kind && BinOpKind::Mul == op.node && !expr.span.from_expansion() - // Does not apply inside const because size_of_val is not cost in stable. - && !is_in_const_context(cx) && let Some((receiver, refs_count)) = simplify(cx, left, right) + && (!is_in_const_context(cx) || self.msrv.meets(cx, msrvs::CONST_SIZE_OF_VAL)) { let ctxt = expr.span.ctxt(); let mut app = Applicability::MachineApplicable; diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 223a8649eb3c6..ec3de2b9dc8d7 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -24,7 +24,7 @@ macro_rules! msrv_aliases { msrv_aliases! { 1,88,0 { LET_CHAINS } 1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT } - 1,85,0 { UINT_FLOAT_MIDPOINT } + 1,85,0 { UINT_FLOAT_MIDPOINT, CONST_SIZE_OF_VAL } 1,84,0 { CONST_OPTION_AS_SLICE, MANUAL_DANGLING_PTR } 1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP } 1,82,0 { IS_NONE_OR, REPEAT_N, RAW_REF_OP } diff --git a/tests/ui/manual_slice_size_calculation.fixed b/tests/ui/manual_slice_size_calculation.fixed index 9df5a2ac5cd59..090f0fd30c555 100644 --- a/tests/ui/manual_slice_size_calculation.fixed +++ b/tests/ui/manual_slice_size_calculation.fixed @@ -60,9 +60,15 @@ fn main() { let _ = size_of::() * 5 * s_i32.len(); // Ok (MISSED OPPORTUNITY) } -const fn _const(s_i32: &[i32]) { - // True negative: - let _ = s_i32.len() * size_of::(); // Ok, can't use size_of_val in const +#[clippy::msrv = "1.85"] +const fn const_ok(s_i32: &[i32]) { + let _ = std::mem::size_of_val(s_i32); + //~^ manual_slice_size_calculation +} + +#[clippy::msrv = "1.84"] +const fn const_before_msrv(s_i32: &[i32]) { + let _ = s_i32.len() * size_of::(); } fn issue_14802() { diff --git a/tests/ui/manual_slice_size_calculation.rs b/tests/ui/manual_slice_size_calculation.rs index db14d891c80b8..3c19a0eb5cea1 100644 --- a/tests/ui/manual_slice_size_calculation.rs +++ b/tests/ui/manual_slice_size_calculation.rs @@ -60,9 +60,15 @@ fn main() { let _ = size_of::() * 5 * s_i32.len(); // Ok (MISSED OPPORTUNITY) } -const fn _const(s_i32: &[i32]) { - // True negative: - let _ = s_i32.len() * size_of::(); // Ok, can't use size_of_val in const +#[clippy::msrv = "1.85"] +const fn const_ok(s_i32: &[i32]) { + let _ = s_i32.len() * size_of::(); + //~^ manual_slice_size_calculation +} + +#[clippy::msrv = "1.84"] +const fn const_before_msrv(s_i32: &[i32]) { + let _ = s_i32.len() * size_of::(); } fn issue_14802() { diff --git a/tests/ui/manual_slice_size_calculation.stderr b/tests/ui/manual_slice_size_calculation.stderr index 00eb32b3e1c3a..8e9b49e4bf295 100644 --- a/tests/ui/manual_slice_size_calculation.stderr +++ b/tests/ui/manual_slice_size_calculation.stderr @@ -56,10 +56,16 @@ LL | let _ = external!(&[1u64][..]).len() * size_of::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(external!(&[1u64][..]))` error: manual slice size calculation - --> tests/ui/manual_slice_size_calculation.rs:75:13 + --> tests/ui/manual_slice_size_calculation.rs:65:13 + | +LL | let _ = s_i32.len() * size_of::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` + +error: manual slice size calculation + --> tests/ui/manual_slice_size_calculation.rs:81:13 | LL | self.dst.len() * size_of::() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(&self.dst)` -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors From 9b3abe79d73d476d317a7a06fea5a11e5dd34950 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 14 May 2025 23:44:24 +0200 Subject: [PATCH 2278/4206] Use more subdiagnostics and reword the overloaded deref note --- compiler/rustc_lint/messages.ftl | 2 +- compiler/rustc_lint/src/autorefs.rs | 29 +++++++++++++++-------- compiler/rustc_lint/src/lints.rs | 32 +++++++++++++++++++------- tests/ui/lint/implicit_autorefs.stderr | 28 ++++------------------ 4 files changed, 49 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index baa017f3084a5..08180bf8f8b2c 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -364,7 +364,7 @@ lint_implicit_unsafe_autorefs = implicit autoref creates a reference to the dere .note = creating a reference requires the pointer target to be valid and imposes aliasing requirements .raw_ptr = this raw pointer has type `{$raw_ptr_ty}` .autoref = autoref is being applied to this expression, resulting in: `{$autoref_ty}` - .through_overloaded_deref = reference(s) created through call(s) to overloaded `Deref(Mut)::deref(_mut)` implementation + .overloaded_deref = references are created through calls to explicit `Deref(Mut)::deref(_mut)` implementations .method_def = method calls to `{$method_name}` require a reference .suggestion = try using a raw pointer method instead; or if this reference is intentional, make it explicit diff --git a/compiler/rustc_lint/src/autorefs.rs b/compiler/rustc_lint/src/autorefs.rs index 9bb235263625d..5de2cbf9939db 100644 --- a/compiler/rustc_lint/src/autorefs.rs +++ b/compiler/rustc_lint/src/autorefs.rs @@ -2,9 +2,12 @@ use rustc_ast::{BorrowKind, UnOp}; use rustc_hir::{Expr, ExprKind, Mutability}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref}; use rustc_session::{declare_lint, declare_lint_pass}; -use rustc_span::{kw, sym}; +use rustc_span::sym; -use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion}; +use crate::lints::{ + ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsMethodNote, ImplicitUnsafeAutorefsOrigin, + ImplicitUnsafeAutorefsSuggestion, +}; use crate::{LateContext, LateLintPass, LintContext}; declare_lint! { @@ -98,8 +101,8 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs { peel_place_mappers(inner).kind // 1. Deref of a raw pointer. && typeck.expr_ty(dereferenced).is_raw_ptr() - // PERF: 5. b. A method call annotated with `#[rustc_no_implicit_refs]` && let method_did = match expr.kind { + // PERF: 5. b. A method call annotated with `#[rustc_no_implicit_refs]` ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id), _ => None, } @@ -111,11 +114,18 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs { ImplicitUnsafeAutorefsDiag { raw_ptr_span: dereferenced.span, raw_ptr_ty: typeck.expr_ty(dereferenced), - autoref_span: inner.span, - autoref_ty: typeck.expr_ty_adjusted(inner), - method_def_span: method_did.map(|did| cx.tcx.def_span(did)), - method_name: method_did.map(|did| cx.tcx.item_name(did)).unwrap_or(kw::Empty), - through_overloaded_deref, + origin: if through_overloaded_deref { + ImplicitUnsafeAutorefsOrigin::OverloadedDeref + } else { + ImplicitUnsafeAutorefsOrigin::Autoref { + autoref_span: inner.span, + autoref_ty: typeck.expr_ty_adjusted(inner), + } + }, + method: method_did.map(|did| ImplicitUnsafeAutorefsMethodNote { + def_span: cx.tcx.def_span(did), + method_name: cx.tcx.item_name(did), + }), suggestion: ImplicitUnsafeAutorefsSuggestion { mutbl: borrow_mutbl.ref_prefix_str(), deref: if is_coming_from_deref { "*" } else { "" }, @@ -151,7 +161,8 @@ fn peel_derefs_adjustments<'a>(mut adjs: &'a [Adjustment<'a>]) -> &'a [Adjustmen /// Test if some adjustment has some implicit borrow. /// -/// Returns `Some(mutability)` if the argument adjustment has implicit borrow in it. +/// Returns `Some((mutability, was_an_overloaded_deref))` if the argument adjustment is +/// an implicit borrow (or has an implicit borrow via an overloaded deref). fn has_implicit_borrow(Adjustment { kind, .. }: &Adjustment<'_>) -> Option<(Mutability, bool)> { match kind { &Adjust::Deref(Some(OverloadedDeref { mutbl, .. })) => Some((mutbl, true)), diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 978bb6d08d5ae..7268a7f704fcb 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -63,18 +63,34 @@ pub(crate) struct ImplicitUnsafeAutorefsDiag<'a> { #[label(lint_raw_ptr)] pub raw_ptr_span: Span, pub raw_ptr_ty: Ty<'a>, - #[note(lint_autoref)] - pub autoref_span: Span, - pub autoref_ty: Ty<'a>, - #[note(lint_method_def)] - pub method_def_span: Option, - pub method_name: Symbol, - #[note(lint_through_overloaded_deref)] - pub through_overloaded_deref: bool, + #[subdiagnostic] + pub origin: ImplicitUnsafeAutorefsOrigin<'a>, + #[subdiagnostic] + pub method: Option, #[subdiagnostic] pub suggestion: ImplicitUnsafeAutorefsSuggestion, } +#[derive(Subdiagnostic)] +pub(crate) enum ImplicitUnsafeAutorefsOrigin<'a> { + #[note(lint_autoref)] + Autoref { + #[primary_span] + autoref_span: Span, + autoref_ty: Ty<'a>, + }, + #[note(lint_overloaded_deref)] + OverloadedDeref, +} + +#[derive(Subdiagnostic)] +#[note(lint_method_def)] +pub(crate) struct ImplicitUnsafeAutorefsMethodNote { + #[primary_span] + pub def_span: Span, + pub method_name: Symbol, +} + #[derive(Subdiagnostic)] #[multipart_suggestion(lint_suggestion, applicability = "maybe-incorrect")] pub(crate) struct ImplicitUnsafeAutorefsSuggestion { diff --git a/tests/ui/lint/implicit_autorefs.stderr b/tests/ui/lint/implicit_autorefs.stderr index 29279a268eb42..80ba8ae2fd277 100644 --- a/tests/ui/lint/implicit_autorefs.stderr +++ b/tests/ui/lint/implicit_autorefs.stderr @@ -128,12 +128,7 @@ LL | let _ = (*ptr).field; | this raw pointer has type `*const ManuallyDrop` | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements -note: autoref is being applied to this expression, resulting in: `Test` - --> $DIR/implicit_autorefs.rs:36:13 - | -LL | let _ = (*ptr).field; - | ^^^^^^ - = note: reference(s) created through call(s) to overloaded `Deref(Mut)::deref(_mut)` implementation + = note: references are created through calls to explicit `Deref(Mut)::deref(_mut)` implementations help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | let _ = (&(*ptr)).field; @@ -148,12 +143,7 @@ LL | let _ = &raw const (*ptr).field; | this raw pointer has type `*const ManuallyDrop` | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements -note: autoref is being applied to this expression, resulting in: `Test` - --> $DIR/implicit_autorefs.rs:38:24 - | -LL | let _ = &raw const (*ptr).field; - | ^^^^^^ - = note: reference(s) created through call(s) to overloaded `Deref(Mut)::deref(_mut)` implementation + = note: references are created through calls to explicit `Deref(Mut)::deref(_mut)` implementations help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | let _ = &raw const (&(*ptr)).field; @@ -168,12 +158,7 @@ LL | let _ = (*ptr).field; | this raw pointer has type `*mut ManuallyDrop` | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements -note: autoref is being applied to this expression, resulting in: `Test` - --> $DIR/implicit_autorefs.rs:43:13 - | -LL | let _ = (*ptr).field; - | ^^^^^^ - = note: reference(s) created through call(s) to overloaded `Deref(Mut)::deref(_mut)` implementation + = note: references are created through calls to explicit `Deref(Mut)::deref(_mut)` implementations help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | let _ = (&(*ptr)).field; @@ -188,12 +173,7 @@ LL | let _ = (*ptr).field; | this raw pointer has type `*const ManuallyDrop>` | = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements -note: autoref is being applied to this expression, resulting in: `Test` - --> $DIR/implicit_autorefs.rs:48:13 - | -LL | let _ = (*ptr).field; - | ^^^^^^ - = note: reference(s) created through call(s) to overloaded `Deref(Mut)::deref(_mut)` implementation + = note: references are created through calls to explicit `Deref(Mut)::deref(_mut)` implementations help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | let _ = (&(*ptr)).field; From 8f0522dc811b7132c3bd2b2bc5c134a869824cf3 Mon Sep 17 00:00:00 2001 From: teor Date: Mon, 12 May 2025 18:49:36 +1000 Subject: [PATCH 2279/4206] Fix confusing WTF surrogate safety docs --- library/std/src/ffi/os_str.rs | 6 +++--- library/std/src/sys/os_str/wtf8.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 72bdf03ee61a4..7f0033c196213 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -594,9 +594,9 @@ impl OsString { /// The slice must be valid for the platform encoding (as described in /// [`OsStr::from_encoded_bytes_unchecked`]). /// - /// This bypasses the encoding-dependent surrogate joining, so `self` must - /// not end with a leading surrogate half and `other` must not start with - /// with a trailing surrogate half. + /// This bypasses the encoding-dependent surrogate joining, so either + /// `self` must not end with a leading surrogate half, or `other` must not + /// start with a trailing surrogate half. #[inline] pub(crate) unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) { // SAFETY: Guaranteed by caller. diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs index 5174ea65d0cd9..892bd2e3de659 100644 --- a/library/std/src/sys/os_str/wtf8.rs +++ b/library/std/src/sys/os_str/wtf8.rs @@ -215,9 +215,9 @@ impl Buf { /// The slice must be valid for the platform encoding (as described in /// [`Slice::from_encoded_bytes_unchecked`]). /// - /// This bypasses the WTF-8 surrogate joining, so `self` must not end with a - /// leading surrogate half and `other` must not start with with a trailing - /// surrogate half. + /// This bypasses the WTF-8 surrogate joining, so either `self` must not + /// end with a leading surrogate half, or `other` must not start with a + /// trailing surrogate half. #[inline] pub unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) { self.inner.extend_from_slice(other); From 57af157ce28b21b1b049346df62da72d5ee150fc Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 14 May 2025 18:26:06 -0700 Subject: [PATCH 2280/4206] Update std doctests for android This updates some doctests that fail to run on android. We will soon be supporting cross-compiled doctests, and the `arm-android` job fails to run these tests. In summary: - Android re-exports some traits from linux under a different path. - Android doesn't seem to have common unix utilities like `true`, `false`, or `whoami`, so these are disabled. --- library/std/src/os/net/linux_ext/addr.rs | 6 ++++++ library/std/src/os/net/linux_ext/socket.rs | 3 +++ library/std/src/os/net/linux_ext/tcp.rs | 6 ++++++ library/std/src/process.rs | 12 ++++++------ 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/library/std/src/os/net/linux_ext/addr.rs b/library/std/src/os/net/linux_ext/addr.rs index aed772056e1b3..41009c0e28457 100644 --- a/library/std/src/os/net/linux_ext/addr.rs +++ b/library/std/src/os/net/linux_ext/addr.rs @@ -23,7 +23,10 @@ pub trait SocketAddrExt: Sealed { /// /// ```no_run /// use std::os::unix::net::{UnixListener, SocketAddr}; + /// #[cfg(target_os = "linux")] /// use std::os::linux::net::SocketAddrExt; + /// #[cfg(target_os = "android")] + /// use std::os::android::net::SocketAddrExt; /// /// fn main() -> std::io::Result<()> { /// let addr = SocketAddr::from_abstract_name(b"hidden")?; @@ -48,7 +51,10 @@ pub trait SocketAddrExt: Sealed { /// /// ```no_run /// use std::os::unix::net::{UnixListener, SocketAddr}; + /// #[cfg(target_os = "linux")] /// use std::os::linux::net::SocketAddrExt; + /// #[cfg(target_os = "android")] + /// use std::os::android::net::SocketAddrExt; /// /// fn main() -> std::io::Result<()> { /// let name = b"hidden"; diff --git a/library/std/src/os/net/linux_ext/socket.rs b/library/std/src/os/net/linux_ext/socket.rs index 4e4168f693c34..a15feb6bd9f28 100644 --- a/library/std/src/os/net/linux_ext/socket.rs +++ b/library/std/src/os/net/linux_ext/socket.rs @@ -27,7 +27,10 @@ pub trait UnixSocketExt: Sealed { /// /// ```no_run /// #![feature(unix_socket_ancillary_data)] + /// #[cfg(target_os = "linux")] /// use std::os::linux::net::UnixSocketExt; + /// #[cfg(target_os = "android")] + /// use std::os::android::net::UnixSocketExt; /// use std::os::unix::net::UnixDatagram; /// /// fn main() -> std::io::Result<()> { diff --git a/library/std/src/os/net/linux_ext/tcp.rs b/library/std/src/os/net/linux_ext/tcp.rs index c8d012962d45a..95dffb3bc4347 100644 --- a/library/std/src/os/net/linux_ext/tcp.rs +++ b/library/std/src/os/net/linux_ext/tcp.rs @@ -25,7 +25,10 @@ pub trait TcpStreamExt: Sealed { /// ```no_run /// #![feature(tcp_quickack)] /// use std::net::TcpStream; + /// #[cfg(target_os = "linux")] /// use std::os::linux::net::TcpStreamExt; + /// #[cfg(target_os = "android")] + /// use std::os::android::net::TcpStreamExt; /// /// let stream = TcpStream::connect("127.0.0.1:8080") /// .expect("Couldn't connect to the server..."); @@ -43,7 +46,10 @@ pub trait TcpStreamExt: Sealed { /// ```no_run /// #![feature(tcp_quickack)] /// use std::net::TcpStream; + /// #[cfg(target_os = "linux")] /// use std::os::linux::net::TcpStreamExt; + /// #[cfg(target_os = "android")] + /// use std::os::android::net::TcpStreamExt; /// /// let stream = TcpStream::connect("127.0.0.1:8080") /// .expect("Couldn't connect to the server..."); diff --git a/library/std/src/process.rs b/library/std/src/process.rs index df6b9a6e563ce..9ef135049d09c 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1348,7 +1348,7 @@ impl Output { /// /// ``` /// #![feature(exit_status_error)] - /// # #[cfg(unix)] { + /// # #[cfg(all(unix, not(target_os = "android")))] { /// use std::process::Command; /// assert!(Command::new("false").output().unwrap().exit_ok().is_err()); /// # } @@ -1695,7 +1695,7 @@ impl From for Stdio { /// # Ok(()) /// # } /// # - /// # if cfg!(unix) { + /// # if cfg!(all(unix, not(target_os = "android"))) { /// # test().unwrap(); /// # } /// ``` @@ -1724,7 +1724,7 @@ impl From for Stdio { /// # Ok(()) /// # } /// # - /// # if cfg!(unix) { + /// # if cfg!(all(unix, not(target_os = "android"))) { /// # test().unwrap(); /// # } /// ``` @@ -1907,7 +1907,7 @@ impl crate::sealed::Sealed for ExitStatusError {} /// /// ``` /// #![feature(exit_status_error)] -/// # if cfg!(unix) { +/// # if cfg!(all(unix, not(target_os = "android"))) { /// use std::process::{Command, ExitStatusError}; /// /// fn run(cmd: &str) -> Result<(), ExitStatusError> { @@ -1950,7 +1950,7 @@ impl ExitStatusError { /// /// ``` /// #![feature(exit_status_error)] - /// # #[cfg(unix)] { + /// # #[cfg(all(unix, not(target_os = "android")))] { /// use std::process::Command; /// /// let bad = Command::new("false").status().unwrap().exit_ok().unwrap_err(); @@ -1975,7 +1975,7 @@ impl ExitStatusError { /// ``` /// #![feature(exit_status_error)] /// - /// # if cfg!(unix) { + /// # if cfg!(all(unix, not(target_os = "android"))) { /// use std::num::NonZero; /// use std::process::Command; /// From f6e95a5b23d99081765ff746e18c34c8aaec7b68 Mon Sep 17 00:00:00 2001 From: relaxcn Date: Thu, 15 May 2025 01:10:25 +0800 Subject: [PATCH 2281/4206] Fix false positive of `useless_conversion` when using `into_iter()` --- clippy_lints/src/useless_conversion.rs | 29 +++++++++++++++++++++++++- tests/ui/useless_conversion.fixed | 15 +++++++++++++ tests/ui/useless_conversion.rs | 15 +++++++++++++ tests/ui/useless_conversion.stderr | 14 ++++++++++++- 4 files changed, 71 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 3a9c997a579d1..c04fcf622b909 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -7,7 +7,7 @@ use clippy_utils::{ }; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; -use rustc_hir::{BindingMode, Expr, ExprKind, HirId, MatchSource, Node, PatKind}; +use rustc_hir::{BindingMode, Expr, ExprKind, HirId, MatchSource, Mutability, Node, PatKind}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::Obligation; use rustc_lint::{LateContext, LateLintPass}; @@ -298,6 +298,33 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { // implements Copy, in which case .into_iter() returns a copy of the receiver and // cannot be safely omitted. if same_type_and_consts(a, b) && !is_copy(cx, b) { + // Below we check if the parent method call meets the following conditions: + // 1. First parameter is `&mut self` (requires mutable reference) + // 2. Second parameter implements the `FnMut` trait (e.g., Iterator::any) + // For methods satisfying these conditions (like any), .into_iter() must be preserved. + if let Some(parent) = get_parent_expr(cx, e) + && let ExprKind::MethodCall(_, recv, _, _) = parent.kind + && recv.hir_id == e.hir_id + && let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id) + && let sig = cx.tcx.fn_sig(def_id).skip_binder().skip_binder() + && let inputs = sig.inputs() + && inputs.len() >= 2 + && let Some(self_ty) = inputs.first() + && let ty::Ref(_, _, Mutability::Mut) = self_ty.kind() + && let Some(second_ty) = inputs.get(1) + && let predicates = cx.tcx.param_env(def_id).caller_bounds() + && predicates.iter().any(|pred| { + if let ty::ClauseKind::Trait(trait_pred) = pred.kind().skip_binder() { + trait_pred.self_ty() == *second_ty + && cx.tcx.lang_items().fn_mut_trait() == Some(trait_pred.def_id()) + } else { + false + } + }) + { + return; + } + let sugg = snippet(cx, recv.span, "").into_owned(); span_lint_and_sugg( cx, diff --git a/tests/ui/useless_conversion.fixed b/tests/ui/useless_conversion.fixed index 489caacf21235..ad30c94f34781 100644 --- a/tests/ui/useless_conversion.fixed +++ b/tests/ui/useless_conversion.fixed @@ -427,3 +427,18 @@ mod issue11819 { } } } + +fn issue14739() { + use std::ops::Range; + + const R: Range = 2..7; + + R.into_iter().all(|_x| true); // no lint + + R.into_iter().any(|_x| true); // no lint + + R.for_each(|_x| {}); + //~^ useless_conversion + let _ = R.map(|_x| 0); + //~^ useless_conversion +} diff --git a/tests/ui/useless_conversion.rs b/tests/ui/useless_conversion.rs index 4f3a3b00ea206..505afb340009a 100644 --- a/tests/ui/useless_conversion.rs +++ b/tests/ui/useless_conversion.rs @@ -427,3 +427,18 @@ mod issue11819 { } } } + +fn issue14739() { + use std::ops::Range; + + const R: Range = 2..7; + + R.into_iter().all(|_x| true); // no lint + + R.into_iter().any(|_x| true); // no lint + + R.into_iter().for_each(|_x| {}); + //~^ useless_conversion + let _ = R.into_iter().map(|_x| 0); + //~^ useless_conversion +} diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr index 3cde2a786e466..3bfaf1411c2c6 100644 --- a/tests/ui/useless_conversion.stderr +++ b/tests/ui/useless_conversion.stderr @@ -377,5 +377,17 @@ LL - takes_into_iter(self.my_field.into_iter()); LL + takes_into_iter(&mut *self.my_field); | -error: aborting due to 41 previous errors +error: useless conversion to the same type: `std::ops::Range` + --> tests/ui/useless_conversion.rs:440:5 + | +LL | R.into_iter().for_each(|_x| {}); + | ^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `R` + +error: useless conversion to the same type: `std::ops::Range` + --> tests/ui/useless_conversion.rs:442:13 + | +LL | let _ = R.into_iter().map(|_x| 0); + | ^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `R` + +error: aborting due to 43 previous errors From 6a35b51860ecf1b9ecbbe6d02579dcd53291e006 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Wed, 14 May 2025 23:02:32 +0800 Subject: [PATCH 2282/4206] fix: ide-assists, generate mut trait impl indent --- .../src/handlers/generate_mut_trait_impl.rs | 94 ++++++++++++++++++- 1 file changed, 91 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs index 2ac960ed7e183..bab2ccf3f3373 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs @@ -1,7 +1,7 @@ use ide_db::famous_defs::FamousDefs; use syntax::{ AstNode, - ast::{self, make}, + ast::{self, edit_in_place::Indent, make}, ted, }; @@ -46,6 +46,7 @@ use crate::{AssistContext, AssistId, Assists}; // ``` pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let impl_def = ctx.find_node_at_offset::()?.clone_for_update(); + let indent = impl_def.indent_level(); let trait_ = impl_def.trait_()?; if let ast::Type::PathType(trait_path) = trait_ { @@ -97,8 +98,8 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_> })?; let assoc_list = make::assoc_item_list().clone_for_update(); - assoc_list.add_item(syntax::ast::AssocItem::Fn(fn_)); ted::replace(impl_def.assoc_item_list()?.syntax(), assoc_list.syntax()); + impl_def.get_or_create_assoc_item_list().add_item(syntax::ast::AssocItem::Fn(fn_)); let target = impl_def.syntax().text_range(); acc.add( @@ -106,7 +107,7 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_> "Generate `IndexMut` impl from this `Index` trait", target, |edit| { - edit.insert(target.start(), format!("$0{impl_def}\n\n")); + edit.insert(target.start(), format!("$0{impl_def}\n\n{indent}")); }, ) } @@ -189,6 +190,93 @@ impl core::ops::Index for [T; 3] where T: Copy { ); } + #[test] + fn test_generate_mut_trait_impl_non_zero_indent() { + check_assist( + generate_mut_trait_impl, + r#" +//- minicore: index +mod foo { + pub enum Axis { X = 0, Y = 1, Z = 2 } + + impl core::ops::Index$0 for [T; 3] where T: Copy { + type Output = T; + + fn index(&self, index: Axis) -> &Self::Output { + let var_name = &self[index as usize]; + var_name + } + } +} +"#, + r#" +mod foo { + pub enum Axis { X = 0, Y = 1, Z = 2 } + + $0impl core::ops::IndexMut for [T; 3] where T: Copy { + fn index_mut(&mut self, index: Axis) -> &mut Self::Output { + let var_name = &self[index as usize]; + var_name + } + } + + impl core::ops::Index for [T; 3] where T: Copy { + type Output = T; + + fn index(&self, index: Axis) -> &Self::Output { + let var_name = &self[index as usize]; + var_name + } + } +} +"#, + ); + + check_assist( + generate_mut_trait_impl, + r#" +//- minicore: index +mod foo { + mod bar { + pub enum Axis { X = 0, Y = 1, Z = 2 } + + impl core::ops::Index$0 for [T; 3] where T: Copy { + type Output = T; + + fn index(&self, index: Axis) -> &Self::Output { + let var_name = &self[index as usize]; + var_name + } + } + } +} +"#, + r#" +mod foo { + mod bar { + pub enum Axis { X = 0, Y = 1, Z = 2 } + + $0impl core::ops::IndexMut for [T; 3] where T: Copy { + fn index_mut(&mut self, index: Axis) -> &mut Self::Output { + let var_name = &self[index as usize]; + var_name + } + } + + impl core::ops::Index for [T; 3] where T: Copy { + type Output = T; + + fn index(&self, index: Axis) -> &Self::Output { + let var_name = &self[index as usize]; + var_name + } + } + } +} +"#, + ); + } + #[test] fn test_generate_mut_trait_impl_not_applicable() { check_assist_not_applicable( From 5adbda4ee5d3013cf9e9a9479268fc8e17d24c40 Mon Sep 17 00:00:00 2001 From: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com> Date: Thu, 15 May 2025 13:18:30 +0900 Subject: [PATCH 2283/4206] rename fn name take_path to any Signed-off-by: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com> --- src/tools/rust-analyzer/crates/hir/src/semantics.rs | 2 +- src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs | 6 +++--- .../ide-assists/src/handlers/remove_unused_imports.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 7ee72614e2206..caa6700de9f94 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -118,7 +118,7 @@ impl PathResolutionPerNs { ) -> Self { PathResolutionPerNs { type_ns, value_ns, macro_ns } } - pub fn take_path(&self) -> Option { + pub fn any(&self) -> Option { self.type_ns.or(self.value_ns).or(self.macro_ns) } } diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 610770d0f31e3..ea21546f9d764 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -1163,7 +1163,7 @@ impl<'db> SourceAnalyzer<'db> { Some(&store), false, ) - .take_path()?; + .any()?; let subst = (|| { let parent = parent()?; let ty = if let Some(expr) = ast::Expr::cast(parent.clone()) { @@ -1556,7 +1556,7 @@ pub(crate) fn resolve_hir_path( hygiene: HygieneId, store: Option<&ExpressionStore>, ) -> Option { - resolve_hir_path_(db, resolver, path, false, hygiene, store, false).take_path() + resolve_hir_path_(db, resolver, path, false, hygiene, store, false).any() } #[inline] @@ -1677,7 +1677,7 @@ fn resolve_hir_path_( .unwrap_or_else(|| PathResolutionPerNs::new(None, values(), None)) }; - if res.take_path().is_some() { + if res.any().is_some() { res } else if let Some(type_ns) = items() { PathResolutionPerNs::new(Some(type_ns), None, None) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs index fb96882ed428e..dff9a660cf598 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs @@ -81,7 +81,7 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>) // Get the actual definition associated with this use item. let res = match ctx.sema.resolve_path_per_ns(&path) { - Some(x) if x.take_path().is_some() => x, + Some(x) if x.any().is_some() => x, Some(_) | None => { return None; } From 2c55a78848cebf3bede3339362bbfcbc6c18fa8c Mon Sep 17 00:00:00 2001 From: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com> Date: Thu, 15 May 2025 14:01:05 +0900 Subject: [PATCH 2284/4206] check glob Signed-off-by: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com> --- .../src/handlers/remove_unused_imports.rs | 43 ++++++++++--------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs index dff9a660cf598..994e7c446cc53 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs @@ -86,28 +86,29 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>) return None; } }; - match res { - PathResolutionPerNs { type_ns: Some(type_ns), .. } if u.star_token().is_some() => { - // Check if any of the children of this module are used - let def_mod = match type_ns { - PathResolution::Def(ModuleDef::Module(module)) => module, - _ => return None, - }; - - if !def_mod - .scope(ctx.db(), Some(use_module)) - .iter() - .filter_map(|(_, x)| match x { - hir::ScopeDef::ModuleDef(d) => Some(Definition::from(*d)), - _ => None, - }) - .any(|d| used_once_in_scope(ctx, d, u.rename(), scope)) - { - Some(u) - } else { - None - } + + if u.star_token().is_some() { + // Check if any of the children of this module are used + let def_mod = match res.type_ns { + Some(PathResolution::Def(ModuleDef::Module(module))) => module, + _ => return None, + }; + + if !def_mod + .scope(ctx.db(), Some(use_module)) + .iter() + .filter_map(|(_, x)| match x { + hir::ScopeDef::ModuleDef(d) => Some(Definition::from(*d)), + _ => None, + }) + .any(|d| used_once_in_scope(ctx, d, u.rename(), scope)) + { + return Some(u); + } else { + return None; } + } + match res { PathResolutionPerNs { type_ns: Some(PathResolution::Def(ModuleDef::Trait(ref t))), value_ns, From 034d2a2fe778d0effe9532775f08a5652159b207 Mon Sep 17 00:00:00 2001 From: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com> Date: Thu, 15 May 2025 15:12:31 +0900 Subject: [PATCH 2285/4206] handle trait in function Signed-off-by: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com> --- .../src/handlers/remove_unused_imports.rs | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs index 994e7c446cc53..16debc4d72858 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs @@ -103,29 +103,12 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>) }) .any(|d| used_once_in_scope(ctx, d, u.rename(), scope)) { - return Some(u); + Some(u) } else { - return None; - } - } - match res { - PathResolutionPerNs { - type_ns: Some(PathResolution::Def(ModuleDef::Trait(ref t))), - value_ns, - macro_ns, - } => { - // If the trait or any item is used. - if is_trait_unused_in_scope(ctx, &u, scope, t) { - let path = [value_ns, macro_ns]; - is_path_unused_in_scope(ctx, &u, scope, &path).then_some(u) - } else { - None - } - } - PathResolutionPerNs { type_ns, value_ns, macro_ns } => { - let path = [type_ns, value_ns, macro_ns]; - is_path_unused_in_scope(ctx, &u, scope, &path).then_some(u) + None } + } else { + is_path_per_ns_unused_in_scope(ctx, &u, scope, &res).then_some(u) } }) .peekable(); @@ -148,6 +131,25 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>) } } +fn is_path_per_ns_unused_in_scope( + ctx: &AssistContext<'_>, + u: &ast::UseTree, + scope: &mut Vec, + path: &PathResolutionPerNs, +) -> bool { + if let Some(PathResolution::Def(ModuleDef::Trait(ref t))) = path.type_ns { + if is_trait_unused_in_scope(ctx, u, scope, t) { + let path = [path.value_ns, path.macro_ns]; + is_path_unused_in_scope(ctx, u, scope, &path) + } else { + false + } + } else { + let path = [path.type_ns, path.value_ns, path.macro_ns]; + is_path_unused_in_scope(ctx, u, scope, &path) + } +} + fn is_path_unused_in_scope( ctx: &AssistContext<'_>, u: &ast::UseTree, From 66fef16bb6229d61ab32decbe5285d9cf5b7f5c8 Mon Sep 17 00:00:00 2001 From: Berrysoft Date: Thu, 15 May 2025 15:14:35 +0800 Subject: [PATCH 2286/4206] Update Cargo.lock --- src/tools/rust-analyzer/Cargo.lock | 102 +++++++++++++++++++---------- 1 file changed, 67 insertions(+), 35 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 8d6c8284e44ef..6010755f8fa41 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -61,9 +61,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" -version = "0.3.74" +version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ "addr2line", "cfg-if", @@ -316,9 +316,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "ctrlc" -version = "3.4.5" +version = "3.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" +checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73" dependencies = [ "nix", "windows-sys 0.59.0", @@ -1010,9 +1010,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", "hashbrown 0.15.2", @@ -1123,12 +1123,12 @@ checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libloading" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.53.0", ] [[package]] @@ -1358,9 +1358,9 @@ dependencies = [ [[package]] name = "nix" -version = "0.29.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ "bitflags 2.9.0", "cfg-if", @@ -1640,14 +1640,14 @@ dependencies = [ [[package]] name = "process-wrap" -version = "8.2.0" +version = "8.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d35f4dc9988d1326b065b4def5e950c3ed727aa03e3151b86cc9e2aec6b03f54" +checksum = "a3ef4f2f0422f23a82ec9f628ea2acd12871c81a9362b02c43c1aa86acfc3ba1" dependencies = [ "indexmap", "nix", "tracing", - "windows 0.59.0", + "windows 0.61.1", ] [[package]] @@ -2750,12 +2750,24 @@ dependencies = [ [[package]] name = "windows" -version = "0.59.0" +version = "0.61.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f919aee0a93304be7f62e8e5027811bbba96bcb1de84d6618be56e43f8a32a1" +checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419" dependencies = [ - "windows-core 0.59.0", - "windows-targets 0.53.0", + "windows-collections", + "windows-core 0.61.0", + "windows-future", + "windows-link", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.0", ] [[package]] @@ -2773,15 +2785,25 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.59.0" +version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce" +checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" dependencies = [ - "windows-implement 0.59.0", - "windows-interface 0.59.0", - "windows-result 0.3.1", - "windows-strings 0.3.1", - "windows-targets 0.53.0", + "windows-implement 0.60.0", + "windows-interface 0.59.1", + "windows-link", + "windows-result 0.3.2", + "windows-strings 0.4.0", +] + +[[package]] +name = "windows-future" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32" +dependencies = [ + "windows-core 0.61.0", + "windows-link", ] [[package]] @@ -2797,9 +2819,9 @@ dependencies = [ [[package]] name = "windows-implement" -version = "0.59.0" +version = "0.60.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", @@ -2819,9 +2841,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.59.0" +version = "0.59.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb26fd936d991781ea39e87c3a27285081e3c0da5ca0fcbc02d368cc6f52ff01" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", @@ -2830,9 +2852,19 @@ dependencies = [ [[package]] name = "windows-link" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.0", + "windows-link", +] [[package]] name = "windows-result" @@ -2845,9 +2877,9 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06374efe858fab7e4f881500e6e86ec8bc28f9462c47e5a9941a0142ad86b189" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" dependencies = [ "windows-link", ] @@ -2864,9 +2896,9 @@ dependencies = [ [[package]] name = "windows-strings" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" dependencies = [ "windows-link", ] From f4ce73ede2f4df0f9983b337ceeed96c11f52c14 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Thu, 15 May 2025 16:32:45 +0800 Subject: [PATCH 2287/4206] Temporarily use Windows Server 2022 instead of Windows Server 2025 images At the moment, it seems like Windows Server 2025 20250504.1.0 is misconfigured causing insufficient disk space failures. Temporarily go back to Windows Server 2022 in the hope that those are not also misconfigured. --- src/ci/github-actions/jobs.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index afcc092e78e8d..88e9c71a9e318 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -35,6 +35,8 @@ runners: os: windows-2022 <<: *base-job + # FIXME(#141022): Windows Server 2025 20250504.1.0 currently experiences + # insufficient disk space. - &job-windows-25 os: windows-2025 <<: *base-job @@ -476,13 +478,17 @@ auto: env: RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-sanitizers --enable-profiler SCRIPT: make ci-msvc-py - <<: *job-windows-25 + # FIXME(#141022): Windows Server 2025 20250504.1.0 currently experiences + # insufficient disk space. + <<: *job-windows - name: x86_64-msvc-2 env: RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-sanitizers --enable-profiler SCRIPT: make ci-msvc-ps1 - <<: *job-windows-25 + # FIXME(#141022): Windows Server 2025 20250504.1.0 currently experiences + # insufficient disk space. + <<: *job-windows # i686-msvc is split into two jobs to run tests in parallel. - name: i686-msvc-1 From 3e051afec7a0223c86bdab9cd751b32f6a988465 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Wed, 14 May 2025 17:58:00 +0800 Subject: [PATCH 2288/4206] Add some negative test coverage for malformed `-Clink-self-contained` flags --- ...ontained-malformed.invalid_modifier.stderr | 2 ++ ...k-self-contained-malformed.no_value.stderr | 2 ++ .../linking/link-self-contained-malformed.rs | 23 +++++++++++++++++++ ...contained-malformed.unknown_boolean.stderr | 2 ++ ...ed-malformed.unknown_modifier_value.stderr | 2 ++ ...f-contained-malformed.unknown_value.stderr | 2 ++ 6 files changed, 33 insertions(+) create mode 100644 tests/ui/linking/link-self-contained-malformed.invalid_modifier.stderr create mode 100644 tests/ui/linking/link-self-contained-malformed.no_value.stderr create mode 100644 tests/ui/linking/link-self-contained-malformed.rs create mode 100644 tests/ui/linking/link-self-contained-malformed.unknown_boolean.stderr create mode 100644 tests/ui/linking/link-self-contained-malformed.unknown_modifier_value.stderr create mode 100644 tests/ui/linking/link-self-contained-malformed.unknown_value.stderr diff --git a/tests/ui/linking/link-self-contained-malformed.invalid_modifier.stderr b/tests/ui/linking/link-self-contained-malformed.invalid_modifier.stderr new file mode 100644 index 0000000000000..28e2c74fda229 --- /dev/null +++ b/tests/ui/linking/link-self-contained-malformed.invalid_modifier.stderr @@ -0,0 +1,2 @@ +error: incorrect value `*lld` for codegen option `link-self-contained` - one of: `y`, `yes`, `on`, `n`, `no`, `off`, or a list of enabled (`+` prefix) and disabled (`-` prefix) components: `crto`, `libc`, `unwind`, `linker`, `sanitizers`, `mingw` was expected + diff --git a/tests/ui/linking/link-self-contained-malformed.no_value.stderr b/tests/ui/linking/link-self-contained-malformed.no_value.stderr new file mode 100644 index 0000000000000..dd8e8af074bfc --- /dev/null +++ b/tests/ui/linking/link-self-contained-malformed.no_value.stderr @@ -0,0 +1,2 @@ +error: incorrect value `` for codegen option `link-self-contained` - one of: `y`, `yes`, `on`, `n`, `no`, `off`, or a list of enabled (`+` prefix) and disabled (`-` prefix) components: `crto`, `libc`, `unwind`, `linker`, `sanitizers`, `mingw` was expected + diff --git a/tests/ui/linking/link-self-contained-malformed.rs b/tests/ui/linking/link-self-contained-malformed.rs new file mode 100644 index 0000000000000..8ccb82eee2707 --- /dev/null +++ b/tests/ui/linking/link-self-contained-malformed.rs @@ -0,0 +1,23 @@ +//! Check that malformed `-Clink-self-contained` invocations are properly rejected. + +//@ revisions: no_value +//@[no_value] compile-flags: -Clink-self-contained= +//[no_value]~? ERROR incorrect value `` for codegen option `link-self-contained` + +//@ revisions: invalid_modifier +//@[invalid_modifier] compile-flags: -Clink-self-contained=*lld +//[invalid_modifier]~? ERROR incorrect value `*lld` for codegen option `link-self-contained` + +//@ revisions: unknown_value +//@[unknown_value] compile-flags: -Clink-self-contained=unknown +//[unknown_value]~? ERROR incorrect value `unknown` for codegen option `link-self-contained` + +//@ revisions: unknown_modifier_value +//@[unknown_modifier_value] compile-flags: -Clink-self-contained=-unknown +//[unknown_modifier_value]~? ERROR incorrect value `-unknown` for codegen option `link-self-contained` + +//@ revisions: unknown_boolean +//@[unknown_boolean] compile-flags: -Clink-self-contained=maybe +//[unknown_boolean]~? ERROR incorrect value `maybe` for codegen option `link-self-contained` + +fn main() {} diff --git a/tests/ui/linking/link-self-contained-malformed.unknown_boolean.stderr b/tests/ui/linking/link-self-contained-malformed.unknown_boolean.stderr new file mode 100644 index 0000000000000..7924074d1bf47 --- /dev/null +++ b/tests/ui/linking/link-self-contained-malformed.unknown_boolean.stderr @@ -0,0 +1,2 @@ +error: incorrect value `maybe` for codegen option `link-self-contained` - one of: `y`, `yes`, `on`, `n`, `no`, `off`, or a list of enabled (`+` prefix) and disabled (`-` prefix) components: `crto`, `libc`, `unwind`, `linker`, `sanitizers`, `mingw` was expected + diff --git a/tests/ui/linking/link-self-contained-malformed.unknown_modifier_value.stderr b/tests/ui/linking/link-self-contained-malformed.unknown_modifier_value.stderr new file mode 100644 index 0000000000000..2dc58c0f7e8f9 --- /dev/null +++ b/tests/ui/linking/link-self-contained-malformed.unknown_modifier_value.stderr @@ -0,0 +1,2 @@ +error: incorrect value `-unknown` for codegen option `link-self-contained` - one of: `y`, `yes`, `on`, `n`, `no`, `off`, or a list of enabled (`+` prefix) and disabled (`-` prefix) components: `crto`, `libc`, `unwind`, `linker`, `sanitizers`, `mingw` was expected + diff --git a/tests/ui/linking/link-self-contained-malformed.unknown_value.stderr b/tests/ui/linking/link-self-contained-malformed.unknown_value.stderr new file mode 100644 index 0000000000000..ce4c44299cd2e --- /dev/null +++ b/tests/ui/linking/link-self-contained-malformed.unknown_value.stderr @@ -0,0 +1,2 @@ +error: incorrect value `unknown` for codegen option `link-self-contained` - one of: `y`, `yes`, `on`, `n`, `no`, `off`, or a list of enabled (`+` prefix) and disabled (`-` prefix) components: `crto`, `libc`, `unwind`, `linker`, `sanitizers`, `mingw` was expected + From a716f1a523a3dad5e5981fef45e25d7e2100f725 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Wed, 14 May 2025 18:11:17 +0800 Subject: [PATCH 2289/4206] Add some negative test coverage for `-Zlinker-features` flag --- ...features-malformed.invalid_modifier.stderr | 2 ++ ...eatures-malformed.invalid_separator.stderr | 2 ++ .../linker-features-malformed.no_value.stderr | 2 ++ tests/ui/linking/linker-features-malformed.rs | 27 +++++++++++++++++++ ...-features-malformed.unknown_boolean.stderr | 2 ++ ...es-malformed.unknown_modifier_value.stderr | 2 ++ ...er-features-malformed.unknown_value.stderr | 2 ++ 7 files changed, 39 insertions(+) create mode 100644 tests/ui/linking/linker-features-malformed.invalid_modifier.stderr create mode 100644 tests/ui/linking/linker-features-malformed.invalid_separator.stderr create mode 100644 tests/ui/linking/linker-features-malformed.no_value.stderr create mode 100644 tests/ui/linking/linker-features-malformed.rs create mode 100644 tests/ui/linking/linker-features-malformed.unknown_boolean.stderr create mode 100644 tests/ui/linking/linker-features-malformed.unknown_modifier_value.stderr create mode 100644 tests/ui/linking/linker-features-malformed.unknown_value.stderr diff --git a/tests/ui/linking/linker-features-malformed.invalid_modifier.stderr b/tests/ui/linking/linker-features-malformed.invalid_modifier.stderr new file mode 100644 index 0000000000000..909b277089f42 --- /dev/null +++ b/tests/ui/linking/linker-features-malformed.invalid_modifier.stderr @@ -0,0 +1,2 @@ +error: incorrect value `*lld` for unstable option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected + diff --git a/tests/ui/linking/linker-features-malformed.invalid_separator.stderr b/tests/ui/linking/linker-features-malformed.invalid_separator.stderr new file mode 100644 index 0000000000000..0f84898a77422 --- /dev/null +++ b/tests/ui/linking/linker-features-malformed.invalid_separator.stderr @@ -0,0 +1,2 @@ +error: incorrect value `-lld@+lld` for unstable option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected + diff --git a/tests/ui/linking/linker-features-malformed.no_value.stderr b/tests/ui/linking/linker-features-malformed.no_value.stderr new file mode 100644 index 0000000000000..e93a4e79bb1d8 --- /dev/null +++ b/tests/ui/linking/linker-features-malformed.no_value.stderr @@ -0,0 +1,2 @@ +error: incorrect value `` for unstable option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected + diff --git a/tests/ui/linking/linker-features-malformed.rs b/tests/ui/linking/linker-features-malformed.rs new file mode 100644 index 0000000000000..0bdcfa39920f0 --- /dev/null +++ b/tests/ui/linking/linker-features-malformed.rs @@ -0,0 +1,27 @@ +//! Check that malformed `-Zlinker-features` flags are properly rejected. + +//@ revisions: no_value +//@[no_value] compile-flags: -Zlinker-features= +//[no_value]~? ERROR incorrect value `` for unstable option `linker-features` + +//@ revisions: invalid_modifier +//@[invalid_modifier] compile-flags: -Zlinker-features=*lld +//[invalid_modifier]~? ERROR incorrect value `*lld` for unstable option `linker-features` + +//@ revisions: unknown_value +//@[unknown_value] compile-flags: -Zlinker-features=unknown +//[unknown_value]~? ERROR incorrect value `unknown` for unstable option `linker-features` + +//@ revisions: unknown_modifier_value +//@[unknown_modifier_value] compile-flags: -Zlinker-features=-unknown +//[unknown_modifier_value]~? ERROR incorrect value `-unknown` for unstable option `linker-features` + +//@ revisions: unknown_boolean +//@[unknown_boolean] compile-flags: -Zlinker-features=maybe +//[unknown_boolean]~? ERROR incorrect value `maybe` for unstable option `linker-features` + +//@ revisions: invalid_separator +//@[invalid_separator] compile-flags: -Zlinker-features=-lld@+lld +//[invalid_separator]~? ERROR incorrect value `-lld@+lld` for unstable option `linker-features` + +fn main() {} diff --git a/tests/ui/linking/linker-features-malformed.unknown_boolean.stderr b/tests/ui/linking/linker-features-malformed.unknown_boolean.stderr new file mode 100644 index 0000000000000..865738d0ccc1a --- /dev/null +++ b/tests/ui/linking/linker-features-malformed.unknown_boolean.stderr @@ -0,0 +1,2 @@ +error: incorrect value `maybe` for unstable option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected + diff --git a/tests/ui/linking/linker-features-malformed.unknown_modifier_value.stderr b/tests/ui/linking/linker-features-malformed.unknown_modifier_value.stderr new file mode 100644 index 0000000000000..03b9620ca2633 --- /dev/null +++ b/tests/ui/linking/linker-features-malformed.unknown_modifier_value.stderr @@ -0,0 +1,2 @@ +error: incorrect value `-unknown` for unstable option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected + diff --git a/tests/ui/linking/linker-features-malformed.unknown_value.stderr b/tests/ui/linking/linker-features-malformed.unknown_value.stderr new file mode 100644 index 0000000000000..566632a3df381 --- /dev/null +++ b/tests/ui/linking/linker-features-malformed.unknown_value.stderr @@ -0,0 +1,2 @@ +error: incorrect value `unknown` for unstable option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected + From 55ad9cd516709b52899d01b2d7be2c4da2af3f02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Thu, 15 May 2025 08:50:01 +0000 Subject: [PATCH 2290/4206] silence unexpected lld warning on old gccs --- compiler/rustc_codegen_ssa/src/back/link.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 159c17b0af757..c5792da267819 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -768,7 +768,7 @@ fn link_natively( && cmd.get_args().iter().any(|e| e.to_string_lossy() == "-fuse-ld=lld") { info!("linker output: {:?}", out); - warn!("The linker driver does not support `-fuse-ld=lld`. Retrying without it."); + info!("The linker driver does not support `-fuse-ld=lld`. Retrying without it."); for arg in cmd.take_args() { if arg.to_string_lossy() != "-fuse-ld=lld" { cmd.arg(arg); From 734a5b1aa7888db3d86faffea1a15254022d68c9 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Thu, 15 May 2025 16:51:32 +0800 Subject: [PATCH 2291/4206] Revert "Fix linking statics on Arm64EC #140176" Unfortunately, multiple people are reporting linker warnings related to `__rust_no_alloc_shim_is_unstable` after this change. The solution isn't quite clear yet, let's revert to green for now, and try a reland with a determined solution for `__rust_no_alloc_shim_is_unstable`. This reverts commit c8b7f32434c0306db5c1b974ee43443746098a92, reversing changes made to 667247db71ea18c4130dd018d060e7f09d589490. --- compiler/rustc_codegen_llvm/src/consts.rs | 7 +- compiler/rustc_codegen_ssa/src/back/linker.rs | 120 +++++------------- .../src/back/symbol_export.rs | 11 +- compiler/rustc_codegen_ssa/src/base.rs | 47 +++---- compiler/rustc_codegen_ssa/src/lib.rs | 2 +- .../src/middle/exported_symbols.rs | 2 +- compiler/rustc_target/src/spec/base/msvc.rs | 14 +- .../arm64ec-import-export-static/export.rs | 23 ---- .../arm64ec-import-export-static/import.rs | 12 -- .../arm64ec-import-export-static/rmake.rs | 15 --- .../run-make/sanitizer-dylib-link/program.rs | 2 +- 11 files changed, 54 insertions(+), 201 deletions(-) delete mode 100644 tests/run-make/arm64ec-import-export-static/export.rs delete mode 100644 tests/run-make/arm64ec-import-export-static/import.rs delete mode 100644 tests/run-make/arm64ec-import-export-static/rmake.rs diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index cbac55c715310..bf81eb648f8ae 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -364,12 +364,7 @@ impl<'ll> CodegenCx<'ll, '_> { if !def_id.is_local() { let needs_dll_storage_attr = self.use_dll_storage_attrs - // If the symbol is a foreign item, then don't automatically apply DLLImport, as - // we'll rely on the #[link] attribute instead. BUT, if this is an internal symbol - // then it may be generated by the compiler in some crate, so we do need to apply - // DLLImport when linking with the MSVC linker. - && (!self.tcx.is_foreign_item(def_id) - || (self.sess().target.is_like_msvc && fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL))) + && !self.tcx.is_foreign_item(def_id) // Local definitions can never be imported, so we must not apply // the DLLImport annotation. && !dso_local diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 80ee8ea22288a..8fc83908efbcc 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -337,12 +337,7 @@ pub(crate) trait Linker { fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]); fn no_crt_objects(&mut self); fn no_default_libraries(&mut self); - fn export_symbols( - &mut self, - tmpdir: &Path, - crate_type: CrateType, - symbols: &[(String, SymbolExportKind)], - ); + fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]); fn subsystem(&mut self, subsystem: &str); fn linker_plugin_lto(&mut self); fn add_eh_frame_header(&mut self) {} @@ -775,12 +770,7 @@ impl<'a> Linker for GccLinker<'a> { } } - fn export_symbols( - &mut self, - tmpdir: &Path, - crate_type: CrateType, - symbols: &[(String, SymbolExportKind)], - ) { + fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) { // Symbol visibility in object files typically takes care of this. if crate_type == CrateType::Executable { let should_export_executable_symbols = @@ -809,7 +799,7 @@ impl<'a> Linker for GccLinker<'a> { // Write a plain, newline-separated list of symbols let res: io::Result<()> = try { let mut f = File::create_buffered(&path)?; - for (sym, _) in symbols { + for sym in symbols { debug!(" _{sym}"); writeln!(f, "_{sym}")?; } @@ -824,12 +814,11 @@ impl<'a> Linker for GccLinker<'a> { // .def file similar to MSVC one but without LIBRARY section // because LD doesn't like when it's empty writeln!(f, "EXPORTS")?; - for (symbol, kind) in symbols { - let kind_marker = if *kind == SymbolExportKind::Data { " DATA" } else { "" }; + for symbol in symbols { debug!(" _{symbol}"); // Quote the name in case it's reserved by linker in some way // (this accounts for names with dots in particular). - writeln!(f, " \"{symbol}\"{kind_marker}")?; + writeln!(f, " \"{symbol}\"")?; } }; if let Err(error) = res { @@ -842,7 +831,7 @@ impl<'a> Linker for GccLinker<'a> { writeln!(f, "{{")?; if !symbols.is_empty() { writeln!(f, " global:")?; - for (sym, _) in symbols { + for sym in symbols { debug!(" {sym};"); writeln!(f, " {sym};")?; } @@ -1109,12 +1098,7 @@ impl<'a> Linker for MsvcLinker<'a> { // crates. Upstream rlibs may be linked statically to this dynamic library, // in which case they may continue to transitively be used and hence need // their symbols exported. - fn export_symbols( - &mut self, - tmpdir: &Path, - crate_type: CrateType, - symbols: &[(String, SymbolExportKind)], - ) { + fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) { // Symbol visibility takes care of this typically if crate_type == CrateType::Executable { let should_export_executable_symbols = @@ -1132,10 +1116,9 @@ impl<'a> Linker for MsvcLinker<'a> { // straight to exports. writeln!(f, "LIBRARY")?; writeln!(f, "EXPORTS")?; - for (symbol, kind) in symbols { - let kind_marker = if *kind == SymbolExportKind::Data { " DATA" } else { "" }; + for symbol in symbols { debug!(" _{symbol}"); - writeln!(f, " {symbol}{kind_marker}")?; + writeln!(f, " {symbol}")?; } }; if let Err(error) = res { @@ -1276,19 +1259,14 @@ impl<'a> Linker for EmLinker<'a> { self.cc_arg("-nodefaultlibs"); } - fn export_symbols( - &mut self, - _tmpdir: &Path, - _crate_type: CrateType, - symbols: &[(String, SymbolExportKind)], - ) { + fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { debug!("EXPORTED SYMBOLS:"); self.cc_arg("-s"); let mut arg = OsString::from("EXPORTED_FUNCTIONS="); let encoded = serde_json::to_string( - &symbols.iter().map(|(sym, _)| "_".to_owned() + sym).collect::>(), + &symbols.iter().map(|sym| "_".to_owned() + sym).collect::>(), ) .unwrap(); debug!("{encoded}"); @@ -1450,13 +1428,8 @@ impl<'a> Linker for WasmLd<'a> { fn no_default_libraries(&mut self) {} - fn export_symbols( - &mut self, - _tmpdir: &Path, - _crate_type: CrateType, - symbols: &[(String, SymbolExportKind)], - ) { - for (sym, _) in symbols { + fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { + for sym in symbols { self.link_args(&["--export", sym]); } @@ -1590,7 +1563,7 @@ impl<'a> Linker for L4Bender<'a> { self.cc_arg("-nostdlib"); } - fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[(String, SymbolExportKind)]) { + fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) { // ToDo, not implemented, copy from GCC self.sess.dcx().emit_warn(errors::L4BenderExportingSymbolsUnimplemented); } @@ -1747,17 +1720,12 @@ impl<'a> Linker for AixLinker<'a> { fn no_default_libraries(&mut self) {} - fn export_symbols( - &mut self, - tmpdir: &Path, - _crate_type: CrateType, - symbols: &[(String, SymbolExportKind)], - ) { + fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { let path = tmpdir.join("list.exp"); let res: io::Result<()> = try { let mut f = File::create_buffered(&path)?; // FIXME: use llvm-nm to generate export list. - for (symbol, _) in symbols { + for symbol in symbols { debug!(" _{symbol}"); writeln!(f, " {symbol}")?; } @@ -1801,12 +1769,9 @@ fn for_each_exported_symbols_include_dep<'tcx>( } } -pub(crate) fn exported_symbols( - tcx: TyCtxt<'_>, - crate_type: CrateType, -) -> Vec<(String, SymbolExportKind)> { +pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec { if let Some(ref exports) = tcx.sess.target.override_export_symbols { - return exports.iter().map(|name| (name.to_string(), SymbolExportKind::Text)).collect(); + return exports.iter().map(ToString::to_string).collect(); } if let CrateType::ProcMacro = crate_type { @@ -1816,10 +1781,7 @@ pub(crate) fn exported_symbols( } } -fn exported_symbols_for_non_proc_macro( - tcx: TyCtxt<'_>, - crate_type: CrateType, -) -> Vec<(String, SymbolExportKind)> { +fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec { let mut symbols = Vec::new(); let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| { @@ -1827,18 +1789,17 @@ fn exported_symbols_for_non_proc_macro( // from any cdylib. The latter doesn't work anyway as we use hidden visibility for // compiler-builtins. Most linkers silently ignore it, but ld64 gives a warning. if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum) { - symbols.push(( - symbol_export::exporting_symbol_name_for_instance_in_crate(tcx, symbol, cnum), - info.kind, + symbols.push(symbol_export::exporting_symbol_name_for_instance_in_crate( + tcx, symbol, cnum, )); - symbol_export::extend_exported_symbols(&mut symbols, tcx, symbol, info, cnum); + symbol_export::extend_exported_symbols(&mut symbols, tcx, symbol, cnum); } }); symbols } -fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<(String, SymbolExportKind)> { +fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec { // `exported_symbols` will be empty when !should_codegen. if !tcx.sess.opts.output_types.should_codegen() { return Vec::new(); @@ -1848,10 +1809,7 @@ fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<(String, Symbol let proc_macro_decls_name = tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id); let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx); - vec![ - (proc_macro_decls_name, SymbolExportKind::Text), - (metadata_symbol_name, SymbolExportKind::Text), - ] + vec![proc_macro_decls_name, metadata_symbol_name] } pub(crate) fn linked_symbols( @@ -1873,9 +1831,7 @@ pub(crate) fn linked_symbols( || info.used { symbols.push(( - symbol_export::linking_symbol_name_for_instance_in_crate( - tcx, symbol, info.kind, cnum, - ), + symbol_export::linking_symbol_name_for_instance_in_crate(tcx, symbol, cnum), info.kind, )); } @@ -1950,13 +1906,7 @@ impl<'a> Linker for PtxLinker<'a> { fn ehcont_guard(&mut self) {} - fn export_symbols( - &mut self, - _tmpdir: &Path, - _crate_type: CrateType, - _symbols: &[(String, SymbolExportKind)], - ) { - } + fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, _symbols: &[String]) {} fn subsystem(&mut self, _subsystem: &str) {} @@ -2025,15 +1975,10 @@ impl<'a> Linker for LlbcLinker<'a> { fn ehcont_guard(&mut self) {} - fn export_symbols( - &mut self, - _tmpdir: &Path, - _crate_type: CrateType, - symbols: &[(String, SymbolExportKind)], - ) { + fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { match _crate_type { CrateType::Cdylib => { - for (sym, _) in symbols { + for sym in symbols { self.link_args(&["--export-symbol", sym]); } } @@ -2107,16 +2052,11 @@ impl<'a> Linker for BpfLinker<'a> { fn ehcont_guard(&mut self) {} - fn export_symbols( - &mut self, - tmpdir: &Path, - _crate_type: CrateType, - symbols: &[(String, SymbolExportKind)], - ) { + fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { let path = tmpdir.join("symbols"); let res: io::Result<()> = try { let mut f = File::create_buffered(&path)?; - for (sym, _) in symbols { + for sym in symbols { writeln!(f, "{sym}")?; } }; diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 06ba5b4f6a752..5f0a0cf922af2 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -692,7 +692,6 @@ fn calling_convention_for_symbol<'tcx>( pub(crate) fn linking_symbol_name_for_instance_in_crate<'tcx>( tcx: TyCtxt<'tcx>, symbol: ExportedSymbol<'tcx>, - export_kind: SymbolExportKind, instantiating_crate: CrateNum, ) -> String { let mut undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate); @@ -713,9 +712,8 @@ pub(crate) fn linking_symbol_name_for_instance_in_crate<'tcx>( let prefix = match &target.arch[..] { "x86" => Some('_'), "x86_64" => None, - // Only functions are decorated for arm64ec. - "arm64ec" if export_kind == SymbolExportKind::Text => Some('#'), - // Only x86/64 and arm64ec use symbol decorations. + "arm64ec" => Some('#'), + // Only x86/64 use symbol decorations. _ => return undecorated, }; @@ -755,10 +753,9 @@ pub(crate) fn exporting_symbol_name_for_instance_in_crate<'tcx>( /// Add it to the symbols list for all kernel functions, so that it is exported in the linked /// object. pub(crate) fn extend_exported_symbols<'tcx>( - symbols: &mut Vec<(String, SymbolExportKind)>, + symbols: &mut Vec, tcx: TyCtxt<'tcx>, symbol: ExportedSymbol<'tcx>, - info: SymbolExportInfo, instantiating_crate: CrateNum, ) { let (conv, _) = calling_convention_for_symbol(tcx, symbol); @@ -770,7 +767,7 @@ pub(crate) fn extend_exported_symbols<'tcx>( let undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate); // Add the symbol for the kernel descriptor (with .kd suffix) - symbols.push((format!("{undecorated}.kd"), info.kind)); + symbols.push(format!("{undecorated}.kd")); } fn maybe_emutls_symbol_name<'tcx>( diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 93cbd4cbb7cc9..775ab9071e743 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -12,9 +12,9 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_data_structures::sync::{IntoDynSyncSend, par_map}; use rustc_data_structures::unord::UnordMap; +use rustc_hir::ItemId; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; -use rustc_hir::{ItemId, Target}; use rustc_metadata::EncodedMetadata; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType}; @@ -1038,35 +1038,21 @@ impl CrateInfo { // by the compiler, but that's ok because all this stuff is unstable anyway. let target = &tcx.sess.target; if !are_upstream_rust_objects_already_included(tcx.sess) { - let add_prefix = match (target.is_like_windows, target.arch.as_ref()) { - (true, "x86") => |name: String, _: SymbolExportKind| format!("_{name}"), - (true, "arm64ec") => { - // Only functions are decorated for arm64ec. - |name: String, export_kind: SymbolExportKind| match export_kind { - SymbolExportKind::Text => format!("#{name}"), - _ => name, - } - } - _ => |name: String, _: SymbolExportKind| name, - }; - let missing_weak_lang_items: FxIndexSet<(Symbol, SymbolExportKind)> = info + let missing_weak_lang_items: FxIndexSet = info .used_crates .iter() .flat_map(|&cnum| tcx.missing_lang_items(cnum)) .filter(|l| l.is_weak()) .filter_map(|&l| { let name = l.link_name()?; - let export_kind = match l.target() { - Target::Fn => SymbolExportKind::Text, - Target::Static => SymbolExportKind::Data, - _ => bug!( - "Don't know what the export kind is for lang item of kind {:?}", - l.target() - ), - }; - lang_items::required(tcx, l).then_some((name, export_kind)) + lang_items::required(tcx, l).then_some(name) }) .collect(); + let prefix = match (target.is_like_windows, target.arch.as_ref()) { + (true, "x86") => "_", + (true, "arm64ec") => "#", + _ => "", + }; // This loop only adds new items to values of the hash map, so the order in which we // iterate over the values is not important. @@ -1079,13 +1065,10 @@ impl CrateInfo { .for_each(|(_, linked_symbols)| { let mut symbols = missing_weak_lang_items .iter() - .map(|(item, export_kind)| { + .map(|item| { ( - add_prefix( - mangle_internal_symbol(tcx, item.as_str()), - *export_kind, - ), - *export_kind, + format!("{prefix}{}", mangle_internal_symbol(tcx, item.as_str())), + SymbolExportKind::Text, ) }) .collect::>(); @@ -1100,12 +1083,12 @@ impl CrateInfo { // errors. linked_symbols.extend(ALLOCATOR_METHODS.iter().map(|method| { ( - add_prefix( + format!( + "{prefix}{}", mangle_internal_symbol( tcx, - global_fn_name(method.name).as_str(), - ), - SymbolExportKind::Text, + global_fn_name(method.name).as_str() + ) ), SymbolExportKind::Text, ) diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 0e410be5a0627..84919645cf071 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -218,7 +218,7 @@ pub struct CrateInfo { pub target_cpu: String, pub target_features: Vec, pub crate_types: Vec, - pub exported_symbols: UnordMap>, + pub exported_symbols: UnordMap>, pub linked_symbols: FxIndexMap>, pub local_crate_name: Symbol, pub compiler_builtins: Option, diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs index 64a1f2aff15c5..1d67d0fe3bbf4 100644 --- a/compiler/rustc_middle/src/middle/exported_symbols.rs +++ b/compiler/rustc_middle/src/middle/exported_symbols.rs @@ -22,7 +22,7 @@ impl SymbolExportLevel { } /// Kind of exported symbols. -#[derive(Eq, PartialEq, Debug, Copy, Clone, Encodable, Decodable, HashStable, Hash)] +#[derive(Eq, PartialEq, Debug, Copy, Clone, Encodable, Decodable, HashStable)] pub enum SymbolExportKind { Text, Data, diff --git a/compiler/rustc_target/src/spec/base/msvc.rs b/compiler/rustc_target/src/spec/base/msvc.rs index bd59678d23665..486d7158723f8 100644 --- a/compiler/rustc_target/src/spec/base/msvc.rs +++ b/compiler/rustc_target/src/spec/base/msvc.rs @@ -5,19 +5,7 @@ use crate::spec::{BinaryFormat, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo pub(crate) fn opts() -> TargetOptions { // Suppress the verbose logo and authorship debugging output, which would needlessly // clog any log files. - let pre_link_args = TargetOptions::link_args( - LinkerFlavor::Msvc(Lld::No), - &[ - "/NOLOGO", - // "Symbol is marked as dllimport, but defined in an object file" - // Harmless warning that flags a potential performance improvement: marking a symbol as - // dllimport indirects usage via the `__imp_` symbol, which isn't required if the symbol - // is in the current binary. This is tripped by __rust_no_alloc_shim_is_unstable as it - // is generated by the compiler, but marked as a foreign item (hence the dllimport) in - // the standard library. - "/IGNORE:4286", - ], - ); + let pre_link_args = TargetOptions::link_args(LinkerFlavor::Msvc(Lld::No), &["/NOLOGO"]); TargetOptions { linker_flavor: LinkerFlavor::Msvc(Lld::No), diff --git a/tests/run-make/arm64ec-import-export-static/export.rs b/tests/run-make/arm64ec-import-export-static/export.rs deleted file mode 100644 index 98b3a66d80c04..0000000000000 --- a/tests/run-make/arm64ec-import-export-static/export.rs +++ /dev/null @@ -1,23 +0,0 @@ -#![crate_type = "dylib"] -#![allow(internal_features)] -#![feature(no_core, lang_items)] -#![no_core] -#![no_std] - -// This is needed because of #![no_core]: -#[lang = "sized"] -trait Sized {} -#[lang = "sync"] -trait Sync {} -impl Sync for i32 {} -#[lang = "copy"] -pub trait Copy {} -impl Copy for i32 {} -#[lang = "drop_in_place"] -pub unsafe fn drop_in_place(_: *mut T) {} -#[no_mangle] -extern "system" fn _DllMainCRTStartup(_: *const u8, _: u32, _: *const u8) -> u32 { - 1 -} - -pub static VALUE: i32 = 42; diff --git a/tests/run-make/arm64ec-import-export-static/import.rs b/tests/run-make/arm64ec-import-export-static/import.rs deleted file mode 100644 index 9d52db251250a..0000000000000 --- a/tests/run-make/arm64ec-import-export-static/import.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![crate_type = "cdylib"] -#![allow(internal_features)] -#![feature(no_core)] -#![no_std] -#![no_core] - -extern crate export; - -#[no_mangle] -pub extern "C" fn func() -> i32 { - export::VALUE -} diff --git a/tests/run-make/arm64ec-import-export-static/rmake.rs b/tests/run-make/arm64ec-import-export-static/rmake.rs deleted file mode 100644 index 7fa31144810df..0000000000000 --- a/tests/run-make/arm64ec-import-export-static/rmake.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Test that a static can be exported from one crate and imported into another. -// -// This was broken for Arm64EC as only functions, not variables, should be -// decorated with `#`. -// See https://github.com/rust-lang/rust/issues/138541 - -//@ needs-llvm-components: aarch64 -//@ only-windows - -use run_make_support::rustc; - -fn main() { - rustc().input("export.rs").target("aarch64-pc-windows-msvc").panic("abort").run(); - rustc().input("import.rs").target("aarch64-pc-windows-msvc").panic("abort").run(); -} diff --git a/tests/run-make/sanitizer-dylib-link/program.rs b/tests/run-make/sanitizer-dylib-link/program.rs index dbf885d343fea..1026c7f89ba9f 100644 --- a/tests/run-make/sanitizer-dylib-link/program.rs +++ b/tests/run-make/sanitizer-dylib-link/program.rs @@ -1,4 +1,4 @@ -#[cfg_attr(windows, link(name = "library", kind = "raw-dylib"))] +#[cfg_attr(windows, link(name = "library.dll.lib", modifiers = "+verbatim"))] #[cfg_attr(not(windows), link(name = "library"))] extern "C" { fn overflow(); From b7f2cd3a2b1606934018cc64bac52bb887ea892a Mon Sep 17 00:00:00 2001 From: joboet Date: Sat, 29 Mar 2025 12:16:49 +0100 Subject: [PATCH 2292/4206] deduplicate abort implementations Currently, the code for process aborts is duplicated across `panic_abort` and `std`. This PR uses `#[rustc_std_internal_symbol]` to make the `std` implementation available to `panic_abort` via the linker, thereby deduplicating the code. --- library/Cargo.lock | 1 - library/panic_abort/Cargo.toml | 7 ++- library/panic_abort/src/lib.rs | 76 ++------------------------ library/panic_unwind/src/hermit.rs | 20 +++---- library/std/src/rt.rs | 9 ++- library/std/src/sys/pal/hermit/mod.rs | 9 --- library/std/src/sys/pal/sgx/mod.rs | 7 ++- library/std/src/sys/pal/uefi/mod.rs | 8 --- library/std/src/sys/pal/windows/mod.rs | 9 ++- library/std/src/sys/pal/xous/mod.rs | 6 ++ library/std/src/sys/pal/xous/os.rs | 8 --- 11 files changed, 43 insertions(+), 117 deletions(-) diff --git a/library/Cargo.lock b/library/Cargo.lock index 97ca3cb06b243..02018057ed53e 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -196,7 +196,6 @@ name = "panic_abort" version = "0.0.0" dependencies = [ "alloc", - "cfg-if", "compiler_builtins", "core", "libc", diff --git a/library/panic_abort/Cargo.toml b/library/panic_abort/Cargo.toml index 6f43ac4809a32..d7d169671f010 100644 --- a/library/panic_abort/Cargo.toml +++ b/library/panic_abort/Cargo.toml @@ -12,10 +12,11 @@ bench = false doc = false [dependencies] -alloc = { path = "../alloc" } -cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } core = { path = "../core" } compiler_builtins = "0.1.0" -[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] +[target.'cfg(target_os = "android")'.dependencies] libc = { version = "0.2", default-features = false } + +[target.'cfg(any(target_os = "android", target_os = "zkvm"))'.dependencies] +alloc = { path = "../alloc" } diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index b2ad0f4ac3d04..d1706b6525295 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -7,15 +7,11 @@ #![unstable(feature = "panic_abort", issue = "32837")] #![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] #![panic_runtime] -#![allow(unused_features)] -#![feature(asm_experimental_arch)] -#![feature(core_intrinsics)] #![feature(panic_runtime)] #![feature(std_internals)] #![feature(staged_api)] #![feature(rustc_attrs)] #![allow(internal_features)] -#![deny(unsafe_op_in_unsafe_fn)] #[cfg(target_os = "android")] mod android; @@ -45,75 +41,13 @@ pub unsafe fn __rust_start_panic(_payload: &mut dyn PanicPayload) -> u32 { zkvm::zkvm_set_abort_message(_payload); } - unsafe { - abort(); + unsafe extern "Rust" { + // This is defined in std::rt. + #[rustc_std_internal_symbol] + safe fn __rust_abort() -> !; } - cfg_if::cfg_if! { - if #[cfg(any(unix, target_os = "solid_asp3"))] { - unsafe fn abort() -> ! { - unsafe { libc::abort(); } - } - } else if #[cfg(any(target_os = "hermit", - all(target_vendor = "fortanix", target_env = "sgx"), - target_os = "xous", - target_os = "uefi", - ))] { - unsafe fn abort() -> ! { - // call std::sys::abort_internal - unsafe extern "C" { - pub fn __rust_abort() -> !; - } - unsafe { __rust_abort(); } - } - } else if #[cfg(all(windows, not(miri)))] { - // On Windows, use the processor-specific __fastfail mechanism. In Windows 8 - // and later, this will terminate the process immediately without running any - // in-process exception handlers. In earlier versions of Windows, this - // sequence of instructions will be treated as an access violation, - // terminating the process but without necessarily bypassing all exception - // handlers. - // - // https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail - // - // Note: this is the same implementation as in std's `abort_internal` - unsafe fn abort() -> ! { - #[allow(unused)] - const FAST_FAIL_FATAL_APP_EXIT: usize = 7; - cfg_if::cfg_if! { - if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { - unsafe { - core::arch::asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack)); - } - } else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] { - unsafe { - core::arch::asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack)); - } - } else if #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] { - unsafe { - core::arch::asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack)); - } - } else { - core::intrinsics::abort(); - } - } - } - } else if #[cfg(target_os = "teeos")] { - mod teeos { - unsafe extern "C" { - pub fn TEE_Panic(code: u32) -> !; - } - } - - unsafe fn abort() -> ! { - unsafe { teeos::TEE_Panic(1); } - } - } else { - unsafe fn abort() -> ! { - core::intrinsics::abort(); - } - } - } + __rust_abort() } // This... is a bit of an oddity. The tl;dr; is that this is required to link diff --git a/library/panic_unwind/src/hermit.rs b/library/panic_unwind/src/hermit.rs index 8f4562d07fc4e..b36d1a019fddb 100644 --- a/library/panic_unwind/src/hermit.rs +++ b/library/panic_unwind/src/hermit.rs @@ -5,20 +5,16 @@ use alloc::boxed::Box; use core::any::Any; +unsafe extern "Rust" { + // This is defined in std::rt + #[rustc_std_internal_symbol] + safe fn __rust_abort() -> !; +} + pub(crate) unsafe fn cleanup(_ptr: *mut u8) -> Box { - unsafe extern "C" { - fn __rust_abort() -> !; - } - unsafe { - __rust_abort(); - } + __rust_abort() } pub(crate) unsafe fn panic(_data: Box) -> u32 { - unsafe extern "C" { - fn __rust_abort() -> !; - } - unsafe { - __rust_abort(); - } + __rust_abort() } diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 9737b2f5bfe60..b3f3b301e3db6 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -26,6 +26,13 @@ use crate::sync::Once; use crate::thread::{self, main_thread}; use crate::{mem, panic, sys}; +// This function is needed by the panic runtime. +#[cfg(not(test))] +#[rustc_std_internal_symbol] +fn __rust_abort() { + crate::process::abort(); +} + // Prints to the "panic output", depending on the platform this may be: // - the standard error output // - some dedicated platform specific output @@ -47,7 +54,7 @@ macro_rules! rtabort { ($($t:tt)*) => { { rtprintpanic!("fatal runtime error: {}, aborting\n", format_args!($($t)*)); - crate::sys::abort_internal(); + crate::process::abort(); } } } diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index ea636938d703f..fb8d69b73759d 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -43,15 +43,6 @@ pub fn abort_internal() -> ! { unsafe { hermit_abi::abort() } } -// This function is needed by the panic runtime. The symbol is named in -// pre-link args for the target specification, so keep that in sync. -#[cfg(not(test))] -#[unsafe(no_mangle)] -// NB. used by both libunwind and libpanic_abort -pub extern "C" fn __rust_abort() { - abort_internal(); -} - // SAFETY: must be called only once during runtime initialization. // NOTE: this is not guaranteed to run, for example when Rust code is called externally. pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) { diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs index 3932f64c0ef44..6e43a79ddec2c 100644 --- a/library/std/src/sys/pal/sgx/mod.rs +++ b/library/std/src/sys/pal/sgx/mod.rs @@ -112,11 +112,14 @@ pub fn abort_internal() -> ! { abi::usercalls::exit(true) } -// This function is needed by the panic runtime. The symbol is named in +// This function is needed by libunwind. The symbol is named in // pre-link args for the target specification, so keep that in sync. +// Note: contrary to the `__rust_abort` in `crate::rt`, this uses `no_mangle` +// because it is actually used from C code. Because symbols annotated with +// #[rustc_std_internal_symbol] get mangled, this will not lead to linker +// conflicts. #[cfg(not(test))] #[unsafe(no_mangle)] -// NB. used by both libunwind and libpanic_abort pub extern "C" fn __rust_abort() { abort_internal(); } diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs index 78fcfcb3b77d5..8911a2ee5194d 100644 --- a/library/std/src/sys/pal/uefi/mod.rs +++ b/library/std/src/sys/pal/uefi/mod.rs @@ -161,14 +161,6 @@ pub fn abort_internal() -> ! { core::intrinsics::abort(); } -// This function is needed by the panic runtime. The symbol is named in -// pre-link args for the target specification, so keep that in sync. -#[cfg(not(test))] -#[unsafe(no_mangle)] -pub extern "C" fn __rust_abort() { - abort_internal(); -} - /// Disable access to BootServices if `EVT_SIGNAL_EXIT_BOOT_SERVICES` is signaled extern "efiapi" fn exit_boot_service_handler(_e: r_efi::efi::Event, _ctx: *mut crate::ffi::c_void) { uefi::env::disable_boot_services(); diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 4f18c4009ab6c..ebe8cfb668137 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -328,8 +328,13 @@ pub fn dur2timeout(dur: Duration) -> u32 { /// Use `__fastfail` to abort the process /// -/// This is the same implementation as in libpanic_abort's `__rust_start_panic`. See -/// that function for more information on `__fastfail` +/// In Windows 8 and later, this will terminate the process immediately without +/// running any in-process exception handlers. In earlier versions of Windows, +/// this sequence of instructions will be treated as an access violation, +/// terminating the process but without necessarily bypassing all exception +/// handlers. +/// +/// https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail #[cfg(not(miri))] // inline assembly does not work in Miri pub fn abort_internal() -> ! { unsafe { diff --git a/library/std/src/sys/pal/xous/mod.rs b/library/std/src/sys/pal/xous/mod.rs index 383d031ed4353..042c4ff862ff6 100644 --- a/library/std/src/sys/pal/xous/mod.rs +++ b/library/std/src/sys/pal/xous/mod.rs @@ -1,5 +1,7 @@ #![forbid(unsafe_op_in_unsafe_fn)] +use crate::os::xous::ffi::exit; + pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; @@ -9,3 +11,7 @@ pub mod time; #[path = "../unsupported/common.rs"] mod common; pub use common::*; + +pub fn abort_internal() -> ! { + exit(101); +} diff --git a/library/std/src/sys/pal/xous/os.rs b/library/std/src/sys/pal/xous/os.rs index 2230dabe096fd..d612a27d2bdb6 100644 --- a/library/std/src/sys/pal/xous/os.rs +++ b/library/std/src/sys/pal/xous/os.rs @@ -62,14 +62,6 @@ mod c_compat { } exit(unsafe { main() }); } - - // This function is needed by the panic runtime. The symbol is named in - // pre-link args for the target specification, so keep that in sync. - #[unsafe(no_mangle)] - // NB. used by both libunwind and libpanic_abort - pub extern "C" fn __rust_abort() -> ! { - exit(101); - } } pub fn errno() -> i32 { From 6647cbb515711774b0dff6c682c176715dcb9d51 Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 21 Apr 2025 15:18:36 +0200 Subject: [PATCH 2293/4206] improve internal fastfail explainer --- library/std/src/sys/pal/windows/mod.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index ebe8cfb668137..8f54e2376eb8b 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -330,9 +330,8 @@ pub fn dur2timeout(dur: Duration) -> u32 { /// /// In Windows 8 and later, this will terminate the process immediately without /// running any in-process exception handlers. In earlier versions of Windows, -/// this sequence of instructions will be treated as an access violation, -/// terminating the process but without necessarily bypassing all exception -/// handlers. +/// this sequence of instructions will be treated as an access violation, which +/// will still terminate the process but might run some exception handlers. /// /// https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail #[cfg(not(miri))] // inline assembly does not work in Miri From f77c16000701491d38e76a1dddb6b35a7658d550 Mon Sep 17 00:00:00 2001 From: joboet Date: Thu, 15 May 2025 11:37:50 +0200 Subject: [PATCH 2294/4206] normalize abort calls in miri tests --- src/tools/miri/tests/fail/alloc/alloc_error_handler.rs | 2 +- .../miri/tests/fail/alloc/alloc_error_handler.stderr | 2 +- .../exported_symbol_bad_unwind2.both.stderr | 2 +- .../exported_symbol_bad_unwind2.definition.stderr | 2 +- .../fail/function_calls/exported_symbol_bad_unwind2.rs | 2 +- .../miri/tests/fail/intrinsics/uninit_uninhabited_type.rs | 2 +- .../tests/fail/intrinsics/uninit_uninhabited_type.stderr | 2 +- src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs | 2 +- src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr | 2 +- src/tools/miri/tests/fail/panic/abort_unwind.rs | 2 +- src/tools/miri/tests/fail/panic/abort_unwind.stderr | 2 +- src/tools/miri/tests/fail/panic/double_panic.rs | 2 +- src/tools/miri/tests/fail/panic/double_panic.stderr | 2 +- src/tools/miri/tests/fail/panic/panic_abort1.rs | 2 +- src/tools/miri/tests/fail/panic/panic_abort1.stderr | 8 +++++--- src/tools/miri/tests/fail/panic/panic_abort2.rs | 2 +- src/tools/miri/tests/fail/panic/panic_abort2.stderr | 8 +++++--- src/tools/miri/tests/fail/panic/panic_abort3.rs | 2 +- src/tools/miri/tests/fail/panic/panic_abort3.stderr | 8 +++++--- src/tools/miri/tests/fail/panic/panic_abort4.rs | 2 +- src/tools/miri/tests/fail/panic/panic_abort4.stderr | 8 +++++--- src/tools/miri/tests/fail/ptr_swap_nonoverlapping.rs | 2 +- src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr | 2 +- src/tools/miri/tests/fail/terminate-terminator.rs | 2 +- src/tools/miri/tests/fail/terminate-terminator.stderr | 2 +- src/tools/miri/tests/fail/unwind-action-terminate.rs | 2 +- src/tools/miri/tests/fail/unwind-action-terminate.stderr | 2 +- 27 files changed, 43 insertions(+), 35 deletions(-) diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler.rs b/src/tools/miri/tests/fail/alloc/alloc_error_handler.rs index 2097126e16b9b..4a87411d755c0 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler.rs +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler.rs @@ -1,5 +1,5 @@ //@error-in-other-file: aborted -//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@normalize-stderr-test: "\| +\^+" -> "| ^" #![feature(allocator_api)] diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr index 3642f3f28ca2a..fa84da841fd46 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr @@ -2,7 +2,7 @@ memory allocation of 4 bytes failed error: abnormal termination: the program aborted execution --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr index b2a501db7763c..7cb2bf9967814 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr @@ -11,7 +11,7 @@ thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr index b2a501db7763c..7cb2bf9967814 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr @@ -11,7 +11,7 @@ thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs index 1382e9571f316..9d993786d57f9 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs @@ -1,5 +1,5 @@ //@revisions: extern_block definition both -//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@normalize-stderr-test: "\n +at [^\n]+" -> "" diff --git a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs index 6e0e0ca9f53e1..dd3246d812031 100644 --- a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs +++ b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs @@ -1,4 +1,4 @@ -//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@normalize-stderr-test: "\n +at [^\n]+" -> "" diff --git a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr index 2c9bea1724d63..ba96e595bee2b 100644 --- a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr +++ b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr @@ -7,7 +7,7 @@ thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs index 0e8d3d08c1287..3d355bad626a9 100644 --- a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs +++ b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs @@ -1,4 +1,4 @@ -//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@normalize-stderr-test: "\n +at [^\n]+" -> "" diff --git a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr index 0634298a38f36..7e1f4160cc0e2 100644 --- a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr +++ b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr @@ -7,7 +7,7 @@ thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail/panic/abort_unwind.rs b/src/tools/miri/tests/fail/panic/abort_unwind.rs index e313d9c11dec3..bd819362da413 100644 --- a/src/tools/miri/tests/fail/panic/abort_unwind.rs +++ b/src/tools/miri/tests/fail/panic/abort_unwind.rs @@ -1,5 +1,5 @@ //@error-in-other-file: the program aborted execution -//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@normalize-stderr-test: "\n +at [^\n]+" -> "" diff --git a/src/tools/miri/tests/fail/panic/abort_unwind.stderr b/src/tools/miri/tests/fail/panic/abort_unwind.stderr index 3a63cb38ad06c..e6668b09f66b6 100644 --- a/src/tools/miri/tests/fail/panic/abort_unwind.stderr +++ b/src/tools/miri/tests/fail/panic/abort_unwind.stderr @@ -11,7 +11,7 @@ thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail/panic/double_panic.rs b/src/tools/miri/tests/fail/panic/double_panic.rs index ddc75521ecad0..4d8f4cb6fb7ba 100644 --- a/src/tools/miri/tests/fail/panic/double_panic.rs +++ b/src/tools/miri/tests/fail/panic/double_panic.rs @@ -1,4 +1,4 @@ -//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@normalize-stderr-test: "\n +at [^\n]+" -> "" diff --git a/src/tools/miri/tests/fail/panic/double_panic.stderr b/src/tools/miri/tests/fail/panic/double_panic.stderr index 16e933be43480..67f88955defb8 100644 --- a/src/tools/miri/tests/fail/panic/double_panic.stderr +++ b/src/tools/miri/tests/fail/panic/double_panic.stderr @@ -14,7 +14,7 @@ thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail/panic/panic_abort1.rs b/src/tools/miri/tests/fail/panic/panic_abort1.rs index 7552c7b7e808e..06cb673778a2b 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort1.rs +++ b/src/tools/miri/tests/fail/panic/panic_abort1.rs @@ -1,6 +1,6 @@ //@error-in-other-file: the program aborted execution //@normalize-stderr-test: "\| +\^+" -> "| ^" -//@normalize-stderr-test: "unsafe \{ libc::abort\(\); \}|core::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@compile-flags: -C panic=abort fn main() { diff --git a/src/tools/miri/tests/fail/panic/panic_abort1.stderr b/src/tools/miri/tests/fail/panic/panic_abort1.stderr index c950b2b4ea63e..6d56874ebde96 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort1.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort1.stderr @@ -4,13 +4,15 @@ panicking from libstd note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect error: abnormal termination: the program aborted execution - --> RUSTLIB/panic_abort/src/lib.rs:LL:CC + --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: - = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC + = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + = note: inside `std::process::abort` at RUSTLIB/std/src/process.rs:LL:CC + = note: inside `std::rt::__rust_abort` at RUSTLIB/std/src/rt.rs:LL:CC = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC diff --git a/src/tools/miri/tests/fail/panic/panic_abort2.rs b/src/tools/miri/tests/fail/panic/panic_abort2.rs index 624f99335455f..c011b3ee7eb84 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort2.rs +++ b/src/tools/miri/tests/fail/panic/panic_abort2.rs @@ -1,6 +1,6 @@ //@error-in-other-file: the program aborted execution //@normalize-stderr-test: "\| +\^+" -> "| ^" -//@normalize-stderr-test: "unsafe \{ libc::abort\(\); \}|core::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@compile-flags: -C panic=abort fn main() { diff --git a/src/tools/miri/tests/fail/panic/panic_abort2.stderr b/src/tools/miri/tests/fail/panic/panic_abort2.stderr index 9a9266ec493a5..dbb56f13f4860 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort2.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort2.stderr @@ -4,13 +4,15 @@ thread 'main' panicked at tests/fail/panic/panic_abort2.rs:LL:CC: note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect error: abnormal termination: the program aborted execution - --> RUSTLIB/panic_abort/src/lib.rs:LL:CC + --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: - = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC + = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + = note: inside `std::process::abort` at RUSTLIB/std/src/process.rs:LL:CC + = note: inside `std::rt::__rust_abort` at RUSTLIB/std/src/rt.rs:LL:CC = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC diff --git a/src/tools/miri/tests/fail/panic/panic_abort3.rs b/src/tools/miri/tests/fail/panic/panic_abort3.rs index d1435b55946c1..911dc4a44abda 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort3.rs +++ b/src/tools/miri/tests/fail/panic/panic_abort3.rs @@ -1,6 +1,6 @@ //@error-in-other-file: the program aborted execution //@normalize-stderr-test: "\| +\^+" -> "| ^" -//@normalize-stderr-test: "unsafe \{ libc::abort\(\); \}|core::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@compile-flags: -C panic=abort fn main() { diff --git a/src/tools/miri/tests/fail/panic/panic_abort3.stderr b/src/tools/miri/tests/fail/panic/panic_abort3.stderr index f04a2b0f3f144..7f0564879e47e 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort3.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort3.stderr @@ -4,13 +4,15 @@ panicking from libcore note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect error: abnormal termination: the program aborted execution - --> RUSTLIB/panic_abort/src/lib.rs:LL:CC + --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: - = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC + = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + = note: inside `std::process::abort` at RUSTLIB/std/src/process.rs:LL:CC + = note: inside `std::rt::__rust_abort` at RUSTLIB/std/src/rt.rs:LL:CC = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC diff --git a/src/tools/miri/tests/fail/panic/panic_abort4.rs b/src/tools/miri/tests/fail/panic/panic_abort4.rs index 54b9c9cbfdb0e..696fdff742237 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort4.rs +++ b/src/tools/miri/tests/fail/panic/panic_abort4.rs @@ -1,6 +1,6 @@ //@error-in-other-file: the program aborted execution //@normalize-stderr-test: "\| +\^+" -> "| ^" -//@normalize-stderr-test: "unsafe \{ libc::abort\(\); \}|core::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@compile-flags: -C panic=abort fn main() { diff --git a/src/tools/miri/tests/fail/panic/panic_abort4.stderr b/src/tools/miri/tests/fail/panic/panic_abort4.stderr index e71c4879ea320..ce6910b99331e 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort4.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort4.stderr @@ -4,13 +4,15 @@ thread 'main' panicked at tests/fail/panic/panic_abort4.rs:LL:CC: note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect error: abnormal termination: the program aborted execution - --> RUSTLIB/panic_abort/src/lib.rs:LL:CC + --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: - = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC + = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + = note: inside `std::process::abort` at RUSTLIB/std/src/process.rs:LL:CC + = note: inside `std::rt::__rust_abort` at RUSTLIB/std/src/rt.rs:LL:CC = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC diff --git a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.rs b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.rs index 6f627c416b0f1..6119e8604b465 100644 --- a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.rs +++ b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.rs @@ -1,6 +1,6 @@ //! This is a regression test for : The precondition //! check in `ptr::swap_nonoverlapping` was incorrectly disabled in Miri. -//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@normalize-stderr-test: "\n +at [^\n]+" -> "" diff --git a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr index 80dd2f39b4260..f57487e3ffe17 100644 --- a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr +++ b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr @@ -9,7 +9,7 @@ thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail/terminate-terminator.rs b/src/tools/miri/tests/fail/terminate-terminator.rs index 465625c757251..31ae829a2de75 100644 --- a/src/tools/miri/tests/fail/terminate-terminator.rs +++ b/src/tools/miri/tests/fail/terminate-terminator.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmir-opt-level=3 -Zinline-mir-hint-threshold=1000 -//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@normalize-stderr-test: "\n +at [^\n]+" -> "" diff --git a/src/tools/miri/tests/fail/terminate-terminator.stderr b/src/tools/miri/tests/fail/terminate-terminator.stderr index f2548bf5cdb27..d16119a30e6fe 100644 --- a/src/tools/miri/tests/fail/terminate-terminator.stderr +++ b/src/tools/miri/tests/fail/terminate-terminator.stderr @@ -13,7 +13,7 @@ thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail/unwind-action-terminate.rs b/src/tools/miri/tests/fail/unwind-action-terminate.rs index 465e07c8db4b8..f0fbcfd88675f 100644 --- a/src/tools/miri/tests/fail/unwind-action-terminate.rs +++ b/src/tools/miri/tests/fail/unwind-action-terminate.rs @@ -1,5 +1,5 @@ //@error-in-other-file: aborted execution -//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@normalize-stderr-test: "\n +at [^\n]+" -> "" diff --git a/src/tools/miri/tests/fail/unwind-action-terminate.stderr b/src/tools/miri/tests/fail/unwind-action-terminate.stderr index 7b9a4383fc4c5..222d4fb286690 100644 --- a/src/tools/miri/tests/fail/unwind-action-terminate.stderr +++ b/src/tools/miri/tests/fail/unwind-action-terminate.stderr @@ -11,7 +11,7 @@ thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: From 5e3aa1610fe47316b65ed6dfeae96965c0f74303 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 15 May 2025 11:38:18 +0200 Subject: [PATCH 2295/4206] avoid upstream pull conflict We changed this line and have not pushed it upstream yet, and upstream changed it in the meanwhile. --- src/doc/rustc-dev-guide/src/autodiff/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/autodiff/installation.md b/src/doc/rustc-dev-guide/src/autodiff/installation.md index 971d07bfa39a4..c9b28dc43a6d1 100644 --- a/src/doc/rustc-dev-guide/src/autodiff/installation.md +++ b/src/doc/rustc-dev-guide/src/autodiff/installation.md @@ -1,6 +1,6 @@ # Installation -In the near future, `std::autodiff` should become available in nightly builds for users. As a contributor however, you will still need to build rustc from source. Please be aware that the msvc target is not supported at the moment, all other tier 1 targets should work. Please open an issue if you encounter any problems on a supported tier 1 target, or if you succesfully build this project on a tier2/tier3 target. +In the near future, `std::autodiff` should become available in nightly builds for users. As a contributor however, you will still need to build rustc from source. Please be aware that the msvc target is not supported at the moment, all other tier 1 targets should work. Please open an issue if you encounter any problems on a supported tier 1 target, or if you successfully build this project on a tier2/tier3 target. ## Build instructions From 4adff2f244140be9ac78c0bd6774bf5acb828029 Mon Sep 17 00:00:00 2001 From: The rustc-dev-guide Cronjob Bot Date: Thu, 15 May 2025 09:46:15 +0000 Subject: [PATCH 2296/4206] Preparing for merge from rustc --- src/doc/rustc-dev-guide/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index ec1602280955d..5e4266f61da2a 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -7e552b46af72df390ed233b58a7f51650515b2a8 +414482f6a0d4e7290f614300581a0b55442552a3 From d14c6f2c7907198701dbbc356c2ce505347114b9 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Thu, 8 May 2025 11:23:46 +0200 Subject: [PATCH 2297/4206] Include `let` assignment in suggestion Placeholders are still given for the content of the whole block. However, if the result of the original `if let` or `match` expression was assigned, the assignment is reflected in the suggestion. No-op assignments (`let x = x;`) are skipped though, unless they contain an explicit type which might help the compiler (`let x: u32 = x;` is kept). --- clippy_lints/src/loops/while_let_loop.rs | 81 +++++++++++---- tests/ui/while_let_loop.rs | 86 ++++++++++++++++ tests/ui/while_let_loop.stderr | 122 ++++++++++++++++++++++- 3 files changed, 265 insertions(+), 24 deletions(-) diff --git a/clippy_lints/src/loops/while_let_loop.rs b/clippy_lints/src/loops/while_let_loop.rs index 0032dc3d7a48e..845edb9cae158 100644 --- a/clippy_lints/src/loops/while_let_loop.rs +++ b/clippy_lints/src/loops/while_let_loop.rs @@ -1,44 +1,51 @@ use super::WHILE_LET_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::higher; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::{snippet, snippet_indent, snippet_opt}; use clippy_utils::ty::needs_ordered_drop; use clippy_utils::visitors::any_temporaries_need_ordered_drop; +use clippy_utils::{higher, peel_blocks}; +use rustc_ast::BindingMode; use rustc_errors::Applicability; -use rustc_hir::{Block, Expr, ExprKind, LetStmt, MatchSource, Pat, StmtKind}; +use rustc_hir::{Block, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind, Path, QPath, StmtKind, Ty}; use rustc_lint::LateContext; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) { - let (init, has_trailing_exprs) = match (loop_block.stmts, loop_block.expr) { - ([stmt, stmts @ ..], expr) => { - if let StmtKind::Let(&LetStmt { + let (init, let_info) = match (loop_block.stmts, loop_block.expr) { + ([stmt, ..], _) => match stmt.kind { + StmtKind::Let(LetStmt { init: Some(e), els: None, + pat, + ty, .. - }) - | StmtKind::Semi(e) - | StmtKind::Expr(e) = stmt.kind - { - (e, !stmts.is_empty() || expr.is_some()) - } else { - return; - } + }) => (*e, Some((*pat, *ty))), + StmtKind::Semi(e) | StmtKind::Expr(e) => (e, None), + _ => return, }, - ([], Some(e)) => (e, false), + ([], Some(e)) => (e, None), _ => return, }; + let has_trailing_exprs = loop_block.stmts.len() + usize::from(loop_block.expr.is_some()) > 1; if let Some(if_let) = higher::IfLet::hir(cx, init) && let Some(else_expr) = if_let.if_else && is_simple_break_expr(else_expr) { - could_be_while_let(cx, expr, if_let.let_pat, if_let.let_expr, has_trailing_exprs); + could_be_while_let( + cx, + expr, + if_let.let_pat, + if_let.let_expr, + has_trailing_exprs, + let_info, + if_let.if_then, + ); } else if let ExprKind::Match(scrutinee, [arm1, arm2], MatchSource::Normal) = init.kind && arm1.guard.is_none() && arm2.guard.is_none() && is_simple_break_expr(arm2.body) { - could_be_while_let(cx, expr, arm1.pat, scrutinee, has_trailing_exprs); + could_be_while_let(cx, expr, arm1.pat, scrutinee, has_trailing_exprs, let_info, arm1.body); } } @@ -62,6 +69,8 @@ fn could_be_while_let<'tcx>( let_pat: &'tcx Pat<'_>, let_expr: &'tcx Expr<'_>, has_trailing_exprs: bool, + let_info: Option<(&Pat<'_>, Option<&Ty<'_>>)>, + inner_expr: &Expr<'_>, ) { if has_trailing_exprs && (needs_ordered_drop(cx, cx.typeck_results().expr_ty(let_expr)) @@ -76,7 +85,24 @@ fn could_be_while_let<'tcx>( // 1) it was ugly with big bodies; // 2) it was not indented properly; // 3) it wasn’t very smart (see #675). - let mut applicability = Applicability::HasPlaceholders; + let inner_content = if let Some((pat, ty)) = let_info + // Prevent trivial reassignments such as `let x = x;` or `let _ = …;`, but + // keep them if the type has been explicitly specified. + && (!is_trivial_assignment(pat, peel_blocks(inner_expr)) || ty.is_some()) + && let Some(pat_str) = snippet_opt(cx, pat.span) + && let Some(init_str) = snippet_opt(cx, peel_blocks(inner_expr).span) + { + let ty_str = ty + .map(|ty| format!(": {}", snippet(cx, ty.span, "_"))) + .unwrap_or_default(); + format!( + "\n{indent} let {pat_str}{ty_str} = {init_str};\n{indent} ..\n{indent}", + indent = snippet_indent(cx, expr.span).unwrap_or_default(), + ) + } else { + " .. ".into() + }; + span_lint_and_sugg( cx, WHILE_LET_LOOP, @@ -84,10 +110,21 @@ fn could_be_while_let<'tcx>( "this loop could be written as a `while let` loop", "try", format!( - "while let {} = {} {{ .. }}", - snippet_with_applicability(cx, let_pat.span, "..", &mut applicability), - snippet_with_applicability(cx, let_expr.span, "..", &mut applicability), + "while let {} = {} {{{inner_content}}}", + snippet(cx, let_pat.span, ".."), + snippet(cx, let_expr.span, ".."), ), - applicability, + Applicability::HasPlaceholders, ); } + +fn is_trivial_assignment(pat: &Pat<'_>, init: &Expr<'_>) -> bool { + match (pat.kind, init.kind) { + (PatKind::Wild, _) => true, + ( + PatKind::Binding(BindingMode::NONE, _, pat_ident, None), + ExprKind::Path(QPath::Resolved(None, Path { segments: [init], .. })), + ) => pat_ident.name == init.ident.name, + _ => false, + } +} diff --git a/tests/ui/while_let_loop.rs b/tests/ui/while_let_loop.rs index d591ab984cfaf..95062c9f46c7d 100644 --- a/tests/ui/while_let_loop.rs +++ b/tests/ui/while_let_loop.rs @@ -154,3 +154,89 @@ fn issue_5715(mut m: core::cell::RefCell>) { m = core::cell::RefCell::new(Some(x + 1)); } } + +mod issue_362 { + pub fn merge_sorted(xs: Vec, ys: Vec) -> Vec + where + T: PartialOrd, + { + let total_len = xs.len() + ys.len(); + let mut res = Vec::with_capacity(total_len); + let mut ix = xs.into_iter().peekable(); + let mut iy = ys.into_iter().peekable(); + loop { + //~^ while_let_loop + let lt = match (ix.peek(), iy.peek()) { + (Some(x), Some(y)) => x < y, + _ => break, + }; + res.push(if lt { &mut ix } else { &mut iy }.next().unwrap()); + } + res.extend(ix); + res.extend(iy); + res + } +} + +fn let_assign() { + loop { + //~^ while_let_loop + let x = if let Some(y) = Some(3) { + y + } else { + break; + }; + if x == 3 { + break; + } + } + + loop { + //~^ while_let_loop + let x: u32 = if let Some(y) = Some(3) { + y + } else { + break; + }; + if x == 3 { + break; + } + } + + loop { + //~^ while_let_loop + let x = if let Some(x) = Some(3) { + x + } else { + break; + }; + if x == 3 { + break; + } + } + + loop { + //~^ while_let_loop + let x: u32 = if let Some(x) = Some(3) { + x + } else { + break; + }; + if x == 3 { + break; + } + } + + loop { + //~^ while_let_loop + let x = if let Some(x) = Some(2) { + let t = 1; + t + x + } else { + break; + }; + if x == 3 { + break; + } + } +} diff --git a/tests/ui/while_let_loop.stderr b/tests/ui/while_let_loop.stderr index bd482857e675a..ed42628a53e7f 100644 --- a/tests/ui/while_let_loop.stderr +++ b/tests/ui/while_let_loop.stderr @@ -57,7 +57,125 @@ LL | | let (e, l) = match "".split_whitespace().next() { ... | LL | | let _ = (e, l); LL | | } - | |_____^ help: try: `while let Some(word) = "".split_whitespace().next() { .. }` + | |_____^ + | +help: try + | +LL ~ while let Some(word) = "".split_whitespace().next() { +LL + let (e, l) = (word.is_empty(), word.len()); +LL + .. +LL + } + | + +error: this loop could be written as a `while let` loop + --> tests/ui/while_let_loop.rs:167:9 + | +LL | / loop { +LL | | +LL | | let lt = match (ix.peek(), iy.peek()) { +LL | | (Some(x), Some(y)) => x < y, +... | +LL | | res.push(if lt { &mut ix } else { &mut iy }.next().unwrap()); +LL | | } + | |_________^ + | +help: try + | +LL ~ while let (Some(x), Some(y)) = (ix.peek(), iy.peek()) { +LL + let lt = x < y; +LL + .. +LL + } + | + +error: this loop could be written as a `while let` loop + --> tests/ui/while_let_loop.rs:182:5 + | +LL | / loop { +LL | | +LL | | let x = if let Some(y) = Some(3) { +LL | | y +... | +LL | | } + | |_____^ + | +help: try + | +LL ~ while let Some(y) = Some(3) { +LL + let x = y; +LL + .. +LL + } + | + +error: this loop could be written as a `while let` loop + --> tests/ui/while_let_loop.rs:194:5 + | +LL | / loop { +LL | | +LL | | let x: u32 = if let Some(y) = Some(3) { +LL | | y +... | +LL | | } + | |_____^ + | +help: try + | +LL ~ while let Some(y) = Some(3) { +LL + let x: u32 = y; +LL + .. +LL + } + | + +error: this loop could be written as a `while let` loop + --> tests/ui/while_let_loop.rs:206:5 + | +LL | / loop { +LL | | +LL | | let x = if let Some(x) = Some(3) { +LL | | x +... | +LL | | } + | |_____^ help: try: `while let Some(x) = Some(3) { .. }` + +error: this loop could be written as a `while let` loop + --> tests/ui/while_let_loop.rs:218:5 + | +LL | / loop { +LL | | +LL | | let x: u32 = if let Some(x) = Some(3) { +LL | | x +... | +LL | | } + | |_____^ + | +help: try + | +LL ~ while let Some(x) = Some(3) { +LL + let x: u32 = x; +LL + .. +LL + } + | + +error: this loop could be written as a `while let` loop + --> tests/ui/while_let_loop.rs:230:5 + | +LL | / loop { +LL | | +LL | | let x = if let Some(x) = Some(2) { +LL | | let t = 1; +... | +LL | | } + | |_____^ + | +help: try + | +LL ~ while let Some(x) = Some(2) { +LL + let x = { +LL + let t = 1; +LL + t + x +LL + }; +LL + .. +LL + } + | -error: aborting due to 5 previous errors +error: aborting due to 11 previous errors From 34c6ba735448f351fb2bcc883ecb9607f6666186 Mon Sep 17 00:00:00 2001 From: Georges Savoundararadj Date: Thu, 15 May 2025 12:31:32 +0200 Subject: [PATCH 2298/4206] comparison_chain: do not lint on 2 blocks expression Clippy should not lint 2 blocks expression for comparison_chain. --- clippy_lints/src/comparison_chain.rs | 7 ++++- tests/ui/comparison_chain.rs | 10 +++---- tests/ui/comparison_chain.stderr | 42 ++++++---------------------- 3 files changed, 19 insertions(+), 40 deletions(-) diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index 9c3009a86cdc0..238ebd4a444cf 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -75,11 +75,15 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain { } // Check that there exists at least one explicit else condition - let (conds, _) = if_sequence(expr); + let (conds, blocks) = if_sequence(expr); if conds.len() < 2 { return; } + if blocks.len() < 3 { + return; + } + for cond in conds.windows(2) { if let (&ExprKind::Binary(ref kind1, lhs1, rhs1), &ExprKind::Binary(ref kind2, lhs2, rhs2)) = (&cond[0].kind, &cond[1].kind) @@ -125,6 +129,7 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain { let ExprKind::Binary(_, lhs, rhs) = conds[0].kind else { unreachable!(); }; + let lhs = Sugg::hir(cx, lhs, "..").maybe_paren(); let rhs = Sugg::hir(cx, rhs, "..").addr(); span_lint_and_sugg( diff --git a/tests/ui/comparison_chain.rs b/tests/ui/comparison_chain.rs index 669690a4d42ce..5695d48e0dfd7 100644 --- a/tests/ui/comparison_chain.rs +++ b/tests/ui/comparison_chain.rs @@ -12,11 +12,10 @@ fn f(x: u8, y: u8, z: u8) { a() } - if x > y { - //~^ comparison_chain - + // Ignored: Not all cases are covered + if x < y { a() - } else if x < y { + } else if x > y { b() } @@ -123,9 +122,8 @@ fn g(x: f64, y: f64, z: f64) { } fn h(x: T, y: T, z: T) { + // Ignored: Not all cases are covered if x > y { - //~^ comparison_chain - a() } else if x < y { b() diff --git a/tests/ui/comparison_chain.stderr b/tests/ui/comparison_chain.stderr index 0256573d0d906..ce580bd54a16a 100644 --- a/tests/ui/comparison_chain.stderr +++ b/tests/ui/comparison_chain.stderr @@ -1,12 +1,12 @@ error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:15:5 + --> tests/ui/comparison_chain.rs:29:5 | LL | / if x > y { LL | | LL | | LL | | a() -LL | | } else if x < y { -LL | | b() +... | +LL | | c() LL | | } | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}` | @@ -14,19 +14,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::comparison_chain)]` error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:30:5 - | -LL | / if x > y { -LL | | -LL | | -LL | | a() -... | -LL | | c() -LL | | } - | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}` - -error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:40:5 + --> tests/ui/comparison_chain.rs:39:5 | LL | / if x > y { LL | | @@ -38,7 +26,7 @@ LL | | } | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}` error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:50:5 + --> tests/ui/comparison_chain.rs:49:5 | LL | / if x > 1 { LL | | @@ -50,19 +38,7 @@ LL | | } | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&1) {...}` error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:126:5 - | -LL | / if x > y { -LL | | -LL | | -LL | | a() -LL | | } else if x < y { -LL | | b() -LL | | } - | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}` - -error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:134:5 + --> tests/ui/comparison_chain.rs:132:5 | LL | / if x > y { LL | | @@ -74,7 +50,7 @@ LL | | } | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}` error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:144:5 + --> tests/ui/comparison_chain.rs:142:5 | LL | / if x > y { LL | | @@ -86,7 +62,7 @@ LL | | } | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}` error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:251:5 + --> tests/ui/comparison_chain.rs:249:5 | LL | / if x + 1 > y * 2 { LL | | @@ -97,5 +73,5 @@ LL | | "cc" LL | | } | |_____^ help: consider rewriting the `if` chain with `match`: `match (x + 1).cmp(&(y * 2)) {...}` -error: aborting due to 8 previous errors +error: aborting due to 6 previous errors From 92116bcfa6d47ebd021296a3f3cabb62f021b74c Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 15 May 2025 10:17:20 +0000 Subject: [PATCH 2299/4206] remove `RustfmtState` to reduce `initial_rustfmt` complexity The current use of `RustfmtState` doesn't serve its main purpose as it never does the lazy evaulation since `Build::build` forces it to be ready on the early stage. If we want rustfmt to be ready on the early stage, we don't need to have `RustfmtState` complexity at all. Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/format.rs | 4 +- src/bootstrap/src/core/build_steps/test.rs | 2 +- src/bootstrap/src/core/config/config.rs | 45 ++------------------ src/bootstrap/src/core/download.rs | 6 ++- src/bootstrap/src/lib.rs | 5 --- 5 files changed, 12 insertions(+), 50 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 93900a9043e7e..1c317ce4b86b1 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -58,7 +58,7 @@ fn rustfmt( fn get_rustfmt_version(build: &Builder<'_>) -> Option<(String, BuildStamp)> { let stamp_file = BuildStamp::new(&build.out).with_prefix("rustfmt"); - let mut cmd = command(build.initial_rustfmt()?); + let mut cmd = command(build.config.initial_rustfmt.as_ref()?); cmd.arg("--version"); let output = cmd.allow_failure().run_capture(build); @@ -243,7 +243,7 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { let override_ = override_builder.build().unwrap(); // `override` is a reserved keyword - let rustfmt_path = build.initial_rustfmt().unwrap_or_else(|| { + let rustfmt_path = build.config.initial_rustfmt.clone().unwrap_or_else(|| { eprintln!("fmt error: `x fmt` is not supported on this channel"); crate::exit!(1); }); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index f708b6e9fd699..b2dc509ddca0e 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1102,7 +1102,7 @@ impl Step for Tidy { if builder.config.channel == "dev" || builder.config.channel == "nightly" { if !builder.config.json_output { builder.info("fmt check"); - if builder.initial_rustfmt().is_none() { + if builder.config.initial_rustfmt.is_none() { let inferred_rustfmt_dir = builder.initial_sysroot.join("bin"); eprintln!( "\ diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index c8beca25bccc5..3b8c3655b8d1c 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -3,7 +3,7 @@ //! This module implements parsing `bootstrap.toml` configuration files to tweak //! how the build runs. -use std::cell::{Cell, RefCell}; +use std::cell::Cell; use std::collections::{BTreeSet, HashMap, HashSet}; use std::fmt::{self, Display}; use std::hash::Hash; @@ -406,11 +406,7 @@ pub struct Config { pub initial_rustc: PathBuf, pub initial_cargo_clippy: Option, pub initial_sysroot: PathBuf, - - #[cfg(not(test))] - initial_rustfmt: RefCell, - #[cfg(test)] - pub initial_rustfmt: RefCell, + pub initial_rustfmt: Option, /// The paths to work with. For example: with `./x check foo bar` we get /// `paths=["foo", "bar"]`. @@ -428,15 +424,6 @@ pub struct Config { pub path_modification_cache: Arc, PathFreshness>>>, } -#[derive(Clone, Debug, Default)] -pub enum RustfmtState { - SystemToolchain(PathBuf), - Downloaded(PathBuf), - Unavailable, - #[default] - LazyEvaluated, -} - #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] pub enum LlvmLibunwind { #[default] @@ -2448,13 +2435,8 @@ impl Config { }); } - if let Some(r) = rustfmt { - *config.initial_rustfmt.borrow_mut() = if r.exists() { - RustfmtState::SystemToolchain(r) - } else { - RustfmtState::Unavailable - }; - } + config.initial_rustfmt = + if let Some(r) = rustfmt { Some(r) } else { config.maybe_download_rustfmt() }; // Now that we've reached the end of our configuration, infer the // default values for all options that we haven't otherwise stored yet. @@ -2851,25 +2833,6 @@ impl Config { .as_deref() } - pub(crate) fn initial_rustfmt(&self) -> Option { - match &mut *self.initial_rustfmt.borrow_mut() { - RustfmtState::SystemToolchain(p) | RustfmtState::Downloaded(p) => Some(p.clone()), - RustfmtState::Unavailable => None, - r @ RustfmtState::LazyEvaluated => { - if self.dry_run() { - return Some(PathBuf::new()); - } - let path = self.maybe_download_rustfmt(); - *r = if let Some(p) = &path { - RustfmtState::Downloaded(p.clone()) - } else { - RustfmtState::Unavailable - }; - path - } - } - } - /// Runs a function if verbosity is greater than 0 pub fn verbose(&self, f: impl Fn()) { if self.is_verbose() { diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 64298964dad54..e0c9877cd55db 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -446,7 +446,7 @@ impl Config { #[cfg(test)] pub(crate) fn maybe_download_rustfmt(&self) -> Option { - None + Some(PathBuf::new()) } /// NOTE: rustfmt is a completely different toolchain than the bootstrap compiler, so it can't @@ -455,6 +455,10 @@ impl Config { pub(crate) fn maybe_download_rustfmt(&self) -> Option { use build_helper::stage0_parser::VersionMetadata; + if self.dry_run() { + return Some(PathBuf::new()); + } + let VersionMetadata { date, version } = self.stage0_metadata.rustfmt.as_ref()?; let channel = format!("{version}-{date}"); diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 1e6acad5c0fc9..9492ffaed7566 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -325,7 +325,6 @@ forward! { tempdir() -> PathBuf, llvm_link_shared() -> bool, download_rustc() -> bool, - initial_rustfmt() -> Option, } impl Build { @@ -614,10 +613,6 @@ impl Build { crate::utils::job::setup(self); } - // Download rustfmt early so that it can be used in rust-analyzer configs. - trace!("downloading rustfmt early"); - let _ = &builder::Builder::new(self).initial_rustfmt(); - // Handle hard-coded subcommands. { #[cfg(feature = "tracing")] From 7b2dcf298909f1493a57387be564fc2f07a3c6ad Mon Sep 17 00:00:00 2001 From: Andrew Zhogin Date: Thu, 15 May 2025 19:03:23 +0700 Subject: [PATCH 2300/4206] Async drop fix for dropee from another crate (#140858) --- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/util.rs | 2 +- .../async-drop/auxiliary/async-drop-dep.rs | 28 +++++++++++++++ .../async-drop/dependency-dropped.rs | 34 +++++++++++++++++++ .../async-drop/dependency-dropped.run.stdout | 1 + 5 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 tests/ui/async-await/async-drop/auxiliary/async-drop-dep.rs create mode 100644 tests/ui/async-await/async-drop/dependency-dropped.rs create mode 100644 tests/ui/async-await/async-drop/dependency-dropped.run.stdout diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index dda0faa3afedd..51eb9461f2d67 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1184,7 +1184,7 @@ pub struct Destructor { #[derive(Copy, Clone, Debug, HashStable, Encodable, Decodable)] pub struct AsyncDestructor { /// The `DefId` of the `impl AsyncDrop` - pub impl_did: LocalDefId, + pub impl_did: DefId, } #[derive(Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 6fe5927c29fcb..9676aa4044823 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -465,7 +465,7 @@ impl<'tcx> TyCtxt<'tcx> { dtor_candidate = Some(impl_did); } - Some(ty::AsyncDestructor { impl_did: dtor_candidate? }) + Some(ty::AsyncDestructor { impl_did: dtor_candidate?.into() }) } /// Returns the set of types that are required to be alive in diff --git a/tests/ui/async-await/async-drop/auxiliary/async-drop-dep.rs b/tests/ui/async-await/async-drop/auxiliary/async-drop-dep.rs new file mode 100644 index 0000000000000..1729599f7b3f3 --- /dev/null +++ b/tests/ui/async-await/async-drop/auxiliary/async-drop-dep.rs @@ -0,0 +1,28 @@ +//@ edition:2021 + +#![feature(async_drop)] +#![allow(incomplete_features)] + +pub struct HasDrop; +impl Drop for HasDrop{ + fn drop(&mut self) { + println!("Sync drop"); + } +} + +pub struct MongoDrop; +impl MongoDrop { + pub async fn new() -> Result { + Ok(Self) + } +} +impl Drop for MongoDrop{ + fn drop(&mut self) { + println!("Sync drop"); + } +} +impl std::future::AsyncDrop for MongoDrop { + async fn drop(self: std::pin::Pin<&mut Self>) { + println!("Async drop"); + } +} diff --git a/tests/ui/async-await/async-drop/dependency-dropped.rs b/tests/ui/async-await/async-drop/dependency-dropped.rs new file mode 100644 index 0000000000000..f763bb32b1733 --- /dev/null +++ b/tests/ui/async-await/async-drop/dependency-dropped.rs @@ -0,0 +1,34 @@ +//@ run-pass +//@ check-run-results +//@ aux-build:async-drop-dep.rs +//@ edition:2021 + +#![feature(async_drop)] +#![allow(incomplete_features)] + +extern crate async_drop_dep; + +use async_drop_dep::MongoDrop; +use std::pin::pin; +use std::task::{Context, Poll, Waker}; +use std::future::Future; + +async fn asyncdrop() { + let _ = MongoDrop::new().await; +} + +pub fn block_on(fut: impl Future) -> T { + let mut fut = pin!(fut); + let ctx = &mut Context::from_waker(Waker::noop()); + + loop { + match fut.as_mut().poll(ctx) { + Poll::Pending => {} + Poll::Ready(t) => break t, + } + } +} + +fn main() { + let _ = block_on(asyncdrop()); +} diff --git a/tests/ui/async-await/async-drop/dependency-dropped.run.stdout b/tests/ui/async-await/async-drop/dependency-dropped.run.stdout new file mode 100644 index 0000000000000..7aaf70c12d608 --- /dev/null +++ b/tests/ui/async-await/async-drop/dependency-dropped.run.stdout @@ -0,0 +1 @@ +Async drop From de8e8641ae8194009b13dcca997e1eaa991b2888 Mon Sep 17 00:00:00 2001 From: bendn Date: Tue, 29 Apr 2025 13:06:21 +0700 Subject: [PATCH 2301/4206] dont handle bool transmute --- .../src/check_unnecessary_transmutes.rs | 3 +-- tests/ui/transmute/unnecessary-transmutation.fixed | 6 +++--- tests/ui/transmute/unnecessary-transmutation.rs | 4 ++-- tests/ui/transmute/unnecessary-transmutation.stderr | 8 +------- 4 files changed, 7 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs b/compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs index 8da17a056e31b..0514de3ea13fb 100644 --- a/compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs +++ b/compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs @@ -9,6 +9,7 @@ use crate::errors::UnnecessaryTransmute as Error; /// Check for transmutes that overlap with stdlib methods. /// For example, transmuting `[u8; 4]` to `u32`. +/// We chose not to lint u8 -> bool transmutes, see #140431 pub(super) struct CheckUnnecessaryTransmutes; impl<'tcx> crate::MirLint<'tcx> for CheckUnnecessaryTransmutes { @@ -98,8 +99,6 @@ impl<'a, 'tcx> UnnecessaryTransmuteChecker<'a, 'tcx> { (Uint(_), Float(ty)) => err(format!("{}::from_bits({arg})", ty.name_str())), // bool → { x8 } (Bool, Int(..) | Uint(..)) => err(format!("({arg}) as {}", fn_sig.output())), - // u8 → bool - (Uint(_), Bool) => err(format!("({arg} == 1)")), _ => return None, }) } diff --git a/tests/ui/transmute/unnecessary-transmutation.fixed b/tests/ui/transmute/unnecessary-transmutation.fixed index bf7d769348aaf..f6478c5aa5c2f 100644 --- a/tests/ui/transmute/unnecessary-transmutation.fixed +++ b/tests/ui/transmute/unnecessary-transmutation.fixed @@ -81,13 +81,13 @@ fn main() { let y: i64 = f64::to_bits(1f64).cast_signed(); //~^ ERROR - let z: bool = (1u8 == 1); - //~^ ERROR + let z: bool = transmute(1u8); + // clippy let z: u8 = (z) as u8; //~^ ERROR let z: bool = transmute(1i8); - // no error! + // clippy let z: i8 = (z) as i8; //~^ ERROR } diff --git a/tests/ui/transmute/unnecessary-transmutation.rs b/tests/ui/transmute/unnecessary-transmutation.rs index b9de529f1cccd..ab0af03acc2ec 100644 --- a/tests/ui/transmute/unnecessary-transmutation.rs +++ b/tests/ui/transmute/unnecessary-transmutation.rs @@ -82,12 +82,12 @@ fn main() { //~^ ERROR let z: bool = transmute(1u8); - //~^ ERROR + // clippy let z: u8 = transmute(z); //~^ ERROR let z: bool = transmute(1i8); - // no error! + // clippy let z: i8 = transmute(z); //~^ ERROR } diff --git a/tests/ui/transmute/unnecessary-transmutation.stderr b/tests/ui/transmute/unnecessary-transmutation.stderr index a19f1bebf16fd..59e933bbc81b9 100644 --- a/tests/ui/transmute/unnecessary-transmutation.stderr +++ b/tests/ui/transmute/unnecessary-transmutation.stderr @@ -239,12 +239,6 @@ error: unnecessary transmute LL | let y: i64 = transmute(1f64); | ^^^^^^^^^^^^^^^ help: replace this with: `f64::to_bits(1f64).cast_signed()` -error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:84:23 - | -LL | let z: bool = transmute(1u8); - | ^^^^^^^^^^^^^^ help: replace this with: `(1u8 == 1)` - error: unnecessary transmute --> $DIR/unnecessary-transmutation.rs:86:21 | @@ -257,5 +251,5 @@ error: unnecessary transmute LL | let z: i8 = transmute(z); | ^^^^^^^^^^^^ help: replace this with: `(z) as i8` -error: aborting due to 36 previous errors +error: aborting due to 35 previous errors From 839534e801b3658fbfa80d8405e0d90623923c9e Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Thu, 15 May 2025 15:41:11 +0200 Subject: [PATCH 2302/4206] ci: split the dist-ohos job --- .../Dockerfile | 18 ------- .../host-x86_64/dist-ohos-armv7/Dockerfile | 53 +++++++++++++++++++ .../host-x86_64/dist-ohos-x86_64/Dockerfile | 53 +++++++++++++++++++ src/ci/github-actions/jobs.yml | 10 +++- 4 files changed, 114 insertions(+), 20 deletions(-) rename src/ci/docker/host-x86_64/{dist-ohos => dist-ohos-aarch64}/Dockerfile (56%) create mode 100644 src/ci/docker/host-x86_64/dist-ohos-armv7/Dockerfile create mode 100644 src/ci/docker/host-x86_64/dist-ohos-x86_64/Dockerfile diff --git a/src/ci/docker/host-x86_64/dist-ohos/Dockerfile b/src/ci/docker/host-x86_64/dist-ohos-aarch64/Dockerfile similarity index 56% rename from src/ci/docker/host-x86_64/dist-ohos/Dockerfile rename to src/ci/docker/host-x86_64/dist-ohos-aarch64/Dockerfile index 2c514fa0d4ddd..adeaf809f4208 100644 --- a/src/ci/docker/host-x86_64/dist-ohos/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-ohos-aarch64/Dockerfile @@ -27,36 +27,18 @@ RUN sh /scripts/ohos-openssl.sh COPY scripts/ohos/aarch64-unknown-linux-ohos-clang.sh /usr/local/bin/ COPY scripts/ohos/aarch64-unknown-linux-ohos-clang++.sh /usr/local/bin/ -COPY scripts/ohos/armv7-unknown-linux-ohos-clang.sh /usr/local/bin/ -COPY scripts/ohos/armv7-unknown-linux-ohos-clang++.sh /usr/local/bin/ -COPY scripts/ohos/x86_64-unknown-linux-ohos-clang.sh /usr/local/bin/ -COPY scripts/ohos/x86_64-unknown-linux-ohos-clang++.sh /usr/local/bin/ # env ENV AARCH64_UNKNOWN_LINUX_OHOS_OPENSSL_DIR=/opt/ohos-openssl/prelude/arm64-v8a -ENV ARMV7_UNKNOWN_LINUX_OHOS_OPENSSL_DIR=/opt/ohos-openssl/prelude/armeabi-v7a -ENV X86_64_UNKNOWN_LINUX_OHOS_OPENSSL_DIR=/opt/ohos-openssl/prelude/x86_64 ENV AARCH64_UNKNOWN_LINUX_OHOS_OPENSSL_NO_VENDOR=1 -ENV ARMV7_UNKNOWN_LINUX_OHOS_OPENSSL_NO_VENDOR=1 -ENV X86_64_UNKNOWN_LINUX_OHOS_OPENSSL_NO_VENDOR=1 ENV TARGETS=aarch64-unknown-linux-ohos -ENV TARGETS=$TARGETS,armv7-unknown-linux-ohos -ENV TARGETS=$TARGETS,x86_64-unknown-linux-ohos ENV \ CC_aarch64_unknown_linux_ohos=/usr/local/bin/aarch64-unknown-linux-ohos-clang.sh \ AR_aarch64_unknown_linux_ohos=/opt/ohos-sdk/native/llvm/bin/llvm-ar \ CXX_aarch64_unknown_linux_ohos=/usr/local/bin/aarch64-unknown-linux-ohos-clang++.sh -ENV \ - CC_armv7_unknown_linux_ohos=/usr/local/bin/armv7-unknown-linux-ohos-clang.sh \ - AR_armv7_unknown_linux_ohos=/opt/ohos-sdk/native/llvm/bin/llvm-ar \ - CXX_armv7_unknown_linux_ohos=/usr/local/bin/armv7-unknown-linux-ohos-clang++.sh -ENV \ - CC_x86_64_unknown_linux_ohos=/usr/local/bin/x86_64-unknown-linux-ohos-clang.sh \ - AR_x86_64_unknown_linux_ohos=/opt/ohos-sdk/native/llvm/bin/llvm-ar \ - CXX_x86_64_unknown_linux_ohos=/usr/local/bin/x86_64-unknown-linux-ohos-clang++.sh ENV RUST_CONFIGURE_ARGS \ --enable-profiler \ diff --git a/src/ci/docker/host-x86_64/dist-ohos-armv7/Dockerfile b/src/ci/docker/host-x86_64/dist-ohos-armv7/Dockerfile new file mode 100644 index 0000000000000..2a23d8aec2376 --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-ohos-armv7/Dockerfile @@ -0,0 +1,53 @@ +FROM ubuntu:24.04 + +ARG DEBIAN_FRONTEND=noninteractive +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + ninja-build \ + file \ + curl \ + ca-certificates \ + python3 \ + git \ + cmake \ + sudo \ + gdb \ + libssl-dev \ + pkg-config \ + xz-utils \ + unzip \ + && rm -rf /var/lib/apt/lists/* + +COPY scripts/ohos-sdk.sh /scripts/ +RUN sh /scripts/ohos-sdk.sh + +COPY scripts/ohos-openssl.sh /scripts/ +RUN sh /scripts/ohos-openssl.sh + +COPY scripts/ohos/armv7-unknown-linux-ohos-clang.sh /usr/local/bin/ +COPY scripts/ohos/armv7-unknown-linux-ohos-clang++.sh /usr/local/bin/ + +# env +ENV ARMV7_UNKNOWN_LINUX_OHOS_OPENSSL_DIR=/opt/ohos-openssl/prelude/armeabi-v7a + +ENV ARMV7_UNKNOWN_LINUX_OHOS_OPENSSL_NO_VENDOR=1 + +ENV TARGETS=armv7-unknown-linux-ohos + +ENV \ + CC_armv7_unknown_linux_ohos=/usr/local/bin/armv7-unknown-linux-ohos-clang.sh \ + AR_armv7_unknown_linux_ohos=/opt/ohos-sdk/native/llvm/bin/llvm-ar \ + CXX_armv7_unknown_linux_ohos=/usr/local/bin/armv7-unknown-linux-ohos-clang++.sh + +ENV RUST_CONFIGURE_ARGS \ + --enable-profiler \ + --disable-docs \ + --tools=cargo,clippy,rustdocs,rustfmt,rust-analyzer,rust-analyzer-proc-macro-srv,analysis,src,wasm-component-ld \ + --enable-extended \ + --enable-sanitizers + +ENV SCRIPT python3 ../x.py dist --host=$TARGETS --target $TARGETS + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh diff --git a/src/ci/docker/host-x86_64/dist-ohos-x86_64/Dockerfile b/src/ci/docker/host-x86_64/dist-ohos-x86_64/Dockerfile new file mode 100644 index 0000000000000..98e402adf2a69 --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-ohos-x86_64/Dockerfile @@ -0,0 +1,53 @@ +FROM ubuntu:24.04 + +ARG DEBIAN_FRONTEND=noninteractive +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + ninja-build \ + file \ + curl \ + ca-certificates \ + python3 \ + git \ + cmake \ + sudo \ + gdb \ + libssl-dev \ + pkg-config \ + xz-utils \ + unzip \ + && rm -rf /var/lib/apt/lists/* + +COPY scripts/ohos-sdk.sh /scripts/ +RUN sh /scripts/ohos-sdk.sh + +COPY scripts/ohos-openssl.sh /scripts/ +RUN sh /scripts/ohos-openssl.sh + +COPY scripts/ohos/x86_64-unknown-linux-ohos-clang.sh /usr/local/bin/ +COPY scripts/ohos/x86_64-unknown-linux-ohos-clang++.sh /usr/local/bin/ + +# env +ENV X86_64_UNKNOWN_LINUX_OHOS_OPENSSL_DIR=/opt/ohos-openssl/prelude/x86_64 + +ENV X86_64_UNKNOWN_LINUX_OHOS_OPENSSL_NO_VENDOR=1 + +ENV TARGETS=x86_64-unknown-linux-ohos + +ENV \ + CC_x86_64_unknown_linux_ohos=/usr/local/bin/x86_64-unknown-linux-ohos-clang.sh \ + AR_x86_64_unknown_linux_ohos=/opt/ohos-sdk/native/llvm/bin/llvm-ar \ + CXX_x86_64_unknown_linux_ohos=/usr/local/bin/x86_64-unknown-linux-ohos-clang++.sh + +ENV RUST_CONFIGURE_ARGS \ + --enable-profiler \ + --disable-docs \ + --tools=cargo,clippy,rustdocs,rustfmt,rust-analyzer,rust-analyzer-proc-macro-srv,analysis,src,wasm-component-ld \ + --enable-extended \ + --enable-sanitizers + +ENV SCRIPT python3 ../x.py dist --host=$TARGETS --target $TARGETS + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 88e9c71a9e318..42ad5acbdac1e 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -188,8 +188,14 @@ auto: - name: dist-loongarch64-musl <<: *job-linux-4c - - name: dist-ohos - <<: *job-linux-4c-largedisk + - name: dist-ohos-aarch64 + <<: *job-linux-4c + + - name: dist-ohos-armv7 + <<: *job-linux-4c + + - name: dist-ohos-x86_64 + <<: *job-linux-4c - name: dist-powerpc-linux <<: *job-linux-4c From 102cc2f8835c2ca73ca9a20172e3c6dda0e4d139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Thu, 15 May 2025 14:05:02 +0000 Subject: [PATCH 2303/4206] move expensive layout sanity check to debug assertions --- .../rustc_ty_utils/src/layout/invariant.rs | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index 7423a156a217a..c929de1162416 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -8,15 +8,6 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, TyAndLayout}; pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) { let tcx = cx.tcx(); - // Type-level uninhabitedness should always imply ABI uninhabitedness. - if layout.ty.is_privately_uninhabited(tcx, cx.typing_env) { - assert!( - layout.is_uninhabited(), - "{:?} is type-level uninhabited but not ABI-uninhabited?", - layout.ty - ); - } - if layout.size.bytes() % layout.align.abi.bytes() != 0 { bug!("size is not a multiple of align, in the following layout:\n{layout:#?}"); } @@ -29,6 +20,19 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou return; } + // Type-level uninhabitedness should always imply ABI uninhabitedness. This can be expensive on + // big non-exhaustive types, and is [hard to + // fix](https://github.com/rust-lang/rust/issues/141006#issuecomment-2883415000) in general. + // Only doing this sanity check when debug assertions are turned on avoids the issue for the + // very specific case of #140944. + if layout.ty.is_privately_uninhabited(tcx, cx.typing_env) { + assert!( + layout.is_uninhabited(), + "{:?} is type-level uninhabited but not ABI-uninhabited?", + layout.ty + ); + } + /// Yields non-ZST fields of the type fn non_zst_fields<'tcx, 'a>( cx: &'a LayoutCx<'tcx>, From 6c21c9fdff5d079f24724ec661fa9d2bc9a2d9f3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 15 May 2025 15:24:19 +0000 Subject: [PATCH 2304/4206] Bump undici from 6.21.1 to 6.21.3 in /editors/code Bumps [undici](https://github.com/nodejs/undici) from 6.21.1 to 6.21.3. - [Release notes](https://github.com/nodejs/undici/releases) - [Commits](https://github.com/nodejs/undici/compare/v6.21.1...v6.21.3) --- updated-dependencies: - dependency-name: undici dependency-version: 6.21.3 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- src/tools/rust-analyzer/editors/code/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json index 11a37c218f7f6..18fb097aad7fb 100644 --- a/src/tools/rust-analyzer/editors/code/package-lock.json +++ b/src/tools/rust-analyzer/editors/code/package-lock.json @@ -5730,9 +5730,9 @@ "license": "MIT" }, "node_modules/undici": { - "version": "6.21.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.1.tgz", - "integrity": "sha512-q/1rj5D0/zayJB2FraXdaWxbhWiNKDvu8naDT2dl1yTlvJp4BLtOcp2a5BvgGNQpYYJzau7tf1WgKv3b+7mqpQ==", + "version": "6.21.3", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.3.tgz", + "integrity": "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==", "dev": true, "license": "MIT", "engines": { From 49553be30784711d7dc6976ef1335b74df7cbe44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Tue, 22 Apr 2025 16:16:23 +0800 Subject: [PATCH 2305/4206] Experimental cygwin support in rustc Co-authored-by: Ookiineko --- compiler/rustc_llvm/build.rs | 1 + compiler/rustc_session/src/filesearch.rs | 19 ++++++++++++++++++- src/bootstrap/src/core/builder/mod.rs | 2 +- src/bootstrap/src/utils/helpers.rs | 2 +- src/bootstrap/src/utils/shared_helpers.rs | 4 ++-- 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 6692ea735401a..a662694ac38f2 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -255,6 +255,7 @@ fn main() { } else if target.contains("haiku") || target.contains("darwin") || (is_crossed && (target.contains("dragonfly") || target.contains("solaris"))) + || target.contains("cygwin") { println!("cargo:rustc-link-lib=z"); } else if target.contains("netbsd") { diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index bdeca91eb64a4..2a85f44278a03 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -58,7 +58,7 @@ pub fn make_target_bin_path(sysroot: &Path, target_triple: &str) -> PathBuf { sysroot.join(rustlib_path).join("bin") } -#[cfg(unix)] +#[cfg(all(unix, not(target_os = "cygwin")))] fn current_dll_path() -> Result { use std::sync::OnceLock; @@ -132,6 +132,23 @@ fn current_dll_path() -> Result { .clone() } +#[cfg(target_os = "cygwin")] +fn current_dll_path() -> Result { + use std::ffi::{CStr, OsStr}; + use std::os::unix::prelude::*; + + unsafe { + let addr = current_dll_path as usize as *mut _; + let mut info = std::mem::zeroed(); + if libc::dladdr(addr, &mut info) == 0 { + return Err("dladdr failed".into()); + } + let bytes = CStr::from_ptr(info.dli_fname.as_ptr()).to_bytes(); + let os = OsStr::from_bytes(bytes); + Ok(PathBuf::from(os)) + } +} + #[cfg(windows)] fn current_dll_path() -> Result { use std::ffi::OsString; diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index cc4fa953ddc5c..af3e3cc37b928 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -1388,7 +1388,7 @@ impl<'a> Builder<'a> { // Windows doesn't need dylib path munging because the dlls for the // compiler live next to the compiler and the system will find them // automatically. - if cfg!(windows) { + if cfg!(any(windows, target_os = "cygwin")) { return; } diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index b29c1fb3889c2..f2c3e8c0df464 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -130,7 +130,7 @@ pub fn is_debug_info(name: &str) -> bool { /// Returns the corresponding relative library directory that the compiler's /// dylibs will be found in. pub fn libdir(target: TargetSelection) -> &'static str { - if target.is_windows() { "bin" } else { "lib" } + if target.is_windows() || target.contains("cygwin") { "bin" } else { "lib" } } /// Adds a list of lookup paths to `cmd`'s dynamic library lookup path. diff --git a/src/bootstrap/src/utils/shared_helpers.rs b/src/bootstrap/src/utils/shared_helpers.rs index 1297a53d48804..3011322158f33 100644 --- a/src/bootstrap/src/utils/shared_helpers.rs +++ b/src/bootstrap/src/utils/shared_helpers.rs @@ -20,7 +20,7 @@ use std::str::FromStr; /// Returns the environment variable which the dynamic library lookup path /// resides in for this platform. pub fn dylib_path_var() -> &'static str { - if cfg!(target_os = "windows") { + if cfg!(any(target_os = "windows", target_os = "cygwin")) { "PATH" } else if cfg!(target_vendor = "apple") { "DYLD_LIBRARY_PATH" @@ -46,7 +46,7 @@ pub fn dylib_path() -> Vec { /// Given an executable called `name`, return the filename for the /// executable for a particular target. pub fn exe(name: &str, target: &str) -> String { - if target.contains("windows") { + if target.contains("windows") || target.contains("cygwin") { format!("{name}.exe") } else if target.contains("uefi") { format!("{name}.efi") From 12fda865f2f67081a96b116cae5194c791b20fb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Sat, 10 May 2025 00:17:09 +0800 Subject: [PATCH 2306/4206] Fix exe() to make rustc wrapper happy --- src/bootstrap/src/utils/shared_helpers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/utils/shared_helpers.rs b/src/bootstrap/src/utils/shared_helpers.rs index 3011322158f33..08e1c21e58e7c 100644 --- a/src/bootstrap/src/utils/shared_helpers.rs +++ b/src/bootstrap/src/utils/shared_helpers.rs @@ -46,7 +46,7 @@ pub fn dylib_path() -> Vec { /// Given an executable called `name`, return the filename for the /// executable for a particular target. pub fn exe(name: &str, target: &str) -> String { - if target.contains("windows") || target.contains("cygwin") { + if target.contains("windows") { format!("{name}.exe") } else if target.contains("uefi") { format!("{name}.efi") From e71deaa88a572ba4d55e8a1300a0dce43b39abe4 Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Wed, 7 May 2025 10:39:07 -0700 Subject: [PATCH 2307/4206] [win][CI] Convert paths to Windows format before adding to PATH --- src/ci/scripts/install-mingw.sh | 2 +- src/ci/scripts/install-ninja.sh | 2 +- src/ci/scripts/install-sccache.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh index c8c501e646a9d..ad852071f2950 100755 --- a/src/ci/scripts/install-mingw.sh +++ b/src/ci/scripts/install-mingw.sh @@ -42,5 +42,5 @@ if isWindows && isKnownToBeMingwBuild; then curl -o mingw.7z "${MIRRORS_BASE}/${mingw_archive}" 7z x -y mingw.7z > /dev/null - ciCommandAddPath "$(pwd)/${mingw_dir}/bin" + ciCommandAddPath "$(cygpath -m "$(pwd)/${mingw_dir}/bin")" fi diff --git a/src/ci/scripts/install-ninja.sh b/src/ci/scripts/install-ninja.sh index 23cbc2eb6d107..7ac19173923cf 100755 --- a/src/ci/scripts/install-ninja.sh +++ b/src/ci/scripts/install-ninja.sh @@ -12,7 +12,7 @@ if isWindows; then 7z x -oninja ninja.zip rm ninja.zip ciCommandSetEnv "RUST_CONFIGURE_ARGS" "${RUST_CONFIGURE_ARGS} --enable-ninja" - ciCommandAddPath "$(pwd)/ninja" + ciCommandAddPath "$(cygpath -m "$(pwd)/ninja")" elif isMacOS; then brew install ninja fi diff --git a/src/ci/scripts/install-sccache.sh b/src/ci/scripts/install-sccache.sh index b055e76a80504..fed06063fa0b3 100755 --- a/src/ci/scripts/install-sccache.sh +++ b/src/ci/scripts/install-sccache.sh @@ -15,7 +15,7 @@ elif isWindows; then mkdir -p sccache curl -fo sccache/sccache.exe \ "${MIRRORS_BASE}/2025-02-24-sccache-v0.10.0-x86_64-pc-windows-msvc.exe" - ciCommandAddPath "$(pwd)/sccache" + ciCommandAddPath "$(cygpath -m "$(pwd)/sccache")" fi # FIXME: we should probably install sccache outside the containers and then From 5be888c4799a4326e545ca23d228824774d5f232 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 15 May 2025 19:19:34 +0200 Subject: [PATCH 2308/4206] Bump nightly version -> 2025-05-14 --- clippy_utils/README.md | 2 +- rust-toolchain.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_utils/README.md b/clippy_utils/README.md index 66192f866fa0e..d4080d06d3ca8 100644 --- a/clippy_utils/README.md +++ b/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: ``` -nightly-2025-05-01 +nightly-2025-05-14 ``` diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 39c7f0e4ad5a5..da41bdd27bcb6 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2025-05-01" +channel = "nightly-2025-05-14" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" From 367073195a0be6476c57e96dcd4354ee6f4830ee Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 15 May 2025 19:19:46 +0200 Subject: [PATCH 2309/4206] Bump Clippy version -> 0.1.89 --- Cargo.toml | 2 +- clippy_config/Cargo.toml | 2 +- clippy_lints/Cargo.toml | 2 +- clippy_utils/Cargo.toml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0df9f2e555987..b6a1b9314c651 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy" # begin autogenerated version -version = "0.1.88" +version = "0.1.89" # end autogenerated version description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" diff --git a/clippy_config/Cargo.toml b/clippy_config/Cargo.toml index 93fd2e35d1ba5..1134b0e97af22 100644 --- a/clippy_config/Cargo.toml +++ b/clippy_config/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_config" # begin autogenerated version -version = "0.1.88" +version = "0.1.89" # end autogenerated version edition = "2024" publish = false diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 20951afccbb7e..7e3cb40424792 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_lints" # begin autogenerated version -version = "0.1.88" +version = "0.1.89" # end autogenerated version description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index b98e990175033..ac970e1c4b0a5 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_utils" # begin autogenerated version -version = "0.1.88" +version = "0.1.89" # end autogenerated version edition = "2024" description = "Helpful tools for writing lints, provided as they are used in Clippy" From 93bd4d893122417b9265563c037f11a158a8e37c Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 15 May 2025 19:28:39 +0200 Subject: [PATCH 2310/4206] Merge commit '0450db33a5d8587f7c1d4b6d233dac963605766b' into clippy-subtree-update --- .github/workflows/clippy_changelog.yml | 17 +- CHANGELOG.md | 104 +- CONTRIBUTING.md | 2 +- Cargo.toml | 5 +- book/src/development/adding_lints.md | 2 +- book/src/development/basics.md | 28 +- .../development/common_tools_writing_lints.md | 4 +- .../infrastructure/changelog_update.md | 27 +- book/src/development/trait_checking.md | 16 +- book/src/lint_configuration.md | 21 + clippy.toml | 3 - clippy_config/Cargo.toml | 2 +- clippy_config/src/conf.rs | 7 + clippy_config/src/lib.rs | 3 +- clippy_config/src/types.rs | 95 +- clippy_dev/src/deprecate_lint.rs | 174 +++ clippy_dev/src/dogfood.rs | 5 +- clippy_dev/src/fmt.rs | 32 +- clippy_dev/src/lib.rs | 5 +- clippy_dev/src/main.rs | 37 +- clippy_dev/src/new_lint.rs | 165 +-- clippy_dev/src/release.rs | 32 +- clippy_dev/src/rename_lint.rs | 194 +++ clippy_dev/src/sync.rs | 31 +- clippy_dev/src/update_lints.rs | 1110 ++++------------- clippy_dev/src/utils.rs | 650 ++++++++-- clippy_lints/Cargo.toml | 2 +- clippy_lints/src/attrs/mod.rs | 2 +- clippy_lints/src/attrs/useless_attribute.rs | 40 +- clippy_lints/src/await_holding_invalid.rs | 13 +- clippy_lints/src/bool_assert_comparison.rs | 9 +- .../casts/confusing_method_to_numeric_cast.rs | 82 ++ clippy_lints/src/casts/manual_dangling_ptr.rs | 19 +- clippy_lints/src/casts/mod.rs | 31 +- clippy_lints/src/cloned_ref_to_slice_refs.rs | 100 ++ clippy_lints/src/collapsible_if.rs | 32 +- clippy_lints/src/declared_lints.rs | 6 +- clippy_lints/src/deprecated_lints.rs | 18 +- clippy_lints/src/derive.rs | 4 +- clippy_lints/src/disallowed_macros.rs | 2 + clippy_lints/src/disallowed_methods.rs | 2 + clippy_lints/src/disallowed_types.rs | 10 +- clippy_lints/src/doc/mod.rs | 2 +- clippy_lints/src/floating_point_arithmetic.rs | 12 +- clippy_lints/src/functions/mod.rs | 4 +- clippy_lints/src/implicit_saturating_sub.rs | 2 +- clippy_lints/src/item_name_repetitions.rs | 50 +- clippy_lints/src/let_underscore.rs | 12 +- clippy_lints/src/let_with_type_underscore.rs | 15 +- clippy_lints/src/lib.rs | 8 +- clippy_lints/src/lifetimes.rs | 2 +- clippy_lints/src/loops/manual_slice_fill.rs | 4 +- clippy_lints/src/loops/mod.rs | 2 +- clippy_lints/src/manual_abs_diff.rs | 2 +- clippy_lints/src/manual_ignore_case_cmp.rs | 9 +- clippy_lints/src/manual_let_else.rs | 71 +- clippy_lints/src/manual_option_as_slice.rs | 16 +- clippy_lints/src/matches/manual_unwrap_or.rs | 3 +- clippy_lints/src/mem_replace.rs | 2 +- ...se_sensitive_file_extension_comparisons.rs | 5 +- clippy_lints/src/methods/io_other_error.rs | 9 +- .../src/methods/manual_c_str_literals.rs | 16 +- .../methods/manual_saturating_arithmetic.rs | 20 +- clippy_lints/src/methods/mod.rs | 102 +- .../methods/needless_character_iteration.rs | 7 +- clippy_lints/src/methods/needless_collect.rs | 10 +- clippy_lints/src/methods/open_options.rs | 20 +- clippy_lints/src/methods/return_and_then.rs | 28 +- clippy_lints/src/methods/str_splitn.rs | 4 +- clippy_lints/src/methods/useless_asref.rs | 9 +- clippy_lints/src/missing_const_for_fn.rs | 4 +- clippy_lints/src/missing_doc.rs | 12 +- .../src/missing_enforced_import_rename.rs | 10 +- clippy_lints/src/mutable_debug_assertion.rs | 11 +- clippy_lints/src/non_std_lazy_statics.rs | 51 +- clippy_lints/src/operators/eq_op.rs | 15 +- .../src/operators/integer_division.rs | 5 +- clippy_lints/src/panic_in_result_fn.rs | 11 +- clippy_lints/src/panic_unimplemented.rs | 8 +- clippy_lints/src/regex.rs | 17 +- clippy_lints/src/returns.rs | 8 +- clippy_lints/src/serde_api.rs | 6 +- clippy_lints/src/single_option_map.rs | 2 +- clippy_lints/src/single_range_in_vec_init.rs | 4 +- clippy_lints/src/strings.rs | 2 +- clippy_lints/src/to_digit_is_some.rs | 40 +- clippy_lints/src/trait_bounds.rs | 18 +- clippy_lints/src/transmute/eager_transmute.rs | 3 - clippy_lints/src/transmute/mod.rs | 115 -- .../src/transmute/transmute_float_to_int.rs | 66 - .../src/transmute/transmute_int_to_char.rs | 47 - .../src/transmute/transmute_int_to_float.rs | 50 - .../src/transmute/transmute_num_to_bytes.rs | 50 - clippy_lints/src/types/mod.rs | 2 +- clippy_lints/src/unit_types/unit_cmp.rs | 17 +- clippy_lints/src/unused_async.rs | 18 +- clippy_lints/src/unused_io_amount.rs | 43 +- clippy_lints/src/unwrap.rs | 61 +- clippy_lints/src/utils/author.rs | 130 +- clippy_lints/src/write.rs | 6 +- clippy_lints/src/zero_sized_map_values.rs | 4 +- clippy_lints_internal/Cargo.toml | 2 +- .../src/collapsible_calls.rs | 6 +- .../derive_deserialize_allowing_unknown.rs | 164 +++ clippy_lints_internal/src/internal_paths.rs | 17 + clippy_lints_internal/src/invalid_paths.rs | 108 -- clippy_lints_internal/src/lib.rs | 11 +- .../src/lint_without_lint_pass.rs | 9 +- clippy_lints_internal/src/msrv_attr_impl.rs | 7 +- .../src/outer_expn_data_pass.rs | 6 +- clippy_lints_internal/src/symbols.rs | 134 +- .../src/unnecessary_def_path.rs | 317 +---- clippy_utils/Cargo.toml | 2 +- clippy_utils/README.md | 2 +- clippy_utils/src/lib.rs | 311 +---- clippy_utils/src/msrvs.rs | 7 +- clippy_utils/src/paths.rs | 391 +++++- clippy_utils/src/sym.rs | 91 +- clippy_utils/src/ty/mod.rs | 85 +- clippy_utils/src/ty/type_certainty/mod.rs | 23 +- lintcheck/src/main.rs | 1 - rust-toolchain.toml | 2 +- src/driver.rs | 1 - tests/compile-test.rs | 2 +- tests/dogfood.rs | 16 +- tests/integration.rs | 2 +- tests/ui-internal/auxiliary/paths.rs | 4 - .../derive_deserialize_allowing_unknown.rs | 60 + ...derive_deserialize_allowing_unknown.stderr | 23 + tests/ui-internal/interning_literals.stderr | 15 +- .../interning_literals_unfixable.stderr | 9 +- tests/ui-internal/invalid_paths.rs | 30 - tests/ui-internal/invalid_paths.stderr | 26 - tests/ui-internal/symbol_as_str.fixed | 7 + tests/ui-internal/symbol_as_str.rs | 7 + tests/ui-internal/symbol_as_str.stderr | 35 +- .../symbol_as_str_unfixable.stderr | 9 +- tests/ui-internal/unnecessary_def_path.fixed | 77 -- tests/ui-internal/unnecessary_def_path.rs | 85 +- tests/ui-internal/unnecessary_def_path.stderr | 120 +- .../unnecessary_def_path_hardcoded_path.rs | 19 - ...unnecessary_def_path_hardcoded_path.stderr | 31 - .../collapsible_if_let_chains.fixed | 1 - .../collapsible_if_let_chains.rs | 1 - .../collapsible_if_let_chains.stderr | 6 +- .../allow_exact_repetitions/clippy.toml | 1 + .../item_name_repetitions.rs | 13 + .../item_name_repetitions.stderr | 11 + .../missing_docs_allow_unused/clippy.toml | 1 + .../missing_docs_allow_unused.rs | 26 + .../missing_docs_allow_unused.stderr | 38 + .../toml_disallowed_methods/clippy.toml | 3 + .../conf_disallowed_methods.rs | 8 + .../conf_disallowed_methods.stderr | 42 +- .../ui-toml/toml_disallowed_types/clippy.toml | 2 +- .../conf_disallowed_types.stderr | 8 +- tests/ui-toml/toml_invalid_path/clippy.toml | 9 +- .../toml_invalid_path/conf_invalid_path.rs | 5 +- .../conf_invalid_path.stderr | 27 +- .../clippy.toml | 4 + .../toml_unknown_config_struct_field.rs | 5 + .../toml_unknown_config_struct_field.stderr | 8 + .../toml_unknown_key/conf_unknown_key.stderr | 6 + tests/ui-toml/toml_unloaded_crate/clippy.toml | 10 + .../conf_unloaded_crate.rs | 6 + .../conf_unloaded_crate.stderr | 20 + .../ui-toml/type_repetition_in_bounds/main.rs | 2 +- .../type_repetition_in_bounds/main.stderr | 2 +- tests/ui/author.stdout | 2 - tests/ui/author/blocks.stdout | 10 +- tests/ui/author/call.stdout | 3 +- tests/ui/author/if.stdout | 4 +- tests/ui/author/issue_3849.stdout | 5 +- tests/ui/author/loop.stdout | 8 +- tests/ui/author/macro_in_closure.stdout | 11 +- tests/ui/author/macro_in_loop.stdout | 11 +- tests/ui/author/matches.stdout | 6 +- tests/ui/author/struct.stdout | 9 +- tests/ui/auxiliary/proc_macro_attr.rs | 79 +- tests/ui/auxiliary/proc_macros.rs | 1 - tests/ui/bool_to_int_with_if.fixed | 1 - tests/ui/bool_to_int_with_if.rs | 1 - tests/ui/bool_to_int_with_if.stderr | 22 +- .../ui/checked_unwrap/simple_conditionals.rs | 85 ++ .../checked_unwrap/simple_conditionals.stderr | 88 +- tests/ui/cloned_ref_to_slice_refs.fixed | 64 + tests/ui/cloned_ref_to_slice_refs.rs | 64 + tests/ui/cloned_ref_to_slice_refs.stderr | 23 + tests/ui/collapsible_if.fixed | 30 +- tests/ui/collapsible_if.rs | 30 +- tests/ui/collapsible_if.stderr | 8 +- ...ollapsible_if_let_chains.edition2024.fixed | 68 + ...llapsible_if_let_chains.edition2024.stderr | 132 ++ tests/ui/collapsible_if_let_chains.fixed | 29 - tests/ui/collapsible_if_let_chains.rs | 52 +- tests/ui/collapsible_if_let_chains.stderr | 58 - tests/ui/collapsible_match.rs | 1 + tests/ui/collapsible_match.stderr | 52 +- tests/ui/comparison_to_empty.fixed | 1 - tests/ui/comparison_to_empty.rs | 1 - tests/ui/comparison_to_empty.stderr | 26 +- .../ui/confusing_method_to_numeric_cast.fixed | 14 + tests/ui/confusing_method_to_numeric_cast.rs | 14 + .../confusing_method_to_numeric_cast.stderr | 100 ++ .../crashes/missing_const_for_fn_14774.fixed | 13 + .../ui/crashes/missing_const_for_fn_14774.rs | 13 + .../crashes/missing_const_for_fn_14774.stderr | 17 + tests/ui/enum_variants.rs | 15 + .../if_let_slice_binding.fixed | 2 +- .../if_let_slice_binding.rs | 2 +- tests/ui/integer_division.rs | 8 + tests/ui/integer_division.stderr | 16 +- tests/ui/let_underscore_untyped.rs | 1 - tests/ui/let_underscore_untyped.stderr | 20 +- tests/ui/let_with_type_underscore.fixed | 47 + tests/ui/let_with_type_underscore.stderr | 34 +- tests/ui/manual_let_else.rs | 32 + tests/ui/manual_let_else.stderr | 22 +- tests/ui/manual_saturating_arithmetic.fixed | 2 - tests/ui/manual_saturating_arithmetic.rs | 2 - tests/ui/manual_saturating_arithmetic.stderr | 48 +- tests/ui/manual_slice_fill.fixed | 37 + tests/ui/manual_slice_fill.rs | 37 + tests/ui/manual_unwrap_or_default.fixed | 13 + tests/ui/manual_unwrap_or_default.rs | 13 + tests/ui/needless_if.fixed | 1 - tests/ui/needless_if.rs | 1 - tests/ui/needless_if.stderr | 14 +- tests/ui/needless_late_init.fixed | 2 - tests/ui/needless_late_init.rs | 2 - tests/ui/needless_late_init.stderr | 34 +- .../non_std_lazy_static_fixable.fixed | 7 + .../non_std_lazy_static_fixable.rs | 7 + .../redundant_pattern_matching_option.fixed | 2 +- tests/ui/redundant_pattern_matching_option.rs | 2 +- tests/ui/rename.fixed | 5 + tests/ui/rename.rs | 5 + tests/ui/rename.stderr | 164 +-- tests/ui/return_and_then.fixed | 52 + tests/ui/return_and_then.rs | 47 + tests/ui/return_and_then.stderr | 47 +- tests/ui/to_digit_is_some.fixed | 17 + tests/ui/to_digit_is_some.rs | 17 + tests/ui/to_digit_is_some.stderr | 14 +- tests/ui/transmute.rs | 132 -- tests/ui/transmute.stderr | 230 +--- tests/ui/transmute_float_to_int.fixed | 60 - tests/ui/transmute_float_to_int.rs | 60 - tests/ui/transmute_float_to_int.stderr | 89 -- tests/ui/transmute_int_to_char.fixed | 16 - tests/ui/transmute_int_to_char.rs | 16 - tests/ui/transmute_int_to_char.stderr | 17 - tests/ui/transmute_int_to_char_no_std.fixed | 28 - tests/ui/transmute_int_to_char_no_std.rs | 28 - tests/ui/transmute_int_to_char_no_std.stderr | 17 - tests/ui/type_repetition_in_bounds.rs | 27 +- tests/ui/type_repetition_in_bounds.stderr | 30 +- tests/ui/unused_async.rs | 8 + tests/ui/unwrap_expect_used.rs | 17 + tests/ui/unwrap_expect_used.stderr | 34 +- triagebot.toml | 6 +- 261 files changed, 5273 insertions(+), 4453 deletions(-) create mode 100644 clippy_dev/src/deprecate_lint.rs create mode 100644 clippy_dev/src/rename_lint.rs create mode 100644 clippy_lints/src/casts/confusing_method_to_numeric_cast.rs create mode 100644 clippy_lints/src/cloned_ref_to_slice_refs.rs delete mode 100644 clippy_lints/src/transmute/transmute_float_to_int.rs delete mode 100644 clippy_lints/src/transmute/transmute_int_to_char.rs delete mode 100644 clippy_lints/src/transmute/transmute_int_to_float.rs delete mode 100644 clippy_lints/src/transmute/transmute_num_to_bytes.rs create mode 100644 clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs create mode 100644 clippy_lints_internal/src/internal_paths.rs delete mode 100644 clippy_lints_internal/src/invalid_paths.rs delete mode 100644 tests/ui-internal/auxiliary/paths.rs create mode 100644 tests/ui-internal/derive_deserialize_allowing_unknown.rs create mode 100644 tests/ui-internal/derive_deserialize_allowing_unknown.stderr delete mode 100644 tests/ui-internal/invalid_paths.rs delete mode 100644 tests/ui-internal/invalid_paths.stderr delete mode 100644 tests/ui-internal/unnecessary_def_path.fixed delete mode 100644 tests/ui-internal/unnecessary_def_path_hardcoded_path.rs delete mode 100644 tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr create mode 100644 tests/ui-toml/item_name_repetitions/allow_exact_repetitions/clippy.toml create mode 100644 tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.rs create mode 100644 tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.stderr create mode 100644 tests/ui-toml/missing_docs_allow_unused/clippy.toml create mode 100644 tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs create mode 100644 tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.stderr create mode 100644 tests/ui-toml/toml_unknown_config_struct_field/clippy.toml create mode 100644 tests/ui-toml/toml_unknown_config_struct_field/toml_unknown_config_struct_field.rs create mode 100644 tests/ui-toml/toml_unknown_config_struct_field/toml_unknown_config_struct_field.stderr create mode 100644 tests/ui-toml/toml_unloaded_crate/clippy.toml create mode 100644 tests/ui-toml/toml_unloaded_crate/conf_unloaded_crate.rs create mode 100644 tests/ui-toml/toml_unloaded_crate/conf_unloaded_crate.stderr create mode 100644 tests/ui/cloned_ref_to_slice_refs.fixed create mode 100644 tests/ui/cloned_ref_to_slice_refs.rs create mode 100644 tests/ui/cloned_ref_to_slice_refs.stderr create mode 100644 tests/ui/collapsible_if_let_chains.edition2024.fixed create mode 100644 tests/ui/collapsible_if_let_chains.edition2024.stderr delete mode 100644 tests/ui/collapsible_if_let_chains.fixed delete mode 100644 tests/ui/collapsible_if_let_chains.stderr create mode 100644 tests/ui/confusing_method_to_numeric_cast.fixed create mode 100644 tests/ui/confusing_method_to_numeric_cast.rs create mode 100644 tests/ui/confusing_method_to_numeric_cast.stderr create mode 100644 tests/ui/crashes/missing_const_for_fn_14774.fixed create mode 100644 tests/ui/crashes/missing_const_for_fn_14774.rs create mode 100644 tests/ui/crashes/missing_const_for_fn_14774.stderr create mode 100644 tests/ui/let_with_type_underscore.fixed delete mode 100644 tests/ui/transmute_float_to_int.fixed delete mode 100644 tests/ui/transmute_float_to_int.rs delete mode 100644 tests/ui/transmute_float_to_int.stderr delete mode 100644 tests/ui/transmute_int_to_char.fixed delete mode 100644 tests/ui/transmute_int_to_char.rs delete mode 100644 tests/ui/transmute_int_to_char.stderr delete mode 100644 tests/ui/transmute_int_to_char_no_std.fixed delete mode 100644 tests/ui/transmute_int_to_char_no_std.rs delete mode 100644 tests/ui/transmute_int_to_char_no_std.stderr diff --git a/.github/workflows/clippy_changelog.yml b/.github/workflows/clippy_changelog.yml index 1e97154bf8a34..4d84d6b6dae4d 100644 --- a/.github/workflows/clippy_changelog.yml +++ b/.github/workflows/clippy_changelog.yml @@ -15,27 +15,18 @@ jobs: changelog: runs-on: ubuntu-latest - defaults: - run: - shell: bash - steps: # Run - name: Check Changelog if: ${{ github.event_name == 'pull_request' }} run: | - body=$(curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -s "https://api.github.com/repos/$%7B%7B%20github.repository%20%7D%7D/pulls/$PR_NUMBER" | \ - python -c "import sys, json; print(json.load(sys.stdin)['body'])") - output=$(awk '/^changelog:\s*\S/ && !/changelog: \[.*\]: your change/' <<< "$body" | sed "s/changelog:\s*//g") - if [ -z "$output" ]; then - echo "ERROR: pull request message must contain 'changelog: ...' with your changelog. Please add it." + if [[ -z $(grep -oP 'changelog: *\K\S+' <<< "$PR_BODY") ]]; then + echo "::error::Pull request message must contain 'changelog: ...' with your changelog. Please add it." exit 1 - else - echo "changelog: $output" fi env: - PYTHONIOENCODING: 'utf-8' - PR_NUMBER: '${{ github.event.number }}' + PR_BODY: ${{ github.event.pull_request.body }}) + # We need to have the "conclusion" job also on PR CI, to make it possible # to add PRs to a merge queue. diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b62c9a59aa5d..28147dfbea3e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,105 @@ document. ## Unreleased / Beta / In Rust Nightly -[3e3715c3...master](https://github.com/rust-lang/rust-clippy/compare/3e3715c3...master) +[1e5237f4...master](https://github.com/rust-lang/rust-clippy/compare/1e5237f4...master) + +## Rust 1.87 + +Current stable, released 2025-05-15 + +[View all 127 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2025-02-06T14%3A54%3A28Z..2025-03-20T20%3A07%3A53Z+base%3Amaster) + +### New Lints + +* Added [`doc_comment_double_space_linebreaks`] to `pedantic` [#12876](https://github.com/rust-lang/rust-clippy/pull/12876) +* Added [`manual_midpoint`] to `pedantic` [#13851](https://github.com/rust-lang/rust-clippy/pull/13851) +* Added [`io_other_error`] to `style` [#14022](https://github.com/rust-lang/rust-clippy/pull/14022) +* Added [`owned_cow`] to `pedantic` [#13948](https://github.com/rust-lang/rust-clippy/pull/13948) +* Added [`manual_contains`] to `perf` [#13817](https://github.com/rust-lang/rust-clippy/pull/13817) +* Added [`unnecessary_debug_formatting`] to `pedantic` [#13893](https://github.com/rust-lang/rust-clippy/pull/13893) +* Added [`elidable_lifetime_names`] to `pedantic` [#13960](https://github.com/rust-lang/rust-clippy/pull/13960) +* Added [`mem_replace_option_with_some`] to `style` [#14197](https://github.com/rust-lang/rust-clippy/pull/14197) +* Added [`unbuffered_bytes`] to `perf` [#14089](https://github.com/rust-lang/rust-clippy/pull/14089) +* Added [`single_option_map`] to `nursery` [#14033](https://github.com/rust-lang/rust-clippy/pull/14033) + +### Moves and Deprecations + +* Moved [`comparison_chain`] to `pedantic` (from `style`) + [#14219](https://github.com/rust-lang/rust-clippy/pull/14219) +* Moved [`manual_ok_or`] to `style` (from `pedantic`) + [#14027](https://github.com/rust-lang/rust-clippy/pull/14027) +* Deprecated [`option_map_or_err_ok`] in favor of [`manual_ok_or`] + [#14027](https://github.com/rust-lang/rust-clippy/pull/14027) + +### Enhancements + +* Add `allow_expect_in_consts` and `allow_unwrap_in_consts` configuration options to [`unwrap_used`], [`expect_used`] + [#14200](https://github.com/rust-lang/rust-clippy/pull/14200) +* Add `check-incompatible-msrv-in-tests` configuration option to [`incompatible_msrv`] + [#14279](https://github.com/rust-lang/rust-clippy/pull/14279) +* [`len_zero`] now also triggers if deref target implements `is_empty()` + [#13871](https://github.com/rust-lang/rust-clippy/pull/13871) +* [`ptr_eq`] now handles more cases, including `!=` in addition to `==` + [#14339](https://github.com/rust-lang/rust-clippy/pull/14339) +* [`struct_field_names`] now also checks private fields of public structs + [#14076](https://github.com/rust-lang/rust-clippy/pull/14076) +* [`needless_pass_by_value`] suggests using a reference on the innermost `Option` content + [#14392](https://github.com/rust-lang/rust-clippy/pull/14392) +* [`obfuscated_if_else`] now supports `then().unwrap_or_else()` and `then_some().unwrap_or_else()` + [#14165](https://github.com/rust-lang/rust-clippy/pull/14165) +* Format macros: all format-handling lints now validate `todo!` and `unimplemented!` macros + [#14266](https://github.com/rust-lang/rust-clippy/pull/14266) +* [`disallowed_methods`] now supports replacements + [#13669](https://github.com/rust-lang/rust-clippy/pull/13669) +* Added MSRV checks for several lints: + * [`question_mark`] [#14436](https://github.com/rust-lang/rust-clippy/pull/14436) + * [`repeat_vec_with_capacity`] [#14126](https://github.com/rust-lang/rust-clippy/pull/14126) + * [`manual_flatten`] [#14086](https://github.com/rust-lang/rust-clippy/pull/14086) + * [`lines_filter_map_ok`] [#14130](https://github.com/rust-lang/rust-clippy/pull/14130) + +### False Positive Fixes + +* [`missing_const_for_fn`] no longer triggers on unstable const traits [#14294](https://github.com/rust-lang/rust-clippy/pull/14294) +* [`unnecessary_to_owned`] now avoids suggesting to call `iter()` on a temporary object [#14243](https://github.com/rust-lang/rust-clippy/pull/14243) +* [`unnecessary_debug_formatting`] no longer triggers in tests [#14347](https://github.com/rust-lang/rust-clippy/pull/14347) +* [`option_if_let_else`] now handles cases when value is partially moved [#14209](https://github.com/rust-lang/rust-clippy/pull/14209) +* [`blocks_in_conditions`] no longer triggers when the condition contains a `return` [#14338](https://github.com/rust-lang/rust-clippy/pull/14338) +* [`undocumented_unsafe_blocks`] no longer triggers on trait/impl items [#13888](https://github.com/rust-lang/rust-clippy/pull/13888) +* [`manual_slice_fill`] no longer triggers due to missing index checks [#14193](https://github.com/rust-lang/rust-clippy/pull/14193) +* [`useless_asref`] no longer suggests using `.clone()` if the target type doesn't implement `Clone` [#14174](https://github.com/rust-lang/rust-clippy/pull/14174) +* [`unnecessary_safety_comment`] no longer triggers on desugared assign [#14371](https://github.com/rust-lang/rust-clippy/pull/14371) +* [`unnecessary_map_or`] no longer consumes the comparison value if it does not implement `Copy` [#14207](https://github.com/rust-lang/rust-clippy/pull/14207) +* [`let_and_return`] no longer triggers involving short-lived block temporary variables [#14180](https://github.com/rust-lang/rust-clippy/pull/14180) +* [`manual_async_fn`] no longer emits suggestions inside macros [#14142](https://github.com/rust-lang/rust-clippy/pull/14142) +* [`use_self`] skips analysis inside macro expansions of a `impl Self` block [#13128](https://github.com/rust-lang/rust-clippy/pull/13128) +* [`double_ended_iterator_last`] no longer triggers on non-reference immutable receiver [#14140](https://github.com/rust-lang/rust-clippy/pull/14140) + +### ICE Fixes + +* [`macro_use_imports`] Fix ICE when checking attributes + [#14317](https://github.com/rust-lang/rust-clippy/pull/14317) +* [`doc_nested_refdefs`] Fix ICE by avoiding invalid ranges + [#14308](https://github.com/rust-lang/rust-clippy/pull/14308) +* [`just_underscores_and_digits`] Fix ICE in error recovery scenario + [#14168](https://github.com/rust-lang/rust-clippy/pull/14168) +* [`declare_interior_mutable_const`], [`borrow_interior_mutable_const`] Fix ICE by properly resolving `::AssocT` projections + [#14125](https://github.com/rust-lang/rust-clippy/pull/14125) + +### Documentation Improvements + +* [`struct_excessive_bools`] Documentation improved with rationale + [#14351](https://github.com/rust-lang/rust-clippy/pull/14351) + +### Others + +* Use edition=2021 in `rustc_tools_util` + [#14211](https://github.com/rust-lang/rust-clippy/pull/14211) +* Fix rustc_tools_util's `version.host_compiler` release channel, expose the rustc version, and add tests + [#14123](https://github.com/rust-lang/rust-clippy/pull/14123) +* Make UI test annotations mandatory + [#11421](https://github.com/rust-lang/rust-clippy/pull/11421) + [#14388](https://github.com/rust-lang/rust-clippy/pull/14388) + [#14393](https://github.com/rust-lang/rust-clippy/pull/14393) ## Rust 1.86 @@ -5583,6 +5681,7 @@ Released 2018-09-13 [`clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy [`clone_on_ref_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_ref_ptr [`cloned_instead_of_copied`]: https://rust-lang.github.io/rust-clippy/master/index.html#cloned_instead_of_copied +[`cloned_ref_to_slice_refs`]: https://rust-lang.github.io/rust-clippy/master/index.html#cloned_ref_to_slice_refs [`cmp_nan`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_nan [`cmp_null`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_null [`cmp_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_owned @@ -5594,6 +5693,7 @@ Released 2018-09-13 [`collection_is_never_read`]: https://rust-lang.github.io/rust-clippy/master/index.html#collection_is_never_read [`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain [`comparison_to_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty +[`confusing_method_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#confusing_method_to_numeric_cast [`const_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_is_empty [`const_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_static_lifetime [`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator @@ -6383,6 +6483,7 @@ Released 2018-09-13 [`accept-comment-above-statement`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-statement [`allow-comparison-to-zero`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-comparison-to-zero [`allow-dbg-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-dbg-in-tests +[`allow-exact-repetitions`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-exact-repetitions [`allow-expect-in-consts`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-expect-in-consts [`allow-expect-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-expect-in-tests [`allow-indexing-slicing-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-indexing-slicing-in-tests @@ -6435,6 +6536,7 @@ Released 2018-09-13 [`max-suggested-slice-pattern-length`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-suggested-slice-pattern-length [`max-trait-bounds`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-trait-bounds [`min-ident-chars-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#min-ident-chars-threshold +[`missing-docs-allow-unused`]: https://doc.rust-lang.org/clippy/lint_configuration.html#missing-docs-allow-unused [`missing-docs-in-crate-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#missing-docs-in-crate-items [`module-item-order-groupings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#module-item-order-groupings [`module-items-ordered-within-groupings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#module-items-ordered-within-groupings diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3b33f71906383..45ba2f078be78 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -77,7 +77,7 @@ debugging to find the actual problem behind the issue. [`T-middle`] issues can be more involved and require verifying types. The [`ty`] module contains a lot of methods that are useful, though one of the most useful would be `expr_ty` (gives the type of -an AST expression). `match_def_path()` in Clippy's `utils` module can also be useful. +an AST expression). [`good-first-issue`]: https://github.com/rust-lang/rust-clippy/labels/good-first-issue [`S-inactive-closed`]: https://github.com/rust-lang/rust-clippy/pulls?q=is%3Aclosed+label%3AS-inactive-closed diff --git a/Cargo.toml b/Cargo.toml index 1cfc1c196c0b6..c7c06afb6129e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy" # begin autogenerated version -version = "0.1.88" +version = "0.1.89" # end autogenerated version description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" @@ -28,7 +28,7 @@ clippy_lints = { path = "clippy_lints" } clippy_utils = { path = "clippy_utils" } rustc_tools_util = { path = "rustc_tools_util", version = "0.4.2" } clippy_lints_internal = { path = "clippy_lints_internal", optional = true } -tempfile = { version = "3.3", optional = true } +tempfile = { version = "3.20", optional = true } termize = "0.1" color-print = "0.3.4" anstream = "0.6.18" @@ -47,7 +47,6 @@ pulldown-cmark = { version = "0.11", default-features = false, features = ["html askama = { version = "0.13", default-features = false, features = ["alloc", "config", "derive"] } # UI test dependencies -clippy_utils = { path = "clippy_utils" } if_chain = "1.0" quote = "1.0.25" syn = { version = "2.0", features = ["full"] } diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index e5e82ede4fdf9..2b89e94cf8f4f 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -416,7 +416,7 @@ In our example, `is_foo_fn` looks like: fn is_foo_fn(fn_kind: FnKind<'_>) -> bool { match fn_kind { - FnKind::Fn(_, ident, ..) => { + FnKind::Fn(_, _, Fn { ident, .. }) => { // check if `fn` name is `foo` ident.name.as_str() == "foo" } diff --git a/book/src/development/basics.md b/book/src/development/basics.md index 4219724ed5df9..cdbbe76bdb08e 100644 --- a/book/src/development/basics.md +++ b/book/src/development/basics.md @@ -145,42 +145,32 @@ unclear to you. If you are hacking on Clippy and want to install it from source, do the following: -First, take note of the toolchain -[override](https://rust-lang.github.io/rustup/overrides.html) in -`/rust-toolchain.toml`. We will use this override to install Clippy into the right -toolchain. - -> Tip: You can view the active toolchain for the current directory with `rustup -> show active-toolchain`. - From the Clippy project root, run the following command to build the Clippy -binaries and copy them into the toolchain directory. This will override the -currently installed Clippy component. +binaries and copy them into the toolchain directory. This will create a new +toolchain called `clippy` by default, see `cargo dev setup toolchain --help` +for other options. ```terminal -cargo build --release --bin cargo-clippy --bin clippy-driver -Zunstable-options --out-dir "$(rustc --print=sysroot)/bin" +cargo dev setup toolcahin ``` -Now you may run `cargo clippy` in any project, using the toolchain where you -just installed Clippy. +Now you may run `cargo +clippy clippy` in any project using the new toolchain. ```terminal cd my-project -cargo +nightly-2021-07-01 clippy +cargo +clippy clippy ``` ...or `clippy-driver` ```terminal -clippy-driver +nightly-2021-07-01 +clippy-driver +clippy ``` -If you need to restore the default Clippy installation, run the following (from -the Clippy project root). +If you no longer need the toolchain it can be uninstalled using `rustup`: ```terminal -rustup component remove clippy -rustup component add clippy +rustup toolchain uninstall clippy ``` > **DO NOT** install using `cargo install --path . --force` since this will diff --git a/book/src/development/common_tools_writing_lints.md b/book/src/development/common_tools_writing_lints.md index 2e39f279eae42..e23b32039c90b 100644 --- a/book/src/development/common_tools_writing_lints.md +++ b/book/src/development/common_tools_writing_lints.md @@ -86,7 +86,7 @@ arguments have to be checked separately. ```rust use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; -use clippy_utils::{paths, match_def_path}; +use clippy_utils::paths; use rustc_span::symbol::sym; use rustc_hir::LangItem; @@ -108,7 +108,7 @@ impl LateLintPass<'_> for MyStructLint { // 3. Using the type path // This method should be avoided if possible - if match_def_path(cx, def_id, &paths::RESULT) { + if paths::RESULT.matches_ty(cx, ty) { // The type is a `core::result::Result` } } diff --git a/book/src/development/infrastructure/changelog_update.md b/book/src/development/infrastructure/changelog_update.md index 2b2c096b0496f..eede6b78d9216 100644 --- a/book/src/development/infrastructure/changelog_update.md +++ b/book/src/development/infrastructure/changelog_update.md @@ -51,7 +51,9 @@ Once you've got the correct commit range, run util/fetch_prs_between.sh commit1 commit2 > changes.txt ``` -and open that file in your editor of choice. +where `commit2` is the commit hash from the previous command and `commit1` +is the commit hash from the current CHANGELOG file. +Open `changes.txt` file in your editor of choice. When updating the changelog it's also a good idea to make sure that `commit1` is already correct in the current changelog. @@ -60,8 +62,8 @@ already correct in the current changelog. The above script should have dumped all the relevant PRs to the file you specified. It should have filtered out most of the irrelevant PRs already, but -it's a good idea to do a manual cleanup pass where you look for more irrelevant -PRs. If you're not sure about some PRs, just leave them in for the review and +it's a good idea to do a manual cleanup pass and choose valuable PRs. +If you're not sure about some PRs, just leave them in for the review and ask for feedback. With the PRs filtered, you can start to take each PR and move the `changelog: ` @@ -74,10 +76,9 @@ The order should roughly be: 2. Moves or deprecations of lints 3. Changes that expand what code existing lints cover 4. False positive fixes -5. Suggestion fixes/improvements -6. ICE fixes -7. Documentation improvements -8. Others +5. ICE fixes +6. Documentation improvements +7. Others As section headers, we use: @@ -91,7 +92,6 @@ As section headers, we use: ### Enhancements ### False Positive Fixes -### Suggestion Fixes/Improvements ### ICE Fixes ### Documentation Improvements ### Others @@ -112,7 +112,16 @@ that label in the changelog. If you can, remove the `beta-accepted` labels ### 4. Update `clippy::version` attributes Next, make sure to check that the `#[clippy::version]` attributes for the added -lints contain the correct version. +lints contain the correct version. +In order to find lints that need a version update, go through the lints in the +"New Lints" section and run the following command for each lint name: + +``` +grep -rB1 "pub $LINT_NAME" . +``` + +The version shown should match the version of the release the changelog is +written for. If not, update the version to the changelog version. [changelog]: https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md [forge]: https://forge.rust-lang.org/ diff --git a/book/src/development/trait_checking.md b/book/src/development/trait_checking.md index b7d229ccc1930..cc4eb966f596a 100644 --- a/book/src/development/trait_checking.md +++ b/book/src/development/trait_checking.md @@ -73,22 +73,24 @@ impl LateLintPass<'_> for CheckDropTraitLint { ## Using Type Path If neither diagnostic item nor a language item is available, we can use -[`clippy_utils::paths`][paths] with the `match_trait_method` to determine trait -implementation. +[`clippy_utils::paths`][paths] to determine get a trait's `DefId`. > **Note**: This approach should be avoided if possible, the best thing to do would be to make a PR to [`rust-lang/rust`][rust] adding a diagnostic item. -Below, we check if the given `expr` implements the `Iterator`'s trait method `cloned` : +Below, we check if the given `expr` implements [`core::iter::Step`](https://doc.rust-lang.org/std/iter/trait.Step.html): ```rust -use clippy_utils::{match_trait_method, paths}; +use clippy_utils::{implements_trait, paths}; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; -impl LateLintPass<'_> for CheckTokioAsyncReadExtTrait { +impl LateLintPass<'_> for CheckIterStep { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if match_trait_method(cx, expr, &paths::CORE_ITER_CLONED) { - println!("`expr` implements `CORE_ITER_CLONED` trait!"); + let ty = cx.typeck_results().expr_ty(expr); + if let Some(trait_def_id) = paths::ITER_STEP.first(cx) + && implements_trait(cx, ty, trait_def_id, &[]) + { + println!("`expr` implements the `core::iter::Step` trait!"); } } } diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 2314d1beac7e0..0db4182dbcdbd 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -71,6 +71,16 @@ Whether `dbg!` should be allowed in test functions or `#[cfg(test)]` * [`dbg_macro`](https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro) +## `allow-exact-repetitions` +Whether an item should be allowed to have the same name as its containing module + +**Default Value:** `true` + +--- +**Affected lints:** +* [`module_name_repetitions`](https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions) + + ## `allow-expect-in-consts` Whether `expect` should be allowed in code always evaluated at compile time @@ -734,6 +744,16 @@ Minimum chars an ident can have, anything below or equal to this will be linted. * [`min_ident_chars`](https://rust-lang.github.io/rust-clippy/master/index.html#min_ident_chars) +## `missing-docs-allow-unused` +Whether to allow fields starting with an underscore to skip documentation requirements + +**Default Value:** `false` + +--- +**Affected lints:** +* [`missing_docs_in_private_items`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items) + + ## `missing-docs-in-crate-items` Whether to **only** check for missing documentation in items visible within the current crate. For example, `pub(crate)` items. @@ -839,6 +859,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`same_item_push`](https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push) * [`seek_from_current`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current) * [`seek_rewind`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_rewind) +* [`to_digit_is_some`](https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some) * [`transmute_ptr_to_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref) * [`tuple_array_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions) * [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds) diff --git a/clippy.toml b/clippy.toml index 0a7724bbe4e61..77573105d86a3 100644 --- a/clippy.toml +++ b/clippy.toml @@ -7,14 +7,11 @@ lint-commented-code = true [[disallowed-methods]] path = "rustc_lint::context::LintContext::lint" reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead" -allow-invalid = true [[disallowed-methods]] path = "rustc_lint::context::LintContext::span_lint" reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead" -allow-invalid = true [[disallowed-methods]] path = "rustc_middle::ty::context::TyCtxt::node_span_lint" reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead" -allow-invalid = true diff --git a/clippy_config/Cargo.toml b/clippy_config/Cargo.toml index 93fd2e35d1ba5..1134b0e97af22 100644 --- a/clippy_config/Cargo.toml +++ b/clippy_config/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_config" # begin autogenerated version -version = "0.1.88" +version = "0.1.89" # end autogenerated version edition = "2024" publish = false diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 511cb84527d80..ad0aea39d41a2 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -360,6 +360,9 @@ define_Conf! { /// Whether `dbg!` should be allowed in test functions or `#[cfg(test)]` #[lints(dbg_macro)] allow_dbg_in_tests: bool = false, + /// Whether an item should be allowed to have the same name as its containing module + #[lints(module_name_repetitions)] + allow_exact_repetitions: bool = true, /// Whether `expect` should be allowed in code always evaluated at compile time #[lints(expect_used)] allow_expect_in_consts: bool = true, @@ -675,6 +678,9 @@ define_Conf! { /// Minimum chars an ident can have, anything below or equal to this will be linted. #[lints(min_ident_chars)] min_ident_chars_threshold: u64 = 1, + /// Whether to allow fields starting with an underscore to skip documentation requirements + #[lints(missing_docs_in_private_items)] + missing_docs_allow_unused: bool = false, /// Whether to **only** check for missing documentation in items visible within the current /// crate. For example, `pub(crate)` items. #[lints(missing_docs_in_private_items)] @@ -756,6 +762,7 @@ define_Conf! { same_item_push, seek_from_current, seek_rewind, + to_digit_is_some, transmute_ptr_to_ref, tuple_array_conversions, type_repetition_in_bounds, diff --git a/clippy_config/src/lib.rs b/clippy_config/src/lib.rs index c227b8900b74a..67904b4fcdc85 100644 --- a/clippy_config/src/lib.rs +++ b/clippy_config/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private, array_windows, let_chains)] +#![feature(rustc_private)] #![warn( trivial_casts, trivial_numeric_casts, @@ -12,6 +12,7 @@ rustc::diagnostic_outside_of_impl, rustc::untranslatable_diagnostic )] +#![deny(clippy::derive_deserialize_allowing_unknown)] extern crate rustc_data_structures; extern crate rustc_errors; diff --git a/clippy_config/src/types.rs b/clippy_config/src/types.rs index 5949eaca7bc1d..f64eefa0c232d 100644 --- a/clippy_config/src/types.rs +++ b/clippy_config/src/types.rs @@ -1,16 +1,18 @@ +use clippy_utils::paths::{PathNS, find_crates, lookup_path}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, Diag}; use rustc_hir::PrimTy; -use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def::DefKind; use rustc_hir::def_id::DefIdMap; use rustc_middle::ty::TyCtxt; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use serde::de::{self, Deserializer, Visitor}; use serde::{Deserialize, Serialize, ser}; use std::collections::HashMap; use std::fmt; #[derive(Debug, Deserialize)] +#[serde(deny_unknown_fields)] pub struct Rename { pub path: String, pub rename: String, @@ -58,7 +60,7 @@ impl<'de, const REPLACEMENT_ALLOWED: bool> Deserialize<'de> for DisallowedPath( tcx: TyCtxt<'_>, disallowed_paths: &'static [DisallowedPath], + ns: PathNS, def_kind_predicate: impl Fn(DefKind) -> bool, predicate_description: &str, allow_prim_tys: bool, @@ -145,57 +148,47 @@ pub fn create_disallowed_map( FxHashMap::default(); for disallowed_path in disallowed_paths { let path = disallowed_path.path(); - let mut resolutions = clippy_utils::def_path_res(tcx, &path.split("::").collect::>()); - - let mut found_def_id = None; - let mut found_prim_ty = false; - resolutions.retain(|res| match res { - Res::Def(def_kind, def_id) => { - found_def_id = Some(*def_id); - def_kind_predicate(*def_kind) - }, - Res::PrimTy(_) => { - found_prim_ty = true; - allow_prim_tys - }, - _ => false, - }); - - if resolutions.is_empty() { - let span = disallowed_path.span(); - - if let Some(def_id) = found_def_id { - tcx.sess.dcx().span_warn( - span, - format!( - "expected a {predicate_description}, found {} {}", - tcx.def_descr_article(def_id), - tcx.def_descr(def_id) - ), - ); + let sym_path: Vec = path.split("::").map(Symbol::intern).collect(); + let mut resolutions = lookup_path(tcx, ns, &sym_path); + resolutions.retain(|&def_id| def_kind_predicate(tcx.def_kind(def_id))); + + let (prim_ty, found_prim_ty) = if let &[name] = sym_path.as_slice() + && let Some(prim) = PrimTy::from_name(name) + { + (allow_prim_tys.then_some(prim), true) + } else { + (None, false) + }; + + if resolutions.is_empty() + && prim_ty.is_none() + && !disallowed_path.allow_invalid + // Don't warn about unloaded crates: + // https://github.com/rust-lang/rust-clippy/pull/14397#issuecomment-2848328221 + && (sym_path.len() < 2 || !find_crates(tcx, sym_path[0]).is_empty()) + { + // Relookup the path in an arbitrary namespace to get a good `expected, found` message + let found_def_ids = lookup_path(tcx, PathNS::Arbitrary, &sym_path); + let message = if let Some(&def_id) = found_def_ids.first() { + let (article, description) = tcx.article_and_description(def_id); + format!("expected a {predicate_description}, found {article} {description}") } else if found_prim_ty { - tcx.sess.dcx().span_warn( - span, - format!("expected a {predicate_description}, found a primitive type",), - ); - } else if !disallowed_path.allow_invalid { - tcx.sess.dcx().span_warn( - span, - format!("`{path}` does not refer to an existing {predicate_description}"), - ); - } + format!("expected a {predicate_description}, found a primitive type") + } else { + format!("`{path}` does not refer to a reachable {predicate_description}") + }; + tcx.sess + .dcx() + .struct_span_warn(disallowed_path.span(), message) + .with_help("add `allow-invalid = true` to the entry to suppress this warning") + .emit(); } - for res in resolutions { - match res { - Res::Def(_, def_id) => { - def_ids.insert(def_id, (path, disallowed_path)); - }, - Res::PrimTy(ty) => { - prim_tys.insert(ty, (path, disallowed_path)); - }, - _ => unreachable!(), - } + for def_id in resolutions { + def_ids.insert(def_id, (path, disallowed_path)); + } + if let Some(ty) = prim_ty { + prim_tys.insert(ty, (path, disallowed_path)); } } diff --git a/clippy_dev/src/deprecate_lint.rs b/clippy_dev/src/deprecate_lint.rs new file mode 100644 index 0000000000000..bf0e777104698 --- /dev/null +++ b/clippy_dev/src/deprecate_lint.rs @@ -0,0 +1,174 @@ +use crate::update_lints::{ + DeprecatedLint, DeprecatedLints, Lint, find_lint_decls, generate_lint_files, read_deprecated_lints, +}; +use crate::utils::{UpdateMode, Version}; +use std::ffi::OsStr; +use std::path::{Path, PathBuf}; +use std::{fs, io}; + +/// Runs the `deprecate` command +/// +/// This does the following: +/// * Adds an entry to `deprecated_lints.rs`. +/// * Removes the lint declaration (and the entire file if applicable) +/// +/// # Panics +/// +/// If a file path could not read from or written to +pub fn deprecate(clippy_version: Version, name: &str, reason: &str) { + let prefixed_name = if name.starts_with("clippy::") { + name.to_owned() + } else { + format!("clippy::{name}") + }; + let stripped_name = &prefixed_name[8..]; + + let mut lints = find_lint_decls(); + let DeprecatedLints { + renamed: renamed_lints, + deprecated: mut deprecated_lints, + file: mut deprecated_file, + contents: mut deprecated_contents, + deprecated_end, + .. + } = read_deprecated_lints(); + + let Some(lint) = lints.iter().find(|l| l.name == stripped_name) else { + eprintln!("error: failed to find lint `{name}`"); + return; + }; + + let mod_path = { + let mut mod_path = PathBuf::from(format!("clippy_lints/src/{}", lint.module)); + if mod_path.is_dir() { + mod_path = mod_path.join("mod"); + } + + mod_path.set_extension("rs"); + mod_path + }; + + if remove_lint_declaration(stripped_name, &mod_path, &mut lints).unwrap_or(false) { + deprecated_contents.insert_str( + deprecated_end as usize, + &format!( + " #[clippy::version = \"{}\"]\n (\"{}\", \"{}\"),\n", + clippy_version.rust_display(), + prefixed_name, + reason, + ), + ); + deprecated_file.replace_contents(deprecated_contents.as_bytes()); + drop(deprecated_file); + + deprecated_lints.push(DeprecatedLint { + name: prefixed_name, + reason: reason.into(), + }); + + generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); + println!("info: `{name}` has successfully been deprecated"); + println!("note: you must run `cargo uitest` to update the test results"); + } else { + eprintln!("error: lint not found"); + } +} + +fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec) -> io::Result { + fn remove_lint(name: &str, lints: &mut Vec) { + lints.iter().position(|l| l.name == name).map(|pos| lints.remove(pos)); + } + + fn remove_test_assets(name: &str) { + let test_file_stem = format!("tests/ui/{name}"); + let path = Path::new(&test_file_stem); + + // Some lints have their own directories, delete them + if path.is_dir() { + let _ = fs::remove_dir_all(path); + return; + } + + // Remove all related test files + let _ = fs::remove_file(path.with_extension("rs")); + let _ = fs::remove_file(path.with_extension("stderr")); + let _ = fs::remove_file(path.with_extension("fixed")); + } + + fn remove_impl_lint_pass(lint_name_upper: &str, content: &mut String) { + let impl_lint_pass_start = content.find("impl_lint_pass!").unwrap_or_else(|| { + content + .find("declare_lint_pass!") + .unwrap_or_else(|| panic!("failed to find `impl_lint_pass`")) + }); + let mut impl_lint_pass_end = content[impl_lint_pass_start..] + .find(']') + .expect("failed to find `impl_lint_pass` terminator"); + + impl_lint_pass_end += impl_lint_pass_start; + if let Some(lint_name_pos) = content[impl_lint_pass_start..impl_lint_pass_end].find(lint_name_upper) { + let mut lint_name_end = impl_lint_pass_start + (lint_name_pos + lint_name_upper.len()); + for c in content[lint_name_end..impl_lint_pass_end].chars() { + // Remove trailing whitespace + if c == ',' || c.is_whitespace() { + lint_name_end += 1; + } else { + break; + } + } + + content.replace_range(impl_lint_pass_start + lint_name_pos..lint_name_end, ""); + } + } + + if path.exists() + && let Some(lint) = lints.iter().find(|l| l.name == name) + { + if lint.module == name { + // The lint name is the same as the file, we can just delete the entire file + fs::remove_file(path)?; + } else { + // We can't delete the entire file, just remove the declaration + + if let Some(Some("mod.rs")) = path.file_name().map(OsStr::to_str) { + // Remove clippy_lints/src/some_mod/some_lint.rs + let mut lint_mod_path = path.to_path_buf(); + lint_mod_path.set_file_name(name); + lint_mod_path.set_extension("rs"); + + let _ = fs::remove_file(lint_mod_path); + } + + let mut content = + fs::read_to_string(path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy())); + + eprintln!( + "warn: you will have to manually remove any code related to `{name}` from `{}`", + path.display() + ); + + assert!( + content[lint.declaration_range.clone()].contains(&name.to_uppercase()), + "error: `{}` does not contain lint `{}`'s declaration", + path.display(), + lint.name + ); + + // Remove lint declaration (declare_clippy_lint!) + content.replace_range(lint.declaration_range.clone(), ""); + + // Remove the module declaration (mod xyz;) + let mod_decl = format!("\nmod {name};"); + content = content.replacen(&mod_decl, "", 1); + + remove_impl_lint_pass(&lint.name.to_uppercase(), &mut content); + fs::write(path, content).unwrap_or_else(|_| panic!("failed to write to `{}`", path.to_string_lossy())); + } + + remove_test_assets(name); + remove_lint(name, lints); + return Ok(true); + } + + Ok(false) +} diff --git a/clippy_dev/src/dogfood.rs b/clippy_dev/src/dogfood.rs index 05fa24d8d4ee5..7e9d92458d057 100644 --- a/clippy_dev/src/dogfood.rs +++ b/clippy_dev/src/dogfood.rs @@ -1,4 +1,4 @@ -use crate::utils::{clippy_project_root, exit_if_err}; +use crate::utils::exit_if_err; use std::process::Command; /// # Panics @@ -8,8 +8,7 @@ use std::process::Command; pub fn dogfood(fix: bool, allow_dirty: bool, allow_staged: bool, allow_no_vcs: bool) { let mut cmd = Command::new("cargo"); - cmd.current_dir(clippy_project_root()) - .args(["test", "--test", "dogfood"]) + cmd.args(["test", "--test", "dogfood"]) .args(["--features", "internal"]) .args(["--", "dogfood_clippy", "--nocapture"]); diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index bdddf46a2cb19..b4c13213f552a 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -1,4 +1,3 @@ -use crate::utils::clippy_project_root; use itertools::Itertools; use rustc_lexer::{TokenKind, tokenize}; use shell_escape::escape; @@ -104,15 +103,8 @@ fn fmt_conf(check: bool) -> Result<(), Error> { Field, } - let path: PathBuf = [ - clippy_project_root().as_path(), - "clippy_config".as_ref(), - "src".as_ref(), - "conf.rs".as_ref(), - ] - .into_iter() - .collect(); - let text = fs::read_to_string(&path)?; + let path = "clippy_config/src/conf.rs"; + let text = fs::read_to_string(path)?; let (pre, conf) = text .split_once("define_Conf! {\n") @@ -203,7 +195,7 @@ fn fmt_conf(check: bool) -> Result<(), Error> { | (State::Lints, TokenKind::Comma | TokenKind::OpenParen | TokenKind::CloseParen) => {}, _ => { return Err(Error::Parse( - path, + PathBuf::from(path), offset_to_line(&text, conf_offset + i), format!("unexpected token `{}`", &conf[i..i + t.len as usize]), )); @@ -213,7 +205,7 @@ fn fmt_conf(check: bool) -> Result<(), Error> { if !matches!(state, State::Field) { return Err(Error::Parse( - path, + PathBuf::from(path), offset_to_line(&text, conf_offset + conf.len()), "incomplete field".into(), )); @@ -260,18 +252,16 @@ fn fmt_conf(check: bool) -> Result<(), Error> { if check { return Err(Error::CheckFailed); } - fs::write(&path, new_text.as_bytes())?; + fs::write(path, new_text.as_bytes())?; } Ok(()) } fn run_rustfmt(context: &FmtContext) -> Result<(), Error> { - let project_root = clippy_project_root(); - // if we added a local rustc repo as path dependency to clippy for rust analyzer, we do NOT want to // format because rustfmt would also format the entire rustc repo as it is a local // dependency - if fs::read_to_string(project_root.join("Cargo.toml")) + if fs::read_to_string("Cargo.toml") .expect("Failed to read clippy Cargo.toml") .contains("[target.'cfg(NOT_A_PLATFORM)'.dependencies]") { @@ -280,12 +270,12 @@ fn run_rustfmt(context: &FmtContext) -> Result<(), Error> { check_for_rustfmt(context)?; - cargo_fmt(context, project_root.as_path())?; - cargo_fmt(context, &project_root.join("clippy_dev"))?; - cargo_fmt(context, &project_root.join("rustc_tools_util"))?; - cargo_fmt(context, &project_root.join("lintcheck"))?; + cargo_fmt(context, ".".as_ref())?; + cargo_fmt(context, "clippy_dev".as_ref())?; + cargo_fmt(context, "rustc_tools_util".as_ref())?; + cargo_fmt(context, "lintcheck".as_ref())?; - let chunks = WalkDir::new(project_root.join("tests")) + let chunks = WalkDir::new("tests") .into_iter() .filter_map(|entry| { let entry = entry.expect("failed to find tests"); diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index c1ffaf269c6fe..e237a05b2530e 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -1,5 +1,4 @@ -#![feature(let_chains)] -#![feature(rustc_private)] +#![feature(rustc_private, if_let_guard, let_chains)] #![warn( trivial_casts, trivial_numeric_casts, @@ -15,11 +14,13 @@ extern crate rustc_driver; extern crate rustc_lexer; extern crate rustc_literal_escaper; +pub mod deprecate_lint; pub mod dogfood; pub mod fmt; pub mod lint; pub mod new_lint; pub mod release; +pub mod rename_lint; pub mod serve; pub mod setup; pub mod sync; diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 83f8e66b33476..5dce0be742b26 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -3,11 +3,18 @@ #![warn(rust_2018_idioms, unused_lifetimes)] use clap::{Args, Parser, Subcommand}; -use clippy_dev::{dogfood, fmt, lint, new_lint, release, serve, setup, sync, update_lints, utils}; +use clippy_dev::{ + deprecate_lint, dogfood, fmt, lint, new_lint, release, rename_lint, serve, setup, sync, update_lints, utils, +}; use std::convert::Infallible; +use std::env; fn main() { let dev = Dev::parse(); + let clippy = utils::ClippyInfo::search_for_manifest(); + if let Err(e) = env::set_current_dir(&clippy.path) { + panic!("error setting current directory to `{}`: {e}", clippy.path.display()); + } match dev.command { DevCommand::Bless => { @@ -20,22 +27,14 @@ fn main() { allow_no_vcs, } => dogfood::dogfood(fix, allow_dirty, allow_staged, allow_no_vcs), DevCommand::Fmt { check, verbose } => fmt::run(check, verbose), - DevCommand::UpdateLints { print_only, check } => { - if print_only { - update_lints::print_lints(); - } else if check { - update_lints::update(utils::UpdateMode::Check); - } else { - update_lints::update(utils::UpdateMode::Change); - } - }, + DevCommand::UpdateLints { check } => update_lints::update(utils::UpdateMode::from_check(check)), DevCommand::NewLint { pass, name, category, r#type, msrv, - } => match new_lint::create(pass, &name, &category, r#type.as_deref(), msrv) { + } => match new_lint::create(clippy.version, pass, &name, &category, r#type.as_deref(), msrv) { Ok(()) => update_lints::update(utils::UpdateMode::Change), Err(e) => eprintln!("Unable to create lint: {e}"), }, @@ -79,13 +78,18 @@ fn main() { old_name, new_name, uplift, - } => update_lints::rename(&old_name, new_name.as_ref().unwrap_or(&old_name), uplift), - DevCommand::Deprecate { name, reason } => update_lints::deprecate(&name, &reason), + } => rename_lint::rename( + clippy.version, + &old_name, + new_name.as_ref().unwrap_or(&old_name), + uplift, + ), + DevCommand::Deprecate { name, reason } => deprecate_lint::deprecate(clippy.version, &name, &reason), DevCommand::Sync(SyncCommand { subcommand }) => match subcommand { SyncSubcommand::UpdateNightly => sync::update_nightly(), }, DevCommand::Release(ReleaseCommand { subcommand }) => match subcommand { - ReleaseSubcommand::BumpVersion => release::bump_version(), + ReleaseSubcommand::BumpVersion => release::bump_version(clippy.version), }, } } @@ -135,11 +139,6 @@ enum DevCommand { /// * lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod` {n} /// * all lints are registered in the lint store UpdateLints { - #[arg(long)] - /// Print a table of lints to STDOUT - /// - /// This does not include deprecated and internal lints. (Does not modify any files) - print_only: bool, #[arg(long)] /// Checks that `cargo dev update_lints` has been run. Used on CI. check: bool, diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 96e12706c9e24..4121daa85e6d7 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -1,4 +1,4 @@ -use crate::utils::{clippy_project_root, clippy_version}; +use crate::utils::{RustSearcher, Token, Version}; use clap::ValueEnum; use indoc::{formatdoc, writedoc}; use std::fmt::{self, Write as _}; @@ -22,11 +22,11 @@ impl fmt::Display for Pass { } struct LintData<'a> { + clippy_version: Version, pass: Pass, name: &'a str, category: &'a str, ty: Option<&'a str>, - project_root: PathBuf, } trait Context { @@ -50,18 +50,25 @@ impl Context for io::Result { /// # Errors /// /// This function errors out if the files couldn't be created or written to. -pub fn create(pass: Pass, name: &str, category: &str, mut ty: Option<&str>, msrv: bool) -> io::Result<()> { +pub fn create( + clippy_version: Version, + pass: Pass, + name: &str, + category: &str, + mut ty: Option<&str>, + msrv: bool, +) -> io::Result<()> { if category == "cargo" && ty.is_none() { // `cargo` is a special category, these lints should always be in `clippy_lints/src/cargo` ty = Some("cargo"); } let lint = LintData { + clippy_version, pass, name, category, ty, - project_root: clippy_project_root(), }; create_lint(&lint, msrv).context("Unable to create lint implementation")?; @@ -88,7 +95,7 @@ fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { } else { let lint_contents = get_lint_file_contents(lint, enable_msrv); let lint_path = format!("clippy_lints/src/{}.rs", lint.name); - write_file(lint.project_root.join(&lint_path), lint_contents.as_bytes())?; + write_file(&lint_path, lint_contents.as_bytes())?; println!("Generated lint file: `{lint_path}`"); Ok(()) @@ -115,8 +122,7 @@ fn create_test(lint: &LintData<'_>, msrv: bool) -> io::Result<()> { } if lint.category == "cargo" { - let relative_test_dir = format!("tests/ui-cargo/{}", lint.name); - let test_dir = lint.project_root.join(&relative_test_dir); + let test_dir = format!("tests/ui-cargo/{}", lint.name); fs::create_dir(&test_dir)?; create_project_layout( @@ -134,11 +140,11 @@ fn create_test(lint: &LintData<'_>, msrv: bool) -> io::Result<()> { false, )?; - println!("Generated test directories: `{relative_test_dir}/pass`, `{relative_test_dir}/fail`"); + println!("Generated test directories: `{test_dir}/pass`, `{test_dir}/fail`"); } else { let test_path = format!("tests/ui/{}.rs", lint.name); let test_contents = get_test_file_contents(lint.name, msrv); - write_file(lint.project_root.join(&test_path), test_contents)?; + write_file(&test_path, test_contents)?; println!("Generated test file: `{test_path}`"); } @@ -193,11 +199,6 @@ fn to_camel_case(name: &str) -> String { .collect() } -pub(crate) fn get_stabilization_version() -> String { - let (minor, patch) = clippy_version(); - format!("{minor}.{patch}.0") -} - fn get_test_file_contents(lint_name: &str, msrv: bool) -> String { let mut test = formatdoc!( r" @@ -292,7 +293,11 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { ); } - let _: fmt::Result = writeln!(result, "{}", get_lint_declaration(&name_upper, category)); + let _: fmt::Result = writeln!( + result, + "{}", + get_lint_declaration(lint.clippy_version, &name_upper, category) + ); if enable_msrv { let _: fmt::Result = writedoc!( @@ -330,7 +335,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { result } -fn get_lint_declaration(name_upper: &str, category: &str) -> String { +fn get_lint_declaration(version: Version, name_upper: &str, category: &str) -> String { let justification_heading = if category == "restriction" { "Why restrict this?" } else { @@ -355,9 +360,8 @@ fn get_lint_declaration(name_upper: &str, category: &str) -> String { pub {name_upper}, {category}, "default lint description" - }} - "#, - get_stabilization_version(), + }}"#, + version.rust_display(), ) } @@ -371,7 +375,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R _ => {}, } - let ty_dir = lint.project_root.join(format!("clippy_lints/src/{ty}")); + let ty_dir = PathBuf::from(format!("clippy_lints/src/{ty}")); assert!( ty_dir.exists() && ty_dir.is_dir(), "Directory `{}` does not exist!", @@ -441,95 +445,25 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R #[allow(clippy::too_many_lines)] fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str> { - use super::update_lints::{LintDeclSearchResult, match_tokens}; - use rustc_lexer::TokenKind; - let lint_name_upper = lint.name.to_uppercase(); let mut file_contents = fs::read_to_string(path)?; assert!( - !file_contents.contains(&lint_name_upper), + !file_contents.contains(&format!("pub {lint_name_upper},")), "Lint `{}` already defined in `{}`", lint.name, path.display() ); - let mut offset = 0usize; - let mut last_decl_curly_offset = None; - let mut lint_context = None; - - let mut iter = rustc_lexer::tokenize(&file_contents).map(|t| { - let range = offset..offset + t.len as usize; - offset = range.end; - - LintDeclSearchResult { - token_kind: t.kind, - content: &file_contents[range.clone()], - range, - } - }); - - // Find both the last lint declaration (declare_clippy_lint!) and the lint pass impl - while let Some(LintDeclSearchResult { content, .. }) = iter.find(|result| result.token_kind == TokenKind::Ident) { - let mut iter = iter - .by_ref() - .filter(|t| !matches!(t.token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. })); - - match content { - "declare_clippy_lint" => { - // matches `!{` - match_tokens!(iter, Bang OpenBrace); - if let Some(LintDeclSearchResult { range, .. }) = - iter.find(|result| result.token_kind == TokenKind::CloseBrace) - { - last_decl_curly_offset = Some(range.end); - } - }, - "impl" => { - let mut token = iter.next(); - match token { - // matches <'foo> - Some(LintDeclSearchResult { - token_kind: TokenKind::Lt, - .. - }) => { - match_tokens!(iter, Lifetime { .. } Gt); - token = iter.next(); - }, - None => break, - _ => {}, - } - - if let Some(LintDeclSearchResult { - token_kind: TokenKind::Ident, - content, - .. - }) = token - { - // Get the appropriate lint context struct - lint_context = match content { - "LateLintPass" => Some("LateContext"), - "EarlyLintPass" => Some("EarlyContext"), - _ => continue, - }; - } - }, - _ => {}, - } - } - - drop(iter); - - let last_decl_curly_offset = - last_decl_curly_offset.unwrap_or_else(|| panic!("No lint declarations found in `{}`", path.display())); - let lint_context = - lint_context.unwrap_or_else(|| panic!("No lint pass implementation found in `{}`", path.display())); + let (lint_context, lint_decl_end) = parse_mod_file(path, &file_contents); // Add the lint declaration to `mod.rs` - file_contents.replace_range( - // Remove the trailing newline, which should always be present - last_decl_curly_offset..=last_decl_curly_offset, - &format!("\n\n{}", get_lint_declaration(&lint_name_upper, lint.category)), + file_contents.insert_str( + lint_decl_end, + &format!( + "\n\n{}", + get_lint_declaration(lint.clippy_version, &lint_name_upper, lint.category) + ), ); // Add the lint to `impl_lint_pass`/`declare_lint_pass` @@ -580,6 +514,41 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str> Ok(lint_context) } +// Find both the last lint declaration (declare_clippy_lint!) and the lint pass impl +fn parse_mod_file(path: &Path, contents: &str) -> (&'static str, usize) { + #[allow(clippy::enum_glob_use)] + use Token::*; + + let mut context = None; + let mut decl_end = None; + let mut searcher = RustSearcher::new(contents); + while let Some(name) = searcher.find_capture_token(CaptureIdent) { + match name { + "declare_clippy_lint" => { + if searcher.match_tokens(&[Bang, OpenBrace], &mut []) && searcher.find_token(CloseBrace) { + decl_end = Some(searcher.pos()); + } + }, + "impl" => { + let mut capture = ""; + if searcher.match_tokens(&[Lt, Lifetime, Gt, CaptureIdent], &mut [&mut capture]) { + match capture { + "LateLintPass" => context = Some("LateContext"), + "EarlyLintPass" => context = Some("EarlyContext"), + _ => {}, + } + } + }, + _ => {}, + } + } + + ( + context.unwrap_or_else(|| panic!("No lint pass implementation found in `{}`", path.display())), + decl_end.unwrap_or_else(|| panic!("No lint declarations found in `{}`", path.display())) as usize, + ) +} + #[test] fn test_camel_case() { let s = "a_lint"; diff --git a/clippy_dev/src/release.rs b/clippy_dev/src/release.rs index ac75516870103..d3b1a7ff3201f 100644 --- a/clippy_dev/src/release.rs +++ b/clippy_dev/src/release.rs @@ -1,27 +1,27 @@ +use crate::utils::{FileUpdater, Version, update_text_region_fn}; use std::fmt::Write; -use std::path::Path; -use crate::utils::{UpdateMode, clippy_version, replace_region_in_file}; - -const CARGO_TOML_FILES: [&str; 4] = [ +static CARGO_TOML_FILES: &[&str] = &[ "clippy_config/Cargo.toml", "clippy_lints/Cargo.toml", "clippy_utils/Cargo.toml", "Cargo.toml", ]; -pub fn bump_version() { - let (minor, mut patch) = clippy_version(); - patch += 1; - for file in &CARGO_TOML_FILES { - replace_region_in_file( - UpdateMode::Change, - Path::new(file), - "# begin autogenerated version\n", - "# end autogenerated version", - |res| { - writeln!(res, "version = \"0.{minor}.{patch}\"").unwrap(); - }, +pub fn bump_version(mut version: Version) { + version.minor += 1; + + let mut updater = FileUpdater::default(); + for file in CARGO_TOML_FILES { + updater.update_file( + file, + &mut update_text_region_fn( + "# begin autogenerated version\n", + "# end autogenerated version", + |dst| { + writeln!(dst, "version = \"{}\"", version.toml_display()).unwrap(); + }, + ), ); } } diff --git a/clippy_dev/src/rename_lint.rs b/clippy_dev/src/rename_lint.rs new file mode 100644 index 0000000000000..9e7e5d97f0219 --- /dev/null +++ b/clippy_dev/src/rename_lint.rs @@ -0,0 +1,194 @@ +use crate::update_lints::{ + DeprecatedLints, RenamedLint, find_lint_decls, gen_renamed_lints_test_fn, generate_lint_files, + read_deprecated_lints, +}; +use crate::utils::{FileUpdater, StringReplacer, UpdateMode, Version, try_rename_file}; +use std::ffi::OsStr; +use std::path::Path; +use walkdir::WalkDir; + +/// Runs the `rename_lint` command. +/// +/// This does the following: +/// * Adds an entry to `renamed_lints.rs`. +/// * Renames all lint attributes to the new name (e.g. `#[allow(clippy::lint_name)]`). +/// * Renames the lint struct to the new name. +/// * Renames the module containing the lint struct to the new name if it shares a name with the +/// lint. +/// +/// # Panics +/// Panics for the following conditions: +/// * If a file path could not read from or then written to +/// * If either lint name has a prefix +/// * If `old_name` doesn't name an existing lint. +/// * If `old_name` names a deprecated or renamed lint. +#[allow(clippy::too_many_lines)] +pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: bool) { + if let Some((prefix, _)) = old_name.split_once("::") { + panic!("`{old_name}` should not contain the `{prefix}` prefix"); + } + if let Some((prefix, _)) = new_name.split_once("::") { + panic!("`{new_name}` should not contain the `{prefix}` prefix"); + } + + let mut updater = FileUpdater::default(); + let mut lints = find_lint_decls(); + let DeprecatedLints { + renamed: mut renamed_lints, + deprecated: deprecated_lints, + file: mut deprecated_file, + contents: mut deprecated_contents, + renamed_end, + .. + } = read_deprecated_lints(); + + let mut old_lint_index = None; + let mut found_new_name = false; + for (i, lint) in lints.iter().enumerate() { + if lint.name == old_name { + old_lint_index = Some(i); + } else if lint.name == new_name { + found_new_name = true; + } + } + let old_lint_index = old_lint_index.unwrap_or_else(|| panic!("could not find lint `{old_name}`")); + + let lint = RenamedLint { + old_name: format!("clippy::{old_name}"), + new_name: if uplift { + new_name.into() + } else { + format!("clippy::{new_name}") + }, + }; + + // Renamed lints and deprecated lints shouldn't have been found in the lint list, but check just in + // case. + assert!( + !renamed_lints.iter().any(|l| lint.old_name == l.old_name), + "`{old_name}` has already been renamed" + ); + assert!( + !deprecated_lints.iter().any(|l| lint.old_name == l.name), + "`{old_name}` has already been deprecated" + ); + + // Update all lint level attributes. (`clippy::lint_name`) + let replacements = &[(&*lint.old_name, &*lint.new_name)]; + let replacer = StringReplacer::new(replacements); + for file in WalkDir::new(".").into_iter().map(Result::unwrap).filter(|f| { + let name = f.path().file_name(); + let ext = f.path().extension(); + (ext == Some(OsStr::new("rs")) || ext == Some(OsStr::new("fixed"))) + && name != Some(OsStr::new("rename.rs")) + && name != Some(OsStr::new("deprecated_lints.rs")) + }) { + updater.update_file(file.path(), &mut replacer.replace_ident_fn()); + } + + deprecated_contents.insert_str( + renamed_end as usize, + &format!( + " #[clippy::version = \"{}\"]\n (\"{}\", \"{}\"),\n", + clippy_version.rust_display(), + lint.old_name, + lint.new_name, + ), + ); + deprecated_file.replace_contents(deprecated_contents.as_bytes()); + drop(deprecated_file); + + renamed_lints.push(lint); + renamed_lints.sort_by(|lhs, rhs| { + lhs.new_name + .starts_with("clippy::") + .cmp(&rhs.new_name.starts_with("clippy::")) + .reverse() + .then_with(|| lhs.old_name.cmp(&rhs.old_name)) + }); + + if uplift { + updater.update_file("tests/ui/rename.rs", &mut gen_renamed_lints_test_fn(&renamed_lints)); + println!( + "`{old_name}` has be uplifted. All the code inside `clippy_lints` related to it needs to be removed manually." + ); + } else if found_new_name { + updater.update_file("tests/ui/rename.rs", &mut gen_renamed_lints_test_fn(&renamed_lints)); + println!( + "`{new_name}` is already defined. The old linting code inside `clippy_lints` needs to be updated/removed manually." + ); + } else { + // Rename the lint struct and source files sharing a name with the lint. + let lint = &mut lints[old_lint_index]; + let old_name_upper = old_name.to_uppercase(); + let new_name_upper = new_name.to_uppercase(); + lint.name = new_name.into(); + + // Rename test files. only rename `.stderr` and `.fixed` files if the new test name doesn't exist. + if try_rename_file( + Path::new(&format!("tests/ui/{old_name}.rs")), + Path::new(&format!("tests/ui/{new_name}.rs")), + ) { + try_rename_file( + Path::new(&format!("tests/ui/{old_name}.stderr")), + Path::new(&format!("tests/ui/{new_name}.stderr")), + ); + try_rename_file( + Path::new(&format!("tests/ui/{old_name}.fixed")), + Path::new(&format!("tests/ui/{new_name}.fixed")), + ); + } + + // Try to rename the file containing the lint if the file name matches the lint's name. + let replacements; + let replacements = if lint.module == old_name + && try_rename_file( + Path::new(&format!("clippy_lints/src/{old_name}.rs")), + Path::new(&format!("clippy_lints/src/{new_name}.rs")), + ) { + // Edit the module name in the lint list. Note there could be multiple lints. + for lint in lints.iter_mut().filter(|l| l.module == old_name) { + lint.module = new_name.into(); + } + replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)]; + replacements.as_slice() + } else if !lint.module.contains("::") + // Catch cases like `methods/lint_name.rs` where the lint is stored in `methods/mod.rs` + && try_rename_file( + Path::new(&format!("clippy_lints/src/{}/{old_name}.rs", lint.module)), + Path::new(&format!("clippy_lints/src/{}/{new_name}.rs", lint.module)), + ) + { + // Edit the module name in the lint list. Note there could be multiple lints, or none. + let renamed_mod = format!("{}::{old_name}", lint.module); + for lint in lints.iter_mut().filter(|l| l.module == renamed_mod) { + lint.module = format!("{}::{new_name}", lint.module); + } + replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)]; + replacements.as_slice() + } else { + replacements = [(&*old_name_upper, &*new_name_upper), ("", "")]; + &replacements[0..1] + }; + + // Don't change `clippy_utils/src/renamed_lints.rs` here as it would try to edit the lint being + // renamed. + let replacer = StringReplacer::new(replacements); + for file in WalkDir::new("clippy_lints/src") { + let file = file.expect("error reading `clippy_lints/src`"); + if file + .path() + .as_os_str() + .to_str() + .is_some_and(|x| x.ends_with("*.rs") && x["clippy_lints/src/".len()..] != *"deprecated_lints.rs") + { + updater.update_file(file.path(), &mut replacer.replace_ident_fn()); + } + } + + generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); + println!("{old_name} has been successfully renamed"); + } + + println!("note: `cargo uitest` still needs to be run to update the test results"); +} diff --git a/clippy_dev/src/sync.rs b/clippy_dev/src/sync.rs index a6b65e561c223..c699b0d7b959c 100644 --- a/clippy_dev/src/sync.rs +++ b/clippy_dev/src/sync.rs @@ -1,33 +1,18 @@ -use std::fmt::Write; -use std::path::Path; - +use crate::utils::{FileUpdater, update_text_region_fn}; use chrono::offset::Utc; - -use crate::utils::{UpdateMode, replace_region_in_file}; +use std::fmt::Write; pub fn update_nightly() { - // Update rust-toolchain nightly version let date = Utc::now().format("%Y-%m-%d").to_string(); - replace_region_in_file( - UpdateMode::Change, - Path::new("rust-toolchain.toml"), + let update = &mut update_text_region_fn( "# begin autogenerated nightly\n", "# end autogenerated nightly", - |res| { - writeln!(res, "channel = \"nightly-{date}\"").unwrap(); + |dst| { + writeln!(dst, "channel = \"nightly-{date}\"").unwrap(); }, ); - // Update clippy_utils nightly version - replace_region_in_file( - UpdateMode::Change, - Path::new("clippy_utils/README.md"), - "\n", - "", - |res| { - writeln!(res, "```").unwrap(); - writeln!(res, "nightly-{date}").unwrap(); - writeln!(res, "```").unwrap(); - }, - ); + let mut updater = FileUpdater::default(); + updater.update_file("rust-toolchain.toml", update); + updater.update_file("clippy_utils/README.md", update); } diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index d848a97f86d2f..0c861b7293562 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -1,15 +1,12 @@ -use crate::utils::{UpdateMode, clippy_project_root, exit_with_failure, replace_region_in_file}; -use aho_corasick::AhoCorasickBuilder; +use crate::utils::{ + File, FileAction, FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, panic_file, update_text_region_fn, +}; use itertools::Itertools; -use rustc_lexer::{LiteralKind, TokenKind, tokenize}; -use rustc_literal_escaper::{Mode, unescape_unicode}; -use std::collections::{HashMap, HashSet}; -use std::ffi::OsStr; -use std::fmt::{self, Write}; -use std::fs::{self, OpenOptions}; -use std::io::{self, Read, Seek, Write as _}; +use std::collections::HashSet; +use std::fmt::Write; +use std::fs::OpenOptions; use std::ops::Range; -use std::path::{Path, PathBuf}; +use std::path::Path; use walkdir::{DirEntry, WalkDir}; const GENERATED_FILE_COMMENT: &str = "// This file was generated by `cargo dev update_lints`.\n\ @@ -28,839 +25,322 @@ const DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.ht%20///%20///%20Panics%20if%20a%20file%20path%20could%20not%20read%20from%20or%20then%20written%20to%20pub%20fn%20update(update_mode:%20UpdateMode)%20%7B-%20%20%20%20let%20(lints,%20deprecated_lints,%20renamed_lints)%20=%20gather_all();-%20%20%20%20generate_lint_files(update_mode,%20&lints,%20&deprecated_lints,%20&renamed_lints);+%20%20%20%20let%20lints%20=%20find_lint_decls();+%20%20%20%20let%20DeprecatedLints%20%7B+%20%20%20%20%20%20%20%20renamed,%20deprecated,%20..+%20%20%20%20%7D%20=%20read_deprecated_lints();+%20%20%20%20generate_lint_files(update_mode,%20&lints,%20&deprecated,%20&renamed);%20%7D%20-fn%20generate_lint_files(+pub%20fn%20generate_lint_files(%20%20%20%20%20update_mode:%20UpdateMode,%20%20%20%20%20lints:%20&[Lint],-%20%20%20%20deprecated_lints:%20&[DeprecatedLint],-%20%20%20%20renamed_lints:%20&[RenamedLint],+%20%20%20%20deprecated:%20&[DeprecatedLint],+%20%20%20%20renamed:%20&[RenamedLint],%20)%20%7B-%20%20%20%20let%20mut%20lints%20=%20lints.to_owned();-%20%20%20%20lints.sort_by_key(|lint|%20lint.name.clone());--%20%20%20%20replace_region_in_file(-%20%20%20%20%20%20%20%20update_mode,-%20%20%20%20%20%20%20%20Path::new("README.md"), - "[There are over ", - " lints included in this crate!]", - |res| { - write!(res, "{}", round_to_fifty(lints.len())).unwrap(); - }, - ); - - replace_region_in_file( - update_mode, - Path::new("book/src/README.md"), - "[There are over ", - " lints included in this crate!]", - |res| { - write!(res, "{}", round_to_fifty(lints.len())).unwrap(); - }, - ); - - replace_region_in_file( - update_mode, - Path::new("CHANGELOG.md"), - "\n", - "", - |res| { - for lint in lints - .iter() - .map(|l| &*l.name) - .chain(deprecated_lints.iter().filter_map(|l| l.name.strip_prefix("clippy::"))) - .chain(renamed_lints.iter().filter_map(|l| l.old_name.strip_prefix("clippy::"))) - .sorted() - { - writeln!(res, "[`{lint}`]: {DOCS_LINK}#{lint}").unwrap(); - } - }, - ); - - // This has to be in lib.rs, otherwise rustfmt doesn't work - replace_region_in_file( - update_mode, - Path::new("clippy_lints/src/lib.rs"), - "// begin lints modules, do not remove this comment, it’s used in `update_lints`\n", - "// end lints modules, do not remove this comment, it’s used in `update_lints`", - |res| { - for lint_mod in lints.iter().map(|l| &l.module).unique().sorted() { - writeln!(res, "mod {lint_mod};").unwrap(); - } - }, - ); - - process_file( - "clippy_lints/src/declared_lints.rs", + FileUpdater::default().update_files_checked( + "cargo dev update_lints", update_mode, - &gen_declared_lints(lints.iter()), - ); - - let content = gen_deprecated_lints_test(deprecated_lints); - process_file("tests/ui/deprecated.rs", update_mode, &content); - - let content = gen_renamed_lints_test(renamed_lints); - process_file("tests/ui/rename.rs", update_mode, &content); -} - -pub fn print_lints() { - let (lints, _, _) = gather_all(); - let lint_count = lints.len(); - let grouped_by_lint_group = Lint::by_lint_group(lints.into_iter()); - - for (lint_group, mut lints) in grouped_by_lint_group { - println!("\n## {lint_group}"); - - lints.sort_by_key(|l| l.name.clone()); - - for lint in lints { - println!("* [{}]({DOCS_LINK}#{}) ({})", lint.name, lint.name, lint.desc); - } - } - - println!("there are {lint_count} lints"); -} - -/// Runs the `rename_lint` command. -/// -/// This does the following: -/// * Adds an entry to `renamed_lints.rs`. -/// * Renames all lint attributes to the new name (e.g. `#[allow(clippy::lint_name)]`). -/// * Renames the lint struct to the new name. -/// * Renames the module containing the lint struct to the new name if it shares a name with the -/// lint. -/// -/// # Panics -/// Panics for the following conditions: -/// * If a file path could not read from or then written to -/// * If either lint name has a prefix -/// * If `old_name` doesn't name an existing lint. -/// * If `old_name` names a deprecated or renamed lint. -#[allow(clippy::too_many_lines)] -pub fn rename(old_name: &str, new_name: &str, uplift: bool) { - if let Some((prefix, _)) = old_name.split_once("::") { - panic!("`{old_name}` should not contain the `{prefix}` prefix"); - } - if let Some((prefix, _)) = new_name.split_once("::") { - panic!("`{new_name}` should not contain the `{prefix}` prefix"); - } - - let (mut lints, deprecated_lints, mut renamed_lints) = gather_all(); - let mut old_lint_index = None; - let mut found_new_name = false; - for (i, lint) in lints.iter().enumerate() { - if lint.name == old_name { - old_lint_index = Some(i); - } else if lint.name == new_name { - found_new_name = true; - } - } - let old_lint_index = old_lint_index.unwrap_or_else(|| panic!("could not find lint `{old_name}`")); - - let lint = RenamedLint { - old_name: format!("clippy::{old_name}"), - new_name: if uplift { - new_name.into() - } else { - format!("clippy::{new_name}") - }, - }; - - // Renamed lints and deprecated lints shouldn't have been found in the lint list, but check just in - // case. - assert!( - !renamed_lints.iter().any(|l| lint.old_name == l.old_name), - "`{old_name}` has already been renamed" - ); - assert!( - !deprecated_lints.iter().any(|l| lint.old_name == l.name), - "`{old_name}` has already been deprecated" - ); - - // Update all lint level attributes. (`clippy::lint_name`) - for file in WalkDir::new(clippy_project_root()) - .into_iter() - .map(Result::unwrap) - .filter(|f| { - let name = f.path().file_name(); - let ext = f.path().extension(); - (ext == Some(OsStr::new("rs")) || ext == Some(OsStr::new("fixed"))) - && name != Some(OsStr::new("rename.rs")) - && name != Some(OsStr::new("deprecated_lints.rs")) - }) - { - rewrite_file(file.path(), |s| { - replace_ident_like(s, &[(&lint.old_name, &lint.new_name)]) - }); - } - - let version = crate::new_lint::get_stabilization_version(); - rewrite_file(Path::new("clippy_lints/src/deprecated_lints.rs"), |s| { - insert_at_marker( - s, - "// end renamed lints. used by `cargo dev rename_lint`", - &format!( - "#[clippy::version = \"{version}\"]\n \ - (\"{}\", \"{}\"),\n ", - lint.old_name, lint.new_name, + &mut [ + ( + "README.md", + &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| { + write!(dst, "{}", round_to_fifty(lints.len())).unwrap(); + }), ), - ) - }); - - renamed_lints.push(lint); - renamed_lints.sort_by(|lhs, rhs| { - lhs.new_name - .starts_with("clippy::") - .cmp(&rhs.new_name.starts_with("clippy::")) - .reverse() - .then_with(|| lhs.old_name.cmp(&rhs.old_name)) - }); - - if uplift { - write_file(Path::new("tests/ui/rename.rs"), &gen_renamed_lints_test(&renamed_lints)); - println!( - "`{old_name}` has be uplifted. All the code inside `clippy_lints` related to it needs to be removed manually." - ); - } else if found_new_name { - write_file(Path::new("tests/ui/rename.rs"), &gen_renamed_lints_test(&renamed_lints)); - println!( - "`{new_name}` is already defined. The old linting code inside `clippy_lints` needs to be updated/removed manually." - ); - } else { - // Rename the lint struct and source files sharing a name with the lint. - let lint = &mut lints[old_lint_index]; - let old_name_upper = old_name.to_uppercase(); - let new_name_upper = new_name.to_uppercase(); - lint.name = new_name.into(); - - // Rename test files. only rename `.stderr` and `.fixed` files if the new test name doesn't exist. - if try_rename_file( - Path::new(&format!("tests/ui/{old_name}.rs")), - Path::new(&format!("tests/ui/{new_name}.rs")), - ) { - try_rename_file( - Path::new(&format!("tests/ui/{old_name}.stderr")), - Path::new(&format!("tests/ui/{new_name}.stderr")), - ); - try_rename_file( - Path::new(&format!("tests/ui/{old_name}.fixed")), - Path::new(&format!("tests/ui/{new_name}.fixed")), - ); - } - - // Try to rename the file containing the lint if the file name matches the lint's name. - let replacements; - let replacements = if lint.module == old_name - && try_rename_file( - Path::new(&format!("clippy_lints/src/{old_name}.rs")), - Path::new(&format!("clippy_lints/src/{new_name}.rs")), - ) { - // Edit the module name in the lint list. Note there could be multiple lints. - for lint in lints.iter_mut().filter(|l| l.module == old_name) { - lint.module = new_name.into(); - } - replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)]; - replacements.as_slice() - } else if !lint.module.contains("::") - // Catch cases like `methods/lint_name.rs` where the lint is stored in `methods/mod.rs` - && try_rename_file( - Path::new(&format!("clippy_lints/src/{}/{old_name}.rs", lint.module)), - Path::new(&format!("clippy_lints/src/{}/{new_name}.rs", lint.module)), - ) - { - // Edit the module name in the lint list. Note there could be multiple lints, or none. - let renamed_mod = format!("{}::{old_name}", lint.module); - for lint in lints.iter_mut().filter(|l| l.module == renamed_mod) { - lint.module = format!("{}::{new_name}", lint.module); - } - replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)]; - replacements.as_slice() - } else { - replacements = [(&*old_name_upper, &*new_name_upper), ("", "")]; - &replacements[0..1] - }; - - // Don't change `clippy_utils/src/renamed_lints.rs` here as it would try to edit the lint being - // renamed. - for (_, file) in clippy_lints_src_files().filter(|(rel_path, _)| rel_path != OsStr::new("deprecated_lints.rs")) - { - rewrite_file(file.path(), |s| replace_ident_like(s, replacements)); - } - - generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); - println!("{old_name} has been successfully renamed"); - } - - println!("note: `cargo uitest` still needs to be run to update the test results"); -} - -/// Runs the `deprecate` command -/// -/// This does the following: -/// * Adds an entry to `deprecated_lints.rs`. -/// * Removes the lint declaration (and the entire file if applicable) -/// -/// # Panics -/// -/// If a file path could not read from or written to -pub fn deprecate(name: &str, reason: &str) { - let prefixed_name = if name.starts_with("clippy::") { - name.to_owned() - } else { - format!("clippy::{name}") - }; - let stripped_name = &prefixed_name[8..]; - - let (mut lints, mut deprecated_lints, renamed_lints) = gather_all(); - let Some(lint) = lints.iter().find(|l| l.name == stripped_name) else { - eprintln!("error: failed to find lint `{name}`"); - return; - }; - - let mod_path = { - let mut mod_path = PathBuf::from(format!("clippy_lints/src/{}", lint.module)); - if mod_path.is_dir() { - mod_path = mod_path.join("mod"); - } - - mod_path.set_extension("rs"); - mod_path - }; - - let deprecated_lints_path = &*clippy_project_root().join("clippy_lints/src/deprecated_lints.rs"); - - if remove_lint_declaration(stripped_name, &mod_path, &mut lints).unwrap_or(false) { - let version = crate::new_lint::get_stabilization_version(); - rewrite_file(deprecated_lints_path, |s| { - insert_at_marker( - s, - "// end deprecated lints. used by `cargo dev deprecate_lint`", - &format!("#[clippy::version = \"{version}\"]\n (\"{prefixed_name}\", \"{reason}\"),\n ",), - ) - }); - - deprecated_lints.push(DeprecatedLint { - name: prefixed_name, - reason: reason.into(), - }); - - generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); - println!("info: `{name}` has successfully been deprecated"); - println!("note: you must run `cargo uitest` to update the test results"); - } else { - eprintln!("error: lint not found"); - } -} - -fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec) -> io::Result { - fn remove_lint(name: &str, lints: &mut Vec) { - lints.iter().position(|l| l.name == name).map(|pos| lints.remove(pos)); - } - - fn remove_test_assets(name: &str) { - let test_file_stem = format!("tests/ui/{name}"); - let path = Path::new(&test_file_stem); - - // Some lints have their own directories, delete them - if path.is_dir() { - let _ = fs::remove_dir_all(path); - return; - } - - // Remove all related test files - let _ = fs::remove_file(path.with_extension("rs")); - let _ = fs::remove_file(path.with_extension("stderr")); - let _ = fs::remove_file(path.with_extension("fixed")); - } - - fn remove_impl_lint_pass(lint_name_upper: &str, content: &mut String) { - let impl_lint_pass_start = content.find("impl_lint_pass!").unwrap_or_else(|| { - content - .find("declare_lint_pass!") - .unwrap_or_else(|| panic!("failed to find `impl_lint_pass`")) - }); - let mut impl_lint_pass_end = content[impl_lint_pass_start..] - .find(']') - .expect("failed to find `impl_lint_pass` terminator"); - - impl_lint_pass_end += impl_lint_pass_start; - if let Some(lint_name_pos) = content[impl_lint_pass_start..impl_lint_pass_end].find(lint_name_upper) { - let mut lint_name_end = impl_lint_pass_start + (lint_name_pos + lint_name_upper.len()); - for c in content[lint_name_end..impl_lint_pass_end].chars() { - // Remove trailing whitespace - if c == ',' || c.is_whitespace() { - lint_name_end += 1; - } else { - break; + ( + "book/src/README.md", + &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| { + write!(dst, "{}", round_to_fifty(lints.len())).unwrap(); + }), + ), + ( + "CHANGELOG.md", + &mut update_text_region_fn( + "\n", + "", + |dst| { + for lint in lints + .iter() + .map(|l| &*l.name) + .chain(deprecated.iter().filter_map(|l| l.name.strip_prefix("clippy::"))) + .chain(renamed.iter().filter_map(|l| l.old_name.strip_prefix("clippy::"))) + .sorted() + { + writeln!(dst, "[`{lint}`]: {DOCS_LINK}#{lint}").unwrap(); + } + }, + ), + ), + ( + "clippy_lints/src/lib.rs", + &mut update_text_region_fn( + "// begin lints modules, do not remove this comment, it’s used in `update_lints`\n", + "// end lints modules, do not remove this comment, it’s used in `update_lints`", + |dst| { + for lint_mod in lints.iter().map(|l| &l.module).sorted().dedup() { + writeln!(dst, "mod {lint_mod};").unwrap(); + } + }, + ), + ), + ("clippy_lints/src/declared_lints.rs", &mut |_, src, dst| { + dst.push_str(GENERATED_FILE_COMMENT); + dst.push_str("pub static LINTS: &[&crate::LintInfo] = &[\n"); + for (module_name, lint_name) in lints.iter().map(|l| (&l.module, l.name.to_uppercase())).sorted() { + writeln!(dst, " crate::{module_name}::{lint_name}_INFO,").unwrap(); } - } - - content.replace_range(impl_lint_pass_start + lint_name_pos..lint_name_end, ""); - } - } - - if path.exists() - && let Some(lint) = lints.iter().find(|l| l.name == name) - { - if lint.module == name { - // The lint name is the same as the file, we can just delete the entire file - fs::remove_file(path)?; - } else { - // We can't delete the entire file, just remove the declaration - - if let Some(Some("mod.rs")) = path.file_name().map(OsStr::to_str) { - // Remove clippy_lints/src/some_mod/some_lint.rs - let mut lint_mod_path = path.to_path_buf(); - lint_mod_path.set_file_name(name); - lint_mod_path.set_extension("rs"); - - let _ = fs::remove_file(lint_mod_path); - } - - let mut content = - fs::read_to_string(path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy())); - - eprintln!( - "warn: you will have to manually remove any code related to `{name}` from `{}`", - path.display() - ); - - assert!( - content[lint.declaration_range.clone()].contains(&name.to_uppercase()), - "error: `{}` does not contain lint `{}`'s declaration", - path.display(), - lint.name - ); - - // Remove lint declaration (declare_clippy_lint!) - content.replace_range(lint.declaration_range.clone(), ""); - - // Remove the module declaration (mod xyz;) - let mod_decl = format!("\nmod {name};"); - content = content.replacen(&mod_decl, "", 1); - - remove_impl_lint_pass(&lint.name.to_uppercase(), &mut content); - fs::write(path, content).unwrap_or_else(|_| panic!("failed to write to `{}`", path.to_string_lossy())); - } - - remove_test_assets(name); - remove_lint(name, lints); - return Ok(true); - } - - Ok(false) -} - -/// Replace substrings if they aren't bordered by identifier characters. Returns `None` if there -/// were no replacements. -fn replace_ident_like(contents: &str, replacements: &[(&str, &str)]) -> Option { - fn is_ident_char(c: u8) -> bool { - matches!(c, b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_') - } - - let searcher = AhoCorasickBuilder::new() - .match_kind(aho_corasick::MatchKind::LeftmostLongest) - .build(replacements.iter().map(|&(x, _)| x.as_bytes())) - .unwrap(); - - let mut result = String::with_capacity(contents.len() + 1024); - let mut pos = 0; - let mut edited = false; - for m in searcher.find_iter(contents) { - let (old, new) = replacements[m.pattern()]; - result.push_str(&contents[pos..m.start()]); - result.push_str( - if !is_ident_char(contents.as_bytes().get(m.start().wrapping_sub(1)).copied().unwrap_or(0)) - && !is_ident_char(contents.as_bytes().get(m.end()).copied().unwrap_or(0)) - { - edited = true; - new - } else { - old - }, - ); - pos = m.end(); - } - result.push_str(&contents[pos..]); - edited.then_some(result) + dst.push_str("];\n"); + UpdateStatus::from_changed(src != dst) + }), + ("tests/ui/deprecated.rs", &mut |_, src, dst| { + dst.push_str(GENERATED_FILE_COMMENT); + for lint in deprecated { + writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.name, lint.name).unwrap(); + } + dst.push_str("\nfn main() {}\n"); + UpdateStatus::from_changed(src != dst) + }), + ("tests/ui/rename.rs", &mut gen_renamed_lints_test_fn(renamed)), + ], + ); } fn round_to_fifty(count: usize) -> usize { count / 50 * 50 } -fn process_file(path: impl AsRef, update_mode: UpdateMode, content: &str) { - if update_mode == UpdateMode::Check { - let old_content = - fs::read_to_string(&path).unwrap_or_else(|e| panic!("Cannot read from {}: {e}", path.as_ref().display())); - if content != old_content { - exit_with_failure(); - } - } else { - fs::write(&path, content.as_bytes()) - .unwrap_or_else(|e| panic!("Cannot write to {}: {e}", path.as_ref().display())); - } -} - /// Lint data parsed from the Clippy source code. #[derive(Clone, PartialEq, Eq, Debug)] -struct Lint { - name: String, - group: String, - desc: String, - module: String, - declaration_range: Range, -} - -impl Lint { - #[must_use] - fn new(name: &str, group: &str, desc: &str, module: &str, declaration_range: Range) -> Self { - Self { - name: name.to_lowercase(), - group: group.into(), - desc: remove_line_splices(desc), - module: module.into(), - declaration_range, - } - } - - /// Returns the lints in a `HashMap`, grouped by the different lint groups - #[must_use] - fn by_lint_group(lints: impl Iterator) -> HashMap> { - lints.map(|lint| (lint.group.to_string(), lint)).into_group_map() - } +pub struct Lint { + pub name: String, + pub group: String, + pub module: String, + pub declaration_range: Range, } #[derive(Clone, PartialEq, Eq, Debug)] -struct DeprecatedLint { - name: String, - reason: String, -} -impl DeprecatedLint { - fn new(name: &str, reason: &str) -> Self { - Self { - name: remove_line_splices(name), - reason: remove_line_splices(reason), - } - } +pub struct DeprecatedLint { + pub name: String, + pub reason: String, } -struct RenamedLint { - old_name: String, - new_name: String, -} -impl RenamedLint { - fn new(old_name: &str, new_name: &str) -> Self { - Self { - old_name: remove_line_splices(old_name), - new_name: remove_line_splices(new_name), - } - } +pub struct RenamedLint { + pub old_name: String, + pub new_name: String, } -/// Generates the code for registering lints -#[must_use] -fn gen_declared_lints<'a>(lints: impl Iterator) -> String { - let mut details: Vec<_> = lints.map(|l| (&l.module, l.name.to_uppercase())).collect(); - details.sort_unstable(); - - let mut output = GENERATED_FILE_COMMENT.to_string(); - output.push_str("pub static LINTS: &[&crate::LintInfo] = &[\n"); - - for (module_name, lint_name) in details { - let _: fmt::Result = writeln!(output, " crate::{module_name}::{lint_name}_INFO,"); - } - output.push_str("];\n"); - - output -} - -fn gen_deprecated_lints_test(lints: &[DeprecatedLint]) -> String { - let mut res: String = GENERATED_FILE_COMMENT.into(); - for lint in lints { - writeln!(res, "#![warn({})] //~ ERROR: lint `{}`", lint.name, lint.name).unwrap(); - } - res.push_str("\nfn main() {}\n"); - res -} - -fn gen_renamed_lints_test(lints: &[RenamedLint]) -> String { - let mut seen_lints = HashSet::new(); - let mut res: String = GENERATED_FILE_COMMENT.into(); - - res.push_str("#![allow(clippy::duplicated_attributes)]\n"); - for lint in lints { - if seen_lints.insert(&lint.new_name) { - writeln!(res, "#![allow({})]", lint.new_name).unwrap(); +pub fn gen_renamed_lints_test_fn(lints: &[RenamedLint]) -> impl Fn(&Path, &str, &mut String) -> UpdateStatus { + move |_, src, dst| { + let mut seen_lints = HashSet::new(); + dst.push_str(GENERATED_FILE_COMMENT); + dst.push_str("#![allow(clippy::duplicated_attributes)]\n"); + for lint in lints { + if seen_lints.insert(&lint.new_name) { + writeln!(dst, "#![allow({})]", lint.new_name).unwrap(); + } } - } - seen_lints.clear(); - for lint in lints { - if seen_lints.insert(&lint.old_name) { - writeln!(res, "#![warn({})] //~ ERROR: lint `{}`", lint.old_name, lint.old_name).unwrap(); + seen_lints.clear(); + for lint in lints { + if seen_lints.insert(&lint.old_name) { + writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.old_name, lint.old_name).unwrap(); + } } + dst.push_str("\nfn main() {}\n"); + UpdateStatus::from_changed(src != dst) } - res.push_str("\nfn main() {}\n"); - res } -/// Gathers all lints defined in `clippy_lints/src` -fn gather_all() -> (Vec, Vec, Vec) { +/// Finds all lint declarations (`declare_clippy_lint!`) +#[must_use] +pub fn find_lint_decls() -> Vec { let mut lints = Vec::with_capacity(1000); - let mut deprecated_lints = Vec::with_capacity(50); - let mut renamed_lints = Vec::with_capacity(50); - - for (rel_path, file) in clippy_lints_src_files() { - let path = file.path(); - let contents = - fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {e}", path.display())); - let module = rel_path - .components() - .map(|c| c.as_os_str().to_str().unwrap()) - .collect::>() - .join("::"); + let mut contents = String::new(); + for (file, module) in read_src_with_module("clippy_lints/src".as_ref()) { + parse_clippy_lint_decls( + File::open_read_to_cleared_string(file.path(), &mut contents), + &module, + &mut lints, + ); + } + lints.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name)); + lints +} - // If the lints are stored in mod.rs, we get the module name from - // the containing directory: - let module = if let Some(module) = module.strip_suffix("::mod.rs") { - module - } else { - module.strip_suffix(".rs").unwrap_or(&module) +/// Reads the source files from the given root directory +fn read_src_with_module(src_root: &Path) -> impl use<'_> + Iterator { + WalkDir::new(src_root).into_iter().filter_map(move |e| { + let e = match e { + Ok(e) => e, + Err(ref e) => panic_file(e, FileAction::Read, src_root), }; - - if module == "deprecated_lints" { - parse_deprecated_contents(&contents, &mut deprecated_lints, &mut renamed_lints); + let path = e.path().as_os_str().as_encoded_bytes(); + if let Some(path) = path.strip_suffix(b".rs") + && let Some(path) = path.get("clippy_lints/src/".len()..) + { + if path == b"lib" { + Some((e, String::new())) + } else { + let path = if let Some(path) = path.strip_suffix(b"mod") + && let Some(path) = path.strip_suffix(b"/").or_else(|| path.strip_suffix(b"\\")) + { + path + } else { + path + }; + if let Ok(path) = str::from_utf8(path) { + let path = path.replace(['/', '\\'], "::"); + Some((e, path)) + } else { + None + } + } } else { - parse_contents(&contents, module, &mut lints); + None } - } - (lints, deprecated_lints, renamed_lints) -} - -fn clippy_lints_src_files() -> impl Iterator { - let root_path = clippy_project_root().join("clippy_lints/src"); - let iter = WalkDir::new(&root_path).into_iter(); - iter.map(Result::unwrap) - .filter(|f| f.path().extension() == Some(OsStr::new("rs"))) - .map(move |f| (f.path().strip_prefix(&root_path).unwrap().to_path_buf(), f)) + }) } -macro_rules! match_tokens { - ($iter:ident, $($token:ident $({$($fields:tt)*})? $(($capture:ident))?)*) => { - { - $(#[allow(clippy::redundant_pattern)] let Some(LintDeclSearchResult { - token_kind: TokenKind::$token $({$($fields)*})?, - content: $($capture @)? _, - .. - }) = $iter.next() else { - continue; - };)* - #[allow(clippy::unused_unit)] - { ($($($capture,)?)*) } +/// Parse a source file looking for `declare_clippy_lint` macro invocations. +fn parse_clippy_lint_decls(contents: &str, module: &str, lints: &mut Vec) { + #[allow(clippy::enum_glob_use)] + use Token::*; + #[rustfmt::skip] + static DECL_TOKENS: &[Token] = &[ + // !{ /// docs + Bang, OpenBrace, AnyDoc, + // #[clippy::version = "version"] + Pound, OpenBracket, Ident("clippy"), DoubleColon, Ident("version"), Eq, LitStr, CloseBracket, + // pub NAME, GROUP, + Ident("pub"), CaptureIdent, Comma, CaptureIdent, Comma, + ]; + + let mut searcher = RustSearcher::new(contents); + while searcher.find_token(Ident("declare_clippy_lint")) { + let start = searcher.pos() as usize - "declare_clippy_lint".len(); + let (mut name, mut group) = ("", ""); + if searcher.match_tokens(DECL_TOKENS, &mut [&mut name, &mut group]) && searcher.find_token(CloseBrace) { + lints.push(Lint { + name: name.to_lowercase(), + group: group.into(), + module: module.into(), + declaration_range: start..searcher.pos() as usize, + }); } } } -pub(crate) use match_tokens; - -pub(crate) struct LintDeclSearchResult<'a> { - pub token_kind: TokenKind, - pub content: &'a str, - pub range: Range, +pub struct DeprecatedLints { + pub file: File<'static>, + pub contents: String, + pub deprecated: Vec, + pub renamed: Vec, + pub deprecated_end: u32, + pub renamed_end: u32, } -/// Parse a source file looking for `declare_clippy_lint` macro invocations. -fn parse_contents(contents: &str, module: &str, lints: &mut Vec) { - let mut offset = 0usize; - let mut iter = tokenize(contents).map(|t| { - let range = offset..offset + t.len as usize; - offset = range.end; - - LintDeclSearchResult { - token_kind: t.kind, - content: &contents[range.clone()], - range, - } - }); - - while let Some(LintDeclSearchResult { range, .. }) = iter.find( - |LintDeclSearchResult { - token_kind, content, .. - }| token_kind == &TokenKind::Ident && *content == "declare_clippy_lint", - ) { - let start = range.start; - let mut iter = iter - .by_ref() - .filter(|t| !matches!(t.token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. })); - // matches `!{` - match_tokens!(iter, Bang OpenBrace); - match iter.next() { - // #[clippy::version = "version"] pub - Some(LintDeclSearchResult { - token_kind: TokenKind::Pound, - .. - }) => { - match_tokens!(iter, OpenBracket Ident Colon Colon Ident Eq Literal{..} CloseBracket Ident); - }, - // pub - Some(LintDeclSearchResult { - token_kind: TokenKind::Ident, - .. - }) => (), - _ => continue, - } - - let (name, group, desc) = match_tokens!( - iter, - // LINT_NAME - Ident(name) Comma - // group, - Ident(group) Comma - // "description" - Literal{..}(desc) - ); - - if let Some(end) = iter.find_map(|t| { - if let LintDeclSearchResult { - token_kind: TokenKind::CloseBrace, - range, - .. - } = t - { - Some(range.end) - } else { - None - } - }) { - lints.push(Lint::new(name, group, desc, module, start..end)); - } - } -} - -/// Parse a source file looking for `declare_deprecated_lint` macro invocations. -fn parse_deprecated_contents(contents: &str, deprecated: &mut Vec, renamed: &mut Vec) { - let Some((_, contents)) = contents.split_once("\ndeclare_with_version! { DEPRECATED") else { - return; - }; - let Some((deprecated_src, renamed_src)) = contents.split_once("\ndeclare_with_version! { RENAMED") else { - return; +#[must_use] +pub fn read_deprecated_lints() -> DeprecatedLints { + #[allow(clippy::enum_glob_use)] + use Token::*; + #[rustfmt::skip] + static DECL_TOKENS: &[Token] = &[ + // #[clippy::version = "version"] + Pound, OpenBracket, Ident("clippy"), DoubleColon, Ident("version"), Eq, LitStr, CloseBracket, + // ("first", "second"), + OpenParen, CaptureLitStr, Comma, CaptureLitStr, CloseParen, Comma, + ]; + #[rustfmt::skip] + static DEPRECATED_TOKENS: &[Token] = &[ + // !{ DEPRECATED(DEPRECATED_VERSION) = [ + Bang, OpenBrace, Ident("DEPRECATED"), OpenParen, Ident("DEPRECATED_VERSION"), CloseParen, Eq, OpenBracket, + ]; + #[rustfmt::skip] + static RENAMED_TOKENS: &[Token] = &[ + // !{ RENAMED(RENAMED_VERSION) = [ + Bang, OpenBrace, Ident("RENAMED"), OpenParen, Ident("RENAMED_VERSION"), CloseParen, Eq, OpenBracket, + ]; + + let path = "clippy_lints/src/deprecated_lints.rs"; + let mut res = DeprecatedLints { + file: File::open(path, OpenOptions::new().read(true).write(true)), + contents: String::new(), + deprecated: Vec::with_capacity(30), + renamed: Vec::with_capacity(80), + deprecated_end: 0, + renamed_end: 0, }; - for line in deprecated_src.lines() { - let mut offset = 0usize; - let mut iter = tokenize(line).map(|t| { - let range = offset..offset + t.len as usize; - offset = range.end; + res.file.read_append_to_string(&mut res.contents); + let mut searcher = RustSearcher::new(&res.contents); - LintDeclSearchResult { - token_kind: t.kind, - content: &line[range.clone()], - range, - } - }); + // First instance is the macro definition. + assert!( + searcher.find_token(Ident("declare_with_version")), + "error reading deprecated lints" + ); - let (name, reason) = match_tokens!( - iter, - // ("old_name", - Whitespace OpenParen Literal{kind: LiteralKind::Str{..},..}(name) Comma - // "new_name"), - Whitespace Literal{kind: LiteralKind::Str{..},..}(reason) CloseParen Comma - ); - deprecated.push(DeprecatedLint::new(name, reason)); + if searcher.find_token(Ident("declare_with_version")) && searcher.match_tokens(DEPRECATED_TOKENS, &mut []) { + let mut name = ""; + let mut reason = ""; + while searcher.match_tokens(DECL_TOKENS, &mut [&mut name, &mut reason]) { + res.deprecated.push(DeprecatedLint { + name: parse_str_single_line(path.as_ref(), name), + reason: parse_str_single_line(path.as_ref(), reason), + }); + } + } else { + panic!("error reading deprecated lints"); + } + // position of the closing `]}` of `declare_with_version` + res.deprecated_end = searcher.pos(); + + if searcher.find_token(Ident("declare_with_version")) && searcher.match_tokens(RENAMED_TOKENS, &mut []) { + let mut old_name = ""; + let mut new_name = ""; + while searcher.match_tokens(DECL_TOKENS, &mut [&mut old_name, &mut new_name]) { + res.renamed.push(RenamedLint { + old_name: parse_str_single_line(path.as_ref(), old_name), + new_name: parse_str_single_line(path.as_ref(), new_name), + }); + } + } else { + panic!("error reading renamed lints"); } - for line in renamed_src.lines() { - let mut offset = 0usize; - let mut iter = tokenize(line).map(|t| { - let range = offset..offset + t.len as usize; - offset = range.end; - - LintDeclSearchResult { - token_kind: t.kind, - content: &line[range.clone()], - range, - } - }); + // position of the closing `]}` of `declare_with_version` + res.renamed_end = searcher.pos(); - let (old_name, new_name) = match_tokens!( - iter, - // ("old_name", - Whitespace OpenParen Literal{kind: LiteralKind::Str{..},..}(old_name) Comma - // "new_name"), - Whitespace Literal{kind: LiteralKind::Str{..},..}(new_name) CloseParen Comma - ); - renamed.push(RenamedLint::new(old_name, new_name)); - } + res } /// Removes the line splices and surrounding quotes from a string literal -fn remove_line_splices(s: &str) -> String { +fn parse_str_lit(s: &str) -> String { + let (s, mode) = if let Some(s) = s.strip_prefix("r") { + (s.trim_matches('#'), rustc_literal_escaper::Mode::RawStr) + } else { + (s, rustc_literal_escaper::Mode::Str) + }; let s = s - .strip_prefix('r') - .unwrap_or(s) - .trim_matches('#') .strip_prefix('"') .and_then(|s| s.strip_suffix('"')) .unwrap_or_else(|| panic!("expected quoted string, found `{s}`")); let mut res = String::with_capacity(s.len()); - unescape_unicode(s, Mode::Str, &mut |range, ch| { - if ch.is_ok() { - res.push_str(&s[range]); + rustc_literal_escaper::unescape_unicode(s, mode, &mut |_, ch| { + if let Ok(ch) = ch { + res.push(ch); } }); res } -fn try_rename_file(old_name: &Path, new_name: &Path) -> bool { - match OpenOptions::new().create_new(true).write(true).open(new_name) { - Ok(file) => drop(file), - Err(e) if matches!(e.kind(), io::ErrorKind::AlreadyExists | io::ErrorKind::NotFound) => return false, - Err(e) => panic_file(e, new_name, "create"), - } - match fs::rename(old_name, new_name) { - Ok(()) => true, - Err(e) => { - drop(fs::remove_file(new_name)); - if e.kind() == io::ErrorKind::NotFound { - false - } else { - panic_file(e, old_name, "rename"); - } - }, - } -} - -#[allow(clippy::needless_pass_by_value)] -fn panic_file(error: io::Error, name: &Path, action: &str) -> ! { - panic!("failed to {action} file `{}`: {error}", name.display()) -} - -fn insert_at_marker(text: &str, marker: &str, new_text: &str) -> Option { - let i = text.find(marker)?; - let (pre, post) = text.split_at(i); - Some([pre, new_text, post].into_iter().collect()) -} - -fn rewrite_file(path: &Path, f: impl FnOnce(&str) -> Option) { - let mut file = OpenOptions::new() - .write(true) - .read(true) - .open(path) - .unwrap_or_else(|e| panic_file(e, path, "open")); - let mut buf = String::new(); - file.read_to_string(&mut buf) - .unwrap_or_else(|e| panic_file(e, path, "read")); - if let Some(new_contents) = f(&buf) { - file.rewind().unwrap_or_else(|e| panic_file(e, path, "write")); - file.write_all(new_contents.as_bytes()) - .unwrap_or_else(|e| panic_file(e, path, "write")); - file.set_len(new_contents.len() as u64) - .unwrap_or_else(|e| panic_file(e, path, "write")); - } -} -fn write_file(path: &Path, contents: &str) { - fs::write(path, contents).unwrap_or_else(|e| panic_file(e, path, "write")); +fn parse_str_single_line(path: &Path, s: &str) -> String { + let value = parse_str_lit(s); + assert!( + !value.contains('\n'), + "error parsing `{}`: `{s}` should be a single line string", + path.display(), + ); + value } #[cfg(test)] @@ -868,7 +348,7 @@ mod tests { use super::*; #[test] - fn test_parse_contents() { + fn test_parse_clippy_lint_decls() { static CONTENTS: &str = r#" declare_clippy_lint! { #[clippy::version = "Hello Clippy!"] @@ -886,61 +366,25 @@ mod tests { } "#; let mut result = Vec::new(); - parse_contents(CONTENTS, "module_name", &mut result); + parse_clippy_lint_decls(CONTENTS, "module_name", &mut result); for r in &mut result { r.declaration_range = Range::default(); } let expected = vec![ - Lint::new( - "ptr_arg", - "style", - "\"really long text\"", - "module_name", - Range::default(), - ), - Lint::new( - "doc_markdown", - "pedantic", - "\"single line\"", - "module_name", - Range::default(), - ), + Lint { + name: "ptr_arg".into(), + group: "style".into(), + module: "module_name".into(), + declaration_range: Range::default(), + }, + Lint { + name: "doc_markdown".into(), + group: "pedantic".into(), + module: "module_name".into(), + declaration_range: Range::default(), + }, ]; assert_eq!(expected, result); } - - #[test] - fn test_by_lint_group() { - let lints = vec![ - Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()), - Lint::new( - "should_assert_eq2", - "group2", - "\"abc\"", - "module_name", - Range::default(), - ), - Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()), - ]; - let mut expected: HashMap> = HashMap::new(); - expected.insert( - "group1".to_string(), - vec![ - Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()), - Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()), - ], - ); - expected.insert( - "group2".to_string(), - vec![Lint::new( - "should_assert_eq2", - "group2", - "\"abc\"", - "module_name", - Range::default(), - )], - ); - assert_eq!(expected, Lint::by_lint_group(lints.into_iter())); - } } diff --git a/clippy_dev/src/utils.rs b/clippy_dev/src/utils.rs index 206816398f50f..ae2eabc45dd00 100644 --- a/clippy_dev/src/utils.rs +++ b/clippy_dev/src/utils.rs @@ -1,12 +1,113 @@ +use aho_corasick::{AhoCorasick, AhoCorasickBuilder}; +use core::fmt::{self, Display}; +use core::slice; +use core::str::FromStr; +use rustc_lexer::{self as lexer, FrontmatterAllowed}; +use std::env; +use std::fs::{self, OpenOptions}; +use std::io::{self, Read as _, Seek as _, SeekFrom, Write}; use std::path::{Path, PathBuf}; use std::process::{self, ExitStatus}; -use std::{fs, io}; #[cfg(not(windows))] static CARGO_CLIPPY_EXE: &str = "cargo-clippy"; #[cfg(windows)] static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe"; +#[derive(Clone, Copy)] +pub enum FileAction { + Open, + Read, + Write, + Create, + Rename, +} +impl FileAction { + fn as_str(self) -> &'static str { + match self { + Self::Open => "opening", + Self::Read => "reading", + Self::Write => "writing", + Self::Create => "creating", + Self::Rename => "renaming", + } + } +} + +#[cold] +#[track_caller] +pub fn panic_file(err: &impl Display, action: FileAction, path: &Path) -> ! { + panic!("error {} `{}`: {}", action.as_str(), path.display(), *err) +} + +/// Wrapper around `std::fs::File` which panics with a path on failure. +pub struct File<'a> { + pub inner: fs::File, + pub path: &'a Path, +} +impl<'a> File<'a> { + /// Opens a file panicking on failure. + #[track_caller] + pub fn open(path: &'a (impl AsRef + ?Sized), options: &mut OpenOptions) -> Self { + let path = path.as_ref(); + match options.open(path) { + Ok(inner) => Self { inner, path }, + Err(e) => panic_file(&e, FileAction::Open, path), + } + } + + /// Opens a file if it exists, panicking on any other failure. + #[track_caller] + pub fn open_if_exists(path: &'a (impl AsRef + ?Sized), options: &mut OpenOptions) -> Option { + let path = path.as_ref(); + match options.open(path) { + Ok(inner) => Some(Self { inner, path }), + Err(e) if e.kind() == io::ErrorKind::NotFound => None, + Err(e) => panic_file(&e, FileAction::Open, path), + } + } + + /// Opens and reads a file into a string, panicking of failure. + #[track_caller] + pub fn open_read_to_cleared_string<'dst>( + path: &'a (impl AsRef + ?Sized), + dst: &'dst mut String, + ) -> &'dst mut String { + Self::open(path, OpenOptions::new().read(true)).read_to_cleared_string(dst) + } + + /// Read the entire contents of a file to the given buffer. + #[track_caller] + pub fn read_append_to_string<'dst>(&mut self, dst: &'dst mut String) -> &'dst mut String { + match self.inner.read_to_string(dst) { + Ok(_) => {}, + Err(e) => panic_file(&e, FileAction::Read, self.path), + } + dst + } + + #[track_caller] + pub fn read_to_cleared_string<'dst>(&mut self, dst: &'dst mut String) -> &'dst mut String { + dst.clear(); + self.read_append_to_string(dst) + } + + /// Replaces the entire contents of a file. + #[track_caller] + pub fn replace_contents(&mut self, data: &[u8]) { + let res = match self.inner.seek(SeekFrom::Start(0)) { + Ok(_) => match self.inner.write_all(data) { + Ok(()) => self.inner.set_len(data.len() as u64), + Err(e) => Err(e), + }, + Err(e) => Err(e), + }; + if let Err(e) = res { + panic_file(&e, FileAction::Write, self.path); + } + } +} + /// Returns the path to the `cargo-clippy` binary /// /// # Panics @@ -14,34 +115,107 @@ static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe"; /// Panics if the path of current executable could not be retrieved. #[must_use] pub fn cargo_clippy_path() -> PathBuf { - let mut path = std::env::current_exe().expect("failed to get current executable name"); + let mut path = env::current_exe().expect("failed to get current executable name"); path.set_file_name(CARGO_CLIPPY_EXE); path } -/// Returns the path to the Clippy project directory -/// -/// # Panics -/// -/// Panics if the current directory could not be retrieved, there was an error reading any of the -/// Cargo.toml files or ancestor directory is the clippy root directory -#[must_use] -pub fn clippy_project_root() -> PathBuf { - let current_dir = std::env::current_dir().unwrap(); - for path in current_dir.ancestors() { - let result = fs::read_to_string(path.join("Cargo.toml")); - if let Err(err) = &result - && err.kind() == io::ErrorKind::NotFound +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct Version { + pub major: u16, + pub minor: u16, +} +impl FromStr for Version { + type Err = (); + fn from_str(s: &str) -> Result { + if let Some(s) = s.strip_prefix("0.") + && let Some((major, minor)) = s.split_once('.') + && let Ok(major) = major.parse() + && let Ok(minor) = minor.parse() { - continue; + Ok(Self { major, minor }) + } else { + Err(()) + } + } +} +impl Version { + /// Displays the version as a rust version. i.e. `x.y.0` + #[must_use] + pub fn rust_display(self) -> impl Display { + struct X(Version); + impl Display for X { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}.{}.0", self.0.major, self.0.minor) + } + } + X(self) + } + + /// Displays the version as it should appear in clippy's toml files. i.e. `0.x.y` + #[must_use] + pub fn toml_display(self) -> impl Display { + struct X(Version); + impl Display for X { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "0.{}.{}", self.0.major, self.0.minor) + } } + X(self) + } +} + +pub struct ClippyInfo { + pub path: PathBuf, + pub version: Version, +} +impl ClippyInfo { + #[must_use] + pub fn search_for_manifest() -> Self { + let mut path = env::current_dir().expect("error reading the working directory"); + let mut buf = String::new(); + loop { + path.push("Cargo.toml"); + if let Some(mut file) = File::open_if_exists(&path, OpenOptions::new().read(true)) { + let mut in_package = false; + let mut is_clippy = false; + let mut version: Option = None; + + // Ad-hoc parsing to avoid dependencies. We control all the file so this + // isn't actually a problem + for line in file.read_to_cleared_string(&mut buf).lines() { + if line.starts_with('[') { + in_package = line.starts_with("[package]"); + } else if in_package && let Some((name, value)) = line.split_once('=') { + match name.trim() { + "name" => is_clippy = value.trim() == "\"clippy\"", + "version" + if let Some(value) = value.trim().strip_prefix('"') + && let Some(value) = value.strip_suffix('"') => + { + version = value.parse().ok(); + }, + _ => {}, + } + } + } - let content = result.unwrap(); - if content.contains("[package]\nname = \"clippy\"") { - return path.to_path_buf(); + if is_clippy { + let Some(version) = version else { + panic!("error reading clippy version from {}", file.path.display()); + }; + path.pop(); + return ClippyInfo { path, version }; + } + } + + path.pop(); + assert!( + path.pop(), + "error finding project root, please run from inside the clippy directory" + ); } } - panic!("error: Can't determine root of project. Please run inside a Clippy working dir."); } /// # Panics @@ -57,86 +231,396 @@ pub fn exit_if_err(status: io::Result) { } } -pub(crate) fn clippy_version() -> (u32, u32) { - fn parse_manifest(contents: &str) -> Option<(u32, u32)> { - let version = contents - .lines() - .filter_map(|l| l.split_once('=')) - .find_map(|(k, v)| (k.trim() == "version").then(|| v.trim()))?; - let Some(("0", version)) = version.get(1..version.len() - 1)?.split_once('.') else { - return None; - }; - let (minor, patch) = version.split_once('.')?; - Some((minor.parse().ok()?, patch.parse().ok()?)) +#[derive(Clone, Copy)] +pub enum UpdateStatus { + Unchanged, + Changed, +} +impl UpdateStatus { + #[must_use] + pub fn from_changed(value: bool) -> Self { + if value { Self::Changed } else { Self::Unchanged } + } + + #[must_use] + pub fn is_changed(self) -> bool { + matches!(self, Self::Changed) } - let contents = fs::read_to_string("Cargo.toml").expect("Unable to read `Cargo.toml`"); - parse_manifest(&contents).expect("Unable to find package version in `Cargo.toml`") } -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy)] pub enum UpdateMode { - Check, Change, + Check, +} +impl UpdateMode { + #[must_use] + pub fn from_check(check: bool) -> Self { + if check { Self::Check } else { Self::Change } + } } -pub(crate) fn exit_with_failure() { - println!( - "Not all lints defined properly. \ - Please run `cargo dev update_lints` to make sure all lints are defined properly." - ); - process::exit(1); +#[derive(Default)] +pub struct FileUpdater { + src_buf: String, + dst_buf: String, } +impl FileUpdater { + fn update_file_checked_inner( + &mut self, + tool: &str, + mode: UpdateMode, + path: &Path, + update: &mut dyn FnMut(&Path, &str, &mut String) -> UpdateStatus, + ) { + let mut file = File::open(path, OpenOptions::new().read(true).write(true)); + file.read_to_cleared_string(&mut self.src_buf); + self.dst_buf.clear(); + match (mode, update(path, &self.src_buf, &mut self.dst_buf)) { + (UpdateMode::Check, UpdateStatus::Changed) => { + eprintln!( + "the contents of `{}` are out of date\nplease run `{tool}` to update", + path.display() + ); + process::exit(1); + }, + (UpdateMode::Change, UpdateStatus::Changed) => file.replace_contents(self.dst_buf.as_bytes()), + (UpdateMode::Check | UpdateMode::Change, UpdateStatus::Unchanged) => {}, + } + } -/// Replaces a region in a file delimited by two lines matching regexes. -/// -/// `path` is the relative path to the file on which you want to perform the replacement. -/// -/// See `replace_region_in_text` for documentation of the other options. -/// -/// # Panics -/// -/// Panics if the path could not read or then written -pub(crate) fn replace_region_in_file( - update_mode: UpdateMode, + fn update_file_inner(&mut self, path: &Path, update: &mut dyn FnMut(&Path, &str, &mut String) -> UpdateStatus) { + let mut file = File::open(path, OpenOptions::new().read(true).write(true)); + file.read_to_cleared_string(&mut self.src_buf); + self.dst_buf.clear(); + if update(path, &self.src_buf, &mut self.dst_buf).is_changed() { + file.replace_contents(self.dst_buf.as_bytes()); + } + } + + pub fn update_file_checked( + &mut self, + tool: &str, + mode: UpdateMode, + path: impl AsRef, + update: &mut dyn FnMut(&Path, &str, &mut String) -> UpdateStatus, + ) { + self.update_file_checked_inner(tool, mode, path.as_ref(), update); + } + + #[expect(clippy::type_complexity)] + pub fn update_files_checked( + &mut self, + tool: &str, + mode: UpdateMode, + files: &mut [( + impl AsRef, + &mut dyn FnMut(&Path, &str, &mut String) -> UpdateStatus, + )], + ) { + for (path, update) in files { + self.update_file_checked_inner(tool, mode, path.as_ref(), update); + } + } + + pub fn update_file( + &mut self, + path: impl AsRef, + update: &mut dyn FnMut(&Path, &str, &mut String) -> UpdateStatus, + ) { + self.update_file_inner(path.as_ref(), update); + } +} + +/// Replaces a region in a text delimited by two strings. Returns the new text if both delimiters +/// were found, or the missing delimiter if not. +pub fn update_text_region( path: &Path, start: &str, end: &str, - write_replacement: impl FnMut(&mut String), -) { - let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {e}", path.display())); - let new_contents = match replace_region_in_text(&contents, start, end, write_replacement) { - Ok(x) => x, - Err(delim) => panic!("Couldn't find `{delim}` in file `{}`", path.display()), + src: &str, + dst: &mut String, + insert: &mut impl FnMut(&mut String), +) -> UpdateStatus { + let Some((src_start, src_end)) = src.split_once(start) else { + panic!("`{}` does not contain `{start}`", path.display()); }; + let Some((replaced_text, src_end)) = src_end.split_once(end) else { + panic!("`{}` does not contain `{end}`", path.display()); + }; + dst.push_str(src_start); + dst.push_str(start); + let new_start = dst.len(); + insert(dst); + let changed = dst[new_start..] != *replaced_text; + dst.push_str(end); + dst.push_str(src_end); + UpdateStatus::from_changed(changed) +} + +pub fn update_text_region_fn( + start: &str, + end: &str, + mut insert: impl FnMut(&mut String), +) -> impl FnMut(&Path, &str, &mut String) -> UpdateStatus { + move |path, src, dst| update_text_region(path, start, end, src, dst, &mut insert) +} + +#[must_use] +pub fn is_ident_char(c: u8) -> bool { + matches!(c, b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_') +} + +pub struct StringReplacer<'a> { + searcher: AhoCorasick, + replacements: &'a [(&'a str, &'a str)], +} +impl<'a> StringReplacer<'a> { + #[must_use] + pub fn new(replacements: &'a [(&'a str, &'a str)]) -> Self { + Self { + searcher: AhoCorasickBuilder::new() + .match_kind(aho_corasick::MatchKind::LeftmostLongest) + .build(replacements.iter().map(|&(x, _)| x)) + .unwrap(), + replacements, + } + } + + /// Replace substrings if they aren't bordered by identifier characters. + pub fn replace_ident_fn(&self) -> impl Fn(&Path, &str, &mut String) -> UpdateStatus { + move |_, src, dst| { + let mut pos = 0; + let mut changed = false; + for m in self.searcher.find_iter(src) { + if !is_ident_char(src.as_bytes().get(m.start().wrapping_sub(1)).copied().unwrap_or(0)) + && !is_ident_char(src.as_bytes().get(m.end()).copied().unwrap_or(0)) + { + changed = true; + dst.push_str(&src[pos..m.start()]); + dst.push_str(self.replacements[m.pattern()].1); + pos = m.end(); + } + } + dst.push_str(&src[pos..]); + UpdateStatus::from_changed(changed) + } + } +} + +#[derive(Clone, Copy)] +pub enum Token { + /// Matches any number of doc comments. + AnyDoc, + Ident(&'static str), + CaptureIdent, + LitStr, + CaptureLitStr, + Bang, + CloseBrace, + CloseBracket, + CloseParen, + /// This will consume the first colon even if the second doesn't exist. + DoubleColon, + Comma, + Eq, + Lifetime, + Lt, + Gt, + OpenBrace, + OpenBracket, + OpenParen, + Pound, +} + +pub struct RustSearcher<'txt> { + text: &'txt str, + cursor: lexer::Cursor<'txt>, + pos: u32, + + // Either the next token or a zero-sized whitespace sentinel. + next_token: lexer::Token, +} +impl<'txt> RustSearcher<'txt> { + #[must_use] + pub fn new(text: &'txt str) -> Self { + Self { + text, + cursor: lexer::Cursor::new(text, FrontmatterAllowed::Yes), + pos: 0, + + // Sentinel value indicating there is no read token. + next_token: lexer::Token { + len: 0, + kind: lexer::TokenKind::Whitespace, + }, + } + } + + #[must_use] + pub fn peek_text(&self) -> &'txt str { + &self.text[self.pos as usize..(self.pos + self.next_token.len) as usize] + } + + #[must_use] + pub fn peek(&self) -> lexer::TokenKind { + self.next_token.kind + } + + #[must_use] + pub fn pos(&self) -> u32 { + self.pos + } + + #[must_use] + pub fn at_end(&self) -> bool { + self.next_token.kind == lexer::TokenKind::Eof + } + + pub fn step(&mut self) { + // `next_len` is zero for the sentinel value and the eof marker. + self.pos += self.next_token.len; + self.next_token = self.cursor.advance_token(); + } + + /// Consumes the next token if it matches the requested value and captures the value if + /// requested. Returns true if a token was matched. + fn read_token(&mut self, token: Token, captures: &mut slice::IterMut<'_, &mut &'txt str>) -> bool { + loop { + match (token, self.next_token.kind) { + // Has to be the first match arm so the empty sentinel token will be handled. + // This will also skip all whitespace/comments preceding any tokens. + ( + _, + lexer::TokenKind::Whitespace + | lexer::TokenKind::LineComment { doc_style: None } + | lexer::TokenKind::BlockComment { + doc_style: None, + terminated: true, + }, + ) => { + self.step(); + if self.at_end() { + // `AnyDoc` always matches. + return matches!(token, Token::AnyDoc); + } + }, + ( + Token::AnyDoc, + lexer::TokenKind::BlockComment { terminated: true, .. } | lexer::TokenKind::LineComment { .. }, + ) => { + self.step(); + if self.at_end() { + // `AnyDoc` always matches. + return true; + } + }, + (Token::AnyDoc, _) => return true, + (Token::Bang, lexer::TokenKind::Bang) + | (Token::CloseBrace, lexer::TokenKind::CloseBrace) + | (Token::CloseBracket, lexer::TokenKind::CloseBracket) + | (Token::CloseParen, lexer::TokenKind::CloseParen) + | (Token::Comma, lexer::TokenKind::Comma) + | (Token::Eq, lexer::TokenKind::Eq) + | (Token::Lifetime, lexer::TokenKind::Lifetime { .. }) + | (Token::Lt, lexer::TokenKind::Lt) + | (Token::Gt, lexer::TokenKind::Gt) + | (Token::OpenBrace, lexer::TokenKind::OpenBrace) + | (Token::OpenBracket, lexer::TokenKind::OpenBracket) + | (Token::OpenParen, lexer::TokenKind::OpenParen) + | (Token::Pound, lexer::TokenKind::Pound) + | ( + Token::LitStr, + lexer::TokenKind::Literal { + kind: lexer::LiteralKind::Str { terminated: true } | lexer::LiteralKind::RawStr { .. }, + .. + }, + ) => { + self.step(); + return true; + }, + (Token::Ident(x), lexer::TokenKind::Ident) if x == self.peek_text() => { + self.step(); + return true; + }, + (Token::DoubleColon, lexer::TokenKind::Colon) => { + self.step(); + if !self.at_end() && matches!(self.next_token.kind, lexer::TokenKind::Colon) { + self.step(); + return true; + } + return false; + }, + ( + Token::CaptureLitStr, + lexer::TokenKind::Literal { + kind: lexer::LiteralKind::Str { terminated: true } | lexer::LiteralKind::RawStr { .. }, + .. + }, + ) + | (Token::CaptureIdent, lexer::TokenKind::Ident) => { + **captures.next().unwrap() = self.peek_text(); + self.step(); + return true; + }, + _ => return false, + } + } + } + + #[must_use] + pub fn find_token(&mut self, token: Token) -> bool { + let mut capture = [].iter_mut(); + while !self.read_token(token, &mut capture) { + self.step(); + if self.at_end() { + return false; + } + } + true + } + + #[must_use] + pub fn find_capture_token(&mut self, token: Token) -> Option<&'txt str> { + let mut res = ""; + let mut capture = &mut res; + let mut capture = slice::from_mut(&mut capture).iter_mut(); + while !self.read_token(token, &mut capture) { + self.step(); + if self.at_end() { + return None; + } + } + Some(res) + } + + #[must_use] + pub fn match_tokens(&mut self, tokens: &[Token], captures: &mut [&mut &'txt str]) -> bool { + let mut captures = captures.iter_mut(); + tokens.iter().all(|&t| self.read_token(t, &mut captures)) + } +} - match update_mode { - UpdateMode::Check if contents != new_contents => exit_with_failure(), - UpdateMode::Check => (), - UpdateMode::Change => { - if let Err(e) = fs::write(path, new_contents.as_bytes()) { - panic!("Cannot write to `{}`: {e}", path.display()); +#[expect(clippy::must_use_candidate)] +pub fn try_rename_file(old_name: &Path, new_name: &Path) -> bool { + match OpenOptions::new().create_new(true).write(true).open(new_name) { + Ok(file) => drop(file), + Err(e) if matches!(e.kind(), io::ErrorKind::AlreadyExists | io::ErrorKind::NotFound) => return false, + Err(e) => panic_file(&e, FileAction::Create, new_name), + } + match fs::rename(old_name, new_name) { + Ok(()) => true, + Err(e) => { + drop(fs::remove_file(new_name)); + if e.kind() == io::ErrorKind::NotFound { + false + } else { + panic_file(&e, FileAction::Rename, old_name); } }, } } -/// Replaces a region in a text delimited by two strings. Returns the new text if both delimiters -/// were found, or the missing delimiter if not. -pub(crate) fn replace_region_in_text<'a>( - text: &str, - start: &'a str, - end: &'a str, - mut write_replacement: impl FnMut(&mut String), -) -> Result { - let (text_start, rest) = text.split_once(start).ok_or(start)?; - let (_, text_end) = rest.split_once(end).ok_or(end)?; - - let mut res = String::with_capacity(text.len() + 4096); - res.push_str(text_start); - res.push_str(start); - write_replacement(&mut res); - res.push_str(end); - res.push_str(text_end); - - Ok(res) +pub fn write_file(path: &Path, contents: &str) { + fs::write(path, contents).unwrap_or_else(|e| panic_file(&e, FileAction::Write, path)); } diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 20951afccbb7e..7e3cb40424792 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_lints" # begin autogenerated version -version = "0.1.88" +version = "0.1.89" # end autogenerated version description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index f7f168cb26792..9a1242980418c 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -468,7 +468,7 @@ declare_clippy_lint! { /// #[ignore = "Some good reason"] /// fn test() {} /// ``` - #[clippy::version = "1.85.0"] + #[clippy::version = "1.88.0"] pub IGNORE_WITHOUT_REASON, pedantic, "ignored tests without messages" diff --git a/clippy_lints/src/attrs/useless_attribute.rs b/clippy_lints/src/attrs/useless_attribute.rs index d75b73280e632..4059f9603c33c 100644 --- a/clippy_lints/src/attrs/useless_attribute.rs +++ b/clippy_lints/src/attrs/useless_attribute.rs @@ -26,16 +26,16 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) { if namespace.is_none() && matches!( - name.as_str(), - "ambiguous_glob_reexports" - | "dead_code" - | "deprecated" - | "hidden_glob_reexports" - | "unreachable_pub" - | "unused" - | "unused_braces" - | "unused_import_braces" - | "unused_imports" + name, + sym::ambiguous_glob_reexports + | sym::dead_code + | sym::deprecated + | sym::hidden_glob_reexports + | sym::unreachable_pub + | sym::unused + | sym::unused_braces + | sym::unused_import_braces + | sym::unused_imports ) { return; @@ -43,16 +43,16 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) { if namespace == Some(sym::clippy) && matches!( - name.as_str(), - "wildcard_imports" - | "enum_glob_use" - | "redundant_pub_crate" - | "macro_use_imports" - | "unsafe_removed_from_name" - | "module_name_repetitions" - | "single_component_path_imports" - | "disallowed_types" - | "unused_trait_names" + name, + sym::wildcard_imports + | sym::enum_glob_use + | sym::redundant_pub_crate + | sym::macro_use_imports + | sym::unsafe_removed_from_name + | sym::module_name_repetitions + | sym::single_component_path_imports + | sym::disallowed_types + | sym::unused_trait_names ) { return; diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 52d1d5b4c67a1..31cc004f6855d 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_config::types::{DisallowedPathWithoutReplacement, create_disallowed_map}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{match_def_path, paths}; +use clippy_utils::paths::{self, PathNS}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, DefIdMap}; use rustc_lint::{LateContext, LateLintPass}; @@ -182,6 +182,7 @@ impl AwaitHolding { let (def_ids, _) = create_disallowed_map( tcx, &conf.await_holding_invalid_types, + PathNS::Type, crate::disallowed_types::def_kind_predicate, "type", false, @@ -275,12 +276,10 @@ fn emit_invalid_type( } fn is_mutex_guard(cx: &LateContext<'_>, def_id: DefId) -> bool { - cx.tcx.is_diagnostic_item(sym::MutexGuard, def_id) - || cx.tcx.is_diagnostic_item(sym::RwLockReadGuard, def_id) - || cx.tcx.is_diagnostic_item(sym::RwLockWriteGuard, def_id) - || match_def_path(cx, def_id, &paths::PARKING_LOT_MUTEX_GUARD) - || match_def_path(cx, def_id, &paths::PARKING_LOT_RWLOCK_READ_GUARD) - || match_def_path(cx, def_id, &paths::PARKING_LOT_RWLOCK_WRITE_GUARD) + match cx.tcx.get_diagnostic_name(def_id) { + Some(name) => matches!(name, sym::MutexGuard | sym::RwLockReadGuard | sym::RwLockWriteGuard), + None => paths::PARKING_LOT_GUARDS.iter().any(|guard| guard.matches(cx, def_id)), + } } fn is_refcell_ref(cx: &LateContext<'_>, def_id: DefId) -> bool { diff --git a/clippy_lints/src/bool_assert_comparison.rs b/clippy_lints/src/bool_assert_comparison.rs index 4a876b854165e..ae36bb76117d7 100644 --- a/clippy_lints/src/bool_assert_comparison.rs +++ b/clippy_lints/src/bool_assert_comparison.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node}; use clippy_utils::sugg::Sugg; +use clippy_utils::sym; use clippy_utils::ty::{implements_trait, is_copy}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -73,10 +74,9 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison { let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return; }; - let macro_name = cx.tcx.item_name(macro_call.def_id); - let eq_macro = match macro_name.as_str() { - "assert_eq" | "debug_assert_eq" => true, - "assert_ne" | "debug_assert_ne" => false, + let eq_macro = match cx.tcx.get_diagnostic_name(macro_call.def_id) { + Some(sym::assert_eq_macro | sym::debug_assert_eq_macro) => true, + Some(sym::assert_ne_macro | sym::debug_assert_ne_macro) => false, _ => return, }; let Some((a, b, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else { @@ -115,6 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison { return; } + let macro_name = cx.tcx.item_name(macro_call.def_id); let macro_name = macro_name.as_str(); let non_eq_mac = ¯o_name[..macro_name.len() - 3]; span_lint_and_then( diff --git a/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs b/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs new file mode 100644 index 0000000000000..31cdd078f45a0 --- /dev/null +++ b/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs @@ -0,0 +1,82 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet_with_applicability; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, GenericArg, Ty}; +use rustc_span::def_id::DefId; +use rustc_span::{Symbol, sym}; + +use super::CONFUSING_METHOD_TO_NUMERIC_CAST; + +fn get_primitive_ty_name(ty: Ty<'_>) -> Option<&'static str> { + match ty.kind() { + ty::Char => Some("char"), + ty::Int(int) => Some(int.name_str()), + ty::Uint(uint) => Some(uint.name_str()), + ty::Float(float) => Some(float.name_str()), + _ => None, + } +} + +fn get_const_name_and_ty_name( + cx: &LateContext<'_>, + method_name: Symbol, + method_def_id: DefId, + generics: &[GenericArg<'_>], +) -> Option<(&'static str, &'static str)> { + let method_name = method_name.as_str(); + let diagnostic_name = cx.tcx.get_diagnostic_name(method_def_id); + + let ty_name = if diagnostic_name.is_some_and(|diag| diag == sym::cmp_ord_min || diag == sym::cmp_ord_max) { + // We get the type on which the `min`/`max` method of the `Ord` trait is implemented. + if let [ty] = generics + && let Some(ty) = ty.as_type() + { + get_primitive_ty_name(ty)? + } else { + return None; + } + } else if let Some(impl_id) = cx.tcx.impl_of_method(method_def_id) + && let Some(ty_name) = get_primitive_ty_name(cx.tcx.type_of(impl_id).instantiate_identity()) + && ["min", "max", "minimum", "maximum", "min_value", "max_value"].contains(&method_name) + { + ty_name + } else { + return None; + }; + + let const_name = if method_name.starts_with("max") { "MAX" } else { "MIN" }; + Some((const_name, ty_name)) +} + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { + // We allow casts from any function type to any function type. + match cast_to.kind() { + ty::FnDef(..) | ty::FnPtr(..) => return, + _ => { /* continue to checks */ }, + } + + if let ty::FnDef(def_id, generics) = cast_from.kind() + && let Some(method_name) = cx.tcx.opt_item_name(*def_id) + && let Some((const_name, ty_name)) = get_const_name_and_ty_name(cx, method_name, *def_id, generics.as_slice()) + { + let mut applicability = Applicability::MaybeIncorrect; + let from_snippet = snippet_with_applicability(cx, cast_expr.span, "..", &mut applicability); + + span_lint_and_then( + cx, + CONFUSING_METHOD_TO_NUMERIC_CAST, + expr.span, + format!("casting function pointer `{from_snippet}` to `{cast_to}`"), + |diag| { + diag.span_suggestion_verbose( + expr.span, + "did you mean to use the associated constant?", + format!("{ty_name}::{const_name} as {cast_to}"), + applicability, + ); + }, + ); + } +} diff --git a/clippy_lints/src/casts/manual_dangling_ptr.rs b/clippy_lints/src/casts/manual_dangling_ptr.rs index 8ace27eca895e..61dfc0fc0425e 100644 --- a/clippy_lints/src/casts/manual_dangling_ptr.rs +++ b/clippy_lints/src/casts/manual_dangling_ptr.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::SpanRangeExt; -use clippy_utils::ty::is_normalizable; -use clippy_utils::{expr_or_init, match_def_path, path_def_id, paths, std_or_core}; +use clippy_utils::{expr_or_init, path_def_id, paths, std_or_core}; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, GenericArg, Mutability, QPath, Ty, TyKind}; @@ -55,7 +54,7 @@ fn is_expr_const_aligned(cx: &LateContext<'_>, expr: &Expr<'_>, to: &Ty<'_>) -> fn is_align_of_call(cx: &LateContext<'_>, fun: &Expr<'_>, to: &Ty<'_>) -> bool { if let ExprKind::Path(QPath::Resolved(_, path)) = fun.kind && let Some(fun_id) = path_def_id(cx, fun) - && match_def_path(cx, fun_id, &paths::ALIGN_OF) + && paths::ALIGN_OF.matches(cx, fun_id) && let Some(args) = path.segments.last().and_then(|seg| seg.args) && let [GenericArg::Type(generic_ty)] = args.args { @@ -71,12 +70,10 @@ fn is_literal_aligned(cx: &LateContext<'_>, lit: &Spanned, to: &Ty<'_>) return false; } let to_mid_ty = cx.typeck_results().node_type(to.hir_id); - is_normalizable(cx, cx.param_env, to_mid_ty) - && cx - .tcx - .layout_of(cx.typing_env().as_query_input(to_mid_ty)) - .is_ok_and(|layout| { - let align = u128::from(layout.align.abi.bytes()); - u128::from(val) <= align - }) + cx.tcx + .layout_of(cx.typing_env().as_query_input(to_mid_ty)) + .is_ok_and(|layout| { + let align = u128::from(layout.align.abi.bytes()); + u128::from(val) <= align + }) } diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 76931fce209e5..daae9a8bb0850 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -14,6 +14,7 @@ mod cast_sign_loss; mod cast_slice_different_sizes; mod cast_slice_from_raw_parts; mod char_lit_as_u8; +mod confusing_method_to_numeric_cast; mod fn_to_numeric_cast; mod fn_to_numeric_cast_any; mod fn_to_numeric_cast_with_truncation; @@ -780,12 +781,38 @@ declare_clippy_lint! { /// let aligned = std::ptr::dangling::(); /// let mut_ptr: *mut i64 = std::ptr::dangling_mut(); /// ``` - #[clippy::version = "1.87.0"] + #[clippy::version = "1.88.0"] pub MANUAL_DANGLING_PTR, style, "casting small constant literals to pointers to create dangling pointers" } +declare_clippy_lint! { + /// ### What it does + /// Checks for casts of a primitive method pointer like `max`/`min` to any integer type. + /// + /// ### Why restrict this? + /// Casting a function pointer to an integer can have surprising results and can occur + /// accidentally if parentheses are omitted from a function call. If you aren't doing anything + /// low-level with function pointers then you can opt out of casting functions to integers in + /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function + /// pointer casts in your code. + /// + /// ### Example + /// ```no_run + /// let _ = u16::max as usize; + /// ``` + /// + /// Use instead: + /// ```no_run + /// let _ = u16::MAX as usize; + /// ``` + #[clippy::version = "1.86.0"] + pub CONFUSING_METHOD_TO_NUMERIC_CAST, + suspicious, + "casting a primitive method pointer to any integer type" +} + pub struct Casts { msrv: Msrv, } @@ -823,6 +850,7 @@ impl_lint_pass!(Casts => [ REF_AS_PTR, AS_POINTER_UNDERSCORE, MANUAL_DANGLING_PTR, + CONFUSING_METHOD_TO_NUMERIC_CAST, ]); impl<'tcx> LateLintPass<'tcx> for Casts { @@ -847,6 +875,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts { ptr_cast_constness::check(cx, expr, cast_from_expr, cast_from, cast_to, self.msrv); as_ptr_cast_mut::check(cx, expr, cast_from_expr, cast_to); fn_to_numeric_cast_any::check(cx, expr, cast_from_expr, cast_from, cast_to); + confusing_method_to_numeric_cast::check(cx, expr, cast_from_expr, cast_from, cast_to); fn_to_numeric_cast::check(cx, expr, cast_from_expr, cast_from, cast_to); fn_to_numeric_cast_with_truncation::check(cx, expr, cast_from_expr, cast_from, cast_to); zero_ptr::check(cx, expr, cast_from_expr, cast_to_hir); diff --git a/clippy_lints/src/cloned_ref_to_slice_refs.rs b/clippy_lints/src/cloned_ref_to_slice_refs.rs new file mode 100644 index 0000000000000..6b239a1541b0d --- /dev/null +++ b/clippy_lints/src/cloned_ref_to_slice_refs.rs @@ -0,0 +1,100 @@ +use clippy_config::Conf; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::sugg::Sugg; +use clippy_utils::visitors::is_const_evaluatable; +use clippy_utils::{is_in_const_context, is_mutable, is_trait_method}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::impl_lint_pass; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for slice references with cloned references such as `&[f.clone()]`. + /// + /// ### Why is this bad + /// + /// A reference does not need to be owned in order to used as a slice. + /// + /// ### Known problems + /// + /// This lint does not know whether or not a clone implementation has side effects. + /// + /// ### Example + /// + /// ```ignore + /// let data = 10; + /// let data_ref = &data; + /// take_slice(&[data_ref.clone()]); + /// ``` + /// Use instead: + /// ```ignore + /// use std::slice; + /// let data = 10; + /// let data_ref = &data; + /// take_slice(slice::from_ref(data_ref)); + /// ``` + #[clippy::version = "1.87.0"] + pub CLONED_REF_TO_SLICE_REFS, + perf, + "cloning a reference for slice references" +} + +pub struct ClonedRefToSliceRefs<'a> { + msrv: &'a Msrv, +} +impl<'a> ClonedRefToSliceRefs<'a> { + pub fn new(conf: &'a Conf) -> Self { + Self { msrv: &conf.msrv } + } +} + +impl_lint_pass!(ClonedRefToSliceRefs<'_> => [CLONED_REF_TO_SLICE_REFS]); + +impl<'tcx> LateLintPass<'tcx> for ClonedRefToSliceRefs<'_> { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + if self.msrv.meets(cx, { + if is_in_const_context(cx) { + msrvs::CONST_SLICE_FROM_REF + } else { + msrvs::SLICE_FROM_REF + } + }) + // `&[foo.clone()]` expressions + && let ExprKind::AddrOf(_, mutability, arr) = &expr.kind + // mutable references would have a different meaning + && mutability.is_not() + + // check for single item arrays + && let ExprKind::Array([item]) = &arr.kind + + // check for clones + && let ExprKind::MethodCall(_, val, _, _) = item.kind + && is_trait_method(cx, item, sym::Clone) + + // check for immutability or purity + && (!is_mutable(cx, val) || is_const_evaluatable(cx, val)) + + // get appropriate crate for `slice::from_ref` + && let Some(builtin_crate) = clippy_utils::std_or_core(cx) + { + let mut sugg = Sugg::hir(cx, val, "_"); + if !cx.typeck_results().expr_ty(val).is_ref() { + sugg = sugg.addr(); + } + + span_lint_and_sugg( + cx, + CLONED_REF_TO_SLICE_REFS, + expr.span, + format!("this call to `clone` can be replaced with `{builtin_crate}::slice::from_ref`"), + "try", + format!("{builtin_crate}::slice::from_ref({sugg})"), + Applicability::MaybeIncorrect, + ); + } + } +} diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index 20fae8a6775b9..7f6ecea99fb02 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -1,11 +1,11 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{IntoSpan as _, SpanRangeExt, snippet, snippet_block, snippet_block_with_applicability}; use rustc_ast::BinOpKind; use rustc_errors::Applicability; -use rustc_hir::{Block, Expr, ExprKind, StmtKind}; +use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; use rustc_span::Span; @@ -78,14 +78,14 @@ declare_clippy_lint! { } pub struct CollapsibleIf { - let_chains_enabled: bool, + msrv: Msrv, lint_commented_code: bool, } impl CollapsibleIf { - pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { + pub fn new(conf: &'static Conf) -> Self { Self { - let_chains_enabled: tcx.features().let_chains(), + msrv: conf.msrv, lint_commented_code: conf.lint_commented_code, } } @@ -127,7 +127,7 @@ impl CollapsibleIf { if let Some(inner) = expr_block(then) && cx.tcx.hir_attrs(inner.hir_id).is_empty() && let ExprKind::If(check_inner, _, None) = &inner.kind - && self.eligible_condition(check_inner) + && self.eligible_condition(cx, check_inner) && let ctxt = expr.span.ctxt() && inner.span.ctxt() == ctxt && (self.lint_commented_code || !block_starts_with_comment(cx, then)) @@ -163,8 +163,9 @@ impl CollapsibleIf { } } - pub fn eligible_condition(&self, cond: &Expr<'_>) -> bool { - self.let_chains_enabled || !matches!(cond.kind, ExprKind::Let(..)) + fn eligible_condition(&self, cx: &LateContext<'_>, cond: &Expr<'_>) -> bool { + !matches!(cond.kind, ExprKind::Let(..)) + || (cx.tcx.sess.edition().at_least_rust_2024() && self.msrv.meets(cx, msrvs::LET_CHAINS)) } } @@ -180,7 +181,7 @@ impl LateLintPass<'_> for CollapsibleIf { { Self::check_collapsible_else_if(cx, then.span, else_); } else if else_.is_none() - && self.eligible_condition(cond) + && self.eligible_condition(cx, cond) && let ExprKind::Block(then, None) = then.kind { self.check_collapsible_if_if(cx, expr, cond, then); @@ -202,13 +203,12 @@ fn block_starts_with_comment(cx: &LateContext<'_>, block: &Block<'_>) -> bool { fn expr_block<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> { match block.stmts { [] => block.expr, - [stmt] => { - if let StmtKind::Semi(expr) = stmt.kind { - Some(expr) - } else { - None - } - }, + [ + Stmt { + kind: StmtKind::Semi(expr), + .. + }, + ] if block.expr.is_none() => Some(expr), _ => None, } } diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 2cccd6ba27027..bb825c7655f87 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -64,6 +64,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::casts::CAST_SLICE_DIFFERENT_SIZES_INFO, crate::casts::CAST_SLICE_FROM_RAW_PARTS_INFO, crate::casts::CHAR_LIT_AS_U8_INFO, + crate::casts::CONFUSING_METHOD_TO_NUMERIC_CAST_INFO, crate::casts::FN_TO_NUMERIC_CAST_INFO, crate::casts::FN_TO_NUMERIC_CAST_ANY_INFO, crate::casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION_INFO, @@ -75,6 +76,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::casts::ZERO_PTR_INFO, crate::cfg_not_test::CFG_NOT_TEST_INFO, crate::checked_conversions::CHECKED_CONVERSIONS_INFO, + crate::cloned_ref_to_slice_refs::CLONED_REF_TO_SLICE_REFS_INFO, crate::cognitive_complexity::COGNITIVE_COMPLEXITY_INFO, crate::collapsible_if::COLLAPSIBLE_ELSE_IF_INFO, crate::collapsible_if::COLLAPSIBLE_IF_INFO, @@ -705,13 +707,9 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::transmute::MISSING_TRANSMUTE_ANNOTATIONS_INFO, crate::transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS_INFO, crate::transmute::TRANSMUTE_BYTES_TO_STR_INFO, - crate::transmute::TRANSMUTE_FLOAT_TO_INT_INFO, crate::transmute::TRANSMUTE_INT_TO_BOOL_INFO, - crate::transmute::TRANSMUTE_INT_TO_CHAR_INFO, - crate::transmute::TRANSMUTE_INT_TO_FLOAT_INFO, crate::transmute::TRANSMUTE_INT_TO_NON_ZERO_INFO, crate::transmute::TRANSMUTE_NULL_TO_FN_INFO, - crate::transmute::TRANSMUTE_NUM_TO_BYTES_INFO, crate::transmute::TRANSMUTE_PTR_TO_PTR_INFO, crate::transmute::TRANSMUTE_PTR_TO_REF_INFO, crate::transmute::TRANSMUTE_UNDEFINED_REPR_INFO, diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index b60c11d79d48f..946515386690c 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -2,18 +2,18 @@ // Prefer to use those when possible. macro_rules! declare_with_version { - ($name:ident($name_version:ident): &[$ty:ty] = &[$( + ($name:ident($name_version:ident) = [$( #[clippy::version = $version:literal] $e:expr, )*]) => { - pub static $name: &[$ty] = &[$($e),*]; + pub static $name: &[(&str, &str)] = &[$($e),*]; #[allow(unused)] pub static $name_version: &[&str] = &[$($version),*]; }; } #[rustfmt::skip] -declare_with_version! { DEPRECATED(DEPRECATED_VERSION): &[(&str, &str)] = &[ +declare_with_version! { DEPRECATED(DEPRECATED_VERSION) = [ #[clippy::version = "pre 1.29.0"] ("clippy::should_assert_eq", "`assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can"), #[clippy::version = "pre 1.29.0"] @@ -44,11 +44,10 @@ declare_with_version! { DEPRECATED(DEPRECATED_VERSION): &[(&str, &str)] = &[ ("clippy::option_map_or_err_ok", "`clippy::manual_ok_or` covers this case"), #[clippy::version = "1.86.0"] ("clippy::match_on_vec_items", "`clippy::indexing_slicing` covers indexing and slicing on `Vec<_>`"), - // end deprecated lints. used by `cargo dev deprecate_lint` ]} #[rustfmt::skip] -declare_with_version! { RENAMED(RENAMED_VERSION): &[(&str, &str)] = &[ +declare_with_version! { RENAMED(RENAMED_VERSION) = [ #[clippy::version = ""] ("clippy::almost_complete_letter_range", "clippy::almost_complete_range"), #[clippy::version = ""] @@ -187,5 +186,12 @@ declare_with_version! { RENAMED(RENAMED_VERSION): &[(&str, &str)] = &[ ("clippy::vtable_address_comparisons", "ambiguous_wide_pointer_comparisons"), #[clippy::version = ""] ("clippy::reverse_range_loop", "clippy::reversed_empty_ranges"), - // end renamed lints. used by `cargo dev rename_lint` + #[clippy::version = "1.88.0"] + ("clippy::transmute_int_to_float", "unnecessary_transmutes"), + #[clippy::version = "1.88.0"] + ("clippy::transmute_int_to_char", "unnecessary_transmutes"), + #[clippy::version = "1.88.0"] + ("clippy::transmute_float_to_int", "unnecessary_transmutes"), + #[clippy::version = "1.88.0"] + ("clippy::transmute_num_to_bytes", "unnecessary_transmutes"), ]} diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 06528f875a29b..3443b36eb4f39 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -2,7 +2,7 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy}; -use clippy_utils::{has_non_exhaustive_attr, is_lint_allowed, match_def_path, paths}; +use clippy_utils::{has_non_exhaustive_attr, is_lint_allowed, paths}; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn, walk_item}; @@ -377,7 +377,7 @@ fn check_unsafe_derive_deserialize<'tcx>( } if let Some(trait_def_id) = trait_ref.trait_def_id() - && match_def_path(cx, trait_def_id, &paths::SERDE_DESERIALIZE) + && paths::SERDE_DESERIALIZE.matches(cx, trait_def_id) && let ty::Adt(def, _) = ty.kind() && let Some(local_def_id) = def.did().as_local() && let adt_hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id) diff --git a/clippy_lints/src/disallowed_macros.rs b/clippy_lints/src/disallowed_macros.rs index fc6af204a74a0..9814d4fa84f95 100644 --- a/clippy_lints/src/disallowed_macros.rs +++ b/clippy_lints/src/disallowed_macros.rs @@ -3,6 +3,7 @@ use clippy_config::Conf; use clippy_config::types::{DisallowedPath, create_disallowed_map}; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::macros::macro_backtrace; +use clippy_utils::paths::PathNS; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefIdMap; @@ -76,6 +77,7 @@ impl DisallowedMacros { let (disallowed, _) = create_disallowed_map( tcx, &conf.disallowed_macros, + PathNS::Macro, |def_kind| matches!(def_kind, DefKind::Macro(_)), "macro", false, diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs index 1382dafa931e4..fb970e17f38f0 100644 --- a/clippy_lints/src/disallowed_methods.rs +++ b/clippy_lints/src/disallowed_methods.rs @@ -1,6 +1,7 @@ use clippy_config::Conf; use clippy_config::types::{DisallowedPath, create_disallowed_map}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::paths::PathNS; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{Expr, ExprKind}; @@ -66,6 +67,7 @@ impl DisallowedMethods { let (disallowed, _) = create_disallowed_map( tcx, &conf.disallowed_methods, + PathNS::Value, |def_kind| { matches!( def_kind, diff --git a/clippy_lints/src/disallowed_types.rs b/clippy_lints/src/disallowed_types.rs index 2bae82648ac76..d0b2f0c8407ff 100644 --- a/clippy_lints/src/disallowed_types.rs +++ b/clippy_lints/src/disallowed_types.rs @@ -1,6 +1,7 @@ use clippy_config::Conf; use clippy_config::types::{DisallowedPath, create_disallowed_map}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::paths::PathNS; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefIdMap; @@ -60,7 +61,14 @@ pub struct DisallowedTypes { impl DisallowedTypes { pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { - let (def_ids, prim_tys) = create_disallowed_map(tcx, &conf.disallowed_types, def_kind_predicate, "type", true); + let (def_ids, prim_tys) = create_disallowed_map( + tcx, + &conf.disallowed_types, + PathNS::Type, + def_kind_predicate, + "type", + true, + ); Self { def_ids, prim_tys } } diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index ab77edf1147cb..87da380e95401 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -93,7 +93,7 @@ declare_clippy_lint! { /// ```no_run /// //! [first](x)second /// ``` - #[clippy::version = "1.86.0"] + #[clippy::version = "1.87.0"] pub DOC_LINK_CODE, nursery, "link with code back-to-back with other code" diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 553a00ed868d5..e653a57196d61 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -759,12 +759,12 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic { let recv_ty = cx.typeck_results().expr_ty(receiver); if recv_ty.is_floating_point() && !is_no_std_crate(cx) && is_inherent_method_call(cx, expr) { - match path.ident.name.as_str() { - "ln" => check_ln1p(cx, expr, receiver), - "log" => check_log_base(cx, expr, receiver, args), - "powf" => check_powf(cx, expr, receiver, args), - "powi" => check_powi(cx, expr, receiver, args), - "sqrt" => check_hypot(cx, expr, receiver), + match path.ident.name { + sym::ln => check_ln1p(cx, expr, receiver), + sym::log => check_log_base(cx, expr, receiver, args), + sym::powf => check_powf(cx, expr, receiver, args), + sym::powi => check_powi(cx, expr, receiver, args), + sym::sqrt => check_hypot(cx, expr, receiver), _ => {}, } } diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 5f3fc5100e75b..d0d02a382d15e 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -9,8 +9,8 @@ mod too_many_arguments; mod too_many_lines; use clippy_config::Conf; -use clippy_utils::def_path_def_ids; use clippy_utils::msrvs::Msrv; +use clippy_utils::paths::{PathNS, lookup_path_str}; use rustc_hir as hir; use rustc_hir::intravisit; use rustc_lint::{LateContext, LateLintPass}; @@ -469,7 +469,7 @@ impl Functions { trait_ids: conf .allow_renamed_params_for .iter() - .flat_map(|p| def_path_def_ids(tcx, &p.split("::").collect::>())) + .flat_map(|p| lookup_path_str(tcx, PathNS::Type, p)) .collect(), msrv: conf.msrv, } diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 514e72a48682d..0823ef53ef98a 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -69,7 +69,7 @@ declare_clippy_lint! { /// /// let result = a.saturating_sub(b); /// ``` - #[clippy::version = "1.44.0"] + #[clippy::version = "1.83.0"] pub INVERTED_SATURATING_SUB, correctness, "Check if a variable is smaller than another one and still subtract from it even if smaller" diff --git a/clippy_lints/src/item_name_repetitions.rs b/clippy_lints/src/item_name_repetitions.rs index b1271a264b548..3d4dcd0207023 100644 --- a/clippy_lints/src/item_name_repetitions.rs +++ b/clippy_lints/src/item_name_repetitions.rs @@ -5,7 +5,7 @@ use clippy_utils::macros::span_is_local; use clippy_utils::source::is_present_in_source; use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start, to_camel_case, to_snake_case}; use rustc_data_structures::fx::FxHashSet; -use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData}; +use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, QPath, TyKind, Variant, VariantData}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::symbol::Symbol; @@ -162,6 +162,7 @@ pub struct ItemNameRepetitions { enum_threshold: u64, struct_threshold: u64, avoid_breaking_exported_api: bool, + allow_exact_repetitions: bool, allow_private_module_inception: bool, allowed_prefixes: FxHashSet, } @@ -173,6 +174,7 @@ impl ItemNameRepetitions { enum_threshold: conf.enum_variant_name_threshold, struct_threshold: conf.struct_field_name_threshold, avoid_breaking_exported_api: conf.avoid_breaking_exported_api, + allow_exact_repetitions: conf.allow_exact_repetitions, allow_private_module_inception: conf.allow_private_module_inception, allowed_prefixes: conf.allowed_prefixes.iter().map(|s| to_camel_case(s)).collect(), } @@ -405,6 +407,7 @@ fn check_enum_start(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_> if count_match_start(item_name, name).char_count == item_name_chars && name.chars().nth(item_name_chars).is_some_and(|c| !c.is_lowercase()) && name.chars().nth(item_name_chars + 1).is_some_and(|c| !c.is_numeric()) + && !check_enum_tuple_path_match(name, variant.data) { span_lint_hir( cx, @@ -420,7 +423,9 @@ fn check_enum_end(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_>) let name = variant.ident.name.as_str(); let item_name_chars = item_name.chars().count(); - if count_match_end(item_name, name).char_count == item_name_chars { + if count_match_end(item_name, name).char_count == item_name_chars + && !check_enum_tuple_path_match(name, variant.data) + { span_lint_hir( cx, ENUM_VARIANT_NAMES, @@ -431,6 +436,27 @@ fn check_enum_end(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_>) } } +/// Checks if an enum tuple variant contains a single field +/// whose qualified path contains the variant's name. +fn check_enum_tuple_path_match(variant_name: &str, variant_data: VariantData<'_>) -> bool { + // Only check single-field tuple variants + let VariantData::Tuple(fields, ..) = variant_data else { + return false; + }; + if fields.len() != 1 { + return false; + } + // Check if field type is a path and contains the variant name + match fields[0].ty.kind { + TyKind::Path(QPath::Resolved(_, path)) => path + .segments + .iter() + .any(|segment| segment.ident.name.as_str() == variant_name), + TyKind::Path(QPath::TypeRelative(_, segment)) => segment.ident.name.as_str() == variant_name, + _ => false, + } +} + impl LateLintPass<'_> for ItemNameRepetitions { fn check_item_post(&mut self, _cx: &LateContext<'_>, item: &Item<'_>) { let Some(_ident) = item.kind.ident() else { return }; @@ -462,11 +488,21 @@ impl LateLintPass<'_> for ItemNameRepetitions { } // The `module_name_repetitions` lint should only trigger if the item has the module in its - // name. Having the same name is accepted. - if cx.tcx.visibility(item.owner_id).is_public() - && cx.tcx.visibility(mod_owner_id.def_id).is_public() - && item_camel.len() > mod_camel.len() - { + // name. Having the same name is only accepted if `allow_exact_repetition` is set to `true`. + + let both_are_public = + cx.tcx.visibility(item.owner_id).is_public() && cx.tcx.visibility(mod_owner_id.def_id).is_public(); + + if both_are_public && !self.allow_exact_repetitions && item_camel == *mod_camel { + span_lint( + cx, + MODULE_NAME_REPETITIONS, + ident.span, + "item name is the same as its containing module's name", + ); + } + + if both_are_public && item_camel.len() > mod_camel.len() { let matching = count_match_start(mod_camel, &item_camel); let rmatching = count_match_end(mod_camel, &item_camel); let nchars = mod_camel.chars().count(); diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index bdbf5b37c5f0e..916191b2a7b0f 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type}; +use clippy_utils::ty::{implements_trait, is_must_use_ty}; use clippy_utils::{is_from_proc_macro, is_must_use_func_call, paths}; use rustc_hir::{LetStmt, LocalSource, PatKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -129,12 +129,6 @@ declare_clippy_lint! { declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_FUTURE, LET_UNDERSCORE_UNTYPED]); -const SYNC_GUARD_PATHS: [&[&str]; 3] = [ - &paths::PARKING_LOT_MUTEX_GUARD, - &paths::PARKING_LOT_RWLOCK_READ_GUARD, - &paths::PARKING_LOT_RWLOCK_WRITE_GUARD, -]; - impl<'tcx> LateLintPass<'tcx> for LetUnderscore { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &LetStmt<'tcx>) { if matches!(local.source, LocalSource::Normal) @@ -144,7 +138,9 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { { let init_ty = cx.typeck_results().expr_ty(init); let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() { - GenericArgKind::Type(inner_ty) => SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path)), + GenericArgKind::Type(inner_ty) => inner_ty + .ty_adt_def() + .is_some_and(|adt| paths::PARKING_LOT_GUARDS.iter().any(|path| path.matches(cx, adt.did()))), GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, }); if contains_sync_guard { diff --git a/clippy_lints/src/let_with_type_underscore.rs b/clippy_lints/src/let_with_type_underscore.rs index 9c8488ff381b3..1917ca24a05bd 100644 --- a/clippy_lints/src/let_with_type_underscore.rs +++ b/clippy_lints/src/let_with_type_underscore.rs @@ -1,5 +1,6 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; +use rustc_errors::Applicability; use rustc_hir::{LetStmt, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -32,13 +33,19 @@ impl<'tcx> LateLintPass<'tcx> for UnderscoreTyped { && !local.span.in_external_macro(cx.tcx.sess.source_map()) && !is_from_proc_macro(cx, ty) { - span_lint_and_help( + span_lint_and_then( cx, LET_WITH_TYPE_UNDERSCORE, local.span, "variable declared with type underscore", - Some(ty.span.with_lo(local.pat.span.hi())), - "remove the explicit type `_` declaration", + |diag| { + diag.span_suggestion_verbose( + ty.span.with_lo(local.pat.span.hi()), + "remove the explicit type `_` declaration", + "", + Applicability::MachineApplicable, + ); + }, ); } } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index bc7fc60827a0b..006145cc623c3 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1,5 +1,4 @@ #![feature(array_windows)] -#![feature(binary_heap_into_iter_sorted)] #![feature(box_patterns)] #![feature(macro_metavar_expr_concat)] #![feature(f128)] @@ -7,7 +6,6 @@ #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(iter_partition_in_place)] -#![feature(let_chains)] #![feature(never_type)] #![feature(round_char_boundary)] #![feature(rustc_private)] @@ -96,6 +94,7 @@ mod cargo; mod casts; mod cfg_not_test; mod checked_conversions; +mod cloned_ref_to_slice_refs; mod cognitive_complexity; mod collapsible_if; mod collection_is_never_read; @@ -731,7 +730,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_early_pass(|| Box::new(unused_unit::UnusedUnit)); store.register_late_pass(|_| Box::new(unused_unit::UnusedUnit)); store.register_late_pass(|_| Box::new(returns::Return)); - store.register_late_pass(move |tcx| Box::new(collapsible_if::CollapsibleIf::new(tcx, conf))); + store.register_late_pass(move |_| Box::new(collapsible_if::CollapsibleIf::new(conf))); store.register_late_pass(|_| Box::new(items_after_statements::ItemsAfterStatements)); store.register_early_pass(|| Box::new(precedence::Precedence)); store.register_late_pass(|_| Box::new(needless_parens_on_range_literals::NeedlessParensOnRangeLiterals)); @@ -748,7 +747,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| Box::new(unused_self::UnusedSelf::new(conf))); store.register_late_pass(|_| Box::new(mutable_debug_assertion::DebugAssertWithMutCall)); store.register_late_pass(|_| Box::new(exit::Exit)); - store.register_late_pass(|_| Box::new(to_digit_is_some::ToDigitIsSome)); + store.register_late_pass(move |_| Box::new(to_digit_is_some::ToDigitIsSome::new(conf))); store.register_late_pass(move |_| Box::new(large_stack_arrays::LargeStackArrays::new(conf))); store.register_late_pass(move |_| Box::new(large_const_arrays::LargeConstArrays::new(conf))); store.register_late_pass(|_| Box::new(floating_point_arithmetic::FloatingPointArithmetic)); @@ -944,5 +943,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(manual_option_as_slice::ManualOptionAsSlice::new(conf))); store.register_late_pass(|_| Box::new(single_option_map::SingleOptionMap)); store.register_late_pass(move |_| Box::new(redundant_test_prefix::RedundantTestPrefix)); + store.register_late_pass(|_| Box::new(cloned_ref_to_slice_refs::ClonedRefToSliceRefs::new(conf))); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 5ef5e3a44f85f..9a64226b1ed96 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -88,7 +88,7 @@ declare_clippy_lint! { /// x.chars() /// } /// ``` - #[clippy::version = "1.84.0"] + #[clippy::version = "1.87.0"] pub ELIDABLE_LIFETIME_NAMES, pedantic, "lifetime name that can be replaced with the anonymous lifetime" diff --git a/clippy_lints/src/loops/manual_slice_fill.rs b/clippy_lints/src/loops/manual_slice_fill.rs index 343f7c5d2d121..15c656cc7bc76 100644 --- a/clippy_lints/src/loops/manual_slice_fill.rs +++ b/clippy_lints/src/loops/manual_slice_fill.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{HasSession, snippet_with_applicability}; -use clippy_utils::ty::implements_trait; +use clippy_utils::ty::{implements_trait, is_slice_like}; use clippy_utils::visitors::is_local_used; use clippy_utils::{higher, peel_blocks_with_stmt, span_contains_comment}; use rustc_ast::ast::LitKind; @@ -58,6 +58,8 @@ pub(super) fn check<'tcx>( && let Res::Local(idx_hir) = idx_path.res && !is_local_used(cx, assignval, idx_hir) && msrv.meets(cx, msrvs::SLICE_FILL) + && let slice_ty = cx.typeck_results().expr_ty(slice).peel_refs() + && is_slice_like(cx, slice_ty) { sugg(cx, body, expr, slice.span, assignval.span); } diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 2b66827e82eeb..56d2bef2305a7 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -778,7 +778,7 @@ declare_clippy_lint! { /// let _ = s[idx..]; /// } /// ``` - #[clippy::version = "1.83.0"] + #[clippy::version = "1.88.0"] pub CHAR_INDICES_AS_BYTE_INDICES, correctness, "using the character position yielded by `.chars().enumerate()` in a context where a byte index is expected" diff --git a/clippy_lints/src/manual_abs_diff.rs b/clippy_lints/src/manual_abs_diff.rs index c515e41f242f5..bac4b3d32f2a5 100644 --- a/clippy_lints/src/manual_abs_diff.rs +++ b/clippy_lints/src/manual_abs_diff.rs @@ -36,7 +36,7 @@ declare_clippy_lint! { /// a.abs_diff(b) /// # ; /// ``` - #[clippy::version = "1.86.0"] + #[clippy::version = "1.88.0"] pub MANUAL_ABS_DIFF, complexity, "using an if-else pattern instead of `abs_diff`" diff --git a/clippy_lints/src/manual_ignore_case_cmp.rs b/clippy_lints/src/manual_ignore_case_cmp.rs index d92069edb6d00..57c03fbb2ed2b 100644 --- a/clippy_lints/src/manual_ignore_case_cmp.rs +++ b/clippy_lints/src/manual_ignore_case_cmp.rs @@ -1,6 +1,7 @@ use crate::manual_ignore_case_cmp::MatchType::{Literal, ToAscii}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sym; use clippy_utils::ty::{get_type_diagnostic_name, is_type_diagnostic_item, is_type_lang_item}; use rustc_ast::LitKind; use rustc_errors::Applicability; @@ -10,7 +11,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::{Ty, UintTy}; use rustc_session::declare_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -47,9 +48,9 @@ enum MatchType<'a, 'b> { fn get_ascii_type<'a, 'b>(cx: &LateContext<'a>, kind: rustc_hir::ExprKind<'b>) -> Option<(Span, MatchType<'a, 'b>)> { if let MethodCall(path, expr, _, _) = kind { - let is_lower = match path.ident.name.as_str() { - "to_ascii_lowercase" => true, - "to_ascii_uppercase" => false, + let is_lower = match path.ident.name { + sym::to_ascii_lowercase => true, + sym::to_ascii_uppercase => false, _ => return None, }; let ty_raw = cx.typeck_results().expr_ty(expr); diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index d6ac6e106b4bd..0b3bec714c0e1 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -4,11 +4,14 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::IfLetOrMatch; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_lint_allowed, is_never_expr, msrvs, pat_and_expr_can_be_question_mark, peel_blocks}; +use clippy_utils::{ + MaybePath, is_lint_allowed, is_never_expr, is_wild, msrvs, pat_and_expr_can_be_question_mark, path_res, peel_blocks, +}; use rustc_ast::BindingMode; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath, Stmt, StmtKind}; +use rustc_hir::def::{CtorOf, DefKind, Res}; +use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LintContext}; use rustc_span::Span; @@ -91,14 +94,15 @@ impl<'tcx> QuestionMark { let Some((idx, diverging_arm)) = diverging_arm_opt else { return; }; + + let pat_arm = &arms[1 - idx]; // If the non-diverging arm is the first one, its pattern can be reused in a let/else statement. // However, if it arrives in second position, its pattern may cover some cases already covered // by the diverging one. - // TODO: accept the non-diverging arm as a second position if patterns are disjointed. - if idx == 0 { + if idx == 0 && !is_arms_disjointed(cx, diverging_arm, pat_arm) { return; } - let pat_arm = &arms[1 - idx]; + let Some(ident_map) = expr_simple_identity_map(local.pat, pat_arm.pat, pat_arm.body) else { return; }; @@ -110,6 +114,63 @@ impl<'tcx> QuestionMark { } } +/// Checks if the patterns of the arms are disjointed. Currently, we only support patterns of simple +/// enum variants without nested patterns or bindings. +/// +/// TODO: Support more complex patterns. +fn is_arms_disjointed(cx: &LateContext<'_>, arm1: &Arm<'_>, arm2: &Arm<'_>) -> bool { + if arm1.guard.is_some() || arm2.guard.is_some() { + return false; + } + + if !is_enum_variant(cx, arm1.pat) || !is_enum_variant(cx, arm2.pat) { + return false; + } + + true +} + +/// Returns `true` if the given pattern is a variant of an enum. +pub fn is_enum_variant(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { + struct Pat<'hir>(&'hir rustc_hir::Pat<'hir>); + + impl<'hir> MaybePath<'hir> for Pat<'hir> { + fn qpath_opt(&self) -> Option<&QPath<'hir>> { + match self.0.kind { + PatKind::Struct(ref qpath, fields, _) + if fields + .iter() + .all(|field| is_wild(field.pat) || matches!(field.pat.kind, PatKind::Binding(..))) => + { + Some(qpath) + }, + PatKind::TupleStruct(ref qpath, pats, _) + if pats + .iter() + .all(|pat| is_wild(pat) || matches!(pat.kind, PatKind::Binding(..))) => + { + Some(qpath) + }, + PatKind::Expr(&PatExpr { + kind: PatExprKind::Path(ref qpath), + .. + }) => Some(qpath), + _ => None, + } + } + + fn hir_id(&self) -> HirId { + self.0.hir_id + } + } + + let res = path_res(cx, &Pat(pat)); + matches!( + res, + Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) + ) +} + fn emit_manual_let_else( cx: &LateContext<'_>, span: Span, diff --git a/clippy_lints/src/manual_option_as_slice.rs b/clippy_lints/src/manual_option_as_slice.rs index b365dbf088f58..b55c11f2d5b69 100644 --- a/clippy_lints/src/manual_option_as_slice.rs +++ b/clippy_lints/src/manual_option_as_slice.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::msrvs::Msrv; -use clippy_utils::{is_none_arm, msrvs, peel_hir_expr_refs, sym}; +use clippy_utils::{is_none_arm, msrvs, paths, peel_hir_expr_refs, sym}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Arm, Expr, ExprKind, LangItem, Pat, PatKind, QPath, is_range_literal}; @@ -80,26 +80,26 @@ impl LateLintPass<'_> for ManualOptionAsSlice { check_map(cx, callee, span, self.msrv); } }, - ExprKind::MethodCall(seg, callee, [or], _) => match seg.ident.name.as_str() { - "unwrap_or" => { + ExprKind::MethodCall(seg, callee, [or], _) => match seg.ident.name { + sym::unwrap_or => { if is_empty_slice(cx, or) { check_map(cx, callee, span, self.msrv); } }, - "unwrap_or_else" => { + sym::unwrap_or_else => { if returns_empty_slice(cx, or) { check_map(cx, callee, span, self.msrv); } }, _ => {}, }, - ExprKind::MethodCall(seg, callee, [or_else, map], _) => match seg.ident.name.as_str() { - "map_or" => { + ExprKind::MethodCall(seg, callee, [or_else, map], _) => match seg.ident.name { + sym::map_or => { if is_empty_slice(cx, or_else) && is_slice_from_ref(cx, map) { check_as_ref(cx, callee, span, self.msrv); } }, - "map_or_else" => { + sym::map_or_else => { if returns_empty_slice(cx, or_else) && is_slice_from_ref(cx, map) { check_as_ref(cx, callee, span, self.msrv); } @@ -220,5 +220,5 @@ fn is_empty_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } fn is_slice_from_ref(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - clippy_utils::is_expr_path_def_path(cx, expr, &["core", "slice", "raw", "from_ref"]) + paths::SLICE_FROM_REF.matches_path(cx, expr) } diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs index b64ae0b24d818..3ac2c9fc2b361 100644 --- a/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/clippy_lints/src/matches/manual_unwrap_or.rs @@ -1,5 +1,6 @@ use clippy_utils::consts::ConstEvalCtxt; use clippy_utils::source::{SpanRangeExt as _, indent_of, reindent_multiline}; +use rustc_ast::{BindingMode, ByRef}; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, Pat, PatExpr, PatExprKind, PatKind, QPath}; @@ -16,7 +17,7 @@ use super::{MANUAL_UNWRAP_OR, MANUAL_UNWRAP_OR_DEFAULT}; fn get_some(cx: &LateContext<'_>, pat: &Pat<'_>) -> Option { if let PatKind::TupleStruct(QPath::Resolved(_, path), &[pat], _) = pat.kind - && let PatKind::Binding(_, pat_id, _, _) = pat.kind + && let PatKind::Binding(BindingMode(ByRef::No, _), pat_id, _, _) = pat.kind && let Some(def_id) = path.res.opt_def_id() // Since it comes from a pattern binding, we need to get the parent to actually match // against it. diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index a54d835b538c1..28efd2038b387 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -62,7 +62,7 @@ declare_clippy_lint! { /// let mut an_option = Some(0); /// let taken = an_option.replace(1); /// ``` - #[clippy::version = "1.86.0"] + #[clippy::version = "1.87.0"] pub MEM_REPLACE_OPTION_WITH_SOME, style, "replacing an `Option` with `Some` instead of `replace()`" diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index d07870d4951e0..292fa08b59843 100644 --- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; +use clippy_utils::sym; use clippy_utils::ty::is_type_lang_item; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -21,8 +22,8 @@ pub(super) fn check<'tcx>( ) { if let ExprKind::MethodCall(path_segment, ..) = recv.kind && matches!( - path_segment.ident.name.as_str(), - "to_lowercase" | "to_uppercase" | "to_ascii_lowercase" | "to_ascii_uppercase" + path_segment.ident.name, + sym::to_lowercase | sym::to_uppercase | sym::to_ascii_lowercase | sym::to_ascii_uppercase ) { return; diff --git a/clippy_lints/src/methods/io_other_error.rs b/clippy_lints/src/methods/io_other_error.rs index bdc834bd47a56..ec4b9c7ae2ee6 100644 --- a/clippy_lints/src/methods/io_other_error.rs +++ b/clippy_lints/src/methods/io_other_error.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::{expr_or_init, paths}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; @@ -8,13 +9,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, path: &Expr<'_>, args if let [error_kind, error] = args && !expr.span.from_expansion() && !error_kind.span.from_expansion() - && clippy_utils::is_expr_path_def_path(cx, path, &clippy_utils::paths::IO_ERROR_NEW) - && clippy_utils::is_expr_path_def_path( - cx, - clippy_utils::expr_or_init(cx, error_kind), - &clippy_utils::paths::IO_ERRORKIND_OTHER, - ) && let ExprKind::Path(QPath::TypeRelative(_, new_segment)) = path.kind + && paths::IO_ERROR_NEW.matches_path(cx, path) + && paths::IO_ERRORKIND_OTHER_CTOR.matches_path(cx, expr_or_init(cx, error_kind)) && msrv.meets(cx, msrvs::IO_ERROR_OTHER) { span_lint_and_then( diff --git a/clippy_lints/src/methods/manual_c_str_literals.rs b/clippy_lints/src/methods/manual_c_str_literals.rs index 0274e31b4c338..3fa83cd39d1d2 100644 --- a/clippy_lints/src/methods/manual_c_str_literals.rs +++ b/clippy_lints/src/methods/manual_c_str_literals.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::get_parent_expr; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; +use clippy_utils::{get_parent_expr, sym}; use rustc_ast::{LitKind, StrStyle}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Node, QPath, TyKind}; use rustc_lint::LateContext; use rustc_span::edition::Edition::Edition2021; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol}; use super::MANUAL_C_STR_LITERALS; @@ -71,15 +71,15 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, func: &Expr<'_>, args && cx.tcx.sess.edition() >= Edition2021 && msrv.meets(cx, msrvs::C_STR_LITERALS) { - match fn_name.as_str() { - name @ ("from_bytes_with_nul" | "from_bytes_with_nul_unchecked") + match fn_name { + sym::from_bytes_with_nul | sym::from_bytes_with_nul_unchecked if !arg.span.from_expansion() && let ExprKind::Lit(lit) = arg.kind && let LitKind::ByteStr(_, StrStyle::Cooked) | LitKind::Str(_, StrStyle::Cooked) = lit.node => { - check_from_bytes(cx, expr, arg, name); + check_from_bytes(cx, expr, arg, fn_name); }, - "from_ptr" => check_from_ptr(cx, expr, arg), + sym::from_ptr => check_from_ptr(cx, expr, arg), _ => {}, } } @@ -106,13 +106,13 @@ fn check_from_ptr(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>) { } } /// Checks `CStr::from_bytes_with_nul(b"foo\0")` -fn check_from_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, method: &str) { +fn check_from_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, method: Symbol) { let (span, applicability) = if let Some(parent) = get_parent_expr(cx, expr) && let ExprKind::MethodCall(method, ..) = parent.kind && [sym::unwrap, sym::expect].contains(&method.ident.name) { (parent.span, Applicability::MachineApplicable) - } else if method == "from_bytes_with_nul_unchecked" { + } else if method == sym::from_bytes_with_nul_unchecked { // `*_unchecked` returns `&CStr` directly, nothing needs to be changed (expr.span, Applicability::MachineApplicable) } else { diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index 18978a1d2bc86..e2df8ce1513c8 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -1,9 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{match_def_path, path_def_id}; +use clippy_utils::{path_res, sym}; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; +use rustc_hir::def::Res; use rustc_lint::LateContext; use rustc_middle::ty::layout::LayoutOf; @@ -79,16 +80,15 @@ fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option { } let ty = cx.typeck_results().expr_ty(expr); - let ty_str = ty.to_string(); - // `std::T::MAX` `std::T::MIN` constants - if let Some(id) = path_def_id(cx, expr) { - if match_def_path(cx, id, &["core", &ty_str, "MAX"]) { - return Some(MinMax::Max); - } - - if match_def_path(cx, id, &["core", &ty_str, "MIN"]) { - return Some(MinMax::Min); + // `T::MAX` and `T::MIN` constants + if let hir::ExprKind::Path(hir::QPath::TypeRelative(base, seg)) = expr.kind + && let Res::PrimTy(_) = path_res(cx, base) + { + match seg.ident.name { + sym::MAX => return Some(MinMax::Max), + sym::MIN => return Some(MinMax::Min), + _ => {}, } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 10f4637d08f66..e0e6a1a59b623 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4428,7 +4428,7 @@ declare_clippy_lint! { /// let file = BufReader::new(std::fs::File::open("./bytes.txt").unwrap()); /// file.bytes(); /// ``` - #[clippy::version = "1.86.0"] + #[clippy::version = "1.87.0"] pub UNBUFFERED_BYTES, perf, "calling .bytes() is very inefficient when data is not in memory" @@ -4453,7 +4453,7 @@ declare_clippy_lint! { /// values.contains(&10) /// } /// ``` - #[clippy::version = "1.86.0"] + #[clippy::version = "1.87.0"] pub MANUAL_CONTAINS, perf, "unnecessary `iter().any()` on slices that can be replaced with `contains()`" @@ -4709,6 +4709,8 @@ impl_lint_pass!(Methods => [ ]); /// Extracts a method call name, args, and `Span` of the method name. +/// This ensures that neither the receiver nor any of the arguments +/// come from expansion. pub fn method_call<'tcx>( recv: &'tcx Expr<'tcx>, ) -> Option<(&'tcx str, &'tcx Expr<'tcx>, &'tcx [Expr<'tcx>], Span, Span)> { @@ -4907,6 +4909,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { impl Methods { #[allow(clippy::too_many_lines)] fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + // Handle method calls whose receiver and arguments may not come from expansion if let Some((name, recv, args, span, call_span)) = method_call(expr) { match (name, args) { ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => { @@ -5049,29 +5052,12 @@ impl Methods { Some(("err", recv, [], err_span, _)) => { err_expect::check(cx, expr, recv, span, err_span, self.msrv); }, - _ => unwrap_expect_used::check( - cx, - expr, - recv, - false, - self.allow_expect_in_consts, - self.allow_expect_in_tests, - unwrap_expect_used::Variant::Expect, - ), + _ => {}, } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, - ("expect_err", [_]) => { + ("expect_err", [_]) | ("unwrap_err" | "unwrap_unchecked" | "unwrap_err_unchecked", []) => { unnecessary_literal_unwrap::check(cx, expr, recv, name, args); - unwrap_expect_used::check( - cx, - expr, - recv, - true, - self.allow_expect_in_consts, - self.allow_expect_in_tests, - unwrap_expect_used::Variant::Expect, - ); }, ("extend", [arg]) => { string_extend_chars::check(cx, expr, recv, arg); @@ -5437,27 +5423,6 @@ impl Methods { _ => {}, } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); - unwrap_expect_used::check( - cx, - expr, - recv, - false, - self.allow_unwrap_in_consts, - self.allow_unwrap_in_tests, - unwrap_expect_used::Variant::Unwrap, - ); - }, - ("unwrap_err", []) => { - unnecessary_literal_unwrap::check(cx, expr, recv, name, args); - unwrap_expect_used::check( - cx, - expr, - recv, - true, - self.allow_unwrap_in_consts, - self.allow_unwrap_in_tests, - unwrap_expect_used::Variant::Unwrap, - ); }, ("unwrap_or", [u_arg]) => { match method_call(recv) { @@ -5486,9 +5451,6 @@ impl Methods { } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, - ("unwrap_unchecked" | "unwrap_err_unchecked", []) => { - unnecessary_literal_unwrap::check(cx, expr, recv, name, args); - }, ("unwrap_or_else", [u_arg]) => { match method_call(recv) { Some(("map", recv, [map_arg], _, _)) @@ -5526,6 +5488,56 @@ impl Methods { _ => {}, } } + // Handle method calls whose receiver and arguments may come from expansion + if let ExprKind::MethodCall(path, recv, args, _call_span) = expr.kind { + match (path.ident.name.as_str(), args) { + ("expect", [_]) if !matches!(method_call(recv), Some(("ok" | "err", _, [], _, _))) => { + unwrap_expect_used::check( + cx, + expr, + recv, + false, + self.allow_expect_in_consts, + self.allow_expect_in_tests, + unwrap_expect_used::Variant::Expect, + ); + }, + ("expect_err", [_]) => { + unwrap_expect_used::check( + cx, + expr, + recv, + true, + self.allow_expect_in_consts, + self.allow_expect_in_tests, + unwrap_expect_used::Variant::Expect, + ); + }, + ("unwrap", []) => { + unwrap_expect_used::check( + cx, + expr, + recv, + false, + self.allow_unwrap_in_consts, + self.allow_unwrap_in_tests, + unwrap_expect_used::Variant::Unwrap, + ); + }, + ("unwrap_err", []) => { + unwrap_expect_used::check( + cx, + expr, + recv, + true, + self.allow_unwrap_in_consts, + self.allow_unwrap_in_tests, + unwrap_expect_used::Variant::Unwrap, + ); + }, + _ => {}, + } + } } } diff --git a/clippy_lints/src/methods/needless_character_iteration.rs b/clippy_lints/src/methods/needless_character_iteration.rs index f528f7f065c6e..71c1576cd57d1 100644 --- a/clippy_lints/src/methods/needless_character_iteration.rs +++ b/clippy_lints/src/methods/needless_character_iteration.rs @@ -7,9 +7,8 @@ use rustc_span::Span; use super::NEEDLESS_CHARACTER_ITERATION; use super::utils::get_last_chain_binding_hir_id; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::paths::CHAR_IS_ASCII; use clippy_utils::source::SpanRangeExt; -use clippy_utils::{match_def_path, path_to_local_id, peel_blocks, sym}; +use clippy_utils::{is_path_diagnostic_item, path_to_local_id, peel_blocks, sym}; fn peels_expr_ref<'a, 'tcx>(mut expr: &'a Expr<'tcx>) -> &'a Expr<'tcx> { while let ExprKind::AddrOf(_, _, e) = expr.kind { @@ -76,9 +75,7 @@ fn handle_expr( // If we have `!is_ascii`, then only `.any()` should warn. And if the condition is // `is_ascii`, then only `.all()` should warn. if revert != is_all - && let ExprKind::Path(path) = fn_path.kind - && let Some(fn_def_id) = cx.qpath_res(&path, fn_path.hir_id).opt_def_id() - && match_def_path(cx, fn_def_id, &CHAR_IS_ASCII) + && is_path_diagnostic_item(cx, fn_path, sym::char_is_ascii) && path_to_local_id(peels_expr_ref(arg), first_param) && let Some(snippet) = before_chars.get_source_text(cx) { diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index cd22583b8a253..4c1ed6a1d833e 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -357,20 +357,20 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { if let Some(hir_id) = self.current_statement_hir_id { self.hir_id_uses_map.insert(hir_id, self.uses.len()); } - match method_name.ident.name.as_str() { - "into_iter" => self.uses.push(Some(IterFunction { + match method_name.ident.name { + sym::into_iter => self.uses.push(Some(IterFunction { func: IterFunctionKind::IntoIter(expr.hir_id), span: expr.span, })), - "len" => self.uses.push(Some(IterFunction { + sym::len => self.uses.push(Some(IterFunction { func: IterFunctionKind::Len, span: expr.span, })), - "is_empty" => self.uses.push(Some(IterFunction { + sym::is_empty => self.uses.push(Some(IterFunction { func: IterFunctionKind::IsEmpty, span: expr.span, })), - "contains" => self.uses.push(Some(IterFunction { + sym::contains => self.uses.push(Some(IterFunction { func: IterFunctionKind::Contains(args[0].span), span: expr.span, })), diff --git a/clippy_lints/src/methods/open_options.rs b/clippy_lints/src/methods/open_options.rs index da084871402a7..bce314e64f053 100644 --- a/clippy_lints/src/methods/open_options.rs +++ b/clippy_lints/src/methods/open_options.rs @@ -1,8 +1,8 @@ use rustc_data_structures::fx::FxHashMap; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::ty::{is_type_diagnostic_item, match_type}; -use clippy_utils::{match_any_def_paths, paths}; +use clippy_utils::paths; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; @@ -13,7 +13,7 @@ use rustc_span::{Span, sym}; use super::{NONSENSICAL_OPEN_OPTIONS, SUSPICIOUS_OPEN_OPTIONS}; fn is_open_options(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - is_type_diagnostic_item(cx, ty, sym::FsOpenOptions) || match_type(cx, ty, &paths::TOKIO_IO_OPEN_OPTIONS) + is_type_diagnostic_item(cx, ty, sym::FsOpenOptions) || paths::TOKIO_IO_OPEN_OPTIONS.matches_ty(cx, ty) } pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { @@ -126,14 +126,14 @@ fn get_open_options( && let ExprKind::Path(path) = callee.kind && let Some(did) = cx.qpath_res(&path, callee.hir_id).opt_def_id() { - let std_file_options = [sym::file_options, sym::open_options_new]; - - let tokio_file_options: &[&[&str]] = &[&paths::TOKIO_IO_OPEN_OPTIONS_NEW, &paths::TOKIO_FILE_OPTIONS]; + let is_std_options = matches!( + cx.tcx.get_diagnostic_name(did), + Some(sym::file_options | sym::open_options_new) + ); - let is_std_options = std_file_options - .into_iter() - .any(|sym| cx.tcx.is_diagnostic_item(sym, did)); - is_std_options || match_any_def_paths(cx, did, tokio_file_options).is_some() + is_std_options + || paths::TOKIO_IO_OPEN_OPTIONS_NEW.matches(cx, did) + || paths::TOKIO_FILE_OPTIONS.matches(cx, did) } else { false } diff --git a/clippy_lints/src/methods/return_and_then.rs b/clippy_lints/src/methods/return_and_then.rs index 91643b0dfefde..df8544f92203e 100644 --- a/clippy_lints/src/methods/return_and_then.rs +++ b/clippy_lints/src/methods/return_and_then.rs @@ -9,7 +9,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline, snippet_with_applicability}; use clippy_utils::ty::get_type_diagnostic_name; use clippy_utils::visitors::for_each_unconsumed_temporary; -use clippy_utils::{is_expr_final_block_expr, peel_blocks}; +use clippy_utils::{get_parent_expr, peel_blocks}; use super::RETURN_AND_THEN; @@ -21,7 +21,7 @@ pub(super) fn check<'tcx>( recv: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'_>, ) { - if !is_expr_final_block_expr(cx.tcx, expr) { + if cx.tcx.hir_get_fn_id_for_return_block(expr.hir_id).is_none() { return; } @@ -55,12 +55,24 @@ pub(super) fn check<'tcx>( None => &body_snip, }; - let sugg = format!( - "let {} = {}?;\n{}", - arg_snip, - recv_snip, - reindent_multiline(inner, false, indent_of(cx, expr.span)) - ); + // If suggestion is going to get inserted as part of a `return` expression, it must be blockified. + let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr) { + let base_indent = indent_of(cx, parent_expr.span); + let inner_indent = base_indent.map(|i| i + 4); + format!( + "{}\n{}\n{}", + reindent_multiline(&format!("{{\nlet {arg_snip} = {recv_snip}?;"), true, inner_indent), + reindent_multiline(inner, false, inner_indent), + reindent_multiline("}", false, base_indent), + ) + } else { + format!( + "let {} = {}?;\n{}", + arg_snip, + recv_snip, + reindent_multiline(inner, false, indent_of(cx, expr.span)) + ) + }; span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index d183457da25a2..c8efb600f576f 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -4,7 +4,7 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use clippy_utils::usage::local_used_after_expr; use clippy_utils::visitors::{Descend, for_each_expr}; -use clippy_utils::{is_diag_item_method, match_def_path, path_to_local_id, paths}; +use clippy_utils::{is_diag_item_method, path_to_local_id, paths}; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::{ @@ -288,7 +288,7 @@ fn parse_iter_usage<'tcx>( match (name.ident.as_str(), args) { ("next", []) if cx.tcx.trait_of_item(did) == Some(iter_id) => (IterUsageKind::Nth(0), e.span), ("next_tuple", []) => { - return if match_def_path(cx, did, &paths::ITERTOOLS_NEXT_TUPLE) + return if paths::ITERTOOLS_NEXT_TUPLE.matches(cx, did) && let ty::Adt(adt_def, subs) = cx.typeck_results().expr_ty(e).kind() && cx.tcx.is_diagnostic_item(sym::Option, adt_def.did()) && let ty::Tuple(subs) = subs.type_at(0).kind() diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs index 0cbf6004be3a0..17e2620d9dd47 100644 --- a/clippy_lints/src/methods/useless_asref.rs +++ b/clippy_lints/src/methods/useless_asref.rs @@ -1,9 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{implements_trait, should_call_clone_as_function, walk_ptrs_ty_depth}; -use clippy_utils::{ - get_parent_expr, is_diag_trait_item, match_def_path, path_to_local_id, peel_blocks, strip_pat_refs, -}; +use clippy_utils::{get_parent_expr, is_diag_trait_item, path_to_local_id, peel_blocks, strip_pat_refs}; use rustc_errors::Applicability; use rustc_hir::{self as hir, LangItem}; use rustc_lint::LateContext; @@ -81,8 +79,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, applicability, ); } - } else if match_def_path(cx, def_id, &["core", "option", "Option", call_name]) - || match_def_path(cx, def_id, &["core", "result", "Result", call_name]) + } else if let Some(impl_id) = cx.tcx.opt_parent(def_id) + && let Some(adt) = cx.tcx.type_of(impl_id).instantiate_identity().ty_adt_def() + && (cx.tcx.lang_items().option_type() == Some(adt.did()) || cx.tcx.is_diagnostic_item(sym::Result, adt.did())) { let rcv_ty = cx.typeck_results().expr_ty(recvr).peel_refs(); let res_ty = cx.typeck_results().expr_ty(expr).peel_refs(); diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 1f142bc3ba63c..f3e24044fb6c2 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -155,9 +155,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { return; } - let mir = cx.tcx.mir_drops_elaborated_and_const_checked(def_id); + let mir = cx.tcx.optimized_mir(def_id); - if let Ok(()) = is_min_const_fn(cx, &mir.borrow(), self.msrv) + if let Ok(()) = is_min_const_fn(cx, mir, self.msrv) && let hir::Node::Item(hir::Item { vis_span, .. }) | hir::Node::ImplItem(hir::ImplItem { vis_span, .. }) = cx.tcx.hir_node_by_def_id(def_id) { diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index b234b190153b6..7772051eb5c61 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -48,6 +48,8 @@ pub struct MissingDoc { /// Whether to **only** check for missing documentation in items visible within the current /// crate. For example, `pub(crate)` items. crate_items_only: bool, + /// Whether to allow fields starting with an underscore to skip documentation requirements + allow_unused: bool, /// Stack of whether #[doc(hidden)] is set /// at each level which has lint attributes. doc_hidden_stack: Vec, @@ -59,6 +61,7 @@ impl MissingDoc { pub fn new(conf: &'static Conf) -> Self { Self { crate_items_only: conf.missing_docs_in_crate_items, + allow_unused: conf.missing_docs_allow_unused, doc_hidden_stack: vec![false], prev_span: None, } @@ -260,11 +263,12 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { } fn check_field_def(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::FieldDef<'_>) { - if !sf.is_positional() { + if !(sf.is_positional() + || is_from_proc_macro(cx, sf) + || self.allow_unused && sf.ident.as_str().starts_with('_')) + { let attrs = cx.tcx.hir_attrs(sf.hir_id); - if !is_from_proc_macro(cx, sf) { - self.check_missing_docs_attrs(cx, sf.def_id, attrs, sf.span, "a", "struct field"); - } + self.check_missing_docs_attrs(cx, sf.def_id, attrs, sf.span, "a", "struct field"); } self.prev_span = Some(sf.span); } diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index 66631a6920636..a1e621cc9f6b5 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; -use clippy_utils::def_path_def_ids; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::paths::{PathNS, lookup_path_str}; use clippy_utils::source::SpanRangeExt; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -56,8 +56,12 @@ impl ImportRename { renames: conf .enforced_import_renames .iter() - .map(|x| (x.path.split("::").collect::>(), Symbol::intern(&x.rename))) - .flat_map(|(path, rename)| def_path_def_ids(tcx, &path).map(move |id| (id, rename))) + .map(|x| (&x.path, Symbol::intern(&x.rename))) + .flat_map(|(path, rename)| { + lookup_path_str(tcx, PathNS::Arbitrary, path) + .into_iter() + .map(move |id| (id, rename)) + }) .collect(), } } diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index 270eebe075804..3b271ca0dc147 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node}; +use clippy_utils::sym; use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BorrowKind, Expr, ExprKind, MatchSource, Mutability}; use rustc_lint::{LateContext, LateLintPass}; @@ -42,10 +43,9 @@ impl<'tcx> LateLintPass<'tcx> for DebugAssertWithMutCall { let Some(macro_call) = root_macro_call_first_node(cx, e) else { return; }; - let macro_name = cx.tcx.item_name(macro_call.def_id); if !matches!( - macro_name.as_str(), - "debug_assert" | "debug_assert_eq" | "debug_assert_ne" + cx.tcx.get_diagnostic_name(macro_call.def_id), + Some(sym::debug_assert_macro | sym::debug_assert_eq_macro | sym::debug_assert_ne_macro) ) { return; } @@ -60,7 +60,10 @@ impl<'tcx> LateLintPass<'tcx> for DebugAssertWithMutCall { cx, DEBUG_ASSERT_WITH_MUT_CALL, span, - format!("do not call a function with mutable arguments inside of `{macro_name}!`"), + format!( + "do not call a function with mutable arguments inside of `{}!`", + cx.tcx.item_name(macro_call.def_id) + ), ); } } diff --git a/clippy_lints/src/non_std_lazy_statics.rs b/clippy_lints/src/non_std_lazy_statics.rs index f6bc9428d65f2..f66b9519317be 100644 --- a/clippy_lints/src/non_std_lazy_statics.rs +++ b/clippy_lints/src/non_std_lazy_statics.rs @@ -1,13 +1,14 @@ use clippy_config::Conf; -use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::diagnostics::{span_lint, span_lint_hir_and_then}; use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::paths::{self, PathNS, find_crates, lookup_path_str}; use clippy_utils::visitors::for_each_expr; -use clippy_utils::{def_path_def_ids, fn_def_id, is_no_std_crate, path_def_id}; +use clippy_utils::{fn_def_id, is_no_std_crate, path_def_id, sym}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId}; -use rustc_hir::{self as hir, BodyId, Expr, ExprKind, Item, ItemKind}; +use rustc_hir::{self as hir, BodyId, Expr, ExprKind, HirId, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::Span; @@ -62,10 +63,7 @@ static FUNCTION_REPLACEMENTS: &[(&str, Option<&str>)] = &[ pub struct NonStdLazyStatic { msrv: Msrv, - lazy_static_lazy_static: Vec, - once_cell_crate: Vec, - once_cell_sync_lazy: Vec, - once_cell_sync_lazy_new: Vec, + once_cell_crates: Vec, sugg_map: FxIndexMap>, lazy_type_defs: FxIndexMap, uses_other_once_cell_types: bool, @@ -76,10 +74,7 @@ impl NonStdLazyStatic { pub fn new(conf: &'static Conf) -> Self { Self { msrv: conf.msrv, - lazy_static_lazy_static: Vec::new(), - once_cell_crate: Vec::new(), - once_cell_sync_lazy: Vec::new(), - once_cell_sync_lazy_new: Vec::new(), + once_cell_crates: Vec::new(), sugg_map: FxIndexMap::default(), lazy_type_defs: FxIndexMap::default(), uses_other_once_cell_types: false, @@ -95,17 +90,15 @@ fn can_use_lazy_cell(cx: &LateContext<'_>, msrv: Msrv) -> bool { impl<'hir> LateLintPass<'hir> for NonStdLazyStatic { fn check_crate(&mut self, cx: &LateContext<'hir>) { - // Fetch def_ids for external paths - self.lazy_static_lazy_static = def_path_def_ids(cx.tcx, &["lazy_static", "lazy_static"]).collect(); - self.once_cell_sync_lazy = def_path_def_ids(cx.tcx, &["once_cell", "sync", "Lazy"]).collect(); - self.once_cell_sync_lazy_new = def_path_def_ids(cx.tcx, &["once_cell", "sync", "Lazy", "new"]).collect(); - // And CrateNums for `once_cell` crate - self.once_cell_crate = self.once_cell_sync_lazy.iter().map(|d| d.krate).collect(); + // Add CrateNums for `once_cell` crate + self.once_cell_crates = find_crates(cx.tcx, sym::once_cell) + .iter() + .map(|def_id| def_id.krate) + .collect(); // Convert hardcoded fn replacement list into a map with def_id for (path, sugg) in FUNCTION_REPLACEMENTS { - let path_vec: Vec<&str> = path.split("::").collect(); - for did in def_path_def_ids(cx.tcx, &path_vec) { + for did in lookup_path_str(cx.tcx, PathNS::Value, path) { self.sugg_map.insert(did, sugg.map(ToOwned::to_owned)); } } @@ -114,7 +107,7 @@ impl<'hir> LateLintPass<'hir> for NonStdLazyStatic { fn check_item(&mut self, cx: &LateContext<'hir>, item: &Item<'hir>) { if let ItemKind::Static(..) = item.kind && let Some(macro_call) = clippy_utils::macros::root_macro_call(item.span) - && self.lazy_static_lazy_static.contains(¯o_call.def_id) + && paths::LAZY_STATIC.matches(cx, macro_call.def_id) && can_use_lazy_cell(cx, self.msrv) { span_lint( @@ -130,7 +123,7 @@ impl<'hir> LateLintPass<'hir> for NonStdLazyStatic { return; } - if let Some(lazy_info) = LazyInfo::from_item(self, cx, item) + if let Some(lazy_info) = LazyInfo::from_item(cx, item) && can_use_lazy_cell(cx, self.msrv) { self.lazy_type_defs.insert(item.owner_id.to_def_id(), lazy_info); @@ -155,9 +148,9 @@ impl<'hir> LateLintPass<'hir> for NonStdLazyStatic { if let rustc_hir::TyKind::Path(qpath) = ty.peel_refs().kind && let Some(ty_def_id) = cx.qpath_res(&qpath, ty.hir_id).opt_def_id() // Is from `once_cell` crate - && self.once_cell_crate.contains(&ty_def_id.krate) + && self.once_cell_crates.contains(&ty_def_id.krate) // And is NOT `once_cell::sync::Lazy` - && !self.once_cell_sync_lazy.contains(&ty_def_id) + && !paths::ONCE_CELL_SYNC_LAZY.matches(cx, ty_def_id) { self.uses_other_once_cell_types = true; } @@ -180,6 +173,8 @@ struct LazyInfo { /// // ^^^^ /// ``` ty_span_no_args: Span, + /// Item on which the lint must be generated. + item_hir_id: HirId, /// `Span` and `DefId` of calls on `Lazy` type. /// i.e.: /// ```ignore @@ -190,12 +185,12 @@ struct LazyInfo { } impl LazyInfo { - fn from_item(state: &NonStdLazyStatic, cx: &LateContext<'_>, item: &Item<'_>) -> Option { + fn from_item(cx: &LateContext<'_>, item: &Item<'_>) -> Option { // Check if item is a `once_cell:sync::Lazy` static. if let ItemKind::Static(_, ty, _, body_id) = item.kind && let Some(path_def_id) = path_def_id(cx, ty) && let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind - && state.once_cell_sync_lazy.contains(&path_def_id) + && paths::ONCE_CELL_SYNC_LAZY.matches(cx, path_def_id) { let ty_span_no_args = path_span_without_args(path); let body = cx.tcx.hir_body(body_id); @@ -204,7 +199,7 @@ impl LazyInfo { let mut new_fn_calls = FxIndexMap::default(); for_each_expr::<(), ()>(cx, body, |ex| { if let Some((fn_did, call_span)) = fn_def_id_and_span_from_body(cx, ex, body_id) - && state.once_cell_sync_lazy_new.contains(&fn_did) + && paths::ONCE_CELL_SYNC_LAZY_NEW.matches(cx, fn_did) { new_fn_calls.insert(call_span, fn_did); } @@ -213,6 +208,7 @@ impl LazyInfo { Some(LazyInfo { ty_span_no_args, + item_hir_id: item.hir_id(), calls_span_and_id: new_fn_calls, }) } else { @@ -236,9 +232,10 @@ impl LazyInfo { } } - span_lint_and_then( + span_lint_hir_and_then( cx, NON_STD_LAZY_STATICS, + self.item_hir_id, self.ty_span_no_args, "this type has been superseded by `LazyLock` in the standard library", |diag| { diff --git a/clippy_lints/src/operators/eq_op.rs b/clippy_lints/src/operators/eq_op.rs index 1421893274f5a..d79101a687df4 100644 --- a/clippy_lints/src/operators/eq_op.rs +++ b/clippy_lints/src/operators/eq_op.rs @@ -1,20 +1,18 @@ use clippy_utils::ast_utils::is_useless_with_eq_exprs; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace}; -use clippy_utils::{eq_expr_value, is_in_test_function}; +use clippy_utils::{eq_expr_value, is_in_test_function, sym}; use rustc_hir::{BinOpKind, Expr}; use rustc_lint::LateContext; use super::EQ_OP; pub(crate) fn check_assert<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let Some((macro_call, macro_name)) = first_node_macro_backtrace(cx, e).find_map(|macro_call| { - let name = cx.tcx.item_name(macro_call.def_id); + if let Some(macro_call) = first_node_macro_backtrace(cx, e).find(|macro_call| { matches!( - name.as_str(), - "assert_eq" | "assert_ne" | "debug_assert_eq" | "debug_assert_ne" + cx.tcx.get_diagnostic_name(macro_call.def_id), + Some(sym::assert_eq_macro | sym::assert_ne_macro | sym::debug_assert_eq_macro | sym::debug_assert_ne_macro) ) - .then(|| (macro_call, name)) }) && let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn) && eq_expr_value(cx, lhs, rhs) && macro_call.is_local() @@ -24,7 +22,10 @@ pub(crate) fn check_assert<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { cx, EQ_OP, lhs.span.to(rhs.span), - format!("identical args used in this `{macro_name}!` macro call"), + format!( + "identical args used in this `{}!` macro call", + cx.tcx.item_name(macro_call.def_id) + ), ); } } diff --git a/clippy_lints/src/operators/integer_division.rs b/clippy_lints/src/operators/integer_division.rs index 76eba7327cff6..7b98afa9b40bd 100644 --- a/clippy_lints/src/operators/integer_division.rs +++ b/clippy_lints/src/operators/integer_division.rs @@ -1,6 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::symbol::sym; use super::INTEGER_DIVISION; @@ -13,7 +15,8 @@ pub(crate) fn check<'tcx>( ) { if op == hir::BinOpKind::Div && cx.typeck_results().expr_ty(left).is_integral() - && cx.typeck_results().expr_ty(right).is_integral() + && let right_ty = cx.typeck_results().expr_ty(right) + && (right_ty.is_integral() || is_type_diagnostic_item(cx, right_ty, sym::NonZero)) { #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] span_lint_and_then(cx, INTEGER_DIVISION, expr.span, "integer division", |diag| { diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index eebc62e2a5a96..ee1d59490ce9f 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::macros::root_macro_call_first_node; +use clippy_utils::macros::{is_panic, root_macro_call_first_node}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::{Descend, for_each_expr}; use clippy_utils::{is_inside_always_const_context, return_ty}; @@ -69,10 +69,11 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir return ControlFlow::Continue(Descend::Yes); }; if !is_inside_always_const_context(cx.tcx, e.hir_id) - && matches!( - cx.tcx.item_name(macro_call.def_id).as_str(), - "panic" | "assert" | "assert_eq" | "assert_ne" - ) + && (is_panic(cx, macro_call.def_id) + || matches!( + cx.tcx.get_diagnostic_name(macro_call.def_id), + Some(sym::assert_macro | sym::assert_eq_macro | sym::assert_ne_macro) + )) { panics.push(macro_call.span); ControlFlow::Continue(Descend::No) diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index 39ae9967e0166..8962f36db1e69 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -113,8 +113,8 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { ); return; } - match cx.tcx.item_name(macro_call.def_id).as_str() { - "todo" => { + match cx.tcx.get_diagnostic_name(macro_call.def_id) { + Some(sym::todo_macro) => { span_lint( cx, TODO, @@ -122,7 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { "`todo` should not be present in production code", ); }, - "unimplemented" => { + Some(sym::unimplemented_macro) => { span_lint( cx, UNIMPLEMENTED, @@ -130,7 +130,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { "`unimplemented` should not be present in production code", ); }, - "unreachable" => { + Some(sym::unreachable_macro) => { span_lint(cx, UNREACHABLE, macro_call.span, "usage of the `unreachable!` macro"); }, _ => {}, diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 834ff2af0e883..89d945161f629 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -2,8 +2,9 @@ use std::fmt::Display; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; +use clippy_utils::paths::PathLookup; use clippy_utils::source::SpanRangeExt; -use clippy_utils::{def_path_res_with_base, find_crates, path_def_id, paths, sym}; +use clippy_utils::{path_def_id, paths}; use rustc_ast::ast::{LitKind, StrStyle}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{BorrowKind, Expr, ExprKind, OwnerId}; @@ -121,17 +122,9 @@ impl_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX, REGEX_CREATION_IN_LOOPS] impl<'tcx> LateLintPass<'tcx> for Regex { fn check_crate(&mut self, cx: &LateContext<'tcx>) { - // We don't use `match_def_path` here because that relies on matching the exact path, which changed - // between regex 1.8 and 1.9 - // - // `def_path_res_with_base` will resolve through re-exports but is relatively heavy, so we only - // perform the operation once and store the results - let regex_crates = find_crates(cx.tcx, sym::regex); - let mut resolve = |path: &[&str], kind: RegexKind| { - for res in def_path_res_with_base(cx.tcx, regex_crates.clone(), &path[1..]) { - if let Some(id) = res.opt_def_id() { - self.definitions.insert(id, kind); - } + let mut resolve = |path: &PathLookup, kind: RegexKind| { + for &id in path.get(cx) { + self.definitions.insert(id, kind); } }; diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index d8e8ead291288..122d97fdf8193 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -5,7 +5,7 @@ use clippy_utils::visitors::for_each_expr; use clippy_utils::{ binary_expr_needs_parentheses, fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, leaks_droppable_temporary_with_limited_lifetime, path_res, path_to_local_id, span_contains_cfg, - span_find_starting_semi, + span_find_starting_semi, sym, }; use core::ops::ControlFlow; use rustc_ast::MetaItemInner; @@ -22,7 +22,7 @@ use rustc_middle::ty::{self, GenericArgKind, Ty}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::edition::Edition; -use rustc_span::{BytePos, Pos, Span, sym}; +use rustc_span::{BytePos, Pos, Span}; use std::borrow::Cow; use std::fmt::Display; @@ -411,8 +411,8 @@ fn check_final_expr<'tcx>( && let [tool, lint_name] = meta_item.path.segments.as_slice() && tool.ident.name == sym::clippy && matches!( - lint_name.ident.name.as_str(), - "needless_return" | "style" | "all" | "warnings" + lint_name.ident.name, + sym::needless_return | sym::style | sym::all | sym::warnings ) { // This is an expectation of the `needless_return` lint diff --git a/clippy_lints/src/serde_api.rs b/clippy_lints/src/serde_api.rs index a8c6518b592ba..a64b9b223786b 100644 --- a/clippy_lints/src/serde_api.rs +++ b/clippy_lints/src/serde_api.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::{get_trait_def_id, paths}; +use clippy_utils::paths; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -32,9 +32,7 @@ impl<'tcx> LateLintPass<'tcx> for SerdeApi { }) = item.kind { let did = trait_ref.path.res.def_id(); - if let Some(visit_did) = get_trait_def_id(cx.tcx, &paths::SERDE_DE_VISITOR) - && did == visit_did - { + if paths::SERDE_DE_VISITOR.matches(cx, did) { let mut seen_str = None; let mut seen_string = None; for item in *items { diff --git a/clippy_lints/src/single_option_map.rs b/clippy_lints/src/single_option_map.rs index 1fb54950612a5..cc497c97a4725 100644 --- a/clippy_lints/src/single_option_map.rs +++ b/clippy_lints/src/single_option_map.rs @@ -30,7 +30,7 @@ declare_clippy_lint! { /// param * 2 /// } /// ``` - #[clippy::version = "1.86.0"] + #[clippy::version = "1.87.0"] pub SINGLE_OPTION_MAP, nursery, "Checks for functions with method calls to `.map(_)` on an arg of type `Option` as the outermost expression." diff --git a/clippy_lints/src/single_range_in_vec_init.rs b/clippy_lints/src/single_range_in_vec_init.rs index 2d989b1cf0ba0..54d09ff9ee402 100644 --- a/clippy_lints/src/single_range_in_vec_init.rs +++ b/clippy_lints/src/single_range_in_vec_init.rs @@ -3,7 +3,7 @@ use clippy_utils::higher::VecArgs; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::implements_trait; -use clippy_utils::{get_trait_def_id, is_no_std_crate}; +use clippy_utils::{is_no_std_crate, paths}; use rustc_ast::{LitIntType, LitKind, UintTy}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, QPath, StructTailExpr}; @@ -100,7 +100,7 @@ impl LateLintPass<'_> for SingleRangeInVecInit { && let Some(start_snippet) = start.span.get_source_text(cx) && let Some(end_snippet) = end.span.get_source_text(cx) { - let should_emit_every_value = if let Some(step_def_id) = get_trait_def_id(cx.tcx, &["core", "iter", "Step"]) + let should_emit_every_value = if let Some(step_def_id) = paths::ITER_STEP.only(cx) && implements_trait(cx, ty, step_def_id, &[]) { true diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index af4d0d541f176..73a9fe71e0018 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -334,7 +334,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { if let ExprKind::MethodCall(path, recv, [], _) = &e.kind && path.ident.name == sym::into_bytes && let ExprKind::MethodCall(path, recv, [], _) = &recv.kind - && matches!(path.ident.name.as_str(), "to_owned" | "to_string") + && matches!(path.ident.name, sym::to_owned | sym::to_string) && let ExprKind::Lit(lit) = &recv.kind && let LitKind::Str(lit_content, _) = &lit.node && lit_content.as_str().is_ascii() diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs index bb969bc802fe5..7d7d74f27b3c2 100644 --- a/clippy_lints/src/to_digit_is_some.rs +++ b/clippy_lints/src/to_digit_is_some.rs @@ -1,11 +1,12 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{match_def_path, sym}; +use clippy_utils::{is_in_const_context, paths, sym}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does @@ -33,34 +34,35 @@ declare_clippy_lint! { "`char.is_digit()` is clearer" } -declare_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]); +impl_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]); + +pub(crate) struct ToDigitIsSome { + msrv: Msrv, +} + +impl ToDigitIsSome { + pub(crate) fn new(conf: &'static Conf) -> Self { + Self { msrv: conf.msrv } + } +} impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { if let hir::ExprKind::MethodCall(is_some_path, to_digit_expr, [], _) = &expr.kind && is_some_path.ident.name == sym::is_some { - let match_result = match &to_digit_expr.kind { + let match_result = match to_digit_expr.kind { hir::ExprKind::MethodCall(to_digits_path, char_arg, [radix_arg], _) => { if to_digits_path.ident.name == sym::to_digit - && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(char_arg) - && *char_arg_ty.kind() == ty::Char + && cx.typeck_results().expr_ty_adjusted(char_arg).is_char() { - Some((true, *char_arg, radix_arg)) + Some((true, char_arg, radix_arg)) } else { None } }, hir::ExprKind::Call(to_digits_call, [char_arg, radix_arg]) => { - if let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind - && let to_digits_call_res = cx.qpath_res(to_digits_path, to_digits_call.hir_id) - && let Some(to_digits_def_id) = to_digits_call_res.opt_def_id() - && match_def_path( - cx, - to_digits_def_id, - &["core", "char", "methods", "", "to_digit"], - ) - { + if paths::CHAR_TO_DIGIT.matches_path(cx, to_digits_call) { Some((false, char_arg, radix_arg)) } else { None @@ -69,7 +71,9 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome { _ => None, }; - if let Some((is_method_call, char_arg, radix_arg)) = match_result { + if let Some((is_method_call, char_arg, radix_arg)) = match_result + && (!is_in_const_context(cx) || self.msrv.meets(cx, msrvs::CONST_CHAR_IS_DIGIT)) + { let mut applicability = Applicability::MachineApplicable; let char_arg_snip = snippet_with_applicability(cx, char_arg.span, "_", &mut applicability); let radix_snip = snippet_with_applicability(cx, radix_arg.span, "_", &mut applicability); diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 8aac3a5910294..45e54302e32c9 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -15,7 +15,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::{BytePos, Span}; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -282,18 +282,18 @@ impl TraitBounds { .iter() .copied() .chain(p.bounds.iter()) - .filter_map(get_trait_info_from_bound) - .map(|(_, _, span)| snippet_with_applicability(cx, span, "..", &mut applicability)) + .map(|bound| snippet_with_applicability(cx, bound.span(), "_", &mut applicability)) .join(" + "); let hint_string = format!( "consider combining the bounds: `{}: {trait_bounds}`", snippet(cx, p.bounded_ty.span, "_"), ); + let ty_name = snippet(cx, p.bounded_ty.span, "_"); span_lint_and_help( cx, TYPE_REPETITION_IN_BOUNDS, bound.span, - "this type has already been used as a bound predicate", + format!("type `{ty_name}` has already been used as a bound predicate"), None, hint_string, ); @@ -395,15 +395,7 @@ impl Hash for ComparableTraitRef<'_, '_> { fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &'a [PathSegment<'a>], Span)> { if let GenericBound::Trait(t) = bound { let trait_path = t.trait_ref.path; - let trait_span = { - let path_span = trait_path.span; - if let BoundPolarity::Maybe(_) = t.modifiers.polarity { - path_span.with_lo(path_span.lo() - BytePos(1)) // include the `?` - } else { - path_span - } - }; - Some((trait_path.res, trait_path.segments, trait_span)) + Some((trait_path.res, trait_path.segments, t.span)) } else { None } diff --git a/clippy_lints/src/transmute/eager_transmute.rs b/clippy_lints/src/transmute/eager_transmute.rs index 1ccab62708b18..535c044f49e68 100644 --- a/clippy_lints/src/transmute/eager_transmute.rs +++ b/clippy_lints/src/transmute/eager_transmute.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::ty::is_normalizable; use clippy_utils::{eq_expr_value, path_to_local, sym}; use rustc_abi::WrappingRange; use rustc_errors::Applicability; @@ -84,8 +83,6 @@ pub(super) fn check<'tcx>( && path.ident.name == sym::then_some && is_local_with_projections(transmutable) && binops_with_local(cx, transmutable, receiver) - && is_normalizable(cx, cx.param_env, from_ty) - && is_normalizable(cx, cx.param_env, to_ty) // we only want to lint if the target type has a niche that is larger than the one of the source type // e.g. `u8` to `NonZero` should lint, but `NonZero` to `u8` should not && let Ok(from_layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(from_ty)) diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index f2da8d35cb4fc..d5112e2c3f97a 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -1,13 +1,9 @@ mod crosspointer_transmute; mod eager_transmute; mod missing_transmute_annotations; -mod transmute_float_to_int; mod transmute_int_to_bool; -mod transmute_int_to_char; -mod transmute_int_to_float; mod transmute_int_to_non_zero; mod transmute_null_to_fn; -mod transmute_num_to_bytes; mod transmute_ptr_to_ptr; mod transmute_ptr_to_ref; mod transmute_ref_to_ref; @@ -141,40 +137,6 @@ declare_clippy_lint! { "transmutes from a pointer to a reference type" } -declare_clippy_lint! { - /// ### What it does - /// Checks for transmutes from an integer to a `char`. - /// - /// ### Why is this bad? - /// Not every integer is a Unicode scalar value. - /// - /// ### Known problems - /// - [`from_u32`] which this lint suggests using is slower than `transmute` - /// as it needs to validate the input. - /// If you are certain that the input is always a valid Unicode scalar value, - /// use [`from_u32_unchecked`] which is as fast as `transmute` - /// but has a semantically meaningful name. - /// - You might want to handle `None` returned from [`from_u32`] instead of calling `unwrap`. - /// - /// [`from_u32`]: https://doc.rust-lang.org/std/char/fn.from_u32.html - /// [`from_u32_unchecked`]: https://doc.rust-lang.org/std/char/fn.from_u32_unchecked.html - /// - /// ### Example - /// ```no_run - /// let x = 1_u32; - /// unsafe { - /// let _: char = std::mem::transmute(x); // where x: u32 - /// } - /// - /// // should be: - /// let _ = std::char::from_u32(x).unwrap(); - /// ``` - #[clippy::version = "pre 1.29.0"] - pub TRANSMUTE_INT_TO_CHAR, - complexity, - "transmutes from an integer to a `char`" -} - declare_clippy_lint! { /// ### What it does /// Checks for transmutes from a `&[u8]` to a `&str`. @@ -232,29 +194,6 @@ declare_clippy_lint! { "transmutes from an integer to a `bool`" } -declare_clippy_lint! { - /// ### What it does - /// Checks for transmutes from an integer to a float. - /// - /// ### Why is this bad? - /// Transmutes are dangerous and error-prone, whereas `from_bits` is intuitive - /// and safe. - /// - /// ### Example - /// ```no_run - /// unsafe { - /// let _: f32 = std::mem::transmute(1_u32); // where x: u32 - /// } - /// - /// // should be: - /// let _: f32 = f32::from_bits(1_u32); - /// ``` - #[clippy::version = "pre 1.29.0"] - pub TRANSMUTE_INT_TO_FLOAT, - complexity, - "transmutes from an integer to a float" -} - declare_clippy_lint! { /// ### What it does /// Checks for transmutes from `T` to `NonZero`, and suggests the `new_unchecked` @@ -280,52 +219,6 @@ declare_clippy_lint! { "transmutes from an integer to a non-zero wrapper" } -declare_clippy_lint! { - /// ### What it does - /// Checks for transmutes from a float to an integer. - /// - /// ### Why is this bad? - /// Transmutes are dangerous and error-prone, whereas `to_bits` is intuitive - /// and safe. - /// - /// ### Example - /// ```no_run - /// unsafe { - /// let _: u32 = std::mem::transmute(1f32); - /// } - /// - /// // should be: - /// let _: u32 = 1f32.to_bits(); - /// ``` - #[clippy::version = "1.41.0"] - pub TRANSMUTE_FLOAT_TO_INT, - complexity, - "transmutes from a float to an integer" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for transmutes from a number to an array of `u8` - /// - /// ### Why this is bad? - /// Transmutes are dangerous and error-prone, whereas `to_ne_bytes` - /// is intuitive and safe. - /// - /// ### Example - /// ```no_run - /// unsafe { - /// let x: [u8; 8] = std::mem::transmute(1i64); - /// } - /// - /// // should be - /// let x: [u8; 8] = 0i64.to_ne_bytes(); - /// ``` - #[clippy::version = "1.58.0"] - pub TRANSMUTE_NUM_TO_BYTES, - complexity, - "transmutes from a number to an array of `u8`" -} - declare_clippy_lint! { /// ### What it does /// Checks for transmutes from a pointer to a pointer, or @@ -581,13 +474,9 @@ impl_lint_pass!(Transmute => [ TRANSMUTE_PTR_TO_PTR, USELESS_TRANSMUTE, WRONG_TRANSMUTE, - TRANSMUTE_INT_TO_CHAR, TRANSMUTE_BYTES_TO_STR, TRANSMUTE_INT_TO_BOOL, - TRANSMUTE_INT_TO_FLOAT, TRANSMUTE_INT_TO_NON_ZERO, - TRANSMUTE_FLOAT_TO_INT, - TRANSMUTE_NUM_TO_BYTES, UNSOUND_COLLECTION_TRANSMUTE, TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, TRANSMUTE_UNDEFINED_REPR, @@ -632,14 +521,10 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { | transmute_null_to_fn::check(cx, e, arg, to_ty) | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, self.msrv) | missing_transmute_annotations::check(cx, path, from_ty, to_ty, e.hir_id) - | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context) | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context) | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg, self.msrv) | transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg) - | transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context, self.msrv) | transmute_int_to_non_zero::check(cx, e, from_ty, to_ty, arg) - | transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context, self.msrv) - | transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context, self.msrv) | (unsound_collection_transmute::check(cx, e, from_ty, to_ty) || transmute_undefined_repr::check(cx, e, from_ty, to_ty)) | (eager_transmute::check(cx, e, arg, from_ty, to_ty)); diff --git a/clippy_lints/src/transmute/transmute_float_to_int.rs b/clippy_lints/src/transmute/transmute_float_to_int.rs deleted file mode 100644 index df2f681a16291..0000000000000 --- a/clippy_lints/src/transmute/transmute_float_to_int.rs +++ /dev/null @@ -1,66 +0,0 @@ -use super::TRANSMUTE_FLOAT_TO_INT; -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::sugg; -use rustc_ast as ast; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, UnOp}; -use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty}; - -/// Checks for `transmute_float_to_int` lint. -/// Returns `true` if it's triggered, otherwise returns `false`. -pub(super) fn check<'tcx>( - cx: &LateContext<'tcx>, - e: &'tcx Expr<'_>, - from_ty: Ty<'tcx>, - to_ty: Ty<'tcx>, - mut arg: &'tcx Expr<'_>, - const_context: bool, - msrv: Msrv, -) -> bool { - match (&from_ty.kind(), &to_ty.kind()) { - (ty::Float(float_ty), ty::Int(_) | ty::Uint(_)) - if !const_context || msrv.meets(cx, msrvs::CONST_FLOAT_BITS_CONV) => - { - span_lint_and_then( - cx, - TRANSMUTE_FLOAT_TO_INT, - e.span, - format!("transmute from a `{from_ty}` to a `{to_ty}`"), - |diag| { - let mut sugg = sugg::Sugg::hir(cx, arg, ".."); - - if let ExprKind::Unary(UnOp::Neg, inner_expr) = &arg.kind { - arg = inner_expr; - } - - if let ExprKind::Lit(lit) = &arg.kind - // if the expression is a float literal and it is unsuffixed then - // add a suffix so the suggestion is valid and unambiguous - && let ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) = lit.node - { - let op = format!("{sugg}{}", float_ty.name_str()).into(); - match sugg { - sugg::Sugg::MaybeParen(_) => sugg = sugg::Sugg::MaybeParen(op), - _ => sugg = sugg::Sugg::NonParen(op), - } - } - - sugg = sugg::Sugg::NonParen(format!("{}.to_bits()", sugg.maybe_paren()).into()); - - // cast the result of `to_bits` if `to_ty` is signed - sugg = if let ty::Int(int_ty) = to_ty.kind() { - sugg.as_ty(int_ty.name_str().to_string()) - } else { - sugg - }; - - diag.span_suggestion(e.span, "consider using", sugg, Applicability::Unspecified); - }, - ); - true - }, - _ => false, - } -} diff --git a/clippy_lints/src/transmute/transmute_int_to_char.rs b/clippy_lints/src/transmute/transmute_int_to_char.rs deleted file mode 100644 index 81d10a7d5bde4..0000000000000 --- a/clippy_lints/src/transmute/transmute_int_to_char.rs +++ /dev/null @@ -1,47 +0,0 @@ -use super::TRANSMUTE_INT_TO_CHAR; -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{std_or_core, sugg}; -use rustc_ast as ast; -use rustc_errors::Applicability; -use rustc_hir::Expr; -use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty}; - -/// Checks for `transmute_int_to_char` lint. -/// Returns `true` if it's triggered, otherwise returns `false`. -pub(super) fn check<'tcx>( - cx: &LateContext<'tcx>, - e: &'tcx Expr<'_>, - from_ty: Ty<'tcx>, - to_ty: Ty<'tcx>, - arg: &'tcx Expr<'_>, - const_context: bool, -) -> bool { - match (&from_ty.kind(), &to_ty.kind()) { - (ty::Int(ty::IntTy::I32) | ty::Uint(ty::UintTy::U32), &ty::Char) if !const_context => { - span_lint_and_then( - cx, - TRANSMUTE_INT_TO_CHAR, - e.span, - format!("transmute from a `{from_ty}` to a `char`"), - |diag| { - let Some(top_crate) = std_or_core(cx) else { return }; - let arg = sugg::Sugg::hir(cx, arg, ".."); - let arg = if let ty::Int(_) = from_ty.kind() { - arg.as_ty(ast::UintTy::U32.name_str()) - } else { - arg - }; - diag.span_suggestion( - e.span, - "consider using", - format!("{top_crate}::char::from_u32({arg}).unwrap()"), - Applicability::Unspecified, - ); - }, - ); - true - }, - _ => false, - } -} diff --git a/clippy_lints/src/transmute/transmute_int_to_float.rs b/clippy_lints/src/transmute/transmute_int_to_float.rs deleted file mode 100644 index aaa95396b4b4b..0000000000000 --- a/clippy_lints/src/transmute/transmute_int_to_float.rs +++ /dev/null @@ -1,50 +0,0 @@ -use super::TRANSMUTE_INT_TO_FLOAT; -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::sugg; -use rustc_errors::Applicability; -use rustc_hir::Expr; -use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty}; - -/// Checks for `transmute_int_to_float` lint. -/// Returns `true` if it's triggered, otherwise returns `false`. -pub(super) fn check<'tcx>( - cx: &LateContext<'tcx>, - e: &'tcx Expr<'_>, - from_ty: Ty<'tcx>, - to_ty: Ty<'tcx>, - arg: &'tcx Expr<'_>, - const_context: bool, - msrv: Msrv, -) -> bool { - match (&from_ty.kind(), &to_ty.kind()) { - (ty::Int(_) | ty::Uint(_), ty::Float(_)) if !const_context || msrv.meets(cx, msrvs::CONST_FLOAT_BITS_CONV) => { - span_lint_and_then( - cx, - TRANSMUTE_INT_TO_FLOAT, - e.span, - format!("transmute from a `{from_ty}` to a `{to_ty}`"), - |diag| { - let arg = sugg::Sugg::hir(cx, arg, ".."); - let arg = if let ty::Int(int_ty) = from_ty.kind() { - arg.as_ty(format!( - "u{}", - int_ty.bit_width().map_or_else(|| "size".to_string(), |v| v.to_string()) - )) - } else { - arg - }; - diag.span_suggestion( - e.span, - "consider using", - format!("{to_ty}::from_bits({arg})"), - Applicability::Unspecified, - ); - }, - ); - true - }, - _ => false, - } -} diff --git a/clippy_lints/src/transmute/transmute_num_to_bytes.rs b/clippy_lints/src/transmute/transmute_num_to_bytes.rs deleted file mode 100644 index d72be270b731f..0000000000000 --- a/clippy_lints/src/transmute/transmute_num_to_bytes.rs +++ /dev/null @@ -1,50 +0,0 @@ -use super::TRANSMUTE_NUM_TO_BYTES; -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::sugg; -use rustc_errors::Applicability; -use rustc_hir::Expr; -use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty, UintTy}; - -/// Checks for `transmute_int_to_float` lint. -/// Returns `true` if it's triggered, otherwise returns `false`. -pub(super) fn check<'tcx>( - cx: &LateContext<'tcx>, - e: &'tcx Expr<'_>, - from_ty: Ty<'tcx>, - to_ty: Ty<'tcx>, - arg: &'tcx Expr<'_>, - const_context: bool, - msrv: Msrv, -) -> bool { - match (&from_ty.kind(), &to_ty.kind()) { - (ty::Int(_) | ty::Uint(_) | ty::Float(_), ty::Array(arr_ty, _)) => { - if !matches!(arr_ty.kind(), ty::Uint(UintTy::U8)) { - return false; - } - if matches!(from_ty.kind(), ty::Float(_)) && const_context && !msrv.meets(cx, msrvs::CONST_FLOAT_BITS_CONV) - { - return false; - } - - span_lint_and_then( - cx, - TRANSMUTE_NUM_TO_BYTES, - e.span, - format!("transmute from a `{from_ty}` to a `{to_ty}`"), - |diag| { - let arg = sugg::Sugg::hir(cx, arg, ".."); - diag.span_suggestion( - e.span, - "consider using `to_ne_bytes()`", - format!("{arg}.to_ne_bytes()"), - Applicability::Unspecified, - ); - }, - ); - true - }, - _ => false, - } -} diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 3147058b4cda0..c1c7cc5165652 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -385,7 +385,7 @@ declare_clippy_lint! { /// ```no_run /// let right: std::borrow::Cow<'_, [u8]>; /// ``` - #[clippy::version = "1.85.0"] + #[clippy::version = "1.87.0"] pub OWNED_COW, style, "needlessly owned Cow type" diff --git a/clippy_lints/src/unit_types/unit_cmp.rs b/clippy_lints/src/unit_types/unit_cmp.rs index 6dcc1195a7051..48b532968cb57 100644 --- a/clippy_lints/src/unit_types/unit_cmp.rs +++ b/clippy_lints/src/unit_types/unit_cmp.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node}; +use clippy_utils::sym; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; @@ -7,11 +8,12 @@ use super::UNIT_CMP; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { if expr.span.from_expansion() { - if let Some(macro_call) = root_macro_call_first_node(cx, expr) { - let macro_name = cx.tcx.item_name(macro_call.def_id); - let result = match macro_name.as_str() { - "assert_eq" | "debug_assert_eq" => "succeed", - "assert_ne" | "debug_assert_ne" => "fail", + if let Some(macro_call) = root_macro_call_first_node(cx, expr) + && let Some(diag_name) = cx.tcx.get_diagnostic_name(macro_call.def_id) + { + let result = match diag_name { + sym::assert_eq_macro | sym::debug_assert_eq_macro => "succeed", + sym::assert_ne_macro | sym::debug_assert_ne_macro => "fail", _ => return, }; let Some((left, _, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else { @@ -24,7 +26,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { cx, UNIT_CMP, macro_call.span, - format!("`{macro_name}` of unit values detected. This will always {result}"), + format!( + "`{}` of unit values detected. This will always {result}", + cx.tcx.item_name(macro_call.def_id) + ), ); } return; diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs index 1c1c841e96412..8ceaa3dc58ec0 100644 --- a/clippy_lints/src/unused_async.rs +++ b/clippy_lints/src/unused_async.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::is_def_id_trait_method; use rustc_hir::def::DefKind; use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn}; -use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, Node, YieldSource}; +use rustc_hir::{Body, Defaultness, Expr, ExprKind, FnDecl, HirId, Node, TraitItem, YieldSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_session::impl_lint_pass; @@ -116,7 +116,11 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync { span: Span, def_id: LocalDefId, ) { - if !span.from_expansion() && fn_kind.asyncness().is_async() && !is_def_id_trait_method(cx, def_id) { + if !span.from_expansion() + && fn_kind.asyncness().is_async() + && !is_def_id_trait_method(cx, def_id) + && !is_default_trait_impl(cx, def_id) + { let mut visitor = AsyncFnVisitor { cx, found_await: false, @@ -189,3 +193,13 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync { } } } + +fn is_default_trait_impl(cx: &LateContext<'_>, def_id: LocalDefId) -> bool { + matches!( + cx.tcx.hir_node_by_def_id(def_id), + Node::TraitItem(TraitItem { + defaultness: Defaultness::Default { .. }, + .. + }) + ) +} diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index 2d88c490b1abe..5e1cb9e54f57a 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::macros::{is_panic, root_macro_call_first_node}; -use clippy_utils::{is_res_lang_ctor, is_trait_method, match_def_path, match_trait_method, paths, peel_blocks}; +use clippy_utils::{is_res_lang_ctor, paths, peel_blocks}; use hir::{ExprKind, HirId, PatKind}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; @@ -93,14 +93,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount { return; } - let async_paths: [&[&str]; 4] = [ + let async_paths = [ &paths::TOKIO_IO_ASYNCREADEXT, &paths::TOKIO_IO_ASYNCWRITEEXT, &paths::FUTURES_IO_ASYNCREADEXT, &paths::FUTURES_IO_ASYNCWRITEEXT, ]; - if async_paths.into_iter().any(|path| match_def_path(cx, trait_id, path)) { + if async_paths.into_iter().any(|path| path.matches(cx, trait_id)) { return; } } @@ -226,7 +226,7 @@ fn is_unreachable_or_panic(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { if is_panic(cx, macro_call.def_id) { return !cx.tcx.hir_is_inside_const_context(expr.hir_id); } - matches!(cx.tcx.item_name(macro_call.def_id).as_str(), "unreachable") + cx.tcx.is_diagnostic_item(sym::unreachable_macro, macro_call.def_id) } fn unpack_call_chain<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { @@ -291,19 +291,28 @@ fn check_io_mode(cx: &LateContext<'_>, call: &hir::Expr<'_>) -> Option { }, }; - match ( - is_trait_method(cx, call, sym::IoRead), - is_trait_method(cx, call, sym::IoWrite), - match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCREADEXT) - || match_trait_method(cx, call, &paths::TOKIO_IO_ASYNCREADEXT), - match_trait_method(cx, call, &paths::TOKIO_IO_ASYNCWRITEEXT) - || match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCWRITEEXT), - ) { - (true, _, _, _) => Some(IoOp::SyncRead(vectorized)), - (_, true, _, _) => Some(IoOp::SyncWrite(vectorized)), - (_, _, true, _) => Some(IoOp::AsyncRead(vectorized)), - (_, _, _, true) => Some(IoOp::AsyncWrite(vectorized)), - _ => None, + if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(call.hir_id) + && let Some(trait_def_id) = cx.tcx.trait_of_item(method_def_id) + { + if let Some(diag_name) = cx.tcx.get_diagnostic_name(trait_def_id) { + match diag_name { + sym::IoRead => Some(IoOp::SyncRead(vectorized)), + sym::IoWrite => Some(IoOp::SyncWrite(vectorized)), + _ => None, + } + } else if paths::FUTURES_IO_ASYNCREADEXT.matches(cx, trait_def_id) + || paths::TOKIO_IO_ASYNCREADEXT.matches(cx, trait_def_id) + { + Some(IoOp::AsyncRead(vectorized)) + } else if paths::TOKIO_IO_ASYNCWRITEEXT.matches(cx, trait_def_id) + || paths::FUTURES_IO_ASYNCWRITEEXT.matches(cx, trait_def_id) + { + Some(IoOp::AsyncWrite(vectorized)) + } else { + None + } + } else { + None } } diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index ba140788bb54e..c641d4e55b940 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -4,15 +4,15 @@ use clippy_utils::usage::is_potentially_local_place; use clippy_utils::{higher, path_to_local, sym}; use rustc_errors::Applicability; use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn}; -use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Node, PathSegment, UnOp}; +use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Node, UnOp}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceWithHirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::declare_lint_pass; -use rustc_span::Span; use rustc_span::def_id::LocalDefId; +use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -111,7 +111,7 @@ struct UnwrapInfo<'tcx> { /// The check, like `x.is_ok()` check: &'tcx Expr<'tcx>, /// The check's name, like `is_ok` - check_name: &'tcx PathSegment<'tcx>, + check_name: Symbol, /// The branch where the check takes place, like `if x.is_ok() { .. }` branch: &'tcx Expr<'tcx>, /// Whether `is_some()` or `is_ok()` was called (as opposed to `is_err()` or `is_none()`). @@ -133,12 +133,12 @@ fn collect_unwrap_info<'tcx>( invert: bool, is_entire_condition: bool, ) -> Vec> { - fn is_relevant_option_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: &str) -> bool { - is_type_diagnostic_item(cx, ty, sym::Option) && ["is_some", "is_none"].contains(&method_name) + fn is_relevant_option_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool { + is_type_diagnostic_item(cx, ty, sym::Option) && matches!(method_name, sym::is_none | sym::is_some) } - fn is_relevant_result_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: &str) -> bool { - is_type_diagnostic_item(cx, ty, sym::Result) && ["is_ok", "is_err"].contains(&method_name) + fn is_relevant_result_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool { + is_type_diagnostic_item(cx, ty, sym::Result) && matches!(method_name, sym::is_err | sym::is_ok) } if let ExprKind::Binary(op, left, right) = &expr.kind { @@ -155,14 +155,10 @@ fn collect_unwrap_info<'tcx>( } else if let ExprKind::MethodCall(method_name, receiver, [], _) = &expr.kind && let Some(local_id) = path_to_local(receiver) && let ty = cx.typeck_results().expr_ty(receiver) - && let name = method_name.ident.as_str() + && let name = method_name.ident.name && (is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name)) { - let unwrappable = match name { - "is_some" | "is_ok" => true, - "is_err" | "is_none" => false, - _ => unreachable!(), - }; + let unwrappable = matches!(name, sym::is_some | sym::is_ok); let safe_to_unwrap = unwrappable != invert; let kind = if is_type_diagnostic_item(cx, ty, sym::Option) { UnwrappableKind::Option @@ -174,7 +170,7 @@ fn collect_unwrap_info<'tcx>( local_id, if_expr, check: expr, - check_name: method_name, + check_name: name, branch, safe_to_unwrap, kind, @@ -184,12 +180,12 @@ fn collect_unwrap_info<'tcx>( Vec::new() } -/// A HIR visitor delegate that checks if a local variable of type `Option<_>` is mutated, -/// *except* for if `Option::as_mut` is called. +/// A HIR visitor delegate that checks if a local variable of type `Option` or `Result` is mutated, +/// *except* for if `.as_mut()` is called. /// The reason for why we allow that one specifically is that `.as_mut()` cannot change -/// the option to `None`, and that is important because this lint relies on the fact that +/// the variant, and that is important because this lint relies on the fact that /// `is_some` + `unwrap` is equivalent to `if let Some(..) = ..`, which it would not be if -/// the option is changed to None between `is_some` and `unwrap`. +/// the option is changed to None between `is_some` and `unwrap`, ditto for `Result`. /// (And also `.as_mut()` is a somewhat common method that is still worth linting on.) struct MutationVisitor<'tcx> { is_mutated: bool, @@ -198,13 +194,13 @@ struct MutationVisitor<'tcx> { } /// Checks if the parent of the expression pointed at by the given `HirId` is a call to -/// `Option::as_mut`. +/// `.as_mut()`. /// /// Used by the mutation visitor to specifically allow `.as_mut()` calls. /// In particular, the `HirId` that the visitor receives is the id of the local expression /// (i.e. the `x` in `x.as_mut()`), and that is the reason for why we care about its parent /// expression: that will be where the actual method call is. -fn is_option_as_mut_use(tcx: TyCtxt<'_>, expr_id: HirId) -> bool { +fn is_as_mut_use(tcx: TyCtxt<'_>, expr_id: HirId) -> bool { if let Node::Expr(mutating_expr) = tcx.parent_hir_node(expr_id) && let ExprKind::MethodCall(path, _, [], _) = mutating_expr.kind { @@ -218,14 +214,16 @@ impl<'tcx> Delegate<'tcx> for MutationVisitor<'tcx> { fn borrow(&mut self, cat: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::BorrowKind) { if let ty::BorrowKind::Mutable = bk && is_potentially_local_place(self.local_id, &cat.place) - && !is_option_as_mut_use(self.tcx, diag_expr_id) + && !is_as_mut_use(self.tcx, diag_expr_id) { self.is_mutated = true; } } - fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) { - self.is_mutated = true; + fn mutate(&mut self, cat: &PlaceWithHirId<'tcx>, _: HirId) { + if is_potentially_local_place(self.local_id, &cat.place) { + self.is_mutated = true; + } } fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} @@ -276,12 +274,10 @@ enum AsRefKind { /// If it isn't, the expression itself is returned. fn consume_option_as_ref<'tcx>(expr: &'tcx Expr<'tcx>) -> (&'tcx Expr<'tcx>, Option) { if let ExprKind::MethodCall(path, recv, [], _) = expr.kind { - if path.ident.name == sym::as_ref { - (recv, Some(AsRefKind::AsRef)) - } else if path.ident.name == sym::as_mut { - (recv, Some(AsRefKind::AsMut)) - } else { - (expr, None) + match path.ident.name { + sym::as_ref => (recv, Some(AsRefKind::AsRef)), + sym::as_mut => (recv, Some(AsRefKind::AsMut)), + _ => (expr, None), } } else { (expr, None) @@ -296,6 +292,10 @@ impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> { if expr.span.in_external_macro(self.cx.tcx.sess.source_map()) { return; } + // Skip checking inside closures since they are visited through `Unwrap::check_fn()` already. + if matches!(expr.kind, ExprKind::Closure(_)) { + return; + } if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr) { walk_expr(self, cond); self.visit_branch(expr, cond, then, false); @@ -332,8 +332,7 @@ impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> { expr.span, format!( "called `{}` on `{unwrappable_variable_name}` after checking its variant with `{}`", - method_name.ident.name, - unwrappable.check_name.ident.as_str(), + method_name.ident.name, unwrappable.check_name, ), |diag| { if is_entire_condition { diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index b7dcd2ffb0eea..812c4df4ddde5 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -1,16 +1,18 @@ -use clippy_utils::{get_attr, higher}; +use clippy_utils::{MaybePath, get_attr, higher, path_def_id}; +use itertools::Itertools; use rustc_ast::LitIntType; use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_data_structures::fx::FxHashMap; +use rustc_hir::def_id::DefId; use rustc_hir::{ self as hir, BindingMode, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind, ExprKind, - FnRetTy, HirId, Lit, PatExprKind, PatKind, QPath, StmtKind, StructTailExpr, TyKind, + FnRetTy, HirId, Lit, PatExprKind, PatKind, QPath, StmtKind, StructTailExpr, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::declare_lint_pass; use rustc_span::symbol::{Ident, Symbol}; use std::cell::Cell; -use std::fmt::{Display, Formatter, Write as _}; +use std::fmt::{Display, Formatter}; declare_lint_pass!( /// ### What it does @@ -148,6 +150,15 @@ fn check_node(cx: &LateContext<'_>, hir_id: HirId, f: impl Fn(&PrintVisitor<'_, } } +fn paths_static_name(cx: &LateContext<'_>, id: DefId) -> String { + cx.get_def_path(id) + .iter() + .map(Symbol::as_str) + .filter(|s| !s.starts_with('<')) + .join("_") + .to_uppercase() +} + struct Binding { name: String, value: T, @@ -257,11 +268,44 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { chain!(self, "{symbol}.as_str() == {:?}", symbol.value.as_str()); } - fn qpath(&self, qpath: &Binding<&QPath<'_>>) { + fn qpath<'p>(&self, qpath: &Binding<&QPath<'_>>, has_hir_id: &Binding<&impl MaybePath<'p>>) { if let QPath::LangItem(lang_item, ..) = *qpath.value { chain!(self, "matches!({qpath}, QPath::LangItem(LangItem::{lang_item:?}, _))"); - } else if let Ok(path) = path_to_string(qpath.value) { - chain!(self, "match_qpath({qpath}, &[{}])", path); + } else if let Some(def_id) = self.cx.qpath_res(qpath.value, has_hir_id.value.hir_id()).opt_def_id() + && !def_id.is_local() + { + bind!(self, def_id); + chain!( + self, + "let Some({def_id}) = cx.qpath_res({qpath}, {has_hir_id}.hir_id).opt_def_id()" + ); + if let Some(name) = self.cx.tcx.get_diagnostic_name(def_id.value) { + chain!(self, "cx.tcx.is_diagnostic_item(sym::{name}, {def_id})"); + } else { + chain!( + self, + "paths::{}.matches(cx, {def_id}) // Add the path to `clippy_utils::paths` if needed", + paths_static_name(self.cx, def_id.value) + ); + } + } + } + + fn maybe_path<'p>(&self, path: &Binding<&impl MaybePath<'p>>) { + if let Some(id) = path_def_id(self.cx, path.value) + && !id.is_local() + { + if let Some(lang) = self.cx.tcx.lang_items().from_def_id(id) { + chain!(self, "is_path_lang_item(cx, {path}, LangItem::{}", lang.name()); + } else if let Some(name) = self.cx.tcx.get_diagnostic_name(id) { + chain!(self, "is_path_diagnostic_item(cx, {path}, sym::{name})"); + } else { + chain!( + self, + "paths::{}.matches_path(cx, {path}) // Add the path to `clippy_utils::paths` if needed", + paths_static_name(self.cx, id) + ); + } } } @@ -270,7 +314,6 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { ConstArgKind::Path(ref qpath) => { bind!(self, qpath); chain!(self, "let ConstArgKind::Path(ref {qpath}) = {const_arg}.kind"); - self.qpath(qpath); }, ConstArgKind::Anon(anon_const) => { bind!(self, anon_const); @@ -394,12 +437,10 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { bind!(self, let_expr); kind!("Let({let_expr})"); self.pat(field!(let_expr.pat)); - // Does what ExprKind::Cast does, only adds a clause for the type - // if it's a path - if let Some(TyKind::Path(qpath)) = let_expr.value.ty.as_ref().map(|ty| &ty.kind) { - bind!(self, qpath); - chain!(self, "let TyKind::Path(ref {qpath}) = {let_expr}.ty.kind"); - self.qpath(qpath); + if let Some(ty) = let_expr.value.ty { + bind!(self, ty); + chain!(self, "let Some({ty}) = {let_expr}.ty"); + self.maybe_path(ty); } self.expr(field!(let_expr.init)); }, @@ -451,11 +492,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { ExprKind::Cast(expr, cast_ty) => { bind!(self, expr, cast_ty); kind!("Cast({expr}, {cast_ty})"); - if let TyKind::Path(ref qpath) = cast_ty.value.kind { - bind!(self, qpath); - chain!(self, "let TyKind::Path(ref {qpath}) = {cast_ty}.kind"); - self.qpath(qpath); - } + self.maybe_path(cast_ty); self.expr(expr); }, ExprKind::Type(expr, _ty) => { @@ -561,10 +598,8 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { self.expr(object); self.expr(index); }, - ExprKind::Path(ref qpath) => { - bind!(self, qpath); - kind!("Path(ref {qpath})"); - self.qpath(qpath); + ExprKind::Path(_) => { + self.maybe_path(expr); }, ExprKind::AddrOf(kind, mutability, inner) => { bind!(self, inner); @@ -608,7 +643,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { StructTailExpr::None | StructTailExpr::DefaultFields(_) => None, }); kind!("Struct({qpath}, {fields}, {base})"); - self.qpath(qpath); + self.qpath(qpath, expr); self.slice(fields, |field| { self.ident(field!(field.ident)); self.expr(field!(field.expr)); @@ -648,7 +683,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { self.expr(expr); } - fn pat_expr(&self, lit: &Binding<&hir::PatExpr<'_>>) { + fn pat_expr(&self, lit: &Binding<&hir::PatExpr<'_>>, pat: &Binding<&hir::Pat<'_>>) { let kind = |kind| chain!(self, "let PatExprKind::{kind} = {lit}.kind"); macro_rules! kind { ($($t:tt)*) => (kind(format_args!($($t)*))); @@ -657,15 +692,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { PatExprKind::Lit { lit, negated } => { bind!(self, lit); bind!(self, negated); - kind!("Lit{{ref {lit}, {negated} }}"); + kind!("Lit {{ ref {lit}, {negated} }}"); self.lit(lit); }, PatExprKind::ConstBlock(_) => kind!("ConstBlock(_)"), - PatExprKind::Path(ref qpath) => { - bind!(self, qpath); - kind!("Path(ref {qpath})"); - self.qpath(qpath); - }, + PatExprKind::Path(_) => self.maybe_path(pat), } } @@ -697,7 +728,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { PatKind::Struct(ref qpath, fields, ignore) => { bind!(self, qpath, fields); kind!("Struct(ref {qpath}, {fields}, {ignore})"); - self.qpath(qpath); + self.qpath(qpath, pat); self.slice(fields, |field| { self.ident(field!(field.ident)); self.pat(field!(field.pat)); @@ -711,7 +742,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { PatKind::TupleStruct(ref qpath, fields, skip_pos) => { bind!(self, qpath, fields); kind!("TupleStruct(ref {qpath}, {fields}, {skip_pos:?})"); - self.qpath(qpath); + self.qpath(qpath, pat); self.slice(fields, |pat| self.pat(pat)); }, PatKind::Tuple(fields, skip_pos) => { @@ -743,13 +774,13 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { PatKind::Expr(lit_expr) => { bind!(self, lit_expr); kind!("Expr({lit_expr})"); - self.pat_expr(lit_expr); + self.pat_expr(lit_expr, pat); }, PatKind::Range(start, end, end_kind) => { opt_bind!(self, start, end); kind!("Range({start}, {end}, RangeEnd::{end_kind:?})"); - start.if_some(|e| self.pat_expr(e)); - end.if_some(|e| self.pat_expr(e)); + start.if_some(|e| self.pat_expr(e, pat)); + end.if_some(|e| self.pat_expr(e, pat)); }, PatKind::Slice(start, middle, end) => { bind!(self, start, end); @@ -797,32 +828,3 @@ fn has_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool { let attrs = cx.tcx.hir_attrs(hir_id); get_attr(cx.sess(), attrs, "author").count() > 0 } - -fn path_to_string(path: &QPath<'_>) -> Result { - fn inner(s: &mut String, path: &QPath<'_>) -> Result<(), ()> { - match *path { - QPath::Resolved(_, path) => { - for (i, segment) in path.segments.iter().enumerate() { - if i > 0 { - *s += ", "; - } - write!(s, "{:?}", segment.ident.as_str()).unwrap(); - } - }, - QPath::TypeRelative(ty, segment) => match &ty.kind { - TyKind::Path(inner_path) => { - inner(s, inner_path)?; - *s += ", "; - write!(s, "{:?}", segment.ident.as_str()).unwrap(); - }, - other => write!(s, "/* unimplemented: {other:?}*/").unwrap(), - }, - QPath::LangItem(..) => return Err(()), - } - - Ok(()) - } - let mut s = String::new(); - inner(&mut s, path)?; - Ok(s) -} diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index f24c127c4521d..a8758b65c9192 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -498,9 +498,9 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { None => return, }, LitKind::Char => ( - match lit.symbol.as_str() { - "\"" => "\\\"", - "\\'" => "'", + match lit.symbol { + sym::DOUBLE_QUOTE => "\\\"", + sym::BACKSLASH_SINGLE_QUOTE => "'", _ => match value_string.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) { Some(stripped) => stripped, None => return, diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs index a97643e0eaca5..24b1381ba458c 100644 --- a/clippy_lints/src/zero_sized_map_values.rs +++ b/clippy_lints/src/zero_sized_map_values.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::ty::{is_normalizable, is_type_diagnostic_item, ty_from_hir_ty}; +use clippy_utils::ty::{is_type_diagnostic_item, ty_from_hir_ty}; use rustc_hir::{self as hir, AmbigArg, HirId, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf as _; @@ -54,8 +54,6 @@ impl LateLintPass<'_> for ZeroSizedMapValues { // Fixes https://github.com/rust-lang/rust-clippy/issues/7447 because of // https://github.com/rust-lang/rust/blob/master/compiler/rustc_middle/src/ty/sty.rs#L968 && !ty.has_escaping_bound_vars() - // Do this to prevent `layout_of` crashing, being unable to fully normalize `ty`. - && is_normalizable(cx, cx.param_env, ty) && let Ok(layout) = cx.layout_of(ty) && layout.is_zst() { diff --git a/clippy_lints_internal/Cargo.toml b/clippy_lints_internal/Cargo.toml index 2a0ceac27a324..a8293a1ad395d 100644 --- a/clippy_lints_internal/Cargo.toml +++ b/clippy_lints_internal/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_lints_internal" version = "0.0.1" -edition = "2021" +edition = "2024" [dependencies] clippy_config = { path = "../clippy_config" } diff --git a/clippy_lints_internal/src/collapsible_calls.rs b/clippy_lints_internal/src/collapsible_calls.rs index d7967a0cc022f..407deb45db0a7 100644 --- a/clippy_lints_internal/src/collapsible_calls.rs +++ b/clippy_lints_internal/src/collapsible_calls.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::{SpanlessEq, is_expr_path_def_path, is_lint_allowed, peel_blocks_with_stmt}; +use clippy_utils::{SpanlessEq, is_lint_allowed, peel_blocks_with_stmt}; use rustc_errors::Applicability; use rustc_hir::{Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -10,6 +10,8 @@ use rustc_span::Span; use std::borrow::{Borrow, Cow}; +use crate::internal_paths; + declare_tool_lint! { /// ### What it does /// Lints `span_lint_and_then` function calls, where the @@ -80,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls { } if let ExprKind::Call(func, [call_cx, call_lint, call_sp, call_msg, call_f]) = expr.kind - && is_expr_path_def_path(cx, func, &["clippy_utils", "diagnostics", "span_lint_and_then"]) + && internal_paths::SPAN_LINT_AND_THEN.matches_path(cx, func) && let ExprKind::Closure(&Closure { body, .. }) = call_f.kind && let body = cx.tcx.hir_body(body) && let only_expr = peel_blocks_with_stmt(body.value) diff --git a/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs b/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs new file mode 100644 index 0000000000000..a1dacd359a06c --- /dev/null +++ b/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs @@ -0,0 +1,164 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::paths; +use rustc_ast::tokenstream::{TokenStream, TokenTree}; +use rustc_ast::{AttrStyle, DelimArgs}; +use rustc_hir::def::Res; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::{ + AttrArgs, AttrItem, AttrPath, Attribute, HirId, Impl, Item, ItemKind, Path, QPath, TraitRef, Ty, TyKind, +}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint_defs::declare_tool_lint; +use rustc_middle::ty::TyCtxt; +use rustc_session::declare_lint_pass; +use rustc_span::sym; + +declare_tool_lint! { + /// ### What it does + /// Checks for structs or enums that derive `serde::Deserialize` and that + /// do not have a `#[serde(deny_unknown_fields)]` attribute. + /// + /// ### Why is this bad? + /// If the struct or enum is used in [`clippy_config::conf::Conf`] and a + /// user inserts an unknown field by mistake, the user's error will be + /// silently ignored. + /// + /// ### Example + /// ```rust + /// #[derive(serde::Deserialize)] + /// pub struct DisallowedPath { + /// path: String, + /// reason: Option, + /// replacement: Option, + /// } + /// ``` + /// + /// Use instead: + /// ```rust + /// #[derive(serde::Deserialize)] + /// #[serde(deny_unknown_fields)] + /// pub struct DisallowedPath { + /// path: String, + /// reason: Option, + /// replacement: Option, + /// } + /// ``` + pub clippy::DERIVE_DESERIALIZE_ALLOWING_UNKNOWN, + Allow, + "`#[derive(serde::Deserialize)]` without `#[serde(deny_unknown_fields)]`", + report_in_external_macro: true +} + +declare_lint_pass!(DeriveDeserializeAllowingUnknown => [DERIVE_DESERIALIZE_ALLOWING_UNKNOWN]); + +impl<'tcx> LateLintPass<'tcx> for DeriveDeserializeAllowingUnknown { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + // Is this an `impl` (of a certain form)? + let ItemKind::Impl(Impl { + of_trait: + Some(TraitRef { + path: + Path { + res: Res::Def(_, trait_def_id), + .. + }, + .. + }), + self_ty: + Ty { + kind: + TyKind::Path(QPath::Resolved( + None, + Path { + res: Res::Def(_, self_ty_def_id), + .. + }, + )), + .. + }, + .. + }) = item.kind + else { + return; + }; + + // Is it an `impl` of the trait `serde::Deserialize`? + if !paths::SERDE_DESERIALIZE.get(cx).contains(trait_def_id) { + return; + } + + // Is it derived? + if !cx.tcx.has_attr(item.owner_id, sym::automatically_derived) { + return; + } + + // Is `self_ty` local? + let Some(local_def_id) = self_ty_def_id.as_local() else { + return; + }; + + // Does `self_ty` have a variant with named fields? + if !has_variant_with_named_fields(cx.tcx, local_def_id) { + return; + } + + let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id); + + // Does `self_ty` have `#[serde(deny_unknown_fields)]`? + if let Some(tokens) = find_serde_attr_item(cx.tcx, hir_id) + && tokens.iter().any(is_deny_unknown_fields_token) + { + return; + } + + span_lint( + cx, + DERIVE_DESERIALIZE_ALLOWING_UNKNOWN, + item.span, + "`#[derive(serde::Deserialize)]` without `#[serde(deny_unknown_fields)]`", + ); + } +} + +// Determines whether `def_id` corresponds to an ADT with at least one variant with named fields. A +// variant has named fields if its `ctor` field is `None`. +fn has_variant_with_named_fields(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + let ty = tcx.type_of(def_id).skip_binder(); + + let rustc_middle::ty::Adt(adt_def, _) = ty.kind() else { + return false; + }; + + adt_def.variants().iter().any(|variant_def| variant_def.ctor.is_none()) +} + +fn find_serde_attr_item(tcx: TyCtxt<'_>, hir_id: HirId) -> Option<&TokenStream> { + tcx.hir_attrs(hir_id).iter().find_map(|attribute| { + if let Attribute::Unparsed(attr_item) = attribute + && let AttrItem { + path: AttrPath { segments, .. }, + args: AttrArgs::Delimited(DelimArgs { tokens, .. }), + style: AttrStyle::Outer, + .. + } = &**attr_item + && segments.len() == 1 + && segments[0].as_str() == "serde" + { + Some(tokens) + } else { + None + } + }) +} + +fn is_deny_unknown_fields_token(tt: &TokenTree) -> bool { + if let TokenTree::Token(token, _) = tt + && token + .ident() + .is_some_and(|(token, _)| token.as_str() == "deny_unknown_fields") + { + true + } else { + false + } +} diff --git a/clippy_lints_internal/src/internal_paths.rs b/clippy_lints_internal/src/internal_paths.rs new file mode 100644 index 0000000000000..dc1e30ab2bdd3 --- /dev/null +++ b/clippy_lints_internal/src/internal_paths.rs @@ -0,0 +1,17 @@ +use clippy_utils::paths::{PathLookup, PathNS}; +use clippy_utils::{sym, type_path, value_path}; + +// Paths inside rustc +pub static EARLY_LINT_PASS: PathLookup = type_path!(rustc_lint::passes::EarlyLintPass); +pub static KW_MODULE: PathLookup = type_path!(rustc_span::symbol::kw); +pub static LINT: PathLookup = type_path!(rustc_lint_defs::Lint); +pub static SYMBOL: PathLookup = type_path!(rustc_span::symbol::Symbol); +pub static SYMBOL_AS_STR: PathLookup = value_path!(rustc_span::symbol::Symbol::as_str); +pub static SYM_MODULE: PathLookup = type_path!(rustc_span::symbol::sym); +pub static SYNTAX_CONTEXT: PathLookup = type_path!(rustc_span::hygiene::SyntaxContext); + +// Paths in clippy itself +pub static CLIPPY_SYM_MODULE: PathLookup = type_path!(clippy_utils::sym); +pub static MSRV_STACK: PathLookup = type_path!(clippy_utils::msrvs::MsrvStack); +pub static PATH_LOOKUP_NEW: PathLookup = value_path!(clippy_utils::paths::PathLookup::new); +pub static SPAN_LINT_AND_THEN: PathLookup = value_path!(clippy_utils::diagnostics::span_lint_and_then); diff --git a/clippy_lints_internal/src/invalid_paths.rs b/clippy_lints_internal/src/invalid_paths.rs deleted file mode 100644 index bee87efa3fcd4..0000000000000 --- a/clippy_lints_internal/src/invalid_paths.rs +++ /dev/null @@ -1,108 +0,0 @@ -use clippy_utils::consts::{ConstEvalCtxt, Constant}; -use clippy_utils::def_path_res; -use clippy_utils::diagnostics::span_lint; -use rustc_hir as hir; -use rustc_hir::Item; -use rustc_hir::def::DefKind; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_lint_defs::declare_tool_lint; -use rustc_middle::ty::fast_reject::SimplifiedType; -use rustc_middle::ty::{self, FloatTy}; -use rustc_session::declare_lint_pass; -use rustc_span::symbol::Symbol; - -declare_tool_lint! { - /// ### What it does - /// Checks the paths module for invalid paths. - /// - /// ### Why is this bad? - /// It indicates a bug in the code. - /// - /// ### Example - /// None. - pub clippy::INVALID_PATHS, - Warn, - "invalid path", - report_in_external_macro: true -} - -declare_lint_pass!(InvalidPaths => [INVALID_PATHS]); - -impl<'tcx> LateLintPass<'tcx> for InvalidPaths { - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - let local_def_id = &cx.tcx.parent_module(item.hir_id()); - let mod_name = &cx.tcx.item_name(local_def_id.to_def_id()); - if mod_name.as_str() == "paths" - && let hir::ItemKind::Const(.., body_id) = item.kind - && let Some(Constant::Vec(path)) = ConstEvalCtxt::with_env( - cx.tcx, - ty::TypingEnv::post_analysis(cx.tcx, item.owner_id), - cx.tcx.typeck(item.owner_id), - ) - .eval_simple(cx.tcx.hir_body(body_id).value) - && let Some(path) = path - .iter() - .map(|x| { - if let Constant::Str(s) = x { - Some(s.as_str()) - } else { - None - } - }) - .collect::>>() - && !check_path(cx, &path[..]) - { - span_lint(cx, INVALID_PATHS, item.span, "invalid path"); - } - } -} - -// This is not a complete resolver for paths. It works on all the paths currently used in the paths -// module. That's all it does and all it needs to do. -pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool { - if !def_path_res(cx.tcx, path).is_empty() { - return true; - } - - // Some implementations can't be found by `path_to_res`, particularly inherent - // implementations of native types. Check lang items. - let path_syms: Vec<_> = path.iter().map(|p| Symbol::intern(p)).collect(); - let lang_items = cx.tcx.lang_items(); - // This list isn't complete, but good enough for our current list of paths. - let incoherent_impls = [ - SimplifiedType::Float(FloatTy::F32), - SimplifiedType::Float(FloatTy::F64), - SimplifiedType::Slice, - SimplifiedType::Str, - SimplifiedType::Bool, - SimplifiedType::Char, - ] - .iter() - .flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter()) - .copied(); - for item_def_id in lang_items.iter().map(|(_, def_id)| def_id).chain(incoherent_impls) { - let lang_item_path = cx.get_def_path(item_def_id); - if path_syms.starts_with(&lang_item_path) - && let [item] = &path_syms[lang_item_path.len()..] - { - if matches!( - cx.tcx.def_kind(item_def_id), - DefKind::Mod | DefKind::Enum | DefKind::Trait - ) { - for child in cx.tcx.module_children(item_def_id) { - if child.ident.name == *item { - return true; - } - } - } else { - for child in cx.tcx.associated_item_def_ids(item_def_id) { - if cx.tcx.item_name(*child) == *item { - return true; - } - } - } - } - } - - false -} diff --git a/clippy_lints_internal/src/lib.rs b/clippy_lints_internal/src/lib.rs index b02d378619cab..43cde86504f5c 100644 --- a/clippy_lints_internal/src/lib.rs +++ b/clippy_lints_internal/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(let_chains, rustc_private)] +#![feature(rustc_private)] #![allow( clippy::missing_docs_in_private_items, clippy::must_use_candidate, @@ -32,7 +32,8 @@ extern crate rustc_span; mod almost_standard_lint_formulation; mod collapsible_calls; -mod invalid_paths; +mod derive_deserialize_allowing_unknown; +mod internal_paths; mod lint_without_lint_pass; mod msrv_attr_impl; mod outer_expn_data_pass; @@ -46,7 +47,7 @@ use rustc_lint::{Lint, LintStore}; static LINTS: &[&Lint] = &[ almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION, collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS, - invalid_paths::INVALID_PATHS, + derive_deserialize_allowing_unknown::DERIVE_DESERIALIZE_ALLOWING_UNKNOWN, lint_without_lint_pass::DEFAULT_LINT, lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE, lint_without_lint_pass::LINT_WITHOUT_LINT_PASS, @@ -66,10 +67,10 @@ pub fn register_lints(store: &mut LintStore) { store.register_early_pass(|| Box::new(unsorted_clippy_utils_paths::UnsortedClippyUtilsPaths)); store.register_early_pass(|| Box::new(produce_ice::ProduceIce)); store.register_late_pass(|_| Box::new(collapsible_calls::CollapsibleCalls)); - store.register_late_pass(|_| Box::new(invalid_paths::InvalidPaths)); + store.register_late_pass(|_| Box::new(derive_deserialize_allowing_unknown::DeriveDeserializeAllowingUnknown)); store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::::default()); - store.register_late_pass(|_| Box::::default()); + store.register_late_pass(|_| Box::new(unnecessary_def_path::UnnecessaryDefPath)); store.register_late_pass(|_| Box::new(outer_expn_data_pass::OuterExpnDataPass)); store.register_late_pass(|_| Box::new(msrv_attr_impl::MsrvAttrImpl)); store.register_late_pass(|_| Box::new(almost_standard_lint_formulation::AlmostStandardFormulation::new())); diff --git a/clippy_lints_internal/src/lint_without_lint_pass.rs b/clippy_lints_internal/src/lint_without_lint_pass.rs index 6a75defcce341..655d8fb8d1bfb 100644 --- a/clippy_lints_internal/src/lint_without_lint_pass.rs +++ b/clippy_lints_internal/src/lint_without_lint_pass.rs @@ -1,6 +1,7 @@ +use crate::internal_paths; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; +use clippy_utils::is_lint_allowed; use clippy_utils::macros::root_macro_call_first_node; -use clippy_utils::{is_lint_allowed, match_def_path, paths}; use rustc_ast::ast::LitKind; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_hir as hir; @@ -209,10 +210,10 @@ pub(super) fn is_lint_ref_type(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { && let TyKind::Path(ref path) = inner.kind && let Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, inner.hir_id) { - return match_def_path(cx, def_id, &paths::LINT); + internal_paths::LINT.matches(cx, def_id) + } else { + false } - - false } fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<'_>) { diff --git a/clippy_lints_internal/src/msrv_attr_impl.rs b/clippy_lints_internal/src/msrv_attr_impl.rs index dda054546e262..d48d8dc57b240 100644 --- a/clippy_lints_internal/src/msrv_attr_impl.rs +++ b/clippy_lints_internal/src/msrv_attr_impl.rs @@ -1,7 +1,6 @@ +use crate::internal_paths; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::ty::match_type; -use clippy_utils::{match_def_path, paths}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -31,7 +30,7 @@ impl LateLintPass<'_> for MsrvAttrImpl { .tcx .impl_trait_ref(item.owner_id) .map(EarlyBinder::instantiate_identity) - && match_def_path(cx, trait_ref.def_id, &paths::EARLY_LINT_PASS) + && internal_paths::EARLY_LINT_PASS.matches(cx, trait_ref.def_id) && let ty::Adt(self_ty_def, _) = trait_ref.self_ty().kind() && self_ty_def.is_struct() && self_ty_def.all_fields().any(|f| { @@ -40,7 +39,7 @@ impl LateLintPass<'_> for MsrvAttrImpl { .instantiate_identity() .walk() .filter(|t| matches!(t.unpack(), GenericArgKind::Type(_))) - .any(|t| match_type(cx, t.expect_ty(), &paths::MSRV_STACK)) + .any(|t| internal_paths::MSRV_STACK.matches_ty(cx, t.expect_ty())) }) && !items.iter().any(|item| item.ident.name.as_str() == "check_attributes") { diff --git a/clippy_lints_internal/src/outer_expn_data_pass.rs b/clippy_lints_internal/src/outer_expn_data_pass.rs index e94419647978c..40951443a48a9 100644 --- a/clippy_lints_internal/src/outer_expn_data_pass.rs +++ b/clippy_lints_internal/src/outer_expn_data_pass.rs @@ -1,6 +1,6 @@ +use crate::internal_paths; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::ty::match_type; -use clippy_utils::{is_lint_allowed, method_calls, paths}; +use clippy_utils::{is_lint_allowed, method_calls}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; @@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass { && let (self_arg, args) = arg_lists[1] && args.is_empty() && let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs() - && match_type(cx, self_ty, &paths::SYNTAX_CONTEXT) + && internal_paths::SYNTAX_CONTEXT.matches_ty(cx, self_ty) { span_lint_and_sugg( cx, diff --git a/clippy_lints_internal/src/symbols.rs b/clippy_lints_internal/src/symbols.rs index c64e5821916bf..5aee545fb0f5b 100644 --- a/clippy_lints_internal/src/symbols.rs +++ b/clippy_lints_internal/src/symbols.rs @@ -1,11 +1,10 @@ +use crate::internal_paths; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::ty::match_type; -use clippy_utils::{def_path_def_ids, match_def_path, paths}; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, Lit, Node, Pat, PatExprKind, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_lint_defs::declare_tool_lint; use rustc_middle::mir::ConstValue; @@ -66,17 +65,50 @@ pub struct Symbols { impl_lint_pass!(Symbols => [INTERNING_LITERALS, SYMBOL_AS_STR]); +impl Symbols { + fn lit_suggestion(&self, lit: &Lit) -> Option<(Span, String)> { + if let LitKind::Str(name, _) = lit.node { + let sugg = if let Some((prefix, name)) = self.symbol_map.get(&name.as_u32()) { + format!("{prefix}::{name}") + } else { + format!("sym::{}", name.as_str().replace(|ch: char| !ch.is_alphanumeric(), "_")) + }; + Some((lit.span, sugg)) + } else { + None + } + } + + fn expr_suggestion(&self, expr: &Expr<'_>) -> Option<(Span, String)> { + if let ExprKind::Lit(lit) = expr.kind { + self.lit_suggestion(lit) + } else { + None + } + } + + fn pat_suggestions(&self, pat: &Pat<'_>, suggestions: &mut Vec<(Span, String)>) { + pat.walk_always(|pat| { + if let PatKind::Expr(pat_expr) = pat.kind + && let PatExprKind::Lit { lit, .. } = pat_expr.kind + { + suggestions.extend(self.lit_suggestion(lit)); + } + }); + } +} + impl<'tcx> LateLintPass<'tcx> for Symbols { fn check_crate(&mut self, cx: &LateContext<'_>) { let modules = [ - ("kw", &paths::KW_MODULE[..]), - ("sym", &paths::SYM_MODULE), - ("sym", &paths::CLIPPY_SYM_MODULE), + ("kw", &internal_paths::KW_MODULE), + ("sym", &internal_paths::SYM_MODULE), + ("sym", &internal_paths::CLIPPY_SYM_MODULE), ]; for (prefix, module) in modules { - for def_id in def_path_def_ids(cx.tcx, module) { + for def_id in module.get(cx) { // When linting `clippy_utils` itself we can't use `module_children` as it's a local def id. It will - // still lint but the suggestion will say to add it to `sym.rs` even if it's already there + // still lint but the suggestion may suggest the incorrect name for symbols such as `sym::CRLF` if def_id.is_local() { continue; } @@ -84,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for Symbols { for item in cx.tcx.module_children(def_id) { if let Res::Def(DefKind::Const, item_def_id) = item.res && let ty = cx.tcx.type_of(item_def_id).instantiate_identity() - && match_type(cx, ty, &paths::SYMBOL) + && internal_paths::SYMBOL.matches_ty(cx, ty) && let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id) && let Some(value) = value.to_u32().discard_err() { @@ -99,8 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for Symbols { if let ExprKind::Call(func, [arg]) = &expr.kind && let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind() && cx.tcx.is_diagnostic_item(sym::SymbolIntern, *def_id) - && let ExprKind::Lit(lit) = arg.kind - && let LitKind::Str(name, _) = lit.node + && let Some((_, sugg)) = self.expr_suggestion(arg) { span_lint_and_then( cx, @@ -108,48 +139,55 @@ impl<'tcx> LateLintPass<'tcx> for Symbols { expr.span, "interning a string literal", |diag| { - let (message, path) = suggestion(&mut self.symbol_map, name); - diag.span_suggestion_verbose(expr.span, message, path, Applicability::MaybeIncorrect); + diag.span_suggestion_verbose( + expr.span, + "use a preinterned symbol instead", + sugg, + Applicability::MaybeIncorrect, + ); + diag.help("add the symbol to `clippy_utils/src/sym.rs` if needed"); }, ); } - if let ExprKind::Binary(_, lhs, rhs) = expr.kind { - check_binary(cx, lhs, rhs, &mut self.symbol_map); - check_binary(cx, rhs, lhs, &mut self.symbol_map); - } - } -} + if let Some(as_str) = as_str_span(cx, expr) + && let Node::Expr(parent) = cx.tcx.parent_hir_node(expr.hir_id) + { + let mut suggestions = Vec::new(); -fn check_binary( - cx: &LateContext<'_>, - lhs: &Expr<'_>, - rhs: &Expr<'_>, - symbols: &mut FxHashMap, -) { - if let Some(removal_span) = as_str_span(cx, lhs) - && let ExprKind::Lit(lit) = rhs.kind - && let LitKind::Str(name, _) = lit.node - { - span_lint_and_then(cx, SYMBOL_AS_STR, lhs.span, "converting a Symbol to a string", |diag| { - let (message, path) = suggestion(symbols, name); - diag.multipart_suggestion_verbose( - message, - vec![(removal_span, String::new()), (rhs.span, path)], - Applicability::MachineApplicable, - ); - }); - } -} + match parent.kind { + ExprKind::Binary(_, lhs, rhs) => { + suggestions.extend(self.expr_suggestion(lhs)); + suggestions.extend(self.expr_suggestion(rhs)); + }, + ExprKind::Match(_, arms, _) => { + for arm in arms { + self.pat_suggestions(arm.pat, &mut suggestions); + } + }, + _ => {}, + } -fn suggestion(symbols: &mut FxHashMap, name: Symbol) -> (&'static str, String) { - if let Some((prefix, name)) = symbols.get(&name.as_u32()) { - ("use the preinterned symbol", format!("{prefix}::{name}")) - } else { - ( - "add the symbol to `clippy_utils/src/sym.rs` and use it", - format!("sym::{}", name.as_str().replace(|ch: char| !ch.is_alphanumeric(), "_")), - ) + if suggestions.is_empty() { + return; + } + + span_lint_and_then( + cx, + SYMBOL_AS_STR, + expr.span, + "converting a Symbol to a string", + |diag| { + suggestions.push((as_str, String::new())); + diag.multipart_suggestion( + "use preinterned symbols instead", + suggestions, + Applicability::MaybeIncorrect, + ); + diag.help("add the symbols to `clippy_utils/src/sym.rs` if needed"); + }, + ); + } } } @@ -160,7 +198,7 @@ fn suggestion(symbols: &mut FxHashMap, name: Symbol fn as_str_span(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { if let ExprKind::MethodCall(_, recv, [], _) = expr.kind && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) - && match_def_path(cx, method_def_id, &paths::SYMBOL_AS_STR) + && internal_paths::SYMBOL_AS_STR.matches(cx, method_def_id) { Some(recv.span.shrink_to_hi().to(expr.span.shrink_to_hi())) } else { diff --git a/clippy_lints_internal/src/unnecessary_def_path.rs b/clippy_lints_internal/src/unnecessary_def_path.rs index 6bdfbed55b062..8877f1faf0ee8 100644 --- a/clippy_lints_internal/src/unnecessary_def_path.rs +++ b/clippy_lints_internal/src/unnecessary_def_path.rs @@ -1,23 +1,14 @@ -use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{def_path_def_ids, is_lint_allowed, match_any_def_paths, peel_hir_expr_refs}; -use rustc_ast::ast::LitKind; -use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; -use rustc_errors::Applicability; -use rustc_hir::def::{DefKind, Res}; +use crate::internal_paths; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::paths::{PathNS, lookup_path}; +use clippy_utils::{path_def_id, peel_ref_operators}; use rustc_hir::def_id::DefId; -use rustc_hir::{Expr, ExprKind, LetStmt, Mutability, Node}; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_lint_defs::declare_tool_lint; +use rustc_lint_defs::{declare_lint_pass, declare_tool_lint}; use rustc_middle::mir::ConstValue; -use rustc_middle::mir::interpret::{Allocation, GlobalAlloc}; -use rustc_middle::ty::{self, Ty}; -use rustc_session::impl_lint_pass; -use rustc_span::Span; use rustc_span::symbol::Symbol; -use std::str; - declare_tool_lint! { /// ### What it does /// Checks for usage of def paths when a diagnostic item or a `LangItem` could be used. @@ -28,12 +19,14 @@ declare_tool_lint! { /// /// ### Example /// ```rust,ignore - /// utils::match_type(cx, ty, &paths::VEC) + /// pub static VEC: PathLookup = path!(alloc::vec::Vec); + /// + /// VEC.contains_ty(cx, ty) /// ``` /// /// Use instead: /// ```rust,ignore - /// utils::is_type_diagnostic_item(cx, ty, sym::Vec) + /// is_type_diagnostic_item(cx, ty, sym::Vec) /// ``` pub clippy::UNNECESSARY_DEF_PATH, Warn, @@ -41,259 +34,67 @@ declare_tool_lint! { report_in_external_macro: true } -impl_lint_pass!(UnnecessaryDefPath => [UNNECESSARY_DEF_PATH]); - -#[derive(Default)] -pub struct UnnecessaryDefPath { - array_def_ids: FxIndexSet<(DefId, Span)>, - linted_def_ids: FxHashSet, -} +declare_lint_pass!(UnnecessaryDefPath => [UNNECESSARY_DEF_PATH]); impl<'tcx> LateLintPass<'tcx> for UnnecessaryDefPath { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if is_lint_allowed(cx, UNNECESSARY_DEF_PATH, expr.hir_id) { - return; - } - - match expr.kind { - ExprKind::Call(func, args) => self.check_call(cx, func, args, expr.span), - ExprKind::Array(elements) => self.check_array(cx, elements, expr.span), - _ => {}, - } - } - - fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { - for &(def_id, span) in &self.array_def_ids { - if self.linted_def_ids.contains(&def_id) { - continue; - } - - let (msg, sugg) = if let Some(sym) = cx.tcx.get_diagnostic_name(def_id) { - ("diagnostic item", format!("sym::{sym}")) - } else if let Some(sym) = get_lang_item_name(cx, def_id) { - ("language item", format!("LangItem::{sym}")) - } else { - continue; - }; - - span_lint_and_help( - cx, - UNNECESSARY_DEF_PATH, - span, - format!("hardcoded path to a {msg}"), - None, - format!("convert all references to use `{sugg}`"), - ); - } - } -} - -impl UnnecessaryDefPath { - #[allow(clippy::too_many_lines)] - fn check_call(&mut self, cx: &LateContext<'_>, func: &Expr<'_>, args: &[Expr<'_>], span: Span) { - enum Item { - LangItem(&'static str), - DiagnosticItem(Symbol), - } - static PATHS: &[&[&str]] = &[ - &["clippy_utils", "match_def_path"], - &["clippy_utils", "match_trait_method"], - &["clippy_utils", "ty", "match_type"], - &["clippy_utils", "is_expr_path_def_path"], - ]; - - if let [cx_arg, def_arg, args @ ..] = args - && let ExprKind::Path(path) = &func.kind - && let Some(id) = cx.qpath_res(path, func.hir_id).opt_def_id() - && let Some(which_path) = match_any_def_paths(cx, id, PATHS) - && let item_arg = if which_path == 4 { &args[1] } else { &args[0] } - // Extract the path to the matched type - && let Some(segments) = path_to_matched_type(cx, item_arg) - && let segments = segments.iter().map(|sym| &**sym).collect::>() - && let Some(def_id) = def_path_def_ids(cx.tcx, &segments[..]).next() + if let ExprKind::Call(ctor, [_, path]) = expr.kind + && internal_paths::PATH_LOOKUP_NEW.matches_path(cx, ctor) + && let ExprKind::Array(segments) = peel_ref_operators(cx, path).kind + && let Some(macro_id) = expr.span.ctxt().outer_expn_data().macro_def_id { - // Check if the target item is a diagnostic item or LangItem. - #[rustfmt::skip] - let (msg, item) = if let Some(item_name) - = cx.tcx.diagnostic_items(def_id.krate).id_to_name.get(&def_id) - { - ( - "use of a def path to a diagnostic item", - Item::DiagnosticItem(*item_name), - ) - } else if let Some(item_name) = get_lang_item_name(cx, def_id) { - ( - "use of a def path to a `LangItem`", - Item::LangItem(item_name), - ) - } else { - return; - }; - - let has_ctor = match cx.tcx.def_kind(def_id) { - DefKind::Struct => { - let variant = cx.tcx.adt_def(def_id).non_enum_variant(); - variant.ctor.is_some() && variant.fields.iter().all(|f| f.vis.is_public()) - }, - DefKind::Variant => { - let variant = cx.tcx.adt_def(cx.tcx.parent(def_id)).variant_with_id(def_id); - variant.ctor.is_some() && variant.fields.iter().all(|f| f.vis.is_public()) - }, - _ => false, + let ns = match cx.tcx.item_name(macro_id).as_str() { + "type_path" => PathNS::Type, + "value_path" => PathNS::Value, + "macro_path" => PathNS::Macro, + _ => unreachable!(), }; - let mut app = Applicability::MachineApplicable; - let cx_snip = snippet_with_applicability(cx, cx_arg.span, "..", &mut app); - let def_snip = snippet_with_applicability(cx, def_arg.span, "..", &mut app); - let (sugg, with_note) = match (which_path, item) { - // match_def_path - (0, Item::DiagnosticItem(item)) => ( - format!("{cx_snip}.tcx.is_diagnostic_item(sym::{item}, {def_snip})"), - has_ctor, - ), - (0, Item::LangItem(item)) => ( - format!("{cx_snip}.tcx.lang_items().get(LangItem::{item}) == Some({def_snip})"), - has_ctor, - ), - // match_trait_method - (1, Item::DiagnosticItem(item)) => { - (format!("is_trait_method({cx_snip}, {def_snip}, sym::{item})"), false) - }, - // match_type - (2, Item::DiagnosticItem(item)) => ( - format!("is_type_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"), - false, - ), - (2, Item::LangItem(item)) => ( - format!("is_type_lang_item({cx_snip}, {def_snip}, LangItem::{item})"), - false, - ), - // is_expr_path_def_path - (3, Item::DiagnosticItem(item)) if has_ctor => ( - format!("is_res_diag_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), sym::{item})",), - false, - ), - (3, Item::LangItem(item)) if has_ctor => ( - format!("is_res_lang_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), LangItem::{item})",), - false, - ), - (3, Item::DiagnosticItem(item)) => ( - format!("is_path_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"), - false, - ), - (3, Item::LangItem(item)) => ( - format!( - "path_res({cx_snip}, {def_snip}).opt_def_id()\ - .map_or(false, |id| {cx_snip}.tcx.lang_items().get(LangItem::{item}) == Some(id))", - ), - false, - ), - _ => return, - }; - - span_lint_and_then(cx, UNNECESSARY_DEF_PATH, span, msg, |diag| { - diag.span_suggestion(span, "try", sugg, app); - if with_note { - diag.help( - "if this `DefId` came from a constructor expression or pattern then the \ - parent `DefId` should be used instead", + let path: Vec = segments + .iter() + .map(|segment| { + if let Some(const_def_id) = path_def_id(cx, segment) + && let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(const_def_id) + && let Some(value) = value.to_u32().discard_err() + { + Symbol::new(value) + } else { + panic!("failed to resolve path {:?}", expr.span); + } + }) + .collect(); + + for def_id in lookup_path(cx.tcx, ns, &path) { + if let Some(name) = cx.tcx.get_diagnostic_name(def_id) { + span_lint_and_then( + cx, + UNNECESSARY_DEF_PATH, + expr.span.source_callsite(), + format!("a diagnostic name exists for this path: sym::{name}"), + |diag| { + diag.help( + "remove the `PathLookup` and use utilities such as `cx.tcx.is_diagnostic_item` instead", + ); + diag.help("see also https://doc.rust-lang.org/nightly/nightly-rustc/?search=diag&filter-crate=clippy_utils"); + }, + ); + } else if let Some(item_name) = get_lang_item_name(cx, def_id) { + span_lint_and_then( + cx, + UNNECESSARY_DEF_PATH, + expr.span.source_callsite(), + format!("a language item exists for this path: LangItem::{item_name}"), + |diag| { + diag.help("remove the `PathLookup` and use utilities such as `cx.tcx.lang_items` instead"); + diag.help("see also https://doc.rust-lang.org/nightly/nightly-rustc/?search=lang&filter-crate=clippy_utils"); + }, ); } - }); - - self.linted_def_ids.insert(def_id); - } - } - - fn check_array(&mut self, cx: &LateContext<'_>, elements: &[Expr<'_>], span: Span) { - let Some(path) = path_from_array(elements) else { return }; - - for def_id in def_path_def_ids(cx.tcx, &path.iter().map(AsRef::as_ref).collect::>()) { - self.array_def_ids.insert((def_id, span)); - } - } -} - -fn path_to_matched_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option> { - match peel_hir_expr_refs(expr).0.kind { - ExprKind::Path(ref qpath) => match cx.qpath_res(qpath, expr.hir_id) { - Res::Local(hir_id) => { - if let Node::LetStmt(LetStmt { init: Some(init), .. }) = cx.tcx.parent_hir_node(hir_id) { - path_to_matched_type(cx, init) - } else { - None - } - }, - Res::Def(DefKind::Static { .. }, def_id) => read_mir_alloc_def_path( - cx, - cx.tcx.eval_static_initializer(def_id).ok()?.inner(), - cx.tcx.type_of(def_id).instantiate_identity(), - ), - Res::Def(DefKind::Const, def_id) => match cx.tcx.const_eval_poly(def_id).ok()? { - ConstValue::Indirect { alloc_id, offset } if offset.bytes() == 0 => { - let alloc = cx.tcx.global_alloc(alloc_id).unwrap_memory(); - read_mir_alloc_def_path(cx, alloc.inner(), cx.tcx.type_of(def_id).instantiate_identity()) - }, - _ => None, - }, - _ => None, - }, - ExprKind::Array(exprs) => path_from_array(exprs), - _ => None, - } -} - -fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation, ty: Ty<'_>) -> Option> { - let (alloc, ty) = if let ty::Ref(_, ty, Mutability::Not) = *ty.kind() { - let &alloc = alloc.provenance().ptrs().values().next()?; - if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc.alloc_id()) { - (alloc.inner(), ty) - } else { - return None; + } } - } else { - (alloc, ty) - }; - - if let ty::Array(ty, _) | ty::Slice(ty) = *ty.kind() - && let ty::Ref(_, ty, Mutability::Not) = *ty.kind() - && ty.is_str() - { - alloc - .provenance() - .ptrs() - .values() - .map(|&alloc| { - if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc.alloc_id()) { - let alloc = alloc.inner(); - str::from_utf8(alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len())) - .ok() - .map(ToOwned::to_owned) - } else { - None - } - }) - .collect() - } else { - None } } -fn path_from_array(exprs: &[Expr<'_>]) -> Option> { - exprs - .iter() - .map(|expr| { - if let ExprKind::Lit(lit) = &expr.kind - && let LitKind::Str(sym, _) = lit.node - { - return Some((*sym.as_str()).to_owned()); - } - - None - }) - .collect() -} - fn get_lang_item_name(cx: &LateContext<'_>, def_id: DefId) -> Option<&'static str> { if let Some((lang_item, _)) = cx.tcx.lang_items().iter().find(|(_, id)| *id == def_id) { Some(lang_item.variant_name()) diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index b98e990175033..ac970e1c4b0a5 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_utils" # begin autogenerated version -version = "0.1.88" +version = "0.1.89" # end autogenerated version edition = "2024" description = "Helpful tools for writing lints, provided as they are used in Clippy" diff --git a/clippy_utils/README.md b/clippy_utils/README.md index 66192f866fa0e..d4080d06d3ca8 100644 --- a/clippy_utils/README.md +++ b/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: ``` -nightly-2025-05-01 +nightly-2025-05-14 ``` diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 187dfa4dda845..0a9c39c41bd81 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1,9 +1,6 @@ -#![feature(array_chunks)] #![feature(box_patterns)] #![feature(if_let_guard)] -#![feature(macro_metavar_expr_concat)] #![feature(macro_metavar_expr)] -#![feature(let_chains)] #![feature(never_type)] #![feature(rustc_private)] #![feature(assert_matches)] @@ -97,28 +94,28 @@ use rustc_data_structures::packed::Pu128; use rustc_data_structures::unhash::UnhashMap; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId}; +use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::definitions::{DefPath, DefPathData}; use rustc_hir::hir_id::{HirIdMap, HirIdSet}; use rustc_hir::intravisit::{FnKind, Visitor, walk_expr}; use rustc_hir::{ - self as hir, Arm, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, ConstContext, - CoroutineDesugaring, CoroutineKind, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArg, - GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, - Mutability, Node, OwnerId, OwnerNode, Param, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, PrimTy, QPath, - Stmt, StmtKind, TraitFn, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, def, + self as hir, Arm, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, CoroutineDesugaring, + CoroutineKind, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArg, GenericArgs, HirId, Impl, + ImplItem, ImplItemKind, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, + Param, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, QPath, Stmt, StmtKind, TraitFn, TraitItem, + TraitItemKind, TraitRef, TyKind, UnOp, def, }; use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::{LateContext, Level, Lint, LintContext}; +use rustc_middle::hir::nested_filter; use rustc_middle::hir::place::PlaceBase; use rustc_middle::lint::LevelAndSource; use rustc_middle::mir::{AggregateKind, Operand, RETURN_PLACE, Rvalue, StatementKind, TerminatorKind}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; -use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{ - self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, FloatTy, GenericArgKind, GenericArgsRef, IntTy, Ty, - TyCtxt, TypeFlags, TypeVisitableExt, UintTy, UpvarCapture, + self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, GenericArgKind, GenericArgsRef, IntTy, Ty, TyCtxt, + TypeFlags, TypeVisitableExt, UintTy, UpvarCapture, }; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; @@ -131,7 +128,6 @@ use crate::consts::{ConstEvalCtxt, Constant, mir_to_const}; use crate::higher::Range; use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type}; use crate::visitors::for_each_expr_without_closures; -use rustc_middle::hir::nested_filter; #[macro_export] macro_rules! extract_msrv_attr { @@ -239,7 +235,7 @@ pub fn is_in_const_context(cx: &LateContext<'_>) -> bool { /// * const blocks (or inline consts) /// * associated constants pub fn is_inside_always_const_context(tcx: TyCtxt<'_>, hir_id: HirId) -> bool { - use ConstContext::{Const, ConstFn, Static}; + use rustc_hir::ConstContext::{Const, ConstFn, Static}; let Some(ctx) = tcx.hir_body_const_context(tcx.hir_enclosing_body_owner(hir_id)) else { return false; }; @@ -347,14 +343,6 @@ pub fn is_ty_alias(qpath: &QPath<'_>) -> bool { } } -/// Checks if the method call given in `expr` belongs to the given trait. -/// This is a deprecated function, consider using [`is_trait_method`]. -pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool { - let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap(); - let trt_id = cx.tcx.trait_of_item(def_id); - trt_id.is_some_and(|trt_id| match_def_path(cx, trt_id, path)) -} - /// Checks if the given method call expression calls an inherent method. pub fn is_inherent_method_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { @@ -438,44 +426,6 @@ pub fn qpath_generic_tys<'tcx>(qpath: &QPath<'tcx>) -> impl Iterator, segments: &[&str]) -> bool { - match *path { - QPath::Resolved(_, path) => match_path(path, segments), - QPath::TypeRelative(ty, segment) => match ty.kind { - TyKind::Path(ref inner_path) => { - if let [prefix @ .., end] = segments - && match_qpath(inner_path, prefix) - { - return segment.ident.name.as_str() == *end; - } - false - }, - _ => false, - }, - QPath::LangItem(..) => false, - } -} - -/// If the expression is a path, resolves it to a `DefId` and checks if it matches the given path. -/// -/// Please use `is_path_diagnostic_item` if the target is a diagnostic item. -pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool { - path_def_id(cx, expr).is_some_and(|id| match_def_path(cx, id, segments)) -} - /// If `maybe_path` is a path node which resolves to an item, resolves it to a `DefId` and checks if /// it matches the given lang item. pub fn is_path_lang_item<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>, lang_item: LangItem) -> bool { @@ -492,34 +442,6 @@ pub fn is_path_diagnostic_item<'tcx>( path_def_id(cx, maybe_path).is_some_and(|id| cx.tcx.is_diagnostic_item(diag_item, id)) } -/// THIS METHOD IS DEPRECATED. Matches a `Path` against a slice of segment string literals. -/// -/// This method is deprecated and will eventually be removed since it does not match against the -/// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from -/// `QPath::Resolved.1.res.opt_def_id()`. -/// -/// There is also `match_qpath` if you are dealing with a `rustc_hir::QPath` instead of a -/// `rustc_hir::Path`. -/// -/// # Examples -/// -/// ```rust,ignore -/// if match_path(&trait_ref.path, &paths::HASH) { -/// // This is the `std::hash::Hash` trait. -/// } -/// -/// if match_path(ty_path, &["rustc", "lint", "Lint"]) { -/// // This is a `rustc_middle::lint::Lint`. -/// } -/// ``` -pub fn match_path(path: &Path<'_>, segments: &[&str]) -> bool { - path.segments - .iter() - .rev() - .zip(segments.iter().rev()) - .all(|(a, b)| a.ident.name.as_str() == *b) -} - /// If the expression is a path to a local, returns the canonical `HirId` of the local. pub fn path_to_local(expr: &Expr<'_>) -> Option { if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind @@ -586,201 +508,6 @@ pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx> path_res(cx, maybe_path).opt_def_id() } -fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator + 'tcx { - let ty = match name { - "bool" => SimplifiedType::Bool, - "char" => SimplifiedType::Char, - "str" => SimplifiedType::Str, - "array" => SimplifiedType::Array, - "slice" => SimplifiedType::Slice, - // FIXME: rustdoc documents these two using just `pointer`. - // - // Maybe this is something we should do here too. - "const_ptr" => SimplifiedType::Ptr(Mutability::Not), - "mut_ptr" => SimplifiedType::Ptr(Mutability::Mut), - "isize" => SimplifiedType::Int(IntTy::Isize), - "i8" => SimplifiedType::Int(IntTy::I8), - "i16" => SimplifiedType::Int(IntTy::I16), - "i32" => SimplifiedType::Int(IntTy::I32), - "i64" => SimplifiedType::Int(IntTy::I64), - "i128" => SimplifiedType::Int(IntTy::I128), - "usize" => SimplifiedType::Uint(UintTy::Usize), - "u8" => SimplifiedType::Uint(UintTy::U8), - "u16" => SimplifiedType::Uint(UintTy::U16), - "u32" => SimplifiedType::Uint(UintTy::U32), - "u64" => SimplifiedType::Uint(UintTy::U64), - "u128" => SimplifiedType::Uint(UintTy::U128), - "f32" => SimplifiedType::Float(FloatTy::F32), - "f64" => SimplifiedType::Float(FloatTy::F64), - _ => { - return [].iter().copied(); - }, - }; - - tcx.incoherent_impls(ty).iter().copied() -} - -fn non_local_item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec { - match tcx.def_kind(def_id) { - DefKind::Mod | DefKind::Enum | DefKind::Trait => tcx - .module_children(def_id) - .iter() - .filter(|item| item.ident.name == name) - .map(|child| child.res.expect_non_local()) - .collect(), - DefKind::Impl { .. } => tcx - .associated_item_def_ids(def_id) - .iter() - .copied() - .filter(|assoc_def_id| tcx.item_name(*assoc_def_id) == name) - .map(|assoc_def_id| Res::Def(tcx.def_kind(assoc_def_id), assoc_def_id)) - .collect(), - _ => Vec::new(), - } -} - -fn local_item_children_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, name: Symbol) -> Vec { - let root_mod; - let item_kind = match tcx.hir_node_by_def_id(local_id) { - Node::Crate(r#mod) => { - root_mod = ItemKind::Mod(Ident::dummy(), r#mod); - &root_mod - }, - Node::Item(item) => &item.kind, - _ => return Vec::new(), - }; - - let res = |ident: Ident, owner_id: OwnerId| { - if ident.name == name { - let def_id = owner_id.to_def_id(); - Some(Res::Def(tcx.def_kind(def_id), def_id)) - } else { - None - } - }; - - match item_kind { - ItemKind::Mod(_, r#mod) => r#mod - .item_ids - .iter() - .filter_map(|&item_id| { - let ident = tcx.hir_item(item_id).kind.ident()?; - res(ident, item_id.owner_id) - }) - .collect(), - ItemKind::Impl(r#impl) => r#impl - .items - .iter() - .filter_map(|&ImplItemRef { ident, id, .. }| res(ident, id.owner_id)) - .collect(), - ItemKind::Trait(.., trait_item_refs) => trait_item_refs - .iter() - .filter_map(|&TraitItemRef { ident, id, .. }| res(ident, id.owner_id)) - .collect(), - _ => Vec::new(), - } -} - -fn item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec { - if let Some(local_id) = def_id.as_local() { - local_item_children_by_name(tcx, local_id, name) - } else { - non_local_item_children_by_name(tcx, def_id, name) - } -} - -/// Finds the crates called `name`, may be multiple due to multiple major versions. -pub fn find_crates(tcx: TyCtxt<'_>, name: Symbol) -> Vec { - tcx.crates(()) - .iter() - .copied() - .filter(move |&num| tcx.crate_name(num) == name) - .map(CrateNum::as_def_id) - .map(|id| Res::Def(tcx.def_kind(id), id)) - .collect() -} - -/// Resolves a def path like `std::vec::Vec`. -/// -/// Can return multiple resolutions when there are multiple versions of the same crate, e.g. -/// `memchr::memchr` could return the functions from both memchr 1.0 and memchr 2.0. -/// -/// Also returns multiple results when there are multiple paths under the same name e.g. `std::vec` -/// would have both a [`DefKind::Mod`] and [`DefKind::Macro`]. -/// -/// This function is expensive and should be used sparingly. -pub fn def_path_res(tcx: TyCtxt<'_>, path: &[&str]) -> Vec { - let (base, path) = match path { - [primitive] => { - return vec![PrimTy::from_name(Symbol::intern(primitive)).map_or(Res::Err, Res::PrimTy)]; - }, - [base, path @ ..] => (base, path), - _ => return Vec::new(), - }; - - let base_sym = Symbol::intern(base); - - let local_crate = if tcx.crate_name(LOCAL_CRATE) == base_sym { - Some(LOCAL_CRATE.as_def_id()) - } else { - None - }; - - let crates = find_primitive_impls(tcx, base) - .chain(local_crate) - .map(|id| Res::Def(tcx.def_kind(id), id)) - .chain(find_crates(tcx, base_sym)) - .collect(); - - def_path_res_with_base(tcx, crates, path) -} - -/// Resolves a def path like `vec::Vec` with the base `std`. -/// -/// This is lighter than [`def_path_res`], and should be called with [`find_crates`] looking up -/// items from the same crate repeatedly, although should still be used sparingly. -pub fn def_path_res_with_base(tcx: TyCtxt<'_>, mut base: Vec, mut path: &[&str]) -> Vec { - while let [segment, rest @ ..] = path { - path = rest; - let segment = Symbol::intern(segment); - - base = base - .into_iter() - .filter_map(|res| res.opt_def_id()) - .flat_map(|def_id| { - // When the current def_id is e.g. `struct S`, check the impl items in - // `impl S { ... }` - let inherent_impl_children = tcx - .inherent_impls(def_id) - .iter() - .flat_map(|&impl_def_id| item_children_by_name(tcx, impl_def_id, segment)); - - let direct_children = item_children_by_name(tcx, def_id, segment); - - inherent_impl_children.chain(direct_children) - }) - .collect(); - } - - base -} - -/// Resolves a def path like `std::vec::Vec` to its [`DefId`]s, see [`def_path_res`]. -pub fn def_path_def_ids(tcx: TyCtxt<'_>, path: &[&str]) -> impl Iterator + use<> { - def_path_res(tcx, path).into_iter().filter_map(|res| res.opt_def_id()) -} - -/// Convenience function to get the `DefId` of a trait by path. -/// It could be a trait or trait alias. -/// -/// This function is expensive and should be used sparingly. -pub fn get_trait_def_id(tcx: TyCtxt<'_>, path: &[&str]) -> Option { - def_path_res(tcx, path).into_iter().find_map(|res| match res { - Res::Def(DefKind::Trait | DefKind::TraitAlias, trait_id) => Some(trait_id), - _ => None, - }) -} - /// Gets the `hir::TraitRef` of the trait the given method is implemented for. /// /// Use this if you want to find the `TraitRef` of the `Add` trait in this example: @@ -2065,24 +1792,6 @@ pub fn in_automatically_derived(tcx: TyCtxt<'_>, id: HirId) -> bool { }) } -/// Checks if the given `DefId` matches any of the paths. Returns the index of matching path, if -/// any. -/// -/// Please use `tcx.get_diagnostic_name` if the targets are all diagnostic items. -pub fn match_any_def_paths(cx: &LateContext<'_>, did: DefId, paths: &[&[&str]]) -> Option { - let search_path = cx.get_def_path(did); - paths - .iter() - .position(|p| p.iter().map(|x| Symbol::intern(x)).eq(search_path.iter().copied())) -} - -/// Checks if the given `DefId` matches the path. -pub fn match_def_path(cx: &LateContext<'_>, did: DefId, syms: &[&str]) -> bool { - // We should probably move to Symbols in Clippy as well rather than interning every time. - let path = cx.get_def_path(did); - syms.iter().map(|x| Symbol::intern(x)).eq(path.iter().copied()) -} - /// Checks if the given `DefId` matches the `libc` item. pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: &str) -> bool { let path = cx.get_def_path(did); diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 19061b574ff88..223a8649eb3c6 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -22,7 +22,8 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { - 1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT } + 1,88,0 { LET_CHAINS } + 1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT } 1,85,0 { UINT_FLOAT_MIDPOINT } 1,84,0 { CONST_OPTION_AS_SLICE, MANUAL_DANGLING_PTR } 1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP } @@ -38,7 +39,7 @@ msrv_aliases! { 1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN } 1,68,0 { PATH_MAIN_SEPARATOR_STR } 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } - 1,63,0 { CLONE_INTO } + 1,63,0 { CLONE_INTO, CONST_SLICE_FROM_REF } 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE, CONST_EXTERN_C_FN } 1,60,0 { ABS_DIFF } 1,59,0 { THREAD_LOCAL_CONST_INIT } @@ -68,7 +69,7 @@ msrv_aliases! { 1,31,0 { OPTION_REPLACE } 1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES } 1,29,0 { ITER_FLATTEN } - 1,28,0 { FROM_BOOL, REPEAT_WITH } + 1,28,0 { FROM_BOOL, REPEAT_WITH, SLICE_FROM_REF } 1,27,0 { ITERATOR_TRY_FOLD } 1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN } 1,24,0 { IS_ASCII_DIGIT } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 7f64ebd3b6437..e5179e479ccd9 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -4,62 +4,343 @@ //! Whenever possible, please consider diagnostic items over hardcoded paths. //! See for more information. -// Paths inside rustc -pub const APPLICABILITY: [&str; 2] = ["rustc_lint_defs", "Applicability"]; -pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [ - ["rustc_lint_defs", "Applicability", "Unspecified"], - ["rustc_lint_defs", "Applicability", "HasPlaceholders"], - ["rustc_lint_defs", "Applicability", "MaybeIncorrect"], - ["rustc_lint_defs", "Applicability", "MachineApplicable"], -]; -pub const DIAG: [&str; 2] = ["rustc_errors", "Diag"]; -pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"]; -pub const EARLY_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "EarlyLintPass"]; -pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"]; -pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"]; -pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"]; -pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"]; -pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"]; -pub const SYMBOL: [&str; 3] = ["rustc_span", "symbol", "Symbol"]; -pub const SYMBOL_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Symbol", "as_str"]; -pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol", "to_ident_string"]; -pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"]; -pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; +use crate::{MaybePath, path_def_id, sym}; +use rustc_ast::Mutability; +use rustc_data_structures::fx::FxHashMap; +use rustc_hir::def::Namespace::{MacroNS, TypeNS, ValueNS}; +use rustc_hir::def::{DefKind, Namespace, Res}; +use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; +use rustc_hir::{ImplItemRef, ItemKind, Node, OwnerId, TraitItemRef, UseKind}; +use rustc_lint::LateContext; +use rustc_middle::ty::fast_reject::SimplifiedType; +use rustc_middle::ty::{FloatTy, IntTy, Ty, TyCtxt, UintTy}; +use rustc_span::{Ident, STDLIB_STABLE_CRATES, Symbol}; +use std::sync::OnceLock; -// Paths in `core`/`alloc`/`std`. This should be avoided and cleaned up by adding diagnostic items. -pub const CHAR_IS_ASCII: [&str; 5] = ["core", "char", "methods", "", "is_ascii"]; -pub const IO_ERROR_NEW: [&str; 5] = ["std", "io", "error", "Error", "new"]; -pub const IO_ERRORKIND_OTHER: [&str; 5] = ["std", "io", "error", "ErrorKind", "Other"]; -pub const ALIGN_OF: [&str; 3] = ["core", "mem", "align_of"]; +/// Specifies whether to resolve a path in the [`TypeNS`], [`ValueNS`], [`MacroNS`] or in an +/// arbitrary namespace +#[derive(Clone, Copy, PartialEq, Debug)] +pub enum PathNS { + Type, + Value, + Macro, + + /// Resolves to the name in the first available namespace, e.g. for `std::vec` this would return + /// either the macro or the module but **not** both + /// + /// Must only be used when the specific resolution is unimportant such as in + /// `missing_enforced_import_renames` + Arbitrary, +} + +impl PathNS { + fn matches(self, ns: Option) -> bool { + let required = match self { + PathNS::Type => TypeNS, + PathNS::Value => ValueNS, + PathNS::Macro => MacroNS, + PathNS::Arbitrary => return true, + }; + + ns == Some(required) + } +} + +/// Lazily resolves a path into a list of [`DefId`]s using [`lookup_path`]. +/// +/// Typically it will contain one [`DefId`] or none, but in some situations there can be multiple: +/// - `memchr::memchr` could return the functions from both memchr 1.0 and memchr 2.0 +/// - `alloc::boxed::Box::downcast` would return a function for each of the different inherent impls +/// ([1], [2], [3]) +/// +/// [1]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast +/// [2]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast-1 +/// [3]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast-2 +pub struct PathLookup { + ns: PathNS, + path: &'static [Symbol], + once: OnceLock>, +} + +impl PathLookup { + /// Only exported for tests and `clippy_lints_internal` + #[doc(hidden)] + pub const fn new(ns: PathNS, path: &'static [Symbol]) -> Self { + Self { + ns, + path, + once: OnceLock::new(), + } + } + + /// Returns the list of [`DefId`]s that the path resolves to + pub fn get(&self, cx: &LateContext<'_>) -> &[DefId] { + self.once.get_or_init(|| lookup_path(cx.tcx, self.ns, self.path)) + } -// Paths in clippy itself -pub const MSRV_STACK: [&str; 3] = ["clippy_utils", "msrvs", "MsrvStack"]; -pub const CLIPPY_SYM_MODULE: [&str; 2] = ["clippy_utils", "sym"]; + /// Returns the single [`DefId`] that the path resolves to, this can only be used for paths into + /// stdlib crates to avoid the issue of multiple [`DefId`]s being returned + /// + /// May return [`None`] in `no_std`/`no_core` environments + pub fn only(&self, cx: &LateContext<'_>) -> Option { + let ids = self.get(cx); + debug_assert!(STDLIB_STABLE_CRATES.contains(&self.path[0])); + debug_assert!(ids.len() <= 1, "{ids:?}"); + ids.first().copied() + } + + /// Checks if the path resolves to the given `def_id` + pub fn matches(&self, cx: &LateContext<'_>, def_id: DefId) -> bool { + self.get(cx).contains(&def_id) + } + + /// Resolves `maybe_path` to a [`DefId`] and checks if the [`PathLookup`] matches it + pub fn matches_path<'tcx>(&self, cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>) -> bool { + path_def_id(cx, maybe_path).is_some_and(|def_id| self.matches(cx, def_id)) + } + + /// Checks if the path resolves to `ty`'s definition, must be an `Adt` + pub fn matches_ty(&self, cx: &LateContext<'_>, ty: Ty<'_>) -> bool { + ty.ty_adt_def().is_some_and(|adt| self.matches(cx, adt.did())) + } +} + +macro_rules! path_macros { + ($($name:ident: $ns:expr,)*) => { + $( + /// Only exported for tests and `clippy_lints_internal` + #[doc(hidden)] + #[macro_export] + macro_rules! $name { + ($$($$seg:ident $$(::)?)*) => { + PathLookup::new($ns, &[$$(sym::$$seg,)*]) + }; + } + )* + }; +} + +path_macros! { + type_path: PathNS::Type, + value_path: PathNS::Value, + macro_path: PathNS::Macro, +} + +// Paths in `core`/`alloc`/`std`. This should be avoided and cleaned up by adding diagnostic items. +pub static ALIGN_OF: PathLookup = value_path!(core::mem::align_of); +pub static CHAR_TO_DIGIT: PathLookup = value_path!(char::to_digit); +pub static IO_ERROR_NEW: PathLookup = value_path!(std::io::Error::new); +pub static IO_ERRORKIND_OTHER_CTOR: PathLookup = value_path!(std::io::ErrorKind::Other); +pub static ITER_STEP: PathLookup = type_path!(core::iter::Step); +pub static SLICE_FROM_REF: PathLookup = value_path!(core::slice::from_ref); // Paths in external crates -#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates -pub const FUTURES_IO_ASYNCREADEXT: [&str; 3] = ["futures_util", "io", "AsyncReadExt"]; -#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates -pub const FUTURES_IO_ASYNCWRITEEXT: [&str; 3] = ["futures_util", "io", "AsyncWriteExt"]; -pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"]; -pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"]; -pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockReadGuard"]; -pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockWriteGuard"]; -pub const REGEX_BUILDER_NEW: [&str; 3] = ["regex", "RegexBuilder", "new"]; -pub const REGEX_BYTES_BUILDER_NEW: [&str; 4] = ["regex", "bytes", "RegexBuilder", "new"]; -pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "bytes", "Regex", "new"]; -pub const REGEX_BYTES_SET_NEW: [&str; 4] = ["regex", "bytes", "RegexSet", "new"]; -pub const REGEX_NEW: [&str; 3] = ["regex", "Regex", "new"]; -pub const REGEX_SET_NEW: [&str; 3] = ["regex", "RegexSet", "new"]; -pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"]; -pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"]; -#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates -pub const TOKIO_FILE_OPTIONS: [&str; 5] = ["tokio", "fs", "file", "File", "options"]; -#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates -pub const TOKIO_IO_ASYNCREADEXT: [&str; 5] = ["tokio", "io", "util", "async_read_ext", "AsyncReadExt"]; -#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates -pub const TOKIO_IO_ASYNCWRITEEXT: [&str; 5] = ["tokio", "io", "util", "async_write_ext", "AsyncWriteExt"]; -#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates -pub const TOKIO_IO_OPEN_OPTIONS: [&str; 4] = ["tokio", "fs", "open_options", "OpenOptions"]; -#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates -pub const TOKIO_IO_OPEN_OPTIONS_NEW: [&str; 5] = ["tokio", "fs", "open_options", "OpenOptions", "new"]; +pub static FUTURES_IO_ASYNCREADEXT: PathLookup = type_path!(futures_util::AsyncReadExt); +pub static FUTURES_IO_ASYNCWRITEEXT: PathLookup = type_path!(futures_util::AsyncWriteExt); +pub static ITERTOOLS_NEXT_TUPLE: PathLookup = value_path!(itertools::Itertools::next_tuple); +pub static PARKING_LOT_GUARDS: [PathLookup; 3] = [ + type_path!(lock_api::mutex::MutexGuard), + type_path!(lock_api::rwlock::RwLockReadGuard), + type_path!(lock_api::rwlock::RwLockWriteGuard), +]; +pub static REGEX_BUILDER_NEW: PathLookup = value_path!(regex::RegexBuilder::new); +pub static REGEX_BYTES_BUILDER_NEW: PathLookup = value_path!(regex::bytes::RegexBuilder::new); +pub static REGEX_BYTES_NEW: PathLookup = value_path!(regex::bytes::Regex::new); +pub static REGEX_BYTES_SET_NEW: PathLookup = value_path!(regex::bytes::RegexSet::new); +pub static REGEX_NEW: PathLookup = value_path!(regex::Regex::new); +pub static REGEX_SET_NEW: PathLookup = value_path!(regex::RegexSet::new); +pub static SERDE_DESERIALIZE: PathLookup = type_path!(serde::de::Deserialize); +pub static SERDE_DE_VISITOR: PathLookup = type_path!(serde::de::Visitor); +pub static TOKIO_FILE_OPTIONS: PathLookup = value_path!(tokio::fs::File::options); +pub static TOKIO_IO_ASYNCREADEXT: PathLookup = type_path!(tokio::io::AsyncReadExt); +pub static TOKIO_IO_ASYNCWRITEEXT: PathLookup = type_path!(tokio::io::AsyncWriteExt); +pub static TOKIO_IO_OPEN_OPTIONS: PathLookup = type_path!(tokio::fs::OpenOptions); +pub static TOKIO_IO_OPEN_OPTIONS_NEW: PathLookup = value_path!(tokio::fs::OpenOptions::new); +pub static LAZY_STATIC: PathLookup = macro_path!(lazy_static::lazy_static); +pub static ONCE_CELL_SYNC_LAZY: PathLookup = type_path!(once_cell::sync::Lazy); +pub static ONCE_CELL_SYNC_LAZY_NEW: PathLookup = value_path!(once_cell::sync::Lazy::new); + +// Paths for internal lints go in `clippy_lints_internal/src/internal_paths.rs` + +/// Equivalent to a [`lookup_path`] after splitting the input string on `::` +/// +/// This function is expensive and should be used sparingly. +pub fn lookup_path_str(tcx: TyCtxt<'_>, ns: PathNS, path: &str) -> Vec { + let path: Vec = path.split("::").map(Symbol::intern).collect(); + lookup_path(tcx, ns, &path) +} + +/// Resolves a def path like `std::vec::Vec`. +/// +/// Typically it will return one [`DefId`] or none, but in some situations there can be multiple: +/// - `memchr::memchr` could return the functions from both memchr 1.0 and memchr 2.0 +/// - `alloc::boxed::Box::downcast` would return a function for each of the different inherent impls +/// ([1], [2], [3]) +/// +/// This function is expensive and should be used sparingly. +/// +/// [1]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast +/// [2]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast-1 +/// [3]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast-2 +pub fn lookup_path(tcx: TyCtxt<'_>, ns: PathNS, path: &[Symbol]) -> Vec { + let (root, rest) = match *path { + [] | [_] => return Vec::new(), + [root, ref rest @ ..] => (root, rest), + }; + + let mut out = Vec::new(); + for &base in find_crates(tcx, root).iter().chain(find_primitive_impls(tcx, root)) { + lookup_with_base(tcx, base, ns, rest, &mut out); + } + out +} + +/// Finds the crates called `name`, may be multiple due to multiple major versions. +pub fn find_crates(tcx: TyCtxt<'_>, name: Symbol) -> &'static [DefId] { + static BY_NAME: OnceLock>> = OnceLock::new(); + let map = BY_NAME.get_or_init(|| { + let mut map = FxHashMap::default(); + map.insert(tcx.crate_name(LOCAL_CRATE), vec![LOCAL_CRATE.as_def_id()]); + for &num in tcx.crates(()) { + map.entry(tcx.crate_name(num)).or_default().push(num.as_def_id()); + } + map + }); + match map.get(&name) { + Some(def_ids) => def_ids, + None => &[], + } +} + +fn find_primitive_impls(tcx: TyCtxt<'_>, name: Symbol) -> &[DefId] { + let ty = match name { + sym::bool => SimplifiedType::Bool, + sym::char => SimplifiedType::Char, + sym::str => SimplifiedType::Str, + sym::array => SimplifiedType::Array, + sym::slice => SimplifiedType::Slice, + // FIXME: rustdoc documents these two using just `pointer`. + // + // Maybe this is something we should do here too. + sym::const_ptr => SimplifiedType::Ptr(Mutability::Not), + sym::mut_ptr => SimplifiedType::Ptr(Mutability::Mut), + sym::isize => SimplifiedType::Int(IntTy::Isize), + sym::i8 => SimplifiedType::Int(IntTy::I8), + sym::i16 => SimplifiedType::Int(IntTy::I16), + sym::i32 => SimplifiedType::Int(IntTy::I32), + sym::i64 => SimplifiedType::Int(IntTy::I64), + sym::i128 => SimplifiedType::Int(IntTy::I128), + sym::usize => SimplifiedType::Uint(UintTy::Usize), + sym::u8 => SimplifiedType::Uint(UintTy::U8), + sym::u16 => SimplifiedType::Uint(UintTy::U16), + sym::u32 => SimplifiedType::Uint(UintTy::U32), + sym::u64 => SimplifiedType::Uint(UintTy::U64), + sym::u128 => SimplifiedType::Uint(UintTy::U128), + sym::f32 => SimplifiedType::Float(FloatTy::F32), + sym::f64 => SimplifiedType::Float(FloatTy::F64), + _ => return &[], + }; + + tcx.incoherent_impls(ty) +} + +/// Resolves a def path like `vec::Vec` with the base `std`. +fn lookup_with_base(tcx: TyCtxt<'_>, mut base: DefId, ns: PathNS, mut path: &[Symbol], out: &mut Vec) { + loop { + match *path { + [segment] => { + out.extend(item_child_by_name(tcx, base, ns, segment)); + + // When the current def_id is e.g. `struct S`, check the impl items in + // `impl S { ... }` + let inherent_impl_children = tcx + .inherent_impls(base) + .iter() + .filter_map(|&impl_def_id| item_child_by_name(tcx, impl_def_id, ns, segment)); + out.extend(inherent_impl_children); + + return; + }, + [segment, ref rest @ ..] => { + path = rest; + let Some(child) = item_child_by_name(tcx, base, PathNS::Type, segment) else { + return; + }; + base = child; + }, + [] => unreachable!(), + } + } +} + +fn item_child_by_name(tcx: TyCtxt<'_>, def_id: DefId, ns: PathNS, name: Symbol) -> Option { + if let Some(local_id) = def_id.as_local() { + local_item_child_by_name(tcx, local_id, ns, name) + } else { + non_local_item_child_by_name(tcx, def_id, ns, name) + } +} + +fn local_item_child_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, ns: PathNS, name: Symbol) -> Option { + let root_mod; + let item_kind = match tcx.hir_node_by_def_id(local_id) { + Node::Crate(r#mod) => { + root_mod = ItemKind::Mod(Ident::dummy(), r#mod); + &root_mod + }, + Node::Item(item) => &item.kind, + _ => return None, + }; + + let res = |ident: Ident, owner_id: OwnerId| { + if ident.name == name && ns.matches(tcx.def_kind(owner_id).ns()) { + Some(owner_id.to_def_id()) + } else { + None + } + }; + + match item_kind { + ItemKind::Mod(_, r#mod) => r#mod.item_ids.iter().find_map(|&item_id| { + let item = tcx.hir_item(item_id); + if let ItemKind::Use(path, UseKind::Single(ident)) = item.kind { + if ident.name == name { + path.res + .iter() + .find(|res| ns.matches(res.ns())) + .and_then(Res::opt_def_id) + } else { + None + } + } else { + res(item.kind.ident()?, item_id.owner_id) + } + }), + ItemKind::Impl(r#impl) => r#impl + .items + .iter() + .find_map(|&ImplItemRef { ident, id, .. }| res(ident, id.owner_id)), + ItemKind::Trait(.., trait_item_refs) => trait_item_refs + .iter() + .find_map(|&TraitItemRef { ident, id, .. }| res(ident, id.owner_id)), + _ => None, + } +} + +fn non_local_item_child_by_name(tcx: TyCtxt<'_>, def_id: DefId, ns: PathNS, name: Symbol) -> Option { + match tcx.def_kind(def_id) { + DefKind::Mod | DefKind::Enum | DefKind::Trait => tcx.module_children(def_id).iter().find_map(|child| { + if child.ident.name == name && ns.matches(child.res.ns()) { + child.res.opt_def_id() + } else { + None + } + }), + DefKind::Impl { .. } => tcx + .associated_item_def_ids(def_id) + .iter() + .copied() + .find(|assoc_def_id| tcx.item_name(*assoc_def_id) == name && ns.matches(tcx.def_kind(assoc_def_id).ns())), + _ => None, + } +} diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index 38f077134c033..9428262b99aa7 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -1,6 +1,6 @@ #![allow(non_upper_case_globals)] -use rustc_span::symbol::{PREDEFINED_SYMBOLS_COUNT, Symbol}; +use rustc_span::symbol::PREDEFINED_SYMBOLS_COUNT; #[doc(no_inline)] pub use rustc_span::sym::*; @@ -24,90 +24,177 @@ macro_rules! generate { ]; $( - pub const $name: Symbol = Symbol::new(PREDEFINED_SYMBOLS_COUNT + ${index()}); + pub const $name: rustc_span::Symbol = rustc_span::Symbol::new(PREDEFINED_SYMBOLS_COUNT + ${index()}); )* }; } generate! { abs, + align_of, + ambiguous_glob_reexports, as_bytes, as_deref_mut, as_deref, as_mut, + AsyncReadExt, + AsyncWriteExt, + BACKSLASH_SINGLE_QUOTE: r"\'", Binary, build_hasher, + bytes, cargo_clippy: "cargo-clippy", Cargo_toml: "Cargo.toml", cast, chars, CLIPPY_ARGS, CLIPPY_CONF_DIR, + clippy_utils, clone_into, cloned, collect, + const_ptr, contains, copied, CRLF: "\r\n", Current, + de, + Deserialize, + diagnostics, + disallowed_types, + DOUBLE_QUOTE: "\"", + EarlyLintPass, ends_with, + enum_glob_use, + error, + ErrorKind, exp, extend, finish_non_exhaustive, finish, flat_map, for_each, + from_bytes_with_nul_unchecked, + from_bytes_with_nul, + from_ptr, from_raw, + from_ref, from_str_radix, + fs, + futures_util, get, + hidden_glob_reexports, + hygiene, insert, int_roundings, into_bytes, into_owned, IntoIter, + io, is_ascii, is_empty, is_err, is_none, is_ok, is_some, + itertools, + Itertools, + kw, last, + lazy_static, + Lazy, LF: "\n", + Lint, + ln, + lock_api, + log, LowerExp, LowerHex, + macro_use_imports, + map_or_else, + map_or, max, + MAX, + mem, min, + MIN, mode, + module_name_repetitions, msrv, + msrvs, + MsrvStack, + mut_ptr, + mutex, + needless_return, + next_tuple, Octal, + once_cell, + OpenOptions, or_default, + Other, parse, + PathLookup, + paths, + powf, + powi, push, + redundant_pub_crate, regex, + Regex, + RegexBuilder, + RegexSet, reserve, resize, restriction, + rustc_lint_defs, + rustc_lint, + rustc_span, rustfmt_skip, + rwlock, + serde, set_len, set_mode, set_readonly, signum, + single_component_path_imports, + span_lint_and_then, split_whitespace, split, + sqrt, Start, + Step, + style, + symbol, + Symbol, + SyntaxContext, take, TBD, then_some, + to_ascii_lowercase, + to_ascii_uppercase, to_digit, + to_lowercase, to_owned, + to_uppercase, + tokio, + unreachable_pub, + unsafe_removed_from_name, + unused_braces, unused_extern_crates, + unused_import_braces, + unused_trait_names, + unused, unwrap_err, unwrap_or_default, + unwrap_or_else, UpperExp, UpperHex, V4, V6, + Visitor, + warnings, Weak, + wildcard_imports, with_capacity, wrapping_offset, } diff --git a/clippy_utils/src/ty/mod.rs b/clippy_utils/src/ty/mod.rs index da09edd7f7c03..26d41cfb4977b 100644 --- a/clippy_utils/src/ty/mod.rs +++ b/clippy_utils/src/ty/mod.rs @@ -20,7 +20,7 @@ use rustc_middle::traits::EvaluationResult; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef, - GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, + GenericParamDefKind, IntTy, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, }; use rustc_span::symbol::Ident; @@ -32,7 +32,8 @@ use std::assert_matches::debug_assert_matches; use std::collections::hash_map::Entry; use std::iter; -use crate::{def_path_def_ids, match_def_path, path_res}; +use crate::path_res; +use crate::paths::{PathNS, lookup_path_str}; mod type_certainty; pub use type_certainty::expr_type_is_certain; @@ -229,9 +230,7 @@ pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option< /// Checks whether a type implements a trait. /// The function returns false in case the type contains an inference variable. /// -/// See: -/// * [`get_trait_def_id`](super::get_trait_def_id) to get a trait [`DefId`]. -/// * [Common tools for writing lints] for an example how to use this function and other options. +/// See [Common tools for writing lints] for an example how to use this function and other options. /// /// [Common tools for writing lints]: https://github.com/rust-lang/rust-clippy/blob/master/book/src/development/common_tools_writing_lints.md#checking-if-a-type-implements-a-specific-trait pub fn implements_trait<'tcx>( @@ -359,56 +358,6 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { } } -// FIXME: Per https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/infer/at/struct.At.html#method.normalize -// this function can be removed once the `normalize` method does not panic when normalization does -// not succeed -/// Checks if `Ty` is normalizable. This function is useful -/// to avoid crashes on `layout_of`. -pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { - is_normalizable_helper(cx, param_env, ty, 0, &mut FxHashMap::default()) -} - -fn is_normalizable_helper<'tcx>( - cx: &LateContext<'tcx>, - param_env: ParamEnv<'tcx>, - ty: Ty<'tcx>, - depth: usize, - cache: &mut FxHashMap, bool>, -) -> bool { - if let Some(&cached_result) = cache.get(&ty) { - return cached_result; - } - if !cx.tcx.recursion_limit().value_within_limit(depth) { - return false; - } - // Prevent recursive loops by answering `true` to recursive requests with the same - // type. This will be adjusted when the outermost call analyzes all the type - // components. - cache.insert(ty, true); - let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); - let cause = ObligationCause::dummy(); - let result = if infcx.at(&cause, param_env).query_normalize(ty).is_ok() { - match ty.kind() { - ty::Adt(def, args) => def.variants().iter().all(|variant| { - variant - .fields - .iter() - .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, args), depth + 1, cache)) - }), - _ => ty.walk().all(|generic_arg| match generic_arg.unpack() { - GenericArgKind::Type(inner_ty) if inner_ty != ty => { - is_normalizable_helper(cx, param_env, inner_ty, depth + 1, cache) - }, - _ => true, // if inner_ty == ty, we've already checked it - }), - } - } else { - false - }; - cache.insert(ty, result); - result -} - /// Returns `true` if the given type is a non aggregate primitive (a `bool` or `char`, any /// integer or floating-point number type). /// @@ -474,17 +423,6 @@ pub fn is_isize_or_usize(typ: Ty<'_>) -> bool { matches!(typ.kind(), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize)) } -/// Checks if type is struct, enum or union type with the given def path. -/// -/// If the type is a diagnostic item, use `is_type_diagnostic_item` instead. -/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem` -pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool { - match ty.kind() { - ty::Adt(adt, _) => match_def_path(cx, adt.did(), path), - _ => false, - } -} - /// Checks if the drop order for a type matters. /// /// Some std types implement drop solely to deallocate memory. For these types, and composites @@ -993,9 +931,6 @@ pub fn adt_and_variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option< /// account the layout of type parameters. pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 { use rustc_middle::ty::layout::LayoutOf; - if !is_normalizable(cx, cx.param_env, ty) { - return 0; - } match (cx.layout_of(ty).map(|layout| layout.size.bytes()), ty.kind()) { (Ok(size), _) => size, (Err(_), ty::Tuple(list)) => list.iter().map(|t| approx_ty_size(cx, t)).sum(), @@ -1184,10 +1119,7 @@ impl<'tcx> InteriorMut<'tcx> { pub fn new(tcx: TyCtxt<'tcx>, ignore_interior_mutability: &[String]) -> Self { let ignored_def_ids = ignore_interior_mutability .iter() - .flat_map(|ignored_ty| { - let path: Vec<&str> = ignored_ty.split("::").collect(); - def_path_def_ids(tcx, path.as_slice()) - }) + .flat_map(|ignored_ty| lookup_path_str(tcx, PathNS::Type, ignored_ty)) .collect(); Self { @@ -1422,3 +1354,10 @@ pub fn has_non_owning_mutable_access<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<' let mut phantoms = FxHashSet::default(); has_non_owning_mutable_access_inner(cx, &mut phantoms, iter_ty) } + +/// Check if `ty` is slice-like, i.e., `&[T]`, `[T; N]`, or `Vec`. +pub fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + ty.is_slice() + || ty.is_array() + || matches!(ty.kind(), ty::Adt(adt_def, _) if cx.tcx.is_diagnostic_item(sym::Vec, adt_def.did())) +} diff --git a/clippy_utils/src/ty/type_certainty/mod.rs b/clippy_utils/src/ty/type_certainty/mod.rs index 3398ff8af2f5a..6e3586623277f 100644 --- a/clippy_utils/src/ty/type_certainty/mod.rs +++ b/clippy_utils/src/ty/type_certainty/mod.rs @@ -11,14 +11,14 @@ //! As a heuristic, `expr_type_is_certain` may produce false negatives, but a false positive should //! be considered a bug. -use crate::def_path_res; +use crate::paths::{PathNS, lookup_path}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_qpath, walk_ty}; use rustc_hir::{self as hir, AmbigArg, Expr, ExprKind, GenericArgs, HirId, Node, PathSegment, QPath, TyKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, AdtDef, GenericArgKind, Ty}; -use rustc_span::{Span, Symbol}; +use rustc_span::Span; mod certainty; use certainty::{Certainty, Meet, join, meet}; @@ -194,7 +194,7 @@ fn path_segment_certainty( path_segment: &PathSegment<'_>, resolves_to_type: bool, ) -> Certainty { - let certainty = match update_res(cx, parent_certainty, path_segment).unwrap_or(path_segment.res) { + let certainty = match update_res(cx, parent_certainty, path_segment, resolves_to_type).unwrap_or(path_segment.res) { // A definition's type is certain if it refers to something without generics (e.g., a crate or module, or // an unparameterized type), or the generics are instantiated with arguments that are certain. // @@ -267,17 +267,24 @@ fn path_segment_certainty( /// For at least some `QPath::TypeRelative`, the path segment's `res` can be `Res::Err`. /// `update_res` tries to fix the resolution when `parent_certainty` is `Certain(Some(..))`. -fn update_res(cx: &LateContext<'_>, parent_certainty: Certainty, path_segment: &PathSegment<'_>) -> Option { +fn update_res( + cx: &LateContext<'_>, + parent_certainty: Certainty, + path_segment: &PathSegment<'_>, + resolves_to_type: bool, +) -> Option { if path_segment.res == Res::Err && let Some(def_id) = parent_certainty.to_def_id() { let mut def_path = cx.get_def_path(def_id); def_path.push(path_segment.ident.name); - let reses = def_path_res(cx.tcx, &def_path.iter().map(Symbol::as_str).collect::>()); - if let [res] = reses.as_slice() { Some(*res) } else { None } - } else { - None + let ns = if resolves_to_type { PathNS::Type } else { PathNS::Value }; + if let &[id] = lookup_path(cx.tcx, ns, &def_path).as_slice() { + return Some(Res::Def(cx.tcx.def_kind(id), id)); + } } + + None } #[allow(clippy::cast_possible_truncation)] diff --git a/lintcheck/src/main.rs b/lintcheck/src/main.rs index fe488ef89da1f..d4bf6cd48a152 100644 --- a/lintcheck/src/main.rs +++ b/lintcheck/src/main.rs @@ -6,7 +6,6 @@ // positives. #![feature(iter_collect_into)] -#![feature(let_chains)] #![warn( trivial_casts, trivial_numeric_casts, diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 39c7f0e4ad5a5..da41bdd27bcb6 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2025-05-01" +channel = "nightly-2025-05-14" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/src/driver.rs b/src/driver.rs index 87ca9c5beddfb..f8acf88cf81c6 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -1,7 +1,6 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] #![feature(rustc_private)] -#![feature(let_chains)] // warn on lints, that are included in `rust-lang/rust`s bootstrap #![warn(rust_2018_idioms, unused_lifetimes)] // warn on rustc internal lints diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 6d391bd622a8d..78b27e2f61399 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private, let_chains)] +#![feature(rustc_private)] #![warn(rust_2018_idioms, unused_lifetimes)] #![allow(unused_extern_crates)] diff --git a/tests/dogfood.rs b/tests/dogfood.rs index 16a1a415102c4..4ac2bd532851e 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -44,8 +44,8 @@ fn dogfood() { "rustc_tools_util", ] { println!("linting {package}"); - if !run_clippy_for_package(package, &["-D", "clippy::all", "-D", "clippy::pedantic"]) { - failed_packages.push(if package.is_empty() { "root" } else { package }); + if !run_clippy_for_package(package) { + failed_packages.push(package); } } @@ -57,7 +57,7 @@ fn dogfood() { } #[must_use] -fn run_clippy_for_package(project: &str, args: &[&str]) -> bool { +fn run_clippy_for_package(project: &str) -> bool { let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); let mut command = Command::new(&*test_utils::CARGO_CLIPPY_PATH); @@ -79,15 +79,17 @@ fn run_clippy_for_package(project: &str, args: &[&str]) -> bool { } } - command.arg("--").args(args); + command.arg("--"); command.arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir - command.args(["-D", "clippy::dbg_macro"]); - + command.args(["-D", "clippy::all", "-D", "clippy::pedantic", "-D", "clippy::dbg_macro"]); if !cfg!(feature = "internal") { // running a clippy built without internal lints on the clippy source - // that contains e.g. `allow(clippy::invalid_paths)` + // that contains e.g. `allow(clippy::symbol_as_str)` command.args(["-A", "unknown_lints"]); } + // Workaround for not being a workspace, add the crate's directory back to the path + command.args(["--remap-path-prefix", &format!("={project}")]); + command.status().unwrap().success() } diff --git a/tests/integration.rs b/tests/integration.rs index 13cf36823c5e4..cb7d61eee24ad 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -30,7 +30,7 @@ fn integration_test() { let repo_dir = tempfile::tempdir() .expect("couldn't create temp dir") - .into_path() + .keep() .join(crate_name); let st = Command::new("git") diff --git a/tests/ui-internal/auxiliary/paths.rs b/tests/ui-internal/auxiliary/paths.rs deleted file mode 100644 index f730f564a09cf..0000000000000 --- a/tests/ui-internal/auxiliary/paths.rs +++ /dev/null @@ -1,4 +0,0 @@ -#![allow(clippy::unnecessary_def_path)] - -pub static OPTION: [&str; 3] = ["core", "option", "Option"]; -pub const RESULT: &[&str] = &["core", "result", "Result"]; diff --git a/tests/ui-internal/derive_deserialize_allowing_unknown.rs b/tests/ui-internal/derive_deserialize_allowing_unknown.rs new file mode 100644 index 0000000000000..9dc8e9e8f4c16 --- /dev/null +++ b/tests/ui-internal/derive_deserialize_allowing_unknown.rs @@ -0,0 +1,60 @@ +#![deny(clippy::derive_deserialize_allowing_unknown)] + +use serde::{Deserialize, Deserializer}; + +#[derive(Deserialize)] //~ derive_deserialize_allowing_unknown +struct Struct { + flag: bool, + limit: u64, +} + +#[derive(Deserialize)] //~ derive_deserialize_allowing_unknown +enum Enum { + A(bool), + B { limit: u64 }, +} + +// negative tests + +#[derive(Deserialize)] +#[serde(deny_unknown_fields)] +struct StructWithDenyUnknownFields { + flag: bool, + limit: u64, +} + +#[derive(Deserialize)] +#[serde(deny_unknown_fields)] +enum EnumWithDenyUnknownFields { + A(bool), + B { limit: u64 }, +} + +#[derive(Deserialize)] +#[serde(untagged, deny_unknown_fields)] +enum MultipleSerdeAttributes { + A(bool), + B { limit: u64 }, +} + +#[derive(Deserialize)] +struct TupleStruct(u64, bool); + +#[derive(Deserialize)] +#[serde(deny_unknown_fields)] +enum EnumWithOnlyTupleVariants { + A(bool), + B(u64), +} + +struct ManualSerdeImplementation; + +impl<'de> Deserialize<'de> for ManualSerdeImplementation { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let () = <() as Deserialize>::deserialize(deserializer)?; + Ok(ManualSerdeImplementation) + } +} diff --git a/tests/ui-internal/derive_deserialize_allowing_unknown.stderr b/tests/ui-internal/derive_deserialize_allowing_unknown.stderr new file mode 100644 index 0000000000000..93d64826c9935 --- /dev/null +++ b/tests/ui-internal/derive_deserialize_allowing_unknown.stderr @@ -0,0 +1,23 @@ +error: `#[derive(serde::Deserialize)]` without `#[serde(deny_unknown_fields)]` + --> tests/ui-internal/derive_deserialize_allowing_unknown.rs:5:10 + | +LL | #[derive(Deserialize)] + | ^^^^^^^^^^^ + | +note: the lint level is defined here + --> tests/ui-internal/derive_deserialize_allowing_unknown.rs:1:9 + | +LL | #![deny(clippy::derive_deserialize_allowing_unknown)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `#[derive(serde::Deserialize)]` without `#[serde(deny_unknown_fields)]` + --> tests/ui-internal/derive_deserialize_allowing_unknown.rs:11:10 + | +LL | #[derive(Deserialize)] + | ^^^^^^^^^^^ + | + = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + diff --git a/tests/ui-internal/interning_literals.stderr b/tests/ui-internal/interning_literals.stderr index 628b97eff84da..9ff4194e542bb 100644 --- a/tests/ui-internal/interning_literals.stderr +++ b/tests/ui-internal/interning_literals.stderr @@ -4,9 +4,10 @@ error: interning a string literal LL | let _ = Symbol::intern("f32"); | ^^^^^^^^^^^^^^^^^^^^^ | + = help: add the symbol to `clippy_utils/src/sym.rs` if needed = note: `-D clippy::interning-literals` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::interning_literals)]` -help: use the preinterned symbol +help: use a preinterned symbol instead | LL - let _ = Symbol::intern("f32"); LL + let _ = sym::f32; @@ -18,7 +19,8 @@ error: interning a string literal LL | let _ = Symbol::intern("proc-macro"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use the preinterned symbol + = help: add the symbol to `clippy_utils/src/sym.rs` if needed +help: use a preinterned symbol instead | LL - let _ = Symbol::intern("proc-macro"); LL + let _ = sym::proc_dash_macro; @@ -30,7 +32,8 @@ error: interning a string literal LL | let _ = Symbol::intern("self"); | ^^^^^^^^^^^^^^^^^^^^^^ | -help: use the preinterned symbol + = help: add the symbol to `clippy_utils/src/sym.rs` if needed +help: use a preinterned symbol instead | LL - let _ = Symbol::intern("self"); LL + let _ = kw::SelfLower; @@ -42,7 +45,8 @@ error: interning a string literal LL | let _ = Symbol::intern("msrv"); | ^^^^^^^^^^^^^^^^^^^^^^ | -help: use the preinterned symbol + = help: add the symbol to `clippy_utils/src/sym.rs` if needed +help: use a preinterned symbol instead | LL - let _ = Symbol::intern("msrv"); LL + let _ = sym::msrv; @@ -54,7 +58,8 @@ error: interning a string literal LL | let _ = Symbol::intern("Cargo.toml"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use the preinterned symbol + = help: add the symbol to `clippy_utils/src/sym.rs` if needed +help: use a preinterned symbol instead | LL - let _ = Symbol::intern("Cargo.toml"); LL + let _ = sym::Cargo_toml; diff --git a/tests/ui-internal/interning_literals_unfixable.stderr b/tests/ui-internal/interning_literals_unfixable.stderr index 8294453a8f945..879d9e633c23d 100644 --- a/tests/ui-internal/interning_literals_unfixable.stderr +++ b/tests/ui-internal/interning_literals_unfixable.stderr @@ -4,9 +4,10 @@ error: interning a string literal LL | let _ = Symbol::intern("xyz123"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: add the symbol to `clippy_utils/src/sym.rs` if needed = note: `-D clippy::interning-literals` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::interning_literals)]` -help: add the symbol to `clippy_utils/src/sym.rs` and use it +help: use a preinterned symbol instead | LL - let _ = Symbol::intern("xyz123"); LL + let _ = sym::xyz123; @@ -18,7 +19,8 @@ error: interning a string literal LL | let _ = Symbol::intern("with-dash"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: add the symbol to `clippy_utils/src/sym.rs` and use it + = help: add the symbol to `clippy_utils/src/sym.rs` if needed +help: use a preinterned symbol instead | LL - let _ = Symbol::intern("with-dash"); LL + let _ = sym::with_dash; @@ -30,7 +32,8 @@ error: interning a string literal LL | let _ = Symbol::intern("with.dot"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: add the symbol to `clippy_utils/src/sym.rs` and use it + = help: add the symbol to `clippy_utils/src/sym.rs` if needed +help: use a preinterned symbol instead | LL - let _ = Symbol::intern("with.dot"); LL + let _ = sym::with_dot; diff --git a/tests/ui-internal/invalid_paths.rs b/tests/ui-internal/invalid_paths.rs deleted file mode 100644 index 7317abc2185a3..0000000000000 --- a/tests/ui-internal/invalid_paths.rs +++ /dev/null @@ -1,30 +0,0 @@ -#![deny(clippy::invalid_paths)] -#![allow(clippy::missing_clippy_version_attribute, clippy::unnecessary_def_path)] - -mod paths { - // Good path - pub const ANY_TRAIT: [&str; 3] = ["std", "any", "Any"]; - - // Path to method on inherent impl of a primitive type - pub const F32_EPSILON: [&str; 4] = ["core", "f32", "", "EPSILON"]; - - // Path to method on inherent impl - pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"]; - - // Path with empty segment - pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"]; - //~^ invalid_paths - - // Path with bad crate - pub const BAD_CRATE_PATH: [&str; 2] = ["bad", "path"]; - //~^ invalid_paths - - // Path with bad module - pub const BAD_MOD_PATH: [&str; 2] = ["std", "xxx"]; - //~^ invalid_paths - - // Path to method on an enum inherent impl - pub const OPTION_IS_SOME: [&str; 4] = ["core", "option", "Option", "is_some"]; -} - -fn main() {} diff --git a/tests/ui-internal/invalid_paths.stderr b/tests/ui-internal/invalid_paths.stderr deleted file mode 100644 index 7b7b25ce8d8db..0000000000000 --- a/tests/ui-internal/invalid_paths.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error: invalid path - --> tests/ui-internal/invalid_paths.rs:15:5 - | -LL | pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> tests/ui-internal/invalid_paths.rs:1:9 - | -LL | #![deny(clippy::invalid_paths)] - | ^^^^^^^^^^^^^^^^^^^^^ - -error: invalid path - --> tests/ui-internal/invalid_paths.rs:19:5 - | -LL | pub const BAD_CRATE_PATH: [&str; 2] = ["bad", "path"]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: invalid path - --> tests/ui-internal/invalid_paths.rs:23:5 - | -LL | pub const BAD_MOD_PATH: [&str; 2] = ["std", "xxx"]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors - diff --git a/tests/ui-internal/symbol_as_str.fixed b/tests/ui-internal/symbol_as_str.fixed index 3e26732836ca8..6a71b16c60494 100644 --- a/tests/ui-internal/symbol_as_str.fixed +++ b/tests/ui-internal/symbol_as_str.fixed @@ -18,4 +18,11 @@ fn f(s: Symbol) { //~^ symbol_as_str sym::get == s; //~^ symbol_as_str + + let _ = match s { + //~^ symbol_as_str + sym::unwrap_err => 1, + sym::unwrap_or_default | sym::unwrap_or_else => 2, + _ => 3, + }; } diff --git a/tests/ui-internal/symbol_as_str.rs b/tests/ui-internal/symbol_as_str.rs index 334c32d189837..43136504bf1af 100644 --- a/tests/ui-internal/symbol_as_str.rs +++ b/tests/ui-internal/symbol_as_str.rs @@ -18,4 +18,11 @@ fn f(s: Symbol) { //~^ symbol_as_str "get" == s.as_str(); //~^ symbol_as_str + + let _ = match s.as_str() { + //~^ symbol_as_str + "unwrap_err" => 1, + "unwrap_or_default" | "unwrap_or_else" => 2, + _ => 3, + }; } diff --git a/tests/ui-internal/symbol_as_str.stderr b/tests/ui-internal/symbol_as_str.stderr index 39f81f3833c49..3eeead4aa8c14 100644 --- a/tests/ui-internal/symbol_as_str.stderr +++ b/tests/ui-internal/symbol_as_str.stderr @@ -4,9 +4,10 @@ error: converting a Symbol to a string LL | s.as_str() == "f32"; | ^^^^^^^^^^ | + = help: add the symbols to `clippy_utils/src/sym.rs` if needed = note: `-D clippy::symbol-as-str` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::symbol_as_str)]` -help: use the preinterned symbol +help: use preinterned symbols instead | LL - s.as_str() == "f32"; LL + s == sym::f32; @@ -18,7 +19,8 @@ error: converting a Symbol to a string LL | s.as_str() == "proc-macro"; | ^^^^^^^^^^ | -help: use the preinterned symbol + = help: add the symbols to `clippy_utils/src/sym.rs` if needed +help: use preinterned symbols instead | LL - s.as_str() == "proc-macro"; LL + s == sym::proc_dash_macro; @@ -30,7 +32,8 @@ error: converting a Symbol to a string LL | s.as_str() == "self"; | ^^^^^^^^^^ | -help: use the preinterned symbol + = help: add the symbols to `clippy_utils/src/sym.rs` if needed +help: use preinterned symbols instead | LL - s.as_str() == "self"; LL + s == kw::SelfLower; @@ -42,7 +45,8 @@ error: converting a Symbol to a string LL | s.as_str() == "msrv"; | ^^^^^^^^^^ | -help: use the preinterned symbol + = help: add the symbols to `clippy_utils/src/sym.rs` if needed +help: use preinterned symbols instead | LL - s.as_str() == "msrv"; LL + s == sym::msrv; @@ -54,7 +58,8 @@ error: converting a Symbol to a string LL | s.as_str() == "Cargo.toml"; | ^^^^^^^^^^ | -help: use the preinterned symbol + = help: add the symbols to `clippy_utils/src/sym.rs` if needed +help: use preinterned symbols instead | LL - s.as_str() == "Cargo.toml"; LL + s == sym::Cargo_toml; @@ -66,11 +71,27 @@ error: converting a Symbol to a string LL | "get" == s.as_str(); | ^^^^^^^^^^ | -help: use the preinterned symbol + = help: add the symbols to `clippy_utils/src/sym.rs` if needed +help: use preinterned symbols instead | LL - "get" == s.as_str(); LL + sym::get == s; | -error: aborting due to 6 previous errors +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str.rs:22:19 + | +LL | let _ = match s.as_str() { + | ^^^^^^^^^^ + | + = help: add the symbols to `clippy_utils/src/sym.rs` if needed +help: use preinterned symbols instead + | +LL ~ let _ = match s { +LL | +LL ~ sym::unwrap_err => 1, +LL ~ sym::unwrap_or_default | sym::unwrap_or_else => 2, + | + +error: aborting due to 7 previous errors diff --git a/tests/ui-internal/symbol_as_str_unfixable.stderr b/tests/ui-internal/symbol_as_str_unfixable.stderr index 5349983ca5196..65664ebb451ae 100644 --- a/tests/ui-internal/symbol_as_str_unfixable.stderr +++ b/tests/ui-internal/symbol_as_str_unfixable.stderr @@ -4,9 +4,10 @@ error: converting a Symbol to a string LL | s.as_str() == "xyz123"; | ^^^^^^^^^^ | + = help: add the symbols to `clippy_utils/src/sym.rs` if needed = note: `-D clippy::symbol-as-str` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::symbol_as_str)]` -help: add the symbol to `clippy_utils/src/sym.rs` and use it +help: use preinterned symbols instead | LL - s.as_str() == "xyz123"; LL + s == sym::xyz123; @@ -18,7 +19,8 @@ error: converting a Symbol to a string LL | s.as_str() == "with-dash"; | ^^^^^^^^^^ | -help: add the symbol to `clippy_utils/src/sym.rs` and use it + = help: add the symbols to `clippy_utils/src/sym.rs` if needed +help: use preinterned symbols instead | LL - s.as_str() == "with-dash"; LL + s == sym::with_dash; @@ -30,7 +32,8 @@ error: converting a Symbol to a string LL | s.as_str() == "with.dot"; | ^^^^^^^^^^ | -help: add the symbol to `clippy_utils/src/sym.rs` and use it + = help: add the symbols to `clippy_utils/src/sym.rs` if needed +help: use preinterned symbols instead | LL - s.as_str() == "with.dot"; LL + s == sym::with_dot; diff --git a/tests/ui-internal/unnecessary_def_path.fixed b/tests/ui-internal/unnecessary_def_path.fixed deleted file mode 100644 index 89902ebe4e54e..0000000000000 --- a/tests/ui-internal/unnecessary_def_path.fixed +++ /dev/null @@ -1,77 +0,0 @@ -//@aux-build:paths.rs -#![deny(clippy::unnecessary_def_path)] -#![feature(rustc_private)] -#![allow(clippy::unnecessary_map_or)] - -extern crate clippy_utils; -extern crate paths; -extern crate rustc_hir; -extern crate rustc_lint; -extern crate rustc_middle; -extern crate rustc_span; - -#[allow(unused)] -use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type}; -#[allow(unused)] -use clippy_utils::{ - is_enum_variant_ctor, is_expr_path_def_path, is_path_diagnostic_item, is_res_lang_ctor, is_trait_method, - match_def_path, match_trait_method, path_res, -}; - -#[allow(unused)] -use rustc_hir::LangItem; -#[allow(unused)] -use rustc_span::sym; - -use rustc_hir::Expr; -use rustc_hir::def_id::DefId; -use rustc_lint::LateContext; -use rustc_middle::ty::Ty; - -#[allow(unused, clippy::unnecessary_def_path)] -static OPTION: [&str; 3] = ["core", "option", "Option"]; -#[allow(unused, clippy::unnecessary_def_path)] -const RESULT: &[&str] = &["core", "result", "Result"]; - -fn _f<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, did: DefId, expr: &Expr<'_>) { - let _ = is_type_diagnostic_item(cx, ty, sym::Option); - //~^ unnecessary_def_path - let _ = is_type_diagnostic_item(cx, ty, sym::Result); - //~^ unnecessary_def_path - let _ = is_type_diagnostic_item(cx, ty, sym::Result); - //~^ unnecessary_def_path - - #[allow(unused, clippy::unnecessary_def_path)] - let rc_path = &["alloc", "rc", "Rc"]; - let _ = is_type_diagnostic_item(cx, ty, sym::Rc); - //~^ unnecessary_def_path - - let _ = is_type_diagnostic_item(cx, ty, sym::Option); - //~^ unnecessary_def_path - let _ = is_type_diagnostic_item(cx, ty, sym::Result); - //~^ unnecessary_def_path - - let _ = is_type_lang_item(cx, ty, LangItem::OwnedBox); - //~^ unnecessary_def_path - let _ = is_type_diagnostic_item(cx, ty, sym::maybe_uninit_uninit); - //~^ unnecessary_def_path - - let _ = cx.tcx.lang_items().get(LangItem::OwnedBox) == Some(did); - //~^ unnecessary_def_path - let _ = cx.tcx.is_diagnostic_item(sym::Option, did); - //~^ unnecessary_def_path - let _ = cx.tcx.lang_items().get(LangItem::OptionSome) == Some(did); - //~^ unnecessary_def_path - - let _ = is_trait_method(cx, expr, sym::AsRef); - //~^ unnecessary_def_path - - let _ = is_path_diagnostic_item(cx, expr, sym::Option); - //~^ unnecessary_def_path - let _ = path_res(cx, expr).opt_def_id().map_or(false, |id| cx.tcx.lang_items().get(LangItem::IteratorNext) == Some(id)); - //~^ unnecessary_def_path - let _ = is_res_lang_ctor(cx, path_res(cx, expr), LangItem::OptionSome); - //~^ unnecessary_def_path -} - -fn main() {} diff --git a/tests/ui-internal/unnecessary_def_path.rs b/tests/ui-internal/unnecessary_def_path.rs index cfca15267c195..5cd3254188d9a 100644 --- a/tests/ui-internal/unnecessary_def_path.rs +++ b/tests/ui-internal/unnecessary_def_path.rs @@ -1,77 +1,20 @@ -//@aux-build:paths.rs -#![deny(clippy::unnecessary_def_path)] #![feature(rustc_private)] -#![allow(clippy::unnecessary_map_or)] -extern crate clippy_utils; -extern crate paths; -extern crate rustc_hir; -extern crate rustc_lint; -extern crate rustc_middle; -extern crate rustc_span; +use clippy_utils::paths::{PathLookup, PathNS}; +use clippy_utils::{macro_path, sym, type_path, value_path}; -#[allow(unused)] -use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type}; -#[allow(unused)] -use clippy_utils::{ - is_enum_variant_ctor, is_expr_path_def_path, is_path_diagnostic_item, is_res_lang_ctor, is_trait_method, - match_def_path, match_trait_method, path_res, -}; +static OPTION: PathLookup = type_path!(core::option::Option); +//~^ unnecessary_def_path +static SOME: PathLookup = type_path!(core::option::Option::Some); +//~^ unnecessary_def_path -#[allow(unused)] -use rustc_hir::LangItem; -#[allow(unused)] -use rustc_span::sym; +static RESULT: PathLookup = type_path!(core::result::Result); +//~^ unnecessary_def_path +static RESULT_VIA_STD: PathLookup = type_path!(std::result::Result); +//~^ unnecessary_def_path -use rustc_hir::Expr; -use rustc_hir::def_id::DefId; -use rustc_lint::LateContext; -use rustc_middle::ty::Ty; +static VEC_NEW: PathLookup = value_path!(alloc::vec::Vec::new); +//~^ unnecessary_def_path -#[allow(unused, clippy::unnecessary_def_path)] -static OPTION: [&str; 3] = ["core", "option", "Option"]; -#[allow(unused, clippy::unnecessary_def_path)] -const RESULT: &[&str] = &["core", "result", "Result"]; - -fn _f<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, did: DefId, expr: &Expr<'_>) { - let _ = match_type(cx, ty, &OPTION); - //~^ unnecessary_def_path - let _ = match_type(cx, ty, RESULT); - //~^ unnecessary_def_path - let _ = match_type(cx, ty, &["core", "result", "Result"]); - //~^ unnecessary_def_path - - #[allow(unused, clippy::unnecessary_def_path)] - let rc_path = &["alloc", "rc", "Rc"]; - let _ = clippy_utils::ty::match_type(cx, ty, rc_path); - //~^ unnecessary_def_path - - let _ = match_type(cx, ty, &paths::OPTION); - //~^ unnecessary_def_path - let _ = match_type(cx, ty, paths::RESULT); - //~^ unnecessary_def_path - - let _ = match_type(cx, ty, &["alloc", "boxed", "Box"]); - //~^ unnecessary_def_path - let _ = match_type(cx, ty, &["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"]); - //~^ unnecessary_def_path - - let _ = match_def_path(cx, did, &["alloc", "boxed", "Box"]); - //~^ unnecessary_def_path - let _ = match_def_path(cx, did, &["core", "option", "Option"]); - //~^ unnecessary_def_path - let _ = match_def_path(cx, did, &["core", "option", "Option", "Some"]); - //~^ unnecessary_def_path - - let _ = match_trait_method(cx, expr, &["core", "convert", "AsRef"]); - //~^ unnecessary_def_path - - let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option"]); - //~^ unnecessary_def_path - let _ = is_expr_path_def_path(cx, expr, &["core", "iter", "traits", "Iterator", "next"]); - //~^ unnecessary_def_path - let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option", "Some"]); - //~^ unnecessary_def_path -} - -fn main() {} +static VEC_MACRO: PathLookup = macro_path!(std::vec); +//~^ unnecessary_def_path diff --git a/tests/ui-internal/unnecessary_def_path.stderr b/tests/ui-internal/unnecessary_def_path.stderr index d7fb4ea551e1d..4abb1be7406c1 100644 --- a/tests/ui-internal/unnecessary_def_path.stderr +++ b/tests/ui-internal/unnecessary_def_path.stderr @@ -1,100 +1,58 @@ -error: use of a def path to a diagnostic item - --> tests/ui-internal/unnecessary_def_path.rs:37:13 +error: a diagnostic name exists for this path: sym::Option + --> tests/ui-internal/unnecessary_def_path.rs:6:29 | -LL | let _ = match_type(cx, ty, &OPTION); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Option)` +LL | static OPTION: PathLookup = type_path!(core::option::Option); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the lint level is defined here - --> tests/ui-internal/unnecessary_def_path.rs:2:9 - | -LL | #![deny(clippy::unnecessary_def_path)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: use of a def path to a diagnostic item - --> tests/ui-internal/unnecessary_def_path.rs:39:13 - | -LL | let _ = match_type(cx, ty, RESULT); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)` + = help: remove the `PathLookup` and use utilities such as `cx.tcx.is_diagnostic_item` instead + = help: see also https://doc.rust-lang.org/nightly/nightly-rustc/?search=diag&filter-crate=clippy_utils + = note: `-D clippy::unnecessary-def-path` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_def_path)]` -error: use of a def path to a diagnostic item - --> tests/ui-internal/unnecessary_def_path.rs:41:13 +error: a language item exists for this path: LangItem::OptionSome + --> tests/ui-internal/unnecessary_def_path.rs:8:27 | -LL | let _ = match_type(cx, ty, &["core", "result", "Result"]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)` - -error: use of a def path to a diagnostic item - --> tests/ui-internal/unnecessary_def_path.rs:46:13 +LL | static SOME: PathLookup = type_path!(core::option::Option::Some); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -LL | let _ = clippy_utils::ty::match_type(cx, ty, rc_path); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Rc)` + = help: remove the `PathLookup` and use utilities such as `cx.tcx.lang_items` instead + = help: see also https://doc.rust-lang.org/nightly/nightly-rustc/?search=lang&filter-crate=clippy_utils -error: use of a def path to a diagnostic item - --> tests/ui-internal/unnecessary_def_path.rs:49:13 +error: a diagnostic name exists for this path: sym::Result + --> tests/ui-internal/unnecessary_def_path.rs:11:29 | -LL | let _ = match_type(cx, ty, &paths::OPTION); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Option)` - -error: use of a def path to a diagnostic item - --> tests/ui-internal/unnecessary_def_path.rs:51:13 +LL | static RESULT: PathLookup = type_path!(core::result::Result); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -LL | let _ = match_type(cx, ty, paths::RESULT); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)` + = help: remove the `PathLookup` and use utilities such as `cx.tcx.is_diagnostic_item` instead + = help: see also https://doc.rust-lang.org/nightly/nightly-rustc/?search=diag&filter-crate=clippy_utils -error: use of a def path to a `LangItem` - --> tests/ui-internal/unnecessary_def_path.rs:54:13 +error: a diagnostic name exists for this path: sym::Result + --> tests/ui-internal/unnecessary_def_path.rs:13:37 | -LL | let _ = match_type(cx, ty, &["alloc", "boxed", "Box"]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_lang_item(cx, ty, LangItem::OwnedBox)` - -error: use of a def path to a diagnostic item - --> tests/ui-internal/unnecessary_def_path.rs:56:13 +LL | static RESULT_VIA_STD: PathLookup = type_path!(std::result::Result); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -LL | let _ = match_type(cx, ty, &["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::maybe_uninit_uninit)` + = help: remove the `PathLookup` and use utilities such as `cx.tcx.is_diagnostic_item` instead + = help: see also https://doc.rust-lang.org/nightly/nightly-rustc/?search=diag&filter-crate=clippy_utils -error: use of a def path to a `LangItem` - --> tests/ui-internal/unnecessary_def_path.rs:59:13 +error: a diagnostic name exists for this path: sym::vec_new + --> tests/ui-internal/unnecessary_def_path.rs:16:30 | -LL | let _ = match_def_path(cx, did, &["alloc", "boxed", "Box"]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().get(LangItem::OwnedBox) == Some(did)` - -error: use of a def path to a diagnostic item - --> tests/ui-internal/unnecessary_def_path.rs:61:13 +LL | static VEC_NEW: PathLookup = value_path!(alloc::vec::Vec::new); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -LL | let _ = match_def_path(cx, did, &["core", "option", "Option"]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.is_diagnostic_item(sym::Option, did)` + = help: remove the `PathLookup` and use utilities such as `cx.tcx.is_diagnostic_item` instead + = help: see also https://doc.rust-lang.org/nightly/nightly-rustc/?search=diag&filter-crate=clippy_utils -error: use of a def path to a `LangItem` - --> tests/ui-internal/unnecessary_def_path.rs:63:13 - | -LL | let _ = match_def_path(cx, did, &["core", "option", "Option", "Some"]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().get(LangItem::OptionSome) == Some(did)` +error: a diagnostic name exists for this path: sym::vec_macro + --> tests/ui-internal/unnecessary_def_path.rs:19:32 | - = help: if this `DefId` came from a constructor expression or pattern then the parent `DefId` should be used instead - -error: use of a def path to a diagnostic item - --> tests/ui-internal/unnecessary_def_path.rs:66:13 - | -LL | let _ = match_trait_method(cx, expr, &["core", "convert", "AsRef"]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_trait_method(cx, expr, sym::AsRef)` - -error: use of a def path to a diagnostic item - --> tests/ui-internal/unnecessary_def_path.rs:69:13 - | -LL | let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option"]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_path_diagnostic_item(cx, expr, sym::Option)` - -error: use of a def path to a `LangItem` - --> tests/ui-internal/unnecessary_def_path.rs:71:13 - | -LL | let _ = is_expr_path_def_path(cx, expr, &["core", "iter", "traits", "Iterator", "next"]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `path_res(cx, expr).opt_def_id().map_or(false, |id| cx.tcx.lang_items().get(LangItem::IteratorNext) == Some(id))` - -error: use of a def path to a `LangItem` - --> tests/ui-internal/unnecessary_def_path.rs:73:13 +LL | static VEC_MACRO: PathLookup = macro_path!(std::vec); + | ^^^^^^^^^^^^^^^^^^^^^ | -LL | let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option", "Some"]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_res_lang_ctor(cx, path_res(cx, expr), LangItem::OptionSome)` + = help: remove the `PathLookup` and use utilities such as `cx.tcx.is_diagnostic_item` instead + = help: see also https://doc.rust-lang.org/nightly/nightly-rustc/?search=diag&filter-crate=clippy_utils -error: aborting due to 15 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs b/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs deleted file mode 100644 index bd7a55114acbc..0000000000000 --- a/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs +++ /dev/null @@ -1,19 +0,0 @@ -#![feature(rustc_private)] -#![allow(unused)] -#![deny(clippy::unnecessary_def_path)] - -extern crate rustc_hir; - -use rustc_hir::LangItem; - -fn main() { - const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"]; - //~^ unnecessary_def_path - const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"]; - //~^ unnecessary_def_path - const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"]; - //~^ unnecessary_def_path - - // Don't lint, not a diagnostic or language item - const OPS_MOD: [&str; 2] = ["core", "ops"]; -} diff --git a/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr b/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr deleted file mode 100644 index 88fdf6f1c1888..0000000000000 --- a/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error: hardcoded path to a diagnostic item - --> tests/ui-internal/unnecessary_def_path_hardcoded_path.rs:10:36 - | -LL | const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: convert all references to use `sym::Deref` -note: the lint level is defined here - --> tests/ui-internal/unnecessary_def_path_hardcoded_path.rs:3:9 - | -LL | #![deny(clippy::unnecessary_def_path)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: hardcoded path to a language item - --> tests/ui-internal/unnecessary_def_path_hardcoded_path.rs:12:40 - | -LL | const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: convert all references to use `LangItem::DerefMut` - -error: hardcoded path to a diagnostic item - --> tests/ui-internal/unnecessary_def_path_hardcoded_path.rs:14:43 - | -LL | const OPS_MOD: [&str; 5] = ["core", "ops"]; - | ^^^^^^^^^^^^^^^ - | - = help: convert all references to use `sym::deref_method` - -error: aborting due to 3 previous errors - diff --git a/tests/ui-toml/collapsible_if/collapsible_if_let_chains.fixed b/tests/ui-toml/collapsible_if/collapsible_if_let_chains.fixed index f12273954c6dd..5e189471b0005 100644 --- a/tests/ui-toml/collapsible_if/collapsible_if_let_chains.fixed +++ b/tests/ui-toml/collapsible_if/collapsible_if_let_chains.fixed @@ -1,4 +1,3 @@ -#![feature(let_chains)] #![warn(clippy::collapsible_if)] fn main() { diff --git a/tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs b/tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs index 5a984d7a3cbee..525eebf632a0c 100644 --- a/tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs +++ b/tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs @@ -1,4 +1,3 @@ -#![feature(let_chains)] #![warn(clippy::collapsible_if)] fn main() { diff --git a/tests/ui-toml/collapsible_if/collapsible_if_let_chains.stderr b/tests/ui-toml/collapsible_if/collapsible_if_let_chains.stderr index c22a65a447301..c9de166a969ad 100644 --- a/tests/ui-toml/collapsible_if/collapsible_if_let_chains.stderr +++ b/tests/ui-toml/collapsible_if/collapsible_if_let_chains.stderr @@ -1,5 +1,5 @@ error: this `if` statement can be collapsed - --> tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs:5:5 + --> tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs:4:5 | LL | / if let Some(a) = Some(3) { LL | | // with comment @@ -21,7 +21,7 @@ LL ~ } | error: this `if` statement can be collapsed - --> tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs:13:5 + --> tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs:12:5 | LL | / if let Some(a) = Some(3) { LL | | // with comment @@ -41,7 +41,7 @@ LL ~ } | error: this `if` statement can be collapsed - --> tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs:21:5 + --> tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs:20:5 | LL | / if Some(3) == Some(4).map(|x| x - 1) { LL | | // with comment diff --git a/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/clippy.toml b/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/clippy.toml new file mode 100644 index 0000000000000..3ed7cedbd147d --- /dev/null +++ b/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/clippy.toml @@ -0,0 +1 @@ +allow-exact-repetitions = false diff --git a/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.rs b/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.rs new file mode 100644 index 0000000000000..20603766624c7 --- /dev/null +++ b/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.rs @@ -0,0 +1,13 @@ +#![warn(clippy::module_name_repetitions)] +#![allow(dead_code)] + +pub mod foo { + // this line should produce a warning: + pub fn foo() {} + //~^ module_name_repetitions + + // but this line shouldn't + pub fn to_foo() {} +} + +fn main() {} diff --git a/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.stderr b/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.stderr new file mode 100644 index 0000000000000..8e6f726d02c01 --- /dev/null +++ b/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.stderr @@ -0,0 +1,11 @@ +error: item name is the same as its containing module's name + --> tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.rs:6:12 + | +LL | pub fn foo() {} + | ^^^ + | + = note: `-D clippy::module-name-repetitions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::module_name_repetitions)]` + +error: aborting due to 1 previous error + diff --git a/tests/ui-toml/missing_docs_allow_unused/clippy.toml b/tests/ui-toml/missing_docs_allow_unused/clippy.toml new file mode 100644 index 0000000000000..2fe64b2755b69 --- /dev/null +++ b/tests/ui-toml/missing_docs_allow_unused/clippy.toml @@ -0,0 +1 @@ +missing-docs-allow-unused = true diff --git a/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs b/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs new file mode 100644 index 0000000000000..155f680c7b13a --- /dev/null +++ b/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs @@ -0,0 +1,26 @@ +//! Test file for missing_docs_in_private_items lint with allow_unused configuration +#![warn(clippy::missing_docs_in_private_items)] +#![allow(dead_code)] + +/// A struct with some documented and undocumented fields +struct Test { + /// This field is documented + field1: i32, + _unused: i32, // This should not trigger a warning because it starts with an underscore + field3: i32, //~ missing_docs_in_private_items +} + +struct Test2 { + //~^ missing_docs_in_private_items + _field1: i32, // This should not trigger a warning + _field2: i32, // This should not trigger a warning +} + +struct Test3 { + //~^ missing_docs_in_private_items + /// This field is documented although this is not mandatory + _unused: i32, // This should not trigger a warning because it starts with an underscore + field2: i32, //~ missing_docs_in_private_items +} + +fn main() {} diff --git a/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.stderr b/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.stderr new file mode 100644 index 0000000000000..8f511883e9005 --- /dev/null +++ b/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.stderr @@ -0,0 +1,38 @@ +error: missing documentation for a struct field + --> tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs:10:5 + | +LL | field3: i32, + | ^^^^^^^^^^^ + | + = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]` + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs:13:1 + | +LL | / struct Test2 { +LL | | +LL | | _field1: i32, // This should not trigger a warning +LL | | _field2: i32, // This should not trigger a warning +LL | | } + | |_^ + +error: missing documentation for a struct + --> tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs:19:1 + | +LL | / struct Test3 { +LL | | +LL | | /// This field is documented although this is not mandatory +LL | | _unused: i32, // This should not trigger a warning because it starts with an underscore +LL | | field2: i32, +LL | | } + | |_^ + +error: missing documentation for a struct field + --> tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs:23:5 + | +LL | field2: i32, + | ^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/tests/ui-toml/toml_disallowed_methods/clippy.toml b/tests/ui-toml/toml_disallowed_methods/clippy.toml index 41dbd5068479b..c7a326f282951 100644 --- a/tests/ui-toml/toml_disallowed_methods/clippy.toml +++ b/tests/ui-toml/toml_disallowed_methods/clippy.toml @@ -14,4 +14,7 @@ disallowed-methods = [ "conf_disallowed_methods::Struct::method", "conf_disallowed_methods::Trait::provided_method", "conf_disallowed_methods::Trait::implemented_method", + # re-exports + "conf_disallowed_methods::identity", + "conf_disallowed_methods::renamed", ] diff --git a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs index dd170d6baf857..2dac01649a0fd 100644 --- a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs +++ b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs @@ -8,6 +8,9 @@ extern crate regex; use futures::stream::{empty, select_all}; use regex::Regex; +use std::convert::identity; +use std::hint::black_box as renamed; + fn local_fn() {} struct Struct; @@ -71,4 +74,9 @@ fn main() { //~^ disallowed_methods s.implemented_method(); //~^ disallowed_methods + + identity(()); + //~^ disallowed_methods + renamed(1); + //~^ disallowed_methods } diff --git a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr index f7dda81eb936e..20474ad6e9270 100644 --- a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr +++ b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr @@ -1,5 +1,5 @@ error: use of a disallowed method `regex::Regex::new` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:33:14 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:36:14 | LL | let re = Regex::new(r"ab.*c").unwrap(); | ^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let re = Regex::new(r"ab.*c").unwrap(); = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]` error: use of a disallowed method `regex::Regex::is_match` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:35:8 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:38:8 | LL | re.is_match("abc"); | ^^^^^^^^ @@ -16,76 +16,88 @@ LL | re.is_match("abc"); = note: no matching allowed error: use of a disallowed method `std::iter::Iterator::sum` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:39:14 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:42:14 | LL | a.iter().sum::(); | ^^^ error: use of a disallowed method `slice::sort_unstable` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:42:7 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:45:7 | LL | a.sort_unstable(); | ^^^^^^^^^^^^^ error: use of a disallowed method `f32::clamp` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:46:20 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:49:20 | LL | let _ = 2.0f32.clamp(3.0f32, 4.0f32); | ^^^^^ error: use of a disallowed method `regex::Regex::new` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:50:61 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:53:61 | LL | let indirect: fn(&str) -> Result = Regex::new; | ^^^^^^^^^^ error: use of a disallowed method `f32::clamp` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:54:28 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:57:28 | LL | let in_call = Box::new(f32::clamp); | ^^^^^^^^^^ error: use of a disallowed method `regex::Regex::new` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:56:53 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:59:53 | LL | let in_method_call = ["^", "$"].into_iter().map(Regex::new); | ^^^^^^^^^^ error: use of a disallowed method `futures::stream::select_all` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:60:31 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:63:31 | LL | let same_name_as_module = select_all(vec![empty::<()>()]); | ^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::local_fn` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:63:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:66:5 | LL | local_fn(); | ^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::local_mod::f` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:65:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:68:5 | LL | local_mod::f(); | ^^^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::Struct::method` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:68:7 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:71:7 | LL | s.method(); | ^^^^^^ error: use of a disallowed method `conf_disallowed_methods::Trait::provided_method` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:70:7 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:73:7 | LL | s.provided_method(); | ^^^^^^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::Trait::implemented_method` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:72:7 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:75:7 | LL | s.implemented_method(); | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 14 previous errors +error: use of a disallowed method `conf_disallowed_methods::identity` + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:78:5 + | +LL | identity(()); + | ^^^^^^^^ + +error: use of a disallowed method `conf_disallowed_methods::renamed` + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:80:5 + | +LL | renamed(1); + | ^^^^^^^ + +error: aborting due to 16 previous errors diff --git a/tests/ui-toml/toml_disallowed_types/clippy.toml b/tests/ui-toml/toml_disallowed_types/clippy.toml index 6cb9e2ef95467..08e35017f782d 100644 --- a/tests/ui-toml/toml_disallowed_types/clippy.toml +++ b/tests/ui-toml/toml_disallowed_types/clippy.toml @@ -6,7 +6,7 @@ disallowed-types = [ "std::thread::Thread", "std::time::Instant", "std::io::Read", - "std::primitive::usize", + "usize", "bool", # can give path and reason with an inline table { path = "std::net::Ipv4Addr", reason = "no IPv4 allowed" }, diff --git a/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.stderr b/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.stderr index 18bc36ca1e33b..061cdc7649ad2 100644 --- a/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.stderr +++ b/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.stderr @@ -37,7 +37,7 @@ error: use of a disallowed type `std::io::Read` LL | fn trait_obj(_: &dyn std::io::Read) {} | ^^^^^^^^^^^^^ -error: use of a disallowed type `std::primitive::usize` +error: use of a disallowed type `usize` --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:26:33 | LL | fn full_and_single_path_prim(_: usize, _: bool) {} @@ -49,13 +49,13 @@ error: use of a disallowed type `bool` LL | fn full_and_single_path_prim(_: usize, _: bool) {} | ^^^^ -error: use of a disallowed type `std::primitive::usize` +error: use of a disallowed type `usize` --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:30:28 | LL | fn const_generics() {} | ^^^^^ -error: use of a disallowed type `std::primitive::usize` +error: use of a disallowed type `usize` --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:33:24 | LL | struct GenArg([u8; U]); @@ -123,7 +123,7 @@ error: use of a disallowed type `proc_macro2::Ident` LL | let _ = syn::Ident::new("", todo!()); | ^^^^^^^^^^ -error: use of a disallowed type `std::primitive::usize` +error: use of a disallowed type `usize` --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:61:12 | LL | let _: usize = 64_usize; diff --git a/tests/ui-toml/toml_invalid_path/clippy.toml b/tests/ui-toml/toml_invalid_path/clippy.toml index 6d0d732a92237..997ed47b71cb6 100644 --- a/tests/ui-toml/toml_invalid_path/clippy.toml +++ b/tests/ui-toml/toml_invalid_path/clippy.toml @@ -1,12 +1,15 @@ -[[disallowed-types]] -path = "std::result::Result::Err" - [[disallowed-macros]] path = "bool" [[disallowed-methods]] path = "std::process::current_exe" +[[disallowed-methods]] +path = "" + +[[disallowed-types]] +path = "std::result::Result::Err" + # negative test [[disallowed-methods]] diff --git a/tests/ui-toml/toml_invalid_path/conf_invalid_path.rs b/tests/ui-toml/toml_invalid_path/conf_invalid_path.rs index c152038270348..ff4eada390071 100644 --- a/tests/ui-toml/toml_invalid_path/conf_invalid_path.rs +++ b/tests/ui-toml/toml_invalid_path/conf_invalid_path.rs @@ -1,5 +1,6 @@ //@error-in-other-file: expected a macro, found a primitive type -//@error-in-other-file: `std::process::current_exe` does not refer to an existing function -//@error-in-other-file: expected a type, found a tuple variant +//@error-in-other-file: `std::process::current_exe` does not refer to a reachable function +//@error-in-other-file: `` does not refer to a reachable function +//@error-in-other-file: expected a type, found a variant fn main() {} diff --git a/tests/ui-toml/toml_invalid_path/conf_invalid_path.stderr b/tests/ui-toml/toml_invalid_path/conf_invalid_path.stderr index 82550108eba53..59a427dc99cae 100644 --- a/tests/ui-toml/toml_invalid_path/conf_invalid_path.stderr +++ b/tests/ui-toml/toml_invalid_path/conf_invalid_path.stderr @@ -1,23 +1,38 @@ warning: expected a macro, found a primitive type - --> $DIR/tests/ui-toml/toml_invalid_path/clippy.toml:4:1 + --> $DIR/tests/ui-toml/toml_invalid_path/clippy.toml:1:1 | LL | / [[disallowed-macros]] LL | | path = "bool" | |_____________^ + | + = help: add `allow-invalid = true` to the entry to suppress this warning -warning: `std::process::current_exe` does not refer to an existing function - --> $DIR/tests/ui-toml/toml_invalid_path/clippy.toml:7:1 +warning: `std::process::current_exe` does not refer to a reachable function + --> $DIR/tests/ui-toml/toml_invalid_path/clippy.toml:4:1 | LL | / [[disallowed-methods]] LL | | path = "std::process::current_exe" | |__________________________________^ + | + = help: add `allow-invalid = true` to the entry to suppress this warning -warning: expected a type, found a tuple variant - --> $DIR/tests/ui-toml/toml_invalid_path/clippy.toml:1:1 +warning: `` does not refer to a reachable function + --> $DIR/tests/ui-toml/toml_invalid_path/clippy.toml:7:1 + | +LL | / [[disallowed-methods]] +LL | | path = "" + | |_________^ + | + = help: add `allow-invalid = true` to the entry to suppress this warning + +warning: expected a type, found a variant + --> $DIR/tests/ui-toml/toml_invalid_path/clippy.toml:10:1 | LL | / [[disallowed-types]] LL | | path = "std::result::Result::Err" | |_________________________________^ + | + = help: add `allow-invalid = true` to the entry to suppress this warning -warning: 3 warnings emitted +warning: 4 warnings emitted diff --git a/tests/ui-toml/toml_unknown_config_struct_field/clippy.toml b/tests/ui-toml/toml_unknown_config_struct_field/clippy.toml new file mode 100644 index 0000000000000..82560cfd5e2a4 --- /dev/null +++ b/tests/ui-toml/toml_unknown_config_struct_field/clippy.toml @@ -0,0 +1,4 @@ +# In the following configuration, "recommendation" should be "reason" or "replacement". +disallowed-macros = [ + { path = "std::panic", recommendation = "return a `std::result::Result::Error` instead" }, +] diff --git a/tests/ui-toml/toml_unknown_config_struct_field/toml_unknown_config_struct_field.rs b/tests/ui-toml/toml_unknown_config_struct_field/toml_unknown_config_struct_field.rs new file mode 100644 index 0000000000000..9c770c31f6f8d --- /dev/null +++ b/tests/ui-toml/toml_unknown_config_struct_field/toml_unknown_config_struct_field.rs @@ -0,0 +1,5 @@ +#[rustfmt::skip] +//@error-in-other-file: error reading Clippy's configuration file: data did not match any variant of untagged enum DisallowedPathEnum +fn main() { + panic!(); +} diff --git a/tests/ui-toml/toml_unknown_config_struct_field/toml_unknown_config_struct_field.stderr b/tests/ui-toml/toml_unknown_config_struct_field/toml_unknown_config_struct_field.stderr new file mode 100644 index 0000000000000..b564709721d5c --- /dev/null +++ b/tests/ui-toml/toml_unknown_config_struct_field/toml_unknown_config_struct_field.stderr @@ -0,0 +1,8 @@ +error: error reading Clippy's configuration file: data did not match any variant of untagged enum DisallowedPathEnum + --> $DIR/tests/ui-toml/toml_unknown_config_struct_field/clippy.toml:3:5 + | +LL | { path = "std::panic", recommendation = "return a `std::result::Result::Error` instead" }, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index f2eaa66a4ae41..6ee77ebd8ece2 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -5,6 +5,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect accept-comment-above-statement allow-comparison-to-zero allow-dbg-in-tests + allow-exact-repetitions allow-expect-in-consts allow-expect-in-tests allow-indexing-slicing-in-tests @@ -57,6 +58,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect max-suggested-slice-pattern-length max-trait-bounds min-ident-chars-threshold + missing-docs-allow-unused missing-docs-in-crate-items module-item-order-groupings module-items-ordered-within-groupings @@ -97,6 +99,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect accept-comment-above-statement allow-comparison-to-zero allow-dbg-in-tests + allow-exact-repetitions allow-expect-in-consts allow-expect-in-tests allow-indexing-slicing-in-tests @@ -149,6 +152,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect max-suggested-slice-pattern-length max-trait-bounds min-ident-chars-threshold + missing-docs-allow-unused missing-docs-in-crate-items module-item-order-groupings module-items-ordered-within-groupings @@ -189,6 +193,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni accept-comment-above-statement allow-comparison-to-zero allow-dbg-in-tests + allow-exact-repetitions allow-expect-in-consts allow-expect-in-tests allow-indexing-slicing-in-tests @@ -241,6 +246,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni max-suggested-slice-pattern-length max-trait-bounds min-ident-chars-threshold + missing-docs-allow-unused missing-docs-in-crate-items module-item-order-groupings module-items-ordered-within-groupings diff --git a/tests/ui-toml/toml_unloaded_crate/clippy.toml b/tests/ui-toml/toml_unloaded_crate/clippy.toml new file mode 100644 index 0000000000000..e664256d2a2fd --- /dev/null +++ b/tests/ui-toml/toml_unloaded_crate/clippy.toml @@ -0,0 +1,10 @@ +# The first two `disallowed-methods` paths should generate warnings, but the third should not. + +[[disallowed-methods]] +path = "regex::Regex::new_" + +[[disallowed-methods]] +path = "regex::Regex_::new" + +[[disallowed-methods]] +path = "regex_::Regex::new" diff --git a/tests/ui-toml/toml_unloaded_crate/conf_unloaded_crate.rs b/tests/ui-toml/toml_unloaded_crate/conf_unloaded_crate.rs new file mode 100644 index 0000000000000..14f15e733111c --- /dev/null +++ b/tests/ui-toml/toml_unloaded_crate/conf_unloaded_crate.rs @@ -0,0 +1,6 @@ +//@error-in-other-file: `regex::Regex::new_` does not refer to a reachable function +//@error-in-other-file: `regex::Regex_::new` does not refer to a reachable function + +extern crate regex; + +fn main() {} diff --git a/tests/ui-toml/toml_unloaded_crate/conf_unloaded_crate.stderr b/tests/ui-toml/toml_unloaded_crate/conf_unloaded_crate.stderr new file mode 100644 index 0000000000000..e5fd548b26df4 --- /dev/null +++ b/tests/ui-toml/toml_unloaded_crate/conf_unloaded_crate.stderr @@ -0,0 +1,20 @@ +warning: `regex::Regex::new_` does not refer to a reachable function + --> $DIR/tests/ui-toml/toml_unloaded_crate/clippy.toml:3:1 + | +LL | / [[disallowed-methods]] +LL | | path = "regex::Regex::new_" + | |___________________________^ + | + = help: add `allow-invalid = true` to the entry to suppress this warning + +warning: `regex::Regex_::new` does not refer to a reachable function + --> $DIR/tests/ui-toml/toml_unloaded_crate/clippy.toml:6:1 + | +LL | / [[disallowed-methods]] +LL | | path = "regex::Regex_::new" + | |___________________________^ + | + = help: add `allow-invalid = true` to the entry to suppress this warning + +warning: 2 warnings emitted + diff --git a/tests/ui-toml/type_repetition_in_bounds/main.rs b/tests/ui-toml/type_repetition_in_bounds/main.rs index 7f93d2071c9db..b60cb7632e201 100644 --- a/tests/ui-toml/type_repetition_in_bounds/main.rs +++ b/tests/ui-toml/type_repetition_in_bounds/main.rs @@ -12,7 +12,7 @@ fn f2() where T: Copy + Clone + Sync + Send + ?Sized, T: Unpin + PartialEq, - //~^ ERROR: this type has already been used as a bound predicate + //~^ type_repetition_in_bounds { } diff --git a/tests/ui-toml/type_repetition_in_bounds/main.stderr b/tests/ui-toml/type_repetition_in_bounds/main.stderr index c5102c39d1cff..ba0f41167a00f 100644 --- a/tests/ui-toml/type_repetition_in_bounds/main.stderr +++ b/tests/ui-toml/type_repetition_in_bounds/main.stderr @@ -1,4 +1,4 @@ -error: this type has already been used as a bound predicate +error: type `T` has already been used as a bound predicate --> tests/ui-toml/type_repetition_in_bounds/main.rs:14:5 | LL | T: Unpin + PartialEq, diff --git a/tests/ui/author.stdout b/tests/ui/author.stdout index eed704e82fe1b..88a275302387c 100644 --- a/tests/ui/author.stdout +++ b/tests/ui/author.stdout @@ -1,8 +1,6 @@ if let StmtKind::Let(local) = stmt.kind && let Some(init) = local.init && let ExprKind::Cast(expr, cast_ty) = init.kind - && let TyKind::Path(ref qpath) = cast_ty.kind - && match_qpath(qpath, &["char"]) && let ExprKind::Lit(ref lit) = expr.kind && let LitKind::Int(69, LitIntType::Unsuffixed) = lit.node && let PatKind::Binding(BindingMode::NONE, _, name, None) = local.pat.kind diff --git a/tests/ui/author/blocks.stdout b/tests/ui/author/blocks.stdout index 54325f9776c52..e453299edbcfc 100644 --- a/tests/ui/author/blocks.stdout +++ b/tests/ui/author/blocks.stdout @@ -14,8 +14,6 @@ if let ExprKind::Block(block, None) = expr.kind && name1.as_str() == "_t" && let StmtKind::Semi(e) = block.stmts[2].kind && let ExprKind::Unary(UnOp::Neg, inner) = e.kind - && let ExprKind::Path(ref qpath) = inner.kind - && match_qpath(qpath, &["x"]) && block.expr.is_none() { // report your lint here @@ -25,18 +23,14 @@ if let ExprKind::Block(block, None) = expr.kind && let StmtKind::Let(local) = block.stmts[0].kind && let Some(init) = local.init && let ExprKind::Call(func, args) = init.kind - && let ExprKind::Path(ref qpath) = func.kind - && match_qpath(qpath, &["String", "new"]) + && is_path_diagnostic_item(cx, func, sym::string_new) && args.is_empty() && let PatKind::Binding(BindingMode::NONE, _, name, None) = local.pat.kind && name.as_str() == "expr" && let Some(trailing_expr) = block.expr && let ExprKind::Call(func1, args1) = trailing_expr.kind - && let ExprKind::Path(ref qpath1) = func1.kind - && match_qpath(qpath1, &["drop"]) + && is_path_diagnostic_item(cx, func1, sym::mem_drop) && args1.len() == 1 - && let ExprKind::Path(ref qpath2) = args1[0].kind - && match_qpath(qpath2, &["expr"]) { // report your lint here } diff --git a/tests/ui/author/call.stdout b/tests/ui/author/call.stdout index 59d4da490fe54..2b179d45112ee 100644 --- a/tests/ui/author/call.stdout +++ b/tests/ui/author/call.stdout @@ -1,8 +1,7 @@ if let StmtKind::Let(local) = stmt.kind && let Some(init) = local.init && let ExprKind::Call(func, args) = init.kind - && let ExprKind::Path(ref qpath) = func.kind - && match_qpath(qpath, &["{{root}}", "std", "cmp", "min"]) + && is_path_diagnostic_item(cx, func, sym::cmp_min) && args.len() == 2 && let ExprKind::Lit(ref lit) = args[0].kind && let LitKind::Int(3, LitIntType::Unsuffixed) = lit.node diff --git a/tests/ui/author/if.stdout b/tests/ui/author/if.stdout index 8ffdf8862027b..da359866bffc6 100644 --- a/tests/ui/author/if.stdout +++ b/tests/ui/author/if.stdout @@ -31,10 +31,8 @@ if let StmtKind::Let(local) = stmt.kind if let ExprKind::If(cond, then, Some(else_expr)) = expr.kind && let ExprKind::Let(let_expr) = cond.kind && let PatKind::Expr(lit_expr) = let_expr.pat.kind - && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind + && let PatExprKind::Lit { ref lit, negated } = lit_expr.kind && let LitKind::Bool(true) = lit.node - && let ExprKind::Path(ref qpath) = let_expr.init.kind - && match_qpath(qpath, &["a"]) && let ExprKind::Block(block, None) = then.kind && block.stmts.is_empty() && block.expr.is_none() diff --git a/tests/ui/author/issue_3849.stdout b/tests/ui/author/issue_3849.stdout index a5a8c0304ee40..f02ea5bf075f7 100644 --- a/tests/ui/author/issue_3849.stdout +++ b/tests/ui/author/issue_3849.stdout @@ -1,11 +1,8 @@ if let StmtKind::Let(local) = stmt.kind && let Some(init) = local.init && let ExprKind::Call(func, args) = init.kind - && let ExprKind::Path(ref qpath) = func.kind - && match_qpath(qpath, &["std", "mem", "transmute"]) + && is_path_diagnostic_item(cx, func, sym::transmute) && args.len() == 1 - && let ExprKind::Path(ref qpath1) = args[0].kind - && match_qpath(qpath1, &["ZPTR"]) && let PatKind::Wild = local.pat.kind { // report your lint here diff --git a/tests/ui/author/loop.stdout b/tests/ui/author/loop.stdout index c94eb171f52b9..79794cec92698 100644 --- a/tests/ui/author/loop.stdout +++ b/tests/ui/author/loop.stdout @@ -14,8 +14,6 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo && block.stmts.len() == 1 && let StmtKind::Let(local) = block.stmts[0].kind && let Some(init) = local.init - && let ExprKind::Path(ref qpath1) = init.kind - && match_qpath(qpath1, &["y"]) && let PatKind::Binding(BindingMode::NONE, _, name1, None) = local.pat.kind && name1.as_str() == "z" && block.expr.is_none() @@ -64,8 +62,6 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo // report your lint here } if let Some(higher::While { condition: condition, body: body }) = higher::While::hir(expr) - && let ExprKind::Path(ref qpath) = condition.kind - && match_qpath(qpath, &["a"]) && let ExprKind::Block(block, None) = body.kind && block.stmts.len() == 1 && let StmtKind::Semi(e) = block.stmts[0].kind @@ -77,10 +73,8 @@ if let Some(higher::While { condition: condition, body: body }) = higher::While: } if let Some(higher::WhileLet { let_pat: let_pat, let_expr: let_expr, if_then: if_then }) = higher::WhileLet::hir(expr) && let PatKind::Expr(lit_expr) = let_pat.kind - && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind + && let PatExprKind::Lit { ref lit, negated } = lit_expr.kind && let LitKind::Bool(true) = lit.node - && let ExprKind::Path(ref qpath) = let_expr.kind - && match_qpath(qpath, &["a"]) && let ExprKind::Block(block, None) = if_then.kind && block.stmts.len() == 1 && let StmtKind::Semi(e) = block.stmts[0].kind diff --git a/tests/ui/author/macro_in_closure.stdout b/tests/ui/author/macro_in_closure.stdout index 3186d0cbc276c..5f8a4ce236302 100644 --- a/tests/ui/author/macro_in_closure.stdout +++ b/tests/ui/author/macro_in_closure.stdout @@ -7,12 +7,10 @@ if let StmtKind::Let(local) = stmt.kind && block.stmts.len() == 1 && let StmtKind::Semi(e) = block.stmts[0].kind && let ExprKind::Call(func, args) = e.kind - && let ExprKind::Path(ref qpath) = func.kind - && match_qpath(qpath, &["$crate", "io", "_print"]) + && paths::STD_IO_STDIO__PRINT.matches_path(cx, func) // Add the path to `clippy_utils::paths` if needed && args.len() == 1 && let ExprKind::Call(func1, args1) = args[0].kind - && let ExprKind::Path(ref qpath1) = func1.kind - && match_qpath(qpath1, &["format_arguments", "new_v1"]) + && paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed && args1.len() == 2 && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind && let ExprKind::Array(elements) = inner.kind @@ -27,12 +25,9 @@ if let StmtKind::Let(local) = stmt.kind && let ExprKind::Array(elements1) = inner1.kind && elements1.len() == 1 && let ExprKind::Call(func2, args2) = elements1[0].kind - && let ExprKind::Path(ref qpath2) = func2.kind - && match_qpath(qpath2, &["format_argument", "new_display"]) + && paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed && args2.len() == 1 && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[0].kind - && let ExprKind::Path(ref qpath3) = inner2.kind - && match_qpath(qpath3, &["x"]) && block.expr.is_none() && let PatKind::Binding(BindingMode::NONE, _, name, None) = local.pat.kind && name.as_str() == "print_text" diff --git a/tests/ui/author/macro_in_loop.stdout b/tests/ui/author/macro_in_loop.stdout index 3f9be297c33c5..ecc252543117a 100644 --- a/tests/ui/author/macro_in_loop.stdout +++ b/tests/ui/author/macro_in_loop.stdout @@ -17,12 +17,10 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo && block1.stmts.len() == 1 && let StmtKind::Semi(e1) = block1.stmts[0].kind && let ExprKind::Call(func, args) = e1.kind - && let ExprKind::Path(ref qpath1) = func.kind - && match_qpath(qpath1, &["$crate", "io", "_print"]) + && paths::STD_IO_STDIO__PRINT.matches_path(cx, func) // Add the path to `clippy_utils::paths` if needed && args.len() == 1 && let ExprKind::Call(func1, args1) = args[0].kind - && let ExprKind::Path(ref qpath2) = func1.kind - && match_qpath(qpath2, &["format_arguments", "new_v1"]) + && paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed && args1.len() == 2 && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind && let ExprKind::Array(elements) = inner.kind @@ -37,12 +35,9 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo && let ExprKind::Array(elements1) = inner1.kind && elements1.len() == 1 && let ExprKind::Call(func2, args2) = elements1[0].kind - && let ExprKind::Path(ref qpath3) = func2.kind - && match_qpath(qpath3, &["format_argument", "new_display"]) + && paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed && args2.len() == 1 && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[0].kind - && let ExprKind::Path(ref qpath4) = inner2.kind - && match_qpath(qpath4, &["i"]) && block1.expr.is_none() && block.expr.is_none() { diff --git a/tests/ui/author/matches.stdout b/tests/ui/author/matches.stdout index acb3b140dfa13..9752d7a9f99d2 100644 --- a/tests/ui/author/matches.stdout +++ b/tests/ui/author/matches.stdout @@ -5,13 +5,13 @@ if let StmtKind::Let(local) = stmt.kind && let LitKind::Int(42, LitIntType::Unsuffixed) = lit.node && arms.len() == 3 && let PatKind::Expr(lit_expr) = arms[0].pat.kind - && let PatExprKind::Lit{ref lit1, negated } = lit_expr.kind + && let PatExprKind::Lit { ref lit1, negated } = lit_expr.kind && let LitKind::Int(16, LitIntType::Unsuffixed) = lit1.node && arms[0].guard.is_none() && let ExprKind::Lit(ref lit2) = arms[0].body.kind && let LitKind::Int(5, LitIntType::Unsuffixed) = lit2.node && let PatKind::Expr(lit_expr1) = arms[1].pat.kind - && let PatExprKind::Lit{ref lit3, negated1 } = lit_expr1.kind + && let PatExprKind::Lit { ref lit3, negated1 } = lit_expr1.kind && let LitKind::Int(17, LitIntType::Unsuffixed) = lit3.node && arms[1].guard.is_none() && let ExprKind::Block(block, None) = arms[1].body.kind @@ -23,8 +23,6 @@ if let StmtKind::Let(local) = stmt.kind && let PatKind::Binding(BindingMode::NONE, _, name, None) = local1.pat.kind && name.as_str() == "x" && let Some(trailing_expr) = block.expr - && let ExprKind::Path(ref qpath) = trailing_expr.kind - && match_qpath(qpath, &["x"]) && let PatKind::Wild = arms[2].pat.kind && arms[2].guard.is_none() && let ExprKind::Lit(ref lit5) = arms[2].body.kind diff --git a/tests/ui/author/struct.stdout b/tests/ui/author/struct.stdout index b66bbccb3cf1b..1e8fbafd30c5c 100644 --- a/tests/ui/author/struct.stdout +++ b/tests/ui/author/struct.stdout @@ -1,5 +1,4 @@ if let ExprKind::Struct(qpath, fields, None) = expr.kind - && match_qpath(qpath, &["Test"]) && fields.len() == 1 && fields[0].ident.as_str() == "field" && let ExprKind::If(cond, then, Some(else_expr)) = fields[0].expr.kind @@ -20,11 +19,10 @@ if let ExprKind::Struct(qpath, fields, None) = expr.kind // report your lint here } if let PatKind::Struct(ref qpath, fields, false) = arm.pat.kind - && match_qpath(qpath, &["Test"]) && fields.len() == 1 && fields[0].ident.as_str() == "field" && let PatKind::Expr(lit_expr) = fields[0].pat.kind - && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind + && let PatExprKind::Lit { ref lit, negated } = lit_expr.kind && let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node && arm.guard.is_none() && let ExprKind::Block(block, None) = arm.body.kind @@ -34,10 +32,9 @@ if let PatKind::Struct(ref qpath, fields, false) = arm.pat.kind // report your lint here } if let PatKind::TupleStruct(ref qpath, fields, None) = arm.pat.kind - && match_qpath(qpath, &["TestTuple"]) && fields.len() == 1 && let PatKind::Expr(lit_expr) = fields[0].kind - && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind + && let PatExprKind::Lit { ref lit, negated } = lit_expr.kind && let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node && arm.guard.is_none() && let ExprKind::Block(block, None) = arm.body.kind @@ -48,8 +45,6 @@ if let PatKind::TupleStruct(ref qpath, fields, None) = arm.pat.kind } if let ExprKind::MethodCall(method_name, receiver, args, _) = expr.kind && method_name.ident.as_str() == "test" - && let ExprKind::Path(ref qpath) = receiver.kind - && match_qpath(qpath, &["test_method_call"]) && args.is_empty() { // report your lint here diff --git a/tests/ui/auxiliary/proc_macro_attr.rs b/tests/ui/auxiliary/proc_macro_attr.rs index e72d6b6ceadfd..4c61c5accd397 100644 --- a/tests/ui/auxiliary/proc_macro_attr.rs +++ b/tests/ui/auxiliary/proc_macro_attr.rs @@ -51,14 +51,14 @@ pub fn rename_my_lifetimes(_args: TokenStream, input: TokenStream) -> TokenStrea fn mut_receiver_of(sig: &mut Signature) -> Option<&mut FnArg> { let arg = sig.inputs.first_mut()?; - if let FnArg::Typed(PatType { pat, .. }) = arg { - if let Pat::Ident(PatIdent { ident, .. }) = &**pat { - if ident == "self" { - return Some(arg); - } - } + if let FnArg::Typed(PatType { pat, .. }) = arg + && let Pat::Ident(PatIdent { ident, .. }) = &**pat + && ident == "self" + { + Some(arg) + } else { + None } - None } let mut elided = 0; @@ -66,30 +66,29 @@ pub fn rename_my_lifetimes(_args: TokenStream, input: TokenStream) -> TokenStrea // Look for methods having arbitrary self type taken by &mut ref for inner in &mut item.items { - if let ImplItem::Fn(method) = inner { - if let Some(FnArg::Typed(pat_type)) = mut_receiver_of(&mut method.sig) { - if let box Type::Reference(reference) = &mut pat_type.ty { - // Target only unnamed lifetimes - let name = match &reference.lifetime { - Some(lt) if lt.ident == "_" => make_name(elided), - None => make_name(elided), - _ => continue, - }; - elided += 1; - - // HACK: Syn uses `Span` from the proc_macro2 crate, and does not seem to reexport it. - // In order to avoid adding the dependency, get a default span from a nonexistent token. - // A default span is needed to mark the code as coming from expansion. - let span = Star::default().span(); - - // Replace old lifetime with the named one - let lifetime = Lifetime::new(&name, span); - reference.lifetime = Some(parse_quote!(#lifetime)); - - // Add lifetime to the generics of the method - method.sig.generics.params.push(parse_quote!(#lifetime)); - } - } + if let ImplItem::Fn(method) = inner + && let Some(FnArg::Typed(pat_type)) = mut_receiver_of(&mut method.sig) + && let box Type::Reference(reference) = &mut pat_type.ty + { + // Target only unnamed lifetimes + let name = match &reference.lifetime { + Some(lt) if lt.ident == "_" => make_name(elided), + None => make_name(elided), + _ => continue, + }; + elided += 1; + + // HACK: Syn uses `Span` from the proc_macro2 crate, and does not seem to reexport it. + // In order to avoid adding the dependency, get a default span from a nonexistent token. + // A default span is needed to mark the code as coming from expansion. + let span = Star::default().span(); + + // Replace old lifetime with the named one + let lifetime = Lifetime::new(&name, span); + reference.lifetime = Some(parse_quote!(#lifetime)); + + // Add lifetime to the generics of the method + method.sig.generics.params.push(parse_quote!(#lifetime)); } } @@ -129,15 +128,15 @@ pub fn fake_desugar_await(_args: TokenStream, input: TokenStream) -> TokenStream let mut async_fn = parse_macro_input!(input as syn::ItemFn); for stmt in &mut async_fn.block.stmts { - if let syn::Stmt::Expr(syn::Expr::Match(syn::ExprMatch { expr: scrutinee, .. }), _) = stmt { - if let syn::Expr::Await(syn::ExprAwait { base, await_token, .. }) = scrutinee.as_mut() { - let blc = quote_spanned!( await_token.span => { - #[allow(clippy::let_and_return)] - let __pinned = #base; - __pinned - }); - *scrutinee = parse_quote!(#blc); - } + if let syn::Stmt::Expr(syn::Expr::Match(syn::ExprMatch { expr: scrutinee, .. }), _) = stmt + && let syn::Expr::Await(syn::ExprAwait { base, await_token, .. }) = scrutinee.as_mut() + { + let blc = quote_spanned!( await_token.span => { + #[allow(clippy::let_and_return)] + let __pinned = #base; + __pinned + }); + *scrutinee = parse_quote!(#blc); } } diff --git a/tests/ui/auxiliary/proc_macros.rs b/tests/ui/auxiliary/proc_macros.rs index 7a4cc4fa9ee8e..bb55539617fc5 100644 --- a/tests/ui/auxiliary/proc_macros.rs +++ b/tests/ui/auxiliary/proc_macros.rs @@ -1,4 +1,3 @@ -#![feature(let_chains)] #![feature(proc_macro_span)] #![allow(clippy::needless_if, dead_code)] diff --git a/tests/ui/bool_to_int_with_if.fixed b/tests/ui/bool_to_int_with_if.fixed index ed6141244b409..7fa7c016f9351 100644 --- a/tests/ui/bool_to_int_with_if.fixed +++ b/tests/ui/bool_to_int_with_if.fixed @@ -1,4 +1,3 @@ -#![feature(let_chains)] #![warn(clippy::bool_to_int_with_if)] #![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)] diff --git a/tests/ui/bool_to_int_with_if.rs b/tests/ui/bool_to_int_with_if.rs index 3f1f1c766e460..2295d6f1362d2 100644 --- a/tests/ui/bool_to_int_with_if.rs +++ b/tests/ui/bool_to_int_with_if.rs @@ -1,4 +1,3 @@ -#![feature(let_chains)] #![warn(clippy::bool_to_int_with_if)] #![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)] diff --git a/tests/ui/bool_to_int_with_if.stderr b/tests/ui/bool_to_int_with_if.stderr index 94089bc6dc8ef..e4ae57304141a 100644 --- a/tests/ui/bool_to_int_with_if.stderr +++ b/tests/ui/bool_to_int_with_if.stderr @@ -1,5 +1,5 @@ error: boolean to int conversion using if - --> tests/ui/bool_to_int_with_if.rs:14:5 + --> tests/ui/bool_to_int_with_if.rs:13:5 | LL | / if a { LL | | @@ -14,7 +14,7 @@ LL | | }; = help: to override `-D warnings` add `#[allow(clippy::bool_to_int_with_if)]` error: boolean to int conversion using if - --> tests/ui/bool_to_int_with_if.rs:20:5 + --> tests/ui/bool_to_int_with_if.rs:19:5 | LL | / if a { LL | | @@ -27,7 +27,7 @@ LL | | }; = note: `!a as i32` or `(!a).into()` can also be valid options error: boolean to int conversion using if - --> tests/ui/bool_to_int_with_if.rs:26:5 + --> tests/ui/bool_to_int_with_if.rs:25:5 | LL | / if !a { LL | | @@ -40,7 +40,7 @@ LL | | }; = note: `!a as i32` or `(!a).into()` can also be valid options error: boolean to int conversion using if - --> tests/ui/bool_to_int_with_if.rs:32:5 + --> tests/ui/bool_to_int_with_if.rs:31:5 | LL | / if a || b { LL | | @@ -53,7 +53,7 @@ LL | | }; = note: `(a || b) as i32` or `(a || b).into()` can also be valid options error: boolean to int conversion using if - --> tests/ui/bool_to_int_with_if.rs:38:5 + --> tests/ui/bool_to_int_with_if.rs:37:5 | LL | / if cond(a, b) { LL | | @@ -66,7 +66,7 @@ LL | | }; = note: `cond(a, b) as i32` or `cond(a, b).into()` can also be valid options error: boolean to int conversion using if - --> tests/ui/bool_to_int_with_if.rs:44:5 + --> tests/ui/bool_to_int_with_if.rs:43:5 | LL | / if x + y < 4 { LL | | @@ -79,7 +79,7 @@ LL | | }; = note: `(x + y < 4) as i32` or `(x + y < 4).into()` can also be valid options error: boolean to int conversion using if - --> tests/ui/bool_to_int_with_if.rs:54:12 + --> tests/ui/bool_to_int_with_if.rs:53:12 | LL | } else if b { | ____________^ @@ -93,7 +93,7 @@ LL | | }; = note: `b as i32` or `b.into()` can also be valid options error: boolean to int conversion using if - --> tests/ui/bool_to_int_with_if.rs:64:12 + --> tests/ui/bool_to_int_with_if.rs:63:12 | LL | } else if b { | ____________^ @@ -107,7 +107,7 @@ LL | | }; = note: `!b as i32` or `(!b).into()` can also be valid options error: boolean to int conversion using if - --> tests/ui/bool_to_int_with_if.rs:130:5 + --> tests/ui/bool_to_int_with_if.rs:129:5 | LL | if a { 1 } else { 0 } | ^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `u8::from(a)` @@ -115,7 +115,7 @@ LL | if a { 1 } else { 0 } = note: `a as u8` or `a.into()` can also be valid options error: boolean to int conversion using if - --> tests/ui/bool_to_int_with_if.rs:174:13 + --> tests/ui/bool_to_int_with_if.rs:173:13 | LL | let _ = if dbg!(4 > 0) { 1 } else { 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `i32::from(dbg!(4 > 0))` @@ -123,7 +123,7 @@ LL | let _ = if dbg!(4 > 0) { 1 } else { 0 }; = note: `dbg!(4 > 0) as i32` or `dbg!(4 > 0).into()` can also be valid options error: boolean to int conversion using if - --> tests/ui/bool_to_int_with_if.rs:177:18 + --> tests/ui/bool_to_int_with_if.rs:176:18 | LL | let _ = dbg!(if 4 > 0 { 1 } else { 0 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `i32::from(4 > 0)` diff --git a/tests/ui/checked_unwrap/simple_conditionals.rs b/tests/ui/checked_unwrap/simple_conditionals.rs index 4101897d38004..ba0d36d85fe54 100644 --- a/tests/ui/checked_unwrap/simple_conditionals.rs +++ b/tests/ui/checked_unwrap/simple_conditionals.rs @@ -188,6 +188,91 @@ fn issue11371() { } } +fn gen_option() -> Option<()> { + Some(()) + // Or None +} + +fn gen_result() -> Result<(), ()> { + Ok(()) + // Or Err(()) +} + +fn issue14725() { + let option = Some(()); + + if option.is_some() { + let _ = option.as_ref().unwrap(); + //~^ unnecessary_unwrap + } else { + let _ = option.as_ref().unwrap(); + //~^ panicking_unwrap + } + + let result = Ok::<(), ()>(()); + + if result.is_ok() { + let _y = 1; + result.as_ref().unwrap(); + //~^ unnecessary_unwrap + } else { + let _y = 1; + result.as_ref().unwrap(); + //~^ panicking_unwrap + } + + let mut option = Some(()); + if option.is_some() { + option = gen_option(); + option.as_mut().unwrap(); + } else { + option = gen_option(); + option.as_mut().unwrap(); + } + + let mut result = Ok::<(), ()>(()); + if result.is_ok() { + result = gen_result(); + result.as_mut().unwrap(); + } else { + result = gen_result(); + result.as_mut().unwrap(); + } +} + +fn issue14763(x: Option, r: Result<(), ()>) { + _ = || { + if x.is_some() { + _ = x.unwrap(); + //~^ unnecessary_unwrap + } else { + _ = x.unwrap(); + //~^ panicking_unwrap + } + }; + _ = || { + if r.is_ok() { + _ = r.as_ref().unwrap(); + //~^ unnecessary_unwrap + } else { + _ = r.as_ref().unwrap(); + //~^ panicking_unwrap + } + }; +} + +const ISSUE14763: fn(Option) = |x| { + _ = || { + if x.is_some() { + _ = x.unwrap(); + //~^ unnecessary_unwrap + } else { + _ = x.unwrap(); + //~^ panicking_unwrap + } + } +}; + fn check_expect() { let x = Some(()); if x.is_some() { diff --git a/tests/ui/checked_unwrap/simple_conditionals.stderr b/tests/ui/checked_unwrap/simple_conditionals.stderr index ad3c420270c14..a4bf00992445e 100644 --- a/tests/ui/checked_unwrap/simple_conditionals.stderr +++ b/tests/ui/checked_unwrap/simple_conditionals.stderr @@ -236,6 +236,92 @@ LL | if result.is_ok() { LL | result.as_mut().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ +error: called `unwrap` on `option` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:205:17 + | +LL | if option.is_some() { + | ------------------- help: try: `if let Some() = &option` +LL | let _ = option.as_ref().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:208:17 + | +LL | if option.is_some() { + | ---------------- because of this check +... +LL | let _ = option.as_ref().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: called `unwrap` on `result` after checking its variant with `is_ok` + --> tests/ui/checked_unwrap/simple_conditionals.rs:216:9 + | +LL | if result.is_ok() { + | ----------------- help: try: `if let Ok() = &result` +LL | let _y = 1; +LL | result.as_ref().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:220:9 + | +LL | if result.is_ok() { + | -------------- because of this check +... +LL | result.as_ref().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: called `unwrap` on `x` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:246:17 + | +LL | if x.is_some() { + | -------------- help: try: `if let Some() = x` +LL | _ = x.unwrap(); + | ^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:249:17 + | +LL | if x.is_some() { + | ----------- because of this check +... +LL | _ = x.unwrap(); + | ^^^^^^^^^^ + +error: called `unwrap` on `r` after checking its variant with `is_ok` + --> tests/ui/checked_unwrap/simple_conditionals.rs:255:17 + | +LL | if r.is_ok() { + | ------------ help: try: `if let Ok() = &r` +LL | _ = r.as_ref().unwrap(); + | ^^^^^^^^^^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:258:17 + | +LL | if r.is_ok() { + | --------- because of this check +... +LL | _ = r.as_ref().unwrap(); + | ^^^^^^^^^^^^^^^^^^^ + +error: called `unwrap` on `x` after checking its variant with `is_some` + --> tests/ui/checked_unwrap/simple_conditionals.rs:267:17 + | +LL | if x.is_some() { + | -------------- help: try: `if let Some() = x` +LL | _ = x.unwrap(); + | ^^^^^^^^^^ + +error: this call to `unwrap()` will always panic + --> tests/ui/checked_unwrap/simple_conditionals.rs:270:17 + | +LL | if x.is_some() { + | ----------- because of this check +... +LL | _ = x.unwrap(); + | ^^^^^^^^^^ + error: creating a shared reference to mutable static --> tests/ui/checked_unwrap/simple_conditionals.rs:183:12 | @@ -246,5 +332,5 @@ LL | if X.is_some() { = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives = note: `#[deny(static_mut_refs)]` on by default -error: aborting due to 26 previous errors +error: aborting due to 36 previous errors diff --git a/tests/ui/cloned_ref_to_slice_refs.fixed b/tests/ui/cloned_ref_to_slice_refs.fixed new file mode 100644 index 0000000000000..818c6e23259e3 --- /dev/null +++ b/tests/ui/cloned_ref_to_slice_refs.fixed @@ -0,0 +1,64 @@ +#![warn(clippy::cloned_ref_to_slice_refs)] + +#[derive(Clone)] +struct Data; + +fn main() { + { + let data = Data; + let data_ref = &data; + let _ = std::slice::from_ref(data_ref); //~ ERROR: this call to `clone` can be replaced with `std::slice::from_ref` + } + + { + let _ = std::slice::from_ref(&Data); //~ ERROR: this call to `clone` can be replaced with `std::slice::from_ref` + } + + { + #[derive(Clone)] + struct Point(i32, i32); + + let _ = std::slice::from_ref(&Point(0, 0)); //~ ERROR: this call to `clone` can be replaced with `std::slice::from_ref` + } + + // the string was cloned with the intention to not mutate + { + struct BetterString(String); + + let mut message = String::from("good"); + let sender = BetterString(message.clone()); + + message.push_str("bye!"); + + println!("{} {}", message, sender.0) + } + + // the string was cloned with the intention to not mutate + { + let mut x = String::from("Hello"); + let r = &[x.clone()]; + x.push('!'); + println!("r = `{}', x = `{x}'", r[0]); + } + + // mutable borrows may have the intention to clone + { + let data = Data; + let data_ref = &data; + let _ = &mut [data_ref.clone()]; + } + + // `T::clone` is used to denote a clone with side effects + { + use std::sync::Arc; + let data = Arc::new(Data); + let _ = &[Arc::clone(&data)]; + } + + // slices with multiple members can only be made from a singular reference + { + let data_1 = Data; + let data_2 = Data; + let _ = &[data_1.clone(), data_2.clone()]; + } +} diff --git a/tests/ui/cloned_ref_to_slice_refs.rs b/tests/ui/cloned_ref_to_slice_refs.rs new file mode 100644 index 0000000000000..9517dbfd1569c --- /dev/null +++ b/tests/ui/cloned_ref_to_slice_refs.rs @@ -0,0 +1,64 @@ +#![warn(clippy::cloned_ref_to_slice_refs)] + +#[derive(Clone)] +struct Data; + +fn main() { + { + let data = Data; + let data_ref = &data; + let _ = &[data_ref.clone()]; //~ ERROR: this call to `clone` can be replaced with `std::slice::from_ref` + } + + { + let _ = &[Data.clone()]; //~ ERROR: this call to `clone` can be replaced with `std::slice::from_ref` + } + + { + #[derive(Clone)] + struct Point(i32, i32); + + let _ = &[Point(0, 0).clone()]; //~ ERROR: this call to `clone` can be replaced with `std::slice::from_ref` + } + + // the string was cloned with the intention to not mutate + { + struct BetterString(String); + + let mut message = String::from("good"); + let sender = BetterString(message.clone()); + + message.push_str("bye!"); + + println!("{} {}", message, sender.0) + } + + // the string was cloned with the intention to not mutate + { + let mut x = String::from("Hello"); + let r = &[x.clone()]; + x.push('!'); + println!("r = `{}', x = `{x}'", r[0]); + } + + // mutable borrows may have the intention to clone + { + let data = Data; + let data_ref = &data; + let _ = &mut [data_ref.clone()]; + } + + // `T::clone` is used to denote a clone with side effects + { + use std::sync::Arc; + let data = Arc::new(Data); + let _ = &[Arc::clone(&data)]; + } + + // slices with multiple members can only be made from a singular reference + { + let data_1 = Data; + let data_2 = Data; + let _ = &[data_1.clone(), data_2.clone()]; + } +} diff --git a/tests/ui/cloned_ref_to_slice_refs.stderr b/tests/ui/cloned_ref_to_slice_refs.stderr new file mode 100644 index 0000000000000..6a31d87823955 --- /dev/null +++ b/tests/ui/cloned_ref_to_slice_refs.stderr @@ -0,0 +1,23 @@ +error: this call to `clone` can be replaced with `std::slice::from_ref` + --> tests/ui/cloned_ref_to_slice_refs.rs:10:17 + | +LL | let _ = &[data_ref.clone()]; + | ^^^^^^^^^^^^^^^^^^^ help: try: `std::slice::from_ref(data_ref)` + | + = note: `-D clippy::cloned-ref-to-slice-refs` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cloned_ref_to_slice_refs)]` + +error: this call to `clone` can be replaced with `std::slice::from_ref` + --> tests/ui/cloned_ref_to_slice_refs.rs:14:17 + | +LL | let _ = &[Data.clone()]; + | ^^^^^^^^^^^^^^^ help: try: `std::slice::from_ref(&Data)` + +error: this call to `clone` can be replaced with `std::slice::from_ref` + --> tests/ui/cloned_ref_to_slice_refs.rs:21:17 + | +LL | let _ = &[Point(0, 0).clone()]; + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::slice::from_ref(&Point(0, 0))` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/collapsible_if.fixed b/tests/ui/collapsible_if.fixed index e1ceb04f9cb89..b553182a44543 100644 --- a/tests/ui/collapsible_if.fixed +++ b/tests/ui/collapsible_if.fixed @@ -101,27 +101,8 @@ fn main() { } } - // Test behavior wrt. `let_chains`. - // None of the cases below should be collapsed. fn truth() -> bool { true } - // Prefix: - if let 0 = 1 { - if truth() {} - } - - // Suffix: - if truth() { - if let 0 = 1 {} - } - - // Midfix: - if truth() { - if let 0 = 1 { - if truth() {} - } - } - // Fix #5962 if matches!(true, true) && matches!(true, true) {} @@ -162,3 +143,14 @@ fn layout_check() -> u32 { ; 3 //~^^^^^ collapsible_if } + +fn issue14722() { + let x = if true { + Some(1) + } else { + if true { + println!("Some debug information"); + }; + None + }; +} diff --git a/tests/ui/collapsible_if.rs b/tests/ui/collapsible_if.rs index 0b996dca22e85..f5998457ca6cf 100644 --- a/tests/ui/collapsible_if.rs +++ b/tests/ui/collapsible_if.rs @@ -108,27 +108,8 @@ fn main() { } } - // Test behavior wrt. `let_chains`. - // None of the cases below should be collapsed. fn truth() -> bool { true } - // Prefix: - if let 0 = 1 { - if truth() {} - } - - // Suffix: - if truth() { - if let 0 = 1 {} - } - - // Midfix: - if truth() { - if let 0 = 1 { - if truth() {} - } - } - // Fix #5962 if matches!(true, true) { if matches!(true, true) {} @@ -172,3 +153,14 @@ fn layout_check() -> u32 { }; 3 //~^^^^^ collapsible_if } + +fn issue14722() { + let x = if true { + Some(1) + } else { + if true { + println!("Some debug information"); + }; + None + }; +} diff --git a/tests/ui/collapsible_if.stderr b/tests/ui/collapsible_if.stderr index 532811462393b..32c6b0194030a 100644 --- a/tests/ui/collapsible_if.stderr +++ b/tests/ui/collapsible_if.stderr @@ -127,7 +127,7 @@ LL ~ } | error: this `if` statement can be collapsed - --> tests/ui/collapsible_if.rs:133:5 + --> tests/ui/collapsible_if.rs:114:5 | LL | / if matches!(true, true) { LL | | if matches!(true, true) {} @@ -141,7 +141,7 @@ LL ~ && matches!(true, true) {} | error: this `if` statement can be collapsed - --> tests/ui/collapsible_if.rs:139:5 + --> tests/ui/collapsible_if.rs:120:5 | LL | / if matches!(true, true) && truth() { LL | | if matches!(true, true) {} @@ -155,7 +155,7 @@ LL ~ && matches!(true, true) {} | error: this `if` statement can be collapsed - --> tests/ui/collapsible_if.rs:151:5 + --> tests/ui/collapsible_if.rs:132:5 | LL | / if true { LL | | if true { @@ -173,7 +173,7 @@ LL ~ } | error: this `if` statement can be collapsed - --> tests/ui/collapsible_if.rs:168:5 + --> tests/ui/collapsible_if.rs:149:5 | LL | / if true { LL | | if true { diff --git a/tests/ui/collapsible_if_let_chains.edition2024.fixed b/tests/ui/collapsible_if_let_chains.edition2024.fixed new file mode 100644 index 0000000000000..ad08c21ba9ede --- /dev/null +++ b/tests/ui/collapsible_if_let_chains.edition2024.fixed @@ -0,0 +1,68 @@ +//@revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 +//@[edition2021] check-pass + +#![warn(clippy::collapsible_if)] + +fn main() { + if let Some(a) = Some(3) { + // with comment, so do not lint + if let Some(b) = Some(4) { + let _ = a + b; + } + } + + //~[edition2024]v collapsible_if + if let Some(a) = Some(3) + && let Some(b) = Some(4) { + let _ = a + b; + } + + //~[edition2024]v collapsible_if + if let Some(a) = Some(3) + && a + 1 == 4 { + let _ = a; + } + + //~[edition2024]v collapsible_if + if Some(3) == Some(4).map(|x| x - 1) + && let Some(b) = Some(4) { + let _ = b; + } + + fn truth() -> bool { + true + } + + // Prefix: + //~[edition2024]v collapsible_if + if let 0 = 1 + && truth() {} + + // Suffix: + //~[edition2024]v collapsible_if + if truth() + && let 0 = 1 {} + + // Midfix: + //~[edition2024]vvv collapsible_if + //~[edition2024]v collapsible_if + if truth() + && let 0 = 1 + && truth() {} +} + +#[clippy::msrv = "1.87.0"] +fn msrv_1_87() { + if let 0 = 1 { + if true {} + } +} + +#[clippy::msrv = "1.88.0"] +fn msrv_1_88() { + //~[edition2024]v collapsible_if + if let 0 = 1 + && true {} +} diff --git a/tests/ui/collapsible_if_let_chains.edition2024.stderr b/tests/ui/collapsible_if_let_chains.edition2024.stderr new file mode 100644 index 0000000000000..b0aa3cecadb60 --- /dev/null +++ b/tests/ui/collapsible_if_let_chains.edition2024.stderr @@ -0,0 +1,132 @@ +error: this `if` statement can be collapsed + --> tests/ui/collapsible_if_let_chains.rs:17:5 + | +LL | / if let Some(a) = Some(3) { +LL | | if let Some(b) = Some(4) { +LL | | let _ = a + b; +LL | | } +LL | | } + | |_____^ + | + = note: `-D clippy::collapsible-if` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::collapsible_if)]` +help: collapse nested if block + | +LL ~ if let Some(a) = Some(3) +LL ~ && let Some(b) = Some(4) { +LL | let _ = a + b; +LL ~ } + | + +error: this `if` statement can be collapsed + --> tests/ui/collapsible_if_let_chains.rs:24:5 + | +LL | / if let Some(a) = Some(3) { +LL | | if a + 1 == 4 { +LL | | let _ = a; +LL | | } +LL | | } + | |_____^ + | +help: collapse nested if block + | +LL ~ if let Some(a) = Some(3) +LL ~ && a + 1 == 4 { +LL | let _ = a; +LL ~ } + | + +error: this `if` statement can be collapsed + --> tests/ui/collapsible_if_let_chains.rs:31:5 + | +LL | / if Some(3) == Some(4).map(|x| x - 1) { +LL | | if let Some(b) = Some(4) { +LL | | let _ = b; +LL | | } +LL | | } + | |_____^ + | +help: collapse nested if block + | +LL ~ if Some(3) == Some(4).map(|x| x - 1) +LL ~ && let Some(b) = Some(4) { +LL | let _ = b; +LL ~ } + | + +error: this `if` statement can be collapsed + --> tests/ui/collapsible_if_let_chains.rs:43:5 + | +LL | / if let 0 = 1 { +LL | | if truth() {} +LL | | } + | |_____^ + | +help: collapse nested if block + | +LL ~ if let 0 = 1 +LL ~ && truth() {} + | + +error: this `if` statement can be collapsed + --> tests/ui/collapsible_if_let_chains.rs:49:5 + | +LL | / if truth() { +LL | | if let 0 = 1 {} +LL | | } + | |_____^ + | +help: collapse nested if block + | +LL ~ if truth() +LL ~ && let 0 = 1 {} + | + +error: this `if` statement can be collapsed + --> tests/ui/collapsible_if_let_chains.rs:56:5 + | +LL | / if truth() { +LL | | if let 0 = 1 { +LL | | if truth() {} +LL | | } +LL | | } + | |_____^ + | +help: collapse nested if block + | +LL ~ if truth() +LL ~ && let 0 = 1 { +LL | if truth() {} +LL ~ } + | + +error: this `if` statement can be collapsed + --> tests/ui/collapsible_if_let_chains.rs:57:9 + | +LL | / if let 0 = 1 { +LL | | if truth() {} +LL | | } + | |_________^ + | +help: collapse nested if block + | +LL ~ if let 0 = 1 +LL ~ && truth() {} + | + +error: this `if` statement can be collapsed + --> tests/ui/collapsible_if_let_chains.rs:73:5 + | +LL | / if let 0 = 1 { +LL | | if true {} +LL | | } + | |_____^ + | +help: collapse nested if block + | +LL ~ if let 0 = 1 +LL ~ && true {} + | + +error: aborting due to 8 previous errors + diff --git a/tests/ui/collapsible_if_let_chains.fixed b/tests/ui/collapsible_if_let_chains.fixed deleted file mode 100644 index 3dd9498a4c9f9..0000000000000 --- a/tests/ui/collapsible_if_let_chains.fixed +++ /dev/null @@ -1,29 +0,0 @@ -#![feature(let_chains)] -#![warn(clippy::collapsible_if)] - -fn main() { - if let Some(a) = Some(3) { - // with comment, so do not lint - if let Some(b) = Some(4) { - let _ = a + b; - } - } - - if let Some(a) = Some(3) - && let Some(b) = Some(4) { - let _ = a + b; - } - //~^^^^^ collapsible_if - - if let Some(a) = Some(3) - && a + 1 == 4 { - let _ = a; - } - //~^^^^^ collapsible_if - - if Some(3) == Some(4).map(|x| x - 1) - && let Some(b) = Some(4) { - let _ = b; - } - //~^^^^^ collapsible_if -} diff --git a/tests/ui/collapsible_if_let_chains.rs b/tests/ui/collapsible_if_let_chains.rs index 064b9a0be4847..b2e88b1a55689 100644 --- a/tests/ui/collapsible_if_let_chains.rs +++ b/tests/ui/collapsible_if_let_chains.rs @@ -1,4 +1,8 @@ -#![feature(let_chains)] +//@revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 +//@[edition2021] check-pass + #![warn(clippy::collapsible_if)] fn main() { @@ -9,24 +13,64 @@ fn main() { } } + //~[edition2024]v collapsible_if if let Some(a) = Some(3) { if let Some(b) = Some(4) { let _ = a + b; } } - //~^^^^^ collapsible_if + //~[edition2024]v collapsible_if if let Some(a) = Some(3) { if a + 1 == 4 { let _ = a; } } - //~^^^^^ collapsible_if + //~[edition2024]v collapsible_if if Some(3) == Some(4).map(|x| x - 1) { if let Some(b) = Some(4) { let _ = b; } } - //~^^^^^ collapsible_if + + fn truth() -> bool { + true + } + + // Prefix: + //~[edition2024]v collapsible_if + if let 0 = 1 { + if truth() {} + } + + // Suffix: + //~[edition2024]v collapsible_if + if truth() { + if let 0 = 1 {} + } + + // Midfix: + //~[edition2024]vvv collapsible_if + //~[edition2024]v collapsible_if + if truth() { + if let 0 = 1 { + if truth() {} + } + } +} + +#[clippy::msrv = "1.87.0"] +fn msrv_1_87() { + if let 0 = 1 { + if true {} + } +} + +#[clippy::msrv = "1.88.0"] +fn msrv_1_88() { + //~[edition2024]v collapsible_if + if let 0 = 1 { + if true {} + } } diff --git a/tests/ui/collapsible_if_let_chains.stderr b/tests/ui/collapsible_if_let_chains.stderr deleted file mode 100644 index 64a88114c47a3..0000000000000 --- a/tests/ui/collapsible_if_let_chains.stderr +++ /dev/null @@ -1,58 +0,0 @@ -error: this `if` statement can be collapsed - --> tests/ui/collapsible_if_let_chains.rs:12:5 - | -LL | / if let Some(a) = Some(3) { -LL | | if let Some(b) = Some(4) { -LL | | let _ = a + b; -LL | | } -LL | | } - | |_____^ - | - = note: `-D clippy::collapsible-if` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::collapsible_if)]` -help: collapse nested if block - | -LL ~ if let Some(a) = Some(3) -LL ~ && let Some(b) = Some(4) { -LL | let _ = a + b; -LL ~ } - | - -error: this `if` statement can be collapsed - --> tests/ui/collapsible_if_let_chains.rs:19:5 - | -LL | / if let Some(a) = Some(3) { -LL | | if a + 1 == 4 { -LL | | let _ = a; -LL | | } -LL | | } - | |_____^ - | -help: collapse nested if block - | -LL ~ if let Some(a) = Some(3) -LL ~ && a + 1 == 4 { -LL | let _ = a; -LL ~ } - | - -error: this `if` statement can be collapsed - --> tests/ui/collapsible_if_let_chains.rs:26:5 - | -LL | / if Some(3) == Some(4).map(|x| x - 1) { -LL | | if let Some(b) = Some(4) { -LL | | let _ = b; -LL | | } -LL | | } - | |_____^ - | -help: collapse nested if block - | -LL ~ if Some(3) == Some(4).map(|x| x - 1) -LL ~ && let Some(b) = Some(4) { -LL | let _ = b; -LL ~ } - | - -error: aborting due to 3 previous errors - diff --git a/tests/ui/collapsible_match.rs b/tests/ui/collapsible_match.rs index 55ef55844957a..71b82040ff62a 100644 --- a/tests/ui/collapsible_match.rs +++ b/tests/ui/collapsible_match.rs @@ -1,5 +1,6 @@ #![warn(clippy::collapsible_match)] #![allow( + clippy::collapsible_if, clippy::equatable_if_let, clippy::needless_return, clippy::no_effect, diff --git a/tests/ui/collapsible_match.stderr b/tests/ui/collapsible_match.stderr index 5294a9d6975db..c290d84ec2976 100644 --- a/tests/ui/collapsible_match.stderr +++ b/tests/ui/collapsible_match.stderr @@ -1,5 +1,5 @@ error: this `match` can be collapsed into the outer `match` - --> tests/ui/collapsible_match.rs:14:20 + --> tests/ui/collapsible_match.rs:15:20 | LL | Ok(val) => match val { | ____________________^ @@ -10,7 +10,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:14:12 + --> tests/ui/collapsible_match.rs:15:12 | LL | Ok(val) => match val { | ^^^ replace this binding @@ -21,7 +21,7 @@ LL | Some(n) => foo(n), = help: to override `-D warnings` add `#[allow(clippy::collapsible_match)]` error: this `match` can be collapsed into the outer `match` - --> tests/ui/collapsible_match.rs:24:20 + --> tests/ui/collapsible_match.rs:25:20 | LL | Ok(val) => match val { | ____________________^ @@ -32,7 +32,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:24:12 + --> tests/ui/collapsible_match.rs:25:12 | LL | Ok(val) => match val { | ^^^ replace this binding @@ -41,7 +41,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `if let` - --> tests/ui/collapsible_match.rs:34:9 + --> tests/ui/collapsible_match.rs:35:9 | LL | / if let Some(n) = val { LL | | @@ -51,7 +51,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:33:15 + --> tests/ui/collapsible_match.rs:34:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -59,7 +59,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `if let` - --> tests/ui/collapsible_match.rs:43:9 + --> tests/ui/collapsible_match.rs:44:9 | LL | / if let Some(n) = val { LL | | @@ -71,7 +71,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:42:15 + --> tests/ui/collapsible_match.rs:43:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -79,7 +79,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `if let` - --> tests/ui/collapsible_match.rs:56:9 + --> tests/ui/collapsible_match.rs:57:9 | LL | / match val { LL | | @@ -89,7 +89,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:55:15 + --> tests/ui/collapsible_match.rs:56:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -98,7 +98,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `match` - --> tests/ui/collapsible_match.rs:66:13 + --> tests/ui/collapsible_match.rs:67:13 | LL | / if let Some(n) = val { LL | | @@ -108,7 +108,7 @@ LL | | } | |_____________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:65:12 + --> tests/ui/collapsible_match.rs:66:12 | LL | Ok(val) => { | ^^^ replace this binding @@ -116,7 +116,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `if let` - --> tests/ui/collapsible_match.rs:77:9 + --> tests/ui/collapsible_match.rs:78:9 | LL | / match val { LL | | @@ -126,7 +126,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:76:15 + --> tests/ui/collapsible_match.rs:77:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -135,7 +135,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `match` - --> tests/ui/collapsible_match.rs:89:13 + --> tests/ui/collapsible_match.rs:90:13 | LL | / if let Some(n) = val { LL | | @@ -147,7 +147,7 @@ LL | | } | |_____________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:88:12 + --> tests/ui/collapsible_match.rs:89:12 | LL | Ok(val) => { | ^^^ replace this binding @@ -155,7 +155,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `match` - --> tests/ui/collapsible_match.rs:102:20 + --> tests/ui/collapsible_match.rs:103:20 | LL | Ok(val) => match val { | ____________________^ @@ -166,7 +166,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:102:12 + --> tests/ui/collapsible_match.rs:103:12 | LL | Ok(val) => match val { | ^^^ replace this binding @@ -175,7 +175,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `match` - --> tests/ui/collapsible_match.rs:112:22 + --> tests/ui/collapsible_match.rs:113:22 | LL | Some(val) => match val { | ______________________^ @@ -186,7 +186,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:112:14 + --> tests/ui/collapsible_match.rs:113:14 | LL | Some(val) => match val { | ^^^ replace this binding @@ -195,7 +195,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `match` - --> tests/ui/collapsible_match.rs:256:22 + --> tests/ui/collapsible_match.rs:257:22 | LL | Some(val) => match val { | ______________________^ @@ -206,7 +206,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:256:14 + --> tests/ui/collapsible_match.rs:257:14 | LL | Some(val) => match val { | ^^^ replace this binding @@ -215,7 +215,7 @@ LL | E::A(val) | E::B(val) => foo(val), | ^^^^^^^^^^^^^^^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `if let` - --> tests/ui/collapsible_match.rs:288:9 + --> tests/ui/collapsible_match.rs:289:9 | LL | / if let Some(u) = a { LL | | @@ -225,7 +225,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:287:27 + --> tests/ui/collapsible_match.rs:288:27 | LL | if let Issue9647::A { a, .. } = x { | ^ replace this binding @@ -233,7 +233,7 @@ LL | if let Some(u) = a { | ^^^^^^^ with this pattern, prefixed by `a`: error: this `if let` can be collapsed into the outer `if let` - --> tests/ui/collapsible_match.rs:298:9 + --> tests/ui/collapsible_match.rs:299:9 | LL | / if let Some(u) = a { LL | | @@ -243,7 +243,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:297:35 + --> tests/ui/collapsible_match.rs:298:35 | LL | if let Issue9647::A { a: Some(a), .. } = x { | ^ replace this binding diff --git a/tests/ui/comparison_to_empty.fixed b/tests/ui/comparison_to_empty.fixed index dfbb616838402..7a71829dd62cc 100644 --- a/tests/ui/comparison_to_empty.fixed +++ b/tests/ui/comparison_to_empty.fixed @@ -1,6 +1,5 @@ #![warn(clippy::comparison_to_empty)] #![allow(clippy::borrow_deref_ref, clippy::needless_if, clippy::useless_vec)] -#![feature(let_chains)] fn main() { // Disallow comparisons to empty diff --git a/tests/ui/comparison_to_empty.rs b/tests/ui/comparison_to_empty.rs index 61cdb2bbe9f81..5d213a09e8126 100644 --- a/tests/ui/comparison_to_empty.rs +++ b/tests/ui/comparison_to_empty.rs @@ -1,6 +1,5 @@ #![warn(clippy::comparison_to_empty)] #![allow(clippy::borrow_deref_ref, clippy::needless_if, clippy::useless_vec)] -#![feature(let_chains)] fn main() { // Disallow comparisons to empty diff --git a/tests/ui/comparison_to_empty.stderr b/tests/ui/comparison_to_empty.stderr index 00a50430a3eea..deb3e93887846 100644 --- a/tests/ui/comparison_to_empty.stderr +++ b/tests/ui/comparison_to_empty.stderr @@ -1,5 +1,5 @@ error: comparison to empty slice - --> tests/ui/comparison_to_empty.rs:8:13 + --> tests/ui/comparison_to_empty.rs:7:13 | LL | let _ = s == ""; | ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` @@ -8,73 +8,73 @@ LL | let _ = s == ""; = help: to override `-D warnings` add `#[allow(clippy::comparison_to_empty)]` error: comparison to empty slice - --> tests/ui/comparison_to_empty.rs:10:13 + --> tests/ui/comparison_to_empty.rs:9:13 | LL | let _ = s != ""; | ^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!s.is_empty()` error: comparison to empty slice - --> tests/ui/comparison_to_empty.rs:14:13 + --> tests/ui/comparison_to_empty.rs:13:13 | LL | let _ = v == []; | ^^^^^^^ help: using `is_empty` is clearer and more explicit: `v.is_empty()` error: comparison to empty slice - --> tests/ui/comparison_to_empty.rs:16:13 + --> tests/ui/comparison_to_empty.rs:15:13 | LL | let _ = v != []; | ^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!v.is_empty()` error: comparison to empty slice using `if let` - --> tests/ui/comparison_to_empty.rs:18:8 + --> tests/ui/comparison_to_empty.rs:17:8 | LL | if let [] = &*v {} | ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(*v).is_empty()` error: comparison to empty slice using `if let` - --> tests/ui/comparison_to_empty.rs:21:8 + --> tests/ui/comparison_to_empty.rs:20:8 | LL | if let [] = s {} | ^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` error: comparison to empty slice using `if let` - --> tests/ui/comparison_to_empty.rs:23:8 + --> tests/ui/comparison_to_empty.rs:22:8 | LL | if let [] = &*s {} | ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` error: comparison to empty slice using `if let` - --> tests/ui/comparison_to_empty.rs:25:8 + --> tests/ui/comparison_to_empty.rs:24:8 | LL | if let [] = &*s | ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` error: comparison to empty slice - --> tests/ui/comparison_to_empty.rs:27:12 + --> tests/ui/comparison_to_empty.rs:26:12 | LL | && s == [] | ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` error: comparison to empty slice - --> tests/ui/comparison_to_empty.rs:48:13 + --> tests/ui/comparison_to_empty.rs:47:13 | LL | let _ = s.eq(""); | ^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` error: comparison to empty slice - --> tests/ui/comparison_to_empty.rs:50:13 + --> tests/ui/comparison_to_empty.rs:49:13 | LL | let _ = s.ne(""); | ^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!s.is_empty()` error: comparison to empty slice - --> tests/ui/comparison_to_empty.rs:53:13 + --> tests/ui/comparison_to_empty.rs:52:13 | LL | let _ = v.eq(&[]); | ^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `v.is_empty()` error: comparison to empty slice - --> tests/ui/comparison_to_empty.rs:55:13 + --> tests/ui/comparison_to_empty.rs:54:13 | LL | let _ = v.ne(&[]); | ^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!v.is_empty()` diff --git a/tests/ui/confusing_method_to_numeric_cast.fixed b/tests/ui/confusing_method_to_numeric_cast.fixed new file mode 100644 index 0000000000000..e698b99edd5c0 --- /dev/null +++ b/tests/ui/confusing_method_to_numeric_cast.fixed @@ -0,0 +1,14 @@ +#![feature(float_minimum_maximum)] +#![warn(clippy::confusing_method_to_numeric_cast)] + +fn main() { + let _ = u16::MAX as usize; //~ confusing_method_to_numeric_cast + let _ = u16::MIN as usize; //~ confusing_method_to_numeric_cast + let _ = u16::MAX as usize; //~ confusing_method_to_numeric_cast + let _ = u16::MIN as usize; //~ confusing_method_to_numeric_cast + + let _ = f32::MAX as usize; //~ confusing_method_to_numeric_cast + let _ = f32::MAX as usize; //~ confusing_method_to_numeric_cast + let _ = f32::MIN as usize; //~ confusing_method_to_numeric_cast + let _ = f32::MIN as usize; //~ confusing_method_to_numeric_cast +} diff --git a/tests/ui/confusing_method_to_numeric_cast.rs b/tests/ui/confusing_method_to_numeric_cast.rs new file mode 100644 index 0000000000000..ef65c21563d98 --- /dev/null +++ b/tests/ui/confusing_method_to_numeric_cast.rs @@ -0,0 +1,14 @@ +#![feature(float_minimum_maximum)] +#![warn(clippy::confusing_method_to_numeric_cast)] + +fn main() { + let _ = u16::max as usize; //~ confusing_method_to_numeric_cast + let _ = u16::min as usize; //~ confusing_method_to_numeric_cast + let _ = u16::max_value as usize; //~ confusing_method_to_numeric_cast + let _ = u16::min_value as usize; //~ confusing_method_to_numeric_cast + + let _ = f32::maximum as usize; //~ confusing_method_to_numeric_cast + let _ = f32::max as usize; //~ confusing_method_to_numeric_cast + let _ = f32::minimum as usize; //~ confusing_method_to_numeric_cast + let _ = f32::min as usize; //~ confusing_method_to_numeric_cast +} diff --git a/tests/ui/confusing_method_to_numeric_cast.stderr b/tests/ui/confusing_method_to_numeric_cast.stderr new file mode 100644 index 0000000000000..ba90df2059af6 --- /dev/null +++ b/tests/ui/confusing_method_to_numeric_cast.stderr @@ -0,0 +1,100 @@ +error: casting function pointer `u16::max` to `usize` + --> tests/ui/confusing_method_to_numeric_cast.rs:5:13 + | +LL | let _ = u16::max as usize; + | ^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::confusing-method-to-numeric-cast` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::confusing_method_to_numeric_cast)]` +help: did you mean to use the associated constant? + | +LL - let _ = u16::max as usize; +LL + let _ = u16::MAX as usize; + | + +error: casting function pointer `u16::min` to `usize` + --> tests/ui/confusing_method_to_numeric_cast.rs:6:13 + | +LL | let _ = u16::min as usize; + | ^^^^^^^^^^^^^^^^^ + | +help: did you mean to use the associated constant? + | +LL - let _ = u16::min as usize; +LL + let _ = u16::MIN as usize; + | + +error: casting function pointer `u16::max_value` to `usize` + --> tests/ui/confusing_method_to_numeric_cast.rs:7:13 + | +LL | let _ = u16::max_value as usize; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: did you mean to use the associated constant? + | +LL - let _ = u16::max_value as usize; +LL + let _ = u16::MAX as usize; + | + +error: casting function pointer `u16::min_value` to `usize` + --> tests/ui/confusing_method_to_numeric_cast.rs:8:13 + | +LL | let _ = u16::min_value as usize; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: did you mean to use the associated constant? + | +LL - let _ = u16::min_value as usize; +LL + let _ = u16::MIN as usize; + | + +error: casting function pointer `f32::maximum` to `usize` + --> tests/ui/confusing_method_to_numeric_cast.rs:10:13 + | +LL | let _ = f32::maximum as usize; + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: did you mean to use the associated constant? + | +LL - let _ = f32::maximum as usize; +LL + let _ = f32::MAX as usize; + | + +error: casting function pointer `f32::max` to `usize` + --> tests/ui/confusing_method_to_numeric_cast.rs:11:13 + | +LL | let _ = f32::max as usize; + | ^^^^^^^^^^^^^^^^^ + | +help: did you mean to use the associated constant? + | +LL - let _ = f32::max as usize; +LL + let _ = f32::MAX as usize; + | + +error: casting function pointer `f32::minimum` to `usize` + --> tests/ui/confusing_method_to_numeric_cast.rs:12:13 + | +LL | let _ = f32::minimum as usize; + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: did you mean to use the associated constant? + | +LL - let _ = f32::minimum as usize; +LL + let _ = f32::MIN as usize; + | + +error: casting function pointer `f32::min` to `usize` + --> tests/ui/confusing_method_to_numeric_cast.rs:13:13 + | +LL | let _ = f32::min as usize; + | ^^^^^^^^^^^^^^^^^ + | +help: did you mean to use the associated constant? + | +LL - let _ = f32::min as usize; +LL + let _ = f32::MIN as usize; + | + +error: aborting due to 8 previous errors + diff --git a/tests/ui/crashes/missing_const_for_fn_14774.fixed b/tests/ui/crashes/missing_const_for_fn_14774.fixed new file mode 100644 index 0000000000000..9c85c4b846489 --- /dev/null +++ b/tests/ui/crashes/missing_const_for_fn_14774.fixed @@ -0,0 +1,13 @@ +//@compile-flags: -Z validate-mir +#![warn(clippy::missing_const_for_fn)] + +static BLOCK_FN_DEF: fn(usize) -> usize = { + //~v missing_const_for_fn + const fn foo(a: usize) -> usize { + a + 10 + } + foo +}; +struct X; + +fn main() {} diff --git a/tests/ui/crashes/missing_const_for_fn_14774.rs b/tests/ui/crashes/missing_const_for_fn_14774.rs new file mode 100644 index 0000000000000..6519be61256e6 --- /dev/null +++ b/tests/ui/crashes/missing_const_for_fn_14774.rs @@ -0,0 +1,13 @@ +//@compile-flags: -Z validate-mir +#![warn(clippy::missing_const_for_fn)] + +static BLOCK_FN_DEF: fn(usize) -> usize = { + //~v missing_const_for_fn + fn foo(a: usize) -> usize { + a + 10 + } + foo +}; +struct X; + +fn main() {} diff --git a/tests/ui/crashes/missing_const_for_fn_14774.stderr b/tests/ui/crashes/missing_const_for_fn_14774.stderr new file mode 100644 index 0000000000000..a407376d0b9d9 --- /dev/null +++ b/tests/ui/crashes/missing_const_for_fn_14774.stderr @@ -0,0 +1,17 @@ +error: this could be a `const fn` + --> tests/ui/crashes/missing_const_for_fn_14774.rs:6:5 + | +LL | / fn foo(a: usize) -> usize { +LL | | a + 10 +LL | | } + | |_____^ + | + = note: `-D clippy::missing-const-for-fn` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_const_for_fn)]` +help: make the function `const` + | +LL | const fn foo(a: usize) -> usize { + | +++++ + +error: aborting due to 1 previous error + diff --git a/tests/ui/enum_variants.rs b/tests/ui/enum_variants.rs index f7bbf83654f11..18c80c7aba43d 100644 --- a/tests/ui/enum_variants.rs +++ b/tests/ui/enum_variants.rs @@ -220,4 +220,19 @@ mod issue11494 { } } +mod encapsulated { + mod types { + pub struct FooError; + pub struct BarError; + pub struct BazError; + } + + enum Error { + FooError(types::FooError), + BarError(types::BarError), + BazError(types::BazError), + Other, + } +} + fn main() {} diff --git a/tests/ui/index_refutable_slice/if_let_slice_binding.fixed b/tests/ui/index_refutable_slice/if_let_slice_binding.fixed index e19aa4acb4c12..050cdfcba966e 100644 --- a/tests/ui/index_refutable_slice/if_let_slice_binding.fixed +++ b/tests/ui/index_refutable_slice/if_let_slice_binding.fixed @@ -1,5 +1,5 @@ #![deny(clippy::index_refutable_slice)] -#![allow(clippy::uninlined_format_args, clippy::needless_lifetimes)] +#![allow(clippy::uninlined_format_args, clippy::needless_lifetimes, clippy::collapsible_if)] enum SomeEnum { One(T), diff --git a/tests/ui/index_refutable_slice/if_let_slice_binding.rs b/tests/ui/index_refutable_slice/if_let_slice_binding.rs index 2903935685541..91429bfea2762 100644 --- a/tests/ui/index_refutable_slice/if_let_slice_binding.rs +++ b/tests/ui/index_refutable_slice/if_let_slice_binding.rs @@ -1,5 +1,5 @@ #![deny(clippy::index_refutable_slice)] -#![allow(clippy::uninlined_format_args, clippy::needless_lifetimes)] +#![allow(clippy::uninlined_format_args, clippy::needless_lifetimes, clippy::collapsible_if)] enum SomeEnum { One(T), diff --git a/tests/ui/integer_division.rs b/tests/ui/integer_division.rs index 632fedc9e8fe3..a40956e2672e3 100644 --- a/tests/ui/integer_division.rs +++ b/tests/ui/integer_division.rs @@ -1,5 +1,9 @@ #![warn(clippy::integer_division)] +use std::num::NonZeroU32; + +const TWO: NonZeroU32 = NonZeroU32::new(2).unwrap(); + fn main() { let two = 2; let n = 1 / 2; @@ -12,4 +16,8 @@ fn main() { //~^ integer_division let x = 1. / 2.0; + + let a = 1; + let s = a / TWO; + //~^ integer_division } diff --git a/tests/ui/integer_division.stderr b/tests/ui/integer_division.stderr index 0fe2021a1a9ca..c0e34a562f652 100644 --- a/tests/ui/integer_division.stderr +++ b/tests/ui/integer_division.stderr @@ -1,5 +1,5 @@ error: integer division - --> tests/ui/integer_division.rs:5:13 + --> tests/ui/integer_division.rs:9:13 | LL | let n = 1 / 2; | ^^^^^ @@ -9,7 +9,7 @@ LL | let n = 1 / 2; = help: to override `-D warnings` add `#[allow(clippy::integer_division)]` error: integer division - --> tests/ui/integer_division.rs:8:13 + --> tests/ui/integer_division.rs:12:13 | LL | let o = 1 / two; | ^^^^^^^ @@ -17,12 +17,20 @@ LL | let o = 1 / two; = help: division of integers may cause loss of precision. consider using floats error: integer division - --> tests/ui/integer_division.rs:11:13 + --> tests/ui/integer_division.rs:15:13 | LL | let p = two / 4; | ^^^^^^^ | = help: division of integers may cause loss of precision. consider using floats -error: aborting due to 3 previous errors +error: integer division + --> tests/ui/integer_division.rs:21:13 + | +LL | let s = a / TWO; + | ^^^^^^^ + | + = help: division of integers may cause loss of precision. consider using floats + +error: aborting due to 4 previous errors diff --git a/tests/ui/let_underscore_untyped.rs b/tests/ui/let_underscore_untyped.rs index 26ba8682dc2d5..7f74ab035bda8 100644 --- a/tests/ui/let_underscore_untyped.rs +++ b/tests/ui/let_underscore_untyped.rs @@ -6,7 +6,6 @@ extern crate proc_macros; use proc_macros::with_span; -use clippy_utils::is_from_proc_macro; use std::boxed::Box; use std::fmt::Display; use std::future::Future; diff --git a/tests/ui/let_underscore_untyped.stderr b/tests/ui/let_underscore_untyped.stderr index 86cdd5c662cc1..54b955ac3a561 100644 --- a/tests/ui/let_underscore_untyped.stderr +++ b/tests/ui/let_underscore_untyped.stderr @@ -1,11 +1,11 @@ error: non-binding `let` without a type annotation - --> tests/ui/let_underscore_untyped.rs:51:5 + --> tests/ui/let_underscore_untyped.rs:50:5 | LL | let _ = a(); | ^^^^^^^^^^^^ | help: consider adding a type annotation - --> tests/ui/let_underscore_untyped.rs:51:10 + --> tests/ui/let_underscore_untyped.rs:50:10 | LL | let _ = a(); | ^ @@ -13,49 +13,49 @@ LL | let _ = a(); = help: to override `-D warnings` add `#[allow(clippy::let_underscore_untyped)]` error: non-binding `let` without a type annotation - --> tests/ui/let_underscore_untyped.rs:53:5 + --> tests/ui/let_underscore_untyped.rs:52:5 | LL | let _ = b(1); | ^^^^^^^^^^^^^ | help: consider adding a type annotation - --> tests/ui/let_underscore_untyped.rs:53:10 + --> tests/ui/let_underscore_untyped.rs:52:10 | LL | let _ = b(1); | ^ error: non-binding `let` without a type annotation - --> tests/ui/let_underscore_untyped.rs:56:5 + --> tests/ui/let_underscore_untyped.rs:55:5 | LL | let _ = d(&1); | ^^^^^^^^^^^^^^ | help: consider adding a type annotation - --> tests/ui/let_underscore_untyped.rs:56:10 + --> tests/ui/let_underscore_untyped.rs:55:10 | LL | let _ = d(&1); | ^ error: non-binding `let` without a type annotation - --> tests/ui/let_underscore_untyped.rs:58:5 + --> tests/ui/let_underscore_untyped.rs:57:5 | LL | let _ = e(); | ^^^^^^^^^^^^ | help: consider adding a type annotation - --> tests/ui/let_underscore_untyped.rs:58:10 + --> tests/ui/let_underscore_untyped.rs:57:10 | LL | let _ = e(); | ^ error: non-binding `let` without a type annotation - --> tests/ui/let_underscore_untyped.rs:60:5 + --> tests/ui/let_underscore_untyped.rs:59:5 | LL | let _ = f(); | ^^^^^^^^^^^^ | help: consider adding a type annotation - --> tests/ui/let_underscore_untyped.rs:60:10 + --> tests/ui/let_underscore_untyped.rs:59:10 | LL | let _ = f(); | ^ diff --git a/tests/ui/let_with_type_underscore.fixed b/tests/ui/let_with_type_underscore.fixed new file mode 100644 index 0000000000000..7a4af4e3d1e7f --- /dev/null +++ b/tests/ui/let_with_type_underscore.fixed @@ -0,0 +1,47 @@ +//@aux-build: proc_macros.rs +#![allow(unused)] +#![warn(clippy::let_with_type_underscore)] +#![allow(clippy::let_unit_value, clippy::needless_late_init)] + +extern crate proc_macros; + +fn func() -> &'static str { + "" +} + +#[rustfmt::skip] +fn main() { + // Will lint + let x = 1; + //~^ let_with_type_underscore + let _ = 2; + //~^ let_with_type_underscore + let x = func(); + //~^ let_with_type_underscore + let x; + //~^ let_with_type_underscore + x = (); + + let x = 1; // Will not lint, Rust infers this to an integer before Clippy + let x = func(); + let x: Vec<_> = Vec::::new(); + let x: [_; 1] = [1]; + let x = 1; + //~^ let_with_type_underscore + + // Do not lint from procedural macros + proc_macros::with_span! { + span + let x: _ = (); + // Late initialization + let x: _; + x = (); + // Ensure weird formatting will not break it (hopefully) + let x : _ = 1; + let x +: _ = 1; + let x : + _; + x = (); + }; +} diff --git a/tests/ui/let_with_type_underscore.stderr b/tests/ui/let_with_type_underscore.stderr index 2284d1fe2e48a..9179f99220718 100644 --- a/tests/ui/let_with_type_underscore.stderr +++ b/tests/ui/let_with_type_underscore.stderr @@ -4,13 +4,13 @@ error: variable declared with type underscore LL | let x: _ = 1; | ^^^^^^^^^^^^^ | -help: remove the explicit type `_` declaration - --> tests/ui/let_with_type_underscore.rs:15:10 - | -LL | let x: _ = 1; - | ^^^ = note: `-D clippy::let-with-type-underscore` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::let_with_type_underscore)]` +help: remove the explicit type `_` declaration + | +LL - let x: _ = 1; +LL + let x = 1; + | error: variable declared with type underscore --> tests/ui/let_with_type_underscore.rs:17:5 @@ -19,10 +19,10 @@ LL | let _: _ = 2; | ^^^^^^^^^^^^^ | help: remove the explicit type `_` declaration - --> tests/ui/let_with_type_underscore.rs:17:10 | -LL | let _: _ = 2; - | ^^^ +LL - let _: _ = 2; +LL + let _ = 2; + | error: variable declared with type underscore --> tests/ui/let_with_type_underscore.rs:19:5 @@ -31,10 +31,10 @@ LL | let x: _ = func(); | ^^^^^^^^^^^^^^^^^^ | help: remove the explicit type `_` declaration - --> tests/ui/let_with_type_underscore.rs:19:10 | -LL | let x: _ = func(); - | ^^^ +LL - let x: _ = func(); +LL + let x = func(); + | error: variable declared with type underscore --> tests/ui/let_with_type_underscore.rs:21:5 @@ -43,10 +43,10 @@ LL | let x: _; | ^^^^^^^^^ | help: remove the explicit type `_` declaration - --> tests/ui/let_with_type_underscore.rs:21:10 | -LL | let x: _; - | ^^^ +LL - let x: _; +LL + let x; + | error: variable declared with type underscore --> tests/ui/let_with_type_underscore.rs:29:5 @@ -55,10 +55,10 @@ LL | let x : _ = 1; | ^^^^^^^^^^^^^^ | help: remove the explicit type `_` declaration - --> tests/ui/let_with_type_underscore.rs:29:10 | -LL | let x : _ = 1; - | ^^^^ +LL - let x : _ = 1; +LL + let x = 1; + | error: aborting due to 5 previous errors diff --git a/tests/ui/manual_let_else.rs b/tests/ui/manual_let_else.rs index a753566b34cb0..3781ba1676f5e 100644 --- a/tests/ui/manual_let_else.rs +++ b/tests/ui/manual_let_else.rs @@ -514,3 +514,35 @@ mod issue13768 { }; } } + +mod issue14598 { + fn bar() -> Result { + let value = match foo() { + //~^ manual_let_else + Err(_) => return Err("abc"), + Ok(value) => value, + }; + + let w = Some(0); + let v = match w { + //~^ manual_let_else + None => return Err("abc"), + Some(x) => x, + }; + + enum Foo { + Foo(T), + } + + let v = match Foo::Foo(Some(())) { + Foo::Foo(Some(_)) => return Err("abc"), + Foo::Foo(v) => v, + }; + + Ok(value == 42) + } + + fn foo() -> Result { + todo!() + } +} diff --git a/tests/ui/manual_let_else.stderr b/tests/ui/manual_let_else.stderr index ef0421921141e..a1eea04192919 100644 --- a/tests/ui/manual_let_else.stderr +++ b/tests/ui/manual_let_else.stderr @@ -529,5 +529,25 @@ LL + return; LL + }; | -error: aborting due to 33 previous errors +error: this could be rewritten as `let...else` + --> tests/ui/manual_let_else.rs:520:9 + | +LL | / let value = match foo() { +LL | | +LL | | Err(_) => return Err("abc"), +LL | | Ok(value) => value, +LL | | }; + | |__________^ help: consider writing: `let Ok(value) = foo() else { return Err("abc") };` + +error: this could be rewritten as `let...else` + --> tests/ui/manual_let_else.rs:527:9 + | +LL | / let v = match w { +LL | | +LL | | None => return Err("abc"), +LL | | Some(x) => x, +LL | | }; + | |__________^ help: consider writing: `let Some(v) = w else { return Err("abc") };` + +error: aborting due to 35 previous errors diff --git a/tests/ui/manual_saturating_arithmetic.fixed b/tests/ui/manual_saturating_arithmetic.fixed index 3f73d6e5a1a67..304be05f6c4cf 100644 --- a/tests/ui/manual_saturating_arithmetic.fixed +++ b/tests/ui/manual_saturating_arithmetic.fixed @@ -1,7 +1,5 @@ #![allow(clippy::legacy_numeric_constants, unused_imports)] -use std::{i32, i128, u32, u128}; - fn main() { let _ = 1u32.saturating_add(1); //~^ manual_saturating_arithmetic diff --git a/tests/ui/manual_saturating_arithmetic.rs b/tests/ui/manual_saturating_arithmetic.rs index 98246a5cd96ca..c2b570e974ac8 100644 --- a/tests/ui/manual_saturating_arithmetic.rs +++ b/tests/ui/manual_saturating_arithmetic.rs @@ -1,7 +1,5 @@ #![allow(clippy::legacy_numeric_constants, unused_imports)] -use std::{i32, i128, u32, u128}; - fn main() { let _ = 1u32.checked_add(1).unwrap_or(u32::max_value()); //~^ manual_saturating_arithmetic diff --git a/tests/ui/manual_saturating_arithmetic.stderr b/tests/ui/manual_saturating_arithmetic.stderr index 9d133d8a073b4..2f006a3ae1702 100644 --- a/tests/ui/manual_saturating_arithmetic.stderr +++ b/tests/ui/manual_saturating_arithmetic.stderr @@ -1,5 +1,5 @@ error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:6:13 + --> tests/ui/manual_saturating_arithmetic.rs:4:13 | LL | let _ = 1u32.checked_add(1).unwrap_or(u32::max_value()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1u32.saturating_add(1)` @@ -8,19 +8,19 @@ LL | let _ = 1u32.checked_add(1).unwrap_or(u32::max_value()); = help: to override `-D warnings` add `#[allow(clippy::manual_saturating_arithmetic)]` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:8:13 + --> tests/ui/manual_saturating_arithmetic.rs:6:13 | LL | let _ = 1u32.checked_add(1).unwrap_or(u32::MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1u32.saturating_add(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:10:13 + --> tests/ui/manual_saturating_arithmetic.rs:8:13 | LL | let _ = 1u8.checked_add(1).unwrap_or(255); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1u8.saturating_add(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:12:13 + --> tests/ui/manual_saturating_arithmetic.rs:10:13 | LL | let _ = 1u128 | _____________^ @@ -30,49 +30,49 @@ LL | | .unwrap_or(340_282_366_920_938_463_463_374_607_431_768_211_455); | |_______________________________________________________________________^ help: consider using `saturating_add`: `1u128.saturating_add(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:18:13 + --> tests/ui/manual_saturating_arithmetic.rs:16:13 | LL | let _ = 1u32.checked_mul(1).unwrap_or(u32::MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_mul`: `1u32.saturating_mul(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:21:13 + --> tests/ui/manual_saturating_arithmetic.rs:19:13 | LL | let _ = 1u32.checked_sub(1).unwrap_or(u32::min_value()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1u32.saturating_sub(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:23:13 + --> tests/ui/manual_saturating_arithmetic.rs:21:13 | LL | let _ = 1u32.checked_sub(1).unwrap_or(u32::MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1u32.saturating_sub(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:25:13 + --> tests/ui/manual_saturating_arithmetic.rs:23:13 | LL | let _ = 1u8.checked_sub(1).unwrap_or(0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1u8.saturating_sub(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:30:13 + --> tests/ui/manual_saturating_arithmetic.rs:28:13 | LL | let _ = 1i32.checked_add(1).unwrap_or(i32::max_value()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i32.saturating_add(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:32:13 + --> tests/ui/manual_saturating_arithmetic.rs:30:13 | LL | let _ = 1i32.checked_add(1).unwrap_or(i32::MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i32.saturating_add(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:34:13 + --> tests/ui/manual_saturating_arithmetic.rs:32:13 | LL | let _ = 1i8.checked_add(1).unwrap_or(127); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i8.saturating_add(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:36:13 + --> tests/ui/manual_saturating_arithmetic.rs:34:13 | LL | let _ = 1i128 | _____________^ @@ -82,25 +82,25 @@ LL | | .unwrap_or(170_141_183_460_469_231_731_687_303_715_884_105_727); | |_______________________________________________________________________^ help: consider using `saturating_add`: `1i128.saturating_add(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:40:13 + --> tests/ui/manual_saturating_arithmetic.rs:38:13 | LL | let _ = 1i32.checked_add(-1).unwrap_or(i32::min_value()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i32.saturating_add(-1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:42:13 + --> tests/ui/manual_saturating_arithmetic.rs:40:13 | LL | let _ = 1i32.checked_add(-1).unwrap_or(i32::MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i32.saturating_add(-1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:44:13 + --> tests/ui/manual_saturating_arithmetic.rs:42:13 | LL | let _ = 1i8.checked_add(-1).unwrap_or(-128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i8.saturating_add(-1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:46:13 + --> tests/ui/manual_saturating_arithmetic.rs:44:13 | LL | let _ = 1i128 | _____________^ @@ -110,25 +110,25 @@ LL | | .unwrap_or(-170_141_183_460_469_231_731_687_303_715_884_105_728); | |________________________________________________________________________^ help: consider using `saturating_add`: `1i128.saturating_add(-1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:54:13 + --> tests/ui/manual_saturating_arithmetic.rs:52:13 | LL | let _ = 1i32.checked_sub(1).unwrap_or(i32::min_value()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i32.saturating_sub(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:56:13 + --> tests/ui/manual_saturating_arithmetic.rs:54:13 | LL | let _ = 1i32.checked_sub(1).unwrap_or(i32::MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i32.saturating_sub(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:58:13 + --> tests/ui/manual_saturating_arithmetic.rs:56:13 | LL | let _ = 1i8.checked_sub(1).unwrap_or(-128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i8.saturating_sub(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:60:13 + --> tests/ui/manual_saturating_arithmetic.rs:58:13 | LL | let _ = 1i128 | _____________^ @@ -138,25 +138,25 @@ LL | | .unwrap_or(-170_141_183_460_469_231_731_687_303_715_884_105_728); | |________________________________________________________________________^ help: consider using `saturating_sub`: `1i128.saturating_sub(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:64:13 + --> tests/ui/manual_saturating_arithmetic.rs:62:13 | LL | let _ = 1i32.checked_sub(-1).unwrap_or(i32::max_value()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i32.saturating_sub(-1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:66:13 + --> tests/ui/manual_saturating_arithmetic.rs:64:13 | LL | let _ = 1i32.checked_sub(-1).unwrap_or(i32::MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i32.saturating_sub(-1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:68:13 + --> tests/ui/manual_saturating_arithmetic.rs:66:13 | LL | let _ = 1i8.checked_sub(-1).unwrap_or(127); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i8.saturating_sub(-1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:70:13 + --> tests/ui/manual_saturating_arithmetic.rs:68:13 | LL | let _ = 1i128 | _____________^ diff --git a/tests/ui/manual_slice_fill.fixed b/tests/ui/manual_slice_fill.fixed index bba863247f5d3..d07d1d60e2c16 100644 --- a/tests/ui/manual_slice_fill.fixed +++ b/tests/ui/manual_slice_fill.fixed @@ -123,3 +123,40 @@ fn issue14189() { *b = !*b; } } + +mod issue14685 { + use std::ops::{Index, IndexMut}; + + #[derive(Clone)] + struct ZipList(T); + + impl ZipList { + fn len(&self) -> usize { + todo!() + } + + fn is_empty(&self) -> bool { + todo!() + } + } + + impl Index for ZipList { + type Output = T; + + fn index(&self, _: usize) -> &Self::Output { + todo!() + } + } + + impl IndexMut for ZipList { + fn index_mut(&mut self, _: usize) -> &mut Self::Output { + todo!() + } + } + + fn index_mut(mut zl: ZipList) { + for i in 0..zl.len() { + zl[i] = 6; + } + } +} diff --git a/tests/ui/manual_slice_fill.rs b/tests/ui/manual_slice_fill.rs index 44c60dc40f074..c74ab2225c0a4 100644 --- a/tests/ui/manual_slice_fill.rs +++ b/tests/ui/manual_slice_fill.rs @@ -136,3 +136,40 @@ fn issue14189() { *b = !*b; } } + +mod issue14685 { + use std::ops::{Index, IndexMut}; + + #[derive(Clone)] + struct ZipList(T); + + impl ZipList { + fn len(&self) -> usize { + todo!() + } + + fn is_empty(&self) -> bool { + todo!() + } + } + + impl Index for ZipList { + type Output = T; + + fn index(&self, _: usize) -> &Self::Output { + todo!() + } + } + + impl IndexMut for ZipList { + fn index_mut(&mut self, _: usize) -> &mut Self::Output { + todo!() + } + } + + fn index_mut(mut zl: ZipList) { + for i in 0..zl.len() { + zl[i] = 6; + } + } +} diff --git a/tests/ui/manual_unwrap_or_default.fixed b/tests/ui/manual_unwrap_or_default.fixed index 9dae9fcae079b..41ca44ceef4e6 100644 --- a/tests/ui/manual_unwrap_or_default.fixed +++ b/tests/ui/manual_unwrap_or_default.fixed @@ -106,3 +106,16 @@ fn issue_12928() { fn allowed_manual_unwrap_or_zero() -> u32 { Some(42).unwrap_or_default() } + +mod issue14716 { + struct Foo { + name: Option, + } + + fn bar(project: &Foo) { + let _name = match project.name { + Some(ref x) => x, + None => "", + }; + } +} diff --git a/tests/ui/manual_unwrap_or_default.rs b/tests/ui/manual_unwrap_or_default.rs index 539d7a8bbae59..343fbc4879ce6 100644 --- a/tests/ui/manual_unwrap_or_default.rs +++ b/tests/ui/manual_unwrap_or_default.rs @@ -147,3 +147,16 @@ fn allowed_manual_unwrap_or_zero() -> u32 { 0 } } + +mod issue14716 { + struct Foo { + name: Option, + } + + fn bar(project: &Foo) { + let _name = match project.name { + Some(ref x) => x, + None => "", + }; + } +} diff --git a/tests/ui/needless_if.fixed b/tests/ui/needless_if.fixed index 347dbff7c595c..c839156bed9bd 100644 --- a/tests/ui/needless_if.fixed +++ b/tests/ui/needless_if.fixed @@ -1,5 +1,4 @@ //@aux-build:proc_macros.rs -#![feature(let_chains)] #![allow( clippy::blocks_in_conditions, clippy::if_same_then_else, diff --git a/tests/ui/needless_if.rs b/tests/ui/needless_if.rs index 5e0f2a14408bc..11103af5c5598 100644 --- a/tests/ui/needless_if.rs +++ b/tests/ui/needless_if.rs @@ -1,5 +1,4 @@ //@aux-build:proc_macros.rs -#![feature(let_chains)] #![allow( clippy::blocks_in_conditions, clippy::if_same_then_else, diff --git a/tests/ui/needless_if.stderr b/tests/ui/needless_if.stderr index 62cdf2459448d..4b56843bd5229 100644 --- a/tests/ui/needless_if.stderr +++ b/tests/ui/needless_if.stderr @@ -1,5 +1,5 @@ error: this `if` branch is empty - --> tests/ui/needless_if.rs:27:5 + --> tests/ui/needless_if.rs:26:5 | LL | if (true) {} | ^^^^^^^^^^^^ help: you can remove it @@ -8,13 +8,13 @@ LL | if (true) {} = help: to override `-D warnings` add `#[allow(clippy::needless_if)]` error: this `if` branch is empty - --> tests/ui/needless_if.rs:30:5 + --> tests/ui/needless_if.rs:29:5 | LL | if maybe_side_effect() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `maybe_side_effect();` error: this `if` branch is empty - --> tests/ui/needless_if.rs:36:5 + --> tests/ui/needless_if.rs:35:5 | LL | / if { LL | | @@ -31,7 +31,7 @@ LL + }); | error: this `if` branch is empty - --> tests/ui/needless_if.rs:51:5 + --> tests/ui/needless_if.rs:50:5 | LL | / if { LL | | @@ -57,19 +57,19 @@ LL + } && true); | error: this `if` branch is empty - --> tests/ui/needless_if.rs:96:5 + --> tests/ui/needless_if.rs:95:5 | LL | if { maybe_side_effect() } {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() });` error: this `if` branch is empty - --> tests/ui/needless_if.rs:99:5 + --> tests/ui/needless_if.rs:98:5 | LL | if { maybe_side_effect() } && true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() } && true);` error: this `if` branch is empty - --> tests/ui/needless_if.rs:104:5 + --> tests/ui/needless_if.rs:103:5 | LL | if true {} | ^^^^^^^^^^ help: you can remove it: `true;` diff --git a/tests/ui/needless_late_init.fixed b/tests/ui/needless_late_init.fixed index f832752ccd798..b686a8e9f1a06 100644 --- a/tests/ui/needless_late_init.fixed +++ b/tests/ui/needless_late_init.fixed @@ -1,6 +1,4 @@ //@aux-build:proc_macros.rs -#![feature(let_chains)] -#![allow(unused)] #![allow( clippy::assign_op_pattern, clippy::blocks_in_conditions, diff --git a/tests/ui/needless_late_init.rs b/tests/ui/needless_late_init.rs index a52fbf5292344..23772ff702931 100644 --- a/tests/ui/needless_late_init.rs +++ b/tests/ui/needless_late_init.rs @@ -1,6 +1,4 @@ //@aux-build:proc_macros.rs -#![feature(let_chains)] -#![allow(unused)] #![allow( clippy::assign_op_pattern, clippy::blocks_in_conditions, diff --git a/tests/ui/needless_late_init.stderr b/tests/ui/needless_late_init.stderr index b24c127588162..e3e25cdc8d769 100644 --- a/tests/ui/needless_late_init.stderr +++ b/tests/ui/needless_late_init.stderr @@ -1,5 +1,5 @@ error: unneeded late initialization - --> tests/ui/needless_late_init.rs:27:5 + --> tests/ui/needless_late_init.rs:25:5 | LL | let a; | ^^^^^^ created here @@ -17,7 +17,7 @@ LL ~ let a = "zero"; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:31:5 + --> tests/ui/needless_late_init.rs:29:5 | LL | let b; | ^^^^^^ created here @@ -35,7 +35,7 @@ LL ~ let b = 1; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:33:5 + --> tests/ui/needless_late_init.rs:31:5 | LL | let c; | ^^^^^^ created here @@ -52,7 +52,7 @@ LL ~ let c = 2; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:38:5 + --> tests/ui/needless_late_init.rs:36:5 | LL | let d: usize; | ^^^^^^^^^^^^^ created here @@ -68,7 +68,7 @@ LL ~ let d: usize = 1; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:42:5 + --> tests/ui/needless_late_init.rs:40:5 | LL | let e; | ^^^^^^ created here @@ -84,7 +84,7 @@ LL ~ let e = format!("{}", d); | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:48:5 + --> tests/ui/needless_late_init.rs:46:5 | LL | let a; | ^^^^^^ @@ -103,7 +103,7 @@ LL ~ }; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:58:5 + --> tests/ui/needless_late_init.rs:56:5 | LL | let b; | ^^^^^^ @@ -120,7 +120,7 @@ LL ~ }; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:66:5 + --> tests/ui/needless_late_init.rs:64:5 | LL | let d; | ^^^^^^ @@ -138,7 +138,7 @@ LL ~ }; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:75:5 + --> tests/ui/needless_late_init.rs:73:5 | LL | let e; | ^^^^^^ @@ -155,7 +155,7 @@ LL ~ }; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:83:5 + --> tests/ui/needless_late_init.rs:81:5 | LL | let f; | ^^^^^^ @@ -169,7 +169,7 @@ LL ~ 1 => "three", | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:90:5 + --> tests/ui/needless_late_init.rs:88:5 | LL | let g: usize; | ^^^^^^^^^^^^^ @@ -186,7 +186,7 @@ LL ~ }; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:99:5 + --> tests/ui/needless_late_init.rs:97:5 | LL | let x; | ^^^^^^ created here @@ -203,7 +203,7 @@ LL ~ let x = 1; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:104:5 + --> tests/ui/needless_late_init.rs:102:5 | LL | let x; | ^^^^^^ created here @@ -220,7 +220,7 @@ LL ~ let x = SignificantDrop; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:109:5 + --> tests/ui/needless_late_init.rs:107:5 | LL | let x; | ^^^^^^ created here @@ -238,7 +238,7 @@ LL ~ let x = SignificantDrop; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:129:5 + --> tests/ui/needless_late_init.rs:127:5 | LL | let a; | ^^^^^^ @@ -257,7 +257,7 @@ LL ~ }; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:147:5 + --> tests/ui/needless_late_init.rs:145:5 | LL | let a; | ^^^^^^ @@ -276,7 +276,7 @@ LL ~ }; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:300:5 + --> tests/ui/needless_late_init.rs:298:5 | LL | let r; | ^^^^^^ created here diff --git a/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.fixed b/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.fixed index 2b30c8f984ebe..d6c35d8097c51 100644 --- a/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.fixed +++ b/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.fixed @@ -70,3 +70,10 @@ mod external_macros { once_cell::external!(); lazy_static::external!(); } + +mod issue14729 { + use once_cell::sync::Lazy; + + #[expect(clippy::non_std_lazy_statics)] + static LAZY_FOO: Lazy = Lazy::new(|| "foo".to_uppercase()); +} diff --git a/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs b/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs index c52338eee83cb..996ef050d6915 100644 --- a/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs +++ b/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs @@ -70,3 +70,10 @@ mod external_macros { once_cell::external!(); lazy_static::external!(); } + +mod issue14729 { + use once_cell::sync::Lazy; + + #[expect(clippy::non_std_lazy_statics)] + static LAZY_FOO: Lazy = Lazy::new(|| "foo".to_uppercase()); +} diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed index 33a5308bd3574..dc9d6491691f3 100644 --- a/tests/ui/redundant_pattern_matching_option.fixed +++ b/tests/ui/redundant_pattern_matching_option.fixed @@ -1,4 +1,4 @@ -#![feature(let_chains, if_let_guard)] +#![feature(if_let_guard)] #![warn(clippy::redundant_pattern_matching)] #![allow( clippy::needless_bool, diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs index 60bce2994ea3a..2e9714ad8e75f 100644 --- a/tests/ui/redundant_pattern_matching_option.rs +++ b/tests/ui/redundant_pattern_matching_option.rs @@ -1,4 +1,4 @@ -#![feature(let_chains, if_let_guard)] +#![feature(if_let_guard)] #![warn(clippy::redundant_pattern_matching)] #![allow( clippy::needless_bool, diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index acf7914d25365..55e287b91596d 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -63,6 +63,7 @@ #![allow(unused_labels)] #![allow(ambiguous_wide_pointer_comparisons)] #![allow(clippy::reversed_empty_ranges)] +#![allow(unnecessary_transmutes)] #![warn(clippy::almost_complete_range)] //~ ERROR: lint `clippy::almost_complete_letter_range` #![warn(clippy::disallowed_names)] //~ ERROR: lint `clippy::blacklisted_name` #![warn(clippy::blocks_in_conditions)] //~ ERROR: lint `clippy::block_in_if_condition_expr` @@ -132,5 +133,9 @@ #![warn(unused_labels)] //~ ERROR: lint `clippy::unused_label` #![warn(ambiguous_wide_pointer_comparisons)] //~ ERROR: lint `clippy::vtable_address_comparisons` #![warn(clippy::reversed_empty_ranges)] //~ ERROR: lint `clippy::reverse_range_loop` +#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_int_to_float` +#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_int_to_char` +#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_float_to_int` +#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_num_to_bytes` fn main() {} diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index 32641a684a44b..31dcd2cea0818 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -63,6 +63,7 @@ #![allow(unused_labels)] #![allow(ambiguous_wide_pointer_comparisons)] #![allow(clippy::reversed_empty_ranges)] +#![allow(unnecessary_transmutes)] #![warn(clippy::almost_complete_letter_range)] //~ ERROR: lint `clippy::almost_complete_letter_range` #![warn(clippy::blacklisted_name)] //~ ERROR: lint `clippy::blacklisted_name` #![warn(clippy::block_in_if_condition_expr)] //~ ERROR: lint `clippy::block_in_if_condition_expr` @@ -132,5 +133,9 @@ #![warn(clippy::unused_label)] //~ ERROR: lint `clippy::unused_label` #![warn(clippy::vtable_address_comparisons)] //~ ERROR: lint `clippy::vtable_address_comparisons` #![warn(clippy::reverse_range_loop)] //~ ERROR: lint `clippy::reverse_range_loop` +#![warn(clippy::transmute_int_to_float)] //~ ERROR: lint `clippy::transmute_int_to_float` +#![warn(clippy::transmute_int_to_char)] //~ ERROR: lint `clippy::transmute_int_to_char` +#![warn(clippy::transmute_float_to_int)] //~ ERROR: lint `clippy::transmute_float_to_int` +#![warn(clippy::transmute_num_to_bytes)] //~ ERROR: lint `clippy::transmute_num_to_bytes` fn main() {} diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index e9d2debff91a3..a8d5c96acc3a7 100644 --- a/tests/ui/rename.stderr +++ b/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range` - --> tests/ui/rename.rs:66:9 + --> tests/ui/rename.rs:67:9 | LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` @@ -8,412 +8,436 @@ LL | #![warn(clippy::almost_complete_letter_range)] = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]` error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` - --> tests/ui/rename.rs:67:9 + --> tests/ui/rename.rs:68:9 | LL | #![warn(clippy::blacklisted_name)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_conditions` - --> tests/ui/rename.rs:68:9 + --> tests/ui/rename.rs:69:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_conditions` - --> tests/ui/rename.rs:69:9 + --> tests/ui/rename.rs:70:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions` error: lint `clippy::blocks_in_if_conditions` has been renamed to `clippy::blocks_in_conditions` - --> tests/ui/rename.rs:70:9 + --> tests/ui/rename.rs:71:9 | LL | #![warn(clippy::blocks_in_if_conditions)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> tests/ui/rename.rs:71:9 + --> tests/ui/rename.rs:72:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> tests/ui/rename.rs:72:9 + --> tests/ui/rename.rs:73:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> tests/ui/rename.rs:73:9 + --> tests/ui/rename.rs:74:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq` - --> tests/ui/rename.rs:74:9 + --> tests/ui/rename.rs:75:9 | LL | #![warn(clippy::derive_hash_xor_eq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> tests/ui/rename.rs:75:9 + --> tests/ui/rename.rs:76:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> tests/ui/rename.rs:76:9 + --> tests/ui/rename.rs:77:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> tests/ui/rename.rs:77:9 + --> tests/ui/rename.rs:78:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::find_map` has been renamed to `clippy::manual_find_map` - --> tests/ui/rename.rs:78:9 + --> tests/ui/rename.rs:79:9 | LL | #![warn(clippy::find_map)] | ^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_find_map` error: lint `clippy::filter_map` has been renamed to `clippy::manual_filter_map` - --> tests/ui/rename.rs:79:9 + --> tests/ui/rename.rs:80:9 | LL | #![warn(clippy::filter_map)] | ^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_filter_map` error: lint `clippy::fn_address_comparisons` has been renamed to `unpredictable_function_pointer_comparisons` - --> tests/ui/rename.rs:80:9 + --> tests/ui/rename.rs:81:9 | LL | #![warn(clippy::fn_address_comparisons)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unpredictable_function_pointer_comparisons` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> tests/ui/rename.rs:81:9 + --> tests/ui/rename.rs:82:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_redundant_pattern_matching` has been renamed to `clippy::redundant_pattern_matching` - --> tests/ui/rename.rs:82:9 + --> tests/ui/rename.rs:83:9 | LL | #![warn(clippy::if_let_redundant_pattern_matching)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_pattern_matching` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> tests/ui/rename.rs:83:9 + --> tests/ui/rename.rs:84:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl` - --> tests/ui/rename.rs:84:9 + --> tests/ui/rename.rs:85:9 | LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl` error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl` - --> tests/ui/rename.rs:85:9 + --> tests/ui/rename.rs:86:9 | LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl` error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects` - --> tests/ui/rename.rs:86:9 + --> tests/ui/rename.rs:87:9 | LL | #![warn(clippy::integer_arithmetic)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects` error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` - --> tests/ui/rename.rs:87:9 + --> tests/ui/rename.rs:88:9 | LL | #![warn(clippy::logic_bug)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> tests/ui/rename.rs:88:9 + --> tests/ui/rename.rs:89:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> tests/ui/rename.rs:89:9 + --> tests/ui/rename.rs:90:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> tests/ui/rename.rs:90:9 + --> tests/ui/rename.rs:91:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> tests/ui/rename.rs:91:9 + --> tests/ui/rename.rs:92:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> tests/ui/rename.rs:92:9 + --> tests/ui/rename.rs:93:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> tests/ui/rename.rs:93:9 + --> tests/ui/rename.rs:94:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::overflow_check_conditional` has been renamed to `clippy::panicking_overflow_checks` - --> tests/ui/rename.rs:94:9 + --> tests/ui/rename.rs:95:9 | LL | #![warn(clippy::overflow_check_conditional)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::panicking_overflow_checks` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> tests/ui/rename.rs:95:9 + --> tests/ui/rename.rs:96:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> tests/ui/rename.rs:96:9 + --> tests/ui/rename.rs:97:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> tests/ui/rename.rs:97:9 + --> tests/ui/rename.rs:98:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> tests/ui/rename.rs:98:9 + --> tests/ui/rename.rs:99:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> tests/ui/rename.rs:99:9 + --> tests/ui/rename.rs:100:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> tests/ui/rename.rs:100:9 + --> tests/ui/rename.rs:101:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::thread_local_initializer_can_be_made_const` has been renamed to `clippy::missing_const_for_thread_local` - --> tests/ui/rename.rs:101:9 + --> tests/ui/rename.rs:102:9 | LL | #![warn(clippy::thread_local_initializer_can_be_made_const)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::missing_const_for_thread_local` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> tests/ui/rename.rs:102:9 + --> tests/ui/rename.rs:103:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default` - --> tests/ui/rename.rs:103:9 + --> tests/ui/rename.rs:104:9 | LL | #![warn(clippy::unwrap_or_else_default)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> tests/ui/rename.rs:104:9 + --> tests/ui/rename.rs:105:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting` - --> tests/ui/rename.rs:105:9 + --> tests/ui/rename.rs:106:9 | LL | #![warn(clippy::cast_ref_to_mut)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting` error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op` - --> tests/ui/rename.rs:106:9 + --> tests/ui/rename.rs:107:9 | LL | #![warn(clippy::clone_double_ref)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op` error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons` - --> tests/ui/rename.rs:107:9 + --> tests/ui/rename.rs:108:9 | LL | #![warn(clippy::cmp_nan)] | ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons` error: lint `clippy::invalid_null_ptr_usage` has been renamed to `invalid_null_arguments` - --> tests/ui/rename.rs:108:9 + --> tests/ui/rename.rs:109:9 | LL | #![warn(clippy::invalid_null_ptr_usage)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_null_arguments` error: lint `clippy::double_neg` has been renamed to `double_negations` - --> tests/ui/rename.rs:109:9 + --> tests/ui/rename.rs:110:9 | LL | #![warn(clippy::double_neg)] | ^^^^^^^^^^^^^^^^^^ help: use the new name: `double_negations` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> tests/ui/rename.rs:110:9 + --> tests/ui/rename.rs:111:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types` - --> tests/ui/rename.rs:111:9 + --> tests/ui/rename.rs:112:9 | LL | #![warn(clippy::drop_copy)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types` error: lint `clippy::drop_ref` has been renamed to `dropping_references` - --> tests/ui/rename.rs:112:9 + --> tests/ui/rename.rs:113:9 | LL | #![warn(clippy::drop_ref)] | ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references` error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks` - --> tests/ui/rename.rs:113:9 + --> tests/ui/rename.rs:114:9 | LL | #![warn(clippy::fn_null_check)] | ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks` error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` - --> tests/ui/rename.rs:114:9 + --> tests/ui/rename.rs:115:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` - --> tests/ui/rename.rs:115:9 + --> tests/ui/rename.rs:116:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` - --> tests/ui/rename.rs:116:9 + --> tests/ui/rename.rs:117:9 | LL | #![warn(clippy::for_loops_over_fallibles)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types` - --> tests/ui/rename.rs:117:9 + --> tests/ui/rename.rs:118:9 | LL | #![warn(clippy::forget_copy)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types` error: lint `clippy::forget_ref` has been renamed to `forgetting_references` - --> tests/ui/rename.rs:118:9 + --> tests/ui/rename.rs:119:9 | LL | #![warn(clippy::forget_ref)] | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> tests/ui/rename.rs:119:9 + --> tests/ui/rename.rs:120:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> tests/ui/rename.rs:120:9 + --> tests/ui/rename.rs:121:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> tests/ui/rename.rs:121:9 + --> tests/ui/rename.rs:122:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked` - --> tests/ui/rename.rs:122:9 + --> tests/ui/rename.rs:123:9 | LL | #![warn(clippy::invalid_utf8_in_unchecked)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked` error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` - --> tests/ui/rename.rs:123:9 + --> tests/ui/rename.rs:124:9 | LL | #![warn(clippy::let_underscore_drop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` error: lint `clippy::maybe_misused_cfg` has been renamed to `unexpected_cfgs` - --> tests/ui/rename.rs:124:9 + --> tests/ui/rename.rs:125:9 | LL | #![warn(clippy::maybe_misused_cfg)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> tests/ui/rename.rs:125:9 + --> tests/ui/rename.rs:126:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::mismatched_target_os` has been renamed to `unexpected_cfgs` - --> tests/ui/rename.rs:126:9 + --> tests/ui/rename.rs:127:9 | LL | #![warn(clippy::mismatched_target_os)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> tests/ui/rename.rs:127:9 + --> tests/ui/rename.rs:128:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` - --> tests/ui/rename.rs:128:9 + --> tests/ui/rename.rs:129:9 | LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries` - --> tests/ui/rename.rs:129:9 + --> tests/ui/rename.rs:130:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries` error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops` - --> tests/ui/rename.rs:130:9 + --> tests/ui/rename.rs:131:9 | LL | #![warn(clippy::undropped_manually_drops)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> tests/ui/rename.rs:131:9 + --> tests/ui/rename.rs:132:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> tests/ui/rename.rs:132:9 + --> tests/ui/rename.rs:133:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons` - --> tests/ui/rename.rs:133:9 + --> tests/ui/rename.rs:134:9 | LL | #![warn(clippy::vtable_address_comparisons)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons` error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_empty_ranges` - --> tests/ui/rename.rs:134:9 + --> tests/ui/rename.rs:135:9 | LL | #![warn(clippy::reverse_range_loop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges` -error: aborting due to 69 previous errors +error: lint `clippy::transmute_int_to_float` has been renamed to `unnecessary_transmutes` + --> tests/ui/rename.rs:136:9 + | +LL | #![warn(clippy::transmute_int_to_float)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes` + +error: lint `clippy::transmute_int_to_char` has been renamed to `unnecessary_transmutes` + --> tests/ui/rename.rs:137:9 + | +LL | #![warn(clippy::transmute_int_to_char)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes` + +error: lint `clippy::transmute_float_to_int` has been renamed to `unnecessary_transmutes` + --> tests/ui/rename.rs:138:9 + | +LL | #![warn(clippy::transmute_float_to_int)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes` + +error: lint `clippy::transmute_num_to_bytes` has been renamed to `unnecessary_transmutes` + --> tests/ui/rename.rs:139:9 + | +LL | #![warn(clippy::transmute_num_to_bytes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes` + +error: aborting due to 73 previous errors diff --git a/tests/ui/return_and_then.fixed b/tests/ui/return_and_then.fixed index 74efa14eeec81..8d9481d159512 100644 --- a/tests/ui/return_and_then.fixed +++ b/tests/ui/return_and_then.fixed @@ -67,8 +67,60 @@ fn main() { .first() // creates temporary reference .and_then(|x| test_opt_block(Some(*x))) } + + fn in_closure() -> bool { + let _ = || { + let x = Some("")?; + if x.len() > 2 { Some(3) } else { None } + //~^ return_and_then + }; + true + } + + fn with_return(shortcut: bool) -> Option { + if shortcut { + return { + let x = Some("")?; + if x.len() > 2 { Some(3) } else { None } + }; + //~^ return_and_then + }; + None + } + + fn with_return_multiline(shortcut: bool) -> Option { + if shortcut { + return { + let mut x = Some("")?; + let x = format!("{x}."); + if x.len() > 2 { Some(3) } else { None } + }; + //~^^^^ return_and_then + }; + None + } } fn gen_option(n: i32) -> Option { Some(n) } + +mod issue14781 { + fn foo(_: &str, _: (u32, u32)) -> Result<(u32, u32), ()> { + Ok((1, 1)) + } + + fn bug(_: Option<&str>) -> Result<(), ()> { + let year: Option<&str> = None; + let month: Option<&str> = None; + let day: Option<&str> = None; + + let _day = if let (Some(year), Some(month)) = (year, month) { + day.and_then(|day| foo(day, (1, 31)).ok()) + } else { + None + }; + + Ok(()) + } +} diff --git a/tests/ui/return_and_then.rs b/tests/ui/return_and_then.rs index 188dc57e588cf..beada921a9187 100644 --- a/tests/ui/return_and_then.rs +++ b/tests/ui/return_and_then.rs @@ -63,8 +63,55 @@ fn main() { .first() // creates temporary reference .and_then(|x| test_opt_block(Some(*x))) } + + fn in_closure() -> bool { + let _ = || { + Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None }) + //~^ return_and_then + }; + true + } + + fn with_return(shortcut: bool) -> Option { + if shortcut { + return Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None }); + //~^ return_and_then + }; + None + } + + fn with_return_multiline(shortcut: bool) -> Option { + if shortcut { + return Some("").and_then(|mut x| { + let x = format!("{x}."); + if x.len() > 2 { Some(3) } else { None } + }); + //~^^^^ return_and_then + }; + None + } } fn gen_option(n: i32) -> Option { Some(n) } + +mod issue14781 { + fn foo(_: &str, _: (u32, u32)) -> Result<(u32, u32), ()> { + Ok((1, 1)) + } + + fn bug(_: Option<&str>) -> Result<(), ()> { + let year: Option<&str> = None; + let month: Option<&str> = None; + let day: Option<&str> = None; + + let _day = if let (Some(year), Some(month)) = (year, month) { + day.and_then(|day| foo(day, (1, 31)).ok()) + } else { + None + }; + + Ok(()) + } +} diff --git a/tests/ui/return_and_then.stderr b/tests/ui/return_and_then.stderr index a7acbe7b3401c..5feca88286057 100644 --- a/tests/ui/return_and_then.stderr +++ b/tests/ui/return_and_then.stderr @@ -101,5 +101,50 @@ LL + })?; LL + if x.len() > 2 { Some(3) } else { None } | -error: aborting due to 7 previous errors +error: use the `?` operator instead of an `and_then` call + --> tests/ui/return_and_then.rs:69:13 + | +LL | Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None }) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL ~ let x = Some("")?; +LL + if x.len() > 2 { Some(3) } else { None } + | + +error: use the `?` operator instead of an `and_then` call + --> tests/ui/return_and_then.rs:77:20 + | +LL | return Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL ~ return { +LL + let x = Some("")?; +LL + if x.len() > 2 { Some(3) } else { None } +LL ~ }; + | + +error: use the `?` operator instead of an `and_then` call + --> tests/ui/return_and_then.rs:85:20 + | +LL | return Some("").and_then(|mut x| { + | ____________________^ +LL | | let x = format!("{x}."); +LL | | if x.len() > 2 { Some(3) } else { None } +LL | | }); + | |______________^ + | +help: try + | +LL ~ return { +LL + let mut x = Some("")?; +LL + let x = format!("{x}."); +LL + if x.len() > 2 { Some(3) } else { None } +LL ~ }; + | + +error: aborting due to 10 previous errors diff --git a/tests/ui/to_digit_is_some.fixed b/tests/ui/to_digit_is_some.fixed index 627d54c5f7384..ff6b32e6bd182 100644 --- a/tests/ui/to_digit_is_some.fixed +++ b/tests/ui/to_digit_is_some.fixed @@ -9,3 +9,20 @@ fn main() { let _ = char::is_digit(c, 8); //~^ to_digit_is_some } + +#[clippy::msrv = "1.86"] +mod cannot_lint_in_const_context { + fn without_const(c: char) -> bool { + c.is_digit(8) + //~^ to_digit_is_some + } + const fn with_const(c: char) -> bool { + c.to_digit(8).is_some() + } +} + +#[clippy::msrv = "1.87"] +const fn with_const(c: char) -> bool { + c.is_digit(8) + //~^ to_digit_is_some +} diff --git a/tests/ui/to_digit_is_some.rs b/tests/ui/to_digit_is_some.rs index d4eccc9931f17..5ba0861743318 100644 --- a/tests/ui/to_digit_is_some.rs +++ b/tests/ui/to_digit_is_some.rs @@ -9,3 +9,20 @@ fn main() { let _ = char::to_digit(c, 8).is_some(); //~^ to_digit_is_some } + +#[clippy::msrv = "1.86"] +mod cannot_lint_in_const_context { + fn without_const(c: char) -> bool { + c.to_digit(8).is_some() + //~^ to_digit_is_some + } + const fn with_const(c: char) -> bool { + c.to_digit(8).is_some() + } +} + +#[clippy::msrv = "1.87"] +const fn with_const(c: char) -> bool { + c.to_digit(8).is_some() + //~^ to_digit_is_some +} diff --git a/tests/ui/to_digit_is_some.stderr b/tests/ui/to_digit_is_some.stderr index f41382a60d53f..5ffedb4683f17 100644 --- a/tests/ui/to_digit_is_some.stderr +++ b/tests/ui/to_digit_is_some.stderr @@ -13,5 +13,17 @@ error: use of `.to_digit(..).is_some()` LL | let _ = char::to_digit(c, 8).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `char::is_digit(c, 8)` -error: aborting due to 2 previous errors +error: use of `.to_digit(..).is_some()` + --> tests/ui/to_digit_is_some.rs:16:9 + | +LL | c.to_digit(8).is_some() + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `c.is_digit(8)` + +error: use of `.to_digit(..).is_some()` + --> tests/ui/to_digit_is_some.rs:26:5 + | +LL | c.to_digit(8).is_some() + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `c.is_digit(8)` + +error: aborting due to 4 previous errors diff --git a/tests/ui/transmute.rs b/tests/ui/transmute.rs index 2b8b6c539ad3c..e968e7a59244d 100644 --- a/tests/ui/transmute.rs +++ b/tests/ui/transmute.rs @@ -116,138 +116,6 @@ fn int_to_bool() { //~^ transmute_int_to_bool } -#[warn(clippy::transmute_int_to_float)] -mod int_to_float { - fn test() { - let _: f16 = unsafe { std::mem::transmute(0_u16) }; - //~^ transmute_int_to_float - - let _: f16 = unsafe { std::mem::transmute(0_i16) }; - //~^ transmute_int_to_float - - let _: f32 = unsafe { std::mem::transmute(0_u32) }; - //~^ transmute_int_to_float - - let _: f32 = unsafe { std::mem::transmute(0_i32) }; - //~^ transmute_int_to_float - - let _: f64 = unsafe { std::mem::transmute(0_u64) }; - //~^ transmute_int_to_float - - let _: f64 = unsafe { std::mem::transmute(0_i64) }; - //~^ transmute_int_to_float - - let _: f128 = unsafe { std::mem::transmute(0_u128) }; - //~^ transmute_int_to_float - - let _: f128 = unsafe { std::mem::transmute(0_i128) }; - //~^ transmute_int_to_float - } - - mod issue_5747 { - const VALUE16: f16 = unsafe { std::mem::transmute(0_u16) }; - //~^ transmute_int_to_float - - const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) }; - //~^ transmute_int_to_float - - const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) }; - //~^ transmute_int_to_float - - const VALUE128: f128 = unsafe { std::mem::transmute(0_i128) }; - //~^ transmute_int_to_float - - const fn from_bits_16(v: i16) -> f16 { - unsafe { std::mem::transmute(v) } - //~^ transmute_int_to_float - } - - const fn from_bits_32(v: i32) -> f32 { - unsafe { std::mem::transmute(v) } - //~^ transmute_int_to_float - } - - const fn from_bits_64(v: u64) -> f64 { - unsafe { std::mem::transmute(v) } - //~^ transmute_int_to_float - } - - const fn from_bits_128(v: u128) -> f128 { - unsafe { std::mem::transmute(v) } - //~^ transmute_int_to_float - } - } -} - -mod num_to_bytes { - fn test() { - unsafe { - let _: [u8; 1] = std::mem::transmute(0u8); - //~^ transmute_num_to_bytes - - let _: [u8; 4] = std::mem::transmute(0u32); - //~^ transmute_num_to_bytes - - let _: [u8; 16] = std::mem::transmute(0u128); - //~^ transmute_num_to_bytes - - let _: [u8; 1] = std::mem::transmute(0i8); - //~^ transmute_num_to_bytes - - let _: [u8; 4] = std::mem::transmute(0i32); - //~^ transmute_num_to_bytes - - let _: [u8; 16] = std::mem::transmute(0i128); - //~^ transmute_num_to_bytes - - let _: [u8; 2] = std::mem::transmute(0.0f16); - //~^ transmute_num_to_bytes - - let _: [u8; 4] = std::mem::transmute(0.0f32); - //~^ transmute_num_to_bytes - - let _: [u8; 8] = std::mem::transmute(0.0f64); - //~^ transmute_num_to_bytes - - let _: [u8; 16] = std::mem::transmute(0.0f128); - //~^ transmute_num_to_bytes - } - } - const fn test_const() { - unsafe { - let _: [u8; 1] = std::mem::transmute(0u8); - //~^ transmute_num_to_bytes - - let _: [u8; 4] = std::mem::transmute(0u32); - //~^ transmute_num_to_bytes - - let _: [u8; 16] = std::mem::transmute(0u128); - //~^ transmute_num_to_bytes - - let _: [u8; 1] = std::mem::transmute(0i8); - //~^ transmute_num_to_bytes - - let _: [u8; 4] = std::mem::transmute(0i32); - //~^ transmute_num_to_bytes - - let _: [u8; 16] = std::mem::transmute(0i128); - //~^ transmute_num_to_bytes - - let _: [u8; 2] = std::mem::transmute(0.0f16); - //~^ transmute_num_to_bytes - - let _: [u8; 4] = std::mem::transmute(0.0f32); - //~^ transmute_num_to_bytes - - let _: [u8; 8] = std::mem::transmute(0.0f64); - //~^ transmute_num_to_bytes - - let _: [u8; 16] = std::mem::transmute(0.0f128); - //~^ transmute_num_to_bytes - } - } -} - fn bytes_to_str(mb: &mut [u8]) { const B: &[u8] = b""; diff --git a/tests/ui/transmute.stderr b/tests/ui/transmute.stderr index 1bb70151965cd..79528ec06f1bf 100644 --- a/tests/ui/transmute.stderr +++ b/tests/ui/transmute.stderr @@ -97,230 +97,8 @@ LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; = note: `-D clippy::transmute-int-to-bool` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_bool)]` -error: transmute from a `u16` to a `f16` - --> tests/ui/transmute.rs:122:31 - | -LL | let _: f16 = unsafe { std::mem::transmute(0_u16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_u16)` - | - = note: `-D clippy::transmute-int-to-float` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_float)]` - -error: transmute from a `i16` to a `f16` - --> tests/ui/transmute.rs:125:31 - | -LL | let _: f16 = unsafe { std::mem::transmute(0_i16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_i16 as u16)` - -error: transmute from a `u32` to a `f32` - --> tests/ui/transmute.rs:128:31 - | -LL | let _: f32 = unsafe { std::mem::transmute(0_u32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` - -error: transmute from a `i32` to a `f32` - --> tests/ui/transmute.rs:131:31 - | -LL | let _: f32 = unsafe { std::mem::transmute(0_i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)` - -error: transmute from a `u64` to a `f64` - --> tests/ui/transmute.rs:134:31 - | -LL | let _: f64 = unsafe { std::mem::transmute(0_u64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_u64)` - -error: transmute from a `i64` to a `f64` - --> tests/ui/transmute.rs:137:31 - | -LL | let _: f64 = unsafe { std::mem::transmute(0_i64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)` - -error: transmute from a `u128` to a `f128` - --> tests/ui/transmute.rs:140:32 - | -LL | let _: f128 = unsafe { std::mem::transmute(0_u128) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_u128)` - -error: transmute from a `i128` to a `f128` - --> tests/ui/transmute.rs:143:32 - | -LL | let _: f128 = unsafe { std::mem::transmute(0_i128) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)` - -error: transmute from a `u16` to a `f16` - --> tests/ui/transmute.rs:148:39 - | -LL | const VALUE16: f16 = unsafe { std::mem::transmute(0_u16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_u16)` - -error: transmute from a `u32` to a `f32` - --> tests/ui/transmute.rs:151:39 - | -LL | const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` - -error: transmute from a `i64` to a `f64` - --> tests/ui/transmute.rs:154:39 - | -LL | const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)` - -error: transmute from a `i128` to a `f128` - --> tests/ui/transmute.rs:157:41 - | -LL | const VALUE128: f128 = unsafe { std::mem::transmute(0_i128) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)` - -error: transmute from a `i16` to a `f16` - --> tests/ui/transmute.rs:161:22 - | -LL | unsafe { std::mem::transmute(v) } - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(v as u16)` - -error: transmute from a `i32` to a `f32` - --> tests/ui/transmute.rs:166:22 - | -LL | unsafe { std::mem::transmute(v) } - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(v as u32)` - -error: transmute from a `u64` to a `f64` - --> tests/ui/transmute.rs:171:22 - | -LL | unsafe { std::mem::transmute(v) } - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(v)` - -error: transmute from a `u128` to a `f128` - --> tests/ui/transmute.rs:176:22 - | -LL | unsafe { std::mem::transmute(v) } - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(v)` - -error: transmute from a `u8` to a `[u8; 1]` - --> tests/ui/transmute.rs:185:30 - | -LL | let _: [u8; 1] = std::mem::transmute(0u8); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` - | - = note: `-D clippy::transmute-num-to-bytes` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::transmute_num_to_bytes)]` - -error: transmute from a `u32` to a `[u8; 4]` - --> tests/ui/transmute.rs:188:30 - | -LL | let _: [u8; 4] = std::mem::transmute(0u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()` - -error: transmute from a `u128` to a `[u8; 16]` - --> tests/ui/transmute.rs:191:31 - | -LL | let _: [u8; 16] = std::mem::transmute(0u128); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()` - -error: transmute from a `i8` to a `[u8; 1]` - --> tests/ui/transmute.rs:194:30 - | -LL | let _: [u8; 1] = std::mem::transmute(0i8); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()` - -error: transmute from a `i32` to a `[u8; 4]` - --> tests/ui/transmute.rs:197:30 - | -LL | let _: [u8; 4] = std::mem::transmute(0i32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()` - -error: transmute from a `i128` to a `[u8; 16]` - --> tests/ui/transmute.rs:200:31 - | -LL | let _: [u8; 16] = std::mem::transmute(0i128); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` - -error: transmute from a `f16` to a `[u8; 2]` - --> tests/ui/transmute.rs:203:30 - | -LL | let _: [u8; 2] = std::mem::transmute(0.0f16); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()` - -error: transmute from a `f32` to a `[u8; 4]` - --> tests/ui/transmute.rs:206:30 - | -LL | let _: [u8; 4] = std::mem::transmute(0.0f32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()` - -error: transmute from a `f64` to a `[u8; 8]` - --> tests/ui/transmute.rs:209:30 - | -LL | let _: [u8; 8] = std::mem::transmute(0.0f64); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()` - -error: transmute from a `f128` to a `[u8; 16]` - --> tests/ui/transmute.rs:212:31 - | -LL | let _: [u8; 16] = std::mem::transmute(0.0f128); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()` - -error: transmute from a `u8` to a `[u8; 1]` - --> tests/ui/transmute.rs:218:30 - | -LL | let _: [u8; 1] = std::mem::transmute(0u8); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` - -error: transmute from a `u32` to a `[u8; 4]` - --> tests/ui/transmute.rs:221:30 - | -LL | let _: [u8; 4] = std::mem::transmute(0u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()` - -error: transmute from a `u128` to a `[u8; 16]` - --> tests/ui/transmute.rs:224:31 - | -LL | let _: [u8; 16] = std::mem::transmute(0u128); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()` - -error: transmute from a `i8` to a `[u8; 1]` - --> tests/ui/transmute.rs:227:30 - | -LL | let _: [u8; 1] = std::mem::transmute(0i8); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()` - -error: transmute from a `i32` to a `[u8; 4]` - --> tests/ui/transmute.rs:230:30 - | -LL | let _: [u8; 4] = std::mem::transmute(0i32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()` - -error: transmute from a `i128` to a `[u8; 16]` - --> tests/ui/transmute.rs:233:31 - | -LL | let _: [u8; 16] = std::mem::transmute(0i128); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` - -error: transmute from a `f16` to a `[u8; 2]` - --> tests/ui/transmute.rs:236:30 - | -LL | let _: [u8; 2] = std::mem::transmute(0.0f16); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()` - -error: transmute from a `f32` to a `[u8; 4]` - --> tests/ui/transmute.rs:239:30 - | -LL | let _: [u8; 4] = std::mem::transmute(0.0f32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()` - -error: transmute from a `f64` to a `[u8; 8]` - --> tests/ui/transmute.rs:242:30 - | -LL | let _: [u8; 8] = std::mem::transmute(0.0f64); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()` - -error: transmute from a `f128` to a `[u8; 16]` - --> tests/ui/transmute.rs:245:31 - | -LL | let _: [u8; 16] = std::mem::transmute(0.0f128); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()` - error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:254:28 + --> tests/ui/transmute.rs:122:28 | LL | let _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()` @@ -329,16 +107,16 @@ LL | let _: &str = unsafe { std::mem::transmute(B) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_bytes_to_str)]` error: transmute from a `&mut [u8]` to a `&mut str` - --> tests/ui/transmute.rs:257:32 + --> tests/ui/transmute.rs:125:32 | LL | let _: &mut str = unsafe { std::mem::transmute(mb) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()` error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:260:30 + --> tests/ui/transmute.rs:128:30 | LL | const _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)` -error: aborting due to 54 previous errors +error: aborting due to 18 previous errors diff --git a/tests/ui/transmute_float_to_int.fixed b/tests/ui/transmute_float_to_int.fixed deleted file mode 100644 index 844445907d7c2..0000000000000 --- a/tests/ui/transmute_float_to_int.fixed +++ /dev/null @@ -1,60 +0,0 @@ -#![warn(clippy::transmute_float_to_int)] -#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)] -#![feature(f128)] -#![feature(f16)] - -fn float_to_int() { - let _: u32 = unsafe { 1f32.to_bits() }; - //~^ transmute_float_to_int - - let _: i32 = unsafe { 1f32.to_bits() as i32 }; - //~^ transmute_float_to_int - - let _: u64 = unsafe { 1f64.to_bits() }; - //~^ transmute_float_to_int - - let _: i64 = unsafe { 1f64.to_bits() as i64 }; - //~^ transmute_float_to_int - - let _: u64 = unsafe { 1.0f64.to_bits() }; - //~^ transmute_float_to_int - - let _: u64 = unsafe { (-1.0f64).to_bits() }; - //~^ transmute_float_to_int -} - -mod issue_5747 { - const VALUE16: i16 = unsafe { 1f16.to_bits() as i16 }; - //~^ transmute_float_to_int - - const VALUE32: i32 = unsafe { 1f32.to_bits() as i32 }; - //~^ transmute_float_to_int - - const VALUE64: u64 = unsafe { 1f64.to_bits() }; - //~^ transmute_float_to_int - - const VALUE128: u128 = unsafe { 1f128.to_bits() }; - //~^ transmute_float_to_int - - const fn to_bits_16(v: f16) -> u16 { - unsafe { v.to_bits() } - //~^ transmute_float_to_int - } - - const fn to_bits_32(v: f32) -> u32 { - unsafe { v.to_bits() } - //~^ transmute_float_to_int - } - - const fn to_bits_64(v: f64) -> i64 { - unsafe { v.to_bits() as i64 } - //~^ transmute_float_to_int - } - - const fn to_bits_128(v: f128) -> i128 { - unsafe { v.to_bits() as i128 } - //~^ transmute_float_to_int - } -} - -fn main() {} diff --git a/tests/ui/transmute_float_to_int.rs b/tests/ui/transmute_float_to_int.rs deleted file mode 100644 index a1f3b15bbfee4..0000000000000 --- a/tests/ui/transmute_float_to_int.rs +++ /dev/null @@ -1,60 +0,0 @@ -#![warn(clippy::transmute_float_to_int)] -#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)] -#![feature(f128)] -#![feature(f16)] - -fn float_to_int() { - let _: u32 = unsafe { std::mem::transmute(1f32) }; - //~^ transmute_float_to_int - - let _: i32 = unsafe { std::mem::transmute(1f32) }; - //~^ transmute_float_to_int - - let _: u64 = unsafe { std::mem::transmute(1f64) }; - //~^ transmute_float_to_int - - let _: i64 = unsafe { std::mem::transmute(1f64) }; - //~^ transmute_float_to_int - - let _: u64 = unsafe { std::mem::transmute(1.0) }; - //~^ transmute_float_to_int - - let _: u64 = unsafe { std::mem::transmute(-1.0) }; - //~^ transmute_float_to_int -} - -mod issue_5747 { - const VALUE16: i16 = unsafe { std::mem::transmute(1f16) }; - //~^ transmute_float_to_int - - const VALUE32: i32 = unsafe { std::mem::transmute(1f32) }; - //~^ transmute_float_to_int - - const VALUE64: u64 = unsafe { std::mem::transmute(1f64) }; - //~^ transmute_float_to_int - - const VALUE128: u128 = unsafe { std::mem::transmute(1f128) }; - //~^ transmute_float_to_int - - const fn to_bits_16(v: f16) -> u16 { - unsafe { std::mem::transmute(v) } - //~^ transmute_float_to_int - } - - const fn to_bits_32(v: f32) -> u32 { - unsafe { std::mem::transmute(v) } - //~^ transmute_float_to_int - } - - const fn to_bits_64(v: f64) -> i64 { - unsafe { std::mem::transmute(v) } - //~^ transmute_float_to_int - } - - const fn to_bits_128(v: f128) -> i128 { - unsafe { std::mem::transmute(v) } - //~^ transmute_float_to_int - } -} - -fn main() {} diff --git a/tests/ui/transmute_float_to_int.stderr b/tests/ui/transmute_float_to_int.stderr deleted file mode 100644 index 223cbc4e90c07..0000000000000 --- a/tests/ui/transmute_float_to_int.stderr +++ /dev/null @@ -1,89 +0,0 @@ -error: transmute from a `f32` to a `u32` - --> tests/ui/transmute_float_to_int.rs:7:27 - | -LL | let _: u32 = unsafe { std::mem::transmute(1f32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits()` - | - = note: `-D clippy::transmute-float-to-int` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::transmute_float_to_int)]` - -error: transmute from a `f32` to a `i32` - --> tests/ui/transmute_float_to_int.rs:10:27 - | -LL | let _: i32 = unsafe { std::mem::transmute(1f32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits() as i32` - -error: transmute from a `f64` to a `u64` - --> tests/ui/transmute_float_to_int.rs:13:27 - | -LL | let _: u64 = unsafe { std::mem::transmute(1f64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits()` - -error: transmute from a `f64` to a `i64` - --> tests/ui/transmute_float_to_int.rs:16:27 - | -LL | let _: i64 = unsafe { std::mem::transmute(1f64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits() as i64` - -error: transmute from a `f64` to a `u64` - --> tests/ui/transmute_float_to_int.rs:19:27 - | -LL | let _: u64 = unsafe { std::mem::transmute(1.0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.0f64.to_bits()` - -error: transmute from a `f64` to a `u64` - --> tests/ui/transmute_float_to_int.rs:22:27 - | -LL | let _: u64 = unsafe { std::mem::transmute(-1.0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-1.0f64).to_bits()` - -error: transmute from a `f16` to a `i16` - --> tests/ui/transmute_float_to_int.rs:27:35 - | -LL | const VALUE16: i16 = unsafe { std::mem::transmute(1f16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f16.to_bits() as i16` - -error: transmute from a `f32` to a `i32` - --> tests/ui/transmute_float_to_int.rs:30:35 - | -LL | const VALUE32: i32 = unsafe { std::mem::transmute(1f32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits() as i32` - -error: transmute from a `f64` to a `u64` - --> tests/ui/transmute_float_to_int.rs:33:35 - | -LL | const VALUE64: u64 = unsafe { std::mem::transmute(1f64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits()` - -error: transmute from a `f128` to a `u128` - --> tests/ui/transmute_float_to_int.rs:36:37 - | -LL | const VALUE128: u128 = unsafe { std::mem::transmute(1f128) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f128.to_bits()` - -error: transmute from a `f16` to a `u16` - --> tests/ui/transmute_float_to_int.rs:40:18 - | -LL | unsafe { std::mem::transmute(v) } - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits()` - -error: transmute from a `f32` to a `u32` - --> tests/ui/transmute_float_to_int.rs:45:18 - | -LL | unsafe { std::mem::transmute(v) } - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits()` - -error: transmute from a `f64` to a `i64` - --> tests/ui/transmute_float_to_int.rs:50:18 - | -LL | unsafe { std::mem::transmute(v) } - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits() as i64` - -error: transmute from a `f128` to a `i128` - --> tests/ui/transmute_float_to_int.rs:55:18 - | -LL | unsafe { std::mem::transmute(v) } - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits() as i128` - -error: aborting due to 14 previous errors - diff --git a/tests/ui/transmute_int_to_char.fixed b/tests/ui/transmute_int_to_char.fixed deleted file mode 100644 index 28644aa9ebbb7..0000000000000 --- a/tests/ui/transmute_int_to_char.fixed +++ /dev/null @@ -1,16 +0,0 @@ -#![warn(clippy::transmute_int_to_char)] -#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)] - -fn int_to_char() { - let _: char = unsafe { std::char::from_u32(0_u32).unwrap() }; - //~^ transmute_int_to_char - - let _: char = unsafe { std::char::from_u32(0_i32 as u32).unwrap() }; - //~^ transmute_int_to_char - - // These shouldn't warn - const _: char = unsafe { std::mem::transmute(0_u32) }; - const _: char = unsafe { std::mem::transmute(0_i32) }; -} - -fn main() {} diff --git a/tests/ui/transmute_int_to_char.rs b/tests/ui/transmute_int_to_char.rs deleted file mode 100644 index 8c83ecc8914b6..0000000000000 --- a/tests/ui/transmute_int_to_char.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![warn(clippy::transmute_int_to_char)] -#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)] - -fn int_to_char() { - let _: char = unsafe { std::mem::transmute(0_u32) }; - //~^ transmute_int_to_char - - let _: char = unsafe { std::mem::transmute(0_i32) }; - //~^ transmute_int_to_char - - // These shouldn't warn - const _: char = unsafe { std::mem::transmute(0_u32) }; - const _: char = unsafe { std::mem::transmute(0_i32) }; -} - -fn main() {} diff --git a/tests/ui/transmute_int_to_char.stderr b/tests/ui/transmute_int_to_char.stderr deleted file mode 100644 index e3a3620f28b75..0000000000000 --- a/tests/ui/transmute_int_to_char.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error: transmute from a `u32` to a `char` - --> tests/ui/transmute_int_to_char.rs:5:28 - | -LL | let _: char = unsafe { std::mem::transmute(0_u32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_u32).unwrap()` - | - = note: `-D clippy::transmute-int-to-char` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_char)]` - -error: transmute from a `i32` to a `char` - --> tests/ui/transmute_int_to_char.rs:8:28 - | -LL | let _: char = unsafe { std::mem::transmute(0_i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_i32 as u32).unwrap()` - -error: aborting due to 2 previous errors - diff --git a/tests/ui/transmute_int_to_char_no_std.fixed b/tests/ui/transmute_int_to_char_no_std.fixed deleted file mode 100644 index e6e09a2be4bf5..0000000000000 --- a/tests/ui/transmute_int_to_char_no_std.fixed +++ /dev/null @@ -1,28 +0,0 @@ -#![no_std] -#![feature(lang_items)] -#![warn(clippy::transmute_int_to_char)] -#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)] - -use core::panic::PanicInfo; - -#[lang = "eh_personality"] -extern "C" fn eh_personality() {} - -#[panic_handler] -fn panic(info: &PanicInfo) -> ! { - loop {} -} - -fn int_to_char() { - let _: char = unsafe { core::char::from_u32(0_u32).unwrap() }; - //~^ transmute_int_to_char - - let _: char = unsafe { core::char::from_u32(0_i32 as u32).unwrap() }; - //~^ transmute_int_to_char - - // These shouldn't warn - const _: char = unsafe { core::mem::transmute(0_u32) }; - const _: char = unsafe { core::mem::transmute(0_i32) }; -} - -fn main() {} diff --git a/tests/ui/transmute_int_to_char_no_std.rs b/tests/ui/transmute_int_to_char_no_std.rs deleted file mode 100644 index 0f2106df00e6c..0000000000000 --- a/tests/ui/transmute_int_to_char_no_std.rs +++ /dev/null @@ -1,28 +0,0 @@ -#![no_std] -#![feature(lang_items)] -#![warn(clippy::transmute_int_to_char)] -#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)] - -use core::panic::PanicInfo; - -#[lang = "eh_personality"] -extern "C" fn eh_personality() {} - -#[panic_handler] -fn panic(info: &PanicInfo) -> ! { - loop {} -} - -fn int_to_char() { - let _: char = unsafe { core::mem::transmute(0_u32) }; - //~^ transmute_int_to_char - - let _: char = unsafe { core::mem::transmute(0_i32) }; - //~^ transmute_int_to_char - - // These shouldn't warn - const _: char = unsafe { core::mem::transmute(0_u32) }; - const _: char = unsafe { core::mem::transmute(0_i32) }; -} - -fn main() {} diff --git a/tests/ui/transmute_int_to_char_no_std.stderr b/tests/ui/transmute_int_to_char_no_std.stderr deleted file mode 100644 index d94580a84d7a4..0000000000000 --- a/tests/ui/transmute_int_to_char_no_std.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error: transmute from a `u32` to a `char` - --> tests/ui/transmute_int_to_char_no_std.rs:17:28 - | -LL | let _: char = unsafe { core::mem::transmute(0_u32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::char::from_u32(0_u32).unwrap()` - | - = note: `-D clippy::transmute-int-to-char` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_char)]` - -error: transmute from a `i32` to a `char` - --> tests/ui/transmute_int_to_char_no_std.rs:20:28 - | -LL | let _: char = unsafe { core::mem::transmute(0_i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::char::from_u32(0_i32 as u32).unwrap()` - -error: aborting due to 2 previous errors - diff --git a/tests/ui/type_repetition_in_bounds.rs b/tests/ui/type_repetition_in_bounds.rs index d325887bfba3f..e75678d5fd93e 100644 --- a/tests/ui/type_repetition_in_bounds.rs +++ b/tests/ui/type_repetition_in_bounds.rs @@ -12,7 +12,7 @@ pub fn foo(_t: T) where T: Copy, T: Clone, - //~^ ERROR: this type has already been used as a bound predicate + //~^ type_repetition_in_bounds { unimplemented!(); } @@ -30,7 +30,7 @@ trait LintBounds where Self: Clone, Self: Copy + Default + Ord, - //~^ ERROR: this type has already been used as a bound predicate + //~^ type_repetition_in_bounds Self: Add + AddAssign + Sub + SubAssign, Self: Mul + MulAssign + Div + DivAssign, { @@ -105,13 +105,13 @@ where pub fn f() where T: Clone, - //~^ ERROR: this type has already been used as a bound predicate + //~^ type_repetition_in_bounds { } pub fn g() where T: ?Sized, - //~^ ERROR: this type has already been used as a bound predicate + //~^ type_repetition_in_bounds { } @@ -137,10 +137,27 @@ mod issue8772_pass { pub fn f(arg: usize) where T: Trait, Box<[String]>, bool> + 'static, - //~^ ERROR: this type has already been used as a bound predicate + //~^ type_repetition_in_bounds U: Clone + Sync + 'static, { } } +struct Issue14744<'a, K: 'a> +where + K: Clone, +{ + phantom: std::marker::PhantomData<&'a K>, +} +//~^^^^ type_repetition_in_bounds + +struct ComplexType +where + Vec: Clone, + Vec: Clone, +{ + t: T, +} +//~^^^^ type_repetition_in_bounds + fn main() {} diff --git a/tests/ui/type_repetition_in_bounds.stderr b/tests/ui/type_repetition_in_bounds.stderr index 77944c9504579..de1b14da1985f 100644 --- a/tests/ui/type_repetition_in_bounds.stderr +++ b/tests/ui/type_repetition_in_bounds.stderr @@ -1,4 +1,4 @@ -error: this type has already been used as a bound predicate +error: type `T` has already been used as a bound predicate --> tests/ui/type_repetition_in_bounds.rs:14:5 | LL | T: Clone, @@ -11,7 +11,7 @@ note: the lint level is defined here LL | #![deny(clippy::type_repetition_in_bounds)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: this type has already been used as a bound predicate +error: type `Self` has already been used as a bound predicate --> tests/ui/type_repetition_in_bounds.rs:32:5 | LL | Self: Copy + Default + Ord, @@ -19,7 +19,7 @@ LL | Self: Copy + Default + Ord, | = help: consider combining the bounds: `Self: Clone + Copy + Default + Ord` -error: this type has already been used as a bound predicate +error: type `T` has already been used as a bound predicate --> tests/ui/type_repetition_in_bounds.rs:107:5 | LL | T: Clone, @@ -27,7 +27,7 @@ LL | T: Clone, | = help: consider combining the bounds: `T: ?Sized + Clone` -error: this type has already been used as a bound predicate +error: type `T` has already been used as a bound predicate --> tests/ui/type_repetition_in_bounds.rs:113:5 | LL | T: ?Sized, @@ -35,13 +35,29 @@ LL | T: ?Sized, | = help: consider combining the bounds: `T: Clone + ?Sized` -error: this type has already been used as a bound predicate +error: type `T` has already been used as a bound predicate --> tests/ui/type_repetition_in_bounds.rs:139:9 | LL | T: Trait, Box<[String]>, bool> + 'static, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider combining the bounds: `T: ?Sized + Trait, Box<[String]>, bool>` + = help: consider combining the bounds: `T: ?Sized + Trait, Box<[String]>, bool> + 'static` -error: aborting due to 5 previous errors +error: type `K` has already been used as a bound predicate + --> tests/ui/type_repetition_in_bounds.rs:148:5 + | +LL | K: Clone, + | ^^^^^^^^ + | + = help: consider combining the bounds: `K: 'a + Clone` + +error: type `Vec` has already been used as a bound predicate + --> tests/ui/type_repetition_in_bounds.rs:157:5 + | +LL | Vec: Clone, + | ^^^^^^^^^^^^^ + | + = help: consider combining the bounds: `Vec: Clone + Clone` + +error: aborting due to 7 previous errors diff --git a/tests/ui/unused_async.rs b/tests/ui/unused_async.rs index 5aaf7b9f5b598..433459253dd76 100644 --- a/tests/ui/unused_async.rs +++ b/tests/ui/unused_async.rs @@ -119,3 +119,11 @@ fn main() { foo(); bar(); } + +mod issue14704 { + use std::sync::Arc; + + trait Action { + async fn cancel(self: Arc) {} + } +} diff --git a/tests/ui/unwrap_expect_used.rs b/tests/ui/unwrap_expect_used.rs index d0bb571273b5a..b429f3a8a0bb9 100644 --- a/tests/ui/unwrap_expect_used.rs +++ b/tests/ui/unwrap_expect_used.rs @@ -66,3 +66,20 @@ fn main() { SOME.expect("Still not three?"); } } + +mod with_expansion { + macro_rules! open { + ($file:expr) => { + std::fs::File::open($file) + }; + } + + fn test(file: &str) { + use std::io::Read; + let mut s = String::new(); + let _ = open!(file).unwrap(); //~ unwrap_used + let _ = open!(file).expect("can open"); //~ expect_used + let _ = open!(file).unwrap_err(); //~ unwrap_used + let _ = open!(file).expect_err("can open"); //~ expect_used + } +} diff --git a/tests/ui/unwrap_expect_used.stderr b/tests/ui/unwrap_expect_used.stderr index 79eac3f58ccb2..6fd1b84d81231 100644 --- a/tests/ui/unwrap_expect_used.stderr +++ b/tests/ui/unwrap_expect_used.stderr @@ -50,5 +50,37 @@ LL | a.expect_err("Hello error!"); | = note: if this value is an `Ok`, it will panic -error: aborting due to 6 previous errors +error: used `unwrap()` on a `Result` value + --> tests/ui/unwrap_expect_used.rs:80:17 + | +LL | let _ = open!(file).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: if this value is an `Err`, it will panic + +error: used `expect()` on a `Result` value + --> tests/ui/unwrap_expect_used.rs:81:17 + | +LL | let _ = open!(file).expect("can open"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: if this value is an `Err`, it will panic + +error: used `unwrap_err()` on a `Result` value + --> tests/ui/unwrap_expect_used.rs:82:17 + | +LL | let _ = open!(file).unwrap_err(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: if this value is an `Ok`, it will panic + +error: used `expect_err()` on a `Result` value + --> tests/ui/unwrap_expect_used.rs:83:17 + | +LL | let _ = open!(file).expect_err("can open"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: if this value is an `Ok`, it will panic + +error: aborting due to 10 previous errors diff --git a/triagebot.toml b/triagebot.toml index f27b109e99536..eb2f9f9dd61f5 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -13,7 +13,9 @@ allow-unauthenticated = [ [note] -[canonicalize-issue-links] +[close] + +[issue-links] # Prevents mentions in commits to avoid users being spammed [no-mentions] @@ -42,7 +44,7 @@ new_pr = true contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md" users_on_vacation = [ "matthiaskrgr", - "samueltardieu", + "Manishearth", ] [assign.owners] From afa6d67f36dc0edf130d538ec208f88286aefecd Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 15 May 2025 19:30:30 +0200 Subject: [PATCH 2311/4206] Update Cargo.lock --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f26d858b698d4..6e950f287f9cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -537,7 +537,7 @@ checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "clippy" -version = "0.1.88" +version = "0.1.89" dependencies = [ "anstream", "askama", @@ -569,7 +569,7 @@ dependencies = [ [[package]] name = "clippy_config" -version = "0.1.88" +version = "0.1.89" dependencies = [ "clippy_utils", "itertools", @@ -594,7 +594,7 @@ dependencies = [ [[package]] name = "clippy_lints" -version = "0.1.88" +version = "0.1.89" dependencies = [ "arrayvec", "cargo_metadata 0.18.1", @@ -624,7 +624,7 @@ dependencies = [ [[package]] name = "clippy_utils" -version = "0.1.88" +version = "0.1.89" dependencies = [ "arrayvec", "itertools", @@ -5084,9 +5084,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.19.1" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ "fastrand", "getrandom 0.3.2", From a1931dd7cc0948adb8e7ce975bb2644caac70767 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 10 May 2025 22:20:08 +0200 Subject: [PATCH 2312/4206] `unnecessary_wraps`: do not include the whole body in the lint span Using the function declaration, by stripping the body, is enough to convey the lint message. --- clippy_lints/src/unnecessary_wraps.rs | 17 ++++--- tests/ui/unnecessary_wraps.stderr | 71 +++++++-------------------- 2 files changed, 30 insertions(+), 58 deletions(-) diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index bcd05cceca9c3..54a7efc090ade 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; @@ -78,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { fn_kind: FnKind<'tcx>, fn_decl: &FnDecl<'tcx>, body: &Body<'tcx>, - span: Span, + _span: Span, def_id: LocalDefId, ) { // Abort if public function/method or closure. @@ -147,19 +149,22 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { "remove the return type...".to_string(), // FIXME: we should instead get the span including the `->` and suggest an // empty string for this case. - "()".to_string(), - "...and then remove returned values", + Cow::Borrowed("()"), + Cow::Borrowed("...and then remove returned values"), ) } else { + let wrapper = if lang_item == OptionSome { "Some" } else { "Ok" }; ( format!("this function's return value is unnecessarily wrapped by `{return_type_label}`"), format!("remove `{return_type_label}` from the return type..."), - inner_type.to_string(), - "...and then change returning expressions", + Cow::Owned(inner_type.to_string()), + Cow::Owned(format!( + "...and then remove the surrounding `{wrapper}()` from returning expressions" + )), ) }; - span_lint_and_then(cx, UNNECESSARY_WRAPS, span, lint_msg, |diag| { + span_lint_and_then(cx, UNNECESSARY_WRAPS, cx.tcx.def_span(def_id), lint_msg, |diag| { diag.span_suggestion( fn_decl.output.span(), return_type_sugg_msg, diff --git a/tests/ui/unnecessary_wraps.stderr b/tests/ui/unnecessary_wraps.stderr index ba562f5a50bec..13d71271e211c 100644 --- a/tests/ui/unnecessary_wraps.stderr +++ b/tests/ui/unnecessary_wraps.stderr @@ -1,13 +1,8 @@ error: this function's return value is unnecessarily wrapped by `Option` --> tests/ui/unnecessary_wraps.rs:9:1 | -LL | / fn func1(a: bool, b: bool) -> Option { -LL | | -LL | | -LL | | if a && b { -... | -LL | | } - | |_^ +LL | fn func1(a: bool, b: bool) -> Option { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unnecessary-wraps` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_wraps)]` @@ -16,7 +11,7 @@ help: remove `Option` from the return type... LL - fn func1(a: bool, b: bool) -> Option { LL + fn func1(a: bool, b: bool) -> i32 { | -help: ...and then change returning expressions +help: ...and then remove the surrounding `Some()` from returning expressions | LL ~ return 42; LL | } @@ -30,21 +25,15 @@ LL ~ return 1337; error: this function's return value is unnecessarily wrapped by `Option` --> tests/ui/unnecessary_wraps.rs:24:1 | -LL | / fn func2(a: bool, b: bool) -> Option { -LL | | -LL | | -LL | | if a && b { -... | -LL | | if a { Some(20) } else { Some(30) } -LL | | } - | |_^ +LL | fn func2(a: bool, b: bool) -> Option { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove `Option` from the return type... | LL - fn func2(a: bool, b: bool) -> Option { LL + fn func2(a: bool, b: bool) -> i32 { | -help: ...and then change returning expressions +help: ...and then remove the surrounding `Some()` from returning expressions | LL ~ return 10; LL | } @@ -54,19 +43,15 @@ LL ~ if a { 20 } else { 30 } error: this function's return value is unnecessarily wrapped by `Option` --> tests/ui/unnecessary_wraps.rs:44:1 | -LL | / fn func5() -> Option { -LL | | -LL | | -LL | | Some(1) -LL | | } - | |_^ +LL | fn func5() -> Option { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove `Option` from the return type... | LL - fn func5() -> Option { LL + fn func5() -> i32 { | -help: ...and then change returning expressions +help: ...and then remove the surrounding `Some()` from returning expressions | LL - Some(1) LL + 1 @@ -75,19 +60,15 @@ LL + 1 error: this function's return value is unnecessarily wrapped by `Result` --> tests/ui/unnecessary_wraps.rs:56:1 | -LL | / fn func7() -> Result { -LL | | -LL | | -LL | | Ok(1) -LL | | } - | |_^ +LL | fn func7() -> Result { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove `Result` from the return type... | LL - fn func7() -> Result { LL + fn func7() -> i32 { | -help: ...and then change returning expressions +help: ...and then remove the surrounding `Ok()` from returning expressions | LL - Ok(1) LL + 1 @@ -96,19 +77,15 @@ LL + 1 error: this function's return value is unnecessarily wrapped by `Option` --> tests/ui/unnecessary_wraps.rs:86:5 | -LL | / fn func12() -> Option { -LL | | -LL | | -LL | | Some(1) -LL | | } - | |_____^ +LL | fn func12() -> Option { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove `Option` from the return type... | LL - fn func12() -> Option { LL + fn func12() -> i32 { | -help: ...and then change returning expressions +help: ...and then remove the surrounding `Some()` from returning expressions | LL - Some(1) LL + 1 @@ -117,13 +94,8 @@ LL + 1 error: this function's return value is unnecessary --> tests/ui/unnecessary_wraps.rs:115:1 | -LL | / fn issue_6640_1(a: bool, b: bool) -> Option<()> { -LL | | -LL | | -LL | | if a && b { -... | -LL | | } - | |_^ +LL | fn issue_6640_1(a: bool, b: bool) -> Option<()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the return type... | @@ -144,13 +116,8 @@ LL ~ return ; error: this function's return value is unnecessary --> tests/ui/unnecessary_wraps.rs:130:1 | -LL | / fn issue_6640_2(a: bool, b: bool) -> Result<(), i32> { -LL | | -LL | | -LL | | if a && b { -... | -LL | | } - | |_^ +LL | fn issue_6640_2(a: bool, b: bool) -> Result<(), i32> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the return type... | From 60750ca0a1e71f0ad8d2a66fbcecd75cd4e8bd3a Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 15 May 2025 19:55:43 +0200 Subject: [PATCH 2313/4206] tempfile dep bump fallout --- compiler/rustc_data_structures/src/temp_dir.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_data_structures/src/temp_dir.rs b/compiler/rustc_data_structures/src/temp_dir.rs index 4dbe11d707d77..9adae049261e4 100644 --- a/compiler/rustc_data_structures/src/temp_dir.rs +++ b/compiler/rustc_data_structures/src/temp_dir.rs @@ -17,7 +17,7 @@ impl Drop for MaybeTempDir { // occur. let dir = unsafe { ManuallyDrop::take(&mut self.dir) }; if self.keep { - let _ = dir.into_path(); + let _ = dir.keep(); } } } From 6128fca0b0b70ac6497bf5da38a5d3db37219f78 Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Thu, 15 May 2025 11:15:52 -0700 Subject: [PATCH 2314/4206] [win][arm64] Remove 'Arm64 Hazard' undocumented MSVC option and instead disable problematic test --- .../src/spec/targets/aarch64_pc_windows_msvc.rs | 7 +------ .../llvm-location-discriminator-limit-dummy-span/rmake.rs | 7 +++++++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs index c5704c574483f..f1b6fa123deb4 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs @@ -1,4 +1,4 @@ -use crate::spec::{FramePointer, LinkerFlavor, Lld, Target, TargetMetadata, base}; +use crate::spec::{FramePointer, Target, TargetMetadata, base}; pub(crate) fn target() -> Target { let mut base = base::windows_msvc::opts(); @@ -11,11 +11,6 @@ pub(crate) fn target() -> Target { // and other services. It must point to the previous {x29, x30} pair on the stack." base.frame_pointer = FramePointer::NonLeaf; - // MSVC emits a warning about code that may trip "Cortex-A53 MPCore processor bug #843419" (see - // https://developer.arm.com/documentation/epm048406/latest) which is sometimes emitted by LLVM. - // Since Arm64 Windows 10+ isn't supported on that processor, it's safe to disable the warning. - base.add_pre_link_args(LinkerFlavor::Msvc(Lld::No), &["/arm64hazardfree"]); - Target { llvm_target: "aarch64-pc-windows-msvc".into(), metadata: TargetMetadata { diff --git a/tests/run-make/llvm-location-discriminator-limit-dummy-span/rmake.rs b/tests/run-make/llvm-location-discriminator-limit-dummy-span/rmake.rs index 2727effe81883..d28c8463016cb 100644 --- a/tests/run-make/llvm-location-discriminator-limit-dummy-span/rmake.rs +++ b/tests/run-make/llvm-location-discriminator-limit-dummy-span/rmake.rs @@ -11,6 +11,13 @@ //@ needs-dynamic-linking //@ only-nightly (requires unstable rustc flag) +// This test trips a check in the MSVC linker for an outdated processor: +// "LNK1322: cannot avoid potential ARM hazard (Cortex-A53 MPCore processor bug #843419)" +// Until MSVC removes this check: +// https://developercommunity.microsoft.com/t/Remove-checking-for-and-fixing-Cortex-A/10905134 +// we'll need to disable this test on Arm64 Windows. +//@ ignore-aarch64-pc-windows-msvc + #![deny(warnings)] use run_make_support::{dynamic_lib_name, rfs, rust_lib_name, rustc}; From e0fd8144c04cd385c044fafeb3ae93269c310ab6 Mon Sep 17 00:00:00 2001 From: Barun Parruck Date: Thu, 15 May 2025 21:23:28 +0100 Subject: [PATCH 2315/4206] Fix tests --- tests/ui/crashes/ice-12491.fixed | 2 +- tests/ui/crashes/ice-12491.rs | 2 +- tests/ui/crashes/ice-12491.stderr | 8 +++----- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/ui/crashes/ice-12491.fixed b/tests/ui/crashes/ice-12491.fixed index ab9c61463e92d..8a31eb9550b23 100644 --- a/tests/ui/crashes/ice-12491.fixed +++ b/tests/ui/crashes/ice-12491.fixed @@ -3,6 +3,6 @@ fn main() { if (true) { // anything一些中文 - //~^^ needless_return + //~^ needless_return } } diff --git a/tests/ui/crashes/ice-12491.rs b/tests/ui/crashes/ice-12491.rs index b774bd3788a77..013aadadce516 100644 --- a/tests/ui/crashes/ice-12491.rs +++ b/tests/ui/crashes/ice-12491.rs @@ -4,6 +4,6 @@ fn main() { if (true) { // anything一些中文 return; - //~^^ needless_return + //~^ needless_return } } diff --git a/tests/ui/crashes/ice-12491.stderr b/tests/ui/crashes/ice-12491.stderr index 7cc418898e881..4b77299dd5e6c 100644 --- a/tests/ui/crashes/ice-12491.stderr +++ b/tests/ui/crashes/ice-12491.stderr @@ -1,10 +1,8 @@ error: unneeded `return` statement - --> tests/ui/crashes/ice-12491.rs:5:24 + --> tests/ui/crashes/ice-12491.rs:6:9 | -LL | // anything一些中文 - | ____________________________^ -LL | | return; - | |______________^ +LL | return; + | ^^^^^^ | = note: `-D clippy::needless-return` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_return)]` From ae304db796b6897b6e68486750495898f2d5fec7 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 15 May 2025 23:36:00 +0300 Subject: [PATCH 2316/4206] Improve asm support Including: - Infer `label {}` and `const` operands. - Correctly handle unsafe check inside `label {}`. - Fix an embarrassing parser typo that cause labels to never be part of the AST --- .../crates/hir-def/src/expr_store.rs | 18 +++--- .../hir-ty/src/diagnostics/unsafe_check.rs | 58 ++++++++++++++----- .../crates/hir-ty/src/infer/expr.rs | 36 +++++++----- .../crates/hir-ty/src/tests/macros.rs | 4 ++ .../crates/hir-ty/src/tests/simple.rs | 39 +++++++++++++ .../src/handlers/missing_unsafe.rs | 21 +++++++ .../parser/src/grammar/expressions/atom.rs | 8 ++- .../parser/test_data/generated/runner.rs | 2 + .../test_data/parser/inline/ok/asm_label.rast | 37 ++++++++++++ .../test_data/parser/inline/ok/asm_label.rs | 3 + 10 files changed, 186 insertions(+), 40 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_label.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_label.rs diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs index 09ee286f5cfe5..f617c3225ae13 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs @@ -298,17 +298,16 @@ impl ExpressionStore { Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op { AsmOperand::In { expr, .. } | AsmOperand::Out { expr: Some(expr), .. } - | AsmOperand::InOut { expr, .. } => f(*expr), + | AsmOperand::InOut { expr, .. } + | AsmOperand::Const(expr) + | AsmOperand::Label(expr) => f(*expr), AsmOperand::SplitInOut { in_expr, out_expr, .. } => { f(*in_expr); if let Some(out_expr) = out_expr { f(*out_expr); } } - AsmOperand::Out { expr: None, .. } - | AsmOperand::Const(_) - | AsmOperand::Label(_) - | AsmOperand::Sym(_) => (), + AsmOperand::Out { expr: None, .. } | AsmOperand::Sym(_) => (), }), Expr::If { condition, then_branch, else_branch } => { f(*condition); @@ -435,17 +434,16 @@ impl ExpressionStore { Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op { AsmOperand::In { expr, .. } | AsmOperand::Out { expr: Some(expr), .. } - | AsmOperand::InOut { expr, .. } => f(*expr), + | AsmOperand::InOut { expr, .. } + | AsmOperand::Const(expr) + | AsmOperand::Label(expr) => f(*expr), AsmOperand::SplitInOut { in_expr, out_expr, .. } => { f(*in_expr); if let Some(out_expr) = out_expr { f(*out_expr); } } - AsmOperand::Out { expr: None, .. } - | AsmOperand::Const(_) - | AsmOperand::Label(_) - | AsmOperand::Sym(_) => (), + AsmOperand::Out { expr: None, .. } | AsmOperand::Sym(_) => (), }), Expr::If { condition, then_branch, else_branch } => { f(*condition); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs index 6d5aaa34725d4..20cf3c7811519 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -7,7 +7,7 @@ use either::Either; use hir_def::{ AdtId, DefWithBodyId, FieldId, FunctionId, VariantId, expr_store::{Body, path::Path}, - hir::{Expr, ExprId, ExprOrPatId, Pat, PatId, Statement, UnaryOp}, + hir::{AsmOperand, Expr, ExprId, ExprOrPatId, Pat, PatId, Statement, UnaryOp}, resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs}, signatures::StaticFlags, type_ref::Rawness, @@ -199,6 +199,17 @@ impl<'db> UnsafeVisitor<'db> { } } + fn with_inside_unsafe_block( + &mut self, + inside_unsafe_block: InsideUnsafeBlock, + f: impl FnOnce(&mut Self) -> R, + ) -> R { + let old = mem::replace(&mut self.inside_unsafe_block, inside_unsafe_block); + let result = f(self); + self.inside_unsafe_block = old; + result + } + fn walk_pats_top(&mut self, pats: impl Iterator, parent_expr: ExprId) { let guard = self.resolver.update_to_inner_scope(self.db, self.def, parent_expr); pats.for_each(|pat| self.walk_pat(pat)); @@ -303,7 +314,29 @@ impl<'db> UnsafeVisitor<'db> { self.walk_pats_top(std::iter::once(target), current); self.inside_assignment = old_inside_assignment; } - Expr::InlineAsm(_) => self.on_unsafe_op(current.into(), UnsafetyReason::InlineAsm), + Expr::InlineAsm(asm) => { + self.on_unsafe_op(current.into(), UnsafetyReason::InlineAsm); + asm.operands.iter().for_each(|(_, op)| match op { + AsmOperand::In { expr, .. } + | AsmOperand::Out { expr: Some(expr), .. } + | AsmOperand::InOut { expr, .. } + | AsmOperand::Const(expr) => self.walk_expr(*expr), + AsmOperand::SplitInOut { in_expr, out_expr, .. } => { + self.walk_expr(*in_expr); + if let Some(out_expr) = out_expr { + self.walk_expr(*out_expr); + } + } + AsmOperand::Out { expr: None, .. } | AsmOperand::Sym(_) => (), + AsmOperand::Label(expr) => { + // Inline asm labels are considered safe even when inside unsafe blocks. + self.with_inside_unsafe_block(InsideUnsafeBlock::No, |this| { + this.walk_expr(*expr) + }); + } + }); + return; + } // rustc allows union assignment to propagate through field accesses and casts. Expr::Cast { .. } => self.inside_assignment = inside_assignment, Expr::Field { .. } => { @@ -317,17 +350,16 @@ impl<'db> UnsafeVisitor<'db> { } } Expr::Unsafe { statements, .. } => { - let old_inside_unsafe_block = - mem::replace(&mut self.inside_unsafe_block, InsideUnsafeBlock::Yes); - self.walk_pats_top( - statements.iter().filter_map(|statement| match statement { - &Statement::Let { pat, .. } => Some(pat), - _ => None, - }), - current, - ); - self.body.walk_child_exprs_without_pats(current, |child| self.walk_expr(child)); - self.inside_unsafe_block = old_inside_unsafe_block; + self.with_inside_unsafe_block(InsideUnsafeBlock::Yes, |this| { + this.walk_pats_top( + statements.iter().filter_map(|statement| match statement { + &Statement::Let { pat, .. } => Some(pat), + _ => None, + }), + current, + ); + this.body.walk_child_exprs_without_pats(current, |child| this.walk_expr(child)); + }); return; } Expr::Block { statements, .. } | Expr::Async { statements, .. } => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 8084b394d044b..87b7f3406ff70 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -959,8 +959,8 @@ impl InferenceContext<'_> { } Expr::OffsetOf(_) => TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner), Expr::InlineAsm(asm) => { - let mut check_expr_asm_operand = |expr, is_input: bool| { - let ty = self.infer_expr_no_expect(expr, ExprIsRead::Yes); + let check_expr_asm_operand = |this: &mut Self, expr, is_input: bool| { + let ty = this.infer_expr_no_expect(expr, ExprIsRead::Yes); // If this is an input value, we require its type to be fully resolved // at this point. This allows us to provide helpful coercions which help @@ -970,18 +970,18 @@ impl InferenceContext<'_> { // allows them to be inferred based on how they are used later in the // function. if is_input { - let ty = self.resolve_ty_shallow(&ty); + let ty = this.resolve_ty_shallow(&ty); match ty.kind(Interner) { TyKind::FnDef(def, parameters) => { let fnptr_ty = TyKind::Function( - CallableSig::from_def(self.db, *def, parameters).to_fn_ptr(), + CallableSig::from_def(this.db, *def, parameters).to_fn_ptr(), ) .intern(Interner); - _ = self.coerce(Some(expr), &ty, &fnptr_ty, CoerceNever::Yes); + _ = this.coerce(Some(expr), &ty, &fnptr_ty, CoerceNever::Yes); } TyKind::Ref(mutbl, _, base_ty) => { let ptr_ty = TyKind::Raw(*mutbl, base_ty.clone()).intern(Interner); - _ = self.coerce(Some(expr), &ty, &ptr_ty, CoerceNever::Yes); + _ = this.coerce(Some(expr), &ty, &ptr_ty, CoerceNever::Yes); } _ => {} } @@ -990,22 +990,28 @@ impl InferenceContext<'_> { let diverge = asm.options.contains(AsmOptions::NORETURN); asm.operands.iter().for_each(|(_, operand)| match *operand { - AsmOperand::In { expr, .. } => check_expr_asm_operand(expr, true), + AsmOperand::In { expr, .. } => check_expr_asm_operand(self, expr, true), AsmOperand::Out { expr: Some(expr), .. } | AsmOperand::InOut { expr, .. } => { - check_expr_asm_operand(expr, false) + check_expr_asm_operand(self, expr, false) } AsmOperand::Out { expr: None, .. } => (), AsmOperand::SplitInOut { in_expr, out_expr, .. } => { - check_expr_asm_operand(in_expr, true); + check_expr_asm_operand(self, in_expr, true); if let Some(out_expr) = out_expr { - check_expr_asm_operand(out_expr, false); + check_expr_asm_operand(self, out_expr, false); } } - // FIXME - AsmOperand::Label(_) => (), - // FIXME - AsmOperand::Const(_) => (), - // FIXME + AsmOperand::Label(expr) => { + self.infer_expr( + expr, + &Expectation::HasType(self.result.standard_types.unit.clone()), + ExprIsRead::No, + ); + } + AsmOperand::Const(expr) => { + self.infer_expr(expr, &Expectation::None, ExprIsRead::No); + } + // FIXME: `sym` should report for things that are not functions or statics. AsmOperand::Sym(_) => (), }); if diverge { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs index 446f0b21a2a18..ea7a113cae3f6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs @@ -1505,6 +1505,10 @@ fn main() { !119..120 'o': i32 293..294 'o': i32 308..317 'thread_id': usize + !314..320 'OffPtr': usize + !333..338 'OffFn': usize + !354..355 '0': i32 + !371..382 'MEM_RELEASE': usize "#]], ) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index 08127eeb46321..cf51671afb2be 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs @@ -3926,3 +3926,42 @@ fn foo() { "#]], ); } + +#[test] +fn asm_const_label() { + check_infer( + r#" +//- minicore: asm +const fn bar() -> i32 { 123 } +fn baz(s: &str) {} + +fn foo() { + unsafe { + core::arch::asm!( + "mov eax, {}", + "jmp {}", + const bar(), + label { + baz("hello"); + }, + ); + } +} + "#, + expect![[r#" + 22..29 '{ 123 }': i32 + 24..27 '123': i32 + 37..38 's': &'? str + 46..48 '{}': () + !0..68 'builti...");},)': () + !40..43 'bar': fn bar() -> i32 + !40..45 'bar()': i32 + !51..66 '{baz("hello");}': () + !52..55 'baz': fn baz(&'? str) + !52..64 'baz("hello")': () + !56..63 '"hello"': &'static str + 59..257 '{ ... } }': () + 65..255 'unsafe... }': () + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs index ff041e183b140..364bead34efae 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs @@ -894,4 +894,25 @@ fn main() { "#, ); } + + #[test] + fn asm_label() { + check_diagnostics( + r#" +//- minicore: asm +fn foo() { + unsafe { + core::arch::asm!( + "jmp {}", + label { + let p = 0xDEADBEAF as *mut u8; + *p = 3; + // ^^ error: dereference of raw pointer is unsafe and requires an unsafe function or block + }, + ); + } +} + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs index 5faf6fc2759e1..8cc332d4633df 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs @@ -381,10 +381,14 @@ fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option { op.complete(p, ASM_REG_OPERAND); op_n.complete(p, ASM_OPERAND_NAMED); } else if p.eat_contextual_kw(T![label]) { + // test asm_label + // fn foo() { + // builtin#asm("", label {}); + // } dir_spec.abandon(p); block_expr(p); - op.complete(p, ASM_OPERAND_NAMED); - op_n.complete(p, ASM_LABEL); + op.complete(p, ASM_LABEL); + op_n.complete(p, ASM_OPERAND_NAMED); } else if p.eat(T![const]) { dir_spec.abandon(p); expr(p); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs index 24db9478ee568..030d8e0f04dd1 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs @@ -21,6 +21,8 @@ mod ok { #[test] fn asm_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/asm_expr.rs"); } #[test] + fn asm_label() { run_and_expect_no_errors("test_data/parser/inline/ok/asm_label.rs"); } + #[test] fn assoc_const_eq() { run_and_expect_no_errors("test_data/parser/inline/ok/assoc_const_eq.rs"); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_label.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_label.rast new file mode 100644 index 0000000000000..38999c9cd34ff --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_label.rast @@ -0,0 +1,37 @@ +SOURCE_FILE + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "foo" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + EXPR_STMT + ASM_EXPR + BUILTIN_KW "builtin" + POUND "#" + ASM_KW "asm" + L_PAREN "(" + LITERAL + STRING "\"\"" + COMMA "," + WHITESPACE " " + ASM_OPERAND_NAMED + ASM_LABEL + LABEL_KW "label" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + R_CURLY "}" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_label.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_label.rs new file mode 100644 index 0000000000000..996c1c8477b69 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_label.rs @@ -0,0 +1,3 @@ +fn foo() { + builtin#asm("", label {}); +} From a64ed161e271a373358bf292de8dab858f8b6bce Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Thu, 15 May 2025 21:26:46 +0000 Subject: [PATCH 2317/4206] Lowercase git url for rust-lang/enzyme.git On Fuchsia, we have an internal Gerrit mirrors of the rust repositories to avoid excess load on the public github servers. Since rust uses submodules, we need to then use git's `url..insteadOf` to point our checkouts at our mirrors. We'd prefer to be able to point all repositories under `https://github.com/rust-lang` to `https://rust.googlesource.com/rust-lang`, but unfortunately it seems that when Rust mirrored Enzyme, the repository name was lower cased to `https://github.com/rust-lang/enzyme`, but kept the name capitalized in the .gitmodules file. This didn't cause a problem for Github, which seems to handle repository names in a case insensitive way, Gerrit is case sensitive, so we can't use a glob rule. Instead we have to setup `insteadOf` rules for each repository. This renames the URL to match the case of the repository name, which should avoid the issue. --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index d09d81ccadcb0..fbf2f59b38da1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -45,7 +45,7 @@ shallow = true [submodule "src/tools/enzyme"] path = src/tools/enzyme - url = https://github.com/rust-lang/Enzyme.git + url = https://github.com/rust-lang/enzyme.git shallow = true [submodule "src/gcc"] path = src/gcc From cf878d8f260e535fab7e6f6401fc61e5d846ac4d Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Thu, 15 May 2025 23:24:47 +0200 Subject: [PATCH 2318/4206] HIR: explain in comment why `ExprKind::If` "then" is an `Expr` One could be tempted to replace the "then" `hir::Expr` with kind `hir::ExprKind::Block` by a `hir::Block`. Explain why this would not be a good idea. --- compiler/rustc_hir/src/hir.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 107aea4e5a401..fa1d1ec0a8601 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2744,6 +2744,8 @@ pub enum ExprKind<'hir> { /// /// The "then" expr is always `ExprKind::Block`. If present, the "else" expr is always /// `ExprKind::Block` (for `else`) or `ExprKind::If` (for `else if`). + /// Note that using an `Expr` instead of a `Block` for the "then" part is intentional, + /// as it simplifies the type coercion machinery. If(&'hir Expr<'hir>, &'hir Expr<'hir>, Option<&'hir Expr<'hir>>), /// A conditionless loop (can be exited with `break`, `continue`, or `return`). /// From c7a2694a803513d09c96dbaf3f3a7b099d93cec6 Mon Sep 17 00:00:00 2001 From: dianqk Date: Fri, 16 May 2025 08:34:16 +0800 Subject: [PATCH 2319/4206] Update to LLVM 20.1.5 --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index 8448283b4bd34..c1118fdbb3024 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 8448283b4bd34ea00d76fd4f18ec730b549d6e1d +Subproject commit c1118fdbb3024157df7f4cfe765f2b0b4339e8a2 From a6bf524975c978dffad2ece4146e339bc88b5d9f Mon Sep 17 00:00:00 2001 From: "Chai T. Rex" Date: Thu, 15 May 2025 19:26:18 -0400 Subject: [PATCH 2320/4206] Update IDEs to use rustfmt 2024, fix Zed settings - Update IDE `rust-analyzer` settings to use 2024 rather than 2021. - Fix Zed settings by removing `${workspaceFolder}/` from paths. --- src/bootstrap/src/core/build_steps/setup.rs | 4 ++++ src/etc/rust_analyzer_eglot.el | 2 +- src/etc/rust_analyzer_helix.toml | 2 +- src/etc/rust_analyzer_settings.json | 2 +- src/etc/rust_analyzer_zed.json | 6 +++--- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 31ec462134d5d..5e22c2d1acbda 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -585,11 +585,13 @@ Select which editor you would like to set up [default: None]: "; "d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45", "b5dd299b93dca3ceeb9b335f929293cb3d4bf4977866fbe7ceeac2a8a9f99088", "631c837b0e98ae35fd48b0e5f743b1ca60adadf2d0a2b23566ba25df372cf1a9", + "080955765db84bb6cbf178879f489c4e2369397626a6ecb3debedb94a9d0b3ce", ], EditorKind::Helix => &[ "2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233", "6736d61409fbebba0933afd2e4c44ff2f97c1cb36cf0299a7f4a7819b8775040", "f252dcc30ca85a193a699581e5e929d5bd6c19d40d7a7ade5e257a9517a124a5", + "198c195ed0c070d15907b279b8b4ea96198ca71b939f5376454f3d636ab54da5", ], EditorKind::Vim | EditorKind::VsCode => &[ "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8", @@ -604,11 +606,13 @@ Select which editor you would like to set up [default: None]: "; "c394386e6133bbf29ffd32c8af0bb3d4aac354cba9ee051f29612aa9350f8f8d", "e53e9129ca5ee5dcbd6ec8b68c2d87376474eb154992deba3c6d9ab1703e0717", "f954316090936c7e590c253ca9d524008375882fa13c5b41d7e2547a896ff893", + "701b73751efd7abd6487f2c79348dab698af7ac4427b79fa3d2087c867144b12", ], EditorKind::Zed => &[ "bbce727c269d1bd0c98afef4d612eb4ce27aea3c3a8968c5f10b31affbc40b6c", "a5380cf5dd9328731aecc5dfb240d16dac46ed272126b9728006151ef42f5909", "2e96bf0d443852b12f016c8fc9840ab3d0a2b4fe0b0fb3a157e8d74d5e7e0e26", + "4fadd4c87389a601a27db0d3d74a142fa3a2e656ae78982e934dbe24bee32ad6", ], } } diff --git a/src/etc/rust_analyzer_eglot.el b/src/etc/rust_analyzer_eglot.el index 90bd38aa89477..3cb229cd98c1d 100644 --- a/src/etc/rust_analyzer_eglot.el +++ b/src/etc/rust_analyzer_eglot.el @@ -14,7 +14,7 @@ "src/bootstrap/Cargo.toml" "src/tools/rust-analyzer/Cargo.toml"] :rustfmt ( :overrideCommand ["build/host/rustfmt/bin/rustfmt" - "--edition=2021"]) + "--edition=2024"]) :procMacro ( :server "build/host/stage0/libexec/rust-analyzer-proc-macro-srv" :enable t) :cargo ( :buildScripts ( :enable t diff --git a/src/etc/rust_analyzer_helix.toml b/src/etc/rust_analyzer_helix.toml index 05fc7716a7252..1a6a14991ecf3 100644 --- a/src/etc/rust_analyzer_helix.toml +++ b/src/etc/rust_analyzer_helix.toml @@ -32,7 +32,7 @@ overrideCommand = [ [language-server.rust-analyzer.config.rustfmt] overrideCommand = [ "build/rust-analyzer/host/rustfmt/bin/rustfmt", - "--edition=2021" + "--edition=2024" ] [language-server.rust-analyzer.config.procMacro] diff --git a/src/etc/rust_analyzer_settings.json b/src/etc/rust_analyzer_settings.json index 5ce886a9b6594..a960cc0173273 100644 --- a/src/etc/rust_analyzer_settings.json +++ b/src/etc/rust_analyzer_settings.json @@ -17,7 +17,7 @@ ], "rust-analyzer.rustfmt.overrideCommand": [ "${workspaceFolder}/build/host/rustfmt/bin/rustfmt", - "--edition=2021" + "--edition=2024" ], "rust-analyzer.procMacro.server": "${workspaceFolder}/build/host/stage0/libexec/rust-analyzer-proc-macro-srv", "rust-analyzer.procMacro.enable": true, diff --git a/src/etc/rust_analyzer_zed.json b/src/etc/rust_analyzer_zed.json index 3461ff887d9b4..27fc524e9b52f 100644 --- a/src/etc/rust_analyzer_zed.json +++ b/src/etc/rust_analyzer_zed.json @@ -29,15 +29,15 @@ ], "procMacro": { "enable": true, - "server": "${workspaceFolder}/build/host/stage0/libexec/rust-analyzer-proc-macro-srv" + "server": "build/host/stage0/libexec/rust-analyzer-proc-macro-srv" }, "rustc": { "source": "./Cargo.toml" }, "rustfmt": { "overrideCommand": [ - "${workspaceFolder}/build/host/rustfmt/bin/rustfmt", - "--edition=2021" + "build/host/rustfmt/bin/rustfmt", + "--edition=2024" ] }, "server": { From 5e048e0786674db68220b7e0e8b19b2a96bcae7c Mon Sep 17 00:00:00 2001 From: Berrysoft Date: Fri, 16 May 2025 09:41:52 +0800 Subject: [PATCH 2321/4206] Simplify current_dll_path for Cygwin --- compiler/rustc_session/src/filesearch.rs | 33 ++++++++---------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 2a85f44278a03..207ba5157bdb6 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -58,7 +58,7 @@ pub fn make_target_bin_path(sysroot: &Path, target_triple: &str) -> PathBuf { sysroot.join(rustlib_path).join("bin") } -#[cfg(all(unix, not(target_os = "cygwin")))] +#[cfg(unix)] fn current_dll_path() -> Result { use std::sync::OnceLock; @@ -78,10 +78,16 @@ fn current_dll_path() -> Result { if libc::dladdr(addr, &mut info) == 0 { return Err("dladdr failed".into()); } - if info.dli_fname.is_null() { - return Err("dladdr returned null pointer".into()); - } - let bytes = CStr::from_ptr(info.dli_fname).to_bytes(); + #[cfg(target_os = "cygwin")] + let fname_ptr = info.dli_fname.as_ptr(); + #[cfg(not(target_os = "cygwin"))] + let fname_ptr = { + if info.dli_fname.is_null() { + return Err("dladdr returned null pointer".into()); + } + info.dli_fname + }; + let bytes = CStr::from_ptr(fname_ptr).to_bytes(); let os = OsStr::from_bytes(bytes); Ok(PathBuf::from(os)) } @@ -132,23 +138,6 @@ fn current_dll_path() -> Result { .clone() } -#[cfg(target_os = "cygwin")] -fn current_dll_path() -> Result { - use std::ffi::{CStr, OsStr}; - use std::os::unix::prelude::*; - - unsafe { - let addr = current_dll_path as usize as *mut _; - let mut info = std::mem::zeroed(); - if libc::dladdr(addr, &mut info) == 0 { - return Err("dladdr failed".into()); - } - let bytes = CStr::from_ptr(info.dli_fname.as_ptr()).to_bytes(); - let os = OsStr::from_bytes(bytes); - Ok(PathBuf::from(os)) - } -} - #[cfg(windows)] fn current_dll_path() -> Result { use std::ffi::OsString; From db950fa77f67ca548526cb3a5b5fbbaaa53e6e3f Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 15 May 2025 19:59:22 -0700 Subject: [PATCH 2322/4206] Updated std doctests for wasm This updates some doctests that fail to run on wasm. We will soon be supporting cross-compiled doctests, and the test-various job fails to run these tests. These tests fail because wasm32-wasip1 does not support threads. --- library/core/src/hint.rs | 2 +- library/core/src/sync/atomic.rs | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 6eefb30468931..8ea9de7e9e52e 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -231,7 +231,7 @@ pub const unsafe fn assert_unchecked(cond: bool) { /// /// # Examples /// -/// ``` +/// ```ignore-wasm /// use std::sync::atomic::{AtomicBool, Ordering}; /// use std::sync::Arc; /// use std::{hint, thread}; diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 84c7f1aafe1b0..bd5a58d74ba0d 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -193,7 +193,7 @@ //! //! A simple spinlock: //! -//! ``` +//! ```ignore-wasm //! use std::sync::Arc; //! use std::sync::atomic::{AtomicUsize, Ordering}; //! use std::{hint, thread}; @@ -622,7 +622,7 @@ impl AtomicBool { /// /// # Examples /// - /// ``` + /// ```ignore-wasm /// #![feature(atomic_from_mut)] /// use std::sync::atomic::{AtomicBool, Ordering}; /// @@ -653,7 +653,7 @@ impl AtomicBool { /// /// # Examples /// - /// ``` + /// ```rust,ignore-wasm /// #![feature(atomic_from_mut)] /// use std::sync::atomic::{AtomicBool, Ordering}; /// @@ -1548,7 +1548,7 @@ impl AtomicPtr { /// /// # Examples /// - /// ``` + /// ```ignore-wasm /// #![feature(atomic_from_mut)] /// use std::ptr::null_mut; /// use std::sync::atomic::{AtomicPtr, Ordering}; @@ -1585,7 +1585,7 @@ impl AtomicPtr { /// /// # Examples /// - /// ``` + /// ```ignore-wasm /// #![feature(atomic_from_mut)] /// use std::ptr::null_mut; /// use std::sync::atomic::{AtomicPtr, Ordering}; @@ -2692,7 +2692,7 @@ macro_rules! atomic_int { /// /// # Examples /// - /// ``` + /// ```ignore-wasm /// #![feature(atomic_from_mut)] #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")] /// @@ -2725,7 +2725,7 @@ macro_rules! atomic_int { /// /// # Examples /// - /// ``` + /// ```ignore-wasm /// #![feature(atomic_from_mut)] #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")] /// From 43ff8855ac55da567a5e2966e0942700d120e067 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Fri, 16 May 2025 16:49:56 +0800 Subject: [PATCH 2323/4206] Add ui test macro-shorthand-issue-140659 Signed-off-by: xizheyin --- .../ui/typeck/macro-shorthand-issue-140659.rs | 57 +++++++++++++++++++ .../macro-shorthand-issue-140659.stderr | 20 +++++++ 2 files changed, 77 insertions(+) create mode 100644 tests/ui/typeck/macro-shorthand-issue-140659.rs create mode 100644 tests/ui/typeck/macro-shorthand-issue-140659.stderr diff --git a/tests/ui/typeck/macro-shorthand-issue-140659.rs b/tests/ui/typeck/macro-shorthand-issue-140659.rs new file mode 100644 index 0000000000000..dba06b43d3931 --- /dev/null +++ b/tests/ui/typeck/macro-shorthand-issue-140659.rs @@ -0,0 +1,57 @@ +trait Reencode { + type Error; + fn tag_index(&mut self, tag: u32) -> Result; +} + +struct Reencoder; +impl Reencode for Reencoder { + type Error = &'static str; + fn tag_index(&mut self, tag: u32) -> Result { + Ok(tag) + } +} + + +enum Operator { + Suspend { tag_index: u32 }, +} + +enum Instruction { + Suspend { tag_index: u32 }, +} + + +macro_rules! for_each_operator { + ($m:ident) => { + $m! { + Suspend { tag_index: u32 } => visit_suspend + } + }; +} + + +fn process(op: &Operator, reencoder: &mut T) -> Instruction { + macro_rules! translate { + (Suspend { tag_index: $ty:ty } => $visit:ident) => { + match op { + Operator::Suspend { tag_index } => { + let tag_index = reencoder.tag_index(*tag_index); + + // KEY POINT: Using field shorthand syntax where the compiler gets confused + // Here tag_index is a Result but we're using it where u32 is expected + Instruction::Suspend { tag_index } //~ ERROR mismatched types [E0308] + } + } + }; + } + + // This should give the specific error message with the wrong help suggestion + for_each_operator!(translate) +} + +fn main() { + let mut reencoder = Reencoder; + let op = Operator::Suspend { tag_index: 1 }; + + let _ = process(&op, &mut reencoder); +} diff --git a/tests/ui/typeck/macro-shorthand-issue-140659.stderr b/tests/ui/typeck/macro-shorthand-issue-140659.stderr new file mode 100644 index 0000000000000..419db9475710c --- /dev/null +++ b/tests/ui/typeck/macro-shorthand-issue-140659.stderr @@ -0,0 +1,20 @@ +error[E0308]: mismatched types + --> $DIR/macro-shorthand-issue-140659.rs:42:44 + | +LL | Instruction::Suspend { tag_index } + | ^^^^^^^^^ expected `u32`, found `Result::Error>` +... +LL | for_each_operator!(translate) + | ----------------------------- in this macro invocation + | + = note: expected type `u32` + found enum `Result::Error>` + = note: this error originates in the macro `translate` which comes from the expansion of the macro `for_each_operator` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider using `Result::expect` to unwrap the `Result::Error>` value, panicking if the value is a `Result::Err` + | +LL | }: tag_index.expect("REASON") + | ++++++++++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. From 8fcff8c6457f16cb0a2760f0b6a846e42d08f0e1 Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 21 Apr 2025 14:38:24 +0200 Subject: [PATCH 2324/4206] Add per page TOC in the rustc book --- src/doc/rustc/book.toml | 2 + src/doc/rustc/theme/pagetoc.css | 104 ++++++++++++++++++++++++++++ src/doc/rustc/theme/pagetoc.js | 118 ++++++++++++++++++++++++++++++++ 3 files changed, 224 insertions(+) create mode 100644 src/doc/rustc/theme/pagetoc.css create mode 100644 src/doc/rustc/theme/pagetoc.js diff --git a/src/doc/rustc/book.toml b/src/doc/rustc/book.toml index 167aece0ed6a3..01f127ad39054 100644 --- a/src/doc/rustc/book.toml +++ b/src/doc/rustc/book.toml @@ -6,6 +6,8 @@ title = "The rustc book" [output.html] git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/rustc" edit-url-template = "https://github.com/rust-lang/rust/edit/master/src/doc/rustc/%7Bpath%7D" +additional-css = ["theme/pagetoc.css"] +additional-js = ["theme/pagetoc.js"] [output.html.search] use-boolean-and = true diff --git a/src/doc/rustc/theme/pagetoc.css b/src/doc/rustc/theme/pagetoc.css new file mode 100644 index 0000000000000..f8f45960d9403 --- /dev/null +++ b/src/doc/rustc/theme/pagetoc.css @@ -0,0 +1,104 @@ +/* Inspired by https://github.com/JorelAli/mdBook-pagetoc/tree/98ee241 (under WTFPL) */ + +:root { + --toc-width: 270px; + --center-content-toc-shift: calc(-1 * var(--toc-width) / 2); +} + +.nav-chapters { + /* adjust width of buttons that bring to the previous or the next page */ + min-width: 50px; +} + +.previous { + /* + adjust the space between the left sidebar or the left side of the screen + and the button that leads to the previous page + */ + margin-left: var(--page-padding); +} + +@media only screen { + main { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + } + + @media (max-width: 1179px) { + .sidebar-hidden #sidetoc { + display: none; + } + } + + @media (max-width: 1439px) { + .sidebar-visible #sidetoc { + display: none; + } + } + + @media (1180px <= width <= 1439px) { + .sidebar-hidden main { + position: relative; + left: var(--center-content-toc-shift); + } + } + + @media (1440px <= width <= 1700px) { + .sidebar-visible main { + position: relative; + left: var(--center-content-toc-shift); + } + } + + .content-wrap { + width: 100%; + } + + #sidetoc { + margin-top: 20px; + margin-left: 20px; + margin-right: auto; + } + #pagetoc { + position: fixed; + /* adjust TOC width */ + width: var(--toc-width); + height: calc(100vh - var(--menu-bar-height) - 0.67em * 4); + overflow: auto; + } + #pagetoc a { + border-left: 1px solid var(--sidebar-bg); + color: var(--sidebar-fg) !important; + display: block; + padding-bottom: 5px; + padding-top: 5px; + padding-left: 10px; + text-align: left; + text-decoration: none; + } + #pagetoc a:hover, + #pagetoc a.active { + background: var(--sidebar-bg); + color: var(--sidebar-active) !important; + } + #pagetoc .active { + background: var(--sidebar-bg); + color: var(--sidebar-active); + } + #pagetoc .pagetoc-H2 { + padding-left: 20px; + } + #pagetoc .pagetoc-H3 { + padding-left: 40px; + } + #pagetoc .pagetoc-H4 { + padding-left: 60px; + } +} + +@media print { + #sidetoc { + display: none; + } +} diff --git a/src/doc/rustc/theme/pagetoc.js b/src/doc/rustc/theme/pagetoc.js new file mode 100644 index 0000000000000..29c09903a3756 --- /dev/null +++ b/src/doc/rustc/theme/pagetoc.js @@ -0,0 +1,118 @@ +// Inspired by https://github.com/JorelAli/mdBook-pagetoc/tree/98ee241 (under WTFPL) + +let activeHref = location.href; +function updatePageToc(elem = undefined) { + let selectedPageTocElem = elem; + const pagetoc = document.getElementById("pagetoc"); + + function getRect(element) { + return element.getBoundingClientRect(); + } + + function overflowTop(container, element) { + return getRect(container).top - getRect(element).top; + } + + function overflowBottom(container, element) { + return getRect(container).bottom - getRect(element).bottom; + } + + // We've not selected a heading to highlight, and the URL needs updating + // so we need to find a heading based on the URL + if (selectedPageTocElem === undefined && location.href !== activeHref) { + activeHref = location.href; + for (const pageTocElement of pagetoc.children) { + if (pageTocElement.href === activeHref) { + selectedPageTocElem = pageTocElement; + } + } + } + + // We still don't have a selected heading, let's try and find the most + // suitable heading based on the scroll position + if (selectedPageTocElem === undefined) { + const margin = window.innerHeight / 3; + + const headers = document.getElementsByClassName("header"); + for (let i = 0; i < headers.length; i++) { + const header = headers[i]; + if (selectedPageTocElem === undefined && getRect(header).top >= 0) { + if (getRect(header).top < margin) { + selectedPageTocElem = header; + } else { + selectedPageTocElem = headers[Math.max(0, i - 1)]; + } + } + // a very long last section's heading is over the screen + if (selectedPageTocElem === undefined && i === headers.length - 1) { + selectedPageTocElem = header; + } + } + } + + // Remove the active flag from all pagetoc elements + for (const pageTocElement of pagetoc.children) { + pageTocElement.classList.remove("active"); + } + + // If we have a selected heading, set it to active and scroll to it + if (selectedPageTocElem !== undefined) { + for (const pageTocElement of pagetoc.children) { + if (selectedPageTocElem.href.localeCompare(pageTocElement.href) === 0) { + pageTocElement.classList.add("active"); + if (overflowTop(pagetoc, pageTocElement) > 0) { + pagetoc.scrollTop = pageTocElement.offsetTop; + } + if (overflowBottom(pagetoc, pageTocElement) < 0) { + pagetoc.scrollTop -= overflowBottom(pagetoc, pageTocElement); + } + } + } + } +} + +if (document.getElementById("sidetoc") === null) { + // Element doesn't exist yet, let's create it + const main = document.querySelector('main'); + const wrapper = document.createElement('div'); + wrapper.className = "content-wrap"; + + // Move all children into the wrapper + while (main.firstChild) { + wrapper.appendChild(main.firstChild); + } + + // Append the wrapper back to main + main.appendChild(wrapper); + + // Create the empty sidetoc and pagetoc elements + const sidetoc = document.createElement("div"); + const pagetoc = document.createElement("div"); + sidetoc.id = "sidetoc"; + pagetoc.id = "pagetoc"; + + // And append them to the current DOM + sidetoc.appendChild(pagetoc); + main.appendChild(sidetoc); +} + +if (document.getElementsByClassName("header").length <= 1) { + // There's one or less headings, we don't need a page table of contents + document.getElementById("sidetoc").remove(); +} else { + // Populate sidebar on load + window.addEventListener("load", () => { + for (const header of document.getElementsByClassName("header")) { + const link = document.createElement("a"); + link.innerHTML = header.innerHTML; + link.href = header.hash; + link.classList.add("pagetoc-" + header.parentElement.tagName); + document.getElementById("pagetoc").appendChild(link); + link.onclick = () => updatePageToc(link); + } + updatePageToc(); + }); + + // Update page table of contents selected heading on scroll + window.addEventListener("scroll", () => updatePageToc()); +} From 72f915aaca3fa3018269de4e57cd1bddf4a17a86 Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 21 Apr 2025 17:15:33 +0200 Subject: [PATCH 2325/4206] Fix flicker when page loads --- src/doc/rustc/theme/pagetoc.css | 14 +------------- src/doc/rustc/theme/pagetoc.js | 20 +++++--------------- 2 files changed, 6 insertions(+), 28 deletions(-) diff --git a/src/doc/rustc/theme/pagetoc.css b/src/doc/rustc/theme/pagetoc.css index f8f45960d9403..26c7ae78e8ac2 100644 --- a/src/doc/rustc/theme/pagetoc.css +++ b/src/doc/rustc/theme/pagetoc.css @@ -19,12 +19,6 @@ } @media only screen { - main { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - } - @media (max-width: 1179px) { .sidebar-hidden #sidetoc { display: none; @@ -51,14 +45,8 @@ } } - .content-wrap { - width: 100%; - } - #sidetoc { - margin-top: 20px; - margin-left: 20px; - margin-right: auto; + margin-left: calc(100% + 20px); } #pagetoc { position: fixed; diff --git a/src/doc/rustc/theme/pagetoc.js b/src/doc/rustc/theme/pagetoc.js index 29c09903a3756..f3549a6de5b02 100644 --- a/src/doc/rustc/theme/pagetoc.js +++ b/src/doc/rustc/theme/pagetoc.js @@ -72,28 +72,18 @@ function updatePageToc(elem = undefined) { } if (document.getElementById("sidetoc") === null) { - // Element doesn't exist yet, let's create it - const main = document.querySelector('main'); - const wrapper = document.createElement('div'); - wrapper.className = "content-wrap"; - - // Move all children into the wrapper - while (main.firstChild) { - wrapper.appendChild(main.firstChild); - } - - // Append the wrapper back to main - main.appendChild(wrapper); + // The sidetoc element doesn't exist yet, let's create it // Create the empty sidetoc and pagetoc elements const sidetoc = document.createElement("div"); const pagetoc = document.createElement("div"); sidetoc.id = "sidetoc"; pagetoc.id = "pagetoc"; - - // And append them to the current DOM sidetoc.appendChild(pagetoc); - main.appendChild(sidetoc); + + // And append them to the current DOM + const main = document.querySelector('main'); + main.insertBefore(sidetoc, main.firstChild); } if (document.getElementsByClassName("header").length <= 1) { From 4cbcb44d702e54b29e4f9df509f0b463e9142e5c Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 21 Apr 2025 17:18:22 +0200 Subject: [PATCH 2326/4206] Cleanup the Javascript and CSS of our custom TOC --- src/doc/rustc/theme/pagetoc.css | 8 -------- src/doc/rustc/theme/pagetoc.js | 10 +++------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/doc/rustc/theme/pagetoc.css b/src/doc/rustc/theme/pagetoc.css index 26c7ae78e8ac2..58ca1f8b26f81 100644 --- a/src/doc/rustc/theme/pagetoc.css +++ b/src/doc/rustc/theme/pagetoc.css @@ -10,14 +10,6 @@ min-width: 50px; } -.previous { - /* - adjust the space between the left sidebar or the left side of the screen - and the button that leads to the previous page - */ - margin-left: var(--page-padding); -} - @media only screen { @media (max-width: 1179px) { .sidebar-hidden #sidetoc { diff --git a/src/doc/rustc/theme/pagetoc.js b/src/doc/rustc/theme/pagetoc.js index f3549a6de5b02..927a5b10749b5 100644 --- a/src/doc/rustc/theme/pagetoc.js +++ b/src/doc/rustc/theme/pagetoc.js @@ -71,7 +71,8 @@ function updatePageToc(elem = undefined) { } } -if (document.getElementById("sidetoc") === null) { +if (document.getElementById("sidetoc") === null && + document.getElementsByClassName("header").length > 0) { // The sidetoc element doesn't exist yet, let's create it // Create the empty sidetoc and pagetoc elements @@ -80,16 +81,11 @@ if (document.getElementById("sidetoc") === null) { sidetoc.id = "sidetoc"; pagetoc.id = "pagetoc"; sidetoc.appendChild(pagetoc); - + // And append them to the current DOM const main = document.querySelector('main'); main.insertBefore(sidetoc, main.firstChild); -} -if (document.getElementsByClassName("header").length <= 1) { - // There's one or less headings, we don't need a page table of contents - document.getElementById("sidetoc").remove(); -} else { // Populate sidebar on load window.addEventListener("load", () => { for (const header of document.getElementsByClassName("header")) { From 84d7edd07ffd4848a3c08ddd46e4b3a296a7819c Mon Sep 17 00:00:00 2001 From: xizheyin Date: Fri, 16 May 2025 17:11:45 +0800 Subject: [PATCH 2327/4206] Enable [behind-upstream] triagebot option for rust-lang/rust Signed-off-by: xizheyin --- triagebot.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 9dcdbcecbeca6..a3866d62dca41 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1424,3 +1424,6 @@ compiletest = [ # Enable `@rustbot note` functionality # Documentation at: https://forge.rust-lang.org/triagebot/note.html [note] + +[behind-upstream] +days-threshold = 7 From 12c8fb857c97f97a0351eecc94e97e71b04cda70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Fri, 16 May 2025 17:47:29 +0800 Subject: [PATCH 2328/4206] Fix fname for miri --- src/tools/miri/src/shims/native_lib.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs index 0258a76c3e703..837e1b31cac50 100644 --- a/src/tools/miri/src/shims/native_lib.rs +++ b/src/tools/miri/src/shims/native_lib.rs @@ -117,7 +117,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let mut info = std::mem::MaybeUninit::::uninit(); unsafe { if libc::dladdr(*func.deref() as *const _, info.as_mut_ptr()) != 0 { - if std::ffi::CStr::from_ptr(info.assume_init().dli_fname).to_str().unwrap() + let info = info.assume_init(); + #[cfg(target_os = "cygwin")] + let fname_ptr = info.dli_fname.as_ptr(); + #[cfg(not(target_os = "cygwin"))] + let fname_ptr = info.dli_fname; + if std::ffi::CStr::from_ptr(fname_ptr).to_str().unwrap() != _lib_path.to_str().unwrap() { return None; From 428279ef6a66bda813fa1c136b232a1b73a6f3b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Fri, 16 May 2025 11:51:58 +0200 Subject: [PATCH 2329/4206] Bump zip to 3.0 --- src/tools/rust-analyzer/Cargo.lock | 11 ++++------- src/tools/rust-analyzer/xtask/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 51b6e109d79a4..9eff747c21a90 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -473,9 +473,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" +checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", "miniz_oxide", @@ -3263,17 +3263,14 @@ dependencies = [ [[package]] name = "zip" -version = "2.4.2" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50" +checksum = "12598812502ed0105f607f941c386f43d441e00148fce9dec3ca5ffb0bde9308" dependencies = [ "arbitrary", "crc32fast", - "crossbeam-utils", - "displaydoc", "flate2", "indexmap", "memchr", - "thiserror 2.0.12", "time", ] diff --git a/src/tools/rust-analyzer/xtask/Cargo.toml b/src/tools/rust-analyzer/xtask/Cargo.toml index 6195de5d20255..bb7d83c4b7d93 100644 --- a/src/tools/rust-analyzer/xtask/Cargo.toml +++ b/src/tools/rust-analyzer/xtask/Cargo.toml @@ -14,7 +14,7 @@ write-json = "0.1.4" xshell.workspace = true xflags = "0.3.2" time = { version = "0.3", default-features = false } -zip = { version = "2.4", default-features = false, features = ["deflate-flate2", "flate2", "time"] } +zip = { version = "3.0", default-features = false, features = ["deflate-flate2", "time"] } stdx.workspace = true proc-macro2 = "1.0.94" quote = "1.0.40" From 5326fc9bc78ca44e04d4583a8ced3a23768815e6 Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 14 Apr 2025 19:01:38 -0500 Subject: [PATCH 2330/4206] rustdoc: on mobile, make the sidebar full width and linewrap this is because the mobile sidebar cannot be resized, unlike on desktop. --- src/librustdoc/html/static/css/rustdoc.css | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index a81d5c9c49b4b..7be83b65fbfaf 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -2527,9 +2527,12 @@ in src-script.js and main.js z-index: 11; /* Reduce height slightly to account for mobile topbar. */ height: calc(100vh - 45px); - width: 200px; /* resize indicator: hide this when on touch or mobile */ border-right: none; + width: 100%; + } + .sidebar-elems .block li a { + white-space: wrap; } /* The source view uses a different design for the sidebar toggle, and doesn't have a topbar, From 7e3e8bdec4c992d2ec7474c1b70fb61aaaa9ed7e Mon Sep 17 00:00:00 2001 From: Ryan van Polen Date: Fri, 16 May 2025 10:32:12 +0200 Subject: [PATCH 2331/4206] Updated feature and stable flags --- library/core/src/result.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 736ffb7d0caf3..1bf713eaa8904 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1692,7 +1692,6 @@ impl Result, E> { /// # Examples /// /// ``` - /// #![feature(result_flattening)] /// let x: Result, u32> = Ok(Ok("hello")); /// assert_eq!(Ok("hello"), x.flatten()); /// @@ -1706,14 +1705,14 @@ impl Result, E> { /// Flattening only removes one level of nesting at a time: /// /// ``` - /// #![feature(result_flattening)] /// let x: Result, u32>, u32> = Ok(Ok(Ok("hello"))); /// assert_eq!(Ok(Ok("hello")), x.flatten()); /// assert_eq!(Ok("hello"), x.flatten().flatten()); /// ``` #[inline] - #[unstable(feature = "result_flattening", issue = "70142")] - #[rustc_const_unstable(feature = "result_flattening", issue = "70142")] + #[stable(feature = "result_flattening", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] + #[rustc_const_stable(feature = "result_flattening", since = "CURRENT_RUSTC_VERSION")] pub const fn flatten(self) -> Result { // FIXME(const-hack): could be written with `and_then` match self { From 4c2d3bc8bd663d619ae8502bc62afb49efb0ddfa Mon Sep 17 00:00:00 2001 From: Ryan van Polen Date: Fri, 16 May 2025 12:00:44 +0200 Subject: [PATCH 2332/4206] Removed feature flag from `compiler/rustc_driver_impl` --- compiler/rustc_driver_impl/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 056c476d5e120..54a331a490444 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -12,7 +12,6 @@ #![feature(decl_macro)] #![feature(panic_backtrace_config)] #![feature(panic_update_hook)] -#![feature(result_flattening)] #![feature(rustdoc_internals)] #![feature(try_blocks)] // tidy-alphabetical-end From 4860712f43a113bbc6c8ebebac39c073b0f750f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Fri, 16 May 2025 12:03:52 +0200 Subject: [PATCH 2333/4206] Inline some format args --- src/tools/rust-analyzer/crates/tt/src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/tt/src/lib.rs b/src/tools/rust-analyzer/crates/tt/src/lib.rs index a511bb0039cb1..14574a6456bda 100644 --- a/src/tools/rust-analyzer/crates/tt/src/lib.rs +++ b/src/tools/rust-analyzer/crates/tt/src/lib.rs @@ -825,12 +825,12 @@ impl Literal { let symbol = self.0.symbol.as_str().strip_prefix('-').unwrap_or(self.0.symbol.as_str()); match self.0.kind { - LitKind::Byte => write!(f, "b'{}'", symbol), - LitKind::Char => write!(f, "'{}'", symbol), - LitKind::Integer | LitKind::Float | LitKind::Err(_) => write!(f, "{}", symbol), - LitKind::Str => write!(f, "\"{}\"", symbol), - LitKind::ByteStr => write!(f, "b\"{}\"", symbol), - LitKind::CStr => write!(f, "c\"{}\"", symbol), + LitKind::Byte => write!(f, "b'{symbol}'"), + LitKind::Char => write!(f, "'{symbol}'"), + LitKind::Integer | LitKind::Float | LitKind::Err(_) => write!(f, "{symbol}"), + LitKind::Str => write!(f, "\"{symbol}\""), + LitKind::ByteStr => write!(f, "b\"{symbol}\""), + LitKind::CStr => write!(f, "c\"{symbol}\""), LitKind::StrRaw(num_of_hashes) => { let num_of_hashes = num_of_hashes as usize; write!( From 57782e0ff1e9833e121187f1c33b72bec6a8a61a Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 3 Aug 2024 00:29:23 -0400 Subject: [PATCH 2334/4206] Rewrite `non_copy_const` --- clippy_lints/src/non_copy_const.rs | 1063 +++++++++++------ clippy_utils/src/ty/mod.rs | 11 + .../ui/borrow_interior_mutable_const/enums.rs | 18 +- .../enums.stderr | 50 +- .../borrow_interior_mutable_const/others.rs | 44 +- .../others.stderr | 63 +- .../projections.stderr | 16 +- .../borrow_interior_mutable_const/traits.rs | 51 +- .../traits.stderr | 66 +- tests/ui/crashes/ice-12979.1.fixed | 2 + tests/ui/crashes/ice-12979.2.fixed | 3 + tests/ui/crashes/ice-12979.rs | 3 + tests/ui/crashes/ice-12979.stderr | 19 + tests/ui/crashes/ice-9445.rs | 4 - tests/ui/crashes/ice-9445.stderr | 12 - .../declare_interior_mutable_const/enums.rs | 29 +- .../enums.stderr | 71 +- .../declare_interior_mutable_const/others.rs | 9 +- .../others.stderr | 26 +- .../declare_interior_mutable_const/traits.rs | 33 +- .../traits.stderr | 65 +- 21 files changed, 981 insertions(+), 677 deletions(-) create mode 100644 tests/ui/crashes/ice-12979.1.fixed create mode 100644 tests/ui/crashes/ice-12979.2.fixed create mode 100644 tests/ui/crashes/ice-12979.rs create mode 100644 tests/ui/crashes/ice-12979.stderr delete mode 100644 tests/ui/crashes/ice-9445.rs delete mode 100644 tests/ui/crashes/ice-9445.stderr diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 6d3e77b6b6e97..f57ab0e6781d6 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -1,25 +1,46 @@ -use std::ptr; +// Implementation for lints detecting interior mutability in constants. +// +// For `declare_interior_mutable_const` there are three strategies used to +// determine if a value has interior mutability: +// * A type-based check. This is the least accurate, but can always run. +// * A const-eval based check. This is the most accurate, but this requires that the value is +// defined and does not work with generics. +// * A HIR-tree based check. This is less accurate than const-eval, but it can be applied to generic +// values. +// +// For `borrow_interior_mutable_const` the same three strategies are applied +// when checking a constant's value, but field and array index projections at +// the borrow site are taken into account as well. As an example: `FOO.bar` may +// have interior mutability, but `FOO.baz` may not. When borrowing `FOO.baz` no +// warning will be issued. +// +// No matter the lint or strategy, a warning should only be issued if a value +// definitely contains interior mutability. use clippy_config::Conf; -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::consts::{ConstEvalCtxt, Constant}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::is_in_const_context; use clippy_utils::macros::macro_backtrace; -use clippy_utils::ty::{InteriorMut, implements_trait}; -use rustc_abi::VariantIdx; +use clippy_utils::paths::{PathNS, lookup_path_str}; +use clippy_utils::ty::{get_field_idx_by_name, implements_trait}; +use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_hir::{ - BodyId, Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp, + Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Node, StructTailExpr, TraitItem, TraitItemKind, UnOp, +}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::mir::{ConstValue, UnevaluatedConst}; +use rustc_middle::ty::adjustment::{Adjust, Adjustment}; +use rustc_middle::ty::{ + self, AliasTyKind, EarlyBinder, GenericArgs, GenericArgsRef, Instance, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, + TypeckResults, TypingEnv, }; -use rustc_lint::{LateContext, LateLintPass, Lint}; -use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId, ReportedErrorInfo}; -use rustc_middle::ty::adjustment::Adjust; -use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::impl_lint_pass; -use rustc_span::{DUMMY_SP, Span, sym}; +use rustc_span::{DUMMY_SP, sym}; +use std::collections::hash_map::Entry; -// FIXME: this is a correctness problem but there's no suitable -// warn-by-default category. declare_clippy_lint! { /// ### What it does /// Checks for declaration of `const` items which is interior @@ -74,8 +95,6 @@ declare_clippy_lint! { "declaring `const` with interior mutability" } -// FIXME: this is a correctness problem but there's no suitable -// warn-by-default category. declare_clippy_lint! { /// ### What it does /// Checks if `const` items which is interior mutable (e.g., @@ -113,60 +132,96 @@ declare_clippy_lint! { "referencing `const` with interior mutability" } -#[derive(Copy, Clone)] -enum Source<'tcx> { - Item { item: Span, ty: Ty<'tcx> }, - Assoc { item: Span }, - Expr { expr: Span }, +#[derive(Clone, Copy)] +enum IsFreeze { + /// The type and all possible values are `Freeze` + Yes, + /// The type itself is non-`Freeze`, but not all values are. + Maybe, + /// The type and all possible values are non-`Freeze` + No, } +impl IsFreeze { + /// Merges the variants of a sum type (i.e. an enum). + fn from_variants(iter: impl Iterator) -> Self { + iter.fold(Self::Yes, |x, y| match (x, y) { + (Self::Maybe, _) | (_, Self::Maybe) | (Self::No, Self::Yes) | (Self::Yes, Self::No) => Self::Maybe, + (Self::No, Self::No) => Self::No, + (Self::Yes, Self::Yes) => Self::Yes, + }) + } + + /// Merges the fields of a product type (e.g. a struct or tuple). + fn from_fields(mut iter: impl Iterator) -> Self { + iter.try_fold(Self::Yes, |x, y| match (x, y) { + (Self::No, _) | (_, Self::No) => None, + (Self::Maybe, _) | (_, Self::Maybe) => Some(Self::Maybe), + (Self::Yes, Self::Yes) => Some(Self::Yes), + }) + .unwrap_or(Self::No) + } + + /// Checks if this is definitely `Freeze`. + fn is_freeze(self) -> bool { + matches!(self, Self::Yes) + } -impl Source<'_> { - #[must_use] - fn lint(&self) -> (&'static Lint, &'static str, Span) { + /// Checks if this is definitely not `Freeze`. + fn is_not_freeze(self) -> bool { + matches!(self, Self::No) + } +} + +/// What operation caused a borrow to occur. +#[derive(Clone, Copy)] +enum BorrowCause { + Borrow, + Deref, + Index, + AutoDeref, + AutoBorrow, +} +impl BorrowCause { + fn note(self) -> Option<&'static str> { match self { - Self::Item { item, .. } | Self::Assoc { item, .. } => ( - DECLARE_INTERIOR_MUTABLE_CONST, - "a `const` item should not be interior mutable", - *item, - ), - Self::Expr { expr } => ( - BORROW_INTERIOR_MUTABLE_CONST, - "a `const` item with interior mutability should not be borrowed", - *expr, - ), + Self::Borrow => None, + Self::Deref => Some("this deref expression is a call to `Deref::deref`"), + Self::Index => Some("this index expression is a call to `Index::index`"), + Self::AutoDeref => Some("there is a compiler inserted call to `Deref::deref` here"), + Self::AutoBorrow => Some("there is a compiler inserted borrow here"), } } } -fn lint<'tcx>(cx: &LateContext<'tcx>, source: Source<'tcx>) { - let (lint, msg, span) = source.lint(); - span_lint_and_then(cx, lint, span, msg, |diag| { - if span.from_expansion() { - return; // Don't give suggestions into macros. - } - match source { - Source::Item { ty, .. } => { - let Some(sync_trait) = cx.tcx.lang_items().sync_trait() else { - return; - }; - if implements_trait(cx, ty, sync_trait, &[]) { - diag.help("consider making this a static item"); - } else { - diag.help( - "consider making this `Sync` so that it can go in a static item or using a `thread_local`", - ); - } - }, - Source::Assoc { .. } => (), - Source::Expr { .. } => { - diag.help("assign this const to a local or static variable, and use the variable here"); - }, - } - }); +/// The source of a borrow. Both what caused it and where. +struct BorrowSource<'tcx> { + expr: &'tcx Expr<'tcx>, + cause: BorrowCause, +} +impl<'tcx> BorrowSource<'tcx> { + fn new(tcx: TyCtxt<'tcx>, expr: &'tcx Expr<'tcx>, cause: BorrowCause) -> Self { + // Custom deref and index impls will always have an auto-borrow inserted since we + // never work with reference types. + let (expr, cause) = if matches!(cause, BorrowCause::AutoBorrow) + && let Node::Expr(parent) = tcx.parent_hir_node(expr.hir_id) + { + match parent.kind { + ExprKind::Unary(UnOp::Deref, _) => (parent, BorrowCause::Deref), + ExprKind::Index(..) => (parent, BorrowCause::Index), + _ => (expr, cause), + } + } else { + (expr, cause) + }; + Self { expr, cause } + } } pub struct NonCopyConst<'tcx> { - interior_mut: InteriorMut<'tcx>, + ignore_tys: DefIdSet, + // Cache checked types. We can recurse through a type multiple times so this + // can be hit quite frequently. + freeze_tys: FxHashMap, IsFreeze>, } impl_lint_pass!(NonCopyConst<'_> => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]); @@ -174,332 +229,631 @@ impl_lint_pass!(NonCopyConst<'_> => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTE impl<'tcx> NonCopyConst<'tcx> { pub fn new(tcx: TyCtxt<'tcx>, conf: &'static Conf) -> Self { Self { - interior_mut: InteriorMut::without_pointers(tcx, &conf.ignore_interior_mutability), + ignore_tys: conf + .ignore_interior_mutability + .iter() + .flat_map(|ignored_ty| lookup_path_str(tcx, PathNS::Type, ignored_ty)) + .collect(), + freeze_tys: FxHashMap::default(), } } - fn is_value_unfrozen_raw_inner(cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool { - // No branch that we check (yet) should continue if val isn't a branch - let Some(branched_val) = val.try_to_branch() else { - return false; - }; - match *ty.kind() { - // the fact that we have to dig into every structs to search enums - // leads us to the point checking `UnsafeCell` directly is the only option. - ty::Adt(ty_def, ..) if ty_def.is_unsafe_cell() => true, - // As of 2022-09-08 miri doesn't track which union field is active so there's no safe way to check the - // contained value. - ty::Adt(def, ..) if def.is_union() => false, - ty::Array(ty, _) => branched_val - .iter() - .any(|field| Self::is_value_unfrozen_raw_inner(cx, *field, ty)), - ty::Adt(def, args) if def.is_enum() => { - let Some((&variant_valtree, fields)) = branched_val.split_first() else { - return false; - }; - let variant_index = variant_valtree.unwrap_leaf(); - let variant_index = VariantIdx::from_u32(variant_index.to_u32()); - fields - .iter() - .copied() - .zip( - def.variants()[variant_index] + /// Checks if a value of the given type is `Freeze`, or may be depending on the value. + fn is_ty_freeze(&mut self, tcx: TyCtxt<'tcx>, typing_env: TypingEnv<'tcx>, ty: Ty<'tcx>) -> IsFreeze { + let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty); + match self.freeze_tys.entry(ty) { + Entry::Occupied(e) => *e.get(), + Entry::Vacant(e) => { + let e = e.insert(IsFreeze::Yes); + if ty.is_freeze(tcx, typing_env) { + return IsFreeze::Yes; + } + let is_freeze = match *ty.kind() { + ty::Adt(adt, _) if adt.is_unsafe_cell() => { + *e = IsFreeze::No; + return IsFreeze::No; + }, + ty::Adt(adt, _) if self.ignore_tys.contains(&adt.did()) => return IsFreeze::Yes, + ty::Adt(adt, args) if adt.is_enum() => IsFreeze::from_variants(adt.variants().iter().map(|v| { + IsFreeze::from_fields( + v.fields + .iter() + .map(|f| self.is_ty_freeze(tcx, typing_env, f.ty(tcx, args))), + ) + })), + // Workaround for `ManuallyDrop`-like unions. + ty::Adt(adt, args) + if adt.is_union() + && adt.non_enum_variant().fields.iter().any(|f| { + tcx.layout_of(typing_env.as_query_input(f.ty(tcx, args))) + .is_ok_and(|l| l.layout.size().bytes() == 0) + }) => + { + return IsFreeze::Yes; + }, + // Rust doesn't have the concept of an active union field so we have + // to treat all fields as active. + ty::Adt(adt, args) => IsFreeze::from_fields( + adt.non_enum_variant() .fields .iter() - .map(|field| field.ty(cx.tcx, args)), - ) - .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, field, ty)) - }, - ty::Adt(def, args) => branched_val - .iter() - .zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, args))) - .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)), - ty::Tuple(tys) => branched_val - .iter() - .zip(tys) - .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)), - ty::Alias(ty::Projection, _) => match cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty) { - Ok(normalized_ty) if ty != normalized_ty => Self::is_value_unfrozen_raw_inner(cx, val, normalized_ty), - _ => false, + .map(|f| self.is_ty_freeze(tcx, typing_env, f.ty(tcx, args))), + ), + ty::Array(ty, _) | ty::Pat(ty, _) => self.is_ty_freeze(tcx, typing_env, ty), + ty::Tuple(tys) => { + IsFreeze::from_fields(tys.iter().map(|ty| self.is_ty_freeze(tcx, typing_env, ty))) + }, + // Treat type parameters as though they were `Freeze`. + ty::Param(_) | ty::Alias(..) => return IsFreeze::Yes, + // TODO: check other types. + _ => { + *e = IsFreeze::No; + return IsFreeze::No; + }, + }; + if !is_freeze.is_freeze() { + self.freeze_tys.insert(ty, is_freeze); + } + is_freeze }, - _ => false, } } - fn is_value_unfrozen_raw( - cx: &LateContext<'tcx>, - result: Result, Ty<'tcx>>, ErrorHandled>, + /// Checks if the given constant value is `Freeze`. Returns `Err` if the constant + /// cannot be read, but the result depends on the value. + fn is_value_freeze( + &mut self, + tcx: TyCtxt<'tcx>, + typing_env: TypingEnv<'tcx>, ty: Ty<'tcx>, - ) -> bool { - result.map_or_else( - |err| { - // Consider `TooGeneric` cases as being unfrozen. - // This causes a false positive where an assoc const whose type is unfrozen - // have a value that is a frozen variant with a generic param (an example is - // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::GENERIC_VARIANT`). - // However, it prevents a number of false negatives that is, I think, important: - // 1. assoc consts in trait defs referring to consts of themselves (an example is - // `declare_interior_mutable_const::traits::ConcreteTypes::ANOTHER_ATOMIC`). - // 2. a path expr referring to assoc consts whose type is doesn't have any frozen variants in trait - // defs (i.e. without substitute for `Self`). (e.g. borrowing - // `borrow_interior_mutable_const::trait::ConcreteTypes::ATOMIC`) - // 3. similar to the false positive above; but the value is an unfrozen variant, or the type has no - // enums. (An example is - // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::UNFROZEN_VARIANT` and - // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::NO_ENUM`). - // One might be able to prevent these FNs correctly, and replace this with `false`; - // e.g. implementing `has_frozen_variant` described above, and not running this function - // when the type doesn't have any frozen variants would be the 'correct' way for the 2nd - // case (that actually removes another suboptimal behavior (I won't say 'false positive') where, - // similar to 2., but with a frozen variant) (e.g. borrowing - // `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`). - // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none). - matches!(err, ErrorHandled::TooGeneric(..)) + val: ConstValue<'tcx>, + ) -> Result { + let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty); + match self.is_ty_freeze(tcx, typing_env, ty) { + IsFreeze::Yes => Ok(true), + IsFreeze::Maybe if matches!(ty.kind(), ty::Adt(..) | ty::Array(..) | ty::Tuple(..)) => { + for &(val, ty) in tcx + .try_destructure_mir_constant_for_user_output(val, ty) + .ok_or(())? + .fields + { + if !self.is_value_freeze(tcx, typing_env, ty, val)? { + return Ok(false); + } + } + Ok(true) }, - |val| val.map_or(true, |val| Self::is_value_unfrozen_raw_inner(cx, val, ty)), - ) - } - - fn is_value_unfrozen_poly(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool { - let def_id = body_id.hir_id.owner.to_def_id(); - let args = ty::GenericArgs::identity_for_item(cx.tcx, def_id); - let instance = ty::Instance::new_raw(def_id, args); - let cid = GlobalId { - instance, - promoted: None, - }; - let typing_env = ty::TypingEnv::post_analysis(cx.tcx, def_id); - let result = cx.tcx.const_eval_global_id_for_typeck(typing_env, cid, DUMMY_SP); - Self::is_value_unfrozen_raw(cx, result, ty) - } - - fn is_value_unfrozen_expr(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool { - let args = cx.typeck_results().node_args(hir_id); - - let result = Self::const_eval_resolve( - cx.tcx, - cx.typing_env(), - ty::UnevaluatedConst::new(def_id, args), - DUMMY_SP, - ); - Self::is_value_unfrozen_raw(cx, result, ty) + IsFreeze::Maybe | IsFreeze::No => Ok(false), + } } - pub fn const_eval_resolve( + /// Checks if the given expression creates a value which is `Freeze`. + /// + /// This will return `true` if the type is maybe `Freeze`, but it cannot be + /// determined for certain from the value. + /// + /// `typing_env` and `gen_args` are from the constant's use site. + /// `typeck` and `e` are from the constant's definition site. + fn is_init_expr_freeze( + &mut self, tcx: TyCtxt<'tcx>, - typing_env: ty::TypingEnv<'tcx>, - ct: ty::UnevaluatedConst<'tcx>, - span: Span, - ) -> EvalToValTreeResult<'tcx> { - match ty::Instance::try_resolve(tcx, typing_env, ct.def, ct.args) { - Ok(Some(instance)) => { - let cid = GlobalId { - instance, - promoted: None, - }; - tcx.const_eval_global_id_for_typeck(typing_env, cid, span) + typing_env: TypingEnv<'tcx>, + typeck: &'tcx TypeckResults<'tcx>, + gen_args: GenericArgsRef<'tcx>, + e: &'tcx Expr<'tcx>, + ) -> bool { + // Make sure to instantiate all types coming from `typeck` with `gen_args`. + let ty = EarlyBinder::bind(typeck.expr_ty(e)).instantiate(tcx, gen_args); + let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty); + match self.is_ty_freeze(tcx, typing_env, ty) { + IsFreeze::Yes => true, + IsFreeze::No => false, + IsFreeze::Maybe => match e.kind { + ExprKind::Block(b, _) + if !b.targeted_by_break + && b.stmts.is_empty() + && let Some(e) = b.expr => + { + self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, e) + }, + ExprKind::Path(ref p) => { + let res = typeck.qpath_res(p, e.hir_id); + let gen_args = EarlyBinder::bind(typeck.node_args(e.hir_id)).instantiate(tcx, gen_args); + match res { + Res::Def(DefKind::Const | DefKind::AssocConst, did) + if let Ok(val) = + tcx.const_eval_resolve(typing_env, UnevaluatedConst::new(did, gen_args), DUMMY_SP) + && let Ok(is_freeze) = self.is_value_freeze(tcx, typing_env, ty, val) => + { + is_freeze + }, + Res::Def(DefKind::Const | DefKind::AssocConst, did) + if let Some((typeck, init)) = get_const_hir_value(tcx, typing_env, did, gen_args) => + { + self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, init) + }, + // Either this is a unit constructor, or some unknown value. + // In either case we consider the value to be `Freeze`. + _ => true, + } + }, + ExprKind::Call(callee, args) + if let ExprKind::Path(p) = &callee.kind + && let res = typeck.qpath_res(p, callee.hir_id) + && matches!(res, Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(_)) => + { + args.iter() + .all(|e| self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, e)) + }, + ExprKind::Struct(_, fields, StructTailExpr::None) => fields + .iter() + .all(|f| self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, f.expr)), + ExprKind::Tup(exprs) | ExprKind::Array(exprs) => exprs + .iter() + .all(|e| self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, e)), + ExprKind::Repeat(e, _) => self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, e), + _ => true, }, - Ok(None) => Err(ErrorHandled::TooGeneric(span)), - Err(err) => Err(ErrorHandled::Reported( - ReportedErrorInfo::non_const_eval_error(err), - span, - )), } } -} -impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { - fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) { - if let ItemKind::Const(.., body_id) = it.kind { - let ty = cx.tcx.type_of(it.owner_id).instantiate_identity(); - if !ignored_macro(cx, it) - && self.interior_mut.is_interior_mut_ty(cx, ty) - && Self::is_value_unfrozen_poly(cx, body_id, ty) - { - lint(cx, Source::Item { item: it.span, ty }); + /// Checks if the given expression (or a local projection of it) is both borrowed and + /// definitely a non-`Freeze` type. + fn is_non_freeze_expr_borrowed( + &mut self, + tcx: TyCtxt<'tcx>, + typing_env: TypingEnv<'tcx>, + typeck: &'tcx TypeckResults<'tcx>, + mut src_expr: &'tcx Expr<'tcx>, + ) -> Option> { + let mut parents = tcx.hir_parent_iter(src_expr.hir_id); + loop { + let ty = typeck.expr_ty(src_expr); + // Normalized as we need to check if this is an array later. + let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty); + let is_freeze = self.is_ty_freeze(tcx, typing_env, ty); + if is_freeze.is_freeze() { + return None; } - } - } - - fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'_>) { - if let TraitItemKind::Const(_, body_id_opt) = &trait_item.kind { - let ty = cx.tcx.type_of(trait_item.owner_id).instantiate_identity(); - - // Normalize assoc types because ones originated from generic params - // bounded other traits could have their bound. - let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty); - if self.interior_mut.is_interior_mut_ty(cx, normalized) - // When there's no default value, lint it only according to its type; - // in other words, lint consts whose value *could* be unfrozen, not definitely is. - // This feels inconsistent with how the lint treats generic types, - // which avoids linting types which potentially become unfrozen. - // One could check whether an unfrozen type have a *frozen variant* - // (like `body_id_opt.map_or_else(|| !has_frozen_variant(...), ...)`), - // and do the same as the case of generic types at impl items. - // Note that it isn't sufficient to check if it has an enum - // since all of that enum's variants can be unfrozen: - // i.e. having an enum doesn't necessary mean a type has a frozen variant. - // And, implementing it isn't a trivial task; it'll probably end up - // re-implementing the trait predicate evaluation specific to `Freeze`. - && body_id_opt.is_none_or(|body_id| Self::is_value_unfrozen_poly(cx, body_id, normalized)) - { - lint(cx, Source::Assoc { item: trait_item.span }); + if let [adjust, ..] = typeck.expr_adjustments(src_expr) { + return does_adjust_borrow(adjust) + .filter(|_| is_freeze.is_not_freeze()) + .map(|cause| BorrowSource::new(tcx, src_expr, cause)); } + let Some((_, Node::Expr(use_expr))) = parents.next() else { + return None; + }; + match use_expr.kind { + ExprKind::Field(..) => {}, + ExprKind::Index(..) if ty.is_array() => {}, + ExprKind::AddrOf(..) if is_freeze.is_not_freeze() => { + return Some(BorrowSource::new(tcx, use_expr, BorrowCause::Borrow)); + }, + // All other expressions use the value. + _ => return None, + } + src_expr = use_expr; } } - fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) { - if let ImplItemKind::Const(_, body_id) = &impl_item.kind { - let item_def_id = cx.tcx.hir_get_parent_item(impl_item.hir_id()).def_id; - let item = cx.tcx.hir_expect_item(item_def_id); - - match &item.kind { - ItemKind::Impl(Impl { - of_trait: Some(of_trait_ref), - .. - }) => { - if let Some(of_trait_def_id) = of_trait_ref.trait_def_id() - // Lint a trait impl item only when the definition is a generic type, - // assuming an assoc const is not meant to be an interior mutable type. - && let Some(of_assoc_item) = cx - .tcx - .associated_item(impl_item.owner_id) - .trait_item_def_id - && cx - .tcx - .layout_of(ty::TypingEnv::post_analysis(cx.tcx, of_trait_def_id).as_query_input( - // Normalize assoc types because ones originated from generic params - // bounded other traits could have their bound at the trait defs; - // and, in that case, the definition is *not* generic. - cx.tcx.normalize_erasing_regions( - ty::TypingEnv::post_analysis(cx.tcx, of_trait_def_id), - cx.tcx.type_of(of_assoc_item).instantiate_identity(), - ), - )) - .is_err() - // If there were a function like `has_frozen_variant` described above, - // we should use here as a frozen variant is a potential to be frozen - // similar to unknown layouts. - // e.g. `layout_of(...).is_err() || has_frozen_variant(...);` - && let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity() - && let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty) - && self.interior_mut.is_interior_mut_ty(cx, normalized) - && Self::is_value_unfrozen_poly(cx, *body_id, normalized) - { - lint(cx, Source::Assoc { item: impl_item.span }); + /// Checks if the given value (or a local projection of it) is both borrowed and + /// definitely non-`Freeze`. Returns `Err` if the constant cannot be read, but the + /// result depends on the value. + fn is_non_freeze_val_borrowed( + &mut self, + tcx: TyCtxt<'tcx>, + typing_env: TypingEnv<'tcx>, + typeck: &'tcx TypeckResults<'tcx>, + mut src_expr: &'tcx Expr<'tcx>, + mut val: ConstValue<'tcx>, + ) -> Result>, ()> { + let mut parents = tcx.hir_parent_iter(src_expr.hir_id); + let mut ty = typeck.expr_ty(src_expr); + loop { + // Normalized as we need to check if this is an array later. + ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty); + if let [adjust, ..] = typeck.expr_adjustments(src_expr) { + let res = if let Some(cause) = does_adjust_borrow(adjust) + && !self.is_value_freeze(tcx, typing_env, ty, val)? + { + Some(BorrowSource::new(tcx, src_expr, cause)) + } else { + None + }; + return Ok(res); + } + // Check only the type here as the result gets cached for each type. + if self.is_ty_freeze(tcx, typing_env, ty).is_freeze() { + return Ok(None); + } + let Some((_, Node::Expr(use_expr))) = parents.next() else { + return Ok(None); + }; + let next_val = match use_expr.kind { + ExprKind::Field(_, name) => { + if let Some(idx) = get_field_idx_by_name(ty, name.name) { + tcx.try_destructure_mir_constant_for_user_output(val, ty) + .ok_or(())? + .fields + .get(idx) + } else { + return Ok(None); } }, - ItemKind::Impl(Impl { of_trait: None, .. }) => { - let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity(); - // Normalize assoc types originated from generic params. - let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty); - - if self.interior_mut.is_interior_mut_ty(cx, normalized) - && Self::is_value_unfrozen_poly(cx, *body_id, normalized) - { - lint(cx, Source::Assoc { item: impl_item.span }); + ExprKind::Index(_, idx, _) if ty.is_array() => { + let val = tcx.try_destructure_mir_constant_for_user_output(val, ty).ok_or(())?; + if let Some(Constant::Int(idx)) = ConstEvalCtxt::with_env(tcx, typing_env, typeck).eval(idx) { + val.fields.get(idx as usize) + } else { + // It's some value in the array so check all of them. + for &(val, _) in val.fields { + if let Some(src) = + self.is_non_freeze_val_borrowed(tcx, typing_env, typeck, use_expr, val)? + { + return Ok(Some(src)); + } + } + return Ok(None); } }, - _ => (), + ExprKind::AddrOf(..) if !self.is_value_freeze(tcx, typing_env, ty, val)? => { + return Ok(Some(BorrowSource::new(tcx, use_expr, BorrowCause::Borrow))); + }, + // All other expressions use the value. + _ => return Ok(None), + }; + src_expr = use_expr; + if let Some(&(next_val, next_ty)) = next_val { + ty = next_ty; + val = next_val; + } else { + return Ok(None); } } } - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Path(qpath) = &expr.kind { - // Only lint if we use the const item inside a function. - if is_in_const_context(cx) { - return; + /// Checks if the given value (or a local projection of it) is both borrowed and + /// definitely non-`Freeze`. + /// + /// `typing_env` and `init_args` are from the constant's use site. + /// `init_typeck` and `init_expr` are from the constant's definition site. + #[expect(clippy::too_many_arguments, clippy::too_many_lines)] + fn is_non_freeze_init_borrowed( + &mut self, + tcx: TyCtxt<'tcx>, + typing_env: TypingEnv<'tcx>, + typeck: &'tcx TypeckResults<'tcx>, + mut src_expr: &'tcx Expr<'tcx>, + mut init_typeck: &'tcx TypeckResults<'tcx>, + mut init_args: GenericArgsRef<'tcx>, + mut init_expr: &'tcx Expr<'tcx>, + ) -> Option> { + // Make sure to instantiate all types coming from `init_typeck` with `init_args`. + let mut parents = tcx.hir_parent_iter(src_expr.hir_id); + loop { + // First handle any adjustments since they are cheap to check. + if let [adjust, ..] = typeck.expr_adjustments(src_expr) { + return does_adjust_borrow(adjust) + .filter(|_| !self.is_init_expr_freeze(tcx, typing_env, init_typeck, init_args, init_expr)) + .map(|cause| BorrowSource::new(tcx, src_expr, cause)); } - // Make sure it is a const item. - let Res::Def(DefKind::Const | DefKind::AssocConst, item_def_id) = cx.qpath_res(qpath, expr.hir_id) else { - return; - }; - - // Climb up to resolve any field access and explicit referencing. - let mut cur_expr = expr; - let mut dereferenced_expr = expr; - let mut needs_check_adjustment = true; + // Then read through constants and blocks on the init expression before + // applying the next use expression. loop { - let parent_id = cx.tcx.parent_hir_id(cur_expr.hir_id); - if parent_id == cur_expr.hir_id { - break; + match init_expr.kind { + ExprKind::Block(b, _) + if !b.targeted_by_break + && b.stmts.is_empty() + && let Some(next_init) = b.expr => + { + init_expr = next_init; + }, + ExprKind::Path(ref init_path) => { + let next_init_args = + EarlyBinder::bind(init_typeck.node_args(init_expr.hir_id)).instantiate(tcx, init_args); + match init_typeck.qpath_res(init_path, init_expr.hir_id) { + Res::Def(DefKind::Ctor(..), _) => return None, + Res::Def(DefKind::Const | DefKind::AssocConst, did) + if let Ok(val) = tcx.const_eval_resolve( + typing_env, + UnevaluatedConst::new(did, next_init_args), + DUMMY_SP, + ) && let Ok(res) = + self.is_non_freeze_val_borrowed(tcx, typing_env, init_typeck, src_expr, val) => + { + return res; + }, + Res::Def(DefKind::Const | DefKind::AssocConst, did) + if let Some((next_typeck, value)) = + get_const_hir_value(tcx, typing_env, did, next_init_args) => + { + init_typeck = next_typeck; + init_args = next_init_args; + init_expr = value; + }, + // There's no more that we can read from the init expression. Switch to a + // type based check. + _ => { + return self.is_non_freeze_expr_borrowed(tcx, typing_env, typeck, src_expr); + }, + } + }, + _ => break, } - if let Node::Expr(parent_expr) = cx.tcx.hir_node(parent_id) { - match &parent_expr.kind { - ExprKind::AddrOf(..) => { - // `&e` => `e` must be referenced. - needs_check_adjustment = false; - }, - ExprKind::Field(..) => { - needs_check_adjustment = true; + } - // Check whether implicit dereferences happened; - // if so, no need to go further up - // because of the same reason as the `ExprKind::Unary` case. - if cx - .typeck_results() - .expr_adjustments(dereferenced_expr) - .iter() - .any(|adj| matches!(adj.kind, Adjust::Deref(_))) - { - break; - } + // Then a type check. Note we only check the type here as the result + // gets cached. + let ty = EarlyBinder::bind(typeck.expr_ty(src_expr)).instantiate(tcx, init_args); + // Normalized as we need to check if this is an array later. + let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty); + if self.is_ty_freeze(tcx, typing_env, ty).is_freeze() { + return None; + } - dereferenced_expr = parent_expr; - }, - ExprKind::Index(e, _, _) if ptr::eq(&raw const **e, cur_expr) => { - // `e[i]` => desugared to `*Index::index(&e, i)`, - // meaning `e` must be referenced. - // no need to go further up since a method call is involved now. - needs_check_adjustment = false; - break; - }, - ExprKind::Unary(UnOp::Deref, _) => { - // `*e` => desugared to `*Deref::deref(&e)`, - // meaning `e` must be referenced. - // no need to go further up since a method call is involved now. - needs_check_adjustment = false; - break; + // Finally reduce the init expression using the next use expression. + let Some((_, Node::Expr(use_expr))) = parents.next() else { + return None; + }; + init_expr = match &use_expr.kind { + ExprKind::Field(_, name) => match init_expr.kind { + ExprKind::Struct(_, fields, _) + if let Some(field) = fields.iter().find(|f| f.ident.name == name.name) => + { + field.expr + }, + ExprKind::Tup(fields) + if let Ok(idx) = name.as_str().parse::() + && let Some(field) = fields.get(idx) => + { + field + }, + ExprKind::Call(callee, args) + if let ExprKind::Path(callee_path) = &callee.kind + && matches!( + init_typeck.qpath_res(callee_path, callee.hir_id), + Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(_) + ) + && let Ok(idx) = name.as_str().parse::() + && let Some(arg) = args.get(idx) => + { + arg + }, + // Revert to a type based check as we don't know the field's value. + _ => return self.is_non_freeze_expr_borrowed(tcx, typing_env, typeck, use_expr), + }, + ExprKind::Index(_, idx, _) if ty.is_array() => match init_expr.kind { + ExprKind::Array(fields) => { + if let Some(Constant::Int(idx)) = ConstEvalCtxt::with_env(tcx, typing_env, typeck).eval(idx) { + // If the index is out of bounds it means the code + // unconditionally panics. In that case there is no borrow. + fields.get(idx as usize)? + } else { + // Unknown index, just run the check for all values. + return fields.iter().find_map(|f| { + self.is_non_freeze_init_borrowed( + tcx, + typing_env, + typeck, + use_expr, + init_typeck, + init_args, + f, + ) + }); + } + }, + // Just assume the index expression doesn't panic here. + ExprKind::Repeat(field, _) => field, + _ => return self.is_non_freeze_expr_borrowed(tcx, typing_env, typeck, use_expr), + }, + ExprKind::AddrOf(..) + if !self.is_init_expr_freeze(tcx, typing_env, init_typeck, init_args, init_expr) => + { + return Some(BorrowSource::new(tcx, use_expr, BorrowCause::Borrow)); + }, + // All other expressions use the value. + _ => return None, + }; + src_expr = use_expr; + } + } +} + +impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { + if let ItemKind::Const(ident, .., body_id) = item.kind + && !ident.is_special() + && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() + && match self.is_ty_freeze(cx.tcx, cx.typing_env(), ty) { + IsFreeze::No => true, + IsFreeze::Yes => false, + IsFreeze::Maybe => match cx.tcx.const_eval_poly(item.owner_id.to_def_id()) { + Ok(val) if let Ok(is_freeze) = self.is_value_freeze(cx.tcx, cx.typing_env(), ty, val) => !is_freeze, + _ => !self.is_init_expr_freeze( + cx.tcx, + cx.typing_env(), + cx.tcx.typeck(item.owner_id), + GenericArgs::identity_for_item(cx.tcx, item.owner_id), + cx.tcx.hir_body(body_id).value, + ), + }, + } + && !item.span.in_external_macro(cx.sess().source_map()) + // Only needed when compiling `std` + && !is_thread_local(cx, item) + { + span_lint_and_then( + cx, + DECLARE_INTERIOR_MUTABLE_CONST, + ident.span, + "a `const` item should not be interior mutable", + |diag| { + let Some(sync_trait) = cx.tcx.lang_items().sync_trait() else { + return; + }; + if implements_trait(cx, ty, sync_trait, &[]) { + diag.help("consider making this a static item"); + } else { + diag.help( + "consider making this `Sync` so that it can go in a static item or using a `thread_local`", + ); + } + }, + ); + } + } + + fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { + if let TraitItemKind::Const(_, body_id_opt) = item.kind + && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() + && match self.is_ty_freeze(cx.tcx, cx.typing_env(), ty) { + IsFreeze::No => true, + IsFreeze::Maybe if let Some(body_id) = body_id_opt => { + match cx.tcx.const_eval_poly(item.owner_id.to_def_id()) { + Ok(val) if let Ok(is_freeze) = self.is_value_freeze(cx.tcx, cx.typing_env(), ty, val) => { + !is_freeze }, - _ => break, + _ => !self.is_init_expr_freeze( + cx.tcx, + cx.typing_env(), + cx.tcx.typeck(item.owner_id), + GenericArgs::identity_for_item(cx.tcx, item.owner_id), + cx.tcx.hir_body(body_id).value, + ), } - cur_expr = parent_expr; - } else { - break; - } + }, + IsFreeze::Yes | IsFreeze::Maybe => false, } + && !item.span.in_external_macro(cx.sess().source_map()) + { + span_lint( + cx, + DECLARE_INTERIOR_MUTABLE_CONST, + item.ident.span, + "a `const` item should not be interior mutable", + ); + } + } - let ty = if needs_check_adjustment { - let adjustments = cx.typeck_results().expr_adjustments(dereferenced_expr); - if let Some(i) = adjustments - .iter() - .position(|adj| matches!(adj.kind, Adjust::Borrow(_) | Adjust::Deref(_))) - { - if i == 0 { - cx.typeck_results().expr_ty(dereferenced_expr) + fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { + if let ImplItemKind::Const(_, body_id) = item.kind + && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() + && match self.is_ty_freeze(cx.tcx, cx.typing_env(), ty) { + IsFreeze::Yes => false, + IsFreeze::No => { + // If this is a trait impl, check if the trait definition is the source + // of the cell. + if let Node::Item(parent_item) = cx.tcx.parent_hir_node(item.hir_id()) + && let ItemKind::Impl(impl_block) = parent_item.kind + && let Some(of_trait) = impl_block.of_trait + && let Some(trait_id) = of_trait.trait_def_id() + { + // Replace all instances of `::AssocType` with the + // unit type and check again. If the result is the same then the + // trait definition is the cause. + let ty = (ReplaceAssocFolder { + tcx: cx.tcx, + trait_id, + self_ty: cx.tcx.type_of(parent_item.owner_id).instantiate_identity(), + }) + .fold_ty(cx.tcx.type_of(item.owner_id).instantiate_identity()); + // `ty` may not be normalizable, but that should be fine. + !self.is_ty_freeze(cx.tcx, cx.typing_env(), ty).is_not_freeze() } else { - adjustments[i - 1].target + true } + }, + // Even if this is from a trait, there are values which don't have + // interior mutability. + IsFreeze::Maybe => match cx.tcx.const_eval_poly(item.owner_id.to_def_id()) { + Ok(val) if let Ok(is_freeze) = self.is_value_freeze(cx.tcx, cx.typing_env(), ty, val) => !is_freeze, + _ => !self.is_init_expr_freeze( + cx.tcx, + cx.typing_env(), + cx.tcx.typeck(item.owner_id), + GenericArgs::identity_for_item(cx.tcx, item.owner_id), + cx.tcx.hir_body(body_id).value, + ), + }, + } + && !item.span.in_external_macro(cx.sess().source_map()) + { + span_lint( + cx, + DECLARE_INTERIOR_MUTABLE_CONST, + item.ident.span, + "a `const` item should not be interior mutable", + ); + } + } + + fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { + if let ExprKind::Path(qpath) = &e.kind + && let typeck = cx.typeck_results() + && let Res::Def(DefKind::Const | DefKind::AssocConst, did) = typeck.qpath_res(qpath, e.hir_id) + // As of `1.80` constant contexts can't borrow any type with interior mutability + && !is_in_const_context(cx) + && !self.is_ty_freeze(cx.tcx, cx.typing_env(), typeck.expr_ty(e)).is_freeze() + && let Some(borrow_src) = { + // The extra block helps formatting a lot. + if let Ok(val) = cx.tcx.const_eval_resolve( + cx.typing_env(), + UnevaluatedConst::new(did, typeck.node_args(e.hir_id)), + DUMMY_SP, + ) && let Ok(src) = self.is_non_freeze_val_borrowed(cx.tcx, cx.typing_env(), typeck, e, val) + { + src + } else if let init_args = typeck.node_args(e.hir_id) + && let Some((init_typeck, init)) = get_const_hir_value(cx.tcx, cx.typing_env(), did, init_args) + { + self.is_non_freeze_init_borrowed(cx.tcx, cx.typing_env(), typeck, e, init_typeck, init_args, init) } else { - // No borrow adjustments means the entire const is moved. - return; + self.is_non_freeze_expr_borrowed(cx.tcx, cx.typing_env(), typeck, e) } - } else { - cx.typeck_results().expr_ty(dereferenced_expr) - }; - - if self.interior_mut.is_interior_mut_ty(cx, ty) - && Self::is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty) - { - lint(cx, Source::Expr { expr: expr.span }); } + && !borrow_src.expr.span.in_external_macro(cx.sess().source_map()) + { + span_lint_and_then( + cx, + BORROW_INTERIOR_MUTABLE_CONST, + borrow_src.expr.span, + "a `const` item with interior mutability should not be borrowed", + |diag| { + if let Some(msg) = borrow_src.cause.note() { + diag.note(msg); + } + diag.help("assign this const to a local or static variable, and use the variable here"); + }, + ); } } } -fn ignored_macro(cx: &LateContext<'_>, it: &Item<'_>) -> bool { +struct ReplaceAssocFolder<'tcx> { + tcx: TyCtxt<'tcx>, + trait_id: DefId, + self_ty: Ty<'tcx>, +} +impl<'tcx> TypeFolder> for ReplaceAssocFolder<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + if let ty::Alias(AliasTyKind::Projection, ty) = ty.kind() + && ty.trait_def_id(self.tcx) == self.trait_id + && ty.self_ty() == self.self_ty + { + self.tcx.types.unit + } else { + ty.super_fold_with(self) + } + } +} + +fn is_thread_local(cx: &LateContext<'_>, it: &Item<'_>) -> bool { macro_backtrace(it.span).any(|macro_call| { matches!( cx.tcx.get_diagnostic_name(macro_call.def_id), @@ -507,3 +861,42 @@ fn ignored_macro(cx: &LateContext<'_>, it: &Item<'_>) -> bool { ) }) } + +/// Checks if the adjustment causes a borrow of the original value. Returns +/// `None` if the value is consumed instead of borrowed. +fn does_adjust_borrow(adjust: &Adjustment<'_>) -> Option { + match adjust.kind { + Adjust::Borrow(_) => Some(BorrowCause::AutoBorrow), + // Custom deref calls `::deref(&x)` resulting in a borrow. + Adjust::Deref(Some(_)) => Some(BorrowCause::AutoDeref), + // All other adjustments read the value. + _ => None, + } +} + +/// Attempts to get the value of a constant as a HIR expression. Also gets the +/// `TypeckResults` associated with the constant's body. +fn get_const_hir_value<'tcx>( + tcx: TyCtxt<'tcx>, + typing_env: TypingEnv<'tcx>, + did: DefId, + args: GenericArgsRef<'tcx>, +) -> Option<(&'tcx TypeckResults<'tcx>, &'tcx Expr<'tcx>)> { + let did = did.as_local()?; + let (did, body_id) = match tcx.hir_node(tcx.local_def_id_to_hir_id(did)) { + Node::Item(item) if let ItemKind::Const(.., body_id) = item.kind => (did, body_id), + Node::ImplItem(item) if let ImplItemKind::Const(.., body_id) = item.kind => (did, body_id), + Node::TraitItem(_) + if let Ok(Some(inst)) = Instance::try_resolve(tcx, typing_env, did.into(), args) + && let Some(did) = inst.def_id().as_local() => + { + match tcx.hir_node(tcx.local_def_id_to_hir_id(did)) { + Node::ImplItem(item) if let ImplItemKind::Const(.., body_id) = item.kind => (did, body_id), + Node::TraitItem(item) if let TraitItemKind::Const(.., Some(body_id)) = item.kind => (did, body_id), + _ => return None, + } + }, + _ => return None, + }; + Some((tcx.typeck(did), tcx.hir_body(body_id).value)) +} diff --git a/clippy_utils/src/ty/mod.rs b/clippy_utils/src/ty/mod.rs index 26d41cfb4977b..c50ad17bfad1e 100644 --- a/clippy_utils/src/ty/mod.rs +++ b/clippy_utils/src/ty/mod.rs @@ -1361,3 +1361,14 @@ pub fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { || ty.is_array() || matches!(ty.kind(), ty::Adt(adt_def, _) if cx.tcx.is_diagnostic_item(sym::Vec, adt_def.did())) } + +/// Gets the index of a field by name. +pub fn get_field_idx_by_name(ty: Ty<'_>, name: Symbol) -> Option { + match *ty.kind() { + ty::Adt(def, _) if def.is_union() || def.is_struct() => { + def.non_enum_variant().fields.iter().position(|f| f.name == name) + }, + ty::Tuple(_) => name.as_str().parse::().ok(), + _ => None, + } +} diff --git a/tests/ui/borrow_interior_mutable_const/enums.rs b/tests/ui/borrow_interior_mutable_const/enums.rs index da940a4cfb50b..ea47e588858ff 100644 --- a/tests/ui/borrow_interior_mutable_const/enums.rs +++ b/tests/ui/borrow_interior_mutable_const/enums.rs @@ -19,7 +19,7 @@ const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; fn borrow_optional_cell() { - let _ = &UNFROZEN_VARIANT; //~ ERROR: interior mutability + let _ = &UNFROZEN_VARIANT; //~ borrow_interior_mutable_const let _ = &FROZEN_VARIANT; } @@ -34,11 +34,11 @@ trait AssocConsts { // This is the "suboptimal behavior" mentioned in `is_value_unfrozen` // caused by a similar reason to unfrozen types without any default values // get linted even if it has frozen variants'. - let _ = &Self::TO_BE_FROZEN_VARIANT; //~ ERROR: interior mutability + let _ = &Self::TO_BE_FROZEN_VARIANT; // The lint ignores default values because an impl of this trait can set // an unfrozen variant to `DEFAULTED_ON_FROZEN_VARIANT` and use the default impl for `function`. - let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; //~ ERROR: interior mutability + let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; } } @@ -47,9 +47,9 @@ impl AssocConsts for u64 { const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; fn function() { - let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR: interior mutability + let _ = &::TO_BE_UNFROZEN_VARIANT; //~ borrow_interior_mutable_const let _ = &::TO_BE_FROZEN_VARIANT; - let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; //~ ERROR: interior mutability + let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; //~ borrow_interior_mutable_const let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; } } @@ -71,7 +71,7 @@ impl AssocTypes for u64 { const TO_BE_FROZEN_VARIANT: Option = None; fn function() { - let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR: interior mutability + let _ = &::TO_BE_UNFROZEN_VARIANT; //~ borrow_interior_mutable_const let _ = &::TO_BE_FROZEN_VARIANT; } } @@ -88,14 +88,14 @@ impl BothOfCellAndGeneric { const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); fn function() { - let _ = &Self::UNFROZEN_VARIANT; //~ ERROR: interior mutability - let _ = &Self::GENERIC_VARIANT; //~ ERROR: interior mutability + let _ = &Self::UNFROZEN_VARIANT; //~ borrow_interior_mutable_const + let _ = &Self::GENERIC_VARIANT; let _ = &Self::FROZEN_VARIANT; } } fn main() { // constants defined in foreign crates - let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ ERROR: interior mutability + let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ borrow_interior_mutable_const let _ = &helper::WRAPPED_PRIVATE_FROZEN_VARIANT; } diff --git a/tests/ui/borrow_interior_mutable_const/enums.stderr b/tests/ui/borrow_interior_mutable_const/enums.stderr index 43850384b9036..7a3cb7d6aa952 100644 --- a/tests/ui/borrow_interior_mutable_const/enums.stderr +++ b/tests/ui/borrow_interior_mutable_const/enums.stderr @@ -1,8 +1,8 @@ error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/enums.rs:22:14 + --> tests/ui/borrow_interior_mutable_const/enums.rs:22:13 | LL | let _ = &UNFROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here note: the lint level is defined here @@ -12,68 +12,44 @@ LL | #![deny(clippy::borrow_interior_mutable_const)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/enums.rs:37:18 - | -LL | let _ = &Self::TO_BE_FROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/enums.rs:41:18 - | -LL | let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/enums.rs:50:18 + --> tests/ui/borrow_interior_mutable_const/enums.rs:50:17 | LL | let _ = &::TO_BE_UNFROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/enums.rs:52:18 + --> tests/ui/borrow_interior_mutable_const/enums.rs:52:17 | LL | let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/enums.rs:74:18 + --> tests/ui/borrow_interior_mutable_const/enums.rs:74:17 | LL | let _ = &::TO_BE_UNFROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/enums.rs:91:18 + --> tests/ui/borrow_interior_mutable_const/enums.rs:91:17 | LL | let _ = &Self::UNFROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/enums.rs:92:18 - | -LL | let _ = &Self::GENERIC_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/enums.rs:99:14 + --> tests/ui/borrow_interior_mutable_const/enums.rs:99:13 | LL | let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here -error: aborting due to 9 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/borrow_interior_mutable_const/others.rs b/tests/ui/borrow_interior_mutable_const/others.rs index fa729b62d7f51..720f88326d7e3 100644 --- a/tests/ui/borrow_interior_mutable_const/others.rs +++ b/tests/ui/borrow_interior_mutable_const/others.rs @@ -62,20 +62,14 @@ mod issue12979 { const CELL_REF: StaticRef<(UnsafeCell,)> = unsafe { StaticRef::new(std::ptr::null()) }; fn main() { - ATOMIC.store(1, Ordering::SeqCst); - //~^ borrow_interior_mutable_const - assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); - //~^ borrow_interior_mutable_const + ATOMIC.store(1, Ordering::SeqCst); //~ borrow_interior_mutable_const + assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ borrow_interior_mutable_const let _once = ONCE_INIT; - let _once_ref = &ONCE_INIT; - //~^ borrow_interior_mutable_const - let _once_ref_2 = &&ONCE_INIT; - //~^ borrow_interior_mutable_const - let _once_ref_4 = &&&&ONCE_INIT; - //~^ borrow_interior_mutable_const - let _once_mut = &mut ONCE_INIT; - //~^ borrow_interior_mutable_const + let _once_ref = &ONCE_INIT; //~ borrow_interior_mutable_const + let _once_ref_2 = &&ONCE_INIT; //~ borrow_interior_mutable_const + let _once_ref_4 = &&&&ONCE_INIT; //~ borrow_interior_mutable_const + let _once_mut = &mut ONCE_INIT; //~ borrow_interior_mutable_const let _atomic_into_inner = ATOMIC.into_inner(); // these should be all fine. let _twice = (ONCE_INIT, ONCE_INIT); @@ -86,30 +80,22 @@ fn main() { let _ref_array_once = &[ONCE_INIT, ONCE_INIT][0]; // referencing projection is still bad. - let _ = &ATOMIC_TUPLE; - //~^ borrow_interior_mutable_const - let _ = &ATOMIC_TUPLE.0; - //~^ borrow_interior_mutable_const - let _ = &(&&&&ATOMIC_TUPLE).0; - //~^ borrow_interior_mutable_const - let _ = &ATOMIC_TUPLE.0[0]; - //~^ borrow_interior_mutable_const - let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); - //~^ borrow_interior_mutable_const + let _ = &ATOMIC_TUPLE; //~ borrow_interior_mutable_const + let _ = &ATOMIC_TUPLE.0; //~ borrow_interior_mutable_const + let _ = &(&&&&ATOMIC_TUPLE).0; //~ borrow_interior_mutable_const + let _ = &ATOMIC_TUPLE.0[0]; //~ borrow_interior_mutable_const + let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ borrow_interior_mutable_const let _ = &ATOMIC_TUPLE.2; - let _ = (&&&&ATOMIC_TUPLE).0; - let _ = (&&&&ATOMIC_TUPLE).2; + let _ = (&&&&ATOMIC_TUPLE).0; //~ borrow_interior_mutable_const + let _ = (&&&&ATOMIC_TUPLE).2; //~ borrow_interior_mutable_const let _ = ATOMIC_TUPLE.0; let _ = ATOMIC_TUPLE.0[0]; - //~^ borrow_interior_mutable_const let _ = ATOMIC_TUPLE.1.into_iter(); let _ = ATOMIC_TUPLE.2; let _ = &{ ATOMIC_TUPLE }; - CELL.set(2); - //~^ borrow_interior_mutable_const - assert_eq!(CELL.get(), 6); - //~^ borrow_interior_mutable_const + CELL.set(2); //~ borrow_interior_mutable_const + assert_eq!(CELL.get(), 6); //~ borrow_interior_mutable_const assert_eq!(INTEGER, 8); assert!(STRING.is_empty()); diff --git a/tests/ui/borrow_interior_mutable_const/others.stderr b/tests/ui/borrow_interior_mutable_const/others.stderr index decea153f7173..6e887406dcdbb 100644 --- a/tests/ui/borrow_interior_mutable_const/others.stderr +++ b/tests/ui/borrow_interior_mutable_const/others.stderr @@ -4,6 +4,7 @@ error: a `const` item with interior mutability should not be borrowed LL | ATOMIC.store(1, Ordering::SeqCst); | ^^^^^^ | + = note: there is a compiler inserted borrow here = help: assign this const to a local or static variable, and use the variable here note: the lint level is defined here --> tests/ui/borrow_interior_mutable_const/others.rs:1:9 @@ -12,108 +13,120 @@ LL | #![deny(clippy::borrow_interior_mutable_const)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:67:16 + --> tests/ui/borrow_interior_mutable_const/others.rs:66:16 | LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); | ^^^^^^ | + = note: there is a compiler inserted borrow here = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:71:22 + --> tests/ui/borrow_interior_mutable_const/others.rs:69:21 | LL | let _once_ref = &ONCE_INIT; - | ^^^^^^^^^ + | ^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:73:25 + --> tests/ui/borrow_interior_mutable_const/others.rs:70:24 | LL | let _once_ref_2 = &&ONCE_INIT; - | ^^^^^^^^^ + | ^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:75:27 + --> tests/ui/borrow_interior_mutable_const/others.rs:71:26 | LL | let _once_ref_4 = &&&&ONCE_INIT; - | ^^^^^^^^^ + | ^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:77:26 + --> tests/ui/borrow_interior_mutable_const/others.rs:72:21 | LL | let _once_mut = &mut ONCE_INIT; - | ^^^^^^^^^ + | ^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:89:14 + --> tests/ui/borrow_interior_mutable_const/others.rs:83:13 | LL | let _ = &ATOMIC_TUPLE; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:91:14 + --> tests/ui/borrow_interior_mutable_const/others.rs:84:13 | LL | let _ = &ATOMIC_TUPLE.0; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:93:19 + --> tests/ui/borrow_interior_mutable_const/others.rs:85:18 | LL | let _ = &(&&&&ATOMIC_TUPLE).0; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:95:14 + --> tests/ui/borrow_interior_mutable_const/others.rs:86:13 | LL | let _ = &ATOMIC_TUPLE.0[0]; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:97:13 + --> tests/ui/borrow_interior_mutable_const/others.rs:87:13 | LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ | + = note: there is a compiler inserted borrow here = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:103:13 + --> tests/ui/borrow_interior_mutable_const/others.rs:89:17 | -LL | let _ = ATOMIC_TUPLE.0[0]; - | ^^^^^^^^^^^^ +LL | let _ = (&&&&ATOMIC_TUPLE).0; + | ^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:109:5 + --> tests/ui/borrow_interior_mutable_const/others.rs:90:17 + | +LL | let _ = (&&&&ATOMIC_TUPLE).2; + | ^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> tests/ui/borrow_interior_mutable_const/others.rs:97:5 | LL | CELL.set(2); | ^^^^ | + = note: there is a compiler inserted borrow here = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:111:16 + --> tests/ui/borrow_interior_mutable_const/others.rs:98:16 | LL | assert_eq!(CELL.get(), 6); | ^^^^ | + = note: there is a compiler inserted borrow here = help: assign this const to a local or static variable, and use the variable here -error: aborting due to 14 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui/borrow_interior_mutable_const/projections.stderr b/tests/ui/borrow_interior_mutable_const/projections.stderr index eabaf66560ada..b0e1883f8bf77 100644 --- a/tests/ui/borrow_interior_mutable_const/projections.stderr +++ b/tests/ui/borrow_interior_mutable_const/projections.stderr @@ -1,8 +1,8 @@ error: a `const` item should not be interior mutable - --> tests/ui/borrow_interior_mutable_const/projections.rs:27:1 + --> tests/ui/borrow_interior_mutable_const/projections.rs:27:7 | LL | const CELL: Assoc = UnsafeCell::new(0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ | = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` note: the lint level is defined here @@ -12,18 +12,18 @@ LL | #![deny(clippy::declare_interior_mutable_const)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/borrow_interior_mutable_const/projections.rs:29:1 + --> tests/ui/borrow_interior_mutable_const/projections.rs:29:7 | LL | const MUTABLE: MaybeMutable = MaybeMutable::Mutable(CELL); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ | = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/projections.rs:38:16 + --> tests/ui/borrow_interior_mutable_const/projections.rs:38:15 | LL | print_ref(&CELL); - | ^^^^ + | ^^^^^ | = help: assign this const to a local or static variable, and use the variable here note: the lint level is defined here @@ -33,10 +33,10 @@ LL | #![deny(clippy::borrow_interior_mutable_const)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/projections.rs:40:16 + --> tests/ui/borrow_interior_mutable_const/projections.rs:40:15 | LL | print_ref(&MUTABLE); - | ^^^^^^^ + | ^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here diff --git a/tests/ui/borrow_interior_mutable_const/traits.rs b/tests/ui/borrow_interior_mutable_const/traits.rs index c4878dbe57b29..34a758efa2c82 100644 --- a/tests/ui/borrow_interior_mutable_const/traits.rs +++ b/tests/ui/borrow_interior_mutable_const/traits.rs @@ -12,8 +12,7 @@ trait ConcreteTypes { const STRING: String; fn function() { - let _ = &Self::ATOMIC; - //~^ borrow_interior_mutable_const + let _ = &Self::ATOMIC; //~ borrow_interior_mutable_const let _ = &Self::STRING; } } @@ -24,8 +23,7 @@ impl ConcreteTypes for u64 { fn function() { // Lint this again since implementers can choose not to borrow it. - let _ = &Self::ATOMIC; - //~^ borrow_interior_mutable_const + let _ = &Self::ATOMIC; //~ borrow_interior_mutable_const let _ = &Self::STRING; } } @@ -50,8 +48,7 @@ impl GenericTypes for Vec { fn function() { let _ = &Self::TO_REMAIN_GENERIC; - let _ = &Self::TO_BE_CONCRETE; - //~^ borrow_interior_mutable_const + let _ = &Self::TO_BE_CONCRETE; //~ borrow_interior_mutable_const } } @@ -86,10 +83,8 @@ impl AssocTypes for Vec { fn function() { let _ = &Self::TO_BE_FROZEN; - let _ = &Self::TO_BE_UNFROZEN; - //~^ borrow_interior_mutable_const - let _ = &Self::WRAPPED_TO_BE_UNFROZEN; - //~^ borrow_interior_mutable_const + let _ = &Self::TO_BE_UNFROZEN; //~ borrow_interior_mutable_const + let _ = &Self::WRAPPED_TO_BE_UNFROZEN; //~ borrow_interior_mutable_const let _ = &Self::WRAPPED_TO_BE_GENERIC_PARAM; } } @@ -111,8 +106,7 @@ where fn function() { let _ = &Self::NOT_BOUNDED; - let _ = &Self::BOUNDED; - //~^ borrow_interior_mutable_const + let _ = &Self::BOUNDED; //~ borrow_interior_mutable_const } } @@ -125,8 +119,7 @@ where fn function() { let _ = &Self::NOT_BOUNDED; - let _ = &Self::BOUNDED; - //~^ borrow_interior_mutable_const + let _ = &Self::BOUNDED; //~ borrow_interior_mutable_const } } @@ -155,10 +148,8 @@ impl SelfType for AtomicUsize { const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); fn function() { - let _ = &Self::SELF; - //~^ borrow_interior_mutable_const - let _ = &Self::WRAPPED_SELF; - //~^ borrow_interior_mutable_const + let _ = &Self::SELF; //~ borrow_interior_mutable_const + let _ = &Self::WRAPPED_SELF; //~ borrow_interior_mutable_const } } @@ -167,10 +158,8 @@ trait BothOfCellAndGeneric { const INDIRECT: Cell<*const T>; fn function() { - let _ = &Self::DIRECT; - //~^ borrow_interior_mutable_const - let _ = &Self::INDIRECT; - //~^ borrow_interior_mutable_const + let _ = &Self::DIRECT; //~ borrow_interior_mutable_const + let _ = &Self::INDIRECT; //~ borrow_interior_mutable_const } } @@ -179,10 +168,8 @@ impl BothOfCellAndGeneric for Vec { const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null()); fn function() { - let _ = &Self::DIRECT; - //~^ borrow_interior_mutable_const - let _ = &Self::INDIRECT; - //~^ borrow_interior_mutable_const + let _ = &Self::DIRECT; //~ borrow_interior_mutable_const + let _ = &Self::INDIRECT; //~ borrow_interior_mutable_const } } @@ -201,19 +188,15 @@ where const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); fn function() { - let _ = &Self::ATOMIC; - //~^ borrow_interior_mutable_const + let _ = &Self::ATOMIC; //~ borrow_interior_mutable_const let _ = &Self::COW; let _ = &Self::GENERIC_TYPE; let _ = &Self::ASSOC_TYPE; - let _ = &Self::BOUNDED_ASSOC_TYPE; - //~^ borrow_interior_mutable_const + let _ = &Self::BOUNDED_ASSOC_TYPE; //~ borrow_interior_mutable_const } } fn main() { - u64::ATOMIC.store(5, Ordering::SeqCst); - //~^ borrow_interior_mutable_const - assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); - //~^ borrow_interior_mutable_const + u64::ATOMIC.store(5, Ordering::SeqCst); //~ borrow_interior_mutable_const + assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ borrow_interior_mutable_const } diff --git a/tests/ui/borrow_interior_mutable_const/traits.stderr b/tests/ui/borrow_interior_mutable_const/traits.stderr index cad68ca9260cb..233ec6dad6702 100644 --- a/tests/ui/borrow_interior_mutable_const/traits.stderr +++ b/tests/ui/borrow_interior_mutable_const/traits.stderr @@ -1,8 +1,8 @@ error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:15:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:15:17 | LL | let _ = &Self::ATOMIC; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here note: the lint level is defined here @@ -12,131 +12,133 @@ LL | #![deny(clippy::borrow_interior_mutable_const)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:27:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:26:17 | LL | let _ = &Self::ATOMIC; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:53:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:51:17 | LL | let _ = &Self::TO_BE_CONCRETE; - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:89:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:86:17 | LL | let _ = &Self::TO_BE_UNFROZEN; - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:91:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:87:17 | LL | let _ = &Self::WRAPPED_TO_BE_UNFROZEN; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:114:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:109:17 | LL | let _ = &Self::BOUNDED; - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:128:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:122:17 | LL | let _ = &Self::BOUNDED; - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:158:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:151:17 | LL | let _ = &Self::SELF; - | ^^^^^^^^^^ + | ^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:160:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:152:17 | LL | let _ = &Self::WRAPPED_SELF; - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:170:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:161:17 | LL | let _ = &Self::DIRECT; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:172:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:162:17 | LL | let _ = &Self::INDIRECT; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:182:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:171:17 | LL | let _ = &Self::DIRECT; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:184:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:172:17 | LL | let _ = &Self::INDIRECT; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:204:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:191:17 | LL | let _ = &Self::ATOMIC; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:209:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:195:17 | LL | let _ = &Self::BOUNDED_ASSOC_TYPE; - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:215:5 + --> tests/ui/borrow_interior_mutable_const/traits.rs:200:5 | LL | u64::ATOMIC.store(5, Ordering::SeqCst); | ^^^^^^^^^^^ | + = note: there is a compiler inserted borrow here = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:217:16 + --> tests/ui/borrow_interior_mutable_const/traits.rs:201:16 | LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); | ^^^^^^^^^^^ | + = note: there is a compiler inserted borrow here = help: assign this const to a local or static variable, and use the variable here error: aborting due to 17 previous errors diff --git a/tests/ui/crashes/ice-12979.1.fixed b/tests/ui/crashes/ice-12979.1.fixed new file mode 100644 index 0000000000000..e68f1c20a8e7c --- /dev/null +++ b/tests/ui/crashes/ice-12979.1.fixed @@ -0,0 +1,2 @@ +#[deny(clippy::declare_interior_mutable_const)] //~ empty_line_after_outer_attr +const FOO: u8 = 0; diff --git a/tests/ui/crashes/ice-12979.2.fixed b/tests/ui/crashes/ice-12979.2.fixed new file mode 100644 index 0000000000000..e89fa636d4b24 --- /dev/null +++ b/tests/ui/crashes/ice-12979.2.fixed @@ -0,0 +1,3 @@ +#![deny(clippy::declare_interior_mutable_const)] //~ empty_line_after_outer_attr + +const FOO: u8 = 0; diff --git a/tests/ui/crashes/ice-12979.rs b/tests/ui/crashes/ice-12979.rs new file mode 100644 index 0000000000000..a2787291d9e15 --- /dev/null +++ b/tests/ui/crashes/ice-12979.rs @@ -0,0 +1,3 @@ +#[deny(clippy::declare_interior_mutable_const)] //~ empty_line_after_outer_attr + +const FOO: u8 = 0; diff --git a/tests/ui/crashes/ice-12979.stderr b/tests/ui/crashes/ice-12979.stderr new file mode 100644 index 0000000000000..5e76081616461 --- /dev/null +++ b/tests/ui/crashes/ice-12979.stderr @@ -0,0 +1,19 @@ +error: empty line after outer attribute + --> tests/ui/crashes/ice-12979.rs:1:1 + | +LL | / #[deny(clippy::declare_interior_mutable_const)] +LL | | + | |_^ +LL | const FOO: u8 = 0; + | --------- the attribute applies to this constant item + | + = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::empty_line_after_outer_attr)]` + = help: if the empty line is unintentional, remove it +help: if the attribute should apply to the crate use an inner attribute + | +LL | #![deny(clippy::declare_interior_mutable_const)] + | + + +error: aborting due to 1 previous error + diff --git a/tests/ui/crashes/ice-9445.rs b/tests/ui/crashes/ice-9445.rs deleted file mode 100644 index 232b8e4a7959d..0000000000000 --- a/tests/ui/crashes/ice-9445.rs +++ /dev/null @@ -1,4 +0,0 @@ -const UNINIT: core::mem::MaybeUninit> = core::mem::MaybeUninit::uninit(); -//~^ declare_interior_mutable_const - -fn main() {} diff --git a/tests/ui/crashes/ice-9445.stderr b/tests/ui/crashes/ice-9445.stderr deleted file mode 100644 index 76689cd6f5c22..0000000000000 --- a/tests/ui/crashes/ice-9445.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error: a `const` item should not be interior mutable - --> tests/ui/crashes/ice-9445.rs:1:1 - | -LL | const UNINIT: core::mem::MaybeUninit> = core::mem::MaybeUninit::uninit(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` - = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` - -error: aborting due to 1 previous error - diff --git a/tests/ui/declare_interior_mutable_const/enums.rs b/tests/ui/declare_interior_mutable_const/enums.rs index c87468277fb31..2ca6b7bc303a6 100644 --- a/tests/ui/declare_interior_mutable_const/enums.rs +++ b/tests/ui/declare_interior_mutable_const/enums.rs @@ -9,8 +9,7 @@ enum OptionalCell { } // a constant with enums should be linted only when the used variant is unfrozen (#3962). -const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); -//~^ declare_interior_mutable_const +const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); //~ declare_interior_mutable_const const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; const fn unfrozen_variant() -> OptionalCell { @@ -21,8 +20,7 @@ const fn frozen_variant() -> OptionalCell { OptionalCell::Frozen } -const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); -//~^ declare_interior_mutable_const +const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); //~ declare_interior_mutable_const const FROZEN_VARIANT_FROM_FN: OptionalCell = frozen_variant(); enum NestedInnermost { @@ -60,24 +58,21 @@ trait AssocConsts { // When there's no default value, lint it only according to its type. // Further details are on the corresponding code (`NonCopyConst::check_trait_item`). const TO_BE_UNFROZEN_VARIANT: OptionalCell; - //~^ declare_interior_mutable_const const TO_BE_FROZEN_VARIANT: OptionalCell; - //~^ declare_interior_mutable_const // Lint default values accordingly. - const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); - //~^ declare_interior_mutable_const + const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ declare_interior_mutable_const const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; } // The lint doesn't trigger for an assoc constant in a trait impl with an unfrozen type even if it // has enums. Further details are on the corresponding code in 'NonCopyConst::check_impl_item'. impl AssocConsts for u64 { - const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); + const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ declare_interior_mutable_const const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; // even if this sets an unfrozen variant, the lint ignores it. - const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); + const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ declare_interior_mutable_const } // At first, I thought I'd need to check every patterns in `trait.rs`; but, what matters @@ -92,8 +87,7 @@ trait AssocTypes { impl AssocTypes for u64 { type ToBeUnfrozen = AtomicUsize; - const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); - //~^ declare_interior_mutable_const + const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); //~ declare_interior_mutable_const const TO_BE_FROZEN_VARIANT: Option = None; } @@ -105,30 +99,25 @@ enum BothOfCellAndGeneric { } impl BothOfCellAndGeneric { - const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); - //~^ declare_interior_mutable_const + const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ declare_interior_mutable_const // This is a false positive. The argument about this is on `is_value_unfrozen_raw` const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); - //~^ declare_interior_mutable_const const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); // This is what is likely to be a false negative when one tries to fix // the `GENERIC_VARIANT` false positive. - const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); - //~^ declare_interior_mutable_const + const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); //~ declare_interior_mutable_const } // associated types here is basically the same as the one above. trait BothOfCellAndGenericWithAssocType { type AssocType; - const UNFROZEN_VARIANT: BothOfCellAndGeneric = - //~^ declare_interior_mutable_const + const UNFROZEN_VARIANT: BothOfCellAndGeneric = //~ declare_interior_mutable_const BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); - //~^ declare_interior_mutable_const const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); } diff --git a/tests/ui/declare_interior_mutable_const/enums.stderr b/tests/ui/declare_interior_mutable_const/enums.stderr index 32839d14f0ed3..25f39f243e011 100644 --- a/tests/ui/declare_interior_mutable_const/enums.stderr +++ b/tests/ui/declare_interior_mutable_const/enums.stderr @@ -1,89 +1,70 @@ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:12:1 + --> tests/ui/declare_interior_mutable_const/enums.rs:12:7 | LL | const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:24:1 + --> tests/ui/declare_interior_mutable_const/enums.rs:23:7 | LL | const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:47:1 + --> tests/ui/declare_interior_mutable_const/enums.rs:45:7 | -LL | / const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost { -LL | | -LL | | outer: NestedOuter::NestedInner(NestedInner { -LL | | inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)), -LL | | }), -LL | | }; - | |__^ +LL | const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost { + | ^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider making this a static item error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:62:5 + --> tests/ui/declare_interior_mutable_const/enums.rs:64:11 | -LL | const TO_BE_UNFROZEN_VARIANT: OptionalCell; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:64:5 + --> tests/ui/declare_interior_mutable_const/enums.rs:71:11 | -LL | const TO_BE_FROZEN_VARIANT: OptionalCell; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); + | ^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:68:5 + --> tests/ui/declare_interior_mutable_const/enums.rs:75:11 | -LL | const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:95:5 + --> tests/ui/declare_interior_mutable_const/enums.rs:90:11 | LL | const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:108:5 + --> tests/ui/declare_interior_mutable_const/enums.rs:102:11 | LL | const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:112:5 - | -LL | const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:119:5 + --> tests/ui/declare_interior_mutable_const/enums.rs:111:11 | LL | const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:127:5 - | -LL | / const UNFROZEN_VARIANT: BothOfCellAndGeneric = -LL | | -LL | | BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); - | |____________________________________________________________________^ + | ^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:130:5 + --> tests/ui/declare_interior_mutable_const/enums.rs:118:11 | -LL | const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const UNFROZEN_VARIANT: BothOfCellAndGeneric = + | ^^^^^^^^^^^^^^^^ -error: aborting due to 12 previous errors +error: aborting due to 10 previous errors diff --git a/tests/ui/declare_interior_mutable_const/others.rs b/tests/ui/declare_interior_mutable_const/others.rs index 7ce04a3f2c340..362f28b8c53b9 100644 --- a/tests/ui/declare_interior_mutable_const/others.rs +++ b/tests/ui/declare_interior_mutable_const/others.rs @@ -7,20 +7,17 @@ use std::ptr; use std::sync::Once; use std::sync::atomic::AtomicUsize; -const ATOMIC: AtomicUsize = AtomicUsize::new(5); -//~^ declare_interior_mutable_const -const CELL: Cell = Cell::new(6); -//~^ declare_interior_mutable_const +const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ declare_interior_mutable_const +const CELL: Cell = Cell::new(6); //~ declare_interior_mutable_const const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); //~^ declare_interior_mutable_const macro_rules! declare_const { ($name:ident: $ty:ty = $e:expr) => { const $name: $ty = $e; - //~^ declare_interior_mutable_const }; } -declare_const!(_ONCE: Once = Once::new()); +declare_const!(_ONCE: Once = Once::new()); //~ declare_interior_mutable_const // const ATOMIC_REF: &AtomicUsize = &AtomicUsize::new(7); // This will simply trigger E0492. diff --git a/tests/ui/declare_interior_mutable_const/others.stderr b/tests/ui/declare_interior_mutable_const/others.stderr index 09299b290416d..243c6b0cc5f8e 100644 --- a/tests/ui/declare_interior_mutable_const/others.stderr +++ b/tests/ui/declare_interior_mutable_const/others.stderr @@ -1,49 +1,47 @@ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/others.rs:10:1 + --> tests/ui/declare_interior_mutable_const/others.rs:10:7 | LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ | = help: consider making this a static item = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/others.rs:12:1 + --> tests/ui/declare_interior_mutable_const/others.rs:11:7 | LL | const CELL: Cell = Cell::new(6); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ | = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/others.rs:14:1 + --> tests/ui/declare_interior_mutable_const/others.rs:12:7 | LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ | = help: consider making this a static item error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/others.rs:19:9 + --> tests/ui/declare_interior_mutable_const/others.rs:20:16 | -LL | const $name: $ty = $e; - | ^^^^^^^^^^^^^^^^^^^^^^ -... LL | declare_const!(_ONCE: Once = Once::new()); - | ----------------------------------------- in this macro invocation + | ^^^^^ | - = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info) + = help: consider making this a static item error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/others.rs:47:13 + --> tests/ui/declare_interior_mutable_const/others.rs:44:19 | LL | const _BAZ: Cell = Cell::new(0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ ... LL | issue_8493!(); | ------------- in this macro invocation | + = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` = note: this error originates in the macro `issue_8493` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 5 previous errors diff --git a/tests/ui/declare_interior_mutable_const/traits.rs b/tests/ui/declare_interior_mutable_const/traits.rs index d3139be6859f3..f4916e1b4cf12 100644 --- a/tests/ui/declare_interior_mutable_const/traits.rs +++ b/tests/ui/declare_interior_mutable_const/traits.rs @@ -7,17 +7,15 @@ use std::sync::atomic::AtomicUsize; macro_rules! declare_const { ($name:ident: $ty:ty = $e:expr) => { const $name: $ty = $e; - //~^ declare_interior_mutable_const }; } // a constant whose type is a concrete type should be linted at the definition site. trait ConcreteTypes { - const ATOMIC: AtomicUsize; - //~^ declare_interior_mutable_const + const ATOMIC: AtomicUsize; //~ declare_interior_mutable_const const INTEGER: u64; const STRING: String; - declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); + declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ declare_interior_mutable_const } impl ConcreteTypes for u64 { @@ -43,7 +41,6 @@ trait GenericTypes { impl GenericTypes for u64 { const TO_REMAIN_GENERIC: T = T::DEFAULT; const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); - //~^ declare_interior_mutable_const } // a helper type used below @@ -68,10 +65,8 @@ impl AssocTypes for Vec { type ToBeGenericParam = T; const TO_BE_FROZEN: Self::ToBeFrozen = 12; - const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); - //~^ declare_interior_mutable_const - const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); - //~^ declare_interior_mutable_const + const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); //~ declare_interior_mutable_const + const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); //~ declare_interior_mutable_const const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper = Wrapper(T::DEFAULT); } @@ -90,8 +85,7 @@ where T: AssocTypesHelper, { const NOT_BOUNDED: T::NotToBeBounded; - const BOUNDED: T::ToBeBounded; - //~^ declare_interior_mutable_const + const BOUNDED: T::ToBeBounded; //~ declare_interior_mutable_const } impl AssocTypesFromGenericParam for u64 @@ -120,23 +114,18 @@ impl SelfType for AtomicUsize { // this (interior mutable `Self` const) exists in `parking_lot`. // `const_trait_impl` will replace it in the future, hopefully. const SELF: Self = AtomicUsize::new(17); - //~^ declare_interior_mutable_const - const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); - //~^ declare_interior_mutable_const + const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); //~ declare_interior_mutable_const } // Even though a constant contains a generic type, if it also have an interior mutable type, // it should be linted at the definition site. trait BothOfCellAndGeneric { - const DIRECT: Cell; - //~^ declare_interior_mutable_const - const INDIRECT: Cell<*const T>; - //~^ declare_interior_mutable_const + const DIRECT: Cell; //~ declare_interior_mutable_const + const INDIRECT: Cell<*const T>; //~ declare_interior_mutable_const } impl BothOfCellAndGeneric for u64 { const DIRECT: Cell = Cell::new(T::DEFAULT); - //~^ declare_interior_mutable_const const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null()); } @@ -148,15 +137,13 @@ impl Local where T: ConstDefault + AssocTypesHelper, { - const ATOMIC: AtomicUsize = AtomicUsize::new(18); - //~^ declare_interior_mutable_const + const ATOMIC: AtomicUsize = AtomicUsize::new(18); //~ declare_interior_mutable_const const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy"); const GENERIC_TYPE: T = T::DEFAULT; const ASSOC_TYPE: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED; - const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); - //~^ declare_interior_mutable_const + const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); //~ declare_interior_mutable_const } fn main() {} diff --git a/tests/ui/declare_interior_mutable_const/traits.stderr b/tests/ui/declare_interior_mutable_const/traits.stderr index b03dd7a084033..9b9d9ddeef937 100644 --- a/tests/ui/declare_interior_mutable_const/traits.stderr +++ b/tests/ui/declare_interior_mutable_const/traits.stderr @@ -1,88 +1,65 @@ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:16:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:15:11 | LL | const ATOMIC: AtomicUsize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ | = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:9:9 + --> tests/ui/declare_interior_mutable_const/traits.rs:18:20 | -LL | const $name: $ty = $e; - | ^^^^^^^^^^^^^^^^^^^^^^ -... LL | declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); - | ---------------------------------------------------------- in this macro invocation - | - = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:45:5 - | -LL | const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:71:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:68:11 | LL | const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:73:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:69:11 | LL | const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:93:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:88:11 | LL | const BOUNDED: T::ToBeBounded; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:122:5 - | -LL | const SELF: Self = AtomicUsize::new(17); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:124:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:117:11 | LL | const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:131:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:123:11 | LL | const DIRECT: Cell; - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:133:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:124:11 | LL | const INDIRECT: Cell<*const T>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:138:5 - | -LL | const DIRECT: Cell = Cell::new(T::DEFAULT); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:151:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:140:11 | LL | const ATOMIC: AtomicUsize = AtomicUsize::new(18); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:158:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:146:11 | LL | const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 13 previous errors +error: aborting due to 10 previous errors From 7c41ec73951429a98a6ae550093393905547da88 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 6 Aug 2024 21:02:36 -0400 Subject: [PATCH 2335/4206] Reword `declare_interior_mutable_const` and `borrow_interior_mutable_const` messages to be less assertive. Update documentation for both lints. --- clippy_lints/src/non_copy_const.rs | 112 +++++++++++------- .../enums.stderr | 24 ++-- .../others.stderr | 60 +++++----- .../projections.stderr | 16 +-- .../traits.stderr | 68 +++++------ .../enums.stderr | 26 ++-- .../others.stderr | 20 ++-- .../traits.stderr | 20 ++-- 8 files changed, 188 insertions(+), 158 deletions(-) diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index f57ab0e6781d6..a27c6aa75e369 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -43,35 +43,36 @@ use std::collections::hash_map::Entry; declare_clippy_lint! { /// ### What it does - /// Checks for declaration of `const` items which is interior - /// mutable (e.g., contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.). + /// Checks for the declaration of named constant which contain interior mutability. /// /// ### Why is this bad? - /// Consts are copied everywhere they are referenced, i.e., - /// every time you refer to the const a fresh instance of the `Cell` or `Mutex` - /// or `AtomicXxxx` will be created, which defeats the whole purpose of using - /// these types in the first place. + /// Named constants are copied at every use site which means any change to their value + /// will be lost after the newly created value is dropped. e.g. /// - /// The `const` should better be replaced by a `static` item if a global - /// variable is wanted, or replaced by a `const fn` if a constructor is wanted. + /// ```rust + /// use core::sync::atomic::{AtomicUsize, Ordering}; + /// const ATOMIC: AtomicUsize = AtomicUsize::new(0); + /// fn add_one() -> usize { + /// // This will always return `0` since `ATOMIC` is copied before it's used. + /// ATOMIC.fetch_add(1, Ordering::AcqRel) + /// } + /// ``` /// - /// ### Known problems - /// A "non-constant" const item is a legacy way to supply an - /// initialized value to downstream `static` items (e.g., the - /// `std::sync::ONCE_INIT` constant). In this case the use of `const` is legit, - /// and this lint should be suppressed. + /// If shared modification of the value is desired, a `static` item is needed instead. + /// If that is not desired, a `const fn` constructor should be used to make it obvious + /// at the use site that a new value is created. /// - /// Even though the lint avoids triggering on a constant whose type has enums that have variants - /// with interior mutability, and its value uses non interior mutable variants (see - /// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962) and - /// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825) for examples); - /// it complains about associated constants without default values only based on its types; - /// which might not be preferable. - /// There're other enums plus associated constants cases that the lint cannot handle. + /// ### Known problems + /// Prior to `const fn` stabilization this was the only way to provide a value which + /// could initialize a `static` item (e.g. the `std::sync::ONCE_INIT` constant). In + /// this case the use of `const` is required and this lint should be suppressed. /// - /// Types that have underlying or potential interior mutability trigger the lint whether - /// the interior mutable field is used or not. See issue - /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) + /// There also exists types which contain private fields with interior mutability, but + /// no way to both create a value as a constant and modify any mutable field using the + /// type's public interface (e.g. `bytes::Bytes`). As there is no reasonable way to + /// scan a crate's interface to see if this is the case, all such types will be linted. + /// If this happens use the `ignore-interior-mutability` configuration option to allow + /// the type. /// /// ### Example /// ```no_run @@ -97,16 +98,42 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks if `const` items which is interior mutable (e.g., - /// contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.) has been borrowed directly. + /// Checks for a borrow of a named constant with interior mutability. /// /// ### Why is this bad? - /// Consts are copied everywhere they are referenced, i.e., - /// every time you refer to the const a fresh instance of the `Cell` or `Mutex` - /// or `AtomicXxxx` will be created, which defeats the whole purpose of using - /// these types in the first place. + /// Named constants are copied at every use site which means any change to their value + /// will be lost after the newly created value is dropped. e.g. + /// + /// ```rust + /// use core::sync::atomic::{AtomicUsize, Ordering}; + /// const ATOMIC: AtomicUsize = AtomicUsize::new(0); + /// fn add_one() -> usize { + /// // This will always return `0` since `ATOMIC` is copied before it's borrowed + /// // for use by `fetch_add`. + /// ATOMIC.fetch_add(1, Ordering::AcqRel) + /// } + /// ``` /// - /// The `const` value should be stored inside a `static` item. + /// ### Known problems + /// This lint does not, and cannot in general, determine if the borrow of the constant + /// is used in a way which causes a mutation. e.g. + /// + /// ```rust + /// use core::cell::Cell; + /// const CELL: Cell = Cell::new(0); + /// fn get_cell() -> Cell { + /// // This is fine. It borrows a copy of `CELL`, but never mutates it through the + /// // borrow. + /// CELL.clone() + /// } + /// ``` + /// + /// There also exists types which contain private fields with interior mutability, but + /// no way to both create a value as a constant and modify any mutable field using the + /// type's public interface (e.g. `bytes::Bytes`). As there is no reasonable way to + /// scan a crate's interface to see if this is the case, all such types will be linted. + /// If this happens use the `ignore-interior-mutability` configuration option to allow + /// the type. /// /// ### Example /// ```no_run @@ -180,6 +207,7 @@ enum BorrowCause { Index, AutoDeref, AutoBorrow, + AutoDerefField, } impl BorrowCause { fn note(self) -> Option<&'static str> { @@ -189,6 +217,9 @@ impl BorrowCause { Self::Index => Some("this index expression is a call to `Index::index`"), Self::AutoDeref => Some("there is a compiler inserted call to `Deref::deref` here"), Self::AutoBorrow => Some("there is a compiler inserted borrow here"), + Self::AutoDerefField => { + Some("there is a compiler inserted call to `Deref::deref` when accessing this field") + }, } } } @@ -208,6 +239,7 @@ impl<'tcx> BorrowSource<'tcx> { match parent.kind { ExprKind::Unary(UnOp::Deref, _) => (parent, BorrowCause::Deref), ExprKind::Index(..) => (parent, BorrowCause::Index), + ExprKind::Field(..) => (parent, BorrowCause::AutoDerefField), _ => (expr, cause), } } else { @@ -688,17 +720,15 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { cx, DECLARE_INTERIOR_MUTABLE_CONST, ident.span, - "a `const` item should not be interior mutable", + "named constant with interior mutability", |diag| { let Some(sync_trait) = cx.tcx.lang_items().sync_trait() else { return; }; if implements_trait(cx, ty, sync_trait, &[]) { - diag.help("consider making this a static item"); + diag.help("did you mean to make this a `static` item"); } else { - diag.help( - "consider making this `Sync` so that it can go in a static item or using a `thread_local`", - ); + diag.help("did you mean to make this a `thread_local!` item"); } }, ); @@ -732,7 +762,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { cx, DECLARE_INTERIOR_MUTABLE_CONST, item.ident.span, - "a `const` item should not be interior mutable", + "named constant with interior mutability", ); } } @@ -784,7 +814,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { cx, DECLARE_INTERIOR_MUTABLE_CONST, item.ident.span, - "a `const` item should not be interior mutable", + "named constant with interior mutability", ); } } @@ -819,12 +849,12 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { cx, BORROW_INTERIOR_MUTABLE_CONST, borrow_src.expr.span, - "a `const` item with interior mutability should not be borrowed", + "borrow of a named constant with interior mutability", |diag| { - if let Some(msg) = borrow_src.cause.note() { - diag.note(msg); + if let Some(note) = borrow_src.cause.note() { + diag.note(note); } - diag.help("assign this const to a local or static variable, and use the variable here"); + diag.help("this lint can be silenced by assigning the value to a local variable before borrowing"); }, ); } diff --git a/tests/ui/borrow_interior_mutable_const/enums.stderr b/tests/ui/borrow_interior_mutable_const/enums.stderr index 7a3cb7d6aa952..80c2deb4b3a5b 100644 --- a/tests/ui/borrow_interior_mutable_const/enums.stderr +++ b/tests/ui/borrow_interior_mutable_const/enums.stderr @@ -1,55 +1,55 @@ -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/enums.rs:22:13 | LL | let _ = &UNFROZEN_VARIANT; | ^^^^^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing note: the lint level is defined here --> tests/ui/borrow_interior_mutable_const/enums.rs:3:9 | LL | #![deny(clippy::borrow_interior_mutable_const)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/enums.rs:50:17 | LL | let _ = &::TO_BE_UNFROZEN_VARIANT; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/enums.rs:52:17 | LL | let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/enums.rs:74:17 | LL | let _ = &::TO_BE_UNFROZEN_VARIANT; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/enums.rs:91:17 | LL | let _ = &Self::UNFROZEN_VARIANT; | ^^^^^^^^^^^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/enums.rs:99:13 | LL | let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing error: aborting due to 6 previous errors diff --git a/tests/ui/borrow_interior_mutable_const/others.stderr b/tests/ui/borrow_interior_mutable_const/others.stderr index 6e887406dcdbb..67b9907f8e385 100644 --- a/tests/ui/borrow_interior_mutable_const/others.stderr +++ b/tests/ui/borrow_interior_mutable_const/others.stderr @@ -1,132 +1,132 @@ -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/others.rs:65:5 | LL | ATOMIC.store(1, Ordering::SeqCst); | ^^^^^^ | = note: there is a compiler inserted borrow here - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing note: the lint level is defined here --> tests/ui/borrow_interior_mutable_const/others.rs:1:9 | LL | #![deny(clippy::borrow_interior_mutable_const)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/others.rs:66:16 | LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); | ^^^^^^ | = note: there is a compiler inserted borrow here - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/others.rs:69:21 | LL | let _once_ref = &ONCE_INIT; | ^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/others.rs:70:24 | LL | let _once_ref_2 = &&ONCE_INIT; | ^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/others.rs:71:26 | LL | let _once_ref_4 = &&&&ONCE_INIT; | ^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/others.rs:72:21 | LL | let _once_mut = &mut ONCE_INIT; | ^^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/others.rs:83:13 | LL | let _ = &ATOMIC_TUPLE; | ^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/others.rs:84:13 | LL | let _ = &ATOMIC_TUPLE.0; | ^^^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/others.rs:85:18 | LL | let _ = &(&&&&ATOMIC_TUPLE).0; | ^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/others.rs:86:13 | LL | let _ = &ATOMIC_TUPLE.0[0]; | ^^^^^^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/others.rs:87:13 | LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); | ^^^^^^^^^^^^^^^^^ | = note: there is a compiler inserted borrow here - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/others.rs:89:17 | LL | let _ = (&&&&ATOMIC_TUPLE).0; | ^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/others.rs:90:17 | LL | let _ = (&&&&ATOMIC_TUPLE).2; | ^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/others.rs:97:5 | LL | CELL.set(2); | ^^^^ | = note: there is a compiler inserted borrow here - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/others.rs:98:16 | LL | assert_eq!(CELL.get(), 6); | ^^^^ | = note: there is a compiler inserted borrow here - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing error: aborting due to 15 previous errors diff --git a/tests/ui/borrow_interior_mutable_const/projections.stderr b/tests/ui/borrow_interior_mutable_const/projections.stderr index b0e1883f8bf77..114fd66651af5 100644 --- a/tests/ui/borrow_interior_mutable_const/projections.stderr +++ b/tests/ui/borrow_interior_mutable_const/projections.stderr @@ -1,44 +1,44 @@ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/projections.rs:27:7 | LL | const CELL: Assoc = UnsafeCell::new(0); | ^^^^ | - = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` + = help: did you mean to make this a `thread_local!` item note: the lint level is defined here --> tests/ui/borrow_interior_mutable_const/projections.rs:2:9 | LL | #![deny(clippy::declare_interior_mutable_const)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/projections.rs:29:7 | LL | const MUTABLE: MaybeMutable = MaybeMutable::Mutable(CELL); | ^^^^^^^ | - = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` + = help: did you mean to make this a `thread_local!` item -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/projections.rs:38:15 | LL | print_ref(&CELL); | ^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing note: the lint level is defined here --> tests/ui/borrow_interior_mutable_const/projections.rs:1:9 | LL | #![deny(clippy::borrow_interior_mutable_const)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/projections.rs:40:15 | LL | print_ref(&MUTABLE); | ^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing error: aborting due to 4 previous errors diff --git a/tests/ui/borrow_interior_mutable_const/traits.stderr b/tests/ui/borrow_interior_mutable_const/traits.stderr index 233ec6dad6702..1d84ebf2ac945 100644 --- a/tests/ui/borrow_interior_mutable_const/traits.stderr +++ b/tests/ui/borrow_interior_mutable_const/traits.stderr @@ -1,145 +1,145 @@ -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/traits.rs:15:17 | LL | let _ = &Self::ATOMIC; | ^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing note: the lint level is defined here --> tests/ui/borrow_interior_mutable_const/traits.rs:1:9 | LL | #![deny(clippy::borrow_interior_mutable_const)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/traits.rs:26:17 | LL | let _ = &Self::ATOMIC; | ^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/traits.rs:51:17 | LL | let _ = &Self::TO_BE_CONCRETE; | ^^^^^^^^^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/traits.rs:86:17 | LL | let _ = &Self::TO_BE_UNFROZEN; | ^^^^^^^^^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/traits.rs:87:17 | LL | let _ = &Self::WRAPPED_TO_BE_UNFROZEN; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/traits.rs:109:17 | LL | let _ = &Self::BOUNDED; | ^^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/traits.rs:122:17 | LL | let _ = &Self::BOUNDED; | ^^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/traits.rs:151:17 | LL | let _ = &Self::SELF; | ^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/traits.rs:152:17 | LL | let _ = &Self::WRAPPED_SELF; | ^^^^^^^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/traits.rs:161:17 | LL | let _ = &Self::DIRECT; | ^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/traits.rs:162:17 | LL | let _ = &Self::INDIRECT; | ^^^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/traits.rs:171:17 | LL | let _ = &Self::DIRECT; | ^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/traits.rs:172:17 | LL | let _ = &Self::INDIRECT; | ^^^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/traits.rs:191:17 | LL | let _ = &Self::ATOMIC; | ^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/traits.rs:195:17 | LL | let _ = &Self::BOUNDED_ASSOC_TYPE; | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/traits.rs:200:5 | LL | u64::ATOMIC.store(5, Ordering::SeqCst); | ^^^^^^^^^^^ | = note: there is a compiler inserted borrow here - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/traits.rs:201:16 | LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); | ^^^^^^^^^^^ | = note: there is a compiler inserted borrow here - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing error: aborting due to 17 previous errors diff --git a/tests/ui/declare_interior_mutable_const/enums.stderr b/tests/ui/declare_interior_mutable_const/enums.stderr index 25f39f243e011..4eca533e5adab 100644 --- a/tests/ui/declare_interior_mutable_const/enums.stderr +++ b/tests/ui/declare_interior_mutable_const/enums.stderr @@ -1,66 +1,66 @@ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/enums.rs:12:7 | LL | const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); | ^^^^^^^^^^^^^^^^ | - = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` + = help: did you mean to make this a `thread_local!` item = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/enums.rs:23:7 | LL | const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` + = help: did you mean to make this a `thread_local!` item -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/enums.rs:45:7 | LL | const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost { | ^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider making this a static item + = help: did you mean to make this a `static` item -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/enums.rs:64:11 | LL | const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/enums.rs:71:11 | LL | const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); | ^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/enums.rs:75:11 | LL | const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/enums.rs:90:11 | LL | const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); | ^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/enums.rs:102:11 | LL | const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); | ^^^^^^^^^^^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/enums.rs:111:11 | LL | const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); | ^^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/enums.rs:118:11 | LL | const UNFROZEN_VARIANT: BothOfCellAndGeneric = diff --git a/tests/ui/declare_interior_mutable_const/others.stderr b/tests/ui/declare_interior_mutable_const/others.stderr index 243c6b0cc5f8e..67fb4d046a6b5 100644 --- a/tests/ui/declare_interior_mutable_const/others.stderr +++ b/tests/ui/declare_interior_mutable_const/others.stderr @@ -1,38 +1,38 @@ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/others.rs:10:7 | LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); | ^^^^^^ | - = help: consider making this a static item + = help: did you mean to make this a `static` item = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/others.rs:11:7 | LL | const CELL: Cell = Cell::new(6); | ^^^^ | - = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` + = help: did you mean to make this a `thread_local!` item -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/others.rs:12:7 | LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); | ^^^^^^^^^^^^ | - = help: consider making this a static item + = help: did you mean to make this a `static` item -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/others.rs:20:16 | LL | declare_const!(_ONCE: Once = Once::new()); | ^^^^^ | - = help: consider making this a static item + = help: did you mean to make this a `static` item -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/others.rs:44:19 | LL | const _BAZ: Cell = Cell::new(0); @@ -41,7 +41,7 @@ LL | const _BAZ: Cell = Cell::new(0); LL | issue_8493!(); | ------------- in this macro invocation | - = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` + = help: did you mean to make this a `thread_local!` item = note: this error originates in the macro `issue_8493` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 5 previous errors diff --git a/tests/ui/declare_interior_mutable_const/traits.stderr b/tests/ui/declare_interior_mutable_const/traits.stderr index 9b9d9ddeef937..a5c08871ba779 100644 --- a/tests/ui/declare_interior_mutable_const/traits.stderr +++ b/tests/ui/declare_interior_mutable_const/traits.stderr @@ -1,4 +1,4 @@ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/traits.rs:15:11 | LL | const ATOMIC: AtomicUsize; @@ -7,55 +7,55 @@ LL | const ATOMIC: AtomicUsize; = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/traits.rs:18:20 | LL | declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); | ^^^^^^^^^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/traits.rs:68:11 | LL | const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); | ^^^^^^^^^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/traits.rs:69:11 | LL | const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); | ^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/traits.rs:88:11 | LL | const BOUNDED: T::ToBeBounded; | ^^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/traits.rs:117:11 | LL | const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); | ^^^^^^^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/traits.rs:123:11 | LL | const DIRECT: Cell; | ^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/traits.rs:124:11 | LL | const INDIRECT: Cell<*const T>; | ^^^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/traits.rs:140:11 | LL | const ATOMIC: AtomicUsize = AtomicUsize::new(18); | ^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/traits.rs:146:11 | LL | const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); From 318ba60cfb59ba3165d1a03bd3ab3acb3406cb14 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 3 Aug 2024 14:53:02 -0400 Subject: [PATCH 2336/4206] Rewrite tests for `declare_interior_mutable_const` and `borrow_interior_mutable_const` to be more thorough on weird constructs --- .../interior_mutable_const.rs} | 0 tests/ui/borrow_interior_mutable_const.rs | 221 ++++++++++++++++ tests/ui/borrow_interior_mutable_const.stderr | 247 ++++++++++++++++++ .../ui/borrow_interior_mutable_const/enums.rs | 101 ------- .../enums.stderr | 55 ---- .../borrow_interior_mutable_const/others.rs | 114 -------- .../others.stderr | 132 ---------- .../projections.rs | 42 --- .../projections.stderr | 44 ---- .../borrow_interior_mutable_const/traits.rs | 202 -------------- .../traits.stderr | 145 ---------- tests/ui/declare_interior_mutable_const.rs | 200 ++++++++++++++ .../ui/declare_interior_mutable_const.stderr | 197 ++++++++++++++ .../declare_interior_mutable_const/enums.rs | 124 --------- .../enums.stderr | 70 ----- .../declare_interior_mutable_const/others.rs | 73 ------ .../others.stderr | 48 ---- .../declare_interior_mutable_const/traits.rs | 149 ----------- .../traits.stderr | 65 ----- 19 files changed, 865 insertions(+), 1364 deletions(-) rename tests/ui/{borrow_interior_mutable_const/auxiliary/helper.rs => auxiliary/interior_mutable_const.rs} (100%) create mode 100644 tests/ui/borrow_interior_mutable_const.rs create mode 100644 tests/ui/borrow_interior_mutable_const.stderr delete mode 100644 tests/ui/borrow_interior_mutable_const/enums.rs delete mode 100644 tests/ui/borrow_interior_mutable_const/enums.stderr delete mode 100644 tests/ui/borrow_interior_mutable_const/others.rs delete mode 100644 tests/ui/borrow_interior_mutable_const/others.stderr delete mode 100644 tests/ui/borrow_interior_mutable_const/projections.rs delete mode 100644 tests/ui/borrow_interior_mutable_const/projections.stderr delete mode 100644 tests/ui/borrow_interior_mutable_const/traits.rs delete mode 100644 tests/ui/borrow_interior_mutable_const/traits.stderr create mode 100644 tests/ui/declare_interior_mutable_const.rs create mode 100644 tests/ui/declare_interior_mutable_const.stderr delete mode 100644 tests/ui/declare_interior_mutable_const/enums.rs delete mode 100644 tests/ui/declare_interior_mutable_const/enums.stderr delete mode 100644 tests/ui/declare_interior_mutable_const/others.rs delete mode 100644 tests/ui/declare_interior_mutable_const/others.stderr delete mode 100644 tests/ui/declare_interior_mutable_const/traits.rs delete mode 100644 tests/ui/declare_interior_mutable_const/traits.stderr diff --git a/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs b/tests/ui/auxiliary/interior_mutable_const.rs similarity index 100% rename from tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs rename to tests/ui/auxiliary/interior_mutable_const.rs diff --git a/tests/ui/borrow_interior_mutable_const.rs b/tests/ui/borrow_interior_mutable_const.rs new file mode 100644 index 0000000000000..0f439f7891507 --- /dev/null +++ b/tests/ui/borrow_interior_mutable_const.rs @@ -0,0 +1,221 @@ +//@aux-build:interior_mutable_const.rs + +#![deny(clippy::borrow_interior_mutable_const)] +#![allow( + clippy::declare_interior_mutable_const, + clippy::out_of_bounds_indexing, + const_item_mutation, + unconditional_panic +)] + +use core::cell::{Cell, UnsafeCell}; +use core::ops::{Deref, Index}; + +trait ConstDefault { + const DEFAULT: Self; +} +impl ConstDefault for u32 { + const DEFAULT: Self = 0; +} +impl ConstDefault for Cell { + const DEFAULT: Self = Cell::new(T::DEFAULT); +} + +fn main() { + { + const C: String = String::new(); + let _ = C; + let _ = &C; + let _ = C.len(); + let _ = &*C; + } + { + const C: UnsafeCell = UnsafeCell::new(0); + let _ = C; + let _ = &C; //~ borrow_interior_mutable_const + let _ = C.into_inner(); + let _ = C.get(); //~ borrow_interior_mutable_const + } + { + const C: Cell = Cell::new(0); + let _ = C; + let _ = &C; //~ borrow_interior_mutable_const + let _ = &mut C; //~ borrow_interior_mutable_const + let _ = C.into_inner(); + + let local = C; + C.swap(&local) //~ borrow_interior_mutable_const + } + { + const C: [(Cell,); 1] = [(Cell::new(0),)]; + let _ = C; + let _ = &C; //~ borrow_interior_mutable_const + let _ = &C[0]; //~ borrow_interior_mutable_const + let _ = &C[0].0; //~ borrow_interior_mutable_const + C[0].0.set(1); //~ borrow_interior_mutable_const + } + { + struct S(Cell); + impl S { + const C: Self = Self(Cell::new(0)); + } + impl Deref for S { + type Target = Cell; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + let _ = S::C; + let _ = S::C.0; + let _ = &S::C; //~ borrow_interior_mutable_const + let _ = &S::C.0; //~ borrow_interior_mutable_const + S::C.set(1); //~ borrow_interior_mutable_const + let _ = &*S::C; //~ borrow_interior_mutable_const + (*S::C).set(1); //~ borrow_interior_mutable_const + } + { + enum E { + Cell(Cell), + Other, + } + const CELL: E = E::Cell(Cell::new(0)); + const OTHER: E = E::Other; + + let _ = CELL; + let _ = &CELL; //~ borrow_interior_mutable_const + let E::Cell(_) = CELL else { + return; + }; + + let _ = OTHER; + let _ = &OTHER; + let E::Cell(ref _x) = OTHER else { + return; + }; + } + { + struct S { + cell: (Cell, u32), + other: Option, + } + impl S { + const C: Self = Self { + cell: (Cell::::DEFAULT, 0), + other: Some(T::DEFAULT), + }; + + fn f() { + let _ = Self::C; + let _ = &Self::C; //~ borrow_interior_mutable_const + let _ = Self::C.other; + let _ = &Self::C.other; + let _ = &Self::C.cell; //~ borrow_interior_mutable_const + let _ = &Self::C.cell.0; //~ borrow_interior_mutable_const + Self::C.cell.0.set(T::DEFAULT); //~ borrow_interior_mutable_const + let _ = &Self::C.cell.1; + } + } + } + { + trait T { + const VALUE: Option> = Some(Cell::new(0)); + } + impl T for u32 {} + impl T for i32 { + const VALUE: Option> = None; + } + + let _ = &u32::VALUE; //~ borrow_interior_mutable_const + let _ = &i32::VALUE; + } + { + trait Trait { + type T: ConstDefault; + const VALUE: Option> = Some(Self::T::::DEFAULT); + } + impl Trait for u32 { + type T = Cell; + } + impl Trait for i32 { + type T = Cell; + const VALUE: Option> = None; + } + + fn f() { + let _ = &>::VALUE; //~ borrow_interior_mutable_const + let _ = &>::VALUE; + } + } + { + trait Trait { + const UNFROZEN: Option> = Some(Cell::new(0)); + const FROZEN: Option> = None; + const NON_FREEZE: u32 = 0; + } + fn f() { + // None of these are guaranteed to be frozen, so don't lint. + let _ = &T::UNFROZEN; + let _ = &T::FROZEN; + let _ = &T::NON_FREEZE; + } + } + { + struct S([Option>; 2]); + impl Index for S { + type Output = Option>; + fn index(&self, idx: usize) -> &Self::Output { + &self.0[idx] + } + } + + const C: S = S([Some(Cell::new(0)), None]); + let _ = &C; //~ borrow_interior_mutable_const + let _ = &C[0]; //~ borrow_interior_mutable_const + let _ = &C.0[0]; //~ borrow_interior_mutable_const + let _ = &C.0[1]; + } + { + const C: [Option>; 2] = [None, None]; + let _ = &C[0]; + let _ = &C[1]; + let _ = &C[2]; + + fn f(i: usize) { + let _ = &C[i]; + } + } + { + const C: [Option>; 2] = [None, Some(Cell::new(0))]; + let _ = &C[0]; + let _ = &C[1]; //~ borrow_interior_mutable_const + let _ = &C[2]; + + fn f(i: usize) { + let _ = &C[i]; //~ borrow_interior_mutable_const + } + } + { + let _ = &interior_mutable_const::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ borrow_interior_mutable_const + let _ = &interior_mutable_const::WRAPPED_PRIVATE_FROZEN_VARIANT; + } + { + type Cell2 = Cell; + type MyCell = Cell2; + struct S(Option); + trait T { + type Assoc; + } + struct S2(T, T, u32); + impl T for S { + type Assoc = S2; + } + type Assoc = ::Assoc; + impl S { + const VALUE: Assoc = S2(Self(None), Self(Some(Cell::new(0))), 0); + } + let _ = &S::VALUE; //~ borrow_interior_mutable_const + let _ = &S::VALUE.0; + let _ = &S::VALUE.1; //~ borrow_interior_mutable_const + let _ = &S::VALUE.2; + } +} diff --git a/tests/ui/borrow_interior_mutable_const.stderr b/tests/ui/borrow_interior_mutable_const.stderr new file mode 100644 index 0000000000000..e7c3f879b05b0 --- /dev/null +++ b/tests/ui/borrow_interior_mutable_const.stderr @@ -0,0 +1,247 @@ +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:35:17 + | +LL | let _ = &C; + | ^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing +note: the lint level is defined here + --> tests/ui/borrow_interior_mutable_const.rs:3:9 + | +LL | #![deny(clippy::borrow_interior_mutable_const)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:37:17 + | +LL | let _ = C.get(); + | ^ + | + = note: there is a compiler inserted borrow here + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:42:17 + | +LL | let _ = &C; + | ^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:43:17 + | +LL | let _ = &mut C; + | ^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:47:9 + | +LL | C.swap(&local) + | ^ + | + = note: there is a compiler inserted borrow here + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:52:17 + | +LL | let _ = &C; + | ^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:53:17 + | +LL | let _ = &C[0]; + | ^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:54:17 + | +LL | let _ = &C[0].0; + | ^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:55:9 + | +LL | C[0].0.set(1); + | ^^^^^^ + | + = note: there is a compiler inserted borrow here + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:70:17 + | +LL | let _ = &S::C; + | ^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:71:17 + | +LL | let _ = &S::C.0; + | ^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:72:9 + | +LL | S::C.set(1); + | ^^^^ + | + = note: there is a compiler inserted call to `Deref::deref` here + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:73:18 + | +LL | let _ = &*S::C; + | ^^^^^ + | + = note: this deref expression is a call to `Deref::deref` + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:74:9 + | +LL | (*S::C).set(1); + | ^^^^^^^ + | + = note: this deref expression is a call to `Deref::deref` + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:85:17 + | +LL | let _ = &CELL; + | ^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:109:25 + | +LL | let _ = &Self::C; + | ^^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:112:25 + | +LL | let _ = &Self::C.cell; + | ^^^^^^^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:113:25 + | +LL | let _ = &Self::C.cell.0; + | ^^^^^^^^^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:114:17 + | +LL | Self::C.cell.0.set(T::DEFAULT); + | ^^^^^^^^^^^^^^ + | + = note: there is a compiler inserted borrow here + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:128:17 + | +LL | let _ = &u32::VALUE; + | ^^^^^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:145:21 + | +LL | let _ = &>::VALUE; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:172:17 + | +LL | let _ = &C; + | ^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:173:18 + | +LL | let _ = &C[0]; + | ^^^^ + | + = note: this index expression is a call to `Index::index` + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:174:17 + | +LL | let _ = &C.0[0]; + | ^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:190:17 + | +LL | let _ = &C[1]; + | ^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:194:21 + | +LL | let _ = &C[i]; + | ^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:198:17 + | +LL | let _ = &interior_mutable_const::WRAPPED_PRIVATE_UNFROZEN_VARIANT; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:216:17 + | +LL | let _ = &S::VALUE; + | ^^^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:218:17 + | +LL | let _ = &S::VALUE.1; + | ^^^^^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: aborting due to 29 previous errors + diff --git a/tests/ui/borrow_interior_mutable_const/enums.rs b/tests/ui/borrow_interior_mutable_const/enums.rs deleted file mode 100644 index ea47e588858ff..0000000000000 --- a/tests/ui/borrow_interior_mutable_const/enums.rs +++ /dev/null @@ -1,101 +0,0 @@ -//@aux-build:helper.rs - -#![deny(clippy::borrow_interior_mutable_const)] -#![allow(clippy::declare_interior_mutable_const)] - -// this file (mostly) replicates its `declare` counterpart. Please see it for more discussions. - -extern crate helper; - -use std::cell::Cell; -use std::sync::atomic::AtomicUsize; - -enum OptionalCell { - Unfrozen(Cell), - Frozen, -} - -const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); -const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; - -fn borrow_optional_cell() { - let _ = &UNFROZEN_VARIANT; //~ borrow_interior_mutable_const - let _ = &FROZEN_VARIANT; -} - -trait AssocConsts { - const TO_BE_UNFROZEN_VARIANT: OptionalCell; - const TO_BE_FROZEN_VARIANT: OptionalCell; - - const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); - const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; - - fn function() { - // This is the "suboptimal behavior" mentioned in `is_value_unfrozen` - // caused by a similar reason to unfrozen types without any default values - // get linted even if it has frozen variants'. - let _ = &Self::TO_BE_FROZEN_VARIANT; - - // The lint ignores default values because an impl of this trait can set - // an unfrozen variant to `DEFAULTED_ON_FROZEN_VARIANT` and use the default impl for `function`. - let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; - } -} - -impl AssocConsts for u64 { - const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); - const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; - - fn function() { - let _ = &::TO_BE_UNFROZEN_VARIANT; //~ borrow_interior_mutable_const - let _ = &::TO_BE_FROZEN_VARIANT; - let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; //~ borrow_interior_mutable_const - let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; - } -} - -trait AssocTypes { - type ToBeUnfrozen; - - const TO_BE_UNFROZEN_VARIANT: Option; - const TO_BE_FROZEN_VARIANT: Option; - - // there's no need to test here because it's the exactly same as `trait::AssocTypes` - fn function(); -} - -impl AssocTypes for u64 { - type ToBeUnfrozen = AtomicUsize; - - const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); - const TO_BE_FROZEN_VARIANT: Option = None; - - fn function() { - let _ = &::TO_BE_UNFROZEN_VARIANT; //~ borrow_interior_mutable_const - let _ = &::TO_BE_FROZEN_VARIANT; - } -} - -enum BothOfCellAndGeneric { - Unfrozen(Cell<*const T>), - Generic(*const T), - Frozen(usize), -} - -impl BothOfCellAndGeneric { - const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); - const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); - const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); - - fn function() { - let _ = &Self::UNFROZEN_VARIANT; //~ borrow_interior_mutable_const - let _ = &Self::GENERIC_VARIANT; - let _ = &Self::FROZEN_VARIANT; - } -} - -fn main() { - // constants defined in foreign crates - let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ borrow_interior_mutable_const - let _ = &helper::WRAPPED_PRIVATE_FROZEN_VARIANT; -} diff --git a/tests/ui/borrow_interior_mutable_const/enums.stderr b/tests/ui/borrow_interior_mutable_const/enums.stderr deleted file mode 100644 index 80c2deb4b3a5b..0000000000000 --- a/tests/ui/borrow_interior_mutable_const/enums.stderr +++ /dev/null @@ -1,55 +0,0 @@ -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/enums.rs:22:13 - | -LL | let _ = &UNFROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing -note: the lint level is defined here - --> tests/ui/borrow_interior_mutable_const/enums.rs:3:9 - | -LL | #![deny(clippy::borrow_interior_mutable_const)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/enums.rs:50:17 - | -LL | let _ = &::TO_BE_UNFROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/enums.rs:52:17 - | -LL | let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/enums.rs:74:17 - | -LL | let _ = &::TO_BE_UNFROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/enums.rs:91:17 - | -LL | let _ = &Self::UNFROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/enums.rs:99:13 - | -LL | let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: aborting due to 6 previous errors - diff --git a/tests/ui/borrow_interior_mutable_const/others.rs b/tests/ui/borrow_interior_mutable_const/others.rs deleted file mode 100644 index 720f88326d7e3..0000000000000 --- a/tests/ui/borrow_interior_mutable_const/others.rs +++ /dev/null @@ -1,114 +0,0 @@ -#![deny(clippy::borrow_interior_mutable_const)] -#![allow(clippy::declare_interior_mutable_const, clippy::needless_borrow)] -#![allow(const_item_mutation)] - -use std::borrow::Cow; -use std::cell::{Cell, UnsafeCell}; -use std::fmt::Display; -use std::sync::Once; -use std::sync::atomic::{AtomicUsize, Ordering}; - -const ATOMIC: AtomicUsize = AtomicUsize::new(5); -const CELL: Cell = Cell::new(6); -const ATOMIC_TUPLE: ([AtomicUsize; 1], Option>, u8) = ([ATOMIC], None, 7); -const INTEGER: u8 = 8; -const STRING: String = String::new(); -const STR: &str = "012345"; -const COW: Cow = Cow::Borrowed("abcdef"); -const NO_ANN: &dyn Display = &70; -static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING); -const ONCE_INIT: Once = Once::new(); - -// This is just a pointer that can be safely dereferenced, -// it's semantically the same as `&'static T`; -// but it isn't allowed to make a static reference from an arbitrary integer value at the moment. -// For more information, please see the issue #5918. -pub struct StaticRef { - ptr: *const T, -} - -impl StaticRef { - /// Create a new `StaticRef` from a raw pointer - /// - /// ## Safety - /// - /// Callers must pass in a reference to statically allocated memory which - /// does not overlap with other values. - pub const unsafe fn new(ptr: *const T) -> StaticRef { - StaticRef { ptr } - } -} - -impl std::ops::Deref for StaticRef { - type Target = T; - - fn deref(&self) -> &T { - unsafe { &*self.ptr } - } -} - -// ICE regression test -mod issue12979 { - use std::cell::UnsafeCell; - - const ATOMIC_TUPLE: (Vec>, ()) = (Vec::new(), ()); - - fn main() { - let _x = &ATOMIC_TUPLE.0; - } -} - -// use a tuple to make sure referencing a field behind a pointer isn't linted. -const CELL_REF: StaticRef<(UnsafeCell,)> = unsafe { StaticRef::new(std::ptr::null()) }; - -fn main() { - ATOMIC.store(1, Ordering::SeqCst); //~ borrow_interior_mutable_const - assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ borrow_interior_mutable_const - - let _once = ONCE_INIT; - let _once_ref = &ONCE_INIT; //~ borrow_interior_mutable_const - let _once_ref_2 = &&ONCE_INIT; //~ borrow_interior_mutable_const - let _once_ref_4 = &&&&ONCE_INIT; //~ borrow_interior_mutable_const - let _once_mut = &mut ONCE_INIT; //~ borrow_interior_mutable_const - let _atomic_into_inner = ATOMIC.into_inner(); - // these should be all fine. - let _twice = (ONCE_INIT, ONCE_INIT); - let _ref_twice = &(ONCE_INIT, ONCE_INIT); - let _ref_once = &(ONCE_INIT, ONCE_INIT).0; - let _array_twice = [ONCE_INIT, ONCE_INIT]; - let _ref_array_twice = &[ONCE_INIT, ONCE_INIT]; - let _ref_array_once = &[ONCE_INIT, ONCE_INIT][0]; - - // referencing projection is still bad. - let _ = &ATOMIC_TUPLE; //~ borrow_interior_mutable_const - let _ = &ATOMIC_TUPLE.0; //~ borrow_interior_mutable_const - let _ = &(&&&&ATOMIC_TUPLE).0; //~ borrow_interior_mutable_const - let _ = &ATOMIC_TUPLE.0[0]; //~ borrow_interior_mutable_const - let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ borrow_interior_mutable_const - let _ = &ATOMIC_TUPLE.2; - let _ = (&&&&ATOMIC_TUPLE).0; //~ borrow_interior_mutable_const - let _ = (&&&&ATOMIC_TUPLE).2; //~ borrow_interior_mutable_const - let _ = ATOMIC_TUPLE.0; - let _ = ATOMIC_TUPLE.0[0]; - let _ = ATOMIC_TUPLE.1.into_iter(); - let _ = ATOMIC_TUPLE.2; - let _ = &{ ATOMIC_TUPLE }; - - CELL.set(2); //~ borrow_interior_mutable_const - assert_eq!(CELL.get(), 6); //~ borrow_interior_mutable_const - - assert_eq!(INTEGER, 8); - assert!(STRING.is_empty()); - - let a = ATOMIC; - a.store(4, Ordering::SeqCst); - assert_eq!(a.load(Ordering::SeqCst), 4); - - STATIC_TUPLE.0.store(3, Ordering::SeqCst); - assert_eq!(STATIC_TUPLE.0.load(Ordering::SeqCst), 3); - assert!(STATIC_TUPLE.1.is_empty()); - - assert_eq!(NO_ANN.to_string(), "70"); // should never lint this. - - let _ = &CELL_REF.0; -} diff --git a/tests/ui/borrow_interior_mutable_const/others.stderr b/tests/ui/borrow_interior_mutable_const/others.stderr deleted file mode 100644 index 67b9907f8e385..0000000000000 --- a/tests/ui/borrow_interior_mutable_const/others.stderr +++ /dev/null @@ -1,132 +0,0 @@ -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:65:5 - | -LL | ATOMIC.store(1, Ordering::SeqCst); - | ^^^^^^ - | - = note: there is a compiler inserted borrow here - = help: this lint can be silenced by assigning the value to a local variable before borrowing -note: the lint level is defined here - --> tests/ui/borrow_interior_mutable_const/others.rs:1:9 - | -LL | #![deny(clippy::borrow_interior_mutable_const)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:66:16 - | -LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); - | ^^^^^^ - | - = note: there is a compiler inserted borrow here - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:69:21 - | -LL | let _once_ref = &ONCE_INIT; - | ^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:70:24 - | -LL | let _once_ref_2 = &&ONCE_INIT; - | ^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:71:26 - | -LL | let _once_ref_4 = &&&&ONCE_INIT; - | ^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:72:21 - | -LL | let _once_mut = &mut ONCE_INIT; - | ^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:83:13 - | -LL | let _ = &ATOMIC_TUPLE; - | ^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:84:13 - | -LL | let _ = &ATOMIC_TUPLE.0; - | ^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:85:18 - | -LL | let _ = &(&&&&ATOMIC_TUPLE).0; - | ^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:86:13 - | -LL | let _ = &ATOMIC_TUPLE.0[0]; - | ^^^^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:87:13 - | -LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); - | ^^^^^^^^^^^^^^^^^ - | - = note: there is a compiler inserted borrow here - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:89:17 - | -LL | let _ = (&&&&ATOMIC_TUPLE).0; - | ^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:90:17 - | -LL | let _ = (&&&&ATOMIC_TUPLE).2; - | ^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:97:5 - | -LL | CELL.set(2); - | ^^^^ - | - = note: there is a compiler inserted borrow here - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:98:16 - | -LL | assert_eq!(CELL.get(), 6); - | ^^^^ - | - = note: there is a compiler inserted borrow here - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: aborting due to 15 previous errors - diff --git a/tests/ui/borrow_interior_mutable_const/projections.rs b/tests/ui/borrow_interior_mutable_const/projections.rs deleted file mode 100644 index bbe5538fbe123..0000000000000 --- a/tests/ui/borrow_interior_mutable_const/projections.rs +++ /dev/null @@ -1,42 +0,0 @@ -#![deny(clippy::borrow_interior_mutable_const)] -#![deny(clippy::declare_interior_mutable_const)] - -// Inspired by https://github.com/rust-lang/rust/pull/130543#issuecomment-2364828139 - -use std::cell::UnsafeCell; - -trait Trait { - type Assoc; -} - -type Assoc = ::Assoc; - -impl Trait for u8 { - type Assoc = UnsafeCell; -} - -impl Trait for () { - type Assoc = (); -} - -enum MaybeMutable { - Mutable(Assoc), - Immutable(Assoc<()>), -} - -const CELL: Assoc = UnsafeCell::new(0); //~ ERROR: interior mutable -const UNIT: Assoc<()> = (); -const MUTABLE: MaybeMutable = MaybeMutable::Mutable(CELL); //~ ERROR: interior mutable -const IMMUTABLE: MaybeMutable = MaybeMutable::Immutable(UNIT); - -fn print_ref(t: &T) { - let p: *const T = t; - println!("{p:p}") -} - -fn main() { - print_ref(&CELL); //~ ERROR: interior mutability - print_ref(&UNIT); - print_ref(&MUTABLE); //~ ERROR: interior mutability - print_ref(&IMMUTABLE); -} diff --git a/tests/ui/borrow_interior_mutable_const/projections.stderr b/tests/ui/borrow_interior_mutable_const/projections.stderr deleted file mode 100644 index 114fd66651af5..0000000000000 --- a/tests/ui/borrow_interior_mutable_const/projections.stderr +++ /dev/null @@ -1,44 +0,0 @@ -error: named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/projections.rs:27:7 - | -LL | const CELL: Assoc = UnsafeCell::new(0); - | ^^^^ - | - = help: did you mean to make this a `thread_local!` item -note: the lint level is defined here - --> tests/ui/borrow_interior_mutable_const/projections.rs:2:9 - | -LL | #![deny(clippy::declare_interior_mutable_const)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/projections.rs:29:7 - | -LL | const MUTABLE: MaybeMutable = MaybeMutable::Mutable(CELL); - | ^^^^^^^ - | - = help: did you mean to make this a `thread_local!` item - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/projections.rs:38:15 - | -LL | print_ref(&CELL); - | ^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing -note: the lint level is defined here - --> tests/ui/borrow_interior_mutable_const/projections.rs:1:9 - | -LL | #![deny(clippy::borrow_interior_mutable_const)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/projections.rs:40:15 - | -LL | print_ref(&MUTABLE); - | ^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: aborting due to 4 previous errors - diff --git a/tests/ui/borrow_interior_mutable_const/traits.rs b/tests/ui/borrow_interior_mutable_const/traits.rs deleted file mode 100644 index 34a758efa2c82..0000000000000 --- a/tests/ui/borrow_interior_mutable_const/traits.rs +++ /dev/null @@ -1,202 +0,0 @@ -#![deny(clippy::borrow_interior_mutable_const)] -#![allow(clippy::declare_interior_mutable_const)] - -// this file replicates its `declare` counterpart. Please see it for more discussions. - -use std::borrow::Cow; -use std::cell::Cell; -use std::sync::atomic::{AtomicUsize, Ordering}; - -trait ConcreteTypes { - const ATOMIC: AtomicUsize; - const STRING: String; - - fn function() { - let _ = &Self::ATOMIC; //~ borrow_interior_mutable_const - let _ = &Self::STRING; - } -} - -impl ConcreteTypes for u64 { - const ATOMIC: AtomicUsize = AtomicUsize::new(9); - const STRING: String = String::new(); - - fn function() { - // Lint this again since implementers can choose not to borrow it. - let _ = &Self::ATOMIC; //~ borrow_interior_mutable_const - let _ = &Self::STRING; - } -} - -// a helper trait used below -trait ConstDefault { - const DEFAULT: Self; -} - -trait GenericTypes { - const TO_REMAIN_GENERIC: T; - const TO_BE_CONCRETE: U; - - fn function() { - let _ = &Self::TO_REMAIN_GENERIC; - } -} - -impl GenericTypes for Vec { - const TO_REMAIN_GENERIC: T = T::DEFAULT; - const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); - - fn function() { - let _ = &Self::TO_REMAIN_GENERIC; - let _ = &Self::TO_BE_CONCRETE; //~ borrow_interior_mutable_const - } -} - -// a helper type used below -pub struct Wrapper(T); - -trait AssocTypes { - type ToBeFrozen; - type ToBeUnfrozen; - type ToBeGenericParam; - - const TO_BE_FROZEN: Self::ToBeFrozen; - const TO_BE_UNFROZEN: Self::ToBeUnfrozen; - const WRAPPED_TO_BE_UNFROZEN: Wrapper; - const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper; - - fn function() { - let _ = &Self::TO_BE_FROZEN; - let _ = &Self::WRAPPED_TO_BE_UNFROZEN; - } -} - -impl AssocTypes for Vec { - type ToBeFrozen = u16; - type ToBeUnfrozen = AtomicUsize; - type ToBeGenericParam = T; - - const TO_BE_FROZEN: Self::ToBeFrozen = 12; - const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); - const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); - const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper = Wrapper(T::DEFAULT); - - fn function() { - let _ = &Self::TO_BE_FROZEN; - let _ = &Self::TO_BE_UNFROZEN; //~ borrow_interior_mutable_const - let _ = &Self::WRAPPED_TO_BE_UNFROZEN; //~ borrow_interior_mutable_const - let _ = &Self::WRAPPED_TO_BE_GENERIC_PARAM; - } -} - -// a helper trait used below -trait AssocTypesHelper { - type NotToBeBounded; - type ToBeBounded; - - const NOT_TO_BE_BOUNDED: Self::NotToBeBounded; -} - -trait AssocTypesFromGenericParam -where - T: AssocTypesHelper, -{ - const NOT_BOUNDED: T::NotToBeBounded; - const BOUNDED: T::ToBeBounded; - - fn function() { - let _ = &Self::NOT_BOUNDED; - let _ = &Self::BOUNDED; //~ borrow_interior_mutable_const - } -} - -impl AssocTypesFromGenericParam for Vec -where - T: AssocTypesHelper, -{ - const NOT_BOUNDED: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED; - const BOUNDED: T::ToBeBounded = AtomicUsize::new(15); - - fn function() { - let _ = &Self::NOT_BOUNDED; - let _ = &Self::BOUNDED; //~ borrow_interior_mutable_const - } -} - -trait SelfType: Sized { - const SELF: Self; - const WRAPPED_SELF: Option; - - fn function() { - let _ = &Self::SELF; - let _ = &Self::WRAPPED_SELF; - } -} - -impl SelfType for u64 { - const SELF: Self = 16; - const WRAPPED_SELF: Option = Some(20); - - fn function() { - let _ = &Self::SELF; - let _ = &Self::WRAPPED_SELF; - } -} - -impl SelfType for AtomicUsize { - const SELF: Self = AtomicUsize::new(17); - const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); - - fn function() { - let _ = &Self::SELF; //~ borrow_interior_mutable_const - let _ = &Self::WRAPPED_SELF; //~ borrow_interior_mutable_const - } -} - -trait BothOfCellAndGeneric { - const DIRECT: Cell; - const INDIRECT: Cell<*const T>; - - fn function() { - let _ = &Self::DIRECT; //~ borrow_interior_mutable_const - let _ = &Self::INDIRECT; //~ borrow_interior_mutable_const - } -} - -impl BothOfCellAndGeneric for Vec { - const DIRECT: Cell = Cell::new(T::DEFAULT); - const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null()); - - fn function() { - let _ = &Self::DIRECT; //~ borrow_interior_mutable_const - let _ = &Self::INDIRECT; //~ borrow_interior_mutable_const - } -} - -struct Local(T); - -impl Local -where - T: ConstDefault + AssocTypesHelper, -{ - const ATOMIC: AtomicUsize = AtomicUsize::new(18); - const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy"); - - const GENERIC_TYPE: T = T::DEFAULT; - - const ASSOC_TYPE: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED; - const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); - - fn function() { - let _ = &Self::ATOMIC; //~ borrow_interior_mutable_const - let _ = &Self::COW; - let _ = &Self::GENERIC_TYPE; - let _ = &Self::ASSOC_TYPE; - let _ = &Self::BOUNDED_ASSOC_TYPE; //~ borrow_interior_mutable_const - } -} - -fn main() { - u64::ATOMIC.store(5, Ordering::SeqCst); //~ borrow_interior_mutable_const - assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ borrow_interior_mutable_const -} diff --git a/tests/ui/borrow_interior_mutable_const/traits.stderr b/tests/ui/borrow_interior_mutable_const/traits.stderr deleted file mode 100644 index 1d84ebf2ac945..0000000000000 --- a/tests/ui/borrow_interior_mutable_const/traits.stderr +++ /dev/null @@ -1,145 +0,0 @@ -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:15:17 - | -LL | let _ = &Self::ATOMIC; - | ^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing -note: the lint level is defined here - --> tests/ui/borrow_interior_mutable_const/traits.rs:1:9 - | -LL | #![deny(clippy::borrow_interior_mutable_const)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:26:17 - | -LL | let _ = &Self::ATOMIC; - | ^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:51:17 - | -LL | let _ = &Self::TO_BE_CONCRETE; - | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:86:17 - | -LL | let _ = &Self::TO_BE_UNFROZEN; - | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:87:17 - | -LL | let _ = &Self::WRAPPED_TO_BE_UNFROZEN; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:109:17 - | -LL | let _ = &Self::BOUNDED; - | ^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:122:17 - | -LL | let _ = &Self::BOUNDED; - | ^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:151:17 - | -LL | let _ = &Self::SELF; - | ^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:152:17 - | -LL | let _ = &Self::WRAPPED_SELF; - | ^^^^^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:161:17 - | -LL | let _ = &Self::DIRECT; - | ^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:162:17 - | -LL | let _ = &Self::INDIRECT; - | ^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:171:17 - | -LL | let _ = &Self::DIRECT; - | ^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:172:17 - | -LL | let _ = &Self::INDIRECT; - | ^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:191:17 - | -LL | let _ = &Self::ATOMIC; - | ^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:195:17 - | -LL | let _ = &Self::BOUNDED_ASSOC_TYPE; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:200:5 - | -LL | u64::ATOMIC.store(5, Ordering::SeqCst); - | ^^^^^^^^^^^ - | - = note: there is a compiler inserted borrow here - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:201:16 - | -LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); - | ^^^^^^^^^^^ - | - = note: there is a compiler inserted borrow here - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: aborting due to 17 previous errors - diff --git a/tests/ui/declare_interior_mutable_const.rs b/tests/ui/declare_interior_mutable_const.rs new file mode 100644 index 0000000000000..c65df275038dc --- /dev/null +++ b/tests/ui/declare_interior_mutable_const.rs @@ -0,0 +1,200 @@ +#![deny(clippy::declare_interior_mutable_const)] +#![allow(clippy::missing_const_for_thread_local)] + +use core::cell::{Cell, RefCell, UnsafeCell}; +use core::mem::{ManuallyDrop, MaybeUninit}; +use core::ptr; +use core::sync::atomic::AtomicUsize; + +fn main() {} + +const _: Cell = Cell::new(0); +const UNSAFE_CELL: UnsafeCell = UnsafeCell::new(0); //~ declare_interior_mutable_const +const REF_CELL: RefCell = RefCell::new(0); //~ declare_interior_mutable_const +const CELL: Cell = Cell::new(0); //~ declare_interior_mutable_const + +// Constants can't contain pointers or references to type with interior mutability. +const fn make_ptr() -> *const Cell { + ptr::null() +} +const PTR: *const Cell = make_ptr(); + +const fn casted_to_cell_ptr() -> *const Cell { + const VALUE: u32 = 0; + &VALUE as *const _ as *const Cell +} +const TRANSMUTED_PTR: *const Cell = casted_to_cell_ptr(); + +const CELL_TUPLE: (bool, Cell) = (true, Cell::new(0)); //~ declare_interior_mutable_const +const CELL_ARRAY: [Cell; 2] = [Cell::new(0), Cell::new(0)]; //~ declare_interior_mutable_const + +const UNINIT_CELL: MaybeUninit> = MaybeUninit::uninit(); + +struct CellStruct { + x: u32, + cell: Cell, +} +//~v declare_interior_mutable_const +const CELL_STRUCT: CellStruct = CellStruct { + x: 0, + cell: Cell::new(0), +}; + +enum CellEnum { + Cell(Cell), +} +const CELL_ENUM: CellEnum = CellEnum::Cell(Cell::new(0)); //~ declare_interior_mutable_const + +const NONE_CELL: Option> = None; +const SOME_CELL: Option> = Some(Cell::new(0)); //~ declare_interior_mutable_const + +struct NestedCell([(Option>,); 1]); +const NONE_NESTED_CELL: NestedCell = NestedCell([(None,)]); +const SOME_NESTED_CELL: NestedCell = NestedCell([(Some(Cell::new(0)),)]); //~ declare_interior_mutable_const + +union UnionCell { + cell: ManuallyDrop>, + x: u32, +} +//~v declare_interior_mutable_const +const UNION_CELL: UnionCell = UnionCell { + cell: ManuallyDrop::new(Cell::new(0)), +}; +// Access to either union field is valid so we have to be conservative here. +const UNION_U32: UnionCell = UnionCell { x: 0 }; //~ declare_interior_mutable_const + +struct Assoc; +impl Assoc { + const SELF: Self = Self; + const CELL: Cell = Cell::new(0); //~ declare_interior_mutable_const +} + +struct AssocCell(Cell); +impl AssocCell { + const SELF: Self = Self(Cell::new(0)); //~ declare_interior_mutable_const + const NONE_SELF: Option = None; + const SOME_SELF: Option = Some(Self(Cell::new(0))); //~ declare_interior_mutable_const +} + +trait ConstDefault { + // May or may not be `Freeze` + const DEFAULT: Self; +} +impl ConstDefault for u32 { + const DEFAULT: Self = 0; +} +impl ConstDefault for Cell { + // Interior mutability is forced by the trait. + const DEFAULT: Self = Cell::new(T::DEFAULT); +} +impl ConstDefault for Option> { + // Could have been `None` + const DEFAULT: Self = Some(Cell::new(T::DEFAULT)); //~ declare_interior_mutable_const +} + +enum GenericEnumCell { + Cell(Cell), + Other(T), +} +impl ConstDefault for GenericEnumCell { + const DEFAULT: Self = Self::Cell(Cell::new(T::DEFAULT)); //~ declare_interior_mutable_const +} +impl GenericEnumCell { + const CELL: Self = Self::DEFAULT; //~ declare_interior_mutable_const + const CELL_BY_DEFAULT: Self = Self::Cell(Cell::DEFAULT); //~ declare_interior_mutable_const + const OTHER: Self = Self::Other(T::DEFAULT); + const FROM_OTHER: Self = Self::OTHER; +} + +enum GenericNestedEnumCell { + GenericEnumCell(GenericEnumCell), + EnumCell(GenericEnumCell), + Other(T), +} +impl GenericNestedEnumCell { + const GENERIC_OTHER: Self = Self::GenericEnumCell(GenericEnumCell::::FROM_OTHER); + const GENERIC_CELL: Self = Self::GenericEnumCell(GenericEnumCell::::CELL); //~ declare_interior_mutable_const + const ENUM_OTHER: Self = Self::EnumCell(GenericEnumCell::::FROM_OTHER); + const ENUM_CELL: Self = Self::EnumCell(GenericEnumCell::::CELL); //~ declare_interior_mutable_const +} + +trait CellTrait: ConstDefault + Sized { + // Must be non-`Freeze` due to the type + const CELL: Cell; //~ declare_interior_mutable_const + // May be non-`Freeze`, but may not be + const OPTION_CELL: Option>; + // May get redefined by the impl, but the default is non-`Freeze`. + const SOME_CELL: Option> = Some(Cell::new(Self::DEFAULT)); //~ declare_interior_mutable_const + // May get redefined by the impl, but the default is `Freeze`. + const NONE_CELL: Option> = None; +} + +trait CellWithAssoc { + type T; + const DEFAULT: Self::T; + // Must be non-`Freeze` due to the type + const CELL: Cell; //~ declare_interior_mutable_const + // May be non-`Freeze`, but may not be + const OPTION_CELL: Option>; + // May get redefined by the impl, but the default is non-`Freeze`. + const SOME_CELL: Option> = Some(Cell::new(Self::DEFAULT)); //~ declare_interior_mutable_const + // May get redefined by the impl, but the default is `Freeze`. + const NONE_CELL: Option> = None; +} + +impl CellWithAssoc for () { + type T = u32; + const DEFAULT: Self::T = 0; + const CELL: Cell = Cell::new(0); + const OPTION_CELL: Option> = None; +} + +trait WithAssoc { + type T; + const VALUE: Self::T; +} + +impl WithAssoc for u32 { + type T = Cell; + // The cell comes from the impl block, not the trait. + const VALUE: Self::T = Cell::new(0); //~ declare_interior_mutable_const +} + +trait WithLayeredAssoc { + type T: WithAssoc; + const VALUE: ::T; +} + +impl WithLayeredAssoc for u32 { + type T = u32; + // The cell comes from the impl block, not the trait. + const VALUE: ::T = Cell::new(0); //~ declare_interior_mutable_const +} + +trait WithGenericAssoc { + type T; + const VALUE: Self::T; +} + +impl WithGenericAssoc for u32 { + type T = Cell; + const VALUE: Self::T = Cell::new(0); //~ declare_interior_mutable_const +} + +trait WithGenericAssocCell { + type T; + const VALUE: Self::T>; +} + +impl WithGenericAssocCell for u32 { + type T = Option; + const VALUE: Self::T> = None; +} + +impl WithGenericAssocCell for i32 { + type T = Option; + const VALUE: Self::T> = Some(Cell::new(0)); //~ declare_interior_mutable_const +} + +thread_local!(static THREAD_LOCAL_CELL: Cell = const { Cell::new(0) }); +thread_local!(static THREAD_LOCAL_CELL2: Cell = Cell::new(0)); diff --git a/tests/ui/declare_interior_mutable_const.stderr b/tests/ui/declare_interior_mutable_const.stderr new file mode 100644 index 0000000000000..9742c17486c5f --- /dev/null +++ b/tests/ui/declare_interior_mutable_const.stderr @@ -0,0 +1,197 @@ +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:12:7 + | +LL | const UNSAFE_CELL: UnsafeCell = UnsafeCell::new(0); + | ^^^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item +note: the lint level is defined here + --> tests/ui/declare_interior_mutable_const.rs:1:9 + | +LL | #![deny(clippy::declare_interior_mutable_const)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:13:7 + | +LL | const REF_CELL: RefCell = RefCell::new(0); + | ^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:14:7 + | +LL | const CELL: Cell = Cell::new(0); + | ^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:28:7 + | +LL | const CELL_TUPLE: (bool, Cell) = (true, Cell::new(0)); + | ^^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:29:7 + | +LL | const CELL_ARRAY: [Cell; 2] = [Cell::new(0), Cell::new(0)]; + | ^^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:38:7 + | +LL | const CELL_STRUCT: CellStruct = CellStruct { + | ^^^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:46:7 + | +LL | const CELL_ENUM: CellEnum = CellEnum::Cell(Cell::new(0)); + | ^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:49:7 + | +LL | const SOME_CELL: Option> = Some(Cell::new(0)); + | ^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:53:7 + | +LL | const SOME_NESTED_CELL: NestedCell = NestedCell([(Some(Cell::new(0)),)]); + | ^^^^^^^^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:60:7 + | +LL | const UNION_CELL: UnionCell = UnionCell { + | ^^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:64:7 + | +LL | const UNION_U32: UnionCell = UnionCell { x: 0 }; + | ^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:69:11 + | +LL | const CELL: Cell = Cell::new(0); + | ^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:74:11 + | +LL | const SELF: Self = Self(Cell::new(0)); + | ^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:76:11 + | +LL | const SOME_SELF: Option = Some(Self(Cell::new(0))); + | ^^^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:92:11 + | +LL | const DEFAULT: Self = Some(Cell::new(T::DEFAULT)); + | ^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:100:11 + | +LL | const DEFAULT: Self = Self::Cell(Cell::new(T::DEFAULT)); + | ^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:103:11 + | +LL | const CELL: Self = Self::DEFAULT; + | ^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:104:11 + | +LL | const CELL_BY_DEFAULT: Self = Self::Cell(Cell::DEFAULT); + | ^^^^^^^^^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:116:11 + | +LL | const GENERIC_CELL: Self = Self::GenericEnumCell(GenericEnumCell::::CELL); + | ^^^^^^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:118:11 + | +LL | const ENUM_CELL: Self = Self::EnumCell(GenericEnumCell::::CELL); + | ^^^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:123:11 + | +LL | const CELL: Cell; + | ^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:127:11 + | +LL | const SOME_CELL: Option> = Some(Cell::new(Self::DEFAULT)); + | ^^^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:136:11 + | +LL | const CELL: Cell; + | ^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:140:11 + | +LL | const SOME_CELL: Option> = Some(Cell::new(Self::DEFAULT)); + | ^^^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:160:11 + | +LL | const VALUE: Self::T = Cell::new(0); + | ^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:171:11 + | +LL | const VALUE: ::T = Cell::new(0); + | ^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:181:11 + | +LL | const VALUE: Self::T = Cell::new(0); + | ^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:196:11 + | +LL | const VALUE: Self::T> = Some(Cell::new(0)); + | ^^^^^ + +error: aborting due to 28 previous errors + diff --git a/tests/ui/declare_interior_mutable_const/enums.rs b/tests/ui/declare_interior_mutable_const/enums.rs deleted file mode 100644 index 2ca6b7bc303a6..0000000000000 --- a/tests/ui/declare_interior_mutable_const/enums.rs +++ /dev/null @@ -1,124 +0,0 @@ -#![warn(clippy::declare_interior_mutable_const)] - -use std::cell::Cell; -use std::sync::atomic::AtomicUsize; - -enum OptionalCell { - Unfrozen(Cell), - Frozen, -} - -// a constant with enums should be linted only when the used variant is unfrozen (#3962). -const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); //~ declare_interior_mutable_const -const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; - -const fn unfrozen_variant() -> OptionalCell { - OptionalCell::Unfrozen(Cell::new(false)) -} - -const fn frozen_variant() -> OptionalCell { - OptionalCell::Frozen -} - -const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); //~ declare_interior_mutable_const -const FROZEN_VARIANT_FROM_FN: OptionalCell = frozen_variant(); - -enum NestedInnermost { - Unfrozen(AtomicUsize), - Frozen, -} - -struct NestedInner { - inner: NestedInnermost, -} - -enum NestedOuter { - NestedInner(NestedInner), - NotNested(usize), -} - -struct NestedOutermost { - outer: NestedOuter, -} - -// a constant with enums should be linted according to its value, no matter how structs involve. -const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost { - //~^ declare_interior_mutable_const - outer: NestedOuter::NestedInner(NestedInner { - inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)), - }), -}; -const NESTED_FROZEN_VARIANT: NestedOutermost = NestedOutermost { - outer: NestedOuter::NestedInner(NestedInner { - inner: NestedInnermost::Frozen, - }), -}; - -trait AssocConsts { - // When there's no default value, lint it only according to its type. - // Further details are on the corresponding code (`NonCopyConst::check_trait_item`). - const TO_BE_UNFROZEN_VARIANT: OptionalCell; - const TO_BE_FROZEN_VARIANT: OptionalCell; - - // Lint default values accordingly. - const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ declare_interior_mutable_const - const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; -} - -// The lint doesn't trigger for an assoc constant in a trait impl with an unfrozen type even if it -// has enums. Further details are on the corresponding code in 'NonCopyConst::check_impl_item'. -impl AssocConsts for u64 { - const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ declare_interior_mutable_const - const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; - - // even if this sets an unfrozen variant, the lint ignores it. - const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ declare_interior_mutable_const -} - -// At first, I thought I'd need to check every patterns in `trait.rs`; but, what matters -// here are values; and I think substituted generics at definitions won't appear in MIR. -trait AssocTypes { - type ToBeUnfrozen; - - const TO_BE_UNFROZEN_VARIANT: Option; - const TO_BE_FROZEN_VARIANT: Option; -} - -impl AssocTypes for u64 { - type ToBeUnfrozen = AtomicUsize; - - const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); //~ declare_interior_mutable_const - const TO_BE_FROZEN_VARIANT: Option = None; -} - -// Use raw pointers since direct generics have a false negative at the type level. -enum BothOfCellAndGeneric { - Unfrozen(Cell<*const T>), - Generic(*const T), - Frozen(usize), -} - -impl BothOfCellAndGeneric { - const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ declare_interior_mutable_const - - // This is a false positive. The argument about this is on `is_value_unfrozen_raw` - const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); - - const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); - - // This is what is likely to be a false negative when one tries to fix - // the `GENERIC_VARIANT` false positive. - const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); //~ declare_interior_mutable_const -} - -// associated types here is basically the same as the one above. -trait BothOfCellAndGenericWithAssocType { - type AssocType; - - const UNFROZEN_VARIANT: BothOfCellAndGeneric = //~ declare_interior_mutable_const - BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); - const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); - const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); -} - -fn main() {} diff --git a/tests/ui/declare_interior_mutable_const/enums.stderr b/tests/ui/declare_interior_mutable_const/enums.stderr deleted file mode 100644 index 4eca533e5adab..0000000000000 --- a/tests/ui/declare_interior_mutable_const/enums.stderr +++ /dev/null @@ -1,70 +0,0 @@ -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/enums.rs:12:7 - | -LL | const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); - | ^^^^^^^^^^^^^^^^ - | - = help: did you mean to make this a `thread_local!` item - = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/enums.rs:23:7 - | -LL | const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: did you mean to make this a `thread_local!` item - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/enums.rs:45:7 - | -LL | const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost { - | ^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: did you mean to make this a `static` item - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/enums.rs:64:11 - | -LL | const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/enums.rs:71:11 - | -LL | const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/enums.rs:75:11 - | -LL | const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/enums.rs:90:11 - | -LL | const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/enums.rs:102:11 - | -LL | const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); - | ^^^^^^^^^^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/enums.rs:111:11 - | -LL | const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); - | ^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/enums.rs:118:11 - | -LL | const UNFROZEN_VARIANT: BothOfCellAndGeneric = - | ^^^^^^^^^^^^^^^^ - -error: aborting due to 10 previous errors - diff --git a/tests/ui/declare_interior_mutable_const/others.rs b/tests/ui/declare_interior_mutable_const/others.rs deleted file mode 100644 index 362f28b8c53b9..0000000000000 --- a/tests/ui/declare_interior_mutable_const/others.rs +++ /dev/null @@ -1,73 +0,0 @@ -#![warn(clippy::declare_interior_mutable_const)] - -use std::borrow::Cow; -use std::cell::Cell; -use std::fmt::Display; -use std::ptr; -use std::sync::Once; -use std::sync::atomic::AtomicUsize; - -const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ declare_interior_mutable_const -const CELL: Cell = Cell::new(6); //~ declare_interior_mutable_const -const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); -//~^ declare_interior_mutable_const - -macro_rules! declare_const { - ($name:ident: $ty:ty = $e:expr) => { - const $name: $ty = $e; - }; -} -declare_const!(_ONCE: Once = Once::new()); //~ declare_interior_mutable_const - -// const ATOMIC_REF: &AtomicUsize = &AtomicUsize::new(7); // This will simply trigger E0492. - -const INTEGER: u8 = 8; -const STRING: String = String::new(); -const STR: &str = "012345"; -const COW: Cow = Cow::Borrowed("abcdef"); -// note: a const item of Cow is used in the `postgres` package. - -const NO_ANN: &dyn Display = &70; - -static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING); -// there should be no lints on the line above line - -mod issue_8493 { - use std::cell::Cell; - - thread_local! { - static _BAR: Cell = const { Cell::new(0) }; - } - - macro_rules! issue_8493 { - () => { - const _BAZ: Cell = Cell::new(0); - //~^ declare_interior_mutable_const - static _FOOBAR: () = { - thread_local! { - static _VAR: Cell = const { Cell::new(0) }; - } - }; - }; - } - - issue_8493!(); -} - -#[repr(C, align(8))] -struct NoAtomic(usize); -#[repr(C, align(8))] -struct WithAtomic(AtomicUsize); - -const fn with_non_null() -> *const WithAtomic { - const NO_ATOMIC: NoAtomic = NoAtomic(0); - (&NO_ATOMIC as *const NoAtomic).cast() -} -const WITH_ATOMIC: *const WithAtomic = with_non_null(); - -struct Generic(T); -impl Generic { - const RAW_POINTER: *const Cell = ptr::null(); -} - -fn main() {} diff --git a/tests/ui/declare_interior_mutable_const/others.stderr b/tests/ui/declare_interior_mutable_const/others.stderr deleted file mode 100644 index 67fb4d046a6b5..0000000000000 --- a/tests/ui/declare_interior_mutable_const/others.stderr +++ /dev/null @@ -1,48 +0,0 @@ -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/others.rs:10:7 - | -LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); - | ^^^^^^ - | - = help: did you mean to make this a `static` item - = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/others.rs:11:7 - | -LL | const CELL: Cell = Cell::new(6); - | ^^^^ - | - = help: did you mean to make this a `thread_local!` item - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/others.rs:12:7 - | -LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); - | ^^^^^^^^^^^^ - | - = help: did you mean to make this a `static` item - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/others.rs:20:16 - | -LL | declare_const!(_ONCE: Once = Once::new()); - | ^^^^^ - | - = help: did you mean to make this a `static` item - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/others.rs:44:19 - | -LL | const _BAZ: Cell = Cell::new(0); - | ^^^^ -... -LL | issue_8493!(); - | ------------- in this macro invocation - | - = help: did you mean to make this a `thread_local!` item - = note: this error originates in the macro `issue_8493` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 5 previous errors - diff --git a/tests/ui/declare_interior_mutable_const/traits.rs b/tests/ui/declare_interior_mutable_const/traits.rs deleted file mode 100644 index f4916e1b4cf12..0000000000000 --- a/tests/ui/declare_interior_mutable_const/traits.rs +++ /dev/null @@ -1,149 +0,0 @@ -#![warn(clippy::declare_interior_mutable_const)] - -use std::borrow::Cow; -use std::cell::Cell; -use std::sync::atomic::AtomicUsize; - -macro_rules! declare_const { - ($name:ident: $ty:ty = $e:expr) => { - const $name: $ty = $e; - }; -} - -// a constant whose type is a concrete type should be linted at the definition site. -trait ConcreteTypes { - const ATOMIC: AtomicUsize; //~ declare_interior_mutable_const - const INTEGER: u64; - const STRING: String; - declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ declare_interior_mutable_const -} - -impl ConcreteTypes for u64 { - const ATOMIC: AtomicUsize = AtomicUsize::new(9); - const INTEGER: u64 = 10; - const STRING: String = String::new(); -} - -// a helper trait used below -trait ConstDefault { - const DEFAULT: Self; -} - -// a constant whose type is a generic type should be linted at the implementation site. -trait GenericTypes { - const TO_REMAIN_GENERIC: T; - const TO_BE_CONCRETE: U; - - const HAVING_DEFAULT: T = Self::TO_REMAIN_GENERIC; - declare_const!(IN_MACRO: T = Self::TO_REMAIN_GENERIC); -} - -impl GenericTypes for u64 { - const TO_REMAIN_GENERIC: T = T::DEFAULT; - const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); -} - -// a helper type used below -struct Wrapper(T); - -// a constant whose type is an associated type should be linted at the implementation site, too. -trait AssocTypes { - type ToBeFrozen; - type ToBeUnfrozen; - type ToBeGenericParam; - - const TO_BE_FROZEN: Self::ToBeFrozen; - const TO_BE_UNFROZEN: Self::ToBeUnfrozen; - const WRAPPED_TO_BE_UNFROZEN: Wrapper; - // to ensure it can handle things when a generic type remains after normalization. - const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper; -} - -impl AssocTypes for Vec { - type ToBeFrozen = u16; - type ToBeUnfrozen = AtomicUsize; - type ToBeGenericParam = T; - - const TO_BE_FROZEN: Self::ToBeFrozen = 12; - const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); //~ declare_interior_mutable_const - const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); //~ declare_interior_mutable_const - const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper = Wrapper(T::DEFAULT); -} - -// a helper trait used below -trait AssocTypesHelper { - type NotToBeBounded; - type ToBeBounded; - - const NOT_TO_BE_BOUNDED: Self::NotToBeBounded; -} - -// a constant whose type is an assoc type originated from a generic param bounded at the definition -// site should be linted at there. -trait AssocTypesFromGenericParam -where - T: AssocTypesHelper, -{ - const NOT_BOUNDED: T::NotToBeBounded; - const BOUNDED: T::ToBeBounded; //~ declare_interior_mutable_const -} - -impl AssocTypesFromGenericParam for u64 -where - T: AssocTypesHelper, -{ - // an associated type could remain unknown in a trait impl. - const NOT_BOUNDED: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED; - const BOUNDED: T::ToBeBounded = AtomicUsize::new(15); -} - -// a constant whose type is `Self` should be linted at the implementation site as well. -// (`Option` requires `Sized` bound.) -trait SelfType: Sized { - const SELF: Self; - // this was the one in the original issue (#5050). - const WRAPPED_SELF: Option; -} - -impl SelfType for u64 { - const SELF: Self = 16; - const WRAPPED_SELF: Option = Some(20); -} - -impl SelfType for AtomicUsize { - // this (interior mutable `Self` const) exists in `parking_lot`. - // `const_trait_impl` will replace it in the future, hopefully. - const SELF: Self = AtomicUsize::new(17); - const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); //~ declare_interior_mutable_const -} - -// Even though a constant contains a generic type, if it also have an interior mutable type, -// it should be linted at the definition site. -trait BothOfCellAndGeneric { - const DIRECT: Cell; //~ declare_interior_mutable_const - const INDIRECT: Cell<*const T>; //~ declare_interior_mutable_const -} - -impl BothOfCellAndGeneric for u64 { - const DIRECT: Cell = Cell::new(T::DEFAULT); - const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null()); -} - -struct Local(T); - -// a constant in an inherent impl are essentially the same as a normal const item -// except there can be a generic or associated type. -impl Local -where - T: ConstDefault + AssocTypesHelper, -{ - const ATOMIC: AtomicUsize = AtomicUsize::new(18); //~ declare_interior_mutable_const - const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy"); - - const GENERIC_TYPE: T = T::DEFAULT; - - const ASSOC_TYPE: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED; - const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); //~ declare_interior_mutable_const -} - -fn main() {} diff --git a/tests/ui/declare_interior_mutable_const/traits.stderr b/tests/ui/declare_interior_mutable_const/traits.stderr deleted file mode 100644 index a5c08871ba779..0000000000000 --- a/tests/ui/declare_interior_mutable_const/traits.stderr +++ /dev/null @@ -1,65 +0,0 @@ -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/traits.rs:15:11 - | -LL | const ATOMIC: AtomicUsize; - | ^^^^^^ - | - = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/traits.rs:18:20 - | -LL | declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); - | ^^^^^^^^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/traits.rs:68:11 - | -LL | const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); - | ^^^^^^^^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/traits.rs:69:11 - | -LL | const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/traits.rs:88:11 - | -LL | const BOUNDED: T::ToBeBounded; - | ^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/traits.rs:117:11 - | -LL | const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); - | ^^^^^^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/traits.rs:123:11 - | -LL | const DIRECT: Cell; - | ^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/traits.rs:124:11 - | -LL | const INDIRECT: Cell<*const T>; - | ^^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/traits.rs:140:11 - | -LL | const ATOMIC: AtomicUsize = AtomicUsize::new(18); - | ^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/traits.rs:146:11 - | -LL | const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); - | ^^^^^^^^^^^^^^^^^^ - -error: aborting due to 10 previous errors - From 44681fd81bc33752a638cf0d8398155da77b260a Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 16 Apr 2025 09:24:39 -0400 Subject: [PATCH 2337/4206] Improve `cargo dev rename_lint` * rename test files inside directories and ui-toml tests * rename tests prefixed with the lint's name * better module path renaming when renaming the lint's module * partially delete lint files when uplifting * rename ui_test error markers --- clippy_dev/Cargo.toml | 1 - clippy_dev/src/lib.rs | 9 +- clippy_dev/src/rename_lint.rs | 459 ++++++++++++++++++++++++--------- clippy_dev/src/update_lints.rs | 63 ++--- clippy_dev/src/utils.rs | 168 ++++++------ 5 files changed, 448 insertions(+), 252 deletions(-) diff --git a/clippy_dev/Cargo.toml b/clippy_dev/Cargo.toml index 47b7b3758613c..a963fba7d98e3 100644 --- a/clippy_dev/Cargo.toml +++ b/clippy_dev/Cargo.toml @@ -5,7 +5,6 @@ version = "0.0.1" edition = "2024" [dependencies] -aho-corasick = "1.0" chrono = { version = "0.4.38", default-features = false, features = ["clock"] } clap = { version = "4.4", features = ["derive"] } indoc = "1.0" diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index e237a05b2530e..1cfcbdfe855e9 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -1,4 +1,11 @@ -#![feature(rustc_private, if_let_guard, let_chains)] +#![feature( + rustc_private, + if_let_guard, + let_chains, + os_str_slice, + os_string_truncate, + slice_split_once +)] #![warn( trivial_casts, trivial_numeric_casts, diff --git a/clippy_dev/src/rename_lint.rs b/clippy_dev/src/rename_lint.rs index 9e7e5d97f0219..e3e6870b8a5de 100644 --- a/clippy_dev/src/rename_lint.rs +++ b/clippy_dev/src/rename_lint.rs @@ -1,9 +1,11 @@ -use crate::update_lints::{ - DeprecatedLints, RenamedLint, find_lint_decls, gen_renamed_lints_test_fn, generate_lint_files, - read_deprecated_lints, +use crate::update_lints::{DeprecatedLints, RenamedLint, find_lint_decls, generate_lint_files, read_deprecated_lints}; +use crate::utils::{ + FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, Version, delete_dir_if_exists, delete_file_if_exists, + try_rename_dir, try_rename_file, }; -use crate::utils::{FileUpdater, StringReplacer, UpdateMode, Version, try_rename_file}; -use std::ffi::OsStr; +use rustc_lexer::TokenKind; +use std::ffi::OsString; +use std::fs; use std::path::Path; use walkdir::WalkDir; @@ -22,7 +24,7 @@ use walkdir::WalkDir; /// * If either lint name has a prefix /// * If `old_name` doesn't name an existing lint. /// * If `old_name` names a deprecated or renamed lint. -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines)] pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: bool) { if let Some((prefix, _)) = old_name.split_once("::") { panic!("`{old_name}` should not contain the `{prefix}` prefix"); @@ -42,153 +44,354 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b .. } = read_deprecated_lints(); - let mut old_lint_index = None; - let mut found_new_name = false; - for (i, lint) in lints.iter().enumerate() { - if lint.name == old_name { - old_lint_index = Some(i); - } else if lint.name == new_name { - found_new_name = true; - } - } - let old_lint_index = old_lint_index.unwrap_or_else(|| panic!("could not find lint `{old_name}`")); + let Ok(lint_idx) = lints.binary_search_by(|x| x.name.as_str().cmp(old_name)) else { + panic!("could not find lint `{old_name}`"); + }; + let lint = &lints[lint_idx]; - let lint = RenamedLint { - old_name: format!("clippy::{old_name}"), + let renamed_lint = RenamedLint { + old_name: String::from_iter(["clippy::", old_name]), new_name: if uplift { - new_name.into() + new_name.to_owned() } else { - format!("clippy::{new_name}") + String::from_iter(["clippy::", new_name]) }, }; - - // Renamed lints and deprecated lints shouldn't have been found in the lint list, but check just in - // case. - assert!( - !renamed_lints.iter().any(|l| lint.old_name == l.old_name), - "`{old_name}` has already been renamed" - ); - assert!( - !deprecated_lints.iter().any(|l| lint.old_name == l.name), - "`{old_name}` has already been deprecated" - ); - - // Update all lint level attributes. (`clippy::lint_name`) - let replacements = &[(&*lint.old_name, &*lint.new_name)]; - let replacer = StringReplacer::new(replacements); - for file in WalkDir::new(".").into_iter().map(Result::unwrap).filter(|f| { - let name = f.path().file_name(); - let ext = f.path().extension(); - (ext == Some(OsStr::new("rs")) || ext == Some(OsStr::new("fixed"))) - && name != Some(OsStr::new("rename.rs")) - && name != Some(OsStr::new("deprecated_lints.rs")) - }) { - updater.update_file(file.path(), &mut replacer.replace_ident_fn()); - } - deprecated_contents.insert_str( renamed_end as usize, &format!( " #[clippy::version = \"{}\"]\n (\"{}\", \"{}\"),\n", clippy_version.rust_display(), - lint.old_name, - lint.new_name, + renamed_lint.old_name, + renamed_lint.new_name, ), ); deprecated_file.replace_contents(deprecated_contents.as_bytes()); - drop(deprecated_file); + renamed_lints.push(renamed_lint); - renamed_lints.push(lint); - renamed_lints.sort_by(|lhs, rhs| { - lhs.new_name - .starts_with("clippy::") - .cmp(&rhs.new_name.starts_with("clippy::")) - .reverse() - .then_with(|| lhs.old_name.cmp(&rhs.old_name)) - }); + // Some tests are named `lint_name_suffix` which should also be renamed, + // but we can't do that if the renamed lint's name overlaps with another + // lint. e.g. renaming 'foo' to 'bar' when a lint 'foo_bar' also exists. + let change_prefixed_tests = lints.get(lint_idx + 1).is_none_or(|l| !l.name.starts_with(old_name)); + let mut mod_edit = ModEdit::None; if uplift { - updater.update_file("tests/ui/rename.rs", &mut gen_renamed_lints_test_fn(&renamed_lints)); - println!( - "`{old_name}` has be uplifted. All the code inside `clippy_lints` related to it needs to be removed manually." - ); - } else if found_new_name { - updater.update_file("tests/ui/rename.rs", &mut gen_renamed_lints_test_fn(&renamed_lints)); - println!( - "`{new_name}` is already defined. The old linting code inside `clippy_lints` needs to be updated/removed manually." - ); + let is_unique_mod = lints[..lint_idx].iter().any(|l| l.module == lint.module) + || lints[lint_idx + 1..].iter().any(|l| l.module == lint.module); + if is_unique_mod { + if delete_file_if_exists(lint.path.as_ref()) { + mod_edit = ModEdit::Delete; + } + } else { + updater.update_file(&lint.path, &mut |_, src, dst| -> UpdateStatus { + let mut start = &src[..lint.declaration_range.start]; + if start.ends_with("\n\n") { + start = &start[..start.len() - 1]; + } + let mut end = &src[lint.declaration_range.end..]; + if end.starts_with("\n\n") { + end = &end[1..]; + } + dst.push_str(start); + dst.push_str(end); + UpdateStatus::Changed + }); + } + delete_test_files(old_name, change_prefixed_tests); + lints.remove(lint_idx); + } else if lints.binary_search_by(|x| x.name.as_str().cmp(new_name)).is_err() { + let lint = &mut lints[lint_idx]; + if lint.module.ends_with(old_name) + && lint + .path + .file_stem() + .is_some_and(|x| x.as_encoded_bytes() == old_name.as_bytes()) + { + let mut new_path = lint.path.with_file_name(new_name).into_os_string(); + new_path.push(".rs"); + if try_rename_file(lint.path.as_ref(), new_path.as_ref()) { + mod_edit = ModEdit::Rename; + } + + let mod_len = lint.module.len(); + lint.module.truncate(mod_len - old_name.len()); + lint.module.push_str(new_name); + } + rename_test_files(old_name, new_name, change_prefixed_tests); + new_name.clone_into(&mut lints[lint_idx].name); + lints.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name)); } else { - // Rename the lint struct and source files sharing a name with the lint. - let lint = &mut lints[old_lint_index]; - let old_name_upper = old_name.to_uppercase(); - let new_name_upper = new_name.to_uppercase(); - lint.name = new_name.into(); - - // Rename test files. only rename `.stderr` and `.fixed` files if the new test name doesn't exist. - if try_rename_file( - Path::new(&format!("tests/ui/{old_name}.rs")), - Path::new(&format!("tests/ui/{new_name}.rs")), - ) { - try_rename_file( - Path::new(&format!("tests/ui/{old_name}.stderr")), - Path::new(&format!("tests/ui/{new_name}.stderr")), - ); - try_rename_file( - Path::new(&format!("tests/ui/{old_name}.fixed")), - Path::new(&format!("tests/ui/{new_name}.fixed")), - ); + println!("Renamed `clippy::{old_name}` to `clippy::{new_name}`"); + println!("Since `{new_name}` already exists the existing code has not been changed"); + return; + } + + let mut update_fn = file_update_fn(old_name, new_name, mod_edit); + for file in WalkDir::new(".").into_iter().filter_entry(|e| { + // Skip traversing some of the larger directories. + e.path() + .as_os_str() + .as_encoded_bytes() + .get(2..) + .is_none_or(|x| x != "target".as_bytes() && x != ".git".as_bytes()) + }) { + let file = file.expect("error reading clippy directory"); + if file.path().as_os_str().as_encoded_bytes().ends_with(b".rs") { + updater.update_file(file.path(), &mut update_fn); } + } + generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); - // Try to rename the file containing the lint if the file name matches the lint's name. - let replacements; - let replacements = if lint.module == old_name - && try_rename_file( - Path::new(&format!("clippy_lints/src/{old_name}.rs")), - Path::new(&format!("clippy_lints/src/{new_name}.rs")), - ) { - // Edit the module name in the lint list. Note there could be multiple lints. - for lint in lints.iter_mut().filter(|l| l.module == old_name) { - lint.module = new_name.into(); + if uplift { + println!("Uplifted `clippy::{old_name}` as `{new_name}`"); + if matches!(mod_edit, ModEdit::None) { + println!("Only the rename has been registered, the code will need to be edited manually"); + } else { + println!("All the lint's code has been deleted"); + println!("Make sure to inspect the results as some things may have been missed"); + } + } else { + println!("Renamed `clippy::{old_name}` to `clippy::{new_name}`"); + println!("All code referencing the old name has been updated"); + println!("Make sure to inspect the results as some things may have been missed"); + } + println!("note: `cargo uibless` still needs to be run to update the test results"); +} + +#[derive(Clone, Copy)] +enum ModEdit { + None, + Delete, + Rename, +} + +fn collect_ui_test_names(lint: &str, rename_prefixed: bool, dst: &mut Vec<(OsString, bool)>) { + for e in fs::read_dir("tests/ui").expect("error reading `tests/ui`") { + let e = e.expect("error reading `tests/ui`"); + let name = e.file_name(); + if let Some((name_only, _)) = name.as_encoded_bytes().split_once(|&x| x == b'.') { + if name_only.starts_with(lint.as_bytes()) && (rename_prefixed || name_only.len() == lint.len()) { + dst.push((name, true)); } - replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)]; - replacements.as_slice() - } else if !lint.module.contains("::") - // Catch cases like `methods/lint_name.rs` where the lint is stored in `methods/mod.rs` - && try_rename_file( - Path::new(&format!("clippy_lints/src/{}/{old_name}.rs", lint.module)), - Path::new(&format!("clippy_lints/src/{}/{new_name}.rs", lint.module)), - ) + } else if name.as_encoded_bytes().starts_with(lint.as_bytes()) && (rename_prefixed || name.len() == lint.len()) { - // Edit the module name in the lint list. Note there could be multiple lints, or none. - let renamed_mod = format!("{}::{old_name}", lint.module); - for lint in lints.iter_mut().filter(|l| l.module == renamed_mod) { - lint.module = format!("{}::{new_name}", lint.module); + dst.push((name, false)); + } + } +} + +fn collect_ui_toml_test_names(lint: &str, rename_prefixed: bool, dst: &mut Vec<(OsString, bool)>) { + if rename_prefixed { + for e in fs::read_dir("tests/ui-toml").expect("error reading `tests/ui-toml`") { + let e = e.expect("error reading `tests/ui-toml`"); + let name = e.file_name(); + if name.as_encoded_bytes().starts_with(lint.as_bytes()) && e.file_type().is_ok_and(|ty| ty.is_dir()) { + dst.push((name, false)); } - replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)]; - replacements.as_slice() + } + } else { + dst.push((lint.into(), false)); + } +} + +/// Renames all test files for the given lint. +/// +/// If `rename_prefixed` is `true` this will also rename tests which have the lint name as a prefix. +fn rename_test_files(old_name: &str, new_name: &str, rename_prefixed: bool) { + let mut tests = Vec::new(); + + let mut old_buf = OsString::from("tests/ui/"); + let mut new_buf = OsString::from("tests/ui/"); + collect_ui_test_names(old_name, rename_prefixed, &mut tests); + for &(ref name, is_file) in &tests { + old_buf.push(name); + new_buf.extend([new_name.as_ref(), name.slice_encoded_bytes(old_name.len()..)]); + if is_file { + try_rename_file(old_buf.as_ref(), new_buf.as_ref()); } else { - replacements = [(&*old_name_upper, &*new_name_upper), ("", "")]; - &replacements[0..1] - }; - - // Don't change `clippy_utils/src/renamed_lints.rs` here as it would try to edit the lint being - // renamed. - let replacer = StringReplacer::new(replacements); - for file in WalkDir::new("clippy_lints/src") { - let file = file.expect("error reading `clippy_lints/src`"); - if file - .path() - .as_os_str() - .to_str() - .is_some_and(|x| x.ends_with("*.rs") && x["clippy_lints/src/".len()..] != *"deprecated_lints.rs") - { - updater.update_file(file.path(), &mut replacer.replace_ident_fn()); - } + try_rename_dir(old_buf.as_ref(), new_buf.as_ref()); + } + old_buf.truncate("tests/ui/".len()); + new_buf.truncate("tests/ui/".len()); + } + + tests.clear(); + old_buf.truncate("tests/ui".len()); + new_buf.truncate("tests/ui".len()); + old_buf.push("-toml/"); + new_buf.push("-toml/"); + collect_ui_toml_test_names(old_name, rename_prefixed, &mut tests); + for (name, _) in &tests { + old_buf.push(name); + new_buf.extend([new_name.as_ref(), name.slice_encoded_bytes(old_name.len()..)]); + try_rename_dir(old_buf.as_ref(), new_buf.as_ref()); + old_buf.truncate("tests/ui/".len()); + new_buf.truncate("tests/ui/".len()); + } +} + +fn delete_test_files(lint: &str, rename_prefixed: bool) { + let mut tests = Vec::new(); + + let mut buf = OsString::from("tests/ui/"); + collect_ui_test_names(lint, rename_prefixed, &mut tests); + for &(ref name, is_file) in &tests { + buf.push(name); + if is_file { + delete_file_if_exists(buf.as_ref()); + } else { + delete_dir_if_exists(buf.as_ref()); } + buf.truncate("tests/ui/".len()); + } + + buf.truncate("tests/ui".len()); + buf.push("-toml/"); - generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); - println!("{old_name} has been successfully renamed"); + tests.clear(); + collect_ui_toml_test_names(lint, rename_prefixed, &mut tests); + for (name, _) in &tests { + buf.push(name); + delete_dir_if_exists(buf.as_ref()); + buf.truncate("tests/ui/".len()); } +} - println!("note: `cargo uitest` still needs to be run to update the test results"); +fn snake_to_pascal(s: &str) -> String { + let mut dst = Vec::with_capacity(s.len()); + let mut iter = s.bytes(); + || -> Option<()> { + dst.push(iter.next()?.to_ascii_uppercase()); + while let Some(c) = iter.next() { + if c == b'_' { + dst.push(iter.next()?.to_ascii_uppercase()); + } else { + dst.push(c); + } + } + Some(()) + }(); + String::from_utf8(dst).unwrap() +} + +#[expect(clippy::too_many_lines)] +fn file_update_fn<'a, 'b>( + old_name: &'a str, + new_name: &'b str, + mod_edit: ModEdit, +) -> impl use<'a, 'b> + FnMut(&Path, &str, &mut String) -> UpdateStatus { + let old_name_pascal = snake_to_pascal(old_name); + let new_name_pascal = snake_to_pascal(new_name); + let old_name_upper = old_name.to_ascii_uppercase(); + let new_name_upper = new_name.to_ascii_uppercase(); + move |_, src, dst| { + let mut copy_pos = 0u32; + let mut changed = false; + let mut searcher = RustSearcher::new(src); + let mut capture = ""; + loop { + match searcher.peek() { + TokenKind::Eof => break, + TokenKind::Ident => { + let match_start = searcher.pos(); + let text = searcher.peek_text(); + searcher.step(); + match text { + // clippy::line_name or clippy::lint-name + "clippy" => { + if searcher.match_tokens(&[Token::DoubleColon, Token::CaptureIdent], &mut [&mut capture]) + && capture == old_name + { + dst.push_str(&src[copy_pos as usize..searcher.pos() as usize - capture.len()]); + dst.push_str(new_name); + copy_pos = searcher.pos(); + changed = true; + } + }, + // mod lint_name + "mod" => { + if !matches!(mod_edit, ModEdit::None) + && searcher.match_tokens(&[Token::CaptureIdent], &mut [&mut capture]) + && capture == old_name + { + match mod_edit { + ModEdit::Rename => { + dst.push_str(&src[copy_pos as usize..searcher.pos() as usize - capture.len()]); + dst.push_str(new_name); + copy_pos = searcher.pos(); + changed = true; + }, + ModEdit::Delete if searcher.match_tokens(&[Token::Semi], &mut []) => { + let mut start = &src[copy_pos as usize..match_start as usize]; + if start.ends_with("\n\n") { + start = &start[..start.len() - 1]; + } + dst.push_str(start); + copy_pos = searcher.pos(); + if src[copy_pos as usize..].starts_with("\n\n") { + copy_pos += 1; + } + changed = true; + }, + ModEdit::Delete | ModEdit::None => {}, + } + } + }, + // lint_name:: + name if matches!(mod_edit, ModEdit::Rename) && name == old_name => { + let name_end = searcher.pos(); + if searcher.match_tokens(&[Token::DoubleColon], &mut []) { + dst.push_str(&src[copy_pos as usize..match_start as usize]); + dst.push_str(new_name); + copy_pos = name_end; + changed = true; + } + }, + // LINT_NAME or LintName + name => { + let replacement = if name == old_name_upper { + &new_name_upper + } else if name == old_name_pascal { + &new_name_pascal + } else { + continue; + }; + dst.push_str(&src[copy_pos as usize..match_start as usize]); + dst.push_str(replacement); + copy_pos = searcher.pos(); + changed = true; + }, + } + }, + // //~ lint_name + TokenKind::LineComment { doc_style: None } => { + let text = searcher.peek_text(); + if text.starts_with("//~") + && let Some(text) = text.strip_suffix(old_name) + && !text.ends_with(|c| matches!(c, 'a'..='z' | 'A'..='Z' | '0'..='9' | '_')) + { + dst.push_str(&src[copy_pos as usize..searcher.pos() as usize + text.len()]); + dst.push_str(new_name); + copy_pos = searcher.pos() + searcher.peek_len(); + changed = true; + } + searcher.step(); + }, + // ::lint_name + TokenKind::Colon + if searcher.match_tokens(&[Token::DoubleColon, Token::CaptureIdent], &mut [&mut capture]) + && capture == old_name => + { + dst.push_str(&src[copy_pos as usize..searcher.pos() as usize - capture.len()]); + dst.push_str(new_name); + copy_pos = searcher.pos(); + changed = true; + }, + _ => searcher.step(), + } + } + + dst.push_str(&src[copy_pos as usize..]); + UpdateStatus::from_changed(changed) + } } diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 0c861b7293562..4899371bd0f85 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -6,7 +6,7 @@ use std::collections::HashSet; use std::fmt::Write; use std::fs::OpenOptions; use std::ops::Range; -use std::path::Path; +use std::path::{Path, PathBuf}; use walkdir::{DirEntry, WalkDir}; const GENERATED_FILE_COMMENT: &str = "// This file was generated by `cargo dev update_lints`.\n\ @@ -101,7 +101,24 @@ pub fn generate_lint_files( dst.push_str("\nfn main() {}\n"); UpdateStatus::from_changed(src != dst) }), - ("tests/ui/rename.rs", &mut gen_renamed_lints_test_fn(renamed)), + ("tests/ui/rename.rs", &mut move |_, src, dst| { + let mut seen_lints = HashSet::new(); + dst.push_str(GENERATED_FILE_COMMENT); + dst.push_str("#![allow(clippy::duplicated_attributes)]\n"); + for lint in renamed { + if seen_lints.insert(&lint.new_name) { + writeln!(dst, "#![allow({})]", lint.new_name).unwrap(); + } + } + seen_lints.clear(); + for lint in renamed { + if seen_lints.insert(&lint.old_name) { + writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.old_name, lint.old_name).unwrap(); + } + } + dst.push_str("\nfn main() {}\n"); + UpdateStatus::from_changed(src != dst) + }), ], ); } @@ -116,6 +133,7 @@ pub struct Lint { pub name: String, pub group: String, pub module: String, + pub path: PathBuf, pub declaration_range: Range, } @@ -130,27 +148,6 @@ pub struct RenamedLint { pub new_name: String, } -pub fn gen_renamed_lints_test_fn(lints: &[RenamedLint]) -> impl Fn(&Path, &str, &mut String) -> UpdateStatus { - move |_, src, dst| { - let mut seen_lints = HashSet::new(); - dst.push_str(GENERATED_FILE_COMMENT); - dst.push_str("#![allow(clippy::duplicated_attributes)]\n"); - for lint in lints { - if seen_lints.insert(&lint.new_name) { - writeln!(dst, "#![allow({})]", lint.new_name).unwrap(); - } - } - seen_lints.clear(); - for lint in lints { - if seen_lints.insert(&lint.old_name) { - writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.old_name, lint.old_name).unwrap(); - } - } - dst.push_str("\nfn main() {}\n"); - UpdateStatus::from_changed(src != dst) - } -} - /// Finds all lint declarations (`declare_clippy_lint!`) #[must_use] pub fn find_lint_decls() -> Vec { @@ -158,6 +155,7 @@ pub fn find_lint_decls() -> Vec { let mut contents = String::new(); for (file, module) in read_src_with_module("clippy_lints/src".as_ref()) { parse_clippy_lint_decls( + file.path(), File::open_read_to_cleared_string(file.path(), &mut contents), &module, &mut lints, @@ -202,17 +200,17 @@ fn read_src_with_module(src_root: &Path) -> impl use<'_> + Iterator) { +fn parse_clippy_lint_decls(path: &Path, contents: &str, module: &str, lints: &mut Vec) { #[allow(clippy::enum_glob_use)] use Token::*; #[rustfmt::skip] - static DECL_TOKENS: &[Token] = &[ + static DECL_TOKENS: &[Token<'_>] = &[ // !{ /// docs - Bang, OpenBrace, AnyDoc, + Bang, OpenBrace, AnyComment, // #[clippy::version = "version"] Pound, OpenBracket, Ident("clippy"), DoubleColon, Ident("version"), Eq, LitStr, CloseBracket, // pub NAME, GROUP, - Ident("pub"), CaptureIdent, Comma, CaptureIdent, Comma, + Ident("pub"), CaptureIdent, Comma, AnyComment, CaptureIdent, Comma, ]; let mut searcher = RustSearcher::new(contents); @@ -224,6 +222,7 @@ fn parse_clippy_lint_decls(contents: &str, module: &str, lints: &mut Vec) name: name.to_lowercase(), group: group.into(), module: module.into(), + path: path.into(), declaration_range: start..searcher.pos() as usize, }); } @@ -244,19 +243,19 @@ pub fn read_deprecated_lints() -> DeprecatedLints { #[allow(clippy::enum_glob_use)] use Token::*; #[rustfmt::skip] - static DECL_TOKENS: &[Token] = &[ + static DECL_TOKENS: &[Token<'_>] = &[ // #[clippy::version = "version"] Pound, OpenBracket, Ident("clippy"), DoubleColon, Ident("version"), Eq, LitStr, CloseBracket, // ("first", "second"), OpenParen, CaptureLitStr, Comma, CaptureLitStr, CloseParen, Comma, ]; #[rustfmt::skip] - static DEPRECATED_TOKENS: &[Token] = &[ + static DEPRECATED_TOKENS: &[Token<'_>] = &[ // !{ DEPRECATED(DEPRECATED_VERSION) = [ Bang, OpenBrace, Ident("DEPRECATED"), OpenParen, Ident("DEPRECATED_VERSION"), CloseParen, Eq, OpenBracket, ]; #[rustfmt::skip] - static RENAMED_TOKENS: &[Token] = &[ + static RENAMED_TOKENS: &[Token<'_>] = &[ // !{ RENAMED(RENAMED_VERSION) = [ Bang, OpenBrace, Ident("RENAMED"), OpenParen, Ident("RENAMED_VERSION"), CloseParen, Eq, OpenBracket, ]; @@ -366,7 +365,7 @@ mod tests { } "#; let mut result = Vec::new(); - parse_clippy_lint_decls(CONTENTS, "module_name", &mut result); + parse_clippy_lint_decls("".as_ref(), CONTENTS, "module_name", &mut result); for r in &mut result { r.declaration_range = Range::default(); } @@ -376,12 +375,14 @@ mod tests { name: "ptr_arg".into(), group: "style".into(), module: "module_name".into(), + path: PathBuf::new(), declaration_range: Range::default(), }, Lint { name: "doc_markdown".into(), group: "pedantic".into(), module: "module_name".into(), + path: PathBuf::new(), declaration_range: Range::default(), }, ]; diff --git a/clippy_dev/src/utils.rs b/clippy_dev/src/utils.rs index ae2eabc45dd00..fb2e25e655dc4 100644 --- a/clippy_dev/src/utils.rs +++ b/clippy_dev/src/utils.rs @@ -1,4 +1,3 @@ -use aho_corasick::{AhoCorasick, AhoCorasickBuilder}; use core::fmt::{self, Display}; use core::slice; use core::str::FromStr; @@ -21,6 +20,7 @@ pub enum FileAction { Write, Create, Rename, + Delete, } impl FileAction { fn as_str(self) -> &'static str { @@ -30,6 +30,7 @@ impl FileAction { Self::Write => "writing", Self::Create => "creating", Self::Rename => "renaming", + Self::Delete => "deleting", } } } @@ -366,53 +367,11 @@ pub fn update_text_region_fn( move |path, src, dst| update_text_region(path, start, end, src, dst, &mut insert) } -#[must_use] -pub fn is_ident_char(c: u8) -> bool { - matches!(c, b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_') -} - -pub struct StringReplacer<'a> { - searcher: AhoCorasick, - replacements: &'a [(&'a str, &'a str)], -} -impl<'a> StringReplacer<'a> { - #[must_use] - pub fn new(replacements: &'a [(&'a str, &'a str)]) -> Self { - Self { - searcher: AhoCorasickBuilder::new() - .match_kind(aho_corasick::MatchKind::LeftmostLongest) - .build(replacements.iter().map(|&(x, _)| x)) - .unwrap(), - replacements, - } - } - - /// Replace substrings if they aren't bordered by identifier characters. - pub fn replace_ident_fn(&self) -> impl Fn(&Path, &str, &mut String) -> UpdateStatus { - move |_, src, dst| { - let mut pos = 0; - let mut changed = false; - for m in self.searcher.find_iter(src) { - if !is_ident_char(src.as_bytes().get(m.start().wrapping_sub(1)).copied().unwrap_or(0)) - && !is_ident_char(src.as_bytes().get(m.end()).copied().unwrap_or(0)) - { - changed = true; - dst.push_str(&src[pos..m.start()]); - dst.push_str(self.replacements[m.pattern()].1); - pos = m.end(); - } - } - dst.push_str(&src[pos..]); - UpdateStatus::from_changed(changed) - } - } -} - #[derive(Clone, Copy)] -pub enum Token { - /// Matches any number of doc comments. - AnyDoc, - Ident(&'static str), +pub enum Token<'a> { + /// Matches any number of comments / doc comments. + AnyComment, + Ident(&'a str), CaptureIdent, LitStr, CaptureLitStr, @@ -431,29 +390,26 @@ pub enum Token { OpenBracket, OpenParen, Pound, + Semi, + Slash, } pub struct RustSearcher<'txt> { text: &'txt str, cursor: lexer::Cursor<'txt>, pos: u32, - - // Either the next token or a zero-sized whitespace sentinel. next_token: lexer::Token, } impl<'txt> RustSearcher<'txt> { #[must_use] + #[expect(clippy::inconsistent_struct_constructor)] pub fn new(text: &'txt str) -> Self { + let mut cursor = lexer::Cursor::new(text, FrontmatterAllowed::Yes); Self { text, - cursor: lexer::Cursor::new(text, FrontmatterAllowed::Yes), pos: 0, - - // Sentinel value indicating there is no read token. - next_token: lexer::Token { - len: 0, - kind: lexer::TokenKind::Whitespace, - }, + next_token: cursor.advance_token(), + cursor, } } @@ -462,6 +418,11 @@ impl<'txt> RustSearcher<'txt> { &self.text[self.pos as usize..(self.pos + self.next_token.len) as usize] } + #[must_use] + pub fn peek_len(&self) -> u32 { + self.next_token.len + } + #[must_use] pub fn peek(&self) -> lexer::TokenKind { self.next_token.kind @@ -485,37 +446,15 @@ impl<'txt> RustSearcher<'txt> { /// Consumes the next token if it matches the requested value and captures the value if /// requested. Returns true if a token was matched. - fn read_token(&mut self, token: Token, captures: &mut slice::IterMut<'_, &mut &'txt str>) -> bool { + fn read_token(&mut self, token: Token<'_>, captures: &mut slice::IterMut<'_, &mut &'txt str>) -> bool { loop { match (token, self.next_token.kind) { - // Has to be the first match arm so the empty sentinel token will be handled. - // This will also skip all whitespace/comments preceding any tokens. - ( - _, - lexer::TokenKind::Whitespace - | lexer::TokenKind::LineComment { doc_style: None } - | lexer::TokenKind::BlockComment { - doc_style: None, - terminated: true, - }, - ) => { - self.step(); - if self.at_end() { - // `AnyDoc` always matches. - return matches!(token, Token::AnyDoc); - } - }, - ( - Token::AnyDoc, + (_, lexer::TokenKind::Whitespace) + | ( + Token::AnyComment, lexer::TokenKind::BlockComment { terminated: true, .. } | lexer::TokenKind::LineComment { .. }, - ) => { - self.step(); - if self.at_end() { - // `AnyDoc` always matches. - return true; - } - }, - (Token::AnyDoc, _) => return true, + ) => self.step(), + (Token::AnyComment, _) => return true, (Token::Bang, lexer::TokenKind::Bang) | (Token::CloseBrace, lexer::TokenKind::CloseBrace) | (Token::CloseBracket, lexer::TokenKind::CloseBracket) @@ -529,6 +468,8 @@ impl<'txt> RustSearcher<'txt> { | (Token::OpenBracket, lexer::TokenKind::OpenBracket) | (Token::OpenParen, lexer::TokenKind::OpenParen) | (Token::Pound, lexer::TokenKind::Pound) + | (Token::Semi, lexer::TokenKind::Semi) + | (Token::Slash, lexer::TokenKind::Slash) | ( Token::LitStr, lexer::TokenKind::Literal { @@ -569,7 +510,7 @@ impl<'txt> RustSearcher<'txt> { } #[must_use] - pub fn find_token(&mut self, token: Token) -> bool { + pub fn find_token(&mut self, token: Token<'_>) -> bool { let mut capture = [].iter_mut(); while !self.read_token(token, &mut capture) { self.step(); @@ -581,7 +522,7 @@ impl<'txt> RustSearcher<'txt> { } #[must_use] - pub fn find_capture_token(&mut self, token: Token) -> Option<&'txt str> { + pub fn find_capture_token(&mut self, token: Token<'_>) -> Option<&'txt str> { let mut res = ""; let mut capture = &mut res; let mut capture = slice::from_mut(&mut capture).iter_mut(); @@ -595,7 +536,7 @@ impl<'txt> RustSearcher<'txt> { } #[must_use] - pub fn match_tokens(&mut self, tokens: &[Token], captures: &mut [&mut &'txt str]) -> bool { + pub fn match_tokens(&mut self, tokens: &[Token<'_>], captures: &mut [&mut &'txt str]) -> bool { let mut captures = captures.iter_mut(); tokens.iter().all(|&t| self.read_token(t, &mut captures)) } @@ -606,16 +547,44 @@ pub fn try_rename_file(old_name: &Path, new_name: &Path) -> bool { match OpenOptions::new().create_new(true).write(true).open(new_name) { Ok(file) => drop(file), Err(e) if matches!(e.kind(), io::ErrorKind::AlreadyExists | io::ErrorKind::NotFound) => return false, - Err(e) => panic_file(&e, FileAction::Create, new_name), + Err(ref e) => panic_file(e, FileAction::Create, new_name), } match fs::rename(old_name, new_name) { Ok(()) => true, - Err(e) => { + Err(ref e) => { drop(fs::remove_file(new_name)); - if e.kind() == io::ErrorKind::NotFound { + // `NotADirectory` happens on posix when renaming a directory to an existing file. + // Windows will ignore this and rename anyways. + if matches!(e.kind(), io::ErrorKind::NotFound | io::ErrorKind::NotADirectory) { false } else { - panic_file(&e, FileAction::Rename, old_name); + panic_file(e, FileAction::Rename, old_name); + } + }, + } +} + +#[expect(clippy::must_use_candidate)] +pub fn try_rename_dir(old_name: &Path, new_name: &Path) -> bool { + match fs::create_dir(new_name) { + Ok(()) => {}, + Err(e) if matches!(e.kind(), io::ErrorKind::AlreadyExists | io::ErrorKind::NotFound) => return false, + Err(ref e) => panic_file(e, FileAction::Create, new_name), + } + // Windows can't reliably rename to an empty directory. + #[cfg(windows)] + drop(fs::remove_dir(new_name)); + match fs::rename(old_name, new_name) { + Ok(()) => true, + Err(ref e) => { + // Already dropped earlier on windows. + #[cfg(not(windows))] + drop(fs::remove_dir(new_name)); + // `NotADirectory` happens on posix when renaming a file to an existing directory. + if matches!(e.kind(), io::ErrorKind::NotFound | io::ErrorKind::NotADirectory) { + false + } else { + panic_file(e, FileAction::Rename, old_name); } }, } @@ -624,3 +593,20 @@ pub fn try_rename_file(old_name: &Path, new_name: &Path) -> bool { pub fn write_file(path: &Path, contents: &str) { fs::write(path, contents).unwrap_or_else(|e| panic_file(&e, FileAction::Write, path)); } + +#[expect(clippy::must_use_candidate)] +pub fn delete_file_if_exists(path: &Path) -> bool { + match fs::remove_file(path) { + Ok(()) => true, + Err(e) if matches!(e.kind(), io::ErrorKind::NotFound | io::ErrorKind::IsADirectory) => false, + Err(ref e) => panic_file(e, FileAction::Delete, path), + } +} + +pub fn delete_dir_if_exists(path: &Path) { + match fs::remove_dir_all(path) { + Ok(()) => {}, + Err(e) if matches!(e.kind(), io::ErrorKind::NotFound | io::ErrorKind::NotADirectory) => {}, + Err(ref e) => panic_file(e, FileAction::Delete, path), + } +} From 5f8954bc4185bf825eb84a44d3833e0ce78590da Mon Sep 17 00:00:00 2001 From: yukang Date: Fri, 16 May 2025 12:38:51 +0200 Subject: [PATCH 2338/4206] Fix the issue of typo of comma in arm parsing --- compiler/rustc_parse/src/parser/expr.rs | 54 ++++++++++++------- .../match-arm-comma-typo-issue-140991.fixed | 24 +++++++++ .../match-arm-comma-typo-issue-140991.rs | 24 +++++++++ .../match-arm-comma-typo-issue-140991.stderr | 26 +++++++++ 4 files changed, 110 insertions(+), 18 deletions(-) create mode 100644 tests/ui/parser/match-arm-comma-typo-issue-140991.fixed create mode 100644 tests/ui/parser/match-arm-comma-typo-issue-140991.rs create mode 100644 tests/ui/parser/match-arm-comma-typo-issue-140991.stderr diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 2a7910a6af4dd..1a44f4af8a629 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3311,26 +3311,44 @@ impl<'a> Parser<'a> { let sm = this.psess.source_map(); if let Ok(expr_lines) = sm.span_to_lines(expr_span) && let Ok(arm_start_lines) = sm.span_to_lines(arm_start_span) - && arm_start_lines.lines[0].end_col == expr_lines.lines[0].end_col && expr_lines.lines.len() == 2 { - // We check whether there's any trailing code in the parse span, - // if there isn't, we very likely have the following: - // - // X | &Y => "y" - // | -- - missing comma - // | | - // | arrow_span - // X | &X => "x" - // | - ^^ self.token.span - // | | - // | parsed until here as `"y" & X` - err.span_suggestion_short( - arm_start_span.shrink_to_hi(), - "missing a comma here to end this `match` arm", - ",", - Applicability::MachineApplicable, - ); + if arm_start_lines.lines[0].end_col == expr_lines.lines[0].end_col { + // We check whether there's any trailing code in the parse span, + // if there isn't, we very likely have the following: + // + // X | &Y => "y" + // | -- - missing comma + // | | + // | arrow_span + // X | &X => "x" + // | - ^^ self.token.span + // | | + // | parsed until here as `"y" & X` + err.span_suggestion_short( + arm_start_span.shrink_to_hi(), + "missing a comma here to end this `match` arm", + ",", + Applicability::MachineApplicable, + ); + } else if arm_start_lines.lines[0].end_col + rustc_span::CharPos(1) + == expr_lines.lines[0].end_col + { + // similar to the above, but we may typo a `.` or `/` at the end of the line + let comma_span = arm_start_span + .shrink_to_hi() + .with_hi(arm_start_span.hi() + rustc_span::BytePos(1)); + if let Ok(res) = sm.span_to_snippet(comma_span) + && (res == "." || res == "/") + { + err.span_suggestion_short( + comma_span, + "you might have meant to write a `,` to end this `match` arm", + ",", + Applicability::MachineApplicable, + ); + } + } } } else { err.span_label( diff --git a/tests/ui/parser/match-arm-comma-typo-issue-140991.fixed b/tests/ui/parser/match-arm-comma-typo-issue-140991.fixed new file mode 100644 index 0000000000000..4d99e4bdc1c3f --- /dev/null +++ b/tests/ui/parser/match-arm-comma-typo-issue-140991.fixed @@ -0,0 +1,24 @@ +//@ run-rustfix + +pub enum Foo { + X, Y +} + +pub fn typo1(foo: Foo) -> Foo { + use Foo::*; + match foo { + X => Y, + Y => X, //~ ERROR expected one of + } +} + +pub fn typo2(foo: Foo) -> Foo { + use Foo::*; + match foo { + X => Y, + Y => X, //~ ERROR expected one of + } +} + + +fn main() { } diff --git a/tests/ui/parser/match-arm-comma-typo-issue-140991.rs b/tests/ui/parser/match-arm-comma-typo-issue-140991.rs new file mode 100644 index 0000000000000..3baf1ff3fa1df --- /dev/null +++ b/tests/ui/parser/match-arm-comma-typo-issue-140991.rs @@ -0,0 +1,24 @@ +//@ run-rustfix + +pub enum Foo { + X, Y +} + +pub fn typo1(foo: Foo) -> Foo { + use Foo::*; + match foo { + X => Y. + Y => X, //~ ERROR expected one of + } +} + +pub fn typo2(foo: Foo) -> Foo { + use Foo::*; + match foo { + X => Y/ + Y => X, //~ ERROR expected one of + } +} + + +fn main() { } diff --git a/tests/ui/parser/match-arm-comma-typo-issue-140991.stderr b/tests/ui/parser/match-arm-comma-typo-issue-140991.stderr new file mode 100644 index 0000000000000..19532d14245d1 --- /dev/null +++ b/tests/ui/parser/match-arm-comma-typo-issue-140991.stderr @@ -0,0 +1,26 @@ +error: expected one of `(`, `,`, `.`, `::`, `?`, `}`, or an operator, found `=>` + --> $DIR/match-arm-comma-typo-issue-140991.rs:11:11 + | +LL | Y => X, + | ^^ expected one of 7 possible tokens + | +help: you might have meant to write a `,` to end this `match` arm + | +LL - X => Y. +LL + X => Y, + | + +error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, `}`, or an operator, found `=>` + --> $DIR/match-arm-comma-typo-issue-140991.rs:19:11 + | +LL | Y => X, + | ^^ expected one of 8 possible tokens + | +help: you might have meant to write a `,` to end this `match` arm + | +LL - X => Y/ +LL + X => Y, + | + +error: aborting due to 2 previous errors + From b3f490202b471eb4714402f816b18c23c2726058 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 16 Apr 2025 15:47:37 -0400 Subject: [PATCH 2339/4206] clippy_dev: order `deprecated_lints.rs` in `update_lints` --- clippy_dev/src/deprecate_lint.rs | 61 ++-- clippy_dev/src/rename_lint.rs | 49 ++-- clippy_dev/src/update_lints.rs | 93 ++++--- clippy_lints/src/deprecated_lints.rs | 166 +++++------ tests/ui/deprecated.rs | 20 +- tests/ui/deprecated.stderr | 80 +++--- tests/ui/rename.fixed | 120 ++++---- tests/ui/rename.rs | 120 ++++---- tests/ui/rename.stderr | 400 +++++++++++++-------------- 9 files changed, 556 insertions(+), 553 deletions(-) diff --git a/clippy_dev/src/deprecate_lint.rs b/clippy_dev/src/deprecate_lint.rs index bf0e777104698..3bdc5b2772327 100644 --- a/clippy_dev/src/deprecate_lint.rs +++ b/clippy_dev/src/deprecate_lint.rs @@ -1,6 +1,4 @@ -use crate::update_lints::{ - DeprecatedLint, DeprecatedLints, Lint, find_lint_decls, generate_lint_files, read_deprecated_lints, -}; +use crate::update_lints::{DeprecatedLint, Lint, find_lint_decls, generate_lint_files, read_deprecated_lints}; use crate::utils::{UpdateMode, Version}; use std::ffi::OsStr; use std::path::{Path, PathBuf}; @@ -16,28 +14,34 @@ use std::{fs, io}; /// /// If a file path could not read from or written to pub fn deprecate(clippy_version: Version, name: &str, reason: &str) { - let prefixed_name = if name.starts_with("clippy::") { - name.to_owned() - } else { - format!("clippy::{name}") - }; - let stripped_name = &prefixed_name[8..]; + if let Some((prefix, _)) = name.split_once("::") { + panic!("`{name}` should not contain the `{prefix}` prefix"); + } let mut lints = find_lint_decls(); - let DeprecatedLints { - renamed: renamed_lints, - deprecated: mut deprecated_lints, - file: mut deprecated_file, - contents: mut deprecated_contents, - deprecated_end, - .. - } = read_deprecated_lints(); - - let Some(lint) = lints.iter().find(|l| l.name == stripped_name) else { + let (mut deprecated_lints, renamed_lints) = read_deprecated_lints(); + + let Some(lint) = lints.iter().find(|l| l.name == name) else { eprintln!("error: failed to find lint `{name}`"); return; }; + let prefixed_name = String::from_iter(["clippy::", name]); + match deprecated_lints.binary_search_by(|x| x.name.cmp(&prefixed_name)) { + Ok(_) => { + println!("`{name}` is already deprecated"); + return; + }, + Err(idx) => deprecated_lints.insert( + idx, + DeprecatedLint { + name: prefixed_name, + reason: reason.into(), + version: clippy_version.rust_display().to_string(), + }, + ), + } + let mod_path = { let mut mod_path = PathBuf::from(format!("clippy_lints/src/{}", lint.module)); if mod_path.is_dir() { @@ -48,24 +52,7 @@ pub fn deprecate(clippy_version: Version, name: &str, reason: &str) { mod_path }; - if remove_lint_declaration(stripped_name, &mod_path, &mut lints).unwrap_or(false) { - deprecated_contents.insert_str( - deprecated_end as usize, - &format!( - " #[clippy::version = \"{}\"]\n (\"{}\", \"{}\"),\n", - clippy_version.rust_display(), - prefixed_name, - reason, - ), - ); - deprecated_file.replace_contents(deprecated_contents.as_bytes()); - drop(deprecated_file); - - deprecated_lints.push(DeprecatedLint { - name: prefixed_name, - reason: reason.into(), - }); - + if remove_lint_declaration(name, &mod_path, &mut lints).unwrap_or(false) { generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); println!("info: `{name}` has successfully been deprecated"); println!("note: you must run `cargo uitest` to update the test results"); diff --git a/clippy_dev/src/rename_lint.rs b/clippy_dev/src/rename_lint.rs index e3e6870b8a5de..9f7c328712c31 100644 --- a/clippy_dev/src/rename_lint.rs +++ b/clippy_dev/src/rename_lint.rs @@ -1,4 +1,4 @@ -use crate::update_lints::{DeprecatedLints, RenamedLint, find_lint_decls, generate_lint_files, read_deprecated_lints}; +use crate::update_lints::{RenamedLint, find_lint_decls, generate_lint_files, read_deprecated_lints}; use crate::utils::{ FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, Version, delete_dir_if_exists, delete_file_if_exists, try_rename_dir, try_rename_file, @@ -35,39 +35,34 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b let mut updater = FileUpdater::default(); let mut lints = find_lint_decls(); - let DeprecatedLints { - renamed: mut renamed_lints, - deprecated: deprecated_lints, - file: mut deprecated_file, - contents: mut deprecated_contents, - renamed_end, - .. - } = read_deprecated_lints(); + let (deprecated_lints, mut renamed_lints) = read_deprecated_lints(); let Ok(lint_idx) = lints.binary_search_by(|x| x.name.as_str().cmp(old_name)) else { panic!("could not find lint `{old_name}`"); }; let lint = &lints[lint_idx]; - let renamed_lint = RenamedLint { - old_name: String::from_iter(["clippy::", old_name]), - new_name: if uplift { - new_name.to_owned() - } else { - String::from_iter(["clippy::", new_name]) + let old_name_prefixed = String::from_iter(["clippy::", old_name]); + match renamed_lints.binary_search_by(|x| x.old_name.cmp(&old_name_prefixed)) { + Ok(_) => { + println!("`{old_name}` already has a rename registered"); + return; }, - }; - deprecated_contents.insert_str( - renamed_end as usize, - &format!( - " #[clippy::version = \"{}\"]\n (\"{}\", \"{}\"),\n", - clippy_version.rust_display(), - renamed_lint.old_name, - renamed_lint.new_name, - ), - ); - deprecated_file.replace_contents(deprecated_contents.as_bytes()); - renamed_lints.push(renamed_lint); + Err(idx) => { + renamed_lints.insert( + idx, + RenamedLint { + old_name: old_name_prefixed, + new_name: if uplift { + new_name.to_owned() + } else { + String::from_iter(["clippy::", new_name]) + }, + version: clippy_version.rust_display().to_string(), + }, + ); + }, + } // Some tests are named `lint_name_suffix` which should also be renamed, // but we can't do that if the renamed lint's name overlaps with another diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 4899371bd0f85..8e203ae514222 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -4,7 +4,6 @@ use crate::utils::{ use itertools::Itertools; use std::collections::HashSet; use std::fmt::Write; -use std::fs::OpenOptions; use std::ops::Range; use std::path::{Path, PathBuf}; use walkdir::{DirEntry, WalkDir}; @@ -26,12 +25,11 @@ const DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.ht%20///%20Panics%20if%20a%20file%20path%20could%20not%20read%20from%20or%20then%20written%20to%20pub%20fn%20update(update_mode:%20UpdateMode)%20%7B%20%20%20%20%20let%20lints%20=%20find_lint_decls();-%20%20%20%20let%20DeprecatedLints%20%7B-%20%20%20%20%20%20%20%20renamed,%20deprecated,%20..-%20%20%20%20%7D%20=%20read_deprecated_lints();+%20%20%20%20let%20(deprecated,%20renamed)%20=%20read_deprecated_lints();%20%20%20%20%20generate_lint_files(update_mode,%20&lints,%20&deprecated,%20&renamed);%20%7D%20+#[expect(clippy::too_many_lines)]%20pub%20fn%20generate_lint_files(%20%20%20%20%20update_mode:%20UpdateMode,%20%20%20%20%20lints:%20&[Lint],@@%20-93,6%20+91,40%20@@%20pub%20fn%20generate_lint_files(%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dst.push_str("];\n"); UpdateStatus::from_changed(src != dst) }), + ("clippy_lints/src/deprecated_lints.rs", &mut |_, src, dst| { + let mut searcher = RustSearcher::new(src); + assert!( + searcher.find_token(Token::Ident("declare_with_version")) + && searcher.find_token(Token::Ident("declare_with_version")), + "error reading deprecated lints" + ); + dst.push_str(&src[..searcher.pos() as usize]); + dst.push_str("! { DEPRECATED(DEPRECATED_VERSION) = [\n"); + for lint in deprecated { + write!( + dst, + " #[clippy::version = \"{}\"]\n (\"{}\", \"{}\"),\n", + lint.version, lint.name, lint.reason, + ) + .unwrap(); + } + dst.push_str( + "]}\n\n\ + #[rustfmt::skip]\n\ + declare_with_version! { RENAMED(RENAMED_VERSION) = [\n\ + ", + ); + for lint in renamed { + write!( + dst, + " #[clippy::version = \"{}\"]\n (\"{}\", \"{}\"),\n", + lint.version, lint.old_name, lint.new_name, + ) + .unwrap(); + } + dst.push_str("]}\n"); + UpdateStatus::from_changed(src != dst) + }), ("tests/ui/deprecated.rs", &mut |_, src, dst| { dst.push_str(GENERATED_FILE_COMMENT); for lint in deprecated { @@ -128,7 +160,7 @@ fn round_to_fifty(count: usize) -> usize { } /// Lint data parsed from the Clippy source code. -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(PartialEq, Eq, Debug)] pub struct Lint { pub name: String, pub group: String, @@ -137,15 +169,16 @@ pub struct Lint { pub declaration_range: Range, } -#[derive(Clone, PartialEq, Eq, Debug)] pub struct DeprecatedLint { pub name: String, pub reason: String, + pub version: String, } pub struct RenamedLint { pub old_name: String, pub new_name: String, + pub version: String, } /// Finds all lint declarations (`declare_clippy_lint!`) @@ -229,23 +262,14 @@ fn parse_clippy_lint_decls(path: &Path, contents: &str, module: &str, lints: &mu } } -pub struct DeprecatedLints { - pub file: File<'static>, - pub contents: String, - pub deprecated: Vec, - pub renamed: Vec, - pub deprecated_end: u32, - pub renamed_end: u32, -} - #[must_use] -pub fn read_deprecated_lints() -> DeprecatedLints { +pub fn read_deprecated_lints() -> (Vec, Vec) { #[allow(clippy::enum_glob_use)] use Token::*; #[rustfmt::skip] static DECL_TOKENS: &[Token<'_>] = &[ // #[clippy::version = "version"] - Pound, OpenBracket, Ident("clippy"), DoubleColon, Ident("version"), Eq, LitStr, CloseBracket, + Pound, OpenBracket, Ident("clippy"), DoubleColon, Ident("version"), Eq, CaptureLitStr, CloseBracket, // ("first", "second"), OpenParen, CaptureLitStr, Comma, CaptureLitStr, CloseParen, Comma, ]; @@ -261,17 +285,12 @@ pub fn read_deprecated_lints() -> DeprecatedLints { ]; let path = "clippy_lints/src/deprecated_lints.rs"; - let mut res = DeprecatedLints { - file: File::open(path, OpenOptions::new().read(true).write(true)), - contents: String::new(), - deprecated: Vec::with_capacity(30), - renamed: Vec::with_capacity(80), - deprecated_end: 0, - renamed_end: 0, - }; + let mut deprecated = Vec::with_capacity(30); + let mut renamed = Vec::with_capacity(80); + let mut contents = String::new(); + File::open_read_to_cleared_string(path, &mut contents); - res.file.read_append_to_string(&mut res.contents); - let mut searcher = RustSearcher::new(&res.contents); + let mut searcher = RustSearcher::new(&contents); // First instance is the macro definition. assert!( @@ -280,36 +299,38 @@ pub fn read_deprecated_lints() -> DeprecatedLints { ); if searcher.find_token(Ident("declare_with_version")) && searcher.match_tokens(DEPRECATED_TOKENS, &mut []) { + let mut version = ""; let mut name = ""; let mut reason = ""; - while searcher.match_tokens(DECL_TOKENS, &mut [&mut name, &mut reason]) { - res.deprecated.push(DeprecatedLint { + while searcher.match_tokens(DECL_TOKENS, &mut [&mut version, &mut name, &mut reason]) { + deprecated.push(DeprecatedLint { name: parse_str_single_line(path.as_ref(), name), reason: parse_str_single_line(path.as_ref(), reason), + version: parse_str_single_line(path.as_ref(), version), }); } } else { panic!("error reading deprecated lints"); } - // position of the closing `]}` of `declare_with_version` - res.deprecated_end = searcher.pos(); if searcher.find_token(Ident("declare_with_version")) && searcher.match_tokens(RENAMED_TOKENS, &mut []) { + let mut version = ""; let mut old_name = ""; let mut new_name = ""; - while searcher.match_tokens(DECL_TOKENS, &mut [&mut old_name, &mut new_name]) { - res.renamed.push(RenamedLint { + while searcher.match_tokens(DECL_TOKENS, &mut [&mut version, &mut old_name, &mut new_name]) { + renamed.push(RenamedLint { old_name: parse_str_single_line(path.as_ref(), old_name), new_name: parse_str_single_line(path.as_ref(), new_name), + version: parse_str_single_line(path.as_ref(), version), }); } } else { panic!("error reading renamed lints"); } - // position of the closing `]}` of `declare_with_version` - res.renamed_end = searcher.pos(); - res + deprecated.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name)); + renamed.sort_by(|lhs, rhs| lhs.old_name.cmp(&rhs.old_name)); + (deprecated, renamed) } /// Removes the line splices and surrounding quotes from a string literal diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index 946515386690c..5204f73ea0a95 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -14,36 +14,36 @@ macro_rules! declare_with_version { #[rustfmt::skip] declare_with_version! { DEPRECATED(DEPRECATED_VERSION) = [ - #[clippy::version = "pre 1.29.0"] - ("clippy::should_assert_eq", "`assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can"), + #[clippy::version = "1.30.0"] + ("clippy::assign_ops", "compound operators are harmless and linting on them is not in scope for clippy"), #[clippy::version = "pre 1.29.0"] ("clippy::extend_from_slice", "`Vec::extend_from_slice` is no longer faster than `Vec::extend` due to specialization"), + #[clippy::version = "1.86.0"] + ("clippy::match_on_vec_items", "`clippy::indexing_slicing` covers indexing and slicing on `Vec<_>`"), + #[clippy::version = "pre 1.29.0"] + ("clippy::misaligned_transmute", "split into `clippy::cast_ptr_alignment` and `clippy::transmute_ptr_to_ptr`"), + #[clippy::version = "1.86.0"] + ("clippy::option_map_or_err_ok", "`clippy::manual_ok_or` covers this case"), + #[clippy::version = "1.54.0"] + ("clippy::pub_enum_variant_names", "`clippy::enum_variant_names` now covers this case via the `avoid-breaking-exported-api` config"), #[clippy::version = "pre 1.29.0"] ("clippy::range_step_by_zero", "`Iterator::step_by(0)` now panics and is no longer an infinite iterator"), + #[clippy::version = "1.47.0"] + ("clippy::regex_macro", "the `regex!` macro was removed from the regex crate in 2018"), + #[clippy::version = "1.44.0"] + ("clippy::replace_consts", "`min_value` and `max_value` are now deprecated"), #[clippy::version = "pre 1.29.0"] - ("clippy::unstable_as_slice", "`Vec::as_slice` is now stable"), + ("clippy::should_assert_eq", "`assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can"), #[clippy::version = "pre 1.29.0"] - ("clippy::unstable_as_mut_slice", "`Vec::as_mut_slice` is now stable"), + ("clippy::unsafe_vector_initialization", "the suggested alternative could be substantially slower"), #[clippy::version = "pre 1.29.0"] - ("clippy::misaligned_transmute", "split into `clippy::cast_ptr_alignment` and `clippy::transmute_ptr_to_ptr`"), - #[clippy::version = "1.30.0"] - ("clippy::assign_ops", "compound operators are harmless and linting on them is not in scope for clippy"), + ("clippy::unstable_as_mut_slice", "`Vec::as_mut_slice` is now stable"), #[clippy::version = "pre 1.29.0"] - ("clippy::unsafe_vector_initialization", "the suggested alternative could be substantially slower"), + ("clippy::unstable_as_slice", "`Vec::as_slice` is now stable"), #[clippy::version = "1.39.0"] ("clippy::unused_collect", "`Iterator::collect` is now marked as `#[must_use]`"), - #[clippy::version = "1.44.0"] - ("clippy::replace_consts", "`min_value` and `max_value` are now deprecated"), - #[clippy::version = "1.47.0"] - ("clippy::regex_macro", "the `regex!` macro was removed from the regex crate in 2018"), - #[clippy::version = "1.54.0"] - ("clippy::pub_enum_variant_names", "`clippy::enum_variant_names` now covers this case via the `avoid-breaking-exported-api` config"), #[clippy::version = "1.54.0"] ("clippy::wrong_pub_self_convention", "`clippy::wrong_self_convention` now covers this case via the `avoid-breaking-exported-api` config"), - #[clippy::version = "1.86.0"] - ("clippy::option_map_or_err_ok", "`clippy::manual_ok_or` covers this case"), - #[clippy::version = "1.86.0"] - ("clippy::match_on_vec_items", "`clippy::indexing_slicing` covers indexing and slicing on `Vec<_>`"), ]} #[rustfmt::skip] @@ -61,6 +61,12 @@ declare_with_version! { RENAMED(RENAMED_VERSION) = [ #[clippy::version = ""] ("clippy::box_vec", "clippy::box_collection"), #[clippy::version = ""] + ("clippy::cast_ref_to_mut", "invalid_reference_casting"), + #[clippy::version = ""] + ("clippy::clone_double_ref", "suspicious_double_ref_op"), + #[clippy::version = ""] + ("clippy::cmp_nan", "invalid_nan_comparisons"), + #[clippy::version = ""] ("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"), #[clippy::version = ""] ("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"), @@ -70,15 +76,35 @@ declare_with_version! { RENAMED(RENAMED_VERSION) = [ ("clippy::disallowed_method", "clippy::disallowed_methods"), #[clippy::version = ""] ("clippy::disallowed_type", "clippy::disallowed_types"), + #[clippy::version = "1.86.0"] + ("clippy::double_neg", "double_negations"), + #[clippy::version = ""] + ("clippy::drop_bounds", "drop_bounds"), + #[clippy::version = ""] + ("clippy::drop_copy", "dropping_copy_types"), + #[clippy::version = ""] + ("clippy::drop_ref", "dropping_references"), #[clippy::version = ""] ("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"), - #[clippy::version = "1.51.0"] - ("clippy::find_map", "clippy::manual_find_map"), #[clippy::version = "1.53.0"] ("clippy::filter_map", "clippy::manual_filter_map"), + #[clippy::version = "1.51.0"] + ("clippy::find_map", "clippy::manual_find_map"), #[clippy::version = ""] ("clippy::fn_address_comparisons", "unpredictable_function_pointer_comparisons"), #[clippy::version = ""] + ("clippy::fn_null_check", "useless_ptr_null_checks"), + #[clippy::version = ""] + ("clippy::for_loop_over_option", "for_loops_over_fallibles"), + #[clippy::version = ""] + ("clippy::for_loop_over_result", "for_loops_over_fallibles"), + #[clippy::version = ""] + ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"), + #[clippy::version = ""] + ("clippy::forget_copy", "forgetting_copy_types"), + #[clippy::version = ""] + ("clippy::forget_ref", "forgetting_references"), + #[clippy::version = ""] ("clippy::identity_conversion", "clippy::useless_conversion"), #[clippy::version = "pre 1.29.0"] ("clippy::if_let_redundant_pattern_matching", "clippy::redundant_pattern_matching"), @@ -91,7 +117,25 @@ declare_with_version! { RENAMED(RENAMED_VERSION) = [ #[clippy::version = ""] ("clippy::integer_arithmetic", "clippy::arithmetic_side_effects"), #[clippy::version = ""] + ("clippy::into_iter_on_array", "array_into_iter"), + #[clippy::version = ""] + ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"), + #[clippy::version = "CURRENT_RUSTC_VERSION"] + ("clippy::invalid_null_ptr_usage", "invalid_null_arguments"), + #[clippy::version = ""] + ("clippy::invalid_ref", "invalid_value"), + #[clippy::version = ""] + ("clippy::invalid_utf8_in_unchecked", "invalid_from_utf8_unchecked"), + #[clippy::version = ""] + ("clippy::let_underscore_drop", "let_underscore_drop"), + #[clippy::version = ""] ("clippy::logic_bug", "clippy::overly_complex_bool_expr"), + #[clippy::version = "1.80.0"] + ("clippy::maybe_misused_cfg", "unexpected_cfgs"), + #[clippy::version = ""] + ("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"), + #[clippy::version = "1.80.0"] + ("clippy::mismatched_target_os", "unexpected_cfgs"), #[clippy::version = ""] ("clippy::new_without_default_derive", "clippy::new_without_default"), #[clippy::version = ""] @@ -107,6 +151,10 @@ declare_with_version! { RENAMED(RENAMED_VERSION) = [ #[clippy::version = ""] ("clippy::overflow_check_conditional", "clippy::panicking_overflow_checks"), #[clippy::version = ""] + ("clippy::panic_params", "non_fmt_panics"), + #[clippy::version = ""] + ("clippy::positional_named_format_parameters", "named_arguments_used_positionally"), + #[clippy::version = ""] ("clippy::ref_in_deref", "clippy::needless_borrow"), #[clippy::version = ""] ("clippy::result_expect_used", "clippy::expect_used"), @@ -115,67 +163,25 @@ declare_with_version! { RENAMED(RENAMED_VERSION) = [ #[clippy::version = ""] ("clippy::result_unwrap_used", "clippy::unwrap_used"), #[clippy::version = ""] + ("clippy::reverse_range_loop", "clippy::reversed_empty_ranges"), + #[clippy::version = ""] ("clippy::single_char_push_str", "clippy::single_char_add_str"), #[clippy::version = ""] ("clippy::stutter", "clippy::module_name_repetitions"), #[clippy::version = ""] + ("clippy::temporary_cstring_as_ptr", "dangling_pointers_from_temporaries"), + #[clippy::version = ""] ("clippy::thread_local_initializer_can_be_made_const", "clippy::missing_const_for_thread_local"), #[clippy::version = ""] ("clippy::to_string_in_display", "clippy::recursive_format_impl"), - #[clippy::version = ""] - ("clippy::unwrap_or_else_default", "clippy::unwrap_or_default"), - #[clippy::version = ""] - ("clippy::zero_width_space", "clippy::invisible_characters"), - #[clippy::version = ""] - ("clippy::cast_ref_to_mut", "invalid_reference_casting"), - #[clippy::version = ""] - ("clippy::clone_double_ref", "suspicious_double_ref_op"), - #[clippy::version = ""] - ("clippy::cmp_nan", "invalid_nan_comparisons"), - #[clippy::version = "CURRENT_RUSTC_VERSION"] - ("clippy::invalid_null_ptr_usage", "invalid_null_arguments"), - #[clippy::version = "1.86.0"] - ("clippy::double_neg", "double_negations"), - #[clippy::version = ""] - ("clippy::drop_bounds", "drop_bounds"), - #[clippy::version = ""] - ("clippy::drop_copy", "dropping_copy_types"), - #[clippy::version = ""] - ("clippy::drop_ref", "dropping_references"), - #[clippy::version = ""] - ("clippy::fn_null_check", "useless_ptr_null_checks"), - #[clippy::version = ""] - ("clippy::for_loop_over_option", "for_loops_over_fallibles"), - #[clippy::version = ""] - ("clippy::for_loop_over_result", "for_loops_over_fallibles"), - #[clippy::version = ""] - ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"), - #[clippy::version = ""] - ("clippy::forget_copy", "forgetting_copy_types"), - #[clippy::version = ""] - ("clippy::forget_ref", "forgetting_references"), - #[clippy::version = ""] - ("clippy::into_iter_on_array", "array_into_iter"), - #[clippy::version = ""] - ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"), - #[clippy::version = ""] - ("clippy::invalid_ref", "invalid_value"), - #[clippy::version = ""] - ("clippy::invalid_utf8_in_unchecked", "invalid_from_utf8_unchecked"), - #[clippy::version = ""] - ("clippy::let_underscore_drop", "let_underscore_drop"), - #[clippy::version = "1.80.0"] - ("clippy::maybe_misused_cfg", "unexpected_cfgs"), - #[clippy::version = ""] - ("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"), - #[clippy::version = "1.80.0"] - ("clippy::mismatched_target_os", "unexpected_cfgs"), - #[clippy::version = ""] - ("clippy::panic_params", "non_fmt_panics"), - #[clippy::version = ""] - ("clippy::positional_named_format_parameters", "named_arguments_used_positionally"), - #[clippy::version = ""] - ("clippy::temporary_cstring_as_ptr", "dangling_pointers_from_temporaries"), + #[clippy::version = "1.88.0"] + ("clippy::transmute_float_to_int", "unnecessary_transmutes"), + #[clippy::version = "1.88.0"] + ("clippy::transmute_int_to_char", "unnecessary_transmutes"), + #[clippy::version = "1.88.0"] + ("clippy::transmute_int_to_float", "unnecessary_transmutes"), + #[clippy::version = "1.88.0"] + ("clippy::transmute_num_to_bytes", "unnecessary_transmutes"), #[clippy::version = ""] ("clippy::undropped_manually_drops", "undropped_manually_drops"), #[clippy::version = ""] @@ -183,15 +189,9 @@ declare_with_version! { RENAMED(RENAMED_VERSION) = [ #[clippy::version = ""] ("clippy::unused_label", "unused_labels"), #[clippy::version = ""] + ("clippy::unwrap_or_else_default", "clippy::unwrap_or_default"), + #[clippy::version = ""] ("clippy::vtable_address_comparisons", "ambiguous_wide_pointer_comparisons"), #[clippy::version = ""] - ("clippy::reverse_range_loop", "clippy::reversed_empty_ranges"), - #[clippy::version = "1.88.0"] - ("clippy::transmute_int_to_float", "unnecessary_transmutes"), - #[clippy::version = "1.88.0"] - ("clippy::transmute_int_to_char", "unnecessary_transmutes"), - #[clippy::version = "1.88.0"] - ("clippy::transmute_float_to_int", "unnecessary_transmutes"), - #[clippy::version = "1.88.0"] - ("clippy::transmute_num_to_bytes", "unnecessary_transmutes"), + ("clippy::zero_width_space", "clippy::invisible_characters"), ]} diff --git a/tests/ui/deprecated.rs b/tests/ui/deprecated.rs index 2787f6406fe39..6b69bdd29ceac 100644 --- a/tests/ui/deprecated.rs +++ b/tests/ui/deprecated.rs @@ -2,20 +2,20 @@ // Use that command to update this file and do not edit by hand. // Manual edits will be overwritten. -#![warn(clippy::should_assert_eq)] //~ ERROR: lint `clippy::should_assert_eq` +#![warn(clippy::assign_ops)] //~ ERROR: lint `clippy::assign_ops` #![warn(clippy::extend_from_slice)] //~ ERROR: lint `clippy::extend_from_slice` -#![warn(clippy::range_step_by_zero)] //~ ERROR: lint `clippy::range_step_by_zero` -#![warn(clippy::unstable_as_slice)] //~ ERROR: lint `clippy::unstable_as_slice` -#![warn(clippy::unstable_as_mut_slice)] //~ ERROR: lint `clippy::unstable_as_mut_slice` +#![warn(clippy::match_on_vec_items)] //~ ERROR: lint `clippy::match_on_vec_items` #![warn(clippy::misaligned_transmute)] //~ ERROR: lint `clippy::misaligned_transmute` -#![warn(clippy::assign_ops)] //~ ERROR: lint `clippy::assign_ops` +#![warn(clippy::option_map_or_err_ok)] //~ ERROR: lint `clippy::option_map_or_err_ok` +#![warn(clippy::pub_enum_variant_names)] //~ ERROR: lint `clippy::pub_enum_variant_names` +#![warn(clippy::range_step_by_zero)] //~ ERROR: lint `clippy::range_step_by_zero` +#![warn(clippy::regex_macro)] //~ ERROR: lint `clippy::regex_macro` +#![warn(clippy::replace_consts)] //~ ERROR: lint `clippy::replace_consts` +#![warn(clippy::should_assert_eq)] //~ ERROR: lint `clippy::should_assert_eq` #![warn(clippy::unsafe_vector_initialization)] //~ ERROR: lint `clippy::unsafe_vector_initialization` +#![warn(clippy::unstable_as_mut_slice)] //~ ERROR: lint `clippy::unstable_as_mut_slice` +#![warn(clippy::unstable_as_slice)] //~ ERROR: lint `clippy::unstable_as_slice` #![warn(clippy::unused_collect)] //~ ERROR: lint `clippy::unused_collect` -#![warn(clippy::replace_consts)] //~ ERROR: lint `clippy::replace_consts` -#![warn(clippy::regex_macro)] //~ ERROR: lint `clippy::regex_macro` -#![warn(clippy::pub_enum_variant_names)] //~ ERROR: lint `clippy::pub_enum_variant_names` #![warn(clippy::wrong_pub_self_convention)] //~ ERROR: lint `clippy::wrong_pub_self_convention` -#![warn(clippy::option_map_or_err_ok)] //~ ERROR: lint `clippy::option_map_or_err_ok` -#![warn(clippy::match_on_vec_items)] //~ ERROR: lint `clippy::match_on_vec_items` fn main() {} diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr index 604732405c370..07e59d33d608b 100644 --- a/tests/ui/deprecated.stderr +++ b/tests/ui/deprecated.stderr @@ -1,8 +1,8 @@ -error: lint `clippy::should_assert_eq` has been removed: `assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can +error: lint `clippy::assign_ops` has been removed: compound operators are harmless and linting on them is not in scope for clippy --> tests/ui/deprecated.rs:5:9 | -LL | #![warn(clippy::should_assert_eq)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::assign_ops)] + | ^^^^^^^^^^^^^^^^^^ | = note: `-D renamed-and-removed-lints` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]` @@ -13,83 +13,83 @@ error: lint `clippy::extend_from_slice` has been removed: `Vec::extend_from_slic LL | #![warn(clippy::extend_from_slice)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::range_step_by_zero` has been removed: `Iterator::step_by(0)` now panics and is no longer an infinite iterator +error: lint `clippy::match_on_vec_items` has been removed: `clippy::indexing_slicing` covers indexing and slicing on `Vec<_>` --> tests/ui/deprecated.rs:7:9 | -LL | #![warn(clippy::range_step_by_zero)] +LL | #![warn(clippy::match_on_vec_items)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` is now stable +error: lint `clippy::misaligned_transmute` has been removed: split into `clippy::cast_ptr_alignment` and `clippy::transmute_ptr_to_ptr` --> tests/ui/deprecated.rs:8:9 | -LL | #![warn(clippy::unstable_as_slice)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::misaligned_transmute)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` is now stable +error: lint `clippy::option_map_or_err_ok` has been removed: `clippy::manual_ok_or` covers this case --> tests/ui/deprecated.rs:9:9 | -LL | #![warn(clippy::unstable_as_mut_slice)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::option_map_or_err_ok)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::misaligned_transmute` has been removed: split into `clippy::cast_ptr_alignment` and `clippy::transmute_ptr_to_ptr` +error: lint `clippy::pub_enum_variant_names` has been removed: `clippy::enum_variant_names` now covers this case via the `avoid-breaking-exported-api` config --> tests/ui/deprecated.rs:10:9 | -LL | #![warn(clippy::misaligned_transmute)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::pub_enum_variant_names)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::assign_ops` has been removed: compound operators are harmless and linting on them is not in scope for clippy +error: lint `clippy::range_step_by_zero` has been removed: `Iterator::step_by(0)` now panics and is no longer an infinite iterator --> tests/ui/deprecated.rs:11:9 | -LL | #![warn(clippy::assign_ops)] - | ^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::range_step_by_zero)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::unsafe_vector_initialization` has been removed: the suggested alternative could be substantially slower +error: lint `clippy::regex_macro` has been removed: the `regex!` macro was removed from the regex crate in 2018 --> tests/ui/deprecated.rs:12:9 | -LL | #![warn(clippy::unsafe_vector_initialization)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::regex_macro)] + | ^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::unused_collect` has been removed: `Iterator::collect` is now marked as `#[must_use]` +error: lint `clippy::replace_consts` has been removed: `min_value` and `max_value` are now deprecated --> tests/ui/deprecated.rs:13:9 | -LL | #![warn(clippy::unused_collect)] +LL | #![warn(clippy::replace_consts)] | ^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::replace_consts` has been removed: `min_value` and `max_value` are now deprecated +error: lint `clippy::should_assert_eq` has been removed: `assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can --> tests/ui/deprecated.rs:14:9 | -LL | #![warn(clippy::replace_consts)] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::should_assert_eq)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::regex_macro` has been removed: the `regex!` macro was removed from the regex crate in 2018 +error: lint `clippy::unsafe_vector_initialization` has been removed: the suggested alternative could be substantially slower --> tests/ui/deprecated.rs:15:9 | -LL | #![warn(clippy::regex_macro)] - | ^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::unsafe_vector_initialization)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::pub_enum_variant_names` has been removed: `clippy::enum_variant_names` now covers this case via the `avoid-breaking-exported-api` config +error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` is now stable --> tests/ui/deprecated.rs:16:9 | -LL | #![warn(clippy::pub_enum_variant_names)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::unstable_as_mut_slice)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::wrong_pub_self_convention` has been removed: `clippy::wrong_self_convention` now covers this case via the `avoid-breaking-exported-api` config +error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` is now stable --> tests/ui/deprecated.rs:17:9 | -LL | #![warn(clippy::wrong_pub_self_convention)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::unstable_as_slice)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::option_map_or_err_ok` has been removed: `clippy::manual_ok_or` covers this case +error: lint `clippy::unused_collect` has been removed: `Iterator::collect` is now marked as `#[must_use]` --> tests/ui/deprecated.rs:18:9 | -LL | #![warn(clippy::option_map_or_err_ok)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::unused_collect)] + | ^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::match_on_vec_items` has been removed: `clippy::indexing_slicing` covers indexing and slicing on `Vec<_>` +error: lint `clippy::wrong_pub_self_convention` has been removed: `clippy::wrong_self_convention` now covers this case via the `avoid-breaking-exported-api` config --> tests/ui/deprecated.rs:19:9 | -LL | #![warn(clippy::match_on_vec_items)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::wrong_pub_self_convention)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 15 previous errors diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index 55e287b91596d..ff81c64260274 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -7,85 +7,107 @@ #![allow(clippy::disallowed_names)] #![allow(clippy::blocks_in_conditions)] #![allow(clippy::box_collection)] +#![allow(invalid_reference_casting)] +#![allow(suspicious_double_ref_op)] +#![allow(invalid_nan_comparisons)] #![allow(clippy::redundant_static_lifetimes)] #![allow(clippy::cognitive_complexity)] #![allow(clippy::derived_hash_with_manual_eq)] #![allow(clippy::disallowed_methods)] #![allow(clippy::disallowed_types)] +#![allow(double_negations)] +#![allow(drop_bounds)] +#![allow(dropping_copy_types)] +#![allow(dropping_references)] #![allow(clippy::mixed_read_write_in_expression)] -#![allow(clippy::manual_find_map)] #![allow(clippy::manual_filter_map)] +#![allow(clippy::manual_find_map)] #![allow(unpredictable_function_pointer_comparisons)] +#![allow(useless_ptr_null_checks)] +#![allow(for_loops_over_fallibles)] +#![allow(forgetting_copy_types)] +#![allow(forgetting_references)] #![allow(clippy::useless_conversion)] #![allow(clippy::redundant_pattern_matching)] #![allow(clippy::match_result_ok)] #![allow(clippy::non_canonical_clone_impl)] #![allow(clippy::non_canonical_partial_ord_impl)] #![allow(clippy::arithmetic_side_effects)] +#![allow(array_into_iter)] +#![allow(invalid_atomic_ordering)] +#![allow(invalid_null_arguments)] +#![allow(invalid_value)] +#![allow(invalid_from_utf8_unchecked)] +#![allow(let_underscore_drop)] #![allow(clippy::overly_complex_bool_expr)] +#![allow(unexpected_cfgs)] +#![allow(enum_intrinsics_non_enums)] #![allow(clippy::new_without_default)] #![allow(clippy::bind_instead_of_map)] #![allow(clippy::expect_used)] #![allow(clippy::map_unwrap_or)] #![allow(clippy::unwrap_used)] #![allow(clippy::panicking_overflow_checks)] +#![allow(non_fmt_panics)] +#![allow(named_arguments_used_positionally)] #![allow(clippy::needless_borrow)] +#![allow(clippy::reversed_empty_ranges)] #![allow(clippy::single_char_add_str)] #![allow(clippy::module_name_repetitions)] +#![allow(dangling_pointers_from_temporaries)] #![allow(clippy::missing_const_for_thread_local)] #![allow(clippy::recursive_format_impl)] -#![allow(clippy::unwrap_or_default)] -#![allow(clippy::invisible_characters)] -#![allow(invalid_reference_casting)] -#![allow(suspicious_double_ref_op)] -#![allow(invalid_nan_comparisons)] -#![allow(invalid_null_arguments)] -#![allow(double_negations)] -#![allow(drop_bounds)] -#![allow(dropping_copy_types)] -#![allow(dropping_references)] -#![allow(useless_ptr_null_checks)] -#![allow(for_loops_over_fallibles)] -#![allow(forgetting_copy_types)] -#![allow(forgetting_references)] -#![allow(array_into_iter)] -#![allow(invalid_atomic_ordering)] -#![allow(invalid_value)] -#![allow(invalid_from_utf8_unchecked)] -#![allow(let_underscore_drop)] -#![allow(unexpected_cfgs)] -#![allow(enum_intrinsics_non_enums)] -#![allow(non_fmt_panics)] -#![allow(named_arguments_used_positionally)] -#![allow(dangling_pointers_from_temporaries)] +#![allow(unnecessary_transmutes)] #![allow(undropped_manually_drops)] #![allow(unknown_lints)] #![allow(unused_labels)] +#![allow(clippy::unwrap_or_default)] #![allow(ambiguous_wide_pointer_comparisons)] -#![allow(clippy::reversed_empty_ranges)] -#![allow(unnecessary_transmutes)] +#![allow(clippy::invisible_characters)] #![warn(clippy::almost_complete_range)] //~ ERROR: lint `clippy::almost_complete_letter_range` #![warn(clippy::disallowed_names)] //~ ERROR: lint `clippy::blacklisted_name` #![warn(clippy::blocks_in_conditions)] //~ ERROR: lint `clippy::block_in_if_condition_expr` #![warn(clippy::blocks_in_conditions)] //~ ERROR: lint `clippy::block_in_if_condition_stmt` #![warn(clippy::blocks_in_conditions)] //~ ERROR: lint `clippy::blocks_in_if_conditions` #![warn(clippy::box_collection)] //~ ERROR: lint `clippy::box_vec` +#![warn(invalid_reference_casting)] //~ ERROR: lint `clippy::cast_ref_to_mut` +#![warn(suspicious_double_ref_op)] //~ ERROR: lint `clippy::clone_double_ref` +#![warn(invalid_nan_comparisons)] //~ ERROR: lint `clippy::cmp_nan` #![warn(clippy::redundant_static_lifetimes)] //~ ERROR: lint `clippy::const_static_lifetime` #![warn(clippy::cognitive_complexity)] //~ ERROR: lint `clippy::cyclomatic_complexity` #![warn(clippy::derived_hash_with_manual_eq)] //~ ERROR: lint `clippy::derive_hash_xor_eq` #![warn(clippy::disallowed_methods)] //~ ERROR: lint `clippy::disallowed_method` #![warn(clippy::disallowed_types)] //~ ERROR: lint `clippy::disallowed_type` +#![warn(double_negations)] //~ ERROR: lint `clippy::double_neg` +#![warn(drop_bounds)] //~ ERROR: lint `clippy::drop_bounds` +#![warn(dropping_copy_types)] //~ ERROR: lint `clippy::drop_copy` +#![warn(dropping_references)] //~ ERROR: lint `clippy::drop_ref` #![warn(clippy::mixed_read_write_in_expression)] //~ ERROR: lint `clippy::eval_order_dependence` -#![warn(clippy::manual_find_map)] //~ ERROR: lint `clippy::find_map` #![warn(clippy::manual_filter_map)] //~ ERROR: lint `clippy::filter_map` +#![warn(clippy::manual_find_map)] //~ ERROR: lint `clippy::find_map` #![warn(unpredictable_function_pointer_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons` +#![warn(useless_ptr_null_checks)] //~ ERROR: lint `clippy::fn_null_check` +#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_option` +#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_result` +#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loops_over_fallibles` +#![warn(forgetting_copy_types)] //~ ERROR: lint `clippy::forget_copy` +#![warn(forgetting_references)] //~ ERROR: lint `clippy::forget_ref` #![warn(clippy::useless_conversion)] //~ ERROR: lint `clippy::identity_conversion` #![warn(clippy::redundant_pattern_matching)] //~ ERROR: lint `clippy::if_let_redundant_pattern_matching` #![warn(clippy::match_result_ok)] //~ ERROR: lint `clippy::if_let_some_result` #![warn(clippy::non_canonical_clone_impl)] //~ ERROR: lint `clippy::incorrect_clone_impl_on_copy_type` #![warn(clippy::non_canonical_partial_ord_impl)] //~ ERROR: lint `clippy::incorrect_partial_ord_impl_on_ord_type` #![warn(clippy::arithmetic_side_effects)] //~ ERROR: lint `clippy::integer_arithmetic` +#![warn(array_into_iter)] //~ ERROR: lint `clippy::into_iter_on_array` +#![warn(invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering` +#![warn(invalid_null_arguments)] //~ ERROR: lint `clippy::invalid_null_ptr_usage` +#![warn(invalid_value)] //~ ERROR: lint `clippy::invalid_ref` +#![warn(invalid_from_utf8_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked` +#![warn(let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop` #![warn(clippy::overly_complex_bool_expr)] //~ ERROR: lint `clippy::logic_bug` +#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::maybe_misused_cfg` +#![warn(enum_intrinsics_non_enums)] //~ ERROR: lint `clippy::mem_discriminant_non_enum` +#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::mismatched_target_os` #![warn(clippy::new_without_default)] //~ ERROR: lint `clippy::new_without_default_derive` #![warn(clippy::bind_instead_of_map)] //~ ERROR: lint `clippy::option_and_then_some` #![warn(clippy::expect_used)] //~ ERROR: lint `clippy::option_expect_used` @@ -93,49 +115,27 @@ #![warn(clippy::map_unwrap_or)] //~ ERROR: lint `clippy::option_map_unwrap_or_else` #![warn(clippy::unwrap_used)] //~ ERROR: lint `clippy::option_unwrap_used` #![warn(clippy::panicking_overflow_checks)] //~ ERROR: lint `clippy::overflow_check_conditional` +#![warn(non_fmt_panics)] //~ ERROR: lint `clippy::panic_params` +#![warn(named_arguments_used_positionally)] //~ ERROR: lint `clippy::positional_named_format_parameters` #![warn(clippy::needless_borrow)] //~ ERROR: lint `clippy::ref_in_deref` #![warn(clippy::expect_used)] //~ ERROR: lint `clippy::result_expect_used` #![warn(clippy::map_unwrap_or)] //~ ERROR: lint `clippy::result_map_unwrap_or_else` #![warn(clippy::unwrap_used)] //~ ERROR: lint `clippy::result_unwrap_used` +#![warn(clippy::reversed_empty_ranges)] //~ ERROR: lint `clippy::reverse_range_loop` #![warn(clippy::single_char_add_str)] //~ ERROR: lint `clippy::single_char_push_str` #![warn(clippy::module_name_repetitions)] //~ ERROR: lint `clippy::stutter` +#![warn(dangling_pointers_from_temporaries)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr` #![warn(clippy::missing_const_for_thread_local)] //~ ERROR: lint `clippy::thread_local_initializer_can_be_made_const` #![warn(clippy::recursive_format_impl)] //~ ERROR: lint `clippy::to_string_in_display` -#![warn(clippy::unwrap_or_default)] //~ ERROR: lint `clippy::unwrap_or_else_default` -#![warn(clippy::invisible_characters)] //~ ERROR: lint `clippy::zero_width_space` -#![warn(invalid_reference_casting)] //~ ERROR: lint `clippy::cast_ref_to_mut` -#![warn(suspicious_double_ref_op)] //~ ERROR: lint `clippy::clone_double_ref` -#![warn(invalid_nan_comparisons)] //~ ERROR: lint `clippy::cmp_nan` -#![warn(invalid_null_arguments)] //~ ERROR: lint `clippy::invalid_null_ptr_usage` -#![warn(double_negations)] //~ ERROR: lint `clippy::double_neg` -#![warn(drop_bounds)] //~ ERROR: lint `clippy::drop_bounds` -#![warn(dropping_copy_types)] //~ ERROR: lint `clippy::drop_copy` -#![warn(dropping_references)] //~ ERROR: lint `clippy::drop_ref` -#![warn(useless_ptr_null_checks)] //~ ERROR: lint `clippy::fn_null_check` -#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_option` -#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_result` -#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loops_over_fallibles` -#![warn(forgetting_copy_types)] //~ ERROR: lint `clippy::forget_copy` -#![warn(forgetting_references)] //~ ERROR: lint `clippy::forget_ref` -#![warn(array_into_iter)] //~ ERROR: lint `clippy::into_iter_on_array` -#![warn(invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering` -#![warn(invalid_value)] //~ ERROR: lint `clippy::invalid_ref` -#![warn(invalid_from_utf8_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked` -#![warn(let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop` -#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::maybe_misused_cfg` -#![warn(enum_intrinsics_non_enums)] //~ ERROR: lint `clippy::mem_discriminant_non_enum` -#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::mismatched_target_os` -#![warn(non_fmt_panics)] //~ ERROR: lint `clippy::panic_params` -#![warn(named_arguments_used_positionally)] //~ ERROR: lint `clippy::positional_named_format_parameters` -#![warn(dangling_pointers_from_temporaries)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr` +#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_float_to_int` +#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_int_to_char` +#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_int_to_float` +#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_num_to_bytes` #![warn(undropped_manually_drops)] //~ ERROR: lint `clippy::undropped_manually_drops` #![warn(unknown_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints` #![warn(unused_labels)] //~ ERROR: lint `clippy::unused_label` +#![warn(clippy::unwrap_or_default)] //~ ERROR: lint `clippy::unwrap_or_else_default` #![warn(ambiguous_wide_pointer_comparisons)] //~ ERROR: lint `clippy::vtable_address_comparisons` -#![warn(clippy::reversed_empty_ranges)] //~ ERROR: lint `clippy::reverse_range_loop` -#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_int_to_float` -#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_int_to_char` -#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_float_to_int` -#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_num_to_bytes` +#![warn(clippy::invisible_characters)] //~ ERROR: lint `clippy::zero_width_space` fn main() {} diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index 31dcd2cea0818..b5d5d07e639a0 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -7,85 +7,107 @@ #![allow(clippy::disallowed_names)] #![allow(clippy::blocks_in_conditions)] #![allow(clippy::box_collection)] +#![allow(invalid_reference_casting)] +#![allow(suspicious_double_ref_op)] +#![allow(invalid_nan_comparisons)] #![allow(clippy::redundant_static_lifetimes)] #![allow(clippy::cognitive_complexity)] #![allow(clippy::derived_hash_with_manual_eq)] #![allow(clippy::disallowed_methods)] #![allow(clippy::disallowed_types)] +#![allow(double_negations)] +#![allow(drop_bounds)] +#![allow(dropping_copy_types)] +#![allow(dropping_references)] #![allow(clippy::mixed_read_write_in_expression)] -#![allow(clippy::manual_find_map)] #![allow(clippy::manual_filter_map)] +#![allow(clippy::manual_find_map)] #![allow(unpredictable_function_pointer_comparisons)] +#![allow(useless_ptr_null_checks)] +#![allow(for_loops_over_fallibles)] +#![allow(forgetting_copy_types)] +#![allow(forgetting_references)] #![allow(clippy::useless_conversion)] #![allow(clippy::redundant_pattern_matching)] #![allow(clippy::match_result_ok)] #![allow(clippy::non_canonical_clone_impl)] #![allow(clippy::non_canonical_partial_ord_impl)] #![allow(clippy::arithmetic_side_effects)] +#![allow(array_into_iter)] +#![allow(invalid_atomic_ordering)] +#![allow(invalid_null_arguments)] +#![allow(invalid_value)] +#![allow(invalid_from_utf8_unchecked)] +#![allow(let_underscore_drop)] #![allow(clippy::overly_complex_bool_expr)] +#![allow(unexpected_cfgs)] +#![allow(enum_intrinsics_non_enums)] #![allow(clippy::new_without_default)] #![allow(clippy::bind_instead_of_map)] #![allow(clippy::expect_used)] #![allow(clippy::map_unwrap_or)] #![allow(clippy::unwrap_used)] #![allow(clippy::panicking_overflow_checks)] +#![allow(non_fmt_panics)] +#![allow(named_arguments_used_positionally)] #![allow(clippy::needless_borrow)] +#![allow(clippy::reversed_empty_ranges)] #![allow(clippy::single_char_add_str)] #![allow(clippy::module_name_repetitions)] +#![allow(dangling_pointers_from_temporaries)] #![allow(clippy::missing_const_for_thread_local)] #![allow(clippy::recursive_format_impl)] -#![allow(clippy::unwrap_or_default)] -#![allow(clippy::invisible_characters)] -#![allow(invalid_reference_casting)] -#![allow(suspicious_double_ref_op)] -#![allow(invalid_nan_comparisons)] -#![allow(invalid_null_arguments)] -#![allow(double_negations)] -#![allow(drop_bounds)] -#![allow(dropping_copy_types)] -#![allow(dropping_references)] -#![allow(useless_ptr_null_checks)] -#![allow(for_loops_over_fallibles)] -#![allow(forgetting_copy_types)] -#![allow(forgetting_references)] -#![allow(array_into_iter)] -#![allow(invalid_atomic_ordering)] -#![allow(invalid_value)] -#![allow(invalid_from_utf8_unchecked)] -#![allow(let_underscore_drop)] -#![allow(unexpected_cfgs)] -#![allow(enum_intrinsics_non_enums)] -#![allow(non_fmt_panics)] -#![allow(named_arguments_used_positionally)] -#![allow(dangling_pointers_from_temporaries)] +#![allow(unnecessary_transmutes)] #![allow(undropped_manually_drops)] #![allow(unknown_lints)] #![allow(unused_labels)] +#![allow(clippy::unwrap_or_default)] #![allow(ambiguous_wide_pointer_comparisons)] -#![allow(clippy::reversed_empty_ranges)] -#![allow(unnecessary_transmutes)] +#![allow(clippy::invisible_characters)] #![warn(clippy::almost_complete_letter_range)] //~ ERROR: lint `clippy::almost_complete_letter_range` #![warn(clippy::blacklisted_name)] //~ ERROR: lint `clippy::blacklisted_name` #![warn(clippy::block_in_if_condition_expr)] //~ ERROR: lint `clippy::block_in_if_condition_expr` #![warn(clippy::block_in_if_condition_stmt)] //~ ERROR: lint `clippy::block_in_if_condition_stmt` #![warn(clippy::blocks_in_if_conditions)] //~ ERROR: lint `clippy::blocks_in_if_conditions` #![warn(clippy::box_vec)] //~ ERROR: lint `clippy::box_vec` +#![warn(clippy::cast_ref_to_mut)] //~ ERROR: lint `clippy::cast_ref_to_mut` +#![warn(clippy::clone_double_ref)] //~ ERROR: lint `clippy::clone_double_ref` +#![warn(clippy::cmp_nan)] //~ ERROR: lint `clippy::cmp_nan` #![warn(clippy::const_static_lifetime)] //~ ERROR: lint `clippy::const_static_lifetime` #![warn(clippy::cyclomatic_complexity)] //~ ERROR: lint `clippy::cyclomatic_complexity` #![warn(clippy::derive_hash_xor_eq)] //~ ERROR: lint `clippy::derive_hash_xor_eq` #![warn(clippy::disallowed_method)] //~ ERROR: lint `clippy::disallowed_method` #![warn(clippy::disallowed_type)] //~ ERROR: lint `clippy::disallowed_type` +#![warn(clippy::double_neg)] //~ ERROR: lint `clippy::double_neg` +#![warn(clippy::drop_bounds)] //~ ERROR: lint `clippy::drop_bounds` +#![warn(clippy::drop_copy)] //~ ERROR: lint `clippy::drop_copy` +#![warn(clippy::drop_ref)] //~ ERROR: lint `clippy::drop_ref` #![warn(clippy::eval_order_dependence)] //~ ERROR: lint `clippy::eval_order_dependence` -#![warn(clippy::find_map)] //~ ERROR: lint `clippy::find_map` #![warn(clippy::filter_map)] //~ ERROR: lint `clippy::filter_map` +#![warn(clippy::find_map)] //~ ERROR: lint `clippy::find_map` #![warn(clippy::fn_address_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons` +#![warn(clippy::fn_null_check)] //~ ERROR: lint `clippy::fn_null_check` +#![warn(clippy::for_loop_over_option)] //~ ERROR: lint `clippy::for_loop_over_option` +#![warn(clippy::for_loop_over_result)] //~ ERROR: lint `clippy::for_loop_over_result` +#![warn(clippy::for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loops_over_fallibles` +#![warn(clippy::forget_copy)] //~ ERROR: lint `clippy::forget_copy` +#![warn(clippy::forget_ref)] //~ ERROR: lint `clippy::forget_ref` #![warn(clippy::identity_conversion)] //~ ERROR: lint `clippy::identity_conversion` #![warn(clippy::if_let_redundant_pattern_matching)] //~ ERROR: lint `clippy::if_let_redundant_pattern_matching` #![warn(clippy::if_let_some_result)] //~ ERROR: lint `clippy::if_let_some_result` #![warn(clippy::incorrect_clone_impl_on_copy_type)] //~ ERROR: lint `clippy::incorrect_clone_impl_on_copy_type` #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)] //~ ERROR: lint `clippy::incorrect_partial_ord_impl_on_ord_type` #![warn(clippy::integer_arithmetic)] //~ ERROR: lint `clippy::integer_arithmetic` +#![warn(clippy::into_iter_on_array)] //~ ERROR: lint `clippy::into_iter_on_array` +#![warn(clippy::invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering` +#![warn(clippy::invalid_null_ptr_usage)] //~ ERROR: lint `clippy::invalid_null_ptr_usage` +#![warn(clippy::invalid_ref)] //~ ERROR: lint `clippy::invalid_ref` +#![warn(clippy::invalid_utf8_in_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked` +#![warn(clippy::let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop` #![warn(clippy::logic_bug)] //~ ERROR: lint `clippy::logic_bug` +#![warn(clippy::maybe_misused_cfg)] //~ ERROR: lint `clippy::maybe_misused_cfg` +#![warn(clippy::mem_discriminant_non_enum)] //~ ERROR: lint `clippy::mem_discriminant_non_enum` +#![warn(clippy::mismatched_target_os)] //~ ERROR: lint `clippy::mismatched_target_os` #![warn(clippy::new_without_default_derive)] //~ ERROR: lint `clippy::new_without_default_derive` #![warn(clippy::option_and_then_some)] //~ ERROR: lint `clippy::option_and_then_some` #![warn(clippy::option_expect_used)] //~ ERROR: lint `clippy::option_expect_used` @@ -93,49 +115,27 @@ #![warn(clippy::option_map_unwrap_or_else)] //~ ERROR: lint `clippy::option_map_unwrap_or_else` #![warn(clippy::option_unwrap_used)] //~ ERROR: lint `clippy::option_unwrap_used` #![warn(clippy::overflow_check_conditional)] //~ ERROR: lint `clippy::overflow_check_conditional` +#![warn(clippy::panic_params)] //~ ERROR: lint `clippy::panic_params` +#![warn(clippy::positional_named_format_parameters)] //~ ERROR: lint `clippy::positional_named_format_parameters` #![warn(clippy::ref_in_deref)] //~ ERROR: lint `clippy::ref_in_deref` #![warn(clippy::result_expect_used)] //~ ERROR: lint `clippy::result_expect_used` #![warn(clippy::result_map_unwrap_or_else)] //~ ERROR: lint `clippy::result_map_unwrap_or_else` #![warn(clippy::result_unwrap_used)] //~ ERROR: lint `clippy::result_unwrap_used` +#![warn(clippy::reverse_range_loop)] //~ ERROR: lint `clippy::reverse_range_loop` #![warn(clippy::single_char_push_str)] //~ ERROR: lint `clippy::single_char_push_str` #![warn(clippy::stutter)] //~ ERROR: lint `clippy::stutter` +#![warn(clippy::temporary_cstring_as_ptr)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr` #![warn(clippy::thread_local_initializer_can_be_made_const)] //~ ERROR: lint `clippy::thread_local_initializer_can_be_made_const` #![warn(clippy::to_string_in_display)] //~ ERROR: lint `clippy::to_string_in_display` -#![warn(clippy::unwrap_or_else_default)] //~ ERROR: lint `clippy::unwrap_or_else_default` -#![warn(clippy::zero_width_space)] //~ ERROR: lint `clippy::zero_width_space` -#![warn(clippy::cast_ref_to_mut)] //~ ERROR: lint `clippy::cast_ref_to_mut` -#![warn(clippy::clone_double_ref)] //~ ERROR: lint `clippy::clone_double_ref` -#![warn(clippy::cmp_nan)] //~ ERROR: lint `clippy::cmp_nan` -#![warn(clippy::invalid_null_ptr_usage)] //~ ERROR: lint `clippy::invalid_null_ptr_usage` -#![warn(clippy::double_neg)] //~ ERROR: lint `clippy::double_neg` -#![warn(clippy::drop_bounds)] //~ ERROR: lint `clippy::drop_bounds` -#![warn(clippy::drop_copy)] //~ ERROR: lint `clippy::drop_copy` -#![warn(clippy::drop_ref)] //~ ERROR: lint `clippy::drop_ref` -#![warn(clippy::fn_null_check)] //~ ERROR: lint `clippy::fn_null_check` -#![warn(clippy::for_loop_over_option)] //~ ERROR: lint `clippy::for_loop_over_option` -#![warn(clippy::for_loop_over_result)] //~ ERROR: lint `clippy::for_loop_over_result` -#![warn(clippy::for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loops_over_fallibles` -#![warn(clippy::forget_copy)] //~ ERROR: lint `clippy::forget_copy` -#![warn(clippy::forget_ref)] //~ ERROR: lint `clippy::forget_ref` -#![warn(clippy::into_iter_on_array)] //~ ERROR: lint `clippy::into_iter_on_array` -#![warn(clippy::invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering` -#![warn(clippy::invalid_ref)] //~ ERROR: lint `clippy::invalid_ref` -#![warn(clippy::invalid_utf8_in_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked` -#![warn(clippy::let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop` -#![warn(clippy::maybe_misused_cfg)] //~ ERROR: lint `clippy::maybe_misused_cfg` -#![warn(clippy::mem_discriminant_non_enum)] //~ ERROR: lint `clippy::mem_discriminant_non_enum` -#![warn(clippy::mismatched_target_os)] //~ ERROR: lint `clippy::mismatched_target_os` -#![warn(clippy::panic_params)] //~ ERROR: lint `clippy::panic_params` -#![warn(clippy::positional_named_format_parameters)] //~ ERROR: lint `clippy::positional_named_format_parameters` -#![warn(clippy::temporary_cstring_as_ptr)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr` +#![warn(clippy::transmute_float_to_int)] //~ ERROR: lint `clippy::transmute_float_to_int` +#![warn(clippy::transmute_int_to_char)] //~ ERROR: lint `clippy::transmute_int_to_char` +#![warn(clippy::transmute_int_to_float)] //~ ERROR: lint `clippy::transmute_int_to_float` +#![warn(clippy::transmute_num_to_bytes)] //~ ERROR: lint `clippy::transmute_num_to_bytes` #![warn(clippy::undropped_manually_drops)] //~ ERROR: lint `clippy::undropped_manually_drops` #![warn(clippy::unknown_clippy_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints` #![warn(clippy::unused_label)] //~ ERROR: lint `clippy::unused_label` +#![warn(clippy::unwrap_or_else_default)] //~ ERROR: lint `clippy::unwrap_or_else_default` #![warn(clippy::vtable_address_comparisons)] //~ ERROR: lint `clippy::vtable_address_comparisons` -#![warn(clippy::reverse_range_loop)] //~ ERROR: lint `clippy::reverse_range_loop` -#![warn(clippy::transmute_int_to_float)] //~ ERROR: lint `clippy::transmute_int_to_float` -#![warn(clippy::transmute_int_to_char)] //~ ERROR: lint `clippy::transmute_int_to_char` -#![warn(clippy::transmute_float_to_int)] //~ ERROR: lint `clippy::transmute_float_to_int` -#![warn(clippy::transmute_num_to_bytes)] //~ ERROR: lint `clippy::transmute_num_to_bytes` +#![warn(clippy::zero_width_space)] //~ ERROR: lint `clippy::zero_width_space` fn main() {} diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index a8d5c96acc3a7..2487dfc8eba44 100644 --- a/tests/ui/rename.stderr +++ b/tests/ui/rename.stderr @@ -37,407 +37,407 @@ error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` -error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` +error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting` --> tests/ui/rename.rs:73:9 | +LL | #![warn(clippy::cast_ref_to_mut)] + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting` + +error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op` + --> tests/ui/rename.rs:74:9 + | +LL | #![warn(clippy::clone_double_ref)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op` + +error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons` + --> tests/ui/rename.rs:75:9 + | +LL | #![warn(clippy::cmp_nan)] + | ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons` + +error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` + --> tests/ui/rename.rs:76:9 + | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> tests/ui/rename.rs:74:9 + --> tests/ui/rename.rs:77:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq` - --> tests/ui/rename.rs:75:9 + --> tests/ui/rename.rs:78:9 | LL | #![warn(clippy::derive_hash_xor_eq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> tests/ui/rename.rs:76:9 + --> tests/ui/rename.rs:79:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> tests/ui/rename.rs:77:9 + --> tests/ui/rename.rs:80:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` -error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> tests/ui/rename.rs:78:9 - | -LL | #![warn(clippy::eval_order_dependence)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` - -error: lint `clippy::find_map` has been renamed to `clippy::manual_find_map` - --> tests/ui/rename.rs:79:9 - | -LL | #![warn(clippy::find_map)] - | ^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_find_map` - -error: lint `clippy::filter_map` has been renamed to `clippy::manual_filter_map` - --> tests/ui/rename.rs:80:9 - | -LL | #![warn(clippy::filter_map)] - | ^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_filter_map` - -error: lint `clippy::fn_address_comparisons` has been renamed to `unpredictable_function_pointer_comparisons` +error: lint `clippy::double_neg` has been renamed to `double_negations` --> tests/ui/rename.rs:81:9 | -LL | #![warn(clippy::fn_address_comparisons)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unpredictable_function_pointer_comparisons` +LL | #![warn(clippy::double_neg)] + | ^^^^^^^^^^^^^^^^^^ help: use the new name: `double_negations` -error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` +error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` --> tests/ui/rename.rs:82:9 | -LL | #![warn(clippy::identity_conversion)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` +LL | #![warn(clippy::drop_bounds)] + | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` -error: lint `clippy::if_let_redundant_pattern_matching` has been renamed to `clippy::redundant_pattern_matching` +error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types` --> tests/ui/rename.rs:83:9 | -LL | #![warn(clippy::if_let_redundant_pattern_matching)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_pattern_matching` +LL | #![warn(clippy::drop_copy)] + | ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types` -error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` +error: lint `clippy::drop_ref` has been renamed to `dropping_references` --> tests/ui/rename.rs:84:9 | -LL | #![warn(clippy::if_let_some_result)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` +LL | #![warn(clippy::drop_ref)] + | ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references` -error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl` +error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` --> tests/ui/rename.rs:85:9 | -LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl` +LL | #![warn(clippy::eval_order_dependence)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` -error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl` +error: lint `clippy::filter_map` has been renamed to `clippy::manual_filter_map` --> tests/ui/rename.rs:86:9 | -LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl` +LL | #![warn(clippy::filter_map)] + | ^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_filter_map` -error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects` +error: lint `clippy::find_map` has been renamed to `clippy::manual_find_map` --> tests/ui/rename.rs:87:9 | -LL | #![warn(clippy::integer_arithmetic)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects` +LL | #![warn(clippy::find_map)] + | ^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_find_map` -error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` +error: lint `clippy::fn_address_comparisons` has been renamed to `unpredictable_function_pointer_comparisons` --> tests/ui/rename.rs:88:9 | -LL | #![warn(clippy::logic_bug)] - | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` +LL | #![warn(clippy::fn_address_comparisons)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unpredictable_function_pointer_comparisons` -error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` +error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks` --> tests/ui/rename.rs:89:9 | -LL | #![warn(clippy::new_without_default_derive)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` +LL | #![warn(clippy::fn_null_check)] + | ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks` -error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` +error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` --> tests/ui/rename.rs:90:9 | -LL | #![warn(clippy::option_and_then_some)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` +LL | #![warn(clippy::for_loop_over_option)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` -error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` +error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` --> tests/ui/rename.rs:91:9 | -LL | #![warn(clippy::option_expect_used)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` +LL | #![warn(clippy::for_loop_over_result)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` -error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` +error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` --> tests/ui/rename.rs:92:9 | -LL | #![warn(clippy::option_map_unwrap_or)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` +LL | #![warn(clippy::for_loops_over_fallibles)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` -error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` +error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types` --> tests/ui/rename.rs:93:9 | -LL | #![warn(clippy::option_map_unwrap_or_else)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` +LL | #![warn(clippy::forget_copy)] + | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types` -error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` +error: lint `clippy::forget_ref` has been renamed to `forgetting_references` --> tests/ui/rename.rs:94:9 | -LL | #![warn(clippy::option_unwrap_used)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` +LL | #![warn(clippy::forget_ref)] + | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references` -error: lint `clippy::overflow_check_conditional` has been renamed to `clippy::panicking_overflow_checks` +error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` --> tests/ui/rename.rs:95:9 | -LL | #![warn(clippy::overflow_check_conditional)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::panicking_overflow_checks` +LL | #![warn(clippy::identity_conversion)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` -error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` +error: lint `clippy::if_let_redundant_pattern_matching` has been renamed to `clippy::redundant_pattern_matching` --> tests/ui/rename.rs:96:9 | -LL | #![warn(clippy::ref_in_deref)] - | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` +LL | #![warn(clippy::if_let_redundant_pattern_matching)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_pattern_matching` -error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` +error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` --> tests/ui/rename.rs:97:9 | -LL | #![warn(clippy::result_expect_used)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` +LL | #![warn(clippy::if_let_some_result)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` -error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` +error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl` --> tests/ui/rename.rs:98:9 | -LL | #![warn(clippy::result_map_unwrap_or_else)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` +LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl` -error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` +error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl` --> tests/ui/rename.rs:99:9 | -LL | #![warn(clippy::result_unwrap_used)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` +LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl` -error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` +error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects` --> tests/ui/rename.rs:100:9 | -LL | #![warn(clippy::single_char_push_str)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` +LL | #![warn(clippy::integer_arithmetic)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects` -error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` +error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` --> tests/ui/rename.rs:101:9 | -LL | #![warn(clippy::stutter)] - | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` +LL | #![warn(clippy::into_iter_on_array)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` -error: lint `clippy::thread_local_initializer_can_be_made_const` has been renamed to `clippy::missing_const_for_thread_local` +error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` --> tests/ui/rename.rs:102:9 | -LL | #![warn(clippy::thread_local_initializer_can_be_made_const)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::missing_const_for_thread_local` +LL | #![warn(clippy::invalid_atomic_ordering)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` -error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` +error: lint `clippy::invalid_null_ptr_usage` has been renamed to `invalid_null_arguments` --> tests/ui/rename.rs:103:9 | -LL | #![warn(clippy::to_string_in_display)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` +LL | #![warn(clippy::invalid_null_ptr_usage)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_null_arguments` -error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default` +error: lint `clippy::invalid_ref` has been renamed to `invalid_value` --> tests/ui/rename.rs:104:9 | -LL | #![warn(clippy::unwrap_or_else_default)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default` +LL | #![warn(clippy::invalid_ref)] + | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` -error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` +error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked` --> tests/ui/rename.rs:105:9 | -LL | #![warn(clippy::zero_width_space)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` +LL | #![warn(clippy::invalid_utf8_in_unchecked)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked` -error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting` +error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` --> tests/ui/rename.rs:106:9 | -LL | #![warn(clippy::cast_ref_to_mut)] - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting` +LL | #![warn(clippy::let_underscore_drop)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` -error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op` +error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` --> tests/ui/rename.rs:107:9 | -LL | #![warn(clippy::clone_double_ref)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op` +LL | #![warn(clippy::logic_bug)] + | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` -error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons` +error: lint `clippy::maybe_misused_cfg` has been renamed to `unexpected_cfgs` --> tests/ui/rename.rs:108:9 | -LL | #![warn(clippy::cmp_nan)] - | ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons` +LL | #![warn(clippy::maybe_misused_cfg)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs` -error: lint `clippy::invalid_null_ptr_usage` has been renamed to `invalid_null_arguments` +error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` --> tests/ui/rename.rs:109:9 | -LL | #![warn(clippy::invalid_null_ptr_usage)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_null_arguments` +LL | #![warn(clippy::mem_discriminant_non_enum)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` -error: lint `clippy::double_neg` has been renamed to `double_negations` +error: lint `clippy::mismatched_target_os` has been renamed to `unexpected_cfgs` --> tests/ui/rename.rs:110:9 | -LL | #![warn(clippy::double_neg)] - | ^^^^^^^^^^^^^^^^^^ help: use the new name: `double_negations` +LL | #![warn(clippy::mismatched_target_os)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs` -error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` +error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` --> tests/ui/rename.rs:111:9 | -LL | #![warn(clippy::drop_bounds)] - | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` +LL | #![warn(clippy::new_without_default_derive)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` -error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types` +error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` --> tests/ui/rename.rs:112:9 | -LL | #![warn(clippy::drop_copy)] - | ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types` +LL | #![warn(clippy::option_and_then_some)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` -error: lint `clippy::drop_ref` has been renamed to `dropping_references` +error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` --> tests/ui/rename.rs:113:9 | -LL | #![warn(clippy::drop_ref)] - | ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references` +LL | #![warn(clippy::option_expect_used)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` -error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks` +error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` --> tests/ui/rename.rs:114:9 | -LL | #![warn(clippy::fn_null_check)] - | ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks` +LL | #![warn(clippy::option_map_unwrap_or)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` -error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` +error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` --> tests/ui/rename.rs:115:9 | -LL | #![warn(clippy::for_loop_over_option)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` +LL | #![warn(clippy::option_map_unwrap_or_else)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` -error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` +error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` --> tests/ui/rename.rs:116:9 | -LL | #![warn(clippy::for_loop_over_result)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` +LL | #![warn(clippy::option_unwrap_used)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` -error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` +error: lint `clippy::overflow_check_conditional` has been renamed to `clippy::panicking_overflow_checks` --> tests/ui/rename.rs:117:9 | -LL | #![warn(clippy::for_loops_over_fallibles)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` +LL | #![warn(clippy::overflow_check_conditional)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::panicking_overflow_checks` -error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types` +error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` --> tests/ui/rename.rs:118:9 | -LL | #![warn(clippy::forget_copy)] - | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types` +LL | #![warn(clippy::panic_params)] + | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` -error: lint `clippy::forget_ref` has been renamed to `forgetting_references` +error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` --> tests/ui/rename.rs:119:9 | -LL | #![warn(clippy::forget_ref)] - | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references` +LL | #![warn(clippy::positional_named_format_parameters)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` -error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` +error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` --> tests/ui/rename.rs:120:9 | -LL | #![warn(clippy::into_iter_on_array)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` +LL | #![warn(clippy::ref_in_deref)] + | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` -error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` +error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` --> tests/ui/rename.rs:121:9 | -LL | #![warn(clippy::invalid_atomic_ordering)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` +LL | #![warn(clippy::result_expect_used)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` -error: lint `clippy::invalid_ref` has been renamed to `invalid_value` +error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` --> tests/ui/rename.rs:122:9 | -LL | #![warn(clippy::invalid_ref)] - | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` +LL | #![warn(clippy::result_map_unwrap_or_else)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` -error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked` +error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` --> tests/ui/rename.rs:123:9 | -LL | #![warn(clippy::invalid_utf8_in_unchecked)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked` +LL | #![warn(clippy::result_unwrap_used)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` -error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` +error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_empty_ranges` --> tests/ui/rename.rs:124:9 | -LL | #![warn(clippy::let_underscore_drop)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` +LL | #![warn(clippy::reverse_range_loop)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges` -error: lint `clippy::maybe_misused_cfg` has been renamed to `unexpected_cfgs` +error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` --> tests/ui/rename.rs:125:9 | -LL | #![warn(clippy::maybe_misused_cfg)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs` +LL | #![warn(clippy::single_char_push_str)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` -error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` +error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` --> tests/ui/rename.rs:126:9 | -LL | #![warn(clippy::mem_discriminant_non_enum)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` +LL | #![warn(clippy::stutter)] + | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` -error: lint `clippy::mismatched_target_os` has been renamed to `unexpected_cfgs` +error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries` --> tests/ui/rename.rs:127:9 | -LL | #![warn(clippy::mismatched_target_os)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs` +LL | #![warn(clippy::temporary_cstring_as_ptr)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries` -error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` +error: lint `clippy::thread_local_initializer_can_be_made_const` has been renamed to `clippy::missing_const_for_thread_local` --> tests/ui/rename.rs:128:9 | -LL | #![warn(clippy::panic_params)] - | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` +LL | #![warn(clippy::thread_local_initializer_can_be_made_const)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::missing_const_for_thread_local` -error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` +error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` --> tests/ui/rename.rs:129:9 | -LL | #![warn(clippy::positional_named_format_parameters)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` +LL | #![warn(clippy::to_string_in_display)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` -error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries` +error: lint `clippy::transmute_float_to_int` has been renamed to `unnecessary_transmutes` --> tests/ui/rename.rs:130:9 | -LL | #![warn(clippy::temporary_cstring_as_ptr)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries` +LL | #![warn(clippy::transmute_float_to_int)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes` -error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops` +error: lint `clippy::transmute_int_to_char` has been renamed to `unnecessary_transmutes` --> tests/ui/rename.rs:131:9 | -LL | #![warn(clippy::undropped_manually_drops)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops` +LL | #![warn(clippy::transmute_int_to_char)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes` -error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` +error: lint `clippy::transmute_int_to_float` has been renamed to `unnecessary_transmutes` --> tests/ui/rename.rs:132:9 | -LL | #![warn(clippy::unknown_clippy_lints)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` +LL | #![warn(clippy::transmute_int_to_float)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes` -error: lint `clippy::unused_label` has been renamed to `unused_labels` +error: lint `clippy::transmute_num_to_bytes` has been renamed to `unnecessary_transmutes` --> tests/ui/rename.rs:133:9 | -LL | #![warn(clippy::unused_label)] - | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` +LL | #![warn(clippy::transmute_num_to_bytes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes` -error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons` +error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops` --> tests/ui/rename.rs:134:9 | -LL | #![warn(clippy::vtable_address_comparisons)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons` +LL | #![warn(clippy::undropped_manually_drops)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops` -error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_empty_ranges` +error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` --> tests/ui/rename.rs:135:9 | -LL | #![warn(clippy::reverse_range_loop)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges` +LL | #![warn(clippy::unknown_clippy_lints)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` -error: lint `clippy::transmute_int_to_float` has been renamed to `unnecessary_transmutes` +error: lint `clippy::unused_label` has been renamed to `unused_labels` --> tests/ui/rename.rs:136:9 | -LL | #![warn(clippy::transmute_int_to_float)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes` +LL | #![warn(clippy::unused_label)] + | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` -error: lint `clippy::transmute_int_to_char` has been renamed to `unnecessary_transmutes` +error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default` --> tests/ui/rename.rs:137:9 | -LL | #![warn(clippy::transmute_int_to_char)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes` +LL | #![warn(clippy::unwrap_or_else_default)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default` -error: lint `clippy::transmute_float_to_int` has been renamed to `unnecessary_transmutes` +error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons` --> tests/ui/rename.rs:138:9 | -LL | #![warn(clippy::transmute_float_to_int)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes` +LL | #![warn(clippy::vtable_address_comparisons)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons` -error: lint `clippy::transmute_num_to_bytes` has been renamed to `unnecessary_transmutes` +error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` --> tests/ui/rename.rs:139:9 | -LL | #![warn(clippy::transmute_num_to_bytes)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes` +LL | #![warn(clippy::zero_width_space)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: aborting due to 73 previous errors From 13b070e3560a2ecfb11d9bb11ca2ea0a8296e4d8 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 16 Apr 2025 16:00:14 -0400 Subject: [PATCH 2340/4206] clippy_dev: Fix previous renames in `rename_lint` --- clippy_dev/src/rename_lint.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/clippy_dev/src/rename_lint.rs b/clippy_dev/src/rename_lint.rs index 9f7c328712c31..be8b27c7a9e9f 100644 --- a/clippy_dev/src/rename_lint.rs +++ b/clippy_dev/src/rename_lint.rs @@ -43,6 +43,17 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b let lint = &lints[lint_idx]; let old_name_prefixed = String::from_iter(["clippy::", old_name]); + let new_name_prefixed = if uplift { + new_name.to_owned() + } else { + String::from_iter(["clippy::", new_name]) + }; + + for lint in &mut renamed_lints { + if lint.new_name == old_name_prefixed { + lint.new_name.clone_from(&new_name_prefixed); + } + } match renamed_lints.binary_search_by(|x| x.old_name.cmp(&old_name_prefixed)) { Ok(_) => { println!("`{old_name}` already has a rename registered"); From 27acbf2c6605a165ffe777c4fec44f90b39ff978 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 15 May 2025 05:58:51 -0400 Subject: [PATCH 2341/4206] Reenable linting on UFCS `deref` calls. --- clippy_lints/src/dereference.rs | 67 +++++++++++--------------- tests/ui/explicit_deref_methods.fixed | 11 +++-- tests/ui/explicit_deref_methods.rs | 11 +++-- tests/ui/explicit_deref_methods.stderr | 44 ++++++++++++----- 4 files changed, 73 insertions(+), 60 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 5edb5c235703e..a22a2ee66d258 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -22,6 +22,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypeckResults}; use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; +use std::borrow::Cow; declare_clippy_lint! { /// ### What it does @@ -252,13 +253,14 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { } let typeck = cx.typeck_results(); - let Some((kind, sub_expr)) = try_parse_ref_op(cx.tcx, typeck, expr) else { + let Some((kind, sub_expr, skip_expr)) = try_parse_ref_op(cx.tcx, typeck, expr) else { // The whole chain of reference operations has been seen if let Some((state, data)) = self.state.take() { report(cx, expr, state, data, typeck); } return; }; + self.skip_expr = skip_expr; match (self.state.take(), kind) { (None, kind) => { @@ -671,42 +673,38 @@ fn try_parse_ref_op<'tcx>( tcx: TyCtxt<'tcx>, typeck: &'tcx TypeckResults<'_>, expr: &'tcx Expr<'_>, -) -> Option<(RefOp, &'tcx Expr<'tcx>)> { - let (is_ufcs, def_id, arg) = match expr.kind { - ExprKind::MethodCall(_, arg, [], _) => (false, typeck.type_dependent_def_id(expr.hir_id)?, arg), +) -> Option<(RefOp, &'tcx Expr<'tcx>, Option)> { + let (call_path_id, def_id, arg) = match expr.kind { + ExprKind::MethodCall(_, arg, [], _) => (None, typeck.type_dependent_def_id(expr.hir_id)?, arg), ExprKind::Call( - Expr { - kind: ExprKind::Path(path), + &Expr { + kind: ExprKind::Path(QPath::Resolved(None, path)), hir_id, .. }, [arg], - ) => (true, typeck.qpath_res(path, *hir_id).opt_def_id()?, arg), + ) => (Some(hir_id), path.res.opt_def_id()?, arg), ExprKind::Unary(UnOp::Deref, sub_expr) if !typeck.expr_ty(sub_expr).is_raw_ptr() => { - return Some((RefOp::Deref, sub_expr)); + return Some((RefOp::Deref, sub_expr, None)); + }, + ExprKind::AddrOf(BorrowKind::Ref, mutability, sub_expr) => { + return Some((RefOp::AddrOf(mutability), sub_expr, None)); }, - ExprKind::AddrOf(BorrowKind::Ref, mutability, sub_expr) => return Some((RefOp::AddrOf(mutability), sub_expr)), _ => return None, }; - if tcx.is_diagnostic_item(sym::deref_method, def_id) { - Some(( - RefOp::Method { - mutbl: Mutability::Not, - is_ufcs, - }, - arg, - )) - } else if tcx.trait_of_item(def_id)? == tcx.lang_items().deref_mut_trait()? { - Some(( - RefOp::Method { - mutbl: Mutability::Mut, - is_ufcs, - }, - arg, - )) - } else { - None - } + let mutbl = match tcx.get_diagnostic_name(def_id) { + Some(sym::deref_method) => Mutability::Not, + Some(sym::deref_mut_method) => Mutability::Mut, + _ => return None, + }; + Some(( + RefOp::Method { + mutbl, + is_ufcs: call_path_id.is_some(), + }, + arg, + call_path_id, + )) } // Checks if the adjustments contains a deref of `ManuallyDrop<_>` @@ -944,7 +942,7 @@ fn report<'tcx>( mutbl, } => { let mut app = Applicability::MachineApplicable; - let (expr_str, _expr_is_macro_call) = + let (expr_str, expr_is_macro_call) = snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app); let ty = typeck.expr_ty(expr); let (_, ref_count) = peel_middle_ty_refs(ty); @@ -968,20 +966,11 @@ fn report<'tcx>( "&" }; - // expr_str (the suggestion) is never shown if is_final_ufcs is true, since it's - // `expr.kind == ExprKind::Call`. Therefore, this is, afaik, always unnecessary. - /* - expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence() < ExprPrecedence::Prefix { + let expr_str = if !expr_is_macro_call && is_ufcs && expr.precedence() < ExprPrecedence::Prefix { Cow::Owned(format!("({expr_str})")) } else { expr_str }; - */ - - // Fix #10850, do not lint if it's `Foo::deref` instead of `foo.deref()`. - if is_ufcs { - return; - } span_lint_and_sugg( cx, diff --git a/tests/ui/explicit_deref_methods.fixed b/tests/ui/explicit_deref_methods.fixed index 0d1a5f80f3d5a..619329a6ade0c 100644 --- a/tests/ui/explicit_deref_methods.fixed +++ b/tests/ui/explicit_deref_methods.fixed @@ -8,7 +8,8 @@ clippy::needless_borrow, clippy::no_effect, clippy::uninlined_format_args, - clippy::unnecessary_literal_unwrap + clippy::unnecessary_literal_unwrap, + clippy::deref_addrof )] use std::ops::{Deref, DerefMut}; @@ -87,9 +88,6 @@ fn main() { let b = &*opt_a.unwrap(); //~^ explicit_deref_methods - // make sure `Aaa::deref` instead of `aaa.deref()` is not linted, as well as fully qualified - // syntax - Aaa::deref(&Aaa); Aaa::deref_mut(&mut Aaa); ::deref(&Aaa); @@ -139,4 +137,9 @@ fn main() { let no_lint = NoLint(42); let b = no_lint.deref(); let b = no_lint.deref_mut(); + + let _ = &*&"foo"; //~ explicit_deref_methods + let mut x = String::new(); + let _ = &&mut **&mut x; //~ explicit_deref_methods + let _ = &&mut ***(&mut &mut x); //~ explicit_deref_methods } diff --git a/tests/ui/explicit_deref_methods.rs b/tests/ui/explicit_deref_methods.rs index 8d4a899cd2607..9f2d513283c9b 100644 --- a/tests/ui/explicit_deref_methods.rs +++ b/tests/ui/explicit_deref_methods.rs @@ -8,7 +8,8 @@ clippy::needless_borrow, clippy::no_effect, clippy::uninlined_format_args, - clippy::unnecessary_literal_unwrap + clippy::unnecessary_literal_unwrap, + clippy::deref_addrof )] use std::ops::{Deref, DerefMut}; @@ -87,9 +88,6 @@ fn main() { let b = opt_a.unwrap().deref(); //~^ explicit_deref_methods - // make sure `Aaa::deref` instead of `aaa.deref()` is not linted, as well as fully qualified - // syntax - Aaa::deref(&Aaa); Aaa::deref_mut(&mut Aaa); ::deref(&Aaa); @@ -139,4 +137,9 @@ fn main() { let no_lint = NoLint(42); let b = no_lint.deref(); let b = no_lint.deref_mut(); + + let _ = &Deref::deref(&"foo"); //~ explicit_deref_methods + let mut x = String::new(); + let _ = &DerefMut::deref_mut(&mut x); //~ explicit_deref_methods + let _ = &DerefMut::deref_mut((&mut &mut x).deref_mut()); //~ explicit_deref_methods } diff --git a/tests/ui/explicit_deref_methods.stderr b/tests/ui/explicit_deref_methods.stderr index 2ca376cba00bd..a81e2f60317b3 100644 --- a/tests/ui/explicit_deref_methods.stderr +++ b/tests/ui/explicit_deref_methods.stderr @@ -1,5 +1,5 @@ error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:54:19 + --> tests/ui/explicit_deref_methods.rs:55:19 | LL | let b: &str = a.deref(); | ^^^^^^^^^ help: try: `&*a` @@ -8,70 +8,88 @@ LL | let b: &str = a.deref(); = help: to override `-D warnings` add `#[allow(clippy::explicit_deref_methods)]` error: explicit `deref_mut` method call - --> tests/ui/explicit_deref_methods.rs:57:23 + --> tests/ui/explicit_deref_methods.rs:58:23 | LL | let b: &mut str = a.deref_mut(); | ^^^^^^^^^^^^^ help: try: `&mut **a` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:61:39 + --> tests/ui/explicit_deref_methods.rs:62:39 | LL | let b: String = format!("{}, {}", a.deref(), a.deref()); | ^^^^^^^^^ help: try: `&*a` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:61:50 + --> tests/ui/explicit_deref_methods.rs:62:50 | LL | let b: String = format!("{}, {}", a.deref(), a.deref()); | ^^^^^^^^^ help: try: `&*a` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:65:20 + --> tests/ui/explicit_deref_methods.rs:66:20 | LL | println!("{}", a.deref()); | ^^^^^^^^^ help: try: `&*a` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:69:11 + --> tests/ui/explicit_deref_methods.rs:70:11 | LL | match a.deref() { | ^^^^^^^^^ help: try: `&*a` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:74:28 + --> tests/ui/explicit_deref_methods.rs:75:28 | LL | let b: String = concat(a.deref()); | ^^^^^^^^^ help: try: `&*a` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:77:13 + --> tests/ui/explicit_deref_methods.rs:78:13 | LL | let b = just_return(a).deref(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `just_return(a)` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:80:28 + --> tests/ui/explicit_deref_methods.rs:81:28 | LL | let b: String = concat(just_return(a).deref()); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `just_return(a)` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:83:19 + --> tests/ui/explicit_deref_methods.rs:84:19 | LL | let b: &str = a.deref().deref(); | ^^^^^^^^^^^^^^^^^ help: try: `&**a` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:87:13 + --> tests/ui/explicit_deref_methods.rs:88:13 | LL | let b = opt_a.unwrap().deref(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*opt_a.unwrap()` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:125:31 + --> tests/ui/explicit_deref_methods.rs:123:31 | LL | let b: &str = expr_deref!(a.deref()); | ^^^^^^^^^ help: try: `&*a` -error: aborting due to 12 previous errors +error: explicit `deref` method call + --> tests/ui/explicit_deref_methods.rs:141:14 + | +LL | let _ = &Deref::deref(&"foo"); + | ^^^^^^^^^^^^^^^^^^^^ help: try: `*&"foo"` + +error: explicit `deref_mut` method call + --> tests/ui/explicit_deref_methods.rs:143:14 + | +LL | let _ = &DerefMut::deref_mut(&mut x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut **&mut x` + +error: explicit `deref_mut` method call + --> tests/ui/explicit_deref_methods.rs:144:14 + | +LL | let _ = &DerefMut::deref_mut((&mut &mut x).deref_mut()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut ***(&mut &mut x)` + +error: aborting due to 15 previous errors From f0648966e4aa48d83bbd395c513ad1febbb5a8e6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 16 May 2025 13:02:20 +0200 Subject: [PATCH 2342/4206] Add missing `add_eval` to generate `__rdl_oom` in the alloc error handler --- src/allocator.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/allocator.rs b/src/allocator.rs index f4ebd42ee2dc0..279b7dd2fb928 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -152,6 +152,7 @@ fn create_wrapper_function( if output.is_some() { block.end_with_return(None, ret); } else { + block.add_eval(None, ret); block.end_with_void_return(None); } From 48538ed16b8f32eddaa5476dab4d461e4b35026c Mon Sep 17 00:00:00 2001 From: Ryan van Polen Date: Fri, 16 May 2025 13:28:33 +0200 Subject: [PATCH 2343/4206] Updated feature flag and output of `clippy/tests/ui/map_flatten*` --- src/tools/clippy/tests/ui/map_flatten.rs | 2 +- .../clippy/tests/ui/map_flatten_fixable.fixed | 1 - .../clippy/tests/ui/map_flatten_fixable.rs | 1 - .../clippy/tests/ui/map_flatten_fixable.stderr | 18 +++++++++--------- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/tools/clippy/tests/ui/map_flatten.rs b/src/tools/clippy/tests/ui/map_flatten.rs index d7e9c9d9900d9..0970da8039a48 100644 --- a/src/tools/clippy/tests/ui/map_flatten.rs +++ b/src/tools/clippy/tests/ui/map_flatten.rs @@ -1,5 +1,5 @@ #![warn(clippy::map_flatten)] -#![feature(result_flattening)] + //@no-rustfix // issue #8506, multi-line #[rustfmt::skip] diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.fixed b/src/tools/clippy/tests/ui/map_flatten_fixable.fixed index f8379ed23c5b2..6d8a27d3018dd 100644 --- a/src/tools/clippy/tests/ui/map_flatten_fixable.fixed +++ b/src/tools/clippy/tests/ui/map_flatten_fixable.fixed @@ -1,4 +1,3 @@ -#![feature(result_flattening)] #![allow( clippy::let_underscore_untyped, clippy::missing_docs_in_private_items, diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.rs b/src/tools/clippy/tests/ui/map_flatten_fixable.rs index 040a9ca85f647..845e3a79ae2b0 100644 --- a/src/tools/clippy/tests/ui/map_flatten_fixable.rs +++ b/src/tools/clippy/tests/ui/map_flatten_fixable.rs @@ -1,4 +1,3 @@ -#![feature(result_flattening)] #![allow( clippy::let_underscore_untyped, clippy::missing_docs_in_private_items, diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.stderr b/src/tools/clippy/tests/ui/map_flatten_fixable.stderr index fe68eb7e4ab44..05d4d9a6ad85c 100644 --- a/src/tools/clippy/tests/ui/map_flatten_fixable.stderr +++ b/src/tools/clippy/tests/ui/map_flatten_fixable.stderr @@ -1,5 +1,5 @@ error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:17:47 + --> tests/ui/map_flatten_fixable.rs:16:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id)` @@ -8,43 +8,43 @@ LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().coll = help: to override `-D warnings` add `#[allow(clippy::map_flatten)]` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:19:47 + --> tests/ui/map_flatten_fixable.rs:18:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_ref)` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:21:47 + --> tests/ui/map_flatten_fixable.rs:20:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_closure)` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:23:47 + --> tests/ui/map_flatten_fixable.rs:22:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(|x| x.checked_add(1))` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:27:47 + --> tests/ui/map_flatten_fixable.rs:26:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `flat_map` and remove the `.flatten()`: `flat_map(|x| 0..x)` error: called `map(..).flatten()` on `Option` - --> tests/ui/map_flatten_fixable.rs:31:40 + --> tests/ui/map_flatten_fixable.rs:30:40 | LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); | ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)` error: called `map(..).flatten()` on `Result` - --> tests/ui/map_flatten_fixable.rs:35:42 + --> tests/ui/map_flatten_fixable.rs:34:42 | LL | let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten(); | ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:45:10 + --> tests/ui/map_flatten_fixable.rs:44:10 | LL | .map(|n| match n { | __________^ @@ -74,7 +74,7 @@ LL ~ }); | error: called `map(..).flatten()` on `Option` - --> tests/ui/map_flatten_fixable.rs:66:10 + --> tests/ui/map_flatten_fixable.rs:65:10 | LL | .map(|_| { | __________^ From a9225f82632c0e15c61bf858604860c7e0aa1abf Mon Sep 17 00:00:00 2001 From: Ryan van Polen Date: Fri, 16 May 2025 13:28:33 +0200 Subject: [PATCH 2344/4206] Updated feature flag and output of `clippy/tests/ui/map_flatten*` --- tests/ui/map_flatten.rs | 2 +- tests/ui/map_flatten_fixable.fixed | 1 - tests/ui/map_flatten_fixable.rs | 1 - tests/ui/map_flatten_fixable.stderr | 18 +++++++++--------- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/tests/ui/map_flatten.rs b/tests/ui/map_flatten.rs index d7e9c9d9900d9..0970da8039a48 100644 --- a/tests/ui/map_flatten.rs +++ b/tests/ui/map_flatten.rs @@ -1,5 +1,5 @@ #![warn(clippy::map_flatten)] -#![feature(result_flattening)] + //@no-rustfix // issue #8506, multi-line #[rustfmt::skip] diff --git a/tests/ui/map_flatten_fixable.fixed b/tests/ui/map_flatten_fixable.fixed index f8379ed23c5b2..6d8a27d3018dd 100644 --- a/tests/ui/map_flatten_fixable.fixed +++ b/tests/ui/map_flatten_fixable.fixed @@ -1,4 +1,3 @@ -#![feature(result_flattening)] #![allow( clippy::let_underscore_untyped, clippy::missing_docs_in_private_items, diff --git a/tests/ui/map_flatten_fixable.rs b/tests/ui/map_flatten_fixable.rs index 040a9ca85f647..845e3a79ae2b0 100644 --- a/tests/ui/map_flatten_fixable.rs +++ b/tests/ui/map_flatten_fixable.rs @@ -1,4 +1,3 @@ -#![feature(result_flattening)] #![allow( clippy::let_underscore_untyped, clippy::missing_docs_in_private_items, diff --git a/tests/ui/map_flatten_fixable.stderr b/tests/ui/map_flatten_fixable.stderr index fe68eb7e4ab44..05d4d9a6ad85c 100644 --- a/tests/ui/map_flatten_fixable.stderr +++ b/tests/ui/map_flatten_fixable.stderr @@ -1,5 +1,5 @@ error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:17:47 + --> tests/ui/map_flatten_fixable.rs:16:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id)` @@ -8,43 +8,43 @@ LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().coll = help: to override `-D warnings` add `#[allow(clippy::map_flatten)]` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:19:47 + --> tests/ui/map_flatten_fixable.rs:18:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_ref)` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:21:47 + --> tests/ui/map_flatten_fixable.rs:20:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_closure)` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:23:47 + --> tests/ui/map_flatten_fixable.rs:22:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(|x| x.checked_add(1))` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:27:47 + --> tests/ui/map_flatten_fixable.rs:26:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `flat_map` and remove the `.flatten()`: `flat_map(|x| 0..x)` error: called `map(..).flatten()` on `Option` - --> tests/ui/map_flatten_fixable.rs:31:40 + --> tests/ui/map_flatten_fixable.rs:30:40 | LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); | ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)` error: called `map(..).flatten()` on `Result` - --> tests/ui/map_flatten_fixable.rs:35:42 + --> tests/ui/map_flatten_fixable.rs:34:42 | LL | let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten(); | ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:45:10 + --> tests/ui/map_flatten_fixable.rs:44:10 | LL | .map(|n| match n { | __________^ @@ -74,7 +74,7 @@ LL ~ }); | error: called `map(..).flatten()` on `Option` - --> tests/ui/map_flatten_fixable.rs:66:10 + --> tests/ui/map_flatten_fixable.rs:65:10 | LL | .map(|_| { | __________^ From 2cdbd69abfbd5a1f0c5b9ceee2393f1a87181d97 Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 5 May 2025 11:05:29 +0200 Subject: [PATCH 2345/4206] disable the stack overflow handler on miri --- .../std/src/sys/pal/unix/stack_overflow.rs | 70 +++++++++++-------- 1 file changed, 41 insertions(+), 29 deletions(-) diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index 804353178aaca..a3be2cdf738f5 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -25,27 +25,36 @@ impl Drop for Handler { } } -#[cfg(any( - target_os = "linux", - target_os = "freebsd", - target_os = "hurd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris", - target_os = "illumos", +#[cfg(all( + not(miri), + any( + target_os = "linux", + target_os = "freebsd", + target_os = "hurd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "illumos", + ), ))] mod thread_info; -#[cfg(any( - target_os = "linux", - target_os = "freebsd", - target_os = "hurd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris", - target_os = "illumos", +// miri doesn't model signals nor stack overflows and this code has some +// synchronization properties that we don't want to expose to user code, +// hence we disable it on miri. +#[cfg(all( + not(miri), + any( + target_os = "linux", + target_os = "freebsd", + target_os = "hurd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "illumos", + ) ))] mod imp { use libc::{ @@ -606,17 +615,20 @@ mod imp { // usually have fewer qualms about forwards compatibility, since the runtime // is shipped with the OS): // -#[cfg(not(any( - target_os = "linux", - target_os = "freebsd", - target_os = "hurd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris", - target_os = "illumos", - target_os = "cygwin", -)))] +#[cfg(any( + miri, + not(any( + target_os = "linux", + target_os = "freebsd", + target_os = "hurd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "illumos", + target_os = "cygwin", + )) +))] mod imp { pub unsafe fn init() {} From 10f4f6ae3d41c95e56a6ba46dd82d5eb283a9e54 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 16 May 2025 14:52:28 +0200 Subject: [PATCH 2346/4206] fix: Don't overwrite `RUSTUP_TOOLCHAIN` if it is already set --- .../rust-analyzer/crates/project-model/src/sysroot.rs | 7 ++++++- .../rust-analyzer/crates/rust-analyzer/src/flycheck.rs | 6 +++++- src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs | 4 ++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs index c7c1b04318677..d4055d9a0af91 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs @@ -137,7 +137,12 @@ impl Sysroot { } let mut cmd = toolchain::command(tool.prefer_proxy(), current_dir, envs); - cmd.env("RUSTUP_TOOLCHAIN", AsRef::::as_ref(root)); + if !envs.contains_key("RUSTUP_TOOLCHAIN") + && std::env::var_os("RUSTUP_TOOLCHAIN").is_none() + { + cmd.env("RUSTUP_TOOLCHAIN", AsRef::::as_ref(root)); + } + cmd } _ => toolchain::command(tool.path(), current_dir, envs), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs index fc312439d58c5..0e418240db0c4 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs @@ -470,7 +470,11 @@ impl FlycheckActor { let mut cmd = toolchain::command(Tool::Cargo.path(), &*self.root, &options.extra_env); if let Some(sysroot_root) = &self.sysroot_root { - cmd.env("RUSTUP_TOOLCHAIN", AsRef::::as_ref(sysroot_root)); + if !options.extra_env.contains_key("RUSTUP_TOOLCHAIN") + && std::env::var_os("RUSTUP_TOOLCHAIN").is_none() + { + cmd.env("RUSTUP_TOOLCHAIN", AsRef::::as_ref(sysroot_root)); + } } cmd.arg(command); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs index 55ed1923653f9..d7c6aeccf0b5f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -659,6 +659,10 @@ impl GlobalState { .chain( ws.sysroot .root() + .filter(|_| { + !self.config.extra_env(None).contains_key("RUSTUP_TOOLCHAIN") + && std::env::var_os("RUSTUP_TOOLCHAIN").is_none() + }) .map(|it| ("RUSTUP_TOOLCHAIN".to_owned(), Some(it.to_string()))), ) .collect(), From 7d9f437f993e213c1f9aeb9c07454f6fd1648821 Mon Sep 17 00:00:00 2001 From: sam skeoch Date: Sat, 22 Feb 2025 17:22:57 +0000 Subject: [PATCH 2347/4206] Add as_ascii_unchecked() methods to char, str, and u8 --- library/core/src/char/methods.rs | 14 ++++++++++++++ library/core/src/num/mod.rs | 14 ++++++++++++++ library/core/src/str/mod.rs | 15 +++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 042925a352f39..3c25ab4fdd709 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -1202,6 +1202,20 @@ impl char { } } + /// Converts this char into an [ASCII character](`ascii::Char`), without + /// checking whether it is valid. + /// + /// # Safety + /// + /// This char must be within the ASCII range, or else this is UB. + #[must_use] + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const unsafe fn as_ascii_unchecked(&self) -> ascii::Char { + // SAFETY: the caller promised that this char is ASCII. + unsafe { ascii::Char::from_u8_unchecked(*self as u8) } + } + /// Makes a copy of the value in its ASCII upper case equivalent. /// /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index ecc1c7bf9021d..9332908398cd0 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -492,6 +492,20 @@ impl u8 { ascii::Char::from_u8(*self) } + /// Converts this byte to an [ASCII character](ascii::Char), without + /// checking whether or not it's valid. + /// + /// # Safety + /// + /// This byte must be valid ASCII, or else this is UB. + #[must_use] + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const unsafe fn as_ascii_unchecked(&self) -> ascii::Char { + // SAFETY: the caller promised that this byte is ASCII. + unsafe { ascii::Char::from_u8_unchecked(*self) } + } + /// Makes a copy of the value in its ASCII upper case equivalent. /// /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 9e7e949b722d7..2eb8f4960856d 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -2634,6 +2634,21 @@ impl str { self.as_bytes().as_ascii() } + /// Converts this string slice into a slice of [ASCII characters](ascii::Char), + /// without checking whether they are valid. + /// + /// # Safety + /// + /// Every character in this string must be ASCII, or else this is UB. + #[unstable(feature = "ascii_char", issue = "110998")] + #[must_use] + #[inline] + pub const unsafe fn as_ascii_unchecked(&self) -> &[ascii::Char] { + // SAFETY: the caller promised that every byte of this string slice + // is ASCII. + unsafe { self.as_bytes().as_ascii_unchecked() } + } + /// Checks that two strings are an ASCII case-insensitive match. /// /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, From 101e24a223f818e17d2c68298d48d4e6008c02aa Mon Sep 17 00:00:00 2001 From: sam skeoch Date: Tue, 13 May 2025 14:55:03 +0100 Subject: [PATCH 2348/4206] Add assert_unsafe_precondition!()s to as_ascii_unchecked() methods --- library/core/src/char/methods.rs | 7 +++++++ library/core/src/num/mod.rs | 6 ++++++ library/core/src/str/mod.rs | 7 +++++++ 3 files changed, 20 insertions(+) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 3c25ab4fdd709..af2edf141b22f 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -4,6 +4,7 @@ use super::*; use crate::panic::const_panic; use crate::slice; use crate::str::from_utf8_unchecked_mut; +use crate::ub_checks::assert_unsafe_precondition; use crate::unicode::printable::is_printable; use crate::unicode::{self, conversions}; @@ -1212,6 +1213,12 @@ impl char { #[unstable(feature = "ascii_char", issue = "110998")] #[inline] pub const unsafe fn as_ascii_unchecked(&self) -> ascii::Char { + assert_unsafe_precondition!( + check_library_ub, + "as_ascii_unchecked requires that the char is valid ASCII", + (it: &char = self) => it.is_ascii() + ); + // SAFETY: the caller promised that this char is ASCII. unsafe { ascii::Char::from_u8_unchecked(*self as u8) } } diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 9332908398cd0..a82b2aa61ce06 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -502,6 +502,12 @@ impl u8 { #[unstable(feature = "ascii_char", issue = "110998")] #[inline] pub const unsafe fn as_ascii_unchecked(&self) -> ascii::Char { + assert_unsafe_precondition!( + check_library_ub, + "as_ascii_unchecked requires that the byte is valid ASCII", + (it: &u8 = self) => it.is_ascii() + ); + // SAFETY: the caller promised that this byte is ASCII. unsafe { ascii::Char::from_u8_unchecked(*self) } } diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 2eb8f4960856d..e505e2280953e 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -17,6 +17,7 @@ use self::pattern::{DoubleEndedSearcher, Pattern, ReverseSearcher, Searcher}; use crate::char::{self, EscapeDebugExtArgs}; use crate::ops::Range; use crate::slice::{self, SliceIndex}; +use crate::ub_checks::assert_unsafe_precondition; use crate::{ascii, mem}; pub mod pattern; @@ -2644,6 +2645,12 @@ impl str { #[must_use] #[inline] pub const unsafe fn as_ascii_unchecked(&self) -> &[ascii::Char] { + assert_unsafe_precondition!( + check_library_ub, + "as_ascii_unchecked requires that the string is valid ASCII", + (it: &str = self) => it.is_ascii() + ); + // SAFETY: the caller promised that every byte of this string slice // is ASCII. unsafe { self.as_bytes().as_ascii_unchecked() } From 39ab00a3a11babce80ab27809653d9c74fe60377 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Wed, 16 Apr 2025 21:22:07 +0000 Subject: [PATCH 2349/4206] `match_same_arms`, `ifs_same_cond`: lint once per same arm/condition --- clippy_lints/src/copies.rs | 25 +- clippy_lints/src/matches/match_same_arms.rs | 122 +++++---- clippy_utils/src/lib.rs | 43 +-- tests/ui-toml/ifs_same_cond/ifs_same_cond.rs | 2 +- .../ifs_same_cond/ifs_same_cond.stderr | 12 +- tests/ui/ifs_same_cond.rs | 12 +- tests/ui/ifs_same_cond.stderr | 62 ++--- tests/ui/match_same_arms.fixed | 142 ++++++++++ tests/ui/match_same_arms.rs | 20 +- tests/ui/match_same_arms.stderr | 137 +++++----- tests/ui/match_same_arms2.fixed | 53 +++- tests/ui/match_same_arms2.rs | 49 +++- tests/ui/match_same_arms2.stderr | 255 ++++++++++++------ tests/ui/match_same_arms_non_exhaustive.fixed | 24 +- tests/ui/match_same_arms_non_exhaustive.rs | 19 +- .../ui/match_same_arms_non_exhaustive.stderr | 86 ++++-- tests/ui/same_functions_in_if_condition.rs | 12 +- .../ui/same_functions_in_if_condition.stderr | 67 ++--- 18 files changed, 745 insertions(+), 397 deletions(-) create mode 100644 tests/ui/match_same_arms.fixed diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 42fbe6438d4ea..48bf3dafa6ef8 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,5 +1,5 @@ use clippy_config::Conf; -use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_note, span_lint_and_then}; use clippy_utils::source::{IntoSpan, SpanRangeExt, first_line_of_span, indent_of, reindent_multiline, snippet}; use clippy_utils::ty::{InteriorMut, needs_ordered_drop}; use clippy_utils::visitors::for_each_expr_without_closures; @@ -567,7 +567,7 @@ fn method_caller_is_mutable<'tcx>( /// Implementation of `IFS_SAME_COND`. fn lint_same_cond<'tcx>(cx: &LateContext<'tcx>, conds: &[&Expr<'_>], interior_mut: &mut InteriorMut<'tcx>) { - for (i, j) in search_same( + for group in search_same( conds, |e| hash_expr(cx, e), |lhs, rhs| { @@ -584,14 +584,8 @@ fn lint_same_cond<'tcx>(cx: &LateContext<'tcx>, conds: &[&Expr<'_>], interior_mu } }, ) { - span_lint_and_note( - cx, - IFS_SAME_COND, - j.span, - "this `if` has the same condition as a previous `if`", - Some(i.span), - "same as this", - ); + let spans: Vec<_> = group.into_iter().map(|expr| expr.span).collect(); + span_lint(cx, IFS_SAME_COND, spans, "these `if` branches have the same condition"); } } @@ -609,14 +603,13 @@ fn lint_same_fns_in_if_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) { SpanlessEq::new(cx).eq_expr(lhs, rhs) }; - for (i, j) in search_same(conds, |e| hash_expr(cx, e), eq) { - span_lint_and_note( + for group in search_same(conds, |e| hash_expr(cx, e), eq) { + let spans: Vec<_> = group.into_iter().map(|expr| expr.span).collect(); + span_lint( cx, SAME_FUNCTIONS_IN_IF_CONDITION, - j.span, - "this `if` has the same function call as a previous `if`", - Some(i.span), - "same as this", + spans, + "these `if` branches have the same function call", ); } } diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index 250f17fa9025a..6de5b5efef0f9 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -1,8 +1,9 @@ -use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{SpanlessEq, SpanlessHash, is_lint_allowed, path_to_local, search_same}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::SpanRangeExt; +use clippy_utils::{SpanlessEq, SpanlessHash, fulfill_or_allowed, is_lint_allowed, path_to_local, search_same}; use core::cmp::Ordering; use core::{iter, slice}; +use itertools::Itertools; use rustc_arena::DroplessArena; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -110,57 +111,68 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { && check_same_body() }; - let mut appl = Applicability::MaybeIncorrect; let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect(); - for (&(i, arm1), &(j, arm2)) in search_same(&indexed_arms, hash, eq) { - if matches!(arm2.pat.kind, PatKind::Wild) { - if !cx.tcx.features().non_exhaustive_omitted_patterns_lint() - || is_lint_allowed(cx, NON_EXHAUSTIVE_OMITTED_PATTERNS, arm2.hir_id) - { - let arm_span = adjusted_arm_span(cx, arm1.span); - span_lint_hir_and_then( - cx, - MATCH_SAME_ARMS, - arm1.hir_id, - arm_span, - "this match arm has an identical body to the `_` wildcard arm", - |diag| { - diag.span_suggestion(arm_span, "try removing the arm", "", appl) - .help("or try changing either arm body") - .span_note(arm2.span, "`_` wildcard arm here"); - }, - ); - } - } else { - let back_block = backwards_blocking_idxs[j]; - let (keep_arm, move_arm) = if back_block < i || (back_block == 0 && forwards_blocking_idxs[i] <= j) { - (arm1, arm2) - } else { - (arm2, arm1) - }; - - span_lint_hir_and_then( - cx, - MATCH_SAME_ARMS, - keep_arm.hir_id, - keep_arm.span, - "this match arm has an identical body to another arm", - |diag| { - let move_pat_snip = snippet_with_applicability(cx, move_arm.pat.span, "", &mut appl); - let keep_pat_snip = snippet_with_applicability(cx, keep_arm.pat.span, "", &mut appl); + for mut group in search_same(&indexed_arms, hash, eq) { + // Filter out (and fulfill) `#[allow]`ed and `#[expect]`ed arms + group.retain(|(_, arm)| !fulfill_or_allowed(cx, MATCH_SAME_ARMS, [arm.hir_id])); - diag.multipart_suggestion( - "or try merging the arm patterns and removing the obsolete arm", - vec![ - (keep_arm.pat.span, format!("{keep_pat_snip} | {move_pat_snip}")), - (adjusted_arm_span(cx, move_arm.span), String::new()), - ], - appl, - ) - .help("try changing either arm body"); - }, - ); + if group.len() < 2 { + continue; } + + span_lint_and_then( + cx, + MATCH_SAME_ARMS, + group.iter().map(|(_, arm)| arm.span).collect_vec(), + "these match arms have identical bodies", + |diag| { + diag.help("if this is unintentional make the arms return different values"); + + if let [prev @ .., (_, last)] = group.as_slice() + && is_wildcard_arm(last.pat) + && is_lint_allowed(cx, NON_EXHAUSTIVE_OMITTED_PATTERNS, last.hir_id) + { + diag.span_label(last.span, "the wildcard arm"); + + let s = if prev.len() > 1 { "s" } else { "" }; + diag.multipart_suggestion_verbose( + format!("otherwise remove the non-wildcard arm{s}"), + prev.iter() + .map(|(_, arm)| (adjusted_arm_span(cx, arm.span), String::new())) + .collect(), + Applicability::MaybeIncorrect, + ); + } else if let &[&(first_idx, _), .., &(last_idx, _)] = group.as_slice() { + let back_block = backwards_blocking_idxs[last_idx]; + let split = if back_block < first_idx + || (back_block == 0 && forwards_blocking_idxs[first_idx] <= last_idx) + { + group.split_first() + } else { + group.split_last() + }; + + if let Some(((_, dest), src)) = split + && let Some(pat_snippets) = group + .iter() + .map(|(_, arm)| arm.pat.span.get_source_text(cx)) + .collect::>>() + { + let mut suggs = src + .iter() + .map(|(_, arm)| (adjusted_arm_span(cx, arm.span), String::new())) + .collect_vec(); + + suggs.push((dest.pat.span, pat_snippets.iter().join(" | "))); + diag.multipart_suggestion_verbose( + "otherwise merge the patterns into a single arm", + suggs, + Applicability::MaybeIncorrect, + ); + } + } + }, + ); } } @@ -449,3 +461,11 @@ fn bindings_eq(pat: &Pat<'_>, mut ids: HirIdSet) -> bool { pat.each_binding_or_first(&mut |_, id, _, _| result &= ids.swap_remove(&id)); result && ids.is_empty() } + +fn is_wildcard_arm(pat: &Pat<'_>) -> bool { + match pat.kind { + PatKind::Wild => true, + PatKind::Or([.., last]) => matches!(last.kind, PatKind::Wild), + _ => false, + } +} diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 551266da02940..cf31cc5281e4c 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -27,6 +27,7 @@ // FIXME: switch to something more ergonomic here, once available. // (Currently there is no way to opt into sysroot crates without `extern crate`.) +extern crate indexmap; extern crate rustc_abi; extern crate rustc_ast; extern crate rustc_attr_parsing; @@ -85,7 +86,6 @@ pub use self::hir_utils::{ use core::mem; use core::ops::ControlFlow; use std::collections::hash_map::Entry; -use std::hash::BuildHasherDefault; use std::iter::{once, repeat_n}; use std::sync::{Mutex, MutexGuard, OnceLock}; @@ -95,7 +95,7 @@ use rustc_ast::ast::{self, LitKind, RangeLimits}; use rustc_attr_parsing::{AttributeKind, find_attr}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::packed::Pu128; -use rustc_data_structures::unhash::UnhashMap; +use rustc_data_structures::unhash::UnindexMap; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId}; @@ -2486,45 +2486,46 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option(exprs: &[T], mut hash: Hash, mut eq: Eq) -> Vec<(&T, &T)> +pub fn search_same(exprs: &[T], mut hash: Hash, mut eq: Eq) -> Vec> where Hash: FnMut(&T) -> u64, Eq: FnMut(&T, &T) -> bool, { match exprs { - [a, b] if eq(a, b) => return vec![(a, b)], + [a, b] if eq(a, b) => return vec![vec![a, b]], _ if exprs.len() <= 2 => return vec![], _ => {}, } - let mut match_expr_list: Vec<(&T, &T)> = Vec::new(); - - let mut map: UnhashMap> = - UnhashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default()); + let mut buckets: UnindexMap>> = UnindexMap::default(); for expr in exprs { - match map.entry(hash(expr)) { - Entry::Occupied(mut o) => { - for o in o.get() { - if eq(o, expr) { - match_expr_list.push((o, expr)); - } + match buckets.entry(hash(expr)) { + indexmap::map::Entry::Occupied(mut o) => { + let bucket = o.get_mut(); + match bucket.iter_mut().find(|group| eq(expr, group[0])) { + Some(group) => group.push(expr), + None => bucket.push(vec![expr]), } - o.get_mut().push(expr); }, - Entry::Vacant(v) => { - v.insert(vec![expr]); + indexmap::map::Entry::Vacant(v) => { + v.insert(vec![vec![expr]]); }, } } - match_expr_list + buckets + .into_values() + .flatten() + .filter(|group| group.len() > 1) + .collect() } /// Peels off all references on the pattern. Returns the underlying pattern and the number of diff --git a/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs b/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs index e953a2a4e90bc..2a6097fb57953 100644 --- a/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs +++ b/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs @@ -11,9 +11,9 @@ fn issue10272() { // should trigger warning let x = Cell::new(true); if x.get() { + //~^ ifs_same_cond } else if !x.take() { } else if x.get() { - //~^ ifs_same_cond } else { } } diff --git a/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr b/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr index d67e7fca6565b..adc44358c4c7b 100644 --- a/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr +++ b/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr @@ -1,14 +1,12 @@ -error: this `if` has the same condition as a previous `if` - --> tests/ui-toml/ifs_same_cond/ifs_same_cond.rs:15:15 - | -LL | } else if x.get() { - | ^^^^^^^ - | -note: same as this +error: these `if` branches have the same condition --> tests/ui-toml/ifs_same_cond/ifs_same_cond.rs:13:8 | LL | if x.get() { | ^^^^^^^ +... +LL | } else if x.get() { + | ^^^^^^^ + | = note: `-D clippy::ifs-same-cond` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::ifs_same_cond)]` diff --git a/tests/ui/ifs_same_cond.rs b/tests/ui/ifs_same_cond.rs index ebc3acb1b77f6..7067434953d6e 100644 --- a/tests/ui/ifs_same_cond.rs +++ b/tests/ui/ifs_same_cond.rs @@ -6,19 +6,25 @@ fn ifs_same_cond() { let b = false; if b { + //~^ ifs_same_cond } else if b { + } + + if b { //~^ ifs_same_cond + } else if b { + } else if b { } if a == 1 { - } else if a == 1 { //~^ ifs_same_cond + } else if a == 1 { } if 2 * a == 1 { + //~^ ifs_same_cond } else if 2 * a == 2 { } else if 2 * a == 1 { - //~^ ifs_same_cond } else if a == 1 { } @@ -50,8 +56,8 @@ fn ifs_same_cond() { fn issue10272() { let a = String::from("ha"); if a.contains("ah") { - } else if a.contains("ah") { //~^ ifs_same_cond + } else if a.contains("ah") { // Trigger this lint } else if a.contains("ha") { diff --git a/tests/ui/ifs_same_cond.stderr b/tests/ui/ifs_same_cond.stderr index df21e6f1b8262..7acbc1a6399b6 100644 --- a/tests/ui/ifs_same_cond.stderr +++ b/tests/ui/ifs_same_cond.stderr @@ -1,52 +1,52 @@ -error: this `if` has the same condition as a previous `if` - --> tests/ui/ifs_same_cond.rs:9:15 - | -LL | } else if b { - | ^ - | -note: same as this +error: these `if` branches have the same condition --> tests/ui/ifs_same_cond.rs:8:8 | LL | if b { | ^ +LL | +LL | } else if b { + | ^ + | = note: `-D clippy::ifs-same-cond` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::ifs_same_cond)]` -error: this `if` has the same condition as a previous `if` - --> tests/ui/ifs_same_cond.rs:14:15 - | -LL | } else if a == 1 { - | ^^^^^^ - | -note: same as this +error: these `if` branches have the same condition --> tests/ui/ifs_same_cond.rs:13:8 | +LL | if b { + | ^ +LL | +LL | } else if b { + | ^ +LL | } else if b { + | ^ + +error: these `if` branches have the same condition + --> tests/ui/ifs_same_cond.rs:19:8 + | LL | if a == 1 { | ^^^^^^ +LL | +LL | } else if a == 1 { + | ^^^^^^ -error: this `if` has the same condition as a previous `if` - --> tests/ui/ifs_same_cond.rs:20:15 - | -LL | } else if 2 * a == 1 { - | ^^^^^^^^^^ - | -note: same as this - --> tests/ui/ifs_same_cond.rs:18:8 +error: these `if` branches have the same condition + --> tests/ui/ifs_same_cond.rs:24:8 | LL | if 2 * a == 1 { | ^^^^^^^^^^ +... +LL | } else if 2 * a == 1 { + | ^^^^^^^^^^ -error: this `if` has the same condition as a previous `if` - --> tests/ui/ifs_same_cond.rs:53:15 - | -LL | } else if a.contains("ah") { - | ^^^^^^^^^^^^^^^^ - | -note: same as this - --> tests/ui/ifs_same_cond.rs:52:8 +error: these `if` branches have the same condition + --> tests/ui/ifs_same_cond.rs:58:8 | LL | if a.contains("ah") { | ^^^^^^^^^^^^^^^^ +LL | +LL | } else if a.contains("ah") { + | ^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/match_same_arms.fixed b/tests/ui/match_same_arms.fixed new file mode 100644 index 0000000000000..31684a5759fe9 --- /dev/null +++ b/tests/ui/match_same_arms.fixed @@ -0,0 +1,142 @@ +#![allow(clippy::manual_range_patterns)] +#![warn(clippy::match_same_arms)] + +pub enum Abc { + A, + B, + C, +} + +fn match_same_arms() { + let _ = match Abc::A { + Abc::B => 1, + _ => 0, + //~^ match_same_arms + }; + + match 0 { + 1 => 'a', + _ => 'b', + //~^ match_same_arms + }; + + match (1, 2, 3) { + (1, .., 3) | (.., 3) => 42, + //~^ match_same_arms + _ => 0, + }; + + let _ = match 42 { + //~^ match_same_arms + 42 | 51 => 1, + 41 | 52 => 2, + //~^ match_same_arms + _ => 0, + }; + + let _ = match 42 { + //~^ match_same_arms + 1 | 2 | 3 => 2, + 4 => 3, + _ => 0, + }; +} + +mod issue4244 { + #[derive(PartialEq, PartialOrd, Eq, Ord)] + pub enum CommandInfo { + BuiltIn { name: String, about: Option }, + External { name: String, path: std::path::PathBuf }, + } + + impl CommandInfo { + pub fn name(&self) -> String { + match self { + //~^ match_same_arms + CommandInfo::BuiltIn { name, .. } | CommandInfo::External { name, .. } => name.to_string(), + } + } + } +} + +macro_rules! m { + (foo) => {}; + (bar) => {}; +} +macro_rules! foo { + () => { + 1 + }; +} +macro_rules! bar { + () => { + 1 + }; +} + +fn main() { + let x = 0; + let _ = match 0 { + 0 => { + m!(foo); + x + }, + 1 => { + m!(bar); + x + }, + _ => 1, + }; + + let _ = match 0 { + 0 => { + m!(foo); + 0 + }, + 1 => { + m!(bar); + 0 + }, + _ => 1, + }; + + let _ = match 0 { + 0 => { + let mut x = 0; + #[cfg(not_enabled)] + { + x = 5; + } + #[cfg(not(not_enabled))] + { + x = 6; + } + x + }, + 1 => { + let mut x = 0; + #[cfg(also_not_enabled)] + { + x = 5; + } + #[cfg(not(also_not_enabled))] + { + x = 6; + } + x + }, + _ => 0, + }; + + let _ = match 0 { + 0 => foo!(), + 1 => bar!(), + _ => 1, + }; + + let _ = match 0 { + 0 => cfg!(not_enabled), + 1 => cfg!(also_not_enabled), + _ => false, + }; +} diff --git a/tests/ui/match_same_arms.rs b/tests/ui/match_same_arms.rs index 55441948e91b6..39bee01bac22b 100644 --- a/tests/ui/match_same_arms.rs +++ b/tests/ui/match_same_arms.rs @@ -1,4 +1,4 @@ -//@no-rustfix: overlapping suggestions +#![allow(clippy::manual_range_patterns)] #![warn(clippy::match_same_arms)] pub enum Abc { @@ -10,9 +10,17 @@ pub enum Abc { fn match_same_arms() { let _ = match Abc::A { Abc::A => 0, - //~^ match_same_arms Abc::B => 1, _ => 0, + //~^ match_same_arms + }; + + match 0 { + 1 => 'a', + 2 => 'b', + 3 => 'b', + _ => 'b', + //~^ match_same_arms }; match (1, 2, 3) { @@ -24,8 +32,8 @@ fn match_same_arms() { let _ = match 42 { 42 => 1, - 51 => 1, //~^ match_same_arms + 51 => 1, 41 => 2, //~^ match_same_arms 52 => 2, @@ -34,11 +42,9 @@ fn match_same_arms() { let _ = match 42 { 1 => 2, - 2 => 2, //~^ match_same_arms - //~| match_same_arms + 2 => 2, 3 => 2, - //~^ match_same_arms 4 => 3, _ => 0, }; @@ -55,8 +61,8 @@ mod issue4244 { pub fn name(&self) -> String { match self { CommandInfo::BuiltIn { name, .. } => name.to_string(), - CommandInfo::External { name, .. } => name.to_string(), //~^ match_same_arms + CommandInfo::External { name, .. } => name.to_string(), } } } diff --git a/tests/ui/match_same_arms.stderr b/tests/ui/match_same_arms.stderr index 3744b83d89cc8..8aa60f8357663 100644 --- a/tests/ui/match_same_arms.stderr +++ b/tests/ui/match_same_arms.stderr @@ -1,118 +1,121 @@ -error: this match arm has an identical body to the `_` wildcard arm +error: these match arms have identical bodies --> tests/ui/match_same_arms.rs:12:9 | -LL | / Abc::A => 0, -LL | | - | |________^ help: try removing the arm - | - = help: or try changing either arm body -note: `_` wildcard arm here - --> tests/ui/match_same_arms.rs:15:9 - | +LL | Abc::A => 0, + | ^^^^^^^^^^^ +LL | Abc::B => 1, LL | _ => 0, - | ^^^^^^ + | ^^^^^^ the wildcard arm + | + = help: if this is unintentional make the arms return different values = note: `-D clippy::match-same-arms` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]` +help: otherwise remove the non-wildcard arm + | +LL - Abc::A => 0, + | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms.rs:19:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms.rs:20:9 + | +LL | 2 => 'b', + | ^^^^^^^^ +LL | 3 => 'b', + | ^^^^^^^^ +LL | _ => 'b', + | ^^^^^^^^ the wildcard arm + | + = help: if this is unintentional make the arms return different values +help: otherwise remove the non-wildcard arms + | +LL - 2 => 'b', +LL - 3 => 'b', +LL + _ => 'b', + | + +error: these match arms have identical bodies + --> tests/ui/match_same_arms.rs:27:9 | LL | (1, .., 3) => 42, | ^^^^^^^^^^^^^^^^ +LL | +LL | (.., 3) => 42, + | ^^^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | LL ~ (1, .., 3) | (.., 3) => 42, LL | LL ~ _ => 0, | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms.rs:27:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms.rs:34:9 | +LL | 42 => 1, + | ^^^^^^^ +LL | LL | 51 => 1, | ^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | -LL - 42 => 1, -LL - 51 => 1, -LL + 51 | 42 => 1, +LL ~ +LL ~ 42 | 51 => 1, | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms.rs:29:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms.rs:37:9 | LL | 41 => 2, | ^^^^^^^ +LL | +LL | 52 => 2, + | ^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | LL ~ 41 | 52 => 2, LL | LL ~ _ => 0, | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms.rs:37:9 - | -LL | 2 => 2, - | ^^^^^^ - | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm - | -LL - 1 => 2, -LL - 2 => 2, -LL + 2 | 1 => 2, - | - -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms.rs:40:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms.rs:44:9 | -LL | 3 => 2, +LL | 1 => 2, | ^^^^^^ - | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm - | -LL ~ 2 => 2, -LL | LL | -LL ~ 3 | 1 => 2, - | - -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms.rs:37:9 - | LL | 2 => 2, | ^^^^^^ +LL | 3 => 2, + | ^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | -LL ~ 2 | 3 => 2, -LL | -LL | LL ~ +LL ~ 1 | 2 | 3 => 2, | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms.rs:58:17 +error: these match arms have identical bodies + --> tests/ui/match_same_arms.rs:63:17 | +LL | CommandInfo::BuiltIn { name, .. } => name.to_string(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | CommandInfo::External { name, .. } => name.to_string(), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | -LL - CommandInfo::BuiltIn { name, .. } => name.to_string(), -LL - CommandInfo::External { name, .. } => name.to_string(), -LL + CommandInfo::External { name, .. } | CommandInfo::BuiltIn { name, .. } => name.to_string(), +LL ~ +LL ~ CommandInfo::BuiltIn { name, .. } | CommandInfo::External { name, .. } => name.to_string(), | -error: aborting due to 8 previous errors +error: aborting due to 7 previous errors diff --git a/tests/ui/match_same_arms2.fixed b/tests/ui/match_same_arms2.fixed index 0d93e2c728d75..cb860cef1e688 100644 --- a/tests/ui/match_same_arms2.fixed +++ b/tests/ui/match_same_arms2.fixed @@ -14,7 +14,7 @@ fn foo() -> bool { fn match_same_arms() { let _ = match 42 { - //~^^^^^^^^^ match_same_arms + //~v match_same_arms _ => { foo(); let mut a = 42 + [23].len() as i32; @@ -27,14 +27,14 @@ fn match_same_arms() { }; let _ = match 42 { - 51 | 42 => foo(), //~^ match_same_arms + 42 | 51 => foo(), _ => true, }; let _ = match Some(42) { - None | Some(_) => 24, //~^ match_same_arms + Some(_) | None => 24, }; let _ = match Some(42) { @@ -55,8 +55,8 @@ fn match_same_arms() { }; match (Some(42), Some(42)) { - (None, Some(a)) | (Some(a), None) => bar(a), //~^ match_same_arms + (Some(a), None) | (None, Some(a)) => bar(a), _ => (), } @@ -69,8 +69,8 @@ fn match_same_arms() { }; let _ = match (Some(42), Some(42)) { - (None, Some(a)) | (Some(a), None) if a == 42 => a, //~^ match_same_arms + (Some(a), None) | (None, Some(a)) if a == 42 => a, _ => 0, }; @@ -124,8 +124,8 @@ fn match_same_arms() { // False negative #2251. match x { Ok(_tmp) => println!("ok"), - Ok(_) | Ok(3) => println!("ok"), //~^ match_same_arms + Ok(3) | Ok(_) => println!("ok"), Err(_) => { unreachable!(); }, @@ -149,10 +149,10 @@ fn match_same_arms() { // still lint if the tokens are the same match 0 { - 1 | 0 => { + //~^^^ match_same_arms + 0 | 1 => { empty!(0); }, - //~^^^ match_same_arms x => { empty!(x); }, @@ -208,9 +208,9 @@ fn main() { // Suggest moving `Foo::X(0)` down. let _ = match Foo::X(0) { - Foo::Y(_) | Foo::Z(0) => 2, - Foo::Z(_) | Foo::X(0) => 1, //~^ match_same_arms + Foo::Y(_) | Foo::Z(0) => 2, + Foo::X(0) | Foo::Z(_) => 1, _ => 0, }; @@ -230,10 +230,10 @@ fn main() { // Lint. let _ = match None { + //~^ match_same_arms Some(Bar { y: 10, z: 0, .. }) => 2, None => 50, - Some(Bar { y: 0, x: 5, .. }) | Some(Bar { x: 0, y: 5, .. }) => 1, - //~^ match_same_arms + Some(Bar { x: 0, y: 5, .. }) | Some(Bar { y: 0, x: 5, .. }) => 1, _ => 200, }; @@ -246,8 +246,8 @@ fn main() { }; let _ = match 0 { - 1 | 0 => cfg!(not_enable), //~^ match_same_arms + 0 | 1 => cfg!(not_enable), _ => false, }; } @@ -262,9 +262,34 @@ mod with_lifetime { impl<'a> MaybeStaticStr<'a> { fn get(&self) -> &'a str { match *self { - MaybeStaticStr::Borrowed(s) | MaybeStaticStr::Static(s) => s, //~^ match_same_arms + MaybeStaticStr::Static(s) | MaybeStaticStr::Borrowed(s) => s, } } } } + +fn lint_levels() { + match 1 { + 0 => "a", + 1 => "b", + #[expect(clippy::match_same_arms)] + _ => "b", + }; + + match 2 { + 0 => "a", + 1 | 2 => "b", + //~^ match_same_arms + #[allow(clippy::match_same_arms)] + _ => "b", + }; + + match 3 { + 0 => "a", + 1 | 2 => "b", + //~^ match_same_arms + #[expect(clippy::match_same_arms)] + _ => "b", + }; +} diff --git a/tests/ui/match_same_arms2.rs b/tests/ui/match_same_arms2.rs index b0ebc4784f331..0fd5d76e7d3e7 100644 --- a/tests/ui/match_same_arms2.rs +++ b/tests/ui/match_same_arms2.rs @@ -23,7 +23,7 @@ fn match_same_arms() { a = -31 - a; a }, - //~^^^^^^^^^ match_same_arms + //~v match_same_arms _ => { foo(); let mut a = 42 + [23].len() as i32; @@ -37,15 +37,15 @@ fn match_same_arms() { let _ = match 42 { 42 => foo(), - 51 => foo(), //~^ match_same_arms + 51 => foo(), _ => true, }; let _ = match Some(42) { Some(_) => 24, - None => 24, //~^ match_same_arms + None => 24, }; let _ = match Some(42) { @@ -67,8 +67,8 @@ fn match_same_arms() { match (Some(42), Some(42)) { (Some(a), None) => bar(a), - (None, Some(a)) => bar(a), //~^ match_same_arms + (None, Some(a)) => bar(a), _ => (), } @@ -82,8 +82,8 @@ fn match_same_arms() { let _ = match (Some(42), Some(42)) { (Some(a), None) if a == 42 => a, - (None, Some(a)) if a == 42 => a, //~^ match_same_arms + (None, Some(a)) if a == 42 => a, _ => 0, }; @@ -140,8 +140,8 @@ fn match_same_arms() { match x { Ok(_tmp) => println!("ok"), Ok(3) => println!("ok"), - Ok(_) => println!("ok"), //~^ match_same_arms + Ok(_) => println!("ok"), Err(_) => { unreachable!(); }, @@ -168,10 +168,10 @@ fn match_same_arms() { 0 => { empty!(0); }, + //~^^^ match_same_arms 1 => { empty!(0); }, - //~^^^ match_same_arms x => { empty!(x); }, @@ -229,9 +229,9 @@ fn main() { // Suggest moving `Foo::X(0)` down. let _ = match Foo::X(0) { Foo::X(0) => 1, + //~^ match_same_arms Foo::Y(_) | Foo::Z(0) => 2, Foo::Z(_) => 1, - //~^ match_same_arms _ => 0, }; @@ -252,10 +252,10 @@ fn main() { // Lint. let _ = match None { Some(Bar { x: 0, y: 5, .. }) => 1, + //~^ match_same_arms Some(Bar { y: 10, z: 0, .. }) => 2, None => 50, Some(Bar { y: 0, x: 5, .. }) => 1, - //~^ match_same_arms _ => 200, }; @@ -269,8 +269,8 @@ fn main() { let _ = match 0 { 0 => cfg!(not_enable), - 1 => cfg!(not_enable), //~^ match_same_arms + 1 => cfg!(not_enable), _ => false, }; } @@ -286,9 +286,36 @@ mod with_lifetime { fn get(&self) -> &'a str { match *self { MaybeStaticStr::Static(s) => s, - MaybeStaticStr::Borrowed(s) => s, //~^ match_same_arms + MaybeStaticStr::Borrowed(s) => s, } } } } + +fn lint_levels() { + match 1 { + 0 => "a", + 1 => "b", + #[expect(clippy::match_same_arms)] + _ => "b", + }; + + match 2 { + 0 => "a", + 1 => "b", + //~^ match_same_arms + 2 => "b", + #[allow(clippy::match_same_arms)] + _ => "b", + }; + + match 3 { + 0 => "a", + 1 => "b", + //~^ match_same_arms + 2 => "b", + #[expect(clippy::match_same_arms)] + _ => "b", + }; +} diff --git a/tests/ui/match_same_arms2.stderr b/tests/ui/match_same_arms2.stderr index 21a8743cc3242..f3031619cce56 100644 --- a/tests/ui/match_same_arms2.stderr +++ b/tests/ui/match_same_arms2.stderr @@ -1,4 +1,4 @@ -error: this match arm has an identical body to the `_` wildcard arm +error: these match arms have identical bodies --> tests/ui/match_same_arms2.rs:17:9 | LL | / 42 => { @@ -6,14 +6,10 @@ LL | | foo(); LL | | let mut a = 42 + [23].len() as i32; LL | | if true { ... | +LL | | a LL | | }, -LL | | - | |________^ help: try removing the arm - | - = help: or try changing either arm body -note: `_` wildcard arm here - --> tests/ui/match_same_arms2.rs:27:9 - | + | |_________^ +LL | LL | / _ => { LL | | foo(); LL | | let mut a = 42 + [23].len() as i32; @@ -21,134 +17,169 @@ LL | | if true { ... | LL | | a LL | | }, - | |_________^ + | |_________^ the wildcard arm + | + = help: if this is unintentional make the arms return different values = note: `-D clippy::match-same-arms` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]` +help: otherwise remove the non-wildcard arm + | +LL - 42 => { +LL - foo(); +LL - let mut a = 42 + [23].len() as i32; +LL - if true { +LL - a += 7; +LL - } +LL - a = -31 - a; +LL - a +LL - }, + | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:40:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms2.rs:39:9 | +LL | 42 => foo(), + | ^^^^^^^^^^^ +LL | LL | 51 => foo(), | ^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | -LL - 42 => foo(), -LL - 51 => foo(), -LL + 51 | 42 => foo(), +LL ~ +LL ~ 42 | 51 => foo(), | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:47:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms2.rs:46:9 | +LL | Some(_) => 24, + | ^^^^^^^^^^^^^ +LL | LL | None => 24, | ^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | -LL - Some(_) => 24, -LL - None => 24, -LL + None | Some(_) => 24, +LL ~ +LL ~ Some(_) | None => 24, | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:70:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms2.rs:69:9 | +LL | (Some(a), None) => bar(a), + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | (None, Some(a)) => bar(a), | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | -LL - (Some(a), None) => bar(a), -LL - (None, Some(a)) => bar(a), -LL + (None, Some(a)) | (Some(a), None) => bar(a), +LL ~ +LL ~ (Some(a), None) | (None, Some(a)) => bar(a), | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:85:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms2.rs:84:9 | +LL | (Some(a), None) if a == 42 => a, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | (None, Some(a)) if a == 42 => a, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | -LL - (Some(a), None) if a == 42 => a, -LL - (None, Some(a)) if a == 42 => a, -LL + (None, Some(a)) | (Some(a), None) if a == 42 => a, +LL ~ +LL ~ (Some(a), None) | (None, Some(a)) if a == 42 => a, | -error: this match arm has an identical body to another arm +error: these match arms have identical bodies --> tests/ui/match_same_arms2.rs:91:9 | LL | (Some(a), ..) => bar(a), | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | (.., Some(a)) => bar(a), + | ^^^^^^^^^^^^^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | LL ~ (Some(a), ..) | (.., Some(a)) => bar(a), LL | LL ~ _ => (), | -error: this match arm has an identical body to another arm +error: these match arms have identical bodies --> tests/ui/match_same_arms2.rs:126:9 | LL | (Ok(x), Some(_)) => println!("ok {}", x), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | (Ok(_), Some(x)) => println!("ok {}", x), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | LL ~ (Ok(x), Some(_)) | (Ok(_), Some(x)) => println!("ok {}", x), LL | LL ~ _ => println!("err"), | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:143:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms2.rs:142:9 | +LL | Ok(3) => println!("ok"), + | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | Ok(_) => println!("ok"), | ^^^^^^^^^^^^^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | -LL - Ok(3) => println!("ok"), -LL - Ok(_) => println!("ok"), -LL + Ok(_) | Ok(3) => println!("ok"), +LL ~ +LL ~ Ok(3) | Ok(_) => println!("ok"), | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:171:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms2.rs:168:9 | +LL | / 0 => { +LL | | empty!(0); +LL | | }, + | |_________^ +LL | LL | / 1 => { LL | | empty!(0); LL | | }, | |_________^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | -LL - 0 => { -LL - empty!(0); -LL - }, -LL - 1 => { -LL + 1 | 0 => { +LL ~ +LL ~ 0 | 1 => { | -error: this match arm has an identical body to another arm +error: these match arms have identical bodies --> tests/ui/match_same_arms2.rs:222:9 | LL | Foo::X(0) => 1, | ^^^^^^^^^^^^^^ +... +LL | Foo::Z(_) => 1, + | ^^^^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | LL ~ Foo::X(0) | Foo::Z(_) => 1, LL | @@ -156,60 +187,106 @@ LL | Foo::X(_) | Foo::Y(_) => 2, LL ~ _ => 0, | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:233:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms2.rs:231:9 | +LL | Foo::X(0) => 1, + | ^^^^^^^^^^^^^^ +... LL | Foo::Z(_) => 1, | ^^^^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | -LL ~ Foo::Y(_) | Foo::Z(0) => 2, -LL ~ Foo::Z(_) | Foo::X(0) => 1, +LL ~ +LL | Foo::Y(_) | Foo::Z(0) => 2, +LL ~ Foo::X(0) | Foo::Z(_) => 1, | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:257:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms2.rs:254:9 | +LL | Some(Bar { x: 0, y: 5, .. }) => 1, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... LL | Some(Bar { y: 0, x: 5, .. }) => 1, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | -LL ~ Some(Bar { y: 10, z: 0, .. }) => 2, +LL ~ +LL | Some(Bar { y: 10, z: 0, .. }) => 2, LL | None => 50, -LL ~ Some(Bar { y: 0, x: 5, .. }) | Some(Bar { x: 0, y: 5, .. }) => 1, +LL ~ Some(Bar { x: 0, y: 5, .. }) | Some(Bar { y: 0, x: 5, .. }) => 1, | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:272:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms2.rs:271:9 | +LL | 0 => cfg!(not_enable), + | ^^^^^^^^^^^^^^^^^^^^^ +LL | LL | 1 => cfg!(not_enable), | ^^^^^^^^^^^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | -LL - 0 => cfg!(not_enable), -LL - 1 => cfg!(not_enable), -LL + 1 | 0 => cfg!(not_enable), +LL ~ +LL ~ 0 | 1 => cfg!(not_enable), | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:289:17 +error: these match arms have identical bodies + --> tests/ui/match_same_arms2.rs:288:17 | +LL | MaybeStaticStr::Static(s) => s, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | MaybeStaticStr::Borrowed(s) => s, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm + | +LL ~ +LL ~ MaybeStaticStr::Static(s) | MaybeStaticStr::Borrowed(s) => s, | -LL - MaybeStaticStr::Static(s) => s, -LL - MaybeStaticStr::Borrowed(s) => s, -LL + MaybeStaticStr::Borrowed(s) | MaybeStaticStr::Static(s) => s, + +error: these match arms have identical bodies + --> tests/ui/match_same_arms2.rs:306:9 + | +LL | 1 => "b", + | ^^^^^^^^ +LL | +LL | 2 => "b", + | ^^^^^^^^ + | + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm + | +LL ~ 1 | 2 => "b", +LL | +LL ~ #[allow(clippy::match_same_arms)] + | + +error: these match arms have identical bodies + --> tests/ui/match_same_arms2.rs:315:9 + | +LL | 1 => "b", + | ^^^^^^^^ +LL | +LL | 2 => "b", + | ^^^^^^^^ + | + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm + | +LL ~ 1 | 2 => "b", +LL | +LL ~ #[expect(clippy::match_same_arms)] | -error: aborting due to 14 previous errors +error: aborting due to 16 previous errors diff --git a/tests/ui/match_same_arms_non_exhaustive.fixed b/tests/ui/match_same_arms_non_exhaustive.fixed index 0c9398933b80e..61a5bd0323a88 100644 --- a/tests/ui/match_same_arms_non_exhaustive.fixed +++ b/tests/ui/match_same_arms_non_exhaustive.fixed @@ -7,14 +7,22 @@ fn repeat() -> ! { panic!() } +#[deny(non_exhaustive_omitted_patterns)] pub fn f(x: Ordering) { - #[deny(non_exhaustive_omitted_patterns)] match x { Ordering::Relaxed => println!("relaxed"), Ordering::Release => println!("release"), Ordering::Acquire => println!("acquire"), - Ordering::AcqRel | Ordering::SeqCst => repeat(), - _ => repeat(), + //~^ match_same_arms + Ordering::AcqRel | Ordering::SeqCst | _ => repeat(), + } + + match x { + Ordering::Relaxed => println!("relaxed"), + Ordering::Release => println!("release"), + Ordering::Acquire => println!("acquire"), + //~^ match_same_arms + Ordering::AcqRel | Ordering::SeqCst | _ => repeat(), } } @@ -28,21 +36,21 @@ mod f { Ordering::Relaxed => println!("relaxed"), Ordering::Release => println!("release"), Ordering::Acquire => println!("acquire"), - Ordering::AcqRel | Ordering::SeqCst => repeat(), - _ => repeat(), + //~^ match_same_arms + Ordering::AcqRel | Ordering::SeqCst | _ => repeat(), } } } -// Below should still lint +// Below can still suggest removing the other patterns pub fn g(x: Ordering) { match x { Ordering::Relaxed => println!("relaxed"), Ordering::Release => println!("release"), Ordering::Acquire => println!("acquire"), - //~^ match_same_arms _ => repeat(), + //~^ match_same_arms } } @@ -54,8 +62,8 @@ mod g { Ordering::Relaxed => println!("relaxed"), Ordering::Release => println!("release"), Ordering::Acquire => println!("acquire"), - //~^ match_same_arms _ => repeat(), + //~^ match_same_arms } } } diff --git a/tests/ui/match_same_arms_non_exhaustive.rs b/tests/ui/match_same_arms_non_exhaustive.rs index 304a9e5c28e76..66f65eb39d0a9 100644 --- a/tests/ui/match_same_arms_non_exhaustive.rs +++ b/tests/ui/match_same_arms_non_exhaustive.rs @@ -7,15 +7,25 @@ fn repeat() -> ! { panic!() } +#[deny(non_exhaustive_omitted_patterns)] pub fn f(x: Ordering) { - #[deny(non_exhaustive_omitted_patterns)] match x { Ordering::Relaxed => println!("relaxed"), Ordering::Release => println!("release"), Ordering::Acquire => println!("acquire"), Ordering::AcqRel | Ordering::SeqCst => repeat(), + //~^ match_same_arms _ => repeat(), } + + match x { + Ordering::Relaxed => println!("relaxed"), + Ordering::Release => println!("release"), + Ordering::Acquire => println!("acquire"), + Ordering::AcqRel => repeat(), + //~^ match_same_arms + Ordering::SeqCst | _ => repeat(), + } } mod f { @@ -29,12 +39,13 @@ mod f { Ordering::Release => println!("release"), Ordering::Acquire => println!("acquire"), Ordering::AcqRel | Ordering::SeqCst => repeat(), + //~^ match_same_arms _ => repeat(), } } } -// Below should still lint +// Below can still suggest removing the other patterns pub fn g(x: Ordering) { match x { @@ -42,8 +53,8 @@ pub fn g(x: Ordering) { Ordering::Release => println!("release"), Ordering::Acquire => println!("acquire"), Ordering::AcqRel | Ordering::SeqCst => repeat(), - //~^ match_same_arms _ => repeat(), + //~^ match_same_arms } } @@ -56,8 +67,8 @@ mod g { Ordering::Release => println!("release"), Ordering::Acquire => println!("acquire"), Ordering::AcqRel | Ordering::SeqCst => repeat(), - //~^ match_same_arms _ => repeat(), + //~^ match_same_arms } } } diff --git a/tests/ui/match_same_arms_non_exhaustive.stderr b/tests/ui/match_same_arms_non_exhaustive.stderr index aa7f8c95dce84..03252f346c6cc 100644 --- a/tests/ui/match_same_arms_non_exhaustive.stderr +++ b/tests/ui/match_same_arms_non_exhaustive.stderr @@ -1,32 +1,80 @@ -error: this match arm has an identical body to the `_` wildcard arm - --> tests/ui/match_same_arms_non_exhaustive.rs:44:9 - | -LL | / Ordering::AcqRel | Ordering::SeqCst => repeat(), -LL | | - | |________^ help: try removing the arm - | - = help: or try changing either arm body -note: `_` wildcard arm here - --> tests/ui/match_same_arms_non_exhaustive.rs:46:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms_non_exhaustive.rs:16:9 | +LL | Ordering::AcqRel | Ordering::SeqCst => repeat(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | _ => repeat(), | ^^^^^^^^^^^^^ + | + = help: if this is unintentional make the arms return different values = note: `-D clippy::match-same-arms` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]` +help: otherwise merge the patterns into a single arm + | +LL ~ +LL ~ Ordering::AcqRel | Ordering::SeqCst | _ => repeat(), + | -error: this match arm has an identical body to the `_` wildcard arm - --> tests/ui/match_same_arms_non_exhaustive.rs:58:13 +error: these match arms have identical bodies + --> tests/ui/match_same_arms_non_exhaustive.rs:25:9 + | +LL | Ordering::AcqRel => repeat(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | Ordering::SeqCst | _ => repeat(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -LL | / Ordering::AcqRel | Ordering::SeqCst => repeat(), -LL | | - | |____________^ help: try removing the arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | - = help: or try changing either arm body -note: `_` wildcard arm here - --> tests/ui/match_same_arms_non_exhaustive.rs:60:13 +LL ~ +LL ~ Ordering::AcqRel | Ordering::SeqCst | _ => repeat(), | + +error: these match arms have identical bodies + --> tests/ui/match_same_arms_non_exhaustive.rs:41:13 + | +LL | Ordering::AcqRel | Ordering::SeqCst => repeat(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | _ => repeat(), | ^^^^^^^^^^^^^ + | + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm + | +LL ~ +LL ~ Ordering::AcqRel | Ordering::SeqCst | _ => repeat(), + | + +error: these match arms have identical bodies + --> tests/ui/match_same_arms_non_exhaustive.rs:55:9 + | +LL | Ordering::AcqRel | Ordering::SeqCst => repeat(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | _ => repeat(), + | ^^^^^^^^^^^^^ the wildcard arm + | + = help: if this is unintentional make the arms return different values +help: otherwise remove the non-wildcard arm + | +LL - Ordering::AcqRel | Ordering::SeqCst => repeat(), + | + +error: these match arms have identical bodies + --> tests/ui/match_same_arms_non_exhaustive.rs:69:13 + | +LL | Ordering::AcqRel | Ordering::SeqCst => repeat(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | _ => repeat(), + | ^^^^^^^^^^^^^ the wildcard arm + | + = help: if this is unintentional make the arms return different values +help: otherwise remove the non-wildcard arm + | +LL - Ordering::AcqRel | Ordering::SeqCst => repeat(), + | -error: aborting due to 2 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/same_functions_in_if_condition.rs b/tests/ui/same_functions_in_if_condition.rs index a98b73c9e1c82..3f205b322ab08 100644 --- a/tests/ui/same_functions_in_if_condition.rs +++ b/tests/ui/same_functions_in_if_condition.rs @@ -31,34 +31,34 @@ fn ifs_same_cond_fn() { let obj = Struct; if function() { - } else if function() { //~^ same_functions_in_if_condition + } else if function() { } if fn_arg(a) { - } else if fn_arg(a) { //~^ same_functions_in_if_condition + } else if fn_arg(a) { } if obj.method() { - } else if obj.method() { //~^ same_functions_in_if_condition + } else if obj.method() { } if obj.method_arg(a) { - } else if obj.method_arg(a) { //~^ same_functions_in_if_condition + } else if obj.method_arg(a) { } let mut v = vec![1]; if v.pop().is_none() { - } else if v.pop().is_none() { //~^ same_functions_in_if_condition + } else if v.pop().is_none() { } if v.len() == 42 { - } else if v.len() == 42 { //~^ same_functions_in_if_condition + } else if v.len() == 42 { } if v.len() == 1 { diff --git a/tests/ui/same_functions_in_if_condition.stderr b/tests/ui/same_functions_in_if_condition.stderr index 35dcbadce5953..59f4511757d61 100644 --- a/tests/ui/same_functions_in_if_condition.stderr +++ b/tests/ui/same_functions_in_if_condition.stderr @@ -1,79 +1,62 @@ -error: this `if` has the same function call as a previous `if` - --> tests/ui/same_functions_in_if_condition.rs:34:15 - | -LL | } else if function() { - | ^^^^^^^^^^ - | -note: same as this +error: these `if` branches have the same function call --> tests/ui/same_functions_in_if_condition.rs:33:8 | LL | if function() { | ^^^^^^^^^^ +LL | +LL | } else if function() { + | ^^^^^^^^^^ + | note: the lint level is defined here --> tests/ui/same_functions_in_if_condition.rs:2:9 | LL | #![deny(clippy::same_functions_in_if_condition)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: this `if` has the same function call as a previous `if` - --> tests/ui/same_functions_in_if_condition.rs:39:15 - | -LL | } else if fn_arg(a) { - | ^^^^^^^^^ - | -note: same as this +error: these `if` branches have the same function call --> tests/ui/same_functions_in_if_condition.rs:38:8 | LL | if fn_arg(a) { | ^^^^^^^^^ +LL | +LL | } else if fn_arg(a) { + | ^^^^^^^^^ -error: this `if` has the same function call as a previous `if` - --> tests/ui/same_functions_in_if_condition.rs:44:15 - | -LL | } else if obj.method() { - | ^^^^^^^^^^^^ - | -note: same as this +error: these `if` branches have the same function call --> tests/ui/same_functions_in_if_condition.rs:43:8 | LL | if obj.method() { | ^^^^^^^^^^^^ +LL | +LL | } else if obj.method() { + | ^^^^^^^^^^^^ -error: this `if` has the same function call as a previous `if` - --> tests/ui/same_functions_in_if_condition.rs:49:15 - | -LL | } else if obj.method_arg(a) { - | ^^^^^^^^^^^^^^^^^ - | -note: same as this +error: these `if` branches have the same function call --> tests/ui/same_functions_in_if_condition.rs:48:8 | LL | if obj.method_arg(a) { | ^^^^^^^^^^^^^^^^^ - -error: this `if` has the same function call as a previous `if` - --> tests/ui/same_functions_in_if_condition.rs:55:15 - | -LL | } else if v.pop().is_none() { +LL | +LL | } else if obj.method_arg(a) { | ^^^^^^^^^^^^^^^^^ - | -note: same as this + +error: these `if` branches have the same function call --> tests/ui/same_functions_in_if_condition.rs:54:8 | LL | if v.pop().is_none() { | ^^^^^^^^^^^^^^^^^ +LL | +LL | } else if v.pop().is_none() { + | ^^^^^^^^^^^^^^^^^ -error: this `if` has the same function call as a previous `if` - --> tests/ui/same_functions_in_if_condition.rs:60:15 - | -LL | } else if v.len() == 42 { - | ^^^^^^^^^^^^^ - | -note: same as this +error: these `if` branches have the same function call --> tests/ui/same_functions_in_if_condition.rs:59:8 | LL | if v.len() == 42 { | ^^^^^^^^^^^^^ +LL | +LL | } else if v.len() == 42 { + | ^^^^^^^^^^^^^ error: aborting due to 6 previous errors From 5240cd3a8210ab56fe5710048f7ab719cbba16a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Fri, 16 May 2025 15:46:44 +0200 Subject: [PATCH 2350/4206] Implement `advance_by` via `try_fold` for `Sized` iterators When `try_fold` is overriden, it is usually easier for compilers to optimize. --- library/core/src/iter/traits/iterator.rs | 36 ++++++++++++++++++++---- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index d1e71f0e60f2a..fab403ce8535a 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -294,13 +294,39 @@ pub trait Iterator { #[inline] #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { - for i in 0..n { - if self.next().is_none() { - // SAFETY: `i` is always less than `n`. - return Err(unsafe { NonZero::new_unchecked(n - i) }); + /// Helper trait to specialize `advance_by` via `try_fold` for `Sized` iterators. + trait SpecAdvanceBy { + fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZero>; + } + + impl SpecAdvanceBy for I { + default fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZero> { + for i in 0..n { + if self.next().is_none() { + // SAFETY: `i` is always less than `n`. + return Err(unsafe { NonZero::new_unchecked(n - i) }); + } + } + Ok(()) + } + } + + impl SpecAdvanceBy for I { + fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZero> { + let Some(n) = NonZero::new(n) else { + return Ok(()); + }; + + let res = self.try_fold(n, |n, _| NonZero::new(n.get() - 1)); + + match res { + None => Ok(()), + Some(n) => Err(n), + } } } - Ok(()) + + self.spec_advance_by(n) } /// Returns the `n`th element of the iterator. From 258e8808616e4cb5c65d2692c66a6c61e17cc09f Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 13 May 2025 15:10:51 +0200 Subject: [PATCH 2351/4206] Remove #![feature(let_chains)] from library and src/librustdoc --- compiler/rustc_pattern_analysis/src/lib.rs | 1 - library/std/src/lib.rs | 1 - src/librustdoc/lib.rs | 1 - tests/run-make/core-no-oom-handling/rmake.rs | 2 +- 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index f63d8b2d79f61..2b85d7b26cea0 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -6,7 +6,6 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] #![allow(unused_crate_dependencies)] -#![cfg_attr(all(feature = "rustc", bootstrap), feature(let_chains))] // tidy-alphabetical-end pub mod constructor; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 0bb40ee4b3177..d1f6b450214f9 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -304,7 +304,6 @@ #![feature(iter_advance_by)] #![feature(iter_next_chunk)] #![feature(lang_items)] -#![feature(let_chains)] #![feature(link_cfg)] #![feature(linkage)] #![feature(macro_metavar_expr_concat)] diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index b4210e7b51819..b4003044e207b 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -11,7 +11,6 @@ #![feature(if_let_guard)] #![feature(impl_trait_in_assoc_type)] #![feature(iter_intersperse)] -#![feature(let_chains)] #![feature(never_type)] #![feature(round_char_boundary)] #![feature(test)] diff --git a/tests/run-make/core-no-oom-handling/rmake.rs b/tests/run-make/core-no-oom-handling/rmake.rs index a9e2b33e21073..5194d77311448 100644 --- a/tests/run-make/core-no-oom-handling/rmake.rs +++ b/tests/run-make/core-no-oom-handling/rmake.rs @@ -6,7 +6,7 @@ use run_make_support::{rustc, source_root}; fn main() { rustc() - .edition("2021") + .edition("2024") .arg("-Dwarnings") .crate_type("rlib") .input(source_root().join("library/core/src/lib.rs")) From 45865f21e3fedd8ba8b0161c126bbc575d1e1e0b Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 16 May 2025 16:49:05 +0200 Subject: [PATCH 2352/4206] ci: Run metrics on the beta channel This way we can catch regressions from upstream earlier --- .../rust-analyzer/.github/workflows/metrics.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/.github/workflows/metrics.yaml b/src/tools/rust-analyzer/.github/workflows/metrics.yaml index a4146d602185e..dc2f432bbc756 100644 --- a/src/tools/rust-analyzer/.github/workflows/metrics.yaml +++ b/src/tools/rust-analyzer/.github/workflows/metrics.yaml @@ -18,9 +18,9 @@ jobs: steps: - name: Install Rust toolchain run: | - rustup update --no-self-update stable - rustup default stable - rustup component add --toolchain stable rust-src + rustup update --no-self-update beta + rustup default beta + rustup component add --toolchain beta rust-src - name: Checkout repository uses: actions/checkout@v4 @@ -61,9 +61,9 @@ jobs: steps: - name: Install Rust toolchain run: | - rustup update --no-self-update stable - rustup default stable - rustup component add --toolchain stable rust-src + rustup update --no-self-update beta + rustup default beta + rustup component add --toolchain beta rust-src - name: Checkout repository uses: actions/checkout@v4 From 8604d458eb0ceafaba09322fd34b7c59038424f5 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Fri, 16 May 2025 11:35:06 -0400 Subject: [PATCH 2353/4206] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 056f5f4f3c100..47c911e9e6f64 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 056f5f4f3c100cb36b5e9aed2d20b9ea70aae295 +Subproject commit 47c911e9e6f6461f90ce19142031fe16876a3b95 From 067fe1ffb5789ff2cfdb3d01f756e48911c48063 Mon Sep 17 00:00:00 2001 From: satler Date: Sat, 17 May 2025 01:09:02 +0900 Subject: [PATCH 2354/4206] add regression test for rust-lang#101650 --- tests/ui/async-await/format-await-send.rs | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 tests/ui/async-await/format-await-send.rs diff --git a/tests/ui/async-await/format-await-send.rs b/tests/ui/async-await/format-await-send.rs new file mode 100644 index 0000000000000..13ae7233fd680 --- /dev/null +++ b/tests/ui/async-await/format-await-send.rs @@ -0,0 +1,24 @@ +// regression test for +// assert that Future which has format!() with an async function is Send + +#![allow(unused)] + +//@ check-pass +//@ edition: 2018 + +use core::future::Future; +use core::pin::Pin; + +fn build_string() -> Pin + Send>> { + Box::pin(async move { + let mut string_builder = String::new(); + string_builder += &format!("Hello {}", helper().await); + string_builder + }) +} + +async fn helper() -> String { + "World".to_string() +} + +fn main() {} From 742c27bc524b806d04c34f22810f88cbf5fa4483 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Fri, 16 May 2025 16:55:46 +0800 Subject: [PATCH 2355/4206] Do not emit help when shorthand from macro when suggest `?` or `expect` Signed-off-by: xizheyin --- compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 1 + tests/ui/typeck/macro-shorthand-issue-140659.rs | 1 - tests/ui/typeck/macro-shorthand-issue-140659.stderr | 4 ---- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 91eb1989864ff..d3618a6ae69a3 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -2034,6 +2034,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let sugg = match self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) { + Some(_) if expr.span.from_expansion() => return false, Some(ident) => format!(": {ident}{sugg}"), None => sugg.to_string(), }; diff --git a/tests/ui/typeck/macro-shorthand-issue-140659.rs b/tests/ui/typeck/macro-shorthand-issue-140659.rs index dba06b43d3931..d71a7ff1d3d4d 100644 --- a/tests/ui/typeck/macro-shorthand-issue-140659.rs +++ b/tests/ui/typeck/macro-shorthand-issue-140659.rs @@ -45,7 +45,6 @@ fn process(op: &Operator, reencoder: &mut T) -> Instruction { }; } - // This should give the specific error message with the wrong help suggestion for_each_operator!(translate) } diff --git a/tests/ui/typeck/macro-shorthand-issue-140659.stderr b/tests/ui/typeck/macro-shorthand-issue-140659.stderr index 419db9475710c..12537754d8029 100644 --- a/tests/ui/typeck/macro-shorthand-issue-140659.stderr +++ b/tests/ui/typeck/macro-shorthand-issue-140659.stderr @@ -10,10 +10,6 @@ LL | for_each_operator!(translate) = note: expected type `u32` found enum `Result::Error>` = note: this error originates in the macro `translate` which comes from the expansion of the macro `for_each_operator` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider using `Result::expect` to unwrap the `Result::Error>` value, panicking if the value is a `Result::Err` - | -LL | }: tag_index.expect("REASON") - | ++++++++++++++++++++++++++++ error: aborting due to 1 previous error From 1c17324c7d82812b3e23902cd118b8ce77e9592c Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sat, 17 May 2025 00:59:09 +0800 Subject: [PATCH 2356/4206] Create tests/ui/typeck/suggestions/ and move some tests in tests/ui/typeck/ to it Signed-off-by: xizheyin --- tests/ui/typeck/{ => suggestions}/macro-shorthand-issue-140659.rs | 0 .../typeck/{ => suggestions}/macro-shorthand-issue-140659.stderr | 0 .../suggest-adding-missing-zero-to-floating-point-number.fixed | 0 .../suggest-adding-missing-zero-to-floating-point-number.rs | 0 .../suggest-adding-missing-zero-to-floating-point-number.stderr | 0 tests/ui/typeck/{ => suggestions}/suggest-arg-comma-delete-ice.rs | 0 .../typeck/{ => suggestions}/suggest-arg-comma-delete-ice.stderr | 0 .../{ => suggestions}/suggest-box-on-divergent-if-else-arms.fixed | 0 .../{ => suggestions}/suggest-box-on-divergent-if-else-arms.rs | 0 .../suggest-box-on-divergent-if-else-arms.stderr | 0 .../suggest-similar-impls-for-root-obligation.rs | 0 .../suggest-similar-impls-for-root-obligation.stderr | 0 12 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/typeck/{ => suggestions}/macro-shorthand-issue-140659.rs (100%) rename tests/ui/typeck/{ => suggestions}/macro-shorthand-issue-140659.stderr (100%) rename tests/ui/typeck/{ => suggestions}/suggest-adding-missing-zero-to-floating-point-number.fixed (100%) rename tests/ui/typeck/{ => suggestions}/suggest-adding-missing-zero-to-floating-point-number.rs (100%) rename tests/ui/typeck/{ => suggestions}/suggest-adding-missing-zero-to-floating-point-number.stderr (100%) rename tests/ui/typeck/{ => suggestions}/suggest-arg-comma-delete-ice.rs (100%) rename tests/ui/typeck/{ => suggestions}/suggest-arg-comma-delete-ice.stderr (100%) rename tests/ui/typeck/{ => suggestions}/suggest-box-on-divergent-if-else-arms.fixed (100%) rename tests/ui/typeck/{ => suggestions}/suggest-box-on-divergent-if-else-arms.rs (100%) rename tests/ui/typeck/{ => suggestions}/suggest-box-on-divergent-if-else-arms.stderr (100%) rename tests/ui/typeck/{ => suggestions}/suggest-similar-impls-for-root-obligation.rs (100%) rename tests/ui/typeck/{ => suggestions}/suggest-similar-impls-for-root-obligation.stderr (100%) diff --git a/tests/ui/typeck/macro-shorthand-issue-140659.rs b/tests/ui/typeck/suggestions/macro-shorthand-issue-140659.rs similarity index 100% rename from tests/ui/typeck/macro-shorthand-issue-140659.rs rename to tests/ui/typeck/suggestions/macro-shorthand-issue-140659.rs diff --git a/tests/ui/typeck/macro-shorthand-issue-140659.stderr b/tests/ui/typeck/suggestions/macro-shorthand-issue-140659.stderr similarity index 100% rename from tests/ui/typeck/macro-shorthand-issue-140659.stderr rename to tests/ui/typeck/suggestions/macro-shorthand-issue-140659.stderr diff --git a/tests/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.fixed b/tests/ui/typeck/suggestions/suggest-adding-missing-zero-to-floating-point-number.fixed similarity index 100% rename from tests/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.fixed rename to tests/ui/typeck/suggestions/suggest-adding-missing-zero-to-floating-point-number.fixed diff --git a/tests/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.rs b/tests/ui/typeck/suggestions/suggest-adding-missing-zero-to-floating-point-number.rs similarity index 100% rename from tests/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.rs rename to tests/ui/typeck/suggestions/suggest-adding-missing-zero-to-floating-point-number.rs diff --git a/tests/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.stderr b/tests/ui/typeck/suggestions/suggest-adding-missing-zero-to-floating-point-number.stderr similarity index 100% rename from tests/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.stderr rename to tests/ui/typeck/suggestions/suggest-adding-missing-zero-to-floating-point-number.stderr diff --git a/tests/ui/typeck/suggest-arg-comma-delete-ice.rs b/tests/ui/typeck/suggestions/suggest-arg-comma-delete-ice.rs similarity index 100% rename from tests/ui/typeck/suggest-arg-comma-delete-ice.rs rename to tests/ui/typeck/suggestions/suggest-arg-comma-delete-ice.rs diff --git a/tests/ui/typeck/suggest-arg-comma-delete-ice.stderr b/tests/ui/typeck/suggestions/suggest-arg-comma-delete-ice.stderr similarity index 100% rename from tests/ui/typeck/suggest-arg-comma-delete-ice.stderr rename to tests/ui/typeck/suggestions/suggest-arg-comma-delete-ice.stderr diff --git a/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.fixed b/tests/ui/typeck/suggestions/suggest-box-on-divergent-if-else-arms.fixed similarity index 100% rename from tests/ui/typeck/suggest-box-on-divergent-if-else-arms.fixed rename to tests/ui/typeck/suggestions/suggest-box-on-divergent-if-else-arms.fixed diff --git a/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.rs b/tests/ui/typeck/suggestions/suggest-box-on-divergent-if-else-arms.rs similarity index 100% rename from tests/ui/typeck/suggest-box-on-divergent-if-else-arms.rs rename to tests/ui/typeck/suggestions/suggest-box-on-divergent-if-else-arms.rs diff --git a/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.stderr b/tests/ui/typeck/suggestions/suggest-box-on-divergent-if-else-arms.stderr similarity index 100% rename from tests/ui/typeck/suggest-box-on-divergent-if-else-arms.stderr rename to tests/ui/typeck/suggestions/suggest-box-on-divergent-if-else-arms.stderr diff --git a/tests/ui/typeck/suggest-similar-impls-for-root-obligation.rs b/tests/ui/typeck/suggestions/suggest-similar-impls-for-root-obligation.rs similarity index 100% rename from tests/ui/typeck/suggest-similar-impls-for-root-obligation.rs rename to tests/ui/typeck/suggestions/suggest-similar-impls-for-root-obligation.rs diff --git a/tests/ui/typeck/suggest-similar-impls-for-root-obligation.stderr b/tests/ui/typeck/suggestions/suggest-similar-impls-for-root-obligation.stderr similarity index 100% rename from tests/ui/typeck/suggest-similar-impls-for-root-obligation.stderr rename to tests/ui/typeck/suggestions/suggest-similar-impls-for-root-obligation.stderr From 5027ee27de1f633de12a23539c21db2873fc301a Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Fri, 16 May 2025 18:08:20 +0000 Subject: [PATCH 2357/4206] bump bootstrap cc-rs to `1.2.23` Signed-off-by: onur-ozkan --- src/bootstrap/Cargo.lock | 4 ++-- src/bootstrap/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 05ab1b6eddefb..06ca8580896fa 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -89,9 +89,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.17" +version = "1.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" +checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766" dependencies = [ "shlex", ] diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index e34de924cc18a..b1466e4f15309 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -32,7 +32,7 @@ test = false # Most of the time updating these dependencies requires modifications to the # bootstrap codebase(e.g., https://github.com/rust-lang/rust/issues/124565); # otherwise, some targets will fail. That's why these dependencies are explicitly pinned. -cc = "=1.2.17" +cc = "=1.2.23" cmake = "=0.1.54" build_helper = { path = "../build_helper" } From 49658e6a3c528dec342d82920f4606dab4d90ae8 Mon Sep 17 00:00:00 2001 From: GrantBirki Date: Fri, 16 May 2025 15:19:44 -0700 Subject: [PATCH 2358/4206] additional edge cases tests for `path.rs` --- library/std/tests/path.rs | 108 +++++++++++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 1 deletion(-) diff --git a/library/std/tests/path.rs b/library/std/tests/path.rs index 978402b6fdaea..7107d41605671 100644 --- a/library/std/tests/path.rs +++ b/library/std/tests/path.rs @@ -15,6 +15,13 @@ use std::ptr; use std::rc::Rc; use std::sync::Arc; +#[cfg(unix)] +use std::os::unix::ffi::OsStrExt; +#[cfg(windows)] +use std::os::windows::ffi::OsStrExt; +#[cfg(windows)] +use std::os::windows::ffi::OsStringExt; + #[allow(unknown_lints, unused_macro_rules)] macro_rules! t ( ($path:expr, iter: $iter:expr) => ( @@ -1235,7 +1242,7 @@ pub fn test_push() { tp!("foo//", "bar", r"foo//bar"); tp!(r"foo\\", "bar", r"foo\\bar"); tp!("foo/.", "bar", r"foo/.\bar"); - tp!("foo./.", "bar", r"foo./.\bar"); + tp!("foo./.", "bar", r"foo././bar"); tp!(r"foo\.", "bar", r"foo\.\bar"); tp!(r"foo.\.", "bar", r"foo.\.\bar"); tp!("foo", "", "foo\\"); @@ -1976,3 +1983,102 @@ fn clone_to_uninit() { unsafe { a.clone_to_uninit(ptr::from_mut::(&mut b).cast()) }; assert_eq!(a, &*b); } + +// Test: Only separators (e.g., "/" or "\\") +// This test checks how Path handles a string that consists only of path separators. +// It should recognize the root and not treat it as a normal component. +#[test] +fn test_only_separators() { + let path = Path::new("/////"); + assert!(path.has_root()); + assert_eq!(path.iter().count(), 1); + assert_eq!(path.parent(), None); +} + +// Test: Non-ASCII/Unicode +// This test verifies that Path can handle Unicode and non-ASCII characters in the path. +// It ensures that such paths are not rejected or misinterpreted. +#[test] +fn test_non_ascii_unicode() { + let path = Path::new("/tmp/❤/🚀/file.txt"); + assert!(path.to_str().is_some()); + assert_eq!(path.file_name(), Some(OsStr::new("file.txt"))); +} + +// Test: Embedded null bytes +// This test checks that Path can be constructed from a byte slice containing a null byte (on Unix). +// It ensures that null bytes are not treated as string terminators. +#[test] +fn test_embedded_null_byte() { + use std::ffi::OsStr; + let bytes = b"foo\0bar"; + let os_str = OsStr::from_bytes(bytes); + let path = Path::new(os_str); + assert!(path.as_os_str().as_bytes().contains(&0)); + assert_eq!(path.file_name(), Some(OsStr::new("foo\0bar"))); + assert_eq!(path.to_str(), Some("foo\0bar")); +} + +// Test: Reserved device names (Windows) +// This test ensures that reserved device names like "CON", "PRN", etc., are handled as normal paths on non-Windows platforms, +// and as special cases on Windows (if applicable). +#[test] +#[cfg(windows)] +fn test_reserved_device_names() { + for &name in &["CON", "PRN", "AUX", "NUL", "COM1", "LPT1"] { + let path = Path::new(name); + assert_eq!(path.file_name(), Some(OsStr::new(name))); + assert_eq!(path.extension(), None); + } +} + +// Test: Trailing dots/spaces (Windows) +// This test checks how Path handles trailing dots or spaces, which are special on Windows. +// On Unix, these should be treated as normal characters. +#[test] +#[cfg(windows)] +fn test_trailing_dots_and_spaces() { + let path = Path::new("foo. "); + assert_eq!(path.file_stem(), Some(OsStr::new("foo"))); + assert_eq!(path.extension(), Some(OsStr::new(" "))); + assert_eq!(path.file_name(), Some(OsStr::new("foo. "))); + assert_eq!(path.to_str(), Some("foo. ")); + let path = Path::new("bar..."); + assert_eq!(path.file_stem(), Some(OsStr::new("bar"))); + assert_eq!(path.extension(), Some(OsStr::new("..."))); + assert_eq!(path.file_name(), Some(OsStr::new("bar..."))); + assert_eq!(path.to_str(), Some("bar...")); +} + +// Test: Only extension (e.g., ".gitignore") +// This test verifies that files with only an extension and no base name are handled correctly. +// It checks that the extension is recognized and the file stem is None or empty as appropriate. +#[test] +fn test_only_extension() { + let path = Path::new(".ext"); + assert_eq!(path.extension(), None); + assert_eq!(path.file_stem(), Some(OsStr::new(".ext"))); + assert_eq!(path.file_name(), Some(OsStr::new(".ext"))); +} + +// Test: Long components +// This test checks that Path can handle very long path components without truncation or error. +// It ensures that the length of the component is preserved. +#[test] +fn test_long_component() { + let long = "a".repeat(300); + let path = Path::new(&long); + assert_eq!(path.file_name(), Some(OsStr::new(&long))); + assert_eq!(path.to_str(), Some(long.as_str())); + assert_eq!(path.iter().count(), 1); +} + +// Test: Embedded newlines +// This test verifies that newlines within path components are preserved and do not break path parsing. +// It ensures that Path treats newlines as normal characters. +#[test] +fn test_embedded_newline() { + let path = Path::new("foo\nbar"); + assert_eq!(path.file_name(), Some(OsStr::new("foo\nbar"))); + assert_eq!(path.to_str(), Some("foo\nbar")); +} From d29d1a332bc44b461859ccc756d53cbd81cbea0e Mon Sep 17 00:00:00 2001 From: Paul Mabileau Date: Sat, 17 May 2025 02:09:06 +0200 Subject: [PATCH 2359/4206] Docs(lib/alloc/vec): Add the missing `an` to `extract_if`'s first sentence As inspired by the equivalent methods from other collection types. Signed-off-by: Paul Mabileau --- library/alloc/src/vec/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 59879f23d7850..4d03ca63ec8ad 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -3648,7 +3648,7 @@ impl Vec { Splice { drain: self.drain(range), replace_with: replace_with.into_iter() } } - /// Creates an iterator which uses a closure to determine if element in the range should be removed. + /// Creates an iterator which uses a closure to determine if an element in the range should be removed. /// /// If the closure returns true, then the element is removed and yielded. /// If the closure returns false, the element will remain in the vector and will not be yielded From cd5772e396361c72e4662655687a462aee6c6aea Mon Sep 17 00:00:00 2001 From: Paul Mabileau Date: Sat, 17 May 2025 02:14:55 +0200 Subject: [PATCH 2360/4206] Docs(lib/coll/hm): Reword `extract_if` to use `element` instead of `value` A minor change, but it seemed interesting to unify this one's description, especially considering all the other equivalents use `element` as well. Signed-off-by: Paul Mabileau --- library/std/src/collections/hash/set.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 8514dfd9a984d..5043d1bd1df7c 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -276,10 +276,10 @@ impl HashSet { Drain { base: self.base.drain() } } - /// Creates an iterator which uses a closure to determine if a value should be removed. + /// Creates an iterator which uses a closure to determine if an element should be removed. /// - /// If the closure returns true, then the value is removed and yielded. - /// If the closure returns false, the value will remain in the list and will not be yielded + /// If the closure returns true, then the element is removed and yielded. + /// If the closure returns false, the element will remain in the list and will not be yielded /// by the iterator. /// /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating From 35f847363729b16332eab1a85900617218495757 Mon Sep 17 00:00:00 2001 From: Paul Mabileau Date: Sat, 17 May 2025 02:22:13 +0200 Subject: [PATCH 2361/4206] Docs(lib/coll/btm): Split `extract_if`'s first sentence from the following ones This also seems like a small mistake: the first main sentence is put in the same paragraph as the other two following ones while other equivalents all have it split. Therefore, do the same here. Signed-off-by: Paul Mabileau --- library/alloc/src/collections/btree/map.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 5ca32ed741af8..ea81645aa6491 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1398,10 +1398,12 @@ impl BTreeMap { } /// Creates an iterator that visits all elements (key-value pairs) in - /// ascending key order and uses a closure to determine if an element should - /// be removed. If the closure returns `true`, the element is removed from - /// the map and yielded. If the closure returns `false`, or panics, the - /// element remains in the map and will not be yielded. + /// ascending key order and uses a closure to determine if an element + /// should be removed. + /// + /// If the closure returns `true`, the element is removed from the map and + /// yielded. If the closure returns `false`, or panics, the element remains + /// in the map and will not be yielded. /// /// The iterator also lets you mutate the value of each element in the /// closure, regardless of whether you choose to keep or remove it. From 9205ee27a815e5b356cfce6269d9ded1d1c098f7 Mon Sep 17 00:00:00 2001 From: Paul Mabileau Date: Sat, 17 May 2025 02:36:08 +0200 Subject: [PATCH 2362/4206] Docs(lib/extract_if): Unify paragraph about closure actions Also fixes `HashSet`'s that incorrectly designated itself as a `list`. Signed-off-by: Paul Mabileau --- library/alloc/src/collections/linked_list.rs | 6 +++--- library/alloc/src/vec/mod.rs | 6 +++--- library/std/src/collections/hash/map.rs | 6 +++--- library/std/src/collections/hash/set.rs | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 00e2805d11f61..1890a114d3cb2 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1124,9 +1124,9 @@ impl LinkedList { /// Creates an iterator which uses a closure to determine if an element should be removed. /// - /// If the closure returns true, then the element is removed and yielded. - /// If the closure returns false, the element will remain in the list and will not be yielded - /// by the iterator. + /// If the closure returns `true`, the element is removed from the list and + /// yielded. If the closure returns `false`, or panics, the element remains + /// in the list and will not be yielded. /// /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating /// or the iteration short-circuits, then the remaining elements will be retained. diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 4d03ca63ec8ad..e5f2c9468e386 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -3650,9 +3650,9 @@ impl Vec { /// Creates an iterator which uses a closure to determine if an element in the range should be removed. /// - /// If the closure returns true, then the element is removed and yielded. - /// If the closure returns false, the element will remain in the vector and will not be yielded - /// by the iterator. + /// If the closure returns `true`, the element is removed from the vector + /// and yielded. If the closure returns `false`, or panics, the element + /// remains in the vector and will not be yielded. /// /// Only elements that fall in the provided range are considered for extraction, but any elements /// after the range will still have to be moved if any element has been extracted. diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 3530f890f5294..9732d2c2d5ce9 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -650,9 +650,9 @@ impl HashMap { /// Creates an iterator which uses a closure to determine if an element should be removed. /// - /// If the closure returns true, the element is removed from the map and yielded. - /// If the closure returns false, or panics, the element remains in the map and will not be - /// yielded. + /// If the closure returns `true`, the element is removed from the map and + /// yielded. If the closure returns `false`, or panics, the element remains + /// in the map and will not be yielded. /// /// Note that `extract_if` lets you mutate every value in the filter closure, regardless of /// whether you choose to keep or remove it. diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 5043d1bd1df7c..482d57b47f677 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -278,9 +278,9 @@ impl HashSet { /// Creates an iterator which uses a closure to determine if an element should be removed. /// - /// If the closure returns true, then the element is removed and yielded. - /// If the closure returns false, the element will remain in the list and will not be yielded - /// by the iterator. + /// If the closure returns `true`, the element is removed from the set and + /// yielded. If the closure returns `false`, or panics, the element remains + /// in the set and will not be yielded. /// /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating /// or the iteration short-circuits, then the remaining elements will be retained. From 014434e96f4f42e06b6c2dfc00110209b121040e Mon Sep 17 00:00:00 2001 From: Paul Mabileau Date: Sat, 17 May 2025 02:45:56 +0200 Subject: [PATCH 2363/4206] Docs(lib/extract_if): Unify paragraph about elements mutation Take the one from `BTreeMap` that seems the best-worded and most precise among the available variations. Signed-off-by: Paul Mabileau --- library/alloc/src/collections/linked_list.rs | 4 ++-- library/alloc/src/vec/mod.rs | 4 ++-- library/std/src/collections/hash/map.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 1890a114d3cb2..0e365ebd3080a 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1132,8 +1132,8 @@ impl LinkedList { /// or the iteration short-circuits, then the remaining elements will be retained. /// Use `extract_if().for_each(drop)` if you do not need the returned iterator. /// - /// Note that `extract_if` lets you mutate every element in the filter closure, regardless of - /// whether you choose to keep or remove it. + /// The iterator also lets you mutate the value of each element in the + /// closure, regardless of whether you choose to keep or remove it. /// /// # Examples /// diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index e5f2c9468e386..3ea5f160666bc 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -3692,8 +3692,8 @@ impl Vec { /// But `extract_if` is easier to use. `extract_if` is also more efficient, /// because it can backshift the elements of the array in bulk. /// - /// Note that `extract_if` also lets you mutate the elements passed to the filter closure, - /// regardless of whether you choose to keep or remove them. + /// The iterator also lets you mutate the value of each element in the + /// closure, regardless of whether you choose to keep or remove it. /// /// # Panics /// diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 9732d2c2d5ce9..5e053d3644856 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -654,8 +654,8 @@ impl HashMap { /// yielded. If the closure returns `false`, or panics, the element remains /// in the map and will not be yielded. /// - /// Note that `extract_if` lets you mutate every value in the filter closure, regardless of - /// whether you choose to keep or remove it. + /// The iterator also lets you mutate the value of each element in the + /// closure, regardless of whether you choose to keep or remove it. /// /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating /// or the iteration short-circuits, then the remaining elements will be retained. From a9330dd0e9fbc1698b69ac82e138d9dcef31bc33 Mon Sep 17 00:00:00 2001 From: Paul Mabileau Date: Sat, 17 May 2025 02:49:57 +0200 Subject: [PATCH 2364/4206] Docs(lib/coll/hm): Add kv pair to `extract_if`'s first sentence Make it consistent in this regard with `BTreeMap`'s. Signed-off-by: Paul Mabileau --- library/std/src/collections/hash/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 5e053d3644856..edbdd0411457f 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -648,7 +648,7 @@ impl HashMap { Drain { base: self.base.drain() } } - /// Creates an iterator which uses a closure to determine if an element should be removed. + /// Creates an iterator which uses a closure to determine if an element (key-value pair) should be removed. /// /// If the closure returns `true`, the element is removed from the map and /// yielded. If the closure returns `false`, or panics, the element remains From b1d7480acbc6bcc01f0eef98feaccdf53b387cd3 Mon Sep 17 00:00:00 2001 From: Paul Mabileau Date: Sat, 17 May 2025 02:54:21 +0200 Subject: [PATCH 2365/4206] Docs(lib/extract_if): Unify example description Signed-off-by: Paul Mabileau --- library/alloc/src/collections/linked_list.rs | 2 +- library/alloc/src/vec/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 0e365ebd3080a..d03c1969b5b70 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1137,7 +1137,7 @@ impl LinkedList { /// /// # Examples /// - /// Splitting a list into evens and odds, reusing the original list: + /// Splitting a list into even and odd values, reusing the original list: /// /// ``` /// use std::collections::LinkedList; diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 3ea5f160666bc..ce7321544b6b9 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -3701,7 +3701,7 @@ impl Vec { /// /// # Examples /// - /// Splitting an array into evens and odds, reusing the original allocation: + /// Splitting a vector into even and odd values, reusing the original vector: /// /// ``` /// let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15]; From dcef449e2c7209d2e591f2c1c4791eb094321929 Mon Sep 17 00:00:00 2001 From: Jack O'Connor Date: Fri, 16 May 2025 20:59:45 -0700 Subject: [PATCH 2366/4206] discuss deadlocks in the std::io::pipe() example --- library/std/src/io/pipe.rs | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/library/std/src/io/pipe.rs b/library/std/src/io/pipe.rs index 47243806cd2d9..16727d445416c 100644 --- a/library/std/src/io/pipe.rs +++ b/library/std/src/io/pipe.rs @@ -38,30 +38,44 @@ use crate::sys_common::{FromInner, IntoInner}; /// > not rely on a particular capacity: an application should be designed so that a reading process /// > consumes data as soon as it is available, so that a writing process does not remain blocked. /// -/// # Examples +/// # Example /// /// ```no_run /// # #[cfg(miri)] fn main() {} /// # #[cfg(not(miri))] /// # fn main() -> std::io::Result<()> { +/// use std::io::{Read, Write, pipe}; /// use std::process::Command; -/// use std::io::{pipe, Read, Write}; -/// let (ping_rx, mut ping_tx) = pipe()?; -/// let (mut pong_rx, pong_tx) = pipe()?; +/// let (ping_reader, mut ping_writer) = pipe()?; +/// let (mut pong_reader, pong_writer) = pipe()?; /// -/// // Spawn a process that echoes its input. -/// let mut echo_server = Command::new("cat").stdin(ping_rx).stdout(pong_tx).spawn()?; +/// // Spawn a child process that echoes its input. +/// let mut echo_command = Command::new("cat"); +/// echo_command.stdin(ping_reader); +/// echo_command.stdout(pong_writer); +/// let mut echo_child = echo_command.spawn()?; /// -/// ping_tx.write_all(b"hello")?; -/// // Close to unblock echo_server's reader. -/// drop(ping_tx); +/// // Send input to the child process. Note that because we're writing all the input before we +/// // read any output, this could deadlock if the child's input and output pipe buffers both +/// // filled up. Those buffers are usually at least a few KB, so "hello" is fine, but for longer +/// // inputs we'd need to read and write at the same time, e.g. using threads. +/// ping_writer.write_all(b"hello")?; +/// +/// // `cat` exits when it reads EOF from stdin, but that can't happen while any ping writer +/// // remains open. We need to drop our ping writer, or read_to_string will deadlock below. +/// drop(ping_writer); +/// +/// // The pong reader can't report EOF while any pong writer remains open. Our Command object is +/// // holding a pong writer, and again read_to_string will deadlock if we don't drop it. +/// drop(echo_command); /// /// let mut buf = String::new(); -/// // Block until echo_server's writer is closed. -/// pong_rx.read_to_string(&mut buf)?; +/// // Block until `cat` closes its stdout (a pong writer). +/// pong_reader.read_to_string(&mut buf)?; /// assert_eq!(&buf, "hello"); /// -/// echo_server.wait()?; +/// // At this point we know `cat` has exited, but we still need to wait to clean up the "zombie". +/// echo_child.wait()?; /// # Ok(()) /// # } /// ``` From e666b83b11689a17571305592f4b67dce6bc1d4a Mon Sep 17 00:00:00 2001 From: Michael Hackner Date: Fri, 16 May 2025 21:35:09 -0700 Subject: [PATCH 2367/4206] excessive_precision: Fix false positive when exponent has leading zero --- clippy_lints/src/float_literal.rs | 2 +- tests/ui/excessive_precision.fixed | 3 +++ tests/ui/excessive_precision.rs | 3 +++ tests/ui/excessive_precision.stderr | 6 +++--- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 012ad8e1a2298..c51267567d01d 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { }, ); } - } else if digits > max as usize && float_str.len() < sym_str.len() { + } else if digits > max as usize && count_digits(&float_str) < count_digits(sym_str) { span_lint_and_then( cx, EXCESSIVE_PRECISION, diff --git a/tests/ui/excessive_precision.fixed b/tests/ui/excessive_precision.fixed index 99d09774d16d3..8a8c2e1939c83 100644 --- a/tests/ui/excessive_precision.fixed +++ b/tests/ui/excessive_precision.fixed @@ -79,6 +79,9 @@ fn main() { // issue #2840 let num = 0.000_000_000_01e-10f64; + // issue #6341 + let exponential: f64 = 4.886506780521244E-03; + // issue #7744 let _ = 2.225_073_858_507_201e-308_f64; //~^ excessive_precision diff --git a/tests/ui/excessive_precision.rs b/tests/ui/excessive_precision.rs index a542fb2e7e3cd..5dcf55cb92735 100644 --- a/tests/ui/excessive_precision.rs +++ b/tests/ui/excessive_precision.rs @@ -79,6 +79,9 @@ fn main() { // issue #2840 let num = 0.000_000_000_01e-10f64; + // issue #6341 + let exponential: f64 = 4.886506780521244E-03; + // issue #7744 let _ = 2.225_073_858_507_201_1e-308_f64; //~^ excessive_precision diff --git a/tests/ui/excessive_precision.stderr b/tests/ui/excessive_precision.stderr index 934a367e10659..f5eeadf0c8cb0 100644 --- a/tests/ui/excessive_precision.stderr +++ b/tests/ui/excessive_precision.stderr @@ -157,7 +157,7 @@ LL + let bad_bige32: f32 = 1.123_456_8E-10; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:83:13 + --> tests/ui/excessive_precision.rs:86:13 | LL | let _ = 2.225_073_858_507_201_1e-308_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +169,7 @@ LL + let _ = 2.225_073_858_507_201e-308_f64; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:87:13 + --> tests/ui/excessive_precision.rs:90:13 | LL | let _ = 1.000_000_000_000_001e-324_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL + let _ = 0_f64; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:98:20 + --> tests/ui/excessive_precision.rs:101:20 | LL | const _: f64 = 3.0000000000000000e+00; | ^^^^^^^^^^^^^^^^^^^^^^ From 0c157b51d339fbfe51b6ef21acd4b21452c76f2c Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Thu, 8 May 2025 14:30:33 -0700 Subject: [PATCH 2368/4206] aarch64-linux: Default to FramePointer::NonLeaf For aarch64-apple and aarch64-windows, platform docs state that code must use frame pointers correctly. This is because the AAPCS64 mandates that a platform specify its frame pointer conformance requirements: - Apple: https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Respect-the-purpose-of-specific-CPU-registers - Windows: https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170#integer-registers - AAPCS64: https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer Unwinding code either requires unwind tables or frame pointers, and on aarch64 the expectation is that one can use frame pointers for this. Most Linux targets represent a motley variety of possible distributions, so it is unclear who to defer to on conformance, other than perhaps Arm. In the absence of a specific edict for a given aarch64-linux target, Rust will assume aarch64-linux targets use non-leaf frame pointers. This reflects what compilers like clang do. --- .../src/spec/targets/aarch64_be_unknown_linux_gnu.rs | 6 +++++- .../targets/aarch64_be_unknown_linux_gnu_ilp32.rs | 6 +++++- .../src/spec/targets/aarch64_linux_android.rs | 8 +++++++- .../src/spec/targets/aarch64_unknown_linux_gnu.rs | 8 +++++++- .../spec/targets/aarch64_unknown_linux_gnu_ilp32.rs | 6 +++++- .../src/spec/targets/aarch64_unknown_linux_musl.rs | 12 ++++++++++-- .../src/spec/targets/aarch64_unknown_linux_ohos.rs | 8 +++++++- tests/assembly/asm/aarch64-types.rs | 7 +++---- tests/codegen/frame-pointer.rs | 4 +++- 9 files changed, 52 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs index 87c07cd31090e..4b75a6e5dbf61 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs @@ -1,6 +1,6 @@ use rustc_abi::Endian; -use crate::spec::{StackProbeType, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{FramePointer, StackProbeType, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -16,6 +16,10 @@ pub(crate) fn target() -> Target { arch: "aarch64".into(), options: TargetOptions { features: "+v8a,+outline-atomics".into(), + // the AAPCS64 expects use of non-leaf frame pointers per + // https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer + // and we tend to encounter interesting bugs in AArch64 unwinding code if we do not + frame_pointer: FramePointer::NonLeaf, max_atomic_width: Some(128), stack_probes: StackProbeType::Inline, mcount: "\u{1}_mcount".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs index e785069c78a12..2a16d1de3b51f 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs @@ -1,6 +1,6 @@ use rustc_abi::Endian; -use crate::spec::{StackProbeType, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{FramePointer, StackProbeType, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { let mut base = base::linux_gnu::opts(); @@ -20,6 +20,10 @@ pub(crate) fn target() -> Target { options: TargetOptions { abi: "ilp32".into(), features: "+v8a,+outline-atomics".into(), + // the AAPCS64 expects use of non-leaf frame pointers per + // https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer + // and we tend to encounter interesting bugs in AArch64 unwinding code if we do not + frame_pointer: FramePointer::NonLeaf, stack_probes: StackProbeType::Inline, mcount: "\u{1}_mcount".into(), endian: Endian::Big, diff --git a/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs b/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs index 41c25393e129b..d8651f305fe94 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs @@ -1,4 +1,6 @@ -use crate::spec::{SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{ + FramePointer, SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base, +}; // See https://developer.android.com/ndk/guides/abis.html#arm64-v8a // for target ABI requirements. @@ -20,6 +22,10 @@ pub(crate) fn target() -> Target { // As documented in https://developer.android.com/ndk/guides/cpu-features.html // the neon (ASIMD) and FP must exist on all android aarch64 targets. features: "+v8a,+neon,+fp-armv8".into(), + // the AAPCS64 expects use of non-leaf frame pointers per + // https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer + // and we tend to encounter interesting bugs in AArch64 unwinding code if we do not + frame_pointer: FramePointer::NonLeaf, stack_probes: StackProbeType::Inline, supported_sanitizers: SanitizerSet::CFI | SanitizerSet::HWADDRESS diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs index c6be2c20ea233..4220d74dfc890 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs @@ -1,4 +1,6 @@ -use crate::spec::{SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{ + FramePointer, SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base, +}; pub(crate) fn target() -> Target { Target { @@ -14,6 +16,10 @@ pub(crate) fn target() -> Target { arch: "aarch64".into(), options: TargetOptions { features: "+v8a,+outline-atomics".into(), + // the AAPCS64 expects use of non-leaf frame pointers per + // https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer + // and we tend to encounter interesting bugs in AArch64 unwinding code if we do not + frame_pointer: FramePointer::NonLeaf, mcount: "\u{1}_mcount".into(), max_atomic_width: Some(128), stack_probes: StackProbeType::Inline, diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs index 166bb1ed2151c..a22c128967736 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs @@ -1,4 +1,4 @@ -use crate::spec::{StackProbeType, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{FramePointer, StackProbeType, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -15,6 +15,10 @@ pub(crate) fn target() -> Target { options: TargetOptions { abi: "ilp32".into(), features: "+v8a,+outline-atomics".into(), + // the AAPCS64 expects use of non-leaf frame pointers per + // https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer + // and we tend to encounter interesting bugs in AArch64 unwinding code if we do not + frame_pointer: FramePointer::NonLeaf, max_atomic_width: Some(128), stack_probes: StackProbeType::Inline, mcount: "\u{1}_mcount".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs index 58ba06e124c73..58daaa0367508 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs @@ -1,4 +1,6 @@ -use crate::spec::{SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{ + FramePointer, SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base, +}; pub(crate) fn target() -> Target { let mut base = base::linux_musl::opts(); @@ -26,6 +28,12 @@ pub(crate) fn target() -> Target { pointer_width: 64, data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), - options: TargetOptions { mcount: "\u{1}_mcount".into(), ..base }, + options: TargetOptions { + // the AAPCS64 expects use of non-leaf frame pointers per + // https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer + // and we tend to encounter interesting bugs in AArch64 unwinding code if we do not + frame_pointer: FramePointer::NonLeaf, + mcount: "\u{1}_mcount".into(), ..base + }, } } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs index f2994b1232e6c..51cdebf22db21 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs @@ -1,4 +1,6 @@ -use crate::spec::{SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{ + FramePointer, SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base, +}; pub(crate) fn target() -> Target { let mut base = base::linux_ohos::opts(); @@ -16,6 +18,10 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: TargetOptions { + // the AAPCS64 expects use of non-leaf frame pointers per + // https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer + // and we tend to encounter interesting bugs in AArch64 unwinding code if we do not + frame_pointer: FramePointer::NonLeaf, mcount: "\u{1}_mcount".into(), stack_probes: StackProbeType::Inline, supported_sanitizers: SanitizerSet::ADDRESS diff --git a/tests/assembly/asm/aarch64-types.rs b/tests/assembly/asm/aarch64-types.rs index ad2770d43e37d..b7abeb0229865 100644 --- a/tests/assembly/asm/aarch64-types.rs +++ b/tests/assembly/asm/aarch64-types.rs @@ -86,12 +86,11 @@ pub unsafe fn sym_static() { // Regression test for #75761 // CHECK-LABEL: {{("#)?}}issue_75761{{"?}} -// aarch64: str {{.*}}x30 -// arm64ec: stp {{.*}}x30 +// x29 holds the frame pointer, right next to x30, so ldp/stp happens sometimes +// CHECK: st[[MAY_PAIR:(r|p).*]]x30 // CHECK: //APP // CHECK: //NO_APP -// aarch64: ldr {{.*}}x30 -// arm64ec: ldp {{.*}}x30 +// CHECK: ld[[MAY_PAIR]]x30 #[no_mangle] pub unsafe fn issue_75761() { asm!("", out("v0") _, out("x30") _); diff --git a/tests/codegen/frame-pointer.rs b/tests/codegen/frame-pointer.rs index 1f7c9a59c9887..23989653fa8e4 100644 --- a/tests/codegen/frame-pointer.rs +++ b/tests/codegen/frame-pointer.rs @@ -26,8 +26,10 @@ pub fn peach(x: u32) -> u32 { // CHECK: attributes [[PEACH_ATTRS]] = { // x64-linux-NOT: {{.*}}"frame-pointer"{{.*}} -// aarch64-linux-NOT: {{.*}}"frame-pointer"{{.*}} // x64-apple-SAME: {{.*}}"frame-pointer"="all" // force-SAME: {{.*}}"frame-pointer"="all" +// +// AAPCS64 demands frame pointers: +// aarch64-linux-SAME: {{.*}}"frame-pointer"="non-leaf" // aarch64-apple-SAME: {{.*}}"frame-pointer"="non-leaf" // CHECK-SAME: } From 604f0e27436b4940399873d0c23e5b609a52e831 Mon Sep 17 00:00:00 2001 From: GrantBirki Date: Fri, 16 May 2025 22:42:05 -0700 Subject: [PATCH 2369/4206] remove `test_embedded_null_byte()` test for now --- library/std/tests/path.rs | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/library/std/tests/path.rs b/library/std/tests/path.rs index 7107d41605671..a6f679d0ffb3c 100644 --- a/library/std/tests/path.rs +++ b/library/std/tests/path.rs @@ -15,13 +15,6 @@ use std::ptr; use std::rc::Rc; use std::sync::Arc; -#[cfg(unix)] -use std::os::unix::ffi::OsStrExt; -#[cfg(windows)] -use std::os::windows::ffi::OsStrExt; -#[cfg(windows)] -use std::os::windows::ffi::OsStringExt; - #[allow(unknown_lints, unused_macro_rules)] macro_rules! t ( ($path:expr, iter: $iter:expr) => ( @@ -2005,19 +1998,6 @@ fn test_non_ascii_unicode() { assert_eq!(path.file_name(), Some(OsStr::new("file.txt"))); } -// Test: Embedded null bytes -// This test checks that Path can be constructed from a byte slice containing a null byte (on Unix). -// It ensures that null bytes are not treated as string terminators. -#[test] -fn test_embedded_null_byte() { - use std::ffi::OsStr; - let bytes = b"foo\0bar"; - let os_str = OsStr::from_bytes(bytes); - let path = Path::new(os_str); - assert!(path.as_os_str().as_bytes().contains(&0)); - assert_eq!(path.file_name(), Some(OsStr::new("foo\0bar"))); - assert_eq!(path.to_str(), Some("foo\0bar")); -} // Test: Reserved device names (Windows) // This test ensures that reserved device names like "CON", "PRN", etc., are handled as normal paths on non-Windows platforms, From 3b7ca287a7ecb80185f2c679e663cd9c94cdc9f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Fri, 14 Mar 2025 10:48:02 +0100 Subject: [PATCH 2370/4206] Describe lifetime of call argument temporaries passed indirectly --- compiler/rustc_codegen_ssa/src/mir/block.rs | 48 +++++++++---- .../codegen/align-byval-alignment-mismatch.rs | 7 +- tests/codegen/call-tmps-lifetime.rs | 68 +++++++++++++++++++ .../issue-98156-const-arg-temp-lifetime.rs | 27 -------- 4 files changed, 108 insertions(+), 42 deletions(-) create mode 100644 tests/codegen/call-tmps-lifetime.rs delete mode 100644 tests/codegen/issues/issue-98156-const-arg-temp-lifetime.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 950f19a6f0f4e..1530ee8564752 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1,6 +1,6 @@ use std::cmp; -use rustc_abi::{BackendRepr, ExternAbi, HasDataLayout, Reg, WrappingRange}; +use rustc_abi::{BackendRepr, ExternAbi, HasDataLayout, Reg, Size, WrappingRange}; use rustc_ast as ast; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_data_structures::packed::Pu128; @@ -158,7 +158,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { llargs: &[Bx::Value], destination: Option<(ReturnDest<'tcx, Bx::Value>, mir::BasicBlock)>, mut unwind: mir::UnwindAction, - copied_constant_arguments: &[PlaceRef<'tcx, ::Value>], + lifetime_ends_after_call: &[(Bx::Value, Size)], instance: Option>, mergeable_succ: bool, ) -> MergingSucc { @@ -245,8 +245,8 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { if let Some((ret_dest, target)) = destination { bx.switch_to_block(fx.llbb(target)); fx.set_debug_loc(bx, self.terminator.source_info); - for tmp in copied_constant_arguments { - bx.lifetime_end(tmp.val.llval, tmp.layout.size); + for &(tmp, size) in lifetime_ends_after_call { + bx.lifetime_end(tmp, size); } fx.store_return(bx, ret_dest, &fn_abi.ret, invokeret); } @@ -259,8 +259,8 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { } if let Some((ret_dest, target)) = destination { - for tmp in copied_constant_arguments { - bx.lifetime_end(tmp.val.llval, tmp.layout.size); + for &(tmp, size) in lifetime_ends_after_call { + bx.lifetime_end(tmp, size); } fx.store_return(bx, ret_dest, &fn_abi.ret, llret); self.funclet_br(fx, bx, target, mergeable_succ) @@ -1048,7 +1048,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (args, None) }; - let mut copied_constant_arguments = vec![]; + // When generating arguments we sometimes introduce temporary allocations with lifetime + // that extend for the duration of a call. Keep track of those allocations and their sizes + // to generate `lifetime_end` when the call returns. + let mut lifetime_ends_after_call: Vec<(Bx::Value, Size)> = Vec::new(); 'make_args: for (i, arg) in first_args.iter().enumerate() { let mut op = self.codegen_operand(bx, &arg.node); @@ -1136,12 +1139,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.lifetime_start(tmp.val.llval, tmp.layout.size); op.val.store(bx, tmp); op.val = Ref(tmp.val); - copied_constant_arguments.push(tmp); + lifetime_ends_after_call.push((tmp.val.llval, tmp.layout.size)); } _ => {} } - self.codegen_argument(bx, op, &mut llargs, &fn_abi.args[i]); + self.codegen_argument( + bx, + op, + &mut llargs, + &fn_abi.args[i], + &mut lifetime_ends_after_call, + ); } let num_untupled = untuple.map(|tup| { self.codegen_arguments_untupled( @@ -1149,6 +1158,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &tup.node, &mut llargs, &fn_abi.args[first_args.len()..], + &mut lifetime_ends_after_call, ) }); @@ -1173,7 +1183,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ); let last_arg = fn_abi.args.last().unwrap(); - self.codegen_argument(bx, location, &mut llargs, last_arg); + self.codegen_argument( + bx, + location, + &mut llargs, + last_arg, + &mut lifetime_ends_after_call, + ); } let fn_ptr = match (instance, llfn) { @@ -1189,7 +1205,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &llargs, destination, unwind, - &copied_constant_arguments, + &lifetime_ends_after_call, instance, mergeable_succ, ) @@ -1479,6 +1495,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { op: OperandRef<'tcx, Bx::Value>, llargs: &mut Vec, arg: &ArgAbi<'tcx, Ty<'tcx>>, + lifetime_ends_after_call: &mut Vec<(Bx::Value, Size)>, ) { match arg.mode { PassMode::Ignore => return, @@ -1517,7 +1534,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { None => arg.layout.align.abi, }; let scratch = PlaceValue::alloca(bx, arg.layout.size, required_align); + bx.lifetime_start(scratch.llval, arg.layout.size); op.val.store(bx, scratch.with_type(arg.layout)); + lifetime_ends_after_call.push((scratch.llval, arg.layout.size)); (scratch.llval, scratch.align, true) } PassMode::Cast { .. } => { @@ -1538,7 +1557,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // alignment requirements may be higher than the type's alignment, so copy // to a higher-aligned alloca. let scratch = PlaceValue::alloca(bx, arg.layout.size, required_align); + bx.lifetime_start(scratch.llval, arg.layout.size); bx.typed_place_copy(scratch, op_place_val, op.layout); + lifetime_ends_after_call.push((scratch.llval, arg.layout.size)); (scratch.llval, scratch.align, true) } else { (op_place_val.llval, op_place_val.align, true) @@ -1620,6 +1641,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { operand: &mir::Operand<'tcx>, llargs: &mut Vec, args: &[ArgAbi<'tcx, Ty<'tcx>>], + lifetime_ends_after_call: &mut Vec<(Bx::Value, Size)>, ) -> usize { let tuple = self.codegen_operand(bx, operand); @@ -1632,13 +1654,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { for i in 0..tuple.layout.fields.count() { let field_ptr = tuple_ptr.project_field(bx, i); let field = bx.load_operand(field_ptr); - self.codegen_argument(bx, field, llargs, &args[i]); + self.codegen_argument(bx, field, llargs, &args[i], lifetime_ends_after_call); } } else { // If the tuple is immediate, the elements are as well. for i in 0..tuple.layout.fields.count() { let op = tuple.extract_field(self, bx, i); - self.codegen_argument(bx, op, llargs, &args[i]); + self.codegen_argument(bx, op, llargs, &args[i], lifetime_ends_after_call); } } tuple.layout.fields.count() diff --git a/tests/codegen/align-byval-alignment-mismatch.rs b/tests/codegen/align-byval-alignment-mismatch.rs index 46cfb2972df3a..c69fc2de9d257 100644 --- a/tests/codegen/align-byval-alignment-mismatch.rs +++ b/tests/codegen/align-byval-alignment-mismatch.rs @@ -2,9 +2,10 @@ //@ add-core-stubs //@ revisions:i686-linux x86_64-linux -//@[i686-linux] compile-flags: --target i686-unknown-linux-gnu -C panic=abort +//@ compile-flags: -Cno-prepopulate-passes -Copt-level=1 -Cpanic=abort +//@[i686-linux] compile-flags: --target i686-unknown-linux-gnu //@[i686-linux] needs-llvm-components: x86 -//@[x86_64-linux] compile-flags: --target x86_64-unknown-linux-gnu -C panic=abort +//@[x86_64-linux] compile-flags: --target x86_64-unknown-linux-gnu //@[x86_64-linux] needs-llvm-components: x86 // Tests that we correctly copy arguments into allocas when the alignment of the byval argument @@ -54,8 +55,10 @@ extern "C" { pub unsafe fn rust_to_c_increases_alignment(x: Align1) { // i686-linux: start: // i686-linux-NEXT: [[ALLOCA:%[0-9a-z]+]] = alloca [48 x i8], align 4 + // i686-linux-NEXT: call void @llvm.lifetime.start.p0(i64 48, ptr {{.*}}[[ALLOCA]]) // i686-linux-NEXT: call void @llvm.memcpy.{{.+}}(ptr {{.*}}align 4 {{.*}}[[ALLOCA]], ptr {{.*}}align 1 {{.*}}%x // i686-linux-NEXT: call void @extern_c_align1({{.+}} [[ALLOCA]]) + // i686-linux-NEXT: call void @llvm.lifetime.end.p0(i64 48, ptr {{.*}}[[ALLOCA]]) // x86_64-linux: start: // x86_64-linux-NEXT: call void @extern_c_align1 diff --git a/tests/codegen/call-tmps-lifetime.rs b/tests/codegen/call-tmps-lifetime.rs new file mode 100644 index 0000000000000..7b7b6e17bddd3 --- /dev/null +++ b/tests/codegen/call-tmps-lifetime.rs @@ -0,0 +1,68 @@ +// Test that temporary allocas used for call arguments have their lifetimes described by +// intrinsics. +// +//@ add-core-stubs +//@ compile-flags: -Copt-level=1 -Cno-prepopulate-passes --crate-type=lib --target i686-unknown-linux-gnu +//@ needs-llvm-components: x86 +#![feature(no_core)] +#![no_std] +#![no_core] +extern crate minicore; +use minicore::*; + +// Const operand. Regression test for #98156. +// +// CHECK-LABEL: define void @const_indirect( +// CHECK-NEXT: start: +// CHECK-NEXT: [[B:%.*]] = alloca +// CHECK-NEXT: [[A:%.*]] = alloca +// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4096, ptr [[A]]) +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 {{.*}}, i32 4096, i1 false) +// CHECK-NEXT: call void %h(ptr {{.*}} [[A]]) +// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4096, ptr [[A]]) +// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4096, ptr [[B]]) +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[B]], ptr align 4 {{.*}}, i32 4096, i1 false) +// CHECK-NEXT: call void %h(ptr {{.*}} [[B]]) +// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4096, ptr [[B]]) +#[no_mangle] +pub fn const_indirect(h: extern "C" fn([u32; 1024])) { + const C: [u32; 1024] = [0; 1024]; + h(C); + h(C); +} + +#[repr(C)] +pub struct Str { + pub ptr: *const u8, + pub len: usize, +} + +// Pair of immediates. Regression test for #132014. +// +// CHECK-LABEL: define void @immediate_indirect(ptr {{.*}}%s.0, i32 {{.*}}%s.1, ptr {{.*}}%g) +// CHECK-NEXT: start: +// CHECK-NEXT: [[A:%.*]] = alloca +// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[A]]) +// CHECK-NEXT: store ptr %s.0, ptr [[A]] +// CHECK-NEXT: [[B:%.]] = getelementptr inbounds i8, ptr [[A]], i32 4 +// CHECK-NEXT: store i32 %s.1, ptr [[B]] +// CHECK-NEXT: call void %g(ptr {{.*}} [[A]]) +// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[A]]) +#[no_mangle] +pub fn immediate_indirect(s: Str, g: extern "C" fn(Str)) { + g(s); +} + +// Indirect argument with a higher alignment requirement than the type's. +// +// CHECK-LABEL: define void @align_indirect(ptr{{.*}} align 1{{.*}} %a, ptr{{.*}} %fun) +// CHECK-NEXT: start: +// CHECK-NEXT: [[A:%.*]] = alloca [1024 x i8], align 4 +// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 1024, ptr [[A]]) +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 1 %a, i32 1024, i1 false) +// CHECK-NEXT: call void %fun(ptr {{.*}} [[A]]) +// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 1024, ptr [[A]]) +#[no_mangle] +pub fn align_indirect(a: [u8; 1024], fun: extern "C" fn([u8; 1024])) { + fun(a); +} diff --git a/tests/codegen/issues/issue-98156-const-arg-temp-lifetime.rs b/tests/codegen/issues/issue-98156-const-arg-temp-lifetime.rs deleted file mode 100644 index aecb81caf22b1..0000000000000 --- a/tests/codegen/issues/issue-98156-const-arg-temp-lifetime.rs +++ /dev/null @@ -1,27 +0,0 @@ -// This test checks that temporaries for indirectly-passed arguments get lifetime markers. - -//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -Zmir-opt-level=0 - -#![crate_type = "lib"] - -extern "Rust" { - fn f(x: [u8; 1024]); -} - -const A: [u8; 1024] = [0; 1024]; - -// CHECK-LABEL: @const_arg_indirect -#[no_mangle] -pub unsafe fn const_arg_indirect() { - // Ensure that the live ranges for the two argument temporaries don't overlap. - - // CHECK: call void @llvm.lifetime.start - // CHECK: call void @f - // CHECK: call void @llvm.lifetime.end - // CHECK: call void @llvm.lifetime.start - // CHECK: call void @f - // CHECK: call void @llvm.lifetime.end - - f(A); - f(A); -} From 3a9ee90deda02db57e34c1434960008678d9923d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 May 2025 09:52:27 +0200 Subject: [PATCH 2371/4206] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 801f78ba85cb2..79abbfaeaf116 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -718ddf660e6a1802c39b4962cf7eaa4db57025ef +a69bc17fb8026bdc0d24bb1896ff95f0eba1da4e From b99daba38e3005f7e430655abf6138b4d9fc03e3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 May 2025 10:07:20 +0200 Subject: [PATCH 2372/4206] fix clippy lints --- src/tools/miri/cargo-miri/src/setup.rs | 8 +++----- src/tools/miri/miri-script/src/commands.rs | 14 +++++--------- src/tools/miri/src/shims/panic.rs | 1 + src/tools/miri/tests/ui.rs | 8 ++++---- 4 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/tools/miri/cargo-miri/src/setup.rs b/src/tools/miri/cargo-miri/src/setup.rs index 7afc8481009cb..b9b58c04f9e4a 100644 --- a/src/tools/miri/cargo-miri/src/setup.rs +++ b/src/tools/miri/cargo-miri/src/setup.rs @@ -24,11 +24,9 @@ pub fn setup( let ask_user = !only_setup; let print_sysroot = only_setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path let show_setup = only_setup && !print_sysroot; - if !only_setup { - if let Some(sysroot) = std::env::var_os("MIRI_SYSROOT") { - // Skip setup step if MIRI_SYSROOT is explicitly set, *unless* we are `cargo miri setup`. - return sysroot.into(); - } + if !only_setup && let Some(sysroot) = std::env::var_os("MIRI_SYSROOT") { + // Skip setup step if MIRI_SYSROOT is explicitly set, *unless* we are `cargo miri setup`. + return sysroot.into(); } // Determine where the rust sources are located. The env var trumps auto-detection. diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs index 1c9750e2cbdc1..3b7b159aeab76 100644 --- a/src/tools/miri/miri-script/src/commands.rs +++ b/src/tools/miri/miri-script/src/commands.rs @@ -675,11 +675,9 @@ impl Command { let mut early_flags = Vec::::new(); // In `dep` mode, the target is already passed via `MIRI_TEST_TARGET` - if !dep { - if let Some(target) = &target { - early_flags.push("--target".into()); - early_flags.push(target.into()); - } + if !dep && let Some(target) = &target { + early_flags.push("--target".into()); + early_flags.push(target.into()); } early_flags.push("--edition".into()); early_flags.push(edition.as_deref().unwrap_or("2021").into()); @@ -707,10 +705,8 @@ impl Command { // Add Miri flags let mut cmd = cmd.args(&miri_flags).args(&early_flags).args(&flags); // For `--dep` we also need to set the target in the env var. - if dep { - if let Some(target) = &target { - cmd = cmd.env("MIRI_TEST_TARGET", target); - } + if dep && let Some(target) = &target { + cmd = cmd.env("MIRI_TEST_TARGET", target); } // Finally, run the thing. Ok(cmd.run()?) diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs index 18af82148763a..b5ed5ea837b3d 100644 --- a/src/tools/miri/src/shims/panic.rs +++ b/src/tools/miri/src/shims/panic.rs @@ -85,6 +85,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Now we make a function call, and pass `data` as first and only argument. let f_instance = this.get_ptr_fn(try_fn)?.as_instance()?; trace!("try_fn: {:?}", f_instance); + #[allow(clippy::cloned_ref_to_slice_refs)] // the code is clearer as-is this.call_function( f_instance, ExternAbi::Rust, diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs index a7b889d966c4a..46472b51f9cd3 100644 --- a/src/tools/miri/tests/ui.rs +++ b/src/tools/miri/tests/ui.rs @@ -318,10 +318,10 @@ fn main() -> Result<()> { let mut args = std::env::args_os(); // Skip the program name and check whether this is a `./miri run-dep` invocation - if let Some(first) = args.nth(1) { - if first == "--miri-run-dep-mode" { - return run_dep_mode(target, args); - } + if let Some(first) = args.nth(1) + && first == "--miri-run-dep-mode" + { + return run_dep_mode(target, args); } ui(Mode::Pass, "tests/pass", &target, WithoutDependencies, tmpdir.path())?; From 9d47e0c8ce80d8251fa944d41bdc7f9b8b6d0c8b Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 16 Apr 2025 20:12:17 -0400 Subject: [PATCH 2373/4206] clippy_dev: remove the need for markers when bumping the version --- Cargo.toml | 2 - clippy_config/Cargo.toml | 2 - clippy_dev/src/release.rs | 24 ++++---- clippy_dev/src/utils.rs | 120 +++++++++++++++++++++++++++++--------- clippy_lints/Cargo.toml | 2 - clippy_utils/Cargo.toml | 2 - 6 files changed, 105 insertions(+), 47 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b6a1b9314c651..2da350ba44e34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,6 @@ [package] name = "clippy" -# begin autogenerated version version = "0.1.89" -# end autogenerated version description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/clippy_config/Cargo.toml b/clippy_config/Cargo.toml index 1134b0e97af22..0606245f990c1 100644 --- a/clippy_config/Cargo.toml +++ b/clippy_config/Cargo.toml @@ -1,8 +1,6 @@ [package] name = "clippy_config" -# begin autogenerated version version = "0.1.89" -# end autogenerated version edition = "2024" publish = false diff --git a/clippy_dev/src/release.rs b/clippy_dev/src/release.rs index d3b1a7ff3201f..62c1bee81850e 100644 --- a/clippy_dev/src/release.rs +++ b/clippy_dev/src/release.rs @@ -1,4 +1,4 @@ -use crate::utils::{FileUpdater, Version, update_text_region_fn}; +use crate::utils::{FileUpdater, UpdateStatus, Version, parse_cargo_package}; use std::fmt::Write; static CARGO_TOML_FILES: &[&str] = &[ @@ -13,15 +13,17 @@ pub fn bump_version(mut version: Version) { let mut updater = FileUpdater::default(); for file in CARGO_TOML_FILES { - updater.update_file( - file, - &mut update_text_region_fn( - "# begin autogenerated version\n", - "# end autogenerated version", - |dst| { - writeln!(dst, "version = \"{}\"", version.toml_display()).unwrap(); - }, - ), - ); + updater.update_file(file, &mut |_, src, dst| { + let package = parse_cargo_package(src); + if package.version_range.is_empty() { + dst.push_str(src); + UpdateStatus::Unchanged + } else { + dst.push_str(&src[..package.version_range.start]); + write!(dst, "\"{}\"", version.toml_display()).unwrap(); + dst.push_str(&src[package.version_range.end..]); + UpdateStatus::from_changed(src.get(package.version_range.clone()) != dst.get(package.version_range)) + } + }); } } diff --git a/clippy_dev/src/utils.rs b/clippy_dev/src/utils.rs index fb2e25e655dc4..7fab64eb7aa9f 100644 --- a/clippy_dev/src/utils.rs +++ b/clippy_dev/src/utils.rs @@ -1,4 +1,5 @@ use core::fmt::{self, Display}; +use core::ops::Range; use core::slice; use core::str::FromStr; use rustc_lexer::{self as lexer, FrontmatterAllowed}; @@ -166,9 +167,85 @@ impl Version { } } +enum TomlPart<'a> { + Table(&'a str), + Value(&'a str, &'a str), +} + +fn toml_iter(s: &str) -> impl Iterator)> { + let mut pos = 0; + s.split('\n') + .map(move |s| { + let x = pos; + pos += s.len() + 1; + (x, s) + }) + .filter_map(|(pos, s)| { + if let Some(s) = s.strip_prefix('[') { + s.split_once(']').map(|(name, _)| (pos, TomlPart::Table(name))) + } else if matches!( + s.as_bytes().get(0), + Some(b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_') + ) { + s.split_once('=').map(|(key, value)| (pos, TomlPart::Value(key, value))) + } else { + None + } + }) +} + +pub struct CargoPackage<'a> { + pub name: &'a str, + pub version_range: Range, + pub not_a_platform_range: Range, +} + +pub fn parse_cargo_package(s: &str) -> CargoPackage<'_> { + let mut in_package = false; + let mut in_platform_deps = false; + let mut name = ""; + let mut version_range = 0..0; + let mut not_a_platform_range = 0..0; + for (offset, part) in toml_iter(s) { + match part { + TomlPart::Table(name) => { + if in_platform_deps { + not_a_platform_range.end = offset; + } + in_package = false; + in_platform_deps = false; + + match name.trim() { + "package" => in_package = true, + "target.'cfg(NOT_A_PLATFORM)'.dependencies" => { + in_platform_deps = true; + not_a_platform_range.start = offset; + }, + _ => {}, + } + }, + TomlPart::Value(key, value) if in_package => match key.trim_end() { + "name" => name = value.trim(), + "version" => { + version_range.start = offset + (value.len() - value.trim().len()) + key.len() + 1; + version_range.end = offset + key.len() + value.trim_end().len() + 1; + }, + _ => {}, + }, + _ => {}, + } + } + CargoPackage { + name, + version_range, + not_a_platform_range, + } +} + pub struct ClippyInfo { pub path: PathBuf, pub version: Version, + pub has_intellij_hook: bool, } impl ClippyInfo { #[must_use] @@ -178,35 +255,22 @@ impl ClippyInfo { loop { path.push("Cargo.toml"); if let Some(mut file) = File::open_if_exists(&path, OpenOptions::new().read(true)) { - let mut in_package = false; - let mut is_clippy = false; - let mut version: Option = None; - - // Ad-hoc parsing to avoid dependencies. We control all the file so this - // isn't actually a problem - for line in file.read_to_cleared_string(&mut buf).lines() { - if line.starts_with('[') { - in_package = line.starts_with("[package]"); - } else if in_package && let Some((name, value)) = line.split_once('=') { - match name.trim() { - "name" => is_clippy = value.trim() == "\"clippy\"", - "version" - if let Some(value) = value.trim().strip_prefix('"') - && let Some(value) = value.strip_suffix('"') => - { - version = value.parse().ok(); - }, - _ => {}, - } - } - } - - if is_clippy { - let Some(version) = version else { + file.read_to_cleared_string(&mut buf); + let package = parse_cargo_package(&buf); + if package.name == "\"clippy\"" { + if let Some(version) = buf[package.version_range].strip_prefix('"') + && let Some(version) = version.strip_suffix('"') + && let Ok(version) = version.parse() + { + path.pop(); + return ClippyInfo { + path, + version, + has_intellij_hook: !package.not_a_platform_range.is_empty(), + }; + } else { panic!("error reading clippy version from {}", file.path.display()); - }; - path.pop(); - return ClippyInfo { path, version }; + } } } diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 7e3cb40424792..39e4e2e365ea3 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,8 +1,6 @@ [package] name = "clippy_lints" -# begin autogenerated version version = "0.1.89" -# end autogenerated version description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index ac970e1c4b0a5..615c0995e8b17 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -1,8 +1,6 @@ [package] name = "clippy_utils" -# begin autogenerated version version = "0.1.89" -# end autogenerated version edition = "2024" description = "Helpful tools for writing lints, provided as they are used in Clippy" repository = "https://github.com/rust-lang/rust-clippy" From ace4c6e01587a213bd0cc78b6d8a981ba403dc81 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 May 2025 10:35:40 +0200 Subject: [PATCH 2374/4206] fix for doctest-xcompile stabilization --- src/tools/miri/cargo-miri/src/main.rs | 34 ++++++++++++------- src/tools/miri/cargo-miri/src/phases.rs | 9 ++--- src/tools/miri/test-cargo-miri/run-test.py | 17 ++++------ .../test.filter.cross-target.stdout.ref | 12 ------- .../test.multiple_targets.stdout.ref | 10 ++++++ ...rget.stdout.ref => test.no-doc.stdout.ref} | 0 .../test.subcrate.cross-target.stdout.ref | 11 ------ 7 files changed, 40 insertions(+), 53 deletions(-) delete mode 100644 src/tools/miri/test-cargo-miri/test.filter.cross-target.stdout.ref rename src/tools/miri/test-cargo-miri/{test.cross-target.stdout.ref => test.no-doc.stdout.ref} (100%) delete mode 100644 src/tools/miri/test-cargo-miri/test.subcrate.cross-target.stdout.ref diff --git a/src/tools/miri/cargo-miri/src/main.rs b/src/tools/miri/cargo-miri/src/main.rs index 322ef0a6c2aa8..4c01a81fdfdc9 100644 --- a/src/tools/miri/cargo-miri/src/main.rs +++ b/src/tools/miri/cargo-miri/src/main.rs @@ -63,27 +63,37 @@ fn main() { return; } + let Some(first) = args.next() else { + show_error!( + "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`" + ) + }; + // The way rustdoc invokes rustc is indistinguishable from the way cargo invokes rustdoc by the // arguments alone. `phase_cargo_rustdoc` sets this environment variable to let us disambiguate. if env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { // ...however, we then also see this variable when rustdoc invokes us as the testrunner! - // The runner is invoked as `$runtool ($runtool-arg)* output_file`; - // since we don't specify any runtool-args, and rustdoc supplies multiple arguments to - // the test-builder unconditionally, we can just check the number of remaining arguments: - if args.len() == 1 { - phase_runner(args, RunnerPhase::Rustdoc); - } else { - phase_rustc(args, RustcPhase::Rustdoc); + // In that case the first argument is `runner` and there are no more arguments. + match first.as_str() { + "runner" => phase_runner(args, RunnerPhase::Rustdoc), + flag if flag.starts_with("--") || flag.starts_with("@") => { + // This is probably rustdoc invoking us to build the test. But we need to get `first` + // "back onto the iterator", it is some part of the rustc invocation. + phase_rustc(iter::once(first).chain(args), RustcPhase::Rustdoc); + } + _ => { + show_error!( + "`cargo-miri` failed to recognize which phase of the build process this is, please report a bug.\n\ + We are inside MIRI_CALLED_FROM_RUSTDOC.\n\ + The command-line arguments were: {:#?}", + Vec::from_iter(env::args()), + ); + } } return; } - let Some(first) = args.next() else { - show_error!( - "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`" - ) - }; match first.as_str() { "miri" => phase_cargo_miri(args), "runner" => phase_runner(args, RunnerPhase::Cargo), diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs index cb62e12413c84..8ff5ac5d4a239 100644 --- a/src/tools/miri/cargo-miri/src/phases.rs +++ b/src/tools/miri/cargo-miri/src/phases.rs @@ -666,11 +666,6 @@ pub fn phase_rustdoc(mut args: impl Iterator) { if arg == "--extern" { // Patch --extern arguments to use *.rmeta files, since phase_cargo_rustc only creates stub *.rlib files. forward_patched_extern_arg(&mut args, &mut cmd); - } else if arg == "--test-runtool" { - // An existing --test-runtool flag indicates cargo is running in cross-target mode, which we don't support. - // Note that this is only passed when cargo is run with the unstable -Zdoctest-xcompile flag; - // otherwise, we won't be called as rustdoc at all. - show_error!("cross-interpreting doctests is not currently supported by Miri."); } else { cmd.arg(arg); } @@ -702,10 +697,10 @@ pub fn phase_rustdoc(mut args: impl Iterator) { // make sure the 'miri' flag is set for rustdoc cmd.arg("--cfg").arg("miri"); - // Make rustdoc call us back. + // Make rustdoc call us back for the build. + // (cargo already sets `--test-runtool` to us since we are the cargo test runner.) let cargo_miri_path = env::current_exe().expect("current executable path invalid"); cmd.arg("--test-builder").arg(&cargo_miri_path); // invoked by forwarding most arguments - cmd.arg("--test-runtool").arg(&cargo_miri_path); // invoked with just a single path argument debug_cmd("[cargo-miri rustdoc]", verbose, &cmd); exec(cmd) diff --git a/src/tools/miri/test-cargo-miri/run-test.py b/src/tools/miri/test-cargo-miri/run-test.py index a9d09ac7a9d6e..40bfe7f845fe5 100755 --- a/src/tools/miri/test-cargo-miri/run-test.py +++ b/src/tools/miri/test-cargo-miri/run-test.py @@ -142,24 +142,19 @@ def test_cargo_miri_run(): ) def test_cargo_miri_test(): - # rustdoc is not run on foreign targets - is_foreign = ARGS.target is not None - default_ref = "test.cross-target.stdout.ref" if is_foreign else "test.default.stdout.ref" - filter_ref = "test.filter.cross-target.stdout.ref" if is_foreign else "test.filter.stdout.ref" - test("`cargo miri test`", cargo_miri("test"), - default_ref, "test.empty.ref", + "test.default.stdout.ref", "test.empty.ref", env={'MIRIFLAGS': "-Zmiri-seed=4242"}, ) test("`cargo miri test` (no isolation, no doctests)", cargo_miri("test") + ["--bins", "--tests"], # no `--lib`, we disabled that in `Cargo.toml` - "test.cross-target.stdout.ref", "test.empty.ref", + "test.no-doc.stdout.ref", "test.empty.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) test("`cargo miri test` (with filter)", cargo_miri("test") + ["--", "--format=pretty", "pl"], - filter_ref, "test.empty.ref", + "test.filter.stdout.ref", "test.empty.ref", ) test("`cargo miri test` (test target)", cargo_miri("test") + ["--test", "test", "--", "--format=pretty"], @@ -171,7 +166,7 @@ def test_cargo_miri_test(): ) test("`cargo miri t` (subcrate, no isolation)", cargo_miri("t") + ["-p", "subcrate"], - "test.subcrate.cross-target.stdout.ref" if is_foreign else "test.subcrate.stdout.ref", + "test.subcrate.stdout.ref", "test.empty.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) @@ -181,12 +176,12 @@ def test_cargo_miri_test(): ) test("`cargo miri test` (custom target dir)", cargo_miri("test") + ["--target-dir=custom-test"], - default_ref, "test.empty.ref", + "test.default.stdout.ref", "test.empty.ref", ) del os.environ["CARGO_TARGET_DIR"] # this overrides `build.target-dir` passed by `--config`, so unset it test("`cargo miri test` (config-cli)", cargo_miri("test") + ["--config=build.target-dir=\"config-cli\""], - default_ref, "test.empty.ref", + "test.default.stdout.ref", "test.empty.ref", ) if ARGS.multi_target: test_cargo_miri_multi_target() diff --git a/src/tools/miri/test-cargo-miri/test.filter.cross-target.stdout.ref b/src/tools/miri/test-cargo-miri/test.filter.cross-target.stdout.ref deleted file mode 100644 index 59b4deb1ff32b..0000000000000 --- a/src/tools/miri/test-cargo-miri/test.filter.cross-target.stdout.ref +++ /dev/null @@ -1,12 +0,0 @@ - -running 0 tests - -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in $TIME - -imported main - -running 1 test -test simple ... ok - -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 5 filtered out; finished in $TIME - diff --git a/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref b/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref index 567c5db07d06b..a376530a8cfb2 100644 --- a/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref +++ b/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref @@ -20,3 +20,13 @@ running 6 tests ...i.. test result: ok. 5 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME + +running 5 tests +..... +test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + + +running 5 tests +..... +test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/tools/miri/test-cargo-miri/test.cross-target.stdout.ref b/src/tools/miri/test-cargo-miri/test.no-doc.stdout.ref similarity index 100% rename from src/tools/miri/test-cargo-miri/test.cross-target.stdout.ref rename to src/tools/miri/test-cargo-miri/test.no-doc.stdout.ref diff --git a/src/tools/miri/test-cargo-miri/test.subcrate.cross-target.stdout.ref b/src/tools/miri/test-cargo-miri/test.subcrate.cross-target.stdout.ref deleted file mode 100644 index 436e6e4fbbbca..0000000000000 --- a/src/tools/miri/test-cargo-miri/test.subcrate.cross-target.stdout.ref +++ /dev/null @@ -1,11 +0,0 @@ - -running 0 tests - -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME - - -running 0 tests - -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME - -subcrate testing From 232be558592cd9b75adb20cfd3b290672c78804e Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 16 Apr 2025 22:56:00 -0400 Subject: [PATCH 2375/4206] clippy_dev: refactor rustfmt calls --- clippy_dev/Cargo.toml | 1 - clippy_dev/src/fmt.rs | 281 +++++++----------- clippy_dev/src/lib.rs | 1 + clippy_dev/src/main.rs | 5 +- clippy_dev/src/update_lints.rs | 4 +- clippy_dev/src/utils.rs | 90 ++++-- .../non_expressive_names_error_recovery.fixed | 0 .../non_expressive_names_error_recovery.rs | 0 ...non_expressive_names_error_recovery.stderr | 2 +- 9 files changed, 180 insertions(+), 204 deletions(-) rename tests/ui/{syntax-error-recovery => skip_rustfmt}/non_expressive_names_error_recovery.fixed (100%) rename tests/ui/{syntax-error-recovery => skip_rustfmt}/non_expressive_names_error_recovery.rs (100%) rename tests/ui/{syntax-error-recovery => skip_rustfmt}/non_expressive_names_error_recovery.stderr (80%) diff --git a/clippy_dev/Cargo.toml b/clippy_dev/Cargo.toml index a963fba7d98e3..10c08dba50b90 100644 --- a/clippy_dev/Cargo.toml +++ b/clippy_dev/Cargo.toml @@ -10,7 +10,6 @@ clap = { version = "4.4", features = ["derive"] } indoc = "1.0" itertools = "0.12" opener = "0.7" -shell-escape = "0.1" walkdir = "2.3" [package.metadata.rust-analyzer] diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index b4c13213f552a..298326174a48c 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -1,19 +1,15 @@ +use crate::utils::{ClippyInfo, ErrAction, UpdateMode, panic_action, run_with_args_split, run_with_output}; use itertools::Itertools; use rustc_lexer::{TokenKind, tokenize}; -use shell_escape::escape; -use std::ffi::{OsStr, OsString}; +use std::fs; +use std::io::{self, Read}; use std::ops::ControlFlow; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::process::{self, Command, Stdio}; -use std::{fs, io}; use walkdir::WalkDir; pub enum Error { - CommandFailed(String, String), Io(io::Error), - RustfmtNotInstalled, - WalkDir(walkdir::Error), - IntellijSetupActive, Parse(PathBuf, usize, String), CheckFailed, } @@ -24,37 +20,15 @@ impl From for Error { } } -impl From for Error { - fn from(error: walkdir::Error) -> Self { - Self::WalkDir(error) - } -} - impl Error { fn display(&self) { match self { Self::CheckFailed => { eprintln!("Formatting check failed!\nRun `cargo dev fmt` to update."); }, - Self::CommandFailed(command, stderr) => { - eprintln!("error: command `{command}` failed!\nstderr: {stderr}"); - }, Self::Io(err) => { eprintln!("error: {err}"); }, - Self::RustfmtNotInstalled => { - eprintln!("error: rustfmt nightly is not installed."); - }, - Self::WalkDir(err) => { - eprintln!("error: {err}"); - }, - Self::IntellijSetupActive => { - eprintln!( - "error: a local rustc repo is enabled as path dependency via `cargo dev setup intellij`.\n\ - Not formatting because that would format the local repo as well!\n\ - Please revert the changes to `Cargo.toml`s with `cargo dev remove intellij`." - ); - }, Self::Parse(path, line, msg) => { eprintln!("error parsing `{}:{line}`: {msg}", path.display()); }, @@ -62,12 +36,6 @@ impl Error { } } -struct FmtContext { - check: bool, - verbose: bool, - rustfmt_path: String, -} - struct ClippyConf<'a> { name: &'a str, attrs: &'a str, @@ -257,155 +225,120 @@ fn fmt_conf(check: bool) -> Result<(), Error> { Ok(()) } -fn run_rustfmt(context: &FmtContext) -> Result<(), Error> { - // if we added a local rustc repo as path dependency to clippy for rust analyzer, we do NOT want to - // format because rustfmt would also format the entire rustc repo as it is a local - // dependency - if fs::read_to_string("Cargo.toml") - .expect("Failed to read clippy Cargo.toml") - .contains("[target.'cfg(NOT_A_PLATFORM)'.dependencies]") - { - return Err(Error::IntellijSetupActive); - } - - check_for_rustfmt(context)?; +fn run_rustfmt(clippy: &ClippyInfo, update_mode: UpdateMode) { + let mut rustfmt_path = String::from_utf8(run_with_output( + "rustup which rustfmt", + Command::new("rustup").args(["which", "rustfmt"]), + )) + .expect("invalid rustfmt path"); + rustfmt_path.truncate(rustfmt_path.trim_end().len()); - cargo_fmt(context, ".".as_ref())?; - cargo_fmt(context, "clippy_dev".as_ref())?; - cargo_fmt(context, "rustc_tools_util".as_ref())?; - cargo_fmt(context, "lintcheck".as_ref())?; + let mut cargo_path = String::from_utf8(run_with_output( + "rustup which cargo", + Command::new("rustup").args(["which", "cargo"]), + )) + .expect("invalid cargo path"); + cargo_path.truncate(cargo_path.trim_end().len()); + + // Start all format jobs first before waiting on the results. + let mut children = Vec::with_capacity(16); + for &path in &[ + ".", + "clippy_config", + "clippy_dev", + "clippy_lints", + "clippy_utils", + "rustc_tools_util", + "lintcheck", + ] { + let mut cmd = Command::new(&cargo_path); + cmd.current_dir(clippy.path.join(path)) + .args(["fmt"]) + .env("RUSTFMT", &rustfmt_path) + .stdout(Stdio::null()) + .stdin(Stdio::null()) + .stderr(Stdio::piped()); + if update_mode.is_check() { + cmd.arg("--check"); + } + match cmd.spawn() { + Ok(x) => children.push(("cargo fmt", x)), + Err(ref e) => panic_action(&e, ErrAction::Run, "cargo fmt".as_ref()), + } + } - let chunks = WalkDir::new("tests") - .into_iter() - .filter_map(|entry| { - let entry = entry.expect("failed to find tests"); - let path = entry.path(); - if path.extension() != Some("rs".as_ref()) - || path - .components() - .nth_back(1) - .is_some_and(|c| c.as_os_str() == "syntax-error-recovery") - || entry.file_name() == "ice-3891.rs" - { - None - } else { - Some(entry.into_path().into_os_string()) + run_with_args_split( + || { + let mut cmd = Command::new(&rustfmt_path); + if update_mode.is_check() { + cmd.arg("--check"); } - }) - .chunks(250); + cmd.stdout(Stdio::null()) + .stdin(Stdio::null()) + .stderr(Stdio::piped()) + .args(["--config", "show_parse_errors=false"]); + cmd + }, + |cmd| match cmd.spawn() { + Ok(x) => children.push(("rustfmt", x)), + Err(ref e) => panic_action(&e, ErrAction::Run, "rustfmt".as_ref()), + }, + WalkDir::new("tests") + .into_iter() + .filter_entry(|p| p.path().file_name().is_none_or(|x| x != "skip_rustfmt")) + .filter_map(|e| { + let e = e.expect("error reading `tests`"); + e.path() + .as_os_str() + .as_encoded_bytes() + .ends_with(b".rs") + .then(|| e.into_path().into_os_string()) + }), + ); - for chunk in &chunks { - rustfmt(context, chunk)?; + for (name, child) in &mut children { + match child.wait() { + Ok(status) => match (update_mode, status.exit_ok()) { + (UpdateMode::Check | UpdateMode::Change, Ok(())) => {}, + (UpdateMode::Check, Err(_)) => { + let mut s = String::new(); + if let Some(mut stderr) = child.stderr.take() + && stderr.read_to_string(&mut s).is_ok() + { + eprintln!("{s}"); + } + eprintln!("Formatting check failed!\nRun `cargo dev fmt` to update."); + process::exit(1); + }, + (UpdateMode::Change, Err(e)) => { + let mut s = String::new(); + if let Some(mut stderr) = child.stderr.take() + && stderr.read_to_string(&mut s).is_ok() + { + eprintln!("{s}"); + } + panic_action(&e, ErrAction::Run, name.as_ref()); + }, + }, + Err(ref e) => panic_action(e, ErrAction::Run, name.as_ref()), + } } - Ok(()) } // the "main" function of cargo dev fmt -pub fn run(check: bool, verbose: bool) { - let output = Command::new("rustup") - .args(["which", "rustfmt"]) - .stderr(Stdio::inherit()) - .output() - .expect("error running `rustup which rustfmt`"); - if !output.status.success() { - eprintln!("`rustup which rustfmt` did not execute successfully"); - process::exit(1); +pub fn run(clippy: &ClippyInfo, update_mode: UpdateMode) { + if clippy.has_intellij_hook { + eprintln!( + "error: a local rustc repo is enabled as path dependency via `cargo dev setup intellij`.\n\ + Not formatting because that would format the local repo as well!\n\ + Please revert the changes to `Cargo.toml`s with `cargo dev remove intellij`." + ); + return; } - let mut rustfmt_path = String::from_utf8(output.stdout).expect("invalid rustfmt path"); - rustfmt_path.truncate(rustfmt_path.trim_end().len()); + run_rustfmt(clippy, update_mode); - let context = FmtContext { - check, - verbose, - rustfmt_path, - }; - if let Err(e) = run_rustfmt(&context).and_then(|()| fmt_conf(check)) { + if let Err(e) = fmt_conf(update_mode.is_check()) { e.display(); process::exit(1); } } - -fn format_command(program: impl AsRef, dir: impl AsRef, args: &[impl AsRef]) -> String { - let arg_display: Vec<_> = args.iter().map(|a| escape(a.as_ref().to_string_lossy())).collect(); - - format!( - "cd {} && {} {}", - escape(dir.as_ref().to_string_lossy()), - escape(program.as_ref().to_string_lossy()), - arg_display.join(" ") - ) -} - -fn exec_fmt_command( - context: &FmtContext, - program: impl AsRef, - dir: impl AsRef, - args: &[impl AsRef], -) -> Result<(), Error> { - if context.verbose { - println!("{}", format_command(&program, &dir, args)); - } - - let output = Command::new(&program) - .env("RUSTFMT", &context.rustfmt_path) - .current_dir(&dir) - .args(args.iter()) - .output() - .unwrap(); - let success = output.status.success(); - - match (context.check, success) { - (_, true) => Ok(()), - (true, false) => Err(Error::CheckFailed), - (false, false) => { - let stderr = std::str::from_utf8(&output.stderr).unwrap_or(""); - Err(Error::CommandFailed( - format_command(&program, &dir, args), - String::from(stderr), - )) - }, - } -} - -fn cargo_fmt(context: &FmtContext, path: &Path) -> Result<(), Error> { - let mut args = vec!["fmt", "--all"]; - if context.check { - args.push("--check"); - } - exec_fmt_command(context, "cargo", path, &args) -} - -fn check_for_rustfmt(context: &FmtContext) -> Result<(), Error> { - let program = "rustfmt"; - let dir = std::env::current_dir()?; - let args = &["--version"]; - - if context.verbose { - println!("{}", format_command(program, &dir, args)); - } - - let output = Command::new(program).current_dir(&dir).args(args.iter()).output()?; - - if output.status.success() { - Ok(()) - } else if std::str::from_utf8(&output.stderr) - .unwrap_or("") - .starts_with("error: 'rustfmt' is not installed") - { - Err(Error::RustfmtNotInstalled) - } else { - Err(Error::CommandFailed( - format_command(program, &dir, args), - std::str::from_utf8(&output.stderr).unwrap_or("").to_string(), - )) - } -} - -fn rustfmt(context: &FmtContext, paths: impl Iterator) -> Result<(), Error> { - let mut args = Vec::new(); - if context.check { - args.push(OsString::from("--check")); - } - args.extend(paths); - exec_fmt_command(context, &context.rustfmt_path, std::env::current_dir()?, &args) -} diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 1cfcbdfe855e9..3361443196ab5 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -1,5 +1,6 @@ #![feature( rustc_private, + exit_status_error, if_let_guard, let_chains, os_str_slice, diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 5dce0be742b26..ebcd8611d78cd 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -26,7 +26,7 @@ fn main() { allow_staged, allow_no_vcs, } => dogfood::dogfood(fix, allow_dirty, allow_staged, allow_no_vcs), - DevCommand::Fmt { check, verbose } => fmt::run(check, verbose), + DevCommand::Fmt { check } => fmt::run(&clippy, utils::UpdateMode::from_check(check)), DevCommand::UpdateLints { check } => update_lints::update(utils::UpdateMode::from_check(check)), DevCommand::NewLint { pass, @@ -125,9 +125,6 @@ enum DevCommand { #[arg(long)] /// Use the rustfmt --check option check: bool, - #[arg(short, long)] - /// Echo commands run - verbose: bool, }, #[command(name = "update_lints")] /// Updates lint registration and information from the source code diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 8e203ae514222..25ba2c7204904 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -1,5 +1,5 @@ use crate::utils::{ - File, FileAction, FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, panic_file, update_text_region_fn, + ErrAction, File, FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, panic_action, update_text_region_fn, }; use itertools::Itertools; use std::collections::HashSet; @@ -203,7 +203,7 @@ fn read_src_with_module(src_root: &Path) -> impl use<'_> + Iterator e, - Err(ref e) => panic_file(e, FileAction::Read, src_root), + Err(ref e) => panic_action(e, ErrAction::Read, src_root), }; let path = e.path().as_os_str().as_encoded_bytes(); if let Some(path) = path.strip_suffix(b".rs") diff --git a/clippy_dev/src/utils.rs b/clippy_dev/src/utils.rs index 7fab64eb7aa9f..255e36afe69c2 100644 --- a/clippy_dev/src/utils.rs +++ b/clippy_dev/src/utils.rs @@ -4,10 +4,11 @@ use core::slice; use core::str::FromStr; use rustc_lexer::{self as lexer, FrontmatterAllowed}; use std::env; +use std::ffi::OsStr; use std::fs::{self, OpenOptions}; use std::io::{self, Read as _, Seek as _, SeekFrom, Write}; use std::path::{Path, PathBuf}; -use std::process::{self, ExitStatus}; +use std::process::{self, Command, ExitStatus, Stdio}; #[cfg(not(windows))] static CARGO_CLIPPY_EXE: &str = "cargo-clippy"; @@ -15,15 +16,16 @@ static CARGO_CLIPPY_EXE: &str = "cargo-clippy"; static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe"; #[derive(Clone, Copy)] -pub enum FileAction { +pub enum ErrAction { Open, Read, Write, Create, Rename, Delete, + Run, } -impl FileAction { +impl ErrAction { fn as_str(self) -> &'static str { match self { Self::Open => "opening", @@ -32,13 +34,14 @@ impl FileAction { Self::Create => "creating", Self::Rename => "renaming", Self::Delete => "deleting", + Self::Run => "running", } } } #[cold] #[track_caller] -pub fn panic_file(err: &impl Display, action: FileAction, path: &Path) -> ! { +pub fn panic_action(err: &impl Display, action: ErrAction, path: &Path) -> ! { panic!("error {} `{}`: {}", action.as_str(), path.display(), *err) } @@ -54,7 +57,7 @@ impl<'a> File<'a> { let path = path.as_ref(); match options.open(path) { Ok(inner) => Self { inner, path }, - Err(e) => panic_file(&e, FileAction::Open, path), + Err(e) => panic_action(&e, ErrAction::Open, path), } } @@ -65,7 +68,7 @@ impl<'a> File<'a> { match options.open(path) { Ok(inner) => Some(Self { inner, path }), Err(e) if e.kind() == io::ErrorKind::NotFound => None, - Err(e) => panic_file(&e, FileAction::Open, path), + Err(e) => panic_action(&e, ErrAction::Open, path), } } @@ -83,7 +86,7 @@ impl<'a> File<'a> { pub fn read_append_to_string<'dst>(&mut self, dst: &'dst mut String) -> &'dst mut String { match self.inner.read_to_string(dst) { Ok(_) => {}, - Err(e) => panic_file(&e, FileAction::Read, self.path), + Err(e) => panic_action(&e, ErrAction::Read, self.path), } dst } @@ -105,7 +108,7 @@ impl<'a> File<'a> { Err(e) => Err(e), }; if let Err(e) = res { - panic_file(&e, FileAction::Write, self.path); + panic_action(&e, ErrAction::Write, self.path); } } } @@ -183,10 +186,7 @@ fn toml_iter(s: &str) -> impl Iterator)> { .filter_map(|(pos, s)| { if let Some(s) = s.strip_prefix('[') { s.split_once(']').map(|(name, _)| (pos, TomlPart::Table(name))) - } else if matches!( - s.as_bytes().get(0), - Some(b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_') - ) { + } else if matches!(s.bytes().next(), Some(b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_')) { s.split_once('=').map(|(key, value)| (pos, TomlPart::Value(key, value))) } else { None @@ -200,6 +200,7 @@ pub struct CargoPackage<'a> { pub not_a_platform_range: Range, } +#[must_use] pub fn parse_cargo_package(s: &str) -> CargoPackage<'_> { let mut in_package = false; let mut in_platform_deps = false; @@ -232,7 +233,7 @@ pub fn parse_cargo_package(s: &str) -> CargoPackage<'_> { }, _ => {}, }, - _ => {}, + TomlPart::Value(..) => {}, } } CargoPackage { @@ -268,9 +269,8 @@ impl ClippyInfo { version, has_intellij_hook: !package.not_a_platform_range.is_empty(), }; - } else { - panic!("error reading clippy version from {}", file.path.display()); } + panic!("error reading clippy version from `{}`", file.path.display()); } } @@ -323,6 +323,11 @@ impl UpdateMode { pub fn from_check(check: bool) -> Self { if check { Self::Check } else { Self::Change } } + + #[must_use] + pub fn is_check(self) -> bool { + matches!(self, Self::Check) + } } #[derive(Default)] @@ -611,7 +616,7 @@ pub fn try_rename_file(old_name: &Path, new_name: &Path) -> bool { match OpenOptions::new().create_new(true).write(true).open(new_name) { Ok(file) => drop(file), Err(e) if matches!(e.kind(), io::ErrorKind::AlreadyExists | io::ErrorKind::NotFound) => return false, - Err(ref e) => panic_file(e, FileAction::Create, new_name), + Err(ref e) => panic_action(e, ErrAction::Create, new_name), } match fs::rename(old_name, new_name) { Ok(()) => true, @@ -622,7 +627,7 @@ pub fn try_rename_file(old_name: &Path, new_name: &Path) -> bool { if matches!(e.kind(), io::ErrorKind::NotFound | io::ErrorKind::NotADirectory) { false } else { - panic_file(e, FileAction::Rename, old_name); + panic_action(e, ErrAction::Rename, old_name); } }, } @@ -633,7 +638,7 @@ pub fn try_rename_dir(old_name: &Path, new_name: &Path) -> bool { match fs::create_dir(new_name) { Ok(()) => {}, Err(e) if matches!(e.kind(), io::ErrorKind::AlreadyExists | io::ErrorKind::NotFound) => return false, - Err(ref e) => panic_file(e, FileAction::Create, new_name), + Err(ref e) => panic_action(e, ErrAction::Create, new_name), } // Windows can't reliably rename to an empty directory. #[cfg(windows)] @@ -648,14 +653,55 @@ pub fn try_rename_dir(old_name: &Path, new_name: &Path) -> bool { if matches!(e.kind(), io::ErrorKind::NotFound | io::ErrorKind::NotADirectory) { false } else { - panic_file(e, FileAction::Rename, old_name); + panic_action(e, ErrAction::Rename, old_name); } }, } } pub fn write_file(path: &Path, contents: &str) { - fs::write(path, contents).unwrap_or_else(|e| panic_file(&e, FileAction::Write, path)); + fs::write(path, contents).unwrap_or_else(|e| panic_action(&e, ErrAction::Write, path)); +} + +#[must_use] +pub fn run_with_output(path: &(impl AsRef + ?Sized), cmd: &mut Command) -> Vec { + fn f(path: &Path, cmd: &mut Command) -> Vec { + match cmd + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .output() + { + Ok(x) => match x.status.exit_ok() { + Ok(()) => x.stdout, + Err(ref e) => panic_action(e, ErrAction::Run, path), + }, + Err(ref e) => panic_action(e, ErrAction::Run, path), + } + } + f(path.as_ref(), cmd) +} + +pub fn run_with_args_split( + mut make_cmd: impl FnMut() -> Command, + mut run_cmd: impl FnMut(&mut Command), + args: impl Iterator>, +) { + let mut cmd = make_cmd(); + let mut len = 0; + for arg in args { + len += arg.as_ref().len(); + cmd.arg(arg); + // Very conservative limit + if len > 10000 { + run_cmd(&mut cmd); + cmd = make_cmd(); + len = 0; + } + } + if len != 0 { + run_cmd(&mut cmd); + } } #[expect(clippy::must_use_candidate)] @@ -663,7 +709,7 @@ pub fn delete_file_if_exists(path: &Path) -> bool { match fs::remove_file(path) { Ok(()) => true, Err(e) if matches!(e.kind(), io::ErrorKind::NotFound | io::ErrorKind::IsADirectory) => false, - Err(ref e) => panic_file(e, FileAction::Delete, path), + Err(ref e) => panic_action(e, ErrAction::Delete, path), } } @@ -671,6 +717,6 @@ pub fn delete_dir_if_exists(path: &Path) { match fs::remove_dir_all(path) { Ok(()) => {}, Err(e) if matches!(e.kind(), io::ErrorKind::NotFound | io::ErrorKind::NotADirectory) => {}, - Err(ref e) => panic_file(e, FileAction::Delete, path), + Err(ref e) => panic_action(e, ErrAction::Delete, path), } } diff --git a/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.fixed b/tests/ui/skip_rustfmt/non_expressive_names_error_recovery.fixed similarity index 100% rename from tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.fixed rename to tests/ui/skip_rustfmt/non_expressive_names_error_recovery.fixed diff --git a/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs b/tests/ui/skip_rustfmt/non_expressive_names_error_recovery.rs similarity index 100% rename from tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs rename to tests/ui/skip_rustfmt/non_expressive_names_error_recovery.rs diff --git a/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.stderr b/tests/ui/skip_rustfmt/non_expressive_names_error_recovery.stderr similarity index 80% rename from tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.stderr rename to tests/ui/skip_rustfmt/non_expressive_names_error_recovery.stderr index e334ca5241eba..4998b9bd2cc40 100644 --- a/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.stderr +++ b/tests/ui/skip_rustfmt/non_expressive_names_error_recovery.stderr @@ -1,5 +1,5 @@ error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `)` - --> tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs:6:19 + --> tests/ui/skip_rustfmt/non_expressive_names_error_recovery.rs:6:19 | LL | fn aa(a: Aa Date: Sat, 17 May 2025 13:18:46 +0300 Subject: [PATCH 2376/4206] opt-dist: fix deprecated BOLT -icf=1 option --- src/tools/opt-dist/src/bolt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/opt-dist/src/bolt.rs b/src/tools/opt-dist/src/bolt.rs index 0f1fda38115c7..a06e59fcc412c 100644 --- a/src/tools/opt-dist/src/bolt.rs +++ b/src/tools/opt-dist/src/bolt.rs @@ -80,7 +80,7 @@ pub fn bolt_optimize( // Move jump tables to a separate section .arg("-jump-tables=move") // Fold functions with identical code - .arg("-icf=1") + .arg("-icf=all") // The following flag saves about 50 MiB of libLLVM.so size. // However, it succeeds very non-deterministically. To avoid frequent artifact size swings, // it is kept disabled for now. From 1c9f20f24c9363eedaf5ea16f7e8f8746c80e1e8 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 17 May 2025 12:45:32 +0200 Subject: [PATCH 2377/4206] Enable rust-analyzer to go from query definition to the corresponding provider field --- compiler/rustc_macros/src/query.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 33fb13e23bf89..ee377277017a5 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -267,6 +267,18 @@ fn add_query_desc_cached_impl( ) { let Query { name, key, modifiers, .. } = &query; + // This dead code exists to instruct rust-analyzer about the link between the `rustc_queries` + // query names and the corresponding produced provider. The issue is that by nature of this + // macro producing a higher order macro that has all its token in the macro declaration we lose + // any meaningful spans, resulting in rust-analyzer being unable to make the connection between + // the query name and the corresponding providers field. The trick to fix this is to have + // `rustc_queries` emit a field access with the given name's span which allows it to succesfully + // show references / go to definition to the correspondig provider assignment which is usually + // the more interesting place. + let ra_hint = quote! { + let crate::query::Providers { #name: _, .. }; + }; + // Find out if we should cache the query on disk let cache = if let Some((args, expr)) = modifiers.cache.as_ref() { let tcx = args.as_ref().map(|t| quote! { #t }).unwrap_or_else(|| quote! { _ }); @@ -277,6 +289,7 @@ fn add_query_desc_cached_impl( #[allow(unused_variables, unused_braces, rustc::pass_by_value)] #[inline] pub fn #name<'tcx>(#tcx: TyCtxt<'tcx>, #key: &crate::query::queries::#name::Key<'tcx>) -> bool { + #ra_hint #expr } } @@ -286,6 +299,7 @@ fn add_query_desc_cached_impl( #[allow(rustc::pass_by_value)] #[inline] pub fn #name<'tcx>(_: TyCtxt<'tcx>, _: &crate::query::queries::#name::Key<'tcx>) -> bool { + #ra_hint false } } From c9b6ccc11ce82c753702716f57f786acf322e64f Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Sat, 17 May 2025 12:50:37 +0200 Subject: [PATCH 2378/4206] Switch library rustc_unimplemented to use `Self` and `This` --- library/core/src/convert/mod.rs | 2 +- library/core/src/fmt/mod.rs | 10 ++--- library/core/src/iter/traits/collect.rs | 33 +++++++--------- library/core/src/iter/traits/iterator.rs | 4 +- library/core/src/marker.rs | 50 ++++++++++++------------ library/core/src/ops/arith.rs | 4 +- library/core/src/ops/function.rs | 6 +-- library/core/src/ops/index.rs | 6 +-- library/core/src/ops/try_trait.rs | 18 ++++----- library/core/src/slice/index.rs | 2 +- library/std/src/process.rs | 2 +- 11 files changed, 67 insertions(+), 70 deletions(-) diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index e1b10e1074d27..aeafc1be3598f 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -575,7 +575,7 @@ pub trait Into: Sized { #[rustc_diagnostic_item = "From"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(on( - all(_Self = "&str", T = "alloc::string::String"), + all(Self = "&str", T = "alloc::string::String"), note = "to coerce a `{T}` into a `{Self}`, use `&*` as a prefix", ))] #[doc(search_unbox)] diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 4f7f8a5b84dd5..5978cb660f6b3 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -856,10 +856,10 @@ impl Display for Arguments<'_> { on( crate_local, label = "`{Self}` cannot be formatted using `{{:?}}`", - note = "add `#[derive(Debug)]` to `{Self}` or manually `impl {Debug} for {Self}`" + note = "add `#[derive(Debug)]` to `{Self}` or manually `impl {This} for {Self}`" ), - message = "`{Self}` doesn't implement `{Debug}`", - label = "`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{Debug}`" + message = "`{Self}` doesn't implement `{This}`", + label = "`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{This}`" )] #[doc(alias = "{:?}")] #[rustc_diagnostic_item = "Debug"] @@ -969,12 +969,12 @@ pub use macros::Debug; /// ``` #[rustc_on_unimplemented( on( - any(_Self = "std::path::Path", _Self = "std::path::PathBuf"), + any(Self = "std::path::Path", Self = "std::path::PathBuf"), label = "`{Self}` cannot be formatted with the default formatter; call `.display()` on it", note = "call `.display()` or `.to_string_lossy()` to safely print paths, \ as they may contain non-Unicode data" ), - message = "`{Self}` doesn't implement `{Display}`", + message = "`{Self}` doesn't implement `{This}`", label = "`{Self}` cannot be formatted with the default formatter", note = "in format strings you may be able to use `{{:?}}` (or {{:#?}} for pretty-print) instead" )] diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 97bb21c8a36e8..3bc9cff8072bf 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -97,32 +97,32 @@ use super::TrustedLen; #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented( on( - _Self = "&[{A}]", + Self = "&[{A}]", message = "a slice of type `{Self}` cannot be built since we need to store the elements somewhere", label = "try explicitly collecting into a `Vec<{A}>`", ), on( - all(A = "{integer}", any(_Self = "&[{integral}]",)), + all(A = "{integer}", any(Self = "&[{integral}]",)), message = "a slice of type `{Self}` cannot be built since we need to store the elements somewhere", label = "try explicitly collecting into a `Vec<{A}>`", ), on( - _Self = "[{A}]", + Self = "[{A}]", message = "a slice of type `{Self}` cannot be built since `{Self}` has no definite size", label = "try explicitly collecting into a `Vec<{A}>`", ), on( - all(A = "{integer}", any(_Self = "[{integral}]",)), + all(A = "{integer}", any(Self = "[{integral}]",)), message = "a slice of type `{Self}` cannot be built since `{Self}` has no definite size", label = "try explicitly collecting into a `Vec<{A}>`", ), on( - _Self = "[{A}; _]", + Self = "[{A}; _]", message = "an array of type `{Self}` cannot be built directly from an iterator", label = "try collecting into a `Vec<{A}>`, then using `.try_into()`", ), on( - all(A = "{integer}", any(_Self = "[{integral}; _]",)), + all(A = "{integer}", any(Self = "[{integral}; _]",)), message = "an array of type `{Self}` cannot be built directly from an iterator", label = "try collecting into a `Vec<{A}>`, then using `.try_into()`", ), @@ -239,41 +239,38 @@ pub trait FromIterator: Sized { #[rustc_diagnostic_item = "IntoIterator"] #[rustc_on_unimplemented( on( - _Self = "core::ops::range::RangeTo", + Self = "core::ops::range::RangeTo", label = "if you meant to iterate until a value, add a starting value", note = "`..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a \ bounded `Range`: `0..end`" ), on( - _Self = "core::ops::range::RangeToInclusive", + Self = "core::ops::range::RangeToInclusive", label = "if you meant to iterate until a value (including it), add a starting value", note = "`..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant \ to have a bounded `RangeInclusive`: `0..=end`" ), on( - _Self = "[]", + Self = "[]", label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`" ), - on(_Self = "&[]", label = "`{Self}` is not an iterator; try calling `.iter()`"), + on(Self = "&[]", label = "`{Self}` is not an iterator; try calling `.iter()`"), on( - _Self = "alloc::vec::Vec", + Self = "alloc::vec::Vec", label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`" ), + on(Self = "&str", label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"), on( - _Self = "&str", + Self = "alloc::string::String", label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`" ), on( - _Self = "alloc::string::String", - label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`" - ), - on( - _Self = "{integral}", + Self = "{integral}", note = "if you want to iterate between `start` until a value `end`, use the exclusive range \ syntax `start..end` or the inclusive range syntax `start..=end`" ), on( - _Self = "{float}", + Self = "{float}", note = "if you want to iterate between `start` until a value `end`, use the exclusive range \ syntax `start..end` or the inclusive range syntax `start..=end`" ), diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index d1e71f0e60f2a..cf85bdb1352ba 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -22,11 +22,11 @@ fn _assert_is_dyn_compatible(_: &dyn Iterator) {} #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented( on( - _Self = "core::ops::range::RangeTo", + Self = "core::ops::range::RangeTo", note = "you might have meant to use a bounded `Range`" ), on( - _Self = "core::ops::range::RangeToInclusive", + Self = "core::ops::range::RangeToInclusive", note = "you might have meant to use a bounded `RangeInclusive`" ), label = "`{Self}` is not an iterator", diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index f33b8d188d86c..700fb0f386eed 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -550,72 +550,72 @@ pub trait BikeshedGuaranteedNoDrop {} #[lang = "sync"] #[rustc_on_unimplemented( on( - _Self = "core::cell::once::OnceCell", + Self = "core::cell::once::OnceCell", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::OnceLock` instead" ), on( - _Self = "core::cell::Cell", + Self = "core::cell::Cell", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU8` instead", ), on( - _Self = "core::cell::Cell", + Self = "core::cell::Cell", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU16` instead", ), on( - _Self = "core::cell::Cell", + Self = "core::cell::Cell", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU32` instead", ), on( - _Self = "core::cell::Cell", + Self = "core::cell::Cell", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU64` instead", ), on( - _Self = "core::cell::Cell", + Self = "core::cell::Cell", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicUsize` instead", ), on( - _Self = "core::cell::Cell", + Self = "core::cell::Cell", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI8` instead", ), on( - _Self = "core::cell::Cell", + Self = "core::cell::Cell", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI16` instead", ), on( - _Self = "core::cell::Cell", + Self = "core::cell::Cell", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead", ), on( - _Self = "core::cell::Cell", + Self = "core::cell::Cell", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI64` instead", ), on( - _Self = "core::cell::Cell", + Self = "core::cell::Cell", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicIsize` instead", ), on( - _Self = "core::cell::Cell", + Self = "core::cell::Cell", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicBool` instead", ), on( all( - _Self = "core::cell::Cell", - not(_Self = "core::cell::Cell"), - not(_Self = "core::cell::Cell"), - not(_Self = "core::cell::Cell"), - not(_Self = "core::cell::Cell"), - not(_Self = "core::cell::Cell"), - not(_Self = "core::cell::Cell"), - not(_Self = "core::cell::Cell"), - not(_Self = "core::cell::Cell"), - not(_Self = "core::cell::Cell"), - not(_Self = "core::cell::Cell"), - not(_Self = "core::cell::Cell") + Self = "core::cell::Cell", + not(Self = "core::cell::Cell"), + not(Self = "core::cell::Cell"), + not(Self = "core::cell::Cell"), + not(Self = "core::cell::Cell"), + not(Self = "core::cell::Cell"), + not(Self = "core::cell::Cell"), + not(Self = "core::cell::Cell"), + not(Self = "core::cell::Cell"), + not(Self = "core::cell::Cell"), + not(Self = "core::cell::Cell"), + not(Self = "core::cell::Cell") ), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock`", ), on( - _Self = "core::cell::RefCell", + Self = "core::cell::RefCell", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead", ), message = "`{Self}` cannot be shared between threads safely", diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs index 54d79beca95ab..098ce4531f0c0 100644 --- a/library/core/src/ops/arith.rs +++ b/library/core/src/ops/arith.rs @@ -67,8 +67,8 @@ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_ops", issue = "90080")] #[rustc_on_unimplemented( - on(all(_Self = "{integer}", Rhs = "{float}"), message = "cannot add a float to an integer",), - on(all(_Self = "{float}", Rhs = "{integer}"), message = "cannot add an integer to a float",), + on(all(Self = "{integer}", Rhs = "{float}"), message = "cannot add a float to an integer",), + on(all(Self = "{float}", Rhs = "{integer}"), message = "cannot add an integer to a float",), message = "cannot add `{Rhs}` to `{Self}`", label = "no implementation for `{Self} + {Rhs}`", append_const_msg diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs index e9014458b48ea..df48c104410ca 100644 --- a/library/core/src/ops/function.rs +++ b/library/core/src/ops/function.rs @@ -62,7 +62,7 @@ use crate::marker::Tuple; note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`" ), on( - _Self = "unsafe fn", + Self = "unsafe fn", note = "unsafe function cannot be called generically without an unsafe block", // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string label = "call the function in a closure: `|| unsafe {{ /* code */ }}`" @@ -149,7 +149,7 @@ pub trait Fn: FnMut { note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`" ), on( - _Self = "unsafe fn", + Self = "unsafe fn", note = "unsafe function cannot be called generically without an unsafe block", // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string label = "call the function in a closure: `|| unsafe {{ /* code */ }}`" @@ -228,7 +228,7 @@ pub trait FnMut: FnOnce { note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`" ), on( - _Self = "unsafe fn", + Self = "unsafe fn", note = "unsafe function cannot be called generically without an unsafe block", // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string label = "call the function in a closure: `|| unsafe {{ /* code */ }}`" diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs index 46e19bed43aba..8092fa9eb2fc5 100644 --- a/library/core/src/ops/index.rs +++ b/library/core/src/ops/index.rs @@ -144,17 +144,17 @@ pub trait Index { #[lang = "index_mut"] #[rustc_on_unimplemented( on( - _Self = "&str", + Self = "&str", note = "you can use `.chars().nth()` or `.bytes().nth()` see chapter in The Book " ), on( - _Self = "str", + Self = "str", note = "you can use `.chars().nth()` or `.bytes().nth()` see chapter in The Book " ), on( - _Self = "alloc::string::String", + Self = "alloc::string::String", note = "you can use `.chars().nth()` or `.bytes().nth()` see chapter in The Book " ), diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index 3ba2957526f9c..bac8ffb074ba8 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -117,12 +117,12 @@ use crate::ops::ControlFlow; on( all(from_desugaring = "TryBlock"), message = "a `try` block must return `Result` or `Option` \ - (or another type that implements `{Try}`)", + (or another type that implements `{This}`)", label = "could not wrap the final value of the block as `{Self}` doesn't implement `Try`", ), on( all(from_desugaring = "QuestionMark"), - message = "the `?` operator can only be applied to values that implement `{Try}`", + message = "the `?` operator can only be applied to values that implement `{This}`", label = "the `?` operator cannot be applied to type `{Self}`" ) )] @@ -226,7 +226,7 @@ pub trait Try: FromResidual { on( all( from_desugaring = "QuestionMark", - _Self = "core::result::Result", + Self = "core::result::Result", R = "core::option::Option", ), message = "the `?` operator can only be used on `Result`s, not `Option`s, \ @@ -237,7 +237,7 @@ pub trait Try: FromResidual { on( all( from_desugaring = "QuestionMark", - _Self = "core::result::Result", + Self = "core::result::Result", ), // There's a special error message in the trait selection code for // `From` in `?`, so this is not shown for result-in-result errors, @@ -250,7 +250,7 @@ pub trait Try: FromResidual { on( all( from_desugaring = "QuestionMark", - _Self = "core::option::Option", + Self = "core::option::Option", R = "core::result::Result", ), message = "the `?` operator can only be used on `Option`s, not `Result`s, \ @@ -261,7 +261,7 @@ pub trait Try: FromResidual { on( all( from_desugaring = "QuestionMark", - _Self = "core::option::Option", + Self = "core::option::Option", ), // `Option`-in-`Option` always works, as there's only one possible // residual, so this can also be phrased strongly. @@ -273,7 +273,7 @@ pub trait Try: FromResidual { on( all( from_desugaring = "QuestionMark", - _Self = "core::ops::control_flow::ControlFlow", + Self = "core::ops::control_flow::ControlFlow", R = "core::ops::control_flow::ControlFlow", ), message = "the `?` operator in {ItemContext} that returns `ControlFlow` \ @@ -285,7 +285,7 @@ pub trait Try: FromResidual { on( all( from_desugaring = "QuestionMark", - _Self = "core::ops::control_flow::ControlFlow", + Self = "core::ops::control_flow::ControlFlow", // `R` is not a `ControlFlow`, as that case was matched previously ), message = "the `?` operator can only be used on `ControlFlow`s \ @@ -297,7 +297,7 @@ pub trait Try: FromResidual { all(from_desugaring = "QuestionMark"), message = "the `?` operator can only be used in {ItemContext} \ that returns `Result` or `Option` \ - (or another type that implements `{FromResidual}`)", + (or another type that implements `{This}`)", label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`", parent_label = "this function should return `Result` or `Option` to accept `?`" ), diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index aafa19c0dd3d3..409bad9f06155 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -161,7 +161,7 @@ mod private_slice_index { #[rustc_on_unimplemented( on(T = "str", label = "string indices are ranges of `usize`",), on( - all(any(T = "str", T = "&str", T = "alloc::string::String"), _Self = "{integer}"), + all(any(T = "str", T = "&str", T = "alloc::string::String"), Self = "{integer}"), note = "you can use `.chars().nth()` or `.bytes().nth()`\n\ for more information, see chapter 8 in The Book: \ " diff --git a/library/std/src/process.rs b/library/std/src/process.rs index df6b9a6e563ce..359e208207252 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -2532,7 +2532,7 @@ pub fn id() -> u32 { #[rustc_on_unimplemented(on( cause = "MainFunctionType", message = "`main` has invalid return type `{Self}`", - label = "`main` can only return types that implement `{Termination}`" + label = "`main` can only return types that implement `{This}`" ))] pub trait Termination { /// Is called to get the representation of the value as status code. From 9578b59eacbdf73d577b70439d580ac3522856db Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 17 May 2025 12:01:13 +0000 Subject: [PATCH 2379/4206] Only select true errors in impossible_predicates --- .../rustc_trait_selection/src/traits/mod.rs | 10 ++++- .../object/ambiguity-vtable-segfault.rs | 37 +++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 tests/ui/traits/object/ambiguity-vtable-segfault.rs diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 4738a538b297f..31b075db04b96 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -701,9 +701,15 @@ pub fn impossible_predicates<'tcx>(tcx: TyCtxt<'tcx>, predicates: Vec::Assoc` and the +// built-in impl for object types. Since they differ by their region responses, +// the goal is ambiguous. This affects codegen since impossible obligations +// for method dispatch will lead to a segfault, since we end up emitting dummy +// call vtable offsets due to . + +// Test for . + +//@ run-pass + +trait Mirror { + type Assoc: ?Sized; +} +impl Mirror for T { + type Assoc = T; +} + +trait Q: 'static { + fn q(&self); +} + +impl Q for i32 { + fn q(&self) { println!("i32"); } +} + +impl Q for ::Assoc where Self: 'static { + fn q(&self) { println!("dyn Q"); } +} + +fn foo(t: &T) { + t.q(); +} + +fn main() { + foo(&1 as &dyn Q); +} From bd9f1fd273102d20aef525d1dd98632f318d39c1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 May 2025 14:22:44 +0200 Subject: [PATCH 2380/4206] exlicitly pass -Zdoctest-xcompile to avoid cargo version behavior differences --- src/tools/miri/cargo-miri/src/phases.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs index 8ff5ac5d4a239..171e157789d7f 100644 --- a/src/tools/miri/cargo-miri/src/phases.rs +++ b/src/tools/miri/cargo-miri/src/phases.rs @@ -176,6 +176,8 @@ pub fn phase_cargo_miri(mut args: impl Iterator) { // Set `--target-dir` to `miri` inside the original target directory. let target_dir = get_target_dir(&metadata); cmd.arg("--target-dir").arg(target_dir); + // Enable cross-target doctests (for consistency between different cargo versions). + cmd.arg("-Zdoctest-xcompile"); // *After* we set all the flags that need setting, forward everything else. Make sure to skip // `--target-dir` (which would otherwise be set twice). From 9cacafdd1ae7b23692d9894c6110b7f8f404b4bb Mon Sep 17 00:00:00 2001 From: klensy Date: Sat, 17 May 2025 15:25:32 +0300 Subject: [PATCH 2381/4206] compiler & tools: bump windows crate to dedupe versions --- Cargo.lock | 71 +++++------------------ compiler/rustc_codegen_ssa/Cargo.toml | 2 +- compiler/rustc_data_structures/Cargo.toml | 2 +- compiler/rustc_driver_impl/Cargo.toml | 2 +- compiler/rustc_errors/Cargo.toml | 2 +- compiler/rustc_session/Cargo.toml | 2 +- src/tools/compiletest/Cargo.toml | 2 +- src/tools/tidy/src/deps.rs | 3 + 8 files changed, 23 insertions(+), 63 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f1fddefcb0144..59f7f3dda8fcd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -738,7 +738,7 @@ dependencies = [ "tracing-subscriber", "unified-diff", "walkdir", - "windows 0.59.0", + "windows", ] [[package]] @@ -1587,7 +1587,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.61.0", + "windows-core", ] [[package]] @@ -3493,7 +3493,7 @@ dependencies = [ "thorin-dwp", "tracing", "wasm-encoder 0.219.2", - "windows 0.59.0", + "windows", ] [[package]] @@ -3552,7 +3552,7 @@ dependencies = [ "tempfile", "thin-vec", "tracing", - "windows 0.59.0", + "windows", ] [[package]] @@ -3615,7 +3615,7 @@ dependencies = [ "shlex", "stable_mir", "tracing", - "windows 0.59.0", + "windows", ] [[package]] @@ -3670,7 +3670,7 @@ dependencies = [ "termcolor", "termize", "tracing", - "windows 0.59.0", + "windows", ] [[package]] @@ -4415,7 +4415,7 @@ dependencies = [ "smallvec", "termize", "tracing", - "windows 0.59.0", + "windows", ] [[package]] @@ -5102,7 +5102,7 @@ dependencies = [ "libc", "objc2-core-foundation", "objc2-io-kit", - "windows 0.61.1", + "windows", ] [[package]] @@ -6002,16 +6002,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f919aee0a93304be7f62e8e5027811bbba96bcb1de84d6618be56e43f8a32a1" -dependencies = [ - "windows-core 0.59.0", - "windows-targets 0.53.0", -] - [[package]] name = "windows" version = "0.61.1" @@ -6019,7 +6009,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419" dependencies = [ "windows-collections", - "windows-core 0.61.0", + "windows-core", "windows-future", "windows-link", "windows-numerics", @@ -6042,20 +6032,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ - "windows-core 0.61.0", -] - -[[package]] -name = "windows-core" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce" -dependencies = [ - "windows-implement 0.59.0", - "windows-interface", - "windows-result", - "windows-strings 0.3.1", - "windows-targets 0.53.0", + "windows-core", ] [[package]] @@ -6064,11 +6041,11 @@ version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" dependencies = [ - "windows-implement 0.60.0", + "windows-implement", "windows-interface", "windows-link", "windows-result", - "windows-strings 0.4.0", + "windows-strings", ] [[package]] @@ -6077,21 +6054,10 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32" dependencies = [ - "windows-core 0.61.0", + "windows-core", "windows-link", ] -[[package]] -name = "windows-implement" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "windows-implement" version = "0.60.0" @@ -6126,7 +6092,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ - "windows-core 0.61.0", + "windows-core", "windows-link", ] @@ -6139,15 +6105,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-strings" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" -dependencies = [ - "windows-link", -] - [[package]] name = "windows-strings" version = "0.4.0" diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 97eebffd1fe8e..d4c8ab80a3313 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -58,5 +58,5 @@ default-features = false features = ["read_core", "elf", "macho", "pe", "xcoff", "unaligned", "archive", "write", "wasm"] [target.'cfg(windows)'.dependencies.windows] -version = "0.59.0" +version = "0.61.0" features = ["Win32_Globalization"] diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index f48c73b13b961..f6a0201161851 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -38,7 +38,7 @@ features = ["nightly"] # for may_dangle version = "0.12" [target.'cfg(windows)'.dependencies.windows] -version = "0.59.0" +version = "0.61.0" features = [ "Win32_Foundation", "Win32_Storage_FileSystem", diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 9da4f2dbc2730..1971d06aad64d 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -60,7 +60,7 @@ libc = "0.2" # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] -version = "0.59.0" +version = "0.61.0" features = [ "Win32_System_Diagnostics_Debug", ] diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index b11793c190a14..82e7468211db0 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -33,7 +33,7 @@ tracing = "0.1" # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] -version = "0.59.0" +version = "0.61.0" features = [ "Win32_Foundation", "Win32_Security", diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index 63772a3222210..f0ee19e3c6774 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -33,7 +33,7 @@ libc = "0.2" # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] -version = "0.59.0" +version = "0.61.0" features = [ "Win32_Foundation", "Win32_System_LibraryLoader", diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 93f7b1cb7cf2c..3b544d8b82817 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -37,7 +37,7 @@ libc = "0.2" miow = "0.6" [target.'cfg(windows)'.dependencies.windows] -version = "0.59.0" +version = "0.61.0" features = [ "Win32_Foundation", "Win32_System_Diagnostics_Debug", diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 4195258af8854..9bb06c31c5c06 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -429,10 +429,13 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "winapi-util", "winapi-x86_64-pc-windows-gnu", "windows", + "windows-collections", "windows-core", + "windows-future", "windows-implement", "windows-interface", "windows-link", + "windows-numerics", "windows-result", "windows-strings", "windows-sys", From 667504b176c9e1ab380cef6eb9eaeba4813337c3 Mon Sep 17 00:00:00 2001 From: lcnr Date: Sat, 17 May 2025 10:51:59 +0000 Subject: [PATCH 2382/4206] check coroutines with TypingMode::Borrowck to avoid cyclic reasoning MIR borrowck taints its output if an obligation fails. This could then cause `check_coroutine_obligations` to silence its error, causing us to not emit and actual error and ICE. --- .../rustc_hir_analysis/src/check/check.rs | 20 +++++++---- .../delayed-obligations-emit.next.stderr | 15 +++++++++ .../ui/coroutine/delayed-obligations-emit.rs | 33 +++++++++++++++++++ 3 files changed, 61 insertions(+), 7 deletions(-) create mode 100644 tests/ui/coroutine/delayed-obligations-emit.next.stderr create mode 100644 tests/ui/coroutine/delayed-obligations-emit.rs diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index f92b2aea160a1..da94331aa26fb 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1754,17 +1754,19 @@ pub(super) fn check_coroutine_obligations( debug!(?typeck_results.coroutine_stalled_predicates); let mode = if tcx.next_trait_solver_globally() { - TypingMode::post_borrowck_analysis(tcx, def_id) + // This query is conceptually between HIR typeck and + // MIR borrowck. We use the opaque types defined by HIR + // and ignore region constraints. + TypingMode::borrowck(tcx, def_id) } else { TypingMode::analysis_in_body(tcx, def_id) }; - let infcx = tcx - .infer_ctxt() - // typeck writeback gives us predicates with their regions erased. - // As borrowck already has checked lifetimes, we do not need to do it again. - .ignoring_regions() - .build(mode); + // Typeck writeback gives us predicates with their regions erased. + // We only need to check the goals while ignoring lifetimes to give good + // error message and to avoid breaking the assumption of `mir_borrowck` + // that all obligations already hold modulo regions. + let infcx = tcx.infer_ctxt().ignoring_regions().build(mode); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); for (predicate, cause) in &typeck_results.coroutine_stalled_predicates { @@ -1785,6 +1787,10 @@ pub(super) fn check_coroutine_obligations( let key = infcx.resolve_vars_if_possible(key); sanity_check_found_hidden_type(tcx, key, hidden_type)?; } + } else { + // We're not checking region constraints here, so we can simply drop the + // added opaque type uses in `TypingMode::Borrowck`. + let _ = infcx.take_opaque_types(); } Ok(()) diff --git a/tests/ui/coroutine/delayed-obligations-emit.next.stderr b/tests/ui/coroutine/delayed-obligations-emit.next.stderr new file mode 100644 index 0000000000000..3a3663398c9a7 --- /dev/null +++ b/tests/ui/coroutine/delayed-obligations-emit.next.stderr @@ -0,0 +1,15 @@ +error[E0275]: overflow evaluating the requirement `{async block@$DIR/delayed-obligations-emit.rs:17:11: 17:16}: Send` + --> $DIR/delayed-obligations-emit.rs:17:5 + | +LL | spawn(async { build_dependencies().await }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: required by a bound in `spawn` + --> $DIR/delayed-obligations-emit.rs:31:13 + | +LL | fn spawn(_: F) {} + | ^^^^ required by this bound in `spawn` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/coroutine/delayed-obligations-emit.rs b/tests/ui/coroutine/delayed-obligations-emit.rs new file mode 100644 index 0000000000000..6334f29fcb22c --- /dev/null +++ b/tests/ui/coroutine/delayed-obligations-emit.rs @@ -0,0 +1,33 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ edition: 2024 +//@[current] check-pass + +// This previously caused an ICE with the new solver. +// The delayed coroutine obligations were checked with the +// opaque types inferred by borrowck. +// +// One of these delayed obligations failed with overflow in +// borrowck, causing us to taint `type_of` for the opaque. This +// then caused us to also not emit an error when checking the +// coroutine obligations. + +fn build_multiple<'a>() -> impl Sized { + spawn(async { build_dependencies().await }); + //[next]~^ ERROR overflow evaluating the requirement +} + +// Adding an explicit `Send` bound fixes it. +// Proving `build_dependencies(): Send` in `build_multiple` adds +// addiitional defining uses/placeholders. +fn build_dependencies() -> impl Future /* + Send */ { + async { + Box::pin(build_dependencies()).await; + async { build_multiple() }.await; + } +} + +fn spawn(_: F) {} + +fn main() {} From 40940e1294338080f88c87f0bde86e75ca603a27 Mon Sep 17 00:00:00 2001 From: klensy Date: Sat, 17 May 2025 15:31:02 +0300 Subject: [PATCH 2383/4206] bootstrap: bump windows too --- src/bootstrap/Cargo.lock | 71 +++++----------------------------- src/bootstrap/Cargo.toml | 2 +- src/bootstrap/src/bin/rustc.rs | 2 +- src/bootstrap/src/utils/job.rs | 1 - 4 files changed, 11 insertions(+), 65 deletions(-) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index ff63b8c62d3a0..d10d2d9bf8ce8 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -64,7 +64,7 @@ dependencies = [ "tracing-subscriber", "tracing-tree", "walkdir", - "windows 0.57.0", + "windows", "xz2", ] @@ -703,7 +703,7 @@ dependencies = [ "ntapi", "objc2-core-foundation", "objc2-io-kit", - "windows 0.61.1", + "windows", ] [[package]] @@ -916,16 +916,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" -dependencies = [ - "windows-core 0.57.0", - "windows-targets", -] - [[package]] name = "windows" version = "0.61.1" @@ -933,7 +923,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419" dependencies = [ "windows-collections", - "windows-core 0.61.0", + "windows-core", "windows-future", "windows-link", "windows-numerics", @@ -945,19 +935,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ - "windows-core 0.61.0", -] - -[[package]] -name = "windows-core" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" -dependencies = [ - "windows-implement 0.57.0", - "windows-interface 0.57.0", - "windows-result 0.1.2", - "windows-targets", + "windows-core", ] [[package]] @@ -966,10 +944,10 @@ version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" dependencies = [ - "windows-implement 0.60.0", - "windows-interface 0.59.1", + "windows-implement", + "windows-interface", "windows-link", - "windows-result 0.3.2", + "windows-result", "windows-strings", ] @@ -979,21 +957,10 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32" dependencies = [ - "windows-core 0.61.0", + "windows-core", "windows-link", ] -[[package]] -name = "windows-implement" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "windows-implement" version = "0.60.0" @@ -1005,17 +972,6 @@ dependencies = [ "syn", ] -[[package]] -name = "windows-interface" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "windows-interface" version = "0.59.1" @@ -1039,19 +995,10 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ - "windows-core 0.61.0", + "windows-core", "windows-link", ] -[[package]] -name = "windows-result" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" -dependencies = [ - "windows-targets", -] - [[package]] name = "windows-result" version = "0.3.2" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index e34de924cc18a..9652d18f1a6c5 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -70,7 +70,7 @@ tracing-tree = { version = "0.4.0", optional = true } version = "1.0.0" [target.'cfg(windows)'.dependencies.windows] -version = "0.57" +version = "0.61" features = [ "Win32_Foundation", "Win32_Security", diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs index 85c682a46c5d1..374884d8a9a07 100644 --- a/src/bootstrap/src/bin/rustc.rs +++ b/src/bootstrap/src/bin/rustc.rs @@ -342,7 +342,7 @@ fn format_rusage_data(child: Child) -> Option { use windows::Win32::System::Threading::GetProcessTimes; use windows::Win32::System::Time::FileTimeToSystemTime; - let handle = HANDLE(child.as_raw_handle() as isize); + let handle = HANDLE(child.as_raw_handle()); let mut user_filetime = Default::default(); let mut user_time = Default::default(); diff --git a/src/bootstrap/src/utils/job.rs b/src/bootstrap/src/utils/job.rs index 4949518de79b0..887deb41ca8bc 100644 --- a/src/bootstrap/src/utils/job.rs +++ b/src/bootstrap/src/utils/job.rs @@ -66,7 +66,6 @@ mod for_windows { // Enable the Windows Error Reporting dialog which msys disables, // so we can JIT debug rustc let mode = SetErrorMode(THREAD_ERROR_MODE::default()); - let mode = THREAD_ERROR_MODE(mode); SetErrorMode(mode & !SEM_NOGPFAULTERRORBOX); // Create a new job object for us to use From 9ffd0bf75a30b4fce1ffa35732666a37a7e9a736 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Sat, 17 May 2025 15:15:53 +0200 Subject: [PATCH 2384/4206] do away with `_Self` and `TraitName` and check generic params for rustc_on_unimplemented --- compiler/rustc_span/src/symbol.rs | 1 - compiler/rustc_trait_selection/messages.ftl | 2 + .../traits/on_unimplemented.rs | 14 +++- .../traits/on_unimplemented_condition.rs | 37 +++++---- .../traits/on_unimplemented_format.rs | 76 ++----------------- compiler/rustc_trait_selection/src/errors.rs | 7 ++ .../clippy/tests/ui/duplicated_attributes.rs | 2 +- ...options_of_the_internal_rustc_attribute.rs | 6 +- ...ons_of_the_internal_rustc_attribute.stderr | 63 +++++++++------ ...o_not_fail_parsing_on_invalid_options_1.rs | 6 +- ...t_fail_parsing_on_invalid_options_1.stderr | 48 +++++++----- tests/ui/on-unimplemented/bad-annotation.rs | 12 ++- .../ui/on-unimplemented/bad-annotation.stderr | 14 +++- tests/ui/on-unimplemented/on-trait.rs | 2 +- 14 files changed, 152 insertions(+), 138 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index efae6250b0720..bd0988b09d162 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -398,7 +398,6 @@ symbols! { Wrapping, Yield, _DECLS, - _Self, __D, __H, __S, diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index 00922c6038eee..9b949a0a79545 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -337,6 +337,8 @@ trait_selection_rustc_on_unimplemented_expected_one_predicate_in_not = expected .label = unexpected quantity of predicates here trait_selection_rustc_on_unimplemented_invalid_flag = invalid flag in `on`-clause .label = expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `{$invalid_flag}` +trait_selection_rustc_on_unimplemented_invalid_name = invalid name in `on`-clause + .label = expected one of `cause`, `from_desugaring`, `Self` or any generic parameter of the trait, not `{$invalid_name}` trait_selection_rustc_on_unimplemented_invalid_predicate = this predicate is invalid .label = expected one of `any`, `all` or `not` here, not `{$invalid_pred}` trait_selection_rustc_on_unimplemented_missing_value = this attribute must have a value 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 d5ee6e2123a19..37968386e9aeb 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 @@ -429,7 +429,19 @@ impl<'tcx> OnUnimplementedDirective { .next() .ok_or_else(|| tcx.dcx().emit_err(InvalidOnClause::Empty { span }))?; - match OnUnimplementedCondition::parse(cond) { + let generics: Vec = tcx + .generics_of(item_def_id) + .own_params + .iter() + .filter_map(|param| { + if matches!(param.kind, GenericParamDefKind::Lifetime) { + None + } else { + Some(param.name) + } + }) + .collect(); + match OnUnimplementedCondition::parse(cond, &generics) { Ok(condition) => Some(condition), Err(e) => return Err(tcx.dcx().emit_err(e)), } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs index 13753761f0923..e8ea9f2d23ebd 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs @@ -26,9 +26,12 @@ impl OnUnimplementedCondition { }) } - pub(crate) fn parse(input: &MetaItemInner) -> Result { + pub(crate) fn parse( + input: &MetaItemInner, + generics: &[Symbol], + ) -> Result { let span = input.span(); - let pred = Predicate::parse(input)?; + let pred = Predicate::parse(input, generics)?; Ok(OnUnimplementedCondition { span, pred }) } } @@ -52,7 +55,7 @@ enum Predicate { } impl Predicate { - fn parse(input: &MetaItemInner) -> Result { + fn parse(input: &MetaItemInner, generics: &[Symbol]) -> Result { let meta_item = match input { MetaItemInner::MetaItem(meta_item) => meta_item, MetaItemInner::Lit(lit) => { @@ -69,10 +72,10 @@ impl Predicate { match meta_item.kind { MetaItemKind::List(ref mis) => match predicate.name { - sym::any => Ok(Predicate::Any(Predicate::parse_sequence(mis)?)), - sym::all => Ok(Predicate::All(Predicate::parse_sequence(mis)?)), + sym::any => Ok(Predicate::Any(Predicate::parse_sequence(mis, generics)?)), + sym::all => Ok(Predicate::All(Predicate::parse_sequence(mis, generics)?)), sym::not => match &**mis { - [one] => Ok(Predicate::Not(Box::new(Predicate::parse(one)?))), + [one] => Ok(Predicate::Not(Box::new(Predicate::parse(one, generics)?))), [first, .., last] => Err(InvalidOnClause::ExpectedOnePredInNot { span: first.span().to(last.span()), }), @@ -83,7 +86,7 @@ impl Predicate { } }, MetaItemKind::NameValue(MetaItemLit { symbol, .. }) => { - let name = Name::parse(predicate); + let name = Name::parse(predicate, generics)?; let value = FilterFormatString::parse(symbol); let kv = NameValue { name, value }; Ok(Predicate::Match(kv)) @@ -95,8 +98,11 @@ impl Predicate { } } - fn parse_sequence(sequence: &[MetaItemInner]) -> Result, InvalidOnClause> { - sequence.iter().map(Predicate::parse).collect() + fn parse_sequence( + sequence: &[MetaItemInner], + generics: &[Symbol], + ) -> Result, InvalidOnClause> { + sequence.iter().map(|item| Predicate::parse(item, generics)).collect() } fn eval(&self, eval: &mut impl FnMut(FlagOrNv<'_>) -> bool) -> bool { @@ -156,14 +162,13 @@ enum Name { } impl Name { - fn parse(Ident { name, .. }: Ident) -> Self { + fn parse(Ident { name, span }: Ident, generics: &[Symbol]) -> Result { match name { - sym::_Self | kw::SelfUpper => Name::SelfUpper, - sym::from_desugaring => Name::FromDesugaring, - sym::cause => Name::Cause, - // FIXME(mejrs) Perhaps we should start checking that - // this actually is a valid generic parameter? - generic => Name::GenericArg(generic), + kw::SelfUpper => Ok(Name::SelfUpper), + sym::from_desugaring => Ok(Name::FromDesugaring), + sym::cause => Ok(Name::Cause), + generic if generics.contains(&generic) => Ok(Name::GenericArg(generic)), + invalid_name => Err(InvalidOnClause::InvalidName { invalid_name, span }), } } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs index ce170f820e12f..7c1dfc1728f04 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs @@ -2,8 +2,8 @@ use std::fmt; use std::ops::Range; use errors::*; -use rustc_middle::ty::TyCtxt; use rustc_middle::ty::print::TraitRefPrintSugared; +use rustc_middle::ty::{GenericParamDefKind, TyCtxt}; use rustc_parse_format::{ Alignment, Argument, Count, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece, Position, @@ -232,48 +232,16 @@ fn parse_arg<'tcx>( ) -> FormatArg { let (Ctx::RustcOnUnimplemented { tcx, trait_def_id } | Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id }) = ctx; - let trait_name = tcx.item_ident(*trait_def_id); - let generics = tcx.generics_of(trait_def_id); + let span = slice_span(input_span, arg.position_span.clone()); match arg.position { // Something like "hello {name}" Position::ArgumentNamed(name) => match (ctx, Symbol::intern(name)) { - // accepted, but deprecated - (Ctx::RustcOnUnimplemented { .. }, sym::_Self) => { - warnings - .push(FormatWarning::FutureIncompat { span, help: String::from("use {Self}") }); - FormatArg::SelfUpper - } - ( - Ctx::RustcOnUnimplemented { .. }, - sym::from_desugaring - | sym::crate_local - | sym::direct - | sym::cause - | sym::float - | sym::integer_ - | sym::integral, - ) => { - warnings.push(FormatWarning::FutureIncompat { - span, - help: String::from("don't use this in a format string"), - }); - FormatArg::AsIs(String::new()) - } - // Only `#[rustc_on_unimplemented]` can use these (Ctx::RustcOnUnimplemented { .. }, sym::ItemContext) => FormatArg::ItemContext, (Ctx::RustcOnUnimplemented { .. }, sym::This) => FormatArg::This, (Ctx::RustcOnUnimplemented { .. }, sym::Trait) => FormatArg::Trait, - // `{ThisTraitsName}`. Some attrs in std use this, but I'd like to change it to the more general `{This}` - // because that'll be simpler to parse and extend in the future - (Ctx::RustcOnUnimplemented { .. }, name) if name == trait_name.name => { - warnings - .push(FormatWarning::FutureIncompat { span, help: String::from("use {This}") }); - FormatArg::This - } - // Any attribute can use these ( Ctx::RustcOnUnimplemented { .. } | Ctx::DiagnosticOnUnimplemented { .. }, @@ -282,7 +250,10 @@ fn parse_arg<'tcx>( ( Ctx::RustcOnUnimplemented { .. } | Ctx::DiagnosticOnUnimplemented { .. }, generic_param, - ) if generics.own_params.iter().any(|param| param.name == generic_param) => { + ) if tcx.generics_of(trait_def_id).own_params.iter().any(|param| { + !matches!(param.kind, GenericParamDefKind::Lifetime) && param.name == generic_param + }) => + { FormatArg::GenericParam { generic_param } } @@ -375,39 +346,4 @@ pub mod errors { #[diag(trait_selection_missing_options_for_on_unimplemented_attr)] #[help] pub struct MissingOptionsForOnUnimplementedAttr; - - #[derive(LintDiagnostic)] - #[diag(trait_selection_ignored_diagnostic_option)] - pub struct IgnoredDiagnosticOption { - pub option_name: &'static str, - #[label] - pub span: Span, - #[label(trait_selection_other_label)] - pub prev_span: Span, - } - - impl IgnoredDiagnosticOption { - pub fn maybe_emit_warning<'tcx>( - tcx: TyCtxt<'tcx>, - item_def_id: DefId, - new: Option, - old: Option, - option_name: &'static str, - ) { - if let (Some(new_item), Some(old_item)) = (new, old) { - if let Some(item_def_id) = item_def_id.as_local() { - tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.local_def_id_to_hir_id(item_def_id), - new_item, - IgnoredDiagnosticOption { - span: new_item, - prev_span: old_item, - option_name, - }, - ); - } - } - } - } } diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 8ab4d795c4597..779c861637a4e 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -72,6 +72,13 @@ pub enum InvalidOnClause { span: Span, invalid_flag: Symbol, }, + #[diag(trait_selection_rustc_on_unimplemented_invalid_name, code = E0232)] + InvalidName { + #[primary_span] + #[label] + span: Span, + invalid_name: Symbol, + }, } #[derive(Diagnostic)] diff --git a/src/tools/clippy/tests/ui/duplicated_attributes.rs b/src/tools/clippy/tests/ui/duplicated_attributes.rs index 874f5d22075c1..3ca91d6f1829c 100644 --- a/src/tools/clippy/tests/ui/duplicated_attributes.rs +++ b/src/tools/clippy/tests/ui/duplicated_attributes.rs @@ -21,7 +21,7 @@ fn foo() {} fn bar() {} // No warning: -#[rustc_on_unimplemented(on(_Self = "&str", label = "`a"), on(_Self = "alloc::string::String", label = "a"))] +#[rustc_on_unimplemented(on(Self = "&str", label = "`a"), on(Self = "alloc::string::String", label = "a"))] trait Abc {} #[proc_macro_attr::duplicated_attr()] // Should not warn! diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs index b76b550fcb246..a0e497fa045b3 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs @@ -3,7 +3,7 @@ //@ reference: attributes.diagnostic.on_unimplemented.syntax //@ reference: attributes.diagnostic.on_unimplemented.invalid-formats #[diagnostic::on_unimplemented( - on(_Self = "&str"), + on(Self = "&str"), //~^WARN malformed `on_unimplemented` attribute //~|WARN malformed `on_unimplemented` attribute message = "trait has `{Self}` and `{T}` as params", @@ -41,7 +41,7 @@ impl Bar for i32 {} //~|WARN there is no parameter `integral` on trait `Baz` //~|WARN there is no parameter `integer` on trait `Baz` //~|WARN there is no parameter `integer` on trait `Baz` - label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" + label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" //~^WARN there is no parameter `float` on trait `Baz` //~|WARN there is no parameter `float` on trait `Baz` //~|WARN there is no parameter `_Self` on trait `Baz` @@ -52,6 +52,8 @@ impl Bar for i32 {} //~|WARN there is no parameter `Trait` on trait `Baz` //~|WARN there is no parameter `ItemContext` on trait `Baz` //~|WARN there is no parameter `ItemContext` on trait `Baz` + //~|WARN there is no parameter `This` on trait `Baz` + //~|WARN there is no parameter `This` on trait `Baz` )] trait Baz {} diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr index 88816a98dcf00..8dace7d905225 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr @@ -9,8 +9,8 @@ LL | #[diagnostic::on_unimplemented(message = "Not allowed to apply it on a impl warning: malformed `on_unimplemented` attribute --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:6:5 | -LL | on(_Self = "&str"), - | ^^^^^^^^^^^^^^^^^^ invalid option found here +LL | on(Self = "&str"), + | ^^^^^^^^^^^^^^^^^ invalid option found here | = help: only `message`, `note` and `label` are allowed as options @@ -81,7 +81,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", warning: there is no parameter `float` on trait `Baz` --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:15 | -LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" +LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" | ^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument @@ -89,7 +89,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" warning: there is no parameter `_Self` on trait `Baz` --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:22 | -LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" +LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" | ^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument @@ -97,7 +97,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" warning: there is no parameter `crate_local` on trait `Baz` --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:29 | -LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" +LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" | ^^^^^^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument @@ -105,7 +105,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" warning: there is no parameter `Trait` on trait `Baz` --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:42 | -LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" +LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" | ^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument @@ -113,16 +113,24 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" warning: there is no parameter `ItemContext` on trait `Baz` --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:49 | -LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" +LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" | ^^^^^^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument +warning: there is no parameter `This` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:62 + | +LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" + | ^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + warning: malformed `on_unimplemented` attribute --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:6:5 | -LL | on(_Self = "&str"), - | ^^^^^^^^^^^^^^^^^^ invalid option found here +LL | on(Self = "&str"), + | ^^^^^^^^^^^^^^^^^ invalid option found here | = help: only `message`, `note` and `label` are allowed as options = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` @@ -146,7 +154,7 @@ LL | append_const_msg = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: trait has `()` and `i32` as params - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:63:15 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:65:15 | LL | takes_foo(()); | --------- ^^ trait has `()` and `i32` as params @@ -161,7 +169,7 @@ help: this trait has no implementations, consider adding one LL | trait Foo {} | ^^^^^^^^^^^^ note: required by a bound in `takes_foo` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:58:22 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:60:22 | LL | fn takes_foo(_: impl Foo) {} | ^^^^^^^^ required by this bound in `takes_foo` @@ -176,7 +184,7 @@ LL | #[diagnostic::on_unimplemented = "Message"] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `(): Bar` is not satisfied - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:65:15 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:67:15 | LL | takes_bar(()); | --------- ^^ the trait `Bar` is not implemented for `()` @@ -185,7 +193,7 @@ LL | takes_bar(()); | = help: the trait `Bar` is implemented for `i32` note: required by a bound in `takes_bar` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:59:22 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:61:22 | LL | fn takes_bar(_: impl Bar) {} | ^^^ required by this bound in `takes_bar` @@ -238,7 +246,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", warning: there is no parameter `float` on trait `Baz` --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:15 | -LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" +LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" | ^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument @@ -247,7 +255,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" warning: there is no parameter `_Self` on trait `Baz` --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:22 | -LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" +LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" | ^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument @@ -256,7 +264,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" warning: there is no parameter `crate_local` on trait `Baz` --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:29 | -LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" +LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" | ^^^^^^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument @@ -265,7 +273,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" warning: there is no parameter `Trait` on trait `Baz` --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:42 | -LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" +LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" | ^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument @@ -274,32 +282,41 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" warning: there is no parameter `ItemContext` on trait `Baz` --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:49 | -LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" +LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" | ^^^^^^^^^^^ | = help: expect either a generic argument name or `{Self}` as format argument = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +warning: there is no parameter `This` on trait `Baz` + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:62 + | +LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}" + | ^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error[E0277]: {from_desugaring}{direct}{cause}{integral}{integer} - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:67:15 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:69:15 | LL | takes_baz(()); - | --------- ^^ {float}{_Self}{crate_local}{Trait}{ItemContext} + | --------- ^^ {float}{_Self}{crate_local}{Trait}{ItemContext}{This} | | | required by a bound introduced by this call | = help: the trait `Baz` is not implemented for `()` help: this trait has no implementations, consider adding one - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:56:1 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:58:1 | LL | trait Baz {} | ^^^^^^^^^ note: required by a bound in `takes_baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:60:22 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:62:22 | LL | fn takes_baz(_: impl Baz) {} | ^^^ required by this bound in `takes_baz` -error: aborting due to 3 previous errors; 29 warnings emitted +error: aborting due to 3 previous errors; 31 warnings emitted For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs index 8328c10d2a077..08eb5707e909e 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs @@ -14,11 +14,15 @@ struct Bar {} //~|WARN malformed `on_unimplemented` attribute trait Baz {} -#[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))] +#[diagnostic::on_unimplemented(message = "Boom", on(Self = "i32", message = "whatever"))] //~^WARN malformed `on_unimplemented` attribute //~|WARN malformed `on_unimplemented` attribute trait Boom {} +#[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))] +//~^WARN malformed `on_unimplemented` attribute +trait _Self {} + #[diagnostic::on_unimplemented = "boom"] //~^WARN malformed `on_unimplemented` attribute trait Doom {} diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr index 4dd8c1afca020..80790dc3f792c 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr @@ -25,13 +25,21 @@ LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")] warning: malformed `on_unimplemented` attribute --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50 | +LL | #[diagnostic::on_unimplemented(message = "Boom", on(Self = "i32", message = "whatever"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here + | + = help: only `message`, `note` and `label` are allowed as options + +warning: malformed `on_unimplemented` attribute + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:22:50 + | LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here | = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:22:32 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:32 | LL | #[diagnostic::on_unimplemented = "boom"] | ^^^^^^^^ invalid option found here @@ -39,7 +47,7 @@ LL | #[diagnostic::on_unimplemented = "boom"] = help: only `message`, `note` and `label` are allowed as options warning: missing options for `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:30:1 | LL | #[diagnostic::on_unimplemented] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -47,7 +55,7 @@ LL | #[diagnostic::on_unimplemented] = help: at least one of the `message`, `note` and `label` options are expected warning: there is no parameter `DoesNotExist` on trait `Test` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:44 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:35:44 | LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")] | ^^^^^^^^^^^^ @@ -64,7 +72,7 @@ LL | #[diagnostic::on_unimplemented(unsupported = "foo")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `i32: Foo` is not satisfied - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:43:14 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:47:14 | LL | take_foo(1_i32); | -------- ^^^^^ the trait `Foo` is not implemented for `i32` @@ -77,7 +85,7 @@ help: this trait has no implementations, consider adding one LL | trait Foo {} | ^^^^^^^^^ note: required by a bound in `take_foo` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:36:21 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:40:21 | LL | fn take_foo(_: impl Foo) {} | ^^^ required by this bound in `take_foo` @@ -92,7 +100,7 @@ LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Boom - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:45:14 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:49:14 | LL | take_baz(1_i32); | -------- ^^^^^ the trait `Baz` is not implemented for `i32` @@ -105,7 +113,7 @@ help: this trait has no implementations, consider adding one LL | trait Baz {} | ^^^^^^^^^ note: required by a bound in `take_baz` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:37:21 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:41:21 | LL | fn take_baz(_: impl Baz) {} | ^^^ required by this bound in `take_baz` @@ -113,14 +121,14 @@ LL | fn take_baz(_: impl Baz) {} warning: malformed `on_unimplemented` attribute --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50 | -LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here +LL | #[diagnostic::on_unimplemented(message = "Boom", on(Self = "i32", message = "whatever"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here | = help: only `message`, `note` and `label` are allowed as options = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Boom - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:47:15 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:51:15 | LL | take_boom(1_i32); | --------- ^^^^^ the trait `Boom` is not implemented for `i32` @@ -133,13 +141,13 @@ help: this trait has no implementations, consider adding one LL | trait Boom {} | ^^^^^^^^^^ note: required by a bound in `take_boom` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:38:22 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:42:22 | LL | fn take_boom(_: impl Boom) {} | ^^^^ required by this bound in `take_boom` warning: missing options for `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:30:1 | LL | #[diagnostic::on_unimplemented] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -148,7 +156,7 @@ LL | #[diagnostic::on_unimplemented] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `i32: Whatever` is not satisfied - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:49:19 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:53:19 | LL | take_whatever(1_i32); | ------------- ^^^^^ the trait `Whatever` is not implemented for `i32` @@ -156,18 +164,18 @@ LL | take_whatever(1_i32); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:29:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:33:1 | LL | trait Whatever {} | ^^^^^^^^^^^^^^ note: required by a bound in `take_whatever` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:39:26 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:43:26 | LL | fn take_whatever(_: impl Whatever) {} | ^^^^^^^^ required by this bound in `take_whatever` warning: there is no parameter `DoesNotExist` on trait `Test` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:44 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:35:44 | LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")] | ^^^^^^^^^^^^ @@ -176,7 +184,7 @@ LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: {DoesNotExist} - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:51:15 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:55:15 | LL | take_test(()); | --------- ^^ the trait `Test` is not implemented for `()` @@ -184,16 +192,16 @@ LL | take_test(()); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:34:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:38:1 | LL | trait Test {} | ^^^^^^^^^^ note: required by a bound in `take_test` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:40:22 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:44:22 | LL | fn take_test(_: impl Test) {} | ^^^^ required by this bound in `take_test` -error: aborting due to 5 previous errors; 12 warnings emitted +error: aborting due to 5 previous errors; 13 warnings emitted For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/on-unimplemented/bad-annotation.rs b/tests/ui/on-unimplemented/bad-annotation.rs index 25de597811027..937e5b82da50c 100644 --- a/tests/ui/on-unimplemented/bad-annotation.rs +++ b/tests/ui/on-unimplemented/bad-annotation.rs @@ -59,7 +59,7 @@ trait EmptyOn {} //~^^^ NOTE expected value here trait ExpectedPredicateInOn {} -#[rustc_on_unimplemented(on(x = "y"), message = "y")] +#[rustc_on_unimplemented(on(Self = "y"), message = "y")] trait OnWithoutDirectives {} #[rustc_on_unimplemented(on(from_desugaring, on(from_desugaring, message = "x")), message = "y")] @@ -107,3 +107,13 @@ trait InvalidPredicate {} //~^ ERROR invalid flag in `on`-clause //~^^ NOTE expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `something` trait InvalidFlag {} + +#[rustc_on_unimplemented(on(_Self = "y", message = "y"))] +//~^ ERROR invalid name in `on`-clause +//~^^ NOTE expected one of `cause`, `from_desugaring`, `Self` or any generic parameter of the trait, not `_Self` +trait InvalidName {} + +#[rustc_on_unimplemented(on(abc = "y", message = "y"))] +//~^ ERROR invalid name in `on`-clause +//~^^ NOTE expected one of `cause`, `from_desugaring`, `Self` or any generic parameter of the trait, not `abc` +trait InvalidName2 {} diff --git a/tests/ui/on-unimplemented/bad-annotation.stderr b/tests/ui/on-unimplemented/bad-annotation.stderr index 35b919c7b7853..3fc5453277404 100644 --- a/tests/ui/on-unimplemented/bad-annotation.stderr +++ b/tests/ui/on-unimplemented/bad-annotation.stderr @@ -125,7 +125,19 @@ error[E0232]: invalid flag in `on`-clause LL | #[rustc_on_unimplemented(on(something, message = "y"))] | ^^^^^^^^^ expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `something` -error: aborting due to 18 previous errors +error[E0232]: invalid name in `on`-clause + --> $DIR/bad-annotation.rs:111:29 + | +LL | #[rustc_on_unimplemented(on(_Self = "y", message = "y"))] + | ^^^^^ expected one of `cause`, `from_desugaring`, `Self` or any generic parameter of the trait, not `_Self` + +error[E0232]: invalid name in `on`-clause + --> $DIR/bad-annotation.rs:116:29 + | +LL | #[rustc_on_unimplemented(on(abc = "y", message = "y"))] + | ^^^ expected one of `cause`, `from_desugaring`, `Self` or any generic parameter of the trait, not `abc` + +error: aborting due to 20 previous errors Some errors have detailed explanations: E0230, E0231, E0232. For more information about an error, try `rustc --explain E0230`. diff --git a/tests/ui/on-unimplemented/on-trait.rs b/tests/ui/on-unimplemented/on-trait.rs index 556813cd4795f..91630af17e92a 100644 --- a/tests/ui/on-unimplemented/on-trait.rs +++ b/tests/ui/on-unimplemented/on-trait.rs @@ -3,7 +3,7 @@ #![feature(rustc_attrs)] pub mod Bar { - #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}` `{Baz}` `{Quux}` in `{Foo}`"] + #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}` `{Baz}` `{Quux}` in `{This}`"] pub trait Foo {} } From f3bad7f4ddf9bf0166037b333b0bf830aa641273 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Sat, 17 May 2025 15:15:53 +0200 Subject: [PATCH 2385/4206] do away with `_Self` and `TraitName` and check generic params for rustc_on_unimplemented --- tests/ui/duplicated_attributes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/duplicated_attributes.rs b/tests/ui/duplicated_attributes.rs index 874f5d22075c1..3ca91d6f1829c 100644 --- a/tests/ui/duplicated_attributes.rs +++ b/tests/ui/duplicated_attributes.rs @@ -21,7 +21,7 @@ fn foo() {} fn bar() {} // No warning: -#[rustc_on_unimplemented(on(_Self = "&str", label = "`a"), on(_Self = "alloc::string::String", label = "a"))] +#[rustc_on_unimplemented(on(Self = "&str", label = "`a"), on(Self = "alloc::string::String", label = "a"))] trait Abc {} #[proc_macro_attr::duplicated_attr()] // Should not warn! From a4765c9fc2f0285e20f0ff155156ddd760fa8fff Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Sat, 17 May 2025 13:05:05 +0000 Subject: [PATCH 2386/4206] Make some `match`es slightly more ergonomic in `librustdoc` --- src/librustdoc/clean/cfg.rs | 64 +++++++++++------------ src/librustdoc/clean/mod.rs | 22 ++++---- src/librustdoc/clean/types.rs | 20 +++---- src/librustdoc/formats/item_type.rs | 33 +++++------- src/librustdoc/html/format.rs | 81 +++++++++++++---------------- 5 files changed, 99 insertions(+), 121 deletions(-) diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 1541e7201cefd..439777843fb06 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -144,7 +144,7 @@ impl Cfg { /// Whether the configuration consists of just `Cfg` or `Not`. fn is_simple(&self) -> bool { - match *self { + match self { Cfg::False | Cfg::True | Cfg::Cfg(..) | Cfg::Not(..) => true, Cfg::All(..) | Cfg::Any(..) => false, } @@ -152,7 +152,7 @@ impl Cfg { /// Whether the configuration consists of just `Cfg`, `Not` or `All`. fn is_all(&self) -> bool { - match *self { + match self { Cfg::False | Cfg::True | Cfg::Cfg(..) | Cfg::Not(..) | Cfg::All(..) => true, Cfg::Any(..) => false, } @@ -204,7 +204,7 @@ impl Cfg { } fn should_append_only_to_description(&self) -> bool { - match *self { + match self { Cfg::False | Cfg::True => false, Cfg::Any(..) | Cfg::All(..) | Cfg::Cfg(..) => true, Cfg::Not(box Cfg::Cfg(..)) => true, @@ -261,17 +261,17 @@ impl ops::Not for Cfg { impl ops::BitAndAssign for Cfg { fn bitand_assign(&mut self, other: Cfg) { match (self, other) { - (&mut Cfg::False, _) | (_, Cfg::True) => {} + (Cfg::False, _) | (_, Cfg::True) => {} (s, Cfg::False) => *s = Cfg::False, - (s @ &mut Cfg::True, b) => *s = b, - (&mut Cfg::All(ref mut a), Cfg::All(ref mut b)) => { + (s @ Cfg::True, b) => *s = b, + (Cfg::All(a), Cfg::All(ref mut b)) => { for c in b.drain(..) { if !a.contains(&c) { a.push(c); } } } - (&mut Cfg::All(ref mut a), ref mut b) => { + (Cfg::All(a), ref mut b) => { if !a.contains(b) { a.push(mem::replace(b, Cfg::True)); } @@ -305,15 +305,15 @@ impl ops::BitOrAssign for Cfg { fn bitor_assign(&mut self, other: Cfg) { match (self, other) { (Cfg::True, _) | (_, Cfg::False) | (_, Cfg::True) => {} - (s @ &mut Cfg::False, b) => *s = b, - (&mut Cfg::Any(ref mut a), Cfg::Any(ref mut b)) => { + (s @ Cfg::False, b) => *s = b, + (Cfg::Any(a), Cfg::Any(ref mut b)) => { for c in b.drain(..) { if !a.contains(&c) { a.push(c); } } } - (&mut Cfg::Any(ref mut a), ref mut b) => { + (Cfg::Any(a), ref mut b) => { if !a.contains(b) { a.push(mem::replace(b, Cfg::True)); } @@ -440,40 +440,34 @@ impl Display<'_> { impl fmt::Display for Display<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self.0 { - Cfg::Not(ref child) => match **child { - Cfg::Any(ref sub_cfgs) => { - let separator = - if sub_cfgs.iter().all(Cfg::is_simple) { " nor " } else { ", nor " }; - fmt.write_str("neither ")?; - - sub_cfgs - .iter() - .map(|sub_cfg| { - fmt::from_fn(|fmt| { - write_with_opt_paren( - fmt, - !sub_cfg.is_all(), - Display(sub_cfg, self.1), - ) - }) + match self.0 { + Cfg::Not(box Cfg::Any(sub_cfgs)) => { + let separator = + if sub_cfgs.iter().all(Cfg::is_simple) { " nor " } else { ", nor " }; + fmt.write_str("neither ")?; + + sub_cfgs + .iter() + .map(|sub_cfg| { + fmt::from_fn(|fmt| { + write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1)) }) - .joined(separator, fmt) - } - ref simple @ Cfg::Cfg(..) => write!(fmt, "non-{}", Display(simple, self.1)), - ref c => write!(fmt, "not ({})", Display(c, self.1)), - }, + }) + .joined(separator, fmt) + } + Cfg::Not(box simple @ Cfg::Cfg(..)) => write!(fmt, "non-{}", Display(simple, self.1)), + Cfg::Not(box c) => write!(fmt, "not ({})", Display(c, self.1)), - Cfg::Any(ref sub_cfgs) => { + Cfg::Any(sub_cfgs) => { let separator = if sub_cfgs.iter().all(Cfg::is_simple) { " or " } else { ", or " }; self.display_sub_cfgs(fmt, sub_cfgs, separator) } - Cfg::All(ref sub_cfgs) => self.display_sub_cfgs(fmt, sub_cfgs, " and "), + Cfg::All(sub_cfgs) => self.display_sub_cfgs(fmt, sub_cfgs, " and "), Cfg::True => fmt.write_str("everywhere"), Cfg::False => fmt.write_str("nowhere"), - Cfg::Cfg(name, value) => { + &Cfg::Cfg(name, value) => { let human_readable = match (name, value) { (sym::unix, None) => "Unix", (sym::windows, None) => "Windows", diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 622a410837b54..28dfa01534ead 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -224,9 +224,9 @@ fn clean_generic_bound<'tcx>( bound: &hir::GenericBound<'tcx>, cx: &mut DocContext<'tcx>, ) -> Option { - Some(match *bound { + Some(match bound { hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)), - hir::GenericBound::Trait(ref t) => { + hir::GenericBound::Trait(t) => { // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op. if let hir::BoundConstness::Maybe(_) = t.modifiers.constness && cx.tcx.lang_items().destruct_trait() == Some(t.trait_ref.trait_def_id().unwrap()) @@ -352,8 +352,8 @@ fn clean_where_predicate<'tcx>( if !predicate.kind.in_where_clause() { return None; } - Some(match *predicate.kind { - hir::WherePredicateKind::BoundPredicate(ref wbp) => { + Some(match predicate.kind { + hir::WherePredicateKind::BoundPredicate(wbp) => { let bound_params = wbp .bound_generic_params .iter() @@ -366,12 +366,12 @@ fn clean_where_predicate<'tcx>( } } - hir::WherePredicateKind::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate { + hir::WherePredicateKind::RegionPredicate(wrp) => WherePredicate::RegionPredicate { lifetime: clean_lifetime(wrp.lifetime, cx), bounds: wrp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), }, - hir::WherePredicateKind::EqPredicate(ref wrp) => WherePredicate::EqPredicate { + hir::WherePredicateKind::EqPredicate(wrp) => WherePredicate::EqPredicate { lhs: clean_ty(wrp.lhs_ty, cx), rhs: clean_ty(wrp.rhs_ty, cx).into(), }, @@ -2112,7 +2112,7 @@ pub(crate) fn clean_middle_ty<'tcx>( ); Type::Path { path } } - ty::Dynamic(obj, ref reg, _) => { + ty::Dynamic(obj, reg, _) => { // HACK: pick the first `did` as the `did` of the trait object. Someone // might want to implement "native" support for marker-trait-only // trait objects. @@ -2129,7 +2129,7 @@ pub(crate) fn clean_middle_ty<'tcx>( inline::record_extern_fqn(cx, did, ItemType::Trait); - let lifetime = clean_trait_object_lifetime_bound(*reg, container, obj, cx.tcx); + let lifetime = clean_trait_object_lifetime_bound(reg, container, obj, cx.tcx); let mut bounds = dids .map(|did| { @@ -2846,7 +2846,7 @@ fn clean_maybe_renamed_item<'tcx>( )); return ret; } - ItemKind::Enum(_, ref def, generics) => EnumItem(Enum { + ItemKind::Enum(_, def, generics) => EnumItem(Enum { variants: def.variants.iter().map(|v| clean_variant(v, cx)).collect(), generics: clean_generics(generics, cx), }), @@ -2854,11 +2854,11 @@ fn clean_maybe_renamed_item<'tcx>( generics: clean_generics(generics, cx), bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), }), - ItemKind::Union(_, ref variant_data, generics) => UnionItem(Union { + ItemKind::Union(_, variant_data, generics) => UnionItem(Union { generics: clean_generics(generics, cx), fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(), }), - ItemKind::Struct(_, ref variant_data, generics) => StructItem(Struct { + ItemKind::Struct(_, variant_data, generics) => StructItem(Struct { ctor_kind: variant_data.ctor_kind(), generics: clean_generics(generics, cx), fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(), diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 15890fff0c336..75f1bc9549cbe 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1337,9 +1337,9 @@ pub(crate) enum WherePredicate { impl WherePredicate { pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> { - match *self { - WherePredicate::BoundPredicate { ref bounds, .. } => Some(bounds), - WherePredicate::RegionPredicate { ref bounds, .. } => Some(bounds), + match self { + WherePredicate::BoundPredicate { bounds, .. } => Some(bounds), + WherePredicate::RegionPredicate { bounds, .. } => Some(bounds), _ => None, } } @@ -1709,13 +1709,13 @@ impl Type { /// /// [clean]: crate::clean pub(crate) fn def_id(&self, cache: &Cache) -> Option { - let t: PrimitiveType = match *self { - Type::Path { ref path } => return Some(path.def_id()), - DynTrait(ref bounds, _) => return bounds.first().map(|b| b.trait_.def_id()), - Primitive(p) => return cache.primitive_locations.get(&p).cloned(), + let t: PrimitiveType = match self { + Type::Path { path } => return Some(path.def_id()), + DynTrait(bounds, _) => return bounds.first().map(|b| b.trait_.def_id()), + Primitive(p) => return cache.primitive_locations.get(p).cloned(), BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference, - BorrowedRef { ref type_, .. } => return type_.def_id(cache), - Tuple(ref tys) => { + BorrowedRef { type_, .. } => return type_.def_id(cache), + Tuple(tys) => { if tys.is_empty() { PrimitiveType::Unit } else { @@ -1727,7 +1727,7 @@ impl Type { Array(..) => PrimitiveType::Array, Type::Pat(..) => PrimitiveType::Pat, RawPointer(..) => PrimitiveType::RawPointer, - QPath(box QPathData { ref self_type, .. }) => return self_type.def_id(cache), + QPath(box QPathData { self_type, .. }) => return self_type.def_id(cache), Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None, }; Primitive(t).def_id(cache) diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs index de6537e992f19..3aba7a370adb2 100644 --- a/src/librustdoc/formats/item_type.rs +++ b/src/librustdoc/formats/item_type.rs @@ -70,12 +70,12 @@ impl Serialize for ItemType { impl<'a> From<&'a clean::Item> for ItemType { fn from(item: &'a clean::Item) -> ItemType { - let kind = match item.kind { - clean::StrippedItem(box ref item) => item, - ref kind => kind, + let kind = match &item.kind { + clean::StrippedItem(box item) => item, + kind => kind, }; - match *kind { + match kind { clean::ModuleItem(..) => ItemType::Module, clean::ExternCrateItem { .. } => ItemType::ExternCrate, clean::ImportItem(..) => ItemType::Import, @@ -103,7 +103,7 @@ impl<'a> From<&'a clean::Item> for ItemType { clean::ForeignTypeItem => ItemType::ForeignType, clean::KeywordItem => ItemType::Keyword, clean::TraitAliasItem(..) => ItemType::TraitAlias, - clean::ProcMacroItem(ref mac) => match mac.kind { + clean::ProcMacroItem(mac) => match mac.kind { MacroKind::Bang => ItemType::Macro, MacroKind::Attr => ItemType::ProcAttribute, MacroKind::Derive => ItemType::ProcDerive, @@ -134,22 +134,15 @@ impl ItemType { DefKind::Trait => Self::Trait, DefKind::TyAlias => Self::TypeAlias, DefKind::TraitAlias => Self::TraitAlias, - DefKind::Macro(kind) => match kind { - MacroKind::Bang => ItemType::Macro, - MacroKind::Attr => ItemType::ProcAttribute, - MacroKind::Derive => ItemType::ProcDerive, - }, + DefKind::Macro(MacroKind::Bang) => ItemType::Macro, + DefKind::Macro(MacroKind::Attr) => ItemType::ProcAttribute, + DefKind::Macro(MacroKind::Derive) => ItemType::ProcDerive, DefKind::ForeignTy => Self::ForeignType, DefKind::Variant => Self::Variant, DefKind::Field => Self::StructField, DefKind::AssocTy => Self::AssocType, - DefKind::AssocFn => { - if let Some(DefKind::Trait) = parent_kind { - Self::TyMethod - } else { - Self::Method - } - } + DefKind::AssocFn if let Some(DefKind::Trait) = parent_kind => Self::TyMethod, + DefKind::AssocFn => Self::Method, DefKind::Ctor(CtorOf::Struct, _) => Self::Struct, DefKind::Ctor(CtorOf::Variant, _) => Self::Variant, DefKind::AssocConst => Self::AssocConst, @@ -170,7 +163,7 @@ impl ItemType { } pub(crate) fn as_str(&self) -> &'static str { - match *self { + match self { ItemType::Module => "mod", ItemType::ExternCrate => "externcrate", ItemType::Import => "import", @@ -199,10 +192,10 @@ impl ItemType { } } pub(crate) fn is_method(&self) -> bool { - matches!(*self, ItemType::Method | ItemType::TyMethod) + matches!(self, ItemType::Method | ItemType::TyMethod) } pub(crate) fn is_adt(&self) -> bool { - matches!(*self, ItemType::Struct | ItemType::Union | ItemType::Enum) + matches!(self, ItemType::Struct | ItemType::Union | ItemType::Enum) } } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 299fd6b9adbb0..8c7ab640bed3f 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -856,15 +856,15 @@ fn fmt_type( ) -> fmt::Result { trace!("fmt_type(t = {t:?})"); - match *t { + match t { clean::Generic(name) => f.write_str(name.as_str()), clean::SelfTy => f.write_str("Self"), - clean::Type::Path { ref path } => { + clean::Type::Path { path } => { // Paths like `T::Output` and `Self::Output` should be rendered with all segments. let did = path.def_id(); resolved_path(f, did, path, path.is_assoc_ty(), use_absolute, cx) } - clean::DynTrait(ref bounds, ref lt) => { + clean::DynTrait(bounds, lt) => { f.write_str("dyn ")?; tybounds(bounds, lt, cx).fmt(f) } @@ -872,8 +872,8 @@ fn fmt_type( clean::Primitive(clean::PrimitiveType::Never) => { primitive_link(f, PrimitiveType::Never, format_args!("!"), cx) } - clean::Primitive(prim) => primitive_link(f, prim, format_args!("{}", prim.as_sym()), cx), - clean::BareFunction(ref decl) => { + &clean::Primitive(prim) => primitive_link(f, prim, format_args!("{}", prim.as_sym()), cx), + clean::BareFunction(decl) => { print_higher_ranked_params_with_space(&decl.generic_params, cx, "for").fmt(f)?; decl.safety.print_with_space().fmt(f)?; print_abi_with_space(decl.abi).fmt(f)?; @@ -884,11 +884,11 @@ fn fmt_type( } decl.decl.print(cx).fmt(f) } - clean::UnsafeBinder(ref binder) => { + clean::UnsafeBinder(binder) => { print_higher_ranked_params_with_space(&binder.generic_params, cx, "unsafe").fmt(f)?; binder.ty.print(cx).fmt(f) } - clean::Tuple(ref typs) => match &typs[..] { + clean::Tuple(typs) => match &typs[..] { &[] => primitive_link(f, PrimitiveType::Unit, format_args!("()"), cx), [one] => { if let clean::Generic(name) = one { @@ -925,45 +925,36 @@ fn fmt_type( } } }, - clean::Slice(ref t) => match **t { - clean::Generic(name) => { - primitive_link(f, PrimitiveType::Slice, format_args!("[{name}]"), cx) - } - _ => { - write!(f, "[")?; - t.print(cx).fmt(f)?; - write!(f, "]") - } - }, - clean::Type::Pat(ref t, ref pat) => { + clean::Slice(box clean::Generic(name)) => { + primitive_link(f, PrimitiveType::Slice, format_args!("[{name}]"), cx) + } + clean::Slice(t) => { + write!(f, "[")?; + t.print(cx).fmt(f)?; + write!(f, "]") + } + clean::Type::Pat(t, pat) => { fmt::Display::fmt(&t.print(cx), f)?; write!(f, " is {pat}") } - clean::Array(ref t, ref n) => match **t { - clean::Generic(name) if !f.alternate() => primitive_link( - f, - PrimitiveType::Array, - format_args!("[{name}; {n}]", n = Escape(n)), - cx, - ), - _ => { - write!(f, "[")?; - t.print(cx).fmt(f)?; - if f.alternate() { - write!(f, "; {n}")?; - } else { - write!(f, "; ")?; - primitive_link( - f, - PrimitiveType::Array, - format_args!("{n}", n = Escape(n)), - cx, - )?; - } - write!(f, "]") + clean::Array(box clean::Generic(name), n) if !f.alternate() => primitive_link( + f, + PrimitiveType::Array, + format_args!("[{name}; {n}]", n = Escape(n)), + cx, + ), + clean::Array(t, n) => { + write!(f, "[")?; + t.print(cx).fmt(f)?; + if f.alternate() { + write!(f, "; {n}")?; + } else { + write!(f, "; ")?; + primitive_link(f, PrimitiveType::Array, format_args!("{n}", n = Escape(n)), cx)?; } - }, - clean::RawPointer(m, ref t) => { + write!(f, "]") + } + clean::RawPointer(m, t) => { let m = match m { hir::Mutability::Mut => "mut", hir::Mutability::Not => "const", @@ -991,7 +982,7 @@ fn fmt_type( t.print(cx).fmt(f) } } - clean::BorrowedRef { lifetime: ref l, mutability, type_: ref ty } => { + clean::BorrowedRef { lifetime: l, mutability, type_: ty } => { let lt = fmt::from_fn(|f| match l { Some(l) => write!(f, "{} ", l.print()), _ => Ok(()), @@ -1028,11 +1019,11 @@ fn fmt_type( } Ok(()) } - clean::ImplTrait(ref bounds) => { + clean::ImplTrait(bounds) => { f.write_str("impl ")?; print_generic_bounds(bounds, cx).fmt(f) } - clean::QPath(box clean::QPathData { + &clean::QPath(box clean::QPathData { ref assoc, ref self_type, ref trait_, From c04873b02d5a5b0723cb7e058bca323a78e6bb70 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 16 May 2025 17:01:24 +0200 Subject: [PATCH 2387/4206] Catch panics in inference in analysis-stats --- .../rust-analyzer/src/cli/analysis_stats.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index a1e4adf0844af..671e838421f28 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -4,6 +4,7 @@ use std::{ env, fmt, ops::AddAssign, + panic::{AssertUnwindSafe, catch_unwind}, time::{SystemTime, UNIX_EPOCH}, }; @@ -721,6 +722,7 @@ impl flags::AnalysisStats { let mut num_pats_unknown = 0; let mut num_pats_partially_unknown = 0; let mut num_pat_type_mismatches = 0; + let mut panics = 0; for &body_id in bodies { let name = body_id.name(db).unwrap_or_else(Name::missing); let module = body_id.module(db); @@ -774,7 +776,20 @@ impl flags::AnalysisStats { } bar.set_message(msg); let body = db.body(body_id.into()); - let inference_result = db.infer(body_id.into()); + let inference_result = catch_unwind(AssertUnwindSafe(|| db.infer(body_id.into()))); + let inference_result = match inference_result { + Ok(inference_result) => inference_result, + Err(p) => { + if let Some(s) = p.downcast_ref::<&str>() { + eprintln!("infer panicked for {}: {}", full_name(), s); + } else if let Some(s) = p.downcast_ref::() { + eprintln!("infer panicked for {}: {}", full_name(), s); + } + panics += 1; + bar.inc(1); + continue; + } + }; // This query is LRU'd, so actually calling it will skew the timing results. let sm = || db.body_with_source_map(body_id.into()).1; @@ -1008,6 +1023,7 @@ impl flags::AnalysisStats { percentage(num_pats_partially_unknown, num_pats), num_pat_type_mismatches ); + eprintln!(" panics: {}", panics); eprintln!("{:<20} {}", "Inference:", inference_time); report_metric("unknown type", num_exprs_unknown, "#"); report_metric("type mismatches", num_expr_type_mismatches, "#"); From 1adfdb42b923d432e8a163350115819e6c0cb887 Mon Sep 17 00:00:00 2001 From: bohan Date: Sat, 17 May 2025 22:01:57 +0800 Subject: [PATCH 2388/4206] Use `crate::` prefix for root macro suggestions --- compiler/rustc_resolve/src/diagnostics.rs | 2 +- tests/ui/imports/issue-99695-b.fixed | 2 +- tests/ui/imports/issue-99695-b.stderr | 2 +- ...5.fixed => issue-99695.edition_2015.fixed} | 6 +++++- ...stderr => issue-99695.edition_2015.stderr} | 4 ++-- .../ui/imports/issue-99695.edition_2018.fixed | 21 +++++++++++++++++++ .../imports/issue-99695.edition_2018.stderr | 16 ++++++++++++++ tests/ui/imports/issue-99695.rs | 4 ++++ 8 files changed, 51 insertions(+), 6 deletions(-) rename tests/ui/imports/{issue-99695.fixed => issue-99695.edition_2015.fixed} (71%) rename tests/ui/imports/{issue-99695.stderr => issue-99695.edition_2015.stderr} (90%) create mode 100644 tests/ui/imports/issue-99695.edition_2018.fixed create mode 100644 tests/ui/imports/issue-99695.edition_2018.stderr diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 0b16983c2c794..d09750fa281ba 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2493,7 +2493,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() else { return None; }; - let module_name = crate_module.kind.name().unwrap_or(kw::Empty); + let module_name = crate_module.kind.name().unwrap_or(kw::Crate); let import_snippet = match import.kind { ImportKind::Single { source, target, .. } if source != target => { format!("{source} as {target}") diff --git a/tests/ui/imports/issue-99695-b.fixed b/tests/ui/imports/issue-99695-b.fixed index 0108f762400f6..ae63b0c4627c5 100644 --- a/tests/ui/imports/issue-99695-b.fixed +++ b/tests/ui/imports/issue-99695-b.fixed @@ -11,7 +11,7 @@ mod m { pub struct other_item; } - use ::nu; + use crate::nu; pub use self::p::{other_item as _}; //~^ ERROR unresolved import `self::p::nu` [E0432] //~| HELP a macro with this name exists at the root of the crate diff --git a/tests/ui/imports/issue-99695-b.stderr b/tests/ui/imports/issue-99695-b.stderr index d58d2798746c1..ad752d5c45a7e 100644 --- a/tests/ui/imports/issue-99695-b.stderr +++ b/tests/ui/imports/issue-99695-b.stderr @@ -7,7 +7,7 @@ LL | pub use self::p::{nu, other_item as _}; = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined help: a macro with this name exists at the root of the crate | -LL ~ use ::nu; +LL ~ use crate::nu; LL ~ pub use self::p::{other_item as _}; | diff --git a/tests/ui/imports/issue-99695.fixed b/tests/ui/imports/issue-99695.edition_2015.fixed similarity index 71% rename from tests/ui/imports/issue-99695.fixed rename to tests/ui/imports/issue-99695.edition_2015.fixed index 51ccd3f8c48d1..798acfd587467 100644 --- a/tests/ui/imports/issue-99695.fixed +++ b/tests/ui/imports/issue-99695.edition_2015.fixed @@ -1,4 +1,8 @@ //@ run-rustfix +//@ revisions: edition_2015 edition_2018 +//@ [edition_2015] edition: 2015 +//@ [edition_2018] edition: 2018 + #![allow(unused, nonstandard_style)] mod m { #[macro_export] @@ -8,7 +12,7 @@ mod m { pub struct other_item; - use ::nu; + use crate::nu; pub use self::{other_item as _}; //~^ ERROR unresolved import `self::nu` [E0432] //~| HELP a macro with this name exists at the root of the crate diff --git a/tests/ui/imports/issue-99695.stderr b/tests/ui/imports/issue-99695.edition_2015.stderr similarity index 90% rename from tests/ui/imports/issue-99695.stderr rename to tests/ui/imports/issue-99695.edition_2015.stderr index 536f51dcb3b20..4ef8e6426fb29 100644 --- a/tests/ui/imports/issue-99695.stderr +++ b/tests/ui/imports/issue-99695.edition_2015.stderr @@ -1,5 +1,5 @@ error[E0432]: unresolved import `self::nu` - --> $DIR/issue-99695.rs:11:20 + --> $DIR/issue-99695.rs:15:20 | LL | pub use self::{nu, other_item as _}; | ^^ no `nu` in `m` @@ -7,7 +7,7 @@ LL | pub use self::{nu, other_item as _}; = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined help: a macro with this name exists at the root of the crate | -LL ~ use ::nu; +LL ~ use crate::nu; LL ~ pub use self::{other_item as _}; | diff --git a/tests/ui/imports/issue-99695.edition_2018.fixed b/tests/ui/imports/issue-99695.edition_2018.fixed new file mode 100644 index 0000000000000..798acfd587467 --- /dev/null +++ b/tests/ui/imports/issue-99695.edition_2018.fixed @@ -0,0 +1,21 @@ +//@ run-rustfix +//@ revisions: edition_2015 edition_2018 +//@ [edition_2015] edition: 2015 +//@ [edition_2018] edition: 2018 + +#![allow(unused, nonstandard_style)] +mod m { + #[macro_export] + macro_rules! nu { + {} => {}; + } + + pub struct other_item; + + use crate::nu; +pub use self::{other_item as _}; + //~^ ERROR unresolved import `self::nu` [E0432] + //~| HELP a macro with this name exists at the root of the crate +} + +fn main() {} diff --git a/tests/ui/imports/issue-99695.edition_2018.stderr b/tests/ui/imports/issue-99695.edition_2018.stderr new file mode 100644 index 0000000000000..4ef8e6426fb29 --- /dev/null +++ b/tests/ui/imports/issue-99695.edition_2018.stderr @@ -0,0 +1,16 @@ +error[E0432]: unresolved import `self::nu` + --> $DIR/issue-99695.rs:15:20 + | +LL | pub use self::{nu, other_item as _}; + | ^^ no `nu` in `m` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL ~ use crate::nu; +LL ~ pub use self::{other_item as _}; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/imports/issue-99695.rs b/tests/ui/imports/issue-99695.rs index a52370e0eb085..dc0a8f438e008 100644 --- a/tests/ui/imports/issue-99695.rs +++ b/tests/ui/imports/issue-99695.rs @@ -1,4 +1,8 @@ //@ run-rustfix +//@ revisions: edition_2015 edition_2018 +//@ [edition_2015] edition: 2015 +//@ [edition_2018] edition: 2018 + #![allow(unused, nonstandard_style)] mod m { #[macro_export] From b3b2153c0b26fa1cfb491c863b2b0196949a9e3e Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sat, 17 May 2025 22:26:42 +0800 Subject: [PATCH 2389/4206] Update triagebot.toml Co-authored-by: Urgau <3616612+Urgau@users.noreply.github.com> --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index a3866d62dca41..36d5838d1e196 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1426,4 +1426,4 @@ compiletest = [ [note] [behind-upstream] -days-threshold = 7 +days-threshold = 14 From 65d381b0cc2b7b8404e7c910055dd3cf806f1cca Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sat, 17 May 2025 23:48:57 +0800 Subject: [PATCH 2390/4206] triagebot: fix Rust for Linux ping group rust-lang/rust label --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 9dcdbcecbeca6..f566a947e0e96 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -133,7 +133,7 @@ In case it's useful, here are some [instructions] for tackling these sorts of is [instructions]: https://rustc-dev-guide.rust-lang.org/notification-groups/rust-for-linux.html """ -label = "O-rfl" +label = "A-rust-for-linux" [ping.wasm] alias = ["webassembly"] From 2dddbd1ecb586b7a7dc67c078c2f7785a5cb63ba Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sat, 17 May 2025 23:51:00 +0800 Subject: [PATCH 2391/4206] rustc-dev-guide: fix Rust for Linux rust-lang/rust label --- .../rustc-dev-guide/src/notification-groups/rust-for-linux.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/notification-groups/rust-for-linux.md b/src/doc/rustc-dev-guide/src/notification-groups/rust-for-linux.md index 9ba4eff629e7c..696f2038e1a4b 100644 --- a/src/doc/rustc-dev-guide/src/notification-groups/rust-for-linux.md +++ b/src/doc/rustc-dev-guide/src/notification-groups/rust-for-linux.md @@ -1,9 +1,9 @@ # Rust for Linux notification group -**Github Label:** [O-rfl]
+**Github Label:** [A-rust-for-linux]
**Ping command:** `@rustbot ping rfl` -[O-rfl]: https://github.com/rust-lang/rust/labels/O-rfl +[A-rust-for-linux]: https://github.com/rust-lang/rust/labels/A-rust-for-linux This list will be used to notify [Rust for Linux (RfL)][rfl] maintainers when the compiler or the standard library changes in a way that would From 1bc8535e61595c87a041cdebd64f073918cce108 Mon Sep 17 00:00:00 2001 From: GrantBirki Date: Sat, 17 May 2025 10:36:39 -0700 Subject: [PATCH 2392/4206] revert forward slash to backslash --- library/std/tests/path.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/tests/path.rs b/library/std/tests/path.rs index a6f679d0ffb3c..dc068db04a7b5 100644 --- a/library/std/tests/path.rs +++ b/library/std/tests/path.rs @@ -1235,7 +1235,7 @@ pub fn test_push() { tp!("foo//", "bar", r"foo//bar"); tp!(r"foo\\", "bar", r"foo\\bar"); tp!("foo/.", "bar", r"foo/.\bar"); - tp!("foo./.", "bar", r"foo././bar"); + tp!("foo./.", "bar", r"foo./.\bar"); tp!(r"foo\.", "bar", r"foo\.\bar"); tp!(r"foo.\.", "bar", r"foo.\.\bar"); tp!("foo", "", "foo\\"); From 4358a1c05e8a8878edf22c8cb1f3eae07e09efc0 Mon Sep 17 00:00:00 2001 From: GrantBirki Date: Sat, 17 May 2025 10:49:15 -0700 Subject: [PATCH 2393/4206] remove extra tests that really might not be all that useful --- library/std/tests/path.rs | 55 --------------------------------------- 1 file changed, 55 deletions(-) diff --git a/library/std/tests/path.rs b/library/std/tests/path.rs index dc068db04a7b5..87e0d226cbd31 100644 --- a/library/std/tests/path.rs +++ b/library/std/tests/path.rs @@ -1998,61 +1998,6 @@ fn test_non_ascii_unicode() { assert_eq!(path.file_name(), Some(OsStr::new("file.txt"))); } - -// Test: Reserved device names (Windows) -// This test ensures that reserved device names like "CON", "PRN", etc., are handled as normal paths on non-Windows platforms, -// and as special cases on Windows (if applicable). -#[test] -#[cfg(windows)] -fn test_reserved_device_names() { - for &name in &["CON", "PRN", "AUX", "NUL", "COM1", "LPT1"] { - let path = Path::new(name); - assert_eq!(path.file_name(), Some(OsStr::new(name))); - assert_eq!(path.extension(), None); - } -} - -// Test: Trailing dots/spaces (Windows) -// This test checks how Path handles trailing dots or spaces, which are special on Windows. -// On Unix, these should be treated as normal characters. -#[test] -#[cfg(windows)] -fn test_trailing_dots_and_spaces() { - let path = Path::new("foo. "); - assert_eq!(path.file_stem(), Some(OsStr::new("foo"))); - assert_eq!(path.extension(), Some(OsStr::new(" "))); - assert_eq!(path.file_name(), Some(OsStr::new("foo. "))); - assert_eq!(path.to_str(), Some("foo. ")); - let path = Path::new("bar..."); - assert_eq!(path.file_stem(), Some(OsStr::new("bar"))); - assert_eq!(path.extension(), Some(OsStr::new("..."))); - assert_eq!(path.file_name(), Some(OsStr::new("bar..."))); - assert_eq!(path.to_str(), Some("bar...")); -} - -// Test: Only extension (e.g., ".gitignore") -// This test verifies that files with only an extension and no base name are handled correctly. -// It checks that the extension is recognized and the file stem is None or empty as appropriate. -#[test] -fn test_only_extension() { - let path = Path::new(".ext"); - assert_eq!(path.extension(), None); - assert_eq!(path.file_stem(), Some(OsStr::new(".ext"))); - assert_eq!(path.file_name(), Some(OsStr::new(".ext"))); -} - -// Test: Long components -// This test checks that Path can handle very long path components without truncation or error. -// It ensures that the length of the component is preserved. -#[test] -fn test_long_component() { - let long = "a".repeat(300); - let path = Path::new(&long); - assert_eq!(path.file_name(), Some(OsStr::new(&long))); - assert_eq!(path.to_str(), Some(long.as_str())); - assert_eq!(path.iter().count(), 1); -} - // Test: Embedded newlines // This test verifies that newlines within path components are preserved and do not break path parsing. // It ensures that Path treats newlines as normal characters. From 98cdb829a8e751a4fa82849bfe3195e3f0756e36 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 17 May 2025 19:35:01 +0000 Subject: [PATCH 2394/4206] Fast path for register_region_obligation --- compiler/rustc_infer/src/infer/outlives/obligations.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 8dde99c45cfa8..5fd98e35e5ce8 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -98,6 +98,14 @@ impl<'tcx> InferCtxt<'tcx> { sub_region: Region<'tcx>, cause: &ObligationCause<'tcx>, ) { + // `is_global` means the type has no params, infer, placeholder, or non-`'static` + // free regions. If the type has none of these things, then we can skip registering + // this outlives obligation since it has no components which affect lifetime + // checking in an interesting way. + if sup_type.is_global() { + return; + } + debug!(?sup_type, ?sub_region, ?cause); let origin = SubregionOrigin::from_obligation_cause(cause, || { infer::RelateParamBound( From cd22c1b88385b65d657dedd520abaf1a0aaf7e3f Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 29 Apr 2025 20:25:59 +0200 Subject: [PATCH 2395/4206] determine later whether an explicit reg was used --- compiler/rustc_builtin_macros/src/asm.rs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 3e8ddb8abd43f..58aba3e590323 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -135,9 +135,8 @@ pub fn parse_asm_args<'a>( None }; - let mut explicit_reg = false; let op = if eat_operand_keyword(p, exp!(In), asm_macro)? { - let reg = parse_reg(p, &mut explicit_reg)?; + let reg = parse_reg(p)?; if p.eat_keyword(exp!(Underscore)) { let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); return Err(err); @@ -145,15 +144,15 @@ pub fn parse_asm_args<'a>( let expr = p.parse_expr()?; ast::InlineAsmOperand::In { reg, expr } } else if eat_operand_keyword(p, exp!(Out), asm_macro)? { - let reg = parse_reg(p, &mut explicit_reg)?; + let reg = parse_reg(p)?; let expr = if p.eat_keyword(exp!(Underscore)) { None } else { Some(p.parse_expr()?) }; ast::InlineAsmOperand::Out { reg, expr, late: false } } else if eat_operand_keyword(p, exp!(Lateout), asm_macro)? { - let reg = parse_reg(p, &mut explicit_reg)?; + let reg = parse_reg(p)?; let expr = if p.eat_keyword(exp!(Underscore)) { None } else { Some(p.parse_expr()?) }; ast::InlineAsmOperand::Out { reg, expr, late: true } } else if eat_operand_keyword(p, exp!(Inout), asm_macro)? { - let reg = parse_reg(p, &mut explicit_reg)?; + let reg = parse_reg(p)?; if p.eat_keyword(exp!(Underscore)) { let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); return Err(err); @@ -167,7 +166,7 @@ pub fn parse_asm_args<'a>( ast::InlineAsmOperand::InOut { reg, expr, late: false } } } else if eat_operand_keyword(p, exp!(Inlateout), asm_macro)? { - let reg = parse_reg(p, &mut explicit_reg)?; + let reg = parse_reg(p)?; if p.eat_keyword(exp!(Underscore)) { let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); return Err(err); @@ -223,6 +222,8 @@ pub fn parse_asm_args<'a>( p.unexpected_any()? }; + let explicit_reg = matches!(op.reg(), Some(ast::InlineAsmRegOrRegClass::Reg(_))); + allow_templates = false; let span = span_start.to(p.prev_token.span); let slot = args.operands.len(); @@ -231,6 +232,7 @@ pub fn parse_asm_args<'a>( // Validate the order of named, positional & explicit register operands and // clobber_abi/options. We do this at the end once we have the full span // of the argument available. + if explicit_reg { if name.is_some() { dcx.emit_err(errors::AsmExplicitRegisterName { span }); @@ -478,15 +480,11 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a, Ok(()) } -fn parse_reg<'a>( - p: &mut Parser<'a>, - explicit_reg: &mut bool, -) -> PResult<'a, ast::InlineAsmRegOrRegClass> { +fn parse_reg<'a>(p: &mut Parser<'a>) -> PResult<'a, ast::InlineAsmRegOrRegClass> { p.expect(exp!(OpenParen))?; let result = match p.token.uninterpolate().kind { token::Ident(name, IdentIsRaw::No) => ast::InlineAsmRegOrRegClass::RegClass(name), token::Literal(token::Lit { kind: token::LitKind::Str, symbol, suffix: _ }) => { - *explicit_reg = true; ast::InlineAsmRegOrRegClass::Reg(symbol) } _ => { From 5af9652e5c733eb14c9a28b92c7a2608cbf7ea59 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 29 Apr 2025 20:35:39 +0200 Subject: [PATCH 2396/4206] extract operand parser --- compiler/rustc_builtin_macros/src/asm.rs | 176 ++++++++++++----------- 1 file changed, 93 insertions(+), 83 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 58aba3e590323..3afa2d3dd8eec 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -69,6 +69,76 @@ fn parse_args<'a>( parse_asm_args(&mut p, sp, asm_macro) } +fn parse_asm_operand<'a>( + p: &mut Parser<'a>, + asm_macro: AsmMacro, +) -> PResult<'a, Option> { + let dcx = p.dcx(); + + Ok(Some(if eat_operand_keyword(p, exp!(In), asm_macro)? { + let reg = parse_reg(p)?; + if p.eat_keyword(exp!(Underscore)) { + let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); + return Err(err); + } + let expr = p.parse_expr()?; + ast::InlineAsmOperand::In { reg, expr } + } else if eat_operand_keyword(p, exp!(Out), asm_macro)? { + let reg = parse_reg(p)?; + let expr = if p.eat_keyword(exp!(Underscore)) { None } else { Some(p.parse_expr()?) }; + ast::InlineAsmOperand::Out { reg, expr, late: false } + } else if eat_operand_keyword(p, exp!(Lateout), asm_macro)? { + let reg = parse_reg(p)?; + let expr = if p.eat_keyword(exp!(Underscore)) { None } else { Some(p.parse_expr()?) }; + ast::InlineAsmOperand::Out { reg, expr, late: true } + } else if eat_operand_keyword(p, exp!(Inout), asm_macro)? { + let reg = parse_reg(p)?; + if p.eat_keyword(exp!(Underscore)) { + let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); + return Err(err); + } + let expr = p.parse_expr()?; + if p.eat(exp!(FatArrow)) { + let out_expr = + if p.eat_keyword(exp!(Underscore)) { None } else { Some(p.parse_expr()?) }; + ast::InlineAsmOperand::SplitInOut { reg, in_expr: expr, out_expr, late: false } + } else { + ast::InlineAsmOperand::InOut { reg, expr, late: false } + } + } else if eat_operand_keyword(p, exp!(Inlateout), asm_macro)? { + let reg = parse_reg(p)?; + if p.eat_keyword(exp!(Underscore)) { + let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); + return Err(err); + } + let expr = p.parse_expr()?; + if p.eat(exp!(FatArrow)) { + let out_expr = + if p.eat_keyword(exp!(Underscore)) { None } else { Some(p.parse_expr()?) }; + ast::InlineAsmOperand::SplitInOut { reg, in_expr: expr, out_expr, late: true } + } else { + ast::InlineAsmOperand::InOut { reg, expr, late: true } + } + } else if eat_operand_keyword(p, exp!(Label), asm_macro)? { + let block = p.parse_block()?; + ast::InlineAsmOperand::Label { block } + } else if p.eat_keyword(exp!(Const)) { + let anon_const = p.parse_expr_anon_const()?; + ast::InlineAsmOperand::Const { anon_const } + } else if p.eat_keyword(exp!(Sym)) { + let expr = p.parse_expr()?; + let ast::ExprKind::Path(qself, path) = &expr.kind else { + let err = dcx.create_err(errors::AsmSymNoPath { span: expr.span }); + return Err(err); + }; + let sym = + ast::InlineAsmSym { id: ast::DUMMY_NODE_ID, qself: qself.clone(), path: path.clone() }; + ast::InlineAsmOperand::Sym { sym } + } else { + return Ok(None); + })) +} + // Primarily public for rustfmt consumption. // Internal consumers should continue to leverage `expand_asm`/`expand__global_asm` pub fn parse_asm_args<'a>( @@ -135,91 +205,31 @@ pub fn parse_asm_args<'a>( None }; - let op = if eat_operand_keyword(p, exp!(In), asm_macro)? { - let reg = parse_reg(p)?; - if p.eat_keyword(exp!(Underscore)) { - let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); - return Err(err); - } - let expr = p.parse_expr()?; - ast::InlineAsmOperand::In { reg, expr } - } else if eat_operand_keyword(p, exp!(Out), asm_macro)? { - let reg = parse_reg(p)?; - let expr = if p.eat_keyword(exp!(Underscore)) { None } else { Some(p.parse_expr()?) }; - ast::InlineAsmOperand::Out { reg, expr, late: false } - } else if eat_operand_keyword(p, exp!(Lateout), asm_macro)? { - let reg = parse_reg(p)?; - let expr = if p.eat_keyword(exp!(Underscore)) { None } else { Some(p.parse_expr()?) }; - ast::InlineAsmOperand::Out { reg, expr, late: true } - } else if eat_operand_keyword(p, exp!(Inout), asm_macro)? { - let reg = parse_reg(p)?; - if p.eat_keyword(exp!(Underscore)) { - let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); - return Err(err); - } - let expr = p.parse_expr()?; - if p.eat(exp!(FatArrow)) { - let out_expr = - if p.eat_keyword(exp!(Underscore)) { None } else { Some(p.parse_expr()?) }; - ast::InlineAsmOperand::SplitInOut { reg, in_expr: expr, out_expr, late: false } - } else { - ast::InlineAsmOperand::InOut { reg, expr, late: false } - } - } else if eat_operand_keyword(p, exp!(Inlateout), asm_macro)? { - let reg = parse_reg(p)?; - if p.eat_keyword(exp!(Underscore)) { - let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); - return Err(err); - } - let expr = p.parse_expr()?; - if p.eat(exp!(FatArrow)) { - let out_expr = - if p.eat_keyword(exp!(Underscore)) { None } else { Some(p.parse_expr()?) }; - ast::InlineAsmOperand::SplitInOut { reg, in_expr: expr, out_expr, late: true } - } else { - ast::InlineAsmOperand::InOut { reg, expr, late: true } - } - } else if eat_operand_keyword(p, exp!(Label), asm_macro)? { - let block = p.parse_block()?; - ast::InlineAsmOperand::Label { block } - } else if p.eat_keyword(exp!(Const)) { - let anon_const = p.parse_expr_anon_const()?; - ast::InlineAsmOperand::Const { anon_const } - } else if p.eat_keyword(exp!(Sym)) { - let expr = p.parse_expr()?; - let ast::ExprKind::Path(qself, path) = &expr.kind else { - let err = dcx.create_err(errors::AsmSymNoPath { span: expr.span }); - return Err(err); - }; - let sym = ast::InlineAsmSym { - id: ast::DUMMY_NODE_ID, - qself: qself.clone(), - path: path.clone(), - }; - ast::InlineAsmOperand::Sym { sym } - } else if allow_templates { - let template = p.parse_expr()?; - // If it can't possibly expand to a string, provide diagnostics here to include other - // things it could have been. - match template.kind { - ast::ExprKind::Lit(token_lit) - if matches!( - token_lit.kind, - token::LitKind::Str | token::LitKind::StrRaw(_) - ) => {} - ast::ExprKind::MacCall(..) => {} - _ => { - let err = dcx.create_err(errors::AsmExpectedOther { - span: template.span, - is_inline_asm: matches!(asm_macro, AsmMacro::Asm), - }); - return Err(err); + let Some(op) = parse_asm_operand(p, asm_macro)? else { + if allow_templates { + let template = p.parse_expr()?; + // If it can't possibly expand to a string, provide diagnostics here to include other + // things it could have been. + match template.kind { + ast::ExprKind::Lit(token_lit) + if matches!( + token_lit.kind, + token::LitKind::Str | token::LitKind::StrRaw(_) + ) => {} + ast::ExprKind::MacCall(..) => {} + _ => { + let err = dcx.create_err(errors::AsmExpectedOther { + span: template.span, + is_inline_asm: matches!(asm_macro, AsmMacro::Asm), + }); + return Err(err); + } } + args.templates.push(template); + continue; + } else { + p.unexpected_any()? } - args.templates.push(template); - continue; - } else { - p.unexpected_any()? }; let explicit_reg = matches!(op.reg(), Some(ast::InlineAsmRegOrRegClass::Reg(_))); From 4320e6f474ba042f235327c4afe0f27cd454a565 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sun, 18 May 2025 04:54:45 +0000 Subject: [PATCH 2397/4206] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 79abbfaeaf116..8b98fe3c4fc3e 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -a69bc17fb8026bdc0d24bb1896ff95f0eba1da4e +ac17c3486c6fdfbb0c3c18b99f3d8dfbff625d29 From 84506c64fff3e636443022abd84c82ba6542dae0 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sun, 18 May 2025 05:02:46 +0000 Subject: [PATCH 2398/4206] fmt --- src/tools/miri/src/helpers.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index d2a7351662393..8e7c9edfcc078 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -933,7 +933,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Check that the calling convention is what we expect. - fn check_callconv<'a>(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, exp_abi: Conv) -> InterpResult<'a, ()> { + fn check_callconv<'a>( + &self, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + exp_abi: Conv, + ) -> InterpResult<'a, ()> { if fn_abi.conv != exp_abi { throw_ub_format!( "calling a function with calling convention {exp_abi} using caller calling convention {}", From cf7caded0bc2d0d84f4c84cc6dc108c16d23f134 Mon Sep 17 00:00:00 2001 From: sayantn Date: Thu, 17 Apr 2025 03:28:16 +0530 Subject: [PATCH 2399/4206] Stabilize `avx512_target_feature` --- compiler/rustc_feature/src/accepted.rs | 2 + compiler/rustc_feature/src/unstable.rs | 1 - compiler/rustc_target/src/target_features.rs | 44 +++++++++---------- library/core/src/lib.rs | 2 +- library/stdarch | 2 +- .../using-target-feature-unstable.rs | 4 +- tests/ui/target-feature/gate.rs | 3 +- tests/ui/target-feature/gate.stderr | 10 ++--- tests/ui/target-feature/unstable-feature.rs | 4 +- .../ui/target-feature/unstable-feature.stderr | 2 +- 10 files changed, 37 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 809d1630ddec1..820af9ac84b2c 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -82,6 +82,8 @@ declare_features! ( (accepted, attr_literals, "1.30.0", Some(34981)), /// Allows overloading augmented assignment operations like `a += b`. (accepted, augmented_assignments, "1.8.0", Some(28235)), + /// Allows using `avx512*` target features. + (accepted, avx512_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)), /// Allows mixing bind-by-move in patterns and references to those identifiers in guards. (accepted, bind_by_move_pattern_guards, "1.39.0", Some(15287)), /// Allows bindings in the subpattern of a binding pattern. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 8fb10736539a3..6cdcf451f37e3 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -318,7 +318,6 @@ declare_features! ( (unstable, aarch64_ver_target_feature, "1.27.0", Some(44839)), (unstable, apx_target_feature, "1.88.0", Some(139284)), (unstable, arm_target_feature, "1.27.0", Some(44839)), - (unstable, avx512_target_feature, "1.27.0", Some(44839)), (unstable, bpf_target_feature, "1.54.0", Some(44839)), (unstable, csky_target_feature, "1.73.0", Some(44839)), (unstable, ermsb_target_feature, "1.49.0", Some(44839)), diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 5428aa4cf7085..99b04ac272009 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -416,25 +416,25 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ), ("avx10.2", Unstable(sym::avx10_target_feature), &["avx10.1"]), ("avx2", Stable, &["avx"]), - ("avx512bf16", Unstable(sym::avx512_target_feature), &["avx512bw"]), - ("avx512bitalg", Unstable(sym::avx512_target_feature), &["avx512bw"]), - ("avx512bw", Unstable(sym::avx512_target_feature), &["avx512f"]), - ("avx512cd", Unstable(sym::avx512_target_feature), &["avx512f"]), - ("avx512dq", Unstable(sym::avx512_target_feature), &["avx512f"]), - ("avx512f", Unstable(sym::avx512_target_feature), &["avx2", "fma", "f16c"]), - ("avx512fp16", Unstable(sym::avx512_target_feature), &["avx512bw"]), - ("avx512ifma", Unstable(sym::avx512_target_feature), &["avx512f"]), - ("avx512vbmi", Unstable(sym::avx512_target_feature), &["avx512bw"]), - ("avx512vbmi2", Unstable(sym::avx512_target_feature), &["avx512bw"]), - ("avx512vl", Unstable(sym::avx512_target_feature), &["avx512f"]), - ("avx512vnni", Unstable(sym::avx512_target_feature), &["avx512f"]), - ("avx512vp2intersect", Unstable(sym::avx512_target_feature), &["avx512f"]), - ("avx512vpopcntdq", Unstable(sym::avx512_target_feature), &["avx512f"]), - ("avxifma", Unstable(sym::avx512_target_feature), &["avx2"]), - ("avxneconvert", Unstable(sym::avx512_target_feature), &["avx2"]), - ("avxvnni", Unstable(sym::avx512_target_feature), &["avx2"]), - ("avxvnniint16", Unstable(sym::avx512_target_feature), &["avx2"]), - ("avxvnniint8", Unstable(sym::avx512_target_feature), &["avx2"]), + ("avx512bf16", Stable, &["avx512bw"]), + ("avx512bitalg", Stable, &["avx512bw"]), + ("avx512bw", Stable, &["avx512f"]), + ("avx512cd", Stable, &["avx512f"]), + ("avx512dq", Stable, &["avx512f"]), + ("avx512f", Stable, &["avx2", "fma", "f16c"]), + ("avx512fp16", Stable, &["avx512bw"]), + ("avx512ifma", Stable, &["avx512f"]), + ("avx512vbmi", Stable, &["avx512bw"]), + ("avx512vbmi2", Stable, &["avx512bw"]), + ("avx512vl", Stable, &["avx512f"]), + ("avx512vnni", Stable, &["avx512f"]), + ("avx512vp2intersect", Stable, &["avx512f"]), + ("avx512vpopcntdq", Stable, &["avx512f"]), + ("avxifma", Stable, &["avx2"]), + ("avxneconvert", Stable, &["avx2"]), + ("avxvnni", Stable, &["avx2"]), + ("avxvnniint16", Stable, &["avx2"]), + ("avxvnniint8", Stable, &["avx2"]), ("bmi1", Stable, &[]), ("bmi2", Stable, &[]), ("cmpxchg16b", Stable, &[]), @@ -442,7 +442,7 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("f16c", Stable, &["avx"]), ("fma", Stable, &["avx"]), ("fxsr", Stable, &[]), - ("gfni", Unstable(sym::avx512_target_feature), &["sse2"]), + ("gfni", Stable, &["sse2"]), ("kl", Unstable(sym::keylocker_x86), &["sse2"]), ("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]), ("lzcnt", Stable, &[]), @@ -469,8 +469,8 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("sse4a", Unstable(sym::sse4a_target_feature), &["sse3"]), ("ssse3", Stable, &["sse3"]), ("tbm", Unstable(sym::tbm_target_feature), &[]), - ("vaes", Unstable(sym::avx512_target_feature), &["avx2", "aes"]), - ("vpclmulqdq", Unstable(sym::avx512_target_feature), &["avx", "pclmulqdq"]), + ("vaes", Stable, &["avx2", "aes"]), + ("vpclmulqdq", Stable, &["avx", "pclmulqdq"]), ("widekl", Unstable(sym::keylocker_x86), &["kl"]), ("x87", Unstable(sym::x87_target_feature), &[]), ("xop", Unstable(sym::xop_target_feature), &[/*"fma4", */ "avx", "sse4a"]), diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 64a7ec8906b6b..b3c7e2c1d2da2 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -188,9 +188,9 @@ // // Target features: // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(avx512_target_feature))] #![feature(aarch64_unstable_target_feature)] #![feature(arm_target_feature)] -#![feature(avx512_target_feature)] #![feature(hexagon_target_feature)] #![feature(keylocker_x86)] #![feature(loongarch_target_feature)] diff --git a/library/stdarch b/library/stdarch index f1c1839c0deb9..1dfaa4db24797 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit f1c1839c0deb985a9f98cbd6b38a6d43f2df6157 +Subproject commit 1dfaa4db2479753a46a3e90f2c3c89d89d0b21f1 diff --git a/tests/ui/target-feature/auxiliary/using-target-feature-unstable.rs b/tests/ui/target-feature/auxiliary/using-target-feature-unstable.rs index 2682028936c19..15bcfdd9076e0 100644 --- a/tests/ui/target-feature/auxiliary/using-target-feature-unstable.rs +++ b/tests/ui/target-feature/auxiliary/using-target-feature-unstable.rs @@ -1,5 +1,5 @@ -#![feature(avx512_target_feature)] +#![feature(x87_target_feature)] #[inline] -#[target_feature(enable = "avx512ifma")] +#[target_feature(enable = "x87")] pub unsafe fn foo() {} diff --git a/tests/ui/target-feature/gate.rs b/tests/ui/target-feature/gate.rs index 14fdad02f5665..9244a98d82fdf 100644 --- a/tests/ui/target-feature/gate.rs +++ b/tests/ui/target-feature/gate.rs @@ -2,7 +2,6 @@ // // gate-test-sse4a_target_feature // gate-test-powerpc_target_feature -// gate-test-avx512_target_feature // gate-test-tbm_target_feature // gate-test-arm_target_feature // gate-test-hexagon_target_feature @@ -27,7 +26,7 @@ // gate-test-x87_target_feature // gate-test-m68k_target_feature -#[target_feature(enable = "avx512bw")] +#[target_feature(enable = "x87")] //~^ ERROR: currently unstable unsafe fn foo() {} diff --git a/tests/ui/target-feature/gate.stderr b/tests/ui/target-feature/gate.stderr index fa876893848f7..32d60ce438227 100644 --- a/tests/ui/target-feature/gate.stderr +++ b/tests/ui/target-feature/gate.stderr @@ -1,11 +1,11 @@ -error[E0658]: the target feature `avx512bw` is currently unstable - --> $DIR/gate.rs:30:18 +error[E0658]: the target feature `x87` is currently unstable + --> $DIR/gate.rs:29:18 | -LL | #[target_feature(enable = "avx512bw")] - | ^^^^^^^^^^^^^^^^^^^ +LL | #[target_feature(enable = "x87")] + | ^^^^^^^^^^^^^^ | = note: see issue #44839 for more information - = help: add `#![feature(avx512_target_feature)]` to the crate attributes to enable + = help: add `#![feature(x87_target_feature)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: aborting due to 1 previous error diff --git a/tests/ui/target-feature/unstable-feature.rs b/tests/ui/target-feature/unstable-feature.rs index f62c4dd938a0b..a79ad4696033a 100644 --- a/tests/ui/target-feature/unstable-feature.rs +++ b/tests/ui/target-feature/unstable-feature.rs @@ -1,8 +1,8 @@ -//@ compile-flags: -Ctarget-feature=+vaes --crate-type=rlib --target=x86_64-unknown-linux-gnu +//@ compile-flags: -Ctarget-feature=+x87 --crate-type=rlib --target=x86_64-unknown-linux-gnu //@ build-pass //@ needs-llvm-components: x86 #![feature(no_core)] #![no_core] -//~? WARN unstable feature specified for `-Ctarget-feature`: `vaes` +//~? WARN unstable feature specified for `-Ctarget-feature`: `x87` diff --git a/tests/ui/target-feature/unstable-feature.stderr b/tests/ui/target-feature/unstable-feature.stderr index d34544c5c2773..309b64afd9224 100644 --- a/tests/ui/target-feature/unstable-feature.stderr +++ b/tests/ui/target-feature/unstable-feature.stderr @@ -1,4 +1,4 @@ -warning: unstable feature specified for `-Ctarget-feature`: `vaes` +warning: unstable feature specified for `-Ctarget-feature`: `x87` | = note: this feature is not stably supported; its behavior can change in the future From 2898680ebdb6608deccf40a93c1fa062b588b365 Mon Sep 17 00:00:00 2001 From: sayantn Date: Thu, 17 Apr 2025 03:31:00 +0530 Subject: [PATCH 2400/4206] Remove uses of `#[feature(avx512_target_feature)]` --- .../pass/shims/x86/intrinsics-x86-aes-vaes.rs | 2 +- .../pass/shims/x86/intrinsics-x86-avx512.rs | 1 - .../pass/shims/x86/intrinsics-x86-gfni.rs | 1 - .../shims/x86/intrinsics-x86-vpclmulqdq.rs | 1 - .../homogenous-floats-target-feature-mixup.rs | 2 -- tests/ui/abi/simd-abi-checks-avx.rs | 1 - tests/ui/abi/simd-abi-checks-avx.stderr | 24 +++++++++---------- .../ui/asm/x86_64/evex512-implicit-feature.rs | 1 - tests/ui/asm/x86_64/target-feature-attr.rs | 2 -- .../ui/asm/x86_64/target-feature-attr.stderr | 8 +++---- tests/ui/simd/target-feature-mixup.rs | 1 - 11 files changed, 17 insertions(+), 27 deletions(-) diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs index 47f086f7340d7..48633c0a7fe66 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs @@ -2,7 +2,7 @@ //@only-target: x86_64 i686 //@compile-flags: -C target-feature=+aes,+vaes,+avx512f -#![feature(avx512_target_feature, stdarch_x86_avx512)] +#![feature(stdarch_x86_avx512)] use core::mem::transmute; #[cfg(target_arch = "x86")] diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs index db59306389016..0ec2f679d80ba 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs @@ -2,7 +2,6 @@ //@only-target: x86_64 i686 //@compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bitalg,+avx512vpopcntdq -#![feature(avx512_target_feature)] #![feature(stdarch_x86_avx512)] #[cfg(target_arch = "x86")] diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs index 882b5e3f79524..b58d68e2ef9ea 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs @@ -6,7 +6,6 @@ // be interpreted as integers; signedness does not make sense for them, but // __mXXXi happens to be defined in terms of signed integers. #![allow(overflowing_literals)] -#![feature(avx512_target_feature)] #![feature(stdarch_x86_avx512)] #[cfg(target_arch = "x86")] diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs index 68964728e4ea4..c7c9eb5e3951f 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs @@ -8,7 +8,6 @@ // be interpreted as integers; signedness does not make sense for them, but // __mXXXi happens to be defined in terms of signed integers. #![allow(overflowing_literals)] -#![feature(avx512_target_feature)] #![feature(stdarch_x86_avx512)] #[cfg(target_arch = "x86")] diff --git a/tests/ui/abi/homogenous-floats-target-feature-mixup.rs b/tests/ui/abi/homogenous-floats-target-feature-mixup.rs index 22b9b029a4049..2c78b794a8d74 100644 --- a/tests/ui/abi/homogenous-floats-target-feature-mixup.rs +++ b/tests/ui/abi/homogenous-floats-target-feature-mixup.rs @@ -7,8 +7,6 @@ //@ run-pass //@ needs-subprocess -#![feature(avx512_target_feature)] - #![allow(overflowing_literals)] #![allow(unused_variables)] diff --git a/tests/ui/abi/simd-abi-checks-avx.rs b/tests/ui/abi/simd-abi-checks-avx.rs index 772512702ece1..7432381d15b72 100644 --- a/tests/ui/abi/simd-abi-checks-avx.rs +++ b/tests/ui/abi/simd-abi-checks-avx.rs @@ -2,7 +2,6 @@ //@ build-fail //@ compile-flags: -C target-feature=-avx -#![feature(avx512_target_feature)] #![feature(portable_simd)] #![feature(simd_ffi)] #![allow(improper_ctypes_definitions)] diff --git a/tests/ui/abi/simd-abi-checks-avx.stderr b/tests/ui/abi/simd-abi-checks-avx.stderr index 48db30bf45371..7489ca0194600 100644 --- a/tests/ui/abi/simd-abi-checks-avx.stderr +++ b/tests/ui/abi/simd-abi-checks-avx.stderr @@ -1,5 +1,5 @@ error: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks-avx.rs:60:11 + --> $DIR/simd-abi-checks-avx.rs:59:11 | LL | f(g()); | ^^^ function called here @@ -7,7 +7,7 @@ LL | f(g()); = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) error: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks-avx.rs:60:9 + --> $DIR/simd-abi-checks-avx.rs:59:9 | LL | f(g()); | ^^^^^^ function called here @@ -15,7 +15,7 @@ LL | f(g()); = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) error: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks-avx.rs:66:14 + --> $DIR/simd-abi-checks-avx.rs:65:14 | LL | gavx(favx()); | ^^^^^^ function called here @@ -23,7 +23,7 @@ LL | gavx(favx()); = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) error: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks-avx.rs:66:9 + --> $DIR/simd-abi-checks-avx.rs:65:9 | LL | gavx(favx()); | ^^^^^^^^^^^^ function called here @@ -31,7 +31,7 @@ LL | gavx(favx()); = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) error: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks-avx.rs:76:19 + --> $DIR/simd-abi-checks-avx.rs:75:19 | LL | w(Wrapper(g())); | ^^^ function called here @@ -39,7 +39,7 @@ LL | w(Wrapper(g())); = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) error: this function call uses SIMD vector type `Wrapper` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks-avx.rs:76:9 + --> $DIR/simd-abi-checks-avx.rs:75:9 | LL | w(Wrapper(g())); | ^^^^^^^^^^^^^^^ function called here @@ -47,7 +47,7 @@ LL | w(Wrapper(g())); = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) error: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks-avx.rs:90:9 + --> $DIR/simd-abi-checks-avx.rs:89:9 | LL | some_extern(); | ^^^^^^^^^^^^^ function called here @@ -55,7 +55,7 @@ LL | some_extern(); = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) error: this function definition uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled - --> $DIR/simd-abi-checks-avx.rs:25:1 + --> $DIR/simd-abi-checks-avx.rs:24:1 | LL | unsafe extern "C" fn g() -> __m256 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -63,7 +63,7 @@ LL | unsafe extern "C" fn g() -> __m256 { = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) error: this function definition uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled - --> $DIR/simd-abi-checks-avx.rs:20:1 + --> $DIR/simd-abi-checks-avx.rs:19:1 | LL | unsafe extern "C" fn f(_: __m256) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -71,7 +71,7 @@ LL | unsafe extern "C" fn f(_: __m256) { = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) error: this function definition uses SIMD vector type `Wrapper` which (with the chosen ABI) requires the `avx` target feature, which is not enabled - --> $DIR/simd-abi-checks-avx.rs:15:1 + --> $DIR/simd-abi-checks-avx.rs:14:1 | LL | unsafe extern "C" fn w(_: Wrapper) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -79,7 +79,7 @@ LL | unsafe extern "C" fn w(_: Wrapper) { = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) error: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller - --> $DIR/simd-abi-checks-avx.rs:54:8 + --> $DIR/simd-abi-checks-avx.rs:53:8 | LL | || g() | ^^^ function called here @@ -87,7 +87,7 @@ LL | || g() = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) note: the above error was encountered while instantiating `fn in_closure::{closure#0}` - --> $DIR/simd-abi-checks-avx.rs:82:9 + --> $DIR/simd-abi-checks-avx.rs:81:9 | LL | in_closure()(); | ^^^^^^^^^^^^^^ diff --git a/tests/ui/asm/x86_64/evex512-implicit-feature.rs b/tests/ui/asm/x86_64/evex512-implicit-feature.rs index ea2acd424e2c6..ec5da7c7fa488 100644 --- a/tests/ui/asm/x86_64/evex512-implicit-feature.rs +++ b/tests/ui/asm/x86_64/evex512-implicit-feature.rs @@ -2,7 +2,6 @@ //@ only-x86_64 //@ compile-flags: --crate-type=lib -C target-cpu=skylake -#![feature(avx512_target_feature)] #![feature(stdarch_x86_avx512)] use std::arch::x86_64::*; diff --git a/tests/ui/asm/x86_64/target-feature-attr.rs b/tests/ui/asm/x86_64/target-feature-attr.rs index 6bb277ac16598..2193117caeb6d 100644 --- a/tests/ui/asm/x86_64/target-feature-attr.rs +++ b/tests/ui/asm/x86_64/target-feature-attr.rs @@ -2,8 +2,6 @@ // Set the base cpu explicitly, in case the default has been changed. //@ compile-flags: -C target-cpu=x86-64 -#![feature(avx512_target_feature)] - use std::arch::asm; #[target_feature(enable = "avx")] diff --git a/tests/ui/asm/x86_64/target-feature-attr.stderr b/tests/ui/asm/x86_64/target-feature-attr.stderr index 0cd571ac8cce8..c852726ee7ff8 100644 --- a/tests/ui/asm/x86_64/target-feature-attr.stderr +++ b/tests/ui/asm/x86_64/target-feature-attr.stderr @@ -1,23 +1,23 @@ error: register class `ymm_reg` requires the `avx` target feature - --> $DIR/target-feature-attr.rs:20:40 + --> $DIR/target-feature-attr.rs:18:40 | LL | asm!("vaddps {2:y}, {0:y}, {1:y}", in(ymm_reg) x, in(ymm_reg) y, lateout(ymm_reg) x); | ^^^^^^^^^^^^^ error: register class `ymm_reg` requires the `avx` target feature - --> $DIR/target-feature-attr.rs:20:55 + --> $DIR/target-feature-attr.rs:18:55 | LL | asm!("vaddps {2:y}, {0:y}, {1:y}", in(ymm_reg) x, in(ymm_reg) y, lateout(ymm_reg) x); | ^^^^^^^^^^^^^ error: register class `ymm_reg` requires the `avx` target feature - --> $DIR/target-feature-attr.rs:20:70 + --> $DIR/target-feature-attr.rs:18:70 | LL | asm!("vaddps {2:y}, {0:y}, {1:y}", in(ymm_reg) x, in(ymm_reg) y, lateout(ymm_reg) x); | ^^^^^^^^^^^^^^^^^^ error: register class `kreg` requires at least one of the following target features: avx512bw, avx512f - --> $DIR/target-feature-attr.rs:35:23 + --> $DIR/target-feature-attr.rs:33:23 | LL | asm!("/* {0} */", in(kreg) x); | ^^^^^^^^^^ diff --git a/tests/ui/simd/target-feature-mixup.rs b/tests/ui/simd/target-feature-mixup.rs index 2786251c7951b..77f1861524870 100644 --- a/tests/ui/simd/target-feature-mixup.rs +++ b/tests/ui/simd/target-feature-mixup.rs @@ -7,7 +7,6 @@ //@ ignore-fuchsia must translate zircon signal to SIGILL, FIXME (#58590) #![feature(repr_simd, target_feature, cfg_target_feature)] -#![feature(avx512_target_feature)] use std::process::{Command, ExitStatus}; use std::env; From 48093fd6959835408dc15d878ad7ae0d9c469a42 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 May 2025 08:10:09 +0200 Subject: [PATCH 2401/4206] attempt to make doctests work properly with old and new cargo --- src/tools/miri/cargo-miri/src/phases.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs index 171e157789d7f..4857f62cd3a1c 100644 --- a/src/tools/miri/cargo-miri/src/phases.rs +++ b/src/tools/miri/cargo-miri/src/phases.rs @@ -176,8 +176,11 @@ pub fn phase_cargo_miri(mut args: impl Iterator) { // Set `--target-dir` to `miri` inside the original target directory. let target_dir = get_target_dir(&metadata); cmd.arg("--target-dir").arg(target_dir); - // Enable cross-target doctests (for consistency between different cargo versions). - cmd.arg("-Zdoctest-xcompile"); + // Only when running in x.py (where we are running with beta cargo): set `RUSTC_STAGE`. + // Will have to be removed on next bootstrap bump. tag: cfg(bootstrap). + if env::var_os("RUSTC_STAGE").is_some() { + cmd.arg("-Zdoctest-xcompile"); + } // *After* we set all the flags that need setting, forward everything else. Make sure to skip // `--target-dir` (which would otherwise be set twice). From 0dec3fee34c5044f68579fedfa6882e0f69ff2cf Mon Sep 17 00:00:00 2001 From: Fluid <90795031+fluiderson@users.noreply.github.com> Date: Sun, 18 May 2025 09:54:57 +0300 Subject: [PATCH 2402/4206] replace `try_reserve_exact` with `try_with_capacity` in `std::fs::read` --- library/std/src/fs.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 11f439b9996de..509e673bdb8b9 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -285,8 +285,7 @@ pub fn read>(path: P) -> io::Result> { fn inner(path: &Path) -> io::Result> { let mut file = File::open(path)?; let size = file.metadata().map(|m| m.len() as usize).ok(); - let mut bytes = Vec::new(); - bytes.try_reserve_exact(size.unwrap_or(0))?; + let mut bytes = Vec::try_with_capacity(size.unwrap_or(0))?; io::default_read_to_end(&mut file, &mut bytes, size)?; Ok(bytes) } From b7caa1b3e0642a4c304a4d8240d4d1c3252b7c0c Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 17 May 2025 21:33:26 +0200 Subject: [PATCH 2403/4206] Do not call `TyCtxt::type_of()` on a trait --- clippy_lints/src/methods/useless_asref.rs | 4 ++-- tests/ui/useless_asref.fixed | 10 ++++++++++ tests/ui/useless_asref.rs | 10 ++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs index 17e2620d9dd47..56d2c407c054e 100644 --- a/clippy_lints/src/methods/useless_asref.rs +++ b/clippy_lints/src/methods/useless_asref.rs @@ -79,9 +79,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, applicability, ); } - } else if let Some(impl_id) = cx.tcx.opt_parent(def_id) + } else if let Some(impl_id) = cx.tcx.impl_of_method(def_id) && let Some(adt) = cx.tcx.type_of(impl_id).instantiate_identity().ty_adt_def() - && (cx.tcx.lang_items().option_type() == Some(adt.did()) || cx.tcx.is_diagnostic_item(sym::Result, adt.did())) + && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::Option | sym::Result)) { let rcv_ty = cx.typeck_results().expr_ty(recvr).peel_refs(); let res_ty = cx.typeck_results().expr_ty(expr).peel_refs(); diff --git a/tests/ui/useless_asref.fixed b/tests/ui/useless_asref.fixed index 8c1f948fb5806..3c3ea5a736d43 100644 --- a/tests/ui/useless_asref.fixed +++ b/tests/ui/useless_asref.fixed @@ -248,6 +248,16 @@ impl Issue12357 { } } +fn issue_14828() { + pub trait T { + fn as_ref(&self) {} + } + + impl T for () {} + + ().as_ref(); +} + fn main() { not_ok(); ok(); diff --git a/tests/ui/useless_asref.rs b/tests/ui/useless_asref.rs index d9db2d4f5596a..c173dd677152d 100644 --- a/tests/ui/useless_asref.rs +++ b/tests/ui/useless_asref.rs @@ -248,6 +248,16 @@ impl Issue12357 { } } +fn issue_14828() { + pub trait T { + fn as_ref(&self) {} + } + + impl T for () {} + + ().as_ref(); +} + fn main() { not_ok(); ok(); From fe0663c33d24c903812ec0fe58b94d68aa275b98 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sun, 18 May 2025 15:53:03 +0800 Subject: [PATCH 2404/4206] Add test sugg-field-in-format-string-issue-141136 Signed-off-by: xizheyin --- ...ugg-field-in-format-string-issue-141136.rs | 14 ++++++ ...field-in-format-string-issue-141136.stderr | 46 +++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.rs create mode 100644 tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.stderr diff --git a/tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.rs b/tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.rs new file mode 100644 index 0000000000000..e0c2f49604617 --- /dev/null +++ b/tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.rs @@ -0,0 +1,14 @@ +struct Foo { + x: i32 +} + +impl Foo { + fn foo(&self) { + let _ = format!("{x}"); //~ ERROR cannot find value `x` in this scope [E0425] + let _ = format!("{x }"); //~ ERROR cannot find value `x` in this scope [E0425] + let _ = format!("{ x}"); //~ ERROR invalid format string: expected `}`, found `x` + let _ = format!("{}", x); //~ ERROR cannot find value `x` in this scope [E0425] + } +} + +fn main(){} diff --git a/tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.stderr b/tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.stderr new file mode 100644 index 0000000000000..4bdefa70a0004 --- /dev/null +++ b/tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.stderr @@ -0,0 +1,46 @@ +error: invalid format string: expected `}`, found `x` + --> $DIR/sugg-field-in-format-string-issue-141136.rs:9:28 + | +LL | let _ = format!("{ x}"); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error[E0425]: cannot find value `x` in this scope + --> $DIR/sugg-field-in-format-string-issue-141136.rs:7:27 + | +LL | let _ = format!("{x}"); + | ^ + | +help: you might have meant to use the available field + | +LL | let _ = format!("{self.x}"); + | +++++ + +error[E0425]: cannot find value `x` in this scope + --> $DIR/sugg-field-in-format-string-issue-141136.rs:8:27 + | +LL | let _ = format!("{x }"); + | ^^ + | +help: you might have meant to use the available field + | +LL | let _ = format!("{self.x }"); + | +++++ + +error[E0425]: cannot find value `x` in this scope + --> $DIR/sugg-field-in-format-string-issue-141136.rs:10:31 + | +LL | let _ = format!("{}", x); + | ^ + | +help: you might have meant to use the available field + | +LL | let _ = format!("{}", self.x); + | +++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0425`. From 9de7fff0d8ab72fb57dea6255fc10fe35219db72 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sun, 18 May 2025 16:14:48 +0800 Subject: [PATCH 2405/4206] Suggest use `"{}", self.x` instead of `{self.x}` when resolve `x` as field of `self` Signed-off-by: xizheyin --- .../rustc_resolve/src/late/diagnostics.rs | 30 +++++++++++++++---- ...field-in-format-string-issue-141136.stderr | 10 ++----- ...e-with-name-similar-to-struct-field.stderr | 12 ++------ 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index b538be34f31f1..30c2125d0b66a 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -751,12 +751,30 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { match candidate { AssocSuggestion::Field(field_span) => { if self_is_available { - err.span_suggestion_verbose( - span.shrink_to_lo(), - "you might have meant to use the available field", - format!("{pre}self."), - Applicability::MachineApplicable, - ); + let source_map = self.r.tcx.sess.source_map(); + // check if the field is used in a format string, such as `"{x}"` + let field_is_format_named_arg = + source_map.span_to_source(span, |s, start, _| { + if let Some(expanded_expr) = s.get(start - 1..start) + && expanded_expr.starts_with("{") + { + Ok(true) + } else { + Ok(false) + } + }); + if let Ok(true) = field_is_format_named_arg { + err.help( + format!("you might have meant to use the available field in a format string: `\"{{}}\", self.{}`", segment.ident.name), + ); + } else { + err.span_suggestion_verbose( + span.shrink_to_lo(), + "you might have meant to use the available field", + format!("{pre}self."), + Applicability::MachineApplicable, + ); + } } else { err.span_label(field_span, "a field by that name exists in `Self`"); } diff --git a/tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.stderr b/tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.stderr index 4bdefa70a0004..795de38d0279c 100644 --- a/tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.stderr +++ b/tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.stderr @@ -14,10 +14,7 @@ error[E0425]: cannot find value `x` in this scope LL | let _ = format!("{x}"); | ^ | -help: you might have meant to use the available field - | -LL | let _ = format!("{self.x}"); - | +++++ + = help: you might have meant to use the available field in a format string: `"{}", self.x` error[E0425]: cannot find value `x` in this scope --> $DIR/sugg-field-in-format-string-issue-141136.rs:8:27 @@ -25,10 +22,7 @@ error[E0425]: cannot find value `x` in this scope LL | let _ = format!("{x }"); | ^^ | -help: you might have meant to use the available field - | -LL | let _ = format!("{self.x }"); - | +++++ + = help: you might have meant to use the available field in a format string: `"{}", self.x` error[E0425]: cannot find value `x` in this scope --> $DIR/sugg-field-in-format-string-issue-141136.rs:10:31 diff --git a/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.stderr b/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.stderr index 5832cb69a3dd8..1ecbfee17bc70 100644 --- a/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.stderr +++ b/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.stderr @@ -20,17 +20,9 @@ error[E0425]: cannot find value `config` in this scope --> $DIR/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs:15:20 | LL | println!("{config}"); - | ^^^^^^ - | -help: you might have meant to use the available field - | -LL | println!("{self.config}"); - | +++++ -help: a local variable with a similar name exists - | -LL - println!("{config}"); -LL + println!("{cofig}"); + | ^^^^^^ help: a local variable with a similar name exists: `cofig` | + = help: you might have meant to use the available field in a format string: `"{}", self.config` error[E0425]: cannot find value `bah` in this scope --> $DIR/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs:33:9 From 1e3fc3cc4634bad24adfb9ed253851a2647d22ec Mon Sep 17 00:00:00 2001 From: Pete LeVasseur Date: Sun, 18 May 2025 17:22:11 +0900 Subject: [PATCH 2406/4206] fix minor typo: toolcahin => toolchain changelog: none --- book/src/development/basics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/development/basics.md b/book/src/development/basics.md index cdbbe76bdb08e..fc405249bcfe8 100644 --- a/book/src/development/basics.md +++ b/book/src/development/basics.md @@ -151,7 +151,7 @@ toolchain called `clippy` by default, see `cargo dev setup toolchain --help` for other options. ```terminal -cargo dev setup toolcahin +cargo dev setup toolchain ``` Now you may run `cargo +clippy clippy` in any project using the new toolchain. From de8e305ba8feae17e5bc1281647865dc3f1deadf Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 29 Apr 2025 22:43:46 +0200 Subject: [PATCH 2407/4206] a new parser generating the exact same error messages Co-authored-by: Travis Cross --- compiler/rustc_builtin_macros/src/asm.rs | 376 ++++++++++++++--------- 1 file changed, 226 insertions(+), 150 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 3afa2d3dd8eec..be6f6b601369f 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -4,7 +4,7 @@ use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{AsmMacro, token}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; -use rustc_errors::PResult; +use rustc_errors::{DiagCtxtHandle, PResult}; use rustc_expand::base::*; use rustc_index::bit_set::GrowableBitSet; use rustc_parse::exp; @@ -18,6 +18,21 @@ use {rustc_ast as ast, rustc_parse_format as parse}; use crate::errors; use crate::util::{ExprToSpannedString, expr_to_spanned_string}; +/// An argument to one of the `asm!` macros. The argument is syntactically valid, but is otherwise +/// not validated at all. +pub struct RawAsmArg { + pub kind: RawAsmArgKind, + pub span: Span, +} + +pub enum RawAsmArgKind { + Template(P), + Operand(Option, ast::InlineAsmOperand), + Options(Vec<(Symbol, ast::InlineAsmOptions, Span, Span)>), + ClobberAbi(Vec<(Symbol, Span)>), +} + +/// Validated assembly arguments, ready for macro expansion. pub struct AsmArgs { pub templates: Vec>, pub operands: Vec<(ast::InlineAsmOperand, Span)>, @@ -59,16 +74,6 @@ fn eat_operand_keyword<'a>( } } -fn parse_args<'a>( - ecx: &ExtCtxt<'a>, - sp: Span, - tts: TokenStream, - asm_macro: AsmMacro, -) -> PResult<'a, AsmArgs> { - let mut p = ecx.new_parser_from_tts(tts); - parse_asm_args(&mut p, sp, asm_macro) -} - fn parse_asm_operand<'a>( p: &mut Parser<'a>, asm_macro: AsmMacro, @@ -139,31 +144,28 @@ fn parse_asm_operand<'a>( })) } -// Primarily public for rustfmt consumption. -// Internal consumers should continue to leverage `expand_asm`/`expand__global_asm` -pub fn parse_asm_args<'a>( +// Public for rustfmt. +pub fn parse_raw_asm_args<'a>( p: &mut Parser<'a>, sp: Span, asm_macro: AsmMacro, -) -> PResult<'a, AsmArgs> { +) -> PResult<'a, Vec> { let dcx = p.dcx(); if p.token == token::Eof { return Err(dcx.create_err(errors::AsmRequiresTemplate { span: sp })); } + let mut args = Vec::new(); + let first_template = p.parse_expr()?; - let mut args = AsmArgs { - templates: vec![first_template], - operands: vec![], - named_args: Default::default(), - reg_args: Default::default(), - clobber_abis: Vec::new(), - options: ast::InlineAsmOptions::empty(), - options_spans: vec![], - }; + args.push(RawAsmArg { + span: first_template.span, + kind: RawAsmArgKind::Template(first_template), + }); let mut allow_templates = true; + while p.token != token::Eof { if !p.eat(exp!(Comma)) { if allow_templates { @@ -174,27 +176,39 @@ pub fn parse_asm_args<'a>( return Err(p.expect(exp!(Comma)).err().unwrap()); } } + + // Accept trailing commas. if p.token == token::Eof { break; - } // accept trailing commas + } + + let span_start = p.token.span; - // Parse clobber_abi + // Parse `clobber_abi`. if p.eat_keyword(exp!(ClobberAbi)) { - parse_clobber_abi(p, &mut args)?; allow_templates = false; + + args.push(RawAsmArg { + kind: RawAsmArgKind::ClobberAbi(parse_clobber_abi(p)?), + span: span_start.to(p.prev_token.span), + }); + continue; } - // Parse options + // Parse `options`. if p.eat_keyword(exp!(Options)) { - parse_options(p, &mut args, asm_macro)?; allow_templates = false; + + args.push(RawAsmArg { + kind: RawAsmArgKind::Options(parse_options(p, asm_macro)?), + span: span_start.to(p.prev_token.span), + }); + continue; } - let span_start = p.token.span; - - // Parse operand names + // Parse operand names. let name = if p.token.is_ident() && p.look_ahead(1, |t| *t == token::Eq) { let (ident, _) = p.token.ident().unwrap(); p.bump(); @@ -205,60 +219,172 @@ pub fn parse_asm_args<'a>( None }; - let Some(op) = parse_asm_operand(p, asm_macro)? else { - if allow_templates { - let template = p.parse_expr()?; - // If it can't possibly expand to a string, provide diagnostics here to include other - // things it could have been. - match template.kind { - ast::ExprKind::Lit(token_lit) - if matches!( - token_lit.kind, - token::LitKind::Str | token::LitKind::StrRaw(_) - ) => {} - ast::ExprKind::MacCall(..) => {} - _ => { - let err = dcx.create_err(errors::AsmExpectedOther { - span: template.span, - is_inline_asm: matches!(asm_macro, AsmMacro::Asm), - }); - return Err(err); + if let Some(op) = parse_asm_operand(p, asm_macro)? { + allow_templates = false; + + args.push(RawAsmArg { + span: span_start.to(p.prev_token.span), + kind: RawAsmArgKind::Operand(name, op), + }); + } else if allow_templates { + let template = p.parse_expr()?; + // If it can't possibly expand to a string, provide diagnostics here to include other + // things it could have been. + match template.kind { + ast::ExprKind::Lit(token_lit) + if matches!( + token_lit.kind, + token::LitKind::Str | token::LitKind::StrRaw(_) + ) => {} + ast::ExprKind::MacCall(..) => {} + _ => { + let err = dcx.create_err(errors::AsmExpectedOther { + span: template.span, + is_inline_asm: matches!(asm_macro, AsmMacro::Asm), + }); + return Err(err); + } + } + + args.push(RawAsmArg { span: template.span, kind: RawAsmArgKind::Template(template) }); + } else { + p.unexpected_any()? + } + } + + Ok(args) +} + +fn parse_args<'a>( + ecx: &ExtCtxt<'a>, + sp: Span, + tts: TokenStream, + asm_macro: AsmMacro, +) -> PResult<'a, AsmArgs> { + let mut p = ecx.new_parser_from_tts(tts); + parse_asm_args(&mut p, sp, asm_macro) +} + +// public for use in rustfmt +// FIXME: use `RawAsmArg` in the formatting code instead. +pub fn parse_asm_args<'a>( + p: &mut Parser<'a>, + sp: Span, + asm_macro: AsmMacro, +) -> PResult<'a, AsmArgs> { + let raw_args = parse_raw_asm_args(p, sp, asm_macro)?; + validate_raw_asm_args(p.dcx(), asm_macro, raw_args) +} + +pub fn validate_raw_asm_args<'a>( + dcx: DiagCtxtHandle<'a>, + asm_macro: AsmMacro, + raw_args: Vec, +) -> PResult<'a, AsmArgs> { + let mut args = AsmArgs { + templates: vec![], + operands: vec![], + named_args: Default::default(), + reg_args: Default::default(), + clobber_abis: Vec::new(), + options: ast::InlineAsmOptions::empty(), + options_spans: vec![], + }; + + let mut allow_templates = true; + + for arg in raw_args { + match arg.kind { + RawAsmArgKind::Template(template) => { + // The error for the first template is delayed. + if !allow_templates { + match template.kind { + ast::ExprKind::Lit(token_lit) + if matches!( + token_lit.kind, + token::LitKind::Str | token::LitKind::StrRaw(_) + ) => {} + ast::ExprKind::MacCall(..) => {} + _ => { + let err = dcx.create_err(errors::AsmExpectedOther { + span: template.span, + is_inline_asm: matches!(asm_macro, AsmMacro::Asm), + }); + return Err(err); + } } } + args.templates.push(template); - continue; - } else { - p.unexpected_any()? } - }; + RawAsmArgKind::Operand(name, op) => { + allow_templates = false; - let explicit_reg = matches!(op.reg(), Some(ast::InlineAsmRegOrRegClass::Reg(_))); + let explicit_reg = matches!(op.reg(), Some(ast::InlineAsmRegOrRegClass::Reg(_))); + let span = arg.span; + let slot = args.operands.len(); + args.operands.push((op, span)); - allow_templates = false; - let span = span_start.to(p.prev_token.span); - let slot = args.operands.len(); - args.operands.push((op, span)); + // Validate the order of named, positional & explicit register operands and + // clobber_abi/options. We do this at the end once we have the full span + // of the argument available. - // Validate the order of named, positional & explicit register operands and - // clobber_abi/options. We do this at the end once we have the full span - // of the argument available. + if explicit_reg { + if name.is_some() { + dcx.emit_err(errors::AsmExplicitRegisterName { span }); + } + args.reg_args.insert(slot); + } else if let Some(name) = name { + if let Some(&prev) = args.named_args.get(&name) { + dcx.emit_err(errors::AsmDuplicateArg { + span, + name, + prev: args.operands[prev].1, + }); + continue; + } + args.named_args.insert(name, slot); + } else if !args.named_args.is_empty() || !args.reg_args.is_empty() { + let named = args.named_args.values().map(|p| args.operands[*p].1).collect(); + let explicit = args.reg_args.iter().map(|p| args.operands[p].1).collect(); - if explicit_reg { - if name.is_some() { - dcx.emit_err(errors::AsmExplicitRegisterName { span }); - } - args.reg_args.insert(slot); - } else if let Some(name) = name { - if let Some(&prev) = args.named_args.get(&name) { - dcx.emit_err(errors::AsmDuplicateArg { span, name, prev: args.operands[prev].1 }); - continue; + dcx.emit_err(errors::AsmPositionalAfter { span, named, explicit }); + } } - args.named_args.insert(name, slot); - } else if !args.named_args.is_empty() || !args.reg_args.is_empty() { - let named = args.named_args.values().map(|p| args.operands[*p].1).collect(); - let explicit = args.reg_args.iter().map(|p| args.operands[p].1).collect(); + RawAsmArgKind::Options(new_options) => { + allow_templates = false; + + for (symbol, option, span, full_span) in new_options { + if !asm_macro.is_supported_option(option) { + /* + // Tool-only output + p.dcx().emit_err(errors::AsmUnsupportedOption { + span, + symbol, + full_span, + macro_name: asm_macro.macro_name(), + }); + */ + } else if args.options.contains(option) { + // Tool-only output. + dcx.emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span }); + } else { + args.options |= option; + } + } - dcx.emit_err(errors::AsmPositionalAfter { span, named, explicit }); + args.options_spans.push(arg.span); + } + RawAsmArgKind::ClobberAbi(new_abis) => { + allow_templates = false; + + match &new_abis[..] { + // This should have errored above during parsing. + [] => unreachable!(), + [(abi, _span)] => args.clobber_abis.push((*abi, arg.span)), + _ => args.clobber_abis.extend(new_abis), + } + } } } @@ -348,61 +474,14 @@ pub fn parse_asm_args<'a>( Ok(args) } -/// Report a duplicate option error. -/// -/// This function must be called immediately after the option token is parsed. -/// Otherwise, the suggestion will be incorrect. -fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) { - // Tool-only output - let full_span = if p.token == token::Comma { span.to(p.token.span) } else { span }; - p.dcx().emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span }); -} - -/// Report an invalid option error. -/// -/// This function must be called immediately after the option token is parsed. -/// Otherwise, the suggestion will be incorrect. -fn err_unsupported_option(p: &Parser<'_>, asm_macro: AsmMacro, symbol: Symbol, span: Span) { - // Tool-only output - let full_span = if p.token == token::Comma { span.to(p.token.span) } else { span }; - p.dcx().emit_err(errors::AsmUnsupportedOption { - span, - symbol, - full_span, - macro_name: asm_macro.macro_name(), - }); -} - -/// Try to set the provided option in the provided `AsmArgs`. -/// If it is already set, report a duplicate option error. -/// -/// This function must be called immediately after the option token is parsed. -/// Otherwise, the error will not point to the correct spot. -fn try_set_option<'a>( - p: &Parser<'a>, - args: &mut AsmArgs, - asm_macro: AsmMacro, - symbol: Symbol, - option: ast::InlineAsmOptions, -) { - if !asm_macro.is_supported_option(option) { - err_unsupported_option(p, asm_macro, symbol, p.prev_token.span); - } else if args.options.contains(option) { - err_duplicate_option(p, symbol, p.prev_token.span); - } else { - args.options |= option; - } -} - fn parse_options<'a>( p: &mut Parser<'a>, - args: &mut AsmArgs, asm_macro: AsmMacro, -) -> PResult<'a, ()> { - let span_start = p.prev_token.span; - +) -> PResult<'a, Vec<(Symbol, ast::InlineAsmOptions, Span, Span)>> { p.expect(exp!(OpenParen))?; + let mut options = Vec::new(); + while !p.eat(exp!(CloseParen)) { const OPTIONS: [(ExpKeywordPair, ast::InlineAsmOptions); ast::InlineAsmOptions::COUNT] = [ (exp!(Pure), ast::InlineAsmOptions::PURE), @@ -418,6 +497,7 @@ fn parse_options<'a>( 'blk: { for (exp, option) in OPTIONS { + // Gives a more accurate list of expected next tokens. let kw_matched = if asm_macro.is_supported_option(option) { p.eat_keyword(exp) } else { @@ -425,30 +505,39 @@ fn parse_options<'a>( }; if kw_matched { - try_set_option(p, args, asm_macro, exp.kw, option); + let span = p.prev_token.span; + let full_span = + if p.token == token::Comma { span.to(p.token.span) } else { span }; + + if !asm_macro.is_supported_option(option) { + // Tool-only output. + p.dcx().emit_err(errors::AsmUnsupportedOption { + span, + symbol: exp.kw, + full_span, + macro_name: asm_macro.macro_name(), + }); + } + + options.push((exp.kw, option, span, full_span)); break 'blk; } } - return p.unexpected(); + return p.unexpected_any(); } - // Allow trailing commas + // Allow trailing commas. if p.eat(exp!(CloseParen)) { break; } p.expect(exp!(Comma))?; } - let new_span = span_start.to(p.prev_token.span); - args.options_spans.push(new_span); - - Ok(()) + Ok(options) } -fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a, ()> { - let span_start = p.prev_token.span; - +fn parse_clobber_abi<'a>(p: &mut Parser<'a>) -> PResult<'a, Vec<(Symbol, Span)>> { p.expect(exp!(OpenParen))?; if p.eat(exp!(CloseParen)) { @@ -474,20 +563,7 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a, p.expect(exp!(Comma))?; } - let full_span = span_start.to(p.prev_token.span); - - match &new_abis[..] { - // should have errored above during parsing - [] => unreachable!(), - [(abi, _span)] => args.clobber_abis.push((*abi, full_span)), - abis => { - for (abi, span) in abis { - args.clobber_abis.push((*abi, *span)); - } - } - } - - Ok(()) + Ok(new_abis) } fn parse_reg<'a>(p: &mut Parser<'a>) -> PResult<'a, ast::InlineAsmRegOrRegClass> { From 7ec06fc3b14933b1937f11ee028e2e8f245e7857 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 30 Apr 2025 01:06:38 +0200 Subject: [PATCH 2408/4206] attempt to have rustfmt use the new logic apparently it doesn't really use the asm parsing at present, so this may work? --- compiler/rustc_builtin_macros/src/asm.rs | 25 ++++++++--------------- src/tools/rustfmt/src/parse/macros/asm.rs | 9 +++++--- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index be6f6b601369f..8298b77f7b1cf 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -4,7 +4,7 @@ use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{AsmMacro, token}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; -use rustc_errors::{DiagCtxtHandle, PResult}; +use rustc_errors::PResult; use rustc_expand::base::*; use rustc_index::bit_set::GrowableBitSet; use rustc_parse::exp; @@ -33,7 +33,7 @@ pub enum RawAsmArgKind { } /// Validated assembly arguments, ready for macro expansion. -pub struct AsmArgs { +struct AsmArgs { pub templates: Vec>, pub operands: Vec<(ast::InlineAsmOperand, Span)>, named_args: FxIndexMap, @@ -261,26 +261,17 @@ fn parse_args<'a>( tts: TokenStream, asm_macro: AsmMacro, ) -> PResult<'a, AsmArgs> { - let mut p = ecx.new_parser_from_tts(tts); - parse_asm_args(&mut p, sp, asm_macro) + let raw_args = parse_raw_asm_args(&mut ecx.new_parser_from_tts(tts), sp, asm_macro)?; + validate_raw_asm_args(ecx, asm_macro, raw_args) } -// public for use in rustfmt -// FIXME: use `RawAsmArg` in the formatting code instead. -pub fn parse_asm_args<'a>( - p: &mut Parser<'a>, - sp: Span, - asm_macro: AsmMacro, -) -> PResult<'a, AsmArgs> { - let raw_args = parse_raw_asm_args(p, sp, asm_macro)?; - validate_raw_asm_args(p.dcx(), asm_macro, raw_args) -} - -pub fn validate_raw_asm_args<'a>( - dcx: DiagCtxtHandle<'a>, +fn validate_raw_asm_args<'a>( + ecx: &ExtCtxt<'a>, asm_macro: AsmMacro, raw_args: Vec, ) -> PResult<'a, AsmArgs> { + let dcx = ecx.dcx(); + let mut args = AsmArgs { templates: vec![], operands: vec![], diff --git a/src/tools/rustfmt/src/parse/macros/asm.rs b/src/tools/rustfmt/src/parse/macros/asm.rs index 58c8d21bd7a4c..18e3386f4f10c 100644 --- a/src/tools/rustfmt/src/parse/macros/asm.rs +++ b/src/tools/rustfmt/src/parse/macros/asm.rs @@ -1,11 +1,14 @@ use rustc_ast::ast; -use rustc_builtin_macros::asm::{AsmArgs, parse_asm_args}; +use rustc_builtin_macros::asm::{RawAsmArg, parse_raw_asm_args}; use crate::rewrite::RewriteContext; #[allow(dead_code)] -pub(crate) fn parse_asm(context: &RewriteContext<'_>, mac: &ast::MacCall) -> Option { +pub(crate) fn parse_asm( + context: &RewriteContext<'_>, + mac: &ast::MacCall, +) -> Option> { let ts = mac.args.tokens.clone(); let mut parser = super::build_parser(context, ts); - parse_asm_args(&mut parser, mac.span(), ast::AsmMacro::Asm).ok() + parse_raw_asm_args(&mut parser, mac.span(), ast::AsmMacro::Asm).ok() } From e12d6757393035aa2de55d0f1712ef7656c60589 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 29 Apr 2025 23:39:10 +0200 Subject: [PATCH 2409/4206] delay error for unsupported options --- compiler/rustc_builtin_macros/src/asm.rs | 16 +------ tests/ui/asm/aarch64/parse-error.rs | 2 - tests/ui/asm/aarch64/parse-error.stderr | 40 ++++++------------ tests/ui/asm/parse-error.rs | 6 +-- tests/ui/asm/parse-error.stderr | 54 +++++++++--------------- 5 files changed, 39 insertions(+), 79 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 8298b77f7b1cf..d9412a3cb423a 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -347,15 +347,13 @@ fn validate_raw_asm_args<'a>( for (symbol, option, span, full_span) in new_options { if !asm_macro.is_supported_option(option) { - /* - // Tool-only output - p.dcx().emit_err(errors::AsmUnsupportedOption { + // Tool-only output. + dcx.emit_err(errors::AsmUnsupportedOption { span, symbol, full_span, macro_name: asm_macro.macro_name(), }); - */ } else if args.options.contains(option) { // Tool-only output. dcx.emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span }); @@ -500,16 +498,6 @@ fn parse_options<'a>( let full_span = if p.token == token::Comma { span.to(p.token.span) } else { span }; - if !asm_macro.is_supported_option(option) { - // Tool-only output. - p.dcx().emit_err(errors::AsmUnsupportedOption { - span, - symbol: exp.kw, - full_span, - macro_name: asm_macro.macro_name(), - }); - } - options.push((exp.kw, option, span, full_span)); break 'blk; } diff --git a/tests/ui/asm/aarch64/parse-error.rs b/tests/ui/asm/aarch64/parse-error.rs index aa731c35dda88..35e1d037f3888 100644 --- a/tests/ui/asm/aarch64/parse-error.rs +++ b/tests/ui/asm/aarch64/parse-error.rs @@ -96,10 +96,8 @@ global_asm!("", options(FOO)); //~^ ERROR expected one of global_asm!("", options(nomem FOO)); //~^ ERROR expected one of -//~| ERROR the `nomem` option cannot be used with `global_asm!` global_asm!("", options(nomem, FOO)); //~^ ERROR expected one of -//~| ERROR the `nomem` option cannot be used with `global_asm!` global_asm!("{}", options(), const FOO); global_asm!("", clobber_abi(FOO)); //~^ ERROR expected string literal diff --git a/tests/ui/asm/aarch64/parse-error.stderr b/tests/ui/asm/aarch64/parse-error.stderr index b5e1169e5f6b4..45f9e7989c2e8 100644 --- a/tests/ui/asm/aarch64/parse-error.stderr +++ b/tests/ui/asm/aarch64/parse-error.stderr @@ -218,68 +218,56 @@ error: expected one of `)`, `att_syntax`, or `raw`, found `FOO` LL | global_asm!("", options(FOO)); | ^^^ expected one of `)`, `att_syntax`, or `raw` -error: the `nomem` option cannot be used with `global_asm!` - --> $DIR/parse-error.rs:97:25 - | -LL | global_asm!("", options(nomem FOO)); - | ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly - error: expected one of `)` or `,`, found `FOO` --> $DIR/parse-error.rs:97:31 | LL | global_asm!("", options(nomem FOO)); | ^^^ expected one of `)` or `,` -error: the `nomem` option cannot be used with `global_asm!` - --> $DIR/parse-error.rs:100:25 - | -LL | global_asm!("", options(nomem, FOO)); - | ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly - error: expected one of `)`, `att_syntax`, or `raw`, found `FOO` - --> $DIR/parse-error.rs:100:32 + --> $DIR/parse-error.rs:99:32 | LL | global_asm!("", options(nomem, FOO)); | ^^^ expected one of `)`, `att_syntax`, or `raw` error: expected string literal - --> $DIR/parse-error.rs:104:29 + --> $DIR/parse-error.rs:102:29 | LL | global_asm!("", clobber_abi(FOO)); | ^^^ not a string literal error: expected one of `)` or `,`, found `FOO` - --> $DIR/parse-error.rs:106:33 + --> $DIR/parse-error.rs:104:33 | LL | global_asm!("", clobber_abi("C" FOO)); | ^^^ expected one of `)` or `,` error: expected string literal - --> $DIR/parse-error.rs:108:34 + --> $DIR/parse-error.rs:106:34 | LL | global_asm!("", clobber_abi("C", FOO)); | ^^^ not a string literal error: `clobber_abi` cannot be used with `global_asm!` - --> $DIR/parse-error.rs:110:19 + --> $DIR/parse-error.rs:108:19 | LL | global_asm!("{}", clobber_abi("C"), const FOO); | ^^^^^^^^^^^^^^^^ error: `clobber_abi` cannot be used with `global_asm!` - --> $DIR/parse-error.rs:112:28 + --> $DIR/parse-error.rs:110:28 | LL | global_asm!("", options(), clobber_abi("C")); | ^^^^^^^^^^^^^^^^ error: `clobber_abi` cannot be used with `global_asm!` - --> $DIR/parse-error.rs:114:30 + --> $DIR/parse-error.rs:112:30 | LL | global_asm!("{}", options(), clobber_abi("C"), const FOO); | ^^^^^^^^^^^^^^^^ error: duplicate argument named `a` - --> $DIR/parse-error.rs:116:35 + --> $DIR/parse-error.rs:114:35 | LL | global_asm!("{a}", a = const FOO, a = const BAR); | ------------- ^^^^^^^^^^^^^ duplicate argument @@ -287,7 +275,7 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR); | previously here error: argument never used - --> $DIR/parse-error.rs:116:35 + --> $DIR/parse-error.rs:114:35 | LL | global_asm!("{a}", a = const FOO, a = const BAR); | ^^^^^^^^^^^^^ argument never used @@ -295,19 +283,19 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `""` - --> $DIR/parse-error.rs:119:28 + --> $DIR/parse-error.rs:117:28 | LL | global_asm!("", options(), ""); | ^^ expected one of `clobber_abi`, `const`, `options`, or `sym` error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `"{}"` - --> $DIR/parse-error.rs:121:30 + --> $DIR/parse-error.rs:119:30 | LL | global_asm!("{}", const FOO, "{}", const FOO); | ^^^^ expected one of `clobber_abi`, `const`, `options`, or `sym` error: asm template must be a string literal - --> $DIR/parse-error.rs:123:13 + --> $DIR/parse-error.rs:121:13 | LL | global_asm!(format!("{{{}}}", 0), const FOO); | ^^^^^^^^^^^^^^^^^^^^ @@ -315,7 +303,7 @@ LL | global_asm!(format!("{{{}}}", 0), const FOO); = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error: asm template must be a string literal - --> $DIR/parse-error.rs:125:20 + --> $DIR/parse-error.rs:123:20 | LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); | ^^^^^^^^^^^^^^^^^^^^ @@ -418,6 +406,6 @@ LL - let mut bar = 0; LL + const bar: /* Type */ = 0; | -error: aborting due to 59 previous errors +error: aborting due to 57 previous errors For more information about this error, try `rustc --explain E0435`. diff --git a/tests/ui/asm/parse-error.rs b/tests/ui/asm/parse-error.rs index 4d7b522f5fc5b..d135ccae12804 100644 --- a/tests/ui/asm/parse-error.rs +++ b/tests/ui/asm/parse-error.rs @@ -113,11 +113,9 @@ global_asm!("", options(FOO)); global_asm!("", options(FOO,)); //~^ ERROR expected one of `)`, `att_syntax`, or `raw`, found `FOO` global_asm!("", options(nomem FOO)); -//~^ ERROR the `nomem` option cannot be used with `global_asm!` -//~| ERROR expected one of `)` or `,`, found `FOO` +//~^ ERROR expected one of `)` or `,`, found `FOO` global_asm!("", options(nomem, FOO)); -//~^ ERROR the `nomem` option cannot be used with `global_asm!` -//~| ERROR expected one of `)`, `att_syntax`, or `raw`, found `FOO` +//~^ ERROR expected one of `)`, `att_syntax`, or `raw`, found `FOO` global_asm!("{}", options(), const FOO); global_asm!("", clobber_abi(FOO)); //~^ ERROR expected string literal diff --git a/tests/ui/asm/parse-error.stderr b/tests/ui/asm/parse-error.stderr index 74647372a3557..0bba1fd8d9b64 100644 --- a/tests/ui/asm/parse-error.stderr +++ b/tests/ui/asm/parse-error.stderr @@ -270,74 +270,62 @@ error: expected one of `)`, `att_syntax`, or `raw`, found `FOO` LL | global_asm!("", options(FOO,)); | ^^^ expected one of `)`, `att_syntax`, or `raw` -error: the `nomem` option cannot be used with `global_asm!` - --> $DIR/parse-error.rs:115:25 - | -LL | global_asm!("", options(nomem FOO)); - | ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly - error: expected one of `)` or `,`, found `FOO` --> $DIR/parse-error.rs:115:31 | LL | global_asm!("", options(nomem FOO)); | ^^^ expected one of `)` or `,` -error: the `nomem` option cannot be used with `global_asm!` - --> $DIR/parse-error.rs:118:25 - | -LL | global_asm!("", options(nomem, FOO)); - | ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly - error: expected one of `)`, `att_syntax`, or `raw`, found `FOO` - --> $DIR/parse-error.rs:118:32 + --> $DIR/parse-error.rs:117:32 | LL | global_asm!("", options(nomem, FOO)); | ^^^ expected one of `)`, `att_syntax`, or `raw` error: expected string literal - --> $DIR/parse-error.rs:122:29 + --> $DIR/parse-error.rs:120:29 | LL | global_asm!("", clobber_abi(FOO)); | ^^^ not a string literal error: expected one of `)` or `,`, found `FOO` - --> $DIR/parse-error.rs:124:33 + --> $DIR/parse-error.rs:122:33 | LL | global_asm!("", clobber_abi("C" FOO)); | ^^^ expected one of `)` or `,` error: expected string literal - --> $DIR/parse-error.rs:126:34 + --> $DIR/parse-error.rs:124:34 | LL | global_asm!("", clobber_abi("C", FOO)); | ^^^ not a string literal error: `clobber_abi` cannot be used with `global_asm!` - --> $DIR/parse-error.rs:128:19 + --> $DIR/parse-error.rs:126:19 | LL | global_asm!("{}", clobber_abi("C"), const FOO); | ^^^^^^^^^^^^^^^^ error: `clobber_abi` cannot be used with `global_asm!` - --> $DIR/parse-error.rs:130:28 + --> $DIR/parse-error.rs:128:28 | LL | global_asm!("", options(), clobber_abi("C")); | ^^^^^^^^^^^^^^^^ error: `clobber_abi` cannot be used with `global_asm!` - --> $DIR/parse-error.rs:132:30 + --> $DIR/parse-error.rs:130:30 | LL | global_asm!("{}", options(), clobber_abi("C"), const FOO); | ^^^^^^^^^^^^^^^^ error: `clobber_abi` cannot be used with `global_asm!` - --> $DIR/parse-error.rs:134:17 + --> $DIR/parse-error.rs:132:17 | LL | global_asm!("", clobber_abi("C"), clobber_abi("C")); | ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ error: duplicate argument named `a` - --> $DIR/parse-error.rs:136:35 + --> $DIR/parse-error.rs:134:35 | LL | global_asm!("{a}", a = const FOO, a = const BAR); | ------------- ^^^^^^^^^^^^^ duplicate argument @@ -345,7 +333,7 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR); | previously here error: argument never used - --> $DIR/parse-error.rs:136:35 + --> $DIR/parse-error.rs:134:35 | LL | global_asm!("{a}", a = const FOO, a = const BAR); | ^^^^^^^^^^^^^ argument never used @@ -353,19 +341,19 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `""` - --> $DIR/parse-error.rs:139:28 + --> $DIR/parse-error.rs:137:28 | LL | global_asm!("", options(), ""); | ^^ expected one of `clobber_abi`, `const`, `options`, or `sym` error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `"{}"` - --> $DIR/parse-error.rs:141:30 + --> $DIR/parse-error.rs:139:30 | LL | global_asm!("{}", const FOO, "{}", const FOO); | ^^^^ expected one of `clobber_abi`, `const`, `options`, or `sym` error: asm template must be a string literal - --> $DIR/parse-error.rs:143:13 + --> $DIR/parse-error.rs:141:13 | LL | global_asm!(format!("{{{}}}", 0), const FOO); | ^^^^^^^^^^^^^^^^^^^^ @@ -373,7 +361,7 @@ LL | global_asm!(format!("{{{}}}", 0), const FOO); = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error: asm template must be a string literal - --> $DIR/parse-error.rs:145:20 + --> $DIR/parse-error.rs:143:20 | LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); | ^^^^^^^^^^^^^^^^^^^^ @@ -381,37 +369,37 @@ LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error: the `in` operand cannot be used with `global_asm!` - --> $DIR/parse-error.rs:148:19 + --> $DIR/parse-error.rs:146:19 | LL | global_asm!("{}", in(reg)); | ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it error: the `out` operand cannot be used with `global_asm!` - --> $DIR/parse-error.rs:150:19 + --> $DIR/parse-error.rs:148:19 | LL | global_asm!("{}", out(reg)); | ^^^ the `out` operand is not meaningful for global-scoped inline assembly, remove it error: the `lateout` operand cannot be used with `global_asm!` - --> $DIR/parse-error.rs:152:19 + --> $DIR/parse-error.rs:150:19 | LL | global_asm!("{}", lateout(reg)); | ^^^^^^^ the `lateout` operand is not meaningful for global-scoped inline assembly, remove it error: the `inout` operand cannot be used with `global_asm!` - --> $DIR/parse-error.rs:154:19 + --> $DIR/parse-error.rs:152:19 | LL | global_asm!("{}", inout(reg)); | ^^^^^ the `inout` operand is not meaningful for global-scoped inline assembly, remove it error: the `inlateout` operand cannot be used with `global_asm!` - --> $DIR/parse-error.rs:156:19 + --> $DIR/parse-error.rs:154:19 | LL | global_asm!("{}", inlateout(reg)); | ^^^^^^^^^ the `inlateout` operand is not meaningful for global-scoped inline assembly, remove it error: the `label` operand cannot be used with `global_asm!` - --> $DIR/parse-error.rs:158:19 + --> $DIR/parse-error.rs:156:19 | LL | global_asm!("{}", label(reg)); | ^^^^^ the `label` operand is not meaningful for global-scoped inline assembly, remove it @@ -476,6 +464,6 @@ LL - let mut bar = 0; LL + const bar: /* Type */ = 0; | -error: aborting due to 72 previous errors +error: aborting due to 70 previous errors For more information about this error, try `rustc --explain E0435`. From 85053d1cd1e65466e6ceae2a925d7d010d7585ea Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 17 May 2025 23:17:06 +0200 Subject: [PATCH 2410/4206] rename to get rid of the 'raw' concept --- compiler/rustc_builtin_macros/src/asm.rs | 127 +++++++++++----------- src/tools/rustfmt/src/parse/macros/asm.rs | 9 +- 2 files changed, 67 insertions(+), 69 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index d9412a3cb423a..867a5b80f918f 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -20,12 +20,12 @@ use crate::util::{ExprToSpannedString, expr_to_spanned_string}; /// An argument to one of the `asm!` macros. The argument is syntactically valid, but is otherwise /// not validated at all. -pub struct RawAsmArg { - pub kind: RawAsmArgKind, +pub struct AsmArg { + pub kind: AsmArgKind, pub span: Span, } -pub enum RawAsmArgKind { +pub enum AsmArgKind { Template(P), Operand(Option, ast::InlineAsmOperand), Options(Vec<(Symbol, ast::InlineAsmOptions, Span, Span)>), @@ -33,7 +33,7 @@ pub enum RawAsmArgKind { } /// Validated assembly arguments, ready for macro expansion. -struct AsmArgs { +struct ValidatedAsmArgs { pub templates: Vec>, pub operands: Vec<(ast::InlineAsmOperand, Span)>, named_args: FxIndexMap, @@ -145,11 +145,11 @@ fn parse_asm_operand<'a>( } // Public for rustfmt. -pub fn parse_raw_asm_args<'a>( +pub fn parse_asm_args<'a>( p: &mut Parser<'a>, sp: Span, asm_macro: AsmMacro, -) -> PResult<'a, Vec> { +) -> PResult<'a, Vec> { let dcx = p.dcx(); if p.token == token::Eof { @@ -159,10 +159,7 @@ pub fn parse_raw_asm_args<'a>( let mut args = Vec::new(); let first_template = p.parse_expr()?; - args.push(RawAsmArg { - span: first_template.span, - kind: RawAsmArgKind::Template(first_template), - }); + args.push(AsmArg { span: first_template.span, kind: AsmArgKind::Template(first_template) }); let mut allow_templates = true; @@ -188,8 +185,8 @@ pub fn parse_raw_asm_args<'a>( if p.eat_keyword(exp!(ClobberAbi)) { allow_templates = false; - args.push(RawAsmArg { - kind: RawAsmArgKind::ClobberAbi(parse_clobber_abi(p)?), + args.push(AsmArg { + kind: AsmArgKind::ClobberAbi(parse_clobber_abi(p)?), span: span_start.to(p.prev_token.span), }); @@ -200,8 +197,8 @@ pub fn parse_raw_asm_args<'a>( if p.eat_keyword(exp!(Options)) { allow_templates = false; - args.push(RawAsmArg { - kind: RawAsmArgKind::Options(parse_options(p, asm_macro)?), + args.push(AsmArg { + kind: AsmArgKind::Options(parse_options(p, asm_macro)?), span: span_start.to(p.prev_token.span), }); @@ -222,9 +219,9 @@ pub fn parse_raw_asm_args<'a>( if let Some(op) = parse_asm_operand(p, asm_macro)? { allow_templates = false; - args.push(RawAsmArg { + args.push(AsmArg { span: span_start.to(p.prev_token.span), - kind: RawAsmArgKind::Operand(name, op), + kind: AsmArgKind::Operand(name, op), }); } else if allow_templates { let template = p.parse_expr()?; @@ -246,7 +243,7 @@ pub fn parse_raw_asm_args<'a>( } } - args.push(RawAsmArg { span: template.span, kind: RawAsmArgKind::Template(template) }); + args.push(AsmArg { span: template.span, kind: AsmArgKind::Template(template) }); } else { p.unexpected_any()? } @@ -260,19 +257,19 @@ fn parse_args<'a>( sp: Span, tts: TokenStream, asm_macro: AsmMacro, -) -> PResult<'a, AsmArgs> { - let raw_args = parse_raw_asm_args(&mut ecx.new_parser_from_tts(tts), sp, asm_macro)?; - validate_raw_asm_args(ecx, asm_macro, raw_args) +) -> PResult<'a, ValidatedAsmArgs> { + let args = parse_asm_args(&mut ecx.new_parser_from_tts(tts), sp, asm_macro)?; + validate_asm_args(ecx, asm_macro, args) } -fn validate_raw_asm_args<'a>( +fn validate_asm_args<'a>( ecx: &ExtCtxt<'a>, asm_macro: AsmMacro, - raw_args: Vec, -) -> PResult<'a, AsmArgs> { + args: Vec, +) -> PResult<'a, ValidatedAsmArgs> { let dcx = ecx.dcx(); - let mut args = AsmArgs { + let mut validated = ValidatedAsmArgs { templates: vec![], operands: vec![], named_args: Default::default(), @@ -284,9 +281,9 @@ fn validate_raw_asm_args<'a>( let mut allow_templates = true; - for arg in raw_args { + for arg in args { match arg.kind { - RawAsmArgKind::Template(template) => { + AsmArgKind::Template(template) => { // The error for the first template is delayed. if !allow_templates { match template.kind { @@ -306,15 +303,15 @@ fn validate_raw_asm_args<'a>( } } - args.templates.push(template); + validated.templates.push(template); } - RawAsmArgKind::Operand(name, op) => { + AsmArgKind::Operand(name, op) => { allow_templates = false; let explicit_reg = matches!(op.reg(), Some(ast::InlineAsmRegOrRegClass::Reg(_))); let span = arg.span; - let slot = args.operands.len(); - args.operands.push((op, span)); + let slot = validated.operands.len(); + validated.operands.push((op, span)); // Validate the order of named, positional & explicit register operands and // clobber_abi/options. We do this at the end once we have the full span @@ -324,25 +321,27 @@ fn validate_raw_asm_args<'a>( if name.is_some() { dcx.emit_err(errors::AsmExplicitRegisterName { span }); } - args.reg_args.insert(slot); + validated.reg_args.insert(slot); } else if let Some(name) = name { - if let Some(&prev) = args.named_args.get(&name) { + if let Some(&prev) = validated.named_args.get(&name) { dcx.emit_err(errors::AsmDuplicateArg { span, name, - prev: args.operands[prev].1, + prev: validated.operands[prev].1, }); continue; } - args.named_args.insert(name, slot); - } else if !args.named_args.is_empty() || !args.reg_args.is_empty() { - let named = args.named_args.values().map(|p| args.operands[*p].1).collect(); - let explicit = args.reg_args.iter().map(|p| args.operands[p].1).collect(); + validated.named_args.insert(name, slot); + } else if !validated.named_args.is_empty() || !validated.reg_args.is_empty() { + let named = + validated.named_args.values().map(|p| validated.operands[*p].1).collect(); + let explicit = + validated.reg_args.iter().map(|p| validated.operands[p].1).collect(); dcx.emit_err(errors::AsmPositionalAfter { span, named, explicit }); } } - RawAsmArgKind::Options(new_options) => { + AsmArgKind::Options(new_options) => { allow_templates = false; for (symbol, option, span, full_span) in new_options { @@ -354,45 +353,47 @@ fn validate_raw_asm_args<'a>( full_span, macro_name: asm_macro.macro_name(), }); - } else if args.options.contains(option) { + } else if validated.options.contains(option) { // Tool-only output. dcx.emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span }); } else { - args.options |= option; + validated.options |= option; } } - args.options_spans.push(arg.span); + validated.options_spans.push(arg.span); } - RawAsmArgKind::ClobberAbi(new_abis) => { + AsmArgKind::ClobberAbi(new_abis) => { allow_templates = false; match &new_abis[..] { // This should have errored above during parsing. [] => unreachable!(), - [(abi, _span)] => args.clobber_abis.push((*abi, arg.span)), - _ => args.clobber_abis.extend(new_abis), + [(abi, _span)] => validated.clobber_abis.push((*abi, arg.span)), + _ => validated.clobber_abis.extend(new_abis), } } } } - if args.options.contains(ast::InlineAsmOptions::NOMEM) - && args.options.contains(ast::InlineAsmOptions::READONLY) + if validated.options.contains(ast::InlineAsmOptions::NOMEM) + && validated.options.contains(ast::InlineAsmOptions::READONLY) { - let spans = args.options_spans.clone(); + let spans = validated.options_spans.clone(); dcx.emit_err(errors::AsmMutuallyExclusive { spans, opt1: "nomem", opt2: "readonly" }); } - if args.options.contains(ast::InlineAsmOptions::PURE) - && args.options.contains(ast::InlineAsmOptions::NORETURN) + if validated.options.contains(ast::InlineAsmOptions::PURE) + && validated.options.contains(ast::InlineAsmOptions::NORETURN) { - let spans = args.options_spans.clone(); + let spans = validated.options_spans.clone(); dcx.emit_err(errors::AsmMutuallyExclusive { spans, opt1: "pure", opt2: "noreturn" }); } - if args.options.contains(ast::InlineAsmOptions::PURE) - && !args.options.intersects(ast::InlineAsmOptions::NOMEM | ast::InlineAsmOptions::READONLY) + if validated.options.contains(ast::InlineAsmOptions::PURE) + && !validated + .options + .intersects(ast::InlineAsmOptions::NOMEM | ast::InlineAsmOptions::READONLY) { - let spans = args.options_spans.clone(); + let spans = validated.options_spans.clone(); dcx.emit_err(errors::AsmPureCombine { spans }); } @@ -400,7 +401,7 @@ fn validate_raw_asm_args<'a>( let mut outputs_sp = vec![]; let mut regclass_outputs = vec![]; let mut labels_sp = vec![]; - for (op, op_sp) in &args.operands { + for (op, op_sp) in &validated.operands { match op { ast::InlineAsmOperand::Out { reg, expr, .. } | ast::InlineAsmOperand::SplitInOut { reg, out_expr: expr, .. } => { @@ -423,10 +424,10 @@ fn validate_raw_asm_args<'a>( _ => {} } } - if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output { - dcx.emit_err(errors::AsmPureNoOutput { spans: args.options_spans.clone() }); + if validated.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output { + dcx.emit_err(errors::AsmPureNoOutput { spans: validated.options_spans.clone() }); } - if args.options.contains(ast::InlineAsmOptions::NORETURN) + if validated.options.contains(ast::InlineAsmOptions::NORETURN) && !outputs_sp.is_empty() && labels_sp.is_empty() { @@ -434,15 +435,15 @@ fn validate_raw_asm_args<'a>( // Bail out now since this is likely to confuse MIR return Err(err); } - if args.options.contains(ast::InlineAsmOptions::MAY_UNWIND) && !labels_sp.is_empty() { + if validated.options.contains(ast::InlineAsmOptions::MAY_UNWIND) && !labels_sp.is_empty() { dcx.emit_err(errors::AsmMayUnwind { labels_sp }); } - if !args.clobber_abis.is_empty() { + if !validated.clobber_abis.is_empty() { match asm_macro { AsmMacro::GlobalAsm | AsmMacro::NakedAsm => { let err = dcx.create_err(errors::AsmUnsupportedClobberAbi { - spans: args.clobber_abis.iter().map(|(_, span)| *span).collect(), + spans: validated.clobber_abis.iter().map(|(_, span)| *span).collect(), macro_name: asm_macro.macro_name(), }); @@ -453,14 +454,14 @@ fn validate_raw_asm_args<'a>( if !regclass_outputs.is_empty() { dcx.emit_err(errors::AsmClobberNoReg { spans: regclass_outputs, - clobbers: args.clobber_abis.iter().map(|(_, span)| *span).collect(), + clobbers: validated.clobber_abis.iter().map(|(_, span)| *span).collect(), }); } } } } - Ok(args) + Ok(validated) } fn parse_options<'a>( @@ -566,7 +567,7 @@ fn parse_reg<'a>(p: &mut Parser<'a>) -> PResult<'a, ast::InlineAsmRegOrRegClass> fn expand_preparsed_asm( ecx: &mut ExtCtxt<'_>, asm_macro: AsmMacro, - args: AsmArgs, + args: ValidatedAsmArgs, ) -> ExpandResult, ()> { let mut template = vec![]; // Register operands are implicitly used since they are not allowed to be diff --git a/src/tools/rustfmt/src/parse/macros/asm.rs b/src/tools/rustfmt/src/parse/macros/asm.rs index 18e3386f4f10c..1a9614bacec89 100644 --- a/src/tools/rustfmt/src/parse/macros/asm.rs +++ b/src/tools/rustfmt/src/parse/macros/asm.rs @@ -1,14 +1,11 @@ use rustc_ast::ast; -use rustc_builtin_macros::asm::{RawAsmArg, parse_raw_asm_args}; +use rustc_builtin_macros::asm::{AsmArg, parse_asm_args}; use crate::rewrite::RewriteContext; #[allow(dead_code)] -pub(crate) fn parse_asm( - context: &RewriteContext<'_>, - mac: &ast::MacCall, -) -> Option> { +pub(crate) fn parse_asm(context: &RewriteContext<'_>, mac: &ast::MacCall) -> Option> { let ts = mac.args.tokens.clone(); let mut parser = super::build_parser(context, ts); - parse_raw_asm_args(&mut parser, mac.span(), ast::AsmMacro::Asm).ok() + parse_asm_args(&mut parser, mac.span(), ast::AsmMacro::Asm).ok() } From 26e3a5041a3d9bcba04a7b201a47b1b03ccb2b2f Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 17 May 2025 23:27:33 +0200 Subject: [PATCH 2411/4206] add `AsmOptions` with some named fields --- compiler/rustc_builtin_macros/src/asm.rs | 46 +++++++++++++-------- compiler/rustc_builtin_macros/src/errors.rs | 4 +- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 867a5b80f918f..62ee71fecc273 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -28,10 +28,19 @@ pub struct AsmArg { pub enum AsmArgKind { Template(P), Operand(Option, ast::InlineAsmOperand), - Options(Vec<(Symbol, ast::InlineAsmOptions, Span, Span)>), + Options(Vec), ClobberAbi(Vec<(Symbol, Span)>), } +pub struct AsmOption { + pub symbol: Symbol, + pub span: Span, + // A bitset, with only the bit for this option's symbol set. + pub options: ast::InlineAsmOptions, + // Used when suggesting to remove an option. + pub span_with_comma: Span, +} + /// Validated assembly arguments, ready for macro expansion. struct ValidatedAsmArgs { pub templates: Vec>, @@ -344,20 +353,26 @@ fn validate_asm_args<'a>( AsmArgKind::Options(new_options) => { allow_templates = false; - for (symbol, option, span, full_span) in new_options { - if !asm_macro.is_supported_option(option) { + for asm_option in new_options { + let AsmOption { span, symbol, span_with_comma, options } = asm_option; + + if !asm_macro.is_supported_option(options) { // Tool-only output. dcx.emit_err(errors::AsmUnsupportedOption { span, symbol, - full_span, + span_with_comma, macro_name: asm_macro.macro_name(), }); - } else if validated.options.contains(option) { + } else if validated.options.contains(options) { // Tool-only output. - dcx.emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span }); + dcx.emit_err(errors::AsmOptAlreadyprovided { + span, + symbol, + span_with_comma, + }); } else { - validated.options |= option; + validated.options |= asm_option.options; } } @@ -464,13 +479,10 @@ fn validate_asm_args<'a>( Ok(validated) } -fn parse_options<'a>( - p: &mut Parser<'a>, - asm_macro: AsmMacro, -) -> PResult<'a, Vec<(Symbol, ast::InlineAsmOptions, Span, Span)>> { +fn parse_options<'a>(p: &mut Parser<'a>, asm_macro: AsmMacro) -> PResult<'a, Vec> { p.expect(exp!(OpenParen))?; - let mut options = Vec::new(); + let mut asm_options = Vec::new(); while !p.eat(exp!(CloseParen)) { const OPTIONS: [(ExpKeywordPair, ast::InlineAsmOptions); ast::InlineAsmOptions::COUNT] = [ @@ -486,9 +498,9 @@ fn parse_options<'a>( ]; 'blk: { - for (exp, option) in OPTIONS { + for (exp, options) in OPTIONS { // Gives a more accurate list of expected next tokens. - let kw_matched = if asm_macro.is_supported_option(option) { + let kw_matched = if asm_macro.is_supported_option(options) { p.eat_keyword(exp) } else { p.eat_keyword_noexpect(exp.kw) @@ -496,10 +508,10 @@ fn parse_options<'a>( if kw_matched { let span = p.prev_token.span; - let full_span = + let span_with_comma = if p.token == token::Comma { span.to(p.token.span) } else { span }; - options.push((exp.kw, option, span, full_span)); + asm_options.push(AsmOption { symbol: exp.kw, span, options, span_with_comma }); break 'blk; } } @@ -514,7 +526,7 @@ fn parse_options<'a>( p.expect(exp!(Comma))?; } - Ok(options) + Ok(asm_options) } fn parse_clobber_abi<'a>(p: &mut Parser<'a>) -> PResult<'a, Vec<(Symbol, Span)>> { diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index d14ad8f40144c..b28f7d312d937 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -910,7 +910,7 @@ pub(crate) struct AsmOptAlreadyprovided { pub(crate) span: Span, pub(crate) symbol: Symbol, #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] - pub(crate) full_span: Span, + pub(crate) span_with_comma: Span, } #[derive(Diagnostic)] @@ -921,7 +921,7 @@ pub(crate) struct AsmUnsupportedOption { pub(crate) span: Span, pub(crate) symbol: Symbol, #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] - pub(crate) full_span: Span, + pub(crate) span_with_comma: Span, pub(crate) macro_name: &'static str, } From 6eb1afa468832f01a042cd13e7f9f018e5857df3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 May 2025 08:33:10 +0200 Subject: [PATCH 2412/4206] tools-aux ci runner: also cross-test doctests --- src/bootstrap/mk/Makefile.in | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 08a288170fa30..7e0eb473fb3fa 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -60,7 +60,8 @@ check-aux: library/alloc \ $(BOOTSTRAP_ARGS) \ --no-doc - # Some doctests use file system operations to demonstrate dealing with `Result`. + # Some doctests use file system operations to demonstrate dealing with `Result`, + # so we have to run them with isolation disabled. $(Q)MIRIFLAGS="-Zmiri-disable-isolation" \ $(BOOTSTRAP) miri --stage 2 \ library/coretests \ @@ -70,22 +71,19 @@ check-aux: --doc # In `std` we cannot test everything, so we skip some modules. $(Q)MIRIFLAGS="-Zmiri-disable-isolation" \ - $(BOOTSTRAP) miri --stage 2 library/std \ - $(BOOTSTRAP_ARGS) \ - --no-doc -- \ - --skip fs:: --skip net:: --skip process:: --skip sys::fd:: --skip sys::pal:: - $(Q)MIRIFLAGS="-Zmiri-disable-isolation" \ - $(BOOTSTRAP) miri --stage 2 library/std \ + $(BOOTSTRAP) miri --stage 2 \ + library/std \ $(BOOTSTRAP_ARGS) \ - --doc -- \ + -- \ --skip fs:: --skip net:: --skip process:: --skip sys::fd:: --skip sys::pal:: # Also test some very target-specific modules on other targets # (making sure to cover an i686 target as well). $(Q)MIRIFLAGS="-Zmiri-disable-isolation" BOOTSTRAP_SKIP_TARGET_SANITY=1 \ - $(BOOTSTRAP) miri --stage 2 library/std \ - $(BOOTSTRAP_ARGS) \ + $(BOOTSTRAP) miri --stage 2 \ + library/std \ --target aarch64-apple-darwin,i686-pc-windows-msvc \ - --no-doc -- \ + $(BOOTSTRAP_ARGS) \ + -- \ time:: sync:: thread:: env:: dist: $(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS) From abbf8fe6e7abf6b6b612bcc65f87ded71a6ce562 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 18 May 2025 10:14:22 +0200 Subject: [PATCH 2413/4206] fix an if statement that can be collapsed --- .../crates/libm-macros/src/lib.rs | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/library/compiler-builtins/crates/libm-macros/src/lib.rs b/library/compiler-builtins/crates/libm-macros/src/lib.rs index e8afe3aad5586..482da974ca89f 100644 --- a/library/compiler-builtins/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/crates/libm-macros/src/lib.rs @@ -1,3 +1,5 @@ +#![feature(let_chains)] + mod enums; mod parse; mod shared; @@ -266,27 +268,27 @@ fn validate(input: &mut StructuredInput) -> syn::Result } } - if let Some(map) = &input.fn_extra { - if !map.keys().any(|key| key == "_") { - // No default provided; make sure every expected function is covered - let mut fns_not_covered = Vec::new(); - for func in &fn_list { - if !map.keys().any(|key| key == func.name) { - // `name` was not mentioned in the `match` statement - fns_not_covered.push(func); - } + if let Some(map) = &input.fn_extra + && !map.keys().any(|key| key == "_") + { + // No default provided; make sure every expected function is covered + let mut fns_not_covered = Vec::new(); + for func in &fn_list { + if !map.keys().any(|key| key == func.name) { + // `name` was not mentioned in the `match` statement + fns_not_covered.push(func); } + } - if !fns_not_covered.is_empty() { - let e = syn::Error::new( - input.fn_extra_span.unwrap(), - format!( - "`fn_extra`: no default `_` pattern specified and the following \ - patterns are not covered: {fns_not_covered:#?}" - ), - ); - return Err(e); - } + if !fns_not_covered.is_empty() { + let e = syn::Error::new( + input.fn_extra_span.unwrap(), + format!( + "`fn_extra`: no default `_` pattern specified and the following \ + patterns are not covered: {fns_not_covered:#?}" + ), + ); + return Err(e); } }; From c2792b29c323c5785ab671fe92f6dafb330ed30c Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Sun, 18 May 2025 12:12:20 +0200 Subject: [PATCH 2414/4206] ci: split dist-arm-linux job --- .../dist-arm-linux-gnueabi/Dockerfile | 35 +++++++++++++++++++ .../arm-linux-gnueabi.defconfig | 0 .../Dockerfile | 10 ++---- .../arm-linux-musl.defconfig | 13 +++++++ src/ci/github-actions/jobs.yml | 7 ++-- 5 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 src/ci/docker/host-x86_64/dist-arm-linux-gnueabi/Dockerfile rename src/ci/docker/host-x86_64/{dist-arm-linux => dist-arm-linux-gnueabi}/arm-linux-gnueabi.defconfig (100%) rename src/ci/docker/host-x86_64/{dist-arm-linux => dist-arm-linux-musl}/Dockerfile (73%) create mode 100644 src/ci/docker/host-x86_64/dist-arm-linux-musl/arm-linux-musl.defconfig diff --git a/src/ci/docker/host-x86_64/dist-arm-linux-gnueabi/Dockerfile b/src/ci/docker/host-x86_64/dist-arm-linux-gnueabi/Dockerfile new file mode 100644 index 0000000000000..996dacd712478 --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-arm-linux-gnueabi/Dockerfile @@ -0,0 +1,35 @@ +FROM ghcr.io/rust-lang/ubuntu:22.04 + +COPY scripts/cross-apt-packages.sh /scripts/ +RUN sh /scripts/cross-apt-packages.sh + +COPY scripts/crosstool-ng.sh /scripts/ +RUN sh /scripts/crosstool-ng.sh + +WORKDIR /build + +COPY scripts/rustbuild-setup.sh /scripts/ +RUN sh /scripts/rustbuild-setup.sh +WORKDIR /tmp + +COPY scripts/crosstool-ng-build.sh /scripts/ +COPY host-x86_64/dist-arm-linux-gnueabi/arm-linux-gnueabi.defconfig /tmp/crosstool.defconfig +RUN /scripts/crosstool-ng-build.sh + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabi/bin + +ENV CC_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-gcc \ + AR_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-ar \ + CXX_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-g++ + +ENV HOSTS=arm-unknown-linux-gnueabi + +ENV RUST_CONFIGURE_ARGS \ + --enable-full-tools \ + --disable-docs \ + --enable-sanitizers \ + --enable-profiler +ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.defconfig b/src/ci/docker/host-x86_64/dist-arm-linux-gnueabi/arm-linux-gnueabi.defconfig similarity index 100% rename from src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.defconfig rename to src/ci/docker/host-x86_64/dist-arm-linux-gnueabi/arm-linux-gnueabi.defconfig diff --git a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-arm-linux-musl/Dockerfile similarity index 73% rename from src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile rename to src/ci/docker/host-x86_64/dist-arm-linux-musl/Dockerfile index 3795859f308e6..6e055cd2bd5aa 100644 --- a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-arm-linux-musl/Dockerfile @@ -19,19 +19,13 @@ RUN sh /scripts/rustbuild-setup.sh WORKDIR /tmp COPY scripts/crosstool-ng-build.sh /scripts/ -COPY host-x86_64/dist-arm-linux/arm-linux-gnueabi.defconfig /tmp/crosstool.defconfig +COPY host-x86_64/dist-arm-linux-musl/arm-linux-musl.defconfig /tmp/crosstool.defconfig RUN /scripts/crosstool-ng-build.sh COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabi/bin - -ENV CC_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-gcc \ - AR_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-ar \ - CXX_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-g++ - -ENV HOSTS=arm-unknown-linux-gnueabi,aarch64-unknown-linux-musl +ENV HOSTS=aarch64-unknown-linux-musl ENV RUST_CONFIGURE_ARGS \ --enable-full-tools \ diff --git a/src/ci/docker/host-x86_64/dist-arm-linux-musl/arm-linux-musl.defconfig b/src/ci/docker/host-x86_64/dist-arm-linux-musl/arm-linux-musl.defconfig new file mode 100644 index 0000000000000..e7afdbe9d4dea --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-arm-linux-musl/arm-linux-musl.defconfig @@ -0,0 +1,13 @@ +CT_CONFIG_VERSION="4" +CT_PREFIX_DIR="/x-tools/${CT_TARGET}" +CT_USE_MIRROR=y +CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc" +CT_ARCH_ARM=y +CT_ARCH_ARCH="armv6" +CT_ARCH_FLOAT_SW=y +CT_KERNEL_LINUX=y +CT_LINUX_V_3_2=y +CT_BINUTILS_V_2_32=y +CT_GLIBC_V_2_17=y +CT_GCC_V_8=y +CT_CC_LANG_CXX=y diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 42ad5acbdac1e..f307972e74df2 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -167,8 +167,11 @@ auto: - name: dist-android <<: *job-linux-4c - - name: dist-arm-linux - <<: *job-linux-8c-codebuild + - name: dist-arm-linux-gnueabi + <<: *job-linux-4c + + - name: dist-arm-linux-musl + <<: *job-linux-4c - name: dist-armhf-linux <<: *job-linux-4c From d2e5a3d131bd5a4ac92c0e6cfd3c49b5b6d44ab6 Mon Sep 17 00:00:00 2001 From: dianqk Date: Sun, 18 May 2025 17:04:49 +0800 Subject: [PATCH 2415/4206] gvn: avoid creating overlapping assignments --- compiler/rustc_mir_transform/src/gvn.rs | 19 ++++++---- .../gvn_overlapping.overlapping.GVN.diff | 18 ++++++++++ tests/mir-opt/gvn_overlapping.rs | 36 +++++++++++++++++++ 3 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 tests/mir-opt/gvn_overlapping.overlapping.GVN.diff create mode 100644 tests/mir-opt/gvn_overlapping.rs diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 8b8d1efbbd2e0..209e818e9e32d 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -836,6 +836,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { #[instrument(level = "trace", skip(self), ret)] fn simplify_rvalue( &mut self, + lhs: &Place<'tcx>, rvalue: &mut Rvalue<'tcx>, location: Location, ) -> Option { @@ -855,7 +856,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Value::Repeat(op, amount) } Rvalue::NullaryOp(op, ty) => Value::NullaryOp(op, ty), - Rvalue::Aggregate(..) => return self.simplify_aggregate(rvalue, location), + Rvalue::Aggregate(..) => return self.simplify_aggregate(lhs, rvalue, location), Rvalue::Ref(_, borrow_kind, ref mut place) => { self.simplify_place_projection(place, location); return Some(self.new_pointer(*place, AddressKind::Ref(borrow_kind))); @@ -943,6 +944,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { fn simplify_aggregate_to_copy( &mut self, + lhs: &Place<'tcx>, rvalue: &mut Rvalue<'tcx>, location: Location, fields: &[VnIndex], @@ -982,12 +984,16 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // Allow introducing places with non-constant offsets, as those are still better than // reconstructing an aggregate. - if let Some(place) = self.try_as_place(copy_from_local_value, location, true) { - if rvalue.ty(self.local_decls, self.tcx) == place.ty(self.local_decls, self.tcx).ty { + if let Some(place) = self.try_as_place(copy_from_local_value, location, true) + && rvalue.ty(self.local_decls, self.tcx) == place.ty(self.local_decls, self.tcx).ty + { + // Avoid creating `*a = copy (*b)`, as they might be aliases resulting in overlapping assignments. + // FIXME: This also avoids any kind of projection, not just derefs. We can add allowed projections. + if lhs.as_local().is_some() { self.reused_locals.insert(place.local); *rvalue = Rvalue::Use(Operand::Copy(place)); - return Some(copy_from_local_value); } + return Some(copy_from_local_value); } None @@ -995,6 +1001,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { fn simplify_aggregate( &mut self, + lhs: &Place<'tcx>, rvalue: &mut Rvalue<'tcx>, location: Location, ) -> Option { @@ -1090,7 +1097,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { if let AggregateTy::Def(_, _) = ty && let Some(value) = - self.simplify_aggregate_to_copy(rvalue, location, &fields, variant_index) + self.simplify_aggregate_to_copy(lhs, rvalue, location, &fields, variant_index) { return Some(value); } @@ -1765,7 +1772,7 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { if let StatementKind::Assign(box (ref mut lhs, ref mut rvalue)) = stmt.kind { self.simplify_place_projection(lhs, location); - let value = self.simplify_rvalue(rvalue, location); + let value = self.simplify_rvalue(lhs, rvalue, location); let value = if let Some(local) = lhs.as_local() && self.ssa.is_ssa(local) // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark diff --git a/tests/mir-opt/gvn_overlapping.overlapping.GVN.diff b/tests/mir-opt/gvn_overlapping.overlapping.GVN.diff new file mode 100644 index 0000000000000..fcabcdbcfef2c --- /dev/null +++ b/tests/mir-opt/gvn_overlapping.overlapping.GVN.diff @@ -0,0 +1,18 @@ +- // MIR for `overlapping` before GVN ++ // MIR for `overlapping` after GVN + + fn overlapping(_1: Adt) -> () { + let mut _0: (); + let mut _2: *mut Adt; + let mut _3: u32; + let mut _4: &Adt; + + bb0: { + _2 = &raw mut _1; + _4 = &(*_2); + _3 = copy (((*_4) as variant#1).0: u32); + (*_2) = Adt::Some(copy _3); + return; + } + } + diff --git a/tests/mir-opt/gvn_overlapping.rs b/tests/mir-opt/gvn_overlapping.rs new file mode 100644 index 0000000000000..99113445e683d --- /dev/null +++ b/tests/mir-opt/gvn_overlapping.rs @@ -0,0 +1,36 @@ +//@ test-mir-pass: GVN + +#![feature(custom_mir, core_intrinsics)] + +// Check that we do not create overlapping assignments. + +use std::intrinsics::mir::*; + +// EMIT_MIR gvn_overlapping.overlapping.GVN.diff +#[custom_mir(dialect = "runtime")] +fn overlapping(_17: Adt) { + // CHECK-LABEL: fn overlapping( + // CHECK: let mut [[PTR:.*]]: *mut Adt; + // CHECK: (*[[PTR]]) = Adt::Some(copy {{.*}}); + mir! { + let _33: *mut Adt; + let _48: u32; + let _73: &Adt; + { + _33 = core::ptr::addr_of_mut!(_17); + _73 = &(*_33); + _48 = Field(Variant((*_73), 1), 0); + (*_33) = Adt::Some(_48); + Return() + } + } +} + +fn main() { + overlapping(Adt::Some(0)); +} + +enum Adt { + None, + Some(u32), +} From f0b8ec1d71f055cbdb741565eaddabc93bf1ae75 Mon Sep 17 00:00:00 2001 From: dianne Date: Wed, 7 May 2025 06:59:30 -0700 Subject: [PATCH 2416/4206] name resolution for guard patterns --- compiler/rustc_ast/src/ast.rs | 2 +- compiler/rustc_resolve/src/late.rs | 36 ++++- .../feature-gate-guard-patterns.rs | 2 - .../feature-gate-guard-patterns.stderr | 31 +--- .../name-resolution.rs | 81 +++++++++++ .../name-resolution.stderr | 133 ++++++++++++++++++ 6 files changed, 255 insertions(+), 30 deletions(-) create mode 100644 tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.rs create mode 100644 tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 114b9835b98cf..ab48a2899a758 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -611,7 +611,7 @@ impl Pat { /// Walk top-down and call `it` in each place where a pattern occurs /// starting with the root pattern `walk` is called on. If `it` returns /// false then we will descend no further but siblings will be processed. - pub fn walk(&self, it: &mut impl FnMut(&Pat) -> bool) { + pub fn walk<'ast>(&'ast self, it: &mut impl FnMut(&'ast Pat) -> bool) { if !it(self) { return; } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index aa211a8f3c292..1b682d0cf8ae9 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -799,7 +799,14 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r fn visit_pat(&mut self, p: &'ast Pat) { let prev = self.diag_metadata.current_pat; self.diag_metadata.current_pat = Some(p); - visit::walk_pat(self, p); + + if let PatKind::Guard(subpat, _) = &p.kind { + // We walk the guard expression in `resolve_pattern_inner`. Don't resolve it twice. + self.visit_pat(subpat); + } else { + visit::walk_pat(self, p); + } + self.diag_metadata.current_pat = prev; } fn visit_local(&mut self, local: &'ast Local) { @@ -3922,7 +3929,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { #[tracing::instrument(skip(self, bindings), level = "debug")] fn resolve_pattern_inner( &mut self, - pat: &Pat, + pat: &'ast Pat, pat_src: PatternSource, bindings: &mut PatternBindings, ) { @@ -3982,6 +3989,31 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // Prevent visiting `ps` as we've already done so above. return false; } + PatKind::Guard(ref subpat, ref guard) => { + // Add a new set of bindings to the stack to collect bindings in `subpat`. + bindings.push((PatBoundCtx::Product, Default::default())); + // Resolving `subpat` adds bindings onto the newly-pushed context. After, the + // total number of contexts on the stack should be the same as before. + let binding_ctx_stack_len = bindings.len(); + self.resolve_pattern_inner(subpat, pat_src, bindings); + assert_eq!(bindings.len(), binding_ctx_stack_len); + // These bindings, but none from the surrounding pattern, are visible in the + // guard; put them in scope and resolve `guard`. + let subpat_bindings = bindings.pop().unwrap().1; + self.with_rib(ValueNS, RibKind::Normal, |this| { + *this.innermost_rib_bindings(ValueNS) = subpat_bindings.clone(); + this.resolve_expr(guard, None); + }); + // Propagate the subpattern's bindings upwards. + // FIXME(guard_patterns): For `if let` guards, we'll also need to get the + // bindings introduced by the guard from its rib and propagate them upwards. + // This will require checking the identifiers for overlaps with `bindings`, like + // what `fresh_binding` does (ideally sharing its logic). To keep them separate + // from `subpat_bindings`, we can introduce a fresh rib for the guard. + bindings.last_mut().unwrap().1.extend(subpat_bindings); + // Prevent visiting `subpat` as we've already done so above. + return false; + } _ => {} } true diff --git a/tests/ui/feature-gates/feature-gate-guard-patterns.rs b/tests/ui/feature-gates/feature-gate-guard-patterns.rs index 74fb5817081c7..095f66eeb9068 100644 --- a/tests/ui/feature-gates/feature-gate-guard-patterns.rs +++ b/tests/ui/feature-gates/feature-gate-guard-patterns.rs @@ -22,7 +22,6 @@ fn other_guards_dont() { let ((x if guard(x)) | x) = 0; //~^ ERROR: guard patterns are experimental - //~| ERROR: cannot find value `x` if let (x if guard(x)) = 0 {} //~^ ERROR: guard patterns are experimental @@ -37,7 +36,6 @@ fn other_guards_dont() { fn even_as_function_parameters(((x if guard(x), _) | (_, x)): (i32, i32)) {} //~^ ERROR: guard patterns are experimental -//~| ERROR: cannot find value `x` fn guard(x: T) -> bool { unimplemented!() diff --git a/tests/ui/feature-gates/feature-gate-guard-patterns.stderr b/tests/ui/feature-gates/feature-gate-guard-patterns.stderr index 8b85b663889f7..b0bf302f3cb6c 100644 --- a/tests/ui/feature-gates/feature-gate-guard-patterns.stderr +++ b/tests/ui/feature-gates/feature-gate-guard-patterns.stderr @@ -10,24 +10,6 @@ LL - (0 if guard(0)) => {}, LL + 0 if guard(0) => {}, | -error[E0425]: cannot find value `x` in this scope - --> $DIR/feature-gate-guard-patterns.rs:23:22 - | -LL | let ((x if guard(x)) | x) = 0; - | ^ not found in this scope - -error[E0425]: cannot find value `x` in this scope - --> $DIR/feature-gate-guard-patterns.rs:38:45 - | -LL | fn even_as_function_parameters(((x if guard(x), _) | (_, x)): (i32, i32)) {} - | ^ - | -help: the binding `x` is available in a different scope in the same function - --> $DIR/feature-gate-guard-patterns.rs:23:11 - | -LL | let ((x if guard(x)) | x) = 0; - | ^ - error[E0658]: guard patterns are experimental --> $DIR/feature-gate-guard-patterns.rs:18:15 | @@ -51,7 +33,7 @@ LL | let ((x if guard(x)) | x) = 0; = help: consider using match arm guards error[E0658]: guard patterns are experimental - --> $DIR/feature-gate-guard-patterns.rs:27:18 + --> $DIR/feature-gate-guard-patterns.rs:26:18 | LL | if let (x if guard(x)) = 0 {} | ^^^^^^^^ @@ -62,7 +44,7 @@ LL | if let (x if guard(x)) = 0 {} = help: consider using match arm guards error[E0658]: guard patterns are experimental - --> $DIR/feature-gate-guard-patterns.rs:30:21 + --> $DIR/feature-gate-guard-patterns.rs:29:21 | LL | while let (x if guard(x)) = 0 {} | ^^^^^^^^ @@ -73,7 +55,7 @@ LL | while let (x if guard(x)) = 0 {} = help: consider using match arm guards error[E0658]: guard patterns are experimental - --> $DIR/feature-gate-guard-patterns.rs:34:21 + --> $DIR/feature-gate-guard-patterns.rs:33:21 | LL | while let (x if guard(x)) = 0 {} | ^^^^^^^^ @@ -84,7 +66,7 @@ LL | while let (x if guard(x)) = 0 {} = help: consider using match arm guards error[E0658]: guard patterns are experimental - --> $DIR/feature-gate-guard-patterns.rs:38:39 + --> $DIR/feature-gate-guard-patterns.rs:37:39 | LL | fn even_as_function_parameters(((x if guard(x), _) | (_, x)): (i32, i32)) {} | ^^^^^^^^ @@ -94,7 +76,6 @@ LL | fn even_as_function_parameters(((x if guard(x), _) | (_, x)): (i32, i32)) { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = help: consider using match arm guards -error: aborting due to 9 previous errors +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0425, E0658. -For more information about an error, try `rustc --explain E0425`. +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.rs b/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.rs new file mode 100644 index 0000000000000..83ad8c76bb1cf --- /dev/null +++ b/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.rs @@ -0,0 +1,81 @@ +//! Test that guard patterns can see bindings already in scope and bindings introduced in their +//! subpattern, but no other bindings from the containing pattern. Also make sure bindings +//! introduced in guard patterns are visible in fn/arm/loop/etc bodies. + +#![feature(guard_patterns)] +#![expect(incomplete_features)] + +fn good_fn_item(((x if x) | x): bool) -> bool { x } + +fn bad_fn_item_1(x: bool, ((y if x) | y): bool) {} +//~^ ERROR cannot find value `x` in this scope +fn bad_fn_item_2(((x if y) | x): bool, y: bool) {} +//~^ ERROR cannot find value `y` in this scope + +fn main() { + let ((local if local) if local) = false; + + match (true, true) { + (x if local, y if good_fn_item(y)) => x && y, + (x, y if x) => x && y, + //~^ ERROR cannot find value `x` in this scope + (x if y, y) => x && y, + //~^ ERROR cannot find value `y` in this scope + }; + + match (true,) { + (x @ y if x && y,) => x && y, + (x @ (y if y),) => x && y, + (x @ (y if x),) => x && y, + //~^ ERROR cannot find value `x` in this scope + }; + + match (Ok(true),) { + ((Ok(x) | Err(x)) if good_fn_item(x),) => x, + ((Ok(x) if local) | (Err(x) if good_fn_item(x)),) => x, + ((Ok(x if x) if x) | (Err(x if x) if x) if x,) if x => x, + ((Ok(x) if y) | (Err(y) if x),) => x && y, + //~^ ERROR variable `x` is not bound in all patterns + //~| ERROR variable `y` is not bound in all patterns + //~| ERROR cannot find value `x` in this scope + //~| ERROR cannot find value `y` in this scope + }; + + let (_ if nonexistent) = true; + //~^ ERROR cannot find value `nonexistent` in this scope + if let ((x, y if x) | (x if y, y)) = (true, true) { x && y; } + //~^ ERROR cannot find value `x` in this scope + //~| ERROR cannot find value `y` in this scope + while let ((x, y if x) | (x if y, y)) = (true, true) { x && y; } + //~^ ERROR cannot find value `x` in this scope + //~| ERROR cannot find value `y` in this scope + for ((x, y if x) | (x if y, y)) in [(true, true)] { x && y; } + //~^ ERROR cannot find value `x` in this scope + //~| ERROR cannot find value `y` in this scope + + (|(x if x), (y if y)| x && y)(true, true); + (|(x if y), (y if x)| x && y)(true, true); + //~^ ERROR cannot find value `x` in this scope + //~| ERROR cannot find value `y` in this scope + + // FIXME(guard_patterns): mismatched bindings are not yet allowed + match Some(0) { + Some(x if x > 0) | None => {} + //~^ ERROR variable `x` is not bound in all patterns + } +} + +/// Make sure shadowing is handled properly. In particular, if a pattern shadows an identifier, +/// a guard pattern's guard should still see the original binding if the shadowing binding isn't in +/// its subpattern. +fn test_shadowing(local: bool) -> u8 { + match (0, 0) { + // The `local` binding here shadows the `bool` definition, so we get a type error. + //~v ERROR mismatched types + local if local => 0, + // The guards here should see the `bool` definition of `local`, not the new `u8` binding. + // The body should see the new binding. + (local, _ if local) => local, + (_ if local, local) => local, + } +} diff --git a/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr b/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr new file mode 100644 index 0000000000000..d76e60478a146 --- /dev/null +++ b/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr @@ -0,0 +1,133 @@ +error[E0408]: variable `y` is not bound in all patterns + --> $DIR/name-resolution.rs:37:10 + | +LL | ((Ok(x) if y) | (Err(y) if x),) => x && y, + | ^^^^^^^^^^^^ - variable not in all patterns + | | + | pattern doesn't bind `y` + +error[E0408]: variable `x` is not bound in all patterns + --> $DIR/name-resolution.rs:37:25 + | +LL | ((Ok(x) if y) | (Err(y) if x),) => x && y, + | - ^^^^^^^^^^^^^ pattern doesn't bind `x` + | | + | variable not in all patterns + +error[E0408]: variable `x` is not bound in all patterns + --> $DIR/name-resolution.rs:63:28 + | +LL | Some(x if x > 0) | None => {} + | - ^^^^ pattern doesn't bind `x` + | | + | variable not in all patterns + +error[E0425]: cannot find value `x` in this scope + --> $DIR/name-resolution.rs:10:34 + | +LL | fn bad_fn_item_1(x: bool, ((y if x) | y): bool) {} + | ^ help: a local variable with a similar name exists: `y` + +error[E0425]: cannot find value `y` in this scope + --> $DIR/name-resolution.rs:12:25 + | +LL | fn bad_fn_item_2(((x if y) | x): bool, y: bool) {} + | ^ help: a local variable with a similar name exists: `x` + +error[E0425]: cannot find value `x` in this scope + --> $DIR/name-resolution.rs:20:18 + | +LL | (x, y if x) => x && y, + | ^ help: a local variable with a similar name exists: `y` + +error[E0425]: cannot find value `y` in this scope + --> $DIR/name-resolution.rs:22:15 + | +LL | (x if y, y) => x && y, + | ^ help: a local variable with a similar name exists: `x` + +error[E0425]: cannot find value `x` in this scope + --> $DIR/name-resolution.rs:29:20 + | +LL | (x @ (y if x),) => x && y, + | ^ help: a local variable with a similar name exists: `y` + +error[E0425]: cannot find value `y` in this scope + --> $DIR/name-resolution.rs:37:20 + | +LL | ((Ok(x) if y) | (Err(y) if x),) => x && y, + | ^ help: a local variable with a similar name exists: `x` + +error[E0425]: cannot find value `x` in this scope + --> $DIR/name-resolution.rs:37:36 + | +LL | ((Ok(x) if y) | (Err(y) if x),) => x && y, + | ^ help: a local variable with a similar name exists: `y` + +error[E0425]: cannot find value `nonexistent` in this scope + --> $DIR/name-resolution.rs:44:15 + | +LL | let (_ if nonexistent) = true; + | ^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `x` in this scope + --> $DIR/name-resolution.rs:46:22 + | +LL | if let ((x, y if x) | (x if y, y)) = (true, true) { x && y; } + | ^ help: a local variable with a similar name exists: `y` + +error[E0425]: cannot find value `y` in this scope + --> $DIR/name-resolution.rs:46:33 + | +LL | if let ((x, y if x) | (x if y, y)) = (true, true) { x && y; } + | ^ help: a local variable with a similar name exists: `x` + +error[E0425]: cannot find value `x` in this scope + --> $DIR/name-resolution.rs:49:25 + | +LL | while let ((x, y if x) | (x if y, y)) = (true, true) { x && y; } + | ^ help: a local variable with a similar name exists: `y` + +error[E0425]: cannot find value `y` in this scope + --> $DIR/name-resolution.rs:49:36 + | +LL | while let ((x, y if x) | (x if y, y)) = (true, true) { x && y; } + | ^ help: a local variable with a similar name exists: `x` + +error[E0425]: cannot find value `x` in this scope + --> $DIR/name-resolution.rs:52:19 + | +LL | for ((x, y if x) | (x if y, y)) in [(true, true)] { x && y; } + | ^ help: a local variable with a similar name exists: `y` + +error[E0425]: cannot find value `y` in this scope + --> $DIR/name-resolution.rs:52:30 + | +LL | for ((x, y if x) | (x if y, y)) in [(true, true)] { x && y; } + | ^ help: a local variable with a similar name exists: `x` + +error[E0425]: cannot find value `y` in this scope + --> $DIR/name-resolution.rs:57:13 + | +LL | (|(x if y), (y if x)| x && y)(true, true); + | ^ help: a local variable with a similar name exists: `x` + +error[E0425]: cannot find value `x` in this scope + --> $DIR/name-resolution.rs:57:23 + | +LL | (|(x if y), (y if x)| x && y)(true, true); + | ^ help: a local variable with a similar name exists: `y` + +error[E0308]: mismatched types + --> $DIR/name-resolution.rs:75:18 + | +LL | local if local => 0, + | ^^^^^ expected `bool`, found `({integer}, {integer})` + | + = note: expected type `bool` + found tuple `({integer}, {integer})` + +error: aborting due to 20 previous errors + +Some errors have detailed explanations: E0308, E0408, E0425. +For more information about an error, try `rustc --explain E0308`. From f9a75a00b4df355f439cc91b0a660ac508ac9d46 Mon Sep 17 00:00:00 2001 From: tiif Date: Sun, 18 May 2025 13:42:07 +0200 Subject: [PATCH 2417/4206] Add more comment to libc-fs-with-isolation test --- src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs index cffcf4a867fee..06a8cc7f4879a 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs @@ -11,6 +11,10 @@ fn main() { assert!(libc::fcntl(1, libc::F_DUPFD, 0) >= 0); } + // Although `readlink` and `stat` require disable-isolation mode + // to properly run, they are tested with isolation mode on to check the error emitted + // with `-Zmiri-isolation-error=warn-nobacktrace`. + // test `readlink` let mut buf = vec![0; "foo_link.txt".len() + 1]; unsafe { From 1d0d258a8635822b49d6cc937d895947523372fd Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 17 May 2025 19:41:06 +0000 Subject: [PATCH 2418/4206] Fast path for processing some obligations in the new solver --- .../rustc_next_trait_solver/src/delegate.rs | 8 +++++ .../src/solve/eval_ctxt/canonical.rs | 11 +++--- .../src/solve/eval_ctxt/mod.rs | 8 +++++ .../src/solve/delegate.rs | 36 +++++++++++++++++-- .../src/solve/fulfill.rs | 11 +++++- 5 files changed, 67 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 90a7c2e9f7879..bb923612cffc4 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -3,6 +3,8 @@ use std::ops::Deref; use rustc_type_ir::solve::{Certainty, Goal, NoSolution}; use rustc_type_ir::{self as ty, InferCtxtLike, Interner, TypeFoldable}; +use crate::solve::HasChanged; + pub trait SolverDelegate: Deref + Sized { type Infcx: InferCtxtLike; type Interner: Interner; @@ -17,6 +19,12 @@ pub trait SolverDelegate: Deref + Sized { where V: TypeFoldable; + fn compute_goal_fast_path( + &self, + goal: Goal::Predicate>, + span: ::Span, + ) -> Option; + fn fresh_var_for_kind_with_span( &self, arg: ::GenericArg, diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index 36f68808a2c8c..c62f2e2e0e95f 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -12,6 +12,7 @@ use std::iter; use rustc_index::IndexVec; +use rustc_type_ir::data_structures::HashSet; use rustc_type_ir::inherent::*; use rustc_type_ir::relate::solver_relating::RelateExt; use rustc_type_ir::{ @@ -158,10 +159,12 @@ where self.compute_external_query_constraints(certainty, normalization_nested_goals); let (var_values, mut external_constraints) = (self.var_values, external_constraints) .fold_with(&mut EagerResolver::new(self.delegate)); - // Remove any trivial region constraints once we've resolved regions - external_constraints - .region_constraints - .retain(|outlives| outlives.0.as_region().is_none_or(|re| re != outlives.1)); + + // Remove any trivial or duplicated region constraints once we've resolved regions + let mut unique = HashSet::default(); + external_constraints.region_constraints.retain(|outlives| { + outlives.0.as_region().is_none_or(|re| re != outlives.1) && unique.insert(*outlives) + }); let canonical = Canonicalizer::canonicalize_response( self.delegate, diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index fc5dad9a3edf5..9a4b95903a970 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -603,6 +603,14 @@ where // If this loop did not result in any progress, what's our final certainty. let mut unchanged_certainty = Some(Certainty::Yes); for (source, goal) in mem::take(&mut self.nested_goals) { + if let Some(has_changed) = self.delegate.compute_goal_fast_path(goal, self.origin_span) + { + if matches!(has_changed, HasChanged::Yes) { + unchanged_certainty = None; + } + continue; + } + // We treat normalizes-to goals specially here. In each iteration we take the // RHS of the projection, replace it with a fresh inference variable, and only // after evaluating that goal do we equate the fresh inference variable with the diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 3601c2cba9b55..b6351e5e60450 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -6,14 +6,15 @@ use rustc_infer::infer::canonical::query_response::make_query_region_constraints use rustc_infer::infer::canonical::{ Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues, }; -use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt}; +use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt}; use rustc_infer::traits::solve::Goal; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::Certainty; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _, TypingMode}; +use rustc_next_trait_solver::solve::HasChanged; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; -use crate::traits::{EvaluateConstErr, specialization_graph}; +use crate::traits::{EvaluateConstErr, ObligationCause, specialization_graph}; #[repr(transparent)] pub struct SolverDelegate<'tcx>(InferCtxt<'tcx>); @@ -55,6 +56,37 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< (SolverDelegate(infcx), value, vars) } + fn compute_goal_fast_path( + &self, + goal: Goal<'tcx, ty::Predicate<'tcx>>, + span: Span, + ) -> Option { + let pred = goal.predicate.kind(); + match pred.no_bound_vars()? { + ty::PredicateKind::DynCompatible(def_id) if self.0.tcx.is_dyn_compatible(def_id) => { + Some(HasChanged::No) + } + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(outlives)) => { + self.0.sub_regions( + SubregionOrigin::RelateRegionParamBound(span, None), + outlives.1, + outlives.0, + ); + Some(HasChanged::No) + } + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => { + self.0.register_region_obligation_with_cause( + outlives.0, + outlives.1, + &ObligationCause::dummy_with_span(span), + ); + + Some(HasChanged::No) + } + _ => None, + } + } + fn fresh_var_for_kind_with_span( &self, arg: ty::GenericArg<'tcx>, diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 3e1cdac84dfd1..aa3be43fcd16b 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -12,6 +12,7 @@ use rustc_infer::traits::{ use rustc_middle::ty::{ self, DelayedSet, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, TypingMode, }; +use rustc_next_trait_solver::delegate::SolverDelegate as _; use rustc_next_trait_solver::solve::{GenerateProofTree, HasChanged, SolverDelegateEvalExt as _}; use rustc_span::Span; use tracing::instrument; @@ -172,7 +173,15 @@ where } let goal = obligation.as_goal(); - let result = <&SolverDelegate<'tcx>>::from(infcx) + let delegate = <&SolverDelegate<'tcx>>::from(infcx); + if let Some(fast_path_has_changed) = + delegate.compute_goal_fast_path(goal, obligation.cause.span) + { + has_changed |= matches!(fast_path_has_changed, HasChanged::Yes); + continue; + } + + let result = delegate .evaluate_root_goal(goal, GenerateProofTree::No, obligation.cause.span) .0; self.inspect_evaluated_obligation(infcx, &obligation, &result); From 407fac54798cf225b81b67cad2525a0acbda9b03 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 17 May 2025 14:11:51 +0000 Subject: [PATCH 2419/4206] Fast path for sized pred --- compiler/rustc_middle/src/ty/sty.rs | 4 ++-- .../rustc_trait_selection/src/solve/delegate.rs | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index ab1f3d6099fcf..77b9becba572f 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1882,9 +1882,9 @@ impl<'tcx> Ty<'tcx> { // Needs normalization or revealing to determine, so no is the safe answer. ty::Alias(..) => false, - ty::Param(..) | ty::Infer(..) | ty::Error(..) => false, + ty::Param(..) | ty::Placeholder(..) | ty::Infer(..) | ty::Error(..) => false, - ty::Bound(..) | ty::Placeholder(..) => { + ty::Bound(..) => { bug!("`is_trivially_pure_clone_copy` applied to unexpected type: {:?}", self); } } diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index b6351e5e60450..a60642b953ced 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -1,6 +1,7 @@ use std::ops::Deref; use rustc_data_structures::fx::FxHashSet; +use rustc_hir::LangItem; use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_infer::infer::canonical::query_response::make_query_region_constraints; use rustc_infer::infer::canonical::{ @@ -83,6 +84,21 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< Some(HasChanged::No) } + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => { + match self.0.tcx.as_lang_item(trait_pred.def_id()) { + Some(LangItem::Sized) + if trait_pred.self_ty().is_trivially_sized(self.0.tcx) => + { + Some(HasChanged::No) + } + Some(LangItem::Copy | LangItem::Clone) + if trait_pred.self_ty().is_trivially_pure_clone_copy() => + { + Some(HasChanged::No) + } + _ => None, + } + } _ => None, } } From 228a7bb91809fefa7eee61f4ec5960e4a263563f Mon Sep 17 00:00:00 2001 From: Mahmoud Mazouz Date: Sun, 18 May 2025 15:37:18 +0200 Subject: [PATCH 2420/4206] Fix typos in "Libraries and Metadata" --- .../src/backend/libs-and-metadata.md | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md b/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md index 513df1650c387..eeb2af5e6bc8b 100644 --- a/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md +++ b/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md @@ -28,8 +28,8 @@ format is specific to `rustc`, and may change over time. This file contains: [`-C embed-bitcode=no`][embed-bitcode] CLI option to improve compile times and reduce disk space if LTO is not needed. * `rustc` [metadata], in a file named `lib.rmeta`. -* A symbol table, which is generally a list of symbols with offsets to the - object file that contain that symbol. This is pretty standard for archive +* A symbol table, which is essentially a list of symbols with offsets to the + object files that contain that symbol. This is pretty standard for archive files. [archive file]: https://en.wikipedia.org/wiki/Ar_(Unix) @@ -46,12 +46,11 @@ A `dylib` is a platform-specific shared library. It includes the `rustc` ### rmeta -An `rmeta` file is custom binary format that contains the [metadata] for the -crate. This file can be used for fast "checks" of a project by skipping all -code generation (as is done with `cargo check`), collecting enough information -for documentation (as is done with `cargo doc`), or for -[pipelining](#pipelining). This file is created if the -[`--emit=metadata`][emit] CLI option is used. +An `rmeta` file is a custom binary format that contains the [metadata] for the +crate. This file can be used for fast "checks" of a project by skipping all code +generation (as is done with `cargo check`), collecting enough information for +documentation (as is done with `cargo doc`), or for [pipelining](#pipelining). +This file is created if the [`--emit=metadata`][emit] CLI option is used. `rmeta` files do not support linking, since they do not contain compiled object files. @@ -60,8 +59,8 @@ object files. ## Metadata -The metadata contains a wide swath of different elements. This guide will not -go into detail of every field it contains. You are encouraged to browse the +The metadata contains a wide swath of different elements. This guide will not go +into detail about every field it contains. You are encouraged to browse the [`CrateRoot`] definition to get a sense of the different elements it contains. Everything about metadata encoding and decoding is in the [`rustc_metadata`] package. @@ -122,9 +121,9 @@ much more. By default, all Rust symbols are mangled and incorporate the stable crate id. This allows multiple versions of the same crate to be included together. Cargo -automatically generates `-C metadata` hashes based on a variety of factors, -like the package version, source, and the target kind (a lib and test can have -the same crate name, so they need to be disambiguated). +automatically generates `-C metadata` hashes based on a variety of factors, like +the package version, source, and target kind (a lib and test can have the same +crate name, so they need to be disambiguated). [`StableCrateId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/def_id/struct.StableCrateId.html [`StableCrateId::new`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/def_id/struct.StableCrateId.html#method.new @@ -154,7 +153,7 @@ will also look at the [sysroot] to find dependencies. As crates are loaded, they are kept in the [`CStore`] with the crate metadata wrapped in the [`CrateMetadata`] struct. After resolution and expansion, the -`CStore` will make its way into the [`GlobalCtxt`] for the rest of +`CStore` will make its way into the [`GlobalCtxt`] for the rest of the compilation. [name resolution]: ../name-resolution.md From bc02a99f8f2b3439fb680be39339b3a8c9d23f32 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 18 May 2025 14:30:42 +0000 Subject: [PATCH 2421/4206] Rustup to rustc 1.89.0-nightly (777d37277 2025-05-17) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 4ca593e6bea58..78cfde6ad01ab 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-05-05" +channel = "nightly-2025-05-18" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 8b48bac63d7774c03644a9ed0404c1c5595add62 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sat, 17 May 2025 14:51:58 +0800 Subject: [PATCH 2422/4206] [std] fix the presentation of `split_off_mut` and `split_off` documentation Signed-off-by: xizheyin --- library/core/src/slice/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 058491b53a16f..c9b8231e856c1 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -4383,7 +4383,7 @@ impl [T] { /// assert_eq!(first_three, &['a', 'b', 'c']); /// ``` /// - /// Splitting off the last two elements of a slice: + /// Splitting off a slice starting with the third element: /// /// ``` /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; @@ -4449,7 +4449,7 @@ impl [T] { /// assert_eq!(first_three, &mut ['a', 'b', 'c']); /// ``` /// - /// Taking the last two elements of a slice: + /// Splitting off a slice starting with the third element: /// /// ``` /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; From 0443a66d3911104dddb457a4f7885cb4fc428723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sun, 18 May 2025 14:50:30 +0200 Subject: [PATCH 2423/4206] more ice tests --- tests/crashes/139905.rs | 6 ++++++ tests/crashes/140011.rs | 11 +++++++++++ tests/crashes/140099.rs | 6 ++++++ tests/crashes/140100.rs | 7 +++++++ tests/crashes/140123-2.rs | 12 ++++++++++++ tests/crashes/140123-3.rs | 10 ++++++++++ tests/crashes/140123-4.rs | 13 +++++++++++++ tests/crashes/140123.rs | 10 ++++++++++ tests/crashes/140255.rs | 3 +++ tests/crashes/140275.rs | 5 +++++ tests/crashes/140281.rs | 18 ++++++++++++++++++ tests/crashes/140303.rs | 22 ++++++++++++++++++++++ tests/crashes/140333.rs | 9 +++++++++ tests/crashes/140365.rs | 8 ++++++++ tests/crashes/140381.rs | 16 ++++++++++++++++ tests/crashes/140429.rs | 6 ++++++ tests/crashes/140479.rs | 5 +++++ tests/crashes/140484.rs | 14 ++++++++++++++ tests/crashes/140500.rs | 14 ++++++++++++++ tests/crashes/140530.rs | 8 ++++++++ tests/crashes/140531.rs | 7 +++++++ tests/crashes/140571.rs | 14 ++++++++++++++ tests/crashes/140577.rs | 32 ++++++++++++++++++++++++++++++++ tests/crashes/140609.rs | 13 +++++++++++++ tests/crashes/140642.rs | 8 ++++++++ tests/crashes/140683.rs | 5 +++++ tests/crashes/140729.rs | 11 +++++++++++ tests/crashes/140823.rs | 9 +++++++++ tests/crashes/140850.rs | 7 +++++++ tests/crashes/140860.rs | 10 ++++++++++ tests/crashes/140884.rs | 6 ++++++ tests/crashes/140891.rs | 6 ++++++ tests/crashes/140974.rs | 14 ++++++++++++++ tests/crashes/140975.rs | 22 ++++++++++++++++++++++ tests/crashes/141124.rs | 16 ++++++++++++++++ tests/crashes/141143.rs | 13 +++++++++++++ 36 files changed, 396 insertions(+) create mode 100644 tests/crashes/139905.rs create mode 100644 tests/crashes/140011.rs create mode 100644 tests/crashes/140099.rs create mode 100644 tests/crashes/140100.rs create mode 100644 tests/crashes/140123-2.rs create mode 100644 tests/crashes/140123-3.rs create mode 100644 tests/crashes/140123-4.rs create mode 100644 tests/crashes/140123.rs create mode 100644 tests/crashes/140255.rs create mode 100644 tests/crashes/140275.rs create mode 100644 tests/crashes/140281.rs create mode 100644 tests/crashes/140303.rs create mode 100644 tests/crashes/140333.rs create mode 100644 tests/crashes/140365.rs create mode 100644 tests/crashes/140381.rs create mode 100644 tests/crashes/140429.rs create mode 100644 tests/crashes/140479.rs create mode 100644 tests/crashes/140484.rs create mode 100644 tests/crashes/140500.rs create mode 100644 tests/crashes/140530.rs create mode 100644 tests/crashes/140531.rs create mode 100644 tests/crashes/140571.rs create mode 100644 tests/crashes/140577.rs create mode 100644 tests/crashes/140609.rs create mode 100644 tests/crashes/140642.rs create mode 100644 tests/crashes/140683.rs create mode 100644 tests/crashes/140729.rs create mode 100644 tests/crashes/140823.rs create mode 100644 tests/crashes/140850.rs create mode 100644 tests/crashes/140860.rs create mode 100644 tests/crashes/140884.rs create mode 100644 tests/crashes/140891.rs create mode 100644 tests/crashes/140974.rs create mode 100644 tests/crashes/140975.rs create mode 100644 tests/crashes/141124.rs create mode 100644 tests/crashes/141143.rs diff --git a/tests/crashes/139905.rs b/tests/crashes/139905.rs new file mode 100644 index 0000000000000..7da622aaabac6 --- /dev/null +++ b/tests/crashes/139905.rs @@ -0,0 +1,6 @@ +//@ known-bug: #139905 +trait a {} +impl a<{}> for () {} +trait c {} +impl c for () where (): a {} +impl c for () {} diff --git a/tests/crashes/140011.rs b/tests/crashes/140011.rs new file mode 100644 index 0000000000000..b9d57a2822d21 --- /dev/null +++ b/tests/crashes/140011.rs @@ -0,0 +1,11 @@ +//@ known-bug: #140011 +//@compile-flags: -Wrust-2021-incompatible-closure-captures +enum b { + c(d), + e(f), +} +struct f; +fn g() { + let h; + || b::e(a) = h; +} diff --git a/tests/crashes/140099.rs b/tests/crashes/140099.rs new file mode 100644 index 0000000000000..fca129100555d --- /dev/null +++ b/tests/crashes/140099.rs @@ -0,0 +1,6 @@ +//@ known-bug: #140099 +struct a; +impl From for a where for<'any> &'any mut (): Clone {} +fn b() -> Result<(), std::convert::Infallible> { + || -> Result<_, a> { b()? } +} diff --git a/tests/crashes/140100.rs b/tests/crashes/140100.rs new file mode 100644 index 0000000000000..0836ffe2d92f9 --- /dev/null +++ b/tests/crashes/140100.rs @@ -0,0 +1,7 @@ +//@ known-bug: #140100 +fn a() +where + b: Sized, +{ + println!() +} diff --git a/tests/crashes/140123-2.rs b/tests/crashes/140123-2.rs new file mode 100644 index 0000000000000..6ed10b9dcc34a --- /dev/null +++ b/tests/crashes/140123-2.rs @@ -0,0 +1,12 @@ +//@ known-bug: #140123 +//@ compile-flags: --crate-type lib + +trait Trait {} + +impl Trait for [(); 0] {} + +const ICE: [&mut dyn Trait; 2] = [const { empty_mut() }; 2]; + +const fn empty_mut() -> &'static mut [(); 0] { + &mut [] +} diff --git a/tests/crashes/140123-3.rs b/tests/crashes/140123-3.rs new file mode 100644 index 0000000000000..a1dcd7fc39fa7 --- /dev/null +++ b/tests/crashes/140123-3.rs @@ -0,0 +1,10 @@ +//@ known-bug: #140123 +//@ compile-flags: --crate-type lib + +const ICE: [&mut [()]; 2] = [const { empty_mut() }; 2]; + +const fn empty_mut() -> &'static mut [()] { + unsafe { + std::slice::from_raw_parts_mut(std::ptr::dangling_mut(), 0) + } +} diff --git a/tests/crashes/140123-4.rs b/tests/crashes/140123-4.rs new file mode 100644 index 0000000000000..39042d897ee28 --- /dev/null +++ b/tests/crashes/140123-4.rs @@ -0,0 +1,13 @@ +//@ known-bug: #140123 +//@ compile-flags: --crate-type lib + +const ICE: [&mut [(); 0]; 2] = [const { empty_mut() }; 2]; + +const fn empty_mut() -> &'static mut [(); 0] { + &mut [] +} +// https://github.com/rust-lang/rust/issues/140123#issuecomment-2820664450 +const ICE2: [&mut [(); 0]; 2] = [const { + let x = &mut []; + x +}; 2]; diff --git a/tests/crashes/140123.rs b/tests/crashes/140123.rs new file mode 100644 index 0000000000000..337b5f3cef046 --- /dev/null +++ b/tests/crashes/140123.rs @@ -0,0 +1,10 @@ +//@ known-bug: #140123 +//@ compile-flags: --crate-type lib + +const OK: [&mut [()]; 2] = [empty_mut(), empty_mut()]; +const ICE: [&mut [()]; 2] = [const { empty_mut() }; 2]; + +// Any kind of fn call gets around E0764. +const fn empty_mut() -> &'static mut [()] { + &mut [] +} diff --git a/tests/crashes/140255.rs b/tests/crashes/140255.rs new file mode 100644 index 0000000000000..6b0ec1718b0b2 --- /dev/null +++ b/tests/crashes/140255.rs @@ -0,0 +1,3 @@ +//@ known-bug: #140255 +#[unsafe(macro_use::VAR2)] +fn dead_code() {} diff --git a/tests/crashes/140275.rs b/tests/crashes/140275.rs new file mode 100644 index 0000000000000..5ea04af0c8e0c --- /dev/null +++ b/tests/crashes/140275.rs @@ -0,0 +1,5 @@ +//@ known-bug: #140275 +#![feature(generic_const_exprs)] +trait T{} +trait V{} +impl T for [i32; N::<&mut V>] {} diff --git a/tests/crashes/140281.rs b/tests/crashes/140281.rs new file mode 100644 index 0000000000000..76858cfc74a55 --- /dev/null +++ b/tests/crashes/140281.rs @@ -0,0 +1,18 @@ +//@ known-bug: #140281 + +macro_rules! foo { + ($x:expr) => { $x } +} + +fn main() { + let t = vec![ + /// ‮test⁦ RTL in doc in vec! + // ICE (Sadly) + 1 + ]; + + foo!( + /// ‮test⁦ RTL in doc in macro + 1 + ); +} diff --git a/tests/crashes/140303.rs b/tests/crashes/140303.rs new file mode 100644 index 0000000000000..43a20b5e58ed4 --- /dev/null +++ b/tests/crashes/140303.rs @@ -0,0 +1,22 @@ +//@ known-bug: #140303 +//@compile-flags: -Zvalidate-mir +use std::future::Future; +async fn a() -> impl Sized { + b(c) +} +async fn c(); // kaboom +fn b(e: d) -> impl Sized +where + d: f, +{ + || -> ::h { panic!() } +} +trait f { + type h; +} +impl f for d +where + d: Fn() -> g, + g: Future, +{ +} diff --git a/tests/crashes/140333.rs b/tests/crashes/140333.rs new file mode 100644 index 0000000000000..cec1100e6adad --- /dev/null +++ b/tests/crashes/140333.rs @@ -0,0 +1,9 @@ +//@ known-bug: #140333 +fn a() -> impl b< + [c; { + struct d { + #[a] + bar: e, + } + }], +>; diff --git a/tests/crashes/140365.rs b/tests/crashes/140365.rs new file mode 100644 index 0000000000000..809ceaf35a059 --- /dev/null +++ b/tests/crashes/140365.rs @@ -0,0 +1,8 @@ +//@ known-bug: #140365 +//@compile-flags: -C opt-level=1 -Zvalidate-mir +fn f() -> &'static str +where + Self: Sized, +{ + "" +} diff --git a/tests/crashes/140381.rs b/tests/crashes/140381.rs new file mode 100644 index 0000000000000..439ca694d5636 --- /dev/null +++ b/tests/crashes/140381.rs @@ -0,0 +1,16 @@ +//@ known-bug: #140381 +pub trait Foo {} +pub trait Lend { + type From<'a> + where + Self: 'a; + fn lend(from: Self::From<'_>) -> impl Foo>; +} + +impl Lend for (T, F) { + type From<'a> = (); + + fn lend(from: Self::From<'_>) -> impl Foo> { + from + } +} diff --git a/tests/crashes/140429.rs b/tests/crashes/140429.rs new file mode 100644 index 0000000000000..041eaf86c5c37 --- /dev/null +++ b/tests/crashes/140429.rs @@ -0,0 +1,6 @@ +//@ known-bug: #140429 +//@ compile-flags: -Zlint-mir --crate-type lib +//@ edition:2024 + +#![feature(async_drop)] +async fn a(x: T) {} diff --git a/tests/crashes/140479.rs b/tests/crashes/140479.rs new file mode 100644 index 0000000000000..ed3ca887546f9 --- /dev/null +++ b/tests/crashes/140479.rs @@ -0,0 +1,5 @@ +//@ known-bug: #140479 +macro_rules! a { ( $( { $ [ $b:c ] } )) => ( $(${ concat(d, $b)} ))} +fn e() { + a!({}) +} diff --git a/tests/crashes/140484.rs b/tests/crashes/140484.rs new file mode 100644 index 0000000000000..92ec19843982d --- /dev/null +++ b/tests/crashes/140484.rs @@ -0,0 +1,14 @@ +//@ known-bug: #140484 +//@edition:2024 +#![feature(async_drop)] +use std::future::AsyncDrop; +struct a; +impl Drop for a { + fn b() {} +} +impl AsyncDrop for a { + type c; +} +async fn bar() { + a; +} diff --git a/tests/crashes/140500.rs b/tests/crashes/140500.rs new file mode 100644 index 0000000000000..ee5b93ab82132 --- /dev/null +++ b/tests/crashes/140500.rs @@ -0,0 +1,14 @@ +//@ known-bug: #140500 + +#![feature(async_drop)] +use std::future::AsyncDrop; +struct a; +impl Drop for a { + fn b() {} +} +impl AsyncDrop for a { + fn c(d: impl Sized) {} +} +async fn bar() { + a; +} diff --git a/tests/crashes/140530.rs b/tests/crashes/140530.rs new file mode 100644 index 0000000000000..7e0372a4bd866 --- /dev/null +++ b/tests/crashes/140530.rs @@ -0,0 +1,8 @@ +//@ known-bug: #140530 +//@ edition: 2024 + +#![feature(async_drop, gen_blocks)] +async gen fn a() { + _ = async {} +} +fn main() {} diff --git a/tests/crashes/140531.rs b/tests/crashes/140531.rs new file mode 100644 index 0000000000000..f664481d44027 --- /dev/null +++ b/tests/crashes/140531.rs @@ -0,0 +1,7 @@ +//@ known-bug: #140531 +//@compile-flags: -Zlint-mir --crate-type lib +//@ edition:2024 +#![feature(async_drop)] +async fn call_once(f: impl AsyncFnOnce()) { + let fut = Box::pin(f()); +} diff --git a/tests/crashes/140571.rs b/tests/crashes/140571.rs new file mode 100644 index 0000000000000..97fa1d8432dd9 --- /dev/null +++ b/tests/crashes/140571.rs @@ -0,0 +1,14 @@ +//@ known-bug: #140571 +pub trait IsVoid { + const IS_VOID: bool; +} +impl IsVoid for T { + default const IS_VOID: bool = false; +} +impl Maybe for () where T: NotVoid + ?Sized {} + +pub trait NotVoid {} +impl NotVoid for T where T: IsVoid + ?Sized {} + +pub trait Maybe {} +impl Maybe for T {} diff --git a/tests/crashes/140577.rs b/tests/crashes/140577.rs new file mode 100644 index 0000000000000..21e6b1e1522fb --- /dev/null +++ b/tests/crashes/140577.rs @@ -0,0 +1,32 @@ +//@ known-bug: #140577 +//@ compile-flags: -Znext-solver=globally +//@ edition:2021 + +use std::future::Future; +use std::pin::Pin; +trait Acquire { + type Connection; +} +impl Acquire for &'static () { + type Connection = (); +} +fn b() -> impl Future + Send { + let x: Pin + Send>> = todo!(); + x +} +fn main() { + async { + b::<&()>().await; + } + .aa(); +} + +impl Filter for F where F: Send {} + +trait Filter { + fn aa(self) + where + Self: Sized, + { + } +} diff --git a/tests/crashes/140609.rs b/tests/crashes/140609.rs new file mode 100644 index 0000000000000..ee8a4bb30489f --- /dev/null +++ b/tests/crashes/140609.rs @@ -0,0 +1,13 @@ +//@ known-bug: #140609 +#![feature(with_negative_coherence)] +#![feature(generic_const_exprs)] +#![crate_type = "lib"] +trait Trait {} +struct A; + +trait C {} + +impl Trait for E where A<{ D <= 2 }>: FnOnce(&isize) {} +struct E; + +impl Trait for E where A<{ D <= 2 }>: C {} diff --git a/tests/crashes/140642.rs b/tests/crashes/140642.rs new file mode 100644 index 0000000000000..ff75a6ec2f230 --- /dev/null +++ b/tests/crashes/140642.rs @@ -0,0 +1,8 @@ +//@ known-bug: #140642 +#![feature(min_generic_const_args)] + +pub trait Tr
{ + const SIZE: usize; +} + +fn mk_array(_x: T) -> [(); >::SIZE] {} diff --git a/tests/crashes/140683.rs b/tests/crashes/140683.rs new file mode 100644 index 0000000000000..74ea5c2533bb9 --- /dev/null +++ b/tests/crashes/140683.rs @@ -0,0 +1,5 @@ +//@ known-bug: #140683 +impl T { +#[core::contracts::ensures] + fn b() { (loop) } +} diff --git a/tests/crashes/140729.rs b/tests/crashes/140729.rs new file mode 100644 index 0000000000000..a436ec58e8e83 --- /dev/null +++ b/tests/crashes/140729.rs @@ -0,0 +1,11 @@ +//@ known-bug: #140729 +#![feature(min_generic_const_args)] + +const C: usize = 0; +pub struct A {} +impl A { + fn fun1() {} +} +impl A { + fn fun1() {} +} diff --git a/tests/crashes/140823.rs b/tests/crashes/140823.rs new file mode 100644 index 0000000000000..ca2d683beedb2 --- /dev/null +++ b/tests/crashes/140823.rs @@ -0,0 +1,9 @@ +//@ known-bug: #140823 + +struct Container { + data: T, +} + +fn ice(callback: Box)>) { + let fails: Box)> = callback; +} diff --git a/tests/crashes/140850.rs b/tests/crashes/140850.rs new file mode 100644 index 0000000000000..fd26097deda00 --- /dev/null +++ b/tests/crashes/140850.rs @@ -0,0 +1,7 @@ +//@ known-bug: #140850 +//@ compile-flags: -Zvalidate-mir +fn A() -> impl { + while A() {} + loop {} +} +fn main() {} diff --git a/tests/crashes/140860.rs b/tests/crashes/140860.rs new file mode 100644 index 0000000000000..04da6bd832c3a --- /dev/null +++ b/tests/crashes/140860.rs @@ -0,0 +1,10 @@ +//@ known-bug: #140860 +#![feature(min_generic_const_args)] +#![feature(unsized_const_params)] +#![feature(with_negative_coherence, negative_impls)] +trait a < const b : &'static str> {} trait c {} struct d< e >(e); +impl c for e where e: a<""> {} +impl c for d {} +impl !a for e {} +const f : &str = ""; +fn main() {} diff --git a/tests/crashes/140884.rs b/tests/crashes/140884.rs new file mode 100644 index 0000000000000..6840760933a39 --- /dev/null +++ b/tests/crashes/140884.rs @@ -0,0 +1,6 @@ +//@ known-bug: #140884 +//@ needs-rustc-debug-assertions + +fn a() { + extern "" {} +} diff --git a/tests/crashes/140891.rs b/tests/crashes/140891.rs new file mode 100644 index 0000000000000..421919403eff2 --- /dev/null +++ b/tests/crashes/140891.rs @@ -0,0 +1,6 @@ +//@ known-bug: #140891 +struct A {} +impl Iterator for A { + fn next() -> [(); std::mem::size_of::>] {} +} +fn main() {} diff --git a/tests/crashes/140974.rs b/tests/crashes/140974.rs new file mode 100644 index 0000000000000..ac1051a64fd31 --- /dev/null +++ b/tests/crashes/140974.rs @@ -0,0 +1,14 @@ +//@ known-bug: #140974 +//@edition:2021 +#![feature(async_drop)] +use core::future::AsyncDrop; + +async fn fun(_: HasIncompleteAsyncDrop) {} + +struct HasIncompleteAsyncDrop; +impl Drop for HasIncompleteAsyncDrop { + fn drop(&mut self) {} +} +impl AsyncDrop for HasIncompleteAsyncDrop { + // not implemented yet.. +} diff --git a/tests/crashes/140975.rs b/tests/crashes/140975.rs new file mode 100644 index 0000000000000..e11dd40612cef --- /dev/null +++ b/tests/crashes/140975.rs @@ -0,0 +1,22 @@ +//@ known-bug: #140975 +//@ compile-flags: --crate-type lib -Zvalidate-mir +//@ edition: 2021 +#![feature(async_drop)] +use std::{future::AsyncDrop, pin::Pin}; + +struct HasAsyncDrop ; +impl Drop for HasAsyncDrop { + fn drop(&mut self) {} +} +impl AsyncDrop for HasAsyncDrop { + async fn drop(self: Pin<&mut Self>) {} +} + +struct Holder { + inner: HasAsyncDrop, +} +async fn bar() { + Holder { + inner: HasAsyncDrop + }; +} diff --git a/tests/crashes/141124.rs b/tests/crashes/141124.rs new file mode 100644 index 0000000000000..38a2a55e1c4a3 --- /dev/null +++ b/tests/crashes/141124.rs @@ -0,0 +1,16 @@ +//@ known-bug: #141124 +struct S; +trait SimpleTrait {} +trait TraitAssoc { + type Assoc; +} + +impl TraitAssoc for T +where + T: SimpleTrait, +{ + type Assoc = <(T,) as TraitAssoc>::Assoc; +} +impl SimpleTrait for ::Assoc {} + +pub fn main() {} diff --git a/tests/crashes/141143.rs b/tests/crashes/141143.rs new file mode 100644 index 0000000000000..a4aa2f19a6c75 --- /dev/null +++ b/tests/crashes/141143.rs @@ -0,0 +1,13 @@ +//@ known-bug: #141143 +trait TypedClient { + fn publish_typed(&self) -> impl Sized + where + F: Clone; +} +impl TypedClient for () { + fn publish_typed(&self) -> impl Sized {} +} + +fn main() { + ().publish_typed(); +} From c801c569dc2b264ee4b6db024155093ea1d616d0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 18 May 2025 15:42:35 +0000 Subject: [PATCH 2424/4206] Do not run `rustfmt` on the `compiler-builtins` subtree This will get checked in the compiler-builtins repository. The rules are slightly different from rust-lang/rust since `use_small_heuristics = "Max"` tends to create difficult to read output with math-heavy code (e.g. multiple `if` statements with numbers are small enough that they sometimes get collapsed into a single line). --- rustfmt.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/rustfmt.toml b/rustfmt.toml index d9857a7e3e788..689e390b990c2 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -29,6 +29,7 @@ ignore = [ # Do not format submodules. "library/backtrace", + "library/compiler-builtins", "library/portable-simd", "library/stdarch", "src/doc/book", From eb11adc7b05c973889a9fcb2e3e474df855dc785 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 May 2025 17:27:54 +0200 Subject: [PATCH 2425/4206] bump rustc-build-sysroot --- src/tools/miri/cargo-miri/Cargo.lock | 4 ++-- src/tools/miri/cargo-miri/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/miri/cargo-miri/Cargo.lock b/src/tools/miri/cargo-miri/Cargo.lock index bd4ca2860f35a..c1915ae617e87 100644 --- a/src/tools/miri/cargo-miri/Cargo.lock +++ b/src/tools/miri/cargo-miri/Cargo.lock @@ -208,9 +208,9 @@ dependencies = [ [[package]] name = "rustc-build-sysroot" -version = "0.5.4" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6d984a9db43148467059309bd1e5ad577085162f695d9fe2cf3543aeb25cd38" +checksum = "10edc2e4393515193bd766e2f6c050b0536a68e56f2b6d56c07ababfdc114ff0" dependencies = [ "anyhow", "rustc_version", diff --git a/src/tools/miri/cargo-miri/Cargo.toml b/src/tools/miri/cargo-miri/Cargo.toml index 23048914af18e..5c579b2a77d62 100644 --- a/src/tools/miri/cargo-miri/Cargo.toml +++ b/src/tools/miri/cargo-miri/Cargo.toml @@ -18,7 +18,7 @@ directories = "6" rustc_version = "0.4" serde_json = "1.0.40" cargo_metadata = "0.19" -rustc-build-sysroot = "0.5.4" +rustc-build-sysroot = "0.5.7" # Enable some feature flags that dev-dependencies need but dependencies # do not. This makes `./miri install` after `./miri build` faster. From 178e09ed3705ee7eed64cfecb02173e9f54d82b0 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Sun, 18 May 2025 18:14:43 +0200 Subject: [PATCH 2426/4206] Remove rustc_attr_data_structures re-export from rustc_attr_parsing --- Cargo.lock | 6 ++++++ compiler/rustc_attr_parsing/src/lib.rs | 4 ++-- compiler/rustc_builtin_macros/Cargo.toml | 1 + .../src/deriving/generic/mod.rs | 3 ++- compiler/rustc_codegen_gcc/src/attributes.rs | 4 ++-- compiler/rustc_codegen_gcc/src/callee.rs | 2 +- compiler/rustc_codegen_gcc/src/lib.rs | 2 +- compiler/rustc_codegen_ssa/Cargo.toml | 1 + .../rustc_codegen_ssa/src/back/symbol_export.rs | 2 +- compiler/rustc_codegen_ssa/src/base.rs | 2 +- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 4 ++-- compiler/rustc_codegen_ssa/src/mir/naked_asm.rs | 2 +- compiler/rustc_codegen_ssa/src/target_features.rs | 2 +- compiler/rustc_expand/Cargo.toml | 1 + compiler/rustc_expand/src/base.rs | 2 +- compiler/rustc_expand/src/mbe/macro_rules.rs | 2 +- compiler/rustc_lint/Cargo.toml | 1 + compiler/rustc_lint/src/nonstandard_style.rs | 3 ++- compiler/rustc_lint/src/types/literal.rs | 12 ++++++------ compiler/rustc_metadata/Cargo.toml | 1 + .../src/rmeta/decoder/cstore_impl.rs | 2 +- compiler/rustc_metadata/src/rmeta/mod.rs | 12 ++++++------ compiler/rustc_middle/src/middle/stability.rs | 8 ++++---- compiler/rustc_resolve/Cargo.toml | 1 + compiler/rustc_resolve/src/macros.rs | 2 +- src/librustdoc/clean/types.rs | 14 ++++++++------ src/librustdoc/formats/cache.rs | 2 +- src/librustdoc/html/format.rs | 2 +- src/librustdoc/html/render/mod.rs | 2 +- src/librustdoc/json/conversions.rs | 6 +++--- src/librustdoc/lib.rs | 1 + src/librustdoc/passes/propagate_stability.rs | 2 +- src/tools/clippy/clippy_lints/src/approx_const.rs | 2 +- .../clippy_lints/src/attrs/repr_attributes.rs | 2 +- src/tools/clippy/clippy_lints/src/booleans.rs | 2 +- .../src/default_union_representation.rs | 2 +- .../src/doc/suspicious_doc_comments.rs | 2 +- .../src/doc/too_long_first_doc_paragraph.rs | 2 +- src/tools/clippy/clippy_lints/src/format_args.rs | 2 +- .../clippy/clippy_lints/src/incompatible_msrv.rs | 2 +- src/tools/clippy/clippy_lints/src/lib.rs | 2 +- .../clippy/clippy_lints/src/std_instead_of_core.rs | 2 +- src/tools/clippy/clippy_lints_internal/src/lib.rs | 1 + src/tools/clippy/clippy_utils/src/lib.rs | 3 ++- src/tools/clippy/clippy_utils/src/msrvs.rs | 3 ++- .../clippy_utils/src/qualify_min_const_fn.rs | 4 ++-- src/tools/miri/src/lib.rs | 2 +- src/tools/miri/src/machine.rs | 2 +- 48 files changed, 83 insertions(+), 63 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e3ef0189c1205..0b34a0800acb2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3376,6 +3376,7 @@ version = "0.0.0" dependencies = [ "rustc_ast", "rustc_ast_pretty", + "rustc_attr_data_structures", "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", @@ -3453,6 +3454,7 @@ dependencies = [ "rustc_abi", "rustc_arena", "rustc_ast", + "rustc_attr_data_structures", "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", @@ -3666,6 +3668,7 @@ dependencies = [ "rustc_ast", "rustc_ast_passes", "rustc_ast_pretty", + "rustc_attr_data_structures", "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", @@ -3936,6 +3939,7 @@ dependencies = [ "rustc_abi", "rustc_ast", "rustc_ast_pretty", + "rustc_attr_data_structures", "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", @@ -4009,6 +4013,7 @@ dependencies = [ "odht", "rustc_abi", "rustc_ast", + "rustc_attr_data_structures", "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", @@ -4329,6 +4334,7 @@ dependencies = [ "rustc_arena", "rustc_ast", "rustc_ast_pretty", + "rustc_attr_data_structures", "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 874fccf7ff6da..dbde90eab25e1 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -60,7 +60,8 @@ //! `#[stable(...)]` and `#[unstable()]` cannot occur together, and both semantically define //! a "stability" of an item. So, the stability attribute has an //! [`AttributeParser`](attributes::AttributeParser) that recognizes both the `#[stable()]` -//! and `#[unstable()]` syntactic attributes, and at the end produce a single [`AttributeKind::Stability`]. +//! and `#[unstable()]` syntactic attributes, and at the end produce a single +//! [`AttributeKind::Stability`](rustc_attr_data_structures::AttributeKind::Stability). //! //! As a rule of thumb, when a syntactical attribute can be applied more than once, they should be //! combined into a single semantic attribute. For example: @@ -92,6 +93,5 @@ mod session_diagnostics; pub use attributes::cfg::*; pub use attributes::util::{find_crate_name, is_builtin_attr, parse_version}; pub use context::{AttributeParser, OmitDoc}; -pub use rustc_attr_data_structures::*; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml index 1289d21308b7a..5c1ae90f7298f 100644 --- a/compiler/rustc_builtin_macros/Cargo.toml +++ b/compiler/rustc_builtin_macros/Cargo.toml @@ -10,6 +10,7 @@ doctest = false # tidy-alphabetical-start rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index d9aac54ee73c7..9aa53f9e4f73b 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -185,7 +185,8 @@ use rustc_ast::{ self as ast, AnonConst, BindingMode, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics, Mutability, PatKind, VariantData, }; -use rustc_attr_parsing::{AttributeKind, AttributeParser, ReprPacked}; +use rustc_attr_data_structures::{AttributeKind, ReprPacked}; +use rustc_attr_parsing::AttributeParser; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_hir::Attribute; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs index 69b04dd579693..3568989a262e3 100644 --- a/compiler/rustc_codegen_gcc/src/attributes.rs +++ b/compiler/rustc_codegen_gcc/src/attributes.rs @@ -2,8 +2,8 @@ use gccjit::FnAttribute; use gccjit::Function; #[cfg(feature = "master")] -use rustc_attr_parsing::InlineAttr; -use rustc_attr_parsing::InstructionSetAttr; +use rustc_attr_data_structures::InlineAttr; +use rustc_attr_data_structures::InstructionSetAttr; #[cfg(feature = "master")] use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::ty; diff --git a/compiler/rustc_codegen_gcc/src/callee.rs b/compiler/rustc_codegen_gcc/src/callee.rs index c133ae4fcdd2a..c8130b7c01068 100644 --- a/compiler/rustc_codegen_gcc/src/callee.rs +++ b/compiler/rustc_codegen_gcc/src/callee.rs @@ -106,7 +106,7 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) // This is a monomorphization of a generic function. if !(cx.tcx.sess.opts.share_generics() || tcx.codegen_fn_attrs(instance_def_id).inline - == rustc_attr_parsing::InlineAttr::Never) + == rustc_attr_data_structures::InlineAttr::Never) { // When not sharing generics, all instances are in the same // crate and have hidden visibility. diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 2c5a787168381..fb8061a4abbcb 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -37,7 +37,7 @@ extern crate tracing; extern crate rustc_abi; extern crate rustc_apfloat; extern crate rustc_ast; -extern crate rustc_attr_parsing; +extern crate rustc_attr_data_structures; extern crate rustc_codegen_ssa; extern crate rustc_data_structures; extern crate rustc_errors; diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 97eebffd1fe8e..816dec5431d6e 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -19,6 +19,7 @@ regex = "1.4" rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 06ba5b4f6a752..9e9029d16b158 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -370,7 +370,7 @@ fn exported_symbols_provider_local<'tcx>( if !tcx.sess.opts.share_generics() { if tcx.codegen_fn_attrs(mono_item.def_id()).inline - == rustc_attr_parsing::InlineAttr::Never + == rustc_attr_data_structures::InlineAttr::Never { // this is OK, we explicitly allow sharing inline(never) across crates even // without share-generics. diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 93cbd4cbb7cc9..3732f2d891569 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -7,7 +7,7 @@ use itertools::Itertools; use rustc_abi::FIRST_VARIANT; use rustc_ast as ast; use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, AllocatorKind, global_fn_name}; -use rustc_attr_parsing::OptimizeAttr; +use rustc_attr_data_structures::OptimizeAttr; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_data_structures::sync::{IntoDynSyncSend, par_map}; diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 5d09e62f2742d..63cd5f0c364a3 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -3,8 +3,8 @@ use std::str::FromStr; use rustc_abi::ExternAbi; use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode}; use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr}; -use rustc_attr_parsing::ReprAttr::ReprAlign; -use rustc_attr_parsing::{AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr}; +use rustc_attr_data_structures::ReprAttr::ReprAlign; +use rustc_attr_data_structures::{AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index d2a687359e0bc..46fb9a895133b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -1,5 +1,5 @@ use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind}; -use rustc_attr_parsing::InstructionSetAttr; +use rustc_attr_data_structures::InstructionSetAttr; use rustc_hir::def_id::DefId; use rustc_middle::mir::mono::{Linkage, MonoItemData, Visibility}; use rustc_middle::mir::{InlineAsmOperand, START_BLOCK}; diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 8058cd1b1783a..3ecea522837a1 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -1,4 +1,4 @@ -use rustc_attr_parsing::InstructionSetAttr; +use rustc_attr_data_structures::InstructionSetAttr; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::Applicability; diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml index 0ba139ea5cc57..e8fd2f54d76cb 100644 --- a/compiler/rustc_expand/Cargo.toml +++ b/compiler/rustc_expand/Cargo.toml @@ -12,6 +12,7 @@ doctest = false rustc_ast = { path = "../rustc_ast" } rustc_ast_passes = { path = "../rustc_ast_passes" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index f5eaf7d616b22..55751aa49089b 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -11,7 +11,7 @@ use rustc_ast::token::MetaVarKind; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind}; -use rustc_attr_parsing::{AttributeKind, Deprecation, Stability, find_attr}; +use rustc_attr_data_structures::{AttributeKind, Deprecation, Stability, find_attr}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync; use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult}; diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 93604a149f1d9..783f061ec6c58 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -10,7 +10,7 @@ use rustc_ast::token::{self, NonterminalKind, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream}; use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId}; use rustc_ast_pretty::pprust; -use rustc_attr_parsing::{AttributeKind, find_attr}; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::{Applicability, Diag, ErrorGuaranteed}; use rustc_feature::Features; diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml index 7718f16984dab..64751eaf1feae 100644 --- a/compiler/rustc_lint/Cargo.toml +++ b/compiler/rustc_lint/Cargo.toml @@ -8,6 +8,7 @@ edition = "2024" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index d1138e8f1fa53..048d377b78fbc 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -1,5 +1,6 @@ use rustc_abi::ExternAbi; -use rustc_attr_parsing::{AttributeKind, AttributeParser, ReprAttr}; +use rustc_attr_data_structures::{AttributeKind, ReprAttr}; +use rustc_attr_parsing::AttributeParser; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::FnKind; use rustc_hir::{AttrArgs, AttrItem, Attribute, GenericParamKind, PatExprKind, PatKind}; diff --git a/compiler/rustc_lint/src/types/literal.rs b/compiler/rustc_lint/src/types/literal.rs index 7cb00262b6ffa..d44f45177bde0 100644 --- a/compiler/rustc_lint/src/types/literal.rs +++ b/compiler/rustc_lint/src/types/literal.rs @@ -5,7 +5,7 @@ use rustc_middle::ty::Ty; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::{bug, ty}; use rustc_span::Span; -use {rustc_ast as ast, rustc_attr_parsing as attr, rustc_hir as hir}; +use {rustc_ast as ast, rustc_attr_data_structures as attrs, rustc_hir as hir}; use crate::LateContext; use crate::context::LintContext; @@ -131,18 +131,18 @@ fn report_bin_hex_error( cx: &LateContext<'_>, hir_id: HirId, span: Span, - ty: attr::IntType, + ty: attrs::IntType, size: Size, repr_str: String, val: u128, negative: bool, ) { let (t, actually) = match ty { - attr::IntType::SignedInt(t) => { + attrs::IntType::SignedInt(t) => { let actually = if negative { -(size.sign_extend(val)) } else { size.sign_extend(val) }; (t.name_str(), actually.to_string()) } - attr::IntType::UnsignedInt(t) => { + attrs::IntType::UnsignedInt(t) => { let actually = size.truncate(val); (t.name_str(), actually.to_string()) } @@ -264,7 +264,7 @@ fn lint_int_literal<'tcx>( cx, hir_id, span, - attr::IntType::SignedInt(ty::ast_int_ty(t)), + attrs::IntType::SignedInt(ty::ast_int_ty(t)), Integer::from_int_ty(cx, t).size(), repr_str, v, @@ -336,7 +336,7 @@ fn lint_uint_literal<'tcx>( cx, hir_id, span, - attr::IntType::UnsignedInt(ty::ast_uint_ty(t)), + attrs::IntType::UnsignedInt(ty::ast_uint_ty(t)), Integer::from_uint_ty(cx, t).size(), repr_str, lit_val, diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index 26878c488b74a..cfe412e99d8d5 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -10,6 +10,7 @@ libloading = "0.8.0" odht = { version = "0.3.1", features = ["nightly"] } rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 76bae39ef8c00..97d3156573367 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -2,7 +2,7 @@ use std::any::Any; use std::mem; use std::sync::Arc; -use rustc_attr_parsing::Deprecation; +use rustc_attr_data_structures::Deprecation; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index c86cf567283fe..d3d928aa88e5c 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -40,7 +40,7 @@ use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextKey}; use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Ident, Span, Symbol}; use rustc_target::spec::{PanicStrategy, TargetTuple}; use table::TableBuilder; -use {rustc_ast as ast, rustc_attr_parsing as attr, rustc_hir as hir}; +use {rustc_ast as ast, rustc_attr_data_structures as attrs, rustc_hir as hir}; use crate::creader::CrateMetadataRef; @@ -200,7 +200,7 @@ type ExpnHashTable = LazyTable>>; #[derive(MetadataEncodable, MetadataDecodable)] pub(crate) struct ProcMacroData { proc_macro_decls_static: DefIndex, - stability: Option, + stability: Option, macros: LazyArray, } @@ -422,10 +422,10 @@ define_tables! { safety: Table, def_span: Table>, def_ident_span: Table>, - lookup_stability: Table>, - lookup_const_stability: Table>, - lookup_default_body_stability: Table>, - lookup_deprecation_entry: Table>, + lookup_stability: Table>, + lookup_const_stability: Table>, + lookup_default_body_stability: Table>, + lookup_deprecation_entry: Table>, explicit_predicates_of: Table>>, generics_of: Table>, type_of: Table>>>, diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 9912e659b05f5..454ab8c107f0a 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -5,7 +5,7 @@ use std::num::NonZero; use rustc_ast::NodeId; use rustc_attr_data_structures::{ - self as attr, ConstStability, DefaultBodyStability, DeprecatedSince, Deprecation, Stability, + self as attrs, ConstStability, DefaultBodyStability, DeprecatedSince, Deprecation, Stability, }; use rustc_data_structures::unord::UnordMap; use rustc_errors::{Applicability, Diag, EmissionGuarantee}; @@ -411,7 +411,7 @@ impl<'tcx> TyCtxt<'tcx> { match stability { Some(Stability { - level: attr::StabilityLevel::Unstable { reason, issue, is_soft, implied_by }, + level: attrs::StabilityLevel::Unstable { reason, issue, is_soft, implied_by }, feature, .. }) => { @@ -494,7 +494,7 @@ impl<'tcx> TyCtxt<'tcx> { match stability { Some(DefaultBodyStability { - level: attr::StabilityLevel::Unstable { reason, issue, is_soft, .. }, + level: attrs::StabilityLevel::Unstable { reason, issue, is_soft, .. }, feature, }) => { if span.allows_unstable(feature) { @@ -643,7 +643,7 @@ impl<'tcx> TyCtxt<'tcx> { match stability { Some(ConstStability { - level: attr::StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. }, + level: attrs::StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. }, feature, .. }) => { diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index 0fcc3d8f6b3aa..a97e0eaa9c631 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -11,6 +11,7 @@ pulldown-cmark = { version = "0.11", features = ["html"], default-features = fal rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index c58f84805720d..ee905065b966b 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -8,7 +8,7 @@ use std::sync::Arc; use rustc_ast::expand::StrippedCfgItem; use rustc_ast::{self as ast, Crate, NodeId, attr}; use rustc_ast_pretty::pprust; -use rustc_attr_parsing::StabilityLevel; +use rustc_attr_data_structures::StabilityLevel; use rustc_data_structures::intern::Interned; use rustc_errors::{Applicability, DiagCtxtHandle, StashKey}; use rustc_expand::base::{ diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 15890fff0c336..e7ff87793af5f 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -5,7 +5,9 @@ use std::{fmt, iter}; use arrayvec::ArrayVec; use rustc_abi::{ExternAbi, VariantIdx}; -use rustc_attr_parsing::{AttributeKind, ConstStability, Deprecation, Stability, StableSince}; +use rustc_attr_data_structures::{ + AttributeKind, ConstStability, Deprecation, Stability, StableSince, +}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; @@ -403,13 +405,13 @@ impl Item { // versions; the paths that are exposed through it are "deprecated" because they // were never supposed to work at all. let stab = self.stability(tcx)?; - if let rustc_attr_parsing::StabilityLevel::Stable { + if let rustc_attr_data_structures::StabilityLevel::Stable { allowed_through_unstable_modules: Some(note), .. } = stab.level { Some(Deprecation { - since: rustc_attr_parsing::DeprecatedSince::Unspecified, + since: rustc_attr_data_structures::DeprecatedSince::Unspecified, note: Some(note), suggestion: None, }) @@ -777,9 +779,9 @@ impl Item { // don't want it it `Item::attrs`. None } - rustc_hir::Attribute::Parsed(rustc_attr_parsing::AttributeKind::Repr( - .., - )) => { + rustc_hir::Attribute::Parsed( + rustc_attr_data_structures::AttributeKind::Repr(..), + ) => { // We have separate pretty-printing logic for `#[repr(..)]` attributes. // For example, there are circumstances where `#[repr(transparent)]` // is applied but should not be publicly shown in rustdoc diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 19402004ed59c..4989bd718c9f9 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -1,6 +1,6 @@ use std::mem; -use rustc_attr_parsing::StabilityLevel; +use rustc_attr_data_structures::StabilityLevel; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet}; use rustc_middle::ty::{self, TyCtxt}; diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 299fd6b9adbb0..1ec0212100947 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -15,7 +15,7 @@ use std::slice; use itertools::Either; use rustc_abi::ExternAbi; -use rustc_attr_parsing::{ConstStability, StabilityLevel, StableSince}; +use rustc_attr_data_structures::{ConstStability, StabilityLevel, StableSince}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::DefKind; diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index beaa6497b8caa..3492df9995593 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -49,7 +49,7 @@ use std::{fs, str}; use askama::Template; use itertools::Either; -use rustc_attr_parsing::{ +use rustc_attr_data_structures::{ ConstStability, DeprecatedSince, Deprecation, RustcVersion, StabilityLevel, StableSince, }; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index f446c9fbbd8b3..705f9b2202c60 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -6,7 +6,7 @@ use rustc_abi::ExternAbi; use rustc_ast::ast; -use rustc_attr_parsing::DeprecatedSince; +use rustc_attr_data_structures::{self as attrs, DeprecatedSince}; use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefId; use rustc_metadata::rendered_const; @@ -153,8 +153,8 @@ where } } -pub(crate) fn from_deprecation(deprecation: rustc_attr_parsing::Deprecation) -> Deprecation { - let rustc_attr_parsing::Deprecation { since, note, suggestion: _ } = deprecation; +pub(crate) fn from_deprecation(deprecation: attrs::Deprecation) -> Deprecation { + let attrs::Deprecation { since, note, suggestion: _ } = deprecation; let since = match since { DeprecatedSince::RustcVersion(version) => Some(version.to_string()), DeprecatedSince::Future => Some("TBD".to_owned()), diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index bca40b8117bdb..d40498f9de240 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -37,6 +37,7 @@ extern crate pulldown_cmark; extern crate rustc_abi; extern crate rustc_ast; extern crate rustc_ast_pretty; +extern crate rustc_attr_data_structures; extern crate rustc_attr_parsing; extern crate rustc_data_structures; extern crate rustc_driver; diff --git a/src/librustdoc/passes/propagate_stability.rs b/src/librustdoc/passes/propagate_stability.rs index fdab2b087799a..7b3da8d7c0fbd 100644 --- a/src/librustdoc/passes/propagate_stability.rs +++ b/src/librustdoc/passes/propagate_stability.rs @@ -6,7 +6,7 @@ //! [`core::error`] module is marked as stable since 1.81.0, so we want to show //! [`core::error::Error`] as stable since 1.81.0 as well. -use rustc_attr_parsing::{Stability, StabilityLevel}; +use rustc_attr_data_structures::{Stability, StabilityLevel}; use rustc_hir::def_id::CRATE_DEF_ID; use crate::clean::{Crate, Item, ItemId, ItemKind}; diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs index 9ae746c13b261..852e48cbcaeec 100644 --- a/src/tools/clippy/clippy_lints/src/approx_const.rs +++ b/src/tools/clippy/clippy_lints/src/approx_const.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::msrvs::{self, Msrv}; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; -use rustc_attr_parsing::RustcVersion; +use rustc_attr_data_structures::RustcVersion; use rustc_hir::{HirId, Lit}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; diff --git a/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs index df01c7fde1819..05d8a8c26d1c1 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs @@ -1,4 +1,4 @@ -use rustc_attr_parsing::{AttributeKind, ReprAttr, find_attr}; +use rustc_attr_data_structures::{AttributeKind, ReprAttr, find_attr}; use rustc_hir::Attribute; use rustc_lint::LateContext; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs index bc6ba84772b3d..7c6fd91ca67f7 100644 --- a/src/tools/clippy/clippy_lints/src/booleans.rs +++ b/src/tools/clippy/clippy_lints/src/booleans.rs @@ -6,7 +6,7 @@ use clippy_utils::source::SpanRangeExt; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use rustc_ast::ast::LitKind; -use rustc_attr_parsing::RustcVersion; +use rustc_attr_data_structures::RustcVersion; use rustc_errors::Applicability; use rustc_hir::intravisit::{FnKind, Visitor, walk_expr}; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp}; diff --git a/src/tools/clippy/clippy_lints/src/default_union_representation.rs b/src/tools/clippy/clippy_lints/src/default_union_representation.rs index 7c64bf46e7bd2..615421f3a40d0 100644 --- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs +++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use rustc_attr_parsing::{AttributeKind, ReprAttr, find_attr}; +use rustc_attr_data_structures::{AttributeKind, ReprAttr, find_attr}; use rustc_hir::{HirId, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; diff --git a/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs b/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs index 9637546b86800..ebfc9972aefd6 100644 --- a/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs +++ b/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::AttrStyle; use rustc_ast::token::CommentKind; -use rustc_attr_parsing::AttributeKind; +use rustc_attr_data_structures::AttributeKind; use rustc_errors::Applicability; use rustc_hir::Attribute; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs b/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs index dc6cbb4254302..7f7224ecfc654 100644 --- a/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs +++ b/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs @@ -1,4 +1,4 @@ -use rustc_attr_parsing::AttributeKind; +use rustc_attr_data_structures::AttributeKind; use rustc_errors::Applicability; use rustc_hir::{Attribute, Item, ItemKind}; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs index 8a3f8e1c5874d..a26e736c7ae35 100644 --- a/src/tools/clippy/clippy_lints/src/format_args.rs +++ b/src/tools/clippy/clippy_lints/src/format_args.rs @@ -15,7 +15,7 @@ use rustc_ast::{ FormatArgPosition, FormatArgPositionKind, FormatArgsPiece, FormatArgumentKind, FormatCount, FormatOptions, FormatPlaceholder, FormatTrait, }; -use rustc_attr_parsing::RustcVersion; +use rustc_attr_data_structures::RustcVersion; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_errors::SuggestionStyle::{CompletelyHidden, ShowCode}; diff --git a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs index e55edb1fcaa81..5d0bd3e8ca303 100644 --- a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs +++ b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_in_test; use clippy_utils::msrvs::Msrv; -use rustc_attr_parsing::{RustcVersion, StabilityLevel, StableSince}; +use rustc_attr_data_structures::{RustcVersion, StabilityLevel, StableSince}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{Expr, ExprKind, HirId, QPath}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index bc7fc60827a0b..308bb9f0e263a 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -37,7 +37,7 @@ extern crate rustc_abi; extern crate rustc_arena; extern crate rustc_ast; extern crate rustc_ast_pretty; -extern crate rustc_attr_parsing; +extern crate rustc_attr_data_structures; extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs index d68ac8bab1286..3d39386ecf909 100644 --- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs +++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; use clippy_utils::msrvs::Msrv; -use rustc_attr_parsing::{StabilityLevel, StableSince}; +use rustc_attr_data_structures::{StabilityLevel, StableSince}; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::def_id::DefId; diff --git a/src/tools/clippy/clippy_lints_internal/src/lib.rs b/src/tools/clippy/clippy_lints_internal/src/lib.rs index b02d378619cab..4d1e56fd7a52b 100644 --- a/src/tools/clippy/clippy_lints_internal/src/lib.rs +++ b/src/tools/clippy/clippy_lints_internal/src/lib.rs @@ -20,6 +20,7 @@ #![allow(clippy::missing_clippy_version_attribute)] extern crate rustc_ast; +extern crate rustc_attr_data_structures; extern crate rustc_attr_parsing; extern crate rustc_data_structures; extern crate rustc_errors; diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 187dfa4dda845..30a7173320e12 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -30,6 +30,7 @@ // (Currently there is no way to opt into sysroot crates without `extern crate`.) extern crate rustc_abi; extern crate rustc_ast; +extern crate rustc_attr_data_structures; extern crate rustc_attr_parsing; extern crate rustc_const_eval; extern crate rustc_data_structures; @@ -91,7 +92,7 @@ use std::sync::{Mutex, MutexGuard, OnceLock}; use itertools::Itertools; use rustc_abi::Integer; use rustc_ast::ast::{self, LitKind, RangeLimits}; -use rustc_attr_parsing::{AttributeKind, find_attr}; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::packed::Pu128; use rustc_data_structures::unhash::UnhashMap; diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs index 19061b574ff88..226d70a57d885 100644 --- a/src/tools/clippy/clippy_utils/src/msrvs.rs +++ b/src/tools/clippy/clippy_utils/src/msrvs.rs @@ -1,7 +1,8 @@ use crate::sym; use rustc_ast::Attribute; use rustc_ast::attr::AttributeExt; -use rustc_attr_parsing::{RustcVersion, parse_version}; +use rustc_attr_data_structures::RustcVersion; +use rustc_attr_parsing::parse_version; use rustc_lint::LateContext; use rustc_session::Session; use rustc_span::Symbol; diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 5d0401010db6a..45da266fd8a9a 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -5,7 +5,7 @@ use crate::msrvs::{self, Msrv}; use hir::LangItem; -use rustc_attr_parsing::{RustcVersion, StableSince}; +use rustc_attr_data_structures::{RustcVersion, StableSince}; use rustc_const_eval::check_consts::ConstCx; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -404,7 +404,7 @@ fn is_stable_const_fn(cx: &LateContext<'_>, def_id: DefId, msrv: Msrv) -> bool { .and_then(|trait_def_id| cx.tcx.lookup_const_stability(trait_def_id)) }) .is_none_or(|const_stab| { - if let rustc_attr_parsing::StabilityLevel::Stable { since, .. } = const_stab.level { + if let rustc_attr_data_structures::StabilityLevel::Stable { since, .. } = const_stab.level { // Checking MSRV is manually necessary because `rustc` has no such concept. This entire // function could be removed if `rustc` provided a MSRV-aware version of `is_stable_const_fn`. // as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262. diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 58b93ae82a1e4..db2bf423c0c7c 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -61,7 +61,7 @@ extern crate tracing; extern crate rustc_abi; extern crate rustc_apfloat; extern crate rustc_ast; -extern crate rustc_attr_parsing; +extern crate rustc_attr_data_structures; extern crate rustc_const_eval; extern crate rustc_data_structures; extern crate rustc_errors; diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 6060d41dac594..31b8eedc29a9d 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -13,7 +13,7 @@ use rand::rngs::StdRng; use rand::{Rng, SeedableRng}; use rustc_abi::{Align, ExternAbi, Size}; use rustc_apfloat::{Float, FloatConvert}; -use rustc_attr_parsing::InlineAttr; +use rustc_attr_data_structures::InlineAttr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; #[allow(unused)] use rustc_data_structures::static_assert_size; From 035146e398d7ef87531c690856d2547f7929377c Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Sun, 18 May 2025 18:14:43 +0200 Subject: [PATCH 2427/4206] Remove rustc_attr_data_structures re-export from rustc_attr_parsing --- clippy_lints/src/approx_const.rs | 2 +- clippy_lints/src/attrs/repr_attributes.rs | 2 +- clippy_lints/src/booleans.rs | 2 +- clippy_lints/src/default_union_representation.rs | 2 +- clippy_lints/src/doc/suspicious_doc_comments.rs | 2 +- clippy_lints/src/doc/too_long_first_doc_paragraph.rs | 2 +- clippy_lints/src/format_args.rs | 2 +- clippy_lints/src/incompatible_msrv.rs | 2 +- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/std_instead_of_core.rs | 2 +- clippy_lints_internal/src/lib.rs | 1 + clippy_utils/src/lib.rs | 3 ++- clippy_utils/src/msrvs.rs | 3 ++- clippy_utils/src/qualify_min_const_fn.rs | 4 ++-- 14 files changed, 17 insertions(+), 14 deletions(-) diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index 9ae746c13b261..852e48cbcaeec 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::msrvs::{self, Msrv}; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; -use rustc_attr_parsing::RustcVersion; +use rustc_attr_data_structures::RustcVersion; use rustc_hir::{HirId, Lit}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; diff --git a/clippy_lints/src/attrs/repr_attributes.rs b/clippy_lints/src/attrs/repr_attributes.rs index df01c7fde1819..05d8a8c26d1c1 100644 --- a/clippy_lints/src/attrs/repr_attributes.rs +++ b/clippy_lints/src/attrs/repr_attributes.rs @@ -1,4 +1,4 @@ -use rustc_attr_parsing::{AttributeKind, ReprAttr, find_attr}; +use rustc_attr_data_structures::{AttributeKind, ReprAttr, find_attr}; use rustc_hir::Attribute; use rustc_lint::LateContext; use rustc_span::Span; diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index bc6ba84772b3d..7c6fd91ca67f7 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -6,7 +6,7 @@ use clippy_utils::source::SpanRangeExt; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use rustc_ast::ast::LitKind; -use rustc_attr_parsing::RustcVersion; +use rustc_attr_data_structures::RustcVersion; use rustc_errors::Applicability; use rustc_hir::intravisit::{FnKind, Visitor, walk_expr}; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp}; diff --git a/clippy_lints/src/default_union_representation.rs b/clippy_lints/src/default_union_representation.rs index 7c64bf46e7bd2..615421f3a40d0 100644 --- a/clippy_lints/src/default_union_representation.rs +++ b/clippy_lints/src/default_union_representation.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use rustc_attr_parsing::{AttributeKind, ReprAttr, find_attr}; +use rustc_attr_data_structures::{AttributeKind, ReprAttr, find_attr}; use rustc_hir::{HirId, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; diff --git a/clippy_lints/src/doc/suspicious_doc_comments.rs b/clippy_lints/src/doc/suspicious_doc_comments.rs index 9637546b86800..ebfc9972aefd6 100644 --- a/clippy_lints/src/doc/suspicious_doc_comments.rs +++ b/clippy_lints/src/doc/suspicious_doc_comments.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::AttrStyle; use rustc_ast::token::CommentKind; -use rustc_attr_parsing::AttributeKind; +use rustc_attr_data_structures::AttributeKind; use rustc_errors::Applicability; use rustc_hir::Attribute; use rustc_lint::LateContext; diff --git a/clippy_lints/src/doc/too_long_first_doc_paragraph.rs b/clippy_lints/src/doc/too_long_first_doc_paragraph.rs index dc6cbb4254302..7f7224ecfc654 100644 --- a/clippy_lints/src/doc/too_long_first_doc_paragraph.rs +++ b/clippy_lints/src/doc/too_long_first_doc_paragraph.rs @@ -1,4 +1,4 @@ -use rustc_attr_parsing::AttributeKind; +use rustc_attr_data_structures::AttributeKind; use rustc_errors::Applicability; use rustc_hir::{Attribute, Item, ItemKind}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 8a3f8e1c5874d..a26e736c7ae35 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -15,7 +15,7 @@ use rustc_ast::{ FormatArgPosition, FormatArgPositionKind, FormatArgsPiece, FormatArgumentKind, FormatCount, FormatOptions, FormatPlaceholder, FormatTrait, }; -use rustc_attr_parsing::RustcVersion; +use rustc_attr_data_structures::RustcVersion; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_errors::SuggestionStyle::{CompletelyHidden, ShowCode}; diff --git a/clippy_lints/src/incompatible_msrv.rs b/clippy_lints/src/incompatible_msrv.rs index e55edb1fcaa81..5d0bd3e8ca303 100644 --- a/clippy_lints/src/incompatible_msrv.rs +++ b/clippy_lints/src/incompatible_msrv.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_in_test; use clippy_utils::msrvs::Msrv; -use rustc_attr_parsing::{RustcVersion, StabilityLevel, StableSince}; +use rustc_attr_data_structures::{RustcVersion, StabilityLevel, StableSince}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{Expr, ExprKind, HirId, QPath}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index bc7fc60827a0b..308bb9f0e263a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -37,7 +37,7 @@ extern crate rustc_abi; extern crate rustc_arena; extern crate rustc_ast; extern crate rustc_ast_pretty; -extern crate rustc_attr_parsing; +extern crate rustc_attr_data_structures; extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs index d68ac8bab1286..3d39386ecf909 100644 --- a/clippy_lints/src/std_instead_of_core.rs +++ b/clippy_lints/src/std_instead_of_core.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; use clippy_utils::msrvs::Msrv; -use rustc_attr_parsing::{StabilityLevel, StableSince}; +use rustc_attr_data_structures::{StabilityLevel, StableSince}; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::def_id::DefId; diff --git a/clippy_lints_internal/src/lib.rs b/clippy_lints_internal/src/lib.rs index b02d378619cab..4d1e56fd7a52b 100644 --- a/clippy_lints_internal/src/lib.rs +++ b/clippy_lints_internal/src/lib.rs @@ -20,6 +20,7 @@ #![allow(clippy::missing_clippy_version_attribute)] extern crate rustc_ast; +extern crate rustc_attr_data_structures; extern crate rustc_attr_parsing; extern crate rustc_data_structures; extern crate rustc_errors; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 187dfa4dda845..30a7173320e12 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -30,6 +30,7 @@ // (Currently there is no way to opt into sysroot crates without `extern crate`.) extern crate rustc_abi; extern crate rustc_ast; +extern crate rustc_attr_data_structures; extern crate rustc_attr_parsing; extern crate rustc_const_eval; extern crate rustc_data_structures; @@ -91,7 +92,7 @@ use std::sync::{Mutex, MutexGuard, OnceLock}; use itertools::Itertools; use rustc_abi::Integer; use rustc_ast::ast::{self, LitKind, RangeLimits}; -use rustc_attr_parsing::{AttributeKind, find_attr}; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::packed::Pu128; use rustc_data_structures::unhash::UnhashMap; diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 19061b574ff88..226d70a57d885 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -1,7 +1,8 @@ use crate::sym; use rustc_ast::Attribute; use rustc_ast::attr::AttributeExt; -use rustc_attr_parsing::{RustcVersion, parse_version}; +use rustc_attr_data_structures::RustcVersion; +use rustc_attr_parsing::parse_version; use rustc_lint::LateContext; use rustc_session::Session; use rustc_span::Symbol; diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 5d0401010db6a..45da266fd8a9a 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -5,7 +5,7 @@ use crate::msrvs::{self, Msrv}; use hir::LangItem; -use rustc_attr_parsing::{RustcVersion, StableSince}; +use rustc_attr_data_structures::{RustcVersion, StableSince}; use rustc_const_eval::check_consts::ConstCx; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -404,7 +404,7 @@ fn is_stable_const_fn(cx: &LateContext<'_>, def_id: DefId, msrv: Msrv) -> bool { .and_then(|trait_def_id| cx.tcx.lookup_const_stability(trait_def_id)) }) .is_none_or(|const_stab| { - if let rustc_attr_parsing::StabilityLevel::Stable { since, .. } = const_stab.level { + if let rustc_attr_data_structures::StabilityLevel::Stable { since, .. } = const_stab.level { // Checking MSRV is manually necessary because `rustc` has no such concept. This entire // function could be removed if `rustc` provided a MSRV-aware version of `is_stable_const_fn`. // as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262. From f36e8f53db9f3015fd872e833427f56af8035275 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Sun, 18 May 2025 18:14:43 +0200 Subject: [PATCH 2428/4206] Remove rustc_attr_data_structures re-export from rustc_attr_parsing --- src/attributes.rs | 4 ++-- src/callee.rs | 2 +- src/lib.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/attributes.rs b/src/attributes.rs index 69b04dd579693..3568989a262e3 100644 --- a/src/attributes.rs +++ b/src/attributes.rs @@ -2,8 +2,8 @@ use gccjit::FnAttribute; use gccjit::Function; #[cfg(feature = "master")] -use rustc_attr_parsing::InlineAttr; -use rustc_attr_parsing::InstructionSetAttr; +use rustc_attr_data_structures::InlineAttr; +use rustc_attr_data_structures::InstructionSetAttr; #[cfg(feature = "master")] use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::ty; diff --git a/src/callee.rs b/src/callee.rs index c133ae4fcdd2a..c8130b7c01068 100644 --- a/src/callee.rs +++ b/src/callee.rs @@ -106,7 +106,7 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) // This is a monomorphization of a generic function. if !(cx.tcx.sess.opts.share_generics() || tcx.codegen_fn_attrs(instance_def_id).inline - == rustc_attr_parsing::InlineAttr::Never) + == rustc_attr_data_structures::InlineAttr::Never) { // When not sharing generics, all instances are in the same // crate and have hidden visibility. diff --git a/src/lib.rs b/src/lib.rs index 2c5a787168381..fb8061a4abbcb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,7 +37,7 @@ extern crate tracing; extern crate rustc_abi; extern crate rustc_apfloat; extern crate rustc_ast; -extern crate rustc_attr_parsing; +extern crate rustc_attr_data_structures; extern crate rustc_codegen_ssa; extern crate rustc_data_structures; extern crate rustc_errors; From 19e967c6b7a592eb0a5955d2ad15a979522b20f5 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Sun, 18 May 2025 14:47:24 +0000 Subject: [PATCH 2429/4206] Add a reason to/remove some `//@no-rustfix` annotations --- tests/ui/assign_ops.fixed | 38 ++++++++- tests/ui/assign_ops.rs | 38 ++++++++- tests/ui/assign_ops.stderr | 30 +++++--- tests/ui/assign_ops2.rs | 77 ------------------- tests/ui/cast.rs | 2 +- tests/ui/cast_size.rs | 2 +- .../complex_conditionals_nested.rs | 2 +- .../ui/checked_unwrap/simple_conditionals.rs | 2 +- tests/ui/comparison_chain.rs | 2 +- tests/ui/dbg_macro/dbg_macro_unfixable.rs | 2 +- .../double_ended_iterator_last_unfixable.rs | 2 +- tests/ui/entry_unfixable.rs | 3 +- tests/ui/entry_unfixable.stderr | 6 +- tests/ui/explicit_counter_loop.rs | 2 +- tests/ui/filter_map_bool_then_unfixable.rs | 3 +- .../ui/filter_map_bool_then_unfixable.stderr | 10 +-- tests/ui/impl_trait_in_params.rs | 2 +- tests/ui/infinite_loop.rs | 2 - tests/ui/infinite_loop.stderr | 22 +++--- tests/ui/infinite_loops.rs | 2 +- tests/ui/into_iter_without_iter.rs | 2 +- tests/ui/iter_out_of_bounds.rs | 2 - tests/ui/iter_out_of_bounds.stderr | 30 ++++---- tests/ui/misrefactored_assign_op.1.fixed | 40 ++++++++++ tests/ui/misrefactored_assign_op.2.fixed | 40 ++++++++++ tests/ui/misrefactored_assign_op.rs | 40 ++++++++++ ....stderr => misrefactored_assign_op.stderr} | 29 +++---- 27 files changed, 267 insertions(+), 165 deletions(-) delete mode 100644 tests/ui/assign_ops2.rs create mode 100644 tests/ui/misrefactored_assign_op.1.fixed create mode 100644 tests/ui/misrefactored_assign_op.2.fixed create mode 100644 tests/ui/misrefactored_assign_op.rs rename tests/ui/{assign_ops2.stderr => misrefactored_assign_op.stderr} (80%) diff --git a/tests/ui/assign_ops.fixed b/tests/ui/assign_ops.fixed index 18f0e04a8807e..429c20f95e919 100644 --- a/tests/ui/assign_ops.fixed +++ b/tests/ui/assign_ops.fixed @@ -1,7 +1,9 @@ +#![allow(clippy::useless_vec)] +#![warn(clippy::assign_op_pattern)] + use core::num::Wrapping; +use std::ops::{Mul, MulAssign}; -#[allow(dead_code, unused_assignments, clippy::useless_vec)] -#[warn(clippy::assign_op_pattern)] fn main() { let mut a = 5; a += 1; @@ -39,3 +41,35 @@ fn main() { v[0] = v[0] + v[1]; let _ = || v[0] = v[0] + v[1]; } + +fn cow_add_assign() { + use std::borrow::Cow; + let mut buf = Cow::Owned(String::from("bar")); + let cows = Cow::Borrowed("foo"); + + // this can be linted + buf += cows.clone(); + //~^ assign_op_pattern + + // this should not as cow Add is not commutative + buf = cows + buf; +} + +// check that we don't lint on op assign impls, because that's just the way to impl them + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct Wrap(i64); + +impl Mul for Wrap { + type Output = Self; + + fn mul(self, rhs: i64) -> Self { + Wrap(self.0 * rhs) + } +} + +impl MulAssign for Wrap { + fn mul_assign(&mut self, rhs: i64) { + *self = *self * rhs + } +} diff --git a/tests/ui/assign_ops.rs b/tests/ui/assign_ops.rs index 8b05c74d86040..480ff07f150ea 100644 --- a/tests/ui/assign_ops.rs +++ b/tests/ui/assign_ops.rs @@ -1,7 +1,9 @@ +#![allow(clippy::useless_vec)] +#![warn(clippy::assign_op_pattern)] + use core::num::Wrapping; +use std::ops::{Mul, MulAssign}; -#[allow(dead_code, unused_assignments, clippy::useless_vec)] -#[warn(clippy::assign_op_pattern)] fn main() { let mut a = 5; a = a + 1; @@ -39,3 +41,35 @@ fn main() { v[0] = v[0] + v[1]; let _ = || v[0] = v[0] + v[1]; } + +fn cow_add_assign() { + use std::borrow::Cow; + let mut buf = Cow::Owned(String::from("bar")); + let cows = Cow::Borrowed("foo"); + + // this can be linted + buf = buf + cows.clone(); + //~^ assign_op_pattern + + // this should not as cow Add is not commutative + buf = cows + buf; +} + +// check that we don't lint on op assign impls, because that's just the way to impl them + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct Wrap(i64); + +impl Mul for Wrap { + type Output = Self; + + fn mul(self, rhs: i64) -> Self { + Wrap(self.0 * rhs) + } +} + +impl MulAssign for Wrap { + fn mul_assign(&mut self, rhs: i64) { + *self = *self * rhs + } +} diff --git a/tests/ui/assign_ops.stderr b/tests/ui/assign_ops.stderr index 17f216ee4a071..881a333fbe4b9 100644 --- a/tests/ui/assign_ops.stderr +++ b/tests/ui/assign_ops.stderr @@ -1,5 +1,5 @@ error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:7:5 + --> tests/ui/assign_ops.rs:9:5 | LL | a = a + 1; | ^^^^^^^^^ help: replace it with: `a += 1` @@ -8,64 +8,70 @@ LL | a = a + 1; = help: to override `-D warnings` add `#[allow(clippy::assign_op_pattern)]` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:9:5 + --> tests/ui/assign_ops.rs:11:5 | LL | a = 1 + a; | ^^^^^^^^^ help: replace it with: `a += 1` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:11:5 + --> tests/ui/assign_ops.rs:13:5 | LL | a = a - 1; | ^^^^^^^^^ help: replace it with: `a -= 1` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:13:5 + --> tests/ui/assign_ops.rs:15:5 | LL | a = a * 99; | ^^^^^^^^^^ help: replace it with: `a *= 99` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:15:5 + --> tests/ui/assign_ops.rs:17:5 | LL | a = 42 * a; | ^^^^^^^^^^ help: replace it with: `a *= 42` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:17:5 + --> tests/ui/assign_ops.rs:19:5 | LL | a = a / 2; | ^^^^^^^^^ help: replace it with: `a /= 2` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:19:5 + --> tests/ui/assign_ops.rs:21:5 | LL | a = a % 5; | ^^^^^^^^^ help: replace it with: `a %= 5` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:21:5 + --> tests/ui/assign_ops.rs:23:5 | LL | a = a & 1; | ^^^^^^^^^ help: replace it with: `a &= 1` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:28:5 + --> tests/ui/assign_ops.rs:30:5 | LL | s = s + "bla"; | ^^^^^^^^^^^^^ help: replace it with: `s += "bla"` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:33:5 + --> tests/ui/assign_ops.rs:35:5 | LL | a = a + Wrapping(1u32); | ^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a += Wrapping(1u32)` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:36:5 + --> tests/ui/assign_ops.rs:38:5 | LL | v[0] = v[0] + v[1]; | ^^^^^^^^^^^^^^^^^^ help: replace it with: `v[0] += v[1]` -error: aborting due to 11 previous errors +error: manual implementation of an assign operation + --> tests/ui/assign_ops.rs:51:5 + | +LL | buf = buf + cows.clone(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `buf += cows.clone()` + +error: aborting due to 12 previous errors diff --git a/tests/ui/assign_ops2.rs b/tests/ui/assign_ops2.rs deleted file mode 100644 index 51867fa6962cf..0000000000000 --- a/tests/ui/assign_ops2.rs +++ /dev/null @@ -1,77 +0,0 @@ -//@no-rustfix: overlapping suggestions -#![allow(clippy::uninlined_format_args)] - -#[allow(unused_assignments)] -#[warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)] -fn main() { - let mut a = 5; - a += a + 1; - //~^ misrefactored_assign_op - - a += 1 + a; - //~^ misrefactored_assign_op - - a -= a - 1; - //~^ misrefactored_assign_op - - a *= a * 99; - //~^ misrefactored_assign_op - - a *= 42 * a; - //~^ misrefactored_assign_op - - a /= a / 2; - //~^ misrefactored_assign_op - - a %= a % 5; - //~^ misrefactored_assign_op - - a &= a & 1; - //~^ misrefactored_assign_op - - a *= a * a; - //~^ misrefactored_assign_op - - a = a * a * a; - a = a * 42 * a; - a = a * 2 + a; - a -= 1 - a; - a /= 5 / a; - a %= 42 % a; - a <<= 6 << a; -} - -// check that we don't lint on op assign impls, because that's just the way to impl them - -use std::ops::{Mul, MulAssign}; - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct Wrap(i64); - -impl Mul for Wrap { - type Output = Self; - - fn mul(self, rhs: i64) -> Self { - Wrap(self.0 * rhs) - } -} - -impl MulAssign for Wrap { - fn mul_assign(&mut self, rhs: i64) { - *self = *self * rhs - } -} - -fn cow_add_assign() { - use std::borrow::Cow; - let mut buf = Cow::Owned(String::from("bar")); - let cows = Cow::Borrowed("foo"); - - // this can be linted - buf = buf + cows.clone(); - //~^ assign_op_pattern - - // this should not as cow Add is not commutative - buf = cows + buf; - println!("{}", buf); -} diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index 88c2549f4dc50..77329cf5455de 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -1,4 +1,4 @@ -//@no-rustfix +//@no-rustfix: only some diagnostics have suggestions #![feature(repr128)] #![allow(incomplete_features)] diff --git a/tests/ui/cast_size.rs b/tests/ui/cast_size.rs index e924018088674..e5bef2a99d59e 100644 --- a/tests/ui/cast_size.rs +++ b/tests/ui/cast_size.rs @@ -1,7 +1,7 @@ //@revisions: 32bit 64bit //@[32bit]ignore-bitwidth: 64 //@[64bit]ignore-bitwidth: 32 -//@no-rustfix +//@no-rustfix: only some diagnostics have suggestions #![warn( clippy::cast_precision_loss, diff --git a/tests/ui/checked_unwrap/complex_conditionals_nested.rs b/tests/ui/checked_unwrap/complex_conditionals_nested.rs index 145885702a9bc..7635f848cb349 100644 --- a/tests/ui/checked_unwrap/complex_conditionals_nested.rs +++ b/tests/ui/checked_unwrap/complex_conditionals_nested.rs @@ -4,7 +4,7 @@ clippy::branches_sharing_code, clippy::unnecessary_literal_unwrap )] -//@no-rustfix +//@no-rustfix: has placeholders fn test_nested() { fn nested() { let x = Some(()); diff --git a/tests/ui/checked_unwrap/simple_conditionals.rs b/tests/ui/checked_unwrap/simple_conditionals.rs index ba0d36d85fe54..785b2473c0530 100644 --- a/tests/ui/checked_unwrap/simple_conditionals.rs +++ b/tests/ui/checked_unwrap/simple_conditionals.rs @@ -1,4 +1,4 @@ -//@no-rustfix: overlapping suggestions +//@no-rustfix: has placeholders #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] #![allow( clippy::if_same_then_else, diff --git a/tests/ui/comparison_chain.rs b/tests/ui/comparison_chain.rs index 5695d48e0dfd7..6db75a4f364d7 100644 --- a/tests/ui/comparison_chain.rs +++ b/tests/ui/comparison_chain.rs @@ -1,4 +1,4 @@ -//@no-rustfix +//@no-rustfix: has placeholders #![allow(dead_code)] #![warn(clippy::comparison_chain)] diff --git a/tests/ui/dbg_macro/dbg_macro_unfixable.rs b/tests/ui/dbg_macro/dbg_macro_unfixable.rs index 1a5119651b539..96b35c9a20c4c 100644 --- a/tests/ui/dbg_macro/dbg_macro_unfixable.rs +++ b/tests/ui/dbg_macro/dbg_macro_unfixable.rs @@ -1,4 +1,4 @@ -//@no-rustfix +//@no-rustfix: overlapping suggestions //@error-in-other-file: #![warn(clippy::dbg_macro)] diff --git a/tests/ui/double_ended_iterator_last_unfixable.rs b/tests/ui/double_ended_iterator_last_unfixable.rs index e9218bbb40940..73f62ac124698 100644 --- a/tests/ui/double_ended_iterator_last_unfixable.rs +++ b/tests/ui/double_ended_iterator_last_unfixable.rs @@ -1,4 +1,4 @@ -//@no-rustfix +//@no-rustfix: requires manual changes #![warn(clippy::double_ended_iterator_last)] // Should not be linted because applying the lint would move the original iterator. This can only be diff --git a/tests/ui/entry_unfixable.rs b/tests/ui/entry_unfixable.rs index dbdacf950569c..c4c055572086e 100644 --- a/tests/ui/entry_unfixable.rs +++ b/tests/ui/entry_unfixable.rs @@ -1,6 +1,5 @@ -#![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)] +#![allow(clippy::needless_pass_by_value, clippy::collapsible_if)] #![warn(clippy::map_entry)] -//@no-rustfix use std::collections::HashMap; use std::hash::Hash; diff --git a/tests/ui/entry_unfixable.stderr b/tests/ui/entry_unfixable.stderr index 9f9956d351b29..0197d2ab4cf9c 100644 --- a/tests/ui/entry_unfixable.stderr +++ b/tests/ui/entry_unfixable.stderr @@ -1,5 +1,5 @@ error: usage of `contains_key` followed by `insert` on a `HashMap` - --> tests/ui/entry_unfixable.rs:28:13 + --> tests/ui/entry_unfixable.rs:27:13 | LL | / if !self.values.contains_key(&name) { LL | | @@ -14,7 +14,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::map_entry)]` error: usage of `contains_key` followed by `insert` on a `HashMap` - --> tests/ui/entry_unfixable.rs:43:5 + --> tests/ui/entry_unfixable.rs:42:5 | LL | / if hm.contains_key(&key) { LL | | @@ -26,7 +26,7 @@ LL | | } | |_____^ error: usage of `contains_key` followed by `insert` on a `HashMap` - --> tests/ui/entry_unfixable.rs:81:13 + --> tests/ui/entry_unfixable.rs:80:13 | LL | / if self.globals.contains_key(&name) { LL | | diff --git a/tests/ui/explicit_counter_loop.rs b/tests/ui/explicit_counter_loop.rs index 8340d99ace226..13934785d7b15 100644 --- a/tests/ui/explicit_counter_loop.rs +++ b/tests/ui/explicit_counter_loop.rs @@ -1,6 +1,6 @@ #![warn(clippy::explicit_counter_loop)] #![allow(clippy::uninlined_format_args, clippy::useless_vec)] -//@no-rustfix +//@no-rustfix: suggestion does not remove the `+= 1` fn main() { let mut vec = vec![1, 2, 3, 4]; let mut _index = 0; diff --git a/tests/ui/filter_map_bool_then_unfixable.rs b/tests/ui/filter_map_bool_then_unfixable.rs index 68294292502ac..5d29e0317bb2f 100644 --- a/tests/ui/filter_map_bool_then_unfixable.rs +++ b/tests/ui/filter_map_bool_then_unfixable.rs @@ -1,6 +1,5 @@ -#![allow(clippy::question_mark, unused)] +#![allow(clippy::question_mark)] #![warn(clippy::filter_map_bool_then)] -//@no-rustfix fn issue11617() { let mut x: Vec = vec![0; 10]; diff --git a/tests/ui/filter_map_bool_then_unfixable.stderr b/tests/ui/filter_map_bool_then_unfixable.stderr index 2025958136ba6..2990423973e10 100644 --- a/tests/ui/filter_map_bool_then_unfixable.stderr +++ b/tests/ui/filter_map_bool_then_unfixable.stderr @@ -1,5 +1,5 @@ error: usage of `bool::then` in `filter_map` - --> tests/ui/filter_map_bool_then_unfixable.rs:7:48 + --> tests/ui/filter_map_bool_then_unfixable.rs:6:48 | LL | let _ = (0..x.len()).zip(x.clone().iter()).filter_map(|(i, v)| { | ________________________________________________^ @@ -16,7 +16,7 @@ LL | | }); = help: to override `-D warnings` add `#[allow(clippy::filter_map_bool_then)]` error: usage of `bool::then` in `filter_map` - --> tests/ui/filter_map_bool_then_unfixable.rs:23:26 + --> tests/ui/filter_map_bool_then_unfixable.rs:22:26 | LL | let _ = x.iter().filter_map(|&x| x?.then(|| do_something(()))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | let _ = x.iter().filter_map(|&x| x?.then(|| do_something(()))); = help: consider using `filter` then `map` instead error: usage of `bool::then` in `filter_map` - --> tests/ui/filter_map_bool_then_unfixable.rs:27:14 + --> tests/ui/filter_map_bool_then_unfixable.rs:26:14 | LL | .filter_map(|&x| if let Some(x) = x { x } else { return None }.then(|| do_something(()))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | .filter_map(|&x| if let Some(x) = x { x } else { return None }. = help: consider using `filter` then `map` instead error: usage of `bool::then` in `filter_map` - --> tests/ui/filter_map_bool_then_unfixable.rs:29:26 + --> tests/ui/filter_map_bool_then_unfixable.rs:28:26 | LL | let _ = x.iter().filter_map(|&x| { | __________________________^ @@ -47,7 +47,7 @@ LL | | }); = help: consider using `filter` then `map` instead error: usage of `bool::then` in `filter_map` - --> tests/ui/filter_map_bool_then_unfixable.rs:47:26 + --> tests/ui/filter_map_bool_then_unfixable.rs:46:26 | LL | let _ = x.iter().filter_map(|&x| { | __________________________^ diff --git a/tests/ui/impl_trait_in_params.rs b/tests/ui/impl_trait_in_params.rs index 2039f6339a878..72e3e068c9c79 100644 --- a/tests/ui/impl_trait_in_params.rs +++ b/tests/ui/impl_trait_in_params.rs @@ -1,7 +1,7 @@ #![allow(unused)] #![warn(clippy::impl_trait_in_params)] -//@no-rustfix +//@no-rustfix: has placeholders pub trait Trait {} pub trait AnotherTrait {} diff --git a/tests/ui/infinite_loop.rs b/tests/ui/infinite_loop.rs index 4a0968918bfbe..8ff7f3b0c18d8 100644 --- a/tests/ui/infinite_loop.rs +++ b/tests/ui/infinite_loop.rs @@ -1,5 +1,3 @@ -//@no-rustfix - fn fn_val(i: i32) -> i32 { unimplemented!() } diff --git a/tests/ui/infinite_loop.stderr b/tests/ui/infinite_loop.stderr index 7ba1374d64f46..04da9776c3025 100644 --- a/tests/ui/infinite_loop.stderr +++ b/tests/ui/infinite_loop.stderr @@ -1,5 +1,5 @@ error: variables in the condition are not mutated in the loop body - --> tests/ui/infinite_loop.rs:22:11 + --> tests/ui/infinite_loop.rs:20:11 | LL | while y < 10 { | ^^^^^^ @@ -8,7 +8,7 @@ LL | while y < 10 { = note: `#[deny(clippy::while_immutable_condition)]` on by default error: variables in the condition are not mutated in the loop body - --> tests/ui/infinite_loop.rs:29:11 + --> tests/ui/infinite_loop.rs:27:11 | LL | while y < 10 && x < 3 { | ^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | while y < 10 && x < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> tests/ui/infinite_loop.rs:38:11 + --> tests/ui/infinite_loop.rs:36:11 | LL | while !cond { | ^^^^^ @@ -24,7 +24,7 @@ LL | while !cond { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> tests/ui/infinite_loop.rs:84:11 + --> tests/ui/infinite_loop.rs:82:11 | LL | while i < 3 { | ^^^^^ @@ -32,7 +32,7 @@ LL | while i < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> tests/ui/infinite_loop.rs:91:11 + --> tests/ui/infinite_loop.rs:89:11 | LL | while i < 3 && j > 0 { | ^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | while i < 3 && j > 0 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> tests/ui/infinite_loop.rs:97:11 + --> tests/ui/infinite_loop.rs:95:11 | LL | while i < 3 { | ^^^^^ @@ -48,7 +48,7 @@ LL | while i < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> tests/ui/infinite_loop.rs:114:11 + --> tests/ui/infinite_loop.rs:112:11 | LL | while i < 3 { | ^^^^^ @@ -56,7 +56,7 @@ LL | while i < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> tests/ui/infinite_loop.rs:121:11 + --> tests/ui/infinite_loop.rs:119:11 | LL | while i < 3 { | ^^^^^ @@ -64,7 +64,7 @@ LL | while i < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> tests/ui/infinite_loop.rs:189:15 + --> tests/ui/infinite_loop.rs:187:15 | LL | while self.count < n { | ^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | while self.count < n { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> tests/ui/infinite_loop.rs:199:11 + --> tests/ui/infinite_loop.rs:197:11 | LL | while y < 10 { | ^^^^^^ @@ -82,7 +82,7 @@ LL | while y < 10 { = help: rewrite it as `if cond { loop { } }` error: variables in the condition are not mutated in the loop body - --> tests/ui/infinite_loop.rs:208:11 + --> tests/ui/infinite_loop.rs:206:11 | LL | while y < 10 { | ^^^^^^ diff --git a/tests/ui/infinite_loops.rs b/tests/ui/infinite_loops.rs index eaa8d00880682..fcd1f795fff09 100644 --- a/tests/ui/infinite_loops.rs +++ b/tests/ui/infinite_loops.rs @@ -1,4 +1,4 @@ -//@no-rustfix +//@no-rustfix: multiple suggestions add `-> !` to the same fn //@aux-build:proc_macros.rs #![allow(clippy::never_loop)] diff --git a/tests/ui/into_iter_without_iter.rs b/tests/ui/into_iter_without_iter.rs index 45e34b3930ad0..f0b86e5620e9b 100644 --- a/tests/ui/into_iter_without_iter.rs +++ b/tests/ui/into_iter_without_iter.rs @@ -1,4 +1,4 @@ -//@no-rustfix +//@no-rustfix: suggestions reference out of scope lifetimes/types //@aux-build:proc_macros.rs #![warn(clippy::into_iter_without_iter)] extern crate proc_macros; diff --git a/tests/ui/iter_out_of_bounds.rs b/tests/ui/iter_out_of_bounds.rs index b34e4ad782409..6458b1342dcd5 100644 --- a/tests/ui/iter_out_of_bounds.rs +++ b/tests/ui/iter_out_of_bounds.rs @@ -1,5 +1,3 @@ -//@no-rustfix - #![deny(clippy::iter_out_of_bounds)] #![allow(clippy::useless_vec)] diff --git a/tests/ui/iter_out_of_bounds.stderr b/tests/ui/iter_out_of_bounds.stderr index 19ac60b9d0ac0..1b3a99e1e9457 100644 --- a/tests/ui/iter_out_of_bounds.stderr +++ b/tests/ui/iter_out_of_bounds.stderr @@ -1,18 +1,18 @@ error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:12:14 + --> tests/ui/iter_out_of_bounds.rs:10:14 | LL | for _ in [1, 2, 3].iter().skip(4) { | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this operation is useless and will create an empty iterator note: the lint level is defined here - --> tests/ui/iter_out_of_bounds.rs:3:9 + --> tests/ui/iter_out_of_bounds.rs:1:9 | LL | #![deny(clippy::iter_out_of_bounds)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `.take()` call takes more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:17:19 + --> tests/ui/iter_out_of_bounds.rs:15:19 | LL | for (i, _) in [1, 2, 3].iter().take(4).enumerate() { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | for (i, _) in [1, 2, 3].iter().take(4).enumerate() { = note: this operation is useless and the returned iterator will simply yield the same items error: this `.take()` call takes more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:24:14 + --> tests/ui/iter_out_of_bounds.rs:22:14 | LL | for _ in (&&&&&&[1, 2, 3]).iter().take(4) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL | for _ in (&&&&&&[1, 2, 3]).iter().take(4) {} = note: this operation is useless and the returned iterator will simply yield the same items error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:27:14 + --> tests/ui/iter_out_of_bounds.rs:25:14 | LL | for _ in [1, 2, 3].iter().skip(4) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | for _ in [1, 2, 3].iter().skip(4) {} = note: this operation is useless and will create an empty iterator error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:30:14 + --> tests/ui/iter_out_of_bounds.rs:28:14 | LL | for _ in [1; 3].iter().skip(4) {} | ^^^^^^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | for _ in [1; 3].iter().skip(4) {} = note: this operation is useless and will create an empty iterator error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:36:14 + --> tests/ui/iter_out_of_bounds.rs:34:14 | LL | for _ in vec![1, 2, 3].iter().skip(4) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -52,7 +52,7 @@ LL | for _ in vec![1, 2, 3].iter().skip(4) {} = note: this operation is useless and will create an empty iterator error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:39:14 + --> tests/ui/iter_out_of_bounds.rs:37:14 | LL | for _ in vec![1; 3].iter().skip(4) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL | for _ in vec![1; 3].iter().skip(4) {} = note: this operation is useless and will create an empty iterator error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:43:14 + --> tests/ui/iter_out_of_bounds.rs:41:14 | LL | for _ in x.iter().skip(4) {} | ^^^^^^^^^^^^^^^^ @@ -68,7 +68,7 @@ LL | for _ in x.iter().skip(4) {} = note: this operation is useless and will create an empty iterator error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:47:14 + --> tests/ui/iter_out_of_bounds.rs:45:14 | LL | for _ in x.iter().skip(n) {} | ^^^^^^^^^^^^^^^^ @@ -76,7 +76,7 @@ LL | for _ in x.iter().skip(n) {} = note: this operation is useless and will create an empty iterator error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:52:14 + --> tests/ui/iter_out_of_bounds.rs:50:14 | LL | for _ in empty().skip(1) {} | ^^^^^^^^^^^^^^^ @@ -84,7 +84,7 @@ LL | for _ in empty().skip(1) {} = note: this operation is useless and will create an empty iterator error: this `.take()` call takes more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:55:14 + --> tests/ui/iter_out_of_bounds.rs:53:14 | LL | for _ in empty().take(1) {} | ^^^^^^^^^^^^^^^ @@ -92,7 +92,7 @@ LL | for _ in empty().take(1) {} = note: this operation is useless and the returned iterator will simply yield the same items error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:58:14 + --> tests/ui/iter_out_of_bounds.rs:56:14 | LL | for _ in std::iter::once(1).skip(2) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -100,7 +100,7 @@ LL | for _ in std::iter::once(1).skip(2) {} = note: this operation is useless and will create an empty iterator error: this `.take()` call takes more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:61:14 + --> tests/ui/iter_out_of_bounds.rs:59:14 | LL | for _ in std::iter::once(1).take(2) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -108,7 +108,7 @@ LL | for _ in std::iter::once(1).take(2) {} = note: this operation is useless and the returned iterator will simply yield the same items error: this `.take()` call takes more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:64:14 + --> tests/ui/iter_out_of_bounds.rs:62:14 | LL | for x in [].iter().take(1) { | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/misrefactored_assign_op.1.fixed b/tests/ui/misrefactored_assign_op.1.fixed new file mode 100644 index 0000000000000..882ff6bf8944a --- /dev/null +++ b/tests/ui/misrefactored_assign_op.1.fixed @@ -0,0 +1,40 @@ +#![allow(clippy::eq_op)] +#![warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)] + +fn main() { + let mut a = 5; + a += 1; + //~^ misrefactored_assign_op + + a += 1; + //~^ misrefactored_assign_op + + a -= 1; + //~^ misrefactored_assign_op + + a *= 99; + //~^ misrefactored_assign_op + + a *= 42; + //~^ misrefactored_assign_op + + a /= 2; + //~^ misrefactored_assign_op + + a %= 5; + //~^ misrefactored_assign_op + + a &= 1; + //~^ misrefactored_assign_op + + a *= a; + //~^ misrefactored_assign_op + + a = a * a * a; + a = a * 42 * a; + a = a * 2 + a; + a -= 1 - a; + a /= 5 / a; + a %= 42 % a; + a <<= 6 << a; +} diff --git a/tests/ui/misrefactored_assign_op.2.fixed b/tests/ui/misrefactored_assign_op.2.fixed new file mode 100644 index 0000000000000..de3a0f1710d24 --- /dev/null +++ b/tests/ui/misrefactored_assign_op.2.fixed @@ -0,0 +1,40 @@ +#![allow(clippy::eq_op)] +#![warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)] + +fn main() { + let mut a = 5; + a = a + a + 1; + //~^ misrefactored_assign_op + + a = a + 1 + a; + //~^ misrefactored_assign_op + + a = a - (a - 1); + //~^ misrefactored_assign_op + + a = a * a * 99; + //~^ misrefactored_assign_op + + a = a * 42 * a; + //~^ misrefactored_assign_op + + a = a / (a / 2); + //~^ misrefactored_assign_op + + a = a % (a % 5); + //~^ misrefactored_assign_op + + a = a & a & 1; + //~^ misrefactored_assign_op + + a = a * a * a; + //~^ misrefactored_assign_op + + a = a * a * a; + a = a * 42 * a; + a = a * 2 + a; + a -= 1 - a; + a /= 5 / a; + a %= 42 % a; + a <<= 6 << a; +} diff --git a/tests/ui/misrefactored_assign_op.rs b/tests/ui/misrefactored_assign_op.rs new file mode 100644 index 0000000000000..62d83d1619c1e --- /dev/null +++ b/tests/ui/misrefactored_assign_op.rs @@ -0,0 +1,40 @@ +#![allow(clippy::eq_op)] +#![warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)] + +fn main() { + let mut a = 5; + a += a + 1; + //~^ misrefactored_assign_op + + a += 1 + a; + //~^ misrefactored_assign_op + + a -= a - 1; + //~^ misrefactored_assign_op + + a *= a * 99; + //~^ misrefactored_assign_op + + a *= 42 * a; + //~^ misrefactored_assign_op + + a /= a / 2; + //~^ misrefactored_assign_op + + a %= a % 5; + //~^ misrefactored_assign_op + + a &= a & 1; + //~^ misrefactored_assign_op + + a *= a * a; + //~^ misrefactored_assign_op + + a = a * a * a; + a = a * 42 * a; + a = a * 2 + a; + a -= 1 - a; + a /= 5 / a; + a %= 42 % a; + a <<= 6 << a; +} diff --git a/tests/ui/assign_ops2.stderr b/tests/ui/misrefactored_assign_op.stderr similarity index 80% rename from tests/ui/assign_ops2.stderr rename to tests/ui/misrefactored_assign_op.stderr index d9ecd3f8b230c..63f3a3e28f12c 100644 --- a/tests/ui/assign_ops2.stderr +++ b/tests/ui/misrefactored_assign_op.stderr @@ -1,5 +1,5 @@ error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:8:5 + --> tests/ui/misrefactored_assign_op.rs:6:5 | LL | a += a + 1; | ^^^^^^^^^^ @@ -18,7 +18,7 @@ LL + a = a + a + 1; | error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:11:5 + --> tests/ui/misrefactored_assign_op.rs:9:5 | LL | a += 1 + a; | ^^^^^^^^^^ @@ -35,7 +35,7 @@ LL + a = a + 1 + a; | error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:14:5 + --> tests/ui/misrefactored_assign_op.rs:12:5 | LL | a -= a - 1; | ^^^^^^^^^^ @@ -52,7 +52,7 @@ LL + a = a - (a - 1); | error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:17:5 + --> tests/ui/misrefactored_assign_op.rs:15:5 | LL | a *= a * 99; | ^^^^^^^^^^^ @@ -69,7 +69,7 @@ LL + a = a * a * 99; | error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:20:5 + --> tests/ui/misrefactored_assign_op.rs:18:5 | LL | a *= 42 * a; | ^^^^^^^^^^^ @@ -86,7 +86,7 @@ LL + a = a * 42 * a; | error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:23:5 + --> tests/ui/misrefactored_assign_op.rs:21:5 | LL | a /= a / 2; | ^^^^^^^^^^ @@ -103,7 +103,7 @@ LL + a = a / (a / 2); | error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:26:5 + --> tests/ui/misrefactored_assign_op.rs:24:5 | LL | a %= a % 5; | ^^^^^^^^^^ @@ -120,7 +120,7 @@ LL + a = a % (a % 5); | error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:29:5 + --> tests/ui/misrefactored_assign_op.rs:27:5 | LL | a &= a & 1; | ^^^^^^^^^^ @@ -137,7 +137,7 @@ LL + a = a & a & 1; | error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:32:5 + --> tests/ui/misrefactored_assign_op.rs:30:5 | LL | a *= a * a; | ^^^^^^^^^^ @@ -153,14 +153,5 @@ LL - a *= a * a; LL + a = a * a * a; | -error: manual implementation of an assign operation - --> tests/ui/assign_ops2.rs:71:5 - | -LL | buf = buf + cows.clone(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `buf += cows.clone()` - | - = note: `-D clippy::assign-op-pattern` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::assign_op_pattern)]` - -error: aborting due to 10 previous errors +error: aborting due to 9 previous errors From 492c4e197dcb357f32a70931c71e99517ab25717 Mon Sep 17 00:00:00 2001 From: yanglsh Date: Sun, 18 May 2025 16:25:40 +0800 Subject: [PATCH 2430/4206] fix: `unnecessary_to_owned` FP when map key is a reference --- .../src/methods/unnecessary_to_owned.rs | 22 ++++++++++++++----- tests/ui/unnecessary_to_owned.fixed | 6 +++++ tests/ui/unnecessary_to_owned.rs | 6 +++++ 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 87bb8d46a1d6a..d4d170f4d49c2 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -655,11 +655,18 @@ fn is_to_string_on_string_like<'a>( } } -fn is_a_std_map_type(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - is_type_diagnostic_item(cx, ty, sym::HashSet) - || is_type_diagnostic_item(cx, ty, sym::HashMap) - || is_type_diagnostic_item(cx, ty, sym::BTreeMap) - || is_type_diagnostic_item(cx, ty, sym::BTreeSet) +fn std_map_key<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { + match ty.kind() { + ty::Adt(adt, args) + if matches!( + cx.tcx.get_diagnostic_name(adt.did()), + Some(sym::BTreeMap | sym::BTreeSet | sym::HashMap | sym::HashSet) + ) => + { + Some(args.type_at(0)) + }, + _ => None, + } } fn is_str_and_string(cx: &LateContext<'_>, arg_ty: Ty<'_>, original_arg_ty: Ty<'_>) -> bool { @@ -721,6 +728,7 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx // 1. This is a method with only one argument that doesn't come from a trait. // 2. That it has `Borrow` in its generic predicates. // 3. `Self` is a std "map type" (ie `HashSet`, `HashMap`, `BTreeSet`, `BTreeMap`). +// 4. The key to the "map type" is not a reference. fn check_borrow_predicate<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { if let ExprKind::MethodCall(_, caller, &[arg], _) = expr.kind && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) @@ -738,7 +746,9 @@ fn check_borrow_predicate<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { }) && let caller_ty = cx.typeck_results().expr_ty(caller) // For now we limit it to "map types". - && is_a_std_map_type(cx, caller_ty) + && let Some(key_ty) = std_map_key(cx, caller_ty) + // We need to check that the key type is not a reference. + && !key_ty.is_ref() { check_if_applicable_to_argument(cx, &arg); } diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index b064a8b8f46fb..316eac0b58b79 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -675,3 +675,9 @@ mod issue_14242 { rc_slice_provider().to_vec().into_iter() } } + +fn issue14833() { + use std::collections::HashSet; + let mut s = HashSet::<&String>::new(); + s.remove(&"hello".to_owned()); +} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index 7954a4ad4ce77..f2dbd1db3c9f6 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -675,3 +675,9 @@ mod issue_14242 { rc_slice_provider().to_vec().into_iter() } } + +fn issue14833() { + use std::collections::HashSet; + let mut s = HashSet::<&String>::new(); + s.remove(&"hello".to_owned()); +} From 0e43247bc94d50b4a341e68cfabe8f7fd75f6376 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 18 May 2025 15:02:09 +0000 Subject: [PATCH 2431/4206] Fix rustc testsuite --- scripts/test_rustc_tests.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index c59e34094dc8d..d014b6881ff4c 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -53,6 +53,8 @@ rm -r tests/run-make/split-debuginfo # same rm -r tests/run-make/target-specs # i686 not supported by Cranelift rm -r tests/run-make/mismatching-target-triples # same rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't work entirely correctly +rm tests/ui/asm/global-asm-mono-sym-fn.rs # same +rm tests/ui/asm/naked-asm-mono-sym-fn.rs # same rm tests/ui/asm/x86_64/goto.rs # inline asm labels not supported rm tests/ui/simd/simd-bitmask-notpow2.rs # non-pow-of-2 simd vector sizes rm -r tests/run-make/embed-source-dwarf # embedding sources in debuginfo @@ -134,6 +136,8 @@ rm -r tests/run-make/const-trait-stable-toolchain # same rm -r tests/run-make/print-request-help-stable-unstable # same rm -r tests/run-make/incr-add-rust-src-component rm tests/ui/errors/remap-path-prefix-sysroot.rs # different sysroot source path +rm -r tests/run-make/export/extern-opt # something about rustc version mismatches +rm -r tests/run-make/export # same # genuine bugs # ============ From 8c150144fd6d2fd5944021c1fb566a2e7b0ee889 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 18 May 2025 15:53:02 +0000 Subject: [PATCH 2432/4206] triagebot: Add pings and autolabels for the compiler-builtins subtree. --- triagebot.toml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 9dcdbcecbeca6..5921c2056f525 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -254,6 +254,11 @@ trigger_files = [ "compiler/rustc_attr_data_structures", ] +[autolabel."A-compiler-builtins"] +trigger_files = [ + "library/compiler-builtins", +] + [autolabel."F-autodiff"] trigger_files = [ "src/tools/enzyme", @@ -851,6 +856,15 @@ cc = ["@Urgau"] message = "Some changes occurred in check-cfg diagnostics" cc = ["@Urgau"] +[mentions."library/compiler-builtins"] +message = """ +`compiler-builtins` is developed in its own repository. If possible, consider \ +making this change to \ +[rust-lang/compiler-builtins](https://github.com/rust-lang/compiler-builtins) \ +instead. +""" +cc = ["@tgross35"] + [mentions."library/core/src/intrinsics/simd.rs"] message = """ Some changes occurred to the platform-builtins intrinsics. Make sure the From 6fc60b8b0493027cc966d4911688f0735bfb329d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 24 Aug 2024 22:29:39 -0500 Subject: [PATCH 2433/4206] float: Add `f16` parsing and printing Use the existing Lemire (decimal -> float) and Dragon / Grisu algorithms (float -> decimal) to add support for `f16`. This allows updating the implementation for `Display` to the expected behavior for `Display` (currently it prints the a hex bitwise representation), matching other floats, and adds a `FromStr` implementation. In order to avoid crashes when compiling with Cranelift or on targets where f16 is not well supported, a fallback is used if `cfg(target_has_reliable_f16)` is not true. --- library/core/src/fmt/float.rs | 36 ++++++++++++++++ library/core/src/lib.rs | 1 + library/core/src/num/dec2flt/float.rs | 57 +++++++++++++++++++++++-- library/core/src/num/dec2flt/mod.rs | 16 +++++++ library/core/src/num/flt2dec/decoder.rs | 7 +++ 5 files changed, 113 insertions(+), 4 deletions(-) diff --git a/library/core/src/fmt/float.rs b/library/core/src/fmt/float.rs index 870ad9df4fd33..556db239f2499 100644 --- a/library/core/src/fmt/float.rs +++ b/library/core/src/fmt/float.rs @@ -20,6 +20,8 @@ macro_rules! impl_general_format { } } +#[cfg(target_has_reliable_f16)] +impl_general_format! { f16 } impl_general_format! { f32 f64 } // Don't inline this so callers don't use the stack space this function @@ -231,6 +233,13 @@ macro_rules! floating { floating! { f32 f64 } +#[cfg(target_has_reliable_f16)] +floating! { f16 } + +// FIXME(f16_f128): A fallback is used when the backend+target does not support f16 well, in order +// to avoid ICEs. + +#[cfg(not(target_has_reliable_f16))] #[stable(feature = "rust1", since = "1.0.0")] impl Debug for f16 { #[inline] @@ -239,6 +248,33 @@ impl Debug for f16 { } } +#[cfg(not(target_has_reliable_f16))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Display for f16 { + #[inline] + fn fmt(&self, fmt: &mut Formatter<'_>) -> Result { + Debug::fmt(self, fmt) + } +} + +#[cfg(not(target_has_reliable_f16))] +#[stable(feature = "rust1", since = "1.0.0")] +impl LowerExp for f16 { + #[inline] + fn fmt(&self, fmt: &mut Formatter<'_>) -> Result { + Debug::fmt(self, fmt) + } +} + +#[cfg(not(target_has_reliable_f16))] +#[stable(feature = "rust1", since = "1.0.0")] +impl UpperExp for f16 { + #[inline] + fn fmt(&self, fmt: &mut Formatter<'_>) -> Result { + Debug::fmt(self, fmt) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Debug for f128 { #[inline] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 64a7ec8906b6b..54555f8beec63 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -101,6 +101,7 @@ #![feature(bstr)] #![feature(bstr_internals)] #![feature(cfg_match)] +#![feature(cfg_target_has_reliable_f16_f128)] #![feature(const_carrying_mul_add)] #![feature(const_eval_select)] #![feature(core_intrinsics)] diff --git a/library/core/src/num/dec2flt/float.rs b/library/core/src/num/dec2flt/float.rs index b8a28a6756917..5bf0faf0bc910 100644 --- a/library/core/src/num/dec2flt/float.rs +++ b/library/core/src/num/dec2flt/float.rs @@ -45,7 +45,7 @@ macro_rules! int { } } -int!(u32, u64); +int!(u16, u32, u64); /// A helper trait to avoid duplicating basically all the conversion code for IEEE floats. /// @@ -189,9 +189,14 @@ pub trait RawFloat: /// Returns the mantissa, exponent and sign as integers. /// - /// That is, this returns `(m, p, s)` such that `s * m * 2^p` represents the original float. - /// For 0, the exponent will be `-(EXP_BIAS + SIG_BITS`, which is the - /// minimum subnormal power. + /// This returns `(m, p, s)` such that `s * m * 2^p` represents the original float. For 0, the + /// exponent will be `-(EXP_BIAS + SIG_BITS)`, which is the minimum subnormal power. For + /// infinity or NaN, the exponent will be `EXP_SAT - EXP_BIAS - SIG_BITS`. + /// + /// If subnormal, the mantissa will be shifted one bit to the left. Otherwise, it is returned + /// with the explicit bit set but otherwise unshifted + /// + /// `s` is only ever +/-1. fn integer_decode(self) -> (u64, i16, i8) { let bits = self.to_bits(); let sign: i8 = if bits >> (Self::BITS - 1) == Self::Int::ZERO { 1 } else { -1 }; @@ -213,6 +218,50 @@ const fn pow2_to_pow10(a: i64) -> i64 { res as i64 } +#[cfg(target_has_reliable_f16)] +impl RawFloat for f16 { + type Int = u16; + + const INFINITY: Self = Self::INFINITY; + const NEG_INFINITY: Self = Self::NEG_INFINITY; + const NAN: Self = Self::NAN; + const NEG_NAN: Self = -Self::NAN; + + 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 MIN_EXPONENT_ROUND_TO_EVEN: i32 = -22; + const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 5; + const SMALLEST_POWER_OF_TEN: i32 = -27; + + #[inline] + fn from_u64(v: u64) -> Self { + debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); + v as _ + } + + #[inline] + fn from_u64_bits(v: u64) -> Self { + Self::from_bits((v & 0xFFFF) as u16) + } + + fn pow10_fast_path(exponent: usize) -> Self { + #[allow(clippy::use_self)] + const TABLE: [f16; 8] = [1e0, 1e1, 1e2, 1e3, 1e4, 0.0, 0.0, 0.]; + TABLE[exponent & 7] + } + + fn to_bits(self) -> Self::Int { + self.to_bits() + } + + fn classify(self) -> FpCategory { + self.classify() + } +} + impl RawFloat for f32 { type Int = u32; diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs index d1a0e1db31314..abad7acb1046a 100644 --- a/library/core/src/num/dec2flt/mod.rs +++ b/library/core/src/num/dec2flt/mod.rs @@ -171,9 +171,25 @@ macro_rules! from_str_float_impl { } }; } + +#[cfg(target_has_reliable_f16)] +from_str_float_impl!(f16); from_str_float_impl!(f32); from_str_float_impl!(f64); +// FIXME(f16_f128): A fallback is used when the backend+target does not support f16 well, in order +// to avoid ICEs. + +#[cfg(not(target_has_reliable_f16))] +impl FromStr for f16 { + type Err = ParseFloatError; + + #[inline] + fn from_str(_src: &str) -> Result { + unimplemented!("requires target_has_reliable_f16") + } +} + /// An error which can be returned when parsing a float. /// /// This error is used as the error type for the [`FromStr`] implementation diff --git a/library/core/src/num/flt2dec/decoder.rs b/library/core/src/num/flt2dec/decoder.rs index 40b3aae24a536..bd6e2cdbafec8 100644 --- a/library/core/src/num/flt2dec/decoder.rs +++ b/library/core/src/num/flt2dec/decoder.rs @@ -45,6 +45,13 @@ pub trait DecodableFloat: RawFloat + Copy { fn min_pos_norm_value() -> Self; } +#[cfg(target_has_reliable_f16)] +impl DecodableFloat for f16 { + fn min_pos_norm_value() -> Self { + f16::MIN_POSITIVE + } +} + impl DecodableFloat for f32 { fn min_pos_norm_value() -> Self { f32::MIN_POSITIVE From 977d8418696438c8cc5f21082d59cdc6d09d94bf Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 8 Mar 2025 03:39:04 +0000 Subject: [PATCH 2434/4206] float: Add tests for `f16` conversions to and from decimal Extend the existing tests for `f32` and `f64` with versions that include `f16`'s new printing and parsing implementations. Co-authored-by: Speedy_Lex --- .../coretests/tests/num/dec2flt/decimal.rs | 14 ++ library/coretests/tests/num/dec2flt/float.rs | 40 +++ library/coretests/tests/num/dec2flt/lemire.rs | 133 +++++++--- library/coretests/tests/num/dec2flt/mod.rs | 65 ++++- library/coretests/tests/num/dec2flt/parse.rs | 23 +- library/coretests/tests/num/flt2dec/mod.rs | 234 +++++++++++++++--- library/coretests/tests/num/flt2dec/random.rs | 60 +++++ .../tests/num/flt2dec/strategy/dragon.rs | 5 + .../tests/num/flt2dec/strategy/grisu.rs | 4 + 9 files changed, 501 insertions(+), 77 deletions(-) diff --git a/library/coretests/tests/num/dec2flt/decimal.rs b/library/coretests/tests/num/dec2flt/decimal.rs index 1fa06de692e07..f759e1dbde6cb 100644 --- a/library/coretests/tests/num/dec2flt/decimal.rs +++ b/library/coretests/tests/num/dec2flt/decimal.rs @@ -7,6 +7,20 @@ const FPATHS_F32: &[FPath] = const FPATHS_F64: &[FPath] = &[((0, 0, false, false), Some(0.0)), ((0, 0, false, false), Some(0.0))]; +// FIXME(f16_f128): enable on all targets once possible. +#[test] +#[cfg(target_has_reliable_f16)] +fn check_fast_path_f16() { + const FPATHS_F16: &[FPath] = + &[((0, 0, false, false), Some(0.0)), ((0, 0, false, false), Some(0.0))]; + for ((exponent, mantissa, negative, many_digits), expected) in FPATHS_F16.iter().copied() { + let dec = Decimal { exponent, mantissa, negative, many_digits }; + let actual = dec.try_fast_path::(); + + assert_eq!(actual, expected); + } +} + #[test] fn check_fast_path_f32() { for ((exponent, mantissa, negative, many_digits), expected) in FPATHS_F32.iter().copied() { diff --git a/library/coretests/tests/num/dec2flt/float.rs b/library/coretests/tests/num/dec2flt/float.rs index b5afd3e3b2436..264de061be98c 100644 --- a/library/coretests/tests/num/dec2flt/float.rs +++ b/library/coretests/tests/num/dec2flt/float.rs @@ -1,5 +1,24 @@ use core::num::dec2flt::float::RawFloat; +// FIXME(f16_f128): enable on all targets once possible. +#[test] +#[cfg(target_has_reliable_f16)] +fn test_f16_integer_decode() { + assert_eq!(3.14159265359f16.integer_decode(), (1608, -9, 1)); + assert_eq!((-8573.5918555f16).integer_decode(), (1072, 3, -1)); + #[cfg(not(miri))] // miri doesn't have powf16 + assert_eq!(2f16.powf(14.0).integer_decode(), (1 << 10, 4, 1)); + assert_eq!(0f16.integer_decode(), (0, -25, 1)); + assert_eq!((-0f16).integer_decode(), (0, -25, -1)); + assert_eq!(f16::INFINITY.integer_decode(), (1 << 10, 6, 1)); + assert_eq!(f16::NEG_INFINITY.integer_decode(), (1 << 10, 6, -1)); + + // Ignore the "sign" (quiet / signalling flag) of NAN. + // It can vary between runtime operations and LLVM folding. + let (nan_m, nan_p, _nan_s) = f16::NAN.integer_decode(); + assert_eq!((nan_m, nan_p), (1536, 6)); +} + #[test] fn test_f32_integer_decode() { assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1)); @@ -34,6 +53,27 @@ fn test_f64_integer_decode() { /* Sanity checks of computed magic numbers */ +// FIXME(f16_f128): enable on all targets once possible. +#[test] +#[cfg(target_has_reliable_f16)] +fn test_f16_consts() { + assert_eq!(::INFINITY, f16::INFINITY); + assert_eq!(::NEG_INFINITY, -f16::INFINITY); + assert_eq!(::NAN.to_bits(), f16::NAN.to_bits()); + assert_eq!(::NEG_NAN.to_bits(), (-f16::NAN).to_bits()); + assert_eq!(::SIG_BITS, 10); + assert_eq!(::MIN_EXPONENT_ROUND_TO_EVEN, -22); + assert_eq!(::MAX_EXPONENT_ROUND_TO_EVEN, 5); + assert_eq!(::MIN_EXPONENT_FAST_PATH, -4); + assert_eq!(::MAX_EXPONENT_FAST_PATH, 4); + assert_eq!(::MAX_EXPONENT_DISGUISED_FAST_PATH, 7); + assert_eq!(::EXP_MIN, -14); + assert_eq!(::EXP_SAT, 0x1f); + assert_eq!(::SMALLEST_POWER_OF_TEN, -27); + assert_eq!(::LARGEST_POWER_OF_TEN, 4); + assert_eq!(::MAX_MANTISSA_FAST_PATH, 2048); +} + #[test] fn test_f32_consts() { assert_eq!(::INFINITY, f32::INFINITY); diff --git a/library/coretests/tests/num/dec2flt/lemire.rs b/library/coretests/tests/num/dec2flt/lemire.rs index 0db80fbd52506..6d49d85170e2d 100644 --- a/library/coretests/tests/num/dec2flt/lemire.rs +++ b/library/coretests/tests/num/dec2flt/lemire.rs @@ -1,6 +1,12 @@ use core::num::dec2flt::float::RawFloat; use core::num::dec2flt::lemire::compute_float; +#[cfg(target_has_reliable_f16)] +fn compute_float16(q: i64, w: u64) -> (i32, u64) { + let fp = compute_float::(q, w); + (fp.p_biased, fp.m) +} + fn compute_float32(q: i64, w: u64) -> (i32, u64) { let fp = compute_float::(q, w); (fp.p_biased, fp.m) @@ -11,23 +17,73 @@ fn compute_float64(q: i64, w: u64) -> (i32, u64) { (fp.p_biased, fp.m) } +// FIXME(f16_f128): enable on all targets once possible. +#[test] +#[cfg(target_has_reliable_f16)] +fn compute_float_f16_rounding() { + // The maximum integer that cna be converted to a `f16` without lost precision. + let val = 1 << 11; + let scale = 10_u64.pow(10); + + // These test near-halfway cases for half-precision floats. + assert_eq!(compute_float16(0, val), (26, 0)); + assert_eq!(compute_float16(0, val + 1), (26, 0)); + assert_eq!(compute_float16(0, val + 2), (26, 1)); + assert_eq!(compute_float16(0, val + 3), (26, 2)); + assert_eq!(compute_float16(0, val + 4), (26, 2)); + + // For the next power up, the two nearest representable numbers are twice as far apart. + let val2 = 1 << 12; + assert_eq!(compute_float16(0, val2), (27, 0)); + assert_eq!(compute_float16(0, val2 + 2), (27, 0)); + assert_eq!(compute_float16(0, val2 + 4), (27, 1)); + assert_eq!(compute_float16(0, val2 + 6), (27, 2)); + assert_eq!(compute_float16(0, val2 + 8), (27, 2)); + + // These are examples of the above tests, with digits from the exponent shifted + // to the mantissa. + assert_eq!(compute_float16(-10, val * scale), (26, 0)); + assert_eq!(compute_float16(-10, (val + 1) * scale), (26, 0)); + assert_eq!(compute_float16(-10, (val + 2) * scale), (26, 1)); + // Let's check the lines to see if anything is different in table... + assert_eq!(compute_float16(-10, (val + 3) * scale), (26, 2)); + assert_eq!(compute_float16(-10, (val + 4) * scale), (26, 2)); + + // Check the rounding point between infinity and the next representable number down + assert_eq!(compute_float16(4, 6), (f16::INFINITE_POWER - 1, 851)); + assert_eq!(compute_float16(4, 7), (f16::INFINITE_POWER, 0)); // infinity + assert_eq!(compute_float16(2, 655), (f16::INFINITE_POWER - 1, 1023)); +} + #[test] fn compute_float_f32_rounding() { + // the maximum integer that cna be converted to a `f32` without lost precision. + let val = 1 << 24; + let scale = 10_u64.pow(10); + // These test near-halfway cases for single-precision floats. - assert_eq!(compute_float32(0, 16777216), (151, 0)); - assert_eq!(compute_float32(0, 16777217), (151, 0)); - assert_eq!(compute_float32(0, 16777218), (151, 1)); - assert_eq!(compute_float32(0, 16777219), (151, 2)); - assert_eq!(compute_float32(0, 16777220), (151, 2)); - - // These are examples of the above tests, with - // digits from the exponent shifted to the mantissa. - assert_eq!(compute_float32(-10, 167772160000000000), (151, 0)); - assert_eq!(compute_float32(-10, 167772170000000000), (151, 0)); - assert_eq!(compute_float32(-10, 167772180000000000), (151, 1)); + assert_eq!(compute_float32(0, val), (151, 0)); + assert_eq!(compute_float32(0, val + 1), (151, 0)); + assert_eq!(compute_float32(0, val + 2), (151, 1)); + assert_eq!(compute_float32(0, val + 3), (151, 2)); + assert_eq!(compute_float32(0, val + 4), (151, 2)); + + // For the next power up, the two nearest representable numbers are twice as far apart. + let val2 = 1 << 25; + assert_eq!(compute_float32(0, val2), (152, 0)); + assert_eq!(compute_float32(0, val2 + 2), (152, 0)); + assert_eq!(compute_float32(0, val2 + 4), (152, 1)); + assert_eq!(compute_float32(0, val2 + 6), (152, 2)); + assert_eq!(compute_float32(0, val2 + 8), (152, 2)); + + // These are examples of the above tests, with digits from the exponent shifted + // to the mantissa. + assert_eq!(compute_float32(-10, val * scale), (151, 0)); + assert_eq!(compute_float32(-10, (val + 1) * scale), (151, 0)); + assert_eq!(compute_float32(-10, (val + 2) * scale), (151, 1)); // Let's check the lines to see if anything is different in table... - assert_eq!(compute_float32(-10, 167772190000000000), (151, 2)); - assert_eq!(compute_float32(-10, 167772200000000000), (151, 2)); + assert_eq!(compute_float32(-10, (val + 3) * scale), (151, 2)); + assert_eq!(compute_float32(-10, (val + 4) * scale), (151, 2)); // Check the rounding point between infinity and the next representable number down assert_eq!(compute_float32(38, 3), (f32::INFINITE_POWER - 1, 6402534)); @@ -37,23 +93,38 @@ fn compute_float_f32_rounding() { #[test] fn compute_float_f64_rounding() { + // The maximum integer that cna be converted to a `f64` without lost precision. + let val = 1 << 53; + let scale = 1000; + // These test near-halfway cases for double-precision floats. - assert_eq!(compute_float64(0, 9007199254740992), (1076, 0)); - assert_eq!(compute_float64(0, 9007199254740993), (1076, 0)); - assert_eq!(compute_float64(0, 9007199254740994), (1076, 1)); - assert_eq!(compute_float64(0, 9007199254740995), (1076, 2)); - assert_eq!(compute_float64(0, 9007199254740996), (1076, 2)); - assert_eq!(compute_float64(0, 18014398509481984), (1077, 0)); - assert_eq!(compute_float64(0, 18014398509481986), (1077, 0)); - assert_eq!(compute_float64(0, 18014398509481988), (1077, 1)); - assert_eq!(compute_float64(0, 18014398509481990), (1077, 2)); - assert_eq!(compute_float64(0, 18014398509481992), (1077, 2)); - - // These are examples of the above tests, with - // digits from the exponent shifted to the mantissa. - assert_eq!(compute_float64(-3, 9007199254740992000), (1076, 0)); - assert_eq!(compute_float64(-3, 9007199254740993000), (1076, 0)); - assert_eq!(compute_float64(-3, 9007199254740994000), (1076, 1)); - assert_eq!(compute_float64(-3, 9007199254740995000), (1076, 2)); - assert_eq!(compute_float64(-3, 9007199254740996000), (1076, 2)); + assert_eq!(compute_float64(0, val), (1076, 0)); + assert_eq!(compute_float64(0, val + 1), (1076, 0)); + assert_eq!(compute_float64(0, val + 2), (1076, 1)); + assert_eq!(compute_float64(0, val + 3), (1076, 2)); + assert_eq!(compute_float64(0, val + 4), (1076, 2)); + + // For the next power up, the two nearest representable numbers are twice as far apart. + let val2 = 1 << 54; + assert_eq!(compute_float64(0, val2), (1077, 0)); + assert_eq!(compute_float64(0, val2 + 2), (1077, 0)); + assert_eq!(compute_float64(0, val2 + 4), (1077, 1)); + assert_eq!(compute_float64(0, val2 + 6), (1077, 2)); + assert_eq!(compute_float64(0, val2 + 8), (1077, 2)); + + // These are examples of the above tests, with digits from the exponent shifted + // to the mantissa. + assert_eq!(compute_float64(-3, val * scale), (1076, 0)); + assert_eq!(compute_float64(-3, (val + 1) * scale), (1076, 0)); + assert_eq!(compute_float64(-3, (val + 2) * scale), (1076, 1)); + assert_eq!(compute_float64(-3, (val + 3) * scale), (1076, 2)); + assert_eq!(compute_float64(-3, (val + 4) * scale), (1076, 2)); + + // Check the rounding point between infinity and the next representable number down + assert_eq!(compute_float64(308, 1), (f64::INFINITE_POWER - 1, 506821272651936)); + assert_eq!(compute_float64(308, 2), (f64::INFINITE_POWER, 0)); // infinity + assert_eq!( + compute_float64(292, 17976931348623157), + (f64::INFINITE_POWER - 1, 4503599627370495) + ); } diff --git a/library/coretests/tests/num/dec2flt/mod.rs b/library/coretests/tests/num/dec2flt/mod.rs index a9025be5ca7f1..b8ca220847cfa 100644 --- a/library/coretests/tests/num/dec2flt/mod.rs +++ b/library/coretests/tests/num/dec2flt/mod.rs @@ -11,15 +11,23 @@ mod parse; // Requires a *polymorphic literal*, i.e., one that can serve as f64 as well as f32. macro_rules! test_literal { ($x: expr) => {{ + #[cfg(target_has_reliable_f16)] + let x16: f16 = $x; let x32: f32 = $x; let x64: f64 = $x; let inputs = &[stringify!($x).into(), format!("{:?}", x64), format!("{:e}", x64)]; + for input in inputs { - assert_eq!(input.parse(), Ok(x64)); - assert_eq!(input.parse(), Ok(x32)); + assert_eq!(input.parse(), Ok(x64), "failed f64 {input}"); + assert_eq!(input.parse(), Ok(x32), "failed f32 {input}"); + #[cfg(target_has_reliable_f16)] + assert_eq!(input.parse(), Ok(x16), "failed f16 {input}"); + let neg_input = format!("-{input}"); - assert_eq!(neg_input.parse(), Ok(-x64)); - assert_eq!(neg_input.parse(), Ok(-x32)); + assert_eq!(neg_input.parse(), Ok(-x64), "failed f64 {neg_input}"); + assert_eq!(neg_input.parse(), Ok(-x32), "failed f32 {neg_input}"); + #[cfg(target_has_reliable_f16)] + assert_eq!(neg_input.parse(), Ok(-x16), "failed f16 {neg_input}"); } }}; } @@ -84,48 +92,87 @@ fn fast_path_correct() { test_literal!(1.448997445238699); } +// FIXME(f16_f128): remove gates once tests work on all targets + #[test] fn lonely_dot() { + #[cfg(target_has_reliable_f16)] + assert!(".".parse::().is_err()); assert!(".".parse::().is_err()); assert!(".".parse::().is_err()); } #[test] fn exponentiated_dot() { + #[cfg(target_has_reliable_f16)] + assert!(".e0".parse::().is_err()); assert!(".e0".parse::().is_err()); assert!(".e0".parse::().is_err()); } #[test] fn lonely_sign() { - assert!("+".parse::().is_err()); - assert!("-".parse::().is_err()); + #[cfg(target_has_reliable_f16)] + assert!("+".parse::().is_err()); + assert!("-".parse::().is_err()); + assert!("+".parse::().is_err()); } #[test] fn whitespace() { + #[cfg(target_has_reliable_f16)] + assert!("1.0 ".parse::().is_err()); assert!(" 1.0".parse::().is_err()); assert!("1.0 ".parse::().is_err()); } #[test] fn nan() { + #[cfg(target_has_reliable_f16)] + { + assert!("NaN".parse::().unwrap().is_nan()); + assert!("-NaN".parse::().unwrap().is_nan()); + } + assert!("NaN".parse::().unwrap().is_nan()); + assert!("-NaN".parse::().unwrap().is_nan()); + assert!("NaN".parse::().unwrap().is_nan()); + assert!("-NaN".parse::().unwrap().is_nan()); } #[test] fn inf() { - assert_eq!("inf".parse(), Ok(f64::INFINITY)); - assert_eq!("-inf".parse(), Ok(f64::NEG_INFINITY)); + #[cfg(target_has_reliable_f16)] + { + assert_eq!("inf".parse(), Ok(f16::INFINITY)); + assert_eq!("-inf".parse(), Ok(f16::NEG_INFINITY)); + } + assert_eq!("inf".parse(), Ok(f32::INFINITY)); assert_eq!("-inf".parse(), Ok(f32::NEG_INFINITY)); + + assert_eq!("inf".parse(), Ok(f64::INFINITY)); + assert_eq!("-inf".parse(), Ok(f64::NEG_INFINITY)); } #[test] fn massive_exponent() { + #[cfg(target_has_reliable_f16)] + { + let max = i16::MAX; + assert_eq!(format!("1e{max}000").parse(), Ok(f16::INFINITY)); + assert_eq!(format!("1e-{max}000").parse(), Ok(0.0f16)); + assert_eq!(format!("1e{max}000").parse(), Ok(f16::INFINITY)); + } + + let max = i32::MAX; + assert_eq!(format!("1e{max}000").parse(), Ok(f32::INFINITY)); + assert_eq!(format!("1e-{max}000").parse(), Ok(0.0f32)); + assert_eq!(format!("1e{max}000").parse(), Ok(f32::INFINITY)); + let max = i64::MAX; assert_eq!(format!("1e{max}000").parse(), Ok(f64::INFINITY)); - assert_eq!(format!("1e-{max}000").parse(), Ok(0.0)); + assert_eq!(format!("1e-{max}000").parse(), Ok(0.0f64)); assert_eq!(format!("1e{max}000").parse(), Ok(f64::INFINITY)); } diff --git a/library/coretests/tests/num/dec2flt/parse.rs b/library/coretests/tests/num/dec2flt/parse.rs index 59be3915052d8..dccb6b5528d4c 100644 --- a/library/coretests/tests/num/dec2flt/parse.rs +++ b/library/coretests/tests/num/dec2flt/parse.rs @@ -10,6 +10,9 @@ fn new_dec(e: i64, m: u64) -> Decimal { fn missing_pieces() { let permutations = &[".e", "1e", "e4", "e", ".12e", "321.e", "32.12e+", "12.32e-"]; for &s in permutations { + #[cfg(target_has_reliable_f16)] + assert_eq!(dec2flt::(s), Err(pfe_invalid())); + assert_eq!(dec2flt::(s), Err(pfe_invalid())); assert_eq!(dec2flt::(s), Err(pfe_invalid())); } } @@ -17,15 +20,31 @@ fn missing_pieces() { #[test] fn invalid_chars() { let invalid = "r,?(&input) == error, "did not reject invalid {:?}", input); + + #[cfg(target_has_reliable_f16)] + assert_eq!( + dec2flt::(&input), + Err(pfe_invalid()), + "f16 did not reject invalid {input:?}", + ); + assert_eq!( + dec2flt::(&input), + Err(pfe_invalid()), + "f32 did not reject invalid {input:?}", + ); + assert_eq!( + dec2flt::(&input), + Err(pfe_invalid()), + "f64 did not reject invalid {input:?}", + ); } } } diff --git a/library/coretests/tests/num/flt2dec/mod.rs b/library/coretests/tests/num/flt2dec/mod.rs index c64bb0a30720a..ce36db33d05f3 100644 --- a/library/coretests/tests/num/flt2dec/mod.rs +++ b/library/coretests/tests/num/flt2dec/mod.rs @@ -16,7 +16,7 @@ mod random; pub fn decode_finite(v: T) -> Decoded { match decode(v).1 { FullDecoded::Finite(decoded) => decoded, - full_decoded => panic!("expected finite, got {full_decoded:?} instead"), + full_decoded => panic!("expected finite, got {full_decoded:?} instead for {v:?}"), } } @@ -75,6 +75,11 @@ macro_rules! try_fixed { }) } +#[cfg(target_has_reliable_f16)] +fn ldexp_f16(a: f16, b: i32) -> f16 { + ldexp_f64(a as f64, b) as f16 +} + fn ldexp_f32(a: f32, b: i32) -> f32 { ldexp_f64(a as f64, b) as f32 } @@ -176,6 +181,13 @@ trait TestableFloat: DecodableFloat + fmt::Display { fn ldexpi(f: i64, exp: isize) -> Self; } +#[cfg(target_has_reliable_f16)] +impl TestableFloat for f16 { + fn ldexpi(f: i64, exp: isize) -> Self { + f as Self * (exp as Self).exp2() + } +} + impl TestableFloat for f32 { fn ldexpi(f: i64, exp: isize) -> Self { f as Self * (exp as Self).exp2() @@ -225,6 +237,76 @@ macro_rules! check_exact_one { // // [1] Vern Paxson, A Program for Testing IEEE Decimal-Binary Conversion // ftp://ftp.ee.lbl.gov/testbase-report.ps.Z +// or https://www.icir.org/vern/papers/testbase-report.pdf + +#[cfg(target_has_reliable_f16)] +pub fn f16_shortest_sanity_test(mut f: F) +where + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), +{ + // 0.0999145507813 + // 0.0999755859375 + // 0.100036621094 + check_shortest!(f(0.1f16) => b"1", 0); + + // 0.3330078125 + // 0.333251953125 (1/3 in the default rounding) + // 0.33349609375 + check_shortest!(f(1.0f16/3.0) => b"3333", 0); + + // 10^1 * 0.3138671875 + // 10^1 * 0.3140625 + // 10^1 * 0.3142578125 + check_shortest!(f(3.14f16) => b"314", 1); + + // 10^18 * 0.31415916243714048 + // 10^18 * 0.314159196796878848 + // 10^18 * 0.314159231156617216 + check_shortest!(f(3.1415e4f16) => b"3141", 5); + + // regression test for decoders + // 10^2 * 0.31984375 + // 10^2 * 0.32 + // 10^2 * 0.3203125 + check_shortest!(f(ldexp_f16(1.0, 5)) => b"32", 2); + + // 10^5 * 0.65472 + // 10^5 * 0.65504 + // 10^5 * 0.65536 + check_shortest!(f(f16::MAX) => b"655", 5); + + // 10^-4 * 0.60975551605224609375 + // 10^-4 * 0.6103515625 + // 10^-4 * 0.61094760894775390625 + check_shortest!(f(f16::MIN_POSITIVE) => b"6104", -4); + + // 10^-9 * 0 + // 10^-9 * 0.59604644775390625 + // 10^-8 * 0.11920928955078125 + let minf16 = ldexp_f16(1.0, -24); + check_shortest!(f(minf16) => b"6", -7); +} + +#[cfg(target_has_reliable_f16)] +pub fn f16_exact_sanity_test(mut f: F) +where + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), +{ + let minf16 = ldexp_f16(1.0, -24); + + check_exact!(f(0.1f16) => b"999755859375 ", -1); + check_exact!(f(0.5f16) => b"5 ", 0); + check_exact!(f(1.0f16/3.0) => b"333251953125 ", 0); + check_exact!(f(3.141f16) => b"3140625 ", 1); + check_exact!(f(3.141e4f16) => b"31408 ", 5); + check_exact!(f(f16::MAX) => b"65504 ", 5); + check_exact!(f(f16::MIN_POSITIVE) => b"6103515625 ", -4); + check_exact!(f(minf16) => b"59604644775390625", -7); + + // FIXME(f16_f128): these should gain the check_exact_one tests like `f32` and `f64` have, + // but these values are not easy to generate. The algorithm from the Paxon paper [1] needs + // to be adapted to binary16. +} pub fn f32_shortest_sanity_test(mut f: F) where @@ -553,23 +635,45 @@ where assert_eq!(to_string(f, 1.9971e20, Minus, 1), "199710000000000000000.0"); assert_eq!(to_string(f, 1.9971e20, Minus, 8), "199710000000000000000.00000000"); - assert_eq!(to_string(f, f32::MAX, Minus, 0), format!("34028235{:0>31}", "")); - assert_eq!(to_string(f, f32::MAX, Minus, 1), format!("34028235{:0>31}.0", "")); - assert_eq!(to_string(f, f32::MAX, Minus, 8), format!("34028235{:0>31}.00000000", "")); - - let minf32 = ldexp_f32(1.0, -149); - assert_eq!(to_string(f, minf32, Minus, 0), format!("0.{:0>44}1", "")); - assert_eq!(to_string(f, minf32, Minus, 45), format!("0.{:0>44}1", "")); - assert_eq!(to_string(f, minf32, Minus, 46), format!("0.{:0>44}10", "")); + #[cfg(target_has_reliable_f16)] + { + // f16 + assert_eq!(to_string(f, f16::MAX, Minus, 0), "65500"); + assert_eq!(to_string(f, f16::MAX, Minus, 1), "65500.0"); + assert_eq!(to_string(f, f16::MAX, Minus, 8), "65500.00000000"); + + let minf16 = ldexp_f16(1.0, -24); + assert_eq!(to_string(f, minf16, Minus, 0), "0.00000006"); + assert_eq!(to_string(f, minf16, Minus, 8), "0.00000006"); + assert_eq!(to_string(f, minf16, Minus, 9), "0.000000060"); + } - assert_eq!(to_string(f, f64::MAX, Minus, 0), format!("17976931348623157{:0>292}", "")); - assert_eq!(to_string(f, f64::MAX, Minus, 1), format!("17976931348623157{:0>292}.0", "")); - assert_eq!(to_string(f, f64::MAX, Minus, 8), format!("17976931348623157{:0>292}.00000000", "")); + { + // f32 + assert_eq!(to_string(f, f32::MAX, Minus, 0), format!("34028235{:0>31}", "")); + assert_eq!(to_string(f, f32::MAX, Minus, 1), format!("34028235{:0>31}.0", "")); + assert_eq!(to_string(f, f32::MAX, Minus, 8), format!("34028235{:0>31}.00000000", "")); + + let minf32 = ldexp_f32(1.0, -149); + assert_eq!(to_string(f, minf32, Minus, 0), format!("0.{:0>44}1", "")); + assert_eq!(to_string(f, minf32, Minus, 45), format!("0.{:0>44}1", "")); + assert_eq!(to_string(f, minf32, Minus, 46), format!("0.{:0>44}10", "")); + } - let minf64 = ldexp_f64(1.0, -1074); - assert_eq!(to_string(f, minf64, Minus, 0), format!("0.{:0>323}5", "")); - assert_eq!(to_string(f, minf64, Minus, 324), format!("0.{:0>323}5", "")); - assert_eq!(to_string(f, minf64, Minus, 325), format!("0.{:0>323}50", "")); + { + // f64 + assert_eq!(to_string(f, f64::MAX, Minus, 0), format!("17976931348623157{:0>292}", "")); + assert_eq!(to_string(f, f64::MAX, Minus, 1), format!("17976931348623157{:0>292}.0", "")); + assert_eq!( + to_string(f, f64::MAX, Minus, 8), + format!("17976931348623157{:0>292}.00000000", "") + ); + + let minf64 = ldexp_f64(1.0, -1074); + assert_eq!(to_string(f, minf64, Minus, 0), format!("0.{:0>323}5", "")); + assert_eq!(to_string(f, minf64, Minus, 324), format!("0.{:0>323}5", "")); + assert_eq!(to_string(f, minf64, Minus, 325), format!("0.{:0>323}50", "")); + } if cfg!(miri) { // Miri is too slow @@ -655,27 +759,45 @@ where assert_eq!(to_string(f, 1.0e23, Minus, (23, 24), false), "100000000000000000000000"); assert_eq!(to_string(f, 1.0e23, Minus, (24, 25), false), "1e23"); - assert_eq!(to_string(f, f32::MAX, Minus, (-4, 16), false), "3.4028235e38"); - assert_eq!(to_string(f, f32::MAX, Minus, (-39, 38), false), "3.4028235e38"); - assert_eq!(to_string(f, f32::MAX, Minus, (-38, 39), false), format!("34028235{:0>31}", "")); - - let minf32 = ldexp_f32(1.0, -149); - assert_eq!(to_string(f, minf32, Minus, (-4, 16), false), "1e-45"); - assert_eq!(to_string(f, minf32, Minus, (-44, 45), false), "1e-45"); - assert_eq!(to_string(f, minf32, Minus, (-45, 44), false), format!("0.{:0>44}1", "")); - - assert_eq!(to_string(f, f64::MAX, Minus, (-4, 16), false), "1.7976931348623157e308"); - assert_eq!( - to_string(f, f64::MAX, Minus, (-308, 309), false), - format!("17976931348623157{:0>292}", "") - ); - assert_eq!(to_string(f, f64::MAX, Minus, (-309, 308), false), "1.7976931348623157e308"); + #[cfg(target_has_reliable_f16)] + { + // f16 + assert_eq!(to_string(f, f16::MAX, Minus, (-2, 2), false), "6.55e4"); + assert_eq!(to_string(f, f16::MAX, Minus, (-4, 4), false), "6.55e4"); + assert_eq!(to_string(f, f16::MAX, Minus, (-5, 5), false), "65500"); + + let minf16 = ldexp_f16(1.0, -24); + assert_eq!(to_string(f, minf16, Minus, (-2, 2), false), "6e-8"); + assert_eq!(to_string(f, minf16, Minus, (-7, 7), false), "6e-8"); + assert_eq!(to_string(f, minf16, Minus, (-8, 8), false), "0.00000006"); + } - let minf64 = ldexp_f64(1.0, -1074); - assert_eq!(to_string(f, minf64, Minus, (-4, 16), false), "5e-324"); - assert_eq!(to_string(f, minf64, Minus, (-324, 323), false), format!("0.{:0>323}5", "")); - assert_eq!(to_string(f, minf64, Minus, (-323, 324), false), "5e-324"); + { + // f32 + assert_eq!(to_string(f, f32::MAX, Minus, (-4, 16), false), "3.4028235e38"); + assert_eq!(to_string(f, f32::MAX, Minus, (-39, 38), false), "3.4028235e38"); + assert_eq!(to_string(f, f32::MAX, Minus, (-38, 39), false), format!("34028235{:0>31}", "")); + + let minf32 = ldexp_f32(1.0, -149); + assert_eq!(to_string(f, minf32, Minus, (-4, 16), false), "1e-45"); + assert_eq!(to_string(f, minf32, Minus, (-44, 45), false), "1e-45"); + assert_eq!(to_string(f, minf32, Minus, (-45, 44), false), format!("0.{:0>44}1", "")); + } + { + // f64 + assert_eq!(to_string(f, f64::MAX, Minus, (-4, 16), false), "1.7976931348623157e308"); + assert_eq!( + to_string(f, f64::MAX, Minus, (-308, 309), false), + format!("17976931348623157{:0>292}", "") + ); + assert_eq!(to_string(f, f64::MAX, Minus, (-309, 308), false), "1.7976931348623157e308"); + + let minf64 = ldexp_f64(1.0, -1074); + assert_eq!(to_string(f, minf64, Minus, (-4, 16), false), "5e-324"); + assert_eq!(to_string(f, minf64, Minus, (-324, 323), false), format!("0.{:0>323}5", "")); + assert_eq!(to_string(f, minf64, Minus, (-323, 324), false), "5e-324"); + } assert_eq!(to_string(f, 1.1, Minus, (i16::MIN, i16::MAX), false), "1.1"); } @@ -791,6 +913,26 @@ where "9.999999999999999547481118258862586856139387236908078193664550781250000e-7" ); + #[cfg(target_has_reliable_f16)] + { + assert_eq!(to_string(f, f16::MAX, Minus, 1, false), "7e4"); + assert_eq!(to_string(f, f16::MAX, Minus, 2, false), "6.6e4"); + assert_eq!(to_string(f, f16::MAX, Minus, 4, false), "6.550e4"); + assert_eq!(to_string(f, f16::MAX, Minus, 5, false), "6.5504e4"); + assert_eq!(to_string(f, f16::MAX, Minus, 6, false), "6.55040e4"); + assert_eq!(to_string(f, f16::MAX, Minus, 16, false), "6.550400000000000e4"); + + let minf16 = ldexp_f16(1.0, -24); + assert_eq!(to_string(f, minf16, Minus, 1, false), "6e-8"); + assert_eq!(to_string(f, minf16, Minus, 2, false), "6.0e-8"); + assert_eq!(to_string(f, minf16, Minus, 4, false), "5.960e-8"); + assert_eq!(to_string(f, minf16, Minus, 8, false), "5.9604645e-8"); + assert_eq!(to_string(f, minf16, Minus, 16, false), "5.960464477539062e-8"); + assert_eq!(to_string(f, minf16, Minus, 17, false), "5.9604644775390625e-8"); + assert_eq!(to_string(f, minf16, Minus, 18, false), "5.96046447753906250e-8"); + assert_eq!(to_string(f, minf16, Minus, 24, false), "5.96046447753906250000000e-8"); + } + assert_eq!(to_string(f, f32::MAX, Minus, 1, false), "3e38"); assert_eq!(to_string(f, f32::MAX, Minus, 2, false), "3.4e38"); assert_eq!(to_string(f, f32::MAX, Minus, 4, false), "3.403e38"); @@ -1069,6 +1211,13 @@ where "0.000000999999999999999954748111825886258685613938723690807819366455078125000" ); + #[cfg(target_has_reliable_f16)] + { + assert_eq!(to_string(f, f16::MAX, Minus, 0), "65504"); + assert_eq!(to_string(f, f16::MAX, Minus, 1), "65504.0"); + assert_eq!(to_string(f, f16::MAX, Minus, 2), "65504.00"); + } + assert_eq!(to_string(f, f32::MAX, Minus, 0), "340282346638528859811704183484516925440"); assert_eq!(to_string(f, f32::MAX, Minus, 1), "340282346638528859811704183484516925440.0"); assert_eq!(to_string(f, f32::MAX, Minus, 2), "340282346638528859811704183484516925440.00"); @@ -1078,6 +1227,21 @@ where return; } + #[cfg(target_has_reliable_f16)] + { + let minf16 = ldexp_f16(1.0, -24); + assert_eq!(to_string(f, minf16, Minus, 0), "0"); + assert_eq!(to_string(f, minf16, Minus, 1), "0.0"); + assert_eq!(to_string(f, minf16, Minus, 2), "0.00"); + assert_eq!(to_string(f, minf16, Minus, 4), "0.0000"); + assert_eq!(to_string(f, minf16, Minus, 8), "0.00000006"); + assert_eq!(to_string(f, minf16, Minus, 10), "0.0000000596"); + assert_eq!(to_string(f, minf16, Minus, 15), "0.000000059604645"); + assert_eq!(to_string(f, minf16, Minus, 20), "0.00000005960464477539"); + assert_eq!(to_string(f, minf16, Minus, 24), "0.000000059604644775390625"); + assert_eq!(to_string(f, minf16, Minus, 32), "0.00000005960464477539062500000000"); + } + let minf32 = ldexp_f32(1.0, -149); assert_eq!(to_string(f, minf32, Minus, 0), "0"); assert_eq!(to_string(f, minf32, Minus, 1), "0.0"); diff --git a/library/coretests/tests/num/flt2dec/random.rs b/library/coretests/tests/num/flt2dec/random.rs index 586b49df7d9b2..7386139aaced5 100644 --- a/library/coretests/tests/num/flt2dec/random.rs +++ b/library/coretests/tests/num/flt2dec/random.rs @@ -79,6 +79,20 @@ where (npassed, nignored) } +#[cfg(target_has_reliable_f16)] +pub fn f16_random_equivalence_test(f: F, g: G, k: usize, n: usize) +where + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> Option<(&'a [u8], i16)>, + G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), +{ + let mut rng = crate::test_rng(); + let f16_range = Uniform::new(0x0001u16, 0x7c00).unwrap(); + iterate("f16_random_equivalence_test", k, n, f, g, |_| { + let x = f16::from_bits(f16_range.sample(&mut rng)); + decode_finite(x) + }); +} + pub fn f32_random_equivalence_test(f: F, g: G, k: usize, n: usize) where F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> Option<(&'a [u8], i16)>, @@ -105,6 +119,24 @@ where }); } +#[cfg(target_has_reliable_f16)] +pub fn f16_exhaustive_equivalence_test(f: F, g: G, k: usize) +where + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> Option<(&'a [u8], i16)>, + G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), +{ + // Unlike the other float types, `f16` is small enough that these exhaustive tests + // can run in less than a second so we don't need to ignore it. + + // iterate from 0x0001 to 0x7bff, i.e., all finite ranges + let (npassed, nignored) = + iterate("f16_exhaustive_equivalence_test", k, 0x7bff, f, g, |i: usize| { + let x = f16::from_bits(i as u16 + 1); + decode_finite(x) + }); + assert_eq!((npassed, nignored), (29735, 2008)); +} + pub fn f32_exhaustive_equivalence_test(f: F, g: G, k: usize) where F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> Option<(&'a [u8], i16)>, @@ -133,6 +165,17 @@ fn shortest_random_equivalence_test() { f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, n); f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, n); + #[cfg(target_has_reliable_f16)] + f16_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, n); +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri is to slow +#[cfg(target_has_reliable_f16)] +fn shortest_f16_exhaustive_equivalence_test() { + // see the f32 version + use core::num::flt2dec::strategy::dragon::format_shortest as fallback; + f16_exhaustive_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS); } #[test] @@ -158,6 +201,23 @@ fn shortest_f64_hard_random_equivalence_test() { f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 100_000_000); } +#[test] +#[cfg(target_has_reliable_f16)] +fn exact_f16_random_equivalence_test() { + use core::num::flt2dec::strategy::dragon::format_exact as fallback; + // Miri is too slow + let n = if cfg!(miri) { 3 } else { 1_000 }; + + for k in 1..21 { + f16_random_equivalence_test( + |d, buf| format_exact_opt(d, buf, i16::MIN), + |d, buf| fallback(d, buf, i16::MIN), + k, + n, + ); + } +} + #[test] fn exact_f32_random_equivalence_test() { use core::num::flt2dec::strategy::dragon::format_exact as fallback; diff --git a/library/coretests/tests/num/flt2dec/strategy/dragon.rs b/library/coretests/tests/num/flt2dec/strategy/dragon.rs index be25fee3f6c71..43bb6024f9cee 100644 --- a/library/coretests/tests/num/flt2dec/strategy/dragon.rs +++ b/library/coretests/tests/num/flt2dec/strategy/dragon.rs @@ -18,6 +18,8 @@ fn test_mul_pow10() { fn shortest_sanity_test() { f64_shortest_sanity_test(format_shortest); f32_shortest_sanity_test(format_shortest); + #[cfg(target_has_reliable_f16)] + f16_shortest_sanity_test(format_shortest); more_shortest_sanity_test(format_shortest); } @@ -41,6 +43,9 @@ fn exact_sanity_test() { f64_exact_sanity_test(format_exact); } f32_exact_sanity_test(format_exact); + + #[cfg(target_has_reliable_f16)] + f16_exact_sanity_test(format_exact); } #[test] diff --git a/library/coretests/tests/num/flt2dec/strategy/grisu.rs b/library/coretests/tests/num/flt2dec/strategy/grisu.rs index 9b2f0453de73e..117191e0c8fdb 100644 --- a/library/coretests/tests/num/flt2dec/strategy/grisu.rs +++ b/library/coretests/tests/num/flt2dec/strategy/grisu.rs @@ -38,6 +38,8 @@ fn test_max_pow10_no_more_than() { fn shortest_sanity_test() { f64_shortest_sanity_test(format_shortest); f32_shortest_sanity_test(format_shortest); + #[cfg(target_has_reliable_f16)] + f16_shortest_sanity_test(format_shortest); more_shortest_sanity_test(format_shortest); } @@ -50,6 +52,8 @@ fn exact_sanity_test() { f64_exact_sanity_test(format_exact); } f32_exact_sanity_test(format_exact); + #[cfg(target_has_reliable_f16)] + f16_exact_sanity_test(format_exact); } #[test] From 250869e909e643c90582337406e943009569fc6e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 25 Aug 2024 01:30:17 -0500 Subject: [PATCH 2435/4206] float: Add `f16` to `test-float-parse` This requires a fix to the subnormal test to cap the maximum allowed value within the maximum mantissa. --- src/bootstrap/src/core/build_steps/test.rs | 4 +++- src/bootstrap/src/core/build_steps/tool.rs | 6 +++++- src/etc/test-float-parse/Cargo.toml | 7 +++++++ src/etc/test-float-parse/src/gen_/subnorm.rs | 9 +++++++-- src/etc/test-float-parse/src/lib.rs | 7 +++++++ src/etc/test-float-parse/src/traits.rs | 5 ++++- 6 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index b2dc509ddca0e..27791825aa0f6 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -3554,7 +3554,7 @@ impl Step for TestFloatParse { builder.ensure(tool::TestFloatParse { host: self.host }); // Run any unit tests in the crate - let cargo_test = tool::prepare_tool_cargo( + let mut cargo_test = tool::prepare_tool_cargo( builder, compiler, Mode::ToolStd, @@ -3564,6 +3564,7 @@ impl Step for TestFloatParse { SourceType::InTree, &[], ); + cargo_test.allow_features(tool::TestFloatParse::ALLOW_FEATURES); run_cargo_test(cargo_test, &[], &[], crate_name, bootstrap_host, builder); @@ -3578,6 +3579,7 @@ impl Step for TestFloatParse { SourceType::InTree, &[], ); + cargo_run.allow_features(tool::TestFloatParse::ALLOW_FEATURES); if !matches!(env::var("FLOAT_PARSE_TESTS_NO_SKIP_HUGE").as_deref(), Ok("1") | Ok("true")) { cargo_run.args(["--", "--skip-huge"]); diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index ac568eab2e8a5..678aa9b01e4ad 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -1259,6 +1259,10 @@ pub struct TestFloatParse { pub host: TargetSelection, } +impl TestFloatParse { + pub const ALLOW_FEATURES: &'static str = "f16,cfg_target_has_reliable_f16_f128"; +} + impl Step for TestFloatParse { type Output = ToolBuildResult; const ONLY_HOSTS: bool = true; @@ -1280,7 +1284,7 @@ impl Step for TestFloatParse { path: "src/etc/test-float-parse", source_type: SourceType::InTree, extra_features: Vec::new(), - allow_features: "", + allow_features: Self::ALLOW_FEATURES, cargo_args: Vec::new(), artifact_kind: ToolArtifactKind::Binary, }) diff --git a/src/etc/test-float-parse/Cargo.toml b/src/etc/test-float-parse/Cargo.toml index 8a9c5322ef7bd..e407e322f9e19 100644 --- a/src/etc/test-float-parse/Cargo.toml +++ b/src/etc/test-float-parse/Cargo.toml @@ -13,3 +13,10 @@ rayon = "1" [lib] name = "test_float_parse" + +[lints.rust.unexpected_cfgs] +level = "warn" +check-cfg = [ + # Internal features aren't marked known config by default + 'cfg(target_has_reliable_f16)', +] diff --git a/src/etc/test-float-parse/src/gen_/subnorm.rs b/src/etc/test-float-parse/src/gen_/subnorm.rs index 4fe3b90a3ddf4..654f324b9b011 100644 --- a/src/etc/test-float-parse/src/gen_/subnorm.rs +++ b/src/etc/test-float-parse/src/gen_/subnorm.rs @@ -1,4 +1,3 @@ -use std::cmp::min; use std::fmt::Write; use std::ops::RangeInclusive; @@ -83,7 +82,13 @@ where } fn new() -> Self { - Self { iter: F::Int::ZERO..=min(F::Int::ONE << 22, F::MAN_BITS.try_into().unwrap()) } + let upper_lim = if F::MAN_BITS >= 22 { + F::Int::ONE << 22 + } else { + (F::Int::ONE << F::MAN_BITS) - F::Int::ONE + }; + + Self { iter: F::Int::ZERO..=upper_lim } } fn write_string(s: &mut String, ctx: Self::WriteCtx) { diff --git a/src/etc/test-float-parse/src/lib.rs b/src/etc/test-float-parse/src/lib.rs index 3c3ef5802b6aa..0bd4878f9a626 100644 --- a/src/etc/test-float-parse/src/lib.rs +++ b/src/etc/test-float-parse/src/lib.rs @@ -1,3 +1,7 @@ +#![feature(f16)] +#![feature(cfg_target_has_reliable_f16_f128)] +#![expect(internal_features)] // reliable_f16_f128 + mod traits; mod ui; mod validate; @@ -114,6 +118,9 @@ pub fn register_tests(cfg: &Config) -> Vec { let mut tests = Vec::new(); // Register normal generators for all floats. + + #[cfg(target_has_reliable_f16)] + register_float::(&mut tests, cfg); register_float::(&mut tests, cfg); register_float::(&mut tests, cfg); diff --git a/src/etc/test-float-parse/src/traits.rs b/src/etc/test-float-parse/src/traits.rs index 57e702b7d0913..65a8721bfa5cd 100644 --- a/src/etc/test-float-parse/src/traits.rs +++ b/src/etc/test-float-parse/src/traits.rs @@ -98,7 +98,7 @@ macro_rules! impl_int { } } -impl_int!(u32, i32; u64, i64); +impl_int!(u16, i16; u32, i32; u64, i64); /// Floating point types. pub trait Float: @@ -170,6 +170,9 @@ macro_rules! impl_float { impl_float!(f32, u32; f64, u64); +#[cfg(target_has_reliable_f16)] +impl_float!(f16, u16); + /// A test generator. Should provide an iterator that produces unique patterns to parse. /// /// The iterator needs to provide a `WriteCtx` (could be anything), which is then used to From 34ee7e206f5e9cc06991ac5fe3732fd3b3149169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sun, 18 May 2025 20:01:47 +0200 Subject: [PATCH 2436/4206] Exclude issues with an associated PR from the "What should I work on" GH query --- src/doc/rustc-dev-guide/src/getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/getting-started.md b/src/doc/rustc-dev-guide/src/getting-started.md index 8bf14bef2a033..0e5b32a06f898 100644 --- a/src/doc/rustc-dev-guide/src/getting-started.md +++ b/src/doc/rustc-dev-guide/src/getting-started.md @@ -89,7 +89,7 @@ filtering the search to areas you're interested in. For example: Not all important or beginner work has issue labels. See below for how to find work that isn't labelled. -[help-wanted-search]: https://github.com/issues?q=is%3Aopen+is%3Aissue+org%3Arust-lang+no%3Aassignee+label%3AE-easy%2C%22good+first+issue%22%2Cgood-first-issue%2CE-medium%2CEasy%2CE-help-wanted%2CE-mentor+-label%3AS-blocked+ +[help-wanted-search]: https://github.com/issues?q=is%3Aopen+is%3Aissue+org%3Arust-lang+no%3Aassignee+label%3AE-easy%2C%22good+first+issue%22%2Cgood-first-issue%2CE-medium%2CEasy%2CE-help-wanted%2CE-mentor+-label%3AS-blocked+-linked:pr+ [Triage]: ./contributing.md#issue-triage ### Recurring work From 90ebad3f49ab355daee86946a41f336b90c6c502 Mon Sep 17 00:00:00 2001 From: Jeremy Smart Date: Sun, 18 May 2025 22:37:30 -0400 Subject: [PATCH 2437/4206] add exact_div functions --- library/core/src/num/int_macros.rs | 106 +++++++++++++++++++++++++++- library/core/src/num/uint_macros.rs | 102 ++++++++++++++++++++++++++ 2 files changed, 207 insertions(+), 1 deletion(-) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 84e1482ed31db..583887c2e632e 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -4,7 +4,7 @@ macro_rules! int_impl { ActualT = $ActualT:ident, UnsignedT = $UnsignedT:ty, - // There are all for use *only* in doc comments. + // These are all for use *only* in doc comments. // As such, they're all passed as literals -- passing them as a string // literal is fine if they need to be multiple code tokens. // In non-comments, use the associated constants rather than these. @@ -1018,6 +1018,110 @@ macro_rules! int_impl { if b { overflow_panic::div() } else { a } } + /// Checked integer division without remainder. Computes `self / rhs`, + /// returning `None` if `rhs == 0`, the division results in overflow, + /// or `self % rhs != 0`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(exact_div)] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).checked_exact_div(-1), Some(", stringify!($Max), "));")] + #[doc = concat!("assert_eq!((-5", stringify!($SelfT), ").checked_exact_div(2), None);")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.checked_exact_div(-1), None);")] + #[doc = concat!("assert_eq!((1", stringify!($SelfT), ").checked_exact_div(0), None);")] + /// ``` + #[unstable( + feature = "exact_div", + issue = "139911", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_exact_div(self, rhs: Self) -> Option { + if intrinsics::unlikely(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) { + None + } else { + // SAFETY: division by zero and overflow are checked above + unsafe { + if intrinsics::unlikely(intrinsics::unchecked_rem(self, rhs) != 0) { + None + } else { + Some(intrinsics::exact_div(self, rhs)) + } + } + } + } + + /// Checked integer division without remainder. Computes `self / rhs`. + /// + /// # Panics + /// + /// This function will panic if `rhs == 0`, the division results in overflow, + /// or `self % rhs != 0`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(exact_div)] + #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(2), 32);")] + #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(32), 2);")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).exact_div(-1), ", stringify!($Max), ");")] + /// ``` + /// + /// ```should_panic + /// #![feature(exact_div)] + #[doc = concat!("let _ = 65", stringify!($SelfT), ".exact_div(2);")] + /// ``` + /// ```should_panic + /// #![feature(exact_div)] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.exact_div(-1);")] + /// ``` + #[unstable( + feature = "exact_div", + issue = "139911", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn exact_div(self, rhs: Self) -> Self { + match self.checked_exact_div(rhs) { + Some(x) => x, + None => panic!("Failed to divide without remainder"), + } + } + + /// Unchecked integer division without remainder. Computes `self / rhs`. + /// + /// # Safety + /// + /// This results in undefined behavior when `rhs == 0`, `self % rhs != 0`, or + #[doc = concat!("`self == ", stringify!($SelfT), "::MIN && rhs == -1`,")] + /// i.e. when [`checked_exact_div`](Self::checked_exact_div) would return `None`. + #[unstable( + feature = "exact_div", + issue = "139911", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const unsafe fn unchecked_exact_div(self, rhs: Self) -> Self { + assert_unsafe_precondition!( + check_language_ub, + concat!(stringify!($SelfT), "::unchecked_exact_div cannot overflow, divide by zero, or leave a remainder"), + ( + lhs: $SelfT = self, + rhs: $SelfT = rhs, + ) => rhs > 0 && lhs % rhs == 0 && (lhs != <$SelfT>::MIN || rhs != -1), + ); + // SAFETY: Same precondition + unsafe { intrinsics::exact_div(self, rhs) } + } + /// Checked integer remainder. Computes `self % rhs`, returning `None` if /// `rhs == 0` or the division results in overflow. /// diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index f38d809c1544b..8b0b28b617f15 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1110,6 +1110,108 @@ macro_rules! uint_impl { self / rhs } + /// Checked integer division without remainder. Computes `self / rhs`. + /// + /// # Panics + /// + /// This function will panic if `rhs == 0` or `self % rhs != 0`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(exact_div)] + #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(2), 32);")] + #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(32), 2);")] + /// ``` + /// + /// ```should_panic + /// #![feature(exact_div)] + #[doc = concat!("let _ = 65", stringify!($SelfT), ".exact_div(2);")] + /// ``` + #[unstable( + feature = "exact_div", + issue = "139911", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_exact_div(self, rhs: Self) -> Option { + if intrinsics::unlikely(rhs == 0) { + None + } else { + // SAFETY: division by zero is checked above + unsafe { + if intrinsics::unlikely(intrinsics::unchecked_rem(self, rhs) != 0) { + None + } else { + Some(intrinsics::exact_div(self, rhs)) + } + } + } + } + + /// Checked integer division without remainder. Computes `self / rhs`. + /// + /// # Panics + /// + /// This function will panic if `rhs == 0` or `self % rhs != 0`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(exact_div)] + #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(2), 32);")] + #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(32), 2);")] + /// ``` + /// + /// ```should_panic + /// #![feature(exact_div)] + #[doc = concat!("let _ = 65", stringify!($SelfT), ".exact_div(2);")] + /// ``` + #[unstable( + feature = "exact_div", + issue = "139911", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn exact_div(self, rhs: Self) -> Self { + match self.checked_exact_div(rhs) { + Some(x) => x, + None => panic!("Failed to divide without remainder"), + } + } + + /// Unchecked integer division without remainder. Computes `self / rhs`. + /// + /// # Safety + /// + /// This results in undefined behavior when `rhs == 0` or `self % rhs != 0`, + /// i.e. when [`checked_exact_div`](Self::checked_exact_div) would return `None`. + #[unstable( + feature = "exact_div", + issue = "139911", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const unsafe fn unchecked_exact_div(self, rhs: Self) -> Self { + assert_unsafe_precondition!( + check_language_ub, + concat!(stringify!($SelfT), "::unchecked_exact_div divide by zero or leave a remainder"), + ( + lhs: $SelfT = self, + rhs: $SelfT = rhs, + ) => rhs > 0 && lhs % rhs == 0, + ); + // SAFETY: Same precondition + unsafe { intrinsics::exact_div(self, rhs) } + } + /// Checked integer remainder. Computes `self % rhs`, returning `None` /// if `rhs == 0`. /// From 70ead0af5be34bf03a9313be20fa610668b41340 Mon Sep 17 00:00:00 2001 From: The rustc-dev-guide Cronjob Bot Date: Mon, 19 May 2025 04:10:52 +0000 Subject: [PATCH 2438/4206] Preparing for merge from rustc --- src/doc/rustc-dev-guide/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 5e4266f61da2a..0d889a5d5b991 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -414482f6a0d4e7290f614300581a0b55442552a3 +e42bbfe1f7c26f8760a99c4b1f27d33aba1040bb From b2a8690aa101c0a3232ec43535dd2f3fc6bd5366 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Mon, 19 May 2025 04:54:41 +0000 Subject: [PATCH 2439/4206] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 8b98fe3c4fc3e..0d889a5d5b991 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -ac17c3486c6fdfbb0c3c18b99f3d8dfbff625d29 +e42bbfe1f7c26f8760a99c4b1f27d33aba1040bb From d22f53b97033a5450c8aa32c9e1115c1d54bafb4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 19 May 2025 08:20:03 +0200 Subject: [PATCH 2440/4206] dladdr cannot leave dli_fname to be null --- compiler/rustc_session/src/filesearch.rs | 4 +--- src/tools/miri/src/shims/native_lib.rs | 8 ++++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 207ba5157bdb6..cb3e9c80a131d 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -82,9 +82,7 @@ fn current_dll_path() -> Result { let fname_ptr = info.dli_fname.as_ptr(); #[cfg(not(target_os = "cygwin"))] let fname_ptr = { - if info.dli_fname.is_null() { - return Err("dladdr returned null pointer".into()); - } + assert!(!info.dli_fname.is_null(), "the docs do not allow dladdr to be null"); info.dli_fname }; let bytes = CStr::from_ptr(fname_ptr).to_bytes(); diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs index 837e1b31cac50..1a43e2297255e 100644 --- a/src/tools/miri/src/shims/native_lib.rs +++ b/src/tools/miri/src/shims/native_lib.rs @@ -92,8 +92,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { fn get_func_ptr_explicitly_from_lib(&mut self, link_name: Symbol) -> Option { let this = self.eval_context_mut(); // Try getting the function from the shared library. - // On windows `_lib_path` will be unused, hence the name starting with `_`. - let (lib, _lib_path) = this.machine.native_lib.as_ref().unwrap(); + let (lib, lib_path) = this.machine.native_lib.as_ref().unwrap(); let func: libloading::Symbol<'_, unsafe extern "C" fn()> = unsafe { match lib.get(link_name.as_str().as_bytes()) { Ok(x) => x, @@ -114,7 +113,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // This code is a reimplementation of the mechanism for getting `dli_fname` in `libloading`, // from: https://docs.rs/libloading/0.7.3/src/libloading/os/unix/mod.rs.html#411 // using the `libc` crate where this interface is public. - let mut info = std::mem::MaybeUninit::::uninit(); + let mut info = std::mem::MaybeUninit::::zeroed(); unsafe { if libc::dladdr(*func.deref() as *const _, info.as_mut_ptr()) != 0 { let info = info.assume_init(); @@ -122,8 +121,9 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let fname_ptr = info.dli_fname.as_ptr(); #[cfg(not(target_os = "cygwin"))] let fname_ptr = info.dli_fname; + assert!(!fname_ptr.is_null()); if std::ffi::CStr::from_ptr(fname_ptr).to_str().unwrap() - != _lib_path.to_str().unwrap() + != lib_path.to_str().unwrap() { return None; } From 687eeeafc8031f143698304b34d5fbdce6bb8e0e Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 19 May 2025 08:40:59 +0200 Subject: [PATCH 2441/4206] Change import prefix default to be by crate The current default plain, tends to create non-uniform import blocks over time, some being relative, some being absolute. I believe we should encourage a different default here. --- src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs | 2 +- .../rust-analyzer/docs/book/src/configuration_generated.md | 2 +- src/tools/rust-analyzer/editors/code/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 03e5b1f6f4b6e..f7158235ca4c5 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -544,7 +544,7 @@ config_data! { /// Whether to prefer import paths containing a `prelude` module. imports_preferPrelude: bool = false, /// The path structure for newly inserted paths to use. - imports_prefix: ImportPrefixDef = ImportPrefixDef::Plain, + imports_prefix: ImportPrefixDef = ImportPrefixDef::ByCrate, /// Whether to prefix external (including std, core) crate imports with `::`. e.g. "use ::std::io::Read;". imports_prefixExternPrelude: bool = false, } diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md index 2ae73df61d0af..de1d0ea4a3599 100644 --- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md +++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md @@ -835,7 +835,7 @@ Whether to prefer import paths containing a `prelude` module. ## rust-analyzer.imports.prefix {#imports.prefix} -Default: `"plain"` +Default: `"crate"` The path structure for newly inserted paths to use. diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index a282eea99973c..88a90aad8c9fc 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -1927,7 +1927,7 @@ "properties": { "rust-analyzer.imports.prefix": { "markdownDescription": "The path structure for newly inserted paths to use.", - "default": "plain", + "default": "crate", "type": "string", "enum": [ "plain", From e493cb1ad2d5aa1c2e21b8c5c948f68aa9f01222 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 17 May 2025 16:08:09 +0200 Subject: [PATCH 2442/4206] Debounce workspace fetching for workspace structure changes --- .../crates/rust-analyzer/src/global_state.rs | 44 ++++++++++++++++--- .../crates/rust-analyzer/src/main_loop.rs | 16 ++++++- .../crates/rust-analyzer/src/op_queue.rs | 2 +- .../crates/rust-analyzer/src/reload.rs | 1 + 4 files changed, 54 insertions(+), 9 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs index 1a31525b46a8d..a870232d4a0e1 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs @@ -3,7 +3,11 @@ //! //! Each tick provides an immutable snapshot of the state as `WorldSnapshot`. -use std::{ops::Not as _, panic::AssertUnwindSafe, time::Instant}; +use std::{ + ops::Not as _, + panic::AssertUnwindSafe, + time::{Duration, Instant}, +}; use crossbeam_channel::{Receiver, Sender, unbounded}; use hir::ChangeWithProcMacros; @@ -41,6 +45,7 @@ use crate::{ test_runner::{CargoTestHandle, CargoTestMessage}, }; +#[derive(Debug)] pub(crate) struct FetchWorkspaceRequest { pub(crate) path: Option, pub(crate) force_crate_graph_reload: bool, @@ -116,6 +121,11 @@ pub(crate) struct GlobalState { pub(crate) discover_sender: Sender, pub(crate) discover_receiver: Receiver, + // Debouncing channel for fetching the workspace + // we want to delay it until the VFS looks stable-ish (and thus is not currently in the middle + // of a VCS operation like `git switch`) + pub(crate) fetch_ws_receiver: Option<(Receiver, FetchWorkspaceRequest)>, + // VFS pub(crate) loader: Handle, Receiver>, pub(crate) vfs: Arc)>>, @@ -268,6 +278,8 @@ impl GlobalState { discover_sender, discover_receiver, + fetch_ws_receiver: None, + vfs: Arc::new(RwLock::new((vfs::Vfs::default(), Default::default()))), vfs_config_version: 0, vfs_progress_config_version: 0, @@ -519,11 +531,7 @@ impl GlobalState { if let Some((path, force_crate_graph_reload)) = workspace_structure_change { let _p = span!(Level::INFO, "GlobalState::process_changes/ws_structure_change") .entered(); - - self.fetch_workspaces_queue.request_op( - format!("workspace vfs file change: {path}"), - FetchWorkspaceRequest { path: Some(path), force_crate_graph_reload }, - ); + self.enqueue_workspace_fetch(path, force_crate_graph_reload); } } @@ -671,6 +679,30 @@ impl GlobalState { None }) } + + fn enqueue_workspace_fetch(&mut self, path: AbsPathBuf, force_crate_graph_reload: bool) { + let already_requested = self.fetch_workspaces_queue.op_requested() + && !self.fetch_workspaces_queue.op_in_progress(); + if self.fetch_ws_receiver.is_none() && already_requested { + // Don't queue up a new fetch request if we already have done so + // Otherwise we will re-fetch in quick succession which is unnecessary + // Note though, that if one is already in progress, we *want* to re-queue + // as the in-progress fetch might not have the latest changes in it anymore + // FIXME: We should cancel the in-progress fetch here + return; + } + + self.fetch_ws_receiver = Some(( + crossbeam_channel::after(Duration::from_millis(100)), + FetchWorkspaceRequest { path: Some(path), force_crate_graph_reload }, + )); + } + + pub(crate) fn debounce_workspace_fetch(&mut self) { + if let Some((fetch_receiver, _)) = &mut self.fetch_ws_receiver { + *fetch_receiver = crossbeam_channel::after(Duration::from_millis(100)); + } + } } impl Drop for GlobalState { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index bd213ffa57a16..0c0438c4b8ff1 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -8,7 +8,7 @@ use std::{ time::{Duration, Instant}, }; -use crossbeam_channel::{Receiver, select}; +use crossbeam_channel::{Receiver, never, select}; use ide_db::base_db::{SourceDatabase, VfsPath, salsa::Database as _}; use lsp_server::{Connection, Notification, Request}; use lsp_types::{TextDocumentIdentifier, notification::Notification as _}; @@ -71,6 +71,7 @@ enum Event { Flycheck(FlycheckMessage), TestResult(CargoTestMessage), DiscoverProject(DiscoverProjectMessage), + FetchWorkspaces(FetchWorkspaceRequest), } impl fmt::Display for Event { @@ -83,6 +84,7 @@ impl fmt::Display for Event { Event::QueuedTask(_) => write!(f, "Event::QueuedTask"), Event::TestResult(_) => write!(f, "Event::TestResult"), Event::DiscoverProject(_) => write!(f, "Event::DiscoverProject"), + Event::FetchWorkspaces(_) => write!(f, "Event::SwitchWorkspaces"), } } } @@ -150,6 +152,7 @@ impl fmt::Debug for Event { } _ => (), } + match self { Event::Lsp(it) => fmt::Debug::fmt(it, f), Event::Task(it) => fmt::Debug::fmt(it, f), @@ -158,6 +161,7 @@ impl fmt::Debug for Event { Event::Flycheck(it) => fmt::Debug::fmt(it, f), Event::TestResult(it) => fmt::Debug::fmt(it, f), Event::DiscoverProject(it) => fmt::Debug::fmt(it, f), + Event::FetchWorkspaces(it) => fmt::Debug::fmt(it, f), } } } @@ -251,7 +255,7 @@ impl GlobalState { } fn next_event( - &self, + &mut self, inbox: &Receiver, ) -> Result, crossbeam_channel::RecvError> { // Make sure we reply to formatting requests ASAP so the editor doesn't block @@ -283,6 +287,10 @@ impl GlobalState { recv(self.discover_receiver) -> task => task.map(Event::DiscoverProject), + + recv(self.fetch_ws_receiver.as_ref().map_or(&never(), |(chan, _)| chan)) -> _instant => { + Ok(Event::FetchWorkspaces(self.fetch_ws_receiver.take().unwrap().1)) + }, } .map(Some) } @@ -412,6 +420,9 @@ impl GlobalState { self.handle_discover_msg(message); } } + Event::FetchWorkspaces(req) => { + self.fetch_workspaces_queue.request_op("project structure change".to_owned(), req) + } } let event_handling_duration = loop_start.elapsed(); let (state_changed, memdocs_added_or_removed) = if self.vfs_done { @@ -830,6 +841,7 @@ impl GlobalState { match message { vfs::loader::Message::Changed { files } | vfs::loader::Message::Loaded { files } => { let _p = tracing::info_span!("GlobalState::handle_vfs_msg{changed/load}").entered(); + self.debounce_workspace_fetch(); let vfs = &mut self.vfs.write().0; for (path, contents) in files { let path = VfsPath::from(path); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/op_queue.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/op_queue.rs index 709d99bda7513..7af5b48bb7a75 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/op_queue.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/op_queue.rs @@ -36,7 +36,7 @@ impl Default for OpQueue { } } -impl OpQueue { +impl OpQueue { /// Request an operation to start. pub(crate) fn request_op(&mut self, reason: Cause, args: Args) { self.op_requested = Some((reason, args)); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs index d7c6aeccf0b5f..ae9e3e9987466 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -69,6 +69,7 @@ impl GlobalState { /// are ready to do semantic work. pub(crate) fn is_quiescent(&self) -> bool { self.vfs_done + && self.fetch_ws_receiver.is_none() && !self.fetch_workspaces_queue.op_in_progress() && !self.fetch_build_data_queue.op_in_progress() && !self.fetch_proc_macros_queue.op_in_progress() From 7123f2acf7e1e85872f7c8dd15aebdd3f459ef12 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Mon, 19 May 2025 09:37:47 +0200 Subject: [PATCH 2443/4206] Docs: Use spaces in `good first issue` label This unifies the Clippy repo with the rest of the rust org repos. --- CONTRIBUTING.md | 6 +++--- book/src/development/the_team.md | 2 +- triagebot.toml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 45ba2f078be78..72ab08792d37e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -51,7 +51,7 @@ Clippy team directly by mentioning them in the issue or over on [Zulip]. All currently active team members can be found [here](https://github.com/rust-lang/rust-clippy/blob/master/triagebot.toml#L18) -Some issues are easier than others. The [`good-first-issue`] label can be used to find the easy +Some issues are easier than others. The [`good first issue`] label can be used to find the easy issues. You can use `@rustbot claim` to assign the issue to yourself. There are also some abandoned PRs, marked with [`S-inactive-closed`]. @@ -70,7 +70,7 @@ To figure out how this syntax structure is encoded in the AST, it is recommended Usually the lint will end up to be a nested series of matches and ifs, [like so][deep-nesting]. But we can make it nest-less by using [let chains], [like this][nest-less]. -[`E-medium`] issues are generally pretty easy too, though it's recommended you work on an [`good-first-issue`] +[`E-medium`] issues are generally pretty easy too, though it's recommended you work on an [`good first issue`] first. Sometimes they are only somewhat involved code wise, but not difficult per-se. Note that [`E-medium`] issues may require some knowledge of Clippy internals or some debugging to find the actual problem behind the issue. @@ -79,7 +79,7 @@ debugging to find the actual problem behind the issue. lot of methods that are useful, though one of the most useful would be `expr_ty` (gives the type of an AST expression). -[`good-first-issue`]: https://github.com/rust-lang/rust-clippy/labels/good-first-issue +[`good first issue`]: https://github.com/rust-lang/rust-clippy/labels/good%20first%20issue [`S-inactive-closed`]: https://github.com/rust-lang/rust-clippy/pulls?q=is%3Aclosed+label%3AS-inactive-closed [`T-AST`]: https://github.com/rust-lang/rust-clippy/labels/T-AST [`T-middle`]: https://github.com/rust-lang/rust-clippy/labels/T-middle diff --git a/book/src/development/the_team.md b/book/src/development/the_team.md index da5d084ed97f3..d22123231868e 100644 --- a/book/src/development/the_team.md +++ b/book/src/development/the_team.md @@ -33,7 +33,7 @@ this group to help with triaging, which can include: 1. **Labeling issues** - For the `good-first-issue` label, it can still be good to use `@rustbot` to + For the `good first issue` label, it can still be good to use `@rustbot` to subscribe to the issue and help interested parties, if they post questions in the comments. diff --git a/triagebot.toml b/triagebot.toml index eb2f9f9dd61f5..389f22c6a2ca3 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1,7 +1,7 @@ [relabel] allow-unauthenticated = [ "A-*", "C-*", "E-*", "I-*", "L-*", "P-*", "S-*", "T-*", - "good-first-issue", "beta-nominated" + "good first issue", "beta-nominated" ] # Allows shortcuts like `@rustbot ready` From 0ba2a3a818e744a6e22e72ec5caa8f1a89c0ac87 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 May 2025 16:50:11 +0200 Subject: [PATCH 2444/4206] enable clippy::as_conversions to fully rule out as-casts --- .../src/borrow_tracker/tree_borrows/unimap.rs | 20 ++++++++++--------- .../miri/src/concurrency/cpu_affinity.rs | 2 +- .../miri/src/concurrency/vector_clock.rs | 5 +++-- src/tools/miri/src/helpers.rs | 11 ++++++++++ src/tools/miri/src/intrinsics/simd.rs | 2 +- src/tools/miri/src/lib.rs | 11 ++-------- src/tools/miri/src/shims/foreign_items.rs | 6 +++--- src/tools/miri/src/shims/native_lib.rs | 17 +++++++--------- .../miri/src/shims/unix/android/thread.rs | 12 +++++++---- src/tools/miri/src/shims/unix/fs.rs | 4 ++-- .../src/shims/unix/linux/foreign_items.rs | 6 +++--- src/tools/miri/src/shims/windows/fs.rs | 2 +- src/tools/miri/src/shims/windows/handle.rs | 12 ++++------- src/tools/miri/src/shims/x86/gfni.rs | 4 ++-- src/tools/miri/src/shims/x86/mod.rs | 2 +- src/tools/miri/src/shims/x86/sse42.rs | 2 +- 16 files changed, 61 insertions(+), 57 deletions(-) diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs index 7874721c0ac37..dcd5a6cb02305 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs @@ -17,6 +17,8 @@ use std::mem; use rustc_data_structures::fx::FxHashMap; +use crate::helpers::ToUsize; + /// Intermediate key between a UniKeyMap and a UniValMap. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct UniIndex { @@ -158,7 +160,7 @@ where impl UniValMap { /// Whether this index has an associated value. pub fn contains_idx(&self, idx: UniIndex) -> bool { - self.data.get(idx.idx as usize).and_then(Option::as_ref).is_some() + self.data.get(idx.idx.to_usize()).and_then(Option::as_ref).is_some() } /// Reserve enough space to insert the value at the right index. @@ -174,29 +176,29 @@ impl UniValMap { /// Assign a value to the index. Permanently overwrites any previous value. pub fn insert(&mut self, idx: UniIndex, val: V) { - self.extend_to_length(idx.idx as usize + 1); - self.data[idx.idx as usize] = Some(val) + self.extend_to_length(idx.idx.to_usize() + 1); + self.data[idx.idx.to_usize()] = Some(val) } /// Get the value at this index, if it exists. pub fn get(&self, idx: UniIndex) -> Option<&V> { - self.data.get(idx.idx as usize).and_then(Option::as_ref) + self.data.get(idx.idx.to_usize()).and_then(Option::as_ref) } /// Get the value at this index mutably, if it exists. pub fn get_mut(&mut self, idx: UniIndex) -> Option<&mut V> { - self.data.get_mut(idx.idx as usize).and_then(Option::as_mut) + self.data.get_mut(idx.idx.to_usize()).and_then(Option::as_mut) } /// Delete any value associated with this index. /// Returns None if the value was not present, otherwise /// returns the previously stored value. pub fn remove(&mut self, idx: UniIndex) -> Option { - if idx.idx as usize >= self.data.len() { + if idx.idx.to_usize() >= self.data.len() { return None; } let mut res = None; - mem::swap(&mut res, &mut self.data[idx.idx as usize]); + mem::swap(&mut res, &mut self.data[idx.idx.to_usize()]); res } } @@ -209,8 +211,8 @@ pub struct UniEntry<'a, V> { impl<'a, V> UniValMap { /// Get a wrapper around a mutable access to the value corresponding to `idx`. pub fn entry(&'a mut self, idx: UniIndex) -> UniEntry<'a, V> { - self.extend_to_length(idx.idx as usize + 1); - UniEntry { inner: &mut self.data[idx.idx as usize] } + self.extend_to_length(idx.idx.to_usize() + 1); + UniEntry { inner: &mut self.data[idx.idx.to_usize()] } } } diff --git a/src/tools/miri/src/concurrency/cpu_affinity.rs b/src/tools/miri/src/concurrency/cpu_affinity.rs index b47b614cf5f0e..9583de5a4838c 100644 --- a/src/tools/miri/src/concurrency/cpu_affinity.rs +++ b/src/tools/miri/src/concurrency/cpu_affinity.rs @@ -25,7 +25,7 @@ impl CpuAffinityMask { let mut this = Self([0; Self::CPU_MASK_BYTES]); // the default affinity mask includes only the available CPUs - for i in 0..cpu_count as usize { + for i in 0..cpu_count.to_usize() { this.set(cx, i); } diff --git a/src/tools/miri/src/concurrency/vector_clock.rs b/src/tools/miri/src/concurrency/vector_clock.rs index 78858fcedaec7..494e7922d2b2b 100644 --- a/src/tools/miri/src/concurrency/vector_clock.rs +++ b/src/tools/miri/src/concurrency/vector_clock.rs @@ -7,6 +7,7 @@ use rustc_span::{DUMMY_SP, Span, SpanData}; use smallvec::SmallVec; use super::data_race::NaReadType; +use crate::helpers::ToUsize; /// A vector clock index, this is associated with a thread id /// but in some cases one vector index may be shared with @@ -157,7 +158,7 @@ impl VClock { #[inline] pub(super) fn index_mut(&mut self, index: VectorIdx) -> &mut VTimestamp { - self.0.as_mut_slice().get_mut(index.to_u32() as usize).unwrap() + self.0.as_mut_slice().get_mut(index.to_u32().to_usize()).unwrap() } /// Get a mutable slice to the internal vector with minimum `min_len` @@ -420,7 +421,7 @@ impl Index for VClock { #[inline] fn index(&self, index: VectorIdx) -> &VTimestamp { - self.as_slice().get(index.to_u32() as usize).unwrap_or(&VTimestamp::ZERO) + self.as_slice().get(index.to_u32().to_usize()).unwrap_or(&VTimestamp::ZERO) } } diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 8e7c9edfcc078..22c60a7e2bf4f 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -1412,3 +1412,14 @@ pub(crate) fn windows_check_buffer_size((success, len): (bool, u64)) -> u32 { u32::try_from(len).unwrap() } } + +/// We don't support 16-bit systems, so let's have ergonomic conversion from `u32` to `usize`. +pub trait ToUsize { + fn to_usize(self) -> usize; +} + +impl ToUsize for u32 { + fn to_usize(self) -> usize { + self.try_into().unwrap() + } +} diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs index c9250ba1b818d..b17fd4fb7f932 100644 --- a/src/tools/miri/src/intrinsics/simd.rs +++ b/src/tools/miri/src/intrinsics/simd.rs @@ -634,7 +634,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let index_len = index.len(); assert_eq!(left_len, right_len); - assert_eq!(index_len as u64, dest_len); + assert_eq!(u64::try_from(index_len).unwrap(), dest_len); for i in 0..dest_len { let src_index: u64 = diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 0b7a067058b99..1e63a6365aada 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -41,14 +41,7 @@ rustc::potential_query_instability, rustc::untranslatable_diagnostic, )] -#![warn( - rust_2018_idioms, - unqualified_local_imports, - clippy::cast_possible_wrap, // unsigned -> signed - clippy::cast_sign_loss, // signed -> unsigned - clippy::cast_lossless, - clippy::cast_possible_truncation, -)] +#![warn(rust_2018_idioms, unqualified_local_imports, clippy::as_conversions)] // Needed for rustdoc from bootstrap (with `-Znormalize-docs`). #![recursion_limit = "256"] @@ -140,7 +133,7 @@ pub use crate::eval::{ AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, MiriEntryFnType, RejectOpWith, ValidationMode, create_ecx, eval_entry, }; -pub use crate::helpers::{AccessKind, EvalContextExt as _}; +pub use crate::helpers::{AccessKind, EvalContextExt as _, ToUsize as _}; pub use crate::intrinsics::EvalContextExt as _; pub use crate::machine::{ AllocExtra, DynMachineCallback, FrameExtra, MachineCallback, MemoryKind, MiriInterpCx, diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 52c16a0c2e2dc..a81f459e5e1ae 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -639,7 +639,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let val = this.read_scalar(val)?.to_i32()?; let num = this.read_target_usize(num)?; // The docs say val is "interpreted as unsigned char". - #[expect(clippy::cast_sign_loss, clippy::cast_possible_truncation)] + #[expect(clippy::as_conversions)] let val = val as u8; // C requires that this must always be a valid pointer (C18 §7.1.4). @@ -665,7 +665,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let val = this.read_scalar(val)?.to_i32()?; let num = this.read_target_usize(num)?; // The docs say val is "interpreted as unsigned char". - #[expect(clippy::cast_sign_loss, clippy::cast_possible_truncation)] + #[expect(clippy::as_conversions)] let val = val as u8; // C requires that this must always be a valid pointer (C18 §7.1.4). @@ -676,7 +676,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { .iter() .position(|&c| c == val); if let Some(idx) = idx { - let new_ptr = ptr.wrapping_offset(Size::from_bytes(idx as u64), this); + let new_ptr = ptr.wrapping_offset(Size::from_bytes(idx), this); this.write_pointer(new_ptr, dest)?; } else { this.write_null(dest)?; diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs index 837e1b31cac50..1f44ed30b9ae7 100644 --- a/src/tools/miri/src/shims/native_lib.rs +++ b/src/tools/miri/src/shims/native_lib.rs @@ -94,14 +94,10 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Try getting the function from the shared library. // On windows `_lib_path` will be unused, hence the name starting with `_`. let (lib, _lib_path) = this.machine.native_lib.as_ref().unwrap(); - let func: libloading::Symbol<'_, unsafe extern "C" fn()> = unsafe { - match lib.get(link_name.as_str().as_bytes()) { - Ok(x) => x, - Err(_) => { - return None; - } - } - }; + let func: libloading::Symbol<'_, unsafe extern "C" fn()> = + unsafe { lib.get(link_name.as_str().as_bytes()).ok()? }; + #[expect(clippy::as_conversions)] // fn-ptr to raw-ptr cast needs `as`. + let fn_ptr = *func.deref() as *mut std::ffi::c_void; // FIXME: this is a hack! // The `libloading` crate will automatically load system libraries like `libc`. @@ -116,7 +112,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // using the `libc` crate where this interface is public. let mut info = std::mem::MaybeUninit::::uninit(); unsafe { - if libc::dladdr(*func.deref() as *const _, info.as_mut_ptr()) != 0 { + if libc::dladdr(fn_ptr, info.as_mut_ptr()) != 0 { let info = info.assume_init(); #[cfg(target_os = "cygwin")] let fname_ptr = info.dli_fname.as_ptr(); @@ -129,8 +125,9 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } } } + // Return a pointer to the function. - Some(CodePtr(*func.deref() as *mut _)) + Some(CodePtr(fn_ptr)) } } diff --git a/src/tools/miri/src/shims/unix/android/thread.rs b/src/tools/miri/src/shims/unix/android/thread.rs index 30ec0aefcbf1a..20fa91fb7b748 100644 --- a/src/tools/miri/src/shims/unix/android/thread.rs +++ b/src/tools/miri/src/shims/unix/android/thread.rs @@ -7,7 +7,7 @@ use crate::helpers::check_min_vararg_count; use crate::shims::unix::thread::{EvalContextExt as _, ThreadNameResult}; use crate::*; -const TASK_COMM_LEN: usize = 16; +const TASK_COMM_LEN: u32 = 16; pub fn prctl<'tcx>( ecx: &mut MiriInterpCx<'tcx>, @@ -29,8 +29,12 @@ pub fn prctl<'tcx>( let thread = ecx.pthread_self()?; // The Linux kernel silently truncates long names. // https://www.man7.org/linux/man-pages/man2/PR_SET_NAME.2const.html - let res = - ecx.pthread_setname_np(thread, name, TASK_COMM_LEN, /* truncate */ true)?; + let res = ecx.pthread_setname_np( + thread, + name, + TASK_COMM_LEN.to_usize(), + /* truncate */ true, + )?; assert_eq!(res, ThreadNameResult::Ok); Scalar::from_u32(0) } @@ -38,7 +42,7 @@ pub fn prctl<'tcx>( let [name] = check_min_vararg_count("prctl(PR_GET_NAME, ...)", varargs)?; let name = ecx.read_scalar(name)?; let thread = ecx.pthread_self()?; - let len = Scalar::from_target_usize(TASK_COMM_LEN as u64, ecx); + let len = Scalar::from_target_usize(TASK_COMM_LEN.into(), ecx); ecx.check_ptr_access( name.to_pointer(ecx)?, Size::from_bytes(TASK_COMM_LEN), diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 1f6acff0787a6..fa8f84e3867b1 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -121,13 +121,13 @@ impl UnixFileDescription for FileHandle { use std::os::windows::io::AsRawHandle; use windows_sys::Win32::Foundation::{ - ERROR_IO_PENDING, ERROR_LOCK_VIOLATION, FALSE, HANDLE, TRUE, + ERROR_IO_PENDING, ERROR_LOCK_VIOLATION, FALSE, TRUE, }; use windows_sys::Win32::Storage::FileSystem::{ LOCKFILE_EXCLUSIVE_LOCK, LOCKFILE_FAIL_IMMEDIATELY, LockFileEx, UnlockFile, }; - let fh = self.file.as_raw_handle() as HANDLE; + let fh = self.file.as_raw_handle(); use FlockOp::*; let (ret, lock_nb) = match op { diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index f5da7b0170b6a..da1e2fa91a10b 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -14,7 +14,7 @@ use crate::*; // The documentation of glibc complains that the kernel never exposes // TASK_COMM_LEN through the headers, so it's assumed to always be 16 bytes // long including a null terminator. -const TASK_COMM_LEN: usize = 16; +const TASK_COMM_LEN: u32 = 16; pub fn is_dyn_sym(name: &str) -> bool { matches!(name, "statx") @@ -80,7 +80,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let res = match this.pthread_setname_np( this.read_scalar(thread)?, this.read_scalar(name)?, - TASK_COMM_LEN, + TASK_COMM_LEN.to_usize(), /* truncate */ false, )? { ThreadNameResult::Ok => Scalar::from_u32(0), @@ -96,7 +96,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // In case of glibc, the length of the output buffer must // be not shorter than TASK_COMM_LEN. let len = this.read_scalar(len)?; - let res = if len.to_target_usize(this)? >= TASK_COMM_LEN as u64 { + let res = if len.to_target_usize(this)? >= TASK_COMM_LEN.into() { match this.pthread_getname_np( this.read_scalar(thread)?, this.read_scalar(name)?, diff --git a/src/tools/miri/src/shims/windows/fs.rs b/src/tools/miri/src/shims/windows/fs.rs index 7561bf45219ba..0ac82d55b1005 100644 --- a/src/tools/miri/src/shims/windows/fs.rs +++ b/src/tools/miri/src/shims/windows/fs.rs @@ -401,7 +401,7 @@ fn extract_windows_epoch<'tcx>( Some(time) => { let duration = ecx.system_time_since_windows_epoch(&time)?; let duration_ticks = ecx.windows_ticks_for(duration)?; - #[allow(clippy::cast_possible_truncation)] + #[expect(clippy::as_conversions)] interp_ok(Some((duration_ticks as u32, (duration_ticks >> 32) as u32))) } None => interp_ok(None), diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs index eec6c62bebc73..09dac9c1378bb 100644 --- a/src/tools/miri/src/shims/windows/handle.rs +++ b/src/tools/miri/src/shims/windows/handle.rs @@ -70,8 +70,7 @@ impl Handle { Self::Null => 0, Self::Pseudo(pseudo_handle) => pseudo_handle.value(), Self::Thread(thread) => thread.to_u32(), - #[expect(clippy::cast_sign_loss)] - Self::File(fd) => fd as u32, + Self::File(fd) => fd.cast_unsigned(), // INVALID_HANDLE_VALUE is -1. This fact is explicitly declared or implied in several // pages of Windows documentation. // 1: https://learn.microsoft.com/en-us/dotnet/api/microsoft.win32.safehandles.safefilehandle?view=net-9.0 @@ -124,11 +123,10 @@ impl Handle { Self::NULL_DISCRIMINANT if data == 0 => Some(Self::Null), Self::PSEUDO_DISCRIMINANT => Some(Self::Pseudo(PseudoHandle::from_value(data)?)), Self::THREAD_DISCRIMINANT => Some(Self::Thread(ThreadId::new_unchecked(data))), - #[expect(clippy::cast_possible_wrap)] Self::FILE_DISCRIMINANT => { // This cast preserves all bits. assert_eq!(size_of_val(&data), size_of::()); - Some(Self::File(data as FdNum)) + Some(Self::File(data.cast_signed())) } Self::INVALID_DISCRIMINANT => Some(Self::Invalid), _ => None, @@ -156,8 +154,7 @@ impl Handle { pub fn to_scalar(self, cx: &impl HasDataLayout) -> Scalar { // 64-bit handles are sign extended 32-bit handles // see https://docs.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication - #[expect(clippy::cast_possible_wrap)] // we want it to wrap - let signed_handle = self.to_packed() as i32; + let signed_handle = self.to_packed().cast_signed(); Scalar::from_target_isize(signed_handle.into(), cx) } @@ -171,9 +168,8 @@ impl Handle { ) -> InterpResult<'tcx, Result> { let sign_extended_handle = handle.to_target_isize(cx)?; - #[expect(clippy::cast_sign_loss)] // we want to lose the sign let handle = if let Ok(signed_handle) = i32::try_from(sign_extended_handle) { - signed_handle as u32 + signed_handle.cast_unsigned() } else { // if a handle doesn't fit in an i32, it isn't valid. return interp_ok(Err(HandleError::InvalidHandle)); diff --git a/src/tools/miri/src/shims/x86/gfni.rs b/src/tools/miri/src/shims/x86/gfni.rs index 4774ec9f9d8f5..a91c74283fd85 100644 --- a/src/tools/miri/src/shims/x86/gfni.rs +++ b/src/tools/miri/src/shims/x86/gfni.rs @@ -133,12 +133,12 @@ fn affine_transform<'tcx>( // This is a evaluated at compile time. Trait based conversion is not available. /// See for the /// definition of `gf_inv` which was used for the creation of this table. -#[expect(clippy::cast_possible_truncation)] static TABLE: [u8; 256] = { let mut array = [0; 256]; let mut i = 1; while i < 256 { + #[expect(clippy::as_conversions)] // no `try_from` in const... let mut x = i as u8; let mut y = gf2p8_mul(x, x); x = y; @@ -160,7 +160,7 @@ static TABLE: [u8; 256] = { /// polynomial representation with the reduction polynomial x^8 + x^4 + x^3 + x + 1. /// See for details. // This is a const function. Trait based conversion is not available. -#[expect(clippy::cast_possible_truncation)] +#[expect(clippy::as_conversions)] const fn gf2p8_mul(left: u8, right: u8) -> u8 { // This implementation is based on the `gf2p8mul_byte` definition found inside the Intel intrinsics guide. // See https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8mul diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index e57217dc6f299..ac59cc2dfeb39 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -1110,7 +1110,7 @@ fn pmulhrsw<'tcx>( // The result of this operation can overflow a signed 16-bit integer. // When `left` and `right` are -0x8000, the result is 0x8000. - #[expect(clippy::cast_possible_truncation)] + #[expect(clippy::as_conversions)] let res = res as i16; ecx.write_scalar(Scalar::from_i16(res), &dest)?; diff --git a/src/tools/miri/src/shims/x86/sse42.rs b/src/tools/miri/src/shims/x86/sse42.rs index 02336a722f7ed..66bff328626a1 100644 --- a/src/tools/miri/src/shims/x86/sse42.rs +++ b/src/tools/miri/src/shims/x86/sse42.rs @@ -440,7 +440,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let crc = if bit_size == 64 { // The 64-bit version will only consider the lower 32 bits, // while the upper 32 bits get discarded. - #[expect(clippy::cast_possible_truncation)] + #[expect(clippy::as_conversions)] u128::from((left.to_u64()? as u32).reverse_bits()) } else { u128::from(left.to_u32()?.reverse_bits()) From 446fa22412e16142658da8664f6fe3981e4aaf3c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 19 May 2025 09:00:05 +0200 Subject: [PATCH 2445/4206] add to_u64() helper method and use it where appropriate --- src/tools/miri/src/alloc_addresses/mod.rs | 2 +- src/tools/miri/src/alloc_addresses/reuse_pool.rs | 3 ++- src/tools/miri/src/alloc_bytes.rs | 6 ++++-- src/tools/miri/src/helpers.rs | 12 ++++++++++++ src/tools/miri/src/lib.rs | 2 +- src/tools/miri/src/shims/backtrace.rs | 8 ++++---- src/tools/miri/src/shims/unix/android/thread.rs | 12 ++++-------- .../miri/src/shims/unix/freebsd/foreign_items.rs | 2 +- src/tools/miri/src/shims/unix/linux/foreign_items.rs | 6 +++--- src/tools/miri/src/shims/unix/macos/foreign_items.rs | 2 +- src/tools/miri/src/shims/unix/thread.rs | 6 +++--- src/tools/miri/src/shims/x86/sha.rs | 2 +- 12 files changed, 37 insertions(+), 26 deletions(-) diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index dd389d97cdce0..21bd7fb54c6cd 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -168,7 +168,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { AllocKind::Dead => unreachable!(), }; // We don't have to expose this pointer yet, we do that in `prepare_for_native_call`. - return interp_ok(base_ptr.addr().try_into().unwrap()); + return interp_ok(base_ptr.addr().to_u64()); } // We are not in native lib mode, so we control the addresses ourselves. if let Some((reuse_addr, clock)) = global_state.reuse.take_addr( diff --git a/src/tools/miri/src/alloc_addresses/reuse_pool.rs b/src/tools/miri/src/alloc_addresses/reuse_pool.rs index 29d4f2bb7b0f3..ab6aaed5e3e1c 100644 --- a/src/tools/miri/src/alloc_addresses/reuse_pool.rs +++ b/src/tools/miri/src/alloc_addresses/reuse_pool.rs @@ -4,6 +4,7 @@ use rand::Rng; use rustc_abi::{Align, Size}; use crate::concurrency::VClock; +use crate::helpers::ToUsize as _; use crate::{MemoryKind, MiriConfig, ThreadId}; const MAX_POOL_SIZE: usize = 64; @@ -46,7 +47,7 @@ impl ReusePool { } fn subpool(&mut self, align: Align) -> &mut Vec<(u64, Size, ThreadId, VClock)> { - let pool_idx: usize = align.bytes().trailing_zeros().try_into().unwrap(); + let pool_idx: usize = align.bytes().trailing_zeros().to_usize(); if self.pool.len() <= pool_idx { self.pool.resize(pool_idx + 1, Vec::new()); } diff --git a/src/tools/miri/src/alloc_bytes.rs b/src/tools/miri/src/alloc_bytes.rs index 69ede279aa9b1..6788494c01cce 100644 --- a/src/tools/miri/src/alloc_bytes.rs +++ b/src/tools/miri/src/alloc_bytes.rs @@ -5,6 +5,8 @@ use std::{alloc, slice}; use rustc_abi::{Align, Size}; use rustc_middle::mir::interpret::AllocBytes; +use crate::helpers::ToU64 as _; + /// Allocation bytes that explicitly handle the layout of the data they're storing. /// This is necessary to interface with native code that accesses the program store in Miri. #[derive(Debug)] @@ -21,7 +23,7 @@ pub struct MiriAllocBytes { impl Clone for MiriAllocBytes { fn clone(&self) -> Self { let bytes: Cow<'_, [u8]> = Cow::Borrowed(self); - let align = Align::from_bytes(self.layout.align().try_into().unwrap()).unwrap(); + let align = Align::from_bytes(self.layout.align().to_u64()).unwrap(); MiriAllocBytes::from_bytes(bytes, align) } } @@ -90,7 +92,7 @@ impl AllocBytes for MiriAllocBytes { let align = align.bytes(); // SAFETY: `alloc_fn` will only be used with `size != 0`. let alloc_fn = |layout| unsafe { alloc::alloc(layout) }; - let alloc_bytes = MiriAllocBytes::alloc_with(size.try_into().unwrap(), align, alloc_fn) + let alloc_bytes = MiriAllocBytes::alloc_with(size.to_u64(), align, alloc_fn) .unwrap_or_else(|()| { panic!("Miri ran out of memory: cannot create allocation of {size} bytes") }); diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 22c60a7e2bf4f..ff2ec1b3e60a8 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -1423,3 +1423,15 @@ impl ToUsize for u32 { self.try_into().unwrap() } } + +/// Similarly, a maximum address size of `u64` is assumed widely here, so let's have ergonomic +/// converion from `usize` to `u64`. +pub trait ToU64 { + fn to_u64(self) -> u64; +} + +impl ToU64 for usize { + fn to_u64(self) -> u64 { + self.try_into().unwrap() + } +} diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 1e63a6365aada..9b3ec977c5d18 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -133,7 +133,7 @@ pub use crate::eval::{ AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, MiriEntryFnType, RejectOpWith, ValidationMode, create_ecx, eval_entry, }; -pub use crate::helpers::{AccessKind, EvalContextExt as _, ToUsize as _}; +pub use crate::helpers::{AccessKind, EvalContextExt as _, ToU64 as _, ToUsize as _}; pub use crate::intrinsics::EvalContextExt as _; pub use crate::machine::{ AllocExtra, DynMachineCallback, FrameExtra, MachineCallback, MemoryKind, MiriInterpCx, diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs index 7e667e70a1721..9f3bc06771f55 100644 --- a/src/tools/miri/src/shims/backtrace.rs +++ b/src/tools/miri/src/shims/backtrace.rs @@ -25,7 +25,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let frame_count = this.active_thread_stack().len(); - this.write_scalar(Scalar::from_target_usize(frame_count.try_into().unwrap(), this), dest) + this.write_scalar(Scalar::from_target_usize(frame_count.to_u64(), this), dest) } fn handle_miri_get_backtrace( @@ -70,7 +70,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } 1 => for (i, ptr) in ptrs.into_iter().enumerate() { - let offset = ptr_layout.size.checked_mul(i.try_into().unwrap(), this).unwrap(); + let offset = ptr_layout.size.checked_mul(i.to_u64(), this).unwrap(); let op_place = buf_place.offset(offset, ptr_layout, this)?; @@ -158,11 +158,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } 1 => { this.write_scalar( - Scalar::from_target_usize(name.len().try_into().unwrap(), this), + Scalar::from_target_usize(name.len().to_u64(), this), &this.project_field(dest, 0)?, )?; this.write_scalar( - Scalar::from_target_usize(filename.len().try_into().unwrap(), this), + Scalar::from_target_usize(filename.len().to_u64(), this), &this.project_field(dest, 1)?, )?; } diff --git a/src/tools/miri/src/shims/unix/android/thread.rs b/src/tools/miri/src/shims/unix/android/thread.rs index 20fa91fb7b748..aa3a05ead85b4 100644 --- a/src/tools/miri/src/shims/unix/android/thread.rs +++ b/src/tools/miri/src/shims/unix/android/thread.rs @@ -7,7 +7,7 @@ use crate::helpers::check_min_vararg_count; use crate::shims::unix::thread::{EvalContextExt as _, ThreadNameResult}; use crate::*; -const TASK_COMM_LEN: u32 = 16; +const TASK_COMM_LEN: u64 = 16; pub fn prctl<'tcx>( ecx: &mut MiriInterpCx<'tcx>, @@ -29,12 +29,8 @@ pub fn prctl<'tcx>( let thread = ecx.pthread_self()?; // The Linux kernel silently truncates long names. // https://www.man7.org/linux/man-pages/man2/PR_SET_NAME.2const.html - let res = ecx.pthread_setname_np( - thread, - name, - TASK_COMM_LEN.to_usize(), - /* truncate */ true, - )?; + let res = + ecx.pthread_setname_np(thread, name, TASK_COMM_LEN, /* truncate */ true)?; assert_eq!(res, ThreadNameResult::Ok); Scalar::from_u32(0) } @@ -42,7 +38,7 @@ pub fn prctl<'tcx>( let [name] = check_min_vararg_count("prctl(PR_GET_NAME, ...)", varargs)?; let name = ecx.read_scalar(name)?; let thread = ecx.pthread_self()?; - let len = Scalar::from_target_usize(TASK_COMM_LEN.into(), ecx); + let len = Scalar::from_target_usize(TASK_COMM_LEN, ecx); ecx.check_ptr_access( name.to_pointer(ecx)?, Size::from_bytes(TASK_COMM_LEN), diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index 21a386b29272a..c0872daee8d64 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -24,7 +24,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Threading "pthread_setname_np" => { let [thread, name] = this.check_shim(abi, Conv::C, link_name, args)?; - let max_len = usize::MAX; // FreeBSD does not seem to have a limit. + let max_len = u64::MAX; // FreeBSD does not seem to have a limit. let res = match this.pthread_setname_np( this.read_scalar(thread)?, this.read_scalar(name)?, diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index da1e2fa91a10b..51c2434d68ac8 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -14,7 +14,7 @@ use crate::*; // The documentation of glibc complains that the kernel never exposes // TASK_COMM_LEN through the headers, so it's assumed to always be 16 bytes // long including a null terminator. -const TASK_COMM_LEN: u32 = 16; +const TASK_COMM_LEN: u64 = 16; pub fn is_dyn_sym(name: &str) -> bool { matches!(name, "statx") @@ -80,7 +80,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let res = match this.pthread_setname_np( this.read_scalar(thread)?, this.read_scalar(name)?, - TASK_COMM_LEN.to_usize(), + TASK_COMM_LEN, /* truncate */ false, )? { ThreadNameResult::Ok => Scalar::from_u32(0), @@ -96,7 +96,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // In case of glibc, the length of the output buffer must // be not shorter than TASK_COMM_LEN. let len = this.read_scalar(len)?; - let res = if len.to_target_usize(this)? >= TASK_COMM_LEN.into() { + let res = if len.to_target_usize(this)? >= TASK_COMM_LEN { match this.pthread_getname_np( this.read_scalar(thread)?, this.read_scalar(name)?, diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index 5046e96508227..0281bb9f71dfc 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -186,7 +186,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let res = match this.pthread_setname_np( thread, this.read_scalar(name)?, - this.eval_libc("MAXTHREADNAMESIZE").to_target_usize(this)?.try_into().unwrap(), + this.eval_libc("MAXTHREADNAMESIZE").to_target_usize(this)?, /* truncate */ false, )? { ThreadNameResult::Ok => Scalar::from_u32(0), diff --git a/src/tools/miri/src/shims/unix/thread.rs b/src/tools/miri/src/shims/unix/thread.rs index 3d990a1a04201..4b6615b3ea82c 100644 --- a/src/tools/miri/src/shims/unix/thread.rs +++ b/src/tools/miri/src/shims/unix/thread.rs @@ -86,7 +86,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, thread: Scalar, name: Scalar, - name_max_len: usize, + name_max_len: u64, truncate: bool, ) -> InterpResult<'tcx, ThreadNameResult> { let this = self.eval_context_mut(); @@ -99,9 +99,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let mut name = this.read_c_str(name)?.to_owned(); // Comparing with `>=` to account for null terminator. - if name.len() >= name_max_len { + if name.len().to_u64() >= name_max_len { if truncate { - name.truncate(name_max_len.saturating_sub(1)); + name.truncate(name_max_len.saturating_sub(1).try_into().unwrap()); } else { return interp_ok(ThreadNameResult::NameTooLong); } diff --git a/src/tools/miri/src/shims/x86/sha.rs b/src/tools/miri/src/shims/x86/sha.rs index 6d2c151243ca1..23c83553f3b32 100644 --- a/src/tools/miri/src/shims/x86/sha.rs +++ b/src/tools/miri/src/shims/x86/sha.rs @@ -43,7 +43,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // We reverse the order because x86 is little endian but the copied implementation uses // big endian. for (i, part) in val.into_iter().rev().enumerate() { - let projected = &ecx.project_index(dest, i.try_into().unwrap())?; + let projected = &ecx.project_index(dest, i.to_u64())?; ecx.write_scalar(Scalar::from_u32(part), projected)?; } interp_ok(()) From 85f9dce889f4b71ee0dfa7f26ac006323fd6d9af Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 19 May 2025 11:11:55 +0200 Subject: [PATCH 2446/4206] in aarch64 asm parse error tests, only test cases specific to that target this is more in line with the x86 parse error tests. The cross-platform tests were more complete anyway --- tests/ui/asm/aarch64/parse-error.rs | 107 +------ tests/ui/asm/aarch64/parse-error.stderr | 370 +----------------------- 2 files changed, 7 insertions(+), 470 deletions(-) diff --git a/tests/ui/asm/aarch64/parse-error.rs b/tests/ui/asm/aarch64/parse-error.rs index 35e1d037f3888..622f99aa1b1e8 100644 --- a/tests/ui/asm/aarch64/parse-error.rs +++ b/tests/ui/asm/aarch64/parse-error.rs @@ -1,57 +1,11 @@ //@ only-aarch64 -use std::arch::{asm, global_asm}; +use std::arch::asm; fn main() { let mut foo = 0; let mut bar = 0; unsafe { - asm!(); - //~^ ERROR requires at least a template string argument - asm!(foo); - //~^ ERROR asm template must be a string literal - asm!("{}" foo); - //~^ ERROR expected token: `,` - asm!("{}", foo); - //~^ ERROR expected operand, clobber_abi, options, or additional template string - asm!("{}", in foo); - //~^ ERROR expected `(`, found `foo` - asm!("{}", in(reg foo)); - //~^ ERROR expected `)`, found `foo` - asm!("{}", in(reg)); - //~^ ERROR expected expression, found end of macro arguments - asm!("{}", inout(=) foo => bar); - //~^ ERROR expected register class or explicit register - asm!("{}", inout(reg) foo =>); - //~^ ERROR expected expression, found end of macro arguments - asm!("{}", in(reg) foo => bar); - //~^ ERROR expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>` - asm!("{}", sym foo + bar); - //~^ ERROR expected a path for argument to `sym` - asm!("", options(foo)); - //~^ ERROR expected one of - asm!("", options(nomem foo)); - //~^ ERROR expected one of - asm!("", options(nomem, foo)); - //~^ ERROR expected one of - asm!("{}", options(), const foo); - //~^ ERROR attempt to use a non-constant value in a constant - asm!("", clobber_abi(foo)); - //~^ ERROR expected string literal - asm!("", clobber_abi("C" foo)); - //~^ ERROR expected one of `)` or `,`, found `foo` - asm!("", clobber_abi("C", foo)); - //~^ ERROR expected string literal - asm!("{}", clobber_abi("C"), const foo); - //~^ ERROR attempt to use a non-constant value in a constant - asm!("", options(), clobber_abi("C")); - asm!("{}", options(), clobber_abi("C"), const foo); - //~^ ERROR attempt to use a non-constant value in a constant - asm!("{a}", a = const foo, a = const bar); - //~^ ERROR duplicate argument named `a` - //~^^ ERROR argument never used - //~^^^ ERROR attempt to use a non-constant value in a constant - //~^^^^ ERROR attempt to use a non-constant value in a constant asm!("", a = in("x0") foo); //~^ ERROR explicit register arguments cannot have names asm!("{a}", in("x0") foo, a = const bar); @@ -61,64 +15,5 @@ fn main() { asm!("{1}", in("x0") foo, const bar); //~^ ERROR positional arguments cannot follow named arguments or explicit register arguments //~^^ ERROR attempt to use a non-constant value in a constant - asm!("", options(), ""); - //~^ ERROR expected one of - asm!("{}", in(reg) foo, "{}", out(reg) foo); - //~^ ERROR expected one of - asm!(format!("{{{}}}", 0), in(reg) foo); - //~^ ERROR asm template must be a string literal - asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); - //~^ ERROR asm template must be a string literal - asm!("{}", in(reg) _); - //~^ ERROR _ cannot be used for input operands - asm!("{}", inout(reg) _); - //~^ ERROR _ cannot be used for input operands - asm!("{}", inlateout(reg) _); - //~^ ERROR _ cannot be used for input operands } } - -const FOO: i32 = 1; -const BAR: i32 = 2; -global_asm!(); -//~^ ERROR requires at least a template string argument -global_asm!(FOO); -//~^ ERROR asm template must be a string literal -global_asm!("{}" FOO); -//~^ ERROR expected token: `,` -global_asm!("{}", FOO); -//~^ ERROR expected operand, options, or additional template string -global_asm!("{}", const); -//~^ ERROR expected expression, found end of macro arguments -global_asm!("{}", const(reg) FOO); -//~^ ERROR expected one of -global_asm!("", options(FOO)); -//~^ ERROR expected one of -global_asm!("", options(nomem FOO)); -//~^ ERROR expected one of -global_asm!("", options(nomem, FOO)); -//~^ ERROR expected one of -global_asm!("{}", options(), const FOO); -global_asm!("", clobber_abi(FOO)); -//~^ ERROR expected string literal -global_asm!("", clobber_abi("C" FOO)); -//~^ ERROR expected one of `)` or `,`, found `FOO` -global_asm!("", clobber_abi("C", FOO)); -//~^ ERROR expected string literal -global_asm!("{}", clobber_abi("C"), const FOO); -//~^ ERROR `clobber_abi` cannot be used with `global_asm!` -global_asm!("", options(), clobber_abi("C")); -//~^ ERROR `clobber_abi` cannot be used with `global_asm!` -global_asm!("{}", options(), clobber_abi("C"), const FOO); -//~^ ERROR `clobber_abi` cannot be used with `global_asm!` -global_asm!("{a}", a = const FOO, a = const BAR); -//~^ ERROR duplicate argument named `a` -//~^^ ERROR argument never used -global_asm!("", options(), ""); -//~^ ERROR expected one of -global_asm!("{}", const FOO, "{}", const FOO); -//~^ ERROR expected one of -global_asm!(format!("{{{}}}", 0), const FOO); -//~^ ERROR asm template must be a string literal -global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); -//~^ ERROR asm template must be a string literal diff --git a/tests/ui/asm/aarch64/parse-error.stderr b/tests/ui/asm/aarch64/parse-error.stderr index 45f9e7989c2e8..ca21311f87f96 100644 --- a/tests/ui/asm/aarch64/parse-error.stderr +++ b/tests/ui/asm/aarch64/parse-error.stderr @@ -1,377 +1,19 @@ -error: requires at least a template string argument - --> $DIR/parse-error.rs:9:9 - | -LL | asm!(); - | ^^^^^^ - -error: asm template must be a string literal - --> $DIR/parse-error.rs:11:14 - | -LL | asm!(foo); - | ^^^ - -error: expected token: `,` - --> $DIR/parse-error.rs:13:19 - | -LL | asm!("{}" foo); - | ^^^ expected `,` - -error: expected operand, clobber_abi, options, or additional template string - --> $DIR/parse-error.rs:15:20 - | -LL | asm!("{}", foo); - | ^^^ expected operand, clobber_abi, options, or additional template string - -error: expected `(`, found `foo` - --> $DIR/parse-error.rs:17:23 - | -LL | asm!("{}", in foo); - | ^^^ expected `(` - -error: expected `)`, found `foo` - --> $DIR/parse-error.rs:19:27 - | -LL | asm!("{}", in(reg foo)); - | ^^^ expected `)` - -error: expected expression, found end of macro arguments - --> $DIR/parse-error.rs:21:27 - | -LL | asm!("{}", in(reg)); - | ^ expected expression - -error: expected register class or explicit register - --> $DIR/parse-error.rs:23:26 - | -LL | asm!("{}", inout(=) foo => bar); - | ^ - -error: expected expression, found end of macro arguments - --> $DIR/parse-error.rs:25:37 - | -LL | asm!("{}", inout(reg) foo =>); - | ^ expected expression - -error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>` - --> $DIR/parse-error.rs:27:32 - | -LL | asm!("{}", in(reg) foo => bar); - | ^^ expected one of 7 possible tokens - -error: expected a path for argument to `sym` - --> $DIR/parse-error.rs:29:24 - | -LL | asm!("{}", sym foo + bar); - | ^^^^^^^^^ - -error: expected one of `)`, `att_syntax`, `may_unwind`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo` - --> $DIR/parse-error.rs:31:26 - | -LL | asm!("", options(foo)); - | ^^^ expected one of 10 possible tokens - -error: expected one of `)` or `,`, found `foo` - --> $DIR/parse-error.rs:33:32 - | -LL | asm!("", options(nomem foo)); - | ^^^ expected one of `)` or `,` - -error: expected one of `)`, `att_syntax`, `may_unwind`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo` - --> $DIR/parse-error.rs:35:33 - | -LL | asm!("", options(nomem, foo)); - | ^^^ expected one of 10 possible tokens - -error: expected string literal - --> $DIR/parse-error.rs:39:30 - | -LL | asm!("", clobber_abi(foo)); - | ^^^ not a string literal - -error: expected one of `)` or `,`, found `foo` - --> $DIR/parse-error.rs:41:34 - | -LL | asm!("", clobber_abi("C" foo)); - | ^^^ expected one of `)` or `,` - -error: expected string literal - --> $DIR/parse-error.rs:43:35 - | -LL | asm!("", clobber_abi("C", foo)); - | ^^^ not a string literal - -error: duplicate argument named `a` - --> $DIR/parse-error.rs:50:36 - | -LL | asm!("{a}", a = const foo, a = const bar); - | ------------- ^^^^^^^^^^^^^ duplicate argument - | | - | previously here - -error: argument never used - --> $DIR/parse-error.rs:50:36 - | -LL | asm!("{a}", a = const foo, a = const bar); - | ^^^^^^^^^^^^^ argument never used - | - = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` - error: explicit register arguments cannot have names - --> $DIR/parse-error.rs:55:18 + --> $DIR/parse-error.rs:9:18 | LL | asm!("", a = in("x0") foo); | ^^^^^^^^^^^^^^^^ error: positional arguments cannot follow named arguments or explicit register arguments - --> $DIR/parse-error.rs:61:35 + --> $DIR/parse-error.rs:15:35 | LL | asm!("{1}", in("x0") foo, const bar); | ------------ ^^^^^^^^^ positional argument | | | explicit register argument -error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `label`, `lateout`, `options`, `out`, or `sym`, found `""` - --> $DIR/parse-error.rs:64:29 - | -LL | asm!("", options(), ""); - | ^^ expected one of 10 possible tokens - -error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `label`, `lateout`, `options`, `out`, or `sym`, found `"{}"` - --> $DIR/parse-error.rs:66:33 - | -LL | asm!("{}", in(reg) foo, "{}", out(reg) foo); - | ^^^^ expected one of 10 possible tokens - -error: asm template must be a string literal - --> $DIR/parse-error.rs:68:14 - | -LL | asm!(format!("{{{}}}", 0), in(reg) foo); - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: asm template must be a string literal - --> $DIR/parse-error.rs:70:21 - | -LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: _ cannot be used for input operands - --> $DIR/parse-error.rs:72:28 - | -LL | asm!("{}", in(reg) _); - | ^ - -error: _ cannot be used for input operands - --> $DIR/parse-error.rs:74:31 - | -LL | asm!("{}", inout(reg) _); - | ^ - -error: _ cannot be used for input operands - --> $DIR/parse-error.rs:76:35 - | -LL | asm!("{}", inlateout(reg) _); - | ^ - -error: requires at least a template string argument - --> $DIR/parse-error.rs:83:1 - | -LL | global_asm!(); - | ^^^^^^^^^^^^^ - -error: asm template must be a string literal - --> $DIR/parse-error.rs:85:13 - | -LL | global_asm!(FOO); - | ^^^ - -error: expected token: `,` - --> $DIR/parse-error.rs:87:18 - | -LL | global_asm!("{}" FOO); - | ^^^ expected `,` - -error: expected operand, options, or additional template string - --> $DIR/parse-error.rs:89:19 - | -LL | global_asm!("{}", FOO); - | ^^^ expected operand, options, or additional template string - -error: expected expression, found end of macro arguments - --> $DIR/parse-error.rs:91:24 - | -LL | global_asm!("{}", const); - | ^ expected expression - -error: expected one of `,`, `.`, `?`, or an operator, found `FOO` - --> $DIR/parse-error.rs:93:30 - | -LL | global_asm!("{}", const(reg) FOO); - | ^^^ expected one of `,`, `.`, `?`, or an operator - -error: expected one of `)`, `att_syntax`, or `raw`, found `FOO` - --> $DIR/parse-error.rs:95:25 - | -LL | global_asm!("", options(FOO)); - | ^^^ expected one of `)`, `att_syntax`, or `raw` - -error: expected one of `)` or `,`, found `FOO` - --> $DIR/parse-error.rs:97:31 - | -LL | global_asm!("", options(nomem FOO)); - | ^^^ expected one of `)` or `,` - -error: expected one of `)`, `att_syntax`, or `raw`, found `FOO` - --> $DIR/parse-error.rs:99:32 - | -LL | global_asm!("", options(nomem, FOO)); - | ^^^ expected one of `)`, `att_syntax`, or `raw` - -error: expected string literal - --> $DIR/parse-error.rs:102:29 - | -LL | global_asm!("", clobber_abi(FOO)); - | ^^^ not a string literal - -error: expected one of `)` or `,`, found `FOO` - --> $DIR/parse-error.rs:104:33 - | -LL | global_asm!("", clobber_abi("C" FOO)); - | ^^^ expected one of `)` or `,` - -error: expected string literal - --> $DIR/parse-error.rs:106:34 - | -LL | global_asm!("", clobber_abi("C", FOO)); - | ^^^ not a string literal - -error: `clobber_abi` cannot be used with `global_asm!` - --> $DIR/parse-error.rs:108:19 - | -LL | global_asm!("{}", clobber_abi("C"), const FOO); - | ^^^^^^^^^^^^^^^^ - -error: `clobber_abi` cannot be used with `global_asm!` - --> $DIR/parse-error.rs:110:28 - | -LL | global_asm!("", options(), clobber_abi("C")); - | ^^^^^^^^^^^^^^^^ - -error: `clobber_abi` cannot be used with `global_asm!` - --> $DIR/parse-error.rs:112:30 - | -LL | global_asm!("{}", options(), clobber_abi("C"), const FOO); - | ^^^^^^^^^^^^^^^^ - -error: duplicate argument named `a` - --> $DIR/parse-error.rs:114:35 - | -LL | global_asm!("{a}", a = const FOO, a = const BAR); - | ------------- ^^^^^^^^^^^^^ duplicate argument - | | - | previously here - -error: argument never used - --> $DIR/parse-error.rs:114:35 - | -LL | global_asm!("{a}", a = const FOO, a = const BAR); - | ^^^^^^^^^^^^^ argument never used - | - = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` - -error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `""` - --> $DIR/parse-error.rs:117:28 - | -LL | global_asm!("", options(), ""); - | ^^ expected one of `clobber_abi`, `const`, `options`, or `sym` - -error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `"{}"` - --> $DIR/parse-error.rs:119:30 - | -LL | global_asm!("{}", const FOO, "{}", const FOO); - | ^^^^ expected one of `clobber_abi`, `const`, `options`, or `sym` - -error: asm template must be a string literal - --> $DIR/parse-error.rs:121:13 - | -LL | global_asm!(format!("{{{}}}", 0), const FOO); - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: asm template must be a string literal - --> $DIR/parse-error.rs:123:20 - | -LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:37:37 - | -LL | asm!("{}", options(), const foo); - | ^^^ non-constant value - | -help: consider using `const` instead of `let` - | -LL - let mut foo = 0; -LL + const foo: /* Type */ = 0; - | - -error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:45:44 - | -LL | asm!("{}", clobber_abi("C"), const foo); - | ^^^ non-constant value - | -help: consider using `const` instead of `let` - | -LL - let mut foo = 0; -LL + const foo: /* Type */ = 0; - | - -error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:48:55 - | -LL | asm!("{}", options(), clobber_abi("C"), const foo); - | ^^^ non-constant value - | -help: consider using `const` instead of `let` - | -LL - let mut foo = 0; -LL + const foo: /* Type */ = 0; - | - -error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:50:31 - | -LL | asm!("{a}", a = const foo, a = const bar); - | ^^^ non-constant value - | -help: consider using `const` instead of `let` - | -LL - let mut foo = 0; -LL + const foo: /* Type */ = 0; - | - -error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:50:46 - | -LL | asm!("{a}", a = const foo, a = const bar); - | ^^^ non-constant value - | -help: consider using `const` instead of `let` - | -LL - let mut bar = 0; -LL + const bar: /* Type */ = 0; - | - error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:57:45 + --> $DIR/parse-error.rs:11:45 | LL | asm!("{a}", in("x0") foo, a = const bar); | ^^^ non-constant value @@ -383,7 +25,7 @@ LL + const bar: /* Type */ = 0; | error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:59:45 + --> $DIR/parse-error.rs:13:45 | LL | asm!("{a}", in("x0") foo, a = const bar); | ^^^ non-constant value @@ -395,7 +37,7 @@ LL + const bar: /* Type */ = 0; | error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:61:41 + --> $DIR/parse-error.rs:15:41 | LL | asm!("{1}", in("x0") foo, const bar); | ^^^ non-constant value @@ -406,6 +48,6 @@ LL - let mut bar = 0; LL + const bar: /* Type */ = 0; | -error: aborting due to 57 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0435`. From 9f82458c2584f6e30dcf715e00dd476f73705ec9 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 19 May 2025 13:08:23 +0200 Subject: [PATCH 2447/4206] Remote dangling file --- .../crates/proc-macro-srv/src/server_impl.rs | 3 +- .../proc-macro-srv/src/server_impl/symbol.rs | 47 ------------------- 2 files changed, 1 insertion(+), 49 deletions(-) delete mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/symbol.rs diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs index 3d999421794bb..11dbd92009152 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs @@ -16,9 +16,8 @@ mod token_stream; pub use token_stream::TokenStream; pub mod rust_analyzer_span; -// mod symbol; pub mod token_id; -// pub use symbol::*; + use tt::Spacing; #[derive(Clone)] diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/symbol.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/symbol.rs deleted file mode 100644 index 6863ce959973e..0000000000000 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/symbol.rs +++ /dev/null @@ -1,47 +0,0 @@ -//! Symbol interner for proc-macro-srv - -use std::{cell::RefCell, collections::HashMap, thread::LocalKey}; - -thread_local! { - pub(crate) static SYMBOL_INTERNER: RefCell = Default::default(); -} - -// ID for an interned symbol. -#[derive(Hash, Eq, PartialEq, Copy, Clone)] -pub struct Symbol(u32); - -pub(crate) type SymbolInternerRef = &'static LocalKey>; - -impl Symbol { - pub(super) fn intern(interner: SymbolInternerRef, data: &str) -> Symbol { - interner.with(|i| i.borrow_mut().intern(data)) - } - - pub(super) fn text(&self, interner: SymbolInternerRef) -> SmolStr { - interner.with(|i| i.borrow().get(self).clone()) - } -} - -#[derive(Default)] -pub(crate) struct SymbolInterner { - idents: HashMap, - ident_data: Vec, -} - -impl SymbolInterner { - fn intern(&mut self, data: &str) -> Symbol { - if let Some(index) = self.idents.get(data) { - return Symbol(*index); - } - - let index = self.idents.len() as u32; - let data = SmolStr::from(data); - self.ident_data.push(data.clone()); - self.idents.insert(data, index); - Symbol(index) - } - - fn get(&self, sym: &Symbol) -> &SmolStr { - &self.ident_data[sym.0 as usize] - } -} From 686f0fa8a2bf4e0971b97b18c0308caa28b247ee Mon Sep 17 00:00:00 2001 From: Stan Manilov Date: Mon, 19 May 2025 14:41:19 +0300 Subject: [PATCH 2448/4206] Remove unused references and simplify one --- src/doc/rustc-dev-guide/src/rustc-driver/intro.md | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/rustc-driver/intro.md b/src/doc/rustc-dev-guide/src/rustc-driver/intro.md index 40500e6bc7a5f..a3684397b2995 100644 --- a/src/doc/rustc-dev-guide/src/rustc-driver/intro.md +++ b/src/doc/rustc-dev-guide/src/rustc-driver/intro.md @@ -7,8 +7,8 @@ It acts as the glue for running the various phases of the compiler in the correc using the interface defined in the [`rustc_interface`] crate. Where possible, using [`rustc_driver`] rather than [`rustc_interface`] is recommended. The main entry point of [`rustc_driver`] is [`rustc_driver::run_compiler`][rd_rc]. -This builder accepts the same command-line args as rustc as well as an implementation of [`Callbacks`][cb] and a couple of other optional options. -[`Callbacks`][cb] is a `trait` that allows for custom compiler configuration, +This builder accepts the same command-line args as rustc as well as an implementation of [`Callbacks`] and a couple of other optional options. +[`Callbacks`] is a `trait` that allows for custom compiler configuration, as well as allowing custom code to run after different phases of the compilation. ## `rustc_interface` @@ -33,14 +33,8 @@ specifically [`rustc_driver_impl::run_compiler`][rdi_rc] [`Compiler`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/interface/struct.Compiler.html [`rustc_driver`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/ [`rustc_interface`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/index.html -[`Session`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/struct.Session.html -[`SourceMap`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/source_map/struct.SourceMap.html -[`TyCtxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html -[Appendix A]: appendix/stupid-stats.html -[cb]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/trait.Callbacks.html +[`Callbacks`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/trait.Callbacks.html [example]: https://github.com/rust-lang/rustc-dev-guide/blob/master/examples/rustc-interface-example.rs [i_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/interface/fn.run_compiler.html [rd_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/fn.run_compiler.html [rdi_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver_impl/fn.run_compiler.html -[stupid-stats]: https://github.com/nrc/stupid-stats -[`nightly-rustc`]: https://doc.rust-lang.org/nightly/nightly-rustc/ From 114367587c3b0910682d7c56e70e20ca13e4789b Mon Sep 17 00:00:00 2001 From: Stan Manilov Date: Mon, 19 May 2025 14:44:36 +0300 Subject: [PATCH 2449/4206] Make run instructions first Better, because then one knows how to run the examples. --- src/doc/rustc-dev-guide/src/SUMMARY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 31119496e754a..a7b76233d1978 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -134,9 +134,9 @@ - [Command-line arguments](./cli.md) - [rustc_driver and rustc_interface](./rustc-driver/intro.md) + - [Remarks on perma-unstable features](./rustc-driver/remarks-on-perma-unstable-features.md) - [Example: Type checking](./rustc-driver/interacting-with-the-ast.md) - [Example: Getting diagnostics](./rustc-driver/getting-diagnostics.md) - - [Remarks on perma-unstable features](./rustc-driver/remarks-on-perma-unstable-features.md) - [Errors and lints](diagnostics.md) - [Diagnostic and subdiagnostic structs](./diagnostics/diagnostic-structs.md) - [Translation](./diagnostics/translation.md) From 31b4808432efc02ead21199f498ee9e68ac6724e Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 19 May 2025 15:34:00 +0300 Subject: [PATCH 2450/4206] Fix cache problems with lints level By removing the cache. --- .../src/handlers/missing_unsafe.rs | 43 +++++ .../crates/ide-diagnostics/src/lib.rs | 181 ++---------------- 2 files changed, 60 insertions(+), 164 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs index 364bead34efae..6bd5417b25d75 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs @@ -915,4 +915,47 @@ fn foo() { "#, ); } + + #[test] + fn regression_19823() { + check_diagnostics( + r#" +pub trait FooTrait { + unsafe fn method1(); + unsafe fn method2(); +} + +unsafe fn some_unsafe_fn() {} + +macro_rules! impl_foo { + () => { + unsafe fn method1() { + some_unsafe_fn(); + } + unsafe fn method2() { + some_unsafe_fn(); + } + }; +} + +pub struct S1; +#[allow(unsafe_op_in_unsafe_fn)] +impl FooTrait for S1 { + unsafe fn method1() { + some_unsafe_fn(); + } + + unsafe fn method2() { + some_unsafe_fn(); + } +} + +pub struct S2; +#[allow(unsafe_op_in_unsafe_fn)] +impl FooTrait for S2 { + impl_foo!(); +} + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs index 2af14ca949bf2..72bd66d1c8bb7 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs @@ -83,12 +83,11 @@ mod handlers { #[cfg(test)] mod tests; -use std::{collections::hash_map, iter, sync::LazyLock}; +use std::{iter, sync::LazyLock}; use either::Either; use hir::{ - Crate, DisplayTarget, HirFileId, InFile, Semantics, db::ExpandDatabase, - diagnostics::AnyDiagnostic, + Crate, DisplayTarget, InFile, Semantics, db::ExpandDatabase, diagnostics::AnyDiagnostic, }; use ide_db::{ EditionedFileId, FileId, FileRange, FxHashMap, FxHashSet, RootDatabase, Severity, SnippetCap, @@ -513,13 +512,7 @@ pub fn semantic_diagnostics( // The edition isn't accurate (each diagnostics may have its own edition due to macros), // but it's okay as it's only being used for error recovery. - handle_lints( - &ctx.sema, - &mut FxHashMap::default(), - &mut lints, - &mut Vec::new(), - editioned_file_id.edition(db), - ); + handle_lints(&ctx.sema, &mut lints, editioned_file_id.edition(db)); res.retain(|d| d.severity != Severity::Allow); @@ -584,8 +577,6 @@ fn handle_diag_from_macros( true } -// `__RA_EVERY_LINT` is a fake lint group to allow every lint in proc macros - struct BuiltLint { lint: &'static Lint, groups: Vec<&'static str>, @@ -629,9 +620,7 @@ fn build_lints_map( fn handle_lints( sema: &Semantics<'_, RootDatabase>, - cache: &mut FxHashMap>, diagnostics: &mut [(InFile, &mut Diagnostic)], - cache_stack: &mut Vec, edition: Edition, ) { for (node, diag) in diagnostics { @@ -645,7 +634,8 @@ fn handle_lints( diag.severity = default_severity; } - let mut diag_severity = fill_lint_attrs(sema, node, cache, cache_stack, diag, edition); + let mut diag_severity = + lint_severity_at(sema, node, &lint_groups(&diag.code, edition), edition); if let outline_diag_severity @ Some(_) = find_outline_mod_lint_severity(sema, node, diag, edition) @@ -698,155 +688,22 @@ fn find_outline_mod_lint_severity( result } -#[derive(Debug, Clone, Copy)] -struct SeverityAttr { - severity: Severity, - /// This field counts how far we are from the main node. Bigger values mean more far. - /// - /// Note this isn't accurate: there can be gaps between values (created when merging severity maps). - /// The important thing is that if an attr is closer to the main node, it will have smaller value. - /// - /// This is necessary even though we take care to never overwrite a value from deeper nesting - /// because of lint groups. For example, in the following code: - /// ``` - /// #[warn(non_snake_case)] - /// mod foo { - /// #[allow(nonstandard_style)] - /// mod bar {} - /// } - /// ``` - /// We want to not warn on non snake case inside `bar`. If we are traversing this for the first - /// time, everything will be fine, because we will set `diag_severity` on the first matching group - /// and never overwrite it since then. But if `bar` is cached, the cache will contain both - /// `#[warn(non_snake_case)]` and `#[allow(nonstandard_style)]`, and without this field, we have - /// no way of differentiating between the two. - depth: u32, -} - -fn fill_lint_attrs( +fn lint_severity_at( sema: &Semantics<'_, RootDatabase>, node: &InFile, - cache: &mut FxHashMap>, - cache_stack: &mut Vec, - diag: &Diagnostic, + lint_groups: &LintGroups, edition: Edition, ) -> Option { - let mut collected_lint_attrs = FxHashMap::::default(); - let mut diag_severity = None; - - let mut ancestors = node.value.ancestors().peekable(); - let mut depth = 0; - loop { - let ancestor = ancestors.next().expect("we always return from top-level nodes"); - depth += 1; - - if ancestors.peek().is_none() { - // We don't want to insert too many nodes into cache, but top level nodes (aka. outline modules - // or macro expansions) need to touch the database so they seem like a good fit to cache. - - if let Some(cached) = cache.get_mut(&node.file_id) { - // This node (and everything above it) is already cached; the attribute is either here or nowhere. - - // Workaround for the borrow checker. - let cached = std::mem::take(cached); - - cached.iter().for_each(|(lint, severity)| { - for item in &*cache_stack { - let node_cache_entry = cache - .get_mut(item) - .expect("we always insert cached nodes into the cache map"); - let lint_cache_entry = node_cache_entry.entry(lint.clone()); - if let hash_map::Entry::Vacant(lint_cache_entry) = lint_cache_entry { - // Do not overwrite existing lint attributes, as we go bottom to top and bottom attrs - // overwrite top attrs. - lint_cache_entry.insert(SeverityAttr { - severity: severity.severity, - depth: severity.depth + depth, - }); - } - } - }); - - let lints = lint_groups(&diag.code, edition); - let all_matching_groups = - lints.iter().filter_map(|lint_group| cached.get(lint_group)); - let cached_severity = - all_matching_groups.min_by_key(|it| it.depth).map(|it| it.severity); - - cache.insert(node.file_id, cached); - - return diag_severity.or(cached_severity); - } - - // Insert this node's descendants' attributes into any outline descendant, but not including this node. - // This must come before inserting this node's own attributes to preserve order. - collected_lint_attrs.drain().for_each(|(lint, severity)| { - if diag_severity.is_none() && lint_groups(&diag.code, edition).contains(&lint) { - diag_severity = Some(severity.severity); - } - - for item in &*cache_stack { - let node_cache_entry = cache - .get_mut(item) - .expect("we always insert cached nodes into the cache map"); - let lint_cache_entry = node_cache_entry.entry(lint.clone()); - if let hash_map::Entry::Vacant(lint_cache_entry) = lint_cache_entry { - // Do not overwrite existing lint attributes, as we go bottom to top and bottom attrs - // overwrite top attrs. - lint_cache_entry.insert(severity); - } - } - }); - - cache_stack.push(node.file_id); - cache.insert(node.file_id, FxHashMap::default()); - - if let Some(ancestor) = ast::AnyHasAttrs::cast(ancestor) { - // Insert this node's attributes into any outline descendant, including this node. - lint_attrs(sema, ancestor, edition).for_each(|(lint, severity)| { - if diag_severity.is_none() && lint_groups(&diag.code, edition).contains(&lint) { - diag_severity = Some(severity); - } - - for item in &*cache_stack { - let node_cache_entry = cache - .get_mut(item) - .expect("we always insert cached nodes into the cache map"); - let lint_cache_entry = node_cache_entry.entry(lint.clone()); - if let hash_map::Entry::Vacant(lint_cache_entry) = lint_cache_entry { - // Do not overwrite existing lint attributes, as we go bottom to top and bottom attrs - // overwrite top attrs. - lint_cache_entry.insert(SeverityAttr { severity, depth }); - } - } - }); - } - - let parent_node = sema.find_parent_file(node.file_id); - if let Some(parent_node) = parent_node { - let parent_severity = - fill_lint_attrs(sema, &parent_node, cache, cache_stack, diag, edition); - if diag_severity.is_none() { - diag_severity = parent_severity; - } - } - cache_stack.pop(); - return diag_severity; - } else if let Some(ancestor) = ast::AnyHasAttrs::cast(ancestor) { - lint_attrs(sema, ancestor, edition).for_each(|(lint, severity)| { - if diag_severity.is_none() && lint_groups(&diag.code, edition).contains(&lint) { - diag_severity = Some(severity); - } - - let lint_cache_entry = collected_lint_attrs.entry(lint); - if let hash_map::Entry::Vacant(lint_cache_entry) = lint_cache_entry { - // Do not overwrite existing lint attributes, as we go bottom to top and bottom attrs - // overwrite top attrs. - lint_cache_entry.insert(SeverityAttr { severity, depth }); - } - }); - } - } + node.value + .ancestors() + .filter_map(ast::AnyHasAttrs::cast) + .find_map(|ancestor| { + lint_attrs(sema, ancestor, edition) + .find_map(|(lint, severity)| lint_groups.contains(&lint).then_some(severity)) + }) + .or_else(|| { + lint_severity_at(sema, &sema.find_parent_file(node.file_id)?, lint_groups, edition) + }) } fn lint_attrs<'a>( @@ -945,10 +802,6 @@ impl LintGroups { fn contains(&self, group: &str) -> bool { self.groups.contains(&group) || (self.inside_warnings && group == "warnings") } - - fn iter(&self) -> impl Iterator { - self.groups.iter().copied().chain(self.inside_warnings.then_some("warnings")) - } } fn lint_groups(lint: &DiagnosticCode, edition: Edition) -> LintGroups { From 9da637a578dfc70da2d38e5a1a86263ae2f5da09 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 19 May 2025 15:37:31 +0300 Subject: [PATCH 2451/4206] skip compiler tools sanity checks on certain commands Signed-off-by: onur-ozkan --- src/bootstrap/src/core/sanity.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index eb7e3799a688d..af4ec679d080d 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -13,7 +13,6 @@ use std::ffi::{OsStr, OsString}; use std::path::PathBuf; use std::{env, fs}; -use crate::Build; #[cfg(not(test))] use crate::builder::Builder; use crate::builder::Kind; @@ -21,6 +20,7 @@ use crate::builder::Kind; use crate::core::build_steps::tool; use crate::core::config::Target; use crate::utils::exec::command; +use crate::{Build, Subcommand}; pub struct Finder { cache: HashMap>, @@ -205,6 +205,20 @@ than building it. .map(|s| s.to_string()) .collect(); + // Compiler tools like `cc` and `ar` are not configured for cross-targets on certain subcommands + // because they are not needed. + // + // See `cc_detect::find` for more details. + let skip_tools_checks = build.config.dry_run() + || matches!( + build.config.cmd, + Subcommand::Clean { .. } + | Subcommand::Check { .. } + | Subcommand::Suggest { .. } + | Subcommand::Format { .. } + | Subcommand::Setup { .. } + ); + // We're gonna build some custom C code here and there, host triples // also build some C++ shims for LLVM so we need a C++ compiler. for target in &build.targets { @@ -278,7 +292,7 @@ than building it. } } - if !build.config.dry_run() { + if !skip_tools_checks { cmd_finder.must_have(build.cc(*target)); if let Some(ar) = build.ar(*target) { cmd_finder.must_have(ar); @@ -286,7 +300,7 @@ than building it. } } - if !build.config.dry_run() { + if !skip_tools_checks { for host in &build.hosts { cmd_finder.must_have(build.cxx(*host).unwrap()); From c5bab6e9aa89e8596079dcec8c5a5e5365aa5440 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Mon, 19 May 2025 21:11:51 +0800 Subject: [PATCH 2452/4206] introduce common macro for `MutVisitor` and `Visitor` to dedup code --- compiler/rustc_ast/src/lib.rs | 1 + compiler/rustc_ast/src/mut_visit.rs | 37 ++----------- compiler/rustc_ast/src/visit.rs | 84 +++++++++++++++++++++++------ 3 files changed, 73 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 89a5a67eb5342..4fc7c7475d757 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -15,6 +15,7 @@ #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(if_let_guard)] +#![feature(macro_metavar_expr)] #![feature(negative_impls)] #![feature(never_type)] #![feature(rustdoc_internals)] diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index e49886721e364..a90349f318c09 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -20,7 +20,7 @@ use thin_vec::ThinVec; use crate::ast::*; use crate::ptr::P; use crate::tokenstream::*; -use crate::visit::{AssocCtxt, BoundKind, FnCtxt}; +use crate::visit::{AssocCtxt, BoundKind, FnCtxt, try_visit}; pub trait ExpectOne { fn expect_one(self, err: &'static str) -> A::Item; @@ -388,6 +388,8 @@ pub trait MutVisitor: Sized { } } +super::common_visitor_and_walkers!((mut) MutVisitor); + /// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful /// when using a `flat_map_*` or `filter_map_*` method within a `visit_` /// method. @@ -777,15 +779,6 @@ fn visit_defaultness(vis: &mut T, defaultness: &mut Defaultness) } } -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -fn visit_safety(vis: &mut T, safety: &mut Safety) { - match safety { - Safety::Unsafe(span) => vis.visit_span(span), - Safety::Safe(span) => vis.visit_span(span), - Safety::Default => {} - } -} - // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. fn visit_polarity(vis: &mut T, polarity: &mut ImplPolarity) { match polarity { @@ -794,14 +787,6 @@ fn visit_polarity(vis: &mut T, polarity: &mut ImplPolarity) { } } -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -fn visit_constness(vis: &mut T, constness: &mut Const) { - match constness { - Const::Yes(span) => vis.visit_span(span), - Const::No => {} - } -} - fn walk_closure_binder(vis: &mut T, binder: &mut ClosureBinder) { match binder { ClosureBinder::NotPresent => {} @@ -940,15 +925,6 @@ pub fn walk_flat_map_generic_param( smallvec![param] } -fn walk_label(vis: &mut T, Label { ident }: &mut Label) { - vis.visit_ident(ident); -} - -fn walk_lifetime(vis: &mut T, Lifetime { id, ident }: &mut Lifetime) { - vis.visit_id(id); - vis.visit_ident(ident); -} - fn walk_generics(vis: &mut T, generics: &mut Generics) { let Generics { params, where_clause, span } = generics; params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); @@ -1340,13 +1316,6 @@ fn walk_const_item(vis: &mut T, item: &mut ConstItem) { walk_define_opaques(vis, define_opaque); } -fn walk_fn_header(vis: &mut T, header: &mut FnHeader) { - let FnHeader { safety, coroutine_kind, constness, ext: _ } = header; - visit_constness(vis, constness); - coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind)); - visit_safety(vis, safety); -} - pub fn walk_crate(vis: &mut T, krate: &mut Crate) { let Crate { attrs, items, spans, id, is_placeholder: _ } = krate; vis.visit_id(id); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 69a186c8cf1b7..e43d7ae065d9e 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -315,6 +315,75 @@ pub trait Visitor<'ast>: Sized { } } +#[macro_export] +macro_rules! common_visitor_and_walkers { + ($(($mut: ident))? $Visitor:ident$(<$lt:lifetime>)?) => { + // this is only used by the MutVisitor. We include this symmetry here to make writing other functions easier + $(${ignore($lt)} + #[expect(unused, rustc::pass_by_value)] + #[inline] + )? + fn visit_span<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, span: &$($lt)? $($mut)? Span) $(-> >::Result)? { + $( + let _ = stringify!($mut); + visitor.visit_span(span); + )? + $(${ignore($lt)}V::Result::output())? + } + + // this is only used by the MutVisitor. We include this symmetry here to make writing other functions easier + $(${ignore($lt)} + #[expect(unused, rustc::pass_by_value)] + #[inline] + )? + fn visit_id<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, id: &$($lt)? $($mut)? NodeId) $(-> >::Result)? { + $( + let _ = stringify!($mut); + visitor.visit_id(id); + )? + $(${ignore($lt)}V::Result::output())? + } + + // this is only used by the MutVisitor. We include this symmetry here to make writing other functions easier + fn visit_safety<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, safety: &$($lt)? $($mut)? Safety) $(-> >::Result)? { + match safety { + Safety::Unsafe(span) => visit_span(vis, span), + Safety::Safe(span) => visit_span(vis, span), + Safety::Default => { $(${ignore($lt)}V::Result::output())? } + } + } + + fn visit_constness<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, constness: &$($lt)? $($mut)? Const) $(-> >::Result)? { + match constness { + Const::Yes(span) => visit_span(vis, span), + Const::No => { + $(>::Result::output())? + } + } + } + + pub fn walk_label<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, Label { ident }: &$($lt)? $($mut)? Label) $(-> >::Result)? { + visitor.visit_ident(ident) + } + + pub fn walk_fn_header<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, header: &$($lt)? $($mut)? FnHeader) $(-> >::Result)? { + let FnHeader { safety, coroutine_kind, constness, ext: _ } = header; + try_visit!(visit_constness(visitor, constness)); + if let Some(coroutine_kind) = coroutine_kind { + try_visit!(visitor.visit_coroutine_kind(coroutine_kind)); + } + visit_safety(visitor, safety) + } + + pub fn walk_lifetime<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, Lifetime { id, ident }: &$($lt)? $($mut)? Lifetime) $(-> >::Result)? { + try_visit!(visit_id(visitor, id)); + visitor.visit_ident(ident) + } + }; +} + +common_visitor_and_walkers!(Visitor<'a>); + pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) -> V::Result { let Crate { attrs, items, spans: _, id: _, is_placeholder: _ } = krate; walk_list!(visitor, visit_attribute, attrs); @@ -334,15 +403,6 @@ pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) -> V::R V::Result::output() } -pub fn walk_label<'a, V: Visitor<'a>>(visitor: &mut V, Label { ident }: &'a Label) -> V::Result { - visitor.visit_ident(ident) -} - -pub fn walk_lifetime<'a, V: Visitor<'a>>(visitor: &mut V, lifetime: &'a Lifetime) -> V::Result { - let Lifetime { id: _, ident } = lifetime; - visitor.visit_ident(ident) -} - pub fn walk_poly_trait_ref<'a, V>(visitor: &mut V, trait_ref: &'a PolyTraitRef) -> V::Result where V: Visitor<'a>, @@ -926,12 +986,6 @@ pub fn walk_fn_ret_ty<'a, V: Visitor<'a>>(visitor: &mut V, ret_ty: &'a FnRetTy) V::Result::output() } -pub fn walk_fn_header<'a, V: Visitor<'a>>(visitor: &mut V, fn_header: &'a FnHeader) -> V::Result { - let FnHeader { safety: _, coroutine_kind, constness: _, ext: _ } = fn_header; - visit_opt!(visitor, visit_coroutine_kind, coroutine_kind.as_ref()); - V::Result::output() -} - pub fn walk_fn_decl<'a, V: Visitor<'a>>( visitor: &mut V, FnDecl { inputs, output }: &'a FnDecl, From 8286487c0ceef102e162d39d0c75adc1e3068b6c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 19 May 2025 15:18:24 +0200 Subject: [PATCH 2453/4206] fix data race in ReentrantLock fallback for targets without 64bit atomics --- library/std/src/sync/reentrant_lock.rs | 8 ++++++-- .../miri/tests/many-seeds/reentrant-lock.rs | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 src/tools/miri/tests/many-seeds/reentrant-lock.rs diff --git a/library/std/src/sync/reentrant_lock.rs b/library/std/src/sync/reentrant_lock.rs index 24539d4e8303d..96a4cf12659cc 100644 --- a/library/std/src/sync/reentrant_lock.rs +++ b/library/std/src/sync/reentrant_lock.rs @@ -136,7 +136,7 @@ cfg_if!( // we only ever read from the tid if `tls_addr` matches the current // TLS address. In that case, either the tid has been set by // the current thread, or by a thread that has terminated before - // the current thread was created. In either case, no further + // the current thread's `tls_addr` was allocated. In either case, no further // synchronization is needed (as per ) tls_addr: Atomic, tid: UnsafeCell, @@ -154,8 +154,12 @@ cfg_if!( // NOTE: This assumes that `owner` is the ID of the current // thread, and may spuriously return `false` if that's not the case. fn contains(&self, owner: ThreadId) -> bool { + // We must call `tls_addr()` *before* doing the load to ensure that if we reuse an + // earlier thread's address, the `tls_addr.load()` below happens-after everything + // that thread did. + let tls_addr = tls_addr(); // SAFETY: See the comments in the struct definition. - self.tls_addr.load(Ordering::Relaxed) == tls_addr() + self.tls_addr.load(Ordering::Relaxed) == tls_addr && unsafe { *self.tid.get() } == owner.as_u64().get() } diff --git a/src/tools/miri/tests/many-seeds/reentrant-lock.rs b/src/tools/miri/tests/many-seeds/reentrant-lock.rs new file mode 100644 index 0000000000000..8a363179a9cc7 --- /dev/null +++ b/src/tools/miri/tests/many-seeds/reentrant-lock.rs @@ -0,0 +1,19 @@ +#![feature(reentrant_lock)] +//! This is a regression test for +//! . + +use std::cell::Cell; +use std::sync::ReentrantLock; +use std::thread; + +static LOCK: ReentrantLock> = ReentrantLock::new(Cell::new(0)); + +fn main() { + for _ in 0..20 { + thread::spawn(move || { + let val = LOCK.lock(); + val.set(val.get() + 1); + drop(val); + }); + } +} From 26ea763f24754cf79191ad9ae949ad285f51c363 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 19 May 2025 15:22:31 +0200 Subject: [PATCH 2454/4206] add this to Miri's trophy case --- src/tools/miri/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index b692ddab4ffc8..122438a2509b3 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -580,6 +580,7 @@ Definite bugs found: * [Weak-memory-induced memory leak in Windows thread-local storage](https://github.com/rust-lang/rust/pull/124281) * [A bug in the new `RwLock::downgrade` implementation](https://rust-lang.zulipchat.com/#narrow/channel/269128-miri/topic/Miri.20error.20library.20test) (caught by Miri before it landed in the Rust repo) * [Mockall reading unintialized memory when mocking `std::io::Read::read`, even if all expectations are satisfied](https://github.com/asomers/mockall/issues/647) (caught by Miri running Tokio's test suite) +* [`ReentrantLock` not correctly dealing with reuse of addresses for TLS storage of different threads](https://github.com/rust-lang/rust/pull/141248) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From aa4d16a1a793e67cdc2225d3a4fac29d9e173c0c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 19 May 2025 15:35:19 +0200 Subject: [PATCH 2455/4206] run tests on mips-unknown-linux-gnu --- src/tools/miri/ci/ci.sh | 9 +++-- .../read_only_atomic_load_large.rs | 1 + src/tools/miri/tests/panic/transmute_fat2.rs | 2 + src/tools/miri/tests/pass/atomic.rs | 40 ++++++++++--------- 4 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 755e02d02eca1..00102bb26778f 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -156,11 +156,12 @@ case $HOST_TARGET in MANY_SEEDS=64 TEST_TARGET=i686-pc-windows-gnu run_tests MANY_SEEDS=64 TEST_TARGET=x86_64-pc-windows-msvc CARGO_MIRI_ENV=1 run_tests # Extra tier 2 - TEST_TARGET=arm-unknown-linux-gnueabi run_tests - TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture of choice + MANY_SEEDS=16 TEST_TARGET=arm-unknown-linux-gnueabi run_tests + MANY_SEEDS=16 TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture of choice # Not officially supported tier 2 - TEST_TARGET=x86_64-unknown-illumos run_tests - TEST_TARGET=x86_64-pc-solaris run_tests + MANY_SEEDS=16 TEST_TARGET=mips-unknown-linux-gnu run_tests # a 32bit big-endian target, and also a target without 64bit atomics + MANY_SEEDS=16 TEST_TARGET=x86_64-unknown-illumos run_tests + MANY_SEEDS=16 TEST_TARGET=x86_64-pc-solaris run_tests # Partially supported targets (tier 2) BASIC="empty_main integer heap_alloc libc-mem vec string btreemap" # ensures we have the basics: pre-main code, system allocator UNIX="hello panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there diff --git a/src/tools/miri/tests/fail/concurrency/read_only_atomic_load_large.rs b/src/tools/miri/tests/fail/concurrency/read_only_atomic_load_large.rs index 42c3a9619d464..2c01b0132b824 100644 --- a/src/tools/miri/tests/fail/concurrency/read_only_atomic_load_large.rs +++ b/src/tools/miri/tests/fail/concurrency/read_only_atomic_load_large.rs @@ -2,6 +2,7 @@ //@compile-flags: -Zmiri-disable-stacked-borrows // Needs atomic accesses larger than the pointer size //@ignore-bitwidth: 64 +//@ignore-target: mips- use std::sync::atomic::{AtomicI64, Ordering}; diff --git a/src/tools/miri/tests/panic/transmute_fat2.rs b/src/tools/miri/tests/panic/transmute_fat2.rs index 0205433ad9fb9..e695ff2d57ba5 100644 --- a/src/tools/miri/tests/panic/transmute_fat2.rs +++ b/src/tools/miri/tests/panic/transmute_fat2.rs @@ -5,6 +5,8 @@ fn main() { let bad = unsafe { std::mem::transmute::(42 << 64) }; #[cfg(all(target_endian = "little", target_pointer_width = "32"))] let bad = unsafe { std::mem::transmute::(42) }; + #[cfg(all(target_endian = "big", target_pointer_width = "32"))] + let bad = unsafe { std::mem::transmute::(42 << 32) }; // This created a slice with length 0, so the following will fail the bounds check. bad[0]; } diff --git a/src/tools/miri/tests/pass/atomic.rs b/src/tools/miri/tests/pass/atomic.rs index 2b2e89e6d70fc..3de34e570c7ee 100644 --- a/src/tools/miri/tests/pass/atomic.rs +++ b/src/tools/miri/tests/pass/atomic.rs @@ -7,15 +7,17 @@ #![allow(static_mut_refs)] use std::sync::atomic::Ordering::*; -use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicPtr, AtomicU64, compiler_fence, fence}; +use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicPtr, AtomicUsize, compiler_fence, fence}; fn main() { atomic_bool(); atomic_all_ops(); - atomic_u64(); atomic_fences(); atomic_ptr(); weak_sometimes_fails(); + + #[cfg(target_has_atomic = "64")] + atomic_u64(); } fn atomic_bool() { @@ -36,25 +38,10 @@ fn atomic_bool() { } } -// There isn't a trait to use to make this generic, so just use a macro -macro_rules! compare_exchange_weak_loop { - ($atom:expr, $from:expr, $to:expr, $succ_order:expr, $fail_order:expr) => { - loop { - match $atom.compare_exchange_weak($from, $to, $succ_order, $fail_order) { - Ok(n) => { - assert_eq!(n, $from); - break; - } - Err(n) => assert_eq!(n, $from), - } - } - }; -} - /// Make sure we can handle all the intrinsics fn atomic_all_ops() { static ATOMIC: AtomicIsize = AtomicIsize::new(0); - static ATOMIC_UNSIGNED: AtomicU64 = AtomicU64::new(0); + static ATOMIC_UNSIGNED: AtomicUsize = AtomicUsize::new(0); let load_orders = [Relaxed, Acquire, SeqCst]; let stored_orders = [Relaxed, Release, SeqCst]; @@ -94,9 +81,26 @@ fn atomic_all_ops() { } } +#[cfg(target_has_atomic = "64")] fn atomic_u64() { + use std::sync::atomic::AtomicU64; static ATOMIC: AtomicU64 = AtomicU64::new(0); + // There isn't a trait to use to make this generic, so just use a macro + macro_rules! compare_exchange_weak_loop { + ($atom:expr, $from:expr, $to:expr, $succ_order:expr, $fail_order:expr) => { + loop { + match $atom.compare_exchange_weak($from, $to, $succ_order, $fail_order) { + Ok(n) => { + assert_eq!(n, $from); + break; + } + Err(n) => assert_eq!(n, $from), + } + } + }; + } + ATOMIC.store(1, SeqCst); assert_eq!(ATOMIC.compare_exchange(0, 0x100, AcqRel, Acquire), Err(1)); assert_eq!(ATOMIC.compare_exchange(0, 1, Release, Relaxed), Err(1)); From be5d6c5425e8dfdf1662225fb23d6deb0e124dd4 Mon Sep 17 00:00:00 2001 From: dianqk Date: Mon, 19 May 2025 21:07:34 +0800 Subject: [PATCH 2456/4206] gvn: bail out unavoidable non-ssa locals in repeat We cannot transform `*elem` to `array[idx1]` in the following code, as `idx1` has already been modified. ```rust mir! { let array; let elem; { array = [*val; 5]; elem = &array[idx1]; idx1 = idx2; RET = *elem; Return() } } ``` --- compiler/rustc_mir_transform/src/gvn.rs | 8 ++- .../mir-opt/gvn_repeat.repeat_local.GVN.diff | 18 +++++++ .../mir-opt/gvn_repeat.repeat_place.GVN.diff | 17 +++++++ tests/mir-opt/gvn_repeat.rs | 49 +++++++++++++++++++ 4 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 tests/mir-opt/gvn_repeat.repeat_local.GVN.diff create mode 100644 tests/mir-opt/gvn_repeat.repeat_place.GVN.diff create mode 100644 tests/mir-opt/gvn_repeat.rs diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 209e818e9e32d..a91d46ec406e7 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -638,6 +638,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { place: PlaceRef<'tcx>, value: VnIndex, proj: PlaceElem<'tcx>, + from_non_ssa_index: &mut bool, ) -> Option { let proj = match proj { ProjectionElem::Deref => { @@ -682,6 +683,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } ProjectionElem::Index(idx) => { if let Value::Repeat(inner, _) = self.get(value) { + *from_non_ssa_index |= self.locals[idx].is_none(); return Some(*inner); } let idx = self.locals[idx]?; @@ -774,6 +776,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // Invariant: `value` holds the value up-to the `index`th projection excluded. let mut value = self.locals[place.local]?; + let mut from_non_ssa_index = false; for (index, proj) in place.projection.iter().enumerate() { if let Value::Projection(pointer, ProjectionElem::Deref) = *self.get(value) && let Value::Address { place: mut pointee, kind, .. } = *self.get(pointer) @@ -791,7 +794,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } let base = PlaceRef { local: place.local, projection: &place.projection[..index] }; - value = self.project(base, value, proj)?; + value = self.project(base, value, proj, &mut from_non_ssa_index)?; } if let Value::Projection(pointer, ProjectionElem::Deref) = *self.get(value) @@ -804,6 +807,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } if let Some(new_local) = self.try_as_local(value, location) { place_ref = PlaceRef { local: new_local, projection: &[] }; + } else if from_non_ssa_index { + // If access to non-SSA locals is unavoidable, bail out. + return None; } if place_ref.local != place.local || place_ref.projection.len() < place.projection.len() { diff --git a/tests/mir-opt/gvn_repeat.repeat_local.GVN.diff b/tests/mir-opt/gvn_repeat.repeat_local.GVN.diff new file mode 100644 index 0000000000000..fd04782528117 --- /dev/null +++ b/tests/mir-opt/gvn_repeat.repeat_local.GVN.diff @@ -0,0 +1,18 @@ +- // MIR for `repeat_local` before GVN ++ // MIR for `repeat_local` after GVN + + fn repeat_local(_1: usize, _2: usize, _3: i32) -> i32 { + let mut _0: i32; + let mut _4: [i32; 5]; + let mut _5: &i32; + + bb0: { + _4 = [copy _3; 5]; + _5 = &_4[_1]; + _1 = copy _2; +- _0 = copy (*_5); ++ _0 = copy _3; + return; + } + } + diff --git a/tests/mir-opt/gvn_repeat.repeat_place.GVN.diff b/tests/mir-opt/gvn_repeat.repeat_place.GVN.diff new file mode 100644 index 0000000000000..e490925bc119e --- /dev/null +++ b/tests/mir-opt/gvn_repeat.repeat_place.GVN.diff @@ -0,0 +1,17 @@ +- // MIR for `repeat_place` before GVN ++ // MIR for `repeat_place` after GVN + + fn repeat_place(_1: usize, _2: usize, _3: &i32) -> i32 { + let mut _0: i32; + let mut _4: [i32; 5]; + let mut _5: &i32; + + bb0: { + _4 = [copy (*_3); 5]; + _5 = &_4[_1]; + _1 = copy _2; + _0 = copy (*_5); + return; + } + } + diff --git a/tests/mir-opt/gvn_repeat.rs b/tests/mir-opt/gvn_repeat.rs new file mode 100644 index 0000000000000..bbbb2a7ccbaf5 --- /dev/null +++ b/tests/mir-opt/gvn_repeat.rs @@ -0,0 +1,49 @@ +//@ test-mir-pass: GVN + +#![feature(custom_mir, core_intrinsics)] + +// Check that we do not introduce out-of-bounds access. + +use std::intrinsics::mir::*; + +// EMIT_MIR gvn_repeat.repeat_place.GVN.diff +#[custom_mir(dialect = "runtime")] +pub fn repeat_place(mut idx1: usize, idx2: usize, val: &i32) -> i32 { + // CHECK-LABEL: fn repeat_place( + // CHECK: let mut [[ELEM:.*]]: &i32; + // CHECK: _0 = copy (*[[ELEM]]) + mir! { + let array; + let elem; + { + array = [*val; 5]; + elem = &array[idx1]; + idx1 = idx2; + RET = *elem; + Return() + } + } +} + +// EMIT_MIR gvn_repeat.repeat_local.GVN.diff +#[custom_mir(dialect = "runtime")] +pub fn repeat_local(mut idx1: usize, idx2: usize, val: i32) -> i32 { + // CHECK-LABEL: fn repeat_local( + // CHECK: _0 = copy _3 + mir! { + let array; + let elem; + { + array = [val; 5]; + elem = &array[idx1]; + idx1 = idx2; + RET = *elem; + Return() + } + } +} + +fn main() { + assert_eq!(repeat_place(0, 5, &0), 0); + assert_eq!(repeat_local(0, 5, 0), 0); +} From 4f45f0442ba616bc15111df3f50bec5e3078a334 Mon Sep 17 00:00:00 2001 From: Stan Manilov Date: Mon, 19 May 2025 17:32:29 +0300 Subject: [PATCH 2457/4206] Update link to Forge guide on new flags --- src/doc/rustc-dev-guide/src/cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/cli.md b/src/doc/rustc-dev-guide/src/cli.md index 408ae20700430..4c77007ea4415 100644 --- a/src/doc/rustc-dev-guide/src/cli.md +++ b/src/doc/rustc-dev-guide/src/cli.md @@ -28,6 +28,6 @@ adding a new command-line argument. unstable-options` flag. [cli-docs]: https://doc.rust-lang.org/rustc/command-line-arguments.html -[forge guide for new options]: https://forge.rust-lang.org/compiler/new_option.html +[forge guide for new options]: https://forge.rust-lang.org/compiler/proposals-and-stabilization.html#compiler-flags [unstable book]: https://doc.rust-lang.org/nightly/unstable-book/ [`parse_bool`]: https://github.com/rust-lang/rust/blob/e5335592e78354e33d798d20c04bcd677c1df62d/src/librustc_session/options.rs#L307-L313 From 61059282eb9ea1f37804790b182e5821337924b4 Mon Sep 17 00:00:00 2001 From: Andrew Zhogin Date: Mon, 19 May 2025 21:14:28 +0700 Subject: [PATCH 2458/4206] Warning added when dependency crate has async drop types, and the feature is disabled --- compiler/rustc_interface/src/passes.rs | 1 + compiler/rustc_metadata/messages.ftl | 4 ++++ compiler/rustc_metadata/src/creader.rs | 21 +++++++++++++++++++ compiler/rustc_metadata/src/errors.rs | 10 +++++++++ compiler/rustc_metadata/src/rmeta/decoder.rs | 4 ++++ .../async-drop/dependency-dropped.rs | 5 ++++- ...ependency-dropped.with_feature.run.stdout} | 0 ...endency-dropped.without_feature.run.stdout | 1 + .../dependency-dropped.without_feature.stderr | 10 +++++++++ 9 files changed, 55 insertions(+), 1 deletion(-) rename tests/ui/async-await/async-drop/{dependency-dropped.run.stdout => dependency-dropped.with_feature.run.stdout} (100%) create mode 100644 tests/ui/async-await/async-drop/dependency-dropped.without_feature.run.stdout create mode 100644 tests/ui/async-await/async-drop/dependency-dropped.without_feature.stderr diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index e28639576f031..8f6c5b47ee23d 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -282,6 +282,7 @@ fn configure_and_expand( resolver.resolve_crate(&krate); CStore::from_tcx(tcx).report_incompatible_target_modifiers(tcx, &krate); + CStore::from_tcx(tcx).report_incompatible_async_drop_feature(tcx, &krate); krate } diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl index d997ba198aca8..cac8f34b0fa0d 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -1,6 +1,10 @@ metadata_as_needed_compatibility = linking modifier `as-needed` is only compatible with `dylib` and `framework` linking kinds +metadata_async_drop_types_in_dependency = + found async drop types in dependecy `{$extern_crate}`, but async_drop feature is disabled for `{$local_crate}` + .help = if async drop type will be dropped in a crate without `feature(async_drop)`, sync Drop will be used + metadata_bad_panic_strategy = the linked panic runtime `{$runtime}` is not compiled with this crate's panic strategy `{$strategy}` diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 07fb2de8a3e0c..c7e9a2936f5dd 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -473,6 +473,27 @@ impl CStore { } } + // Report about async drop types in dependency if async drop feature is disabled + pub fn report_incompatible_async_drop_feature(&self, tcx: TyCtxt<'_>, krate: &Crate) { + if tcx.features().async_drop() { + return; + } + for (_cnum, data) in self.iter_crate_data() { + if data.is_proc_macro_crate() { + continue; + } + if data.has_async_drops() { + let extern_crate = data.name(); + let local_crate = tcx.crate_name(LOCAL_CRATE); + tcx.dcx().emit_warn(errors::AsyncDropTypesInDependency { + span: krate.spans.inner_span.shrink_to_lo(), + extern_crate, + local_crate, + }); + } + } + } + pub fn new(metadata_loader: Box) -> CStore { CStore { metadata_loader, diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index c45daeda85dbc..16f59793e6326 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -811,3 +811,13 @@ pub struct UnknownTargetModifierUnsafeAllowed { pub span: Span, pub flag_name: String, } + +#[derive(Diagnostic)] +#[diag(metadata_async_drop_types_in_dependency)] +#[help] +pub struct AsyncDropTypesInDependency { + #[primary_span] + pub span: Span, + pub extern_crate: Symbol, + pub local_crate: Symbol, +} diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index bd813cadedcd4..2e4352ca532aa 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1984,6 +1984,10 @@ impl CrateMetadata { self.root.header.hash } + pub(crate) fn has_async_drops(&self) -> bool { + self.root.tables.adt_async_destructor.len > 0 + } + fn num_def_ids(&self) -> usize { self.root.tables.def_keys.size() } diff --git a/tests/ui/async-await/async-drop/dependency-dropped.rs b/tests/ui/async-await/async-drop/dependency-dropped.rs index f763bb32b1733..c8670be4e8baa 100644 --- a/tests/ui/async-await/async-drop/dependency-dropped.rs +++ b/tests/ui/async-await/async-drop/dependency-dropped.rs @@ -1,9 +1,12 @@ //@ run-pass //@ check-run-results +//@ revisions: with_feature without_feature //@ aux-build:async-drop-dep.rs //@ edition:2021 -#![feature(async_drop)] +#![cfg_attr(with_feature, feature(async_drop))] +//[without_feature]~^ WARN found async drop types in dependecy `async_drop_dep`, but async_drop feature is disabled for `dependency_dropped` + #![allow(incomplete_features)] extern crate async_drop_dep; diff --git a/tests/ui/async-await/async-drop/dependency-dropped.run.stdout b/tests/ui/async-await/async-drop/dependency-dropped.with_feature.run.stdout similarity index 100% rename from tests/ui/async-await/async-drop/dependency-dropped.run.stdout rename to tests/ui/async-await/async-drop/dependency-dropped.with_feature.run.stdout diff --git a/tests/ui/async-await/async-drop/dependency-dropped.without_feature.run.stdout b/tests/ui/async-await/async-drop/dependency-dropped.without_feature.run.stdout new file mode 100644 index 0000000000000..80eeeefc2220f --- /dev/null +++ b/tests/ui/async-await/async-drop/dependency-dropped.without_feature.run.stdout @@ -0,0 +1 @@ +Sync drop diff --git a/tests/ui/async-await/async-drop/dependency-dropped.without_feature.stderr b/tests/ui/async-await/async-drop/dependency-dropped.without_feature.stderr new file mode 100644 index 0000000000000..56e49568e1004 --- /dev/null +++ b/tests/ui/async-await/async-drop/dependency-dropped.without_feature.stderr @@ -0,0 +1,10 @@ +warning: found async drop types in dependecy `async_drop_dep`, but async_drop feature is disabled for `dependency_dropped` + --> $DIR/dependency-dropped.rs:7:1 + | +LL | #![cfg_attr(with_feature, feature(async_drop))] + | ^ + | + = help: if async drop type will be dropped in a crate without `feature(async_drop)`, sync Drop will be used + +warning: 1 warning emitted + From a14e25c76832b16e48f293e8dcdd6c889e4f6402 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 19 May 2025 13:27:49 +0200 Subject: [PATCH 2459/4206] windows: document that we rely on an undocumented property of GetUserProfileDirectoryW --- library/std/src/sys/pal/windows/os.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs index f331282d2d72a..1ebbbec9e914f 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/pal/windows/os.rs @@ -202,6 +202,8 @@ fn home_dir_crt() -> Option { |buf, mut sz| { // GetUserProfileDirectoryW does not quite use the usual protocol for // negotiating the buffer size, so we have to translate. + // FIXME(#141254): We rely on the *undocumented* property that this function will + // always set the size, not just on failure. match c::GetUserProfileDirectoryW( ptr::without_provenance_mut(CURRENT_PROCESS_TOKEN), buf, From 758b7994e8c7b478ce7e532a9ba4911190c78218 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 19 May 2025 17:07:33 +0200 Subject: [PATCH 2460/4206] GetUserProfileDirectoryW: reference issue regarding implementation details we rely on --- src/tools/miri/src/shims/windows/env.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/src/shims/windows/env.rs b/src/tools/miri/src/shims/windows/env.rs index 1b2ccd99ef9f4..0cbabc52d2a5d 100644 --- a/src/tools/miri/src/shims/windows/env.rs +++ b/src/tools/miri/src/shims/windows/env.rs @@ -238,8 +238,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Of course we cannot use `windows_check_buffer_size` here since this uses // a different method for dealing with a too-small buffer than the other functions... let (success, len) = this.write_path_to_wide_str(home, buf, size_avail.into())?; - // The Windows docs just say that this is written on failure. But std - // seems to rely on it always being written. + // The Windows docs just say that this is written on failure, but std relies on it + // always being written. Also see . this.write_scalar(Scalar::from_u32(len.try_into().unwrap()), &size)?; if success { Scalar::from_i32(1) // return TRUE From c24e1c378f93055a53503b02894ccbede02203db Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 19 May 2025 15:14:38 +0200 Subject: [PATCH 2461/4206] add s390x z17 target features --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 8 ++++++ compiler/rustc_target/src/target_features.rs | 26 ++++++++++++-------- tests/ui/check-cfg/target_feature.stderr | 12 +++++++++ 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 8f57f0983abb9..9718c95f38a88 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -282,6 +282,14 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option None, + ( + "s390x", + "message-security-assist-extension12" + | "concurrent-functions" + | "miscellaneous-extensions-4" + | "vector-enhancements-3" + | "vector-packed-decimal-enhancement-3", + ) if get_version().0 < 20 => None, // Enable the evex512 target feature if an avx512 target feature is enabled. ("x86", s) if s.starts_with("avx512") => Some(LLVMFeature::with_dependencies( s, diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 99b04ac272009..45c971cdfa6f3 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -710,29 +710,35 @@ static LOONGARCH_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-end ]; +#[rustfmt::skip] const IBMZ_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start ("backchain", Unstable(sym::s390x_target_feature), &[]), + ("concurrent-functions", Unstable(sym::s390x_target_feature), &[]), ("deflate-conversion", Unstable(sym::s390x_target_feature), &[]), ("enhanced-sort", Unstable(sym::s390x_target_feature), &[]), ("guarded-storage", Unstable(sym::s390x_target_feature), &[]), ("high-word", Unstable(sym::s390x_target_feature), &[]), + // LLVM does not define message-security-assist-extension versions 1, 2, 6, 10 and 11. + ("message-security-assist-extension12", Unstable(sym::s390x_target_feature), &[]), + ("message-security-assist-extension3", Unstable(sym::s390x_target_feature), &[]), + ("message-security-assist-extension4", Unstable(sym::s390x_target_feature), &[]), + ("message-security-assist-extension5", Unstable(sym::s390x_target_feature), &[]), + ("message-security-assist-extension8", Unstable(sym::s390x_target_feature), &["message-security-assist-extension3"]), + ("message-security-assist-extension9", Unstable(sym::s390x_target_feature), &["message-security-assist-extension3", "message-security-assist-extension4"]), + ("miscellaneous-extensions-2", Unstable(sym::s390x_target_feature), &[]), + ("miscellaneous-extensions-3", Unstable(sym::s390x_target_feature), &[]), + ("miscellaneous-extensions-4", Unstable(sym::s390x_target_feature), &[]), ("nnp-assist", Unstable(sym::s390x_target_feature), &["vector"]), ("transactional-execution", Unstable(sym::s390x_target_feature), &[]), ("vector", Unstable(sym::s390x_target_feature), &[]), ("vector-enhancements-1", Unstable(sym::s390x_target_feature), &["vector"]), ("vector-enhancements-2", Unstable(sym::s390x_target_feature), &["vector-enhancements-1"]), + ("vector-enhancements-3", Unstable(sym::s390x_target_feature), &["vector-enhancements-2"]), ("vector-packed-decimal", Unstable(sym::s390x_target_feature), &["vector"]), - ( - "vector-packed-decimal-enhancement", - Unstable(sym::s390x_target_feature), - &["vector-packed-decimal"], - ), - ( - "vector-packed-decimal-enhancement-2", - Unstable(sym::s390x_target_feature), - &["vector-packed-decimal-enhancement"], - ), + ("vector-packed-decimal-enhancement", Unstable(sym::s390x_target_feature), &["vector-packed-decimal"]), + ("vector-packed-decimal-enhancement-2", Unstable(sym::s390x_target_feature), &["vector-packed-decimal-enhancement"]), + ("vector-packed-decimal-enhancement-3", Unstable(sym::s390x_target_feature), &["vector-packed-decimal-enhancement-2"]), // tidy-alphabetical-end ]; diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index eb66633f9dd7c..ec81ba2e3d89f 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -62,6 +62,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `c` `cache` `cmpxchg16b` +`concurrent-functions` `crc` `crt-static` `cssc` @@ -159,6 +160,15 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `lzcnt` `m` `mclass` +`message-security-assist-extension12` +`message-security-assist-extension3` +`message-security-assist-extension4` +`message-security-assist-extension5` +`message-security-assist-extension8` +`message-security-assist-extension9` +`miscellaneous-extensions-2` +`miscellaneous-extensions-3` +`miscellaneous-extensions-4` `mops` `movbe` `movrs` @@ -287,9 +297,11 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `vector` `vector-enhancements-1` `vector-enhancements-2` +`vector-enhancements-3` `vector-packed-decimal` `vector-packed-decimal-enhancement` `vector-packed-decimal-enhancement-2` +`vector-packed-decimal-enhancement-3` `vfp2` `vfp3` `vfp4` From db42c7dddc2ad9a5cc25dcd6773592e2dfbc2e7a Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Mon, 19 May 2025 17:31:56 +0200 Subject: [PATCH 2462/4206] Remove obsolete restriction in code --- src/driver.rs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/driver.rs b/src/driver.rs index f8acf88cf81c6..37adb14169a3f 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -96,16 +96,11 @@ fn track_files(psess: &mut ParseSess) { // During development track the `clippy-driver` executable so that cargo will re-run clippy whenever // it is rebuilt - #[expect( - clippy::collapsible_if, - reason = "Due to a bug in let_chains this if statement can't be collapsed" - )] - if cfg!(debug_assertions) { - if let Ok(current_exe) = env::current_exe() - && let Some(current_exe) = current_exe.to_str() - { - file_depinfo.insert(Symbol::intern(current_exe)); - } + if cfg!(debug_assertions) + && let Ok(current_exe) = env::current_exe() + && let Some(current_exe) = current_exe.to_str() + { + file_depinfo.insert(Symbol::intern(current_exe)); } } From c8f5ff867d2fee553c4c0c6401aae170be3ece19 Mon Sep 17 00:00:00 2001 From: Mario Pastorelli Date: Wed, 5 Mar 2025 00:03:04 +0100 Subject: [PATCH 2463/4206] Add `std::io::Seek` instance for `std::io::Take` --- library/std/src/io/mod.rs | 53 +++++++++++++++- library/std/src/io/tests.rs | 120 ++++++++++++++++++++++++++++++++++++ library/std/src/lib.rs | 1 + 3 files changed, 173 insertions(+), 1 deletion(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 96fac4f6bde68..03f5f838311a9 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -1214,7 +1214,7 @@ pub trait Read { where Self: Sized, { - Take { inner: self, limit } + Take { inner: self, len: limit, limit } } } @@ -2830,6 +2830,7 @@ impl SizeHint for Chain { #[derive(Debug)] pub struct Take { inner: T, + len: u64, limit: u64, } @@ -2864,6 +2865,12 @@ impl Take { self.limit } + /// Returns the number of bytes read so far. + #[unstable(feature = "seek_io_take_position", issue = "97227")] + pub fn position(&self) -> u64 { + self.len - self.limit + } + /// Sets the number of bytes that can be read before this instance will /// return EOF. This is the same as constructing a new `Take` instance, so /// the amount of bytes read and the previous limit value don't matter when @@ -2889,6 +2896,7 @@ impl Take { /// ``` #[stable(feature = "take_set_limit", since = "1.27.0")] pub fn set_limit(&mut self, limit: u64) { + self.len = limit; self.limit = limit; } @@ -3076,6 +3084,49 @@ impl SizeHint for Take { } } +#[stable(feature = "seek_io_take", since = "CURRENT_RUSTC_VERSION")] +impl Seek for Take { + fn seek(&mut self, pos: SeekFrom) -> Result { + let new_position = match pos { + SeekFrom::Start(v) => Some(v), + SeekFrom::Current(v) => self.position().checked_add_signed(v), + SeekFrom::End(v) => self.len.checked_add_signed(v), + }; + let new_position = match new_position { + Some(v) if v <= self.len => v, + _ => return Err(ErrorKind::InvalidInput.into()), + }; + while new_position != self.position() { + if let Some(offset) = new_position.checked_signed_diff(self.position()) { + self.inner.seek_relative(offset)?; + self.limit = self.limit.wrapping_sub(offset as u64); + break; + } + let offset = if new_position > self.position() { i64::MAX } else { i64::MIN }; + self.inner.seek_relative(offset)?; + self.limit = self.limit.wrapping_sub(offset as u64); + } + Ok(new_position) + } + + fn stream_len(&mut self) -> Result { + Ok(self.len) + } + + fn stream_position(&mut self) -> Result { + Ok(self.position()) + } + + fn seek_relative(&mut self, offset: i64) -> Result<()> { + if !self.position().checked_add_signed(offset).is_some_and(|p| p <= self.len) { + return Err(ErrorKind::InvalidInput.into()); + } + self.inner.seek_relative(offset)?; + self.limit = self.limit.wrapping_sub(offset as u64); + Ok(()) + } +} + /// An iterator over `u8` values of a reader. /// /// This struct is generally created by calling [`bytes`] on a reader. diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index fd962b0415c7d..b22988d4a8a9d 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -416,6 +416,126 @@ fn seek_position() -> io::Result<()> { Ok(()) } +#[test] +fn take_seek() -> io::Result<()> { + let mut buf = Cursor::new(b"0123456789"); + buf.set_position(2); + let mut take = buf.by_ref().take(4); + let mut buf1 = [0u8; 1]; + let mut buf2 = [0u8; 2]; + assert_eq!(take.position(), 0); + + assert_eq!(take.seek(SeekFrom::Start(0))?, 0); + take.read_exact(&mut buf2)?; + assert_eq!(buf2, [b'2', b'3']); + assert_eq!(take.seek(SeekFrom::Start(1))?, 1); + take.read_exact(&mut buf2)?; + assert_eq!(buf2, [b'3', b'4']); + assert_eq!(take.seek(SeekFrom::Start(2))?, 2); + take.read_exact(&mut buf2)?; + assert_eq!(buf2, [b'4', b'5']); + assert_eq!(take.seek(SeekFrom::Start(3))?, 3); + take.read_exact(&mut buf1)?; + assert_eq!(buf1, [b'5']); + assert_eq!(take.seek(SeekFrom::Start(4))?, 4); + assert_eq!(take.read(&mut buf1)?, 0); + + assert_eq!(take.seek(SeekFrom::End(0))?, 4); + assert_eq!(take.seek(SeekFrom::End(-1))?, 3); + take.read_exact(&mut buf1)?; + assert_eq!(buf1, [b'5']); + assert_eq!(take.seek(SeekFrom::End(-2))?, 2); + take.read_exact(&mut buf2)?; + assert_eq!(buf2, [b'4', b'5']); + assert_eq!(take.seek(SeekFrom::End(-3))?, 1); + take.read_exact(&mut buf2)?; + assert_eq!(buf2, [b'3', b'4']); + assert_eq!(take.seek(SeekFrom::End(-4))?, 0); + take.read_exact(&mut buf2)?; + assert_eq!(buf2, [b'2', b'3']); + + assert_eq!(take.seek(SeekFrom::Current(0))?, 2); + take.read_exact(&mut buf2)?; + assert_eq!(buf2, [b'4', b'5']); + + assert_eq!(take.seek(SeekFrom::Current(-3))?, 1); + take.read_exact(&mut buf2)?; + assert_eq!(buf2, [b'3', b'4']); + + assert_eq!(take.seek(SeekFrom::Current(-1))?, 2); + take.read_exact(&mut buf2)?; + assert_eq!(buf2, [b'4', b'5']); + + assert_eq!(take.seek(SeekFrom::Current(-4))?, 0); + take.read_exact(&mut buf2)?; + assert_eq!(buf2, [b'2', b'3']); + + assert_eq!(take.seek(SeekFrom::Current(2))?, 4); + assert_eq!(take.read(&mut buf1)?, 0); + + Ok(()) +} + +#[test] +fn take_seek_error() { + let buf = Cursor::new(b"0123456789"); + let mut take = buf.take(2); + assert!(take.seek(SeekFrom::Start(3)).is_err()); + assert!(take.seek(SeekFrom::End(1)).is_err()); + assert!(take.seek(SeekFrom::End(-3)).is_err()); + assert!(take.seek(SeekFrom::Current(-1)).is_err()); + assert!(take.seek(SeekFrom::Current(3)).is_err()); +} + +struct ExampleHugeRangeOfZeroes { + position: u64, +} + +impl Read for ExampleHugeRangeOfZeroes { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let max = buf.len().min(usize::MAX); + for i in 0..max { + if self.position == u64::MAX { + return Ok(i); + } + self.position += 1; + buf[i] = 0; + } + Ok(max) + } +} + +impl Seek for ExampleHugeRangeOfZeroes { + fn seek(&mut self, pos: io::SeekFrom) -> io::Result { + match pos { + io::SeekFrom::Start(i) => self.position = i, + io::SeekFrom::End(i) if i >= 0 => self.position = u64::MAX, + io::SeekFrom::End(i) => self.position = self.position - i.unsigned_abs(), + io::SeekFrom::Current(i) => { + self.position = if i >= 0 { + self.position.saturating_add(i.unsigned_abs()) + } else { + self.position.saturating_sub(i.unsigned_abs()) + }; + } + } + Ok(self.position) + } +} + +#[test] +fn take_seek_big_offsets() -> io::Result<()> { + let inner = ExampleHugeRangeOfZeroes { position: 1 }; + let mut take = inner.take(u64::MAX - 2); + assert_eq!(take.seek(io::SeekFrom::Start(u64::MAX - 2))?, u64::MAX - 2); + assert_eq!(take.inner.position, u64::MAX - 1); + assert_eq!(take.seek(io::SeekFrom::Start(0))?, 0); + assert_eq!(take.inner.position, 1); + assert_eq!(take.seek(io::SeekFrom::End(-1))?, u64::MAX - 3); + assert_eq!(take.inner.position, u64::MAX - 2); + Ok(()) +} + // A simple example reader which uses the default implementation of // read_to_end. struct ExampleSliceReader<'a> { diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index ca04a381271b2..ef41b47384d61 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -325,6 +325,7 @@ #![feature(try_blocks)] #![feature(try_trait_v2)] #![feature(type_alias_impl_trait)] +#![feature(unsigned_signed_diff)] // tidy-alphabetical-end // // Library features (core): From e2b1de107f2fa687254e818b5287c6c6614726b9 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Mon, 19 May 2025 17:52:20 +0200 Subject: [PATCH 2464/4206] Access items through `rustc_session` instead of `rustc_lint_defs` Items such as the `declare_tool_lint!()` macro are publicly reexported from `rustc_lint_defs` to `rustc_session`. Use the latter for consistency. --- clippy_lints_internal/src/almost_standard_lint_formulation.rs | 3 +-- clippy_lints_internal/src/collapsible_calls.rs | 3 +-- .../src/derive_deserialize_allowing_unknown.rs | 3 +-- clippy_lints_internal/src/lib.rs | 1 - clippy_lints_internal/src/lint_without_lint_pass.rs | 3 +-- clippy_lints_internal/src/msrv_attr_impl.rs | 3 +-- clippy_lints_internal/src/outer_expn_data_pass.rs | 3 +-- clippy_lints_internal/src/produce_ice.rs | 3 +-- clippy_lints_internal/src/symbols.rs | 3 +-- clippy_lints_internal/src/unnecessary_def_path.rs | 2 +- clippy_lints_internal/src/unsorted_clippy_utils_paths.rs | 3 +-- 11 files changed, 10 insertions(+), 20 deletions(-) diff --git a/clippy_lints_internal/src/almost_standard_lint_formulation.rs b/clippy_lints_internal/src/almost_standard_lint_formulation.rs index 4fd5ea459a554..311f76fee6b8b 100644 --- a/clippy_lints_internal/src/almost_standard_lint_formulation.rs +++ b/clippy_lints_internal/src/almost_standard_lint_formulation.rs @@ -3,8 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use regex::Regex; use rustc_hir::{Attribute, Item, ItemKind, Mutability}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_lint_defs::declare_tool_lint; -use rustc_session::impl_lint_pass; +use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_tool_lint! { /// ### What it does diff --git a/clippy_lints_internal/src/collapsible_calls.rs b/clippy_lints_internal/src/collapsible_calls.rs index 407deb45db0a7..7c9e7286925ef 100644 --- a/clippy_lints_internal/src/collapsible_calls.rs +++ b/clippy_lints_internal/src/collapsible_calls.rs @@ -4,8 +4,7 @@ use clippy_utils::{SpanlessEq, is_lint_allowed, peel_blocks_with_stmt}; use rustc_errors::Applicability; use rustc_hir::{Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_lint_defs::declare_tool_lint; -use rustc_session::declare_lint_pass; +use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; use std::borrow::{Borrow, Cow}; diff --git a/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs b/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs index a1dacd359a06c..ad6214fb52a28 100644 --- a/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs +++ b/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs @@ -8,9 +8,8 @@ use rustc_hir::{ AttrArgs, AttrItem, AttrPath, Attribute, HirId, Impl, Item, ItemKind, Path, QPath, TraitRef, Ty, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_lint_defs::declare_tool_lint; use rustc_middle::ty::TyCtxt; -use rustc_session::declare_lint_pass; +use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; declare_tool_lint! { diff --git a/clippy_lints_internal/src/lib.rs b/clippy_lints_internal/src/lib.rs index 43cde86504f5c..ba7263f290812 100644 --- a/clippy_lints_internal/src/lib.rs +++ b/clippy_lints_internal/src/lib.rs @@ -25,7 +25,6 @@ extern crate rustc_data_structures; extern crate rustc_errors; extern crate rustc_hir; extern crate rustc_lint; -extern crate rustc_lint_defs; extern crate rustc_middle; extern crate rustc_session; extern crate rustc_span; diff --git a/clippy_lints_internal/src/lint_without_lint_pass.rs b/clippy_lints_internal/src/lint_without_lint_pass.rs index 655d8fb8d1bfb..0edeef3ab8559 100644 --- a/clippy_lints_internal/src/lint_without_lint_pass.rs +++ b/clippy_lints_internal/src/lint_without_lint_pass.rs @@ -10,9 +10,8 @@ use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_hir::intravisit::Visitor; use rustc_hir::{ExprKind, HirId, Item, MutTy, Mutability, Path, TyKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_lint_defs::declare_tool_lint; use rustc_middle::hir::nested_filter; -use rustc_session::impl_lint_pass; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Spanned; use rustc_span::symbol::Symbol; use rustc_span::{Span, sym}; diff --git a/clippy_lints_internal/src/msrv_attr_impl.rs b/clippy_lints_internal/src/msrv_attr_impl.rs index d48d8dc57b240..441c688485236 100644 --- a/clippy_lints_internal/src/msrv_attr_impl.rs +++ b/clippy_lints_internal/src/msrv_attr_impl.rs @@ -4,9 +4,8 @@ use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_lint_defs::declare_tool_lint; use rustc_middle::ty::{self, EarlyBinder, GenericArgKind}; -use rustc_session::declare_lint_pass; +use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_tool_lint! { /// ### What it does diff --git a/clippy_lints_internal/src/outer_expn_data_pass.rs b/clippy_lints_internal/src/outer_expn_data_pass.rs index 40951443a48a9..1d0b61ede48b3 100644 --- a/clippy_lints_internal/src/outer_expn_data_pass.rs +++ b/clippy_lints_internal/src/outer_expn_data_pass.rs @@ -4,8 +4,7 @@ use clippy_utils::{is_lint_allowed, method_calls}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_lint_defs::declare_tool_lint; -use rustc_session::declare_lint_pass; +use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Symbol; declare_tool_lint! { diff --git a/clippy_lints_internal/src/produce_ice.rs b/clippy_lints_internal/src/produce_ice.rs index 14e93dc6d5f13..3a813b4b9a223 100644 --- a/clippy_lints_internal/src/produce_ice.rs +++ b/clippy_lints_internal/src/produce_ice.rs @@ -1,8 +1,7 @@ use rustc_ast::ast::NodeId; use rustc_ast::visit::FnKind; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_lint_defs::declare_tool_lint; -use rustc_session::declare_lint_pass; +use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; declare_tool_lint! { diff --git a/clippy_lints_internal/src/symbols.rs b/clippy_lints_internal/src/symbols.rs index 5aee545fb0f5b..7b5d58824c38f 100644 --- a/clippy_lints_internal/src/symbols.rs +++ b/clippy_lints_internal/src/symbols.rs @@ -6,10 +6,9 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind, Lit, Node, Pat, PatExprKind, PatKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_lint_defs::declare_tool_lint; use rustc_middle::mir::ConstValue; use rustc_middle::ty; -use rustc_session::impl_lint_pass; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::Symbol; use rustc_span::{Span, sym}; diff --git a/clippy_lints_internal/src/unnecessary_def_path.rs b/clippy_lints_internal/src/unnecessary_def_path.rs index 8877f1faf0ee8..1850d428f0916 100644 --- a/clippy_lints_internal/src/unnecessary_def_path.rs +++ b/clippy_lints_internal/src/unnecessary_def_path.rs @@ -5,8 +5,8 @@ use clippy_utils::{path_def_id, peel_ref_operators}; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_lint_defs::{declare_lint_pass, declare_tool_lint}; use rustc_middle::mir::ConstValue; +use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Symbol; declare_tool_lint! { diff --git a/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs b/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs index 8e281ecb2ee44..2d478fa04af8e 100644 --- a/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs +++ b/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs @@ -1,8 +1,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Crate, ItemKind, ModKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_lint_defs::declare_tool_lint; -use rustc_session::declare_lint_pass; +use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_tool_lint! { /// ### What it does From 608f6822cabc8bbe9459e746262263513db5d1cf Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Mon, 19 May 2025 18:07:52 +0200 Subject: [PATCH 2465/4206] `cargo dev fmt`: format `clippy_lints_internal` as well --- clippy_dev/src/fmt.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index 298326174a48c..e43b2d7a5b3c0 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -247,6 +247,7 @@ fn run_rustfmt(clippy: &ClippyInfo, update_mode: UpdateMode) { "clippy_config", "clippy_dev", "clippy_lints", + "clippy_lints_internal", "clippy_utils", "rustc_tools_util", "lintcheck", From 8ecb128a2241dfe45ff27ce9765fd7653c6d50ad Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 19 May 2025 22:02:37 +0530 Subject: [PATCH 2466/4206] trim cache module in utils --- src/bootstrap/src/utils/cache.rs | 30 -------------------------- src/bootstrap/src/utils/cache/tests.rs | 20 ----------------- 2 files changed, 50 deletions(-) diff --git a/src/bootstrap/src/utils/cache.rs b/src/bootstrap/src/utils/cache.rs index 1c8cc4025df11..46eeffad88c38 100644 --- a/src/bootstrap/src/utils/cache.rs +++ b/src/bootstrap/src/utils/cache.rs @@ -20,7 +20,6 @@ use std::collections::HashMap; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::ops::Deref; -use std::path::PathBuf; use std::sync::{LazyLock, Mutex}; use std::{fmt, mem}; @@ -51,26 +50,11 @@ impl PartialEq for Interned { } impl Eq for Interned {} -impl PartialEq for Interned { - fn eq(&self, other: &str) -> bool { - *self == other - } -} impl PartialEq<&str> for Interned { fn eq(&self, other: &&str) -> bool { **self == **other } } -impl PartialEq<&Interned> for Interned { - fn eq(&self, other: &&Self) -> bool { - self.0 == other.0 - } -} -impl PartialEq> for &Interned { - fn eq(&self, other: &Interned) -> bool { - self.0 == other.0 - } -} unsafe impl Send for Interned {} unsafe impl Sync for Interned {} @@ -188,8 +172,6 @@ impl TyIntern { #[derive(Default)] pub struct Interner { strs: Mutex>, - paths: Mutex>, - lists: Mutex>>, } /// Defines the behavior required for a type to be internable. @@ -210,18 +192,6 @@ impl Internable for String { } } -impl Internable for PathBuf { - fn intern_cache() -> &'static Mutex> { - &INTERNER.paths - } -} - -impl Internable for Vec { - fn intern_cache() -> &'static Mutex> { - &INTERNER.lists - } -} - impl Interner { /// Interns a string reference, ensuring it is stored uniquely. /// diff --git a/src/bootstrap/src/utils/cache/tests.rs b/src/bootstrap/src/utils/cache/tests.rs index 28f5563a589b1..8562a35b3e06b 100644 --- a/src/bootstrap/src/utils/cache/tests.rs +++ b/src/bootstrap/src/utils/cache/tests.rs @@ -12,26 +12,6 @@ fn test_string_interning() { assert_ne!(s1, s3, "Different strings should have different interned values"); } -#[test] -fn test_path_interning() { - let p1 = PathBuf::from("/tmp/file").intern(); - let p2 = PathBuf::from("/tmp/file").intern(); - let p3 = PathBuf::from("/tmp/other").intern(); - - assert_eq!(p1, p2); - assert_ne!(p1, p3); -} - -#[test] -fn test_vec_interning() { - let v1 = vec!["a".to_string(), "b".to_string()].intern(); - let v2 = vec!["a".to_string(), "b".to_string()].intern(); - let v3 = vec!["c".to_string()].intern(); - - assert_eq!(v1, v2); - assert_ne!(v1, v3); -} - #[test] fn test_interned_equality() { let s1 = INTERNER.intern_str("test"); From 7600453bd5afdd46d8e414a4ef325754d9bbfdac Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Mon, 19 May 2025 19:01:24 +0200 Subject: [PATCH 2467/4206] Update books --- src/doc/book | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/book b/src/doc/book index d33916341d480..230c68bc1e08f 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit d33916341d480caede1d0ae57cbeae23aab23e88 +Subproject commit 230c68bc1e08f5f3228384a28cc228c81dfbd10d diff --git a/src/doc/reference b/src/doc/reference index 387392674d746..acd0231ebc748 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 387392674d74656f7cb437c05a96f0c52ea8e601 +Subproject commit acd0231ebc74849f6a8907b5e646ce86721aad76 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 8a8918c698534..c9d151f9147c4 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 8a8918c698534547fa8a1a693cb3e7277f0bfb2f +Subproject commit c9d151f9147c4808c77f0375ba3fa5d54443cb9e From db1ac980818078ce3fb49b8cf0607464126da199 Mon Sep 17 00:00:00 2001 From: Josh Gunter <59844337+jagunter@users.noreply.github.com> Date: Sun, 18 May 2025 14:23:53 -0700 Subject: [PATCH 2468/4206] Fixed possible ICE in annotate_mut_binding_to_immutable_binding --- compiler/rustc_hir_typeck/src/demand.rs | 14 +++++----- tests/crashes/140823.rs | 9 ------- tests/ui/fn/coerce-suggestion-infer-region.rs | 26 +++++++++++++++++++ .../fn/coerce-suggestion-infer-region.stderr | 12 +++++++++ 4 files changed, 46 insertions(+), 15 deletions(-) delete mode 100644 tests/crashes/140823.rs create mode 100644 tests/ui/fn/coerce-suggestion-infer-region.rs create mode 100644 tests/ui/fn/coerce-suggestion-infer-region.stderr diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index d1bc54ed73ead..8182851a015bf 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -84,7 +84,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.annotate_expected_due_to_let_ty(err, expr, error); self.annotate_loop_expected_due_to_inference(err, expr, error); - if self.annotate_mut_binding_to_immutable_binding(err, expr, error) { + if self.annotate_mut_binding_to_immutable_binding(err, expr, expr_ty, expected, error) { return; } @@ -799,17 +799,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Detect the following case /// /// ```text - /// fn change_object(mut a: &Ty) { + /// fn change_object(mut b: &Ty) { /// let a = Ty::new(); /// b = a; /// } /// ``` /// - /// where the user likely meant to modify the value behind there reference, use `a` as an out + /// where the user likely meant to modify the value behind there reference, use `b` as an out /// parameter, instead of mutating the local binding. When encountering this we suggest: /// /// ```text - /// fn change_object(a: &'_ mut Ty) { + /// fn change_object(b: &'_ mut Ty) { /// let a = Ty::new(); /// *b = a; /// } @@ -818,13 +818,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, err: &mut Diag<'_>, expr: &hir::Expr<'_>, + expr_ty: Ty<'tcx>, + expected: Ty<'tcx>, error: Option>, ) -> bool { - if let Some(TypeError::Sorts(ExpectedFound { expected, found })) = error + if let Some(TypeError::Sorts(ExpectedFound { .. })) = error && let ty::Ref(_, inner, hir::Mutability::Not) = expected.kind() // The difference between the expected and found values is one level of borrowing. - && self.can_eq(self.param_env, *inner, found) + && self.can_eq(self.param_env, *inner, expr_ty) // We have an `ident = expr;` assignment. && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(lhs, rhs, _), .. }) = diff --git a/tests/crashes/140823.rs b/tests/crashes/140823.rs deleted file mode 100644 index ca2d683beedb2..0000000000000 --- a/tests/crashes/140823.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ known-bug: #140823 - -struct Container { - data: T, -} - -fn ice(callback: Box)>) { - let fails: Box)> = callback; -} diff --git a/tests/ui/fn/coerce-suggestion-infer-region.rs b/tests/ui/fn/coerce-suggestion-infer-region.rs new file mode 100644 index 0000000000000..7edb828c97339 --- /dev/null +++ b/tests/ui/fn/coerce-suggestion-infer-region.rs @@ -0,0 +1,26 @@ +//! Functions with a mismatch between the expected and found type where the difference is a +//! reference may trigger analysis for additional help. In this test the expected type will be +//! &'a Container<&'a u8> and the found type will be Container<&'?0 u8>. +//! +//! This test exercises a scenario where the found type being analyzed contains an inference region +//! variable ('?0). This cannot be used in comparisons because the variable no longer exists by the +//! time the later analysis is performed. +//! +//! This is a regression test of #140823 + +trait MyFn

{} + +struct Container { + data: T, +} + +struct Desugared { + callback: Box MyFn<&'a Container<&'a u8>>>, +} + +fn test(callback: Box MyFn>>) -> Desugared { + Desugared { callback } + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/fn/coerce-suggestion-infer-region.stderr b/tests/ui/fn/coerce-suggestion-infer-region.stderr new file mode 100644 index 0000000000000..9dd0fcf76ce19 --- /dev/null +++ b/tests/ui/fn/coerce-suggestion-infer-region.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/coerce-suggestion-infer-region.rs:22:17 + | +LL | Desugared { callback } + | ^^^^^^^^ expected `Box>>`, found `Box>>` + | + = note: expected struct `Box<(dyn for<'a> MyFn<&'a Container<&'a u8>> + 'static)>` + found struct `Box<(dyn for<'a> MyFn> + 'static)>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. From c99c4b17b2a28f4056cbd460bfbf8cb27bc0be64 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 19 May 2025 20:20:34 +0200 Subject: [PATCH 2469/4206] current_dll_path: fix mistake in assertion message --- compiler/rustc_session/src/filesearch.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index cb3e9c80a131d..92f1bd8ab7367 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -82,7 +82,7 @@ fn current_dll_path() -> Result { let fname_ptr = info.dli_fname.as_ptr(); #[cfg(not(target_os = "cygwin"))] let fname_ptr = { - assert!(!info.dli_fname.is_null(), "the docs do not allow dladdr to be null"); + assert!(!info.dli_fname.is_null(), "dli_fname cannot be null"); info.dli_fname }; let bytes = CStr::from_ptr(fname_ptr).to_bytes(); From 9478598fc907e54d3df3f167620ef1aaaec233a1 Mon Sep 17 00:00:00 2001 From: nora <48135649+Noratrieb@users.noreply.github.com> Date: Mon, 19 May 2025 21:02:25 +0200 Subject: [PATCH 2470/4206] Properly remove Noratrieb from review rotation I've put myself on vacation a while ago, but really I just want to remove myself from the queue because I couldn't get around to reviewing all the PRs, I'm still here and available :3. --- triagebot.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index 3afa2d364109e..e62e49b90fbbb 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1171,7 +1171,6 @@ contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" users_on_vacation = [ "fmease", "jyn514", - "Noratrieb", "spastorino", ] @@ -1198,7 +1197,6 @@ compiler = [ "@lcnr", "@Nadrieril", "@nnethercote", - "@Noratrieb", "@oli-obk", "@petrochenkov", "@SparrowLii", @@ -1206,7 +1204,6 @@ compiler = [ ] libs = [ "@Mark-Simulacrum", - "@Noratrieb", "@workingjubilee", "@joboet", "@jhpratt", From bb724f34215ca54c0a82deadf20342d881af99d3 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sun, 18 May 2025 18:46:15 +0200 Subject: [PATCH 2471/4206] Sort the existing list of symbols --- clippy_utils/src/sym.rs | 98 +++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index 9428262b99aa7..4e1e573ad9026 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -29,26 +29,62 @@ macro_rules! generate { }; } +// List of extra symbols to be included in Clippy (for example, as `sym::ambiguous_glob_reexports`). +// An alternative content can be specified using a colon after the symbol name. generate! { + AsyncReadExt, + AsyncWriteExt, + BACKSLASH_SINGLE_QUOTE: r"\'", + Binary, + CLIPPY_ARGS, + CLIPPY_CONF_DIR, + CRLF: "\r\n", + Cargo_toml: "Cargo.toml", + Current, + DOUBLE_QUOTE: "\"", + Deserialize, + EarlyLintPass, + ErrorKind, + IntoIter, + Itertools, + LF: "\n", + Lazy, + Lint, + LowerExp, + LowerHex, + MAX, + MIN, + MsrvStack, + Octal, + OpenOptions, + Other, + PathLookup, + Regex, + RegexBuilder, + RegexSet, + Start, + Step, + Symbol, + SyntaxContext, + TBD, + UpperExp, + UpperHex, + V4, + V6, + Visitor, + Weak, abs, align_of, ambiguous_glob_reexports, as_bytes, - as_deref_mut, as_deref, + as_deref_mut, as_mut, - AsyncReadExt, - AsyncWriteExt, - BACKSLASH_SINGLE_QUOTE: r"\'", - Binary, build_hasher, bytes, cargo_clippy: "cargo-clippy", - Cargo_toml: "Cargo.toml", cast, chars, - CLIPPY_ARGS, - CLIPPY_CONF_DIR, clippy_utils, clone_into, cloned, @@ -56,26 +92,20 @@ generate! { const_ptr, contains, copied, - CRLF: "\r\n", - Current, de, - Deserialize, diagnostics, disallowed_types, - DOUBLE_QUOTE: "\"", - EarlyLintPass, ends_with, enum_glob_use, error, - ErrorKind, exp, extend, - finish_non_exhaustive, finish, + finish_non_exhaustive, flat_map, for_each, - from_bytes_with_nul_unchecked, from_bytes_with_nul, + from_bytes_with_nul_unchecked, from_ptr, from_raw, from_ref, @@ -89,7 +119,6 @@ generate! { int_roundings, into_bytes, into_owned, - IntoIter, io, is_ascii, is_empty, @@ -98,56 +127,40 @@ generate! { is_ok, is_some, itertools, - Itertools, kw, last, lazy_static, - Lazy, - LF: "\n", - Lint, ln, lock_api, log, - LowerExp, - LowerHex, macro_use_imports, - map_or_else, map_or, + map_or_else, max, - MAX, mem, min, - MIN, mode, module_name_repetitions, msrv, msrvs, - MsrvStack, mut_ptr, mutex, needless_return, next_tuple, - Octal, once_cell, - OpenOptions, or_default, - Other, parse, - PathLookup, paths, powf, powi, push, redundant_pub_crate, regex, - Regex, - RegexBuilder, - RegexSet, reserve, resize, restriction, - rustc_lint_defs, rustc_lint, + rustc_lint_defs, rustc_span, rustfmt_skip, rwlock, @@ -158,17 +171,12 @@ generate! { signum, single_component_path_imports, span_lint_and_then, - split_whitespace, split, + split_whitespace, sqrt, - Start, - Step, style, symbol, - Symbol, - SyntaxContext, take, - TBD, then_some, to_ascii_lowercase, to_ascii_uppercase, @@ -179,21 +187,15 @@ generate! { tokio, unreachable_pub, unsafe_removed_from_name, + unused, unused_braces, unused_extern_crates, unused_import_braces, unused_trait_names, - unused, unwrap_err, unwrap_or_default, unwrap_or_else, - UpperExp, - UpperHex, - V4, - V6, - Visitor, warnings, - Weak, wildcard_imports, with_capacity, wrapping_offset, From 82bf659dc80a1ab4da1b473206131f4d70a41ea9 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sun, 18 May 2025 18:20:53 +0200 Subject: [PATCH 2472/4206] Ensure that symbols list stays sorted --- clippy_dev/src/fmt.rs | 39 +++++++++++++++++++++++++++++++++++++-- clippy_utils/src/sym.rs | 2 ++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index e43b2d7a5b3c0..13d6b1285dcdb 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -1,6 +1,9 @@ -use crate::utils::{ClippyInfo, ErrAction, UpdateMode, panic_action, run_with_args_split, run_with_output}; +use crate::utils::{ + ClippyInfo, ErrAction, FileUpdater, UpdateMode, UpdateStatus, panic_action, run_with_args_split, run_with_output, +}; use itertools::Itertools; use rustc_lexer::{TokenKind, tokenize}; +use std::fmt::Write; use std::fs; use std::io::{self, Read}; use std::ops::ControlFlow; @@ -225,6 +228,38 @@ fn fmt_conf(check: bool) -> Result<(), Error> { Ok(()) } +/// Format the symbols list +fn fmt_syms(update_mode: UpdateMode) { + FileUpdater::default().update_file_checked( + "cargo dev fmt", + update_mode, + "clippy_utils/src/sym.rs", + &mut |_, text: &str, new_text: &mut String| { + let (pre, conf) = text.split_once("generate! {\n").expect("can't find generate! call"); + let (conf, post) = conf.split_once("\n}\n").expect("can't find end of generate! call"); + let mut lines = conf + .lines() + .map(|line| { + let line = line.trim(); + line.strip_suffix(',').unwrap_or(line).trim_end() + }) + .collect::>(); + lines.sort_unstable(); + write!( + new_text, + "{pre}generate! {{\n {},\n}}\n{post}", + lines.join(",\n "), + ) + .unwrap(); + if text == new_text { + UpdateStatus::Unchanged + } else { + UpdateStatus::Changed + } + }, + ); +} + fn run_rustfmt(clippy: &ClippyInfo, update_mode: UpdateMode) { let mut rustfmt_path = String::from_utf8(run_with_output( "rustup which rustfmt", @@ -337,7 +372,7 @@ pub fn run(clippy: &ClippyInfo, update_mode: UpdateMode) { return; } run_rustfmt(clippy, update_mode); - + fmt_syms(update_mode); if let Err(e) = fmt_conf(update_mode.is_check()) { e.display(); process::exit(1); diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index 4e1e573ad9026..a5f0e9562c9ef 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -31,6 +31,8 @@ macro_rules! generate { // List of extra symbols to be included in Clippy (for example, as `sym::ambiguous_glob_reexports`). // An alternative content can be specified using a colon after the symbol name. +// +// `cargo dev fmt` ensures that the content of the `generate!()` macro call stays sorted. generate! { AsyncReadExt, AsyncWriteExt, From e16801e68c8d3fef6edcbeabd60cd535754ec017 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sun, 18 May 2025 16:05:12 +0200 Subject: [PATCH 2473/4206] Use symbols instead of `&str` when possible --- .../src/assertions_on_result_states.rs | 9 +- .../src/casts/cast_possible_truncation.rs | 4 +- clippy_lints/src/casts/cast_sign_loss.rs | 27 +- .../casts/confusing_method_to_numeric_cast.rs | 15 +- clippy_lints/src/casts/ptr_cast_constness.rs | 9 +- clippy_lints/src/cognitive_complexity.rs | 8 +- clippy_lints/src/doc/missing_headers.rs | 3 +- clippy_lints/src/explicit_write.rs | 8 +- clippy_lints/src/fallible_impl_from.rs | 2 +- clippy_lints/src/floating_point_arithmetic.rs | 54 +-- clippy_lints/src/index_refutable_slice.rs | 4 +- clippy_lints/src/ineffective_open_options.rs | 10 +- clippy_lints/src/infinite_iter.rs | 85 ++-- clippy_lints/src/lines_filter_map_ok.rs | 18 +- .../src/loops/char_indices_as_byte_indices.rs | 38 +- clippy_lints/src/loops/mod.rs | 10 +- clippy_lints/src/manual_is_power_of_two.rs | 4 +- clippy_lints/src/map_unit_fn.rs | 2 +- clippy_lints/src/matches/mod.rs | 6 +- clippy_lints/src/matches/redundant_guards.rs | 14 +- .../src/matches/redundant_pattern_match.rs | 2 +- .../matches/significant_drop_in_scrutinee.rs | 4 +- clippy_lints/src/methods/bytes_nth.rs | 3 +- clippy_lints/src/methods/chars_cmp.rs | 3 +- .../src/methods/chars_cmp_with_unwrap.rs | 3 +- clippy_lints/src/methods/chars_last_cmp.rs | 5 +- .../src/methods/chars_last_cmp_with_unwrap.rs | 17 +- clippy_lints/src/methods/chars_next_cmp.rs | 3 +- .../src/methods/chars_next_cmp_with_unwrap.rs | 9 +- .../src/methods/collapsible_str_replace.rs | 6 +- clippy_lints/src/methods/expect_fun_call.rs | 6 +- clippy_lints/src/methods/extend_with_drain.rs | 4 +- clippy_lints/src/methods/implicit_clone.rs | 16 +- .../src/methods/iter_cloned_collect.rs | 9 +- clippy_lints/src/methods/iter_count.rs | 4 +- clippy_lints/src/methods/iter_kv_map.rs | 10 +- clippy_lints/src/methods/iter_nth.rs | 8 +- .../iter_on_single_or_empty_collections.rs | 11 +- .../src/methods/iter_overeager_cloned.rs | 4 +- .../src/methods/manual_c_str_literals.rs | 2 +- clippy_lints/src/methods/manual_inspect.rs | 10 +- clippy_lints/src/methods/map_identity.rs | 4 +- clippy_lints/src/methods/mod.rs | 415 +++++++++--------- clippy_lints/src/methods/needless_as_bytes.rs | 4 +- .../src/methods/needless_option_as_deref.rs | 8 +- .../src/methods/needless_option_take.rs | 10 +- .../src/methods/obfuscated_if_else.rs | 19 +- .../src/methods/option_as_ref_cloned.rs | 6 +- clippy_lints/src/methods/or_fun_call.rs | 25 +- clippy_lints/src/methods/search_is_some.rs | 11 +- clippy_lints/src/methods/str_split.rs | 2 +- clippy_lints/src/methods/str_splitn.rs | 18 +- .../src/methods/string_extend_chars.rs | 4 +- clippy_lints/src/methods/suspicious_splitn.rs | 3 +- .../src/methods/unnecessary_filter_map.rs | 20 +- .../src/methods/unnecessary_literal_unwrap.rs | 29 +- .../src/methods/unnecessary_min_or_max.rs | 9 +- .../src/methods/unnecessary_to_owned.rs | 10 +- clippy_lints/src/methods/useless_asref.rs | 6 +- .../src/methods/wrong_self_convention.rs | 7 +- clippy_lints/src/needless_bool.rs | 4 +- clippy_lints/src/needless_pass_by_value.rs | 10 +- clippy_lints/src/operators/duration_subsec.rs | 8 +- clippy_lints/src/option_env_unwrap.rs | 2 +- .../src/significant_drop_tightening.rs | 6 +- clippy_lints/src/size_of_in_element_count.rs | 27 +- .../src/slow_vector_initialization.rs | 4 +- clippy_lints/src/string_patterns.rs | 52 +-- clippy_lints/src/strlen_on_c_strings.rs | 5 +- clippy_lints/src/unused_peekable.rs | 9 +- clippy_lints/src/unused_rounding.rs | 11 +- clippy_lints/src/unwrap_in_result.rs | 4 +- clippy_lints/src/useless_conversion.rs | 6 +- clippy_lints/src/utils/author.rs | 4 +- clippy_lints/src/utils/dump_hir.rs | 4 +- clippy_lints/src/vec.rs | 8 +- .../src/outer_expn_data_pass.rs | 6 +- .../src/unsorted_clippy_utils_paths.rs | 5 +- clippy_utils/src/attrs.rs | 40 +- clippy_utils/src/consts.rs | 6 +- clippy_utils/src/eager_or_lazy.rs | 6 +- clippy_utils/src/higher.rs | 2 +- clippy_utils/src/lib.rs | 16 +- clippy_utils/src/macros.rs | 20 +- clippy_utils/src/ptr.rs | 12 +- clippy_utils/src/sym.rs | 154 +++++++ 86 files changed, 857 insertions(+), 653 deletions(-) diff --git a/clippy_lints/src/assertions_on_result_states.rs b/clippy_lints/src/assertions_on_result_states.rs index c073dee855e20..6f2a6a36a38b7 100644 --- a/clippy_lints/src/assertions_on_result_states.rs +++ b/clippy_lints/src/assertions_on_result_states.rs @@ -3,14 +3,13 @@ use clippy_utils::macros::{PanicExpn, find_assert_args, root_macro_call_first_no use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{has_debug_impl, is_copy, is_type_diagnostic_item}; use clippy_utils::usage::local_used_after_expr; -use clippy_utils::{is_expr_final_block_expr, path_res}; +use clippy_utils::{is_expr_final_block_expr, path_res, sym}; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -68,11 +67,11 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { return; } } - let (message, replacement) = match method_segment.ident.as_str() { - "is_ok" if type_suitable_to_unwrap(cx, args.type_at(1)) => { + let (message, replacement) = match method_segment.ident.name { + sym::is_ok if type_suitable_to_unwrap(cx, args.type_at(1)) => { ("called `assert!` with `Result::is_ok`", "unwrap") }, - "is_err" if type_suitable_to_unwrap(cx, args.type_at(0)) => { + sym::is_err if type_suitable_to_unwrap(cx, args.type_at(0)) => { ("called `assert!` with `Result::is_err`", "unwrap_err") }, _ => return, diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index e92879b853d7b..4120e5c8cb7d0 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -56,7 +56,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b if signed { return nbits; } - let max_bits = if method.ident.as_str() == "min" { + let max_bits = if method.ident.name == sym::min { get_constant_bits(cx, right) } else { None @@ -64,7 +64,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::MAX)) }, ExprKind::MethodCall(method, _, [lo, hi], _) => { - if method.ident.as_str() == "clamp" + if method.ident.name == sym::clamp //FIXME: make this a diagnostic item && let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi)) { diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs index c8abf9dac9af5..9a1ad8a747386 100644 --- a/clippy_lints/src/casts/cast_sign_loss.rs +++ b/clippy_lints/src/casts/cast_sign_loss.rs @@ -4,10 +4,11 @@ use std::ops::ControlFlow; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::visitors::{Descend, for_each_expr_without_closures}; -use clippy_utils::{method_chain_args, sext}; +use clippy_utils::{method_chain_args, sext, sym}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; +use rustc_span::Symbol; use super::CAST_SIGN_LOSS; @@ -16,24 +17,24 @@ use super::CAST_SIGN_LOSS; /// /// Methods that can overflow and return a negative value must not be included in this list, /// because casting their return values can still result in sign loss. -const METHODS_RET_POSITIVE: &[&str] = &[ - "checked_abs", - "saturating_abs", - "isqrt", - "checked_isqrt", - "rem_euclid", - "checked_rem_euclid", - "wrapping_rem_euclid", +const METHODS_RET_POSITIVE: &[Symbol] = &[ + sym::checked_abs, + sym::saturating_abs, + sym::isqrt, + sym::checked_isqrt, + sym::rem_euclid, + sym::checked_rem_euclid, + sym::wrapping_rem_euclid, ]; /// A list of methods that act like `pow()`. See `pow_call_result_sign()` for details. /// /// Methods that can overflow and return a negative value must not be included in this list, /// because casting their return values can still result in sign loss. -const METHODS_POW: &[&str] = &["pow", "saturating_pow", "checked_pow"]; +const METHODS_POW: &[Symbol] = &[sym::pow, sym::saturating_pow, sym::checked_pow]; /// A list of methods that act like `unwrap()`, and don't change the sign of the inner value. -const METHODS_UNWRAP: &[&str] = &["unwrap", "unwrap_unchecked", "expect", "into_ok"]; +const METHODS_UNWRAP: &[Symbol] = &[sym::unwrap, sym::unwrap_unchecked, sym::expect, sym::into_ok]; pub(super) fn check<'cx>( cx: &LateContext<'cx>, @@ -129,7 +130,7 @@ fn expr_sign<'cx, 'tcx>(cx: &LateContext<'cx>, mut expr: &'tcx Expr<'tcx>, ty: i // Calling on methods that always return non-negative values. if let ExprKind::MethodCall(path, caller, args, ..) = expr.kind { - let mut method_name = path.ident.name.as_str(); + let mut method_name = path.ident.name; // Peel unwrap(), expect(), etc. while let Some(&found_name) = METHODS_UNWRAP.iter().find(|&name| &method_name == name) @@ -138,7 +139,7 @@ fn expr_sign<'cx, 'tcx>(cx: &LateContext<'cx>, mut expr: &'tcx Expr<'tcx>, ty: i { // The original type has changed, but we can't use `ty` here anyway, because it has been // moved. - method_name = inner_path.ident.name.as_str(); + method_name = inner_path.ident.name; expr = recv; } diff --git a/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs b/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs index 31cdd078f45a0..769cc120c9504 100644 --- a/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs +++ b/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs @@ -1,11 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sym; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, GenericArg, Ty}; +use rustc_span::Symbol; use rustc_span::def_id::DefId; -use rustc_span::{Symbol, sym}; use super::CONFUSING_METHOD_TO_NUMERIC_CAST; @@ -25,7 +26,6 @@ fn get_const_name_and_ty_name( method_def_id: DefId, generics: &[GenericArg<'_>], ) -> Option<(&'static str, &'static str)> { - let method_name = method_name.as_str(); let diagnostic_name = cx.tcx.get_diagnostic_name(method_def_id); let ty_name = if diagnostic_name.is_some_and(|diag| diag == sym::cmp_ord_min || diag == sym::cmp_ord_max) { @@ -39,14 +39,21 @@ fn get_const_name_and_ty_name( } } else if let Some(impl_id) = cx.tcx.impl_of_method(method_def_id) && let Some(ty_name) = get_primitive_ty_name(cx.tcx.type_of(impl_id).instantiate_identity()) - && ["min", "max", "minimum", "maximum", "min_value", "max_value"].contains(&method_name) + && matches!( + method_name, + sym::min | sym::max | sym::minimum | sym::maximum | sym::min_value | sym::max_value + ) { ty_name } else { return None; }; - let const_name = if method_name.starts_with("max") { "MAX" } else { "MIN" }; + let const_name = if matches!(method_name, sym::max | sym::maximum | sym::max_value) { + "MAX" + } else { + "MIN" + }; Some((const_name, ty_name)) } diff --git a/clippy_lints/src/casts/ptr_cast_constness.rs b/clippy_lints/src/casts/ptr_cast_constness.rs index 2471c7355518b..c0c0a47f85515 100644 --- a/clippy_lints/src/casts/ptr_cast_constness.rs +++ b/clippy_lints/src/casts/ptr_cast_constness.rs @@ -1,12 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::std_or_core; use clippy_utils::sugg::Sugg; +use clippy_utils::{std_or_core, sym}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Mutability, QPath}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; -use rustc_span::sym; use super::PTR_CAST_CONSTNESS; @@ -78,9 +77,9 @@ pub(super) fn check_null_ptr_cast_method(cx: &LateContext<'_>, expr: &Expr<'_>) && let ExprKind::Call(func, []) = cast_expr.kind && let ExprKind::Path(QPath::Resolved(None, path)) = func.kind && let Some(defid) = path.res.opt_def_id() - && let method = match (cx.tcx.get_diagnostic_name(defid), method.ident.as_str()) { - (Some(sym::ptr_null), "cast_mut") => "null_mut", - (Some(sym::ptr_null_mut), "cast_const") => "null", + && let method = match (cx.tcx.get_diagnostic_name(defid), method.ident.name) { + (Some(sym::ptr_null), sym::cast_mut) => "null_mut", + (Some(sym::ptr_null_mut), sym::cast_const) => "null", _ => return, } && let Some(prefix) = std_or_core(cx) diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index aeb53a52cf3d5..5c64216dd92ca 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -3,14 +3,14 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::{IntoSpan, SpanRangeExt}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::for_each_expr_without_closures; -use clippy_utils::{LimitStack, get_async_fn_body, is_async_fn}; +use clippy_utils::{LimitStack, get_async_fn_body, is_async_fn, sym}; use core::ops::ControlFlow; use rustc_hir::intravisit::FnKind; use rustc_hir::{Attribute, Body, Expr, ExprKind, FnDecl}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; +use rustc_span::Span; use rustc_span::def_id::LocalDefId; -use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -157,9 +157,9 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity { } fn check_attributes(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) { - self.limit.push_attrs(cx.sess(), attrs, "cognitive_complexity"); + self.limit.push_attrs(cx.sess(), attrs, sym::cognitive_complexity); } fn check_attributes_post(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) { - self.limit.pop_attrs(cx.sess(), attrs, "cognitive_complexity"); + self.limit.pop_attrs(cx.sess(), attrs, sym::cognitive_complexity); } } diff --git a/clippy_lints/src/doc/missing_headers.rs b/clippy_lints/src/doc/missing_headers.rs index 039937e0207b0..9ee32fced8c44 100644 --- a/clippy_lints/src/doc/missing_headers.rs +++ b/clippy_lints/src/doc/missing_headers.rs @@ -113,7 +113,8 @@ fn find_panic(cx: &LateContext<'_>, body_id: BodyId) -> Option { } // check for `unwrap` and `expect` for both `Option` and `Result` - if let Some(arglists) = method_chain_args(expr, &["unwrap"]).or_else(|| method_chain_args(expr, &["expect"])) + if let Some(arglists) = + method_chain_args(expr, &[sym::unwrap]).or_else(|| method_chain_args(expr, &[sym::expect])) && let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs() && matches!( get_type_diagnostic_name(cx, receiver_ty), diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index a5a4e05b3a6d2..085ee4448a4ee 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::{FormatArgsStorage, format_args_inputs_span}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_expn_of, path_def_id}; +use clippy_utils::{is_expn_of, path_def_id, sym}; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{BindingMode, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::{ExpnId, sym}; +use rustc_span::ExpnId; declare_clippy_lint! { /// ### What it does @@ -72,9 +72,9 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { }; // ordering is important here, since `writeln!` uses `write!` internally - let calling_macro = if is_expn_of(write_call.span, "writeln").is_some() { + let calling_macro = if is_expn_of(write_call.span, sym::writeln).is_some() { Some("writeln") - } else if is_expn_of(write_call.span, "write").is_some() { + } else if is_expn_of(write_call.span, sym::write).is_some() { Some("write") } else { None diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index c868b782f43c3..68d0cd19c8a69 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -82,7 +82,7 @@ fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::Impl } // check for `unwrap` - if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { + if let Some(arglists) = method_chain_args(expr, &[sym::unwrap]) { let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs(); if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option) || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result) diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index e653a57196d61..3c7e83b069726 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -294,8 +294,8 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: && let Some(parent) = get_parent_expr(cx, expr) { if let Some(grandparent) = get_parent_expr(cx, parent) - && let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = grandparent.kind - && method_name.as_str() == "sqrt" + && let ExprKind::MethodCall(PathSegment { ident: method, .. }, receiver, ..) = grandparent.kind + && method.name == sym::sqrt && detect_hypot(cx, receiver).is_some() { return; @@ -375,24 +375,10 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option { } // check if expression of the form x.powi(2) + y.powi(2) - if let ExprKind::MethodCall( - PathSegment { - ident: lmethod_name, .. - }, - largs_0, - [largs_1, ..], - _, - ) = &add_lhs.kind - && let ExprKind::MethodCall( - PathSegment { - ident: rmethod_name, .. - }, - rargs_0, - [rargs_1, ..], - _, - ) = &add_rhs.kind - && lmethod_name.as_str() == "powi" - && rmethod_name.as_str() == "powi" + if let ExprKind::MethodCall(PathSegment { ident: lmethod, .. }, largs_0, [largs_1, ..], _) = &add_lhs.kind + && let ExprKind::MethodCall(PathSegment { ident: rmethod, .. }, rargs_0, [rargs_1, ..], _) = &add_rhs.kind + && lmethod.name == sym::powi + && rmethod.name == sym::powi && let ecx = ConstEvalCtxt::new(cx) && let Some(lvalue) = ecx.eval(largs_1) && let Some(rvalue) = ecx.eval(rargs_1) @@ -482,8 +468,8 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) { ) = &expr.kind { if let Some(parent) = get_parent_expr(cx, expr) - && let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = parent.kind - && method_name.as_str() == "sqrt" + && let ExprKind::MethodCall(PathSegment { ident: method, .. }, receiver, ..) = parent.kind + && method.name == sym::sqrt && detect_hypot(cx, receiver).is_some() { return; @@ -623,27 +609,13 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) { } fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool { - if let ExprKind::MethodCall( - PathSegment { - ident: method_name_a, .. - }, - _, - args_a, - _, - ) = expr_a.kind - && let ExprKind::MethodCall( - PathSegment { - ident: method_name_b, .. - }, - _, - args_b, - _, - ) = expr_b.kind + if let ExprKind::MethodCall(PathSegment { ident: method_a, .. }, _, args_a, _) = expr_a.kind + && let ExprKind::MethodCall(PathSegment { ident: method_b, .. }, _, args_b, _) = expr_b.kind { - return method_name_a.as_str() == method_name_b.as_str() + return method_a.name == method_b.name && args_a.len() == args_b.len() - && (["ln", "log2", "log10"].contains(&method_name_a.as_str()) - || method_name_a.as_str() == "log" && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0])); + && (matches!(method_a.name, sym::ln | sym::log2 | sym::log10) + || method_a.name == sym::log && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0])); } false diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index 989997d69f7c7..0b1cae30ca501 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::IfLet; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::is_copy; -use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local}; +use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local, sym}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::Applicability; use rustc_hir as hir; @@ -72,7 +72,7 @@ impl_lint_pass!(IndexRefutableSlice => [INDEX_REFUTABLE_SLICE]); impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { if let Some(IfLet { let_pat, if_then, .. }) = IfLet::hir(cx, expr) - && (!expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some()) + && (!expr.span.from_expansion() || is_expn_of(expr.span, sym::if_chain).is_some()) && !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id) && let found_slices = find_slice_values(cx, let_pat) && !found_slices.is_empty() diff --git a/clippy_lints/src/ineffective_open_options.rs b/clippy_lints/src/ineffective_open_options.rs index 3a28553b55e25..7a751514b6476 100644 --- a/clippy_lints/src/ineffective_open_options.rs +++ b/clippy_lints/src/ineffective_open_options.rs @@ -1,13 +1,13 @@ use crate::methods::method_call; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::peel_blocks; +use clippy_utils::{peel_blocks, sym}; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{BytePos, Span, sym}; +use rustc_span::{BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -57,7 +57,7 @@ fn index_if_arg_is_boolean(args: &[Expr<'_>], call_span: Span) -> Option { impl<'tcx> LateLintPass<'tcx> for IneffectiveOpenOptions { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let Some(("open", mut receiver, [_arg], _, _)) = method_call(expr) else { + let Some((sym::open, mut receiver, [_arg], _, _)) = method_call(expr) else { return; }; let receiver_ty = cx.typeck_results().expr_ty(receiver); @@ -70,9 +70,9 @@ impl<'tcx> LateLintPass<'tcx> for IneffectiveOpenOptions { let mut write = None; while let Some((name, recv, args, _, span)) = method_call(receiver) { - if name == "append" { + if name == sym::append { append = index_if_arg_is_boolean(args, span); - } else if name == "write" { + } else if name == sym::write { write = index_if_arg_is_boolean(args, span); } receiver = recv; diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index c4e10837bf192..bf3eafe09b3d0 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -4,6 +4,7 @@ use clippy_utils::{higher, sym}; use rustc_hir::{BorrowKind, Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; +use rustc_span::Symbol; declare_clippy_lint! { /// ### What it does @@ -119,33 +120,33 @@ use self::Heuristic::{All, Always, Any, First}; /// returns an infinite or possibly infinite iterator. The finiteness /// is an upper bound, e.g., some methods can return a possibly /// infinite iterator at worst, e.g., `take_while`. -const HEURISTICS: [(&str, usize, Heuristic, Finiteness); 19] = [ - ("zip", 1, All, Infinite), - ("chain", 1, Any, Infinite), - ("cycle", 0, Always, Infinite), - ("map", 1, First, Infinite), - ("by_ref", 0, First, Infinite), - ("cloned", 0, First, Infinite), - ("rev", 0, First, Infinite), - ("inspect", 0, First, Infinite), - ("enumerate", 0, First, Infinite), - ("peekable", 1, First, Infinite), - ("fuse", 0, First, Infinite), - ("skip", 1, First, Infinite), - ("skip_while", 0, First, Infinite), - ("filter", 1, First, Infinite), - ("filter_map", 1, First, Infinite), - ("flat_map", 1, First, Infinite), - ("unzip", 0, First, Infinite), - ("take_while", 1, First, MaybeInfinite), - ("scan", 2, First, MaybeInfinite), +const HEURISTICS: [(Symbol, usize, Heuristic, Finiteness); 19] = [ + (sym::zip, 1, All, Infinite), + (sym::chain, 1, Any, Infinite), + (sym::cycle, 0, Always, Infinite), + (sym::map, 1, First, Infinite), + (sym::by_ref, 0, First, Infinite), + (sym::cloned, 0, First, Infinite), + (sym::rev, 0, First, Infinite), + (sym::inspect, 0, First, Infinite), + (sym::enumerate, 0, First, Infinite), + (sym::peekable, 1, First, Infinite), + (sym::fuse, 0, First, Infinite), + (sym::skip, 1, First, Infinite), + (sym::skip_while, 0, First, Infinite), + (sym::filter, 1, First, Infinite), + (sym::filter_map, 1, First, Infinite), + (sym::flat_map, 1, First, Infinite), + (sym::unzip, 0, First, Infinite), + (sym::take_while, 1, First, MaybeInfinite), + (sym::scan, 2, First, MaybeInfinite), ]; fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { match expr.kind { ExprKind::MethodCall(method, receiver, args, _) => { for &(name, len, heuristic, cap) in &HEURISTICS { - if method.ident.name.as_str() == name && args.len() == len { + if method.ident.name == name && args.len() == len { return (match heuristic { Always => Infinite, First => is_infinite(cx, receiver), @@ -183,36 +184,36 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { /// the names and argument lengths of methods that *may* exhaust their /// iterators -const POSSIBLY_COMPLETING_METHODS: [(&str, usize); 6] = [ - ("find", 1), - ("rfind", 1), - ("position", 1), - ("rposition", 1), - ("any", 1), - ("all", 1), +const POSSIBLY_COMPLETING_METHODS: [(Symbol, usize); 6] = [ + (sym::find, 1), + (sym::rfind, 1), + (sym::position, 1), + (sym::rposition, 1), + (sym::any, 1), + (sym::all, 1), ]; /// the names and argument lengths of methods that *always* exhaust /// their iterators -const COMPLETING_METHODS: [(&str, usize); 12] = [ - ("count", 0), - ("fold", 2), - ("for_each", 1), - ("partition", 1), - ("max", 0), - ("max_by", 1), - ("max_by_key", 1), - ("min", 0), - ("min_by", 1), - ("min_by_key", 1), - ("sum", 0), - ("product", 0), +const COMPLETING_METHODS: [(Symbol, usize); 12] = [ + (sym::count, 0), + (sym::fold, 2), + (sym::for_each, 1), + (sym::partition, 1), + (sym::max, 0), + (sym::max_by, 1), + (sym::max_by_key, 1), + (sym::min, 0), + (sym::min_by, 1), + (sym::min_by_key, 1), + (sym::sum, 0), + (sym::product, 0), ]; fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { match expr.kind { ExprKind::MethodCall(method, receiver, args, _) => { - let method_str = method.ident.name.as_str(); + let method_str = method.ident.name; for &(name, len) in &COMPLETING_METHODS { if method_str == name && args.len() == len { return is_infinite(cx, receiver); diff --git a/clippy_lints/src/lines_filter_map_ok.rs b/clippy_lints/src/lines_filter_map_ok.rs index d8af44233d3ee..14ccb6fce2239 100644 --- a/clippy_lints/src/lines_filter_map_ok.rs +++ b/clippy_lints/src/lines_filter_map_ok.rs @@ -2,12 +2,12 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_diag_item_method, is_trait_method, path_to_local_id}; +use clippy_utils::{is_diag_item_method, is_trait_method, path_to_local_id, sym}; use rustc_errors::Applicability; use rustc_hir::{Body, Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::sym; +use rustc_span::Symbol; pub struct LinesFilterMapOk { msrv: Msrv, @@ -74,17 +74,17 @@ impl LateLintPass<'_> for LinesFilterMapOk { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::MethodCall(fm_method, fm_receiver, fm_args, fm_span) = expr.kind && is_trait_method(cx, expr, sym::Iterator) - && let fm_method_str = fm_method.ident.as_str() - && matches!(fm_method_str, "filter_map" | "flat_map" | "flatten") + && let fm_method_name = fm_method.ident.name + && matches!(fm_method_name, sym::filter_map | sym::flat_map | sym::flatten) && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), sym::IoLines) - && should_lint(cx, fm_args, fm_method_str) + && should_lint(cx, fm_args, fm_method_name) && self.msrv.meets(cx, msrvs::MAP_WHILE) { span_lint_and_then( cx, LINES_FILTER_MAP_OK, fm_span, - format!("`{fm_method_str}()` will run forever if the iterator repeatedly produces an `Err`",), + format!("`{fm_method_name}()` will run forever if the iterator repeatedly produces an `Err`",), |diag| { diag.span_note( fm_receiver.span, @@ -101,9 +101,9 @@ impl LateLintPass<'_> for LinesFilterMapOk { } } -fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_str: &str) -> bool { +fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_name: Symbol) -> bool { match args { - [] => method_str == "flatten", + [] => method_name == sym::flatten, [fm_arg] => { match &fm_arg.kind { // Detect `Result::ok` @@ -120,7 +120,7 @@ fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_str: &str) -> boo && path_to_local_id(receiver, param.pat.hir_id) && let Some(method_did) = cx.typeck_results().type_dependent_def_id(value.hir_id) { - is_diag_item_method(cx, method_did, sym::Result) && method.ident.as_str() == "ok" + is_diag_item_method(cx, method_did, sym::Result) && method.ident.name == sym::ok } else { false } diff --git a/clippy_lints/src/loops/char_indices_as_byte_indices.rs b/clippy_lints/src/loops/char_indices_as_byte_indices.rs index 8916454ada16e..a702e60f1c276 100644 --- a/clippy_lints/src/loops/char_indices_as_byte_indices.rs +++ b/clippy_lints/src/loops/char_indices_as_byte_indices.rs @@ -3,12 +3,12 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::ty::is_type_lang_item; use clippy_utils::visitors::for_each_expr; -use clippy_utils::{eq_expr_value, higher, path_to_local_id}; +use clippy_utils::{eq_expr_value, higher, path_to_local_id, sym}; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::{Expr, ExprKind, LangItem, Node, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; -use rustc_span::{Span, sym}; +use rustc_span::{Span, Symbol}; use super::CHAR_INDICES_AS_BYTE_INDICES; @@ -16,22 +16,22 @@ use super::CHAR_INDICES_AS_BYTE_INDICES; // Note: `String` also has methods that work with byte indices, // but they all take `&mut self` and aren't worth considering since the user couldn't have called // them while the chars iterator is live anyway. -const BYTE_INDEX_METHODS: &[&str] = &[ - "is_char_boundary", - "floor_char_boundary", - "ceil_char_boundary", - "get", - "index", - "index_mut", - "get_mut", - "get_unchecked", - "get_unchecked_mut", - "slice_unchecked", - "slice_mut_unchecked", - "split_at", - "split_at_mut", - "split_at_checked", - "split_at_mut_checked", +const BYTE_INDEX_METHODS: &[Symbol] = &[ + sym::ceil_char_boundary, + sym::floor_char_boundary, + sym::get, + sym::get_mut, + sym::get_unchecked, + sym::get_unchecked_mut, + sym::index, + sym::index_mut, + sym::is_char_boundary, + sym::slice_mut_unchecked, + sym::slice_unchecked, + sym::split_at, + sym::split_at_checked, + sym::split_at_mut, + sym::split_at_mut_checked, ]; const CONTINUE: ControlFlow = ControlFlow::Continue(()); @@ -88,7 +88,7 @@ fn check_index_usage<'tcx>( // (contrary to the `ExprKind::Index` case which needs to handle both with `is_string_like` because `String` implements // `Index` directly and no deref to `str` would happen in that case). if cx.typeck_results().expr_ty_adjusted(recv).peel_refs().is_str() - && BYTE_INDEX_METHODS.contains(&segment.ident.name.as_str()) + && BYTE_INDEX_METHODS.contains(&segment.ident.name) && eq_expr_value(cx, chars_recv, recv) => { "passing a character position to a method that expects a byte index" diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 56d2bef2305a7..22cab317e3d24 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -25,8 +25,8 @@ mod while_let_loop; mod while_let_on_iterator; use clippy_config::Conf; -use clippy_utils::higher; use clippy_utils::msrvs::Msrv; +use clippy_utils::{higher, sym}; use rustc_ast::Label; use rustc_hir::{Expr, ExprKind, LoopSource, Pat}; use rustc_lint::{LateContext, LateLintPass}; @@ -910,14 +910,14 @@ impl Loops { fn check_for_loop_arg(&self, cx: &LateContext<'_>, _: &Pat<'_>, arg: &Expr<'_>) { if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind { - match method.ident.as_str() { - "iter" | "iter_mut" => { + match method.ident.name { + sym::iter | sym::iter_mut => { explicit_iter_loop::check(cx, self_arg, arg, self.msrv, self.enforce_iter_loop_reborrow); }, - "into_iter" => { + sym::into_iter => { explicit_into_iter_loop::check(cx, self_arg, arg); }, - "next" => { + sym::next => { iter_next_loop::check(cx, arg); }, _ => {}, diff --git a/clippy_lints/src/manual_is_power_of_two.rs b/clippy_lints/src/manual_is_power_of_two.rs index b4cd988329d32..4439a28763a2f 100644 --- a/clippy_lints/src/manual_is_power_of_two.rs +++ b/clippy_lints/src/manual_is_power_of_two.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::ty_from_hir_ty; -use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal}; +use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal, sym}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; @@ -103,7 +103,7 @@ fn count_ones_receiver<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Optio } else { return None; }; - (method.ident.as_str() == "count_ones" && matches!(ty.kind(), ty::Uint(_))).then_some(receiver) + (method.ident.name == sym::count_ones && matches!(ty.kind(), ty::Uint(_))).then_some(receiver) } /// Return `greater` if `smaller == greater - 1` diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index b607f8117eb89..af6a1b07a4929 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -255,7 +255,7 @@ impl LateLintPass<'_> for MapUnit { fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) { if let hir::StmtKind::Semi(expr) = stmt.kind && !stmt.span.from_expansion() - && let Some(arglists) = method_chain_args(expr, &["map"]) + && let Some(arglists) = method_chain_args(expr, &[sym::map]) { lint_map_unit_fn(cx, stmt, expr, arglists[0]); } diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index c6ebd6144c76f..c128fc40b7334 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -28,7 +28,7 @@ use clippy_config::Conf; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::walk_span_to_context; use clippy_utils::{ - higher, is_direct_expn_of, is_in_const_context, is_span_match, span_contains_cfg, span_extract_comments, + higher, is_direct_expn_of, is_in_const_context, is_span_match, span_contains_cfg, span_extract_comments, sym, }; use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -1053,13 +1053,13 @@ impl_lint_pass!(Matches => [ impl<'tcx> LateLintPass<'tcx> for Matches { #[expect(clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if is_direct_expn_of(expr.span, "matches").is_none() && expr.span.in_external_macro(cx.sess().source_map()) { + if is_direct_expn_of(expr.span, sym::matches).is_none() && expr.span.in_external_macro(cx.sess().source_map()) { return; } let from_expansion = expr.span.from_expansion(); if let ExprKind::Match(ex, arms, source) = expr.kind { - if is_direct_expn_of(expr.span, "matches").is_some() + if is_direct_expn_of(expr.span, sym::matches).is_some() && let [arm, _] = arms { redundant_pattern_match::check_match(cx, expr, ex, arms); diff --git a/clippy_lints/src/matches/redundant_guards.rs b/clippy_lints/src/matches/redundant_guards.rs index 9bbef8da0a466..7c6d45e424006 100644 --- a/clippy_lints/src/matches/redundant_guards.rs +++ b/clippy_lints/src/matches/redundant_guards.rs @@ -3,14 +3,14 @@ use clippy_utils::macros::matching_root_macro_call; use clippy_utils::msrvs::Msrv; use clippy_utils::source::snippet; use clippy_utils::visitors::{for_each_expr_without_closures, is_local_used}; -use clippy_utils::{is_in_const_context, path_to_local}; +use clippy_utils::{is_in_const_context, path_to_local, sym}; use rustc_ast::{BorrowKind, LitKind}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, MatchSource, Node, PatKind, UnOp}; use rustc_lint::LateContext; use rustc_span::symbol::Ident; -use rustc_span::{Span, sym}; +use rustc_span::{Span, Symbol}; use std::borrow::Cow; use std::ops::ControlFlow; @@ -95,7 +95,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv: } else if let ExprKind::MethodCall(path, recv, args, ..) = guard.kind && let Some(binding) = get_pat_binding(cx, recv, outer_arm) { - check_method_calls(cx, outer_arm, path.ident.name.as_str(), recv, args, guard, &binding); + check_method_calls(cx, outer_arm, path.ident.name, recv, args, guard, &binding); } } } @@ -103,7 +103,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv: fn check_method_calls<'tcx>( cx: &LateContext<'tcx>, arm: &Arm<'tcx>, - method: &str, + method: Symbol, recv: &Expr<'_>, args: &[Expr<'_>], if_expr: &Expr<'_>, @@ -112,7 +112,7 @@ fn check_method_calls<'tcx>( let ty = cx.typeck_results().expr_ty(recv).peel_refs(); let slice_like = ty.is_slice() || ty.is_array(); - let sugg = if method == "is_empty" { + let sugg = if method == sym::is_empty { // `s if s.is_empty()` becomes "" // `arr if arr.is_empty()` becomes [] @@ -137,9 +137,9 @@ fn check_method_calls<'tcx>( if needles.is_empty() { sugg.insert_str(1, ".."); - } else if method == "starts_with" { + } else if method == sym::starts_with { sugg.insert_str(sugg.len() - 1, ", .."); - } else if method == "ends_with" { + } else if method == sym::ends_with { sugg.insert_str(1, ".., "); } else { return; diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index db20be40f27ea..aa9be61bf4d43 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -273,7 +273,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind); if let Some((good_method, maybe_guard)) = found_good_method(cx, arms, node_pair) { - let span = is_expn_of(expr.span, "matches").unwrap_or(expr.span.to(op.span)); + let span = is_expn_of(expr.span, sym::matches).unwrap_or(expr.span.to(op.span)); let result_expr = match &op.kind { ExprKind::AddrOf(_, _, borrowed) => borrowed, _ => op, diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index d7dc7604088f7..0f3ad40784d36 100644 --- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -4,7 +4,7 @@ use crate::FxHashSet; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{first_line_of_span, indent_of, snippet}; use clippy_utils::ty::{for_each_top_level_late_bound_region, is_copy}; -use clippy_utils::{get_attr, is_lint_allowed}; +use clippy_utils::{get_attr, is_lint_allowed, sym}; use itertools::Itertools; use rustc_ast::Mutability; use rustc_data_structures::fx::FxIndexSet; @@ -186,7 +186,7 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> { && get_attr( self.cx.sess(), self.cx.tcx.get_attrs_unchecked(adt.did()), - "has_significant_drop", + sym::has_significant_drop, ) .count() > 0 diff --git a/clippy_lints/src/methods/bytes_nth.rs b/clippy_lints/src/methods/bytes_nth.rs index de22514c37c66..02fc09170e59c 100644 --- a/clippy_lints/src/methods/bytes_nth.rs +++ b/clippy_lints/src/methods/bytes_nth.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sym; use clippy_utils::ty::is_type_lang_item; use rustc_errors::Applicability; use rustc_hir::{Expr, LangItem}; @@ -25,7 +26,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E if let Some(parent) = clippy_utils::get_parent_expr(cx, expr) && let Some((name, _, _, _, _)) = method_call(parent) - && name == "unwrap" + && name == sym::unwrap { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/chars_cmp.rs b/clippy_lints/src/methods/chars_cmp.rs index 4ae0aeea2d1c5..de27a45ba4d92 100644 --- a/clippy_lints/src/methods/chars_cmp.rs +++ b/clippy_lints/src/methods/chars_cmp.rs @@ -5,12 +5,13 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, Lint}; use rustc_middle::ty; +use rustc_span::Symbol; /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints. pub(super) fn check( cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>, - chain_methods: &[&str], + chain_methods: &[Symbol], lint: &'static Lint, suggest: &str, ) -> bool { diff --git a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs index 9c45ec2e56cbe..1c72a973cfa13 100644 --- a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs +++ b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs @@ -5,12 +5,13 @@ use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, Lint}; +use rustc_span::Symbol; /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`. pub(super) fn check( cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>, - chain_methods: &[&str], + chain_methods: &[Symbol], lint: &'static Lint, suggest: &str, ) -> bool { diff --git a/clippy_lints/src/methods/chars_last_cmp.rs b/clippy_lints/src/methods/chars_last_cmp.rs index 2efff4c3c5497..8729e91d191f8 100644 --- a/clippy_lints/src/methods/chars_last_cmp.rs +++ b/clippy_lints/src/methods/chars_last_cmp.rs @@ -1,13 +1,14 @@ use crate::methods::chars_cmp; +use clippy_utils::sym; use rustc_lint::LateContext; use super::CHARS_LAST_CMP; /// Checks for the `CHARS_LAST_CMP` lint. pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { - if chars_cmp::check(cx, info, &["chars", "last"], CHARS_LAST_CMP, "ends_with") { + if chars_cmp::check(cx, info, &[sym::chars, sym::last], CHARS_LAST_CMP, "ends_with") { true } else { - chars_cmp::check(cx, info, &["chars", "next_back"], CHARS_LAST_CMP, "ends_with") + chars_cmp::check(cx, info, &[sym::chars, sym::next_back], CHARS_LAST_CMP, "ends_with") } } diff --git a/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs b/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs index 5b8713f7d7903..027d0a3947bfb 100644 --- a/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs +++ b/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs @@ -1,13 +1,26 @@ use crate::methods::chars_cmp_with_unwrap; +use clippy_utils::sym; use rustc_lint::LateContext; use super::CHARS_LAST_CMP; /// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`. pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { - if chars_cmp_with_unwrap::check(cx, info, &["chars", "last", "unwrap"], CHARS_LAST_CMP, "ends_with") { + if chars_cmp_with_unwrap::check( + cx, + info, + &[sym::chars, sym::last, sym::unwrap], + CHARS_LAST_CMP, + "ends_with", + ) { true } else { - chars_cmp_with_unwrap::check(cx, info, &["chars", "next_back", "unwrap"], CHARS_LAST_CMP, "ends_with") + chars_cmp_with_unwrap::check( + cx, + info, + &[sym::chars, sym::next_back, sym::unwrap], + CHARS_LAST_CMP, + "ends_with", + ) } } diff --git a/clippy_lints/src/methods/chars_next_cmp.rs b/clippy_lints/src/methods/chars_next_cmp.rs index b631fecab9729..2438843bf3ab1 100644 --- a/clippy_lints/src/methods/chars_next_cmp.rs +++ b/clippy_lints/src/methods/chars_next_cmp.rs @@ -1,8 +1,9 @@ +use clippy_utils::sym; use rustc_lint::LateContext; use super::CHARS_NEXT_CMP; /// Checks for the `CHARS_NEXT_CMP` lint. pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { - crate::methods::chars_cmp::check(cx, info, &["chars", "next"], CHARS_NEXT_CMP, "starts_with") + crate::methods::chars_cmp::check(cx, info, &[sym::chars, sym::next], CHARS_NEXT_CMP, "starts_with") } diff --git a/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs b/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs index caf21d3ff3bcb..9b3609f19d724 100644 --- a/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs +++ b/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs @@ -1,8 +1,15 @@ +use clippy_utils::sym; use rustc_lint::LateContext; use super::CHARS_NEXT_CMP; /// Checks for the `CHARS_NEXT_CMP` lint with `unwrap()`. pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { - crate::methods::chars_cmp_with_unwrap::check(cx, info, &["chars", "next", "unwrap"], CHARS_NEXT_CMP, "starts_with") + crate::methods::chars_cmp_with_unwrap::check( + cx, + info, + &[sym::chars, sym::next, sym::unwrap], + CHARS_NEXT_CMP, + "starts_with", + ) } diff --git a/clippy_lints/src/methods/collapsible_str_replace.rs b/clippy_lints/src/methods/collapsible_str_replace.rs index f7bf8764bdebc..6d0b944df55d6 100644 --- a/clippy_lints/src/methods/collapsible_str_replace.rs +++ b/clippy_lints/src/methods/collapsible_str_replace.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::visitors::for_each_expr_without_closures; -use clippy_utils::{eq_expr_value, get_parent_expr}; +use clippy_utils::{eq_expr_value, get_parent_expr, sym}; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir as hir; @@ -22,7 +22,7 @@ pub(super) fn check<'tcx>( // If the parent node's `to` argument is the same as the `to` argument // of the last replace call in the current chain, don't lint as it was already linted if let Some(parent) = get_parent_expr(cx, expr) - && let Some(("replace", _, [current_from, current_to], _, _)) = method_call(parent) + && let Some((sym::replace, _, [current_from, current_to], _, _)) = method_call(parent) && eq_expr_value(cx, to, current_to) && from_kind == cx.typeck_results().expr_ty(current_from).peel_refs().kind() { @@ -47,7 +47,7 @@ fn collect_replace_calls<'tcx>( let mut from_args = VecDeque::new(); let _: Option<()> = for_each_expr_without_closures(expr, |e| { - if let Some(("replace", _, [from, to], _, _)) = method_call(e) { + if let Some((sym::replace, _, [from, to], _, _)) = method_call(e) { if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() { methods.push_front(e); from_args.push_front(from); diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index f5688e370a478..82e5a6d5a4120 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -6,8 +6,8 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::Span; use rustc_span::symbol::sym; +use rustc_span::{Span, Symbol}; use std::borrow::Cow; use super::EXPECT_FUN_CALL; @@ -19,7 +19,7 @@ pub(super) fn check<'tcx>( format_args_storage: &FormatArgsStorage, expr: &hir::Expr<'_>, method_span: Span, - name: &str, + name: Symbol, receiver: &'tcx hir::Expr<'tcx>, args: &'tcx [hir::Expr<'tcx>], ) { @@ -114,7 +114,7 @@ pub(super) fn check<'tcx>( } } - if args.len() != 1 || name != "expect" || !is_call(&args[0].kind) { + if args.len() != 1 || name != sym::expect || !is_call(&args[0].kind) { return; } diff --git a/clippy_lints/src/methods/extend_with_drain.rs b/clippy_lints/src/methods/extend_with_drain.rs index 460ec7b3640a6..db60061904f6f 100644 --- a/clippy_lints/src/methods/extend_with_drain.rs +++ b/clippy_lints/src/methods/extend_with_drain.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sym; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::LateContext; -use rustc_span::symbol::sym; use super::EXTEND_WITH_DRAIN; @@ -13,7 +13,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: if is_type_diagnostic_item(cx, ty, sym::Vec) //check source object && let ExprKind::MethodCall(src_method, drain_vec, [drain_arg], _) = &arg.kind - && src_method.ident.as_str() == "drain" + && src_method.ident.name == sym::drain && let src_ty = cx.typeck_results().expr_ty(drain_vec) //check if actual src type is mutable for code suggestion && let immutable = src_ty.is_mutable_ptr() diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs index 519091406ccf3..9724463f0c084 100644 --- a/clippy_lints/src/methods/implicit_clone.rs +++ b/clippy_lints/src/methods/implicit_clone.rs @@ -1,15 +1,15 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::implements_trait; -use clippy_utils::{is_diag_item_method, is_diag_trait_item, peel_middle_ty_refs}; +use clippy_utils::{is_diag_item_method, is_diag_trait_item, peel_middle_ty_refs, sym}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::sym; +use rustc_span::Symbol; use super::IMPLICIT_CLONE; -pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { +pub fn check(cx: &LateContext<'_>, method_name: Symbol, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && is_clone_like(cx, method_name, method_def_id) && let return_type = cx.typeck_results().expr_ty(expr) @@ -43,12 +43,12 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv /// Note that `to_string` is not flagged by `implicit_clone`. So other lints that call /// `is_clone_like` and that do flag `to_string` must handle it separately. See, e.g., /// `is_to_owned_like` in `unnecessary_to_owned.rs`. -pub fn is_clone_like(cx: &LateContext<'_>, method_name: &str, method_def_id: hir::def_id::DefId) -> bool { +pub fn is_clone_like(cx: &LateContext<'_>, method_name: Symbol, method_def_id: hir::def_id::DefId) -> bool { match method_name { - "to_os_string" => is_diag_item_method(cx, method_def_id, sym::OsStr), - "to_owned" => is_diag_trait_item(cx, method_def_id, sym::ToOwned), - "to_path_buf" => is_diag_item_method(cx, method_def_id, sym::Path), - "to_vec" => cx + sym::to_os_string => is_diag_item_method(cx, method_def_id, sym::OsStr), + sym::to_owned => is_diag_trait_item(cx, method_def_id, sym::ToOwned), + sym::to_path_buf => is_diag_item_method(cx, method_def_id, sym::Path), + sym::to_vec => cx .tcx .impl_of_method(method_def_id) .filter(|&impl_did| { diff --git a/clippy_lints/src/methods/iter_cloned_collect.rs b/clippy_lints/src/methods/iter_cloned_collect.rs index 17cc07b91c5da..b4ab313fe98d1 100644 --- a/clippy_lints/src/methods/iter_cloned_collect.rs +++ b/clippy_lints/src/methods/iter_cloned_collect.rs @@ -5,11 +5,16 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::sym; +use rustc_span::{Symbol, sym}; use super::ITER_CLONED_COLLECT; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, method_name: &str, expr: &hir::Expr<'_>, recv: &'tcx hir::Expr<'_>) { +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + method_name: Symbol, + expr: &hir::Expr<'_>, + recv: &'tcx hir::Expr<'_>, +) { let expr_ty = cx.typeck_results().expr_ty(expr); if is_type_diagnostic_item(cx, expr_ty, sym::Vec) && let Some(slice) = derefs_to_slice(cx, recv, cx.typeck_results().expr_ty(recv)) diff --git a/clippy_lints/src/methods/iter_count.rs b/clippy_lints/src/methods/iter_count.rs index 209cf2fcc0a44..6b64cc8b50ae7 100644 --- a/clippy_lints/src/methods/iter_count.rs +++ b/clippy_lints/src/methods/iter_count.rs @@ -5,11 +5,11 @@ use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_span::sym; +use rustc_span::{Symbol, sym}; use super::ITER_COUNT; -pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, iter_method: &str) { +pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, iter_method: Symbol) { let ty = cx.typeck_results().expr_ty(recv); let caller_type = if derefs_to_slice(cx, recv, ty).is_some() { "slice" diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index 3ac9299ba9157..c88462129af02 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -1,12 +1,12 @@ use super::ITER_KV_MAP; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::pat_is_wild; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{pat_is_wild, sym}; use rustc_hir::{Body, Expr, ExprKind, PatKind}; use rustc_lint::LateContext; -use rustc_span::sym; +use rustc_span::Symbol; /// lint use of: /// @@ -16,13 +16,13 @@ use rustc_span::sym; /// on `HashMaps` and `BTreeMaps` in std pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, - map_type: &'tcx str, // iter / into_iter + map_type: Symbol, // iter / into_iter expr: &'tcx Expr<'tcx>, // .iter().map(|(_, v_| v)) recv: &'tcx Expr<'tcx>, // hashmap m_arg: &'tcx Expr<'tcx>, // |(_, v)| v msrv: Msrv, ) { - if map_type == "into_iter" && !msrv.meets(cx, msrvs::INTO_KEYS) { + if map_type == sym::into_iter && !msrv.meets(cx, msrvs::INTO_KEYS) { return; } if !expr.span.from_expansion() @@ -42,7 +42,7 @@ pub(super) fn check<'tcx>( { let mut applicability = rustc_errors::Applicability::MachineApplicable; let recv_snippet = snippet_with_applicability(cx, recv.span, "map", &mut applicability); - let into_prefix = if map_type == "into_iter" { "into_" } else { "" }; + let into_prefix = if map_type == sym::into_iter { "into_" } else { "" }; if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind && let [local_ident] = path.segments diff --git a/clippy_lints/src/methods/iter_nth.rs b/clippy_lints/src/methods/iter_nth.rs index 82bda5d951225..1fdbd81bf240e 100644 --- a/clippy_lints/src/methods/iter_nth.rs +++ b/clippy_lints/src/methods/iter_nth.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sym; use clippy_utils::ty::get_type_diagnostic_name; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::Span; -use rustc_span::symbol::sym; +use rustc_span::{Span, Symbol}; use super::ITER_NTH; @@ -12,7 +12,7 @@ pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, iter_recv: &'tcx hir::Expr<'tcx>, - iter_method: &str, + iter_method: Symbol, iter_span: Span, nth_span: Span, ) -> bool { @@ -30,7 +30,7 @@ pub(super) fn check<'tcx>( expr.span, format!("called `.{iter_method}().nth()` on a {caller_type}"), |diag| { - let get_method = if iter_method == "iter_mut" { "get_mut" } else { "get" }; + let get_method = if iter_method == sym::iter_mut { "get_mut" } else { "get" }; diag.span_suggestion_verbose( iter_span.to(nth_span), format!("`{get_method}` is equivalent but more concise"), diff --git a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs index 9d562f5e51d2c..c0366765234f9 100644 --- a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs +++ b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -2,7 +2,7 @@ use std::iter::once; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::{get_expr_use_or_unification_node, is_res_lang_ctor, path_res, std_or_core}; +use clippy_utils::{get_expr_use_or_unification_node, is_res_lang_ctor, path_res, std_or_core, sym}; use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, OptionSome}; @@ -10,6 +10,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::hir_id::HirId; use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::LateContext; +use rustc_span::Symbol; use super::{ITER_ON_EMPTY_COLLECTIONS, ITER_ON_SINGLE_ITEMS}; @@ -51,7 +52,7 @@ fn is_arg_ty_unified_in_fn<'tcx>( .any(|(i, ty)| i != arg_id_in_args && ty.skip_binder().walk().any(|arg| arg.as_type() == Some(arg_ty_in_args))) } -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: &str, recv: &'tcx Expr<'tcx>) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, recv: &'tcx Expr<'tcx>) { let item = match recv.kind { ExprKind::Array([]) => None, ExprKind::Array([e]) => Some(e), @@ -60,9 +61,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method _ => return, }; let iter_type = match method_name { - "iter" => IterType::Iter, - "iter_mut" => IterType::IterMut, - "into_iter" => IterType::IntoIter, + sym::iter => IterType::Iter, + sym::iter_mut => IterType::IterMut, + sym::into_iter => IterType::IntoIter, _ => return, }; diff --git a/clippy_lints/src/methods/iter_overeager_cloned.rs b/clippy_lints/src/methods/iter_overeager_cloned.rs index 7bb625222ec0f..f5fe4316eb0d3 100644 --- a/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -8,7 +8,7 @@ use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, Pl use rustc_lint::LateContext; use rustc_middle::mir::{FakeReadCause, Mutability}; use rustc_middle::ty::{self, BorrowKind}; -use rustc_span::sym; +use rustc_span::{Symbol, sym}; use super::ITER_OVEREAGER_CLONED; use crate::redundant_clone::REDUNDANT_CLONE; @@ -26,7 +26,7 @@ pub(super) enum Op<'a> { // later `.cloned()` // and add `&` to the parameter of closure parameter // e.g. `find` `filter` - FixClosure(&'a str, &'a Expr<'a>), + FixClosure(Symbol, &'a Expr<'a>), // later `.cloned()` // e.g. `skip` `take` diff --git a/clippy_lints/src/methods/manual_c_str_literals.rs b/clippy_lints/src/methods/manual_c_str_literals.rs index 3fa83cd39d1d2..a8445b68dd608 100644 --- a/clippy_lints/src/methods/manual_c_str_literals.rs +++ b/clippy_lints/src/methods/manual_c_str_literals.rs @@ -168,7 +168,7 @@ fn rewrite_as_cstr(cx: &LateContext<'_>, span: Span) -> Option { fn get_cast_target<'tcx>(e: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { match &e.kind { - ExprKind::MethodCall(method, receiver, [], _) if method.ident.as_str() == "cast" => Some(receiver), + ExprKind::MethodCall(method, receiver, [], _) if method.ident.name == sym::cast => Some(receiver), ExprKind::Cast(expr, _) => Some(expr), _ => None, } diff --git a/clippy_lints/src/methods/manual_inspect.rs b/clippy_lints/src/methods/manual_inspect.rs index c47879442fc9f..21f2ce8b7c900 100644 --- a/clippy_lints/src/methods/manual_inspect.rs +++ b/clippy_lints/src/methods/manual_inspect.rs @@ -3,18 +3,18 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{IntoSpan, SpanRangeExt}; use clippy_utils::ty::get_field_by_name; use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures}; -use clippy_utils::{ExprUseNode, expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id}; +use clippy_utils::{ExprUseNode, expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id, sym}; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::{BindingMode, BorrowKind, ByRef, ClosureKind, Expr, ExprKind, Mutability, Node, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; -use rustc_span::{DUMMY_SP, Span, Symbol, sym}; +use rustc_span::{DUMMY_SP, Span, Symbol}; use super::MANUAL_INSPECT; #[expect(clippy::too_many_lines)] -pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: &str, name_span: Span, msrv: Msrv) { +pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: Symbol, name_span: Span, msrv: Msrv) { if let ExprKind::Closure(c) = arg.kind && matches!(c.kind, ClosureKind::Closure) && let typeck = cx.typeck_results() @@ -168,8 +168,8 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: edits.extend(addr_of_edits); } let edit = match name { - "map" => "inspect", - "map_err" => "inspect_err", + sym::map => "inspect", + sym::map_err => "inspect_err", _ => return, }; edits.push((name_span, edit.to_string())); diff --git a/clippy_lints/src/methods/map_identity.rs b/clippy_lints/src/methods/map_identity.rs index 0536014465731..98def66ca1499 100644 --- a/clippy_lints/src/methods/map_identity.rs +++ b/clippy_lints/src/methods/map_identity.rs @@ -5,7 +5,7 @@ use rustc_ast::BindingMode; use rustc_errors::Applicability; use rustc_hir::{self as hir, Node, PatKind}; use rustc_lint::LateContext; -use rustc_span::{Span, sym}; +use rustc_span::{Span, Symbol, sym}; use super::MAP_IDENTITY; @@ -14,7 +14,7 @@ pub(super) fn check( expr: &hir::Expr<'_>, caller: &hir::Expr<'_>, map_arg: &hir::Expr<'_>, - name: &str, + name: Symbol, _map_span: Span, ) { let caller_ty = cx.typeck_results().expr_ty(caller); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e0e6a1a59b623..d2d59f0013c0c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -150,7 +150,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::macros::FormatArgsStorage; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item}; -use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty}; +use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty, sym}; pub use path_ends_with_ext::DEFAULT_ALLOWED_DOTFILES; use rustc_abi::ExternAbi; use rustc_data_structures::fx::FxHashSet; @@ -159,7 +159,7 @@ use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::{self, TraitRef, Ty}; use rustc_session::impl_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::{Span, Symbol, kw}; declare_clippy_lint! { /// ### What it does @@ -4711,17 +4711,15 @@ impl_lint_pass!(Methods => [ /// Extracts a method call name, args, and `Span` of the method name. /// This ensures that neither the receiver nor any of the arguments /// come from expansion. -pub fn method_call<'tcx>( - recv: &'tcx Expr<'tcx>, -) -> Option<(&'tcx str, &'tcx Expr<'tcx>, &'tcx [Expr<'tcx>], Span, Span)> { +pub fn method_call<'tcx>(recv: &'tcx Expr<'tcx>) -> Option<(Symbol, &'tcx Expr<'tcx>, &'tcx [Expr<'tcx>], Span, Span)> { if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind && !args.iter().any(|e| e.span.from_expansion()) && !receiver.span.from_expansion() { - let name = path.ident.name.as_str(); - return Some((name, receiver, args, path.ident.span, call_span)); + Some((path.ident.name, receiver, args, path.ident.span, call_span)) + } else { + None } - None } impl<'tcx> LateLintPass<'tcx> for Methods { @@ -4743,13 +4741,13 @@ impl<'tcx> LateLintPass<'tcx> for Methods { }, ExprKind::MethodCall(method_call, receiver, args, _) => { let method_span = method_call.ident.span; - or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args); + or_fun_call::check(cx, expr, method_span, method_call.ident.name, receiver, args); expect_fun_call::check( cx, &self.format_args, expr, method_span, - method_call.ident.as_str(), + method_call.ident.name, receiver, args, ); @@ -4778,7 +4776,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if impl_item.span.in_external_macro(cx.sess().source_map()) { return; } - let name = impl_item.ident.name.as_str(); + let name = impl_item.ident.name; let parent = cx.tcx.hir_get_parent_item(impl_item.hir_id()).def_id; let item = cx.tcx.hir_expect_item(parent); let self_ty = cx.tcx.type_of(item.owner_id).instantiate_identity(); @@ -4851,7 +4849,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { return; } - if name == "new" && ret_ty != self_ty { + if name == sym::new && ret_ty != self_ty { span_lint( cx, NEW_RET_NO_SELF, @@ -4881,7 +4879,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty(); wrong_self_convention::check( cx, - item.ident.name.as_str(), + item.ident.name, self_ty, first_arg_ty, first_arg_hir_ty.span, @@ -4912,14 +4910,17 @@ impl Methods { // Handle method calls whose receiver and arguments may not come from expansion if let Some((name, recv, args, span, call_span)) = method_call(expr) { match (name, args) { - ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => { + ( + sym::add | sym::offset | sym::sub | sym::wrapping_offset | sym::wrapping_add | sym::wrapping_sub, + [_arg], + ) => { zst_offset::check(cx, expr, recv); }, - ("all", [arg]) => { + (sym::all, [arg]) => { unused_enumerate_index::check(cx, expr, recv, arg); needless_character_iteration::check(cx, expr, recv, arg, true); match method_call(recv) { - Some(("cloned", recv2, [], _, _)) => { + Some((sym::cloned, recv2, [], _, _)) => { iter_overeager_cloned::check( cx, expr, @@ -4929,13 +4930,13 @@ impl Methods { false, ); }, - Some(("map", _, [map_arg], _, map_call_span)) => { + Some((sym::map, _, [map_arg], _, map_call_span)) => { map_all_any_identity::check(cx, expr, recv, map_call_span, map_arg, call_span, arg, "all"); }, _ => {}, } }, - ("and_then", [arg]) => { + (sym::and_then, [arg]) => { let biom_option_linted = bind_instead_of_map::check_and_then_some(cx, expr, recv, arg); let biom_result_linted = bind_instead_of_map::check_and_then_ok(cx, expr, recv, arg); if !biom_option_linted && !biom_result_linted { @@ -4945,11 +4946,11 @@ impl Methods { } } }, - ("any", [arg]) => { + (sym::any, [arg]) => { unused_enumerate_index::check(cx, expr, recv, arg); needless_character_iteration::check(cx, expr, recv, arg, false); match method_call(recv) { - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check( cx, expr, recv, @@ -4957,80 +4958,79 @@ impl Methods { iter_overeager_cloned::Op::NeedlessMove(arg), false, ), - Some(("chars", recv, _, _, _)) + Some((sym::chars, recv, _, _, _)) if let ExprKind::Closure(arg) = arg.kind && let body = cx.tcx.hir_body(arg.body) && let [param] = body.params => { string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), self.msrv); }, - Some(("map", _, [map_arg], _, map_call_span)) => { + Some((sym::map, _, [map_arg], _, map_call_span)) => { map_all_any_identity::check(cx, expr, recv, map_call_span, map_arg, call_span, arg, "any"); }, - Some(("iter", iter_recv, ..)) => { + Some((sym::iter, iter_recv, ..)) => { manual_contains::check(cx, expr, iter_recv, arg); }, _ => {}, } }, - ("arg", [arg]) => { + (sym::arg, [arg]) => { suspicious_command_arg_space::check(cx, recv, arg, span); }, - ("as_deref" | "as_deref_mut", []) => { + (sym::as_deref | sym::as_deref_mut, []) => { needless_option_as_deref::check(cx, expr, recv, name); }, - ("as_bytes", []) => { - if let Some(("as_str", recv, [], as_str_span, _)) = method_call(recv) { + (sym::as_bytes, []) => { + if let Some((sym::as_str, recv, [], as_str_span, _)) = method_call(recv) { redundant_as_str::check(cx, expr, recv, as_str_span, span); } sliced_string_as_bytes::check(cx, expr, recv); }, - ("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv), - ("as_ptr", []) => manual_c_str_literals::check_as_ptr(cx, expr, recv, self.msrv), - ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv), - ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv), - ("bytes", []) => unbuffered_bytes::check(cx, expr, recv), - ("cloned", []) => { + (sym::as_mut | sym::as_ref, []) => useless_asref::check(cx, expr, name, recv), + (sym::as_ptr, []) => manual_c_str_literals::check_as_ptr(cx, expr, recv, self.msrv), + (sym::assume_init, []) => uninit_assumed_init::check(cx, expr, recv), + (sym::bytes, []) => unbuffered_bytes::check(cx, expr, recv), + (sym::cloned, []) => { cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv); option_as_ref_cloned::check(cx, recv, span); }, - ("collect", []) if is_trait_method(cx, expr, sym::Iterator) => { + (sym::collect, []) if is_trait_method(cx, expr, sym::Iterator) => { needless_collect::check(cx, span, expr, recv, call_span); match method_call(recv) { - Some((name @ ("cloned" | "copied"), recv2, [], _, _)) => { + Some((name @ (sym::cloned | sym::copied), recv2, [], _, _)) => { iter_cloned_collect::check(cx, name, expr, recv2); }, - Some(("map", m_recv, [m_arg], m_ident_span, _)) => { + Some((sym::map, m_recv, [m_arg], m_ident_span, _)) => { map_collect_result_unit::check(cx, expr, m_recv, m_arg); format_collect::check(cx, expr, m_arg, m_ident_span); }, - Some(("take", take_self_arg, [take_arg], _, _)) => { + Some((sym::take, take_self_arg, [take_arg], _, _)) => { if self.msrv.meets(cx, msrvs::STR_REPEAT) { manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg); } }, - Some(("drain", recv, args, ..)) => { + Some((sym::drain, recv, args, ..)) => { drain_collect::check(cx, args, expr, recv); }, _ => {}, } }, - ("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) { - Some(("cloned", recv2, [], _, _)) => { + (sym::count, []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) { + Some((sym::cloned, recv2, [], _, _)) => { iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::RmCloned, false); }, - Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _, _)) => { + Some((name2 @ (sym::into_iter | sym::iter | sym::iter_mut), recv2, [], _, _)) => { iter_count::check(cx, expr, recv2, name2); }, - Some(("map", _, [arg], _, _)) => suspicious_map::check(cx, expr, recv, arg), - Some(("filter", recv2, [arg], _, _)) => bytecount::check(cx, expr, recv2, arg), - Some(("bytes", recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2), + Some((sym::map, _, [arg], _, _)) => suspicious_map::check(cx, expr, recv, arg), + Some((sym::filter, recv2, [arg], _, _)) => bytecount::check(cx, expr, recv2, arg), + Some((sym::bytes, recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2), _ => {}, }, - ("min" | "max", [arg]) => { + (sym::min | sym::max, [arg]) => { unnecessary_min_or_max::check(cx, expr, name, recv, arg); }, - ("drain", ..) => { + (sym::drain, ..) => { if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.parent_hir_node(expr.hir_id) && matches!(kind, StmtKind::Semi(_)) && args.len() <= 1 @@ -5040,31 +5040,31 @@ impl Methods { iter_with_drain::check(cx, expr, recv, span, arg); } }, - ("ends_with", [arg]) => { + (sym::ends_with, [arg]) => { if let ExprKind::MethodCall(.., span) = expr.kind { case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg, self.msrv); } path_ends_with_ext::check(cx, recv, arg, expr, self.msrv, &self.allowed_dotfiles); }, - ("expect", [_]) => { + (sym::expect, [_]) => { match method_call(recv) { - Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv), - Some(("err", recv, [], err_span, _)) => { + Some((sym::ok, recv, [], _, _)) => ok_expect::check(cx, expr, recv), + Some((sym::err, recv, [], err_span, _)) => { err_expect::check(cx, expr, recv, span, err_span, self.msrv); }, _ => {}, } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, - ("expect_err", [_]) | ("unwrap_err" | "unwrap_unchecked" | "unwrap_err_unchecked", []) => { + (sym::expect_err, [_]) | (sym::unwrap_err | sym::unwrap_unchecked | sym::unwrap_err_unchecked, []) => { unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, - ("extend", [arg]) => { + (sym::extend, [arg]) => { string_extend_chars::check(cx, expr, recv, arg); extend_with_drain::check(cx, expr, recv, arg); }, - ("filter", [arg]) => { - if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { + (sym::filter, [arg]) => { + if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) { // if `arg` has side-effect, the semantic will change iter_overeager_cloned::check( cx, @@ -5080,8 +5080,8 @@ impl Methods { iter_filter::check(cx, expr, arg, span); } }, - ("find", [arg]) => { - if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { + (sym::find, [arg]) => { + if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) { // if `arg` has side-effect, the semantic will change iter_overeager_cloned::check( cx, @@ -5093,26 +5093,26 @@ impl Methods { ); } }, - ("filter_map", [arg]) => { + (sym::filter_map, [arg]) => { unused_enumerate_index::check(cx, expr, recv, arg); unnecessary_filter_map::check(cx, expr, arg, name); filter_map_bool_then::check(cx, expr, arg, call_span); filter_map_identity::check(cx, expr, arg, span); }, - ("find_map", [arg]) => { + (sym::find_map, [arg]) => { unused_enumerate_index::check(cx, expr, recv, arg); unnecessary_filter_map::check(cx, expr, arg, name); }, - ("flat_map", [arg]) => { + (sym::flat_map, [arg]) => { unused_enumerate_index::check(cx, expr, recv, arg); flat_map_identity::check(cx, expr, arg, span); flat_map_option::check(cx, expr, arg, span); }, - ("flatten", []) => match method_call(recv) { - Some(("map", recv, [map_arg], map_span, _)) => { + (sym::flatten, []) => match method_call(recv) { + Some((sym::map, recv, [map_arg], map_span, _)) => { map_flatten::check(cx, expr, recv, map_arg, map_span); }, - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check( cx, expr, recv, @@ -5122,15 +5122,15 @@ impl Methods { ), _ => {}, }, - ("fold", [init, acc]) => { + (sym::fold, [init, acc]) => { manual_try_fold::check(cx, expr, init, acc, call_span, self.msrv); unnecessary_fold::check(cx, expr, init, acc, span); }, - ("for_each", [arg]) => { + (sym::for_each, [arg]) => { unused_enumerate_index::check(cx, expr, recv, arg); match method_call(recv) { - Some(("inspect", _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2), - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + Some((sym::inspect, _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2), + Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check( cx, expr, recv, @@ -5141,44 +5141,44 @@ impl Methods { _ => {}, } }, - ("get", [arg]) => { + (sym::get, [arg]) => { get_first::check(cx, expr, recv, arg); get_last_with_len::check(cx, expr, recv, arg); }, - ("get_or_insert_with", [arg]) => { + (sym::get_or_insert_with, [arg]) => { unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"); }, - ("hash", [arg]) => { + (sym::hash, [arg]) => { unit_hash::check(cx, expr, recv, arg); }, - ("is_empty", []) => { + (sym::is_empty, []) => { match method_call(recv) { - Some((prev_method @ ("as_bytes" | "bytes"), prev_recv, [], _, _)) => { - needless_as_bytes::check(cx, prev_method, "is_empty", prev_recv, expr.span); + Some((prev_method @ (sym::as_bytes | sym::bytes), prev_recv, [], _, _)) => { + needless_as_bytes::check(cx, prev_method, name, prev_recv, expr.span); }, - Some(("as_str", recv, [], as_str_span, _)) => { + Some((sym::as_str, recv, [], as_str_span, _)) => { redundant_as_str::check(cx, expr, recv, as_str_span, span); }, _ => {}, } is_empty::check(cx, expr, recv); }, - ("is_file", []) => filetype_is_file::check(cx, expr, recv), - ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv), - ("is_none", []) => check_is_some_is_none(cx, expr, recv, call_span, false), - ("is_some", []) => check_is_some_is_none(cx, expr, recv, call_span, true), - ("iter" | "iter_mut" | "into_iter", []) => { + (sym::is_file, []) => filetype_is_file::check(cx, expr, recv), + (sym::is_digit, [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv), + (sym::is_none, []) => check_is_some_is_none(cx, expr, recv, call_span, false), + (sym::is_some, []) => check_is_some_is_none(cx, expr, recv, call_span, true), + (sym::iter | sym::iter_mut | sym::into_iter, []) => { iter_on_single_or_empty_collections::check(cx, expr, name, recv); }, - ("join", [join_arg]) => { - if let Some(("collect", _, _, span, _)) = method_call(recv) { + (sym::join, [join_arg]) => { + if let Some((sym::collect, _, _, span, _)) = method_call(recv) { unnecessary_join::check(cx, expr, recv, join_arg, span); } else { join_absolute_paths::check(cx, recv, join_arg, expr.span); } }, - ("last", []) => { - if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { + (sym::last, []) => { + if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) { iter_overeager_cloned::check( cx, expr, @@ -5190,24 +5190,24 @@ impl Methods { } double_ended_iterator_last::check(cx, expr, recv, call_span); }, - ("len", []) => { - if let Some((prev_method @ ("as_bytes" | "bytes"), prev_recv, [], _, _)) = method_call(recv) { - needless_as_bytes::check(cx, prev_method, "len", prev_recv, expr.span); + (sym::len, []) => { + if let Some((prev_method @ (sym::as_bytes | sym::bytes), prev_recv, [], _, _)) = method_call(recv) { + needless_as_bytes::check(cx, prev_method, sym::len, prev_recv, expr.span); } }, - ("lock", []) => { + (sym::lock, []) => { mut_mutex_lock::check(cx, expr, recv, span); }, - (name @ ("map" | "map_err"), [m_arg]) => { - if name == "map" { + (name @ (sym::map | sym::map_err), [m_arg]) => { + if name == sym::map { unused_enumerate_index::check(cx, expr, recv, m_arg); map_clone::check(cx, expr, recv, m_arg, self.msrv); map_with_unused_argument_over_ranges::check(cx, expr, recv, m_arg, self.msrv, span); match method_call(recv) { - Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) => { + Some((map_name @ (sym::iter | sym::into_iter), recv2, _, _, _)) => { iter_kv_map::check(cx, map_name, expr, recv2, m_arg, self.msrv); }, - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check( cx, expr, recv, @@ -5222,12 +5222,12 @@ impl Methods { } if let Some((name, recv2, args, span2, _)) = method_call(recv) { match (name, args) { - ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv), - ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv), - ("filter", [f_arg]) => { + (sym::as_mut, []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv), + (sym::as_ref, []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv), + (sym::filter, [f_arg]) => { filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false); }, - ("find", [f_arg]) => { + (sym::find, [f_arg]) => { filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true); }, _ => {}, @@ -5237,22 +5237,22 @@ impl Methods { manual_inspect::check(cx, expr, m_arg, name, span, self.msrv); crate::useless_conversion::check_function_application(cx, expr, recv, m_arg); }, - ("map_break" | "map_continue", [m_arg]) => { + (sym::map_break | sym::map_continue, [m_arg]) => { crate::useless_conversion::check_function_application(cx, expr, recv, m_arg); }, - ("map_or", [def, map]) => { + (sym::map_or, [def, map]) => { option_map_or_none::check(cx, expr, recv, def, map); manual_ok_or::check(cx, expr, recv, def, map); unnecessary_map_or::check(cx, expr, recv, def, map, span, self.msrv); }, - ("map_or_else", [def, map]) => { + (sym::map_or_else, [def, map]) => { result_map_or_else_none::check(cx, expr, recv, def, map); unnecessary_result_map_or_else::check(cx, expr, recv, def, map); }, - ("next", []) => { + (sym::next, []) => { if let Some((name2, recv2, args2, _, _)) = method_call(recv) { match (name2, args2) { - ("cloned", []) => iter_overeager_cloned::check( + (sym::cloned, []) => iter_overeager_cloned::check( cx, expr, recv, @@ -5260,19 +5260,19 @@ impl Methods { iter_overeager_cloned::Op::LaterCloned, false, ), - ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg), - ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, self.msrv), - ("iter", []) => iter_next_slice::check(cx, expr, recv2), - ("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg), - ("skip_while", [_]) => skip_while_next::check(cx, expr), - ("rev", []) => manual_next_back::check(cx, expr, recv, recv2), + (sym::filter, [arg]) => filter_next::check(cx, expr, recv2, arg), + (sym::filter_map, [arg]) => filter_map_next::check(cx, expr, recv2, arg, self.msrv), + (sym::iter, []) => iter_next_slice::check(cx, expr, recv2), + (sym::skip, [arg]) => iter_skip_next::check(cx, expr, recv2, arg), + (sym::skip_while, [_]) => skip_while_next::check(cx, expr), + (sym::rev, []) => manual_next_back::check(cx, expr, recv, recv2), _ => {}, } } }, - ("nth", [n_arg]) => match method_call(recv) { - Some(("bytes", recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg), - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + (sym::nth, [n_arg]) => match method_call(recv) { + Some((sym::bytes, recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg), + Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check( cx, expr, recv, @@ -5280,54 +5280,54 @@ impl Methods { iter_overeager_cloned::Op::LaterCloned, false, ), - Some((iter_method @ ("iter" | "iter_mut"), iter_recv, [], iter_span, _)) => { + Some((iter_method @ (sym::iter | sym::iter_mut), iter_recv, [], iter_span, _)) => { if !iter_nth::check(cx, expr, iter_recv, iter_method, iter_span, span) { iter_nth_zero::check(cx, expr, recv, n_arg); } }, _ => iter_nth_zero::check(cx, expr, recv, n_arg), }, - ("ok_or_else", [arg]) => { + (sym::ok_or_else, [arg]) => { unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"); }, - ("open", [_]) => { + (sym::open, [_]) => { open_options::check(cx, expr, recv); }, - ("or_else", [arg]) => { + (sym::or_else, [arg]) => { if !bind_instead_of_map::check_or_else_err(cx, expr, recv, arg) { unnecessary_lazy_eval::check(cx, expr, recv, arg, "or"); } }, - ("push", [arg]) => { + (sym::push, [arg]) => { path_buf_push_overwrite::check(cx, expr, arg); }, - ("read_to_end", [_]) => { + (sym::read_to_end, [_]) => { verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_END_MSG); }, - ("read_to_string", [_]) => { + (sym::read_to_string, [_]) => { verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_STRING_MSG); }, - ("read_line", [arg]) => { + (sym::read_line, [arg]) => { read_line_without_trim::check(cx, expr, recv, arg); }, - ("repeat", [arg]) => { + (sym::repeat, [arg]) => { repeat_once::check(cx, expr, recv, arg); }, - (name @ ("replace" | "replacen"), [arg1, arg2] | [arg1, arg2, _]) => { + (name @ (sym::replace | sym::replacen), [arg1, arg2] | [arg1, arg2, _]) => { no_effect_replace::check(cx, expr, arg1, arg2); // Check for repeated `str::replace` calls to perform `collapsible_str_replace` lint if self.msrv.meets(cx, msrvs::PATTERN_TRAIT_CHAR_ARRAY) - && name == "replace" - && let Some(("replace", ..)) = method_call(recv) + && name == sym::replace + && let Some((sym::replace, ..)) = method_call(recv) { collapsible_str_replace::check(cx, expr, arg1, arg2); } }, - ("resize", [count_arg, default_arg]) => { + (sym::resize, [count_arg, default_arg]) => { vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span); }, - ("seek", [arg]) => { + (sym::seek, [arg]) => { if self.msrv.meets(cx, msrvs::SEEK_FROM_CURRENT) { seek_from_current::check(cx, expr, recv, arg); } @@ -5335,11 +5335,11 @@ impl Methods { seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span); } }, - ("skip", [arg]) => { + (sym::skip, [arg]) => { iter_skip_zero::check(cx, expr, arg); iter_out_of_bounds::check_skip(cx, expr, recv, arg); - if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { + if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) { iter_overeager_cloned::check( cx, expr, @@ -5350,34 +5350,34 @@ impl Methods { ); } }, - ("sort", []) => { + (sym::sort, []) => { stable_sort_primitive::check(cx, expr, recv); }, - ("sort_by", [arg]) => { + (sym::sort_by, [arg]) => { unnecessary_sort_by::check(cx, expr, recv, arg, false); }, - ("sort_unstable_by", [arg]) => { + (sym::sort_unstable_by, [arg]) => { unnecessary_sort_by::check(cx, expr, recv, arg, true); }, - ("split", [arg]) => { + (sym::split, [arg]) => { str_split::check(cx, expr, recv, arg); }, - ("splitn" | "rsplitn", [count_arg, pat_arg]) => { + (sym::splitn | sym::rsplitn, [count_arg, pat_arg]) => { if let Some(Constant::Int(count)) = ConstEvalCtxt::new(cx).eval(count_arg) { suspicious_splitn::check(cx, name, expr, recv, count); str_splitn::check(cx, name, expr, recv, pat_arg, count, self.msrv); } }, - ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => { + (sym::splitn_mut | sym::rsplitn_mut, [count_arg, _]) => { if let Some(Constant::Int(count)) = ConstEvalCtxt::new(cx).eval(count_arg) { suspicious_splitn::check(cx, name, expr, recv, count); } }, - ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg), - ("take", [arg]) => { + (sym::step_by, [arg]) => iterator_step_by_zero::check(cx, expr, arg), + (sym::take, [arg]) => { iter_out_of_bounds::check_take(cx, expr, recv, arg); manual_repeat_n::check(cx, expr, recv, arg, self.msrv); - if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { + if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) { iter_overeager_cloned::check( cx, expr, @@ -5388,74 +5388,89 @@ impl Methods { ); } }, - ("take", []) => needless_option_take::check(cx, expr, recv), - ("then", [arg]) => { + (sym::take, []) => needless_option_take::check(cx, expr, recv), + (sym::then, [arg]) => { if !self.msrv.meets(cx, msrvs::BOOL_THEN_SOME) { return; } unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some"); }, - ("try_into", []) if is_trait_method(cx, expr, sym::TryInto) => { + (sym::try_into, []) if is_trait_method(cx, expr, sym::TryInto) => { unnecessary_fallible_conversions::check_method(cx, expr); }, - ("to_owned", []) => { + (sym::to_owned, []) => { if !suspicious_to_owned::check(cx, expr, recv) { implicit_clone::check(cx, name, expr, recv); } }, - ("to_os_string" | "to_path_buf" | "to_vec", []) => { + (sym::to_os_string | sym::to_path_buf | sym::to_vec, []) => { implicit_clone::check(cx, name, expr, recv); }, - ("type_id", []) => { + (sym::type_id, []) => { type_id_on_box::check(cx, recv, expr.span); }, - ("unwrap", []) => { + (sym::unwrap, []) => { match method_call(recv) { - Some(("get", recv, [get_arg], _, _)) => { + Some((sym::get, recv, [get_arg], _, _)) => { get_unwrap::check(cx, expr, recv, get_arg, false); }, - Some(("get_mut", recv, [get_arg], _, _)) => { + Some((sym::get_mut, recv, [get_arg], _, _)) => { get_unwrap::check(cx, expr, recv, get_arg, true); }, - Some(("or", recv, [or_arg], or_span, _)) => { + Some((sym::or, recv, [or_arg], or_span, _)) => { or_then_unwrap::check(cx, expr, recv, or_arg, or_span); }, _ => {}, } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, - ("unwrap_or", [u_arg]) => { + (sym::unwrap_or, [u_arg]) => { match method_call(recv) { - Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _, _)) => { - manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]); + Some((arith @ (sym::checked_add | sym::checked_sub | sym::checked_mul), lhs, [rhs], _, _)) => { + manual_saturating_arithmetic::check( + cx, + expr, + lhs, + rhs, + u_arg, + &arith.as_str()[const { "checked_".len() }..], + ); }, - Some(("map", m_recv, [m_arg], span, _)) => { + Some((sym::map, m_recv, [m_arg], span, _)) => { option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, self.msrv); }, - Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => { - obfuscated_if_else::check(cx, expr, t_recv, t_arg, Some(u_arg), then_method, "unwrap_or"); + Some((then_method @ (sym::then | sym::then_some), t_recv, [t_arg], _, _)) => { + obfuscated_if_else::check(cx, expr, t_recv, t_arg, Some(u_arg), then_method, name); }, _ => {}, } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, - ("unwrap_or_default", []) => { + (sym::unwrap_or_default, []) => { match method_call(recv) { - Some(("map", m_recv, [arg], span, _)) => { + Some((sym::map, m_recv, [arg], span, _)) => { manual_is_variant_and::check(cx, expr, m_recv, arg, span, self.msrv); }, - Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => { - obfuscated_if_else::check(cx, expr, t_recv, t_arg, None, then_method, "unwrap_or_default"); + Some((then_method @ (sym::then | sym::then_some), t_recv, [t_arg], _, _)) => { + obfuscated_if_else::check( + cx, + expr, + t_recv, + t_arg, + None, + then_method, + sym::unwrap_or_default, + ); }, _ => {}, } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, - ("unwrap_or_else", [u_arg]) => { + (sym::unwrap_or_else, [u_arg]) => { match method_call(recv) { - Some(("map", recv, [map_arg], _, _)) + Some((sym::map, recv, [map_arg], _, _)) if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {}, - Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => { + Some((then_method @ (sym::then | sym::then_some), t_recv, [t_arg], _, _)) => { obfuscated_if_else::check( cx, expr, @@ -5463,7 +5478,7 @@ impl Methods { t_arg, Some(u_arg), then_method, - "unwrap_or_else", + sym::unwrap_or_else, ); }, _ => { @@ -5472,13 +5487,13 @@ impl Methods { } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, - ("wake", []) => { + (sym::wake, []) => { waker_clone_wake::check(cx, expr, recv); }, - ("write", []) => { + (sym::write, []) => { readonly_write_lock::check(cx, expr, recv); }, - ("zip", [arg]) => { + (sym::zip, [arg]) => { if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind && name.ident.name == sym::iter { @@ -5490,8 +5505,8 @@ impl Methods { } // Handle method calls whose receiver and arguments may come from expansion if let ExprKind::MethodCall(path, recv, args, _call_span) = expr.kind { - match (path.ident.name.as_str(), args) { - ("expect", [_]) if !matches!(method_call(recv), Some(("ok" | "err", _, [], _, _))) => { + match (path.ident.name, args) { + (sym::expect, [_]) if !matches!(method_call(recv), Some((sym::ok | sym::err, _, [], _, _))) => { unwrap_expect_used::check( cx, expr, @@ -5502,7 +5517,7 @@ impl Methods { unwrap_expect_used::Variant::Expect, ); }, - ("expect_err", [_]) => { + (sym::expect_err, [_]) => { unwrap_expect_used::check( cx, expr, @@ -5513,7 +5528,7 @@ impl Methods { unwrap_expect_used::Variant::Expect, ); }, - ("unwrap", []) => { + (sym::unwrap, []) => { unwrap_expect_used::check( cx, expr, @@ -5524,7 +5539,7 @@ impl Methods { unwrap_expect_used::Variant::Unwrap, ); }, - ("unwrap_err", []) => { + (sym::unwrap_err, []) => { unwrap_expect_used::check( cx, expr, @@ -5543,13 +5558,13 @@ impl Methods { fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, call_span: Span, is_some: bool) { match method_call(recv) { - Some((name @ ("find" | "position" | "rposition"), f_recv, [arg], span, _)) => { + Some((name @ (sym::find | sym::position | sym::rposition), f_recv, [arg], span, _)) => { search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span); }, - Some(("get", f_recv, [arg], _, _)) => { + Some((sym::get, f_recv, [arg], _, _)) => { unnecessary_get_then_check::check(cx, call_span, recv, f_recv, arg, is_some); }, - Some(("first", f_recv, [], _, _)) => { + Some((sym::first, f_recv, [], _, _)) => { unnecessary_first_then_check::check(cx, call_span, recv, f_recv, is_some); }, _ => {}, @@ -5593,7 +5608,7 @@ const FN_HEADER: hir::FnHeader = hir::FnHeader { struct ShouldImplTraitCase { trait_name: &'static str, - method_name: &'static str, + method_name: Symbol, param_count: usize, fn_header: hir::FnHeader, // implicit self kind expected (none, self, &self, ...) @@ -5606,7 +5621,7 @@ struct ShouldImplTraitCase { impl ShouldImplTraitCase { const fn new( trait_name: &'static str, - method_name: &'static str, + method_name: Symbol, param_count: usize, fn_header: hir::FnHeader, self_kind: SelfKind, @@ -5639,36 +5654,36 @@ impl ShouldImplTraitCase { #[rustfmt::skip] const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [ - ShouldImplTraitCase::new("std::ops::Add", "add", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::convert::AsMut", "as_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), - ShouldImplTraitCase::new("std::convert::AsRef", "as_ref", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true), - ShouldImplTraitCase::new("std::ops::BitAnd", "bitand", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::BitOr", "bitor", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::BitXor", "bitxor", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::borrow::Borrow", "borrow", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true), - ShouldImplTraitCase::new("std::borrow::BorrowMut", "borrow_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), - ShouldImplTraitCase::new("std::clone::Clone", "clone", 1, FN_HEADER, SelfKind::Ref, OutType::Any, true), - ShouldImplTraitCase::new("std::cmp::Ord", "cmp", 2, FN_HEADER, SelfKind::Ref, OutType::Any, true), - ShouldImplTraitCase::new("std::default::Default", "default", 0, FN_HEADER, SelfKind::No, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::Deref", "deref", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true), - ShouldImplTraitCase::new("std::ops::DerefMut", "deref_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), - ShouldImplTraitCase::new("std::ops::Div", "div", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::Drop", "drop", 1, FN_HEADER, SelfKind::RefMut, OutType::Unit, true), - ShouldImplTraitCase::new("std::cmp::PartialEq", "eq", 2, FN_HEADER, SelfKind::Ref, OutType::Bool, true), - ShouldImplTraitCase::new("std::iter::FromIterator", "from_iter", 1, FN_HEADER, SelfKind::No, OutType::Any, true), - ShouldImplTraitCase::new("std::str::FromStr", "from_str", 1, FN_HEADER, SelfKind::No, OutType::Any, true), - ShouldImplTraitCase::new("std::hash::Hash", "hash", 2, FN_HEADER, SelfKind::Ref, OutType::Unit, true), - ShouldImplTraitCase::new("std::ops::Index", "index", 2, FN_HEADER, SelfKind::Ref, OutType::Ref, true), - ShouldImplTraitCase::new("std::ops::IndexMut", "index_mut", 2, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), - ShouldImplTraitCase::new("std::iter::IntoIterator", "into_iter", 1, FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::Mul", "mul", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::Neg", "neg", 1, FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::iter::Iterator", "next", 1, FN_HEADER, SelfKind::RefMut, OutType::Any, false), - ShouldImplTraitCase::new("std::ops::Not", "not", 1, FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::Rem", "rem", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::Shl", "shl", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::Shr", "shr", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::Sub", "sub", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Add", sym::add, 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::convert::AsMut", sym::as_mut, 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), + ShouldImplTraitCase::new("std::convert::AsRef", sym::as_ref, 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true), + ShouldImplTraitCase::new("std::ops::BitAnd", sym::bitand, 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::BitOr", sym::bitor, 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::BitXor", sym::bitxor, 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::borrow::Borrow", sym::borrow, 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true), + ShouldImplTraitCase::new("std::borrow::BorrowMut", sym::borrow_mut, 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), + ShouldImplTraitCase::new("std::clone::Clone", sym::clone, 1, FN_HEADER, SelfKind::Ref, OutType::Any, true), + ShouldImplTraitCase::new("std::cmp::Ord", sym::cmp, 2, FN_HEADER, SelfKind::Ref, OutType::Any, true), + ShouldImplTraitCase::new("std::default::Default", kw::Default, 0, FN_HEADER, SelfKind::No, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Deref", sym::deref, 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true), + ShouldImplTraitCase::new("std::ops::DerefMut", sym::deref_mut, 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), + ShouldImplTraitCase::new("std::ops::Div", sym::div, 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Drop", sym::drop, 1, FN_HEADER, SelfKind::RefMut, OutType::Unit, true), + ShouldImplTraitCase::new("std::cmp::PartialEq", sym::eq, 2, FN_HEADER, SelfKind::Ref, OutType::Bool, true), + ShouldImplTraitCase::new("std::iter::FromIterator", sym::from_iter, 1, FN_HEADER, SelfKind::No, OutType::Any, true), + ShouldImplTraitCase::new("std::str::FromStr", sym::from_str, 1, FN_HEADER, SelfKind::No, OutType::Any, true), + ShouldImplTraitCase::new("std::hash::Hash", sym::hash, 2, FN_HEADER, SelfKind::Ref, OutType::Unit, true), + ShouldImplTraitCase::new("std::ops::Index", sym::index, 2, FN_HEADER, SelfKind::Ref, OutType::Ref, true), + ShouldImplTraitCase::new("std::ops::IndexMut", sym::index_mut, 2, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), + ShouldImplTraitCase::new("std::iter::IntoIterator", sym::into_iter, 1, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Mul", sym::mul, 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Neg", sym::neg, 1, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::iter::Iterator", sym::next, 1, FN_HEADER, SelfKind::RefMut, OutType::Any, false), + ShouldImplTraitCase::new("std::ops::Not", sym::not, 1, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Rem", sym::rem, 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Shl", sym::shl, 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Shr", sym::shr, 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Sub", sym::sub, 2, FN_HEADER, SelfKind::Value, OutType::Any, true), ]; #[derive(Clone, Copy, PartialEq, Eq, Debug)] diff --git a/clippy_lints/src/methods/needless_as_bytes.rs b/clippy_lints/src/methods/needless_as_bytes.rs index 7c9f7bae99063..635d06330e058 100644 --- a/clippy_lints/src/methods/needless_as_bytes.rs +++ b/clippy_lints/src/methods/needless_as_bytes.rs @@ -4,11 +4,11 @@ use clippy_utils::ty::is_type_lang_item; use rustc_errors::Applicability; use rustc_hir::{Expr, LangItem}; use rustc_lint::LateContext; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use super::NEEDLESS_AS_BYTES; -pub fn check(cx: &LateContext<'_>, prev_method: &str, method: &str, prev_recv: &Expr<'_>, span: Span) { +pub fn check(cx: &LateContext<'_>, prev_method: Symbol, method: Symbol, prev_recv: &Expr<'_>, span: Span) { let ty1 = cx.typeck_results().expr_ty_adjusted(prev_recv).peel_refs(); if is_type_lang_item(cx, ty1, LangItem::String) || ty1.is_str() { let mut app = Applicability::MachineApplicable; diff --git a/clippy_lints/src/methods/needless_option_as_deref.rs b/clippy_lints/src/methods/needless_option_as_deref.rs index 538aa9097a40f..d77d044340dca 100644 --- a/clippy_lints/src/methods/needless_option_as_deref.rs +++ b/clippy_lints/src/methods/needless_option_as_deref.rs @@ -1,22 +1,22 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::path_res; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::local_used_after_expr; +use clippy_utils::{path_res, sym}; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_hir::def::Res; use rustc_lint::LateContext; -use rustc_span::sym; +use rustc_span::Symbol; use super::NEEDLESS_OPTION_AS_DEREF; -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name: &str) { +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name: Symbol) { let typeck = cx.typeck_results(); let outer_ty = typeck.expr_ty(expr); if is_type_diagnostic_item(cx, outer_ty, sym::Option) && outer_ty == typeck.expr_ty(recv) { - if name == "as_deref_mut" && recv.is_syntactic_place_expr() { + if name == sym::as_deref_mut && recv.is_syntactic_place_expr() { let Res::Local(binding_id) = path_res(cx, recv) else { return; }; diff --git a/clippy_lints/src/methods/needless_option_take.rs b/clippy_lints/src/methods/needless_option_take.rs index cd1b97f3c51b5..1544a12e6ba83 100644 --- a/clippy_lints/src/methods/needless_option_take.rs +++ b/clippy_lints/src/methods/needless_option_take.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; -use rustc_span::sym; +use rustc_span::{Symbol, sym}; use super::NEEDLESS_OPTION_TAKE; @@ -42,20 +42,20 @@ fn is_expr_option(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// When this function is called, we are reasonably certain that the `ExprKind` is either /// `Call` or `MethodCall` because we already checked that the expression is not /// `is_syntactic_place_expr()`. -fn source_of_temporary_value<'a>(expr: &'a Expr<'_>) -> Option<&'a str> { +fn source_of_temporary_value(expr: &Expr<'_>) -> Option { match expr.peel_borrows().kind { ExprKind::Call(function, _) => { if let ExprKind::Path(QPath::Resolved(_, func_path)) = function.kind && !func_path.segments.is_empty() { - return Some(func_path.segments[0].ident.name.as_str()); + return Some(func_path.segments[0].ident.name); } if let ExprKind::Path(QPath::TypeRelative(_, func_path_segment)) = function.kind { - return Some(func_path_segment.ident.name.as_str()); + return Some(func_path_segment.ident.name); } None }, - ExprKind::MethodCall(path_segment, ..) => Some(path_segment.ident.name.as_str()), + ExprKind::MethodCall(path_segment, ..) => Some(path_segment.ident.name), _ => None, } } diff --git a/clippy_lints/src/methods/obfuscated_if_else.rs b/clippy_lints/src/methods/obfuscated_if_else.rs index 1cc56de48763e..604b48656aeac 100644 --- a/clippy_lints/src/methods/obfuscated_if_else.rs +++ b/clippy_lints/src/methods/obfuscated_if_else.rs @@ -1,13 +1,14 @@ use super::OBFUSCATED_IF_ELSE; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::eager_or_lazy::switch_to_eager_eval; -use clippy_utils::get_parent_expr; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; +use clippy_utils::{get_parent_expr, sym}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::ExprKind; use rustc_lint::LateContext; +use rustc_span::Symbol; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, @@ -15,8 +16,8 @@ pub(super) fn check<'tcx>( then_recv: &'tcx hir::Expr<'_>, then_arg: &'tcx hir::Expr<'_>, unwrap_arg: Option<&'tcx hir::Expr<'_>>, - then_method_name: &str, - unwrap_method_name: &str, + then_method_name: Symbol, + unwrap_method_name: Symbol, ) { let recv_ty = cx.typeck_results().expr_ty(then_recv); @@ -31,25 +32,25 @@ pub(super) fn check<'tcx>( }; let if_then = match then_method_name { - "then" if let ExprKind::Closure(closure) = then_arg.kind => { + sym::then if let ExprKind::Closure(closure) = then_arg.kind => { let body = cx.tcx.hir_body(closure.body); snippet_with_applicability(cx, body.value.span, "..", &mut applicability) }, - "then_some" => snippet_with_applicability(cx, then_arg.span, "..", &mut applicability), + sym::then_some => snippet_with_applicability(cx, then_arg.span, "..", &mut applicability), _ => return, }; // FIXME: Add `unwrap_or_else` and `unwrap_or_default` symbol let els = match unwrap_method_name { - "unwrap_or" => snippet_with_applicability(cx, unwrap_arg.unwrap().span, "..", &mut applicability), - "unwrap_or_else" if let ExprKind::Closure(closure) = unwrap_arg.unwrap().kind => { + sym::unwrap_or => snippet_with_applicability(cx, unwrap_arg.unwrap().span, "..", &mut applicability), + sym::unwrap_or_else if let ExprKind::Closure(closure) = unwrap_arg.unwrap().kind => { let body = cx.tcx.hir_body(closure.body); snippet_with_applicability(cx, body.value.span, "..", &mut applicability) }, - "unwrap_or_else" if let ExprKind::Path(_) = unwrap_arg.unwrap().kind => { + sym::unwrap_or_else if let ExprKind::Path(_) = unwrap_arg.unwrap().kind => { snippet_with_applicability(cx, unwrap_arg.unwrap().span, "_", &mut applicability) + "()" }, - "unwrap_or_default" => "Default::default()".into(), + sym::unwrap_or_default => "Default::default()".into(), _ => return, }; diff --git a/clippy_lints/src/methods/option_as_ref_cloned.rs b/clippy_lints/src/methods/option_as_ref_cloned.rs index 9b22494888fb2..3c38deca6cd1f 100644 --- a/clippy_lints/src/methods/option_as_ref_cloned.rs +++ b/clippy_lints/src/methods/option_as_ref_cloned.rs @@ -1,14 +1,16 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::sym; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_span::{Span, sym}; +use rustc_span::Span; use super::{OPTION_AS_REF_CLONED, method_call}; pub(super) fn check(cx: &LateContext<'_>, cloned_recv: &Expr<'_>, cloned_ident_span: Span) { - if let Some((method @ ("as_ref" | "as_mut"), as_ref_recv, [], as_ref_ident_span, _)) = method_call(cloned_recv) + if let Some((method @ (sym::as_ref | sym::as_mut), as_ref_recv, [], as_ref_ident_span, _)) = + method_call(cloned_recv) && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(as_ref_recv).peel_refs(), sym::Option) { span_lint_and_sugg( diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index b78b082e460ef..c74c42e9e5bd5 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_span: Span, - name: &str, + name: Symbol, receiver: &'tcx hir::Expr<'_>, args: &'tcx [hir::Expr<'_>], ) { @@ -33,7 +33,7 @@ pub(super) fn check<'tcx>( /// `or_insert_with(T::new)` or `or_insert_with(T::default)`. fn check_unwrap_or_default( cx: &LateContext<'_>, - name: &str, + name: Symbol, receiver: &hir::Expr<'_>, fun: &hir::Expr<'_>, call_expr: Option<&hir::Expr<'_>>, @@ -66,8 +66,8 @@ pub(super) fn check<'tcx>( }; let sugg = match (name, call_expr.is_some()) { - ("unwrap_or", true) | ("unwrap_or_else", false) => sym::unwrap_or_default, - ("or_insert", true) | ("or_insert_with", false) => sym::or_default, + (sym::unwrap_or, true) | (sym::unwrap_or_else, false) => sym::unwrap_or_default, + (sym::or_insert, true) | (sym::or_insert_with, false) => sym::or_default, _ => return false, }; @@ -126,7 +126,7 @@ pub(super) fn check<'tcx>( #[expect(clippy::too_many_arguments)] fn check_or_fn_call<'tcx>( cx: &LateContext<'tcx>, - name: &str, + name: Symbol, method_span: Span, self_expr: &hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, @@ -137,11 +137,16 @@ pub(super) fn check<'tcx>( fun_span: Option, ) -> bool { // (path, fn_has_argument, methods, suffix) - const KNOW_TYPES: [(Symbol, bool, &[&str], &str); 4] = [ - (sym::BTreeEntry, false, &["or_insert"], "with"), - (sym::HashMapEntry, false, &["or_insert"], "with"), - (sym::Option, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"), - (sym::Result, true, &["or", "unwrap_or"], "else"), + const KNOW_TYPES: [(Symbol, bool, &[Symbol], &str); 4] = [ + (sym::BTreeEntry, false, &[sym::or_insert], "with"), + (sym::HashMapEntry, false, &[sym::or_insert], "with"), + ( + sym::Option, + false, + &[sym::map_or, sym::ok_or, sym::or, sym::unwrap_or], + "else", + ), + (sym::Result, true, &[sym::or, sym::unwrap_or], "else"), ]; if KNOW_TYPES.iter().any(|k| k.2.contains(&name)) diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index 97c8ce2bcdd28..855babb797a21 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -2,14 +2,13 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::deref_closure_args; use clippy_utils::ty::is_type_lang_item; -use clippy_utils::{is_receiver_of_method_call, is_trait_method, strip_pat_refs}; +use clippy_utils::{is_receiver_of_method_call, is_trait_method, strip_pat_refs, sym}; use hir::ExprKind; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::PatKind; use rustc_lint::LateContext; -use rustc_span::Span; -use rustc_span::symbol::sym; +use rustc_span::{Span, Symbol}; use super::SEARCH_IS_SOME; @@ -19,7 +18,7 @@ use super::SEARCH_IS_SOME; pub(super) fn check<'tcx>( cx: &LateContext<'_>, expr: &'tcx hir::Expr<'_>, - search_method: &str, + search_method: Symbol, is_some: bool, search_recv: &hir::Expr<'_>, search_arg: &'tcx hir::Expr<'_>, @@ -35,7 +34,7 @@ pub(super) fn check<'tcx>( // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()` // suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()` let mut applicability = Applicability::MachineApplicable; - let any_search_snippet = if search_method == "find" + let any_search_snippet = if search_method == sym::find && let ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind && let closure_body = cx.tcx.hir_body(body) && let Some(closure_arg) = closure_body.params.first() @@ -107,7 +106,7 @@ pub(super) fn check<'tcx>( } } // lint if `find()` is called by `String` or `&str` - else if search_method == "find" { + else if search_method == sym::find { let is_string_or_str_slice = |e| { let self_ty = cx.typeck_results().expr_ty(e).peel_refs(); if is_type_lang_item(cx, self_ty, hir::LangItem::String) { diff --git a/clippy_lints/src/methods/str_split.rs b/clippy_lints/src/methods/str_split.rs index fb4ac7b3613dd..479064a0671e5 100644 --- a/clippy_lints/src/methods/str_split.rs +++ b/clippy_lints/src/methods/str_split.rs @@ -15,7 +15,7 @@ pub(super) fn check<'a>(cx: &LateContext<'a>, expr: &'_ Expr<'_>, split_recv: &' // or `"\r\n"`). There are a lot of ways to specify a pattern, and this lint only checks the most // basic ones: a `'\n'`, `"\n"`, and `"\r\n"`. if let ExprKind::MethodCall(trim_method_name, trim_recv, [], _) = split_recv.kind - && trim_method_name.ident.as_str() == "trim" + && trim_method_name.ident.name == sym::trim && cx.typeck_results().expr_ty_adjusted(trim_recv).peel_refs().is_str() && !is_const_evaluatable(cx, trim_recv) && let ExprKind::Lit(split_lit) = split_arg.kind diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index c8efb600f576f..6935ae1f391fa 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -4,7 +4,7 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use clippy_utils::usage::local_used_after_expr; use clippy_utils::visitors::{Descend, for_each_expr}; -use clippy_utils::{is_diag_item_method, path_to_local_id, paths}; +use clippy_utils::{is_diag_item_method, path_to_local_id, paths, sym}; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::{ @@ -12,13 +12,13 @@ use rustc_hir::{ }; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{Span, Symbol, SyntaxContext, sym}; +use rustc_span::{Span, Symbol, SyntaxContext}; use super::{MANUAL_SPLIT_ONCE, NEEDLESS_SPLITN}; pub(super) fn check( cx: &LateContext<'_>, - method_name: &str, + method_name: Symbol, expr: &Expr<'_>, self_arg: &Expr<'_>, pat_arg: &Expr<'_>, @@ -45,9 +45,9 @@ pub(super) fn check( } } -fn lint_needless(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_arg: &Expr<'_>, pat_arg: &Expr<'_>) { +fn lint_needless(cx: &LateContext<'_>, method_name: Symbol, expr: &Expr<'_>, self_arg: &Expr<'_>, pat_arg: &Expr<'_>) { let mut app = Applicability::MachineApplicable; - let r = if method_name == "splitn" { "" } else { "r" }; + let r = if method_name == sym::splitn { "" } else { "r" }; span_lint_and_sugg( cx, @@ -66,14 +66,14 @@ fn lint_needless(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_ fn check_manual_split_once( cx: &LateContext<'_>, - method_name: &str, + method_name: Symbol, expr: &Expr<'_>, self_arg: &Expr<'_>, pat_arg: &Expr<'_>, usage: &IterUsage, ) { let ctxt = expr.span.ctxt(); - let (msg, reverse) = if method_name == "splitn" { + let (msg, reverse) = if method_name == sym::splitn { ("manual implementation of `split_once`", false) } else { ("manual implementation of `rsplit_once`", true) @@ -121,7 +121,7 @@ fn check_manual_split_once( /// ``` fn check_manual_split_once_indirect( cx: &LateContext<'_>, - method_name: &str, + method_name: Symbol, expr: &Expr<'_>, self_arg: &Expr<'_>, pat_arg: &Expr<'_>, @@ -143,7 +143,7 @@ fn check_manual_split_once_indirect( && first.name != second.name && !local_used_after_expr(cx, iter_binding_id, second.init_expr) { - let (r, lhs, rhs) = if method_name == "splitn" { + let (r, lhs, rhs) = if method_name == sym::splitn { ("", first.name, second.name) } else { ("r", second.name, first.name) diff --git a/clippy_lints/src/methods/string_extend_chars.rs b/clippy_lints/src/methods/string_extend_chars.rs index c7885f689d75b..f11a41f90f1ab 100644 --- a/clippy_lints/src/methods/string_extend_chars.rs +++ b/clippy_lints/src/methods/string_extend_chars.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::method_chain_args; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_lang_item; +use clippy_utils::{method_chain_args, sym}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -13,7 +13,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr if !is_type_lang_item(cx, obj_ty, hir::LangItem::String) { return; } - if let Some(arglists) = method_chain_args(arg, &["chars"]) { + if let Some(arglists) = method_chain_args(arg, &[sym::chars]) { let target = &arglists[0].0; let self_ty = cx.typeck_results().expr_ty(target).peel_refs(); let ref_str = if self_ty.is_str() { diff --git a/clippy_lints/src/methods/suspicious_splitn.rs b/clippy_lints/src/methods/suspicious_splitn.rs index ff5c1d1a40193..f8b6d4349fbeb 100644 --- a/clippy_lints/src/methods/suspicious_splitn.rs +++ b/clippy_lints/src/methods/suspicious_splitn.rs @@ -2,11 +2,12 @@ use clippy_utils::diagnostics::span_lint_and_note; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; +use rustc_span::Symbol; use rustc_span::source_map::Spanned; use super::SUSPICIOUS_SPLITN; -pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_arg: &Expr<'_>, count: u128) { +pub(super) fn check(cx: &LateContext<'_>, method_name: Symbol, expr: &Expr<'_>, self_arg: &Expr<'_>, count: u128) { if count <= 1 && let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && let Some(impl_id) = cx.tcx.impl_of_method(call_id) diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index 79ed352193fd7..d260e0ef6e197 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -9,10 +9,16 @@ use rustc_hir as hir; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_lint::LateContext; use rustc_middle::ty; +use rustc_span::Symbol; use super::{UNNECESSARY_FILTER_MAP, UNNECESSARY_FIND_MAP}; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>, name: &str) { +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + arg: &'tcx hir::Expr<'tcx>, + name: Symbol, +) { if !is_trait_method(cx, expr, sym::Iterator) { return; } @@ -38,7 +44,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a let in_ty = cx.typeck_results().node_type(body.params[0].hir_id); let sugg = if !found_filtering { // Check if the closure is .filter_map(|x| Some(x)) - if name == "filter_map" + if name == sym::filter_map && let hir::ExprKind::Call(expr, args) = body.value.kind && is_res_lang_ctor(cx, path_res(cx, expr), OptionSome) && let hir::ExprKind::Path(_) = args[0].kind @@ -51,7 +57,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a ); return; } - if name == "filter_map" { + if name == sym::filter_map { "map(..)" } else { "map(..).next()" @@ -61,7 +67,11 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a ty::Adt(adt, subst) if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && in_ty == subst.type_at(0) => { - if name == "filter_map" { "filter(..)" } else { "find(..)" } + if name == sym::filter_map { + "filter(..)" + } else { + "find(..)" + } }, _ => return, } @@ -70,7 +80,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a }; span_lint( cx, - if name == "filter_map" { + if name == sym::filter_map { UNNECESSARY_FILTER_MAP } else { UNNECESSARY_FIND_MAP diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index fa3a29e366709..cc4448192d3e7 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -1,10 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{MaybePath, is_res_lang_ctor, last_path_segment, path_res}; +use clippy_utils::{MaybePath, is_res_lang_ctor, last_path_segment, path_res, sym}; use rustc_errors::Applicability; use rustc_hir::{self as hir, AmbigArg}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_middle::ty::print::with_forced_trimmed_paths; +use rustc_span::Symbol; use super::UNNECESSARY_LITERAL_UNWRAP; @@ -25,7 +26,7 @@ pub(super) fn check( cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, - method: &str, + method: Symbol, args: &[hir::Expr<'_>], ) { let init = clippy_utils::expr_or_init(cx, recv); @@ -42,17 +43,17 @@ pub(super) fn check( let res = cx.qpath_res(qpath, call.hir_id()); if is_res_lang_ctor(cx, res, hir::LangItem::OptionSome) { - ("Some", call_args, get_ty_from_args(args, 0)) + (sym::Some, call_args, get_ty_from_args(args, 0)) } else if is_res_lang_ctor(cx, res, hir::LangItem::ResultOk) { - ("Ok", call_args, get_ty_from_args(args, 0)) + (sym::Ok, call_args, get_ty_from_args(args, 0)) } else if is_res_lang_ctor(cx, res, hir::LangItem::ResultErr) { - ("Err", call_args, get_ty_from_args(args, 1)) + (sym::Err, call_args, get_ty_from_args(args, 1)) } else { return; } } else if is_res_lang_ctor(cx, path_res(cx, init), hir::LangItem::OptionNone) { let call_args: &[hir::Expr<'_>] = &[]; - ("None", call_args, None) + (sym::None, call_args, None) } else { return; }; @@ -62,12 +63,12 @@ pub(super) fn check( span_lint_and_then(cx, UNNECESSARY_LITERAL_UNWRAP, expr.span, help_message, |diag| { let suggestions = match (constructor, method, ty) { - ("None", "unwrap", _) => Some(vec![(expr.span, "panic!()".to_string())]), - ("None", "expect", _) => Some(vec![ + (sym::None, sym::unwrap, _) => Some(vec![(expr.span, "panic!()".to_string())]), + (sym::None, sym::expect, _) => Some(vec![ (expr.span.with_hi(args[0].span.lo()), "panic!(".to_string()), (expr.span.with_lo(args[0].span.hi()), ")".to_string()), ]), - ("Some" | "Ok", "unwrap_unchecked", _) | ("Err", "unwrap_err_unchecked", _) => { + (sym::Some | sym::Ok, sym::unwrap_unchecked, _) | (sym::Err, sym::unwrap_err_unchecked, _) => { let mut suggs = vec![ (recv.span.with_hi(call_args[0].span.lo()), String::new()), (expr.span.with_lo(call_args[0].span.hi()), String::new()), @@ -83,7 +84,7 @@ pub(super) fn check( } Some(suggs) }, - ("None", "unwrap_or_default", _) => { + (sym::None, sym::unwrap_or_default, _) => { let ty = cx.typeck_results().expr_ty(expr); let default_ty_string = if let ty::Adt(def, ..) = ty.kind() { with_forced_trimmed_paths!(format!("{}", cx.tcx.def_path_str(def.did()))) @@ -92,11 +93,11 @@ pub(super) fn check( }; Some(vec![(expr.span, format!("{default_ty_string}::default()"))]) }, - ("None", "unwrap_or", _) => Some(vec![ + (sym::None, sym::unwrap_or, _) => Some(vec![ (expr.span.with_hi(args[0].span.lo()), String::new()), (expr.span.with_lo(args[0].span.hi()), String::new()), ]), - ("None", "unwrap_or_else", _) => match args[0].kind { + (sym::None, sym::unwrap_or_else, _) => match args[0].kind { hir::ExprKind::Closure(hir::Closure { body, .. }) => Some(vec![ (expr.span.with_hi(cx.tcx.hir_body(*body).value.span.lo()), String::new()), (expr.span.with_lo(args[0].span.hi()), String::new()), @@ -105,14 +106,14 @@ pub(super) fn check( }, _ if call_args.is_empty() => None, (_, _, Some(_)) => None, - ("Ok", "unwrap_err", None) | ("Err", "unwrap", None) => Some(vec![ + (sym::Ok, sym::unwrap_err, None) | (sym::Err, sym::unwrap, None) => Some(vec![ ( recv.span.with_hi(call_args[0].span.lo()), "panic!(\"{:?}\", ".to_string(), ), (expr.span.with_lo(call_args[0].span.hi()), ")".to_string()), ]), - ("Ok", "expect_err", None) | ("Err", "expect", None) => Some(vec![ + (sym::Ok, sym::expect_err, None) | (sym::Err, sym::expect, None) => Some(vec![ ( recv.span.with_hi(call_args[0].span.lo()), "panic!(\"{1}: {:?}\", ".to_string(), diff --git a/clippy_lints/src/methods/unnecessary_min_or_max.rs b/clippy_lints/src/methods/unnecessary_min_or_max.rs index 7d01bdc2269bd..413881d5ec99e 100644 --- a/clippy_lints/src/methods/unnecessary_min_or_max.rs +++ b/clippy_lints/src/methods/unnecessary_min_or_max.rs @@ -5,16 +5,17 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant, ConstantSource, FullInt}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; +use clippy_utils::sym; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{Span, sym}; +use rustc_span::{Span, Symbol}; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, - name: &str, + name: Symbol, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>, ) { @@ -47,10 +48,10 @@ pub(super) fn check<'tcx>( } } -fn lint(cx: &LateContext<'_>, expr: &Expr<'_>, name: &str, lhs: Span, rhs: Span, order: Ordering) { +fn lint(cx: &LateContext<'_>, expr: &Expr<'_>, name: Symbol, lhs: Span, rhs: Span, order: Ordering) { let cmp_str = if order.is_ge() { "smaller" } else { "greater" }; - let suggested_value = if (name == "min" && order.is_ge()) || (name == "max" && order.is_le()) { + let suggested_value = if (name == sym::min && order.is_ge()) || (name == sym::max && order.is_le()) { snippet(cx, rhs, "..") } else { snippet(cx, lhs, "..") diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index d4d170f4d49c2..29a0d2950bc6a 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -619,7 +619,7 @@ fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id: /// Returns true if the named method can be used to convert the receiver to its "owned" /// representation. fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name: Symbol, method_def_id: DefId) -> bool { - is_clone_like(cx, method_name.as_str(), method_def_id) + is_clone_like(cx, method_name, method_def_id) || is_cow_into_owned(cx, method_name, method_def_id) || is_to_string_on_string_like(cx, call_expr, method_name, method_def_id) } @@ -686,11 +686,11 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, expr) = arg.kind && let ExprKind::MethodCall(method_path, caller, &[], _) = expr.kind && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) - && let method_name = method_path.ident.name.as_str() + && let method_name = method_path.ident.name && match method_name { - "to_owned" => cx.tcx.is_diagnostic_item(sym::to_owned_method, method_def_id), - "to_string" => cx.tcx.is_diagnostic_item(sym::to_string_method, method_def_id), - "to_vec" => cx + sym::to_owned => cx.tcx.is_diagnostic_item(sym::to_owned_method, method_def_id), + sym::to_string => cx.tcx.is_diagnostic_item(sym::to_string_method, method_def_id), + sym::to_vec => cx .tcx .impl_of_method(method_def_id) .filter(|&impl_did| cx.tcx.type_of(impl_did).instantiate_identity().is_slice()) diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs index 56d2c407c054e..d30c12e0c4830 100644 --- a/clippy_lints/src/methods/useless_asref.rs +++ b/clippy_lints/src/methods/useless_asref.rs @@ -7,7 +7,7 @@ use rustc_hir::{self as hir, LangItem}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use rustc_span::{Span, sym}; +use rustc_span::{Span, Symbol, sym}; use core::ops::ControlFlow; @@ -39,7 +39,7 @@ fn get_enum_ty(enum_ty: Ty<'_>) -> Option> { } /// Checks for the `USELESS_ASREF` lint. -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, recvr: &hir::Expr<'_>) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: Symbol, recvr: &hir::Expr<'_>) { // when we get here, we've already checked that the call name is "as_ref" or "as_mut" // check if the call is to the actual `AsRef` or `AsMut` trait let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) else { @@ -161,7 +161,7 @@ fn is_calling_clone(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool { } } -fn lint_as_ref_clone(cx: &LateContext<'_>, span: Span, recvr: &hir::Expr<'_>, call_name: &str) { +fn lint_as_ref_clone(cx: &LateContext<'_>, span: Span, recvr: &hir::Expr<'_>, call_name: Symbol) { let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/wrong_self_convention.rs b/clippy_lints/src/methods/wrong_self_convention.rs index 7384e534ed7d7..ad9b3c3645425 100644 --- a/clippy_lints/src/methods/wrong_self_convention.rs +++ b/clippy_lints/src/methods/wrong_self_convention.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::is_copy; use rustc_lint::LateContext; use rustc_middle::ty::Ty; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use std::fmt; use super::WRONG_SELF_CONVENTION; @@ -83,17 +83,18 @@ impl fmt::Display for Convention { #[allow(clippy::too_many_arguments)] pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, - item_name: &str, + item_name: Symbol, self_ty: Ty<'tcx>, first_arg_ty: Ty<'tcx>, first_arg_span: Span, implements_trait: bool, is_trait_item: bool, ) { + let item_name_str = item_name.as_str(); if let Some((conventions, self_kinds)) = &CONVENTIONS.iter().find(|(convs, _)| { convs .iter() - .all(|conv| conv.check(cx, self_ty, item_name, implements_trait, is_trait_item)) + .all(|conv| conv.check(cx, self_ty, item_name_str, implements_trait, is_trait_item)) }) { // don't lint if it implements a trait but not willing to check `Copy` types conventions (see #7032) if implements_trait diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index f768e11a4a2bb..3ed4b1c2ea947 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use clippy_utils::{ SpanlessEq, get_parent_expr, higher, is_block_like, is_else_clause, is_expn_of, is_parent_stmt, - is_receiver_of_method_call, peel_blocks, peel_blocks_with_stmt, span_extract_comment, + is_receiver_of_method_call, peel_blocks, peel_blocks_with_stmt, span_extract_comment, sym, }; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -320,7 +320,7 @@ fn check_comparison<'a, 'tcx>( cx.typeck_results().expr_ty(left_side), cx.typeck_results().expr_ty(right_side), ); - if is_expn_of(left_side.span, "cfg").is_some() || is_expn_of(right_side.span, "cfg").is_some() { + if is_expn_of(left_side.span, sym::cfg).is_some() || is_expn_of(right_side.span, sym::cfg).is_some() { return; } if l_ty.is_bool() && r_ty.is_bool() { diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 275d710c76a9b..95623467b8153 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -212,7 +212,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { } if is_type_diagnostic_item(cx, ty, sym::Vec) - && let Some(clone_spans) = get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")]) + && let Some(clone_spans) = get_spans(cx, Some(body.id()), idx, &[(sym::clone, ".to_owned()")]) && let TyKind::Path(QPath::Resolved(_, path)) = input.kind && let Some(elem_ty) = path .segments @@ -253,8 +253,12 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { } if is_type_lang_item(cx, ty, LangItem::String) - && let Some(clone_spans) = - get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")]) + && let Some(clone_spans) = get_spans( + cx, + Some(body.id()), + idx, + &[(sym::clone, ".to_string()"), (sym::as_str, "")], + ) { diag.span_suggestion( input.span, diff --git a/clippy_lints/src/operators/duration_subsec.rs b/clippy_lints/src/operators/duration_subsec.rs index e3029f8438e5f..6c9be7c5e90b3 100644 --- a/clippy_lints/src/operators/duration_subsec.rs +++ b/clippy_lints/src/operators/duration_subsec.rs @@ -1,11 +1,11 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sym; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::sym; use super::DURATION_SUBSEC; @@ -21,9 +21,9 @@ pub(crate) fn check<'tcx>( && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_arg).peel_refs(), sym::Duration) && let Some(Constant::Int(divisor)) = ConstEvalCtxt::new(cx).eval(right) { - let suggested_fn = match (method_path.ident.as_str(), divisor) { - ("subsec_micros", 1_000) | ("subsec_nanos", 1_000_000) => "subsec_millis", - ("subsec_nanos", 1_000) => "subsec_micros", + let suggested_fn = match (method_path.ident.name, divisor) { + (sym::subsec_micros, 1_000) | (sym::subsec_nanos, 1_000_000) => "subsec_millis", + (sym::subsec_nanos, 1_000) => "subsec_micros", _ => return, }; let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_lints/src/option_env_unwrap.rs b/clippy_lints/src/option_env_unwrap.rs index d16f5f8e112c3..64ad92b1ebb50 100644 --- a/clippy_lints/src/option_env_unwrap.rs +++ b/clippy_lints/src/option_env_unwrap.rs @@ -37,7 +37,7 @@ impl EarlyLintPass for OptionEnvUnwrap { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind && matches!(seg.ident.name, sym::expect | sym::unwrap) - && is_direct_expn_of(receiver.span, "option_env").is_some() + && is_direct_expn_of(receiver.span, sym::option_env).is_some() { span_lint_and_help( cx, diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index ccb1209c6fcbe..f3fea3add592d 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{indent_of, snippet}; -use clippy_utils::{expr_or_init, get_attr, path_to_local, peel_hir_expr_unary}; +use clippy_utils::{expr_or_init, get_attr, path_to_local, peel_hir_expr_unary, sym}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::{GenericArgKind, Ty}; use rustc_session::impl_lint_pass; use rustc_span::symbol::Ident; -use rustc_span::{DUMMY_SP, Span, sym}; +use rustc_span::{DUMMY_SP, Span}; use std::borrow::Cow; use std::collections::hash_map::Entry; @@ -169,7 +169,7 @@ impl<'cx, 'others, 'tcx> AttrChecker<'cx, 'others, 'tcx> { let mut iter = get_attr( self.cx.sess(), self.cx.tcx.get_attrs_unchecked(adt.did()), - "has_significant_drop", + sym::has_significant_drop, ); if iter.next().is_some() { return true; diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs index 835ec1e4ca1c7..3623039aece15 100644 --- a/clippy_lints/src/size_of_in_element_count.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -1,9 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::sym; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; -use rustc_span::sym; +use rustc_span::Symbol; declare_clippy_lint! { /// ### What it does @@ -62,17 +63,17 @@ fn get_pointee_ty_and_count_expr<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> { - const METHODS: [&str; 10] = [ - "copy_to", - "copy_from", - "copy_to_nonoverlapping", - "copy_from_nonoverlapping", - "add", - "wrapping_add", - "sub", - "wrapping_sub", - "offset", - "wrapping_offset", + const METHODS: [Symbol; 10] = [ + sym::copy_to, + sym::copy_from, + sym::copy_to_nonoverlapping, + sym::copy_from_nonoverlapping, + sym::add, + sym::wrapping_add, + sym::sub, + sym::wrapping_sub, + sym::offset, + sym::wrapping_offset, ]; if let ExprKind::Call(func, [.., count]) = expr.kind @@ -97,7 +98,7 @@ fn get_pointee_ty_and_count_expr<'tcx>( } if let ExprKind::MethodCall(method_path, ptr_self, [.., count], _) = expr.kind // Find calls to copy_{from,to}{,_nonoverlapping} - && let method_ident = method_path.ident.as_str() + && let method_ident = method_path.ident.name && METHODS.contains(&method_ident) // Get the pointee type diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 30a5fe4db27e1..f497d0700b8eb 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -266,7 +266,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> { let is_matching_resize = if let InitializedSize::Initialized(size_expr) = self.vec_alloc.size_expr { // If we have a size expression, check that it is equal to what's passed to `resize` SpanlessEq::new(self.cx).eq_expr(len_arg, size_expr) - || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.as_str() == "capacity") + || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.name == sym::capacity) } else { self.vec_alloc.size_expr = InitializedSize::Initialized(len_arg); true @@ -288,7 +288,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> { if let InitializedSize::Initialized(size_expr) = self.vec_alloc.size_expr { // Check that len expression is equals to `with_capacity` expression return SpanlessEq::new(self.cx).eq_expr(len_arg, size_expr) - || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.as_str() == "capacity"); + || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.name == sym::capacity); } self.vec_alloc.size_expr = InitializedSize::Initialized(len_arg); diff --git a/clippy_lints/src/string_patterns.rs b/clippy_lints/src/string_patterns.rs index 5c95dfe834730..f63e6b3087b9e 100644 --- a/clippy_lints/src/string_patterns.rs +++ b/clippy_lints/src/string_patterns.rs @@ -5,9 +5,9 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::macros::matching_root_macro_call; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::path_to_local_id; use clippy_utils::source::{snippet, str_literal_to_char_literal}; use clippy_utils::visitors::{Descend, for_each_expr}; +use clippy_utils::{path_to_local_id, sym}; use itertools::Itertools; use rustc_ast::{BinOpKind, LitKind}; use rustc_errors::Applicability; @@ -15,7 +15,7 @@ use rustc_hir::{Expr, ExprKind, PatExprKind, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -83,29 +83,29 @@ impl StringPatterns { impl_lint_pass!(StringPatterns => [MANUAL_PATTERN_CHAR_COMPARISON, SINGLE_CHAR_PATTERN]); -const PATTERN_METHODS: [(&str, usize); 22] = [ - ("contains", 0), - ("starts_with", 0), - ("ends_with", 0), - ("find", 0), - ("rfind", 0), - ("split", 0), - ("split_inclusive", 0), - ("rsplit", 0), - ("split_terminator", 0), - ("rsplit_terminator", 0), - ("splitn", 1), - ("rsplitn", 1), - ("split_once", 0), - ("rsplit_once", 0), - ("matches", 0), - ("rmatches", 0), - ("match_indices", 0), - ("rmatch_indices", 0), - ("trim_start_matches", 0), - ("trim_end_matches", 0), - ("replace", 0), - ("replacen", 0), +const PATTERN_METHODS: [(Symbol, usize); 22] = [ + (sym::contains, 0), + (sym::starts_with, 0), + (sym::ends_with, 0), + (sym::find, 0), + (sym::rfind, 0), + (sym::split, 0), + (sym::split_inclusive, 0), + (sym::rsplit, 0), + (sym::split_terminator, 0), + (sym::rsplit_terminator, 0), + (sym::splitn, 1), + (sym::rsplitn, 1), + (sym::split_once, 0), + (sym::rsplit_once, 0), + (sym::matches, 0), + (sym::rmatches, 0), + (sym::match_indices, 0), + (sym::rmatch_indices, 0), + (sym::trim_start_matches, 0), + (sym::trim_end_matches, 0), + (sym::replace, 0), + (sym::replacen, 0), ]; fn check_single_char_pattern_lint(cx: &LateContext<'_>, arg: &Expr<'_>) { @@ -228,7 +228,7 @@ impl<'tcx> LateLintPass<'tcx> for StringPatterns { && let ExprKind::MethodCall(method, receiver, args, _) = expr.kind && let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind() && ty.is_str() - && let method_name = method.ident.name.as_str() + && let method_name = method.ident.name && let Some(&(_, pos)) = PATTERN_METHODS .iter() .find(|(array_method_name, _)| *array_method_name == method_name) diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs index 1ada7094dc550..33856c750d7e9 100644 --- a/clippy_lints/src/strlen_on_c_strings.rs +++ b/clippy_lints/src/strlen_on_c_strings.rs @@ -1,13 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::match_libc_symbol; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::visitors::is_expr_unsafe; +use clippy_utils::{match_libc_symbol, sym}; use rustc_errors::Applicability; use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, LangItem, Node, UnsafeSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::sym; declare_clippy_lint! { /// ### What it does @@ -44,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings { && let ExprKind::Call(func, [recv]) = expr.kind && let ExprKind::Path(path) = &func.kind && let Some(did) = cx.qpath_res(path, func.hir_id).opt_def_id() - && match_libc_symbol(cx, did, "strlen") + && match_libc_symbol(cx, did, sym::strlen) && let ExprKind::MethodCall(path, self_arg, [], _) = recv.kind && !recv.span.from_expansion() && path.ident.name == sym::as_ptr diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs index 7487e273caa7e..1f5351e32aacf 100644 --- a/clippy_lints/src/unused_peekable.rs +++ b/clippy_lints/src/unused_peekable.rs @@ -1,13 +1,12 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable}; -use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators}; +use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators, sym}; use rustc_ast::Mutability; use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Block, Expr, ExprKind, HirId, LetStmt, Node, PatKind, PathSegment, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_session::declare_lint_pass; -use rustc_span::sym; use std::ops::ControlFlow; declare_clippy_lint! { @@ -150,10 +149,10 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> { remaining_args, _, ) => { - let method_name = method_name_ident.name.as_str(); + let method_name = method_name_ident.name; // `Peekable` methods - if matches!(method_name, "peek" | "peek_mut" | "next_if" | "next_if_eq") + if matches!(method_name, sym::peek | sym::peek_mut | sym::next_if | sym::next_if_eq) && arg_is_mut_peekable(self.cx, self_arg) { return ControlFlow::Break(()); @@ -167,7 +166,7 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> { } // foo.by_ref(), keep checking for `peek` - if method_name == "by_ref" { + if method_name == sym::by_ref { continue; } diff --git a/clippy_lints/src/unused_rounding.rs b/clippy_lints/src/unused_rounding.rs index 3e5afec541c49..c21004b5362dd 100644 --- a/clippy_lints/src/unused_rounding.rs +++ b/clippy_lints/src/unused_rounding.rs @@ -1,9 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; +use clippy_utils::sym; use rustc_ast::ast::{Expr, ExprKind, MethodCall}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; +use rustc_span::Symbol; declare_clippy_lint! { /// ### What it does @@ -30,19 +32,20 @@ declare_clippy_lint! { } declare_lint_pass!(UnusedRounding => [UNUSED_ROUNDING]); -fn is_useless_rounding<'a>(cx: &EarlyContext<'_>, expr: &'a Expr) -> Option<(&'a str, String)> { +fn is_useless_rounding(cx: &EarlyContext<'_>, expr: &Expr) -> Option<(Symbol, String)> { if let ExprKind::MethodCall(box MethodCall { seg: name_ident, receiver, .. }) = &expr.kind - && let method_name = name_ident.ident.name.as_str() - && (method_name == "ceil" || method_name == "round" || method_name == "floor") + && let method_name = name_ident.ident.name + && matches!(method_name, sym::ceil | sym::floor | sym::round) && let ExprKind::Lit(token_lit) = &receiver.kind && token_lit.is_semantic_float() && let Ok(f) = token_lit.symbol.as_str().replace('_', "").parse::() + && f.fract() == 0.0 { - (f.fract() == 0.0).then(|| (method_name, snippet(cx, receiver.span, "..").to_string())) + Some((method_name, snippet(cx, receiver.span, "..").into())) } else { None } diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index f870eb71e19b9..7bec212a23ca0 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -79,7 +79,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tc let mut result = Vec::new(); let _: Option = for_each_expr(cx, body.value, |e| { // check for `expect` - if let Some(arglists) = method_chain_args(e, &["expect"]) { + if let Some(arglists) = method_chain_args(e, &[sym::expect]) { let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs(); if is_type_diagnostic_item(cx, receiver_ty, sym::Option) || is_type_diagnostic_item(cx, receiver_ty, sym::Result) @@ -89,7 +89,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tc } // check for `unwrap` - if let Some(arglists) = method_chain_args(e, &["unwrap"]) { + if let Some(arglists) = method_chain_args(e, &[sym::unwrap]) { let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs(); if is_type_diagnostic_item(cx, receiver_ty, sym::Option) || is_type_diagnostic_item(cx, receiver_ty, sym::Result) diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index c04fcf622b909..380ddea4e1e83 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -3,7 +3,7 @@ use clippy_utils::source::{snippet, snippet_with_context}; use clippy_utils::sugg::{DiagExt as _, Sugg}; use clippy_utils::ty::{get_type_diagnostic_name, is_copy, is_type_diagnostic_item, same_type_and_consts}; use clippy_utils::{ - get_parent_expr, is_inherent_method_call, is_trait_item, is_trait_method, is_ty_alias, path_to_local, + get_parent_expr, is_inherent_method_call, is_trait_item, is_trait_method, is_ty_alias, path_to_local, sym, }; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; @@ -15,7 +15,7 @@ use rustc_middle::traits::ObligationCause; use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::{self, EarlyBinder, GenericArg, GenericArgsRef, Ty, TypeVisitableExt}; use rustc_session::impl_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::Span; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; declare_clippy_lint! { @@ -177,7 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { }, ExprKind::MethodCall(name, recv, [], _) => { - if is_trait_method(cx, e, sym::Into) && name.ident.as_str() == "into" { + if is_trait_method(cx, e, sym::Into) && name.ident.name == sym::into { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(recv); if same_type_and_consts(a, b) { diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 812c4df4ddde5..3a08531cf1c9c 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -1,4 +1,4 @@ -use clippy_utils::{MaybePath, get_attr, higher, path_def_id}; +use clippy_utils::{MaybePath, get_attr, higher, path_def_id, sym}; use itertools::Itertools; use rustc_ast::LitIntType; use rustc_ast::ast::{LitFloatType, LitKind}; @@ -826,5 +826,5 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { fn has_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool { let attrs = cx.tcx.hir_attrs(hir_id); - get_attr(cx.sess(), attrs, "author").count() > 0 + get_attr(cx.sess(), attrs, sym::author).count() > 0 } diff --git a/clippy_lints/src/utils/dump_hir.rs b/clippy_lints/src/utils/dump_hir.rs index 9910be9bc2853..d6cf07fdaf3f8 100644 --- a/clippy_lints/src/utils/dump_hir.rs +++ b/clippy_lints/src/utils/dump_hir.rs @@ -1,4 +1,4 @@ -use clippy_utils::get_attr; +use clippy_utils::{get_attr, sym}; use hir::TraitItem; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -60,5 +60,5 @@ impl<'tcx> LateLintPass<'tcx> for DumpHir { fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool { let attrs = cx.tcx.hir_attrs(hir_id); - get_attr(cx.sess(), attrs, "dump").count() > 0 + get_attr(cx.sess(), attrs, sym::dump).count() > 0 } diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 3346b15dae9ca..7b6a25123e85e 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -8,14 +8,14 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::is_copy; use clippy_utils::visitors::for_each_local_use_after_expr; -use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method, span_contains_comment}; +use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method, span_contains_comment, sym}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, LetStmt, Mutability, Node, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::layout::LayoutOf; use rustc_session::impl_lint_pass; -use rustc_span::{DesugaringKind, Span, sym}; +use rustc_span::{DesugaringKind, Span}; pub struct UselessVec { too_large_for_stack: u64, @@ -249,10 +249,8 @@ fn adjusts_to_slice(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { /// that also exists on slices. If this returns true, it means that /// this expression does not actually require a `Vec` and could just work with an array. pub fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { - const ALLOWED_METHOD_NAMES: &[&str] = &["len", "as_ptr", "is_empty"]; - if let ExprKind::MethodCall(path, _, [], _) = e.kind { - ALLOWED_METHOD_NAMES.contains(&path.ident.name.as_str()) + matches!(path.ident.name, sym::as_ptr | sym::is_empty | sym::len) } else { is_trait_method(cx, e, sym::IntoIterator) } diff --git a/clippy_lints_internal/src/outer_expn_data_pass.rs b/clippy_lints_internal/src/outer_expn_data_pass.rs index 1d0b61ede48b3..4d8a6e130f77d 100644 --- a/clippy_lints_internal/src/outer_expn_data_pass.rs +++ b/clippy_lints_internal/src/outer_expn_data_pass.rs @@ -1,11 +1,10 @@ use crate::internal_paths; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{is_lint_allowed, method_calls}; +use clippy_utils::{is_lint_allowed, method_calls, sym}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::symbol::Symbol; declare_tool_lint! { /// ### What it does @@ -39,8 +38,7 @@ impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass { } let (method_names, arg_lists, spans) = method_calls(expr, 2); - let method_names: Vec<&str> = method_names.iter().map(Symbol::as_str).collect(); - if let ["expn_data", "outer_expn"] = method_names.as_slice() + if let [sym::expn_data, sym::outer_expn] = method_names.as_slice() && let (self_arg, args) = arg_lists[1] && args.is_empty() && let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs() diff --git a/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs b/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs index 2d478fa04af8e..9ca4ae31d455c 100644 --- a/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs +++ b/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint; +use clippy_utils::sym; use rustc_ast::ast::{Crate, ItemKind, ModKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -25,11 +26,11 @@ impl EarlyLintPass for UnsortedClippyUtilsPaths { if let Some(utils) = krate .items .iter() - .find(|item| item.kind.ident().is_some_and(|i| i.name.as_str() == "utils")) + .find(|item| item.kind.ident().is_some_and(|i| i.name == sym::utils)) && let ItemKind::Mod(_, _, ModKind::Loaded(ref items, ..)) = utils.kind && let Some(paths) = items .iter() - .find(|item| item.kind.ident().is_some_and(|i| i.name.as_str() == "paths")) + .find(|item| item.kind.ident().is_some_and(|i| i.name == sym::paths)) && let ItemKind::Mod(_, _, ModKind::Loaded(ref items, ..)) = paths.kind { let mut last_name: Option = None; diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 09de5c055379f..8a0ff5323c98d 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -5,11 +5,11 @@ use rustc_lexer::TokenKind; use rustc_lint::LateContext; use rustc_middle::ty::{AdtDef, TyCtxt}; use rustc_session::Session; -use rustc_span::{Span, sym}; +use rustc_span::{Span, Symbol}; use std::str::FromStr; use crate::source::SpanRangeExt; -use crate::tokenize_with_text; +use crate::{sym, tokenize_with_text}; /// Deprecation status of attributes known by Clippy. pub enum DeprecationStatus { @@ -21,17 +21,17 @@ pub enum DeprecationStatus { } #[rustfmt::skip] -pub const BUILTIN_ATTRIBUTES: &[(&str, DeprecationStatus)] = &[ - ("author", DeprecationStatus::None), - ("version", DeprecationStatus::None), - ("cognitive_complexity", DeprecationStatus::None), - ("cyclomatic_complexity", DeprecationStatus::Replaced("cognitive_complexity")), - ("dump", DeprecationStatus::None), - ("msrv", DeprecationStatus::None), +pub const BUILTIN_ATTRIBUTES: &[(Symbol, DeprecationStatus)] = &[ + (sym::author, DeprecationStatus::None), + (sym::version, DeprecationStatus::None), + (sym::cognitive_complexity, DeprecationStatus::None), + (sym::cyclomatic_complexity, DeprecationStatus::Replaced("cognitive_complexity")), + (sym::dump, DeprecationStatus::None), + (sym::msrv, DeprecationStatus::None), // The following attributes are for the 3rd party crate authors. // See book/src/attribs.md - ("has_significant_drop", DeprecationStatus::None), - ("format_args", DeprecationStatus::None), + (sym::has_significant_drop, DeprecationStatus::None), + (sym::format_args, DeprecationStatus::None), ]; pub struct LimitStack { @@ -52,11 +52,11 @@ impl LimitStack { pub fn limit(&self) -> u64 { *self.stack.last().expect("there should always be a value in the stack") } - pub fn push_attrs(&mut self, sess: &Session, attrs: &[impl AttributeExt], name: &'static str) { + pub fn push_attrs(&mut self, sess: &Session, attrs: &[impl AttributeExt], name: Symbol) { let stack = &mut self.stack; parse_attrs(sess, attrs, name, |val| stack.push(val)); } - pub fn pop_attrs(&mut self, sess: &Session, attrs: &[impl AttributeExt], name: &'static str) { + pub fn pop_attrs(&mut self, sess: &Session, attrs: &[impl AttributeExt], name: Symbol) { let stack = &mut self.stack; parse_attrs(sess, attrs, name, |val| assert_eq!(stack.pop(), Some(val))); } @@ -65,7 +65,7 @@ impl LimitStack { pub fn get_attr<'a, A: AttributeExt + 'a>( sess: &'a Session, attrs: &'a [A], - name: &'static str, + name: Symbol, ) -> impl Iterator { attrs.iter().filter(move |attr| { let Some(attr_segments) = attr.ident_path() else { @@ -75,8 +75,8 @@ pub fn get_attr<'a, A: AttributeExt + 'a>( if attr_segments.len() == 2 && attr_segments[0].name == sym::clippy { BUILTIN_ATTRIBUTES .iter() - .find_map(|&(builtin_name, ref deprecation_status)| { - if attr_segments[1].name.as_str() == builtin_name { + .find_map(|(builtin_name, deprecation_status)| { + if attr_segments[1].name == *builtin_name { Some(deprecation_status) } else { None @@ -108,7 +108,7 @@ pub fn get_attr<'a, A: AttributeExt + 'a>( }, DeprecationStatus::None => { diag.cancel(); - attr_segments[1].as_str() == name + attr_segments[1].name == name }, } }, @@ -119,9 +119,9 @@ pub fn get_attr<'a, A: AttributeExt + 'a>( }) } -fn parse_attrs(sess: &Session, attrs: &[impl AttributeExt], name: &'static str, mut f: F) { +fn parse_attrs(sess: &Session, attrs: &[impl AttributeExt], name: Symbol, mut f: F) { for attr in get_attr(sess, attrs, name) { - if let Some(ref value) = attr.value_str() { + if let Some(value) = attr.value_str() { if let Ok(value) = FromStr::from_str(value.as_str()) { f(value); } else { @@ -133,7 +133,7 @@ fn parse_attrs(sess: &Session, attrs: &[impl AttributeExt], name: } } -pub fn get_unique_attr<'a, A: AttributeExt>(sess: &'a Session, attrs: &'a [A], name: &'static str) -> Option<&'a A> { +pub fn get_unique_attr<'a, A: AttributeExt>(sess: &'a Session, attrs: &'a [A], name: Symbol) -> Option<&'a A> { let mut unique_attr: Option<&A> = None; for attr in get_attr(sess, attrs, name) { if let Some(duplicate) = unique_attr { diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index b9928b8eed497..6f5b0ec54cd85 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -487,7 +487,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> { ExprKind::Path(ref qpath) => self.qpath(qpath, e.hir_id), ExprKind::Block(block, _) => self.block(block), ExprKind::Lit(lit) => { - if is_direct_expn_of(e.span, "cfg").is_some() { + if is_direct_expn_of(e.span, sym::cfg).is_some() { None } else { Some(lit_to_mir_constant(&lit.node, self.typeck.expr_ty_opt(e))) @@ -565,7 +565,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> { }) }, ExprKind::Lit(lit) => { - if is_direct_expn_of(e.span, "cfg").is_some() { + if is_direct_expn_of(e.span, sym::cfg).is_some() { None } else { match &lit.node { @@ -654,7 +654,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> { span, .. }) = self.tcx.hir_node(body_id.hir_id) - && is_direct_expn_of(*span, "cfg").is_some() + && is_direct_expn_of(*span, sym::cfg).is_some() { return None; } diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index 4543a20cc2cd4..9d38672efada9 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -10,6 +10,7 @@ //! - option-if-let-else use crate::consts::{ConstEvalCtxt, FullInt}; +use crate::sym; use crate::ty::{all_predicates_of, is_copy}; use crate::visitors::is_const_evaluatable; use rustc_hir::def::{DefKind, Res}; @@ -19,7 +20,7 @@ use rustc_hir::{BinOpKind, Block, Expr, ExprKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_middle::ty::adjustment::Adjust; -use rustc_span::{Symbol, sym}; +use rustc_span::Symbol; use std::{cmp, ops}; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] @@ -49,14 +50,13 @@ impl ops::BitOrAssign for EagernessSuggestion { /// Determine the eagerness of the given function call. fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: bool) -> EagernessSuggestion { use EagernessSuggestion::{Eager, Lazy, NoChange}; - let name = name.as_str(); let ty = match cx.tcx.impl_of_method(fn_id) { Some(id) => cx.tcx.type_of(id).instantiate_identity(), None => return Lazy, }; - if (name.starts_with("as_") || name == "len" || name == "is_empty") && have_one_arg { + if (matches!(name, sym::is_empty | sym::len) || name.as_str().starts_with("as_")) && have_one_arg { if matches!( cx.tcx.crate_name(fn_id.krate), sym::std | sym::core | sym::alloc | sym::proc_macro diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index dbb993482902f..6971b488013c4 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -299,7 +299,7 @@ impl<'a> VecArgs<'a> { pub fn hir(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option> { if let ExprKind::Call(fun, args) = expr.kind && let ExprKind::Path(ref qpath) = fun.kind - && is_expn_of(fun.span, "vec").is_some() + && is_expn_of(fun.span, sym::vec).is_some() && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id() { return if cx.tcx.is_diagnostic_item(sym::vec_from_elem, fun_def_id) && args.len() == 2 { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 057b6e62da37b..d68e08da7bd23 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1097,13 +1097,13 @@ pub fn method_calls<'tcx>(expr: &'tcx Expr<'tcx>, max_depth: usize) -> (Vec(expr: &'a Expr<'_>, methods: &[&str]) -> Option, &'a [Expr<'a>])>> { +pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[Symbol]) -> Option, &'a [Expr<'a>])>> { let mut current = expr; let mut matched = Vec::with_capacity(methods.len()); for method_name in methods.iter().rev() { // method chains are stored last -> first if let ExprKind::MethodCall(path, receiver, args, _) = current.kind { - if path.ident.name.as_str() == *method_name { + if path.ident.name == *method_name { if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) { return None; } @@ -1489,14 +1489,14 @@ pub fn is_adjusted(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { /// macro `name`. /// See also [`is_direct_expn_of`]. #[must_use] -pub fn is_expn_of(mut span: Span, name: &str) -> Option { +pub fn is_expn_of(mut span: Span, name: Symbol) -> Option { loop { if span.from_expansion() { let data = span.ctxt().outer_expn_data(); let new_span = data.call_site; if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind - && mac_name.as_str() == name + && mac_name == name { return Some(new_span); } @@ -1519,13 +1519,13 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option { /// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only /// from `bar!` by `is_direct_expn_of`. #[must_use] -pub fn is_direct_expn_of(span: Span, name: &str) -> Option { +pub fn is_direct_expn_of(span: Span, name: Symbol) -> Option { if span.from_expansion() { let data = span.ctxt().outer_expn_data(); let new_span = data.call_site; if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind - && mac_name.as_str() == name + && mac_name == name { return Some(new_span); } @@ -1789,11 +1789,11 @@ pub fn in_automatically_derived(tcx: TyCtxt<'_>, id: HirId) -> bool { } /// Checks if the given `DefId` matches the `libc` item. -pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: &str) -> bool { +pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: Symbol) -> bool { let path = cx.get_def_path(did); // libc is meant to be used as a flat list of names, but they're all actually defined in different // modules based on the target platform. Ignore everything but crate name and the item name. - path.first().is_some_and(|s| *s == sym::libc) && path.last().is_some_and(|s| s.as_str() == name) + path.first().is_some_and(|s| *s == sym::libc) && path.last().copied() == Some(name) } /// Returns the list of condition expressions and the list of blocks in a diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index dfb30b9c21864..ba126fcd05de9 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -2,8 +2,8 @@ use std::sync::{Arc, OnceLock}; -use crate::get_unique_attr; use crate::visitors::{Descend, for_each_expr_without_closures}; +use crate::{get_unique_attr, sym}; use arrayvec::ArrayVec; use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder}; @@ -12,7 +12,7 @@ use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath}; use rustc_lint::{LateContext, LintContext}; use rustc_span::def_id::DefId; use rustc_span::hygiene::{self, MacroKind, SyntaxContext}; -use rustc_span::{BytePos, ExpnData, ExpnId, ExpnKind, Span, SpanData, Symbol, sym}; +use rustc_span::{BytePos, ExpnData, ExpnId, ExpnKind, Span, SpanData, Symbol}; use std::ops::ControlFlow; const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[ @@ -42,7 +42,7 @@ pub fn is_format_macro(cx: &LateContext<'_>, macro_def_id: DefId) -> bool { } else { // Allow users to tag any macro as being format!-like // TODO: consider deleting FORMAT_MACRO_DIAG_ITEMS and using just this method - get_unique_attr(cx.sess(), cx.tcx.get_attrs_unchecked(macro_def_id), "format_args").is_some() + get_unique_attr(cx.sess(), cx.tcx.get_attrs_unchecked(macro_def_id), sym::format_args).is_some() } } @@ -248,10 +248,10 @@ impl<'a> PanicExpn<'a> { let ExprKind::Path(QPath::Resolved(_, path)) = &callee.kind else { return None; }; - let name = path.segments.last().unwrap().ident.as_str(); + let name = path.segments.last().unwrap().ident.name; // This has no argument - if name == "panic_cold_explicit" { + if name == sym::panic_cold_explicit { return Some(Self::Empty); } @@ -259,18 +259,18 @@ impl<'a> PanicExpn<'a> { return None; }; let result = match name { - "panic" if arg.span.eq_ctxt(expr.span) => Self::Empty, - "panic" | "panic_str" => Self::Str(arg), - "panic_display" | "panic_cold_display" => { + sym::panic if arg.span.eq_ctxt(expr.span) => Self::Empty, + sym::panic | sym::panic_str => Self::Str(arg), + sym::panic_display | sym::panic_cold_display => { let ExprKind::AddrOf(_, _, e) = &arg.kind else { return None; }; Self::Display(e) }, - "panic_fmt" => Self::Format(arg), + sym::panic_fmt => Self::Format(arg), // Since Rust 1.52, `assert_{eq,ne}` macros expand to use: // `core::panicking::assert_failed(.., left_val, right_val, None | Some(format_args!(..)));` - "assert_failed" => { + sym::assert_failed => { // It should have 4 arguments in total (we already matched with the first argument, // so we're just checking for 3) if rest.len() != 3 { diff --git a/clippy_utils/src/ptr.rs b/clippy_utils/src/ptr.rs index 360c6251a57c2..5847e916e340f 100644 --- a/clippy_utils/src/ptr.rs +++ b/clippy_utils/src/ptr.rs @@ -1,17 +1,17 @@ use crate::source::snippet; use crate::visitors::{Descend, for_each_expr_without_closures}; -use crate::{path_to_local_id, strip_pat_refs}; +use crate::{path_to_local_id, strip_pat_refs, sym}; use core::ops::ControlFlow; use rustc_hir::{Body, BodyId, ExprKind, HirId, PatKind}; use rustc_lint::LateContext; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use std::borrow::Cow; pub fn get_spans( cx: &LateContext<'_>, opt_body_id: Option, idx: usize, - replacements: &[(&'static str, &'static str)], + replacements: &[(Symbol, &'static str)], ) -> Option)>> { if let Some(body) = opt_body_id.map(|id| cx.tcx.hir_body(id)) { if let PatKind::Binding(_, binding_id, _, _) = strip_pat_refs(body.params[idx].pat).kind { @@ -27,7 +27,7 @@ pub fn get_spans( fn extract_clone_suggestions<'tcx>( cx: &LateContext<'tcx>, id: HirId, - replace: &[(&'static str, &'static str)], + replace: &[(Symbol, &'static str)], body: &'tcx Body<'_>, ) -> Option)>> { let mut spans = Vec::new(); @@ -35,11 +35,11 @@ fn extract_clone_suggestions<'tcx>( if let ExprKind::MethodCall(seg, recv, [], _) = e.kind && path_to_local_id(recv, id) { - if seg.ident.as_str() == "capacity" { + if seg.ident.name == sym::capacity { return ControlFlow::Break(()); } for &(fn_name, suffix) in replace { - if seg.ident.as_str() == fn_name { + if seg.ident.name == fn_name { spans.push((e.span, snippet(cx, recv.span, "_") + suffix)); return ControlFlow::Continue(Descend::No); } diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index a5f0e9562c9ef..f417530be3672 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -78,69 +78,144 @@ generate! { abs, align_of, ambiguous_glob_reexports, + append, + arg, as_bytes, as_deref, as_deref_mut, as_mut, + assert_failed, + author, + borrow, + borrow_mut, build_hasher, + by_ref, bytes, + capacity, cargo_clippy: "cargo-clippy", cast, + cast_const, + cast_mut, + ceil, + ceil_char_boundary, + chain, chars, + checked_abs, + checked_add, + checked_isqrt, + checked_mul, + checked_pow, + checked_rem_euclid, + checked_sub, + clamp, clippy_utils, clone_into, cloned, + cognitive_complexity, collect, const_ptr, contains, copied, + copy_from, + copy_from_nonoverlapping, + copy_to, + copy_to_nonoverlapping, + count_ones, + cycle, + cyclomatic_complexity, de, diagnostics, disallowed_types, + drain, + dump, ends_with, enum_glob_use, + enumerate, + err, error, exp, + expect_err, + expn_data, extend, + filter, + filter_map, + find, + find_map, finish, finish_non_exhaustive, + first, flat_map, + flatten, + floor, + floor_char_boundary, + fold, for_each, from_bytes_with_nul, from_bytes_with_nul_unchecked, from_ptr, from_raw, from_ref, + from_str, from_str_radix, fs, + fuse, futures_util, get, + get_mut, + get_or_insert_with, + get_unchecked, + get_unchecked_mut, + has_significant_drop, hidden_glob_reexports, hygiene, + if_chain, insert, + inspect, int_roundings, + into, into_bytes, + into_ok, into_owned, io, is_ascii, + is_char_boundary, + is_digit, is_empty, is_err, + is_file, is_none, is_ok, is_some, + isqrt, itertools, + join, kw, last, lazy_static, ln, + lock, lock_api, log, + log10, + log2, macro_use_imports, + map_break, + map_continue, map_or, map_or_else, + match_indices, + matches, max, + max_by, + max_by_key, + max_value, + maximum, mem, min, + min_by, + min_by_key, + min_value, + minimum, mode, module_name_repetitions, msrv, @@ -148,45 +223,116 @@ generate! { mut_ptr, mutex, needless_return, + next_back, + next_if, + next_if_eq, next_tuple, + nth, + ok, + ok_or, once_cell, + open, or_default, + or_else, + or_insert, + or_insert_with, + outer_expn, + panic_cold_display, + panic_cold_explicit, + panic_display, + panic_str, parse, + partition, paths, + peek, + peek_mut, + peekable, + pow, powf, powi, + product, push, + read_line, + read_to_end, + read_to_string, redundant_pub_crate, regex, + rem_euclid, + repeat, + replace, + replacen, reserve, resize, restriction, + rev, + rfind, + rmatch_indices, + rmatches, + round, + rposition, + rsplit, + rsplit_once, + rsplit_terminator, + rsplitn, + rsplitn_mut, rustc_lint, rustc_lint_defs, rustc_span, rustfmt_skip, rwlock, + saturating_abs, + saturating_pow, + scan, + seek, serde, set_len, set_mode, set_readonly, signum, single_component_path_imports, + skip_while, + slice_mut_unchecked, + slice_unchecked, + sort, + sort_by, + sort_unstable_by, span_lint_and_then, split, + split_at, + split_at_checked, + split_at_mut, + split_at_mut_checked, + split_inclusive, + split_once, + split_terminator, split_whitespace, + splitn, + splitn_mut, sqrt, + starts_with, + step_by, + strlen, style, + subsec_micros, + subsec_nanos, + sum, symbol, take, + take_while, + then, then_some, to_ascii_lowercase, to_ascii_uppercase, to_digit, to_lowercase, + to_os_string, to_owned, + to_path_buf, to_uppercase, tokio, + trim, + trim_end_matches, + trim_start_matches, unreachable_pub, unsafe_removed_from_name, unused, @@ -195,10 +341,18 @@ generate! { unused_import_braces, unused_trait_names, unwrap_err, + unwrap_err_unchecked, unwrap_or_default, unwrap_or_else, + unwrap_unchecked, + unzip, + utils, + wake, warnings, wildcard_imports, with_capacity, wrapping_offset, + write, + writeln, + zip, } From 4a99cbbf6b1e5074017d49a14cf37259d7c82e50 Mon Sep 17 00:00:00 2001 From: Andrew Zhogin Date: Mon, 19 May 2025 21:14:28 +0700 Subject: [PATCH 2474/4206] Warning when dependency crate has async drop types, and the feature is disabled - typo fixed --- compiler/rustc_metadata/messages.ftl | 2 +- tests/ui/async-await/async-drop/dependency-dropped.rs | 2 +- .../async-drop/dependency-dropped.without_feature.stderr | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl index cac8f34b0fa0d..bccffe3924373 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -2,7 +2,7 @@ metadata_as_needed_compatibility = linking modifier `as-needed` is only compatible with `dylib` and `framework` linking kinds metadata_async_drop_types_in_dependency = - found async drop types in dependecy `{$extern_crate}`, but async_drop feature is disabled for `{$local_crate}` + found async drop types in dependency `{$extern_crate}`, but async_drop feature is disabled for `{$local_crate}` .help = if async drop type will be dropped in a crate without `feature(async_drop)`, sync Drop will be used metadata_bad_panic_strategy = diff --git a/tests/ui/async-await/async-drop/dependency-dropped.rs b/tests/ui/async-await/async-drop/dependency-dropped.rs index c8670be4e8baa..d7f415e19aadf 100644 --- a/tests/ui/async-await/async-drop/dependency-dropped.rs +++ b/tests/ui/async-await/async-drop/dependency-dropped.rs @@ -5,7 +5,7 @@ //@ edition:2021 #![cfg_attr(with_feature, feature(async_drop))] -//[without_feature]~^ WARN found async drop types in dependecy `async_drop_dep`, but async_drop feature is disabled for `dependency_dropped` +//[without_feature]~^ WARN found async drop types in dependency `async_drop_dep`, but async_drop feature is disabled for `dependency_dropped` #![allow(incomplete_features)] diff --git a/tests/ui/async-await/async-drop/dependency-dropped.without_feature.stderr b/tests/ui/async-await/async-drop/dependency-dropped.without_feature.stderr index 56e49568e1004..96a4572055c60 100644 --- a/tests/ui/async-await/async-drop/dependency-dropped.without_feature.stderr +++ b/tests/ui/async-await/async-drop/dependency-dropped.without_feature.stderr @@ -1,4 +1,4 @@ -warning: found async drop types in dependecy `async_drop_dep`, but async_drop feature is disabled for `dependency_dropped` +warning: found async drop types in dependency `async_drop_dep`, but async_drop feature is disabled for `dependency_dropped` --> $DIR/dependency-dropped.rs:7:1 | LL | #![cfg_attr(with_feature, feature(async_drop))] From e139d268f0d863fb45111b64dff7c981a377c8af Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 1 May 2025 16:09:53 +1000 Subject: [PATCH 2475/4206] Introduce some typedefs to improve readability. --- compiler/rustc_attr_parsing/src/context.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 55c3df003fe16..6edb9133eabda 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -26,12 +26,16 @@ macro_rules! attribute_groups { ( pub(crate) static $name: ident = [$($names: ty),* $(,)?]; ) => { - pub(crate) static $name: LazyLock<( - BTreeMap<&'static [Symbol], Vec, &ArgParser<'_>) + Send + Sync>>>, - Vec) -> Option>> - )> = LazyLock::new(|| { - let mut accepts = BTreeMap::<_, Vec, &ArgParser<'_>) + Send + Sync>>>::new(); - let mut finalizes = Vec::) -> Option>>::new(); + type Accepts = BTreeMap< + &'static [Symbol], + Vec, &ArgParser<'_>)>> + >; + type Finalizes = Vec< + Box) -> Option> + >; + pub(crate) static $name: LazyLock<(Accepts, Finalizes)> = LazyLock::new(|| { + let mut accepts = Accepts::new(); + let mut finalizes = Finalizes::new(); $( { thread_local! { From 8224956dffb1b296841c2e31c5496ab1a53b2d83 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Wed, 16 Apr 2025 20:43:23 +0200 Subject: [PATCH 2476/4206] Various macro fixes for loop lints The `explicit_into_iter_loop`, `explicit_iter_loop` and `iter_next_loop` will now: - trigger only when the triggering expression is not located into macro code; - properly expose code rewrite proposal with code coming from the root context. --- clippy_lints/src/loops/explicit_into_iter_loop.rs | 4 ++-- clippy_lints/src/loops/explicit_iter_loop.rs | 4 ++-- clippy_lints/src/loops/mod.rs | 4 +++- tests/ui/explicit_into_iter_loop.fixed | 13 +++++++++++++ tests/ui/explicit_into_iter_loop.rs | 13 +++++++++++++ tests/ui/explicit_into_iter_loop.stderr | 8 +++++++- tests/ui/explicit_iter_loop.fixed | 13 +++++++++++++ tests/ui/explicit_iter_loop.rs | 13 +++++++++++++ tests/ui/explicit_iter_loop.stderr | 8 +++++++- tests/ui/iter_next_loop.rs | 13 +++++++++++++ tests/ui/iter_next_loop.stderr | 8 +++++++- 11 files changed, 93 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/loops/explicit_into_iter_loop.rs b/clippy_lints/src/loops/explicit_into_iter_loop.rs index d5ddc33e928db..4aa1c2e211d33 100644 --- a/clippy_lints/src/loops/explicit_into_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_into_iter_loop.rs @@ -1,7 +1,7 @@ use super::EXPLICIT_INTO_ITER_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_trait_method; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; @@ -76,7 +76,7 @@ pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, call_expr: &Expr< }; let mut applicability = Applicability::MachineApplicable; - let object = snippet_with_applicability(cx, self_arg.span, "_", &mut applicability); + let object = snippet_with_context(cx, self_arg.span, call_expr.span.ctxt(), "_", &mut applicability).0; span_lint_and_sugg( cx, EXPLICIT_INTO_ITER_LOOP, diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index d0b26c91ffafb..010652e1cb902 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -1,7 +1,7 @@ use super::EXPLICIT_ITER_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::sym; use clippy_utils::ty::{ implements_trait, implements_trait_with_env, is_copy, is_type_lang_item, make_normalized_projection, @@ -36,7 +36,7 @@ pub(super) fn check( } let mut applicability = Applicability::MachineApplicable; - let object = snippet_with_applicability(cx, self_arg.span, "_", &mut applicability); + let object = snippet_with_context(cx, self_arg.span, call_expr.span.ctxt(), "_", &mut applicability).0; span_lint_and_sugg( cx, EXPLICIT_ITER_LOOP, diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 22cab317e3d24..01c36b8cb12fc 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -909,7 +909,9 @@ impl Loops { } fn check_for_loop_arg(&self, cx: &LateContext<'_>, _: &Pat<'_>, arg: &Expr<'_>) { - if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind { + if !arg.span.from_expansion() + && let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind + { match method.ident.name { sym::iter | sym::iter_mut => { explicit_iter_loop::check(cx, self_arg, arg, self.msrv, self.enforce_iter_loop_reborrow); diff --git a/tests/ui/explicit_into_iter_loop.fixed b/tests/ui/explicit_into_iter_loop.fixed index 2b68906ae39fa..c1b3c478eeb91 100644 --- a/tests/ui/explicit_into_iter_loop.fixed +++ b/tests/ui/explicit_into_iter_loop.fixed @@ -73,3 +73,16 @@ fn main() { for _ in S.into_iter::() {} } + +fn issue14630() { + macro_rules! mac { + (into_iter $e:expr) => { + $e.into_iter() + }; + } + + for _ in dbg!([1, 2]) {} + //~^ explicit_into_iter_loop + + for _ in mac!(into_iter [1, 2]) {} +} diff --git a/tests/ui/explicit_into_iter_loop.rs b/tests/ui/explicit_into_iter_loop.rs index ca335b62d9068..581e0dadcecb3 100644 --- a/tests/ui/explicit_into_iter_loop.rs +++ b/tests/ui/explicit_into_iter_loop.rs @@ -73,3 +73,16 @@ fn main() { for _ in S.into_iter::() {} } + +fn issue14630() { + macro_rules! mac { + (into_iter $e:expr) => { + $e.into_iter() + }; + } + + for _ in dbg!([1, 2]).into_iter() {} + //~^ explicit_into_iter_loop + + for _ in mac!(into_iter [1, 2]) {} +} diff --git a/tests/ui/explicit_into_iter_loop.stderr b/tests/ui/explicit_into_iter_loop.stderr index 1c3156755d4ee..26fb11e004822 100644 --- a/tests/ui/explicit_into_iter_loop.stderr +++ b/tests/ui/explicit_into_iter_loop.stderr @@ -37,5 +37,11 @@ error: it is more concise to loop over containers instead of using explicit iter LL | for _ in mr.into_iter() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut *mr` -error: aborting due to 6 previous errors +error: it is more concise to loop over containers instead of using explicit iteration methods + --> tests/ui/explicit_into_iter_loop.rs:84:14 + | +LL | for _ in dbg!([1, 2]).into_iter() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `dbg!([1, 2])` + +error: aborting due to 7 previous errors diff --git a/tests/ui/explicit_iter_loop.fixed b/tests/ui/explicit_iter_loop.fixed index cd0898dfc3672..f246ec61800e1 100644 --- a/tests/ui/explicit_iter_loop.fixed +++ b/tests/ui/explicit_iter_loop.fixed @@ -183,3 +183,16 @@ pub fn issue_13184() { let rvalues = &values; for _ in rvalues.iter() {} } + +fn issue14630() { + macro_rules! mac { + (iter $e:expr) => { + $e.into_iter() + }; + } + + for _ in &dbg!([1, 2]) {} + //~^ explicit_iter_loop + + for _ in mac!(iter [1, 2]) {} +} diff --git a/tests/ui/explicit_iter_loop.rs b/tests/ui/explicit_iter_loop.rs index 02405280ce423..35f4fb7097d89 100644 --- a/tests/ui/explicit_iter_loop.rs +++ b/tests/ui/explicit_iter_loop.rs @@ -183,3 +183,16 @@ pub fn issue_13184() { let rvalues = &values; for _ in rvalues.iter() {} } + +fn issue14630() { + macro_rules! mac { + (iter $e:expr) => { + $e.into_iter() + }; + } + + for _ in dbg!([1, 2]).iter() {} + //~^ explicit_iter_loop + + for _ in mac!(iter [1, 2]) {} +} diff --git a/tests/ui/explicit_iter_loop.stderr b/tests/ui/explicit_iter_loop.stderr index 3816bb4db98b3..575dbe7813d75 100644 --- a/tests/ui/explicit_iter_loop.stderr +++ b/tests/ui/explicit_iter_loop.stderr @@ -112,5 +112,11 @@ error: it is more concise to loop over references to containers instead of using LL | for _ in r.iter() {} | ^^^^^^^^ help: to write this more concisely, try: `r` -error: aborting due to 18 previous errors +error: it is more concise to loop over references to containers instead of using explicit iteration methods + --> tests/ui/explicit_iter_loop.rs:194:14 + | +LL | for _ in dbg!([1, 2]).iter() {} + | ^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&dbg!([1, 2])` + +error: aborting due to 19 previous errors diff --git a/tests/ui/iter_next_loop.rs b/tests/ui/iter_next_loop.rs index 32711c7ef6239..8e62ed963b900 100644 --- a/tests/ui/iter_next_loop.rs +++ b/tests/ui/iter_next_loop.rs @@ -15,3 +15,16 @@ fn main() { let u = Unrelated(&[0]); for _v in u.next() {} // no error } + +fn issue14630() { + macro_rules! mac { + (next $e:expr) => { + $e.iter().next() + }; + } + + for _ in dbg!([1, 2].iter()).next() {} + //~^ iter_next_loop + + for _ in mac!(next [1, 2]) {} +} diff --git a/tests/ui/iter_next_loop.stderr b/tests/ui/iter_next_loop.stderr index acc55031c3b29..c076e86db93bb 100644 --- a/tests/ui/iter_next_loop.stderr +++ b/tests/ui/iter_next_loop.stderr @@ -7,5 +7,11 @@ LL | for _ in x.iter().next() {} = note: `-D clippy::iter-next-loop` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::iter_next_loop)]` -error: aborting due to 1 previous error +error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want + --> tests/ui/iter_next_loop.rs:26:14 + | +LL | for _ in dbg!([1, 2].iter()).next() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors From 5b808b7da8df062f1c4d5d73c98e19e6cc4b283b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 1 May 2025 16:09:16 +1000 Subject: [PATCH 2477/4206] Simplify `Accepts`. There only needs to be one `Fn` per symbol, not multiple. --- compiler/rustc_attr_parsing/src/context.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 6edb9133eabda..aef803c7442c6 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -28,7 +28,7 @@ macro_rules! attribute_groups { ) => { type Accepts = BTreeMap< &'static [Symbol], - Vec, &ArgParser<'_>)>> + Box, &ArgParser<'_>)> >; type Finalizes = Vec< Box) -> Option> @@ -43,11 +43,12 @@ macro_rules! attribute_groups { }; for (k, v) in <$names>::ATTRIBUTES { - accepts.entry(*k).or_default().push(Box::new(|cx, args| { + let old = accepts.insert(*k, Box::new(|cx, args| { STATE_OBJECT.with_borrow_mut(|s| { v(s, cx, args) }) })); + assert!(old.is_none()); } finalizes.push(Box::new(|cx| { @@ -267,15 +268,11 @@ impl<'sess> AttributeParser<'sess> { let (path, args) = parser.deconstruct(); let parts = path.segments().map(|i| i.name).collect::>(); - if let Some(accepts) = ATTRIBUTE_MAPPING.0.get(parts.as_slice()) { - for f in accepts { - let cx = AcceptContext { - group_cx: &group_cx, - attr_span: lower_span(attr.span), - }; + if let Some(accept) = ATTRIBUTE_MAPPING.0.get(parts.as_slice()) { + let cx = + AcceptContext { group_cx: &group_cx, attr_span: lower_span(attr.span) }; - f(&cx, &args) - } + accept(&cx, &args) } else { // if we're here, we must be compiling a tool attribute... Or someone forgot to // parse their fancy new attribute. Let's warn them in any case. If you are that From 1525f548bc376b04692b97a84898900e8f27fdd0 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 1 May 2025 16:24:48 +1000 Subject: [PATCH 2478/4206] Fix up some comments. Some are too long (> 100 chars), some are too short, some are missing full stops, some are missing upper-case letters at the start of sentences. --- compiler/rustc_attr_parsing/src/context.rs | 31 +++++++++++----------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index aef803c7442c6..1360fc6871422 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -115,7 +115,8 @@ impl<'a> Deref for AcceptContext<'a> { /// Context given to every attribute parser during finalization. /// -/// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create errors, for example. +/// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create +/// errors, for example. pub(crate) struct FinalizeContext<'a> { /// The parse context, gives access to the session and the /// diagnostics context. @@ -146,10 +147,9 @@ pub struct AttributeParser<'sess> { sess: &'sess Session, features: Option<&'sess Features>, - /// *only* parse attributes with this symbol. + /// *Only* parse attributes with this symbol. /// - /// Used in cases where we want the lowering infrastructure for - /// parse just a single attribute. + /// Used in cases where we want the lowering infrastructure for parse just a single attribute. parse_only: Option, /// Can be used to instruct parsers to reduce the number of diagnostics it emits. @@ -162,9 +162,9 @@ impl<'sess> AttributeParser<'sess> { /// One example where this is necessary, is to parse `feature` attributes themselves for /// example. /// - /// Try to use this as little as possible. Attributes *should* be lowered during `rustc_ast_lowering`. - /// Some attributes require access to features to parse, which would crash if you tried to do so - /// through [`parse_limited`](Self::parse_limited). + /// Try to use this as little as possible. Attributes *should* be lowered during + /// `rustc_ast_lowering`. Some attributes require access to features to parse, which would + /// crash if you tried to do so through [`parse_limited`](Self::parse_limited). /// /// To make sure use is limited, supply a `Symbol` you'd like to parse. Only attributes with /// that symbol are picked out of the list of instructions and parsed. Those are returned. @@ -222,19 +222,18 @@ impl<'sess> AttributeParser<'sess> { let group_cx = FinalizeContext { cx: self, target_span }; for attr in attrs { - // if we're only looking for a single attribute, - // skip all the ones we don't care about + // If we're only looking for a single attribute, skip all the ones we don't care about. if let Some(expected) = self.parse_only { if !attr.has_name(expected) { continue; } } - // sometimes, for example for `#![doc = include_str!("readme.md")]`, + // Sometimes, for example for `#![doc = include_str!("readme.md")]`, // doc still contains a non-literal. You might say, when we're lowering attributes // that's expanded right? But no, sometimes, when parsing attributes on macros, // we already use the lowering logic and these are still there. So, when `omit_doc` - // is set we *also* want to ignore these + // is set we *also* want to ignore these. if omit_doc == OmitDoc::Skip && attr.has_name(sym::doc) { continue; } @@ -274,11 +273,11 @@ impl<'sess> AttributeParser<'sess> { accept(&cx, &args) } else { - // if we're here, we must be compiling a tool attribute... Or someone forgot to - // parse their fancy new attribute. Let's warn them in any case. If you are that - // person, and you really your attribute should remain unparsed, carefully read the - // documentation in this module and if you still think so you can add an exception - // to this assertion. + // If we're here, we must be compiling a tool attribute... Or someone + // forgot to parse their fancy new attribute. Let's warn them in any case. + // If you are that person, and you really think your attribute should + // remain unparsed, carefully read the documentation in this module and if + // you still think so you can add an exception to this assertion. // FIXME(jdonszelmann): convert other attributes, and check with this that // we caught em all From 354b1cbcca13dc85bd0a57f8c2b254831394b6fb Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 May 2025 09:20:27 +1000 Subject: [PATCH 2479/4206] Avoid `rustc_span::` qualifiers. In several files they are entirely unnecessary, with the relevant names already imported. And in a few I have added the necessary `use` item. --- .../rustc_attr_parsing/src/attributes/allow_unstable.rs | 4 ++-- compiler/rustc_attr_parsing/src/attributes/deprecation.rs | 4 ++-- compiler/rustc_attr_parsing/src/attributes/mod.rs | 8 ++++---- compiler/rustc_attr_parsing/src/attributes/repr.rs | 6 +++--- compiler/rustc_attr_parsing/src/attributes/stability.rs | 2 +- .../rustc_attr_parsing/src/attributes/transparency.rs | 6 +++--- compiler/rustc_attr_parsing/src/parser.rs | 3 +-- 7 files changed, 16 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index c1d95d07f4c65..b9b6ca261193f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -10,7 +10,7 @@ use crate::session_diagnostics; pub(crate) struct AllowInternalUnstableParser; impl CombineAttributeParser for AllowInternalUnstableParser { - const PATH: &'static [rustc_span::Symbol] = &[sym::allow_internal_unstable]; + const PATH: &'static [Symbol] = &[sym::allow_internal_unstable]; type Item = (Symbol, Span); const CONVERT: ConvertFn = AttributeKind::AllowInternalUnstable; @@ -24,7 +24,7 @@ impl CombineAttributeParser for AllowInternalUnstableParser { pub(crate) struct AllowConstFnUnstableParser; impl CombineAttributeParser for AllowConstFnUnstableParser { - const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_allow_const_fn_unstable]; + const PATH: &'static [Symbol] = &[sym::rustc_allow_const_fn_unstable]; type Item = Symbol; const CONVERT: ConvertFn = AttributeKind::AllowConstFnUnstable; diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index fb3d5f57d4fac..1775770ec680e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -42,9 +42,9 @@ fn get( } impl SingleAttributeParser for DeprecationParser { - const PATH: &'static [rustc_span::Symbol] = &[sym::deprecated]; + const PATH: &'static [Symbol] = &[sym::deprecated]; - fn on_duplicate(cx: &AcceptContext<'_>, first_span: rustc_span::Span) { + fn on_duplicate(cx: &AcceptContext<'_>, first_span: Span) { // FIXME(jdonszelmann): merge with errors from check_attrs.rs cx.emit_err(session_diagnostics::UnusedMultiple { this: cx.attr_span, diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 6ecd6b4d7dbb7..f45cf984f7191 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -17,7 +17,7 @@ use std::marker::PhantomData; use rustc_attr_data_structures::AttributeKind; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use thin_vec::ThinVec; use crate::context::{AcceptContext, FinalizeContext}; @@ -33,7 +33,7 @@ pub(crate) mod transparency; pub(crate) mod util; type AcceptFn = fn(&mut T, &AcceptContext<'_>, &ArgParser<'_>); -type AcceptMapping = &'static [(&'static [rustc_span::Symbol], AcceptFn)]; +type AcceptMapping = &'static [(&'static [Symbol], AcceptFn)]; /// An [`AttributeParser`] is a type which searches for syntactic attributes. /// @@ -72,7 +72,7 @@ pub(crate) trait AttributeParser: Default + 'static { /// [`SingleAttributeParser`] can only convert attributes one-to-one, and cannot combine multiple /// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example. pub(crate) trait SingleAttributeParser: 'static { - const PATH: &'static [rustc_span::Symbol]; + const PATH: &'static [Symbol]; /// Caled when a duplicate attribute is found. /// @@ -119,7 +119,7 @@ type ConvertFn = fn(ThinVec) -> AttributeKind; /// [`CombineAttributeParser`] can only convert a single kind of attribute, and cannot combine multiple /// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example. pub(crate) trait CombineAttributeParser: 'static { - const PATH: &'static [rustc_span::Symbol]; + const PATH: &'static [Symbol]; type Item; const CONVERT: ConvertFn; diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 43dfb85a7c411..ab523ce0038da 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -1,7 +1,7 @@ use rustc_abi::Align; use rustc_ast::{IntTy, LitIntType, LitKind, UintTy}; use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr}; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use super::{CombineAttributeParser, ConvertFn}; use crate::context::AcceptContext; @@ -21,7 +21,7 @@ pub(crate) struct ReprParser; impl CombineAttributeParser for ReprParser { type Item = (ReprAttr, Span); - const PATH: &'static [rustc_span::Symbol] = &[sym::repr]; + const PATH: &'static [Symbol] = &[sym::repr]; const CONVERT: ConvertFn = AttributeKind::Repr; fn extend<'a>( @@ -99,7 +99,7 @@ fn parse_repr(cx: &AcceptContext<'_>, param: &MetaItemParser<'_>) -> Option, _first_span: Span) {} diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index ce42b0507ed57..d229fc0974010 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -1,6 +1,6 @@ use rustc_attr_data_structures::AttributeKind; use rustc_span::hygiene::Transparency; -use rustc_span::sym; +use rustc_span::{Span, Symbol, sym}; use super::{AcceptContext, SingleAttributeParser}; use crate::parser::ArgParser; @@ -11,9 +11,9 @@ pub(crate) struct TransparencyParser; #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] impl SingleAttributeParser for TransparencyParser { - const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_macro_transparency]; + const PATH: &'static [Symbol] = &[sym::rustc_macro_transparency]; - fn on_duplicate(cx: &crate::context::AcceptContext<'_>, first_span: rustc_span::Span) { + fn on_duplicate(cx: &crate::context::AcceptContext<'_>, first_span: Span) { cx.dcx().span_err(vec![first_span, cx.attr_span], "multiple macro transparency attributes"); } diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 077d953cfa318..f433d3574e186 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -12,8 +12,7 @@ use rustc_ast::{AttrArgs, DelimArgs, Expr, ExprKind, LitKind, MetaItemLit, Norma use rustc_ast_pretty::pprust; use rustc_errors::DiagCtxtHandle; use rustc_hir::{self as hir, AttrPath}; -use rustc_span::symbol::{Ident, kw, sym}; -use rustc_span::{ErrorGuaranteed, Span, Symbol}; +use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym}; pub struct SegmentIterator<'a> { offset: usize, From 72a4e33d69d982c6d26d19d65e136f21bded3184 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sun, 18 May 2025 14:39:28 +0200 Subject: [PATCH 2480/4206] Fix ICE while computing type layout If a type is incomplete, for example if generic parameters are not available yet, although they are not escaping, its layout may not be computable. Calling `TyCtxt::layout_of()` would create a delayed bug in the compiler. --- clippy_lints/src/zero_sized_map_values.rs | 8 +++++--- tests/ui/crashes/ice-6840.rs | 1 + tests/ui/zero_sized_hashmap_values.rs | 21 +++++++++++++++++++++ tests/ui/zero_sized_hashmap_values.stderr | 16 ++++++++++++---- 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs index 24b1381ba458c..1550872bca2b9 100644 --- a/clippy_lints/src/zero_sized_map_values.rs +++ b/clippy_lints/src/zero_sized_map_values.rs @@ -51,9 +51,11 @@ impl LateLintPass<'_> for ZeroSizedMapValues { && (is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap)) && let ty::Adt(_, args) = ty.kind() && let ty = args.type_at(1) - // Fixes https://github.com/rust-lang/rust-clippy/issues/7447 because of - // https://github.com/rust-lang/rust/blob/master/compiler/rustc_middle/src/ty/sty.rs#L968 - && !ty.has_escaping_bound_vars() + // Ensure that no type information is missing, to avoid a delayed bug in the compiler if this is not the case. + // This might happen when computing a reference/pointer metadata on a type for which we + // cannot check if it is `Sized` or not, such as an incomplete associated type in a + // type alias. See an example in `issue14822()` of `tests/ui/zero_sized_hashmap_values.rs`. + && !ty.has_non_region_param() && let Ok(layout) = cx.layout_of(ty) && layout.is_zst() { diff --git a/tests/ui/crashes/ice-6840.rs b/tests/ui/crashes/ice-6840.rs index 94481f2489987..f30d83e1eeecd 100644 --- a/tests/ui/crashes/ice-6840.rs +++ b/tests/ui/crashes/ice-6840.rs @@ -2,6 +2,7 @@ //! This is a reproducer for the ICE 6840: https://github.com/rust-lang/rust-clippy/issues/6840. //! The ICE is caused by `TyCtxt::layout_of` and `is_normalizable` not being strict enough #![allow(dead_code)] +#![deny(clippy::zero_sized_map_values)] // For ICE 14822 use std::collections::HashMap; pub trait Rule { diff --git a/tests/ui/zero_sized_hashmap_values.rs b/tests/ui/zero_sized_hashmap_values.rs index 4beeef421f30e..dcbfd16843de4 100644 --- a/tests/ui/zero_sized_hashmap_values.rs +++ b/tests/ui/zero_sized_hashmap_values.rs @@ -71,6 +71,27 @@ fn test2(map: HashMap, key: &str) -> HashMap { todo!(); } +fn issue14822() { + trait Trait { + type T; + } + struct S(T::T); + + // The `delay_bug` happens when evaluating the pointer metadata of `S` which depends on + // whether `T::T` is `Sized`. Since the type alias doesn't have a trait bound of `T: Trait` + // evaluating `T::T: Sized` ultimately fails with `NoSolution`. + type A = HashMap>; + type B = HashMap>; + + enum E {} + impl Trait for E { + type T = (); + } + type C = HashMap>; + type D = HashMap>; + //~^ zero_sized_map_values +} + fn main() { let _: HashMap = HashMap::new(); //~^ zero_sized_map_values diff --git a/tests/ui/zero_sized_hashmap_values.stderr b/tests/ui/zero_sized_hashmap_values.stderr index ed8536acfe8fa..d29491fa05c76 100644 --- a/tests/ui/zero_sized_hashmap_values.stderr +++ b/tests/ui/zero_sized_hashmap_values.stderr @@ -81,7 +81,15 @@ LL | fn test(map: HashMap, key: &str) -> HashMap { = help: consider using a set instead error: map with zero-sized value type - --> tests/ui/zero_sized_hashmap_values.rs:75:34 + --> tests/ui/zero_sized_hashmap_values.rs:91:14 + | +LL | type D = HashMap>; + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: map with zero-sized value type + --> tests/ui/zero_sized_hashmap_values.rs:96:34 | LL | let _: HashMap = HashMap::new(); | ^^^^^^^ @@ -89,7 +97,7 @@ LL | let _: HashMap = HashMap::new(); = help: consider using a set instead error: map with zero-sized value type - --> tests/ui/zero_sized_hashmap_values.rs:75:12 + --> tests/ui/zero_sized_hashmap_values.rs:96:12 | LL | let _: HashMap = HashMap::new(); | ^^^^^^^^^^^^^^^^^^^ @@ -97,12 +105,12 @@ LL | let _: HashMap = HashMap::new(); = help: consider using a set instead error: map with zero-sized value type - --> tests/ui/zero_sized_hashmap_values.rs:81:12 + --> tests/ui/zero_sized_hashmap_values.rs:102:12 | LL | let _: HashMap<_, _> = std::iter::empty::<(String, ())>().collect(); | ^^^^^^^^^^^^^ | = help: consider using a set instead -error: aborting due to 13 previous errors +error: aborting due to 14 previous errors From ed983c21842be5e84f11b745c0c04ea23baa5509 Mon Sep 17 00:00:00 2001 From: dianne Date: Mon, 19 May 2025 18:02:54 -0700 Subject: [PATCH 2481/4206] only resolve top-level guard patterns' guards once We resolve guard patterns' guards in `resolve_pattern_inner`, so to avoid resolving them multiple times, we must avoid doing so earlier. To accomplish this, `LateResolutionVisitor::visit_pat` contains a case for guard patterns that avoids visiting their guards while walking patterns. This fixes an ICE due to `visit::walk_pat` being used instead, which meant guards at the top level of a pattern would be visited twice. --- compiler/rustc_resolve/src/late.rs | 4 +- ...ve-top-level-guard-expr-once-ice-141265.rs | 12 +++++ ...op-level-guard-expr-once-ice-141265.stderr | 48 +++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.rs create mode 100644 tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.stderr diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 1b682d0cf8ae9..fd977a8eb6c0b 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3901,7 +3901,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // We walk the pattern before declaring the pattern's inner bindings, // so that we avoid resolving a literal expression to a binding defined // by the pattern. - visit::walk_pat(self, pat); + // NB: `Self::visit_pat` must be used rather than `visit::walk_pat` to avoid resolving guard + // patterns' guard expressions multiple times (#141265). + self.visit_pat(pat); self.resolve_pattern_inner(pat, pat_src, bindings); // This has to happen *after* we determine which pat_idents are variants: self.check_consistent_bindings(pat); diff --git a/tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.rs b/tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.rs new file mode 100644 index 0000000000000..7dc9ef7161d1b --- /dev/null +++ b/tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.rs @@ -0,0 +1,12 @@ +//! Regression test for . +//! Make sure expressions in top-level guard patterns are only resolved once. + +fn main() { + for + else if b 0 {} + //~^ ERROR expected identifier, found keyword `else` + //~| ERROR missing `in` in `for` loop + //~| ERROR cannot find value `b` in this scope + //~| ERROR guard patterns are experimental + //~| ERROR `{integer}` is not an iterator +} diff --git a/tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.stderr b/tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.stderr new file mode 100644 index 0000000000000..dae384137f529 --- /dev/null +++ b/tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.stderr @@ -0,0 +1,48 @@ +error: expected identifier, found keyword `else` + --> $DIR/only-resolve-top-level-guard-expr-once-ice-141265.rs:6:5 + | +LL | else if b 0 {} + | ^^^^ expected identifier, found keyword + +error: missing `in` in `for` loop + --> $DIR/only-resolve-top-level-guard-expr-once-ice-141265.rs:6:14 + | +LL | else if b 0 {} + | ^ + | +help: try adding `in` here + | +LL | else if b in 0 {} + | ++ + +error[E0425]: cannot find value `b` in this scope + --> $DIR/only-resolve-top-level-guard-expr-once-ice-141265.rs:6:13 + | +LL | else if b 0 {} + | ^ not found in this scope + +error[E0658]: guard patterns are experimental + --> $DIR/only-resolve-top-level-guard-expr-once-ice-141265.rs:6:13 + | +LL | else if b 0 {} + | ^ + | + = note: see issue #129967 for more information + = help: add `#![feature(guard_patterns)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: consider using match arm guards + +error[E0277]: `{integer}` is not an iterator + --> $DIR/only-resolve-top-level-guard-expr-once-ice-141265.rs:6:15 + | +LL | else if b 0 {} + | ^ `{integer}` is not an iterator + | + = help: the trait `Iterator` is not implemented for `{integer}` + = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` + = note: required for `{integer}` to implement `IntoIterator` + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0277, E0425, E0658. +For more information about an error, try `rustc --explain E0277`. From ee1c2d583a081e24684e09fbbcc78fe4d5220066 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 May 2025 11:57:50 +1000 Subject: [PATCH 2482/4206] Remove `MetaItemListParser::all_{word,path}_list`, which are unused. --- compiler/rustc_attr_parsing/src/parser.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 077d953cfa318..a5c3cec3bdd40 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -561,20 +561,6 @@ impl<'a> MetaItemListParser<'a> { self.len() == 0 } - /// Asserts that every item in the list is another list starting with a word. - /// - /// See [`MetaItemParser::word`] for examples of words. - pub fn all_word_list<'s>(&'s self) -> Option)>> { - self.mixed().map(|i| i.meta_item()?.word()).collect() - } - - /// Asserts that every item in the list is another list starting with a full path. - /// - /// See [`MetaItemParser::path`] for examples of paths. - pub fn all_path_list<'s>(&'s self) -> Option, &'s ArgParser<'a>)>> { - self.mixed().map(|i| Some(i.meta_item()?.path())).collect() - } - /// Returns Some if the list contains only a single element. /// /// Inside the Some is the parser to parse this single element. From 0c0b2cbcb597bac8cf7fa34b99d5dbe7a35419e1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 May 2025 14:01:58 +1000 Subject: [PATCH 2483/4206] Remove unused return value from `lower_node`. --- compiler/rustc_ast_lowering/src/item.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index f48a571b86a7d..9a9068ec7478e 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -70,7 +70,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { } } - pub(super) fn lower_node(&mut self, def_id: LocalDefId) -> hir::MaybeOwner<'hir> { + pub(super) fn lower_node(&mut self, def_id: LocalDefId) { let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom); if let hir::MaybeOwner::Phantom = owner { let node = self.ast_index[def_id]; @@ -82,8 +82,6 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { AstOwner::ForeignItem(item) => self.lower_foreign_item(item), } } - - self.owners[def_id] } #[instrument(level = "debug", skip(self, c))] From 7c62e78cf95daf69f8b0bec232f48fec6c8b935c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 May 2025 14:04:24 +1000 Subject: [PATCH 2484/4206] Hoist `ItemLowerer` out of a loop. --- compiler/rustc_ast_lowering/src/lib.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 19095f2e01e54..422e79ca82ffd 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -444,14 +444,14 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> { tcx.definitions_untracked().def_index_count(), ); + let mut lowerer = item::ItemLowerer { + tcx, + resolver: &mut resolver, + ast_index: &ast_index, + owners: &mut owners, + }; for def_id in ast_index.indices() { - item::ItemLowerer { - tcx, - resolver: &mut resolver, - ast_index: &ast_index, - owners: &mut owners, - } - .lower_node(def_id); + lowerer.lower_node(def_id); } drop(ast_index); From 8a927e63ff5b7de37ed91d5cc616009f7fed0dce Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 May 2025 14:13:33 +1000 Subject: [PATCH 2485/4206] Inline and remove `lower_*` methods. They are all short and have a single call site. --- compiler/rustc_ast_lowering/src/item.rs | 46 ++++++++++--------------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 9a9068ec7478e..e98d6c50ee791 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -76,37 +76,27 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { let node = self.ast_index[def_id]; match node { AstOwner::NonOwner => {} - AstOwner::Crate(c) => self.lower_crate(c), - AstOwner::Item(item) => self.lower_item(item), - AstOwner::AssocItem(item, ctxt) => self.lower_assoc_item(item, ctxt), - AstOwner::ForeignItem(item) => self.lower_foreign_item(item), + AstOwner::Crate(c) => { + debug_assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID); + self.with_lctx(CRATE_NODE_ID, |lctx| { + let module = lctx.lower_mod(&c.items, &c.spans); + // FIXME(jdonszelman): is dummy span ever a problem here? + lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs, DUMMY_SP); + hir::OwnerNode::Crate(module) + }) + } + AstOwner::Item(item) => { + self.with_lctx(item.id, |lctx| hir::OwnerNode::Item(lctx.lower_item(item))) + } + AstOwner::AssocItem(item, ctxt) => { + self.with_lctx(item.id, |lctx| lctx.lower_assoc_item(item, ctxt)) + } + AstOwner::ForeignItem(item) => self.with_lctx(item.id, |lctx| { + hir::OwnerNode::ForeignItem(lctx.lower_foreign_item(item)) + }), } } } - - #[instrument(level = "debug", skip(self, c))] - fn lower_crate(&mut self, c: &Crate) { - debug_assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID); - self.with_lctx(CRATE_NODE_ID, |lctx| { - let module = lctx.lower_mod(&c.items, &c.spans); - // FIXME(jdonszelman): is dummy span ever a problem here? - lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs, DUMMY_SP); - hir::OwnerNode::Crate(module) - }) - } - - #[instrument(level = "debug", skip(self))] - fn lower_item(&mut self, item: &Item) { - self.with_lctx(item.id, |lctx| hir::OwnerNode::Item(lctx.lower_item(item))) - } - - fn lower_assoc_item(&mut self, item: &AssocItem, ctxt: AssocCtxt) { - self.with_lctx(item.id, |lctx| lctx.lower_assoc_item(item, ctxt)) - } - - fn lower_foreign_item(&mut self, item: &ForeignItem) { - self.with_lctx(item.id, |lctx| hir::OwnerNode::ForeignItem(lctx.lower_foreign_item(item))) - } } impl<'hir> LoweringContext<'_, 'hir> { From 969a25b6cee0077d06a28c44d0dd333ef8ccf4df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 May 2025 08:02:40 +0200 Subject: [PATCH 2486/4206] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 0d889a5d5b991..5b47d1bbaed7c 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -e42bbfe1f7c26f8760a99c4b1f27d33aba1040bb +a8e4c68dcb4dc1e48a0db294c5323cab0227fcb9 From a29756d0853654cc4deb7c9ed899156f0ed19ca6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 16 Apr 2025 14:50:18 +0200 Subject: [PATCH 2487/4206] make std::intrinsic functions actually be intrinsics --- library/core/src/intrinsics/mod.rs | 317 ++---------------- library/core/src/mem/mod.rs | 2 + library/core/src/ptr/mod.rs | 293 +++++++++++++++- .../tests/fail/intrinsics/copy_overlapping.rs | 9 +- .../fail/intrinsics/copy_overlapping.stderr | 4 +- .../tests/fail/intrinsics/copy_unaligned.rs | 9 +- .../fail/intrinsics/copy_unaligned.stderr | 4 +- ...erlapping.LowerIntrinsics.panic-abort.diff | 2 +- ...rlapping.LowerIntrinsics.panic-unwind.diff | 2 +- tests/mir-opt/lower_intrinsics.rs | 9 +- tests/ui/consts/const-eval/raw-pointer-ub.rs | 2 +- .../consts/const-eval/raw-pointer-ub.stderr | 4 +- tests/ui/consts/copy-intrinsic.rs | 20 +- tests/ui/consts/copy-intrinsic.stderr | 8 +- .../consts/missing_span_in_backtrace.stderr | 4 +- 15 files changed, 336 insertions(+), 353 deletions(-) diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index effdc3c63eeaa..23bafa778bc6b 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -62,8 +62,7 @@ #![allow(missing_docs)] use crate::marker::{DiscriminantKind, Tuple}; -use crate::mem::SizedTypeProperties; -use crate::{ptr, ub_checks}; +use crate::ptr; pub mod fallback; pub mod mir; @@ -3317,7 +3316,7 @@ pub const unsafe fn typed_swap_nonoverlapping(x: *mut T, y: *mut T) { /// `#[inline]`), gating assertions on `ub_checks()` rather than `cfg!(ub_checks)` means that /// assertions are enabled whenever the *user crate* has UB checks enabled. However, if the /// user has UB checks disabled, the checks will still get optimized out. This intrinsic is -/// primarily used by [`ub_checks::assert_unsafe_precondition`]. +/// primarily used by [`crate::ub_checks::assert_unsafe_precondition`]. #[rustc_intrinsic_const_stable_indirect] // just for UB checks #[inline(always)] #[rustc_intrinsic] @@ -3595,306 +3594,38 @@ impl AggregateRawPtr<*mut T> for *mut P { #[rustc_intrinsic] pub const fn ptr_metadata + ?Sized, M>(ptr: *const P) -> M; -// Some functions are defined here because they accidentally got made -// available in this module on stable. See . -// (`transmute` also falls into this category, but it cannot be wrapped due to the -// check that `T` and `U` have the same size.) - -/// Copies `count * size_of::()` bytes from `src` to `dst`. The source -/// and destination must *not* overlap. -/// -/// For regions of memory which might overlap, use [`copy`] instead. -/// -/// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but -/// with the source and destination arguments swapped, -/// and `count` counting the number of `T`s instead of bytes. -/// -/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the -/// requirements of `T`. The initialization state is preserved exactly. -/// -/// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `src` must be [valid] for reads of `count * size_of::()` bytes. -/// -/// * `dst` must be [valid] for writes of `count * size_of::()` bytes. -/// -/// * Both `src` and `dst` must be properly aligned. -/// -/// * The region of memory beginning at `src` with a size of `count * -/// size_of::()` bytes must *not* overlap with the region of memory -/// beginning at `dst` with the same size. -/// -/// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of -/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values -/// in the region beginning at `*src` and the region beginning at `*dst` can -/// [violate memory safety][read-ownership]. -/// -/// Note that even if the effectively copied size (`count * size_of::()`) is -/// `0`, the pointers must be properly aligned. -/// -/// [`read`]: crate::ptr::read -/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value -/// [valid]: crate::ptr#safety -/// -/// # Examples -/// -/// Manually implement [`Vec::append`]: -/// -/// ``` -/// use std::ptr; -/// -/// /// Moves all the elements of `src` into `dst`, leaving `src` empty. -/// fn append(dst: &mut Vec, src: &mut Vec) { -/// let src_len = src.len(); -/// let dst_len = dst.len(); -/// -/// // Ensure that `dst` has enough capacity to hold all of `src`. -/// dst.reserve(src_len); -/// -/// unsafe { -/// // The call to add is always safe because `Vec` will never -/// // allocate more than `isize::MAX` bytes. -/// let dst_ptr = dst.as_mut_ptr().add(dst_len); -/// let src_ptr = src.as_ptr(); -/// -/// // Truncate `src` without dropping its contents. We do this first, -/// // to avoid problems in case something further down panics. -/// src.set_len(0); -/// -/// // The two regions cannot overlap because mutable references do -/// // not alias, and two different vectors cannot own the same -/// // memory. -/// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len); -/// -/// // Notify `dst` that it now holds the contents of `src`. -/// dst.set_len(dst_len + src_len); -/// } -/// } -/// -/// let mut a = vec!['r']; -/// let mut b = vec!['u', 's', 't']; -/// -/// append(&mut a, &mut b); -/// -/// assert_eq!(a, &['r', 'u', 's', 't']); -/// assert!(b.is_empty()); -/// ``` -/// -/// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append -#[doc(alias = "memcpy")] +/// This is an accidentally-stable alias to [`ptr::copy_nonoverlapping`]; use that instead. +// Note (intentionally not in the doc comment): `ptr::copy_nonoverlapping` adds some extra +// debug assertions; if you are writing compiler tests or code inside the standard library +// that wants to avoid those debug assertions, directly call this intrinsic instead. #[stable(feature = "rust1", since = "1.0.0")] #[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] -#[inline(always)] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces -#[rustc_diagnostic_item = "ptr_copy_nonoverlapping"] -pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { - #[rustc_intrinsic_const_stable_indirect] - #[rustc_nounwind] - #[rustc_intrinsic] - const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); - - ub_checks::assert_unsafe_precondition!( - check_language_ub, - "ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null \ - and the specified memory ranges do not overlap", - ( - src: *const () = src as *const (), - dst: *mut () = dst as *mut (), - size: usize = size_of::(), - align: usize = align_of::(), - count: usize = count, - ) => { - let zero_size = count == 0 || size == 0; - ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size) - && ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size) - && ub_checks::maybe_is_nonoverlapping(src, dst, size, count) - } - ); - - // SAFETY: the safety contract for `copy_nonoverlapping` must be - // upheld by the caller. - unsafe { copy_nonoverlapping(src, dst, count) } -} +#[rustc_nounwind] +#[rustc_intrinsic] +pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); -/// Copies `count * size_of::()` bytes from `src` to `dst`. The source -/// and destination may overlap. -/// -/// If the source and destination will *never* overlap, -/// [`copy_nonoverlapping`] can be used instead. -/// -/// `copy` is semantically equivalent to C's [`memmove`], but -/// with the source and destination arguments swapped, -/// and `count` counting the number of `T`s instead of bytes. -/// Copying takes place as if the bytes were copied from `src` -/// to a temporary array and then copied from the array to `dst`. -/// -/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the -/// requirements of `T`. The initialization state is preserved exactly. -/// -/// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `src` must be [valid] for reads of `count * size_of::()` bytes. -/// -/// * `dst` must be [valid] for writes of `count * size_of::()` bytes, and must remain valid even -/// when `src` is read for `count * size_of::()` bytes. (This means if the memory ranges -/// overlap, the `dst` pointer must not be invalidated by `src` reads.) -/// -/// * Both `src` and `dst` must be properly aligned. -/// -/// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of -/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values -/// in the region beginning at `*src` and the region beginning at `*dst` can -/// [violate memory safety][read-ownership]. -/// -/// Note that even if the effectively copied size (`count * size_of::()`) is -/// `0`, the pointers must be properly aligned. -/// -/// [`read`]: crate::ptr::read -/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value -/// [valid]: crate::ptr#safety -/// -/// # Examples -/// -/// Efficiently create a Rust vector from an unsafe buffer: -/// -/// ``` -/// use std::ptr; -/// -/// /// # Safety -/// /// -/// /// * `ptr` must be correctly aligned for its type and non-zero. -/// /// * `ptr` must be valid for reads of `elts` contiguous elements of type `T`. -/// /// * Those elements must not be used after calling this function unless `T: Copy`. -/// # #[allow(dead_code)] -/// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { -/// let mut dst = Vec::with_capacity(elts); -/// -/// // SAFETY: Our precondition ensures the source is aligned and valid, -/// // and `Vec::with_capacity` ensures that we have usable space to write them. -/// unsafe { ptr::copy(ptr, dst.as_mut_ptr(), elts); } -/// -/// // SAFETY: We created it with this much capacity earlier, -/// // and the previous `copy` has initialized these elements. -/// unsafe { dst.set_len(elts); } -/// dst -/// } -/// ``` -#[doc(alias = "memmove")] +/// This is an accidentally-stable alias to [`ptr::copy`]; use that instead. +// Note (intentionally not in the doc comment): `ptr::copy` adds some extra +// debug assertions; if you are writing compiler tests or code inside the standard library +// that wants to avoid those debug assertions, directly call this intrinsic instead. #[stable(feature = "rust1", since = "1.0.0")] #[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] -#[inline(always)] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces -#[rustc_diagnostic_item = "ptr_copy"] -pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { - #[rustc_intrinsic_const_stable_indirect] - #[rustc_nounwind] - #[rustc_intrinsic] - const unsafe fn copy(src: *const T, dst: *mut T, count: usize); - - // SAFETY: the safety contract for `copy` must be upheld by the caller. - unsafe { - ub_checks::assert_unsafe_precondition!( - check_language_ub, - "ptr::copy requires that both pointer arguments are aligned and non-null", - ( - src: *const () = src as *const (), - dst: *mut () = dst as *mut (), - align: usize = align_of::(), - zero_size: bool = T::IS_ZST || count == 0, - ) => - ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size) - && ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size) - ); - copy(src, dst, count) - } -} +#[rustc_nounwind] +#[rustc_intrinsic] +pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize); -/// Sets `count * size_of::()` bytes of memory starting at `dst` to -/// `val`. -/// -/// `write_bytes` is similar to C's [`memset`], but sets `count * -/// size_of::()` bytes to `val`. -/// -/// [`memset`]: https://en.cppreference.com/w/c/string/byte/memset -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `dst` must be [valid] for writes of `count * size_of::()` bytes. -/// -/// * `dst` must be properly aligned. -/// -/// Note that even if the effectively copied size (`count * size_of::()`) is -/// `0`, the pointer must be properly aligned. -/// -/// Additionally, note that changing `*dst` in this way can easily lead to undefined behavior (UB) -/// later if the written bytes are not a valid representation of some `T`. For instance, the -/// following is an **incorrect** use of this function: -/// -/// ```rust,no_run -/// unsafe { -/// let mut value: u8 = 0; -/// let ptr: *mut bool = &mut value as *mut u8 as *mut bool; -/// let _bool = ptr.read(); // This is fine, `ptr` points to a valid `bool`. -/// ptr.write_bytes(42u8, 1); // This function itself does not cause UB... -/// let _bool = ptr.read(); // ...but it makes this operation UB! ⚠️ -/// } -/// ``` -/// -/// [valid]: crate::ptr#safety -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::ptr; -/// -/// let mut vec = vec![0u32; 4]; -/// unsafe { -/// let vec_ptr = vec.as_mut_ptr(); -/// ptr::write_bytes(vec_ptr, 0xfe, 2); -/// } -/// assert_eq!(vec, [0xfefefefe, 0xfefefefe, 0, 0]); -/// ``` -#[doc(alias = "memset")] +/// This is an accidentally-stable alias to [`ptr::write_bytes`]; use that instead. +// Note (intentionally not in the doc comment): `ptr::write_bytes` adds some extra +// debug assertions; if you are writing compiler tests or code inside the standard library +// that wants to avoid those debug assertions, directly call this intrinsic instead. #[stable(feature = "rust1", since = "1.0.0")] #[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"] -#[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")] -#[inline(always)] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces -#[rustc_diagnostic_item = "ptr_write_bytes"] -pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { - #[rustc_intrinsic_const_stable_indirect] - #[rustc_nounwind] - #[rustc_intrinsic] - const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize); - - // SAFETY: the safety contract for `write_bytes` must be upheld by the caller. - unsafe { - ub_checks::assert_unsafe_precondition!( - check_language_ub, - "ptr::write_bytes requires that the destination pointer is aligned and non-null", - ( - addr: *const () = dst as *const (), - align: usize = align_of::(), - zero_size: bool = T::IS_ZST || count == 0, - ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, zero_size) - ); - write_bytes(dst, val, count) - } -} +#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] +#[rustc_nounwind] +#[rustc_intrinsic] +pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize); /// Returns the minimum (IEEE 754-2008 minNum) of two `f16` values. /// diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 27387754633d1..0a5f3ee35b105 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -21,6 +21,8 @@ mod transmutability; #[unstable(feature = "transmutability", issue = "99571")] pub use transmutability::{Assume, TransmuteFrom}; +// This one has to be a re-export (rather than wrapping the underlying intrinsic) so that we can do +// the special magic "types have equal size" check at the call site. #[stable(feature = "rust1", since = "1.0.0")] #[doc(inline)] pub use crate::intrinsics::transmute; diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index bd6c4daa509d9..35a909f6904cd 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -405,16 +405,6 @@ mod alignment; #[unstable(feature = "ptr_alignment_type", issue = "102070")] pub use alignment::Alignment; -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(inline)] -pub use crate::intrinsics::copy; -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(inline)] -pub use crate::intrinsics::copy_nonoverlapping; -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(inline)] -pub use crate::intrinsics::write_bytes; - mod metadata; #[unstable(feature = "ptr_metadata", issue = "81513")] pub use metadata::{DynMetadata, Pointee, Thin, from_raw_parts, from_raw_parts_mut, metadata}; @@ -430,6 +420,289 @@ pub use unique::Unique; mod const_ptr; mod mut_ptr; +// Some functions are defined here because they accidentally got made +// available in this module on stable. See . +// (`transmute` also falls into this category, but it cannot be wrapped due to the +// check that `T` and `U` have the same size.) + +/// Copies `count * size_of::()` bytes from `src` to `dst`. The source +/// and destination must *not* overlap. +/// +/// For regions of memory which might overlap, use [`copy`] instead. +/// +/// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but +/// with the source and destination arguments swapped, +/// and `count` counting the number of `T`s instead of bytes. +/// +/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the +/// requirements of `T`. The initialization state is preserved exactly. +/// +/// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must be [valid] for reads of `count * size_of::()` bytes. +/// +/// * `dst` must be [valid] for writes of `count * size_of::()` bytes. +/// +/// * Both `src` and `dst` must be properly aligned. +/// +/// * The region of memory beginning at `src` with a size of `count * +/// size_of::()` bytes must *not* overlap with the region of memory +/// beginning at `dst` with the same size. +/// +/// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of +/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values +/// in the region beginning at `*src` and the region beginning at `*dst` can +/// [violate memory safety][read-ownership]. +/// +/// Note that even if the effectively copied size (`count * size_of::()`) is +/// `0`, the pointers must be properly aligned. +/// +/// [`read`]: crate::ptr::read +/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value +/// [valid]: crate::ptr#safety +/// +/// # Examples +/// +/// Manually implement [`Vec::append`]: +/// +/// ``` +/// use std::ptr; +/// +/// /// Moves all the elements of `src` into `dst`, leaving `src` empty. +/// fn append(dst: &mut Vec, src: &mut Vec) { +/// let src_len = src.len(); +/// let dst_len = dst.len(); +/// +/// // Ensure that `dst` has enough capacity to hold all of `src`. +/// dst.reserve(src_len); +/// +/// unsafe { +/// // The call to add is always safe because `Vec` will never +/// // allocate more than `isize::MAX` bytes. +/// let dst_ptr = dst.as_mut_ptr().add(dst_len); +/// let src_ptr = src.as_ptr(); +/// +/// // Truncate `src` without dropping its contents. We do this first, +/// // to avoid problems in case something further down panics. +/// src.set_len(0); +/// +/// // The two regions cannot overlap because mutable references do +/// // not alias, and two different vectors cannot own the same +/// // memory. +/// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len); +/// +/// // Notify `dst` that it now holds the contents of `src`. +/// dst.set_len(dst_len + src_len); +/// } +/// } +/// +/// let mut a = vec!['r']; +/// let mut b = vec!['u', 's', 't']; +/// +/// append(&mut a, &mut b); +/// +/// assert_eq!(a, &['r', 'u', 's', 't']); +/// assert!(b.is_empty()); +/// ``` +/// +/// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append +#[doc(alias = "memcpy")] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] +#[inline(always)] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces +#[rustc_diagnostic_item = "ptr_copy_nonoverlapping"] +pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null \ + and the specified memory ranges do not overlap", + ( + src: *const () = src as *const (), + dst: *mut () = dst as *mut (), + size: usize = size_of::(), + align: usize = align_of::(), + count: usize = count, + ) => { + let zero_size = count == 0 || size == 0; + ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size) + && ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size) + && ub_checks::maybe_is_nonoverlapping(src, dst, size, count) + } + ); + + // SAFETY: the safety contract for `copy_nonoverlapping` must be + // upheld by the caller. + unsafe { crate::intrinsics::copy_nonoverlapping(src, dst, count) } +} + +/// Copies `count * size_of::()` bytes from `src` to `dst`. The source +/// and destination may overlap. +/// +/// If the source and destination will *never* overlap, +/// [`copy_nonoverlapping`] can be used instead. +/// +/// `copy` is semantically equivalent to C's [`memmove`], but +/// with the source and destination arguments swapped, +/// and `count` counting the number of `T`s instead of bytes. +/// Copying takes place as if the bytes were copied from `src` +/// to a temporary array and then copied from the array to `dst`. +/// +/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the +/// requirements of `T`. The initialization state is preserved exactly. +/// +/// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must be [valid] for reads of `count * size_of::()` bytes. +/// +/// * `dst` must be [valid] for writes of `count * size_of::()` bytes, and must remain valid even +/// when `src` is read for `count * size_of::()` bytes. (This means if the memory ranges +/// overlap, the `dst` pointer must not be invalidated by `src` reads.) +/// +/// * Both `src` and `dst` must be properly aligned. +/// +/// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of +/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values +/// in the region beginning at `*src` and the region beginning at `*dst` can +/// [violate memory safety][read-ownership]. +/// +/// Note that even if the effectively copied size (`count * size_of::()`) is +/// `0`, the pointers must be properly aligned. +/// +/// [`read`]: crate::ptr::read +/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value +/// [valid]: crate::ptr#safety +/// +/// # Examples +/// +/// Efficiently create a Rust vector from an unsafe buffer: +/// +/// ``` +/// use std::ptr; +/// +/// /// # Safety +/// /// +/// /// * `ptr` must be correctly aligned for its type and non-zero. +/// /// * `ptr` must be valid for reads of `elts` contiguous elements of type `T`. +/// /// * Those elements must not be used after calling this function unless `T: Copy`. +/// # #[allow(dead_code)] +/// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { +/// let mut dst = Vec::with_capacity(elts); +/// +/// // SAFETY: Our precondition ensures the source is aligned and valid, +/// // and `Vec::with_capacity` ensures that we have usable space to write them. +/// unsafe { ptr::copy(ptr, dst.as_mut_ptr(), elts); } +/// +/// // SAFETY: We created it with this much capacity earlier, +/// // and the previous `copy` has initialized these elements. +/// unsafe { dst.set_len(elts); } +/// dst +/// } +/// ``` +#[doc(alias = "memmove")] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] +#[inline(always)] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces +#[rustc_diagnostic_item = "ptr_copy"] +pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { + // SAFETY: the safety contract for `copy` must be upheld by the caller. + unsafe { + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "ptr::copy requires that both pointer arguments are aligned and non-null", + ( + src: *const () = src as *const (), + dst: *mut () = dst as *mut (), + align: usize = align_of::(), + zero_size: bool = T::IS_ZST || count == 0, + ) => + ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size) + && ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size) + ); + crate::intrinsics::copy(src, dst, count) + } +} + +/// Sets `count * size_of::()` bytes of memory starting at `dst` to +/// `val`. +/// +/// `write_bytes` is similar to C's [`memset`], but sets `count * +/// size_of::()` bytes to `val`. +/// +/// [`memset`]: https://en.cppreference.com/w/c/string/byte/memset +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `dst` must be [valid] for writes of `count * size_of::()` bytes. +/// +/// * `dst` must be properly aligned. +/// +/// Note that even if the effectively copied size (`count * size_of::()`) is +/// `0`, the pointer must be properly aligned. +/// +/// Additionally, note that changing `*dst` in this way can easily lead to undefined behavior (UB) +/// later if the written bytes are not a valid representation of some `T`. For instance, the +/// following is an **incorrect** use of this function: +/// +/// ```rust,no_run +/// unsafe { +/// let mut value: u8 = 0; +/// let ptr: *mut bool = &mut value as *mut u8 as *mut bool; +/// let _bool = ptr.read(); // This is fine, `ptr` points to a valid `bool`. +/// ptr.write_bytes(42u8, 1); // This function itself does not cause UB... +/// let _bool = ptr.read(); // ...but it makes this operation UB! ⚠️ +/// } +/// ``` +/// +/// [valid]: crate::ptr#safety +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::ptr; +/// +/// let mut vec = vec![0u32; 4]; +/// unsafe { +/// let vec_ptr = vec.as_mut_ptr(); +/// ptr::write_bytes(vec_ptr, 0xfe, 2); +/// } +/// assert_eq!(vec, [0xfefefefe, 0xfefefefe, 0, 0]); +/// ``` +#[doc(alias = "memset")] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")] +#[inline(always)] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces +#[rustc_diagnostic_item = "ptr_write_bytes"] +pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { + // SAFETY: the safety contract for `write_bytes` must be upheld by the caller. + unsafe { + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "ptr::write_bytes requires that the destination pointer is aligned and non-null", + ( + addr: *const () = dst as *const (), + align: usize = align_of::(), + zero_size: bool = T::IS_ZST || count == 0, + ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, zero_size) + ); + crate::intrinsics::write_bytes(dst, val, count) + } +} + /// Executes the destructor (if any) of the pointed-to value. /// /// This is almost the same as calling [`ptr::read`] and discarding diff --git a/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs b/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs index e6282613df720..ff16ac61d8b87 100644 --- a/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs +++ b/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs @@ -1,14 +1,11 @@ -#![feature(intrinsics)] - -// Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); +#![feature(core_intrinsics)] fn main() { let mut data = [0u8; 16]; unsafe { let a = data.as_mut_ptr(); let b = a.wrapping_offset(1) as *mut _; - copy_nonoverlapping(a, b, 2); //~ ERROR: `copy_nonoverlapping` called on overlapping ranges + // Directly call intrinsic to avoid debug assertions in the `std::ptr` version. + std::intrinsics::copy_nonoverlapping(a, b, 2); //~ ERROR: `copy_nonoverlapping` called on overlapping ranges } } diff --git a/src/tools/miri/tests/fail/intrinsics/copy_overlapping.stderr b/src/tools/miri/tests/fail/intrinsics/copy_overlapping.stderr index fef5a0a82a07d..9b60a48703ba4 100644 --- a/src/tools/miri/tests/fail/intrinsics/copy_overlapping.stderr +++ b/src/tools/miri/tests/fail/intrinsics/copy_overlapping.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `copy_nonoverlapping` called on overlapping ranges --> tests/fail/intrinsics/copy_overlapping.rs:LL:CC | -LL | copy_nonoverlapping(a, b, 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `copy_nonoverlapping` called on overlapping ranges +LL | std::intrinsics::copy_nonoverlapping(a, b, 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `copy_nonoverlapping` called on overlapping ranges | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs b/src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs index ded9d0b669e6f..311789cdc4b42 100644 --- a/src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs +++ b/src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs @@ -1,14 +1,11 @@ -#![feature(intrinsics)] - -// Directly call intrinsic to avoid debug assertions in libstd -#[rustc_intrinsic] -unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); +#![feature(core_intrinsics)] fn main() { let mut data = [0u16; 8]; let ptr = (&mut data[0] as *mut u16 as *mut u8).wrapping_add(1) as *mut u16; // Even copying 0 elements to something unaligned should error unsafe { - copy_nonoverlapping(&data[5], ptr, 0); //~ ERROR: accessing memory with alignment 1, but alignment 2 is required + // Directly call intrinsic to avoid debug assertions in the `std::ptr` version. + std::intrinsics::copy_nonoverlapping(&data[5], ptr, 0); //~ ERROR: accessing memory with alignment 1, but alignment 2 is required } } diff --git a/src/tools/miri/tests/fail/intrinsics/copy_unaligned.stderr b/src/tools/miri/tests/fail/intrinsics/copy_unaligned.stderr index 2d0edd4e6cbe7..65dbdb3bbb640 100644 --- a/src/tools/miri/tests/fail/intrinsics/copy_unaligned.stderr +++ b/src/tools/miri/tests/fail/intrinsics/copy_unaligned.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required --> tests/fail/intrinsics/copy_unaligned.rs:LL:CC | -LL | copy_nonoverlapping(&data[5], ptr, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required +LL | std::intrinsics::copy_nonoverlapping(&data[5], ptr, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-abort.diff index 7f325245bce63..d73cc3d214e4c 100644 --- a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-abort.diff +++ b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-abort.diff @@ -45,7 +45,7 @@ _9 = copy _10; _8 = move _9 as *mut i32 (PtrToPtr); StorageDead(_9); -- _3 = copy_nonoverlapping::(move _4, move _8, const 0_usize) -> [return: bb1, unwind unreachable]; +- _3 = std::intrinsics::copy_nonoverlapping::(move _4, move _8, const 0_usize) -> [return: bb1, unwind unreachable]; + copy_nonoverlapping(dst = move _8, src = move _4, count = const 0_usize); + goto -> bb1; } diff --git a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-unwind.diff index 7f325245bce63..d73cc3d214e4c 100644 --- a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-unwind.diff +++ b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-unwind.diff @@ -45,7 +45,7 @@ _9 = copy _10; _8 = move _9 as *mut i32 (PtrToPtr); StorageDead(_9); -- _3 = copy_nonoverlapping::(move _4, move _8, const 0_usize) -> [return: bb1, unwind unreachable]; +- _3 = std::intrinsics::copy_nonoverlapping::(move _4, move _8, const 0_usize) -> [return: bb1, unwind unreachable]; + copy_nonoverlapping(dst = move _8, src = move _4, count = const 0_usize); + goto -> bb1; } diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs index 5afddc5ff7301..4e000b05a4b47 100644 --- a/tests/mir-opt/lower_intrinsics.rs +++ b/tests/mir-opt/lower_intrinsics.rs @@ -1,9 +1,11 @@ //@ test-mir-pass: LowerIntrinsics // EMIT_MIR_FOR_EACH_PANIC_STRATEGY -#![feature(core_intrinsics, intrinsics, rustc_attrs)] +#![feature(core_intrinsics)] #![crate_type = "lib"] +use std::intrinsics::copy_nonoverlapping; + // EMIT_MIR lower_intrinsics.wrapping.LowerIntrinsics.diff pub fn wrapping(a: i32, b: i32) { // CHECK-LABEL: fn wrapping( @@ -153,11 +155,6 @@ pub fn discriminant(t: T) { core::intrinsics::discriminant_value(&E::B); } -// Cannot use `std::intrinsics::copy_nonoverlapping` as that is a wrapper function -#[rustc_nounwind] -#[rustc_intrinsic] -unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); - // EMIT_MIR lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff pub fn f_copy_nonoverlapping() { // CHECK-LABEL: fn f_copy_nonoverlapping( diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.rs b/tests/ui/consts/const-eval/raw-pointer-ub.rs index 13a95f9b78f90..1383de63109c4 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.rs +++ b/tests/ui/consts/const-eval/raw-pointer-ub.rs @@ -19,7 +19,7 @@ const MISALIGNED_COPY: () = unsafe { y.copy_to_nonoverlapping(&mut z, 1); //~^ ERROR evaluation of constant value failed //~| NOTE inside `std::ptr::const_ptr - //~| NOTE inside `copy_nonoverlapping::` + //~| NOTE inside `std::ptr::copy_nonoverlapping::` //~| NOTE accessing memory with alignment 1, but alignment 4 is required // The actual error points into the implementation of `copy_to_nonoverlapping`. }; diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.stderr b/tests/ui/consts/const-eval/raw-pointer-ub.stderr index ed5793c84c57f..0f3dc33f3a31b 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.stderr +++ b/tests/ui/consts/const-eval/raw-pointer-ub.stderr @@ -18,8 +18,8 @@ LL | y.copy_to_nonoverlapping(&mut z, 1); | note: inside `std::ptr::const_ptr::::copy_to_nonoverlapping` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL -note: inside `copy_nonoverlapping::` - --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL +note: inside `std::ptr::copy_nonoverlapping::` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL error[E0080]: evaluation of constant value failed --> $DIR/raw-pointer-ub.rs:34:16 diff --git a/tests/ui/consts/copy-intrinsic.rs b/tests/ui/consts/copy-intrinsic.rs index da483d671f97f..d0242f285444a 100644 --- a/tests/ui/consts/copy-intrinsic.rs +++ b/tests/ui/consts/copy-intrinsic.rs @@ -1,22 +1,8 @@ -#![stable(feature = "dummy", since = "1.0.0")] - // ignore-tidy-linelength -#![feature(intrinsics, staged_api, rustc_attrs)] -use std::mem; - -#[stable(feature = "dummy", since = "1.0.0")] -#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] -#[rustc_intrinsic] -const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { - unimplemented!() -} +#![feature(core_intrinsics)] -#[stable(feature = "dummy", since = "1.0.0")] -#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] -#[rustc_intrinsic] -const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { - unimplemented!() -} +use std::mem; +use std::intrinsics::{copy, copy_nonoverlapping}; const COPY_ZERO: () = unsafe { // Since we are not copying anything, this should be allowed. diff --git a/tests/ui/consts/copy-intrinsic.stderr b/tests/ui/consts/copy-intrinsic.stderr index 13321b5703a36..8d586428e56f8 100644 --- a/tests/ui/consts/copy-intrinsic.stderr +++ b/tests/ui/consts/copy-intrinsic.stderr @@ -1,23 +1,23 @@ error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:34:5 + --> $DIR/copy-intrinsic.rs:20:5 | LL | copy_nonoverlapping(0x100 as *const i32, dangle, 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got 0x100[noalloc] which is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:43:5 + --> $DIR/copy-intrinsic.rs:29:5 | LL | copy_nonoverlapping(dangle, 0x100 as *mut i32, 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got ALLOC0+0x28 which is at or beyond the end of the allocation of size 4 bytes error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:50:5 + --> $DIR/copy-intrinsic.rs:36:5 | LL | copy(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy` error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:56:5 + --> $DIR/copy-intrinsic.rs:42:5 | LL | copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy_nonoverlapping` diff --git a/tests/ui/consts/missing_span_in_backtrace.stderr b/tests/ui/consts/missing_span_in_backtrace.stderr index 88b3e37bb84ff..7c07710332b80 100644 --- a/tests/ui/consts/missing_span_in_backtrace.stderr +++ b/tests/ui/consts/missing_span_in_backtrace.stderr @@ -14,8 +14,8 @@ note: inside `swap_nonoverlapping::compiletime::>` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL note: inside `std::ptr::swap_nonoverlapping_const::>` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -note: inside `copy_nonoverlapping::>` - --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL +note: inside `std::ptr::copy_nonoverlapping::>` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported = note: this error originates in the macro `$crate::intrinsics::const_eval_select` which comes from the expansion of the macro `const_eval_select` (in Nightly builds, run with -Z macro-backtrace for more info) From 4ec991989af4662104fdbafc43b12232887fa0b4 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Tue, 20 May 2025 14:10:17 +0800 Subject: [PATCH 2488/4206] Add println! test for sugg-field-in-format-string-issue-141136 Signed-off-by: xizheyin --- .../sugg-field-in-format-string-issue-141136.rs | 1 + .../sugg-field-in-format-string-issue-141136.stderr | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.rs b/tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.rs index e0c2f49604617..d2aa61186bcd0 100644 --- a/tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.rs +++ b/tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.rs @@ -8,6 +8,7 @@ impl Foo { let _ = format!("{x }"); //~ ERROR cannot find value `x` in this scope [E0425] let _ = format!("{ x}"); //~ ERROR invalid format string: expected `}`, found `x` let _ = format!("{}", x); //~ ERROR cannot find value `x` in this scope [E0425] + println!("{x}"); //~ ERROR cannot find value `x` in this scope [E0425] } } diff --git a/tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.stderr b/tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.stderr index 795de38d0279c..0a84848081d5c 100644 --- a/tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.stderr +++ b/tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.stderr @@ -35,6 +35,14 @@ help: you might have meant to use the available field LL | let _ = format!("{}", self.x); | +++++ -error: aborting due to 4 previous errors +error[E0425]: cannot find value `x` in this scope + --> $DIR/sugg-field-in-format-string-issue-141136.rs:11:20 + | +LL | println!("{x}"); + | ^ + | + = help: you might have meant to use the available field in a format string: `"{}", self.x` + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0425`. From c343b2a47c29bdfe4c611ba74f9c9e455f12539b Mon Sep 17 00:00:00 2001 From: dianne Date: Mon, 19 May 2025 23:18:08 -0700 Subject: [PATCH 2489/4206] `gather_locals`: only visit guard pattern guards when checking the guard When checking a pattern with guards in it, `GatherLocalsVisitor` will visit both the pattern (when type-checking the let, arm, or param containing it) and the guard expression (when checking the guard itself). This keeps it from visiting the guard when visiting the pattern, since otherwise it would gather locals from the guard twice, which would lead to a delayed bug: "evaluated expression more than once". --- compiler/rustc_hir_typeck/src/gather_locals.rs | 7 ++++++- .../only-gather-locals-once.rs | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 tests/ui/pattern/rfc-3637-guard-patterns/only-gather-locals-once.rs diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 956671fc66ed2..7d99b0e78694e 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -218,7 +218,12 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { ); } let old_outermost_fn_param_pat = self.outermost_fn_param_pat.take(); - intravisit::walk_pat(self, p); + if let PatKind::Guard(subpat, _) = p.kind { + // We'll visit the guard when checking it. Don't gather its locals twice. + self.visit_pat(subpat); + } else { + intravisit::walk_pat(self, p); + } self.outermost_fn_param_pat = old_outermost_fn_param_pat; } diff --git a/tests/ui/pattern/rfc-3637-guard-patterns/only-gather-locals-once.rs b/tests/ui/pattern/rfc-3637-guard-patterns/only-gather-locals-once.rs new file mode 100644 index 0000000000000..7bb39ca7bb987 --- /dev/null +++ b/tests/ui/pattern/rfc-3637-guard-patterns/only-gather-locals-once.rs @@ -0,0 +1,15 @@ +//@ check-pass +//! Test that `GatherLocalsVisitor` only visits expressions in guard patterns when checking the +//! expressions, and not a second time when visiting the pattern. If locals are declared inside the +//! the guard expression, it would ICE if visited twice ("evaluated expression more than once"). + +#![feature(guard_patterns)] +#![expect(incomplete_features)] + +fn main() { + match (0,) { + // FIXME(guard_patterns): liveness lints don't work yet; this will ICE without the `_`. + (_ if { let _x = false; _x },) => {} + _ => {} + } +} From cb07fd8cf767d1f158ab1bfb06a7f99deebf8c82 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 May 2025 08:56:00 +0200 Subject: [PATCH 2490/4206] Miri CI: test aarch64-apple-darwin in PRs instead of the x86_64 target --- src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh | 6 +++--- src/ci/github-actions/jobs.yml | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh index 9222710b84376..62e0451814b35 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh @@ -53,8 +53,8 @@ MIRIFLAGS="-Zmiri-force-intrinsic-fallback --cfg force_intrinsic_fallback -O -Zm case $HOST_TARGET in x86_64-unknown-linux-gnu) # Only this branch runs in PR CI. - # Fully test all main OSes, including a 32bit target. - python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri --target x86_64-apple-darwin + # Fully test all main OSes, and all main architectures. + python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri --target aarch64-apple-darwin python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri --target i686-pc-windows-msvc # Only run "pass" tests for the remaining targets, which is quite a bit faster. python3 "$X_PY" test --stage 2 src/tools/miri --target x86_64-pc-windows-gnu --test-args pass @@ -69,7 +69,7 @@ case $HOST_TARGET in #FIXME: Re-enable this once CI issues are fixed # See # For now, these tests are moved to `x86_64-msvc-ext2` in `src/ci/github-actions/jobs.yml`. - #python3 "$X_PY" test --stage 2 src/tools/miri --target aarch64-apple-darwin --test-args pass + #python3 "$X_PY" test --stage 2 src/tools/miri --target x86_64-apple-darwin --test-args pass ;; *) echo "FATAL: unexpected host $HOST_TARGET" diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 42ad5acbdac1e..988d1057630d7 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -522,11 +522,13 @@ auto: - name: x86_64-msvc-ext2 env: SCRIPT: > - python x.py test --stage 2 src/tools/miri --target aarch64-apple-darwin --test-args pass && + python x.py test --stage 2 src/tools/miri --target x86_64-apple-darwin --test-args pass && python x.py test --stage 2 src/tools/miri --target x86_64-pc-windows-gnu --test-args pass && python x.py miri --stage 2 library/core --test-args notest && python x.py miri --stage 2 library/alloc --test-args notest && python x.py miri --stage 2 library/std --test-args notest + # The last 3 lines smoke-test `x.py miri`. This doesn't run any actual tests (that would take + # too long), but it ensures that the crates build properly when tested with Miri. RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-lld <<: *job-windows From 1dafeea8cfe587aa55131709a46e21283faaeb20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 20 May 2025 10:00:23 +0300 Subject: [PATCH 2491/4206] Preparing for merge from rust-lang/rust --- src/tools/rust-analyzer/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index 90e4d65bf961c..5b47d1bbaed7c 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -6e23095adf9209614a45f7f75fea36dad7b92afb +a8e4c68dcb4dc1e48a0db294c5323cab0227fcb9 From a6674952979445a81a890a936d968f81cf766c61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 20 May 2025 10:03:14 +0300 Subject: [PATCH 2492/4206] Bump rustc crates --- src/tools/rust-analyzer/Cargo.lock | 28 +++++++++---------- src/tools/rust-analyzer/Cargo.toml | 15 ++++++---- .../crates/hir-def/src/hir/format_args.rs | 3 +- .../crates/parser/src/lexed_str.rs | 5 +++- 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 9eff747c21a90..c4d25284b278a 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1750,9 +1750,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_abi" -version = "0.110.0" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "912228bd8ed3beff1f6f9e5e2d4b37c0827ba3e2070060bf3858a311d0e29e30" +checksum = "c33b8fa229789975647ca5426be432c7c327ebde89ab15889928185dbcee3230" dependencies = [ "bitflags 2.9.0", "ra-ap-rustc_hashes", @@ -1762,18 +1762,18 @@ dependencies = [ [[package]] name = "ra-ap-rustc_hashes" -version = "0.110.0" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba520764daf057a9d963fa769f4762eaf87ac5d4900ae76195eeead64cd35afd" +checksum = "0d68a3e389927002f552938a90b04787f6435f55b46fc5691360470d1cb2e99d" dependencies = [ "rustc-stable-hash", ] [[package]] name = "ra-ap-rustc_index" -version = "0.110.0" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b76b5f9ee55f2d0e5a65bea23f6d738893349ce8d3d17a6720933e647ab04978" +checksum = "32502273df2838d0ca13f1c67e2a48feef940e591f9771869f07e2db2acede53" dependencies = [ "ra-ap-rustc_index_macros", "smallvec", @@ -1781,9 +1781,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_index_macros" -version = "0.110.0" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd972eb1face2fcaa0d94c01d97862fb955b5561d4f5932003bce8a6cadd8c6" +checksum = "8a32f081864ae34c7ae6634edfa7a95ab9260ba85015e8b1d347580eda79d14f" dependencies = [ "proc-macro2", "quote", @@ -1792,9 +1792,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_lexer" -version = "0.110.0" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a9876456fb2521097deef33ddeac1c18260c8eafb68054d986f8b9d6ce9fa" +checksum = "ed34c51974718c5bd90d876d1364d9725159fc8030c2382b9cb837034152ed68" dependencies = [ "memchr", "unicode-properties", @@ -1803,9 +1803,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.110.0" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e85de58dfcc60a5f9d5ec0157a657e3f84abd8f22c8a0c4d707cfb42c9011f4" +checksum = "ff0440e5d27facbf4ff13ea651e48c2f6e360b3dbfc56251b41d60719b965fb8" dependencies = [ "ra-ap-rustc_lexer", "rustc-literal-escaper", @@ -1813,9 +1813,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_pattern_analysis" -version = "0.110.0" +version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceadf9db550db67deff7eff2e2765109b860c9d7e5bdfca144863020289c823d" +checksum = "a6056efa57aba3aa0cc69a0bf1a8281624c23ad25b05748d11ebcd4668037bfc" dependencies = [ "ra-ap-rustc_index", "rustc-hash 2.1.1", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index c4c2fdf34bae9..07731bae3f30f 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -85,11 +85,11 @@ vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" } edition = { path = "./crates/edition", version = "0.0.0" } -ra-ap-rustc_lexer = { version = "0.110", default-features = false } -ra-ap-rustc_parse_format = { version = "0.110", default-features = false } -ra-ap-rustc_index = { version = "0.110", default-features = false } -ra-ap-rustc_abi = { version = "0.110", default-features = false } -ra-ap-rustc_pattern_analysis = { version = "0.110", default-features = false } +ra-ap-rustc_lexer = { version = "0.113", default-features = false } +ra-ap-rustc_parse_format = { version = "0.113", default-features = false } +ra-ap-rustc_index = { version = "0.113", default-features = false } +ra-ap-rustc_abi = { version = "0.113", default-features = false } +ra-ap-rustc_pattern_analysis = { version = "0.113", default-features = false } # local crates that aren't published to crates.io. These should not have versions. @@ -132,7 +132,10 @@ pulldown-cmark-to-cmark = "10.0.4" pulldown-cmark = { version = "0.9.6", default-features = false } rayon = "1.10.0" rowan = "=0.15.15" -salsa = { version = "0.21.1", default-features = false, features = ["rayon","salsa_unstable"] } +salsa = { version = "0.21.1", default-features = false, features = [ + "rayon", + "salsa_unstable", +] } salsa-macros = "0.21.1" semver = "1.0.26" serde = { version = "1.0.219" } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs index f27a4062a63b6..271484da7b9a2 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs @@ -297,7 +297,8 @@ pub(crate) fn parse( unfinished_literal.clear(); } - let span = parser.arg_places.get(placeholder_index).and_then(|s| to_span(s.clone())); + let span = + parser.arg_places.get(placeholder_index).and_then(|s| to_span(s.clone())); placeholder_index += 1; let position_span = to_span(position_span); diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs index 0a5c16dc4c499..0fa9a264545df 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs @@ -179,7 +179,10 @@ impl<'a> Converter<'a> { COMMENT } - rustc_lexer::TokenKind::Frontmatter { has_invalid_preceding_whitespace, invalid_infostring } => { + rustc_lexer::TokenKind::Frontmatter { + has_invalid_preceding_whitespace, + invalid_infostring, + } => { if *has_invalid_preceding_whitespace { err = "invalid preceding whitespace for frontmatter opening" } else if *invalid_infostring { From eb530325f08b9151cb1917d01a8cb913ab1dd1ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 20 May 2025 10:39:34 +0200 Subject: [PATCH 2493/4206] Use Docker cache from the current repository This is needed to make the cache work after moving CI from the `rust-lang-ci` org to `rust-lang`. --- src/ci/docker/run.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 36f7df2b06907..4e69fb2f37057 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -97,9 +97,8 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then docker --version REGISTRY=ghcr.io - # Hardcode username to reuse cache between auto and pr jobs - # FIXME: should be changed after move from rust-lang-ci - REGISTRY_USERNAME=rust-lang-ci + # Default to `rust-lang` to allow reusing the cache for local builds + REGISTRY_USERNAME=${GITHUB_REPOSITORY_OWNER:-rust-lang} # Tag used to push the final Docker image, so that it can be pulled by e.g. rustup IMAGE_TAG=${REGISTRY}/${REGISTRY_USERNAME}/rust-ci:${cksum} # Tag used to cache the Docker build From 0653799745f9f3b09e18b8cf16cb863ad8ea646d Mon Sep 17 00:00:00 2001 From: Stan Manilov Date: Tue, 20 May 2025 11:41:55 +0300 Subject: [PATCH 2494/4206] Small typo and style fixes in binders.md Normally I refrain from nit picking, but this seamed worth it. --- src/doc/rustc-dev-guide/src/ty_module/binders.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/ty_module/binders.md b/src/doc/rustc-dev-guide/src/ty_module/binders.md index 71157eca9b11e..7fd9eeed54aca 100644 --- a/src/doc/rustc-dev-guide/src/ty_module/binders.md +++ b/src/doc/rustc-dev-guide/src/ty_module/binders.md @@ -1,6 +1,6 @@ # `Binder` and Higher ranked regions -Sometimes we define generic parameters not on an item but as part of a type or a where clauses. As an example the type `for<'a> fn(&'a u32)` or the where clause `for<'a> T: Trait<'a>` both introduce a generic lifetime named `'a`. Currently there is no stable syntax for `for` or `for` but on nightly `feature(non_lifetime_binders)` feature can be used to write where clauses (but not types) using `for`/`for`. +Sometimes we define generic parameters not on an item but as part of a type or a where clause. As an example the type `for<'a> fn(&'a u32)` or the where clause `for<'a> T: Trait<'a>` both introduce a generic lifetime named `'a`. Currently there is no stable syntax for `for` or `for` but on nightly `feature(non_lifetime_binders)` can be used to write where clauses (but not types) using `for`/`for`. The `for` is referred to as a "binder" because it brings new names into scope. In rustc we use the `Binder` type to track where these parameters are introduced and what the parameters are (i.e. how many and whether the parameter is a type/const/region). A type such as `for<'a> fn(&'a u32)` would be represented in rustc as: @@ -13,8 +13,9 @@ Binder( Usages of these parameters is represented by the `RegionKind::Bound` (or `TyKind::Bound`/`ConstKind::Bound` variants). These bound regions/types/consts are composed of two main pieces of data: - A [DebruijnIndex](../appendix/background.md#what-is-a-de-bruijn-index) to specify which binder we are referring to. -- A [`BoundVar`] which specifies which of the parameters the `Binder` introduces we are referring to. -- We also sometimes store some extra information for diagnostics reasons via the [`BoundTyKind`]/[`BoundRegionKind`] but this is not important for type equality or more generally the semantics of `Ty`. (omitted from the above example) +- A [`BoundVar`] which specifies which of the parameters that the `Binder` introduces we are referring to. + +We also sometimes store some extra information for diagnostics reasons via the [`BoundTyKind`]/[`BoundRegionKind`] but this is not important for type equality or more generally the semantics of `Ty`. (omitted from the above example) In debug output (and also informally when talking to each other) we tend to write these bound variables in the format of `^DebruijnIndex_BoundVar`. The above example would instead be written as `Binder(fn(&'^0_0), &[BoundVariableKind::Region])`. Sometimes when the `DebruijnIndex` is `0` we just omit it and would write `^0`. @@ -43,7 +44,7 @@ Binder( &[BoundVariableKind::Region(...)], ) ``` -This would cause all kinds of issues as the region `'^1_0` refers to a binder at a higher level than the outermost binder i.e. it is an escaping bound var. The `'^1` region (also writeable as `'^0_1`) is also ill formed as the binder it refers to does not introduce a second parameter. Modern day rustc will ICE when constructing this binder due to both of those regions, in the past we would have simply allowed this to work and then ran into issues in other parts of the codebase. +This would cause all kinds of issues as the region `'^1_0` refers to a binder at a higher level than the outermost binder i.e. it is an escaping bound var. The `'^1` region (also writeable as `'^0_1`) is also ill formed as the binder it refers to does not introduce a second parameter. Modern day rustc will ICE when constructing this binder due to both of those reasons, in the past we would have simply allowed this to work and then ran into issues in other parts of the codebase. [`Binder`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Binder.html [`BoundVar`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.BoundVar.html From 04c7e5a7e320dfc4e5ffda56e370479c3974dbaf Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 20 May 2025 09:43:45 +0000 Subject: [PATCH 2495/4206] Rustup to rustc 1.89.0-nightly (60dabef95 2025-05-19) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 78cfde6ad01ab..4b6ed82762bed 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-05-18" +channel = "nightly-2025-05-20" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From e5617a79fba6705c36b8690f43d2ce6deb0a59d3 Mon Sep 17 00:00:00 2001 From: yanglsh Date: Mon, 5 May 2025 14:20:08 +0800 Subject: [PATCH 2496/4206] fix: `needless_for_each` suggests wrongly when closure has no braces --- clippy_lints/src/needless_for_each.rs | 32 ++++++++++++++++++++--- tests/ui/needless_for_each_fixable.fixed | 15 +++++++++++ tests/ui/needless_for_each_fixable.rs | 15 +++++++++++ tests/ui/needless_for_each_fixable.stderr | 14 +++++++++- 4 files changed, 71 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index 7dd96f1f037fd..6a7c8436bad4f 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { && let body = cx.tcx.hir_body(body) // Skip the lint if the body is not safe, so as not to suggest `for … in … unsafe {}` // and suggesting `for … in … { unsafe { } }` is a little ugly. - && let ExprKind::Block(Block { rules: BlockCheckMode::DefaultBlock, .. }, ..) = body.value.kind + && !matches!(body.value.kind, ExprKind::Block(Block { rules: BlockCheckMode::UnsafeBlock(_), .. }, ..)) { let mut ret_collector = RetCollector::default(); ret_collector.visit_expr(body.value); @@ -99,11 +99,21 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { ) }; + let body_param_sugg = snippet_with_applicability(cx, body.params[0].pat.span, "..", &mut applicability); + let for_each_rev_sugg = snippet_with_applicability(cx, for_each_recv.span, "..", &mut applicability); + let body_value_sugg = snippet_with_applicability(cx, body.value.span, "..", &mut applicability); + let sugg = format!( "for {} in {} {}", - snippet_with_applicability(cx, body.params[0].pat.span, "..", &mut applicability), - snippet_with_applicability(cx, for_each_recv.span, "..", &mut applicability), - snippet_with_applicability(cx, body.value.span, "..", &mut applicability), + body_param_sugg, + for_each_rev_sugg, + match body.value.kind { + ExprKind::Block(block, _) if is_let_desugar(block) => { + format!("{{ {body_value_sugg} }}") + }, + ExprKind::Block(_, _) => body_value_sugg.to_string(), + _ => format!("{{ {body_value_sugg}; }}"), + } ); span_lint_and_then(cx, NEEDLESS_FOR_EACH, stmt.span, "needless use of `for_each`", |diag| { @@ -116,6 +126,20 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { } } +/// Check if the block is a desugared `_ = expr` statement. +fn is_let_desugar(block: &Block<'_>) -> bool { + matches!( + block, + Block { + stmts: [Stmt { + kind: StmtKind::Let(_), + .. + },], + .. + } + ) +} + /// This type plays two roles. /// 1. Collect spans of `return` in the closure body. /// 2. Detect use of `return` in `Loop` in the closure body. diff --git a/tests/ui/needless_for_each_fixable.fixed b/tests/ui/needless_for_each_fixable.fixed index fa23e18318f19..a73aff556399e 100644 --- a/tests/ui/needless_for_each_fixable.fixed +++ b/tests/ui/needless_for_each_fixable.fixed @@ -128,3 +128,18 @@ fn should_not_lint() { } fn main() {} + +mod issue14734 { + fn let_desugar(rows: &[u8]) { + let mut v = vec![]; + for x in rows.iter() { _ = v.push(x) } + //~^ needless_for_each + } + + fn do_something(_: &u8, _: u8) {} + + fn single_expr(rows: &[u8]) { + for x in rows.iter() { do_something(x, 1u8); } + //~^ needless_for_each + } +} diff --git a/tests/ui/needless_for_each_fixable.rs b/tests/ui/needless_for_each_fixable.rs index 2c7e68a6f5128..d92f055d3f45b 100644 --- a/tests/ui/needless_for_each_fixable.rs +++ b/tests/ui/needless_for_each_fixable.rs @@ -128,3 +128,18 @@ fn should_not_lint() { } fn main() {} + +mod issue14734 { + fn let_desugar(rows: &[u8]) { + let mut v = vec![]; + rows.iter().for_each(|x| _ = v.push(x)); + //~^ needless_for_each + } + + fn do_something(_: &u8, _: u8) {} + + fn single_expr(rows: &[u8]) { + rows.iter().for_each(|x| do_something(x, 1u8)); + //~^ needless_for_each + } +} diff --git a/tests/ui/needless_for_each_fixable.stderr b/tests/ui/needless_for_each_fixable.stderr index 013a3fa3e36d5..f801445609769 100644 --- a/tests/ui/needless_for_each_fixable.stderr +++ b/tests/ui/needless_for_each_fixable.stderr @@ -136,5 +136,17 @@ LL + acc += elem; LL + } | -error: aborting due to 8 previous errors +error: needless use of `for_each` + --> tests/ui/needless_for_each_fixable.rs:135:9 + | +LL | rows.iter().for_each(|x| _ = v.push(x)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in rows.iter() { _ = v.push(x) }` + +error: needless use of `for_each` + --> tests/ui/needless_for_each_fixable.rs:142:9 + | +LL | rows.iter().for_each(|x| do_something(x, 1u8)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in rows.iter() { do_something(x, 1u8); }` + +error: aborting due to 10 previous errors From 520cb092b894f20b79a5e2a3139cc94be238c2af Mon Sep 17 00:00:00 2001 From: yanglsh Date: Sun, 18 May 2025 14:33:50 +0800 Subject: [PATCH 2497/4206] Apply `needless_for_each` to clippy itself --- lintcheck/src/output.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lintcheck/src/output.rs b/lintcheck/src/output.rs index dcc1ec339ef90..d7fe0915121db 100644 --- a/lintcheck/src/output.rs +++ b/lintcheck/src/output.rs @@ -162,9 +162,9 @@ pub fn summarize_and_print_changes( fn gather_stats(warnings: &[ClippyWarning]) -> (String, HashMap<&String, usize>) { // count lint type occurrences let mut counter: HashMap<&String, usize> = HashMap::new(); - warnings - .iter() - .for_each(|wrn| *counter.entry(&wrn.name).or_insert(0) += 1); + for wrn in warnings { + *counter.entry(&wrn.name).or_insert(0) += 1; + } // collect into a tupled list for sorting let mut stats: Vec<(&&String, &usize)> = counter.iter().collect(); From 7e7c2c3947089834791a9d302f76947c00300b7d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 5 Apr 2025 18:06:47 +0000 Subject: [PATCH 2498/4206] Just error on recursive opaque ty in HIR typeck --- compiler/rustc_hir_typeck/src/writeback.rs | 70 +++++++++++++++++- .../impl-trait/issues/issue-100075-2.stderr | 15 ++-- .../ui/impl-trait/issues/issue-100075.stderr | 5 +- tests/ui/impl-trait/issues/issue-103599.rs | 5 +- .../ui/impl-trait/issues/issue-103599.stderr | 13 +++- tests/ui/impl-trait/issues/issue-87450.rs | 4 +- tests/ui/impl-trait/issues/issue-87450.stderr | 18 ++--- .../recursive-impl-trait-type-indirect.stderr | 73 ++++--------------- ...recursive-in-exhaustiveness.current.stderr | 53 +++----------- .../recursive-in-exhaustiveness.next.stderr | 18 ++--- .../impl-trait/recursive-in-exhaustiveness.rs | 6 +- .../infinite-cycle-involving-weak.rs | 2 +- .../infinite-cycle-involving-weak.stderr | 6 +- .../match-upvar-discriminant-of-opaque.rs} | 6 +- .../match-upvar-discriminant-of-opaque.stderr | 9 +++ .../recursive-fn-tait.rs | 2 +- .../recursive-fn-tait.stderr | 11 +-- .../recursive-tait-conflicting-defn-2.rs | 2 +- .../recursive-tait-conflicting-defn-2.stderr | 9 +-- .../recursive-tait-conflicting-defn.rs | 2 +- .../recursive-tait-conflicting-defn.stderr | 11 +-- 21 files changed, 157 insertions(+), 183 deletions(-) rename tests/{crashes/139817.rs => ui/type-alias-impl-trait/match-upvar-discriminant-of-opaque.rs} (62%) create mode 100644 tests/ui/type-alias-impl-trait/match-upvar-discriminant-of-opaque.stderr diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 9be041f75d769..b2497cb0de16b 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -9,17 +9,21 @@ //! which creates a new `TypeckResults` which doesn't contain any inference variables. use std::mem; +use std::ops::ControlFlow; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::unord::ExtendUnord; -use rustc_errors::ErrorGuaranteed; +use rustc_errors::{E0720, ErrorGuaranteed}; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, InferKind, Visitor}; use rustc_hir::{self as hir, AmbigArg, HirId}; use rustc_infer::traits::solve::Goal; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; use rustc_middle::ty::{ - self, DefiningScopeKind, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, - TypeVisitableExt, fold_regions, + self, DefiningScopeKind, OpaqueHiddenType, Ty, TyCtxt, TypeFoldable, TypeFolder, + TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, + fold_regions, }; use rustc_span::{Span, sym}; use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; @@ -595,6 +599,35 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { entry.span = prev.span.substitute_dummy(hidden_type.span); } } + + let recursive_opaques: Vec<_> = self + .typeck_results + .concrete_opaque_types + .iter() + .filter(|&(&def_id, hidden_ty)| { + hidden_ty + .ty + .visit_with(&mut HasRecursiveOpaque { + def_id, + seen: Default::default(), + opaques: &self.typeck_results.concrete_opaque_types, + tcx, + }) + .is_break() + }) + .map(|(def_id, hidden_ty)| (*def_id, hidden_ty.span)) + .collect(); + for (def_id, span) in recursive_opaques { + let guar = self + .fcx + .dcx() + .struct_span_err(span, "cannot resolve opaque type") + .with_code(E0720) + .emit(); + self.typeck_results + .concrete_opaque_types + .insert(def_id, OpaqueHiddenType { span, ty: Ty::new_error(tcx, guar) }); + } } fn visit_field_id(&mut self, hir_id: HirId) { @@ -959,3 +992,34 @@ impl<'tcx> TypeFolder> for EagerlyNormalizeConsts<'tcx> { self.tcx.try_normalize_erasing_regions(self.typing_env, ct).unwrap_or(ct) } } + +struct HasRecursiveOpaque<'a, 'tcx> { + def_id: LocalDefId, + seen: FxHashSet, + opaques: &'a FxIndexMap>, + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> TypeVisitor> for HasRecursiveOpaque<'_, 'tcx> { + type Result = ControlFlow<()>; + + fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { + if let ty::Alias(ty::Opaque, alias_ty) = *t.kind() + && let Some(def_id) = alias_ty.def_id.as_local() + { + if self.def_id == def_id { + return ControlFlow::Break(()); + } + + if self.seen.insert(def_id) + && let Some(hidden_ty) = self.opaques.get(&def_id) + { + ty::EarlyBinder::bind(hidden_ty.ty) + .instantiate(self.tcx, alias_ty.args) + .visit_with(self)?; + } + } + + t.super_visit_with(self) + } +} diff --git a/tests/ui/impl-trait/issues/issue-100075-2.stderr b/tests/ui/impl-trait/issues/issue-100075-2.stderr index b3b6967750705..554c3ea34331e 100644 --- a/tests/ui/impl-trait/issues/issue-100075-2.stderr +++ b/tests/ui/impl-trait/issues/issue-100075-2.stderr @@ -1,3 +1,9 @@ +error[E0720]: cannot resolve opaque type + --> $DIR/issue-100075-2.rs:1:23 + | +LL | fn opaque(t: T) -> impl Sized { + | ^^^^^^^^^^ + warning: function cannot return without recursing --> $DIR/issue-100075-2.rs:1:1 | @@ -10,15 +16,6 @@ LL | opaque(Some(t)) = help: a `loop` may express intention better if this is on purpose = note: `#[warn(unconditional_recursion)]` on by default -error[E0720]: cannot resolve opaque type - --> $DIR/issue-100075-2.rs:1:23 - | -LL | fn opaque(t: T) -> impl Sized { - | ^^^^^^^^^^ recursive opaque type -... -LL | opaque(Some(t)) - | --------------- returning here with type `impl Sized` - error: aborting due to 1 previous error; 1 warning emitted For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/issues/issue-100075.stderr b/tests/ui/impl-trait/issues/issue-100075.stderr index 7596348923693..bca2874b2b4b1 100644 --- a/tests/ui/impl-trait/issues/issue-100075.stderr +++ b/tests/ui/impl-trait/issues/issue-100075.stderr @@ -2,10 +2,7 @@ error[E0720]: cannot resolve opaque type --> $DIR/issue-100075.rs:13:37 | LL | fn _g(t: &'static T) -> &'static impl Marker { - | ^^^^^^^^^^^ recursive opaque type -... -LL | return _g(t); - | ----- returning here with type `&impl Marker` + | ^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/issues/issue-103599.rs b/tests/ui/impl-trait/issues/issue-103599.rs index 62741a7454cee..e674ce3cbdf8f 100644 --- a/tests/ui/impl-trait/issues/issue-103599.rs +++ b/tests/ui/impl-trait/issues/issue-103599.rs @@ -1,9 +1,8 @@ -//@ check-pass - trait T {} fn wrap(x: impl T) -> impl T { - //~^ WARN function cannot return without recursing + //~^ ERROR cannot resolve opaque type + //~| WARN function cannot return without recursing wrap(wrap(x)) } diff --git a/tests/ui/impl-trait/issues/issue-103599.stderr b/tests/ui/impl-trait/issues/issue-103599.stderr index 82038c1dceb37..9878b12044f70 100644 --- a/tests/ui/impl-trait/issues/issue-103599.stderr +++ b/tests/ui/impl-trait/issues/issue-103599.stderr @@ -1,14 +1,21 @@ +error[E0720]: cannot resolve opaque type + --> $DIR/issue-103599.rs:3:23 + | +LL | fn wrap(x: impl T) -> impl T { + | ^^^^^^ + warning: function cannot return without recursing - --> $DIR/issue-103599.rs:5:1 + --> $DIR/issue-103599.rs:3:1 | LL | fn wrap(x: impl T) -> impl T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing -LL | +... LL | wrap(wrap(x)) | ------- recursive call site | = help: a `loop` may express intention better if this is on purpose = note: `#[warn(unconditional_recursion)]` on by default -warning: 1 warning emitted +error: aborting due to 1 previous error; 1 warning emitted +For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/issues/issue-87450.rs b/tests/ui/impl-trait/issues/issue-87450.rs index 983ef7cfbe0af..5a7759af1119f 100644 --- a/tests/ui/impl-trait/issues/issue-87450.rs +++ b/tests/ui/impl-trait/issues/issue-87450.rs @@ -3,8 +3,8 @@ fn bar() -> impl Fn() { } fn foo() -> impl Fn() { - //~^ WARNING 5:1: 5:22: function cannot return without recursing [unconditional_recursion] - //~| ERROR 5:13: 5:22: cannot resolve opaque type [E0720] + //~^ WARN function cannot return without recursing + //~| ERROR cannot resolve opaque type wrap(wrap(wrap(wrap(wrap(wrap(wrap(foo()))))))) } diff --git a/tests/ui/impl-trait/issues/issue-87450.stderr b/tests/ui/impl-trait/issues/issue-87450.stderr index 9567e09651d6c..f0f8b5859c031 100644 --- a/tests/ui/impl-trait/issues/issue-87450.stderr +++ b/tests/ui/impl-trait/issues/issue-87450.stderr @@ -1,3 +1,9 @@ +error[E0720]: cannot resolve opaque type + --> $DIR/issue-87450.rs:5:13 + | +LL | fn foo() -> impl Fn() { + | ^^^^^^^^^ + warning: function cannot return without recursing --> $DIR/issue-87450.rs:5:1 | @@ -10,18 +16,6 @@ LL | wrap(wrap(wrap(wrap(wrap(wrap(wrap(foo()))))))) = help: a `loop` may express intention better if this is on purpose = note: `#[warn(unconditional_recursion)]` on by default -error[E0720]: cannot resolve opaque type - --> $DIR/issue-87450.rs:5:13 - | -LL | fn foo() -> impl Fn() { - | ^^^^^^^^^ recursive opaque type -... -LL | wrap(wrap(wrap(wrap(wrap(wrap(wrap(foo()))))))) - | ----------------------------------------------- returning here with type `impl Fn()` -... -LL | fn wrap(f: impl Fn()) -> impl Fn() { - | --------- returning this opaque type `impl Fn()` - error: aborting due to 1 previous error; 1 warning emitted For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr index 2d2731e4368f5..af84375c74766 100644 --- a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr +++ b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr @@ -2,112 +2,67 @@ error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:6:22 | LL | fn option(i: i32) -> impl Sized { - | ^^^^^^^^^^ recursive opaque type -LL | -LL | if i < 0 { None } else { Some((option(i - 1), i)) } - | ---- ------------------------ returning here with type `Option<(impl Sized, i32)>` - | | - | returning here with type `Option<(impl Sized, i32)>` + | ^^^^^^^^^^ error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:11:15 | LL | fn tuple() -> impl Sized { - | ^^^^^^^^^^ recursive opaque type -LL | -LL | (tuple(),) - | ---------- returning here with type `(impl Sized,)` + | ^^^^^^^^^^ error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:16:15 | LL | fn array() -> impl Sized { - | ^^^^^^^^^^ recursive opaque type -LL | -LL | [array()] - | --------- returning here with type `[impl Sized; 1]` + | ^^^^^^^^^^ error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:21:13 | LL | fn ptr() -> impl Sized { - | ^^^^^^^^^^ recursive opaque type -LL | -LL | &ptr() as *const _ - | ------------------ returning here with type `*const impl Sized` + | ^^^^^^^^^^ error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:26:16 | LL | fn fn_ptr() -> impl Sized { - | ^^^^^^^^^^ recursive opaque type -LL | -LL | fn_ptr as fn() -> _ - | ------------------- returning here with type `fn() -> impl Sized` + | ^^^^^^^^^^ error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:31:25 | -LL | fn closure_capture() -> impl Sized { - | ^^^^^^^^^^ recursive opaque type -... -LL | / move || { -LL | | x; - | | - closure captures itself here -LL | | } - | |_____- returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:34:5: 34:12}` +LL | fn closure_capture() -> impl Sized { + | ^^^^^^^^^^ error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:39:29 | -LL | fn closure_ref_capture() -> impl Sized { - | ^^^^^^^^^^ recursive opaque type -... -LL | / move || { -LL | | &x; - | | - closure captures itself here -LL | | } - | |_____- returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:42:5: 42:12}` +LL | fn closure_ref_capture() -> impl Sized { + | ^^^^^^^^^^ error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:47:21 | LL | fn closure_sig() -> impl Sized { - | ^^^^^^^^^^ recursive opaque type -LL | -LL | || closure_sig() - | ---------------- returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:49:5: 49:7}` + | ^^^^^^^^^^ error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:52:23 | LL | fn coroutine_sig() -> impl Sized { - | ^^^^^^^^^^ recursive opaque type -LL | -LL | || coroutine_sig() - | ------------------ returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:54:5: 54:7}` + | ^^^^^^^^^^ error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:57:27 | -LL | fn coroutine_capture() -> impl Sized { - | ^^^^^^^^^^ recursive opaque type -... -LL | / move || { -LL | | yield; -LL | | x; - | | - coroutine captures itself here -LL | | } - | |_____- returning here with type `{coroutine@$DIR/recursive-impl-trait-type-indirect.rs:62:5: 62:12}` +LL | fn coroutine_capture() -> impl Sized { + | ^^^^^^^^^^ error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:68:35 | LL | fn substs_change() -> impl Sized { - | ^^^^^^^^^^ recursive opaque type -LL | -LL | (substs_change::<&T>(),) - | ------------------------ returning here with type `(impl Sized,)` + | ^^^^^^^^^^ error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:78:26 diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr b/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr index 42dbc7c91607f..080c328464153 100644 --- a/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr +++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr @@ -1,56 +1,21 @@ -warning: function cannot return without recursing - --> $DIR/recursive-in-exhaustiveness.rs:17:1 +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-in-exhaustiveness.rs:17:22 | LL | fn build(x: T) -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing -LL | -LL | let (x,) = (build(x),); - | -------- recursive call site - | - = help: a `loop` may express intention better if this is on purpose - = note: `#[warn(unconditional_recursion)]` on by default - -warning: function cannot return without recursing - --> $DIR/recursive-in-exhaustiveness.rs:27:1 - | -LL | fn build2(x: T) -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing -... -LL | let (x,) = (build2(x),); - | --------- recursive call site - | - = help: a `loop` may express intention better if this is on purpose + | ^^^^^^^^^^ error[E0720]: cannot resolve opaque type --> $DIR/recursive-in-exhaustiveness.rs:27:23 | LL | fn build2(x: T) -> impl Sized { - | ^^^^^^^^^^ recursive opaque type -... -LL | (build2(x),) - | ------------ returning here with type `(impl Sized,)` + | ^^^^^^^^^^ -warning: function cannot return without recursing - --> $DIR/recursive-in-exhaustiveness.rs:40:1 - | -LL | fn build3(x: T) -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing -LL | -LL | let (x,) = (build3((x,)),); - | ------------ recursive call site - | - = help: a `loop` may express intention better if this is on purpose - -error[E0792]: expected generic type parameter, found `(T,)` - --> $DIR/recursive-in-exhaustiveness.rs:49:5 +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-in-exhaustiveness.rs:39:23 | LL | fn build3(x: T) -> impl Sized { - | - this generic parameter must be used with a generic type parameter -... -LL | build3(x) - | ^^^^^^^^^ + | ^^^^^^^^^^ -error: aborting due to 2 previous errors; 3 warnings emitted +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0720, E0792. -For more information about an error, try `rustc --explain E0720`. +For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr b/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr index 4c3d5aa8fb8f0..a3609b93cb3a8 100644 --- a/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr +++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr @@ -5,19 +5,19 @@ LL | let (x,) = (build(x),); | ^^^^^^^^ cannot satisfy `impl Sized == _` error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _` - --> $DIR/recursive-in-exhaustiveness.rs:31:6 + --> $DIR/recursive-in-exhaustiveness.rs:30:6 | LL | (build2(x),) | ^^^^^^^^^ types differ error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _` - --> $DIR/recursive-in-exhaustiveness.rs:31:5 + --> $DIR/recursive-in-exhaustiveness.rs:30:5 | LL | (build2(x),) | ^^^^^^^^^^^^ types differ error[E0277]: the size for values of type `(impl Sized,)` cannot be known at compilation time - --> $DIR/recursive-in-exhaustiveness.rs:31:5 + --> $DIR/recursive-in-exhaustiveness.rs:30:5 | LL | (build2(x),) | ^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -26,13 +26,13 @@ LL | (build2(x),) = note: tuples must have a statically known size to be initialized error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _` - --> $DIR/recursive-in-exhaustiveness.rs:42:17 + --> $DIR/recursive-in-exhaustiveness.rs:41:17 | LL | let (x,) = (build3((x,)),); | ^^^^^^^^^^^^ types differ error[E0277]: the size for values of type `(impl Sized,)` cannot be known at compilation time - --> $DIR/recursive-in-exhaustiveness.rs:42:16 + --> $DIR/recursive-in-exhaustiveness.rs:41:16 | LL | let (x,) = (build3((x,)),); | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -41,7 +41,7 @@ LL | let (x,) = (build3((x,)),); = note: tuples must have a statically known size to be initialized error[E0308]: mismatched types - --> $DIR/recursive-in-exhaustiveness.rs:42:16 + --> $DIR/recursive-in-exhaustiveness.rs:41:16 | LL | fn build3(x: T) -> impl Sized { | ---------- the found opaque type @@ -53,7 +53,7 @@ LL | let (x,) = (build3((x,)),); found tuple `(impl Sized,)` error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _` - --> $DIR/recursive-in-exhaustiveness.rs:42:17 + --> $DIR/recursive-in-exhaustiveness.rs:41:17 | LL | let (x,) = (build3((x,)),); | ^^^^^^^^^^^^ types differ @@ -61,13 +61,13 @@ LL | let (x,) = (build3((x,)),); = note: the return type of a function must have a statically known size error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _` - --> $DIR/recursive-in-exhaustiveness.rs:42:16 + --> $DIR/recursive-in-exhaustiveness.rs:41:16 | LL | let (x,) = (build3((x,)),); | ^^^^^^^^^^^^^^^ types differ error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _` - --> $DIR/recursive-in-exhaustiveness.rs:42:17 + --> $DIR/recursive-in-exhaustiveness.rs:41:17 | LL | let (x,) = (build3((x,)),); | ^^^^^^^^^^^^ types differ diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.rs b/tests/ui/impl-trait/recursive-in-exhaustiveness.rs index 58944533686cc..fa8fa0e81743b 100644 --- a/tests/ui/impl-trait/recursive-in-exhaustiveness.rs +++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.rs @@ -15,7 +15,7 @@ // We unfortunately accept this today, and due to how opaque type relating is implemented // in the NLL type relation, this defines `Opaque = T`. fn build(x: T) -> impl Sized { - //[current]~^ WARN function cannot return without recursing + //[current]~^ ERROR cannot resolve opaque type let (x,) = (build(x),); //[next]~^ ERROR type annotations needed build(x) @@ -26,7 +26,6 @@ fn build(x: T) -> impl Sized { // Not allowed today. Detected as recursive. fn build2(x: T) -> impl Sized { //[current]~^ ERROR cannot resolve opaque type - //[current]~| WARN function cannot return without recursing let (x,) = (build2(x),); (build2(x),) //[next]~^ ERROR type mismatch resolving @@ -38,7 +37,7 @@ fn build2(x: T) -> impl Sized { // // Not allowed today. Detected as not defining. fn build3(x: T) -> impl Sized { - //[current]~^ WARN function cannot return without recursing + //[current]~^ ERROR cannot resolve opaque type let (x,) = (build3((x,)),); //[next]~^ ERROR type mismatch resolving //[next]~| ERROR type mismatch resolving @@ -47,7 +46,6 @@ fn build3(x: T) -> impl Sized { //[next]~| ERROR the size for values of type //[next]~| ERROR mismatched types build3(x) - //[current]~^ ERROR expected generic type parameter, found `(T,)` } fn main() {} diff --git a/tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.rs b/tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.rs index ef6871bec7c42..0aaee5d1764e1 100644 --- a/tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.rs +++ b/tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.rs @@ -1,10 +1,10 @@ #![feature(type_alias_impl_trait)] type T = impl Copy; -//~^ ERROR cannot resolve opaque type #[define_opaque(T)] fn foo() -> T { + //~^ ERROR cannot resolve opaque type None::<&'static T> } diff --git a/tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.stderr b/tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.stderr index d820df472f95b..426a6c29fff66 100644 --- a/tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.stderr +++ b/tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.stderr @@ -1,8 +1,8 @@ error[E0720]: cannot resolve opaque type - --> $DIR/infinite-cycle-involving-weak.rs:3:10 + --> $DIR/infinite-cycle-involving-weak.rs:6:13 | -LL | type T = impl Copy; - | ^^^^^^^^^ cannot resolve opaque type +LL | fn foo() -> T { + | ^ error: aborting due to 1 previous error diff --git a/tests/crashes/139817.rs b/tests/ui/type-alias-impl-trait/match-upvar-discriminant-of-opaque.rs similarity index 62% rename from tests/crashes/139817.rs rename to tests/ui/type-alias-impl-trait/match-upvar-discriminant-of-opaque.rs index d439ed4cacbd6..f4e2cb0c037b4 100644 --- a/tests/crashes/139817.rs +++ b/tests/ui/type-alias-impl-trait/match-upvar-discriminant-of-opaque.rs @@ -1,8 +1,12 @@ -//@ known-bug: #139817 +#![feature(type_alias_impl_trait)] + fn enum_upvar() { type T = impl Copy; let foo: T = Some((42, std::marker::PhantomData::)); let x = move || match foo { None => (), + //~^ ERROR cannot resolve opaque type }; } + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/match-upvar-discriminant-of-opaque.stderr b/tests/ui/type-alias-impl-trait/match-upvar-discriminant-of-opaque.stderr new file mode 100644 index 0000000000000..2bfce2d63a8ee --- /dev/null +++ b/tests/ui/type-alias-impl-trait/match-upvar-discriminant-of-opaque.stderr @@ -0,0 +1,9 @@ +error[E0720]: cannot resolve opaque type + --> $DIR/match-upvar-discriminant-of-opaque.rs:7:9 + | +LL | None => (), + | ^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/type-alias-impl-trait/recursive-fn-tait.rs b/tests/ui/type-alias-impl-trait/recursive-fn-tait.rs index 94597adfed04f..fe354cc65452b 100644 --- a/tests/ui/type-alias-impl-trait/recursive-fn-tait.rs +++ b/tests/ui/type-alias-impl-trait/recursive-fn-tait.rs @@ -13,7 +13,7 @@ pub fn add( n: Diff, m: Diff, ) -> Diff { - //~^ ERROR concrete type differs + //~^ ERROR cannot resolve opaque type move |x: usize| m(n(x)) } diff --git a/tests/ui/type-alias-impl-trait/recursive-fn-tait.stderr b/tests/ui/type-alias-impl-trait/recursive-fn-tait.stderr index 59ff991761247..847f1cc6c2eb6 100644 --- a/tests/ui/type-alias-impl-trait/recursive-fn-tait.stderr +++ b/tests/ui/type-alias-impl-trait/recursive-fn-tait.stderr @@ -1,14 +1,9 @@ -error: concrete type differs from previous defining opaque type use +error[E0720]: cannot resolve opaque type --> $DIR/recursive-fn-tait.rs:15:6 | LL | ) -> Diff { - | ^^^^ expected `{closure@$DIR/recursive-fn-tait.rs:8:5: 8:16}`, got `{closure@$DIR/recursive-fn-tait.rs:17:5: 17:20}` - | -note: previous use here - --> $DIR/recursive-fn-tait.rs:7:18 - | -LL | pub fn lift() -> Diff { - | ^^^^ + | ^^^^ error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.rs b/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.rs index 858f2a2feb678..7803b3b78db83 100644 --- a/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.rs +++ b/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.rs @@ -13,7 +13,7 @@ fn transform() -> impl std::fmt::Display { } #[define_opaque(Op)] fn bad() -> Op { - //~^ ERROR concrete type differs from previous defining opaque type use + //~^ ERROR cannot resolve opaque type transform::() } diff --git a/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.stderr b/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.stderr index e527b5bc7f8f8..837df7f5d4340 100644 --- a/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.stderr +++ b/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.stderr @@ -1,14 +1,9 @@ -error: concrete type differs from previous defining opaque type use +error[E0720]: cannot resolve opaque type --> $DIR/recursive-tait-conflicting-defn-2.rs:15:13 | LL | fn bad() -> Op { - | ^^ expected `&&str`, got `impl std::fmt::Display` - | -note: previous use here - --> $DIR/recursive-tait-conflicting-defn-2.rs:7:13 - | -LL | fn foo() -> Op { | ^^ error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.rs b/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.rs index 90581a98a3468..d66ceda523498 100644 --- a/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.rs +++ b/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.rs @@ -23,7 +23,7 @@ pub fn test() -> TestImpl { #[define_opaque(TestImpl)] fn make_option2() -> Option { - //~^ ERROR concrete type differs from previous defining opaque type use + //~^ ERROR cannot resolve opaque type let inner = make_option().unwrap(); Some(B { inner }) } diff --git a/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.stderr b/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.stderr index 256f13b622179..c7a3381d61588 100644 --- a/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.stderr +++ b/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.stderr @@ -1,14 +1,9 @@ -error: concrete type differs from previous defining opaque type use +error[E0720]: cannot resolve opaque type --> $DIR/recursive-tait-conflicting-defn.rs:25:22 | LL | fn make_option2() -> Option { - | ^^^^^^^^^^^^^^^^ expected `A`, got `B` - | -note: previous use here - --> $DIR/recursive-tait-conflicting-defn.rs:20:18 - | -LL | pub fn test() -> TestImpl { - | ^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0720`. From 47b9e373cba69d66da9f91345219ff4f07eba84a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 28 Apr 2025 19:41:37 +0000 Subject: [PATCH 2499/4206] Revert "Fix stack overflow in exhaustiveness due to recursive HIR opaque type values" This reverts commit b08e9c2a60f4dbab4bdaa733727947b3395de329. --- compiler/rustc_pattern_analysis/src/rustc.rs | 40 +++----------------- 1 file changed, 5 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index a89d01dcbbe4a..d9f1888bfd9ad 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -1,6 +1,5 @@ use std::fmt; use std::iter::once; -use std::ops::ControlFlow; use rustc_abi::{FIRST_VARIANT, FieldIdx, Integer, VariantIdx}; use rustc_arena::DroplessArena; @@ -12,8 +11,7 @@ use rustc_middle::mir::{self, Const}; use rustc_middle::thir::{self, Pat, PatKind, PatRange, PatRangeBoundary}; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{ - self, FieldDef, OpaqueTypeKey, ScalarInt, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, - TypeVisitableExt, TypeVisitor, VariantDef, + self, FieldDef, OpaqueTypeKey, ScalarInt, Ty, TyCtxt, TypeVisitableExt, VariantDef, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint; @@ -137,22 +135,11 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { /// Returns the hidden type corresponding to this key if the body under analysis is allowed to /// know it. fn reveal_opaque_key(&self, key: OpaqueTypeKey<'tcx>) -> Option> { - if let Some(hidden_ty) = self.typeck_results.concrete_opaque_types.get(&key.def_id) { - let ty = ty::EarlyBinder::bind(hidden_ty.ty).instantiate(self.tcx, key.args); - if ty.visit_with(&mut RecursiveOpaque { def_id: key.def_id.into() }).is_continue() { - Some(ty) - } else { - // HACK: We skip revealing opaque types which recursively expand - // to themselves. This is because we may infer hidden types like - // `Opaque = Opaque>` or `Opaque = Opaque<(T,)>` - // in hir typeck. - None - } - } else { - None - } + self.typeck_results + .concrete_opaque_types + .get(&key.def_id) + .map(|x| ty::EarlyBinder::bind(x.ty).instantiate(self.tcx, key.args)) } - // This can take a non-revealed `Ty` because it reveals opaques itself. pub fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool { !ty.inhabited_predicate(self.tcx).apply_revealing_opaque( @@ -1177,20 +1164,3 @@ fn detect_mixed_deref_pat_ctors<'p, 'tcx>( } Ok(()) } - -struct RecursiveOpaque { - def_id: DefId, -} -impl<'tcx> TypeVisitor> for RecursiveOpaque { - type Result = ControlFlow<()>; - - fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { - if let ty::Alias(ty::Opaque, alias_ty) = t.kind() { - if alias_ty.def_id == self.def_id { - return ControlFlow::Break(()); - } - } - - if t.has_opaque_types() { t.super_visit_with(self) } else { ControlFlow::Continue(()) } - } -} From 37260e1c5b920baf12ec0dd6755751d1783e27ed Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 20 May 2025 10:22:08 +0000 Subject: [PATCH 2500/4206] Allow trailing comma after argument in query definition --- compiler/rustc_macros/src/query.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index ee377277017a5..2196f71299a53 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -51,6 +51,7 @@ impl Parse for Query { let key = Pat::parse_single(&arg_content)?; arg_content.parse::()?; let arg = arg_content.parse()?; + let _ = arg_content.parse::>()?; let result = input.parse()?; // Parse the query modifiers From 1d8db54f7634363d93232a412b265d0d196c0bb8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 20 May 2025 10:24:21 +0000 Subject: [PATCH 2501/4206] Add tick to RePlaceholder debug output --- compiler/rustc_type_ir/src/region_kind.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs index eae3213ead0d0..1b5d04e6025fa 100644 --- a/compiler/rustc_type_ir/src/region_kind.rs +++ b/compiler/rustc_type_ir/src/region_kind.rs @@ -193,7 +193,7 @@ impl fmt::Debug for RegionKind { ReVar(vid) => write!(f, "{vid:?}"), - RePlaceholder(placeholder) => write!(f, "{placeholder:?}"), + RePlaceholder(placeholder) => write!(f, "'{placeholder:?}"), // Use `'{erased}` as the output instead of `'erased` so that its more obviously distinct from // a `ReEarlyParam` named `'erased`. Technically that would print as `'erased/#IDX` so this is From 2754f18199697c8b16439a6d32c48e57ec5daa4b Mon Sep 17 00:00:00 2001 From: Stan Manilov Date: Tue, 20 May 2025 13:46:04 +0300 Subject: [PATCH 2502/4206] Update links between ty-module and binders The order might have been reversed at some point, leading to the two chapters talking about each other in the wrong order. --- .../src/ty_module/instantiating_binders.md | 4 +++- .../src/ty_module/param_ty_const_regions.md | 12 ++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/ty_module/instantiating_binders.md b/src/doc/rustc-dev-guide/src/ty_module/instantiating_binders.md index 04d56ccbc6310..e3f091ca45f2e 100644 --- a/src/doc/rustc-dev-guide/src/ty_module/instantiating_binders.md +++ b/src/doc/rustc-dev-guide/src/ty_module/instantiating_binders.md @@ -105,7 +105,8 @@ the `RePlaceholder` for the `'b` parameter is in a higher universe to track the ## Instantiating with `ReLateParam` -As discussed in a previous chapter, `RegionKind` has two variants for representing generic parameters, `ReLateParam` and `ReEarlyParam`. `ReLateParam` is conceptually a `Placeholder` that is always in the root universe (`U0`). It is used when instantiating late bound parameters of functions/closures while inside of them. Its actual representation is relatively different from both `ReEarlyParam` and `RePlaceholder`: +As discussed in [the chapter about representing types][representing-types], `RegionKind` has two variants for representing generic parameters, `ReLateParam` and `ReEarlyParam`. +`ReLateParam` is conceptually a `Placeholder` that is always in the root universe (`U0`). It is used when instantiating late bound parameters of functions/closures while inside of them. Its actual representation is relatively different from both `ReEarlyParam` and `RePlaceholder`: - A `DefId` for the item that introduced the late bound generic parameter - A [`BoundRegionKind`] which either specifies the `DefId` of the generic parameter and its name (via a `Symbol`), or that this placeholder is representing the anonymous lifetime of a `Fn`/`FnMut` closure's self borrow. There is also a variant for `BrAnon` but this is not used for `ReLateParam`. @@ -133,6 +134,7 @@ Generally whenever we have a `Binder` for late bound parameters on a function/cl As a concrete example, accessing the signature of a function we are type checking will be represented as `EarlyBinder>`. As we are already "inside" of these binders, we would call `instantiate_identity` followed by `liberate_late_bound_regions`. [`liberate_late_bound_regions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.liberate_late_bound_regions +[representing-types]: param_ty_const_regions.md [`BoundRegionKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.BoundRegionKind.html [`enter_forall`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/infer/struct.InferCtxt.html#method.enter_forall [ch_placeholders_universes]: ../borrow_check/region_inference/placeholders_and_universes.md diff --git a/src/doc/rustc-dev-guide/src/ty_module/param_ty_const_regions.md b/src/doc/rustc-dev-guide/src/ty_module/param_ty_const_regions.md index c52f0c0df2a4c..493693c9a4400 100644 --- a/src/doc/rustc-dev-guide/src/ty_module/param_ty_const_regions.md +++ b/src/doc/rustc-dev-guide/src/ty_module/param_ty_const_regions.md @@ -11,15 +11,15 @@ TyKind::Ref( There are three separate ways we represent usages of generic parameters: - [`TyKind::Param`]/[`ConstKind::Param`]/[`RegionKind::EarlyParam`] for early bound generic parameters (note: all type and const parameters are considered early bound, see the [chapter on early vs late bound parameters][ch_early_late_bound] for more information) -- [`TyKind::Bound`]/[`ConstKind::Bound`]/[`RegionKind::Bound`] for references to parameters introduced via higher ranked bounds or higher ranked types i.e. `for<'a> fn(&'a u32)` or `for<'a> T: Trait<'a>`. This will be discussed in the [chapter on `Binder`s][ch_binders]. -- [`RegionKind::LateParam`] for late bound lifetime parameters, `LateParam` will be discussed in the [chapter on instantiating `Binder`s][ch_instantiating_binders]. +- [`TyKind::Bound`]/[`ConstKind::Bound`]/[`RegionKind::Bound`] for references to parameters introduced via higher ranked bounds or higher ranked types i.e. `for<'a> fn(&'a u32)` or `for<'a> T: Trait<'a>`. This is discussed in the [chapter on `Binder`s][ch_binders]. +- [`RegionKind::LateParam`] for late bound lifetime parameters, `LateParam` is discussed in the [chapter on instantiating `Binder`s][ch_instantiating_binders]. -This chapter will only cover `TyKind::Param` `ConstKind::Param` and `RegionKind::EarlyParam`. +This chapter only covers `TyKind::Param` `ConstKind::Param` and `RegionKind::EarlyParam`. ## Ty/Const Parameters -As `TyKind::Param` and `ConstKind::Param` are implemented identically this section will only refer to `TyKind::Param` for simplicity. However -you should keep in mind that everything here also is true of `ConstKind::Param` +As `TyKind::Param` and `ConstKind::Param` are implemented identically this section only refers to `TyKind::Param` for simplicity. +However you should keep in mind that everything here also is true of `ConstKind::Param` Each `TyKind::Param` contains two things: the name of the parameter and an index. @@ -83,7 +83,7 @@ fn foo<'a, 'b, T: 'a>(one: T, two: &'a &'b u32) -> &'b u32 { } ``` -`RegionKind::LateParam` will be discussed more in the chapter on [instantiating binders][ch_instantiating_binders]. +`RegionKind::LateParam` is discussed more in the chapter on [instantiating binders][ch_instantiating_binders]. [ch_early_late_bound]: ../early_late_parameters.md [ch_binders]: ./binders.md From a611f5016af427c63b9e13106a7ae0d2f50131ac Mon Sep 17 00:00:00 2001 From: Frank Steffahn Date: Tue, 20 May 2025 13:26:22 +0200 Subject: [PATCH 2503/4206] Fix misdirected link for `TypingEnv` --- src/doc/rustc-dev-guide/src/typing_parameter_envs.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/typing_parameter_envs.md b/src/doc/rustc-dev-guide/src/typing_parameter_envs.md index 67eaf51bf2985..a8f4059827f95 100644 --- a/src/doc/rustc-dev-guide/src/typing_parameter_envs.md +++ b/src/doc/rustc-dev-guide/src/typing_parameter_envs.md @@ -199,8 +199,8 @@ In the next-gen trait solver the requirement for all where clauses in the `Param Depending on what context we are performing type system operations in, different behaviour may be required. For example during coherence there are stronger requirements about when we can consider goals to not hold or when we can consider types to be unequal. -Tracking which "phase" of the compiler type system operations are being performed in is done by the [`TypingMode`][tenv] enum. The documentation on the `TypingMode` enum is quite good so instead of repeating it here verbatim we would recommend reading the API documentation directly. +Tracking which "phase" of the compiler type system operations are being performed in is done by the [`TypingMode`][tmode] enum. The documentation on the `TypingMode` enum is quite good so instead of repeating it here verbatim we would recommend reading the API documentation directly. [penv]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html -[tenv]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/infer_ctxt/enum.TypingMode.html +[tenv]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypingEnv.html [tmode]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.TypingMode.html From 6555ef7f09a5b23a8eea05cba499a5b9fd16909a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 20 May 2025 10:28:31 +0000 Subject: [PATCH 2504/4206] Querify coroutine_hidden_types --- compiler/rustc_middle/src/query/erase.rs | 7 +++- compiler/rustc_middle/src/query/mod.rs | 6 +++ compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_middle/src/ty/util.rs | 36 +----------------- .../src/solve/assembly/structural_traits.rs | 4 +- .../src/traits/select/mod.rs | 2 +- .../rustc_traits/src/coroutine_witnesses.rs | 37 +++++++++++++++++++ compiler/rustc_traits/src/lib.rs | 2 + compiler/rustc_type_ir/src/interner.rs | 2 +- compiler/rustc_type_ir/src/ty_kind.rs | 10 +++++ 10 files changed, 67 insertions(+), 41 deletions(-) create mode 100644 compiler/rustc_traits/src/coroutine_witnesses.rs diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 5bd111fa2f22d..2d248e028fe8b 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -6,7 +6,7 @@ use rustc_span::ErrorGuaranteed; use crate::query::CyclePlaceholder; use crate::ty::adjustment::CoerceUnsizedInfo; -use crate::ty::{self, Ty}; +use crate::ty::{self, Ty, TyCtxt}; use crate::{mir, traits}; #[derive(Copy, Clone)] @@ -207,6 +207,11 @@ impl EraseType for ty::Binder<'_, ty::FnSig<'_>> { type Result = [u8; size_of::>>()]; } +impl EraseType for ty::Binder<'_, ty::CoroutineWitnessTypes>> { + type Result = + [u8; size_of::>>>()]; +} + impl EraseType for ty::Binder<'_, &'_ ty::List>> { type Result = [u8; size_of::>>>()]; } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b2133fea08cc3..b6218fff0c417 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -922,6 +922,12 @@ rustc_queries! { separate_provide_extern } + query coroutine_hidden_types( + def_id: DefId + ) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, ty::CoroutineWitnessTypes>>> { + desc { "looking up the hidden types stored across await points in a coroutine" } + } + /// Gets a map with the variances of every item in the local crate. /// ///

diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0759fa3da428a..c205d53b93f1f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -340,7 +340,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn coroutine_hidden_types( self, def_id: DefId, - ) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, &'tcx ty::List>>> { + ) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, ty::CoroutineWitnessTypes>>> { self.coroutine_hidden_types(def_id) } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 9676aa4044823..ecf83926df7d2 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -26,7 +26,7 @@ use crate::query::Providers; use crate::ty::layout::{FloatExt, IntegerExt}; use crate::ty::{ self, Asyncness, FallibleTypeFolder, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeFoldable, - TypeFolder, TypeSuperFoldable, TypeVisitableExt, Upcast, fold_regions, + TypeFolder, TypeSuperFoldable, TypeVisitableExt, Upcast, }; #[derive(Copy, Clone, Debug)] @@ -737,40 +737,6 @@ impl<'tcx> TyCtxt<'tcx> { } } - /// Return the set of types that should be taken into account when checking - /// trait bounds on a coroutine's internal state. This properly replaces - /// `ReErased` with new existential bound lifetimes. - pub fn coroutine_hidden_types( - self, - def_id: DefId, - ) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, &'tcx ty::List>>> { - let coroutine_layout = self.mir_coroutine_witnesses(def_id); - let mut vars = vec![]; - let bound_tys = self.mk_type_list_from_iter( - coroutine_layout - .as_ref() - .map_or_else(|| [].iter(), |l| l.field_tys.iter()) - .filter(|decl| !decl.ignore_for_traits) - .map(|decl| { - let ty = fold_regions(self, decl.ty, |re, debruijn| { - assert_eq!(re, self.lifetimes.re_erased); - let var = ty::BoundVar::from_usize(vars.len()); - vars.push(ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon)); - ty::Region::new_bound( - self, - debruijn, - ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon }, - ) - }); - ty - }), - ); - ty::EarlyBinder::bind(ty::Binder::bind_with_vars( - bound_tys, - self.mk_bound_variable_kinds(&vars), - )) - } - /// Expands the given impl trait type, stopping if the type is recursive. #[instrument(skip(self), level = "debug", ret)] pub fn try_expand_impl_trait_type( diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 2a2b462a36cbd..9b89b9fad8626 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -83,7 +83,7 @@ where .cx() .coroutine_hidden_types(def_id) .instantiate(cx, args) - .map_bound(|tys| tys.to_vec())), + .map_bound(|bound| bound.types.to_vec())), ty::UnsafeBinder(bound_ty) => Ok(bound_ty.map_bound(|ty| vec![ty])), @@ -249,7 +249,7 @@ where .cx() .coroutine_hidden_types(def_id) .instantiate(ecx.cx(), args) - .map_bound(|tys| tys.to_vec())), + .map_bound(|bound| bound.types.to_vec())), } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 44a76f6e08327..549aed908f381 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2866,7 +2866,7 @@ fn rebind_coroutine_witness_types<'tcx>( let shifted_coroutine_types = tcx.shift_bound_var_indices(bound_vars.len(), bound_coroutine_types.skip_binder()); ty::Binder::bind_with_vars( - ty::EarlyBinder::bind(shifted_coroutine_types.to_vec()).instantiate(tcx, args), + ty::EarlyBinder::bind(shifted_coroutine_types.types.to_vec()).instantiate(tcx, args), tcx.mk_bound_variable_kinds_from_iter( bound_vars.iter().chain(bound_coroutine_types.bound_vars()), ), diff --git a/compiler/rustc_traits/src/coroutine_witnesses.rs b/compiler/rustc_traits/src/coroutine_witnesses.rs new file mode 100644 index 0000000000000..447e13126ccdc --- /dev/null +++ b/compiler/rustc_traits/src/coroutine_witnesses.rs @@ -0,0 +1,37 @@ +use rustc_hir::def_id::DefId; +use rustc_middle::ty::{self, TyCtxt, fold_regions}; + +/// Return the set of types that should be taken into account when checking +/// trait bounds on a coroutine's internal state. This properly replaces +/// `ReErased` with new existential bound lifetimes. +pub(crate) fn coroutine_hidden_types<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, ty::CoroutineWitnessTypes>>> { + let coroutine_layout = tcx.mir_coroutine_witnesses(def_id); + let mut vars = vec![]; + let bound_tys = tcx.mk_type_list_from_iter( + coroutine_layout + .as_ref() + .map_or_else(|| [].iter(), |l| l.field_tys.iter()) + .filter(|decl| !decl.ignore_for_traits) + .map(|decl| { + let ty = fold_regions(tcx, decl.ty, |re, debruijn| { + assert_eq!(re, tcx.lifetimes.re_erased); + let var = ty::BoundVar::from_usize(vars.len()); + vars.push(ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon)); + ty::Region::new_bound( + tcx, + debruijn, + ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon }, + ) + }); + ty + }), + ); + + ty::EarlyBinder::bind(ty::Binder::bind_with_vars( + ty::CoroutineWitnessTypes { types: bound_tys }, + tcx.mk_bound_variable_kinds(&vars), + )) +} diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index 697c839180312..32d8c3f58e08a 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -5,6 +5,7 @@ // tidy-alphabetical-end mod codegen; +mod coroutine_witnesses; mod dropck_outlives; mod evaluate_obligation; mod implied_outlives_bounds; @@ -24,4 +25,5 @@ pub fn provide(p: &mut Providers) { normalize_erasing_regions::provide(p); type_op::provide(p); p.codegen_select_candidate = codegen::codegen_select_candidate; + p.coroutine_hidden_types = coroutine_witnesses::coroutine_hidden_types; } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 0fd2d9f3ad38b..c10241cfcf0f6 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -210,7 +210,7 @@ pub trait Interner: fn coroutine_hidden_types( self, def_id: Self::DefId, - ) -> ty::EarlyBinder>; + ) -> ty::EarlyBinder>>; fn fn_sig( self, diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index cf2e4284d10da..0cd98b5aa53b4 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -1163,3 +1163,13 @@ pub struct FnHeader { pub safety: I::Safety, pub abi: I::Abi, } + +#[derive_where(Clone, Copy, Debug, PartialEq, Eq, Hash; I: Interner)] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +pub struct CoroutineWitnessTypes { + pub types: I::Tys, +} From b21c9e7bfb0180b67b486013a7137fb200cb1076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= <69964857+Sa4dUs@users.noreply.github.com> Date: Tue, 6 May 2025 09:19:33 +0200 Subject: [PATCH 2505/4206] Split `autodiff` into `autodiff_forward` and `autodiff_reverse` Pending fix. ``` error: cannot find a built-in macro with name `autodiff_forward` --> library\core\src\macros\mod.rs:1542:5 | 1542 | / pub macro autodiff_forward($item:item) { 1543 | | /* compiler built-in */ 1544 | | } | |_____^ error: cannot find a built-in macro with name `autodiff_reverse` --> library\core\src\macros\mod.rs:1549:5 | 1549 | / pub macro autodiff_reverse($item:item) { 1550 | | /* compiler built-in */ 1551 | | } | |_____^ error: could not compile `core` (lib) due to 2 previous errors ``` --- compiler/rustc_builtin_macros/src/autodiff.rs | 41 +++++++++++++------ compiler/rustc_builtin_macros/src/lib.rs | 3 +- compiler/rustc_passes/src/check_attr.rs | 2 +- compiler/rustc_span/src/symbol.rs | 3 +- library/core/src/lib.rs | 2 +- library/core/src/macros/mod.rs | 14 +++++++ 6 files changed, 48 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 1ff4fc6aaab22..8073de15925e6 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -88,25 +88,20 @@ mod llvm_enzyme { has_ret: bool, ) -> AutoDiffAttrs { let dcx = ecx.sess.dcx(); - let mode = name(&meta_item[1]); - let Ok(mode) = DiffMode::from_str(&mode) else { - dcx.emit_err(errors::AutoDiffInvalidMode { span: meta_item[1].span(), mode }); - return AutoDiffAttrs::error(); - }; // Now we check, whether the user wants autodiff in batch/vector mode, or scalar mode. // If he doesn't specify an integer (=width), we default to scalar mode, thus width=1. - let mut first_activity = 2; + let mut first_activity = 1; - let width = if let [_, _, x, ..] = &meta_item[..] + let width = if let [_, x, ..] = &meta_item[..] && let Some(x) = width(x) { - first_activity = 3; + first_activity = 2; match x.try_into() { Ok(x) => x, Err(_) => { dcx.emit_err(errors::AutoDiffInvalidWidth { - span: meta_item[2].span(), + span: meta_item[1].span(), width: x, }); return AutoDiffAttrs::error(); @@ -150,7 +145,7 @@ mod llvm_enzyme { }; AutoDiffAttrs { - mode, + mode: DiffMode::Error, width, ret_activity: *ret_activity, input_activity: input_activity.to_vec(), @@ -165,6 +160,24 @@ mod llvm_enzyme { ts.push(TokenTree::Token(comma.clone(), Spacing::Alone)); } + pub(crate) fn expand_forward( + ecx: &mut ExtCtxt<'_>, + expand_span: Span, + meta_item: &ast::MetaItem, + item: Annotatable, + ) -> Vec { + expand_with_mode(ecx, expand_span, meta_item, item, DiffMode::Forward) + } + + pub(crate) fn expand_reverse( + ecx: &mut ExtCtxt<'_>, + expand_span: Span, + meta_item: &ast::MetaItem, + item: Annotatable, + ) -> Vec { + expand_with_mode(ecx, expand_span, meta_item, item, DiffMode::Reverse) + } + /// We expand the autodiff macro to generate a new placeholder function which passes /// type-checking and can be called by users. The function body of the placeholder function will /// later be replaced on LLVM-IR level, so the design of the body is less important and for now @@ -198,11 +211,12 @@ mod llvm_enzyme { /// ``` /// FIXME(ZuseZ4): Once autodiff is enabled by default, make this a doc comment which is checked /// in CI. - pub(crate) fn expand( + pub(crate) fn expand_with_mode( ecx: &mut ExtCtxt<'_>, expand_span: Span, meta_item: &ast::MetaItem, mut item: Annotatable, + mode: DiffMode, ) -> Vec { if cfg!(not(llvm_enzyme)) { ecx.sess.dcx().emit_err(errors::AutoDiffSupportNotBuild { span: meta_item.span }); @@ -289,7 +303,8 @@ mod llvm_enzyme { ts.pop(); let ts: TokenStream = TokenStream::from_iter(ts); - let x: AutoDiffAttrs = from_ast(ecx, &meta_item_vec, has_ret); + let mut x: AutoDiffAttrs = from_ast(ecx, &meta_item_vec, has_ret); + x.mode = mode; if !x.is_active() { // We encountered an error, so we return the original item. // This allows us to potentially parse other attributes. @@ -1017,4 +1032,4 @@ mod llvm_enzyme { } } -pub(crate) use llvm_enzyme::expand; +pub(crate) use llvm_enzyme::{expand_forward, expand_reverse}; diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 9cd4d17059a0f..a89b3642f7e53 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -112,7 +112,8 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { register_attr! { alloc_error_handler: alloc_error_handler::expand, - autodiff: autodiff::expand, + autodiff_forward: autodiff::expand_forward, + autodiff_reverse: autodiff::expand_reverse, bench: test::expand_bench, cfg_accessible: cfg_accessible::Expander, cfg_eval: cfg_eval::expand, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 5c0d0cf47969a..5aff24f7aa0c1 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -255,7 +255,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_generic_attr(hir_id, attr, target, Target::Fn); self.check_proc_macro(hir_id, target, ProcMacroKind::Derive) } - [sym::autodiff, ..] => { + [sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => { self.check_autodiff(hir_id, attr, span, target) } [sym::coroutine, ..] => { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index efae6250b0720..bb19b5761bb19 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -531,7 +531,8 @@ symbols! { audit_that, augmented_assignments, auto_traits, - autodiff, + autodiff_forward, + autodiff_reverse, automatically_derived, avx, avx10_target_feature, diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index e605d7e0d7844..aaa8c872f985c 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -229,7 +229,7 @@ pub mod assert_matches { /// Unstable module containing the unstable `autodiff` macro. pub mod autodiff { #[unstable(feature = "autodiff", issue = "124509")] - pub use crate::macros::builtin::autodiff; + pub use crate::macros::builtin::{autodiff_forward, autodiff_reverse}; } #[unstable(feature = "contracts", issue = "128044")] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 7dc8c060cd5bc..dc50ad6a09076 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1536,6 +1536,20 @@ pub(crate) mod builtin { /* compiler built-in */ } + #[unstable(feature = "autodiff", issue = "124509")] + #[allow_internal_unstable(rustc_attrs)] + #[rustc_builtin_macro] + pub macro autodiff_forward($item:item) { + /* compiler built-in */ + } + + #[unstable(feature = "autodiff", issue = "124509")] + #[allow_internal_unstable(rustc_attrs)] + #[rustc_builtin_macro] + pub macro autodiff_reverse($item:item) { + /* compiler built-in */ + } + /// Asserts that a boolean expression is `true` at runtime. /// /// This will invoke the [`panic!`] macro if the provided expression cannot be From 81af658cb317a8325b4be9fb89d10cd6d6e4d79e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 20 May 2025 12:16:04 +0000 Subject: [PATCH 2506/4206] Make clif ir debug output a bit nicer --- src/abi/mod.rs | 18 +++++------ src/base.rs | 4 +-- src/pretty_clif.rs | 73 +++++++++++++++++++++++++++++++----------- src/value_and_place.rs | 2 +- 4 files changed, 66 insertions(+), 31 deletions(-) diff --git a/src/abi/mod.rs b/src/abi/mod.rs index 57ac2d18d494d..7324856bce4a7 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -185,12 +185,11 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { let sig = Signature { params, returns, call_conv: self.target_config.default_call_conv }; let func_id = self.module.declare_function(name, Linkage::Import, &sig).unwrap(); let func_ref = self.module.declare_func_in_func(func_id, &mut self.bcx.func); + let call_inst = self.bcx.ins().call(func_ref, args); if self.clif_comments.enabled() { self.add_comment(func_ref, format!("{:?}", name)); - let inst = self.bcx.func.layout.last_inst(self.bcx.current_block().unwrap()).unwrap(); - self.add_comment(inst, format!("lib_call {}", name)); + self.add_comment(call_inst, format!("lib_call {}", name)); } - let call_inst = self.bcx.ins().call(func_ref, args); let results = self.bcx.inst_results(call_inst); assert!(results.len() <= 2, "{}", results.len()); results @@ -530,7 +529,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( Some(Instance { def: InstanceKind::Virtual(_, idx), .. }) => { if fx.clif_comments.enabled() { let nop_inst = fx.bcx.ins().nop(); - fx.add_comment( + fx.add_post_comment( nop_inst, with_no_trimmed_paths!(format!( "virtual call; self arg pass mode: {:?}", @@ -556,7 +555,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( None => { if fx.clif_comments.enabled() { let nop_inst = fx.bcx.ins().nop(); - fx.add_comment(nop_inst, "indirect call"); + fx.add_post_comment(nop_inst, "indirect call"); } let func = func.load_scalar(fx); @@ -586,11 +585,6 @@ pub(crate) fn codegen_terminator_call<'tcx>( adjust_call_for_c_variadic(fx, &fn_abi, source_info, func_ref, &mut call_args); } - if fx.clif_comments.enabled() { - let nop_inst = fx.bcx.ins().nop(); - with_no_trimmed_paths!(fx.add_comment(nop_inst, format!("abi: {:?}", fn_abi))); - } - let call_inst = match func_ref { CallTarget::Direct(func_ref) => fx.bcx.ins().call(func_ref, &call_args), CallTarget::Indirect(sig, func_ptr) => { @@ -598,6 +592,10 @@ pub(crate) fn codegen_terminator_call<'tcx>( } }; + if fx.clif_comments.enabled() { + with_no_trimmed_paths!(fx.add_comment(call_inst, format!("abi: {:?}", fn_abi))); + } + fx.bcx.func.dfg.inst_results(call_inst).iter().copied().collect::>() }); diff --git a/src/base.rs b/src/base.rs index f46535966f1c8..c3255327f3400 100644 --- a/src/base.rs +++ b/src/base.rs @@ -315,7 +315,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { bb_data.terminator().kind.fmt_head(&mut terminator_head).unwrap(); }); let inst = fx.bcx.func.layout.last_inst(block).unwrap(); - fx.add_comment(inst, terminator_head); + fx.add_post_comment(inst, terminator_head); } let source_info = bb_data.terminator().source_info; @@ -570,7 +570,7 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: if fx.clif_comments.enabled() { let inst = fx.bcx.func.layout.last_inst(cur_block).unwrap(); with_no_trimmed_paths!({ - fx.add_comment(inst, format!("{:?}", stmt)); + fx.add_post_comment(inst, format!("{:?}", stmt)); }); } } diff --git a/src/pretty_clif.rs b/src/pretty_clif.rs index cd254b04ed9e1..9400ae9fcff0f 100644 --- a/src/pretty_clif.rs +++ b/src/pretty_clif.rs @@ -8,40 +8,41 @@ //! target x86_64 //! //! function u0:22(i64) -> i8, i8 system_v { -//! ; symbol _ZN97_$LT$example..IsNotEmpty$u20$as$u20$mini_core..FnOnce$LT$$LP$$RF$$RF$$u5b$u16$u5d$$C$$RP$$GT$$GT$9call_once17hd517c453d67c0915E -//! ; instance Instance { def: Item(WithOptConstParam { did: DefId(0:42 ~ example[4e51]::{impl#0}::call_once), const_param_did: None }), args: [ReErased, ReErased] } -//! ; abi FnAbi { args: [ArgAbi { layout: TyAndLayout { ty: IsNotEmpty, layout: Layout { size: Size(0 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, abi: Aggregate { sized: true }, fields: Arbitrary { offsets: [], memory_index: [] }, largest_niche: None, variants: Single { index: 0 } } }, mode: Ignore }, ArgAbi { layout: TyAndLayout { ty: &&[u16], layout: Layout { size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), fields: Primitive, largest_niche: Some(Niche { offset: Size(0 bytes), value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), variants: Single { index: 0 } } }, mode: Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(8 bytes)) }) }], ret: ArgAbi { layout: TyAndLayout { ty: (u8, u8), layout: Layout { size: Size(2 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, abi: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=255 }, Initialized { value: Int(I8, false), valid_range: 0..=255 }), fields: Arbitrary { offsets: [Size(0 bytes), Size(1 bytes)], memory_index: [0, 1] }, largest_niche: None, variants: Single { index: 0 } } }, mode: Pair(ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }, ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }) }, c_variadic: false, fixed_count: 1, conv: Rust, can_unwind: false } +//! ; symbol _ZN97_$LT$example..IsNotEmpty$u20$as$u20$mini_core..FnOnce$LT$$LP$$RF$$RF$$u5b$u16$u5d$$C$$RP$$GT$$GT$9call_once17hd361e9f5c3d1c4deE +//! ; instance Instance { def: Item(DefId(0:42 ~ example[3895]::{impl#0}::call_once)), args: ['{erased}, '{erased}] } +//! ; abi FnAbi { args: [ArgAbi { layout: TyAndLayout { ty: IsNotEmpty, layout: Layout { size: Size(0 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, backend_repr: Memory { sized: true }, fields: Arbitrary { offsets: [], memory_index: [] }, largest_niche: None, uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), randomization_seed: 12266848898570219025 } }, mode: Ignore }, ArgAbi { layout: TyAndLayout { ty: &&[u16], layout: Layout { size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, backend_repr: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), fields: Primitive, largest_niche: Some(Niche { offset: Size(0 bytes), value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), randomization_seed: 281492156579847 } }, mode: Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(8 bytes)) }) }], ret: ArgAbi { layout: TyAndLayout { ty: (u8, u8), layout: Layout { size: Size(2 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, backend_repr: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=255 }, Initialized { value: Int(I8, false), valid_range: 0..=255 }), fields: Arbitrary { offsets: [Size(0 bytes), Size(1 bytes)], memory_index: [0, 1] }, largest_niche: None, uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), randomization_seed: 71776127651151873 } }, mode: Pair(ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }, ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }) }, c_variadic: false, fixed_count: 1, conv: Rust, can_unwind: false } //! //! ; kind loc.idx param pass mode ty -//! ; ssa _0 (u8, u8) 2b 1, 8 var=(0, 1) +//! ; ssa _0 (u8, u8) 2b 1 var=(0, 1) //! ; ret _0 - Pair(ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }, ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }) (u8, u8) //! ; arg _1 - Ignore IsNotEmpty -//! ; arg _2.0 = v0 Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(8 bytes)) }) &&[u16] +//! ; arg _2.0 = v0 Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(8 bytes)) }) &'{erased} &'{erased} [u16] //! -//! ; kind local ty size align (abi,pref) -//! ; zst _1 IsNotEmpty 0b 1, 8 align=8,offset= -//! ; stack _2 (&&[u16],) 8b 8, 8 storage=ss0 -//! ; ssa _3 &mut IsNotEmpty 8b 8, 8 var=2 +//! ; kind local ty size align (abi) +//! ; zst _1 IsNotEmpty 0b 1 align=1,offset= +//! ; stack _2 (&'{erased} &'{erased} [u16],) 8b 8 storage=ss0 +//! ; ssa _3 &'{erased} mut IsNotEmpty 8b 8 var=2 //! -//! ss0 = explicit_slot 16 +//! ss0 = explicit_slot 16, align = 16 //! sig0 = (i64, i64) -> i8, i8 system_v -//! fn0 = colocated u0:23 sig0 ; Instance { def: Item(WithOptConstParam { did: DefId(0:46 ~ example[4e51]::{impl#1}::call_mut), const_param_did: None }), args: [ReErased, ReErased] } +//! fn0 = colocated u0:23 sig0 ; Instance { def: Item(DefId(0:46 ~ example[3895]::{impl#1}::call_mut)), args: ['{erased}, '{erased}] } //! //! block0(v0: i64): //! nop -//! ; write_cvalue: Addr(Pointer { base: Stack(ss0), offset: Offset32(0) }, None): &&[u16] <- ByVal(v0): &&[u16] +//! ; write_cvalue: Addr(Pointer { base: Stack(ss0), offset: Offset32(0) }, None): &'{erased} &'{erased} [u16] <- ByVal(v0): &'{erased} &'{erased} [u16] //! stack_store v0, ss0 //! jump block1 //! //! block1: //! nop //! ; _3 = &mut _1 -//! v1 = iconst.i64 8 -//! ; write_cvalue: Var(_3, var2): &mut IsNotEmpty <- ByVal(v1): &mut IsNotEmpty +//! v1 = iconst.i64 1 +//! ; write_cvalue: Var(_3, var2): &'{erased} mut IsNotEmpty <- ByVal(v1): &'{erased} mut IsNotEmpty //! ; -//! ; _0 = >::call_mut(move _3, _2) +//! ; _0 = >::call_mut(move _3, copy _2) //! v2 = stack_load.i64 ss0 -//! v3, v4 = call fn0(v1, v2) ; v1 = 8 +//! ; abi: FnAbi { args: [ArgAbi { layout: TyAndLayout { ty: &mut IsNotEmpty, layout: Layout { size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, backend_repr: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), fields: Primitive, largest_niche: Some(Niche { offset: Size(0 bytes), value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), randomization_seed: 281492156579847 } }, mode: Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(1 bytes)) }) }, ArgAbi { layout: TyAndLayout { ty: &&[u16], layout: Layout { size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, backend_repr: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), fields: Primitive, largest_niche: Some(Niche { offset: Size(0 bytes), value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), randomization_seed: 281492156579847 } }, mode: Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(8 bytes)) }) }], ret: ArgAbi { layout: TyAndLayout { ty: (u8, u8), layout: Layout { size: Size(2 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, backend_repr: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=255 }, Initialized { value: Int(I8, false), valid_range: 0..=255 }), fields: Arbitrary { offsets: [Size(0 bytes), Size(1 bytes)], memory_index: [0, 1] }, largest_niche: None, uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), randomization_seed: 71776127651151873 } }, mode: Pair(ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }, ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }) }, c_variadic: false, fixed_count: 1, conv: Rust, can_unwind: false } +//! v3, v4 = call fn0(v1, v2) ; v1 = 1 //! v5 -> v3 //! v6 -> v4 //! ; write_cvalue: VarPair(_0, var0, var1): (u8, u8) <- ByValPair(v3, v4): (u8, u8) @@ -73,6 +74,7 @@ pub(crate) struct CommentWriter { enabled: bool, global_comments: Vec, entity_comments: FxHashMap, + inst_post_comments: FxHashMap, } impl CommentWriter { @@ -95,7 +97,12 @@ impl CommentWriter { vec![] }; - CommentWriter { enabled, global_comments, entity_comments: FxHashMap::default() } + CommentWriter { + enabled, + global_comments, + entity_comments: FxHashMap::default(), + inst_post_comments: FxHashMap::default(), + } } } @@ -127,6 +134,25 @@ impl CommentWriter { } } } + + pub(crate) fn add_post_comment + AsRef>( + &mut self, + entity: Inst, + comment: S, + ) { + debug_assert!(self.enabled); + + use std::collections::hash_map::Entry; + match self.inst_post_comments.entry(entity) { + Entry::Occupied(mut occ) => { + occ.get_mut().push('\n'); + occ.get_mut().push_str(comment.as_ref()); + } + Entry::Vacant(vac) => { + vac.insert(comment.into()); + } + } + } } impl FuncWriter for &'_ CommentWriter { @@ -188,10 +214,13 @@ impl FuncWriter for &'_ CommentWriter { inst: Inst, indent: usize, ) -> fmt::Result { - PlainWriter.write_instruction(w, func, aliases, inst, indent)?; if let Some(comment) = self.entity_comments.get(&inst.into()) { writeln!(w, "; {}", comment.replace('\n', "\n; "))?; } + PlainWriter.write_instruction(w, func, aliases, inst, indent)?; + if let Some(comment) = self.inst_post_comments.get(&inst) { + writeln!(w, "; {}", comment.replace('\n', "\n; "))?; + } Ok(()) } } @@ -208,6 +237,14 @@ impl FunctionCx<'_, '_, '_> { ) { self.clif_comments.add_comment(entity, comment); } + + pub(crate) fn add_post_comment + AsRef>( + &mut self, + entity: Inst, + comment: S, + ) { + self.clif_comments.add_post_comment(entity, comment); + } } pub(crate) fn should_write_ir(tcx: TyCtxt<'_>) -> bool { diff --git a/src/value_and_place.rs b/src/value_and_place.rs index 1168701f10323..5ec970b493b5b 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -593,7 +593,7 @@ impl<'tcx> CPlace<'tcx> { if fx.clif_comments.enabled() { let inst = fx.bcx.func.layout.last_inst(fx.bcx.current_block().unwrap()).unwrap(); - fx.add_comment( + fx.add_post_comment( inst, format!( "{}: {:?}: {:?} <- {:?}: {:?}", From 4c39287e34fea2a8a3b330a6cf2c3afab21d4951 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 5 May 2025 15:07:38 +0000 Subject: [PATCH 2507/4206] Update to Cranelift 0.120 --- Cargo.lock | 72 +++++++++++++++++++------------------- Cargo.toml | 24 ++++++------- src/base.rs | 4 +-- src/intrinsics/llvm_x86.rs | 4 +-- src/intrinsics/simd.rs | 8 ++--- 5 files changed, 56 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 066d5a61adde6..a906bec8b7e23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,42 +43,42 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-assembler-x64" -version = "0.119.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "263cc79b8a23c29720eb596d251698f604546b48c34d0d84f8fd2761e5bf8888" +checksum = "9ff8e35182c7372df00447cb90a04e584e032c42b9b9b6e8c50ddaaf0d7900d5" dependencies = [ "cranelift-assembler-x64-meta", ] [[package]] name = "cranelift-assembler-x64-meta" -version = "0.119.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b4a113455f8c0e13e3b3222a9c38d6940b958ff22573108be083495c72820e1" +checksum = "14220f9c2698015c3b94dc6b84ae045c1c45509ddc406e43c6139252757fdb7a" dependencies = [ "cranelift-srcgen", ] [[package]] name = "cranelift-bforest" -version = "0.119.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f96dca41c5acf5d4312c1d04b3391e21a312f8d64ce31a2723a3bb8edd5d4d" +checksum = "d372ef2777ceefd75829e1390211ac240e9196bc60699218f7ea2419038288ee" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.119.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d821ed698dd83d9c012447eb63a5406c1e9c23732a2f674fb5b5015afd42202" +checksum = "56323783e423818fa89ce8078e90a3913d2a6e0810399bfce8ebd7ee87baa81f" [[package]] name = "cranelift-codegen" -version = "0.119.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06c52fdec4322cb8d5545a648047819aaeaa04e630f88d3a609c0d3c1a00e9a0" +checksum = "74ffb780aab6186c6e9ba26519654b1ac55a09c0a866f6088a4efbbd84da68ed" dependencies = [ "bumpalo", "cranelift-assembler-x64", @@ -101,9 +101,9 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.119.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af2c215e0c9afa8069aafb71d22aa0e0dde1048d9a5c3c72a83cacf9b61fcf4a" +checksum = "c23ef13814d3b39c869650d5961128cbbecad83fbdff4e6836a03ecf6862d7ed" dependencies = [ "cranelift-assembler-x64-meta", "cranelift-codegen-shared", @@ -112,33 +112,33 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.119.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97524b2446fc26a78142132d813679dda19f620048ebc9a9fbb0ac9f2d320dcb" +checksum = "b9f623300657679f847803ce80811454bfff89cea4f6bf684be5c468d4a73631" [[package]] name = "cranelift-control" -version = "0.119.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e32e900aee81f9e3cc493405ef667a7812cb5c79b5fc6b669e0a2795bda4b22" +checksum = "31f4168af69989aa6b91fab46799ed4df6096f3209f4a6c8fb4358f49c60188f" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.119.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16a2e28e0fa6b9108d76879d60fe1cc95ba90e1bcf52bac96496371044484ee" +checksum = "ca6fa9bae1c8de26d71ac2162f069447610fd91e7780cb480ee0d76ac81eabb8" dependencies = [ "cranelift-bitset", ] [[package]] name = "cranelift-frontend" -version = "0.119.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "328181a9083d99762d85954a16065d2560394a862b8dc10239f39668df528b95" +checksum = "b8219205608aa0b0e6769b580284a7e055c7e0c323c1041cde7ca078add3e412" dependencies = [ "cranelift-codegen", "log", @@ -148,15 +148,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.119.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e916f36f183e377e9a3ed71769f2721df88b72648831e95bb9fa6b0cd9b1c709" +checksum = "588d0c5964f10860b04043e55aab26d7f7a206b0fd4f10c5260e8aa5773832bd" [[package]] name = "cranelift-jit" -version = "0.119.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bb584ac927f1076d552504b0075b833b9d61e2e9178ba55df6b2d966b4375d" +checksum = "56bd917ddc524f84f4066f954062875bdfc0dffea068ee94e906d98de5ac7c33" dependencies = [ "anyhow", "cranelift-codegen", @@ -174,9 +174,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.119.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40c18ccb8e4861cf49cec79998af73b772a2b47212d12d3d63bf57cc4293a1e3" +checksum = "68a03c057d8a992e06596c871341e446af43ff9224f941e5b8adea39137a5391" dependencies = [ "anyhow", "cranelift-codegen", @@ -185,9 +185,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.119.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc852cf04128877047dc2027aa1b85c64f681dc3a6a37ff45dcbfa26e4d52d2f" +checksum = "19ed3c94cb97b14f92b6a94a1d45ef8c851f6a2ad9114e5d91d233f7da638fed" dependencies = [ "cranelift-codegen", "libc", @@ -196,9 +196,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.119.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f6ad789197bda49f7c98280ee8d7ccd63a5a1cc67283f87798a2d61e089ce4" +checksum = "a64dacef362a69375a604f6636e5e9a174fb96dba3b273646fcd9fa85c1d0997" dependencies = [ "anyhow", "cranelift-codegen", @@ -211,9 +211,9 @@ dependencies = [ [[package]] name = "cranelift-srcgen" -version = "0.119.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47e1a86340a16e74b4285cc86ac69458fa1c8e7aaff313da4a89d10efd3535ee" +checksum = "85256fac1519a7d25a040c1d850fba67478f3f021ad5fdf738ba4425ee862dbf" [[package]] name = "crc32fast" @@ -341,9 +341,9 @@ dependencies = [ [[package]] name = "regalloc2" -version = "0.11.3" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d4c3c15aa088eccea44550bffea9e9a5d0b14a264635323d23c6e6351acca98" +checksum = "5216b1837de2149f8bc8e6d5f88a9326b63b8c836ed58ce4a0a29ec736a59734" dependencies = [ "allocator-api2", "bumpalo", @@ -446,9 +446,9 @@ checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "wasmtime-jit-icache-coherence" -version = "32.0.0" +version = "33.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb399eaabd7594f695e1159d236bf40ef55babcb3af97f97c027864ed2104db6" +checksum = "175e924dbc944c185808466d1e90b5a7feb610f3b9abdfe26f8ee25fd1086d1c" dependencies = [ "anyhow", "cfg-if", diff --git a/Cargo.toml b/Cargo.toml index 82fde4b838e13..94fcbd0a5023d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,12 +8,12 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.119.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } -cranelift-frontend = { version = "0.119.0" } -cranelift-module = { version = "0.119.0" } -cranelift-native = { version = "0.119.0" } -cranelift-jit = { version = "0.119.0", optional = true } -cranelift-object = { version = "0.119.0" } +cranelift-codegen = { version = "0.120.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } +cranelift-frontend = { version = "0.120.0" } +cranelift-module = { version = "0.120.0" } +cranelift-native = { version = "0.120.0" } +cranelift-jit = { version = "0.120.0", optional = true } +cranelift-object = { version = "0.120.0" } target-lexicon = "0.13" gimli = { version = "0.31", default-features = false, features = ["write"] } object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } @@ -24,12 +24,12 @@ smallvec = "1.8.1" [patch.crates-io] # Uncomment to use an unreleased version of cranelift -#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-32.0.0", version = "0.119.0" } -#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-32.0.0", version = "0.119.0" } -#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-32.0.0", version = "0.119.0" } -#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-32.0.0", version = "0.119.0" } -#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-32.0.0", version = "0.119.0" } -#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-32.0.0", version = "0.119.0" } +#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" } +#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" } +#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" } +#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" } +#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" } +#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" } # Uncomment to use local checkout of cranelift #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" } diff --git a/src/base.rs b/src/base.rs index c3255327f3400..c1f4c065ce03f 100644 --- a/src/base.rs +++ b/src/base.rs @@ -806,7 +806,7 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: let done_block = fx.bcx.create_block(); let index = fx.bcx.append_block_param(loop_block, fx.pointer_type); let zero = fx.bcx.ins().iconst(fx.pointer_type, 0); - fx.bcx.ins().jump(loop_block, &[zero]); + fx.bcx.ins().jump(loop_block, &[zero.into()]); fx.bcx.switch_to_block(loop_block); let done = fx.bcx.ins().icmp_imm(IntCC::Equal, index, times as i64); @@ -816,7 +816,7 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: let to = lval.place_index(fx, index); to.write_cvalue(fx, operand); let index = fx.bcx.ins().iadd_imm(index, 1); - fx.bcx.ins().jump(loop_block, &[index]); + fx.bcx.ins().jump(loop_block, &[index.into()]); fx.bcx.switch_to_block(done_block); fx.bcx.ins().nop(); diff --git a/src/intrinsics/llvm_x86.rs b/src/intrinsics/llvm_x86.rs index e145eda606855..3d67913a8fff1 100644 --- a/src/intrinsics/llvm_x86.rs +++ b/src/intrinsics/llvm_x86.rs @@ -147,10 +147,10 @@ pub(super) fn codegen_x86_llvm_intrinsic_call<'tcx>( let offset = fx.bcx.ins().imul(index_lane, scale); let lane_ptr = fx.bcx.ins().iadd(ptr, offset); let res = fx.bcx.ins().load(lane_clif_ty, MemFlags::trusted(), lane_ptr, 0); - fx.bcx.ins().jump(next, &[res]); + fx.bcx.ins().jump(next, &[res.into()]); fx.bcx.switch_to_block(if_disabled); - fx.bcx.ins().jump(next, &[src_lane]); + fx.bcx.ins().jump(next, &[src_lane.into()]); fx.bcx.seal_block(next); fx.bcx.switch_to_block(next); diff --git a/src/intrinsics/simd.rs b/src/intrinsics/simd.rs index 7a041469bccdd..46a441488fa6a 100644 --- a/src/intrinsics/simd.rs +++ b/src/intrinsics/simd.rs @@ -1008,10 +1008,10 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( fx.bcx.switch_to_block(if_enabled); let res = fx.bcx.ins().load(lane_clif_ty, MemFlags::trusted(), ptr_lane, 0); - fx.bcx.ins().jump(next, &[res]); + fx.bcx.ins().jump(next, &[res.into()]); fx.bcx.switch_to_block(if_disabled); - fx.bcx.ins().jump(next, &[val_lane]); + fx.bcx.ins().jump(next, &[val_lane.into()]); fx.bcx.seal_block(next); fx.bcx.switch_to_block(next); @@ -1057,10 +1057,10 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( ptr_val, Offset32::new(offset), ); - fx.bcx.ins().jump(next, &[res]); + fx.bcx.ins().jump(next, &[res.into()]); fx.bcx.switch_to_block(if_disabled); - fx.bcx.ins().jump(next, &[val_lane]); + fx.bcx.ins().jump(next, &[val_lane.into()]); fx.bcx.seal_block(next); fx.bcx.switch_to_block(next); From a8173fcd1f44baf1ef2f582983f17898317ff81b Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Tue, 20 May 2025 15:16:29 +0200 Subject: [PATCH 2508/4206] ci: split powerpc64le-linux job --- .../dist-powerpc64le-linux-gnu/Dockerfile | 41 +++++++++++++++++++ .../powerpc64le-unknown-linux-gnu.defconfig | 14 +++++++ .../Dockerfile | 9 ++-- .../powerpc64le-unknown-linux-musl.defconfig | 0 .../build-powerpc64le-toolchain.sh | 0 src/ci/github-actions/jobs.yml | 12 +++--- 6 files changed, 63 insertions(+), 13 deletions(-) create mode 100644 src/ci/docker/host-x86_64/dist-powerpc64le-linux-gnu/Dockerfile create mode 100644 src/ci/docker/host-x86_64/dist-powerpc64le-linux-gnu/powerpc64le-unknown-linux-gnu.defconfig rename src/ci/docker/host-x86_64/{dist-powerpc64le-linux => dist-powerpc64le-linux-musl}/Dockerfile (71%) rename src/ci/docker/host-x86_64/{dist-powerpc64le-linux => dist-powerpc64le-linux-musl}/powerpc64le-unknown-linux-musl.defconfig (100%) rename src/ci/docker/{host-x86_64/dist-powerpc64le-linux => scripts}/build-powerpc64le-toolchain.sh (100%) diff --git a/src/ci/docker/host-x86_64/dist-powerpc64le-linux-gnu/Dockerfile b/src/ci/docker/host-x86_64/dist-powerpc64le-linux-gnu/Dockerfile new file mode 100644 index 0000000000000..d2f1b9400ad84 --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-powerpc64le-linux-gnu/Dockerfile @@ -0,0 +1,41 @@ +FROM ubuntu:22.04 + +COPY scripts/cross-apt-packages.sh /scripts/ +RUN sh /scripts/cross-apt-packages.sh + +COPY scripts/crosstool-ng.sh /scripts/ +RUN sh /scripts/crosstool-ng.sh + +COPY scripts/rustbuild-setup.sh /scripts/ +RUN sh /scripts/rustbuild-setup.sh + +WORKDIR /tmp + +COPY scripts/crosstool-ng-build.sh /scripts/ +COPY host-x86_64/dist-powerpc64le-linux-gnu/powerpc64le-unknown-linux-gnu.defconfig /tmp/crosstool.defconfig +RUN /scripts/crosstool-ng-build.sh + +WORKDIR /build + +RUN apt-get install -y --no-install-recommends rpm2cpio cpio +COPY scripts/shared.sh scripts/build-powerpc64le-toolchain.sh /build/ +RUN ./build-powerpc64le-toolchain.sh + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +ENV \ + AR_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-ar \ + CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \ + CXX_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-g++ + +ENV HOSTS=powerpc64le-unknown-linux-gnu + +ENV RUST_CONFIGURE_ARGS \ + --enable-extended \ + --enable-full-tools \ + --enable-profiler \ + --enable-sanitizers \ + --disable-docs + +ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/host-x86_64/dist-powerpc64le-linux-gnu/powerpc64le-unknown-linux-gnu.defconfig b/src/ci/docker/host-x86_64/dist-powerpc64le-linux-gnu/powerpc64le-unknown-linux-gnu.defconfig new file mode 100644 index 0000000000000..363e5850894e3 --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-powerpc64le-linux-gnu/powerpc64le-unknown-linux-gnu.defconfig @@ -0,0 +1,14 @@ +CT_CONFIG_VERSION="4" +CT_EXPERIMENTAL=y +CT_PREFIX_DIR="/x-tools/${CT_TARGET}" +CT_USE_MIRROR=y +CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc" +CT_ARCH_POWERPC=y +CT_ARCH_LE=y +CT_ARCH_64=y +# CT_DEMULTILIB is not set +CT_ARCH_ARCH="powerpc64le" +CT_KERNEL_LINUX=y +CT_LINUX_V_4_19=y +CT_CC_LANG_CXX=y +CT_GETTEXT_NEEDED=y diff --git a/src/ci/docker/host-x86_64/dist-powerpc64le-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-powerpc64le-linux-musl/Dockerfile similarity index 71% rename from src/ci/docker/host-x86_64/dist-powerpc64le-linux/Dockerfile rename to src/ci/docker/host-x86_64/dist-powerpc64le-linux-musl/Dockerfile index cb20f43cff706..f045b2a5f6558 100644 --- a/src/ci/docker/host-x86_64/dist-powerpc64le-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-powerpc64le-linux-musl/Dockerfile @@ -12,13 +12,13 @@ RUN sh /scripts/rustbuild-setup.sh WORKDIR /tmp COPY scripts/crosstool-ng-build.sh /scripts/ -COPY host-x86_64/dist-powerpc64le-linux/powerpc64le-unknown-linux-musl.defconfig /tmp/crosstool.defconfig +COPY host-x86_64/dist-powerpc64le-linux-musl/powerpc64le-unknown-linux-musl.defconfig /tmp/crosstool.defconfig RUN /scripts/crosstool-ng-build.sh WORKDIR /build RUN apt-get install -y --no-install-recommends rpm2cpio cpio -COPY scripts/shared.sh host-x86_64/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh /build/ +COPY scripts/shared.sh scripts/build-powerpc64le-toolchain.sh /build/ RUN ./build-powerpc64le-toolchain.sh COPY scripts/sccache.sh /scripts/ @@ -27,14 +27,11 @@ RUN sh /scripts/sccache.sh ENV PATH=$PATH:/x-tools/powerpc64le-unknown-linux-musl/bin ENV \ - AR_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-ar \ - CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \ - CXX_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-g++ \ AR_powerpc64le_unknown_linux_musl=powerpc64le-unknown-linux-musl-ar \ CC_powerpc64le_unknown_linux_musl=powerpc64le-unknown-linux-musl-gcc \ CXX_powerpc64le_unknown_linux_musl=powerpc64le-unknown-linux-musl-g++ -ENV HOSTS=powerpc64le-unknown-linux-gnu,powerpc64le-unknown-linux-musl +ENV HOSTS=powerpc64le-unknown-linux-musl ENV RUST_CONFIGURE_ARGS \ --enable-extended \ diff --git a/src/ci/docker/host-x86_64/dist-powerpc64le-linux/powerpc64le-unknown-linux-musl.defconfig b/src/ci/docker/host-x86_64/dist-powerpc64le-linux-musl/powerpc64le-unknown-linux-musl.defconfig similarity index 100% rename from src/ci/docker/host-x86_64/dist-powerpc64le-linux/powerpc64le-unknown-linux-musl.defconfig rename to src/ci/docker/host-x86_64/dist-powerpc64le-linux-musl/powerpc64le-unknown-linux-musl.defconfig diff --git a/src/ci/docker/host-x86_64/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh b/src/ci/docker/scripts/build-powerpc64le-toolchain.sh similarity index 100% rename from src/ci/docker/host-x86_64/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh rename to src/ci/docker/scripts/build-powerpc64le-toolchain.sh diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 42ad5acbdac1e..93d4345ffd052 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -10,11 +10,6 @@ runners: free_disk: true <<: *base-job - # Large runner used mainly for its bigger disk capacity - - &job-linux-4c-largedisk - os: ubuntu-24.04-4core-16gb - <<: *base-job - - &job-linux-8c os: ubuntu-24.04-8core-32gb <<: *base-job @@ -203,8 +198,11 @@ auto: - name: dist-powerpc64-linux <<: *job-linux-4c - - name: dist-powerpc64le-linux - <<: *job-linux-4c-largedisk + - name: dist-powerpc64le-linux-gnu + <<: *job-linux-4c + + - name: dist-powerpc64le-linux-musl + <<: *job-linux-4c - name: dist-riscv64-linux <<: *job-linux-4c From 29d97cdabe21aa4a243b368555a47a33ad0cee8b Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Tue, 20 May 2025 13:17:13 +0000 Subject: [PATCH 2509/4206] Make some fns return `fmt::Result` to get rid of a few `unwrap`s --- src/librustdoc/html/render/context.rs | 2 +- src/librustdoc/html/render/mod.rs | 33 ++++++++++++++------------- src/librustdoc/html/render/sidebar.rs | 10 ++++++-- src/librustdoc/html/sources.rs | 15 ++++++------ 4 files changed, 33 insertions(+), 27 deletions(-) diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index f22935df96c87..ba95c1bf9e335 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -251,7 +251,7 @@ impl<'tcx> Context<'tcx> { &self.shared.layout, &page, BufDisplay(|buf: &mut String| { - print_sidebar(self, it, buf); + print_sidebar(self, it, buf).unwrap(); }), content, &self.shared.style_files, diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 3492df9995593..6abc3b82e4a52 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -661,7 +661,7 @@ fn document_full_inner( }; if let clean::ItemKind::FunctionItem(..) | clean::ItemKind::MethodItem(..) = kind { - render_call_locations(f, cx, item); + render_call_locations(f, cx, item)?; } Ok(()) }) @@ -2584,11 +2584,15 @@ const MAX_FULL_EXAMPLES: usize = 5; const NUM_VISIBLE_LINES: usize = 10; /// Generates the HTML for example call locations generated via the --scrape-examples flag. -fn render_call_locations(mut w: W, cx: &Context<'_>, item: &clean::Item) { +fn render_call_locations( + mut w: W, + cx: &Context<'_>, + item: &clean::Item, +) -> fmt::Result { let tcx = cx.tcx(); let def_id = item.item_id.expect_def_id(); let key = tcx.def_path_hash(def_id); - let Some(call_locations) = cx.shared.call_locations.get(&key) else { return }; + let Some(call_locations) = cx.shared.call_locations.get(&key) else { return Ok(()) }; // Generate a unique ID so users can link to this section for a given method let id = cx.derive_id("scraped-examples"); @@ -2602,8 +2606,7 @@ fn render_call_locations(mut w: W, cx: &Context<'_>, item: &clean ", root_path = cx.root_path(), id = id - ) - .unwrap(); + )?; // Create a URL to a particular location in a reverse-dependency's source file let link_to_loc = |call_data: &CallData, loc: &CallLocation| -> (String, String) { @@ -2705,7 +2708,8 @@ fn render_call_locations(mut w: W, cx: &Context<'_>, item: &clean title: init_title, locations: locations_encoded, }), - ); + ) + .unwrap(); true }; @@ -2761,8 +2765,7 @@ fn render_call_locations(mut w: W, cx: &Context<'_>, item: &clean
Hide additional examples
\
\
" - ) - .unwrap(); + )?; // Only generate inline code for MAX_FULL_EXAMPLES number of examples. Otherwise we could // make the page arbitrarily huge! @@ -2774,9 +2777,8 @@ fn render_call_locations(mut w: W, cx: &Context<'_>, item: &clean if it.peek().is_some() { w.write_str( r#"").unwrap(); + })?; + w.write_str("
")?; } - w.write_str("
").unwrap(); + w.write_str("
")?; } - w.write_str("").unwrap(); + w.write_str("") } diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index cd0c9775f5c97..a9029972d9630 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -1,5 +1,6 @@ use std::borrow::Cow; use std::cmp::Ordering; +use std::fmt; use askama::Template; use rustc_data_structures::fx::FxHashSet; @@ -135,7 +136,11 @@ pub(crate) mod filters { } } -pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut String) { +pub(super) fn print_sidebar( + cx: &Context<'_>, + it: &clean::Item, + mut buffer: impl fmt::Write, +) -> fmt::Result { let mut ids = IdMap::new(); let mut blocks: Vec> = docblock_toc(cx, it, &mut ids).into_iter().collect(); let deref_id_map = cx.deref_id_map.borrow(); @@ -195,7 +200,8 @@ pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Str blocks, path, }; - sidebar.render_into(buffer).unwrap(); + sidebar.render_into(&mut buffer)?; + Ok(()) } fn get_struct_fields_name<'a>(fields: &'a [clean::Item]) -> Vec> { diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 095795c711d9c..6044d1c281934 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -252,7 +252,8 @@ impl SourceCollector<'_, '_> { &root_path, &highlight::DecorationInfo::default(), &source_context, - ); + ) + .unwrap(); }), &shared.style_files, ); @@ -331,7 +332,7 @@ pub(crate) fn print_src( root_path: &str, decoration_info: &highlight::DecorationInfo, source_context: &SourceContext<'_>, -) { +) -> fmt::Result { let mut lines = s.lines().count(); let line_info = if let SourceContext::Embedded(info) = source_context { highlight::LineInfo::new_scraped(lines as u32, info.offset as u32) @@ -367,12 +368,10 @@ pub(crate) fn print_src( }, max_nb_digits, } - .render_into(&mut writer) - .unwrap(), + .render_into(&mut writer), SourceContext::Embedded(info) => { - ScrapedSource { info, code_html: code, max_nb_digits } - .render_into(&mut writer) - .unwrap(); + ScrapedSource { info, code_html: code, max_nb_digits }.render_into(&mut writer) } - }; + }?; + Ok(()) } From 7a68021dfce68f4e3a5edde8d93dee34dda68aa4 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Tue, 20 May 2025 13:19:39 +0000 Subject: [PATCH 2510/4206] Replace some `unwrap`s with `?`s where possible --- src/librustdoc/html/render/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 6abc3b82e4a52..06cb9269cc87f 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -538,7 +538,7 @@ fn document( } fmt::from_fn(move |f| { - document_item_info(cx, item, parent).render_into(f).unwrap(); + document_item_info(cx, item, parent).render_into(f)?; if parent.is_none() { write!(f, "{}", document_full_collapsible(item, cx, heading_offset)) } else { @@ -582,7 +582,7 @@ fn document_short( show_def_docs: bool, ) -> impl fmt::Display { fmt::from_fn(move |f| { - document_item_info(cx, item, Some(parent)).render_into(f).unwrap(); + document_item_info(cx, item, Some(parent)).render_into(f)?; if !show_def_docs { return Ok(()); } From 8682dfc7a382c1eec5e8ba1bad26665acf376418 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Tue, 20 May 2025 13:20:29 +0000 Subject: [PATCH 2511/4206] Get rid of unnecessary `BufDisplay` abstraction --- src/librustdoc/html/layout.rs | 19 +------------------ src/librustdoc/html/render/context.rs | 7 ++----- src/librustdoc/html/sources.rs | 8 +++----- 3 files changed, 6 insertions(+), 28 deletions(-) diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 44b3be23914c2..3b5f9b5a45897 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -1,4 +1,4 @@ -use std::fmt::{self, Display}; +use std::fmt::Display; use std::path::PathBuf; use askama::Template; @@ -71,23 +71,6 @@ struct PageLayout<'a> { pub(crate) use crate::html::render::sidebar::filters; -/// Implements [`Display`] for a function that accepts a mutable reference to a [`String`], and (optionally) writes to it. -/// -/// The wrapped function will receive an empty string, and can modify it, -/// and the `Display` implementation will write the contents of the string after the function has finished. -pub(crate) struct BufDisplay(pub F); - -impl Display for BufDisplay -where - F: Fn(&mut String), -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut buf = String::new(); - self.0(&mut buf); - f.write_str(&buf) - } -} - pub(crate) fn render( layout: &Layout, page: &Page<'_>, diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index ba95c1bf9e335..1f7201b8ca8b2 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -28,11 +28,10 @@ use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; use crate::html::escape::Escape; use crate::html::format::join_with_double_colon; -use crate::html::layout::{self, BufDisplay}; use crate::html::markdown::{self, ErrorCodes, IdMap, plain_text_summary}; use crate::html::render::write_shared::write_shared; use crate::html::url_parts_builder::UrlPartsBuilder; -use crate::html::{sources, static_files}; +use crate::html::{layout, sources, static_files}; use crate::scrape_examples::AllCallLocations; use crate::{DOC_RUST_LANG_ORG_VERSION, try_err}; @@ -250,9 +249,7 @@ impl<'tcx> Context<'tcx> { layout::render( &self.shared.layout, &page, - BufDisplay(|buf: &mut String| { - print_sidebar(self, it, buf).unwrap(); - }), + fmt::from_fn(|f| print_sidebar(self, it, f)), content, &self.shared.style_files, ) diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 6044d1c281934..1fa6b5a60f3a7 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -11,9 +11,8 @@ use rustc_session::Session; use rustc_span::{FileName, FileNameDisplayPreference, RealFileName, sym}; use tracing::info; -use super::highlight; -use super::layout::{self, BufDisplay}; use super::render::Context; +use super::{highlight, layout}; use crate::clean; use crate::clean::utils::has_doc_flag; use crate::docfs::PathError; @@ -243,9 +242,9 @@ impl SourceCollector<'_, '_> { &shared.layout, &page, "", - BufDisplay(|buf: &mut String| { + fmt::from_fn(|f| { print_src( - buf, + f, contents, file_span, self.cx, @@ -253,7 +252,6 @@ impl SourceCollector<'_, '_> { &highlight::DecorationInfo::default(), &source_context, ) - .unwrap(); }), &shared.style_files, ); From 50211e008e07e9d22e74e5f5f9dd0f574dfe70f2 Mon Sep 17 00:00:00 2001 From: Stan Manilov Date: Tue, 20 May 2025 16:25:11 +0300 Subject: [PATCH 2512/4206] Make it clear we talk about early bound params --- src/doc/rustc-dev-guide/src/early_late_parameters.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/early_late_parameters.md b/src/doc/rustc-dev-guide/src/early_late_parameters.md index 3b2a5e8a155b6..3f94b09056684 100644 --- a/src/doc/rustc-dev-guide/src/early_late_parameters.md +++ b/src/doc/rustc-dev-guide/src/early_late_parameters.md @@ -174,7 +174,8 @@ As mentioned previously, the distinction between early and late bound parameters - When naming a function (early) - When calling a function (late) -There currently is no syntax for explicitly specifying generic arguments for late bound parameters as part of the call step, only specifying generic arguments when naming a function. The syntax `foo::<'static>();`, despite being part of a function call, behaves as `(foo::<'static>)();` and instantiates the early bound generic parameters on the function item type. +There is currently no syntax for explicitly specifying generic arguments for late bound parameters during the call step; generic arguments can only be specified for early bound parameters when naming a function. +The syntax `foo::<'static>();`, despite being part of a function call, behaves as `(foo::<'static>)();` and instantiates the early bound generic parameters on the function item type. See the following example: ```rust From 7b5ea0e7f5bece3ddde9a5891c853322cfc6c0f8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 20 May 2025 16:03:04 +0200 Subject: [PATCH 2513/4206] use Self alias in self types rather than manually substituting it --- library/alloc/src/str.rs | 4 ++-- library/core/src/pin.rs | 2 +- library/std/src/ffi/os_str.rs | 2 +- library/std/src/path.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 24c5d4c92f71f..8766fd904b074 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -234,7 +234,7 @@ impl str { #[stable(feature = "str_box_extras", since = "1.20.0")] #[must_use = "`self` will be dropped if the result is not used"] #[inline] - pub fn into_boxed_bytes(self: Box) -> Box<[u8]> { + pub fn into_boxed_bytes(self: Box) -> Box<[u8]> { self.into() } @@ -501,7 +501,7 @@ impl str { #[rustc_allow_incoherent_impl] #[must_use = "`self` will be dropped if the result is not used"] #[inline] - pub fn into_string(self: Box) -> String { + pub fn into_string(self: Box) -> String { let slice = Box::<[u8]>::from(self); unsafe { String::from_utf8_unchecked(slice.into_vec()) } } diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index dd1c2f2c28513..066d90c4e49a7 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1422,7 +1422,7 @@ impl Pin { #[stable(feature = "pin_deref_mut", since = "1.84.0")] #[must_use = "`self` will be dropped if the result is not used"] #[inline(always)] - pub fn as_deref_mut(self: Pin<&mut Pin>) -> Pin<&mut Ptr::Target> { + pub fn as_deref_mut(self: Pin<&mut Self>) -> Pin<&mut Ptr::Target> { // SAFETY: What we're asserting here is that going from // // Pin<&mut Pin> diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 72bdf03ee61a4..ead4877512727 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -1040,7 +1040,7 @@ impl OsStr { /// Converts a [Box]<[OsStr]> into an [`OsString`] without copying or allocating. #[stable(feature = "into_boxed_os_str", since = "1.20.0")] #[must_use = "`self` will be dropped if the result is not used"] - pub fn into_os_string(self: Box) -> OsString { + pub fn into_os_string(self: Box) -> OsString { let boxed = unsafe { Box::from_raw(Box::into_raw(self) as *mut Slice) }; OsString { inner: Buf::from_box(boxed) } } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 1a4a7aa7448cb..7959c63385816 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -3163,7 +3163,7 @@ impl Path { /// allocating. #[stable(feature = "into_boxed_path", since = "1.20.0")] #[must_use = "`self` will be dropped if the result is not used"] - pub fn into_path_buf(self: Box) -> PathBuf { + pub fn into_path_buf(self: Box) -> PathBuf { let rw = Box::into_raw(self) as *mut OsStr; let inner = unsafe { Box::from_raw(rw) }; PathBuf { inner: OsString::from(inner) } From b68ebd04a5f8193dd47630f3286588be3b93d2c7 Mon Sep 17 00:00:00 2001 From: Dan Johnson Date: Tue, 20 May 2025 07:40:52 -0700 Subject: [PATCH 2514/4206] link tracking issue in explicit-extern-abis.md --- .../src/language-features/explicit-extern-abis.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/doc/unstable-book/src/language-features/explicit-extern-abis.md b/src/doc/unstable-book/src/language-features/explicit-extern-abis.md index ba622466ba74a..7728f6725b1df 100644 --- a/src/doc/unstable-book/src/language-features/explicit-extern-abis.md +++ b/src/doc/unstable-book/src/language-features/explicit-extern-abis.md @@ -1,6 +1,6 @@ # `explicit_extern_abis` -The tracking issue for this feature is: #134986 +The tracking issue for this feature is: [#134986] ------ @@ -21,3 +21,5 @@ extern "C" fn function2() {} // compiles extern "aapcs" fn function3() {} // compiles ``` + +[#134986]: https://github.com/rust-lang/rust/issues/134986 From 8e3d0b2b031ee49596e4ae6da3845928909baca8 Mon Sep 17 00:00:00 2001 From: stefnotch Date: Tue, 20 May 2025 17:17:36 +0200 Subject: [PATCH 2515/4206] Update availability of Cranelift (#1579) - include source --- Readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index 28edb5795ce3c..4d1e4d843ffeb 100644 --- a/Readme.md +++ b/Readme.md @@ -7,7 +7,7 @@ If not please open an issue. ## Download using Rustup -The Cranelift codegen backend is distributed in nightly builds on Linux and x86_64 macOS. If you want to +The Cranelift codegen backend is distributed in nightly builds on Linux, macOS and x86_64 Windows. If you want to install it using Rustup, you can do that by running: ```bash @@ -79,7 +79,7 @@ For more docs on how to build and test see [build_system/usage.txt](build_system Not all targets are available as rustup component for nightly. See notes in the platform support matrix. [^xcoff]: XCOFF object file format is not supported. -[^no-rustup]: Not available as rustup component for nightly. You can build it yourself. +[^no-rustup]: Not available as [rustup component for nightly](https://rust-lang.github.io/rustup-components-history/). You can build it yourself. ## Usage From c506046ba2330d100d84f7beac0674f2ac4b5299 Mon Sep 17 00:00:00 2001 From: binarycat Date: Tue, 20 May 2025 10:22:13 -0500 Subject: [PATCH 2516/4206] triagebot: ping me if rustdoc js is modified --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index 9dcdbcecbeca6..c4e534817213f 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -887,6 +887,7 @@ message = "Some changes occurred in HTML/CSS/JS." cc = [ "@GuillaumeGomez", "@jsha", + "@lolbinarycat", ] [mentions."tests/rustdoc-gui/"] From 28db348fdd8a22352826e31d793ae916a8a60385 Mon Sep 17 00:00:00 2001 From: Stypox Date: Tue, 13 May 2025 17:06:23 +0200 Subject: [PATCH 2517/4206] Add enter_trace_span!() that checks if tracing is enabled --- .../rustc_const_eval/src/interpret/util.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index ba579e25f036a..847905e834310 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -45,3 +45,22 @@ pub(crate) fn create_static_alloc<'tcx>( assert!(ecx.memory.alloc_map.insert(alloc_id, (MemoryKind::Stack, alloc)).is_none()); interp_ok(ecx.ptr_to_mplace(Pointer::from(alloc_id).into(), layout)) } + +/// This struct is needed to enforce `#[must_use]` on [tracing::span::EnteredSpan] +/// while wrapping them in an `Option`. +#[must_use] +pub enum MaybeEnteredSpan { + Some(tracing::span::EnteredSpan), + None, +} + +#[macro_export] +macro_rules! enter_trace_span { + ($machine:ident, $($tt:tt)*) => { + if $machine::TRACING_ENABLED { + $crate::interpret::tracing_utils::MaybeEnteredSpan::Some(tracing::info_span!($($tt)*).entered()) + } else { + $crate::interpret::tracing_utils::MaybeEnteredSpan::None + } + } +} From f6709bb6834818193efce3315f107744982d2d43 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Tue, 20 May 2025 10:08:15 +0100 Subject: [PATCH 2518/4206] `core_float_math`: Move functions to `math` folder When these functions were added in https://github.com/rust-lang/rust/pull/138087 It made a relatively common pattern for emulating these functions using an extension trait (which internally uses `libm`) much more fragile. If `core::f32` happened to be imported by the user (to access a constant, say), then that import in the module namespace would take precedence over `f32` in the type namespace for resolving these functions, running headfirst into the stability attribute. We ran into this in Color - https://github.com/linebender/color - and chose to release the remedial 0.3.1 and 0.2.4, to allow downstream crates to build on `docs.rs`. As these methods are perma-unstable, moving them into a new module should not have any long-term concerns, and ensures that this breakage doesn't adversely impact anyone else. --- library/core/src/num/f32.rs | 806 +++++++++++++------------- library/core/src/num/f64.rs | 794 +++++++++++++------------ library/coretests/tests/floats/f32.rs | 142 ++--- library/coretests/tests/floats/f64.rs | 129 +++-- library/std/src/f32.rs | 26 +- library/std/src/f64.rs | 26 +- 6 files changed, 990 insertions(+), 933 deletions(-) diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 9525bdb6762a2..43bf414d6be32 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -12,7 +12,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::convert::FloatToInt; -use crate::num::{FpCategory, libm}; +use crate::num::FpCategory; use crate::panic::const_assert; use crate::{cfg_match, intrinsics, mem}; @@ -1557,413 +1557,441 @@ impl f32 { } } -/// Experimental version of `floor` in `core`. See [`f32::floor`] for details. +/// Experimental implementations of floating point functions in `core`. /// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// use core::f32; -/// -/// let f = 3.7_f32; -/// let g = 3.0_f32; -/// let h = -3.7_f32; -/// -/// assert_eq!(f32::floor(f), 3.0); -/// assert_eq!(f32::floor(g), 3.0); -/// assert_eq!(f32::floor(h), -4.0); -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f32::floor`]: ../../std/primitive.f32.html#method.floor -#[inline] +/// _The standalone functions in this module are for testing only. +/// They will be stabilized as inherent methods._ #[unstable(feature = "core_float_math", issue = "137578")] -#[must_use = "method returns a new number and does not mutate the original value"] -pub fn floor(x: f32) -> f32 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::floorf32(x) } -} +pub mod math { + use crate::intrinsics; + use crate::num::libm; -/// Experimental version of `ceil` in `core`. See [`f32::ceil`] for details. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// use core::f32; -/// -/// let f = 3.01_f32; -/// let g = 4.0_f32; -/// -/// assert_eq!(f32::ceil(f), 4.0); -/// assert_eq!(f32::ceil(g), 4.0); -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f32::ceil`]: ../../std/primitive.f32.html#method.ceil -#[inline] -#[doc(alias = "ceiling")] -#[must_use = "method returns a new number and does not mutate the original value"] -#[unstable(feature = "core_float_math", issue = "137578")] -pub fn ceil(x: f32) -> f32 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::ceilf32(x) } -} + /// Experimental version of `floor` in `core`. See [`f32::floor`] for details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// use core::f32; + /// + /// let f = 3.7_f32; + /// let g = 3.0_f32; + /// let h = -3.7_f32; + /// + /// assert_eq!(f32::math::floor(f), 3.0); + /// assert_eq!(f32::math::floor(g), 3.0); + /// assert_eq!(f32::math::floor(h), -4.0); + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f32::floor`]: ../../../std/primitive.f32.html#method.floor + #[inline] + #[unstable(feature = "core_float_math", issue = "137578")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn floor(x: f32) -> f32 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::floorf32(x) } + } -/// Experimental version of `round` in `core`. See [`f32::round`] for details. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// use core::f32; -/// -/// let f = 3.3_f32; -/// let g = -3.3_f32; -/// let h = -3.7_f32; -/// let i = 3.5_f32; -/// let j = 4.5_f32; -/// -/// assert_eq!(f32::round(f), 3.0); -/// assert_eq!(f32::round(g), -3.0); -/// assert_eq!(f32::round(h), -4.0); -/// assert_eq!(f32::round(i), 4.0); -/// assert_eq!(f32::round(j), 5.0); -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f32::round`]: ../../std/primitive.f32.html#method.round -#[inline] -#[unstable(feature = "core_float_math", issue = "137578")] -#[must_use = "method returns a new number and does not mutate the original value"] -pub fn round(x: f32) -> f32 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::roundf32(x) } -} + /// Experimental version of `ceil` in `core`. See [`f32::ceil`] for details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// use core::f32; + /// + /// let f = 3.01_f32; + /// let g = 4.0_f32; + /// + /// assert_eq!(f32::math::ceil(f), 4.0); + /// assert_eq!(f32::math::ceil(g), 4.0); + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f32::ceil`]: ../../../std/primitive.f32.html#method.ceil + #[inline] + #[doc(alias = "ceiling")] + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "core_float_math", issue = "137578")] + pub fn ceil(x: f32) -> f32 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::ceilf32(x) } + } -/// Experimental version of `round_ties_even` in `core`. See [`f32::round_ties_even`] for details. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// use core::f32; -/// -/// let f = 3.3_f32; -/// let g = -3.3_f32; -/// let h = 3.5_f32; -/// let i = 4.5_f32; -/// -/// assert_eq!(f32::round_ties_even(f), 3.0); -/// assert_eq!(f32::round_ties_even(g), -3.0); -/// assert_eq!(f32::round_ties_even(h), 4.0); -/// assert_eq!(f32::round_ties_even(i), 4.0); -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f32::round_ties_even`]: ../../std/primitive.f32.html#method.round_ties_even -#[inline] -#[unstable(feature = "core_float_math", issue = "137578")] -#[must_use = "method returns a new number and does not mutate the original value"] -pub fn round_ties_even(x: f32) -> f32 { - intrinsics::round_ties_even_f32(x) -} + /// Experimental version of `round` in `core`. See [`f32::round`] for details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// use core::f32; + /// + /// let f = 3.3_f32; + /// let g = -3.3_f32; + /// let h = -3.7_f32; + /// let i = 3.5_f32; + /// let j = 4.5_f32; + /// + /// assert_eq!(f32::math::round(f), 3.0); + /// assert_eq!(f32::math::round(g), -3.0); + /// assert_eq!(f32::math::round(h), -4.0); + /// assert_eq!(f32::math::round(i), 4.0); + /// assert_eq!(f32::math::round(j), 5.0); + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f32::round`]: ../../../std/primitive.f32.html#method.round + #[inline] + #[unstable(feature = "core_float_math", issue = "137578")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn round(x: f32) -> f32 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::roundf32(x) } + } -/// Experimental version of `trunc` in `core`. See [`f32::trunc`] for details. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// use core::f32; -/// -/// let f = 3.7_f32; -/// let g = 3.0_f32; -/// let h = -3.7_f32; -/// -/// assert_eq!(f32::trunc(f), 3.0); -/// assert_eq!(f32::trunc(g), 3.0); -/// assert_eq!(f32::trunc(h), -3.0); -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f32::trunc`]: ../../std/primitive.f32.html#method.trunc -#[inline] -#[doc(alias = "truncate")] -#[must_use = "method returns a new number and does not mutate the original value"] -#[unstable(feature = "core_float_math", issue = "137578")] -pub fn trunc(x: f32) -> f32 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::truncf32(x) } -} + /// Experimental version of `round_ties_even` in `core`. See [`f32::round_ties_even`] for + /// details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// use core::f32; + /// + /// let f = 3.3_f32; + /// let g = -3.3_f32; + /// let h = 3.5_f32; + /// let i = 4.5_f32; + /// + /// assert_eq!(f32::math::round_ties_even(f), 3.0); + /// assert_eq!(f32::math::round_ties_even(g), -3.0); + /// assert_eq!(f32::math::round_ties_even(h), 4.0); + /// assert_eq!(f32::math::round_ties_even(i), 4.0); + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f32::round_ties_even`]: ../../../std/primitive.f32.html#method.round_ties_even + #[inline] + #[unstable(feature = "core_float_math", issue = "137578")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn round_ties_even(x: f32) -> f32 { + intrinsics::round_ties_even_f32(x) + } -/// Experimental version of `fract` in `core`. See [`f32::fract`] for details. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// use core::f32; -/// -/// let x = 3.6_f32; -/// let y = -3.6_f32; -/// let abs_difference_x = (f32::fract(x) - 0.6).abs(); -/// let abs_difference_y = (f32::fract(y) - (-0.6)).abs(); -/// -/// assert!(abs_difference_x <= f32::EPSILON); -/// assert!(abs_difference_y <= f32::EPSILON); -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f32::fract`]: ../../std/primitive.f32.html#method.fract -#[inline] -#[unstable(feature = "core_float_math", issue = "137578")] -#[must_use = "method returns a new number and does not mutate the original value"] -pub fn fract(x: f32) -> f32 { - x - trunc(x) -} + /// Experimental version of `trunc` in `core`. See [`f32::trunc`] for details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// use core::f32; + /// + /// let f = 3.7_f32; + /// let g = 3.0_f32; + /// let h = -3.7_f32; + /// + /// assert_eq!(f32::math::trunc(f), 3.0); + /// assert_eq!(f32::math::trunc(g), 3.0); + /// assert_eq!(f32::math::trunc(h), -3.0); + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f32::trunc`]: ../../../std/primitive.f32.html#method.trunc + #[inline] + #[doc(alias = "truncate")] + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "core_float_math", issue = "137578")] + pub fn trunc(x: f32) -> f32 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::truncf32(x) } + } -/// Experimental version of `mul_add` in `core`. See [`f32::mul_add`] for details. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// # // FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/ -/// # #[cfg(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")))] { -/// use core::f32; -/// -/// let m = 10.0_f32; -/// let x = 4.0_f32; -/// let b = 60.0_f32; -/// -/// assert_eq!(f32::mul_add(m, x, b), 100.0); -/// assert_eq!(m * x + b, 100.0); -/// -/// let one_plus_eps = 1.0_f32 + f32::EPSILON; -/// let one_minus_eps = 1.0_f32 - f32::EPSILON; -/// let minus_one = -1.0_f32; -/// -/// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps. -/// assert_eq!(f32::mul_add(one_plus_eps, one_minus_eps, minus_one), -f32::EPSILON * f32::EPSILON); -/// // Different rounding with the non-fused multiply and add. -/// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0); -/// # } -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f32::mul_add`]: ../../std/primitive.f32.html#method.mul_add -#[inline] -#[doc(alias = "fmaf", alias = "fusedMultiplyAdd")] -#[must_use = "method returns a new number and does not mutate the original value"] -#[unstable(feature = "core_float_math", issue = "137578")] -pub fn mul_add(x: f32, y: f32, z: f32) -> f32 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::fmaf32(x, y, z) } -} + /// Experimental version of `fract` in `core`. See [`f32::fract`] for details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// use core::f32; + /// + /// let x = 3.6_f32; + /// let y = -3.6_f32; + /// let abs_difference_x = (f32::math::fract(x) - 0.6).abs(); + /// let abs_difference_y = (f32::math::fract(y) - (-0.6)).abs(); + /// + /// assert!(abs_difference_x <= f32::EPSILON); + /// assert!(abs_difference_y <= f32::EPSILON); + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f32::fract`]: ../../../std/primitive.f32.html#method.fract + #[inline] + #[unstable(feature = "core_float_math", issue = "137578")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn fract(x: f32) -> f32 { + x - trunc(x) + } -/// Experimental version of `div_euclid` in `core`. See [`f32::div_euclid`] for details. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// use core::f32; -/// -/// let a: f32 = 7.0; -/// let b = 4.0; -/// assert_eq!(f32::div_euclid(a, b), 1.0); // 7.0 > 4.0 * 1.0 -/// assert_eq!(f32::div_euclid(-a, b), -2.0); // -7.0 >= 4.0 * -2.0 -/// assert_eq!(f32::div_euclid(a, -b), -1.0); // 7.0 >= -4.0 * -1.0 -/// assert_eq!(f32::div_euclid(-a, -b), 2.0); // -7.0 >= -4.0 * 2.0 -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f32::div_euclid`]: ../../std/primitive.f32.html#method.div_euclid -#[inline] -#[unstable(feature = "core_float_math", issue = "137578")] -#[must_use = "method returns a new number and does not mutate the original value"] -pub fn div_euclid(x: f32, rhs: f32) -> f32 { - let q = trunc(x / rhs); - if x % rhs < 0.0 { - return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; + /// Experimental version of `mul_add` in `core`. See [`f32::mul_add`] for details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// # // FIXME(#140515): mingw has an incorrect fma + /// # // https://sourceforge.net/p/mingw-w64/bugs/848/ + /// # #[cfg(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")))] { + /// use core::f32; + /// + /// let m = 10.0_f32; + /// let x = 4.0_f32; + /// let b = 60.0_f32; + /// + /// assert_eq!(f32::math::mul_add(m, x, b), 100.0); + /// assert_eq!(m * x + b, 100.0); + /// + /// let one_plus_eps = 1.0_f32 + f32::EPSILON; + /// let one_minus_eps = 1.0_f32 - f32::EPSILON; + /// let minus_one = -1.0_f32; + /// + /// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps. + /// assert_eq!( + /// f32::math::mul_add(one_plus_eps, one_minus_eps, minus_one), + /// -f32::EPSILON * f32::EPSILON + /// ); + /// // Different rounding with the non-fused multiply and add. + /// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0); + /// # } + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f32::mul_add`]: ../../../std/primitive.f32.html#method.mul_add + #[inline] + #[doc(alias = "fmaf", alias = "fusedMultiplyAdd")] + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "core_float_math", issue = "137578")] + pub fn mul_add(x: f32, y: f32, z: f32) -> f32 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::fmaf32(x, y, z) } } - q -} -/// Experimental version of `rem_euclid` in `core`. See [`f32::rem_euclid`] for details. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// use core::f32; -/// -/// let a: f32 = 7.0; -/// let b = 4.0; -/// assert_eq!(f32::rem_euclid(a, b), 3.0); -/// assert_eq!(f32::rem_euclid(-a, b), 1.0); -/// assert_eq!(f32::rem_euclid(a, -b), 3.0); -/// assert_eq!(f32::rem_euclid(-a, -b), 1.0); -/// // limitation due to round-off error -/// assert!(f32::rem_euclid(-f32::EPSILON, 3.0) != 0.0); -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f32::rem_euclid`]: ../../std/primitive.f32.html#method.rem_euclid -#[inline] -#[doc(alias = "modulo", alias = "mod")] -#[unstable(feature = "core_float_math", issue = "137578")] -#[must_use = "method returns a new number and does not mutate the original value"] -pub fn rem_euclid(x: f32, rhs: f32) -> f32 { - let r = x % rhs; - if r < 0.0 { r + rhs.abs() } else { r } -} + /// Experimental version of `div_euclid` in `core`. See [`f32::div_euclid`] for details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// use core::f32; + /// + /// let a: f32 = 7.0; + /// let b = 4.0; + /// assert_eq!(f32::math::div_euclid(a, b), 1.0); // 7.0 > 4.0 * 1.0 + /// assert_eq!(f32::math::div_euclid(-a, b), -2.0); // -7.0 >= 4.0 * -2.0 + /// assert_eq!(f32::math::div_euclid(a, -b), -1.0); // 7.0 >= -4.0 * -1.0 + /// assert_eq!(f32::math::div_euclid(-a, -b), 2.0); // -7.0 >= -4.0 * 2.0 + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f32::div_euclid`]: ../../../std/primitive.f32.html#method.div_euclid + #[inline] + #[unstable(feature = "core_float_math", issue = "137578")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn div_euclid(x: f32, rhs: f32) -> f32 { + let q = trunc(x / rhs); + if x % rhs < 0.0 { + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; + } + q + } -/// Experimental version of `powi` in `core`. See [`f32::powi`] for details. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// use core::f32; -/// -/// let x = 2.0_f32; -/// let abs_difference = (f32::powi(x, 2) - (x * x)).abs(); -/// assert!(abs_difference <= f32::EPSILON); -/// -/// assert_eq!(f32::powi(f32::NAN, 0), 1.0); -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f32::powi`]: ../../std/primitive.f32.html#method.powi -#[inline] -#[must_use = "method returns a new number and does not mutate the original value"] -#[unstable(feature = "core_float_math", issue = "137578")] -pub fn powi(x: f32, n: i32) -> f32 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::powif32(x, n) } -} + /// Experimental version of `rem_euclid` in `core`. See [`f32::rem_euclid`] for details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// use core::f32; + /// + /// let a: f32 = 7.0; + /// let b = 4.0; + /// assert_eq!(f32::math::rem_euclid(a, b), 3.0); + /// assert_eq!(f32::math::rem_euclid(-a, b), 1.0); + /// assert_eq!(f32::math::rem_euclid(a, -b), 3.0); + /// assert_eq!(f32::math::rem_euclid(-a, -b), 1.0); + /// // limitation due to round-off error + /// assert!(f32::math::rem_euclid(-f32::EPSILON, 3.0) != 0.0); + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f32::rem_euclid`]: ../../../std/primitive.f32.html#method.rem_euclid + #[inline] + #[doc(alias = "modulo", alias = "mod")] + #[unstable(feature = "core_float_math", issue = "137578")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn rem_euclid(x: f32, rhs: f32) -> f32 { + let r = x % rhs; + if r < 0.0 { r + rhs.abs() } else { r } + } -/// Experimental version of `sqrt` in `core`. See [`f32::sqrt`] for details. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// use core::f32; -/// -/// let positive = 4.0_f32; -/// let negative = -4.0_f32; -/// let negative_zero = -0.0_f32; -/// -/// assert_eq!(f32::sqrt(positive), 2.0); -/// assert!(f32::sqrt(negative).is_nan()); -/// assert_eq!(f32::sqrt(negative_zero), negative_zero); -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f32::sqrt`]: ../../std/primitive.f32.html#method.sqrt -#[inline] -#[doc(alias = "squareRoot")] -#[unstable(feature = "core_float_math", issue = "137578")] -#[must_use = "method returns a new number and does not mutate the original value"] -pub fn sqrt(x: f32) -> f32 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::sqrtf32(x) } -} + /// Experimental version of `powi` in `core`. See [`f32::powi`] for details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// use core::f32; + /// + /// let x = 2.0_f32; + /// let abs_difference = (f32::math::powi(x, 2) - (x * x)).abs(); + /// assert!(abs_difference <= f32::EPSILON); + /// + /// assert_eq!(f32::math::powi(f32::NAN, 0), 1.0); + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f32::powi`]: ../../../std/primitive.f32.html#method.powi + #[inline] + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "core_float_math", issue = "137578")] + pub fn powi(x: f32, n: i32) -> f32 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::powif32(x, n) } + } -/// Experimental version of `abs_sub` in `core`. See [`f32::abs_sub`] for details. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// use core::f32; -/// -/// let x = 3.0f32; -/// let y = -3.0f32; -/// -/// let abs_difference_x = (f32::abs_sub(x, 1.0) - 2.0).abs(); -/// let abs_difference_y = (f32::abs_sub(y, 1.0) - 0.0).abs(); -/// -/// assert!(abs_difference_x <= f32::EPSILON); -/// assert!(abs_difference_y <= f32::EPSILON); -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f32::abs_sub`]: ../../std/primitive.f32.html#method.abs_sub -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -#[deprecated( - since = "1.10.0", - note = "you probably meant `(self - other).abs()`: \ + /// Experimental version of `sqrt` in `core`. See [`f32::sqrt`] for details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// use core::f32; + /// + /// let positive = 4.0_f32; + /// let negative = -4.0_f32; + /// let negative_zero = -0.0_f32; + /// + /// assert_eq!(f32::math::sqrt(positive), 2.0); + /// assert!(f32::math::sqrt(negative).is_nan()); + /// assert_eq!(f32::math::sqrt(negative_zero), negative_zero); + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f32::sqrt`]: ../../../std/primitive.f32.html#method.sqrt + #[inline] + #[doc(alias = "squareRoot")] + #[unstable(feature = "core_float_math", issue = "137578")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn sqrt(x: f32) -> f32 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::sqrtf32(x) } + } + + /// Experimental version of `abs_sub` in `core`. See [`f32::abs_sub`] for details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// use core::f32; + /// + /// let x = 3.0f32; + /// let y = -3.0f32; + /// + /// let abs_difference_x = (f32::math::abs_sub(x, 1.0) - 2.0).abs(); + /// let abs_difference_y = (f32::math::abs_sub(y, 1.0) - 0.0).abs(); + /// + /// assert!(abs_difference_x <= f32::EPSILON); + /// assert!(abs_difference_y <= f32::EPSILON); + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f32::abs_sub`]: ../../../std/primitive.f32.html#method.abs_sub + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + #[deprecated( + since = "1.10.0", + note = "you probably meant `(self - other).abs()`: \ this operation is `(self - other).max(0.0)` \ except that `abs_sub` also propagates NaNs (also \ known as `fdimf` in C). If you truly need the positive \ difference, consider using that expression or the C function \ `fdimf`, depending on how you wish to handle NaN (please consider \ filing an issue describing your use-case too)." -)] -#[must_use = "method returns a new number and does not mutate the original value"] -pub fn abs_sub(x: f32, other: f32) -> f32 { - libm::fdimf(x, other) -} + )] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn abs_sub(x: f32, other: f32) -> f32 { + libm::fdimf(x, other) + } -/// Experimental version of `cbrt` in `core`. See [`f32::cbrt`] for details. -/// -/// # Unspecified precision -/// -/// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and -/// can even differ within the same execution from one invocation to the next. -/// This function currently corresponds to the `cbrtf` from libc on Unix -/// and Windows. Note that this might change in the future. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// use core::f32; -/// -/// let x = 8.0f32; -/// -/// // x^(1/3) - 2 == 0 -/// let abs_difference = (f32::cbrt(x) - 2.0).abs(); -/// -/// assert!(abs_difference <= f32::EPSILON); -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f32::cbrt`]: ../../std/primitive.f32.html#method.cbrt -#[inline] -#[must_use = "method returns a new number and does not mutate the original value"] -#[unstable(feature = "core_float_math", issue = "137578")] -pub fn cbrt(x: f32) -> f32 { - libm::cbrtf(x) + /// Experimental version of `cbrt` in `core`. See [`f32::cbrt`] for details. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and + /// can even differ within the same execution from one invocation to the next. + /// This function currently corresponds to the `cbrtf` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// use core::f32; + /// + /// let x = 8.0f32; + /// + /// // x^(1/3) - 2 == 0 + /// let abs_difference = (f32::math::cbrt(x) - 2.0).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f32::cbrt`]: ../../../std/primitive.f32.html#method.cbrt + #[inline] + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "core_float_math", issue = "137578")] + pub fn cbrt(x: f32) -> f32 { + libm::cbrtf(x) + } } diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 76c4e5d1a6f78..8fbf2cffbaf4e 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -12,7 +12,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::convert::FloatToInt; -use crate::num::{FpCategory, libm}; +use crate::num::FpCategory; use crate::panic::const_assert; use crate::{intrinsics, mem}; @@ -1556,406 +1556,434 @@ impl f64 { } } -/// Experimental version of `floor` in `core`. See [`f64::floor`] for details. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// use core::f64; -/// -/// let f = 3.7_f64; -/// let g = 3.0_f64; -/// let h = -3.7_f64; -/// -/// assert_eq!(f64::floor(f), 3.0); -/// assert_eq!(f64::floor(g), 3.0); -/// assert_eq!(f64::floor(h), -4.0); -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f64::floor`]: ../../std/primitive.f64.html#method.floor -#[inline] #[unstable(feature = "core_float_math", issue = "137578")] -#[must_use = "method returns a new number and does not mutate the original value"] -pub fn floor(x: f64) -> f64 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::floorf64(x) } -} - -/// Experimental version of `ceil` in `core`. See [`f64::ceil`] for details. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// use core::f64; -/// -/// let f = 3.01_f64; -/// let g = 4.0_f64; -/// -/// assert_eq!(f64::ceil(f), 4.0); -/// assert_eq!(f64::ceil(g), 4.0); -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// Experimental implementations of floating point functions in `core`. /// -/// [`f64::ceil`]: ../../std/primitive.f64.html#method.ceil -#[inline] -#[doc(alias = "ceiling")] -#[unstable(feature = "core_float_math", issue = "137578")] -#[must_use = "method returns a new number and does not mutate the original value"] -pub fn ceil(x: f64) -> f64 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::ceilf64(x) } -} +/// _The standalone functions in this module are for testing only. +/// They will be stabilized as inherent methods._ +pub mod math { + use crate::intrinsics; + use crate::num::libm; -/// Experimental version of `round` in `core`. See [`f64::round`] for details. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// use core::f64; -/// -/// let f = 3.3_f64; -/// let g = -3.3_f64; -/// let h = -3.7_f64; -/// let i = 3.5_f64; -/// let j = 4.5_f64; -/// -/// assert_eq!(f64::round(f), 3.0); -/// assert_eq!(f64::round(g), -3.0); -/// assert_eq!(f64::round(h), -4.0); -/// assert_eq!(f64::round(i), 4.0); -/// assert_eq!(f64::round(j), 5.0); -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f64::round`]: ../../std/primitive.f64.html#method.round -#[inline] -#[unstable(feature = "core_float_math", issue = "137578")] -#[must_use = "method returns a new number and does not mutate the original value"] -pub fn round(x: f64) -> f64 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::roundf64(x) } -} + /// Experimental version of `floor` in `core`. See [`f64::floor`] for details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// use core::f64; + /// + /// let f = 3.7_f64; + /// let g = 3.0_f64; + /// let h = -3.7_f64; + /// + /// assert_eq!(f64::math::floor(f), 3.0); + /// assert_eq!(f64::math::floor(g), 3.0); + /// assert_eq!(f64::math::floor(h), -4.0); + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f64::floor`]: ../../../std/primitive.f64.html#method.floor + #[inline] + #[unstable(feature = "core_float_math", issue = "137578")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn floor(x: f64) -> f64 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::floorf64(x) } + } -/// Experimental version of `round_ties_even` in `core`. See [`f64::round_ties_even`] for details. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// use core::f64; -/// -/// let f = 3.3_f64; -/// let g = -3.3_f64; -/// let h = 3.5_f64; -/// let i = 4.5_f64; -/// -/// assert_eq!(f64::round_ties_even(f), 3.0); -/// assert_eq!(f64::round_ties_even(g), -3.0); -/// assert_eq!(f64::round_ties_even(h), 4.0); -/// assert_eq!(f64::round_ties_even(i), 4.0); -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f64::round_ties_even`]: ../../std/primitive.f64.html#method.round_ties_even -#[inline] -#[unstable(feature = "core_float_math", issue = "137578")] -#[must_use = "method returns a new number and does not mutate the original value"] -pub fn round_ties_even(x: f64) -> f64 { - intrinsics::round_ties_even_f64(x) -} + /// Experimental version of `ceil` in `core`. See [`f64::ceil`] for details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// use core::f64; + /// + /// let f = 3.01_f64; + /// let g = 4.0_f64; + /// + /// assert_eq!(f64::math::ceil(f), 4.0); + /// assert_eq!(f64::math::ceil(g), 4.0); + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f64::ceil`]: ../../../std/primitive.f64.html#method.ceil + #[inline] + #[doc(alias = "ceiling")] + #[unstable(feature = "core_float_math", issue = "137578")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn ceil(x: f64) -> f64 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::ceilf64(x) } + } -/// Experimental version of `trunc` in `core`. See [`f64::trunc`] for details. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// use core::f64; -/// -/// let f = 3.7_f64; -/// let g = 3.0_f64; -/// let h = -3.7_f64; -/// -/// assert_eq!(f64::trunc(f), 3.0); -/// assert_eq!(f64::trunc(g), 3.0); -/// assert_eq!(f64::trunc(h), -3.0); -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f64::trunc`]: ../../std/primitive.f64.html#method.trunc -#[inline] -#[doc(alias = "truncate")] -#[unstable(feature = "core_float_math", issue = "137578")] -#[must_use = "method returns a new number and does not mutate the original value"] -pub fn trunc(x: f64) -> f64 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::truncf64(x) } -} + /// Experimental version of `round` in `core`. See [`f64::round`] for details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// use core::f64; + /// + /// let f = 3.3_f64; + /// let g = -3.3_f64; + /// let h = -3.7_f64; + /// let i = 3.5_f64; + /// let j = 4.5_f64; + /// + /// assert_eq!(f64::math::round(f), 3.0); + /// assert_eq!(f64::math::round(g), -3.0); + /// assert_eq!(f64::math::round(h), -4.0); + /// assert_eq!(f64::math::round(i), 4.0); + /// assert_eq!(f64::math::round(j), 5.0); + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f64::round`]: ../../../std/primitive.f64.html#method.round + #[inline] + #[unstable(feature = "core_float_math", issue = "137578")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn round(x: f64) -> f64 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::roundf64(x) } + } -/// Experimental version of `fract` in `core`. See [`f64::fract`] for details. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// use core::f64; -/// -/// let x = 3.6_f64; -/// let y = -3.6_f64; -/// let abs_difference_x = (f64::fract(x) - 0.6).abs(); -/// let abs_difference_y = (f64::fract(y) - (-0.6)).abs(); -/// -/// assert!(abs_difference_x < 1e-10); -/// assert!(abs_difference_y < 1e-10); -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f64::fract`]: ../../std/primitive.f64.html#method.fract -#[inline] -#[unstable(feature = "core_float_math", issue = "137578")] -#[must_use = "method returns a new number and does not mutate the original value"] -pub fn fract(x: f64) -> f64 { - x - trunc(x) -} + /// Experimental version of `round_ties_even` in `core`. See [`f64::round_ties_even`] for + /// details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// use core::f64; + /// + /// let f = 3.3_f64; + /// let g = -3.3_f64; + /// let h = 3.5_f64; + /// let i = 4.5_f64; + /// + /// assert_eq!(f64::math::round_ties_even(f), 3.0); + /// assert_eq!(f64::math::round_ties_even(g), -3.0); + /// assert_eq!(f64::math::round_ties_even(h), 4.0); + /// assert_eq!(f64::math::round_ties_even(i), 4.0); + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f64::round_ties_even`]: ../../../std/primitive.f64.html#method.round_ties_even + #[inline] + #[unstable(feature = "core_float_math", issue = "137578")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn round_ties_even(x: f64) -> f64 { + intrinsics::round_ties_even_f64(x) + } -/// Experimental version of `mul_add` in `core`. See [`f64::mul_add`] for details. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// # // FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/ -/// # #[cfg(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")))] { -/// use core::f64; -/// -/// let m = 10.0_f64; -/// let x = 4.0_f64; -/// let b = 60.0_f64; -/// -/// assert_eq!(f64::mul_add(m, x, b), 100.0); -/// assert_eq!(m * x + b, 100.0); -/// -/// let one_plus_eps = 1.0_f64 + f64::EPSILON; -/// let one_minus_eps = 1.0_f64 - f64::EPSILON; -/// let minus_one = -1.0_f64; -/// -/// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps. -/// assert_eq!(f64::mul_add(one_plus_eps, one_minus_eps, minus_one), -f64::EPSILON * f64::EPSILON); -/// // Different rounding with the non-fused multiply and add. -/// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0); -/// # } -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f64::mul_add`]: ../../std/primitive.f64.html#method.mul_add -#[inline] -#[doc(alias = "fma", alias = "fusedMultiplyAdd")] -#[unstable(feature = "core_float_math", issue = "137578")] -#[must_use = "method returns a new number and does not mutate the original value"] -pub fn mul_add(x: f64, a: f64, b: f64) -> f64 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::fmaf64(x, a, b) } -} + /// Experimental version of `trunc` in `core`. See [`f64::trunc`] for details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// use core::f64; + /// + /// let f = 3.7_f64; + /// let g = 3.0_f64; + /// let h = -3.7_f64; + /// + /// assert_eq!(f64::math::trunc(f), 3.0); + /// assert_eq!(f64::math::trunc(g), 3.0); + /// assert_eq!(f64::math::trunc(h), -3.0); + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f64::trunc`]: ../../../std/primitive.f64.html#method.trunc + #[inline] + #[doc(alias = "truncate")] + #[unstable(feature = "core_float_math", issue = "137578")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn trunc(x: f64) -> f64 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::truncf64(x) } + } -/// Experimental version of `div_euclid` in `core`. See [`f64::div_euclid`] for details. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// use core::f64; -/// -/// let a: f64 = 7.0; -/// let b = 4.0; -/// assert_eq!(f64::div_euclid(a, b), 1.0); // 7.0 > 4.0 * 1.0 -/// assert_eq!(f64::div_euclid(-a, b), -2.0); // -7.0 >= 4.0 * -2.0 -/// assert_eq!(f64::div_euclid(a, -b), -1.0); // 7.0 >= -4.0 * -1.0 -/// assert_eq!(f64::div_euclid(-a, -b), 2.0); // -7.0 >= -4.0 * 2.0 -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f64::div_euclid`]: ../../std/primitive.f64.html#method.div_euclid -#[inline] -#[unstable(feature = "core_float_math", issue = "137578")] -#[must_use = "method returns a new number and does not mutate the original value"] -pub fn div_euclid(x: f64, rhs: f64) -> f64 { - let q = trunc(x / rhs); - if x % rhs < 0.0 { - return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; + /// Experimental version of `fract` in `core`. See [`f64::fract`] for details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// use core::f64; + /// + /// let x = 3.6_f64; + /// let y = -3.6_f64; + /// let abs_difference_x = (f64::math::fract(x) - 0.6).abs(); + /// let abs_difference_y = (f64::math::fract(y) - (-0.6)).abs(); + /// + /// assert!(abs_difference_x < 1e-10); + /// assert!(abs_difference_y < 1e-10); + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f64::fract`]: ../../../std/primitive.f64.html#method.fract + #[inline] + #[unstable(feature = "core_float_math", issue = "137578")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn fract(x: f64) -> f64 { + x - trunc(x) } - q -} -/// Experimental version of `rem_euclid` in `core`. See [`f64::rem_euclid`] for details. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// use core::f64; -/// -/// let a: f64 = 7.0; -/// let b = 4.0; -/// assert_eq!(f64::rem_euclid(a, b), 3.0); -/// assert_eq!(f64::rem_euclid(-a, b), 1.0); -/// assert_eq!(f64::rem_euclid(a, -b), 3.0); -/// assert_eq!(f64::rem_euclid(-a, -b), 1.0); -/// // limitation due to round-off error -/// assert!(f64::rem_euclid(-f64::EPSILON, 3.0) != 0.0); -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f64::rem_euclid`]: ../../std/primitive.f64.html#method.rem_euclid -#[inline] -#[doc(alias = "modulo", alias = "mod")] -#[unstable(feature = "core_float_math", issue = "137578")] -#[must_use = "method returns a new number and does not mutate the original value"] -pub fn rem_euclid(x: f64, rhs: f64) -> f64 { - let r = x % rhs; - if r < 0.0 { r + rhs.abs() } else { r } -} + /// Experimental version of `mul_add` in `core`. See [`f64::mul_add`] for details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// # // FIXME(#140515): mingw has an incorrect fma + /// # // https://sourceforge.net/p/mingw-w64/bugs/848/ + /// # #[cfg(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")))] { + /// use core::f64; + /// + /// let m = 10.0_f64; + /// let x = 4.0_f64; + /// let b = 60.0_f64; + /// + /// assert_eq!(f64::math::mul_add(m, x, b), 100.0); + /// assert_eq!(m * x + b, 100.0); + /// + /// let one_plus_eps = 1.0_f64 + f64::EPSILON; + /// let one_minus_eps = 1.0_f64 - f64::EPSILON; + /// let minus_one = -1.0_f64; + /// + /// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps. + /// assert_eq!( + /// f64::math::mul_add(one_plus_eps, one_minus_eps, minus_one), + /// -f64::EPSILON * f64::EPSILON + /// ); + /// // Different rounding with the non-fused multiply and add. + /// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0); + /// # } + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f64::mul_add`]: ../../../std/primitive.f64.html#method.mul_add + #[inline] + #[doc(alias = "fma", alias = "fusedMultiplyAdd")] + #[unstable(feature = "core_float_math", issue = "137578")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn mul_add(x: f64, a: f64, b: f64) -> f64 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::fmaf64(x, a, b) } + } -/// Experimental version of `powi` in `core`. See [`f64::powi`] for details. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// use core::f64; -/// -/// let x = 2.0_f64; -/// let abs_difference = (f64::powi(x, 2) - (x * x)).abs(); -/// assert!(abs_difference <= f64::EPSILON); -/// -/// assert_eq!(f64::powi(f64::NAN, 0), 1.0); -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f64::powi`]: ../../std/primitive.f64.html#method.powi -#[inline] -#[unstable(feature = "core_float_math", issue = "137578")] -#[must_use = "method returns a new number and does not mutate the original value"] -pub fn powi(x: f64, n: i32) -> f64 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::powif64(x, n) } -} + /// Experimental version of `div_euclid` in `core`. See [`f64::div_euclid`] for details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// use core::f64; + /// + /// let a: f64 = 7.0; + /// let b = 4.0; + /// assert_eq!(f64::math::div_euclid(a, b), 1.0); // 7.0 > 4.0 * 1.0 + /// assert_eq!(f64::math::div_euclid(-a, b), -2.0); // -7.0 >= 4.0 * -2.0 + /// assert_eq!(f64::math::div_euclid(a, -b), -1.0); // 7.0 >= -4.0 * -1.0 + /// assert_eq!(f64::math::div_euclid(-a, -b), 2.0); // -7.0 >= -4.0 * 2.0 + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f64::div_euclid`]: ../../../std/primitive.f64.html#method.div_euclid + #[inline] + #[unstable(feature = "core_float_math", issue = "137578")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn div_euclid(x: f64, rhs: f64) -> f64 { + let q = trunc(x / rhs); + if x % rhs < 0.0 { + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; + } + q + } -/// Experimental version of `sqrt` in `core`. See [`f64::sqrt`] for details. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// use core::f64; -/// -/// let positive = 4.0_f64; -/// let negative = -4.0_f64; -/// let negative_zero = -0.0_f64; -/// -/// assert_eq!(f64::sqrt(positive), 2.0); -/// assert!(f64::sqrt(negative).is_nan()); -/// assert_eq!(f64::sqrt(negative_zero), negative_zero); -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f64::sqrt`]: ../../std/primitive.f64.html#method.sqrt -#[inline] -#[doc(alias = "squareRoot")] -#[unstable(feature = "core_float_math", issue = "137578")] -#[must_use = "method returns a new number and does not mutate the original value"] -pub fn sqrt(x: f64) -> f64 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::sqrtf64(x) } -} + /// Experimental version of `rem_euclid` in `core`. See [`f64::rem_euclid`] for details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// use core::f64; + /// + /// let a: f64 = 7.0; + /// let b = 4.0; + /// assert_eq!(f64::math::rem_euclid(a, b), 3.0); + /// assert_eq!(f64::math::rem_euclid(-a, b), 1.0); + /// assert_eq!(f64::math::rem_euclid(a, -b), 3.0); + /// assert_eq!(f64::math::rem_euclid(-a, -b), 1.0); + /// // limitation due to round-off error + /// assert!(f64::math::rem_euclid(-f64::EPSILON, 3.0) != 0.0); + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f64::rem_euclid`]: ../../../std/primitive.f64.html#method.rem_euclid + #[inline] + #[doc(alias = "modulo", alias = "mod")] + #[unstable(feature = "core_float_math", issue = "137578")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn rem_euclid(x: f64, rhs: f64) -> f64 { + let r = x % rhs; + if r < 0.0 { r + rhs.abs() } else { r } + } -/// Experimental version of `abs_sub` in `core`. See [`f64::abs_sub`] for details. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// use core::f64; -/// -/// let x = 3.0_f64; -/// let y = -3.0_f64; -/// -/// let abs_difference_x = (f64::abs_sub(x, 1.0) - 2.0).abs(); -/// let abs_difference_y = (f64::abs_sub(y, 1.0) - 0.0).abs(); -/// -/// assert!(abs_difference_x < 1e-10); -/// assert!(abs_difference_y < 1e-10); -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f64::abs_sub`]: ../../std/primitive.f64.html#method.abs_sub -#[inline] -#[unstable(feature = "core_float_math", issue = "137578")] -#[deprecated( - since = "1.10.0", - note = "you probably meant `(self - other).abs()`: \ + /// Experimental version of `powi` in `core`. See [`f64::powi`] for details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// use core::f64; + /// + /// let x = 2.0_f64; + /// let abs_difference = (f64::math::powi(x, 2) - (x * x)).abs(); + /// assert!(abs_difference <= f64::EPSILON); + /// + /// assert_eq!(f64::math::powi(f64::NAN, 0), 1.0); + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f64::powi`]: ../../../std/primitive.f64.html#method.powi + #[inline] + #[unstable(feature = "core_float_math", issue = "137578")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn powi(x: f64, n: i32) -> f64 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::powif64(x, n) } + } + + /// Experimental version of `sqrt` in `core`. See [`f64::sqrt`] for details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// use core::f64; + /// + /// let positive = 4.0_f64; + /// let negative = -4.0_f64; + /// let negative_zero = -0.0_f64; + /// + /// assert_eq!(f64::math::sqrt(positive), 2.0); + /// assert!(f64::math::sqrt(negative).is_nan()); + /// assert_eq!(f64::math::sqrt(negative_zero), negative_zero); + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f64::sqrt`]: ../../../std/primitive.f64.html#method.sqrt + #[inline] + #[doc(alias = "squareRoot")] + #[unstable(feature = "core_float_math", issue = "137578")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn sqrt(x: f64) -> f64 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::sqrtf64(x) } + } + + /// Experimental version of `abs_sub` in `core`. See [`f64::abs_sub`] for details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// use core::f64; + /// + /// let x = 3.0_f64; + /// let y = -3.0_f64; + /// + /// let abs_difference_x = (f64::math::abs_sub(x, 1.0) - 2.0).abs(); + /// let abs_difference_y = (f64::math::abs_sub(y, 1.0) - 0.0).abs(); + /// + /// assert!(abs_difference_x < 1e-10); + /// assert!(abs_difference_y < 1e-10); + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f64::abs_sub`]: ../../../std/primitive.f64.html#method.abs_sub + #[inline] + #[unstable(feature = "core_float_math", issue = "137578")] + #[deprecated( + since = "1.10.0", + note = "you probably meant `(self - other).abs()`: \ this operation is `(self - other).max(0.0)` \ except that `abs_sub` also propagates NaNs (also \ known as `fdim` in C). If you truly need the positive \ difference, consider using that expression or the C function \ `fdim`, depending on how you wish to handle NaN (please consider \ filing an issue describing your use-case too)." -)] -#[must_use = "method returns a new number and does not mutate the original value"] -pub fn abs_sub(x: f64, other: f64) -> f64 { - libm::fdim(x, other) -} + )] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn abs_sub(x: f64, other: f64) -> f64 { + libm::fdim(x, other) + } -/// Experimental version of `cbrt` in `core`. See [`f64::cbrt`] for details. -/// -/// # Examples -/// -/// ``` -/// #![feature(core_float_math)] -/// -/// use core::f64; -/// -/// let x = 8.0_f64; -/// -/// // x^(1/3) - 2 == 0 -/// let abs_difference = (f64::cbrt(x) - 2.0).abs(); -/// -/// assert!(abs_difference < 1e-10); -/// ``` -/// -/// _This standalone function is for testing only. It will be stabilized as an inherent method._ -/// -/// [`f64::cbrt`]: ../../std/primitive.f64.html#method.cbrt -#[inline] -#[unstable(feature = "core_float_math", issue = "137578")] -#[must_use = "method returns a new number and does not mutate the original value"] -pub fn cbrt(x: f64) -> f64 { - libm::cbrt(x) + /// Experimental version of `cbrt` in `core`. See [`f64::cbrt`] for details. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_float_math)] + /// + /// use core::f64; + /// + /// let x = 8.0_f64; + /// + /// // x^(1/3) - 2 == 0 + /// let abs_difference = (f64::math::cbrt(x) - 2.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + /// + /// _This standalone function is for testing only. + /// It will be stabilized as an inherent method._ + /// + /// [`f64::cbrt`]: ../../../std/primitive.f64.html#method.cbrt + #[inline] + #[unstable(feature = "core_float_math", issue = "137578")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn cbrt(x: f64) -> f64 { + libm::cbrt(x) + } } diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 9b551643bae24..36f1937bedfeb 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -215,88 +215,88 @@ fn test_classify() { #[test] fn test_floor() { - assert_approx_eq!(f32::floor(1.0f32), 1.0f32); - assert_approx_eq!(f32::floor(1.3f32), 1.0f32); - assert_approx_eq!(f32::floor(1.5f32), 1.0f32); - assert_approx_eq!(f32::floor(1.7f32), 1.0f32); - assert_approx_eq!(f32::floor(0.0f32), 0.0f32); - assert_approx_eq!(f32::floor(-0.0f32), -0.0f32); - assert_approx_eq!(f32::floor(-1.0f32), -1.0f32); - assert_approx_eq!(f32::floor(-1.3f32), -2.0f32); - assert_approx_eq!(f32::floor(-1.5f32), -2.0f32); - assert_approx_eq!(f32::floor(-1.7f32), -2.0f32); + assert_approx_eq!(f32::math::floor(1.0f32), 1.0f32); + assert_approx_eq!(f32::math::floor(1.3f32), 1.0f32); + assert_approx_eq!(f32::math::floor(1.5f32), 1.0f32); + assert_approx_eq!(f32::math::floor(1.7f32), 1.0f32); + assert_approx_eq!(f32::math::floor(0.0f32), 0.0f32); + assert_approx_eq!(f32::math::floor(-0.0f32), -0.0f32); + assert_approx_eq!(f32::math::floor(-1.0f32), -1.0f32); + assert_approx_eq!(f32::math::floor(-1.3f32), -2.0f32); + assert_approx_eq!(f32::math::floor(-1.5f32), -2.0f32); + assert_approx_eq!(f32::math::floor(-1.7f32), -2.0f32); } #[test] fn test_ceil() { - assert_approx_eq!(f32::ceil(1.0f32), 1.0f32); - assert_approx_eq!(f32::ceil(1.3f32), 2.0f32); - assert_approx_eq!(f32::ceil(1.5f32), 2.0f32); - assert_approx_eq!(f32::ceil(1.7f32), 2.0f32); - assert_approx_eq!(f32::ceil(0.0f32), 0.0f32); - assert_approx_eq!(f32::ceil(-0.0f32), -0.0f32); - assert_approx_eq!(f32::ceil(-1.0f32), -1.0f32); - assert_approx_eq!(f32::ceil(-1.3f32), -1.0f32); - assert_approx_eq!(f32::ceil(-1.5f32), -1.0f32); - assert_approx_eq!(f32::ceil(-1.7f32), -1.0f32); + assert_approx_eq!(f32::math::ceil(1.0f32), 1.0f32); + assert_approx_eq!(f32::math::ceil(1.3f32), 2.0f32); + assert_approx_eq!(f32::math::ceil(1.5f32), 2.0f32); + assert_approx_eq!(f32::math::ceil(1.7f32), 2.0f32); + assert_approx_eq!(f32::math::ceil(0.0f32), 0.0f32); + assert_approx_eq!(f32::math::ceil(-0.0f32), -0.0f32); + assert_approx_eq!(f32::math::ceil(-1.0f32), -1.0f32); + assert_approx_eq!(f32::math::ceil(-1.3f32), -1.0f32); + assert_approx_eq!(f32::math::ceil(-1.5f32), -1.0f32); + assert_approx_eq!(f32::math::ceil(-1.7f32), -1.0f32); } #[test] fn test_round() { - assert_approx_eq!(f32::round(2.5f32), 3.0f32); - assert_approx_eq!(f32::round(1.0f32), 1.0f32); - assert_approx_eq!(f32::round(1.3f32), 1.0f32); - assert_approx_eq!(f32::round(1.5f32), 2.0f32); - assert_approx_eq!(f32::round(1.7f32), 2.0f32); - assert_approx_eq!(f32::round(0.0f32), 0.0f32); - assert_approx_eq!(f32::round(-0.0f32), -0.0f32); - assert_approx_eq!(f32::round(-1.0f32), -1.0f32); - assert_approx_eq!(f32::round(-1.3f32), -1.0f32); - assert_approx_eq!(f32::round(-1.5f32), -2.0f32); - assert_approx_eq!(f32::round(-1.7f32), -2.0f32); + assert_approx_eq!(f32::math::round(2.5f32), 3.0f32); + assert_approx_eq!(f32::math::round(1.0f32), 1.0f32); + assert_approx_eq!(f32::math::round(1.3f32), 1.0f32); + assert_approx_eq!(f32::math::round(1.5f32), 2.0f32); + assert_approx_eq!(f32::math::round(1.7f32), 2.0f32); + assert_approx_eq!(f32::math::round(0.0f32), 0.0f32); + assert_approx_eq!(f32::math::round(-0.0f32), -0.0f32); + assert_approx_eq!(f32::math::round(-1.0f32), -1.0f32); + assert_approx_eq!(f32::math::round(-1.3f32), -1.0f32); + assert_approx_eq!(f32::math::round(-1.5f32), -2.0f32); + assert_approx_eq!(f32::math::round(-1.7f32), -2.0f32); } #[test] fn test_round_ties_even() { - assert_approx_eq!(f32::round_ties_even(2.5f32), 2.0f32); - assert_approx_eq!(f32::round_ties_even(1.0f32), 1.0f32); - assert_approx_eq!(f32::round_ties_even(1.3f32), 1.0f32); - assert_approx_eq!(f32::round_ties_even(1.5f32), 2.0f32); - assert_approx_eq!(f32::round_ties_even(1.7f32), 2.0f32); - assert_approx_eq!(f32::round_ties_even(0.0f32), 0.0f32); - assert_approx_eq!(f32::round_ties_even(-0.0f32), -0.0f32); - assert_approx_eq!(f32::round_ties_even(-1.0f32), -1.0f32); - assert_approx_eq!(f32::round_ties_even(-1.3f32), -1.0f32); - assert_approx_eq!(f32::round_ties_even(-1.5f32), -2.0f32); - assert_approx_eq!(f32::round_ties_even(-1.7f32), -2.0f32); + assert_approx_eq!(f32::math::round_ties_even(2.5f32), 2.0f32); + assert_approx_eq!(f32::math::round_ties_even(1.0f32), 1.0f32); + assert_approx_eq!(f32::math::round_ties_even(1.3f32), 1.0f32); + assert_approx_eq!(f32::math::round_ties_even(1.5f32), 2.0f32); + assert_approx_eq!(f32::math::round_ties_even(1.7f32), 2.0f32); + assert_approx_eq!(f32::math::round_ties_even(0.0f32), 0.0f32); + assert_approx_eq!(f32::math::round_ties_even(-0.0f32), -0.0f32); + assert_approx_eq!(f32::math::round_ties_even(-1.0f32), -1.0f32); + assert_approx_eq!(f32::math::round_ties_even(-1.3f32), -1.0f32); + assert_approx_eq!(f32::math::round_ties_even(-1.5f32), -2.0f32); + assert_approx_eq!(f32::math::round_ties_even(-1.7f32), -2.0f32); } #[test] fn test_trunc() { - assert_approx_eq!(f32::trunc(1.0f32), 1.0f32); - assert_approx_eq!(f32::trunc(1.3f32), 1.0f32); - assert_approx_eq!(f32::trunc(1.5f32), 1.0f32); - assert_approx_eq!(f32::trunc(1.7f32), 1.0f32); - assert_approx_eq!(f32::trunc(0.0f32), 0.0f32); - assert_approx_eq!(f32::trunc(-0.0f32), -0.0f32); - assert_approx_eq!(f32::trunc(-1.0f32), -1.0f32); - assert_approx_eq!(f32::trunc(-1.3f32), -1.0f32); - assert_approx_eq!(f32::trunc(-1.5f32), -1.0f32); - assert_approx_eq!(f32::trunc(-1.7f32), -1.0f32); + assert_approx_eq!(f32::math::trunc(1.0f32), 1.0f32); + assert_approx_eq!(f32::math::trunc(1.3f32), 1.0f32); + assert_approx_eq!(f32::math::trunc(1.5f32), 1.0f32); + assert_approx_eq!(f32::math::trunc(1.7f32), 1.0f32); + assert_approx_eq!(f32::math::trunc(0.0f32), 0.0f32); + assert_approx_eq!(f32::math::trunc(-0.0f32), -0.0f32); + assert_approx_eq!(f32::math::trunc(-1.0f32), -1.0f32); + assert_approx_eq!(f32::math::trunc(-1.3f32), -1.0f32); + assert_approx_eq!(f32::math::trunc(-1.5f32), -1.0f32); + assert_approx_eq!(f32::math::trunc(-1.7f32), -1.0f32); } #[test] fn test_fract() { - assert_approx_eq!(f32::fract(1.0f32), 0.0f32); - assert_approx_eq!(f32::fract(1.3f32), 0.3f32); - assert_approx_eq!(f32::fract(1.5f32), 0.5f32); - assert_approx_eq!(f32::fract(1.7f32), 0.7f32); - assert_approx_eq!(f32::fract(0.0f32), 0.0f32); - assert_approx_eq!(f32::fract(-0.0f32), -0.0f32); - assert_approx_eq!(f32::fract(-1.0f32), -0.0f32); - assert_approx_eq!(f32::fract(-1.3f32), -0.3f32); - assert_approx_eq!(f32::fract(-1.5f32), -0.5f32); - assert_approx_eq!(f32::fract(-1.7f32), -0.7f32); + assert_approx_eq!(f32::math::fract(1.0f32), 0.0f32); + assert_approx_eq!(f32::math::fract(1.3f32), 0.3f32); + assert_approx_eq!(f32::math::fract(1.5f32), 0.5f32); + assert_approx_eq!(f32::math::fract(1.7f32), 0.7f32); + assert_approx_eq!(f32::math::fract(0.0f32), 0.0f32); + assert_approx_eq!(f32::math::fract(-0.0f32), -0.0f32); + assert_approx_eq!(f32::math::fract(-1.0f32), -0.0f32); + assert_approx_eq!(f32::math::fract(-1.3f32), -0.3f32); + assert_approx_eq!(f32::math::fract(-1.5f32), -0.5f32); + assert_approx_eq!(f32::math::fract(-1.7f32), -0.7f32); } #[test] @@ -417,15 +417,15 @@ fn test_mul_add() { let nan: f32 = f32::NAN; let inf: f32 = f32::INFINITY; let neg_inf: f32 = f32::NEG_INFINITY; - assert_approx_eq!(f32::mul_add(12.3f32, 4.5, 6.7), 62.05); - assert_approx_eq!(f32::mul_add(-12.3f32, -4.5, -6.7), 48.65); - assert_approx_eq!(f32::mul_add(0.0f32, 8.9, 1.2), 1.2); - assert_approx_eq!(f32::mul_add(3.4f32, -0.0, 5.6), 5.6); - assert!(f32::mul_add(nan, 7.8, 9.0).is_nan()); - assert_eq!(f32::mul_add(inf, 7.8, 9.0), inf); - assert_eq!(f32::mul_add(neg_inf, 7.8, 9.0), neg_inf); - assert_eq!(f32::mul_add(8.9f32, inf, 3.2), inf); - assert_eq!(f32::mul_add(-3.2f32, 2.4, neg_inf), neg_inf); + assert_approx_eq!(f32::math::mul_add(12.3f32, 4.5, 6.7), 62.05); + assert_approx_eq!(f32::math::mul_add(-12.3f32, -4.5, -6.7), 48.65); + assert_approx_eq!(f32::math::mul_add(0.0f32, 8.9, 1.2), 1.2); + assert_approx_eq!(f32::math::mul_add(3.4f32, -0.0, 5.6), 5.6); + assert!(f32::math::mul_add(nan, 7.8, 9.0).is_nan()); + assert_eq!(f32::math::mul_add(inf, 7.8, 9.0), inf); + assert_eq!(f32::math::mul_add(neg_inf, 7.8, 9.0), neg_inf); + assert_eq!(f32::math::mul_add(8.9f32, inf, 3.2), inf); + assert_eq!(f32::math::mul_add(-3.2f32, 2.4, neg_inf), neg_inf); } #[test] diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 988108371d731..970519983538d 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -1,5 +1,6 @@ -use std::f64::consts; -use std::num::FpCategory as Fp; +use core::f64; +use core::f64::consts; +use core::num::FpCategory as Fp; /// Smallest number const TINY_BITS: u64 = 0x1; @@ -201,88 +202,88 @@ fn test_classify() { #[test] fn test_floor() { - assert_approx_eq!(f64::floor(1.0f64), 1.0f64); - assert_approx_eq!(f64::floor(1.3f64), 1.0f64); - assert_approx_eq!(f64::floor(1.5f64), 1.0f64); - assert_approx_eq!(f64::floor(1.7f64), 1.0f64); - assert_approx_eq!(f64::floor(0.0f64), 0.0f64); - assert_approx_eq!(f64::floor(-0.0f64), -0.0f64); - assert_approx_eq!(f64::floor(-1.0f64), -1.0f64); - assert_approx_eq!(f64::floor(-1.3f64), -2.0f64); - assert_approx_eq!(f64::floor(-1.5f64), -2.0f64); - assert_approx_eq!(f64::floor(-1.7f64), -2.0f64); + assert_approx_eq!(f64::math::floor(1.0f64), 1.0f64); + assert_approx_eq!(f64::math::floor(1.3f64), 1.0f64); + assert_approx_eq!(f64::math::floor(1.5f64), 1.0f64); + assert_approx_eq!(f64::math::floor(1.7f64), 1.0f64); + assert_approx_eq!(f64::math::floor(0.0f64), 0.0f64); + assert_approx_eq!(f64::math::floor(-0.0f64), -0.0f64); + assert_approx_eq!(f64::math::floor(-1.0f64), -1.0f64); + assert_approx_eq!(f64::math::floor(-1.3f64), -2.0f64); + assert_approx_eq!(f64::math::floor(-1.5f64), -2.0f64); + assert_approx_eq!(f64::math::floor(-1.7f64), -2.0f64); } #[test] fn test_ceil() { - assert_approx_eq!(f64::ceil(1.0f64), 1.0f64); - assert_approx_eq!(f64::ceil(1.3f64), 2.0f64); - assert_approx_eq!(f64::ceil(1.5f64), 2.0f64); - assert_approx_eq!(f64::ceil(1.7f64), 2.0f64); - assert_approx_eq!(f64::ceil(0.0f64), 0.0f64); - assert_approx_eq!(f64::ceil(-0.0f64), -0.0f64); - assert_approx_eq!(f64::ceil(-1.0f64), -1.0f64); - assert_approx_eq!(f64::ceil(-1.3f64), -1.0f64); - assert_approx_eq!(f64::ceil(-1.5f64), -1.0f64); - assert_approx_eq!(f64::ceil(-1.7f64), -1.0f64); + assert_approx_eq!(f64::math::ceil(1.0f64), 1.0f64); + assert_approx_eq!(f64::math::ceil(1.3f64), 2.0f64); + assert_approx_eq!(f64::math::ceil(1.5f64), 2.0f64); + assert_approx_eq!(f64::math::ceil(1.7f64), 2.0f64); + assert_approx_eq!(f64::math::ceil(0.0f64), 0.0f64); + assert_approx_eq!(f64::math::ceil(-0.0f64), -0.0f64); + assert_approx_eq!(f64::math::ceil(-1.0f64), -1.0f64); + assert_approx_eq!(f64::math::ceil(-1.3f64), -1.0f64); + assert_approx_eq!(f64::math::ceil(-1.5f64), -1.0f64); + assert_approx_eq!(f64::math::ceil(-1.7f64), -1.0f64); } #[test] fn test_round() { - assert_approx_eq!(f64::round(2.5f64), 3.0f64); - assert_approx_eq!(f64::round(1.0f64), 1.0f64); - assert_approx_eq!(f64::round(1.3f64), 1.0f64); - assert_approx_eq!(f64::round(1.5f64), 2.0f64); - assert_approx_eq!(f64::round(1.7f64), 2.0f64); - assert_approx_eq!(f64::round(0.0f64), 0.0f64); - assert_approx_eq!(f64::round(-0.0f64), -0.0f64); - assert_approx_eq!(f64::round(-1.0f64), -1.0f64); - assert_approx_eq!(f64::round(-1.3f64), -1.0f64); - assert_approx_eq!(f64::round(-1.5f64), -2.0f64); - assert_approx_eq!(f64::round(-1.7f64), -2.0f64); + assert_approx_eq!(f64::math::round(2.5f64), 3.0f64); + assert_approx_eq!(f64::math::round(1.0f64), 1.0f64); + assert_approx_eq!(f64::math::round(1.3f64), 1.0f64); + assert_approx_eq!(f64::math::round(1.5f64), 2.0f64); + assert_approx_eq!(f64::math::round(1.7f64), 2.0f64); + assert_approx_eq!(f64::math::round(0.0f64), 0.0f64); + assert_approx_eq!(f64::math::round(-0.0f64), -0.0f64); + assert_approx_eq!(f64::math::round(-1.0f64), -1.0f64); + assert_approx_eq!(f64::math::round(-1.3f64), -1.0f64); + assert_approx_eq!(f64::math::round(-1.5f64), -2.0f64); + assert_approx_eq!(f64::math::round(-1.7f64), -2.0f64); } #[test] fn test_round_ties_even() { - assert_approx_eq!(f64::round_ties_even(2.5f64), 2.0f64); - assert_approx_eq!(f64::round_ties_even(1.0f64), 1.0f64); - assert_approx_eq!(f64::round_ties_even(1.3f64), 1.0f64); - assert_approx_eq!(f64::round_ties_even(1.5f64), 2.0f64); - assert_approx_eq!(f64::round_ties_even(1.7f64), 2.0f64); - assert_approx_eq!(f64::round_ties_even(0.0f64), 0.0f64); - assert_approx_eq!(f64::round_ties_even(-0.0f64), -0.0f64); - assert_approx_eq!(f64::round_ties_even(-1.0f64), -1.0f64); - assert_approx_eq!(f64::round_ties_even(-1.3f64), -1.0f64); - assert_approx_eq!(f64::round_ties_even(-1.5f64), -2.0f64); - assert_approx_eq!(f64::round_ties_even(-1.7f64), -2.0f64); + assert_approx_eq!(f64::math::round_ties_even(2.5f64), 2.0f64); + assert_approx_eq!(f64::math::round_ties_even(1.0f64), 1.0f64); + assert_approx_eq!(f64::math::round_ties_even(1.3f64), 1.0f64); + assert_approx_eq!(f64::math::round_ties_even(1.5f64), 2.0f64); + assert_approx_eq!(f64::math::round_ties_even(1.7f64), 2.0f64); + assert_approx_eq!(f64::math::round_ties_even(0.0f64), 0.0f64); + assert_approx_eq!(f64::math::round_ties_even(-0.0f64), -0.0f64); + assert_approx_eq!(f64::math::round_ties_even(-1.0f64), -1.0f64); + assert_approx_eq!(f64::math::round_ties_even(-1.3f64), -1.0f64); + assert_approx_eq!(f64::math::round_ties_even(-1.5f64), -2.0f64); + assert_approx_eq!(f64::math::round_ties_even(-1.7f64), -2.0f64); } #[test] fn test_trunc() { - assert_approx_eq!(f64::trunc(1.0f64), 1.0f64); - assert_approx_eq!(f64::trunc(1.3f64), 1.0f64); - assert_approx_eq!(f64::trunc(1.5f64), 1.0f64); - assert_approx_eq!(f64::trunc(1.7f64), 1.0f64); - assert_approx_eq!(f64::trunc(0.0f64), 0.0f64); - assert_approx_eq!(f64::trunc(-0.0f64), -0.0f64); - assert_approx_eq!(f64::trunc(-1.0f64), -1.0f64); - assert_approx_eq!(f64::trunc(-1.3f64), -1.0f64); - assert_approx_eq!(f64::trunc(-1.5f64), -1.0f64); - assert_approx_eq!(f64::trunc(-1.7f64), -1.0f64); + assert_approx_eq!(f64::math::trunc(1.0f64), 1.0f64); + assert_approx_eq!(f64::math::trunc(1.3f64), 1.0f64); + assert_approx_eq!(f64::math::trunc(1.5f64), 1.0f64); + assert_approx_eq!(f64::math::trunc(1.7f64), 1.0f64); + assert_approx_eq!(f64::math::trunc(0.0f64), 0.0f64); + assert_approx_eq!(f64::math::trunc(-0.0f64), -0.0f64); + assert_approx_eq!(f64::math::trunc(-1.0f64), -1.0f64); + assert_approx_eq!(f64::math::trunc(-1.3f64), -1.0f64); + assert_approx_eq!(f64::math::trunc(-1.5f64), -1.0f64); + assert_approx_eq!(f64::math::trunc(-1.7f64), -1.0f64); } #[test] fn test_fract() { - assert_approx_eq!(f64::fract(1.0f64), 0.0f64); - assert_approx_eq!(f64::fract(1.3f64), 0.3f64); - assert_approx_eq!(f64::fract(1.5f64), 0.5f64); - assert_approx_eq!(f64::fract(1.7f64), 0.7f64); - assert_approx_eq!(f64::fract(0.0f64), 0.0f64); - assert_approx_eq!(f64::fract(-0.0f64), -0.0f64); - assert_approx_eq!(f64::fract(-1.0f64), -0.0f64); - assert_approx_eq!(f64::fract(-1.3f64), -0.3f64); - assert_approx_eq!(f64::fract(-1.5f64), -0.5f64); - assert_approx_eq!(f64::fract(-1.7f64), -0.7f64); + assert_approx_eq!(f64::math::fract(1.0f64), 0.0f64); + assert_approx_eq!(f64::math::fract(1.3f64), 0.3f64); + assert_approx_eq!(f64::math::fract(1.5f64), 0.5f64); + assert_approx_eq!(f64::math::fract(1.7f64), 0.7f64); + assert_approx_eq!(f64::math::fract(0.0f64), 0.0f64); + assert_approx_eq!(f64::math::fract(-0.0f64), -0.0f64); + assert_approx_eq!(f64::math::fract(-1.0f64), -0.0f64); + assert_approx_eq!(f64::math::fract(-1.3f64), -0.3f64); + assert_approx_eq!(f64::math::fract(-1.5f64), -0.5f64); + assert_approx_eq!(f64::math::fract(-1.7f64), -0.7f64); } #[test] diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index 94140d01d8b7e..5210e75ec4531 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -46,7 +46,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn floor(self) -> f32 { - core::f32::floor(self) + core::f32::math::floor(self) } /// Returns the smallest integer greater than or equal to `self`. @@ -68,7 +68,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn ceil(self) -> f32 { - core::f32::ceil(self) + core::f32::math::ceil(self) } /// Returns the nearest integer to `self`. If a value is half-way between two @@ -96,7 +96,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn round(self) -> f32 { - core::f32::round(self) + core::f32::math::round(self) } /// Returns the nearest integer to a number. Rounds half-way cases to the number @@ -122,7 +122,7 @@ impl f32 { #[stable(feature = "round_ties_even", since = "1.77.0")] #[inline] pub fn round_ties_even(self) -> f32 { - core::f32::round_ties_even(self) + core::f32::math::round_ties_even(self) } /// Returns the integer part of `self`. @@ -147,7 +147,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn trunc(self) -> f32 { - core::f32::trunc(self) + core::f32::math::trunc(self) } /// Returns the fractional part of `self`. @@ -170,7 +170,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn fract(self) -> f32 { - core::f32::fract(self) + core::f32::math::fract(self) } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding @@ -212,7 +212,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn mul_add(self, a: f32, b: f32) -> f32 { - core::f32::mul_add(self, a, b) + core::f32::math::mul_add(self, a, b) } /// Calculates Euclidean division, the matching method for `rem_euclid`. @@ -242,7 +242,7 @@ impl f32 { #[inline] #[stable(feature = "euclidean_division", since = "1.38.0")] pub fn div_euclid(self, rhs: f32) -> f32 { - core::f32::div_euclid(self, rhs) + core::f32::math::div_euclid(self, rhs) } /// Calculates the least nonnegative remainder of `self (mod rhs)`. @@ -279,7 +279,7 @@ impl f32 { #[inline] #[stable(feature = "euclidean_division", since = "1.38.0")] pub fn rem_euclid(self, rhs: f32) -> f32 { - core::f32::rem_euclid(self, rhs) + core::f32::math::rem_euclid(self, rhs) } /// Raises a number to an integer power. @@ -307,7 +307,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn powi(self, n: i32) -> f32 { - core::f32::powi(self, n) + core::f32::math::powi(self, n) } /// Raises a number to a floating point power. @@ -362,7 +362,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn sqrt(self) -> f32 { - core::f32::sqrt(self) + core::f32::math::sqrt(self) } /// Returns `e^(self)`, (the exponential function). @@ -595,7 +595,7 @@ impl f32 { )] pub fn abs_sub(self, other: f32) -> f32 { #[allow(deprecated)] - core::f32::abs_sub(self, other) + core::f32::math::abs_sub(self, other) } /// Returns the cube root of a number. @@ -622,7 +622,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cbrt(self) -> f32 { - core::f32::cbrt(self) + core::f32::math::cbrt(self) } /// Compute the distance between the origin and a point (`x`, `y`) on the diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index 051061ae60555..f837800d66342 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -46,7 +46,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn floor(self) -> f64 { - core::f64::floor(self) + core::f64::math::floor(self) } /// Returns the smallest integer greater than or equal to `self`. @@ -68,7 +68,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn ceil(self) -> f64 { - core::f64::ceil(self) + core::f64::math::ceil(self) } /// Returns the nearest integer to `self`. If a value is half-way between two @@ -96,7 +96,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn round(self) -> f64 { - core::f64::round(self) + core::f64::math::round(self) } /// Returns the nearest integer to a number. Rounds half-way cases to the number @@ -122,7 +122,7 @@ impl f64 { #[stable(feature = "round_ties_even", since = "1.77.0")] #[inline] pub fn round_ties_even(self) -> f64 { - core::f64::round_ties_even(self) + core::f64::math::round_ties_even(self) } /// Returns the integer part of `self`. @@ -147,7 +147,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn trunc(self) -> f64 { - core::f64::trunc(self) + core::f64::math::trunc(self) } /// Returns the fractional part of `self`. @@ -170,7 +170,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn fract(self) -> f64 { - core::f64::fract(self) + core::f64::math::fract(self) } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding @@ -212,7 +212,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn mul_add(self, a: f64, b: f64) -> f64 { - core::f64::mul_add(self, a, b) + core::f64::math::mul_add(self, a, b) } /// Calculates Euclidean division, the matching method for `rem_euclid`. @@ -242,7 +242,7 @@ impl f64 { #[inline] #[stable(feature = "euclidean_division", since = "1.38.0")] pub fn div_euclid(self, rhs: f64) -> f64 { - core::f64::div_euclid(self, rhs) + core::f64::math::div_euclid(self, rhs) } /// Calculates the least nonnegative remainder of `self (mod rhs)`. @@ -279,7 +279,7 @@ impl f64 { #[inline] #[stable(feature = "euclidean_division", since = "1.38.0")] pub fn rem_euclid(self, rhs: f64) -> f64 { - core::f64::rem_euclid(self, rhs) + core::f64::math::rem_euclid(self, rhs) } /// Raises a number to an integer power. @@ -307,7 +307,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn powi(self, n: i32) -> f64 { - core::f64::powi(self, n) + core::f64::math::powi(self, n) } /// Raises a number to a floating point power. @@ -362,7 +362,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn sqrt(self) -> f64 { - core::f64::sqrt(self) + core::f64::math::sqrt(self) } /// Returns `e^(self)`, (the exponential function). @@ -595,7 +595,7 @@ impl f64 { )] pub fn abs_sub(self, other: f64) -> f64 { #[allow(deprecated)] - core::f64::abs_sub(self, other) + core::f64::math::abs_sub(self, other) } /// Returns the cube root of a number. @@ -622,7 +622,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cbrt(self) -> f64 { - core::f64::cbrt(self) + core::f64::math::cbrt(self) } /// Compute the distance between the origin and a point (`x`, `y`) on the From a3cf6f640828647e34afe96a626b3b4f6bbb22b1 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 27 Feb 2025 22:00:15 +0000 Subject: [PATCH 2519/4206] Add `std::os::unix::process::CommandExt::chroot` to safely chroot a child process This adds a `chroot` method to the `CommandExt` extension trait for the `Command` builder, to set a directory to chroot into. This will chroot the child process into that directory right before calling chdir for the `Command`'s working directory. To avoid allowing a process to have a working directory outside of the chroot, if the `Command` does not yet have a working directory set, `chroot` will set its working directory to "/". --- library/std/src/os/unix/process.rs | 16 ++++++++++++++++ library/std/src/sys/process/unix/common.rs | 13 +++++++++++++ library/std/src/sys/process/unix/unix.rs | 10 ++++++++++ library/std/src/sys/process/unix/vxworks.rs | 6 ++++++ 4 files changed, 45 insertions(+) diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index 7c3fa7d6507e7..27866badfbe58 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -8,6 +8,7 @@ use cfg_if::cfg_if; use crate::ffi::OsStr; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; +use crate::path::Path; use crate::sealed::Sealed; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; use crate::{io, process, sys}; @@ -197,6 +198,16 @@ pub trait CommandExt: Sealed { /// ``` #[stable(feature = "process_set_process_group", since = "1.64.0")] fn process_group(&mut self, pgroup: i32) -> &mut process::Command; + + /// Set the root of the child process. This calls `chroot` in the child process before executing + /// the command. + /// + /// This happens before changing to the directory specified with `Command::current_dir`, and + /// that directory will be relative to the new root. If no directory has been specified with + /// `Command::current_dir`, this will set the directory to `/`, to avoid leaving the current + /// directory outside the chroot. + #[unstable(feature = "process_chroot", issue = "none")] + fn chroot>(&mut self, dir: P) -> &mut process::Command; } #[stable(feature = "rust1", since = "1.0.0")] @@ -242,6 +253,11 @@ impl CommandExt for process::Command { self.as_inner_mut().pgroup(pgroup); self } + + fn chroot>(&mut self, dir: P) -> &mut process::Command { + self.as_inner_mut().chroot(dir.as_ref()); + self + } } /// Unix-specific extensions to [`process::ExitStatus`] and diff --git a/library/std/src/sys/process/unix/common.rs b/library/std/src/sys/process/unix/common.rs index a9c2510e6d454..e205a8390052f 100644 --- a/library/std/src/sys/process/unix/common.rs +++ b/library/std/src/sys/process/unix/common.rs @@ -88,6 +88,7 @@ pub struct Command { program_kind: ProgramKind, cwd: Option, + chroot: Option, uid: Option, gid: Option, saw_nul: bool, @@ -182,6 +183,7 @@ impl Command { program_kind, env: Default::default(), cwd: None, + chroot: None, uid: None, gid: None, saw_nul, @@ -206,6 +208,7 @@ impl Command { program_kind, env: Default::default(), cwd: None, + chroot: None, uid: None, gid: None, saw_nul, @@ -254,6 +257,12 @@ impl Command { pub fn pgroup(&mut self, pgroup: pid_t) { self.pgroup = Some(pgroup); } + pub fn chroot(&mut self, dir: &Path) { + self.chroot = Some(os2c(dir.as_os_str(), &mut self.saw_nul)); + if self.cwd.is_none() { + self.cwd(&OsStr::new("/")); + } + } #[cfg(target_os = "linux")] pub fn create_pidfd(&mut self, val: bool) { @@ -326,6 +335,10 @@ impl Command { pub fn get_pgroup(&self) -> Option { self.pgroup } + #[allow(dead_code)] + pub fn get_chroot(&self) -> Option<&CStr> { + self.chroot.as_deref() + } pub fn get_closures(&mut self) -> &mut Vec io::Result<()> + Send + Sync>> { &mut self.closures diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs index 1b3bd2de265da..4f595ac9a1c5f 100644 --- a/library/std/src/sys/process/unix/unix.rs +++ b/library/std/src/sys/process/unix/unix.rs @@ -323,6 +323,15 @@ impl Command { cvt(libc::setuid(u as uid_t))?; } } + if let Some(chroot) = self.get_chroot() { + #[cfg(not(target_os = "fuchsia"))] + cvt(libc::chroot(chroot.as_ptr()))?; + #[cfg(target_os = "fuchsia")] + return Err(io::const_error!( + io::ErrorKind::Unsupported, + "chroot not supported by fuchsia" + )); + } if let Some(cwd) = self.get_cwd() { cvt(libc::chdir(cwd.as_ptr()))?; } @@ -447,6 +456,7 @@ impl Command { || (self.env_saw_path() && !self.program_is_path()) || !self.get_closures().is_empty() || self.get_groups().is_some() + || self.get_chroot().is_some() { return Ok(None); } diff --git a/library/std/src/sys/process/unix/vxworks.rs b/library/std/src/sys/process/unix/vxworks.rs index fab3b36ebf3fa..f33b4a375da83 100644 --- a/library/std/src/sys/process/unix/vxworks.rs +++ b/library/std/src/sys/process/unix/vxworks.rs @@ -27,6 +27,12 @@ impl Command { "nul byte found in provided data", )); } + if self.get_chroot().is_some() { + return Err(io::const_error!( + ErrorKind::Unsupported, + "chroot not supported by vxworks", + )); + } let (ours, theirs) = self.setup_io(default, needs_stdin)?; let mut p = Process { pid: 0, status: None }; From c3b750ce0f6d1b40874f88b552d271abea3a3dde Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 20 May 2025 17:59:18 +0200 Subject: [PATCH 2520/4206] `CommandExt::chroot`: Document difference to underlying `chroot` --- library/std/src/os/unix/process.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index 27866badfbe58..8d238aa583519 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -203,9 +203,11 @@ pub trait CommandExt: Sealed { /// the command. /// /// This happens before changing to the directory specified with `Command::current_dir`, and - /// that directory will be relative to the new root. If no directory has been specified with - /// `Command::current_dir`, this will set the directory to `/`, to avoid leaving the current - /// directory outside the chroot. + /// that directory will be relative to the new root. + /// + /// If no directory has been specified with `Command::current_dir`, this will set the directory + /// to `/`, to avoid leaving the current directory outside the chroot. (This is an intentional + /// difference from the underlying `chroot` system call.) #[unstable(feature = "process_chroot", issue = "none")] fn chroot>(&mut self, dir: P) -> &mut process::Command; } From 17fdf19c9cd566987c3f96f69ac60d4741e05b07 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 20 May 2025 18:04:53 +0200 Subject: [PATCH 2521/4206] `CommandExt::chroot`: Add tracking issue --- library/std/src/os/unix/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index 8d238aa583519..659b354483458 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -208,7 +208,7 @@ pub trait CommandExt: Sealed { /// If no directory has been specified with `Command::current_dir`, this will set the directory /// to `/`, to avoid leaving the current directory outside the chroot. (This is an intentional /// difference from the underlying `chroot` system call.) - #[unstable(feature = "process_chroot", issue = "none")] + #[unstable(feature = "process_chroot", issue = "141298")] fn chroot>(&mut self, dir: P) -> &mut process::Command; } From 097b7a2ac7d918ccd5158550f7f3440d7d4073e2 Mon Sep 17 00:00:00 2001 From: bohan Date: Mon, 12 May 2025 21:42:35 +0800 Subject: [PATCH 2522/4206] collect doc alias as tips during resolution --- Cargo.lock | 1 + .../rustc_attr_parsing/src/attributes/util.rs | 30 ++++ compiler/rustc_attr_parsing/src/lib.rs | 4 +- compiler/rustc_hir_typeck/Cargo.toml | 1 + compiler/rustc_hir_typeck/src/method/probe.rs | 37 +---- .../rustc_resolve/src/late/diagnostics.rs | 75 ++++++++- .../auxiliary/use-doc-alias-name-extern.rs | 24 +++ tests/ui/attributes/use-doc-alias-name.rs | 67 ++++++++ tests/ui/attributes/use-doc-alias-name.stderr | 150 ++++++++++++++++++ 9 files changed, 357 insertions(+), 32 deletions(-) create mode 100644 tests/ui/attributes/auxiliary/use-doc-alias-name-extern.rs create mode 100644 tests/ui/attributes/use-doc-alias-name.rs create mode 100644 tests/ui/attributes/use-doc-alias-name.stderr diff --git a/Cargo.lock b/Cargo.lock index e2b7b58c372ba..99cb71cd0ac87 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3809,6 +3809,7 @@ dependencies = [ "rustc_abi", "rustc_ast", "rustc_attr_data_structures", + "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs index 05a9029c59aa5..503d2f1fae168 100644 --- a/compiler/rustc_attr_parsing/src/attributes/util.rs +++ b/compiler/rustc_attr_parsing/src/attributes/util.rs @@ -26,3 +26,33 @@ pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool { pub fn find_crate_name(attrs: &[impl AttributeExt]) -> Option { first_attr_value_str_by_name(attrs, sym::crate_name) } + +pub fn is_doc_alias_attrs_contain_symbol<'tcx, T: AttributeExt + 'tcx>( + attrs: impl Iterator, + symbol: Symbol, +) -> bool { + let doc_attrs = attrs.filter(|attr| attr.has_name(sym::doc)); + for attr in doc_attrs { + let Some(values) = attr.meta_item_list() else { + continue; + }; + let alias_values = values.iter().filter(|v| v.has_name(sym::alias)); + for v in alias_values { + if let Some(nested) = v.meta_item_list() { + // #[doc(alias("foo", "bar"))] + let mut iter = nested.iter().filter_map(|item| item.lit()).map(|item| item.symbol); + if iter.any(|s| s == symbol) { + return true; + } + } else if let Some(meta) = v.meta_item() + && let Some(lit) = meta.name_value_literal() + { + // #[doc(alias = "foo")] + if lit.symbol == symbol { + return true; + } + } + } + } + false +} diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index da683ad58c134..63bccf5201827 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -90,7 +90,9 @@ pub mod parser; mod session_diagnostics; pub use attributes::cfg::*; -pub use attributes::util::{find_crate_name, is_builtin_attr, parse_version}; +pub use attributes::util::{ + find_crate_name, is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version, +}; pub use context::{AttributeParser, OmitDoc}; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml index 40fb2d6a106fa..c963f0ddefd4c 100644 --- a/compiler/rustc_hir_typeck/Cargo.toml +++ b/compiler/rustc_hir_typeck/Cargo.toml @@ -9,6 +9,7 @@ itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } +rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index bda051f156084..6090c0f9aee22 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -2,6 +2,7 @@ use std::cell::{Cell, RefCell}; use std::cmp::max; use std::ops::Deref; +use rustc_attr_parsing::is_doc_alias_attrs_contain_symbol; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sso::SsoHashSet; use rustc_errors::Applicability; @@ -2333,10 +2334,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }; let hir_id = self.fcx.tcx.local_def_id_to_hir_id(local_def_id); let attrs = self.fcx.tcx.hir_attrs(hir_id); + + if is_doc_alias_attrs_contain_symbol(attrs.into_iter(), method.name) { + return true; + } + for attr in attrs { - if attr.has_name(sym::doc) { - // do nothing - } else if attr.has_name(sym::rustc_confusables) { + if attr.has_name(sym::rustc_confusables) { let Some(confusables) = attr.meta_item_list() else { continue; }; @@ -2348,33 +2352,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { return true; } } - continue; - } else { - continue; - }; - let Some(values) = attr.meta_item_list() else { - continue; - }; - for v in values { - if !v.has_name(sym::alias) { - continue; - } - if let Some(nested) = v.meta_item_list() { - // #[doc(alias("foo", "bar"))] - for n in nested { - if let Some(lit) = n.lit() - && method.name == lit.symbol - { - return true; - } - } - } else if let Some(meta) = v.meta_item() - && let Some(lit) = meta.name_value_literal() - && method.name == lit.symbol - { - // #[doc(alias = "foo")] - return true; - } } } false diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index b538be34f31f1..6768907addee2 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -11,6 +11,7 @@ use rustc_ast::{ Item, ItemKind, MethodCall, NodeId, Path, PathSegment, Ty, TyKind, }; use rustc_ast_pretty::pprust::where_bound_predicate_to_string; +use rustc_attr_parsing::is_doc_alias_attrs_contain_symbol; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ @@ -39,7 +40,7 @@ use crate::late::{ }; use crate::ty::fast_reject::SimplifiedType; use crate::{ - Module, ModuleKind, ModuleOrUniformRoot, PathResult, PathSource, Segment, errors, + Module, ModuleKind, ModuleOrUniformRoot, PathResult, PathSource, Resolver, Segment, errors, path_names_to_string, }; @@ -477,6 +478,19 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { return (err, Vec::new()); } + if let Some((did, item)) = self.lookup_doc_alias_name(path, source.namespace()) { + let item_name = item.name; + let suggestion_name = self.r.tcx.item_name(did); + err.span_suggestion( + item.span, + format!("`{suggestion_name}` has a name defined in the doc alias attribute as `{item_name}`"), + suggestion_name, + Applicability::MaybeIncorrect + ); + + return (err, Vec::new()); + }; + let (found, suggested_candidates, mut candidates) = self.try_lookup_name_relaxed( &mut err, source, @@ -852,6 +866,65 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { (false, suggested_candidates, candidates) } + fn lookup_doc_alias_name(&mut self, path: &[Segment], ns: Namespace) -> Option<(DefId, Ident)> { + let find_doc_alias_name = |r: &mut Resolver<'ra, '_>, m: Module<'ra>, item_name: Symbol| { + for resolution in r.resolutions(m).borrow().values() { + let Some(did) = + resolution.borrow().binding.and_then(|binding| binding.res().opt_def_id()) + else { + continue; + }; + if did.is_local() { + // We don't record the doc alias name in the local crate + // because the people who write doc alias are usually not + // confused by them. + continue; + } + if is_doc_alias_attrs_contain_symbol(r.tcx.get_attrs(did, sym::doc), item_name) { + return Some(did); + } + } + None + }; + + if path.len() == 1 { + for rib in self.ribs[ns].iter().rev() { + let item = path[0].ident; + if let RibKind::Module(module) = rib.kind + && let Some(did) = find_doc_alias_name(self.r, module, item.name) + { + return Some((did, item)); + } + } + } else { + // Finds to the last resolved module item in the path + // and searches doc aliases within that module. + // + // Example: For the path `a::b::last_resolved::not_exist::c::d`, + // we will try to find any item has doc aliases named `not_exist` + // in `last_resolved` module. + // + // - Use `skip(1)` because the final segment must remain unresolved. + for (idx, seg) in path.iter().enumerate().rev().skip(1) { + let Some(id) = seg.id else { + continue; + }; + let Some(res) = self.r.partial_res_map.get(&id) else { + continue; + }; + if let Res::Def(DefKind::Mod, module) = res.expect_full_res() + && let Some(module) = self.r.get_module(module) + && let item = path[idx + 1].ident + && let Some(did) = find_doc_alias_name(self.r, module, item.name) + { + return Some((did, item)); + } + break; + } + } + None + } + fn suggest_trait_and_bounds( &mut self, err: &mut Diag<'_>, diff --git a/tests/ui/attributes/auxiliary/use-doc-alias-name-extern.rs b/tests/ui/attributes/auxiliary/use-doc-alias-name-extern.rs new file mode 100644 index 0000000000000..4c06d0fdfe390 --- /dev/null +++ b/tests/ui/attributes/auxiliary/use-doc-alias-name-extern.rs @@ -0,0 +1,24 @@ +#[doc(alias="DocAliasS1")] +pub struct S1; + +#[doc(alias="DocAliasS2")] +#[doc(alias("DocAliasS3", "DocAliasS4"))] +pub struct S2; + +#[doc(alias("doc_alias_f1", "doc_alias_f2"))] +pub fn f() {} + +pub mod m { + #[doc(alias="DocAliasS5")] + pub struct S5; + + pub mod n { + #[doc(alias("DocAliasX"))] + pub mod x { + pub mod y { + #[doc(alias="DocAliasS6")] + pub struct S6; + } + } + } +} diff --git a/tests/ui/attributes/use-doc-alias-name.rs b/tests/ui/attributes/use-doc-alias-name.rs new file mode 100644 index 0000000000000..1fc9199b6e382 --- /dev/null +++ b/tests/ui/attributes/use-doc-alias-name.rs @@ -0,0 +1,67 @@ +//@ aux-build: use-doc-alias-name-extern.rs + +// issue#124273 + +extern crate use_doc_alias_name_extern; + +use use_doc_alias_name_extern::*; + +#[doc(alias="LocalDocAliasS")] +struct S; + +fn main() { + LocalDocAliasS; // don't show help in local crate + //~^ ERROR: cannot find value `LocalDocAliasS` in this scope + + DocAliasS1; + //~^ ERROR: cannot find value `DocAliasS1` in this scope + //~| HELP: `S1` has a name defined in the doc alias attribute as `DocAliasS1` + + DocAliasS2; + //~^ ERROR: cannot find value `DocAliasS2` in this scope + //~| HELP: `S2` has a name defined in the doc alias attribute as `DocAliasS2` + + DocAliasS3; + //~^ ERROR: cannot find value `DocAliasS3` in this scope + //~| HELP: `S2` has a name defined in the doc alias attribute as `DocAliasS3` + + DocAliasS4; + //~^ ERROR: cannot find value `DocAliasS4` in this scope + //~| HELP: `S2` has a name defined in the doc alias attribute as `DocAliasS4` + + doc_alias_f1(); + //~^ ERROR: cannot find function `doc_alias_f1` in this scope + //~| HELP: `f` has a name defined in the doc alias attribute as `doc_alias_f1` + + doc_alias_f2(); + //~^ ERROR: cannot find function `doc_alias_f2` in this scope + //~| HELP: `f` has a name defined in the doc alias attribute as `doc_alias_f2` + + m::DocAliasS5; + //~^ ERROR: cannot find value `DocAliasS5` in module `m` + //~| HELP: `S5` has a name defined in the doc alias attribute as `DocAliasS5` + + not_exist_module::DocAliasS1; + //~^ ERROR: use of unresolved module or unlinked crate `not_exist_module` + //~| HELP: you might be missing a crate named `not_exist_module` + + use_doc_alias_name_extern::DocAliasS1; + //~^ ERROR: cannot find value `DocAliasS1` in crate `use_doc_alias_name_extern + //~| HELP: `S1` has a name defined in the doc alias attribute as `DocAliasS1` + + m::n::DocAliasX::y::S6; + //~^ ERROR: could not find `DocAliasX` in `n` + //~| HELP: `x` has a name defined in the doc alias attribute as `DocAliasX` + + m::n::x::y::DocAliasS6; + //~^ ERROR: cannot find value `DocAliasS6` in module `m::n::x::y` + //~| HELP: `S6` has a name defined in the doc alias attribute as `DocAliasS6` +} + +trait T { + fn f() { + DocAliasS1; + //~^ ERROR: cannot find value `DocAliasS1` in this scope + //~| HELP: `S1` has a name defined in the doc alias attribute as `DocAliasS1` + } +} diff --git a/tests/ui/attributes/use-doc-alias-name.stderr b/tests/ui/attributes/use-doc-alias-name.stderr new file mode 100644 index 0000000000000..07f4865e41520 --- /dev/null +++ b/tests/ui/attributes/use-doc-alias-name.stderr @@ -0,0 +1,150 @@ +error[E0433]: failed to resolve: could not find `DocAliasX` in `n` + --> $DIR/use-doc-alias-name.rs:52:11 + | +LL | m::n::DocAliasX::y::S6; + | ^^^^^^^^^ could not find `DocAliasX` in `n` + | +help: `x` has a name defined in the doc alias attribute as `DocAliasX` + | +LL - m::n::DocAliasX::y::S6; +LL + m::n::x::y::S6; + | + +error[E0425]: cannot find value `LocalDocAliasS` in this scope + --> $DIR/use-doc-alias-name.rs:13:5 + | +LL | LocalDocAliasS; // don't show help in local crate + | ^^^^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `DocAliasS1` in this scope + --> $DIR/use-doc-alias-name.rs:16:5 + | +LL | DocAliasS1; + | ^^^^^^^^^^ + | +help: `S1` has a name defined in the doc alias attribute as `DocAliasS1` + | +LL - DocAliasS1; +LL + S1; + | + +error[E0425]: cannot find value `DocAliasS2` in this scope + --> $DIR/use-doc-alias-name.rs:20:5 + | +LL | DocAliasS2; + | ^^^^^^^^^^ + | +help: `S2` has a name defined in the doc alias attribute as `DocAliasS2` + | +LL - DocAliasS2; +LL + S2; + | + +error[E0425]: cannot find value `DocAliasS3` in this scope + --> $DIR/use-doc-alias-name.rs:24:5 + | +LL | DocAliasS3; + | ^^^^^^^^^^ + | +help: `S2` has a name defined in the doc alias attribute as `DocAliasS3` + | +LL - DocAliasS3; +LL + S2; + | + +error[E0425]: cannot find value `DocAliasS4` in this scope + --> $DIR/use-doc-alias-name.rs:28:5 + | +LL | DocAliasS4; + | ^^^^^^^^^^ + | +help: `S2` has a name defined in the doc alias attribute as `DocAliasS4` + | +LL - DocAliasS4; +LL + S2; + | + +error[E0425]: cannot find value `DocAliasS5` in module `m` + --> $DIR/use-doc-alias-name.rs:40:8 + | +LL | m::DocAliasS5; + | ^^^^^^^^^^ + | +help: `S5` has a name defined in the doc alias attribute as `DocAliasS5` + | +LL - m::DocAliasS5; +LL + m::S5; + | + +error[E0425]: cannot find value `DocAliasS1` in crate `use_doc_alias_name_extern` + --> $DIR/use-doc-alias-name.rs:48:32 + | +LL | use_doc_alias_name_extern::DocAliasS1; + | ^^^^^^^^^^ + | +help: `S1` has a name defined in the doc alias attribute as `DocAliasS1` + | +LL - use_doc_alias_name_extern::DocAliasS1; +LL + use_doc_alias_name_extern::S1; + | + +error[E0425]: cannot find value `DocAliasS6` in module `m::n::x::y` + --> $DIR/use-doc-alias-name.rs:56:17 + | +LL | m::n::x::y::DocAliasS6; + | ^^^^^^^^^^ + | +help: `S6` has a name defined in the doc alias attribute as `DocAliasS6` + | +LL - m::n::x::y::DocAliasS6; +LL + m::n::x::y::S6; + | + +error[E0425]: cannot find value `DocAliasS1` in this scope + --> $DIR/use-doc-alias-name.rs:63:9 + | +LL | DocAliasS1; + | ^^^^^^^^^^ + | +help: `S1` has a name defined in the doc alias attribute as `DocAliasS1` + | +LL - DocAliasS1; +LL + S1; + | + +error[E0425]: cannot find function `doc_alias_f1` in this scope + --> $DIR/use-doc-alias-name.rs:32:5 + | +LL | doc_alias_f1(); + | ^^^^^^^^^^^^ + | +help: `f` has a name defined in the doc alias attribute as `doc_alias_f1` + | +LL - doc_alias_f1(); +LL + f(); + | + +error[E0425]: cannot find function `doc_alias_f2` in this scope + --> $DIR/use-doc-alias-name.rs:36:5 + | +LL | doc_alias_f2(); + | ^^^^^^^^^^^^ + | +help: `f` has a name defined in the doc alias attribute as `doc_alias_f2` + | +LL - doc_alias_f2(); +LL + f(); + | + +error[E0433]: failed to resolve: use of unresolved module or unlinked crate `not_exist_module` + --> $DIR/use-doc-alias-name.rs:44:5 + | +LL | not_exist_module::DocAliasS1; + | ^^^^^^^^^^^^^^^^ use of unresolved module or unlinked crate `not_exist_module` + | + = help: you might be missing a crate named `not_exist_module` + +error: aborting due to 13 previous errors + +Some errors have detailed explanations: E0425, E0433. +For more information about an error, try `rustc --explain E0425`. From b8732aaa4d5af1c5a287e2baac38dc1e4d41c56e Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 20 May 2025 20:03:17 +0200 Subject: [PATCH 2523/4206] Fix pagetoc inactive color in rustc book --- src/doc/rustc/theme/pagetoc.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/theme/pagetoc.css b/src/doc/rustc/theme/pagetoc.css index 58ca1f8b26f81..fa709194f3755 100644 --- a/src/doc/rustc/theme/pagetoc.css +++ b/src/doc/rustc/theme/pagetoc.css @@ -49,7 +49,7 @@ } #pagetoc a { border-left: 1px solid var(--sidebar-bg); - color: var(--sidebar-fg) !important; + color: var(--fg); display: block; padding-bottom: 5px; padding-top: 5px; From a822e557cd19efa0dcf62ae3e7af6b6310fa2f5c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 May 2025 12:01:03 +1000 Subject: [PATCH 2524/4206] Remove an unnecessary lifetime. --- compiler/rustc_attr_parsing/src/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index a5c3cec3bdd40..a9eb0a5188821 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -549,7 +549,7 @@ impl<'a> MetaItemListParser<'a> { } /// Lets you pick and choose as what you want to parse each element in the list - pub fn mixed<'s>(&'s self) -> impl Iterator> + 's { + pub fn mixed(&self) -> impl Iterator> { self.sub_parsers.iter() } From ea3b3fdcc155fb0cd758392b68b1859cf9a435b4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 May 2025 12:08:00 +1000 Subject: [PATCH 2525/4206] Remove `MetaItemParser::{word,word_without_args,path_is}`. They are unused. --- compiler/rustc_attr_parsing/src/parser.rs | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index a9eb0a5188821..8366f163a684d 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -276,38 +276,15 @@ impl<'a> MetaItemParser<'a> { self.deconstruct() } - /// Asserts that this MetaItem starts with a word, or single segment path. - /// Doesn't return the args parser. - /// - /// For examples. see [`Self::word`] - pub fn word_without_args(&self) -> Option { - Some(self.word()?.0) - } - /// Asserts that this MetaItem starts with a word, or single segment path. /// /// Some examples: /// - `#[inline]`: `inline` is a word /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path, /// and not a word and should instead be parsed using [`path`](Self::path) - pub fn word(&self) -> Option<(Ident, &ArgParser<'a>)> { - let (path, args) = self.deconstruct(); - Some((path.word()?, args)) - } - - /// Asserts that this MetaItem starts with some specific word. - /// - /// See [`word`](Self::word) for examples of what a word is. pub fn word_is(&self, sym: Symbol) -> Option<&ArgParser<'a>> { self.path_without_args().word_is(sym).then(|| self.args()) } - - /// Asserts that this MetaItem starts with some specific path. - /// - /// See [`word`](Self::path) for examples of what a word is. - pub fn path_is(&self, segments: &[Symbol]) -> Option<&ArgParser<'a>> { - self.path_without_args().segments_is(segments).then(|| self.args()) - } } #[derive(Clone)] From 2cd2d249673b316bb4a15c10c6a1113b2bee02db Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 May 2025 11:57:21 +1000 Subject: [PATCH 2526/4206] Remove `MetaItemParser::{path,deconstruct}`. They're equivalent, and `path` is unused, and `deconstruct` has only one call site outside of `path`. --- compiler/rustc_attr_parsing/src/context.rs | 3 ++- compiler/rustc_attr_parsing/src/parser.rs | 19 +++++-------------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 55c3df003fe16..820c70edebf8d 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -260,7 +260,8 @@ impl<'sess> AttributeParser<'sess> { // } ast::AttrKind::Normal(n) => { let parser = MetaItemParser::from_attr(n, self.dcx()); - let (path, args) = parser.deconstruct(); + let path = parser.path_without_args(); + let args = parser.args(); let parts = path.segments().map(|i| i.name).collect::>(); if let Some(accepts) = ATTRIBUTE_MAPPING.0.get(parts.as_slice()) { diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 8366f163a684d..30d8aa0272095 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -253,7 +253,11 @@ impl<'a> MetaItemParser<'a> { } } - /// Gets just the path, without the args. + /// Gets just the path, without the args. Some examples: + /// + /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path + /// - `#[allow(clippy::complexity)]`: `clippy::complexity` is a path + /// - `#[inline]`: `inline` is a single segment path pub fn path_without_args(&self) -> PathParser<'a> { self.path.clone() } @@ -263,19 +267,6 @@ impl<'a> MetaItemParser<'a> { &self.args } - pub fn deconstruct(&self) -> (PathParser<'a>, &ArgParser<'a>) { - (self.path_without_args(), self.args()) - } - - /// Asserts that this MetaItem starts with a path. Some examples: - /// - /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path - /// - `#[allow(clippy::complexity)]`: `clippy::complexity` is a path - /// - `#[inline]`: `inline` is a single segment path - pub fn path(&self) -> (PathParser<'a>, &ArgParser<'a>) { - self.deconstruct() - } - /// Asserts that this MetaItem starts with a word, or single segment path. /// /// Some examples: From e5c78de85c01e576671f9ba0c880520baf0d938d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 May 2025 12:41:56 +1000 Subject: [PATCH 2527/4206] Rename `MetaItemParser::path_without_args` as `MetaItemParser::path`. And avoid the clone. --- .../src/attributes/allow_unstable.rs | 2 +- .../rustc_attr_parsing/src/attributes/deprecation.rs | 4 ++-- compiler/rustc_attr_parsing/src/attributes/repr.rs | 2 +- .../rustc_attr_parsing/src/attributes/stability.rs | 10 +++++----- compiler/rustc_attr_parsing/src/context.rs | 2 +- compiler/rustc_attr_parsing/src/parser.rs | 6 +++--- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index c1d95d07f4c65..8460a4a412279 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -53,7 +53,7 @@ fn parse_unstable<'a>( for param in list.mixed() { let param_span = param.span(); - if let Some(ident) = param.meta_item().and_then(|i| i.path_without_args().word()) { + if let Some(ident) = param.meta_item().and_then(|i| i.path().word()) { res.push(ident.name); } else { cx.emit_err(session_diagnostics::ExpectsFeatures { diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index fb3d5f57d4fac..5e94261f1c49a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -79,7 +79,7 @@ impl SingleAttributeParser for DeprecationParser { return None; }; - let ident_name = param.path_without_args().word_sym(); + let ident_name = param.path().word_sym(); match ident_name { Some(name @ sym::since) => { @@ -102,7 +102,7 @@ impl SingleAttributeParser for DeprecationParser { _ => { cx.emit_err(session_diagnostics::UnknownMetaItem { span: param_span, - item: param.path_without_args().to_string(), + item: param.path().to_string(), expected: if features.deprecated_suggestion() { &["since", "note", "suggestion"] } else { diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 43dfb85a7c411..97c865230f2d0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -96,7 +96,7 @@ fn parse_repr(cx: &AcceptContext<'_>, param: &MetaItemParser<'_>) -> Option insert_value_into_option_or_error(cx, ¶m, &mut feature)?, Some(sym::since) => insert_value_into_option_or_error(cx, ¶m, &mut since)?, _ => { cx.emit_err(session_diagnostics::UnknownMetaItem { span: param_span, - item: param.path_without_args().to_string(), + item: param.path().to_string(), expected: &["feature", "since"], }); return None; @@ -310,7 +310,7 @@ pub(crate) fn parse_unstability( return None; }; - match param.path_without_args().word_sym() { + match param.path().word_sym() { Some(sym::feature) => insert_value_into_option_or_error(cx, ¶m, &mut feature)?, Some(sym::reason) => insert_value_into_option_or_error(cx, ¶m, &mut reason)?, Some(sym::issue) => { @@ -349,7 +349,7 @@ pub(crate) fn parse_unstability( _ => { cx.emit_err(session_diagnostics::UnknownMetaItem { span: param.span(), - item: param.path_without_args().to_string(), + item: param.path().to_string(), expected: &["feature", "reason", "issue", "soft", "implied_by"], }); return None; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 820c70edebf8d..c101785491665 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -260,7 +260,7 @@ impl<'sess> AttributeParser<'sess> { // } ast::AttrKind::Normal(n) => { let parser = MetaItemParser::from_attr(n, self.dcx()); - let path = parser.path_without_args(); + let path = parser.path(); let args = parser.args(); let parts = path.segments().map(|i| i.name).collect::>(); diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 30d8aa0272095..7e89f6c6a2e9a 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -258,8 +258,8 @@ impl<'a> MetaItemParser<'a> { /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path /// - `#[allow(clippy::complexity)]`: `clippy::complexity` is a path /// - `#[inline]`: `inline` is a single segment path - pub fn path_without_args(&self) -> PathParser<'a> { - self.path.clone() + pub fn path(&self) -> &PathParser<'a> { + &self.path } /// Gets just the args parser, without caring about the path. @@ -274,7 +274,7 @@ impl<'a> MetaItemParser<'a> { /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path, /// and not a word and should instead be parsed using [`path`](Self::path) pub fn word_is(&self, sym: Symbol) -> Option<&ArgParser<'a>> { - self.path_without_args().word_is(sym).then(|| self.args()) + self.path().word_is(sym).then(|| self.args()) } } From 66d47c16873fc04a02cb0bd977ec7f3d50f228f1 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 20 May 2025 16:55:09 -0300 Subject: [PATCH 2528/4206] Do not call name() on rpitit assoc_item --- .../src/error_reporting/traits/suggestions.rs | 23 +++++++++++-------- .../in-trait/not-inferred-generic.rs} | 2 +- .../in-trait/not-inferred-generic.stderr | 21 +++++++++++++++++ 3 files changed, 35 insertions(+), 11 deletions(-) rename tests/{crashes/141143.rs => ui/impl-trait/in-trait/not-inferred-generic.rs} (81%) create mode 100644 tests/ui/impl-trait/in-trait/not-inferred-generic.stderr 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 8801397b77541..6863857f9ecb8 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -2124,16 +2124,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { accessed through a specific `impl`", self.tcx.def_kind_descr(assoc_item.as_def_kind(), item_def_id) )); - err.span_suggestion( - span, - "use the fully qualified path to an implementation", - format!( - "::{}", - self.tcx.def_path_str(trait_ref), - assoc_item.name() - ), - Applicability::HasPlaceholders, - ); + + if !assoc_item.is_impl_trait_in_trait() { + err.span_suggestion( + span, + "use the fully qualified path to an implementation", + format!( + "::{}", + self.tcx.def_path_str(trait_ref), + assoc_item.name() + ), + Applicability::HasPlaceholders, + ); + } } } } diff --git a/tests/crashes/141143.rs b/tests/ui/impl-trait/in-trait/not-inferred-generic.rs similarity index 81% rename from tests/crashes/141143.rs rename to tests/ui/impl-trait/in-trait/not-inferred-generic.rs index a4aa2f19a6c75..3879ea0e62628 100644 --- a/tests/crashes/141143.rs +++ b/tests/ui/impl-trait/in-trait/not-inferred-generic.rs @@ -1,4 +1,3 @@ -//@ known-bug: #141143 trait TypedClient { fn publish_typed(&self) -> impl Sized where @@ -10,4 +9,5 @@ impl TypedClient for () { fn main() { ().publish_typed(); + //~^ ERROR type annotations needed [E0283] } diff --git a/tests/ui/impl-trait/in-trait/not-inferred-generic.stderr b/tests/ui/impl-trait/in-trait/not-inferred-generic.stderr new file mode 100644 index 0000000000000..07f029d3bb7dc --- /dev/null +++ b/tests/ui/impl-trait/in-trait/not-inferred-generic.stderr @@ -0,0 +1,21 @@ +error[E0283]: type annotations needed + --> $DIR/not-inferred-generic.rs:11:8 + | +LL | ().publish_typed(); + | ^^^^^^^^^^^^^ cannot infer type of the type parameter `F` declared on the method `publish_typed` + | + = note: cannot satisfy `_: Clone` + = note: associated types cannot be accessed directly on a `trait`, they can only be accessed through a specific `impl` +note: required by a bound in `TypedClient::publish_typed::{anon_assoc#0}` + --> $DIR/not-inferred-generic.rs:4:12 + | +LL | F: Clone; + | ^^^^^ required by this bound in `TypedClient::publish_typed::{anon_assoc#0}` +help: consider specifying the generic argument + | +LL | ().publish_typed::(); + | +++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. From 9d1cf125f8ba4e509d5eacc2193b6b2c0999f9e1 Mon Sep 17 00:00:00 2001 From: Mathis Bottinelli Date: Sun, 18 May 2025 13:46:42 +0200 Subject: [PATCH 2529/4206] Implement `ptr::try_cast_aligned` and `NonNull::try_cast_aligned`. --- library/core/src/ptr/const_ptr.rs | 28 ++++++++++++++++++++++++++++ library/core/src/ptr/mut_ptr.rs | 28 ++++++++++++++++++++++++++++ library/core/src/ptr/non_null.rs | 29 +++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 35089b4853d7f..f6109cafe86b1 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -66,6 +66,34 @@ impl *const T { self as _ } + /// Try to cast to a pointer of another type by checking aligment. + /// + /// If the pointer is properly aligned to the target type, it will be + /// cast to the target type. Otherwise, `None` is returned. + /// + /// # Examples + /// + /// ```rust + /// #![feature(pointer_try_cast_aligned)] + /// + /// let aligned: *const u8 = 0x1000 as _; + /// + /// // i32 has at most 4-byte alignment, so this will succeed + /// assert!(aligned.try_cast_aligned::().is_some()); + /// + /// let unaligned: *const u8 = 0x1001 as _; + /// + /// // i32 has at least 2-byte alignment, so this will fail + /// assert!(unaligned.try_cast_aligned::().is_none()); + /// ``` + #[unstable(feature = "pointer_try_cast_aligned", issue = "141221")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub fn try_cast_aligned(self) -> Option<*const U> { + if self.is_aligned_to(align_of::()) { Some(self.cast()) } else { None } + } + /// Uses the address value in a new pointer of another type. /// /// This operation will ignore the address part of its `meta` operand and discard existing diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 9cf251742d427..2662a4fdc3138 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -48,6 +48,34 @@ impl *mut T { self as _ } + /// Try to cast to a pointer of another type by checking aligment. + /// + /// If the pointer is properly aligned to the target type, it will be + /// cast to the target type. Otherwise, `None` is returned. + /// + /// # Examples + /// + /// ```rust + /// #![feature(pointer_try_cast_aligned)] + /// + /// let aligned: *mut u8 = 0x1000 as _; + /// + /// // i32 has at most 4-byte alignment, so this will succeed + /// assert!(aligned.try_cast_aligned::().is_some()); + /// + /// let unaligned: *mut u8 = 0x1001 as _; + /// + /// // i32 has at least 2-byte alignment, so this will fail + /// assert!(unaligned.try_cast_aligned::().is_none()); + /// ``` + #[unstable(feature = "pointer_try_cast_aligned", issue = "141221")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub fn try_cast_aligned(self) -> Option<*mut U> { + if self.is_aligned_to(align_of::()) { Some(self.cast()) } else { None } + } + /// Uses the address value in a new pointer of another type. /// /// This operation will ignore the address part of its `meta` operand and discard existing diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 8b31328de047f..bb344c6a0d316 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -490,6 +490,35 @@ impl NonNull { unsafe { NonNull { pointer: self.as_ptr() as *mut U } } } + /// Try to cast to a pointer of another type by checking aligment. + /// + /// If the pointer is properly aligned to the target type, it will be + /// cast to the target type. Otherwise, `None` is returned. + /// + /// # Examples + /// + /// ```rust + /// #![feature(pointer_try_cast_aligned)] + /// use std::ptr::NonNull; + /// + /// let aligned: NonNull = NonNull::new(0x1000 as _).unwrap(); + /// + /// // i32 has at most 4-byte alignment, so this will succeed + /// assert!(aligned.try_cast_aligned::().is_some()); + /// + /// let unaligned: NonNull = NonNull::new(0x1001 as _).unwrap(); + /// + /// // i32 has at least 2-byte alignment, so this will fail + /// assert!(unaligned.try_cast_aligned::().is_none()); + /// ``` + #[unstable(feature = "pointer_try_cast_aligned", issue = "141221")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub fn try_cast_aligned(self) -> Option> { + if self.is_aligned_to(align_of::()) { Some(self.cast()) } else { None } + } + /// Adds an offset to a pointer. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer From 9febbf827088cc8e94b2799e6c5976997bb88c65 Mon Sep 17 00:00:00 2001 From: Christopher Berner Date: Tue, 6 May 2025 20:18:06 -0700 Subject: [PATCH 2530/4206] Remove unnecessary handling of ERROR_IO_PENDING try_lock() and try_lock_shared() do not need to handle these per the discussion in https://github.com/rust-lang/rust/pull/140718#discussion_r2076678485 --- library/std/src/fs/tests.rs | 22 ++++++++++++++++++++++ library/std/src/sys/fs/windows.rs | 10 ++-------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 46b0d832fec45..49f99351c8aaf 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -366,6 +366,28 @@ fn file_lock_blocking_async() { t.join().unwrap(); } +#[test] +#[cfg(windows)] +fn file_try_lock_async() { + const FILE_FLAG_OVERLAPPED: u32 = 0x40000000; + + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_try_lock_async.txt"); + let f1 = check!(File::create(filename)); + let f2 = + check!(OpenOptions::new().custom_flags(FILE_FLAG_OVERLAPPED).write(true).open(filename)); + + // Check that shared locks block exclusive locks + check!(f1.lock_shared()); + assert_matches!(f2.try_lock(), Err(TryLockError::WouldBlock)); + check!(f1.unlock()); + + // Check that exclusive locks block all locks + check!(f1.lock()); + assert_matches!(f2.try_lock(), Err(TryLockError::WouldBlock)); + assert_matches!(f2.try_lock_shared(), Err(TryLockError::WouldBlock)); +} + #[test] fn file_test_io_seek_shakedown() { // 01234567890123 diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index 9039fd00f5d62..d01a572ac7332 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -415,10 +415,7 @@ impl File { match result { Ok(_) => Ok(()), - Err(err) - if err.raw_os_error() == Some(c::ERROR_IO_PENDING as i32) - || err.raw_os_error() == Some(c::ERROR_LOCK_VIOLATION as i32) => - { + Err(err) if err.raw_os_error() == Some(c::ERROR_LOCK_VIOLATION as i32) => { Err(TryLockError::WouldBlock) } Err(err) => Err(TryLockError::Error(err)), @@ -440,10 +437,7 @@ impl File { match result { Ok(_) => Ok(()), - Err(err) - if err.raw_os_error() == Some(c::ERROR_IO_PENDING as i32) - || err.raw_os_error() == Some(c::ERROR_LOCK_VIOLATION as i32) => - { + Err(err) if err.raw_os_error() == Some(c::ERROR_LOCK_VIOLATION as i32) => { Err(TryLockError::WouldBlock) } Err(err) => Err(TryLockError::Error(err)), From fd260d530b880c44874340eaf2e31666a138a874 Mon Sep 17 00:00:00 2001 From: Christopher Berner Date: Tue, 20 May 2025 14:04:38 -0700 Subject: [PATCH 2531/4206] Add From for io::Error This makes error propagation from try_lock() and try_lock_shared() more convenient --- library/std/src/fs.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 11f439b9996de..4be52ac1eb386 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -392,6 +392,16 @@ impl fmt::Display for TryLockError { } } +#[unstable(feature = "file_lock", issue = "130994")] +impl From for io::Error { + fn from(err: TryLockError) -> io::Error { + match err { + TryLockError::Error(err) => err, + TryLockError::WouldBlock => io::ErrorKind::WouldBlock.into(), + } + } +} + impl File { /// Attempts to open a file in read-only mode. /// @@ -821,11 +831,14 @@ impl File { /// /// fn main() -> std::io::Result<()> { /// let f = File::create("foo.txt")?; + /// // Explicit handling of the WouldBlock error /// match f.try_lock() { /// Ok(_) => (), /// Err(TryLockError::WouldBlock) => (), // Lock not acquired /// Err(TryLockError::Error(err)) => return Err(err), /// } + /// // Alternately, propagate the error as an io::Error + /// f.try_lock()?; /// Ok(()) /// } /// ``` @@ -882,11 +895,14 @@ impl File { /// /// fn main() -> std::io::Result<()> { /// let f = File::open("foo.txt")?; + /// // Explicit handling of the WouldBlock error /// match f.try_lock_shared() { /// Ok(_) => (), /// Err(TryLockError::WouldBlock) => (), // Lock not acquired /// Err(TryLockError::Error(err)) => return Err(err), /// } + /// // Alternately, propagate the error as an io::Error + /// f.try_lock_shared()?; /// /// Ok(()) /// } From 999967a57dce987bbad353d152f03c3ef67d41f2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 18 Feb 2025 00:27:30 +0000 Subject: [PATCH 2532/4206] Rename `cfg_match!` to `cfg_select!` At [1] it was pointed out that `cfg_match!` syntax does not actually align well with match syntax, which is a possible source of confusion. The comment points out that usage is instead more similar to ecosystem `select!` macros. Rename `cfg_match!` to `cfg_select!` to match this. Tracking issue: https://github.com/rust-lang/rust/issues/115585 [1]: https://github.com/rust-lang/rust/issues/115585#issuecomment-2346307605 --- ...sroot_tests-128bit-atomic-operations.patch | 2 +- compiler/rustc_data_structures/src/flock.rs | 2 +- compiler/rustc_data_structures/src/lib.rs | 2 +- .../rustc_data_structures/src/profiling.rs | 2 +- .../rustc_span/src/analyze_source_file.rs | 2 +- compiler/rustc_span/src/lib.rs | 2 +- library/core/src/ffi/primitives.rs | 6 +-- library/core/src/lib.rs | 6 +-- library/core/src/macros/mod.rs | 20 ++++----- library/core/src/num/f32.rs | 4 +- library/core/src/slice/sort/select.rs | 4 +- library/core/src/slice/sort/stable/mod.rs | 6 +-- library/core/src/slice/sort/unstable/mod.rs | 4 +- .../core/src/slice/sort/unstable/quicksort.rs | 4 +- library/coretests/tests/lib.rs | 2 +- library/coretests/tests/macros.rs | 42 +++++++++---------- library/std/src/lib.rs | 4 +- src/tools/miri/src/concurrency/mod.rs | 2 +- src/tools/miri/src/lib.rs | 2 +- src/tools/miri/src/shims/unix/fs.rs | 2 +- 20 files changed, 60 insertions(+), 60 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/patches/0027-sysroot_tests-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-sysroot_tests-128bit-atomic-operations.patch index 16c8488acdb56..f6e6bbc2387c2 100644 --- a/compiler/rustc_codegen_cranelift/patches/0027-sysroot_tests-128bit-atomic-operations.patch +++ b/compiler/rustc_codegen_cranelift/patches/0027-sysroot_tests-128bit-atomic-operations.patch @@ -17,7 +17,7 @@ index 1e336bf..35e6f54 100644 @@ -2,5 +2,4 @@ // tidy-alphabetical-start -#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] - #![cfg_attr(test, feature(cfg_match))] + #![cfg_attr(test, feature(cfg_select))] #![feature(alloc_layout_extra)] #![feature(array_chunks)] diff --git a/coretests/tests/atomic.rs b/coretests/tests/atomic.rs diff --git a/compiler/rustc_data_structures/src/flock.rs b/compiler/rustc_data_structures/src/flock.rs index d423d8acefd0a..f33f6b7cac1ac 100644 --- a/compiler/rustc_data_structures/src/flock.rs +++ b/compiler/rustc_data_structures/src/flock.rs @@ -4,7 +4,7 @@ //! green/native threading. This is just a bare-bones enough solution for //! librustdoc, it is not production quality at all. -cfg_match! { +cfg_select! { target_os = "linux" => { mod linux; use linux as imp; diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 865424fd6bbdc..b34a7fdb9e415 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -19,7 +19,7 @@ #![feature(ascii_char_variants)] #![feature(assert_matches)] #![feature(auto_traits)] -#![feature(cfg_match)] +#![feature(cfg_select)] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(extend_one)] diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index 60f007083baf3..36649a3607070 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -860,7 +860,7 @@ fn get_thread_id() -> u32 { } // Memory reporting -cfg_match! { +cfg_select! { windows => { pub fn get_resident_set_size() -> Option { use windows::{ diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs index 6384fa06c21b0..c32593a6d95ab 100644 --- a/compiler/rustc_span/src/analyze_source_file.rs +++ b/compiler/rustc_span/src/analyze_source_file.rs @@ -29,7 +29,7 @@ pub(crate) fn analyze_source_file(src: &str) -> (Vec, Vec { fn analyze_source_file_dispatch( src: &str, diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 22ca8accf9fde..906462a0d229d 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -20,7 +20,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] -#![feature(cfg_match)] +#![feature(cfg_select)] #![feature(core_io_borrowed_buf)] #![feature(hash_set_entry)] #![feature(if_let_guard)] diff --git a/library/core/src/ffi/primitives.rs b/library/core/src/ffi/primitives.rs index 351bf9f831476..fa23cf33af431 100644 --- a/library/core/src/ffi/primitives.rs +++ b/library/core/src/ffi/primitives.rs @@ -35,7 +35,7 @@ type_alias! { "c_float.md", c_float = f32; } type_alias! { "c_double.md", c_double = f64; } mod c_char_definition { - crate::cfg_match! { + crate::cfg_select! { // These are the targets on which c_char is unsigned. Usually the // signedness is the same for all target_os values on a given architecture // but there are some exceptions (see isSignedCharDefault() in clang). @@ -133,7 +133,7 @@ mod c_char_definition { } mod c_long_definition { - crate::cfg_match! { + crate::cfg_select! { any( all(target_pointer_width = "64", not(windows)), // wasm32 Linux ABI uses 64-bit long @@ -172,7 +172,7 @@ pub type c_ptrdiff_t = isize; pub type c_ssize_t = isize; mod c_int_definition { - crate::cfg_match! { + crate::cfg_select! { any(target_arch = "avr", target_arch = "msp430") => { pub(super) type c_int = i16; pub(super) type c_uint = u16; diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index e605d7e0d7844..b76213fdd41d3 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -100,7 +100,7 @@ #![feature(bigint_helper_methods)] #![feature(bstr)] #![feature(bstr_internals)] -#![feature(cfg_match)] +#![feature(cfg_select)] #![feature(cfg_target_has_reliable_f16_f128)] #![feature(const_carrying_mul_add)] #![feature(const_eval_select)] @@ -235,8 +235,8 @@ pub mod autodiff { #[unstable(feature = "contracts", issue = "128044")] pub mod contracts; -#[unstable(feature = "cfg_match", issue = "115585")] -pub use crate::macros::cfg_match; +#[unstable(feature = "cfg_select", issue = "115585")] +pub use crate::macros::cfg_select; #[macro_use] mod internal_macros; diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 7dc8c060cd5bc..4742add095771 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -210,9 +210,9 @@ pub macro assert_matches { /// # Example /// /// ``` -/// #![feature(cfg_match)] +/// #![feature(cfg_select)] /// -/// cfg_match! { +/// cfg_select! { /// unix => { /// fn foo() { /* unix specific functionality */ } /// } @@ -228,19 +228,19 @@ pub macro assert_matches { /// If desired, it is possible to return expressions through the use of surrounding braces: /// /// ``` -/// #![feature(cfg_match)] +/// #![feature(cfg_select)] /// -/// let _some_string = cfg_match! {{ +/// let _some_string = cfg_select! {{ /// unix => { "With great power comes great electricity bills" } /// _ => { "Behind every successful diet is an unwatched pizza" } /// }}; /// ``` -#[unstable(feature = "cfg_match", issue = "115585")] -#[rustc_diagnostic_item = "cfg_match"] +#[unstable(feature = "cfg_select", issue = "115585")] +#[rustc_diagnostic_item = "cfg_select"] #[rustc_macro_transparency = "semitransparent"] -pub macro cfg_match { +pub macro cfg_select { ({ $($tt:tt)* }) => {{ - $crate::cfg_match! { $($tt)* } + $crate::cfg_select! { $($tt)* } }}, (_ => { $($output:tt)* }) => { $($output)* @@ -250,10 +250,10 @@ pub macro cfg_match { $($( $rest:tt )+)? ) => { #[cfg($cfg)] - $crate::cfg_match! { _ => $output } + $crate::cfg_select! { _ => $output } $( #[cfg(not($cfg))] - $crate::cfg_match! { $($rest)+ } + $crate::cfg_select! { $($rest)+ } )? }, } diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 9525bdb6762a2..a865078b1420f 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -14,7 +14,7 @@ use crate::convert::FloatToInt; use crate::num::{FpCategory, libm}; use crate::panic::const_assert; -use crate::{cfg_match, intrinsics, mem}; +use crate::{cfg_select, intrinsics, mem}; /// The radix or base of the internal representation of `f32`. /// Use [`f32::RADIX`] instead. @@ -990,7 +990,7 @@ impl f32 { #[stable(feature = "num_midpoint", since = "1.85.0")] #[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")] pub const fn midpoint(self, other: f32) -> f32 { - cfg_match! { + cfg_select! { // Allow faster implementation that have known good 64-bit float // implementations. Falling back to the branchy code on targets that don't // have 64-bit hardware floats or buggy implementations. diff --git a/library/core/src/slice/sort/select.rs b/library/core/src/slice/sort/select.rs index c4808b1065d07..82194db7fd86b 100644 --- a/library/core/src/slice/sort/select.rs +++ b/library/core/src/slice/sort/select.rs @@ -6,7 +6,7 @@ //! for pivot selection. Using this as a fallback ensures O(n) worst case running time with //! better performance than one would get using heapsort as fallback. -use crate::cfg_match; +use crate::cfg_select; use crate::mem::{self, SizedTypeProperties}; #[cfg(not(feature = "optimize_for_size"))] use crate::slice::sort::shared::pivot::choose_pivot; @@ -42,7 +42,7 @@ where let min_idx = min_index(v, &mut is_less).unwrap(); v.swap(min_idx, index); } else { - cfg_match! { + cfg_select! { feature = "optimize_for_size" => { median_of_medians(v, &mut is_less, index); } diff --git a/library/core/src/slice/sort/stable/mod.rs b/library/core/src/slice/sort/stable/mod.rs index a36e5f7801d49..8b4e5c0c8c3a1 100644 --- a/library/core/src/slice/sort/stable/mod.rs +++ b/library/core/src/slice/sort/stable/mod.rs @@ -7,7 +7,7 @@ use crate::mem::{MaybeUninit, SizedTypeProperties}; use crate::slice::sort::shared::smallsort::{ SMALL_SORT_GENERAL_SCRATCH_LEN, StableSmallSortTypeImpl, insertion_sort_shift_left, }; -use crate::{cfg_match, intrinsics}; +use crate::{cfg_select, intrinsics}; pub(crate) mod merge; @@ -39,13 +39,13 @@ pub fn sort bool, BufT: BufGuard>(v: &mut [T], is_less return; } - cfg_match! { + cfg_select! { any(feature = "optimize_for_size", target_pointer_width = "16") => { // Unlike driftsort, mergesort only requires len / 2, // not len - len / 2. let alloc_len = len / 2; - cfg_match! { + cfg_select! { target_pointer_width = "16" => { let mut heap_buf = BufT::with_capacity(alloc_len); let scratch = heap_buf.as_uninit_slice_mut(); diff --git a/library/core/src/slice/sort/unstable/mod.rs b/library/core/src/slice/sort/unstable/mod.rs index b6c2e05a06a0e..d4df8d3a264db 100644 --- a/library/core/src/slice/sort/unstable/mod.rs +++ b/library/core/src/slice/sort/unstable/mod.rs @@ -5,7 +5,7 @@ use crate::mem::SizedTypeProperties; use crate::slice::sort::shared::find_existing_run; #[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] use crate::slice::sort::shared::smallsort::insertion_sort_shift_left; -use crate::{cfg_match, intrinsics}; +use crate::{cfg_select, intrinsics}; pub(crate) mod heapsort; pub(crate) mod quicksort; @@ -30,7 +30,7 @@ pub fn sort bool>(v: &mut [T], is_less: &mut F) { return; } - cfg_match! { + cfg_select! { any(feature = "optimize_for_size", target_pointer_width = "16") => { heapsort::heapsort(v, is_less); } diff --git a/library/core/src/slice/sort/unstable/quicksort.rs b/library/core/src/slice/sort/unstable/quicksort.rs index 7e6cfb5599050..98efee242ebae 100644 --- a/library/core/src/slice/sort/unstable/quicksort.rs +++ b/library/core/src/slice/sort/unstable/quicksort.rs @@ -9,7 +9,7 @@ use crate::slice::sort::shared::pivot::choose_pivot; use crate::slice::sort::shared::smallsort::UnstableSmallSortTypeImpl; #[cfg(not(feature = "optimize_for_size"))] use crate::slice::sort::unstable::heapsort; -use crate::{cfg_match, intrinsics, ptr}; +use crate::{cfg_select, intrinsics, ptr}; /// Sorts `v` recursively. /// @@ -142,7 +142,7 @@ const fn inst_partition bool>() -> fn(&mut [T], &T, &mut if size_of::() <= MAX_BRANCHLESS_PARTITION_SIZE { // Specialize for types that are relatively cheap to copy, where branchless optimizations // have large leverage e.g. `u64` and `String`. - cfg_match! { + cfg_select! { feature = "optimize_for_size" => { partition_lomuto_branchless_simple:: } diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index b98e52718f60b..b13012009815c 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -1,6 +1,6 @@ // tidy-alphabetical-start #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] -#![cfg_attr(test, feature(cfg_match))] +#![cfg_attr(test, feature(cfg_select))] #![feature(alloc_layout_extra)] #![feature(array_chunks)] #![feature(array_ptr_get)] diff --git a/library/coretests/tests/macros.rs b/library/coretests/tests/macros.rs index b30a40b7df28e..d220e628d7339 100644 --- a/library/coretests/tests/macros.rs +++ b/library/coretests/tests/macros.rs @@ -9,7 +9,7 @@ trait Trait { struct Struct; impl Trait for Struct { - cfg_match! { + cfg_select! { feature = "blah" => { fn blah(&self) { unimplemented!(); @@ -45,22 +45,22 @@ fn matches_leading_pipe() { } #[test] -fn cfg_match_basic() { - cfg_match! { +fn cfg_select_basic() { + cfg_select! { target_pointer_width = "64" => { fn f0_() -> bool { true }} } - cfg_match! { + cfg_select! { unix => { fn f1_() -> bool { true } } any(target_os = "macos", target_os = "linux") => { fn f1_() -> bool { false }} } - cfg_match! { + cfg_select! { target_pointer_width = "32" => { fn f2_() -> bool { false } } target_pointer_width = "64" => { fn f2_() -> bool { true } } } - cfg_match! { + cfg_select! { target_pointer_width = "16" => { fn f3_() -> i32 { 1 } } _ => { fn f3_() -> i32 { 2 }} } @@ -81,8 +81,8 @@ fn cfg_match_basic() { } #[test] -fn cfg_match_debug_assertions() { - cfg_match! { +fn cfg_select_debug_assertions() { + cfg_select! { debug_assertions => { assert!(cfg!(debug_assertions)); assert_eq!(4, 2+2); @@ -96,8 +96,8 @@ fn cfg_match_debug_assertions() { #[cfg(target_pointer_width = "64")] #[test] -fn cfg_match_no_duplication_on_64() { - cfg_match! { +fn cfg_select_no_duplication_on_64() { + cfg_select! { windows => { fn foo() {} } @@ -112,8 +112,8 @@ fn cfg_match_no_duplication_on_64() { } #[test] -fn cfg_match_options() { - cfg_match! { +fn cfg_select_options() { + cfg_select! { test => { use core::option::Option as Option2; fn works1() -> Option2 { Some(1) } @@ -121,25 +121,25 @@ fn cfg_match_options() { _ => { fn works1() -> Option { None } } } - cfg_match! { + cfg_select! { feature = "foo" => { fn works2() -> bool { false } } test => { fn works2() -> bool { true } } _ => { fn works2() -> bool { false } } } - cfg_match! { + cfg_select! { feature = "foo" => { fn works3() -> bool { false } } _ => { fn works3() -> bool { true } } } - cfg_match! { + cfg_select! { test => { use core::option::Option as Option3; fn works4() -> Option3 { Some(1) } } } - cfg_match! { + cfg_select! { feature = "foo" => { fn works5() -> bool { false } } test => { fn works5() -> bool { true } } } @@ -152,8 +152,8 @@ fn cfg_match_options() { } #[test] -fn cfg_match_two_functions() { - cfg_match! { +fn cfg_select_two_functions() { + cfg_select! { target_pointer_width = "64" => { fn foo1() {} fn bar1() {} @@ -177,7 +177,7 @@ fn cfg_match_two_functions() { } fn _accepts_expressions() -> i32 { - cfg_match! { + cfg_select! { unix => { 1 } _ => { 2 } } @@ -188,14 +188,14 @@ fn _accepts_expressions() -> i32 { fn _allows_stmt_expr_attributes() { let one = 1; let two = 2; - cfg_match! { + cfg_select! { unix => { one * two; } _ => { one + two; } } } fn _expression() { - let _ = cfg_match!({ + let _ = cfg_select!({ windows => { " XP" } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index ef41b47384d61..4d98461773918 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -700,8 +700,8 @@ mod panicking; #[allow(dead_code, unused_attributes, fuzzy_provenance_casts, unsafe_op_in_unsafe_fn)] mod backtrace_rs; -#[unstable(feature = "cfg_match", issue = "115585")] -pub use core::cfg_match; +#[unstable(feature = "cfg_select", issue = "115585")] +pub use core::cfg_select; #[unstable( feature = "concat_bytes", issue = "87555", diff --git a/src/tools/miri/src/concurrency/mod.rs b/src/tools/miri/src/concurrency/mod.rs index dd33f90f153d5..17d0f3f5ff67e 100644 --- a/src/tools/miri/src/concurrency/mod.rs +++ b/src/tools/miri/src/concurrency/mod.rs @@ -9,7 +9,7 @@ mod vector_clock; pub mod weak_memory; // Import either the real genmc adapter or a dummy module. -cfg_match! { +cfg_select! { feature = "genmc" => { mod genmc; pub use self::genmc::{GenmcCtx, GenmcConfig}; diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 329a7e56bc09f..b87682a7caf7e 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -1,5 +1,5 @@ #![feature(rustc_private)] -#![feature(cfg_match)] +#![feature(cfg_select)] #![feature(float_gamma)] #![feature(float_erf)] #![feature(map_try_insert)] diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 1f6acff0787a6..3bcfe3f1e4dc9 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -90,7 +90,7 @@ impl UnixFileDescription for FileHandle { op: FlockOp, ) -> InterpResult<'tcx, io::Result<()>> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); - cfg_match! { + cfg_select! { all(target_family = "unix", not(target_os = "solaris")) => { use std::os::fd::AsRawFd; From ff1a5ab4c3492ff74f3b964c4201d8c56ce9e35d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 18 Feb 2025 00:27:30 +0000 Subject: [PATCH 2533/4206] Rename `cfg_match!` to `cfg_select!` At [1] it was pointed out that `cfg_match!` syntax does not actually align well with match syntax, which is a possible source of confusion. The comment points out that usage is instead more similar to ecosystem `select!` macros. Rename `cfg_match!` to `cfg_select!` to match this. Tracking issue: https://github.com/rust-lang/rust/issues/115585 [1]: https://github.com/rust-lang/rust/issues/115585#issuecomment-2346307605 --- patches/0027-sysroot_tests-128bit-atomic-operations.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patches/0027-sysroot_tests-128bit-atomic-operations.patch b/patches/0027-sysroot_tests-128bit-atomic-operations.patch index 16c8488acdb56..f6e6bbc2387c2 100644 --- a/patches/0027-sysroot_tests-128bit-atomic-operations.patch +++ b/patches/0027-sysroot_tests-128bit-atomic-operations.patch @@ -17,7 +17,7 @@ index 1e336bf..35e6f54 100644 @@ -2,5 +2,4 @@ // tidy-alphabetical-start -#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] - #![cfg_attr(test, feature(cfg_match))] + #![cfg_attr(test, feature(cfg_select))] #![feature(alloc_layout_extra)] #![feature(array_chunks)] diff --git a/coretests/tests/atomic.rs b/coretests/tests/atomic.rs From fc31437b4c5298f86c523d379d4a19f675e7c2c9 Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Wed, 21 May 2025 01:50:12 +0200 Subject: [PATCH 2534/4206] Update books --- src/doc/edition-guide | 2 +- src/doc/reference | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/edition-guide b/src/doc/edition-guide index 1b1bb49babd65..aa6ce337c0adf 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit 1b1bb49babd65c732468cfa515b0c009bd1d26bc +Subproject commit aa6ce337c0adf7a63e33960d184270f2a45ab9ef diff --git a/src/doc/reference b/src/doc/reference index acd0231ebc748..118fd1f1f0854 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit acd0231ebc74849f6a8907b5e646ce86721aad76 +Subproject commit 118fd1f1f0854f50e3ae1fe4b64862aad23009ca From ed01a205144f53741534611a74d40487f611cdea Mon Sep 17 00:00:00 2001 From: dianne Date: Tue, 20 May 2025 17:27:38 -0700 Subject: [PATCH 2535/4206] typeck: catch `continue`s pointing to blocks This taints the typeck results with errors if a `continue` is found not pointing to a loop, which fixes an ICE. A few things were going wrong here. First, since this wasn't caught in typeck, we'd end up building the THIR and then running liveness lints on ill-formed HIR. Since liveness assumes all `continue`s point to loops, it wasn't setting a live node for the `continue`'s destination. However, the fallback for this was faulty; it would create a new live node to represent the erroneous state after the analysis's RWU table had already been built. This would ICE if the new live node was used in operations, such as merging results from the arms of a match. I've removed this error-recovery since it was buggy, and we should really catch bad labels before liveness. I've also replaced an outdated comment about when liveness lints are run. At this point, I think the call to `check_liveness` could be moved elsewhere, but if it can be run when the typeck results are tainted by errors, it'll need some slight refactoring so it can bail out in that case. In lieu of that, I've added an assertion. --- compiler/rustc_hir_typeck/src/expr.rs | 34 +++++++++++---- compiler/rustc_mir_build/src/builder/mod.rs | 3 +- compiler/rustc_passes/src/liveness.rs | 10 +++-- tests/crashes/113379.rs | 7 --- tests/crashes/121623.rs | 8 ---- .../continue-pointing-to-block-ice-113379.rs | 12 ++++++ ...ntinue-pointing-to-block-ice-113379.stderr | 43 +++++++++++++++++++ .../continue-pointing-to-block-ice-121623.rs | 11 +++++ ...ntinue-pointing-to-block-ice-121623.stderr | 14 ++++++ 9 files changed, 113 insertions(+), 29 deletions(-) delete mode 100644 tests/crashes/113379.rs delete mode 100644 tests/crashes/121623.rs create mode 100644 tests/ui/label/continue-pointing-to-block-ice-113379.rs create mode 100644 tests/ui/label/continue-pointing-to-block-ice-113379.stderr create mode 100644 tests/ui/label/continue-pointing-to-block-ice-121623.rs create mode 100644 tests/ui/label/continue-pointing-to-block-ice-121623.stderr diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 2c28ffd1fe3df..a1a33885b944c 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -532,14 +532,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::Break(destination, ref expr_opt) => { self.check_expr_break(destination, expr_opt.as_deref(), expr) } - ExprKind::Continue(destination) => { - if destination.target_id.is_ok() { - tcx.types.never - } else { - // There was an error; make type-check fail. - Ty::new_misc_error(tcx) - } - } + ExprKind::Continue(destination) => self.check_expr_continue(destination, expr), ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr), ExprKind::Become(call) => self.check_expr_become(call, expr), ExprKind::Let(let_expr) => self.check_expr_let(let_expr, expr.hir_id), @@ -989,6 +982,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn check_expr_continue( + &self, + destination: hir::Destination, + expr: &'tcx hir::Expr<'tcx>, + ) -> Ty<'tcx> { + if let Ok(target_id) = destination.target_id { + if let hir::Node::Expr(hir::Expr { kind: ExprKind::Loop(..), .. }) = + self.tcx.hir_node(target_id) + { + self.tcx.types.never + } else { + // Liveness linting assumes `continue`s all point to loops. We'll report an error + // in `check_mod_loops`, but make sure we don't run liveness (#113379, #121623). + let guar = self.dcx().span_delayed_bug( + expr.span, + "found `continue` not pointing to loop, but no error reported", + ); + Ty::new_error(self.tcx, guar) + } + } else { + // There was an error; make type-check fail. + Ty::new_misc_error(self.tcx) + } + } + fn check_expr_return( &self, expr_opt: Option<&'tcx hir::Expr<'tcx>>, diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 9cf051a8760be..8400709740f05 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -66,8 +66,7 @@ pub fn build_mir<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> { } }; - // this must run before MIR dump, because - // "not all control paths return a value" is reported here. + // Checking liveness after building the THIR ensures there were no typeck errors. // // maybe move the check to a MIR pass? tcx.ensure_ok().check_liveness(def); diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 4e9b7fd44d4b8..763d9fda80494 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -122,7 +122,6 @@ enum LiveNodeKind { VarDefNode(Span, HirId), ClosureNode, ExitNode, - ErrNode, } fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String { @@ -133,7 +132,6 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String { VarDefNode(s, _) => format!("Var def node [{}]", sm.span_to_diagnostic_string(s)), ClosureNode => "Closure node".to_owned(), ExitNode => "Exit node".to_owned(), - ErrNode => "Error node".to_owned(), } } @@ -492,6 +490,9 @@ struct Liveness<'a, 'tcx> { impl<'a, 'tcx> Liveness<'a, 'tcx> { fn new(ir: &'a mut IrMaps<'tcx>, body_owner: LocalDefId) -> Liveness<'a, 'tcx> { let typeck_results = ir.tcx.typeck(body_owner); + // Liveness linting runs after building the THIR. We make several assumptions based on + // typeck succeeding, e.g. that breaks and continues are well-formed. + assert!(typeck_results.tainted_by_errors.is_none()); // FIXME(#132279): we're in a body here. let typing_env = ty::TypingEnv::non_body_analysis(ir.tcx, body_owner); let closure_min_captures = typeck_results.closure_min_captures.get(&body_owner); @@ -976,8 +977,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // Now that we know the label we're going to, // look it up in the continue loop nodes table self.cont_ln.get(&sc).cloned().unwrap_or_else(|| { - self.ir.tcx.dcx().span_delayed_bug(expr.span, "continue to unknown label"); - self.ir.add_live_node(ErrNode) + // Liveness linting happens after building the THIR. Bad labels should already + // have been caught. + span_bug!(expr.span, "continue to unknown label"); }) } diff --git a/tests/crashes/113379.rs b/tests/crashes/113379.rs deleted file mode 100644 index 7163cbc39342d..0000000000000 --- a/tests/crashes/113379.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ known-bug: #113379 - -async fn f999() -> Vec { - 'b: { - continue 'b; - } -} diff --git a/tests/crashes/121623.rs b/tests/crashes/121623.rs deleted file mode 100644 index 3c01a7f452ca7..0000000000000 --- a/tests/crashes/121623.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: #121623 -fn main() { - match () { - _ => 'b: { - continue 'b; - } - } -} diff --git a/tests/ui/label/continue-pointing-to-block-ice-113379.rs b/tests/ui/label/continue-pointing-to-block-ice-113379.rs new file mode 100644 index 0000000000000..8a6a9cc840986 --- /dev/null +++ b/tests/ui/label/continue-pointing-to-block-ice-113379.rs @@ -0,0 +1,12 @@ +//! Regression test for ICE #113379. Liveness linting assumes that `continue`s all point to loops. +//! This tests that if a `continue` points to a block, we don't run liveness lints. + +async fn f999() -> Vec { + //~^ ERROR `async fn` is not permitted in Rust 2015 + 'b: { + //~^ ERROR mismatched types + continue 'b; + //~^ ERROR `continue` pointing to a labeled block + } +} +//~^ ERROR `main` function not found diff --git a/tests/ui/label/continue-pointing-to-block-ice-113379.stderr b/tests/ui/label/continue-pointing-to-block-ice-113379.stderr new file mode 100644 index 0000000000000..ada6305ec999b --- /dev/null +++ b/tests/ui/label/continue-pointing-to-block-ice-113379.stderr @@ -0,0 +1,43 @@ +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/continue-pointing-to-block-ice-113379.rs:4:1 + | +LL | async fn f999() -> Vec { + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2024` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0601]: `main` function not found in crate `continue_pointing_to_block_ice_113379` + --> $DIR/continue-pointing-to-block-ice-113379.rs:11:2 + | +LL | } + | ^ consider adding a `main` function to `$DIR/continue-pointing-to-block-ice-113379.rs` + +error[E0696]: `continue` pointing to a labeled block + --> $DIR/continue-pointing-to-block-ice-113379.rs:8:9 + | +LL | / 'b: { +LL | | +LL | | continue 'b; + | | ^^^^^^^^^^^ labeled blocks cannot be `continue`'d +LL | | +LL | | } + | |_____- labeled block the `continue` points to + +error[E0308]: mismatched types + --> $DIR/continue-pointing-to-block-ice-113379.rs:6:5 + | +LL | / 'b: { +LL | | +LL | | continue 'b; +LL | | +LL | | } + | |_____^ expected `Vec`, found `()` + | + = note: expected struct `Vec` + found unit type `()` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0308, E0601, E0670, E0696. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/label/continue-pointing-to-block-ice-121623.rs b/tests/ui/label/continue-pointing-to-block-ice-121623.rs new file mode 100644 index 0000000000000..7047f7a309aaf --- /dev/null +++ b/tests/ui/label/continue-pointing-to-block-ice-121623.rs @@ -0,0 +1,11 @@ +//! Regression test for ICE #121623. Liveness linting assumes that `continue`s all point to loops. +//! This tests that if a `continue` points to a block, we don't run liveness lints. + +fn main() { + match () { + _ => 'b: { + continue 'b; + //~^ ERROR `continue` pointing to a labeled block + } + } +} diff --git a/tests/ui/label/continue-pointing-to-block-ice-121623.stderr b/tests/ui/label/continue-pointing-to-block-ice-121623.stderr new file mode 100644 index 0000000000000..a484fb629d181 --- /dev/null +++ b/tests/ui/label/continue-pointing-to-block-ice-121623.stderr @@ -0,0 +1,14 @@ +error[E0696]: `continue` pointing to a labeled block + --> $DIR/continue-pointing-to-block-ice-121623.rs:7:13 + | +LL | _ => 'b: { + | ______________- +LL | | continue 'b; + | | ^^^^^^^^^^^ labeled blocks cannot be `continue`'d +LL | | +LL | | } + | |_________- labeled block the `continue` points to + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0696`. From 5c4eb87dbefaf8f00623574c9386df235fb95411 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 19 May 2025 18:07:32 +0300 Subject: [PATCH 2536/4206] add missing PATH Signed-off-by: onur-ozkan --- src/ci/docker/host-x86_64/arm-android/Dockerfile | 1 + src/ci/docker/host-x86_64/dist-android/Dockerfile | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/ci/docker/host-x86_64/arm-android/Dockerfile b/src/ci/docker/host-x86_64/arm-android/Dockerfile index aade95882685f..bc311be05808d 100644 --- a/src/ci/docker/host-x86_64/arm-android/Dockerfile +++ b/src/ci/docker/host-x86_64/arm-android/Dockerfile @@ -28,6 +28,7 @@ RUN /scripts/android-sdk.sh ENV PATH=$PATH:/android/sdk/emulator ENV PATH=$PATH:/android/sdk/tools ENV PATH=$PATH:/android/sdk/platform-tools +ENV PATH=$PATH:/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/bin ENV TARGETS=arm-linux-androideabi diff --git a/src/ci/docker/host-x86_64/dist-android/Dockerfile b/src/ci/docker/host-x86_64/dist-android/Dockerfile index 95fed6ee767b0..7b73326e35900 100644 --- a/src/ci/docker/host-x86_64/dist-android/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-android/Dockerfile @@ -22,6 +22,8 @@ ENV RUST_CONFIGURE_ARGS \ --android-ndk=/android/ndk/ \ --disable-docs +ENV PATH=$PATH:/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/bin + ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS COPY scripts/sccache.sh /scripts/ From 293b0ac7521476b91287b6182ef1c42231b17780 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Wed, 21 May 2025 04:53:50 +0000 Subject: [PATCH 2537/4206] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 5b47d1bbaed7c..4698969530292 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -a8e4c68dcb4dc1e48a0db294c5323cab0227fcb9 +2b96ddca1272960623e41829439df8dae82d20af From 348c1b0d886960a57a866e537458dae6bf75ec23 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 20 May 2025 23:00:24 +0200 Subject: [PATCH 2538/4206] Apply suggestions from code review Link `Command::current_dir`. Co-authored-by: Amanieu d'Antras --- library/std/src/os/unix/process.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index 659b354483458..57ce3c5a4bf4a 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -202,12 +202,12 @@ pub trait CommandExt: Sealed { /// Set the root of the child process. This calls `chroot` in the child process before executing /// the command. /// - /// This happens before changing to the directory specified with `Command::current_dir`, and - /// that directory will be relative to the new root. + /// This happens before changing to the directory specified with + /// [`process::Command::current_dir`], and that directory will be relative to the new root. /// - /// If no directory has been specified with `Command::current_dir`, this will set the directory - /// to `/`, to avoid leaving the current directory outside the chroot. (This is an intentional - /// difference from the underlying `chroot` system call.) + /// If no directory has been specified with [`process::Command::current_dir`], this will set the + /// directory to `/`, to avoid leaving the current directory outside the chroot. (This is an + /// intentional difference from the underlying `chroot` system call.) #[unstable(feature = "process_chroot", issue = "141298")] fn chroot>(&mut self, dir: P) -> &mut process::Command; } From 9efad3a87bb69ce62f9a5b1703e1b8decfe5c4a6 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sun, 27 Apr 2025 16:18:29 +0200 Subject: [PATCH 2539/4206] Add data_ptr method to Mutex and RwLock --- library/std/src/sync/poison/mutex.rs | 6 ++++++ library/std/src/sync/poison/rwlock.rs | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs index 1c29c619edc3a..372bf0a302929 100644 --- a/library/std/src/sync/poison/mutex.rs +++ b/library/std/src/sync/poison/mutex.rs @@ -608,6 +608,12 @@ impl Mutex { let data = self.data.get_mut(); poison::map_result(self.poison.borrow(), |()| data) } + + /// Returns a raw pointer to the underlying data. + #[unstable(feature = "mutex_data_ptr", issue = "140368")] + pub fn data_ptr(&self) -> *mut T { + self.data.get() + } } #[stable(feature = "mutex_from", since = "1.24.0")] diff --git a/library/std/src/sync/poison/rwlock.rs b/library/std/src/sync/poison/rwlock.rs index 6976c0a64e23f..0b32a2f1be153 100644 --- a/library/std/src/sync/poison/rwlock.rs +++ b/library/std/src/sync/poison/rwlock.rs @@ -634,6 +634,12 @@ impl RwLock { let data = self.data.get_mut(); poison::map_result(self.poison.borrow(), |()| data) } + + /// Returns a raw pointer to the underlying data. + #[unstable(feature = "rwlock_data_ptr", issue = "140368")] + pub fn data_ptr(&self) -> *mut T { + self.data.get() + } } #[stable(feature = "rust1", since = "1.0.0")] From 9d6c5a88a18405eb53e91645d35371ab089f0a37 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 21 May 2025 08:05:44 +0200 Subject: [PATCH 2540/4206] Add more docs to new data_ptr methods --- library/std/src/sync/poison/mutex.rs | 5 +++++ library/std/src/sync/poison/rwlock.rs | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs index 372bf0a302929..30325be685c32 100644 --- a/library/std/src/sync/poison/mutex.rs +++ b/library/std/src/sync/poison/mutex.rs @@ -610,6 +610,11 @@ impl Mutex { } /// Returns a raw pointer to the underlying data. + /// + /// The returned pointer is always non-null and properly aligned, but it is + /// the user's responsibility to ensure that any reads and writes through it + /// are properly synchronized to avoid data races, and that it is not read + /// or written through after the mutex is dropped. #[unstable(feature = "mutex_data_ptr", issue = "140368")] pub fn data_ptr(&self) -> *mut T { self.data.get() diff --git a/library/std/src/sync/poison/rwlock.rs b/library/std/src/sync/poison/rwlock.rs index 0b32a2f1be153..a060e2ea57a7b 100644 --- a/library/std/src/sync/poison/rwlock.rs +++ b/library/std/src/sync/poison/rwlock.rs @@ -636,6 +636,11 @@ impl RwLock { } /// Returns a raw pointer to the underlying data. + /// + /// The returned pointer is always non-null and properly aligned, but it is + /// the user's responsibility to ensure that any reads and writes through it + /// are properly synchronized to avoid data races, and that it is not read + /// or written through after the lock is dropped. #[unstable(feature = "rwlock_data_ptr", issue = "140368")] pub fn data_ptr(&self) -> *mut T { self.data.get() From 20589bd6050ff9596348c751231ac84b7538adb4 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 21 May 2025 08:06:04 +0200 Subject: [PATCH 2541/4206] Add ReentrantLock::data_ptr --- library/std/src/sync/reentrant_lock.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/library/std/src/sync/reentrant_lock.rs b/library/std/src/sync/reentrant_lock.rs index 96a4cf12659cc..727252f03a24e 100644 --- a/library/std/src/sync/reentrant_lock.rs +++ b/library/std/src/sync/reentrant_lock.rs @@ -349,6 +349,17 @@ impl ReentrantLock { } } + /// Returns a raw pointer to the underlying data. + /// + /// The returned pointer is always non-null and properly aligned, but it is + /// the user's responsibility to ensure that any reads through it are + /// properly synchronized to avoid data races, and that it is not read + /// through after the lock is dropped. + #[unstable(feature = "reentrant_lock_data_ptr", issue = "140368")] + pub fn data_ptr(&self) -> *const T { + &raw const self.data + } + unsafe fn increment_lock_count(&self) -> Option<()> { unsafe { *self.lock_count.get() = (*self.lock_count.get()).checked_add(1)?; From 2f34354e66caabfb563f4bcfaa1bd6bbdc673ff6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 May 2025 08:10:37 +0200 Subject: [PATCH 2542/4206] test direct usage of io::{stdout,stderr,stdin} --- .../miri/tests/fail-dep/libc/fs/isolated_stdin.rs | 9 --------- src/tools/miri/tests/fail/shims/isolated_stdin.rs | 12 ++++++++++++ .../libc/fs => fail/shims}/isolated_stdin.stderr | 11 ++++++----- src/tools/miri/tests/pass/shims/io.rs | 8 +++++--- src/tools/miri/tests/pass/shims/io.stderr | 1 + src/tools/miri/tests/pass/shims/io.stdout | 1 + 6 files changed, 25 insertions(+), 17 deletions(-) delete mode 100644 src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs create mode 100644 src/tools/miri/tests/fail/shims/isolated_stdin.rs rename src/tools/miri/tests/{fail-dep/libc/fs => fail/shims}/isolated_stdin.stderr (58%) create mode 100644 src/tools/miri/tests/pass/shims/io.stderr create mode 100644 src/tools/miri/tests/pass/shims/io.stdout diff --git a/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs b/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs deleted file mode 100644 index 3ef194c5c7172..0000000000000 --- a/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ignore-target: windows # No libc IO on Windows - -fn main() -> std::io::Result<()> { - let mut bytes = [0u8; 512]; - unsafe { - libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR: `read` from stdin not available when isolation is enabled - } - Ok(()) -} diff --git a/src/tools/miri/tests/fail/shims/isolated_stdin.rs b/src/tools/miri/tests/fail/shims/isolated_stdin.rs new file mode 100644 index 0000000000000..040c3cc216481 --- /dev/null +++ b/src/tools/miri/tests/fail/shims/isolated_stdin.rs @@ -0,0 +1,12 @@ +//@ignore-target: windows # FIXME: stdin does not work on Windows +//@error-in-other-file: `read` from stdin not available when isolation is enabled +//@normalize-stderr-test: "src/sys/.*\.rs" -> "$$FILE" +//@normalize-stderr-test: "\nLL \| .*" -> "" +//@normalize-stderr-test: "\| +[|_^]+" -> "| ^" +//@normalize-stderr-test: "\n *= note:.*" -> "" +use std::io::{self, Read}; + +fn main() { + let mut bytes = [0u8; 512]; + io::stdin().read(&mut bytes).unwrap(); +} diff --git a/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr b/src/tools/miri/tests/fail/shims/isolated_stdin.stderr similarity index 58% rename from src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr rename to src/tools/miri/tests/fail/shims/isolated_stdin.stderr index bb7e8cef5dcd2..1a4d7e963298e 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr +++ b/src/tools/miri/tests/fail/shims/isolated_stdin.stderr @@ -1,13 +1,14 @@ error: unsupported operation: `read` from stdin not available when isolation is enabled - --> tests/fail-dep/libc/fs/isolated_stdin.rs:LL:CC + --> RUSTLIB/std/$FILE:LL:CC | -LL | libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `read` from stdin not available when isolation is enabled + | ^ `read` from stdin not available when isolation is enabled | = help: set `MIRIFLAGS=-Zmiri-disable-isolation` to disable isolation; = help: or set `MIRIFLAGS=-Zmiri-isolation-error=warn` to make Miri return an error code from isolated operations (if supported for that operation) and continue with a warning - = note: BACKTRACE: - = note: inside `main` at tests/fail-dep/libc/fs/isolated_stdin.rs:LL:CC +note: inside `main` + --> tests/fail/shims/isolated_stdin.rs:LL:CC + | + | ^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/pass/shims/io.rs b/src/tools/miri/tests/pass/shims/io.rs index 420ef95a0cbf4..a96b98c022746 100644 --- a/src/tools/miri/tests/pass/shims/io.rs +++ b/src/tools/miri/tests/pass/shims/io.rs @@ -1,8 +1,10 @@ -use std::io::{self, IsTerminal}; +use std::io::{self, IsTerminal, Write}; fn main() { - // We can't really assume that this is truly a terminal, and anyway on Windows Miri will always - // return `false` here, but we can check that the call succeeds. + io::stdout().write_all(b"stdout\n").unwrap(); + io::stderr().write_all(b"stderr\n").unwrap(); + + // We can't assume that this is truly a terminal, but we can check that the call succeeds. io::stdout().is_terminal(); // Ensure we can format `io::Error` created from OS errors diff --git a/src/tools/miri/tests/pass/shims/io.stderr b/src/tools/miri/tests/pass/shims/io.stderr new file mode 100644 index 0000000000000..af6415db3c724 --- /dev/null +++ b/src/tools/miri/tests/pass/shims/io.stderr @@ -0,0 +1 @@ +stderr diff --git a/src/tools/miri/tests/pass/shims/io.stdout b/src/tools/miri/tests/pass/shims/io.stdout new file mode 100644 index 0000000000000..faa3a15c184b5 --- /dev/null +++ b/src/tools/miri/tests/pass/shims/io.stdout @@ -0,0 +1 @@ +stdout From 05235541a8fe621491bb6560664b14fc9d91633a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 May 2025 08:48:36 +0200 Subject: [PATCH 2543/4206] FileDescription: improve read/write docs --- src/tools/miri/src/shims/files.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/src/shims/files.rs b/src/tools/miri/src/shims/files.rs index 42603e784bbd7..31142431247c4 100644 --- a/src/tools/miri/src/shims/files.rs +++ b/src/tools/miri/src/shims/files.rs @@ -135,7 +135,10 @@ pub trait FileDescription: std::fmt::Debug + FileDescriptionExt { /// Reads as much as possible into the given buffer `ptr`. /// `len` indicates how many bytes we should try to read. - /// `dest` is where the return value should be stored: number of bytes read, or `-1` in case of error. + /// + /// When the read is done, `finish` will be called. Note that `read` itself may return before + /// that happens! Everything that should happen "after" the `read` needs to happen inside + /// `finish`. fn read<'tcx>( self: FileDescriptionRef, _communicate_allowed: bool, @@ -149,7 +152,10 @@ pub trait FileDescription: std::fmt::Debug + FileDescriptionExt { /// Writes as much as possible from the given buffer `ptr`. /// `len` indicates how many bytes we should try to write. - /// `dest` is where the return value should be stored: number of bytes written, or `-1` in case of error. + /// + /// When the write is done, `finish` will be called. Note that `write` itself may return before + /// that happens! Everything that should happen "after" the `write` needs to happen inside + /// `finish`. fn write<'tcx>( self: FileDescriptionRef, _communicate_allowed: bool, From 6ac8e512839677f673bd5cd2d5d6892b2bb9f71c Mon Sep 17 00:00:00 2001 From: Ell Date: Wed, 21 May 2025 10:07:17 +0300 Subject: [PATCH 2544/4206] Allow x perf to find rustc.exe on Windows --- src/bootstrap/src/core/build_steps/perf.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/perf.rs b/src/bootstrap/src/core/build_steps/perf.rs index 7f4e88bd73c6f..71cdb665ed47e 100644 --- a/src/bootstrap/src/core/build_steps/perf.rs +++ b/src/bootstrap/src/core/build_steps/perf.rs @@ -1,3 +1,4 @@ +use std::env::consts::EXE_EXTENSION; use std::fmt::{Display, Formatter}; use crate::core::build_steps::compile::{Std, Sysroot}; @@ -160,7 +161,10 @@ Consider setting `rust.debuginfo-level = 1` in `bootstrap.toml`."#); } let sysroot = builder.ensure(Sysroot::new(compiler)); - let rustc = sysroot.join("bin/rustc"); + let mut rustc = sysroot.clone(); + rustc.push("bin"); + rustc.push("rustc"); + rustc.set_extension(EXE_EXTENSION); let rustc_perf_dir = builder.build.tempdir().join("rustc-perf"); let results_dir = rustc_perf_dir.join("results"); From b725cf6af8c5a709828d649c86185b30872219ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= Date: Sat, 10 May 2025 00:11:06 +0000 Subject: [PATCH 2545/4206] Disable autodiff bootstrapping --- compiler/rustc_builtin_macros/src/errors.rs | 8 ----- compiler/rustc_builtin_macros/src/lib.rs | 2 +- library/core/src/lib.rs | 1 + library/core/src/macros/mod.rs | 40 ++++++++++++--------- library/std/src/lib.rs | 7 ++-- 5 files changed, 30 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index b28f7d312d937..b3cc460abbfc8 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -187,14 +187,6 @@ mod autodiff { pub(crate) act: String, } - #[derive(Diagnostic)] - #[diag(builtin_macros_autodiff_mode)] - pub(crate) struct AutoDiffInvalidMode { - #[primary_span] - pub(crate) span: Span, - pub(crate) mode: String, - } - #[derive(Diagnostic)] #[diag(builtin_macros_autodiff_width)] pub(crate) struct AutoDiffInvalidWidth { diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index a89b3642f7e53..b16f3cff5cfb1 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -5,10 +5,10 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(not(bootstrap), feature(autodiff))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] -#![feature(autodiff)] #![feature(box_patterns)] #![feature(decl_macro)] #![feature(if_let_guard)] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index aaa8c872f985c..e1982116994b4 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -226,6 +226,7 @@ pub mod assert_matches { // We don't export this through #[macro_export] for now, to avoid breakage. #[unstable(feature = "autodiff", issue = "124509")] +#[cfg(not(bootstrap))] /// Unstable module containing the unstable `autodiff` macro. pub mod autodiff { #[unstable(feature = "autodiff", issue = "124509")] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index dc50ad6a09076..99a4ab52b6c57 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1519,33 +1519,39 @@ pub(crate) mod builtin { ($file:expr $(,)?) => {{ /* compiler built-in */ }}; } - /// Automatic Differentiation macro which allows generating a new function to compute - /// the derivative of a given function. It may only be applied to a function. - /// The expected usage syntax is - /// `#[autodiff(NAME, MODE, INPUT_ACTIVITIES, OUTPUT_ACTIVITY)]` - /// where: - /// NAME is a string that represents a valid function name. - /// MODE is any of Forward, Reverse, ForwardFirst, ReverseFirst. - /// INPUT_ACTIVITIES consists of one valid activity for each input parameter. - /// OUTPUT_ACTIVITY must not be set if we implicitly return nothing (or explicitly return - /// `-> ()`). Otherwise it must be set to one of the allowed activities. - #[unstable(feature = "autodiff", issue = "124509")] - #[allow_internal_unstable(rustc_attrs)] - #[rustc_builtin_macro] - pub macro autodiff($item:item) { - /* compiler built-in */ - } - + /// the derivative of a given function in the forward mode of differentiation. + /// It may only be applied to a function. + /// + /// The expected usage syntax is: + /// `#[autodiff_forward(NAME, INPUT_ACTIVITIES, OUTPUT_ACTIVITY)]` + /// + /// - `NAME`: A string that represents a valid function name. + /// - `INPUT_ACTIVITIES`: Specifies one valid activity for each input parameter. + /// - `OUTPUT_ACTIVITY`: Must not be set if the function implicitly returns nothing + /// (or explicitly returns `-> ()`). Otherwise, it must be set to one of the allowed activities. #[unstable(feature = "autodiff", issue = "124509")] #[allow_internal_unstable(rustc_attrs)] #[rustc_builtin_macro] + #[cfg(not(bootstrap))] pub macro autodiff_forward($item:item) { /* compiler built-in */ } + /// Automatic Differentiation macro which allows generating a new function to compute + /// the derivative of a given function in the reverse mode of differentiation. + /// It may only be applied to a function. + /// + /// The expected usage syntax is: + /// `#[autodiff_reverse(NAME, INPUT_ACTIVITIES, OUTPUT_ACTIVITY)]` + /// + /// - `NAME`: A string that represents a valid function name. + /// - `INPUT_ACTIVITIES`: Specifies one valid activity for each input parameter. + /// - `OUTPUT_ACTIVITY`: Must not be set if the function implicitly returns nothing + /// (or explicitly returns `-> ()`). Otherwise, it must be set to one of the allowed activities. #[unstable(feature = "autodiff", issue = "124509")] #[allow_internal_unstable(rustc_attrs)] #[rustc_builtin_macro] + #[cfg(not(bootstrap))] pub macro autodiff_reverse($item:item) { /* compiler built-in */ } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index ef41b47384d61..0ac674d989060 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -276,12 +276,12 @@ // tidy-alphabetical-start // stabilization was reverted after it hit beta +#![cfg_attr(not(bootstrap), feature(autodiff))] #![feature(alloc_error_handler)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] #![feature(asm_experimental_arch)] -#![feature(autodiff)] #![feature(cfg_sanitizer_cfi)] #![feature(cfg_target_thread_local)] #![feature(cfi_encoding)] @@ -636,12 +636,15 @@ pub mod simd { #[doc(inline)] pub use crate::std_float::StdFloat; } + #[unstable(feature = "autodiff", issue = "124509")] +#[cfg(not(bootstrap))] /// This module provides support for automatic differentiation. pub mod autodiff { /// This macro handles automatic differentiation. - pub use core::autodiff::autodiff; + pub use core::autodiff::{autodiff_forward, autodiff_reverse}; } + #[stable(feature = "futures_api", since = "1.36.0")] pub mod task { //! Types and Traits for working with asynchronous tasks. From 2041de7083c114025646220068d3943be517af4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= Date: Sat, 10 May 2025 00:37:15 +0000 Subject: [PATCH 2546/4206] Update codegen and pretty tests UI tests are pending, will depend on error messages change. --- tests/codegen/autodiff/batched.rs | 8 +++--- tests/codegen/autodiff/identical_fnc.rs | 6 ++--- tests/codegen/autodiff/inline.rs | 4 +-- tests/codegen/autodiff/scalar.rs | 4 +-- tests/codegen/autodiff/sret.rs | 4 +-- tests/pretty/autodiff/autodiff_forward.pp | 2 +- tests/pretty/autodiff/autodiff_forward.rs | 30 +++++++++++------------ tests/pretty/autodiff/autodiff_reverse.pp | 2 +- tests/pretty/autodiff/autodiff_reverse.rs | 12 ++++----- tests/pretty/autodiff/inherent_impl.pp | 2 +- tests/pretty/autodiff/inherent_impl.rs | 4 +-- 11 files changed, 39 insertions(+), 39 deletions(-) diff --git a/tests/codegen/autodiff/batched.rs b/tests/codegen/autodiff/batched.rs index e004711640553..d27aed50e6cc4 100644 --- a/tests/codegen/autodiff/batched.rs +++ b/tests/codegen/autodiff/batched.rs @@ -11,11 +11,11 @@ #![feature(autodiff)] -use std::autodiff::autodiff; +use std::autodiff::autodiff_forward; -#[autodiff(d_square3, Forward, Dual, DualOnly)] -#[autodiff(d_square2, Forward, 4, Dual, DualOnly)] -#[autodiff(d_square1, Forward, 4, Dual, Dual)] +#[autodiff_forward(d_square3, Dual, DualOnly)] +#[autodiff_forward(d_square2, 4, Dual, DualOnly)] +#[autodiff_forward(d_square1, 4, Dual, Dual)] #[no_mangle] fn square(x: &f32) -> f32 { x * x diff --git a/tests/codegen/autodiff/identical_fnc.rs b/tests/codegen/autodiff/identical_fnc.rs index 1c3277f52b488..1c25b3d09ab0d 100644 --- a/tests/codegen/autodiff/identical_fnc.rs +++ b/tests/codegen/autodiff/identical_fnc.rs @@ -11,14 +11,14 @@ // identical function calls in the LLVM-IR, while having two different calls in the Rust code. #![feature(autodiff)] -use std::autodiff::autodiff; +use std::autodiff::autodiff_reverse; -#[autodiff(d_square, Reverse, Duplicated, Active)] +#[autodiff_reverse(d_square, Duplicated, Active)] fn square(x: &f64) -> f64 { x * x } -#[autodiff(d_square2, Reverse, Duplicated, Active)] +#[autodiff_reverse(d_square2, Duplicated, Active)] fn square2(x: &f64) -> f64 { x * x } diff --git a/tests/codegen/autodiff/inline.rs b/tests/codegen/autodiff/inline.rs index e90faa4aa3802..65bed170207cc 100644 --- a/tests/codegen/autodiff/inline.rs +++ b/tests/codegen/autodiff/inline.rs @@ -4,9 +4,9 @@ #![feature(autodiff)] -use std::autodiff::autodiff; +use std::autodiff::autodiff_reverse; -#[autodiff(d_square, Reverse, Duplicated, Active)] +#[autodiff_reverse(d_square, Duplicated, Active)] fn square(x: &f64) -> f64 { x * x } diff --git a/tests/codegen/autodiff/scalar.rs b/tests/codegen/autodiff/scalar.rs index 85358f5fcb693..096b4209e84ad 100644 --- a/tests/codegen/autodiff/scalar.rs +++ b/tests/codegen/autodiff/scalar.rs @@ -3,9 +3,9 @@ //@ needs-enzyme #![feature(autodiff)] -use std::autodiff::autodiff; +use std::autodiff::autodiff_reverse; -#[autodiff(d_square, Reverse, Duplicated, Active)] +#[autodiff_reverse(d_square, Duplicated, Active)] #[no_mangle] fn square(x: &f64) -> f64 { x * x diff --git a/tests/codegen/autodiff/sret.rs b/tests/codegen/autodiff/sret.rs index 5ead90041edc3..d2fa85e3e3787 100644 --- a/tests/codegen/autodiff/sret.rs +++ b/tests/codegen/autodiff/sret.rs @@ -9,10 +9,10 @@ #![feature(autodiff)] -use std::autodiff::autodiff; +use std::autodiff::autodiff_reverse; #[no_mangle] -#[autodiff(df, Reverse, Active, Active, Active)] +#[autodiff_reverse(df, Active, Active, Active)] fn primal(x: f32, y: f32) -> f64 { (x * x * y) as f64 } diff --git a/tests/pretty/autodiff/autodiff_forward.pp b/tests/pretty/autodiff/autodiff_forward.pp index 8253603e8079c..a2525abc83207 100644 --- a/tests/pretty/autodiff/autodiff_forward.pp +++ b/tests/pretty/autodiff/autodiff_forward.pp @@ -13,7 +13,7 @@ // Test that forward mode ad macros are expanded correctly. -use std::autodiff::autodiff; +use std::autodiff::{autodiff_forward, autodiff_reverse}; #[rustc_autodiff] #[inline(never)] diff --git a/tests/pretty/autodiff/autodiff_forward.rs b/tests/pretty/autodiff/autodiff_forward.rs index ae974f9b4dbf9..181b6ebc77048 100644 --- a/tests/pretty/autodiff/autodiff_forward.rs +++ b/tests/pretty/autodiff/autodiff_forward.rs @@ -7,48 +7,48 @@ // Test that forward mode ad macros are expanded correctly. -use std::autodiff::autodiff; +use std::autodiff::{autodiff_forward, autodiff_reverse}; -#[autodiff(df1, Forward, Dual, Const, Dual)] +#[autodiff_forward(df1, Dual, Const, Dual)] pub fn f1(x: &[f64], y: f64) -> f64 { unimplemented!() } -#[autodiff(df2, Forward, Dual, Const, Const)] +#[autodiff_forward(df2, Dual, Const, Const)] pub fn f2(x: &[f64], y: f64) -> f64 { unimplemented!() } -#[autodiff(df3, Forward, Dual, Const, Const)] +#[autodiff_forward(df3, Dual, Const, Const)] pub fn f3(x: &[f64], y: f64) -> f64 { unimplemented!() } // Not the most interesting derivative, but who are we to judge -#[autodiff(df4, Forward)] +#[autodiff_forward(df4)] pub fn f4() {} // We want to be sure that the same function can be differentiated in different ways -#[autodiff(df5_rev, Reverse, Duplicated, Const, Active)] -#[autodiff(df5_x, Forward, Dual, Const, Const)] -#[autodiff(df5_y, Forward, Const, Dual, Const)] +#[autodiff_reverse(df5_rev, Duplicated, Const, Active)] +#[autodiff_forward(df5_x, Dual, Const, Const)] +#[autodiff_forward(df5_y, Const, Dual, Const)] pub fn f5(x: &[f64], y: f64) -> f64 { unimplemented!() } struct DoesNotImplDefault; -#[autodiff(df6, Forward, Const)] +#[autodiff_forward(df6, Const)] pub fn f6() -> DoesNotImplDefault { unimplemented!() } // Make sure, that we add the None for the default return. -#[autodiff(df7, Forward, Const)] +#[autodiff_forward(df7, Const)] pub fn f7(x: f32) -> () {} -#[autodiff(f8_1, Forward, Dual, DualOnly)] -#[autodiff(f8_2, Forward, 4, Dual, DualOnly)] -#[autodiff(f8_3, Forward, 4, Dual, Dual)] +#[autodiff_forward(f8_1, Dual, DualOnly)] +#[autodiff_forward(f8_2, 4, Dual, DualOnly)] +#[autodiff_forward(f8_3, 4, Dual, Dual)] #[no_mangle] fn f8(x: &f32) -> f32 { unimplemented!() @@ -56,8 +56,8 @@ fn f8(x: &f32) -> f32 { // We want to make sure that we can use the macro for functions defined inside of functions pub fn f9() { - #[autodiff(d_inner_1, Forward, Dual, DualOnly)] - #[autodiff(d_inner_2, Forward, Dual, Dual)] + #[autodiff_forward(d_inner_1, Dual, DualOnly)] + #[autodiff_forward(d_inner_2, Dual, Dual)] fn inner(x: f32) -> f32 { x * x } diff --git a/tests/pretty/autodiff/autodiff_reverse.pp b/tests/pretty/autodiff/autodiff_reverse.pp index 31920694a3ad5..e67c3443ddef1 100644 --- a/tests/pretty/autodiff/autodiff_reverse.pp +++ b/tests/pretty/autodiff/autodiff_reverse.pp @@ -13,7 +13,7 @@ // Test that reverse mode ad macros are expanded correctly. -use std::autodiff::autodiff; +use std::autodiff::autodiff_reverse; #[rustc_autodiff] #[inline(never)] diff --git a/tests/pretty/autodiff/autodiff_reverse.rs b/tests/pretty/autodiff/autodiff_reverse.rs index 3c024272f407e..d37e5e3eb4cec 100644 --- a/tests/pretty/autodiff/autodiff_reverse.rs +++ b/tests/pretty/autodiff/autodiff_reverse.rs @@ -7,18 +7,18 @@ // Test that reverse mode ad macros are expanded correctly. -use std::autodiff::autodiff; +use std::autodiff::autodiff_reverse; -#[autodiff(df1, Reverse, Duplicated, Const, Active)] +#[autodiff_reverse(df1, Duplicated, Const, Active)] pub fn f1(x: &[f64], y: f64) -> f64 { unimplemented!() } // Not the most interesting derivative, but who are we to judge -#[autodiff(df2, Reverse)] +#[autodiff_reverse(df2)] pub fn f2() {} -#[autodiff(df3, Reverse, Duplicated, Const, Active)] +#[autodiff_reverse(df3, Duplicated, Const, Active)] pub fn f3(x: &[f64], y: f64) -> f64 { unimplemented!() } @@ -27,12 +27,12 @@ enum Foo { Reverse } use Foo::Reverse; // What happens if we already have Reverse in type (enum variant decl) and value (enum variant // constructor) namespace? > It's expected to work normally. -#[autodiff(df4, Reverse, Const)] +#[autodiff_reverse(df4, Const)] pub fn f4(x: f32) { unimplemented!() } -#[autodiff(df5, Reverse, DuplicatedOnly, Duplicated)] +#[autodiff_reverse(df5, DuplicatedOnly, Duplicated)] pub fn f5(x: *const f32, y: &f32) { unimplemented!() } diff --git a/tests/pretty/autodiff/inherent_impl.pp b/tests/pretty/autodiff/inherent_impl.pp index 97ac766b6b99e..d18061b2dbdef 100644 --- a/tests/pretty/autodiff/inherent_impl.pp +++ b/tests/pretty/autodiff/inherent_impl.pp @@ -11,7 +11,7 @@ //@ pretty-compare-only //@ pp-exact:inherent_impl.pp -use std::autodiff::autodiff; +use std::autodiff::autodiff_reverse; struct Foo { a: f64, diff --git a/tests/pretty/autodiff/inherent_impl.rs b/tests/pretty/autodiff/inherent_impl.rs index 59de93f7e0ffd..11ff209f9d89e 100644 --- a/tests/pretty/autodiff/inherent_impl.rs +++ b/tests/pretty/autodiff/inherent_impl.rs @@ -5,7 +5,7 @@ //@ pretty-compare-only //@ pp-exact:inherent_impl.pp -use std::autodiff::autodiff; +use std::autodiff::autodiff_reverse; struct Foo { a: f64, @@ -17,7 +17,7 @@ trait MyTrait { } impl MyTrait for Foo { - #[autodiff(df, Reverse, Const, Active, Active)] + #[autodiff_reverse(df, Const, Active, Active)] fn f(&self, x: f64) -> f64 { self.a * 0.25 * (x * x - 1.0 - 2.0 * x.ln()) } From f92d84cc6e0770c0d8f3dc775bafdf7f8786db61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= Date: Sat, 10 May 2025 00:52:47 +0000 Subject: [PATCH 2547/4206] Initial naive implementation using `Symbols` to represent autodiff modes (`Forward`, `Reverse`) Since the mode is no longer part of `meta_item`, we must insert it manually (otherwise macro expansion with `#[rustc_autodiff]` won't work). This can be revised later if a more structured representation becomes necessary (using enums, annotated structs, etc). Some tests are currently failing. I'll address them next. --- compiler/rustc_builtin_macros/src/autodiff.rs | 28 +++++++++++++------ compiler/rustc_span/src/symbol.rs | 2 ++ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 8073de15925e6..d60bb0ae5cbde 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -259,29 +259,41 @@ mod llvm_enzyme { // create TokenStream from vec elemtents: // meta_item doesn't have a .tokens field let mut ts: Vec = vec![]; - if meta_item_vec.len() < 2 { - // At the bare minimum, we need a fnc name and a mode, even for a dummy function with no - // input and output args. + if meta_item_vec.len() < 1 { + // At the bare minimum, we need a fnc name. dcx.emit_err(errors::AutoDiffMissingConfig { span: item.span() }); return vec![item]; } - meta_item_inner_to_ts(&meta_item_vec[1], &mut ts); + let mode_symbol = match mode { + DiffMode::Forward => sym::Forward, + DiffMode::Reverse => sym::Reverse, + _ => unreachable!("Unsupported mode: {:?}", mode), + }; + + // Insert mode token + let mode_token = Token::new(TokenKind::Ident(mode_symbol, false.into()), Span::default()); + ts.insert(0, TokenTree::Token(mode_token, Spacing::Joint)); + ts.insert( + 1, + TokenTree::Token(Token::new(TokenKind::Comma, Span::default()), Spacing::Alone), + ); // Now, if the user gave a width (vector aka batch-mode ad), then we copy it. // If it is not given, we default to 1 (scalar mode). let start_position; let kind: LitKind = LitKind::Integer; let symbol; - if meta_item_vec.len() >= 3 - && let Some(width) = width(&meta_item_vec[2]) + if meta_item_vec.len() >= 2 + && let Some(width) = width(&meta_item_vec[1]) { - start_position = 3; + start_position = 2; symbol = Symbol::intern(&width.to_string()); } else { - start_position = 2; + start_position = 1; symbol = sym::integer(1); } + let l: Lit = Lit { kind, symbol, suffix: None }; let t = Token::new(TokenKind::Literal(l), Span::default()); let comma = Token::new(TokenKind::Comma, Span::default()); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index bb19b5761bb19..9dff87e0a0011 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -253,6 +253,7 @@ symbols! { FnMut, FnOnce, Formatter, + Forward, From, FromIterator, FromResidual, @@ -348,6 +349,7 @@ symbols! { Result, ResumeTy, Return, + Reverse, Right, Rust, RustaceansAreAwesome, From 8dd62e8188d08baeb5d28cb221241cb61a65e532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= Date: Sat, 10 May 2025 21:50:06 +0000 Subject: [PATCH 2548/4206] Update UI tests --- compiler/rustc_builtin_macros/messages.ftl | 1 - compiler/rustc_builtin_macros/src/autodiff.rs | 6 +- tests/ui/autodiff/autodiff_illegal.rs | 60 +++++--------- tests/ui/autodiff/autodiff_illegal.stderr | 83 ++++++++----------- tests/ui/autodiff/auxiliary/my_macro.rs | 2 +- tests/ui/autodiff/visibility.rs | 9 +- .../autodiff/visibility.std_autodiff.stderr | 26 +++--- ...ature-gate-autodiff-use.has_support.stderr | 8 +- ...eature-gate-autodiff-use.no_support.stderr | 12 +-- .../feature-gate-autodiff-use.rs | 4 +- .../feature-gate-autodiff.has_support.stderr | 8 +- .../feature-gate-autodiff.no_support.stderr | 8 +- .../ui/feature-gates/feature-gate-autodiff.rs | 6 +- 13 files changed, 101 insertions(+), 132 deletions(-) diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 73be954cefd76..4796f3a188897 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -71,7 +71,6 @@ builtin_macros_assert_requires_expression = macro requires an expression as an a builtin_macros_autodiff = autodiff must be applied to function builtin_macros_autodiff_missing_config = autodiff requires at least a name and mode -builtin_macros_autodiff_mode = unknown Mode: `{$mode}`. Use `Forward` or `Reverse` builtin_macros_autodiff_mode_activity = {$act} can not be used in {$mode} Mode builtin_macros_autodiff_not_build = this rustc version does not support autodiff builtin_macros_autodiff_number_activities = expected {$expected} activities, but found {$found} diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index d60bb0ae5cbde..dc3bb8ab52a5d 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -86,6 +86,7 @@ mod llvm_enzyme { ecx: &mut ExtCtxt<'_>, meta_item: &ThinVec, has_ret: bool, + mode: DiffMode, ) -> AutoDiffAttrs { let dcx = ecx.sess.dcx(); @@ -145,7 +146,7 @@ mod llvm_enzyme { }; AutoDiffAttrs { - mode: DiffMode::Error, + mode, width, ret_activity: *ret_activity, input_activity: input_activity.to_vec(), @@ -315,8 +316,7 @@ mod llvm_enzyme { ts.pop(); let ts: TokenStream = TokenStream::from_iter(ts); - let mut x: AutoDiffAttrs = from_ast(ecx, &meta_item_vec, has_ret); - x.mode = mode; + let x: AutoDiffAttrs = from_ast(ecx, &meta_item_vec, has_ret, mode); if !x.is_active() { // We encountered an error, so we return the original item. // This allows us to potentially parse other attributes. diff --git a/tests/ui/autodiff/autodiff_illegal.rs b/tests/ui/autodiff/autodiff_illegal.rs index a916bd8b857b9..a53b6d5e58981 100644 --- a/tests/ui/autodiff/autodiff_illegal.rs +++ b/tests/ui/autodiff/autodiff_illegal.rs @@ -7,38 +7,38 @@ // Test that invalid ad macros give nice errors and don't ICE. -use std::autodiff::autodiff; +use std::autodiff::{autodiff_forward, autodiff_reverse}; // We can't use Duplicated on scalars -#[autodiff(df1, Reverse, Duplicated)] +#[autodiff_reverse(df1, Duplicated)] pub fn f1(x: f64) { //~^ ERROR Duplicated can not be used for this type unimplemented!() } // Too many activities -#[autodiff(df3, Reverse, Duplicated, Const)] +#[autodiff_reverse(df3, Duplicated, Const)] pub fn f3(x: f64) { //~^^ ERROR expected 1 activities, but found 2 unimplemented!() } // To few activities -#[autodiff(df4, Reverse)] +#[autodiff_reverse(df4)] pub fn f4(x: f64) { //~^^ ERROR expected 1 activities, but found 0 unimplemented!() } // We can't use Dual in Reverse mode -#[autodiff(df5, Reverse, Dual)] +#[autodiff_reverse(df5, Dual)] pub fn f5(x: f64) { //~^^ ERROR Dual can not be used in Reverse Mode unimplemented!() } // We can't use Duplicated in Forward mode -#[autodiff(df6, Forward, Duplicated)] +#[autodiff_forward(df6, Duplicated)] pub fn f6(x: f64) { //~^^ ERROR Duplicated can not be used in Forward Mode //~^^ ERROR Duplicated can not be used for this type @@ -46,36 +46,36 @@ pub fn f6(x: f64) { } fn dummy() { - #[autodiff(df7, Forward, Dual)] + #[autodiff_forward(df7, Dual)] let mut x = 5; //~^ ERROR autodiff must be applied to function - #[autodiff(df7, Forward, Dual)] + #[autodiff_forward(df7, Dual)] x = x + 3; //~^^ ERROR attributes on expressions are experimental [E0658] //~^^ ERROR autodiff must be applied to function - #[autodiff(df7, Forward, Dual)] + #[autodiff_forward(df7, Dual)] let add_one_v2 = |x: u32| -> u32 { x + 1 }; //~^ ERROR autodiff must be applied to function } // Malformed, where args? -#[autodiff] +#[autodiff_forward] pub fn f7(x: f64) { //~^ ERROR autodiff requires at least a name and mode unimplemented!() } // Malformed, where args? -#[autodiff()] +#[autodiff_forward()] pub fn f8(x: f64) { //~^ ERROR autodiff requires at least a name and mode unimplemented!() } // Invalid attribute syntax -#[autodiff = ""] +#[autodiff_forward = ""] pub fn f9(x: f64) { //~^ ERROR autodiff requires at least a name and mode unimplemented!() @@ -84,29 +84,15 @@ pub fn f9(x: f64) { fn fn_exists() {} // We colide with an already existing function -#[autodiff(fn_exists, Reverse, Active)] +#[autodiff_reverse(fn_exists, Active)] pub fn f10(x: f64) { //~^^ ERROR the name `fn_exists` is defined multiple times [E0428] unimplemented!() } -// Malformed, missing a mode -#[autodiff(df11)] -pub fn f11() { - //~^ ERROR autodiff requires at least a name and mode - unimplemented!() -} - -// Invalid Mode -#[autodiff(df12, Debug)] -pub fn f12() { - //~^^ ERROR unknown Mode: `Debug`. Use `Forward` or `Reverse` - unimplemented!() -} - // Invalid, please pick one Mode // or use two autodiff macros. -#[autodiff(df13, Forward, Reverse)] +#[autodiff_reverse(df13, Reverse)] pub fn f13() { //~^^ ERROR did not recognize Activity: `Reverse` unimplemented!() @@ -117,7 +103,7 @@ struct Foo {} // We can't handle Active structs, because that would mean (in the general case), that we would // need to allocate and initialize arbitrary user types. We have Duplicated/Dual input args for // that. FIXME: Give a nicer error and suggest to the user to have a `&mut Foo` input instead. -#[autodiff(df14, Reverse, Active, Active)] +#[autodiff_reverse(df14, Active, Active)] fn f14(x: f32) -> Foo { unimplemented!() } @@ -127,14 +113,14 @@ type MyFloat = f32; // We would like to support type alias to f32/f64 in argument type in the future, // but that requires us to implement our checks at a later stage // like THIR which has type information available. -#[autodiff(df15, Reverse, Active, Active)] +#[autodiff_reverse(df15, Active, Active)] fn f15(x: MyFloat) -> f32 { //~^^ ERROR failed to resolve: use of undeclared type `MyFloat` [E0433] unimplemented!() } // We would like to support type alias to f32/f64 in return type in the future -#[autodiff(df16, Reverse, Active, Active)] +#[autodiff_reverse(df16, Active, Active)] fn f16(x: f32) -> MyFloat { unimplemented!() } @@ -145,40 +131,40 @@ struct F64Trans { } // We would like to support `#[repr(transparent)]` f32/f64 wrapper in return type in the future -#[autodiff(df17, Reverse, Active, Active)] +#[autodiff_reverse(df17, Active, Active)] fn f17(x: f64) -> F64Trans { unimplemented!() } // We would like to support `#[repr(transparent)]` f32/f64 wrapper in argument type in the future -#[autodiff(df18, Reverse, Active, Active)] +#[autodiff_reverse(df18, Active, Active)] fn f18(x: F64Trans) -> f64 { //~^^ ERROR failed to resolve: use of undeclared type `F64Trans` [E0433] unimplemented!() } // Invalid return activity -#[autodiff(df19, Forward, Dual, Active)] +#[autodiff_forward(df19, Dual, Active)] fn f19(x: f32) -> f32 { //~^^ ERROR invalid return activity Active in Forward Mode unimplemented!() } -#[autodiff(df20, Reverse, Active, Dual)] +#[autodiff_reverse(df20, Active, Dual)] fn f20(x: f32) -> f32 { //~^^ ERROR invalid return activity Dual in Reverse Mode unimplemented!() } // Duplicated cannot be used as return activity -#[autodiff(df21, Reverse, Active, Duplicated)] +#[autodiff_reverse(df21, Active, Duplicated)] fn f21(x: f32) -> f32 { //~^^ ERROR invalid return activity Duplicated in Reverse Mode unimplemented!() } struct DoesNotImplDefault; -#[autodiff(df22, Forward, Dual)] +#[autodiff_forward(df22, Dual)] pub fn f22() -> DoesNotImplDefault { //~^^ ERROR the function or associated item `default` exists for tuple `(DoesNotImplDefault, DoesNotImplDefault)`, but its trait bounds were not satisfied unimplemented!() diff --git a/tests/ui/autodiff/autodiff_illegal.stderr b/tests/ui/autodiff/autodiff_illegal.stderr index b119f61b8ae66..ad6f10af46780 100644 --- a/tests/ui/autodiff/autodiff_illegal.stderr +++ b/tests/ui/autodiff/autodiff_illegal.stderr @@ -1,8 +1,8 @@ error[E0658]: attributes on expressions are experimental --> $DIR/autodiff_illegal.rs:53:5 | -LL | #[autodiff(df7, Forward, Dual)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[autodiff_forward(df7, Dual)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #15701 for more information = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable @@ -17,26 +17,26 @@ LL | pub fn f1(x: f64) { error: expected 1 activities, but found 2 --> $DIR/autodiff_illegal.rs:20:1 | -LL | #[autodiff(df3, Reverse, Duplicated, Const)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[autodiff_reverse(df3, Duplicated, Const)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected 1 activities, but found 0 --> $DIR/autodiff_illegal.rs:27:1 | -LL | #[autodiff(df4, Reverse)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[autodiff_reverse(df4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: Dual can not be used in Reverse Mode --> $DIR/autodiff_illegal.rs:34:1 | -LL | #[autodiff(df5, Reverse, Dual)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[autodiff_reverse(df5, Dual)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Duplicated can not be used in Forward Mode --> $DIR/autodiff_illegal.rs:41:1 | -LL | #[autodiff(df6, Forward, Duplicated)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[autodiff_forward(df6, Duplicated)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Duplicated can not be used for this type --> $DIR/autodiff_illegal.rs:42:14 @@ -95,69 +95,54 @@ error[E0428]: the name `fn_exists` is defined multiple times LL | fn fn_exists() {} | -------------- previous definition of the value `fn_exists` here ... -LL | #[autodiff(fn_exists, Reverse, Active)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `fn_exists` redefined here +LL | #[autodiff_reverse(fn_exists, Active)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `fn_exists` redefined here | = note: `fn_exists` must be defined only once in the value namespace of this module -error: autodiff requires at least a name and mode - --> $DIR/autodiff_illegal.rs:95:1 - | -LL | / pub fn f11() { -LL | | -LL | | unimplemented!() -LL | | } - | |_^ - -error: unknown Mode: `Debug`. Use `Forward` or `Reverse` - --> $DIR/autodiff_illegal.rs:101:18 - | -LL | #[autodiff(df12, Debug)] - | ^^^^^ - error: did not recognize Activity: `Reverse` - --> $DIR/autodiff_illegal.rs:109:27 + --> $DIR/autodiff_illegal.rs:95:26 | -LL | #[autodiff(df13, Forward, Reverse)] - | ^^^^^^^ +LL | #[autodiff_reverse(df13, Reverse)] + | ^^^^^^^ error: invalid return activity Active in Forward Mode - --> $DIR/autodiff_illegal.rs:161:1 + --> $DIR/autodiff_illegal.rs:147:1 | -LL | #[autodiff(df19, Forward, Dual, Active)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[autodiff_forward(df19, Dual, Active)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid return activity Dual in Reverse Mode - --> $DIR/autodiff_illegal.rs:167:1 + --> $DIR/autodiff_illegal.rs:153:1 | -LL | #[autodiff(df20, Reverse, Active, Dual)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[autodiff_reverse(df20, Active, Dual)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid return activity Duplicated in Reverse Mode - --> $DIR/autodiff_illegal.rs:174:1 + --> $DIR/autodiff_illegal.rs:160:1 | -LL | #[autodiff(df21, Reverse, Active, Duplicated)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[autodiff_reverse(df21, Active, Duplicated)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0433]: failed to resolve: use of undeclared type `MyFloat` - --> $DIR/autodiff_illegal.rs:130:1 + --> $DIR/autodiff_illegal.rs:116:1 | -LL | #[autodiff(df15, Reverse, Active, Active)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared type `MyFloat` +LL | #[autodiff_reverse(df15, Active, Active)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared type `MyFloat` error[E0433]: failed to resolve: use of undeclared type `F64Trans` - --> $DIR/autodiff_illegal.rs:154:1 + --> $DIR/autodiff_illegal.rs:140:1 | -LL | #[autodiff(df18, Reverse, Active, Active)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared type `F64Trans` +LL | #[autodiff_reverse(df18, Active, Active)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared type `F64Trans` error[E0599]: the function or associated item `default` exists for tuple `(DoesNotImplDefault, DoesNotImplDefault)`, but its trait bounds were not satisfied - --> $DIR/autodiff_illegal.rs:181:1 + --> $DIR/autodiff_illegal.rs:167:1 | LL | struct DoesNotImplDefault; | ------------------------- doesn't satisfy `DoesNotImplDefault: Default` -LL | #[autodiff(df22, Forward, Dual)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function or associated item cannot be called on `(DoesNotImplDefault, DoesNotImplDefault)` due to unsatisfied trait bounds +LL | #[autodiff_forward(df22, Dual)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function or associated item cannot be called on `(DoesNotImplDefault, DoesNotImplDefault)` due to unsatisfied trait bounds | = note: the following trait bounds were not satisfied: `DoesNotImplDefault: Default` @@ -168,7 +153,7 @@ LL + #[derive(Default)] LL | struct DoesNotImplDefault; | -error: aborting due to 23 previous errors +error: aborting due to 21 previous errors Some errors have detailed explanations: E0428, E0433, E0599, E0658. For more information about an error, try `rustc --explain E0428`. diff --git a/tests/ui/autodiff/auxiliary/my_macro.rs b/tests/ui/autodiff/auxiliary/my_macro.rs index 217631a33c9bc..1d5a6de145483 100644 --- a/tests/ui/autodiff/auxiliary/my_macro.rs +++ b/tests/ui/autodiff/auxiliary/my_macro.rs @@ -3,6 +3,6 @@ use proc_macro::TokenStream; #[proc_macro_attribute] #[macro_use] -pub fn autodiff(_attr: TokenStream, item: TokenStream) -> TokenStream { +pub fn autodiff_forward(_attr: TokenStream, item: TokenStream) -> TokenStream { item // identity proc-macro } diff --git a/tests/ui/autodiff/visibility.rs b/tests/ui/autodiff/visibility.rs index dfaec03aef01f..a84df75e79966 100644 --- a/tests/ui/autodiff/visibility.rs +++ b/tests/ui/autodiff/visibility.rs @@ -6,12 +6,11 @@ #![feature(autodiff)] #[cfg(std_autodiff)] -use std::autodiff::autodiff; - +use std::autodiff::autodiff_forward; extern crate my_macro; -use my_macro::autodiff; // bring `autodiff` in scope +use my_macro::autodiff_forward; // bring `autodiff_forward` in scope -#[autodiff] -//[std_autodiff]~^^^ ERROR the name `autodiff` is defined multiple times +#[autodiff_forward(dfoo)] +//[std_autodiff]~^^^ ERROR the name `autodiff_forward` is defined multiple times //[std_autodiff]~^^ ERROR this rustc version does not support autodiff fn foo() {} diff --git a/tests/ui/autodiff/visibility.std_autodiff.stderr b/tests/ui/autodiff/visibility.std_autodiff.stderr index 720c9a00170e9..e45f1139012a6 100644 --- a/tests/ui/autodiff/visibility.std_autodiff.stderr +++ b/tests/ui/autodiff/visibility.std_autodiff.stderr @@ -1,23 +1,23 @@ -error[E0252]: the name `autodiff` is defined multiple times - --> $DIR/visibility.rs:12:5 +error[E0252]: the name `autodiff_forward` is defined multiple times + --> $DIR/visibility.rs:11:5 | -LL | use std::autodiff::autodiff; - | ----------------------- previous import of the macro `autodiff` here -... -LL | use my_macro::autodiff; // bring `autodiff` in scope - | ^^^^^^^^^^^^^^^^^^ `autodiff` reimported here +LL | use std::autodiff::autodiff_forward; + | ------------------------------- previous import of the macro `autodiff_forward` here +LL | extern crate my_macro; +LL | use my_macro::autodiff_forward; // bring `autodiff_forward` in scope + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `autodiff_forward` reimported here | - = note: `autodiff` must be defined only once in the macro namespace of this module + = note: `autodiff_forward` must be defined only once in the macro namespace of this module help: you can use `as` to change the binding name of the import | -LL | use my_macro::autodiff as other_autodiff; // bring `autodiff` in scope - | +++++++++++++++++ +LL | use my_macro::autodiff_forward as other_autodiff_forward; // bring `autodiff_forward` in scope + | +++++++++++++++++++++++++ error: this rustc version does not support autodiff - --> $DIR/visibility.rs:14:1 + --> $DIR/visibility.rs:13:1 | -LL | #[autodiff] - | ^^^^^^^^^^^ +LL | #[autodiff_forward(dfoo)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/feature-gates/feature-gate-autodiff-use.has_support.stderr b/tests/ui/feature-gates/feature-gate-autodiff-use.has_support.stderr index 15ef257fbd84d..e5edd8e45e6c2 100644 --- a/tests/ui/feature-gates/feature-gate-autodiff-use.has_support.stderr +++ b/tests/ui/feature-gates/feature-gate-autodiff-use.has_support.stderr @@ -1,8 +1,8 @@ error[E0658]: use of unstable library feature `autodiff` --> $DIR/feature-gate-autodiff-use.rs:13:3 | -LL | #[autodiff(dfoo, Reverse)] - | ^^^^^^^^ +LL | #[autodiff_reverse(dfoo)] + | ^^^^^^^^^^^^^^^^ | = note: see issue #124509 for more information = help: add `#![feature(autodiff)]` to the crate attributes to enable @@ -11,8 +11,8 @@ LL | #[autodiff(dfoo, Reverse)] error[E0658]: use of unstable library feature `autodiff` --> $DIR/feature-gate-autodiff-use.rs:9:5 | -LL | use std::autodiff::autodiff; - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | use std::autodiff::autodiff_reverse; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #124509 for more information = help: add `#![feature(autodiff)]` to the crate attributes to enable diff --git a/tests/ui/feature-gates/feature-gate-autodiff-use.no_support.stderr b/tests/ui/feature-gates/feature-gate-autodiff-use.no_support.stderr index f59e495545202..65ba033b3589c 100644 --- a/tests/ui/feature-gates/feature-gate-autodiff-use.no_support.stderr +++ b/tests/ui/feature-gates/feature-gate-autodiff-use.no_support.stderr @@ -1,8 +1,8 @@ error[E0658]: use of unstable library feature `autodiff` --> $DIR/feature-gate-autodiff-use.rs:13:3 | -LL | #[autodiff(dfoo, Reverse)] - | ^^^^^^^^ +LL | #[autodiff_reverse(dfoo)] + | ^^^^^^^^^^^^^^^^ | = note: see issue #124509 for more information = help: add `#![feature(autodiff)]` to the crate attributes to enable @@ -11,14 +11,14 @@ LL | #[autodiff(dfoo, Reverse)] error: this rustc version does not support autodiff --> $DIR/feature-gate-autodiff-use.rs:13:1 | -LL | #[autodiff(dfoo, Reverse)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[autodiff_reverse(dfoo)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0658]: use of unstable library feature `autodiff` --> $DIR/feature-gate-autodiff-use.rs:9:5 | -LL | use std::autodiff::autodiff; - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | use std::autodiff::autodiff_reverse; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #124509 for more information = help: add `#![feature(autodiff)]` to the crate attributes to enable diff --git a/tests/ui/feature-gates/feature-gate-autodiff-use.rs b/tests/ui/feature-gates/feature-gate-autodiff-use.rs index 602e830b0b21c..2864b786c121f 100644 --- a/tests/ui/feature-gates/feature-gate-autodiff-use.rs +++ b/tests/ui/feature-gates/feature-gate-autodiff-use.rs @@ -6,11 +6,11 @@ #![crate_type = "lib"] -use std::autodiff::autodiff; +use std::autodiff::autodiff_reverse; //[has_support]~^ ERROR use of unstable library feature `autodiff` //[no_support]~^^ ERROR use of unstable library feature `autodiff` -#[autodiff(dfoo, Reverse)] +#[autodiff_reverse(dfoo)] //[has_support]~^ ERROR use of unstable library feature `autodiff` [E0658] //[no_support]~^^ ERROR use of unstable library feature `autodiff` [E0658] //[no_support]~| ERROR this rustc version does not support autodiff diff --git a/tests/ui/feature-gates/feature-gate-autodiff.has_support.stderr b/tests/ui/feature-gates/feature-gate-autodiff.has_support.stderr index c25cf7d337371..dcbaba716459b 100644 --- a/tests/ui/feature-gates/feature-gate-autodiff.has_support.stderr +++ b/tests/ui/feature-gates/feature-gate-autodiff.has_support.stderr @@ -1,12 +1,12 @@ -error: cannot find attribute `autodiff` in this scope +error: cannot find attribute `autodiff_reverse` in this scope --> $DIR/feature-gate-autodiff.rs:9:3 | -LL | #[autodiff(dfoo, Reverse)] - | ^^^^^^^^ +LL | #[autodiff_reverse(dfoo)] + | ^^^^^^^^^^^^^^^^ | help: consider importing this attribute macro | -LL + use std::autodiff::autodiff; +LL + use std::autodiff::autodiff_reverse; | error: aborting due to 1 previous error diff --git a/tests/ui/feature-gates/feature-gate-autodiff.no_support.stderr b/tests/ui/feature-gates/feature-gate-autodiff.no_support.stderr index c25cf7d337371..dcbaba716459b 100644 --- a/tests/ui/feature-gates/feature-gate-autodiff.no_support.stderr +++ b/tests/ui/feature-gates/feature-gate-autodiff.no_support.stderr @@ -1,12 +1,12 @@ -error: cannot find attribute `autodiff` in this scope +error: cannot find attribute `autodiff_reverse` in this scope --> $DIR/feature-gate-autodiff.rs:9:3 | -LL | #[autodiff(dfoo, Reverse)] - | ^^^^^^^^ +LL | #[autodiff_reverse(dfoo)] + | ^^^^^^^^^^^^^^^^ | help: consider importing this attribute macro | -LL + use std::autodiff::autodiff; +LL + use std::autodiff::autodiff_reverse; | error: aborting due to 1 previous error diff --git a/tests/ui/feature-gates/feature-gate-autodiff.rs b/tests/ui/feature-gates/feature-gate-autodiff.rs index 4249b229a6985..adb35cb8e3356 100644 --- a/tests/ui/feature-gates/feature-gate-autodiff.rs +++ b/tests/ui/feature-gates/feature-gate-autodiff.rs @@ -6,7 +6,7 @@ // This checks that without the autodiff feature enabled, we can't use it. -#[autodiff(dfoo, Reverse)] -//[has_support]~^ ERROR cannot find attribute `autodiff` in this scope -//[no_support]~^^ ERROR cannot find attribute `autodiff` in this scope +#[autodiff_reverse(dfoo)] +//[has_support]~^ ERROR cannot find attribute `autodiff_reverse` in this scope +//[no_support]~^^ ERROR cannot find attribute `autodiff_reverse` in this scope fn foo() {} From 8917ff602446372e45abed7ab3a58dc879638b1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= Date: Tue, 20 May 2025 12:36:12 +0000 Subject: [PATCH 2549/4206] Update generic tests --- tests/codegen/autodiff/generic.rs | 4 ++-- tests/pretty/autodiff/autodiff_forward.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/codegen/autodiff/generic.rs b/tests/codegen/autodiff/generic.rs index 15e7d8a495745..2f674079be021 100644 --- a/tests/codegen/autodiff/generic.rs +++ b/tests/codegen/autodiff/generic.rs @@ -3,9 +3,9 @@ //@ needs-enzyme #![feature(autodiff)] -use std::autodiff::autodiff; +use std::autodiff::autodiff_reverse; -#[autodiff(d_square, Reverse, Duplicated, Active)] +#[autodiff_reverse(d_square, Duplicated, Active)] fn square + Copy>(x: &T) -> T { *x * *x } diff --git a/tests/pretty/autodiff/autodiff_forward.rs b/tests/pretty/autodiff/autodiff_forward.rs index 181b6ebc77048..e23a1b3e241e9 100644 --- a/tests/pretty/autodiff/autodiff_forward.rs +++ b/tests/pretty/autodiff/autodiff_forward.rs @@ -64,7 +64,7 @@ pub fn f9() { } // Make sure we can handle generics -#[autodiff(d_square, Reverse, Duplicated, Active)] +#[autodiff_reverse(d_square, Duplicated, Active)] pub fn f10 + Copy>(x: &T) -> T { *x * *x } From 84f67a5e51bf1695a0c368a9f44a15f15cdf6b9e Mon Sep 17 00:00:00 2001 From: xizheyin Date: Wed, 21 May 2025 16:19:51 +0800 Subject: [PATCH 2550/4206] Downgrade the confident of suggestion `available field in format string` and optimize expression Signed-off-by: xizheyin --- compiler/rustc_resolve/src/late/diagnostics.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 30c2125d0b66a..80d7a4dd47ac8 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -753,15 +753,9 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if self_is_available { let source_map = self.r.tcx.sess.source_map(); // check if the field is used in a format string, such as `"{x}"` - let field_is_format_named_arg = - source_map.span_to_source(span, |s, start, _| { - if let Some(expanded_expr) = s.get(start - 1..start) - && expanded_expr.starts_with("{") - { - Ok(true) - } else { - Ok(false) - } + let field_is_format_named_arg = source_map + .span_to_source(span, |s, start, _| { + Ok(s.get(start - 1..start) == Some("{")) }); if let Ok(true) = field_is_format_named_arg { err.help( @@ -772,7 +766,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { span.shrink_to_lo(), "you might have meant to use the available field", format!("{pre}self."), - Applicability::MachineApplicable, + Applicability::MaybeIncorrect, ); } } else { From 1cc0e38fdc4d2ec8c9c130d7ffc9c30d100885a2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 21 May 2025 13:28:08 +1000 Subject: [PATCH 2551/4206] Avoid creating an empty identifer in `Symbol::to_ident_string`. Because that causes an assertion failure in debug builds. Fixes #140884. --- compiler/rustc_span/src/symbol.rs | 3 ++- tests/crashes/140884.rs | 6 ------ .../ui/extern/extern-empty-string-issue-140884.rs | 3 +++ .../extern-empty-string-issue-140884.stderr | 15 +++++++++++++++ 4 files changed, 20 insertions(+), 7 deletions(-) delete mode 100644 tests/crashes/140884.rs create mode 100644 tests/ui/extern/extern-empty-string-issue-140884.rs create mode 100644 tests/ui/extern/extern-empty-string-issue-140884.stderr diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index efae6250b0720..fbe3b4ca6f5f6 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2592,7 +2592,8 @@ impl Symbol { /// (`token_to_string`, `Ident::to_string`), except that symbols don't keep the rawness flag /// or edition, so we have to guess the rawness using the global edition. pub fn to_ident_string(self) -> String { - Ident::with_dummy_span(self).to_string() + // Avoid creating an empty identifier, because that asserts in debug builds. + if self == kw::Empty { String::new() } else { Ident::with_dummy_span(self).to_string() } } } diff --git a/tests/crashes/140884.rs b/tests/crashes/140884.rs deleted file mode 100644 index 6840760933a39..0000000000000 --- a/tests/crashes/140884.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ known-bug: #140884 -//@ needs-rustc-debug-assertions - -fn a() { - extern "" {} -} diff --git a/tests/ui/extern/extern-empty-string-issue-140884.rs b/tests/ui/extern/extern-empty-string-issue-140884.rs new file mode 100644 index 0000000000000..10291513d34d2 --- /dev/null +++ b/tests/ui/extern/extern-empty-string-issue-140884.rs @@ -0,0 +1,3 @@ +extern "" {} //~ ERROR invalid ABI: found `` + +fn main() {} diff --git a/tests/ui/extern/extern-empty-string-issue-140884.stderr b/tests/ui/extern/extern-empty-string-issue-140884.stderr new file mode 100644 index 0000000000000..accae0c0f7c73 --- /dev/null +++ b/tests/ui/extern/extern-empty-string-issue-140884.stderr @@ -0,0 +1,15 @@ +error[E0703]: invalid ABI: found `` + --> $DIR/extern-empty-string-issue-140884.rs:1:8 + | +LL | extern "" {} + | ^^ invalid ABI + | + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions +help: there's a similarly named valid ABI `C` + | +LL | extern "C" {} + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0703`. From 44a2af306825dcfa9fc28547e6ccea1cb5076c68 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 21 May 2025 09:17:47 +0000 Subject: [PATCH 2552/4206] Do not eagerly fold consts in normalize_param_env_or_error if new solver --- compiler/rustc_trait_selection/src/traits/mod.rs | 4 +--- tests/ui/traits/next-solver/no-param-env-const-fold.rs | 10 ++++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 tests/ui/traits/next-solver/no-param-env-const-fold.rs diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 31b075db04b96..f73603c00539d 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -340,7 +340,7 @@ pub fn normalize_param_env_or_error<'tcx>( let mut predicates: Vec<_> = util::elaborate( tcx, unnormalized_env.caller_bounds().into_iter().map(|predicate| { - if tcx.features().generic_const_exprs() { + if tcx.features().generic_const_exprs() || tcx.next_trait_solver_globally() { return predicate; } @@ -405,8 +405,6 @@ pub fn normalize_param_env_or_error<'tcx>( // compatibility. Eventually when lazy norm is implemented this can just be removed. // We do not normalize types here as there is no backwards compatibility requirement // for us to do so. - // - // FIXME(-Znext-solver): remove this hack since we have deferred projection equality predicate.fold_with(&mut ConstNormalizer(tcx)) }), ) diff --git a/tests/ui/traits/next-solver/no-param-env-const-fold.rs b/tests/ui/traits/next-solver/no-param-env-const-fold.rs new file mode 100644 index 0000000000000..4f47332dd23ae --- /dev/null +++ b/tests/ui/traits/next-solver/no-param-env-const-fold.rs @@ -0,0 +1,10 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +// Regression test for . + +use std::ops::Deref; + +trait Trait: Deref {} + +fn main() {} From ad59f0b6e6e5c45ea64064758a88e8521259bfcf Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 21 May 2025 10:02:54 +0000 Subject: [PATCH 2553/4206] Use DeepRejectCtxt in assemble_inherent_candidates_from_param --- compiler/rustc_hir_typeck/src/lib.rs | 1 + compiler/rustc_hir_typeck/src/method/probe.rs | 23 +++++++-------- ...am-method-from-unnormalized-param-env-2.rs | 29 +++++++++++++++++++ ...aram-method-from-unnormalized-param-env.rs | 17 +++++++++++ 4 files changed, 58 insertions(+), 12 deletions(-) create mode 100644 tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env-2.rs create mode 100644 tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env.rs diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 161f5e981d430..a7444b45ab0f2 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -2,6 +2,7 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] #![feature(array_windows)] +#![feature(assert_matches)] #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(iter_intersperse)] diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 6090c0f9aee22..725240b480ba9 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1,3 +1,4 @@ +use std::assert_matches::debug_assert_matches; use std::cell::{Cell, RefCell}; use std::cmp::max; use std::ops::Deref; @@ -16,7 +17,7 @@ use rustc_infer::traits::ObligationCauseCode; use rustc_middle::middle::stability; use rustc_middle::query::Providers; use rustc_middle::ty::elaborate::supertrait_def_ids; -use rustc_middle::ty::fast_reject::{TreatParams, simplify_type}; +use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, simplify_type}; use rustc_middle::ty::{ self, AssocItem, AssocItemContainer, GenericArgs, GenericArgsRef, GenericParamDefKind, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt, Upcast, @@ -807,8 +808,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { ); } } - ty::Param(p) => { - self.assemble_inherent_candidates_from_param(p); + ty::Param(_) => { + self.assemble_inherent_candidates_from_param(raw_self_ty); } ty::Bool | ty::Char @@ -909,18 +910,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } #[instrument(level = "debug", skip(self))] - fn assemble_inherent_candidates_from_param(&mut self, param_ty: ty::ParamTy) { + fn assemble_inherent_candidates_from_param(&mut self, param_ty: Ty<'tcx>) { + debug_assert_matches!(param_ty.kind(), ty::Param(_)); + + let tcx = self.tcx; let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| { let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { - ty::ClauseKind::Trait(trait_predicate) => { - match *trait_predicate.trait_ref.self_ty().kind() { - ty::Param(p) if p == param_ty => { - Some(bound_predicate.rebind(trait_predicate.trait_ref)) - } - _ => None, - } - } + ty::ClauseKind::Trait(trait_predicate) => DeepRejectCtxt::relate_rigid_rigid(tcx) + .types_may_unify(param_ty, trait_predicate.trait_ref.self_ty()) + .then(|| bound_predicate.rebind(trait_predicate.trait_ref)), ty::ClauseKind::RegionOutlives(_) | ty::ClauseKind::TypeOutlives(_) | ty::ClauseKind::Projection(_) diff --git a/tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env-2.rs b/tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env-2.rs new file mode 100644 index 0000000000000..ffb99d6d63855 --- /dev/null +++ b/tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env-2.rs @@ -0,0 +1,29 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +// Regression test for . +// See comment below. + +trait A { + fn hello(&self) {} +} + +trait B { + fn hello(&self) {} +} + +impl A for T {} +impl B for T {} + +fn test(q: F::Item) +where + F: Iterator, + // We want to prefer `A` for `R.hello()` + F::Item: A, +{ + q.hello(); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env.rs b/tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env.rs new file mode 100644 index 0000000000000..dde4f745879e4 --- /dev/null +++ b/tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env.rs @@ -0,0 +1,17 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +// Regression test for . + +fn execute(q: F::Item) -> R +where + F: Iterator, + // Both of the below bounds should be considered for `.into()`, and then be combined + // into a single `R: Into` bound which can be inferred to `?0 = R`. + F::Item: Into, + R: Into, +{ + q.into() +} + +fn main() {} From 196c3b3ef40a84a05d265f4ec599cbe157cc5cb6 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 21 May 2025 10:02:30 +0000 Subject: [PATCH 2554/4206] eagerly check nested obligations when coercing fndefs --- compiler/rustc_hir_typeck/src/coercion.rs | 20 ++++++++++++++++--- .../src/traits/engine.rs | 14 +++++++++++++ .../coerce-ambig-alias-to-rigid-alias.rs | 0 .../{ => coercion}/coerce-depth.rs | 0 .../fn-def-coerce-nested-obligations.rs | 16 +++++++++++++++ .../non-wf-in-coerce-pointers.rs | 0 .../non-wf-in-coerce-pointers.stderr | 0 .../trait-upcast-lhs-needs-normalization.rs | 0 .../{ => coercion}/upcast-right-substs.rs | 0 .../{ => coercion}/upcast-wrong-substs.rs | 0 .../{ => coercion}/upcast-wrong-substs.stderr | 0 11 files changed, 47 insertions(+), 3 deletions(-) rename tests/ui/traits/next-solver/{ => coercion}/coerce-ambig-alias-to-rigid-alias.rs (100%) rename tests/ui/traits/next-solver/{ => coercion}/coerce-depth.rs (100%) create mode 100644 tests/ui/traits/next-solver/coercion/fn-def-coerce-nested-obligations.rs rename tests/ui/traits/next-solver/{ => coercion}/non-wf-in-coerce-pointers.rs (100%) rename tests/ui/traits/next-solver/{ => coercion}/non-wf-in-coerce-pointers.stderr (100%) rename tests/ui/traits/next-solver/{ => coercion}/trait-upcast-lhs-needs-normalization.rs (100%) rename tests/ui/traits/next-solver/{ => coercion}/upcast-right-substs.rs (100%) rename tests/ui/traits/next-solver/{ => coercion}/upcast-wrong-substs.rs (100%) rename tests/ui/traits/next-solver/{ => coercion}/upcast-wrong-substs.stderr (100%) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index d2fc5ae05434a..9c07f97a73400 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1190,9 +1190,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (ty::FnDef(..), ty::FnDef(..)) => { // Don't reify if the function types have a LUB, i.e., they // are the same function and their parameters have a LUB. - match self - .commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty)) - { + match self.commit_if_ok(|_| { + // We need to eagerly handle nested obligations due to lazy norm. + if self.next_trait_solver() { + let ocx = ObligationCtxt::new(self); + let value = ocx.lub(cause, self.param_env, prev_ty, new_ty)?; + if ocx.select_where_possible().is_empty() { + Ok(InferOk { + value, + obligations: ocx.into_pending_obligations(), + }) + } else { + Err(TypeError::Mismatch) + } + } else { + self.at(cause, self.param_env).lub(prev_ty, new_ty) + } + }) { // We have a LUB of prev_ty and new_ty, just return it. Ok(ok) => return Ok(self.register_infer_ok_obligations(ok)), Err(_) => { diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 8d6e6b4a65165..18f28d72f6f8f 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -188,6 +188,20 @@ where .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } + /// Computes the least-upper-bound, or mutual supertype, of two values. + pub fn lub>( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + expected: T, + actual: T, + ) -> Result> { + self.infcx + .at(cause, param_env) + .lub(expected, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + } + #[must_use] pub fn select_where_possible(&self) -> Vec { self.engine.borrow_mut().select_where_possible(self.infcx) diff --git a/tests/ui/traits/next-solver/coerce-ambig-alias-to-rigid-alias.rs b/tests/ui/traits/next-solver/coercion/coerce-ambig-alias-to-rigid-alias.rs similarity index 100% rename from tests/ui/traits/next-solver/coerce-ambig-alias-to-rigid-alias.rs rename to tests/ui/traits/next-solver/coercion/coerce-ambig-alias-to-rigid-alias.rs diff --git a/tests/ui/traits/next-solver/coerce-depth.rs b/tests/ui/traits/next-solver/coercion/coerce-depth.rs similarity index 100% rename from tests/ui/traits/next-solver/coerce-depth.rs rename to tests/ui/traits/next-solver/coercion/coerce-depth.rs diff --git a/tests/ui/traits/next-solver/coercion/fn-def-coerce-nested-obligations.rs b/tests/ui/traits/next-solver/coercion/fn-def-coerce-nested-obligations.rs new file mode 100644 index 0000000000000..1b5abcb02f2f8 --- /dev/null +++ b/tests/ui/traits/next-solver/coercion/fn-def-coerce-nested-obligations.rs @@ -0,0 +1,16 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// Make sure that we consider nested obligations when checking whether +// we should coerce fn definitions to function pointers. + +fn foo() {} +fn bar() {} +fn main() { + let _ = if true { foo::<{ 0 + 0 }> } else { foo::<1> }; + let _ = if true { + bar:: fn( as IntoIterator>::Item)> + } else { + bar:: + }; +} diff --git a/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.rs b/tests/ui/traits/next-solver/coercion/non-wf-in-coerce-pointers.rs similarity index 100% rename from tests/ui/traits/next-solver/non-wf-in-coerce-pointers.rs rename to tests/ui/traits/next-solver/coercion/non-wf-in-coerce-pointers.rs diff --git a/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr b/tests/ui/traits/next-solver/coercion/non-wf-in-coerce-pointers.stderr similarity index 100% rename from tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr rename to tests/ui/traits/next-solver/coercion/non-wf-in-coerce-pointers.stderr diff --git a/tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs b/tests/ui/traits/next-solver/coercion/trait-upcast-lhs-needs-normalization.rs similarity index 100% rename from tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs rename to tests/ui/traits/next-solver/coercion/trait-upcast-lhs-needs-normalization.rs diff --git a/tests/ui/traits/next-solver/upcast-right-substs.rs b/tests/ui/traits/next-solver/coercion/upcast-right-substs.rs similarity index 100% rename from tests/ui/traits/next-solver/upcast-right-substs.rs rename to tests/ui/traits/next-solver/coercion/upcast-right-substs.rs diff --git a/tests/ui/traits/next-solver/upcast-wrong-substs.rs b/tests/ui/traits/next-solver/coercion/upcast-wrong-substs.rs similarity index 100% rename from tests/ui/traits/next-solver/upcast-wrong-substs.rs rename to tests/ui/traits/next-solver/coercion/upcast-wrong-substs.rs diff --git a/tests/ui/traits/next-solver/upcast-wrong-substs.stderr b/tests/ui/traits/next-solver/coercion/upcast-wrong-substs.stderr similarity index 100% rename from tests/ui/traits/next-solver/upcast-wrong-substs.stderr rename to tests/ui/traits/next-solver/coercion/upcast-wrong-substs.stderr From 78d3ea14f700037860db6cf98728cede523c7aad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 20 May 2025 15:16:16 +0200 Subject: [PATCH 2555/4206] Add bors environment to CI This will be used to access secrets once we move off rust-lang-ci. --- .github/workflows/ci.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 93316b9cff7b1..0bce8389d8ec2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,6 +73,15 @@ jobs: needs: [ calculate_matrix ] runs-on: "${{ matrix.os }}" timeout-minutes: 360 + # The bors environment contains secrets required for elevated workflows (try and auto builds), + # which need to access e.g. S3 and upload artifacts. We want to provide access to that + # environment only on the try/auto branches, which are only accessible to bors. + # This also ensures that PR CI (which doesn't get write access to S3) works, as it cannot + # access the environment. + # + # We only enable the environment for the rust-lang/rust repository, so that rust-lang-ci/rust + # CI works until we migrate off it (since that repository doesn't contain the environment). + environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/auto')) && 'bors') || '' }} env: CI_JOB_NAME: ${{ matrix.name }} CI_JOB_DOC_URL: ${{ matrix.doc_url }} From dc794f18a425a20563943ea4201b34ebea2aa017 Mon Sep 17 00:00:00 2001 From: Andrew Zhogin Date: Wed, 21 May 2025 15:21:01 +0700 Subject: [PATCH 2556/4206] When AsyncDrop impl is empty, sync drop generated in elaborator (Fixes #140974) --- .../rustc_mir_transform/src/elaborate_drop.rs | 24 ++++++++++++++++++- .../elaborate-index-out-of-bounds.rs} | 7 ++++-- .../elaborate-index-out-of-bounds.stderr | 11 +++++++++ 3 files changed, 39 insertions(+), 3 deletions(-) rename tests/{crashes/140974.rs => ui/async-await/async-drop/elaborate-index-out-of-bounds.rs} (62%) create mode 100644 tests/ui/async-await/async-drop/elaborate-index-out-of-bounds.stderr diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index 73a58160a6aac..5d86b1353c07b 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -251,7 +251,29 @@ where span_bug!(span, "invalid `AsyncDrop` impl_source: {:?}", impl_source); } }; - let drop_fn_def_id = tcx.associated_item_def_ids(drop_trait)[0]; + // impl_item_refs may be empty if drop fn is not implemented in 'impl AsyncDrop for ...' + // (#140974). + // Such code will report error, so just generate sync drop here and return + let Some(drop_fn_def_id) = + tcx.associated_item_def_ids(drop_trait).into_iter().nth(0).copied() + else { + tcx.dcx().span_delayed_bug( + self.elaborator.body().span, + "AsyncDrop type without correct `async fn drop(...)`.", + ); + self.elaborator.patch().patch_terminator( + pin_obj_bb, + TerminatorKind::Drop { + place, + target: succ, + unwind: unwind.into_action(), + replace: false, + drop: None, + async_fut: None, + }, + ); + return pin_obj_bb; + }; let drop_fn = Ty::new_fn_def(tcx, drop_fn_def_id, trait_args); let sig = drop_fn.fn_sig(tcx); let sig = tcx.instantiate_bound_regions_with_erased(sig); diff --git a/tests/crashes/140974.rs b/tests/ui/async-await/async-drop/elaborate-index-out-of-bounds.rs similarity index 62% rename from tests/crashes/140974.rs rename to tests/ui/async-await/async-drop/elaborate-index-out-of-bounds.rs index ac1051a64fd31..bd0a95eb1e497 100644 --- a/tests/crashes/140974.rs +++ b/tests/ui/async-await/async-drop/elaborate-index-out-of-bounds.rs @@ -1,5 +1,7 @@ -//@ known-bug: #140974 -//@edition:2021 +//@ edition: 2024 +// Ex-ICE: #140974 +#![crate_type = "lib"] +#![allow(incomplete_features)] #![feature(async_drop)] use core::future::AsyncDrop; @@ -10,5 +12,6 @@ impl Drop for HasIncompleteAsyncDrop { fn drop(&mut self) {} } impl AsyncDrop for HasIncompleteAsyncDrop { + //~^ ERROR: not all trait items implemented, missing: `drop` [E0046] // not implemented yet.. } diff --git a/tests/ui/async-await/async-drop/elaborate-index-out-of-bounds.stderr b/tests/ui/async-await/async-drop/elaborate-index-out-of-bounds.stderr new file mode 100644 index 0000000000000..d8582398c797e --- /dev/null +++ b/tests/ui/async-await/async-drop/elaborate-index-out-of-bounds.stderr @@ -0,0 +1,11 @@ +error[E0046]: not all trait items implemented, missing: `drop` + --> $DIR/elaborate-index-out-of-bounds.rs:14:1 + | +LL | impl AsyncDrop for HasIncompleteAsyncDrop { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `drop` in implementation + | + = help: implement the missing item: `async fn drop(self: Pin<&mut Self>) { todo!() }` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0046`. From 7c38b6fd28b1972659b662683866c359f198a6f7 Mon Sep 17 00:00:00 2001 From: Andrew Zhogin Date: Tue, 20 May 2025 22:36:03 +0700 Subject: [PATCH 2557/4206] Async drop fix for 'broken mir in AsyncDropGlue, place has deref as a later projection' (#140975) --- .../rustc_mir_transform/src/elaborate_drop.rs | 21 ++++++++++++------- .../async-drop/deref-later-projection.rs} | 10 ++++++--- 2 files changed, 20 insertions(+), 11 deletions(-) rename tests/{crashes/140975.rs => ui/async-await/async-drop/deref-later-projection.rs} (70%) diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index 73a58160a6aac..61312eb7d1ae6 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -318,15 +318,20 @@ where bug!(); }; let obj_ptr_ty = Ty::new_mut_ptr(tcx, drop_ty); - let obj_ptr_place = Place::from(self.new_temp(obj_ptr_ty)); let unwrap_ty = adt_def.non_enum_variant().fields[FieldIdx::ZERO].ty(tcx, adt_args); - let addr = Rvalue::RawPtr( - RawPtrKind::Mut, - pin_obj_place.project_deeper( - &[ProjectionElem::Field(FieldIdx::ZERO, unwrap_ty), ProjectionElem::Deref], - tcx, - ), - ); + let obj_ref_place = Place::from(self.new_temp(unwrap_ty)); + call_statements.push(self.assign( + obj_ref_place, + Rvalue::Use(Operand::Copy(tcx.mk_place_field( + pin_obj_place, + FieldIdx::ZERO, + unwrap_ty, + ))), + )); + + let obj_ptr_place = Place::from(self.new_temp(obj_ptr_ty)); + + let addr = Rvalue::RawPtr(RawPtrKind::Mut, tcx.mk_place_deref(obj_ref_place)); call_statements.push(self.assign(obj_ptr_place, addr)); obj_ptr_place }; diff --git a/tests/crashes/140975.rs b/tests/ui/async-await/async-drop/deref-later-projection.rs similarity index 70% rename from tests/crashes/140975.rs rename to tests/ui/async-await/async-drop/deref-later-projection.rs index e11dd40612cef..baf81daf766b6 100644 --- a/tests/crashes/140975.rs +++ b/tests/ui/async-await/async-drop/deref-later-projection.rs @@ -1,7 +1,11 @@ -//@ known-bug: #140975 -//@ compile-flags: --crate-type lib -Zvalidate-mir -//@ edition: 2021 +// Ex-ICE: #140975 +//@ compile-flags: -Zvalidate-mir +//@ build-pass +//@ edition:2021 +#![crate_type = "lib"] #![feature(async_drop)] +#![allow(incomplete_features)] + use std::{future::AsyncDrop, pin::Pin}; struct HasAsyncDrop ; From 4502ae8c69f7f672108a64181c1f15013fafa9c4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 May 2025 13:41:58 +0200 Subject: [PATCH 2558/4206] bump stdarch --- library/stdarch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch b/library/stdarch index 1dfaa4db24797..b6e2249e388f5 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit 1dfaa4db2479753a46a3e90f2c3c89d89d0b21f1 +Subproject commit b6e2249e388f520627544812649b77b0944e1a2e From 8a28b797b88e2980c40316cce230c4f560538cd0 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Wed, 21 May 2025 14:50:18 +0200 Subject: [PATCH 2559/4206] Bump nightly version -> 2025-05-21 --- clippy_dev/src/sync.rs | 13 ++++++++++--- clippy_utils/README.md | 2 +- rust-toolchain.toml | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/clippy_dev/src/sync.rs b/clippy_dev/src/sync.rs index c699b0d7b959c..98fd72fc0bd1a 100644 --- a/clippy_dev/src/sync.rs +++ b/clippy_dev/src/sync.rs @@ -4,15 +4,22 @@ use std::fmt::Write; pub fn update_nightly() { let date = Utc::now().format("%Y-%m-%d").to_string(); - let update = &mut update_text_region_fn( + let toolchain_update = &mut update_text_region_fn( "# begin autogenerated nightly\n", "# end autogenerated nightly", |dst| { writeln!(dst, "channel = \"nightly-{date}\"").unwrap(); }, ); + let readme_update = &mut update_text_region_fn( + "\n", + "", + |dst| { + writeln!(dst, "```\nnightly-{date}\n```").unwrap(); + }, + ); let mut updater = FileUpdater::default(); - updater.update_file("rust-toolchain.toml", update); - updater.update_file("clippy_utils/README.md", update); + updater.update_file("rust-toolchain.toml", toolchain_update); + updater.update_file("clippy_utils/README.md", readme_update); } diff --git a/clippy_utils/README.md b/clippy_utils/README.md index d4080d06d3ca8..c9083f654c4cb 100644 --- a/clippy_utils/README.md +++ b/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: ``` -nightly-2025-05-14 +nightly-2025-05-21 ``` diff --git a/rust-toolchain.toml b/rust-toolchain.toml index da41bdd27bcb6..0b9ebe554f5b4 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2025-05-14" +channel = "nightly-2025-05-21" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" From e36dc78edd4f166953afc0530500d589894ac412 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 27 Aug 2024 11:05:45 -0400 Subject: [PATCH 2560/4206] Add some track_caller info to precondition panics --- library/core/src/alloc/layout.rs | 1 + library/core/src/ascii/ascii_char.rs | 1 + library/core/src/char/convert.rs | 1 + library/core/src/hint.rs | 2 +- library/core/src/intrinsics/mod.rs | 2 +- library/core/src/num/int_macros.rs | 12 +++--- library/core/src/num/nonzero.rs | 2 + library/core/src/num/uint_macros.rs | 10 ++--- library/core/src/ops/index_range.rs | 1 + library/core/src/ptr/alignment.rs | 1 + library/core/src/ptr/const_ptr.rs | 26 ++++++------- library/core/src/ptr/mod.rs | 14 ++++--- library/core/src/ptr/mut_ptr.rs | 38 +++++++++---------- library/core/src/ptr/non_null.rs | 1 + library/core/src/slice/index.rs | 6 +++ library/core/src/slice/mod.rs | 8 ++++ library/core/src/slice/raw.rs | 3 ++ library/core/src/str/traits.rs | 4 ++ library/core/src/ub_checks.rs | 6 ++- .../tests/fail/ptr_swap_nonoverlapping.stderr | 5 +-- ...ng_operand.test.GVN.32bit.panic-abort.diff | 2 +- ...ng_operand.test.GVN.64bit.panic-abort.diff | 2 +- tests/mir-opt/inline/unchecked_shifts.rs | 4 +- ...l_unsigned_smaller.Inline.panic-abort.diff | 2 +- ..._unsigned_smaller.Inline.panic-unwind.diff | 2 +- ...d_smaller.PreCodegen.after.panic-abort.mir | 2 +- ..._smaller.PreCodegen.after.panic-unwind.mir | 2 +- ..._shr_signed_bigger.Inline.panic-abort.diff | 2 +- ...shr_signed_bigger.Inline.panic-unwind.diff | 2 +- ...ed_bigger.PreCodegen.after.panic-abort.mir | 2 +- ...d_bigger.PreCodegen.after.panic-unwind.mir | 2 +- ...d.unwrap_unchecked.Inline.panic-abort.diff | 2 +- ....unwrap_unchecked.Inline.panic-unwind.diff | 2 +- ...unchecked.PreCodegen.after.panic-abort.mir | 2 +- ...nchecked.PreCodegen.after.panic-unwind.mir | 2 +- ...hecked.InstSimplify-after-simplifycfg.diff | 2 +- ...ecked_shl.PreCodegen.after.panic-abort.mir | 2 +- ...cked_shl.PreCodegen.after.panic-unwind.mir | 2 +- ...witch_targets.ub_if_b.PreCodegen.after.mir | 2 +- .../loops.int_range.PreCodegen.after.mir | 2 +- ...e_add_fat.PreCodegen.after.panic-abort.mir | 4 +- ..._add_fat.PreCodegen.after.panic-unwind.mir | 4 +- ..._add_thin.PreCodegen.after.panic-abort.mir | 4 +- ...add_thin.PreCodegen.after.panic-unwind.mir | 4 +- ...ward_loop.PreCodegen.after.panic-abort.mir | 2 +- ...ard_loop.PreCodegen.after.panic-unwind.mir | 2 +- ...iter_next.PreCodegen.after.panic-abort.mir | 2 +- ...ter_next.PreCodegen.after.panic-unwind.mir | 2 +- ...mut_range.PreCodegen.after.panic-abort.mir | 4 +- ...ut_range.PreCodegen.after.panic-unwind.mir | 4 +- ...ked_range.PreCodegen.after.panic-abort.mir | 2 +- ...ed_range.PreCodegen.after.panic-unwind.mir | 2 +- ...ated_loop.PreCodegen.after.panic-abort.mir | 4 +- ...ted_loop.PreCodegen.after.panic-unwind.mir | 2 +- ...ward_loop.PreCodegen.after.panic-abort.mir | 4 +- ...ard_loop.PreCodegen.after.panic-unwind.mir | 4 +- ...ange_loop.PreCodegen.after.panic-abort.mir | 2 +- ...nge_loop.PreCodegen.after.panic-unwind.mir | 2 +- ...erse_loop.PreCodegen.after.panic-abort.mir | 2 +- ...rse_loop.PreCodegen.after.panic-unwind.mir | 2 +- ...iter_next.PreCodegen.after.panic-abort.mir | 2 +- ...ter_next.PreCodegen.after.panic-unwind.mir | 2 +- ..._to_slice.PreCodegen.after.panic-abort.mir | 2 +- ...to_slice.PreCodegen.after.panic-unwind.mir | 2 +- tests/ui/const-ptr/forbidden_slices.stderr | 21 ---------- tests/ui/const-ptr/out_of_bounds_read.stderr | 13 ------- tests/ui/consts/const-eval/raw-pointer-ub.rs | 1 - .../consts/const-eval/raw-pointer-ub.stderr | 6 +-- tests/ui/consts/const-eval/ub-ref-ptr.stderr | 5 --- .../ui/consts/const_unsafe_unreachable_ub.rs | 5 ++- .../consts/const_unsafe_unreachable_ub.stderr | 6 +-- tests/ui/consts/issue-miri-1910.stderr | 4 -- .../consts/missing_span_in_backtrace.stderr | 3 -- tests/ui/consts/offset_ub.stderr | 33 ---------------- .../interpret-in-promoted.noopt.stderr | 4 +- .../interpret-in-promoted.opt.stderr | 4 +- .../ui/print_type_sizes/niche-filling.stdout | 25 ++++++++++++ 77 files changed, 175 insertions(+), 207 deletions(-) diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index e8a03aadc3390..380f67f91f947 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -126,6 +126,7 @@ impl Layout { #[rustc_const_stable(feature = "const_alloc_layout_unchecked", since = "1.36.0")] #[must_use] #[inline] + #[track_caller] pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { assert_unsafe_precondition!( check_library_ub, diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs index 48de4f17b1b3a..0b72b4780f163 100644 --- a/library/core/src/ascii/ascii_char.rs +++ b/library/core/src/ascii/ascii_char.rs @@ -503,6 +503,7 @@ impl AsciiChar { /// something useful. It might be tightened before stabilization.) #[unstable(feature = "ascii_char", issue = "110998")] #[inline] + #[track_caller] pub const unsafe fn digit_unchecked(d: u8) -> Self { assert_unsafe_precondition!( check_language_ub, diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs index fd17f92f7be08..78cd89fefae71 100644 --- a/library/core/src/char/convert.rs +++ b/library/core/src/char/convert.rs @@ -22,6 +22,7 @@ pub(super) const fn from_u32(i: u32) -> Option { #[inline] #[must_use] #[allow(unnecessary_transmutes)] +#[track_caller] pub(super) const unsafe fn from_u32_unchecked(i: u32) -> char { // SAFETY: the caller must guarantee that `i` is a valid char value. unsafe { diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 6eefb30468931..435b610feb91a 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -98,7 +98,7 @@ use crate::{intrinsics, ub_checks}; #[inline] #[stable(feature = "unreachable", since = "1.27.0")] #[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces +#[track_caller] pub const unsafe fn unreachable_unchecked() -> ! { ub_checks::assert_unsafe_precondition!( check_language_ub, diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 23bafa778bc6b..ca9f4f38bf39a 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2634,7 +2634,7 @@ pub const fn three_way_compare(lhs: T, rhss: T) -> crate::cmp::Ordering #[rustc_const_unstable(feature = "disjoint_bitor", issue = "135758")] #[rustc_nounwind] #[rustc_intrinsic] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces +#[track_caller] #[miri::intrinsic_fallback_is_spec] // the fallbacks all `assume` to tell Miri pub const unsafe fn disjoint_bitor(a: T, b: T) -> T { // SAFETY: same preconditions as this function. diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 84e1482ed31db..f320a194271eb 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -555,7 +555,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn unchecked_add(self, rhs: Self) -> Self { assert_unsafe_precondition!( check_language_ub, @@ -705,7 +705,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self { assert_unsafe_precondition!( check_language_ub, @@ -855,7 +855,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self { assert_unsafe_precondition!( check_language_ub, @@ -1199,7 +1199,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn unchecked_neg(self) -> Self { assert_unsafe_precondition!( check_language_ub, @@ -1327,7 +1327,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self { assert_unsafe_precondition!( check_language_ub, @@ -1448,7 +1448,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self { assert_unsafe_precondition!( check_language_ub, diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 8a8b2733d5e88..a279f002772ea 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -388,6 +388,7 @@ where #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] #[must_use] #[inline] + #[track_caller] pub const unsafe fn new_unchecked(n: T) -> Self { match Self::new(n) { Some(n) => n, @@ -428,6 +429,7 @@ where #[unstable(feature = "nonzero_from_mut", issue = "106290")] #[must_use] #[inline] + #[track_caller] pub unsafe fn from_mut_unchecked(n: &mut T) -> &mut Self { match Self::from_mut(n) { Some(n) => n, diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index f38d809c1544b..10597854ff877 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -601,7 +601,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn unchecked_add(self, rhs: Self) -> Self { assert_unsafe_precondition!( check_language_ub, @@ -791,7 +791,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self { assert_unsafe_precondition!( check_language_ub, @@ -974,7 +974,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self { assert_unsafe_precondition!( check_language_ub, @@ -1588,7 +1588,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self { assert_unsafe_precondition!( check_language_ub, @@ -1709,7 +1709,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self { assert_unsafe_precondition!( check_language_ub, diff --git a/library/core/src/ops/index_range.rs b/library/core/src/ops/index_range.rs index c645c996eb707..507fa9460bea6 100644 --- a/library/core/src/ops/index_range.rs +++ b/library/core/src/ops/index_range.rs @@ -19,6 +19,7 @@ impl IndexRange { /// # Safety /// - `start <= end` #[inline] + #[track_caller] pub(crate) const unsafe fn new_unchecked(start: usize, end: usize) -> Self { ub_checks::assert_unsafe_precondition!( check_library_ub, diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index 19311e39b454e..3e66e271f03b6 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -73,6 +73,7 @@ impl Alignment { /// It must *not* be zero. #[unstable(feature = "ptr_alignment_type", issue = "102070")] #[inline] + #[track_caller] pub const unsafe fn new_unchecked(align: usize) -> Self { assert_unsafe_precondition!( check_language_ub, diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index f6109cafe86b1..fe4eb48132dea 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -444,7 +444,7 @@ impl *const T { #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn offset(self, count: isize) -> *const T where T: Sized, @@ -497,7 +497,7 @@ impl *const T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn byte_offset(self, count: isize) -> Self { // SAFETY: the caller must uphold the safety contract for `offset`. unsafe { self.cast::().offset(count).with_metadata_of(self) } @@ -796,7 +796,7 @@ impl *const T { #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn offset_from_unsigned(self, origin: *const T) -> usize where T: Sized, @@ -841,7 +841,7 @@ impl *const T { #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn byte_offset_from_unsigned(self, origin: *const U) -> usize { // SAFETY: the caller must uphold the safety contract for `offset_from_unsigned`. unsafe { self.cast::().offset_from_unsigned(origin.cast::()) } @@ -955,7 +955,7 @@ impl *const T { #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn add(self, count: usize) -> Self where T: Sized, @@ -1007,7 +1007,7 @@ impl *const T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn byte_add(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `add`. unsafe { self.cast::().add(count).with_metadata_of(self) } @@ -1061,7 +1061,7 @@ impl *const T { #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn sub(self, count: usize) -> Self where T: Sized, @@ -1119,7 +1119,7 @@ impl *const T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn byte_sub(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `sub`. unsafe { self.cast::().sub(count).with_metadata_of(self) } @@ -1292,7 +1292,7 @@ impl *const T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn read(self) -> T where T: Sized, @@ -1313,7 +1313,7 @@ impl *const T { /// [`ptr::read_volatile`]: crate::ptr::read_volatile() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub unsafe fn read_volatile(self) -> T where T: Sized, @@ -1333,7 +1333,7 @@ impl *const T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn read_unaligned(self) -> T where T: Sized, @@ -1353,7 +1353,7 @@ impl *const T { #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn copy_to(self, dest: *mut T, count: usize) where T: Sized, @@ -1373,7 +1373,7 @@ impl *const T { #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize) where T: Sized, diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 35a909f6904cd..99c4211cea862 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -1377,6 +1377,7 @@ pub const unsafe fn swap(x: *mut T, y: *mut T) { #[rustc_const_stable(feature = "const_swap_nonoverlapping", since = "1.88.0")] #[rustc_diagnostic_item = "ptr_swap_nonoverlapping"] #[rustc_allow_const_fn_unstable(const_eval_select)] // both implementations behave the same +#[track_caller] pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { ub_checks::assert_unsafe_precondition!( check_library_ub, @@ -1557,6 +1558,7 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, bytes: NonZero(dst: *mut T, src: T) -> T { // SAFETY: the caller must guarantee that `dst` is valid to be // cast to a mutable reference (valid for writes, aligned, initialized), @@ -1684,7 +1686,7 @@ pub const unsafe fn replace(dst: *mut T, src: T) -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces +#[track_caller] #[rustc_diagnostic_item = "ptr_read"] pub const unsafe fn read(src: *const T) -> T { // It would be semantically correct to implement this via `copy_nonoverlapping` @@ -1802,7 +1804,7 @@ pub const unsafe fn read(src: *const T) -> T { #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces +#[track_caller] #[rustc_diagnostic_item = "ptr_read_unaligned"] pub const unsafe fn read_unaligned(src: *const T) -> T { let mut tmp = MaybeUninit::::uninit(); @@ -1901,7 +1903,7 @@ pub const unsafe fn read_unaligned(src: *const T) -> T { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")] #[rustc_diagnostic_item = "ptr_write"] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces +#[track_caller] pub const unsafe fn write(dst: *mut T, src: T) { // Semantically, it would be fine for this to be implemented as a // `copy_nonoverlapping` and appropriate drop suppression of `src`. @@ -2005,7 +2007,7 @@ pub const unsafe fn write(dst: *mut T, src: T) { #[stable(feature = "ptr_unaligned", since = "1.17.0")] #[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")] #[rustc_diagnostic_item = "ptr_write_unaligned"] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces +#[track_caller] pub const unsafe fn write_unaligned(dst: *mut T, src: T) { // SAFETY: the caller must guarantee that `dst` is valid for writes. // `dst` cannot overlap `src` because the caller has mutable access @@ -2079,7 +2081,7 @@ pub const unsafe fn write_unaligned(dst: *mut T, src: T) { /// ``` #[inline] #[stable(feature = "volatile", since = "1.9.0")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces +#[track_caller] #[rustc_diagnostic_item = "ptr_read_volatile"] pub unsafe fn read_volatile(src: *const T) -> T { // SAFETY: the caller must uphold the safety contract for `volatile_load`. @@ -2160,7 +2162,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { #[inline] #[stable(feature = "volatile", since = "1.9.0")] #[rustc_diagnostic_item = "ptr_write_volatile"] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces +#[track_caller] pub unsafe fn write_volatile(dst: *mut T, src: T) { // SAFETY: the caller must uphold the safety contract for `volatile_store`. unsafe { diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 2662a4fdc3138..7a0452563f901 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -440,7 +440,7 @@ impl *mut T { #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn offset(self, count: isize) -> *mut T where T: Sized, @@ -495,7 +495,7 @@ impl *mut T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn byte_offset(self, count: isize) -> Self { // SAFETY: the caller must uphold the safety contract for `offset`. unsafe { self.cast::().offset(count).with_metadata_of(self) } @@ -970,7 +970,7 @@ impl *mut T { #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn offset_from_unsigned(self, origin: *const T) -> usize where T: Sized, @@ -992,7 +992,7 @@ impl *mut T { #[stable(feature = "ptr_sub_ptr", since = "1.87.0")] #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "1.87.0")] #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn byte_offset_from_unsigned(self, origin: *mut U) -> usize { // SAFETY: the caller must uphold the safety contract for `byte_offset_from_unsigned`. unsafe { (self as *const T).byte_offset_from_unsigned(origin) } @@ -1046,7 +1046,7 @@ impl *mut T { #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn add(self, count: usize) -> Self where T: Sized, @@ -1098,7 +1098,7 @@ impl *mut T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn byte_add(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `add`. unsafe { self.cast::().add(count).with_metadata_of(self) } @@ -1152,7 +1152,7 @@ impl *mut T { #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn sub(self, count: usize) -> Self where T: Sized, @@ -1210,7 +1210,7 @@ impl *mut T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn byte_sub(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `sub`. unsafe { self.cast::().sub(count).with_metadata_of(self) } @@ -1377,7 +1377,7 @@ impl *mut T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn read(self) -> T where T: Sized, @@ -1398,7 +1398,7 @@ impl *mut T { /// [`ptr::read_volatile`]: crate::ptr::read_volatile() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub unsafe fn read_volatile(self) -> T where T: Sized, @@ -1418,7 +1418,7 @@ impl *mut T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn read_unaligned(self) -> T where T: Sized, @@ -1438,7 +1438,7 @@ impl *mut T { #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn copy_to(self, dest: *mut T, count: usize) where T: Sized, @@ -1458,7 +1458,7 @@ impl *mut T { #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize) where T: Sized, @@ -1478,7 +1478,7 @@ impl *mut T { #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn copy_from(self, src: *const T, count: usize) where T: Sized, @@ -1498,7 +1498,7 @@ impl *mut T { #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn copy_from_nonoverlapping(self, src: *const T, count: usize) where T: Sized, @@ -1528,7 +1528,7 @@ impl *mut T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn write(self, val: T) where T: Sized, @@ -1547,7 +1547,7 @@ impl *mut T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn write_bytes(self, val: u8, count: usize) where T: Sized, @@ -1568,7 +1568,7 @@ impl *mut T { /// [`ptr::write_volatile`]: crate::ptr::write_volatile() #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub unsafe fn write_volatile(self, val: T) where T: Sized, @@ -1588,7 +1588,7 @@ impl *mut T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")] #[inline(always)] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[track_caller] pub const unsafe fn write_unaligned(self, val: T) where T: Sized, diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index bb344c6a0d316..1985526e4c970 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -216,6 +216,7 @@ impl NonNull { #[stable(feature = "nonnull", since = "1.25.0")] #[rustc_const_stable(feature = "const_nonnull_new_unchecked", since = "1.25.0")] #[inline] + #[track_caller] pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { // SAFETY: the caller must guarantee that `ptr` is non-null. unsafe { diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index aafa19c0dd3d3..644d22897deb6 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -239,6 +239,7 @@ unsafe impl SliceIndex<[T]> for usize { } #[inline] + #[track_caller] unsafe fn get_unchecked(self, slice: *const [T]) -> *const T { assert_unsafe_precondition!( check_language_ub, @@ -258,6 +259,7 @@ unsafe impl SliceIndex<[T]> for usize { } #[inline] + #[track_caller] unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T { assert_unsafe_precondition!( check_library_ub, @@ -307,6 +309,7 @@ unsafe impl SliceIndex<[T]> for ops::IndexRange { } #[inline] + #[track_caller] unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { assert_unsafe_precondition!( check_library_ub, @@ -321,6 +324,7 @@ unsafe impl SliceIndex<[T]> for ops::IndexRange { } #[inline] + #[track_caller] unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { assert_unsafe_precondition!( check_library_ub, @@ -386,6 +390,7 @@ unsafe impl SliceIndex<[T]> for ops::Range { } #[inline] + #[track_caller] unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { assert_unsafe_precondition!( check_library_ub, @@ -410,6 +415,7 @@ unsafe impl SliceIndex<[T]> for ops::Range { } #[inline] + #[track_caller] unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { assert_unsafe_precondition!( check_library_ub, diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index c9b8231e856c1..3339c71180d37 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -631,6 +631,7 @@ impl [T] { #[rustc_no_implicit_autorefs] #[inline] #[must_use] + #[track_caller] pub unsafe fn get_unchecked(&self, index: I) -> &I::Output where I: SliceIndex, @@ -674,6 +675,7 @@ impl [T] { #[rustc_no_implicit_autorefs] #[inline] #[must_use] + #[track_caller] pub unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output where I: SliceIndex, @@ -935,6 +937,7 @@ impl [T] { /// [`swap`]: slice::swap /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[unstable(feature = "slice_swap_unchecked", issue = "88539")] + #[track_caller] pub const unsafe fn swap_unchecked(&mut self, a: usize, b: usize) { assert_unsafe_precondition!( check_library_ub, @@ -1307,6 +1310,7 @@ impl [T] { #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] #[inline] #[must_use] + #[track_caller] pub const unsafe fn as_chunks_unchecked(&self) -> &[[T; N]] { assert_unsafe_precondition!( check_language_ub, @@ -1502,6 +1506,7 @@ impl [T] { #[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")] #[inline] #[must_use] + #[track_caller] pub const unsafe fn as_chunks_unchecked_mut(&mut self) -> &mut [[T; N]] { assert_unsafe_precondition!( check_language_ub, @@ -2061,6 +2066,7 @@ impl [T] { #[rustc_const_stable(feature = "const_slice_split_at_unchecked", since = "1.77.0")] #[inline] #[must_use] + #[track_caller] pub const unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) { // FIXME(const-hack): the const function `from_raw_parts` is used to make this // function const; previously the implementation used @@ -2114,6 +2120,7 @@ impl [T] { #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "1.83.0")] #[inline] #[must_use] + #[track_caller] pub const unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [T]) { let len = self.len(); let ptr = self.as_mut_ptr(); @@ -4642,6 +4649,7 @@ impl [T] { /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[stable(feature = "get_many_mut", since = "1.86.0")] #[inline] + #[track_caller] pub unsafe fn get_disjoint_unchecked_mut( &mut self, indices: [I; N], diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs index 3582c7e8b3f38..40da69c15627d 100644 --- a/library/core/src/slice/raw.rs +++ b/library/core/src/slice/raw.rs @@ -120,6 +120,7 @@ use crate::{array, ptr, ub_checks}; #[rustc_const_stable(feature = "const_slice_from_raw_parts", since = "1.64.0")] #[must_use] #[rustc_diagnostic_item = "slice_from_raw_parts"] +#[track_caller] pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. unsafe { @@ -174,6 +175,7 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] #[rustc_const_stable(feature = "const_slice_from_raw_parts_mut", since = "1.83.0")] #[must_use] #[rustc_diagnostic_item = "slice_from_raw_parts_mut"] +#[track_caller] pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. unsafe { @@ -270,6 +272,7 @@ pub const fn from_mut(s: &mut T) -> &mut [T] { /// [valid]: ptr#safety #[unstable(feature = "slice_from_ptr_range", issue = "89792")] #[rustc_const_unstable(feature = "const_slice_from_ptr_range", issue = "89792")] +#[track_caller] pub const unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] { // SAFETY: the caller must uphold the safety contract for `from_ptr_range`. unsafe { from_raw_parts(range.start, range.end.offset_from_unsigned(range.start)) } diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index 77c70b978fd15..4baf9aacad7b3 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -186,6 +186,7 @@ unsafe impl SliceIndex for ops::Range { } } #[inline] + #[track_caller] unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { let slice = slice as *const [u8]; @@ -213,6 +214,7 @@ unsafe impl SliceIndex for ops::Range { } } #[inline] + #[track_caller] unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { let slice = slice as *mut [u8]; @@ -288,6 +290,7 @@ unsafe impl SliceIndex for range::Range { } } #[inline] + #[track_caller] unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { let slice = slice as *const [u8]; @@ -315,6 +318,7 @@ unsafe impl SliceIndex for range::Range { } } #[inline] + #[track_caller] unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { let slice = slice as *mut [u8]; diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs index 9eb71922218f3..a7caaeb95cdba 100644 --- a/library/core/src/ub_checks.rs +++ b/library/core/src/ub_checks.rs @@ -63,11 +63,13 @@ macro_rules! assert_unsafe_precondition { #[rustc_no_mir_inline] #[inline] #[rustc_nounwind] + #[track_caller] const fn precondition_check($($name:$ty),*) { if !$e { - ::core::panicking::panic_nounwind(concat!("unsafe precondition(s) violated: ", $message, + let msg = concat!("unsafe precondition(s) violated: ", $message, "\n\nThis indicates a bug in the program. \ - This Undefined Behavior check is optional, and cannot be relied on for safety.")); + This Undefined Behavior check is optional, and cannot be relied on for safety."); + ::core::panicking::panic_nounwind_fmt(::core::fmt::Arguments::new_const(&[msg]), false); } } diff --git a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr index f57487e3ffe17..b4dadeecaa8cf 100644 --- a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr +++ b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr @@ -1,5 +1,5 @@ -thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC: +thread 'main' panicked at tests/fail/ptr_swap_nonoverlapping.rs:LL:CC: unsafe precondition(s) violated: ptr::swap_nonoverlapping requires that both pointer arguments are aligned and non-null and the specified memory ranges do not overlap This indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety. @@ -18,9 +18,6 @@ LL | ABORT() = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC - = note: inside `std::ptr::swap_nonoverlapping::precondition_check` at RUSTLIB/core/src/ub_checks.rs:LL:CC - = note: inside `std::ptr::swap_nonoverlapping::` at RUSTLIB/core/src/ub_checks.rs:LL:CC note: inside `main` --> tests/fail/ptr_swap_nonoverlapping.rs:LL:CC | diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff index 35eb4fbd106a1..25ffff619e60b 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff @@ -59,7 +59,7 @@ scope 10 (inlined ::allocate) { } } - scope 9 (inlined Layout::from_size_align_unchecked) { + scope 9 (inlined #[track_caller] Layout::from_size_align_unchecked) { let mut _19: bool; let _20: (); let mut _21: std::ptr::Alignment; diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff index 4427a5fcc7deb..839b53e3b0b3b 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff @@ -59,7 +59,7 @@ scope 10 (inlined ::allocate) { } } - scope 9 (inlined Layout::from_size_align_unchecked) { + scope 9 (inlined #[track_caller] Layout::from_size_align_unchecked) { let mut _19: bool; let _20: (); let mut _21: std::ptr::Alignment; diff --git a/tests/mir-opt/inline/unchecked_shifts.rs b/tests/mir-opt/inline/unchecked_shifts.rs index 3c4e73bf7ea6c..122f099da4b7d 100644 --- a/tests/mir-opt/inline/unchecked_shifts.rs +++ b/tests/mir-opt/inline/unchecked_shifts.rs @@ -11,7 +11,7 @@ // EMIT_MIR unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.mir pub unsafe fn unchecked_shl_unsigned_smaller(a: u16, b: u32) -> u16 { // CHECK-LABEL: fn unchecked_shl_unsigned_smaller( - // CHECK: (inlined core::num::::unchecked_shl) + // CHECK: (inlined #[track_caller] core::num::::unchecked_shl) a.unchecked_shl(b) } @@ -19,6 +19,6 @@ pub unsafe fn unchecked_shl_unsigned_smaller(a: u16, b: u32) -> u16 { // EMIT_MIR unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.mir pub unsafe fn unchecked_shr_signed_bigger(a: i64, b: u32) -> i64 { // CHECK-LABEL: fn unchecked_shr_signed_bigger( - // CHECK: (inlined core::num::::unchecked_shr) + // CHECK: (inlined #[track_caller] core::num::::unchecked_shr) a.unchecked_shr(b) } diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff index 39ba480d20330..813796657b247 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff @@ -7,7 +7,7 @@ let mut _0: u16; let mut _3: u16; let mut _4: u32; -+ scope 1 (inlined core::num::::unchecked_shl) { ++ scope 1 (inlined #[track_caller] core::num::::unchecked_shl) { + let _5: (); + scope 2 (inlined core::ub_checks::check_language_ub) { + let mut _6: bool; diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff index 5a758d3574060..61fdb69f74b70 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff @@ -7,7 +7,7 @@ let mut _0: u16; let mut _3: u16; let mut _4: u32; -+ scope 1 (inlined core::num::::unchecked_shl) { ++ scope 1 (inlined #[track_caller] core::num::::unchecked_shl) { + let _5: (); + scope 2 (inlined core::ub_checks::check_language_ub) { + let mut _6: bool; diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir index 611273ab08d74..0fc7c4b7947e2 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-abort.mir @@ -4,7 +4,7 @@ fn unchecked_shl_unsigned_smaller(_1: u16, _2: u32) -> u16 { debug a => _1; debug b => _2; let mut _0: u16; - scope 1 (inlined core::num::::unchecked_shl) { + scope 1 (inlined #[track_caller] core::num::::unchecked_shl) { scope 2 (inlined core::ub_checks::check_language_ub) { scope 3 (inlined core::ub_checks::check_language_ub::runtime) { } diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir index 611273ab08d74..0fc7c4b7947e2 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.panic-unwind.mir @@ -4,7 +4,7 @@ fn unchecked_shl_unsigned_smaller(_1: u16, _2: u32) -> u16 { debug a => _1; debug b => _2; let mut _0: u16; - scope 1 (inlined core::num::::unchecked_shl) { + scope 1 (inlined #[track_caller] core::num::::unchecked_shl) { scope 2 (inlined core::ub_checks::check_language_ub) { scope 3 (inlined core::ub_checks::check_language_ub::runtime) { } diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff index a0caf141f2d06..5ea99e8301b80 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff @@ -7,7 +7,7 @@ let mut _0: i64; let mut _3: i64; let mut _4: u32; -+ scope 1 (inlined core::num::::unchecked_shr) { ++ scope 1 (inlined #[track_caller] core::num::::unchecked_shr) { + let _5: (); + scope 2 (inlined core::ub_checks::check_language_ub) { + let mut _6: bool; diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff index 633089e7b2a28..b13531ab148f2 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff @@ -7,7 +7,7 @@ let mut _0: i64; let mut _3: i64; let mut _4: u32; -+ scope 1 (inlined core::num::::unchecked_shr) { ++ scope 1 (inlined #[track_caller] core::num::::unchecked_shr) { + let _5: (); + scope 2 (inlined core::ub_checks::check_language_ub) { + let mut _6: bool; diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-abort.mir index f4ddd0bca04d9..bef7fa7b1df75 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-abort.mir @@ -4,7 +4,7 @@ fn unchecked_shr_signed_bigger(_1: i64, _2: u32) -> i64 { debug a => _1; debug b => _2; let mut _0: i64; - scope 1 (inlined core::num::::unchecked_shr) { + scope 1 (inlined #[track_caller] core::num::::unchecked_shr) { scope 2 (inlined core::ub_checks::check_language_ub) { scope 3 (inlined core::ub_checks::check_language_ub::runtime) { } diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-unwind.mir index f4ddd0bca04d9..bef7fa7b1df75 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.PreCodegen.after.panic-unwind.mir @@ -4,7 +4,7 @@ fn unchecked_shr_signed_bigger(_1: i64, _2: u32) -> i64 { debug a => _1; debug b => _2; let mut _0: i64; - scope 1 (inlined core::num::::unchecked_shr) { + scope 1 (inlined #[track_caller] core::num::::unchecked_shr) { scope 2 (inlined core::ub_checks::check_language_ub) { scope 3 (inlined core::ub_checks::check_language_ub::runtime) { } diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff index a5986a4315a2d..0119dd799704d 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff @@ -9,7 +9,7 @@ + let mut _3: isize; + scope 2 { + } -+ scope 3 (inlined unreachable_unchecked) { ++ scope 3 (inlined #[track_caller] unreachable_unchecked) { + let _4: (); + scope 4 (inlined core::ub_checks::check_language_ub) { + let mut _5: bool; diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff index 12b03a6b6d921..d6a5eab1d6e93 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff @@ -9,7 +9,7 @@ + let mut _3: isize; + scope 2 { + } -+ scope 3 (inlined unreachable_unchecked) { ++ scope 3 (inlined #[track_caller] unreachable_unchecked) { + let _4: (); + scope 4 (inlined core::ub_checks::check_language_ub) { + let mut _5: bool; diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir index 66ab5e1b96228..b7b892c177c3e 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir @@ -7,7 +7,7 @@ fn unwrap_unchecked(_1: Option) -> T { let mut _2: isize; scope 2 { } - scope 3 (inlined unreachable_unchecked) { + scope 3 (inlined #[track_caller] unreachable_unchecked) { scope 4 (inlined core::ub_checks::check_language_ub) { scope 5 (inlined core::ub_checks::check_language_ub::runtime) { } diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir index 66ab5e1b96228..b7b892c177c3e 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir @@ -7,7 +7,7 @@ fn unwrap_unchecked(_1: Option) -> T { let mut _2: isize; scope 2 { } - scope 3 (inlined unreachable_unchecked) { + scope 3 (inlined #[track_caller] unreachable_unchecked) { scope 4 (inlined core::ub_checks::check_language_ub) { scope 5 (inlined core::ub_checks::check_language_ub::runtime) { } diff --git a/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff b/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff index 82353a2d5404a..2c9071e6e2079 100644 --- a/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff +++ b/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff @@ -9,7 +9,7 @@ let mut _3: isize; scope 2 { } - scope 3 (inlined unreachable_unchecked) { + scope 3 (inlined #[track_caller] unreachable_unchecked) { let _4: (); scope 4 (inlined core::ub_checks::check_language_ub) { let mut _5: bool; diff --git a/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.panic-abort.mir index a9dd8886577dd..18eeb8e4d3b61 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.panic-abort.mir @@ -7,7 +7,7 @@ fn checked_shl(_1: u32, _2: u32) -> Option { scope 1 (inlined core::num::::checked_shl) { let mut _3: bool; let mut _4: u32; - scope 2 (inlined core::num::::unchecked_shl) { + scope 2 (inlined #[track_caller] core::num::::unchecked_shl) { scope 3 (inlined core::ub_checks::check_language_ub) { scope 4 (inlined core::ub_checks::check_language_ub::runtime) { } diff --git a/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.panic-unwind.mir index a9dd8886577dd..18eeb8e4d3b61 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.panic-unwind.mir @@ -7,7 +7,7 @@ fn checked_shl(_1: u32, _2: u32) -> Option { scope 1 (inlined core::num::::checked_shl) { let mut _3: bool; let mut _4: u32; - scope 2 (inlined core::num::::unchecked_shl) { + scope 2 (inlined #[track_caller] core::num::::unchecked_shl) { scope 3 (inlined core::ub_checks::check_language_ub) { scope 4 (inlined core::ub_checks::check_language_ub::runtime) { } diff --git a/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir index 518fedffc1698..8a6732d5f745a 100644 --- a/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir @@ -4,7 +4,7 @@ fn ub_if_b(_1: Thing) -> Thing { debug t => _1; let mut _0: Thing; let mut _2: isize; - scope 1 (inlined unreachable_unchecked) { + scope 1 (inlined #[track_caller] unreachable_unchecked) { scope 2 (inlined core::ub_checks::check_language_ub) { scope 3 (inlined core::ub_checks::check_language_ub::runtime) { } diff --git a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir index 1f9c464d633b3..154cbd3791cbd 100644 --- a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir @@ -29,7 +29,7 @@ fn int_range(_1: usize, _2: usize) -> () { scope 8 (inlined ::forward_unchecked) { debug start => _11; debug n => const 1_usize; - scope 9 (inlined core::num::::unchecked_add) { + scope 9 (inlined #[track_caller] core::num::::unchecked_add) { debug self => _11; debug rhs => const 1_usize; scope 10 (inlined core::ub_checks::check_language_ub) { diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir index 5faa1e210cf4f..a6dad00bbdb19 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir @@ -4,12 +4,12 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { debug p => _1; debug n => _2; let mut _0: *const [u32]; - scope 1 (inlined std::ptr::const_ptr::::byte_add) { + scope 1 (inlined #[track_caller] std::ptr::const_ptr::::byte_add) { let mut _3: *const u8; let mut _4: *const u8; scope 2 (inlined std::ptr::const_ptr::::cast::) { } - scope 3 (inlined std::ptr::const_ptr::::add) { + scope 3 (inlined #[track_caller] std::ptr::const_ptr::::add) { } scope 4 (inlined std::ptr::const_ptr::::with_metadata_of::<[u32]>) { let mut _5: usize; diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir index 5faa1e210cf4f..a6dad00bbdb19 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir @@ -4,12 +4,12 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { debug p => _1; debug n => _2; let mut _0: *const [u32]; - scope 1 (inlined std::ptr::const_ptr::::byte_add) { + scope 1 (inlined #[track_caller] std::ptr::const_ptr::::byte_add) { let mut _3: *const u8; let mut _4: *const u8; scope 2 (inlined std::ptr::const_ptr::::cast::) { } - scope 3 (inlined std::ptr::const_ptr::::add) { + scope 3 (inlined #[track_caller] std::ptr::const_ptr::::add) { } scope 4 (inlined std::ptr::const_ptr::::with_metadata_of::<[u32]>) { let mut _5: usize; diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir index 9429785045a29..cb7f15657463b 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir @@ -4,12 +4,12 @@ fn demo_byte_add_thin(_1: *const u32, _2: usize) -> *const u32 { debug p => _1; debug n => _2; let mut _0: *const u32; - scope 1 (inlined std::ptr::const_ptr::::byte_add) { + scope 1 (inlined #[track_caller] std::ptr::const_ptr::::byte_add) { let mut _3: *const u8; let mut _4: *const u8; scope 2 (inlined std::ptr::const_ptr::::cast::) { } - scope 3 (inlined std::ptr::const_ptr::::add) { + scope 3 (inlined #[track_caller] std::ptr::const_ptr::::add) { } scope 4 (inlined std::ptr::const_ptr::::with_metadata_of::) { scope 5 (inlined std::ptr::metadata::) { diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir index 9429785045a29..cb7f15657463b 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir @@ -4,12 +4,12 @@ fn demo_byte_add_thin(_1: *const u32, _2: usize) -> *const u32 { debug p => _1; debug n => _2; let mut _0: *const u32; - scope 1 (inlined std::ptr::const_ptr::::byte_add) { + scope 1 (inlined #[track_caller] std::ptr::const_ptr::::byte_add) { let mut _3: *const u8; let mut _4: *const u8; scope 2 (inlined std::ptr::const_ptr::::cast::) { } - scope 3 (inlined std::ptr::const_ptr::::add) { + scope 3 (inlined #[track_caller] std::ptr::const_ptr::::add) { } scope 4 (inlined std::ptr::const_ptr::::with_metadata_of::) { scope 5 (inlined std::ptr::metadata::) { diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir index 0aa37203c1b01..dfe618612ab96 100644 --- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir @@ -24,7 +24,7 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { let mut _8: u32; scope 6 { scope 8 (inlined ::forward_unchecked) { - scope 9 (inlined core::num::::unchecked_add) { + scope 9 (inlined #[track_caller] core::num::::unchecked_add) { scope 10 (inlined core::ub_checks::check_language_ub) { scope 11 (inlined core::ub_checks::check_language_ub::runtime) { } diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir index 699d8bc8feab6..e0fcfcaffc59a 100644 --- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir @@ -24,7 +24,7 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { let mut _8: u32; scope 6 { scope 8 (inlined ::forward_unchecked) { - scope 9 (inlined core::num::::unchecked_add) { + scope 9 (inlined #[track_caller] core::num::::unchecked_add) { scope 10 (inlined core::ub_checks::check_language_ub) { scope 11 (inlined core::ub_checks::check_language_ub::runtime) { } diff --git a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir index f3033d4a2fa81..1f82fc59ac2c1 100644 --- a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir @@ -10,7 +10,7 @@ fn range_iter_next(_1: &mut std::ops::Range) -> Option { let mut _6: u32; scope 3 { scope 5 (inlined ::forward_unchecked) { - scope 6 (inlined core::num::::unchecked_add) { + scope 6 (inlined #[track_caller] core::num::::unchecked_add) { scope 7 (inlined core::ub_checks::check_language_ub) { scope 8 (inlined core::ub_checks::check_language_ub::runtime) { } diff --git a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir index f3033d4a2fa81..1f82fc59ac2c1 100644 --- a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir @@ -10,7 +10,7 @@ fn range_iter_next(_1: &mut std::ops::Range) -> Option { let mut _6: u32; scope 3 { scope 5 (inlined ::forward_unchecked) { - scope 6 (inlined core::num::::unchecked_add) { + scope 6 (inlined #[track_caller] core::num::::unchecked_add) { scope 7 (inlined core::ub_checks::check_language_ub) { scope 8 (inlined core::ub_checks::check_language_ub::runtime) { } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir index 220e881f86645..597f02e837ab6 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir @@ -6,10 +6,10 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> let mut _0: &mut [u32]; let mut _3: usize; let mut _4: usize; - scope 1 (inlined core::slice::::get_unchecked_mut::>) { + scope 1 (inlined #[track_caller] core::slice::::get_unchecked_mut::>) { let mut _5: *mut [u32]; let mut _11: *mut [u32]; - scope 2 (inlined as SliceIndex<[u32]>>::get_unchecked_mut) { + scope 2 (inlined #[track_caller] as SliceIndex<[u32]>>::get_unchecked_mut) { let mut _6: usize; let _7: (); let _8: usize; diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir index 220e881f86645..597f02e837ab6 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir @@ -6,10 +6,10 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> let mut _0: &mut [u32]; let mut _3: usize; let mut _4: usize; - scope 1 (inlined core::slice::::get_unchecked_mut::>) { + scope 1 (inlined #[track_caller] core::slice::::get_unchecked_mut::>) { let mut _5: *mut [u32]; let mut _11: *mut [u32]; - scope 2 (inlined as SliceIndex<[u32]>>::get_unchecked_mut) { + scope 2 (inlined #[track_caller] as SliceIndex<[u32]>>::get_unchecked_mut) { let mut _6: usize; let _7: (); let _8: usize; diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir index 1e0df94b67fb1..e34723898e4ac 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir @@ -7,7 +7,7 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - let mut _3: usize; let mut _4: usize; scope 1 (inlined std::ptr::const_ptr::::get_unchecked::>) { - scope 2 (inlined as SliceIndex<[u32]>>::get_unchecked) { + scope 2 (inlined #[track_caller] as SliceIndex<[u32]>>::get_unchecked) { let mut _5: usize; let _6: (); let _7: usize; diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir index 1e0df94b67fb1..e34723898e4ac 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir @@ -7,7 +7,7 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - let mut _3: usize; let mut _4: usize; scope 1 (inlined std::ptr::const_ptr::::get_unchecked::>) { - scope 2 (inlined as SliceIndex<[u32]>>::get_unchecked) { + scope 2 (inlined #[track_caller] as SliceIndex<[u32]>>::get_unchecked) { let mut _5: usize; let _6: (); let _7: usize; diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir index c75edde711e12..d389e4069d05a 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir @@ -58,7 +58,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { scope 30 { let _23: usize; scope 31 { - scope 34 (inlined core::num::::unchecked_sub) { + scope 34 (inlined #[track_caller] core::num::::unchecked_sub) { scope 35 (inlined core::ub_checks::check_language_ub) { scope 36 (inlined core::ub_checks::check_language_ub::runtime) { } @@ -115,7 +115,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } scope 13 (inlined NonNull::::as_ptr) { } - scope 14 (inlined std::ptr::mut_ptr::::add) { + scope 14 (inlined #[track_caller] std::ptr::mut_ptr::::add) { } } scope 8 (inlined NonNull::<[T]>::from_ref) { diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir index bc72181b77c42..3b58f1d61f4bb 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir @@ -40,7 +40,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } scope 13 (inlined NonNull::::as_ptr) { } - scope 14 (inlined std::ptr::mut_ptr::::add) { + scope 14 (inlined #[track_caller] std::ptr::mut_ptr::::add) { } } scope 8 (inlined NonNull::<[T]>::from_ref) { diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir index 38c509d0b534b..216e05ec5b79c 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir @@ -30,7 +30,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 18 { let _22: usize; scope 19 { - scope 22 (inlined core::num::::unchecked_sub) { + scope 22 (inlined #[track_caller] core::num::::unchecked_sub) { scope 23 (inlined core::ub_checks::check_language_ub) { scope 24 (inlined core::ub_checks::check_language_ub::runtime) { } @@ -86,7 +86,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } scope 13 (inlined NonNull::::as_ptr) { } - scope 14 (inlined std::ptr::mut_ptr::::add) { + scope 14 (inlined #[track_caller] std::ptr::mut_ptr::::add) { } } scope 8 (inlined NonNull::<[T]>::from_ref) { diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir index 158cc284b1aeb..001023919804a 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir @@ -30,7 +30,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 18 { let _22: usize; scope 19 { - scope 22 (inlined core::num::::unchecked_sub) { + scope 22 (inlined #[track_caller] core::num::::unchecked_sub) { scope 23 (inlined core::ub_checks::check_language_ub) { scope 24 (inlined core::ub_checks::check_language_ub::runtime) { } @@ -86,7 +86,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } scope 13 (inlined NonNull::::as_ptr) { } - scope 14 (inlined std::ptr::mut_ptr::::add) { + scope 14 (inlined #[track_caller] std::ptr::mut_ptr::::add) { } } scope 8 (inlined NonNull::<[T]>::from_ref) { diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir index f8d11df5185cc..41e273151eca4 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir @@ -29,7 +29,7 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { let mut _8: usize; scope 7 { scope 9 (inlined ::forward_unchecked) { - scope 10 (inlined core::num::::unchecked_add) { + scope 10 (inlined #[track_caller] core::num::::unchecked_add) { scope 11 (inlined core::ub_checks::check_language_ub) { scope 12 (inlined core::ub_checks::check_language_ub::runtime) { } diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir index 2c249197894a1..ec781c1480c74 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir @@ -29,7 +29,7 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { let mut _8: usize; scope 7 { scope 9 (inlined ::forward_unchecked) { - scope 10 (inlined core::num::::unchecked_add) { + scope 10 (inlined #[track_caller] core::num::::unchecked_add) { scope 11 (inlined core::ub_checks::check_language_ub) { scope 12 (inlined core::ub_checks::check_language_ub::runtime) { } diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir index 0036676210804..b09e36223441a 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir @@ -40,7 +40,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } scope 13 (inlined NonNull::::as_ptr) { } - scope 14 (inlined std::ptr::mut_ptr::::add) { + scope 14 (inlined #[track_caller] std::ptr::mut_ptr::::add) { } } scope 8 (inlined NonNull::<[T]>::from_ref) { diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir index e1d710fb689cf..12b54b57b8448 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir @@ -40,7 +40,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } scope 13 (inlined NonNull::::as_ptr) { } - scope 14 (inlined std::ptr::mut_ptr::::add) { + scope 14 (inlined #[track_caller] std::ptr::mut_ptr::::add) { } } scope 8 (inlined NonNull::<[T]>::from_ref) { diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-abort.mir index b6df2300efb1f..c0ed0aea1e260 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-abort.mir @@ -15,7 +15,7 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { scope 3 { let _11: usize; scope 4 { - scope 7 (inlined core::num::::unchecked_sub) { + scope 7 (inlined #[track_caller] core::num::::unchecked_sub) { scope 8 (inlined core::ub_checks::check_language_ub) { scope 9 (inlined core::ub_checks::check_language_ub::runtime) { } diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir index b6df2300efb1f..c0ed0aea1e260 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir @@ -15,7 +15,7 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { scope 3 { let _11: usize; scope 4 { - scope 7 (inlined core::num::::unchecked_sub) { + scope 7 (inlined #[track_caller] core::num::::unchecked_sub) { scope 8 (inlined core::ub_checks::check_language_ub) { scope 9 (inlined core::ub_checks::check_language_ub::runtime) { } diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir index 927deabd253f1..30eafe8594b3f 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir @@ -29,7 +29,7 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { } } } - scope 12 (inlined std::slice::from_raw_parts::<'_, u8>) { + scope 12 (inlined #[track_caller] std::slice::from_raw_parts::<'_, u8>) { debug data => _3; debug len => _4; let _5: *const [u8]; diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir index 927deabd253f1..30eafe8594b3f 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir @@ -29,7 +29,7 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { } } } - scope 12 (inlined std::slice::from_raw_parts::<'_, u8>) { + scope 12 (inlined #[track_caller] std::slice::from_raw_parts::<'_, u8>) { debug data => _3; debug len => _4; let _5: *const [u8]; diff --git a/tests/ui/const-ptr/forbidden_slices.stderr b/tests/ui/const-ptr/forbidden_slices.stderr index c73d2ca938cbe..e618fbf7e0fe4 100644 --- a/tests/ui/const-ptr/forbidden_slices.stderr +++ b/tests/ui/const-ptr/forbidden_slices.stderr @@ -104,20 +104,12 @@ error[E0080]: could not evaluate static initializer | LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; // errors inside libcore | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation panicked: assertion failed: 0 < pointee_size && pointee_size <= isize::MAX as usize - | -note: inside `from_ptr_range::<'_, ()>` - --> $SRC_DIR/core/src/slice/raw.rs:LL:COL -note: inside `std::ptr::const_ptr::::offset_from_unsigned` - --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL error[E0080]: could not evaluate static initializer --> $DIR/forbidden_slices.rs:54:25 | LL | from_ptr_range(ptr..ptr.add(2)) // errors inside libcore | ^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 8 bytes, but got ALLOC10 which is only 4 bytes from the end of the allocation - | -note: inside `std::ptr::const_ptr::::add` - --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL error[E0080]: it is undefined behavior to use this value --> $DIR/forbidden_slices.rs:57:1 @@ -170,31 +162,18 @@ error[E0080]: could not evaluate static initializer | LL | from_ptr_range(ptr..ptr.add(1)) | ^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 8 bytes, but got ALLOC11+0x1 which is only 7 bytes from the end of the allocation - | -note: inside `std::ptr::const_ptr::::add` - --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL error[E0080]: could not evaluate static initializer --> $DIR/forbidden_slices.rs:85:34 | LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation - | -note: inside `from_ptr_range::<'_, u32>` - --> $SRC_DIR/core/src/slice/raw.rs:LL:COL -note: inside `std::ptr::const_ptr::::offset_from_unsigned` - --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL error[E0080]: could not evaluate static initializer --> $DIR/forbidden_slices.rs:87:35 | LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation - | -note: inside `from_ptr_range::<'_, u32>` - --> $SRC_DIR/core/src/slice/raw.rs:LL:COL -note: inside `std::ptr::const_ptr::::offset_from_unsigned` - --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL error: aborting due to 18 previous errors diff --git a/tests/ui/const-ptr/out_of_bounds_read.stderr b/tests/ui/const-ptr/out_of_bounds_read.stderr index 1d625a26b78c6..8f93793802ba3 100644 --- a/tests/ui/const-ptr/out_of_bounds_read.stderr +++ b/tests/ui/const-ptr/out_of_bounds_read.stderr @@ -3,31 +3,18 @@ error[E0080]: evaluation of constant value failed | LL | const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) }; | ^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes - | -note: inside `std::ptr::read::` - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL error[E0080]: evaluation of constant value failed --> $DIR/out_of_bounds_read.rs:10:39 | LL | const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() }; | ^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes - | -note: inside `std::ptr::const_ptr::::read` - --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL -note: inside `std::ptr::read::` - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL error[E0080]: evaluation of constant value failed --> $DIR/out_of_bounds_read.rs:12:37 | LL | const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes - | -note: inside `std::ptr::mut_ptr::::read` - --> $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL -note: inside `std::ptr::read::` - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL error: aborting due to 3 previous errors diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.rs b/tests/ui/consts/const-eval/raw-pointer-ub.rs index 1383de63109c4..1e76104d515e2 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.rs +++ b/tests/ui/consts/const-eval/raw-pointer-ub.rs @@ -18,7 +18,6 @@ const MISALIGNED_COPY: () = unsafe { let mut z = 123; y.copy_to_nonoverlapping(&mut z, 1); //~^ ERROR evaluation of constant value failed - //~| NOTE inside `std::ptr::const_ptr //~| NOTE inside `std::ptr::copy_nonoverlapping::` //~| NOTE accessing memory with alignment 1, but alignment 4 is required // The actual error points into the implementation of `copy_to_nonoverlapping`. diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.stderr b/tests/ui/consts/const-eval/raw-pointer-ub.stderr index 0f3dc33f3a31b..01a8decc93b01 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.stderr +++ b/tests/ui/consts/const-eval/raw-pointer-ub.stderr @@ -16,19 +16,17 @@ error[E0080]: evaluation of constant value failed LL | y.copy_to_nonoverlapping(&mut z, 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment 1, but alignment 4 is required | -note: inside `std::ptr::const_ptr::::copy_to_nonoverlapping` - --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `std::ptr::copy_nonoverlapping::` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL error[E0080]: evaluation of constant value failed - --> $DIR/raw-pointer-ub.rs:34:16 + --> $DIR/raw-pointer-ub.rs:33:16 | LL | let _val = (*ptr).0; | ^^^^^^^^ accessing memory based on pointer with alignment 4, but alignment 16 is required error[E0080]: evaluation of constant value failed - --> $DIR/raw-pointer-ub.rs:41:16 + --> $DIR/raw-pointer-ub.rs:40:16 | LL | let _val = *ptr; | ^^^^ memory access failed: attempting to access 8 bytes, but got ALLOC0 which is only 4 bytes from the end of the allocation diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.stderr b/tests/ui/consts/const-eval/ub-ref-ptr.stderr index de5e721c3f716..cfec1a42f28aa 100644 --- a/tests/ui/consts/const-eval/ub-ref-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-ref-ptr.stderr @@ -153,11 +153,6 @@ error[E0080]: evaluation of constant value failed | LL | ptr.read(); | ^^^^^^^^^^ accessing memory based on pointer with alignment 1, but alignment 4 is required - | -note: inside `std::ptr::const_ptr::::read` - --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL -note: inside `std::ptr::read::` - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL error: aborting due to 15 previous errors diff --git a/tests/ui/consts/const_unsafe_unreachable_ub.rs b/tests/ui/consts/const_unsafe_unreachable_ub.rs index a3f7fd46a7597..76c6c56d7c50a 100644 --- a/tests/ui/consts/const_unsafe_unreachable_ub.rs +++ b/tests/ui/consts/const_unsafe_unreachable_ub.rs @@ -1,14 +1,15 @@ const unsafe fn foo(x: bool) -> bool { match x { true => true, - false => std::hint::unreachable_unchecked(), //~ NOTE inside `foo` + false => std::hint::unreachable_unchecked(), + //~^ NOTE inside `foo` + //~| NOTE the failure occurred here } } const BAR: bool = unsafe { foo(false) }; //~^ ERROR evaluation of constant value failed //~| NOTE entering unreachable code -//~| NOTE inside `unreachable_unchecked` fn main() { assert_eq!(BAR, true); diff --git a/tests/ui/consts/const_unsafe_unreachable_ub.stderr b/tests/ui/consts/const_unsafe_unreachable_ub.stderr index 079ed77b219bb..42bf69aded022 100644 --- a/tests/ui/consts/const_unsafe_unreachable_ub.stderr +++ b/tests/ui/consts/const_unsafe_unreachable_ub.stderr @@ -1,5 +1,5 @@ error[E0080]: evaluation of constant value failed - --> $DIR/const_unsafe_unreachable_ub.rs:8:28 + --> $DIR/const_unsafe_unreachable_ub.rs:10:28 | LL | const BAR: bool = unsafe { foo(false) }; | ^^^^^^^^^^ entering unreachable code @@ -8,9 +8,7 @@ note: inside `foo` --> $DIR/const_unsafe_unreachable_ub.rs:4:18 | LL | false => std::hint::unreachable_unchecked(), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: inside `unreachable_unchecked` - --> $SRC_DIR/core/src/hint.rs:LL:COL + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the failure occurred here error: aborting due to 1 previous error diff --git a/tests/ui/consts/issue-miri-1910.stderr b/tests/ui/consts/issue-miri-1910.stderr index 59cbccc13a720..52edad0c389d8 100644 --- a/tests/ui/consts/issue-miri-1910.stderr +++ b/tests/ui/consts/issue-miri-1910.stderr @@ -4,10 +4,6 @@ error[E0080]: evaluation of constant value failed LL | (&foo as *const _ as *const u8).add(one_and_a_half_pointers).read(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer | -note: inside `std::ptr::const_ptr::::read` - --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL -note: inside `std::ptr::read::` - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/missing_span_in_backtrace.stderr b/tests/ui/consts/missing_span_in_backtrace.stderr index 7c07710332b80..f802138c61314 100644 --- a/tests/ui/consts/missing_span_in_backtrace.stderr +++ b/tests/ui/consts/missing_span_in_backtrace.stderr @@ -8,8 +8,6 @@ error[E0080]: evaluation of constant value failed 18 | | ); | |_________^ unable to copy parts of a pointer from memory at ALLOC0 | -note: inside `swap_nonoverlapping::>` - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL note: inside `swap_nonoverlapping::compiletime::>` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL note: inside `std::ptr::swap_nonoverlapping_const::>` @@ -18,7 +16,6 @@ note: inside `std::ptr::copy_nonoverlapping::>` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported - = note: this error originates in the macro `$crate::intrinsics::const_eval_select` which comes from the expansion of the macro `const_eval_select` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/consts/offset_ub.stderr b/tests/ui/consts/offset_ub.stderr index 699b63dfd66d8..31a2a36a6690a 100644 --- a/tests/ui/consts/offset_ub.stderr +++ b/tests/ui/consts/offset_ub.stderr @@ -3,99 +3,66 @@ error[E0080]: evaluation of constant value failed | LL | pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC0 which is at the beginning of the allocation - | -note: inside `std::ptr::const_ptr::::offset` - --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:9:43 | LL | pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got ALLOC1 which is only 1 byte from the end of the allocation - | -note: inside `std::ptr::const_ptr::::offset` - --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:10:45 | LL | pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got ALLOC2 which is only $BYTES bytes from the end of the allocation - | -note: inside `std::ptr::const_ptr::::offset` - --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:12:43 | LL | pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize` - | -note: inside `std::ptr::const_ptr::::offset` - --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:13:44 | LL | pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize` - | -note: inside `std::ptr::const_ptr::::offset` - --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:14:56 | LL | pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got 0xf..f[noalloc] which is a dangling pointer (it has no provenance) - | -note: inside `std::ptr::const_ptr::::offset` - --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:15:57 | LL | pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) - | -note: inside `std::ptr::const_ptr::::offset` - --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:16:49 | LL | pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC3-0x2 which is only $BYTES bytes from the beginning of the allocation - | -note: inside `std::ptr::const_ptr::::offset` - --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:18:50 | LL | pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got ALLOC4 which is at or beyond the end of the allocation of size $BYTES bytes - | -note: inside `std::ptr::const_ptr::::offset` - --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:19:42 | LL | pub const DANGLING: *const u8 = unsafe { ptr::NonNull::::dangling().as_ptr().offset(4) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) - | -note: inside `std::ptr::mut_ptr::::offset` - --> $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:22:47 | LL | pub const UNDERFLOW_ABS: *const u8 = unsafe { (usize::MAX as *const u8).offset(isize::MIN) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got 0xf..f[noalloc] which is a dangling pointer (it has no provenance) - | -note: inside `std::ptr::const_ptr::::offset` - --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL error: aborting due to 11 previous errors diff --git a/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr b/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr index f70e262ac4c58..1375ac751f22b 100644 --- a/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr +++ b/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr @@ -8,9 +8,7 @@ note: inside `ub` --> $DIR/interpret-in-promoted.rs:9:5 | LL | std::hint::unreachable_unchecked(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: inside `unreachable_unchecked` - --> $SRC_DIR/core/src/hint.rs:LL:COL + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the failure occurred here note: erroneous constant encountered --> $DIR/interpret-in-promoted.rs:15:27 diff --git a/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr b/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr index f70e262ac4c58..1375ac751f22b 100644 --- a/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr +++ b/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr @@ -8,9 +8,7 @@ note: inside `ub` --> $DIR/interpret-in-promoted.rs:9:5 | LL | std::hint::unreachable_unchecked(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: inside `unreachable_unchecked` - --> $SRC_DIR/core/src/hint.rs:LL:COL + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the failure occurred here note: erroneous constant encountered --> $DIR/interpret-in-promoted.rs:15:27 diff --git a/tests/ui/print_type_sizes/niche-filling.stdout b/tests/ui/print_type_sizes/niche-filling.stdout index 70612490a4716..432ab960a5024 100644 --- a/tests/ui/print_type_sizes/niche-filling.stdout +++ b/tests/ui/print_type_sizes/niche-filling.stdout @@ -1,3 +1,25 @@ +print-type-size type: `std::fmt::Arguments<'_>`: 48 bytes, alignment: 8 bytes +print-type-size field `.pieces`: 16 bytes +print-type-size field `.args`: 16 bytes +print-type-size field `.fmt`: 16 bytes +print-type-size type: `std::panic::Location<'_>`: 24 bytes, alignment: 8 bytes +print-type-size field `.file`: 16 bytes +print-type-size field `.line`: 4 bytes +print-type-size field `.col`: 4 bytes +print-type-size type: `core::fmt::rt::Argument<'_>`: 16 bytes, alignment: 8 bytes +print-type-size field `.ty`: 16 bytes +print-type-size type: `core::fmt::rt::ArgumentType<'_>`: 16 bytes, alignment: 8 bytes +print-type-size variant `Placeholder`: 16 bytes +print-type-size field `.value`: 8 bytes +print-type-size field `.formatter`: 8 bytes +print-type-size field `._lifetime`: 0 bytes +print-type-size variant `Count`: 10 bytes +print-type-size padding: 8 bytes +print-type-size field `.0`: 2 bytes, alignment: 2 bytes +print-type-size type: `std::option::Option<&[core::fmt::rt::Placeholder]>`: 16 bytes, alignment: 8 bytes +print-type-size variant `Some`: 16 bytes +print-type-size field `.0`: 16 bytes +print-type-size variant `None`: 0 bytes print-type-size type: `IndirectNonZero`: 12 bytes, alignment: 4 bytes print-type-size field `.nested`: 8 bytes print-type-size field `.post`: 2 bytes @@ -34,6 +56,8 @@ print-type-size field `.val`: 4 bytes print-type-size field `.post`: 2 bytes print-type-size field `.pre`: 1 bytes print-type-size end padding: 1 bytes +print-type-size type: `std::ptr::NonNull<()>`: 8 bytes, alignment: 8 bytes +print-type-size field `.pointer`: 8 bytes print-type-size type: `Enum4<(), char, (), ()>`: 4 bytes, alignment: 4 bytes print-type-size variant `Two`: 4 bytes print-type-size field `.0`: 4 bytes @@ -116,3 +140,4 @@ print-type-size discriminant: 1 bytes print-type-size variant `Less`: 0 bytes print-type-size variant `Equal`: 0 bytes print-type-size variant `Greater`: 0 bytes +print-type-size type: `std::marker::PhantomData<&()>`: 0 bytes, alignment: 1 bytes From 7debaf6b44f993c7aaf363ed394c4b4a840d9254 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Wed, 21 May 2025 15:15:38 +0200 Subject: [PATCH 2561/4206] Merge commit 'cadf98bb7d783e2ea3572446c3f80d3592ec5f86' into clippy-subtree-update --- CHANGELOG.md | 1 + CONTRIBUTING.md | 6 +- Cargo.toml | 2 - book/src/development/basics.md | 2 +- book/src/development/the_team.md | 2 +- book/src/lint_configuration.md | 1 + clippy_config/Cargo.toml | 2 - clippy_config/src/conf.rs | 1 + clippy_dev/Cargo.toml | 2 - clippy_dev/src/deprecate_lint.rs | 61 +- clippy_dev/src/fmt.rs | 313 ++--- clippy_dev/src/lib.rs | 10 +- clippy_dev/src/main.rs | 5 +- clippy_dev/src/release.rs | 24 +- clippy_dev/src/rename_lint.rs | 499 ++++--- clippy_dev/src/sync.rs | 13 +- clippy_dev/src/update_lints.rs | 160 ++- clippy_dev/src/utils.rs | 352 +++-- clippy_lints/Cargo.toml | 2 - .../src/arbitrary_source_item_ordering.rs | 19 +- .../src/assertions_on_result_states.rs | 9 +- .../src/casts/cast_possible_truncation.rs | 4 +- clippy_lints/src/casts/cast_sign_loss.rs | 27 +- .../casts/confusing_method_to_numeric_cast.rs | 15 +- clippy_lints/src/casts/ptr_cast_constness.rs | 9 +- clippy_lints/src/cognitive_complexity.rs | 10 +- clippy_lints/src/comparison_chain.rs | 7 +- clippy_lints/src/copies.rs | 27 +- clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/deprecated_lints.rs | 166 +-- clippy_lints/src/dereference.rs | 67 +- clippy_lints/src/doc/missing_headers.rs | 3 +- clippy_lints/src/empty_with_brackets.rs | 1 + clippy_lints/src/explicit_write.rs | 8 +- .../src/extra_unused_type_parameters.rs | 2 +- clippy_lints/src/fallible_impl_from.rs | 2 +- clippy_lints/src/float_literal.rs | 2 +- clippy_lints/src/floating_point_arithmetic.rs | 54 +- clippy_lints/src/functions/must_use.rs | 2 +- clippy_lints/src/functions/result.rs | 2 +- clippy_lints/src/implicit_hasher.rs | 13 +- clippy_lints/src/index_refutable_slice.rs | 4 +- clippy_lints/src/ineffective_open_options.rs | 10 +- clippy_lints/src/infinite_iter.rs | 85 +- clippy_lints/src/inherent_to_string.rs | 2 +- clippy_lints/src/lib.rs | 4 +- clippy_lints/src/lifetimes.rs | 2 +- clippy_lints/src/lines_filter_map_ok.rs | 18 +- .../src/loops/char_indices_as_byte_indices.rs | 38 +- .../src/loops/explicit_into_iter_loop.rs | 4 +- clippy_lints/src/loops/explicit_iter_loop.rs | 4 +- clippy_lints/src/loops/mod.rs | 14 +- clippy_lints/src/manual_is_power_of_two.rs | 4 +- .../src/manual_slice_size_calculation.rs | 25 +- clippy_lints/src/map_unit_fn.rs | 2 +- clippy_lints/src/matches/match_same_arms.rs | 122 +- clippy_lints/src/matches/mod.rs | 6 +- clippy_lints/src/matches/needless_match.rs | 18 +- clippy_lints/src/matches/redundant_guards.rs | 14 +- .../src/matches/redundant_pattern_match.rs | 2 +- .../matches/significant_drop_in_scrutinee.rs | 4 +- clippy_lints/src/methods/bytes_nth.rs | 3 +- clippy_lints/src/methods/chars_cmp.rs | 3 +- .../src/methods/chars_cmp_with_unwrap.rs | 3 +- clippy_lints/src/methods/chars_last_cmp.rs | 5 +- .../src/methods/chars_last_cmp_with_unwrap.rs | 17 +- clippy_lints/src/methods/chars_next_cmp.rs | 3 +- .../src/methods/chars_next_cmp_with_unwrap.rs | 9 +- .../src/methods/collapsible_str_replace.rs | 6 +- clippy_lints/src/methods/expect_fun_call.rs | 6 +- clippy_lints/src/methods/extend_with_drain.rs | 4 +- clippy_lints/src/methods/implicit_clone.rs | 16 +- .../src/methods/iter_cloned_collect.rs | 9 +- clippy_lints/src/methods/iter_count.rs | 4 +- clippy_lints/src/methods/iter_kv_map.rs | 10 +- clippy_lints/src/methods/iter_nth.rs | 8 +- .../iter_on_single_or_empty_collections.rs | 11 +- .../src/methods/iter_overeager_cloned.rs | 4 +- .../src/methods/manual_c_str_literals.rs | 2 +- clippy_lints/src/methods/manual_inspect.rs | 12 +- clippy_lints/src/methods/map_identity.rs | 4 +- clippy_lints/src/methods/mod.rs | 415 +++--- clippy_lints/src/methods/needless_as_bytes.rs | 4 +- .../src/methods/needless_option_as_deref.rs | 8 +- .../src/methods/needless_option_take.rs | 10 +- .../src/methods/obfuscated_if_else.rs | 19 +- .../src/methods/option_as_ref_cloned.rs | 6 +- clippy_lints/src/methods/or_fun_call.rs | 25 +- clippy_lints/src/methods/search_is_some.rs | 11 +- clippy_lints/src/methods/str_split.rs | 2 +- clippy_lints/src/methods/str_splitn.rs | 18 +- .../src/methods/string_extend_chars.rs | 4 +- clippy_lints/src/methods/suspicious_splitn.rs | 3 +- .../src/methods/unnecessary_filter_map.rs | 20 +- .../src/methods/unnecessary_literal_unwrap.rs | 29 +- .../src/methods/unnecessary_min_or_max.rs | 9 +- .../src/methods/unnecessary_to_owned.rs | 32 +- clippy_lints/src/methods/useless_asref.rs | 10 +- .../src/methods/wrong_self_convention.rs | 7 +- clippy_lints/src/missing_const_for_fn.rs | 4 +- clippy_lints/src/mut_key.rs | 2 +- clippy_lints/src/needless_bool.rs | 4 +- clippy_lints/src/needless_pass_by_value.rs | 10 +- clippy_lints/src/no_effect.rs | 14 +- clippy_lints/src/non_copy_const.rs | 1153 +++++++++++------ .../src/operators/assign_op_pattern.rs | 2 +- clippy_lints/src/operators/duration_subsec.rs | 8 +- clippy_lints/src/option_env_unwrap.rs | 2 +- clippy_lints/src/returns.rs | 12 +- .../src/significant_drop_tightening.rs | 6 +- clippy_lints/src/size_of_in_element_count.rs | 27 +- .../src/slow_vector_initialization.rs | 4 +- clippy_lints/src/string_patterns.rs | 52 +- clippy_lints/src/strlen_on_c_strings.rs | 5 +- clippy_lints/src/suspicious_trait_impl.rs | 2 +- clippy_lints/src/unnecessary_wraps.rs | 17 +- clippy_lints/src/unused_peekable.rs | 9 +- clippy_lints/src/unused_rounding.rs | 11 +- clippy_lints/src/unwrap_in_result.rs | 4 +- clippy_lints/src/useless_concat.rs | 104 ++ clippy_lints/src/useless_conversion.rs | 35 +- clippy_lints/src/utils/author.rs | 4 +- clippy_lints/src/utils/dump_hir.rs | 4 +- clippy_lints/src/vec.rs | 8 +- clippy_lints/src/zero_sized_map_values.rs | 8 +- .../src/almost_standard_lint_formulation.rs | 3 +- .../src/collapsible_calls.rs | 3 +- .../src/lint_without_lint_pass.rs | 3 +- clippy_lints_internal/src/msrv_attr_impl.rs | 3 +- .../src/outer_expn_data_pass.rs | 6 +- clippy_lints_internal/src/produce_ice.rs | 3 +- clippy_lints_internal/src/symbols.rs | 3 +- .../src/unsorted_clippy_utils_paths.rs | 8 +- clippy_utils/Cargo.toml | 2 - clippy_utils/README.md | 2 +- clippy_utils/src/attrs.rs | 40 +- clippy_utils/src/consts.rs | 6 +- clippy_utils/src/eager_or_lazy.rs | 6 +- clippy_utils/src/higher.rs | 2 +- clippy_utils/src/lib.rs | 67 +- clippy_utils/src/macros.rs | 20 +- clippy_utils/src/msrvs.rs | 2 +- clippy_utils/src/paths.rs | 1 + clippy_utils/src/ptr.rs | 12 +- clippy_utils/src/source.rs | 86 +- clippy_utils/src/sym.rs | 254 +++- clippy_utils/src/ty/mod.rs | 11 + rust-toolchain.toml | 2 +- src/driver.rs | 15 +- .../ordering_mixed.default.stderr | 70 +- .../ordering_mixed.default_exp.stderr | 70 +- .../ordering_mixed.ord_within.stderr | 94 +- .../ordering_mixed.rs | 16 + .../collapsible_if/collapsible_if.fixed | 4 +- .../collapsible_if/collapsible_if.stderr | 4 +- tests/ui-toml/ifs_same_cond/ifs_same_cond.rs | 2 +- .../ifs_same_cond/ifs_same_cond.stderr | 12 +- tests/ui/assign_ops.fixed | 38 +- tests/ui/assign_ops.rs | 38 +- tests/ui/assign_ops.stderr | 30 +- tests/ui/assign_ops2.rs | 77 -- .../interior_mutable_const.rs} | 0 tests/ui/borrow_interior_mutable_const.rs | 221 ++++ tests/ui/borrow_interior_mutable_const.stderr | 247 ++++ .../ui/borrow_interior_mutable_const/enums.rs | 101 -- .../enums.stderr | 79 -- .../borrow_interior_mutable_const/others.rs | 128 -- .../others.stderr | 119 -- .../projections.rs | 42 - .../projections.stderr | 44 - .../borrow_interior_mutable_const/traits.rs | 219 ---- .../traits.stderr | 143 -- tests/ui/cast.rs | 2 +- tests/ui/cast_size.rs | 2 +- .../complex_conditionals_nested.rs | 2 +- .../ui/checked_unwrap/simple_conditionals.rs | 2 +- tests/ui/comparison_chain.rs | 12 +- tests/ui/comparison_chain.stderr | 42 +- tests/ui/crashes/ice-12491.fixed | 2 +- tests/ui/crashes/ice-12491.rs | 2 +- tests/ui/crashes/ice-12491.stderr | 8 +- tests/ui/crashes/ice-12979.1.fixed | 2 + tests/ui/crashes/ice-12979.2.fixed | 3 + tests/ui/crashes/ice-12979.rs | 3 + tests/ui/crashes/ice-12979.stderr | 19 + tests/ui/crashes/ice-6840.rs | 1 + tests/ui/crashes/ice-9445.rs | 4 - tests/ui/crashes/ice-9445.stderr | 12 - tests/ui/dbg_macro/dbg_macro_unfixable.rs | 2 +- tests/ui/declare_interior_mutable_const.rs | 200 +++ .../ui/declare_interior_mutable_const.stderr | 197 +++ .../declare_interior_mutable_const/enums.rs | 135 -- .../enums.stderr | 89 -- .../declare_interior_mutable_const/others.rs | 76 -- .../others.stderr | 50 - .../declare_interior_mutable_const/traits.rs | 162 --- .../traits.stderr | 88 -- tests/ui/deprecated.rs | 20 +- tests/ui/deprecated.stderr | 80 +- .../double_ended_iterator_last_unfixable.rs | 2 +- tests/ui/empty_structs_with_brackets.fixed | 8 + tests/ui/empty_structs_with_brackets.rs | 8 + tests/ui/entry_unfixable.rs | 3 +- tests/ui/entry_unfixable.stderr | 6 +- tests/ui/excessive_precision.fixed | 3 + tests/ui/excessive_precision.rs | 3 + tests/ui/excessive_precision.stderr | 6 +- tests/ui/explicit_counter_loop.rs | 2 +- tests/ui/explicit_deref_methods.fixed | 11 +- tests/ui/explicit_deref_methods.rs | 11 +- tests/ui/explicit_deref_methods.stderr | 44 +- tests/ui/explicit_into_iter_loop.fixed | 13 + tests/ui/explicit_into_iter_loop.rs | 13 + tests/ui/explicit_into_iter_loop.stderr | 8 +- tests/ui/explicit_iter_loop.fixed | 13 + tests/ui/explicit_iter_loop.rs | 13 + tests/ui/explicit_iter_loop.stderr | 8 +- tests/ui/filter_map_bool_then_unfixable.rs | 3 +- .../ui/filter_map_bool_then_unfixable.stderr | 10 +- tests/ui/ifs_same_cond.rs | 12 +- tests/ui/ifs_same_cond.stderr | 62 +- tests/ui/impl_trait_in_params.rs | 2 +- tests/ui/infinite_loop.rs | 2 - tests/ui/infinite_loop.stderr | 22 +- tests/ui/infinite_loops.rs | 2 +- tests/ui/into_iter_without_iter.rs | 2 +- tests/ui/iter_next_loop.rs | 13 + tests/ui/iter_next_loop.stderr | 8 +- tests/ui/iter_out_of_bounds.rs | 2 - tests/ui/iter_out_of_bounds.stderr | 30 +- tests/ui/manual_inspect.fixed | 2 +- tests/ui/manual_inspect.stderr | 2 +- tests/ui/manual_slice_size_calculation.fixed | 25 +- tests/ui/manual_slice_size_calculation.rs | 25 +- tests/ui/manual_slice_size_calculation.stderr | 14 +- tests/ui/match_same_arms.fixed | 142 ++ tests/ui/match_same_arms.rs | 20 +- tests/ui/match_same_arms.stderr | 137 +- tests/ui/match_same_arms2.fixed | 53 +- tests/ui/match_same_arms2.rs | 49 +- tests/ui/match_same_arms2.stderr | 255 ++-- tests/ui/match_same_arms_non_exhaustive.fixed | 24 +- tests/ui/match_same_arms_non_exhaustive.rs | 19 +- .../ui/match_same_arms_non_exhaustive.stderr | 86 +- tests/ui/misrefactored_assign_op.1.fixed | 40 + tests/ui/misrefactored_assign_op.2.fixed | 40 + tests/ui/misrefactored_assign_op.rs | 40 + ....stderr => misrefactored_assign_op.stderr} | 29 +- tests/ui/needless_match.fixed | 12 + tests/ui/needless_match.rs | 15 + tests/ui/needless_match.stderr | 12 +- tests/ui/needless_return.fixed | 18 +- tests/ui/needless_return.rs | 18 +- tests/ui/needless_return.stderr | 76 +- tests/ui/no_effect.rs | 53 + tests/ui/rename.fixed | 120 +- tests/ui/rename.rs | 120 +- tests/ui/rename.stderr | 400 +++--- tests/ui/same_functions_in_if_condition.rs | 12 +- .../ui/same_functions_in_if_condition.stderr | 67 +- tests/ui/single_range_in_vec_init.rs | 2 +- .../non_expressive_names_error_recovery.fixed | 0 .../non_expressive_names_error_recovery.rs | 0 ...non_expressive_names_error_recovery.stderr | 2 +- tests/ui/unnecessary_to_owned.fixed | 6 + tests/ui/unnecessary_to_owned.rs | 6 + tests/ui/unnecessary_wraps.stderr | 71 +- tests/ui/useless_asref.fixed | 10 + tests/ui/useless_asref.rs | 10 + tests/ui/useless_concat.fixed | 41 + tests/ui/useless_concat.rs | 41 + tests/ui/useless_concat.stderr | 89 ++ tests/ui/useless_conversion.fixed | 15 + tests/ui/useless_conversion.rs | 15 + tests/ui/useless_conversion.stderr | 14 +- tests/ui/zero_sized_hashmap_values.rs | 21 + tests/ui/zero_sized_hashmap_values.stderr | 16 +- triagebot.toml | 2 +- 278 files changed, 6166 insertions(+), 4612 deletions(-) create mode 100644 clippy_lints/src/useless_concat.rs delete mode 100644 tests/ui/assign_ops2.rs rename tests/ui/{borrow_interior_mutable_const/auxiliary/helper.rs => auxiliary/interior_mutable_const.rs} (100%) create mode 100644 tests/ui/borrow_interior_mutable_const.rs create mode 100644 tests/ui/borrow_interior_mutable_const.stderr delete mode 100644 tests/ui/borrow_interior_mutable_const/enums.rs delete mode 100644 tests/ui/borrow_interior_mutable_const/enums.stderr delete mode 100644 tests/ui/borrow_interior_mutable_const/others.rs delete mode 100644 tests/ui/borrow_interior_mutable_const/others.stderr delete mode 100644 tests/ui/borrow_interior_mutable_const/projections.rs delete mode 100644 tests/ui/borrow_interior_mutable_const/projections.stderr delete mode 100644 tests/ui/borrow_interior_mutable_const/traits.rs delete mode 100644 tests/ui/borrow_interior_mutable_const/traits.stderr create mode 100644 tests/ui/crashes/ice-12979.1.fixed create mode 100644 tests/ui/crashes/ice-12979.2.fixed create mode 100644 tests/ui/crashes/ice-12979.rs create mode 100644 tests/ui/crashes/ice-12979.stderr delete mode 100644 tests/ui/crashes/ice-9445.rs delete mode 100644 tests/ui/crashes/ice-9445.stderr create mode 100644 tests/ui/declare_interior_mutable_const.rs create mode 100644 tests/ui/declare_interior_mutable_const.stderr delete mode 100644 tests/ui/declare_interior_mutable_const/enums.rs delete mode 100644 tests/ui/declare_interior_mutable_const/enums.stderr delete mode 100644 tests/ui/declare_interior_mutable_const/others.rs delete mode 100644 tests/ui/declare_interior_mutable_const/others.stderr delete mode 100644 tests/ui/declare_interior_mutable_const/traits.rs delete mode 100644 tests/ui/declare_interior_mutable_const/traits.stderr create mode 100644 tests/ui/match_same_arms.fixed create mode 100644 tests/ui/misrefactored_assign_op.1.fixed create mode 100644 tests/ui/misrefactored_assign_op.2.fixed create mode 100644 tests/ui/misrefactored_assign_op.rs rename tests/ui/{assign_ops2.stderr => misrefactored_assign_op.stderr} (80%) rename tests/ui/{syntax-error-recovery => skip_rustfmt}/non_expressive_names_error_recovery.fixed (100%) rename tests/ui/{syntax-error-recovery => skip_rustfmt}/non_expressive_names_error_recovery.rs (100%) rename tests/ui/{syntax-error-recovery => skip_rustfmt}/non_expressive_names_error_recovery.stderr (80%) create mode 100644 tests/ui/useless_concat.fixed create mode 100644 tests/ui/useless_concat.rs create mode 100644 tests/ui/useless_concat.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 28147dfbea3e0..3a98217f625a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6440,6 +6440,7 @@ Released 2018-09-13 [`used_underscore_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#used_underscore_items [`useless_asref`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_asref [`useless_attribute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_attribute +[`useless_concat`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_concat [`useless_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion [`useless_format`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_format [`useless_let_if_seq`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_let_if_seq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 45ba2f078be78..72ab08792d37e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -51,7 +51,7 @@ Clippy team directly by mentioning them in the issue or over on [Zulip]. All currently active team members can be found [here](https://github.com/rust-lang/rust-clippy/blob/master/triagebot.toml#L18) -Some issues are easier than others. The [`good-first-issue`] label can be used to find the easy +Some issues are easier than others. The [`good first issue`] label can be used to find the easy issues. You can use `@rustbot claim` to assign the issue to yourself. There are also some abandoned PRs, marked with [`S-inactive-closed`]. @@ -70,7 +70,7 @@ To figure out how this syntax structure is encoded in the AST, it is recommended Usually the lint will end up to be a nested series of matches and ifs, [like so][deep-nesting]. But we can make it nest-less by using [let chains], [like this][nest-less]. -[`E-medium`] issues are generally pretty easy too, though it's recommended you work on an [`good-first-issue`] +[`E-medium`] issues are generally pretty easy too, though it's recommended you work on an [`good first issue`] first. Sometimes they are only somewhat involved code wise, but not difficult per-se. Note that [`E-medium`] issues may require some knowledge of Clippy internals or some debugging to find the actual problem behind the issue. @@ -79,7 +79,7 @@ debugging to find the actual problem behind the issue. lot of methods that are useful, though one of the most useful would be `expr_ty` (gives the type of an AST expression). -[`good-first-issue`]: https://github.com/rust-lang/rust-clippy/labels/good-first-issue +[`good first issue`]: https://github.com/rust-lang/rust-clippy/labels/good%20first%20issue [`S-inactive-closed`]: https://github.com/rust-lang/rust-clippy/pulls?q=is%3Aclosed+label%3AS-inactive-closed [`T-AST`]: https://github.com/rust-lang/rust-clippy/labels/T-AST [`T-middle`]: https://github.com/rust-lang/rust-clippy/labels/T-middle diff --git a/Cargo.toml b/Cargo.toml index c7c06afb6129e..f69e5bee4bb2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,6 @@ [package] name = "clippy" -# begin autogenerated version version = "0.1.89" -# end autogenerated version description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/book/src/development/basics.md b/book/src/development/basics.md index cdbbe76bdb08e..fc405249bcfe8 100644 --- a/book/src/development/basics.md +++ b/book/src/development/basics.md @@ -151,7 +151,7 @@ toolchain called `clippy` by default, see `cargo dev setup toolchain --help` for other options. ```terminal -cargo dev setup toolcahin +cargo dev setup toolchain ``` Now you may run `cargo +clippy clippy` in any project using the new toolchain. diff --git a/book/src/development/the_team.md b/book/src/development/the_team.md index da5d084ed97f3..d22123231868e 100644 --- a/book/src/development/the_team.md +++ b/book/src/development/the_team.md @@ -33,7 +33,7 @@ this group to help with triaging, which can include: 1. **Labeling issues** - For the `good-first-issue` label, it can still be good to use `@rustbot` to + For the `good first issue` label, it can still be good to use `@rustbot` to subscribe to the issue and help interested parties, if they post questions in the comments. diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 0db4182dbcdbd..9809e32de8a44 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -836,6 +836,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`manual_repeat_n`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_repeat_n) * [`manual_retain`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain) * [`manual_slice_fill`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_slice_fill) +* [`manual_slice_size_calculation`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_slice_size_calculation) * [`manual_split_once`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once) * [`manual_str_repeat`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat) * [`manual_strip`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip) diff --git a/clippy_config/Cargo.toml b/clippy_config/Cargo.toml index 1134b0e97af22..0606245f990c1 100644 --- a/clippy_config/Cargo.toml +++ b/clippy_config/Cargo.toml @@ -1,8 +1,6 @@ [package] name = "clippy_config" -# begin autogenerated version version = "0.1.89" -# end autogenerated version edition = "2024" publish = false diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index ad0aea39d41a2..4ce8d001c2f00 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -739,6 +739,7 @@ define_Conf! { manual_repeat_n, manual_retain, manual_slice_fill, + manual_slice_size_calculation, manual_split_once, manual_str_repeat, manual_strip, diff --git a/clippy_dev/Cargo.toml b/clippy_dev/Cargo.toml index 47b7b3758613c..10c08dba50b90 100644 --- a/clippy_dev/Cargo.toml +++ b/clippy_dev/Cargo.toml @@ -5,13 +5,11 @@ version = "0.0.1" edition = "2024" [dependencies] -aho-corasick = "1.0" chrono = { version = "0.4.38", default-features = false, features = ["clock"] } clap = { version = "4.4", features = ["derive"] } indoc = "1.0" itertools = "0.12" opener = "0.7" -shell-escape = "0.1" walkdir = "2.3" [package.metadata.rust-analyzer] diff --git a/clippy_dev/src/deprecate_lint.rs b/clippy_dev/src/deprecate_lint.rs index bf0e777104698..3bdc5b2772327 100644 --- a/clippy_dev/src/deprecate_lint.rs +++ b/clippy_dev/src/deprecate_lint.rs @@ -1,6 +1,4 @@ -use crate::update_lints::{ - DeprecatedLint, DeprecatedLints, Lint, find_lint_decls, generate_lint_files, read_deprecated_lints, -}; +use crate::update_lints::{DeprecatedLint, Lint, find_lint_decls, generate_lint_files, read_deprecated_lints}; use crate::utils::{UpdateMode, Version}; use std::ffi::OsStr; use std::path::{Path, PathBuf}; @@ -16,28 +14,34 @@ use std::{fs, io}; /// /// If a file path could not read from or written to pub fn deprecate(clippy_version: Version, name: &str, reason: &str) { - let prefixed_name = if name.starts_with("clippy::") { - name.to_owned() - } else { - format!("clippy::{name}") - }; - let stripped_name = &prefixed_name[8..]; + if let Some((prefix, _)) = name.split_once("::") { + panic!("`{name}` should not contain the `{prefix}` prefix"); + } let mut lints = find_lint_decls(); - let DeprecatedLints { - renamed: renamed_lints, - deprecated: mut deprecated_lints, - file: mut deprecated_file, - contents: mut deprecated_contents, - deprecated_end, - .. - } = read_deprecated_lints(); - - let Some(lint) = lints.iter().find(|l| l.name == stripped_name) else { + let (mut deprecated_lints, renamed_lints) = read_deprecated_lints(); + + let Some(lint) = lints.iter().find(|l| l.name == name) else { eprintln!("error: failed to find lint `{name}`"); return; }; + let prefixed_name = String::from_iter(["clippy::", name]); + match deprecated_lints.binary_search_by(|x| x.name.cmp(&prefixed_name)) { + Ok(_) => { + println!("`{name}` is already deprecated"); + return; + }, + Err(idx) => deprecated_lints.insert( + idx, + DeprecatedLint { + name: prefixed_name, + reason: reason.into(), + version: clippy_version.rust_display().to_string(), + }, + ), + } + let mod_path = { let mut mod_path = PathBuf::from(format!("clippy_lints/src/{}", lint.module)); if mod_path.is_dir() { @@ -48,24 +52,7 @@ pub fn deprecate(clippy_version: Version, name: &str, reason: &str) { mod_path }; - if remove_lint_declaration(stripped_name, &mod_path, &mut lints).unwrap_or(false) { - deprecated_contents.insert_str( - deprecated_end as usize, - &format!( - " #[clippy::version = \"{}\"]\n (\"{}\", \"{}\"),\n", - clippy_version.rust_display(), - prefixed_name, - reason, - ), - ); - deprecated_file.replace_contents(deprecated_contents.as_bytes()); - drop(deprecated_file); - - deprecated_lints.push(DeprecatedLint { - name: prefixed_name, - reason: reason.into(), - }); - + if remove_lint_declaration(name, &mod_path, &mut lints).unwrap_or(false) { generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); println!("info: `{name}` has successfully been deprecated"); println!("note: you must run `cargo uitest` to update the test results"); diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index b4c13213f552a..13d6b1285dcdb 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -1,19 +1,18 @@ +use crate::utils::{ + ClippyInfo, ErrAction, FileUpdater, UpdateMode, UpdateStatus, panic_action, run_with_args_split, run_with_output, +}; use itertools::Itertools; use rustc_lexer::{TokenKind, tokenize}; -use shell_escape::escape; -use std::ffi::{OsStr, OsString}; +use std::fmt::Write; +use std::fs; +use std::io::{self, Read}; use std::ops::ControlFlow; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::process::{self, Command, Stdio}; -use std::{fs, io}; use walkdir::WalkDir; pub enum Error { - CommandFailed(String, String), Io(io::Error), - RustfmtNotInstalled, - WalkDir(walkdir::Error), - IntellijSetupActive, Parse(PathBuf, usize, String), CheckFailed, } @@ -24,37 +23,15 @@ impl From for Error { } } -impl From for Error { - fn from(error: walkdir::Error) -> Self { - Self::WalkDir(error) - } -} - impl Error { fn display(&self) { match self { Self::CheckFailed => { eprintln!("Formatting check failed!\nRun `cargo dev fmt` to update."); }, - Self::CommandFailed(command, stderr) => { - eprintln!("error: command `{command}` failed!\nstderr: {stderr}"); - }, Self::Io(err) => { eprintln!("error: {err}"); }, - Self::RustfmtNotInstalled => { - eprintln!("error: rustfmt nightly is not installed."); - }, - Self::WalkDir(err) => { - eprintln!("error: {err}"); - }, - Self::IntellijSetupActive => { - eprintln!( - "error: a local rustc repo is enabled as path dependency via `cargo dev setup intellij`.\n\ - Not formatting because that would format the local repo as well!\n\ - Please revert the changes to `Cargo.toml`s with `cargo dev remove intellij`." - ); - }, Self::Parse(path, line, msg) => { eprintln!("error parsing `{}:{line}`: {msg}", path.display()); }, @@ -62,12 +39,6 @@ impl Error { } } -struct FmtContext { - check: bool, - verbose: bool, - rustfmt_path: String, -} - struct ClippyConf<'a> { name: &'a str, attrs: &'a str, @@ -257,155 +228,153 @@ fn fmt_conf(check: bool) -> Result<(), Error> { Ok(()) } -fn run_rustfmt(context: &FmtContext) -> Result<(), Error> { - // if we added a local rustc repo as path dependency to clippy for rust analyzer, we do NOT want to - // format because rustfmt would also format the entire rustc repo as it is a local - // dependency - if fs::read_to_string("Cargo.toml") - .expect("Failed to read clippy Cargo.toml") - .contains("[target.'cfg(NOT_A_PLATFORM)'.dependencies]") - { - return Err(Error::IntellijSetupActive); - } - - check_for_rustfmt(context)?; - - cargo_fmt(context, ".".as_ref())?; - cargo_fmt(context, "clippy_dev".as_ref())?; - cargo_fmt(context, "rustc_tools_util".as_ref())?; - cargo_fmt(context, "lintcheck".as_ref())?; - - let chunks = WalkDir::new("tests") - .into_iter() - .filter_map(|entry| { - let entry = entry.expect("failed to find tests"); - let path = entry.path(); - if path.extension() != Some("rs".as_ref()) - || path - .components() - .nth_back(1) - .is_some_and(|c| c.as_os_str() == "syntax-error-recovery") - || entry.file_name() == "ice-3891.rs" - { - None +/// Format the symbols list +fn fmt_syms(update_mode: UpdateMode) { + FileUpdater::default().update_file_checked( + "cargo dev fmt", + update_mode, + "clippy_utils/src/sym.rs", + &mut |_, text: &str, new_text: &mut String| { + let (pre, conf) = text.split_once("generate! {\n").expect("can't find generate! call"); + let (conf, post) = conf.split_once("\n}\n").expect("can't find end of generate! call"); + let mut lines = conf + .lines() + .map(|line| { + let line = line.trim(); + line.strip_suffix(',').unwrap_or(line).trim_end() + }) + .collect::>(); + lines.sort_unstable(); + write!( + new_text, + "{pre}generate! {{\n {},\n}}\n{post}", + lines.join(",\n "), + ) + .unwrap(); + if text == new_text { + UpdateStatus::Unchanged } else { - Some(entry.into_path().into_os_string()) + UpdateStatus::Changed } - }) - .chunks(250); - - for chunk in &chunks { - rustfmt(context, chunk)?; - } - Ok(()) + }, + ); } -// the "main" function of cargo dev fmt -pub fn run(check: bool, verbose: bool) { - let output = Command::new("rustup") - .args(["which", "rustfmt"]) - .stderr(Stdio::inherit()) - .output() - .expect("error running `rustup which rustfmt`"); - if !output.status.success() { - eprintln!("`rustup which rustfmt` did not execute successfully"); - process::exit(1); - } - let mut rustfmt_path = String::from_utf8(output.stdout).expect("invalid rustfmt path"); +fn run_rustfmt(clippy: &ClippyInfo, update_mode: UpdateMode) { + let mut rustfmt_path = String::from_utf8(run_with_output( + "rustup which rustfmt", + Command::new("rustup").args(["which", "rustfmt"]), + )) + .expect("invalid rustfmt path"); rustfmt_path.truncate(rustfmt_path.trim_end().len()); - let context = FmtContext { - check, - verbose, - rustfmt_path, - }; - if let Err(e) = run_rustfmt(&context).and_then(|()| fmt_conf(check)) { - e.display(); - process::exit(1); - } -} - -fn format_command(program: impl AsRef, dir: impl AsRef, args: &[impl AsRef]) -> String { - let arg_display: Vec<_> = args.iter().map(|a| escape(a.as_ref().to_string_lossy())).collect(); - - format!( - "cd {} && {} {}", - escape(dir.as_ref().to_string_lossy()), - escape(program.as_ref().to_string_lossy()), - arg_display.join(" ") - ) -} - -fn exec_fmt_command( - context: &FmtContext, - program: impl AsRef, - dir: impl AsRef, - args: &[impl AsRef], -) -> Result<(), Error> { - if context.verbose { - println!("{}", format_command(&program, &dir, args)); + let mut cargo_path = String::from_utf8(run_with_output( + "rustup which cargo", + Command::new("rustup").args(["which", "cargo"]), + )) + .expect("invalid cargo path"); + cargo_path.truncate(cargo_path.trim_end().len()); + + // Start all format jobs first before waiting on the results. + let mut children = Vec::with_capacity(16); + for &path in &[ + ".", + "clippy_config", + "clippy_dev", + "clippy_lints", + "clippy_lints_internal", + "clippy_utils", + "rustc_tools_util", + "lintcheck", + ] { + let mut cmd = Command::new(&cargo_path); + cmd.current_dir(clippy.path.join(path)) + .args(["fmt"]) + .env("RUSTFMT", &rustfmt_path) + .stdout(Stdio::null()) + .stdin(Stdio::null()) + .stderr(Stdio::piped()); + if update_mode.is_check() { + cmd.arg("--check"); + } + match cmd.spawn() { + Ok(x) => children.push(("cargo fmt", x)), + Err(ref e) => panic_action(&e, ErrAction::Run, "cargo fmt".as_ref()), + } } - let output = Command::new(&program) - .env("RUSTFMT", &context.rustfmt_path) - .current_dir(&dir) - .args(args.iter()) - .output() - .unwrap(); - let success = output.status.success(); - - match (context.check, success) { - (_, true) => Ok(()), - (true, false) => Err(Error::CheckFailed), - (false, false) => { - let stderr = std::str::from_utf8(&output.stderr).unwrap_or(""); - Err(Error::CommandFailed( - format_command(&program, &dir, args), - String::from(stderr), - )) + run_with_args_split( + || { + let mut cmd = Command::new(&rustfmt_path); + if update_mode.is_check() { + cmd.arg("--check"); + } + cmd.stdout(Stdio::null()) + .stdin(Stdio::null()) + .stderr(Stdio::piped()) + .args(["--config", "show_parse_errors=false"]); + cmd }, - } -} + |cmd| match cmd.spawn() { + Ok(x) => children.push(("rustfmt", x)), + Err(ref e) => panic_action(&e, ErrAction::Run, "rustfmt".as_ref()), + }, + WalkDir::new("tests") + .into_iter() + .filter_entry(|p| p.path().file_name().is_none_or(|x| x != "skip_rustfmt")) + .filter_map(|e| { + let e = e.expect("error reading `tests`"); + e.path() + .as_os_str() + .as_encoded_bytes() + .ends_with(b".rs") + .then(|| e.into_path().into_os_string()) + }), + ); -fn cargo_fmt(context: &FmtContext, path: &Path) -> Result<(), Error> { - let mut args = vec!["fmt", "--all"]; - if context.check { - args.push("--check"); + for (name, child) in &mut children { + match child.wait() { + Ok(status) => match (update_mode, status.exit_ok()) { + (UpdateMode::Check | UpdateMode::Change, Ok(())) => {}, + (UpdateMode::Check, Err(_)) => { + let mut s = String::new(); + if let Some(mut stderr) = child.stderr.take() + && stderr.read_to_string(&mut s).is_ok() + { + eprintln!("{s}"); + } + eprintln!("Formatting check failed!\nRun `cargo dev fmt` to update."); + process::exit(1); + }, + (UpdateMode::Change, Err(e)) => { + let mut s = String::new(); + if let Some(mut stderr) = child.stderr.take() + && stderr.read_to_string(&mut s).is_ok() + { + eprintln!("{s}"); + } + panic_action(&e, ErrAction::Run, name.as_ref()); + }, + }, + Err(ref e) => panic_action(e, ErrAction::Run, name.as_ref()), + } } - exec_fmt_command(context, "cargo", path, &args) } -fn check_for_rustfmt(context: &FmtContext) -> Result<(), Error> { - let program = "rustfmt"; - let dir = std::env::current_dir()?; - let args = &["--version"]; - - if context.verbose { - println!("{}", format_command(program, &dir, args)); - } - - let output = Command::new(program).current_dir(&dir).args(args.iter()).output()?; - - if output.status.success() { - Ok(()) - } else if std::str::from_utf8(&output.stderr) - .unwrap_or("") - .starts_with("error: 'rustfmt' is not installed") - { - Err(Error::RustfmtNotInstalled) - } else { - Err(Error::CommandFailed( - format_command(program, &dir, args), - std::str::from_utf8(&output.stderr).unwrap_or("").to_string(), - )) +// the "main" function of cargo dev fmt +pub fn run(clippy: &ClippyInfo, update_mode: UpdateMode) { + if clippy.has_intellij_hook { + eprintln!( + "error: a local rustc repo is enabled as path dependency via `cargo dev setup intellij`.\n\ + Not formatting because that would format the local repo as well!\n\ + Please revert the changes to `Cargo.toml`s with `cargo dev remove intellij`." + ); + return; } -} - -fn rustfmt(context: &FmtContext, paths: impl Iterator) -> Result<(), Error> { - let mut args = Vec::new(); - if context.check { - args.push(OsString::from("--check")); + run_rustfmt(clippy, update_mode); + fmt_syms(update_mode); + if let Err(e) = fmt_conf(update_mode.is_check()) { + e.display(); + process::exit(1); } - args.extend(paths); - exec_fmt_command(context, &context.rustfmt_path, std::env::current_dir()?, &args) } diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index e237a05b2530e..3361443196ab5 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -1,4 +1,12 @@ -#![feature(rustc_private, if_let_guard, let_chains)] +#![feature( + rustc_private, + exit_status_error, + if_let_guard, + let_chains, + os_str_slice, + os_string_truncate, + slice_split_once +)] #![warn( trivial_casts, trivial_numeric_casts, diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 5dce0be742b26..ebcd8611d78cd 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -26,7 +26,7 @@ fn main() { allow_staged, allow_no_vcs, } => dogfood::dogfood(fix, allow_dirty, allow_staged, allow_no_vcs), - DevCommand::Fmt { check, verbose } => fmt::run(check, verbose), + DevCommand::Fmt { check } => fmt::run(&clippy, utils::UpdateMode::from_check(check)), DevCommand::UpdateLints { check } => update_lints::update(utils::UpdateMode::from_check(check)), DevCommand::NewLint { pass, @@ -125,9 +125,6 @@ enum DevCommand { #[arg(long)] /// Use the rustfmt --check option check: bool, - #[arg(short, long)] - /// Echo commands run - verbose: bool, }, #[command(name = "update_lints")] /// Updates lint registration and information from the source code diff --git a/clippy_dev/src/release.rs b/clippy_dev/src/release.rs index d3b1a7ff3201f..62c1bee81850e 100644 --- a/clippy_dev/src/release.rs +++ b/clippy_dev/src/release.rs @@ -1,4 +1,4 @@ -use crate::utils::{FileUpdater, Version, update_text_region_fn}; +use crate::utils::{FileUpdater, UpdateStatus, Version, parse_cargo_package}; use std::fmt::Write; static CARGO_TOML_FILES: &[&str] = &[ @@ -13,15 +13,17 @@ pub fn bump_version(mut version: Version) { let mut updater = FileUpdater::default(); for file in CARGO_TOML_FILES { - updater.update_file( - file, - &mut update_text_region_fn( - "# begin autogenerated version\n", - "# end autogenerated version", - |dst| { - writeln!(dst, "version = \"{}\"", version.toml_display()).unwrap(); - }, - ), - ); + updater.update_file(file, &mut |_, src, dst| { + let package = parse_cargo_package(src); + if package.version_range.is_empty() { + dst.push_str(src); + UpdateStatus::Unchanged + } else { + dst.push_str(&src[..package.version_range.start]); + write!(dst, "\"{}\"", version.toml_display()).unwrap(); + dst.push_str(&src[package.version_range.end..]); + UpdateStatus::from_changed(src.get(package.version_range.clone()) != dst.get(package.version_range)) + } + }); } } diff --git a/clippy_dev/src/rename_lint.rs b/clippy_dev/src/rename_lint.rs index 9e7e5d97f0219..be8b27c7a9e9f 100644 --- a/clippy_dev/src/rename_lint.rs +++ b/clippy_dev/src/rename_lint.rs @@ -1,9 +1,11 @@ -use crate::update_lints::{ - DeprecatedLints, RenamedLint, find_lint_decls, gen_renamed_lints_test_fn, generate_lint_files, - read_deprecated_lints, +use crate::update_lints::{RenamedLint, find_lint_decls, generate_lint_files, read_deprecated_lints}; +use crate::utils::{ + FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, Version, delete_dir_if_exists, delete_file_if_exists, + try_rename_dir, try_rename_file, }; -use crate::utils::{FileUpdater, StringReplacer, UpdateMode, Version, try_rename_file}; -use std::ffi::OsStr; +use rustc_lexer::TokenKind; +use std::ffi::OsString; +use std::fs; use std::path::Path; use walkdir::WalkDir; @@ -22,7 +24,7 @@ use walkdir::WalkDir; /// * If either lint name has a prefix /// * If `old_name` doesn't name an existing lint. /// * If `old_name` names a deprecated or renamed lint. -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines)] pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: bool) { if let Some((prefix, _)) = old_name.split_once("::") { panic!("`{old_name}` should not contain the `{prefix}` prefix"); @@ -33,162 +35,369 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b let mut updater = FileUpdater::default(); let mut lints = find_lint_decls(); - let DeprecatedLints { - renamed: mut renamed_lints, - deprecated: deprecated_lints, - file: mut deprecated_file, - contents: mut deprecated_contents, - renamed_end, - .. - } = read_deprecated_lints(); - - let mut old_lint_index = None; - let mut found_new_name = false; - for (i, lint) in lints.iter().enumerate() { - if lint.name == old_name { - old_lint_index = Some(i); - } else if lint.name == new_name { - found_new_name = true; + let (deprecated_lints, mut renamed_lints) = read_deprecated_lints(); + + let Ok(lint_idx) = lints.binary_search_by(|x| x.name.as_str().cmp(old_name)) else { + panic!("could not find lint `{old_name}`"); + }; + let lint = &lints[lint_idx]; + + let old_name_prefixed = String::from_iter(["clippy::", old_name]); + let new_name_prefixed = if uplift { + new_name.to_owned() + } else { + String::from_iter(["clippy::", new_name]) + }; + + for lint in &mut renamed_lints { + if lint.new_name == old_name_prefixed { + lint.new_name.clone_from(&new_name_prefixed); } } - let old_lint_index = old_lint_index.unwrap_or_else(|| panic!("could not find lint `{old_name}`")); + match renamed_lints.binary_search_by(|x| x.old_name.cmp(&old_name_prefixed)) { + Ok(_) => { + println!("`{old_name}` already has a rename registered"); + return; + }, + Err(idx) => { + renamed_lints.insert( + idx, + RenamedLint { + old_name: old_name_prefixed, + new_name: if uplift { + new_name.to_owned() + } else { + String::from_iter(["clippy::", new_name]) + }, + version: clippy_version.rust_display().to_string(), + }, + ); + }, + } - let lint = RenamedLint { - old_name: format!("clippy::{old_name}"), - new_name: if uplift { - new_name.into() + // Some tests are named `lint_name_suffix` which should also be renamed, + // but we can't do that if the renamed lint's name overlaps with another + // lint. e.g. renaming 'foo' to 'bar' when a lint 'foo_bar' also exists. + let change_prefixed_tests = lints.get(lint_idx + 1).is_none_or(|l| !l.name.starts_with(old_name)); + + let mut mod_edit = ModEdit::None; + if uplift { + let is_unique_mod = lints[..lint_idx].iter().any(|l| l.module == lint.module) + || lints[lint_idx + 1..].iter().any(|l| l.module == lint.module); + if is_unique_mod { + if delete_file_if_exists(lint.path.as_ref()) { + mod_edit = ModEdit::Delete; + } } else { - format!("clippy::{new_name}") - }, - }; + updater.update_file(&lint.path, &mut |_, src, dst| -> UpdateStatus { + let mut start = &src[..lint.declaration_range.start]; + if start.ends_with("\n\n") { + start = &start[..start.len() - 1]; + } + let mut end = &src[lint.declaration_range.end..]; + if end.starts_with("\n\n") { + end = &end[1..]; + } + dst.push_str(start); + dst.push_str(end); + UpdateStatus::Changed + }); + } + delete_test_files(old_name, change_prefixed_tests); + lints.remove(lint_idx); + } else if lints.binary_search_by(|x| x.name.as_str().cmp(new_name)).is_err() { + let lint = &mut lints[lint_idx]; + if lint.module.ends_with(old_name) + && lint + .path + .file_stem() + .is_some_and(|x| x.as_encoded_bytes() == old_name.as_bytes()) + { + let mut new_path = lint.path.with_file_name(new_name).into_os_string(); + new_path.push(".rs"); + if try_rename_file(lint.path.as_ref(), new_path.as_ref()) { + mod_edit = ModEdit::Rename; + } - // Renamed lints and deprecated lints shouldn't have been found in the lint list, but check just in - // case. - assert!( - !renamed_lints.iter().any(|l| lint.old_name == l.old_name), - "`{old_name}` has already been renamed" - ); - assert!( - !deprecated_lints.iter().any(|l| lint.old_name == l.name), - "`{old_name}` has already been deprecated" - ); - - // Update all lint level attributes. (`clippy::lint_name`) - let replacements = &[(&*lint.old_name, &*lint.new_name)]; - let replacer = StringReplacer::new(replacements); - for file in WalkDir::new(".").into_iter().map(Result::unwrap).filter(|f| { - let name = f.path().file_name(); - let ext = f.path().extension(); - (ext == Some(OsStr::new("rs")) || ext == Some(OsStr::new("fixed"))) - && name != Some(OsStr::new("rename.rs")) - && name != Some(OsStr::new("deprecated_lints.rs")) - }) { - updater.update_file(file.path(), &mut replacer.replace_ident_fn()); + let mod_len = lint.module.len(); + lint.module.truncate(mod_len - old_name.len()); + lint.module.push_str(new_name); + } + rename_test_files(old_name, new_name, change_prefixed_tests); + new_name.clone_into(&mut lints[lint_idx].name); + lints.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name)); + } else { + println!("Renamed `clippy::{old_name}` to `clippy::{new_name}`"); + println!("Since `{new_name}` already exists the existing code has not been changed"); + return; } - deprecated_contents.insert_str( - renamed_end as usize, - &format!( - " #[clippy::version = \"{}\"]\n (\"{}\", \"{}\"),\n", - clippy_version.rust_display(), - lint.old_name, - lint.new_name, - ), - ); - deprecated_file.replace_contents(deprecated_contents.as_bytes()); - drop(deprecated_file); - - renamed_lints.push(lint); - renamed_lints.sort_by(|lhs, rhs| { - lhs.new_name - .starts_with("clippy::") - .cmp(&rhs.new_name.starts_with("clippy::")) - .reverse() - .then_with(|| lhs.old_name.cmp(&rhs.old_name)) - }); + let mut update_fn = file_update_fn(old_name, new_name, mod_edit); + for file in WalkDir::new(".").into_iter().filter_entry(|e| { + // Skip traversing some of the larger directories. + e.path() + .as_os_str() + .as_encoded_bytes() + .get(2..) + .is_none_or(|x| x != "target".as_bytes() && x != ".git".as_bytes()) + }) { + let file = file.expect("error reading clippy directory"); + if file.path().as_os_str().as_encoded_bytes().ends_with(b".rs") { + updater.update_file(file.path(), &mut update_fn); + } + } + generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); if uplift { - updater.update_file("tests/ui/rename.rs", &mut gen_renamed_lints_test_fn(&renamed_lints)); - println!( - "`{old_name}` has be uplifted. All the code inside `clippy_lints` related to it needs to be removed manually." - ); - } else if found_new_name { - updater.update_file("tests/ui/rename.rs", &mut gen_renamed_lints_test_fn(&renamed_lints)); - println!( - "`{new_name}` is already defined. The old linting code inside `clippy_lints` needs to be updated/removed manually." - ); - } else { - // Rename the lint struct and source files sharing a name with the lint. - let lint = &mut lints[old_lint_index]; - let old_name_upper = old_name.to_uppercase(); - let new_name_upper = new_name.to_uppercase(); - lint.name = new_name.into(); - - // Rename test files. only rename `.stderr` and `.fixed` files if the new test name doesn't exist. - if try_rename_file( - Path::new(&format!("tests/ui/{old_name}.rs")), - Path::new(&format!("tests/ui/{new_name}.rs")), - ) { - try_rename_file( - Path::new(&format!("tests/ui/{old_name}.stderr")), - Path::new(&format!("tests/ui/{new_name}.stderr")), - ); - try_rename_file( - Path::new(&format!("tests/ui/{old_name}.fixed")), - Path::new(&format!("tests/ui/{new_name}.fixed")), - ); + println!("Uplifted `clippy::{old_name}` as `{new_name}`"); + if matches!(mod_edit, ModEdit::None) { + println!("Only the rename has been registered, the code will need to be edited manually"); + } else { + println!("All the lint's code has been deleted"); + println!("Make sure to inspect the results as some things may have been missed"); } + } else { + println!("Renamed `clippy::{old_name}` to `clippy::{new_name}`"); + println!("All code referencing the old name has been updated"); + println!("Make sure to inspect the results as some things may have been missed"); + } + println!("note: `cargo uibless` still needs to be run to update the test results"); +} + +#[derive(Clone, Copy)] +enum ModEdit { + None, + Delete, + Rename, +} - // Try to rename the file containing the lint if the file name matches the lint's name. - let replacements; - let replacements = if lint.module == old_name - && try_rename_file( - Path::new(&format!("clippy_lints/src/{old_name}.rs")), - Path::new(&format!("clippy_lints/src/{new_name}.rs")), - ) { - // Edit the module name in the lint list. Note there could be multiple lints. - for lint in lints.iter_mut().filter(|l| l.module == old_name) { - lint.module = new_name.into(); +fn collect_ui_test_names(lint: &str, rename_prefixed: bool, dst: &mut Vec<(OsString, bool)>) { + for e in fs::read_dir("tests/ui").expect("error reading `tests/ui`") { + let e = e.expect("error reading `tests/ui`"); + let name = e.file_name(); + if let Some((name_only, _)) = name.as_encoded_bytes().split_once(|&x| x == b'.') { + if name_only.starts_with(lint.as_bytes()) && (rename_prefixed || name_only.len() == lint.len()) { + dst.push((name, true)); } - replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)]; - replacements.as_slice() - } else if !lint.module.contains("::") - // Catch cases like `methods/lint_name.rs` where the lint is stored in `methods/mod.rs` - && try_rename_file( - Path::new(&format!("clippy_lints/src/{}/{old_name}.rs", lint.module)), - Path::new(&format!("clippy_lints/src/{}/{new_name}.rs", lint.module)), - ) + } else if name.as_encoded_bytes().starts_with(lint.as_bytes()) && (rename_prefixed || name.len() == lint.len()) { - // Edit the module name in the lint list. Note there could be multiple lints, or none. - let renamed_mod = format!("{}::{old_name}", lint.module); - for lint in lints.iter_mut().filter(|l| l.module == renamed_mod) { - lint.module = format!("{}::{new_name}", lint.module); + dst.push((name, false)); + } + } +} + +fn collect_ui_toml_test_names(lint: &str, rename_prefixed: bool, dst: &mut Vec<(OsString, bool)>) { + if rename_prefixed { + for e in fs::read_dir("tests/ui-toml").expect("error reading `tests/ui-toml`") { + let e = e.expect("error reading `tests/ui-toml`"); + let name = e.file_name(); + if name.as_encoded_bytes().starts_with(lint.as_bytes()) && e.file_type().is_ok_and(|ty| ty.is_dir()) { + dst.push((name, false)); } - replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)]; - replacements.as_slice() + } + } else { + dst.push((lint.into(), false)); + } +} + +/// Renames all test files for the given lint. +/// +/// If `rename_prefixed` is `true` this will also rename tests which have the lint name as a prefix. +fn rename_test_files(old_name: &str, new_name: &str, rename_prefixed: bool) { + let mut tests = Vec::new(); + + let mut old_buf = OsString::from("tests/ui/"); + let mut new_buf = OsString::from("tests/ui/"); + collect_ui_test_names(old_name, rename_prefixed, &mut tests); + for &(ref name, is_file) in &tests { + old_buf.push(name); + new_buf.extend([new_name.as_ref(), name.slice_encoded_bytes(old_name.len()..)]); + if is_file { + try_rename_file(old_buf.as_ref(), new_buf.as_ref()); } else { - replacements = [(&*old_name_upper, &*new_name_upper), ("", "")]; - &replacements[0..1] - }; - - // Don't change `clippy_utils/src/renamed_lints.rs` here as it would try to edit the lint being - // renamed. - let replacer = StringReplacer::new(replacements); - for file in WalkDir::new("clippy_lints/src") { - let file = file.expect("error reading `clippy_lints/src`"); - if file - .path() - .as_os_str() - .to_str() - .is_some_and(|x| x.ends_with("*.rs") && x["clippy_lints/src/".len()..] != *"deprecated_lints.rs") - { - updater.update_file(file.path(), &mut replacer.replace_ident_fn()); - } + try_rename_dir(old_buf.as_ref(), new_buf.as_ref()); + } + old_buf.truncate("tests/ui/".len()); + new_buf.truncate("tests/ui/".len()); + } + + tests.clear(); + old_buf.truncate("tests/ui".len()); + new_buf.truncate("tests/ui".len()); + old_buf.push("-toml/"); + new_buf.push("-toml/"); + collect_ui_toml_test_names(old_name, rename_prefixed, &mut tests); + for (name, _) in &tests { + old_buf.push(name); + new_buf.extend([new_name.as_ref(), name.slice_encoded_bytes(old_name.len()..)]); + try_rename_dir(old_buf.as_ref(), new_buf.as_ref()); + old_buf.truncate("tests/ui/".len()); + new_buf.truncate("tests/ui/".len()); + } +} + +fn delete_test_files(lint: &str, rename_prefixed: bool) { + let mut tests = Vec::new(); + + let mut buf = OsString::from("tests/ui/"); + collect_ui_test_names(lint, rename_prefixed, &mut tests); + for &(ref name, is_file) in &tests { + buf.push(name); + if is_file { + delete_file_if_exists(buf.as_ref()); + } else { + delete_dir_if_exists(buf.as_ref()); } + buf.truncate("tests/ui/".len()); + } - generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); - println!("{old_name} has been successfully renamed"); + buf.truncate("tests/ui".len()); + buf.push("-toml/"); + + tests.clear(); + collect_ui_toml_test_names(lint, rename_prefixed, &mut tests); + for (name, _) in &tests { + buf.push(name); + delete_dir_if_exists(buf.as_ref()); + buf.truncate("tests/ui/".len()); } +} - println!("note: `cargo uitest` still needs to be run to update the test results"); +fn snake_to_pascal(s: &str) -> String { + let mut dst = Vec::with_capacity(s.len()); + let mut iter = s.bytes(); + || -> Option<()> { + dst.push(iter.next()?.to_ascii_uppercase()); + while let Some(c) = iter.next() { + if c == b'_' { + dst.push(iter.next()?.to_ascii_uppercase()); + } else { + dst.push(c); + } + } + Some(()) + }(); + String::from_utf8(dst).unwrap() +} + +#[expect(clippy::too_many_lines)] +fn file_update_fn<'a, 'b>( + old_name: &'a str, + new_name: &'b str, + mod_edit: ModEdit, +) -> impl use<'a, 'b> + FnMut(&Path, &str, &mut String) -> UpdateStatus { + let old_name_pascal = snake_to_pascal(old_name); + let new_name_pascal = snake_to_pascal(new_name); + let old_name_upper = old_name.to_ascii_uppercase(); + let new_name_upper = new_name.to_ascii_uppercase(); + move |_, src, dst| { + let mut copy_pos = 0u32; + let mut changed = false; + let mut searcher = RustSearcher::new(src); + let mut capture = ""; + loop { + match searcher.peek() { + TokenKind::Eof => break, + TokenKind::Ident => { + let match_start = searcher.pos(); + let text = searcher.peek_text(); + searcher.step(); + match text { + // clippy::line_name or clippy::lint-name + "clippy" => { + if searcher.match_tokens(&[Token::DoubleColon, Token::CaptureIdent], &mut [&mut capture]) + && capture == old_name + { + dst.push_str(&src[copy_pos as usize..searcher.pos() as usize - capture.len()]); + dst.push_str(new_name); + copy_pos = searcher.pos(); + changed = true; + } + }, + // mod lint_name + "mod" => { + if !matches!(mod_edit, ModEdit::None) + && searcher.match_tokens(&[Token::CaptureIdent], &mut [&mut capture]) + && capture == old_name + { + match mod_edit { + ModEdit::Rename => { + dst.push_str(&src[copy_pos as usize..searcher.pos() as usize - capture.len()]); + dst.push_str(new_name); + copy_pos = searcher.pos(); + changed = true; + }, + ModEdit::Delete if searcher.match_tokens(&[Token::Semi], &mut []) => { + let mut start = &src[copy_pos as usize..match_start as usize]; + if start.ends_with("\n\n") { + start = &start[..start.len() - 1]; + } + dst.push_str(start); + copy_pos = searcher.pos(); + if src[copy_pos as usize..].starts_with("\n\n") { + copy_pos += 1; + } + changed = true; + }, + ModEdit::Delete | ModEdit::None => {}, + } + } + }, + // lint_name:: + name if matches!(mod_edit, ModEdit::Rename) && name == old_name => { + let name_end = searcher.pos(); + if searcher.match_tokens(&[Token::DoubleColon], &mut []) { + dst.push_str(&src[copy_pos as usize..match_start as usize]); + dst.push_str(new_name); + copy_pos = name_end; + changed = true; + } + }, + // LINT_NAME or LintName + name => { + let replacement = if name == old_name_upper { + &new_name_upper + } else if name == old_name_pascal { + &new_name_pascal + } else { + continue; + }; + dst.push_str(&src[copy_pos as usize..match_start as usize]); + dst.push_str(replacement); + copy_pos = searcher.pos(); + changed = true; + }, + } + }, + // //~ lint_name + TokenKind::LineComment { doc_style: None } => { + let text = searcher.peek_text(); + if text.starts_with("//~") + && let Some(text) = text.strip_suffix(old_name) + && !text.ends_with(|c| matches!(c, 'a'..='z' | 'A'..='Z' | '0'..='9' | '_')) + { + dst.push_str(&src[copy_pos as usize..searcher.pos() as usize + text.len()]); + dst.push_str(new_name); + copy_pos = searcher.pos() + searcher.peek_len(); + changed = true; + } + searcher.step(); + }, + // ::lint_name + TokenKind::Colon + if searcher.match_tokens(&[Token::DoubleColon, Token::CaptureIdent], &mut [&mut capture]) + && capture == old_name => + { + dst.push_str(&src[copy_pos as usize..searcher.pos() as usize - capture.len()]); + dst.push_str(new_name); + copy_pos = searcher.pos(); + changed = true; + }, + _ => searcher.step(), + } + } + + dst.push_str(&src[copy_pos as usize..]); + UpdateStatus::from_changed(changed) + } } diff --git a/clippy_dev/src/sync.rs b/clippy_dev/src/sync.rs index c699b0d7b959c..98fd72fc0bd1a 100644 --- a/clippy_dev/src/sync.rs +++ b/clippy_dev/src/sync.rs @@ -4,15 +4,22 @@ use std::fmt::Write; pub fn update_nightly() { let date = Utc::now().format("%Y-%m-%d").to_string(); - let update = &mut update_text_region_fn( + let toolchain_update = &mut update_text_region_fn( "# begin autogenerated nightly\n", "# end autogenerated nightly", |dst| { writeln!(dst, "channel = \"nightly-{date}\"").unwrap(); }, ); + let readme_update = &mut update_text_region_fn( + "\n", + "", + |dst| { + writeln!(dst, "```\nnightly-{date}\n```").unwrap(); + }, + ); let mut updater = FileUpdater::default(); - updater.update_file("rust-toolchain.toml", update); - updater.update_file("clippy_utils/README.md", update); + updater.update_file("rust-toolchain.toml", toolchain_update); + updater.update_file("clippy_utils/README.md", readme_update); } diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 0c861b7293562..25ba2c7204904 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -1,12 +1,11 @@ use crate::utils::{ - File, FileAction, FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, panic_file, update_text_region_fn, + ErrAction, File, FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, panic_action, update_text_region_fn, }; use itertools::Itertools; use std::collections::HashSet; use std::fmt::Write; -use std::fs::OpenOptions; use std::ops::Range; -use std::path::Path; +use std::path::{Path, PathBuf}; use walkdir::{DirEntry, WalkDir}; const GENERATED_FILE_COMMENT: &str = "// This file was generated by `cargo dev update_lints`.\n\ @@ -26,12 +25,11 @@ const DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.ht%20///%20Panics%20if%20a%20file%20path%20could%20not%20read%20from%20or%20then%20written%20to%20pub%20fn%20update(update_mode:%20UpdateMode)%20%7B%20%20%20%20%20let%20lints%20=%20find_lint_decls();-%20%20%20%20let%20DeprecatedLints%20%7B-%20%20%20%20%20%20%20%20renamed,%20deprecated,%20..-%20%20%20%20%7D%20=%20read_deprecated_lints();+%20%20%20%20let%20(deprecated,%20renamed)%20=%20read_deprecated_lints();%20%20%20%20%20generate_lint_files(update_mode,%20&lints,%20&deprecated,%20&renamed);%20%7D%20+#[expect(clippy::too_many_lines)]%20pub%20fn%20generate_lint_files(%20%20%20%20%20update_mode:%20UpdateMode,%20%20%20%20%20lints:%20&[Lint],@@%20-93,6%20+91,40%20@@%20pub%20fn%20generate_lint_files(%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dst.push_str("];\n"); UpdateStatus::from_changed(src != dst) }), + ("clippy_lints/src/deprecated_lints.rs", &mut |_, src, dst| { + let mut searcher = RustSearcher::new(src); + assert!( + searcher.find_token(Token::Ident("declare_with_version")) + && searcher.find_token(Token::Ident("declare_with_version")), + "error reading deprecated lints" + ); + dst.push_str(&src[..searcher.pos() as usize]); + dst.push_str("! { DEPRECATED(DEPRECATED_VERSION) = [\n"); + for lint in deprecated { + write!( + dst, + " #[clippy::version = \"{}\"]\n (\"{}\", \"{}\"),\n", + lint.version, lint.name, lint.reason, + ) + .unwrap(); + } + dst.push_str( + "]}\n\n\ + #[rustfmt::skip]\n\ + declare_with_version! { RENAMED(RENAMED_VERSION) = [\n\ + ", + ); + for lint in renamed { + write!( + dst, + " #[clippy::version = \"{}\"]\n (\"{}\", \"{}\"),\n", + lint.version, lint.old_name, lint.new_name, + ) + .unwrap(); + } + dst.push_str("]}\n"); + UpdateStatus::from_changed(src != dst) + }), ("tests/ui/deprecated.rs", &mut |_, src, dst| { dst.push_str(GENERATED_FILE_COMMENT); for lint in deprecated { @@ -101,7 +133,24 @@ pub fn generate_lint_files( dst.push_str("\nfn main() {}\n"); UpdateStatus::from_changed(src != dst) }), - ("tests/ui/rename.rs", &mut gen_renamed_lints_test_fn(renamed)), + ("tests/ui/rename.rs", &mut move |_, src, dst| { + let mut seen_lints = HashSet::new(); + dst.push_str(GENERATED_FILE_COMMENT); + dst.push_str("#![allow(clippy::duplicated_attributes)]\n"); + for lint in renamed { + if seen_lints.insert(&lint.new_name) { + writeln!(dst, "#![allow({})]", lint.new_name).unwrap(); + } + } + seen_lints.clear(); + for lint in renamed { + if seen_lints.insert(&lint.old_name) { + writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.old_name, lint.old_name).unwrap(); + } + } + dst.push_str("\nfn main() {}\n"); + UpdateStatus::from_changed(src != dst) + }), ], ); } @@ -111,44 +160,25 @@ fn round_to_fifty(count: usize) -> usize { } /// Lint data parsed from the Clippy source code. -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(PartialEq, Eq, Debug)] pub struct Lint { pub name: String, pub group: String, pub module: String, + pub path: PathBuf, pub declaration_range: Range, } -#[derive(Clone, PartialEq, Eq, Debug)] pub struct DeprecatedLint { pub name: String, pub reason: String, + pub version: String, } pub struct RenamedLint { pub old_name: String, pub new_name: String, -} - -pub fn gen_renamed_lints_test_fn(lints: &[RenamedLint]) -> impl Fn(&Path, &str, &mut String) -> UpdateStatus { - move |_, src, dst| { - let mut seen_lints = HashSet::new(); - dst.push_str(GENERATED_FILE_COMMENT); - dst.push_str("#![allow(clippy::duplicated_attributes)]\n"); - for lint in lints { - if seen_lints.insert(&lint.new_name) { - writeln!(dst, "#![allow({})]", lint.new_name).unwrap(); - } - } - seen_lints.clear(); - for lint in lints { - if seen_lints.insert(&lint.old_name) { - writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.old_name, lint.old_name).unwrap(); - } - } - dst.push_str("\nfn main() {}\n"); - UpdateStatus::from_changed(src != dst) - } + pub version: String, } /// Finds all lint declarations (`declare_clippy_lint!`) @@ -158,6 +188,7 @@ pub fn find_lint_decls() -> Vec { let mut contents = String::new(); for (file, module) in read_src_with_module("clippy_lints/src".as_ref()) { parse_clippy_lint_decls( + file.path(), File::open_read_to_cleared_string(file.path(), &mut contents), &module, &mut lints, @@ -172,7 +203,7 @@ fn read_src_with_module(src_root: &Path) -> impl use<'_> + Iterator e, - Err(ref e) => panic_file(e, FileAction::Read, src_root), + Err(ref e) => panic_action(e, ErrAction::Read, src_root), }; let path = e.path().as_os_str().as_encoded_bytes(); if let Some(path) = path.strip_suffix(b".rs") @@ -202,17 +233,17 @@ fn read_src_with_module(src_root: &Path) -> impl use<'_> + Iterator) { +fn parse_clippy_lint_decls(path: &Path, contents: &str, module: &str, lints: &mut Vec) { #[allow(clippy::enum_glob_use)] use Token::*; #[rustfmt::skip] - static DECL_TOKENS: &[Token] = &[ + static DECL_TOKENS: &[Token<'_>] = &[ // !{ /// docs - Bang, OpenBrace, AnyDoc, + Bang, OpenBrace, AnyComment, // #[clippy::version = "version"] Pound, OpenBracket, Ident("clippy"), DoubleColon, Ident("version"), Eq, LitStr, CloseBracket, // pub NAME, GROUP, - Ident("pub"), CaptureIdent, Comma, CaptureIdent, Comma, + Ident("pub"), CaptureIdent, Comma, AnyComment, CaptureIdent, Comma, ]; let mut searcher = RustSearcher::new(contents); @@ -224,55 +255,42 @@ fn parse_clippy_lint_decls(contents: &str, module: &str, lints: &mut Vec) name: name.to_lowercase(), group: group.into(), module: module.into(), + path: path.into(), declaration_range: start..searcher.pos() as usize, }); } } } -pub struct DeprecatedLints { - pub file: File<'static>, - pub contents: String, - pub deprecated: Vec, - pub renamed: Vec, - pub deprecated_end: u32, - pub renamed_end: u32, -} - #[must_use] -pub fn read_deprecated_lints() -> DeprecatedLints { +pub fn read_deprecated_lints() -> (Vec, Vec) { #[allow(clippy::enum_glob_use)] use Token::*; #[rustfmt::skip] - static DECL_TOKENS: &[Token] = &[ + static DECL_TOKENS: &[Token<'_>] = &[ // #[clippy::version = "version"] - Pound, OpenBracket, Ident("clippy"), DoubleColon, Ident("version"), Eq, LitStr, CloseBracket, + Pound, OpenBracket, Ident("clippy"), DoubleColon, Ident("version"), Eq, CaptureLitStr, CloseBracket, // ("first", "second"), OpenParen, CaptureLitStr, Comma, CaptureLitStr, CloseParen, Comma, ]; #[rustfmt::skip] - static DEPRECATED_TOKENS: &[Token] = &[ + static DEPRECATED_TOKENS: &[Token<'_>] = &[ // !{ DEPRECATED(DEPRECATED_VERSION) = [ Bang, OpenBrace, Ident("DEPRECATED"), OpenParen, Ident("DEPRECATED_VERSION"), CloseParen, Eq, OpenBracket, ]; #[rustfmt::skip] - static RENAMED_TOKENS: &[Token] = &[ + static RENAMED_TOKENS: &[Token<'_>] = &[ // !{ RENAMED(RENAMED_VERSION) = [ Bang, OpenBrace, Ident("RENAMED"), OpenParen, Ident("RENAMED_VERSION"), CloseParen, Eq, OpenBracket, ]; let path = "clippy_lints/src/deprecated_lints.rs"; - let mut res = DeprecatedLints { - file: File::open(path, OpenOptions::new().read(true).write(true)), - contents: String::new(), - deprecated: Vec::with_capacity(30), - renamed: Vec::with_capacity(80), - deprecated_end: 0, - renamed_end: 0, - }; + let mut deprecated = Vec::with_capacity(30); + let mut renamed = Vec::with_capacity(80); + let mut contents = String::new(); + File::open_read_to_cleared_string(path, &mut contents); - res.file.read_append_to_string(&mut res.contents); - let mut searcher = RustSearcher::new(&res.contents); + let mut searcher = RustSearcher::new(&contents); // First instance is the macro definition. assert!( @@ -281,36 +299,38 @@ pub fn read_deprecated_lints() -> DeprecatedLints { ); if searcher.find_token(Ident("declare_with_version")) && searcher.match_tokens(DEPRECATED_TOKENS, &mut []) { + let mut version = ""; let mut name = ""; let mut reason = ""; - while searcher.match_tokens(DECL_TOKENS, &mut [&mut name, &mut reason]) { - res.deprecated.push(DeprecatedLint { + while searcher.match_tokens(DECL_TOKENS, &mut [&mut version, &mut name, &mut reason]) { + deprecated.push(DeprecatedLint { name: parse_str_single_line(path.as_ref(), name), reason: parse_str_single_line(path.as_ref(), reason), + version: parse_str_single_line(path.as_ref(), version), }); } } else { panic!("error reading deprecated lints"); } - // position of the closing `]}` of `declare_with_version` - res.deprecated_end = searcher.pos(); if searcher.find_token(Ident("declare_with_version")) && searcher.match_tokens(RENAMED_TOKENS, &mut []) { + let mut version = ""; let mut old_name = ""; let mut new_name = ""; - while searcher.match_tokens(DECL_TOKENS, &mut [&mut old_name, &mut new_name]) { - res.renamed.push(RenamedLint { + while searcher.match_tokens(DECL_TOKENS, &mut [&mut version, &mut old_name, &mut new_name]) { + renamed.push(RenamedLint { old_name: parse_str_single_line(path.as_ref(), old_name), new_name: parse_str_single_line(path.as_ref(), new_name), + version: parse_str_single_line(path.as_ref(), version), }); } } else { panic!("error reading renamed lints"); } - // position of the closing `]}` of `declare_with_version` - res.renamed_end = searcher.pos(); - res + deprecated.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name)); + renamed.sort_by(|lhs, rhs| lhs.old_name.cmp(&rhs.old_name)); + (deprecated, renamed) } /// Removes the line splices and surrounding quotes from a string literal @@ -366,7 +386,7 @@ mod tests { } "#; let mut result = Vec::new(); - parse_clippy_lint_decls(CONTENTS, "module_name", &mut result); + parse_clippy_lint_decls("".as_ref(), CONTENTS, "module_name", &mut result); for r in &mut result { r.declaration_range = Range::default(); } @@ -376,12 +396,14 @@ mod tests { name: "ptr_arg".into(), group: "style".into(), module: "module_name".into(), + path: PathBuf::new(), declaration_range: Range::default(), }, Lint { name: "doc_markdown".into(), group: "pedantic".into(), module: "module_name".into(), + path: PathBuf::new(), declaration_range: Range::default(), }, ]; diff --git a/clippy_dev/src/utils.rs b/clippy_dev/src/utils.rs index ae2eabc45dd00..255e36afe69c2 100644 --- a/clippy_dev/src/utils.rs +++ b/clippy_dev/src/utils.rs @@ -1,13 +1,14 @@ -use aho_corasick::{AhoCorasick, AhoCorasickBuilder}; use core::fmt::{self, Display}; +use core::ops::Range; use core::slice; use core::str::FromStr; use rustc_lexer::{self as lexer, FrontmatterAllowed}; use std::env; +use std::ffi::OsStr; use std::fs::{self, OpenOptions}; use std::io::{self, Read as _, Seek as _, SeekFrom, Write}; use std::path::{Path, PathBuf}; -use std::process::{self, ExitStatus}; +use std::process::{self, Command, ExitStatus, Stdio}; #[cfg(not(windows))] static CARGO_CLIPPY_EXE: &str = "cargo-clippy"; @@ -15,14 +16,16 @@ static CARGO_CLIPPY_EXE: &str = "cargo-clippy"; static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe"; #[derive(Clone, Copy)] -pub enum FileAction { +pub enum ErrAction { Open, Read, Write, Create, Rename, + Delete, + Run, } -impl FileAction { +impl ErrAction { fn as_str(self) -> &'static str { match self { Self::Open => "opening", @@ -30,13 +33,15 @@ impl FileAction { Self::Write => "writing", Self::Create => "creating", Self::Rename => "renaming", + Self::Delete => "deleting", + Self::Run => "running", } } } #[cold] #[track_caller] -pub fn panic_file(err: &impl Display, action: FileAction, path: &Path) -> ! { +pub fn panic_action(err: &impl Display, action: ErrAction, path: &Path) -> ! { panic!("error {} `{}`: {}", action.as_str(), path.display(), *err) } @@ -52,7 +57,7 @@ impl<'a> File<'a> { let path = path.as_ref(); match options.open(path) { Ok(inner) => Self { inner, path }, - Err(e) => panic_file(&e, FileAction::Open, path), + Err(e) => panic_action(&e, ErrAction::Open, path), } } @@ -63,7 +68,7 @@ impl<'a> File<'a> { match options.open(path) { Ok(inner) => Some(Self { inner, path }), Err(e) if e.kind() == io::ErrorKind::NotFound => None, - Err(e) => panic_file(&e, FileAction::Open, path), + Err(e) => panic_action(&e, ErrAction::Open, path), } } @@ -81,7 +86,7 @@ impl<'a> File<'a> { pub fn read_append_to_string<'dst>(&mut self, dst: &'dst mut String) -> &'dst mut String { match self.inner.read_to_string(dst) { Ok(_) => {}, - Err(e) => panic_file(&e, FileAction::Read, self.path), + Err(e) => panic_action(&e, ErrAction::Read, self.path), } dst } @@ -103,7 +108,7 @@ impl<'a> File<'a> { Err(e) => Err(e), }; if let Err(e) = res { - panic_file(&e, FileAction::Write, self.path); + panic_action(&e, ErrAction::Write, self.path); } } } @@ -165,9 +170,83 @@ impl Version { } } +enum TomlPart<'a> { + Table(&'a str), + Value(&'a str, &'a str), +} + +fn toml_iter(s: &str) -> impl Iterator)> { + let mut pos = 0; + s.split('\n') + .map(move |s| { + let x = pos; + pos += s.len() + 1; + (x, s) + }) + .filter_map(|(pos, s)| { + if let Some(s) = s.strip_prefix('[') { + s.split_once(']').map(|(name, _)| (pos, TomlPart::Table(name))) + } else if matches!(s.bytes().next(), Some(b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_')) { + s.split_once('=').map(|(key, value)| (pos, TomlPart::Value(key, value))) + } else { + None + } + }) +} + +pub struct CargoPackage<'a> { + pub name: &'a str, + pub version_range: Range, + pub not_a_platform_range: Range, +} + +#[must_use] +pub fn parse_cargo_package(s: &str) -> CargoPackage<'_> { + let mut in_package = false; + let mut in_platform_deps = false; + let mut name = ""; + let mut version_range = 0..0; + let mut not_a_platform_range = 0..0; + for (offset, part) in toml_iter(s) { + match part { + TomlPart::Table(name) => { + if in_platform_deps { + not_a_platform_range.end = offset; + } + in_package = false; + in_platform_deps = false; + + match name.trim() { + "package" => in_package = true, + "target.'cfg(NOT_A_PLATFORM)'.dependencies" => { + in_platform_deps = true; + not_a_platform_range.start = offset; + }, + _ => {}, + } + }, + TomlPart::Value(key, value) if in_package => match key.trim_end() { + "name" => name = value.trim(), + "version" => { + version_range.start = offset + (value.len() - value.trim().len()) + key.len() + 1; + version_range.end = offset + key.len() + value.trim_end().len() + 1; + }, + _ => {}, + }, + TomlPart::Value(..) => {}, + } + } + CargoPackage { + name, + version_range, + not_a_platform_range, + } +} + pub struct ClippyInfo { pub path: PathBuf, pub version: Version, + pub has_intellij_hook: bool, } impl ClippyInfo { #[must_use] @@ -177,35 +256,21 @@ impl ClippyInfo { loop { path.push("Cargo.toml"); if let Some(mut file) = File::open_if_exists(&path, OpenOptions::new().read(true)) { - let mut in_package = false; - let mut is_clippy = false; - let mut version: Option = None; - - // Ad-hoc parsing to avoid dependencies. We control all the file so this - // isn't actually a problem - for line in file.read_to_cleared_string(&mut buf).lines() { - if line.starts_with('[') { - in_package = line.starts_with("[package]"); - } else if in_package && let Some((name, value)) = line.split_once('=') { - match name.trim() { - "name" => is_clippy = value.trim() == "\"clippy\"", - "version" - if let Some(value) = value.trim().strip_prefix('"') - && let Some(value) = value.strip_suffix('"') => - { - version = value.parse().ok(); - }, - _ => {}, - } + file.read_to_cleared_string(&mut buf); + let package = parse_cargo_package(&buf); + if package.name == "\"clippy\"" { + if let Some(version) = buf[package.version_range].strip_prefix('"') + && let Some(version) = version.strip_suffix('"') + && let Ok(version) = version.parse() + { + path.pop(); + return ClippyInfo { + path, + version, + has_intellij_hook: !package.not_a_platform_range.is_empty(), + }; } - } - - if is_clippy { - let Some(version) = version else { - panic!("error reading clippy version from {}", file.path.display()); - }; - path.pop(); - return ClippyInfo { path, version }; + panic!("error reading clippy version from `{}`", file.path.display()); } } @@ -258,6 +323,11 @@ impl UpdateMode { pub fn from_check(check: bool) -> Self { if check { Self::Check } else { Self::Change } } + + #[must_use] + pub fn is_check(self) -> bool { + matches!(self, Self::Check) + } } #[derive(Default)] @@ -366,53 +436,11 @@ pub fn update_text_region_fn( move |path, src, dst| update_text_region(path, start, end, src, dst, &mut insert) } -#[must_use] -pub fn is_ident_char(c: u8) -> bool { - matches!(c, b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_') -} - -pub struct StringReplacer<'a> { - searcher: AhoCorasick, - replacements: &'a [(&'a str, &'a str)], -} -impl<'a> StringReplacer<'a> { - #[must_use] - pub fn new(replacements: &'a [(&'a str, &'a str)]) -> Self { - Self { - searcher: AhoCorasickBuilder::new() - .match_kind(aho_corasick::MatchKind::LeftmostLongest) - .build(replacements.iter().map(|&(x, _)| x)) - .unwrap(), - replacements, - } - } - - /// Replace substrings if they aren't bordered by identifier characters. - pub fn replace_ident_fn(&self) -> impl Fn(&Path, &str, &mut String) -> UpdateStatus { - move |_, src, dst| { - let mut pos = 0; - let mut changed = false; - for m in self.searcher.find_iter(src) { - if !is_ident_char(src.as_bytes().get(m.start().wrapping_sub(1)).copied().unwrap_or(0)) - && !is_ident_char(src.as_bytes().get(m.end()).copied().unwrap_or(0)) - { - changed = true; - dst.push_str(&src[pos..m.start()]); - dst.push_str(self.replacements[m.pattern()].1); - pos = m.end(); - } - } - dst.push_str(&src[pos..]); - UpdateStatus::from_changed(changed) - } - } -} - #[derive(Clone, Copy)] -pub enum Token { - /// Matches any number of doc comments. - AnyDoc, - Ident(&'static str), +pub enum Token<'a> { + /// Matches any number of comments / doc comments. + AnyComment, + Ident(&'a str), CaptureIdent, LitStr, CaptureLitStr, @@ -431,29 +459,26 @@ pub enum Token { OpenBracket, OpenParen, Pound, + Semi, + Slash, } pub struct RustSearcher<'txt> { text: &'txt str, cursor: lexer::Cursor<'txt>, pos: u32, - - // Either the next token or a zero-sized whitespace sentinel. next_token: lexer::Token, } impl<'txt> RustSearcher<'txt> { #[must_use] + #[expect(clippy::inconsistent_struct_constructor)] pub fn new(text: &'txt str) -> Self { + let mut cursor = lexer::Cursor::new(text, FrontmatterAllowed::Yes); Self { text, - cursor: lexer::Cursor::new(text, FrontmatterAllowed::Yes), pos: 0, - - // Sentinel value indicating there is no read token. - next_token: lexer::Token { - len: 0, - kind: lexer::TokenKind::Whitespace, - }, + next_token: cursor.advance_token(), + cursor, } } @@ -462,6 +487,11 @@ impl<'txt> RustSearcher<'txt> { &self.text[self.pos as usize..(self.pos + self.next_token.len) as usize] } + #[must_use] + pub fn peek_len(&self) -> u32 { + self.next_token.len + } + #[must_use] pub fn peek(&self) -> lexer::TokenKind { self.next_token.kind @@ -485,37 +515,15 @@ impl<'txt> RustSearcher<'txt> { /// Consumes the next token if it matches the requested value and captures the value if /// requested. Returns true if a token was matched. - fn read_token(&mut self, token: Token, captures: &mut slice::IterMut<'_, &mut &'txt str>) -> bool { + fn read_token(&mut self, token: Token<'_>, captures: &mut slice::IterMut<'_, &mut &'txt str>) -> bool { loop { match (token, self.next_token.kind) { - // Has to be the first match arm so the empty sentinel token will be handled. - // This will also skip all whitespace/comments preceding any tokens. - ( - _, - lexer::TokenKind::Whitespace - | lexer::TokenKind::LineComment { doc_style: None } - | lexer::TokenKind::BlockComment { - doc_style: None, - terminated: true, - }, - ) => { - self.step(); - if self.at_end() { - // `AnyDoc` always matches. - return matches!(token, Token::AnyDoc); - } - }, - ( - Token::AnyDoc, + (_, lexer::TokenKind::Whitespace) + | ( + Token::AnyComment, lexer::TokenKind::BlockComment { terminated: true, .. } | lexer::TokenKind::LineComment { .. }, - ) => { - self.step(); - if self.at_end() { - // `AnyDoc` always matches. - return true; - } - }, - (Token::AnyDoc, _) => return true, + ) => self.step(), + (Token::AnyComment, _) => return true, (Token::Bang, lexer::TokenKind::Bang) | (Token::CloseBrace, lexer::TokenKind::CloseBrace) | (Token::CloseBracket, lexer::TokenKind::CloseBracket) @@ -529,6 +537,8 @@ impl<'txt> RustSearcher<'txt> { | (Token::OpenBracket, lexer::TokenKind::OpenBracket) | (Token::OpenParen, lexer::TokenKind::OpenParen) | (Token::Pound, lexer::TokenKind::Pound) + | (Token::Semi, lexer::TokenKind::Semi) + | (Token::Slash, lexer::TokenKind::Slash) | ( Token::LitStr, lexer::TokenKind::Literal { @@ -569,7 +579,7 @@ impl<'txt> RustSearcher<'txt> { } #[must_use] - pub fn find_token(&mut self, token: Token) -> bool { + pub fn find_token(&mut self, token: Token<'_>) -> bool { let mut capture = [].iter_mut(); while !self.read_token(token, &mut capture) { self.step(); @@ -581,7 +591,7 @@ impl<'txt> RustSearcher<'txt> { } #[must_use] - pub fn find_capture_token(&mut self, token: Token) -> Option<&'txt str> { + pub fn find_capture_token(&mut self, token: Token<'_>) -> Option<&'txt str> { let mut res = ""; let mut capture = &mut res; let mut capture = slice::from_mut(&mut capture).iter_mut(); @@ -595,7 +605,7 @@ impl<'txt> RustSearcher<'txt> { } #[must_use] - pub fn match_tokens(&mut self, tokens: &[Token], captures: &mut [&mut &'txt str]) -> bool { + pub fn match_tokens(&mut self, tokens: &[Token<'_>], captures: &mut [&mut &'txt str]) -> bool { let mut captures = captures.iter_mut(); tokens.iter().all(|&t| self.read_token(t, &mut captures)) } @@ -606,21 +616,107 @@ pub fn try_rename_file(old_name: &Path, new_name: &Path) -> bool { match OpenOptions::new().create_new(true).write(true).open(new_name) { Ok(file) => drop(file), Err(e) if matches!(e.kind(), io::ErrorKind::AlreadyExists | io::ErrorKind::NotFound) => return false, - Err(e) => panic_file(&e, FileAction::Create, new_name), + Err(ref e) => panic_action(e, ErrAction::Create, new_name), } match fs::rename(old_name, new_name) { Ok(()) => true, - Err(e) => { + Err(ref e) => { drop(fs::remove_file(new_name)); - if e.kind() == io::ErrorKind::NotFound { + // `NotADirectory` happens on posix when renaming a directory to an existing file. + // Windows will ignore this and rename anyways. + if matches!(e.kind(), io::ErrorKind::NotFound | io::ErrorKind::NotADirectory) { false } else { - panic_file(&e, FileAction::Rename, old_name); + panic_action(e, ErrAction::Rename, old_name); + } + }, + } +} + +#[expect(clippy::must_use_candidate)] +pub fn try_rename_dir(old_name: &Path, new_name: &Path) -> bool { + match fs::create_dir(new_name) { + Ok(()) => {}, + Err(e) if matches!(e.kind(), io::ErrorKind::AlreadyExists | io::ErrorKind::NotFound) => return false, + Err(ref e) => panic_action(e, ErrAction::Create, new_name), + } + // Windows can't reliably rename to an empty directory. + #[cfg(windows)] + drop(fs::remove_dir(new_name)); + match fs::rename(old_name, new_name) { + Ok(()) => true, + Err(ref e) => { + // Already dropped earlier on windows. + #[cfg(not(windows))] + drop(fs::remove_dir(new_name)); + // `NotADirectory` happens on posix when renaming a file to an existing directory. + if matches!(e.kind(), io::ErrorKind::NotFound | io::ErrorKind::NotADirectory) { + false + } else { + panic_action(e, ErrAction::Rename, old_name); } }, } } pub fn write_file(path: &Path, contents: &str) { - fs::write(path, contents).unwrap_or_else(|e| panic_file(&e, FileAction::Write, path)); + fs::write(path, contents).unwrap_or_else(|e| panic_action(&e, ErrAction::Write, path)); +} + +#[must_use] +pub fn run_with_output(path: &(impl AsRef + ?Sized), cmd: &mut Command) -> Vec { + fn f(path: &Path, cmd: &mut Command) -> Vec { + match cmd + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .output() + { + Ok(x) => match x.status.exit_ok() { + Ok(()) => x.stdout, + Err(ref e) => panic_action(e, ErrAction::Run, path), + }, + Err(ref e) => panic_action(e, ErrAction::Run, path), + } + } + f(path.as_ref(), cmd) +} + +pub fn run_with_args_split( + mut make_cmd: impl FnMut() -> Command, + mut run_cmd: impl FnMut(&mut Command), + args: impl Iterator>, +) { + let mut cmd = make_cmd(); + let mut len = 0; + for arg in args { + len += arg.as_ref().len(); + cmd.arg(arg); + // Very conservative limit + if len > 10000 { + run_cmd(&mut cmd); + cmd = make_cmd(); + len = 0; + } + } + if len != 0 { + run_cmd(&mut cmd); + } +} + +#[expect(clippy::must_use_candidate)] +pub fn delete_file_if_exists(path: &Path) -> bool { + match fs::remove_file(path) { + Ok(()) => true, + Err(e) if matches!(e.kind(), io::ErrorKind::NotFound | io::ErrorKind::IsADirectory) => false, + Err(ref e) => panic_action(e, ErrAction::Delete, path), + } +} + +pub fn delete_dir_if_exists(path: &Path) { + match fs::remove_dir_all(path) { + Ok(()) => {}, + Err(e) if matches!(e.kind(), io::ErrorKind::NotFound | io::ErrorKind::NotADirectory) => {}, + Err(ref e) => panic_action(e, ErrAction::Delete, path), + } } diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 7e3cb40424792..39e4e2e365ea3 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,8 +1,6 @@ [package] name = "clippy_lints" -# begin autogenerated version version = "0.1.89" -# end autogenerated version description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/clippy_lints/src/arbitrary_source_item_ordering.rs b/clippy_lints/src/arbitrary_source_item_ordering.rs index 272444475c0c4..5c1c85d39184d 100644 --- a/clippy_lints/src/arbitrary_source_item_ordering.rs +++ b/clippy_lints/src/arbitrary_source_item_ordering.rs @@ -6,9 +6,10 @@ use clippy_config::types::{ }; use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::is_cfg_test; +use rustc_attr_data_structures::AttributeKind; use rustc_hir::{ - AssocItemKind, FieldDef, HirId, ImplItemRef, IsAuto, Item, ItemKind, Mod, QPath, TraitItemRef, TyKind, Variant, - VariantData, + AssocItemKind, Attribute, FieldDef, HirId, ImplItemRef, IsAuto, Item, ItemKind, Mod, QPath, TraitItemRef, TyKind, + Variant, VariantData, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; @@ -28,6 +29,11 @@ declare_clippy_lint! { /// implemented in the code. Sometimes this will be referred to as /// "bikeshedding". /// + /// The content of items with a representation clause attribute, such as + /// `#[repr(C)]` will not be checked, as the order of their fields or + /// variants might be dictated by an external API (application binary + /// interface). + /// /// ### Default Ordering and Configuration /// /// As there is no generally applicable rule, and each project may have @@ -256,6 +262,15 @@ impl ArbitrarySourceItemOrdering { impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + if cx + .tcx + .hir_attrs(item.hir_id()) + .iter() + .any(|attr| matches!(attr, Attribute::Parsed(AttributeKind::Repr(..)))) + { + // Do not lint items with a `#[repr]` attribute as their layout may be imposed by an external API. + return; + } match &item.kind { ItemKind::Enum(_, enum_def, _generics) if self.enable_ordering_for_enum => { let mut cur_v: Option<&Variant<'_>> = None; diff --git a/clippy_lints/src/assertions_on_result_states.rs b/clippy_lints/src/assertions_on_result_states.rs index c073dee855e20..6f2a6a36a38b7 100644 --- a/clippy_lints/src/assertions_on_result_states.rs +++ b/clippy_lints/src/assertions_on_result_states.rs @@ -3,14 +3,13 @@ use clippy_utils::macros::{PanicExpn, find_assert_args, root_macro_call_first_no use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{has_debug_impl, is_copy, is_type_diagnostic_item}; use clippy_utils::usage::local_used_after_expr; -use clippy_utils::{is_expr_final_block_expr, path_res}; +use clippy_utils::{is_expr_final_block_expr, path_res, sym}; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -68,11 +67,11 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { return; } } - let (message, replacement) = match method_segment.ident.as_str() { - "is_ok" if type_suitable_to_unwrap(cx, args.type_at(1)) => { + let (message, replacement) = match method_segment.ident.name { + sym::is_ok if type_suitable_to_unwrap(cx, args.type_at(1)) => { ("called `assert!` with `Result::is_ok`", "unwrap") }, - "is_err" if type_suitable_to_unwrap(cx, args.type_at(0)) => { + sym::is_err if type_suitable_to_unwrap(cx, args.type_at(0)) => { ("called `assert!` with `Result::is_err`", "unwrap_err") }, _ => return, diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index e92879b853d7b..4120e5c8cb7d0 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -56,7 +56,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b if signed { return nbits; } - let max_bits = if method.ident.as_str() == "min" { + let max_bits = if method.ident.name == sym::min { get_constant_bits(cx, right) } else { None @@ -64,7 +64,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::MAX)) }, ExprKind::MethodCall(method, _, [lo, hi], _) => { - if method.ident.as_str() == "clamp" + if method.ident.name == sym::clamp //FIXME: make this a diagnostic item && let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi)) { diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs index c8abf9dac9af5..9a1ad8a747386 100644 --- a/clippy_lints/src/casts/cast_sign_loss.rs +++ b/clippy_lints/src/casts/cast_sign_loss.rs @@ -4,10 +4,11 @@ use std::ops::ControlFlow; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::visitors::{Descend, for_each_expr_without_closures}; -use clippy_utils::{method_chain_args, sext}; +use clippy_utils::{method_chain_args, sext, sym}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; +use rustc_span::Symbol; use super::CAST_SIGN_LOSS; @@ -16,24 +17,24 @@ use super::CAST_SIGN_LOSS; /// /// Methods that can overflow and return a negative value must not be included in this list, /// because casting their return values can still result in sign loss. -const METHODS_RET_POSITIVE: &[&str] = &[ - "checked_abs", - "saturating_abs", - "isqrt", - "checked_isqrt", - "rem_euclid", - "checked_rem_euclid", - "wrapping_rem_euclid", +const METHODS_RET_POSITIVE: &[Symbol] = &[ + sym::checked_abs, + sym::saturating_abs, + sym::isqrt, + sym::checked_isqrt, + sym::rem_euclid, + sym::checked_rem_euclid, + sym::wrapping_rem_euclid, ]; /// A list of methods that act like `pow()`. See `pow_call_result_sign()` for details. /// /// Methods that can overflow and return a negative value must not be included in this list, /// because casting their return values can still result in sign loss. -const METHODS_POW: &[&str] = &["pow", "saturating_pow", "checked_pow"]; +const METHODS_POW: &[Symbol] = &[sym::pow, sym::saturating_pow, sym::checked_pow]; /// A list of methods that act like `unwrap()`, and don't change the sign of the inner value. -const METHODS_UNWRAP: &[&str] = &["unwrap", "unwrap_unchecked", "expect", "into_ok"]; +const METHODS_UNWRAP: &[Symbol] = &[sym::unwrap, sym::unwrap_unchecked, sym::expect, sym::into_ok]; pub(super) fn check<'cx>( cx: &LateContext<'cx>, @@ -129,7 +130,7 @@ fn expr_sign<'cx, 'tcx>(cx: &LateContext<'cx>, mut expr: &'tcx Expr<'tcx>, ty: i // Calling on methods that always return non-negative values. if let ExprKind::MethodCall(path, caller, args, ..) = expr.kind { - let mut method_name = path.ident.name.as_str(); + let mut method_name = path.ident.name; // Peel unwrap(), expect(), etc. while let Some(&found_name) = METHODS_UNWRAP.iter().find(|&name| &method_name == name) @@ -138,7 +139,7 @@ fn expr_sign<'cx, 'tcx>(cx: &LateContext<'cx>, mut expr: &'tcx Expr<'tcx>, ty: i { // The original type has changed, but we can't use `ty` here anyway, because it has been // moved. - method_name = inner_path.ident.name.as_str(); + method_name = inner_path.ident.name; expr = recv; } diff --git a/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs b/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs index 31cdd078f45a0..769cc120c9504 100644 --- a/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs +++ b/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs @@ -1,11 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sym; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, GenericArg, Ty}; +use rustc_span::Symbol; use rustc_span::def_id::DefId; -use rustc_span::{Symbol, sym}; use super::CONFUSING_METHOD_TO_NUMERIC_CAST; @@ -25,7 +26,6 @@ fn get_const_name_and_ty_name( method_def_id: DefId, generics: &[GenericArg<'_>], ) -> Option<(&'static str, &'static str)> { - let method_name = method_name.as_str(); let diagnostic_name = cx.tcx.get_diagnostic_name(method_def_id); let ty_name = if diagnostic_name.is_some_and(|diag| diag == sym::cmp_ord_min || diag == sym::cmp_ord_max) { @@ -39,14 +39,21 @@ fn get_const_name_and_ty_name( } } else if let Some(impl_id) = cx.tcx.impl_of_method(method_def_id) && let Some(ty_name) = get_primitive_ty_name(cx.tcx.type_of(impl_id).instantiate_identity()) - && ["min", "max", "minimum", "maximum", "min_value", "max_value"].contains(&method_name) + && matches!( + method_name, + sym::min | sym::max | sym::minimum | sym::maximum | sym::min_value | sym::max_value + ) { ty_name } else { return None; }; - let const_name = if method_name.starts_with("max") { "MAX" } else { "MIN" }; + let const_name = if matches!(method_name, sym::max | sym::maximum | sym::max_value) { + "MAX" + } else { + "MIN" + }; Some((const_name, ty_name)) } diff --git a/clippy_lints/src/casts/ptr_cast_constness.rs b/clippy_lints/src/casts/ptr_cast_constness.rs index 2471c7355518b..c0c0a47f85515 100644 --- a/clippy_lints/src/casts/ptr_cast_constness.rs +++ b/clippy_lints/src/casts/ptr_cast_constness.rs @@ -1,12 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::std_or_core; use clippy_utils::sugg::Sugg; +use clippy_utils::{std_or_core, sym}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Mutability, QPath}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; -use rustc_span::sym; use super::PTR_CAST_CONSTNESS; @@ -78,9 +77,9 @@ pub(super) fn check_null_ptr_cast_method(cx: &LateContext<'_>, expr: &Expr<'_>) && let ExprKind::Call(func, []) = cast_expr.kind && let ExprKind::Path(QPath::Resolved(None, path)) = func.kind && let Some(defid) = path.res.opt_def_id() - && let method = match (cx.tcx.get_diagnostic_name(defid), method.ident.as_str()) { - (Some(sym::ptr_null), "cast_mut") => "null_mut", - (Some(sym::ptr_null_mut), "cast_const") => "null", + && let method = match (cx.tcx.get_diagnostic_name(defid), method.ident.name) { + (Some(sym::ptr_null), sym::cast_mut) => "null_mut", + (Some(sym::ptr_null_mut), sym::cast_const) => "null", _ => return, } && let Some(prefix) = std_or_core(cx) diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 1d44c7e9c88b0..5c64216dd92ca 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -3,14 +3,14 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::{IntoSpan, SpanRangeExt}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::for_each_expr_without_closures; -use clippy_utils::{LimitStack, get_async_fn_body, is_async_fn}; +use clippy_utils::{LimitStack, get_async_fn_body, is_async_fn, sym}; use core::ops::ControlFlow; use rustc_hir::intravisit::FnKind; use rustc_hir::{Attribute, Body, Expr, ExprKind, FnDecl}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; +use rustc_span::Span; use rustc_span::def_id::LocalDefId; -use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -104,7 +104,7 @@ impl CognitiveComplexity { FnKind::Closure => { let header_span = body_span.with_hi(decl.output.span().lo()); #[expect(clippy::range_plus_one)] - if let Some(range) = header_span.map_range(cx, |src, range| { + if let Some(range) = header_span.map_range(cx, |_, src, range| { let mut idxs = src.get(range.clone())?.match_indices('|'); Some(range.start + idxs.next()?.0..range.start + idxs.next()?.0 + 1) }) { @@ -157,9 +157,9 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity { } fn check_attributes(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) { - self.limit.push_attrs(cx.sess(), attrs, "cognitive_complexity"); + self.limit.push_attrs(cx.sess(), attrs, sym::cognitive_complexity); } fn check_attributes_post(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) { - self.limit.pop_attrs(cx.sess(), attrs, "cognitive_complexity"); + self.limit.pop_attrs(cx.sess(), attrs, sym::cognitive_complexity); } } diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index 9c3009a86cdc0..238ebd4a444cf 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -75,11 +75,15 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain { } // Check that there exists at least one explicit else condition - let (conds, _) = if_sequence(expr); + let (conds, blocks) = if_sequence(expr); if conds.len() < 2 { return; } + if blocks.len() < 3 { + return; + } + for cond in conds.windows(2) { if let (&ExprKind::Binary(ref kind1, lhs1, rhs1), &ExprKind::Binary(ref kind2, lhs2, rhs2)) = (&cond[0].kind, &cond[1].kind) @@ -125,6 +129,7 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain { let ExprKind::Binary(_, lhs, rhs) = conds[0].kind else { unreachable!(); }; + let lhs = Sugg::hir(cx, lhs, "..").maybe_paren(); let rhs = Sugg::hir(cx, rhs, "..").addr(); span_lint_and_sugg( diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 42fbe6438d4ea..2467fc95fd055 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,5 +1,5 @@ use clippy_config::Conf; -use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_note, span_lint_and_then}; use clippy_utils::source::{IntoSpan, SpanRangeExt, first_line_of_span, indent_of, reindent_multiline, snippet}; use clippy_utils::ty::{InteriorMut, needs_ordered_drop}; use clippy_utils::visitors::for_each_expr_without_closures; @@ -258,7 +258,7 @@ fn lint_branches_sharing_code<'tcx>( let span = span.with_hi(last_block.span.hi()); // Improve formatting if the inner block has indentation (i.e. normal Rust formatting) let span = span - .map_range(cx, |src, range| { + .map_range(cx, |_, src, range| { (range.start > 4 && src.get(range.start - 4..range.start)? == " ") .then_some(range.start - 4..range.end) }) @@ -567,7 +567,7 @@ fn method_caller_is_mutable<'tcx>( /// Implementation of `IFS_SAME_COND`. fn lint_same_cond<'tcx>(cx: &LateContext<'tcx>, conds: &[&Expr<'_>], interior_mut: &mut InteriorMut<'tcx>) { - for (i, j) in search_same( + for group in search_same( conds, |e| hash_expr(cx, e), |lhs, rhs| { @@ -584,14 +584,8 @@ fn lint_same_cond<'tcx>(cx: &LateContext<'tcx>, conds: &[&Expr<'_>], interior_mu } }, ) { - span_lint_and_note( - cx, - IFS_SAME_COND, - j.span, - "this `if` has the same condition as a previous `if`", - Some(i.span), - "same as this", - ); + let spans: Vec<_> = group.into_iter().map(|expr| expr.span).collect(); + span_lint(cx, IFS_SAME_COND, spans, "these `if` branches have the same condition"); } } @@ -609,14 +603,13 @@ fn lint_same_fns_in_if_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) { SpanlessEq::new(cx).eq_expr(lhs, rhs) }; - for (i, j) in search_same(conds, |e| hash_expr(cx, e), eq) { - span_lint_and_note( + for group in search_same(conds, |e| hash_expr(cx, e), eq) { + let spans: Vec<_> = group.into_iter().map(|expr| expr.span).collect(); + span_lint( cx, SAME_FUNCTIONS_IN_IF_CONDITION, - j.span, - "this `if` has the same function call as a previous `if`", - Some(i.span), - "same as this", + spans, + "these `if` branches have the same function call", ); } } diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index bb825c7655f87..5fcb851dfebce 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -764,6 +764,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::unwrap_in_result::UNWRAP_IN_RESULT_INFO, crate::upper_case_acronyms::UPPER_CASE_ACRONYMS_INFO, crate::use_self::USE_SELF_INFO, + crate::useless_concat::USELESS_CONCAT_INFO, crate::useless_conversion::USELESS_CONVERSION_INFO, crate::vec::USELESS_VEC_INFO, crate::vec_init_then_push::VEC_INIT_THEN_PUSH_INFO, diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index 946515386690c..5204f73ea0a95 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -14,36 +14,36 @@ macro_rules! declare_with_version { #[rustfmt::skip] declare_with_version! { DEPRECATED(DEPRECATED_VERSION) = [ - #[clippy::version = "pre 1.29.0"] - ("clippy::should_assert_eq", "`assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can"), + #[clippy::version = "1.30.0"] + ("clippy::assign_ops", "compound operators are harmless and linting on them is not in scope for clippy"), #[clippy::version = "pre 1.29.0"] ("clippy::extend_from_slice", "`Vec::extend_from_slice` is no longer faster than `Vec::extend` due to specialization"), + #[clippy::version = "1.86.0"] + ("clippy::match_on_vec_items", "`clippy::indexing_slicing` covers indexing and slicing on `Vec<_>`"), + #[clippy::version = "pre 1.29.0"] + ("clippy::misaligned_transmute", "split into `clippy::cast_ptr_alignment` and `clippy::transmute_ptr_to_ptr`"), + #[clippy::version = "1.86.0"] + ("clippy::option_map_or_err_ok", "`clippy::manual_ok_or` covers this case"), + #[clippy::version = "1.54.0"] + ("clippy::pub_enum_variant_names", "`clippy::enum_variant_names` now covers this case via the `avoid-breaking-exported-api` config"), #[clippy::version = "pre 1.29.0"] ("clippy::range_step_by_zero", "`Iterator::step_by(0)` now panics and is no longer an infinite iterator"), + #[clippy::version = "1.47.0"] + ("clippy::regex_macro", "the `regex!` macro was removed from the regex crate in 2018"), + #[clippy::version = "1.44.0"] + ("clippy::replace_consts", "`min_value` and `max_value` are now deprecated"), #[clippy::version = "pre 1.29.0"] - ("clippy::unstable_as_slice", "`Vec::as_slice` is now stable"), + ("clippy::should_assert_eq", "`assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can"), #[clippy::version = "pre 1.29.0"] - ("clippy::unstable_as_mut_slice", "`Vec::as_mut_slice` is now stable"), + ("clippy::unsafe_vector_initialization", "the suggested alternative could be substantially slower"), #[clippy::version = "pre 1.29.0"] - ("clippy::misaligned_transmute", "split into `clippy::cast_ptr_alignment` and `clippy::transmute_ptr_to_ptr`"), - #[clippy::version = "1.30.0"] - ("clippy::assign_ops", "compound operators are harmless and linting on them is not in scope for clippy"), + ("clippy::unstable_as_mut_slice", "`Vec::as_mut_slice` is now stable"), #[clippy::version = "pre 1.29.0"] - ("clippy::unsafe_vector_initialization", "the suggested alternative could be substantially slower"), + ("clippy::unstable_as_slice", "`Vec::as_slice` is now stable"), #[clippy::version = "1.39.0"] ("clippy::unused_collect", "`Iterator::collect` is now marked as `#[must_use]`"), - #[clippy::version = "1.44.0"] - ("clippy::replace_consts", "`min_value` and `max_value` are now deprecated"), - #[clippy::version = "1.47.0"] - ("clippy::regex_macro", "the `regex!` macro was removed from the regex crate in 2018"), - #[clippy::version = "1.54.0"] - ("clippy::pub_enum_variant_names", "`clippy::enum_variant_names` now covers this case via the `avoid-breaking-exported-api` config"), #[clippy::version = "1.54.0"] ("clippy::wrong_pub_self_convention", "`clippy::wrong_self_convention` now covers this case via the `avoid-breaking-exported-api` config"), - #[clippy::version = "1.86.0"] - ("clippy::option_map_or_err_ok", "`clippy::manual_ok_or` covers this case"), - #[clippy::version = "1.86.0"] - ("clippy::match_on_vec_items", "`clippy::indexing_slicing` covers indexing and slicing on `Vec<_>`"), ]} #[rustfmt::skip] @@ -61,6 +61,12 @@ declare_with_version! { RENAMED(RENAMED_VERSION) = [ #[clippy::version = ""] ("clippy::box_vec", "clippy::box_collection"), #[clippy::version = ""] + ("clippy::cast_ref_to_mut", "invalid_reference_casting"), + #[clippy::version = ""] + ("clippy::clone_double_ref", "suspicious_double_ref_op"), + #[clippy::version = ""] + ("clippy::cmp_nan", "invalid_nan_comparisons"), + #[clippy::version = ""] ("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"), #[clippy::version = ""] ("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"), @@ -70,15 +76,35 @@ declare_with_version! { RENAMED(RENAMED_VERSION) = [ ("clippy::disallowed_method", "clippy::disallowed_methods"), #[clippy::version = ""] ("clippy::disallowed_type", "clippy::disallowed_types"), + #[clippy::version = "1.86.0"] + ("clippy::double_neg", "double_negations"), + #[clippy::version = ""] + ("clippy::drop_bounds", "drop_bounds"), + #[clippy::version = ""] + ("clippy::drop_copy", "dropping_copy_types"), + #[clippy::version = ""] + ("clippy::drop_ref", "dropping_references"), #[clippy::version = ""] ("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"), - #[clippy::version = "1.51.0"] - ("clippy::find_map", "clippy::manual_find_map"), #[clippy::version = "1.53.0"] ("clippy::filter_map", "clippy::manual_filter_map"), + #[clippy::version = "1.51.0"] + ("clippy::find_map", "clippy::manual_find_map"), #[clippy::version = ""] ("clippy::fn_address_comparisons", "unpredictable_function_pointer_comparisons"), #[clippy::version = ""] + ("clippy::fn_null_check", "useless_ptr_null_checks"), + #[clippy::version = ""] + ("clippy::for_loop_over_option", "for_loops_over_fallibles"), + #[clippy::version = ""] + ("clippy::for_loop_over_result", "for_loops_over_fallibles"), + #[clippy::version = ""] + ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"), + #[clippy::version = ""] + ("clippy::forget_copy", "forgetting_copy_types"), + #[clippy::version = ""] + ("clippy::forget_ref", "forgetting_references"), + #[clippy::version = ""] ("clippy::identity_conversion", "clippy::useless_conversion"), #[clippy::version = "pre 1.29.0"] ("clippy::if_let_redundant_pattern_matching", "clippy::redundant_pattern_matching"), @@ -91,7 +117,25 @@ declare_with_version! { RENAMED(RENAMED_VERSION) = [ #[clippy::version = ""] ("clippy::integer_arithmetic", "clippy::arithmetic_side_effects"), #[clippy::version = ""] + ("clippy::into_iter_on_array", "array_into_iter"), + #[clippy::version = ""] + ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"), + #[clippy::version = "CURRENT_RUSTC_VERSION"] + ("clippy::invalid_null_ptr_usage", "invalid_null_arguments"), + #[clippy::version = ""] + ("clippy::invalid_ref", "invalid_value"), + #[clippy::version = ""] + ("clippy::invalid_utf8_in_unchecked", "invalid_from_utf8_unchecked"), + #[clippy::version = ""] + ("clippy::let_underscore_drop", "let_underscore_drop"), + #[clippy::version = ""] ("clippy::logic_bug", "clippy::overly_complex_bool_expr"), + #[clippy::version = "1.80.0"] + ("clippy::maybe_misused_cfg", "unexpected_cfgs"), + #[clippy::version = ""] + ("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"), + #[clippy::version = "1.80.0"] + ("clippy::mismatched_target_os", "unexpected_cfgs"), #[clippy::version = ""] ("clippy::new_without_default_derive", "clippy::new_without_default"), #[clippy::version = ""] @@ -107,6 +151,10 @@ declare_with_version! { RENAMED(RENAMED_VERSION) = [ #[clippy::version = ""] ("clippy::overflow_check_conditional", "clippy::panicking_overflow_checks"), #[clippy::version = ""] + ("clippy::panic_params", "non_fmt_panics"), + #[clippy::version = ""] + ("clippy::positional_named_format_parameters", "named_arguments_used_positionally"), + #[clippy::version = ""] ("clippy::ref_in_deref", "clippy::needless_borrow"), #[clippy::version = ""] ("clippy::result_expect_used", "clippy::expect_used"), @@ -115,67 +163,25 @@ declare_with_version! { RENAMED(RENAMED_VERSION) = [ #[clippy::version = ""] ("clippy::result_unwrap_used", "clippy::unwrap_used"), #[clippy::version = ""] + ("clippy::reverse_range_loop", "clippy::reversed_empty_ranges"), + #[clippy::version = ""] ("clippy::single_char_push_str", "clippy::single_char_add_str"), #[clippy::version = ""] ("clippy::stutter", "clippy::module_name_repetitions"), #[clippy::version = ""] + ("clippy::temporary_cstring_as_ptr", "dangling_pointers_from_temporaries"), + #[clippy::version = ""] ("clippy::thread_local_initializer_can_be_made_const", "clippy::missing_const_for_thread_local"), #[clippy::version = ""] ("clippy::to_string_in_display", "clippy::recursive_format_impl"), - #[clippy::version = ""] - ("clippy::unwrap_or_else_default", "clippy::unwrap_or_default"), - #[clippy::version = ""] - ("clippy::zero_width_space", "clippy::invisible_characters"), - #[clippy::version = ""] - ("clippy::cast_ref_to_mut", "invalid_reference_casting"), - #[clippy::version = ""] - ("clippy::clone_double_ref", "suspicious_double_ref_op"), - #[clippy::version = ""] - ("clippy::cmp_nan", "invalid_nan_comparisons"), - #[clippy::version = "CURRENT_RUSTC_VERSION"] - ("clippy::invalid_null_ptr_usage", "invalid_null_arguments"), - #[clippy::version = "1.86.0"] - ("clippy::double_neg", "double_negations"), - #[clippy::version = ""] - ("clippy::drop_bounds", "drop_bounds"), - #[clippy::version = ""] - ("clippy::drop_copy", "dropping_copy_types"), - #[clippy::version = ""] - ("clippy::drop_ref", "dropping_references"), - #[clippy::version = ""] - ("clippy::fn_null_check", "useless_ptr_null_checks"), - #[clippy::version = ""] - ("clippy::for_loop_over_option", "for_loops_over_fallibles"), - #[clippy::version = ""] - ("clippy::for_loop_over_result", "for_loops_over_fallibles"), - #[clippy::version = ""] - ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"), - #[clippy::version = ""] - ("clippy::forget_copy", "forgetting_copy_types"), - #[clippy::version = ""] - ("clippy::forget_ref", "forgetting_references"), - #[clippy::version = ""] - ("clippy::into_iter_on_array", "array_into_iter"), - #[clippy::version = ""] - ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"), - #[clippy::version = ""] - ("clippy::invalid_ref", "invalid_value"), - #[clippy::version = ""] - ("clippy::invalid_utf8_in_unchecked", "invalid_from_utf8_unchecked"), - #[clippy::version = ""] - ("clippy::let_underscore_drop", "let_underscore_drop"), - #[clippy::version = "1.80.0"] - ("clippy::maybe_misused_cfg", "unexpected_cfgs"), - #[clippy::version = ""] - ("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"), - #[clippy::version = "1.80.0"] - ("clippy::mismatched_target_os", "unexpected_cfgs"), - #[clippy::version = ""] - ("clippy::panic_params", "non_fmt_panics"), - #[clippy::version = ""] - ("clippy::positional_named_format_parameters", "named_arguments_used_positionally"), - #[clippy::version = ""] - ("clippy::temporary_cstring_as_ptr", "dangling_pointers_from_temporaries"), + #[clippy::version = "1.88.0"] + ("clippy::transmute_float_to_int", "unnecessary_transmutes"), + #[clippy::version = "1.88.0"] + ("clippy::transmute_int_to_char", "unnecessary_transmutes"), + #[clippy::version = "1.88.0"] + ("clippy::transmute_int_to_float", "unnecessary_transmutes"), + #[clippy::version = "1.88.0"] + ("clippy::transmute_num_to_bytes", "unnecessary_transmutes"), #[clippy::version = ""] ("clippy::undropped_manually_drops", "undropped_manually_drops"), #[clippy::version = ""] @@ -183,15 +189,9 @@ declare_with_version! { RENAMED(RENAMED_VERSION) = [ #[clippy::version = ""] ("clippy::unused_label", "unused_labels"), #[clippy::version = ""] + ("clippy::unwrap_or_else_default", "clippy::unwrap_or_default"), + #[clippy::version = ""] ("clippy::vtable_address_comparisons", "ambiguous_wide_pointer_comparisons"), #[clippy::version = ""] - ("clippy::reverse_range_loop", "clippy::reversed_empty_ranges"), - #[clippy::version = "1.88.0"] - ("clippy::transmute_int_to_float", "unnecessary_transmutes"), - #[clippy::version = "1.88.0"] - ("clippy::transmute_int_to_char", "unnecessary_transmutes"), - #[clippy::version = "1.88.0"] - ("clippy::transmute_float_to_int", "unnecessary_transmutes"), - #[clippy::version = "1.88.0"] - ("clippy::transmute_num_to_bytes", "unnecessary_transmutes"), + ("clippy::zero_width_space", "clippy::invisible_characters"), ]} diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 5edb5c235703e..a22a2ee66d258 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -22,6 +22,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypeckResults}; use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; +use std::borrow::Cow; declare_clippy_lint! { /// ### What it does @@ -252,13 +253,14 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { } let typeck = cx.typeck_results(); - let Some((kind, sub_expr)) = try_parse_ref_op(cx.tcx, typeck, expr) else { + let Some((kind, sub_expr, skip_expr)) = try_parse_ref_op(cx.tcx, typeck, expr) else { // The whole chain of reference operations has been seen if let Some((state, data)) = self.state.take() { report(cx, expr, state, data, typeck); } return; }; + self.skip_expr = skip_expr; match (self.state.take(), kind) { (None, kind) => { @@ -671,42 +673,38 @@ fn try_parse_ref_op<'tcx>( tcx: TyCtxt<'tcx>, typeck: &'tcx TypeckResults<'_>, expr: &'tcx Expr<'_>, -) -> Option<(RefOp, &'tcx Expr<'tcx>)> { - let (is_ufcs, def_id, arg) = match expr.kind { - ExprKind::MethodCall(_, arg, [], _) => (false, typeck.type_dependent_def_id(expr.hir_id)?, arg), +) -> Option<(RefOp, &'tcx Expr<'tcx>, Option)> { + let (call_path_id, def_id, arg) = match expr.kind { + ExprKind::MethodCall(_, arg, [], _) => (None, typeck.type_dependent_def_id(expr.hir_id)?, arg), ExprKind::Call( - Expr { - kind: ExprKind::Path(path), + &Expr { + kind: ExprKind::Path(QPath::Resolved(None, path)), hir_id, .. }, [arg], - ) => (true, typeck.qpath_res(path, *hir_id).opt_def_id()?, arg), + ) => (Some(hir_id), path.res.opt_def_id()?, arg), ExprKind::Unary(UnOp::Deref, sub_expr) if !typeck.expr_ty(sub_expr).is_raw_ptr() => { - return Some((RefOp::Deref, sub_expr)); + return Some((RefOp::Deref, sub_expr, None)); + }, + ExprKind::AddrOf(BorrowKind::Ref, mutability, sub_expr) => { + return Some((RefOp::AddrOf(mutability), sub_expr, None)); }, - ExprKind::AddrOf(BorrowKind::Ref, mutability, sub_expr) => return Some((RefOp::AddrOf(mutability), sub_expr)), _ => return None, }; - if tcx.is_diagnostic_item(sym::deref_method, def_id) { - Some(( - RefOp::Method { - mutbl: Mutability::Not, - is_ufcs, - }, - arg, - )) - } else if tcx.trait_of_item(def_id)? == tcx.lang_items().deref_mut_trait()? { - Some(( - RefOp::Method { - mutbl: Mutability::Mut, - is_ufcs, - }, - arg, - )) - } else { - None - } + let mutbl = match tcx.get_diagnostic_name(def_id) { + Some(sym::deref_method) => Mutability::Not, + Some(sym::deref_mut_method) => Mutability::Mut, + _ => return None, + }; + Some(( + RefOp::Method { + mutbl, + is_ufcs: call_path_id.is_some(), + }, + arg, + call_path_id, + )) } // Checks if the adjustments contains a deref of `ManuallyDrop<_>` @@ -944,7 +942,7 @@ fn report<'tcx>( mutbl, } => { let mut app = Applicability::MachineApplicable; - let (expr_str, _expr_is_macro_call) = + let (expr_str, expr_is_macro_call) = snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app); let ty = typeck.expr_ty(expr); let (_, ref_count) = peel_middle_ty_refs(ty); @@ -968,20 +966,11 @@ fn report<'tcx>( "&" }; - // expr_str (the suggestion) is never shown if is_final_ufcs is true, since it's - // `expr.kind == ExprKind::Call`. Therefore, this is, afaik, always unnecessary. - /* - expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence() < ExprPrecedence::Prefix { + let expr_str = if !expr_is_macro_call && is_ufcs && expr.precedence() < ExprPrecedence::Prefix { Cow::Owned(format!("({expr_str})")) } else { expr_str }; - */ - - // Fix #10850, do not lint if it's `Foo::deref` instead of `foo.deref()`. - if is_ufcs { - return; - } span_lint_and_sugg( cx, diff --git a/clippy_lints/src/doc/missing_headers.rs b/clippy_lints/src/doc/missing_headers.rs index 039937e0207b0..9ee32fced8c44 100644 --- a/clippy_lints/src/doc/missing_headers.rs +++ b/clippy_lints/src/doc/missing_headers.rs @@ -113,7 +113,8 @@ fn find_panic(cx: &LateContext<'_>, body_id: BodyId) -> Option { } // check for `unwrap` and `expect` for both `Option` and `Result` - if let Some(arglists) = method_chain_args(expr, &["unwrap"]).or_else(|| method_chain_args(expr, &["expect"])) + if let Some(arglists) = + method_chain_args(expr, &[sym::unwrap]).or_else(|| method_chain_args(expr, &[sym::expect])) && let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs() && matches!( get_type_diagnostic_name(cx, receiver_ty), diff --git a/clippy_lints/src/empty_with_brackets.rs b/clippy_lints/src/empty_with_brackets.rs index a38d6df89f2b9..8c12364883c7e 100644 --- a/clippy_lints/src/empty_with_brackets.rs +++ b/clippy_lints/src/empty_with_brackets.rs @@ -93,6 +93,7 @@ impl_lint_pass!(EmptyWithBrackets => [EMPTY_STRUCTS_WITH_BRACKETS, EMPTY_ENUM_VA impl LateLintPass<'_> for EmptyWithBrackets { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { if let ItemKind::Struct(ident, var_data, _) = &item.kind + && !item.span.from_expansion() && has_brackets(var_data) && let span_after_ident = item.span.with_lo(ident.span.hi()) && has_no_fields(cx, var_data, span_after_ident) diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index a5a4e05b3a6d2..085ee4448a4ee 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::{FormatArgsStorage, format_args_inputs_span}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_expn_of, path_def_id}; +use clippy_utils::{is_expn_of, path_def_id, sym}; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{BindingMode, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::{ExpnId, sym}; +use rustc_span::ExpnId; declare_clippy_lint! { /// ### What it does @@ -72,9 +72,9 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { }; // ordering is important here, since `writeln!` uses `write!` internally - let calling_macro = if is_expn_of(write_call.span, "writeln").is_some() { + let calling_macro = if is_expn_of(write_call.span, sym::writeln).is_some() { Some("writeln") - } else if is_expn_of(write_call.span, "write").is_some() { + } else if is_expn_of(write_call.span, sym::write).is_some() { Some("write") } else { None diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs index 6a217b6182ce7..c0b0fd88d9e16 100644 --- a/clippy_lints/src/extra_unused_type_parameters.rs +++ b/clippy_lints/src/extra_unused_type_parameters.rs @@ -273,7 +273,7 @@ impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters { // Only lint on inherent methods, not trait methods. if let ImplItemKind::Fn(.., body_id) = item.kind && !item.generics.params.is_empty() - && trait_ref_of_method(cx, item.owner_id.def_id).is_none() + && trait_ref_of_method(cx, item.owner_id).is_none() && !is_empty_body(cx, body_id) && (!self.avoid_breaking_exported_api || !cx.effective_visibilities.is_exported(item.owner_id.def_id)) && !item.span.in_external_macro(cx.sess().source_map()) diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index c868b782f43c3..68d0cd19c8a69 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -82,7 +82,7 @@ fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::Impl } // check for `unwrap` - if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { + if let Some(arglists) = method_chain_args(expr, &[sym::unwrap]) { let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs(); if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option) || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result) diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 012ad8e1a2298..c51267567d01d 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { }, ); } - } else if digits > max as usize && float_str.len() < sym_str.len() { + } else if digits > max as usize && count_digits(&float_str) < count_digits(sym_str) { span_lint_and_then( cx, EXCESSIVE_PRECISION, diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index e653a57196d61..3c7e83b069726 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -294,8 +294,8 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: && let Some(parent) = get_parent_expr(cx, expr) { if let Some(grandparent) = get_parent_expr(cx, parent) - && let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = grandparent.kind - && method_name.as_str() == "sqrt" + && let ExprKind::MethodCall(PathSegment { ident: method, .. }, receiver, ..) = grandparent.kind + && method.name == sym::sqrt && detect_hypot(cx, receiver).is_some() { return; @@ -375,24 +375,10 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option { } // check if expression of the form x.powi(2) + y.powi(2) - if let ExprKind::MethodCall( - PathSegment { - ident: lmethod_name, .. - }, - largs_0, - [largs_1, ..], - _, - ) = &add_lhs.kind - && let ExprKind::MethodCall( - PathSegment { - ident: rmethod_name, .. - }, - rargs_0, - [rargs_1, ..], - _, - ) = &add_rhs.kind - && lmethod_name.as_str() == "powi" - && rmethod_name.as_str() == "powi" + if let ExprKind::MethodCall(PathSegment { ident: lmethod, .. }, largs_0, [largs_1, ..], _) = &add_lhs.kind + && let ExprKind::MethodCall(PathSegment { ident: rmethod, .. }, rargs_0, [rargs_1, ..], _) = &add_rhs.kind + && lmethod.name == sym::powi + && rmethod.name == sym::powi && let ecx = ConstEvalCtxt::new(cx) && let Some(lvalue) = ecx.eval(largs_1) && let Some(rvalue) = ecx.eval(rargs_1) @@ -482,8 +468,8 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) { ) = &expr.kind { if let Some(parent) = get_parent_expr(cx, expr) - && let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = parent.kind - && method_name.as_str() == "sqrt" + && let ExprKind::MethodCall(PathSegment { ident: method, .. }, receiver, ..) = parent.kind + && method.name == sym::sqrt && detect_hypot(cx, receiver).is_some() { return; @@ -623,27 +609,13 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) { } fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool { - if let ExprKind::MethodCall( - PathSegment { - ident: method_name_a, .. - }, - _, - args_a, - _, - ) = expr_a.kind - && let ExprKind::MethodCall( - PathSegment { - ident: method_name_b, .. - }, - _, - args_b, - _, - ) = expr_b.kind + if let ExprKind::MethodCall(PathSegment { ident: method_a, .. }, _, args_a, _) = expr_a.kind + && let ExprKind::MethodCall(PathSegment { ident: method_b, .. }, _, args_b, _) = expr_b.kind { - return method_name_a.as_str() == method_name_b.as_str() + return method_a.name == method_b.name && args_a.len() == args_b.len() - && (["ln", "log2", "log10"].contains(&method_name_a.as_str()) - || method_name_a.as_str() == "log" && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0])); + && (matches!(method_a.name, sym::ln | sym::log2 | sym::log10) + || method_a.name == sym::log && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0])); } false diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index c3e0d5e8b694d..70655838b6af0 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -55,7 +55,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); if let Some(attr) = attr { check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig); - } else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id.def_id).is_none() { + } else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id).is_none() { check_must_use_candidate( cx, sig.decl, diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs index 07a92a4ed70c6..00ce4cfcc5266 100644 --- a/clippy_lints/src/functions/result.rs +++ b/clippy_lints/src/functions/result.rs @@ -55,7 +55,7 @@ pub(super) fn check_impl_item<'tcx>( // Don't lint if method is a trait's implementation, we can't do anything about those if let hir::ImplItemKind::Fn(ref sig, _) = item.kind && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.owner_id.def_id, item.span) - && trait_ref_of_method(cx, item.owner_id.def_id).is_none() + && trait_ref_of_method(cx, item.owner_id).is_none() { if cx.effective_visibilities.is_exported(item.owner_id.def_id) { let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 4c17834c3adf9..cab7a9fb70990 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -119,7 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { } let generics_suggestion_span = impl_.generics.span.substitute_dummy({ - let range = (item.span.lo()..target.span().lo()).map_range(cx, |src, range| { + let range = (item.span.lo()..target.span().lo()).map_range(cx, |_, src, range| { Some(src.get(range.clone())?.find("impl")? + 4..range.end) }); if let Some(range) = range { @@ -165,11 +165,12 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { continue; } let generics_suggestion_span = generics.span.substitute_dummy({ - let range = (item.span.lo()..body.params[0].pat.span.lo()).map_range(cx, |src, range| { - let (pre, post) = src.get(range.clone())?.split_once("fn")?; - let pos = post.find('(')? + pre.len() + 2; - Some(pos..pos) - }); + let range = + (item.span.lo()..body.params[0].pat.span.lo()).map_range(cx, |_, src, range| { + let (pre, post) = src.get(range.clone())?.split_once("fn")?; + let pos = post.find('(')? + pre.len() + 2; + Some(pos..pos) + }); if let Some(range) = range { range.with_ctxt(item.span.ctxt()) } else { diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index 989997d69f7c7..0b1cae30ca501 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::IfLet; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::is_copy; -use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local}; +use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local, sym}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::Applicability; use rustc_hir as hir; @@ -72,7 +72,7 @@ impl_lint_pass!(IndexRefutableSlice => [INDEX_REFUTABLE_SLICE]); impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { if let Some(IfLet { let_pat, if_then, .. }) = IfLet::hir(cx, expr) - && (!expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some()) + && (!expr.span.from_expansion() || is_expn_of(expr.span, sym::if_chain).is_some()) && !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id) && let found_slices = find_slice_values(cx, let_pat) && !found_slices.is_empty() diff --git a/clippy_lints/src/ineffective_open_options.rs b/clippy_lints/src/ineffective_open_options.rs index 3a28553b55e25..7a751514b6476 100644 --- a/clippy_lints/src/ineffective_open_options.rs +++ b/clippy_lints/src/ineffective_open_options.rs @@ -1,13 +1,13 @@ use crate::methods::method_call; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::peel_blocks; +use clippy_utils::{peel_blocks, sym}; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{BytePos, Span, sym}; +use rustc_span::{BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -57,7 +57,7 @@ fn index_if_arg_is_boolean(args: &[Expr<'_>], call_span: Span) -> Option { impl<'tcx> LateLintPass<'tcx> for IneffectiveOpenOptions { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let Some(("open", mut receiver, [_arg], _, _)) = method_call(expr) else { + let Some((sym::open, mut receiver, [_arg], _, _)) = method_call(expr) else { return; }; let receiver_ty = cx.typeck_results().expr_ty(receiver); @@ -70,9 +70,9 @@ impl<'tcx> LateLintPass<'tcx> for IneffectiveOpenOptions { let mut write = None; while let Some((name, recv, args, _, span)) = method_call(receiver) { - if name == "append" { + if name == sym::append { append = index_if_arg_is_boolean(args, span); - } else if name == "write" { + } else if name == sym::write { write = index_if_arg_is_boolean(args, span); } receiver = recv; diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index c4e10837bf192..bf3eafe09b3d0 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -4,6 +4,7 @@ use clippy_utils::{higher, sym}; use rustc_hir::{BorrowKind, Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; +use rustc_span::Symbol; declare_clippy_lint! { /// ### What it does @@ -119,33 +120,33 @@ use self::Heuristic::{All, Always, Any, First}; /// returns an infinite or possibly infinite iterator. The finiteness /// is an upper bound, e.g., some methods can return a possibly /// infinite iterator at worst, e.g., `take_while`. -const HEURISTICS: [(&str, usize, Heuristic, Finiteness); 19] = [ - ("zip", 1, All, Infinite), - ("chain", 1, Any, Infinite), - ("cycle", 0, Always, Infinite), - ("map", 1, First, Infinite), - ("by_ref", 0, First, Infinite), - ("cloned", 0, First, Infinite), - ("rev", 0, First, Infinite), - ("inspect", 0, First, Infinite), - ("enumerate", 0, First, Infinite), - ("peekable", 1, First, Infinite), - ("fuse", 0, First, Infinite), - ("skip", 1, First, Infinite), - ("skip_while", 0, First, Infinite), - ("filter", 1, First, Infinite), - ("filter_map", 1, First, Infinite), - ("flat_map", 1, First, Infinite), - ("unzip", 0, First, Infinite), - ("take_while", 1, First, MaybeInfinite), - ("scan", 2, First, MaybeInfinite), +const HEURISTICS: [(Symbol, usize, Heuristic, Finiteness); 19] = [ + (sym::zip, 1, All, Infinite), + (sym::chain, 1, Any, Infinite), + (sym::cycle, 0, Always, Infinite), + (sym::map, 1, First, Infinite), + (sym::by_ref, 0, First, Infinite), + (sym::cloned, 0, First, Infinite), + (sym::rev, 0, First, Infinite), + (sym::inspect, 0, First, Infinite), + (sym::enumerate, 0, First, Infinite), + (sym::peekable, 1, First, Infinite), + (sym::fuse, 0, First, Infinite), + (sym::skip, 1, First, Infinite), + (sym::skip_while, 0, First, Infinite), + (sym::filter, 1, First, Infinite), + (sym::filter_map, 1, First, Infinite), + (sym::flat_map, 1, First, Infinite), + (sym::unzip, 0, First, Infinite), + (sym::take_while, 1, First, MaybeInfinite), + (sym::scan, 2, First, MaybeInfinite), ]; fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { match expr.kind { ExprKind::MethodCall(method, receiver, args, _) => { for &(name, len, heuristic, cap) in &HEURISTICS { - if method.ident.name.as_str() == name && args.len() == len { + if method.ident.name == name && args.len() == len { return (match heuristic { Always => Infinite, First => is_infinite(cx, receiver), @@ -183,36 +184,36 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { /// the names and argument lengths of methods that *may* exhaust their /// iterators -const POSSIBLY_COMPLETING_METHODS: [(&str, usize); 6] = [ - ("find", 1), - ("rfind", 1), - ("position", 1), - ("rposition", 1), - ("any", 1), - ("all", 1), +const POSSIBLY_COMPLETING_METHODS: [(Symbol, usize); 6] = [ + (sym::find, 1), + (sym::rfind, 1), + (sym::position, 1), + (sym::rposition, 1), + (sym::any, 1), + (sym::all, 1), ]; /// the names and argument lengths of methods that *always* exhaust /// their iterators -const COMPLETING_METHODS: [(&str, usize); 12] = [ - ("count", 0), - ("fold", 2), - ("for_each", 1), - ("partition", 1), - ("max", 0), - ("max_by", 1), - ("max_by_key", 1), - ("min", 0), - ("min_by", 1), - ("min_by_key", 1), - ("sum", 0), - ("product", 0), +const COMPLETING_METHODS: [(Symbol, usize); 12] = [ + (sym::count, 0), + (sym::fold, 2), + (sym::for_each, 1), + (sym::partition, 1), + (sym::max, 0), + (sym::max_by, 1), + (sym::max_by_key, 1), + (sym::min, 0), + (sym::min_by, 1), + (sym::min_by_key, 1), + (sym::sum, 0), + (sym::product, 0), ]; fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { match expr.kind { ExprKind::MethodCall(method, receiver, args, _) => { - let method_str = method.ident.name.as_str(); + let method_str = method.ident.name; for &(name, len) in &COMPLETING_METHODS { if method_str == name && args.len() == len { return is_infinite(cx, receiver); diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index 1d582fb0223e1..7f2e25367a6a4 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -106,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString { // Check if return type is String && is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String) // Filters instances of to_string which are required by a trait - && trait_ref_of_method(cx, impl_item.owner_id.def_id).is_none() + && trait_ref_of_method(cx, impl_item.owner_id).is_none() { show_lint(cx, impl_item); } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ff028713bf049..92eb3d7a7c59d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -393,6 +393,7 @@ mod unwrap; mod unwrap_in_result; mod upper_case_acronyms; mod use_self; +mod useless_concat; mod useless_conversion; mod vec; mod vec_init_then_push; @@ -866,7 +867,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| Box::new(unnecessary_box_returns::UnnecessaryBoxReturns::new(conf))); store.register_late_pass(move |_| Box::new(lines_filter_map_ok::LinesFilterMapOk::new(conf))); store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule)); - store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation)); + store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation::new(conf))); store.register_early_pass(move || Box::new(excessive_nesting::ExcessiveNesting::new(conf))); store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule)); store.register_early_pass(|| Box::new(ref_patterns::RefPatterns)); @@ -937,6 +938,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(unnecessary_literal_bound::UnnecessaryLiteralBound)); store.register_early_pass(|| Box::new(empty_line_after::EmptyLineAfter::new())); store.register_late_pass(move |_| Box::new(arbitrary_source_item_ordering::ArbitrarySourceItemOrdering::new(conf))); + store.register_late_pass(|_| Box::new(useless_concat::UselessConcat)); store.register_late_pass(|_| Box::new(unneeded_struct_pattern::UnneededStructPattern)); store.register_late_pass(|_| Box::::default()); store.register_late_pass(move |_| Box::new(non_std_lazy_statics::NonStdLazyStatic::new(conf))); diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 9a64226b1ed96..8fe0c9d60f961 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -159,7 +159,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { if let ImplItemKind::Fn(ref sig, id) = item.kind { - let report_extra_lifetimes = trait_ref_of_method(cx, item.owner_id.def_id).is_none(); + let report_extra_lifetimes = trait_ref_of_method(cx, item.owner_id).is_none(); check_fn_inner( cx, sig, diff --git a/clippy_lints/src/lines_filter_map_ok.rs b/clippy_lints/src/lines_filter_map_ok.rs index d8af44233d3ee..14ccb6fce2239 100644 --- a/clippy_lints/src/lines_filter_map_ok.rs +++ b/clippy_lints/src/lines_filter_map_ok.rs @@ -2,12 +2,12 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_diag_item_method, is_trait_method, path_to_local_id}; +use clippy_utils::{is_diag_item_method, is_trait_method, path_to_local_id, sym}; use rustc_errors::Applicability; use rustc_hir::{Body, Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::sym; +use rustc_span::Symbol; pub struct LinesFilterMapOk { msrv: Msrv, @@ -74,17 +74,17 @@ impl LateLintPass<'_> for LinesFilterMapOk { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::MethodCall(fm_method, fm_receiver, fm_args, fm_span) = expr.kind && is_trait_method(cx, expr, sym::Iterator) - && let fm_method_str = fm_method.ident.as_str() - && matches!(fm_method_str, "filter_map" | "flat_map" | "flatten") + && let fm_method_name = fm_method.ident.name + && matches!(fm_method_name, sym::filter_map | sym::flat_map | sym::flatten) && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), sym::IoLines) - && should_lint(cx, fm_args, fm_method_str) + && should_lint(cx, fm_args, fm_method_name) && self.msrv.meets(cx, msrvs::MAP_WHILE) { span_lint_and_then( cx, LINES_FILTER_MAP_OK, fm_span, - format!("`{fm_method_str}()` will run forever if the iterator repeatedly produces an `Err`",), + format!("`{fm_method_name}()` will run forever if the iterator repeatedly produces an `Err`",), |diag| { diag.span_note( fm_receiver.span, @@ -101,9 +101,9 @@ impl LateLintPass<'_> for LinesFilterMapOk { } } -fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_str: &str) -> bool { +fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_name: Symbol) -> bool { match args { - [] => method_str == "flatten", + [] => method_name == sym::flatten, [fm_arg] => { match &fm_arg.kind { // Detect `Result::ok` @@ -120,7 +120,7 @@ fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_str: &str) -> boo && path_to_local_id(receiver, param.pat.hir_id) && let Some(method_did) = cx.typeck_results().type_dependent_def_id(value.hir_id) { - is_diag_item_method(cx, method_did, sym::Result) && method.ident.as_str() == "ok" + is_diag_item_method(cx, method_did, sym::Result) && method.ident.name == sym::ok } else { false } diff --git a/clippy_lints/src/loops/char_indices_as_byte_indices.rs b/clippy_lints/src/loops/char_indices_as_byte_indices.rs index 8916454ada16e..a702e60f1c276 100644 --- a/clippy_lints/src/loops/char_indices_as_byte_indices.rs +++ b/clippy_lints/src/loops/char_indices_as_byte_indices.rs @@ -3,12 +3,12 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::ty::is_type_lang_item; use clippy_utils::visitors::for_each_expr; -use clippy_utils::{eq_expr_value, higher, path_to_local_id}; +use clippy_utils::{eq_expr_value, higher, path_to_local_id, sym}; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::{Expr, ExprKind, LangItem, Node, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; -use rustc_span::{Span, sym}; +use rustc_span::{Span, Symbol}; use super::CHAR_INDICES_AS_BYTE_INDICES; @@ -16,22 +16,22 @@ use super::CHAR_INDICES_AS_BYTE_INDICES; // Note: `String` also has methods that work with byte indices, // but they all take `&mut self` and aren't worth considering since the user couldn't have called // them while the chars iterator is live anyway. -const BYTE_INDEX_METHODS: &[&str] = &[ - "is_char_boundary", - "floor_char_boundary", - "ceil_char_boundary", - "get", - "index", - "index_mut", - "get_mut", - "get_unchecked", - "get_unchecked_mut", - "slice_unchecked", - "slice_mut_unchecked", - "split_at", - "split_at_mut", - "split_at_checked", - "split_at_mut_checked", +const BYTE_INDEX_METHODS: &[Symbol] = &[ + sym::ceil_char_boundary, + sym::floor_char_boundary, + sym::get, + sym::get_mut, + sym::get_unchecked, + sym::get_unchecked_mut, + sym::index, + sym::index_mut, + sym::is_char_boundary, + sym::slice_mut_unchecked, + sym::slice_unchecked, + sym::split_at, + sym::split_at_checked, + sym::split_at_mut, + sym::split_at_mut_checked, ]; const CONTINUE: ControlFlow = ControlFlow::Continue(()); @@ -88,7 +88,7 @@ fn check_index_usage<'tcx>( // (contrary to the `ExprKind::Index` case which needs to handle both with `is_string_like` because `String` implements // `Index` directly and no deref to `str` would happen in that case). if cx.typeck_results().expr_ty_adjusted(recv).peel_refs().is_str() - && BYTE_INDEX_METHODS.contains(&segment.ident.name.as_str()) + && BYTE_INDEX_METHODS.contains(&segment.ident.name) && eq_expr_value(cx, chars_recv, recv) => { "passing a character position to a method that expects a byte index" diff --git a/clippy_lints/src/loops/explicit_into_iter_loop.rs b/clippy_lints/src/loops/explicit_into_iter_loop.rs index d5ddc33e928db..4aa1c2e211d33 100644 --- a/clippy_lints/src/loops/explicit_into_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_into_iter_loop.rs @@ -1,7 +1,7 @@ use super::EXPLICIT_INTO_ITER_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_trait_method; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; @@ -76,7 +76,7 @@ pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, call_expr: &Expr< }; let mut applicability = Applicability::MachineApplicable; - let object = snippet_with_applicability(cx, self_arg.span, "_", &mut applicability); + let object = snippet_with_context(cx, self_arg.span, call_expr.span.ctxt(), "_", &mut applicability).0; span_lint_and_sugg( cx, EXPLICIT_INTO_ITER_LOOP, diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index d0b26c91ffafb..010652e1cb902 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -1,7 +1,7 @@ use super::EXPLICIT_ITER_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::sym; use clippy_utils::ty::{ implements_trait, implements_trait_with_env, is_copy, is_type_lang_item, make_normalized_projection, @@ -36,7 +36,7 @@ pub(super) fn check( } let mut applicability = Applicability::MachineApplicable; - let object = snippet_with_applicability(cx, self_arg.span, "_", &mut applicability); + let object = snippet_with_context(cx, self_arg.span, call_expr.span.ctxt(), "_", &mut applicability).0; span_lint_and_sugg( cx, EXPLICIT_ITER_LOOP, diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 56d2bef2305a7..01c36b8cb12fc 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -25,8 +25,8 @@ mod while_let_loop; mod while_let_on_iterator; use clippy_config::Conf; -use clippy_utils::higher; use clippy_utils::msrvs::Msrv; +use clippy_utils::{higher, sym}; use rustc_ast::Label; use rustc_hir::{Expr, ExprKind, LoopSource, Pat}; use rustc_lint::{LateContext, LateLintPass}; @@ -909,15 +909,17 @@ impl Loops { } fn check_for_loop_arg(&self, cx: &LateContext<'_>, _: &Pat<'_>, arg: &Expr<'_>) { - if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind { - match method.ident.as_str() { - "iter" | "iter_mut" => { + if !arg.span.from_expansion() + && let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind + { + match method.ident.name { + sym::iter | sym::iter_mut => { explicit_iter_loop::check(cx, self_arg, arg, self.msrv, self.enforce_iter_loop_reborrow); }, - "into_iter" => { + sym::into_iter => { explicit_into_iter_loop::check(cx, self_arg, arg); }, - "next" => { + sym::next => { iter_next_loop::check(cx, arg); }, _ => {}, diff --git a/clippy_lints/src/manual_is_power_of_two.rs b/clippy_lints/src/manual_is_power_of_two.rs index b4cd988329d32..4439a28763a2f 100644 --- a/clippy_lints/src/manual_is_power_of_two.rs +++ b/clippy_lints/src/manual_is_power_of_two.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::ty_from_hir_ty; -use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal}; +use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal, sym}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; @@ -103,7 +103,7 @@ fn count_ones_receiver<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Optio } else { return None; }; - (method.ident.as_str() == "count_ones" && matches!(ty.kind(), ty::Uint(_))).then_some(receiver) + (method.ident.name == sym::count_ones && matches!(ty.kind(), ty::Uint(_))).then_some(receiver) } /// Return `greater` if `smaller == greater - 1` diff --git a/clippy_lints/src/manual_slice_size_calculation.rs b/clippy_lints/src/manual_slice_size_calculation.rs index 2dad0fa4925e7..0c09a47c96518 100644 --- a/clippy_lints/src/manual_slice_size_calculation.rs +++ b/clippy_lints/src/manual_slice_size_calculation.rs @@ -1,11 +1,13 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use clippy_utils::{expr_or_init, is_in_const_context, std_or_core}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { @@ -36,20 +38,33 @@ declare_clippy_lint! { complexity, "manual slice size calculation" } -declare_lint_pass!(ManualSliceSizeCalculation => [MANUAL_SLICE_SIZE_CALCULATION]); +impl_lint_pass!(ManualSliceSizeCalculation => [MANUAL_SLICE_SIZE_CALCULATION]); + +pub struct ManualSliceSizeCalculation { + msrv: Msrv, +} + +impl ManualSliceSizeCalculation { + pub fn new(conf: &Conf) -> Self { + Self { msrv: conf.msrv } + } +} impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let ExprKind::Binary(ref op, left, right) = expr.kind && BinOpKind::Mul == op.node && !expr.span.from_expansion() - // Does not apply inside const because size_of_val is not cost in stable. - && !is_in_const_context(cx) && let Some((receiver, refs_count)) = simplify(cx, left, right) + && (!is_in_const_context(cx) || self.msrv.meets(cx, msrvs::CONST_SIZE_OF_VAL)) { let ctxt = expr.span.ctxt(); let mut app = Applicability::MachineApplicable; - let deref = "*".repeat(refs_count - 1); + let deref = if refs_count > 0 { + "*".repeat(refs_count - 1) + } else { + "&".into() + }; let val_name = snippet_with_context(cx, receiver.span, ctxt, "slice", &mut app).0; let Some(sugg) = std_or_core(cx) else { return }; diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index b607f8117eb89..af6a1b07a4929 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -255,7 +255,7 @@ impl LateLintPass<'_> for MapUnit { fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) { if let hir::StmtKind::Semi(expr) = stmt.kind && !stmt.span.from_expansion() - && let Some(arglists) = method_chain_args(expr, &["map"]) + && let Some(arglists) = method_chain_args(expr, &[sym::map]) { lint_map_unit_fn(cx, stmt, expr, arglists[0]); } diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index a21597ffb93d7..dbb29ee776b18 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -1,8 +1,9 @@ -use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{SpanlessEq, SpanlessHash, is_lint_allowed, path_to_local, search_same}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::SpanRangeExt; +use clippy_utils::{SpanlessEq, SpanlessHash, fulfill_or_allowed, is_lint_allowed, path_to_local, search_same}; use core::cmp::Ordering; use core::{iter, slice}; +use itertools::Itertools; use rustc_arena::DroplessArena; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -110,57 +111,68 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { && check_same_body() }; - let mut appl = Applicability::MaybeIncorrect; let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect(); - for (&(i, arm1), &(j, arm2)) in search_same(&indexed_arms, hash, eq) { - if matches!(arm2.pat.kind, PatKind::Wild) { - if !cx.tcx.features().non_exhaustive_omitted_patterns_lint() - || is_lint_allowed(cx, NON_EXHAUSTIVE_OMITTED_PATTERNS, arm2.hir_id) - { - let arm_span = adjusted_arm_span(cx, arm1.span); - span_lint_hir_and_then( - cx, - MATCH_SAME_ARMS, - arm1.hir_id, - arm_span, - "this match arm has an identical body to the `_` wildcard arm", - |diag| { - diag.span_suggestion(arm_span, "try removing the arm", "", appl) - .help("or try changing either arm body") - .span_note(arm2.span, "`_` wildcard arm here"); - }, - ); - } - } else { - let back_block = backwards_blocking_idxs[j]; - let (keep_arm, move_arm) = if back_block < i || (back_block == 0 && forwards_blocking_idxs[i] <= j) { - (arm1, arm2) - } else { - (arm2, arm1) - }; - - span_lint_hir_and_then( - cx, - MATCH_SAME_ARMS, - keep_arm.hir_id, - keep_arm.span, - "this match arm has an identical body to another arm", - |diag| { - let move_pat_snip = snippet_with_applicability(cx, move_arm.pat.span, "", &mut appl); - let keep_pat_snip = snippet_with_applicability(cx, keep_arm.pat.span, "", &mut appl); + for mut group in search_same(&indexed_arms, hash, eq) { + // Filter out (and fulfill) `#[allow]`ed and `#[expect]`ed arms + group.retain(|(_, arm)| !fulfill_or_allowed(cx, MATCH_SAME_ARMS, [arm.hir_id])); - diag.multipart_suggestion( - "or try merging the arm patterns and removing the obsolete arm", - vec![ - (keep_arm.pat.span, format!("{keep_pat_snip} | {move_pat_snip}")), - (adjusted_arm_span(cx, move_arm.span), String::new()), - ], - appl, - ) - .help("try changing either arm body"); - }, - ); + if group.len() < 2 { + continue; } + + span_lint_and_then( + cx, + MATCH_SAME_ARMS, + group.iter().map(|(_, arm)| arm.span).collect_vec(), + "these match arms have identical bodies", + |diag| { + diag.help("if this is unintentional make the arms return different values"); + + if let [prev @ .., (_, last)] = group.as_slice() + && is_wildcard_arm(last.pat) + && is_lint_allowed(cx, NON_EXHAUSTIVE_OMITTED_PATTERNS, last.hir_id) + { + diag.span_label(last.span, "the wildcard arm"); + + let s = if prev.len() > 1 { "s" } else { "" }; + diag.multipart_suggestion_verbose( + format!("otherwise remove the non-wildcard arm{s}"), + prev.iter() + .map(|(_, arm)| (adjusted_arm_span(cx, arm.span), String::new())) + .collect(), + Applicability::MaybeIncorrect, + ); + } else if let &[&(first_idx, _), .., &(last_idx, _)] = group.as_slice() { + let back_block = backwards_blocking_idxs[last_idx]; + let split = if back_block < first_idx + || (back_block == 0 && forwards_blocking_idxs[first_idx] <= last_idx) + { + group.split_first() + } else { + group.split_last() + }; + + if let Some(((_, dest), src)) = split + && let Some(pat_snippets) = group + .iter() + .map(|(_, arm)| arm.pat.span.get_source_text(cx)) + .collect::>>() + { + let mut suggs = src + .iter() + .map(|(_, arm)| (adjusted_arm_span(cx, arm.span), String::new())) + .collect_vec(); + + suggs.push((dest.pat.span, pat_snippets.iter().join(" | "))); + diag.multipart_suggestion_verbose( + "otherwise merge the patterns into a single arm", + suggs, + Applicability::MaybeIncorrect, + ); + } + } + }, + ); } } @@ -450,3 +462,11 @@ fn bindings_eq(pat: &Pat<'_>, mut ids: HirIdSet) -> bool { pat.each_binding_or_first(&mut |_, id, _, _| result &= ids.swap_remove(&id)); result && ids.is_empty() } + +fn is_wildcard_arm(pat: &Pat<'_>) -> bool { + match pat.kind { + PatKind::Wild => true, + PatKind::Or([.., last]) => matches!(last.kind, PatKind::Wild), + _ => false, + } +} diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index c6ebd6144c76f..c128fc40b7334 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -28,7 +28,7 @@ use clippy_config::Conf; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::walk_span_to_context; use clippy_utils::{ - higher, is_direct_expn_of, is_in_const_context, is_span_match, span_contains_cfg, span_extract_comments, + higher, is_direct_expn_of, is_in_const_context, is_span_match, span_contains_cfg, span_extract_comments, sym, }; use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -1053,13 +1053,13 @@ impl_lint_pass!(Matches => [ impl<'tcx> LateLintPass<'tcx> for Matches { #[expect(clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if is_direct_expn_of(expr.span, "matches").is_none() && expr.span.in_external_macro(cx.sess().source_map()) { + if is_direct_expn_of(expr.span, sym::matches).is_none() && expr.span.in_external_macro(cx.sess().source_map()) { return; } let from_expansion = expr.span.from_expansion(); if let ExprKind::Match(ex, arms, source) = expr.kind { - if is_direct_expn_of(expr.span, "matches").is_some() + if is_direct_expn_of(expr.span, sym::matches).is_some() && let [arm, _] = arms { redundant_pattern_match::check_match(cx, expr, ex, arms); diff --git a/clippy_lints/src/matches/needless_match.rs b/clippy_lints/src/matches/needless_match.rs index 6c5d7cab2036e..b04db03f8d2e7 100644 --- a/clippy_lints/src/matches/needless_match.rs +++ b/clippy_lints/src/matches/needless_match.rs @@ -74,7 +74,7 @@ fn check_all_arms(cx: &LateContext<'_>, match_expr: &Expr<'_>, arms: &[Arm<'_>]) } if let PatKind::Wild = arm.pat.kind { - if !eq_expr_value(cx, match_expr, strip_return(arm_expr)) { + if !eq_expr_value(cx, match_expr, arm_expr) { return false; } } else if !pat_same_as_expr(arm.pat, arm_expr) { @@ -103,27 +103,18 @@ fn check_if_let_inner(cx: &LateContext<'_>, if_let: &higher::IfLet<'_>) -> bool if matches!(else_expr.kind, ExprKind::Block(..)) { return false; } - let ret = strip_return(else_expr); let let_expr_ty = cx.typeck_results().expr_ty(if_let.let_expr); if is_type_diagnostic_item(cx, let_expr_ty, sym::Option) { - return is_res_lang_ctor(cx, path_res(cx, ret), OptionNone) || eq_expr_value(cx, if_let.let_expr, ret); + return is_res_lang_ctor(cx, path_res(cx, else_expr), OptionNone) + || eq_expr_value(cx, if_let.let_expr, else_expr); } - return eq_expr_value(cx, if_let.let_expr, ret); + return eq_expr_value(cx, if_let.let_expr, else_expr); } } false } -/// Strip `return` keyword if the expression type is `ExprKind::Ret`. -fn strip_return<'hir>(expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> { - if let ExprKind::Ret(Some(ret)) = expr.kind { - ret - } else { - expr - } -} - /// Manually check for coercion casting by checking if the type of the match operand or let expr /// differs with the assigned local variable or the function return type. fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_>) -> bool { @@ -161,7 +152,6 @@ fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_> } fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool { - let expr = strip_return(expr); match (&pat.kind, &expr.kind) { // Example: `Some(val) => Some(val)` (PatKind::TupleStruct(QPath::Resolved(_, path), tuple_params, _), ExprKind::Call(call_expr, call_params)) => { diff --git a/clippy_lints/src/matches/redundant_guards.rs b/clippy_lints/src/matches/redundant_guards.rs index 9bbef8da0a466..7c6d45e424006 100644 --- a/clippy_lints/src/matches/redundant_guards.rs +++ b/clippy_lints/src/matches/redundant_guards.rs @@ -3,14 +3,14 @@ use clippy_utils::macros::matching_root_macro_call; use clippy_utils::msrvs::Msrv; use clippy_utils::source::snippet; use clippy_utils::visitors::{for_each_expr_without_closures, is_local_used}; -use clippy_utils::{is_in_const_context, path_to_local}; +use clippy_utils::{is_in_const_context, path_to_local, sym}; use rustc_ast::{BorrowKind, LitKind}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, MatchSource, Node, PatKind, UnOp}; use rustc_lint::LateContext; use rustc_span::symbol::Ident; -use rustc_span::{Span, sym}; +use rustc_span::{Span, Symbol}; use std::borrow::Cow; use std::ops::ControlFlow; @@ -95,7 +95,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv: } else if let ExprKind::MethodCall(path, recv, args, ..) = guard.kind && let Some(binding) = get_pat_binding(cx, recv, outer_arm) { - check_method_calls(cx, outer_arm, path.ident.name.as_str(), recv, args, guard, &binding); + check_method_calls(cx, outer_arm, path.ident.name, recv, args, guard, &binding); } } } @@ -103,7 +103,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv: fn check_method_calls<'tcx>( cx: &LateContext<'tcx>, arm: &Arm<'tcx>, - method: &str, + method: Symbol, recv: &Expr<'_>, args: &[Expr<'_>], if_expr: &Expr<'_>, @@ -112,7 +112,7 @@ fn check_method_calls<'tcx>( let ty = cx.typeck_results().expr_ty(recv).peel_refs(); let slice_like = ty.is_slice() || ty.is_array(); - let sugg = if method == "is_empty" { + let sugg = if method == sym::is_empty { // `s if s.is_empty()` becomes "" // `arr if arr.is_empty()` becomes [] @@ -137,9 +137,9 @@ fn check_method_calls<'tcx>( if needles.is_empty() { sugg.insert_str(1, ".."); - } else if method == "starts_with" { + } else if method == sym::starts_with { sugg.insert_str(sugg.len() - 1, ", .."); - } else if method == "ends_with" { + } else if method == sym::ends_with { sugg.insert_str(1, ".., "); } else { return; diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index db20be40f27ea..aa9be61bf4d43 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -273,7 +273,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind); if let Some((good_method, maybe_guard)) = found_good_method(cx, arms, node_pair) { - let span = is_expn_of(expr.span, "matches").unwrap_or(expr.span.to(op.span)); + let span = is_expn_of(expr.span, sym::matches).unwrap_or(expr.span.to(op.span)); let result_expr = match &op.kind { ExprKind::AddrOf(_, _, borrowed) => borrowed, _ => op, diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index d7dc7604088f7..0f3ad40784d36 100644 --- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -4,7 +4,7 @@ use crate::FxHashSet; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{first_line_of_span, indent_of, snippet}; use clippy_utils::ty::{for_each_top_level_late_bound_region, is_copy}; -use clippy_utils::{get_attr, is_lint_allowed}; +use clippy_utils::{get_attr, is_lint_allowed, sym}; use itertools::Itertools; use rustc_ast::Mutability; use rustc_data_structures::fx::FxIndexSet; @@ -186,7 +186,7 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> { && get_attr( self.cx.sess(), self.cx.tcx.get_attrs_unchecked(adt.did()), - "has_significant_drop", + sym::has_significant_drop, ) .count() > 0 diff --git a/clippy_lints/src/methods/bytes_nth.rs b/clippy_lints/src/methods/bytes_nth.rs index de22514c37c66..02fc09170e59c 100644 --- a/clippy_lints/src/methods/bytes_nth.rs +++ b/clippy_lints/src/methods/bytes_nth.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sym; use clippy_utils::ty::is_type_lang_item; use rustc_errors::Applicability; use rustc_hir::{Expr, LangItem}; @@ -25,7 +26,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E if let Some(parent) = clippy_utils::get_parent_expr(cx, expr) && let Some((name, _, _, _, _)) = method_call(parent) - && name == "unwrap" + && name == sym::unwrap { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/chars_cmp.rs b/clippy_lints/src/methods/chars_cmp.rs index 4ae0aeea2d1c5..de27a45ba4d92 100644 --- a/clippy_lints/src/methods/chars_cmp.rs +++ b/clippy_lints/src/methods/chars_cmp.rs @@ -5,12 +5,13 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, Lint}; use rustc_middle::ty; +use rustc_span::Symbol; /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints. pub(super) fn check( cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>, - chain_methods: &[&str], + chain_methods: &[Symbol], lint: &'static Lint, suggest: &str, ) -> bool { diff --git a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs index 9c45ec2e56cbe..1c72a973cfa13 100644 --- a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs +++ b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs @@ -5,12 +5,13 @@ use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, Lint}; +use rustc_span::Symbol; /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`. pub(super) fn check( cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>, - chain_methods: &[&str], + chain_methods: &[Symbol], lint: &'static Lint, suggest: &str, ) -> bool { diff --git a/clippy_lints/src/methods/chars_last_cmp.rs b/clippy_lints/src/methods/chars_last_cmp.rs index 2efff4c3c5497..8729e91d191f8 100644 --- a/clippy_lints/src/methods/chars_last_cmp.rs +++ b/clippy_lints/src/methods/chars_last_cmp.rs @@ -1,13 +1,14 @@ use crate::methods::chars_cmp; +use clippy_utils::sym; use rustc_lint::LateContext; use super::CHARS_LAST_CMP; /// Checks for the `CHARS_LAST_CMP` lint. pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { - if chars_cmp::check(cx, info, &["chars", "last"], CHARS_LAST_CMP, "ends_with") { + if chars_cmp::check(cx, info, &[sym::chars, sym::last], CHARS_LAST_CMP, "ends_with") { true } else { - chars_cmp::check(cx, info, &["chars", "next_back"], CHARS_LAST_CMP, "ends_with") + chars_cmp::check(cx, info, &[sym::chars, sym::next_back], CHARS_LAST_CMP, "ends_with") } } diff --git a/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs b/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs index 5b8713f7d7903..027d0a3947bfb 100644 --- a/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs +++ b/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs @@ -1,13 +1,26 @@ use crate::methods::chars_cmp_with_unwrap; +use clippy_utils::sym; use rustc_lint::LateContext; use super::CHARS_LAST_CMP; /// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`. pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { - if chars_cmp_with_unwrap::check(cx, info, &["chars", "last", "unwrap"], CHARS_LAST_CMP, "ends_with") { + if chars_cmp_with_unwrap::check( + cx, + info, + &[sym::chars, sym::last, sym::unwrap], + CHARS_LAST_CMP, + "ends_with", + ) { true } else { - chars_cmp_with_unwrap::check(cx, info, &["chars", "next_back", "unwrap"], CHARS_LAST_CMP, "ends_with") + chars_cmp_with_unwrap::check( + cx, + info, + &[sym::chars, sym::next_back, sym::unwrap], + CHARS_LAST_CMP, + "ends_with", + ) } } diff --git a/clippy_lints/src/methods/chars_next_cmp.rs b/clippy_lints/src/methods/chars_next_cmp.rs index b631fecab9729..2438843bf3ab1 100644 --- a/clippy_lints/src/methods/chars_next_cmp.rs +++ b/clippy_lints/src/methods/chars_next_cmp.rs @@ -1,8 +1,9 @@ +use clippy_utils::sym; use rustc_lint::LateContext; use super::CHARS_NEXT_CMP; /// Checks for the `CHARS_NEXT_CMP` lint. pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { - crate::methods::chars_cmp::check(cx, info, &["chars", "next"], CHARS_NEXT_CMP, "starts_with") + crate::methods::chars_cmp::check(cx, info, &[sym::chars, sym::next], CHARS_NEXT_CMP, "starts_with") } diff --git a/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs b/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs index caf21d3ff3bcb..9b3609f19d724 100644 --- a/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs +++ b/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs @@ -1,8 +1,15 @@ +use clippy_utils::sym; use rustc_lint::LateContext; use super::CHARS_NEXT_CMP; /// Checks for the `CHARS_NEXT_CMP` lint with `unwrap()`. pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { - crate::methods::chars_cmp_with_unwrap::check(cx, info, &["chars", "next", "unwrap"], CHARS_NEXT_CMP, "starts_with") + crate::methods::chars_cmp_with_unwrap::check( + cx, + info, + &[sym::chars, sym::next, sym::unwrap], + CHARS_NEXT_CMP, + "starts_with", + ) } diff --git a/clippy_lints/src/methods/collapsible_str_replace.rs b/clippy_lints/src/methods/collapsible_str_replace.rs index f7bf8764bdebc..6d0b944df55d6 100644 --- a/clippy_lints/src/methods/collapsible_str_replace.rs +++ b/clippy_lints/src/methods/collapsible_str_replace.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::visitors::for_each_expr_without_closures; -use clippy_utils::{eq_expr_value, get_parent_expr}; +use clippy_utils::{eq_expr_value, get_parent_expr, sym}; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir as hir; @@ -22,7 +22,7 @@ pub(super) fn check<'tcx>( // If the parent node's `to` argument is the same as the `to` argument // of the last replace call in the current chain, don't lint as it was already linted if let Some(parent) = get_parent_expr(cx, expr) - && let Some(("replace", _, [current_from, current_to], _, _)) = method_call(parent) + && let Some((sym::replace, _, [current_from, current_to], _, _)) = method_call(parent) && eq_expr_value(cx, to, current_to) && from_kind == cx.typeck_results().expr_ty(current_from).peel_refs().kind() { @@ -47,7 +47,7 @@ fn collect_replace_calls<'tcx>( let mut from_args = VecDeque::new(); let _: Option<()> = for_each_expr_without_closures(expr, |e| { - if let Some(("replace", _, [from, to], _, _)) = method_call(e) { + if let Some((sym::replace, _, [from, to], _, _)) = method_call(e) { if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() { methods.push_front(e); from_args.push_front(from); diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index f5688e370a478..82e5a6d5a4120 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -6,8 +6,8 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::Span; use rustc_span::symbol::sym; +use rustc_span::{Span, Symbol}; use std::borrow::Cow; use super::EXPECT_FUN_CALL; @@ -19,7 +19,7 @@ pub(super) fn check<'tcx>( format_args_storage: &FormatArgsStorage, expr: &hir::Expr<'_>, method_span: Span, - name: &str, + name: Symbol, receiver: &'tcx hir::Expr<'tcx>, args: &'tcx [hir::Expr<'tcx>], ) { @@ -114,7 +114,7 @@ pub(super) fn check<'tcx>( } } - if args.len() != 1 || name != "expect" || !is_call(&args[0].kind) { + if args.len() != 1 || name != sym::expect || !is_call(&args[0].kind) { return; } diff --git a/clippy_lints/src/methods/extend_with_drain.rs b/clippy_lints/src/methods/extend_with_drain.rs index 460ec7b3640a6..db60061904f6f 100644 --- a/clippy_lints/src/methods/extend_with_drain.rs +++ b/clippy_lints/src/methods/extend_with_drain.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sym; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::LateContext; -use rustc_span::symbol::sym; use super::EXTEND_WITH_DRAIN; @@ -13,7 +13,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: if is_type_diagnostic_item(cx, ty, sym::Vec) //check source object && let ExprKind::MethodCall(src_method, drain_vec, [drain_arg], _) = &arg.kind - && src_method.ident.as_str() == "drain" + && src_method.ident.name == sym::drain && let src_ty = cx.typeck_results().expr_ty(drain_vec) //check if actual src type is mutable for code suggestion && let immutable = src_ty.is_mutable_ptr() diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs index 519091406ccf3..9724463f0c084 100644 --- a/clippy_lints/src/methods/implicit_clone.rs +++ b/clippy_lints/src/methods/implicit_clone.rs @@ -1,15 +1,15 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::implements_trait; -use clippy_utils::{is_diag_item_method, is_diag_trait_item, peel_middle_ty_refs}; +use clippy_utils::{is_diag_item_method, is_diag_trait_item, peel_middle_ty_refs, sym}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::sym; +use rustc_span::Symbol; use super::IMPLICIT_CLONE; -pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { +pub fn check(cx: &LateContext<'_>, method_name: Symbol, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && is_clone_like(cx, method_name, method_def_id) && let return_type = cx.typeck_results().expr_ty(expr) @@ -43,12 +43,12 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv /// Note that `to_string` is not flagged by `implicit_clone`. So other lints that call /// `is_clone_like` and that do flag `to_string` must handle it separately. See, e.g., /// `is_to_owned_like` in `unnecessary_to_owned.rs`. -pub fn is_clone_like(cx: &LateContext<'_>, method_name: &str, method_def_id: hir::def_id::DefId) -> bool { +pub fn is_clone_like(cx: &LateContext<'_>, method_name: Symbol, method_def_id: hir::def_id::DefId) -> bool { match method_name { - "to_os_string" => is_diag_item_method(cx, method_def_id, sym::OsStr), - "to_owned" => is_diag_trait_item(cx, method_def_id, sym::ToOwned), - "to_path_buf" => is_diag_item_method(cx, method_def_id, sym::Path), - "to_vec" => cx + sym::to_os_string => is_diag_item_method(cx, method_def_id, sym::OsStr), + sym::to_owned => is_diag_trait_item(cx, method_def_id, sym::ToOwned), + sym::to_path_buf => is_diag_item_method(cx, method_def_id, sym::Path), + sym::to_vec => cx .tcx .impl_of_method(method_def_id) .filter(|&impl_did| { diff --git a/clippy_lints/src/methods/iter_cloned_collect.rs b/clippy_lints/src/methods/iter_cloned_collect.rs index 17cc07b91c5da..b4ab313fe98d1 100644 --- a/clippy_lints/src/methods/iter_cloned_collect.rs +++ b/clippy_lints/src/methods/iter_cloned_collect.rs @@ -5,11 +5,16 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::sym; +use rustc_span::{Symbol, sym}; use super::ITER_CLONED_COLLECT; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, method_name: &str, expr: &hir::Expr<'_>, recv: &'tcx hir::Expr<'_>) { +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + method_name: Symbol, + expr: &hir::Expr<'_>, + recv: &'tcx hir::Expr<'_>, +) { let expr_ty = cx.typeck_results().expr_ty(expr); if is_type_diagnostic_item(cx, expr_ty, sym::Vec) && let Some(slice) = derefs_to_slice(cx, recv, cx.typeck_results().expr_ty(recv)) diff --git a/clippy_lints/src/methods/iter_count.rs b/clippy_lints/src/methods/iter_count.rs index 209cf2fcc0a44..6b64cc8b50ae7 100644 --- a/clippy_lints/src/methods/iter_count.rs +++ b/clippy_lints/src/methods/iter_count.rs @@ -5,11 +5,11 @@ use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_span::sym; +use rustc_span::{Symbol, sym}; use super::ITER_COUNT; -pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, iter_method: &str) { +pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, iter_method: Symbol) { let ty = cx.typeck_results().expr_ty(recv); let caller_type = if derefs_to_slice(cx, recv, ty).is_some() { "slice" diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index 3ac9299ba9157..c88462129af02 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -1,12 +1,12 @@ use super::ITER_KV_MAP; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::pat_is_wild; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{pat_is_wild, sym}; use rustc_hir::{Body, Expr, ExprKind, PatKind}; use rustc_lint::LateContext; -use rustc_span::sym; +use rustc_span::Symbol; /// lint use of: /// @@ -16,13 +16,13 @@ use rustc_span::sym; /// on `HashMaps` and `BTreeMaps` in std pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, - map_type: &'tcx str, // iter / into_iter + map_type: Symbol, // iter / into_iter expr: &'tcx Expr<'tcx>, // .iter().map(|(_, v_| v)) recv: &'tcx Expr<'tcx>, // hashmap m_arg: &'tcx Expr<'tcx>, // |(_, v)| v msrv: Msrv, ) { - if map_type == "into_iter" && !msrv.meets(cx, msrvs::INTO_KEYS) { + if map_type == sym::into_iter && !msrv.meets(cx, msrvs::INTO_KEYS) { return; } if !expr.span.from_expansion() @@ -42,7 +42,7 @@ pub(super) fn check<'tcx>( { let mut applicability = rustc_errors::Applicability::MachineApplicable; let recv_snippet = snippet_with_applicability(cx, recv.span, "map", &mut applicability); - let into_prefix = if map_type == "into_iter" { "into_" } else { "" }; + let into_prefix = if map_type == sym::into_iter { "into_" } else { "" }; if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind && let [local_ident] = path.segments diff --git a/clippy_lints/src/methods/iter_nth.rs b/clippy_lints/src/methods/iter_nth.rs index 82bda5d951225..1fdbd81bf240e 100644 --- a/clippy_lints/src/methods/iter_nth.rs +++ b/clippy_lints/src/methods/iter_nth.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sym; use clippy_utils::ty::get_type_diagnostic_name; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::Span; -use rustc_span::symbol::sym; +use rustc_span::{Span, Symbol}; use super::ITER_NTH; @@ -12,7 +12,7 @@ pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, iter_recv: &'tcx hir::Expr<'tcx>, - iter_method: &str, + iter_method: Symbol, iter_span: Span, nth_span: Span, ) -> bool { @@ -30,7 +30,7 @@ pub(super) fn check<'tcx>( expr.span, format!("called `.{iter_method}().nth()` on a {caller_type}"), |diag| { - let get_method = if iter_method == "iter_mut" { "get_mut" } else { "get" }; + let get_method = if iter_method == sym::iter_mut { "get_mut" } else { "get" }; diag.span_suggestion_verbose( iter_span.to(nth_span), format!("`{get_method}` is equivalent but more concise"), diff --git a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs index 9d562f5e51d2c..c0366765234f9 100644 --- a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs +++ b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -2,7 +2,7 @@ use std::iter::once; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::{get_expr_use_or_unification_node, is_res_lang_ctor, path_res, std_or_core}; +use clippy_utils::{get_expr_use_or_unification_node, is_res_lang_ctor, path_res, std_or_core, sym}; use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, OptionSome}; @@ -10,6 +10,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::hir_id::HirId; use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::LateContext; +use rustc_span::Symbol; use super::{ITER_ON_EMPTY_COLLECTIONS, ITER_ON_SINGLE_ITEMS}; @@ -51,7 +52,7 @@ fn is_arg_ty_unified_in_fn<'tcx>( .any(|(i, ty)| i != arg_id_in_args && ty.skip_binder().walk().any(|arg| arg.as_type() == Some(arg_ty_in_args))) } -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: &str, recv: &'tcx Expr<'tcx>) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, recv: &'tcx Expr<'tcx>) { let item = match recv.kind { ExprKind::Array([]) => None, ExprKind::Array([e]) => Some(e), @@ -60,9 +61,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method _ => return, }; let iter_type = match method_name { - "iter" => IterType::Iter, - "iter_mut" => IterType::IterMut, - "into_iter" => IterType::IntoIter, + sym::iter => IterType::Iter, + sym::iter_mut => IterType::IterMut, + sym::into_iter => IterType::IntoIter, _ => return, }; diff --git a/clippy_lints/src/methods/iter_overeager_cloned.rs b/clippy_lints/src/methods/iter_overeager_cloned.rs index 7bb625222ec0f..f5fe4316eb0d3 100644 --- a/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -8,7 +8,7 @@ use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, Pl use rustc_lint::LateContext; use rustc_middle::mir::{FakeReadCause, Mutability}; use rustc_middle::ty::{self, BorrowKind}; -use rustc_span::sym; +use rustc_span::{Symbol, sym}; use super::ITER_OVEREAGER_CLONED; use crate::redundant_clone::REDUNDANT_CLONE; @@ -26,7 +26,7 @@ pub(super) enum Op<'a> { // later `.cloned()` // and add `&` to the parameter of closure parameter // e.g. `find` `filter` - FixClosure(&'a str, &'a Expr<'a>), + FixClosure(Symbol, &'a Expr<'a>), // later `.cloned()` // e.g. `skip` `take` diff --git a/clippy_lints/src/methods/manual_c_str_literals.rs b/clippy_lints/src/methods/manual_c_str_literals.rs index 3fa83cd39d1d2..a8445b68dd608 100644 --- a/clippy_lints/src/methods/manual_c_str_literals.rs +++ b/clippy_lints/src/methods/manual_c_str_literals.rs @@ -168,7 +168,7 @@ fn rewrite_as_cstr(cx: &LateContext<'_>, span: Span) -> Option { fn get_cast_target<'tcx>(e: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { match &e.kind { - ExprKind::MethodCall(method, receiver, [], _) if method.ident.as_str() == "cast" => Some(receiver), + ExprKind::MethodCall(method, receiver, [], _) if method.ident.name == sym::cast => Some(receiver), ExprKind::Cast(expr, _) => Some(expr), _ => None, } diff --git a/clippy_lints/src/methods/manual_inspect.rs b/clippy_lints/src/methods/manual_inspect.rs index 173ebcb7020b7..21f2ce8b7c900 100644 --- a/clippy_lints/src/methods/manual_inspect.rs +++ b/clippy_lints/src/methods/manual_inspect.rs @@ -3,18 +3,18 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{IntoSpan, SpanRangeExt}; use clippy_utils::ty::get_field_by_name; use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures}; -use clippy_utils::{ExprUseNode, expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id}; +use clippy_utils::{ExprUseNode, expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id, sym}; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::{BindingMode, BorrowKind, ByRef, ClosureKind, Expr, ExprKind, Mutability, Node, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; -use rustc_span::{DUMMY_SP, Span, Symbol, sym}; +use rustc_span::{DUMMY_SP, Span, Symbol}; use super::MANUAL_INSPECT; #[expect(clippy::too_many_lines)] -pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: &str, name_span: Span, msrv: Msrv) { +pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: Symbol, name_span: Span, msrv: Msrv) { if let ExprKind::Closure(c) = arg.kind && matches!(c.kind, ClosureKind::Closure) && let typeck = cx.typeck_results() @@ -101,7 +101,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: UseKind::Return(s) => edits.push((s.with_leading_whitespace(cx).with_ctxt(s.ctxt()), String::new())), UseKind::Borrowed(s) => { #[expect(clippy::range_plus_one)] - let range = s.map_range(cx, |src, range| { + let range = s.map_range(cx, |_, src, range| { let src = src.get(range.clone())?; let trimmed = src.trim_start_matches([' ', '\t', '\n', '\r', '(']); trimmed.starts_with('&').then(|| { @@ -168,8 +168,8 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: edits.extend(addr_of_edits); } let edit = match name { - "map" => "inspect", - "map_err" => "inspect_err", + sym::map => "inspect", + sym::map_err => "inspect_err", _ => return, }; edits.push((name_span, edit.to_string())); diff --git a/clippy_lints/src/methods/map_identity.rs b/clippy_lints/src/methods/map_identity.rs index 0536014465731..98def66ca1499 100644 --- a/clippy_lints/src/methods/map_identity.rs +++ b/clippy_lints/src/methods/map_identity.rs @@ -5,7 +5,7 @@ use rustc_ast::BindingMode; use rustc_errors::Applicability; use rustc_hir::{self as hir, Node, PatKind}; use rustc_lint::LateContext; -use rustc_span::{Span, sym}; +use rustc_span::{Span, Symbol, sym}; use super::MAP_IDENTITY; @@ -14,7 +14,7 @@ pub(super) fn check( expr: &hir::Expr<'_>, caller: &hir::Expr<'_>, map_arg: &hir::Expr<'_>, - name: &str, + name: Symbol, _map_span: Span, ) { let caller_ty = cx.typeck_results().expr_ty(caller); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e0e6a1a59b623..d2d59f0013c0c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -150,7 +150,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::macros::FormatArgsStorage; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item}; -use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty}; +use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty, sym}; pub use path_ends_with_ext::DEFAULT_ALLOWED_DOTFILES; use rustc_abi::ExternAbi; use rustc_data_structures::fx::FxHashSet; @@ -159,7 +159,7 @@ use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::{self, TraitRef, Ty}; use rustc_session::impl_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::{Span, Symbol, kw}; declare_clippy_lint! { /// ### What it does @@ -4711,17 +4711,15 @@ impl_lint_pass!(Methods => [ /// Extracts a method call name, args, and `Span` of the method name. /// This ensures that neither the receiver nor any of the arguments /// come from expansion. -pub fn method_call<'tcx>( - recv: &'tcx Expr<'tcx>, -) -> Option<(&'tcx str, &'tcx Expr<'tcx>, &'tcx [Expr<'tcx>], Span, Span)> { +pub fn method_call<'tcx>(recv: &'tcx Expr<'tcx>) -> Option<(Symbol, &'tcx Expr<'tcx>, &'tcx [Expr<'tcx>], Span, Span)> { if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind && !args.iter().any(|e| e.span.from_expansion()) && !receiver.span.from_expansion() { - let name = path.ident.name.as_str(); - return Some((name, receiver, args, path.ident.span, call_span)); + Some((path.ident.name, receiver, args, path.ident.span, call_span)) + } else { + None } - None } impl<'tcx> LateLintPass<'tcx> for Methods { @@ -4743,13 +4741,13 @@ impl<'tcx> LateLintPass<'tcx> for Methods { }, ExprKind::MethodCall(method_call, receiver, args, _) => { let method_span = method_call.ident.span; - or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args); + or_fun_call::check(cx, expr, method_span, method_call.ident.name, receiver, args); expect_fun_call::check( cx, &self.format_args, expr, method_span, - method_call.ident.as_str(), + method_call.ident.name, receiver, args, ); @@ -4778,7 +4776,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if impl_item.span.in_external_macro(cx.sess().source_map()) { return; } - let name = impl_item.ident.name.as_str(); + let name = impl_item.ident.name; let parent = cx.tcx.hir_get_parent_item(impl_item.hir_id()).def_id; let item = cx.tcx.hir_expect_item(parent); let self_ty = cx.tcx.type_of(item.owner_id).instantiate_identity(); @@ -4851,7 +4849,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { return; } - if name == "new" && ret_ty != self_ty { + if name == sym::new && ret_ty != self_ty { span_lint( cx, NEW_RET_NO_SELF, @@ -4881,7 +4879,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty(); wrong_self_convention::check( cx, - item.ident.name.as_str(), + item.ident.name, self_ty, first_arg_ty, first_arg_hir_ty.span, @@ -4912,14 +4910,17 @@ impl Methods { // Handle method calls whose receiver and arguments may not come from expansion if let Some((name, recv, args, span, call_span)) = method_call(expr) { match (name, args) { - ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => { + ( + sym::add | sym::offset | sym::sub | sym::wrapping_offset | sym::wrapping_add | sym::wrapping_sub, + [_arg], + ) => { zst_offset::check(cx, expr, recv); }, - ("all", [arg]) => { + (sym::all, [arg]) => { unused_enumerate_index::check(cx, expr, recv, arg); needless_character_iteration::check(cx, expr, recv, arg, true); match method_call(recv) { - Some(("cloned", recv2, [], _, _)) => { + Some((sym::cloned, recv2, [], _, _)) => { iter_overeager_cloned::check( cx, expr, @@ -4929,13 +4930,13 @@ impl Methods { false, ); }, - Some(("map", _, [map_arg], _, map_call_span)) => { + Some((sym::map, _, [map_arg], _, map_call_span)) => { map_all_any_identity::check(cx, expr, recv, map_call_span, map_arg, call_span, arg, "all"); }, _ => {}, } }, - ("and_then", [arg]) => { + (sym::and_then, [arg]) => { let biom_option_linted = bind_instead_of_map::check_and_then_some(cx, expr, recv, arg); let biom_result_linted = bind_instead_of_map::check_and_then_ok(cx, expr, recv, arg); if !biom_option_linted && !biom_result_linted { @@ -4945,11 +4946,11 @@ impl Methods { } } }, - ("any", [arg]) => { + (sym::any, [arg]) => { unused_enumerate_index::check(cx, expr, recv, arg); needless_character_iteration::check(cx, expr, recv, arg, false); match method_call(recv) { - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check( cx, expr, recv, @@ -4957,80 +4958,79 @@ impl Methods { iter_overeager_cloned::Op::NeedlessMove(arg), false, ), - Some(("chars", recv, _, _, _)) + Some((sym::chars, recv, _, _, _)) if let ExprKind::Closure(arg) = arg.kind && let body = cx.tcx.hir_body(arg.body) && let [param] = body.params => { string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), self.msrv); }, - Some(("map", _, [map_arg], _, map_call_span)) => { + Some((sym::map, _, [map_arg], _, map_call_span)) => { map_all_any_identity::check(cx, expr, recv, map_call_span, map_arg, call_span, arg, "any"); }, - Some(("iter", iter_recv, ..)) => { + Some((sym::iter, iter_recv, ..)) => { manual_contains::check(cx, expr, iter_recv, arg); }, _ => {}, } }, - ("arg", [arg]) => { + (sym::arg, [arg]) => { suspicious_command_arg_space::check(cx, recv, arg, span); }, - ("as_deref" | "as_deref_mut", []) => { + (sym::as_deref | sym::as_deref_mut, []) => { needless_option_as_deref::check(cx, expr, recv, name); }, - ("as_bytes", []) => { - if let Some(("as_str", recv, [], as_str_span, _)) = method_call(recv) { + (sym::as_bytes, []) => { + if let Some((sym::as_str, recv, [], as_str_span, _)) = method_call(recv) { redundant_as_str::check(cx, expr, recv, as_str_span, span); } sliced_string_as_bytes::check(cx, expr, recv); }, - ("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv), - ("as_ptr", []) => manual_c_str_literals::check_as_ptr(cx, expr, recv, self.msrv), - ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv), - ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv), - ("bytes", []) => unbuffered_bytes::check(cx, expr, recv), - ("cloned", []) => { + (sym::as_mut | sym::as_ref, []) => useless_asref::check(cx, expr, name, recv), + (sym::as_ptr, []) => manual_c_str_literals::check_as_ptr(cx, expr, recv, self.msrv), + (sym::assume_init, []) => uninit_assumed_init::check(cx, expr, recv), + (sym::bytes, []) => unbuffered_bytes::check(cx, expr, recv), + (sym::cloned, []) => { cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv); option_as_ref_cloned::check(cx, recv, span); }, - ("collect", []) if is_trait_method(cx, expr, sym::Iterator) => { + (sym::collect, []) if is_trait_method(cx, expr, sym::Iterator) => { needless_collect::check(cx, span, expr, recv, call_span); match method_call(recv) { - Some((name @ ("cloned" | "copied"), recv2, [], _, _)) => { + Some((name @ (sym::cloned | sym::copied), recv2, [], _, _)) => { iter_cloned_collect::check(cx, name, expr, recv2); }, - Some(("map", m_recv, [m_arg], m_ident_span, _)) => { + Some((sym::map, m_recv, [m_arg], m_ident_span, _)) => { map_collect_result_unit::check(cx, expr, m_recv, m_arg); format_collect::check(cx, expr, m_arg, m_ident_span); }, - Some(("take", take_self_arg, [take_arg], _, _)) => { + Some((sym::take, take_self_arg, [take_arg], _, _)) => { if self.msrv.meets(cx, msrvs::STR_REPEAT) { manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg); } }, - Some(("drain", recv, args, ..)) => { + Some((sym::drain, recv, args, ..)) => { drain_collect::check(cx, args, expr, recv); }, _ => {}, } }, - ("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) { - Some(("cloned", recv2, [], _, _)) => { + (sym::count, []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) { + Some((sym::cloned, recv2, [], _, _)) => { iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::RmCloned, false); }, - Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _, _)) => { + Some((name2 @ (sym::into_iter | sym::iter | sym::iter_mut), recv2, [], _, _)) => { iter_count::check(cx, expr, recv2, name2); }, - Some(("map", _, [arg], _, _)) => suspicious_map::check(cx, expr, recv, arg), - Some(("filter", recv2, [arg], _, _)) => bytecount::check(cx, expr, recv2, arg), - Some(("bytes", recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2), + Some((sym::map, _, [arg], _, _)) => suspicious_map::check(cx, expr, recv, arg), + Some((sym::filter, recv2, [arg], _, _)) => bytecount::check(cx, expr, recv2, arg), + Some((sym::bytes, recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2), _ => {}, }, - ("min" | "max", [arg]) => { + (sym::min | sym::max, [arg]) => { unnecessary_min_or_max::check(cx, expr, name, recv, arg); }, - ("drain", ..) => { + (sym::drain, ..) => { if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.parent_hir_node(expr.hir_id) && matches!(kind, StmtKind::Semi(_)) && args.len() <= 1 @@ -5040,31 +5040,31 @@ impl Methods { iter_with_drain::check(cx, expr, recv, span, arg); } }, - ("ends_with", [arg]) => { + (sym::ends_with, [arg]) => { if let ExprKind::MethodCall(.., span) = expr.kind { case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg, self.msrv); } path_ends_with_ext::check(cx, recv, arg, expr, self.msrv, &self.allowed_dotfiles); }, - ("expect", [_]) => { + (sym::expect, [_]) => { match method_call(recv) { - Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv), - Some(("err", recv, [], err_span, _)) => { + Some((sym::ok, recv, [], _, _)) => ok_expect::check(cx, expr, recv), + Some((sym::err, recv, [], err_span, _)) => { err_expect::check(cx, expr, recv, span, err_span, self.msrv); }, _ => {}, } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, - ("expect_err", [_]) | ("unwrap_err" | "unwrap_unchecked" | "unwrap_err_unchecked", []) => { + (sym::expect_err, [_]) | (sym::unwrap_err | sym::unwrap_unchecked | sym::unwrap_err_unchecked, []) => { unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, - ("extend", [arg]) => { + (sym::extend, [arg]) => { string_extend_chars::check(cx, expr, recv, arg); extend_with_drain::check(cx, expr, recv, arg); }, - ("filter", [arg]) => { - if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { + (sym::filter, [arg]) => { + if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) { // if `arg` has side-effect, the semantic will change iter_overeager_cloned::check( cx, @@ -5080,8 +5080,8 @@ impl Methods { iter_filter::check(cx, expr, arg, span); } }, - ("find", [arg]) => { - if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { + (sym::find, [arg]) => { + if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) { // if `arg` has side-effect, the semantic will change iter_overeager_cloned::check( cx, @@ -5093,26 +5093,26 @@ impl Methods { ); } }, - ("filter_map", [arg]) => { + (sym::filter_map, [arg]) => { unused_enumerate_index::check(cx, expr, recv, arg); unnecessary_filter_map::check(cx, expr, arg, name); filter_map_bool_then::check(cx, expr, arg, call_span); filter_map_identity::check(cx, expr, arg, span); }, - ("find_map", [arg]) => { + (sym::find_map, [arg]) => { unused_enumerate_index::check(cx, expr, recv, arg); unnecessary_filter_map::check(cx, expr, arg, name); }, - ("flat_map", [arg]) => { + (sym::flat_map, [arg]) => { unused_enumerate_index::check(cx, expr, recv, arg); flat_map_identity::check(cx, expr, arg, span); flat_map_option::check(cx, expr, arg, span); }, - ("flatten", []) => match method_call(recv) { - Some(("map", recv, [map_arg], map_span, _)) => { + (sym::flatten, []) => match method_call(recv) { + Some((sym::map, recv, [map_arg], map_span, _)) => { map_flatten::check(cx, expr, recv, map_arg, map_span); }, - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check( cx, expr, recv, @@ -5122,15 +5122,15 @@ impl Methods { ), _ => {}, }, - ("fold", [init, acc]) => { + (sym::fold, [init, acc]) => { manual_try_fold::check(cx, expr, init, acc, call_span, self.msrv); unnecessary_fold::check(cx, expr, init, acc, span); }, - ("for_each", [arg]) => { + (sym::for_each, [arg]) => { unused_enumerate_index::check(cx, expr, recv, arg); match method_call(recv) { - Some(("inspect", _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2), - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + Some((sym::inspect, _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2), + Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check( cx, expr, recv, @@ -5141,44 +5141,44 @@ impl Methods { _ => {}, } }, - ("get", [arg]) => { + (sym::get, [arg]) => { get_first::check(cx, expr, recv, arg); get_last_with_len::check(cx, expr, recv, arg); }, - ("get_or_insert_with", [arg]) => { + (sym::get_or_insert_with, [arg]) => { unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"); }, - ("hash", [arg]) => { + (sym::hash, [arg]) => { unit_hash::check(cx, expr, recv, arg); }, - ("is_empty", []) => { + (sym::is_empty, []) => { match method_call(recv) { - Some((prev_method @ ("as_bytes" | "bytes"), prev_recv, [], _, _)) => { - needless_as_bytes::check(cx, prev_method, "is_empty", prev_recv, expr.span); + Some((prev_method @ (sym::as_bytes | sym::bytes), prev_recv, [], _, _)) => { + needless_as_bytes::check(cx, prev_method, name, prev_recv, expr.span); }, - Some(("as_str", recv, [], as_str_span, _)) => { + Some((sym::as_str, recv, [], as_str_span, _)) => { redundant_as_str::check(cx, expr, recv, as_str_span, span); }, _ => {}, } is_empty::check(cx, expr, recv); }, - ("is_file", []) => filetype_is_file::check(cx, expr, recv), - ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv), - ("is_none", []) => check_is_some_is_none(cx, expr, recv, call_span, false), - ("is_some", []) => check_is_some_is_none(cx, expr, recv, call_span, true), - ("iter" | "iter_mut" | "into_iter", []) => { + (sym::is_file, []) => filetype_is_file::check(cx, expr, recv), + (sym::is_digit, [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv), + (sym::is_none, []) => check_is_some_is_none(cx, expr, recv, call_span, false), + (sym::is_some, []) => check_is_some_is_none(cx, expr, recv, call_span, true), + (sym::iter | sym::iter_mut | sym::into_iter, []) => { iter_on_single_or_empty_collections::check(cx, expr, name, recv); }, - ("join", [join_arg]) => { - if let Some(("collect", _, _, span, _)) = method_call(recv) { + (sym::join, [join_arg]) => { + if let Some((sym::collect, _, _, span, _)) = method_call(recv) { unnecessary_join::check(cx, expr, recv, join_arg, span); } else { join_absolute_paths::check(cx, recv, join_arg, expr.span); } }, - ("last", []) => { - if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { + (sym::last, []) => { + if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) { iter_overeager_cloned::check( cx, expr, @@ -5190,24 +5190,24 @@ impl Methods { } double_ended_iterator_last::check(cx, expr, recv, call_span); }, - ("len", []) => { - if let Some((prev_method @ ("as_bytes" | "bytes"), prev_recv, [], _, _)) = method_call(recv) { - needless_as_bytes::check(cx, prev_method, "len", prev_recv, expr.span); + (sym::len, []) => { + if let Some((prev_method @ (sym::as_bytes | sym::bytes), prev_recv, [], _, _)) = method_call(recv) { + needless_as_bytes::check(cx, prev_method, sym::len, prev_recv, expr.span); } }, - ("lock", []) => { + (sym::lock, []) => { mut_mutex_lock::check(cx, expr, recv, span); }, - (name @ ("map" | "map_err"), [m_arg]) => { - if name == "map" { + (name @ (sym::map | sym::map_err), [m_arg]) => { + if name == sym::map { unused_enumerate_index::check(cx, expr, recv, m_arg); map_clone::check(cx, expr, recv, m_arg, self.msrv); map_with_unused_argument_over_ranges::check(cx, expr, recv, m_arg, self.msrv, span); match method_call(recv) { - Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) => { + Some((map_name @ (sym::iter | sym::into_iter), recv2, _, _, _)) => { iter_kv_map::check(cx, map_name, expr, recv2, m_arg, self.msrv); }, - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check( cx, expr, recv, @@ -5222,12 +5222,12 @@ impl Methods { } if let Some((name, recv2, args, span2, _)) = method_call(recv) { match (name, args) { - ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv), - ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv), - ("filter", [f_arg]) => { + (sym::as_mut, []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv), + (sym::as_ref, []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv), + (sym::filter, [f_arg]) => { filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false); }, - ("find", [f_arg]) => { + (sym::find, [f_arg]) => { filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true); }, _ => {}, @@ -5237,22 +5237,22 @@ impl Methods { manual_inspect::check(cx, expr, m_arg, name, span, self.msrv); crate::useless_conversion::check_function_application(cx, expr, recv, m_arg); }, - ("map_break" | "map_continue", [m_arg]) => { + (sym::map_break | sym::map_continue, [m_arg]) => { crate::useless_conversion::check_function_application(cx, expr, recv, m_arg); }, - ("map_or", [def, map]) => { + (sym::map_or, [def, map]) => { option_map_or_none::check(cx, expr, recv, def, map); manual_ok_or::check(cx, expr, recv, def, map); unnecessary_map_or::check(cx, expr, recv, def, map, span, self.msrv); }, - ("map_or_else", [def, map]) => { + (sym::map_or_else, [def, map]) => { result_map_or_else_none::check(cx, expr, recv, def, map); unnecessary_result_map_or_else::check(cx, expr, recv, def, map); }, - ("next", []) => { + (sym::next, []) => { if let Some((name2, recv2, args2, _, _)) = method_call(recv) { match (name2, args2) { - ("cloned", []) => iter_overeager_cloned::check( + (sym::cloned, []) => iter_overeager_cloned::check( cx, expr, recv, @@ -5260,19 +5260,19 @@ impl Methods { iter_overeager_cloned::Op::LaterCloned, false, ), - ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg), - ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, self.msrv), - ("iter", []) => iter_next_slice::check(cx, expr, recv2), - ("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg), - ("skip_while", [_]) => skip_while_next::check(cx, expr), - ("rev", []) => manual_next_back::check(cx, expr, recv, recv2), + (sym::filter, [arg]) => filter_next::check(cx, expr, recv2, arg), + (sym::filter_map, [arg]) => filter_map_next::check(cx, expr, recv2, arg, self.msrv), + (sym::iter, []) => iter_next_slice::check(cx, expr, recv2), + (sym::skip, [arg]) => iter_skip_next::check(cx, expr, recv2, arg), + (sym::skip_while, [_]) => skip_while_next::check(cx, expr), + (sym::rev, []) => manual_next_back::check(cx, expr, recv, recv2), _ => {}, } } }, - ("nth", [n_arg]) => match method_call(recv) { - Some(("bytes", recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg), - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + (sym::nth, [n_arg]) => match method_call(recv) { + Some((sym::bytes, recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg), + Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check( cx, expr, recv, @@ -5280,54 +5280,54 @@ impl Methods { iter_overeager_cloned::Op::LaterCloned, false, ), - Some((iter_method @ ("iter" | "iter_mut"), iter_recv, [], iter_span, _)) => { + Some((iter_method @ (sym::iter | sym::iter_mut), iter_recv, [], iter_span, _)) => { if !iter_nth::check(cx, expr, iter_recv, iter_method, iter_span, span) { iter_nth_zero::check(cx, expr, recv, n_arg); } }, _ => iter_nth_zero::check(cx, expr, recv, n_arg), }, - ("ok_or_else", [arg]) => { + (sym::ok_or_else, [arg]) => { unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"); }, - ("open", [_]) => { + (sym::open, [_]) => { open_options::check(cx, expr, recv); }, - ("or_else", [arg]) => { + (sym::or_else, [arg]) => { if !bind_instead_of_map::check_or_else_err(cx, expr, recv, arg) { unnecessary_lazy_eval::check(cx, expr, recv, arg, "or"); } }, - ("push", [arg]) => { + (sym::push, [arg]) => { path_buf_push_overwrite::check(cx, expr, arg); }, - ("read_to_end", [_]) => { + (sym::read_to_end, [_]) => { verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_END_MSG); }, - ("read_to_string", [_]) => { + (sym::read_to_string, [_]) => { verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_STRING_MSG); }, - ("read_line", [arg]) => { + (sym::read_line, [arg]) => { read_line_without_trim::check(cx, expr, recv, arg); }, - ("repeat", [arg]) => { + (sym::repeat, [arg]) => { repeat_once::check(cx, expr, recv, arg); }, - (name @ ("replace" | "replacen"), [arg1, arg2] | [arg1, arg2, _]) => { + (name @ (sym::replace | sym::replacen), [arg1, arg2] | [arg1, arg2, _]) => { no_effect_replace::check(cx, expr, arg1, arg2); // Check for repeated `str::replace` calls to perform `collapsible_str_replace` lint if self.msrv.meets(cx, msrvs::PATTERN_TRAIT_CHAR_ARRAY) - && name == "replace" - && let Some(("replace", ..)) = method_call(recv) + && name == sym::replace + && let Some((sym::replace, ..)) = method_call(recv) { collapsible_str_replace::check(cx, expr, arg1, arg2); } }, - ("resize", [count_arg, default_arg]) => { + (sym::resize, [count_arg, default_arg]) => { vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span); }, - ("seek", [arg]) => { + (sym::seek, [arg]) => { if self.msrv.meets(cx, msrvs::SEEK_FROM_CURRENT) { seek_from_current::check(cx, expr, recv, arg); } @@ -5335,11 +5335,11 @@ impl Methods { seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span); } }, - ("skip", [arg]) => { + (sym::skip, [arg]) => { iter_skip_zero::check(cx, expr, arg); iter_out_of_bounds::check_skip(cx, expr, recv, arg); - if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { + if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) { iter_overeager_cloned::check( cx, expr, @@ -5350,34 +5350,34 @@ impl Methods { ); } }, - ("sort", []) => { + (sym::sort, []) => { stable_sort_primitive::check(cx, expr, recv); }, - ("sort_by", [arg]) => { + (sym::sort_by, [arg]) => { unnecessary_sort_by::check(cx, expr, recv, arg, false); }, - ("sort_unstable_by", [arg]) => { + (sym::sort_unstable_by, [arg]) => { unnecessary_sort_by::check(cx, expr, recv, arg, true); }, - ("split", [arg]) => { + (sym::split, [arg]) => { str_split::check(cx, expr, recv, arg); }, - ("splitn" | "rsplitn", [count_arg, pat_arg]) => { + (sym::splitn | sym::rsplitn, [count_arg, pat_arg]) => { if let Some(Constant::Int(count)) = ConstEvalCtxt::new(cx).eval(count_arg) { suspicious_splitn::check(cx, name, expr, recv, count); str_splitn::check(cx, name, expr, recv, pat_arg, count, self.msrv); } }, - ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => { + (sym::splitn_mut | sym::rsplitn_mut, [count_arg, _]) => { if let Some(Constant::Int(count)) = ConstEvalCtxt::new(cx).eval(count_arg) { suspicious_splitn::check(cx, name, expr, recv, count); } }, - ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg), - ("take", [arg]) => { + (sym::step_by, [arg]) => iterator_step_by_zero::check(cx, expr, arg), + (sym::take, [arg]) => { iter_out_of_bounds::check_take(cx, expr, recv, arg); manual_repeat_n::check(cx, expr, recv, arg, self.msrv); - if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { + if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) { iter_overeager_cloned::check( cx, expr, @@ -5388,74 +5388,89 @@ impl Methods { ); } }, - ("take", []) => needless_option_take::check(cx, expr, recv), - ("then", [arg]) => { + (sym::take, []) => needless_option_take::check(cx, expr, recv), + (sym::then, [arg]) => { if !self.msrv.meets(cx, msrvs::BOOL_THEN_SOME) { return; } unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some"); }, - ("try_into", []) if is_trait_method(cx, expr, sym::TryInto) => { + (sym::try_into, []) if is_trait_method(cx, expr, sym::TryInto) => { unnecessary_fallible_conversions::check_method(cx, expr); }, - ("to_owned", []) => { + (sym::to_owned, []) => { if !suspicious_to_owned::check(cx, expr, recv) { implicit_clone::check(cx, name, expr, recv); } }, - ("to_os_string" | "to_path_buf" | "to_vec", []) => { + (sym::to_os_string | sym::to_path_buf | sym::to_vec, []) => { implicit_clone::check(cx, name, expr, recv); }, - ("type_id", []) => { + (sym::type_id, []) => { type_id_on_box::check(cx, recv, expr.span); }, - ("unwrap", []) => { + (sym::unwrap, []) => { match method_call(recv) { - Some(("get", recv, [get_arg], _, _)) => { + Some((sym::get, recv, [get_arg], _, _)) => { get_unwrap::check(cx, expr, recv, get_arg, false); }, - Some(("get_mut", recv, [get_arg], _, _)) => { + Some((sym::get_mut, recv, [get_arg], _, _)) => { get_unwrap::check(cx, expr, recv, get_arg, true); }, - Some(("or", recv, [or_arg], or_span, _)) => { + Some((sym::or, recv, [or_arg], or_span, _)) => { or_then_unwrap::check(cx, expr, recv, or_arg, or_span); }, _ => {}, } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, - ("unwrap_or", [u_arg]) => { + (sym::unwrap_or, [u_arg]) => { match method_call(recv) { - Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _, _)) => { - manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]); + Some((arith @ (sym::checked_add | sym::checked_sub | sym::checked_mul), lhs, [rhs], _, _)) => { + manual_saturating_arithmetic::check( + cx, + expr, + lhs, + rhs, + u_arg, + &arith.as_str()[const { "checked_".len() }..], + ); }, - Some(("map", m_recv, [m_arg], span, _)) => { + Some((sym::map, m_recv, [m_arg], span, _)) => { option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, self.msrv); }, - Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => { - obfuscated_if_else::check(cx, expr, t_recv, t_arg, Some(u_arg), then_method, "unwrap_or"); + Some((then_method @ (sym::then | sym::then_some), t_recv, [t_arg], _, _)) => { + obfuscated_if_else::check(cx, expr, t_recv, t_arg, Some(u_arg), then_method, name); }, _ => {}, } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, - ("unwrap_or_default", []) => { + (sym::unwrap_or_default, []) => { match method_call(recv) { - Some(("map", m_recv, [arg], span, _)) => { + Some((sym::map, m_recv, [arg], span, _)) => { manual_is_variant_and::check(cx, expr, m_recv, arg, span, self.msrv); }, - Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => { - obfuscated_if_else::check(cx, expr, t_recv, t_arg, None, then_method, "unwrap_or_default"); + Some((then_method @ (sym::then | sym::then_some), t_recv, [t_arg], _, _)) => { + obfuscated_if_else::check( + cx, + expr, + t_recv, + t_arg, + None, + then_method, + sym::unwrap_or_default, + ); }, _ => {}, } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, - ("unwrap_or_else", [u_arg]) => { + (sym::unwrap_or_else, [u_arg]) => { match method_call(recv) { - Some(("map", recv, [map_arg], _, _)) + Some((sym::map, recv, [map_arg], _, _)) if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {}, - Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => { + Some((then_method @ (sym::then | sym::then_some), t_recv, [t_arg], _, _)) => { obfuscated_if_else::check( cx, expr, @@ -5463,7 +5478,7 @@ impl Methods { t_arg, Some(u_arg), then_method, - "unwrap_or_else", + sym::unwrap_or_else, ); }, _ => { @@ -5472,13 +5487,13 @@ impl Methods { } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, - ("wake", []) => { + (sym::wake, []) => { waker_clone_wake::check(cx, expr, recv); }, - ("write", []) => { + (sym::write, []) => { readonly_write_lock::check(cx, expr, recv); }, - ("zip", [arg]) => { + (sym::zip, [arg]) => { if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind && name.ident.name == sym::iter { @@ -5490,8 +5505,8 @@ impl Methods { } // Handle method calls whose receiver and arguments may come from expansion if let ExprKind::MethodCall(path, recv, args, _call_span) = expr.kind { - match (path.ident.name.as_str(), args) { - ("expect", [_]) if !matches!(method_call(recv), Some(("ok" | "err", _, [], _, _))) => { + match (path.ident.name, args) { + (sym::expect, [_]) if !matches!(method_call(recv), Some((sym::ok | sym::err, _, [], _, _))) => { unwrap_expect_used::check( cx, expr, @@ -5502,7 +5517,7 @@ impl Methods { unwrap_expect_used::Variant::Expect, ); }, - ("expect_err", [_]) => { + (sym::expect_err, [_]) => { unwrap_expect_used::check( cx, expr, @@ -5513,7 +5528,7 @@ impl Methods { unwrap_expect_used::Variant::Expect, ); }, - ("unwrap", []) => { + (sym::unwrap, []) => { unwrap_expect_used::check( cx, expr, @@ -5524,7 +5539,7 @@ impl Methods { unwrap_expect_used::Variant::Unwrap, ); }, - ("unwrap_err", []) => { + (sym::unwrap_err, []) => { unwrap_expect_used::check( cx, expr, @@ -5543,13 +5558,13 @@ impl Methods { fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, call_span: Span, is_some: bool) { match method_call(recv) { - Some((name @ ("find" | "position" | "rposition"), f_recv, [arg], span, _)) => { + Some((name @ (sym::find | sym::position | sym::rposition), f_recv, [arg], span, _)) => { search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span); }, - Some(("get", f_recv, [arg], _, _)) => { + Some((sym::get, f_recv, [arg], _, _)) => { unnecessary_get_then_check::check(cx, call_span, recv, f_recv, arg, is_some); }, - Some(("first", f_recv, [], _, _)) => { + Some((sym::first, f_recv, [], _, _)) => { unnecessary_first_then_check::check(cx, call_span, recv, f_recv, is_some); }, _ => {}, @@ -5593,7 +5608,7 @@ const FN_HEADER: hir::FnHeader = hir::FnHeader { struct ShouldImplTraitCase { trait_name: &'static str, - method_name: &'static str, + method_name: Symbol, param_count: usize, fn_header: hir::FnHeader, // implicit self kind expected (none, self, &self, ...) @@ -5606,7 +5621,7 @@ struct ShouldImplTraitCase { impl ShouldImplTraitCase { const fn new( trait_name: &'static str, - method_name: &'static str, + method_name: Symbol, param_count: usize, fn_header: hir::FnHeader, self_kind: SelfKind, @@ -5639,36 +5654,36 @@ impl ShouldImplTraitCase { #[rustfmt::skip] const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [ - ShouldImplTraitCase::new("std::ops::Add", "add", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::convert::AsMut", "as_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), - ShouldImplTraitCase::new("std::convert::AsRef", "as_ref", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true), - ShouldImplTraitCase::new("std::ops::BitAnd", "bitand", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::BitOr", "bitor", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::BitXor", "bitxor", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::borrow::Borrow", "borrow", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true), - ShouldImplTraitCase::new("std::borrow::BorrowMut", "borrow_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), - ShouldImplTraitCase::new("std::clone::Clone", "clone", 1, FN_HEADER, SelfKind::Ref, OutType::Any, true), - ShouldImplTraitCase::new("std::cmp::Ord", "cmp", 2, FN_HEADER, SelfKind::Ref, OutType::Any, true), - ShouldImplTraitCase::new("std::default::Default", "default", 0, FN_HEADER, SelfKind::No, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::Deref", "deref", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true), - ShouldImplTraitCase::new("std::ops::DerefMut", "deref_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), - ShouldImplTraitCase::new("std::ops::Div", "div", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::Drop", "drop", 1, FN_HEADER, SelfKind::RefMut, OutType::Unit, true), - ShouldImplTraitCase::new("std::cmp::PartialEq", "eq", 2, FN_HEADER, SelfKind::Ref, OutType::Bool, true), - ShouldImplTraitCase::new("std::iter::FromIterator", "from_iter", 1, FN_HEADER, SelfKind::No, OutType::Any, true), - ShouldImplTraitCase::new("std::str::FromStr", "from_str", 1, FN_HEADER, SelfKind::No, OutType::Any, true), - ShouldImplTraitCase::new("std::hash::Hash", "hash", 2, FN_HEADER, SelfKind::Ref, OutType::Unit, true), - ShouldImplTraitCase::new("std::ops::Index", "index", 2, FN_HEADER, SelfKind::Ref, OutType::Ref, true), - ShouldImplTraitCase::new("std::ops::IndexMut", "index_mut", 2, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), - ShouldImplTraitCase::new("std::iter::IntoIterator", "into_iter", 1, FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::Mul", "mul", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::Neg", "neg", 1, FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::iter::Iterator", "next", 1, FN_HEADER, SelfKind::RefMut, OutType::Any, false), - ShouldImplTraitCase::new("std::ops::Not", "not", 1, FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::Rem", "rem", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::Shl", "shl", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::Shr", "shr", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::Sub", "sub", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Add", sym::add, 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::convert::AsMut", sym::as_mut, 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), + ShouldImplTraitCase::new("std::convert::AsRef", sym::as_ref, 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true), + ShouldImplTraitCase::new("std::ops::BitAnd", sym::bitand, 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::BitOr", sym::bitor, 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::BitXor", sym::bitxor, 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::borrow::Borrow", sym::borrow, 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true), + ShouldImplTraitCase::new("std::borrow::BorrowMut", sym::borrow_mut, 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), + ShouldImplTraitCase::new("std::clone::Clone", sym::clone, 1, FN_HEADER, SelfKind::Ref, OutType::Any, true), + ShouldImplTraitCase::new("std::cmp::Ord", sym::cmp, 2, FN_HEADER, SelfKind::Ref, OutType::Any, true), + ShouldImplTraitCase::new("std::default::Default", kw::Default, 0, FN_HEADER, SelfKind::No, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Deref", sym::deref, 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true), + ShouldImplTraitCase::new("std::ops::DerefMut", sym::deref_mut, 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), + ShouldImplTraitCase::new("std::ops::Div", sym::div, 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Drop", sym::drop, 1, FN_HEADER, SelfKind::RefMut, OutType::Unit, true), + ShouldImplTraitCase::new("std::cmp::PartialEq", sym::eq, 2, FN_HEADER, SelfKind::Ref, OutType::Bool, true), + ShouldImplTraitCase::new("std::iter::FromIterator", sym::from_iter, 1, FN_HEADER, SelfKind::No, OutType::Any, true), + ShouldImplTraitCase::new("std::str::FromStr", sym::from_str, 1, FN_HEADER, SelfKind::No, OutType::Any, true), + ShouldImplTraitCase::new("std::hash::Hash", sym::hash, 2, FN_HEADER, SelfKind::Ref, OutType::Unit, true), + ShouldImplTraitCase::new("std::ops::Index", sym::index, 2, FN_HEADER, SelfKind::Ref, OutType::Ref, true), + ShouldImplTraitCase::new("std::ops::IndexMut", sym::index_mut, 2, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), + ShouldImplTraitCase::new("std::iter::IntoIterator", sym::into_iter, 1, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Mul", sym::mul, 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Neg", sym::neg, 1, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::iter::Iterator", sym::next, 1, FN_HEADER, SelfKind::RefMut, OutType::Any, false), + ShouldImplTraitCase::new("std::ops::Not", sym::not, 1, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Rem", sym::rem, 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Shl", sym::shl, 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Shr", sym::shr, 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Sub", sym::sub, 2, FN_HEADER, SelfKind::Value, OutType::Any, true), ]; #[derive(Clone, Copy, PartialEq, Eq, Debug)] diff --git a/clippy_lints/src/methods/needless_as_bytes.rs b/clippy_lints/src/methods/needless_as_bytes.rs index 7c9f7bae99063..635d06330e058 100644 --- a/clippy_lints/src/methods/needless_as_bytes.rs +++ b/clippy_lints/src/methods/needless_as_bytes.rs @@ -4,11 +4,11 @@ use clippy_utils::ty::is_type_lang_item; use rustc_errors::Applicability; use rustc_hir::{Expr, LangItem}; use rustc_lint::LateContext; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use super::NEEDLESS_AS_BYTES; -pub fn check(cx: &LateContext<'_>, prev_method: &str, method: &str, prev_recv: &Expr<'_>, span: Span) { +pub fn check(cx: &LateContext<'_>, prev_method: Symbol, method: Symbol, prev_recv: &Expr<'_>, span: Span) { let ty1 = cx.typeck_results().expr_ty_adjusted(prev_recv).peel_refs(); if is_type_lang_item(cx, ty1, LangItem::String) || ty1.is_str() { let mut app = Applicability::MachineApplicable; diff --git a/clippy_lints/src/methods/needless_option_as_deref.rs b/clippy_lints/src/methods/needless_option_as_deref.rs index 538aa9097a40f..d77d044340dca 100644 --- a/clippy_lints/src/methods/needless_option_as_deref.rs +++ b/clippy_lints/src/methods/needless_option_as_deref.rs @@ -1,22 +1,22 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::path_res; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::local_used_after_expr; +use clippy_utils::{path_res, sym}; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_hir::def::Res; use rustc_lint::LateContext; -use rustc_span::sym; +use rustc_span::Symbol; use super::NEEDLESS_OPTION_AS_DEREF; -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name: &str) { +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name: Symbol) { let typeck = cx.typeck_results(); let outer_ty = typeck.expr_ty(expr); if is_type_diagnostic_item(cx, outer_ty, sym::Option) && outer_ty == typeck.expr_ty(recv) { - if name == "as_deref_mut" && recv.is_syntactic_place_expr() { + if name == sym::as_deref_mut && recv.is_syntactic_place_expr() { let Res::Local(binding_id) = path_res(cx, recv) else { return; }; diff --git a/clippy_lints/src/methods/needless_option_take.rs b/clippy_lints/src/methods/needless_option_take.rs index cd1b97f3c51b5..1544a12e6ba83 100644 --- a/clippy_lints/src/methods/needless_option_take.rs +++ b/clippy_lints/src/methods/needless_option_take.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; -use rustc_span::sym; +use rustc_span::{Symbol, sym}; use super::NEEDLESS_OPTION_TAKE; @@ -42,20 +42,20 @@ fn is_expr_option(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// When this function is called, we are reasonably certain that the `ExprKind` is either /// `Call` or `MethodCall` because we already checked that the expression is not /// `is_syntactic_place_expr()`. -fn source_of_temporary_value<'a>(expr: &'a Expr<'_>) -> Option<&'a str> { +fn source_of_temporary_value(expr: &Expr<'_>) -> Option { match expr.peel_borrows().kind { ExprKind::Call(function, _) => { if let ExprKind::Path(QPath::Resolved(_, func_path)) = function.kind && !func_path.segments.is_empty() { - return Some(func_path.segments[0].ident.name.as_str()); + return Some(func_path.segments[0].ident.name); } if let ExprKind::Path(QPath::TypeRelative(_, func_path_segment)) = function.kind { - return Some(func_path_segment.ident.name.as_str()); + return Some(func_path_segment.ident.name); } None }, - ExprKind::MethodCall(path_segment, ..) => Some(path_segment.ident.name.as_str()), + ExprKind::MethodCall(path_segment, ..) => Some(path_segment.ident.name), _ => None, } } diff --git a/clippy_lints/src/methods/obfuscated_if_else.rs b/clippy_lints/src/methods/obfuscated_if_else.rs index 1cc56de48763e..604b48656aeac 100644 --- a/clippy_lints/src/methods/obfuscated_if_else.rs +++ b/clippy_lints/src/methods/obfuscated_if_else.rs @@ -1,13 +1,14 @@ use super::OBFUSCATED_IF_ELSE; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::eager_or_lazy::switch_to_eager_eval; -use clippy_utils::get_parent_expr; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; +use clippy_utils::{get_parent_expr, sym}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::ExprKind; use rustc_lint::LateContext; +use rustc_span::Symbol; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, @@ -15,8 +16,8 @@ pub(super) fn check<'tcx>( then_recv: &'tcx hir::Expr<'_>, then_arg: &'tcx hir::Expr<'_>, unwrap_arg: Option<&'tcx hir::Expr<'_>>, - then_method_name: &str, - unwrap_method_name: &str, + then_method_name: Symbol, + unwrap_method_name: Symbol, ) { let recv_ty = cx.typeck_results().expr_ty(then_recv); @@ -31,25 +32,25 @@ pub(super) fn check<'tcx>( }; let if_then = match then_method_name { - "then" if let ExprKind::Closure(closure) = then_arg.kind => { + sym::then if let ExprKind::Closure(closure) = then_arg.kind => { let body = cx.tcx.hir_body(closure.body); snippet_with_applicability(cx, body.value.span, "..", &mut applicability) }, - "then_some" => snippet_with_applicability(cx, then_arg.span, "..", &mut applicability), + sym::then_some => snippet_with_applicability(cx, then_arg.span, "..", &mut applicability), _ => return, }; // FIXME: Add `unwrap_or_else` and `unwrap_or_default` symbol let els = match unwrap_method_name { - "unwrap_or" => snippet_with_applicability(cx, unwrap_arg.unwrap().span, "..", &mut applicability), - "unwrap_or_else" if let ExprKind::Closure(closure) = unwrap_arg.unwrap().kind => { + sym::unwrap_or => snippet_with_applicability(cx, unwrap_arg.unwrap().span, "..", &mut applicability), + sym::unwrap_or_else if let ExprKind::Closure(closure) = unwrap_arg.unwrap().kind => { let body = cx.tcx.hir_body(closure.body); snippet_with_applicability(cx, body.value.span, "..", &mut applicability) }, - "unwrap_or_else" if let ExprKind::Path(_) = unwrap_arg.unwrap().kind => { + sym::unwrap_or_else if let ExprKind::Path(_) = unwrap_arg.unwrap().kind => { snippet_with_applicability(cx, unwrap_arg.unwrap().span, "_", &mut applicability) + "()" }, - "unwrap_or_default" => "Default::default()".into(), + sym::unwrap_or_default => "Default::default()".into(), _ => return, }; diff --git a/clippy_lints/src/methods/option_as_ref_cloned.rs b/clippy_lints/src/methods/option_as_ref_cloned.rs index 9b22494888fb2..3c38deca6cd1f 100644 --- a/clippy_lints/src/methods/option_as_ref_cloned.rs +++ b/clippy_lints/src/methods/option_as_ref_cloned.rs @@ -1,14 +1,16 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::sym; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_span::{Span, sym}; +use rustc_span::Span; use super::{OPTION_AS_REF_CLONED, method_call}; pub(super) fn check(cx: &LateContext<'_>, cloned_recv: &Expr<'_>, cloned_ident_span: Span) { - if let Some((method @ ("as_ref" | "as_mut"), as_ref_recv, [], as_ref_ident_span, _)) = method_call(cloned_recv) + if let Some((method @ (sym::as_ref | sym::as_mut), as_ref_recv, [], as_ref_ident_span, _)) = + method_call(cloned_recv) && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(as_ref_recv).peel_refs(), sym::Option) { span_lint_and_sugg( diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index b78b082e460ef..c74c42e9e5bd5 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_span: Span, - name: &str, + name: Symbol, receiver: &'tcx hir::Expr<'_>, args: &'tcx [hir::Expr<'_>], ) { @@ -33,7 +33,7 @@ pub(super) fn check<'tcx>( /// `or_insert_with(T::new)` or `or_insert_with(T::default)`. fn check_unwrap_or_default( cx: &LateContext<'_>, - name: &str, + name: Symbol, receiver: &hir::Expr<'_>, fun: &hir::Expr<'_>, call_expr: Option<&hir::Expr<'_>>, @@ -66,8 +66,8 @@ pub(super) fn check<'tcx>( }; let sugg = match (name, call_expr.is_some()) { - ("unwrap_or", true) | ("unwrap_or_else", false) => sym::unwrap_or_default, - ("or_insert", true) | ("or_insert_with", false) => sym::or_default, + (sym::unwrap_or, true) | (sym::unwrap_or_else, false) => sym::unwrap_or_default, + (sym::or_insert, true) | (sym::or_insert_with, false) => sym::or_default, _ => return false, }; @@ -126,7 +126,7 @@ pub(super) fn check<'tcx>( #[expect(clippy::too_many_arguments)] fn check_or_fn_call<'tcx>( cx: &LateContext<'tcx>, - name: &str, + name: Symbol, method_span: Span, self_expr: &hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, @@ -137,11 +137,16 @@ pub(super) fn check<'tcx>( fun_span: Option, ) -> bool { // (path, fn_has_argument, methods, suffix) - const KNOW_TYPES: [(Symbol, bool, &[&str], &str); 4] = [ - (sym::BTreeEntry, false, &["or_insert"], "with"), - (sym::HashMapEntry, false, &["or_insert"], "with"), - (sym::Option, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"), - (sym::Result, true, &["or", "unwrap_or"], "else"), + const KNOW_TYPES: [(Symbol, bool, &[Symbol], &str); 4] = [ + (sym::BTreeEntry, false, &[sym::or_insert], "with"), + (sym::HashMapEntry, false, &[sym::or_insert], "with"), + ( + sym::Option, + false, + &[sym::map_or, sym::ok_or, sym::or, sym::unwrap_or], + "else", + ), + (sym::Result, true, &[sym::or, sym::unwrap_or], "else"), ]; if KNOW_TYPES.iter().any(|k| k.2.contains(&name)) diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index 97c8ce2bcdd28..855babb797a21 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -2,14 +2,13 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::deref_closure_args; use clippy_utils::ty::is_type_lang_item; -use clippy_utils::{is_receiver_of_method_call, is_trait_method, strip_pat_refs}; +use clippy_utils::{is_receiver_of_method_call, is_trait_method, strip_pat_refs, sym}; use hir::ExprKind; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::PatKind; use rustc_lint::LateContext; -use rustc_span::Span; -use rustc_span::symbol::sym; +use rustc_span::{Span, Symbol}; use super::SEARCH_IS_SOME; @@ -19,7 +18,7 @@ use super::SEARCH_IS_SOME; pub(super) fn check<'tcx>( cx: &LateContext<'_>, expr: &'tcx hir::Expr<'_>, - search_method: &str, + search_method: Symbol, is_some: bool, search_recv: &hir::Expr<'_>, search_arg: &'tcx hir::Expr<'_>, @@ -35,7 +34,7 @@ pub(super) fn check<'tcx>( // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()` // suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()` let mut applicability = Applicability::MachineApplicable; - let any_search_snippet = if search_method == "find" + let any_search_snippet = if search_method == sym::find && let ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind && let closure_body = cx.tcx.hir_body(body) && let Some(closure_arg) = closure_body.params.first() @@ -107,7 +106,7 @@ pub(super) fn check<'tcx>( } } // lint if `find()` is called by `String` or `&str` - else if search_method == "find" { + else if search_method == sym::find { let is_string_or_str_slice = |e| { let self_ty = cx.typeck_results().expr_ty(e).peel_refs(); if is_type_lang_item(cx, self_ty, hir::LangItem::String) { diff --git a/clippy_lints/src/methods/str_split.rs b/clippy_lints/src/methods/str_split.rs index fb4ac7b3613dd..479064a0671e5 100644 --- a/clippy_lints/src/methods/str_split.rs +++ b/clippy_lints/src/methods/str_split.rs @@ -15,7 +15,7 @@ pub(super) fn check<'a>(cx: &LateContext<'a>, expr: &'_ Expr<'_>, split_recv: &' // or `"\r\n"`). There are a lot of ways to specify a pattern, and this lint only checks the most // basic ones: a `'\n'`, `"\n"`, and `"\r\n"`. if let ExprKind::MethodCall(trim_method_name, trim_recv, [], _) = split_recv.kind - && trim_method_name.ident.as_str() == "trim" + && trim_method_name.ident.name == sym::trim && cx.typeck_results().expr_ty_adjusted(trim_recv).peel_refs().is_str() && !is_const_evaluatable(cx, trim_recv) && let ExprKind::Lit(split_lit) = split_arg.kind diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index c8efb600f576f..6935ae1f391fa 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -4,7 +4,7 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use clippy_utils::usage::local_used_after_expr; use clippy_utils::visitors::{Descend, for_each_expr}; -use clippy_utils::{is_diag_item_method, path_to_local_id, paths}; +use clippy_utils::{is_diag_item_method, path_to_local_id, paths, sym}; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::{ @@ -12,13 +12,13 @@ use rustc_hir::{ }; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{Span, Symbol, SyntaxContext, sym}; +use rustc_span::{Span, Symbol, SyntaxContext}; use super::{MANUAL_SPLIT_ONCE, NEEDLESS_SPLITN}; pub(super) fn check( cx: &LateContext<'_>, - method_name: &str, + method_name: Symbol, expr: &Expr<'_>, self_arg: &Expr<'_>, pat_arg: &Expr<'_>, @@ -45,9 +45,9 @@ pub(super) fn check( } } -fn lint_needless(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_arg: &Expr<'_>, pat_arg: &Expr<'_>) { +fn lint_needless(cx: &LateContext<'_>, method_name: Symbol, expr: &Expr<'_>, self_arg: &Expr<'_>, pat_arg: &Expr<'_>) { let mut app = Applicability::MachineApplicable; - let r = if method_name == "splitn" { "" } else { "r" }; + let r = if method_name == sym::splitn { "" } else { "r" }; span_lint_and_sugg( cx, @@ -66,14 +66,14 @@ fn lint_needless(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_ fn check_manual_split_once( cx: &LateContext<'_>, - method_name: &str, + method_name: Symbol, expr: &Expr<'_>, self_arg: &Expr<'_>, pat_arg: &Expr<'_>, usage: &IterUsage, ) { let ctxt = expr.span.ctxt(); - let (msg, reverse) = if method_name == "splitn" { + let (msg, reverse) = if method_name == sym::splitn { ("manual implementation of `split_once`", false) } else { ("manual implementation of `rsplit_once`", true) @@ -121,7 +121,7 @@ fn check_manual_split_once( /// ``` fn check_manual_split_once_indirect( cx: &LateContext<'_>, - method_name: &str, + method_name: Symbol, expr: &Expr<'_>, self_arg: &Expr<'_>, pat_arg: &Expr<'_>, @@ -143,7 +143,7 @@ fn check_manual_split_once_indirect( && first.name != second.name && !local_used_after_expr(cx, iter_binding_id, second.init_expr) { - let (r, lhs, rhs) = if method_name == "splitn" { + let (r, lhs, rhs) = if method_name == sym::splitn { ("", first.name, second.name) } else { ("r", second.name, first.name) diff --git a/clippy_lints/src/methods/string_extend_chars.rs b/clippy_lints/src/methods/string_extend_chars.rs index c7885f689d75b..f11a41f90f1ab 100644 --- a/clippy_lints/src/methods/string_extend_chars.rs +++ b/clippy_lints/src/methods/string_extend_chars.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::method_chain_args; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_lang_item; +use clippy_utils::{method_chain_args, sym}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -13,7 +13,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr if !is_type_lang_item(cx, obj_ty, hir::LangItem::String) { return; } - if let Some(arglists) = method_chain_args(arg, &["chars"]) { + if let Some(arglists) = method_chain_args(arg, &[sym::chars]) { let target = &arglists[0].0; let self_ty = cx.typeck_results().expr_ty(target).peel_refs(); let ref_str = if self_ty.is_str() { diff --git a/clippy_lints/src/methods/suspicious_splitn.rs b/clippy_lints/src/methods/suspicious_splitn.rs index ff5c1d1a40193..f8b6d4349fbeb 100644 --- a/clippy_lints/src/methods/suspicious_splitn.rs +++ b/clippy_lints/src/methods/suspicious_splitn.rs @@ -2,11 +2,12 @@ use clippy_utils::diagnostics::span_lint_and_note; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; +use rustc_span::Symbol; use rustc_span::source_map::Spanned; use super::SUSPICIOUS_SPLITN; -pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_arg: &Expr<'_>, count: u128) { +pub(super) fn check(cx: &LateContext<'_>, method_name: Symbol, expr: &Expr<'_>, self_arg: &Expr<'_>, count: u128) { if count <= 1 && let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && let Some(impl_id) = cx.tcx.impl_of_method(call_id) diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index 79ed352193fd7..d260e0ef6e197 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -9,10 +9,16 @@ use rustc_hir as hir; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_lint::LateContext; use rustc_middle::ty; +use rustc_span::Symbol; use super::{UNNECESSARY_FILTER_MAP, UNNECESSARY_FIND_MAP}; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>, name: &str) { +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + arg: &'tcx hir::Expr<'tcx>, + name: Symbol, +) { if !is_trait_method(cx, expr, sym::Iterator) { return; } @@ -38,7 +44,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a let in_ty = cx.typeck_results().node_type(body.params[0].hir_id); let sugg = if !found_filtering { // Check if the closure is .filter_map(|x| Some(x)) - if name == "filter_map" + if name == sym::filter_map && let hir::ExprKind::Call(expr, args) = body.value.kind && is_res_lang_ctor(cx, path_res(cx, expr), OptionSome) && let hir::ExprKind::Path(_) = args[0].kind @@ -51,7 +57,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a ); return; } - if name == "filter_map" { + if name == sym::filter_map { "map(..)" } else { "map(..).next()" @@ -61,7 +67,11 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a ty::Adt(adt, subst) if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && in_ty == subst.type_at(0) => { - if name == "filter_map" { "filter(..)" } else { "find(..)" } + if name == sym::filter_map { + "filter(..)" + } else { + "find(..)" + } }, _ => return, } @@ -70,7 +80,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a }; span_lint( cx, - if name == "filter_map" { + if name == sym::filter_map { UNNECESSARY_FILTER_MAP } else { UNNECESSARY_FIND_MAP diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index fa3a29e366709..cc4448192d3e7 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -1,10 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{MaybePath, is_res_lang_ctor, last_path_segment, path_res}; +use clippy_utils::{MaybePath, is_res_lang_ctor, last_path_segment, path_res, sym}; use rustc_errors::Applicability; use rustc_hir::{self as hir, AmbigArg}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_middle::ty::print::with_forced_trimmed_paths; +use rustc_span::Symbol; use super::UNNECESSARY_LITERAL_UNWRAP; @@ -25,7 +26,7 @@ pub(super) fn check( cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, - method: &str, + method: Symbol, args: &[hir::Expr<'_>], ) { let init = clippy_utils::expr_or_init(cx, recv); @@ -42,17 +43,17 @@ pub(super) fn check( let res = cx.qpath_res(qpath, call.hir_id()); if is_res_lang_ctor(cx, res, hir::LangItem::OptionSome) { - ("Some", call_args, get_ty_from_args(args, 0)) + (sym::Some, call_args, get_ty_from_args(args, 0)) } else if is_res_lang_ctor(cx, res, hir::LangItem::ResultOk) { - ("Ok", call_args, get_ty_from_args(args, 0)) + (sym::Ok, call_args, get_ty_from_args(args, 0)) } else if is_res_lang_ctor(cx, res, hir::LangItem::ResultErr) { - ("Err", call_args, get_ty_from_args(args, 1)) + (sym::Err, call_args, get_ty_from_args(args, 1)) } else { return; } } else if is_res_lang_ctor(cx, path_res(cx, init), hir::LangItem::OptionNone) { let call_args: &[hir::Expr<'_>] = &[]; - ("None", call_args, None) + (sym::None, call_args, None) } else { return; }; @@ -62,12 +63,12 @@ pub(super) fn check( span_lint_and_then(cx, UNNECESSARY_LITERAL_UNWRAP, expr.span, help_message, |diag| { let suggestions = match (constructor, method, ty) { - ("None", "unwrap", _) => Some(vec![(expr.span, "panic!()".to_string())]), - ("None", "expect", _) => Some(vec![ + (sym::None, sym::unwrap, _) => Some(vec![(expr.span, "panic!()".to_string())]), + (sym::None, sym::expect, _) => Some(vec![ (expr.span.with_hi(args[0].span.lo()), "panic!(".to_string()), (expr.span.with_lo(args[0].span.hi()), ")".to_string()), ]), - ("Some" | "Ok", "unwrap_unchecked", _) | ("Err", "unwrap_err_unchecked", _) => { + (sym::Some | sym::Ok, sym::unwrap_unchecked, _) | (sym::Err, sym::unwrap_err_unchecked, _) => { let mut suggs = vec![ (recv.span.with_hi(call_args[0].span.lo()), String::new()), (expr.span.with_lo(call_args[0].span.hi()), String::new()), @@ -83,7 +84,7 @@ pub(super) fn check( } Some(suggs) }, - ("None", "unwrap_or_default", _) => { + (sym::None, sym::unwrap_or_default, _) => { let ty = cx.typeck_results().expr_ty(expr); let default_ty_string = if let ty::Adt(def, ..) = ty.kind() { with_forced_trimmed_paths!(format!("{}", cx.tcx.def_path_str(def.did()))) @@ -92,11 +93,11 @@ pub(super) fn check( }; Some(vec![(expr.span, format!("{default_ty_string}::default()"))]) }, - ("None", "unwrap_or", _) => Some(vec![ + (sym::None, sym::unwrap_or, _) => Some(vec![ (expr.span.with_hi(args[0].span.lo()), String::new()), (expr.span.with_lo(args[0].span.hi()), String::new()), ]), - ("None", "unwrap_or_else", _) => match args[0].kind { + (sym::None, sym::unwrap_or_else, _) => match args[0].kind { hir::ExprKind::Closure(hir::Closure { body, .. }) => Some(vec![ (expr.span.with_hi(cx.tcx.hir_body(*body).value.span.lo()), String::new()), (expr.span.with_lo(args[0].span.hi()), String::new()), @@ -105,14 +106,14 @@ pub(super) fn check( }, _ if call_args.is_empty() => None, (_, _, Some(_)) => None, - ("Ok", "unwrap_err", None) | ("Err", "unwrap", None) => Some(vec![ + (sym::Ok, sym::unwrap_err, None) | (sym::Err, sym::unwrap, None) => Some(vec![ ( recv.span.with_hi(call_args[0].span.lo()), "panic!(\"{:?}\", ".to_string(), ), (expr.span.with_lo(call_args[0].span.hi()), ")".to_string()), ]), - ("Ok", "expect_err", None) | ("Err", "expect", None) => Some(vec![ + (sym::Ok, sym::expect_err, None) | (sym::Err, sym::expect, None) => Some(vec![ ( recv.span.with_hi(call_args[0].span.lo()), "panic!(\"{1}: {:?}\", ".to_string(), diff --git a/clippy_lints/src/methods/unnecessary_min_or_max.rs b/clippy_lints/src/methods/unnecessary_min_or_max.rs index 7d01bdc2269bd..413881d5ec99e 100644 --- a/clippy_lints/src/methods/unnecessary_min_or_max.rs +++ b/clippy_lints/src/methods/unnecessary_min_or_max.rs @@ -5,16 +5,17 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant, ConstantSource, FullInt}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; +use clippy_utils::sym; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{Span, sym}; +use rustc_span::{Span, Symbol}; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, - name: &str, + name: Symbol, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>, ) { @@ -47,10 +48,10 @@ pub(super) fn check<'tcx>( } } -fn lint(cx: &LateContext<'_>, expr: &Expr<'_>, name: &str, lhs: Span, rhs: Span, order: Ordering) { +fn lint(cx: &LateContext<'_>, expr: &Expr<'_>, name: Symbol, lhs: Span, rhs: Span, order: Ordering) { let cmp_str = if order.is_ge() { "smaller" } else { "greater" }; - let suggested_value = if (name == "min" && order.is_ge()) || (name == "max" && order.is_le()) { + let suggested_value = if (name == sym::min && order.is_ge()) || (name == sym::max && order.is_le()) { snippet(cx, rhs, "..") } else { snippet(cx, lhs, "..") diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 87bb8d46a1d6a..29a0d2950bc6a 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -619,7 +619,7 @@ fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id: /// Returns true if the named method can be used to convert the receiver to its "owned" /// representation. fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name: Symbol, method_def_id: DefId) -> bool { - is_clone_like(cx, method_name.as_str(), method_def_id) + is_clone_like(cx, method_name, method_def_id) || is_cow_into_owned(cx, method_name, method_def_id) || is_to_string_on_string_like(cx, call_expr, method_name, method_def_id) } @@ -655,11 +655,18 @@ fn is_to_string_on_string_like<'a>( } } -fn is_a_std_map_type(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - is_type_diagnostic_item(cx, ty, sym::HashSet) - || is_type_diagnostic_item(cx, ty, sym::HashMap) - || is_type_diagnostic_item(cx, ty, sym::BTreeMap) - || is_type_diagnostic_item(cx, ty, sym::BTreeSet) +fn std_map_key<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { + match ty.kind() { + ty::Adt(adt, args) + if matches!( + cx.tcx.get_diagnostic_name(adt.did()), + Some(sym::BTreeMap | sym::BTreeSet | sym::HashMap | sym::HashSet) + ) => + { + Some(args.type_at(0)) + }, + _ => None, + } } fn is_str_and_string(cx: &LateContext<'_>, arg_ty: Ty<'_>, original_arg_ty: Ty<'_>) -> bool { @@ -679,11 +686,11 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, expr) = arg.kind && let ExprKind::MethodCall(method_path, caller, &[], _) = expr.kind && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) - && let method_name = method_path.ident.name.as_str() + && let method_name = method_path.ident.name && match method_name { - "to_owned" => cx.tcx.is_diagnostic_item(sym::to_owned_method, method_def_id), - "to_string" => cx.tcx.is_diagnostic_item(sym::to_string_method, method_def_id), - "to_vec" => cx + sym::to_owned => cx.tcx.is_diagnostic_item(sym::to_owned_method, method_def_id), + sym::to_string => cx.tcx.is_diagnostic_item(sym::to_string_method, method_def_id), + sym::to_vec => cx .tcx .impl_of_method(method_def_id) .filter(|&impl_did| cx.tcx.type_of(impl_did).instantiate_identity().is_slice()) @@ -721,6 +728,7 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx // 1. This is a method with only one argument that doesn't come from a trait. // 2. That it has `Borrow` in its generic predicates. // 3. `Self` is a std "map type" (ie `HashSet`, `HashMap`, `BTreeSet`, `BTreeMap`). +// 4. The key to the "map type" is not a reference. fn check_borrow_predicate<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { if let ExprKind::MethodCall(_, caller, &[arg], _) = expr.kind && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) @@ -738,7 +746,9 @@ fn check_borrow_predicate<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { }) && let caller_ty = cx.typeck_results().expr_ty(caller) // For now we limit it to "map types". - && is_a_std_map_type(cx, caller_ty) + && let Some(key_ty) = std_map_key(cx, caller_ty) + // We need to check that the key type is not a reference. + && !key_ty.is_ref() { check_if_applicable_to_argument(cx, &arg); } diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs index 17e2620d9dd47..d30c12e0c4830 100644 --- a/clippy_lints/src/methods/useless_asref.rs +++ b/clippy_lints/src/methods/useless_asref.rs @@ -7,7 +7,7 @@ use rustc_hir::{self as hir, LangItem}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use rustc_span::{Span, sym}; +use rustc_span::{Span, Symbol, sym}; use core::ops::ControlFlow; @@ -39,7 +39,7 @@ fn get_enum_ty(enum_ty: Ty<'_>) -> Option> { } /// Checks for the `USELESS_ASREF` lint. -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, recvr: &hir::Expr<'_>) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: Symbol, recvr: &hir::Expr<'_>) { // when we get here, we've already checked that the call name is "as_ref" or "as_mut" // check if the call is to the actual `AsRef` or `AsMut` trait let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) else { @@ -79,9 +79,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, applicability, ); } - } else if let Some(impl_id) = cx.tcx.opt_parent(def_id) + } else if let Some(impl_id) = cx.tcx.impl_of_method(def_id) && let Some(adt) = cx.tcx.type_of(impl_id).instantiate_identity().ty_adt_def() - && (cx.tcx.lang_items().option_type() == Some(adt.did()) || cx.tcx.is_diagnostic_item(sym::Result, adt.did())) + && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::Option | sym::Result)) { let rcv_ty = cx.typeck_results().expr_ty(recvr).peel_refs(); let res_ty = cx.typeck_results().expr_ty(expr).peel_refs(); @@ -161,7 +161,7 @@ fn is_calling_clone(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool { } } -fn lint_as_ref_clone(cx: &LateContext<'_>, span: Span, recvr: &hir::Expr<'_>, call_name: &str) { +fn lint_as_ref_clone(cx: &LateContext<'_>, span: Span, recvr: &hir::Expr<'_>, call_name: Symbol) { let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/wrong_self_convention.rs b/clippy_lints/src/methods/wrong_self_convention.rs index 7384e534ed7d7..ad9b3c3645425 100644 --- a/clippy_lints/src/methods/wrong_self_convention.rs +++ b/clippy_lints/src/methods/wrong_self_convention.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::is_copy; use rustc_lint::LateContext; use rustc_middle::ty::Ty; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use std::fmt; use super::WRONG_SELF_CONVENTION; @@ -83,17 +83,18 @@ impl fmt::Display for Convention { #[allow(clippy::too_many_arguments)] pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, - item_name: &str, + item_name: Symbol, self_ty: Ty<'tcx>, first_arg_ty: Ty<'tcx>, first_arg_span: Span, implements_trait: bool, is_trait_item: bool, ) { + let item_name_str = item_name.as_str(); if let Some((conventions, self_kinds)) = &CONVENTIONS.iter().find(|(convs, _)| { convs .iter() - .all(|conv| conv.check(cx, self_ty, item_name, implements_trait, is_trait_item)) + .all(|conv| conv.check(cx, self_ty, item_name_str, implements_trait, is_trait_item)) }) { // don't lint if it implements a trait but not willing to check `Copy` types conventions (see #7032) if implements_trait diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index f3e24044fb6c2..a6be7581c9a38 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -7,7 +7,7 @@ use rustc_abi::ExternAbi; use rustc_errors::Applicability; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_hir::intravisit::FnKind; -use rustc_hir::{self as hir, Body, Constness, FnDecl, GenericParamKind}; +use rustc_hir::{self as hir, Body, Constness, FnDecl, GenericParamKind, OwnerId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; @@ -125,7 +125,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { } }, FnKind::Method(_, sig, ..) => { - if already_const(sig.header) || trait_ref_of_method(cx, def_id).is_some() { + if already_const(sig.header) || trait_ref_of_method(cx, OwnerId { def_id }).is_some() { return; } }, diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index a45031ce22b91..98a9a98d281af 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -83,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType<'tcx> { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'tcx>) { if let hir::ImplItemKind::Fn(ref sig, ..) = item.kind - && trait_ref_of_method(cx, item.owner_id.def_id).is_none() + && trait_ref_of_method(cx, item.owner_id).is_none() { self.check_sig(cx, item.owner_id.def_id, sig.decl); } diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index f768e11a4a2bb..3ed4b1c2ea947 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use clippy_utils::{ SpanlessEq, get_parent_expr, higher, is_block_like, is_else_clause, is_expn_of, is_parent_stmt, - is_receiver_of_method_call, peel_blocks, peel_blocks_with_stmt, span_extract_comment, + is_receiver_of_method_call, peel_blocks, peel_blocks_with_stmt, span_extract_comment, sym, }; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -320,7 +320,7 @@ fn check_comparison<'a, 'tcx>( cx.typeck_results().expr_ty(left_side), cx.typeck_results().expr_ty(right_side), ); - if is_expn_of(left_side.span, "cfg").is_some() || is_expn_of(right_side.span, "cfg").is_some() { + if is_expn_of(left_side.span, sym::cfg).is_some() || is_expn_of(right_side.span, sym::cfg).is_some() { return; } if l_ty.is_bool() && r_ty.is_bool() { diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 275d710c76a9b..95623467b8153 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -212,7 +212,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { } if is_type_diagnostic_item(cx, ty, sym::Vec) - && let Some(clone_spans) = get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")]) + && let Some(clone_spans) = get_spans(cx, Some(body.id()), idx, &[(sym::clone, ".to_owned()")]) && let TyKind::Path(QPath::Resolved(_, path)) = input.kind && let Some(elem_ty) = path .segments @@ -253,8 +253,12 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { } if is_type_lang_item(cx, ty, LangItem::String) - && let Some(clone_spans) = - get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")]) + && let Some(clone_spans) = get_spans( + cx, + Some(body.id()), + idx, + &[(sym::clone, ".to_string()"), (sym::as_str, "")], + ) { diag.span_suggestion( input.span, diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 7ab7976d5697a..02c48166131ef 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -221,10 +221,16 @@ fn is_operator_overridden(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } } +/// Checks if dropping `expr` might have a visible side effect. +fn expr_ty_has_significant_drop(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + let ty = cx.typeck_results().expr_ty(expr); + ty.has_significant_drop(cx.tcx, cx.typing_env()) +} + fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { match expr.kind { ExprKind::Lit(..) | ExprKind::Closure { .. } => true, - ExprKind::Path(..) => !has_drop(cx, cx.typeck_results().expr_ty(expr)), + ExprKind::Path(..) => !expr_ty_has_significant_drop(cx, expr), ExprKind::Index(a, b, _) | ExprKind::Binary(_, a, b) => has_no_effect(cx, a) && has_no_effect(cx, b), ExprKind::Array(v) | ExprKind::Tup(v) => v.iter().all(|val| has_no_effect(cx, val)), ExprKind::Repeat(inner, _) @@ -233,8 +239,8 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { | ExprKind::Unary(_, inner) | ExprKind::Field(inner, _) | ExprKind::AddrOf(_, _, inner) => has_no_effect(cx, inner), - ExprKind::Struct(_, fields, ref base) => { - !has_drop(cx, cx.typeck_results().expr_ty(expr)) + ExprKind::Struct(_, fields, base) => { + !expr_ty_has_significant_drop(cx, expr) && fields.iter().all(|field| has_no_effect(cx, field.expr)) && match &base { StructTailExpr::None | StructTailExpr::DefaultFields(_) => true, @@ -252,7 +258,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..) ); if def_matched || is_range_literal(expr) { - !has_drop(cx, cx.typeck_results().expr_ty(expr)) && args.iter().all(|arg| has_no_effect(cx, arg)) + !expr_ty_has_significant_drop(cx, expr) && args.iter().all(|arg| has_no_effect(cx, arg)) } else { false } diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 6d3e77b6b6e97..a27c6aa75e369 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -1,56 +1,78 @@ -use std::ptr; +// Implementation for lints detecting interior mutability in constants. +// +// For `declare_interior_mutable_const` there are three strategies used to +// determine if a value has interior mutability: +// * A type-based check. This is the least accurate, but can always run. +// * A const-eval based check. This is the most accurate, but this requires that the value is +// defined and does not work with generics. +// * A HIR-tree based check. This is less accurate than const-eval, but it can be applied to generic +// values. +// +// For `borrow_interior_mutable_const` the same three strategies are applied +// when checking a constant's value, but field and array index projections at +// the borrow site are taken into account as well. As an example: `FOO.bar` may +// have interior mutability, but `FOO.baz` may not. When borrowing `FOO.baz` no +// warning will be issued. +// +// No matter the lint or strategy, a warning should only be issued if a value +// definitely contains interior mutability. use clippy_config::Conf; -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::consts::{ConstEvalCtxt, Constant}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::is_in_const_context; use clippy_utils::macros::macro_backtrace; -use clippy_utils::ty::{InteriorMut, implements_trait}; -use rustc_abi::VariantIdx; +use clippy_utils::paths::{PathNS, lookup_path_str}; +use clippy_utils::ty::{get_field_idx_by_name, implements_trait}; +use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_hir::{ - BodyId, Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp, + Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Node, StructTailExpr, TraitItem, TraitItemKind, UnOp, +}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::mir::{ConstValue, UnevaluatedConst}; +use rustc_middle::ty::adjustment::{Adjust, Adjustment}; +use rustc_middle::ty::{ + self, AliasTyKind, EarlyBinder, GenericArgs, GenericArgsRef, Instance, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, + TypeckResults, TypingEnv, }; -use rustc_lint::{LateContext, LateLintPass, Lint}; -use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId, ReportedErrorInfo}; -use rustc_middle::ty::adjustment::Adjust; -use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::impl_lint_pass; -use rustc_span::{DUMMY_SP, Span, sym}; +use rustc_span::{DUMMY_SP, sym}; +use std::collections::hash_map::Entry; -// FIXME: this is a correctness problem but there's no suitable -// warn-by-default category. declare_clippy_lint! { /// ### What it does - /// Checks for declaration of `const` items which is interior - /// mutable (e.g., contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.). + /// Checks for the declaration of named constant which contain interior mutability. /// /// ### Why is this bad? - /// Consts are copied everywhere they are referenced, i.e., - /// every time you refer to the const a fresh instance of the `Cell` or `Mutex` - /// or `AtomicXxxx` will be created, which defeats the whole purpose of using - /// these types in the first place. + /// Named constants are copied at every use site which means any change to their value + /// will be lost after the newly created value is dropped. e.g. /// - /// The `const` should better be replaced by a `static` item if a global - /// variable is wanted, or replaced by a `const fn` if a constructor is wanted. + /// ```rust + /// use core::sync::atomic::{AtomicUsize, Ordering}; + /// const ATOMIC: AtomicUsize = AtomicUsize::new(0); + /// fn add_one() -> usize { + /// // This will always return `0` since `ATOMIC` is copied before it's used. + /// ATOMIC.fetch_add(1, Ordering::AcqRel) + /// } + /// ``` /// - /// ### Known problems - /// A "non-constant" const item is a legacy way to supply an - /// initialized value to downstream `static` items (e.g., the - /// `std::sync::ONCE_INIT` constant). In this case the use of `const` is legit, - /// and this lint should be suppressed. + /// If shared modification of the value is desired, a `static` item is needed instead. + /// If that is not desired, a `const fn` constructor should be used to make it obvious + /// at the use site that a new value is created. /// - /// Even though the lint avoids triggering on a constant whose type has enums that have variants - /// with interior mutability, and its value uses non interior mutable variants (see - /// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962) and - /// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825) for examples); - /// it complains about associated constants without default values only based on its types; - /// which might not be preferable. - /// There're other enums plus associated constants cases that the lint cannot handle. + /// ### Known problems + /// Prior to `const fn` stabilization this was the only way to provide a value which + /// could initialize a `static` item (e.g. the `std::sync::ONCE_INIT` constant). In + /// this case the use of `const` is required and this lint should be suppressed. /// - /// Types that have underlying or potential interior mutability trigger the lint whether - /// the interior mutable field is used or not. See issue - /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) + /// There also exists types which contain private fields with interior mutability, but + /// no way to both create a value as a constant and modify any mutable field using the + /// type's public interface (e.g. `bytes::Bytes`). As there is no reasonable way to + /// scan a crate's interface to see if this is the case, all such types will be linted. + /// If this happens use the `ignore-interior-mutability` configuration option to allow + /// the type. /// /// ### Example /// ```no_run @@ -74,20 +96,44 @@ declare_clippy_lint! { "declaring `const` with interior mutability" } -// FIXME: this is a correctness problem but there's no suitable -// warn-by-default category. declare_clippy_lint! { /// ### What it does - /// Checks if `const` items which is interior mutable (e.g., - /// contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.) has been borrowed directly. + /// Checks for a borrow of a named constant with interior mutability. /// /// ### Why is this bad? - /// Consts are copied everywhere they are referenced, i.e., - /// every time you refer to the const a fresh instance of the `Cell` or `Mutex` - /// or `AtomicXxxx` will be created, which defeats the whole purpose of using - /// these types in the first place. + /// Named constants are copied at every use site which means any change to their value + /// will be lost after the newly created value is dropped. e.g. + /// + /// ```rust + /// use core::sync::atomic::{AtomicUsize, Ordering}; + /// const ATOMIC: AtomicUsize = AtomicUsize::new(0); + /// fn add_one() -> usize { + /// // This will always return `0` since `ATOMIC` is copied before it's borrowed + /// // for use by `fetch_add`. + /// ATOMIC.fetch_add(1, Ordering::AcqRel) + /// } + /// ``` /// - /// The `const` value should be stored inside a `static` item. + /// ### Known problems + /// This lint does not, and cannot in general, determine if the borrow of the constant + /// is used in a way which causes a mutation. e.g. + /// + /// ```rust + /// use core::cell::Cell; + /// const CELL: Cell = Cell::new(0); + /// fn get_cell() -> Cell { + /// // This is fine. It borrows a copy of `CELL`, but never mutates it through the + /// // borrow. + /// CELL.clone() + /// } + /// ``` + /// + /// There also exists types which contain private fields with interior mutability, but + /// no way to both create a value as a constant and modify any mutable field using the + /// type's public interface (e.g. `bytes::Bytes`). As there is no reasonable way to + /// scan a crate's interface to see if this is the case, all such types will be linted. + /// If this happens use the `ignore-interior-mutability` configuration option to allow + /// the type. /// /// ### Example /// ```no_run @@ -113,60 +159,101 @@ declare_clippy_lint! { "referencing `const` with interior mutability" } -#[derive(Copy, Clone)] -enum Source<'tcx> { - Item { item: Span, ty: Ty<'tcx> }, - Assoc { item: Span }, - Expr { expr: Span }, +#[derive(Clone, Copy)] +enum IsFreeze { + /// The type and all possible values are `Freeze` + Yes, + /// The type itself is non-`Freeze`, but not all values are. + Maybe, + /// The type and all possible values are non-`Freeze` + No, } +impl IsFreeze { + /// Merges the variants of a sum type (i.e. an enum). + fn from_variants(iter: impl Iterator) -> Self { + iter.fold(Self::Yes, |x, y| match (x, y) { + (Self::Maybe, _) | (_, Self::Maybe) | (Self::No, Self::Yes) | (Self::Yes, Self::No) => Self::Maybe, + (Self::No, Self::No) => Self::No, + (Self::Yes, Self::Yes) => Self::Yes, + }) + } -impl Source<'_> { - #[must_use] - fn lint(&self) -> (&'static Lint, &'static str, Span) { - match self { - Self::Item { item, .. } | Self::Assoc { item, .. } => ( - DECLARE_INTERIOR_MUTABLE_CONST, - "a `const` item should not be interior mutable", - *item, - ), - Self::Expr { expr } => ( - BORROW_INTERIOR_MUTABLE_CONST, - "a `const` item with interior mutability should not be borrowed", - *expr, - ), - } + /// Merges the fields of a product type (e.g. a struct or tuple). + fn from_fields(mut iter: impl Iterator) -> Self { + iter.try_fold(Self::Yes, |x, y| match (x, y) { + (Self::No, _) | (_, Self::No) => None, + (Self::Maybe, _) | (_, Self::Maybe) => Some(Self::Maybe), + (Self::Yes, Self::Yes) => Some(Self::Yes), + }) + .unwrap_or(Self::No) + } + + /// Checks if this is definitely `Freeze`. + fn is_freeze(self) -> bool { + matches!(self, Self::Yes) + } + + /// Checks if this is definitely not `Freeze`. + fn is_not_freeze(self) -> bool { + matches!(self, Self::No) } } -fn lint<'tcx>(cx: &LateContext<'tcx>, source: Source<'tcx>) { - let (lint, msg, span) = source.lint(); - span_lint_and_then(cx, lint, span, msg, |diag| { - if span.from_expansion() { - return; // Don't give suggestions into macros. - } - match source { - Source::Item { ty, .. } => { - let Some(sync_trait) = cx.tcx.lang_items().sync_trait() else { - return; - }; - if implements_trait(cx, ty, sync_trait, &[]) { - diag.help("consider making this a static item"); - } else { - diag.help( - "consider making this `Sync` so that it can go in a static item or using a `thread_local`", - ); - } - }, - Source::Assoc { .. } => (), - Source::Expr { .. } => { - diag.help("assign this const to a local or static variable, and use the variable here"); +/// What operation caused a borrow to occur. +#[derive(Clone, Copy)] +enum BorrowCause { + Borrow, + Deref, + Index, + AutoDeref, + AutoBorrow, + AutoDerefField, +} +impl BorrowCause { + fn note(self) -> Option<&'static str> { + match self { + Self::Borrow => None, + Self::Deref => Some("this deref expression is a call to `Deref::deref`"), + Self::Index => Some("this index expression is a call to `Index::index`"), + Self::AutoDeref => Some("there is a compiler inserted call to `Deref::deref` here"), + Self::AutoBorrow => Some("there is a compiler inserted borrow here"), + Self::AutoDerefField => { + Some("there is a compiler inserted call to `Deref::deref` when accessing this field") }, } - }); + } +} + +/// The source of a borrow. Both what caused it and where. +struct BorrowSource<'tcx> { + expr: &'tcx Expr<'tcx>, + cause: BorrowCause, +} +impl<'tcx> BorrowSource<'tcx> { + fn new(tcx: TyCtxt<'tcx>, expr: &'tcx Expr<'tcx>, cause: BorrowCause) -> Self { + // Custom deref and index impls will always have an auto-borrow inserted since we + // never work with reference types. + let (expr, cause) = if matches!(cause, BorrowCause::AutoBorrow) + && let Node::Expr(parent) = tcx.parent_hir_node(expr.hir_id) + { + match parent.kind { + ExprKind::Unary(UnOp::Deref, _) => (parent, BorrowCause::Deref), + ExprKind::Index(..) => (parent, BorrowCause::Index), + ExprKind::Field(..) => (parent, BorrowCause::AutoDerefField), + _ => (expr, cause), + } + } else { + (expr, cause) + }; + Self { expr, cause } + } } pub struct NonCopyConst<'tcx> { - interior_mut: InteriorMut<'tcx>, + ignore_tys: DefIdSet, + // Cache checked types. We can recurse through a type multiple times so this + // can be hit quite frequently. + freeze_tys: FxHashMap, IsFreeze>, } impl_lint_pass!(NonCopyConst<'_> => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]); @@ -174,332 +261,629 @@ impl_lint_pass!(NonCopyConst<'_> => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTE impl<'tcx> NonCopyConst<'tcx> { pub fn new(tcx: TyCtxt<'tcx>, conf: &'static Conf) -> Self { Self { - interior_mut: InteriorMut::without_pointers(tcx, &conf.ignore_interior_mutability), + ignore_tys: conf + .ignore_interior_mutability + .iter() + .flat_map(|ignored_ty| lookup_path_str(tcx, PathNS::Type, ignored_ty)) + .collect(), + freeze_tys: FxHashMap::default(), } } - fn is_value_unfrozen_raw_inner(cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool { - // No branch that we check (yet) should continue if val isn't a branch - let Some(branched_val) = val.try_to_branch() else { - return false; - }; - match *ty.kind() { - // the fact that we have to dig into every structs to search enums - // leads us to the point checking `UnsafeCell` directly is the only option. - ty::Adt(ty_def, ..) if ty_def.is_unsafe_cell() => true, - // As of 2022-09-08 miri doesn't track which union field is active so there's no safe way to check the - // contained value. - ty::Adt(def, ..) if def.is_union() => false, - ty::Array(ty, _) => branched_val - .iter() - .any(|field| Self::is_value_unfrozen_raw_inner(cx, *field, ty)), - ty::Adt(def, args) if def.is_enum() => { - let Some((&variant_valtree, fields)) = branched_val.split_first() else { - return false; - }; - let variant_index = variant_valtree.unwrap_leaf(); - let variant_index = VariantIdx::from_u32(variant_index.to_u32()); - fields - .iter() - .copied() - .zip( - def.variants()[variant_index] + /// Checks if a value of the given type is `Freeze`, or may be depending on the value. + fn is_ty_freeze(&mut self, tcx: TyCtxt<'tcx>, typing_env: TypingEnv<'tcx>, ty: Ty<'tcx>) -> IsFreeze { + let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty); + match self.freeze_tys.entry(ty) { + Entry::Occupied(e) => *e.get(), + Entry::Vacant(e) => { + let e = e.insert(IsFreeze::Yes); + if ty.is_freeze(tcx, typing_env) { + return IsFreeze::Yes; + } + let is_freeze = match *ty.kind() { + ty::Adt(adt, _) if adt.is_unsafe_cell() => { + *e = IsFreeze::No; + return IsFreeze::No; + }, + ty::Adt(adt, _) if self.ignore_tys.contains(&adt.did()) => return IsFreeze::Yes, + ty::Adt(adt, args) if adt.is_enum() => IsFreeze::from_variants(adt.variants().iter().map(|v| { + IsFreeze::from_fields( + v.fields + .iter() + .map(|f| self.is_ty_freeze(tcx, typing_env, f.ty(tcx, args))), + ) + })), + // Workaround for `ManuallyDrop`-like unions. + ty::Adt(adt, args) + if adt.is_union() + && adt.non_enum_variant().fields.iter().any(|f| { + tcx.layout_of(typing_env.as_query_input(f.ty(tcx, args))) + .is_ok_and(|l| l.layout.size().bytes() == 0) + }) => + { + return IsFreeze::Yes; + }, + // Rust doesn't have the concept of an active union field so we have + // to treat all fields as active. + ty::Adt(adt, args) => IsFreeze::from_fields( + adt.non_enum_variant() .fields .iter() - .map(|field| field.ty(cx.tcx, args)), - ) - .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, field, ty)) - }, - ty::Adt(def, args) => branched_val - .iter() - .zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, args))) - .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)), - ty::Tuple(tys) => branched_val - .iter() - .zip(tys) - .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)), - ty::Alias(ty::Projection, _) => match cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty) { - Ok(normalized_ty) if ty != normalized_ty => Self::is_value_unfrozen_raw_inner(cx, val, normalized_ty), - _ => false, + .map(|f| self.is_ty_freeze(tcx, typing_env, f.ty(tcx, args))), + ), + ty::Array(ty, _) | ty::Pat(ty, _) => self.is_ty_freeze(tcx, typing_env, ty), + ty::Tuple(tys) => { + IsFreeze::from_fields(tys.iter().map(|ty| self.is_ty_freeze(tcx, typing_env, ty))) + }, + // Treat type parameters as though they were `Freeze`. + ty::Param(_) | ty::Alias(..) => return IsFreeze::Yes, + // TODO: check other types. + _ => { + *e = IsFreeze::No; + return IsFreeze::No; + }, + }; + if !is_freeze.is_freeze() { + self.freeze_tys.insert(ty, is_freeze); + } + is_freeze }, - _ => false, } } - fn is_value_unfrozen_raw( - cx: &LateContext<'tcx>, - result: Result, Ty<'tcx>>, ErrorHandled>, + /// Checks if the given constant value is `Freeze`. Returns `Err` if the constant + /// cannot be read, but the result depends on the value. + fn is_value_freeze( + &mut self, + tcx: TyCtxt<'tcx>, + typing_env: TypingEnv<'tcx>, ty: Ty<'tcx>, - ) -> bool { - result.map_or_else( - |err| { - // Consider `TooGeneric` cases as being unfrozen. - // This causes a false positive where an assoc const whose type is unfrozen - // have a value that is a frozen variant with a generic param (an example is - // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::GENERIC_VARIANT`). - // However, it prevents a number of false negatives that is, I think, important: - // 1. assoc consts in trait defs referring to consts of themselves (an example is - // `declare_interior_mutable_const::traits::ConcreteTypes::ANOTHER_ATOMIC`). - // 2. a path expr referring to assoc consts whose type is doesn't have any frozen variants in trait - // defs (i.e. without substitute for `Self`). (e.g. borrowing - // `borrow_interior_mutable_const::trait::ConcreteTypes::ATOMIC`) - // 3. similar to the false positive above; but the value is an unfrozen variant, or the type has no - // enums. (An example is - // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::UNFROZEN_VARIANT` and - // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::NO_ENUM`). - // One might be able to prevent these FNs correctly, and replace this with `false`; - // e.g. implementing `has_frozen_variant` described above, and not running this function - // when the type doesn't have any frozen variants would be the 'correct' way for the 2nd - // case (that actually removes another suboptimal behavior (I won't say 'false positive') where, - // similar to 2., but with a frozen variant) (e.g. borrowing - // `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`). - // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none). - matches!(err, ErrorHandled::TooGeneric(..)) + val: ConstValue<'tcx>, + ) -> Result { + let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty); + match self.is_ty_freeze(tcx, typing_env, ty) { + IsFreeze::Yes => Ok(true), + IsFreeze::Maybe if matches!(ty.kind(), ty::Adt(..) | ty::Array(..) | ty::Tuple(..)) => { + for &(val, ty) in tcx + .try_destructure_mir_constant_for_user_output(val, ty) + .ok_or(())? + .fields + { + if !self.is_value_freeze(tcx, typing_env, ty, val)? { + return Ok(false); + } + } + Ok(true) }, - |val| val.map_or(true, |val| Self::is_value_unfrozen_raw_inner(cx, val, ty)), - ) - } - - fn is_value_unfrozen_poly(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool { - let def_id = body_id.hir_id.owner.to_def_id(); - let args = ty::GenericArgs::identity_for_item(cx.tcx, def_id); - let instance = ty::Instance::new_raw(def_id, args); - let cid = GlobalId { - instance, - promoted: None, - }; - let typing_env = ty::TypingEnv::post_analysis(cx.tcx, def_id); - let result = cx.tcx.const_eval_global_id_for_typeck(typing_env, cid, DUMMY_SP); - Self::is_value_unfrozen_raw(cx, result, ty) - } - - fn is_value_unfrozen_expr(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool { - let args = cx.typeck_results().node_args(hir_id); - - let result = Self::const_eval_resolve( - cx.tcx, - cx.typing_env(), - ty::UnevaluatedConst::new(def_id, args), - DUMMY_SP, - ); - Self::is_value_unfrozen_raw(cx, result, ty) + IsFreeze::Maybe | IsFreeze::No => Ok(false), + } } - pub fn const_eval_resolve( + /// Checks if the given expression creates a value which is `Freeze`. + /// + /// This will return `true` if the type is maybe `Freeze`, but it cannot be + /// determined for certain from the value. + /// + /// `typing_env` and `gen_args` are from the constant's use site. + /// `typeck` and `e` are from the constant's definition site. + fn is_init_expr_freeze( + &mut self, tcx: TyCtxt<'tcx>, - typing_env: ty::TypingEnv<'tcx>, - ct: ty::UnevaluatedConst<'tcx>, - span: Span, - ) -> EvalToValTreeResult<'tcx> { - match ty::Instance::try_resolve(tcx, typing_env, ct.def, ct.args) { - Ok(Some(instance)) => { - let cid = GlobalId { - instance, - promoted: None, - }; - tcx.const_eval_global_id_for_typeck(typing_env, cid, span) + typing_env: TypingEnv<'tcx>, + typeck: &'tcx TypeckResults<'tcx>, + gen_args: GenericArgsRef<'tcx>, + e: &'tcx Expr<'tcx>, + ) -> bool { + // Make sure to instantiate all types coming from `typeck` with `gen_args`. + let ty = EarlyBinder::bind(typeck.expr_ty(e)).instantiate(tcx, gen_args); + let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty); + match self.is_ty_freeze(tcx, typing_env, ty) { + IsFreeze::Yes => true, + IsFreeze::No => false, + IsFreeze::Maybe => match e.kind { + ExprKind::Block(b, _) + if !b.targeted_by_break + && b.stmts.is_empty() + && let Some(e) = b.expr => + { + self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, e) + }, + ExprKind::Path(ref p) => { + let res = typeck.qpath_res(p, e.hir_id); + let gen_args = EarlyBinder::bind(typeck.node_args(e.hir_id)).instantiate(tcx, gen_args); + match res { + Res::Def(DefKind::Const | DefKind::AssocConst, did) + if let Ok(val) = + tcx.const_eval_resolve(typing_env, UnevaluatedConst::new(did, gen_args), DUMMY_SP) + && let Ok(is_freeze) = self.is_value_freeze(tcx, typing_env, ty, val) => + { + is_freeze + }, + Res::Def(DefKind::Const | DefKind::AssocConst, did) + if let Some((typeck, init)) = get_const_hir_value(tcx, typing_env, did, gen_args) => + { + self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, init) + }, + // Either this is a unit constructor, or some unknown value. + // In either case we consider the value to be `Freeze`. + _ => true, + } + }, + ExprKind::Call(callee, args) + if let ExprKind::Path(p) = &callee.kind + && let res = typeck.qpath_res(p, callee.hir_id) + && matches!(res, Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(_)) => + { + args.iter() + .all(|e| self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, e)) + }, + ExprKind::Struct(_, fields, StructTailExpr::None) => fields + .iter() + .all(|f| self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, f.expr)), + ExprKind::Tup(exprs) | ExprKind::Array(exprs) => exprs + .iter() + .all(|e| self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, e)), + ExprKind::Repeat(e, _) => self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, e), + _ => true, }, - Ok(None) => Err(ErrorHandled::TooGeneric(span)), - Err(err) => Err(ErrorHandled::Reported( - ReportedErrorInfo::non_const_eval_error(err), - span, - )), } } -} -impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { - fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) { - if let ItemKind::Const(.., body_id) = it.kind { - let ty = cx.tcx.type_of(it.owner_id).instantiate_identity(); - if !ignored_macro(cx, it) - && self.interior_mut.is_interior_mut_ty(cx, ty) - && Self::is_value_unfrozen_poly(cx, body_id, ty) - { - lint(cx, Source::Item { item: it.span, ty }); + /// Checks if the given expression (or a local projection of it) is both borrowed and + /// definitely a non-`Freeze` type. + fn is_non_freeze_expr_borrowed( + &mut self, + tcx: TyCtxt<'tcx>, + typing_env: TypingEnv<'tcx>, + typeck: &'tcx TypeckResults<'tcx>, + mut src_expr: &'tcx Expr<'tcx>, + ) -> Option> { + let mut parents = tcx.hir_parent_iter(src_expr.hir_id); + loop { + let ty = typeck.expr_ty(src_expr); + // Normalized as we need to check if this is an array later. + let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty); + let is_freeze = self.is_ty_freeze(tcx, typing_env, ty); + if is_freeze.is_freeze() { + return None; } - } - } - - fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'_>) { - if let TraitItemKind::Const(_, body_id_opt) = &trait_item.kind { - let ty = cx.tcx.type_of(trait_item.owner_id).instantiate_identity(); - - // Normalize assoc types because ones originated from generic params - // bounded other traits could have their bound. - let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty); - if self.interior_mut.is_interior_mut_ty(cx, normalized) - // When there's no default value, lint it only according to its type; - // in other words, lint consts whose value *could* be unfrozen, not definitely is. - // This feels inconsistent with how the lint treats generic types, - // which avoids linting types which potentially become unfrozen. - // One could check whether an unfrozen type have a *frozen variant* - // (like `body_id_opt.map_or_else(|| !has_frozen_variant(...), ...)`), - // and do the same as the case of generic types at impl items. - // Note that it isn't sufficient to check if it has an enum - // since all of that enum's variants can be unfrozen: - // i.e. having an enum doesn't necessary mean a type has a frozen variant. - // And, implementing it isn't a trivial task; it'll probably end up - // re-implementing the trait predicate evaluation specific to `Freeze`. - && body_id_opt.is_none_or(|body_id| Self::is_value_unfrozen_poly(cx, body_id, normalized)) - { - lint(cx, Source::Assoc { item: trait_item.span }); + if let [adjust, ..] = typeck.expr_adjustments(src_expr) { + return does_adjust_borrow(adjust) + .filter(|_| is_freeze.is_not_freeze()) + .map(|cause| BorrowSource::new(tcx, src_expr, cause)); + } + let Some((_, Node::Expr(use_expr))) = parents.next() else { + return None; + }; + match use_expr.kind { + ExprKind::Field(..) => {}, + ExprKind::Index(..) if ty.is_array() => {}, + ExprKind::AddrOf(..) if is_freeze.is_not_freeze() => { + return Some(BorrowSource::new(tcx, use_expr, BorrowCause::Borrow)); + }, + // All other expressions use the value. + _ => return None, } + src_expr = use_expr; } } - fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) { - if let ImplItemKind::Const(_, body_id) = &impl_item.kind { - let item_def_id = cx.tcx.hir_get_parent_item(impl_item.hir_id()).def_id; - let item = cx.tcx.hir_expect_item(item_def_id); - - match &item.kind { - ItemKind::Impl(Impl { - of_trait: Some(of_trait_ref), - .. - }) => { - if let Some(of_trait_def_id) = of_trait_ref.trait_def_id() - // Lint a trait impl item only when the definition is a generic type, - // assuming an assoc const is not meant to be an interior mutable type. - && let Some(of_assoc_item) = cx - .tcx - .associated_item(impl_item.owner_id) - .trait_item_def_id - && cx - .tcx - .layout_of(ty::TypingEnv::post_analysis(cx.tcx, of_trait_def_id).as_query_input( - // Normalize assoc types because ones originated from generic params - // bounded other traits could have their bound at the trait defs; - // and, in that case, the definition is *not* generic. - cx.tcx.normalize_erasing_regions( - ty::TypingEnv::post_analysis(cx.tcx, of_trait_def_id), - cx.tcx.type_of(of_assoc_item).instantiate_identity(), - ), - )) - .is_err() - // If there were a function like `has_frozen_variant` described above, - // we should use here as a frozen variant is a potential to be frozen - // similar to unknown layouts. - // e.g. `layout_of(...).is_err() || has_frozen_variant(...);` - && let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity() - && let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty) - && self.interior_mut.is_interior_mut_ty(cx, normalized) - && Self::is_value_unfrozen_poly(cx, *body_id, normalized) - { - lint(cx, Source::Assoc { item: impl_item.span }); + /// Checks if the given value (or a local projection of it) is both borrowed and + /// definitely non-`Freeze`. Returns `Err` if the constant cannot be read, but the + /// result depends on the value. + fn is_non_freeze_val_borrowed( + &mut self, + tcx: TyCtxt<'tcx>, + typing_env: TypingEnv<'tcx>, + typeck: &'tcx TypeckResults<'tcx>, + mut src_expr: &'tcx Expr<'tcx>, + mut val: ConstValue<'tcx>, + ) -> Result>, ()> { + let mut parents = tcx.hir_parent_iter(src_expr.hir_id); + let mut ty = typeck.expr_ty(src_expr); + loop { + // Normalized as we need to check if this is an array later. + ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty); + if let [adjust, ..] = typeck.expr_adjustments(src_expr) { + let res = if let Some(cause) = does_adjust_borrow(adjust) + && !self.is_value_freeze(tcx, typing_env, ty, val)? + { + Some(BorrowSource::new(tcx, src_expr, cause)) + } else { + None + }; + return Ok(res); + } + // Check only the type here as the result gets cached for each type. + if self.is_ty_freeze(tcx, typing_env, ty).is_freeze() { + return Ok(None); + } + let Some((_, Node::Expr(use_expr))) = parents.next() else { + return Ok(None); + }; + let next_val = match use_expr.kind { + ExprKind::Field(_, name) => { + if let Some(idx) = get_field_idx_by_name(ty, name.name) { + tcx.try_destructure_mir_constant_for_user_output(val, ty) + .ok_or(())? + .fields + .get(idx) + } else { + return Ok(None); } }, - ItemKind::Impl(Impl { of_trait: None, .. }) => { - let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity(); - // Normalize assoc types originated from generic params. - let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty); - - if self.interior_mut.is_interior_mut_ty(cx, normalized) - && Self::is_value_unfrozen_poly(cx, *body_id, normalized) - { - lint(cx, Source::Assoc { item: impl_item.span }); + ExprKind::Index(_, idx, _) if ty.is_array() => { + let val = tcx.try_destructure_mir_constant_for_user_output(val, ty).ok_or(())?; + if let Some(Constant::Int(idx)) = ConstEvalCtxt::with_env(tcx, typing_env, typeck).eval(idx) { + val.fields.get(idx as usize) + } else { + // It's some value in the array so check all of them. + for &(val, _) in val.fields { + if let Some(src) = + self.is_non_freeze_val_borrowed(tcx, typing_env, typeck, use_expr, val)? + { + return Ok(Some(src)); + } + } + return Ok(None); } }, - _ => (), + ExprKind::AddrOf(..) if !self.is_value_freeze(tcx, typing_env, ty, val)? => { + return Ok(Some(BorrowSource::new(tcx, use_expr, BorrowCause::Borrow))); + }, + // All other expressions use the value. + _ => return Ok(None), + }; + src_expr = use_expr; + if let Some(&(next_val, next_ty)) = next_val { + ty = next_ty; + val = next_val; + } else { + return Ok(None); } } } - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Path(qpath) = &expr.kind { - // Only lint if we use the const item inside a function. - if is_in_const_context(cx) { - return; + /// Checks if the given value (or a local projection of it) is both borrowed and + /// definitely non-`Freeze`. + /// + /// `typing_env` and `init_args` are from the constant's use site. + /// `init_typeck` and `init_expr` are from the constant's definition site. + #[expect(clippy::too_many_arguments, clippy::too_many_lines)] + fn is_non_freeze_init_borrowed( + &mut self, + tcx: TyCtxt<'tcx>, + typing_env: TypingEnv<'tcx>, + typeck: &'tcx TypeckResults<'tcx>, + mut src_expr: &'tcx Expr<'tcx>, + mut init_typeck: &'tcx TypeckResults<'tcx>, + mut init_args: GenericArgsRef<'tcx>, + mut init_expr: &'tcx Expr<'tcx>, + ) -> Option> { + // Make sure to instantiate all types coming from `init_typeck` with `init_args`. + let mut parents = tcx.hir_parent_iter(src_expr.hir_id); + loop { + // First handle any adjustments since they are cheap to check. + if let [adjust, ..] = typeck.expr_adjustments(src_expr) { + return does_adjust_borrow(adjust) + .filter(|_| !self.is_init_expr_freeze(tcx, typing_env, init_typeck, init_args, init_expr)) + .map(|cause| BorrowSource::new(tcx, src_expr, cause)); } - // Make sure it is a const item. - let Res::Def(DefKind::Const | DefKind::AssocConst, item_def_id) = cx.qpath_res(qpath, expr.hir_id) else { - return; - }; - - // Climb up to resolve any field access and explicit referencing. - let mut cur_expr = expr; - let mut dereferenced_expr = expr; - let mut needs_check_adjustment = true; + // Then read through constants and blocks on the init expression before + // applying the next use expression. loop { - let parent_id = cx.tcx.parent_hir_id(cur_expr.hir_id); - if parent_id == cur_expr.hir_id { - break; + match init_expr.kind { + ExprKind::Block(b, _) + if !b.targeted_by_break + && b.stmts.is_empty() + && let Some(next_init) = b.expr => + { + init_expr = next_init; + }, + ExprKind::Path(ref init_path) => { + let next_init_args = + EarlyBinder::bind(init_typeck.node_args(init_expr.hir_id)).instantiate(tcx, init_args); + match init_typeck.qpath_res(init_path, init_expr.hir_id) { + Res::Def(DefKind::Ctor(..), _) => return None, + Res::Def(DefKind::Const | DefKind::AssocConst, did) + if let Ok(val) = tcx.const_eval_resolve( + typing_env, + UnevaluatedConst::new(did, next_init_args), + DUMMY_SP, + ) && let Ok(res) = + self.is_non_freeze_val_borrowed(tcx, typing_env, init_typeck, src_expr, val) => + { + return res; + }, + Res::Def(DefKind::Const | DefKind::AssocConst, did) + if let Some((next_typeck, value)) = + get_const_hir_value(tcx, typing_env, did, next_init_args) => + { + init_typeck = next_typeck; + init_args = next_init_args; + init_expr = value; + }, + // There's no more that we can read from the init expression. Switch to a + // type based check. + _ => { + return self.is_non_freeze_expr_borrowed(tcx, typing_env, typeck, src_expr); + }, + } + }, + _ => break, } - if let Node::Expr(parent_expr) = cx.tcx.hir_node(parent_id) { - match &parent_expr.kind { - ExprKind::AddrOf(..) => { - // `&e` => `e` must be referenced. - needs_check_adjustment = false; - }, - ExprKind::Field(..) => { - needs_check_adjustment = true; + } - // Check whether implicit dereferences happened; - // if so, no need to go further up - // because of the same reason as the `ExprKind::Unary` case. - if cx - .typeck_results() - .expr_adjustments(dereferenced_expr) - .iter() - .any(|adj| matches!(adj.kind, Adjust::Deref(_))) - { - break; - } + // Then a type check. Note we only check the type here as the result + // gets cached. + let ty = EarlyBinder::bind(typeck.expr_ty(src_expr)).instantiate(tcx, init_args); + // Normalized as we need to check if this is an array later. + let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty); + if self.is_ty_freeze(tcx, typing_env, ty).is_freeze() { + return None; + } - dereferenced_expr = parent_expr; - }, - ExprKind::Index(e, _, _) if ptr::eq(&raw const **e, cur_expr) => { - // `e[i]` => desugared to `*Index::index(&e, i)`, - // meaning `e` must be referenced. - // no need to go further up since a method call is involved now. - needs_check_adjustment = false; - break; - }, - ExprKind::Unary(UnOp::Deref, _) => { - // `*e` => desugared to `*Deref::deref(&e)`, - // meaning `e` must be referenced. - // no need to go further up since a method call is involved now. - needs_check_adjustment = false; - break; + // Finally reduce the init expression using the next use expression. + let Some((_, Node::Expr(use_expr))) = parents.next() else { + return None; + }; + init_expr = match &use_expr.kind { + ExprKind::Field(_, name) => match init_expr.kind { + ExprKind::Struct(_, fields, _) + if let Some(field) = fields.iter().find(|f| f.ident.name == name.name) => + { + field.expr + }, + ExprKind::Tup(fields) + if let Ok(idx) = name.as_str().parse::() + && let Some(field) = fields.get(idx) => + { + field + }, + ExprKind::Call(callee, args) + if let ExprKind::Path(callee_path) = &callee.kind + && matches!( + init_typeck.qpath_res(callee_path, callee.hir_id), + Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(_) + ) + && let Ok(idx) = name.as_str().parse::() + && let Some(arg) = args.get(idx) => + { + arg + }, + // Revert to a type based check as we don't know the field's value. + _ => return self.is_non_freeze_expr_borrowed(tcx, typing_env, typeck, use_expr), + }, + ExprKind::Index(_, idx, _) if ty.is_array() => match init_expr.kind { + ExprKind::Array(fields) => { + if let Some(Constant::Int(idx)) = ConstEvalCtxt::with_env(tcx, typing_env, typeck).eval(idx) { + // If the index is out of bounds it means the code + // unconditionally panics. In that case there is no borrow. + fields.get(idx as usize)? + } else { + // Unknown index, just run the check for all values. + return fields.iter().find_map(|f| { + self.is_non_freeze_init_borrowed( + tcx, + typing_env, + typeck, + use_expr, + init_typeck, + init_args, + f, + ) + }); + } + }, + // Just assume the index expression doesn't panic here. + ExprKind::Repeat(field, _) => field, + _ => return self.is_non_freeze_expr_borrowed(tcx, typing_env, typeck, use_expr), + }, + ExprKind::AddrOf(..) + if !self.is_init_expr_freeze(tcx, typing_env, init_typeck, init_args, init_expr) => + { + return Some(BorrowSource::new(tcx, use_expr, BorrowCause::Borrow)); + }, + // All other expressions use the value. + _ => return None, + }; + src_expr = use_expr; + } + } +} + +impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { + if let ItemKind::Const(ident, .., body_id) = item.kind + && !ident.is_special() + && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() + && match self.is_ty_freeze(cx.tcx, cx.typing_env(), ty) { + IsFreeze::No => true, + IsFreeze::Yes => false, + IsFreeze::Maybe => match cx.tcx.const_eval_poly(item.owner_id.to_def_id()) { + Ok(val) if let Ok(is_freeze) = self.is_value_freeze(cx.tcx, cx.typing_env(), ty, val) => !is_freeze, + _ => !self.is_init_expr_freeze( + cx.tcx, + cx.typing_env(), + cx.tcx.typeck(item.owner_id), + GenericArgs::identity_for_item(cx.tcx, item.owner_id), + cx.tcx.hir_body(body_id).value, + ), + }, + } + && !item.span.in_external_macro(cx.sess().source_map()) + // Only needed when compiling `std` + && !is_thread_local(cx, item) + { + span_lint_and_then( + cx, + DECLARE_INTERIOR_MUTABLE_CONST, + ident.span, + "named constant with interior mutability", + |diag| { + let Some(sync_trait) = cx.tcx.lang_items().sync_trait() else { + return; + }; + if implements_trait(cx, ty, sync_trait, &[]) { + diag.help("did you mean to make this a `static` item"); + } else { + diag.help("did you mean to make this a `thread_local!` item"); + } + }, + ); + } + } + + fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { + if let TraitItemKind::Const(_, body_id_opt) = item.kind + && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() + && match self.is_ty_freeze(cx.tcx, cx.typing_env(), ty) { + IsFreeze::No => true, + IsFreeze::Maybe if let Some(body_id) = body_id_opt => { + match cx.tcx.const_eval_poly(item.owner_id.to_def_id()) { + Ok(val) if let Ok(is_freeze) = self.is_value_freeze(cx.tcx, cx.typing_env(), ty, val) => { + !is_freeze }, - _ => break, + _ => !self.is_init_expr_freeze( + cx.tcx, + cx.typing_env(), + cx.tcx.typeck(item.owner_id), + GenericArgs::identity_for_item(cx.tcx, item.owner_id), + cx.tcx.hir_body(body_id).value, + ), } - cur_expr = parent_expr; - } else { - break; - } + }, + IsFreeze::Yes | IsFreeze::Maybe => false, } + && !item.span.in_external_macro(cx.sess().source_map()) + { + span_lint( + cx, + DECLARE_INTERIOR_MUTABLE_CONST, + item.ident.span, + "named constant with interior mutability", + ); + } + } - let ty = if needs_check_adjustment { - let adjustments = cx.typeck_results().expr_adjustments(dereferenced_expr); - if let Some(i) = adjustments - .iter() - .position(|adj| matches!(adj.kind, Adjust::Borrow(_) | Adjust::Deref(_))) - { - if i == 0 { - cx.typeck_results().expr_ty(dereferenced_expr) + fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { + if let ImplItemKind::Const(_, body_id) = item.kind + && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() + && match self.is_ty_freeze(cx.tcx, cx.typing_env(), ty) { + IsFreeze::Yes => false, + IsFreeze::No => { + // If this is a trait impl, check if the trait definition is the source + // of the cell. + if let Node::Item(parent_item) = cx.tcx.parent_hir_node(item.hir_id()) + && let ItemKind::Impl(impl_block) = parent_item.kind + && let Some(of_trait) = impl_block.of_trait + && let Some(trait_id) = of_trait.trait_def_id() + { + // Replace all instances of `::AssocType` with the + // unit type and check again. If the result is the same then the + // trait definition is the cause. + let ty = (ReplaceAssocFolder { + tcx: cx.tcx, + trait_id, + self_ty: cx.tcx.type_of(parent_item.owner_id).instantiate_identity(), + }) + .fold_ty(cx.tcx.type_of(item.owner_id).instantiate_identity()); + // `ty` may not be normalizable, but that should be fine. + !self.is_ty_freeze(cx.tcx, cx.typing_env(), ty).is_not_freeze() } else { - adjustments[i - 1].target + true } + }, + // Even if this is from a trait, there are values which don't have + // interior mutability. + IsFreeze::Maybe => match cx.tcx.const_eval_poly(item.owner_id.to_def_id()) { + Ok(val) if let Ok(is_freeze) = self.is_value_freeze(cx.tcx, cx.typing_env(), ty, val) => !is_freeze, + _ => !self.is_init_expr_freeze( + cx.tcx, + cx.typing_env(), + cx.tcx.typeck(item.owner_id), + GenericArgs::identity_for_item(cx.tcx, item.owner_id), + cx.tcx.hir_body(body_id).value, + ), + }, + } + && !item.span.in_external_macro(cx.sess().source_map()) + { + span_lint( + cx, + DECLARE_INTERIOR_MUTABLE_CONST, + item.ident.span, + "named constant with interior mutability", + ); + } + } + + fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { + if let ExprKind::Path(qpath) = &e.kind + && let typeck = cx.typeck_results() + && let Res::Def(DefKind::Const | DefKind::AssocConst, did) = typeck.qpath_res(qpath, e.hir_id) + // As of `1.80` constant contexts can't borrow any type with interior mutability + && !is_in_const_context(cx) + && !self.is_ty_freeze(cx.tcx, cx.typing_env(), typeck.expr_ty(e)).is_freeze() + && let Some(borrow_src) = { + // The extra block helps formatting a lot. + if let Ok(val) = cx.tcx.const_eval_resolve( + cx.typing_env(), + UnevaluatedConst::new(did, typeck.node_args(e.hir_id)), + DUMMY_SP, + ) && let Ok(src) = self.is_non_freeze_val_borrowed(cx.tcx, cx.typing_env(), typeck, e, val) + { + src + } else if let init_args = typeck.node_args(e.hir_id) + && let Some((init_typeck, init)) = get_const_hir_value(cx.tcx, cx.typing_env(), did, init_args) + { + self.is_non_freeze_init_borrowed(cx.tcx, cx.typing_env(), typeck, e, init_typeck, init_args, init) } else { - // No borrow adjustments means the entire const is moved. - return; + self.is_non_freeze_expr_borrowed(cx.tcx, cx.typing_env(), typeck, e) } - } else { - cx.typeck_results().expr_ty(dereferenced_expr) - }; - - if self.interior_mut.is_interior_mut_ty(cx, ty) - && Self::is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty) - { - lint(cx, Source::Expr { expr: expr.span }); } + && !borrow_src.expr.span.in_external_macro(cx.sess().source_map()) + { + span_lint_and_then( + cx, + BORROW_INTERIOR_MUTABLE_CONST, + borrow_src.expr.span, + "borrow of a named constant with interior mutability", + |diag| { + if let Some(note) = borrow_src.cause.note() { + diag.note(note); + } + diag.help("this lint can be silenced by assigning the value to a local variable before borrowing"); + }, + ); + } + } +} + +struct ReplaceAssocFolder<'tcx> { + tcx: TyCtxt<'tcx>, + trait_id: DefId, + self_ty: Ty<'tcx>, +} +impl<'tcx> TypeFolder> for ReplaceAssocFolder<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + if let ty::Alias(AliasTyKind::Projection, ty) = ty.kind() + && ty.trait_def_id(self.tcx) == self.trait_id + && ty.self_ty() == self.self_ty + { + self.tcx.types.unit + } else { + ty.super_fold_with(self) } } } -fn ignored_macro(cx: &LateContext<'_>, it: &Item<'_>) -> bool { +fn is_thread_local(cx: &LateContext<'_>, it: &Item<'_>) -> bool { macro_backtrace(it.span).any(|macro_call| { matches!( cx.tcx.get_diagnostic_name(macro_call.def_id), @@ -507,3 +891,42 @@ fn ignored_macro(cx: &LateContext<'_>, it: &Item<'_>) -> bool { ) }) } + +/// Checks if the adjustment causes a borrow of the original value. Returns +/// `None` if the value is consumed instead of borrowed. +fn does_adjust_borrow(adjust: &Adjustment<'_>) -> Option { + match adjust.kind { + Adjust::Borrow(_) => Some(BorrowCause::AutoBorrow), + // Custom deref calls `::deref(&x)` resulting in a borrow. + Adjust::Deref(Some(_)) => Some(BorrowCause::AutoDeref), + // All other adjustments read the value. + _ => None, + } +} + +/// Attempts to get the value of a constant as a HIR expression. Also gets the +/// `TypeckResults` associated with the constant's body. +fn get_const_hir_value<'tcx>( + tcx: TyCtxt<'tcx>, + typing_env: TypingEnv<'tcx>, + did: DefId, + args: GenericArgsRef<'tcx>, +) -> Option<(&'tcx TypeckResults<'tcx>, &'tcx Expr<'tcx>)> { + let did = did.as_local()?; + let (did, body_id) = match tcx.hir_node(tcx.local_def_id_to_hir_id(did)) { + Node::Item(item) if let ItemKind::Const(.., body_id) = item.kind => (did, body_id), + Node::ImplItem(item) if let ImplItemKind::Const(.., body_id) = item.kind => (did, body_id), + Node::TraitItem(_) + if let Ok(Some(inst)) = Instance::try_resolve(tcx, typing_env, did.into(), args) + && let Some(did) = inst.def_id().as_local() => + { + match tcx.hir_node(tcx.local_def_id_to_hir_id(did)) { + Node::ImplItem(item) if let ImplItemKind::Const(.., body_id) = item.kind => (did, body_id), + Node::TraitItem(item) if let TraitItemKind::Const(.., Some(body_id)) = item.kind => (did, body_id), + _ => return None, + } + }, + _ => return None, + }; + Some((tcx.typeck(did), tcx.hir_body(body_id).value)) +} diff --git a/clippy_lints/src/operators/assign_op_pattern.rs b/clippy_lints/src/operators/assign_op_pattern.rs index 03b907ebdf4d8..4be42267b14b3 100644 --- a/clippy_lints/src/operators/assign_op_pattern.rs +++ b/clippy_lints/src/operators/assign_op_pattern.rs @@ -26,7 +26,7 @@ pub(super) fn check<'tcx>( let rty = cx.typeck_results().expr_ty(rhs); if let Some((_, lang_item)) = binop_traits(op.node) && let Some(trait_id) = cx.tcx.lang_items().get(lang_item) - && let parent_fn = cx.tcx.hir_get_parent_item(e.hir_id).def_id + && let parent_fn = cx.tcx.hir_get_parent_item(e.hir_id) && trait_ref_of_method(cx, parent_fn).is_none_or(|t| t.path.res.def_id() != trait_id) && implements_trait(cx, ty, trait_id, &[rty.into()]) { diff --git a/clippy_lints/src/operators/duration_subsec.rs b/clippy_lints/src/operators/duration_subsec.rs index e3029f8438e5f..6c9be7c5e90b3 100644 --- a/clippy_lints/src/operators/duration_subsec.rs +++ b/clippy_lints/src/operators/duration_subsec.rs @@ -1,11 +1,11 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sym; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::sym; use super::DURATION_SUBSEC; @@ -21,9 +21,9 @@ pub(crate) fn check<'tcx>( && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_arg).peel_refs(), sym::Duration) && let Some(Constant::Int(divisor)) = ConstEvalCtxt::new(cx).eval(right) { - let suggested_fn = match (method_path.ident.as_str(), divisor) { - ("subsec_micros", 1_000) | ("subsec_nanos", 1_000_000) => "subsec_millis", - ("subsec_nanos", 1_000) => "subsec_micros", + let suggested_fn = match (method_path.ident.name, divisor) { + (sym::subsec_micros, 1_000) | (sym::subsec_nanos, 1_000_000) => "subsec_millis", + (sym::subsec_nanos, 1_000) => "subsec_micros", _ => return, }; let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_lints/src/option_env_unwrap.rs b/clippy_lints/src/option_env_unwrap.rs index d16f5f8e112c3..64ad92b1ebb50 100644 --- a/clippy_lints/src/option_env_unwrap.rs +++ b/clippy_lints/src/option_env_unwrap.rs @@ -37,7 +37,7 @@ impl EarlyLintPass for OptionEnvUnwrap { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind && matches!(seg.ident.name, sym::expect | sym::unwrap) - && is_direct_expn_of(receiver.span, "option_env").is_some() + && is_direct_expn_of(receiver.span, sym::option_env).is_some() { span_lint_and_help( cx, diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 122d97fdf8193..ab9b0f88f936c 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -423,7 +423,14 @@ fn check_final_expr<'tcx>( _ => return, } - emit_return_lint(cx, ret_span, semi_spans, &replacement, expr.hir_id); + emit_return_lint( + cx, + peeled_drop_expr.span, + ret_span, + semi_spans, + &replacement, + expr.hir_id, + ); }, ExprKind::If(_, then, else_clause_opt) => { check_block_return(cx, &then.kind, peeled_drop_expr.span, semi_spans.clone()); @@ -448,6 +455,7 @@ fn check_final_expr<'tcx>( fn emit_return_lint( cx: &LateContext<'_>, + lint_span: Span, ret_span: Span, semi_spans: Vec, replacement: &RetReplacement<'_>, @@ -457,7 +465,7 @@ fn emit_return_lint( cx, NEEDLESS_RETURN, at, - ret_span, + lint_span, "unneeded `return` statement", |diag| { let suggestions = std::iter::once((ret_span, replacement.to_string())) diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index ccb1209c6fcbe..f3fea3add592d 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{indent_of, snippet}; -use clippy_utils::{expr_or_init, get_attr, path_to_local, peel_hir_expr_unary}; +use clippy_utils::{expr_or_init, get_attr, path_to_local, peel_hir_expr_unary, sym}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::{GenericArgKind, Ty}; use rustc_session::impl_lint_pass; use rustc_span::symbol::Ident; -use rustc_span::{DUMMY_SP, Span, sym}; +use rustc_span::{DUMMY_SP, Span}; use std::borrow::Cow; use std::collections::hash_map::Entry; @@ -169,7 +169,7 @@ impl<'cx, 'others, 'tcx> AttrChecker<'cx, 'others, 'tcx> { let mut iter = get_attr( self.cx.sess(), self.cx.tcx.get_attrs_unchecked(adt.did()), - "has_significant_drop", + sym::has_significant_drop, ); if iter.next().is_some() { return true; diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs index 835ec1e4ca1c7..3623039aece15 100644 --- a/clippy_lints/src/size_of_in_element_count.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -1,9 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::sym; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; -use rustc_span::sym; +use rustc_span::Symbol; declare_clippy_lint! { /// ### What it does @@ -62,17 +63,17 @@ fn get_pointee_ty_and_count_expr<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> { - const METHODS: [&str; 10] = [ - "copy_to", - "copy_from", - "copy_to_nonoverlapping", - "copy_from_nonoverlapping", - "add", - "wrapping_add", - "sub", - "wrapping_sub", - "offset", - "wrapping_offset", + const METHODS: [Symbol; 10] = [ + sym::copy_to, + sym::copy_from, + sym::copy_to_nonoverlapping, + sym::copy_from_nonoverlapping, + sym::add, + sym::wrapping_add, + sym::sub, + sym::wrapping_sub, + sym::offset, + sym::wrapping_offset, ]; if let ExprKind::Call(func, [.., count]) = expr.kind @@ -97,7 +98,7 @@ fn get_pointee_ty_and_count_expr<'tcx>( } if let ExprKind::MethodCall(method_path, ptr_self, [.., count], _) = expr.kind // Find calls to copy_{from,to}{,_nonoverlapping} - && let method_ident = method_path.ident.as_str() + && let method_ident = method_path.ident.name && METHODS.contains(&method_ident) // Get the pointee type diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 30a5fe4db27e1..f497d0700b8eb 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -266,7 +266,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> { let is_matching_resize = if let InitializedSize::Initialized(size_expr) = self.vec_alloc.size_expr { // If we have a size expression, check that it is equal to what's passed to `resize` SpanlessEq::new(self.cx).eq_expr(len_arg, size_expr) - || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.as_str() == "capacity") + || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.name == sym::capacity) } else { self.vec_alloc.size_expr = InitializedSize::Initialized(len_arg); true @@ -288,7 +288,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> { if let InitializedSize::Initialized(size_expr) = self.vec_alloc.size_expr { // Check that len expression is equals to `with_capacity` expression return SpanlessEq::new(self.cx).eq_expr(len_arg, size_expr) - || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.as_str() == "capacity"); + || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.name == sym::capacity); } self.vec_alloc.size_expr = InitializedSize::Initialized(len_arg); diff --git a/clippy_lints/src/string_patterns.rs b/clippy_lints/src/string_patterns.rs index 5c95dfe834730..f63e6b3087b9e 100644 --- a/clippy_lints/src/string_patterns.rs +++ b/clippy_lints/src/string_patterns.rs @@ -5,9 +5,9 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::macros::matching_root_macro_call; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::path_to_local_id; use clippy_utils::source::{snippet, str_literal_to_char_literal}; use clippy_utils::visitors::{Descend, for_each_expr}; +use clippy_utils::{path_to_local_id, sym}; use itertools::Itertools; use rustc_ast::{BinOpKind, LitKind}; use rustc_errors::Applicability; @@ -15,7 +15,7 @@ use rustc_hir::{Expr, ExprKind, PatExprKind, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -83,29 +83,29 @@ impl StringPatterns { impl_lint_pass!(StringPatterns => [MANUAL_PATTERN_CHAR_COMPARISON, SINGLE_CHAR_PATTERN]); -const PATTERN_METHODS: [(&str, usize); 22] = [ - ("contains", 0), - ("starts_with", 0), - ("ends_with", 0), - ("find", 0), - ("rfind", 0), - ("split", 0), - ("split_inclusive", 0), - ("rsplit", 0), - ("split_terminator", 0), - ("rsplit_terminator", 0), - ("splitn", 1), - ("rsplitn", 1), - ("split_once", 0), - ("rsplit_once", 0), - ("matches", 0), - ("rmatches", 0), - ("match_indices", 0), - ("rmatch_indices", 0), - ("trim_start_matches", 0), - ("trim_end_matches", 0), - ("replace", 0), - ("replacen", 0), +const PATTERN_METHODS: [(Symbol, usize); 22] = [ + (sym::contains, 0), + (sym::starts_with, 0), + (sym::ends_with, 0), + (sym::find, 0), + (sym::rfind, 0), + (sym::split, 0), + (sym::split_inclusive, 0), + (sym::rsplit, 0), + (sym::split_terminator, 0), + (sym::rsplit_terminator, 0), + (sym::splitn, 1), + (sym::rsplitn, 1), + (sym::split_once, 0), + (sym::rsplit_once, 0), + (sym::matches, 0), + (sym::rmatches, 0), + (sym::match_indices, 0), + (sym::rmatch_indices, 0), + (sym::trim_start_matches, 0), + (sym::trim_end_matches, 0), + (sym::replace, 0), + (sym::replacen, 0), ]; fn check_single_char_pattern_lint(cx: &LateContext<'_>, arg: &Expr<'_>) { @@ -228,7 +228,7 @@ impl<'tcx> LateLintPass<'tcx> for StringPatterns { && let ExprKind::MethodCall(method, receiver, args, _) = expr.kind && let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind() && ty.is_str() - && let method_name = method.ident.name.as_str() + && let method_name = method.ident.name && let Some(&(_, pos)) = PATTERN_METHODS .iter() .find(|(array_method_name, _)| *array_method_name == method_name) diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs index 1ada7094dc550..33856c750d7e9 100644 --- a/clippy_lints/src/strlen_on_c_strings.rs +++ b/clippy_lints/src/strlen_on_c_strings.rs @@ -1,13 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::match_libc_symbol; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::visitors::is_expr_unsafe; +use clippy_utils::{match_libc_symbol, sym}; use rustc_errors::Applicability; use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, LangItem, Node, UnsafeSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::sym; declare_clippy_lint! { /// ### What it does @@ -44,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings { && let ExprKind::Call(func, [recv]) = expr.kind && let ExprKind::Path(path) = &func.kind && let Some(did) = cx.qpath_res(path, func.hir_id).opt_def_id() - && match_libc_symbol(cx, did, "strlen") + && match_libc_symbol(cx, did, sym::strlen) && let ExprKind::MethodCall(path, self_arg, [], _) = recv.kind && !recv.span.from_expansion() && path.ident.name == sym::as_ptr diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index 83241f97a99ac..edb7600b7c067 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -80,7 +80,7 @@ fn check_expr_inner<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, bin && let hir::Node::ImplItem(impl_item) = cx.tcx.hir_node_by_def_id(parent_fn) && let hir::ImplItemKind::Fn(_, body_id) = impl_item.kind && let body = cx.tcx.hir_body(body_id) - && let parent_fn = cx.tcx.hir_get_parent_item(expr.hir_id).def_id + && let parent_fn = cx.tcx.hir_get_parent_item(expr.hir_id) && let Some(trait_ref) = trait_ref_of_method(cx, parent_fn) && let trait_id = trait_ref.path.res.def_id() && ![binop_trait_id, op_assign_trait_id].contains(&trait_id) diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index bcd05cceca9c3..54a7efc090ade 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; @@ -78,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { fn_kind: FnKind<'tcx>, fn_decl: &FnDecl<'tcx>, body: &Body<'tcx>, - span: Span, + _span: Span, def_id: LocalDefId, ) { // Abort if public function/method or closure. @@ -147,19 +149,22 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { "remove the return type...".to_string(), // FIXME: we should instead get the span including the `->` and suggest an // empty string for this case. - "()".to_string(), - "...and then remove returned values", + Cow::Borrowed("()"), + Cow::Borrowed("...and then remove returned values"), ) } else { + let wrapper = if lang_item == OptionSome { "Some" } else { "Ok" }; ( format!("this function's return value is unnecessarily wrapped by `{return_type_label}`"), format!("remove `{return_type_label}` from the return type..."), - inner_type.to_string(), - "...and then change returning expressions", + Cow::Owned(inner_type.to_string()), + Cow::Owned(format!( + "...and then remove the surrounding `{wrapper}()` from returning expressions" + )), ) }; - span_lint_and_then(cx, UNNECESSARY_WRAPS, span, lint_msg, |diag| { + span_lint_and_then(cx, UNNECESSARY_WRAPS, cx.tcx.def_span(def_id), lint_msg, |diag| { diag.span_suggestion( fn_decl.output.span(), return_type_sugg_msg, diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs index 7487e273caa7e..1f5351e32aacf 100644 --- a/clippy_lints/src/unused_peekable.rs +++ b/clippy_lints/src/unused_peekable.rs @@ -1,13 +1,12 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable}; -use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators}; +use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators, sym}; use rustc_ast::Mutability; use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Block, Expr, ExprKind, HirId, LetStmt, Node, PatKind, PathSegment, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_session::declare_lint_pass; -use rustc_span::sym; use std::ops::ControlFlow; declare_clippy_lint! { @@ -150,10 +149,10 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> { remaining_args, _, ) => { - let method_name = method_name_ident.name.as_str(); + let method_name = method_name_ident.name; // `Peekable` methods - if matches!(method_name, "peek" | "peek_mut" | "next_if" | "next_if_eq") + if matches!(method_name, sym::peek | sym::peek_mut | sym::next_if | sym::next_if_eq) && arg_is_mut_peekable(self.cx, self_arg) { return ControlFlow::Break(()); @@ -167,7 +166,7 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> { } // foo.by_ref(), keep checking for `peek` - if method_name == "by_ref" { + if method_name == sym::by_ref { continue; } diff --git a/clippy_lints/src/unused_rounding.rs b/clippy_lints/src/unused_rounding.rs index 3e5afec541c49..c21004b5362dd 100644 --- a/clippy_lints/src/unused_rounding.rs +++ b/clippy_lints/src/unused_rounding.rs @@ -1,9 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; +use clippy_utils::sym; use rustc_ast::ast::{Expr, ExprKind, MethodCall}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; +use rustc_span::Symbol; declare_clippy_lint! { /// ### What it does @@ -30,19 +32,20 @@ declare_clippy_lint! { } declare_lint_pass!(UnusedRounding => [UNUSED_ROUNDING]); -fn is_useless_rounding<'a>(cx: &EarlyContext<'_>, expr: &'a Expr) -> Option<(&'a str, String)> { +fn is_useless_rounding(cx: &EarlyContext<'_>, expr: &Expr) -> Option<(Symbol, String)> { if let ExprKind::MethodCall(box MethodCall { seg: name_ident, receiver, .. }) = &expr.kind - && let method_name = name_ident.ident.name.as_str() - && (method_name == "ceil" || method_name == "round" || method_name == "floor") + && let method_name = name_ident.ident.name + && matches!(method_name, sym::ceil | sym::floor | sym::round) && let ExprKind::Lit(token_lit) = &receiver.kind && token_lit.is_semantic_float() && let Ok(f) = token_lit.symbol.as_str().replace('_', "").parse::() + && f.fract() == 0.0 { - (f.fract() == 0.0).then(|| (method_name, snippet(cx, receiver.span, "..").to_string())) + Some((method_name, snippet(cx, receiver.span, "..").into())) } else { None } diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index f870eb71e19b9..7bec212a23ca0 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -79,7 +79,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tc let mut result = Vec::new(); let _: Option = for_each_expr(cx, body.value, |e| { // check for `expect` - if let Some(arglists) = method_chain_args(e, &["expect"]) { + if let Some(arglists) = method_chain_args(e, &[sym::expect]) { let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs(); if is_type_diagnostic_item(cx, receiver_ty, sym::Option) || is_type_diagnostic_item(cx, receiver_ty, sym::Result) @@ -89,7 +89,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tc } // check for `unwrap` - if let Some(arglists) = method_chain_args(e, &["unwrap"]) { + if let Some(arglists) = method_chain_args(e, &[sym::unwrap]) { let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs(); if is_type_diagnostic_item(cx, receiver_ty, sym::Option) || is_type_diagnostic_item(cx, receiver_ty, sym::Result) diff --git a/clippy_lints/src/useless_concat.rs b/clippy_lints/src/useless_concat.rs new file mode 100644 index 0000000000000..1ed1fbb3b9c69 --- /dev/null +++ b/clippy_lints/src/useless_concat.rs @@ -0,0 +1,104 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::macros::macro_backtrace; +use clippy_utils::paths::CONCAT; +use clippy_utils::source::snippet_opt; +use clippy_utils::tokenize_with_text; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lexer::TokenKind; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// Checks that the `concat!` macro has at least two arguments. + /// + /// ### Why is this bad? + /// If there are less than 2 arguments, then calling the macro is doing nothing. + /// + /// ### Example + /// ```no_run + /// let x = concat!("a"); + /// ``` + /// Use instead: + /// ```no_run + /// let x = "a"; + /// ``` + #[clippy::version = "1.89.0"] + pub USELESS_CONCAT, + complexity, + "checks that the `concat` macro has at least two arguments" +} + +declare_lint_pass!(UselessConcat => [USELESS_CONCAT]); + +impl LateLintPass<'_> for UselessConcat { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + // Check that the expression is generated by a macro. + if expr.span.from_expansion() + // Check that it's a string literal. + && let ExprKind::Lit(lit) = expr.kind + && let LitKind::Str(lit_s, _) = lit.node + // Get the direct parent of the expression. + && let Some(macro_call) = macro_backtrace(expr.span).next() + // Check if the `concat` macro from the `core` library. + && CONCAT.matches(cx, macro_call.def_id) + // We get the original code to parse it. + && let Some(original_code) = snippet_opt(cx, macro_call.span) + // This check allows us to ensure that the code snippet: + // 1. Doesn't come from proc-macro expansion. + // 2. Doesn't come from foreign macro expansion. + // + // It works as follows: if the snippet we get doesn't contain `concat!(`, then it + // means it's not code written in the current crate so we shouldn't lint. + && let mut parts = original_code.split('!') + && parts.next().is_some_and(|p| p.trim() == "concat") + && parts.next().is_some_and(|p| p.trim().starts_with('(')) + { + let mut literal = None; + let mut nb_commas = 0; + let mut nb_idents = 0; + for (token_kind, token_s, _) in tokenize_with_text(&original_code) { + match token_kind { + TokenKind::Eof => break, + TokenKind::Literal { .. } => { + if literal.is_some() { + return; + } + literal = Some(token_s); + }, + TokenKind::Ident => { + if token_s == "true" || token_s == "false" { + literal = Some(token_s); + } else { + nb_idents += 1; + } + }, + TokenKind::Comma => { + nb_commas += 1; + if nb_commas > 1 { + return; + } + }, + // We're inside a macro definition and we are manipulating something we likely + // shouldn't, so aborting. + TokenKind::Dollar => return, + _ => {}, + } + } + // There should always be the ident of the `concat` macro. + if nb_idents == 1 { + span_lint_and_sugg( + cx, + USELESS_CONCAT, + macro_call.span, + "unneeded use of `concat!` macro", + "replace with", + format!("{lit_s:?}"), + Applicability::MachineApplicable, + ); + } + } + } +} diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 3a9c997a579d1..380ddea4e1e83 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -3,11 +3,11 @@ use clippy_utils::source::{snippet, snippet_with_context}; use clippy_utils::sugg::{DiagExt as _, Sugg}; use clippy_utils::ty::{get_type_diagnostic_name, is_copy, is_type_diagnostic_item, same_type_and_consts}; use clippy_utils::{ - get_parent_expr, is_inherent_method_call, is_trait_item, is_trait_method, is_ty_alias, path_to_local, + get_parent_expr, is_inherent_method_call, is_trait_item, is_trait_method, is_ty_alias, path_to_local, sym, }; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; -use rustc_hir::{BindingMode, Expr, ExprKind, HirId, MatchSource, Node, PatKind}; +use rustc_hir::{BindingMode, Expr, ExprKind, HirId, MatchSource, Mutability, Node, PatKind}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::Obligation; use rustc_lint::{LateContext, LateLintPass}; @@ -15,7 +15,7 @@ use rustc_middle::traits::ObligationCause; use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::{self, EarlyBinder, GenericArg, GenericArgsRef, Ty, TypeVisitableExt}; use rustc_session::impl_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::Span; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; declare_clippy_lint! { @@ -177,7 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { }, ExprKind::MethodCall(name, recv, [], _) => { - if is_trait_method(cx, e, sym::Into) && name.ident.as_str() == "into" { + if is_trait_method(cx, e, sym::Into) && name.ident.name == sym::into { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(recv); if same_type_and_consts(a, b) { @@ -298,6 +298,33 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { // implements Copy, in which case .into_iter() returns a copy of the receiver and // cannot be safely omitted. if same_type_and_consts(a, b) && !is_copy(cx, b) { + // Below we check if the parent method call meets the following conditions: + // 1. First parameter is `&mut self` (requires mutable reference) + // 2. Second parameter implements the `FnMut` trait (e.g., Iterator::any) + // For methods satisfying these conditions (like any), .into_iter() must be preserved. + if let Some(parent) = get_parent_expr(cx, e) + && let ExprKind::MethodCall(_, recv, _, _) = parent.kind + && recv.hir_id == e.hir_id + && let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id) + && let sig = cx.tcx.fn_sig(def_id).skip_binder().skip_binder() + && let inputs = sig.inputs() + && inputs.len() >= 2 + && let Some(self_ty) = inputs.first() + && let ty::Ref(_, _, Mutability::Mut) = self_ty.kind() + && let Some(second_ty) = inputs.get(1) + && let predicates = cx.tcx.param_env(def_id).caller_bounds() + && predicates.iter().any(|pred| { + if let ty::ClauseKind::Trait(trait_pred) = pred.kind().skip_binder() { + trait_pred.self_ty() == *second_ty + && cx.tcx.lang_items().fn_mut_trait() == Some(trait_pred.def_id()) + } else { + false + } + }) + { + return; + } + let sugg = snippet(cx, recv.span, "").into_owned(); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 812c4df4ddde5..3a08531cf1c9c 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -1,4 +1,4 @@ -use clippy_utils::{MaybePath, get_attr, higher, path_def_id}; +use clippy_utils::{MaybePath, get_attr, higher, path_def_id, sym}; use itertools::Itertools; use rustc_ast::LitIntType; use rustc_ast::ast::{LitFloatType, LitKind}; @@ -826,5 +826,5 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { fn has_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool { let attrs = cx.tcx.hir_attrs(hir_id); - get_attr(cx.sess(), attrs, "author").count() > 0 + get_attr(cx.sess(), attrs, sym::author).count() > 0 } diff --git a/clippy_lints/src/utils/dump_hir.rs b/clippy_lints/src/utils/dump_hir.rs index 9910be9bc2853..d6cf07fdaf3f8 100644 --- a/clippy_lints/src/utils/dump_hir.rs +++ b/clippy_lints/src/utils/dump_hir.rs @@ -1,4 +1,4 @@ -use clippy_utils::get_attr; +use clippy_utils::{get_attr, sym}; use hir::TraitItem; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -60,5 +60,5 @@ impl<'tcx> LateLintPass<'tcx> for DumpHir { fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool { let attrs = cx.tcx.hir_attrs(hir_id); - get_attr(cx.sess(), attrs, "dump").count() > 0 + get_attr(cx.sess(), attrs, sym::dump).count() > 0 } diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 3346b15dae9ca..7b6a25123e85e 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -8,14 +8,14 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::is_copy; use clippy_utils::visitors::for_each_local_use_after_expr; -use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method, span_contains_comment}; +use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method, span_contains_comment, sym}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, LetStmt, Mutability, Node, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::layout::LayoutOf; use rustc_session::impl_lint_pass; -use rustc_span::{DesugaringKind, Span, sym}; +use rustc_span::{DesugaringKind, Span}; pub struct UselessVec { too_large_for_stack: u64, @@ -249,10 +249,8 @@ fn adjusts_to_slice(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { /// that also exists on slices. If this returns true, it means that /// this expression does not actually require a `Vec` and could just work with an array. pub fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { - const ALLOWED_METHOD_NAMES: &[&str] = &["len", "as_ptr", "is_empty"]; - if let ExprKind::MethodCall(path, _, [], _) = e.kind { - ALLOWED_METHOD_NAMES.contains(&path.ident.name.as_str()) + matches!(path.ident.name, sym::as_ptr | sym::is_empty | sym::len) } else { is_trait_method(cx, e, sym::IntoIterator) } diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs index 24b1381ba458c..1550872bca2b9 100644 --- a/clippy_lints/src/zero_sized_map_values.rs +++ b/clippy_lints/src/zero_sized_map_values.rs @@ -51,9 +51,11 @@ impl LateLintPass<'_> for ZeroSizedMapValues { && (is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap)) && let ty::Adt(_, args) = ty.kind() && let ty = args.type_at(1) - // Fixes https://github.com/rust-lang/rust-clippy/issues/7447 because of - // https://github.com/rust-lang/rust/blob/master/compiler/rustc_middle/src/ty/sty.rs#L968 - && !ty.has_escaping_bound_vars() + // Ensure that no type information is missing, to avoid a delayed bug in the compiler if this is not the case. + // This might happen when computing a reference/pointer metadata on a type for which we + // cannot check if it is `Sized` or not, such as an incomplete associated type in a + // type alias. See an example in `issue14822()` of `tests/ui/zero_sized_hashmap_values.rs`. + && !ty.has_non_region_param() && let Ok(layout) = cx.layout_of(ty) && layout.is_zst() { diff --git a/clippy_lints_internal/src/almost_standard_lint_formulation.rs b/clippy_lints_internal/src/almost_standard_lint_formulation.rs index 4fd5ea459a554..311f76fee6b8b 100644 --- a/clippy_lints_internal/src/almost_standard_lint_formulation.rs +++ b/clippy_lints_internal/src/almost_standard_lint_formulation.rs @@ -3,8 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use regex::Regex; use rustc_hir::{Attribute, Item, ItemKind, Mutability}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_lint_defs::declare_tool_lint; -use rustc_session::impl_lint_pass; +use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_tool_lint! { /// ### What it does diff --git a/clippy_lints_internal/src/collapsible_calls.rs b/clippy_lints_internal/src/collapsible_calls.rs index 407deb45db0a7..7c9e7286925ef 100644 --- a/clippy_lints_internal/src/collapsible_calls.rs +++ b/clippy_lints_internal/src/collapsible_calls.rs @@ -4,8 +4,7 @@ use clippy_utils::{SpanlessEq, is_lint_allowed, peel_blocks_with_stmt}; use rustc_errors::Applicability; use rustc_hir::{Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_lint_defs::declare_tool_lint; -use rustc_session::declare_lint_pass; +use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; use std::borrow::{Borrow, Cow}; diff --git a/clippy_lints_internal/src/lint_without_lint_pass.rs b/clippy_lints_internal/src/lint_without_lint_pass.rs index 655d8fb8d1bfb..0edeef3ab8559 100644 --- a/clippy_lints_internal/src/lint_without_lint_pass.rs +++ b/clippy_lints_internal/src/lint_without_lint_pass.rs @@ -10,9 +10,8 @@ use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_hir::intravisit::Visitor; use rustc_hir::{ExprKind, HirId, Item, MutTy, Mutability, Path, TyKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_lint_defs::declare_tool_lint; use rustc_middle::hir::nested_filter; -use rustc_session::impl_lint_pass; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Spanned; use rustc_span::symbol::Symbol; use rustc_span::{Span, sym}; diff --git a/clippy_lints_internal/src/msrv_attr_impl.rs b/clippy_lints_internal/src/msrv_attr_impl.rs index d48d8dc57b240..441c688485236 100644 --- a/clippy_lints_internal/src/msrv_attr_impl.rs +++ b/clippy_lints_internal/src/msrv_attr_impl.rs @@ -4,9 +4,8 @@ use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_lint_defs::declare_tool_lint; use rustc_middle::ty::{self, EarlyBinder, GenericArgKind}; -use rustc_session::declare_lint_pass; +use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_tool_lint! { /// ### What it does diff --git a/clippy_lints_internal/src/outer_expn_data_pass.rs b/clippy_lints_internal/src/outer_expn_data_pass.rs index 40951443a48a9..5cdc66ae90536 100644 --- a/clippy_lints_internal/src/outer_expn_data_pass.rs +++ b/clippy_lints_internal/src/outer_expn_data_pass.rs @@ -1,12 +1,11 @@ use crate::internal_paths; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{is_lint_allowed, method_calls}; +use clippy_utils::{is_lint_allowed, method_calls, sym}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_lint_defs::declare_tool_lint; use rustc_session::declare_lint_pass; -use rustc_span::symbol::Symbol; declare_tool_lint! { /// ### What it does @@ -40,8 +39,7 @@ impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass { } let (method_names, arg_lists, spans) = method_calls(expr, 2); - let method_names: Vec<&str> = method_names.iter().map(Symbol::as_str).collect(); - if let ["expn_data", "outer_expn"] = method_names.as_slice() + if let [sym::expn_data, sym::outer_expn] = method_names.as_slice() && let (self_arg, args) = arg_lists[1] && args.is_empty() && let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs() diff --git a/clippy_lints_internal/src/produce_ice.rs b/clippy_lints_internal/src/produce_ice.rs index 14e93dc6d5f13..3a813b4b9a223 100644 --- a/clippy_lints_internal/src/produce_ice.rs +++ b/clippy_lints_internal/src/produce_ice.rs @@ -1,8 +1,7 @@ use rustc_ast::ast::NodeId; use rustc_ast::visit::FnKind; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_lint_defs::declare_tool_lint; -use rustc_session::declare_lint_pass; +use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; declare_tool_lint! { diff --git a/clippy_lints_internal/src/symbols.rs b/clippy_lints_internal/src/symbols.rs index 5aee545fb0f5b..7b5d58824c38f 100644 --- a/clippy_lints_internal/src/symbols.rs +++ b/clippy_lints_internal/src/symbols.rs @@ -6,10 +6,9 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind, Lit, Node, Pat, PatExprKind, PatKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_lint_defs::declare_tool_lint; use rustc_middle::mir::ConstValue; use rustc_middle::ty; -use rustc_session::impl_lint_pass; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::Symbol; use rustc_span::{Span, sym}; diff --git a/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs b/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs index 8e281ecb2ee44..9ca4ae31d455c 100644 --- a/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs +++ b/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::span_lint; +use clippy_utils::sym; use rustc_ast::ast::{Crate, ItemKind, ModKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_lint_defs::declare_tool_lint; -use rustc_session::declare_lint_pass; +use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_tool_lint! { /// ### What it does @@ -26,11 +26,11 @@ impl EarlyLintPass for UnsortedClippyUtilsPaths { if let Some(utils) = krate .items .iter() - .find(|item| item.kind.ident().is_some_and(|i| i.name.as_str() == "utils")) + .find(|item| item.kind.ident().is_some_and(|i| i.name == sym::utils)) && let ItemKind::Mod(_, _, ModKind::Loaded(ref items, ..)) = utils.kind && let Some(paths) = items .iter() - .find(|item| item.kind.ident().is_some_and(|i| i.name.as_str() == "paths")) + .find(|item| item.kind.ident().is_some_and(|i| i.name == sym::paths)) && let ItemKind::Mod(_, _, ModKind::Loaded(ref items, ..)) = paths.kind { let mut last_name: Option = None; diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index ac970e1c4b0a5..615c0995e8b17 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -1,8 +1,6 @@ [package] name = "clippy_utils" -# begin autogenerated version version = "0.1.89" -# end autogenerated version edition = "2024" description = "Helpful tools for writing lints, provided as they are used in Clippy" repository = "https://github.com/rust-lang/rust-clippy" diff --git a/clippy_utils/README.md b/clippy_utils/README.md index d4080d06d3ca8..c9083f654c4cb 100644 --- a/clippy_utils/README.md +++ b/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: ``` -nightly-2025-05-14 +nightly-2025-05-21 ``` diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 09de5c055379f..8a0ff5323c98d 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -5,11 +5,11 @@ use rustc_lexer::TokenKind; use rustc_lint::LateContext; use rustc_middle::ty::{AdtDef, TyCtxt}; use rustc_session::Session; -use rustc_span::{Span, sym}; +use rustc_span::{Span, Symbol}; use std::str::FromStr; use crate::source::SpanRangeExt; -use crate::tokenize_with_text; +use crate::{sym, tokenize_with_text}; /// Deprecation status of attributes known by Clippy. pub enum DeprecationStatus { @@ -21,17 +21,17 @@ pub enum DeprecationStatus { } #[rustfmt::skip] -pub const BUILTIN_ATTRIBUTES: &[(&str, DeprecationStatus)] = &[ - ("author", DeprecationStatus::None), - ("version", DeprecationStatus::None), - ("cognitive_complexity", DeprecationStatus::None), - ("cyclomatic_complexity", DeprecationStatus::Replaced("cognitive_complexity")), - ("dump", DeprecationStatus::None), - ("msrv", DeprecationStatus::None), +pub const BUILTIN_ATTRIBUTES: &[(Symbol, DeprecationStatus)] = &[ + (sym::author, DeprecationStatus::None), + (sym::version, DeprecationStatus::None), + (sym::cognitive_complexity, DeprecationStatus::None), + (sym::cyclomatic_complexity, DeprecationStatus::Replaced("cognitive_complexity")), + (sym::dump, DeprecationStatus::None), + (sym::msrv, DeprecationStatus::None), // The following attributes are for the 3rd party crate authors. // See book/src/attribs.md - ("has_significant_drop", DeprecationStatus::None), - ("format_args", DeprecationStatus::None), + (sym::has_significant_drop, DeprecationStatus::None), + (sym::format_args, DeprecationStatus::None), ]; pub struct LimitStack { @@ -52,11 +52,11 @@ impl LimitStack { pub fn limit(&self) -> u64 { *self.stack.last().expect("there should always be a value in the stack") } - pub fn push_attrs(&mut self, sess: &Session, attrs: &[impl AttributeExt], name: &'static str) { + pub fn push_attrs(&mut self, sess: &Session, attrs: &[impl AttributeExt], name: Symbol) { let stack = &mut self.stack; parse_attrs(sess, attrs, name, |val| stack.push(val)); } - pub fn pop_attrs(&mut self, sess: &Session, attrs: &[impl AttributeExt], name: &'static str) { + pub fn pop_attrs(&mut self, sess: &Session, attrs: &[impl AttributeExt], name: Symbol) { let stack = &mut self.stack; parse_attrs(sess, attrs, name, |val| assert_eq!(stack.pop(), Some(val))); } @@ -65,7 +65,7 @@ impl LimitStack { pub fn get_attr<'a, A: AttributeExt + 'a>( sess: &'a Session, attrs: &'a [A], - name: &'static str, + name: Symbol, ) -> impl Iterator { attrs.iter().filter(move |attr| { let Some(attr_segments) = attr.ident_path() else { @@ -75,8 +75,8 @@ pub fn get_attr<'a, A: AttributeExt + 'a>( if attr_segments.len() == 2 && attr_segments[0].name == sym::clippy { BUILTIN_ATTRIBUTES .iter() - .find_map(|&(builtin_name, ref deprecation_status)| { - if attr_segments[1].name.as_str() == builtin_name { + .find_map(|(builtin_name, deprecation_status)| { + if attr_segments[1].name == *builtin_name { Some(deprecation_status) } else { None @@ -108,7 +108,7 @@ pub fn get_attr<'a, A: AttributeExt + 'a>( }, DeprecationStatus::None => { diag.cancel(); - attr_segments[1].as_str() == name + attr_segments[1].name == name }, } }, @@ -119,9 +119,9 @@ pub fn get_attr<'a, A: AttributeExt + 'a>( }) } -fn parse_attrs(sess: &Session, attrs: &[impl AttributeExt], name: &'static str, mut f: F) { +fn parse_attrs(sess: &Session, attrs: &[impl AttributeExt], name: Symbol, mut f: F) { for attr in get_attr(sess, attrs, name) { - if let Some(ref value) = attr.value_str() { + if let Some(value) = attr.value_str() { if let Ok(value) = FromStr::from_str(value.as_str()) { f(value); } else { @@ -133,7 +133,7 @@ fn parse_attrs(sess: &Session, attrs: &[impl AttributeExt], name: } } -pub fn get_unique_attr<'a, A: AttributeExt>(sess: &'a Session, attrs: &'a [A], name: &'static str) -> Option<&'a A> { +pub fn get_unique_attr<'a, A: AttributeExt>(sess: &'a Session, attrs: &'a [A], name: Symbol) -> Option<&'a A> { let mut unique_attr: Option<&A> = None; for attr in get_attr(sess, attrs, name) { if let Some(duplicate) = unique_attr { diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index b9928b8eed497..6f5b0ec54cd85 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -487,7 +487,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> { ExprKind::Path(ref qpath) => self.qpath(qpath, e.hir_id), ExprKind::Block(block, _) => self.block(block), ExprKind::Lit(lit) => { - if is_direct_expn_of(e.span, "cfg").is_some() { + if is_direct_expn_of(e.span, sym::cfg).is_some() { None } else { Some(lit_to_mir_constant(&lit.node, self.typeck.expr_ty_opt(e))) @@ -565,7 +565,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> { }) }, ExprKind::Lit(lit) => { - if is_direct_expn_of(e.span, "cfg").is_some() { + if is_direct_expn_of(e.span, sym::cfg).is_some() { None } else { match &lit.node { @@ -654,7 +654,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> { span, .. }) = self.tcx.hir_node(body_id.hir_id) - && is_direct_expn_of(*span, "cfg").is_some() + && is_direct_expn_of(*span, sym::cfg).is_some() { return None; } diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index 4543a20cc2cd4..9d38672efada9 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -10,6 +10,7 @@ //! - option-if-let-else use crate::consts::{ConstEvalCtxt, FullInt}; +use crate::sym; use crate::ty::{all_predicates_of, is_copy}; use crate::visitors::is_const_evaluatable; use rustc_hir::def::{DefKind, Res}; @@ -19,7 +20,7 @@ use rustc_hir::{BinOpKind, Block, Expr, ExprKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_middle::ty::adjustment::Adjust; -use rustc_span::{Symbol, sym}; +use rustc_span::Symbol; use std::{cmp, ops}; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] @@ -49,14 +50,13 @@ impl ops::BitOrAssign for EagernessSuggestion { /// Determine the eagerness of the given function call. fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: bool) -> EagernessSuggestion { use EagernessSuggestion::{Eager, Lazy, NoChange}; - let name = name.as_str(); let ty = match cx.tcx.impl_of_method(fn_id) { Some(id) => cx.tcx.type_of(id).instantiate_identity(), None => return Lazy, }; - if (name.starts_with("as_") || name == "len" || name == "is_empty") && have_one_arg { + if (matches!(name, sym::is_empty | sym::len) || name.as_str().starts_with("as_")) && have_one_arg { if matches!( cx.tcx.crate_name(fn_id.krate), sym::std | sym::core | sym::alloc | sym::proc_macro diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index dbb993482902f..6971b488013c4 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -299,7 +299,7 @@ impl<'a> VecArgs<'a> { pub fn hir(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option> { if let ExprKind::Call(fun, args) = expr.kind && let ExprKind::Path(ref qpath) = fun.kind - && is_expn_of(fun.span, "vec").is_some() + && is_expn_of(fun.span, sym::vec).is_some() && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id() { return if cx.tcx.is_diagnostic_item(sym::vec_from_elem, fun_def_id) && args.len() == 2 { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 4fb608a64828a..3a31917657103 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -25,6 +25,7 @@ // FIXME: switch to something more ergonomic here, once available. // (Currently there is no way to opt into sysroot crates without `extern crate`.) +extern crate indexmap; extern crate rustc_abi; extern crate rustc_ast; extern crate rustc_attr_data_structures; @@ -82,7 +83,6 @@ pub use self::hir_utils::{ use core::mem; use core::ops::ControlFlow; use std::collections::hash_map::Entry; -use std::hash::BuildHasherDefault; use std::iter::{once, repeat_n}; use std::sync::{Mutex, MutexGuard, OnceLock}; @@ -92,7 +92,7 @@ use rustc_ast::ast::{self, LitKind, RangeLimits}; use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::packed::Pu128; -use rustc_data_structures::unhash::UnhashMap; +use rustc_data_structures::unhash::UnindexMap; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; @@ -524,12 +524,8 @@ pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx> /// } /// } /// ``` -pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, def_id: LocalDefId) -> Option<&'tcx TraitRef<'tcx>> { - // Get the implemented trait for the current function - let hir_id = cx.tcx.local_def_id_to_hir_id(def_id); - let parent_impl = cx.tcx.hir_get_parent_item(hir_id); - if parent_impl != hir::CRATE_OWNER_ID - && let Node::Item(item) = cx.tcx.hir_node_by_def_id(parent_impl.def_id) +pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, owner: OwnerId) -> Option<&'tcx TraitRef<'tcx>> { + if let Node::Item(item) = cx.tcx.hir_node(cx.tcx.hir_owner_parent(owner)) && let ItemKind::Impl(impl_) = &item.kind { return impl_.of_trait.as_ref(); @@ -1102,13 +1098,13 @@ pub fn method_calls<'tcx>(expr: &'tcx Expr<'tcx>, max_depth: usize) -> (Vec(expr: &'a Expr<'_>, methods: &[&str]) -> Option, &'a [Expr<'a>])>> { +pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[Symbol]) -> Option, &'a [Expr<'a>])>> { let mut current = expr; let mut matched = Vec::with_capacity(methods.len()); for method_name in methods.iter().rev() { // method chains are stored last -> first if let ExprKind::MethodCall(path, receiver, args, _) = current.kind { - if path.ident.name.as_str() == *method_name { + if path.ident.name == *method_name { if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) { return None; } @@ -1494,14 +1490,14 @@ pub fn is_adjusted(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { /// macro `name`. /// See also [`is_direct_expn_of`]. #[must_use] -pub fn is_expn_of(mut span: Span, name: &str) -> Option { +pub fn is_expn_of(mut span: Span, name: Symbol) -> Option { loop { if span.from_expansion() { let data = span.ctxt().outer_expn_data(); let new_span = data.call_site; if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind - && mac_name.as_str() == name + && mac_name == name { return Some(new_span); } @@ -1524,13 +1520,13 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option { /// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only /// from `bar!` by `is_direct_expn_of`. #[must_use] -pub fn is_direct_expn_of(span: Span, name: &str) -> Option { +pub fn is_direct_expn_of(span: Span, name: Symbol) -> Option { if span.from_expansion() { let data = span.ctxt().outer_expn_data(); let new_span = data.call_site; if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind - && mac_name.as_str() == name + && mac_name == name { return Some(new_span); } @@ -1794,11 +1790,11 @@ pub fn in_automatically_derived(tcx: TyCtxt<'_>, id: HirId) -> bool { } /// Checks if the given `DefId` matches the `libc` item. -pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: &str) -> bool { +pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: Symbol) -> bool { let path = cx.get_def_path(did); // libc is meant to be used as a flat list of names, but they're all actually defined in different // modules based on the target platform. Ignore everything but crate name and the item name. - path.first().is_some_and(|s| *s == sym::libc) && path.last().is_some_and(|s| s.as_str() == name) + path.first().is_some_and(|s| *s == sym::libc) && path.last().copied() == Some(name) } /// Returns the list of condition expressions and the list of blocks in a @@ -2197,45 +2193,46 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option(exprs: &[T], mut hash: Hash, mut eq: Eq) -> Vec<(&T, &T)> +pub fn search_same(exprs: &[T], mut hash: Hash, mut eq: Eq) -> Vec> where Hash: FnMut(&T) -> u64, Eq: FnMut(&T, &T) -> bool, { match exprs { - [a, b] if eq(a, b) => return vec![(a, b)], + [a, b] if eq(a, b) => return vec![vec![a, b]], _ if exprs.len() <= 2 => return vec![], _ => {}, } - let mut match_expr_list: Vec<(&T, &T)> = Vec::new(); - - let mut map: UnhashMap> = - UnhashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default()); + let mut buckets: UnindexMap>> = UnindexMap::default(); for expr in exprs { - match map.entry(hash(expr)) { - Entry::Occupied(mut o) => { - for o in o.get() { - if eq(o, expr) { - match_expr_list.push((o, expr)); - } + match buckets.entry(hash(expr)) { + indexmap::map::Entry::Occupied(mut o) => { + let bucket = o.get_mut(); + match bucket.iter_mut().find(|group| eq(expr, group[0])) { + Some(group) => group.push(expr), + None => bucket.push(vec![expr]), } - o.get_mut().push(expr); }, - Entry::Vacant(v) => { - v.insert(vec![expr]); + indexmap::map::Entry::Vacant(v) => { + v.insert(vec![vec![expr]]); }, } } - match_expr_list + buckets + .into_values() + .flatten() + .filter(|group| group.len() > 1) + .collect() } /// Peels off all references on the pattern. Returns the underlying pattern and the number of diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index dfb30b9c21864..ba126fcd05de9 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -2,8 +2,8 @@ use std::sync::{Arc, OnceLock}; -use crate::get_unique_attr; use crate::visitors::{Descend, for_each_expr_without_closures}; +use crate::{get_unique_attr, sym}; use arrayvec::ArrayVec; use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder}; @@ -12,7 +12,7 @@ use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath}; use rustc_lint::{LateContext, LintContext}; use rustc_span::def_id::DefId; use rustc_span::hygiene::{self, MacroKind, SyntaxContext}; -use rustc_span::{BytePos, ExpnData, ExpnId, ExpnKind, Span, SpanData, Symbol, sym}; +use rustc_span::{BytePos, ExpnData, ExpnId, ExpnKind, Span, SpanData, Symbol}; use std::ops::ControlFlow; const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[ @@ -42,7 +42,7 @@ pub fn is_format_macro(cx: &LateContext<'_>, macro_def_id: DefId) -> bool { } else { // Allow users to tag any macro as being format!-like // TODO: consider deleting FORMAT_MACRO_DIAG_ITEMS and using just this method - get_unique_attr(cx.sess(), cx.tcx.get_attrs_unchecked(macro_def_id), "format_args").is_some() + get_unique_attr(cx.sess(), cx.tcx.get_attrs_unchecked(macro_def_id), sym::format_args).is_some() } } @@ -248,10 +248,10 @@ impl<'a> PanicExpn<'a> { let ExprKind::Path(QPath::Resolved(_, path)) = &callee.kind else { return None; }; - let name = path.segments.last().unwrap().ident.as_str(); + let name = path.segments.last().unwrap().ident.name; // This has no argument - if name == "panic_cold_explicit" { + if name == sym::panic_cold_explicit { return Some(Self::Empty); } @@ -259,18 +259,18 @@ impl<'a> PanicExpn<'a> { return None; }; let result = match name { - "panic" if arg.span.eq_ctxt(expr.span) => Self::Empty, - "panic" | "panic_str" => Self::Str(arg), - "panic_display" | "panic_cold_display" => { + sym::panic if arg.span.eq_ctxt(expr.span) => Self::Empty, + sym::panic | sym::panic_str => Self::Str(arg), + sym::panic_display | sym::panic_cold_display => { let ExprKind::AddrOf(_, _, e) = &arg.kind else { return None; }; Self::Display(e) }, - "panic_fmt" => Self::Format(arg), + sym::panic_fmt => Self::Format(arg), // Since Rust 1.52, `assert_{eq,ne}` macros expand to use: // `core::panicking::assert_failed(.., left_val, right_val, None | Some(format_args!(..)));` - "assert_failed" => { + sym::assert_failed => { // It should have 4 arguments in total (we already matched with the first argument, // so we're just checking for 3) if rest.len() != 3 { diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 599c6f3a4ff33..a5e66ad463bbb 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -25,7 +25,7 @@ macro_rules! msrv_aliases { msrv_aliases! { 1,88,0 { LET_CHAINS } 1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT } - 1,85,0 { UINT_FLOAT_MIDPOINT } + 1,85,0 { UINT_FLOAT_MIDPOINT, CONST_SIZE_OF_VAL } 1,84,0 { CONST_OPTION_AS_SLICE, MANUAL_DANGLING_PTR } 1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP } 1,82,0 { IS_NONE_OR, REPEAT_N, RAW_REF_OP } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index e5179e479ccd9..9d7f3086b05fa 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -129,6 +129,7 @@ path_macros! { // Paths in `core`/`alloc`/`std`. This should be avoided and cleaned up by adding diagnostic items. pub static ALIGN_OF: PathLookup = value_path!(core::mem::align_of); pub static CHAR_TO_DIGIT: PathLookup = value_path!(char::to_digit); +pub static CONCAT: PathLookup = macro_path!(core::concat); pub static IO_ERROR_NEW: PathLookup = value_path!(std::io::Error::new); pub static IO_ERRORKIND_OTHER_CTOR: PathLookup = value_path!(std::io::ErrorKind::Other); pub static ITER_STEP: PathLookup = type_path!(core::iter::Step); diff --git a/clippy_utils/src/ptr.rs b/clippy_utils/src/ptr.rs index 360c6251a57c2..5847e916e340f 100644 --- a/clippy_utils/src/ptr.rs +++ b/clippy_utils/src/ptr.rs @@ -1,17 +1,17 @@ use crate::source::snippet; use crate::visitors::{Descend, for_each_expr_without_closures}; -use crate::{path_to_local_id, strip_pat_refs}; +use crate::{path_to_local_id, strip_pat_refs, sym}; use core::ops::ControlFlow; use rustc_hir::{Body, BodyId, ExprKind, HirId, PatKind}; use rustc_lint::LateContext; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use std::borrow::Cow; pub fn get_spans( cx: &LateContext<'_>, opt_body_id: Option, idx: usize, - replacements: &[(&'static str, &'static str)], + replacements: &[(Symbol, &'static str)], ) -> Option)>> { if let Some(body) = opt_body_id.map(|id| cx.tcx.hir_body(id)) { if let PatKind::Binding(_, binding_id, _, _) = strip_pat_refs(body.params[idx].pat).kind { @@ -27,7 +27,7 @@ pub fn get_spans( fn extract_clone_suggestions<'tcx>( cx: &LateContext<'tcx>, id: HirId, - replace: &[(&'static str, &'static str)], + replace: &[(Symbol, &'static str)], body: &'tcx Body<'_>, ) -> Option)>> { let mut spans = Vec::new(); @@ -35,11 +35,11 @@ fn extract_clone_suggestions<'tcx>( if let ExprKind::MethodCall(seg, recv, [], _) = e.kind && path_to_local_id(recv, id) { - if seg.ident.as_str() == "capacity" { + if seg.ident.name == sym::capacity { return ControlFlow::Break(()); } for &(fn_name, suffix) in replace { - if seg.ident.as_str() == fn_name { + if seg.ident.name == fn_name { spans.push((e.span, snippet(cx, recv.span, "_") + suffix)); return ControlFlow::Continue(Descend::No); } diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index 8645d5730fedb..7f2bf99daff20 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -7,13 +7,14 @@ use std::sync::Arc; use rustc_ast::{LitKind, StrStyle}; use rustc_errors::Applicability; use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource}; +use rustc_lexer::{LiteralKind, TokenKind, tokenize}; use rustc_lint::{EarlyContext, LateContext}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::source_map::{SourceMap, original_sp}; use rustc_span::{ - BytePos, DUMMY_SP, FileNameDisplayPreference, Pos, SourceFile, SourceFileAndLine, Span, SpanData, SyntaxContext, - hygiene, + BytePos, DUMMY_SP, FileNameDisplayPreference, Pos, RelativeBytePos, SourceFile, SourceFileAndLine, Span, SpanData, + SyntaxContext, hygiene, }; use std::borrow::Cow; use std::fmt; @@ -137,25 +138,25 @@ pub trait SpanRangeExt: SpanRange { fn map_range( self, cx: &impl HasSession, - f: impl for<'a> FnOnce(&'a str, Range) -> Option>, + f: impl for<'a> FnOnce(&'a SourceFile, &'a str, Range) -> Option>, ) -> Option> { map_range(cx.sess().source_map(), self.into_range(), f) } #[allow(rustdoc::invalid_rust_codeblocks, reason = "The codeblock is intentionally broken")] - /// Extends the range to include all preceding whitespace characters, unless there - /// are non-whitespace characters left on the same line after `self`. + /// Extends the range to include all preceding whitespace characters. + /// + /// The range will not be expanded if it would cross a line boundary, the line the range would + /// be extended to ends with a line comment and the text after the range contains a + /// non-whitespace character on the same line. e.g. /// - /// This extra condition prevents a problem when removing the '}' in: /// ```ignore - /// ( // There was an opening bracket after the parenthesis, which has been removed - /// // This is a comment - /// }) + /// ( // Some comment + /// foo) /// ``` - /// Removing the whitespaces, including the linefeed, before the '}', would put the - /// closing parenthesis at the end of the `// This is a comment` line, which would - /// make it part of the comment as well. In this case, it is best to keep the span - /// on the '}' alone. + /// + /// When the range points to `foo`, suggesting to remove the range after it's been extended will + /// cause the `)` to be placed inside the line comment as `( // Some comment)`. fn with_leading_whitespace(self, cx: &impl HasSession) -> Range { with_leading_whitespace(cx.sess().source_map(), self.into_range()) } @@ -254,11 +255,11 @@ fn with_source_text_and_range( fn map_range( sm: &SourceMap, sp: Range, - f: impl for<'a> FnOnce(&'a str, Range) -> Option>, + f: impl for<'a> FnOnce(&'a SourceFile, &'a str, Range) -> Option>, ) -> Option> { if let Some(src) = get_source_range(sm, sp.clone()) && let Some(text) = &src.sf.src - && let Some(range) = f(text, src.range.clone()) + && let Some(range) = f(&src.sf, text, src.range.clone()) { debug_assert!( range.start <= text.len() && range.end <= text.len(), @@ -275,20 +276,57 @@ fn map_range( } } +fn ends_with_line_comment_or_broken(text: &str) -> bool { + let Some(last) = tokenize(text).last() else { + return false; + }; + match last.kind { + // Will give the wrong result on text like `" // "` where the first quote ends a string + // started earlier. The only workaround is to lex the whole file which we don't really want + // to do. + TokenKind::LineComment { .. } | TokenKind::BlockComment { terminated: false, .. } => true, + TokenKind::Literal { kind, .. } => matches!( + kind, + LiteralKind::Byte { terminated: false } + | LiteralKind::ByteStr { terminated: false } + | LiteralKind::CStr { terminated: false } + | LiteralKind::Char { terminated: false } + | LiteralKind::RawByteStr { n_hashes: None } + | LiteralKind::RawCStr { n_hashes: None } + | LiteralKind::RawStr { n_hashes: None } + ), + _ => false, + } +} + +fn with_leading_whitespace_inner(lines: &[RelativeBytePos], src: &str, range: Range) -> Option { + debug_assert!(lines.is_empty() || lines[0].to_u32() == 0); + + let start = src.get(..range.start)?.trim_end(); + let next_line = lines.partition_point(|&pos| pos.to_usize() <= start.len()); + if let Some(line_end) = lines.get(next_line) + && line_end.to_usize() <= range.start + && let prev_start = lines.get(next_line - 1).map_or(0, |&x| x.to_usize()) + && ends_with_line_comment_or_broken(&start[prev_start..]) + && let next_line = lines.partition_point(|&pos| pos.to_usize() < range.end) + && let next_start = lines.get(next_line).map_or(src.len(), |&x| x.to_usize()) + && tokenize(src.get(range.end..next_start)?).any(|t| !matches!(t.kind, TokenKind::Whitespace)) + { + Some(range.start) + } else { + Some(start.len()) + } +} + fn with_leading_whitespace(sm: &SourceMap, sp: Range) -> Range { - map_range(sm, sp, |src, range| { - let non_blank_after = src.len() - src.get(range.end..)?.trim_start().len(); - if src.get(range.end..non_blank_after)?.contains(['\r', '\n']) { - Some(src.get(..range.start)?.trim_end().len()..range.end) - } else { - Some(range) - } + map_range(sm, sp.clone(), |sf, src, range| { + Some(with_leading_whitespace_inner(sf.lines(), src, range.clone())?..range.end) }) - .unwrap() + .unwrap_or(sp) } fn trim_start(sm: &SourceMap, sp: Range) -> Range { - map_range(sm, sp.clone(), |src, range| { + map_range(sm, sp.clone(), |_, src, range| { let src = src.get(range.clone())?; Some(range.start + (src.len() - src.trim_start().len())..range.end) }) diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index 9428262b99aa7..f417530be3672 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -29,172 +29,330 @@ macro_rules! generate { }; } +// List of extra symbols to be included in Clippy (for example, as `sym::ambiguous_glob_reexports`). +// An alternative content can be specified using a colon after the symbol name. +// +// `cargo dev fmt` ensures that the content of the `generate!()` macro call stays sorted. generate! { + AsyncReadExt, + AsyncWriteExt, + BACKSLASH_SINGLE_QUOTE: r"\'", + Binary, + CLIPPY_ARGS, + CLIPPY_CONF_DIR, + CRLF: "\r\n", + Cargo_toml: "Cargo.toml", + Current, + DOUBLE_QUOTE: "\"", + Deserialize, + EarlyLintPass, + ErrorKind, + IntoIter, + Itertools, + LF: "\n", + Lazy, + Lint, + LowerExp, + LowerHex, + MAX, + MIN, + MsrvStack, + Octal, + OpenOptions, + Other, + PathLookup, + Regex, + RegexBuilder, + RegexSet, + Start, + Step, + Symbol, + SyntaxContext, + TBD, + UpperExp, + UpperHex, + V4, + V6, + Visitor, + Weak, abs, align_of, ambiguous_glob_reexports, + append, + arg, as_bytes, - as_deref_mut, as_deref, + as_deref_mut, as_mut, - AsyncReadExt, - AsyncWriteExt, - BACKSLASH_SINGLE_QUOTE: r"\'", - Binary, + assert_failed, + author, + borrow, + borrow_mut, build_hasher, + by_ref, bytes, + capacity, cargo_clippy: "cargo-clippy", - Cargo_toml: "Cargo.toml", cast, + cast_const, + cast_mut, + ceil, + ceil_char_boundary, + chain, chars, - CLIPPY_ARGS, - CLIPPY_CONF_DIR, + checked_abs, + checked_add, + checked_isqrt, + checked_mul, + checked_pow, + checked_rem_euclid, + checked_sub, + clamp, clippy_utils, clone_into, cloned, + cognitive_complexity, collect, const_ptr, contains, copied, - CRLF: "\r\n", - Current, + copy_from, + copy_from_nonoverlapping, + copy_to, + copy_to_nonoverlapping, + count_ones, + cycle, + cyclomatic_complexity, de, - Deserialize, diagnostics, disallowed_types, - DOUBLE_QUOTE: "\"", - EarlyLintPass, + drain, + dump, ends_with, enum_glob_use, + enumerate, + err, error, - ErrorKind, exp, + expect_err, + expn_data, extend, - finish_non_exhaustive, + filter, + filter_map, + find, + find_map, finish, + finish_non_exhaustive, + first, flat_map, + flatten, + floor, + floor_char_boundary, + fold, for_each, - from_bytes_with_nul_unchecked, from_bytes_with_nul, + from_bytes_with_nul_unchecked, from_ptr, from_raw, from_ref, + from_str, from_str_radix, fs, + fuse, futures_util, get, + get_mut, + get_or_insert_with, + get_unchecked, + get_unchecked_mut, + has_significant_drop, hidden_glob_reexports, hygiene, + if_chain, insert, + inspect, int_roundings, + into, into_bytes, + into_ok, into_owned, - IntoIter, io, is_ascii, + is_char_boundary, + is_digit, is_empty, is_err, + is_file, is_none, is_ok, is_some, + isqrt, itertools, - Itertools, + join, kw, last, lazy_static, - Lazy, - LF: "\n", - Lint, ln, + lock, lock_api, log, - LowerExp, - LowerHex, + log10, + log2, macro_use_imports, - map_or_else, + map_break, + map_continue, map_or, + map_or_else, + match_indices, + matches, max, - MAX, + max_by, + max_by_key, + max_value, + maximum, mem, min, - MIN, + min_by, + min_by_key, + min_value, + minimum, mode, module_name_repetitions, msrv, msrvs, - MsrvStack, mut_ptr, mutex, needless_return, + next_back, + next_if, + next_if_eq, next_tuple, - Octal, + nth, + ok, + ok_or, once_cell, - OpenOptions, + open, or_default, - Other, + or_else, + or_insert, + or_insert_with, + outer_expn, + panic_cold_display, + panic_cold_explicit, + panic_display, + panic_str, parse, - PathLookup, + partition, paths, + peek, + peek_mut, + peekable, + pow, powf, powi, + product, push, + read_line, + read_to_end, + read_to_string, redundant_pub_crate, regex, - Regex, - RegexBuilder, - RegexSet, + rem_euclid, + repeat, + replace, + replacen, reserve, resize, restriction, - rustc_lint_defs, + rev, + rfind, + rmatch_indices, + rmatches, + round, + rposition, + rsplit, + rsplit_once, + rsplit_terminator, + rsplitn, + rsplitn_mut, rustc_lint, + rustc_lint_defs, rustc_span, rustfmt_skip, rwlock, + saturating_abs, + saturating_pow, + scan, + seek, serde, set_len, set_mode, set_readonly, signum, single_component_path_imports, + skip_while, + slice_mut_unchecked, + slice_unchecked, + sort, + sort_by, + sort_unstable_by, span_lint_and_then, - split_whitespace, split, + split_at, + split_at_checked, + split_at_mut, + split_at_mut_checked, + split_inclusive, + split_once, + split_terminator, + split_whitespace, + splitn, + splitn_mut, sqrt, - Start, - Step, + starts_with, + step_by, + strlen, style, + subsec_micros, + subsec_nanos, + sum, symbol, - Symbol, - SyntaxContext, take, - TBD, + take_while, + then, then_some, to_ascii_lowercase, to_ascii_uppercase, to_digit, to_lowercase, + to_os_string, to_owned, + to_path_buf, to_uppercase, tokio, + trim, + trim_end_matches, + trim_start_matches, unreachable_pub, unsafe_removed_from_name, + unused, unused_braces, unused_extern_crates, unused_import_braces, unused_trait_names, - unused, unwrap_err, + unwrap_err_unchecked, unwrap_or_default, unwrap_or_else, - UpperExp, - UpperHex, - V4, - V6, - Visitor, + unwrap_unchecked, + unzip, + utils, + wake, warnings, - Weak, wildcard_imports, with_capacity, wrapping_offset, + write, + writeln, + zip, } diff --git a/clippy_utils/src/ty/mod.rs b/clippy_utils/src/ty/mod.rs index 26d41cfb4977b..c50ad17bfad1e 100644 --- a/clippy_utils/src/ty/mod.rs +++ b/clippy_utils/src/ty/mod.rs @@ -1361,3 +1361,14 @@ pub fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { || ty.is_array() || matches!(ty.kind(), ty::Adt(adt_def, _) if cx.tcx.is_diagnostic_item(sym::Vec, adt_def.did())) } + +/// Gets the index of a field by name. +pub fn get_field_idx_by_name(ty: Ty<'_>, name: Symbol) -> Option { + match *ty.kind() { + ty::Adt(def, _) if def.is_union() || def.is_struct() => { + def.non_enum_variant().fields.iter().position(|f| f.name == name) + }, + ty::Tuple(_) => name.as_str().parse::().ok(), + _ => None, + } +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml index da41bdd27bcb6..0b9ebe554f5b4 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2025-05-14" +channel = "nightly-2025-05-21" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/src/driver.rs b/src/driver.rs index f8acf88cf81c6..37adb14169a3f 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -96,16 +96,11 @@ fn track_files(psess: &mut ParseSess) { // During development track the `clippy-driver` executable so that cargo will re-run clippy whenever // it is rebuilt - #[expect( - clippy::collapsible_if, - reason = "Due to a bug in let_chains this if statement can't be collapsed" - )] - if cfg!(debug_assertions) { - if let Ok(current_exe) = env::current_exe() - && let Some(current_exe) = current_exe.to_str() - { - file_depinfo.insert(Symbol::intern(current_exe)); - } + if cfg!(debug_assertions) + && let Ok(current_exe) = env::current_exe() + && let Some(current_exe) = current_exe.to_str() + { + file_depinfo.insert(Symbol::intern(current_exe)); } } diff --git a/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default.stderr b/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default.stderr index 50567e32b1bb9..a3c35a31c3314 100644 --- a/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default.stderr +++ b/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default.stderr @@ -13,37 +13,37 @@ LL | const SNAKE_CASE: &str = "zzzzzzzz"; = help: to override `-D warnings` add `#[allow(clippy::arbitrary_source_item_ordering)]` error: incorrect ordering of items (module item groupings specify another order) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:149:7 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:165:7 | LL | const ZIS_SHOULD_BE_REALLY_EARLY: () = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `TraitUnorderedItemKinds` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:136:7 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:152:7 | LL | trait TraitUnorderedItemKinds { | ^^^^^^^^^^^^^^^^^^^^^^^ error: incorrect ordering of items (module item groupings specify another order) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:188:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:204:5 | LL | mod this_is_in_the_wrong_position { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `main` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:183:4 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:199:4 | LL | fn main() { | ^^^^ error: incorrect ordering of items (module item groupings specify another order) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:198:7 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:214:7 | LL | const ZIS_SHOULD_BE_EVEN_EARLIER: () = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `ZisShouldBeBeforeZeMainFn` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:196:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:212:8 | LL | struct ZisShouldBeBeforeZeMainFn; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,100 +61,124 @@ LL | C, | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:96:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:5 + | +LL | g: u8, + | ^ + | +note: should be placed before `r` + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:56:5 + | +LL | r: u8, + | ^ + +error: incorrect ordering of items (must be alphabetically ordered) + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:59:5 + | +LL | b: u8, + | ^ + | +note: should be placed before `g` + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:5 + | +LL | g: u8, + | ^ + +error: incorrect ordering of items (must be alphabetically ordered) + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:112:5 | LL | b: bool, | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:95:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:111:5 | LL | c: bool, | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:105:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:121:5 | LL | b: bool, | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:104:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:120:5 | LL | c: bool, | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:125:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:141:11 | LL | const B: bool; | ^ | note: should be placed before `C` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:124:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:140:11 | LL | const C: bool; | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:132:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:148:8 | LL | fn b(); | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:131:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:147:8 | LL | fn c(); | ^ error: incorrect ordering of trait items (defined order: [Const, Type, Fn]) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:139:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:155:5 | LL | const A: bool; | ^^^^^^^^^^^^^^ | note: should be placed before `SomeType` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:137:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:153:5 | LL | type SomeType; | ^^^^^^^^^^^^^^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:155:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:11 | LL | const B: bool = false; | ^ | note: should be placed before `C` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:154:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:170:11 | LL | const C: bool = false; | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:162:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:178:8 | LL | fn b() {} | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:161:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:177:8 | LL | fn c() {} | ^ error: incorrect ordering of impl items (defined order: [Const, Type, Fn]) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:173:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:189:5 | LL | const A: bool = false; | ^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `SomeType` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:187:5 | LL | type SomeType = (); | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 13 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default_exp.stderr b/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default_exp.stderr index 50567e32b1bb9..a3c35a31c3314 100644 --- a/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default_exp.stderr +++ b/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default_exp.stderr @@ -13,37 +13,37 @@ LL | const SNAKE_CASE: &str = "zzzzzzzz"; = help: to override `-D warnings` add `#[allow(clippy::arbitrary_source_item_ordering)]` error: incorrect ordering of items (module item groupings specify another order) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:149:7 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:165:7 | LL | const ZIS_SHOULD_BE_REALLY_EARLY: () = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `TraitUnorderedItemKinds` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:136:7 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:152:7 | LL | trait TraitUnorderedItemKinds { | ^^^^^^^^^^^^^^^^^^^^^^^ error: incorrect ordering of items (module item groupings specify another order) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:188:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:204:5 | LL | mod this_is_in_the_wrong_position { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `main` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:183:4 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:199:4 | LL | fn main() { | ^^^^ error: incorrect ordering of items (module item groupings specify another order) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:198:7 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:214:7 | LL | const ZIS_SHOULD_BE_EVEN_EARLIER: () = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `ZisShouldBeBeforeZeMainFn` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:196:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:212:8 | LL | struct ZisShouldBeBeforeZeMainFn; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,100 +61,124 @@ LL | C, | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:96:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:5 + | +LL | g: u8, + | ^ + | +note: should be placed before `r` + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:56:5 + | +LL | r: u8, + | ^ + +error: incorrect ordering of items (must be alphabetically ordered) + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:59:5 + | +LL | b: u8, + | ^ + | +note: should be placed before `g` + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:5 + | +LL | g: u8, + | ^ + +error: incorrect ordering of items (must be alphabetically ordered) + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:112:5 | LL | b: bool, | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:95:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:111:5 | LL | c: bool, | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:105:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:121:5 | LL | b: bool, | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:104:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:120:5 | LL | c: bool, | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:125:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:141:11 | LL | const B: bool; | ^ | note: should be placed before `C` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:124:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:140:11 | LL | const C: bool; | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:132:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:148:8 | LL | fn b(); | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:131:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:147:8 | LL | fn c(); | ^ error: incorrect ordering of trait items (defined order: [Const, Type, Fn]) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:139:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:155:5 | LL | const A: bool; | ^^^^^^^^^^^^^^ | note: should be placed before `SomeType` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:137:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:153:5 | LL | type SomeType; | ^^^^^^^^^^^^^^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:155:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:11 | LL | const B: bool = false; | ^ | note: should be placed before `C` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:154:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:170:11 | LL | const C: bool = false; | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:162:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:178:8 | LL | fn b() {} | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:161:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:177:8 | LL | fn c() {} | ^ error: incorrect ordering of impl items (defined order: [Const, Type, Fn]) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:173:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:189:5 | LL | const A: bool = false; | ^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `SomeType` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:187:5 | LL | type SomeType = (); | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 13 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.ord_within.stderr b/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.ord_within.stderr index ae5261dcc6df8..3fdd706fc627f 100644 --- a/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.ord_within.stderr +++ b/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.ord_within.stderr @@ -25,7 +25,19 @@ LL | const SNAKE_CASE: &str = "zzzzzzzz"; | ^^^^^^^^^^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:71:1 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:64:8 + | +LL | struct EnumWithExternButAtWrongPosition { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: should be placed before `EnumWithoutExtern` + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:55:8 + | +LL | struct EnumWithoutExtern { + | ^^^^^^^^^^^^^^^^^ + +error: incorrect ordering of items (must be alphabetically ordered) + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:87:1 | LL | / impl CloneSelf for StructOrdered { LL | | @@ -36,7 +48,7 @@ LL | | } | |_^ | note: should be placed before the following item - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:61:1 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:77:1 | LL | / impl Default for StructOrdered { LL | | fn default() -> Self { @@ -47,25 +59,25 @@ LL | | } | |_^ error: incorrect ordering of items (module item groupings specify another order) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:149:7 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:165:7 | LL | const ZIS_SHOULD_BE_REALLY_EARLY: () = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `TraitUnorderedItemKinds` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:136:7 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:152:7 | LL | trait TraitUnorderedItemKinds { | ^^^^^^^^^^^^^^^^^^^^^^^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:167:1 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:183:1 | LL | impl BasicEmptyTrait for StructOrdered {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before the following item - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:152:1 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:168:1 | LL | / impl TraitUnordered for StructUnordered { LL | | const A: bool = false; @@ -76,25 +88,25 @@ LL | | } | |_^ error: incorrect ordering of items (module item groupings specify another order) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:188:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:204:5 | LL | mod this_is_in_the_wrong_position { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `main` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:183:4 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:199:4 | LL | fn main() { | ^^^^ error: incorrect ordering of items (module item groupings specify another order) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:198:7 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:214:7 | LL | const ZIS_SHOULD_BE_EVEN_EARLIER: () = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `ZisShouldBeBeforeZeMainFn` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:196:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:212:8 | LL | struct ZisShouldBeBeforeZeMainFn; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -124,112 +136,136 @@ LL | C, | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:96:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:5 + | +LL | g: u8, + | ^ + | +note: should be placed before `r` + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:56:5 + | +LL | r: u8, + | ^ + +error: incorrect ordering of items (must be alphabetically ordered) + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:59:5 + | +LL | b: u8, + | ^ + | +note: should be placed before `g` + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:5 + | +LL | g: u8, + | ^ + +error: incorrect ordering of items (must be alphabetically ordered) + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:112:5 | LL | b: bool, | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:95:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:111:5 | LL | c: bool, | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:105:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:121:5 | LL | b: bool, | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:104:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:120:5 | LL | c: bool, | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:125:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:141:11 | LL | const B: bool; | ^ | note: should be placed before `C` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:124:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:140:11 | LL | const C: bool; | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:132:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:148:8 | LL | fn b(); | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:131:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:147:8 | LL | fn c(); | ^ error: incorrect ordering of trait items (defined order: [Const, Type, Fn]) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:139:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:155:5 | LL | const A: bool; | ^^^^^^^^^^^^^^ | note: should be placed before `SomeType` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:137:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:153:5 | LL | type SomeType; | ^^^^^^^^^^^^^^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:155:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:11 | LL | const B: bool = false; | ^ | note: should be placed before `C` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:154:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:170:11 | LL | const C: bool = false; | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:162:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:178:8 | LL | fn b() {} | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:161:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:177:8 | LL | fn c() {} | ^ error: incorrect ordering of impl items (defined order: [Const, Type, Fn]) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:173:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:189:5 | LL | const A: bool = false; | ^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `SomeType` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:187:5 | LL | type SomeType = (); | ^^^^^^^^^^^^^^^^^^^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:191:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:207:11 | LL | const A: i8 = 1; | ^ | note: should be placed before `C` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:190:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:206:11 | LL | const C: i8 = 0; | ^ -error: aborting due to 18 previous errors +error: aborting due to 21 previous errors diff --git a/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs b/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs index 90399470d4c09..1cfed9790c120 100644 --- a/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs +++ b/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs @@ -52,6 +52,22 @@ enum EnumUnorderedAllowed { B, } +struct EnumWithoutExtern { + r: u8, + g: u8, + //~^ arbitrary_source_item_ordering + b: u8, + //~^ arbitrary_source_item_ordering +} + +#[repr(C)] +struct EnumWithExternButAtWrongPosition { + //~[ord_within]^ arbitrary_source_item_ordering + r: u8, + g: u8, + b: u8, +} + struct StructOrdered { a: bool, b: bool, diff --git a/tests/ui-toml/collapsible_if/collapsible_if.fixed b/tests/ui-toml/collapsible_if/collapsible_if.fixed index 6f5cc47ba6c75..f695f9804d59c 100644 --- a/tests/ui-toml/collapsible_if/collapsible_if.fixed +++ b/tests/ui-toml/collapsible_if/collapsible_if.fixed @@ -13,7 +13,7 @@ fn main() { //~^^^^^^ collapsible_if // The following tests check for the fix of https://github.com/rust-lang/rust-clippy/issues/798 - if x == "hello" // Inner comment + if x == "hello" // Inner comment && y == "world" { println!("Hello world!"); } @@ -26,7 +26,7 @@ fn main() { } //~^^^^^^ collapsible_if - if x == "hello" /* Inner comment */ + if x == "hello" /* Inner comment */ && y == "world" { println!("Hello world!"); } diff --git a/tests/ui-toml/collapsible_if/collapsible_if.stderr b/tests/ui-toml/collapsible_if/collapsible_if.stderr index 357ce4ad32deb..a12c2112f5877 100644 --- a/tests/ui-toml/collapsible_if/collapsible_if.stderr +++ b/tests/ui-toml/collapsible_if/collapsible_if.stderr @@ -32,7 +32,7 @@ LL | | } | help: collapse nested if block | -LL ~ if x == "hello" // Inner comment +LL ~ if x == "hello" // Inner comment LL ~ && y == "world" { LL | println!("Hello world!"); LL ~ } @@ -70,7 +70,7 @@ LL | | } | help: collapse nested if block | -LL ~ if x == "hello" /* Inner comment */ +LL ~ if x == "hello" /* Inner comment */ LL ~ && y == "world" { LL | println!("Hello world!"); LL ~ } diff --git a/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs b/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs index e953a2a4e90bc..2a6097fb57953 100644 --- a/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs +++ b/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs @@ -11,9 +11,9 @@ fn issue10272() { // should trigger warning let x = Cell::new(true); if x.get() { + //~^ ifs_same_cond } else if !x.take() { } else if x.get() { - //~^ ifs_same_cond } else { } } diff --git a/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr b/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr index d67e7fca6565b..adc44358c4c7b 100644 --- a/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr +++ b/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr @@ -1,14 +1,12 @@ -error: this `if` has the same condition as a previous `if` - --> tests/ui-toml/ifs_same_cond/ifs_same_cond.rs:15:15 - | -LL | } else if x.get() { - | ^^^^^^^ - | -note: same as this +error: these `if` branches have the same condition --> tests/ui-toml/ifs_same_cond/ifs_same_cond.rs:13:8 | LL | if x.get() { | ^^^^^^^ +... +LL | } else if x.get() { + | ^^^^^^^ + | = note: `-D clippy::ifs-same-cond` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::ifs_same_cond)]` diff --git a/tests/ui/assign_ops.fixed b/tests/ui/assign_ops.fixed index 18f0e04a8807e..429c20f95e919 100644 --- a/tests/ui/assign_ops.fixed +++ b/tests/ui/assign_ops.fixed @@ -1,7 +1,9 @@ +#![allow(clippy::useless_vec)] +#![warn(clippy::assign_op_pattern)] + use core::num::Wrapping; +use std::ops::{Mul, MulAssign}; -#[allow(dead_code, unused_assignments, clippy::useless_vec)] -#[warn(clippy::assign_op_pattern)] fn main() { let mut a = 5; a += 1; @@ -39,3 +41,35 @@ fn main() { v[0] = v[0] + v[1]; let _ = || v[0] = v[0] + v[1]; } + +fn cow_add_assign() { + use std::borrow::Cow; + let mut buf = Cow::Owned(String::from("bar")); + let cows = Cow::Borrowed("foo"); + + // this can be linted + buf += cows.clone(); + //~^ assign_op_pattern + + // this should not as cow Add is not commutative + buf = cows + buf; +} + +// check that we don't lint on op assign impls, because that's just the way to impl them + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct Wrap(i64); + +impl Mul for Wrap { + type Output = Self; + + fn mul(self, rhs: i64) -> Self { + Wrap(self.0 * rhs) + } +} + +impl MulAssign for Wrap { + fn mul_assign(&mut self, rhs: i64) { + *self = *self * rhs + } +} diff --git a/tests/ui/assign_ops.rs b/tests/ui/assign_ops.rs index 8b05c74d86040..480ff07f150ea 100644 --- a/tests/ui/assign_ops.rs +++ b/tests/ui/assign_ops.rs @@ -1,7 +1,9 @@ +#![allow(clippy::useless_vec)] +#![warn(clippy::assign_op_pattern)] + use core::num::Wrapping; +use std::ops::{Mul, MulAssign}; -#[allow(dead_code, unused_assignments, clippy::useless_vec)] -#[warn(clippy::assign_op_pattern)] fn main() { let mut a = 5; a = a + 1; @@ -39,3 +41,35 @@ fn main() { v[0] = v[0] + v[1]; let _ = || v[0] = v[0] + v[1]; } + +fn cow_add_assign() { + use std::borrow::Cow; + let mut buf = Cow::Owned(String::from("bar")); + let cows = Cow::Borrowed("foo"); + + // this can be linted + buf = buf + cows.clone(); + //~^ assign_op_pattern + + // this should not as cow Add is not commutative + buf = cows + buf; +} + +// check that we don't lint on op assign impls, because that's just the way to impl them + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct Wrap(i64); + +impl Mul for Wrap { + type Output = Self; + + fn mul(self, rhs: i64) -> Self { + Wrap(self.0 * rhs) + } +} + +impl MulAssign for Wrap { + fn mul_assign(&mut self, rhs: i64) { + *self = *self * rhs + } +} diff --git a/tests/ui/assign_ops.stderr b/tests/ui/assign_ops.stderr index 17f216ee4a071..881a333fbe4b9 100644 --- a/tests/ui/assign_ops.stderr +++ b/tests/ui/assign_ops.stderr @@ -1,5 +1,5 @@ error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:7:5 + --> tests/ui/assign_ops.rs:9:5 | LL | a = a + 1; | ^^^^^^^^^ help: replace it with: `a += 1` @@ -8,64 +8,70 @@ LL | a = a + 1; = help: to override `-D warnings` add `#[allow(clippy::assign_op_pattern)]` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:9:5 + --> tests/ui/assign_ops.rs:11:5 | LL | a = 1 + a; | ^^^^^^^^^ help: replace it with: `a += 1` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:11:5 + --> tests/ui/assign_ops.rs:13:5 | LL | a = a - 1; | ^^^^^^^^^ help: replace it with: `a -= 1` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:13:5 + --> tests/ui/assign_ops.rs:15:5 | LL | a = a * 99; | ^^^^^^^^^^ help: replace it with: `a *= 99` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:15:5 + --> tests/ui/assign_ops.rs:17:5 | LL | a = 42 * a; | ^^^^^^^^^^ help: replace it with: `a *= 42` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:17:5 + --> tests/ui/assign_ops.rs:19:5 | LL | a = a / 2; | ^^^^^^^^^ help: replace it with: `a /= 2` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:19:5 + --> tests/ui/assign_ops.rs:21:5 | LL | a = a % 5; | ^^^^^^^^^ help: replace it with: `a %= 5` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:21:5 + --> tests/ui/assign_ops.rs:23:5 | LL | a = a & 1; | ^^^^^^^^^ help: replace it with: `a &= 1` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:28:5 + --> tests/ui/assign_ops.rs:30:5 | LL | s = s + "bla"; | ^^^^^^^^^^^^^ help: replace it with: `s += "bla"` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:33:5 + --> tests/ui/assign_ops.rs:35:5 | LL | a = a + Wrapping(1u32); | ^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a += Wrapping(1u32)` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:36:5 + --> tests/ui/assign_ops.rs:38:5 | LL | v[0] = v[0] + v[1]; | ^^^^^^^^^^^^^^^^^^ help: replace it with: `v[0] += v[1]` -error: aborting due to 11 previous errors +error: manual implementation of an assign operation + --> tests/ui/assign_ops.rs:51:5 + | +LL | buf = buf + cows.clone(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `buf += cows.clone()` + +error: aborting due to 12 previous errors diff --git a/tests/ui/assign_ops2.rs b/tests/ui/assign_ops2.rs deleted file mode 100644 index 51867fa6962cf..0000000000000 --- a/tests/ui/assign_ops2.rs +++ /dev/null @@ -1,77 +0,0 @@ -//@no-rustfix: overlapping suggestions -#![allow(clippy::uninlined_format_args)] - -#[allow(unused_assignments)] -#[warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)] -fn main() { - let mut a = 5; - a += a + 1; - //~^ misrefactored_assign_op - - a += 1 + a; - //~^ misrefactored_assign_op - - a -= a - 1; - //~^ misrefactored_assign_op - - a *= a * 99; - //~^ misrefactored_assign_op - - a *= 42 * a; - //~^ misrefactored_assign_op - - a /= a / 2; - //~^ misrefactored_assign_op - - a %= a % 5; - //~^ misrefactored_assign_op - - a &= a & 1; - //~^ misrefactored_assign_op - - a *= a * a; - //~^ misrefactored_assign_op - - a = a * a * a; - a = a * 42 * a; - a = a * 2 + a; - a -= 1 - a; - a /= 5 / a; - a %= 42 % a; - a <<= 6 << a; -} - -// check that we don't lint on op assign impls, because that's just the way to impl them - -use std::ops::{Mul, MulAssign}; - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct Wrap(i64); - -impl Mul for Wrap { - type Output = Self; - - fn mul(self, rhs: i64) -> Self { - Wrap(self.0 * rhs) - } -} - -impl MulAssign for Wrap { - fn mul_assign(&mut self, rhs: i64) { - *self = *self * rhs - } -} - -fn cow_add_assign() { - use std::borrow::Cow; - let mut buf = Cow::Owned(String::from("bar")); - let cows = Cow::Borrowed("foo"); - - // this can be linted - buf = buf + cows.clone(); - //~^ assign_op_pattern - - // this should not as cow Add is not commutative - buf = cows + buf; - println!("{}", buf); -} diff --git a/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs b/tests/ui/auxiliary/interior_mutable_const.rs similarity index 100% rename from tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs rename to tests/ui/auxiliary/interior_mutable_const.rs diff --git a/tests/ui/borrow_interior_mutable_const.rs b/tests/ui/borrow_interior_mutable_const.rs new file mode 100644 index 0000000000000..0f439f7891507 --- /dev/null +++ b/tests/ui/borrow_interior_mutable_const.rs @@ -0,0 +1,221 @@ +//@aux-build:interior_mutable_const.rs + +#![deny(clippy::borrow_interior_mutable_const)] +#![allow( + clippy::declare_interior_mutable_const, + clippy::out_of_bounds_indexing, + const_item_mutation, + unconditional_panic +)] + +use core::cell::{Cell, UnsafeCell}; +use core::ops::{Deref, Index}; + +trait ConstDefault { + const DEFAULT: Self; +} +impl ConstDefault for u32 { + const DEFAULT: Self = 0; +} +impl ConstDefault for Cell { + const DEFAULT: Self = Cell::new(T::DEFAULT); +} + +fn main() { + { + const C: String = String::new(); + let _ = C; + let _ = &C; + let _ = C.len(); + let _ = &*C; + } + { + const C: UnsafeCell = UnsafeCell::new(0); + let _ = C; + let _ = &C; //~ borrow_interior_mutable_const + let _ = C.into_inner(); + let _ = C.get(); //~ borrow_interior_mutable_const + } + { + const C: Cell = Cell::new(0); + let _ = C; + let _ = &C; //~ borrow_interior_mutable_const + let _ = &mut C; //~ borrow_interior_mutable_const + let _ = C.into_inner(); + + let local = C; + C.swap(&local) //~ borrow_interior_mutable_const + } + { + const C: [(Cell,); 1] = [(Cell::new(0),)]; + let _ = C; + let _ = &C; //~ borrow_interior_mutable_const + let _ = &C[0]; //~ borrow_interior_mutable_const + let _ = &C[0].0; //~ borrow_interior_mutable_const + C[0].0.set(1); //~ borrow_interior_mutable_const + } + { + struct S(Cell); + impl S { + const C: Self = Self(Cell::new(0)); + } + impl Deref for S { + type Target = Cell; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + let _ = S::C; + let _ = S::C.0; + let _ = &S::C; //~ borrow_interior_mutable_const + let _ = &S::C.0; //~ borrow_interior_mutable_const + S::C.set(1); //~ borrow_interior_mutable_const + let _ = &*S::C; //~ borrow_interior_mutable_const + (*S::C).set(1); //~ borrow_interior_mutable_const + } + { + enum E { + Cell(Cell), + Other, + } + const CELL: E = E::Cell(Cell::new(0)); + const OTHER: E = E::Other; + + let _ = CELL; + let _ = &CELL; //~ borrow_interior_mutable_const + let E::Cell(_) = CELL else { + return; + }; + + let _ = OTHER; + let _ = &OTHER; + let E::Cell(ref _x) = OTHER else { + return; + }; + } + { + struct S { + cell: (Cell, u32), + other: Option, + } + impl S { + const C: Self = Self { + cell: (Cell::::DEFAULT, 0), + other: Some(T::DEFAULT), + }; + + fn f() { + let _ = Self::C; + let _ = &Self::C; //~ borrow_interior_mutable_const + let _ = Self::C.other; + let _ = &Self::C.other; + let _ = &Self::C.cell; //~ borrow_interior_mutable_const + let _ = &Self::C.cell.0; //~ borrow_interior_mutable_const + Self::C.cell.0.set(T::DEFAULT); //~ borrow_interior_mutable_const + let _ = &Self::C.cell.1; + } + } + } + { + trait T { + const VALUE: Option> = Some(Cell::new(0)); + } + impl T for u32 {} + impl T for i32 { + const VALUE: Option> = None; + } + + let _ = &u32::VALUE; //~ borrow_interior_mutable_const + let _ = &i32::VALUE; + } + { + trait Trait { + type T: ConstDefault; + const VALUE: Option> = Some(Self::T::::DEFAULT); + } + impl Trait for u32 { + type T = Cell; + } + impl Trait for i32 { + type T = Cell; + const VALUE: Option> = None; + } + + fn f() { + let _ = &>::VALUE; //~ borrow_interior_mutable_const + let _ = &>::VALUE; + } + } + { + trait Trait { + const UNFROZEN: Option> = Some(Cell::new(0)); + const FROZEN: Option> = None; + const NON_FREEZE: u32 = 0; + } + fn f() { + // None of these are guaranteed to be frozen, so don't lint. + let _ = &T::UNFROZEN; + let _ = &T::FROZEN; + let _ = &T::NON_FREEZE; + } + } + { + struct S([Option>; 2]); + impl Index for S { + type Output = Option>; + fn index(&self, idx: usize) -> &Self::Output { + &self.0[idx] + } + } + + const C: S = S([Some(Cell::new(0)), None]); + let _ = &C; //~ borrow_interior_mutable_const + let _ = &C[0]; //~ borrow_interior_mutable_const + let _ = &C.0[0]; //~ borrow_interior_mutable_const + let _ = &C.0[1]; + } + { + const C: [Option>; 2] = [None, None]; + let _ = &C[0]; + let _ = &C[1]; + let _ = &C[2]; + + fn f(i: usize) { + let _ = &C[i]; + } + } + { + const C: [Option>; 2] = [None, Some(Cell::new(0))]; + let _ = &C[0]; + let _ = &C[1]; //~ borrow_interior_mutable_const + let _ = &C[2]; + + fn f(i: usize) { + let _ = &C[i]; //~ borrow_interior_mutable_const + } + } + { + let _ = &interior_mutable_const::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ borrow_interior_mutable_const + let _ = &interior_mutable_const::WRAPPED_PRIVATE_FROZEN_VARIANT; + } + { + type Cell2 = Cell; + type MyCell = Cell2; + struct S(Option); + trait T { + type Assoc; + } + struct S2(T, T, u32); + impl T for S { + type Assoc = S2; + } + type Assoc = ::Assoc; + impl S { + const VALUE: Assoc = S2(Self(None), Self(Some(Cell::new(0))), 0); + } + let _ = &S::VALUE; //~ borrow_interior_mutable_const + let _ = &S::VALUE.0; + let _ = &S::VALUE.1; //~ borrow_interior_mutable_const + let _ = &S::VALUE.2; + } +} diff --git a/tests/ui/borrow_interior_mutable_const.stderr b/tests/ui/borrow_interior_mutable_const.stderr new file mode 100644 index 0000000000000..e7c3f879b05b0 --- /dev/null +++ b/tests/ui/borrow_interior_mutable_const.stderr @@ -0,0 +1,247 @@ +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:35:17 + | +LL | let _ = &C; + | ^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing +note: the lint level is defined here + --> tests/ui/borrow_interior_mutable_const.rs:3:9 + | +LL | #![deny(clippy::borrow_interior_mutable_const)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:37:17 + | +LL | let _ = C.get(); + | ^ + | + = note: there is a compiler inserted borrow here + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:42:17 + | +LL | let _ = &C; + | ^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:43:17 + | +LL | let _ = &mut C; + | ^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:47:9 + | +LL | C.swap(&local) + | ^ + | + = note: there is a compiler inserted borrow here + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:52:17 + | +LL | let _ = &C; + | ^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:53:17 + | +LL | let _ = &C[0]; + | ^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:54:17 + | +LL | let _ = &C[0].0; + | ^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:55:9 + | +LL | C[0].0.set(1); + | ^^^^^^ + | + = note: there is a compiler inserted borrow here + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:70:17 + | +LL | let _ = &S::C; + | ^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:71:17 + | +LL | let _ = &S::C.0; + | ^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:72:9 + | +LL | S::C.set(1); + | ^^^^ + | + = note: there is a compiler inserted call to `Deref::deref` here + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:73:18 + | +LL | let _ = &*S::C; + | ^^^^^ + | + = note: this deref expression is a call to `Deref::deref` + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:74:9 + | +LL | (*S::C).set(1); + | ^^^^^^^ + | + = note: this deref expression is a call to `Deref::deref` + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:85:17 + | +LL | let _ = &CELL; + | ^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:109:25 + | +LL | let _ = &Self::C; + | ^^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:112:25 + | +LL | let _ = &Self::C.cell; + | ^^^^^^^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:113:25 + | +LL | let _ = &Self::C.cell.0; + | ^^^^^^^^^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:114:17 + | +LL | Self::C.cell.0.set(T::DEFAULT); + | ^^^^^^^^^^^^^^ + | + = note: there is a compiler inserted borrow here + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:128:17 + | +LL | let _ = &u32::VALUE; + | ^^^^^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:145:21 + | +LL | let _ = &>::VALUE; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:172:17 + | +LL | let _ = &C; + | ^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:173:18 + | +LL | let _ = &C[0]; + | ^^^^ + | + = note: this index expression is a call to `Index::index` + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:174:17 + | +LL | let _ = &C.0[0]; + | ^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:190:17 + | +LL | let _ = &C[1]; + | ^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:194:21 + | +LL | let _ = &C[i]; + | ^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:198:17 + | +LL | let _ = &interior_mutable_const::WRAPPED_PRIVATE_UNFROZEN_VARIANT; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:216:17 + | +LL | let _ = &S::VALUE; + | ^^^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:218:17 + | +LL | let _ = &S::VALUE.1; + | ^^^^^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: aborting due to 29 previous errors + diff --git a/tests/ui/borrow_interior_mutable_const/enums.rs b/tests/ui/borrow_interior_mutable_const/enums.rs deleted file mode 100644 index da940a4cfb50b..0000000000000 --- a/tests/ui/borrow_interior_mutable_const/enums.rs +++ /dev/null @@ -1,101 +0,0 @@ -//@aux-build:helper.rs - -#![deny(clippy::borrow_interior_mutable_const)] -#![allow(clippy::declare_interior_mutable_const)] - -// this file (mostly) replicates its `declare` counterpart. Please see it for more discussions. - -extern crate helper; - -use std::cell::Cell; -use std::sync::atomic::AtomicUsize; - -enum OptionalCell { - Unfrozen(Cell), - Frozen, -} - -const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); -const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; - -fn borrow_optional_cell() { - let _ = &UNFROZEN_VARIANT; //~ ERROR: interior mutability - let _ = &FROZEN_VARIANT; -} - -trait AssocConsts { - const TO_BE_UNFROZEN_VARIANT: OptionalCell; - const TO_BE_FROZEN_VARIANT: OptionalCell; - - const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); - const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; - - fn function() { - // This is the "suboptimal behavior" mentioned in `is_value_unfrozen` - // caused by a similar reason to unfrozen types without any default values - // get linted even if it has frozen variants'. - let _ = &Self::TO_BE_FROZEN_VARIANT; //~ ERROR: interior mutability - - // The lint ignores default values because an impl of this trait can set - // an unfrozen variant to `DEFAULTED_ON_FROZEN_VARIANT` and use the default impl for `function`. - let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; //~ ERROR: interior mutability - } -} - -impl AssocConsts for u64 { - const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); - const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; - - fn function() { - let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR: interior mutability - let _ = &::TO_BE_FROZEN_VARIANT; - let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; //~ ERROR: interior mutability - let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; - } -} - -trait AssocTypes { - type ToBeUnfrozen; - - const TO_BE_UNFROZEN_VARIANT: Option; - const TO_BE_FROZEN_VARIANT: Option; - - // there's no need to test here because it's the exactly same as `trait::AssocTypes` - fn function(); -} - -impl AssocTypes for u64 { - type ToBeUnfrozen = AtomicUsize; - - const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); - const TO_BE_FROZEN_VARIANT: Option = None; - - fn function() { - let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR: interior mutability - let _ = &::TO_BE_FROZEN_VARIANT; - } -} - -enum BothOfCellAndGeneric { - Unfrozen(Cell<*const T>), - Generic(*const T), - Frozen(usize), -} - -impl BothOfCellAndGeneric { - const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); - const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); - const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); - - fn function() { - let _ = &Self::UNFROZEN_VARIANT; //~ ERROR: interior mutability - let _ = &Self::GENERIC_VARIANT; //~ ERROR: interior mutability - let _ = &Self::FROZEN_VARIANT; - } -} - -fn main() { - // constants defined in foreign crates - let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ ERROR: interior mutability - let _ = &helper::WRAPPED_PRIVATE_FROZEN_VARIANT; -} diff --git a/tests/ui/borrow_interior_mutable_const/enums.stderr b/tests/ui/borrow_interior_mutable_const/enums.stderr deleted file mode 100644 index 43850384b9036..0000000000000 --- a/tests/ui/borrow_interior_mutable_const/enums.stderr +++ /dev/null @@ -1,79 +0,0 @@ -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/enums.rs:22:14 - | -LL | let _ = &UNFROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here -note: the lint level is defined here - --> tests/ui/borrow_interior_mutable_const/enums.rs:3:9 - | -LL | #![deny(clippy::borrow_interior_mutable_const)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/enums.rs:37:18 - | -LL | let _ = &Self::TO_BE_FROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/enums.rs:41:18 - | -LL | let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/enums.rs:50:18 - | -LL | let _ = &::TO_BE_UNFROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/enums.rs:52:18 - | -LL | let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/enums.rs:74:18 - | -LL | let _ = &::TO_BE_UNFROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/enums.rs:91:18 - | -LL | let _ = &Self::UNFROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/enums.rs:92:18 - | -LL | let _ = &Self::GENERIC_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/enums.rs:99:14 - | -LL | let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: aborting due to 9 previous errors - diff --git a/tests/ui/borrow_interior_mutable_const/others.rs b/tests/ui/borrow_interior_mutable_const/others.rs deleted file mode 100644 index fa729b62d7f51..0000000000000 --- a/tests/ui/borrow_interior_mutable_const/others.rs +++ /dev/null @@ -1,128 +0,0 @@ -#![deny(clippy::borrow_interior_mutable_const)] -#![allow(clippy::declare_interior_mutable_const, clippy::needless_borrow)] -#![allow(const_item_mutation)] - -use std::borrow::Cow; -use std::cell::{Cell, UnsafeCell}; -use std::fmt::Display; -use std::sync::Once; -use std::sync::atomic::{AtomicUsize, Ordering}; - -const ATOMIC: AtomicUsize = AtomicUsize::new(5); -const CELL: Cell = Cell::new(6); -const ATOMIC_TUPLE: ([AtomicUsize; 1], Option>, u8) = ([ATOMIC], None, 7); -const INTEGER: u8 = 8; -const STRING: String = String::new(); -const STR: &str = "012345"; -const COW: Cow = Cow::Borrowed("abcdef"); -const NO_ANN: &dyn Display = &70; -static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING); -const ONCE_INIT: Once = Once::new(); - -// This is just a pointer that can be safely dereferenced, -// it's semantically the same as `&'static T`; -// but it isn't allowed to make a static reference from an arbitrary integer value at the moment. -// For more information, please see the issue #5918. -pub struct StaticRef { - ptr: *const T, -} - -impl StaticRef { - /// Create a new `StaticRef` from a raw pointer - /// - /// ## Safety - /// - /// Callers must pass in a reference to statically allocated memory which - /// does not overlap with other values. - pub const unsafe fn new(ptr: *const T) -> StaticRef { - StaticRef { ptr } - } -} - -impl std::ops::Deref for StaticRef { - type Target = T; - - fn deref(&self) -> &T { - unsafe { &*self.ptr } - } -} - -// ICE regression test -mod issue12979 { - use std::cell::UnsafeCell; - - const ATOMIC_TUPLE: (Vec>, ()) = (Vec::new(), ()); - - fn main() { - let _x = &ATOMIC_TUPLE.0; - } -} - -// use a tuple to make sure referencing a field behind a pointer isn't linted. -const CELL_REF: StaticRef<(UnsafeCell,)> = unsafe { StaticRef::new(std::ptr::null()) }; - -fn main() { - ATOMIC.store(1, Ordering::SeqCst); - //~^ borrow_interior_mutable_const - assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); - //~^ borrow_interior_mutable_const - - let _once = ONCE_INIT; - let _once_ref = &ONCE_INIT; - //~^ borrow_interior_mutable_const - let _once_ref_2 = &&ONCE_INIT; - //~^ borrow_interior_mutable_const - let _once_ref_4 = &&&&ONCE_INIT; - //~^ borrow_interior_mutable_const - let _once_mut = &mut ONCE_INIT; - //~^ borrow_interior_mutable_const - let _atomic_into_inner = ATOMIC.into_inner(); - // these should be all fine. - let _twice = (ONCE_INIT, ONCE_INIT); - let _ref_twice = &(ONCE_INIT, ONCE_INIT); - let _ref_once = &(ONCE_INIT, ONCE_INIT).0; - let _array_twice = [ONCE_INIT, ONCE_INIT]; - let _ref_array_twice = &[ONCE_INIT, ONCE_INIT]; - let _ref_array_once = &[ONCE_INIT, ONCE_INIT][0]; - - // referencing projection is still bad. - let _ = &ATOMIC_TUPLE; - //~^ borrow_interior_mutable_const - let _ = &ATOMIC_TUPLE.0; - //~^ borrow_interior_mutable_const - let _ = &(&&&&ATOMIC_TUPLE).0; - //~^ borrow_interior_mutable_const - let _ = &ATOMIC_TUPLE.0[0]; - //~^ borrow_interior_mutable_const - let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); - //~^ borrow_interior_mutable_const - let _ = &ATOMIC_TUPLE.2; - let _ = (&&&&ATOMIC_TUPLE).0; - let _ = (&&&&ATOMIC_TUPLE).2; - let _ = ATOMIC_TUPLE.0; - let _ = ATOMIC_TUPLE.0[0]; - //~^ borrow_interior_mutable_const - let _ = ATOMIC_TUPLE.1.into_iter(); - let _ = ATOMIC_TUPLE.2; - let _ = &{ ATOMIC_TUPLE }; - - CELL.set(2); - //~^ borrow_interior_mutable_const - assert_eq!(CELL.get(), 6); - //~^ borrow_interior_mutable_const - - assert_eq!(INTEGER, 8); - assert!(STRING.is_empty()); - - let a = ATOMIC; - a.store(4, Ordering::SeqCst); - assert_eq!(a.load(Ordering::SeqCst), 4); - - STATIC_TUPLE.0.store(3, Ordering::SeqCst); - assert_eq!(STATIC_TUPLE.0.load(Ordering::SeqCst), 3); - assert!(STATIC_TUPLE.1.is_empty()); - - assert_eq!(NO_ANN.to_string(), "70"); // should never lint this. - - let _ = &CELL_REF.0; -} diff --git a/tests/ui/borrow_interior_mutable_const/others.stderr b/tests/ui/borrow_interior_mutable_const/others.stderr deleted file mode 100644 index decea153f7173..0000000000000 --- a/tests/ui/borrow_interior_mutable_const/others.stderr +++ /dev/null @@ -1,119 +0,0 @@ -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:65:5 - | -LL | ATOMIC.store(1, Ordering::SeqCst); - | ^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here -note: the lint level is defined here - --> tests/ui/borrow_interior_mutable_const/others.rs:1:9 - | -LL | #![deny(clippy::borrow_interior_mutable_const)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:67:16 - | -LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); - | ^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:71:22 - | -LL | let _once_ref = &ONCE_INIT; - | ^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:73:25 - | -LL | let _once_ref_2 = &&ONCE_INIT; - | ^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:75:27 - | -LL | let _once_ref_4 = &&&&ONCE_INIT; - | ^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:77:26 - | -LL | let _once_mut = &mut ONCE_INIT; - | ^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:89:14 - | -LL | let _ = &ATOMIC_TUPLE; - | ^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:91:14 - | -LL | let _ = &ATOMIC_TUPLE.0; - | ^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:93:19 - | -LL | let _ = &(&&&&ATOMIC_TUPLE).0; - | ^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:95:14 - | -LL | let _ = &ATOMIC_TUPLE.0[0]; - | ^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:97:13 - | -LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); - | ^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:103:13 - | -LL | let _ = ATOMIC_TUPLE.0[0]; - | ^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:109:5 - | -LL | CELL.set(2); - | ^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:111:16 - | -LL | assert_eq!(CELL.get(), 6); - | ^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: aborting due to 14 previous errors - diff --git a/tests/ui/borrow_interior_mutable_const/projections.rs b/tests/ui/borrow_interior_mutable_const/projections.rs deleted file mode 100644 index bbe5538fbe123..0000000000000 --- a/tests/ui/borrow_interior_mutable_const/projections.rs +++ /dev/null @@ -1,42 +0,0 @@ -#![deny(clippy::borrow_interior_mutable_const)] -#![deny(clippy::declare_interior_mutable_const)] - -// Inspired by https://github.com/rust-lang/rust/pull/130543#issuecomment-2364828139 - -use std::cell::UnsafeCell; - -trait Trait { - type Assoc; -} - -type Assoc = ::Assoc; - -impl Trait for u8 { - type Assoc = UnsafeCell; -} - -impl Trait for () { - type Assoc = (); -} - -enum MaybeMutable { - Mutable(Assoc), - Immutable(Assoc<()>), -} - -const CELL: Assoc = UnsafeCell::new(0); //~ ERROR: interior mutable -const UNIT: Assoc<()> = (); -const MUTABLE: MaybeMutable = MaybeMutable::Mutable(CELL); //~ ERROR: interior mutable -const IMMUTABLE: MaybeMutable = MaybeMutable::Immutable(UNIT); - -fn print_ref(t: &T) { - let p: *const T = t; - println!("{p:p}") -} - -fn main() { - print_ref(&CELL); //~ ERROR: interior mutability - print_ref(&UNIT); - print_ref(&MUTABLE); //~ ERROR: interior mutability - print_ref(&IMMUTABLE); -} diff --git a/tests/ui/borrow_interior_mutable_const/projections.stderr b/tests/ui/borrow_interior_mutable_const/projections.stderr deleted file mode 100644 index eabaf66560ada..0000000000000 --- a/tests/ui/borrow_interior_mutable_const/projections.stderr +++ /dev/null @@ -1,44 +0,0 @@ -error: a `const` item should not be interior mutable - --> tests/ui/borrow_interior_mutable_const/projections.rs:27:1 - | -LL | const CELL: Assoc = UnsafeCell::new(0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` -note: the lint level is defined here - --> tests/ui/borrow_interior_mutable_const/projections.rs:2:9 - | -LL | #![deny(clippy::declare_interior_mutable_const)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item should not be interior mutable - --> tests/ui/borrow_interior_mutable_const/projections.rs:29:1 - | -LL | const MUTABLE: MaybeMutable = MaybeMutable::Mutable(CELL); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/projections.rs:38:16 - | -LL | print_ref(&CELL); - | ^^^^ - | - = help: assign this const to a local or static variable, and use the variable here -note: the lint level is defined here - --> tests/ui/borrow_interior_mutable_const/projections.rs:1:9 - | -LL | #![deny(clippy::borrow_interior_mutable_const)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/projections.rs:40:16 - | -LL | print_ref(&MUTABLE); - | ^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: aborting due to 4 previous errors - diff --git a/tests/ui/borrow_interior_mutable_const/traits.rs b/tests/ui/borrow_interior_mutable_const/traits.rs deleted file mode 100644 index c4878dbe57b29..0000000000000 --- a/tests/ui/borrow_interior_mutable_const/traits.rs +++ /dev/null @@ -1,219 +0,0 @@ -#![deny(clippy::borrow_interior_mutable_const)] -#![allow(clippy::declare_interior_mutable_const)] - -// this file replicates its `declare` counterpart. Please see it for more discussions. - -use std::borrow::Cow; -use std::cell::Cell; -use std::sync::atomic::{AtomicUsize, Ordering}; - -trait ConcreteTypes { - const ATOMIC: AtomicUsize; - const STRING: String; - - fn function() { - let _ = &Self::ATOMIC; - //~^ borrow_interior_mutable_const - let _ = &Self::STRING; - } -} - -impl ConcreteTypes for u64 { - const ATOMIC: AtomicUsize = AtomicUsize::new(9); - const STRING: String = String::new(); - - fn function() { - // Lint this again since implementers can choose not to borrow it. - let _ = &Self::ATOMIC; - //~^ borrow_interior_mutable_const - let _ = &Self::STRING; - } -} - -// a helper trait used below -trait ConstDefault { - const DEFAULT: Self; -} - -trait GenericTypes { - const TO_REMAIN_GENERIC: T; - const TO_BE_CONCRETE: U; - - fn function() { - let _ = &Self::TO_REMAIN_GENERIC; - } -} - -impl GenericTypes for Vec { - const TO_REMAIN_GENERIC: T = T::DEFAULT; - const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); - - fn function() { - let _ = &Self::TO_REMAIN_GENERIC; - let _ = &Self::TO_BE_CONCRETE; - //~^ borrow_interior_mutable_const - } -} - -// a helper type used below -pub struct Wrapper(T); - -trait AssocTypes { - type ToBeFrozen; - type ToBeUnfrozen; - type ToBeGenericParam; - - const TO_BE_FROZEN: Self::ToBeFrozen; - const TO_BE_UNFROZEN: Self::ToBeUnfrozen; - const WRAPPED_TO_BE_UNFROZEN: Wrapper; - const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper; - - fn function() { - let _ = &Self::TO_BE_FROZEN; - let _ = &Self::WRAPPED_TO_BE_UNFROZEN; - } -} - -impl AssocTypes for Vec { - type ToBeFrozen = u16; - type ToBeUnfrozen = AtomicUsize; - type ToBeGenericParam = T; - - const TO_BE_FROZEN: Self::ToBeFrozen = 12; - const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); - const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); - const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper = Wrapper(T::DEFAULT); - - fn function() { - let _ = &Self::TO_BE_FROZEN; - let _ = &Self::TO_BE_UNFROZEN; - //~^ borrow_interior_mutable_const - let _ = &Self::WRAPPED_TO_BE_UNFROZEN; - //~^ borrow_interior_mutable_const - let _ = &Self::WRAPPED_TO_BE_GENERIC_PARAM; - } -} - -// a helper trait used below -trait AssocTypesHelper { - type NotToBeBounded; - type ToBeBounded; - - const NOT_TO_BE_BOUNDED: Self::NotToBeBounded; -} - -trait AssocTypesFromGenericParam -where - T: AssocTypesHelper, -{ - const NOT_BOUNDED: T::NotToBeBounded; - const BOUNDED: T::ToBeBounded; - - fn function() { - let _ = &Self::NOT_BOUNDED; - let _ = &Self::BOUNDED; - //~^ borrow_interior_mutable_const - } -} - -impl AssocTypesFromGenericParam for Vec -where - T: AssocTypesHelper, -{ - const NOT_BOUNDED: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED; - const BOUNDED: T::ToBeBounded = AtomicUsize::new(15); - - fn function() { - let _ = &Self::NOT_BOUNDED; - let _ = &Self::BOUNDED; - //~^ borrow_interior_mutable_const - } -} - -trait SelfType: Sized { - const SELF: Self; - const WRAPPED_SELF: Option; - - fn function() { - let _ = &Self::SELF; - let _ = &Self::WRAPPED_SELF; - } -} - -impl SelfType for u64 { - const SELF: Self = 16; - const WRAPPED_SELF: Option = Some(20); - - fn function() { - let _ = &Self::SELF; - let _ = &Self::WRAPPED_SELF; - } -} - -impl SelfType for AtomicUsize { - const SELF: Self = AtomicUsize::new(17); - const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); - - fn function() { - let _ = &Self::SELF; - //~^ borrow_interior_mutable_const - let _ = &Self::WRAPPED_SELF; - //~^ borrow_interior_mutable_const - } -} - -trait BothOfCellAndGeneric { - const DIRECT: Cell; - const INDIRECT: Cell<*const T>; - - fn function() { - let _ = &Self::DIRECT; - //~^ borrow_interior_mutable_const - let _ = &Self::INDIRECT; - //~^ borrow_interior_mutable_const - } -} - -impl BothOfCellAndGeneric for Vec { - const DIRECT: Cell = Cell::new(T::DEFAULT); - const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null()); - - fn function() { - let _ = &Self::DIRECT; - //~^ borrow_interior_mutable_const - let _ = &Self::INDIRECT; - //~^ borrow_interior_mutable_const - } -} - -struct Local(T); - -impl Local -where - T: ConstDefault + AssocTypesHelper, -{ - const ATOMIC: AtomicUsize = AtomicUsize::new(18); - const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy"); - - const GENERIC_TYPE: T = T::DEFAULT; - - const ASSOC_TYPE: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED; - const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); - - fn function() { - let _ = &Self::ATOMIC; - //~^ borrow_interior_mutable_const - let _ = &Self::COW; - let _ = &Self::GENERIC_TYPE; - let _ = &Self::ASSOC_TYPE; - let _ = &Self::BOUNDED_ASSOC_TYPE; - //~^ borrow_interior_mutable_const - } -} - -fn main() { - u64::ATOMIC.store(5, Ordering::SeqCst); - //~^ borrow_interior_mutable_const - assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); - //~^ borrow_interior_mutable_const -} diff --git a/tests/ui/borrow_interior_mutable_const/traits.stderr b/tests/ui/borrow_interior_mutable_const/traits.stderr deleted file mode 100644 index cad68ca9260cb..0000000000000 --- a/tests/ui/borrow_interior_mutable_const/traits.stderr +++ /dev/null @@ -1,143 +0,0 @@ -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:15:18 - | -LL | let _ = &Self::ATOMIC; - | ^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here -note: the lint level is defined here - --> tests/ui/borrow_interior_mutable_const/traits.rs:1:9 - | -LL | #![deny(clippy::borrow_interior_mutable_const)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:27:18 - | -LL | let _ = &Self::ATOMIC; - | ^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:53:18 - | -LL | let _ = &Self::TO_BE_CONCRETE; - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:89:18 - | -LL | let _ = &Self::TO_BE_UNFROZEN; - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:91:18 - | -LL | let _ = &Self::WRAPPED_TO_BE_UNFROZEN; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:114:18 - | -LL | let _ = &Self::BOUNDED; - | ^^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:128:18 - | -LL | let _ = &Self::BOUNDED; - | ^^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:158:18 - | -LL | let _ = &Self::SELF; - | ^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:160:18 - | -LL | let _ = &Self::WRAPPED_SELF; - | ^^^^^^^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:170:18 - | -LL | let _ = &Self::DIRECT; - | ^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:172:18 - | -LL | let _ = &Self::INDIRECT; - | ^^^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:182:18 - | -LL | let _ = &Self::DIRECT; - | ^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:184:18 - | -LL | let _ = &Self::INDIRECT; - | ^^^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:204:18 - | -LL | let _ = &Self::ATOMIC; - | ^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:209:18 - | -LL | let _ = &Self::BOUNDED_ASSOC_TYPE; - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:215:5 - | -LL | u64::ATOMIC.store(5, Ordering::SeqCst); - | ^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:217:16 - | -LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); - | ^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: aborting due to 17 previous errors - diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index 88c2549f4dc50..77329cf5455de 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -1,4 +1,4 @@ -//@no-rustfix +//@no-rustfix: only some diagnostics have suggestions #![feature(repr128)] #![allow(incomplete_features)] diff --git a/tests/ui/cast_size.rs b/tests/ui/cast_size.rs index e924018088674..e5bef2a99d59e 100644 --- a/tests/ui/cast_size.rs +++ b/tests/ui/cast_size.rs @@ -1,7 +1,7 @@ //@revisions: 32bit 64bit //@[32bit]ignore-bitwidth: 64 //@[64bit]ignore-bitwidth: 32 -//@no-rustfix +//@no-rustfix: only some diagnostics have suggestions #![warn( clippy::cast_precision_loss, diff --git a/tests/ui/checked_unwrap/complex_conditionals_nested.rs b/tests/ui/checked_unwrap/complex_conditionals_nested.rs index 145885702a9bc..7635f848cb349 100644 --- a/tests/ui/checked_unwrap/complex_conditionals_nested.rs +++ b/tests/ui/checked_unwrap/complex_conditionals_nested.rs @@ -4,7 +4,7 @@ clippy::branches_sharing_code, clippy::unnecessary_literal_unwrap )] -//@no-rustfix +//@no-rustfix: has placeholders fn test_nested() { fn nested() { let x = Some(()); diff --git a/tests/ui/checked_unwrap/simple_conditionals.rs b/tests/ui/checked_unwrap/simple_conditionals.rs index ba0d36d85fe54..785b2473c0530 100644 --- a/tests/ui/checked_unwrap/simple_conditionals.rs +++ b/tests/ui/checked_unwrap/simple_conditionals.rs @@ -1,4 +1,4 @@ -//@no-rustfix: overlapping suggestions +//@no-rustfix: has placeholders #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] #![allow( clippy::if_same_then_else, diff --git a/tests/ui/comparison_chain.rs b/tests/ui/comparison_chain.rs index 669690a4d42ce..6db75a4f364d7 100644 --- a/tests/ui/comparison_chain.rs +++ b/tests/ui/comparison_chain.rs @@ -1,4 +1,4 @@ -//@no-rustfix +//@no-rustfix: has placeholders #![allow(dead_code)] #![warn(clippy::comparison_chain)] @@ -12,11 +12,10 @@ fn f(x: u8, y: u8, z: u8) { a() } - if x > y { - //~^ comparison_chain - + // Ignored: Not all cases are covered + if x < y { a() - } else if x < y { + } else if x > y { b() } @@ -123,9 +122,8 @@ fn g(x: f64, y: f64, z: f64) { } fn h(x: T, y: T, z: T) { + // Ignored: Not all cases are covered if x > y { - //~^ comparison_chain - a() } else if x < y { b() diff --git a/tests/ui/comparison_chain.stderr b/tests/ui/comparison_chain.stderr index 0256573d0d906..ce580bd54a16a 100644 --- a/tests/ui/comparison_chain.stderr +++ b/tests/ui/comparison_chain.stderr @@ -1,12 +1,12 @@ error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:15:5 + --> tests/ui/comparison_chain.rs:29:5 | LL | / if x > y { LL | | LL | | LL | | a() -LL | | } else if x < y { -LL | | b() +... | +LL | | c() LL | | } | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}` | @@ -14,19 +14,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::comparison_chain)]` error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:30:5 - | -LL | / if x > y { -LL | | -LL | | -LL | | a() -... | -LL | | c() -LL | | } - | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}` - -error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:40:5 + --> tests/ui/comparison_chain.rs:39:5 | LL | / if x > y { LL | | @@ -38,7 +26,7 @@ LL | | } | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}` error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:50:5 + --> tests/ui/comparison_chain.rs:49:5 | LL | / if x > 1 { LL | | @@ -50,19 +38,7 @@ LL | | } | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&1) {...}` error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:126:5 - | -LL | / if x > y { -LL | | -LL | | -LL | | a() -LL | | } else if x < y { -LL | | b() -LL | | } - | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}` - -error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:134:5 + --> tests/ui/comparison_chain.rs:132:5 | LL | / if x > y { LL | | @@ -74,7 +50,7 @@ LL | | } | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}` error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:144:5 + --> tests/ui/comparison_chain.rs:142:5 | LL | / if x > y { LL | | @@ -86,7 +62,7 @@ LL | | } | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}` error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:251:5 + --> tests/ui/comparison_chain.rs:249:5 | LL | / if x + 1 > y * 2 { LL | | @@ -97,5 +73,5 @@ LL | | "cc" LL | | } | |_____^ help: consider rewriting the `if` chain with `match`: `match (x + 1).cmp(&(y * 2)) {...}` -error: aborting due to 8 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/crashes/ice-12491.fixed b/tests/ui/crashes/ice-12491.fixed index ab9c61463e92d..8a31eb9550b23 100644 --- a/tests/ui/crashes/ice-12491.fixed +++ b/tests/ui/crashes/ice-12491.fixed @@ -3,6 +3,6 @@ fn main() { if (true) { // anything一些中文 - //~^^ needless_return + //~^ needless_return } } diff --git a/tests/ui/crashes/ice-12491.rs b/tests/ui/crashes/ice-12491.rs index b774bd3788a77..013aadadce516 100644 --- a/tests/ui/crashes/ice-12491.rs +++ b/tests/ui/crashes/ice-12491.rs @@ -4,6 +4,6 @@ fn main() { if (true) { // anything一些中文 return; - //~^^ needless_return + //~^ needless_return } } diff --git a/tests/ui/crashes/ice-12491.stderr b/tests/ui/crashes/ice-12491.stderr index 7cc418898e881..4b77299dd5e6c 100644 --- a/tests/ui/crashes/ice-12491.stderr +++ b/tests/ui/crashes/ice-12491.stderr @@ -1,10 +1,8 @@ error: unneeded `return` statement - --> tests/ui/crashes/ice-12491.rs:5:24 + --> tests/ui/crashes/ice-12491.rs:6:9 | -LL | // anything一些中文 - | ____________________________^ -LL | | return; - | |______________^ +LL | return; + | ^^^^^^ | = note: `-D clippy::needless-return` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_return)]` diff --git a/tests/ui/crashes/ice-12979.1.fixed b/tests/ui/crashes/ice-12979.1.fixed new file mode 100644 index 0000000000000..e68f1c20a8e7c --- /dev/null +++ b/tests/ui/crashes/ice-12979.1.fixed @@ -0,0 +1,2 @@ +#[deny(clippy::declare_interior_mutable_const)] //~ empty_line_after_outer_attr +const FOO: u8 = 0; diff --git a/tests/ui/crashes/ice-12979.2.fixed b/tests/ui/crashes/ice-12979.2.fixed new file mode 100644 index 0000000000000..e89fa636d4b24 --- /dev/null +++ b/tests/ui/crashes/ice-12979.2.fixed @@ -0,0 +1,3 @@ +#![deny(clippy::declare_interior_mutable_const)] //~ empty_line_after_outer_attr + +const FOO: u8 = 0; diff --git a/tests/ui/crashes/ice-12979.rs b/tests/ui/crashes/ice-12979.rs new file mode 100644 index 0000000000000..a2787291d9e15 --- /dev/null +++ b/tests/ui/crashes/ice-12979.rs @@ -0,0 +1,3 @@ +#[deny(clippy::declare_interior_mutable_const)] //~ empty_line_after_outer_attr + +const FOO: u8 = 0; diff --git a/tests/ui/crashes/ice-12979.stderr b/tests/ui/crashes/ice-12979.stderr new file mode 100644 index 0000000000000..5e76081616461 --- /dev/null +++ b/tests/ui/crashes/ice-12979.stderr @@ -0,0 +1,19 @@ +error: empty line after outer attribute + --> tests/ui/crashes/ice-12979.rs:1:1 + | +LL | / #[deny(clippy::declare_interior_mutable_const)] +LL | | + | |_^ +LL | const FOO: u8 = 0; + | --------- the attribute applies to this constant item + | + = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::empty_line_after_outer_attr)]` + = help: if the empty line is unintentional, remove it +help: if the attribute should apply to the crate use an inner attribute + | +LL | #![deny(clippy::declare_interior_mutable_const)] + | + + +error: aborting due to 1 previous error + diff --git a/tests/ui/crashes/ice-6840.rs b/tests/ui/crashes/ice-6840.rs index 94481f2489987..f30d83e1eeecd 100644 --- a/tests/ui/crashes/ice-6840.rs +++ b/tests/ui/crashes/ice-6840.rs @@ -2,6 +2,7 @@ //! This is a reproducer for the ICE 6840: https://github.com/rust-lang/rust-clippy/issues/6840. //! The ICE is caused by `TyCtxt::layout_of` and `is_normalizable` not being strict enough #![allow(dead_code)] +#![deny(clippy::zero_sized_map_values)] // For ICE 14822 use std::collections::HashMap; pub trait Rule { diff --git a/tests/ui/crashes/ice-9445.rs b/tests/ui/crashes/ice-9445.rs deleted file mode 100644 index 232b8e4a7959d..0000000000000 --- a/tests/ui/crashes/ice-9445.rs +++ /dev/null @@ -1,4 +0,0 @@ -const UNINIT: core::mem::MaybeUninit> = core::mem::MaybeUninit::uninit(); -//~^ declare_interior_mutable_const - -fn main() {} diff --git a/tests/ui/crashes/ice-9445.stderr b/tests/ui/crashes/ice-9445.stderr deleted file mode 100644 index 76689cd6f5c22..0000000000000 --- a/tests/ui/crashes/ice-9445.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error: a `const` item should not be interior mutable - --> tests/ui/crashes/ice-9445.rs:1:1 - | -LL | const UNINIT: core::mem::MaybeUninit> = core::mem::MaybeUninit::uninit(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` - = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` - -error: aborting due to 1 previous error - diff --git a/tests/ui/dbg_macro/dbg_macro_unfixable.rs b/tests/ui/dbg_macro/dbg_macro_unfixable.rs index 1a5119651b539..96b35c9a20c4c 100644 --- a/tests/ui/dbg_macro/dbg_macro_unfixable.rs +++ b/tests/ui/dbg_macro/dbg_macro_unfixable.rs @@ -1,4 +1,4 @@ -//@no-rustfix +//@no-rustfix: overlapping suggestions //@error-in-other-file: #![warn(clippy::dbg_macro)] diff --git a/tests/ui/declare_interior_mutable_const.rs b/tests/ui/declare_interior_mutable_const.rs new file mode 100644 index 0000000000000..c65df275038dc --- /dev/null +++ b/tests/ui/declare_interior_mutable_const.rs @@ -0,0 +1,200 @@ +#![deny(clippy::declare_interior_mutable_const)] +#![allow(clippy::missing_const_for_thread_local)] + +use core::cell::{Cell, RefCell, UnsafeCell}; +use core::mem::{ManuallyDrop, MaybeUninit}; +use core::ptr; +use core::sync::atomic::AtomicUsize; + +fn main() {} + +const _: Cell = Cell::new(0); +const UNSAFE_CELL: UnsafeCell = UnsafeCell::new(0); //~ declare_interior_mutable_const +const REF_CELL: RefCell = RefCell::new(0); //~ declare_interior_mutable_const +const CELL: Cell = Cell::new(0); //~ declare_interior_mutable_const + +// Constants can't contain pointers or references to type with interior mutability. +const fn make_ptr() -> *const Cell { + ptr::null() +} +const PTR: *const Cell = make_ptr(); + +const fn casted_to_cell_ptr() -> *const Cell { + const VALUE: u32 = 0; + &VALUE as *const _ as *const Cell +} +const TRANSMUTED_PTR: *const Cell = casted_to_cell_ptr(); + +const CELL_TUPLE: (bool, Cell) = (true, Cell::new(0)); //~ declare_interior_mutable_const +const CELL_ARRAY: [Cell; 2] = [Cell::new(0), Cell::new(0)]; //~ declare_interior_mutable_const + +const UNINIT_CELL: MaybeUninit> = MaybeUninit::uninit(); + +struct CellStruct { + x: u32, + cell: Cell, +} +//~v declare_interior_mutable_const +const CELL_STRUCT: CellStruct = CellStruct { + x: 0, + cell: Cell::new(0), +}; + +enum CellEnum { + Cell(Cell), +} +const CELL_ENUM: CellEnum = CellEnum::Cell(Cell::new(0)); //~ declare_interior_mutable_const + +const NONE_CELL: Option> = None; +const SOME_CELL: Option> = Some(Cell::new(0)); //~ declare_interior_mutable_const + +struct NestedCell([(Option>,); 1]); +const NONE_NESTED_CELL: NestedCell = NestedCell([(None,)]); +const SOME_NESTED_CELL: NestedCell = NestedCell([(Some(Cell::new(0)),)]); //~ declare_interior_mutable_const + +union UnionCell { + cell: ManuallyDrop>, + x: u32, +} +//~v declare_interior_mutable_const +const UNION_CELL: UnionCell = UnionCell { + cell: ManuallyDrop::new(Cell::new(0)), +}; +// Access to either union field is valid so we have to be conservative here. +const UNION_U32: UnionCell = UnionCell { x: 0 }; //~ declare_interior_mutable_const + +struct Assoc; +impl Assoc { + const SELF: Self = Self; + const CELL: Cell = Cell::new(0); //~ declare_interior_mutable_const +} + +struct AssocCell(Cell); +impl AssocCell { + const SELF: Self = Self(Cell::new(0)); //~ declare_interior_mutable_const + const NONE_SELF: Option = None; + const SOME_SELF: Option = Some(Self(Cell::new(0))); //~ declare_interior_mutable_const +} + +trait ConstDefault { + // May or may not be `Freeze` + const DEFAULT: Self; +} +impl ConstDefault for u32 { + const DEFAULT: Self = 0; +} +impl ConstDefault for Cell { + // Interior mutability is forced by the trait. + const DEFAULT: Self = Cell::new(T::DEFAULT); +} +impl ConstDefault for Option> { + // Could have been `None` + const DEFAULT: Self = Some(Cell::new(T::DEFAULT)); //~ declare_interior_mutable_const +} + +enum GenericEnumCell { + Cell(Cell), + Other(T), +} +impl ConstDefault for GenericEnumCell { + const DEFAULT: Self = Self::Cell(Cell::new(T::DEFAULT)); //~ declare_interior_mutable_const +} +impl GenericEnumCell { + const CELL: Self = Self::DEFAULT; //~ declare_interior_mutable_const + const CELL_BY_DEFAULT: Self = Self::Cell(Cell::DEFAULT); //~ declare_interior_mutable_const + const OTHER: Self = Self::Other(T::DEFAULT); + const FROM_OTHER: Self = Self::OTHER; +} + +enum GenericNestedEnumCell { + GenericEnumCell(GenericEnumCell), + EnumCell(GenericEnumCell), + Other(T), +} +impl GenericNestedEnumCell { + const GENERIC_OTHER: Self = Self::GenericEnumCell(GenericEnumCell::::FROM_OTHER); + const GENERIC_CELL: Self = Self::GenericEnumCell(GenericEnumCell::::CELL); //~ declare_interior_mutable_const + const ENUM_OTHER: Self = Self::EnumCell(GenericEnumCell::::FROM_OTHER); + const ENUM_CELL: Self = Self::EnumCell(GenericEnumCell::::CELL); //~ declare_interior_mutable_const +} + +trait CellTrait: ConstDefault + Sized { + // Must be non-`Freeze` due to the type + const CELL: Cell; //~ declare_interior_mutable_const + // May be non-`Freeze`, but may not be + const OPTION_CELL: Option>; + // May get redefined by the impl, but the default is non-`Freeze`. + const SOME_CELL: Option> = Some(Cell::new(Self::DEFAULT)); //~ declare_interior_mutable_const + // May get redefined by the impl, but the default is `Freeze`. + const NONE_CELL: Option> = None; +} + +trait CellWithAssoc { + type T; + const DEFAULT: Self::T; + // Must be non-`Freeze` due to the type + const CELL: Cell; //~ declare_interior_mutable_const + // May be non-`Freeze`, but may not be + const OPTION_CELL: Option>; + // May get redefined by the impl, but the default is non-`Freeze`. + const SOME_CELL: Option> = Some(Cell::new(Self::DEFAULT)); //~ declare_interior_mutable_const + // May get redefined by the impl, but the default is `Freeze`. + const NONE_CELL: Option> = None; +} + +impl CellWithAssoc for () { + type T = u32; + const DEFAULT: Self::T = 0; + const CELL: Cell = Cell::new(0); + const OPTION_CELL: Option> = None; +} + +trait WithAssoc { + type T; + const VALUE: Self::T; +} + +impl WithAssoc for u32 { + type T = Cell; + // The cell comes from the impl block, not the trait. + const VALUE: Self::T = Cell::new(0); //~ declare_interior_mutable_const +} + +trait WithLayeredAssoc { + type T: WithAssoc; + const VALUE: ::T; +} + +impl WithLayeredAssoc for u32 { + type T = u32; + // The cell comes from the impl block, not the trait. + const VALUE: ::T = Cell::new(0); //~ declare_interior_mutable_const +} + +trait WithGenericAssoc { + type T; + const VALUE: Self::T; +} + +impl WithGenericAssoc for u32 { + type T = Cell; + const VALUE: Self::T = Cell::new(0); //~ declare_interior_mutable_const +} + +trait WithGenericAssocCell { + type T; + const VALUE: Self::T>; +} + +impl WithGenericAssocCell for u32 { + type T = Option; + const VALUE: Self::T> = None; +} + +impl WithGenericAssocCell for i32 { + type T = Option; + const VALUE: Self::T> = Some(Cell::new(0)); //~ declare_interior_mutable_const +} + +thread_local!(static THREAD_LOCAL_CELL: Cell = const { Cell::new(0) }); +thread_local!(static THREAD_LOCAL_CELL2: Cell = Cell::new(0)); diff --git a/tests/ui/declare_interior_mutable_const.stderr b/tests/ui/declare_interior_mutable_const.stderr new file mode 100644 index 0000000000000..9742c17486c5f --- /dev/null +++ b/tests/ui/declare_interior_mutable_const.stderr @@ -0,0 +1,197 @@ +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:12:7 + | +LL | const UNSAFE_CELL: UnsafeCell = UnsafeCell::new(0); + | ^^^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item +note: the lint level is defined here + --> tests/ui/declare_interior_mutable_const.rs:1:9 + | +LL | #![deny(clippy::declare_interior_mutable_const)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:13:7 + | +LL | const REF_CELL: RefCell = RefCell::new(0); + | ^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:14:7 + | +LL | const CELL: Cell = Cell::new(0); + | ^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:28:7 + | +LL | const CELL_TUPLE: (bool, Cell) = (true, Cell::new(0)); + | ^^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:29:7 + | +LL | const CELL_ARRAY: [Cell; 2] = [Cell::new(0), Cell::new(0)]; + | ^^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:38:7 + | +LL | const CELL_STRUCT: CellStruct = CellStruct { + | ^^^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:46:7 + | +LL | const CELL_ENUM: CellEnum = CellEnum::Cell(Cell::new(0)); + | ^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:49:7 + | +LL | const SOME_CELL: Option> = Some(Cell::new(0)); + | ^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:53:7 + | +LL | const SOME_NESTED_CELL: NestedCell = NestedCell([(Some(Cell::new(0)),)]); + | ^^^^^^^^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:60:7 + | +LL | const UNION_CELL: UnionCell = UnionCell { + | ^^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:64:7 + | +LL | const UNION_U32: UnionCell = UnionCell { x: 0 }; + | ^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:69:11 + | +LL | const CELL: Cell = Cell::new(0); + | ^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:74:11 + | +LL | const SELF: Self = Self(Cell::new(0)); + | ^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:76:11 + | +LL | const SOME_SELF: Option = Some(Self(Cell::new(0))); + | ^^^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:92:11 + | +LL | const DEFAULT: Self = Some(Cell::new(T::DEFAULT)); + | ^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:100:11 + | +LL | const DEFAULT: Self = Self::Cell(Cell::new(T::DEFAULT)); + | ^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:103:11 + | +LL | const CELL: Self = Self::DEFAULT; + | ^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:104:11 + | +LL | const CELL_BY_DEFAULT: Self = Self::Cell(Cell::DEFAULT); + | ^^^^^^^^^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:116:11 + | +LL | const GENERIC_CELL: Self = Self::GenericEnumCell(GenericEnumCell::::CELL); + | ^^^^^^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:118:11 + | +LL | const ENUM_CELL: Self = Self::EnumCell(GenericEnumCell::::CELL); + | ^^^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:123:11 + | +LL | const CELL: Cell; + | ^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:127:11 + | +LL | const SOME_CELL: Option> = Some(Cell::new(Self::DEFAULT)); + | ^^^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:136:11 + | +LL | const CELL: Cell; + | ^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:140:11 + | +LL | const SOME_CELL: Option> = Some(Cell::new(Self::DEFAULT)); + | ^^^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:160:11 + | +LL | const VALUE: Self::T = Cell::new(0); + | ^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:171:11 + | +LL | const VALUE: ::T = Cell::new(0); + | ^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:181:11 + | +LL | const VALUE: Self::T = Cell::new(0); + | ^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:196:11 + | +LL | const VALUE: Self::T> = Some(Cell::new(0)); + | ^^^^^ + +error: aborting due to 28 previous errors + diff --git a/tests/ui/declare_interior_mutable_const/enums.rs b/tests/ui/declare_interior_mutable_const/enums.rs deleted file mode 100644 index c87468277fb31..0000000000000 --- a/tests/ui/declare_interior_mutable_const/enums.rs +++ /dev/null @@ -1,135 +0,0 @@ -#![warn(clippy::declare_interior_mutable_const)] - -use std::cell::Cell; -use std::sync::atomic::AtomicUsize; - -enum OptionalCell { - Unfrozen(Cell), - Frozen, -} - -// a constant with enums should be linted only when the used variant is unfrozen (#3962). -const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); -//~^ declare_interior_mutable_const -const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; - -const fn unfrozen_variant() -> OptionalCell { - OptionalCell::Unfrozen(Cell::new(false)) -} - -const fn frozen_variant() -> OptionalCell { - OptionalCell::Frozen -} - -const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); -//~^ declare_interior_mutable_const -const FROZEN_VARIANT_FROM_FN: OptionalCell = frozen_variant(); - -enum NestedInnermost { - Unfrozen(AtomicUsize), - Frozen, -} - -struct NestedInner { - inner: NestedInnermost, -} - -enum NestedOuter { - NestedInner(NestedInner), - NotNested(usize), -} - -struct NestedOutermost { - outer: NestedOuter, -} - -// a constant with enums should be linted according to its value, no matter how structs involve. -const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost { - //~^ declare_interior_mutable_const - outer: NestedOuter::NestedInner(NestedInner { - inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)), - }), -}; -const NESTED_FROZEN_VARIANT: NestedOutermost = NestedOutermost { - outer: NestedOuter::NestedInner(NestedInner { - inner: NestedInnermost::Frozen, - }), -}; - -trait AssocConsts { - // When there's no default value, lint it only according to its type. - // Further details are on the corresponding code (`NonCopyConst::check_trait_item`). - const TO_BE_UNFROZEN_VARIANT: OptionalCell; - //~^ declare_interior_mutable_const - const TO_BE_FROZEN_VARIANT: OptionalCell; - //~^ declare_interior_mutable_const - - // Lint default values accordingly. - const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); - //~^ declare_interior_mutable_const - const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; -} - -// The lint doesn't trigger for an assoc constant in a trait impl with an unfrozen type even if it -// has enums. Further details are on the corresponding code in 'NonCopyConst::check_impl_item'. -impl AssocConsts for u64 { - const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); - const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; - - // even if this sets an unfrozen variant, the lint ignores it. - const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); -} - -// At first, I thought I'd need to check every patterns in `trait.rs`; but, what matters -// here are values; and I think substituted generics at definitions won't appear in MIR. -trait AssocTypes { - type ToBeUnfrozen; - - const TO_BE_UNFROZEN_VARIANT: Option; - const TO_BE_FROZEN_VARIANT: Option; -} - -impl AssocTypes for u64 { - type ToBeUnfrozen = AtomicUsize; - - const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); - //~^ declare_interior_mutable_const - const TO_BE_FROZEN_VARIANT: Option = None; -} - -// Use raw pointers since direct generics have a false negative at the type level. -enum BothOfCellAndGeneric { - Unfrozen(Cell<*const T>), - Generic(*const T), - Frozen(usize), -} - -impl BothOfCellAndGeneric { - const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); - //~^ declare_interior_mutable_const - - // This is a false positive. The argument about this is on `is_value_unfrozen_raw` - const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); - //~^ declare_interior_mutable_const - - const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); - - // This is what is likely to be a false negative when one tries to fix - // the `GENERIC_VARIANT` false positive. - const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); - //~^ declare_interior_mutable_const -} - -// associated types here is basically the same as the one above. -trait BothOfCellAndGenericWithAssocType { - type AssocType; - - const UNFROZEN_VARIANT: BothOfCellAndGeneric = - //~^ declare_interior_mutable_const - BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); - const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); - //~^ declare_interior_mutable_const - const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); -} - -fn main() {} diff --git a/tests/ui/declare_interior_mutable_const/enums.stderr b/tests/ui/declare_interior_mutable_const/enums.stderr deleted file mode 100644 index 32839d14f0ed3..0000000000000 --- a/tests/ui/declare_interior_mutable_const/enums.stderr +++ /dev/null @@ -1,89 +0,0 @@ -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:12:1 - | -LL | const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` - = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:24:1 - | -LL | const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:47:1 - | -LL | / const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost { -LL | | -LL | | outer: NestedOuter::NestedInner(NestedInner { -LL | | inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)), -LL | | }), -LL | | }; - | |__^ - | - = help: consider making this a static item - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:62:5 - | -LL | const TO_BE_UNFROZEN_VARIANT: OptionalCell; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:64:5 - | -LL | const TO_BE_FROZEN_VARIANT: OptionalCell; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:68:5 - | -LL | const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:95:5 - | -LL | const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:108:5 - | -LL | const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:112:5 - | -LL | const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:119:5 - | -LL | const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:127:5 - | -LL | / const UNFROZEN_VARIANT: BothOfCellAndGeneric = -LL | | -LL | | BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); - | |____________________________________________________________________^ - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:130:5 - | -LL | const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 12 previous errors - diff --git a/tests/ui/declare_interior_mutable_const/others.rs b/tests/ui/declare_interior_mutable_const/others.rs deleted file mode 100644 index 7ce04a3f2c340..0000000000000 --- a/tests/ui/declare_interior_mutable_const/others.rs +++ /dev/null @@ -1,76 +0,0 @@ -#![warn(clippy::declare_interior_mutable_const)] - -use std::borrow::Cow; -use std::cell::Cell; -use std::fmt::Display; -use std::ptr; -use std::sync::Once; -use std::sync::atomic::AtomicUsize; - -const ATOMIC: AtomicUsize = AtomicUsize::new(5); -//~^ declare_interior_mutable_const -const CELL: Cell = Cell::new(6); -//~^ declare_interior_mutable_const -const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); -//~^ declare_interior_mutable_const - -macro_rules! declare_const { - ($name:ident: $ty:ty = $e:expr) => { - const $name: $ty = $e; - //~^ declare_interior_mutable_const - }; -} -declare_const!(_ONCE: Once = Once::new()); - -// const ATOMIC_REF: &AtomicUsize = &AtomicUsize::new(7); // This will simply trigger E0492. - -const INTEGER: u8 = 8; -const STRING: String = String::new(); -const STR: &str = "012345"; -const COW: Cow = Cow::Borrowed("abcdef"); -// note: a const item of Cow is used in the `postgres` package. - -const NO_ANN: &dyn Display = &70; - -static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING); -// there should be no lints on the line above line - -mod issue_8493 { - use std::cell::Cell; - - thread_local! { - static _BAR: Cell = const { Cell::new(0) }; - } - - macro_rules! issue_8493 { - () => { - const _BAZ: Cell = Cell::new(0); - //~^ declare_interior_mutable_const - static _FOOBAR: () = { - thread_local! { - static _VAR: Cell = const { Cell::new(0) }; - } - }; - }; - } - - issue_8493!(); -} - -#[repr(C, align(8))] -struct NoAtomic(usize); -#[repr(C, align(8))] -struct WithAtomic(AtomicUsize); - -const fn with_non_null() -> *const WithAtomic { - const NO_ATOMIC: NoAtomic = NoAtomic(0); - (&NO_ATOMIC as *const NoAtomic).cast() -} -const WITH_ATOMIC: *const WithAtomic = with_non_null(); - -struct Generic(T); -impl Generic { - const RAW_POINTER: *const Cell = ptr::null(); -} - -fn main() {} diff --git a/tests/ui/declare_interior_mutable_const/others.stderr b/tests/ui/declare_interior_mutable_const/others.stderr deleted file mode 100644 index 09299b290416d..0000000000000 --- a/tests/ui/declare_interior_mutable_const/others.stderr +++ /dev/null @@ -1,50 +0,0 @@ -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/others.rs:10:1 - | -LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider making this a static item - = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/others.rs:12:1 - | -LL | const CELL: Cell = Cell::new(6); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/others.rs:14:1 - | -LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider making this a static item - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/others.rs:19:9 - | -LL | const $name: $ty = $e; - | ^^^^^^^^^^^^^^^^^^^^^^ -... -LL | declare_const!(_ONCE: Once = Once::new()); - | ----------------------------------------- in this macro invocation - | - = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/others.rs:47:13 - | -LL | const _BAZ: Cell = Cell::new(0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | issue_8493!(); - | ------------- in this macro invocation - | - = note: this error originates in the macro `issue_8493` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 5 previous errors - diff --git a/tests/ui/declare_interior_mutable_const/traits.rs b/tests/ui/declare_interior_mutable_const/traits.rs deleted file mode 100644 index d3139be6859f3..0000000000000 --- a/tests/ui/declare_interior_mutable_const/traits.rs +++ /dev/null @@ -1,162 +0,0 @@ -#![warn(clippy::declare_interior_mutable_const)] - -use std::borrow::Cow; -use std::cell::Cell; -use std::sync::atomic::AtomicUsize; - -macro_rules! declare_const { - ($name:ident: $ty:ty = $e:expr) => { - const $name: $ty = $e; - //~^ declare_interior_mutable_const - }; -} - -// a constant whose type is a concrete type should be linted at the definition site. -trait ConcreteTypes { - const ATOMIC: AtomicUsize; - //~^ declare_interior_mutable_const - const INTEGER: u64; - const STRING: String; - declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); -} - -impl ConcreteTypes for u64 { - const ATOMIC: AtomicUsize = AtomicUsize::new(9); - const INTEGER: u64 = 10; - const STRING: String = String::new(); -} - -// a helper trait used below -trait ConstDefault { - const DEFAULT: Self; -} - -// a constant whose type is a generic type should be linted at the implementation site. -trait GenericTypes { - const TO_REMAIN_GENERIC: T; - const TO_BE_CONCRETE: U; - - const HAVING_DEFAULT: T = Self::TO_REMAIN_GENERIC; - declare_const!(IN_MACRO: T = Self::TO_REMAIN_GENERIC); -} - -impl GenericTypes for u64 { - const TO_REMAIN_GENERIC: T = T::DEFAULT; - const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); - //~^ declare_interior_mutable_const -} - -// a helper type used below -struct Wrapper(T); - -// a constant whose type is an associated type should be linted at the implementation site, too. -trait AssocTypes { - type ToBeFrozen; - type ToBeUnfrozen; - type ToBeGenericParam; - - const TO_BE_FROZEN: Self::ToBeFrozen; - const TO_BE_UNFROZEN: Self::ToBeUnfrozen; - const WRAPPED_TO_BE_UNFROZEN: Wrapper; - // to ensure it can handle things when a generic type remains after normalization. - const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper; -} - -impl AssocTypes for Vec { - type ToBeFrozen = u16; - type ToBeUnfrozen = AtomicUsize; - type ToBeGenericParam = T; - - const TO_BE_FROZEN: Self::ToBeFrozen = 12; - const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); - //~^ declare_interior_mutable_const - const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); - //~^ declare_interior_mutable_const - const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper = Wrapper(T::DEFAULT); -} - -// a helper trait used below -trait AssocTypesHelper { - type NotToBeBounded; - type ToBeBounded; - - const NOT_TO_BE_BOUNDED: Self::NotToBeBounded; -} - -// a constant whose type is an assoc type originated from a generic param bounded at the definition -// site should be linted at there. -trait AssocTypesFromGenericParam -where - T: AssocTypesHelper, -{ - const NOT_BOUNDED: T::NotToBeBounded; - const BOUNDED: T::ToBeBounded; - //~^ declare_interior_mutable_const -} - -impl AssocTypesFromGenericParam for u64 -where - T: AssocTypesHelper, -{ - // an associated type could remain unknown in a trait impl. - const NOT_BOUNDED: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED; - const BOUNDED: T::ToBeBounded = AtomicUsize::new(15); -} - -// a constant whose type is `Self` should be linted at the implementation site as well. -// (`Option` requires `Sized` bound.) -trait SelfType: Sized { - const SELF: Self; - // this was the one in the original issue (#5050). - const WRAPPED_SELF: Option; -} - -impl SelfType for u64 { - const SELF: Self = 16; - const WRAPPED_SELF: Option = Some(20); -} - -impl SelfType for AtomicUsize { - // this (interior mutable `Self` const) exists in `parking_lot`. - // `const_trait_impl` will replace it in the future, hopefully. - const SELF: Self = AtomicUsize::new(17); - //~^ declare_interior_mutable_const - const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); - //~^ declare_interior_mutable_const -} - -// Even though a constant contains a generic type, if it also have an interior mutable type, -// it should be linted at the definition site. -trait BothOfCellAndGeneric { - const DIRECT: Cell; - //~^ declare_interior_mutable_const - const INDIRECT: Cell<*const T>; - //~^ declare_interior_mutable_const -} - -impl BothOfCellAndGeneric for u64 { - const DIRECT: Cell = Cell::new(T::DEFAULT); - //~^ declare_interior_mutable_const - const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null()); -} - -struct Local(T); - -// a constant in an inherent impl are essentially the same as a normal const item -// except there can be a generic or associated type. -impl Local -where - T: ConstDefault + AssocTypesHelper, -{ - const ATOMIC: AtomicUsize = AtomicUsize::new(18); - //~^ declare_interior_mutable_const - const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy"); - - const GENERIC_TYPE: T = T::DEFAULT; - - const ASSOC_TYPE: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED; - const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); - //~^ declare_interior_mutable_const -} - -fn main() {} diff --git a/tests/ui/declare_interior_mutable_const/traits.stderr b/tests/ui/declare_interior_mutable_const/traits.stderr deleted file mode 100644 index b03dd7a084033..0000000000000 --- a/tests/ui/declare_interior_mutable_const/traits.stderr +++ /dev/null @@ -1,88 +0,0 @@ -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:16:5 - | -LL | const ATOMIC: AtomicUsize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:9:9 - | -LL | const $name: $ty = $e; - | ^^^^^^^^^^^^^^^^^^^^^^ -... -LL | declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); - | ---------------------------------------------------------- in this macro invocation - | - = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:45:5 - | -LL | const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:71:5 - | -LL | const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:73:5 - | -LL | const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:93:5 - | -LL | const BOUNDED: T::ToBeBounded; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:122:5 - | -LL | const SELF: Self = AtomicUsize::new(17); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:124:5 - | -LL | const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:131:5 - | -LL | const DIRECT: Cell; - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:133:5 - | -LL | const INDIRECT: Cell<*const T>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:138:5 - | -LL | const DIRECT: Cell = Cell::new(T::DEFAULT); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:151:5 - | -LL | const ATOMIC: AtomicUsize = AtomicUsize::new(18); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:158:5 - | -LL | const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 13 previous errors - diff --git a/tests/ui/deprecated.rs b/tests/ui/deprecated.rs index 2787f6406fe39..6b69bdd29ceac 100644 --- a/tests/ui/deprecated.rs +++ b/tests/ui/deprecated.rs @@ -2,20 +2,20 @@ // Use that command to update this file and do not edit by hand. // Manual edits will be overwritten. -#![warn(clippy::should_assert_eq)] //~ ERROR: lint `clippy::should_assert_eq` +#![warn(clippy::assign_ops)] //~ ERROR: lint `clippy::assign_ops` #![warn(clippy::extend_from_slice)] //~ ERROR: lint `clippy::extend_from_slice` -#![warn(clippy::range_step_by_zero)] //~ ERROR: lint `clippy::range_step_by_zero` -#![warn(clippy::unstable_as_slice)] //~ ERROR: lint `clippy::unstable_as_slice` -#![warn(clippy::unstable_as_mut_slice)] //~ ERROR: lint `clippy::unstable_as_mut_slice` +#![warn(clippy::match_on_vec_items)] //~ ERROR: lint `clippy::match_on_vec_items` #![warn(clippy::misaligned_transmute)] //~ ERROR: lint `clippy::misaligned_transmute` -#![warn(clippy::assign_ops)] //~ ERROR: lint `clippy::assign_ops` +#![warn(clippy::option_map_or_err_ok)] //~ ERROR: lint `clippy::option_map_or_err_ok` +#![warn(clippy::pub_enum_variant_names)] //~ ERROR: lint `clippy::pub_enum_variant_names` +#![warn(clippy::range_step_by_zero)] //~ ERROR: lint `clippy::range_step_by_zero` +#![warn(clippy::regex_macro)] //~ ERROR: lint `clippy::regex_macro` +#![warn(clippy::replace_consts)] //~ ERROR: lint `clippy::replace_consts` +#![warn(clippy::should_assert_eq)] //~ ERROR: lint `clippy::should_assert_eq` #![warn(clippy::unsafe_vector_initialization)] //~ ERROR: lint `clippy::unsafe_vector_initialization` +#![warn(clippy::unstable_as_mut_slice)] //~ ERROR: lint `clippy::unstable_as_mut_slice` +#![warn(clippy::unstable_as_slice)] //~ ERROR: lint `clippy::unstable_as_slice` #![warn(clippy::unused_collect)] //~ ERROR: lint `clippy::unused_collect` -#![warn(clippy::replace_consts)] //~ ERROR: lint `clippy::replace_consts` -#![warn(clippy::regex_macro)] //~ ERROR: lint `clippy::regex_macro` -#![warn(clippy::pub_enum_variant_names)] //~ ERROR: lint `clippy::pub_enum_variant_names` #![warn(clippy::wrong_pub_self_convention)] //~ ERROR: lint `clippy::wrong_pub_self_convention` -#![warn(clippy::option_map_or_err_ok)] //~ ERROR: lint `clippy::option_map_or_err_ok` -#![warn(clippy::match_on_vec_items)] //~ ERROR: lint `clippy::match_on_vec_items` fn main() {} diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr index 604732405c370..07e59d33d608b 100644 --- a/tests/ui/deprecated.stderr +++ b/tests/ui/deprecated.stderr @@ -1,8 +1,8 @@ -error: lint `clippy::should_assert_eq` has been removed: `assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can +error: lint `clippy::assign_ops` has been removed: compound operators are harmless and linting on them is not in scope for clippy --> tests/ui/deprecated.rs:5:9 | -LL | #![warn(clippy::should_assert_eq)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::assign_ops)] + | ^^^^^^^^^^^^^^^^^^ | = note: `-D renamed-and-removed-lints` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]` @@ -13,83 +13,83 @@ error: lint `clippy::extend_from_slice` has been removed: `Vec::extend_from_slic LL | #![warn(clippy::extend_from_slice)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::range_step_by_zero` has been removed: `Iterator::step_by(0)` now panics and is no longer an infinite iterator +error: lint `clippy::match_on_vec_items` has been removed: `clippy::indexing_slicing` covers indexing and slicing on `Vec<_>` --> tests/ui/deprecated.rs:7:9 | -LL | #![warn(clippy::range_step_by_zero)] +LL | #![warn(clippy::match_on_vec_items)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` is now stable +error: lint `clippy::misaligned_transmute` has been removed: split into `clippy::cast_ptr_alignment` and `clippy::transmute_ptr_to_ptr` --> tests/ui/deprecated.rs:8:9 | -LL | #![warn(clippy::unstable_as_slice)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::misaligned_transmute)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` is now stable +error: lint `clippy::option_map_or_err_ok` has been removed: `clippy::manual_ok_or` covers this case --> tests/ui/deprecated.rs:9:9 | -LL | #![warn(clippy::unstable_as_mut_slice)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::option_map_or_err_ok)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::misaligned_transmute` has been removed: split into `clippy::cast_ptr_alignment` and `clippy::transmute_ptr_to_ptr` +error: lint `clippy::pub_enum_variant_names` has been removed: `clippy::enum_variant_names` now covers this case via the `avoid-breaking-exported-api` config --> tests/ui/deprecated.rs:10:9 | -LL | #![warn(clippy::misaligned_transmute)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::pub_enum_variant_names)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::assign_ops` has been removed: compound operators are harmless and linting on them is not in scope for clippy +error: lint `clippy::range_step_by_zero` has been removed: `Iterator::step_by(0)` now panics and is no longer an infinite iterator --> tests/ui/deprecated.rs:11:9 | -LL | #![warn(clippy::assign_ops)] - | ^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::range_step_by_zero)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::unsafe_vector_initialization` has been removed: the suggested alternative could be substantially slower +error: lint `clippy::regex_macro` has been removed: the `regex!` macro was removed from the regex crate in 2018 --> tests/ui/deprecated.rs:12:9 | -LL | #![warn(clippy::unsafe_vector_initialization)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::regex_macro)] + | ^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::unused_collect` has been removed: `Iterator::collect` is now marked as `#[must_use]` +error: lint `clippy::replace_consts` has been removed: `min_value` and `max_value` are now deprecated --> tests/ui/deprecated.rs:13:9 | -LL | #![warn(clippy::unused_collect)] +LL | #![warn(clippy::replace_consts)] | ^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::replace_consts` has been removed: `min_value` and `max_value` are now deprecated +error: lint `clippy::should_assert_eq` has been removed: `assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can --> tests/ui/deprecated.rs:14:9 | -LL | #![warn(clippy::replace_consts)] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::should_assert_eq)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::regex_macro` has been removed: the `regex!` macro was removed from the regex crate in 2018 +error: lint `clippy::unsafe_vector_initialization` has been removed: the suggested alternative could be substantially slower --> tests/ui/deprecated.rs:15:9 | -LL | #![warn(clippy::regex_macro)] - | ^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::unsafe_vector_initialization)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::pub_enum_variant_names` has been removed: `clippy::enum_variant_names` now covers this case via the `avoid-breaking-exported-api` config +error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` is now stable --> tests/ui/deprecated.rs:16:9 | -LL | #![warn(clippy::pub_enum_variant_names)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::unstable_as_mut_slice)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::wrong_pub_self_convention` has been removed: `clippy::wrong_self_convention` now covers this case via the `avoid-breaking-exported-api` config +error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` is now stable --> tests/ui/deprecated.rs:17:9 | -LL | #![warn(clippy::wrong_pub_self_convention)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::unstable_as_slice)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::option_map_or_err_ok` has been removed: `clippy::manual_ok_or` covers this case +error: lint `clippy::unused_collect` has been removed: `Iterator::collect` is now marked as `#[must_use]` --> tests/ui/deprecated.rs:18:9 | -LL | #![warn(clippy::option_map_or_err_ok)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::unused_collect)] + | ^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::match_on_vec_items` has been removed: `clippy::indexing_slicing` covers indexing and slicing on `Vec<_>` +error: lint `clippy::wrong_pub_self_convention` has been removed: `clippy::wrong_self_convention` now covers this case via the `avoid-breaking-exported-api` config --> tests/ui/deprecated.rs:19:9 | -LL | #![warn(clippy::match_on_vec_items)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::wrong_pub_self_convention)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 15 previous errors diff --git a/tests/ui/double_ended_iterator_last_unfixable.rs b/tests/ui/double_ended_iterator_last_unfixable.rs index e9218bbb40940..73f62ac124698 100644 --- a/tests/ui/double_ended_iterator_last_unfixable.rs +++ b/tests/ui/double_ended_iterator_last_unfixable.rs @@ -1,4 +1,4 @@ -//@no-rustfix +//@no-rustfix: requires manual changes #![warn(clippy::double_ended_iterator_last)] // Should not be linted because applying the lint would move the original iterator. This can only be diff --git a/tests/ui/empty_structs_with_brackets.fixed b/tests/ui/empty_structs_with_brackets.fixed index b1600862a8f60..419cf2354f89b 100644 --- a/tests/ui/empty_structs_with_brackets.fixed +++ b/tests/ui/empty_structs_with_brackets.fixed @@ -23,4 +23,12 @@ struct MyTupleStruct(usize, String); // should not trigger lint struct MySingleTupleStruct(usize); // should not trigger lint struct MyUnitLikeStruct; // should not trigger lint +macro_rules! empty_struct { + ($s:ident) => { + struct $s {} + }; +} + +empty_struct!(FromMacro); + fn main() {} diff --git a/tests/ui/empty_structs_with_brackets.rs b/tests/ui/empty_structs_with_brackets.rs index 1f69c4be9ec77..90c415c122063 100644 --- a/tests/ui/empty_structs_with_brackets.rs +++ b/tests/ui/empty_structs_with_brackets.rs @@ -23,4 +23,12 @@ struct MyTupleStruct(usize, String); // should not trigger lint struct MySingleTupleStruct(usize); // should not trigger lint struct MyUnitLikeStruct; // should not trigger lint +macro_rules! empty_struct { + ($s:ident) => { + struct $s {} + }; +} + +empty_struct!(FromMacro); + fn main() {} diff --git a/tests/ui/entry_unfixable.rs b/tests/ui/entry_unfixable.rs index dbdacf950569c..c4c055572086e 100644 --- a/tests/ui/entry_unfixable.rs +++ b/tests/ui/entry_unfixable.rs @@ -1,6 +1,5 @@ -#![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)] +#![allow(clippy::needless_pass_by_value, clippy::collapsible_if)] #![warn(clippy::map_entry)] -//@no-rustfix use std::collections::HashMap; use std::hash::Hash; diff --git a/tests/ui/entry_unfixable.stderr b/tests/ui/entry_unfixable.stderr index 9f9956d351b29..0197d2ab4cf9c 100644 --- a/tests/ui/entry_unfixable.stderr +++ b/tests/ui/entry_unfixable.stderr @@ -1,5 +1,5 @@ error: usage of `contains_key` followed by `insert` on a `HashMap` - --> tests/ui/entry_unfixable.rs:28:13 + --> tests/ui/entry_unfixable.rs:27:13 | LL | / if !self.values.contains_key(&name) { LL | | @@ -14,7 +14,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::map_entry)]` error: usage of `contains_key` followed by `insert` on a `HashMap` - --> tests/ui/entry_unfixable.rs:43:5 + --> tests/ui/entry_unfixable.rs:42:5 | LL | / if hm.contains_key(&key) { LL | | @@ -26,7 +26,7 @@ LL | | } | |_____^ error: usage of `contains_key` followed by `insert` on a `HashMap` - --> tests/ui/entry_unfixable.rs:81:13 + --> tests/ui/entry_unfixable.rs:80:13 | LL | / if self.globals.contains_key(&name) { LL | | diff --git a/tests/ui/excessive_precision.fixed b/tests/ui/excessive_precision.fixed index 99d09774d16d3..8a8c2e1939c83 100644 --- a/tests/ui/excessive_precision.fixed +++ b/tests/ui/excessive_precision.fixed @@ -79,6 +79,9 @@ fn main() { // issue #2840 let num = 0.000_000_000_01e-10f64; + // issue #6341 + let exponential: f64 = 4.886506780521244E-03; + // issue #7744 let _ = 2.225_073_858_507_201e-308_f64; //~^ excessive_precision diff --git a/tests/ui/excessive_precision.rs b/tests/ui/excessive_precision.rs index a542fb2e7e3cd..5dcf55cb92735 100644 --- a/tests/ui/excessive_precision.rs +++ b/tests/ui/excessive_precision.rs @@ -79,6 +79,9 @@ fn main() { // issue #2840 let num = 0.000_000_000_01e-10f64; + // issue #6341 + let exponential: f64 = 4.886506780521244E-03; + // issue #7744 let _ = 2.225_073_858_507_201_1e-308_f64; //~^ excessive_precision diff --git a/tests/ui/excessive_precision.stderr b/tests/ui/excessive_precision.stderr index 934a367e10659..f5eeadf0c8cb0 100644 --- a/tests/ui/excessive_precision.stderr +++ b/tests/ui/excessive_precision.stderr @@ -157,7 +157,7 @@ LL + let bad_bige32: f32 = 1.123_456_8E-10; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:83:13 + --> tests/ui/excessive_precision.rs:86:13 | LL | let _ = 2.225_073_858_507_201_1e-308_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +169,7 @@ LL + let _ = 2.225_073_858_507_201e-308_f64; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:87:13 + --> tests/ui/excessive_precision.rs:90:13 | LL | let _ = 1.000_000_000_000_001e-324_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL + let _ = 0_f64; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:98:20 + --> tests/ui/excessive_precision.rs:101:20 | LL | const _: f64 = 3.0000000000000000e+00; | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/explicit_counter_loop.rs b/tests/ui/explicit_counter_loop.rs index 8340d99ace226..13934785d7b15 100644 --- a/tests/ui/explicit_counter_loop.rs +++ b/tests/ui/explicit_counter_loop.rs @@ -1,6 +1,6 @@ #![warn(clippy::explicit_counter_loop)] #![allow(clippy::uninlined_format_args, clippy::useless_vec)] -//@no-rustfix +//@no-rustfix: suggestion does not remove the `+= 1` fn main() { let mut vec = vec![1, 2, 3, 4]; let mut _index = 0; diff --git a/tests/ui/explicit_deref_methods.fixed b/tests/ui/explicit_deref_methods.fixed index 0d1a5f80f3d5a..619329a6ade0c 100644 --- a/tests/ui/explicit_deref_methods.fixed +++ b/tests/ui/explicit_deref_methods.fixed @@ -8,7 +8,8 @@ clippy::needless_borrow, clippy::no_effect, clippy::uninlined_format_args, - clippy::unnecessary_literal_unwrap + clippy::unnecessary_literal_unwrap, + clippy::deref_addrof )] use std::ops::{Deref, DerefMut}; @@ -87,9 +88,6 @@ fn main() { let b = &*opt_a.unwrap(); //~^ explicit_deref_methods - // make sure `Aaa::deref` instead of `aaa.deref()` is not linted, as well as fully qualified - // syntax - Aaa::deref(&Aaa); Aaa::deref_mut(&mut Aaa); ::deref(&Aaa); @@ -139,4 +137,9 @@ fn main() { let no_lint = NoLint(42); let b = no_lint.deref(); let b = no_lint.deref_mut(); + + let _ = &*&"foo"; //~ explicit_deref_methods + let mut x = String::new(); + let _ = &&mut **&mut x; //~ explicit_deref_methods + let _ = &&mut ***(&mut &mut x); //~ explicit_deref_methods } diff --git a/tests/ui/explicit_deref_methods.rs b/tests/ui/explicit_deref_methods.rs index 8d4a899cd2607..9f2d513283c9b 100644 --- a/tests/ui/explicit_deref_methods.rs +++ b/tests/ui/explicit_deref_methods.rs @@ -8,7 +8,8 @@ clippy::needless_borrow, clippy::no_effect, clippy::uninlined_format_args, - clippy::unnecessary_literal_unwrap + clippy::unnecessary_literal_unwrap, + clippy::deref_addrof )] use std::ops::{Deref, DerefMut}; @@ -87,9 +88,6 @@ fn main() { let b = opt_a.unwrap().deref(); //~^ explicit_deref_methods - // make sure `Aaa::deref` instead of `aaa.deref()` is not linted, as well as fully qualified - // syntax - Aaa::deref(&Aaa); Aaa::deref_mut(&mut Aaa); ::deref(&Aaa); @@ -139,4 +137,9 @@ fn main() { let no_lint = NoLint(42); let b = no_lint.deref(); let b = no_lint.deref_mut(); + + let _ = &Deref::deref(&"foo"); //~ explicit_deref_methods + let mut x = String::new(); + let _ = &DerefMut::deref_mut(&mut x); //~ explicit_deref_methods + let _ = &DerefMut::deref_mut((&mut &mut x).deref_mut()); //~ explicit_deref_methods } diff --git a/tests/ui/explicit_deref_methods.stderr b/tests/ui/explicit_deref_methods.stderr index 2ca376cba00bd..a81e2f60317b3 100644 --- a/tests/ui/explicit_deref_methods.stderr +++ b/tests/ui/explicit_deref_methods.stderr @@ -1,5 +1,5 @@ error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:54:19 + --> tests/ui/explicit_deref_methods.rs:55:19 | LL | let b: &str = a.deref(); | ^^^^^^^^^ help: try: `&*a` @@ -8,70 +8,88 @@ LL | let b: &str = a.deref(); = help: to override `-D warnings` add `#[allow(clippy::explicit_deref_methods)]` error: explicit `deref_mut` method call - --> tests/ui/explicit_deref_methods.rs:57:23 + --> tests/ui/explicit_deref_methods.rs:58:23 | LL | let b: &mut str = a.deref_mut(); | ^^^^^^^^^^^^^ help: try: `&mut **a` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:61:39 + --> tests/ui/explicit_deref_methods.rs:62:39 | LL | let b: String = format!("{}, {}", a.deref(), a.deref()); | ^^^^^^^^^ help: try: `&*a` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:61:50 + --> tests/ui/explicit_deref_methods.rs:62:50 | LL | let b: String = format!("{}, {}", a.deref(), a.deref()); | ^^^^^^^^^ help: try: `&*a` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:65:20 + --> tests/ui/explicit_deref_methods.rs:66:20 | LL | println!("{}", a.deref()); | ^^^^^^^^^ help: try: `&*a` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:69:11 + --> tests/ui/explicit_deref_methods.rs:70:11 | LL | match a.deref() { | ^^^^^^^^^ help: try: `&*a` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:74:28 + --> tests/ui/explicit_deref_methods.rs:75:28 | LL | let b: String = concat(a.deref()); | ^^^^^^^^^ help: try: `&*a` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:77:13 + --> tests/ui/explicit_deref_methods.rs:78:13 | LL | let b = just_return(a).deref(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `just_return(a)` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:80:28 + --> tests/ui/explicit_deref_methods.rs:81:28 | LL | let b: String = concat(just_return(a).deref()); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `just_return(a)` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:83:19 + --> tests/ui/explicit_deref_methods.rs:84:19 | LL | let b: &str = a.deref().deref(); | ^^^^^^^^^^^^^^^^^ help: try: `&**a` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:87:13 + --> tests/ui/explicit_deref_methods.rs:88:13 | LL | let b = opt_a.unwrap().deref(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*opt_a.unwrap()` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:125:31 + --> tests/ui/explicit_deref_methods.rs:123:31 | LL | let b: &str = expr_deref!(a.deref()); | ^^^^^^^^^ help: try: `&*a` -error: aborting due to 12 previous errors +error: explicit `deref` method call + --> tests/ui/explicit_deref_methods.rs:141:14 + | +LL | let _ = &Deref::deref(&"foo"); + | ^^^^^^^^^^^^^^^^^^^^ help: try: `*&"foo"` + +error: explicit `deref_mut` method call + --> tests/ui/explicit_deref_methods.rs:143:14 + | +LL | let _ = &DerefMut::deref_mut(&mut x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut **&mut x` + +error: explicit `deref_mut` method call + --> tests/ui/explicit_deref_methods.rs:144:14 + | +LL | let _ = &DerefMut::deref_mut((&mut &mut x).deref_mut()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut ***(&mut &mut x)` + +error: aborting due to 15 previous errors diff --git a/tests/ui/explicit_into_iter_loop.fixed b/tests/ui/explicit_into_iter_loop.fixed index 2b68906ae39fa..c1b3c478eeb91 100644 --- a/tests/ui/explicit_into_iter_loop.fixed +++ b/tests/ui/explicit_into_iter_loop.fixed @@ -73,3 +73,16 @@ fn main() { for _ in S.into_iter::() {} } + +fn issue14630() { + macro_rules! mac { + (into_iter $e:expr) => { + $e.into_iter() + }; + } + + for _ in dbg!([1, 2]) {} + //~^ explicit_into_iter_loop + + for _ in mac!(into_iter [1, 2]) {} +} diff --git a/tests/ui/explicit_into_iter_loop.rs b/tests/ui/explicit_into_iter_loop.rs index ca335b62d9068..581e0dadcecb3 100644 --- a/tests/ui/explicit_into_iter_loop.rs +++ b/tests/ui/explicit_into_iter_loop.rs @@ -73,3 +73,16 @@ fn main() { for _ in S.into_iter::() {} } + +fn issue14630() { + macro_rules! mac { + (into_iter $e:expr) => { + $e.into_iter() + }; + } + + for _ in dbg!([1, 2]).into_iter() {} + //~^ explicit_into_iter_loop + + for _ in mac!(into_iter [1, 2]) {} +} diff --git a/tests/ui/explicit_into_iter_loop.stderr b/tests/ui/explicit_into_iter_loop.stderr index 1c3156755d4ee..26fb11e004822 100644 --- a/tests/ui/explicit_into_iter_loop.stderr +++ b/tests/ui/explicit_into_iter_loop.stderr @@ -37,5 +37,11 @@ error: it is more concise to loop over containers instead of using explicit iter LL | for _ in mr.into_iter() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut *mr` -error: aborting due to 6 previous errors +error: it is more concise to loop over containers instead of using explicit iteration methods + --> tests/ui/explicit_into_iter_loop.rs:84:14 + | +LL | for _ in dbg!([1, 2]).into_iter() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `dbg!([1, 2])` + +error: aborting due to 7 previous errors diff --git a/tests/ui/explicit_iter_loop.fixed b/tests/ui/explicit_iter_loop.fixed index cd0898dfc3672..f246ec61800e1 100644 --- a/tests/ui/explicit_iter_loop.fixed +++ b/tests/ui/explicit_iter_loop.fixed @@ -183,3 +183,16 @@ pub fn issue_13184() { let rvalues = &values; for _ in rvalues.iter() {} } + +fn issue14630() { + macro_rules! mac { + (iter $e:expr) => { + $e.into_iter() + }; + } + + for _ in &dbg!([1, 2]) {} + //~^ explicit_iter_loop + + for _ in mac!(iter [1, 2]) {} +} diff --git a/tests/ui/explicit_iter_loop.rs b/tests/ui/explicit_iter_loop.rs index 02405280ce423..35f4fb7097d89 100644 --- a/tests/ui/explicit_iter_loop.rs +++ b/tests/ui/explicit_iter_loop.rs @@ -183,3 +183,16 @@ pub fn issue_13184() { let rvalues = &values; for _ in rvalues.iter() {} } + +fn issue14630() { + macro_rules! mac { + (iter $e:expr) => { + $e.into_iter() + }; + } + + for _ in dbg!([1, 2]).iter() {} + //~^ explicit_iter_loop + + for _ in mac!(iter [1, 2]) {} +} diff --git a/tests/ui/explicit_iter_loop.stderr b/tests/ui/explicit_iter_loop.stderr index 3816bb4db98b3..575dbe7813d75 100644 --- a/tests/ui/explicit_iter_loop.stderr +++ b/tests/ui/explicit_iter_loop.stderr @@ -112,5 +112,11 @@ error: it is more concise to loop over references to containers instead of using LL | for _ in r.iter() {} | ^^^^^^^^ help: to write this more concisely, try: `r` -error: aborting due to 18 previous errors +error: it is more concise to loop over references to containers instead of using explicit iteration methods + --> tests/ui/explicit_iter_loop.rs:194:14 + | +LL | for _ in dbg!([1, 2]).iter() {} + | ^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&dbg!([1, 2])` + +error: aborting due to 19 previous errors diff --git a/tests/ui/filter_map_bool_then_unfixable.rs b/tests/ui/filter_map_bool_then_unfixable.rs index 68294292502ac..5d29e0317bb2f 100644 --- a/tests/ui/filter_map_bool_then_unfixable.rs +++ b/tests/ui/filter_map_bool_then_unfixable.rs @@ -1,6 +1,5 @@ -#![allow(clippy::question_mark, unused)] +#![allow(clippy::question_mark)] #![warn(clippy::filter_map_bool_then)] -//@no-rustfix fn issue11617() { let mut x: Vec = vec![0; 10]; diff --git a/tests/ui/filter_map_bool_then_unfixable.stderr b/tests/ui/filter_map_bool_then_unfixable.stderr index 2025958136ba6..2990423973e10 100644 --- a/tests/ui/filter_map_bool_then_unfixable.stderr +++ b/tests/ui/filter_map_bool_then_unfixable.stderr @@ -1,5 +1,5 @@ error: usage of `bool::then` in `filter_map` - --> tests/ui/filter_map_bool_then_unfixable.rs:7:48 + --> tests/ui/filter_map_bool_then_unfixable.rs:6:48 | LL | let _ = (0..x.len()).zip(x.clone().iter()).filter_map(|(i, v)| { | ________________________________________________^ @@ -16,7 +16,7 @@ LL | | }); = help: to override `-D warnings` add `#[allow(clippy::filter_map_bool_then)]` error: usage of `bool::then` in `filter_map` - --> tests/ui/filter_map_bool_then_unfixable.rs:23:26 + --> tests/ui/filter_map_bool_then_unfixable.rs:22:26 | LL | let _ = x.iter().filter_map(|&x| x?.then(|| do_something(()))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | let _ = x.iter().filter_map(|&x| x?.then(|| do_something(()))); = help: consider using `filter` then `map` instead error: usage of `bool::then` in `filter_map` - --> tests/ui/filter_map_bool_then_unfixable.rs:27:14 + --> tests/ui/filter_map_bool_then_unfixable.rs:26:14 | LL | .filter_map(|&x| if let Some(x) = x { x } else { return None }.then(|| do_something(()))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | .filter_map(|&x| if let Some(x) = x { x } else { return None }. = help: consider using `filter` then `map` instead error: usage of `bool::then` in `filter_map` - --> tests/ui/filter_map_bool_then_unfixable.rs:29:26 + --> tests/ui/filter_map_bool_then_unfixable.rs:28:26 | LL | let _ = x.iter().filter_map(|&x| { | __________________________^ @@ -47,7 +47,7 @@ LL | | }); = help: consider using `filter` then `map` instead error: usage of `bool::then` in `filter_map` - --> tests/ui/filter_map_bool_then_unfixable.rs:47:26 + --> tests/ui/filter_map_bool_then_unfixable.rs:46:26 | LL | let _ = x.iter().filter_map(|&x| { | __________________________^ diff --git a/tests/ui/ifs_same_cond.rs b/tests/ui/ifs_same_cond.rs index ebc3acb1b77f6..7067434953d6e 100644 --- a/tests/ui/ifs_same_cond.rs +++ b/tests/ui/ifs_same_cond.rs @@ -6,19 +6,25 @@ fn ifs_same_cond() { let b = false; if b { + //~^ ifs_same_cond } else if b { + } + + if b { //~^ ifs_same_cond + } else if b { + } else if b { } if a == 1 { - } else if a == 1 { //~^ ifs_same_cond + } else if a == 1 { } if 2 * a == 1 { + //~^ ifs_same_cond } else if 2 * a == 2 { } else if 2 * a == 1 { - //~^ ifs_same_cond } else if a == 1 { } @@ -50,8 +56,8 @@ fn ifs_same_cond() { fn issue10272() { let a = String::from("ha"); if a.contains("ah") { - } else if a.contains("ah") { //~^ ifs_same_cond + } else if a.contains("ah") { // Trigger this lint } else if a.contains("ha") { diff --git a/tests/ui/ifs_same_cond.stderr b/tests/ui/ifs_same_cond.stderr index df21e6f1b8262..7acbc1a6399b6 100644 --- a/tests/ui/ifs_same_cond.stderr +++ b/tests/ui/ifs_same_cond.stderr @@ -1,52 +1,52 @@ -error: this `if` has the same condition as a previous `if` - --> tests/ui/ifs_same_cond.rs:9:15 - | -LL | } else if b { - | ^ - | -note: same as this +error: these `if` branches have the same condition --> tests/ui/ifs_same_cond.rs:8:8 | LL | if b { | ^ +LL | +LL | } else if b { + | ^ + | = note: `-D clippy::ifs-same-cond` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::ifs_same_cond)]` -error: this `if` has the same condition as a previous `if` - --> tests/ui/ifs_same_cond.rs:14:15 - | -LL | } else if a == 1 { - | ^^^^^^ - | -note: same as this +error: these `if` branches have the same condition --> tests/ui/ifs_same_cond.rs:13:8 | +LL | if b { + | ^ +LL | +LL | } else if b { + | ^ +LL | } else if b { + | ^ + +error: these `if` branches have the same condition + --> tests/ui/ifs_same_cond.rs:19:8 + | LL | if a == 1 { | ^^^^^^ +LL | +LL | } else if a == 1 { + | ^^^^^^ -error: this `if` has the same condition as a previous `if` - --> tests/ui/ifs_same_cond.rs:20:15 - | -LL | } else if 2 * a == 1 { - | ^^^^^^^^^^ - | -note: same as this - --> tests/ui/ifs_same_cond.rs:18:8 +error: these `if` branches have the same condition + --> tests/ui/ifs_same_cond.rs:24:8 | LL | if 2 * a == 1 { | ^^^^^^^^^^ +... +LL | } else if 2 * a == 1 { + | ^^^^^^^^^^ -error: this `if` has the same condition as a previous `if` - --> tests/ui/ifs_same_cond.rs:53:15 - | -LL | } else if a.contains("ah") { - | ^^^^^^^^^^^^^^^^ - | -note: same as this - --> tests/ui/ifs_same_cond.rs:52:8 +error: these `if` branches have the same condition + --> tests/ui/ifs_same_cond.rs:58:8 | LL | if a.contains("ah") { | ^^^^^^^^^^^^^^^^ +LL | +LL | } else if a.contains("ah") { + | ^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/impl_trait_in_params.rs b/tests/ui/impl_trait_in_params.rs index 2039f6339a878..72e3e068c9c79 100644 --- a/tests/ui/impl_trait_in_params.rs +++ b/tests/ui/impl_trait_in_params.rs @@ -1,7 +1,7 @@ #![allow(unused)] #![warn(clippy::impl_trait_in_params)] -//@no-rustfix +//@no-rustfix: has placeholders pub trait Trait {} pub trait AnotherTrait {} diff --git a/tests/ui/infinite_loop.rs b/tests/ui/infinite_loop.rs index 4a0968918bfbe..8ff7f3b0c18d8 100644 --- a/tests/ui/infinite_loop.rs +++ b/tests/ui/infinite_loop.rs @@ -1,5 +1,3 @@ -//@no-rustfix - fn fn_val(i: i32) -> i32 { unimplemented!() } diff --git a/tests/ui/infinite_loop.stderr b/tests/ui/infinite_loop.stderr index 7ba1374d64f46..04da9776c3025 100644 --- a/tests/ui/infinite_loop.stderr +++ b/tests/ui/infinite_loop.stderr @@ -1,5 +1,5 @@ error: variables in the condition are not mutated in the loop body - --> tests/ui/infinite_loop.rs:22:11 + --> tests/ui/infinite_loop.rs:20:11 | LL | while y < 10 { | ^^^^^^ @@ -8,7 +8,7 @@ LL | while y < 10 { = note: `#[deny(clippy::while_immutable_condition)]` on by default error: variables in the condition are not mutated in the loop body - --> tests/ui/infinite_loop.rs:29:11 + --> tests/ui/infinite_loop.rs:27:11 | LL | while y < 10 && x < 3 { | ^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | while y < 10 && x < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> tests/ui/infinite_loop.rs:38:11 + --> tests/ui/infinite_loop.rs:36:11 | LL | while !cond { | ^^^^^ @@ -24,7 +24,7 @@ LL | while !cond { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> tests/ui/infinite_loop.rs:84:11 + --> tests/ui/infinite_loop.rs:82:11 | LL | while i < 3 { | ^^^^^ @@ -32,7 +32,7 @@ LL | while i < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> tests/ui/infinite_loop.rs:91:11 + --> tests/ui/infinite_loop.rs:89:11 | LL | while i < 3 && j > 0 { | ^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | while i < 3 && j > 0 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> tests/ui/infinite_loop.rs:97:11 + --> tests/ui/infinite_loop.rs:95:11 | LL | while i < 3 { | ^^^^^ @@ -48,7 +48,7 @@ LL | while i < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> tests/ui/infinite_loop.rs:114:11 + --> tests/ui/infinite_loop.rs:112:11 | LL | while i < 3 { | ^^^^^ @@ -56,7 +56,7 @@ LL | while i < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> tests/ui/infinite_loop.rs:121:11 + --> tests/ui/infinite_loop.rs:119:11 | LL | while i < 3 { | ^^^^^ @@ -64,7 +64,7 @@ LL | while i < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> tests/ui/infinite_loop.rs:189:15 + --> tests/ui/infinite_loop.rs:187:15 | LL | while self.count < n { | ^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | while self.count < n { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> tests/ui/infinite_loop.rs:199:11 + --> tests/ui/infinite_loop.rs:197:11 | LL | while y < 10 { | ^^^^^^ @@ -82,7 +82,7 @@ LL | while y < 10 { = help: rewrite it as `if cond { loop { } }` error: variables in the condition are not mutated in the loop body - --> tests/ui/infinite_loop.rs:208:11 + --> tests/ui/infinite_loop.rs:206:11 | LL | while y < 10 { | ^^^^^^ diff --git a/tests/ui/infinite_loops.rs b/tests/ui/infinite_loops.rs index eaa8d00880682..fcd1f795fff09 100644 --- a/tests/ui/infinite_loops.rs +++ b/tests/ui/infinite_loops.rs @@ -1,4 +1,4 @@ -//@no-rustfix +//@no-rustfix: multiple suggestions add `-> !` to the same fn //@aux-build:proc_macros.rs #![allow(clippy::never_loop)] diff --git a/tests/ui/into_iter_without_iter.rs b/tests/ui/into_iter_without_iter.rs index 45e34b3930ad0..f0b86e5620e9b 100644 --- a/tests/ui/into_iter_without_iter.rs +++ b/tests/ui/into_iter_without_iter.rs @@ -1,4 +1,4 @@ -//@no-rustfix +//@no-rustfix: suggestions reference out of scope lifetimes/types //@aux-build:proc_macros.rs #![warn(clippy::into_iter_without_iter)] extern crate proc_macros; diff --git a/tests/ui/iter_next_loop.rs b/tests/ui/iter_next_loop.rs index 32711c7ef6239..8e62ed963b900 100644 --- a/tests/ui/iter_next_loop.rs +++ b/tests/ui/iter_next_loop.rs @@ -15,3 +15,16 @@ fn main() { let u = Unrelated(&[0]); for _v in u.next() {} // no error } + +fn issue14630() { + macro_rules! mac { + (next $e:expr) => { + $e.iter().next() + }; + } + + for _ in dbg!([1, 2].iter()).next() {} + //~^ iter_next_loop + + for _ in mac!(next [1, 2]) {} +} diff --git a/tests/ui/iter_next_loop.stderr b/tests/ui/iter_next_loop.stderr index acc55031c3b29..c076e86db93bb 100644 --- a/tests/ui/iter_next_loop.stderr +++ b/tests/ui/iter_next_loop.stderr @@ -7,5 +7,11 @@ LL | for _ in x.iter().next() {} = note: `-D clippy::iter-next-loop` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::iter_next_loop)]` -error: aborting due to 1 previous error +error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want + --> tests/ui/iter_next_loop.rs:26:14 + | +LL | for _ in dbg!([1, 2].iter()).next() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/tests/ui/iter_out_of_bounds.rs b/tests/ui/iter_out_of_bounds.rs index b34e4ad782409..6458b1342dcd5 100644 --- a/tests/ui/iter_out_of_bounds.rs +++ b/tests/ui/iter_out_of_bounds.rs @@ -1,5 +1,3 @@ -//@no-rustfix - #![deny(clippy::iter_out_of_bounds)] #![allow(clippy::useless_vec)] diff --git a/tests/ui/iter_out_of_bounds.stderr b/tests/ui/iter_out_of_bounds.stderr index 19ac60b9d0ac0..1b3a99e1e9457 100644 --- a/tests/ui/iter_out_of_bounds.stderr +++ b/tests/ui/iter_out_of_bounds.stderr @@ -1,18 +1,18 @@ error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:12:14 + --> tests/ui/iter_out_of_bounds.rs:10:14 | LL | for _ in [1, 2, 3].iter().skip(4) { | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this operation is useless and will create an empty iterator note: the lint level is defined here - --> tests/ui/iter_out_of_bounds.rs:3:9 + --> tests/ui/iter_out_of_bounds.rs:1:9 | LL | #![deny(clippy::iter_out_of_bounds)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `.take()` call takes more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:17:19 + --> tests/ui/iter_out_of_bounds.rs:15:19 | LL | for (i, _) in [1, 2, 3].iter().take(4).enumerate() { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | for (i, _) in [1, 2, 3].iter().take(4).enumerate() { = note: this operation is useless and the returned iterator will simply yield the same items error: this `.take()` call takes more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:24:14 + --> tests/ui/iter_out_of_bounds.rs:22:14 | LL | for _ in (&&&&&&[1, 2, 3]).iter().take(4) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL | for _ in (&&&&&&[1, 2, 3]).iter().take(4) {} = note: this operation is useless and the returned iterator will simply yield the same items error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:27:14 + --> tests/ui/iter_out_of_bounds.rs:25:14 | LL | for _ in [1, 2, 3].iter().skip(4) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | for _ in [1, 2, 3].iter().skip(4) {} = note: this operation is useless and will create an empty iterator error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:30:14 + --> tests/ui/iter_out_of_bounds.rs:28:14 | LL | for _ in [1; 3].iter().skip(4) {} | ^^^^^^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | for _ in [1; 3].iter().skip(4) {} = note: this operation is useless and will create an empty iterator error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:36:14 + --> tests/ui/iter_out_of_bounds.rs:34:14 | LL | for _ in vec![1, 2, 3].iter().skip(4) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -52,7 +52,7 @@ LL | for _ in vec![1, 2, 3].iter().skip(4) {} = note: this operation is useless and will create an empty iterator error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:39:14 + --> tests/ui/iter_out_of_bounds.rs:37:14 | LL | for _ in vec![1; 3].iter().skip(4) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL | for _ in vec![1; 3].iter().skip(4) {} = note: this operation is useless and will create an empty iterator error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:43:14 + --> tests/ui/iter_out_of_bounds.rs:41:14 | LL | for _ in x.iter().skip(4) {} | ^^^^^^^^^^^^^^^^ @@ -68,7 +68,7 @@ LL | for _ in x.iter().skip(4) {} = note: this operation is useless and will create an empty iterator error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:47:14 + --> tests/ui/iter_out_of_bounds.rs:45:14 | LL | for _ in x.iter().skip(n) {} | ^^^^^^^^^^^^^^^^ @@ -76,7 +76,7 @@ LL | for _ in x.iter().skip(n) {} = note: this operation is useless and will create an empty iterator error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:52:14 + --> tests/ui/iter_out_of_bounds.rs:50:14 | LL | for _ in empty().skip(1) {} | ^^^^^^^^^^^^^^^ @@ -84,7 +84,7 @@ LL | for _ in empty().skip(1) {} = note: this operation is useless and will create an empty iterator error: this `.take()` call takes more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:55:14 + --> tests/ui/iter_out_of_bounds.rs:53:14 | LL | for _ in empty().take(1) {} | ^^^^^^^^^^^^^^^ @@ -92,7 +92,7 @@ LL | for _ in empty().take(1) {} = note: this operation is useless and the returned iterator will simply yield the same items error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:58:14 + --> tests/ui/iter_out_of_bounds.rs:56:14 | LL | for _ in std::iter::once(1).skip(2) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -100,7 +100,7 @@ LL | for _ in std::iter::once(1).skip(2) {} = note: this operation is useless and will create an empty iterator error: this `.take()` call takes more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:61:14 + --> tests/ui/iter_out_of_bounds.rs:59:14 | LL | for _ in std::iter::once(1).take(2) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -108,7 +108,7 @@ LL | for _ in std::iter::once(1).take(2) {} = note: this operation is useless and the returned iterator will simply yield the same items error: this `.take()` call takes more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:64:14 + --> tests/ui/iter_out_of_bounds.rs:62:14 | LL | for x in [].iter().take(1) { | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/manual_inspect.fixed b/tests/ui/manual_inspect.fixed index ec87fe217aee6..9b768dbad700c 100644 --- a/tests/ui/manual_inspect.fixed +++ b/tests/ui/manual_inspect.fixed @@ -107,7 +107,7 @@ fn main() { let _ = || { let _x = x; }; - return ; + return; } println!("test"); }); diff --git a/tests/ui/manual_inspect.stderr b/tests/ui/manual_inspect.stderr index eb98f9f5995a3..78b085fdfca30 100644 --- a/tests/ui/manual_inspect.stderr +++ b/tests/ui/manual_inspect.stderr @@ -98,7 +98,7 @@ LL | if x.is_empty() { LL | let _ = || { LL ~ let _x = x; LL | }; -LL ~ return ; +LL ~ return; LL | } LL ~ println!("test"); | diff --git a/tests/ui/manual_slice_size_calculation.fixed b/tests/ui/manual_slice_size_calculation.fixed index 294d1e1506dec..090f0fd30c555 100644 --- a/tests/ui/manual_slice_size_calculation.fixed +++ b/tests/ui/manual_slice_size_calculation.fixed @@ -60,7 +60,26 @@ fn main() { let _ = size_of::() * 5 * s_i32.len(); // Ok (MISSED OPPORTUNITY) } -const fn _const(s_i32: &[i32]) { - // True negative: - let _ = s_i32.len() * size_of::(); // Ok, can't use size_of_val in const +#[clippy::msrv = "1.85"] +const fn const_ok(s_i32: &[i32]) { + let _ = std::mem::size_of_val(s_i32); + //~^ manual_slice_size_calculation +} + +#[clippy::msrv = "1.84"] +const fn const_before_msrv(s_i32: &[i32]) { + let _ = s_i32.len() * size_of::(); +} + +fn issue_14802() { + struct IcedSlice { + dst: [u8], + } + + impl IcedSlice { + fn get_len(&self) -> usize { + std::mem::size_of_val(&self.dst) + //~^ manual_slice_size_calculation + } + } } diff --git a/tests/ui/manual_slice_size_calculation.rs b/tests/ui/manual_slice_size_calculation.rs index ae5225663139b..3c19a0eb5cea1 100644 --- a/tests/ui/manual_slice_size_calculation.rs +++ b/tests/ui/manual_slice_size_calculation.rs @@ -60,7 +60,26 @@ fn main() { let _ = size_of::() * 5 * s_i32.len(); // Ok (MISSED OPPORTUNITY) } -const fn _const(s_i32: &[i32]) { - // True negative: - let _ = s_i32.len() * size_of::(); // Ok, can't use size_of_val in const +#[clippy::msrv = "1.85"] +const fn const_ok(s_i32: &[i32]) { + let _ = s_i32.len() * size_of::(); + //~^ manual_slice_size_calculation +} + +#[clippy::msrv = "1.84"] +const fn const_before_msrv(s_i32: &[i32]) { + let _ = s_i32.len() * size_of::(); +} + +fn issue_14802() { + struct IcedSlice { + dst: [u8], + } + + impl IcedSlice { + fn get_len(&self) -> usize { + self.dst.len() * size_of::() + //~^ manual_slice_size_calculation + } + } } diff --git a/tests/ui/manual_slice_size_calculation.stderr b/tests/ui/manual_slice_size_calculation.stderr index f07e97a1c8638..8e9b49e4bf295 100644 --- a/tests/ui/manual_slice_size_calculation.stderr +++ b/tests/ui/manual_slice_size_calculation.stderr @@ -55,5 +55,17 @@ error: manual slice size calculation LL | let _ = external!(&[1u64][..]).len() * size_of::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(external!(&[1u64][..]))` -error: aborting due to 9 previous errors +error: manual slice size calculation + --> tests/ui/manual_slice_size_calculation.rs:65:13 + | +LL | let _ = s_i32.len() * size_of::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` + +error: manual slice size calculation + --> tests/ui/manual_slice_size_calculation.rs:81:13 + | +LL | self.dst.len() * size_of::() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(&self.dst)` + +error: aborting due to 11 previous errors diff --git a/tests/ui/match_same_arms.fixed b/tests/ui/match_same_arms.fixed new file mode 100644 index 0000000000000..31684a5759fe9 --- /dev/null +++ b/tests/ui/match_same_arms.fixed @@ -0,0 +1,142 @@ +#![allow(clippy::manual_range_patterns)] +#![warn(clippy::match_same_arms)] + +pub enum Abc { + A, + B, + C, +} + +fn match_same_arms() { + let _ = match Abc::A { + Abc::B => 1, + _ => 0, + //~^ match_same_arms + }; + + match 0 { + 1 => 'a', + _ => 'b', + //~^ match_same_arms + }; + + match (1, 2, 3) { + (1, .., 3) | (.., 3) => 42, + //~^ match_same_arms + _ => 0, + }; + + let _ = match 42 { + //~^ match_same_arms + 42 | 51 => 1, + 41 | 52 => 2, + //~^ match_same_arms + _ => 0, + }; + + let _ = match 42 { + //~^ match_same_arms + 1 | 2 | 3 => 2, + 4 => 3, + _ => 0, + }; +} + +mod issue4244 { + #[derive(PartialEq, PartialOrd, Eq, Ord)] + pub enum CommandInfo { + BuiltIn { name: String, about: Option }, + External { name: String, path: std::path::PathBuf }, + } + + impl CommandInfo { + pub fn name(&self) -> String { + match self { + //~^ match_same_arms + CommandInfo::BuiltIn { name, .. } | CommandInfo::External { name, .. } => name.to_string(), + } + } + } +} + +macro_rules! m { + (foo) => {}; + (bar) => {}; +} +macro_rules! foo { + () => { + 1 + }; +} +macro_rules! bar { + () => { + 1 + }; +} + +fn main() { + let x = 0; + let _ = match 0 { + 0 => { + m!(foo); + x + }, + 1 => { + m!(bar); + x + }, + _ => 1, + }; + + let _ = match 0 { + 0 => { + m!(foo); + 0 + }, + 1 => { + m!(bar); + 0 + }, + _ => 1, + }; + + let _ = match 0 { + 0 => { + let mut x = 0; + #[cfg(not_enabled)] + { + x = 5; + } + #[cfg(not(not_enabled))] + { + x = 6; + } + x + }, + 1 => { + let mut x = 0; + #[cfg(also_not_enabled)] + { + x = 5; + } + #[cfg(not(also_not_enabled))] + { + x = 6; + } + x + }, + _ => 0, + }; + + let _ = match 0 { + 0 => foo!(), + 1 => bar!(), + _ => 1, + }; + + let _ = match 0 { + 0 => cfg!(not_enabled), + 1 => cfg!(also_not_enabled), + _ => false, + }; +} diff --git a/tests/ui/match_same_arms.rs b/tests/ui/match_same_arms.rs index 55441948e91b6..39bee01bac22b 100644 --- a/tests/ui/match_same_arms.rs +++ b/tests/ui/match_same_arms.rs @@ -1,4 +1,4 @@ -//@no-rustfix: overlapping suggestions +#![allow(clippy::manual_range_patterns)] #![warn(clippy::match_same_arms)] pub enum Abc { @@ -10,9 +10,17 @@ pub enum Abc { fn match_same_arms() { let _ = match Abc::A { Abc::A => 0, - //~^ match_same_arms Abc::B => 1, _ => 0, + //~^ match_same_arms + }; + + match 0 { + 1 => 'a', + 2 => 'b', + 3 => 'b', + _ => 'b', + //~^ match_same_arms }; match (1, 2, 3) { @@ -24,8 +32,8 @@ fn match_same_arms() { let _ = match 42 { 42 => 1, - 51 => 1, //~^ match_same_arms + 51 => 1, 41 => 2, //~^ match_same_arms 52 => 2, @@ -34,11 +42,9 @@ fn match_same_arms() { let _ = match 42 { 1 => 2, - 2 => 2, //~^ match_same_arms - //~| match_same_arms + 2 => 2, 3 => 2, - //~^ match_same_arms 4 => 3, _ => 0, }; @@ -55,8 +61,8 @@ mod issue4244 { pub fn name(&self) -> String { match self { CommandInfo::BuiltIn { name, .. } => name.to_string(), - CommandInfo::External { name, .. } => name.to_string(), //~^ match_same_arms + CommandInfo::External { name, .. } => name.to_string(), } } } diff --git a/tests/ui/match_same_arms.stderr b/tests/ui/match_same_arms.stderr index 3744b83d89cc8..8aa60f8357663 100644 --- a/tests/ui/match_same_arms.stderr +++ b/tests/ui/match_same_arms.stderr @@ -1,118 +1,121 @@ -error: this match arm has an identical body to the `_` wildcard arm +error: these match arms have identical bodies --> tests/ui/match_same_arms.rs:12:9 | -LL | / Abc::A => 0, -LL | | - | |________^ help: try removing the arm - | - = help: or try changing either arm body -note: `_` wildcard arm here - --> tests/ui/match_same_arms.rs:15:9 - | +LL | Abc::A => 0, + | ^^^^^^^^^^^ +LL | Abc::B => 1, LL | _ => 0, - | ^^^^^^ + | ^^^^^^ the wildcard arm + | + = help: if this is unintentional make the arms return different values = note: `-D clippy::match-same-arms` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]` +help: otherwise remove the non-wildcard arm + | +LL - Abc::A => 0, + | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms.rs:19:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms.rs:20:9 + | +LL | 2 => 'b', + | ^^^^^^^^ +LL | 3 => 'b', + | ^^^^^^^^ +LL | _ => 'b', + | ^^^^^^^^ the wildcard arm + | + = help: if this is unintentional make the arms return different values +help: otherwise remove the non-wildcard arms + | +LL - 2 => 'b', +LL - 3 => 'b', +LL + _ => 'b', + | + +error: these match arms have identical bodies + --> tests/ui/match_same_arms.rs:27:9 | LL | (1, .., 3) => 42, | ^^^^^^^^^^^^^^^^ +LL | +LL | (.., 3) => 42, + | ^^^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | LL ~ (1, .., 3) | (.., 3) => 42, LL | LL ~ _ => 0, | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms.rs:27:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms.rs:34:9 | +LL | 42 => 1, + | ^^^^^^^ +LL | LL | 51 => 1, | ^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | -LL - 42 => 1, -LL - 51 => 1, -LL + 51 | 42 => 1, +LL ~ +LL ~ 42 | 51 => 1, | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms.rs:29:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms.rs:37:9 | LL | 41 => 2, | ^^^^^^^ +LL | +LL | 52 => 2, + | ^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | LL ~ 41 | 52 => 2, LL | LL ~ _ => 0, | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms.rs:37:9 - | -LL | 2 => 2, - | ^^^^^^ - | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm - | -LL - 1 => 2, -LL - 2 => 2, -LL + 2 | 1 => 2, - | - -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms.rs:40:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms.rs:44:9 | -LL | 3 => 2, +LL | 1 => 2, | ^^^^^^ - | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm - | -LL ~ 2 => 2, -LL | LL | -LL ~ 3 | 1 => 2, - | - -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms.rs:37:9 - | LL | 2 => 2, | ^^^^^^ +LL | 3 => 2, + | ^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | -LL ~ 2 | 3 => 2, -LL | -LL | LL ~ +LL ~ 1 | 2 | 3 => 2, | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms.rs:58:17 +error: these match arms have identical bodies + --> tests/ui/match_same_arms.rs:63:17 | +LL | CommandInfo::BuiltIn { name, .. } => name.to_string(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | CommandInfo::External { name, .. } => name.to_string(), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | -LL - CommandInfo::BuiltIn { name, .. } => name.to_string(), -LL - CommandInfo::External { name, .. } => name.to_string(), -LL + CommandInfo::External { name, .. } | CommandInfo::BuiltIn { name, .. } => name.to_string(), +LL ~ +LL ~ CommandInfo::BuiltIn { name, .. } | CommandInfo::External { name, .. } => name.to_string(), | -error: aborting due to 8 previous errors +error: aborting due to 7 previous errors diff --git a/tests/ui/match_same_arms2.fixed b/tests/ui/match_same_arms2.fixed index 0d93e2c728d75..cb860cef1e688 100644 --- a/tests/ui/match_same_arms2.fixed +++ b/tests/ui/match_same_arms2.fixed @@ -14,7 +14,7 @@ fn foo() -> bool { fn match_same_arms() { let _ = match 42 { - //~^^^^^^^^^ match_same_arms + //~v match_same_arms _ => { foo(); let mut a = 42 + [23].len() as i32; @@ -27,14 +27,14 @@ fn match_same_arms() { }; let _ = match 42 { - 51 | 42 => foo(), //~^ match_same_arms + 42 | 51 => foo(), _ => true, }; let _ = match Some(42) { - None | Some(_) => 24, //~^ match_same_arms + Some(_) | None => 24, }; let _ = match Some(42) { @@ -55,8 +55,8 @@ fn match_same_arms() { }; match (Some(42), Some(42)) { - (None, Some(a)) | (Some(a), None) => bar(a), //~^ match_same_arms + (Some(a), None) | (None, Some(a)) => bar(a), _ => (), } @@ -69,8 +69,8 @@ fn match_same_arms() { }; let _ = match (Some(42), Some(42)) { - (None, Some(a)) | (Some(a), None) if a == 42 => a, //~^ match_same_arms + (Some(a), None) | (None, Some(a)) if a == 42 => a, _ => 0, }; @@ -124,8 +124,8 @@ fn match_same_arms() { // False negative #2251. match x { Ok(_tmp) => println!("ok"), - Ok(_) | Ok(3) => println!("ok"), //~^ match_same_arms + Ok(3) | Ok(_) => println!("ok"), Err(_) => { unreachable!(); }, @@ -149,10 +149,10 @@ fn match_same_arms() { // still lint if the tokens are the same match 0 { - 1 | 0 => { + //~^^^ match_same_arms + 0 | 1 => { empty!(0); }, - //~^^^ match_same_arms x => { empty!(x); }, @@ -208,9 +208,9 @@ fn main() { // Suggest moving `Foo::X(0)` down. let _ = match Foo::X(0) { - Foo::Y(_) | Foo::Z(0) => 2, - Foo::Z(_) | Foo::X(0) => 1, //~^ match_same_arms + Foo::Y(_) | Foo::Z(0) => 2, + Foo::X(0) | Foo::Z(_) => 1, _ => 0, }; @@ -230,10 +230,10 @@ fn main() { // Lint. let _ = match None { + //~^ match_same_arms Some(Bar { y: 10, z: 0, .. }) => 2, None => 50, - Some(Bar { y: 0, x: 5, .. }) | Some(Bar { x: 0, y: 5, .. }) => 1, - //~^ match_same_arms + Some(Bar { x: 0, y: 5, .. }) | Some(Bar { y: 0, x: 5, .. }) => 1, _ => 200, }; @@ -246,8 +246,8 @@ fn main() { }; let _ = match 0 { - 1 | 0 => cfg!(not_enable), //~^ match_same_arms + 0 | 1 => cfg!(not_enable), _ => false, }; } @@ -262,9 +262,34 @@ mod with_lifetime { impl<'a> MaybeStaticStr<'a> { fn get(&self) -> &'a str { match *self { - MaybeStaticStr::Borrowed(s) | MaybeStaticStr::Static(s) => s, //~^ match_same_arms + MaybeStaticStr::Static(s) | MaybeStaticStr::Borrowed(s) => s, } } } } + +fn lint_levels() { + match 1 { + 0 => "a", + 1 => "b", + #[expect(clippy::match_same_arms)] + _ => "b", + }; + + match 2 { + 0 => "a", + 1 | 2 => "b", + //~^ match_same_arms + #[allow(clippy::match_same_arms)] + _ => "b", + }; + + match 3 { + 0 => "a", + 1 | 2 => "b", + //~^ match_same_arms + #[expect(clippy::match_same_arms)] + _ => "b", + }; +} diff --git a/tests/ui/match_same_arms2.rs b/tests/ui/match_same_arms2.rs index b0ebc4784f331..0fd5d76e7d3e7 100644 --- a/tests/ui/match_same_arms2.rs +++ b/tests/ui/match_same_arms2.rs @@ -23,7 +23,7 @@ fn match_same_arms() { a = -31 - a; a }, - //~^^^^^^^^^ match_same_arms + //~v match_same_arms _ => { foo(); let mut a = 42 + [23].len() as i32; @@ -37,15 +37,15 @@ fn match_same_arms() { let _ = match 42 { 42 => foo(), - 51 => foo(), //~^ match_same_arms + 51 => foo(), _ => true, }; let _ = match Some(42) { Some(_) => 24, - None => 24, //~^ match_same_arms + None => 24, }; let _ = match Some(42) { @@ -67,8 +67,8 @@ fn match_same_arms() { match (Some(42), Some(42)) { (Some(a), None) => bar(a), - (None, Some(a)) => bar(a), //~^ match_same_arms + (None, Some(a)) => bar(a), _ => (), } @@ -82,8 +82,8 @@ fn match_same_arms() { let _ = match (Some(42), Some(42)) { (Some(a), None) if a == 42 => a, - (None, Some(a)) if a == 42 => a, //~^ match_same_arms + (None, Some(a)) if a == 42 => a, _ => 0, }; @@ -140,8 +140,8 @@ fn match_same_arms() { match x { Ok(_tmp) => println!("ok"), Ok(3) => println!("ok"), - Ok(_) => println!("ok"), //~^ match_same_arms + Ok(_) => println!("ok"), Err(_) => { unreachable!(); }, @@ -168,10 +168,10 @@ fn match_same_arms() { 0 => { empty!(0); }, + //~^^^ match_same_arms 1 => { empty!(0); }, - //~^^^ match_same_arms x => { empty!(x); }, @@ -229,9 +229,9 @@ fn main() { // Suggest moving `Foo::X(0)` down. let _ = match Foo::X(0) { Foo::X(0) => 1, + //~^ match_same_arms Foo::Y(_) | Foo::Z(0) => 2, Foo::Z(_) => 1, - //~^ match_same_arms _ => 0, }; @@ -252,10 +252,10 @@ fn main() { // Lint. let _ = match None { Some(Bar { x: 0, y: 5, .. }) => 1, + //~^ match_same_arms Some(Bar { y: 10, z: 0, .. }) => 2, None => 50, Some(Bar { y: 0, x: 5, .. }) => 1, - //~^ match_same_arms _ => 200, }; @@ -269,8 +269,8 @@ fn main() { let _ = match 0 { 0 => cfg!(not_enable), - 1 => cfg!(not_enable), //~^ match_same_arms + 1 => cfg!(not_enable), _ => false, }; } @@ -286,9 +286,36 @@ mod with_lifetime { fn get(&self) -> &'a str { match *self { MaybeStaticStr::Static(s) => s, - MaybeStaticStr::Borrowed(s) => s, //~^ match_same_arms + MaybeStaticStr::Borrowed(s) => s, } } } } + +fn lint_levels() { + match 1 { + 0 => "a", + 1 => "b", + #[expect(clippy::match_same_arms)] + _ => "b", + }; + + match 2 { + 0 => "a", + 1 => "b", + //~^ match_same_arms + 2 => "b", + #[allow(clippy::match_same_arms)] + _ => "b", + }; + + match 3 { + 0 => "a", + 1 => "b", + //~^ match_same_arms + 2 => "b", + #[expect(clippy::match_same_arms)] + _ => "b", + }; +} diff --git a/tests/ui/match_same_arms2.stderr b/tests/ui/match_same_arms2.stderr index 21a8743cc3242..f3031619cce56 100644 --- a/tests/ui/match_same_arms2.stderr +++ b/tests/ui/match_same_arms2.stderr @@ -1,4 +1,4 @@ -error: this match arm has an identical body to the `_` wildcard arm +error: these match arms have identical bodies --> tests/ui/match_same_arms2.rs:17:9 | LL | / 42 => { @@ -6,14 +6,10 @@ LL | | foo(); LL | | let mut a = 42 + [23].len() as i32; LL | | if true { ... | +LL | | a LL | | }, -LL | | - | |________^ help: try removing the arm - | - = help: or try changing either arm body -note: `_` wildcard arm here - --> tests/ui/match_same_arms2.rs:27:9 - | + | |_________^ +LL | LL | / _ => { LL | | foo(); LL | | let mut a = 42 + [23].len() as i32; @@ -21,134 +17,169 @@ LL | | if true { ... | LL | | a LL | | }, - | |_________^ + | |_________^ the wildcard arm + | + = help: if this is unintentional make the arms return different values = note: `-D clippy::match-same-arms` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]` +help: otherwise remove the non-wildcard arm + | +LL - 42 => { +LL - foo(); +LL - let mut a = 42 + [23].len() as i32; +LL - if true { +LL - a += 7; +LL - } +LL - a = -31 - a; +LL - a +LL - }, + | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:40:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms2.rs:39:9 | +LL | 42 => foo(), + | ^^^^^^^^^^^ +LL | LL | 51 => foo(), | ^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | -LL - 42 => foo(), -LL - 51 => foo(), -LL + 51 | 42 => foo(), +LL ~ +LL ~ 42 | 51 => foo(), | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:47:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms2.rs:46:9 | +LL | Some(_) => 24, + | ^^^^^^^^^^^^^ +LL | LL | None => 24, | ^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | -LL - Some(_) => 24, -LL - None => 24, -LL + None | Some(_) => 24, +LL ~ +LL ~ Some(_) | None => 24, | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:70:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms2.rs:69:9 | +LL | (Some(a), None) => bar(a), + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | (None, Some(a)) => bar(a), | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | -LL - (Some(a), None) => bar(a), -LL - (None, Some(a)) => bar(a), -LL + (None, Some(a)) | (Some(a), None) => bar(a), +LL ~ +LL ~ (Some(a), None) | (None, Some(a)) => bar(a), | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:85:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms2.rs:84:9 | +LL | (Some(a), None) if a == 42 => a, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | (None, Some(a)) if a == 42 => a, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | -LL - (Some(a), None) if a == 42 => a, -LL - (None, Some(a)) if a == 42 => a, -LL + (None, Some(a)) | (Some(a), None) if a == 42 => a, +LL ~ +LL ~ (Some(a), None) | (None, Some(a)) if a == 42 => a, | -error: this match arm has an identical body to another arm +error: these match arms have identical bodies --> tests/ui/match_same_arms2.rs:91:9 | LL | (Some(a), ..) => bar(a), | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | (.., Some(a)) => bar(a), + | ^^^^^^^^^^^^^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | LL ~ (Some(a), ..) | (.., Some(a)) => bar(a), LL | LL ~ _ => (), | -error: this match arm has an identical body to another arm +error: these match arms have identical bodies --> tests/ui/match_same_arms2.rs:126:9 | LL | (Ok(x), Some(_)) => println!("ok {}", x), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | (Ok(_), Some(x)) => println!("ok {}", x), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | LL ~ (Ok(x), Some(_)) | (Ok(_), Some(x)) => println!("ok {}", x), LL | LL ~ _ => println!("err"), | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:143:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms2.rs:142:9 | +LL | Ok(3) => println!("ok"), + | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | Ok(_) => println!("ok"), | ^^^^^^^^^^^^^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | -LL - Ok(3) => println!("ok"), -LL - Ok(_) => println!("ok"), -LL + Ok(_) | Ok(3) => println!("ok"), +LL ~ +LL ~ Ok(3) | Ok(_) => println!("ok"), | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:171:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms2.rs:168:9 | +LL | / 0 => { +LL | | empty!(0); +LL | | }, + | |_________^ +LL | LL | / 1 => { LL | | empty!(0); LL | | }, | |_________^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | -LL - 0 => { -LL - empty!(0); -LL - }, -LL - 1 => { -LL + 1 | 0 => { +LL ~ +LL ~ 0 | 1 => { | -error: this match arm has an identical body to another arm +error: these match arms have identical bodies --> tests/ui/match_same_arms2.rs:222:9 | LL | Foo::X(0) => 1, | ^^^^^^^^^^^^^^ +... +LL | Foo::Z(_) => 1, + | ^^^^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | LL ~ Foo::X(0) | Foo::Z(_) => 1, LL | @@ -156,60 +187,106 @@ LL | Foo::X(_) | Foo::Y(_) => 2, LL ~ _ => 0, | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:233:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms2.rs:231:9 | +LL | Foo::X(0) => 1, + | ^^^^^^^^^^^^^^ +... LL | Foo::Z(_) => 1, | ^^^^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | -LL ~ Foo::Y(_) | Foo::Z(0) => 2, -LL ~ Foo::Z(_) | Foo::X(0) => 1, +LL ~ +LL | Foo::Y(_) | Foo::Z(0) => 2, +LL ~ Foo::X(0) | Foo::Z(_) => 1, | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:257:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms2.rs:254:9 | +LL | Some(Bar { x: 0, y: 5, .. }) => 1, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... LL | Some(Bar { y: 0, x: 5, .. }) => 1, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | -LL ~ Some(Bar { y: 10, z: 0, .. }) => 2, +LL ~ +LL | Some(Bar { y: 10, z: 0, .. }) => 2, LL | None => 50, -LL ~ Some(Bar { y: 0, x: 5, .. }) | Some(Bar { x: 0, y: 5, .. }) => 1, +LL ~ Some(Bar { x: 0, y: 5, .. }) | Some(Bar { y: 0, x: 5, .. }) => 1, | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:272:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms2.rs:271:9 | +LL | 0 => cfg!(not_enable), + | ^^^^^^^^^^^^^^^^^^^^^ +LL | LL | 1 => cfg!(not_enable), | ^^^^^^^^^^^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | -LL - 0 => cfg!(not_enable), -LL - 1 => cfg!(not_enable), -LL + 1 | 0 => cfg!(not_enable), +LL ~ +LL ~ 0 | 1 => cfg!(not_enable), | -error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:289:17 +error: these match arms have identical bodies + --> tests/ui/match_same_arms2.rs:288:17 | +LL | MaybeStaticStr::Static(s) => s, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | MaybeStaticStr::Borrowed(s) => s, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: try changing either arm body -help: or try merging the arm patterns and removing the obsolete arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm + | +LL ~ +LL ~ MaybeStaticStr::Static(s) | MaybeStaticStr::Borrowed(s) => s, | -LL - MaybeStaticStr::Static(s) => s, -LL - MaybeStaticStr::Borrowed(s) => s, -LL + MaybeStaticStr::Borrowed(s) | MaybeStaticStr::Static(s) => s, + +error: these match arms have identical bodies + --> tests/ui/match_same_arms2.rs:306:9 + | +LL | 1 => "b", + | ^^^^^^^^ +LL | +LL | 2 => "b", + | ^^^^^^^^ + | + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm + | +LL ~ 1 | 2 => "b", +LL | +LL ~ #[allow(clippy::match_same_arms)] + | + +error: these match arms have identical bodies + --> tests/ui/match_same_arms2.rs:315:9 + | +LL | 1 => "b", + | ^^^^^^^^ +LL | +LL | 2 => "b", + | ^^^^^^^^ + | + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm + | +LL ~ 1 | 2 => "b", +LL | +LL ~ #[expect(clippy::match_same_arms)] | -error: aborting due to 14 previous errors +error: aborting due to 16 previous errors diff --git a/tests/ui/match_same_arms_non_exhaustive.fixed b/tests/ui/match_same_arms_non_exhaustive.fixed index 0c9398933b80e..61a5bd0323a88 100644 --- a/tests/ui/match_same_arms_non_exhaustive.fixed +++ b/tests/ui/match_same_arms_non_exhaustive.fixed @@ -7,14 +7,22 @@ fn repeat() -> ! { panic!() } +#[deny(non_exhaustive_omitted_patterns)] pub fn f(x: Ordering) { - #[deny(non_exhaustive_omitted_patterns)] match x { Ordering::Relaxed => println!("relaxed"), Ordering::Release => println!("release"), Ordering::Acquire => println!("acquire"), - Ordering::AcqRel | Ordering::SeqCst => repeat(), - _ => repeat(), + //~^ match_same_arms + Ordering::AcqRel | Ordering::SeqCst | _ => repeat(), + } + + match x { + Ordering::Relaxed => println!("relaxed"), + Ordering::Release => println!("release"), + Ordering::Acquire => println!("acquire"), + //~^ match_same_arms + Ordering::AcqRel | Ordering::SeqCst | _ => repeat(), } } @@ -28,21 +36,21 @@ mod f { Ordering::Relaxed => println!("relaxed"), Ordering::Release => println!("release"), Ordering::Acquire => println!("acquire"), - Ordering::AcqRel | Ordering::SeqCst => repeat(), - _ => repeat(), + //~^ match_same_arms + Ordering::AcqRel | Ordering::SeqCst | _ => repeat(), } } } -// Below should still lint +// Below can still suggest removing the other patterns pub fn g(x: Ordering) { match x { Ordering::Relaxed => println!("relaxed"), Ordering::Release => println!("release"), Ordering::Acquire => println!("acquire"), - //~^ match_same_arms _ => repeat(), + //~^ match_same_arms } } @@ -54,8 +62,8 @@ mod g { Ordering::Relaxed => println!("relaxed"), Ordering::Release => println!("release"), Ordering::Acquire => println!("acquire"), - //~^ match_same_arms _ => repeat(), + //~^ match_same_arms } } } diff --git a/tests/ui/match_same_arms_non_exhaustive.rs b/tests/ui/match_same_arms_non_exhaustive.rs index 304a9e5c28e76..66f65eb39d0a9 100644 --- a/tests/ui/match_same_arms_non_exhaustive.rs +++ b/tests/ui/match_same_arms_non_exhaustive.rs @@ -7,15 +7,25 @@ fn repeat() -> ! { panic!() } +#[deny(non_exhaustive_omitted_patterns)] pub fn f(x: Ordering) { - #[deny(non_exhaustive_omitted_patterns)] match x { Ordering::Relaxed => println!("relaxed"), Ordering::Release => println!("release"), Ordering::Acquire => println!("acquire"), Ordering::AcqRel | Ordering::SeqCst => repeat(), + //~^ match_same_arms _ => repeat(), } + + match x { + Ordering::Relaxed => println!("relaxed"), + Ordering::Release => println!("release"), + Ordering::Acquire => println!("acquire"), + Ordering::AcqRel => repeat(), + //~^ match_same_arms + Ordering::SeqCst | _ => repeat(), + } } mod f { @@ -29,12 +39,13 @@ mod f { Ordering::Release => println!("release"), Ordering::Acquire => println!("acquire"), Ordering::AcqRel | Ordering::SeqCst => repeat(), + //~^ match_same_arms _ => repeat(), } } } -// Below should still lint +// Below can still suggest removing the other patterns pub fn g(x: Ordering) { match x { @@ -42,8 +53,8 @@ pub fn g(x: Ordering) { Ordering::Release => println!("release"), Ordering::Acquire => println!("acquire"), Ordering::AcqRel | Ordering::SeqCst => repeat(), - //~^ match_same_arms _ => repeat(), + //~^ match_same_arms } } @@ -56,8 +67,8 @@ mod g { Ordering::Release => println!("release"), Ordering::Acquire => println!("acquire"), Ordering::AcqRel | Ordering::SeqCst => repeat(), - //~^ match_same_arms _ => repeat(), + //~^ match_same_arms } } } diff --git a/tests/ui/match_same_arms_non_exhaustive.stderr b/tests/ui/match_same_arms_non_exhaustive.stderr index aa7f8c95dce84..03252f346c6cc 100644 --- a/tests/ui/match_same_arms_non_exhaustive.stderr +++ b/tests/ui/match_same_arms_non_exhaustive.stderr @@ -1,32 +1,80 @@ -error: this match arm has an identical body to the `_` wildcard arm - --> tests/ui/match_same_arms_non_exhaustive.rs:44:9 - | -LL | / Ordering::AcqRel | Ordering::SeqCst => repeat(), -LL | | - | |________^ help: try removing the arm - | - = help: or try changing either arm body -note: `_` wildcard arm here - --> tests/ui/match_same_arms_non_exhaustive.rs:46:9 +error: these match arms have identical bodies + --> tests/ui/match_same_arms_non_exhaustive.rs:16:9 | +LL | Ordering::AcqRel | Ordering::SeqCst => repeat(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | _ => repeat(), | ^^^^^^^^^^^^^ + | + = help: if this is unintentional make the arms return different values = note: `-D clippy::match-same-arms` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]` +help: otherwise merge the patterns into a single arm + | +LL ~ +LL ~ Ordering::AcqRel | Ordering::SeqCst | _ => repeat(), + | -error: this match arm has an identical body to the `_` wildcard arm - --> tests/ui/match_same_arms_non_exhaustive.rs:58:13 +error: these match arms have identical bodies + --> tests/ui/match_same_arms_non_exhaustive.rs:25:9 + | +LL | Ordering::AcqRel => repeat(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | Ordering::SeqCst | _ => repeat(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -LL | / Ordering::AcqRel | Ordering::SeqCst => repeat(), -LL | | - | |____________^ help: try removing the arm + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm | - = help: or try changing either arm body -note: `_` wildcard arm here - --> tests/ui/match_same_arms_non_exhaustive.rs:60:13 +LL ~ +LL ~ Ordering::AcqRel | Ordering::SeqCst | _ => repeat(), | + +error: these match arms have identical bodies + --> tests/ui/match_same_arms_non_exhaustive.rs:41:13 + | +LL | Ordering::AcqRel | Ordering::SeqCst => repeat(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | _ => repeat(), | ^^^^^^^^^^^^^ + | + = help: if this is unintentional make the arms return different values +help: otherwise merge the patterns into a single arm + | +LL ~ +LL ~ Ordering::AcqRel | Ordering::SeqCst | _ => repeat(), + | + +error: these match arms have identical bodies + --> tests/ui/match_same_arms_non_exhaustive.rs:55:9 + | +LL | Ordering::AcqRel | Ordering::SeqCst => repeat(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | _ => repeat(), + | ^^^^^^^^^^^^^ the wildcard arm + | + = help: if this is unintentional make the arms return different values +help: otherwise remove the non-wildcard arm + | +LL - Ordering::AcqRel | Ordering::SeqCst => repeat(), + | + +error: these match arms have identical bodies + --> tests/ui/match_same_arms_non_exhaustive.rs:69:13 + | +LL | Ordering::AcqRel | Ordering::SeqCst => repeat(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | _ => repeat(), + | ^^^^^^^^^^^^^ the wildcard arm + | + = help: if this is unintentional make the arms return different values +help: otherwise remove the non-wildcard arm + | +LL - Ordering::AcqRel | Ordering::SeqCst => repeat(), + | -error: aborting due to 2 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/misrefactored_assign_op.1.fixed b/tests/ui/misrefactored_assign_op.1.fixed new file mode 100644 index 0000000000000..882ff6bf8944a --- /dev/null +++ b/tests/ui/misrefactored_assign_op.1.fixed @@ -0,0 +1,40 @@ +#![allow(clippy::eq_op)] +#![warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)] + +fn main() { + let mut a = 5; + a += 1; + //~^ misrefactored_assign_op + + a += 1; + //~^ misrefactored_assign_op + + a -= 1; + //~^ misrefactored_assign_op + + a *= 99; + //~^ misrefactored_assign_op + + a *= 42; + //~^ misrefactored_assign_op + + a /= 2; + //~^ misrefactored_assign_op + + a %= 5; + //~^ misrefactored_assign_op + + a &= 1; + //~^ misrefactored_assign_op + + a *= a; + //~^ misrefactored_assign_op + + a = a * a * a; + a = a * 42 * a; + a = a * 2 + a; + a -= 1 - a; + a /= 5 / a; + a %= 42 % a; + a <<= 6 << a; +} diff --git a/tests/ui/misrefactored_assign_op.2.fixed b/tests/ui/misrefactored_assign_op.2.fixed new file mode 100644 index 0000000000000..de3a0f1710d24 --- /dev/null +++ b/tests/ui/misrefactored_assign_op.2.fixed @@ -0,0 +1,40 @@ +#![allow(clippy::eq_op)] +#![warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)] + +fn main() { + let mut a = 5; + a = a + a + 1; + //~^ misrefactored_assign_op + + a = a + 1 + a; + //~^ misrefactored_assign_op + + a = a - (a - 1); + //~^ misrefactored_assign_op + + a = a * a * 99; + //~^ misrefactored_assign_op + + a = a * 42 * a; + //~^ misrefactored_assign_op + + a = a / (a / 2); + //~^ misrefactored_assign_op + + a = a % (a % 5); + //~^ misrefactored_assign_op + + a = a & a & 1; + //~^ misrefactored_assign_op + + a = a * a * a; + //~^ misrefactored_assign_op + + a = a * a * a; + a = a * 42 * a; + a = a * 2 + a; + a -= 1 - a; + a /= 5 / a; + a %= 42 % a; + a <<= 6 << a; +} diff --git a/tests/ui/misrefactored_assign_op.rs b/tests/ui/misrefactored_assign_op.rs new file mode 100644 index 0000000000000..62d83d1619c1e --- /dev/null +++ b/tests/ui/misrefactored_assign_op.rs @@ -0,0 +1,40 @@ +#![allow(clippy::eq_op)] +#![warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)] + +fn main() { + let mut a = 5; + a += a + 1; + //~^ misrefactored_assign_op + + a += 1 + a; + //~^ misrefactored_assign_op + + a -= a - 1; + //~^ misrefactored_assign_op + + a *= a * 99; + //~^ misrefactored_assign_op + + a *= 42 * a; + //~^ misrefactored_assign_op + + a /= a / 2; + //~^ misrefactored_assign_op + + a %= a % 5; + //~^ misrefactored_assign_op + + a &= a & 1; + //~^ misrefactored_assign_op + + a *= a * a; + //~^ misrefactored_assign_op + + a = a * a * a; + a = a * 42 * a; + a = a * 2 + a; + a -= 1 - a; + a /= 5 / a; + a %= 42 % a; + a <<= 6 << a; +} diff --git a/tests/ui/assign_ops2.stderr b/tests/ui/misrefactored_assign_op.stderr similarity index 80% rename from tests/ui/assign_ops2.stderr rename to tests/ui/misrefactored_assign_op.stderr index d9ecd3f8b230c..63f3a3e28f12c 100644 --- a/tests/ui/assign_ops2.stderr +++ b/tests/ui/misrefactored_assign_op.stderr @@ -1,5 +1,5 @@ error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:8:5 + --> tests/ui/misrefactored_assign_op.rs:6:5 | LL | a += a + 1; | ^^^^^^^^^^ @@ -18,7 +18,7 @@ LL + a = a + a + 1; | error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:11:5 + --> tests/ui/misrefactored_assign_op.rs:9:5 | LL | a += 1 + a; | ^^^^^^^^^^ @@ -35,7 +35,7 @@ LL + a = a + 1 + a; | error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:14:5 + --> tests/ui/misrefactored_assign_op.rs:12:5 | LL | a -= a - 1; | ^^^^^^^^^^ @@ -52,7 +52,7 @@ LL + a = a - (a - 1); | error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:17:5 + --> tests/ui/misrefactored_assign_op.rs:15:5 | LL | a *= a * 99; | ^^^^^^^^^^^ @@ -69,7 +69,7 @@ LL + a = a * a * 99; | error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:20:5 + --> tests/ui/misrefactored_assign_op.rs:18:5 | LL | a *= 42 * a; | ^^^^^^^^^^^ @@ -86,7 +86,7 @@ LL + a = a * 42 * a; | error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:23:5 + --> tests/ui/misrefactored_assign_op.rs:21:5 | LL | a /= a / 2; | ^^^^^^^^^^ @@ -103,7 +103,7 @@ LL + a = a / (a / 2); | error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:26:5 + --> tests/ui/misrefactored_assign_op.rs:24:5 | LL | a %= a % 5; | ^^^^^^^^^^ @@ -120,7 +120,7 @@ LL + a = a % (a % 5); | error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:29:5 + --> tests/ui/misrefactored_assign_op.rs:27:5 | LL | a &= a & 1; | ^^^^^^^^^^ @@ -137,7 +137,7 @@ LL + a = a & a & 1; | error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:32:5 + --> tests/ui/misrefactored_assign_op.rs:30:5 | LL | a *= a * a; | ^^^^^^^^^^ @@ -153,14 +153,5 @@ LL - a *= a * a; LL + a = a * a * a; | -error: manual implementation of an assign operation - --> tests/ui/assign_ops2.rs:71:5 - | -LL | buf = buf + cows.clone(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `buf += cows.clone()` - | - = note: `-D clippy::assign-op-pattern` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::assign_op_pattern)]` - -error: aborting due to 10 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/needless_match.fixed b/tests/ui/needless_match.fixed index b2c2bbfaa3613..41acf44023f63 100644 --- a/tests/ui/needless_match.fixed +++ b/tests/ui/needless_match.fixed @@ -301,4 +301,16 @@ pub fn issue13574() -> Option<()> { None } +fn issue14754(t: Result) -> Result { + let _ = match t { + Ok(v) => Ok::<_, &'static str>(v), + err @ Err(_) => return err, + }; + println!("Still here"); + let x = t; + //~^^^^ needless_match + println!("Still here"); + x +} + fn main() {} diff --git a/tests/ui/needless_match.rs b/tests/ui/needless_match.rs index 1cb670edc60fb..936653b961bbb 100644 --- a/tests/ui/needless_match.rs +++ b/tests/ui/needless_match.rs @@ -364,4 +364,19 @@ pub fn issue13574() -> Option<()> { None } +fn issue14754(t: Result) -> Result { + let _ = match t { + Ok(v) => Ok::<_, &'static str>(v), + err @ Err(_) => return err, + }; + println!("Still here"); + let x = match t { + Ok(v) => Ok::<_, &'static str>(v), + err @ Err(_) => err, + }; + //~^^^^ needless_match + println!("Still here"); + x +} + fn main() {} diff --git a/tests/ui/needless_match.stderr b/tests/ui/needless_match.stderr index 719b0ef884696..5195ecdfa555e 100644 --- a/tests/ui/needless_match.stderr +++ b/tests/ui/needless_match.stderr @@ -151,5 +151,15 @@ LL | | None LL | | } | |_________^ help: replace it with: `A` -error: aborting due to 14 previous errors +error: this match expression is unnecessary + --> tests/ui/needless_match.rs:373:13 + | +LL | let x = match t { + | _____________^ +LL | | Ok(v) => Ok::<_, &'static str>(v), +LL | | err @ Err(_) => err, +LL | | }; + | |_____^ help: replace it with: `t` + +error: aborting due to 15 previous errors diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index ad625ad6d5076..17d3862cd8668 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -84,14 +84,14 @@ fn test_macro_call() -> i32 { } fn test_void_fun() { - //~^^ needless_return + //~^ needless_return } fn test_void_if_fun(b: bool) { if b { - //~^^ needless_return + //~^ needless_return } else { - //~^^ needless_return + //~^ needless_return } } @@ -108,7 +108,7 @@ fn test_nested_match(x: u32) { 0 => (), 1 => { let _ = 42; - //~^^ needless_return + //~^ needless_return }, _ => (), //~^ needless_return @@ -156,7 +156,7 @@ mod issue6501 { fn test_closure() { let _ = || { - //~^^ needless_return + //~^ needless_return }; let _ = || {}; //~^ needless_return @@ -220,14 +220,14 @@ async fn async_test_macro_call() -> i32 { } async fn async_test_void_fun() { - //~^^ needless_return + //~^ needless_return } async fn async_test_void_if_fun(b: bool) { if b { - //~^^ needless_return + //~^ needless_return } else { - //~^^ needless_return + //~^ needless_return } } @@ -354,7 +354,7 @@ fn issue9503(x: usize) -> isize { mod issue9416 { pub fn with_newline() { let _ = 42; - //~^^ needless_return + //~^ needless_return } #[rustfmt::skip] diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index 41d7e5bdd5065..1c6e7ffa1ee8c 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -85,16 +85,16 @@ fn test_macro_call() -> i32 { fn test_void_fun() { return; - //~^^ needless_return + //~^ needless_return } fn test_void_if_fun(b: bool) { if b { return; - //~^^ needless_return + //~^ needless_return } else { return; - //~^^ needless_return + //~^ needless_return } } @@ -112,7 +112,7 @@ fn test_nested_match(x: u32) { 1 => { let _ = 42; return; - //~^^ needless_return + //~^ needless_return }, _ => return, //~^ needless_return @@ -161,7 +161,7 @@ mod issue6501 { fn test_closure() { let _ = || { return; - //~^^ needless_return + //~^ needless_return }; let _ = || return; //~^ needless_return @@ -226,16 +226,16 @@ async fn async_test_macro_call() -> i32 { async fn async_test_void_fun() { return; - //~^^ needless_return + //~^ needless_return } async fn async_test_void_if_fun(b: bool) { if b { return; - //~^^ needless_return + //~^ needless_return } else { return; - //~^^ needless_return + //~^ needless_return } } @@ -363,7 +363,7 @@ mod issue9416 { pub fn with_newline() { let _ = 42; return; - //~^^ needless_return + //~^ needless_return } #[rustfmt::skip] diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index 80863b9b62b20..26dd265379be0 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -133,12 +133,10 @@ LL + the_answer!() | error: unneeded `return` statement - --> tests/ui/needless_return.rs:86:21 + --> tests/ui/needless_return.rs:87:5 | -LL | fn test_void_fun() { - | _____________________^ -LL | | return; - | |__________^ +LL | return; + | ^^^^^^ | help: remove `return` | @@ -148,12 +146,10 @@ LL + fn test_void_fun() { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:92:11 + --> tests/ui/needless_return.rs:93:9 | -LL | if b { - | ___________^ -LL | | return; - | |______________^ +LL | return; + | ^^^^^^ | help: remove `return` | @@ -163,12 +159,10 @@ LL + if b { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:95:13 + --> tests/ui/needless_return.rs:96:9 | -LL | } else { - | _____________^ -LL | | return; - | |______________^ +LL | return; + | ^^^^^^ | help: remove `return` | @@ -190,12 +184,10 @@ LL + _ => (), | error: unneeded `return` statement - --> tests/ui/needless_return.rs:113:24 + --> tests/ui/needless_return.rs:114:13 | -LL | let _ = 42; - | ________________________^ -LL | | return; - | |__________________^ +LL | return; + | ^^^^^^ | help: remove `return` | @@ -253,12 +245,10 @@ LL + bar.unwrap_or_else(|_| {}) | error: unneeded `return` statement - --> tests/ui/needless_return.rs:162:21 + --> tests/ui/needless_return.rs:163:13 | -LL | let _ = || { - | _____________________^ -LL | | return; - | |__________________^ +LL | return; + | ^^^^^^ | help: remove `return` | @@ -400,12 +390,10 @@ LL + the_answer!() | error: unneeded `return` statement - --> tests/ui/needless_return.rs:227:33 + --> tests/ui/needless_return.rs:228:5 | -LL | async fn async_test_void_fun() { - | _________________________________^ -LL | | return; - | |__________^ +LL | return; + | ^^^^^^ | help: remove `return` | @@ -415,12 +403,10 @@ LL + async fn async_test_void_fun() { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:233:11 + --> tests/ui/needless_return.rs:234:9 | -LL | if b { - | ___________^ -LL | | return; - | |______________^ +LL | return; + | ^^^^^^ | help: remove `return` | @@ -430,12 +416,10 @@ LL + if b { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:236:13 + --> tests/ui/needless_return.rs:237:9 | -LL | } else { - | _____________^ -LL | | return; - | |______________^ +LL | return; + | ^^^^^^ | help: remove `return` | @@ -593,12 +577,10 @@ LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:364:20 + --> tests/ui/needless_return.rs:365:9 | -LL | let _ = 42; - | ____________________^ -LL | | return; - | |______________^ +LL | return; + | ^^^^^^ | help: remove `return` | @@ -608,10 +590,10 @@ LL + let _ = 42; | error: unneeded `return` statement - --> tests/ui/needless_return.rs:371:20 + --> tests/ui/needless_return.rs:371:21 | LL | let _ = 42; return; - | ^^^^^^^ + | ^^^^^^ | help: remove `return` | diff --git a/tests/ui/no_effect.rs b/tests/ui/no_effect.rs index 703c2a3d98479..4ab5bc9acdeeb 100644 --- a/tests/ui/no_effect.rs +++ b/tests/ui/no_effect.rs @@ -221,3 +221,56 @@ fn main() { Cout << 142; -Cout; } + +fn issue14592() { + struct MyStruct { + _inner: MyInner, + } + struct MyInner {} + + impl Drop for MyInner { + fn drop(&mut self) { + println!("dropping"); + } + } + + let x = MyStruct { _inner: MyInner {} }; + + let closure = || { + // Do not lint: dropping the assignment or assigning to `_` would + // change the output. + let _x = x; + }; + + println!("1"); + closure(); + println!("2"); + + struct Innocuous { + a: i32, + } + + // Do not lint: one of the fields has a side effect. + let x = MyInner {}; + let closure = || { + let _x = Innocuous { + a: { + x; + 10 + }, + }; + }; + + // Do not lint: the base has a side effect. + let x = MyInner {}; + let closure = || { + let _x = Innocuous { + ..Innocuous { + a: { + x; + 10 + }, + } + }; + }; +} diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index 55e287b91596d..ff81c64260274 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -7,85 +7,107 @@ #![allow(clippy::disallowed_names)] #![allow(clippy::blocks_in_conditions)] #![allow(clippy::box_collection)] +#![allow(invalid_reference_casting)] +#![allow(suspicious_double_ref_op)] +#![allow(invalid_nan_comparisons)] #![allow(clippy::redundant_static_lifetimes)] #![allow(clippy::cognitive_complexity)] #![allow(clippy::derived_hash_with_manual_eq)] #![allow(clippy::disallowed_methods)] #![allow(clippy::disallowed_types)] +#![allow(double_negations)] +#![allow(drop_bounds)] +#![allow(dropping_copy_types)] +#![allow(dropping_references)] #![allow(clippy::mixed_read_write_in_expression)] -#![allow(clippy::manual_find_map)] #![allow(clippy::manual_filter_map)] +#![allow(clippy::manual_find_map)] #![allow(unpredictable_function_pointer_comparisons)] +#![allow(useless_ptr_null_checks)] +#![allow(for_loops_over_fallibles)] +#![allow(forgetting_copy_types)] +#![allow(forgetting_references)] #![allow(clippy::useless_conversion)] #![allow(clippy::redundant_pattern_matching)] #![allow(clippy::match_result_ok)] #![allow(clippy::non_canonical_clone_impl)] #![allow(clippy::non_canonical_partial_ord_impl)] #![allow(clippy::arithmetic_side_effects)] +#![allow(array_into_iter)] +#![allow(invalid_atomic_ordering)] +#![allow(invalid_null_arguments)] +#![allow(invalid_value)] +#![allow(invalid_from_utf8_unchecked)] +#![allow(let_underscore_drop)] #![allow(clippy::overly_complex_bool_expr)] +#![allow(unexpected_cfgs)] +#![allow(enum_intrinsics_non_enums)] #![allow(clippy::new_without_default)] #![allow(clippy::bind_instead_of_map)] #![allow(clippy::expect_used)] #![allow(clippy::map_unwrap_or)] #![allow(clippy::unwrap_used)] #![allow(clippy::panicking_overflow_checks)] +#![allow(non_fmt_panics)] +#![allow(named_arguments_used_positionally)] #![allow(clippy::needless_borrow)] +#![allow(clippy::reversed_empty_ranges)] #![allow(clippy::single_char_add_str)] #![allow(clippy::module_name_repetitions)] +#![allow(dangling_pointers_from_temporaries)] #![allow(clippy::missing_const_for_thread_local)] #![allow(clippy::recursive_format_impl)] -#![allow(clippy::unwrap_or_default)] -#![allow(clippy::invisible_characters)] -#![allow(invalid_reference_casting)] -#![allow(suspicious_double_ref_op)] -#![allow(invalid_nan_comparisons)] -#![allow(invalid_null_arguments)] -#![allow(double_negations)] -#![allow(drop_bounds)] -#![allow(dropping_copy_types)] -#![allow(dropping_references)] -#![allow(useless_ptr_null_checks)] -#![allow(for_loops_over_fallibles)] -#![allow(forgetting_copy_types)] -#![allow(forgetting_references)] -#![allow(array_into_iter)] -#![allow(invalid_atomic_ordering)] -#![allow(invalid_value)] -#![allow(invalid_from_utf8_unchecked)] -#![allow(let_underscore_drop)] -#![allow(unexpected_cfgs)] -#![allow(enum_intrinsics_non_enums)] -#![allow(non_fmt_panics)] -#![allow(named_arguments_used_positionally)] -#![allow(dangling_pointers_from_temporaries)] +#![allow(unnecessary_transmutes)] #![allow(undropped_manually_drops)] #![allow(unknown_lints)] #![allow(unused_labels)] +#![allow(clippy::unwrap_or_default)] #![allow(ambiguous_wide_pointer_comparisons)] -#![allow(clippy::reversed_empty_ranges)] -#![allow(unnecessary_transmutes)] +#![allow(clippy::invisible_characters)] #![warn(clippy::almost_complete_range)] //~ ERROR: lint `clippy::almost_complete_letter_range` #![warn(clippy::disallowed_names)] //~ ERROR: lint `clippy::blacklisted_name` #![warn(clippy::blocks_in_conditions)] //~ ERROR: lint `clippy::block_in_if_condition_expr` #![warn(clippy::blocks_in_conditions)] //~ ERROR: lint `clippy::block_in_if_condition_stmt` #![warn(clippy::blocks_in_conditions)] //~ ERROR: lint `clippy::blocks_in_if_conditions` #![warn(clippy::box_collection)] //~ ERROR: lint `clippy::box_vec` +#![warn(invalid_reference_casting)] //~ ERROR: lint `clippy::cast_ref_to_mut` +#![warn(suspicious_double_ref_op)] //~ ERROR: lint `clippy::clone_double_ref` +#![warn(invalid_nan_comparisons)] //~ ERROR: lint `clippy::cmp_nan` #![warn(clippy::redundant_static_lifetimes)] //~ ERROR: lint `clippy::const_static_lifetime` #![warn(clippy::cognitive_complexity)] //~ ERROR: lint `clippy::cyclomatic_complexity` #![warn(clippy::derived_hash_with_manual_eq)] //~ ERROR: lint `clippy::derive_hash_xor_eq` #![warn(clippy::disallowed_methods)] //~ ERROR: lint `clippy::disallowed_method` #![warn(clippy::disallowed_types)] //~ ERROR: lint `clippy::disallowed_type` +#![warn(double_negations)] //~ ERROR: lint `clippy::double_neg` +#![warn(drop_bounds)] //~ ERROR: lint `clippy::drop_bounds` +#![warn(dropping_copy_types)] //~ ERROR: lint `clippy::drop_copy` +#![warn(dropping_references)] //~ ERROR: lint `clippy::drop_ref` #![warn(clippy::mixed_read_write_in_expression)] //~ ERROR: lint `clippy::eval_order_dependence` -#![warn(clippy::manual_find_map)] //~ ERROR: lint `clippy::find_map` #![warn(clippy::manual_filter_map)] //~ ERROR: lint `clippy::filter_map` +#![warn(clippy::manual_find_map)] //~ ERROR: lint `clippy::find_map` #![warn(unpredictable_function_pointer_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons` +#![warn(useless_ptr_null_checks)] //~ ERROR: lint `clippy::fn_null_check` +#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_option` +#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_result` +#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loops_over_fallibles` +#![warn(forgetting_copy_types)] //~ ERROR: lint `clippy::forget_copy` +#![warn(forgetting_references)] //~ ERROR: lint `clippy::forget_ref` #![warn(clippy::useless_conversion)] //~ ERROR: lint `clippy::identity_conversion` #![warn(clippy::redundant_pattern_matching)] //~ ERROR: lint `clippy::if_let_redundant_pattern_matching` #![warn(clippy::match_result_ok)] //~ ERROR: lint `clippy::if_let_some_result` #![warn(clippy::non_canonical_clone_impl)] //~ ERROR: lint `clippy::incorrect_clone_impl_on_copy_type` #![warn(clippy::non_canonical_partial_ord_impl)] //~ ERROR: lint `clippy::incorrect_partial_ord_impl_on_ord_type` #![warn(clippy::arithmetic_side_effects)] //~ ERROR: lint `clippy::integer_arithmetic` +#![warn(array_into_iter)] //~ ERROR: lint `clippy::into_iter_on_array` +#![warn(invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering` +#![warn(invalid_null_arguments)] //~ ERROR: lint `clippy::invalid_null_ptr_usage` +#![warn(invalid_value)] //~ ERROR: lint `clippy::invalid_ref` +#![warn(invalid_from_utf8_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked` +#![warn(let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop` #![warn(clippy::overly_complex_bool_expr)] //~ ERROR: lint `clippy::logic_bug` +#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::maybe_misused_cfg` +#![warn(enum_intrinsics_non_enums)] //~ ERROR: lint `clippy::mem_discriminant_non_enum` +#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::mismatched_target_os` #![warn(clippy::new_without_default)] //~ ERROR: lint `clippy::new_without_default_derive` #![warn(clippy::bind_instead_of_map)] //~ ERROR: lint `clippy::option_and_then_some` #![warn(clippy::expect_used)] //~ ERROR: lint `clippy::option_expect_used` @@ -93,49 +115,27 @@ #![warn(clippy::map_unwrap_or)] //~ ERROR: lint `clippy::option_map_unwrap_or_else` #![warn(clippy::unwrap_used)] //~ ERROR: lint `clippy::option_unwrap_used` #![warn(clippy::panicking_overflow_checks)] //~ ERROR: lint `clippy::overflow_check_conditional` +#![warn(non_fmt_panics)] //~ ERROR: lint `clippy::panic_params` +#![warn(named_arguments_used_positionally)] //~ ERROR: lint `clippy::positional_named_format_parameters` #![warn(clippy::needless_borrow)] //~ ERROR: lint `clippy::ref_in_deref` #![warn(clippy::expect_used)] //~ ERROR: lint `clippy::result_expect_used` #![warn(clippy::map_unwrap_or)] //~ ERROR: lint `clippy::result_map_unwrap_or_else` #![warn(clippy::unwrap_used)] //~ ERROR: lint `clippy::result_unwrap_used` +#![warn(clippy::reversed_empty_ranges)] //~ ERROR: lint `clippy::reverse_range_loop` #![warn(clippy::single_char_add_str)] //~ ERROR: lint `clippy::single_char_push_str` #![warn(clippy::module_name_repetitions)] //~ ERROR: lint `clippy::stutter` +#![warn(dangling_pointers_from_temporaries)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr` #![warn(clippy::missing_const_for_thread_local)] //~ ERROR: lint `clippy::thread_local_initializer_can_be_made_const` #![warn(clippy::recursive_format_impl)] //~ ERROR: lint `clippy::to_string_in_display` -#![warn(clippy::unwrap_or_default)] //~ ERROR: lint `clippy::unwrap_or_else_default` -#![warn(clippy::invisible_characters)] //~ ERROR: lint `clippy::zero_width_space` -#![warn(invalid_reference_casting)] //~ ERROR: lint `clippy::cast_ref_to_mut` -#![warn(suspicious_double_ref_op)] //~ ERROR: lint `clippy::clone_double_ref` -#![warn(invalid_nan_comparisons)] //~ ERROR: lint `clippy::cmp_nan` -#![warn(invalid_null_arguments)] //~ ERROR: lint `clippy::invalid_null_ptr_usage` -#![warn(double_negations)] //~ ERROR: lint `clippy::double_neg` -#![warn(drop_bounds)] //~ ERROR: lint `clippy::drop_bounds` -#![warn(dropping_copy_types)] //~ ERROR: lint `clippy::drop_copy` -#![warn(dropping_references)] //~ ERROR: lint `clippy::drop_ref` -#![warn(useless_ptr_null_checks)] //~ ERROR: lint `clippy::fn_null_check` -#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_option` -#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_result` -#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loops_over_fallibles` -#![warn(forgetting_copy_types)] //~ ERROR: lint `clippy::forget_copy` -#![warn(forgetting_references)] //~ ERROR: lint `clippy::forget_ref` -#![warn(array_into_iter)] //~ ERROR: lint `clippy::into_iter_on_array` -#![warn(invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering` -#![warn(invalid_value)] //~ ERROR: lint `clippy::invalid_ref` -#![warn(invalid_from_utf8_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked` -#![warn(let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop` -#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::maybe_misused_cfg` -#![warn(enum_intrinsics_non_enums)] //~ ERROR: lint `clippy::mem_discriminant_non_enum` -#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::mismatched_target_os` -#![warn(non_fmt_panics)] //~ ERROR: lint `clippy::panic_params` -#![warn(named_arguments_used_positionally)] //~ ERROR: lint `clippy::positional_named_format_parameters` -#![warn(dangling_pointers_from_temporaries)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr` +#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_float_to_int` +#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_int_to_char` +#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_int_to_float` +#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_num_to_bytes` #![warn(undropped_manually_drops)] //~ ERROR: lint `clippy::undropped_manually_drops` #![warn(unknown_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints` #![warn(unused_labels)] //~ ERROR: lint `clippy::unused_label` +#![warn(clippy::unwrap_or_default)] //~ ERROR: lint `clippy::unwrap_or_else_default` #![warn(ambiguous_wide_pointer_comparisons)] //~ ERROR: lint `clippy::vtable_address_comparisons` -#![warn(clippy::reversed_empty_ranges)] //~ ERROR: lint `clippy::reverse_range_loop` -#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_int_to_float` -#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_int_to_char` -#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_float_to_int` -#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_num_to_bytes` +#![warn(clippy::invisible_characters)] //~ ERROR: lint `clippy::zero_width_space` fn main() {} diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index 31dcd2cea0818..b5d5d07e639a0 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -7,85 +7,107 @@ #![allow(clippy::disallowed_names)] #![allow(clippy::blocks_in_conditions)] #![allow(clippy::box_collection)] +#![allow(invalid_reference_casting)] +#![allow(suspicious_double_ref_op)] +#![allow(invalid_nan_comparisons)] #![allow(clippy::redundant_static_lifetimes)] #![allow(clippy::cognitive_complexity)] #![allow(clippy::derived_hash_with_manual_eq)] #![allow(clippy::disallowed_methods)] #![allow(clippy::disallowed_types)] +#![allow(double_negations)] +#![allow(drop_bounds)] +#![allow(dropping_copy_types)] +#![allow(dropping_references)] #![allow(clippy::mixed_read_write_in_expression)] -#![allow(clippy::manual_find_map)] #![allow(clippy::manual_filter_map)] +#![allow(clippy::manual_find_map)] #![allow(unpredictable_function_pointer_comparisons)] +#![allow(useless_ptr_null_checks)] +#![allow(for_loops_over_fallibles)] +#![allow(forgetting_copy_types)] +#![allow(forgetting_references)] #![allow(clippy::useless_conversion)] #![allow(clippy::redundant_pattern_matching)] #![allow(clippy::match_result_ok)] #![allow(clippy::non_canonical_clone_impl)] #![allow(clippy::non_canonical_partial_ord_impl)] #![allow(clippy::arithmetic_side_effects)] +#![allow(array_into_iter)] +#![allow(invalid_atomic_ordering)] +#![allow(invalid_null_arguments)] +#![allow(invalid_value)] +#![allow(invalid_from_utf8_unchecked)] +#![allow(let_underscore_drop)] #![allow(clippy::overly_complex_bool_expr)] +#![allow(unexpected_cfgs)] +#![allow(enum_intrinsics_non_enums)] #![allow(clippy::new_without_default)] #![allow(clippy::bind_instead_of_map)] #![allow(clippy::expect_used)] #![allow(clippy::map_unwrap_or)] #![allow(clippy::unwrap_used)] #![allow(clippy::panicking_overflow_checks)] +#![allow(non_fmt_panics)] +#![allow(named_arguments_used_positionally)] #![allow(clippy::needless_borrow)] +#![allow(clippy::reversed_empty_ranges)] #![allow(clippy::single_char_add_str)] #![allow(clippy::module_name_repetitions)] +#![allow(dangling_pointers_from_temporaries)] #![allow(clippy::missing_const_for_thread_local)] #![allow(clippy::recursive_format_impl)] -#![allow(clippy::unwrap_or_default)] -#![allow(clippy::invisible_characters)] -#![allow(invalid_reference_casting)] -#![allow(suspicious_double_ref_op)] -#![allow(invalid_nan_comparisons)] -#![allow(invalid_null_arguments)] -#![allow(double_negations)] -#![allow(drop_bounds)] -#![allow(dropping_copy_types)] -#![allow(dropping_references)] -#![allow(useless_ptr_null_checks)] -#![allow(for_loops_over_fallibles)] -#![allow(forgetting_copy_types)] -#![allow(forgetting_references)] -#![allow(array_into_iter)] -#![allow(invalid_atomic_ordering)] -#![allow(invalid_value)] -#![allow(invalid_from_utf8_unchecked)] -#![allow(let_underscore_drop)] -#![allow(unexpected_cfgs)] -#![allow(enum_intrinsics_non_enums)] -#![allow(non_fmt_panics)] -#![allow(named_arguments_used_positionally)] -#![allow(dangling_pointers_from_temporaries)] +#![allow(unnecessary_transmutes)] #![allow(undropped_manually_drops)] #![allow(unknown_lints)] #![allow(unused_labels)] +#![allow(clippy::unwrap_or_default)] #![allow(ambiguous_wide_pointer_comparisons)] -#![allow(clippy::reversed_empty_ranges)] -#![allow(unnecessary_transmutes)] +#![allow(clippy::invisible_characters)] #![warn(clippy::almost_complete_letter_range)] //~ ERROR: lint `clippy::almost_complete_letter_range` #![warn(clippy::blacklisted_name)] //~ ERROR: lint `clippy::blacklisted_name` #![warn(clippy::block_in_if_condition_expr)] //~ ERROR: lint `clippy::block_in_if_condition_expr` #![warn(clippy::block_in_if_condition_stmt)] //~ ERROR: lint `clippy::block_in_if_condition_stmt` #![warn(clippy::blocks_in_if_conditions)] //~ ERROR: lint `clippy::blocks_in_if_conditions` #![warn(clippy::box_vec)] //~ ERROR: lint `clippy::box_vec` +#![warn(clippy::cast_ref_to_mut)] //~ ERROR: lint `clippy::cast_ref_to_mut` +#![warn(clippy::clone_double_ref)] //~ ERROR: lint `clippy::clone_double_ref` +#![warn(clippy::cmp_nan)] //~ ERROR: lint `clippy::cmp_nan` #![warn(clippy::const_static_lifetime)] //~ ERROR: lint `clippy::const_static_lifetime` #![warn(clippy::cyclomatic_complexity)] //~ ERROR: lint `clippy::cyclomatic_complexity` #![warn(clippy::derive_hash_xor_eq)] //~ ERROR: lint `clippy::derive_hash_xor_eq` #![warn(clippy::disallowed_method)] //~ ERROR: lint `clippy::disallowed_method` #![warn(clippy::disallowed_type)] //~ ERROR: lint `clippy::disallowed_type` +#![warn(clippy::double_neg)] //~ ERROR: lint `clippy::double_neg` +#![warn(clippy::drop_bounds)] //~ ERROR: lint `clippy::drop_bounds` +#![warn(clippy::drop_copy)] //~ ERROR: lint `clippy::drop_copy` +#![warn(clippy::drop_ref)] //~ ERROR: lint `clippy::drop_ref` #![warn(clippy::eval_order_dependence)] //~ ERROR: lint `clippy::eval_order_dependence` -#![warn(clippy::find_map)] //~ ERROR: lint `clippy::find_map` #![warn(clippy::filter_map)] //~ ERROR: lint `clippy::filter_map` +#![warn(clippy::find_map)] //~ ERROR: lint `clippy::find_map` #![warn(clippy::fn_address_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons` +#![warn(clippy::fn_null_check)] //~ ERROR: lint `clippy::fn_null_check` +#![warn(clippy::for_loop_over_option)] //~ ERROR: lint `clippy::for_loop_over_option` +#![warn(clippy::for_loop_over_result)] //~ ERROR: lint `clippy::for_loop_over_result` +#![warn(clippy::for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loops_over_fallibles` +#![warn(clippy::forget_copy)] //~ ERROR: lint `clippy::forget_copy` +#![warn(clippy::forget_ref)] //~ ERROR: lint `clippy::forget_ref` #![warn(clippy::identity_conversion)] //~ ERROR: lint `clippy::identity_conversion` #![warn(clippy::if_let_redundant_pattern_matching)] //~ ERROR: lint `clippy::if_let_redundant_pattern_matching` #![warn(clippy::if_let_some_result)] //~ ERROR: lint `clippy::if_let_some_result` #![warn(clippy::incorrect_clone_impl_on_copy_type)] //~ ERROR: lint `clippy::incorrect_clone_impl_on_copy_type` #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)] //~ ERROR: lint `clippy::incorrect_partial_ord_impl_on_ord_type` #![warn(clippy::integer_arithmetic)] //~ ERROR: lint `clippy::integer_arithmetic` +#![warn(clippy::into_iter_on_array)] //~ ERROR: lint `clippy::into_iter_on_array` +#![warn(clippy::invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering` +#![warn(clippy::invalid_null_ptr_usage)] //~ ERROR: lint `clippy::invalid_null_ptr_usage` +#![warn(clippy::invalid_ref)] //~ ERROR: lint `clippy::invalid_ref` +#![warn(clippy::invalid_utf8_in_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked` +#![warn(clippy::let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop` #![warn(clippy::logic_bug)] //~ ERROR: lint `clippy::logic_bug` +#![warn(clippy::maybe_misused_cfg)] //~ ERROR: lint `clippy::maybe_misused_cfg` +#![warn(clippy::mem_discriminant_non_enum)] //~ ERROR: lint `clippy::mem_discriminant_non_enum` +#![warn(clippy::mismatched_target_os)] //~ ERROR: lint `clippy::mismatched_target_os` #![warn(clippy::new_without_default_derive)] //~ ERROR: lint `clippy::new_without_default_derive` #![warn(clippy::option_and_then_some)] //~ ERROR: lint `clippy::option_and_then_some` #![warn(clippy::option_expect_used)] //~ ERROR: lint `clippy::option_expect_used` @@ -93,49 +115,27 @@ #![warn(clippy::option_map_unwrap_or_else)] //~ ERROR: lint `clippy::option_map_unwrap_or_else` #![warn(clippy::option_unwrap_used)] //~ ERROR: lint `clippy::option_unwrap_used` #![warn(clippy::overflow_check_conditional)] //~ ERROR: lint `clippy::overflow_check_conditional` +#![warn(clippy::panic_params)] //~ ERROR: lint `clippy::panic_params` +#![warn(clippy::positional_named_format_parameters)] //~ ERROR: lint `clippy::positional_named_format_parameters` #![warn(clippy::ref_in_deref)] //~ ERROR: lint `clippy::ref_in_deref` #![warn(clippy::result_expect_used)] //~ ERROR: lint `clippy::result_expect_used` #![warn(clippy::result_map_unwrap_or_else)] //~ ERROR: lint `clippy::result_map_unwrap_or_else` #![warn(clippy::result_unwrap_used)] //~ ERROR: lint `clippy::result_unwrap_used` +#![warn(clippy::reverse_range_loop)] //~ ERROR: lint `clippy::reverse_range_loop` #![warn(clippy::single_char_push_str)] //~ ERROR: lint `clippy::single_char_push_str` #![warn(clippy::stutter)] //~ ERROR: lint `clippy::stutter` +#![warn(clippy::temporary_cstring_as_ptr)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr` #![warn(clippy::thread_local_initializer_can_be_made_const)] //~ ERROR: lint `clippy::thread_local_initializer_can_be_made_const` #![warn(clippy::to_string_in_display)] //~ ERROR: lint `clippy::to_string_in_display` -#![warn(clippy::unwrap_or_else_default)] //~ ERROR: lint `clippy::unwrap_or_else_default` -#![warn(clippy::zero_width_space)] //~ ERROR: lint `clippy::zero_width_space` -#![warn(clippy::cast_ref_to_mut)] //~ ERROR: lint `clippy::cast_ref_to_mut` -#![warn(clippy::clone_double_ref)] //~ ERROR: lint `clippy::clone_double_ref` -#![warn(clippy::cmp_nan)] //~ ERROR: lint `clippy::cmp_nan` -#![warn(clippy::invalid_null_ptr_usage)] //~ ERROR: lint `clippy::invalid_null_ptr_usage` -#![warn(clippy::double_neg)] //~ ERROR: lint `clippy::double_neg` -#![warn(clippy::drop_bounds)] //~ ERROR: lint `clippy::drop_bounds` -#![warn(clippy::drop_copy)] //~ ERROR: lint `clippy::drop_copy` -#![warn(clippy::drop_ref)] //~ ERROR: lint `clippy::drop_ref` -#![warn(clippy::fn_null_check)] //~ ERROR: lint `clippy::fn_null_check` -#![warn(clippy::for_loop_over_option)] //~ ERROR: lint `clippy::for_loop_over_option` -#![warn(clippy::for_loop_over_result)] //~ ERROR: lint `clippy::for_loop_over_result` -#![warn(clippy::for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loops_over_fallibles` -#![warn(clippy::forget_copy)] //~ ERROR: lint `clippy::forget_copy` -#![warn(clippy::forget_ref)] //~ ERROR: lint `clippy::forget_ref` -#![warn(clippy::into_iter_on_array)] //~ ERROR: lint `clippy::into_iter_on_array` -#![warn(clippy::invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering` -#![warn(clippy::invalid_ref)] //~ ERROR: lint `clippy::invalid_ref` -#![warn(clippy::invalid_utf8_in_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked` -#![warn(clippy::let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop` -#![warn(clippy::maybe_misused_cfg)] //~ ERROR: lint `clippy::maybe_misused_cfg` -#![warn(clippy::mem_discriminant_non_enum)] //~ ERROR: lint `clippy::mem_discriminant_non_enum` -#![warn(clippy::mismatched_target_os)] //~ ERROR: lint `clippy::mismatched_target_os` -#![warn(clippy::panic_params)] //~ ERROR: lint `clippy::panic_params` -#![warn(clippy::positional_named_format_parameters)] //~ ERROR: lint `clippy::positional_named_format_parameters` -#![warn(clippy::temporary_cstring_as_ptr)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr` +#![warn(clippy::transmute_float_to_int)] //~ ERROR: lint `clippy::transmute_float_to_int` +#![warn(clippy::transmute_int_to_char)] //~ ERROR: lint `clippy::transmute_int_to_char` +#![warn(clippy::transmute_int_to_float)] //~ ERROR: lint `clippy::transmute_int_to_float` +#![warn(clippy::transmute_num_to_bytes)] //~ ERROR: lint `clippy::transmute_num_to_bytes` #![warn(clippy::undropped_manually_drops)] //~ ERROR: lint `clippy::undropped_manually_drops` #![warn(clippy::unknown_clippy_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints` #![warn(clippy::unused_label)] //~ ERROR: lint `clippy::unused_label` +#![warn(clippy::unwrap_or_else_default)] //~ ERROR: lint `clippy::unwrap_or_else_default` #![warn(clippy::vtable_address_comparisons)] //~ ERROR: lint `clippy::vtable_address_comparisons` -#![warn(clippy::reverse_range_loop)] //~ ERROR: lint `clippy::reverse_range_loop` -#![warn(clippy::transmute_int_to_float)] //~ ERROR: lint `clippy::transmute_int_to_float` -#![warn(clippy::transmute_int_to_char)] //~ ERROR: lint `clippy::transmute_int_to_char` -#![warn(clippy::transmute_float_to_int)] //~ ERROR: lint `clippy::transmute_float_to_int` -#![warn(clippy::transmute_num_to_bytes)] //~ ERROR: lint `clippy::transmute_num_to_bytes` +#![warn(clippy::zero_width_space)] //~ ERROR: lint `clippy::zero_width_space` fn main() {} diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index a8d5c96acc3a7..2487dfc8eba44 100644 --- a/tests/ui/rename.stderr +++ b/tests/ui/rename.stderr @@ -37,407 +37,407 @@ error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` -error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` +error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting` --> tests/ui/rename.rs:73:9 | +LL | #![warn(clippy::cast_ref_to_mut)] + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting` + +error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op` + --> tests/ui/rename.rs:74:9 + | +LL | #![warn(clippy::clone_double_ref)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op` + +error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons` + --> tests/ui/rename.rs:75:9 + | +LL | #![warn(clippy::cmp_nan)] + | ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons` + +error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` + --> tests/ui/rename.rs:76:9 + | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> tests/ui/rename.rs:74:9 + --> tests/ui/rename.rs:77:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq` - --> tests/ui/rename.rs:75:9 + --> tests/ui/rename.rs:78:9 | LL | #![warn(clippy::derive_hash_xor_eq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> tests/ui/rename.rs:76:9 + --> tests/ui/rename.rs:79:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> tests/ui/rename.rs:77:9 + --> tests/ui/rename.rs:80:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` -error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> tests/ui/rename.rs:78:9 - | -LL | #![warn(clippy::eval_order_dependence)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` - -error: lint `clippy::find_map` has been renamed to `clippy::manual_find_map` - --> tests/ui/rename.rs:79:9 - | -LL | #![warn(clippy::find_map)] - | ^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_find_map` - -error: lint `clippy::filter_map` has been renamed to `clippy::manual_filter_map` - --> tests/ui/rename.rs:80:9 - | -LL | #![warn(clippy::filter_map)] - | ^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_filter_map` - -error: lint `clippy::fn_address_comparisons` has been renamed to `unpredictable_function_pointer_comparisons` +error: lint `clippy::double_neg` has been renamed to `double_negations` --> tests/ui/rename.rs:81:9 | -LL | #![warn(clippy::fn_address_comparisons)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unpredictable_function_pointer_comparisons` +LL | #![warn(clippy::double_neg)] + | ^^^^^^^^^^^^^^^^^^ help: use the new name: `double_negations` -error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` +error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` --> tests/ui/rename.rs:82:9 | -LL | #![warn(clippy::identity_conversion)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` +LL | #![warn(clippy::drop_bounds)] + | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` -error: lint `clippy::if_let_redundant_pattern_matching` has been renamed to `clippy::redundant_pattern_matching` +error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types` --> tests/ui/rename.rs:83:9 | -LL | #![warn(clippy::if_let_redundant_pattern_matching)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_pattern_matching` +LL | #![warn(clippy::drop_copy)] + | ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types` -error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` +error: lint `clippy::drop_ref` has been renamed to `dropping_references` --> tests/ui/rename.rs:84:9 | -LL | #![warn(clippy::if_let_some_result)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` +LL | #![warn(clippy::drop_ref)] + | ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references` -error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl` +error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` --> tests/ui/rename.rs:85:9 | -LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl` +LL | #![warn(clippy::eval_order_dependence)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` -error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl` +error: lint `clippy::filter_map` has been renamed to `clippy::manual_filter_map` --> tests/ui/rename.rs:86:9 | -LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl` +LL | #![warn(clippy::filter_map)] + | ^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_filter_map` -error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects` +error: lint `clippy::find_map` has been renamed to `clippy::manual_find_map` --> tests/ui/rename.rs:87:9 | -LL | #![warn(clippy::integer_arithmetic)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects` +LL | #![warn(clippy::find_map)] + | ^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_find_map` -error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` +error: lint `clippy::fn_address_comparisons` has been renamed to `unpredictable_function_pointer_comparisons` --> tests/ui/rename.rs:88:9 | -LL | #![warn(clippy::logic_bug)] - | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` +LL | #![warn(clippy::fn_address_comparisons)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unpredictable_function_pointer_comparisons` -error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` +error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks` --> tests/ui/rename.rs:89:9 | -LL | #![warn(clippy::new_without_default_derive)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` +LL | #![warn(clippy::fn_null_check)] + | ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks` -error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` +error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` --> tests/ui/rename.rs:90:9 | -LL | #![warn(clippy::option_and_then_some)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` +LL | #![warn(clippy::for_loop_over_option)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` -error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` +error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` --> tests/ui/rename.rs:91:9 | -LL | #![warn(clippy::option_expect_used)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` +LL | #![warn(clippy::for_loop_over_result)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` -error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` +error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` --> tests/ui/rename.rs:92:9 | -LL | #![warn(clippy::option_map_unwrap_or)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` +LL | #![warn(clippy::for_loops_over_fallibles)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` -error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` +error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types` --> tests/ui/rename.rs:93:9 | -LL | #![warn(clippy::option_map_unwrap_or_else)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` +LL | #![warn(clippy::forget_copy)] + | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types` -error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` +error: lint `clippy::forget_ref` has been renamed to `forgetting_references` --> tests/ui/rename.rs:94:9 | -LL | #![warn(clippy::option_unwrap_used)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` +LL | #![warn(clippy::forget_ref)] + | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references` -error: lint `clippy::overflow_check_conditional` has been renamed to `clippy::panicking_overflow_checks` +error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` --> tests/ui/rename.rs:95:9 | -LL | #![warn(clippy::overflow_check_conditional)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::panicking_overflow_checks` +LL | #![warn(clippy::identity_conversion)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` -error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` +error: lint `clippy::if_let_redundant_pattern_matching` has been renamed to `clippy::redundant_pattern_matching` --> tests/ui/rename.rs:96:9 | -LL | #![warn(clippy::ref_in_deref)] - | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` +LL | #![warn(clippy::if_let_redundant_pattern_matching)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_pattern_matching` -error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` +error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` --> tests/ui/rename.rs:97:9 | -LL | #![warn(clippy::result_expect_used)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` +LL | #![warn(clippy::if_let_some_result)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` -error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` +error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl` --> tests/ui/rename.rs:98:9 | -LL | #![warn(clippy::result_map_unwrap_or_else)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` +LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl` -error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` +error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl` --> tests/ui/rename.rs:99:9 | -LL | #![warn(clippy::result_unwrap_used)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` +LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl` -error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` +error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects` --> tests/ui/rename.rs:100:9 | -LL | #![warn(clippy::single_char_push_str)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` +LL | #![warn(clippy::integer_arithmetic)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects` -error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` +error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` --> tests/ui/rename.rs:101:9 | -LL | #![warn(clippy::stutter)] - | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` +LL | #![warn(clippy::into_iter_on_array)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` -error: lint `clippy::thread_local_initializer_can_be_made_const` has been renamed to `clippy::missing_const_for_thread_local` +error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` --> tests/ui/rename.rs:102:9 | -LL | #![warn(clippy::thread_local_initializer_can_be_made_const)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::missing_const_for_thread_local` +LL | #![warn(clippy::invalid_atomic_ordering)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` -error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` +error: lint `clippy::invalid_null_ptr_usage` has been renamed to `invalid_null_arguments` --> tests/ui/rename.rs:103:9 | -LL | #![warn(clippy::to_string_in_display)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` +LL | #![warn(clippy::invalid_null_ptr_usage)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_null_arguments` -error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default` +error: lint `clippy::invalid_ref` has been renamed to `invalid_value` --> tests/ui/rename.rs:104:9 | -LL | #![warn(clippy::unwrap_or_else_default)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default` +LL | #![warn(clippy::invalid_ref)] + | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` -error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` +error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked` --> tests/ui/rename.rs:105:9 | -LL | #![warn(clippy::zero_width_space)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` +LL | #![warn(clippy::invalid_utf8_in_unchecked)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked` -error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting` +error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` --> tests/ui/rename.rs:106:9 | -LL | #![warn(clippy::cast_ref_to_mut)] - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting` +LL | #![warn(clippy::let_underscore_drop)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` -error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op` +error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` --> tests/ui/rename.rs:107:9 | -LL | #![warn(clippy::clone_double_ref)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op` +LL | #![warn(clippy::logic_bug)] + | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` -error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons` +error: lint `clippy::maybe_misused_cfg` has been renamed to `unexpected_cfgs` --> tests/ui/rename.rs:108:9 | -LL | #![warn(clippy::cmp_nan)] - | ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons` +LL | #![warn(clippy::maybe_misused_cfg)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs` -error: lint `clippy::invalid_null_ptr_usage` has been renamed to `invalid_null_arguments` +error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` --> tests/ui/rename.rs:109:9 | -LL | #![warn(clippy::invalid_null_ptr_usage)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_null_arguments` +LL | #![warn(clippy::mem_discriminant_non_enum)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` -error: lint `clippy::double_neg` has been renamed to `double_negations` +error: lint `clippy::mismatched_target_os` has been renamed to `unexpected_cfgs` --> tests/ui/rename.rs:110:9 | -LL | #![warn(clippy::double_neg)] - | ^^^^^^^^^^^^^^^^^^ help: use the new name: `double_negations` +LL | #![warn(clippy::mismatched_target_os)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs` -error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` +error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` --> tests/ui/rename.rs:111:9 | -LL | #![warn(clippy::drop_bounds)] - | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` +LL | #![warn(clippy::new_without_default_derive)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` -error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types` +error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` --> tests/ui/rename.rs:112:9 | -LL | #![warn(clippy::drop_copy)] - | ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types` +LL | #![warn(clippy::option_and_then_some)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` -error: lint `clippy::drop_ref` has been renamed to `dropping_references` +error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` --> tests/ui/rename.rs:113:9 | -LL | #![warn(clippy::drop_ref)] - | ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references` +LL | #![warn(clippy::option_expect_used)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` -error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks` +error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` --> tests/ui/rename.rs:114:9 | -LL | #![warn(clippy::fn_null_check)] - | ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks` +LL | #![warn(clippy::option_map_unwrap_or)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` -error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` +error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` --> tests/ui/rename.rs:115:9 | -LL | #![warn(clippy::for_loop_over_option)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` +LL | #![warn(clippy::option_map_unwrap_or_else)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` -error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` +error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` --> tests/ui/rename.rs:116:9 | -LL | #![warn(clippy::for_loop_over_result)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` +LL | #![warn(clippy::option_unwrap_used)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` -error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` +error: lint `clippy::overflow_check_conditional` has been renamed to `clippy::panicking_overflow_checks` --> tests/ui/rename.rs:117:9 | -LL | #![warn(clippy::for_loops_over_fallibles)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` +LL | #![warn(clippy::overflow_check_conditional)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::panicking_overflow_checks` -error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types` +error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` --> tests/ui/rename.rs:118:9 | -LL | #![warn(clippy::forget_copy)] - | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types` +LL | #![warn(clippy::panic_params)] + | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` -error: lint `clippy::forget_ref` has been renamed to `forgetting_references` +error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` --> tests/ui/rename.rs:119:9 | -LL | #![warn(clippy::forget_ref)] - | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references` +LL | #![warn(clippy::positional_named_format_parameters)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` -error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` +error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` --> tests/ui/rename.rs:120:9 | -LL | #![warn(clippy::into_iter_on_array)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` +LL | #![warn(clippy::ref_in_deref)] + | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` -error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` +error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` --> tests/ui/rename.rs:121:9 | -LL | #![warn(clippy::invalid_atomic_ordering)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` +LL | #![warn(clippy::result_expect_used)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` -error: lint `clippy::invalid_ref` has been renamed to `invalid_value` +error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` --> tests/ui/rename.rs:122:9 | -LL | #![warn(clippy::invalid_ref)] - | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` +LL | #![warn(clippy::result_map_unwrap_or_else)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` -error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked` +error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` --> tests/ui/rename.rs:123:9 | -LL | #![warn(clippy::invalid_utf8_in_unchecked)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked` +LL | #![warn(clippy::result_unwrap_used)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` -error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` +error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_empty_ranges` --> tests/ui/rename.rs:124:9 | -LL | #![warn(clippy::let_underscore_drop)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` +LL | #![warn(clippy::reverse_range_loop)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges` -error: lint `clippy::maybe_misused_cfg` has been renamed to `unexpected_cfgs` +error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` --> tests/ui/rename.rs:125:9 | -LL | #![warn(clippy::maybe_misused_cfg)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs` +LL | #![warn(clippy::single_char_push_str)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` -error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` +error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` --> tests/ui/rename.rs:126:9 | -LL | #![warn(clippy::mem_discriminant_non_enum)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` +LL | #![warn(clippy::stutter)] + | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` -error: lint `clippy::mismatched_target_os` has been renamed to `unexpected_cfgs` +error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries` --> tests/ui/rename.rs:127:9 | -LL | #![warn(clippy::mismatched_target_os)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs` +LL | #![warn(clippy::temporary_cstring_as_ptr)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries` -error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` +error: lint `clippy::thread_local_initializer_can_be_made_const` has been renamed to `clippy::missing_const_for_thread_local` --> tests/ui/rename.rs:128:9 | -LL | #![warn(clippy::panic_params)] - | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` +LL | #![warn(clippy::thread_local_initializer_can_be_made_const)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::missing_const_for_thread_local` -error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` +error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` --> tests/ui/rename.rs:129:9 | -LL | #![warn(clippy::positional_named_format_parameters)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` +LL | #![warn(clippy::to_string_in_display)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` -error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries` +error: lint `clippy::transmute_float_to_int` has been renamed to `unnecessary_transmutes` --> tests/ui/rename.rs:130:9 | -LL | #![warn(clippy::temporary_cstring_as_ptr)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries` +LL | #![warn(clippy::transmute_float_to_int)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes` -error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops` +error: lint `clippy::transmute_int_to_char` has been renamed to `unnecessary_transmutes` --> tests/ui/rename.rs:131:9 | -LL | #![warn(clippy::undropped_manually_drops)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops` +LL | #![warn(clippy::transmute_int_to_char)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes` -error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` +error: lint `clippy::transmute_int_to_float` has been renamed to `unnecessary_transmutes` --> tests/ui/rename.rs:132:9 | -LL | #![warn(clippy::unknown_clippy_lints)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` +LL | #![warn(clippy::transmute_int_to_float)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes` -error: lint `clippy::unused_label` has been renamed to `unused_labels` +error: lint `clippy::transmute_num_to_bytes` has been renamed to `unnecessary_transmutes` --> tests/ui/rename.rs:133:9 | -LL | #![warn(clippy::unused_label)] - | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` +LL | #![warn(clippy::transmute_num_to_bytes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes` -error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons` +error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops` --> tests/ui/rename.rs:134:9 | -LL | #![warn(clippy::vtable_address_comparisons)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons` +LL | #![warn(clippy::undropped_manually_drops)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops` -error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_empty_ranges` +error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` --> tests/ui/rename.rs:135:9 | -LL | #![warn(clippy::reverse_range_loop)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges` +LL | #![warn(clippy::unknown_clippy_lints)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` -error: lint `clippy::transmute_int_to_float` has been renamed to `unnecessary_transmutes` +error: lint `clippy::unused_label` has been renamed to `unused_labels` --> tests/ui/rename.rs:136:9 | -LL | #![warn(clippy::transmute_int_to_float)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes` +LL | #![warn(clippy::unused_label)] + | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` -error: lint `clippy::transmute_int_to_char` has been renamed to `unnecessary_transmutes` +error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default` --> tests/ui/rename.rs:137:9 | -LL | #![warn(clippy::transmute_int_to_char)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes` +LL | #![warn(clippy::unwrap_or_else_default)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default` -error: lint `clippy::transmute_float_to_int` has been renamed to `unnecessary_transmutes` +error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons` --> tests/ui/rename.rs:138:9 | -LL | #![warn(clippy::transmute_float_to_int)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes` +LL | #![warn(clippy::vtable_address_comparisons)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons` -error: lint `clippy::transmute_num_to_bytes` has been renamed to `unnecessary_transmutes` +error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` --> tests/ui/rename.rs:139:9 | -LL | #![warn(clippy::transmute_num_to_bytes)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes` +LL | #![warn(clippy::zero_width_space)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: aborting due to 73 previous errors diff --git a/tests/ui/same_functions_in_if_condition.rs b/tests/ui/same_functions_in_if_condition.rs index a98b73c9e1c82..3f205b322ab08 100644 --- a/tests/ui/same_functions_in_if_condition.rs +++ b/tests/ui/same_functions_in_if_condition.rs @@ -31,34 +31,34 @@ fn ifs_same_cond_fn() { let obj = Struct; if function() { - } else if function() { //~^ same_functions_in_if_condition + } else if function() { } if fn_arg(a) { - } else if fn_arg(a) { //~^ same_functions_in_if_condition + } else if fn_arg(a) { } if obj.method() { - } else if obj.method() { //~^ same_functions_in_if_condition + } else if obj.method() { } if obj.method_arg(a) { - } else if obj.method_arg(a) { //~^ same_functions_in_if_condition + } else if obj.method_arg(a) { } let mut v = vec![1]; if v.pop().is_none() { - } else if v.pop().is_none() { //~^ same_functions_in_if_condition + } else if v.pop().is_none() { } if v.len() == 42 { - } else if v.len() == 42 { //~^ same_functions_in_if_condition + } else if v.len() == 42 { } if v.len() == 1 { diff --git a/tests/ui/same_functions_in_if_condition.stderr b/tests/ui/same_functions_in_if_condition.stderr index 35dcbadce5953..59f4511757d61 100644 --- a/tests/ui/same_functions_in_if_condition.stderr +++ b/tests/ui/same_functions_in_if_condition.stderr @@ -1,79 +1,62 @@ -error: this `if` has the same function call as a previous `if` - --> tests/ui/same_functions_in_if_condition.rs:34:15 - | -LL | } else if function() { - | ^^^^^^^^^^ - | -note: same as this +error: these `if` branches have the same function call --> tests/ui/same_functions_in_if_condition.rs:33:8 | LL | if function() { | ^^^^^^^^^^ +LL | +LL | } else if function() { + | ^^^^^^^^^^ + | note: the lint level is defined here --> tests/ui/same_functions_in_if_condition.rs:2:9 | LL | #![deny(clippy::same_functions_in_if_condition)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: this `if` has the same function call as a previous `if` - --> tests/ui/same_functions_in_if_condition.rs:39:15 - | -LL | } else if fn_arg(a) { - | ^^^^^^^^^ - | -note: same as this +error: these `if` branches have the same function call --> tests/ui/same_functions_in_if_condition.rs:38:8 | LL | if fn_arg(a) { | ^^^^^^^^^ +LL | +LL | } else if fn_arg(a) { + | ^^^^^^^^^ -error: this `if` has the same function call as a previous `if` - --> tests/ui/same_functions_in_if_condition.rs:44:15 - | -LL | } else if obj.method() { - | ^^^^^^^^^^^^ - | -note: same as this +error: these `if` branches have the same function call --> tests/ui/same_functions_in_if_condition.rs:43:8 | LL | if obj.method() { | ^^^^^^^^^^^^ +LL | +LL | } else if obj.method() { + | ^^^^^^^^^^^^ -error: this `if` has the same function call as a previous `if` - --> tests/ui/same_functions_in_if_condition.rs:49:15 - | -LL | } else if obj.method_arg(a) { - | ^^^^^^^^^^^^^^^^^ - | -note: same as this +error: these `if` branches have the same function call --> tests/ui/same_functions_in_if_condition.rs:48:8 | LL | if obj.method_arg(a) { | ^^^^^^^^^^^^^^^^^ - -error: this `if` has the same function call as a previous `if` - --> tests/ui/same_functions_in_if_condition.rs:55:15 - | -LL | } else if v.pop().is_none() { +LL | +LL | } else if obj.method_arg(a) { | ^^^^^^^^^^^^^^^^^ - | -note: same as this + +error: these `if` branches have the same function call --> tests/ui/same_functions_in_if_condition.rs:54:8 | LL | if v.pop().is_none() { | ^^^^^^^^^^^^^^^^^ +LL | +LL | } else if v.pop().is_none() { + | ^^^^^^^^^^^^^^^^^ -error: this `if` has the same function call as a previous `if` - --> tests/ui/same_functions_in_if_condition.rs:60:15 - | -LL | } else if v.len() == 42 { - | ^^^^^^^^^^^^^ - | -note: same as this +error: these `if` branches have the same function call --> tests/ui/same_functions_in_if_condition.rs:59:8 | LL | if v.len() == 42 { | ^^^^^^^^^^^^^ +LL | +LL | } else if v.len() == 42 { + | ^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/tests/ui/single_range_in_vec_init.rs b/tests/ui/single_range_in_vec_init.rs index c6c0cb347dc68..25884450b0842 100644 --- a/tests/ui/single_range_in_vec_init.rs +++ b/tests/ui/single_range_in_vec_init.rs @@ -1,6 +1,6 @@ //@aux-build:proc_macros.rs //@no-rustfix: overlapping suggestions -#![allow(clippy::no_effect, clippy::useless_vec, unused)] +#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::useless_vec, unused)] #![warn(clippy::single_range_in_vec_init)] #![feature(generic_arg_infer)] diff --git a/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.fixed b/tests/ui/skip_rustfmt/non_expressive_names_error_recovery.fixed similarity index 100% rename from tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.fixed rename to tests/ui/skip_rustfmt/non_expressive_names_error_recovery.fixed diff --git a/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs b/tests/ui/skip_rustfmt/non_expressive_names_error_recovery.rs similarity index 100% rename from tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs rename to tests/ui/skip_rustfmt/non_expressive_names_error_recovery.rs diff --git a/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.stderr b/tests/ui/skip_rustfmt/non_expressive_names_error_recovery.stderr similarity index 80% rename from tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.stderr rename to tests/ui/skip_rustfmt/non_expressive_names_error_recovery.stderr index e334ca5241eba..4998b9bd2cc40 100644 --- a/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.stderr +++ b/tests/ui/skip_rustfmt/non_expressive_names_error_recovery.stderr @@ -1,5 +1,5 @@ error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `)` - --> tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs:6:19 + --> tests/ui/skip_rustfmt/non_expressive_names_error_recovery.rs:6:19 | LL | fn aa(a: Aa::new(); + s.remove(&"hello".to_owned()); +} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index 7954a4ad4ce77..f2dbd1db3c9f6 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -675,3 +675,9 @@ mod issue_14242 { rc_slice_provider().to_vec().into_iter() } } + +fn issue14833() { + use std::collections::HashSet; + let mut s = HashSet::<&String>::new(); + s.remove(&"hello".to_owned()); +} diff --git a/tests/ui/unnecessary_wraps.stderr b/tests/ui/unnecessary_wraps.stderr index ba562f5a50bec..13d71271e211c 100644 --- a/tests/ui/unnecessary_wraps.stderr +++ b/tests/ui/unnecessary_wraps.stderr @@ -1,13 +1,8 @@ error: this function's return value is unnecessarily wrapped by `Option` --> tests/ui/unnecessary_wraps.rs:9:1 | -LL | / fn func1(a: bool, b: bool) -> Option { -LL | | -LL | | -LL | | if a && b { -... | -LL | | } - | |_^ +LL | fn func1(a: bool, b: bool) -> Option { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unnecessary-wraps` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_wraps)]` @@ -16,7 +11,7 @@ help: remove `Option` from the return type... LL - fn func1(a: bool, b: bool) -> Option { LL + fn func1(a: bool, b: bool) -> i32 { | -help: ...and then change returning expressions +help: ...and then remove the surrounding `Some()` from returning expressions | LL ~ return 42; LL | } @@ -30,21 +25,15 @@ LL ~ return 1337; error: this function's return value is unnecessarily wrapped by `Option` --> tests/ui/unnecessary_wraps.rs:24:1 | -LL | / fn func2(a: bool, b: bool) -> Option { -LL | | -LL | | -LL | | if a && b { -... | -LL | | if a { Some(20) } else { Some(30) } -LL | | } - | |_^ +LL | fn func2(a: bool, b: bool) -> Option { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove `Option` from the return type... | LL - fn func2(a: bool, b: bool) -> Option { LL + fn func2(a: bool, b: bool) -> i32 { | -help: ...and then change returning expressions +help: ...and then remove the surrounding `Some()` from returning expressions | LL ~ return 10; LL | } @@ -54,19 +43,15 @@ LL ~ if a { 20 } else { 30 } error: this function's return value is unnecessarily wrapped by `Option` --> tests/ui/unnecessary_wraps.rs:44:1 | -LL | / fn func5() -> Option { -LL | | -LL | | -LL | | Some(1) -LL | | } - | |_^ +LL | fn func5() -> Option { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove `Option` from the return type... | LL - fn func5() -> Option { LL + fn func5() -> i32 { | -help: ...and then change returning expressions +help: ...and then remove the surrounding `Some()` from returning expressions | LL - Some(1) LL + 1 @@ -75,19 +60,15 @@ LL + 1 error: this function's return value is unnecessarily wrapped by `Result` --> tests/ui/unnecessary_wraps.rs:56:1 | -LL | / fn func7() -> Result { -LL | | -LL | | -LL | | Ok(1) -LL | | } - | |_^ +LL | fn func7() -> Result { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove `Result` from the return type... | LL - fn func7() -> Result { LL + fn func7() -> i32 { | -help: ...and then change returning expressions +help: ...and then remove the surrounding `Ok()` from returning expressions | LL - Ok(1) LL + 1 @@ -96,19 +77,15 @@ LL + 1 error: this function's return value is unnecessarily wrapped by `Option` --> tests/ui/unnecessary_wraps.rs:86:5 | -LL | / fn func12() -> Option { -LL | | -LL | | -LL | | Some(1) -LL | | } - | |_____^ +LL | fn func12() -> Option { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove `Option` from the return type... | LL - fn func12() -> Option { LL + fn func12() -> i32 { | -help: ...and then change returning expressions +help: ...and then remove the surrounding `Some()` from returning expressions | LL - Some(1) LL + 1 @@ -117,13 +94,8 @@ LL + 1 error: this function's return value is unnecessary --> tests/ui/unnecessary_wraps.rs:115:1 | -LL | / fn issue_6640_1(a: bool, b: bool) -> Option<()> { -LL | | -LL | | -LL | | if a && b { -... | -LL | | } - | |_^ +LL | fn issue_6640_1(a: bool, b: bool) -> Option<()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the return type... | @@ -144,13 +116,8 @@ LL ~ return ; error: this function's return value is unnecessary --> tests/ui/unnecessary_wraps.rs:130:1 | -LL | / fn issue_6640_2(a: bool, b: bool) -> Result<(), i32> { -LL | | -LL | | -LL | | if a && b { -... | -LL | | } - | |_^ +LL | fn issue_6640_2(a: bool, b: bool) -> Result<(), i32> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the return type... | diff --git a/tests/ui/useless_asref.fixed b/tests/ui/useless_asref.fixed index 8c1f948fb5806..3c3ea5a736d43 100644 --- a/tests/ui/useless_asref.fixed +++ b/tests/ui/useless_asref.fixed @@ -248,6 +248,16 @@ impl Issue12357 { } } +fn issue_14828() { + pub trait T { + fn as_ref(&self) {} + } + + impl T for () {} + + ().as_ref(); +} + fn main() { not_ok(); ok(); diff --git a/tests/ui/useless_asref.rs b/tests/ui/useless_asref.rs index d9db2d4f5596a..c173dd677152d 100644 --- a/tests/ui/useless_asref.rs +++ b/tests/ui/useless_asref.rs @@ -248,6 +248,16 @@ impl Issue12357 { } } +fn issue_14828() { + pub trait T { + fn as_ref(&self) {} + } + + impl T for () {} + + ().as_ref(); +} + fn main() { not_ok(); ok(); diff --git a/tests/ui/useless_concat.fixed b/tests/ui/useless_concat.fixed new file mode 100644 index 0000000000000..360b6f6ce82ee --- /dev/null +++ b/tests/ui/useless_concat.fixed @@ -0,0 +1,41 @@ +//@aux-build:proc_macros.rs + +#![warn(clippy::useless_concat)] +#![allow(clippy::print_literal)] + +extern crate proc_macros; +use proc_macros::{external, with_span}; + +macro_rules! my_concat { + ($fmt:literal $(, $e:expr)*) => { + println!(concat!("ERROR: ", $fmt), $($e,)*); + } +} + +fn main() { + let x = ""; //~ useless_concat + let x = "c"; //~ useless_concat + let x = "\""; //~ useless_concat + let x = "true"; //~ useless_concat + let x = "1"; //~ useless_concat + let x = "1.0000"; //~ useless_concat + let x = "1"; //~ useless_concat + let x = "1"; //~ useless_concat + let x = "1.0000"; //~ useless_concat + let x = "1.0000"; //~ useless_concat + let x = "a😀\n"; //~ useless_concat + let x = "a"; //~ useless_concat + let x = "1"; //~ useless_concat + println!("b: {}", "a"); //~ useless_concat + // Should not lint. + let x = concat!("a", "b"); + let local_i32 = 1; + my_concat!("{}", local_i32); + let x = concat!(file!(), "#L", line!()); + + external! { concat!(); } + with_span! { + span + concat!(); + } +} diff --git a/tests/ui/useless_concat.rs b/tests/ui/useless_concat.rs new file mode 100644 index 0000000000000..338d20a48ae96 --- /dev/null +++ b/tests/ui/useless_concat.rs @@ -0,0 +1,41 @@ +//@aux-build:proc_macros.rs + +#![warn(clippy::useless_concat)] +#![allow(clippy::print_literal)] + +extern crate proc_macros; +use proc_macros::{external, with_span}; + +macro_rules! my_concat { + ($fmt:literal $(, $e:expr)*) => { + println!(concat!("ERROR: ", $fmt), $($e,)*); + } +} + +fn main() { + let x = concat!(); //~ useless_concat + let x = concat!('c'); //~ useless_concat + let x = concat!('"'); //~ useless_concat + let x = concat!(true); //~ useless_concat + let x = concat!(1f32); //~ useless_concat + let x = concat!(1.0000f32); //~ useless_concat + let x = concat!(1_f32); //~ useless_concat + let x = concat!(1_); //~ useless_concat + let x = concat!(1.0000_f32); //~ useless_concat + let x = concat!(1.0000_); //~ useless_concat + let x = concat!("a\u{1f600}\n"); //~ useless_concat + let x = concat!(r##"a"##); //~ useless_concat + let x = concat!(1); //~ useless_concat + println!("b: {}", concat!("a")); //~ useless_concat + // Should not lint. + let x = concat!("a", "b"); + let local_i32 = 1; + my_concat!("{}", local_i32); + let x = concat!(file!(), "#L", line!()); + + external! { concat!(); } + with_span! { + span + concat!(); + } +} diff --git a/tests/ui/useless_concat.stderr b/tests/ui/useless_concat.stderr new file mode 100644 index 0000000000000..43d6d9ff5799d --- /dev/null +++ b/tests/ui/useless_concat.stderr @@ -0,0 +1,89 @@ +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:16:13 + | +LL | let x = concat!(); + | ^^^^^^^^^ help: replace with: `""` + | + = note: `-D clippy::useless-concat` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::useless_concat)]` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:17:13 + | +LL | let x = concat!('c'); + | ^^^^^^^^^^^^ help: replace with: `"c"` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:18:13 + | +LL | let x = concat!('"'); + | ^^^^^^^^^^^^ help: replace with: `"\""` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:19:13 + | +LL | let x = concat!(true); + | ^^^^^^^^^^^^^ help: replace with: `"true"` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:20:13 + | +LL | let x = concat!(1f32); + | ^^^^^^^^^^^^^ help: replace with: `"1"` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:21:13 + | +LL | let x = concat!(1.0000f32); + | ^^^^^^^^^^^^^^^^^^ help: replace with: `"1.0000"` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:22:13 + | +LL | let x = concat!(1_f32); + | ^^^^^^^^^^^^^^ help: replace with: `"1"` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:23:13 + | +LL | let x = concat!(1_); + | ^^^^^^^^^^^ help: replace with: `"1"` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:24:13 + | +LL | let x = concat!(1.0000_f32); + | ^^^^^^^^^^^^^^^^^^^ help: replace with: `"1.0000"` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:25:13 + | +LL | let x = concat!(1.0000_); + | ^^^^^^^^^^^^^^^^ help: replace with: `"1.0000"` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:26:13 + | +LL | let x = concat!("a\u{1f600}\n"); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `"a😀\n"` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:27:13 + | +LL | let x = concat!(r##"a"##); + | ^^^^^^^^^^^^^^^^^ help: replace with: `"a"` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:28:13 + | +LL | let x = concat!(1); + | ^^^^^^^^^^ help: replace with: `"1"` + +error: unneeded use of `concat!` macro + --> tests/ui/useless_concat.rs:29:23 + | +LL | println!("b: {}", concat!("a")); + | ^^^^^^^^^^^^ help: replace with: `"a"` + +error: aborting due to 14 previous errors + diff --git a/tests/ui/useless_conversion.fixed b/tests/ui/useless_conversion.fixed index 489caacf21235..ad30c94f34781 100644 --- a/tests/ui/useless_conversion.fixed +++ b/tests/ui/useless_conversion.fixed @@ -427,3 +427,18 @@ mod issue11819 { } } } + +fn issue14739() { + use std::ops::Range; + + const R: Range = 2..7; + + R.into_iter().all(|_x| true); // no lint + + R.into_iter().any(|_x| true); // no lint + + R.for_each(|_x| {}); + //~^ useless_conversion + let _ = R.map(|_x| 0); + //~^ useless_conversion +} diff --git a/tests/ui/useless_conversion.rs b/tests/ui/useless_conversion.rs index 4f3a3b00ea206..505afb340009a 100644 --- a/tests/ui/useless_conversion.rs +++ b/tests/ui/useless_conversion.rs @@ -427,3 +427,18 @@ mod issue11819 { } } } + +fn issue14739() { + use std::ops::Range; + + const R: Range = 2..7; + + R.into_iter().all(|_x| true); // no lint + + R.into_iter().any(|_x| true); // no lint + + R.into_iter().for_each(|_x| {}); + //~^ useless_conversion + let _ = R.into_iter().map(|_x| 0); + //~^ useless_conversion +} diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr index 3cde2a786e466..3bfaf1411c2c6 100644 --- a/tests/ui/useless_conversion.stderr +++ b/tests/ui/useless_conversion.stderr @@ -377,5 +377,17 @@ LL - takes_into_iter(self.my_field.into_iter()); LL + takes_into_iter(&mut *self.my_field); | -error: aborting due to 41 previous errors +error: useless conversion to the same type: `std::ops::Range` + --> tests/ui/useless_conversion.rs:440:5 + | +LL | R.into_iter().for_each(|_x| {}); + | ^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `R` + +error: useless conversion to the same type: `std::ops::Range` + --> tests/ui/useless_conversion.rs:442:13 + | +LL | let _ = R.into_iter().map(|_x| 0); + | ^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `R` + +error: aborting due to 43 previous errors diff --git a/tests/ui/zero_sized_hashmap_values.rs b/tests/ui/zero_sized_hashmap_values.rs index 4beeef421f30e..dcbfd16843de4 100644 --- a/tests/ui/zero_sized_hashmap_values.rs +++ b/tests/ui/zero_sized_hashmap_values.rs @@ -71,6 +71,27 @@ fn test2(map: HashMap, key: &str) -> HashMap { todo!(); } +fn issue14822() { + trait Trait { + type T; + } + struct S(T::T); + + // The `delay_bug` happens when evaluating the pointer metadata of `S` which depends on + // whether `T::T` is `Sized`. Since the type alias doesn't have a trait bound of `T: Trait` + // evaluating `T::T: Sized` ultimately fails with `NoSolution`. + type A = HashMap>; + type B = HashMap>; + + enum E {} + impl Trait for E { + type T = (); + } + type C = HashMap>; + type D = HashMap>; + //~^ zero_sized_map_values +} + fn main() { let _: HashMap = HashMap::new(); //~^ zero_sized_map_values diff --git a/tests/ui/zero_sized_hashmap_values.stderr b/tests/ui/zero_sized_hashmap_values.stderr index ed8536acfe8fa..d29491fa05c76 100644 --- a/tests/ui/zero_sized_hashmap_values.stderr +++ b/tests/ui/zero_sized_hashmap_values.stderr @@ -81,7 +81,15 @@ LL | fn test(map: HashMap, key: &str) -> HashMap { = help: consider using a set instead error: map with zero-sized value type - --> tests/ui/zero_sized_hashmap_values.rs:75:34 + --> tests/ui/zero_sized_hashmap_values.rs:91:14 + | +LL | type D = HashMap>; + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider using a set instead + +error: map with zero-sized value type + --> tests/ui/zero_sized_hashmap_values.rs:96:34 | LL | let _: HashMap = HashMap::new(); | ^^^^^^^ @@ -89,7 +97,7 @@ LL | let _: HashMap = HashMap::new(); = help: consider using a set instead error: map with zero-sized value type - --> tests/ui/zero_sized_hashmap_values.rs:75:12 + --> tests/ui/zero_sized_hashmap_values.rs:96:12 | LL | let _: HashMap = HashMap::new(); | ^^^^^^^^^^^^^^^^^^^ @@ -97,12 +105,12 @@ LL | let _: HashMap = HashMap::new(); = help: consider using a set instead error: map with zero-sized value type - --> tests/ui/zero_sized_hashmap_values.rs:81:12 + --> tests/ui/zero_sized_hashmap_values.rs:102:12 | LL | let _: HashMap<_, _> = std::iter::empty::<(String, ())>().collect(); | ^^^^^^^^^^^^^ | = help: consider using a set instead -error: aborting due to 13 previous errors +error: aborting due to 14 previous errors diff --git a/triagebot.toml b/triagebot.toml index eb2f9f9dd61f5..389f22c6a2ca3 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1,7 +1,7 @@ [relabel] allow-unauthenticated = [ "A-*", "C-*", "E-*", "I-*", "L-*", "P-*", "S-*", "T-*", - "good-first-issue", "beta-nominated" + "good first issue", "beta-nominated" ] # Allows shortcuts like `@rustbot ready` From 0e203f3914bf893253da7755f1fbae39d8c69915 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Wed, 21 May 2025 15:20:26 +0200 Subject: [PATCH 2562/4206] Update Cargo.lock --- Cargo.lock | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 99cb71cd0ac87..57157b32b9782 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -582,13 +582,11 @@ dependencies = [ name = "clippy_dev" version = "0.0.1" dependencies = [ - "aho-corasick", "chrono", "clap", "indoc", "itertools", "opener", - "shell-escape", "walkdir", ] @@ -4888,12 +4886,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "shell-escape" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" - [[package]] name = "shlex" version = "1.3.0" From d8a22a281cc20dc58f1da62be02048622392da05 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 21 May 2025 14:21:33 +0200 Subject: [PATCH 2563/4206] limit impls of `VaArgSafe` to just types that are actually safe 8 and 16-bit integers are subject to upcasting in C, and hence are not reliably safe. users should perform their own casting and deal with the consequences --- library/core/src/ffi/mod.rs | 2 +- library/core/src/ffi/va_list.rs | 70 ++++++++++++------- library/std/src/ffi/mod.rs | 2 +- .../c-link-to-rust-va-list-fn/checkrust.rs | 12 ++-- 4 files changed, 52 insertions(+), 34 deletions(-) diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index 288d0df0d05bb..0bc98e2ea8645 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -28,7 +28,7 @@ pub mod c_str; issue = "44930", reason = "the `c_variadic` feature has not been properly tested on all supported platforms" )] -pub use self::va_list::{VaList, VaListImpl}; +pub use self::va_list::{VaArgSafe, VaList, VaListImpl}; #[unstable( feature = "c_variadic", diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs index 1ad8038cbf6eb..f12bd289f27aa 100644 --- a/library/core/src/ffi/va_list.rs +++ b/library/core/src/ffi/va_list.rs @@ -223,39 +223,57 @@ impl<'a, 'f: 'a> DerefMut for VaList<'a, 'f> { } } -// The VaArgSafe trait needs to be used in public interfaces, however, the trait -// itself must not be allowed to be used outside this module. Allowing users to -// implement the trait for a new type (thereby allowing the va_arg intrinsic to -// be used on a new type) is likely to cause undefined behavior. -// -// FIXME(dlrobertson): In order to use the VaArgSafe trait in a public interface -// but also ensure it cannot be used elsewhere, the trait needs to be public -// within a private module. Once RFC 2145 has been implemented look into -// improving this. -mod sealed_trait { - /// Trait which permits the allowed types to be used with [super::VaListImpl::arg]. - pub unsafe trait VaArgSafe {} -} +mod sealed { + pub trait Sealed {} -macro_rules! impl_va_arg_safe { - ($($t:ty),+) => { - $( - unsafe impl sealed_trait::VaArgSafe for $t {} - )+ - } + impl Sealed for i32 {} + impl Sealed for i64 {} + impl Sealed for isize {} + + impl Sealed for u32 {} + impl Sealed for u64 {} + impl Sealed for usize {} + + impl Sealed for f64 {} + + impl Sealed for *mut T {} + impl Sealed for *const T {} } -impl_va_arg_safe! {i8, i16, i32, i64, usize} -impl_va_arg_safe! {u8, u16, u32, u64, isize} -impl_va_arg_safe! {f64} +/// Trait which permits the allowed types to be used with [`VaListImpl::arg`]. +/// +/// # Safety +/// +/// This trait must only be implemented for types that C passes as varargs without implicit promotion. +/// +/// In C varargs, integers smaller than [`c_int`] and floats smaller than [`c_double`] +/// are implicitly promoted to [`c_int`] and [`c_double`] respectively. Implementing this trait for +/// types that are subject to this promotion rule is invalid. +/// +/// [`c_int`]: core::ffi::c_int +/// [`c_double`]: core::ffi::c_double +pub unsafe trait VaArgSafe: sealed::Sealed {} + +// i8 and i16 are implicitly promoted to c_int in C, and cannot implement `VaArgSafe`. +unsafe impl VaArgSafe for i32 {} +unsafe impl VaArgSafe for i64 {} +unsafe impl VaArgSafe for isize {} + +// u8 and u16 are implicitly promoted to c_int in C, and cannot implement `VaArgSafe`. +unsafe impl VaArgSafe for u32 {} +unsafe impl VaArgSafe for u64 {} +unsafe impl VaArgSafe for usize {} + +// f32 is implicitly promoted to c_double in C, and cannot implement `VaArgSafe`. +unsafe impl VaArgSafe for f64 {} -unsafe impl sealed_trait::VaArgSafe for *mut T {} -unsafe impl sealed_trait::VaArgSafe for *const T {} +unsafe impl VaArgSafe for *mut T {} +unsafe impl VaArgSafe for *const T {} impl<'f> VaListImpl<'f> { /// Advance to the next arg. #[inline] - pub unsafe fn arg(&mut self) -> T { + pub unsafe fn arg(&mut self) -> T { // SAFETY: the caller must uphold the safety contract for `va_arg`. unsafe { va_arg(self) } } @@ -317,4 +335,4 @@ unsafe fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>); /// argument `ap` points to. #[rustc_intrinsic] #[rustc_nounwind] -unsafe fn va_arg(ap: &mut VaListImpl<'_>) -> T; +unsafe fn va_arg(ap: &mut VaListImpl<'_>) -> T; diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index 567916099101b..024cb71b915d7 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -172,7 +172,7 @@ pub use core::ffi::c_void; all supported platforms", issue = "44930" )] -pub use core::ffi::{VaList, VaListImpl}; +pub use core::ffi::{VaArgSafe, VaList, VaListImpl}; #[stable(feature = "core_ffi_c", since = "1.64.0")] pub use core::ffi::{ c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, diff --git a/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs b/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs index bcaef33344e51..7e4344f1c69b2 100644 --- a/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs +++ b/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs @@ -30,9 +30,9 @@ pub unsafe extern "C" fn check_list_0(mut ap: VaList) -> usize { #[no_mangle] pub unsafe extern "C" fn check_list_1(mut ap: VaList) -> usize { continue_if!(ap.arg::() == -1); - continue_if!(ap.arg::() == 'A' as c_char); - continue_if!(ap.arg::() == '4' as c_char); - continue_if!(ap.arg::() == ';' as c_char); + continue_if!(ap.arg::() == 'A' as c_int); + continue_if!(ap.arg::() == '4' as c_int); + continue_if!(ap.arg::() == ';' as c_int); continue_if!(ap.arg::() == 0x32); continue_if!(ap.arg::() == 0x10000001); continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Valid!")); @@ -43,7 +43,7 @@ pub unsafe extern "C" fn check_list_1(mut ap: VaList) -> usize { pub unsafe extern "C" fn check_list_2(mut ap: VaList) -> usize { continue_if!(ap.arg::().floor() == 3.14f64.floor()); continue_if!(ap.arg::() == 12); - continue_if!(ap.arg::() == 'a' as c_char); + continue_if!(ap.arg::() == 'a' as c_int); continue_if!(ap.arg::().floor() == 6.18f64.floor()); continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Hello")); continue_if!(ap.arg::() == 42); @@ -55,7 +55,7 @@ pub unsafe extern "C" fn check_list_2(mut ap: VaList) -> usize { pub unsafe extern "C" fn check_list_copy_0(mut ap: VaList) -> usize { continue_if!(ap.arg::().floor() == 6.28f64.floor()); continue_if!(ap.arg::() == 16); - continue_if!(ap.arg::() == 'A' as c_char); + continue_if!(ap.arg::() == 'A' as c_int); continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Skip Me!")); ap.with_copy( |mut ap| { @@ -75,7 +75,7 @@ pub unsafe extern "C" fn check_varargs_0(_: c_int, mut ap: ...) -> usize { pub unsafe extern "C" fn check_varargs_1(_: c_int, mut ap: ...) -> usize { continue_if!(ap.arg::().floor() == 3.14f64.floor()); continue_if!(ap.arg::() == 12); - continue_if!(ap.arg::() == 'A' as c_char); + continue_if!(ap.arg::() == 'A' as c_int); continue_if!(ap.arg::() == 1); 0 } From 5d9141c6c8640e98856fbe703b9f73204d85ba43 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 21 May 2025 13:54:19 +0000 Subject: [PATCH 2564/4206] fix better_any breakage by making the solver more unsound --- .../src/solve/trait_goals.rs | 44 ++++++++++++++++++- .../assembly/better_any-backcompat.rs | 33 ++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 tests/ui/traits/next-solver/assembly/better_any-backcompat.rs diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 966d5422fbb7b..7c4e1dc2c12e3 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -9,7 +9,7 @@ use rustc_type_ir::{ self as ty, Interner, Movability, TraitPredicate, TypeVisitableExt as _, TypingMode, Upcast as _, elaborate, }; -use tracing::{instrument, trace}; +use tracing::{debug, instrument, trace}; use crate::delegate::SolverDelegate; use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes}; @@ -17,7 +17,7 @@ use crate::solve::assembly::{self, AllowInferenceConstraints, AssembleCandidates use crate::solve::inspect::ProbeKind; use crate::solve::{ BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause, - NoSolution, ParamEnvSource, QueryResult, + NoSolution, ParamEnvSource, QueryResult, has_only_region_constraints, }; impl assembly::GoalKind for TraitPredicate @@ -1253,6 +1253,45 @@ where D: SolverDelegate, I: Interner, { + /// FIXME(#57893): For backwards compatability with the old trait solver implementation, + /// we need to handle overlap between builtin and user-written impls for trait objects. + /// + /// This overlap is unsound in general and something which we intend to fix separately. + /// To avoid blocking the stabilization of the trait solver, we add this hack to avoid + /// breakage in cases which are *mostly fine*™. Importantly, this preference is strictly + /// weaker than the old behavior. + /// + /// We only prefer builtin over user-written impls if there are no inference constraints. + /// Importantly, we also only prefer the builtin impls for trait goals, and not during + /// normalization. This means the only case where this special-case results in exploitable + /// unsoundness should be lifetime dependent user-written impls. + pub(super) fn unsound_prefer_builtin_dyn_impl(&mut self, candidates: &mut Vec>) { + match self.typing_mode() { + TypingMode::Coherence => return, + TypingMode::Analysis { .. } + | TypingMode::Borrowck { .. } + | TypingMode::PostBorrowckAnalysis { .. } + | TypingMode::PostAnalysis => {} + } + + if candidates + .iter() + .find(|c| { + matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Object(_))) + }) + .is_some_and(|c| has_only_region_constraints(c.result)) + { + candidates.retain(|c| { + if matches!(c.source, CandidateSource::Impl(_)) { + debug!(?c, "unsoundly dropping impl in favor of builtin dyn-candidate"); + false + } else { + true + } + }); + } + } + #[instrument(level = "debug", skip(self), ret)] pub(super) fn merge_trait_candidates( &mut self, @@ -1313,6 +1352,7 @@ where } self.filter_specialized_impls(AllowInferenceConstraints::No, &mut candidates); + self.unsound_prefer_builtin_dyn_impl(&mut candidates); // If there are *only* global where bounds, then make sure to return that this // is still reported as being proven-via the param-env so that rigid projections diff --git a/tests/ui/traits/next-solver/assembly/better_any-backcompat.rs b/tests/ui/traits/next-solver/assembly/better_any-backcompat.rs new file mode 100644 index 0000000000000..8b153833e3a7a --- /dev/null +++ b/tests/ui/traits/next-solver/assembly/better_any-backcompat.rs @@ -0,0 +1,33 @@ +//@ check-pass +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) + +// A regression test for trait-system-refactor-initiative#183. While +// this concrete instance is likely not practically unsound, the general +// pattern is, see #57893. + +use std::any::TypeId; + +unsafe trait TidAble<'a>: Tid<'a> {} +trait TidExt<'a>: Tid<'a> { + fn downcast_box(self: Box) { + loop {} + } +} + +impl<'a, X: ?Sized + Tid<'a>> TidExt<'a> for X {} + +unsafe trait Tid<'a>: 'a {} + +unsafe impl<'a, T: ?Sized + TidAble<'a>> Tid<'a> for T {} + +impl<'a> dyn Tid<'a> + 'a { + fn downcast_any_box(self: Box) { + self.downcast_box(); + } +} + +unsafe impl<'a> TidAble<'a> for dyn Tid<'a> + 'a {} + +fn main() {} From 3ab6af049bb84a6e107851ecf333512b0d4562eb Mon Sep 17 00:00:00 2001 From: beetrees Date: Wed, 21 May 2025 15:59:52 +0200 Subject: [PATCH 2565/4206] Use Cranelift bitcast instead of store & load to bitcast between vectors and non-vectors (#1580) --- src/abi/mod.rs | 5 +---- src/value_and_place.rs | 22 +--------------------- 2 files changed, 2 insertions(+), 25 deletions(-) diff --git a/src/abi/mod.rs b/src/abi/mod.rs index 7324856bce4a7..70d29596e22cb 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -154,10 +154,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { let ret = self.lib_call_unadjusted(name, params, returns, &args)[0]; - // FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128 - let ret_ptr = self.create_stack_slot(16, 16); - ret_ptr.store(self, ret, MemFlags::trusted()); - Cow::Owned(vec![ret_ptr.load(self, types::I128, MemFlags::trusted())]) + Cow::Owned(vec![codegen_bitcast(self, types::I128, ret)]) } else if ret_single_i128 && self.tcx.sess.target.arch == "s390x" { // Return i128 using a return area pointer on s390x. let mut params = params; diff --git a/src/value_and_place.rs b/src/value_and_place.rs index 5ec970b493b5b..0938c990514c2 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -564,27 +564,7 @@ impl<'tcx> CPlace<'tcx> { src_ty, dst_ty, ); - let data = match (src_ty, dst_ty) { - (_, _) if src_ty == dst_ty => data, - - // This is a `write_cvalue_transmute`. - (types::I32, types::F32) - | (types::F32, types::I32) - | (types::I64, types::F64) - | (types::F64, types::I64) => codegen_bitcast(fx, dst_ty, data), - _ if src_ty.is_vector() && dst_ty.is_vector() => codegen_bitcast(fx, dst_ty, data), - _ if src_ty.is_vector() || dst_ty.is_vector() => { - // FIXME(bytecodealliance/wasmtime#6104) do something more efficient for transmutes between vectors and integers. - let ptr = fx.create_stack_slot(src_ty.bytes(), src_ty.bytes()); - ptr.store(fx, data, MemFlags::trusted()); - ptr.load(fx, dst_ty, MemFlags::trusted()) - } - - // `CValue`s should never contain SSA-only types, so if you ended - // up here having seen an error like `B1 -> I8`, then before - // calling `write_cvalue` you need to add a `bint` instruction. - _ => unreachable!("write_cvalue_transmute: {:?} -> {:?}", src_ty, dst_ty), - }; + let data = if src_ty == dst_ty { data } else { codegen_bitcast(fx, dst_ty, data) }; //fx.bcx.set_val_label(data, cranelift_codegen::ir::ValueLabel::new(var.index())); fx.bcx.def_var(var, data); } From 46a5c91591a0d7a6fd8f8994810a3fc6c7ea444d Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sun, 18 May 2025 23:50:19 +0800 Subject: [PATCH 2566/4206] std: fix doctest and explain for as_slices and as_mut_slices in VecDeque Signed-off-by: xizheyin --- .../alloc/src/collections/vec_deque/mod.rs | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 712f38a76c018..08b1828ff000e 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1312,6 +1312,8 @@ impl VecDeque { /// /// If [`make_contiguous`] was previously called, all elements of the /// deque will be in the first slice and the second slice will be empty. + /// Otherwise, the exact split point depends on implementation details + /// and is not guaranteed. /// /// [`make_contiguous`]: VecDeque::make_contiguous /// @@ -1326,12 +1328,18 @@ impl VecDeque { /// deque.push_back(1); /// deque.push_back(2); /// - /// assert_eq!(deque.as_slices(), (&[0, 1, 2][..], &[][..])); + /// let expected = [0, 1, 2]; + /// let (front, back) = deque.as_slices(); + /// assert_eq!(&expected[..front.len()], front); + /// assert_eq!(&expected[front.len()..], back); /// /// deque.push_front(10); /// deque.push_front(9); /// - /// assert_eq!(deque.as_slices(), (&[9, 10][..], &[0, 1, 2][..])); + /// let expected = [9, 10, 0, 1, 2]; + /// let (front, back) = deque.as_slices(); + /// assert_eq!(&expected[..front.len()], front); + /// assert_eq!(&expected[front.len()..], back); /// ``` #[inline] #[stable(feature = "deque_extras_15", since = "1.5.0")] @@ -1347,6 +1355,8 @@ impl VecDeque { /// /// If [`make_contiguous`] was previously called, all elements of the /// deque will be in the first slice and the second slice will be empty. + /// Otherwise, the exact split point depends on implementation details + /// and is not guaranteed. /// /// [`make_contiguous`]: VecDeque::make_contiguous /// @@ -1363,9 +1373,22 @@ impl VecDeque { /// deque.push_front(10); /// deque.push_front(9); /// - /// deque.as_mut_slices().0[0] = 42; - /// deque.as_mut_slices().1[0] = 24; - /// assert_eq!(deque.as_slices(), (&[42, 10][..], &[24, 1][..])); + /// // Since the split point is not guaranteed, we may need to update + /// // either slice. + /// let mut update_nth = |index: usize, val: u32| { + /// let (front, back) = deque.as_mut_slices(); + /// if index > front.len() - 1 { + /// back[index - front.len()] = val; + /// } else { + /// front[index] = val; + /// } + /// }; + /// + /// update_nth(0, 42); + /// update_nth(2, 24); + /// + /// let v: Vec<_> = deque.into(); + /// assert_eq!(v, [42, 10, 24, 1]); /// ``` #[inline] #[stable(feature = "deque_extras_15", since = "1.5.0")] From 96ac5714455dfba4f3e090d4b2545cc00d96a097 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 19 Feb 2025 10:22:17 +0000 Subject: [PATCH 2567/4206] Move -Zcrate-attr injection to just after crate root parsing This way after_crate_root_parsing and -Zpretty will see them. --- compiler/rustc_interface/src/passes.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 8f6c5b47ee23d..75d92ae7a2ed6 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -45,7 +45,7 @@ use crate::interface::Compiler; use crate::{errors, limits, proc_macro_decls, util}; pub fn parse<'a>(sess: &'a Session) -> ast::Crate { - let krate = sess + let mut krate = sess .time("parse_crate", || { let mut parser = unwrap_or_emit_fatal(match &sess.io.input { Input::File(file) => new_parser_from_file(&sess.psess, file, None), @@ -64,6 +64,12 @@ pub fn parse<'a>(sess: &'a Session) -> ast::Crate { input_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS", "ast-stats-1"); } + rustc_builtin_macros::cmdline_attrs::inject( + &mut krate, + &sess.psess, + &sess.opts.unstable_opts.crate_attr, + ); + krate } @@ -805,17 +811,11 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| { pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( compiler: &Compiler, - mut krate: rustc_ast::Crate, + krate: rustc_ast::Crate, f: F, ) -> T { let sess = &compiler.sess; - rustc_builtin_macros::cmdline_attrs::inject( - &mut krate, - &sess.psess, - &sess.opts.unstable_opts.crate_attr, - ); - let pre_configured_attrs = rustc_expand::config::pre_configure_attrs(sess, &krate.attrs); let crate_name = get_crate_name(sess, &pre_configured_attrs); From 226db317b1fcf13fc2cebea92855a30ff7877f32 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 21 May 2025 18:31:14 +0300 Subject: [PATCH 2568/4206] Correctly set the span of the proc_macro crate's Group delimiters Previously only the open delimiter's span was set, and this caused... weird problems. --- .../src/server_impl/rust_analyzer_span.rs | 4 +++- .../crates/proc-macro-srv/src/server_impl/token_id.rs | 3 ++- .../proc-macro-srv/src/server_impl/token_stream.rs | 11 +++++++++-- .../crates/proc-macro-srv/src/tests/mod.rs | 2 +- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index 64b40e7b94372..e0c6e68f80379 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -258,7 +258,9 @@ impl server::TokenStream for RaSpanServer { &mut self, stream: Self::TokenStream, ) -> Vec> { - stream.into_bridge() + stream.into_bridge(&mut |first, second| { + server::Span::join(self, first, second).unwrap_or(first) + }) } } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs index 24a67bf45c8d6..d55b269f868db 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs @@ -238,7 +238,8 @@ impl server::TokenStream for TokenIdServer { &mut self, stream: Self::TokenStream, ) -> Vec> { - stream.into_bridge() + // Can't join with `TokenId`. + stream.into_bridge(&mut |first, _second| first) } } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_stream.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_stream.rs index 072557913c2b0..c5019a5917221 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_stream.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_stream.rs @@ -56,7 +56,10 @@ impl TokenStream { self.token_trees.is_empty() } - pub(crate) fn into_bridge(self) -> Vec> { + pub(crate) fn into_bridge( + self, + join_spans: &mut dyn FnMut(S, S) -> S, + ) -> Vec> { let mut result = Vec::new(); let mut iter = self.token_trees.into_iter(); while let Some(tree) = iter.next() { @@ -98,7 +101,11 @@ impl TokenStream { token_trees: iter.by_ref().take(subtree.usize_len()).collect(), }) }, - span: bridge::DelimSpan::from_single(subtree.delimiter.open), + span: bridge::DelimSpan { + open: subtree.delimiter.open, + close: subtree.delimiter.close, + entire: join_spans(subtree.delimiter.open, subtree.delimiter.close), + }, })) } } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs index 3868fee40fba2..3a6ce639d135f 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs @@ -144,7 +144,7 @@ fn test_fn_like_macro_clone_ident_subtree() { SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 IDENT ident 42:2@0..5#ROOT2024 PUNCH , [alone] 42:2@5..6#ROOT2024 - SUBTREE [] 42:2@7..8#ROOT2024 42:2@7..8#ROOT2024"#]], + SUBTREE [] 42:2@7..9#ROOT2024 42:2@7..9#ROOT2024"#]], ); } From 2a403dc81d092ed42edfed48b94ba34c33028ae3 Mon Sep 17 00:00:00 2001 From: dianne Date: Wed, 21 May 2025 09:17:11 -0700 Subject: [PATCH 2569/4206] lower bodies' params to thir before the body's value --- compiler/rustc_mir_build/src/thir/cx/mod.rs | 3 ++- ...ociated-const-type-parameter-pattern.stderr | 18 +++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 2f593b9a0a741..8c817605847aa 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -27,8 +27,8 @@ pub(crate) fn thir_body( if let Some(reported) = cx.typeck_results.tainted_by_errors { return Err(reported); } - let expr = cx.mirror_expr(body.value); + // Lower the params before the body's expression so errors from params are shown first. let owner_id = tcx.local_def_id_to_hir_id(owner_def); if let Some(fn_decl) = tcx.hir_fn_decl_by_hir_id(owner_id) { let closure_env_param = cx.closure_env_param(owner_def, owner_id); @@ -48,6 +48,7 @@ pub(crate) fn thir_body( } } + let expr = cx.mirror_expr(body.value); Ok((tcx.alloc_steal_thir(cx.thir), expr)) } diff --git a/tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr b/tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr index a8256f775a68c..19b63a041d616 100644 --- a/tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr +++ b/tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr @@ -27,7 +27,7 @@ LL | B::X => println!("B::X"), | ^^^^ `const` depends on a generic parameter error[E0158]: constant pattern cannot depend on generic parameters - --> $DIR/associated-const-type-parameter-pattern.rs:30:9 + --> $DIR/associated-const-type-parameter-pattern.rs:28:48 | LL | pub trait Foo { | ------------- @@ -35,13 +35,12 @@ LL | const X: EFoo; | ------------- constant defined here ... LL | pub fn test_let_pat(arg: EFoo, A::X: EFoo) { - | - constant depends on this generic parameter -LL | -LL | let A::X = arg; - | ^^^^ `const` depends on a generic parameter + | - ^^^^ `const` depends on a generic parameter + | | + | constant depends on this generic parameter error[E0158]: constant pattern cannot depend on generic parameters - --> $DIR/associated-const-type-parameter-pattern.rs:28:48 + --> $DIR/associated-const-type-parameter-pattern.rs:30:9 | LL | pub trait Foo { | ------------- @@ -49,9 +48,10 @@ LL | const X: EFoo; | ------------- constant defined here ... LL | pub fn test_let_pat(arg: EFoo, A::X: EFoo) { - | - ^^^^ `const` depends on a generic parameter - | | - | constant depends on this generic parameter + | - constant depends on this generic parameter +LL | +LL | let A::X = arg; + | ^^^^ `const` depends on a generic parameter error: aborting due to 4 previous errors From f2d94c1d9372742fd1668c3887840ad0833390b5 Mon Sep 17 00:00:00 2001 From: dianne Date: Sat, 17 May 2025 23:43:28 -0700 Subject: [PATCH 2570/4206] `unpretty=thir-tree`: don't require the final expr to be the entrypoint --- compiler/rustc_mir_build/src/builder/mod.rs | 4 ---- compiler/rustc_mir_build/src/thir/print.rs | 9 ++++----- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 9cf051a8760be..762560def2392 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -451,10 +451,6 @@ fn construct_fn<'tcx>( let span = tcx.def_span(fn_def); let fn_id = tcx.local_def_id_to_hir_id(fn_def); - // The representation of thir for `-Zunpretty=thir-tree` relies on - // the entry expression being the last element of `thir.exprs`. - assert_eq!(expr.as_usize(), thir.exprs.len() - 1); - // Figure out what primary body this item has. let body = tcx.hir_body_owned_by(fn_def); let span_with_body = tcx.hir_span_with_body(fn_id); diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 37248941e2c45..db9547a481fb4 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -8,10 +8,10 @@ use rustc_span::def_id::LocalDefId; /// Create a THIR tree for debugging. pub fn thir_tree(tcx: TyCtxt<'_>, owner_def: LocalDefId) -> String { match super::cx::thir_body(tcx, owner_def) { - Ok((thir, _)) => { + Ok((thir, expr)) => { let thir = thir.steal(); let mut printer = ThirPrinter::new(&thir); - printer.print(); + printer.print(expr); printer.into_buffer() } Err(_) => "error".into(), @@ -58,7 +58,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { } } - fn print(&mut self) { + fn print(&mut self, body_expr: ExprId) { print_indented!(self, "params: [", 0); for param in self.thir.params.iter() { self.print_param(param, 1); @@ -66,8 +66,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, "]", 0); print_indented!(self, "body:", 0); - let expr = ExprId::from_usize(self.thir.exprs.len() - 1); - self.print_expr(expr, 1); + self.print_expr(body_expr, 1); } fn into_buffer(self) -> String { From f57a64ae5af9907d108532ff437dc05020445397 Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Wed, 21 May 2025 18:50:01 +0200 Subject: [PATCH 2571/4206] ci: improve citool job db errors --- src/ci/citool/src/jobs.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/ci/citool/src/jobs.rs b/src/ci/citool/src/jobs.rs index 5600d7b4db59b..60cbf50c7a3a1 100644 --- a/src/ci/citool/src/jobs.rs +++ b/src/ci/citool/src/jobs.rs @@ -85,14 +85,20 @@ impl JobDatabase { } pub fn load_job_db(db: &str) -> anyhow::Result { - let mut db: Value = serde_yaml::from_str(db)?; + let mut db: Value = serde_yaml::from_str(db).context("failed to parse YAML content")?; // We need to expand merge keys (<<), because serde_yaml can't deal with them // `apply_merge` only applies the merge once, so do it a few times to unwrap nested merges. - db.apply_merge()?; - db.apply_merge()?; - let db: JobDatabase = serde_yaml::from_value(db)?; + let apply_merge = |db: &mut Value| -> anyhow::Result<()> { + db.apply_merge().context("failed to apply merge keys") + }; + + // Apply merge twice to handle nested merges + apply_merge(&mut db)?; + apply_merge(&mut db)?; + + let db: JobDatabase = serde_yaml::from_value(db).context("failed to parse job database")?; Ok(db) } From f1ad1cd799e025a260e9f50d775c8ac3a74a7855 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Wed, 21 May 2025 12:22:59 +0200 Subject: [PATCH 2572/4206] Support different lintcheck CARGO_TARGET_DIR --- lintcheck/src/input.rs | 21 ++++++++++++--------- lintcheck/src/main.rs | 20 ++++++++++++++------ 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/lintcheck/src/input.rs b/lintcheck/src/input.rs index 83eb0a577d6b9..408a2e087af28 100644 --- a/lintcheck/src/input.rs +++ b/lintcheck/src/input.rs @@ -8,7 +8,7 @@ use std::time::Duration; use serde::Deserialize; use walkdir::{DirEntry, WalkDir}; -use crate::{Crate, LINTCHECK_DOWNLOADS, LINTCHECK_SOURCES}; +use crate::{Crate, lintcheck_sources, target_dir}; const DEFAULT_DOCS_LINK: &str = "https://docs.rs/%7Bkrate%7D/%7Bversion%7D/src/%7Bkrate_%7D/%7Bfile%7D.html#{line}"; const DEFAULT_GITHUB_LINK: &str = "{url}/blob/{hash}/src/{file}#L{line}"; @@ -201,8 +201,10 @@ impl CrateWithSource { let file_link = &self.file_link; match &self.source { CrateSource::CratesIo { version } => { - let extract_dir = PathBuf::from(LINTCHECK_SOURCES); - let krate_download_dir = PathBuf::from(LINTCHECK_DOWNLOADS); + let extract_dir = PathBuf::from(lintcheck_sources()); + // Keep constant downloads path to avoid repeating work and + // filling up disk space unnecessarily. + let krate_download_dir = PathBuf::from("target/lintcheck/downloads/"); // url to download the crate from crates.io let url = format!("https://crates.io/api/v1/crates/%7Bname%7D/%7Bversion%7D/download"); @@ -211,7 +213,7 @@ impl CrateWithSource { let krate_file_path = krate_download_dir.join(format!("{name}-{version}.crate.tar.gz")); // don't download/extract if we already have done so - if !krate_file_path.is_file() { + if !krate_file_path.is_file() || !extract_dir.join(format!("{name}-{version}")).exists() { // create a file path to download and write the crate data into let mut krate_dest = fs::File::create(&krate_file_path).unwrap(); let mut krate_req = get(&url).unwrap().into_reader(); @@ -236,7 +238,7 @@ impl CrateWithSource { }, CrateSource::Git { url, commit } => { let repo_path = { - let mut repo_path = PathBuf::from(LINTCHECK_SOURCES); + let mut repo_path = PathBuf::from(lintcheck_sources()); // add a -git suffix in case we have the same crate from crates.io and a git repo repo_path.push(format!("{name}-git")); repo_path @@ -286,7 +288,7 @@ impl CrateWithSource { // copy path into the dest_crate_root but skip directories that contain a CACHEDIR.TAG file. // The target/ directory contains a CACHEDIR.TAG file so it is the most commonly skipped directory // as a result of this filter. - let dest_crate_root = PathBuf::from(LINTCHECK_SOURCES).join(name); + let dest_crate_root = PathBuf::from(lintcheck_sources()).join(name); if dest_crate_root.exists() { println!("Deleting existing directory at `{}`", dest_crate_root.display()); fs::remove_dir_all(&dest_crate_root).unwrap(); @@ -326,15 +328,16 @@ impl CrateWithSource { /// /// This function panics if creating one of the dirs fails. fn create_dirs(krate_download_dir: &Path, extract_dir: &Path) { - fs::create_dir("target/lintcheck/").unwrap_or_else(|err| { + fs::create_dir(format!("{}/lintcheck/", target_dir())).unwrap_or_else(|err| { assert_eq!( err.kind(), ErrorKind::AlreadyExists, "cannot create lintcheck target dir" ); }); - fs::create_dir(krate_download_dir).unwrap_or_else(|err| { - assert_eq!(err.kind(), ErrorKind::AlreadyExists, "cannot create crate download dir"); + fs::create_dir_all(krate_download_dir).unwrap_or_else(|err| { + // We are allowed to reuse download dirs + assert_ne!(err.kind(), ErrorKind::AlreadyExists); }); fs::create_dir(extract_dir).unwrap_or_else(|err| { assert_eq!( diff --git a/lintcheck/src/main.rs b/lintcheck/src/main.rs index d4bf6cd48a152..8418383143280 100644 --- a/lintcheck/src/main.rs +++ b/lintcheck/src/main.rs @@ -43,8 +43,14 @@ use input::read_crates; use output::{ClippyCheckOutput, ClippyWarning, RustcIce}; use rayon::prelude::*; -const LINTCHECK_DOWNLOADS: &str = "target/lintcheck/downloads"; -const LINTCHECK_SOURCES: &str = "target/lintcheck/sources"; +#[must_use] +pub fn target_dir() -> String { + env::var("CARGO_TARGET_DIR").unwrap_or("target".to_owned()) +} + +fn lintcheck_sources() -> String { + format!("{}/lintcheck/sources", target_dir()) +} /// Represents the actual source code of a crate that we ran "cargo clippy" on #[derive(Debug)] @@ -307,7 +313,8 @@ fn main() { fn lintcheck(config: LintcheckConfig) { let clippy_ver = build_clippy(config.perf); let clippy_driver_path = fs::canonicalize(format!( - "target/{}/clippy-driver{EXE_SUFFIX}", + "{}/{}/clippy-driver{EXE_SUFFIX}", + target_dir(), if config.perf { "release" } else { "debug" } )) .unwrap(); @@ -315,7 +322,8 @@ fn lintcheck(config: LintcheckConfig) { // assert that clippy is found assert!( clippy_driver_path.is_file(), - "target/{}/clippy-driver binary not found! {}", + "{}/{}/clippy-driver binary not found! {}", + target_dir(), if config.perf { "release" } else { "debug" }, clippy_driver_path.display() ); @@ -386,7 +394,7 @@ fn lintcheck(config: LintcheckConfig) { .unwrap(); let server = config.recursive.then(|| { - let _: io::Result<()> = fs::remove_dir_all("target/lintcheck/shared_target_dir/recursive"); + let _: io::Result<()> = fs::remove_dir_all(format!("{}/lintcheck/shared_target_dir/recursive", target_dir())); LintcheckServer::spawn(recursive_options) }); @@ -488,7 +496,7 @@ fn clippy_project_root() -> &'static Path { #[must_use] fn shared_target_dir(qualifier: &str) -> PathBuf { clippy_project_root() - .join("target/lintcheck/shared_target_dir") + .join(format!("{}/lintcheck/shared_target_dir", target_dir())) .join(qualifier) } From 11c15229557cb489a5604f13e26a51099cc05314 Mon Sep 17 00:00:00 2001 From: beetrees Date: Wed, 21 May 2025 18:11:11 +0100 Subject: [PATCH 2573/4206] Enable `__powitf2` on MSVC --- library/compiler-builtins/builtins-test/tests/float_pow.rs | 2 -- library/compiler-builtins/compiler-builtins/src/float/pow.rs | 2 -- 2 files changed, 4 deletions(-) diff --git a/library/compiler-builtins/builtins-test/tests/float_pow.rs b/library/compiler-builtins/builtins-test/tests/float_pow.rs index 8209543e666a0..0e8ae88e83eff 100644 --- a/library/compiler-builtins/builtins-test/tests/float_pow.rs +++ b/library/compiler-builtins/builtins-test/tests/float_pow.rs @@ -58,8 +58,6 @@ pow! { } #[cfg(f128_enabled)] -// FIXME(f16_f128): MSVC cannot build these until `__divtf3` is available in nightly. -#[cfg(not(target_env = "msvc"))] #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] pow! { f128, 1e-36, __powitf2, not(feature = "no-sys-f128"); diff --git a/library/compiler-builtins/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/compiler-builtins/src/float/pow.rs index 45a4ad9049de4..6997a9c213c59 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/pow.rs @@ -32,8 +32,6 @@ intrinsics! { #[ppc_alias = __powikf2] #[cfg(f128_enabled)] - // FIXME(f16_f128): MSVC cannot build these until `__divtf3` is available in nightly. - #[cfg(not(target_env = "msvc"))] pub extern "C" fn __powitf2(a: f128, b: i32) -> f128 { pow(a, b) } From 8acb1b5f0b3955f114677ee1725d39024202f16b Mon Sep 17 00:00:00 2001 From: David Barsky Date: Wed, 21 May 2025 09:47:29 -0400 Subject: [PATCH 2574/4206] internal: fix `integrated_benchmarks` to make actual edits --- .../src/integrated_benchmarks.rs | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs index 49ebffa909acd..84b7888258f87 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs @@ -147,7 +147,7 @@ fn integrated_completion_benchmark() { let _it = stdx::timeit("change"); let mut text = host.analysis().file_text(file_id).unwrap().to_string(); let completion_offset = - patch(&mut text, "db.struct_data(self.id)", "sel;\ndb.struct_data(self.id)") + patch(&mut text, "db.struct_signature(self.id)", "sel;\ndb.struct_signature(self.id)") + "sel".len(); let mut change = ChangeWithProcMacros::default(); change.change_file(file_id, Some(text)); @@ -197,9 +197,11 @@ fn integrated_completion_benchmark() { let completion_offset = { let _it = stdx::timeit("change"); let mut text = host.analysis().file_text(file_id).unwrap().to_string(); - let completion_offset = - patch(&mut text, "sel;\ndb.struct_data(self.id)", ";sel;\ndb.struct_data(self.id)") - + ";sel".len(); + let completion_offset = patch( + &mut text, + "sel;\ndb.struct_signature(self.id)", + ";sel;\ndb.struct_signature(self.id)", + ) + ";sel".len(); let mut change = ChangeWithProcMacros::default(); change.change_file(file_id, Some(text)); host.apply_change(change); @@ -247,9 +249,11 @@ fn integrated_completion_benchmark() { let completion_offset = { let _it = stdx::timeit("change"); let mut text = host.analysis().file_text(file_id).unwrap().to_string(); - let completion_offset = - patch(&mut text, "sel;\ndb.struct_data(self.id)", "self.;\ndb.struct_data(self.id)") - + "self.".len(); + let completion_offset = patch( + &mut text, + "sel;\ndb.struct_signature(self.id)", + "self.;\ndb.struct_signature(self.id)", + ) + "self.".len(); let mut change = ChangeWithProcMacros::default(); change.change_file(file_id, Some(text)); host.apply_change(change); @@ -366,7 +370,7 @@ fn integrated_diagnostics_benchmark() { { let _it = stdx::timeit("change"); let mut text = host.analysis().file_text(file_id).unwrap().to_string(); - patch(&mut text, "db.struct_data(self.id)", "();\ndb.struct_data(self.id)"); + patch(&mut text, "db.struct_signature(self.id)", "();\ndb.struct_signature(self.id)"); let mut change = ChangeWithProcMacros::default(); change.change_file(file_id, Some(text)); host.apply_change(change); From 5dfcb12a208205039000dc222b79014f226278b2 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Tue, 22 Apr 2025 21:43:01 +0200 Subject: [PATCH 2575/4206] Implement FreeBSD syscall cpuset_getaffinity. --- src/tools/miri/ci/ci.sh | 4 +- .../src/shims/unix/freebsd/foreign_items.rs | 64 +++++++++++++++++++ .../pass-dep/shims/freebsd-cpuset-affinity.rs | 51 +++++++++++++++ 3 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 src/tools/miri/tests/pass-dep/shims/freebsd-cpuset-affinity.rs diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 00102bb26778f..3a9e55f5738d2 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -165,8 +165,8 @@ case $HOST_TARGET in # Partially supported targets (tier 2) BASIC="empty_main integer heap_alloc libc-mem vec string btreemap" # ensures we have the basics: pre-main code, system allocator UNIX="hello panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there - TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency fs libc-pipe - TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency fs libc-pipe + TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency fs libc-pipe affinity + TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency fs libc-pipe affinity TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency epoll eventfd TEST_TARGET=wasm32-wasip2 run_tests_minimal $BASIC wasm TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index c0872daee8d64..533a741fea3f2 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -56,6 +56,70 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } + "cpuset_getaffinity" => { + // The "same" kind of api as `sched_getaffinity` but more fine grained control for FreeBSD specifically. + let [level, which, id, set_size, mask] = + this.check_shim(abi, Conv::C, link_name, args)?; + + let level = this.read_scalar(level)?.to_i32()?; + let which = this.read_scalar(which)?.to_i32()?; + let id = this.read_scalar(id)?.to_i64()?; + let set_size = this.read_target_usize(set_size)?; // measured in bytes + let mask = this.read_pointer(mask)?; + + let _level_root = this.eval_libc_i32("CPU_LEVEL_ROOT"); + let _level_cpuset = this.eval_libc_i32("CPU_LEVEL_CPUSET"); + let level_which = this.eval_libc_i32("CPU_LEVEL_WHICH"); + + let _which_tid = this.eval_libc_i32("CPU_WHICH_TID"); + let which_pid = this.eval_libc_i32("CPU_WHICH_PID"); + let _which_jail = this.eval_libc_i32("CPU_WHICH_JAIL"); + let _which_cpuset = this.eval_libc_i32("CPU_WHICH_CPUSET"); + let _which_irq = this.eval_libc_i32("CPU_WHICH_IRQ"); + + // For sched_getaffinity, the current process is identified by -1. + // TODO: Use gettid? I'm (LorrensP-2158466) not that familiar with this api . + let id = match id { + -1 => this.active_thread(), + _ => + throw_unsup_format!( + "`cpuset_getaffinity` is only supported with a pid of -1 (indicating the current thread)" + ), + }; + + if this.ptr_is_null(mask)? { + this.set_last_error_and_return(LibcError("EFAULT"), dest)?; + } + // We only support CPU_LEVEL_WHICH and CPU_WHICH_PID for now. + // This is the bare minimum to make the tests pass. + else if level != level_which || which != which_pid { + throw_unsup_format!( + "`cpuset_getaffinity` is only supported with `level` set to CPU_LEVEL_WHICH and `which` set to CPU_WHICH_PID." + ); + } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&id) { + // `cpusetsize` must be large enough to contain the entire CPU mask. + // FreeBSD only uses `cpusetsize` to verify that it's sufficient for the kernel's CPU mask. + // If it's too small, the syscall returns ERANGE. + // If it's large enough, copying the kernel mask to user space is safe, regardless of the actual size. + // See https://github.com/freebsd/freebsd-src/blob/909aa6781340f8c0b4ae01c6366bf1556ee2d1be/sys/kern/kern_cpuset.c#L1985 + if set_size < u64::from(this.machine.num_cpus).div_ceil(8) { + this.set_last_error_and_return(LibcError("ERANGE"), dest)?; + } else { + let cpuset = cpuset.clone(); + let byte_count = + Ord::min(cpuset.as_slice().len(), set_size.try_into().unwrap()); + this.write_bytes_ptr( + mask, + cpuset.as_slice()[..byte_count].iter().copied(), + )?; + this.write_null(dest)?; + } + } else { + // `id` is always that of the active thread, so this is currently unreachable. + unreachable!(); + } + } + // Synchronization primitives "_umtx_op" => { let [obj, op, val, uaddr, uaddr2] = diff --git a/src/tools/miri/tests/pass-dep/shims/freebsd-cpuset-affinity.rs b/src/tools/miri/tests/pass-dep/shims/freebsd-cpuset-affinity.rs new file mode 100644 index 0000000000000..9a868128d2716 --- /dev/null +++ b/src/tools/miri/tests/pass-dep/shims/freebsd-cpuset-affinity.rs @@ -0,0 +1,51 @@ +//@only-target: freebsd +//@compile-flags: -Zmiri-num-cpus=256 + +use std::mem; + +fn getaffinity() { + let mut set: libc::cpuset_t = unsafe { mem::zeroed() }; + unsafe { + if libc::cpuset_getaffinity( + libc::CPU_LEVEL_WHICH, + libc::CPU_WHICH_PID, + -1, + size_of::(), + &mut set, + ) == 0 + { + assert!(libc::CPU_COUNT(&set) == 256); + } + } +} + +fn get_small_cpu_mask() { + let mut set: libc::cpuset_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; + + // 256 CPUs so we need 32 bytes to represent this mask. + // According to Freebsd only when `cpusetsize` is smaller than this value, does it return with ERANGE + + let err = unsafe { + libc::cpuset_getaffinity(libc::CPU_LEVEL_WHICH, libc::CPU_WHICH_PID, -1, 32, &mut set) + }; + assert_eq!(err, 0, "Success Expected"); + + // 31 is not enough, so it should fail. + let err = unsafe { + libc::cpuset_getaffinity(libc::CPU_LEVEL_WHICH, libc::CPU_WHICH_PID, -1, 31, &mut set) + }; + assert_eq!(err, -1, "Expected Failure"); + assert_eq!(std::io::Error::last_os_error().raw_os_error().unwrap(), libc::ERANGE); + + // Zero should fail as well. + let err = unsafe { + libc::cpuset_getaffinity(libc::CPU_LEVEL_WHICH, libc::CPU_WHICH_PID, -1, 0, &mut set) + }; + assert_eq!(err, -1, "Expected Failure"); + assert_eq!(std::io::Error::last_os_error().raw_os_error().unwrap(), libc::ERANGE); +} + +fn main() { + getaffinity(); + get_small_cpu_mask(); +} From 5955969543c986cff786eec4d54ebba8c9dc6ea7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 May 2025 21:09:03 +0200 Subject: [PATCH 2576/4206] run the full test suite under FreeBSD --- src/tools/miri/ci/ci.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 3a9e55f5738d2..9ae15739dcbe1 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -162,11 +162,11 @@ case $HOST_TARGET in MANY_SEEDS=16 TEST_TARGET=mips-unknown-linux-gnu run_tests # a 32bit big-endian target, and also a target without 64bit atomics MANY_SEEDS=16 TEST_TARGET=x86_64-unknown-illumos run_tests MANY_SEEDS=16 TEST_TARGET=x86_64-pc-solaris run_tests + MANY_SEEDS=16 TEST_TARGET=x86_64-unknown-freebsd run_tests + MANY_SEEDS=16 TEST_TARGET=i686-unknown-freebsd run_tests # Partially supported targets (tier 2) BASIC="empty_main integer heap_alloc libc-mem vec string btreemap" # ensures we have the basics: pre-main code, system allocator UNIX="hello panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there - TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency fs libc-pipe affinity - TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency fs libc-pipe affinity TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency epoll eventfd TEST_TARGET=wasm32-wasip2 run_tests_minimal $BASIC wasm TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std From 544c300fb65abda37b99d1a9baac24c517e7b1c9 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 21 May 2025 09:57:38 -0400 Subject: [PATCH 2577/4206] Improve speed of `cargo dev fmt`. --- clippy_dev/src/fmt.rs | 96 ++++++------------- clippy_dev/src/main.rs | 2 +- clippy_dev/src/rename_lint.rs | 14 +-- clippy_dev/src/utils.rs | 93 ++++++++++++++---- rustfmt.toml | 6 +- .../non_expressive_names_error_recovery.fixed | 0 .../non_expressive_names_error_recovery.rs | 0 ...non_expressive_names_error_recovery.stderr | 2 +- 8 files changed, 113 insertions(+), 100 deletions(-) rename tests/ui/{skip_rustfmt => }/non_expressive_names_error_recovery.fixed (100%) rename tests/ui/{skip_rustfmt => }/non_expressive_names_error_recovery.rs (100%) rename tests/ui/{skip_rustfmt => }/non_expressive_names_error_recovery.stderr (81%) diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index 13d6b1285dcdb..c21b76b62e055 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -1,5 +1,6 @@ use crate::utils::{ - ClippyInfo, ErrAction, FileUpdater, UpdateMode, UpdateStatus, panic_action, run_with_args_split, run_with_output, + ErrAction, FileUpdater, UpdateMode, UpdateStatus, panic_action, run_with_output, split_args_for_threads, + walk_dir_no_dot_or_target, }; use itertools::Itertools; use rustc_lexer::{TokenKind, tokenize}; @@ -9,7 +10,6 @@ use std::io::{self, Read}; use std::ops::ControlFlow; use std::path::PathBuf; use std::process::{self, Command, Stdio}; -use walkdir::WalkDir; pub enum Error { Io(io::Error), @@ -260,7 +260,7 @@ fn fmt_syms(update_mode: UpdateMode) { ); } -fn run_rustfmt(clippy: &ClippyInfo, update_mode: UpdateMode) { +fn run_rustfmt(update_mode: UpdateMode) { let mut rustfmt_path = String::from_utf8(run_with_output( "rustup which rustfmt", Command::new("rustup").args(["which", "rustfmt"]), @@ -268,42 +268,19 @@ fn run_rustfmt(clippy: &ClippyInfo, update_mode: UpdateMode) { .expect("invalid rustfmt path"); rustfmt_path.truncate(rustfmt_path.trim_end().len()); - let mut cargo_path = String::from_utf8(run_with_output( - "rustup which cargo", - Command::new("rustup").args(["which", "cargo"]), - )) - .expect("invalid cargo path"); - cargo_path.truncate(cargo_path.trim_end().len()); - - // Start all format jobs first before waiting on the results. - let mut children = Vec::with_capacity(16); - for &path in &[ - ".", - "clippy_config", - "clippy_dev", - "clippy_lints", - "clippy_lints_internal", - "clippy_utils", - "rustc_tools_util", - "lintcheck", - ] { - let mut cmd = Command::new(&cargo_path); - cmd.current_dir(clippy.path.join(path)) - .args(["fmt"]) - .env("RUSTFMT", &rustfmt_path) - .stdout(Stdio::null()) - .stdin(Stdio::null()) - .stderr(Stdio::piped()); - if update_mode.is_check() { - cmd.arg("--check"); - } - match cmd.spawn() { - Ok(x) => children.push(("cargo fmt", x)), - Err(ref e) => panic_action(&e, ErrAction::Run, "cargo fmt".as_ref()), - } - } + let args: Vec<_> = walk_dir_no_dot_or_target() + .filter_map(|e| { + let e = e.expect("error reading `.`"); + e.path() + .as_os_str() + .as_encoded_bytes() + .ends_with(b".rs") + .then(|| e.into_path().into_os_string()) + }) + .collect(); - run_with_args_split( + let mut children: Vec<_> = split_args_for_threads( + 32, || { let mut cmd = Command::new(&rustfmt_path); if update_mode.is_check() { @@ -312,27 +289,18 @@ fn run_rustfmt(clippy: &ClippyInfo, update_mode: UpdateMode) { cmd.stdout(Stdio::null()) .stdin(Stdio::null()) .stderr(Stdio::piped()) - .args(["--config", "show_parse_errors=false"]); + .args(["--unstable-features", "--skip-children"]); cmd }, - |cmd| match cmd.spawn() { - Ok(x) => children.push(("rustfmt", x)), - Err(ref e) => panic_action(&e, ErrAction::Run, "rustfmt".as_ref()), - }, - WalkDir::new("tests") - .into_iter() - .filter_entry(|p| p.path().file_name().is_none_or(|x| x != "skip_rustfmt")) - .filter_map(|e| { - let e = e.expect("error reading `tests`"); - e.path() - .as_os_str() - .as_encoded_bytes() - .ends_with(b".rs") - .then(|| e.into_path().into_os_string()) - }), - ); + args.iter(), + ) + .map(|mut cmd| match cmd.spawn() { + Ok(x) => x, + Err(ref e) => panic_action(&e, ErrAction::Run, "rustfmt".as_ref()), + }) + .collect(); - for (name, child) in &mut children { + for child in &mut children { match child.wait() { Ok(status) => match (update_mode, status.exit_ok()) { (UpdateMode::Check | UpdateMode::Change, Ok(())) => {}, @@ -353,25 +321,17 @@ fn run_rustfmt(clippy: &ClippyInfo, update_mode: UpdateMode) { { eprintln!("{s}"); } - panic_action(&e, ErrAction::Run, name.as_ref()); + panic_action(&e, ErrAction::Run, "rustfmt".as_ref()); }, }, - Err(ref e) => panic_action(e, ErrAction::Run, name.as_ref()), + Err(ref e) => panic_action(e, ErrAction::Run, "rustfmt".as_ref()), } } } // the "main" function of cargo dev fmt -pub fn run(clippy: &ClippyInfo, update_mode: UpdateMode) { - if clippy.has_intellij_hook { - eprintln!( - "error: a local rustc repo is enabled as path dependency via `cargo dev setup intellij`.\n\ - Not formatting because that would format the local repo as well!\n\ - Please revert the changes to `Cargo.toml`s with `cargo dev remove intellij`." - ); - return; - } - run_rustfmt(clippy, update_mode); +pub fn run(update_mode: UpdateMode) { + run_rustfmt(update_mode); fmt_syms(update_mode); if let Err(e) = fmt_conf(update_mode.is_check()) { e.display(); diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index ebcd8611d78cd..26aa269fb6388 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -26,7 +26,7 @@ fn main() { allow_staged, allow_no_vcs, } => dogfood::dogfood(fix, allow_dirty, allow_staged, allow_no_vcs), - DevCommand::Fmt { check } => fmt::run(&clippy, utils::UpdateMode::from_check(check)), + DevCommand::Fmt { check } => fmt::run(utils::UpdateMode::from_check(check)), DevCommand::UpdateLints { check } => update_lints::update(utils::UpdateMode::from_check(check)), DevCommand::NewLint { pass, diff --git a/clippy_dev/src/rename_lint.rs b/clippy_dev/src/rename_lint.rs index be8b27c7a9e9f..86f65b60d1b08 100644 --- a/clippy_dev/src/rename_lint.rs +++ b/clippy_dev/src/rename_lint.rs @@ -1,13 +1,12 @@ use crate::update_lints::{RenamedLint, find_lint_decls, generate_lint_files, read_deprecated_lints}; use crate::utils::{ FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, Version, delete_dir_if_exists, delete_file_if_exists, - try_rename_dir, try_rename_file, + try_rename_dir, try_rename_file, walk_dir_no_dot_or_target, }; use rustc_lexer::TokenKind; use std::ffi::OsString; use std::fs; use std::path::Path; -use walkdir::WalkDir; /// Runs the `rename_lint` command. /// @@ -133,15 +132,8 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b } let mut update_fn = file_update_fn(old_name, new_name, mod_edit); - for file in WalkDir::new(".").into_iter().filter_entry(|e| { - // Skip traversing some of the larger directories. - e.path() - .as_os_str() - .as_encoded_bytes() - .get(2..) - .is_none_or(|x| x != "target".as_bytes() && x != ".git".as_bytes()) - }) { - let file = file.expect("error reading clippy directory"); + for file in walk_dir_no_dot_or_target() { + let file = file.expect("error reading `.`"); if file.path().as_os_str().as_encoded_bytes().ends_with(b".rs") { updater.update_file(file.path(), &mut update_fn); } diff --git a/clippy_dev/src/utils.rs b/clippy_dev/src/utils.rs index 255e36afe69c2..f90068ee7bd19 100644 --- a/clippy_dev/src/utils.rs +++ b/clippy_dev/src/utils.rs @@ -1,14 +1,16 @@ use core::fmt::{self, Display}; +use core::num::NonZero; use core::ops::Range; use core::slice; use core::str::FromStr; use rustc_lexer::{self as lexer, FrontmatterAllowed}; -use std::env; use std::ffi::OsStr; use std::fs::{self, OpenOptions}; use std::io::{self, Read as _, Seek as _, SeekFrom, Write}; use std::path::{Path, PathBuf}; use std::process::{self, Command, ExitStatus, Stdio}; +use std::{env, thread}; +use walkdir::WalkDir; #[cfg(not(windows))] static CARGO_CLIPPY_EXE: &str = "cargo-clippy"; @@ -682,25 +684,71 @@ pub fn run_with_output(path: &(impl AsRef + ?Sized), cmd: &mut Command) -> f(path.as_ref(), cmd) } -pub fn run_with_args_split( - mut make_cmd: impl FnMut() -> Command, - mut run_cmd: impl FnMut(&mut Command), - args: impl Iterator>, -) { - let mut cmd = make_cmd(); - let mut len = 0; - for arg in args { - len += arg.as_ref().len(); - cmd.arg(arg); - // Very conservative limit - if len > 10000 { - run_cmd(&mut cmd); - cmd = make_cmd(); - len = 0; +/// Splits an argument list across multiple `Command` invocations. +/// +/// The argument list will be split into a number of batches based on +/// `thread::available_parallelism`, with `min_batch_size` setting a lower bound on the size of each +/// batch. +/// +/// If the size of the arguments would exceed the system limit additional batches will be created. +pub fn split_args_for_threads( + min_batch_size: usize, + make_cmd: impl FnMut() -> Command, + args: impl ExactSizeIterator>, +) -> impl Iterator { + struct Iter { + make_cmd: F, + args: I, + min_batch_size: usize, + batch_size: usize, + thread_count: usize, + } + impl Iterator for Iter + where + F: FnMut() -> Command, + I: ExactSizeIterator>, + { + type Item = Command; + fn next(&mut self) -> Option { + if self.thread_count > 1 { + self.thread_count -= 1; + } + let mut cmd = (self.make_cmd)(); + let mut cmd_len = 0usize; + for arg in self.args.by_ref().take(self.batch_size) { + cmd.arg(arg.as_ref()); + // `+ 8` to account for the `argv` pointer on unix. + // Windows is complicated since the arguments are first converted to UTF-16ish, + // but this needs to account for the space between arguments and whatever additional + // is needed to escape within an argument. + cmd_len += arg.as_ref().len() + 8; + cmd_len += 8; + + // Windows has a command length limit of 32767. For unix systems this is more + // complicated since the limit includes environment variables and room needs to be + // left to edit them once the program starts, but the total size comes from + // `getconf ARG_MAX`. + // + // For simplicity we use 30000 here under a few assumptions. + // * Individual arguments aren't super long (the final argument is still added) + // * `ARG_MAX` is set to a reasonable amount. Basically every system will be configured way above + // what windows supports, but POSIX only requires `4096`. + if cmd_len > 30000 { + self.batch_size = self.args.len().div_ceil(self.thread_count).max(self.min_batch_size); + break; + } + } + (cmd_len != 0).then_some(cmd) } } - if len != 0 { - run_cmd(&mut cmd); + let thread_count = thread::available_parallelism().map_or(1, NonZero::get); + let batch_size = args.len().div_ceil(thread_count).max(min_batch_size); + Iter { + make_cmd, + args, + min_batch_size, + batch_size, + thread_count, } } @@ -720,3 +768,12 @@ pub fn delete_dir_if_exists(path: &Path) { Err(ref e) => panic_action(e, ErrAction::Delete, path), } } + +/// Walks all items excluding top-level dot files/directories and any target directories. +pub fn walk_dir_no_dot_or_target() -> impl Iterator> { + WalkDir::new(".").into_iter().filter_entry(|e| { + e.path() + .file_name() + .is_none_or(|x| x != "target" && x.as_encoded_bytes().first().copied() != Some(b'.')) + }) +} diff --git a/rustfmt.toml b/rustfmt.toml index 0dc6adce7bfce..0ed58a2dfc19f 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -6,4 +6,8 @@ edition = "2024" error_on_line_overflow = true imports_granularity = "Module" style_edition = "2024" -ignore = ["tests/ui/crashes/ice-10912.rs"] +ignore = [ + "tests/ui/crashes/ice-9405.rs", + "tests/ui/crashes/ice-10912.rs", + "tests/ui/non_expressive_names_error_recovery.rs", +] diff --git a/tests/ui/skip_rustfmt/non_expressive_names_error_recovery.fixed b/tests/ui/non_expressive_names_error_recovery.fixed similarity index 100% rename from tests/ui/skip_rustfmt/non_expressive_names_error_recovery.fixed rename to tests/ui/non_expressive_names_error_recovery.fixed diff --git a/tests/ui/skip_rustfmt/non_expressive_names_error_recovery.rs b/tests/ui/non_expressive_names_error_recovery.rs similarity index 100% rename from tests/ui/skip_rustfmt/non_expressive_names_error_recovery.rs rename to tests/ui/non_expressive_names_error_recovery.rs diff --git a/tests/ui/skip_rustfmt/non_expressive_names_error_recovery.stderr b/tests/ui/non_expressive_names_error_recovery.stderr similarity index 81% rename from tests/ui/skip_rustfmt/non_expressive_names_error_recovery.stderr rename to tests/ui/non_expressive_names_error_recovery.stderr index 4998b9bd2cc40..28d9a42a9a1ed 100644 --- a/tests/ui/skip_rustfmt/non_expressive_names_error_recovery.stderr +++ b/tests/ui/non_expressive_names_error_recovery.stderr @@ -1,5 +1,5 @@ error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `)` - --> tests/ui/skip_rustfmt/non_expressive_names_error_recovery.rs:6:19 + --> tests/ui/non_expressive_names_error_recovery.rs:6:19 | LL | fn aa(a: Aa Date: Wed, 21 May 2025 14:56:27 -0400 Subject: [PATCH 2578/4206] Add `expect_action` helper to `clippy_dev` --- clippy_dev/src/fmt.rs | 53 +++++++++++++++------------------- clippy_dev/src/rename_lint.rs | 12 ++++---- clippy_dev/src/update_lints.rs | 7 ++--- clippy_dev/src/utils.rs | 47 +++++++++++++++--------------- 4 files changed, 56 insertions(+), 63 deletions(-) diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index c21b76b62e055..c1b6b37070696 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -1,5 +1,5 @@ use crate::utils::{ - ErrAction, FileUpdater, UpdateMode, UpdateStatus, panic_action, run_with_output, split_args_for_threads, + ErrAction, FileUpdater, UpdateMode, UpdateStatus, expect_action, run_with_output, split_args_for_threads, walk_dir_no_dot_or_target, }; use itertools::Itertools; @@ -270,7 +270,7 @@ fn run_rustfmt(update_mode: UpdateMode) { let args: Vec<_> = walk_dir_no_dot_or_target() .filter_map(|e| { - let e = e.expect("error reading `.`"); + let e = expect_action(e, ErrAction::Read, "."); e.path() .as_os_str() .as_encoded_bytes() @@ -294,37 +294,32 @@ fn run_rustfmt(update_mode: UpdateMode) { }, args.iter(), ) - .map(|mut cmd| match cmd.spawn() { - Ok(x) => x, - Err(ref e) => panic_action(&e, ErrAction::Run, "rustfmt".as_ref()), - }) + .map(|mut cmd| expect_action(cmd.spawn(), ErrAction::Run, "rustfmt")) .collect(); for child in &mut children { - match child.wait() { - Ok(status) => match (update_mode, status.exit_ok()) { - (UpdateMode::Check | UpdateMode::Change, Ok(())) => {}, - (UpdateMode::Check, Err(_)) => { - let mut s = String::new(); - if let Some(mut stderr) = child.stderr.take() - && stderr.read_to_string(&mut s).is_ok() - { - eprintln!("{s}"); - } - eprintln!("Formatting check failed!\nRun `cargo dev fmt` to update."); - process::exit(1); - }, - (UpdateMode::Change, Err(e)) => { - let mut s = String::new(); - if let Some(mut stderr) = child.stderr.take() - && stderr.read_to_string(&mut s).is_ok() - { - eprintln!("{s}"); - } - panic_action(&e, ErrAction::Run, "rustfmt".as_ref()); - }, + let status = expect_action(child.wait(), ErrAction::Run, "rustfmt"); + match (update_mode, status.exit_ok()) { + (UpdateMode::Check | UpdateMode::Change, Ok(())) => {}, + (UpdateMode::Check, Err(_)) => { + let mut s = String::new(); + if let Some(mut stderr) = child.stderr.take() + && stderr.read_to_string(&mut s).is_ok() + { + eprintln!("{s}"); + } + eprintln!("Formatting check failed!\nRun `cargo dev fmt` to update."); + process::exit(1); + }, + (UpdateMode::Change, e) => { + let mut s = String::new(); + if let Some(mut stderr) = child.stderr.take() + && stderr.read_to_string(&mut s).is_ok() + { + eprintln!("{s}"); + } + expect_action(e, ErrAction::Run, "rustfmt"); }, - Err(ref e) => panic_action(e, ErrAction::Run, "rustfmt".as_ref()), } } } diff --git a/clippy_dev/src/rename_lint.rs b/clippy_dev/src/rename_lint.rs index 86f65b60d1b08..d62597428e210 100644 --- a/clippy_dev/src/rename_lint.rs +++ b/clippy_dev/src/rename_lint.rs @@ -1,7 +1,7 @@ use crate::update_lints::{RenamedLint, find_lint_decls, generate_lint_files, read_deprecated_lints}; use crate::utils::{ - FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, Version, delete_dir_if_exists, delete_file_if_exists, - try_rename_dir, try_rename_file, walk_dir_no_dot_or_target, + ErrAction, FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, Version, delete_dir_if_exists, + delete_file_if_exists, expect_action, try_rename_dir, try_rename_file, walk_dir_no_dot_or_target, }; use rustc_lexer::TokenKind; use std::ffi::OsString; @@ -132,10 +132,10 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b } let mut update_fn = file_update_fn(old_name, new_name, mod_edit); - for file in walk_dir_no_dot_or_target() { - let file = file.expect("error reading `.`"); - if file.path().as_os_str().as_encoded_bytes().ends_with(b".rs") { - updater.update_file(file.path(), &mut update_fn); + for e in walk_dir_no_dot_or_target() { + let e = expect_action(e, ErrAction::Read, "."); + if e.path().as_os_str().as_encoded_bytes().ends_with(b".rs") { + updater.update_file(e.path(), &mut update_fn); } } generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 25ba2c7204904..320462a2c9688 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -1,5 +1,5 @@ use crate::utils::{ - ErrAction, File, FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, panic_action, update_text_region_fn, + ErrAction, File, FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, expect_action, update_text_region_fn, }; use itertools::Itertools; use std::collections::HashSet; @@ -201,10 +201,7 @@ pub fn find_lint_decls() -> Vec { /// Reads the source files from the given root directory fn read_src_with_module(src_root: &Path) -> impl use<'_> + Iterator { WalkDir::new(src_root).into_iter().filter_map(move |e| { - let e = match e { - Ok(e) => e, - Err(ref e) => panic_action(e, ErrAction::Read, src_root), - }; + let e = expect_action(e, ErrAction::Read, src_root); let path = e.path().as_os_str().as_encoded_bytes(); if let Some(path) = path.strip_suffix(b".rs") && let Some(path) = path.get("clippy_lints/src/".len()..) diff --git a/clippy_dev/src/utils.rs b/clippy_dev/src/utils.rs index f90068ee7bd19..c4808b7048b03 100644 --- a/clippy_dev/src/utils.rs +++ b/clippy_dev/src/utils.rs @@ -47,6 +47,14 @@ pub fn panic_action(err: &impl Display, action: ErrAction, path: &Path) -> ! { panic!("error {} `{}`: {}", action.as_str(), path.display(), *err) } +#[track_caller] +pub fn expect_action(res: Result, action: ErrAction, path: impl AsRef) -> T { + match res { + Ok(x) => x, + Err(ref e) => panic_action(e, action, path.as_ref()), + } +} + /// Wrapper around `std::fs::File` which panics with a path on failure. pub struct File<'a> { pub inner: fs::File, @@ -57,9 +65,9 @@ impl<'a> File<'a> { #[track_caller] pub fn open(path: &'a (impl AsRef + ?Sized), options: &mut OpenOptions) -> Self { let path = path.as_ref(); - match options.open(path) { - Ok(inner) => Self { inner, path }, - Err(e) => panic_action(&e, ErrAction::Open, path), + Self { + inner: expect_action(options.open(path), ErrAction::Open, path), + path, } } @@ -86,10 +94,7 @@ impl<'a> File<'a> { /// Read the entire contents of a file to the given buffer. #[track_caller] pub fn read_append_to_string<'dst>(&mut self, dst: &'dst mut String) -> &'dst mut String { - match self.inner.read_to_string(dst) { - Ok(_) => {}, - Err(e) => panic_action(&e, ErrAction::Read, self.path), - } + expect_action(self.inner.read_to_string(dst), ErrAction::Read, self.path); dst } @@ -109,9 +114,7 @@ impl<'a> File<'a> { }, Err(e) => Err(e), }; - if let Err(e) = res { - panic_action(&e, ErrAction::Write, self.path); - } + expect_action(res, ErrAction::Write, self.path); } } @@ -662,24 +665,22 @@ pub fn try_rename_dir(old_name: &Path, new_name: &Path) -> bool { } pub fn write_file(path: &Path, contents: &str) { - fs::write(path, contents).unwrap_or_else(|e| panic_action(&e, ErrAction::Write, path)); + expect_action(fs::write(path, contents), ErrAction::Write, path); } #[must_use] pub fn run_with_output(path: &(impl AsRef + ?Sized), cmd: &mut Command) -> Vec { fn f(path: &Path, cmd: &mut Command) -> Vec { - match cmd - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .stderr(Stdio::inherit()) - .output() - { - Ok(x) => match x.status.exit_ok() { - Ok(()) => x.stdout, - Err(ref e) => panic_action(e, ErrAction::Run, path), - }, - Err(ref e) => panic_action(e, ErrAction::Run, path), - } + let output = expect_action( + cmd.stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .output(), + ErrAction::Run, + path, + ); + expect_action(output.status.exit_ok(), ErrAction::Run, path); + output.stdout } f(path.as_ref(), cmd) } From 6d6259f310f4142dea37333f879da55be53f1b3e Mon Sep 17 00:00:00 2001 From: Boxy Date: Wed, 21 May 2025 20:09:41 +0100 Subject: [PATCH 2579/4206] Document why we allow escaping bound vars in LTA norm --- .../src/traits/normalize.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 88a0c402702e1..eb6d5c8a60a25 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -299,12 +299,21 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { ); } + // We don't replace bound vars in the generic arguments of the free alias with + // placeholders. This doesn't cause any issues as instantiating parameters with + // bound variables is special-cased to rewrite the debruijn index to be higher + // whenever we fold through a binder. + // + // However, we do replace any escaping bound vars in the resulting goals with + // placeholders as the trait solver does not expect to encounter escaping bound + // vars in obligations. + // + // FIXME(lazy_type_alias): Check how much this actually matters for perf before + // stabilization. This is a bit weird and generally not how we handle binders in + // the compiler so ideally we'd do the same boundvar->placeholder->boundvar dance + // that other kinds of normalization do. let infcx = self.selcx.infcx; self.obligations.extend( - // FIXME(BoxyUwU): - // FIXME(lazy_type_alias): - // It seems suspicious to instantiate the predicates with arguments that might be bound vars, - // we might wind up instantiating one of these bound vars underneath a hrtb. infcx.tcx.predicates_of(free.def_id).instantiate_own(infcx.tcx, free.args).map( |(mut predicate, span)| { if free.has_escaping_bound_vars() { From 4a18888cade6dd7350bcacaea1648c4478a6280f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 May 2025 21:11:03 +0200 Subject: [PATCH 2580/4206] document that the entire test suite passes under freebsd --- src/tools/miri/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 122438a2509b3..de521393cd0ab 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -218,7 +218,7 @@ degree documented below): make no promises and we don't run tests for such targets. - We have unofficial support (not maintained by the Miri team itself) for some further operating systems. - `solaris` / `illumos`: maintained by @devnexen. Supports the entire test suite. - - `freebsd`: maintained by @YohDeadfall. Supports `std::env` and parts of `std::{thread, fs}`, but not `std::sync`. + - `freebsd`: maintained by @YohDeadfall and @LorrensP-2158466. Supports the entire test suite. - `android`: **maintainer wanted**. Support very incomplete, but a basic "hello world" works. - `wasi`: **maintainer wanted**. Support very incomplete, not even standard output works, but an empty `main` function works. - For targets on other operating systems, Miri might fail before even reaching the `main` function. From 996a185ba74755cb39a4fe24151ea65e671d4c0d Mon Sep 17 00:00:00 2001 From: Boxy Date: Wed, 12 Mar 2025 11:23:20 +0000 Subject: [PATCH 2581/4206] Introduce `tcx.anon_const_kind` query --- compiler/rustc_hir_analysis/src/collect.rs | 25 +++++++ .../src/collect/generics_of.rs | 71 ++++++++----------- .../src/rmeta/decoder/cstore_impl.rs | 1 + compiler/rustc_metadata/src/rmeta/encoder.rs | 3 + compiler/rustc_metadata/src/rmeta/mod.rs | 1 + compiler/rustc_middle/src/query/erase.rs | 1 + compiler/rustc_middle/src/query/mod.rs | 6 ++ compiler/rustc_middle/src/ty/consts.rs | 10 ++- compiler/rustc_middle/src/ty/mod.rs | 4 +- compiler/rustc_middle/src/ty/parameterized.rs | 1 + .../rustc_trait_selection/src/traits/mod.rs | 9 ++- 11 files changed, 86 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 4520fbe352cea..dfe9d7af3adac 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -89,6 +89,7 @@ pub(crate) fn provide(providers: &mut Providers) { opaque_ty_origin, rendered_precise_capturing_args, const_param_default, + anon_const_kind, ..*providers }; } @@ -1828,3 +1829,27 @@ fn const_param_default<'tcx>( .lower_const_arg(default_ct, FeedConstTy::Param(def_id.to_def_id(), identity_args)); ty::EarlyBinder::bind(ct) } + +fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKind { + let hir_id = tcx.local_def_id_to_hir_id(def); + let const_arg_id = tcx.parent_hir_id(hir_id); + match tcx.hir_node(const_arg_id) { + hir::Node::ConstArg(_) => { + if tcx.features().generic_const_exprs() { + ty::AnonConstKind::GCEConst + } else if tcx.features().min_generic_const_args() { + ty::AnonConstKind::MCGConst + } else if let hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Repeat(_, repeat_count), + .. + }) = tcx.hir_node(tcx.parent_hir_id(const_arg_id)) + && repeat_count.hir_id == const_arg_id + { + ty::AnonConstKind::RepeatExprCount + } else { + ty::AnonConstKind::MCGConst + } + } + _ => ty::AnonConstKind::NonTypeSystem, + } +} diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 2bed28d7b710c..d261f3f85fe71 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -104,19 +104,27 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { } } - if in_param_ty { - // We do not allow generic parameters in anon consts if we are inside - // of a const parameter type, e.g. `struct Foo` is not allowed. - None - } else if tcx.features().generic_const_exprs() { - let parent_node = tcx.parent_hir_node(hir_id); - debug!(?parent_node); - if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node - && constant.hir_id == hir_id - { - // enum variant discriminants are not allowed to use any kind of generics - None - } else if let Some(param_id) = tcx.hir_opt_const_param_default_param_def_id(hir_id) + match tcx.anon_const_kind(def_id) { + // Stable: anon consts are not able to use any generic parameters... + ty::AnonConstKind::MCGConst => None, + // we provide generics to repeat expr counts as a backwards compatibility hack. #76200 + ty::AnonConstKind::RepeatExprCount => Some(parent_did), + + // Even GCE anon const should not be allowed to use generic parameters as it would be + // trivially forward declared uses once desugared. E.g. `const N: [u8; ANON::]`. + // + // We could potentially mirror the hack done for defaults of generic parameters but + // this case just doesn't come up much compared to `const N: u32 = ...`. Long term the + // hack for defaulted parameters should be removed eventually anyway. + ty::AnonConstKind::GCEConst if in_param_ty => None, + // GCE anon consts as a default for a generic parameter should have their provided generics + // "truncated" up to whatever generic parameter this anon const is within the default of. + // + // FIXME(generic_const_exprs): This only handles `const N: usize = /*defid*/` but not type + // parameter defaults, e.g. `T = Foo`. + ty::AnonConstKind::GCEConst + if let Some(param_id) = + tcx.hir_opt_const_param_default_param_def_id(hir_id) => { // If the def_id we are calling generics_of on is an anon ct default i.e: // @@ -160,36 +168,17 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { has_self: generics.has_self, has_late_bound_regions: generics.has_late_bound_regions, }; - } else { - // HACK(eddyb) this provides the correct generics when - // `feature(generic_const_expressions)` is enabled, so that const expressions - // used with const generics, e.g. `Foo<{N+1}>`, can work at all. - // - // Note that we do not supply the parent generics when using - // `min_const_generics`. - Some(parent_did) } - } else { - let parent_node = tcx.parent_hir_node(hir_id); - let parent_node = match parent_node { - Node::ConstArg(ca) => tcx.parent_hir_node(ca.hir_id), - _ => parent_node, - }; - match parent_node { - // HACK(eddyb) this provides the correct generics for repeat - // expressions' count (i.e. `N` in `[x; N]`), and explicit - // `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`), - // as they shouldn't be able to cause query cycle errors. - Node::Expr(Expr { kind: ExprKind::Repeat(_, ct), .. }) - if ct.anon_const_hir_id() == Some(hir_id) => - { - Some(parent_did) - } - Node::TyPat(_) => Some(parent_did), - // Field default values inherit the ADT's generics. - Node::Field(_) => Some(parent_did), - _ => None, + ty::AnonConstKind::GCEConst => Some(parent_did), + + // Field defaults are allowed to use generic parameters, e.g. `field: u32 = /*defid: N + 1*/` + ty::AnonConstKind::NonTypeSystem + if matches!(tcx.parent_hir_node(hir_id), Node::TyPat(_) | Node::Field(_)) => + { + Some(parent_did) } + // Default to no generic parameters for other kinds of anon consts + ty::AnonConstKind::NonTypeSystem => None, } } Node::ConstBlock(_) diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 97d3156573367..f40a2374beac2 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -425,6 +425,7 @@ provide! { tcx, def_id, other, cdata, doc_link_traits_in_scope => { tcx.arena.alloc_from_iter(cdata.get_doc_link_traits_in_scope(def_id.index)) } + anon_const_kind => { table } } pub(in crate::rmeta) fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 7ac72ef814a9c..3ab989d2d3ba7 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1569,6 +1569,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { <- tcx.explicit_implied_const_bounds(def_id).skip_binder()); } } + if let DefKind::AnonConst = def_kind { + record!(self.tables.anon_const_kind[def_id] <- self.tcx.anon_const_kind(def_id)); + } if tcx.impl_method_has_trait_impl_trait_tys(def_id) && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id) { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index d3d928aa88e5c..077835283e968 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -480,6 +480,7 @@ define_tables! { doc_link_traits_in_scope: Table>, assumed_wf_types_for_rpitit: Table, Span)>>, opaque_ty_origin: Table>>, + anon_const_kind: Table>, } #[derive(TyEncodable, TyDecodable)] diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 5bd111fa2f22d..fef1db8799c49 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -311,6 +311,7 @@ trivial! { rustc_middle::ty::Asyncness, rustc_middle::ty::AsyncDestructor, rustc_middle::ty::BoundVariableKind, + rustc_middle::ty::AnonConstKind, rustc_middle::ty::DeducedParamAttrs, rustc_middle::ty::Destructor, rustc_middle::ty::fast_reject::SimplifiedType, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b2133fea08cc3..2e8a2bceb38bb 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2586,6 +2586,12 @@ rustc_queries! { desc { "estimating codegen size of `{}`", key } cache_on_disk_if { true } } + + query anon_const_kind(def_id: DefId) -> ty::AnonConstKind { + desc { |tcx| "looking up anon const kind of `{}`", tcx.def_path_str(def_id) } + cache_on_disk_if { def_id.is_local() } + separate_provide_extern + } } rustc_with_all_queries! { define_callbacks! } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index dc5fe2d8f8b06..f1ea2152f3bd0 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use rustc_data_structures::intern::Interned; use rustc_error_messages::MultiSpan; -use rustc_macros::HashStable; +use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_type_ir::walk::TypeWalker; use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo}; @@ -259,3 +259,11 @@ impl<'tcx> Const<'tcx> { TypeWalker::new(self.into()) } } + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable, HashStable)] +pub enum AnonConstKind { + GCEConst, + MCGConst, + RepeatExprCount, + NonTypeSystem, +} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index b2a58897c31bd..f57329608ef77 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -74,8 +74,8 @@ pub use self::closure::{ place_to_string_for_capture, }; pub use self::consts::{ - Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree, ValTreeKind, - Value, + AnonConstKind, Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, + ValTree, ValTreeKind, Value, }; pub use self::context::{ CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index ecd6132b3ef35..3858778bfc8fb 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -68,6 +68,7 @@ trivially_parameterized_over_tcx! { ty::AsyncDestructor, ty::AssocItemContainer, ty::Asyncness, + ty::AnonConstKind, ty::DeducedParamAttrs, ty::Destructor, ty::Generics, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 31b075db04b96..e00be6425bc72 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -553,7 +553,8 @@ pub fn try_evaluate_const<'tcx>( // // FIXME: `const_eval_resolve_for_typeck` should probably just modify the env itself // instead of having this logic here - let (args, typing_env) = if tcx.features().generic_const_exprs() + let (args, typing_env) = if tcx.def_kind(uv.def) == DefKind::AnonConst + && let ty::AnonConstKind::GCEConst = tcx.anon_const_kind(uv.def) && uv.has_non_region_infer() { // `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause @@ -582,7 +583,10 @@ pub fn try_evaluate_const<'tcx>( (args, typing_env) } } - } else if tcx.def_kind(uv.def) == DefKind::AnonConst && uv.has_non_region_infer() { + } else if tcx.def_kind(uv.def) == DefKind::AnonConst + && let ty::AnonConstKind::RepeatExprCount = tcx.anon_const_kind(uv.def) + && uv.has_non_region_infer() + { // FIXME: remove this when `const_evaluatable_unchecked` is a hard error. // // Diagnostics will sometimes replace the identity args of anon consts in @@ -599,6 +603,7 @@ pub fn try_evaluate_const<'tcx>( let args = GenericArgs::identity_for_item(tcx, uv.def); let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def); + (args, typing_env) } else { // FIXME: This codepath is reachable under `associated_const_equality` and in the From b4079c62bd6b8ca5321ac8b75e336d772985dfeb Mon Sep 17 00:00:00 2001 From: Boxy Date: Thu, 1 May 2025 14:57:25 +0100 Subject: [PATCH 2582/4206] Don't evaluate constants depending on infers or params --- .../rustc_trait_selection/src/traits/mod.rs | 106 +++++++++++------- 1 file changed, 64 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index e00be6425bc72..c174de44558c8 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -545,7 +545,7 @@ pub fn try_evaluate_const<'tcx>( // Postpone evaluation of constants that depend on generic parameters or // inference variables. // - // We use `TypingMode::PostAnalysis` here which is not *technically* correct + // We use `TypingMode::PostAnalysis` here which is not *technically* correct // to be revealing opaque types here as borrowcheck has not run yet. However, // CTFE itself uses `TypingMode::PostAnalysis` unconditionally even during // typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821). @@ -555,68 +555,90 @@ pub fn try_evaluate_const<'tcx>( // instead of having this logic here let (args, typing_env) = if tcx.def_kind(uv.def) == DefKind::AnonConst && let ty::AnonConstKind::GCEConst = tcx.anon_const_kind(uv.def) - && uv.has_non_region_infer() { - // `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause - // inference variables and generic parameters to show up in `ty::Const` even though the anon const - // does not actually make use of them. We handle this case specially and attempt to evaluate anyway. - match tcx.thir_abstract_const(uv.def) { - Ok(Some(ct)) => { - let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, uv.args)); - if let Err(e) = ct.error_reported() { - return Err(EvaluateConstErr::EvaluationFailure(e)); - } else if ct.has_non_region_infer() || ct.has_non_region_param() { - // If the anon const *does* actually use generic parameters or inference variables from - // the generic arguments provided for it, then we should *not* attempt to evaluate it. - return Err(EvaluateConstErr::HasGenericsOrInfers); - } else { - let args = replace_param_and_infer_args_with_placeholder(tcx, uv.args); - let typing_env = infcx - .typing_env(tcx.erase_regions(param_env)) - .with_post_analysis_normalized(tcx); + // We handle `generic_const_exprs` separately as reasonable ways of handling constants in the type system + // completely fall apart under `generic_const_exprs` and makes this whole function Really hard to reason + // about if you have to consider gce whatsoever. + + if uv.has_non_region_infer() || uv.has_non_region_param() { + // `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause + // inference variables and generic parameters to show up in `ty::Const` even though the anon const + // does not actually make use of them. We handle this case specially and attempt to evaluate anyway. + match tcx.thir_abstract_const(uv.def) { + Ok(Some(ct)) => { + let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, uv.args)); + if let Err(e) = ct.error_reported() { + return Err(EvaluateConstErr::EvaluationFailure(e)); + } else if ct.has_non_region_infer() || ct.has_non_region_param() { + // If the anon const *does* actually use generic parameters or inference variables from + // the generic arguments provided for it, then we should *not* attempt to evaluate it. + return Err(EvaluateConstErr::HasGenericsOrInfers); + } else { + let args = + replace_param_and_infer_args_with_placeholder(tcx, uv.args); + let typing_env = infcx + .typing_env(tcx.erase_regions(param_env)) + .with_post_analysis_normalized(tcx); + (args, typing_env) + } + } + Err(_) | Ok(None) => { + let args = GenericArgs::identity_for_item(tcx, uv.def); + let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def); (args, typing_env) } } - Err(_) | Ok(None) => { - let args = GenericArgs::identity_for_item(tcx, uv.def); - let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def); - (args, typing_env) - } + } else { + let typing_env = infcx + .typing_env(tcx.erase_regions(param_env)) + .with_post_analysis_normalized(tcx); + (uv.args, typing_env) } } else if tcx.def_kind(uv.def) == DefKind::AnonConst && let ty::AnonConstKind::RepeatExprCount = tcx.anon_const_kind(uv.def) - && uv.has_non_region_infer() { - // FIXME: remove this when `const_evaluatable_unchecked` is a hard error. - // - // Diagnostics will sometimes replace the identity args of anon consts in - // array repeat expr counts with inference variables so we have to handle this - // even though it is not something we should ever actually encounter. - // - // Array repeat expr counts are allowed to syntactically use generic parameters - // but must not actually depend on them in order to evalaute successfully. This means - // that it is actually fine to evalaute them in their own environment rather than with - // the actually provided generic arguments. - tcx.dcx().delayed_bug( - "Encountered anon const with inference variable args but no error reported", - ); + if uv.has_non_region_infer() { + // Diagnostics will sometimes replace the identity args of anon consts in + // array repeat expr counts with inference variables so we have to handle this + // even though it is not something we should ever actually encounter. + // + // Array repeat expr counts are allowed to syntactically use generic parameters + // but must not actually depend on them in order to evalaute successfully. This means + // that it is actually fine to evalaute them in their own environment rather than with + // the actually provided generic arguments. + tcx.dcx().delayed_bug( + "Encountered anon const with inference variable args but no error reported", + ); + } + // The generic args of repeat expr counts under `min_const_generics` are not supposed to + // affect evaluation of the constant as this would make it a "truly" generic const arg. + // To prevent this we discard all the generic arguments and evalaute with identity args + // and in its own environment instead of the current environment we are normalizing in. let args = GenericArgs::identity_for_item(tcx, uv.def); let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def); (args, typing_env) } else { - // FIXME: This codepath is reachable under `associated_const_equality` and in the - // future will be reachable by `min_generic_const_args`. We should handle inference - // variables and generic parameters properly instead of doing nothing. + // We are only dealing with "truly" generic/uninferred constants here: + // - GCEConsts have been handled separately + // - Repeat expr count back compat consts have also been handled separately + // So we are free to simply defer evaluation here. + // + // FIXME: This assumes that `args` are normalized which is not necessarily true + if uv.args.has_non_region_param() || uv.args.has_non_region_infer() { + return Err(EvaluateConstErr::HasGenericsOrInfers); + } + let typing_env = infcx .typing_env(tcx.erase_regions(param_env)) .with_post_analysis_normalized(tcx); (uv.args, typing_env) }; - let uv = ty::UnevaluatedConst::new(uv.def, args); + let uv = ty::UnevaluatedConst::new(uv.def, args); let erased_uv = tcx.erase_regions(uv); + use rustc_middle::mir::interpret::ErrorHandled; match tcx.const_eval_resolve_for_typeck(typing_env, erased_uv, DUMMY_SP) { Ok(Ok(val)) => Ok(ty::Const::new_value( From b1774b8d7382325d2bb5cc518e463ae9d6de5898 Mon Sep 17 00:00:00 2001 From: Boxy Date: Thu, 1 May 2025 15:46:33 +0100 Subject: [PATCH 2583/4206] Fix tests --- tests/crashes/133199.rs | 11 -- tests/crashes/136894.rs | 8 - tests/crashes/137813.rs | 18 -- .../equality_bound_with_infer.rs | 24 +++ .../equality_bound_with_infer.stderr | 17 ++ .../unconstrained_impl_param.rs | 24 +++ .../unconstrained_impl_param.stderr | 39 ++++ .../auxiliary/cross-crate-2.rs} | 4 +- .../generic_const_exprs/cross-crate-2.rs | 10 + .../dependence_lint.full.stderr | 6 +- .../dependence_lint.gce.stderr | 19 +- .../generic_const_exprs/dependence_lint.rs | 3 +- .../generic_const_exprs/different-fn.stderr | 4 +- .../serializing_error_guaranteed.rs | 16 ++ tests/ui/const-generics/issues/issue-71202.rs | 4 +- .../const-generics/issues/issue-71202.stderr | 46 ++++- tests/ui/const-generics/issues/issue-83765.rs | 16 +- .../const-generics/issues/issue-83765.stderr | 174 ++++++++++++++---- .../in-where-clause.stderr | 5 + 19 files changed, 356 insertions(+), 92 deletions(-) delete mode 100644 tests/crashes/133199.rs delete mode 100644 tests/crashes/136894.rs delete mode 100644 tests/crashes/137813.rs create mode 100644 tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.rs create mode 100644 tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.stderr create mode 100644 tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs create mode 100644 tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr rename tests/{crashes/auxiliary/aux133199.rs => ui/const-generics/generic_const_exprs/auxiliary/cross-crate-2.rs} (67%) create mode 100644 tests/ui/const-generics/generic_const_exprs/cross-crate-2.rs create mode 100644 tests/ui/const-generics/generic_const_exprs/serializing_error_guaranteed.rs diff --git a/tests/crashes/133199.rs b/tests/crashes/133199.rs deleted file mode 100644 index 76535fa83a6d0..0000000000000 --- a/tests/crashes/133199.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: #133199 -//@ aux-build: aux133199.rs - -extern crate aux133199; - -use aux133199::FixedBitSet; - -fn main() { - FixedBitSet::<7>::new(); - //~^ ERROR -} diff --git a/tests/crashes/136894.rs b/tests/crashes/136894.rs deleted file mode 100644 index 26bbb78717e1b..0000000000000 --- a/tests/crashes/136894.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: #136894 -#![feature(generic_const_exprs)] -#![crate_type = "lib"] -#![allow(incomplete_features, dead_code)] - -struct X([(); f::()]) where [(); f::()]:; - -const fn f() -> usize { panic!() } diff --git a/tests/crashes/137813.rs b/tests/crashes/137813.rs deleted file mode 100644 index 5d205ee533122..0000000000000 --- a/tests/crashes/137813.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ known-bug: #137813 -trait AssocConst { - const A: u8; -} - -impl AssocConst for (T,) { - const A: u8 = 0; -} - -trait Trait {} - -impl Trait for () where (U,): AssocConst {} - -fn foo() -where - (): Trait, -{ -} diff --git a/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.rs b/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.rs new file mode 100644 index 0000000000000..f45b7c3268b17 --- /dev/null +++ b/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.rs @@ -0,0 +1,24 @@ +#![feature(generic_arg_infer, associated_const_equality, generic_const_items)] +#![expect(incomplete_features)] + +// Regression test for #133066 where we would try to evaluate `<() as Foo>::ASSOC<_>` even +// though it contained inference variables, which would cause ICEs. + +trait Foo { + const ASSOC: u32; +} + +impl Foo for () { + const ASSOC: u32 = N; +} + +fn bar = 10>>() {} + +fn main() { + bar::<_, ()>(); + //~^ ERROR: type mismatch resolving `<() as Foo>::ASSOC<_> == 10` + + // FIXME(mgca): + // FIXME(associated_const_equality): + // This ought to start compiling once const items are aliases rather than bodies +} diff --git a/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.stderr b/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.stderr new file mode 100644 index 0000000000000..00741c901e4c1 --- /dev/null +++ b/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.stderr @@ -0,0 +1,17 @@ +error[E0271]: type mismatch resolving `<() as Foo>::ASSOC<_> == 10` + --> $DIR/equality_bound_with_infer.rs:18:14 + | +LL | bar::<_, ()>(); + | ^^ expected `10`, found `<() as Foo>::ASSOC::<_>` + | + = note: expected constant `10` + found constant `<() as Foo>::ASSOC::<_>` +note: required by a bound in `bar` + --> $DIR/equality_bound_with_infer.rs:15:29 + | +LL | fn bar = 10>>() {} + | ^^^^^^^^^^^^^ required by this bound in `bar` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs new file mode 100644 index 0000000000000..19cddb71b018f --- /dev/null +++ b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs @@ -0,0 +1,24 @@ +// regression test for #137813 where we would assume all constants in the type system +// cannot contain inference variables, even though associated const equality syntax +// was still lowered without the feature gate enabled. + +trait AssocConst { + const A: u8; +} + +impl AssocConst for (T,) { + const A: u8 = 0; +} + +trait Trait {} + +impl Trait for () where (U,): AssocConst {} +//~^ ERROR associated const equality is incomplete +//~| ERROR the type parameter `U` is not constrained by the impl trait + +fn foo() +where + (): Trait, + //~^ ERROR type mismatch resolving +{ +} diff --git a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr new file mode 100644 index 0000000000000..e6799ec5c3aa4 --- /dev/null +++ b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr @@ -0,0 +1,39 @@ +error[E0658]: associated const equality is incomplete + --> $DIR/unconstrained_impl_param.rs:15:45 + | +LL | impl Trait for () where (U,): AssocConst {} + | ^^^^^^^^^ + | + = note: see issue #92827 for more information + = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates + --> $DIR/unconstrained_impl_param.rs:15:6 + | +LL | impl Trait for () where (U,): AssocConst {} + | ^ unconstrained type parameter + +error[E0271]: type mismatch resolving `<(_,) as AssocConst>::A == 0` + --> $DIR/unconstrained_impl_param.rs:21:5 + | +LL | (): Trait, + | ^^^^^^^^^ expected `0`, found `<(_,) as AssocConst>::A` + | + = note: expected constant `0` + found constant `<(_,) as AssocConst>::A` +note: required for `()` to implement `Trait` + --> $DIR/unconstrained_impl_param.rs:15:9 + | +LL | impl Trait for () where (U,): AssocConst {} + | ^^^^^ ^^ --------- unsatisfied trait bound introduced here + = help: see issue #48214 +help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + | +LL + #![feature(trivial_bounds)] + | + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0207, E0271, E0658. +For more information about an error, try `rustc --explain E0207`. diff --git a/tests/crashes/auxiliary/aux133199.rs b/tests/ui/const-generics/generic_const_exprs/auxiliary/cross-crate-2.rs similarity index 67% rename from tests/crashes/auxiliary/aux133199.rs rename to tests/ui/const-generics/generic_const_exprs/auxiliary/cross-crate-2.rs index 40765d92fbfe9..a8bda14f4bd81 100644 --- a/tests/crashes/auxiliary/aux133199.rs +++ b/tests/ui/const-generics/generic_const_exprs/auxiliary/cross-crate-2.rs @@ -1,9 +1,9 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs)] -pub struct FixedBitSet; +pub struct Foo; -impl FixedBitSet +impl Foo where [u8; N.div_ceil(8)]: Sized, { diff --git a/tests/ui/const-generics/generic_const_exprs/cross-crate-2.rs b/tests/ui/const-generics/generic_const_exprs/cross-crate-2.rs new file mode 100644 index 0000000000000..77998c7ec0a14 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/cross-crate-2.rs @@ -0,0 +1,10 @@ +//@ check-pass +//@ aux-build: cross-crate-2.rs + +extern crate cross_crate_2; + +use cross_crate_2::Foo; + +fn main() { + Foo::<7>::new(); +} diff --git a/tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr b/tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr index f454ff4e6c036..6b095f3818a16 100644 --- a/tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr +++ b/tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr @@ -1,5 +1,5 @@ error: generic parameters may not be used in const operations - --> $DIR/dependence_lint.rs:14:32 + --> $DIR/dependence_lint.rs:15:32 | LL | let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce | ^ cannot perform const operation using `T` @@ -8,7 +8,7 @@ LL | let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/dependence_lint.rs:21:37 + --> $DIR/dependence_lint.rs:22:37 | LL | let _: [u8; if true { size_of::() } else { 3 }]; // error on stable, error with gce | ^ cannot perform const operation using `T` @@ -27,7 +27,7 @@ LL | [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_ = note: `#[warn(const_evaluatable_unchecked)]` on by default warning: cannot use constants which depend on generic parameters in types - --> $DIR/dependence_lint.rs:17:9 + --> $DIR/dependence_lint.rs:18:9 | LL | [0; if false { size_of::() } else { 3 }]; // lint on stable, error with gce | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr b/tests/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr index f6119c17bf47e..12ac980c97544 100644 --- a/tests/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr +++ b/tests/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr @@ -9,8 +9,19 @@ help: try adding a `where` bound LL | fn foo() where [(); size_of::<*mut T>()]: { | ++++++++++++++++++++++++++++++++ +error: unconstrained generic constant + --> $DIR/dependence_lint.rs:10:5 + | +LL | [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_exprs` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try adding a `where` bound + | +LL | fn foo() where [(); size_of::<*mut T>()]: { + | ++++++++++++++++++++++++++++++++ + error: overly complex generic constant - --> $DIR/dependence_lint.rs:17:9 + --> $DIR/dependence_lint.rs:18:9 | LL | [0; if false { size_of::() } else { 3 }]; // lint on stable, error with gce | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ control flow is not supported in generic constants @@ -18,7 +29,7 @@ LL | [0; if false { size_of::() } else { 3 }]; // lint on stable, error w = help: consider moving this anonymous constant into a `const` function error: unconstrained generic constant - --> $DIR/dependence_lint.rs:14:12 + --> $DIR/dependence_lint.rs:15:12 | LL | let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -29,12 +40,12 @@ LL | fn foo() where [(); size_of::<*mut T>()]: { | ++++++++++++++++++++++++++++++++ error: overly complex generic constant - --> $DIR/dependence_lint.rs:21:17 + --> $DIR/dependence_lint.rs:22:17 | LL | let _: [u8; if true { size_of::() } else { 3 }]; // error on stable, error with gce | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ control flow is not supported in generic constants | = help: consider moving this anonymous constant into a `const` function -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/const-generics/generic_const_exprs/dependence_lint.rs b/tests/ui/const-generics/generic_const_exprs/dependence_lint.rs index 107466cd1d9ca..6b3c8f84be3d1 100644 --- a/tests/ui/const-generics/generic_const_exprs/dependence_lint.rs +++ b/tests/ui/const-generics/generic_const_exprs/dependence_lint.rs @@ -9,7 +9,8 @@ use std::mem::size_of; fn foo() { [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_exprs` //[gce]~^ ERROR unconstrained - //[full]~^^ WARNING cannot use constants + //[gce]~| ERROR unconstrained generic constant + //[full]~^^^ WARNING cannot use constants //[full]~| WARNING this was previously accepted let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce //[full]~^ ERROR generic parameters may not be used diff --git a/tests/ui/const-generics/generic_const_exprs/different-fn.stderr b/tests/ui/const-generics/generic_const_exprs/different-fn.stderr index ac80463480db1..52917df0da157 100644 --- a/tests/ui/const-generics/generic_const_exprs/different-fn.stderr +++ b/tests/ui/const-generics/generic_const_exprs/different-fn.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/different-fn.rs:10:5 | LL | [0; size_of::>()] - | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `size_of::()`, found `0` + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `size_of::()`, found `size_of::>()` | = note: expected constant `size_of::()` - found constant `0` + found constant `size_of::>()` error: unconstrained generic constant --> $DIR/different-fn.rs:10:9 diff --git a/tests/ui/const-generics/generic_const_exprs/serializing_error_guaranteed.rs b/tests/ui/const-generics/generic_const_exprs/serializing_error_guaranteed.rs new file mode 100644 index 0000000000000..83b73350f83b6 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/serializing_error_guaranteed.rs @@ -0,0 +1,16 @@ +//@ check-pass + +// regression test for #136894. +// I (BoxyUwU) don't know what the underlying cause was here + +#![feature(generic_const_exprs)] +#![crate_type = "lib"] +#![allow(incomplete_features, dead_code)] + +struct X([(); f::()]) +where + [(); f::()]:; + +const fn f() -> usize { + panic!() +} diff --git a/tests/ui/const-generics/issues/issue-71202.rs b/tests/ui/const-generics/issues/issue-71202.rs index 0f955414d843e..8ff49b55e6fd9 100644 --- a/tests/ui/const-generics/issues/issue-71202.rs +++ b/tests/ui/const-generics/issues/issue-71202.rs @@ -25,7 +25,9 @@ impl DataHolder { } >::VALUE - } as usize] = []; //~ ERROR unconstrained generic constant + } as usize] = []; + //~^ ERROR unconstrained generic constant + //~^^ ERROR mismatched types } fn main() {} diff --git a/tests/ui/const-generics/issues/issue-71202.stderr b/tests/ui/const-generics/issues/issue-71202.stderr index cc3603d1145c3..b7c3db494a576 100644 --- a/tests/ui/const-generics/issues/issue-71202.stderr +++ b/tests/ui/const-generics/issues/issue-71202.stderr @@ -59,5 +59,49 @@ LL + >::VALUE LL ~ } as usize]: = []; | -error: aborting due to 2 previous errors +error[E0308]: mismatched types + --> $DIR/issue-71202.rs:28:19 + | +LL | } as usize] = []; + | ^^ expected `1 - { + trait NotCopy { + const VALUE: bool = false; + } + + impl<__Type: ?Sized> NotCopy for __Type {} + + struct IsCopy<__Type: ?Sized>(PhantomData<__Type>); + + impl<__Type> IsCopy<__Type> + where + __Type: Sized + Copy, + { + const VALUE: bool = true; + } + + >::VALUE + } as usize`, found `0` + | + = note: expected constant `1 - { + trait NotCopy { + const VALUE: bool = false; + } + + impl<__Type: ?Sized> NotCopy for __Type {} + + struct IsCopy<__Type: ?Sized>(PhantomData<__Type>); + + impl<__Type> IsCopy<__Type> + where + __Type: Sized + Copy, + { + const VALUE: bool = true; + } + + >::VALUE + } as usize` + found constant `0` + +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/issues/issue-83765.rs b/tests/ui/const-generics/issues/issue-83765.rs index 0959f771c22ed..f31c61408e9c6 100644 --- a/tests/ui/const-generics/issues/issue-83765.rs +++ b/tests/ui/const-generics/issues/issue-83765.rs @@ -3,10 +3,6 @@ trait TensorDimension { const DIM: usize; - //~^ ERROR cycle detected when resolving instance - //~| ERROR cycle detected when resolving instance - // FIXME Given the current state of the compiler its expected that we cycle here, - // but the cycle is still wrong. const ISSCALAR: bool = Self::DIM == 0; fn is_scalar(&self) -> bool { Self::ISSCALAR @@ -49,6 +45,7 @@ impl<'a, T: Broadcastable, const DIM: usize> TensorDimension for LazyUpdim<'a, T impl<'a, T: Broadcastable, const DIM: usize> TensorSize for LazyUpdim<'a, T, { T::DIM }, DIM> { fn size(&self) -> [usize; DIM] { + //~^ ERROR: method not compatible with trait self.size } } @@ -56,12 +53,17 @@ impl<'a, T: Broadcastable, const DIM: usize> TensorSize for LazyUpdim<'a, T, { T impl<'a, T: Broadcastable, const DIM: usize> Broadcastable for LazyUpdim<'a, T, { T::DIM }, DIM> { type Element = T::Element; fn bget(&self, index: [usize; DIM]) -> Option { + //~^ ERROR: method not compatible with trait assert!(DIM >= T::DIM); if !self.inbounds(index) { + //~^ ERROR: unconstrained generic constant + //~| ERROR: mismatched types return None; } let size = self.size(); + //~^ ERROR: unconstrained generic constant let newindex: [usize; T::DIM] = Default::default(); + //~^ ERROR: the trait bound self.reference.bget(newindex) } } @@ -82,6 +84,8 @@ impl<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> TensorSi fn size(&self) -> [usize; DIM] { //~^ ERROR: method not compatible with trait self.reference.size() + //~^ ERROR: unconstrained generic constant + //~| ERROR: mismatched types } } @@ -92,6 +96,8 @@ impl<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> Broadcas fn bget(&self, index: [usize; DIM]) -> Option { //~^ ERROR: method not compatible with trait self.reference.bget(index).map(&self.closure) + //~^ ERROR: unconstrained generic constant + //~| ERROR: mismatched types } } @@ -100,12 +106,14 @@ impl TensorDimension for Vec { } impl TensorSize for Vec { fn size(&self) -> [usize; 1] { + //~^ ERROR: method not compatible with trait [self.len()] } } impl Broadcastable for Vec { type Element = T; fn bget(&self, index: [usize; 1]) -> Option { + //~^ ERROR: method not compatible with trait self.get(index[0]).cloned() } } diff --git a/tests/ui/const-generics/issues/issue-83765.stderr b/tests/ui/const-generics/issues/issue-83765.stderr index 6b62012c14fc7..5a06ee7ddbc03 100644 --- a/tests/ui/const-generics/issues/issue-83765.stderr +++ b/tests/ui/const-generics/issues/issue-83765.stderr @@ -1,43 +1,23 @@ -error[E0391]: cycle detected when resolving instance `::DIM, DIM> as TensorDimension>::DIM` - --> $DIR/issue-83765.rs:5:5 - | -LL | const DIM: usize; - | ^^^^^^^^^^^^^^^^ - | -note: ...which requires computing candidate for `::DIM, DIM> as TensorDimension>`... - --> $DIR/issue-83765.rs:4:1 - | -LL | trait TensorDimension { - | ^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires resolving instance `::DIM, DIM> as TensorDimension>::DIM`, completing the cycle -note: cycle used when checking assoc item `::size` is compatible with trait definition - --> $DIR/issue-83765.rs:51:5 +error[E0308]: method not compatible with trait + --> $DIR/issue-83765.rs:47:5 | LL | fn size(&self) -> [usize; DIM] { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error[E0391]: cycle detected when resolving instance `::DIM, DIM> as TensorDimension>::DIM` - --> $DIR/issue-83765.rs:5:5 - | -LL | const DIM: usize; - | ^^^^^^^^^^^^^^^^ - | -note: ...which requires computing candidate for `::DIM, DIM> as TensorDimension>`... - --> $DIR/issue-83765.rs:4:1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM` | -LL | trait TensorDimension { - | ^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires resolving instance `::DIM, DIM> as TensorDimension>::DIM`, completing the cycle -note: cycle used when checking assoc item `::bget` is compatible with trait definition - --> $DIR/issue-83765.rs:58:5 + = note: expected constant `Self::DIM` + found constant `DIM` + +error[E0308]: method not compatible with trait + --> $DIR/issue-83765.rs:55:5 | LL | fn bget(&self, index: [usize; DIM]) -> Option { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM` + | + = note: expected constant `Self::DIM` + found constant `DIM` error[E0308]: method not compatible with trait - --> $DIR/issue-83765.rs:82:5 + --> $DIR/issue-83765.rs:84:5 | LL | fn size(&self) -> [usize; DIM] { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM` @@ -46,7 +26,7 @@ LL | fn size(&self) -> [usize; DIM] { found constant `DIM` error[E0308]: method not compatible with trait - --> $DIR/issue-83765.rs:92:5 + --> $DIR/issue-83765.rs:96:5 | LL | fn bget(&self, index: [usize; DIM]) -> Option { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM` @@ -54,7 +34,127 @@ LL | fn bget(&self, index: [usize; DIM]) -> Option { = note: expected constant `Self::DIM` found constant `DIM` -error: aborting due to 4 previous errors +error[E0308]: method not compatible with trait + --> $DIR/issue-83765.rs:108:5 + | +LL | fn size(&self) -> [usize; 1] { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `1` + | + = note: expected constant `Self::DIM` + found constant `1` + +error[E0308]: method not compatible with trait + --> $DIR/issue-83765.rs:115:5 + | +LL | fn bget(&self, index: [usize; 1]) -> Option { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `1` + | + = note: expected constant `Self::DIM` + found constant `1` + +error: unconstrained generic constant + --> $DIR/issue-83765.rs:58:13 + | +LL | if !self.inbounds(index) { + | ^^^^ + | +note: required by a bound in `TensorSize::inbounds` + --> $DIR/issue-83765.rs:14:39 + | +LL | fn inbounds(&self, index: [usize; Self::DIM]) -> bool { + | ^^^^^^^^^ required by this bound in `TensorSize::inbounds` +help: try adding a `where` bound + | +LL | fn bget(&self, index: [usize; DIM]) -> Option where [(); Self::DIM]: { + | ++++++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/issue-83765.rs:58:27 + | +LL | if !self.inbounds(index) { + | ^^^^^ expected `Self::DIM`, found `DIM` + | + = note: expected constant `Self::DIM` + found constant `DIM` + +error: unconstrained generic constant + --> $DIR/issue-83765.rs:63:25 + | +LL | let size = self.size(); + | ^^^^ + | +note: required by a bound in `TensorSize::size` + --> $DIR/issue-83765.rs:13:31 + | +LL | fn size(&self) -> [usize; Self::DIM]; + | ^^^^^^^^^ required by this bound in `TensorSize::size` +help: try adding a `where` bound + | +LL | fn bget(&self, index: [usize; DIM]) -> Option where [(); Self::DIM]: { + | ++++++++++++++++++++++ + +error[E0277]: the trait bound `[usize; T::DIM]: Default` is not satisfied + --> $DIR/issue-83765.rs:65:41 + | +LL | let newindex: [usize; T::DIM] = Default::default(); + | ^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `[usize; T::DIM]` + | +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | impl<'a, T: Broadcastable, const DIM: usize> Broadcastable for LazyUpdim<'a, T, { T::DIM }, DIM> where [usize; T::DIM]: Default { + | ++++++++++++++++++++++++++++++ + +error: unconstrained generic constant + --> $DIR/issue-83765.rs:86:24 + | +LL | self.reference.size() + | ^^^^ + | +note: required by a bound in `TensorSize::size` + --> $DIR/issue-83765.rs:13:31 + | +LL | fn size(&self) -> [usize; Self::DIM]; + | ^^^^^^^^^ required by this bound in `TensorSize::size` +help: try adding a `where` bound + | +LL | fn size(&self) -> [usize; DIM] where [(); Self::DIM]: { + | ++++++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/issue-83765.rs:86:9 + | +LL | self.reference.size() + | ^^^^^^^^^^^^^^^^^^^^^ expected `DIM`, found `Self::DIM` + | + = note: expected constant `DIM` + found constant `Self::DIM` + +error: unconstrained generic constant + --> $DIR/issue-83765.rs:98:9 + | +LL | self.reference.bget(index).map(&self.closure) + | ^^^^^^^^^^^^^^ + | +note: required by a bound in `Broadcastable::bget` + --> $DIR/issue-83765.rs:21:35 + | +LL | fn bget(&self, index: [usize; Self::DIM]) -> Option; + | ^^^^^^^^^ required by this bound in `Broadcastable::bget` +help: try adding a `where` bound + | +LL | fn bget(&self, index: [usize; DIM]) -> Option where [(); Self::DIM]: { + | ++++++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/issue-83765.rs:98:29 + | +LL | self.reference.bget(index).map(&self.closure) + | ^^^^^ expected `Self::DIM`, found `DIM` + | + = note: expected constant `Self::DIM` + found constant `DIM` + +error: aborting due to 14 previous errors -Some errors have detailed explanations: E0308, E0391. -For more information about an error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/type-alias-impl-trait/in-where-clause.stderr b/tests/ui/type-alias-impl-trait/in-where-clause.stderr index 9fcb26c20a682..81be8c8362e35 100644 --- a/tests/ui/type-alias-impl-trait/in-where-clause.stderr +++ b/tests/ui/type-alias-impl-trait/in-where-clause.stderr @@ -62,6 +62,11 @@ LL | / fn foo() -> Bar LL | | where LL | | Bar: Send, | |______________^ +note: ...which requires computing revealed normalized predicates of `foo::{constant#0}`... + --> $DIR/in-where-clause.rs:13:9 + | +LL | [0; 1 + 2] + | ^^^^^ = note: ...which requires revealing opaque types in `[Binder { value: TraitPredicate(, polarity:Positive), bound_vars: [] }]`... note: ...which requires computing type of `Bar::{opaque#0}`... --> $DIR/in-where-clause.rs:5:12 From f60bab475e47e84bb188e463b6a17894a57092c4 Mon Sep 17 00:00:00 2001 From: Boxy Date: Tue, 8 Apr 2025 17:01:29 +0100 Subject: [PATCH 2584/4206] Don't allow repeat expr count inference side effects to propagate --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 63 ++++++++++++++----- .../copy-check-deferred-before-fallback.rs | 3 +- ...copy-check-deferred-before-fallback.stderr | 14 +++++ .../copy-check-inference-side-effects.rs | 34 ++++++++++ .../copy-check-inference-side-effects.stderr | 28 +++++++++ 5 files changed, 123 insertions(+), 19 deletions(-) create mode 100644 tests/ui/repeat-expr/copy-check-deferred-before-fallback.stderr create mode 100644 tests/ui/repeat-expr/copy-check-inference-side-effects.rs create mode 100644 tests/ui/repeat-expr/copy-check-inference-side-effects.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index d2cdfe22a3ad0..533b5b2be7981 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -104,24 +104,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn check_repeat_exprs(&self) { let mut deferred_repeat_expr_checks = self.deferred_repeat_expr_checks.borrow_mut(); debug!("FnCtxt::check_repeat_exprs: {} deferred checks", deferred_repeat_expr_checks.len()); - for (element, element_ty, count) in deferred_repeat_expr_checks.drain(..) { - // We want to emit an error if the const is not structurally resolveable as otherwise - // we can find up conservatively proving `Copy` which may infer the repeat expr count - // to something that never required `Copy` in the first place. - let count = - self.structurally_resolve_const(element.span, self.normalize(element.span, count)); - - // Avoid run on "`NotCopy: Copy` is not implemented" errors when the repeat expr count - // is erroneous/unknown. The user might wind up specifying a repeat count of 0/1. - if count.references_error() { - continue; - } - // If the length is 0, we don't create any elements, so we don't copy any. - // If the length is 1, we don't copy that one element, we move it. Only check - // for `Copy` if the length is larger. - if count.try_to_target_usize(self.tcx).is_none_or(|x| x > 1) { - self.enforce_repeat_element_needs_copy_bound(element, element_ty); + let deferred_repeat_expr_checks = deferred_repeat_expr_checks + .drain(..) + .flat_map(|(element, element_ty, count)| { + // We want to emit an error if the const is not structurally resolveable as otherwise + // we can find up conservatively proving `Copy` which may infer the repeat expr count + // to something that never required `Copy` in the first place. + let count = self + .structurally_resolve_const(element.span, self.normalize(element.span, count)); + + // Avoid run on "`NotCopy: Copy` is not implemented" errors when the repeat expr count + // is erroneous/unknown. The user might wind up specifying a repeat count of 0/1. + if count.references_error() { + return None; + } + + Some((element, element_ty, count)) + }) + // We collect to force the side effects of structurally resolving the repeat count to happen in one + // go, to avoid side effects from proving `Copy` affecting whether repeat counts are known or not. + // If we did not do this we would get results that depend on the order that we evaluate each repeat + // expr's `Copy` check. + .collect::>(); + + for (element, element_ty, count) in deferred_repeat_expr_checks { + match count.kind() { + ty::ConstKind::Value(val) + if val.try_to_target_usize(self.tcx).is_none_or(|count| count > 1) => + { + self.enforce_repeat_element_needs_copy_bound(element, element_ty) + } + // If the length is 0 or 1 we don't actually copy the element, we either don't create it + // or we just use the one value. + ty::ConstKind::Value(_) => (), + + // If the length is a generic parameter or some rigid alias then conservatively + // require `element_ty: Copy` as it may wind up being `>1` after monomorphization. + ty::ConstKind::Param(_) + | ty::ConstKind::Expr(_) + | ty::ConstKind::Placeholder(_) + | ty::ConstKind::Unevaluated(_) => { + self.enforce_repeat_element_needs_copy_bound(element, element_ty) + } + + ty::ConstKind::Bound(_, _) | ty::ConstKind::Infer(_) | ty::ConstKind::Error(_) => { + unreachable!() + } } } } diff --git a/tests/ui/repeat-expr/copy-check-deferred-before-fallback.rs b/tests/ui/repeat-expr/copy-check-deferred-before-fallback.rs index 4654d7483a64d..bf519febb302c 100644 --- a/tests/ui/repeat-expr/copy-check-deferred-before-fallback.rs +++ b/tests/ui/repeat-expr/copy-check-deferred-before-fallback.rs @@ -1,5 +1,3 @@ -//@ check-pass - #![feature(generic_arg_infer)] // Test that if we defer repeat expr copy checks to end of typechecking they're @@ -37,6 +35,7 @@ fn main() { let b: [Foo<_>; 2] = [Foo(PhantomData); _]; tie(&a, b); let c = [NotCopy; _]; + //~^ ERROR: type annotations needed for `[NotCopy; _]` // a is of type `?y` // b is of type `[Foo; 2]` diff --git a/tests/ui/repeat-expr/copy-check-deferred-before-fallback.stderr b/tests/ui/repeat-expr/copy-check-deferred-before-fallback.stderr new file mode 100644 index 0000000000000..d6189329c92ad --- /dev/null +++ b/tests/ui/repeat-expr/copy-check-deferred-before-fallback.stderr @@ -0,0 +1,14 @@ +error[E0282]: type annotations needed for `[NotCopy; _]` + --> $DIR/copy-check-deferred-before-fallback.rs:37:9 + | +LL | let c = [NotCopy; _]; + | ^ ------- type must be known at this point + | +help: consider giving `c` an explicit type, where the value of const parameter `N` is specified + | +LL | let c: [_; N] = [NotCopy; _]; + | ++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/repeat-expr/copy-check-inference-side-effects.rs b/tests/ui/repeat-expr/copy-check-inference-side-effects.rs new file mode 100644 index 0000000000000..416a20169fba1 --- /dev/null +++ b/tests/ui/repeat-expr/copy-check-inference-side-effects.rs @@ -0,0 +1,34 @@ +#![feature(generic_arg_infer)] + +struct Foo; + +impl Clone for Foo<1> { + fn clone(&self) -> Self { + Self + } +} +impl Copy for Foo<1> {} + +fn unify(_: &[Foo; 2], _: &[String; N]) {} + +fn works_if_inference_side_effects() { + // This will only pass if inference side effectrs from proving `Foo: Copy` are + // able to be relied upon by other repeat expressions. + let a /* : [Foo; 2] */ = [Foo::<_>; 2]; + //~^ ERROR: type annotations needed for `[Foo<_>; 2]` + let b /* : [String; ?x] */ = ["string".to_string(); _]; + + unify(&a, &b); +} + +fn works_if_fixed_point() { + // This will only pass if the *second* array repeat expr is checked first + // allowing `Foo: Copy` to infer the array length of the first repeat expr. + let b /* : [String; ?x] */ = ["string".to_string(); _]; + //~^ ERROR: type annotations needed for `[String; _]` + let a /* : [Foo; 2] */ = [Foo::<_>; 2]; + + unify(&a, &b); +} + +fn main() {} diff --git a/tests/ui/repeat-expr/copy-check-inference-side-effects.stderr b/tests/ui/repeat-expr/copy-check-inference-side-effects.stderr new file mode 100644 index 0000000000000..505beff0f6b2e --- /dev/null +++ b/tests/ui/repeat-expr/copy-check-inference-side-effects.stderr @@ -0,0 +1,28 @@ +error[E0282]: type annotations needed for `[Foo<_>; 2]` + --> $DIR/copy-check-inference-side-effects.rs:17:9 + | +LL | let a /* : [Foo; 2] */ = [Foo::<_>; 2]; + | ^ +LL | +LL | let b /* : [String; ?x] */ = ["string".to_string(); _]; + | -------------------- type must be known at this point + | +help: consider giving `a` an explicit type, where the value of const parameter `N` is specified + | +LL | let a: [Foo; 2] /* : [Foo; 2] */ = [Foo::<_>; 2]; + | +++++++++++++ + +error[E0282]: type annotations needed for `[String; _]` + --> $DIR/copy-check-inference-side-effects.rs:27:9 + | +LL | let b /* : [String; ?x] */ = ["string".to_string(); _]; + | ^ -------------------- type must be known at this point + | +help: consider giving `b` an explicit type, where the value of const parameter `N` is specified + | +LL | let b: [_; N] /* : [String; ?x] */ = ["string".to_string(); _]; + | ++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0282`. From 52f2c45dee5211418e762789ad63e3ae56d9f3bf Mon Sep 17 00:00:00 2001 From: Boxy Date: Thu, 10 Apr 2025 13:02:07 +0100 Subject: [PATCH 2585/4206] Properly test whether repeat expr checks are pre/post integer fallback --- .../copy-check-deferred-after-fallback.rs | 64 +++++++++++------- .../copy-check-deferred-after-fallback.stderr | 12 ++-- .../copy-check-deferred-before-fallback.rs | 66 ++++++++----------- ...copy-check-deferred-before-fallback.stderr | 14 ---- 4 files changed, 74 insertions(+), 82 deletions(-) delete mode 100644 tests/ui/repeat-expr/copy-check-deferred-before-fallback.stderr diff --git a/tests/ui/repeat-expr/copy-check-deferred-after-fallback.rs b/tests/ui/repeat-expr/copy-check-deferred-after-fallback.rs index d9ad93541ecff..3f310f07de0fe 100644 --- a/tests/ui/repeat-expr/copy-check-deferred-after-fallback.rs +++ b/tests/ui/repeat-expr/copy-check-deferred-after-fallback.rs @@ -1,37 +1,53 @@ #![feature(generic_arg_infer)] -// Test that would start passing if we defer repeat expr copy checks to end of -// typechecking and they're checked after integer fallback occurs. We accomplish -// this by contriving a situation where integer fallback allows progress to be -// made on a trait goal that infers the length of a repeat expr. +// Test when deferring repeat expr copy checks to end of typechecking whether they're +// checked before integer fallback occurs or not. We accomplish this by having a repeat +// count that can only be inferred after integer fallback has occured. This test will +// pass if we were to check repeat exprs after integer fallback. use std::marker::PhantomData; - -struct NotCopy; +struct Foo(PhantomData); + +// We impl Copy/Clone for multiple (but not all) substitutions +// to ensure that `Foo: Copy` can't be proven on the basis +// of there only being one applying impl. +impl Clone for Foo { + fn clone(&self) -> Self { + Foo(PhantomData) + } +} +impl Clone for Foo { + fn clone(&self) -> Self { + Foo(PhantomData) + } +} +impl Copy for Foo {} +impl Copy for Foo {} trait Trait {} -impl Trait<2> for u32 {} +// We impl `Trait` for both `i32` and `u32` to avoid being able +// to prove `?int: Trait` from there only being one impl. impl Trait<1> for i32 {} +impl Trait<2> for u32 {} -fn make_goal, const N: usize>(_: &T, _: [NotCopy; N]) {} +fn tie_and_make_goal>(_: &T, _: &[Foo; N]) {} fn main() { let a = 1; - let b = [NotCopy; _]; - //~^ ERROR: type annotations needed - - // a is of type `?y` - // b is of type `[NotCopy; ?x]` - // there is a goal ?y: Trait` with two candidates: - // - `i32: Trait<1>`, ?y=i32 ?x=1 which doesnt require `NotCopy: Copy` - // - `u32: Trait<2>` ?y=u32 ?x=2 which requires `NotCopy: Copy` - make_goal(&a, b); - - // final repeat expr checks: - // - // `NotCopy; ?x` - // - succeeds if fallback happens before repeat exprs as `i32: Trait` infers `?x=1` - // - fails if repeat expr checks happen first as `?x` is unconstrained so cannot be - // structurally resolved + // Deferred repeat expr `Foo; ?n` + let b = [Foo(PhantomData); _]; + //~^ ERROR: type annotations needed for `[Foo<{integer}>; _]` + + // Introduces a `?int: Trait` goal + tie_and_make_goal(&a, &b); + + // If fallback doesn't occur: + // - `Foo; ?n`is ambig as repeat count is unknown -> error + + // If fallback occurs: + // - `?int` inferred to `i32` + // - `?int: Trait` becomes `i32: Trait` wihhc infers `?n=1` + // - Repeat expr check `Foo; ?n` is now `Foo; 1` + // - `Foo; 1` doesn't require `Foo: Copy` } diff --git a/tests/ui/repeat-expr/copy-check-deferred-after-fallback.stderr b/tests/ui/repeat-expr/copy-check-deferred-after-fallback.stderr index 2a0cb3fb7a394..103b074dda7c8 100644 --- a/tests/ui/repeat-expr/copy-check-deferred-after-fallback.stderr +++ b/tests/ui/repeat-expr/copy-check-deferred-after-fallback.stderr @@ -1,13 +1,13 @@ -error[E0282]: type annotations needed for `[NotCopy; _]` - --> $DIR/copy-check-deferred-after-fallback.rs:21:9 +error[E0282]: type annotations needed for `[Foo<{integer}>; _]` + --> $DIR/copy-check-deferred-after-fallback.rs:39:9 | -LL | let b = [NotCopy; _]; - | ^ ------- type must be known at this point +LL | let b = [Foo(PhantomData); _]; + | ^ ---------------- type must be known at this point | help: consider giving `b` an explicit type, where the value of const parameter `N` is specified | -LL | let b: [_; N] = [NotCopy; _]; - | ++++++++ +LL | let b: [Foo<{integer}>; N] = [Foo(PhantomData); _]; + | +++++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/repeat-expr/copy-check-deferred-before-fallback.rs b/tests/ui/repeat-expr/copy-check-deferred-before-fallback.rs index bf519febb302c..b81997a3c9fa3 100644 --- a/tests/ui/repeat-expr/copy-check-deferred-before-fallback.rs +++ b/tests/ui/repeat-expr/copy-check-deferred-before-fallback.rs @@ -1,16 +1,13 @@ +//@ check-pass #![feature(generic_arg_infer)] -// Test that if we defer repeat expr copy checks to end of typechecking they're -// checked before integer fallback occurs. We accomplish this by contriving a -// situation where we have a goal that can be proven either via another repeat expr -// check or by integer fallback. In the integer fallback case an array length would -// be inferred to `2` requiring `NotCopy: Copy`, and in the repeat expr case it would -// be inferred to `1`. +// Test when deferring repeat expr checks to end of typechecking whether they're +// checked before integer fallback occurs. We accomplish this by having the repeat +// expr check allow inference progress on an ambiguous goal, where the ambiguous goal +// would fail if the inference variable was fallen back to `i32`. This test will +// pass if wecheck repeat exprs before integer fallback. use std::marker::PhantomData; - -struct NotCopy; - struct Foo(PhantomData); impl Clone for Foo { @@ -18,41 +15,34 @@ impl Clone for Foo { Foo(PhantomData) } } - impl Copy for Foo {} -fn tie(_: &T, _: [Foo; 2]) {} - -trait Trait {} +trait Trait {} -impl Trait<2> for i32 {} -impl Trait<1> for u32 {} +// Two impls just to ensure that `?int: Trait` wont itself succeed by unifying with +// a self type on an impl here. It also ensures that integer fallback would actually +// be valid for all of the stalled goals incase that's ever something we take into account. +impl Trait for i32 {} +impl Trait for u32 {} -fn make_goal, const N: usize>(_: &T, _: [NotCopy; N]) {} +fn make_goal(_: &T) {} +fn tie(_: &T, _: &[Foo; 2]) {} fn main() { let a = 1; + // `?int: Trait` + make_goal(&a); + + // Deferred `Foo: Copy` requirement let b: [Foo<_>; 2] = [Foo(PhantomData); _]; - tie(&a, b); - let c = [NotCopy; _]; - //~^ ERROR: type annotations needed for `[NotCopy; _]` - - // a is of type `?y` - // b is of type `[Foo; 2]` - // c is of type `[NotCopy; ?x]` - // there is a goal ?y: Trait` with two candidates: - // - `i32: Trait<2>`, ?y=i32 ?x=2 which requires `NotCopy: Copy` when expr checks happen - // - `u32: Trait<1>` ?y=u32 ?x=1 which doesnt require `NotCopy: Copy` - make_goal(&a, c); - - // final repeat expr checks: - // - // `Foo; 2` - // - Foo: Copy - // - requires ?y=u32 - // - // `NotCopy; ?x` - // - fails if fallback happens before repeat exprs as `i32: Trait` infers `?x=2` - // - succeeds if repeat expr checks happen first as `?y=u32` means `u32: Trait` - // infers `?x=1` + tie(&a, &b); + + // If fallback doesn't occur: + // - `Foo; 2`is > 1, needs copy + // - `Foo: Copy` infers `?int=u32` + // - stalled goal `?int: Trait` can now make progress and succeed + + // If fallback occurs: + // - `Foo; 2` is > 1, needs copy + // - `Foo: Copy` doesn't hold -> error } diff --git a/tests/ui/repeat-expr/copy-check-deferred-before-fallback.stderr b/tests/ui/repeat-expr/copy-check-deferred-before-fallback.stderr deleted file mode 100644 index d6189329c92ad..0000000000000 --- a/tests/ui/repeat-expr/copy-check-deferred-before-fallback.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0282]: type annotations needed for `[NotCopy; _]` - --> $DIR/copy-check-deferred-before-fallback.rs:37:9 - | -LL | let c = [NotCopy; _]; - | ^ ------- type must be known at this point - | -help: consider giving `c` an explicit type, where the value of const parameter `N` is specified - | -LL | let c: [_; N] = [NotCopy; _]; - | ++++++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0282`. From 77a2fc60a11838d93df08a7a31ba47bcc828f750 Mon Sep 17 00:00:00 2001 From: Boxy Date: Thu, 10 Apr 2025 15:11:55 +0100 Subject: [PATCH 2586/4206] GAI logic on stable too --- compiler/rustc_hir_typeck/src/expr.rs | 51 +-------------- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 48 +++++++++++++- .../lang-item-generic-requirements.rs | 2 + .../lang-item-generic-requirements.stderr | 20 +++++- ...py-check-const-element-uninferred-count.rs | 65 +++++++++++++++++++ ...heck-const-element-uninferred-count.stderr | 36 ++++++++++ .../copy-inference-side-effects-are-lazy.rs | 9 +-- ...opy-inference-side-effects-are-lazy.stderr | 17 +++++ 8 files changed, 186 insertions(+), 62 deletions(-) create mode 100644 tests/ui/repeat-expr/copy-check-const-element-uninferred-count.rs create mode 100644 tests/ui/repeat-expr/copy-check-const-element-uninferred-count.stderr create mode 100644 tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.stderr diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index a1a33885b944c..de769c1166608 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1900,62 +1900,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We defer checking whether the element type is `Copy` as it is possible to have // an inference variable as a repeat count and it seems unlikely that `Copy` would // have inference side effects required for type checking to succeed. - if tcx.features().generic_arg_infer() { - self.deferred_repeat_expr_checks.borrow_mut().push((element, element_ty, count)); - // If the length is 0, we don't create any elements, so we don't copy any. - // If the length is 1, we don't copy that one element, we move it. Only check - // for `Copy` if the length is larger, or unevaluated. - } else if count.try_to_target_usize(self.tcx).is_none_or(|x| x > 1) { - self.enforce_repeat_element_needs_copy_bound(element, element_ty); - } + self.deferred_repeat_expr_checks.borrow_mut().push((element, element_ty, count)); let ty = Ty::new_array_with_const_len(tcx, t, count); self.register_wf_obligation(ty.into(), expr.span, ObligationCauseCode::WellFormed(None)); ty } - /// Requires that `element_ty` is `Copy` (unless it's a const expression itself). - pub(super) fn enforce_repeat_element_needs_copy_bound( - &self, - element: &hir::Expr<'_>, - element_ty: Ty<'tcx>, - ) { - let tcx = self.tcx; - // Actual constants as the repeat element get inserted repeatedly instead of getting copied via Copy. - match &element.kind { - hir::ExprKind::ConstBlock(..) => return, - hir::ExprKind::Path(qpath) => { - let res = self.typeck_results.borrow().qpath_res(qpath, element.hir_id); - if let Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::AnonConst, _) = res - { - return; - } - } - _ => {} - } - // If someone calls a const fn or constructs a const value, they can extract that - // out into a separate constant (or a const block in the future), so we check that - // to tell them that in the diagnostic. Does not affect typeck. - let is_constable = match element.kind { - hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() { - ty::FnDef(def_id, _) if tcx.is_stable_const_fn(def_id) => traits::IsConstable::Fn, - _ => traits::IsConstable::No, - }, - hir::ExprKind::Path(qpath) => { - match self.typeck_results.borrow().qpath_res(&qpath, element.hir_id) { - Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => traits::IsConstable::Ctor, - _ => traits::IsConstable::No, - } - } - _ => traits::IsConstable::No, - }; - - let lang_item = self.tcx.require_lang_item(LangItem::Copy, None); - let code = - traits::ObligationCauseCode::RepeatElementCopy { is_constable, elt_span: element.span }; - self.require_type_meets(element_ty, element.span, code, lang_item); - } - fn check_expr_tuple( &self, elts: &'tcx [hir::Expr<'tcx>], diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 533b5b2be7981..7a0b4c22a19ae 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -4,10 +4,10 @@ use itertools::Itertools; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, a_or_an, listify, pluralize}; -use rustc_hir::def::{CtorOf, DefKind, Res}; +use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; -use rustc_hir::{ExprKind, HirId, Node, QPath}; +use rustc_hir::{ExprKind, HirId, LangItem, Node, QPath}; use rustc_hir_analysis::check::potentially_plural_count; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_index::IndexVec; @@ -155,6 +155,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + /// Requires that `element_ty` is `Copy` (unless it's a const expression itself). + pub(super) fn enforce_repeat_element_needs_copy_bound( + &self, + element: &hir::Expr<'_>, + element_ty: Ty<'tcx>, + ) { + // Actual constants as the repeat element get inserted repeatedly instead of getting copied via Copy. + match &element.kind { + hir::ExprKind::ConstBlock(..) => return, + hir::ExprKind::Path(qpath) => { + let res = self.typeck_results.borrow().qpath_res(qpath, element.hir_id); + if let Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::AnonConst, _) = res + { + return; + } + } + _ => {} + } + + // If someone calls a const fn or constructs a const value, they can extract that + // out into a separate constant (or a const block in the future), so we check that + // to tell them that in the diagnostic. Does not affect typeck. + let is_constable = match element.kind { + hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() { + ty::FnDef(def_id, _) if self.tcx.is_stable_const_fn(def_id) => { + traits::IsConstable::Fn + } + _ => traits::IsConstable::No, + }, + hir::ExprKind::Path(qpath) => { + match self.typeck_results.borrow().qpath_res(&qpath, element.hir_id) { + Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => traits::IsConstable::Ctor, + _ => traits::IsConstable::No, + } + } + _ => traits::IsConstable::No, + }; + + let lang_item = self.tcx.require_lang_item(LangItem::Copy, None); + let code = + traits::ObligationCauseCode::RepeatElementCopy { is_constable, elt_span: element.span }; + self.require_type_meets(element_ty, element.span, code, lang_item); + } + /// Generic function that factors out common logic from function calls, /// method calls and overloaded operators. pub(in super::super) fn check_argument_types( diff --git a/tests/ui/lang-items/lang-item-generic-requirements.rs b/tests/ui/lang-items/lang-item-generic-requirements.rs index 90ed5f3f0efd0..7676b5557d22b 100644 --- a/tests/ui/lang-items/lang-item-generic-requirements.rs +++ b/tests/ui/lang-items/lang-item-generic-requirements.rs @@ -49,12 +49,14 @@ fn ice() { // Use index let arr = [0; 5]; let _ = arr[2]; + //~^ ERROR cannot index into a value of type `[{integer}; 5]` // Use phantomdata let _ = MyPhantomData::<(), i32>; // Use Foo let _: () = Foo; + //~^ ERROR mismatched types } // use `start` diff --git a/tests/ui/lang-items/lang-item-generic-requirements.stderr b/tests/ui/lang-items/lang-item-generic-requirements.stderr index 3de67d6594035..409fa05d6371a 100644 --- a/tests/ui/lang-items/lang-item-generic-requirements.stderr +++ b/tests/ui/lang-items/lang-item-generic-requirements.stderr @@ -76,9 +76,23 @@ LL | r + a; | | | {integer} +error[E0608]: cannot index into a value of type `[{integer}; 5]` + --> $DIR/lang-item-generic-requirements.rs:51:16 + | +LL | let _ = arr[2]; + | ^^^ + +error[E0308]: mismatched types + --> $DIR/lang-item-generic-requirements.rs:58:17 + | +LL | let _: () = Foo; + | -- ^^^ expected `()`, found `Foo` + | | + | expected due to this + error: requires `copy` lang_item -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors -Some errors have detailed explanations: E0369, E0392, E0718. -For more information about an error, try `rustc --explain E0369`. +Some errors have detailed explanations: E0308, E0369, E0392, E0608, E0718. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/repeat-expr/copy-check-const-element-uninferred-count.rs b/tests/ui/repeat-expr/copy-check-const-element-uninferred-count.rs new file mode 100644 index 0000000000000..8ef0c2690ba0e --- /dev/null +++ b/tests/ui/repeat-expr/copy-check-const-element-uninferred-count.rs @@ -0,0 +1,65 @@ +#![feature(generic_arg_infer)] + +// Test when deferring repeat expr copy checks to end of typechecking whether elements +// that are const items allow for repeat counts to go uninferred without an error being +// emitted if they would later wind up inferred by integer fallback. +// +// This test should be updated if we wind up deferring repeat expr checks until *after* +// integer fallback as the point of the test is not *specifically* about integer fallback +// but rather about the behaviour of `const` element exprs. + +trait Trait {} + +// We impl `Trait` for both `i32` and `u32` to avoid being able +// to prove `?int: Trait` from there only being one impl. +impl Trait<2> for i32 {} +impl Trait<2> for u32 {} + +fn tie_and_make_goal>(_: &T, _: &[String; N]) {} + +fn const_block() { + // Deferred repeat expr `String; ?n` + let a = [const { String::new() }; _]; + //~^ ERROR: type annotations needed for `[String; _]` + + // `?int: Trait` goal + tie_and_make_goal(&1, &a); + + // If repeat expr checks structurally resolve the `?n`s before checking if the + // element is a `const` then we would error here. Otherwise we avoid doing so, + // integer fallback occurs, allowing `?int: Trait` goals to make progress, + // inferring the repeat counts (to `2` but that doesn't matter as the element is `const`). +} + +fn const_item() { + const MY_CONST: String = String::new(); + + // Deferred repeat expr `String; ?n` + let a = [MY_CONST; _]; + //~^ ERROR: type annotations needed for `[String; _]` + + // `?int: Trait` goal + tie_and_make_goal(&1, &a); + + // ... same as `const_block` +} + +fn assoc_const() { + trait Dummy { + const ASSOC: String; + } + impl Dummy for () { + const ASSOC: String = String::new(); + } + + // Deferred repeat expr `String; ?n` + let a = [<() as Dummy>::ASSOC; _]; + //~^ ERROR: type annotations needed for `[String; _]` + + // `?int: Trait` goal + tie_and_make_goal(&1, &a); + + // ... same as `const_block` +} + +fn main() {} diff --git a/tests/ui/repeat-expr/copy-check-const-element-uninferred-count.stderr b/tests/ui/repeat-expr/copy-check-const-element-uninferred-count.stderr new file mode 100644 index 0000000000000..8229b0b2b3794 --- /dev/null +++ b/tests/ui/repeat-expr/copy-check-const-element-uninferred-count.stderr @@ -0,0 +1,36 @@ +error[E0282]: type annotations needed for `[String; _]` + --> $DIR/copy-check-const-element-uninferred-count.rs:22:9 + | +LL | let a = [const { String::new() }; _]; + | ^ ----------------------- type must be known at this point + | +help: consider giving `a` an explicit type, where the value of const parameter `N` is specified + | +LL | let a: [_; N] = [const { String::new() }; _]; + | ++++++++ + +error[E0282]: type annotations needed for `[String; _]` + --> $DIR/copy-check-const-element-uninferred-count.rs:38:9 + | +LL | let a = [MY_CONST; _]; + | ^ -------- type must be known at this point + | +help: consider giving `a` an explicit type, where the value of const parameter `N` is specified + | +LL | let a: [_; N] = [MY_CONST; _]; + | ++++++++ + +error[E0282]: type annotations needed for `[String; _]` + --> $DIR/copy-check-const-element-uninferred-count.rs:56:9 + | +LL | let a = [<() as Dummy>::ASSOC; _]; + | ^ -------------------- type must be known at this point + | +help: consider giving `a` an explicit type, where the value of const parameter `N` is specified + | +LL | let a: [_; N] = [<() as Dummy>::ASSOC; _]; + | ++++++++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.rs b/tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.rs index 0b0672d9c2b56..d50466ac4bbd8 100644 --- a/tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.rs +++ b/tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.rs @@ -1,8 +1,3 @@ -//@revisions: current gai -//@[current] check-pass - -#![cfg_attr(gai, feature(generic_arg_infer))] - use std::marker::PhantomData; struct Foo(PhantomData); @@ -20,6 +15,6 @@ fn extract(_: [Foo; N]) -> T { fn main() { let x = [Foo(PhantomData); 2]; - //[gai]~^ ERROR: type annotations needed - _ = extract(x).max(2); + //~^ ERROR: type annotations needed + extract(x).max(2); } diff --git a/tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.stderr b/tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.stderr new file mode 100644 index 0000000000000..ba44beb76dbb7 --- /dev/null +++ b/tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.stderr @@ -0,0 +1,17 @@ +error[E0282]: type annotations needed for `[Foo<_>; 2]` + --> $DIR/copy-inference-side-effects-are-lazy.rs:17:9 + | +LL | let x = [Foo(PhantomData); 2]; + | ^ +LL | +LL | extract(x).max(2); + | ---------- type must be known at this point + | +help: consider giving `x` an explicit type, where the type for type parameter `T` is specified + | +LL | let x: [Foo; 2] = [Foo(PhantomData); 2]; + | +++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. From 508a9f085393a1e348725ca7f169780c65dbc212 Mon Sep 17 00:00:00 2001 From: Boxy Date: Thu, 10 Apr 2025 15:30:28 +0100 Subject: [PATCH 2587/4206] Check for element being `const` before resolving repeat count --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 95 +++++++++---------- ...py-check-const-element-uninferred-count.rs | 13 ++- ...heck-const-element-uninferred-count.stderr | 37 ++------ 3 files changed, 65 insertions(+), 80 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 7a0b4c22a19ae..dc6a9dc93d07a 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -108,6 +108,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let deferred_repeat_expr_checks = deferred_repeat_expr_checks .drain(..) .flat_map(|(element, element_ty, count)| { + // Actual constants as the repeat element get inserted repeatedly instead of getting copied via Copy + // so we don't need to attempt to structurally resolve the repeat count which may unnecessarily error. + match &element.kind { + hir::ExprKind::ConstBlock(..) => return None, + hir::ExprKind::Path(qpath) => { + let res = self.typeck_results.borrow().qpath_res(qpath, element.hir_id); + if let Res::Def( + DefKind::Const | DefKind::AssocConst | DefKind::AnonConst, + _, + ) = res + { + return None; + } + } + _ => {} + } + // We want to emit an error if the const is not structurally resolveable as otherwise // we can find up conservatively proving `Copy` which may infer the repeat expr count // to something that never required `Copy` in the first place. @@ -128,12 +145,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // expr's `Copy` check. .collect::>(); + let enforce_copy_bound = |element: &hir::Expr<'_>, element_ty| { + // If someone calls a const fn or constructs a const value, they can extract that + // out into a separate constant (or a const block in the future), so we check that + // to tell them that in the diagnostic. Does not affect typeck. + let is_constable = match element.kind { + hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() { + ty::FnDef(def_id, _) if self.tcx.is_stable_const_fn(def_id) => { + traits::IsConstable::Fn + } + _ => traits::IsConstable::No, + }, + hir::ExprKind::Path(qpath) => { + match self.typeck_results.borrow().qpath_res(&qpath, element.hir_id) { + Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => traits::IsConstable::Ctor, + _ => traits::IsConstable::No, + } + } + _ => traits::IsConstable::No, + }; + + let lang_item = self.tcx.require_lang_item(LangItem::Copy, None); + let code = traits::ObligationCauseCode::RepeatElementCopy { + is_constable, + elt_span: element.span, + }; + self.require_type_meets(element_ty, element.span, code, lang_item); + }; + for (element, element_ty, count) in deferred_repeat_expr_checks { match count.kind() { ty::ConstKind::Value(val) if val.try_to_target_usize(self.tcx).is_none_or(|count| count > 1) => { - self.enforce_repeat_element_needs_copy_bound(element, element_ty) + enforce_copy_bound(element, element_ty) } // If the length is 0 or 1 we don't actually copy the element, we either don't create it // or we just use the one value. @@ -144,9 +189,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::ConstKind::Param(_) | ty::ConstKind::Expr(_) | ty::ConstKind::Placeholder(_) - | ty::ConstKind::Unevaluated(_) => { - self.enforce_repeat_element_needs_copy_bound(element, element_ty) - } + | ty::ConstKind::Unevaluated(_) => enforce_copy_bound(element, element_ty), ty::ConstKind::Bound(_, _) | ty::ConstKind::Infer(_) | ty::ConstKind::Error(_) => { unreachable!() @@ -155,50 +198,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - /// Requires that `element_ty` is `Copy` (unless it's a const expression itself). - pub(super) fn enforce_repeat_element_needs_copy_bound( - &self, - element: &hir::Expr<'_>, - element_ty: Ty<'tcx>, - ) { - // Actual constants as the repeat element get inserted repeatedly instead of getting copied via Copy. - match &element.kind { - hir::ExprKind::ConstBlock(..) => return, - hir::ExprKind::Path(qpath) => { - let res = self.typeck_results.borrow().qpath_res(qpath, element.hir_id); - if let Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::AnonConst, _) = res - { - return; - } - } - _ => {} - } - - // If someone calls a const fn or constructs a const value, they can extract that - // out into a separate constant (or a const block in the future), so we check that - // to tell them that in the diagnostic. Does not affect typeck. - let is_constable = match element.kind { - hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() { - ty::FnDef(def_id, _) if self.tcx.is_stable_const_fn(def_id) => { - traits::IsConstable::Fn - } - _ => traits::IsConstable::No, - }, - hir::ExprKind::Path(qpath) => { - match self.typeck_results.borrow().qpath_res(&qpath, element.hir_id) { - Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => traits::IsConstable::Ctor, - _ => traits::IsConstable::No, - } - } - _ => traits::IsConstable::No, - }; - - let lang_item = self.tcx.require_lang_item(LangItem::Copy, None); - let code = - traits::ObligationCauseCode::RepeatElementCopy { is_constable, elt_span: element.span }; - self.require_type_meets(element_ty, element.span, code, lang_item); - } - /// Generic function that factors out common logic from function calls, /// method calls and overloaded operators. pub(in super::super) fn check_argument_types( diff --git a/tests/ui/repeat-expr/copy-check-const-element-uninferred-count.rs b/tests/ui/repeat-expr/copy-check-const-element-uninferred-count.rs index 8ef0c2690ba0e..6115146539c19 100644 --- a/tests/ui/repeat-expr/copy-check-const-element-uninferred-count.rs +++ b/tests/ui/repeat-expr/copy-check-const-element-uninferred-count.rs @@ -20,7 +20,6 @@ fn tie_and_make_goal>(_: &T, _: &[String; N]) {} fn const_block() { // Deferred repeat expr `String; ?n` let a = [const { String::new() }; _]; - //~^ ERROR: type annotations needed for `[String; _]` // `?int: Trait` goal tie_and_make_goal(&1, &a); @@ -36,7 +35,6 @@ fn const_item() { // Deferred repeat expr `String; ?n` let a = [MY_CONST; _]; - //~^ ERROR: type annotations needed for `[String; _]` // `?int: Trait` goal tie_and_make_goal(&1, &a); @@ -54,7 +52,6 @@ fn assoc_const() { // Deferred repeat expr `String; ?n` let a = [<() as Dummy>::ASSOC; _]; - //~^ ERROR: type annotations needed for `[String; _]` // `?int: Trait` goal tie_and_make_goal(&1, &a); @@ -62,4 +59,14 @@ fn assoc_const() { // ... same as `const_block` } +fn const_block_but_uninferred() { + // Deferred repeat expr `String; ?n` + let a = [const { String::new() }; _]; + //~^ ERROR: type annotations needed for `[String; _]` + + // Even if we don't structurally resolve the repeat count as part of repeat expr + // checks, we still error on the repeat count being uninferred as we require all + // types/consts to be inferred by the end of type checking. +} + fn main() {} diff --git a/tests/ui/repeat-expr/copy-check-const-element-uninferred-count.stderr b/tests/ui/repeat-expr/copy-check-const-element-uninferred-count.stderr index 8229b0b2b3794..2f52537fa9407 100644 --- a/tests/ui/repeat-expr/copy-check-const-element-uninferred-count.stderr +++ b/tests/ui/repeat-expr/copy-check-const-element-uninferred-count.stderr @@ -1,36 +1,15 @@ -error[E0282]: type annotations needed for `[String; _]` - --> $DIR/copy-check-const-element-uninferred-count.rs:22:9 +error[E0284]: type annotations needed for `[String; _]` + --> $DIR/copy-check-const-element-uninferred-count.rs:64:9 | LL | let a = [const { String::new() }; _]; - | ^ ----------------------- type must be known at this point + | ^ ---------------------------- type must be known at this point | -help: consider giving `a` an explicit type, where the value of const parameter `N` is specified + = note: the length of array `[String; _]` must be type `usize` +help: consider giving `a` an explicit type, where the placeholders `_` are specified | -LL | let a: [_; N] = [const { String::new() }; _]; +LL | let a: [_; _] = [const { String::new() }; _]; | ++++++++ -error[E0282]: type annotations needed for `[String; _]` - --> $DIR/copy-check-const-element-uninferred-count.rs:38:9 - | -LL | let a = [MY_CONST; _]; - | ^ -------- type must be known at this point - | -help: consider giving `a` an explicit type, where the value of const parameter `N` is specified - | -LL | let a: [_; N] = [MY_CONST; _]; - | ++++++++ - -error[E0282]: type annotations needed for `[String; _]` - --> $DIR/copy-check-const-element-uninferred-count.rs:56:9 - | -LL | let a = [<() as Dummy>::ASSOC; _]; - | ^ -------------------- type must be known at this point - | -help: consider giving `a` an explicit type, where the value of const parameter `N` is specified - | -LL | let a: [_; N] = [<() as Dummy>::ASSOC; _]; - | ++++++++ - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0284`. From 43162597292f904ff5ff47e251ba40fb9ae41ded Mon Sep 17 00:00:00 2001 From: Boxy Date: Mon, 14 Apr 2025 13:38:37 +0100 Subject: [PATCH 2588/4206] Anon consts cant appear as repeat expr elements --- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index dc6a9dc93d07a..124b6e80fd44d 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -114,11 +114,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::ExprKind::ConstBlock(..) => return None, hir::ExprKind::Path(qpath) => { let res = self.typeck_results.borrow().qpath_res(qpath, element.hir_id); - if let Res::Def( - DefKind::Const | DefKind::AssocConst | DefKind::AnonConst, - _, - ) = res - { + if let Res::Def(DefKind::Const | DefKind::AssocConst, _) = res { return None; } } From 8cdfabd230282f11a04de6d638546bf52ba0bf24 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Wed, 21 May 2025 19:43:45 +0000 Subject: [PATCH 2589/4206] rustdoc-json: Remove false docs and add test for inline attribute The docs about how `#[inline]` was represented isn't true. Updates the comment, and adds a test. CC https://www.github.com/rust-lang/rust/issues/137645 --- src/rustdoc-json-types/lib.rs | 8 +------- tests/rustdoc-json/attrs/inline.rs | 11 +++++++++++ 2 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 tests/rustdoc-json/attrs/inline.rs diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 64223b5b75896..0b8a906529466 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -180,19 +180,13 @@ pub struct Item { /// /// Does not include `#[deprecated]` attributes: see the [`Self::deprecation`] field instead. /// - /// Some attributes appear in pretty-printed Rust form, regardless of their formatting + /// Attributes appear in pretty-printed Rust form, regardless of their formatting /// in the original source code. For example: /// - `#[non_exhaustive]` and `#[must_use]` are represented as themselves. /// - `#[no_mangle]` and `#[export_name]` are also represented as themselves. /// - `#[repr(C)]` and other reprs also appear as themselves, /// though potentially with a different order: e.g. `repr(i8, C)` may become `repr(C, i8)`. /// Multiple repr attributes on the same item may be combined into an equivalent single attr. - /// - /// Other attributes may appear debug-printed. For example: - /// - `#[inline]` becomes something similar to `#[attr="Inline(Hint)"]`. - /// - /// As an internal implementation detail subject to change, this debug-printing format - /// is currently equivalent to the HIR pretty-printing of parsed attributes. pub attrs: Vec, /// Information about the item’s deprecation, if present. pub deprecation: Option, diff --git a/tests/rustdoc-json/attrs/inline.rs b/tests/rustdoc-json/attrs/inline.rs new file mode 100644 index 0000000000000..74f5f36f03f3b --- /dev/null +++ b/tests/rustdoc-json/attrs/inline.rs @@ -0,0 +1,11 @@ +//@ is "$.index[?(@.name=='just_inline')].attrs" '["#[inline]"]' +#[inline] +pub fn just_inline() {} + +//@ is "$.index[?(@.name=='inline_always')].attrs" '["#[inline(always)]"]' +#[inline(always)] +pub fn inline_always() {} + +//@ is "$.index[?(@.name=='inline_never')].attrs" '["#[inline(never)]"]' +#[inline(never)] +pub fn inline_never() {} From ca912d794d42336ddd54389480b56bfc2bc6685f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 21 May 2025 14:55:47 +0000 Subject: [PATCH 2590/4206] Make captures state error more precise --- .../src/error_reporting/traits/fulfillment_errors.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) 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 970160ba212af..7d8c4df6341c4 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 @@ -841,16 +841,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return None; }; - let (closure_def_id, found_args, by_ref_captures) = match *self_ty.kind() { + let (closure_def_id, found_args, has_self_borrows) = match *self_ty.kind() { ty::Closure(def_id, args) => { - (def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), None) + (def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), false) } ty::CoroutineClosure(def_id, args) => ( def_id, args.as_coroutine_closure() .coroutine_closure_sig() .map_bound(|sig| sig.tupled_inputs_ty), - Some(args.as_coroutine_closure().coroutine_captures_by_ref_ty()), + !args.as_coroutine_closure().tupled_upvars_ty().is_ty_var() + && args.as_coroutine_closure().has_self_borrows(), ), _ => return None, }; @@ -884,10 +885,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // If the closure has captures, then perhaps the reason that the trait // is unimplemented is because async closures don't implement `Fn`/`FnMut` // if they have captures. - if let Some(by_ref_captures) = by_ref_captures - && let ty::FnPtr(sig_tys, _) = by_ref_captures.kind() - && !sig_tys.skip_binder().output().is_unit() - { + if has_self_borrows && expected_kind != ty::ClosureKind::FnOnce { let mut err = self.dcx().create_err(AsyncClosureNotFn { span: self.tcx.def_span(closure_def_id), kind: expected_kind.as_str(), From e0f80558716372902b2eda1e43ab2e169bfb3669 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 21 May 2025 18:07:29 +0000 Subject: [PATCH 2591/4206] Fix FnOnce impl for AsyncFn/AsyncFnMut closures in new solver --- .../src/solve/assembly/structural_traits.rs | 2 +- .../async-closures/async-fn-mut-impl-fn-once.rs | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/ui/async-await/async-closures/async-fn-mut-impl-fn-once.rs diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 2a2b462a36cbd..26ad72bea806c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -327,7 +327,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable(_: impl FnOnce() -> F) {} + +fn main() { + let mut i = 0; + let c = async || { + i += 1; + }; + call_once(c); +} From 82160c49a3f102e7f485c491408f8813196f780d Mon Sep 17 00:00:00 2001 From: michal kostrubiec Date: Tue, 20 May 2025 21:30:22 +0200 Subject: [PATCH 2592/4206] Changes to constant handling - faster deduplication, more compact representation --- src/common.rs | 84 ++++++++++++++++++++++++++++++++++++++++++++------ src/consts.rs | 24 +++++++-------- src/context.rs | 5 +++ 3 files changed, 90 insertions(+), 23 deletions(-) diff --git a/src/common.rs b/src/common.rs index 918195364ffee..cfa951ddf4b70 100644 --- a/src/common.rs +++ b/src/common.rs @@ -9,7 +9,6 @@ use rustc_middle::mir::Mutability; use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; use rustc_middle::ty::layout::LayoutOf; -use crate::consts::const_alloc_to_gcc; use crate::context::CodegenCx; use crate::type_of::LayoutGccExt; @@ -46,12 +45,65 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> RValue<'gcc> { - let context = &cx.context; - let byte_type = context.new_type::(); - let typ = context.new_array_type(None, byte_type, bytes.len() as u64); - let elements: Vec<_> = - bytes.iter().map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32)).collect(); - context.new_array_constructor(None, typ, &elements) + // Instead of always using an array of bytes, use an array of larger integers of target endianness + // if possible. This reduces the amount of `rvalues` we use, which reduces memory usage significantly. + // + // FIXME(FractalFir): Consider using `global_set_initializer` instead. Before this is done, we need to confirm that + // `global_set_initializer` is more memory efficient than the current solution. + // `global_set_initializer` calls `global_set_initializer_rvalue` under the hood - does it generate an array of rvalues, + // or is it using a more efficient representation? + match bytes.len() % 8 { + 0 => { + let context = &cx.context; + let byte_type = context.new_type::(); + let typ = context.new_array_type(None, byte_type, bytes.len() as u64 / 8); + let elements: Vec<_> = bytes + .chunks_exact(8) + .map(|arr| { + let arr: [u8; 8] = arr.try_into().unwrap(); + context.new_rvalue_from_long( + byte_type, + // Since we are representing arbitrary byte runs as integers, we need to follow the target + // endianness. + match cx.sess().target.options.endian { + rustc_abi::Endian::Little => u64::from_le_bytes(arr) as i64, + rustc_abi::Endian::Big => u64::from_be_bytes(arr) as i64, + }, + ) + }) + .collect(); + context.new_array_constructor(None, typ, &elements) + } + 4 => { + let context = &cx.context; + let byte_type = context.new_type::(); + let typ = context.new_array_type(None, byte_type, bytes.len() as u64 / 4); + let elements: Vec<_> = bytes + .chunks_exact(4) + .map(|arr| { + let arr: [u8; 4] = arr.try_into().unwrap(); + context.new_rvalue_from_int( + byte_type, + match cx.sess().target.options.endian { + rustc_abi::Endian::Little => u32::from_le_bytes(arr) as i32, + rustc_abi::Endian::Big => u32::from_be_bytes(arr) as i32, + }, + ) + }) + .collect(); + context.new_array_constructor(None, typ, &elements) + } + _ => { + let context = cx.context; + let byte_type = context.new_type::(); + let typ = context.new_array_type(None, byte_type, bytes.len() as u64); + let elements: Vec<_> = bytes + .iter() + .map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32)) + .collect(); + context.new_array_constructor(None, typ, &elements) + } + } } pub fn type_is_pointer(typ: Type<'_>) -> bool { @@ -212,7 +264,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { let alloc_id = prov.alloc_id(); let base_addr = match self.tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => { - let init = const_alloc_to_gcc(self, alloc); + let init = self.const_data_from_alloc(alloc); let alloc = alloc.inner(); let value = match alloc.mutability { Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None), @@ -234,7 +286,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { }), ))) .unwrap_memory(); - let init = const_alloc_to_gcc(self, alloc); + let init = self.const_data_from_alloc(alloc); self.static_addr_of(init, alloc.inner().align, None) } GlobalAlloc::Static(def_id) => { @@ -257,7 +309,19 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { } fn const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value { - const_alloc_to_gcc(self, alloc) + // We ignore the alignment for the purpose of deduping RValues + // The alignment is not handled / used in any way by `const_alloc_to_gcc`, + // so it is OK to overwrite it here. + let mut mock_alloc = alloc.inner().clone(); + mock_alloc.align = rustc_abi::Align::MAX; + // Check if the rvalue is already in the cache - if so, just return it directly. + if let Some(res) = self.const_cache.borrow().get(&mock_alloc) { + return *res; + } + // Rvalue not in the cache - convert and add it. + let res = crate::consts::const_alloc_to_gcc_uncached(self, alloc); + self.const_cache.borrow_mut().insert(mock_alloc, res); + res } fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value { diff --git a/src/consts.rs b/src/consts.rs index 033afc0f8fbf4..73d3beede7f63 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -42,18 +42,14 @@ fn set_global_alignment<'gcc, 'tcx>( impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'gcc, 'tcx> { fn static_addr_of(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> { - // TODO(antoyo): implement a proper rvalue comparison in libgccjit instead of doing the - // following: - for (value, variable) in &*self.const_globals.borrow() { - if format!("{:?}", value) == format!("{:?}", cv) { - if let Some(global_variable) = self.global_lvalues.borrow().get(variable) { - let alignment = align.bits() as i32; - if alignment > global_variable.get_alignment() { - global_variable.set_alignment(alignment); - } + if let Some(variable) = self.const_globals.borrow().get(&cv) { + if let Some(global_variable) = self.global_lvalues.borrow().get(variable) { + let alignment = align.bits() as i32; + if alignment > global_variable.get_alignment() { + global_variable.set_alignment(alignment); } - return *variable; } + return *variable; } let global_value = self.static_addr_of_mut(cv, align, kind); #[cfg(feature = "master")] @@ -299,8 +295,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { global } } - -pub fn const_alloc_to_gcc<'gcc>( +/// Converts a given const alloc to a gcc Rvalue, without any caching or deduplication. +/// YOU SHOULD NOT call this function directly - that may break the semantics of Rust. +/// Use `const_data_from_alloc` instead. +pub(crate) fn const_alloc_to_gcc_uncached<'gcc>( cx: &CodegenCx<'gcc, '_>, alloc: ConstAllocation<'_>, ) -> RValue<'gcc> { @@ -371,7 +369,7 @@ fn codegen_static_initializer<'gcc, 'tcx>( def_id: DefId, ) -> Result<(RValue<'gcc>, ConstAllocation<'tcx>), ErrorHandled> { let alloc = cx.tcx.eval_static_initializer(def_id)?; - Ok((const_alloc_to_gcc(cx, alloc), alloc)) + Ok((cx.const_data_from_alloc(alloc), alloc)) } fn check_and_apply_linkage<'gcc, 'tcx>( diff --git a/src/context.rs b/src/context.rs index 73718994e6417..10494a4be55b5 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,4 +1,5 @@ use std::cell::{Cell, RefCell}; +use std::collections::HashMap; use gccjit::{ Block, CType, Context, Function, FunctionPtrType, FunctionType, LValue, Location, RValue, Type, @@ -9,6 +10,7 @@ use rustc_codegen_ssa::errors as ssa_errors; use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeCodegenMethods, MiscCodegenMethods}; use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_middle::mir::interpret::Allocation; use rustc_middle::mir::mono::CodegenUnit; use rustc_middle::span_bug; use rustc_middle::ty::layout::{ @@ -30,6 +32,8 @@ use crate::common::SignType; #[cfg_attr(not(feature = "master"), allow(dead_code))] pub struct CodegenCx<'gcc, 'tcx> { + /// A cache of converted ConstAllocs + pub const_cache: RefCell>>, pub codegen_unit: &'tcx CodegenUnit<'tcx>, pub context: &'gcc Context<'gcc>, @@ -222,6 +226,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } let mut cx = Self { + const_cache: Default::default(), codegen_unit, context, current_func: RefCell::new(None), From cff790c98e9601281accf86f9c80cf894727564b Mon Sep 17 00:00:00 2001 From: waffle Date: Wed, 21 May 2025 23:43:57 +0200 Subject: [PATCH 2593/4206] add doc alias `replace_first` for `str::replacen` --- library/alloc/src/str.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 8766fd904b074..f1b1734b8b2d0 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -320,6 +320,7 @@ impl str { /// ``` #[cfg(not(no_global_oom_handling))] #[rustc_allow_incoherent_impl] + #[doc(alias = "replace_first")] #[must_use = "this returns the replaced string as a new allocation, \ without modifying the original"] #[stable(feature = "str_replacen", since = "1.16.0")] From acff5d36cc4553bfb59a76d41e51020116ce4c6c Mon Sep 17 00:00:00 2001 From: blyxyas Date: Wed, 21 May 2025 23:42:38 +0200 Subject: [PATCH 2594/4206] Review comments & Add testing --- clippy_lints/src/doc/markdown.rs | 24 +++---- tests/ui/doc/doc_markdown-issue_13097.fixed | 36 ++++++++-- tests/ui/doc/doc_markdown-issue_13097.rs | 36 ++++++++-- tests/ui/doc/doc_markdown-issue_13097.stderr | 74 ++++++++++++++++++-- 4 files changed, 138 insertions(+), 32 deletions(-) diff --git a/clippy_lints/src/doc/markdown.rs b/clippy_lints/src/doc/markdown.rs index e40b4e20ea452..69c3b9150c300 100644 --- a/clippy_lints/src/doc/markdown.rs +++ b/clippy_lints/src/doc/markdown.rs @@ -7,7 +7,7 @@ use rustc_span::{BytePos, Pos, Span}; use url::Url; use crate::doc::{DOC_MARKDOWN, Fragments}; -use std::ops::{ControlFlow, Range}; +use std::ops::Range; pub fn check( cx: &LateContext<'_>, @@ -70,7 +70,7 @@ pub fn check( let fragment_offset = word.as_ptr() as usize - text.as_ptr() as usize; // Adjust for the current word - if check_word( + check_word( cx, word, fragments, @@ -78,11 +78,7 @@ pub fn check( fragment_offset, code_level, blockquote_level, - ) - .is_break() - { - return; - } + ); } } @@ -94,10 +90,10 @@ fn check_word( fragment_offset: usize, code_level: isize, blockquote_level: isize, -) -> ControlFlow<()> { +) { /// Checks if a string is upper-camel-case, i.e., starts with an uppercase and /// contains at least two uppercase letters (`Clippy` is ok) and one lower-case - /// letter (`NASA` is ok).[ + /// letter (`NASA` is ok). /// Plurals are also excluded (`IDs` is ok). fn is_camel_case(s: &str) -> bool { if s.starts_with(|c: char| c.is_ascii_digit() | c.is_ascii_lowercase()) { @@ -135,9 +131,8 @@ fn check_word( && !url.cannot_be_a_base() { let Some(fragment_span) = fragments.span(cx, range.clone()) else { - return ControlFlow::Break(()); + return; }; - let span = Span::new( fragment_span.lo() + BytePos::from_usize(fragment_offset), fragment_span.lo() + BytePos::from_usize(fragment_offset + word.len()), @@ -154,19 +149,19 @@ fn check_word( format!("<{word}>"), Applicability::MachineApplicable, ); - return ControlFlow::Continue(()); + return; } // We assume that mixed-case words are not meant to be put inside backticks. (Issue #2343) // // We also assume that backticks are not necessary if inside a quote. (Issue #10262) if code_level > 0 || blockquote_level > 0 || (has_underscore(word) && has_hyphen(word)) { - return ControlFlow::Break(()); + return; } if has_underscore(word) || word.contains("::") || is_camel_case(word) || word.ends_with("()") { let Some(fragment_span) = fragments.span(cx, range.clone()) else { - return ControlFlow::Break(()); + return; }; let span = Span::new( @@ -188,5 +183,4 @@ fn check_word( }, ); } - ControlFlow::Continue(()) } diff --git a/tests/ui/doc/doc_markdown-issue_13097.fixed b/tests/ui/doc/doc_markdown-issue_13097.fixed index fb0f40b34a4b8..e0136584f3deb 100644 --- a/tests/ui/doc/doc_markdown-issue_13097.fixed +++ b/tests/ui/doc/doc_markdown-issue_13097.fixed @@ -1,11 +1,37 @@ -// This test checks that words starting with capital letters and ending with "ified" don't -// trigger the lint. - #![deny(clippy::doc_markdown)] +#![allow(clippy::doc_lazy_continuation)] + +mod issue13097 { + // This test checks that words starting with capital letters and ending with "ified" don't + // trigger the lint. + pub enum OutputFormat { + /// `HumaNified` + //~^ ERROR: item in documentation is missing backticks + Plain, + // Should not warn! + /// JSONified console output + Json, + } +} +#[rustfmt::skip] pub enum OutputFormat { - /// `HumaNified` - //~^ ERROR: item in documentation is missing backticks + /** + * `HumaNified` + //~^ ERROR: item in documentation is missing backticks + * Before \u{08888} `HumaNified` \{u08888} After + //~^ ERROR: item in documentation is missing backticks + * meow meow \[`meow_meow`\] meow meow? + //~^ ERROR: item in documentation is missing backticks + * \u{08888} `meow_meow` \[meow meow] meow? + //~^ ERROR: item in documentation is missing backticks + * Above + * \u{08888} + * \[hi\]() `HumaNified` \[example]() + //~^ ERROR: item in documentation is missing backticks + * \u{08888} + * Below + */ Plain, // Should not warn! /// JSONified console output diff --git a/tests/ui/doc/doc_markdown-issue_13097.rs b/tests/ui/doc/doc_markdown-issue_13097.rs index 8c1e1a3cd6c24..2e89fe6c56b4c 100644 --- a/tests/ui/doc/doc_markdown-issue_13097.rs +++ b/tests/ui/doc/doc_markdown-issue_13097.rs @@ -1,11 +1,37 @@ -// This test checks that words starting with capital letters and ending with "ified" don't -// trigger the lint. - #![deny(clippy::doc_markdown)] +#![allow(clippy::doc_lazy_continuation)] + +mod issue13097 { + // This test checks that words starting with capital letters and ending with "ified" don't + // trigger the lint. + pub enum OutputFormat { + /// HumaNified + //~^ ERROR: item in documentation is missing backticks + Plain, + // Should not warn! + /// JSONified console output + Json, + } +} +#[rustfmt::skip] pub enum OutputFormat { - /// HumaNified - //~^ ERROR: item in documentation is missing backticks + /** + * HumaNified + //~^ ERROR: item in documentation is missing backticks + * Before \u{08888} HumaNified \{u08888} After + //~^ ERROR: item in documentation is missing backticks + * meow meow \[meow_meow\] meow meow? + //~^ ERROR: item in documentation is missing backticks + * \u{08888} meow_meow \[meow meow] meow? + //~^ ERROR: item in documentation is missing backticks + * Above + * \u{08888} + * \[hi\]() HumaNified \[example]() + //~^ ERROR: item in documentation is missing backticks + * \u{08888} + * Below + */ Plain, // Should not warn! /// JSONified console output diff --git a/tests/ui/doc/doc_markdown-issue_13097.stderr b/tests/ui/doc/doc_markdown-issue_13097.stderr index 65b8f2ed80b6c..cea788301d4dc 100644 --- a/tests/ui/doc/doc_markdown-issue_13097.stderr +++ b/tests/ui/doc/doc_markdown-issue_13097.stderr @@ -1,19 +1,79 @@ error: item in documentation is missing backticks - --> tests/ui/doc/doc_markdown-issue_13097.rs:7:9 + --> tests/ui/doc/doc_markdown-issue_13097.rs:8:13 | -LL | /// HumaNified - | ^^^^^^^^^^ +LL | /// HumaNified + | ^^^^^^^^^^ | note: the lint level is defined here - --> tests/ui/doc/doc_markdown-issue_13097.rs:4:9 + --> tests/ui/doc/doc_markdown-issue_13097.rs:1:9 | LL | #![deny(clippy::doc_markdown)] | ^^^^^^^^^^^^^^^^^^^^ help: try | -LL - /// HumaNified -LL + /// `HumaNified` +LL - /// HumaNified +LL + /// `HumaNified` | -error: aborting due to 1 previous error +error: item in documentation is missing backticks + --> tests/ui/doc/doc_markdown-issue_13097.rs:20:8 + | +LL | * HumaNified + | ^^^^^^^^^^ + | +help: try + | +LL - * HumaNified +LL + * `HumaNified` + | + +error: item in documentation is missing backticks + --> tests/ui/doc/doc_markdown-issue_13097.rs:22:25 + | +LL | * Before \u{08888} HumaNified \{u08888} After + | ^^^^^^^^^^ + | +help: try + | +LL - * Before \u{08888} HumaNified \{u08888} After +LL + * Before \u{08888} `HumaNified` \{u08888} After + | + +error: item in documentation is missing backticks + --> tests/ui/doc/doc_markdown-issue_13097.rs:24:20 + | +LL | * meow meow \[meow_meow\] meow meow? + | ^^^^^^^^^ + | +help: try + | +LL - * meow meow \[meow_meow\] meow meow? +LL + * meow meow \[`meow_meow`\] meow meow? + | + +error: item in documentation is missing backticks + --> tests/ui/doc/doc_markdown-issue_13097.rs:26:18 + | +LL | * \u{08888} meow_meow \[meow meow] meow? + | ^^^^^^^^^ + | +help: try + | +LL - * \u{08888} meow_meow \[meow meow] meow? +LL + * \u{08888} `meow_meow` \[meow meow] meow? + | + +error: item in documentation is missing backticks + --> tests/ui/doc/doc_markdown-issue_13097.rs:30:38 + | +LL | * \[hi\]() HumaNified \[example]() + | ^^^^^^^^^^ + | +help: try + | +LL - * \[hi\]() HumaNified \[example]() +LL + * \[hi\]() `HumaNified` \[example]() + | + +error: aborting due to 6 previous errors From 90a007c73412c6444e7379688e609e29efd618d8 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 21 May 2025 14:33:56 -0400 Subject: [PATCH 2595/4206] Add spell checking job in the CI --- .github/workflows/ci.yml | 6 ++++++ _typos.toml | 9 +++++++++ 2 files changed, 15 insertions(+) create mode 100644 _typos.toml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ef024258ffc86..14a594cbb5ce4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -115,6 +115,12 @@ jobs: - uses: actions/checkout@v4 - run: python tools/check_intrinsics_duplicates.py + spell_check: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - uses: crate-ci/typos@v1.32.0 + build_system: runs-on: ubuntu-24.04 steps: diff --git a/_typos.toml b/_typos.toml new file mode 100644 index 0000000000000..4a6a506a981a1 --- /dev/null +++ b/_typos.toml @@ -0,0 +1,9 @@ +[default.extend-words] +ba = "ba" +hsa = "hsa" +olt = "olt" +seh = "seh" +typ = "typ" + +[files] +extend-exclude = ["src/intrinsic/archs.rs"] From c430b87539d49720346f2652ebf87fa7396776c5 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 21 May 2025 14:38:19 -0400 Subject: [PATCH 2596/4206] Fix typos --- example/std_example.rs | 24 ++++++++++++------------ src/attributes.rs | 4 ++-- src/type_of.rs | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/example/std_example.rs b/example/std_example.rs index 5fa1e0afb0603..7587b4827ca76 100644 --- a/example/std_example.rs +++ b/example/std_example.rs @@ -77,18 +77,18 @@ fn main() { assert_eq!(tmp as i128, -0x1234_5678_9ABC_DEF0i128); // Check that all u/i128 <-> float casts work correctly. - let houndred_u128 = 100u128; - let houndred_i128 = 100i128; - let houndred_f32 = 100.0f32; - let houndred_f64 = 100.0f64; - assert_eq!(houndred_u128 as f32, 100.0); - assert_eq!(houndred_u128 as f64, 100.0); - assert_eq!(houndred_f32 as u128, 100); - assert_eq!(houndred_f64 as u128, 100); - assert_eq!(houndred_i128 as f32, 100.0); - assert_eq!(houndred_i128 as f64, 100.0); - assert_eq!(houndred_f32 as i128, 100); - assert_eq!(houndred_f64 as i128, 100); + let hundred_u128 = 100u128; + let hundred_i128 = 100i128; + let hundred_f32 = 100.0f32; + let hundred_f64 = 100.0f64; + assert_eq!(hundred_u128 as f32, 100.0); + assert_eq!(hundred_u128 as f64, 100.0); + assert_eq!(hundred_f32 as u128, 100); + assert_eq!(hundred_f64 as u128, 100); + assert_eq!(hundred_i128 as f32, 100.0); + assert_eq!(hundred_i128 as f64, 100.0); + assert_eq!(hundred_f32 as i128, 100); + assert_eq!(hundred_f64 as i128, 100); let _a = 1u32 << 2u8; diff --git a/src/attributes.rs b/src/attributes.rs index e63091c6082a7..8779bb47ef01d 100644 --- a/src/attributes.rs +++ b/src/attributes.rs @@ -16,7 +16,7 @@ use crate::gcc_util::to_gcc_features; /// Checks if the function `instance` is recursively inline. /// Returns `false` if a functions is guaranteed to be non-recursive, and `true` if it *might* be recursive. #[cfg(feature = "master")] -fn resursively_inline<'gcc, 'tcx>( +fn recursively_inline<'gcc, 'tcx>( cx: &CodegenCx<'gcc, 'tcx>, instance: ty::Instance<'tcx>, ) -> bool { @@ -61,7 +61,7 @@ fn inline_attr<'gcc, 'tcx>( // // That prevents issues steming from recursive `#[inline(always)]` at a *relatively* small cost. // We *only* need to check all the terminators of a function marked with this attribute. - if resursively_inline(cx, instance) { + if recursively_inline(cx, instance) { Some(FnAttribute::Inline) } else { Some(FnAttribute::AlwaysInline) diff --git a/src/type_of.rs b/src/type_of.rs index 5745acce6fee7..093f902bc3d86 100644 --- a/src/type_of.rs +++ b/src/type_of.rs @@ -217,7 +217,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { let ty = match *self.ty.kind() { // NOTE: we cannot remove this match like in the LLVM codegen because the call // to fn_ptr_backend_type handle the on-stack attribute. - // TODO(antoyo): find a less hackish way to hande the on-stack attribute. + // TODO(antoyo): find a less hackish way to handle the on-stack attribute. ty::FnPtr(sig_tys, hdr) => cx .fn_ptr_backend_type(cx.fn_abi_of_fn_ptr(sig_tys.with(hdr), ty::List::empty())), _ => self.scalar_gcc_type_at(cx, scalar, Size::ZERO), From ce3dae9c52a145ae1cb9eea5089ec2d1cca8e9bf Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 21 May 2025 19:46:24 -0400 Subject: [PATCH 2597/4206] Update to nightly-2025-05-21 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index a8cda28688c84..bafe497a2a2a1 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2025-05-12" +channel = "nightly-2025-05-21" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] From 593d7ca571bb00d87713110f4566208727238c0e Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 21 May 2025 21:03:48 -0400 Subject: [PATCH 2598/4206] Implement missing f16/f128 builtins --- src/builder.rs | 10 ++++++- src/intrinsic/mod.rs | 67 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 64 insertions(+), 13 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 4e2163201fd01..f54a1a941ea83 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -765,7 +765,15 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { #[cfg(feature = "master")] match self.cx.type_kind(a_type) { - TypeKind::Half | TypeKind::Float => { + TypeKind::Half => { + let fmodf = self.context.get_builtin_function("fmodf"); + let f32_type = self.type_f32(); + let a = self.context.new_cast(self.location, a, f32_type); + let b = self.context.new_cast(self.location, b, f32_type); + let result = self.context.new_call(self.location, fmodf, &[a, b]); + return self.context.new_cast(self.location, result, a_type); + } + TypeKind::Float => { let fmodf = self.context.get_builtin_function("fmodf"); return self.context.new_call(self.location, fmodf, &[a, b]); } diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index 4e5018ae01181..8402d0c6fcf84 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -45,8 +45,10 @@ fn get_simple_intrinsic<'gcc, 'tcx>( let gcc_name = match name { sym::sqrtf32 => "sqrtf", sym::sqrtf64 => "sqrt", + sym::sqrtf128 => "sqrtl", sym::powif32 => "__builtin_powif", sym::powif64 => "__builtin_powi", + sym::powif128 => "__builtin_powil", sym::sinf32 => "sinf", sym::sinf64 => "sin", sym::cosf32 => "cosf", @@ -65,6 +67,7 @@ fn get_simple_intrinsic<'gcc, 'tcx>( sym::log2f64 => "log2", sym::fmaf32 => "fmaf", sym::fmaf64 => "fma", + sym::fmaf128 => "fmal", // FIXME: calling `fma` from libc without FMA target feature uses expensive software emulation sym::fmuladdf32 => "fmaf", // TODO: use gcc intrinsic analogous to llvm.fmuladd.f32 sym::fmuladdf64 => "fma", // TODO: use gcc intrinsic analogous to llvm.fmuladd.f64 @@ -72,22 +75,29 @@ fn get_simple_intrinsic<'gcc, 'tcx>( sym::fabsf64 => "fabs", sym::minnumf32 => "fminf", sym::minnumf64 => "fmin", + sym::minnumf128 => "fminl", sym::maxnumf32 => "fmaxf", sym::maxnumf64 => "fmax", + sym::maxnumf128 => "fmaxl", sym::copysignf32 => "copysignf", sym::copysignf64 => "copysign", sym::copysignf128 => "copysignl", sym::floorf32 => "floorf", sym::floorf64 => "floor", + sym::floorf128 => "floorl", sym::ceilf32 => "ceilf", sym::ceilf64 => "ceil", + sym::ceilf128 => "ceill", sym::truncf32 => "truncf", sym::truncf64 => "trunc", + sym::truncf128 => "truncl", // We match the LLVM backend and lower this to `rint`. sym::round_ties_even_f32 => "rintf", sym::round_ties_even_f64 => "rint", + sym::round_ties_even_f128 => "rintl", sym::roundf32 => "roundf", sym::roundf64 => "round", + sym::roundf128 => "roundl", sym::abort => "abort", _ => return None, }; @@ -160,6 +170,40 @@ fn get_simple_function<'gcc, 'tcx>( )) } +fn f16_builtin<'gcc, 'tcx>( + cx: &CodegenCx<'gcc, 'tcx>, + name: Symbol, + args: &[OperandRef<'tcx, RValue<'gcc>>], +) -> RValue<'gcc> { + let f32_type = cx.type_f32(); + let builtin_name = match name { + sym::ceilf16 => "__builtin_ceilf", + sym::floorf16 => "__builtin_floorf", + sym::fmaf16 => "fmaf", + sym::maxnumf16 => "__builtin_fmaxf", + sym::minnumf16 => "__builtin_fminf", + sym::powf16 => "__builtin_powf", + sym::powif16 => { + let func = cx.context.get_builtin_function("__builtin_powif"); + let arg0 = cx.context.new_cast(None, args[0].immediate(), f32_type); + let args = [arg0, args[1].immediate()]; + let result = cx.context.new_call(None, func, &args); + return cx.context.new_cast(None, result, cx.type_f16()); + } + sym::roundf16 => "__builtin_roundf", + sym::round_ties_even_f16 => "__builtin_rintf", + sym::sqrtf16 => "__builtin_sqrtf", + sym::truncf16 => "__builtin_truncf", + _ => unreachable!(), + }; + + let func = cx.context.get_builtin_function(builtin_name); + let args: Vec<_> = + args.iter().map(|arg| cx.context.new_cast(None, arg.immediate(), f32_type)).collect(); + let result = cx.context.new_call(None, func, &args); + cx.context.new_cast(None, result, cx.type_f16()) +} + impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { fn codegen_intrinsic_call( &mut self, @@ -211,18 +255,17 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc &args.iter().map(|arg| arg.immediate()).collect::>(), ) } - sym::fmaf16 => { - // TODO(antoyo): use the correct builtin for f16. - let func = self.cx.context.get_builtin_function("fmaf"); - let args: Vec<_> = args - .iter() - .map(|arg| { - self.cx.context.new_cast(self.location, arg.immediate(), self.cx.type_f32()) - }) - .collect(); - let result = self.cx.context.new_call(self.location, func, &args); - self.cx.context.new_cast(self.location, result, self.cx.type_f16()) - } + sym::ceilf16 + | sym::floorf16 + | sym::fmaf16 + | sym::maxnumf16 + | sym::minnumf16 + | sym::powf16 + | sym::powif16 + | sym::roundf16 + | sym::round_ties_even_f16 + | sym::sqrtf16 + | sym::truncf16 => f16_builtin(self, name, args), sym::is_val_statically_known => { let a = args[0].immediate(); let builtin = self.context.get_builtin_function("__builtin_constant_p"); From dca28e588cb9c49bf275c073e28663bfc8393b5f Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 21 May 2025 21:04:07 -0400 Subject: [PATCH 2599/4206] Only specify that we have reliable f16 and f128 on targets where those types are supported --- src/lib.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6994c385fc831..66e9ce4627c80 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -521,13 +521,16 @@ fn target_config(sess: &Session, target_info: &LockedTargetInfo) -> TargetConfig let target_features = f(false); let unstable_target_features = f(true); + let has_reliable_f16 = target_info.supports_target_dependent_type(CType::Float16); + let has_reliable_f128 = target_info.supports_target_dependent_type(CType::Float128); + TargetConfig { target_features, unstable_target_features, // There are no known bugs with GCC support for f16 or f128 - has_reliable_f16: true, - has_reliable_f16_math: true, - has_reliable_f128: true, - has_reliable_f128_math: true, + has_reliable_f16, + has_reliable_f16_math: has_reliable_f16, + has_reliable_f128, + has_reliable_f128_math: has_reliable_f128, } } From 849cabf4c4a97f0a1c6320993b08bf8e6068e58f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 22 May 2025 11:55:22 +1000 Subject: [PATCH 2600/4206] Rename `kw::Empty` as `sym::empty`. Because the empty string is not a keyword. --- compiler/rustc_ast_lowering/src/format.rs | 4 +-- .../rustc_codegen_ssa/src/mir/debuginfo.rs | 6 ++--- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 6 ++--- compiler/rustc_resolve/src/rustdoc.rs | 6 ++--- compiler/rustc_span/src/symbol.rs | 27 +++++++++---------- compiler/rustc_symbol_mangling/src/v0.rs | 4 +-- .../clippy_lints/src/manual_string_new.rs | 4 +-- .../clippy_lints/src/methods/or_fun_call.rs | 4 +-- 9 files changed, 31 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 0de0319c66763..17b443b8ecc2c 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -6,7 +6,7 @@ use rustc_ast::*; use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; use rustc_session::config::FmtDebug; -use rustc_span::{Ident, Span, Symbol, kw, sym}; +use rustc_span::{Ident, Span, Symbol, sym}; use super::LoweringContext; @@ -418,7 +418,7 @@ fn expand_format_args<'hir>( &FormatArgsPiece::Placeholder(_) => { // Inject empty string before placeholders when not already preceded by a literal piece. if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) { - Some(ctx.expr_str(fmt.span, kw::Empty)) + Some(ctx.expr_str(fmt.span, sym::empty)) } else { None } diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 5924c8991ad64..f731613d67e8a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -10,7 +10,7 @@ use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::{Instance, Ty}; use rustc_middle::{bug, mir, ty}; use rustc_session::config::DebugInfo; -use rustc_span::{BytePos, Span, Symbol, hygiene, kw}; +use rustc_span::{BytePos, Span, Symbol, hygiene, sym}; use super::operand::{OperandRef, OperandValue}; use super::place::{PlaceRef, PlaceValue}; @@ -283,7 +283,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // (after #67586 gets fixed). None } else { - let name = kw::Empty; + let name = sym::empty; let decl = &self.mir.local_decls[local]; let dbg_var = if full_debug_info { self.adjusted_span_and_dbg_scope(decl.source_info).map( @@ -318,7 +318,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { None } else { Some(match whole_local_var.or(fallback_var.clone()) { - Some(var) if var.name != kw::Empty => var.name.to_string(), + Some(var) if var.name != sym::empty => var.name.to_string(), _ => format!("{local:?}"), }) }; diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index fa1d1ec0a8601..f63ab30368914 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -85,7 +85,7 @@ impl From for LifetimeSyntax { fn from(ident: Ident) -> Self { let name = ident.name; - if name == kw::Empty { + if name == sym::empty { unreachable!("A lifetime name should never be empty"); } else if name == kw::UnderscoreLifetime { LifetimeSyntax::Anonymous diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 5c0d0cf47969a..1d0246940499f 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -35,7 +35,7 @@ use rustc_session::lint::builtin::{ UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, }; use rustc_session::parse::feature_err; -use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, edition, kw, sym}; +use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, edition, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs}; use rustc_trait_selection::traits::ObligationCtxt; @@ -936,7 +936,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let span = meta.name_value_literal_span().unwrap_or_else(|| meta.span()); let attr_str = &format!("`#[doc(alias{})]`", if is_list { "(\"...\")" } else { " = \"...\"" }); - if doc_alias == kw::Empty { + if doc_alias == sym::empty { tcx.dcx().emit_err(errors::DocAliasEmpty { span, attr_str }); return; } @@ -1068,7 +1068,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } let doc_keyword = match meta.value_str() { - Some(value) if value != kw::Empty => value, + Some(value) if value != sym::empty => value, _ => return self.doc_attr_str_error(meta, "keyword"), }; diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index a32fe6990160c..d701410e4dc2e 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -12,7 +12,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::UnordSet; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; -use rustc_span::{DUMMY_SP, InnerSpan, Span, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, InnerSpan, Span, Symbol, sym}; use thin_vec::ThinVec; use tracing::{debug, trace}; @@ -157,7 +157,7 @@ pub fn unindent_doc_fragments(docs: &mut [DocFragment]) { }; for fragment in docs { - if fragment.doc == kw::Empty { + if fragment.doc == sym::empty { continue; } @@ -177,7 +177,7 @@ pub fn unindent_doc_fragments(docs: &mut [DocFragment]) { /// /// Note: remove the trailing newline where appropriate pub fn add_doc_fragment(out: &mut String, frag: &DocFragment) { - if frag.doc == kw::Empty { + if frag.doc == sym::empty { out.push('\n'); return; } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index fbe3b4ca6f5f6..befc5bbff52c8 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -34,17 +34,8 @@ symbols! { // unnamed method parameters, crate root module, error recovery etc. // Matching predicates: `is_special`/`is_reserved` // - // Notes about `kw::Empty`: - // - Its use can blur the lines between "empty symbol" and "no symbol". - // Using `Option` is preferable, where possible, because that - // is unambiguous. - // - For dummy symbols that are never used and absolutely must be - // present, it's better to use `sym::dummy` than `kw::Empty`, because - // it's clearer that it's intended as a dummy value, and more likely - // to be detected if it accidentally does get used. // tidy-alphabetical-start DollarCrate: "$crate", - Empty: "", PathRoot: "{{root}}", Underscore: "_", // tidy-alphabetical-end @@ -864,7 +855,7 @@ symbols! { drop_types_in_const, dropck_eyepatch, dropck_parametricity, - dummy: "", // use this instead of `kw::Empty` for symbols that won't be used + dummy: "", // use this instead of `sym::empty` for symbols that won't be used dummy_cgu_name, dylib, dyn_compatible_for_dispatch, @@ -883,6 +874,14 @@ symbols! { emit_enum_variant_arg, emit_struct, emit_struct_field, + // Notes about `sym::empty`: + // - It should only be used when it genuinely means "empty symbol". Use + // `Option` when "no symbol" is a possibility. + // - For dummy symbols that are never used and absolutely must be + // present, it's better to use `sym::dummy` than `sym::empty`, because + // it's clearer that it's intended as a dummy value, and more likely + // to be detected if it accidentally does get used. + empty: "", emscripten_wasm_eh, enable, encode, @@ -2362,7 +2361,7 @@ impl Ident { #[inline] /// Constructs a new identifier from a symbol and a span. pub fn new(name: Symbol, span: Span) -> Ident { - debug_assert_ne!(name, kw::Empty); + debug_assert_ne!(name, sym::empty); Ident { name, span } } @@ -2584,7 +2583,7 @@ impl Symbol { } pub fn is_empty(self) -> bool { - self == kw::Empty + self == sym::empty } /// This method is supposed to be used in error messages, so it's expected to be @@ -2593,7 +2592,7 @@ impl Symbol { /// or edition, so we have to guess the rawness using the global edition. pub fn to_ident_string(self) -> String { // Avoid creating an empty identifier, because that asserts in debug builds. - if self == kw::Empty { String::new() } else { Ident::with_dummy_span(self).to_string() } + if self == sym::empty { String::new() } else { Ident::with_dummy_span(self).to_string() } } } @@ -2773,7 +2772,7 @@ impl Symbol { /// Returns `true` if this symbol can be a raw identifier. pub fn can_be_raw(self) -> bool { - self != kw::Empty && self != kw::Underscore && !self.is_path_segment_keyword() + self != sym::empty && self != kw::Underscore && !self.is_path_segment_keyword() } /// Was this symbol predefined in the compiler's `symbols!` macro diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 4a99ce09b39ab..644031af8597a 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -20,7 +20,7 @@ use rustc_middle::ty::{ self, FloatTy, GenericArg, GenericArgKind, Instance, IntTy, ReifyReason, Ty, TyCtxt, TypeVisitable, TypeVisitableExt, UintTy, }; -use rustc_span::kw; +use rustc_span::sym; pub(super) fn mangle<'tcx>( tcx: TyCtxt<'tcx>, @@ -902,7 +902,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { print_prefix, ns, disambiguated_data.disambiguator as u64, - name.unwrap_or(kw::Empty).as_str(), + name.unwrap_or(sym::empty).as_str(), ) } diff --git a/src/tools/clippy/clippy_lints/src/manual_string_new.rs b/src/tools/clippy/clippy_lints/src/manual_string_new.rs index 7ca3b71206671..73ee1c3c78abc 100644 --- a/src/tools/clippy/clippy_lints/src/manual_string_new.rs +++ b/src/tools/clippy/clippy_lints/src/manual_string_new.rs @@ -5,7 +5,7 @@ use rustc_hir::{Expr, ExprKind, PathSegment, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{Span, sym, symbol}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -67,7 +67,7 @@ impl LateLintPass<'_> for ManualStringNew { fn is_expr_kind_empty_str(expr_kind: &ExprKind<'_>) -> bool { if let ExprKind::Lit(lit) = expr_kind && let LitKind::Str(value, _) = lit.node - && value == symbol::kw::Empty + && value == sym::empty { return true; } diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs index c74c42e9e5bd5..38cb4d51ca0f4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs @@ -12,7 +12,7 @@ use rustc_errors::Applicability; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::Span; -use rustc_span::symbol::{self, Symbol}; +use rustc_span::Symbol; use {rustc_ast as ast, rustc_hir as hir}; use super::{OR_FUN_CALL, UNWRAP_OR_DEFAULT}; @@ -265,7 +265,7 @@ fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) && ident.name == sym::to_string && let hir::Expr { kind, .. } = self_arg && let hir::ExprKind::Lit(lit) = kind - && let ast::LitKind::Str(symbol::kw::Empty, _) = lit.node + && let ast::LitKind::Str(rustc_span::sym::empty, _) = lit.node { return true; } From a0760cf5c0b411de847f963f5b66bef951585d1f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 22 May 2025 11:55:22 +1000 Subject: [PATCH 2601/4206] Rename `kw::Empty` as `sym::empty`. Because the empty string is not a keyword. --- clippy_lints/src/manual_string_new.rs | 4 ++-- clippy_lints/src/methods/or_fun_call.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/manual_string_new.rs b/clippy_lints/src/manual_string_new.rs index 7ca3b71206671..73ee1c3c78abc 100644 --- a/clippy_lints/src/manual_string_new.rs +++ b/clippy_lints/src/manual_string_new.rs @@ -5,7 +5,7 @@ use rustc_hir::{Expr, ExprKind, PathSegment, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{Span, sym, symbol}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -67,7 +67,7 @@ impl LateLintPass<'_> for ManualStringNew { fn is_expr_kind_empty_str(expr_kind: &ExprKind<'_>) -> bool { if let ExprKind::Lit(lit) = expr_kind && let LitKind::Str(value, _) = lit.node - && value == symbol::kw::Empty + && value == sym::empty { return true; } diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index c74c42e9e5bd5..38cb4d51ca0f4 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -12,7 +12,7 @@ use rustc_errors::Applicability; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::Span; -use rustc_span::symbol::{self, Symbol}; +use rustc_span::Symbol; use {rustc_ast as ast, rustc_hir as hir}; use super::{OR_FUN_CALL, UNWRAP_OR_DEFAULT}; @@ -265,7 +265,7 @@ fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) && ident.name == sym::to_string && let hir::Expr { kind, .. } = self_arg && let hir::ExprKind::Lit(lit) = kind - && let ast::LitKind::Str(symbol::kw::Empty, _) = lit.node + && let ast::LitKind::Str(rustc_span::sym::empty, _) = lit.node { return true; } From 85d2d843c3cff20beb242a0d1726630ad10b5ff9 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 22 May 2025 13:25:45 +1000 Subject: [PATCH 2602/4206] Remove `is_empty` check in `filter_assoc_items_by_name_and_namespace`. It was added in #140052, but the subsequent changes in #140252 means it is no longer necessary. (Indeed, `Ident`s cannot be empty any more.) --- src/librustdoc/passes/collect_intra_doc_links.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index f3e2138d1a575..37628f166002d 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -59,12 +59,7 @@ fn filter_assoc_items_by_name_and_namespace( ident: Ident, ns: Namespace, ) -> impl Iterator { - let iter: Box> = if !ident.name.is_empty() { - Box::new(tcx.associated_items(assoc_items_of).filter_by_name_unhygienic(ident.name)) - } else { - Box::new([].iter()) - }; - iter.filter(move |item| { + tcx.associated_items(assoc_items_of).filter_by_name_unhygienic(ident.name).filter(move |item| { item.namespace() == ns && tcx.hygienic_eq(ident, item.ident(tcx), assoc_items_of) }) } From c309065ece12632a522676c794e0befbceb213f5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 22 May 2025 13:31:19 +1000 Subject: [PATCH 2603/4206] Remove `is_empty` check in `Ident::is_numeric`. `Ident`s can no longer be empty, so the test always succeeds. --- compiler/rustc_span/src/symbol.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index fbe3b4ca6f5f6..dc77eb52b2e60 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2823,7 +2823,7 @@ impl Ident { /// Whether this would be the identifier for a tuple field like `self.0`, as /// opposed to a named field like `self.thing`. pub fn is_numeric(self) -> bool { - !self.name.is_empty() && self.as_str().bytes().all(|b| b.is_ascii_digit()) + self.as_str().bytes().all(|b| b.is_ascii_digit()) } } From 24a416cc5714ab7129fa91f4e94f6dd877675b05 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 22 May 2025 07:55:06 +0200 Subject: [PATCH 2604/4206] Support `transmute_unchecked` intrinsic for mir-eval --- src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index 7cf948b178e46..90c52ee96f1ff 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -1121,7 +1121,7 @@ impl Evaluator<'_> { // We don't call any drop glue yet, so there is nothing here Ok(()) } - "transmute" => { + "transmute" | "transmute_unchecked" => { let [arg] = args else { return Err(MirEvalError::InternalError( "transmute arg is not provided".into(), From 1e796370508c67dd7a9cf68c7dc6f2b199312372 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Wed, 9 Apr 2025 18:55:36 -0700 Subject: [PATCH 2605/4206] Implement file read/write on Windows --- src/tools/miri/src/machine.rs | 5 - src/tools/miri/src/shims/io_error.rs | 24 ++ .../miri/src/shims/windows/foreign_items.rs | 110 ++++---- src/tools/miri/src/shims/windows/fs.rs | 262 ++++++++++++++++++ src/tools/miri/src/shims/windows/handle.rs | 24 ++ src/tools/miri/test_dependencies/Cargo.toml | 9 +- .../miri/tests/pass-dep/shims/windows-fs.rs | 97 ++++++- src/tools/miri/tests/pass/shims/fs.rs | 10 +- 8 files changed, 460 insertions(+), 81 deletions(-) diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 1c6c7894cb456..f75adffd9508e 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -544,9 +544,6 @@ pub struct MiriMachine<'tcx> { /// Failure rate of compare_exchange_weak, between 0.0 and 1.0 pub(crate) cmpxchg_weak_failure_rate: f64, - /// Corresponds to -Zmiri-mute-stdout-stderr and doesn't write the output but acts as if it succeeded. - pub(crate) mute_stdout_stderr: bool, - /// The probability of the active thread being preempted at the end of each basic block. pub(crate) preemption_rate: f64, @@ -722,7 +719,6 @@ impl<'tcx> MiriMachine<'tcx> { track_alloc_accesses: config.track_alloc_accesses, check_alignment: config.check_alignment, cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate, - mute_stdout_stderr: config.mute_stdout_stderr, preemption_rate: config.preemption_rate, report_progress: config.report_progress, basic_block_count: 0, @@ -925,7 +921,6 @@ impl VisitProvenance for MiriMachine<'_> { track_alloc_accesses: _, check_alignment: _, cmpxchg_weak_failure_rate: _, - mute_stdout_stderr: _, preemption_rate: _, report_progress: _, basic_block_count: _, diff --git a/src/tools/miri/src/shims/io_error.rs b/src/tools/miri/src/shims/io_error.rs index acf3f74a93d8b..e597b527cb7a8 100644 --- a/src/tools/miri/src/shims/io_error.rs +++ b/src/tools/miri/src/shims/io_error.rs @@ -1,4 +1,5 @@ use std::io; +use std::io::ErrorKind; use crate::*; @@ -13,6 +14,29 @@ pub enum IoError { } pub use self::IoError::*; +impl IoError { + pub(crate) fn into_ntstatus(self) -> i32 { + let raw = match self { + HostError(e) => + match e.kind() { + // STATUS_MEDIA_WRITE_PROTECTED + ErrorKind::ReadOnlyFilesystem => 0xC00000A2u32, + // STATUS_FILE_INVALID + ErrorKind::InvalidInput => 0xC0000098, + // STATUS_DISK_FULL + ErrorKind::QuotaExceeded => 0xC000007F, + // STATUS_ACCESS_DENIED + ErrorKind::PermissionDenied => 0xC0000022, + // For the default error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR. + _ => 0xC0000185, + }, + // For the default error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR. + _ => 0xC0000185, + }; + raw.cast_signed() + } +} + impl From for IoError { fn from(value: io::Error) -> Self { IoError::HostError(value) diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index c80858c63639a..d822dd07fcd7b 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -195,69 +195,52 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // File related shims "NtWriteFile" => { - if !this.frame_in_std() { - throw_unsup_format!( - "`NtWriteFile` support is crude and just enough for stdout to work" - ); - } - let [ handle, - _event, - _apc_routine, - _apc_context, + event, + apc_routine, + apc_context, io_status_block, buf, n, byte_offset, - _key, + key, ] = this.check_shim(abi, sys_conv, link_name, args)?; - let handle = this.read_target_isize(handle)?; - let buf = this.read_pointer(buf)?; - let n = this.read_scalar(n)?.to_u32()?; - let byte_offset = this.read_target_usize(byte_offset)?; // is actually a pointer - let io_status_block = this - .deref_pointer_as(io_status_block, this.windows_ty_layout("IO_STATUS_BLOCK"))?; - - if byte_offset != 0 { - throw_unsup_format!( - "`NtWriteFile` `ByteOffset` parameter is non-null, which is unsupported" - ); - } - - let written = if handle == -11 || handle == -12 { - // stdout/stderr - use io::Write; - - let buf_cont = - this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(u64::from(n)))?; - let res = if this.machine.mute_stdout_stderr { - Ok(buf_cont.len()) - } else if handle == -11 { - io::stdout().write(buf_cont) - } else { - io::stderr().write(buf_cont) - }; - // We write at most `n` bytes, which is a `u32`, so we cannot have written more than that. - res.ok().map(|n| u32::try_from(n).unwrap()) - } else { - throw_unsup_format!( - "on Windows, writing to anything except stdout/stderr is not supported" - ) - }; - // We have to put the result into io_status_block. - if let Some(n) = written { - let io_status_information = - this.project_field_named(&io_status_block, "Information")?; - this.write_scalar( - Scalar::from_target_usize(n.into(), this), - &io_status_information, - )?; - } - // Return whether this was a success. >= 0 is success. - // For the error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR. - this.write_scalar( - Scalar::from_u32(if written.is_some() { 0 } else { 0xC0000185u32 }), + this.NtWriteFile( + handle, + event, + apc_routine, + apc_context, + io_status_block, + buf, + n, + byte_offset, + key, + dest, + )?; + } + "NtReadFile" => { + let [ + handle, + event, + apc_routine, + apc_context, + io_status_block, + buf, + n, + byte_offset, + key, + ] = this.check_shim(abi, sys_conv, link_name, args)?; + this.NtReadFile( + handle, + event, + apc_routine, + apc_context, + io_status_block, + buf, + n, + byte_offset, + key, dest, )?; } @@ -322,6 +305,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let res = this.DeleteFileW(file_name)?; this.write_scalar(res, dest)?; } + "SetFilePointerEx" => { + let [file, distance_to_move, new_file_pointer, move_method] = + this.check_shim(abi, sys_conv, link_name, args)?; + let res = + this.SetFilePointerEx(file, distance_to_move, new_file_pointer, move_method)?; + this.write_scalar(res, dest)?; + } // Allocation "HeapAlloc" => { @@ -700,12 +690,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "GetStdHandle" => { let [which] = this.check_shim(abi, sys_conv, link_name, args)?; - let which = this.read_scalar(which)?.to_i32()?; - // We just make this the identity function, so we know later in `NtWriteFile` which - // one it is. This is very fake, but libtest needs it so we cannot make it a - // std-only shim. - // FIXME: this should return real HANDLEs when io support is added - this.write_scalar(Scalar::from_target_isize(which.into(), this), dest)?; + let res = this.GetStdHandle(which)?; + this.write_scalar(res, dest)?; } "CloseHandle" => { let [handle] = this.check_shim(abi, sys_conv, link_name, args)?; diff --git a/src/tools/miri/src/shims/windows/fs.rs b/src/tools/miri/src/shims/windows/fs.rs index 0ac82d55b1005..72e016c12e944 100644 --- a/src/tools/miri/src/shims/windows/fs.rs +++ b/src/tools/miri/src/shims/windows/fs.rs @@ -1,5 +1,6 @@ use std::fs::{Metadata, OpenOptions}; use std::io; +use std::io::SeekFrom; use std::path::PathBuf; use std::time::SystemTime; @@ -390,6 +391,267 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } } + + fn NtWriteFile( + &mut self, + handle: &OpTy<'tcx>, // HANDLE + event: &OpTy<'tcx>, // HANDLE + apc_routine: &OpTy<'tcx>, // PIO_APC_ROUTINE + apc_ctx: &OpTy<'tcx>, // PVOID + io_status_block: &OpTy<'tcx>, // PIO_STATUS_BLOCK + buf: &OpTy<'tcx>, // PVOID + n: &OpTy<'tcx>, // ULONG + byte_offset: &OpTy<'tcx>, // PLARGE_INTEGER + key: &OpTy<'tcx>, // PULONG + dest: &MPlaceTy<'tcx>, // return type: NTSTATUS + ) -> InterpResult<'tcx, ()> { + let this = self.eval_context_mut(); + let handle = this.read_handle(handle, "NtWriteFile")?; + let event = this.read_handle(event, "NtWriteFile")?; + let apc_routine = this.read_pointer(apc_routine)?; + let apc_ctx = this.read_pointer(apc_ctx)?; + let buf = this.read_pointer(buf)?; + let count = this.read_scalar(n)?.to_u32()?; + let byte_offset = this.read_target_usize(byte_offset)?; // is actually a pointer, but we only support null + let key = this.read_pointer(key)?; + let io_status_block = + this.deref_pointer_as(io_status_block, this.windows_ty_layout("IO_STATUS_BLOCK"))?; + + if event != Handle::Null { + throw_unsup_format!( + "`NtWriteFile` `Event` parameter is non-null, which is unsupported" + ); + } + + if !this.ptr_is_null(apc_routine)? { + throw_unsup_format!( + "`NtWriteFile` `ApcRoutine` parameter is non-null, which is unsupported" + ); + } + + if !this.ptr_is_null(apc_ctx)? { + throw_unsup_format!( + "`NtWriteFile` `ApcContext` parameter is non-null, which is unsupported" + ); + } + + if byte_offset != 0 { + throw_unsup_format!( + "`NtWriteFile` `ByteOffset` parameter is non-null, which is unsupported" + ); + } + + if !this.ptr_is_null(key)? { + throw_unsup_format!("`NtWriteFile` `Key` parameter is non-null, which is unsupported"); + } + + let fd = match handle { + Handle::File(fd) => fd, + _ => this.invalid_handle("NtWriteFile")?, + }; + + let Some(desc) = this.machine.fds.get(fd) else { this.invalid_handle("NtWriteFile")? }; + + // Windows writes the output code to IO_STATUS_BLOCK.Status, and number of bytes written + // to IO_STATUS_BLOCK.Information. + // The status block value and the returned value don't need to match - but + // for the cases implemented by miri so far, we can choose to decide that they do. + let io_status = { + let anon = this.project_field_named(&io_status_block, "Anonymous")?; + this.project_field_named(&anon, "Status")? + }; + let io_status_info = this.project_field_named(&io_status_block, "Information")?; + + let finish = { + let io_status = io_status.clone(); + let io_status_info = io_status_info.clone(); + let dest = dest.clone(); + callback!( + @capture<'tcx> { + count: u32, + io_status: MPlaceTy<'tcx>, + io_status_info: MPlaceTy<'tcx>, + dest: MPlaceTy<'tcx>, + } + |this, result: Result| { + match result { + Ok(read_size) => { + assert!(read_size <= count.try_into().unwrap()); + // This must fit since `count` fits. + this.write_int(u64::try_from(read_size).unwrap(), &io_status_info)?; + this.write_int(0, &io_status)?; + this.write_int(0, &dest) + } + Err(e) => { + this.write_int(0, &io_status_info)?; + let status = e.into_ntstatus(); + this.write_int(status, &io_status)?; + this.write_int(status, &dest) + } + }} + ) + }; + + desc.write(this.machine.communicate(), buf, count.try_into().unwrap(), this, finish)?; + + // Return status is written to `dest` and `io_status_block` on callback completion. + interp_ok(()) + } + + fn NtReadFile( + &mut self, + handle: &OpTy<'tcx>, // HANDLE + event: &OpTy<'tcx>, // HANDLE + apc_routine: &OpTy<'tcx>, // PIO_APC_ROUTINE + apc_ctx: &OpTy<'tcx>, // PVOID + io_status_block: &OpTy<'tcx>, // PIO_STATUS_BLOCK + buf: &OpTy<'tcx>, // PVOID + n: &OpTy<'tcx>, // ULONG + byte_offset: &OpTy<'tcx>, // PLARGE_INTEGER + key: &OpTy<'tcx>, // PULONG + dest: &MPlaceTy<'tcx>, // return type: NTSTATUS + ) -> InterpResult<'tcx, ()> { + let this = self.eval_context_mut(); + let handle = this.read_handle(handle, "NtReadFile")?; + let event = this.read_handle(event, "NtReadFile")?; + let apc_routine = this.read_pointer(apc_routine)?; + let apc_ctx = this.read_pointer(apc_ctx)?; + let buf = this.read_pointer(buf)?; + let count = this.read_scalar(n)?.to_u32()?; + let byte_offset = this.read_target_usize(byte_offset)?; // is actually a pointer, but we only support null + let key = this.read_pointer(key)?; + let io_status_block = + this.deref_pointer_as(io_status_block, this.windows_ty_layout("IO_STATUS_BLOCK"))?; + + if event != Handle::Null { + throw_unsup_format!("`NtReadFile` `Event` parameter is non-null, which is unsupported"); + } + + if !this.ptr_is_null(apc_routine)? { + throw_unsup_format!( + "`NtReadFile` `ApcRoutine` parameter is non-null, which is unsupported" + ); + } + + if !this.ptr_is_null(apc_ctx)? { + throw_unsup_format!( + "`NtReadFile` `ApcContext` parameter is non-null, which is unsupported" + ); + } + + if byte_offset != 0 { + throw_unsup_format!( + "`NtReadFile` `ByteOffset` parameter is non-null, which is unsupported" + ); + } + + if !this.ptr_is_null(key)? { + throw_unsup_format!("`NtReadFile` `Key` parameter is non-null, which is unsupported"); + } + + // See NtWriteFile above for commentary on this + let io_status = { + let anon = this.project_field_named(&io_status_block, "Anonymous")?; + this.project_field_named(&anon, "Status")? + }; + let io_status_info = this.project_field_named(&io_status_block, "Information")?; + + let finish = { + let io_status = io_status.clone(); + let io_status_info = io_status_info.clone(); + let dest = dest.clone(); + callback!( + @capture<'tcx> { + count: u32, + io_status: MPlaceTy<'tcx>, + io_status_info: MPlaceTy<'tcx>, + dest: MPlaceTy<'tcx>, + } + |this, result: Result| { + match result { + Ok(read_size) => { + assert!(read_size <= count.try_into().unwrap()); + // This must fit since `count` fits. + this.write_int(u64::try_from(read_size).unwrap(), &io_status_info)?; + this.write_int(0, &io_status)?; + this.write_int(0, &dest) + } + Err(e) => { + this.write_int(0, &io_status_info)?; + let status = e.into_ntstatus(); + this.write_int(status, &io_status)?; + this.write_int(status, &dest) + } + }} + ) + }; + + let fd = match handle { + Handle::File(fd) => fd, + _ => this.invalid_handle("NtWriteFile")?, + }; + + let Some(desc) = this.machine.fds.get(fd) else { this.invalid_handle("NtReadFile")? }; + + desc.read(this.machine.communicate(), buf, count.try_into().unwrap(), this, finish)?; + + // See NtWriteFile for commentary on this + interp_ok(()) + } + + fn SetFilePointerEx( + &mut self, + file: &OpTy<'tcx>, // HANDLE + dist_to_move: &OpTy<'tcx>, // LARGE_INTEGER + new_fp: &OpTy<'tcx>, // PLARGE_INTEGER + move_method: &OpTy<'tcx>, // DWORD + ) -> InterpResult<'tcx, Scalar> { + // ^ Returns BOOL (i32 on Windows) + let this = self.eval_context_mut(); + let file = this.read_handle(file, "SetFilePointerEx")?; + let dist_to_move = this.read_scalar(dist_to_move)?.to_i64()?; + let new_fp_ptr = this.read_pointer(new_fp)?; + let move_method = this.read_scalar(move_method)?.to_u32()?; + + let fd = match file { + Handle::File(fd) => fd, + _ => this.invalid_handle("SetFilePointerEx")?, + }; + + let Some(desc) = this.machine.fds.get(fd) else { + throw_unsup_format!("`SetFilePointerEx` is only supported on file backed handles"); + }; + + let file_begin = this.eval_windows_u32("c", "FILE_BEGIN"); + let file_current = this.eval_windows_u32("c", "FILE_CURRENT"); + let file_end = this.eval_windows_u32("c", "FILE_END"); + + let seek = if move_method == file_begin { + SeekFrom::Start(dist_to_move.try_into().unwrap()) + } else if move_method == file_current { + SeekFrom::Current(dist_to_move) + } else if move_method == file_end { + SeekFrom::End(dist_to_move) + } else { + throw_unsup_format!("Invalid move method: {move_method}") + }; + + match desc.seek(this.machine.communicate(), seek)? { + Ok(n) => { + if !this.ptr_is_null(new_fp_ptr)? { + this.write_scalar( + Scalar::from_i64(n.try_into().unwrap()), + &this.deref_pointer_as(new_fp, this.machine.layouts.i64)?, + )?; + } + interp_ok(this.eval_windows("c", "TRUE")) + } + Err(e) => { + this.set_last_error(e)?; + interp_ok(this.eval_windows("c", "FALSE")) + } + } + } } /// Windows FILETIME is measured in 100-nanosecs since 1601 diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs index 09dac9c1378bb..5c04271fac590 100644 --- a/src/tools/miri/src/shims/windows/handle.rs +++ b/src/tools/miri/src/shims/windows/handle.rs @@ -220,6 +220,30 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ))) } + fn GetStdHandle(&mut self, which: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + let which = this.read_scalar(which)?.to_i32()?; + + let stdin = this.eval_windows("c", "STD_INPUT_HANDLE").to_i32()?; + let stdout = this.eval_windows("c", "STD_OUTPUT_HANDLE").to_i32()?; + let stderr = this.eval_windows("c", "STD_ERROR_HANDLE").to_i32()?; + + // These values don't mean anything on Windows, but Miri unconditionally sets them up to the + // unix in/out/err descriptors. So we take advantage of that. + // Due to the `Handle` encoding, these values will not be directly exposed to the user. + let fd_num = if which == stdin { + 0 + } else if which == stdout { + 1 + } else if which == stderr { + 2 + } else { + throw_unsup_format!("Invalid argument to `GetStdHandle`: {which}") + }; + let handle = Handle::File(fd_num); + interp_ok(handle.to_scalar(this)) + } + fn CloseHandle(&mut self, handle_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); diff --git a/src/tools/miri/test_dependencies/Cargo.toml b/src/tools/miri/test_dependencies/Cargo.toml index 653228a5e3db6..fa833b51fa31b 100644 --- a/src/tools/miri/test_dependencies/Cargo.toml +++ b/src/tools/miri/test_dependencies/Cargo.toml @@ -25,6 +25,13 @@ page_size = "0.6" tokio = { version = "1", features = ["macros", "rt-multi-thread", "time", "net", "fs", "sync", "signal", "io-util"] } [target.'cfg(windows)'.dependencies] -windows-sys = { version = "0.59", features = ["Win32_Foundation", "Win32_System_Threading", "Win32_Storage_FileSystem", "Win32_Security"] } +windows-sys = { version = "0.59", features = [ + "Win32_Foundation", + "Win32_System_Threading", + "Win32_Storage_FileSystem", + "Win32_Security", + "Win32_System_IO", + "Wdk_Storage_FileSystem", +] } [workspace] diff --git a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs index 698ca4e0b4ba6..4ca19046b676b 100644 --- a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs +++ b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs @@ -2,25 +2,28 @@ //@compile-flags: -Zmiri-disable-isolation #![allow(nonstandard_style)] -use std::io::ErrorKind; +use std::io::{ErrorKind, Read, Write}; use std::os::windows::ffi::OsStrExt; +use std::os::windows::io::AsRawHandle; use std::path::Path; -use std::ptr; +use std::{fs, ptr}; #[path = "../../utils/mod.rs"] mod utils; +use windows_sys::Wdk::Storage::FileSystem::{NtReadFile, NtWriteFile}; use windows_sys::Win32::Foundation::{ CloseHandle, ERROR_ACCESS_DENIED, ERROR_ALREADY_EXISTS, ERROR_IO_DEVICE, GENERIC_READ, GENERIC_WRITE, GetLastError, RtlNtStatusToDosError, STATUS_ACCESS_DENIED, - STATUS_IO_DEVICE_ERROR, + STATUS_IO_DEVICE_ERROR, STATUS_SUCCESS, SetLastError, }; use windows_sys::Win32::Storage::FileSystem::{ BY_HANDLE_FILE_INFORMATION, CREATE_ALWAYS, CREATE_NEW, CreateFileW, DeleteFileW, - FILE_ATTRIBUTE_DIRECTORY, FILE_ATTRIBUTE_NORMAL, FILE_FLAG_BACKUP_SEMANTICS, - FILE_FLAG_OPEN_REPARSE_POINT, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, - GetFileInformationByHandle, OPEN_ALWAYS, OPEN_EXISTING, + FILE_ATTRIBUTE_DIRECTORY, FILE_ATTRIBUTE_NORMAL, FILE_BEGIN, FILE_CURRENT, + FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT, FILE_SHARE_DELETE, FILE_SHARE_READ, + FILE_SHARE_WRITE, GetFileInformationByHandle, OPEN_ALWAYS, OPEN_EXISTING, SetFilePointerEx, }; +use windows_sys::Win32::System::IO::IO_STATUS_BLOCK; fn main() { unsafe { @@ -31,6 +34,8 @@ fn main() { test_open_dir_reparse(); test_delete_file(); test_ntstatus_to_dos(); + test_file_read_write(); + test_file_seek(); } } @@ -199,13 +204,13 @@ unsafe fn test_open_dir_reparse() { unsafe fn test_delete_file() { let temp = utils::tmp().join("test_delete_file.txt"); let raw_path = to_wide_cstr(&temp); - let _ = std::fs::File::create(&temp).unwrap(); + let _ = fs::File::create(&temp).unwrap(); if DeleteFileW(raw_path.as_ptr()) == 0 { panic!("Failed to delete file"); } - match std::fs::File::open(temp) { + match fs::File::open(temp) { Ok(_) => panic!("File not deleted"), Err(e) => assert!(e.kind() == ErrorKind::NotFound, "File not deleted"), } @@ -217,6 +222,82 @@ unsafe fn test_ntstatus_to_dos() { assert_eq!(RtlNtStatusToDosError(STATUS_ACCESS_DENIED), ERROR_ACCESS_DENIED); } +unsafe fn test_file_read_write() { + let temp = utils::tmp().join("test_file_read_write.txt"); + let file = fs::File::create(&temp).unwrap(); + let handle = file.as_raw_handle(); + + // Testing NtWriteFile doesn't clobber the error + SetLastError(1234); + + let text = b"Example text!"; + let mut status = std::mem::zeroed::(); + let out = NtWriteFile( + handle, + ptr::null_mut(), + None, + ptr::null_mut(), + &mut status, + text.as_ptr().cast(), + text.len() as u32, + ptr::null_mut(), + ptr::null_mut(), + ); + + assert_eq!(out, status.Anonymous.Status); + assert_eq!(out, STATUS_SUCCESS); + assert_eq!(GetLastError(), 1234); + + let file = fs::File::open(&temp).unwrap(); + let handle = file.as_raw_handle(); + + // Testing NtReadFile doesn't clobber the error + SetLastError(1234); + + let mut buffer = vec![0; 13]; + let out = NtReadFile( + handle, + ptr::null_mut(), + None, + ptr::null_mut(), + &mut status, + buffer.as_mut_ptr().cast(), + buffer.len() as u32, + ptr::null_mut(), + ptr::null_mut(), + ); + + assert_eq!(out, status.Anonymous.Status); + assert_eq!(out, STATUS_SUCCESS); + assert_eq!(buffer, text); + assert_eq!(GetLastError(), 1234); +} + +unsafe fn test_file_seek() { + let temp = utils::tmp().join("test_file_seek.txt"); + let mut file = fs::File::options().create(true).write(true).read(true).open(&temp).unwrap(); + file.write_all(b"Hello, World!\n").unwrap(); + + let handle = file.as_raw_handle(); + + if SetFilePointerEx(handle, 7, ptr::null_mut(), FILE_BEGIN) == 0 { + panic!("Failed to seek"); + } + + let mut buf = vec![0; 5]; + file.read(&mut buf).unwrap(); + assert_eq!(buf, b"World"); + + let mut pos = 0; + if SetFilePointerEx(handle, -7, &mut pos, FILE_CURRENT) == 0 { + panic!("Failed to seek"); + } + buf.truncate(2); + file.read_exact(&mut buf).unwrap(); + assert_eq!(buf, b", "); + assert_eq!(pos, 5); +} + fn to_wide_cstr(path: &Path) -> Vec { let mut raw_path = path.as_os_str().encode_wide().collect::>(); raw_path.extend([0, 0]); diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs index d0a7f245ee0ff..315637ff7ec73 100644 --- a/src/tools/miri/tests/pass/shims/fs.rs +++ b/src/tools/miri/tests/pass/shims/fs.rs @@ -17,20 +17,20 @@ mod utils; fn main() { test_path_conversion(); + test_file(); test_file_create_new(); + test_metadata(); + test_seek(); + test_errors(); + test_from_raw_os_error(); // Windows file handling is very incomplete. if cfg!(not(windows)) { - test_file(); - test_seek(); test_file_clone(); - test_metadata(); test_file_set_len(); test_file_sync(); - test_errors(); test_rename(); test_directory(); test_canonicalize(); - test_from_raw_os_error(); #[cfg(unix)] test_pread_pwrite(); } From 9e1f3a50e9f0594618d6c8d830d4062a49b8b912 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 22 May 2025 09:11:06 +0200 Subject: [PATCH 2606/4206] enable isolated-stdin test on Windows --- src/tools/miri/tests/fail/shims/isolated_stdin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/tests/fail/shims/isolated_stdin.rs b/src/tools/miri/tests/fail/shims/isolated_stdin.rs index 040c3cc216481..9f809039adad7 100644 --- a/src/tools/miri/tests/fail/shims/isolated_stdin.rs +++ b/src/tools/miri/tests/fail/shims/isolated_stdin.rs @@ -1,7 +1,7 @@ -//@ignore-target: windows # FIXME: stdin does not work on Windows //@error-in-other-file: `read` from stdin not available when isolation is enabled //@normalize-stderr-test: "src/sys/.*\.rs" -> "$$FILE" //@normalize-stderr-test: "\nLL \| .*" -> "" +//@normalize-stderr-test: "\n... .*" -> "" //@normalize-stderr-test: "\| +[|_^]+" -> "| ^" //@normalize-stderr-test: "\n *= note:.*" -> "" use std::io::{self, Read}; From fb181cf6603ebe56a9cc39b9a1bcbc39a226f190 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 22 May 2025 07:35:59 +0000 Subject: [PATCH 2607/4206] Remove rust-analyzer.vs from other editors --- .../docs/book/src/other_editors.md | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/src/tools/rust-analyzer/docs/book/src/other_editors.md b/src/tools/rust-analyzer/docs/book/src/other_editors.md index 1eac7dd2c2568..896df52af5f94 100644 --- a/src/tools/rust-analyzer/docs/book/src/other_editors.md +++ b/src/tools/rust-analyzer/docs/book/src/other_editors.md @@ -364,30 +364,6 @@ binary](./rust_analyzer_binary.html). There are multiple rust-analyzer extensions for Visual Studio 2022 on Windows: -### rust-analyzer.vs - -(License: Creative Commons Attribution-NonCommercial-ShareAlike 4.0 -International) - -[Visual Studio -Marketplace](https://marketplace.visualstudio.com/items?itemName=kitamstudios.RustAnalyzer) - -[GitHub](https://github.com/kitamstudios/rust-analyzer/) - -Support for Rust development in the Visual Studio IDE is enabled by the -[rust-analyzer](https://marketplace.visualstudio.com/items?itemName=kitamstudios.RustAnalyzer) -package. Either click on the download link or install from IDE’s -extension manager. For now [Visual Studio -2022](https://visualstudio.microsoft.com/downloads/) is required. All -editions are supported viz. Community, Professional & Enterprise. The -package aims to provide 0-friction installation and therefore comes -loaded with most things required including rust-analyzer binary. If -anything it needs is missing, appropriate errors / warnings will guide -the user. E.g. cargo.exe needs to be in path and the package will tell -you as much. This package is under rapid active development. So if you -encounter any issues please file it at -[rust-analyzer.vs](https://github.com/kitamstudios/rust-analyzer/). - ### VS RustAnalyzer (License: GPL) From 27677ef14393e7789f2d0a29bfdcf20bf657eddb Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Thu, 22 May 2025 09:53:35 +0200 Subject: [PATCH 2608/4206] ci: convert distcheck to free runner --- src/ci/github-actions/jobs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 005007bbccdd1..58a1db93e6e3c 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -324,7 +324,7 @@ auto: <<: *job-linux-4c - name: x86_64-gnu-distcheck - <<: *job-linux-8c + <<: *job-linux-4c # The x86_64-gnu-llvm-20 job is split into multiple jobs to run tests in parallel. # x86_64-gnu-llvm-20-1 skips tests that run in x86_64-gnu-llvm-20-{2,3}. From b9e69959c6a7c26159d2b7f3be1e7c92d1f13452 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 22 May 2025 08:41:18 +0200 Subject: [PATCH 2609/4206] run core and alloc tests with strict provenance --- src/bootstrap/mk/Makefile.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 7e0eb473fb3fa..1ef3e07acf016 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -54,7 +54,8 @@ check-aux: src/etc/test-float-parse \ $(BOOTSTRAP_ARGS) # Run standard library tests in Miri. - $(Q)$(BOOTSTRAP) miri --stage 2 \ + $(Q)MIRIFLAGS="-Zmiri-strict-provenance" \ + $(BOOTSTRAP) miri --stage 2 \ library/coretests \ library/alloctests \ library/alloc \ From 3f0c39de36efd6ed4ee3e7a6979a0d71a04ffcce Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 22 May 2025 10:13:45 +0200 Subject: [PATCH 2610/4206] update lockfile --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e2b7b58c372ba..8ccad78614ba3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3118,9 +3118,9 @@ dependencies = [ [[package]] name = "rustc-build-sysroot" -version = "0.5.5" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb332121f7845c6bd016f9655cf22f03c2999df936694b624a88669a78667d98" +checksum = "10edc2e4393515193bd766e2f6c050b0536a68e56f2b6d56c07ababfdc114ff0" dependencies = [ "anyhow", "rustc_version", From 8bed64670f6e99b7b5d2f1e069bb37a8c8915c43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 22 May 2025 11:21:24 +0200 Subject: [PATCH 2611/4206] Enable review queue tracking --- triagebot.toml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index fd7a861bc92dc..2d63655b708e9 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1411,8 +1411,10 @@ compiletest = [ "/src/tools/rustdoc-gui-test" = ["bootstrap", "@onur-ozkan"] "/src/tools/libcxx-version" = ["@onur-ozkan"] -# Enable tracking of PR review assignment -# Documentation at: https://forge.rust-lang.org/triagebot/pr-assignment-tracking.html +# Enable review queue tracking +# Documentation at: https://forge.rust-lang.org/triagebot/review-queue-tracking.html +[assign.review_prefs] + [pr-tracking] # Enable issue transfers within the org From 7966f1b556f39882b3e451533a74a3b24a34cb05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A1lyi=20L=C5=91rinc?= Date: Sat, 10 May 2025 08:36:28 +0000 Subject: [PATCH 2612/4206] fixed typo in readme --- library/compiler-builtins/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/README.md b/library/compiler-builtins/README.md index 3130ff7b77d9d..177bce624e0a1 100644 --- a/library/compiler-builtins/README.md +++ b/library/compiler-builtins/README.md @@ -5,7 +5,7 @@ This repository contains two main crates: * `compiler-builtins`: symbols that the compiler expects to be available at link time * `libm`: a Rust implementation of C math libraries, used to provide - implementations in `ocre`. + implementations in `core`. More details are at [compiler-builtins/README.md](compiler-builtins/README.md) and [libm/README.md](libm/README.md). From 8373bb17d6f9ccb00171f788bbc1379bffc61f68 Mon Sep 17 00:00:00 2001 From: bendn Date: Tue, 29 Apr 2025 13:51:45 +0700 Subject: [PATCH 2613/4206] use uX::from instead of _ as uX in non - const contexts --- .../src/check_unnecessary_transmutes.rs | 19 ++- .../transmute/unnecessary-transmutation.fixed | 24 +++- .../ui/transmute/unnecessary-transmutation.rs | 20 ++++ .../unnecessary-transmutation.stderr | 113 +++++++++++------- 4 files changed, 130 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs b/compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs index 0514de3ea13fb..1a3715465ad4e 100644 --- a/compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs +++ b/compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs @@ -30,6 +30,7 @@ impl<'a, 'tcx> UnnecessaryTransmuteChecker<'a, 'tcx> { function: &Operand<'tcx>, arg: String, span: Span, + is_in_const: bool, ) -> Option { let fn_sig = function.ty(self.body, self.tcx).fn_sig(self.tcx).skip_binder(); let [input] = fn_sig.inputs() else { return None }; @@ -97,8 +98,14 @@ impl<'a, 'tcx> UnnecessaryTransmuteChecker<'a, 'tcx> { )), // uNN → fNN (Uint(_), Float(ty)) => err(format!("{}::from_bits({arg})", ty.name_str())), - // bool → { x8 } - (Bool, Int(..) | Uint(..)) => err(format!("({arg}) as {}", fn_sig.output())), + // bool → { x8 } in const context since `From::from` is not const yet + // FIXME: is it possible to know when the parentheses arent necessary? + // FIXME(const_traits): Remove this when From::from is constified? + (Bool, Int(..) | Uint(..)) if is_in_const => { + err(format!("({arg}) as {}", fn_sig.output())) + } + // " using `x8::from` + (Bool, Int(..) | Uint(..)) => err(format!("{}::from({arg})", fn_sig.output())), _ => return None, }) } @@ -114,7 +121,13 @@ impl<'tcx> Visitor<'tcx> for UnnecessaryTransmuteChecker<'_, 'tcx> { && self.tcx.is_intrinsic(func_def_id, sym::transmute) && let span = self.body.source_info(location).span && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(arg) - && let Some(lint) = self.is_unnecessary_transmute(func, snippet, span) + && let def_id = self.body.source.def_id() + && let Some(lint) = self.is_unnecessary_transmute( + func, + snippet, + span, + self.tcx.hir_body_const_context(def_id.expect_local()).is_some(), + ) && let Some(hir_id) = terminator.source_info.scope.lint_root(&self.body.source_scopes) { self.tcx.emit_node_span_lint(UNNECESSARY_TRANSMUTES, hir_id, span, lint); diff --git a/tests/ui/transmute/unnecessary-transmutation.fixed b/tests/ui/transmute/unnecessary-transmutation.fixed index f6478c5aa5c2f..08010ec8b84e4 100644 --- a/tests/ui/transmute/unnecessary-transmutation.fixed +++ b/tests/ui/transmute/unnecessary-transmutation.fixed @@ -8,7 +8,27 @@ pub fn bytes_at_home(x: u32) -> [u8; 4] { //~^ ERROR } +pub const fn intinator_const(from: bool) -> u8 { + unsafe { (from) as u8 } + //~^ ERROR +} + +pub static X: u8 = unsafe { (true) as u8 }; +//~^ ERROR +pub const Y: u8 = unsafe { (true) as u8 }; +//~^ ERROR + +pub struct Z {} +impl Z { + pub const fn intinator_assoc(x: bool) -> u8 { + unsafe { (x) as u8 } + //~^ ERROR + } +} + fn main() { + const { unsafe { (true) as u8 } }; + //~^ ERROR unsafe { let x: u16 = u16::from_ne_bytes(*b"01"); //~^ ERROR @@ -83,12 +103,12 @@ fn main() { let z: bool = transmute(1u8); // clippy - let z: u8 = (z) as u8; + let z: u8 = u8::from(z); //~^ ERROR let z: bool = transmute(1i8); // clippy - let z: i8 = (z) as i8; + let z: i8 = i8::from(z); //~^ ERROR } } diff --git a/tests/ui/transmute/unnecessary-transmutation.rs b/tests/ui/transmute/unnecessary-transmutation.rs index ab0af03acc2ec..43eefb97dc28f 100644 --- a/tests/ui/transmute/unnecessary-transmutation.rs +++ b/tests/ui/transmute/unnecessary-transmutation.rs @@ -8,7 +8,27 @@ pub fn bytes_at_home(x: u32) -> [u8; 4] { //~^ ERROR } +pub const fn intinator_const(from: bool) -> u8 { + unsafe { transmute(from) } + //~^ ERROR +} + +pub static X: u8 = unsafe { transmute(true) }; +//~^ ERROR +pub const Y: u8 = unsafe { transmute(true) }; +//~^ ERROR + +pub struct Z {} +impl Z { + pub const fn intinator_assoc(x: bool) -> u8 { + unsafe { transmute(x) } + //~^ ERROR + } +} + fn main() { + const { unsafe { transmute::<_, u8>(true) } }; + //~^ ERROR unsafe { let x: u16 = transmute(*b"01"); //~^ ERROR diff --git a/tests/ui/transmute/unnecessary-transmutation.stderr b/tests/ui/transmute/unnecessary-transmutation.stderr index 59e933bbc81b9..602e964f5b2bd 100644 --- a/tests/ui/transmute/unnecessary-transmutation.stderr +++ b/tests/ui/transmute/unnecessary-transmutation.stderr @@ -1,10 +1,9 @@ error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:7:14 + --> $DIR/unnecessary-transmutation.rs:16:29 | -LL | unsafe { transmute(x) } - | ^^^^^^^^^^^^ help: replace this with: `u32::to_ne_bytes(x)` +LL | pub static X: u8 = unsafe { transmute(true) }; + | ^^^^^^^^^^^^^^^ help: replace this with: `(true) as u8` | - = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order note: the lint level is defined here --> $DIR/unnecessary-transmutation.rs:2:9 | @@ -12,7 +11,33 @@ LL | #![deny(unnecessary_transmutes)] | ^^^^^^^^^^^^^^^^^^^^^^ error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:13:22 + --> $DIR/unnecessary-transmutation.rs:18:28 + | +LL | pub const Y: u8 = unsafe { transmute(true) }; + | ^^^^^^^^^^^^^^^ help: replace this with: `(true) as u8` + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:7:14 + | +LL | unsafe { transmute(x) } + | ^^^^^^^^^^^^ help: replace this with: `u32::to_ne_bytes(x)` + | + = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:12:14 + | +LL | unsafe { transmute(from) } + | ^^^^^^^^^^^^^^^ help: replace this with: `(from) as u8` + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:24:18 + | +LL | unsafe { transmute(x) } + | ^^^^^^^^^^^^ help: replace this with: `(x) as u8` + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:33:22 | LL | let x: u16 = transmute(*b"01"); | ^^^^^^^^^^^^^^^^^ help: replace this with: `u16::from_ne_bytes(*b"01")` @@ -20,7 +45,7 @@ LL | let x: u16 = transmute(*b"01"); = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:15:26 + --> $DIR/unnecessary-transmutation.rs:35:26 | LL | let x: [u8; 2] = transmute(x); | ^^^^^^^^^^^^ help: replace this with: `u16::to_ne_bytes(x)` @@ -28,7 +53,7 @@ LL | let x: [u8; 2] = transmute(x); = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:17:22 + --> $DIR/unnecessary-transmutation.rs:37:22 | LL | let x: u32 = transmute(*b"0123"); | ^^^^^^^^^^^^^^^^^^^ help: replace this with: `u32::from_ne_bytes(*b"0123")` @@ -36,7 +61,7 @@ LL | let x: u32 = transmute(*b"0123"); = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:19:26 + --> $DIR/unnecessary-transmutation.rs:39:26 | LL | let x: [u8; 4] = transmute(x); | ^^^^^^^^^^^^ help: replace this with: `u32::to_ne_bytes(x)` @@ -44,7 +69,7 @@ LL | let x: [u8; 4] = transmute(x); = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:21:22 + --> $DIR/unnecessary-transmutation.rs:41:22 | LL | let x: u64 = transmute(*b"feriscat"); | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `u64::from_ne_bytes(*b"feriscat")` @@ -52,7 +77,7 @@ LL | let x: u64 = transmute(*b"feriscat"); = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:23:26 + --> $DIR/unnecessary-transmutation.rs:43:26 | LL | let x: [u8; 8] = transmute(x); | ^^^^^^^^^^^^ help: replace this with: `u64::to_ne_bytes(x)` @@ -60,7 +85,7 @@ LL | let x: [u8; 8] = transmute(x); = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:26:22 + --> $DIR/unnecessary-transmutation.rs:46:22 | LL | let y: i16 = transmute(*b"01"); | ^^^^^^^^^^^^^^^^^ help: replace this with: `i16::from_ne_bytes(*b"01")` @@ -68,7 +93,7 @@ LL | let y: i16 = transmute(*b"01"); = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:28:26 + --> $DIR/unnecessary-transmutation.rs:48:26 | LL | let y: [u8; 2] = transmute(y); | ^^^^^^^^^^^^ help: replace this with: `i16::to_ne_bytes(y)` @@ -76,7 +101,7 @@ LL | let y: [u8; 2] = transmute(y); = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:30:22 + --> $DIR/unnecessary-transmutation.rs:50:22 | LL | let y: i32 = transmute(*b"0123"); | ^^^^^^^^^^^^^^^^^^^ help: replace this with: `i32::from_ne_bytes(*b"0123")` @@ -84,7 +109,7 @@ LL | let y: i32 = transmute(*b"0123"); = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:32:26 + --> $DIR/unnecessary-transmutation.rs:52:26 | LL | let y: [u8; 4] = transmute(y); | ^^^^^^^^^^^^ help: replace this with: `i32::to_ne_bytes(y)` @@ -92,7 +117,7 @@ LL | let y: [u8; 4] = transmute(y); = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:34:22 + --> $DIR/unnecessary-transmutation.rs:54:22 | LL | let y: i64 = transmute(*b"feriscat"); | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `i64::from_ne_bytes(*b"feriscat")` @@ -100,7 +125,7 @@ LL | let y: i64 = transmute(*b"feriscat"); = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:36:26 + --> $DIR/unnecessary-transmutation.rs:56:26 | LL | let y: [u8; 8] = transmute(y); | ^^^^^^^^^^^^ help: replace this with: `i64::to_ne_bytes(y)` @@ -108,7 +133,7 @@ LL | let y: [u8; 8] = transmute(y); = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:39:22 + --> $DIR/unnecessary-transmutation.rs:59:22 | LL | let z: f32 = transmute(*b"0123"); | ^^^^^^^^^^^^^^^^^^^ help: replace this with: `f32::from_ne_bytes(*b"0123")` @@ -116,7 +141,7 @@ LL | let z: f32 = transmute(*b"0123"); = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:41:26 + --> $DIR/unnecessary-transmutation.rs:61:26 | LL | let z: [u8; 4] = transmute(z); | ^^^^^^^^^^^^ help: replace this with: `f32::to_ne_bytes(z)` @@ -124,7 +149,7 @@ LL | let z: [u8; 4] = transmute(z); = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:43:22 + --> $DIR/unnecessary-transmutation.rs:63:22 | LL | let z: f64 = transmute(*b"feriscat"); | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `f64::from_ne_bytes(*b"feriscat")` @@ -132,7 +157,7 @@ LL | let z: f64 = transmute(*b"feriscat"); = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:45:26 + --> $DIR/unnecessary-transmutation.rs:65:26 | LL | let z: [u8; 8] = transmute(z); | ^^^^^^^^^^^^ help: replace this with: `f64::to_ne_bytes(z)` @@ -140,13 +165,13 @@ LL | let z: [u8; 8] = transmute(z); = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:48:22 + --> $DIR/unnecessary-transmutation.rs:68:22 | LL | let y: u32 = transmute('🦀'); | ^^^^^^^^^^^^^^^ help: replace this with: `u32::from('🦀')` error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:50:23 + --> $DIR/unnecessary-transmutation.rs:70:23 | LL | let y: char = transmute(y); | ^^^^^^^^^^^^ help: replace this with: `char::from_u32_unchecked(y)` @@ -154,13 +179,13 @@ LL | let y: char = transmute(y); = help: consider `char::from_u32(…).unwrap()` error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:52:22 + --> $DIR/unnecessary-transmutation.rs:72:22 | LL | let y: i32 = transmute('🐱'); | ^^^^^^^^^^^^^^^ help: replace this with: `u32::from('🐱').cast_signed()` error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:54:23 + --> $DIR/unnecessary-transmutation.rs:74:23 | LL | let y: char = transmute(y); | ^^^^^^^^^^^^ help: replace this with: `char::from_u32_unchecked(i32::cast_unsigned(y))` @@ -168,88 +193,94 @@ LL | let y: char = transmute(y); = help: consider `char::from_u32(i32::cast_unsigned(…)).unwrap()` error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:57:22 + --> $DIR/unnecessary-transmutation.rs:77:22 | LL | let x: u16 = transmute(8i16); | ^^^^^^^^^^^^^^^ help: replace this with: `i16::cast_unsigned(8i16)` error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:59:22 + --> $DIR/unnecessary-transmutation.rs:79:22 | LL | let x: i16 = transmute(x); | ^^^^^^^^^^^^ help: replace this with: `u16::cast_signed(x)` error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:61:22 + --> $DIR/unnecessary-transmutation.rs:81:22 | LL | let x: u32 = transmute(4i32); | ^^^^^^^^^^^^^^^ help: replace this with: `i32::cast_unsigned(4i32)` error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:63:22 + --> $DIR/unnecessary-transmutation.rs:83:22 | LL | let x: i32 = transmute(x); | ^^^^^^^^^^^^ help: replace this with: `u32::cast_signed(x)` error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:65:22 + --> $DIR/unnecessary-transmutation.rs:85:22 | LL | let x: u64 = transmute(7i64); | ^^^^^^^^^^^^^^^ help: replace this with: `i64::cast_unsigned(7i64)` error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:67:22 + --> $DIR/unnecessary-transmutation.rs:87:22 | LL | let x: i64 = transmute(x); | ^^^^^^^^^^^^ help: replace this with: `u64::cast_signed(x)` error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:70:22 + --> $DIR/unnecessary-transmutation.rs:90:22 | LL | let y: f32 = transmute(1u32); | ^^^^^^^^^^^^^^^ help: replace this with: `f32::from_bits(1u32)` error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:72:22 + --> $DIR/unnecessary-transmutation.rs:92:22 | LL | let y: u32 = transmute(y); | ^^^^^^^^^^^^ help: replace this with: `f32::to_bits(y)` error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:74:22 + --> $DIR/unnecessary-transmutation.rs:94:22 | LL | let y: f64 = transmute(3u64); | ^^^^^^^^^^^^^^^ help: replace this with: `f64::from_bits(3u64)` error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:76:22 + --> $DIR/unnecessary-transmutation.rs:96:22 | LL | let y: u64 = transmute(2.0); | ^^^^^^^^^^^^^^ help: replace this with: `f64::to_bits(2.0)` error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:79:22 + --> $DIR/unnecessary-transmutation.rs:99:22 | LL | let y: f64 = transmute(1i64); | ^^^^^^^^^^^^^^^ help: replace this with: `f64::from_bits(i64::cast_unsigned(1i64))` error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:81:22 + --> $DIR/unnecessary-transmutation.rs:101:22 | LL | let y: i64 = transmute(1f64); | ^^^^^^^^^^^^^^^ help: replace this with: `f64::to_bits(1f64).cast_signed()` error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:86:21 + --> $DIR/unnecessary-transmutation.rs:106:21 | LL | let z: u8 = transmute(z); - | ^^^^^^^^^^^^ help: replace this with: `(z) as u8` + | ^^^^^^^^^^^^ help: replace this with: `u8::from(z)` error: unnecessary transmute - --> $DIR/unnecessary-transmutation.rs:91:21 + --> $DIR/unnecessary-transmutation.rs:111:21 | LL | let z: i8 = transmute(z); - | ^^^^^^^^^^^^ help: replace this with: `(z) as i8` + | ^^^^^^^^^^^^ help: replace this with: `i8::from(z)` + +error: unnecessary transmute + --> $DIR/unnecessary-transmutation.rs:30:22 + | +LL | const { unsafe { transmute::<_, u8>(true) } }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `(true) as u8` -error: aborting due to 35 previous errors +error: aborting due to 40 previous errors From 7d32303574c63cb396d5e1cb17f00061665a0f75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 22 May 2025 12:09:37 +0200 Subject: [PATCH 2614/4206] Move `dist-x86_64-linux` CI job to GitHub temporarily To make it easier to migrate off the `rust-lang-ci/rust` repository. --- src/ci/github-actions/jobs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 005007bbccdd1..58d05b057b742 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -228,7 +228,7 @@ auto: - name: dist-x86_64-linux env: CODEGEN_BACKENDS: llvm,cranelift - <<: *job-linux-36c-codebuild + <<: *job-linux-16c - name: dist-x86_64-linux-alt env: From 30c87defe686ca5043e86ad9d795976ce42ca3ff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jan 2025 16:16:10 +0100 Subject: [PATCH 2615/4206] aarch64-softfloat: forbid enabling the neon target feature --- compiler/rustc_target/src/target_features.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 99b04ac272009..576c9bd6b57f7 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -980,14 +980,16 @@ impl Target { // the use of soft-float, so all we can do here is some crude hacks. match &*self.abi { "softfloat" => { - // This is not fully correct, LLVM actually doesn't let us enforce the softfloat - // ABI properly... see . - // FIXME: should we forbid "neon" here? But that would be a breaking change. - NOTHING + // LLVM will use float registers when `fp-armv8` is available, e.g. for + // calls to built-ins. The only way to ensure a consistent softfloat ABI + // on aarch64 is to never enable `fp-armv8`, so we enforce that. + // In Rust we tie `neon` and `fp-armv8` together, therefore `neon` is the + // feature we have to mark as incompatible. + FeatureConstraints { required: &[], incompatible: &["neon"] } } _ => { // Everything else is assumed to use a hardfloat ABI. neon and fp-armv8 must be enabled. - // These are Rust feature names and we use "neon" to control both of them. + // `FeatureConstraints` uses Rust feature names, hence only "neon" shows up. FeatureConstraints { required: &["neon"], incompatible: &[] } } } From 3c020e59a24a7739968fbd891a09e316a86c7b40 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 1 May 2025 11:34:52 +0200 Subject: [PATCH 2616/4206] make enabling the neon target feature a FCW --- compiler/rustc_codegen_ssa/messages.ftl | 2 + .../rustc_codegen_ssa/src/codegen_attrs.rs | 1 + compiler/rustc_codegen_ssa/src/errors.rs | 4 ++ .../rustc_codegen_ssa/src/target_features.rs | 23 ++++++-- compiler/rustc_lint_defs/src/builtin.rs | 58 ++++++++++++++++--- ...compatible-target-feature-attribute-fcw.rs | 14 +++++ ...atible-target-feature-attribute-fcw.stderr | 31 ++++++++++ 7 files changed, 120 insertions(+), 13 deletions(-) create mode 100644 tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.rs create mode 100644 tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.stderr diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 2621935eecf94..acb4cbaa13fc3 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -1,5 +1,7 @@ codegen_ssa_L4Bender_exporting_symbols_unimplemented = exporting symbols not implemented yet for L4Bender +codegen_ssa_aarch64_softfloat_neon = enabling the `neon` target feature on the current target is unsound due to ABI issues + codegen_ssa_add_native_library = failed to add native library {$library_path}: {$error} codegen_ssa_aix_strip_not_used = using host's `strip` binary to cross-compile to AIX which is not guaranteed to work diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index aa55a0e0f1488..b3bda784d43eb 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -299,6 +299,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } from_target_feature_attr( tcx, + did, attr, rust_target_features, &mut codegen_fn_attrs.target_features, diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index d49aac75d0582..572d7b1e06a73 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1316,3 +1316,7 @@ pub(crate) struct XcrunSdkPathWarning { pub sdk_name: &'static str, pub stderr: String, } + +#[derive(LintDiagnostic)] +#[diag(codegen_ssa_aarch64_softfloat_neon)] +pub(crate) struct Aarch64SoftfloatNeon; diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 3ecea522837a1..6bb3150c1c57d 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -8,6 +8,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_middle::middle::codegen_fn_attrs::TargetFeature; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; +use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; use rustc_target::target_features::{self, Stability}; @@ -18,6 +19,7 @@ use crate::errors; /// Enabled target features are added to `target_features`. pub(crate) fn from_target_feature_attr( tcx: TyCtxt<'_>, + did: LocalDefId, attr: &hir::Attribute, rust_target_features: &UnordMap, target_features: &mut Vec, @@ -92,11 +94,22 @@ pub(crate) fn from_target_feature_attr( // generating code so "it's fine". if !tcx.sess.opts.actually_rustdoc { if abi_feature_constraints.incompatible.contains(&name.as_str()) { - tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr { - span: item.span(), - feature: name.as_str(), - reason: "this feature is incompatible with the target ABI", - }); + // For "neon" specifically, we emit an FCW instead of a hard error. + // See . + if tcx.sess.target.arch == "aarch64" && name.as_str() == "neon" { + tcx.emit_node_span_lint( + AARCH64_SOFTFLOAT_NEON, + tcx.local_def_id_to_hir_id(did), + item.span(), + errors::Aarch64SoftfloatNeon, + ); + } else { + tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr { + span: item.span(), + feature: name.as_str(), + reason: "this feature is incompatible with the target ABI", + }); + } } } target_features.push(TargetFeature { name, implied: name != feature_sym }) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 3cea24634feee..b8d242bad86ac 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -16,6 +16,7 @@ declare_lint_pass! { /// that are used by other parts of the compiler. HardwiredLints => [ // tidy-alphabetical-start + AARCH64_SOFTFLOAT_NEON, ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, AMBIGUOUS_ASSOCIATED_ITEMS, AMBIGUOUS_GLOB_IMPORTS, @@ -5043,14 +5044,14 @@ declare_lint! { /// /// ```text /// error: this function function definition is affected by the wasm ABI transition: it passes an argument of non-scalar type `MyType` - /// --> $DIR/wasm_c_abi_transition.rs:17:1 - /// | - /// | pub extern "C" fn my_fun(_x: MyType) {} - /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - /// | - /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - /// = note: for more information, see issue #138762 - /// = help: the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target + /// --> $DIR/wasm_c_abi_transition.rs:17:1 + /// | + /// | pub extern "C" fn my_fun(_x: MyType) {} + /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + /// | + /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + /// = note: for more information, see issue #138762 + /// = help: the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target /// ``` /// /// ### Explanation @@ -5067,3 +5068,44 @@ declare_lint! { reference: "issue #138762 ", }; } + +declare_lint! { + /// The `aarch64_softfloat_neon` lint detects usage of `#[target_feature(enable = "neon")]` on + /// softfloat aarch64 targets. Enabling this target feature causes LLVM to alter the ABI of + /// function calls, making this attribute unsound to use. + /// + /// ### Example + /// + /// ```rust,ignore (needs aarch64-unknown-none-softfloat) + /// #[target_feature(enable = "neon")] + /// fn with_neon() {} + /// ``` + /// + /// This will produce: + /// + /// ```text + /// error: enabling the `neon` target feature on the current target is unsound due to ABI issues + /// --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:11:18 + /// | + /// | #[target_feature(enable = "neon")] + /// | ^^^^^^^^^^^^^^^ + /// | + /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + /// = note: for more information, see issue #134375 + /// ``` + /// + /// ### Explanation + /// + /// If a function like `with_neon` above ends up containing calls to LLVM builtins, those will + /// not use the correct ABI. This is caused by a lack of support in LLVM for mixing code with + /// and without the `neon` target feature. The target feature should never have been stabilized + /// on this target due to this issue, but the problem was not known at the time of + /// stabilization. + pub AARCH64_SOFTFLOAT_NEON, + Warn, + "detects code that could be affected by ABI issues on aarch64 softfloat targets", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, + reference: "issue #134375 ", + }; +} diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.rs b/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.rs new file mode 100644 index 0000000000000..270874a9f5811 --- /dev/null +++ b/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.rs @@ -0,0 +1,14 @@ +//@ compile-flags: --crate-type=lib +//@ compile-flags: --target=aarch64-unknown-none-softfloat +//@ needs-llvm-components: aarch64 +#![feature(no_core, lang_items)] +#![no_core] +#![deny(aarch64_softfloat_neon)] + +#[lang = "sized"] +pub trait Sized {} + +#[target_feature(enable = "neon")] +//~^ERROR: enabling the `neon` target feature on the current target is unsound +//~|WARN: previously accepted +pub unsafe fn my_fun() {} diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.stderr b/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.stderr new file mode 100644 index 0000000000000..bf745291a5a81 --- /dev/null +++ b/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.stderr @@ -0,0 +1,31 @@ +error: enabling the `neon` target feature on the current target is unsound due to ABI issues + --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:11:18 + | +LL | #[target_feature(enable = "neon")] + | ^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #134375 +note: the lint level is defined here + --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:6:9 + | +LL | #![deny(aarch64_softfloat_neon)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +Future incompatibility report: Future breakage diagnostic: +error: enabling the `neon` target feature on the current target is unsound due to ABI issues + --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:11:18 + | +LL | #[target_feature(enable = "neon")] + | ^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #134375 +note: the lint level is defined here + --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:6:9 + | +LL | #![deny(aarch64_softfloat_neon)] + | ^^^^^^^^^^^^^^^^^^^^^^ + From cc10370fc8b2b412600aa846e3046b8a09dda7ca Mon Sep 17 00:00:00 2001 From: Boxy Date: Mon, 14 Apr 2025 13:41:18 +0100 Subject: [PATCH 2617/4206] Reviews --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 38 ++++++++++--------- compiler/rustc_hir_typeck/src/lib.rs | 15 +++++--- .../copy-check-deferred-before-fallback.rs | 2 +- .../copy-check-inference-side-effects.rs | 2 +- 4 files changed, 32 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 124b6e80fd44d..4da014dd23626 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -108,8 +108,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let deferred_repeat_expr_checks = deferred_repeat_expr_checks .drain(..) .flat_map(|(element, element_ty, count)| { - // Actual constants as the repeat element get inserted repeatedly instead of getting copied via Copy - // so we don't need to attempt to structurally resolve the repeat count which may unnecessarily error. + // Actual constants as the repeat element are inserted repeatedly instead + // of being copied via `Copy`, so we don't need to attempt to structurally + // resolve the repeat count which may unnecessarily error. match &element.kind { hir::ExprKind::ConstBlock(..) => return None, hir::ExprKind::Path(qpath) => { @@ -121,23 +122,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => {} } - // We want to emit an error if the const is not structurally resolveable as otherwise - // we can find up conservatively proving `Copy` which may infer the repeat expr count - // to something that never required `Copy` in the first place. + // We want to emit an error if the const is not structurally resolveable + // as otherwise we can wind up conservatively proving `Copy` which may + // infer the repeat expr count to something that never required `Copy` in + // the first place. let count = self .structurally_resolve_const(element.span, self.normalize(element.span, count)); - // Avoid run on "`NotCopy: Copy` is not implemented" errors when the repeat expr count - // is erroneous/unknown. The user might wind up specifying a repeat count of 0/1. + // Avoid run on "`NotCopy: Copy` is not implemented" errors when the + // repeat expr count is erroneous/unknown. The user might wind up + // specifying a repeat count of 0/1. if count.references_error() { return None; } Some((element, element_ty, count)) }) - // We collect to force the side effects of structurally resolving the repeat count to happen in one - // go, to avoid side effects from proving `Copy` affecting whether repeat counts are known or not. - // If we did not do this we would get results that depend on the order that we evaluate each repeat + // We collect to force the side effects of structurally resolving the repeat + // count to happen in one go, to avoid side effects from proving `Copy` + // affecting whether repeat counts are known or not. If we did not do this we + // would get results that depend on the order that we evaluate each repeat // expr's `Copy` check. .collect::>(); @@ -171,14 +175,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for (element, element_ty, count) in deferred_repeat_expr_checks { match count.kind() { - ty::ConstKind::Value(val) - if val.try_to_target_usize(self.tcx).is_none_or(|count| count > 1) => - { - enforce_copy_bound(element, element_ty) + ty::ConstKind::Value(val) => { + if val.try_to_target_usize(self.tcx).is_none_or(|count| count > 1) { + enforce_copy_bound(element, element_ty) + } else { + // If the length is 0 or 1 we don't actually copy the element, we either don't create it + // or we just use the one value. + } } - // If the length is 0 or 1 we don't actually copy the element, we either don't create it - // or we just use the one value. - ty::ConstKind::Value(_) => (), // If the length is a generic parameter or some rigid alias then conservatively // require `element_ty: Copy` as it may wind up being `>1` after monomorphization. diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 161f5e981d430..ba83db7eebd00 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -195,13 +195,16 @@ fn typeck_with_inspect<'tcx>( fcx.write_ty(id, expected_type); }; - // Whether to check repeat exprs before/after inference fallback is somewhat arbitrary of a decision - // as neither option is strictly more permissive than the other. However, we opt to check repeat exprs - // first as errors from not having inferred array lengths yet seem less confusing than errors from inference - // fallback arbitrarily inferring something incompatible with `Copy` inference side effects. + // Whether to check repeat exprs before/after inference fallback is somewhat + // arbitrary of a decision as neither option is strictly more permissive than + // the other. However, we opt to check repeat exprs first as errors from not + // having inferred array lengths yet seem less confusing than errors from inference + // fallback arbitrarily inferring something incompatible with `Copy` inference + // side effects. // - // This should also be forwards compatible with moving repeat expr checks to a custom goal kind or using - // marker traits in the future. + // FIXME(#140855): This should also be forwards compatible with moving + // repeat expr checks to a custom goal kind or using marker traits in + // the future. fcx.check_repeat_exprs(); fcx.type_inference_fallback(); diff --git a/tests/ui/repeat-expr/copy-check-deferred-before-fallback.rs b/tests/ui/repeat-expr/copy-check-deferred-before-fallback.rs index b81997a3c9fa3..4fbb8f0a00caf 100644 --- a/tests/ui/repeat-expr/copy-check-deferred-before-fallback.rs +++ b/tests/ui/repeat-expr/copy-check-deferred-before-fallback.rs @@ -5,7 +5,7 @@ // checked before integer fallback occurs. We accomplish this by having the repeat // expr check allow inference progress on an ambiguous goal, where the ambiguous goal // would fail if the inference variable was fallen back to `i32`. This test will -// pass if wecheck repeat exprs before integer fallback. +// pass if we check repeat exprs before integer fallback. use std::marker::PhantomData; struct Foo(PhantomData); diff --git a/tests/ui/repeat-expr/copy-check-inference-side-effects.rs b/tests/ui/repeat-expr/copy-check-inference-side-effects.rs index 416a20169fba1..4e3bfdead26b4 100644 --- a/tests/ui/repeat-expr/copy-check-inference-side-effects.rs +++ b/tests/ui/repeat-expr/copy-check-inference-side-effects.rs @@ -12,7 +12,7 @@ impl Copy for Foo<1> {} fn unify(_: &[Foo; 2], _: &[String; N]) {} fn works_if_inference_side_effects() { - // This will only pass if inference side effectrs from proving `Foo: Copy` are + // This will only pass if inference side effects from proving `Foo: Copy` are // able to be relied upon by other repeat expressions. let a /* : [Foo; 2] */ = [Foo::<_>; 2]; //~^ ERROR: type annotations needed for `[Foo<_>; 2]` From 806cd12f56446bd31aea495e83661f5c3cf3a17d Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Thu, 22 May 2025 12:48:12 +0200 Subject: [PATCH 2618/4206] ci: prepare aws access keys for migration --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0bce8389d8ec2..566ae2235001c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -234,8 +234,8 @@ jobs: fi exit ${STATUS} env: - AWS_ACCESS_KEY_ID: ${{ env.CACHES_AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }} + AWS_ACCESS_KEY_ID: ${{ (github.repository == 'rust-lang/rust' && secrets.CACHES_AWS_ACCESS_KEY_ID) || env.CACHES_AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ (github.repository == 'rust-lang/rust' && secrets.CACHES_AWS_SECRET_ACCESS_KEY) || secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }} - name: create github artifacts run: src/ci/scripts/create-doc-artifacts.sh @@ -257,8 +257,8 @@ jobs: - name: upload artifacts to S3 run: src/ci/scripts/upload-artifacts.sh env: - AWS_ACCESS_KEY_ID: ${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }} + AWS_ACCESS_KEY_ID: ${{ (github.repository == 'rust-lang/rust' && secrets.ARTIFACTS_AWS_ACCESS_KEY_ID) || env.ARTIFACTS_AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ (github.repository == 'rust-lang/rust' && secrets.ARTIFACTS_AWS_SECRET_ACCESS_KEY) || secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }} # Adding a condition on DEPLOY=1 or DEPLOY_ALT=1 is not needed as all deploy # builders *should* have the AWS credentials available. Still, explicitly # adding the condition is helpful as this way CI will not silently skip From bc9cdc960f7ba7a926cea97cf0cec77097ca7851 Mon Sep 17 00:00:00 2001 From: Boxy Date: Wed, 21 May 2025 18:37:39 +0100 Subject: [PATCH 2619/4206] Return correct error term kind on projection errors --- .../src/traits/project.rs | 29 ++++++++++++-- tests/crashes/140642.rs | 8 ---- .../const-generics/mgca/projection-error.rs | 17 ++++++++ .../mgca/projection-error.stderr | 39 +++++++++++++++++++ 4 files changed, 81 insertions(+), 12 deletions(-) delete mode 100644 tests/crashes/140642.rs create mode 100644 tests/ui/const-generics/mgca/projection-error.rs create mode 100644 tests/ui/const-generics/mgca/projection-error.stderr diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index ca58da5ca6d55..ed0f34b5aa915 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -378,6 +378,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( term: projected_term, obligations: mut projected_obligations, })) => { + debug!("opt_normalize_projection_type: progress"); // if projection succeeded, then what we get out of this // is also non-normalized (consider: it was derived from // an impl, where-clause etc) and hence we must @@ -408,6 +409,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( Ok(Some(result.value)) } Ok(Projected::NoProgress(projected_ty)) => { + debug!("opt_normalize_projection_type: no progress"); let result = Normalized { value: projected_ty, obligations: PredicateObligations::new() }; infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); @@ -621,8 +623,17 @@ struct Progress<'tcx> { } impl<'tcx> Progress<'tcx> { - fn error(tcx: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Self { - Progress { term: Ty::new_error(tcx, guar).into(), obligations: PredicateObligations::new() } + fn error_for_term( + tcx: TyCtxt<'tcx>, + alias_term: ty::AliasTerm<'tcx>, + guar: ErrorGuaranteed, + ) -> Self { + let err_term = if alias_term.kind(tcx).is_type() { + Ty::new_error(tcx, guar).into() + } else { + ty::Const::new_error(tcx, guar).into() + }; + Progress { term: err_term, obligations: PredicateObligations::new() } } fn with_addl_obligations(mut self, mut obligations: PredicateObligations<'tcx>) -> Self { @@ -650,7 +661,11 @@ fn project<'cx, 'tcx>( } if let Err(guar) = obligation.predicate.error_reported() { - return Ok(Projected::Progress(Progress::error(selcx.tcx(), guar))); + return Ok(Projected::Progress(Progress::error_for_term( + selcx.tcx(), + obligation.predicate, + guar, + ))); } let mut candidates = ProjectionCandidateSet::None; @@ -1965,7 +1980,13 @@ fn confirm_impl_candidate<'cx, 'tcx>( let param_env = obligation.param_env; let assoc_term = match specialization_graph::assoc_def(tcx, impl_def_id, assoc_item_id) { Ok(assoc_term) => assoc_term, - Err(guar) => return Ok(Projected::Progress(Progress::error(tcx, guar))), + Err(guar) => { + return Ok(Projected::Progress(Progress::error_for_term( + tcx, + obligation.predicate, + guar, + ))); + } }; // This means that the impl is missing a definition for the diff --git a/tests/crashes/140642.rs b/tests/crashes/140642.rs deleted file mode 100644 index ff75a6ec2f230..0000000000000 --- a/tests/crashes/140642.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: #140642 -#![feature(min_generic_const_args)] - -pub trait Tr { - const SIZE: usize; -} - -fn mk_array(_x: T) -> [(); >::SIZE] {} diff --git a/tests/ui/const-generics/mgca/projection-error.rs b/tests/ui/const-generics/mgca/projection-error.rs new file mode 100644 index 0000000000000..d1c4fa8a492d3 --- /dev/null +++ b/tests/ui/const-generics/mgca/projection-error.rs @@ -0,0 +1,17 @@ +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +// Regression test for #140642. Test that normalizing const aliases +// containing erroneous types normalizes to a const error instead of +// a type error. + + +pub trait Tr { + const SIZE: usize; +} + +fn mk_array(_x: T) -> [(); >::SIZE] {} +//~^ ERROR: cannot find type `T` in this scope +//~| ERROR: cannot find type `T` in this scope + +fn main() {} diff --git a/tests/ui/const-generics/mgca/projection-error.stderr b/tests/ui/const-generics/mgca/projection-error.stderr new file mode 100644 index 0000000000000..e6888351da13a --- /dev/null +++ b/tests/ui/const-generics/mgca/projection-error.stderr @@ -0,0 +1,39 @@ +error[E0412]: cannot find type `T` in this scope + --> $DIR/projection-error.rs:13:17 + | +LL | pub trait Tr { + | --------------- similarly named trait `Tr` defined here +... +LL | fn mk_array(_x: T) -> [(); >::SIZE] {} + | ^ + | +help: a trait with a similar name exists + | +LL | fn mk_array(_x: Tr) -> [(); >::SIZE] {} + | + +help: you might be missing a type parameter + | +LL | fn mk_array(_x: T) -> [(); >::SIZE] {} + | +++ + +error[E0412]: cannot find type `T` in this scope + --> $DIR/projection-error.rs:13:29 + | +LL | pub trait Tr { + | --------------- similarly named trait `Tr` defined here +... +LL | fn mk_array(_x: T) -> [(); >::SIZE] {} + | ^ + | +help: a trait with a similar name exists + | +LL | fn mk_array(_x: T) -> [(); >::SIZE] {} + | + +help: you might be missing a type parameter + | +LL | fn mk_array(_x: T) -> [(); >::SIZE] {} + | +++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0412`. From db21837095f18a76d1fecb7d55547688a6b19647 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 22 Apr 2025 19:35:21 -0400 Subject: [PATCH 2620/4206] libm: Clean up unused files These were deleted during refactoring in 0a2dc5d9 ("Combine the source files for more generic implementations") but got added back by accident in 54bac411 ("refactor: Move the libm crate to a subdirectory"). Remove them again here. --- .../libm/src/math/copysignf.rs | 8 ---- .../libm/src/math/copysignf128.rs | 8 ---- .../libm/src/math/copysignf16.rs | 8 ---- .../compiler-builtins/libm/src/math/fabsf.rs | 39 ------------------- .../libm/src/math/fabsf128.rs | 31 --------------- .../libm/src/math/fabsf16.rs | 31 --------------- .../compiler-builtins/libm/src/math/fdimf.rs | 12 ------ .../libm/src/math/fdimf128.rs | 12 ------ .../libm/src/math/fdimf16.rs | 12 ------ .../compiler-builtins/libm/src/math/floorf.rs | 13 ------- .../libm/src/math/floorf128.rs | 7 ---- .../libm/src/math/floorf16.rs | 7 ---- .../compiler-builtins/libm/src/math/fmodf.rs | 5 --- .../libm/src/math/fmodf128.rs | 5 --- .../libm/src/math/fmodf16.rs | 5 --- .../compiler-builtins/libm/src/math/ldexpf.rs | 4 -- .../libm/src/math/ldexpf128.rs | 4 -- .../libm/src/math/ldexpf16.rs | 4 -- .../compiler-builtins/libm/src/math/roundf.rs | 5 --- .../libm/src/math/roundf128.rs | 5 --- .../libm/src/math/roundf16.rs | 5 --- .../libm/src/math/scalbnf.rs | 4 -- .../libm/src/math/scalbnf128.rs | 4 -- .../libm/src/math/scalbnf16.rs | 4 -- .../compiler-builtins/libm/src/math/sqrtf.rs | 15 ------- .../libm/src/math/sqrtf128.rs | 5 --- .../libm/src/math/sqrtf16.rs | 11 ------ .../compiler-builtins/libm/src/math/truncf.rs | 23 ----------- .../libm/src/math/truncf128.rs | 7 ---- .../libm/src/math/truncf16.rs | 7 ---- 30 files changed, 310 deletions(-) delete mode 100644 library/compiler-builtins/libm/src/math/copysignf.rs delete mode 100644 library/compiler-builtins/libm/src/math/copysignf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/copysignf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/fabsf.rs delete mode 100644 library/compiler-builtins/libm/src/math/fabsf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/fabsf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/fdimf.rs delete mode 100644 library/compiler-builtins/libm/src/math/fdimf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/fdimf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/floorf.rs delete mode 100644 library/compiler-builtins/libm/src/math/floorf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/floorf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/fmodf.rs delete mode 100644 library/compiler-builtins/libm/src/math/fmodf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/fmodf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/ldexpf.rs delete mode 100644 library/compiler-builtins/libm/src/math/ldexpf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/ldexpf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/roundf.rs delete mode 100644 library/compiler-builtins/libm/src/math/roundf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/roundf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/scalbnf.rs delete mode 100644 library/compiler-builtins/libm/src/math/scalbnf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/scalbnf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/sqrtf.rs delete mode 100644 library/compiler-builtins/libm/src/math/sqrtf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/sqrtf16.rs delete mode 100644 library/compiler-builtins/libm/src/math/truncf.rs delete mode 100644 library/compiler-builtins/libm/src/math/truncf128.rs delete mode 100644 library/compiler-builtins/libm/src/math/truncf16.rs diff --git a/library/compiler-builtins/libm/src/math/copysignf.rs b/library/compiler-builtins/libm/src/math/copysignf.rs deleted file mode 100644 index 8b9bed4c0c427..0000000000000 --- a/library/compiler-builtins/libm/src/math/copysignf.rs +++ /dev/null @@ -1,8 +0,0 @@ -/// Sign of Y, magnitude of X (f32) -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysignf(x: f32, y: f32) -> f32 { - super::generic::copysign(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/copysignf128.rs b/library/compiler-builtins/libm/src/math/copysignf128.rs deleted file mode 100644 index 7bd81d42b2e9a..0000000000000 --- a/library/compiler-builtins/libm/src/math/copysignf128.rs +++ /dev/null @@ -1,8 +0,0 @@ -/// Sign of Y, magnitude of X (f128) -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysignf128(x: f128, y: f128) -> f128 { - super::generic::copysign(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/copysignf16.rs b/library/compiler-builtins/libm/src/math/copysignf16.rs deleted file mode 100644 index 8206586860102..0000000000000 --- a/library/compiler-builtins/libm/src/math/copysignf16.rs +++ /dev/null @@ -1,8 +0,0 @@ -/// Sign of Y, magnitude of X (f16) -/// -/// Constructs a number with the magnitude (absolute value) of its -/// first argument, `x`, and the sign of its second argument, `y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn copysignf16(x: f16, y: f16) -> f16 { - super::generic::copysign(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fabsf.rs b/library/compiler-builtins/libm/src/math/fabsf.rs deleted file mode 100644 index e5820a26c5238..0000000000000 --- a/library/compiler-builtins/libm/src/math/fabsf.rs +++ /dev/null @@ -1,39 +0,0 @@ -/// Absolute value (magnitude) (f32) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabsf(x: f32) -> f32 { - select_implementation! { - name: fabsf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - super::generic::fabs(x) -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(fabsf(-1.0), 1.0); - assert_eq!(fabsf(2.8), 2.8); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs - #[test] - fn spec_tests() { - assert!(fabsf(f32::NAN).is_nan()); - for f in [0.0, -0.0].iter().copied() { - assert_eq!(fabsf(f), 0.0); - } - for f in [f32::INFINITY, f32::NEG_INFINITY].iter().copied() { - assert_eq!(fabsf(f), f32::INFINITY); - } - } -} diff --git a/library/compiler-builtins/libm/src/math/fabsf128.rs b/library/compiler-builtins/libm/src/math/fabsf128.rs deleted file mode 100644 index 46429ca494033..0000000000000 --- a/library/compiler-builtins/libm/src/math/fabsf128.rs +++ /dev/null @@ -1,31 +0,0 @@ -/// Absolute value (magnitude) (f128) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabsf128(x: f128) -> f128 { - super::generic::fabs(x) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(fabsf128(-1.0), 1.0); - assert_eq!(fabsf128(2.8), 2.8); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs - #[test] - fn spec_tests() { - assert!(fabsf128(f128::NAN).is_nan()); - for f in [0.0, -0.0].iter().copied() { - assert_eq!(fabsf128(f), 0.0); - } - for f in [f128::INFINITY, f128::NEG_INFINITY].iter().copied() { - assert_eq!(fabsf128(f), f128::INFINITY); - } - } -} diff --git a/library/compiler-builtins/libm/src/math/fabsf16.rs b/library/compiler-builtins/libm/src/math/fabsf16.rs deleted file mode 100644 index eee42ac6a3c60..0000000000000 --- a/library/compiler-builtins/libm/src/math/fabsf16.rs +++ /dev/null @@ -1,31 +0,0 @@ -/// Absolute value (magnitude) (f16) -/// -/// Calculates the absolute value (magnitude) of the argument `x`, -/// by direct manipulation of the bit representation of `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fabsf16(x: f16) -> f16 { - super::generic::fabs(x) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn sanity_check() { - assert_eq!(fabsf16(-1.0), 1.0); - assert_eq!(fabsf16(2.8), 2.8); - } - - /// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs - #[test] - fn spec_tests() { - assert!(fabsf16(f16::NAN).is_nan()); - for f in [0.0, -0.0].iter().copied() { - assert_eq!(fabsf16(f), 0.0); - } - for f in [f16::INFINITY, f16::NEG_INFINITY].iter().copied() { - assert_eq!(fabsf16(f), f16::INFINITY); - } - } -} diff --git a/library/compiler-builtins/libm/src/math/fdimf.rs b/library/compiler-builtins/libm/src/math/fdimf.rs deleted file mode 100644 index 367ef517c63be..0000000000000 --- a/library/compiler-builtins/libm/src/math/fdimf.rs +++ /dev/null @@ -1,12 +0,0 @@ -/// Positive difference (f32) -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdimf(x: f32, y: f32) -> f32 { - super::generic::fdim(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fdimf128.rs b/library/compiler-builtins/libm/src/math/fdimf128.rs deleted file mode 100644 index 6f3d1d0ff1d54..0000000000000 --- a/library/compiler-builtins/libm/src/math/fdimf128.rs +++ /dev/null @@ -1,12 +0,0 @@ -/// Positive difference (f128) -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdimf128(x: f128, y: f128) -> f128 { - super::generic::fdim(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fdimf16.rs b/library/compiler-builtins/libm/src/math/fdimf16.rs deleted file mode 100644 index 37bd688581797..0000000000000 --- a/library/compiler-builtins/libm/src/math/fdimf16.rs +++ /dev/null @@ -1,12 +0,0 @@ -/// Positive difference (f16) -/// -/// Determines the positive difference between arguments, returning: -/// * x - y if x > y, or -/// * +0 if x <= y, or -/// * NAN if either argument is NAN. -/// -/// A range error may occur. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fdimf16(x: f16, y: f16) -> f16 { - super::generic::fdim(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/floorf.rs b/library/compiler-builtins/libm/src/math/floorf.rs deleted file mode 100644 index 16957b7f35573..0000000000000 --- a/library/compiler-builtins/libm/src/math/floorf.rs +++ /dev/null @@ -1,13 +0,0 @@ -/// Floor (f32) -/// -/// Finds the nearest integer less than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floorf(x: f32) -> f32 { - select_implementation! { - name: floorf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - return super::generic::floor(x); -} diff --git a/library/compiler-builtins/libm/src/math/floorf128.rs b/library/compiler-builtins/libm/src/math/floorf128.rs deleted file mode 100644 index 9a9fe4151152b..0000000000000 --- a/library/compiler-builtins/libm/src/math/floorf128.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Floor (f128) -/// -/// Finds the nearest integer less than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floorf128(x: f128) -> f128 { - return super::generic::floor(x); -} diff --git a/library/compiler-builtins/libm/src/math/floorf16.rs b/library/compiler-builtins/libm/src/math/floorf16.rs deleted file mode 100644 index f9b868e04109d..0000000000000 --- a/library/compiler-builtins/libm/src/math/floorf16.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Floor (f16) -/// -/// Finds the nearest integer less than or equal to `x`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn floorf16(x: f16) -> f16 { - return super::generic::floor(x); -} diff --git a/library/compiler-builtins/libm/src/math/fmodf.rs b/library/compiler-builtins/libm/src/math/fmodf.rs deleted file mode 100644 index 4e95696e20d63..0000000000000 --- a/library/compiler-builtins/libm/src/math/fmodf.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmodf(x: f32, y: f32) -> f32 { - super::generic::fmod(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fmodf128.rs b/library/compiler-builtins/libm/src/math/fmodf128.rs deleted file mode 100644 index ff0e0493e26b6..0000000000000 --- a/library/compiler-builtins/libm/src/math/fmodf128.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmodf128(x: f128, y: f128) -> f128 { - super::generic::fmod(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/fmodf16.rs b/library/compiler-builtins/libm/src/math/fmodf16.rs deleted file mode 100644 index 11972a7de4ff0..0000000000000 --- a/library/compiler-builtins/libm/src/math/fmodf16.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn fmodf16(x: f16, y: f16) -> f16 { - super::generic::fmod(x, y) -} diff --git a/library/compiler-builtins/libm/src/math/ldexpf.rs b/library/compiler-builtins/libm/src/math/ldexpf.rs deleted file mode 100644 index 95b27fc49d28e..0000000000000 --- a/library/compiler-builtins/libm/src/math/ldexpf.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexpf(x: f32, n: i32) -> f32 { - super::scalbnf(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/ldexpf128.rs b/library/compiler-builtins/libm/src/math/ldexpf128.rs deleted file mode 100644 index b35277d15fbae..0000000000000 --- a/library/compiler-builtins/libm/src/math/ldexpf128.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexpf128(x: f128, n: i32) -> f128 { - super::scalbnf128(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/ldexpf16.rs b/library/compiler-builtins/libm/src/math/ldexpf16.rs deleted file mode 100644 index 8de6cffd69987..0000000000000 --- a/library/compiler-builtins/libm/src/math/ldexpf16.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn ldexpf16(x: f16, n: i32) -> f16 { - super::scalbnf16(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/roundf.rs b/library/compiler-builtins/libm/src/math/roundf.rs deleted file mode 100644 index b5d7c9d693e71..0000000000000 --- a/library/compiler-builtins/libm/src/math/roundf.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Round `x` to the nearest integer, breaking ties away from zero. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundf(x: f32) -> f32 { - super::generic::round(x) -} diff --git a/library/compiler-builtins/libm/src/math/roundf128.rs b/library/compiler-builtins/libm/src/math/roundf128.rs deleted file mode 100644 index fc3164929fe4f..0000000000000 --- a/library/compiler-builtins/libm/src/math/roundf128.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Round `x` to the nearest integer, breaking ties away from zero. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundf128(x: f128) -> f128 { - super::generic::round(x) -} diff --git a/library/compiler-builtins/libm/src/math/roundf16.rs b/library/compiler-builtins/libm/src/math/roundf16.rs deleted file mode 100644 index 8b356eaabeecd..0000000000000 --- a/library/compiler-builtins/libm/src/math/roundf16.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Round `x` to the nearest integer, breaking ties away from zero. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn roundf16(x: f16) -> f16 { - super::generic::round(x) -} diff --git a/library/compiler-builtins/libm/src/math/scalbnf.rs b/library/compiler-builtins/libm/src/math/scalbnf.rs deleted file mode 100644 index 57e7ba76f60b5..0000000000000 --- a/library/compiler-builtins/libm/src/math/scalbnf.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf(x: f32, n: i32) -> f32 { - super::generic::scalbn(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/scalbnf128.rs b/library/compiler-builtins/libm/src/math/scalbnf128.rs deleted file mode 100644 index c1d2b48558568..0000000000000 --- a/library/compiler-builtins/libm/src/math/scalbnf128.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf128(x: f128, n: i32) -> f128 { - super::generic::scalbn(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/scalbnf16.rs b/library/compiler-builtins/libm/src/math/scalbnf16.rs deleted file mode 100644 index 2209e1a179566..0000000000000 --- a/library/compiler-builtins/libm/src/math/scalbnf16.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn scalbnf16(x: f16, n: i32) -> f16 { - super::generic::scalbn(x, n) -} diff --git a/library/compiler-builtins/libm/src/math/sqrtf.rs b/library/compiler-builtins/libm/src/math/sqrtf.rs deleted file mode 100644 index c28a705e378e6..0000000000000 --- a/library/compiler-builtins/libm/src/math/sqrtf.rs +++ /dev/null @@ -1,15 +0,0 @@ -/// The square root of `x` (f32). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrtf(x: f32) -> f32 { - select_implementation! { - name: sqrtf, - use_arch: any( - all(target_arch = "aarch64", target_feature = "neon"), - all(target_arch = "wasm32", intrinsics_enabled), - target_feature = "sse2" - ), - args: x, - } - - super::generic::sqrt(x) -} diff --git a/library/compiler-builtins/libm/src/math/sqrtf128.rs b/library/compiler-builtins/libm/src/math/sqrtf128.rs deleted file mode 100644 index eaef6ae0c1c85..0000000000000 --- a/library/compiler-builtins/libm/src/math/sqrtf128.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// The square root of `x` (f128). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrtf128(x: f128) -> f128 { - return super::generic::sqrt(x); -} diff --git a/library/compiler-builtins/libm/src/math/sqrtf16.rs b/library/compiler-builtins/libm/src/math/sqrtf16.rs deleted file mode 100644 index 7bedb7f8bbb6b..0000000000000 --- a/library/compiler-builtins/libm/src/math/sqrtf16.rs +++ /dev/null @@ -1,11 +0,0 @@ -/// The square root of `x` (f16). -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn sqrtf16(x: f16) -> f16 { - select_implementation! { - name: sqrtf16, - use_arch: all(target_arch = "aarch64", target_feature = "fp16"), - args: x, - } - - return super::generic::sqrt(x); -} diff --git a/library/compiler-builtins/libm/src/math/truncf.rs b/library/compiler-builtins/libm/src/math/truncf.rs deleted file mode 100644 index 14533a2670632..0000000000000 --- a/library/compiler-builtins/libm/src/math/truncf.rs +++ /dev/null @@ -1,23 +0,0 @@ -/// Rounds the number toward 0 to the closest integral value (f32). -/// -/// This effectively removes the decimal part of the number, leaving the integral part. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn truncf(x: f32) -> f32 { - select_implementation! { - name: truncf, - use_arch: all(target_arch = "wasm32", intrinsics_enabled), - args: x, - } - - super::generic::trunc(x) -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - #[test] - fn sanity_check() { - assert_eq!(super::truncf(1.1), 1.0); - } -} diff --git a/library/compiler-builtins/libm/src/math/truncf128.rs b/library/compiler-builtins/libm/src/math/truncf128.rs deleted file mode 100644 index 9dccc0d0e9d7f..0000000000000 --- a/library/compiler-builtins/libm/src/math/truncf128.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Rounds the number toward 0 to the closest integral value (f128). -/// -/// This effectively removes the decimal part of the number, leaving the integral part. -#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn truncf128(x: f128) -> f128 { - super::generic::trunc(x) -} diff --git a/library/compiler-builtins/libm/src/math/truncf16.rs b/library/compiler-builtins/libm/src/math/truncf16.rs deleted file mode 100644 index d7c3d225cf9b8..0000000000000 --- a/library/compiler-builtins/libm/src/math/truncf16.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// 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_attr(all(test, assert_no_panic), no_panic::no_panic)] -pub fn truncf16(x: f16) -> f16 { - super::generic::trunc(x) -} From 16b6ffe0dbced4eeb1828b3a5674786dedc56cfc Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 22 May 2025 11:06:42 +0000 Subject: [PATCH 2621/4206] Don't allow poly_select in new solver --- .../traits/fulfillment_errors.rs | 10 ++++---- .../rustc_trait_selection/src/solve/select.rs | 4 +-- .../src/traits/select/mod.rs | 8 +++--- .../hr-projection-mismatch.current.stderr | 12 +++++++++ .../hr-projection-mismatch.next.stderr | 20 +++++++++++++++ .../hr-projection-mismatch.rs | 25 +++++++++++++++++++ 6 files changed, 69 insertions(+), 10 deletions(-) create mode 100644 tests/ui/mismatched_types/hr-projection-mismatch.current.stderr create mode 100644 tests/ui/mismatched_types/hr-projection-mismatch.next.stderr create mode 100644 tests/ui/mismatched_types/hr-projection-mismatch.rs 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 970160ba212af..bfff60e49c714 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 @@ -1503,11 +1503,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return None; }; - let Ok(Some(ImplSource::UserDefined(impl_data))) = SelectionContext::new(self) - .poly_select(&obligation.with( - self.tcx, - predicate.kind().rebind(proj.projection_term.trait_ref(self.tcx)), - )) + let trait_ref = self.enter_forall_and_leak_universe( + predicate.kind().rebind(proj.projection_term.trait_ref(self.tcx)), + ); + let Ok(Some(ImplSource::UserDefined(impl_data))) = + SelectionContext::new(self).select(&obligation.with(self.tcx, trait_ref)) else { return None; }; diff --git a/compiler/rustc_trait_selection/src/solve/select.rs b/compiler/rustc_trait_selection/src/solve/select.rs index 4fdaf740287ba..1f3168fafb1da 100644 --- a/compiler/rustc_trait_selection/src/solve/select.rs +++ b/compiler/rustc_trait_selection/src/solve/select.rs @@ -5,7 +5,7 @@ use rustc_infer::traits::solve::inspect::ProbeKind; use rustc_infer::traits::solve::{CandidateSource, Certainty, Goal}; use rustc_infer::traits::{ BuiltinImplSource, ImplSource, ImplSourceUserDefinedData, Obligation, ObligationCause, - PolyTraitObligation, Selection, SelectionError, SelectionResult, + Selection, SelectionError, SelectionResult, TraitObligation, }; use rustc_macros::extension; use rustc_middle::{bug, span_bug}; @@ -17,7 +17,7 @@ use crate::solve::inspect::{self, ProofTreeInferCtxtExt}; impl<'tcx> InferCtxt<'tcx> { fn select_in_new_trait_solver( &self, - obligation: &PolyTraitObligation<'tcx>, + obligation: &TraitObligation<'tcx>, ) -> SelectionResult<'tcx, Selection<'tcx>> { assert!(self.next_trait_solver()); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 44a76f6e08327..f4ec528c6726e 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -265,9 +265,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &PolyTraitObligation<'tcx>, ) -> SelectionResult<'tcx, Selection<'tcx>> { - if self.infcx.next_trait_solver() { - return self.infcx.select_in_new_trait_solver(obligation); - } + assert!(!self.infcx.next_trait_solver()); let candidate = match self.select_from_obligation(obligation) { Err(SelectionError::Overflow(OverflowError::Canonical)) => { @@ -299,6 +297,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &TraitObligation<'tcx>, ) -> SelectionResult<'tcx, Selection<'tcx>> { + if self.infcx.next_trait_solver() { + return self.infcx.select_in_new_trait_solver(obligation); + } + self.poly_select(&Obligation { cause: obligation.cause.clone(), param_env: obligation.param_env, diff --git a/tests/ui/mismatched_types/hr-projection-mismatch.current.stderr b/tests/ui/mismatched_types/hr-projection-mismatch.current.stderr new file mode 100644 index 0000000000000..a2cec972e4a99 --- /dev/null +++ b/tests/ui/mismatched_types/hr-projection-mismatch.current.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/hr-projection-mismatch.rs:20:5 + | +LL | wrap::<_, Thing>(); + | ^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected reference `&'a _` + found reference `&_` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/mismatched_types/hr-projection-mismatch.next.stderr b/tests/ui/mismatched_types/hr-projection-mismatch.next.stderr new file mode 100644 index 0000000000000..6ea0d43e1530c --- /dev/null +++ b/tests/ui/mismatched_types/hr-projection-mismatch.next.stderr @@ -0,0 +1,20 @@ +error[E0271]: type mismatch resolving `>::Assoc == &i32` + --> $DIR/hr-projection-mismatch.rs:20:15 + | +LL | wrap::<_, Thing>(); + | ^^^^^ type mismatch resolving `>::Assoc == &i32` + | +note: types differ + --> $DIR/hr-projection-mismatch.rs:14:18 + | +LL | type Assoc = &'a i32; + | ^^^^^^^ +note: required by a bound in `wrap` + --> $DIR/hr-projection-mismatch.rs:17:33 + | +LL | fn wrap Trait<'a, Assoc = T>>() {} + | ^^^^^^^^^ required by this bound in `wrap` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/mismatched_types/hr-projection-mismatch.rs b/tests/ui/mismatched_types/hr-projection-mismatch.rs new file mode 100644 index 0000000000000..f96314a3fca07 --- /dev/null +++ b/tests/ui/mismatched_types/hr-projection-mismatch.rs @@ -0,0 +1,25 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +// Regression test for . + +trait Trait<'a> { + type Assoc; +} + +struct Thing; + +impl<'a> Trait<'a> for Thing { + type Assoc = &'a i32; +} + +fn wrap Trait<'a, Assoc = T>>() {} + +fn foo() { + wrap::<_, Thing>(); + //[next]~^ ERROR type mismatch resolving `>::Assoc == &i32 + //[current]~^^ ERROR mismatched types +} + +fn main() {} From 09ae053f7a6d29909a309953182b6f067717cc83 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 22 May 2025 08:24:40 +0200 Subject: [PATCH 2622/4206] try_cast_aligned: avoid bare int-to-ptr casts --- library/core/src/ptr/const_ptr.rs | 12 +++++------- library/core/src/ptr/mut_ptr.rs | 12 +++++------- library/core/src/ptr/non_null.rs | 12 +++++------- 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index f6109cafe86b1..19ed7599a5101 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -76,15 +76,13 @@ impl *const T { /// ```rust /// #![feature(pointer_try_cast_aligned)] /// - /// let aligned: *const u8 = 0x1000 as _; + /// let x = 0u64; /// - /// // i32 has at most 4-byte alignment, so this will succeed - /// assert!(aligned.try_cast_aligned::().is_some()); + /// let aligned: *const u64 = &x; + /// let unaligned = unsafe { aligned.byte_add(1) }; /// - /// let unaligned: *const u8 = 0x1001 as _; - /// - /// // i32 has at least 2-byte alignment, so this will fail - /// assert!(unaligned.try_cast_aligned::().is_none()); + /// assert!(aligned.try_cast_aligned::().is_some()); + /// assert!(unaligned.try_cast_aligned::().is_none()); /// ``` #[unstable(feature = "pointer_try_cast_aligned", issue = "141221")] #[must_use = "this returns the result of the operation, \ diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 2662a4fdc3138..53aa3ab49388f 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -58,15 +58,13 @@ impl *mut T { /// ```rust /// #![feature(pointer_try_cast_aligned)] /// - /// let aligned: *mut u8 = 0x1000 as _; + /// let mut x = 0u64; /// - /// // i32 has at most 4-byte alignment, so this will succeed - /// assert!(aligned.try_cast_aligned::().is_some()); + /// let aligned: *mut u64 = &mut x; + /// let unaligned = unsafe { aligned.byte_add(1) }; /// - /// let unaligned: *mut u8 = 0x1001 as _; - /// - /// // i32 has at least 2-byte alignment, so this will fail - /// assert!(unaligned.try_cast_aligned::().is_none()); + /// assert!(aligned.try_cast_aligned::().is_some()); + /// assert!(unaligned.try_cast_aligned::().is_none()); /// ``` #[unstable(feature = "pointer_try_cast_aligned", issue = "141221")] #[must_use = "this returns the result of the operation, \ diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index bb344c6a0d316..7c9b898f8e99f 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -501,15 +501,13 @@ impl NonNull { /// #![feature(pointer_try_cast_aligned)] /// use std::ptr::NonNull; /// - /// let aligned: NonNull = NonNull::new(0x1000 as _).unwrap(); + /// let mut x = 0u64; /// - /// // i32 has at most 4-byte alignment, so this will succeed - /// assert!(aligned.try_cast_aligned::().is_some()); + /// let aligned = NonNull::from_mut(&mut x); + /// let unaligned = unsafe { aligned.byte_add(1) }; /// - /// let unaligned: NonNull = NonNull::new(0x1001 as _).unwrap(); - /// - /// // i32 has at least 2-byte alignment, so this will fail - /// assert!(unaligned.try_cast_aligned::().is_none()); + /// assert!(aligned.try_cast_aligned::().is_some()); + /// assert!(unaligned.try_cast_aligned::().is_none()); /// ``` #[unstable(feature = "pointer_try_cast_aligned", issue = "141221")] #[must_use = "this returns the result of the operation, \ From 217c4ad427a5dbf6b23f23c70358a31064884231 Mon Sep 17 00:00:00 2001 From: Boxy Date: Thu, 1 May 2025 16:22:31 +0100 Subject: [PATCH 2623/4206] Review Comments --- compiler/rustc_hir_analysis/src/collect.rs | 6 +- .../src/collect/generics_of.rs | 8 +- compiler/rustc_middle/src/query/mod.rs | 1 - compiler/rustc_middle/src/ty/consts.rs | 9 +- .../rustc_trait_selection/src/traits/mod.rs | 138 +++++++++--------- .../unconstrained_impl_param.rs | 2 + 6 files changed, 85 insertions(+), 79 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index dfe9d7af3adac..8b9fae732c1f5 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1836,9 +1836,9 @@ fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKin match tcx.hir_node(const_arg_id) { hir::Node::ConstArg(_) => { if tcx.features().generic_const_exprs() { - ty::AnonConstKind::GCEConst + ty::AnonConstKind::GCE } else if tcx.features().min_generic_const_args() { - ty::AnonConstKind::MCGConst + ty::AnonConstKind::MCG } else if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Repeat(_, repeat_count), .. @@ -1847,7 +1847,7 @@ fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKin { ty::AnonConstKind::RepeatExprCount } else { - ty::AnonConstKind::MCGConst + ty::AnonConstKind::MCG } } _ => ty::AnonConstKind::NonTypeSystem, diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index d261f3f85fe71..7eb896f0bf149 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -106,7 +106,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { match tcx.anon_const_kind(def_id) { // Stable: anon consts are not able to use any generic parameters... - ty::AnonConstKind::MCGConst => None, + ty::AnonConstKind::MCG => None, // we provide generics to repeat expr counts as a backwards compatibility hack. #76200 ty::AnonConstKind::RepeatExprCount => Some(parent_did), @@ -116,13 +116,13 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // We could potentially mirror the hack done for defaults of generic parameters but // this case just doesn't come up much compared to `const N: u32 = ...`. Long term the // hack for defaulted parameters should be removed eventually anyway. - ty::AnonConstKind::GCEConst if in_param_ty => None, + ty::AnonConstKind::GCE if in_param_ty => None, // GCE anon consts as a default for a generic parameter should have their provided generics // "truncated" up to whatever generic parameter this anon const is within the default of. // // FIXME(generic_const_exprs): This only handles `const N: usize = /*defid*/` but not type // parameter defaults, e.g. `T = Foo`. - ty::AnonConstKind::GCEConst + ty::AnonConstKind::GCE if let Some(param_id) = tcx.hir_opt_const_param_default_param_def_id(hir_id) => { @@ -169,7 +169,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { has_late_bound_regions: generics.has_late_bound_regions, }; } - ty::AnonConstKind::GCEConst => Some(parent_did), + ty::AnonConstKind::GCE => Some(parent_did), // Field defaults are allowed to use generic parameters, e.g. `field: u32 = /*defid: N + 1*/` ty::AnonConstKind::NonTypeSystem diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 2e8a2bceb38bb..6937b54eba289 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2589,7 +2589,6 @@ rustc_queries! { query anon_const_kind(def_id: DefId) -> ty::AnonConstKind { desc { |tcx| "looking up anon const kind of `{}`", tcx.def_path_str(def_id) } - cache_on_disk_if { def_id.is_local() } separate_provide_extern } } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index f1ea2152f3bd0..455ac66041261 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -262,8 +262,13 @@ impl<'tcx> Const<'tcx> { #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable, HashStable)] pub enum AnonConstKind { - GCEConst, - MCGConst, + /// `feature(generic_const_exprs)` anon consts are allowed to use arbitrary generic parameters in scope + GCE, + /// stable `min_const_generics` anon consts are not allowed to use any generic parameters + MCG, + /// anon consts used as the length of a repeat expr are syntactically allowed to use generic parameters + /// but must not depend on the actual instantiation. See #76200 for more information RepeatExprCount, + /// anon consts outside of the type system, e.g. enum discriminants NonTypeSystem, } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index c174de44558c8..d8e83dc72b022 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -542,6 +542,9 @@ pub fn try_evaluate_const<'tcx>( | ty::ConstKind::Placeholder(_) | ty::ConstKind::Expr(_) => Err(EvaluateConstErr::HasGenericsOrInfers), ty::ConstKind::Unevaluated(uv) => { + let opt_anon_const_kind = + (tcx.def_kind(uv.def) == DefKind::AnonConst).then(|| tcx.anon_const_kind(uv.def)); + // Postpone evaluation of constants that depend on generic parameters or // inference variables. // @@ -553,87 +556,84 @@ pub fn try_evaluate_const<'tcx>( // // FIXME: `const_eval_resolve_for_typeck` should probably just modify the env itself // instead of having this logic here - let (args, typing_env) = if tcx.def_kind(uv.def) == DefKind::AnonConst - && let ty::AnonConstKind::GCEConst = tcx.anon_const_kind(uv.def) - { + let (args, typing_env) = match opt_anon_const_kind { // We handle `generic_const_exprs` separately as reasonable ways of handling constants in the type system // completely fall apart under `generic_const_exprs` and makes this whole function Really hard to reason // about if you have to consider gce whatsoever. - - if uv.has_non_region_infer() || uv.has_non_region_param() { - // `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause - // inference variables and generic parameters to show up in `ty::Const` even though the anon const - // does not actually make use of them. We handle this case specially and attempt to evaluate anyway. - match tcx.thir_abstract_const(uv.def) { - Ok(Some(ct)) => { - let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, uv.args)); - if let Err(e) = ct.error_reported() { - return Err(EvaluateConstErr::EvaluationFailure(e)); - } else if ct.has_non_region_infer() || ct.has_non_region_param() { - // If the anon const *does* actually use generic parameters or inference variables from - // the generic arguments provided for it, then we should *not* attempt to evaluate it. - return Err(EvaluateConstErr::HasGenericsOrInfers); - } else { - let args = - replace_param_and_infer_args_with_placeholder(tcx, uv.args); - let typing_env = infcx - .typing_env(tcx.erase_regions(param_env)) - .with_post_analysis_normalized(tcx); + Some(ty::AnonConstKind::GCE) => { + if uv.has_non_region_infer() || uv.has_non_region_param() { + // `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause + // inference variables and generic parameters to show up in `ty::Const` even though the anon const + // does not actually make use of them. We handle this case specially and attempt to evaluate anyway. + match tcx.thir_abstract_const(uv.def) { + Ok(Some(ct)) => { + let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, uv.args)); + if let Err(e) = ct.error_reported() { + return Err(EvaluateConstErr::EvaluationFailure(e)); + } else if ct.has_non_region_infer() || ct.has_non_region_param() { + // If the anon const *does* actually use generic parameters or inference variables from + // the generic arguments provided for it, then we should *not* attempt to evaluate it. + return Err(EvaluateConstErr::HasGenericsOrInfers); + } else { + let args = + replace_param_and_infer_args_with_placeholder(tcx, uv.args); + let typing_env = infcx + .typing_env(tcx.erase_regions(param_env)) + .with_post_analysis_normalized(tcx); + (args, typing_env) + } + } + Err(_) | Ok(None) => { + let args = GenericArgs::identity_for_item(tcx, uv.def); + let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def); (args, typing_env) } } - Err(_) | Ok(None) => { - let args = GenericArgs::identity_for_item(tcx, uv.def); - let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def); - (args, typing_env) - } + } else { + let typing_env = infcx + .typing_env(tcx.erase_regions(param_env)) + .with_post_analysis_normalized(tcx); + (uv.args, typing_env) } - } else { - let typing_env = infcx - .typing_env(tcx.erase_regions(param_env)) - .with_post_analysis_normalized(tcx); - (uv.args, typing_env) - } - } else if tcx.def_kind(uv.def) == DefKind::AnonConst - && let ty::AnonConstKind::RepeatExprCount = tcx.anon_const_kind(uv.def) - { - if uv.has_non_region_infer() { - // Diagnostics will sometimes replace the identity args of anon consts in - // array repeat expr counts with inference variables so we have to handle this - // even though it is not something we should ever actually encounter. - // - // Array repeat expr counts are allowed to syntactically use generic parameters - // but must not actually depend on them in order to evalaute successfully. This means - // that it is actually fine to evalaute them in their own environment rather than with - // the actually provided generic arguments. - tcx.dcx().delayed_bug( - "Encountered anon const with inference variable args but no error reported", - ); } + Some(ty::AnonConstKind::RepeatExprCount) => { + if uv.has_non_region_infer() { + // Diagnostics will sometimes replace the identity args of anon consts in + // array repeat expr counts with inference variables so we have to handle this + // even though it is not something we should ever actually encounter. + // + // Array repeat expr counts are allowed to syntactically use generic parameters + // but must not actually depend on them in order to evalaute successfully. This means + // that it is actually fine to evalaute them in their own environment rather than with + // the actually provided generic arguments. + tcx.dcx().delayed_bug("AnonConst with infer args but no error reported"); + } - // The generic args of repeat expr counts under `min_const_generics` are not supposed to - // affect evaluation of the constant as this would make it a "truly" generic const arg. - // To prevent this we discard all the generic arguments and evalaute with identity args - // and in its own environment instead of the current environment we are normalizing in. - let args = GenericArgs::identity_for_item(tcx, uv.def); - let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def); + // The generic args of repeat expr counts under `min_const_generics` are not supposed to + // affect evaluation of the constant as this would make it a "truly" generic const arg. + // To prevent this we discard all the generic arguments and evalaute with identity args + // and in its own environment instead of the current environment we are normalizing in. + let args = GenericArgs::identity_for_item(tcx, uv.def); + let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def); - (args, typing_env) - } else { - // We are only dealing with "truly" generic/uninferred constants here: - // - GCEConsts have been handled separately - // - Repeat expr count back compat consts have also been handled separately - // So we are free to simply defer evaluation here. - // - // FIXME: This assumes that `args` are normalized which is not necessarily true - if uv.args.has_non_region_param() || uv.args.has_non_region_infer() { - return Err(EvaluateConstErr::HasGenericsOrInfers); + (args, typing_env) } + _ => { + // We are only dealing with "truly" generic/uninferred constants here: + // - GCEConsts have been handled separately + // - Repeat expr count back compat consts have also been handled separately + // So we are free to simply defer evaluation here. + // + // FIXME: This assumes that `args` are normalized which is not necessarily true + if uv.args.has_non_region_param() || uv.args.has_non_region_infer() { + return Err(EvaluateConstErr::HasGenericsOrInfers); + } - let typing_env = infcx - .typing_env(tcx.erase_regions(param_env)) - .with_post_analysis_normalized(tcx); - (uv.args, typing_env) + let typing_env = infcx + .typing_env(tcx.erase_regions(param_env)) + .with_post_analysis_normalized(tcx); + (uv.args, typing_env) + } }; let uv = ty::UnevaluatedConst::new(uv.def, args); diff --git a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs index 19cddb71b018f..99318ef75984e 100644 --- a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs +++ b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs @@ -22,3 +22,5 @@ where //~^ ERROR type mismatch resolving { } + +fn main() {} From fdccb42167028b33a7ceee7343cfe3500c1c4b8b Mon Sep 17 00:00:00 2001 From: Boxy Date: Thu, 22 May 2025 12:52:46 +0100 Subject: [PATCH 2624/4206] Add test/comment about const patterns with unused params --- .../rustc_trait_selection/src/traits/mod.rs | 6 ++++++ .../unused-parameters-const-pattern.rs | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 tests/ui/pattern/unused-parameters-const-pattern.rs diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index d8e83dc72b022..588ffc16e5100 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -625,6 +625,12 @@ pub fn try_evaluate_const<'tcx>( // So we are free to simply defer evaluation here. // // FIXME: This assumes that `args` are normalized which is not necessarily true + // + // Const patterns are converted to type system constants before being + // evaluated. However, we don't care about them here as pattern evaluation + // logic does not go through type system normalization. If it did this would + // be a backwards compatibility problem as we do not enforce "syntactic" non- + // usage of generic parameters like we do here. if uv.args.has_non_region_param() || uv.args.has_non_region_infer() { return Err(EvaluateConstErr::HasGenericsOrInfers); } diff --git a/tests/ui/pattern/unused-parameters-const-pattern.rs b/tests/ui/pattern/unused-parameters-const-pattern.rs new file mode 100644 index 0000000000000..107c65ddfd3ae --- /dev/null +++ b/tests/ui/pattern/unused-parameters-const-pattern.rs @@ -0,0 +1,19 @@ +//@ check-pass + +// Tests that const patterns that use generic parameters are +// allowed if we are still able to evaluate them. + +trait Trait { const ASSOC: usize; } + +impl Trait for T { + const ASSOC: usize = 10; +} + +fn foo(a: usize) { + match a { + ::ASSOC => (), + _ => (), + } +} + +fn main() {} From d6dc08c3f4c32744c7163561da1a16825d1eed2d Mon Sep 17 00:00:00 2001 From: Dannyyy93 Date: Thu, 22 May 2025 22:47:36 +0800 Subject: [PATCH 2625/4206] docs: fix typos --- library/std/src/sync/mpmc/list.rs | 2 +- library/std/src/sys/thread_local/guard/key.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/sync/mpmc/list.rs b/library/std/src/sync/mpmc/list.rs index 3fcfb85cf2aab..050f26b097a0e 100644 --- a/library/std/src/sync/mpmc/list.rs +++ b/library/std/src/sync/mpmc/list.rs @@ -575,7 +575,7 @@ impl Channel { // After this point `head.block` is not modified again and it will be deallocated if it's // non-null. The `Drop` code of the channel, which runs after this function, also attempts // to deallocate `head.block` if it's non-null. Therefore this function must maintain the - // invariant that if a deallocation of head.block is attemped then it must also be set to + // invariant that if a deallocation of head.block is attempted then it must also be set to // NULL. Failing to do so will lead to the Drop code attempting a double free. For this // reason both reads above do an atomic swap instead of a simple atomic load. diff --git a/library/std/src/sys/thread_local/guard/key.rs b/library/std/src/sys/thread_local/guard/key.rs index 59581e6f281e6..f91471419c1cc 100644 --- a/library/std/src/sys/thread_local/guard/key.rs +++ b/library/std/src/sys/thread_local/guard/key.rs @@ -32,7 +32,7 @@ pub fn enable() { /// On platforms with key-based TLS, the system runs the destructors for us. /// We still have to make sure that [`crate::rt::thread_cleanup`] is called, -/// however. This is done by defering the execution of a TLS destructor to +/// however. This is done by deferring the execution of a TLS destructor to /// the next round of destruction inside the TLS destructors. #[cfg(not(target_thread_local))] pub fn enable() { @@ -46,7 +46,7 @@ pub fn enable() { unsafe extern "C" fn run(state: *mut u8) { if state == DEFER { // Make sure that this function is run again in the next round of - // TLS destruction. If there is no futher round, there will be leaks, + // TLS destruction. If there is no further round, there will be leaks, // but that's okay, `thread_cleanup` is not guaranteed to be called. unsafe { set(CLEANUP.force(), RUN) } } else { From eec894d3f9bf708d8c4c0679bc57ed899d6c37ab Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 1 May 2025 21:56:30 +0200 Subject: [PATCH 2626/4206] Fix future-incompatible lint group test --- tests/ui/future-incompatible-lint-group.rs | 10 ++--- .../ui/future-incompatible-lint-group.stderr | 40 ++++++++++++++----- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/tests/ui/future-incompatible-lint-group.rs b/tests/ui/future-incompatible-lint-group.rs index c84538318f70f..ed2c47bb60907 100644 --- a/tests/ui/future-incompatible-lint-group.rs +++ b/tests/ui/future-incompatible-lint-group.rs @@ -2,16 +2,14 @@ // lints for changes that are not tied to an edition #![deny(future_incompatible)] +// Error since this is a `future_incompatible` lint +macro_rules! m { ($i) => {} } //~ ERROR missing fragment specifier + //~| WARN this was previously accepted + trait Tr { // Warn only since this is not a `future_incompatible` lint fn f(u8) {} //~ WARN anonymous parameters are deprecated //~| WARN this is accepted in the current edition } -pub mod submodule { - // Error since this is a `future_incompatible` lint - #![doc(test(some_test))] - //~^ ERROR this attribute can only be applied at the crate level -} - fn main() {} diff --git a/tests/ui/future-incompatible-lint-group.stderr b/tests/ui/future-incompatible-lint-group.stderr index 4e6c434fa29b2..4c867e0aab3cb 100644 --- a/tests/ui/future-incompatible-lint-group.stderr +++ b/tests/ui/future-incompatible-lint-group.stderr @@ -1,5 +1,20 @@ +error: missing fragment specifier + --> $DIR/future-incompatible-lint-group.rs:6:19 + | +LL | macro_rules! m { ($i) => {} } + | ^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 +note: the lint level is defined here + --> $DIR/future-incompatible-lint-group.rs:3:9 + | +LL | #![deny(future_incompatible)] + | ^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(missing_fragment_specifier)]` implied by `#[deny(future_incompatible)]` + warning: anonymous parameters are deprecated and will be removed in the next edition - --> $DIR/future-incompatible-lint-group.rs:7:10 + --> $DIR/future-incompatible-lint-group.rs:11:10 | LL | fn f(u8) {} | ^^ help: try naming the parameter or explicitly ignoring it: `_: u8` @@ -8,14 +23,21 @@ LL | fn f(u8) {} = note: for more information, see issue #41686 = note: `#[warn(anonymous_parameters)]` on by default -error: this attribute can only be applied at the crate level - --> $DIR/future-incompatible-lint-group.rs:13:12 +error: aborting due to 1 previous error; 1 warning emitted + +Future incompatibility report: Future breakage diagnostic: +error: missing fragment specifier + --> $DIR/future-incompatible-lint-group.rs:6:19 | -LL | #![doc(test(some_test))] - | ^^^^^^^^^^^^^^^ +LL | macro_rules! m { ($i) => {} } + | ^^ | - = note: read for more information - = note: `#[deny(invalid_doc_attributes)]` on by default - -error: aborting due to 1 previous error; 1 warning emitted + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 +note: the lint level is defined here + --> $DIR/future-incompatible-lint-group.rs:3:9 + | +LL | #![deny(future_incompatible)] + | ^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(missing_fragment_specifier)]` implied by `#[deny(future_incompatible)]` From 80c6a0885079038caa0bc90670afbf5ead806c17 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 1 May 2025 17:24:00 +0200 Subject: [PATCH 2627/4206] Allow `#![doc(test(attr(..)))]` at module level too --- compiler/rustc_passes/messages.ftl | 5 ++ compiler/rustc_passes/src/check_attr.rs | 51 ++++++++++++++++--- compiler/rustc_passes/src/errors.rs | 12 ++++- .../write-documentation/the-doc-attribute.md | 19 +++++++ tests/rustdoc-ui/lints/invalid-doc-attr.rs | 4 ++ .../rustdoc-ui/lints/invalid-doc-attr.stderr | 32 ++++++++---- tests/ui/rustdoc/doc-test-attr-pass.rs | 4 ++ 7 files changed, 107 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 6d815e510ea20..2f264ed4fc023 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -46,6 +46,11 @@ passes_attr_crate_level = .suggestion = to apply to the crate, use an inner attribute .note = read for more information +passes_attr_mod_level = + this attribute can only be applied at module level + .suggestion = to apply to the crate, use an inner attribute at the crate level + .note = read for more information + passes_attr_only_in_functions = `{$attr}` attribute can only be used on functions diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 5c0d0cf47969a..376b424a1af5d 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1252,7 +1252,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let bang_span = attr.span().lo() + BytePos(1); let sugg = (attr.style() == AttrStyle::Outer && self.tcx.hir_get_parent_item(hir_id) == CRATE_OWNER_ID) - .then_some(errors::AttrCrateLevelOnlySugg { + .then_some(errors::AttrCrateLevelSugg { attr: attr.span().with_lo(bang_span).with_hi(bang_span), }); self.tcx.emit_node_span_lint( @@ -1266,13 +1266,50 @@ impl<'tcx> CheckAttrVisitor<'tcx> { true } - /// Checks that `doc(test(...))` attribute contains only valid attributes. Returns `true` if - /// valid. - fn check_test_attr(&self, meta: &MetaItemInner, hir_id: HirId) { + /// Checks that an attribute is used at module level. Returns `true` if valid. + fn check_attr_mod_level( + &self, + attr: &Attribute, + meta: &MetaItemInner, + hir_id: HirId, + target: Target, + ) -> bool { + if target != Target::Mod { + // insert a bang between `#` and `[...` + let bang_span = attr.span().lo() + BytePos(1); + let sugg = (attr.style() == AttrStyle::Outer + && self.tcx.hir_get_parent_item(hir_id) == CRATE_OWNER_ID) + .then_some(errors::AttrCrateLevelSugg { + attr: attr.span().with_lo(bang_span).with_hi(bang_span), + }); + self.tcx.emit_node_span_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + meta.span(), + errors::AttrModLevelOnly { sugg }, + ); + return false; + } + true + } + + /// Checks that `doc(test(...))` attribute contains only valid attributes and are at the right place. + fn check_test_attr( + &self, + attr: &Attribute, + meta: &MetaItemInner, + hir_id: HirId, + target: Target, + ) { if let Some(metas) = meta.meta_item_list() { for i_meta in metas { match (i_meta.name(), i_meta.meta_item()) { - (Some(sym::attr | sym::no_crate_inject), _) => {} + (Some(sym::attr), _) => { + self.check_attr_mod_level(attr, meta, hir_id, target); + } + (Some(sym::no_crate_inject), _) => { + self.check_attr_crate_level(attr, meta, hir_id); + } (_, Some(m)) => { self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, @@ -1359,9 +1396,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } Some(sym::test) => { - if self.check_attr_crate_level(attr, meta, hir_id) { - self.check_test_attr(meta, hir_id); - } + self.check_test_attr(attr, meta, hir_id, target); } Some( diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 00682a9c7a794..38b0db37e12b4 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1890,12 +1890,20 @@ pub(crate) struct UnusedVarTryIgnoreSugg { #[note] pub(crate) struct AttrCrateLevelOnly { #[subdiagnostic] - pub sugg: Option, + pub sugg: Option, +} + +#[derive(LintDiagnostic)] +#[diag(passes_attr_mod_level)] +#[note] +pub(crate) struct AttrModLevelOnly { + #[subdiagnostic] + pub sugg: Option, } #[derive(Subdiagnostic)] #[suggestion(passes_suggestion, applicability = "maybe-incorrect", code = "!", style = "verbose")] -pub(crate) struct AttrCrateLevelOnlySugg { +pub(crate) struct AttrCrateLevelSugg { #[primary_span] pub attr: Span, } diff --git a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md index 45146993371f9..afbcf4000c538 100644 --- a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md +++ b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md @@ -141,6 +141,11 @@ But if you include this: it will not. +## At the module level + +These forms of the `#[doc]` attribute are used on individual modules, to control how +they are documented. + ### `test(attr(...))` This form of the `doc` attribute allows you to add arbitrary attributes to all your doctests. For @@ -148,6 +153,20 @@ example, if you want your doctests to fail if they have dead code, you could add ```rust,no_run #![doc(test(attr(deny(dead_code))))] + +mod my_mod { + #![doc(test(attr(allow(dead_code))))] // but allow `dead_code` for this module +} +``` + +`test(attr(..))` attributes are appended to the parent module's, they do not replace the current +list of attributes. In the previous example, both attributes would be present: + +```rust,no_run +// For every doctest in `my_mod` + +#![deny(dead_code)] // from the crate-root +#![allow(dead_code)] // from `my_mod` ``` ## At the item level diff --git a/tests/rustdoc-ui/lints/invalid-doc-attr.rs b/tests/rustdoc-ui/lints/invalid-doc-attr.rs index e1cc08ca24272..cd5ae44b1266d 100644 --- a/tests/rustdoc-ui/lints/invalid-doc-attr.rs +++ b/tests/rustdoc-ui/lints/invalid-doc-attr.rs @@ -4,6 +4,10 @@ #![doc(masked)] //~^ ERROR this attribute can only be applied to an `extern crate` item +#[doc(test(attr(allow(warnings))))] +//~^ ERROR can only be applied at module level +//~| HELP to apply to the crate, use an inner attribute +//~| SUGGESTION ! #[doc(test(no_crate_inject))] //~^ ERROR can only be applied at the crate level //~| HELP to apply to the crate, use an inner attribute diff --git a/tests/rustdoc-ui/lints/invalid-doc-attr.stderr b/tests/rustdoc-ui/lints/invalid-doc-attr.stderr index 7621999a8ca52..0fd55ff94d872 100644 --- a/tests/rustdoc-ui/lints/invalid-doc-attr.stderr +++ b/tests/rustdoc-ui/lints/invalid-doc-attr.stderr @@ -1,18 +1,30 @@ -error: this attribute can only be applied at the crate level +error: this attribute can only be applied at module level --> $DIR/invalid-doc-attr.rs:7:7 | +LL | #[doc(test(attr(allow(warnings))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: read for more information + = note: `#[deny(invalid_doc_attributes)]` on by default +help: to apply to the crate, use an inner attribute at the crate level + | +LL | #![doc(test(attr(allow(warnings))))] + | + + +error: this attribute can only be applied at the crate level + --> $DIR/invalid-doc-attr.rs:11:7 + | LL | #[doc(test(no_crate_inject))] | ^^^^^^^^^^^^^^^^^^^^^ | = note: read for more information - = note: `#[deny(invalid_doc_attributes)]` on by default help: to apply to the crate, use an inner attribute | LL | #![doc(test(no_crate_inject))] | + error: this attribute can only be applied to a `use` item - --> $DIR/invalid-doc-attr.rs:11:7 + --> $DIR/invalid-doc-attr.rs:15:7 | LL | #[doc(inline)] | ^^^^^^ only applicable on `use` items @@ -23,7 +35,7 @@ LL | pub fn foo() {} = note: read for more information error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:16:12 + --> $DIR/invalid-doc-attr.rs:20:12 | LL | #![doc(test(no_crate_inject))] | ^^^^^^^^^^^^^^^^^^^^^ @@ -31,7 +43,7 @@ LL | #![doc(test(no_crate_inject))] = note: read for more information error: conflicting doc inlining attributes - --> $DIR/invalid-doc-attr.rs:26:7 + --> $DIR/invalid-doc-attr.rs:30:7 | LL | #[doc(inline)] | ^^^^^^ this attribute... @@ -41,7 +53,7 @@ LL | #[doc(no_inline)] = help: remove one of the conflicting attributes error: this attribute can only be applied to an `extern crate` item - --> $DIR/invalid-doc-attr.rs:32:7 + --> $DIR/invalid-doc-attr.rs:36:7 | LL | #[doc(masked)] | ^^^^^^ only applicable on `extern crate` items @@ -52,7 +64,7 @@ LL | pub struct Masked; = note: read for more information error: this attribute cannot be applied to an `extern crate self` item - --> $DIR/invalid-doc-attr.rs:36:7 + --> $DIR/invalid-doc-attr.rs:40:7 | LL | #[doc(masked)] | ^^^^^^ not applicable on `extern crate self` items @@ -69,7 +81,7 @@ LL | #![doc(masked)] = note: read for more information error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:19:11 + --> $DIR/invalid-doc-attr.rs:23:11 | LL | #[doc(test(no_crate_inject))] | ^^^^^^^^^^^^^^^^^^^^^ @@ -77,7 +89,7 @@ LL | #[doc(test(no_crate_inject))] = note: read for more information error: this attribute can only be applied to a `use` item - --> $DIR/invalid-doc-attr.rs:21:11 + --> $DIR/invalid-doc-attr.rs:25:11 | LL | #[doc(inline)] | ^^^^^^ only applicable on `use` items @@ -87,5 +99,5 @@ LL | pub fn baz() {} | = note: read for more information -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors diff --git a/tests/ui/rustdoc/doc-test-attr-pass.rs b/tests/ui/rustdoc/doc-test-attr-pass.rs index f0120b7c2d0b4..40ffd5b25723a 100644 --- a/tests/ui/rustdoc/doc-test-attr-pass.rs +++ b/tests/ui/rustdoc/doc-test-attr-pass.rs @@ -6,4 +6,8 @@ #![doc(test(attr(deny(warnings))))] #![doc(test())] +mod test { + #![doc(test(attr(allow(warnings))))] +} + pub fn foo() {} From 3005a09fedd5c874c36ca1c788954e51e3fa0617 Mon Sep 17 00:00:00 2001 From: binarycat Date: Sat, 1 Feb 2025 13:35:06 -0600 Subject: [PATCH 2628/4206] rustdoc: improve diagnostics on raw doc fragments 1. rustdoc::bare_urls doesn't output invalid suggestions if source_span_for_markdown_range fails to find a span 2. source_span_for_markdown_range tries harder to return a span by applying an additional diagnostic fixes https://github.com/rust-lang/rust/issues/135851 --- compiler/rustc_resolve/src/rustdoc.rs | 51 +++++++++++++++++-- src/librustdoc/passes/lint/bare_urls.rs | 12 +++-- tests/rustdoc-ui/intra-doc/warning.stderr | 36 +++---------- tests/rustdoc-ui/lints/bare-urls-limit.rs | 12 +++++ tests/rustdoc-ui/lints/bare-urls-limit.stderr | 18 +++++++ tests/rustdoc-ui/lints/bare-urls.fixed | 10 ++++ tests/rustdoc-ui/lints/bare-urls.rs | 10 ++++ tests/rustdoc-ui/lints/bare-urls.stderr | 38 +++++++++++++- tests/rustdoc-ui/unescaped_backticks.stderr | 8 +-- 9 files changed, 154 insertions(+), 41 deletions(-) create mode 100644 tests/rustdoc-ui/lints/bare-urls-limit.rs create mode 100644 tests/rustdoc-ui/lints/bare-urls-limit.stderr diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index a32fe6990160c..24ebb4ddfbc2d 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -514,20 +514,30 @@ pub fn span_of_fragments(fragments: &[DocFragment]) -> Option { /// This method does not always work, because markdown bytes don't necessarily match source bytes, /// like if escapes are used in the string. In this case, it returns `None`. /// -/// This method will return `Some` only if: +/// `markdown` is typically the entire documentation for an item, +/// after combining fragments. +/// +/// This method will return `Some` only if one of the following is true: /// /// - The doc is made entirely from sugared doc comments, which cannot contain escapes -/// - The doc is entirely from a single doc fragment, with a string literal, exactly equal +/// - The doc is entirely from a single doc fragment with a string literal exactly equal to `markdown`. /// - The doc comes from `include_str!` +/// - The doc includes exactly one substring matching `markdown[md_range]` which is contained in a single doc fragment. +/// +/// This function is defined in the compiler so it can be used by +/// both `rustdoc` and `clippy`. pub fn source_span_for_markdown_range( tcx: TyCtxt<'_>, markdown: &str, md_range: &Range, fragments: &[DocFragment], ) -> Option { + use rustc_span::BytePos; + + let map = tcx.sess.source_map(); if let &[fragment] = &fragments && fragment.kind == DocFragmentKind::RawDoc - && let Ok(snippet) = tcx.sess.source_map().span_to_snippet(fragment.span) + && let Ok(snippet) = map.span_to_snippet(fragment.span) && snippet.trim_end() == markdown.trim_end() && let Ok(md_range_lo) = u32::try_from(md_range.start) && let Ok(md_range_hi) = u32::try_from(md_range.end) @@ -544,10 +554,43 @@ pub fn source_span_for_markdown_range( let is_all_sugared_doc = fragments.iter().all(|frag| frag.kind == DocFragmentKind::SugaredDoc); if !is_all_sugared_doc { + // This case ignores the markdown outside of the range so that it can + // work in cases where the markdown is made from several different + // doc fragments, but the target range does not span across multiple + // fragments. + let mut match_data = None; + let pat = &markdown[md_range.clone()]; + // This heirustic doesn't make sense with a zero-sized range. + if pat.is_empty() { + return None; + } + for (i, fragment) in fragments.iter().enumerate() { + if let Ok(snippet) = map.span_to_snippet(fragment.span) + && let Some(match_start) = snippet.find(pat) + { + // If there is either a match in a previous fragment, or + // multiple matches in this fragment, there is ambiguity. + if match_data.is_none() && !snippet[match_start + 1..].contains(pat) { + match_data = Some((i, match_start)); + } else { + // Heirustic produced ambiguity, return nothing. + return None; + } + } + } + if let Some((i, match_start)) = match_data { + let sp = fragments[i].span; + // we need to calculate the span start, + // then use that in our calulations for the span end + let lo = sp.lo() + BytePos(match_start as u32); + return Some( + sp.with_lo(lo).with_hi(lo + BytePos((md_range.end - md_range.start) as u32)), + ); + } return None; } - let snippet = tcx.sess.source_map().span_to_snippet(span_of_fragments(fragments)?).ok()?; + let snippet = map.span_to_snippet(span_of_fragments(fragments)?).ok()?; let starting_line = markdown[..md_range.start].matches('\n').count(); let ending_line = starting_line + markdown[md_range.start..md_range.end].matches('\n').count(); diff --git a/src/librustdoc/passes/lint/bare_urls.rs b/src/librustdoc/passes/lint/bare_urls.rs index 1e07277d38e5c..3b3ce3e92202a 100644 --- a/src/librustdoc/passes/lint/bare_urls.rs +++ b/src/librustdoc/passes/lint/bare_urls.rs @@ -18,12 +18,15 @@ use crate::html::markdown::main_body_opts; pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &str) { let report_diag = |cx: &DocContext<'_>, msg: &'static str, range: Range| { - let sp = source_span_for_markdown_range(cx.tcx, dox, &range, &item.attrs.doc_strings) - .unwrap_or_else(|| item.attr_span(cx.tcx)); + let maybe_sp = source_span_for_markdown_range(cx.tcx, dox, &range, &item.attrs.doc_strings); + let sp = maybe_sp.unwrap_or_else(|| item.attr_span(cx.tcx)); cx.tcx.node_span_lint(crate::lint::BARE_URLS, hir_id, sp, |lint| { lint.primary_message(msg) - .note("bare URLs are not automatically turned into clickable links") - .multipart_suggestion( + .note("bare URLs are not automatically turned into clickable links"); + // The fallback of using the attribute span is suitable for + // highlighting where the error is, but not for placing the < and > + if let Some(sp) = maybe_sp { + lint.multipart_suggestion( "use an automatic link instead", vec![ (sp.shrink_to_lo(), "<".to_string()), @@ -31,6 +34,7 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: & ], Applicability::MachineApplicable, ); + } }); }; diff --git a/tests/rustdoc-ui/intra-doc/warning.stderr b/tests/rustdoc-ui/intra-doc/warning.stderr index 3a06f1787e093..9b3f6f822d75b 100644 --- a/tests/rustdoc-ui/intra-doc/warning.stderr +++ b/tests/rustdoc-ui/intra-doc/warning.stderr @@ -69,29 +69,19 @@ LL | bar [BarC] bar = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `BarD` - --> $DIR/warning.rs:45:9 + --> $DIR/warning.rs:45:20 | LL | #[doc = "Foo\nbar [BarD] bar\nbaz"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ no item named `BarD` in scope | - = note: the link appears in this line: - - bar [BarD] bar - ^^^^ - = note: no item named `BarD` in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `BarF` - --> $DIR/warning.rs:54:4 + --> $DIR/warning.rs:54:15 | LL | f!("Foo\nbar [BarF] bar\nbaz"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ no item named `BarF` in scope | - = note: the link appears in this line: - - bar [BarF] bar - ^^^^ - = note: no item named `BarF` in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = note: this warning originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -112,29 +102,19 @@ LL | * time to introduce a link [error] = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` - --> $DIR/warning.rs:68:9 + --> $DIR/warning.rs:68:23 | LL | #[doc = "single line [error]"] - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ no item named `error` in scope | - = note: the link appears in this line: - - single line [error] - ^^^^^ - = note: no item named `error` in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` - --> $DIR/warning.rs:71:9 + --> $DIR/warning.rs:71:41 | LL | #[doc = "single line with \"escaping\" [error]"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ no item named `error` in scope | - = note: the link appears in this line: - - single line with "escaping" [error] - ^^^^^ - = note: no item named `error` in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` diff --git a/tests/rustdoc-ui/lints/bare-urls-limit.rs b/tests/rustdoc-ui/lints/bare-urls-limit.rs new file mode 100644 index 0000000000000..f64154b049698 --- /dev/null +++ b/tests/rustdoc-ui/lints/bare-urls-limit.rs @@ -0,0 +1,12 @@ +//@ check-fail + +#![deny(rustdoc::bare_urls)] + +// examples of bare urls that are beyond our ability to generate suggestions for + +// this falls through every heuristic in `source_span_for_markdown_range`, +// and thus does not get any suggestion. +#[doc = "good: \n\n"] +//~^ ERROR this URL is not a hyperlink +#[doc = "bad: https://example.com/"] +pub fn duplicate_raw() {} diff --git a/tests/rustdoc-ui/lints/bare-urls-limit.stderr b/tests/rustdoc-ui/lints/bare-urls-limit.stderr new file mode 100644 index 0000000000000..9573665cb1311 --- /dev/null +++ b/tests/rustdoc-ui/lints/bare-urls-limit.stderr @@ -0,0 +1,18 @@ +error: this URL is not a hyperlink + --> $DIR/bare-urls-limit.rs:9:9 + | +LL | #[doc = "good: \n\n"] + | _________^ +LL | | +LL | | #[doc = "bad: https://example.com/"] + | |___________________________________^ + | + = note: bare URLs are not automatically turned into clickable links +note: the lint level is defined here + --> $DIR/bare-urls-limit.rs:3:9 + | +LL | #![deny(rustdoc::bare_urls)] + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/rustdoc-ui/lints/bare-urls.fixed b/tests/rustdoc-ui/lints/bare-urls.fixed index 7938d715199de..a91573146b823 100644 --- a/tests/rustdoc-ui/lints/bare-urls.fixed +++ b/tests/rustdoc-ui/lints/bare-urls.fixed @@ -38,6 +38,16 @@ //~^ ERROR this URL is not a hyperlink pub fn c() {} +#[doc = "here's a thing: "] +//~^ ERROR this URL is not a hyperlink +pub fn f() {} + +/// +//~^ ERROR this URL is not a hyperlink +#[doc = ""] +//~^ ERROR this URL is not a hyperlink +pub fn mixed() {} + /// /// [a](http://a.com) /// [b] diff --git a/tests/rustdoc-ui/lints/bare-urls.rs b/tests/rustdoc-ui/lints/bare-urls.rs index 75f42b78ffbbe..5b008cdafa232 100644 --- a/tests/rustdoc-ui/lints/bare-urls.rs +++ b/tests/rustdoc-ui/lints/bare-urls.rs @@ -38,6 +38,16 @@ //~^ ERROR this URL is not a hyperlink pub fn c() {} +#[doc = "here's a thing: https://example.com/"] +//~^ ERROR this URL is not a hyperlink +pub fn f() {} + +/// https://example.com/sugar +//~^ ERROR this URL is not a hyperlink +#[doc = "https://example.com/raw"] +//~^ ERROR this URL is not a hyperlink +pub fn mixed() {} + /// /// [a](http://a.com) /// [b] diff --git a/tests/rustdoc-ui/lints/bare-urls.stderr b/tests/rustdoc-ui/lints/bare-urls.stderr index ddfc387eaf66e..e1108c7e7f84e 100644 --- a/tests/rustdoc-ui/lints/bare-urls.stderr +++ b/tests/rustdoc-ui/lints/bare-urls.stderr @@ -207,5 +207,41 @@ help: use an automatic link instead LL | /// hey! | + + -error: aborting due to 17 previous errors +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:41:26 + | +LL | #[doc = "here's a thing: https://example.com/"] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: bare URLs are not automatically turned into clickable links +help: use an automatic link instead + | +LL | #[doc = "here's a thing: "] + | + + + +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:45:5 + | +LL | /// https://example.com/sugar + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: bare URLs are not automatically turned into clickable links +help: use an automatic link instead + | +LL | /// + | + + + +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:47:10 + | +LL | #[doc = "https://example.com/raw"] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: bare URLs are not automatically turned into clickable links +help: use an automatic link instead + | +LL | #[doc = ""] + | + + + +error: aborting due to 20 previous errors diff --git a/tests/rustdoc-ui/unescaped_backticks.stderr b/tests/rustdoc-ui/unescaped_backticks.stderr index d93aaf5f3ca94..1bcb88e108f20 100644 --- a/tests/rustdoc-ui/unescaped_backticks.stderr +++ b/tests/rustdoc-ui/unescaped_backticks.stderr @@ -628,10 +628,10 @@ LL | /// or even to add a number `n` to 42 (`add(42, n)\`)! | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:108:9 + --> $DIR/unescaped_backticks.rs:108:10 | LL | #[doc = "`"] - | ^^^ + | ^ | = help: the opening or closing backtick of an inline code may be missing = help: if you meant to use a literal backtick, escape it @@ -639,10 +639,10 @@ LL | #[doc = "`"] to this: \` error: unescaped backtick - --> $DIR/unescaped_backticks.rs:115:9 + --> $DIR/unescaped_backticks.rs:115:26 | LL | #[doc = concat!("\\", "`")] - | ^^^^^^^^^^^^^^^^^^^^ + | ^ | = help: the opening backtick of an inline code may be missing change: \` From bf90c3eb866d83e91da7bf40676836b0cde90859 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 22 May 2025 19:37:29 +0200 Subject: [PATCH 2629/4206] ~? annotation type is special It does not do any line matching, so it should be separated from the other types. --- src/doc/rustc-dev-guide/src/tests/ui.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md index 721d20b65c5a7..3402838da878b 100644 --- a/src/doc/rustc-dev-guide/src/tests/ui.md +++ b/src/doc/rustc-dev-guide/src/tests/ui.md @@ -192,7 +192,7 @@ They have several forms, but generally are a comment with the diagnostic level to write out the entire message, just make sure to include the important part of the message to make it self-documenting. -The error annotation needs to match with the line of the diagnostic. There are +Most error annotations need to match with the line of the diagnostic. There are several ways to match the message with the line (see the examples below): * `~`: Associates the error level and message with the *current* line @@ -205,9 +205,6 @@ several ways to match the message with the line (see the examples below): * `~v`: Associates the error level and message with the *next* error annotation line. Each symbol (`v`) that you add adds a line to this, so `~vvv` is three lines below the error annotation line. -* `~?`: Used to match error levels and messages with errors not having line - information. These can be placed on any line in the test file, but are - conventionally placed at the end. Example: @@ -222,6 +219,10 @@ The space character between `//~` (or other variants) and the subsequent text is negligible (i.e. there is no semantic difference between `//~ ERROR` and `//~ERROR` although the former is more common in the codebase). +`~? ` (example being `~? ERROR`) +is used to match diagnostics without line information. +These can be placed on any line in the test file, but are conventionally placed at the end. + ### Error annotation examples Here are examples of error annotations on different lines of UI test source. From 1f862a82e2ed32a0c9a6dc33fb7cf32ed7195653 Mon Sep 17 00:00:00 2001 From: Jeremy Drake Date: Wed, 21 May 2025 22:10:28 -0700 Subject: [PATCH 2630/4206] make shared_helpers exe function work for both cygwin and non-cygwin hosts On Cygwin, it needs to not append .exe, because /proc/self/exe (and therefore std::env::current_exe) does not include the .exe extension, breaking bootstrap's rustc wrapper. On hosts other than Cygwin, it *does* need to append .exe because the file really does have a .exe extension, and non-Cygwin hosts won't be doing the same filename rewriting that Cygwin does when looking for a file X but finding only X.exe in its place. --- src/bootstrap/src/utils/shared_helpers.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/utils/shared_helpers.rs b/src/bootstrap/src/utils/shared_helpers.rs index 08e1c21e58e7c..561af34a4478b 100644 --- a/src/bootstrap/src/utils/shared_helpers.rs +++ b/src/bootstrap/src/utils/shared_helpers.rs @@ -46,7 +46,16 @@ pub fn dylib_path() -> Vec { /// Given an executable called `name`, return the filename for the /// executable for a particular target. pub fn exe(name: &str, target: &str) -> String { - if target.contains("windows") { + // On Cygwin, the decision to append .exe or not is not as straightforward. + // Executable files do actually have .exe extensions so on hosts other than + // Cygwin it is necessary. But on a Cygwin host there is magic happening + // that redirects requests for file X to file X.exe if it exists, and + // furthermore /proc/self/exe (and thus std::env::current_exe) always + // returns the name *without* the .exe extension. For comparisons against + // that to match, we therefore do not append .exe for Cygwin targets on + // a Cygwin host. + if target.contains("windows") || (cfg!(not(target_os = "cygwin")) && target.contains("cygwin")) + { format!("{name}.exe") } else if target.contains("uefi") { format!("{name}.efi") From 9d9705f4c360df5d8c77876496b0c5594cbc7fa0 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 1 May 2025 18:15:04 +0200 Subject: [PATCH 2631/4206] Collect and use `#![doc(test(attr(..)))]` at module level too --- src/librustdoc/doctest.rs | 18 ++--- src/librustdoc/doctest/extracted.rs | 5 +- src/librustdoc/doctest/make.rs | 21 +++++- src/librustdoc/doctest/markdown.rs | 2 +- src/librustdoc/doctest/runner.rs | 11 ++- src/librustdoc/doctest/rust.rs | 40 ++++++++++- src/librustdoc/doctest/tests.rs | 68 +++++++++++-------- src/librustdoc/html/markdown.rs | 1 - .../rustdoc-ui/doctest/dead-code-module-2.rs | 27 ++++++++ .../doctest/dead-code-module-2.stdout | 30 ++++++++ tests/rustdoc-ui/doctest/dead-code-module.rs | 18 +++++ .../doctest/dead-code-module.stdout | 29 ++++++++ .../doctest/doc-test-attr-pass-module.rs | 11 +++ 13 files changed, 229 insertions(+), 52 deletions(-) create mode 100644 tests/rustdoc-ui/doctest/dead-code-module-2.rs create mode 100644 tests/rustdoc-ui/doctest/dead-code-module-2.stdout create mode 100644 tests/rustdoc-ui/doctest/dead-code-module.rs create mode 100644 tests/rustdoc-ui/doctest/dead-code-module.stdout create mode 100644 tests/rustdoc-ui/doctest/doc-test-attr-pass-module.rs diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index b2fe24db0a2eb..45e5c894bb9db 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -45,8 +45,6 @@ pub(crate) struct GlobalTestOptions { /// Whether inserting extra indent spaces in code block, /// default is `false`, only `true` for generating code link of Rust playground pub(crate) insert_indent_space: bool, - /// Additional crate-level attributes to add to doctests. - pub(crate) attrs: Vec, /// Path to file containing arguments for the invocation of rustc. pub(crate) args_file: PathBuf, } @@ -371,12 +369,9 @@ fn scrape_test_config( attrs: &[hir::Attribute], args_file: PathBuf, ) -> GlobalTestOptions { - use rustc_ast_pretty::pprust; - let mut opts = GlobalTestOptions { crate_name, no_crate_inject: false, - attrs: Vec::new(), insert_indent_space: false, args_file, }; @@ -393,13 +388,7 @@ fn scrape_test_config( if attr.has_name(sym::no_crate_inject) { opts.no_crate_inject = true; } - if attr.has_name(sym::attr) - && let Some(l) = attr.meta_item_list() - { - for item in l { - opts.attrs.push(pprust::meta_list_item_to_string(item)); - } - } + // NOTE: `test(attr(..))` is handled when discovering the individual tests } opts @@ -848,6 +837,7 @@ pub(crate) struct ScrapedDocTest { text: String, name: String, span: Span, + global_crate_attrs: Vec, } impl ScrapedDocTest { @@ -858,6 +848,7 @@ impl ScrapedDocTest { langstr: LangString, text: String, span: Span, + global_crate_attrs: Vec, ) -> Self { let mut item_path = logical_path.join("::"); item_path.retain(|c| c != ' '); @@ -867,7 +858,7 @@ impl ScrapedDocTest { let name = format!("{} - {item_path}(line {line})", filename.prefer_remapped_unconditionaly()); - Self { filename, line, langstr, text, name, span } + Self { filename, line, langstr, text, name, span, global_crate_attrs } } fn edition(&self, opts: &RustdocOptions) -> Edition { self.langstr.edition.unwrap_or(opts.edition) @@ -949,6 +940,7 @@ impl CreateRunnableDocTests { let edition = scraped_test.edition(&self.rustdoc_options); let doctest = BuildDocTestBuilder::new(&scraped_test.text) .crate_name(&self.opts.crate_name) + .global_crate_attrs(scraped_test.global_crate_attrs.clone()) .edition(edition) .can_merge_doctests(self.can_merge_doctests) .test_id(test_id) diff --git a/src/librustdoc/doctest/extracted.rs b/src/librustdoc/doctest/extracted.rs index 3b17ccc78c712..ebe6bfd22ba10 100644 --- a/src/librustdoc/doctest/extracted.rs +++ b/src/librustdoc/doctest/extracted.rs @@ -35,13 +35,16 @@ impl ExtractedDocTests { ) { let edition = scraped_test.edition(options); - let ScrapedDocTest { filename, line, langstr, text, name, .. } = scraped_test; + let ScrapedDocTest { filename, line, langstr, text, name, global_crate_attrs, .. } = + scraped_test; let doctest = BuildDocTestBuilder::new(&text) .crate_name(&opts.crate_name) + .global_crate_attrs(global_crate_attrs) .edition(edition) .lang_str(&langstr) .build(None); + let (full_test_code, size) = doctest.generate_unique_doctest( &text, langstr.test_harness, diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 66647b880186d..5e571613d6ff6 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -45,6 +45,7 @@ pub(crate) struct BuildDocTestBuilder<'a> { test_id: Option, lang_str: Option<&'a LangString>, span: Span, + global_crate_attrs: Vec, } impl<'a> BuildDocTestBuilder<'a> { @@ -57,6 +58,7 @@ impl<'a> BuildDocTestBuilder<'a> { test_id: None, lang_str: None, span: DUMMY_SP, + global_crate_attrs: Vec::new(), } } @@ -96,6 +98,12 @@ impl<'a> BuildDocTestBuilder<'a> { self } + #[inline] + pub(crate) fn global_crate_attrs(mut self, global_crate_attrs: Vec) -> Self { + self.global_crate_attrs = global_crate_attrs; + self + } + pub(crate) fn build(self, dcx: Option>) -> DocTestBuilder { let BuildDocTestBuilder { source, @@ -106,6 +114,7 @@ impl<'a> BuildDocTestBuilder<'a> { test_id, lang_str, span, + global_crate_attrs, } = self; let can_merge_doctests = can_merge_doctests && lang_str.is_some_and(|lang_str| { @@ -133,6 +142,7 @@ impl<'a> BuildDocTestBuilder<'a> { // If the AST returned an error, we don't want this doctest to be merged with the // others. return DocTestBuilder::invalid( + Vec::new(), String::new(), String::new(), String::new(), @@ -155,6 +165,7 @@ impl<'a> BuildDocTestBuilder<'a> { DocTestBuilder { supports_color, has_main_fn, + global_crate_attrs, crate_attrs, maybe_crate_attrs, crates, @@ -173,6 +184,7 @@ pub(crate) struct DocTestBuilder { pub(crate) supports_color: bool, pub(crate) already_has_extern_crate: bool, pub(crate) has_main_fn: bool, + pub(crate) global_crate_attrs: Vec, pub(crate) crate_attrs: String, /// If this is a merged doctest, it will be put into `everything_else`, otherwise it will /// put into `crate_attrs`. @@ -186,6 +198,7 @@ pub(crate) struct DocTestBuilder { impl DocTestBuilder { fn invalid( + global_crate_attrs: Vec, crate_attrs: String, maybe_crate_attrs: String, crates: String, @@ -195,6 +208,7 @@ impl DocTestBuilder { Self { supports_color: false, has_main_fn: false, + global_crate_attrs, crate_attrs, maybe_crate_attrs, crates, @@ -224,7 +238,8 @@ impl DocTestBuilder { let mut line_offset = 0; let mut prog = String::new(); let everything_else = self.everything_else.trim(); - if opts.attrs.is_empty() { + + if self.global_crate_attrs.is_empty() { // If there aren't any attributes supplied by #![doc(test(attr(...)))], then allow some // lints that are commonly triggered in doctests. The crate-level test attributes are // commonly used to make tests fail in case they trigger warnings, so having this there in @@ -233,8 +248,8 @@ impl DocTestBuilder { line_offset += 1; } - // Next, any attributes that came from the crate root via #![doc(test(attr(...)))]. - for attr in &opts.attrs { + // Next, any attributes that came from #![doc(test(attr(...)))]. + for attr in &self.global_crate_attrs { prog.push_str(&format!("#![{attr}]\n")); line_offset += 1; } diff --git a/src/librustdoc/doctest/markdown.rs b/src/librustdoc/doctest/markdown.rs index e358a7e44e515..7f26605f2562c 100644 --- a/src/librustdoc/doctest/markdown.rs +++ b/src/librustdoc/doctest/markdown.rs @@ -31,6 +31,7 @@ impl DocTestVisitor for MdCollector { config, test, DUMMY_SP, + Vec::new(), )); } @@ -96,7 +97,6 @@ pub(crate) fn test(input: &Input, options: Options) -> Result<(), String> { crate_name, no_crate_inject: true, insert_indent_space: false, - attrs: vec![], args_file, }; diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs index 39a4f23560a7e..f0914474c7934 100644 --- a/src/librustdoc/doctest/runner.rs +++ b/src/librustdoc/doctest/runner.rs @@ -12,6 +12,7 @@ use crate::html::markdown::{Ignore, LangString}; /// Convenient type to merge compatible doctests into one. pub(crate) struct DocTestRunner { crate_attrs: FxIndexSet, + global_crate_attrs: FxIndexSet, ids: String, output: String, output_merged_tests: String, @@ -23,6 +24,7 @@ impl DocTestRunner { pub(crate) fn new() -> Self { Self { crate_attrs: FxIndexSet::default(), + global_crate_attrs: FxIndexSet::default(), ids: String::new(), output: String::new(), output_merged_tests: String::new(), @@ -46,6 +48,9 @@ impl DocTestRunner { for line in doctest.crate_attrs.split('\n') { self.crate_attrs.insert(line.to_string()); } + for line in &doctest.global_crate_attrs { + self.global_crate_attrs.insert(line.to_string()); + } } self.ids.push_str(&format!( "tests.push({}::TEST);\n", @@ -85,7 +90,7 @@ impl DocTestRunner { code_prefix.push('\n'); } - if opts.attrs.is_empty() { + if self.global_crate_attrs.is_empty() { // If there aren't any attributes supplied by #![doc(test(attr(...)))], then allow some // lints that are commonly triggered in doctests. The crate-level test attributes are // commonly used to make tests fail in case they trigger warnings, so having this there in @@ -93,8 +98,8 @@ impl DocTestRunner { code_prefix.push_str("#![allow(unused)]\n"); } - // Next, any attributes that came from the crate root via #![doc(test(attr(...)))]. - for attr in &opts.attrs { + // Next, any attributes that came from #![doc(test(attr(...)))]. + for attr in &self.global_crate_attrs { code_prefix.push_str(&format!("#![{attr}]\n")); } diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index f9d2aa3d3b4bd..4e9b1ee36f3db 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -4,6 +4,7 @@ use std::cell::Cell; use std::env; use std::sync::Arc; +use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_hir::{self as hir, CRATE_HIR_ID, intravisit}; @@ -11,7 +12,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_resolve::rustdoc::span_of_fragments; use rustc_span::source_map::SourceMap; -use rustc_span::{BytePos, DUMMY_SP, FileName, Pos, Span}; +use rustc_span::{BytePos, DUMMY_SP, FileName, Pos, Span, sym}; use super::{DocTestVisitor, ScrapedDocTest}; use crate::clean::{Attributes, extract_cfg_from_attrs}; @@ -22,6 +23,7 @@ struct RustCollector { tests: Vec, cur_path: Vec, position: Span, + global_crate_attrs: Vec, } impl RustCollector { @@ -75,6 +77,7 @@ impl DocTestVisitor for RustCollector { config, test, span, + self.global_crate_attrs.clone(), )); } @@ -94,6 +97,7 @@ impl<'tcx> HirCollector<'tcx> { cur_path: vec![], position: DUMMY_SP, tests: vec![], + global_crate_attrs: Vec::new(), }; Self { codes, tcx, collector } } @@ -170,6 +174,40 @@ impl<'tcx> intravisit::Visitor<'tcx> for HirCollector<'tcx> { self.tcx } + fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, _s: Span, hir_id: hir::HirId) { + let attrs = self.tcx.hir_attrs(hir_id); + + if !attrs.is_empty() { + // Try collecting `#![doc(test(attr(...)))]` from the attribute module + let old_len = self.collector.global_crate_attrs.len(); + for doc_test_attrs in attrs + .iter() + .filter(|a| a.has_name(sym::doc)) + .flat_map(|a| a.meta_item_list().unwrap_or_default()) + .filter(|a| a.has_name(sym::test)) + { + let Some(doc_test_attrs) = doc_test_attrs.meta_item_list() else { continue }; + for attr in doc_test_attrs + .iter() + .filter(|a| a.has_name(sym::attr)) + .flat_map(|a| a.meta_item_list().unwrap_or_default()) + .map(|i| pprust::meta_list_item_to_string(i)) + { + // Add the additional attributes to the global_crate_attrs vector + self.collector.global_crate_attrs.push(attr); + } + } + + let r = intravisit::walk_mod(self, m); + + // Restore global_crate_attrs to it's previous size/content + self.collector.global_crate_attrs.truncate(old_len); + r + } else { + intravisit::walk_mod(self, m) + } + } + fn visit_item(&mut self, item: &'tcx hir::Item<'_>) { let name = match &item.kind { hir::ItemKind::Impl(impl_) => { diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs index 08248fdf39bbe..ce2984ced7904 100644 --- a/src/librustdoc/doctest/tests.rs +++ b/src/librustdoc/doctest/tests.rs @@ -7,9 +7,11 @@ fn make_test( crate_name: Option<&str>, dont_insert_main: bool, opts: &GlobalTestOptions, + global_crate_attrs: Vec<&str>, test_id: Option<&str>, ) -> (String, usize) { - let mut builder = BuildDocTestBuilder::new(test_code); + let mut builder = BuildDocTestBuilder::new(test_code) + .global_crate_attrs(global_crate_attrs.into_iter().map(|a| a.to_string()).collect()); if let Some(crate_name) = crate_name { builder = builder.crate_name(crate_name); } @@ -28,7 +30,6 @@ fn default_global_opts(crate_name: impl Into) -> GlobalTestOptions { crate_name: crate_name.into(), no_crate_inject: false, insert_indent_space: false, - attrs: vec![], args_file: PathBuf::new(), } } @@ -43,7 +44,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -58,7 +59,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, Some("asdf"), false, &opts, None); + let (output, len) = make_test(input, Some("asdf"), false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -77,7 +78,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, Some("asdf"), false, &opts, None); + let (output, len) = make_test(input, Some("asdf"), false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 3)); } @@ -94,7 +95,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, Some("asdf"), false, &opts, None); + let (output, len) = make_test(input, Some("asdf"), false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -112,7 +113,7 @@ use std::*; assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, Some("std"), false, &opts, None); + let (output, len) = make_test(input, Some("std"), false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -131,7 +132,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, Some("asdf"), false, &opts, None); + let (output, len) = make_test(input, Some("asdf"), false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -148,7 +149,7 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, Some("asdf"), false, &opts, None); + let (output, len) = make_test(input, Some("asdf"), false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -156,8 +157,7 @@ assert_eq!(2+2, 4); fn make_test_opts_attrs() { // If you supplied some doctest attributes with `#![doc(test(attr(...)))]`, it will use // those instead of the stock `#![allow(unused)]`. - let mut opts = default_global_opts("asdf"); - opts.attrs.push("feature(sick_rad)".to_string()); + let opts = default_global_opts("asdf"); let input = "use asdf::qwop; assert_eq!(2+2, 4);"; let expected = "#![feature(sick_rad)] @@ -168,11 +168,10 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, Some("asdf"), false, &opts, None); + let (output, len) = + make_test(input, Some("asdf"), false, &opts, vec!["feature(sick_rad)"], None); assert_eq!((output, len), (expected, 3)); - // Adding more will also bump the returned line offset. - opts.attrs.push("feature(hella_dope)".to_string()); let expected = "#![feature(sick_rad)] #![feature(hella_dope)] #[allow(unused_extern_crates)] @@ -182,7 +181,18 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, Some("asdf"), false, &opts, None); + let (output, len) = make_test( + input, + Some("asdf"), + false, + &opts, + vec![ + "feature(sick_rad)", + // Adding more will also bump the returned line offset. + "feature(hella_dope)", + ], + None, + ); assert_eq!((output, len), (expected, 4)); } @@ -200,7 +210,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -216,7 +226,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 1)); } @@ -232,7 +242,7 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -246,7 +256,7 @@ assert_eq!(2+2, 4);"; //Ceci n'est pas une `fn main` assert_eq!(2+2, 4);" .to_string(); - let (output, len) = make_test(input, None, true, &opts, None); + let (output, len) = make_test(input, None, true, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 1)); } @@ -264,7 +274,7 @@ assert_eq!(2+2, 4); }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -284,7 +294,7 @@ assert_eq!(asdf::foo, 4); }" .to_string(); - let (output, len) = make_test(input, Some("asdf"), false, &opts, None); + let (output, len) = make_test(input, Some("asdf"), false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 3)); } @@ -302,7 +312,7 @@ test_wrapper! { }" .to_string(); - let (output, len) = make_test(input, Some("my_crate"), false, &opts, None); + let (output, len) = make_test(input, Some("my_crate"), false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 1)); } @@ -322,7 +332,7 @@ io::stdin().read_line(&mut input)?; Ok::<(), io:Error>(()) } _inner().unwrap() }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -336,7 +346,7 @@ fn main() { #[allow(non_snake_case)] fn _doctest_main__some_unique_name() { assert_eq!(2+2, 4); } _doctest_main__some_unique_name() }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, Some("_some_unique_name")); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), Some("_some_unique_name")); assert_eq!((output, len), (expected, 2)); } @@ -355,7 +365,7 @@ fn main() { eprintln!(\"hello anan\"); }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } @@ -375,7 +385,7 @@ fn main() { eprintln!(\"hello anan\"); }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 1)); } @@ -400,7 +410,7 @@ fn main() { }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); // And same, if there is a `main` function provided by the user, we ensure that it's @@ -420,7 +430,7 @@ fn main() {}"; fn main() {}" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 1)); } @@ -448,6 +458,6 @@ pub mod outer_module { } }" .to_string(); - let (output, len) = make_test(input, None, false, &opts, None); + let (output, len) = make_test(input, None, false, &opts, Vec::new(), None); assert_eq!((output, len), (expected, 2)); } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index ad7dfafd90c7d..b48082defa705 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -300,7 +300,6 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { crate_name: krate.map(String::from).unwrap_or_default(), no_crate_inject: false, insert_indent_space: true, - attrs: vec![], args_file: PathBuf::new(), }; let mut builder = doctest::BuildDocTestBuilder::new(&test).edition(edition); diff --git a/tests/rustdoc-ui/doctest/dead-code-module-2.rs b/tests/rustdoc-ui/doctest/dead-code-module-2.rs new file mode 100644 index 0000000000000..de7b11b91ec57 --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code-module-2.rs @@ -0,0 +1,27 @@ +// Same test as dead-code-module but with 2 doc(test(attr())) at different levels. + +//@ edition: 2024 +//@ compile-flags:--test +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ failure-status: 101 + +#![doc(test(attr(allow(unused_variables))))] + +mod my_mod { + #![doc(test(attr(deny(warnings))))] + + /// Example + /// + /// ```rust,no_run + /// trait T { fn f(); } + /// ``` + pub fn f() {} +} + +/// Example +/// +/// ```rust,no_run +/// trait OnlyWarning { fn no_deny_warnings(); } +/// ``` +pub fn g() {} diff --git a/tests/rustdoc-ui/doctest/dead-code-module-2.stdout b/tests/rustdoc-ui/doctest/dead-code-module-2.stdout new file mode 100644 index 0000000000000..36b8eaed22bb2 --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code-module-2.stdout @@ -0,0 +1,30 @@ + +running 2 tests +test $DIR/dead-code-module-2.rs - my_mod::f (line 16) - compile ... FAILED +test $DIR/dead-code-module-2.rs - g (line 24) - compile ... ok + +failures: + +---- $DIR/dead-code-module-2.rs - my_mod::f (line 16) stdout ---- +error: trait `T` is never used + --> $DIR/dead-code-module-2.rs:17:7 + | +LL | trait T { fn f(); } + | ^ + | +note: the lint level is defined here + --> $DIR/dead-code-module-2.rs:15:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(dead_code)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. + +failures: + $DIR/dead-code-module-2.rs - my_mod::f (line 16) + +test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/dead-code-module.rs b/tests/rustdoc-ui/doctest/dead-code-module.rs new file mode 100644 index 0000000000000..f825749a6a25a --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code-module.rs @@ -0,0 +1,18 @@ +// Same test as dead-code but inside a module. + +//@ edition: 2024 +//@ compile-flags:--test +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ failure-status: 101 + +mod my_mod { + #![doc(test(attr(allow(unused_variables), deny(warnings))))] + + /// Example + /// + /// ```rust,no_run + /// trait T { fn f(); } + /// ``` + pub fn f() {} +} diff --git a/tests/rustdoc-ui/doctest/dead-code-module.stdout b/tests/rustdoc-ui/doctest/dead-code-module.stdout new file mode 100644 index 0000000000000..b5ccf225d25c7 --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code-module.stdout @@ -0,0 +1,29 @@ + +running 1 test +test $DIR/dead-code-module.rs - my_mod::f (line 14) - compile ... FAILED + +failures: + +---- $DIR/dead-code-module.rs - my_mod::f (line 14) stdout ---- +error: trait `T` is never used + --> $DIR/dead-code-module.rs:15:7 + | +LL | trait T { fn f(); } + | ^ + | +note: the lint level is defined here + --> $DIR/dead-code-module.rs:13:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(dead_code)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. + +failures: + $DIR/dead-code-module.rs - my_mod::f (line 14) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/doc-test-attr-pass-module.rs b/tests/rustdoc-ui/doctest/doc-test-attr-pass-module.rs new file mode 100644 index 0000000000000..e916ca41ea0eb --- /dev/null +++ b/tests/rustdoc-ui/doctest/doc-test-attr-pass-module.rs @@ -0,0 +1,11 @@ +//@ check-pass + +#![crate_type = "lib"] +#![deny(invalid_doc_attributes)] +#![doc(test(no_crate_inject))] + +mod my_mod { + #![doc(test(attr(deny(warnings))))] + + pub fn foo() {} +} From 041d95d4dca9f31c4abf6938bb5eb1d893917e5b Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 1 May 2025 18:44:38 +0200 Subject: [PATCH 2632/4206] Allow `#![doc(test(attr(..)))]` doctests to be again merged together --- src/librustdoc/doctest.rs | 31 ++++++++++++++----- .../doctests-keep-binaries-2024/rmake.rs | 17 +++++++++- .../doctest/dead-code-module-2.stdout | 11 +++++-- 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 45e5c894bb9db..a81d6020f7143 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -5,6 +5,7 @@ mod runner; mod rust; use std::fs::File; +use std::hash::{Hash, Hasher}; use std::io::{self, Write}; use std::path::{Path, PathBuf}; use std::process::{self, Command, Stdio}; @@ -14,7 +15,7 @@ use std::{panic, str}; pub(crate) use make::{BuildDocTestBuilder, DocTestBuilder}; pub(crate) use markdown::test as test_markdown; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxHasher, FxIndexMap, FxIndexSet}; use rustc_errors::emitter::HumanReadableErrorType; use rustc_errors::{ColorConfig, DiagCtxtHandle}; use rustc_hir as hir; @@ -281,7 +282,7 @@ pub(crate) fn run_tests( rustdoc_options: &Arc, unused_extern_reports: &Arc>>, mut standalone_tests: Vec, - mergeable_tests: FxIndexMap>, + mergeable_tests: FxIndexMap>, // We pass this argument so we can drop it manually before using `exit`. mut temp_dir: Option, ) { @@ -296,7 +297,7 @@ pub(crate) fn run_tests( let mut ran_edition_tests = 0; let target_str = rustdoc_options.target.to_string(); - for (edition, mut doctests) in mergeable_tests { + for (MergeableTestKey { edition, global_crate_attrs_hash }, mut doctests) in mergeable_tests { if doctests.is_empty() { continue; } @@ -306,8 +307,8 @@ pub(crate) fn run_tests( let rustdoc_test_options = IndividualTestOptions::new( rustdoc_options, - &Some(format!("merged_doctest_{edition}")), - PathBuf::from(format!("doctest_{edition}.rs")), + &Some(format!("merged_doctest_{edition}_{global_crate_attrs_hash}")), + PathBuf::from(format!("doctest_{edition}_{global_crate_attrs_hash}.rs")), ); for (doctest, scraped_test) in &doctests { @@ -887,9 +888,15 @@ pub(crate) trait DocTestVisitor { fn visit_header(&mut self, _name: &str, _level: u32) {} } +#[derive(Clone, Debug, Hash, Eq, PartialEq)] +pub(crate) struct MergeableTestKey { + edition: Edition, + global_crate_attrs_hash: u64, +} + struct CreateRunnableDocTests { standalone_tests: Vec, - mergeable_tests: FxIndexMap>, + mergeable_tests: FxIndexMap>, rustdoc_options: Arc, opts: GlobalTestOptions, @@ -957,7 +964,17 @@ impl CreateRunnableDocTests { let test_desc = self.generate_test_desc_and_fn(doctest, scraped_test); self.standalone_tests.push(test_desc); } else { - self.mergeable_tests.entry(edition).or_default().push((doctest, scraped_test)); + self.mergeable_tests + .entry(MergeableTestKey { + edition, + global_crate_attrs_hash: { + let mut hasher = FxHasher::default(); + scraped_test.global_crate_attrs.hash(&mut hasher); + hasher.finish() + }, + }) + .or_default() + .push((doctest, scraped_test)); } } diff --git a/tests/run-make/doctests-keep-binaries-2024/rmake.rs b/tests/run-make/doctests-keep-binaries-2024/rmake.rs index 3e8ffcbf24457..97324e1dcbc8e 100644 --- a/tests/run-make/doctests-keep-binaries-2024/rmake.rs +++ b/tests/run-make/doctests-keep-binaries-2024/rmake.rs @@ -16,7 +16,22 @@ fn setup_test_env(callback: F) { } fn check_generated_binaries() { - run("doctests/merged_doctest_2024/rust_out"); + let mut found_merged_doctest = false; + rfs::read_dir_entries("doctests/", |path| { + if path + .file_name() + .and_then(|name| name.to_str()) + .is_some_and(|name| name.starts_with("merged_doctest_2024")) + { + found_merged_doctest = true; + let rust_out = path.join("rust_out"); + let rust_out = rust_out.to_string_lossy(); + run(&*rust_out); + } + }); + if !found_merged_doctest { + panic!("no directory starting with `merged_doctest_2024` found under `doctests/`"); + } } fn main() { diff --git a/tests/rustdoc-ui/doctest/dead-code-module-2.stdout b/tests/rustdoc-ui/doctest/dead-code-module-2.stdout index 36b8eaed22bb2..d44068dcbf5d7 100644 --- a/tests/rustdoc-ui/doctest/dead-code-module-2.stdout +++ b/tests/rustdoc-ui/doctest/dead-code-module-2.stdout @@ -1,8 +1,13 @@ -running 2 tests -test $DIR/dead-code-module-2.rs - my_mod::f (line 16) - compile ... FAILED +running 1 test test $DIR/dead-code-module-2.rs - g (line 24) - compile ... ok +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + + +running 1 test +test $DIR/dead-code-module-2.rs - my_mod::f (line 16) - compile ... FAILED + failures: ---- $DIR/dead-code-module-2.rs - my_mod::f (line 16) stdout ---- @@ -26,5 +31,5 @@ Couldn't compile the test. failures: $DIR/dead-code-module-2.rs - my_mod::f (line 16) -test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME From 316e62a05855d80c6800dac3437414f7675afbc9 Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 5 May 2025 22:50:40 +0200 Subject: [PATCH 2633/4206] Allow `#![doc(test(attr(..)))]` at every level --- compiler/rustc_passes/messages.ftl | 5 -- compiler/rustc_passes/src/check_attr.rs | 41 +---------- compiler/rustc_passes/src/errors.rs | 12 +-- .../write-documentation/the-doc-attribute.md | 51 ++++++------- tests/rustdoc-ui/lints/invalid-doc-attr.rs | 4 - .../rustdoc-ui/lints/invalid-doc-attr.stderr | 32 +++----- tests/ui/lint/unused/useless-comment.rs | 7 ++ tests/ui/lint/unused/useless-comment.stderr | 73 ++++++++++++++++--- tests/ui/rustdoc/doc-test-attr-pass.rs | 38 ++++++++++ 9 files changed, 147 insertions(+), 116 deletions(-) diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 2f264ed4fc023..6d815e510ea20 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -46,11 +46,6 @@ passes_attr_crate_level = .suggestion = to apply to the crate, use an inner attribute .note = read for more information -passes_attr_mod_level = - this attribute can only be applied at module level - .suggestion = to apply to the crate, use an inner attribute at the crate level - .note = read for more information - passes_attr_only_in_functions = `{$attr}` attribute can only be used on functions diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 376b424a1af5d..29063ea8d2911 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1252,7 +1252,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let bang_span = attr.span().lo() + BytePos(1); let sugg = (attr.style() == AttrStyle::Outer && self.tcx.hir_get_parent_item(hir_id) == CRATE_OWNER_ID) - .then_some(errors::AttrCrateLevelSugg { + .then_some(errors::AttrCrateLevelOnlySugg { attr: attr.span().with_lo(bang_span).with_hi(bang_span), }); self.tcx.emit_node_span_lint( @@ -1266,46 +1266,13 @@ impl<'tcx> CheckAttrVisitor<'tcx> { true } - /// Checks that an attribute is used at module level. Returns `true` if valid. - fn check_attr_mod_level( - &self, - attr: &Attribute, - meta: &MetaItemInner, - hir_id: HirId, - target: Target, - ) -> bool { - if target != Target::Mod { - // insert a bang between `#` and `[...` - let bang_span = attr.span().lo() + BytePos(1); - let sugg = (attr.style() == AttrStyle::Outer - && self.tcx.hir_get_parent_item(hir_id) == CRATE_OWNER_ID) - .then_some(errors::AttrCrateLevelSugg { - attr: attr.span().with_lo(bang_span).with_hi(bang_span), - }); - self.tcx.emit_node_span_lint( - INVALID_DOC_ATTRIBUTES, - hir_id, - meta.span(), - errors::AttrModLevelOnly { sugg }, - ); - return false; - } - true - } - /// Checks that `doc(test(...))` attribute contains only valid attributes and are at the right place. - fn check_test_attr( - &self, - attr: &Attribute, - meta: &MetaItemInner, - hir_id: HirId, - target: Target, - ) { + fn check_test_attr(&self, attr: &Attribute, meta: &MetaItemInner, hir_id: HirId) { if let Some(metas) = meta.meta_item_list() { for i_meta in metas { match (i_meta.name(), i_meta.meta_item()) { (Some(sym::attr), _) => { - self.check_attr_mod_level(attr, meta, hir_id, target); + // Allowed everywhere like `#[doc]` } (Some(sym::no_crate_inject), _) => { self.check_attr_crate_level(attr, meta, hir_id); @@ -1396,7 +1363,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } Some(sym::test) => { - self.check_test_attr(attr, meta, hir_id, target); + self.check_test_attr(attr, meta, hir_id); } Some( diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 38b0db37e12b4..00682a9c7a794 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1890,20 +1890,12 @@ pub(crate) struct UnusedVarTryIgnoreSugg { #[note] pub(crate) struct AttrCrateLevelOnly { #[subdiagnostic] - pub sugg: Option, -} - -#[derive(LintDiagnostic)] -#[diag(passes_attr_mod_level)] -#[note] -pub(crate) struct AttrModLevelOnly { - #[subdiagnostic] - pub sugg: Option, + pub sugg: Option, } #[derive(Subdiagnostic)] #[suggestion(passes_suggestion, applicability = "maybe-incorrect", code = "!", style = "verbose")] -pub(crate) struct AttrCrateLevelSugg { +pub(crate) struct AttrCrateLevelOnlySugg { #[primary_span] pub attr: Span, } diff --git a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md index afbcf4000c538..a70861faa761a 100644 --- a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md +++ b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md @@ -141,34 +141,6 @@ But if you include this: it will not. -## At the module level - -These forms of the `#[doc]` attribute are used on individual modules, to control how -they are documented. - -### `test(attr(...))` - -This form of the `doc` attribute allows you to add arbitrary attributes to all your doctests. For -example, if you want your doctests to fail if they have dead code, you could add this: - -```rust,no_run -#![doc(test(attr(deny(dead_code))))] - -mod my_mod { - #![doc(test(attr(allow(dead_code))))] // but allow `dead_code` for this module -} -``` - -`test(attr(..))` attributes are appended to the parent module's, they do not replace the current -list of attributes. In the previous example, both attributes would be present: - -```rust,no_run -// For every doctest in `my_mod` - -#![deny(dead_code)] // from the crate-root -#![allow(dead_code)] // from `my_mod` -``` - ## At the item level These forms of the `#[doc]` attribute are used on individual items, to control how @@ -300,3 +272,26 @@ To get around this limitation, we just add `#[doc(alias = "lib_name_do_something on the `do_something` method and then it's all good! Users can now look for `lib_name_do_something` in our crate directly and find `Obj::do_something`. + +### `test(attr(...))` + +This form of the `doc` attribute allows you to add arbitrary attributes to all your doctests. For +example, if you want your doctests to fail if they have dead code, you could add this: + +```rust,no_run +#![doc(test(attr(deny(dead_code))))] + +mod my_mod { + #![doc(test(attr(allow(dead_code))))] // but allow `dead_code` for this module +} +``` + +`test(attr(..))` attributes are appended to the parent module's, they do not replace the current +list of attributes. In the previous example, both attributes would be present: + +```rust,no_run +// For every doctest in `my_mod` + +#![deny(dead_code)] // from the crate-root +#![allow(dead_code)] // from `my_mod` +``` diff --git a/tests/rustdoc-ui/lints/invalid-doc-attr.rs b/tests/rustdoc-ui/lints/invalid-doc-attr.rs index cd5ae44b1266d..e1cc08ca24272 100644 --- a/tests/rustdoc-ui/lints/invalid-doc-attr.rs +++ b/tests/rustdoc-ui/lints/invalid-doc-attr.rs @@ -4,10 +4,6 @@ #![doc(masked)] //~^ ERROR this attribute can only be applied to an `extern crate` item -#[doc(test(attr(allow(warnings))))] -//~^ ERROR can only be applied at module level -//~| HELP to apply to the crate, use an inner attribute -//~| SUGGESTION ! #[doc(test(no_crate_inject))] //~^ ERROR can only be applied at the crate level //~| HELP to apply to the crate, use an inner attribute diff --git a/tests/rustdoc-ui/lints/invalid-doc-attr.stderr b/tests/rustdoc-ui/lints/invalid-doc-attr.stderr index 0fd55ff94d872..7621999a8ca52 100644 --- a/tests/rustdoc-ui/lints/invalid-doc-attr.stderr +++ b/tests/rustdoc-ui/lints/invalid-doc-attr.stderr @@ -1,30 +1,18 @@ -error: this attribute can only be applied at module level - --> $DIR/invalid-doc-attr.rs:7:7 - | -LL | #[doc(test(attr(allow(warnings))))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: read for more information - = note: `#[deny(invalid_doc_attributes)]` on by default -help: to apply to the crate, use an inner attribute at the crate level - | -LL | #![doc(test(attr(allow(warnings))))] - | + - error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:11:7 + --> $DIR/invalid-doc-attr.rs:7:7 | LL | #[doc(test(no_crate_inject))] | ^^^^^^^^^^^^^^^^^^^^^ | = note: read for more information + = note: `#[deny(invalid_doc_attributes)]` on by default help: to apply to the crate, use an inner attribute | LL | #![doc(test(no_crate_inject))] | + error: this attribute can only be applied to a `use` item - --> $DIR/invalid-doc-attr.rs:15:7 + --> $DIR/invalid-doc-attr.rs:11:7 | LL | #[doc(inline)] | ^^^^^^ only applicable on `use` items @@ -35,7 +23,7 @@ LL | pub fn foo() {} = note: read for more information error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:20:12 + --> $DIR/invalid-doc-attr.rs:16:12 | LL | #![doc(test(no_crate_inject))] | ^^^^^^^^^^^^^^^^^^^^^ @@ -43,7 +31,7 @@ LL | #![doc(test(no_crate_inject))] = note: read for more information error: conflicting doc inlining attributes - --> $DIR/invalid-doc-attr.rs:30:7 + --> $DIR/invalid-doc-attr.rs:26:7 | LL | #[doc(inline)] | ^^^^^^ this attribute... @@ -53,7 +41,7 @@ LL | #[doc(no_inline)] = help: remove one of the conflicting attributes error: this attribute can only be applied to an `extern crate` item - --> $DIR/invalid-doc-attr.rs:36:7 + --> $DIR/invalid-doc-attr.rs:32:7 | LL | #[doc(masked)] | ^^^^^^ only applicable on `extern crate` items @@ -64,7 +52,7 @@ LL | pub struct Masked; = note: read for more information error: this attribute cannot be applied to an `extern crate self` item - --> $DIR/invalid-doc-attr.rs:40:7 + --> $DIR/invalid-doc-attr.rs:36:7 | LL | #[doc(masked)] | ^^^^^^ not applicable on `extern crate self` items @@ -81,7 +69,7 @@ LL | #![doc(masked)] = note: read for more information error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:23:11 + --> $DIR/invalid-doc-attr.rs:19:11 | LL | #[doc(test(no_crate_inject))] | ^^^^^^^^^^^^^^^^^^^^^ @@ -89,7 +77,7 @@ LL | #[doc(test(no_crate_inject))] = note: read for more information error: this attribute can only be applied to a `use` item - --> $DIR/invalid-doc-attr.rs:25:11 + --> $DIR/invalid-doc-attr.rs:21:11 | LL | #[doc(inline)] | ^^^^^^ only applicable on `use` items @@ -99,5 +87,5 @@ LL | pub fn baz() {} | = note: read for more information -error: aborting due to 10 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/lint/unused/useless-comment.rs b/tests/ui/lint/unused/useless-comment.rs index 4ec52f20747da..898665278e39c 100644 --- a/tests/ui/lint/unused/useless-comment.rs +++ b/tests/ui/lint/unused/useless-comment.rs @@ -9,8 +9,13 @@ macro_rules! mac { /// foo //~ ERROR unused doc comment mac!(); +/// a //~ ERROR unused doc comment +#[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment +unsafe extern "C" { } + fn foo() { /// a //~ ERROR unused doc comment + #[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment let x = 12; /// multi-line //~ ERROR unused doc comment @@ -19,6 +24,7 @@ fn foo() { match x { /// c //~ ERROR unused doc comment 1 => {}, + #[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment _ => {} } @@ -32,6 +38,7 @@ fn foo() { /// bar //~ ERROR unused doc comment mac!(); + #[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment let x = /** comment */ 47; //~ ERROR unused doc comment /// dox //~ ERROR unused doc comment diff --git a/tests/ui/lint/unused/useless-comment.stderr b/tests/ui/lint/unused/useless-comment.stderr index 8bb5bdaeb250f..39873b82b7575 100644 --- a/tests/ui/lint/unused/useless-comment.stderr +++ b/tests/ui/lint/unused/useless-comment.stderr @@ -12,7 +12,28 @@ LL | #![deny(unused_doc_comments)] | ^^^^^^^^^^^^^^^^^^^ error: unused doc comment - --> $DIR/useless-comment.rs:32:5 + --> $DIR/useless-comment.rs:12:1 + | +LL | /// a + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[doc(test(attr(allow(dead_code))))] +LL | unsafe extern "C" { } + | --------------------- rustdoc does not generate documentation for extern blocks + | + = help: use `//` for a plain comment + +error: unused doc comment + --> $DIR/useless-comment.rs:13:1 + | +LL | #[doc(test(attr(allow(dead_code))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unsafe extern "C" { } + | --------------------- rustdoc does not generate documentation for extern blocks + | + = help: use `//` for a plain comment + +error: unused doc comment + --> $DIR/useless-comment.rs:38:5 | LL | /// bar | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ rustdoc does not generate documentation for macro invocations @@ -20,17 +41,28 @@ LL | /// bar = help: to document an item produced by a macro, the macro must produce the documentation as part of its expansion error: unused doc comment - --> $DIR/useless-comment.rs:13:5 + --> $DIR/useless-comment.rs:17:5 | LL | /// a | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[doc(test(attr(allow(dead_code))))] LL | let x = 12; | ----------- rustdoc does not generate documentation for statements | = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:16:5 + --> $DIR/useless-comment.rs:18:5 + | +LL | #[doc(test(attr(allow(dead_code))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let x = 12; + | ----------- rustdoc does not generate documentation for statements + | + = help: use `//` for a plain comment + +error: unused doc comment + --> $DIR/useless-comment.rs:21:5 | LL | / /// multi-line LL | | /// doc comment @@ -39,6 +71,7 @@ LL | | /// that is unused LL | / match x { LL | | /// c LL | | 1 => {}, +LL | | #[doc(test(attr(allow(dead_code))))] LL | | _ => {} LL | | } | |_____- rustdoc does not generate documentation for expressions @@ -46,7 +79,7 @@ LL | | } = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:20:9 + --> $DIR/useless-comment.rs:25:9 | LL | /// c | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,7 +89,17 @@ LL | 1 => {}, = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:25:5 + --> $DIR/useless-comment.rs:27:9 + | +LL | #[doc(test(attr(allow(dead_code))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | _ => {} + | ------- rustdoc does not generate documentation for match arms + | + = help: use `//` for a plain comment + +error: unused doc comment + --> $DIR/useless-comment.rs:31:5 | LL | /// foo | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -66,7 +109,7 @@ LL | unsafe {} = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:28:5 + --> $DIR/useless-comment.rs:34:5 | LL | #[doc = "foo"] | ^^^^^^^^^^^^^^ @@ -77,7 +120,7 @@ LL | 3; = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:29:5 + --> $DIR/useless-comment.rs:35:5 | LL | #[doc = "bar"] | ^^^^^^^^^^^^^^ @@ -87,7 +130,17 @@ LL | 3; = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:35:13 + --> $DIR/useless-comment.rs:41:5 + | +LL | #[doc(test(attr(allow(dead_code))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let x = /** comment */ 47; + | -------------------------- rustdoc does not generate documentation for statements + | + = help: use `//` for a plain comment + +error: unused doc comment + --> $DIR/useless-comment.rs:42:13 | LL | let x = /** comment */ 47; | ^^^^^^^^^^^^^^ -- rustdoc does not generate documentation for expressions @@ -95,7 +148,7 @@ LL | let x = /** comment */ 47; = help: use `/* */` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:37:5 + --> $DIR/useless-comment.rs:44:5 | LL | /// dox | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -106,5 +159,5 @@ LL | | } | = help: use `//` for a plain comment -error: aborting due to 10 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui/rustdoc/doc-test-attr-pass.rs b/tests/ui/rustdoc/doc-test-attr-pass.rs index 40ffd5b25723a..60d1e3722bdff 100644 --- a/tests/ui/rustdoc/doc-test-attr-pass.rs +++ b/tests/ui/rustdoc/doc-test-attr-pass.rs @@ -10,4 +10,42 @@ mod test { #![doc(test(attr(allow(warnings))))] } +#[doc(test(attr(allow(dead_code))))] +static S: u32 = 5; + +#[doc(test(attr(allow(dead_code))))] +const C: u32 = 5; + +#[doc(test(attr(deny(dead_code))))] +struct A { + #[doc(test(attr(allow(dead_code))))] + field: u32 +} + +#[doc(test(attr(deny(dead_code))))] +union U { + #[doc(test(attr(allow(dead_code))))] + field: u32, + field2: u64, +} + +#[doc(test(attr(deny(dead_code))))] +enum Enum { + #[doc(test(attr(allow(dead_code))))] + Variant1, +} + +#[doc(test(attr(deny(dead_code))))] +impl A { + #[doc(test(attr(deny(dead_code))))] + fn method() {} +} + +#[doc(test(attr(deny(dead_code))))] +trait MyTrait { + #[doc(test(attr(deny(dead_code))))] + fn my_trait_fn(); +} + +#[doc(test(attr(deny(dead_code))))] pub fn foo() {} From d96d3bed6fc14fa03b077b1b7acf493815a6ef31 Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 5 May 2025 23:07:29 +0200 Subject: [PATCH 2634/4206] Collect and use `#[doc(test(attr(..)))]` at every level --- src/librustdoc/doctest/rust.rs | 57 +++---- tests/rustdoc-ui/doctest/dead-code-items.rs | 116 ++++++++++++++ .../rustdoc-ui/doctest/dead-code-items.stdout | 146 ++++++++++++++++++ 3 files changed, 285 insertions(+), 34 deletions(-) create mode 100644 tests/rustdoc-ui/doctest/dead-code-items.rs create mode 100644 tests/rustdoc-ui/doctest/dead-code-items.stdout diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index 4e9b1ee36f3db..96975105ac507 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -127,6 +127,26 @@ impl HirCollector<'_> { return; } + // Try collecting `#[doc(test(attr(...)))]` + let old_global_crate_attrs_len = self.collector.global_crate_attrs.len(); + for doc_test_attrs in ast_attrs + .iter() + .filter(|a| a.has_name(sym::doc)) + .flat_map(|a| a.meta_item_list().unwrap_or_default()) + .filter(|a| a.has_name(sym::test)) + { + let Some(doc_test_attrs) = doc_test_attrs.meta_item_list() else { continue }; + for attr in doc_test_attrs + .iter() + .filter(|a| a.has_name(sym::attr)) + .flat_map(|a| a.meta_item_list().unwrap_or_default()) + .map(|i| pprust::meta_list_item_to_string(i)) + { + // Add the additional attributes to the global_crate_attrs vector + self.collector.global_crate_attrs.push(attr); + } + } + let mut has_name = false; if let Some(name) = name { self.collector.cur_path.push(name); @@ -161,6 +181,9 @@ impl HirCollector<'_> { nested(self); + // Restore global_crate_attrs to it's previous size/content + self.collector.global_crate_attrs.truncate(old_global_crate_attrs_len); + if has_name { self.collector.cur_path.pop(); } @@ -174,40 +197,6 @@ impl<'tcx> intravisit::Visitor<'tcx> for HirCollector<'tcx> { self.tcx } - fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, _s: Span, hir_id: hir::HirId) { - let attrs = self.tcx.hir_attrs(hir_id); - - if !attrs.is_empty() { - // Try collecting `#![doc(test(attr(...)))]` from the attribute module - let old_len = self.collector.global_crate_attrs.len(); - for doc_test_attrs in attrs - .iter() - .filter(|a| a.has_name(sym::doc)) - .flat_map(|a| a.meta_item_list().unwrap_or_default()) - .filter(|a| a.has_name(sym::test)) - { - let Some(doc_test_attrs) = doc_test_attrs.meta_item_list() else { continue }; - for attr in doc_test_attrs - .iter() - .filter(|a| a.has_name(sym::attr)) - .flat_map(|a| a.meta_item_list().unwrap_or_default()) - .map(|i| pprust::meta_list_item_to_string(i)) - { - // Add the additional attributes to the global_crate_attrs vector - self.collector.global_crate_attrs.push(attr); - } - } - - let r = intravisit::walk_mod(self, m); - - // Restore global_crate_attrs to it's previous size/content - self.collector.global_crate_attrs.truncate(old_len); - r - } else { - intravisit::walk_mod(self, m) - } - } - fn visit_item(&mut self, item: &'tcx hir::Item<'_>) { let name = match &item.kind { hir::ItemKind::Impl(impl_) => { diff --git a/tests/rustdoc-ui/doctest/dead-code-items.rs b/tests/rustdoc-ui/doctest/dead-code-items.rs new file mode 100644 index 0000000000000..015504cbcedbc --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code-items.rs @@ -0,0 +1,116 @@ +// Same test as dead-code-module but with 2 doc(test(attr())) at different levels. + +//@ edition: 2024 +//@ compile-flags:--test --test-args=--test-threads=1 +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ failure-status: 101 + +#![doc(test(attr(deny(warnings))))] + +#[doc(test(attr(allow(dead_code))))] +/// Example +/// +/// ```rust,no_run +/// trait OnlyWarning { fn no_deny_warnings(); } +/// ``` +static S: u32 = 5; + +#[doc(test(attr(allow(dead_code))))] +/// Example +/// +/// ```rust,no_run +/// let unused_error = 5; +/// +/// fn dead_code_but_no_error() {} +/// ``` +const C: u32 = 5; + +#[doc(test(attr(allow(dead_code))))] +/// Example +/// +/// ```rust,no_run +/// trait OnlyWarningAtA { fn no_deny_warnings(); } +/// ``` +struct A { + #[doc(test(attr(deny(dead_code))))] + /// Example + /// + /// ```rust,no_run + /// trait DeadCodeInField {} + /// ``` + field: u32 +} + +#[doc(test(attr(allow(dead_code))))] +/// Example +/// +/// ```rust,no_run +/// trait OnlyWarningAtU { fn no_deny_warnings(); } +/// ``` +union U { + #[doc(test(attr(deny(dead_code))))] + /// Example + /// + /// ```rust,no_run + /// trait DeadCodeInUnionField {} + /// ``` + field: u32, + /// Example + /// + /// ```rust,no_run + /// trait NotDeadCodeInUnionField {} + /// ``` + field2: u64, +} + +#[doc(test(attr(deny(dead_code))))] +/// Example +/// +/// ```rust,no_run +/// let not_dead_code_but_unused = 5; +/// ``` +enum Enum { + #[doc(test(attr(allow(dead_code))))] + /// Example + /// + /// ```rust,no_run + /// trait NotDeadCodeInVariant {} + /// + /// fn main() { let unused_in_variant = 5; } + /// ``` + Variant1, +} + +#[doc(test(attr(allow(dead_code))))] +/// Example +/// +/// ```rust,no_run +/// trait OnlyWarningAtImplA { fn no_deny_warnings(); } +/// ``` +impl A { + /// Example + /// + /// ```rust,no_run + /// trait NotDeadCodeInImplMethod {} + /// ``` + fn method() {} +} + +#[doc(test(attr(deny(dead_code))))] +/// Example +/// +/// ```rust,no_run +/// trait StillDeadCodeAtMyTrait { } +/// ``` +trait MyTrait { + #[doc(test(attr(allow(dead_code))))] + /// Example + /// + /// ```rust,no_run + /// trait NotDeadCodeAtImplFn {} + /// + /// fn main() { let unused_in_impl = 5; } + /// ``` + fn my_trait_fn(); +} diff --git a/tests/rustdoc-ui/doctest/dead-code-items.stdout b/tests/rustdoc-ui/doctest/dead-code-items.stdout new file mode 100644 index 0000000000000..4b9d8be94dd3c --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code-items.stdout @@ -0,0 +1,146 @@ + +running 13 tests +test $DIR/dead-code-items.rs - A (line 32) - compile ... ok +test $DIR/dead-code-items.rs - A (line 88) - compile ... ok +test $DIR/dead-code-items.rs - A::field (line 39) - compile ... FAILED +test $DIR/dead-code-items.rs - A::method (line 94) - compile ... ok +test $DIR/dead-code-items.rs - C (line 22) - compile ... FAILED +test $DIR/dead-code-items.rs - Enum (line 70) - compile ... FAILED +test $DIR/dead-code-items.rs - Enum::Variant1 (line 77) - compile ... FAILED +test $DIR/dead-code-items.rs - MyTrait (line 103) - compile ... FAILED +test $DIR/dead-code-items.rs - MyTrait::my_trait_fn (line 110) - compile ... FAILED +test $DIR/dead-code-items.rs - S (line 14) - compile ... ok +test $DIR/dead-code-items.rs - U (line 48) - compile ... ok +test $DIR/dead-code-items.rs - U::field (line 55) - compile ... FAILED +test $DIR/dead-code-items.rs - U::field2 (line 61) - compile ... ok + +failures: + +---- $DIR/dead-code-items.rs - A::field (line 39) stdout ---- +error: trait `DeadCodeInField` is never used + --> $DIR/dead-code-items.rs:40:7 + | +LL | trait DeadCodeInField {} + | ^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/dead-code-items.rs:38:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: aborting due to 1 previous error + +Couldn't compile the test. +---- $DIR/dead-code-items.rs - C (line 22) stdout ---- +error: unused variable: `unused_error` + --> $DIR/dead-code-items.rs:23:5 + | +LL | let unused_error = 5; + | ^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused_error` + | +note: the lint level is defined here + --> $DIR/dead-code-items.rs:20:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. +---- $DIR/dead-code-items.rs - Enum (line 70) stdout ---- +error: unused variable: `not_dead_code_but_unused` + --> $DIR/dead-code-items.rs:71:5 + | +LL | let not_dead_code_but_unused = 5; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_not_dead_code_but_unused` + | +note: the lint level is defined here + --> $DIR/dead-code-items.rs:68:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. +---- $DIR/dead-code-items.rs - Enum::Variant1 (line 77) stdout ---- +error: unused variable: `unused_in_variant` + --> $DIR/dead-code-items.rs:80:17 + | +LL | fn main() { let unused_in_variant = 5; } + | ^^^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused_in_variant` + | +note: the lint level is defined here + --> $DIR/dead-code-items.rs:75:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. +---- $DIR/dead-code-items.rs - MyTrait (line 103) stdout ---- +error: trait `StillDeadCodeAtMyTrait` is never used + --> $DIR/dead-code-items.rs:104:7 + | +LL | trait StillDeadCodeAtMyTrait { } + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/dead-code-items.rs:102:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: aborting due to 1 previous error + +Couldn't compile the test. +---- $DIR/dead-code-items.rs - MyTrait::my_trait_fn (line 110) stdout ---- +error: unused variable: `unused_in_impl` + --> $DIR/dead-code-items.rs:113:17 + | +LL | fn main() { let unused_in_impl = 5; } + | ^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused_in_impl` + | +note: the lint level is defined here + --> $DIR/dead-code-items.rs:108:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. +---- $DIR/dead-code-items.rs - U::field (line 55) stdout ---- +error: trait `DeadCodeInUnionField` is never used + --> $DIR/dead-code-items.rs:56:7 + | +LL | trait DeadCodeInUnionField {} + | ^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/dead-code-items.rs:54:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: aborting due to 1 previous error + +Couldn't compile the test. + +failures: + $DIR/dead-code-items.rs - A::field (line 39) + $DIR/dead-code-items.rs - C (line 22) + $DIR/dead-code-items.rs - Enum (line 70) + $DIR/dead-code-items.rs - Enum::Variant1 (line 77) + $DIR/dead-code-items.rs - MyTrait (line 103) + $DIR/dead-code-items.rs - MyTrait::my_trait_fn (line 110) + $DIR/dead-code-items.rs - U::field (line 55) + +test result: FAILED. 6 passed; 7 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + From 17b92136e180cbb894aed9bdafb21f05c3e469a3 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Thu, 22 May 2025 11:59:14 -0700 Subject: [PATCH 2635/4206] Implement file cloning on Windows --- .../miri/src/shims/windows/foreign_items.rs | 22 ++++++ src/tools/miri/src/shims/windows/handle.rs | 74 +++++++++++++++++++ src/tools/miri/tests/pass/shims/fs.rs | 2 +- 3 files changed, 97 insertions(+), 1 deletion(-) diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index d822dd07fcd7b..98099e07b2eac 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -572,6 +572,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let ret = this.WaitForSingleObject(handle, timeout)?; this.write_scalar(ret, dest)?; } + "GetCurrentProcess" => { + let [] = this.check_shim(abi, sys_conv, link_name, args)?; + + this.write_scalar( + Handle::Pseudo(PseudoHandle::CurrentProcess).to_scalar(this), + dest, + )?; + } "GetCurrentThread" => { let [] = this.check_shim(abi, sys_conv, link_name, args)?; @@ -693,6 +701,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let res = this.GetStdHandle(which)?; this.write_scalar(res, dest)?; } + "DuplicateHandle" => { + let [src_proc, src_handle, target_proc, target_handle, access, inherit, options] = + this.check_shim(abi, sys_conv, link_name, args)?; + let res = this.DuplicateHandle( + src_proc, + src_handle, + target_proc, + target_handle, + access, + inherit, + options, + )?; + this.write_scalar(res, dest)?; + } "CloseHandle" => { let [handle] = this.check_shim(abi, sys_conv, link_name, args)?; diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs index 5c04271fac590..1e30bf25ed92e 100644 --- a/src/tools/miri/src/shims/windows/handle.rs +++ b/src/tools/miri/src/shims/windows/handle.rs @@ -9,6 +9,7 @@ use crate::*; #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum PseudoHandle { CurrentThread, + CurrentProcess, } /// Miri representation of a Windows `HANDLE` @@ -23,16 +24,19 @@ pub enum Handle { impl PseudoHandle { const CURRENT_THREAD_VALUE: u32 = 0; + const CURRENT_PROCESS_VALUE: u32 = 1; fn value(self) -> u32 { match self { Self::CurrentThread => Self::CURRENT_THREAD_VALUE, + Self::CurrentProcess => Self::CURRENT_PROCESS_VALUE, } } fn from_value(value: u32) -> Option { match value { Self::CURRENT_THREAD_VALUE => Some(Self::CurrentThread), + Self::CURRENT_PROCESS_VALUE => Some(Self::CurrentProcess), _ => None, } } @@ -244,6 +248,76 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(handle.to_scalar(this)) } + fn DuplicateHandle( + &mut self, + src_proc: &OpTy<'tcx>, // HANDLE + src_handle: &OpTy<'tcx>, // HANDLE + target_proc: &OpTy<'tcx>, // HANDLE + target_handle: &OpTy<'tcx>, // LPHANDLE + desired_access: &OpTy<'tcx>, // DWORD + inherit: &OpTy<'tcx>, // BOOL + options: &OpTy<'tcx>, // DWORD + ) -> InterpResult<'tcx, Scalar> { + // ^ Returns BOOL (i32 on Windows) + let this = self.eval_context_mut(); + + let src_proc = this.read_handle(src_proc, "DuplicateHandle")?; + let src_handle = this.read_handle(src_handle, "DuplicateHandle")?; + let target_proc = this.read_handle(target_proc, "DuplicateHandle")?; + let target_handle_ptr = this.read_pointer(target_handle)?; + // Since we only support DUPLICATE_SAME_ACCESS, this value is ignored, but should be valid + let _ = this.read_scalar(desired_access)?.to_u32()?; + // We don't support the CreateProcess API, so inheritable or not means nothing. + // If we ever add CreateProcess support, this will need to be implemented. + let _ = this.read_scalar(inherit)?; + let options = this.read_scalar(options)?; + + if src_proc != Handle::Pseudo(PseudoHandle::CurrentProcess) { + throw_unsup_format!( + "`DuplicateHandle` `hSourceProcessHandle` parameter is not the current process, which is unsupported" + ); + } + + if target_proc != Handle::Pseudo(PseudoHandle::CurrentProcess) { + throw_unsup_format!( + "`DuplicateHandle` `hSourceProcessHandle` parameter is not the current process, which is unsupported" + ); + } + + if this.ptr_is_null(target_handle_ptr)? { + throw_unsup_format!( + "`DuplicateHandle` `lpTargetHandle` parameter is null, which is unsupported" + ); + } + + if options != this.eval_windows("c", "DUPLICATE_SAME_ACCESS") { + throw_unsup_format!( + "`DuplicateHandle` `dwOptions` parameter is not `DUPLICATE_SAME_ACCESS`, which is unsupported" + ); + } + + let new_handle = match src_handle { + Handle::File(old_fd_num) => { + let Some(fd) = this.machine.fds.get(old_fd_num) else { + this.invalid_handle("DuplicateHandle")? + }; + Handle::File(this.machine.fds.insert(fd)) + } + Handle::Thread(_) => { + throw_unsup_format!( + "`DuplicateHandle` called on a thread handle, which is unsupported" + ); + } + Handle::Pseudo(pseudo) => Handle::Pseudo(pseudo), + Handle::Null | Handle::Invalid => this.invalid_handle("DuplicateHandle")?, + }; + + let target_place = this.deref_pointer_as(target_handle, this.machine.layouts.usize)?; + this.write_scalar(new_handle.to_scalar(this), &target_place)?; + + interp_ok(this.eval_windows("c", "TRUE")) + } + fn CloseHandle(&mut self, handle_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs index 315637ff7ec73..87df43ca7e57f 100644 --- a/src/tools/miri/tests/pass/shims/fs.rs +++ b/src/tools/miri/tests/pass/shims/fs.rs @@ -23,9 +23,9 @@ fn main() { test_seek(); test_errors(); test_from_raw_os_error(); + test_file_clone(); // Windows file handling is very incomplete. if cfg!(not(windows)) { - test_file_clone(); test_file_set_len(); test_file_sync(); test_rename(); From 6a9e189f53f8ad77d0cdb4a87ce02a13b89303a2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 22 May 2025 20:15:22 +0200 Subject: [PATCH 2636/4206] interpret: do not force_allocate all return places --- .../src/const_eval/dummy_machine.rs | 4 +- .../src/const_eval/eval_queries.rs | 7 ++- .../src/const_eval/machine.rs | 8 +-- .../rustc_const_eval/src/interpret/call.rs | 52 +++++++--------- .../src/interpret/intrinsics.rs | 22 +++---- .../rustc_const_eval/src/interpret/machine.rs | 16 +++-- .../rustc_const_eval/src/interpret/stack.rs | 62 +++++++++---------- .../rustc_const_eval/src/interpret/step.rs | 2 +- src/tools/miri/src/concurrency/thread.rs | 17 ++--- src/tools/miri/src/eval.rs | 19 +++--- src/tools/miri/src/helpers.rs | 2 +- src/tools/miri/src/intrinsics/mod.rs | 7 ++- src/tools/miri/src/machine.rs | 29 +++++---- src/tools/miri/src/shims/foreign_items.rs | 9 ++- .../tests/fail/data_race/stack_pop_race.rs | 5 +- .../fail/data_race/stack_pop_race.stderr | 11 +--- .../fail/tail_calls/dangling-local-var.stderr | 4 +- .../miri/tests/pass/alloc-access-tracking.rs | 4 +- 18 files changed, 138 insertions(+), 142 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs index 46dcebc46e9c8..8492e01629be8 100644 --- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs @@ -90,7 +90,7 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine { _instance: ty::Instance<'tcx>, _abi: &FnAbi<'tcx, Ty<'tcx>>, _args: &[interpret::FnArg<'tcx, Self::Provenance>], - _destination: &interpret::MPlaceTy<'tcx, Self::Provenance>, + _destination: &interpret::PlaceTy<'tcx, Self::Provenance>, _target: Option, _unwind: UnwindAction, ) -> interpret::InterpResult<'tcx, Option<(&'tcx Body<'tcx>, ty::Instance<'tcx>)>> { @@ -108,7 +108,7 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine { _ecx: &mut InterpCx<'tcx, Self>, _instance: ty::Instance<'tcx>, _args: &[interpret::OpTy<'tcx, Self::Provenance>], - _destination: &interpret::MPlaceTy<'tcx, Self::Provenance>, + _destination: &interpret::PlaceTy<'tcx, Self::Provenance>, _target: Option, _unwind: UnwindAction, ) -> interpret::InterpResult<'tcx, Option>> { diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index ce8eceebdf8d2..a79ba6a634272 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -71,7 +71,12 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( // This can't use `init_stack_frame` since `body` is not a function, // so computing its ABI would fail. It's also not worth it since there are no arguments to pass. - ecx.push_stack_frame_raw(cid.instance, body, &ret, StackPopCleanup::Root { cleanup: false })?; + ecx.push_stack_frame_raw( + cid.instance, + body, + &ret.clone().into(), + StackPopCleanup::Root { cleanup: false }, + )?; ecx.storage_live_for_always_live_locals()?; // The main interpreter loop. diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 7c7daed525b2d..9fe7a2336c32b 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -22,7 +22,7 @@ use crate::errors::{LongRunning, LongRunningWarn}; use crate::fluent_generated as fluent; use crate::interpret::{ self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, - GlobalAlloc, ImmTy, InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, RangeSet, Scalar, + GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, RangeSet, Scalar, compile_time_machine, interp_ok, throw_exhaust, throw_inval, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format, }; @@ -226,7 +226,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { &mut self, instance: ty::Instance<'tcx>, args: &[FnArg<'tcx>], - _dest: &MPlaceTy<'tcx>, + _dest: &PlaceTy<'tcx>, _ret: Option, ) -> InterpResult<'tcx, Option>> { let def_id = instance.def_id(); @@ -343,7 +343,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { orig_instance: ty::Instance<'tcx>, _abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[FnArg<'tcx>], - dest: &MPlaceTy<'tcx>, + dest: &PlaceTy<'tcx>, ret: Option, _unwind: mir::UnwindAction, // unwinding is not supported in consts ) -> InterpResult<'tcx, Option<(&'tcx mir::Body<'tcx>, ty::Instance<'tcx>)>> { @@ -385,7 +385,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { ecx: &mut InterpCx<'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], - dest: &MPlaceTy<'tcx, Self::Provenance>, + dest: &PlaceTy<'tcx, Self::Provenance>, target: Option, _unwind: mir::UnwindAction, ) -> InterpResult<'tcx, Option>> { diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 405208e94f4b8..789baea073463 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -339,7 +339,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { caller_fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[FnArg<'tcx, M::Provenance>], with_caller_location: bool, - destination: &MPlaceTy<'tcx, M::Provenance>, + destination: &PlaceTy<'tcx, M::Provenance>, mut stack_pop: StackPopCleanup, ) -> InterpResult<'tcx> { // Compute callee information. @@ -487,7 +487,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } // Protect return place for in-place return value passing. - M::protect_in_place_function_argument(self, &destination)?; + // We only need to protect anything if this is actually an in-memory place. + if let Left(mplace) = destination.as_mplace_or_local() { + M::protect_in_place_function_argument(self, &mplace)?; + } // Don't forget to mark "initially live" locals as live. self.storage_live_for_always_live_locals()?; @@ -512,7 +515,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { (caller_abi, caller_fn_abi): (ExternAbi, &FnAbi<'tcx, Ty<'tcx>>), args: &[FnArg<'tcx, M::Provenance>], with_caller_location: bool, - destination: &MPlaceTy<'tcx, M::Provenance>, + destination: &PlaceTy<'tcx, M::Provenance>, target: Option, unwind: mir::UnwindAction, ) -> InterpResult<'tcx> { @@ -776,10 +779,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Note that we are using `pop_stack_frame_raw` and not `return_from_current_stack_frame`, // as the latter "executes" the goto to the return block, but we don't want to, // only the tail called function should return to the current return block. - M::before_stack_pop(self, self.frame())?; - - let StackPopInfo { return_action, return_to_block, return_place } = - self.pop_stack_frame_raw(false)?; + let StackPopInfo { return_action, return_to_block, return_place } = self + .pop_stack_frame_raw(false, |_this, _return_place| { + // This function's return value is just discarded, the tail-callee will fill in the return place instead. + interp_ok(()) + })?; assert_eq!(return_action, ReturnAction::Normal); @@ -850,7 +854,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { (ExternAbi::Rust, fn_abi), &[FnArg::Copy(arg.into())], false, - &ret, + &ret.into(), Some(target), unwind, ) @@ -891,28 +895,16 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { throw_ub_custom!(fluent::const_eval_unwind_past_top); } - M::before_stack_pop(self, self.frame())?; - - // Copy return value. Must of course happen *before* we deallocate the locals. - // Must be *after* `before_stack_pop` as otherwise the return place might still be protected. - let copy_ret_result = if !unwinding { - let op = self - .local_to_op(mir::RETURN_PLACE, None) - .expect("return place should always be live"); - let dest = self.frame().return_place.clone(); - let res = self.copy_op_allow_transmute(&op, &dest); - trace!("return value: {:?}", self.dump_place(&dest.into())); - // We delay actually short-circuiting on this error until *after* the stack frame is - // popped, since we want this error to be attributed to the caller, whose type defines - // this transmute. - res - } else { + // Get out the return value. Must happen *before* the frame is popped as we have to get the + // local's value out. + let return_op = + self.local_to_op(mir::RETURN_PLACE, None).expect("return place should always be live"); + // Do the actual pop + copy. + let stack_pop_info = self.pop_stack_frame_raw(unwinding, |this, return_place| { + this.copy_op_allow_transmute(&return_op, return_place)?; + trace!("return value: {:?}", this.dump_place(return_place)); interp_ok(()) - }; - - // All right, now it is time to actually pop the frame. - // An error here takes precedence over the copy error. - let (stack_pop_info, ()) = self.pop_stack_frame_raw(unwinding).and(copy_ret_result)?; + })?; match stack_pop_info.return_action { ReturnAction::Normal => {} @@ -924,7 +916,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // If we are not doing cleanup, also skip everything else. assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked"); assert!(!unwinding, "tried to skip cleanup during unwinding"); - // Skip machine hook. + // Don't jump anywhere. return interp_ok(()); } } diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 090b2a692cfc3..ee670b6245f09 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -17,9 +17,9 @@ use tracing::trace; use super::memory::MemoryKind; use super::util::ensure_monomorphic_enough; use super::{ - Allocation, CheckInAllocMsg, ConstAllocation, GlobalId, ImmTy, InterpCx, InterpResult, - MPlaceTy, Machine, OpTy, Pointer, PointerArithmetic, Provenance, Scalar, err_inval, - err_ub_custom, err_unsup_format, interp_ok, throw_inval, throw_ub_custom, throw_ub_format, + Allocation, CheckInAllocMsg, ConstAllocation, GlobalId, ImmTy, InterpCx, InterpResult, Machine, + OpTy, PlaceTy, Pointer, PointerArithmetic, Provenance, Scalar, err_inval, err_ub_custom, + err_unsup_format, interp_ok, throw_inval, throw_ub_custom, throw_ub_format, }; use crate::fluent_generated as fluent; @@ -112,7 +112,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { &mut self, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, M::Provenance>], - dest: &MPlaceTy<'tcx, M::Provenance>, + dest: &PlaceTy<'tcx, M::Provenance>, ret: Option, ) -> InterpResult<'tcx, bool> { let instance_args = instance.args; @@ -587,7 +587,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { &mut self, a: &ImmTy<'tcx, M::Provenance>, b: &ImmTy<'tcx, M::Provenance>, - dest: &MPlaceTy<'tcx, M::Provenance>, + dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { assert_eq!(a.layout.ty, b.layout.ty); assert_matches!(a.layout.ty.kind(), ty::Int(..) | ty::Uint(..)); @@ -801,7 +801,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { fn float_min_intrinsic( &mut self, args: &[OpTy<'tcx, M::Provenance>], - dest: &MPlaceTy<'tcx, M::Provenance>, + dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, ()> where F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, @@ -822,7 +822,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { fn float_max_intrinsic( &mut self, args: &[OpTy<'tcx, M::Provenance>], - dest: &MPlaceTy<'tcx, M::Provenance>, + dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, ()> where F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, @@ -843,7 +843,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { fn float_minimum_intrinsic( &mut self, args: &[OpTy<'tcx, M::Provenance>], - dest: &MPlaceTy<'tcx, M::Provenance>, + dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, ()> where F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, @@ -859,7 +859,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { fn float_maximum_intrinsic( &mut self, args: &[OpTy<'tcx, M::Provenance>], - dest: &MPlaceTy<'tcx, M::Provenance>, + dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, ()> where F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, @@ -875,7 +875,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { fn float_copysign_intrinsic( &mut self, args: &[OpTy<'tcx, M::Provenance>], - dest: &MPlaceTy<'tcx, M::Provenance>, + dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, ()> where F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, @@ -890,7 +890,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { fn float_abs_intrinsic( &mut self, args: &[OpTy<'tcx, M::Provenance>], - dest: &MPlaceTy<'tcx, M::Provenance>, + dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, ()> where F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index d13e17a481a46..b65d9444caf01 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -208,7 +208,7 @@ pub trait Machine<'tcx>: Sized { instance: ty::Instance<'tcx>, abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[FnArg<'tcx, Self::Provenance>], - destination: &MPlaceTy<'tcx, Self::Provenance>, + destination: &PlaceTy<'tcx, Self::Provenance>, target: Option, unwind: mir::UnwindAction, ) -> InterpResult<'tcx, Option<(&'tcx mir::Body<'tcx>, ty::Instance<'tcx>)>>; @@ -220,7 +220,7 @@ pub trait Machine<'tcx>: Sized { fn_val: Self::ExtraFnVal, abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[FnArg<'tcx, Self::Provenance>], - destination: &MPlaceTy<'tcx, Self::Provenance>, + destination: &PlaceTy<'tcx, Self::Provenance>, target: Option, unwind: mir::UnwindAction, ) -> InterpResult<'tcx>; @@ -234,7 +234,7 @@ pub trait Machine<'tcx>: Sized { ecx: &mut InterpCx<'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Self::Provenance>], - destination: &MPlaceTy<'tcx, Self::Provenance>, + destination: &PlaceTy<'tcx, Self::Provenance>, target: Option, unwind: mir::UnwindAction, ) -> InterpResult<'tcx, Option>>; @@ -536,11 +536,9 @@ pub trait Machine<'tcx>: Sized { interp_ok(()) } - /// Called just before the return value is copied to the caller-provided return place. - fn before_stack_pop( - _ecx: &InterpCx<'tcx, Self>, - _frame: &Frame<'tcx, Self::Provenance, Self::FrameExtra>, - ) -> InterpResult<'tcx> { + /// Called just before the frame is removed from the stack (followed by return value copy and + /// local cleanup). + fn before_stack_pop(_ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> { interp_ok(()) } @@ -675,7 +673,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { fn_val: !, _abi: &FnAbi<$tcx, Ty<$tcx>>, _args: &[FnArg<$tcx>], - _destination: &MPlaceTy<$tcx, Self::Provenance>, + _destination: &PlaceTy<$tcx, Self::Provenance>, _target: Option, _unwind: mir::UnwindAction, ) -> InterpResult<$tcx> { diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs index d7b03776bc481..2a2d1bb27547e 100644 --- a/compiler/rustc_const_eval/src/interpret/stack.rs +++ b/compiler/rustc_const_eval/src/interpret/stack.rs @@ -15,9 +15,9 @@ use rustc_span::Span; use tracing::{info_span, instrument, trace}; use super::{ - AllocId, CtfeProvenance, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, - MemPlaceMeta, MemoryKind, Operand, Pointer, Provenance, ReturnAction, Scalar, - from_known_layout, interp_ok, throw_ub, throw_unsup, + AllocId, CtfeProvenance, Immediate, InterpCx, InterpResult, Machine, MemPlace, MemPlaceMeta, + MemoryKind, Operand, PlaceTy, Pointer, Provenance, ReturnAction, Scalar, from_known_layout, + interp_ok, throw_ub, throw_unsup, }; use crate::errors; @@ -76,8 +76,10 @@ pub struct Frame<'tcx, Prov: Provenance = CtfeProvenance, Extra = ()> { return_to_block: StackPopCleanup, /// The location where the result of the current stack frame should be written to, - /// and its layout in the caller. - pub return_place: MPlaceTy<'tcx, Prov>, + /// and its layout in the caller. This place is to be interpreted relative to the + /// *caller's* stack frame. We use a `PlaceTy` instead of an `MPlaceTy` since this + /// avoids having to move *all* return places into Miri's memory. + pub return_place: PlaceTy<'tcx, Prov>, /// The list of locals for this stack frame, stored in order as /// `[return_ptr, arguments..., variables..., temporaries...]`. @@ -129,7 +131,7 @@ pub struct StackPopInfo<'tcx, Prov: Provenance> { pub return_to_block: StackPopCleanup, /// [`return_place`](Frame::return_place) of the popped stack frame. - pub return_place: MPlaceTy<'tcx, Prov>, + pub return_place: PlaceTy<'tcx, Prov>, } /// State of a local variable including a memoized layout @@ -353,7 +355,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { &mut self, instance: ty::Instance<'tcx>, body: &'tcx mir::Body<'tcx>, - return_place: &MPlaceTy<'tcx, M::Provenance>, + return_place: &PlaceTy<'tcx, M::Provenance>, return_to_block: StackPopCleanup, ) -> InterpResult<'tcx> { trace!("body: {:#?}", body); @@ -404,9 +406,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// it. /// /// This also deallocates locals, if necessary. + /// `copy_ret_val` gets called after the frame has been taken from the stack but before the locals have been deallocated. /// - /// [`M::before_stack_pop`] should be called before calling this function. - /// [`M::after_stack_pop`] is called by this function automatically. + /// [`M::before_stack_pop`] and [`M::after_stack_pop`] are called by this function + /// automatically. /// /// The high-level version of this is `return_from_current_stack_frame`. /// @@ -415,47 +418,44 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { pub(super) fn pop_stack_frame_raw( &mut self, unwinding: bool, + copy_ret_val: impl FnOnce(&mut Self, &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx>, ) -> InterpResult<'tcx, StackPopInfo<'tcx, M::Provenance>> { - let cleanup = self.cleanup_current_frame_locals()?; - + M::before_stack_pop(self)?; let frame = self.stack_mut().pop().expect("tried to pop a stack frame, but there were none"); + // Copy return value (unless we are unwinding). + if !unwinding { + copy_ret_val(self, &frame.return_place)?; + } + let return_to_block = frame.return_to_block; let return_place = frame.return_place.clone(); - let return_action; - if cleanup { - return_action = M::after_stack_pop(self, frame, unwinding)?; - assert_ne!(return_action, ReturnAction::NoCleanup); - } else { - return_action = ReturnAction::NoCleanup; - }; - - interp_ok(StackPopInfo { return_action, return_to_block, return_place }) - } - - /// A private helper for [`pop_stack_frame_raw`](InterpCx::pop_stack_frame_raw). - /// Returns `true` if cleanup has been done, `false` otherwise. - fn cleanup_current_frame_locals(&mut self) -> InterpResult<'tcx, bool> { // Cleanup: deallocate locals. // Usually we want to clean up (deallocate locals), but in a few rare cases we don't. // We do this while the frame is still on the stack, so errors point to the callee. - let return_to_block = self.frame().return_to_block; let cleanup = match return_to_block { StackPopCleanup::Goto { .. } => true, StackPopCleanup::Root { cleanup, .. } => cleanup, }; - if cleanup { + let return_action = if cleanup { // We need to take the locals out, since we need to mutate while iterating. - let locals = mem::take(&mut self.frame_mut().locals); - for local in &locals { + for local in &frame.locals { self.deallocate_local(local.value)?; } - } - interp_ok(cleanup) + // Call the machine hook, which determines the next steps. + let return_action = M::after_stack_pop(self, frame, unwinding)?; + assert_ne!(return_action, ReturnAction::NoCleanup); + return_action + } else { + // We also skip the machine hook when there's no cleanup. This not a real "pop" anyway. + ReturnAction::NoCleanup + }; + + interp_ok(StackPopInfo { return_action, return_to_block, return_place }) } /// In the current stack frame, mark all locals as live that are not arguments and don't have diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 363ceee1970ee..975325b0c1e09 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -506,7 +506,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location } = self.eval_callee_and_args(terminator, func, args)?; - let destination = self.force_allocation(&self.eval_place(destination)?)?; + let destination = self.eval_place(destination)?; self.init_fn_call( callee, (fn_sig.abi, fn_abi), diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 8aa65e6cb612b..6b760034ee805 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -218,34 +218,37 @@ impl<'tcx> Thread<'tcx> { } } - /// Return the top user-relevant frame, if there is one. + /// Return the top user-relevant frame, if there is one. `skip` indicates how many top frames + /// should be skipped. /// Note that the choice to return `None` here when there is no user-relevant frame is part of /// justifying the optimization that only pushes of user-relevant frames require updating the /// `top_user_relevant_frame` field. - fn compute_top_user_relevant_frame(&self) -> Option { + fn compute_top_user_relevant_frame(&self, skip: usize) -> Option { self.stack .iter() .enumerate() .rev() + .skip(skip) .find_map(|(idx, frame)| if frame.extra.is_user_relevant { Some(idx) } else { None }) } - /// Re-compute the top user-relevant frame from scratch. - pub fn recompute_top_user_relevant_frame(&mut self) { - self.top_user_relevant_frame = self.compute_top_user_relevant_frame(); + /// Re-compute the top user-relevant frame from scratch. `skip` indicates how many top frames + /// should be skipped. + pub fn recompute_top_user_relevant_frame(&mut self, skip: usize) { + self.top_user_relevant_frame = self.compute_top_user_relevant_frame(skip); } /// Set the top user-relevant frame to the given value. Must be equal to what /// `get_top_user_relevant_frame` would return! pub fn set_top_user_relevant_frame(&mut self, frame_idx: usize) { - debug_assert_eq!(Some(frame_idx), self.compute_top_user_relevant_frame()); + debug_assert_eq!(Some(frame_idx), self.compute_top_user_relevant_frame(0)); self.top_user_relevant_frame = Some(frame_idx); } /// Returns the topmost frame that is considered user-relevant, or the /// top of the stack if there is no such frame, or `None` if the stack is empty. pub fn top_user_relevant_frame(&self) -> Option { - debug_assert_eq!(self.top_user_relevant_frame, self.compute_top_user_relevant_frame()); + debug_assert_eq!(self.top_user_relevant_frame, self.compute_top_user_relevant_frame(0)); // This can be called upon creation of an allocation. We create allocations while setting up // parts of the Rust runtime when we do not have any stack frames yet, so we need to handle // empty stacks. diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index a90c6ab9d40e9..8fe034d258297 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -354,11 +354,10 @@ pub fn create_ecx<'tcx>( argvs.push(arg_place.to_ref(&ecx)); } // Make an array with all these pointers, in the Miri memory. - let argvs_layout = ecx.layout_of(Ty::new_array( - tcx, - Ty::new_imm_ptr(tcx, tcx.types.u8), - u64::try_from(argvs.len()).unwrap(), - ))?; + let u8_ptr_type = Ty::new_imm_ptr(tcx, tcx.types.u8); + let u8_ptr_ptr_type = Ty::new_imm_ptr(tcx, u8_ptr_type); + let argvs_layout = + ecx.layout_of(Ty::new_array(tcx, u8_ptr_type, u64::try_from(argvs.len()).unwrap()))?; let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into())?; for (idx, arg) in argvs.into_iter().enumerate() { let place = ecx.project_field(&argvs_place, idx)?; @@ -373,10 +372,8 @@ pub fn create_ecx<'tcx>( ecx.mark_immutable(&argc_place); ecx.machine.argc = Some(argc_place.ptr()); - let argv_place = ecx.allocate( - ecx.layout_of(Ty::new_imm_ptr(tcx, tcx.types.unit))?, - MiriMemoryKind::Machine.into(), - )?; + let argv_place = + ecx.allocate(ecx.layout_of(u8_ptr_ptr_type)?, MiriMemoryKind::Machine.into())?; ecx.write_pointer(argvs_place.ptr(), &argv_place)?; ecx.mark_immutable(&argv_place); ecx.machine.argv = Some(argv_place.ptr()); @@ -398,7 +395,9 @@ pub fn create_ecx<'tcx>( } ecx.mark_immutable(&cmd_place); } - ecx.mplace_to_ref(&argvs_place)? + let imm = argvs_place.to_ref(&ecx); + let layout = ecx.layout_of(u8_ptr_ptr_type)?; + ImmTy::from_immediate(imm, layout) }; // Return place (in static memory so that it does not count as leak). diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 8e7c9edfcc078..935afcb6e9290 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -470,7 +470,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { caller_fn_abi, &args.iter().map(|a| FnArg::Copy(a.clone().into())).collect::>(), /*with_caller_location*/ false, - &dest, + &dest.into(), stack_pop, ) } diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 982fbc318110e..69baa472cd694 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -22,7 +22,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], - dest: &MPlaceTy<'tcx>, + dest: &PlaceTy<'tcx>, ret: Option, unwind: mir::UnwindAction, ) -> InterpResult<'tcx, Option>> { @@ -45,7 +45,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let intrinsic_name = this.tcx.item_name(instance.def_id()); let intrinsic_name = intrinsic_name.as_str(); - match this.emulate_intrinsic_by_name(intrinsic_name, instance.args, args, dest, ret)? { + // FIXME: avoid allocating memory + let dest = this.force_allocation(dest)?; + + match this.emulate_intrinsic_by_name(intrinsic_name, instance.args, args, &dest, ret)? { EmulateItemResult::NotSupported => { // We haven't handled the intrinsic, let's see if we can use a fallback body. if this.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden { diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 1c6c7894cb456..ac1f9f3822cd5 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1120,7 +1120,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { instance: ty::Instance<'tcx>, abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[FnArg<'tcx, Provenance>], - dest: &MPlaceTy<'tcx>, + dest: &PlaceTy<'tcx>, ret: Option, unwind: mir::UnwindAction, ) -> InterpResult<'tcx, Option<(&'tcx mir::Body<'tcx>, ty::Instance<'tcx>)>> { @@ -1147,7 +1147,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { fn_val: DynSym, abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[FnArg<'tcx, Provenance>], - dest: &MPlaceTy<'tcx>, + dest: &PlaceTy<'tcx>, ret: Option, unwind: mir::UnwindAction, ) -> InterpResult<'tcx> { @@ -1160,7 +1160,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { ecx: &mut MiriInterpCx<'tcx>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], - dest: &MPlaceTy<'tcx>, + dest: &PlaceTy<'tcx>, ret: Option, unwind: mir::UnwindAction, ) -> InterpResult<'tcx, Option>> { @@ -1639,15 +1639,21 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { interp_ok(()) } - fn before_stack_pop( - ecx: &InterpCx<'tcx, Self>, - frame: &Frame<'tcx, Self::Provenance, Self::FrameExtra>, - ) -> InterpResult<'tcx> { + fn before_stack_pop(ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> { + let frame = ecx.frame(); // We want this *before* the return value copy, because the return place itself is protected // until we do `end_call` here. if ecx.machine.borrow_tracker.is_some() { ecx.on_stack_pop(frame)?; } + if frame.extra.is_user_relevant { + // All that we store is whether or not the frame we just removed is local, so now we + // have no idea where the next topmost local frame is. So we recompute it. + // (If this ever becomes a bottleneck, we could have `push` store the previous + // user-relevant frame and restore that here.) + // We have to skip the frame that is just being popped. + ecx.active_thread_mut().recompute_top_user_relevant_frame(/* skip */ 1); + } // tracing-tree can autoamtically annotate scope changes, but it gets very confused by our // concurrency and what it prints is just plain wrong. So we print our own information // instead. (Cc https://github.com/rust-lang/miri/issues/2266) @@ -1661,15 +1667,8 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { frame: Frame<'tcx, Provenance, FrameExtra<'tcx>>, unwinding: bool, ) -> InterpResult<'tcx, ReturnAction> { - if frame.extra.is_user_relevant { - // All that we store is whether or not the frame we just removed is local, so now we - // have no idea where the next topmost local frame is. So we recompute it. - // (If this ever becomes a bottleneck, we could have `push` store the previous - // user-relevant frame and restore that here.) - ecx.active_thread_mut().recompute_top_user_relevant_frame(); - } let res = { - // Move `frame`` into a sub-scope so we control when it will be dropped. + // Move `frame` into a sub-scope so we control when it will be dropped. let mut frame = frame; let timing = frame.extra.timing.take(); let res = ecx.handle_stack_pop_unwind(frame.extra, unwinding); diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 52c16a0c2e2dc..1195b741b19eb 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -43,7 +43,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { link_name: Symbol, abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], - dest: &MPlaceTy<'tcx>, + dest: &PlaceTy<'tcx>, ret: Option, unwind: mir::UnwindAction, ) -> InterpResult<'tcx, Option<(&'tcx mir::Body<'tcx>, ty::Instance<'tcx>)>> { @@ -69,8 +69,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => {} } + // FIXME: avoid allocating memory + let dest = this.force_allocation(dest)?; + // The rest either implements the logic, or falls back to `lookup_exported_symbol`. - match this.emulate_foreign_item_inner(link_name, abi, args, dest)? { + match this.emulate_foreign_item_inner(link_name, abi, args, &dest)? { EmulateItemResult::NeedsReturn => { trace!("{:?}", this.dump_place(&dest.clone().into())); this.return_to_block(ret)?; @@ -111,7 +114,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { sym: DynSym, abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OpTy<'tcx>], - dest: &MPlaceTy<'tcx>, + dest: &PlaceTy<'tcx>, ret: Option, unwind: mir::UnwindAction, ) -> InterpResult<'tcx> { diff --git a/src/tools/miri/tests/fail/data_race/stack_pop_race.rs b/src/tools/miri/tests/fail/data_race/stack_pop_race.rs index 5138bcbf8f74d..e7632d43126ac 100644 --- a/src/tools/miri/tests/fail/data_race/stack_pop_race.rs +++ b/src/tools/miri/tests/fail/data_race/stack_pop_race.rs @@ -8,7 +8,7 @@ struct MakeSend(*const i32); unsafe impl Send for MakeSend {} fn main() { - race(0); + race(0); //~ERROR: Data race detected between (1) non-atomic read on thread `unnamed-1` and (2) deallocation on thread `main` } // Using an argument for the ptr to point to, since those do not get StorageDead. @@ -22,5 +22,4 @@ fn race(local: i32) { thread::yield_now(); // Deallocating the local (when `main` returns) // races with the read in the other thread. - // Make sure the error points at this function's end, not just the call site. -} //~ERROR: Data race detected between (1) non-atomic read on thread `unnamed-1` and (2) deallocation on thread `main` +} diff --git a/src/tools/miri/tests/fail/data_race/stack_pop_race.stderr b/src/tools/miri/tests/fail/data_race/stack_pop_race.stderr index 643426aba99eb..721b75630449f 100644 --- a/src/tools/miri/tests/fail/data_race/stack_pop_race.stderr +++ b/src/tools/miri/tests/fail/data_race/stack_pop_race.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) deallocation on thread `main` at ALLOC. (2) just happened here --> tests/fail/data_race/stack_pop_race.rs:LL:CC | -LL | } - | ^ Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) deallocation on thread `main` at ALLOC. (2) just happened here +LL | race(0); + | ^^^^^^^ Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) deallocation on thread `main` at ALLOC. (2) just happened here | help: and (1) occurred earlier here --> tests/fail/data_race/stack_pop_race.rs:LL:CC @@ -12,12 +12,7 @@ LL | let _val = unsafe { *ptr.0 }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span): - = note: inside `race` at tests/fail/data_race/stack_pop_race.rs:LL:CC -note: inside `main` - --> tests/fail/data_race/stack_pop_race.rs:LL:CC - | -LL | race(0); - | ^^^^^^^ + = note: inside `main` at tests/fail/data_race/stack_pop_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr index 33e1e53ea0605..15f73c8a9ae15 100644 --- a/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr +++ b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr @@ -14,8 +14,8 @@ LL | let local = 0; help: ALLOC was deallocated here: --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC | -LL | become g(ptr) - | ^^^^^^^^^^^^^ +LL | f(std::ptr::null()); + | ^^^^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): = note: inside `g` at tests/fail/tail_calls/dangling-local-var.rs:LL:CC note: inside `main` diff --git a/src/tools/miri/tests/pass/alloc-access-tracking.rs b/src/tools/miri/tests/pass/alloc-access-tracking.rs index c47063bef03c7..0e88951dc43f9 100644 --- a/src/tools/miri/tests/pass/alloc-access-tracking.rs +++ b/src/tools/miri/tests/pass/alloc-access-tracking.rs @@ -1,7 +1,7 @@ #![no_std] #![no_main] -//@compile-flags: -Zmiri-track-alloc-id=21 -Zmiri-track-alloc-accesses -Cpanic=abort -//@normalize-stderr-test: "id 21" -> "id $$ALLOC" +//@compile-flags: -Zmiri-track-alloc-id=20 -Zmiri-track-alloc-accesses -Cpanic=abort +//@normalize-stderr-test: "id 20" -> "id $$ALLOC" //@only-target: linux # alloc IDs differ between OSes (due to extern static allocations) extern "Rust" { From 98bd1a6a3a56951b2fe676988d8cb005a6b752c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sat, 17 May 2025 14:38:26 +0200 Subject: [PATCH 2637/4206] rustdoc JSON: Don't apply `#[repr]` privacy heuristics --- src/librustdoc/clean/types.rs | 22 ++++-------- src/rustdoc-json-types/lib.rs | 2 +- tests/rustdoc-json/attrs/repr_combination.rs | 4 +++ tests/rustdoc-json/attrs/repr_transparent.rs | 37 -------------------- 4 files changed, 12 insertions(+), 53 deletions(-) delete mode 100644 tests/rustdoc-json/attrs/repr_transparent.rs diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index e45f28444fe0d..07ecd98f77596 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -774,20 +774,11 @@ impl Item { .filter_map(|attr| { if is_json { match attr { - hir::Attribute::Parsed(AttributeKind::Deprecation { .. }) => { - // rustdoc-json stores this in `Item::deprecation`, so we - // don't want it it `Item::attrs`. - None - } - rustc_hir::Attribute::Parsed( - rustc_attr_data_structures::AttributeKind::Repr(..), - ) => { - // We have separate pretty-printing logic for `#[repr(..)]` attributes. - // For example, there are circumstances where `#[repr(transparent)]` - // is applied but should not be publicly shown in rustdoc - // because it isn't public API. - None - } + // rustdoc-json stores this in `Item::deprecation`, so we + // don't want it it `Item::attrs`. + hir::Attribute::Parsed(AttributeKind::Deprecation { .. }) => None, + // We have separate pretty-printing logic for `#[repr(..)]` attributes. + hir::Attribute::Parsed(AttributeKind::Repr(..)) => None, _ => Some({ let mut s = rustc_hir_pretty::attribute_to_string(&tcx, attr); assert_eq!(s.pop(), Some('\n')); @@ -820,7 +811,8 @@ impl Item { if repr.transparent() { // Render `repr(transparent)` iff the non-1-ZST field is public or at least one // field is public in case all fields are 1-ZST fields. - let render_transparent = cache.document_private + let render_transparent = is_json + || cache.document_private || adt .all_fields() .find(|field| { diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 0b8a906529466..c091c955ed5eb 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -30,7 +30,7 @@ pub type FxHashMap = HashMap; // re-export for use in src/librustdoc /// This integer is incremented with every breaking change to the API, /// and is returned along with the JSON blob as [`Crate::format_version`]. /// Consuming code should assert that this value matches the format version(s) that it supports. -pub const FORMAT_VERSION: u32 = 45; +pub const FORMAT_VERSION: u32 = 46; /// The root of the emitted JSON blob. /// diff --git a/tests/rustdoc-json/attrs/repr_combination.rs b/tests/rustdoc-json/attrs/repr_combination.rs index 0e8e2ef0d83e9..6fe29c5eac093 100644 --- a/tests/rustdoc-json/attrs/repr_combination.rs +++ b/tests/rustdoc-json/attrs/repr_combination.rs @@ -77,3 +77,7 @@ pub enum AlignedExplicitRepr { pub enum ReorderedAlignedExplicitRepr { First, } + +//@ is "$.index[?(@.name=='Transparent')].attrs" '["#[repr(transparent)]"]' +#[repr(transparent)] +pub struct Transparent(i64); diff --git a/tests/rustdoc-json/attrs/repr_transparent.rs b/tests/rustdoc-json/attrs/repr_transparent.rs deleted file mode 100644 index 1e634ca901dc4..0000000000000 --- a/tests/rustdoc-json/attrs/repr_transparent.rs +++ /dev/null @@ -1,37 +0,0 @@ -#![no_std] - -// Rustdoc JSON *only* includes `#[repr(transparent)]` -// if the transparency is public API: -// - if a non-1-ZST field exists, it has to be public -// - otherwise, all fields are 1-ZST and at least one of them is public -// -// More info: https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent - -// Here, the non-1-ZST field is public. -// We expect `#[repr(transparent)]` in the attributes. -// -//@ is "$.index[?(@.name=='Transparent')].attrs" '["#[repr(transparent)]"]' -#[repr(transparent)] -pub struct Transparent(pub i64); - -// Here the non-1-ZST field isn't public, so the attribute isn't included. -// -//@ has "$.index[?(@.name=='TransparentNonPub')]" -//@ is "$.index[?(@.name=='TransparentNonPub')].attrs" '[]' -#[repr(transparent)] -pub struct TransparentNonPub(i64); - -// Only 1-ZST fields here, and one of them is public. -// We expect `#[repr(transparent)]` in the attributes. -// -//@ is "$.index[?(@.name=='AllZst')].attrs" '["#[repr(transparent)]"]' -#[repr(transparent)] -pub struct AllZst<'a>(pub core::marker::PhantomData<&'a ()>, ()); - -// Only 1-ZST fields here but none of them are public. -// The attribute isn't included. -// -//@ has "$.index[?(@.name=='AllZstNotPublic')]" -//@ is "$.index[?(@.name=='AllZstNotPublic')].attrs" '[]' -#[repr(transparent)] -pub struct AllZstNotPublic<'a>(core::marker::PhantomData<&'a ()>, ()); From cb8fdb4d80a855c87c5a56a0652aa8f91b0d545d Mon Sep 17 00:00:00 2001 From: Andrew Zhogin Date: Tue, 13 May 2025 20:26:22 +0700 Subject: [PATCH 2638/4206] Async drop poll shim for error dropee generates noop body (fixes #140930) --- .../src/shim/async_destructor_ctor.rs | 7 ++++--- .../async-drop/open-drop-error2.rs | 21 +++++++++++++++++++ .../async-drop/open-drop-error2.stderr | 19 +++++++++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 tests/ui/async-await/async-drop/open-drop-error2.rs create mode 100644 tests/ui/async-await/async-drop/open-drop-error2.stderr diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs index 7976b65aae7b0..fbc8ee9b06c03 100644 --- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs +++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs @@ -6,7 +6,7 @@ use rustc_middle::mir::{ BasicBlock, BasicBlockData, Body, Local, LocalDecl, MirSource, Operand, Place, Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, }; -use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt}; +use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt, TypeVisitableExt}; use super::*; use crate::patch::MirPatch; @@ -121,9 +121,10 @@ pub(super) fn build_async_drop_shim<'tcx>( parent_args.as_coroutine().resume_ty(), ))); body.phase = MirPhase::Runtime(RuntimePhase::Initial); - if !needs_async_drop { + if !needs_async_drop || drop_ty.references_error() { // Returning noop body for types without `need async drop` - // (or sync Drop in case of !`need async drop` && `need drop`) + // (or sync Drop in case of !`need async drop` && `need drop`). + // And also for error types. return body; } diff --git a/tests/ui/async-await/async-drop/open-drop-error2.rs b/tests/ui/async-await/async-drop/open-drop-error2.rs new file mode 100644 index 0000000000000..b2a7b68190ec1 --- /dev/null +++ b/tests/ui/async-await/async-drop/open-drop-error2.rs @@ -0,0 +1,21 @@ +//@compile-flags: -Zvalidate-mir -Zinline-mir=yes --crate-type=lib + +#![feature(async_drop)] +#![allow(incomplete_features)] + +use std::{ + future::{Future, async_drop_in_place}, + pin::pin, + task::Context, +}; + +fn wrong() -> impl Sized { + //~^ ERROR: the size for values of type `str` cannot be known at compilation time + *"abc" // Doesn't implement Sized +} +fn weird(context: &mut Context<'_>) { + let mut e = wrong(); + let h = unsafe { async_drop_in_place(&raw mut e) }; + let i = pin!(h); + i.poll(context); +} diff --git a/tests/ui/async-await/async-drop/open-drop-error2.stderr b/tests/ui/async-await/async-drop/open-drop-error2.stderr new file mode 100644 index 0000000000000..e849829b1c78b --- /dev/null +++ b/tests/ui/async-await/async-drop/open-drop-error2.stderr @@ -0,0 +1,19 @@ +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/open-drop-error2.rs:12:15 + | +LL | fn wrong() -> impl Sized { + | ^^^^^^^^^^ doesn't have a size known at compile-time +LL | +LL | *"abc" // Doesn't implement Sized + | ------ return type was inferred to be `str` here + | + = help: the trait `Sized` is not implemented for `str` +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - *"abc" // Doesn't implement Sized +LL + "abc" // Doesn't implement Sized + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From caf665e692d74085e28a62ce4497eb7f02c5f37f Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Wed, 21 May 2025 16:21:00 -0700 Subject: [PATCH 2639/4206] Use the fn_span when emitting function calls for better debug info. This especially improves the developer experience for long chains of function calls that span multiple lines, which is common with builder patterns, chains of iterator/future combinators, etc. --- compiler/rustc_codegen_ssa/src/mir/block.rs | 1 + tests/debuginfo/multiline-calls.rs | 35 +++++++++++++++++++ .../location-detail-unwrap-multiline.rs | 11 ++++++ 3 files changed, 47 insertions(+) create mode 100644 tests/debuginfo/multiline-calls.rs create mode 100644 tests/ui/panics/location-detail-unwrap-multiline.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 950f19a6f0f4e..600d6ff68015f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1181,6 +1181,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (_, Some(llfn)) => llfn, _ => span_bug!(span, "no instance or llfn for call"), }; + self.set_debug_loc(bx, mir::SourceInfo { span: fn_span, ..source_info }); helper.do_call( self, bx, diff --git a/tests/debuginfo/multiline-calls.rs b/tests/debuginfo/multiline-calls.rs new file mode 100644 index 0000000000000..724ad29729fd2 --- /dev/null +++ b/tests/debuginfo/multiline-calls.rs @@ -0,0 +1,35 @@ +//@ compile-flags:-g +//@ min-gdb-version: 16.0 + +// === GDB TESTS =================================================================================== + +// gdb-command: run +// gdb-check:[...]#break[...] +// gdb-command: up +// gdb-check:[...]zzz[...] + +// === LLDB TESTS ================================================================================== + +// lldb-command:run +// lldb-check:[...]#break[...] +// lldb-command: up +// lldb-check:[...]zzz[...] + +struct Foo; + +impl Foo { + fn bar(self) -> Foo { + println!("bar"); + self + } + fn baz(self) -> Foo { + println!("baz"); // #break + self + } +} + +fn main() { + let f = Foo; + f.bar() // aaa + .baz(); // zzz +} diff --git a/tests/ui/panics/location-detail-unwrap-multiline.rs b/tests/ui/panics/location-detail-unwrap-multiline.rs new file mode 100644 index 0000000000000..afe15a579c41c --- /dev/null +++ b/tests/ui/panics/location-detail-unwrap-multiline.rs @@ -0,0 +1,11 @@ +//@ run-fail +//@ compile-flags: -Cstrip=none -Cdebuginfo=line-tables-only -Copt-level=0 +//@ exec-env:RUST_BACKTRACE=1 +//@ regex-error-pattern: location-detail-unwrap-multiline\.rs:10(:10)?\n +//@ needs-unwind + +fn main() { + let opt: Option = None; + opt + .unwrap(); +} From 1eba1b56e33f196e6b48cad2efb41b9b9ab7452f Mon Sep 17 00:00:00 2001 From: binarycat Date: Thu, 22 May 2025 16:05:52 -0500 Subject: [PATCH 2640/4206] rustdoc: rip out all the gui tests for <100% width mobile sidebar stuff like "clicking the settings menu closes the mobile sidebar" is now impossible for users to observe, since the mobile sidebar will always cover the settings menu due to being full-width, which is good because that behavior is also now impossible for our testing framework to observe. --- tests/rustdoc-gui/notable-trait.goml | 4 ---- tests/rustdoc-gui/pocket-menu.goml | 13 ------------- tests/rustdoc-gui/sidebar-mobile.goml | 7 +++++-- 3 files changed, 5 insertions(+), 19 deletions(-) diff --git a/tests/rustdoc-gui/notable-trait.goml b/tests/rustdoc-gui/notable-trait.goml index 4624fb80b3779..7fc70e0675df4 100644 --- a/tests/rustdoc-gui/notable-trait.goml +++ b/tests/rustdoc-gui/notable-trait.goml @@ -244,10 +244,6 @@ click: ".sidebar-menu-toggle" assert: "//*[@class='sidebar shown']" assert-count: ("//*[@class='tooltip popover']", 0) assert-false: "#method\.create_an_iterator_from_read .tooltip:focus" -// Clicking a notable trait tooltip popover should close the sidebar. -click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" -assert-count: ("//*[@class='tooltip popover']", 1) -assert-false: "//*[@class='sidebar shown']" // Also check the focus handling for the settings button. set-window-size: (1100, 600) diff --git a/tests/rustdoc-gui/pocket-menu.goml b/tests/rustdoc-gui/pocket-menu.goml index 4a062fec7516d..073172dd8a791 100644 --- a/tests/rustdoc-gui/pocket-menu.goml +++ b/tests/rustdoc-gui/pocket-menu.goml @@ -68,16 +68,3 @@ assert-css: ("#settings-menu .popover", {"display": "block"}) click: ".sidebar-menu-toggle" assert: "//*[@class='sidebar shown']" assert-css: ("#settings-menu .popover", {"display": "none"}) -// Opening the settings popover should close the sidebar. -click: "#settings-menu a" -assert-css: ("#settings-menu .popover", {"display": "block"}) -assert-false: "//*[@class='sidebar shown']" - -// Opening the settings popover at start (which async loads stuff) should also close. -reload: -click: ".sidebar-menu-toggle" -assert: "//*[@class='sidebar shown']" -assert-false: "#settings-menu .popover" -click: "#settings-menu a" -assert-false: "//*[@class='sidebar shown']" -wait-for: "#settings-menu .popover" diff --git a/tests/rustdoc-gui/sidebar-mobile.goml b/tests/rustdoc-gui/sidebar-mobile.goml index 4ada4837a5774..0596f84317481 100644 --- a/tests/rustdoc-gui/sidebar-mobile.goml +++ b/tests/rustdoc-gui/sidebar-mobile.goml @@ -32,8 +32,8 @@ assert-css: ( {"display": "block"} ) -// Click elsewhere. -click: "body" +// Click the toggle to close it +click: ".sidebar-menu-toggle" assert-css: (".sidebar", {"display": "block", "left": "-1000px"}) // Open the sidebar menu, and make sure pressing Escape closes it. @@ -57,6 +57,7 @@ scroll-to: ".block.keyword li:nth-child(1)" compare-elements-position-near: (".block.keyword li:nth-child(1)", ".mobile-topbar", {"y": 544}) // Now checking the background color of the sidebar. +reload: show-text: true define-function: ( @@ -72,6 +73,8 @@ define-function: ( "background-color": |background|, "color": |color|, }) + // Close the sidebar menu. + press-key: "Escape" }, ) From f0096aea4020b354415268539cb4fddf6fc5f48d Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Fri, 23 May 2025 01:01:21 +0300 Subject: [PATCH 2641/4206] Normalize when checking for uninhabited types for pattern exhaustiveness checking --- .../crates/hir-ty/src/diagnostics/expr.rs | 10 +++++--- .../diagnostics/match_check/pat_analysis.rs | 24 +++++++++++++----- .../crates/hir-ty/src/inhabitedness.rs | 23 ++++++++++++++--- .../crates/hir-ty/src/mir/lower.rs | 24 ++++++++++-------- .../src/handlers/non_exhaustive_let.rs | 25 +++++++++++++++++++ 5 files changed, 81 insertions(+), 25 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs index e4a23cbbacffa..8665e9d33fcba 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs @@ -25,7 +25,7 @@ use triomphe::Arc; use typed_arena::Arena; use crate::{ - Adjust, InferenceResult, Interner, Ty, TyExt, TyKind, + Adjust, InferenceResult, Interner, TraitEnvironment, Ty, TyExt, TyKind, db::HirDatabase, diagnostics::match_check::{ self, @@ -74,8 +74,9 @@ impl BodyValidationDiagnostic { let _p = tracing::info_span!("BodyValidationDiagnostic::collect").entered(); let infer = db.infer(owner); let body = db.body(owner); + let env = db.trait_environment_for_body(owner); let mut validator = - ExprValidator { owner, body, infer, diagnostics: Vec::new(), validate_lints }; + ExprValidator { owner, body, infer, diagnostics: Vec::new(), validate_lints, env }; validator.validate_body(db); validator.diagnostics } @@ -85,6 +86,7 @@ struct ExprValidator { owner: DefWithBodyId, body: Arc, infer: Arc, + env: Arc, diagnostics: Vec, validate_lints: bool, } @@ -190,7 +192,7 @@ impl ExprValidator { return; } - let cx = MatchCheckCtx::new(self.owner.module(db), self.owner, db); + let cx = MatchCheckCtx::new(self.owner.module(db), self.owner, db, self.env.clone()); let pattern_arena = Arena::new(); let mut m_arms = Vec::with_capacity(arms.len()); @@ -317,7 +319,7 @@ impl ExprValidator { return; }; let pattern_arena = Arena::new(); - let cx = MatchCheckCtx::new(self.owner.module(db), self.owner, db); + let cx = MatchCheckCtx::new(self.owner.module(db), self.owner, db, self.env.clone()); for stmt in &**statements { let &Statement::Let { pat, initializer, else_branch: None, .. } = stmt else { continue; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs index 785277d70c64b..dd82a0f45ca44 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -12,9 +12,10 @@ use rustc_pattern_analysis::{ }; use smallvec::{SmallVec, smallvec}; use stdx::never; +use triomphe::Arc; use crate::{ - AdtId, Interner, Scalar, Ty, TyExt, TyKind, + AdtId, Interner, Scalar, TraitEnvironment, Ty, TyExt, TyKind, db::HirDatabase, infer::normalize, inhabitedness::{is_enum_variant_uninhabited_from, is_ty_uninhabited_from}, @@ -69,13 +70,19 @@ pub(crate) struct MatchCheckCtx<'db> { body: DefWithBodyId, pub(crate) db: &'db dyn HirDatabase, exhaustive_patterns: bool, + env: Arc, } impl<'db> MatchCheckCtx<'db> { - pub(crate) fn new(module: ModuleId, body: DefWithBodyId, db: &'db dyn HirDatabase) -> Self { + pub(crate) fn new( + module: ModuleId, + body: DefWithBodyId, + db: &'db dyn HirDatabase, + env: Arc, + ) -> Self { let def_map = module.crate_def_map(db); let exhaustive_patterns = def_map.is_unstable_feature_enabled(&sym::exhaustive_patterns); - Self { module, body, db, exhaustive_patterns } + Self { module, body, db, exhaustive_patterns, env } } pub(crate) fn compute_match_usefulness( @@ -100,7 +107,7 @@ impl<'db> MatchCheckCtx<'db> { } fn is_uninhabited(&self, ty: &Ty) -> bool { - is_ty_uninhabited_from(self.db, ty, self.module) + is_ty_uninhabited_from(self.db, ty, self.module, self.env.clone()) } /// Returns whether the given ADT is from another crate declared `#[non_exhaustive]`. @@ -459,8 +466,13 @@ impl PatCx for MatchCheckCtx<'_> { } else { let mut variants = IndexVec::with_capacity(enum_data.variants.len()); for &(variant, _) in enum_data.variants.iter() { - let is_uninhabited = - is_enum_variant_uninhabited_from(cx.db, variant, subst, cx.module); + let is_uninhabited = is_enum_variant_uninhabited_from( + cx.db, + variant, + subst, + cx.module, + self.env.clone(), + ); let visibility = if is_uninhabited { VariantVisibility::Empty } else { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs index e0c3279d3fb01..e81a5e3c3114b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs @@ -7,17 +7,24 @@ use chalk_ir::{ }; use hir_def::{AdtId, EnumVariantId, ModuleId, VariantId, visibility::Visibility}; use rustc_hash::FxHashSet; +use triomphe::Arc; use crate::{ - Binders, Interner, Substitution, Ty, TyKind, consteval::try_const_usize, db::HirDatabase, + AliasTy, Binders, Interner, Substitution, TraitEnvironment, Ty, TyKind, + consteval::try_const_usize, db::HirDatabase, }; // FIXME: Turn this into a query, it can be quite slow /// Checks whether a type is visibly uninhabited from a particular module. -pub(crate) fn is_ty_uninhabited_from(db: &dyn HirDatabase, ty: &Ty, target_mod: ModuleId) -> bool { +pub(crate) fn is_ty_uninhabited_from( + db: &dyn HirDatabase, + ty: &Ty, + target_mod: ModuleId, + env: Arc, +) -> bool { let _p = tracing::info_span!("is_ty_uninhabited_from", ?ty).entered(); let mut uninhabited_from = - UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default() }; + UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default(), env }; let inhabitedness = ty.visit_with(&mut uninhabited_from, DebruijnIndex::INNERMOST); inhabitedness == BREAK_VISIBLY_UNINHABITED } @@ -29,11 +36,12 @@ pub(crate) fn is_enum_variant_uninhabited_from( variant: EnumVariantId, subst: &Substitution, target_mod: ModuleId, + env: Arc, ) -> bool { let _p = tracing::info_span!("is_enum_variant_uninhabited_from").entered(); let mut uninhabited_from = - UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default() }; + UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default(), env }; let inhabitedness = uninhabited_from.visit_variant(variant.into(), subst); inhabitedness == BREAK_VISIBLY_UNINHABITED } @@ -44,6 +52,7 @@ struct UninhabitedFrom<'a> { // guard for preventing stack overflow in non trivial non terminating types max_depth: usize, db: &'a dyn HirDatabase, + env: Arc, } const CONTINUE_OPAQUELY_INHABITED: ControlFlow = Continue(()); @@ -78,6 +87,12 @@ impl TypeVisitor for UninhabitedFrom<'_> { Some(0) | None => CONTINUE_OPAQUELY_INHABITED, Some(1..) => item_ty.super_visit_with(self, outer_binder), }, + TyKind::Alias(AliasTy::Projection(projection)) => { + // FIXME: I think this currently isn't used for monomorphized bodies, so there is no need to handle + // `TyKind::AssociatedType`, but perhaps in the future it will. + let normalized = self.db.normalize_projection(projection.clone(), self.env.clone()); + self.visit_ty(&normalized, outer_binder) + } _ => CONTINUE_OPAQUELY_INHABITED, }; self.recursive_ty.remove(ty); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 7fcc89e5183a8..e6caf2d8d97a5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -25,7 +25,7 @@ use syntax::TextRange; use triomphe::Arc; use crate::{ - Adjust, Adjustment, AutoBorrow, CallableDefId, TyBuilder, TyExt, + Adjust, Adjustment, AutoBorrow, CallableDefId, TraitEnvironment, TyBuilder, TyExt, consteval::ConstEvalError, db::{HirDatabase, InternedClosure, InternedClosureId}, display::{DisplayTarget, HirDisplay, hir_display_with_store}, @@ -79,6 +79,7 @@ struct MirLowerCtx<'db> { infer: &'db InferenceResult, resolver: Resolver<'db>, drop_scopes: Vec, + env: Arc, } // FIXME: Make this smaller, its stored in database queries @@ -288,6 +289,7 @@ impl<'ctx> MirLowerCtx<'ctx> { closures: vec![], }; let resolver = owner.resolver(db); + let env = db.trait_environment_for_body(owner); MirLowerCtx { result: mir, @@ -300,6 +302,7 @@ impl<'ctx> MirLowerCtx<'ctx> { labeled_loop_blocks: Default::default(), discr_temp: None, drop_scopes: vec![DropScope::default()], + env, } } @@ -944,10 +947,7 @@ impl<'ctx> MirLowerCtx<'ctx> { let cast_kind = if source_ty.as_reference().is_some() { CastKind::PointerCoercion(PointerCast::ArrayToPointer) } else { - let mut table = InferenceTable::new( - self.db, - self.db.trait_environment_for_body(self.owner), - ); + let mut table = InferenceTable::new(self.db, self.env.clone()); cast_kind(&mut table, &source_ty, &target_ty)? }; @@ -1412,11 +1412,8 @@ impl<'ctx> MirLowerCtx<'ctx> { } fn lower_literal_to_operand(&mut self, ty: Ty, l: &Literal) -> Result { - let size = || { - self.db - .layout_of_ty(ty.clone(), self.db.trait_environment_for_body(self.owner)) - .map(|it| it.size.bytes_usize()) - }; + let size = + || self.db.layout_of_ty(ty.clone(), self.env.clone()).map(|it| it.size.bytes_usize()); const USIZE_SIZE: usize = size_of::(); let bytes: Box<[_]> = match l { hir_def::hir::Literal::String(b) => { @@ -1723,7 +1720,12 @@ impl<'ctx> MirLowerCtx<'ctx> { } fn is_uninhabited(&self, expr_id: ExprId) -> bool { - is_ty_uninhabited_from(self.db, &self.infer[expr_id], self.owner.module(self.db)) + is_ty_uninhabited_from( + self.db, + &self.infer[expr_id], + self.owner.module(self.db), + self.env.clone(), + ) } /// This function push `StorageLive` statement for the binding, and applies changes to add `StorageDead` and diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs index 35cefd2397529..f20b6dea1227e 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs @@ -106,4 +106,29 @@ fn test(x: Result) { "#, ); } + + #[test] + fn empty_patterns_normalize() { + check_diagnostics( + r#" +enum Infallible {} + +trait Foo { + type Assoc; +} +enum Enum { + A, + B(T::Assoc), +} + +impl Foo for () { + type Assoc = Infallible; +} + +fn foo(v: Enum<()>) { + let Enum::A = v; +} + "#, + ); + } } From 34411547fb40d95c313dada70a01104676c65df0 Mon Sep 17 00:00:00 2001 From: lolbinarycat Date: Thu, 22 May 2025 17:31:36 -0500 Subject: [PATCH 2642/4206] rustdoc.md: reorder list so test suites are not split up --- src/doc/rustc-dev-guide/src/rustdoc.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/rustdoc.md b/src/doc/rustc-dev-guide/src/rustdoc.md index e36d6a388a981..78e17ba1e8573 100644 --- a/src/doc/rustc-dev-guide/src/rustdoc.md +++ b/src/doc/rustc-dev-guide/src/rustdoc.md @@ -93,13 +93,13 @@ does is call the `main()` that's in this crate's `lib.rs`, though.) interactivity. For information on how to write this form of test, see [`tests/rustdoc-gui/README.md`][rustdoc-gui-readme] as well as [the description of the `.goml` format][goml-script] -* Additionally, JavaScript type annotations are written using [TypeScript-flavored JSDoc] - comments and an external d.ts file. The code itself is plain, valid JavaScript; we only - use tsc as a linter. -* The tests on the structure of rustdoc HTML output are located in `tests/rustdoc`, +* Tests on the structure of rustdoc HTML output are located in `tests/rustdoc`, where they're handled by the test runner of bootstrap and the supplementary script `src/etc/htmldocck.py`. [These tests have several extra directives available to them](./rustdoc-internals/rustdoc-test-suite.md). +* Additionally, JavaScript type annotations are written using [TypeScript-flavored JSDoc] + comments and an external d.ts file. The code itself is plain, valid JavaScript; we only + use tsc as a linter. [TypeScript-flavored JSDoc]: https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html [rustdoc-gui-readme]: https://github.com/rust-lang/rust/blob/master/tests/rustdoc-gui/README.md From 6d716743211c1c7e28f32c48f586fbeb3068304f Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 23 May 2025 01:53:54 +0200 Subject: [PATCH 2643/4206] Remove #![feature(let_chains)] from libcore --- library/core/src/lib.rs | 1 - src/ci/docker/scripts/rfl-build.sh | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index b76213fdd41d3..c49513f7a6d37 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -158,7 +158,6 @@ #![feature(intra_doc_pointers)] #![feature(intrinsics)] #![feature(lang_items)] -#![feature(let_chains)] #![feature(link_llvm_intrinsics)] #![feature(macro_metavar_expr)] #![feature(marker_trait_attr)] diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh index 1d280948ebe68..fa18f67583ff6 100755 --- a/src/ci/docker/scripts/rfl-build.sh +++ b/src/ci/docker/scripts/rfl-build.sh @@ -2,7 +2,8 @@ set -euo pipefail -LINUX_VERSION=v6.15-rc4 +# https://github.com/Rust-for-Linux/linux/issues/1163 +LINUX_VERSION=3ca02fc80cc4fdac63aaa6796642f1e07be591d6 # Build rustc, rustdoc, cargo, clippy-driver and rustfmt ../x.py build --stage 2 library rustdoc clippy rustfmt From 5f3242c0848bc7e7b02a6fb56cf8ac2f6633c335 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Fri, 23 May 2025 04:53:31 +0000 Subject: [PATCH 2644/4206] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 4698969530292..88a53545d51aa 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -2b96ddca1272960623e41829439df8dae82d20af +e7f4317ea0e891296163414c6f681ccec976abc3 From 5d5fb18e54fe875d247f41c81a3932273adeabc0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 23 May 2025 08:57:11 +0200 Subject: [PATCH 2645/4206] ./miri bench: sort results alphabetically --- src/tools/miri/miri-script/src/commands.rs | 26 +++++++++++++--------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs index 3b7b159aeab76..1781ca119eeec 100644 --- a/src/tools/miri/miri-script/src/commands.rs +++ b/src/tools/miri/miri-script/src/commands.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::BTreeMap; use std::ffi::{OsStr, OsString}; use std::fmt::Write as _; use std::fs::{self, File}; @@ -489,7 +489,9 @@ impl Command { sh.read_dir(benches_dir)? .into_iter() .filter(|path| path.is_dir()) - .map(|path| path.into_os_string().into_string().unwrap()) + // Only keep the basename: that matches the usage with a manual bench list, + // and it ensure the path concatenations below work as intended. + .map(|path| path.file_name().unwrap().to_owned().into_string().unwrap()) .collect() } else { benches.into_iter().collect() @@ -530,14 +532,16 @@ impl Command { stddev: f64, } - let gather_results = || -> Result> { + let gather_results = || -> Result> { let baseline_temp_dir = results_json_dir.unwrap(); - let mut results = HashMap::new(); + let mut results = BTreeMap::new(); for bench in &benches { - let result = File::open(path!(baseline_temp_dir / format!("{bench}.bench.json")))?; - let mut result: serde_json::Value = - serde_json::from_reader(BufReader::new(result))?; - let result: BenchResult = serde_json::from_value(result["results"][0].take())?; + let result = File::open(path!(baseline_temp_dir / format!("{bench}.bench.json"))) + .context("failed to read hyperfine JSON")?; + let mut result: serde_json::Value = serde_json::from_reader(BufReader::new(result)) + .context("failed to parse hyperfine JSON")?; + let result: BenchResult = serde_json::from_value(result["results"][0].take()) + .context("failed to interpret hyperfine JSON")?; results.insert(bench as &str, result); } Ok(results) @@ -549,15 +553,15 @@ impl Command { serde_json::to_writer_pretty(BufWriter::new(baseline), &results)?; } else if let Some(baseline_file) = load_baseline { let new_results = gather_results()?; - let baseline_results: HashMap = { + let baseline_results: BTreeMap = { let f = File::open(baseline_file)?; serde_json::from_reader(BufReader::new(f))? }; println!( "Comparison with baseline (relative speed, lower is better for the new results):" ); - for (bench, new_result) in new_results.iter() { - let Some(baseline_result) = baseline_results.get(*bench) else { continue }; + for (bench, new_result) in new_results { + let Some(baseline_result) = baseline_results.get(bench) else { continue }; // Compare results (inspired by hyperfine) let ratio = new_result.mean / baseline_result.mean; From f34c67e7a4af4889f8c50006f0499a4967de0fbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Fri, 23 May 2025 11:08:56 +0200 Subject: [PATCH 2646/4206] Disable `triagebot`'s `glacier` handler --- triagebot.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index fd7a861bc92dc..cfcd100003dae 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -44,8 +44,6 @@ remove_labels = ["S-waiting-on-author"] # Those labels are added when PR author requests a review from an assignee add_labels = ["S-waiting-on-review"] -[glacier] - [ping.icebreakers-llvm] message = """\ Hey LLVM ICE-breakers! This bug has been identified as a good From 0a059d9e971863b02259cb23e6fa82043db8b304 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Thu, 15 May 2025 01:20:52 +0200 Subject: [PATCH 2647/4206] `needless_borrow`: do not contradict `dangerous_implicit_autorefs` Rust 1.88 introduces the `dangerous_implicit_autorefs` lint which warns about using implicit autorefs on a place obtained from a raw pointer, as this may create aliasing issues. Prevent `clippy::needless_borrow` from triggering in this case, by disabling the lint when taking a reference on a raw pointer dereference. There might be a better way for doing this in the long run with a finer way of distinguish the problematic cases, but this will prevent Clippy from contradicting the compiler in the meantime. --- clippy_lints/src/dereference.rs | 9 +++++++++ tests/ui/needless_borrow.fixed | 15 ++++++++++++--- tests/ui/needless_borrow.rs | 15 ++++++++++++--- tests/ui/needless_borrow.stderr | 32 ++++++++++++++++---------------- 4 files changed, 49 insertions(+), 22 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 5edb5c235703e..a2cedba98327b 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -997,6 +997,15 @@ fn report<'tcx>( ); }, State::DerefedBorrow(state) => { + // Do not suggest removing a non-mandatory `&` in `&*rawptr` in an `unsafe` context, + // as this may make rustc trigger its `dangerous_implicit_autorefs` lint. + if let ExprKind::AddrOf(BorrowKind::Ref, _, subexpr) = data.first_expr.kind + && let ExprKind::Unary(UnOp::Deref, subsubexpr) = subexpr.kind + && cx.typeck_results().expr_ty_adjusted(subsubexpr).is_raw_ptr() + { + return; + } + let mut app = Applicability::MachineApplicable; let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app); diff --git a/tests/ui/needless_borrow.fixed b/tests/ui/needless_borrow.fixed index d7d344452c5d8..54cad2e393fd4 100644 --- a/tests/ui/needless_borrow.fixed +++ b/tests/ui/needless_borrow.fixed @@ -107,9 +107,6 @@ fn main() { let x = (1, 2); let _ = x.0; //~^ needless_borrow - let x = &x as *const (i32, i32); - let _ = unsafe { (*x).0 }; - //~^ needless_borrow // Issue #8367 trait Foo { @@ -289,3 +286,15 @@ fn issue_12268() { // compiler } + +fn issue_14743(slice: &[T]) { + let _ = slice.len(); + //~^ needless_borrow + + let slice = slice as *const [T]; + let _ = unsafe { (&*slice).len() }; + + // Check that rustc would actually warn if Clippy had suggested removing the reference + #[expect(dangerous_implicit_autorefs)] + let _ = unsafe { (*slice).len() }; +} diff --git a/tests/ui/needless_borrow.rs b/tests/ui/needless_borrow.rs index 1f05b90b47285..b698c6bfc9695 100644 --- a/tests/ui/needless_borrow.rs +++ b/tests/ui/needless_borrow.rs @@ -107,9 +107,6 @@ fn main() { let x = (1, 2); let _ = (&x).0; //~^ needless_borrow - let x = &x as *const (i32, i32); - let _ = unsafe { (&*x).0 }; - //~^ needless_borrow // Issue #8367 trait Foo { @@ -289,3 +286,15 @@ fn issue_12268() { // compiler } + +fn issue_14743(slice: &[T]) { + let _ = (&slice).len(); + //~^ needless_borrow + + let slice = slice as *const [T]; + let _ = unsafe { (&*slice).len() }; + + // Check that rustc would actually warn if Clippy had suggested removing the reference + #[expect(dangerous_implicit_autorefs)] + let _ = unsafe { (*slice).len() }; +} diff --git a/tests/ui/needless_borrow.stderr b/tests/ui/needless_borrow.stderr index b036b1e47d187..172d36bd73a0a 100644 --- a/tests/ui/needless_borrow.stderr +++ b/tests/ui/needless_borrow.stderr @@ -103,71 +103,71 @@ error: this expression borrows a value the compiler would automatically borrow LL | let _ = (&x).0; | ^^^^ help: change this to: `x` -error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:111:22 - | -LL | let _ = unsafe { (&*x).0 }; - | ^^^^^ help: change this to: `(*x)` - error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:122:5 + --> tests/ui/needless_borrow.rs:119:5 | LL | (&&()).foo(); | ^^^^^^ help: change this to: `(&())` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:132:5 + --> tests/ui/needless_borrow.rs:129:5 | LL | (&&5).foo(); | ^^^^^ help: change this to: `(&5)` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:159:23 + --> tests/ui/needless_borrow.rs:156:23 | LL | let x: (&str,) = (&"",); | ^^^ help: change this to: `""` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:202:13 + --> tests/ui/needless_borrow.rs:199:13 | LL | (&self.f)() | ^^^^^^^^^ help: change this to: `(self.f)` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:212:13 + --> tests/ui/needless_borrow.rs:209:13 | LL | (&mut self.f)() | ^^^^^^^^^^^^^ help: change this to: `(self.f)` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:250:22 + --> tests/ui/needless_borrow.rs:247:22 | LL | let _ = &mut (&mut { x.u }).x; | ^^^^^^^^^^^^^^ help: change this to: `{ x.u }` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:258:22 + --> tests/ui/needless_borrow.rs:255:22 | LL | let _ = &mut (&mut { x.u }).x; | ^^^^^^^^^^^^^^ help: change this to: `{ x.u }` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:263:22 + --> tests/ui/needless_borrow.rs:260:22 | LL | let _ = &mut (&mut x.u).x; | ^^^^^^^^^^ help: change this to: `x.u` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:265:22 + --> tests/ui/needless_borrow.rs:262:22 | LL | let _ = &mut (&mut { x.u }).x; | ^^^^^^^^^^^^^^ help: change this to: `{ x.u }` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:287:23 + --> tests/ui/needless_borrow.rs:284:23 | LL | option.unwrap_or((&x.0,)); | ^^^^ help: change this to: `x.0` +error: this expression creates a reference which is immediately dereferenced by the compiler + --> tests/ui/needless_borrow.rs:291:13 + | +LL | let _ = (&slice).len(); + | ^^^^^^^^ help: change this to: `slice` + error: aborting due to 28 previous errors From 24d950398cf0181c052d969f9496f967fb186800 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 23 May 2025 11:38:42 +0200 Subject: [PATCH 2648/4206] many-seeds tests have become a lot faster thanks to multithreading --- src/tools/miri/ci/ci.sh | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 9ae15739dcbe1..ad5524f175010 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -142,12 +142,10 @@ case $HOST_TARGET in # Host GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests # Extra tier 1 - # With reduced many-seed count to avoid spending too much time on that. - # (All OSes and ABIs are run with 64 seeds at least once though via the macOS runner.) - MANY_SEEDS=16 TEST_TARGET=i686-unknown-linux-gnu run_tests - MANY_SEEDS=16 TEST_TARGET=aarch64-unknown-linux-gnu run_tests - MANY_SEEDS=16 TEST_TARGET=x86_64-apple-darwin run_tests - MANY_SEEDS=16 TEST_TARGET=x86_64-pc-windows-gnu run_tests + MANY_SEEDS=64 TEST_TARGET=i686-unknown-linux-gnu run_tests + MANY_SEEDS=64 TEST_TARGET=aarch64-unknown-linux-gnu run_tests + MANY_SEEDS=64 TEST_TARGET=x86_64-apple-darwin run_tests + MANY_SEEDS=64 TEST_TARGET=x86_64-pc-windows-gnu run_tests ;; aarch64-apple-darwin) # Host @@ -178,7 +176,7 @@ case $HOST_TARGET in # Host # Without GC_STRESS and with reduced many-seeds count as this is the slowest runner. # (The macOS runner checks windows-msvc with full many-seeds count.) - MIR_OPT=1 MANY_SEEDS=16 TEST_BENCH=1 run_tests + MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 run_tests # Extra tier 1 # We really want to ensure a Linux target works on a Windows host, # and a 64bit target works on a 32bit host. From 20236c6094884ea97d9f14dcbe862a41ff4fab6b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 23 May 2025 11:41:28 +0200 Subject: [PATCH 2649/4206] test some aarch64 windows targets --- src/tools/miri/ci/ci.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index ad5524f175010..8941af681a478 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -146,6 +146,8 @@ case $HOST_TARGET in MANY_SEEDS=64 TEST_TARGET=aarch64-unknown-linux-gnu run_tests MANY_SEEDS=64 TEST_TARGET=x86_64-apple-darwin run_tests MANY_SEEDS=64 TEST_TARGET=x86_64-pc-windows-gnu run_tests + # Extra tier 1 candidate + MANY_SEEDS=64 TEST_TARGET=aarch64-pc-windows-msvc run_tests ;; aarch64-apple-darwin) # Host @@ -154,7 +156,8 @@ case $HOST_TARGET in MANY_SEEDS=64 TEST_TARGET=i686-pc-windows-gnu run_tests MANY_SEEDS=64 TEST_TARGET=x86_64-pc-windows-msvc CARGO_MIRI_ENV=1 run_tests # Extra tier 2 - MANY_SEEDS=16 TEST_TARGET=arm-unknown-linux-gnueabi run_tests + MANY_SEEDS=16 TEST_TARGET=arm-unknown-linux-gnueabi run_tests # 32bit ARM + MANY_SEEDS=16 TEST_TARGET=aarch64-pc-windows-gnullvm run_tests # gnullvm ABI MANY_SEEDS=16 TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture of choice # Not officially supported tier 2 MANY_SEEDS=16 TEST_TARGET=mips-unknown-linux-gnu run_tests # a 32bit big-endian target, and also a target without 64bit atomics From 46606a3f81d67f16b738b3dff74aba5070c7890e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 23 May 2025 09:43:21 +0000 Subject: [PATCH 2650/4206] Dont walk into unsafe binders when emiting error for non-structural type match --- .../src/thir/pattern/const_to_pat.rs | 3 +++ .../unsafe-binders/non-strucutral-type-diag.rs | 17 +++++++++++++++++ .../non-strucutral-type-diag.stderr | 13 +++++++++++++ 3 files changed, 33 insertions(+) create mode 100644 tests/ui/unsafe-binders/non-strucutral-type-diag.rs create mode 100644 tests/ui/unsafe-binders/non-strucutral-type-diag.stderr diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index b7d203e3cd78c..e233358f3866e 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -382,6 +382,9 @@ fn extend_type_not_partial_eq<'tcx>( fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { match ty.kind() { ty::Dynamic(..) => return ControlFlow::Break(()), + // Unsafe binders never implement `PartialEq`, so avoid walking into them + // which would require instantiating its binder with placeholders too. + ty::UnsafeBinder(..) => return ControlFlow::Break(()), ty::FnPtr(..) => return ControlFlow::Continue(()), ty::Adt(def, _args) => { let ty_def_id = def.did(); diff --git a/tests/ui/unsafe-binders/non-strucutral-type-diag.rs b/tests/ui/unsafe-binders/non-strucutral-type-diag.rs new file mode 100644 index 0000000000000..e021e9567e5c8 --- /dev/null +++ b/tests/ui/unsafe-binders/non-strucutral-type-diag.rs @@ -0,0 +1,17 @@ +// regression test for . + +#![feature(unsafe_binders)] +#![allow(incomplete_features)] + +#[derive(Copy, Clone)] +struct Adt<'a>(&'a ()); + +const C: Option<(unsafe<'a> Adt<'a>, Box)> = None; + +fn main() { + match None { + C => {} + //~^ ERROR constant of non-structural type + _ => {} + } +} diff --git a/tests/ui/unsafe-binders/non-strucutral-type-diag.stderr b/tests/ui/unsafe-binders/non-strucutral-type-diag.stderr new file mode 100644 index 0000000000000..ab23210b2e577 --- /dev/null +++ b/tests/ui/unsafe-binders/non-strucutral-type-diag.stderr @@ -0,0 +1,13 @@ +error: constant of non-structural type `Option<(unsafe<'a> Adt<'a>, Box)>` in a pattern + --> $DIR/non-strucutral-type-diag.rs:13:9 + | +LL | const C: Option<(unsafe<'a> Adt<'a>, Box)> = None; + | ---------------------------------------------------- constant defined here +... +LL | C => {} + | ^ constant of non-structural type + | + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details + +error: aborting due to 1 previous error + From 04ddafc53ce0e045bae86ad0b20f5be540ca0e84 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 23 May 2025 10:18:05 +0000 Subject: [PATCH 2651/4206] Properly analyze captures from unsafe binders --- .../rustc_hir_typeck/src/expr_use_visitor.rs | 16 +++++++++++--- compiler/rustc_hir_typeck/src/upvar.rs | 8 +++++-- compiler/rustc_middle/src/hir/place.rs | 3 +++ .../src/builder/expr/as_place.rs | 3 +++ compiler/rustc_mir_build/src/thir/cx/expr.rs | 3 +++ src/tools/clippy/clippy_utils/src/sugg.rs | 2 ++ tests/ui/unsafe-binders/cat-projection.rs | 21 +++++++++++++++++++ 7 files changed, 51 insertions(+), 5 deletions(-) create mode 100644 tests/ui/unsafe-binders/cat-projection.rs diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 3493d359028d9..2034131882820 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -13,6 +13,7 @@ use hir::Expr; use hir::def::DefKind; use hir::pat_util::EnumerateAndAdjustIterator as _; use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx}; +use rustc_ast::UnsafeBinderCastKind; use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def::{CtorOf, Res}; use rustc_hir::def_id::LocalDefId; @@ -1393,10 +1394,18 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx self.cat_res(expr.hir_id, expr.span, expr_ty, res) } - // both type ascription and unsafe binder casts don't affect - // the place-ness of the subexpression. + // type ascription doesn't affect the place-ness of the subexpression. hir::ExprKind::Type(e, _) => self.cat_expr(e), - hir::ExprKind::UnsafeBinderCast(_, e, _) => self.cat_expr(e), + + hir::ExprKind::UnsafeBinderCast(UnsafeBinderCastKind::Unwrap, e, _) => { + let base = self.cat_expr(e)?; + Ok(self.cat_projection( + expr.hir_id, + base, + expr_ty, + ProjectionKind::UnwrapUnsafeBinder, + )) + } hir::ExprKind::AddrOf(..) | hir::ExprKind::Call(..) @@ -1427,6 +1436,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx | hir::ExprKind::Repeat(..) | hir::ExprKind::InlineAsm(..) | hir::ExprKind::OffsetOf(..) + | hir::ExprKind::UnsafeBinderCast(UnsafeBinderCastKind::Wrap, ..) | hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr_ty)), } } diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 8ab71e5220bb7..4b2e87f5674a6 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -902,7 +902,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn is_field<'a>(p: &&Projection<'a>) -> bool { match p.kind { ProjectionKind::Field(_, _) => true, - ProjectionKind::Deref | ProjectionKind::OpaqueCast => false, + ProjectionKind::Deref + | ProjectionKind::OpaqueCast + | ProjectionKind::UnwrapUnsafeBinder => false, p @ (ProjectionKind::Subslice | ProjectionKind::Index) => { bug!("ProjectionKind {:?} was unexpected", p) } @@ -2197,7 +2199,8 @@ fn restrict_capture_precision( } ProjectionKind::Deref => {} ProjectionKind::OpaqueCast => {} - ProjectionKind::Field(..) => {} // ignore + ProjectionKind::Field(..) => {} + ProjectionKind::UnwrapUnsafeBinder => {} } } @@ -2268,6 +2271,7 @@ fn construct_place_string<'tcx>(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String ProjectionKind::Index => String::from("Index"), ProjectionKind::Subslice => String::from("Subslice"), ProjectionKind::OpaqueCast => String::from("OpaqueCast"), + ProjectionKind::UnwrapUnsafeBinder => String::from("UnwrapUnsafeBinder"), }; if i != 0 { projections_str.push(','); diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs index c3d10615cf10c..a34a3419d68b2 100644 --- a/compiler/rustc_middle/src/hir/place.rs +++ b/compiler/rustc_middle/src/hir/place.rs @@ -43,6 +43,9 @@ pub enum ProjectionKind { /// /// This is unused if `-Znext-solver` is enabled. OpaqueCast, + + /// `unwrap_binder!(expr)` + UnwrapUnsafeBinder, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs index fbe530811567f..830a129c58542 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs @@ -240,6 +240,9 @@ fn strip_prefix<'tcx>( HirProjectionKind::OpaqueCast => { assert_matches!(iter.next(), Some(ProjectionElem::OpaqueCast(..))); } + HirProjectionKind::UnwrapUnsafeBinder => { + assert_matches!(iter.next(), Some(ProjectionElem::UnwrapUnsafeBinder(..))); + } HirProjectionKind::Index | HirProjectionKind::Subslice => { bug!("unexpected projection kind: {:?}", projection); } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index fde23413972b6..226dc920a496c 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -1220,6 +1220,9 @@ impl<'tcx> ThirBuildCx<'tcx> { HirProjectionKind::OpaqueCast => { ExprKind::Use { source: self.thir.exprs.push(captured_place_expr) } } + HirProjectionKind::UnwrapUnsafeBinder => ExprKind::PlaceUnwrapUnsafeBinder { + source: self.thir.exprs.push(captured_place_expr), + }, HirProjectionKind::Index | HirProjectionKind::Subslice => { // We don't capture these projections, so we can ignore them here continue; diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 93dec113d31a5..f4dfc8f4b5a7f 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -941,6 +941,8 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { ProjectionKind::Subslice | // Doesn't have surface syntax. Only occurs in patterns. ProjectionKind::OpaqueCast => (), + // Only occurs in closure captures. + ProjectionKind::UnwrapUnsafeBinder => (), ProjectionKind::Deref => { // Explicit derefs are typically handled later on, but // some items do not need explicit deref, such as array accesses, diff --git a/tests/ui/unsafe-binders/cat-projection.rs b/tests/ui/unsafe-binders/cat-projection.rs new file mode 100644 index 0000000000000..dd7a78d59b364 --- /dev/null +++ b/tests/ui/unsafe-binders/cat-projection.rs @@ -0,0 +1,21 @@ +//@ check-pass + +#![feature(unsafe_binders)] +#![allow(incomplete_features)] + +use std::unsafe_binder::unwrap_binder; + +#[derive(Copy, Clone)] +pub struct S([usize; 8]); + +// Regression test for . +pub fn by_value(x: unsafe<'a> S) -> usize { + unsafe { (|| unwrap_binder!(x).0[0])() } +} + +// Regression test for . +pub fn by_ref(x: unsafe<'a> &'a S) -> usize { + unsafe { (|| unwrap_binder!(x).0[0])() } +} + +fn main() {} From 6059d59548f94a43b346b0b95c7a74e2dd9b1aa0 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 23 May 2025 10:18:05 +0000 Subject: [PATCH 2652/4206] Properly analyze captures from unsafe binders --- clippy_utils/src/sugg.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index 93dec113d31a5..f4dfc8f4b5a7f 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -941,6 +941,8 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { ProjectionKind::Subslice | // Doesn't have surface syntax. Only occurs in patterns. ProjectionKind::OpaqueCast => (), + // Only occurs in closure captures. + ProjectionKind::UnwrapUnsafeBinder => (), ProjectionKind::Deref => { // Explicit derefs are typically handled later on, but // some items do not need explicit deref, such as array accesses, From 11392f4978fe3a81a87e4fd8abcb78a0dcf166e5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 23 May 2025 09:44:22 +0000 Subject: [PATCH 2653/4206] Emit dummy open drop for unsafe binder --- .../rustc_mir_transform/src/elaborate_drop.rs | 17 +++++++++++++++++ tests/ui/unsafe/move-out-of-non-copy.rs | 15 +++++++++++++++ tests/ui/unsafe/move-out-of-non-copy.stderr | 14 ++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 tests/ui/unsafe/move-out-of-non-copy.rs create mode 100644 tests/ui/unsafe/move-out-of-non-copy.stderr diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index 14f7c2a263b62..211e2a92f73d8 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -1278,6 +1278,23 @@ where } ty::Slice(ety) => self.drop_loop_trio_for_slice(*ety), + ty::UnsafeBinder(_) => { + // Unsafe binders may elaborate drops if their inner type isn't copy. + // This is enforced in typeck, so this should never happen. + self.tcx().dcx().span_delayed_bug( + self.source_info.span, + "open drop for unsafe binder shouldn't be encountered", + ); + self.elaborator.patch().new_block(BasicBlockData { + statements: vec![], + terminator: Some(Terminator { + source_info: self.source_info, + kind: TerminatorKind::Unreachable, + }), + is_cleanup: self.unwind.is_cleanup(), + }) + } + _ => span_bug!(self.source_info.span, "open drop from non-ADT `{:?}`", ty), } } diff --git a/tests/ui/unsafe/move-out-of-non-copy.rs b/tests/ui/unsafe/move-out-of-non-copy.rs new file mode 100644 index 0000000000000..ca6bf4277a152 --- /dev/null +++ b/tests/ui/unsafe/move-out-of-non-copy.rs @@ -0,0 +1,15 @@ +//@ compile-flags: -Zvalidate-mir + +// Regression test for . + +#![feature(unsafe_binders)] +#![allow(incomplete_features)] + +use std::unsafe_binder::unwrap_binder; + +fn id(x: unsafe<> T) -> T { + //~^ ERROR the trait bound `T: Copy` is not satisfied + unsafe { unwrap_binder!(x) } +} + +fn main() {} diff --git a/tests/ui/unsafe/move-out-of-non-copy.stderr b/tests/ui/unsafe/move-out-of-non-copy.stderr new file mode 100644 index 0000000000000..4598742c92b43 --- /dev/null +++ b/tests/ui/unsafe/move-out-of-non-copy.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `T: Copy` is not satisfied + --> $DIR/move-out-of-non-copy.rs:10:13 + | +LL | fn id(x: unsafe<> T) -> T { + | ^^^^^^^^^^ the trait `Copy` is not implemented for `T` + | +help: consider restricting type parameter `T` with trait `Copy` + | +LL | fn id(x: unsafe<> T) -> T { + | +++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From 89a8abc4bea115c3508ee5ac4eb9ac3a55920316 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 21 May 2025 19:18:31 +0200 Subject: [PATCH 2654/4206] use `cfg_select!` to select the right `VaListImpl` definition --- library/core/src/ffi/va_list.rs | 311 ++++++++++++++------------------ 1 file changed, 136 insertions(+), 175 deletions(-) diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs index f12bd289f27aa..8f7c090bc1ba2 100644 --- a/library/core/src/ffi/va_list.rs +++ b/library/core/src/ffi/va_list.rs @@ -5,148 +5,120 @@ use crate::ffi::c_void; #[allow(unused_imports)] use crate::fmt; -use crate::marker::PhantomData; +use crate::marker::{PhantomData, PhantomInvariantLifetime}; use crate::ops::{Deref, DerefMut}; -/// Basic implementation of a `va_list`. // The name is WIP, using `VaListImpl` for now. -#[cfg(any( +// +// Most targets explicitly specify the layout of `va_list`, this layout is matched here. +crate::cfg_select! { all( - not(target_arch = "aarch64"), - not(target_arch = "powerpc"), - not(target_arch = "s390x"), - not(target_arch = "xtensa"), - not(target_arch = "x86_64") - ), - all(target_arch = "aarch64", target_vendor = "apple"), - target_family = "wasm", - target_os = "uefi", - windows, -))] -#[repr(transparent)] -#[lang = "va_list"] -pub struct VaListImpl<'f> { - ptr: *mut c_void, - - // Invariant over `'f`, so each `VaListImpl<'f>` object is tied to - // the region of the function it's defined in - _marker: PhantomData<&'f mut &'f c_void>, -} - -#[cfg(any( - all( - not(target_arch = "aarch64"), - not(target_arch = "powerpc"), - not(target_arch = "s390x"), - not(target_arch = "xtensa"), - not(target_arch = "x86_64") - ), - all(target_arch = "aarch64", target_vendor = "apple"), - target_family = "wasm", - target_os = "uefi", - windows, -))] -impl<'f> fmt::Debug for VaListImpl<'f> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "va_list* {:p}", self.ptr) + target_arch = "aarch64", + not(target_vendor = "apple"), + not(target_os = "uefi"), + not(windows), + ) => { + /// AArch64 ABI implementation of a `va_list`. See the + /// [AArch64 Procedure Call Standard] for more details. + /// + /// [AArch64 Procedure Call Standard]: + /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf + #[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 + #[derive(Debug)] + #[lang = "va_list"] + pub struct VaListImpl<'f> { + stack: *mut c_void, + gr_top: *mut c_void, + vr_top: *mut c_void, + gr_offs: i32, + vr_offs: i32, + _marker: PhantomInvariantLifetime<'f>, + } + } + all(target_arch = "powerpc", not(target_os = "uefi"), not(windows)) => { + /// PowerPC ABI implementation of a `va_list`. + #[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 + #[derive(Debug)] + #[lang = "va_list"] + pub struct VaListImpl<'f> { + gpr: u8, + fpr: u8, + reserved: u16, + overflow_arg_area: *mut c_void, + reg_save_area: *mut c_void, + _marker: PhantomInvariantLifetime<'f>, + } + } + target_arch = "s390x" => { + /// s390x ABI implementation of a `va_list`. + #[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 + #[derive(Debug)] + #[lang = "va_list"] + pub struct VaListImpl<'f> { + gpr: i64, + fpr: i64, + overflow_arg_area: *mut c_void, + reg_save_area: *mut c_void, + _marker: PhantomInvariantLifetime<'f>, + } + } + all(target_arch = "x86_64", not(target_os = "uefi"), not(windows)) => { + /// x86_64 ABI implementation of a `va_list`. + #[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 + #[derive(Debug)] + #[lang = "va_list"] + pub struct VaListImpl<'f> { + gp_offset: i32, + fp_offset: i32, + overflow_arg_area: *mut c_void, + reg_save_area: *mut c_void, + _marker: PhantomInvariantLifetime<'f>, + } + } + target_arch = "xtensa" => { + /// Xtensa ABI implementation of a `va_list`. + #[repr(C)] + #[derive(Debug)] + #[lang = "va_list"] + pub struct VaListImpl<'f> { + stk: *mut i32, + reg: *mut i32, + ndx: i32, + _marker: PhantomInvariantLifetime<'f>, + } } -} - -/// AArch64 ABI implementation of a `va_list`. See the -/// [AArch64 Procedure Call Standard] for more details. -/// -/// [AArch64 Procedure Call Standard]: -/// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf -#[cfg(all( - target_arch = "aarch64", - not(target_vendor = "apple"), - not(target_os = "uefi"), - not(windows), -))] -#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 -#[derive(Debug)] -#[lang = "va_list"] -pub struct VaListImpl<'f> { - stack: *mut c_void, - gr_top: *mut c_void, - vr_top: *mut c_void, - gr_offs: i32, - vr_offs: i32, - _marker: PhantomData<&'f mut &'f c_void>, -} - -/// PowerPC ABI implementation of a `va_list`. -#[cfg(all(target_arch = "powerpc", not(target_os = "uefi"), not(windows)))] -#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 -#[derive(Debug)] -#[lang = "va_list"] -pub struct VaListImpl<'f> { - gpr: u8, - fpr: u8, - reserved: u16, - overflow_arg_area: *mut c_void, - reg_save_area: *mut c_void, - _marker: PhantomData<&'f mut &'f c_void>, -} - -/// s390x ABI implementation of a `va_list`. -#[cfg(target_arch = "s390x")] -#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 -#[derive(Debug)] -#[lang = "va_list"] -pub struct VaListImpl<'f> { - gpr: i64, - fpr: i64, - overflow_arg_area: *mut c_void, - reg_save_area: *mut c_void, - _marker: PhantomData<&'f mut &'f c_void>, -} -/// x86_64 ABI implementation of a `va_list`. -#[cfg(all(target_arch = "x86_64", not(target_os = "uefi"), not(windows)))] -#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 -#[derive(Debug)] -#[lang = "va_list"] -pub struct VaListImpl<'f> { - gp_offset: i32, - fp_offset: i32, - overflow_arg_area: *mut c_void, - reg_save_area: *mut c_void, - _marker: PhantomData<&'f mut &'f c_void>, -} + // The fallback implementation, used for: + // + // - apple aarch64 (see https://github.com/rust-lang/rust/pull/56599) + // - windows + // - uefi + // - any other target for which we don't specify the `VaListImpl` above + // + // In this implementation the `va_list` type is just an alias for an opaque pointer. + // That pointer is probably just the next variadic argument on the caller's stack. + _ => { + /// Basic implementation of a `va_list`. + #[repr(transparent)] + #[lang = "va_list"] + pub struct VaListImpl<'f> { + ptr: *mut c_void, + + // Invariant over `'f`, so each `VaListImpl<'f>` object is tied to + // the region of the function it's defined in + _marker: PhantomInvariantLifetime<'f>, + } -/// Xtensa ABI implementation of a `va_list`. -#[cfg(target_arch = "xtensa")] -#[repr(C)] -#[derive(Debug)] -#[lang = "va_list"] -pub struct VaListImpl<'f> { - stk: *mut i32, - reg: *mut i32, - ndx: i32, - _marker: PhantomData<&'f mut &'f c_void>, + impl<'f> fmt::Debug for VaListImpl<'f> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "va_list* {:p}", self.ptr) + } + } + } } -/// A wrapper for a `va_list` -#[repr(transparent)] -#[derive(Debug)] -pub struct VaList<'a, 'f: 'a> { - #[cfg(any( - all( - not(target_arch = "aarch64"), - not(target_arch = "powerpc"), - not(target_arch = "s390x"), - not(target_arch = "x86_64") - ), - target_arch = "xtensa", - all(target_arch = "aarch64", target_vendor = "apple"), - target_family = "wasm", - target_os = "uefi", - windows, - ))] - inner: VaListImpl<'f>, - - #[cfg(all( +crate::cfg_select! { + all( any( target_arch = "aarch64", target_arch = "powerpc", @@ -158,52 +130,41 @@ pub struct VaList<'a, 'f: 'a> { not(target_family = "wasm"), not(target_os = "uefi"), not(windows), - ))] - inner: &'a mut VaListImpl<'f>, + ) => { + /// A wrapper for a `va_list` + #[repr(transparent)] + #[derive(Debug)] + pub struct VaList<'a, 'f: 'a> { + inner: &'a mut VaListImpl<'f>, + _marker: PhantomData<&'a mut VaListImpl<'f>>, + } - _marker: PhantomData<&'a mut VaListImpl<'f>>, -} -#[cfg(any( - all( - not(target_arch = "aarch64"), - not(target_arch = "powerpc"), - not(target_arch = "s390x"), - not(target_arch = "x86_64") - ), - target_arch = "xtensa", - all(target_arch = "aarch64", target_vendor = "apple"), - target_family = "wasm", - target_os = "uefi", - windows, -))] -impl<'f> VaListImpl<'f> { - /// Converts a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`. - #[inline] - pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> { - VaList { inner: VaListImpl { ..*self }, _marker: PhantomData } + impl<'f> VaListImpl<'f> { + /// Converts a [`VaListImpl`] into a [`VaList`] that is binary-compatible with C's `va_list`. + #[inline] + pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> { + VaList { inner: self, _marker: PhantomData } + } + } } -} -#[cfg(all( - any( - target_arch = "aarch64", - target_arch = "powerpc", - target_arch = "s390x", - target_arch = "xtensa", - target_arch = "x86_64" - ), - not(target_arch = "xtensa"), - any(not(target_arch = "aarch64"), not(target_vendor = "apple")), - not(target_family = "wasm"), - not(target_os = "uefi"), - not(windows), -))] -impl<'f> VaListImpl<'f> { - /// Converts a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`. - #[inline] - pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> { - VaList { inner: self, _marker: PhantomData } + _ => { + /// A wrapper for a `va_list` + #[repr(transparent)] + #[derive(Debug)] + pub struct VaList<'a, 'f: 'a> { + inner: VaListImpl<'f>, + _marker: PhantomData<&'a mut VaListImpl<'f>>, + } + + impl<'f> VaListImpl<'f> { + /// Converts a [`VaListImpl`] into a [`VaList`] that is binary-compatible with C's `va_list`. + #[inline] + pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> { + VaList { inner: VaListImpl { ..*self }, _marker: PhantomData } + } + } } } From 69ba323c1ca1faba14ace7cec19dd5b738367960 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 23 May 2025 12:57:07 +0200 Subject: [PATCH 2655/4206] Bump salsa --- src/tools/rust-analyzer/Cargo.lock | 241 ++---------------- src/tools/rust-analyzer/Cargo.toml | 7 +- .../rust-analyzer/crates/base-db/src/input.rs | 12 +- .../rust-analyzer/crates/base-db/src/lib.rs | 4 +- .../crates/hir-def/src/lang_item.rs | 2 +- .../crates/hir-def/src/nameres.rs | 8 +- .../crates/hir-def/src/test_db.rs | 23 +- .../crates/hir-ty/src/test_db.rs | 22 +- .../rust-analyzer/crates/ide-db/src/lib.rs | 4 +- .../query-group-macro/tests/logger_db.rs | 40 +-- 10 files changed, 83 insertions(+), 280 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index bd8146defae95..01de430925dca 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -17,15 +17,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - [[package]] name = "allocator-api2" version = "0.2.21" @@ -124,12 +115,9 @@ dependencies = [ [[package]] name = "boxcar" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6740c6e2fc6360fa57c35214c7493826aee95993926092606f27c983b40837be" -dependencies = [ - "loom", -] +checksum = "66bb12751a83493ef4b8da1120451a262554e216a247f14b48cb5e8fe7ed8bdf" [[package]] name = "camino" @@ -511,19 +499,6 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a" -[[package]] -name = "generator" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6bd114ceda131d3b1d665eba35788690ad37f5916457286b32ab6fd3c438dd" -dependencies = [ - "cfg-if", - "libc", - "log", - "rustversion", - "windows 0.58.0", -] - [[package]] name = "getrandom" version = "0.2.15" @@ -1213,19 +1188,6 @@ version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" -[[package]] -name = "loom" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" -dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "tracing", - "tracing-subscriber", -] - [[package]] name = "lsp-server" version = "0.7.8" @@ -1265,15 +1227,6 @@ dependencies = [ "url", ] -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - [[package]] name = "mbe" version = "0.0.0" @@ -1400,16 +1353,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d" -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - [[package]] name = "nu-ansi-term" version = "0.50.1" @@ -1471,12 +1414,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - [[package]] name = "parking_lot" version = "0.12.3" @@ -1648,7 +1585,7 @@ dependencies = [ "indexmap", "nix", "tracing", - "windows 0.61.1", + "windows", ] [[package]] @@ -1864,50 +1801,6 @@ dependencies = [ "thiserror 2.0.12", ] -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata 0.4.9", - "regex-syntax 0.8.5", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.5", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - [[package]] name = "rowan" version = "0.15.15" @@ -2026,12 +1919,6 @@ dependencies = [ "smallvec", ] -[[package]] -name = "rustversion" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" - [[package]] name = "ryu" version = "1.0.20" @@ -2040,9 +1927,9 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "salsa" -version = "0.21.1" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f80d5cf3c3fcab2cef898012f242a670477a1baa609267376af9cb4409026c5" +checksum = "c8fff508e3d6ef42a32607f7538e17171a877a12015e32036f46e99d00c95781" dependencies = [ "boxcar", "crossbeam-queue", @@ -2063,15 +1950,15 @@ dependencies = [ [[package]] name = "salsa-macro-rules" -version = "0.21.1" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05303d72606fbf2b9c9523cda2039bb8ecb00304027a3cd7e52b02a65c7d9185" +checksum = "8ea72b3c06f2ce6350fe3a0eeb7aaaf842d1d8352b706973c19c4f02e298a87c" [[package]] name = "salsa-macros" -version = "0.21.1" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb2f0e2a30c65cb3cd63440c491dde68d9af7e1be2b77832ac7057141107db50" +checksum = "0ce92025bc160b27814a207cb78d680973af17f863c7f4fc56cf3a535e22f378" dependencies = [ "heck", "proc-macro2", @@ -2556,15 +2443,9 @@ version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ - "matchers", - "nu-ansi-term 0.46.0", - "once_cell", - "regex", "sharded-slab", - "smallvec", "thread_local", "time", - "tracing", "tracing-core", "tracing-log", ] @@ -2575,7 +2456,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f459ca79f1b0d5f71c54ddfde6debfc59c8b6eeb46808ae492077f739dc7b49c" dependencies = [ - "nu-ansi-term 0.50.1", + "nu-ansi-term", "tracing-core", "tracing-log", "tracing-subscriber", @@ -2709,22 +2590,6 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - [[package]] name = "winapi-util" version = "0.1.9" @@ -2734,22 +2599,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" -dependencies = [ - "windows-core 0.58.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows" version = "0.61.1" @@ -2757,7 +2606,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419" dependencies = [ "windows-collections", - "windows-core 0.61.0", + "windows-core", "windows-future", "windows-link", "windows-numerics", @@ -2769,20 +2618,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ - "windows-core 0.61.0", -] - -[[package]] -name = "windows-core" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" -dependencies = [ - "windows-implement 0.58.0", - "windows-interface 0.58.0", - "windows-result 0.2.0", - "windows-strings 0.1.0", - "windows-targets 0.52.6", + "windows-core", ] [[package]] @@ -2791,11 +2627,11 @@ version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" dependencies = [ - "windows-implement 0.60.0", - "windows-interface 0.59.1", + "windows-implement", + "windows-interface", "windows-link", - "windows-result 0.3.2", - "windows-strings 0.4.0", + "windows-result", + "windows-strings", ] [[package]] @@ -2804,21 +2640,10 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32" dependencies = [ - "windows-core 0.61.0", + "windows-core", "windows-link", ] -[[package]] -name = "windows-implement" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "windows-implement" version = "0.60.0" @@ -2830,17 +2655,6 @@ dependencies = [ "syn", ] -[[package]] -name = "windows-interface" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "windows-interface" version = "0.59.1" @@ -2864,19 +2678,10 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ - "windows-core 0.61.0", + "windows-core", "windows-link", ] -[[package]] -name = "windows-result" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-result" version = "0.3.2" @@ -2886,16 +2691,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-strings" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" -dependencies = [ - "windows-result 0.2.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows-strings" version = "0.4.0" diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 07731bae3f30f..8c50718984667 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -132,11 +132,8 @@ pulldown-cmark-to-cmark = "10.0.4" pulldown-cmark = { version = "0.9.6", default-features = false } rayon = "1.10.0" rowan = "=0.15.15" -salsa = { version = "0.21.1", default-features = false, features = [ - "rayon", - "salsa_unstable", -] } -salsa-macros = "0.21.1" +salsa = { version = "0.22.0", default-features = false, features = ["rayon","salsa_unstable"] } +salsa-macros = "0.22.0" semver = "1.0.26" serde = { version = "1.0.219" } serde_derive = { version = "1.0.219" } diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs index d42d7e5707d34..745238167bc17 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/input.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs @@ -395,21 +395,21 @@ impl BuiltDependency { pub type CratesIdMap = FxHashMap; #[salsa_macros::input] -#[derive(Debug)] +#[derive(Debug, PartialOrd, Ord)] pub struct Crate { - #[return_ref] + #[returns(ref)] pub data: BuiltCrateData, /// Crate data that is not needed for analysis. /// /// This is split into a separate field to increase incrementality. - #[return_ref] + #[returns(ref)] pub extra_data: ExtraCrateData, // This is in `Arc` because it is shared for all crates in a workspace. - #[return_ref] + #[returns(ref)] pub workspace_data: Arc, - #[return_ref] + #[returns(ref)] pub cfg_options: CfgOptions, - #[return_ref] + #[returns(ref)] pub env: Env, } diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index a67fbf75c02f1..4d4e6cae0373a 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -32,6 +32,7 @@ pub use vfs::{AnchoredPath, AnchoredPathBuf, FileId, VfsPath, file_set::FileSet} macro_rules! impl_intern_key { ($id:ident, $loc:ident) => { #[salsa_macros::interned(no_lifetime)] + #[derive(PartialOrd, Ord)] pub struct $id { pub loc: $loc, } @@ -165,6 +166,7 @@ impl Files { } #[salsa_macros::interned(no_lifetime, debug, constructor=from_span)] +#[derive(PartialOrd, Ord)] pub struct EditionedFileId { pub editioned_file_id: span::EditionedFileId, } @@ -356,7 +358,7 @@ fn parse(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Parse Option<&[SyntaxError]> { - #[salsa_macros::tracked(return_ref)] + #[salsa_macros::tracked(returns(ref))] fn parse_errors(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Option> { let errors = db.parse(file_id).errors(); match &*errors { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index 59344641f47af..4ad44775ea141 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -85,7 +85,7 @@ impl LangItemTarget { } /// Salsa query. This will look for lang items in a specific crate. -#[salsa_macros::tracked(return_ref)] +#[salsa_macros::tracked(returns(ref))] pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option> { let _p = tracing::info_span!("crate_lang_items_query").entered(); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs index d4b30a1d3e68b..f337f83156a96 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs @@ -381,15 +381,15 @@ mod __ { #[salsa_macros::tracked] pub(crate) struct DefMapPair<'db> { #[tracked] - #[return_ref] + #[returns(ref)] pub(crate) def_map: DefMap, - #[return_ref] + #[returns(ref)] pub(crate) local: LocalDefMap, } } pub(crate) use __::DefMapPair; -#[salsa_macros::tracked(return_ref)] +#[salsa_macros::tracked(returns(ref))] pub(crate) fn crate_local_def_map(db: &dyn DefDatabase, crate_id: Crate) -> DefMapPair<'_> { let krate = crate_id.data(db); let _p = tracing::info_span!( @@ -420,7 +420,7 @@ pub(crate) fn crate_local_def_map(db: &dyn DefDatabase, crate_id: Crate) -> DefM DefMapPair::new(db, def_map, local_def_map) } -#[salsa_macros::tracked(return_ref)] +#[salsa_macros::tracked(returns(ref))] pub fn block_def_map(db: &dyn DefDatabase, block_id: BlockId) -> DefMap { let BlockLoc { ast_id, module } = block_id.lookup(db); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs index 6c995ab6c23f7..e30a5b65a1f79 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs @@ -30,9 +30,18 @@ pub(crate) struct TestDB { impl Default for TestDB { fn default() -> Self { + let events = >>>>::default(); let mut this = Self { - storage: Default::default(), - events: Default::default(), + storage: salsa::Storage::new(Some(Box::new({ + let events = events.clone(); + move |event| { + let mut events = events.lock().unwrap(); + if let Some(events) = &mut *events { + events.push(event); + } + } + }))), + events, files: Default::default(), crates_map: Default::default(), }; @@ -45,15 +54,7 @@ impl Default for TestDB { } #[salsa_macros::db] -impl salsa::Database for TestDB { - fn salsa_event(&self, event: &dyn std::ops::Fn() -> salsa::Event) { - let mut events = self.events.lock().unwrap(); - if let Some(events) = &mut *events { - let event = event(); - events.push(event); - } - } -} +impl salsa::Database for TestDB {} impl fmt::Debug for TestDB { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs index 8f0d17c9dc4e9..d049c678e2db5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs @@ -27,9 +27,18 @@ pub(crate) struct TestDB { impl Default for TestDB { fn default() -> Self { + let events = >>>>::default(); let mut this = Self { - storage: Default::default(), - events: Default::default(), + storage: salsa::Storage::new(Some(Box::new({ + let events = events.clone(); + move |event| { + let mut events = events.lock().unwrap(); + if let Some(events) = &mut *events { + events.push(event); + } + } + }))), + events, files: Default::default(), crates_map: Default::default(), }; @@ -103,14 +112,7 @@ impl SourceDatabase for TestDB { } #[salsa_macros::db] -impl salsa::Database for TestDB { - fn salsa_event(&self, event: &dyn std::ops::Fn() -> salsa::Event) { - let mut events = self.events.lock().unwrap(); - if let Some(events) = &mut *events { - events.push(event()); - } - } -} +impl salsa::Database for TestDB {} impl panic::RefUnwindSafe for TestDB {} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs index 63cc7cde28081..c94be7e164e27 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs @@ -92,9 +92,7 @@ pub struct RootDatabase { impl std::panic::RefUnwindSafe for RootDatabase {} #[salsa_macros::db] -impl salsa::Database for RootDatabase { - fn salsa_event(&self, _event: &dyn Fn() -> salsa::Event) {} -} +impl salsa::Database for RootDatabase {} impl Drop for RootDatabase { fn drop(&mut self) { diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs index bade0c2cd6faa..71af63a0d3b8b 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs +++ b/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs @@ -1,33 +1,41 @@ use std::sync::{Arc, Mutex}; #[salsa_macros::db] -#[derive(Default, Clone)] +#[derive(Clone)] pub(crate) struct LoggerDb { storage: salsa::Storage, logger: Logger, } +impl Default for LoggerDb { + fn default() -> Self { + let logger = Logger::default(); + Self { + storage: salsa::Storage::new(Some(Box::new({ + let logger = logger.clone(); + move |event| match event.kind { + salsa::EventKind::WillExecute { .. } + | salsa::EventKind::WillCheckCancellation + | salsa::EventKind::DidValidateMemoizedValue { .. } + | salsa::EventKind::WillDiscardStaleOutput { .. } + | salsa::EventKind::DidDiscard { .. } => { + logger.logs.lock().unwrap().push(format!("salsa_event({:?})", event.kind)); + } + _ => {} + } + }))), + logger, + } + } +} + #[derive(Default, Clone)] struct Logger { logs: Arc>>, } #[salsa_macros::db] -impl salsa::Database for LoggerDb { - fn salsa_event(&self, event: &dyn Fn() -> salsa::Event) { - let event = event(); - match event.kind { - salsa::EventKind::WillExecute { .. } - | salsa::EventKind::WillCheckCancellation - | salsa::EventKind::DidValidateMemoizedValue { .. } - | salsa::EventKind::WillDiscardStaleOutput { .. } - | salsa::EventKind::DidDiscard { .. } => { - self.push_log(format!("salsa_event({:?})", event.kind)); - } - _ => {} - } - } -} +impl salsa::Database for LoggerDb {} impl LoggerDb { /// Log an event from inside a tracked function. From c364717b15dc7db94ea1f986c2388726b4cc34c3 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Tue, 13 May 2025 21:45:57 +0200 Subject: [PATCH 2656/4206] `needless_return`: look inside `else if` parts as well `if` expressions don't necessarily contain a block in the `else` part in the presence of an `else if`. The `else` part, if present, must be handled as a regular expression, not necessarily as a block expression. --- clippy_lints/src/panic_unimplemented.rs | 1 - clippy_lints/src/returns.rs | 4 +- tests/ui/needless_return.fixed | 65 ++++++++++++++++ tests/ui/needless_return.rs | 65 ++++++++++++++++ tests/ui/needless_return.stderr | 98 ++++++++++++++++++++++++- 5 files changed, 230 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index 8962f36db1e69..449d3da763941 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -152,7 +152,6 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { expr.span, "`panic_any` should not be present in production code", ); - return; } } } diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 122d97fdf8193..7326d96985c85 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -428,7 +428,9 @@ fn check_final_expr<'tcx>( ExprKind::If(_, then, else_clause_opt) => { check_block_return(cx, &then.kind, peeled_drop_expr.span, semi_spans.clone()); if let Some(else_clause) = else_clause_opt { - check_block_return(cx, &else_clause.kind, peeled_drop_expr.span, semi_spans); + // The `RetReplacement` won't be used there as `else_clause` will be either a block or + // a `if` expression. + check_final_expr(cx, else_clause, semi_spans, RetReplacement::Empty, match_ty_opt); } }, // a match expr, check all arms diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index ad625ad6d5076..9b90171f5fbad 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -452,3 +452,68 @@ pub unsafe fn issue_12157() -> *const i32 { (unsafe { todo() } as *const i32) //~^ needless_return } + +mod else_ifs { + fn test1(a: i32) -> u32 { + if a == 0 { + 1 + //~^ needless_return + } else if a < 10 { + 2 + //~^ needless_return + } else { + 3 + //~^ needless_return + } + } + + fn test2(a: i32) -> u32 { + if a == 0 { + 1 + //~^ needless_return + } else if a < 10 { + 2 + } else { + 3 + //~^ needless_return + } + } + + fn test3(a: i32) -> u32 { + if a == 0 { + 1 + //~^ needless_return + } else if a < 10 { + 2 + } else { + 3 + //~^ needless_return + } + } + + #[allow(clippy::match_single_binding, clippy::redundant_pattern)] + fn test4(a: i32) -> u32 { + if a == 0 { + 1 + //~^ needless_return + } else if if if a > 0x1_1 { + return 2; + } else { + return 5; + } { + true + } else { + true + } { + 0xDEADC0DE + } else if match a { + b @ _ => { + return 1; + }, + } { + 0xDEADBEEF + } else { + 1 + } + } +} diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index 41d7e5bdd5065..fc4590c9cba7c 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -461,3 +461,68 @@ pub unsafe fn issue_12157() -> *const i32 { return unsafe { todo() } as *const i32; //~^ needless_return } + +mod else_ifs { + fn test1(a: i32) -> u32 { + if a == 0 { + return 1; + //~^ needless_return + } else if a < 10 { + return 2; + //~^ needless_return + } else { + return 3; + //~^ needless_return + } + } + + fn test2(a: i32) -> u32 { + if a == 0 { + return 1; + //~^ needless_return + } else if a < 10 { + 2 + } else { + return 3; + //~^ needless_return + } + } + + fn test3(a: i32) -> u32 { + if a == 0 { + return 1; + //~^ needless_return + } else if a < 10 { + 2 + } else { + return 3; + //~^ needless_return + } + } + + #[allow(clippy::match_single_binding, clippy::redundant_pattern)] + fn test4(a: i32) -> u32 { + if a == 0 { + return 1; + //~^ needless_return + } else if if if a > 0x1_1 { + return 2; + } else { + return 5; + } { + true + } else { + true + } { + 0xDEADC0DE + } else if match a { + b @ _ => { + return 1; + }, + } { + 0xDEADBEEF + } else { + 1 + } + } +} diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index 80863b9b62b20..212d662c9679a 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -703,5 +703,101 @@ LL - return unsafe { todo() } as *const i32; LL + (unsafe { todo() } as *const i32) | -error: aborting due to 55 previous errors +error: unneeded `return` statement + --> tests/ui/needless_return.rs:468:13 + | +LL | return 1; + | ^^^^^^^^ + | +help: remove `return` + | +LL - return 1; +LL + 1 + | + +error: unneeded `return` statement + --> tests/ui/needless_return.rs:471:13 + | +LL | return 2; + | ^^^^^^^^ + | +help: remove `return` + | +LL - return 2; +LL + 2 + | + +error: unneeded `return` statement + --> tests/ui/needless_return.rs:474:13 + | +LL | return 3; + | ^^^^^^^^ + | +help: remove `return` + | +LL - return 3; +LL + 3 + | + +error: unneeded `return` statement + --> tests/ui/needless_return.rs:481:13 + | +LL | return 1; + | ^^^^^^^^ + | +help: remove `return` + | +LL - return 1; +LL + 1 + | + +error: unneeded `return` statement + --> tests/ui/needless_return.rs:486:13 + | +LL | return 3; + | ^^^^^^^^ + | +help: remove `return` + | +LL - return 3; +LL + 3 + | + +error: unneeded `return` statement + --> tests/ui/needless_return.rs:493:13 + | +LL | return 1; + | ^^^^^^^^ + | +help: remove `return` + | +LL - return 1; +LL + 1 + | + +error: unneeded `return` statement + --> tests/ui/needless_return.rs:498:13 + | +LL | return 3; + | ^^^^^^^^ + | +help: remove `return` + | +LL - return 3; +LL + 3 + | + +error: unneeded `return` statement + --> tests/ui/needless_return.rs:506:13 + | +LL | return 1; + | ^^^^^^^^ + | +help: remove `return` + | +LL - return 1; +LL + 1 + | + +error: aborting due to 63 previous errors From 346ef86a58e678a50bd0bdb757acc86ec273c6f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 23 May 2025 13:27:17 +0200 Subject: [PATCH 2657/4206] Remove mentions of rust-lang-ci/rust Now that CI has been finally migrated to `rust-lang/rust`. --- src/doc/rustc-dev-guide/src/tests/ci.md | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/ci.md b/src/doc/rustc-dev-guide/src/tests/ci.md index 825be11c82a97..d8be8224dd0a0 100644 --- a/src/doc/rustc-dev-guide/src/tests/ci.md +++ b/src/doc/rustc-dev-guide/src/tests/ci.md @@ -100,8 +100,8 @@ Most platforms only run the build steps, some run a restricted set of tests, only a subset run the full suite of tests (see Rust's [platform tiers]). Auto jobs are defined in the `auto` section of [`jobs.yml`]. They are executed -on the `auto` branch under the `rust-lang-ci/rust` repository[^rust-lang-ci] and -their results can be seen [here](https://github.com/rust-lang-ci/rust/actions), +on the `auto` branch under the `rust-lang/rust` repository and +their results can be seen [here](https://github.com/rust-lang/rust/actions), although usually you will be notified of the result by a comment made by bors on the corresponding PR. @@ -110,9 +110,6 @@ more [here](#merging-prs-serially-with-bors). [platform tiers]: https://forge.rust-lang.org/release/platform-support.html#rust-platform-support -[^rust-lang-ci]: The `auto` and `try` jobs run under the `rust-lang-ci` fork for - historical reasons. This may change in the future. - ### Try builds Sometimes we want to run a subset of the test suite on CI for a given PR, or @@ -179,8 +176,8 @@ the pattern as Markdown. > that are exercised this way. Try jobs are defined in the `try` section of [`jobs.yml`]. They are executed on -the `try` branch under the `rust-lang-ci/rust` repository[^rust-lang-ci] and -their results can be seen [here](https://github.com/rust-lang-ci/rust/actions), +the `try` branch under the `rust-lang/rust` repository and +their results can be seen [here](https://github.com/rust-lang/rust/actions), although usually you will be notified of the result by a comment made by bors on the corresponding PR. @@ -355,7 +352,7 @@ invalidated if one of the following changes: - Files copied into the Docker image in the Dockerfile - The architecture of the GitHub runner (x86 or ARM) -[ghcr.io]: https://github.com/rust-lang-ci/rust/pkgs/container/rust-ci +[ghcr.io]: https://github.com/rust-lang/rust/pkgs/container/rust-ci [Docker registry caching]: https://docs.docker.com/build/cache/backends/registry/ ### LLVM caching with sccache @@ -446,7 +443,7 @@ particular job, it is probably easiest to just look at the build log. To do this: 1. Go to - + to find the most recently successful build, and click on it. 2. Choose the job you are interested in on the left-hand side. 3. Click on the gear icon and choose "View raw logs" @@ -458,7 +455,6 @@ this: [`jobs.yml`]: https://github.com/rust-lang/rust/blob/master/src/ci/github-actions/jobs.yml [`.github/workflows/ci.yml`]: https://github.com/rust-lang/rust/blob/master/.github/workflows/ci.yml [`src/ci/citool`]: https://github.com/rust-lang/rust/blob/master/src/ci/citool -[rust-lang-ci]: https://github.com/rust-lang-ci/rust/actions [bors]: https://github.com/bors [homu]: https://github.com/rust-lang/homu [merge queue]: https://bors.rust-lang.org/queue/rust From 326b7e9a6b3d33f7fda03419af3ed286d0262b7c Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 23 May 2025 10:12:55 +0000 Subject: [PATCH 2658/4206] yeet `CanonicalVarInfo` --- .../src/infer/canonical/canonicalizer.rs | 159 ++++++++---------- .../rustc_infer/src/infer/canonical/mod.rs | 8 +- .../src/infer/canonical/query_response.rs | 10 +- compiler/rustc_middle/src/infer/canonical.rs | 6 +- compiler/rustc_middle/src/ty/codec.rs | 6 +- compiler/rustc_middle/src/ty/context.rs | 21 ++- .../src/canonicalizer.rs | 62 +++---- .../rustc_next_trait_solver/src/delegate.rs | 2 +- .../src/solve/eval_ctxt/canonical.rs | 13 +- .../src/solve/eval_ctxt/mod.rs | 2 +- .../rustc_next_trait_solver/src/solve/mod.rs | 2 +- .../src/solve/delegate.rs | 6 +- compiler/rustc_type_ir/src/canonical.rs | 98 ++++------- compiler/rustc_type_ir/src/interner.rs | 9 +- ..._of_reborrow.SimplifyCfg-initial.after.mir | 36 ++-- ...ceiver_ptr_mutability.main.built.after.mir | 4 +- tests/rustdoc-js/auxiliary/interner.rs | 8 +- tests/rustdoc-js/looks-like-rustc-interner.js | 6 +- 18 files changed, 208 insertions(+), 250 deletions(-) diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index a1a0926cd8188..26ecaebe97f2d 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -17,8 +17,7 @@ use tracing::debug; use crate::infer::InferCtxt; use crate::infer::canonical::{ - Canonical, CanonicalQueryInput, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, - OriginalQueryValues, + Canonical, CanonicalQueryInput, CanonicalTyVarKind, CanonicalVarKind, OriginalQueryValues, }; impl<'tcx> InferCtxt<'tcx> { @@ -174,10 +173,8 @@ impl CanonicalizeMode for CanonicalizeQueryResponse { match r.kind() { ty::ReLateParam(_) | ty::ReErased | ty::ReStatic | ty::ReEarlyParam(..) => r, - ty::RePlaceholder(placeholder) => canonicalizer.canonical_var_for_region( - CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderRegion(placeholder) }, - r, - ), + ty::RePlaceholder(placeholder) => canonicalizer + .canonical_var_for_region(CanonicalVarKind::PlaceholderRegion(placeholder), r), ty::ReVar(vid) => { let universe = infcx @@ -186,10 +183,7 @@ impl CanonicalizeMode for CanonicalizeQueryResponse { .unwrap_region_constraints() .probe_value(vid) .unwrap_err(); - canonicalizer.canonical_var_for_region( - CanonicalVarInfo { kind: CanonicalVarKind::Region(universe) }, - r, - ) + canonicalizer.canonical_var_for_region(CanonicalVarKind::Region(universe), r) } _ => { @@ -294,7 +288,7 @@ struct Canonicalizer<'cx, 'tcx> { /// Set to `None` to disable the resolution of inference variables. infcx: Option<&'cx InferCtxt<'tcx>>, tcx: TyCtxt<'tcx>, - variables: SmallVec<[CanonicalVarInfo<'tcx>; 8]>, + variables: SmallVec<[CanonicalVarKind<'tcx>; 8]>, query_state: &'cx mut OriginalQueryValues<'tcx>, // Note that indices is only used once `var_values` is big enough to be // heap-allocated. @@ -368,9 +362,7 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { ui = ty::UniverseIndex::ROOT; } self.canonicalize_ty_var( - CanonicalVarInfo { - kind: CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)), - }, + CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)), t, ) } @@ -382,10 +374,7 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { if nt != t { return self.fold_ty(nt); } else { - self.canonicalize_ty_var( - CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int) }, - t, - ) + self.canonicalize_ty_var(CanonicalVarKind::Ty(CanonicalTyVarKind::Int), t) } } ty::Infer(ty::FloatVar(vid)) => { @@ -393,10 +382,7 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { if nt != t { return self.fold_ty(nt); } else { - self.canonicalize_ty_var( - CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float) }, - t, - ) + self.canonicalize_ty_var(CanonicalVarKind::Ty(CanonicalTyVarKind::Float), t) } } @@ -408,10 +394,7 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { if !self.canonicalize_mode.preserve_universes() { placeholder.universe = ty::UniverseIndex::ROOT; } - self.canonicalize_ty_var( - CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderTy(placeholder) }, - t, - ) + self.canonicalize_ty_var(CanonicalVarKind::PlaceholderTy(placeholder), t) } ty::Bound(debruijn, _) => { @@ -483,10 +466,7 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { // FIXME: perf problem described in #55921. ui = ty::UniverseIndex::ROOT; } - return self.canonicalize_const_var( - CanonicalVarInfo { kind: CanonicalVarKind::Const(ui) }, - ct, - ); + return self.canonicalize_const_var(CanonicalVarKind::Const(ui), ct); } } } @@ -501,10 +481,8 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { } } ty::ConstKind::Placeholder(placeholder) => { - return self.canonicalize_const_var( - CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderConst(placeholder) }, - ct, - ); + return self + .canonicalize_const_var(CanonicalVarKind::PlaceholderConst(placeholder), ct); } _ => {} } @@ -595,7 +573,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { debug_assert!(!out_value.has_infer() && !out_value.has_placeholders()); let canonical_variables = - tcx.mk_canonical_var_infos(&canonicalizer.universe_canonicalized_variables()); + tcx.mk_canonical_var_kinds(&canonicalizer.universe_canonicalized_variables()); let max_universe = canonical_variables .iter() @@ -610,18 +588,22 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { /// or returns an existing variable if `kind` has already been /// seen. `kind` is expected to be an unbound variable (or /// potentially a free region). - fn canonical_var(&mut self, info: CanonicalVarInfo<'tcx>, kind: GenericArg<'tcx>) -> BoundVar { + fn canonical_var( + &mut self, + var_kind: CanonicalVarKind<'tcx>, + value: GenericArg<'tcx>, + ) -> BoundVar { let Canonicalizer { variables, query_state, indices, .. } = self; let var_values = &mut query_state.var_values; - let universe = info.universe(); + let universe = var_kind.universe(); if universe != ty::UniverseIndex::ROOT { assert!(self.canonicalize_mode.preserve_universes()); // Insert universe into the universe map. To preserve the order of the // universes in the value being canonicalized, we don't update the - // universe in `info` until we have finished canonicalizing. + // universe in `var_kind` until we have finished canonicalizing. match query_state.universe_map.binary_search(&universe) { Err(idx) => query_state.universe_map.insert(idx, universe), Ok(_) => {} @@ -636,14 +618,14 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { if !var_values.spilled() { // `var_values` is stack-allocated. `indices` isn't used yet. Do a // direct linear search of `var_values`. - if let Some(idx) = var_values.iter().position(|&k| k == kind) { + if let Some(idx) = var_values.iter().position(|&v| v == value) { // `kind` is already present in `var_values`. BoundVar::new(idx) } else { // `kind` isn't present in `var_values`. Append it. Likewise - // for `info` and `variables`. - variables.push(info); - var_values.push(kind); + // for `var_kind` and `variables`. + variables.push(var_kind); + var_values.push(value); assert_eq!(variables.len(), var_values.len()); // If `var_values` has become big enough to be heap-allocated, @@ -653,7 +635,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { *indices = var_values .iter() .enumerate() - .map(|(i, &kind)| (kind, BoundVar::new(i))) + .map(|(i, &value)| (value, BoundVar::new(i))) .collect(); } // The cv is the index of the appended element. @@ -661,9 +643,9 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { } } else { // `var_values` is large. Do a hashmap search via `indices`. - *indices.entry(kind).or_insert_with(|| { - variables.push(info); - var_values.push(kind); + *indices.entry(value).or_insert_with(|| { + variables.push(var_kind); + var_values.push(value); assert_eq!(variables.len(), var_values.len()); BoundVar::new(variables.len() - 1) }) @@ -673,7 +655,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { /// Replaces the universe indexes used in `var_values` with their index in /// `query_state.universe_map`. This minimizes the maximum universe used in /// the canonicalized value. - fn universe_canonicalized_variables(self) -> SmallVec<[CanonicalVarInfo<'tcx>; 8]> { + fn universe_canonicalized_variables(self) -> SmallVec<[CanonicalVarKind<'tcx>; 8]> { if self.query_state.universe_map.len() == 1 { return self.variables; } @@ -688,37 +670,33 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { self.variables .iter() - .map(|v| CanonicalVarInfo { - kind: match v.kind { - CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => { - return *v; - } - CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => { - CanonicalVarKind::Ty(CanonicalTyVarKind::General(reverse_universe_map[&u])) - } - CanonicalVarKind::Region(u) => { - CanonicalVarKind::Region(reverse_universe_map[&u]) - } - CanonicalVarKind::Const(u) => CanonicalVarKind::Const(reverse_universe_map[&u]), - CanonicalVarKind::PlaceholderTy(placeholder) => { - CanonicalVarKind::PlaceholderTy(ty::Placeholder { - universe: reverse_universe_map[&placeholder.universe], - ..placeholder - }) - } - CanonicalVarKind::PlaceholderRegion(placeholder) => { - CanonicalVarKind::PlaceholderRegion(ty::Placeholder { - universe: reverse_universe_map[&placeholder.universe], - ..placeholder - }) - } - CanonicalVarKind::PlaceholderConst(placeholder) => { - CanonicalVarKind::PlaceholderConst(ty::Placeholder { - universe: reverse_universe_map[&placeholder.universe], - ..placeholder - }) - } - }, + .map(|&kind| match kind { + CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => { + return kind; + } + CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => { + CanonicalVarKind::Ty(CanonicalTyVarKind::General(reverse_universe_map[&u])) + } + CanonicalVarKind::Region(u) => CanonicalVarKind::Region(reverse_universe_map[&u]), + CanonicalVarKind::Const(u) => CanonicalVarKind::Const(reverse_universe_map[&u]), + CanonicalVarKind::PlaceholderTy(placeholder) => { + CanonicalVarKind::PlaceholderTy(ty::Placeholder { + universe: reverse_universe_map[&placeholder.universe], + ..placeholder + }) + } + CanonicalVarKind::PlaceholderRegion(placeholder) => { + CanonicalVarKind::PlaceholderRegion(ty::Placeholder { + universe: reverse_universe_map[&placeholder.universe], + ..placeholder + }) + } + CanonicalVarKind::PlaceholderConst(placeholder) => { + CanonicalVarKind::PlaceholderConst(ty::Placeholder { + universe: reverse_universe_map[&placeholder.universe], + ..placeholder + }) + } }) .collect() } @@ -740,20 +718,17 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { &mut self, r: ty::Region<'tcx>, ) -> ty::Region<'tcx> { - self.canonical_var_for_region( - CanonicalVarInfo { kind: CanonicalVarKind::Region(ty::UniverseIndex::ROOT) }, - r, - ) + self.canonical_var_for_region(CanonicalVarKind::Region(ty::UniverseIndex::ROOT), r) } /// Creates a canonical variable (with the given `info`) /// representing the region `r`; return a region referencing it. fn canonical_var_for_region( &mut self, - info: CanonicalVarInfo<'tcx>, + var_kind: CanonicalVarKind<'tcx>, r: ty::Region<'tcx>, ) -> ty::Region<'tcx> { - let var = self.canonical_var(info, r.into()); + let var = self.canonical_var(var_kind, r.into()); let br = ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon }; ty::Region::new_bound(self.cx(), self.binder_index, br) } @@ -762,9 +737,13 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { /// if `ty_var` is bound to anything; if so, canonicalize /// *that*. Otherwise, create a new canonical variable for /// `ty_var`. - fn canonicalize_ty_var(&mut self, info: CanonicalVarInfo<'tcx>, ty_var: Ty<'tcx>) -> Ty<'tcx> { + fn canonicalize_ty_var( + &mut self, + var_kind: CanonicalVarKind<'tcx>, + ty_var: Ty<'tcx>, + ) -> Ty<'tcx> { debug_assert!(!self.infcx.is_some_and(|infcx| ty_var != infcx.shallow_resolve(ty_var))); - let var = self.canonical_var(info, ty_var.into()); + let var = self.canonical_var(var_kind, ty_var.into()); Ty::new_bound(self.tcx, self.binder_index, var.into()) } @@ -774,13 +753,13 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { /// `const_var`. fn canonicalize_const_var( &mut self, - info: CanonicalVarInfo<'tcx>, - const_var: ty::Const<'tcx>, + var_kind: CanonicalVarKind<'tcx>, + ct_var: ty::Const<'tcx>, ) -> ty::Const<'tcx> { debug_assert!( - !self.infcx.is_some_and(|infcx| const_var != infcx.shallow_resolve_const(const_var)) + !self.infcx.is_some_and(|infcx| ct_var != infcx.shallow_resolve_const(ct_var)) ); - let var = self.canonical_var(info, const_var.into()); + let var = self.canonical_var(var_kind, ct_var.into()); ty::Const::new_bound(self.tcx, self.binder_index, var) } } diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 3be07dbe208f9..5dffedc709968 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -81,14 +81,14 @@ impl<'tcx> InferCtxt<'tcx> { fn instantiate_canonical_vars( &self, span: Span, - variables: &List>, + variables: &List>, universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, ) -> CanonicalVarValues<'tcx> { CanonicalVarValues { var_values: self.tcx.mk_args_from_iter( variables .iter() - .map(|info| self.instantiate_canonical_var(span, info, &universe_map)), + .map(|kind| self.instantiate_canonical_var(span, kind, &universe_map)), ), } } @@ -104,10 +104,10 @@ impl<'tcx> InferCtxt<'tcx> { pub fn instantiate_canonical_var( &self, span: Span, - cv_info: CanonicalVarInfo<'tcx>, + kind: CanonicalVarKind<'tcx>, universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, ) -> GenericArg<'tcx> { - match cv_info.kind { + match kind { CanonicalVarKind::Ty(ty_kind) => { let ty = match ty_kind { CanonicalTyVarKind::General(ui) => { diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 1ae864c454f28..ec72e05494bef 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -445,17 +445,17 @@ impl<'tcx> InferCtxt<'tcx> { // a fresh inference variable. let result_args = CanonicalVarValues { var_values: self.tcx.mk_args_from_iter( - query_response.variables.iter().enumerate().map(|(index, info)| { - if info.universe() != ty::UniverseIndex::ROOT { + query_response.variables.iter().enumerate().map(|(index, var_kind)| { + if var_kind.universe() != ty::UniverseIndex::ROOT { // A variable from inside a binder of the query. While ideally these shouldn't // exist at all, we have to deal with them for now. - self.instantiate_canonical_var(cause.span, info, |u| { + self.instantiate_canonical_var(cause.span, var_kind, |u| { universe_map[u.as_usize()] }) - } else if info.is_existential() { + } else if var_kind.is_existential() { match opt_values[BoundVar::new(index)] { Some(k) => k, - None => self.instantiate_canonical_var(cause.span, info, |u| { + None => self.instantiate_canonical_var(cause.span, var_kind, |u| { universe_map[u.as_usize()] }), } diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 5b8603744961c..2bbc48b633c85 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -27,7 +27,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lock; use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; pub use rustc_type_ir as ir; -pub use rustc_type_ir::{CanonicalTyVarKind, CanonicalVarKind}; +pub use rustc_type_ir::CanonicalTyVarKind; use smallvec::SmallVec; use crate::mir::ConstraintCategory; @@ -35,9 +35,9 @@ use crate::ty::{self, GenericArg, List, Ty, TyCtxt, TypeFlags, TypeVisitableExt} pub type CanonicalQueryInput<'tcx, V> = ir::CanonicalQueryInput, V>; pub type Canonical<'tcx, V> = ir::Canonical, V>; -pub type CanonicalVarInfo<'tcx> = ir::CanonicalVarInfo>; +pub type CanonicalVarKind<'tcx> = ir::CanonicalVarKind>; pub type CanonicalVarValues<'tcx> = ir::CanonicalVarValues>; -pub type CanonicalVarInfos<'tcx> = &'tcx List>; +pub type CanonicalVarKinds<'tcx> = &'tcx List>; /// When we canonicalize a value to form a query, we wind up replacing /// various parts of it with canonical variables. This struct stores diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 5ff87959a800d..e0f70737add00 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -18,7 +18,7 @@ use rustc_span::source_map::Spanned; use rustc_span::{Span, SpanDecoder, SpanEncoder}; use crate::arena::ArenaAllocatable; -use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos}; +use crate::infer::canonical::{CanonicalVarKind, CanonicalVarKinds}; use crate::mir::interpret::{AllocId, ConstAllocation, CtfeProvenance}; use crate::mir::mono::MonoItem; use crate::mir::{self}; @@ -310,11 +310,11 @@ impl<'tcx, D: TyDecoder<'tcx>> Decodable for ty::Region<'tcx> { } } -impl<'tcx, D: TyDecoder<'tcx>> Decodable for CanonicalVarInfos<'tcx> { +impl<'tcx, D: TyDecoder<'tcx>> Decodable for CanonicalVarKinds<'tcx> { fn decode(decoder: &mut D) -> Self { let len = decoder.read_usize(); decoder.interner().mk_canonical_var_infos_from_iter( - (0..len).map::, _>(|_| Decodable::decode(decoder)), + (0..len).map::, _>(|_| Decodable::decode(decoder)), ) } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index c205d53b93f1f..8c915fea950a4 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -60,7 +60,7 @@ use tracing::{debug, instrument}; use crate::arena::Arena; use crate::dep_graph::{DepGraph, DepKindStruct}; -use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarInfo, CanonicalVarInfos}; +use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarKind, CanonicalVarKinds}; use crate::lint::lint_level; use crate::metadata::ModChild; use crate::middle::codegen_fn_attrs::{CodegenFnAttrs, TargetFeature}; @@ -107,9 +107,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.mk_predefined_opaques_in_body(data) } type LocalDefIds = &'tcx ty::List; - type CanonicalVars = CanonicalVarInfos<'tcx>; - fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo]) -> Self::CanonicalVars { - self.mk_canonical_var_infos(infos) + type CanonicalVarKinds = CanonicalVarKinds<'tcx>; + fn mk_canonical_var_kinds( + self, + kinds: &[ty::CanonicalVarKind], + ) -> Self::CanonicalVarKinds { + self.mk_canonical_var_kinds(kinds) } type ExternalConstraints = ExternalConstraints<'tcx>; @@ -833,7 +836,7 @@ pub struct CtxtInterners<'tcx> { const_lists: InternedSet<'tcx, List>>, args: InternedSet<'tcx, GenericArgs<'tcx>>, type_lists: InternedSet<'tcx, List>>, - canonical_var_infos: InternedSet<'tcx, List>>, + canonical_var_kinds: InternedSet<'tcx, List>>, region: InternedSet<'tcx, RegionKind<'tcx>>, poly_existential_predicates: InternedSet<'tcx, List>>, predicate: InternedSet<'tcx, WithCachedTypeInfo>>>, @@ -872,7 +875,7 @@ impl<'tcx> CtxtInterners<'tcx> { type_lists: InternedSet::with_capacity(N * 4), region: InternedSet::with_capacity(N * 4), poly_existential_predicates: InternedSet::with_capacity(N / 4), - canonical_var_infos: InternedSet::with_capacity(N / 2), + canonical_var_kinds: InternedSet::with_capacity(N / 2), predicate: InternedSet::with_capacity(N), clauses: InternedSet::with_capacity(N), projs: InternedSet::with_capacity(N * 4), @@ -2675,7 +2678,7 @@ slice_interners!( const_lists: pub mk_const_list(Const<'tcx>), args: pub mk_args(GenericArg<'tcx>), type_lists: pub mk_type_list(Ty<'tcx>), - canonical_var_infos: pub mk_canonical_var_infos(CanonicalVarInfo<'tcx>), + canonical_var_kinds: pub mk_canonical_var_kinds(CanonicalVarKind<'tcx>), poly_existential_predicates: intern_poly_existential_predicates(PolyExistentialPredicate<'tcx>), projs: pub mk_projs(ProjectionKind), place_elems: pub mk_place_elems(PlaceElem<'tcx>), @@ -3055,9 +3058,9 @@ impl<'tcx> TyCtxt<'tcx> { pub fn mk_canonical_var_infos_from_iter(self, iter: I) -> T::Output where I: Iterator, - T: CollectAndApply, &'tcx List>>, + T: CollectAndApply, &'tcx List>>, { - T::collect_and_apply(iter, |xs| self.mk_canonical_var_infos(xs)) + T::collect_and_apply(iter, |xs| self.mk_canonical_var_kinds(xs)) } pub fn mk_place_elems_from_iter(self, iter: I) -> T::Output diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index bbb4a162027dc..93b8940ee37d8 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -4,8 +4,8 @@ use rustc_type_ir::data_structures::{HashMap, ensure_sufficient_stack}; use rustc_type_ir::inherent::*; use rustc_type_ir::solve::{Goal, QueryInput}; use rustc_type_ir::{ - self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, InferCtxtLike, - Interner, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, + self as ty, Canonical, CanonicalTyVarKind, CanonicalVarKind, InferCtxtLike, Interner, + TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; use crate::delegate::SolverDelegate; @@ -50,7 +50,7 @@ pub struct Canonicalizer<'a, D: SolverDelegate, I: Interner> { // Mutable fields. variables: &'a mut Vec, - primitive_var_infos: Vec>, + var_kinds: Vec>, variable_lookup_table: HashMap, binder_index: ty::DebruijnIndex, @@ -73,7 +73,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { variables, variable_lookup_table: Default::default(), - primitive_var_infos: Vec::new(), + var_kinds: Vec::new(), binder_index: ty::INNERMOST, cache: Default::default(), @@ -106,7 +106,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { variables, variable_lookup_table: Default::default(), - primitive_var_infos: Vec::new(), + var_kinds: Vec::new(), binder_index: ty::INNERMOST, cache: Default::default(), @@ -123,7 +123,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { // We're able to reuse the `variable_lookup_table` as whether or not // it already contains an entry for `'static` does not matter. variable_lookup_table: env_canonicalizer.variable_lookup_table, - primitive_var_infos: env_canonicalizer.primitive_var_infos, + var_kinds: env_canonicalizer.var_kinds, binder_index: ty::INNERMOST, // We do not reuse the cache as it may contain entries whose canonicalized @@ -149,7 +149,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { fn get_or_insert_bound_var( &mut self, arg: impl Into, - canonical_var_info: CanonicalVarInfo, + kind: CanonicalVarKind, ) -> ty::BoundVar { // FIXME: 16 is made up and arbitrary. We should look at some // perf data here. @@ -162,14 +162,14 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { *self.variable_lookup_table.entry(arg).or_insert_with(|| { let var = self.variables.len(); self.variables.push(arg); - self.primitive_var_infos.push(canonical_var_info); + self.var_kinds.push(kind); var }) } else { self.variables.iter().position(|&v| v == arg).unwrap_or_else(|| { let var = self.variables.len(); self.variables.push(arg); - self.primitive_var_infos.push(canonical_var_info); + self.var_kinds.push(kind); var }) }; @@ -177,8 +177,8 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { ty::BoundVar::from(idx) } - fn finalize(self) -> (ty::UniverseIndex, I::CanonicalVars) { - let mut var_infos = self.primitive_var_infos; + fn finalize(self) -> (ty::UniverseIndex, I::CanonicalVarKinds) { + let mut var_kinds = self.var_kinds; // See the rustc-dev-guide section about how we deal with universes // during canonicalization in the new solver. match self.canonicalize_mode { @@ -192,25 +192,25 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { // information for placeholders and inference variables created inside // of the query. CanonicalizeMode::Response { max_input_universe } => { - for var in var_infos.iter_mut() { + for var in var_kinds.iter_mut() { let uv = var.universe(); let new_uv = ty::UniverseIndex::from( uv.index().saturating_sub(max_input_universe.index()), ); *var = var.with_updated_universe(new_uv); } - let max_universe = var_infos + let max_universe = var_kinds .iter() - .map(|info| info.universe()) + .map(|kind| kind.universe()) .max() .unwrap_or(ty::UniverseIndex::ROOT); - let var_infos = self.delegate.cx().mk_canonical_var_infos(&var_infos); - return (max_universe, var_infos); + let var_kinds = self.delegate.cx().mk_canonical_var_kinds(&var_kinds); + return (max_universe, var_kinds); } } - // Given a `var_infos` with existentials `En` and universals `Un` in + // Given a `var_kinds` with existentials `En` and universals `Un` in // universes `n`, this algorithm compresses them in place so that: // // - the new universe indices are as small as possible @@ -219,12 +219,12 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { // 2. put a placeholder in the same universe as an existential which cannot name it // // Let's walk through an example: - // - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 0 - // - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 1 - // - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 1, next_orig_uv: 2 - // - var_infos: [E0, U1, E5, U1, E1, E6, U6], curr_compressed_uv: 1, next_orig_uv: 5 - // - var_infos: [E0, U1, E2, U1, E1, E6, U6], curr_compressed_uv: 2, next_orig_uv: 6 - // - var_infos: [E0, U1, E1, U1, E1, E3, U3], curr_compressed_uv: 2, next_orig_uv: - + // - var_kinds: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 0 + // - var_kinds: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 1 + // - var_kinds: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 1, next_orig_uv: 2 + // - var_kinds: [E0, U1, E5, U1, E1, E6, U6], curr_compressed_uv: 1, next_orig_uv: 5 + // - var_kinds: [E0, U1, E2, U1, E1, E6, U6], curr_compressed_uv: 2, next_orig_uv: 6 + // - var_kinds: [E0, U1, E1, U1, E1, E3, U3], curr_compressed_uv: 2, next_orig_uv: - // // This algorithm runs in `O(mn)` where `n` is the number of different universes and // `m` the number of variables. This should be fine as both are expected to be small. @@ -232,7 +232,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { let mut existential_in_new_uv = None; let mut next_orig_uv = Some(ty::UniverseIndex::ROOT); while let Some(orig_uv) = next_orig_uv.take() { - let mut update_uv = |var: &mut CanonicalVarInfo, orig_uv, is_existential| { + let mut update_uv = |var: &mut CanonicalVarKind, orig_uv, is_existential| { let uv = var.universe(); match uv.cmp(&orig_uv) { Ordering::Less => (), // Already updated @@ -284,7 +284,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { // Whenever we compress the universe of a placeholder, no existential with // an already compressed universe can name that placeholder. for is_existential in [false, true] { - for var in var_infos.iter_mut() { + for var in var_kinds.iter_mut() { // We simply put all regions from the input into the highest // compressed universe, so we only deal with them at the end. if !var.is_region() { @@ -298,7 +298,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { // We put all regions into a separate universe. let mut first_region = true; - for var in var_infos.iter_mut() { + for var in var_kinds.iter_mut() { if var.is_region() { if first_region { first_region = false; @@ -309,8 +309,8 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { } } - let var_infos = self.delegate.cx().mk_canonical_var_infos(&var_infos); - (curr_compressed_uv, var_infos) + let var_kinds = self.delegate.cx().mk_canonical_var_kinds(&var_kinds); + (curr_compressed_uv, var_kinds) } fn cached_fold_ty(&mut self, t: I::Ty) -> I::Ty { @@ -391,7 +391,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { } }; - let var = self.get_or_insert_bound_var(t, CanonicalVarInfo { kind }); + let var = self.get_or_insert_bound_var(t, kind); Ty::new_anon_bound(self.cx(), self.binder_index, var) } @@ -475,7 +475,7 @@ impl, I: Interner> TypeFolder for Canonicaliz } }; - let var = self.get_or_insert_bound_var(r, CanonicalVarInfo { kind }); + let var = self.get_or_insert_bound_var(r, kind); Region::new_anon_bound(self.cx(), self.binder_index, var) } @@ -525,7 +525,7 @@ impl, I: Interner> TypeFolder for Canonicaliz | ty::ConstKind::Expr(_) => return c.super_fold_with(self), }; - let var = self.get_or_insert_bound_var(c, CanonicalVarInfo { kind }); + let var = self.get_or_insert_bound_var(c, kind); Const::new_anon_bound(self.cx(), self.binder_index, var) } diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index bb923612cffc4..32dc85b3e6a71 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -61,7 +61,7 @@ pub trait SolverDelegate: Deref + Sized { fn instantiate_canonical_var_with_infer( &self, - cv_info: ty::CanonicalVarInfo, + kind: ty::CanonicalVarKind, span: ::Span, universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, ) -> ::GenericArg; diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index c62f2e2e0e95f..455a178595b29 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -360,15 +360,15 @@ where } let var_values = delegate.cx().mk_args_from_iter( - response.variables.iter().enumerate().map(|(index, info)| { - if info.universe() != ty::UniverseIndex::ROOT { + response.variables.iter().enumerate().map(|(index, var_kind)| { + if var_kind.universe() != ty::UniverseIndex::ROOT { // A variable from inside a binder of the query. While ideally these shouldn't // exist at all (see the FIXME at the start of this method), we have to deal with // them for now. - delegate.instantiate_canonical_var_with_infer(info, span, |idx| { + delegate.instantiate_canonical_var_with_infer(var_kind, span, |idx| { prev_universe + idx.index() }) - } else if info.is_existential() { + } else if var_kind.is_existential() { // As an optimization we sometimes avoid creating a new inference variable here. // // All new inference variables we create start out in the current universe of the caller. @@ -379,12 +379,13 @@ where if let Some(v) = opt_values[ty::BoundVar::from_usize(index)] { v } else { - delegate.instantiate_canonical_var_with_infer(info, span, |_| prev_universe) + delegate + .instantiate_canonical_var_with_infer(var_kind, span, |_| prev_universe) } } else { // For placeholders which were already part of the input, we simply map this // universal bound variable back the placeholder of the input. - original_values[info.expect_placeholder_index()] + original_values[var_kind.expect_placeholder_index()] } }), ); diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 9a4b95903a970..dfabb94ebfc60 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -91,7 +91,7 @@ where /// The variable info for the `var_values`, only used to make an ambiguous response /// with no constraints. - variables: I::CanonicalVars, + variables: I::CanonicalVarKinds, /// What kind of goal we're currently computing, see the enum definition /// for more info. diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 8173146e2fe24..2a64180715411 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -354,7 +354,7 @@ where fn response_no_constraints_raw( cx: I, max_universe: ty::UniverseIndex, - variables: I::CanonicalVars, + variables: I::CanonicalVarKinds, certainty: Certainty, ) -> CanonicalResponse { ty::Canonical { diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index a60642b953ced..b68a784536604 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -5,7 +5,7 @@ use rustc_hir::LangItem; use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_infer::infer::canonical::query_response::make_query_region_constraints; use rustc_infer::infer::canonical::{ - Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues, + Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarKind, CanonicalVarValues, }; use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt}; use rustc_infer::traits::solve::Goal; @@ -190,11 +190,11 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< fn instantiate_canonical_var_with_infer( &self, - cv_info: CanonicalVarInfo<'tcx>, + kind: CanonicalVarKind<'tcx>, span: Span, universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, ) -> ty::GenericArg<'tcx> { - self.0.instantiate_canonical_var(span, cv_info, universe_map) + self.0.instantiate_canonical_var(span, kind, universe_map) } fn add_item_bounds_for_hidden_type( diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index 67b67df4b2817..2b1b0617cef6a 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -41,7 +41,7 @@ pub struct CanonicalQueryInput { pub struct Canonical { pub value: V, pub max_universe: UniverseIndex, - pub variables: I::CanonicalVars, + pub variables: I::CanonicalVarKinds, } impl Canonical { @@ -89,63 +89,6 @@ impl fmt::Display for Canonical { /// a copy of the canonical value in some other inference context, /// with fresh inference variables replacing the canonical values. #[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] -#[cfg_attr( - feature = "nightly", - derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) -)] -pub struct CanonicalVarInfo { - pub kind: CanonicalVarKind, -} - -impl CanonicalVarInfo { - pub fn universe(self) -> UniverseIndex { - self.kind.universe() - } - - #[must_use] - pub fn with_updated_universe(self, ui: UniverseIndex) -> CanonicalVarInfo { - CanonicalVarInfo { kind: self.kind.with_updated_universe(ui) } - } - - pub fn is_existential(&self) -> bool { - match self.kind { - CanonicalVarKind::Ty(_) => true, - CanonicalVarKind::PlaceholderTy(_) => false, - CanonicalVarKind::Region(_) => true, - CanonicalVarKind::PlaceholderRegion(..) => false, - CanonicalVarKind::Const(_) => true, - CanonicalVarKind::PlaceholderConst(_) => false, - } - } - - pub fn is_region(&self) -> bool { - match self.kind { - CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => true, - CanonicalVarKind::Ty(_) - | CanonicalVarKind::PlaceholderTy(_) - | CanonicalVarKind::Const(_) - | CanonicalVarKind::PlaceholderConst(_) => false, - } - } - - pub fn expect_placeholder_index(self) -> usize { - match self.kind { - CanonicalVarKind::Ty(_) | CanonicalVarKind::Region(_) | CanonicalVarKind::Const(_) => { - panic!("expected placeholder: {self:?}") - } - - CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.var().as_usize(), - CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.var().as_usize(), - CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.var().as_usize(), - } - } -} - -/// Describes the "kind" of the canonical variable. This is a "kind" -/// in the type-theory sense of the term -- i.e., a "meta" type system -/// that analyzes type-like values. -#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] #[cfg_attr( feature = "nightly", derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) @@ -214,6 +157,39 @@ impl CanonicalVarKind { } } } + + pub fn is_existential(self) -> bool { + match self { + CanonicalVarKind::Ty(_) => true, + CanonicalVarKind::PlaceholderTy(_) => false, + CanonicalVarKind::Region(_) => true, + CanonicalVarKind::PlaceholderRegion(..) => false, + CanonicalVarKind::Const(_) => true, + CanonicalVarKind::PlaceholderConst(_) => false, + } + } + + pub fn is_region(self) -> bool { + match self { + CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => true, + CanonicalVarKind::Ty(_) + | CanonicalVarKind::PlaceholderTy(_) + | CanonicalVarKind::Const(_) + | CanonicalVarKind::PlaceholderConst(_) => false, + } + } + + pub fn expect_placeholder_index(self) -> usize { + match self { + CanonicalVarKind::Ty(_) | CanonicalVarKind::Region(_) | CanonicalVarKind::Const(_) => { + panic!("expected placeholder: {self:?}") + } + + CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.var().as_usize(), + CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.var().as_usize(), + CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.var().as_usize(), + } + } } /// Rust actually has more than one category of type variables; @@ -306,11 +282,11 @@ impl CanonicalVarValues { // Given a list of canonical variables, construct a set of values which are // the identity response. - pub fn make_identity(cx: I, infos: I::CanonicalVars) -> CanonicalVarValues { + pub fn make_identity(cx: I, infos: I::CanonicalVarKinds) -> CanonicalVarValues { CanonicalVarValues { var_values: cx.mk_args_from_iter(infos.iter().enumerate().map( - |(i, info)| -> I::GenericArg { - match info.kind { + |(i, kind)| -> I::GenericArg { + match kind { CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => { Ty::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i)) .into() diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index c10241cfcf0f6..7e88114df460f 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -64,13 +64,16 @@ pub trait Interner: + TypeVisitable + SliceLike; - type CanonicalVars: Copy + type CanonicalVarKinds: Copy + Debug + Hash + Eq - + SliceLike> + + SliceLike> + Default; - fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo]) -> Self::CanonicalVars; + fn mk_canonical_var_kinds( + self, + kinds: &[ty::CanonicalVarKind], + ) -> Self::CanonicalVarKinds; type ExternalConstraints: Copy + Debug diff --git a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir index 5fc77f95eaf72..8afb6ad250e03 100644 --- a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir @@ -1,34 +1,34 @@ // MIR for `address_of_reborrow` after SimplifyCfg-initial | User Type Annotations -| 0: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:8:10: 8:18, inferred_ty: *const [i32; 10] -| 1: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:10:10: 10:25, inferred_ty: *const dyn std::marker::Send -| 2: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] -| 3: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] +| 0: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:8:10: 8:18, inferred_ty: *const [i32; 10] +| 1: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:10:10: 10:25, inferred_ty: *const dyn std::marker::Send +| 2: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] +| 3: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] | 4: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10] | 5: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10] -| 6: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send -| 7: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send +| 6: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send +| 7: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send | 8: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32] | 9: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32] -| 10: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:19:10: 19:18, inferred_ty: *const [i32; 10] -| 11: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:21:10: 21:25, inferred_ty: *const dyn std::marker::Send -| 12: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] -| 13: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] +| 10: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:19:10: 19:18, inferred_ty: *const [i32; 10] +| 11: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:21:10: 21:25, inferred_ty: *const dyn std::marker::Send +| 12: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] +| 13: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] | 14: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10] | 15: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10] -| 16: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send -| 17: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send +| 16: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send +| 17: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send | 18: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32] | 19: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32] -| 20: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:29:10: 29:16, inferred_ty: *mut [i32; 10] -| 21: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:31:10: 31:23, inferred_ty: *mut dyn std::marker::Send -| 22: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] -| 23: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] +| 20: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:29:10: 29:16, inferred_ty: *mut [i32; 10] +| 21: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:31:10: 31:23, inferred_ty: *mut dyn std::marker::Send +| 22: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] +| 23: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] | 24: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10] | 25: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10] -| 26: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send -| 27: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send +| 26: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send +| 27: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send | 28: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:37:12: 37:22, inferred_ty: *mut [i32] | 29: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:37:12: 37:22, inferred_ty: *mut [i32] | diff --git a/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir b/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir index 6e349a2a24ff6..744553c7cd266 100644 --- a/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir +++ b/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir @@ -3,8 +3,8 @@ | User Type Annotations | 0: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [] }, span: $DIR/receiver_ptr_mutability.rs:15:14: 15:23, inferred_ty: *mut Test | 1: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [] }, span: $DIR/receiver_ptr_mutability.rs:15:14: 15:23, inferred_ty: *mut Test -| 2: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/receiver_ptr_mutability.rs:19:18: 19:31, inferred_ty: &&&&*mut Test -| 3: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/receiver_ptr_mutability.rs:19:18: 19:31, inferred_ty: &&&&*mut Test +| 2: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [Region(U0), Region(U0), Region(U0), Region(U0)] }, span: $DIR/receiver_ptr_mutability.rs:19:18: 19:31, inferred_ty: &&&&*mut Test +| 3: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [Region(U0), Region(U0), Region(U0), Region(U0)] }, span: $DIR/receiver_ptr_mutability.rs:19:18: 19:31, inferred_ty: &&&&*mut Test | fn main() -> () { let mut _0: (); diff --git a/tests/rustdoc-js/auxiliary/interner.rs b/tests/rustdoc-js/auxiliary/interner.rs index e4e4ff6276d66..8af3b732ef7a0 100644 --- a/tests/rustdoc-js/auxiliary/interner.rs +++ b/tests/rustdoc-js/auxiliary/interner.rs @@ -18,7 +18,7 @@ pub trait Interner: Sized { type Binder>: BoundVars + TypeSuperVisitable; type BoundVars: IntoIterator; type BoundVar; - type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator>; + type CanonicalVarKinds: Copy + Debug + Hash + Eq + IntoIterator>; type Ty: Copy + DebugWithInfcx + Hash @@ -77,7 +77,7 @@ pub trait Interner: Sized { type ClosureKind: Copy + Debug + Hash + Eq; // Required method - fn mk_canonical_var_infos(self, infos: &[CanonicalVarInfo]) -> Self::CanonicalVars; + fn mk_canonical_var_kinds(self, kinds: &[CanonicalVarKind]) -> Self::CanonicalVarKinds; } pub trait DebugWithInfcx: Debug { @@ -104,10 +104,6 @@ pub trait TypeSuperVisitable: TypeVisitable { fn super_visit_with>(&self, visitor: &mut V) -> V::Result; } -pub struct CanonicalVarInfo { - pub kind: CanonicalVarKind, -} - pub struct CanonicalVarKind(std::marker::PhantomData); pub struct TyKind(std::marker::PhantomData); diff --git a/tests/rustdoc-js/looks-like-rustc-interner.js b/tests/rustdoc-js/looks-like-rustc-interner.js index d6d2764c3aede..7d0511944546a 100644 --- a/tests/rustdoc-js/looks-like-rustc-interner.js +++ b/tests/rustdoc-js/looks-like-rustc-interner.js @@ -3,13 +3,13 @@ const EXPECTED = [ { - 'query': 'canonicalvarinfo, intoiterator -> intoiterator', + 'query': 'CanonicalVarKind, intoiterator -> intoiterator', 'others': [], }, { - 'query': '[canonicalvarinfo], interner -> intoiterator', + 'query': '[CanonicalVarKind], interner -> intoiterator', 'others': [ - { 'path': 'looks_like_rustc_interner::Interner', 'name': 'mk_canonical_var_infos' }, + { 'path': 'looks_like_rustc_interner::Interner', 'name': 'mk_canonical_var_kinds' }, ], }, ]; From d0413436d5217de732d37cb3a2e9e816eee7ee25 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 23 May 2025 11:27:07 +0000 Subject: [PATCH 2659/4206] Do not try to confirm non-dyn compatible method --- .../rustc_hir_typeck/src/method/confirm.rs | 8 +++ .../dyn/mut-is-pointer-like.stderr | 28 +---------- tests/ui/async-await/dyn/works.stderr | 36 +------------- .../dyn-compatibility-err-ret.rs | 2 +- .../dyn-compatibility-err-ret.stderr | 21 +------- .../dyn-compatibility-err-where-bounds.rs | 1 - .../dyn-compatibility-err-where-bounds.stderr | 19 +------ ...tchable-receiver-and-wc-references-Self.rs | 1 - ...ble-receiver-and-wc-references-Self.stderr | 20 +------- tests/ui/error-codes/E0038.rs | 2 - tests/ui/error-codes/E0038.stderr | 31 +----------- .../feature-gate-async-fn-in-dyn-trait.rs | 2 - .../feature-gate-async-fn-in-dyn-trait.stderr | 34 +------------ .../generic-associated-types/trait-objects.rs | 2 - .../trait-objects.stderr | 34 +------------ .../impl-trait/in-trait/dyn-compatibility.rs | 2 - .../in-trait/dyn-compatibility.stderr | 36 +------------- tests/ui/issues/issue-18959.rs | 1 - tests/ui/issues/issue-18959.stderr | 22 ++------- ...ch-dyn-incompatible-that-does-not-deref.rs | 18 +++++++ ...yn-incompatible-that-does-not-deref.stderr | 49 +++++++++++++++++++ tests/ui/traits/test-2.rs | 1 - tests/ui/traits/test-2.stderr | 25 +--------- 23 files changed, 91 insertions(+), 304 deletions(-) create mode 100644 tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.rs create mode 100644 tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.stderr diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index a614b4f00ffe4..53b5dff9c6b50 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -291,6 +291,14 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { probe::ObjectPick => { let trait_def_id = pick.item.container_id(self.tcx); + // If the trait is not object safe (specifically, we care about when + // the receiver is not valid), then there's a chance that we will not + // actually be able to recover the object by derefing the receiver like + // we should if it were valid. + if !self.tcx.is_dyn_compatible(trait_def_id) { + return ty::GenericArgs::extend_with_error(self.tcx, trait_def_id, &[]); + } + // This shouldn't happen for non-region error kinds, but may occur // when we have error regions. Specifically, since we canonicalize // during method steps, we may successfully deref when we assemble diff --git a/tests/ui/async-await/dyn/mut-is-pointer-like.stderr b/tests/ui/async-await/dyn/mut-is-pointer-like.stderr index bf20473924bc5..07c3fd3527f28 100644 --- a/tests/ui/async-await/dyn/mut-is-pointer-like.stderr +++ b/tests/ui/async-await/dyn/mut-is-pointer-like.stderr @@ -42,30 +42,6 @@ LL | async fn async_dispatch(self: Pin<&mut Self>) -> Self::Output; = help: consider moving `async_dispatch` to another trait = note: required for the cast from `Pin<&mut {async block@$DIR/mut-is-pointer-like.rs:32:32: 32:37}>` to `Pin<&mut dyn AsyncTrait>` -error[E0277]: the trait bound `dyn AsyncTrait: AsyncTrait` is not satisfied - --> $DIR/mut-is-pointer-like.rs:36:11 - | -LL | x.async_dispatch().await; - | ^^^^^^^^^^^^^^ the trait `AsyncTrait` is not implemented for `dyn AsyncTrait` - -error[E0038]: the trait `AsyncTrait` is not dyn compatible - --> $DIR/mut-is-pointer-like.rs:36:9 - | -LL | x.async_dispatch().await; - | ^^^^^^^^^^^^^^^^^^ `AsyncTrait` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/mut-is-pointer-like.rs:16:14 - | -LL | trait AsyncTrait { - | ---------- this trait is not dyn compatible... -... -LL | async fn async_dispatch(self: Pin<&mut Self>) -> Self::Output; - | ^^^^^^^^^^^^^^ ...because method `async_dispatch` is `async` - = help: consider moving `async_dispatch` to another trait - -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted -Some errors have detailed explanations: E0038, E0277. -For more information about an error, try `rustc --explain E0038`. +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/async-await/dyn/works.stderr b/tests/ui/async-await/dyn/works.stderr index 47abeab5aacb5..1fe2b28eca82f 100644 --- a/tests/ui/async-await/dyn/works.stderr +++ b/tests/ui/async-await/dyn/works.stderr @@ -42,40 +42,6 @@ LL | async fn async_dispatch(&self); = help: consider moving `async_dispatch` to another trait = help: only type `&'static str` implements `AsyncTrait`; consider using it directly instead. -error[E0038]: the trait `AsyncTrait` is not dyn compatible - --> $DIR/works.rs:28:11 - | -LL | x.async_dispatch().await; - | ^^^^^^^^^^^^^^ `AsyncTrait` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/works.rs:14:14 - | -LL | trait AsyncTrait { - | ---------- this trait is not dyn compatible... -LL | async fn async_dispatch(&self); - | ^^^^^^^^^^^^^^ ...because method `async_dispatch` is `async` - = help: consider moving `async_dispatch` to another trait - = help: only type `&'static str` implements `AsyncTrait`; consider using it directly instead. - -error[E0038]: the trait `AsyncTrait` is not dyn compatible - --> $DIR/works.rs:28:9 - | -LL | x.async_dispatch().await; - | ^^^^^^^^^^^^^^^^^^ `AsyncTrait` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/works.rs:14:14 - | -LL | trait AsyncTrait { - | ---------- this trait is not dyn compatible... -LL | async fn async_dispatch(&self); - | ^^^^^^^^^^^^^^ ...because method `async_dispatch` is `async` - = help: consider moving `async_dispatch` to another trait - = help: only type `&'static str` implements `AsyncTrait`; consider using it directly instead. - -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.rs b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.rs index 9ab715d01f7a0..da9a75b50efa2 100644 --- a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.rs +++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.rs @@ -15,7 +15,7 @@ impl Foo for () { } fn use_dyn(v: &dyn Foo) { //~ERROR the trait `Foo` is not dyn compatible - v.test(); //~ERROR the trait `Foo` is not dyn compatible + v.test(); } fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr index 8bc6ef093d046..120ee435e2563 100644 --- a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr +++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr @@ -17,25 +17,6 @@ LL | fn test(&self) -> [u8; bar::()]; = help: consider moving `test` to another trait = help: only type `()` implements `Foo`; consider using it directly instead. -error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/dyn-compatibility-err-ret.rs:18:5 - | -LL | v.test(); - | ^^^^^^^^ `Foo` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/dyn-compatibility-err-ret.rs:8:8 - | -LL | trait Foo { - | --- this trait is not dyn compatible... -LL | fn test(&self) -> [u8; bar::()]; - | ^^^^ ^^^^^^^^^^^^^^^^^^^ ...because method `test` references the `Self` type in its return type - | | - | ...because method `test` references the `Self` type in its `where` clause - = help: consider moving `test` to another trait - = help: only type `()` implements `Foo`; consider using it directly instead. - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.rs b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.rs index a7b771cd4f840..8b735188f3261 100644 --- a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.rs +++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.rs @@ -15,7 +15,6 @@ impl Foo for () { fn use_dyn(v: &dyn Foo) { //~^ ERROR the trait `Foo` is not dyn compatible v.test(); - //~^ ERROR the trait `Foo` is not dyn compatible } fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr index f5eaaa37916db..c2ad4d1498843 100644 --- a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr +++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr @@ -15,23 +15,6 @@ LL | fn test(&self) where [u8; bar::()]: Sized; = help: consider moving `test` to another trait = help: only type `()` implements `Foo`; consider using it directly instead. -error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/dyn-compatibility-err-where-bounds.rs:17:5 - | -LL | v.test(); - | ^^^^^^^^ `Foo` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/dyn-compatibility-err-where-bounds.rs:8:8 - | -LL | trait Foo { - | --- this trait is not dyn compatible... -LL | fn test(&self) where [u8; bar::()]: Sized; - | ^^^^ ...because method `test` references the `Self` type in its `where` clause - = help: consider moving `test` to another trait - = help: only type `()` implements `Foo`; consider using it directly instead. - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.rs b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.rs index ec32bec7785ac..ac3c2aadf2907 100644 --- a/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.rs +++ b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.rs @@ -25,5 +25,4 @@ pub fn foo() { let fetcher = fetcher(); //~^ ERROR the trait `Fetcher` is not dyn compatible let _ = fetcher.get(); - //~^ ERROR the trait `Fetcher` is not dyn compatible } diff --git a/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr index 1299167159e24..867a719e2ebfd 100644 --- a/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr +++ b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr @@ -34,24 +34,6 @@ LL | pub trait Fetcher: Send + Sync { LL | fn get<'a>(self: &'a Box) -> Pin> + 'a>> | ^^^^^^^^^^^^^ ...because method `get`'s `self` parameter cannot be dispatched on -error[E0038]: the trait `Fetcher` is not dyn compatible - --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:27:13 - | -LL | fn get<'a>(self: &'a Box) -> Pin> + 'a>> - | ------------- help: consider changing method `get`'s `self` parameter to be `&self`: `&Self` -... -LL | let _ = fetcher.get(); - | ^^^^^^^^^^^^^ `Fetcher` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:11:22 - | -LL | pub trait Fetcher: Send + Sync { - | ------- this trait is not dyn compatible... -LL | fn get<'a>(self: &'a Box) -> Pin> + 'a>> - | ^^^^^^^^^^^^^ ...because method `get`'s `self` parameter cannot be dispatched on - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/error-codes/E0038.rs b/tests/ui/error-codes/E0038.rs index a467767c3faaa..9757e2ab10c7a 100644 --- a/tests/ui/error-codes/E0038.rs +++ b/tests/ui/error-codes/E0038.rs @@ -5,8 +5,6 @@ trait Trait { fn call_foo(x: Box) { //~^ ERROR E0038 let y = x.foo(); - //~^ ERROR E0038 - //~| ERROR E0277 } fn main() { diff --git a/tests/ui/error-codes/E0038.stderr b/tests/ui/error-codes/E0038.stderr index 63a5249a38645..e09aefaa0dd1a 100644 --- a/tests/ui/error-codes/E0038.stderr +++ b/tests/ui/error-codes/E0038.stderr @@ -14,33 +14,6 @@ LL | fn foo(&self) -> Self; | ^^^^ ...because method `foo` references the `Self` type in its return type = help: consider moving `foo` to another trait -error[E0038]: the trait `Trait` is not dyn compatible - --> $DIR/E0038.rs:7:13 - | -LL | let y = x.foo(); - | ^^^^^^^ `Trait` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/E0038.rs:2:22 - | -LL | trait Trait { - | ----- this trait is not dyn compatible... -LL | fn foo(&self) -> Self; - | ^^^^ ...because method `foo` references the `Self` type in its return type - = help: consider moving `foo` to another trait - -error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time - --> $DIR/E0038.rs:7:9 - | -LL | let y = x.foo(); - | ^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `dyn Trait` - = note: all local variables must have a statically known size - = help: unsized locals are gated as an unstable feature - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0038, E0277. -For more information about an error, try `rustc --explain E0038`. +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.rs b/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.rs index 278a5451e842e..50e5fd1ab7a85 100644 --- a/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.rs +++ b/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.rs @@ -7,8 +7,6 @@ trait Foo { async fn takes_dyn_trait(x: &dyn Foo) { //~^ ERROR the trait `Foo` is not dyn compatible x.bar().await; - //~^ ERROR the trait `Foo` is not dyn compatible - //~| ERROR the trait `Foo` is not dyn compatible } fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr b/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr index ab8c092a82654..fd94b0babdb0c 100644 --- a/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr +++ b/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr @@ -14,38 +14,6 @@ LL | async fn bar(&self); | ^^^ ...because method `bar` is `async` = help: consider moving `bar` to another trait -error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:9:7 - | -LL | x.bar().await; - | ^^^ `Foo` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14 - | -LL | trait Foo { - | --- this trait is not dyn compatible... -LL | async fn bar(&self); - | ^^^ ...because method `bar` is `async` - = help: consider moving `bar` to another trait - -error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:9:5 - | -LL | x.bar().await; - | ^^^^^^^ `Foo` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14 - | -LL | trait Foo { - | --- this trait is not dyn compatible... -LL | async fn bar(&self); - | ^^^ ...because method `bar` is `async` - = help: consider moving `bar` to another trait - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/generic-associated-types/trait-objects.rs b/tests/ui/generic-associated-types/trait-objects.rs index 256cfee4c8098..87817111b546e 100644 --- a/tests/ui/generic-associated-types/trait-objects.rs +++ b/tests/ui/generic-associated-types/trait-objects.rs @@ -8,8 +8,6 @@ trait StreamingIterator { fn min_size(x: &mut dyn for<'a> StreamingIterator = &'a i32>) -> usize { //~^ ERROR the trait `StreamingIterator` is not dyn compatible x.size_hint().0 - //~^ ERROR the trait `StreamingIterator` is not dyn compatible - //~| ERROR the trait `StreamingIterator` is not dyn compatible } fn main() {} diff --git a/tests/ui/generic-associated-types/trait-objects.stderr b/tests/ui/generic-associated-types/trait-objects.stderr index 7d95718ec874b..8c3af6b654ab7 100644 --- a/tests/ui/generic-associated-types/trait-objects.stderr +++ b/tests/ui/generic-associated-types/trait-objects.stderr @@ -14,38 +14,6 @@ LL | type Item<'a> where Self: 'a; | ^^^^ ...because it contains the generic associated type `Item` = help: consider moving `Item` to another trait -error[E0038]: the trait `StreamingIterator` is not dyn compatible - --> $DIR/trait-objects.rs:10:7 - | -LL | x.size_hint().0 - | ^^^^^^^^^ `StreamingIterator` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/trait-objects.rs:2:10 - | -LL | trait StreamingIterator { - | ----------------- this trait is not dyn compatible... -LL | type Item<'a> where Self: 'a; - | ^^^^ ...because it contains the generic associated type `Item` - = help: consider moving `Item` to another trait - -error[E0038]: the trait `StreamingIterator` is not dyn compatible - --> $DIR/trait-objects.rs:10:5 - | -LL | x.size_hint().0 - | ^^^^^^^^^^^^^ `StreamingIterator` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/trait-objects.rs:2:10 - | -LL | trait StreamingIterator { - | ----------------- this trait is not dyn compatible... -LL | type Item<'a> where Self: 'a; - | ^^^^ ...because it contains the generic associated type `Item` - = help: consider moving `Item` to another trait - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/impl-trait/in-trait/dyn-compatibility.rs b/tests/ui/impl-trait/in-trait/dyn-compatibility.rs index 85b1ba269fc8c..92203c470bba5 100644 --- a/tests/ui/impl-trait/in-trait/dyn-compatibility.rs +++ b/tests/ui/impl-trait/in-trait/dyn-compatibility.rs @@ -15,6 +15,4 @@ fn main() { //~^ ERROR the trait `Foo` is not dyn compatible //~| ERROR the trait `Foo` is not dyn compatible let s = i.baz(); - //~^ ERROR the trait `Foo` is not dyn compatible - //~| ERROR the trait `Foo` is not dyn compatible } diff --git a/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr b/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr index 840c27e183f09..5c498548affdf 100644 --- a/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr +++ b/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr @@ -15,40 +15,6 @@ LL | fn baz(&self) -> impl Debug; = help: consider moving `baz` to another trait = help: only type `u32` implements `Foo`; consider using it directly instead. -error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/dyn-compatibility.rs:17:15 - | -LL | let s = i.baz(); - | ^^^ `Foo` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/dyn-compatibility.rs:4:22 - | -LL | trait Foo { - | --- this trait is not dyn compatible... -LL | fn baz(&self) -> impl Debug; - | ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type - = help: consider moving `baz` to another trait - = help: only type `u32` implements `Foo`; consider using it directly instead. - -error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/dyn-compatibility.rs:17:13 - | -LL | let s = i.baz(); - | ^^^^^^^ `Foo` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/dyn-compatibility.rs:4:22 - | -LL | trait Foo { - | --- this trait is not dyn compatible... -LL | fn baz(&self) -> impl Debug; - | ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type - = help: consider moving `baz` to another trait - = help: only type `u32` implements `Foo`; consider using it directly instead. - error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/dyn-compatibility.rs:14:13 | @@ -67,6 +33,6 @@ LL | fn baz(&self) -> impl Debug; = help: only type `u32` implements `Foo`; consider using it directly instead. = note: required for the cast from `Box` to `Box` -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/issues/issue-18959.rs b/tests/ui/issues/issue-18959.rs index 6aeb34879ea1c..dbc73bafce9e5 100644 --- a/tests/ui/issues/issue-18959.rs +++ b/tests/ui/issues/issue-18959.rs @@ -11,7 +11,6 @@ impl Foo for Thing { fn foo(b: &dyn Bar) { //~^ ERROR E0038 b.foo(&0) - //~^ ERROR E0038 } fn main() { diff --git a/tests/ui/issues/issue-18959.stderr b/tests/ui/issues/issue-18959.stderr index 1e050b115e573..7ddfdb49d9594 100644 --- a/tests/ui/issues/issue-18959.stderr +++ b/tests/ui/issues/issue-18959.stderr @@ -15,23 +15,7 @@ LL | pub trait Bar: Foo { } = help: consider moving `foo` to another trait error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/issue-18959.rs:13:5 - | -LL | b.foo(&0) - | ^^^^^^^^^ `Bar` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/issue-18959.rs:1:20 - | -LL | pub trait Foo { fn foo(&self, ext_thing: &T); } - | ^^^ ...because method `foo` has generic type parameters -LL | pub trait Bar: Foo { } - | --- this trait is not dyn compatible... - = help: consider moving `foo` to another trait - -error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/issue-18959.rs:19:26 + --> $DIR/issue-18959.rs:18:26 | LL | let test: &dyn Bar = &mut thing; | ^^^^^^^^^^ `Bar` is not dyn compatible @@ -48,7 +32,7 @@ LL | pub trait Bar: Foo { } = note: required for the cast from `&mut Thing` to `&dyn Bar` error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/issue-18959.rs:19:15 + --> $DIR/issue-18959.rs:18:15 | LL | let test: &dyn Bar = &mut thing; | ^^^^^^^^ `Bar` is not dyn compatible @@ -63,6 +47,6 @@ LL | pub trait Bar: Foo { } | --- this trait is not dyn compatible... = help: consider moving `foo` to another trait -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.rs b/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.rs new file mode 100644 index 0000000000000..af35d1e0359db --- /dev/null +++ b/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.rs @@ -0,0 +1,18 @@ +// Regression test for . + +use std::ops::Deref; + +struct W; + +trait Foo: Deref { + fn method(self: &W) {} + //~^ ERROR invalid `self` parameter type: `&W` +} + +fn test(x: &dyn Foo) { + //~^ ERROR the trait `Foo` is not dyn compatible + x.method(); + //~^ ERROR the trait `Foo` is not dyn compatible +} + +fn main() {} diff --git a/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.stderr b/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.stderr new file mode 100644 index 0000000000000..237bbc5671515 --- /dev/null +++ b/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.stderr @@ -0,0 +1,49 @@ +error[E0038]: the trait `Foo` is not dyn compatible + --> $DIR/dispatch-dyn-incompatible-that-does-not-deref.rs:12:13 + | +LL | fn method(self: &W) {} + | -- help: consider changing method `method`'s `self` parameter to be `&self`: `&Self` +... +LL | fn test(x: &dyn Foo) { + | ^^^^^^^ `Foo` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $DIR/dispatch-dyn-incompatible-that-does-not-deref.rs:8:21 + | +LL | trait Foo: Deref { + | --- this trait is not dyn compatible... +LL | fn method(self: &W) {} + | ^^ ...because method `method`'s `self` parameter cannot be dispatched on + +error[E0307]: invalid `self` parameter type: `&W` + --> $DIR/dispatch-dyn-incompatible-that-does-not-deref.rs:8:21 + | +LL | fn method(self: &W) {} + | ^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0038]: the trait `Foo` is not dyn compatible + --> $DIR/dispatch-dyn-incompatible-that-does-not-deref.rs:14:5 + | +LL | fn method(self: &W) {} + | -- help: consider changing method `method`'s `self` parameter to be `&self`: `&Self` +... +LL | x.method(); + | ^^^^^^^^^^ `Foo` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $DIR/dispatch-dyn-incompatible-that-does-not-deref.rs:8:21 + | +LL | trait Foo: Deref { + | --- this trait is not dyn compatible... +LL | fn method(self: &W) {} + | ^^ ...because method `method`'s `self` parameter cannot be dispatched on + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0038, E0307. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/traits/test-2.rs b/tests/ui/traits/test-2.rs index ffb778a014140..4ee880da87ad6 100644 --- a/tests/ui/traits/test-2.rs +++ b/tests/ui/traits/test-2.rs @@ -13,5 +13,4 @@ fn main() { (Box::new(10) as Box).dup(); //~^ ERROR E0038 //~| ERROR E0038 - //~| ERROR E0038 } diff --git a/tests/ui/traits/test-2.stderr b/tests/ui/traits/test-2.stderr index 6a6cb503aa4dc..b52839c300ef7 100644 --- a/tests/ui/traits/test-2.stderr +++ b/tests/ui/traits/test-2.stderr @@ -49,29 +49,6 @@ LL | trait bar { fn dup(&self) -> Self; fn blah(&self); } consider defining an enum where each variant holds one of these types, implementing `bar` for this new enum and using it instead -error[E0038]: the trait `bar` is not dyn compatible - --> $DIR/test-2.rs:13:5 - | -LL | (Box::new(10) as Box).dup(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `bar` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/test-2.rs:4:30 - | -LL | trait bar { fn dup(&self) -> Self; fn blah(&self); } - | --- ^^^^ ^^^^ ...because method `blah` has generic type parameters - | | | - | | ...because method `dup` references the `Self` type in its return type - | this trait is not dyn compatible... - = help: consider moving `dup` to another trait - = help: consider moving `blah` to another trait - = help: the following types implement `bar`: - i32 - u32 - consider defining an enum where each variant holds one of these types, - implementing `bar` for this new enum and using it instead - error[E0038]: the trait `bar` is not dyn compatible --> $DIR/test-2.rs:13:6 | @@ -96,7 +73,7 @@ LL | trait bar { fn dup(&self) -> Self; fn blah(&self); } implementing `bar` for this new enum and using it instead = note: required for the cast from `Box<{integer}>` to `Box` -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0038, E0107. For more information about an error, try `rustc --explain E0038`. From 5b47d340d360760dd6d33587c0431414cf550ac9 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Wed, 21 May 2025 21:03:08 +0000 Subject: [PATCH 2660/4206] Simplify `format_integer_with_underscore_sep` Only ever needs to handle decimal reprs --- src/librustdoc/clean/utils.rs | 42 +++++++++++------------------ src/librustdoc/clean/utils/tests.rs | 42 +++++------------------------ src/librustdoc/lib.rs | 2 ++ 3 files changed, 23 insertions(+), 63 deletions(-) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index af7986d030ee7..d3617e682ca5b 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -1,7 +1,7 @@ use std::assert_matches::debug_assert_matches; use std::fmt::{self, Display, Write as _}; -use std::mem; use std::sync::LazyLock as Lazy; +use std::{ascii, mem}; use rustc_ast::tokenstream::TokenTree; use rustc_hir::def::{DefKind, Res}; @@ -391,30 +391,12 @@ pub(crate) fn print_evaluated_const( }) } -fn format_integer_with_underscore_sep(num: &str) -> String { - let num_chars: Vec<_> = num.chars().collect(); - let mut num_start_index = if num_chars.first() == Some(&'-') { 1 } else { 0 }; - let chunk_size = match &num.as_bytes()[num_start_index..] { - [b'0', b'b' | b'x', ..] => { - num_start_index += 2; - 4 - } - [b'0', b'o', ..] => { - num_start_index += 2; - let remaining_chars = num_chars.len() - num_start_index; - if remaining_chars <= 6 { - // don't add underscores to Unix permissions like 0755 or 100755 - return num.to_string(); - } - 3 - } - _ => 3, - }; - - num_chars[..num_start_index] - .iter() - .chain(num_chars[num_start_index..].rchunks(chunk_size).rev().intersperse(&['_']).flatten()) - .collect() +fn format_integer_with_underscore_sep(num: u128, is_negative: bool) -> String { + let num = num.to_string(); + let chars = num.as_ascii().unwrap(); + let mut result = if is_negative { "-".to_string() } else { String::new() }; + result.extend(chars.rchunks(3).rev().intersperse(&[ascii::Char::LowLine]).flatten()); + result } fn print_const_with_custom_print_scalar<'tcx>( @@ -428,7 +410,10 @@ fn print_const_with_custom_print_scalar<'tcx>( match (ct, ct.ty().kind()) { (mir::Const::Val(mir::ConstValue::Scalar(int), _), ty::Uint(ui)) => { let mut output = if with_underscores { - format_integer_with_underscore_sep(&int.to_string()) + format_integer_with_underscore_sep( + int.assert_scalar_int().to_bits_unchecked(), + false, + ) } else { int.to_string() }; @@ -445,7 +430,10 @@ fn print_const_with_custom_print_scalar<'tcx>( .size; let sign_extended_data = int.assert_scalar_int().to_int(size); let mut output = if with_underscores { - format_integer_with_underscore_sep(&sign_extended_data.to_string()) + format_integer_with_underscore_sep( + sign_extended_data.unsigned_abs(), + sign_extended_data.is_negative(), + ) } else { sign_extended_data.to_string() }; diff --git a/src/librustdoc/clean/utils/tests.rs b/src/librustdoc/clean/utils/tests.rs index ebf4b49548394..65c8255b2f274 100644 --- a/src/librustdoc/clean/utils/tests.rs +++ b/src/librustdoc/clean/utils/tests.rs @@ -2,40 +2,10 @@ use super::*; #[test] fn int_format_decimal() { - assert_eq!(format_integer_with_underscore_sep("12345678"), "12_345_678"); - assert_eq!(format_integer_with_underscore_sep("123"), "123"); - assert_eq!(format_integer_with_underscore_sep("123459"), "123_459"); - assert_eq!(format_integer_with_underscore_sep("-12345678"), "-12_345_678"); - assert_eq!(format_integer_with_underscore_sep("-123"), "-123"); - assert_eq!(format_integer_with_underscore_sep("-123459"), "-123_459"); -} - -#[test] -fn int_format_hex() { - assert_eq!(format_integer_with_underscore_sep("0xab3"), "0xab3"); - assert_eq!(format_integer_with_underscore_sep("0xa2345b"), "0xa2_345b"); - assert_eq!(format_integer_with_underscore_sep("0xa2e6345b"), "0xa2e6_345b"); - assert_eq!(format_integer_with_underscore_sep("-0xab3"), "-0xab3"); - assert_eq!(format_integer_with_underscore_sep("-0xa2345b"), "-0xa2_345b"); - assert_eq!(format_integer_with_underscore_sep("-0xa2e6345b"), "-0xa2e6_345b"); -} - -#[test] -fn int_format_binary() { - assert_eq!(format_integer_with_underscore_sep("0o12345671"), "0o12_345_671"); - assert_eq!(format_integer_with_underscore_sep("0o123"), "0o123"); - assert_eq!(format_integer_with_underscore_sep("0o123451"), "0o123451"); - assert_eq!(format_integer_with_underscore_sep("-0o12345671"), "-0o12_345_671"); - assert_eq!(format_integer_with_underscore_sep("-0o123"), "-0o123"); - assert_eq!(format_integer_with_underscore_sep("-0o123451"), "-0o123451"); -} - -#[test] -fn int_format_octal() { - assert_eq!(format_integer_with_underscore_sep("0b101"), "0b101"); - assert_eq!(format_integer_with_underscore_sep("0b101101011"), "0b1_0110_1011"); - assert_eq!(format_integer_with_underscore_sep("0b01101011"), "0b0110_1011"); - assert_eq!(format_integer_with_underscore_sep("-0b101"), "-0b101"); - assert_eq!(format_integer_with_underscore_sep("-0b101101011"), "-0b1_0110_1011"); - assert_eq!(format_integer_with_underscore_sep("-0b01101011"), "-0b0110_1011"); + assert_eq!(format_integer_with_underscore_sep(12345678, false), "12_345_678"); + assert_eq!(format_integer_with_underscore_sep(123, false), "123"); + assert_eq!(format_integer_with_underscore_sep(123459, false), "123_459"); + assert_eq!(format_integer_with_underscore_sep(12345678, true), "-12_345_678"); + assert_eq!(format_integer_with_underscore_sep(123, true), "-123"); + assert_eq!(format_integer_with_underscore_sep(123459, true), "-123_459"); } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 001668c54a745..025c135aff2a6 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -3,6 +3,8 @@ html_playground_url = "https://play.rust-lang.org/" )] #![feature(rustc_private)] +#![feature(ascii_char)] +#![feature(ascii_char_variants)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(debug_closure_helpers)] From 5c735d154e1d2bc2844039ef5b13b4872a5404ef Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Wed, 21 May 2025 21:11:30 +0000 Subject: [PATCH 2661/4206] Small cleanup for `qpath_to_string` --- src/librustdoc/clean/utils.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index d3617e682ca5b..2e38b6cdc650b 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -24,7 +24,7 @@ use crate::clean::{ clean_middle_ty, inline, }; use crate::core::DocContext; -use crate::display::Joined as _; +use crate::display::{Joined as _, MaybeDisplay as _}; #[cfg(test)] mod tests; @@ -254,14 +254,7 @@ pub(crate) fn qpath_to_string(p: &hir::QPath<'_>) -> String { fmt::from_fn(|f| { segments .iter() - .map(|seg| { - fmt::from_fn(|f| { - if seg.ident.name != kw::PathRoot { - write!(f, "{}", seg.ident)?; - } - Ok(()) - }) - }) + .map(|seg| (seg.ident.name != kw::PathRoot).then_some(seg.ident).maybe_display()) .joined("::", f) }) .to_string() From 180ab161b025e62c4fd0f772c820f2621fca4a81 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 23 May 2025 15:02:56 +0200 Subject: [PATCH 2662/4206] make teach_help message for cast-before-pass-to-variadic more precise --- compiler/rustc_hir_typeck/messages.ftl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 23309102c4da5..034cec83299ae 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -169,7 +169,7 @@ hir_typeck_option_result_copied = use `{$def_path}::copied` to copy the value in hir_typeck_pass_to_variadic_function = can't pass `{$ty}` to variadic function .suggestion = cast the value to `{$cast_ty}` - .teach_help = certain types, like `{$ty}`, must be casted before passing them to a variadic function, because of arcane ABI rules dictated by the C standard + .teach_help = certain types, like `{$ty}`, must be cast before passing them to a variadic function to match the implicit cast that a C compiler would perform as part of C's integer promotion rules hir_typeck_ptr_cast_add_auto_to_object = cannot add {$traits_len -> [1] auto trait {$traits} From df61c7ad45d61eeab5dfb3ef3fbde3b847eb5ac7 Mon Sep 17 00:00:00 2001 From: Petr Sumbera Date: Fri, 23 May 2025 15:02:19 +0200 Subject: [PATCH 2663/4206] Add 2nd Solaris target maintainer --- src/doc/rustc/src/platform-support/solaris.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/rustc/src/platform-support/solaris.md b/src/doc/rustc/src/platform-support/solaris.md index 0452d76f6c28f..c22b5c24c125d 100644 --- a/src/doc/rustc/src/platform-support/solaris.md +++ b/src/doc/rustc/src/platform-support/solaris.md @@ -8,6 +8,7 @@ Rust for Solaris operating system. ## Target maintainers [@psumbera](https://github.com/psumbera) +[@kulikjak](https://github.com/kulikjak) ## Requirements From 898b6a13f1bdbeb5adbf45875fac01cec09d09a4 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 23 May 2025 16:50:24 +0800 Subject: [PATCH 2664/4206] further deduplicate ast visitor code --- compiler/rustc_ast/src/mut_visit.rs | 238 +------------- compiler/rustc_ast/src/visit.rs | 475 ++++++++++++++++------------ compiler/rustc_lint/src/early.rs | 2 +- 3 files changed, 285 insertions(+), 430 deletions(-) diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index a90349f318c09..6770fd5a4aaeb 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -20,7 +20,7 @@ use thin_vec::ThinVec; use crate::ast::*; use crate::ptr::P; use crate::tokenstream::*; -use crate::visit::{AssocCtxt, BoundKind, FnCtxt, try_visit}; +use crate::visit::{AssocCtxt, BoundKind, FnCtxt, try_visit, visit_opt, walk_list}; pub trait ExpectOne { fn expect_one(self, err: &'static str) -> A::Item; @@ -33,18 +33,6 @@ impl ExpectOne for SmallVec { } } -pub trait WalkItemKind { - type Ctxt; - fn walk( - &mut self, - span: Span, - id: NodeId, - visibility: &mut Visibility, - ctxt: Self::Ctxt, - visitor: &mut impl MutVisitor, - ); -} - pub trait MutVisitor: Sized { // Methods in this trait have one of three forms: // @@ -451,11 +439,6 @@ fn visit_thin_exprs(vis: &mut T, exprs: &mut ThinVec>) { exprs.flat_map_in_place(|expr| vis.filter_map_expr(expr)) } -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -fn visit_bounds(vis: &mut T, bounds: &mut GenericBounds, ctxt: BoundKind) { - visit_vec(bounds, |bound| vis.visit_param_bound(bound, ctxt)); -} - // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. fn visit_attr_args(vis: &mut T, args: &mut AttrArgs) { match args { @@ -610,12 +593,6 @@ pub fn walk_ty_pat(vis: &mut T, ty: &mut P) { vis.visit_span(span); } -fn walk_foreign_mod(vis: &mut T, foreign_mod: &mut ForeignMod) { - let ForeignMod { extern_span: _, safety, abi: _, items } = foreign_mod; - visit_safety(vis, safety); - items.flat_map_in_place(|item| vis.flat_map_foreign_item(item)); -} - pub fn walk_variant(visitor: &mut T, variant: &mut Variant) { let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = variant; visitor.visit_id(id); @@ -771,22 +748,6 @@ pub fn walk_flat_map_param(vis: &mut T, mut param: Param) -> Smal smallvec![param] } -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -fn visit_defaultness(vis: &mut T, defaultness: &mut Defaultness) { - match defaultness { - Defaultness::Default(span) => vis.visit_span(span), - Defaultness::Final => {} - } -} - -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -fn visit_polarity(vis: &mut T, polarity: &mut ImplPolarity) { - match polarity { - ImplPolarity::Positive => {} - ImplPolarity::Negative(span) => vis.visit_span(span), - } -} - fn walk_closure_binder(vis: &mut T, binder: &mut ClosureBinder) { match binder { ClosureBinder::NotPresent => {} @@ -1080,169 +1041,15 @@ pub fn walk_item_kind( kind.walk(span, id, visibility, ctxt, vis) } -impl WalkItemKind for ItemKind { - type Ctxt = (); - fn walk( - &mut self, - span: Span, - id: NodeId, - visibility: &mut Visibility, - _ctxt: Self::Ctxt, - vis: &mut impl MutVisitor, - ) { - match self { - ItemKind::ExternCrate(_orig_name, ident) => vis.visit_ident(ident), - ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree), - ItemKind::Static(box StaticItem { - ident, - ty, - safety: _, - mutability: _, - expr, - define_opaque, - }) => { - vis.visit_ident(ident); - vis.visit_ty(ty); - visit_opt(expr, |expr| vis.visit_expr(expr)); - walk_define_opaques(vis, define_opaque); - } - ItemKind::Const(item) => { - walk_const_item(vis, item); - } - ItemKind::Fn(func) => { - vis.visit_fn(FnKind::Fn(FnCtxt::Free, visibility, &mut *func), span, id); - } - ItemKind::Mod(safety, ident, mod_kind) => { - visit_safety(vis, safety); - vis.visit_ident(ident); - match mod_kind { - ModKind::Loaded( - items, - _inline, - ModSpans { inner_span, inject_use_span }, - _, - ) => { - items.flat_map_in_place(|item| vis.flat_map_item(item)); - vis.visit_span(inner_span); - vis.visit_span(inject_use_span); - } - ModKind::Unloaded => {} - } - } - ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm), - ItemKind::GlobalAsm(asm) => vis.visit_inline_asm(asm), - ItemKind::TyAlias(box TyAlias { - defaultness, - ident, - generics, - where_clauses, - bounds, - ty, - }) => { - visit_defaultness(vis, defaultness); - vis.visit_ident(ident); - vis.visit_generics(generics); - visit_bounds(vis, bounds, BoundKind::Bound); - visit_opt(ty, |ty| vis.visit_ty(ty)); - walk_ty_alias_where_clauses(vis, where_clauses); - } - ItemKind::Enum(ident, EnumDef { variants }, generics) => { - vis.visit_ident(ident); - vis.visit_generics(generics); - variants.flat_map_in_place(|variant| vis.flat_map_variant(variant)); - } - ItemKind::Struct(ident, variant_data, generics) - | ItemKind::Union(ident, variant_data, generics) => { - vis.visit_ident(ident); - vis.visit_generics(generics); - vis.visit_variant_data(variant_data); - } - ItemKind::Impl(box Impl { - defaultness, - safety, - generics, - constness, - polarity, - of_trait, - self_ty, - items, - }) => { - visit_defaultness(vis, defaultness); - visit_safety(vis, safety); - vis.visit_generics(generics); - visit_constness(vis, constness); - visit_polarity(vis, polarity); - visit_opt(of_trait, |trait_ref| vis.visit_trait_ref(trait_ref)); - vis.visit_ty(self_ty); - items.flat_map_in_place(|item| { - vis.flat_map_assoc_item(item, AssocCtxt::Impl { of_trait: of_trait.is_some() }) - }); - } - ItemKind::Trait(box Trait { safety, is_auto: _, ident, generics, bounds, items }) => { - visit_safety(vis, safety); - vis.visit_ident(ident); - vis.visit_generics(generics); - visit_bounds(vis, bounds, BoundKind::Bound); - items.flat_map_in_place(|item| vis.flat_map_assoc_item(item, AssocCtxt::Trait)); - } - ItemKind::TraitAlias(ident, generics, bounds) => { - vis.visit_ident(ident); - vis.visit_generics(generics); - visit_bounds(vis, bounds, BoundKind::Bound); - } - ItemKind::MacCall(m) => vis.visit_mac_call(m), - ItemKind::MacroDef(ident, def) => { - vis.visit_ident(ident); - vis.visit_macro_def(def) - } - ItemKind::Delegation(box Delegation { - id, - qself, - path, - ident, - rename, - body, - from_glob: _, - }) => { - vis.visit_id(id); - vis.visit_qself(qself); - vis.visit_path(path); - vis.visit_ident(ident); - if let Some(rename) = rename { - vis.visit_ident(rename); - } - if let Some(body) = body { - vis.visit_block(body); - } - } - ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { - vis.visit_qself(qself); - vis.visit_path(prefix); - if let Some(suffixes) = suffixes { - for (ident, rename) in suffixes { - vis.visit_ident(ident); - if let Some(rename) = rename { - vis.visit_ident(rename); - } - } - } - if let Some(body) = body { - vis.visit_block(body); - } - } - } - } -} - impl WalkItemKind for AssocItemKind { type Ctxt = AssocCtxt; - fn walk( + fn walk( &mut self, span: Span, id: NodeId, visibility: &mut Visibility, ctxt: Self::Ctxt, - visitor: &mut impl MutVisitor, + visitor: &mut V, ) { match self { AssocItemKind::Const(item) => { @@ -1306,16 +1113,6 @@ impl WalkItemKind for AssocItemKind { } } -fn walk_const_item(vis: &mut T, item: &mut ConstItem) { - let ConstItem { defaultness, ident, generics, ty, expr, define_opaque } = item; - visit_defaultness(vis, defaultness); - vis.visit_ident(ident); - vis.visit_generics(generics); - vis.visit_ty(ty); - visit_opt(expr, |expr| vis.visit_expr(expr)); - walk_define_opaques(vis, define_opaque); -} - pub fn walk_crate(vis: &mut T, krate: &mut Crate) { let Crate { attrs, items, spans, id, is_placeholder: _ } = krate; vis.visit_id(id); @@ -1334,19 +1131,6 @@ pub fn walk_assoc_item(visitor: &mut impl MutVisitor, item: &mut P, c walk_item_ctxt(visitor, item, ctxt) } -fn walk_item_ctxt( - visitor: &mut impl MutVisitor, - item: &mut P>, - ctxt: K::Ctxt, -) { - let Item { attrs, id, kind, vis, span, tokens: _ } = item.deref_mut(); - visitor.visit_id(id); - visit_attrs(visitor, attrs); - visitor.visit_vis(vis); - kind.walk(*span, *id, vis, ctxt, visitor); - visitor.visit_span(span); -} - pub fn walk_flat_map_item(vis: &mut impl MutVisitor, mut item: P) -> SmallVec<[P; 1]> { vis.visit_item(&mut item); smallvec![item] @@ -1371,13 +1155,13 @@ pub fn walk_flat_map_assoc_item( impl WalkItemKind for ForeignItemKind { type Ctxt = (); - fn walk( + fn walk( &mut self, span: Span, id: NodeId, visibility: &mut Visibility, _ctxt: Self::Ctxt, - visitor: &mut impl MutVisitor, + visitor: &mut V, ) { match self { ForeignItemKind::Static(box StaticItem { @@ -1786,18 +1570,6 @@ fn walk_capture_by(vis: &mut T, capture_by: &mut CaptureBy) { } } -fn walk_define_opaques( - vis: &mut T, - define_opaque: &mut Option>, -) { - if let Some(define_opaque) = define_opaque { - for (id, path) in define_opaque { - vis.visit_id(id); - vis.visit_path(path) - } - } -} - /// Some value for the AST node that is valid but possibly meaningless. Similar /// to `Default` but not intended for wide use. The value will never be used /// meaningfully, it exists just to support unwinding in `visit_clobber` in the diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index e43d7ae065d9e..c069425748098 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -112,18 +112,6 @@ pub enum LifetimeCtxt { GenericArg, } -pub trait WalkItemKind { - type Ctxt; - fn walk<'a, V: Visitor<'a>>( - &'a self, - span: Span, - id: NodeId, - visibility: &'a Visibility, - ctxt: Self::Ctxt, - visitor: &mut V, - ) -> V::Result; -} - /// Each method of the `Visitor` trait is a hook to be potentially /// overridden. Each method's default implementation recursively visits /// the substructure of the input via the corresponding `walk` method; @@ -141,6 +129,9 @@ pub trait Visitor<'ast>: Sized { fn visit_ident(&mut self, _ident: &'ast Ident) -> Self::Result { Self::Result::output() } + fn visit_foreign_mod(&mut self, nm: &'ast ForeignMod) -> Self::Result { + walk_foreign_mod(self, nm) + } fn visit_foreign_item(&mut self, i: &'ast ForeignItem) -> Self::Result { walk_item(self, i) } @@ -242,7 +233,7 @@ pub trait Visitor<'ast>: Sized { fn visit_mac_call(&mut self, mac: &'ast MacCall) -> Self::Result { walk_mac(self, mac) } - fn visit_mac_def(&mut self, _mac: &'ast MacroDef, _id: NodeId) -> Self::Result { + fn visit_macro_def(&mut self, _mac: &'ast MacroDef, _id: NodeId) -> Self::Result { Self::Result::output() } fn visit_path(&mut self, path: &'ast Path, _id: NodeId) -> Self::Result { @@ -318,6 +309,18 @@ pub trait Visitor<'ast>: Sized { #[macro_export] macro_rules! common_visitor_and_walkers { ($(($mut: ident))? $Visitor:ident$(<$lt:lifetime>)?) => { + pub trait WalkItemKind { + type Ctxt; + fn walk<$($lt,)? V: $Visitor$(<$lt>)?>( + &$($lt)? $($mut)? self, + span: Span, + id: NodeId, + visibility: &$($lt)? $($mut)? Visibility, + ctxt: Self::Ctxt, + visitor: &mut V, + ) $(-> >::Result)?; + } + // this is only used by the MutVisitor. We include this symmetry here to make writing other functions easier $(${ignore($lt)} #[expect(unused, rustc::pass_by_value)] @@ -325,7 +328,7 @@ macro_rules! common_visitor_and_walkers { )? fn visit_span<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, span: &$($lt)? $($mut)? Span) $(-> >::Result)? { $( - let _ = stringify!($mut); + ${ignore($mut)} visitor.visit_span(span); )? $(${ignore($lt)}V::Result::output())? @@ -338,7 +341,7 @@ macro_rules! common_visitor_and_walkers { )? fn visit_id<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, id: &$($lt)? $($mut)? NodeId) $(-> >::Result)? { $( - let _ = stringify!($mut); + ${ignore($mut)} visitor.visit_id(id); )? $(${ignore($lt)}V::Result::output())? @@ -362,6 +365,27 @@ macro_rules! common_visitor_and_walkers { } } + fn visit_defaultness<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, defaultness: &$($lt)? $($mut)? Defaultness) $(-> >::Result)? { + match defaultness { + Defaultness::Default(span) => visit_span(vis, span), + Defaultness::Final => { + $(>::Result::output())? + } + } + } + + fn visit_polarity<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, polarity: &$($lt)? $($mut)? ImplPolarity) $(-> >::Result)? { + match polarity { + ImplPolarity::Positive => { $(>::Result::output())? } + ImplPolarity::Negative(span) => visit_span(vis, span), + } + } + + fn visit_bounds<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, bounds: &$($lt)? $($mut)? GenericBounds, ctxt: BoundKind) $(-> >::Result)? { + walk_list!(visitor, visit_param_bound, bounds, ctxt); + $(>::Result::output())? + } + pub fn walk_label<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, Label { ident }: &$($lt)? $($mut)? Label) $(-> >::Result)? { visitor.visit_ident(ident) } @@ -379,6 +403,246 @@ macro_rules! common_visitor_and_walkers { try_visit!(visit_id(visitor, id)); visitor.visit_ident(ident) } + + fn walk_item_ctxt<$($lt,)? V: $Visitor$(<$lt>)?, K: WalkItemKind>( + visitor: &mut V, + item: &$($mut P>)? $($lt Item)?, + ctxt: K::Ctxt, + ) $(-> >::Result)? { + let Item { attrs, id, kind, vis, span, tokens: _ } = &$($mut *)? *item; + try_visit!(visit_id(visitor, id)); + walk_list!(visitor, visit_attribute, attrs); + try_visit!(visitor.visit_vis(vis)); + try_visit!(kind.walk(*span, *id, vis, ctxt, visitor)); + visit_span(visitor, span) + } + + impl WalkItemKind for ItemKind { + type Ctxt = (); + fn walk<$($lt,)? V: $Visitor$(<$lt>)?>( + &$($lt)? $($mut)? self, + span: Span, + id: NodeId, + visibility: &$($lt)? $($mut)? Visibility, + _ctxt: Self::Ctxt, + vis: &mut V, + ) $(-> >::Result)? { + match self { + ItemKind::ExternCrate(_orig_name, ident) => vis.visit_ident(ident), + // FIXME(fee1-dead): look into this weird assymetry + ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree$(${ignore($lt)}, id, false)?), + ItemKind::Static(box StaticItem { + ident, + ty, + safety: _, + mutability: _, + expr, + define_opaque, + }) => { + try_visit!(vis.visit_ident(ident)); + try_visit!(vis.visit_ty(ty)); + visit_opt!(vis, visit_expr, expr); + walk_define_opaques(vis, define_opaque) + } + ItemKind::Const(item) => { + walk_const_item(vis, item) + } + ItemKind::Fn(func) => { + let kind = FnKind::Fn(FnCtxt::Free, visibility, &$($mut)? *func); + vis.visit_fn(kind, span, id) + } + ItemKind::Mod(safety, ident, mod_kind) => { + try_visit!(visit_safety(vis, safety)); + try_visit!(vis.visit_ident(ident)); + match mod_kind { + ModKind::Loaded( + items, + _inline, + ModSpans { inner_span, inject_use_span }, + _, + ) => { + $(${ignore($mut)} + items.flat_map_in_place(|item| vis.flat_map_item(item)); + )? + $(${ignore($lt)} + walk_list!(vis, visit_item, items); + )? + try_visit!(visit_span(vis, inner_span)); + try_visit!(visit_span(vis, inject_use_span)); + } + ModKind::Unloaded => {} + } + $(>::Result::output())? + } + ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm), + ItemKind::GlobalAsm(asm) => vis.visit_inline_asm(asm), + ItemKind::TyAlias(box TyAlias { + defaultness, + ident, + generics, + $(${ignore($lt)} #[expect(unused)])? + where_clauses, + bounds, + ty, + }) => { + try_visit!(visit_defaultness(vis, defaultness)); + try_visit!(vis.visit_ident(ident)); + try_visit!(vis.visit_generics(generics)); + try_visit!(visit_bounds(vis, bounds, BoundKind::Bound)); + visit_opt!(vis, visit_ty, ty); + $(${ignore($mut)} + walk_ty_alias_where_clauses(vis, where_clauses); + )? + $(>::Result::output())? + } + ItemKind::Enum(ident, enum_definition, generics) => { + try_visit!(vis.visit_ident(ident)); + try_visit!(vis.visit_generics(generics)); + $(${ignore($mut)} + enum_definition.variants.flat_map_in_place(|variant| vis.flat_map_variant(variant)); + )? + $(${ignore($lt)}vis.visit_enum_def(enum_definition))? + } + ItemKind::Struct(ident, variant_data, generics) + | ItemKind::Union(ident, variant_data, generics) => { + try_visit!(vis.visit_ident(ident)); + try_visit!(vis.visit_generics(generics)); + vis.visit_variant_data(variant_data) + } + ItemKind::Impl(box Impl { + defaultness, + safety, + generics, + constness, + polarity, + of_trait, + self_ty, + items, + }) => { + try_visit!(visit_defaultness(vis, defaultness)); + try_visit!(visit_safety(vis, safety)); + try_visit!(vis.visit_generics(generics)); + try_visit!(visit_constness(vis, constness)); + try_visit!(visit_polarity(vis, polarity)); + visit_opt!(vis, visit_trait_ref, of_trait); + try_visit!(vis.visit_ty(self_ty)); + $(${ignore($mut)} + items.flat_map_in_place(|item| { + vis.flat_map_assoc_item(item, AssocCtxt::Impl { of_trait: of_trait.is_some() }) + }); + )? + $(${ignore($lt)} + walk_list!( + vis, + visit_assoc_item, + items, + AssocCtxt::Impl { of_trait: of_trait.is_some() } + ); + >::Result::output() + )? + } + ItemKind::Trait(box Trait { safety, is_auto: _, ident, generics, bounds, items }) => { + try_visit!(visit_safety(vis, safety)); + try_visit!(vis.visit_ident(ident)); + try_visit!(vis.visit_generics(generics)); + try_visit!(visit_bounds(vis, bounds, BoundKind::Bound)); + $(${ignore($mut)} + items.flat_map_in_place(|item| { + vis.flat_map_assoc_item(item, AssocCtxt::Trait) + }); + )? + $(${ignore($lt)} + walk_list!(vis, visit_assoc_item, items, AssocCtxt::Trait); + >::Result::output() + )? + } + ItemKind::TraitAlias(ident, generics, bounds) => { + try_visit!(vis.visit_ident(ident)); + try_visit!(vis.visit_generics(generics)); + visit_bounds(vis, bounds, BoundKind::Bound) + } + ItemKind::MacCall(m) => vis.visit_mac_call(m), + ItemKind::MacroDef(ident, def) => { + try_visit!(vis.visit_ident(ident)); + // FIXME(fee1-dead) assymetry + vis.visit_macro_def(def$(${ignore($lt)}, id)?) + } + ItemKind::Delegation(box Delegation { + id, + qself, + path, + ident, + rename, + body, + from_glob: _, + }) => { + try_visit!(visit_id(vis, id)); + try_visit!(vis.visit_qself(qself)); + try_visit!(vis.visit_path(path$(${ignore($lt)}, *id)?)); + try_visit!(vis.visit_ident(ident)); + if let Some(rename) = rename { + try_visit!(vis.visit_ident(rename)); + } + if let Some(body) = body { + try_visit!(vis.visit_block(body)); + } + $(>::Result::output())? + } + ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { + try_visit!(vis.visit_qself(qself)); + try_visit!(vis.visit_path(prefix$(${ignore($lt)}, id)?)); + if let Some(suffixes) = suffixes { + for (ident, rename) in suffixes { + try_visit!(vis.visit_ident(ident)); + if let Some(rename) = rename { + try_visit!(vis.visit_ident(rename)); + } + } + } + if let Some(body) = body { + try_visit!(vis.visit_block(body)); + } + $(>::Result::output())? + } + } + } + } + + fn walk_const_item<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, item: &$($lt)? $($mut)? ConstItem) $(-> >::Result)? { + let ConstItem { defaultness, ident, generics, ty, expr, define_opaque } = item; + try_visit!(visit_defaultness(vis, defaultness)); + try_visit!(vis.visit_ident(ident)); + try_visit!(vis.visit_generics(generics)); + try_visit!(vis.visit_ty(ty)); + visit_opt!(vis, visit_expr, expr); + walk_define_opaques(vis, define_opaque) + } + + fn walk_foreign_mod<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, foreign_mod: &$($lt)? $($mut)? ForeignMod) $(-> >::Result)? { + let ForeignMod { extern_span: _, safety, abi: _, items } = foreign_mod; + try_visit!(visit_safety(vis, safety)); + $(${ignore($mut)} + items.flat_map_in_place(|item| vis.flat_map_foreign_item(item)); + )? + $( + walk_list!(vis, visit_foreign_item, items); + >::Result::output() + )? + } + + fn walk_define_opaques<$($lt,)? V: $Visitor$(<$lt>)?>( + visitor: &mut V, + define_opaque: &$($lt)? $($mut)? Option>, + ) $(-> >::Result)? { + if let Some(define_opaque) = define_opaque { + for (id, path) in define_opaque { + try_visit!(visit_id(visitor, id)); + // FIXME(fee1-dead): look into this weird assymetry + try_visit!(visitor.visit_path(path$(${ignore($lt)}, *id)?)); + } + } + $(>::Result::output())? + } }; } @@ -417,163 +681,6 @@ pub fn walk_trait_ref<'a, V: Visitor<'a>>(visitor: &mut V, trait_ref: &'a TraitR visitor.visit_path(path, *ref_id) } -impl WalkItemKind for ItemKind { - type Ctxt = (); - fn walk<'a, V: Visitor<'a>>( - &'a self, - span: Span, - id: NodeId, - vis: &'a Visibility, - _ctxt: Self::Ctxt, - visitor: &mut V, - ) -> V::Result { - match self { - ItemKind::ExternCrate(_rename, ident) => try_visit!(visitor.visit_ident(ident)), - ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, id, false)), - ItemKind::Static(box StaticItem { - ident, - ty, - safety: _, - mutability: _, - expr, - define_opaque, - }) => { - try_visit!(visitor.visit_ident(ident)); - try_visit!(visitor.visit_ty(ty)); - visit_opt!(visitor, visit_expr, expr); - try_visit!(walk_define_opaques(visitor, define_opaque)); - } - ItemKind::Const(box ConstItem { - defaultness: _, - ident, - generics, - ty, - expr, - define_opaque, - }) => { - try_visit!(visitor.visit_ident(ident)); - try_visit!(visitor.visit_generics(generics)); - try_visit!(visitor.visit_ty(ty)); - visit_opt!(visitor, visit_expr, expr); - try_visit!(walk_define_opaques(visitor, define_opaque)); - } - ItemKind::Fn(func) => { - let kind = FnKind::Fn(FnCtxt::Free, vis, &*func); - try_visit!(visitor.visit_fn(kind, span, id)); - } - ItemKind::Mod(_unsafety, ident, mod_kind) => { - try_visit!(visitor.visit_ident(ident)); - match mod_kind { - ModKind::Loaded(items, _inline, _inner_span, _) => { - walk_list!(visitor, visit_item, items); - } - ModKind::Unloaded => {} - } - } - ItemKind::ForeignMod(ForeignMod { extern_span: _, safety: _, abi: _, items }) => { - walk_list!(visitor, visit_foreign_item, items); - } - ItemKind::GlobalAsm(asm) => try_visit!(visitor.visit_inline_asm(asm)), - ItemKind::TyAlias(box TyAlias { - generics, - ident, - bounds, - ty, - defaultness: _, - where_clauses: _, - }) => { - try_visit!(visitor.visit_ident(ident)); - try_visit!(visitor.visit_generics(generics)); - walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); - visit_opt!(visitor, visit_ty, ty); - } - ItemKind::Enum(ident, enum_definition, generics) => { - try_visit!(visitor.visit_ident(ident)); - try_visit!(visitor.visit_generics(generics)); - try_visit!(visitor.visit_enum_def(enum_definition)); - } - ItemKind::Impl(box Impl { - defaultness: _, - safety: _, - generics, - constness: _, - polarity: _, - of_trait, - self_ty, - items, - }) => { - try_visit!(visitor.visit_generics(generics)); - visit_opt!(visitor, visit_trait_ref, of_trait); - try_visit!(visitor.visit_ty(self_ty)); - walk_list!( - visitor, - visit_assoc_item, - items, - AssocCtxt::Impl { of_trait: of_trait.is_some() } - ); - } - ItemKind::Struct(ident, struct_definition, generics) - | ItemKind::Union(ident, struct_definition, generics) => { - try_visit!(visitor.visit_ident(ident)); - try_visit!(visitor.visit_generics(generics)); - try_visit!(visitor.visit_variant_data(struct_definition)); - } - ItemKind::Trait(box Trait { - safety: _, - is_auto: _, - ident, - generics, - bounds, - items, - }) => { - try_visit!(visitor.visit_ident(ident)); - try_visit!(visitor.visit_generics(generics)); - walk_list!(visitor, visit_param_bound, bounds, BoundKind::SuperTraits); - walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait); - } - ItemKind::TraitAlias(ident, generics, bounds) => { - try_visit!(visitor.visit_ident(ident)); - try_visit!(visitor.visit_generics(generics)); - walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); - } - ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)), - ItemKind::MacroDef(ident, ts) => { - try_visit!(visitor.visit_ident(ident)); - try_visit!(visitor.visit_mac_def(ts, id)) - } - ItemKind::Delegation(box Delegation { - id, - qself, - path, - ident, - rename, - body, - from_glob: _, - }) => { - try_visit!(visitor.visit_qself(qself)); - try_visit!(visitor.visit_path(path, *id)); - try_visit!(visitor.visit_ident(ident)); - visit_opt!(visitor, visit_ident, rename); - visit_opt!(visitor, visit_block, body); - } - ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { - try_visit!(visitor.visit_qself(qself)); - try_visit!(visitor.visit_path(prefix, id)); - if let Some(suffixes) = suffixes { - for (ident, rename) in suffixes { - visitor.visit_ident(ident); - if let Some(rename) = rename { - visitor.visit_ident(rename); - } - } - } - visit_opt!(visitor, visit_block, body); - } - } - V::Result::output() - } -} - pub fn walk_enum_def<'a, V: Visitor<'a>>( visitor: &mut V, EnumDef { variants }: &'a EnumDef, @@ -1121,18 +1228,6 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>( walk_item_ctxt(visitor, item, ctxt) } -fn walk_item_ctxt<'a, V: Visitor<'a>, K: WalkItemKind>( - visitor: &mut V, - item: &'a Item, - ctxt: K::Ctxt, -) -> V::Result { - let Item { id, span, vis, attrs, kind, tokens: _ } = item; - walk_list!(visitor, visit_attribute, attrs); - try_visit!(visitor.visit_vis(vis)); - try_visit!(kind.walk(*span, *id, vis, ctxt, visitor)); - V::Result::output() -} - pub fn walk_struct_def<'a, V: Visitor<'a>>( visitor: &mut V, struct_definition: &'a VariantData, @@ -1455,15 +1550,3 @@ pub fn walk_attr_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a AttrArgs) - } V::Result::output() } - -fn walk_define_opaques<'a, V: Visitor<'a>>( - visitor: &mut V, - define_opaque: &'a Option>, -) -> V::Result { - if let Some(define_opaque) = define_opaque { - for (id, path) in define_opaque { - try_visit!(visitor.visit_path(path, *id)); - } - } - V::Result::output() -} diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index f9601fa5ef1d8..2aeff4e66d56b 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -277,7 +277,7 @@ impl<'ast, 'ecx, 'tcx, T: EarlyLintPass> ast_visit::Visitor<'ast> ast_visit::walk_attribute(self, attr); } - fn visit_mac_def(&mut self, mac: &'ast ast::MacroDef, id: ast::NodeId) { + fn visit_macro_def(&mut self, mac: &'ast ast::MacroDef, id: ast::NodeId) { lint_callback!(self, check_mac_def, mac); self.check_id(id); } From 7c026ea31daa07d2ab2ae9562f878870ef8705c9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 23 May 2025 16:41:37 +0200 Subject: [PATCH 2665/4206] Add missing space in usage.md --- docs/usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/usage.md b/docs/usage.md index dbe36109f83e9..9dcfee4f535a7 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -47,7 +47,7 @@ These are a few functions that allow you to easily run rust code from the shell ```bash function jit_naked() { - echo "$@" | $cg_clif_dir/dist/rustc-clif - -Zunstable-options -Cllvm-args=jit-mode-Cprefer-dynamic + echo "$@" | $cg_clif_dir/dist/rustc-clif - -Zunstable-options -Cllvm-args=jit-mode -Cprefer-dynamic } function jit() { From dcd3168c97c6024b24f80abbb2407c81d9b0a25a Mon Sep 17 00:00:00 2001 From: beetrees Date: Fri, 23 May 2025 15:51:51 +0100 Subject: [PATCH 2666/4206] Use correct sign extension on `__powi*f2` arguments --- src/abi/mod.rs | 28 ++++++++++++++++++++++++++++ src/intrinsics/mod.rs | 3 ++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/abi/mod.rs b/src/abi/mod.rs index 70d29596e22cb..5f7bf3821d77d 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -828,3 +828,31 @@ pub(crate) fn codegen_drop<'tcx>( } } } + +pub(crate) fn lib_call_arg_param(tcx: TyCtxt<'_>, ty: Type, is_signed: bool) -> AbiParam { + let param = AbiParam::new(ty); + if ty.is_int() && u64::from(ty.bits()) < tcx.data_layout.pointer_size.bits() { + match (&*tcx.sess.target.arch, &*tcx.sess.target.vendor) { + ("x86_64", _) | ("aarch64", "apple") => match (ty, is_signed) { + (types::I8 | types::I16, true) => param.sext(), + (types::I8 | types::I16, false) => param.uext(), + _ => param, + }, + ("aarch64", _) => param, + ("riscv64", _) => match (ty, is_signed) { + (types::I32, _) | (_, true) => param.sext(), + _ => param.uext(), + }, + ("s390x", _) => { + if is_signed { + param.sext() + } else { + param.uext() + } + } + _ => unimplemented!("{:?}", tcx.sess.target.arch), + } + } else { + param + } +} diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index 25e224ebfe2c9..7c18922d93cd3 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -416,7 +416,8 @@ fn codegen_float_intrinsic_call<'tcx>( // These intrinsics aren't supported natively by Cranelift. // Lower them to a libcall. sym::powif32 | sym::powif64 => { - let input_tys: Vec<_> = vec![AbiParam::new(clif_ty), AbiParam::new(types::I32)]; + let input_tys: Vec<_> = + vec![AbiParam::new(clif_ty), lib_call_arg_param(fx.tcx, types::I32, true)]; let ret_val = fx.lib_call(name, input_tys, vec![AbiParam::new(clif_ty)], &args)[0]; CValue::by_val(ret_val, fx.layout_of(ty)) } From 589d03cd05b14d930d851ee56a551401d9ed4d3d Mon Sep 17 00:00:00 2001 From: jyn Date: Fri, 23 May 2025 10:41:44 -0400 Subject: [PATCH 2667/4206] document why rustdoc cannot look at function bodies --- src/doc/rustc-dev-guide/src/rustdoc.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/rustdoc.md b/src/doc/rustc-dev-guide/src/rustdoc.md index e36d6a388a981..3139dfc63fd00 100644 --- a/src/doc/rustc-dev-guide/src/rustdoc.md +++ b/src/doc/rustc-dev-guide/src/rustdoc.md @@ -116,6 +116,28 @@ Certain browser features that require secure origins, like `localStorage` and Service Workers, don't work reliably. We can still use such features but we should make sure pages are still usable without them. +Rustdoc [does not type-check function bodies][platform-specific docs]. +This works by [overriding the built-in queries for typeck][override queries], +by [silencing name resolution errors], and by [not resolving opaque types]. +This comes with several caveats: in particular, rustdoc *cannot* run any parts of the compiler that +require type-checking bodies; for example it cannot generate `.rlib` files or run most lints. +We want to move away from this model eventually, but we need some alternative for +[the people using it][async-std]; see [various][zulip stop accepting broken code] +[previous][rustdoc meeting 2024-07-08] [zulip][compiler meeting 2023-01-26] [discussion][notriddle rfc]. +For examples of code that breaks if this hack is removed, see +[`tests/rustdoc-ui/error-in-impl-trait`]. + +[platform-specific docs]: https://doc.rust-lang.org/rustdoc/advanced-features.html#interactions-between-platform-specific-docs +[override queries]: https://github.com/rust-lang/rust/blob/52bf0cf795dfecc8b929ebb1c1e2545c3f41d4c9/src/librustdoc/core.rs#L299-L323 +[silencing name resolution errors]: https://github.com/rust-lang/rust/blob/52bf0cf795dfecc8b929ebb1c1e2545c3f41d4c9/compiler/rustc_resolve/src/late.rs#L4517 +[not resolving opaque types]: https://github.com/rust-lang/rust/blob/52bf0cf795dfecc8b929ebb1c1e2545c3f41d4c9/compiler/rustc_hir_analysis/src/check/check.rs#L188-L194 +[async-std]: https://github.com/rust-lang/rust/issues/75100 +[rustdoc meeting 2024-07-08]: https://rust-lang.zulipchat.com/#narrow/channel/393423-t-rustdoc.2Fmeetings/topic/meeting.202024-07-08/near/449969836 +[compiler meeting 2023-01-26]: https://rust-lang.zulipchat.com/#narrow/channel/238009-t-compiler.2Fmeetings/topic/.5Bweekly.5D.202023-01-26/near/323755789 +[zulip stop accepting broken code]: https://rust-lang.zulipchat.com/#narrow/stream/266220-rustdoc/topic/stop.20accepting.20broken.20code +[notriddle rfc]: https://rust-lang.zulipchat.com/#narrow/channel/266220-t-rustdoc/topic/Pre-RFC.3A.20stop.20accepting.20broken.20code +[`tests/rustdoc-ui/error-in-impl-trait`]: https://github.com/rust-lang/rust/tree/163cb4ea3f0ae3bc7921cc259a08a7bf92e73ee6/tests/rustdoc-ui/error-in-impl-trait + ## Multiple runs, same output directory Rustdoc can be run multiple times for varying inputs, with its output set to the From a467516c2208474ec21b0ea139c45f7d41cbad7e Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 24 Mar 2025 18:12:21 +0100 Subject: [PATCH 2668/4206] std: fix aliasing bug in UNIX process implementation `CStringArray` contained both `CString`s and their pointers. Unfortunately, since `CString` uses `Box`, moving the `CString`s into the `Vec` can (under stacked borrows) invalidate the pointer to the string, meaning the resulting `Vec<*const c_char>` was, from an opsem perspective, unusable. This PR removes removes the `Vec` from `CStringArray`, instead recreating the `CString`/`CStr` from the pointers when necessary. Also,`CStringArray` is now used for the process args as well, the old implementation was suffering from the same kind of bug. --- library/std/src/sys/process/unix/common.rs | 116 ++++-------------- .../sys/process/unix/common/cstring_array.rs | 102 +++++++++++++++ 2 files changed, 129 insertions(+), 89 deletions(-) create mode 100644 library/std/src/sys/process/unix/common/cstring_array.rs diff --git a/library/std/src/sys/process/unix/common.rs b/library/std/src/sys/process/unix/common.rs index e205a8390052f..b6777b76668d5 100644 --- a/library/std/src/sys/process/unix/common.rs +++ b/library/std/src/sys/process/unix/common.rs @@ -1,8 +1,10 @@ #[cfg(all(test, not(target_os = "emscripten")))] mod tests; -use libc::{EXIT_FAILURE, EXIT_SUCCESS, c_char, c_int, gid_t, pid_t, uid_t}; +use libc::{EXIT_FAILURE, EXIT_SUCCESS, c_int, gid_t, pid_t, uid_t}; +pub use self::cstring_array::CStringArray; +use self::cstring_array::CStringIter; use crate::collections::BTreeMap; use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::os::unix::prelude::*; @@ -14,7 +16,9 @@ use crate::sys::fs::OpenOptions; use crate::sys::pipe::{self, AnonPipe}; use crate::sys::process::env::{CommandEnv, CommandEnvs}; use crate::sys_common::{FromInner, IntoInner}; -use crate::{fmt, io, ptr}; +use crate::{fmt, io}; + +mod cstring_array; cfg_if::cfg_if! { if #[cfg(target_os = "fuchsia")] { @@ -77,13 +81,7 @@ cfg_if::cfg_if! { pub struct Command { program: CString, - args: Vec, - /// Exactly what will be passed to `execvp`. - /// - /// First element is a pointer to `program`, followed by pointers to - /// `args`, followed by a `null`. Be careful when modifying `program` or - /// `args` to properly update this as well. - argv: Argv, + args: CStringArray, env: CommandEnv, program_kind: ProgramKind, @@ -102,14 +100,6 @@ pub struct Command { pgroup: Option, } -// Create a new type for argv, so that we can make it `Send` and `Sync` -struct Argv(Vec<*const c_char>); - -// It is safe to make `Argv` `Send` and `Sync`, because it contains -// pointers to memory owned by `Command.args` -unsafe impl Send for Argv {} -unsafe impl Sync for Argv {} - // passed back to std::process with the pipes connected to the child, if any // were requested pub struct StdioPipes { @@ -171,42 +161,17 @@ impl ProgramKind { } impl Command { - #[cfg(not(target_os = "linux"))] pub fn new(program: &OsStr) -> Command { let mut saw_nul = false; let program_kind = ProgramKind::new(program.as_ref()); let program = os2c(program, &mut saw_nul); + let mut args = CStringArray::with_capacity(1); + args.push(program.clone()); Command { - argv: Argv(vec![program.as_ptr(), ptr::null()]), - args: vec![program.clone()], program, - program_kind, + args, env: Default::default(), - cwd: None, - chroot: None, - uid: None, - gid: None, - saw_nul, - closures: Vec::new(), - groups: None, - stdin: None, - stdout: None, - stderr: None, - pgroup: None, - } - } - - #[cfg(target_os = "linux")] - pub fn new(program: &OsStr) -> Command { - let mut saw_nul = false; - let program_kind = ProgramKind::new(program.as_ref()); - let program = os2c(program, &mut saw_nul); - Command { - argv: Argv(vec![program.as_ptr(), ptr::null()]), - args: vec![program.clone()], - program, program_kind, - env: Default::default(), cwd: None, chroot: None, uid: None, @@ -217,6 +182,7 @@ impl Command { stdin: None, stdout: None, stderr: None, + #[cfg(target_os = "linux")] create_pidfd: false, pgroup: None, } @@ -225,20 +191,11 @@ impl Command { pub fn set_arg_0(&mut self, arg: &OsStr) { // Set a new arg0 let arg = os2c(arg, &mut self.saw_nul); - debug_assert!(self.argv.0.len() > 1); - self.argv.0[0] = arg.as_ptr(); - self.args[0] = arg; + self.args.write(0, arg); } pub fn arg(&mut self, arg: &OsStr) { - // Overwrite the trailing null pointer in `argv` and then add a new null - // pointer. let arg = os2c(arg, &mut self.saw_nul); - self.argv.0[self.args.len()] = arg.as_ptr(); - self.argv.0.push(ptr::null()); - - // Also make sure we keep track of the owned value to schedule a - // destructor for this memory. self.args.push(arg); } @@ -295,6 +252,8 @@ impl Command { pub fn get_args(&self) -> CommandArgs<'_> { let mut iter = self.args.iter(); + // argv[0] contains the program name, but we are only interested in the + // arguments so skip it. iter.next(); CommandArgs { iter } } @@ -307,12 +266,12 @@ impl Command { self.cwd.as_ref().map(|cs| Path::new(OsStr::from_bytes(cs.as_bytes()))) } - pub fn get_argv(&self) -> &Vec<*const c_char> { - &self.argv.0 + pub fn get_argv(&self) -> &CStringArray { + &self.args } pub fn get_program_cstr(&self) -> &CStr { - &*self.program + &self.program } #[allow(dead_code)] @@ -405,32 +364,6 @@ fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString { }) } -// Helper type to manage ownership of the strings within a C-style array. -pub struct CStringArray { - items: Vec, - ptrs: Vec<*const c_char>, -} - -impl CStringArray { - pub fn with_capacity(capacity: usize) -> Self { - let mut result = CStringArray { - items: Vec::with_capacity(capacity), - ptrs: Vec::with_capacity(capacity + 1), - }; - result.ptrs.push(ptr::null()); - result - } - pub fn push(&mut self, item: CString) { - let l = self.ptrs.len(); - self.ptrs[l - 1] = item.as_ptr(); - self.ptrs.push(ptr::null()); - self.items.push(item); - } - pub fn as_ptr(&self) -> *const *const c_char { - self.ptrs.as_ptr() - } -} - fn construct_envp(env: BTreeMap, saw_nul: &mut bool) -> CStringArray { let mut result = CStringArray::with_capacity(env.len()); for (mut k, v) in env { @@ -619,14 +552,16 @@ impl fmt::Debug for Command { write!(f, "{}={value:?} ", key.to_string_lossy())?; } } - if self.program != self.args[0] { + + if *self.program != self.args[0] { write!(f, "[{:?}] ", self.program)?; } - write!(f, "{:?}", self.args[0])?; + write!(f, "{:?}", &self.args[0])?; - for arg in &self.args[1..] { + for arg in self.get_args() { write!(f, " {:?}", arg)?; } + Ok(()) } } @@ -658,14 +593,16 @@ impl From for ExitCode { } pub struct CommandArgs<'a> { - iter: crate::slice::Iter<'a, CString>, + iter: CStringIter<'a>, } impl<'a> Iterator for CommandArgs<'a> { type Item = &'a OsStr; + fn next(&mut self) -> Option<&'a OsStr> { - self.iter.next().map(|cs| OsStr::from_bytes(cs.as_bytes())) + self.iter.next().map(|cs| OsStr::from_bytes(cs.to_bytes())) } + fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } @@ -675,6 +612,7 @@ impl<'a> ExactSizeIterator for CommandArgs<'a> { fn len(&self) -> usize { self.iter.len() } + fn is_empty(&self) -> bool { self.iter.is_empty() } diff --git a/library/std/src/sys/process/unix/common/cstring_array.rs b/library/std/src/sys/process/unix/common/cstring_array.rs new file mode 100644 index 0000000000000..69569461ba408 --- /dev/null +++ b/library/std/src/sys/process/unix/common/cstring_array.rs @@ -0,0 +1,102 @@ +use crate::ffi::{CStr, CString, c_char}; +use crate::ops::Index; +use crate::{fmt, mem, ptr}; + +/// Helper type to manage ownership of the strings within a C-style array. +/// +/// This type manages an array of C-string pointers terminated by a null +/// pointer. The pointer to the array (as returned by `as_ptr`) can be used as +/// a value of `argv` or `environ`. +pub struct CStringArray { + ptrs: Vec<*const c_char>, +} + +impl CStringArray { + /// Creates a new `CStringArray` with enough capacity to hold `capacity` + /// strings. + pub fn with_capacity(capacity: usize) -> Self { + let mut result = CStringArray { ptrs: Vec::with_capacity(capacity + 1) }; + result.ptrs.push(ptr::null()); + result + } + + /// Replace the string at position `index`. + pub fn write(&mut self, index: usize, item: CString) { + let argc = self.ptrs.len() - 1; + let ptr = &mut self.ptrs[..argc][index]; + let old = mem::replace(ptr, item.into_raw()); + drop(unsafe { CString::from_raw(old.cast_mut()) }); + } + + /// Push an additional string to the array. + pub fn push(&mut self, item: CString) { + let argc = self.ptrs.len() - 1; + // Replace the null pointer at the end of the array... + self.ptrs[argc] = item.into_raw(); + // ... and recreate it to restore the data structure invariant. + self.ptrs.push(ptr::null()); + } + + /// Returns a pointer to the C-string array managed by this type. + pub fn as_ptr(&self) -> *const *const c_char { + self.ptrs.as_ptr() + } + + /// Returns an iterator over all `CStr`s contained in this array. + pub fn iter(&self) -> CStringIter<'_> { + CStringIter { iter: self.ptrs[..self.ptrs.len() - 1].iter() } + } +} + +impl Index for CStringArray { + type Output = CStr; + fn index(&self, index: usize) -> &CStr { + let ptr = self.ptrs[..self.ptrs.len() - 1][index]; + unsafe { CStr::from_ptr(ptr) } + } +} + +impl fmt::Debug for CStringArray { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +// SAFETY: `CStringArray` is basically just a `Vec` +unsafe impl Send for CStringArray {} +// SAFETY: `CStringArray` is basically just a `Vec` +unsafe impl Sync for CStringArray {} + +impl Drop for CStringArray { + fn drop(&mut self) { + self.ptrs[..self.ptrs.len() - 1] + .iter() + .for_each(|&p| drop(unsafe { CString::from_raw(p.cast_mut()) })) + } +} + +/// An iterator over all `CStr`s contained in a `CStringArray`. +#[derive(Clone)] +pub struct CStringIter<'a> { + iter: crate::slice::Iter<'a, *const c_char>, +} + +impl<'a> Iterator for CStringIter<'a> { + type Item = &'a CStr; + fn next(&mut self) -> Option<&'a CStr> { + self.iter.next().map(|&p| unsafe { CStr::from_ptr(p) }) + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl<'a> ExactSizeIterator for CStringIter<'a> { + fn len(&self) -> usize { + self.iter.len() + } + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} From 89a90d664082280584a27cc8030aba85d122448f Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 21 Apr 2025 15:57:46 +0200 Subject: [PATCH 2669/4206] std: add safety comments to `CStringArray` --- .../src/sys/process/unix/common/cstring_array.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/library/std/src/sys/process/unix/common/cstring_array.rs b/library/std/src/sys/process/unix/common/cstring_array.rs index 69569461ba408..1c840a85df9ba 100644 --- a/library/std/src/sys/process/unix/common/cstring_array.rs +++ b/library/std/src/sys/process/unix/common/cstring_array.rs @@ -25,6 +25,10 @@ impl CStringArray { let argc = self.ptrs.len() - 1; let ptr = &mut self.ptrs[..argc][index]; let old = mem::replace(ptr, item.into_raw()); + // SAFETY: + // `CStringArray` owns all of its strings, and they were all transformed + // into pointers using `CString::into_raw`. Also, this is not the null + // pointer since the indexing above would have failed. drop(unsafe { CString::from_raw(old.cast_mut()) }); } @@ -52,6 +56,9 @@ impl Index for CStringArray { type Output = CStr; fn index(&self, index: usize) -> &CStr { let ptr = self.ptrs[..self.ptrs.len() - 1][index]; + // SAFETY: + // `CStringArray` owns all of its strings. Also, this is not the null + // pointer since the indexing above would have failed. unsafe { CStr::from_ptr(ptr) } } } @@ -69,6 +76,9 @@ unsafe impl Sync for CStringArray {} impl Drop for CStringArray { fn drop(&mut self) { + // SAFETY: + // `CStringArray` owns all of its strings, and they were all transformed + // into pointers using `CString::into_raw`. self.ptrs[..self.ptrs.len() - 1] .iter() .for_each(|&p| drop(unsafe { CString::from_raw(p.cast_mut()) })) @@ -84,6 +94,9 @@ pub struct CStringIter<'a> { impl<'a> Iterator for CStringIter<'a> { type Item = &'a CStr; fn next(&mut self) -> Option<&'a CStr> { + // SAFETY: + // `CStringArray` owns all of its strings. Also, this is not the null + // pointer since the last element is excluded when creating `iter`. self.iter.next().map(|&p| unsafe { CStr::from_ptr(p) }) } From a08f6f10d4ab94d53793480782e9e939b48a3ebe Mon Sep 17 00:00:00 2001 From: Benno Lossin Date: Fri, 23 May 2025 15:38:57 +0200 Subject: [PATCH 2670/4206] document representation of `Option` --- library/core/src/option.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index aed5a043c11a3..e2182e54b484c 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -135,7 +135,7 @@ //! | [`ptr::NonNull`] | when `U: Sized` | //! | `#[repr(transparent)]` struct around one of the types in this list. | when it holds for the inner type | //! -//! [^extern_fn]: this remains true for any argument/return types and any other ABI: `extern "abi" fn` (_e.g._, `extern "system" fn`) +//! [^extern_fn]: this remains true for `unsafe` variants, any argument/return types, and any other ABI: `[unsafe] extern "abi" fn` (_e.g._, `extern "system" fn`) //! //! Under some conditions the above types `T` are also null pointer optimized when wrapped in a [`Result`][result_repr]. //! From 55298ea6ea61f337ac563381582b66d3aa9c0b7f Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sat, 10 May 2025 19:25:46 +0300 Subject: [PATCH 2671/4206] if stage isn't set explicitly, default to 1 when running miri Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/run.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 0bba441c3fa26..f6eb1f6fd9055 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -118,7 +118,15 @@ impl Step for Miri { fn run(self, builder: &Builder<'_>) { let host = builder.build.build; let target = self.target; - let stage = builder.top_stage; + + // `x run` uses stage 0 by default but miri does not work well with stage 0. + // Change the stage to 1 if it's not set explicitly. + let stage = if builder.config.is_explicit_stage() || builder.top_stage >= 1 { + builder.top_stage + } else { + 1 + }; + if stage == 0 { eprintln!("miri cannot be run at stage 0"); std::process::exit(1); From 8bf515330fb68ba10a54e9087a2b5629a968e766 Mon Sep 17 00:00:00 2001 From: joboet Date: Fri, 23 May 2025 18:00:09 +0200 Subject: [PATCH 2672/4206] std: abort the process on failure to allocate a TLS key The panic machinery uses TLS, so panicking if no TLS keys are left can lead to infinite recursion (see https://github.com/rust-lang/rust/issues/140798#issuecomment-2872307377). Rather than having separate logic for the panic count and the thread name, just always abort the process if a TLS key allocation fails. This also has the benefit of aligning the key-based TLS implementation with the documentation, which does not mention that a panic could also occur because of resource exhaustion. --- library/std/src/sys/thread_local/key/unix.rs | 4 +++- library/std/src/sys/thread_local/key/windows.rs | 17 +++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/library/std/src/sys/thread_local/key/unix.rs b/library/std/src/sys/thread_local/key/unix.rs index 93bd0d1f66850..8fa24265e432a 100644 --- a/library/std/src/sys/thread_local/key/unix.rs +++ b/library/std/src/sys/thread_local/key/unix.rs @@ -25,7 +25,9 @@ pub type Key = libc::pthread_key_t; #[inline] pub fn create(dtor: Option) -> Key { let mut key = 0; - assert_eq!(unsafe { libc::pthread_key_create(&mut key, mem::transmute(dtor)) }, 0); + if unsafe { libc::pthread_key_create(&mut key, mem::transmute(dtor)) } != 0 { + rtabort!("out of TLS keys"); + } key } diff --git a/library/std/src/sys/thread_local/key/windows.rs b/library/std/src/sys/thread_local/key/windows.rs index c34c7bc204fd4..2ff0fd1196e12 100644 --- a/library/std/src/sys/thread_local/key/windows.rs +++ b/library/std/src/sys/thread_local/key/windows.rs @@ -81,15 +81,10 @@ impl LazyKey { } else { let key = unsafe { c::TlsAlloc() }; if key == c::TLS_OUT_OF_INDEXES { - // Wakeup the waiting threads before panicking to avoid deadlock. - unsafe { - c::InitOnceComplete( - self.once.get(), - c::INIT_ONCE_INIT_FAILED, - ptr::null_mut(), - ); - } - panic!("out of TLS indexes"); + // Since we abort the process, there is no need to wake up + // the waiting threads. If this were a panic, the wakeup + // would need to occur first in order to avoid deadlock. + rtabort!("out of TLS indexes"); } unsafe { @@ -112,7 +107,9 @@ impl LazyKey { // If there is no destructor to clean up, we can use racy initialization. let key = unsafe { c::TlsAlloc() }; - assert_ne!(key, c::TLS_OUT_OF_INDEXES, "out of TLS indexes"); + if key == c::TLS_OUT_OF_INDEXES { + rtabort!("out of TLS indexes"); + } match self.key.compare_exchange(0, key + 1, AcqRel, Acquire) { Ok(_) => key, From 343fecabc750fa10bc695ad840cfc3ff9bc70830 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 23 May 2025 18:14:49 +0200 Subject: [PATCH 2673/4206] Suggest correct `version("..")` predicate syntax in check-cfg --- compiler/rustc_lint/messages.ftl | 1 + .../src/early/diagnostics/check_cfg.rs | 8 ++++++++ compiler/rustc_lint/src/lints.rs | 10 ++++++++++ tests/ui/check-cfg/wrong-version-syntax.fixed | 14 ++++++++++++++ tests/ui/check-cfg/wrong-version-syntax.rs | 14 ++++++++++++++ tests/ui/check-cfg/wrong-version-syntax.stderr | 17 +++++++++++++++++ 6 files changed, 64 insertions(+) create mode 100644 tests/ui/check-cfg/wrong-version-syntax.fixed create mode 100644 tests/ui/check-cfg/wrong-version-syntax.rs create mode 100644 tests/ui/check-cfg/wrong-version-syntax.stderr diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 08180bf8f8b2c..7fdf26bf3af99 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -835,6 +835,7 @@ lint_unexpected_cfg_name_similar_name = there is a config with a similar name lint_unexpected_cfg_name_similar_name_different_values = there is a config with a similar name and different values lint_unexpected_cfg_name_similar_name_no_value = there is a config with a similar name and no value lint_unexpected_cfg_name_similar_name_value = there is a config with a similar name and value +lint_unexpected_cfg_name_version_syntax = there is a similar config predicate: `version("..")` lint_unexpected_cfg_name_with_similar_value = found config with similar value lint_unexpected_cfg_value = unexpected `cfg` condition value: {$has_value -> diff --git a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs index 946dbc34f7138..e2f5dd315d570 100644 --- a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs +++ b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs @@ -140,6 +140,14 @@ pub(super) fn unexpected_cfg_name( let code_sugg = if is_feature_cfg && is_from_cargo { lints::unexpected_cfg_name::CodeSuggestion::DefineFeatures + // Suggest correct `version("..")` predicate syntax + } else if let Some((_value, value_span)) = value + && name == sym::version + { + lints::unexpected_cfg_name::CodeSuggestion::VersionSyntax { + between_name_and_value: name_span.between(value_span), + after_value: value_span.shrink_to_hi(), + } // Suggest the most probable if we found one } else if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) { is_feature_cfg |= best_match == sym::feature; diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 7268a7f704fcb..af8fa8ffa1fa7 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2273,6 +2273,16 @@ pub(crate) mod unexpected_cfg_name { pub(crate) enum CodeSuggestion { #[help(lint_unexpected_cfg_define_features)] DefineFeatures, + #[multipart_suggestion( + lint_unexpected_cfg_name_version_syntax, + applicability = "machine-applicable" + )] + VersionSyntax { + #[suggestion_part(code = "(")] + between_name_and_value: Span, + #[suggestion_part(code = ")")] + after_value: Span, + }, #[suggestion( lint_unexpected_cfg_name_similar_name_value, applicability = "maybe-incorrect", diff --git a/tests/ui/check-cfg/wrong-version-syntax.fixed b/tests/ui/check-cfg/wrong-version-syntax.fixed new file mode 100644 index 0000000000000..efbe2ed1bd855 --- /dev/null +++ b/tests/ui/check-cfg/wrong-version-syntax.fixed @@ -0,0 +1,14 @@ +// Check warning for wrong `cfg(version("1.27"))` syntax +// +//@ check-pass +//@ no-auto-check-cfg +//@ compile-flags: --check-cfg=cfg() +//@ run-rustfix + +#![feature(cfg_version)] + +#[cfg(not(version("1.48.0")))] +//~^ WARNING unexpected `cfg` condition name: `version` +pub fn g() {} + +pub fn main() {} diff --git a/tests/ui/check-cfg/wrong-version-syntax.rs b/tests/ui/check-cfg/wrong-version-syntax.rs new file mode 100644 index 0000000000000..221ecf4cae887 --- /dev/null +++ b/tests/ui/check-cfg/wrong-version-syntax.rs @@ -0,0 +1,14 @@ +// Check warning for wrong `cfg(version("1.27"))` syntax +// +//@ check-pass +//@ no-auto-check-cfg +//@ compile-flags: --check-cfg=cfg() +//@ run-rustfix + +#![feature(cfg_version)] + +#[cfg(not(version = "1.48.0"))] +//~^ WARNING unexpected `cfg` condition name: `version` +pub fn g() {} + +pub fn main() {} diff --git a/tests/ui/check-cfg/wrong-version-syntax.stderr b/tests/ui/check-cfg/wrong-version-syntax.stderr new file mode 100644 index 0000000000000..97157a0c02b97 --- /dev/null +++ b/tests/ui/check-cfg/wrong-version-syntax.stderr @@ -0,0 +1,17 @@ +warning: unexpected `cfg` condition name: `version` + --> $DIR/wrong-version-syntax.rs:10:11 + | +LL | #[cfg(not(version = "1.48.0"))] + | ^^^^^^^^^^^^^^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(version, values("1.48.0"))` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default +help: there is a similar config predicate: `version("..")` + | +LL - #[cfg(not(version = "1.48.0"))] +LL + #[cfg(not(version("1.48.0")))] + | + +warning: 1 warning emitted + From a12b455bd05a5e8336013f03dc20905651837d54 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 23 May 2025 09:37:23 -0700 Subject: [PATCH 2674/4206] Update mdbook to 0.4.50 --- src/tools/rustbook/Cargo.lock | 53 +++-------------------------------- src/tools/rustbook/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 50 deletions(-) diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index 0b38937701117..5c862e9540075 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -343,17 +343,6 @@ dependencies = [ "regex", ] -[[package]] -name = "dbus" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b" -dependencies = [ - "libc", - "libdbus-sys", - "winapi", -] - [[package]] name = "derive_builder" version = "0.20.2" @@ -823,16 +812,6 @@ version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" -[[package]] -name = "libdbus-sys" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72" -dependencies = [ - "cc", - "pkg-config", -] - [[package]] name = "linereader" version = "0.4.0" @@ -906,9 +885,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.49" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1daacee059634081dee4250d2814763a365b92dfe14bfdef964bc27835209d4" +checksum = "f72bc08f096e1fb15cfc382babe218317c2897d2040f967c4db40d156ca28e21" dependencies = [ "ammonia", "anyhow", @@ -921,7 +900,6 @@ dependencies = [ "hex", "log", "memchr", - "once_cell", "opener", "pulldown-cmark 0.10.3", "regex", @@ -1070,12 +1048,11 @@ dependencies = [ [[package]] name = "opener" -version = "0.7.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0812e5e4df08da354c851a3376fead46db31c2214f849d3de356d774d057681" +checksum = "de96cad6ee771be7f68df884d3767460b4684012308d8342ed5623fe62b2628c" dependencies = [ "bstr", - "dbus", "normpath", "windows-sys", ] @@ -1905,22 +1882,6 @@ dependencies = [ "string_cache_codegen", ] -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - [[package]] name = "winapi-util" version = "0.1.9" @@ -1930,12 +1891,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - [[package]] name = "windows-core" version = "0.61.0" diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index 10fde31306dff..ee2ada5aa2b38 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -15,6 +15,6 @@ mdbook-i18n-helpers = "0.3.3" mdbook-spec = { path = "../../doc/reference/mdbook-spec" } [dependencies.mdbook] -version = "0.4.49" +version = "0.4.50" default-features = false features = ["search"] From 17d27c993e67f5a466a0911cf1f54df93514d8db Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sat, 10 May 2025 19:23:36 +0300 Subject: [PATCH 2675/4206] let `tool::Miri` implementation to handle compilers Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/run.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index f6eb1f6fd9055..eeba7780c65b3 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -133,8 +133,10 @@ impl Step for Miri { } // This compiler runs on the host, we'll just use it for the target. - let target_compiler = builder.compiler(stage, host); - let host_compiler = tool::get_tool_rustc_compiler(builder, target_compiler); + let target_compiler = builder.compiler(stage, target); + let miri_build = builder.ensure(tool::Miri { compiler: target_compiler, target }); + // Rustc tools are off by one stage, so use the build compiler to run miri. + let host_compiler = miri_build.build_compiler; // Get a target sysroot for Miri. let miri_sysroot = test::Miri::build_miri_sysroot(builder, target_compiler, target); From 4a7598f815825fa485a9f71d759a2f2faf9342ed Mon Sep 17 00:00:00 2001 From: blyxyas Date: Thu, 22 May 2025 12:44:37 +0200 Subject: [PATCH 2676/4206] [HEAVY PERF] Optimize documentation lints 2/2 So, after https://github.com/rust-lang/rust-clippy/pull/14693 was merged, this is the continuation. It performs some optimizations on `Fragments::span` , makes it so we don't call it so much, and makes a 85.75% decrease (7.51% -> 10.07%) in execution samples of `source_span_for_markdown_range` and a 6.39% -> 0.88% for `core::StrSearcher::new`. Overall a 13.11% icount decrase on docs-heavy crates. Benchmarked mainly on `regex-1.10.5`. This means that currently our heaviest function is `rustc_middle::Interners::intern_ty`, even for documentation-heavy crates Co-authored-by: Roope Salmi --- clippy_lints/src/doc/lazy_continuation.rs | 88 ++++++++++++----------- clippy_lints/src/doc/mod.rs | 18 ++--- 2 files changed, 54 insertions(+), 52 deletions(-) diff --git a/clippy_lints/src/doc/lazy_continuation.rs b/clippy_lints/src/doc/lazy_continuation.rs index 8aeb835fe3934..cb9d68224dbb8 100644 --- a/clippy_lints/src/doc/lazy_continuation.rs +++ b/clippy_lints/src/doc/lazy_continuation.rs @@ -2,11 +2,10 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use itertools::Itertools; use rustc_errors::Applicability; use rustc_lint::LateContext; -use rustc_span::{BytePos, Span}; -use std::cmp::Ordering; +use rustc_span::BytePos; use std::ops::Range; -use super::{DOC_LAZY_CONTINUATION, DOC_OVERINDENTED_LIST_ITEMS}; +use super::{DOC_LAZY_CONTINUATION, DOC_OVERINDENTED_LIST_ITEMS, Fragments}; fn map_container_to_text(c: &super::Container) -> &'static str { match c { @@ -19,29 +18,27 @@ fn map_container_to_text(c: &super::Container) -> &'static str { pub(super) fn check( cx: &LateContext<'_>, doc: &str, - range: Range, - mut span: Span, + cooked_range: Range, + fragments: &Fragments<'_>, containers: &[super::Container], ) { - if doc[range.clone()].contains('\t') { - // We don't do tab stops correctly. - return; - } - - // Blockquote - let ccount = doc[range.clone()].chars().filter(|c| *c == '>').count(); + // Get blockquotes + let ccount = doc[cooked_range.clone()].chars().filter(|c| *c == '>').count(); let blockquote_level = containers .iter() .filter(|c| matches!(c, super::Container::Blockquote)) .count(); - if ccount < blockquote_level { + + if ccount < blockquote_level + && let Some(mut span) = fragments.span(cx, cooked_range.clone()) + { span_lint_and_then( cx, DOC_LAZY_CONTINUATION, span, "doc quote line without `>` marker", |diag| { - let mut doc_start_range = &doc[range]; + let mut doc_start_range = &doc[cooked_range]; let mut suggested = String::new(); for c in containers { let text = map_container_to_text(c); @@ -78,7 +75,7 @@ pub(super) fn check( } // List - let leading_spaces = doc[range].chars().filter(|c| *c == ' ').count(); + let leading_spaces = doc[cooked_range.clone()].chars().filter(|c| *c == ' ').count(); let list_indentation = containers .iter() .map(|c| { @@ -89,36 +86,41 @@ pub(super) fn check( } }) .sum(); - match leading_spaces.cmp(&list_indentation) { - Ordering::Less => span_lint_and_then( - cx, - DOC_LAZY_CONTINUATION, - span, - "doc list item without indentation", - |diag| { - // simpler suggestion style for indentation - let indent = list_indentation - leading_spaces; - diag.span_suggestion_verbose( - span.shrink_to_hi(), - "indent this line", - std::iter::repeat_n(" ", indent).join(""), - Applicability::MaybeIncorrect, - ); - diag.help("if this is supposed to be its own paragraph, add a blank line"); - }, - ), - Ordering::Greater => { - let sugg = std::iter::repeat_n(" ", list_indentation).join(""); - span_lint_and_sugg( + + if leading_spaces != list_indentation + && let Some(span) = fragments.span(cx, cooked_range.clone()) + { + if leading_spaces < list_indentation { + span_lint_and_then( cx, - DOC_OVERINDENTED_LIST_ITEMS, + DOC_LAZY_CONTINUATION, span, - "doc list item overindented", - format!("try using `{sugg}` ({list_indentation} spaces)"), - sugg, - Applicability::MaybeIncorrect, + "doc list item without indentation", + |diag| { + // simpler suggestion style for indentation + let indent = list_indentation - leading_spaces; + diag.span_suggestion_verbose( + span.shrink_to_hi(), + "indent this line", + std::iter::repeat_n(" ", indent).join(""), + Applicability::MaybeIncorrect, + ); + diag.help("if this is supposed to be its own paragraph, add a blank line"); + }, ); - }, - Ordering::Equal => {}, + + return; + } + + let sugg = std::iter::repeat_n(" ", list_indentation).join(""); + span_lint_and_sugg( + cx, + DOC_OVERINDENTED_LIST_ITEMS, + span, + "doc list item overindented", + format!("try using `{sugg}` ({list_indentation} spaces)"), + sugg, + Applicability::MaybeIncorrect, + ); } } diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index c1491d96ceba7..c46dd09d60c56 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -3,7 +3,6 @@ use clippy_config::Conf; use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_then}; -use clippy_utils::source::snippet_opt; use clippy_utils::{is_entrypoint_fn, is_trait_impl_item}; use pulldown_cmark::Event::{ Code, DisplayMath, End, FootnoteReference, HardBreak, Html, InlineHtml, InlineMath, Rule, SoftBreak, Start, @@ -1082,26 +1081,27 @@ fn check_doc<'a, Events: Iterator, Range (), SoftBreak | HardBreak => { if !containers.is_empty() - && let Some((next_event, next_range)) = events.peek() - && let Some(next_span) = fragments.span(cx, next_range.clone()) - && let Some(span) = fragments.span(cx, range.clone()) && !in_footnote_definition + // Tabs aren't handled correctly vvvv + && !doc[range.clone()].contains('\t') + && let Some((next_event, next_range)) = events.peek() && !matches!(next_event, End(_)) { lazy_continuation::check( cx, doc, range.end..next_range.start, - Span::new(span.hi(), next_span.lo(), span.ctxt(), span.parent()), + &fragments, &containers[..], ); } - if let Some(span) = fragments.span(cx, range.clone()) + + if event == HardBreak + && !doc[range.clone()].trim().starts_with('\\') + && let Some(span) = fragments.span(cx, range.clone()) && !span.from_expansion() - && let Some(snippet) = snippet_opt(cx, span) - && !snippet.trim().starts_with('\\') - && event == HardBreak { + { collected_breaks.push(span); } }, From 11a6348820cfc881e5bf8aa61fb84214af2c3131 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Fri, 23 May 2025 13:59:12 -0400 Subject: [PATCH 2677/4206] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 47c911e9e6f64..68db37499f2de 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 47c911e9e6f6461f90ce19142031fe16876a3b95 +Subproject commit 68db37499f2de8acef704c73d9031be6fbcbaee4 From e21aab5b5c488f016fd7dbdbea5940fd605e0ab8 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Wed, 2 Apr 2025 18:41:27 +0530 Subject: [PATCH 2678/4206] std: sys: net: uefi: Implement TCP4 connect - Implement TCP4 connect using EFI_TCP4_PROTOCOL. - Tested on QEMU setup with connecting to TCP server on host. Signed-off-by: Ayush Singh --- .../std/src/sys/net/connection/uefi/mod.rs | 59 ++++----- .../std/src/sys/net/connection/uefi/tcp.rs | 21 ++++ .../std/src/sys/net/connection/uefi/tcp4.rs | 118 ++++++++++++++++++ library/std/src/sys/pal/uefi/helpers.rs | 10 +- 4 files changed, 178 insertions(+), 30 deletions(-) create mode 100644 library/std/src/sys/net/connection/uefi/tcp.rs create mode 100644 library/std/src/sys/net/connection/uefi/tcp4.rs diff --git a/library/std/src/sys/net/connection/uefi/mod.rs b/library/std/src/sys/net/connection/uefi/mod.rs index da2174396266f..46d67c8e51019 100644 --- a/library/std/src/sys/net/connection/uefi/mod.rs +++ b/library/std/src/sys/net/connection/uefi/mod.rs @@ -4,11 +4,14 @@ use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; use crate::sys::unsupported; use crate::time::Duration; -pub struct TcpStream(!); +mod tcp; +pub(crate) mod tcp4; + +pub struct TcpStream(#[expect(dead_code)] tcp::Tcp); impl TcpStream { - pub fn connect(_: io::Result<&SocketAddr>) -> io::Result { - unsupported() + pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result { + tcp::Tcp::connect(addr?).map(Self) } pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result { @@ -16,105 +19,105 @@ impl TcpStream { } pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { - self.0 + unsupported() } pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { - self.0 + unsupported() } pub fn read_timeout(&self) -> io::Result> { - self.0 + unsupported() } pub fn write_timeout(&self) -> io::Result> { - self.0 + unsupported() } pub fn peek(&self, _: &mut [u8]) -> io::Result { - self.0 + unsupported() } pub fn read(&self, _: &mut [u8]) -> io::Result { - self.0 + unsupported() } pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> { - self.0 + unsupported() } pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result { - self.0 + unsupported() } pub fn is_read_vectored(&self) -> bool { - self.0 + false } pub fn write(&self, _: &[u8]) -> io::Result { - self.0 + unsupported() } pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result { - self.0 + unsupported() } pub fn is_write_vectored(&self) -> bool { - self.0 + false } pub fn peer_addr(&self) -> io::Result { - self.0 + unsupported() } pub fn socket_addr(&self) -> io::Result { - self.0 + unsupported() } pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { - self.0 + unsupported() } pub fn duplicate(&self) -> io::Result { - self.0 + unsupported() } pub fn set_linger(&self, _: Option) -> io::Result<()> { - self.0 + unsupported() } pub fn linger(&self) -> io::Result> { - self.0 + unsupported() } pub fn set_nodelay(&self, _: bool) -> io::Result<()> { - self.0 + unsupported() } pub fn nodelay(&self) -> io::Result { - self.0 + unsupported() } pub fn set_ttl(&self, _: u32) -> io::Result<()> { - self.0 + unsupported() } pub fn ttl(&self) -> io::Result { - self.0 + unsupported() } pub fn take_error(&self) -> io::Result> { - self.0 + unsupported() } pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - self.0 + unsupported() } } impl fmt::Debug for TcpStream { fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 + todo!() } } diff --git a/library/std/src/sys/net/connection/uefi/tcp.rs b/library/std/src/sys/net/connection/uefi/tcp.rs new file mode 100644 index 0000000000000..f87accdc41de8 --- /dev/null +++ b/library/std/src/sys/net/connection/uefi/tcp.rs @@ -0,0 +1,21 @@ +use super::tcp4; +use crate::io; +use crate::net::SocketAddr; + +pub(crate) enum Tcp { + V4(#[expect(dead_code)] tcp4::Tcp4), +} + +impl Tcp { + pub(crate) fn connect(addr: &SocketAddr) -> io::Result { + match addr { + SocketAddr::V4(x) => { + let temp = tcp4::Tcp4::new()?; + temp.configure(true, Some(x), None)?; + temp.connect()?; + Ok(Tcp::V4(temp)) + } + SocketAddr::V6(_) => todo!(), + } + } +} diff --git a/library/std/src/sys/net/connection/uefi/tcp4.rs b/library/std/src/sys/net/connection/uefi/tcp4.rs new file mode 100644 index 0000000000000..f7ca373b52b5a --- /dev/null +++ b/library/std/src/sys/net/connection/uefi/tcp4.rs @@ -0,0 +1,118 @@ +use r_efi::efi::{self, Status}; +use r_efi::protocols::tcp4; + +use crate::io; +use crate::net::SocketAddrV4; +use crate::ptr::NonNull; +use crate::sync::atomic::{AtomicBool, Ordering}; +use crate::sys::pal::helpers; + +const TYPE_OF_SERVICE: u8 = 8; +const TIME_TO_LIVE: u8 = 255; + +pub(crate) struct Tcp4 { + protocol: NonNull, + flag: AtomicBool, + #[expect(dead_code)] + service_binding: helpers::ServiceProtocol, +} + +const DEFAULT_ADDR: efi::Ipv4Address = efi::Ipv4Address { addr: [0u8; 4] }; + +impl Tcp4 { + pub(crate) fn new() -> io::Result { + let service_binding = helpers::ServiceProtocol::open(tcp4::SERVICE_BINDING_PROTOCOL_GUID)?; + let protocol = helpers::open_protocol(service_binding.child_handle(), tcp4::PROTOCOL_GUID)?; + + Ok(Self { service_binding, protocol, flag: AtomicBool::new(false) }) + } + + pub(crate) fn configure( + &self, + active: bool, + remote_address: Option<&SocketAddrV4>, + station_address: Option<&SocketAddrV4>, + ) -> io::Result<()> { + let protocol = self.protocol.as_ptr(); + + let (remote_address, remote_port) = if let Some(x) = remote_address { + (helpers::ipv4_to_r_efi(*x.ip()), x.port()) + } else { + (DEFAULT_ADDR, 0) + }; + + // FIXME: Remove when passive connections with proper subnet handling are added + assert!(station_address.is_none()); + let use_default_address = efi::Boolean::TRUE; + let (station_address, station_port) = (DEFAULT_ADDR, 0); + let subnet_mask = helpers::ipv4_to_r_efi(crate::net::Ipv4Addr::new(0, 0, 0, 0)); + + let mut config_data = tcp4::ConfigData { + type_of_service: TYPE_OF_SERVICE, + time_to_live: TIME_TO_LIVE, + access_point: tcp4::AccessPoint { + use_default_address, + remote_address, + remote_port, + active_flag: active.into(), + station_address, + station_port, + subnet_mask, + }, + control_option: crate::ptr::null_mut(), + }; + + let r = unsafe { ((*protocol).configure)(protocol, &mut config_data) }; + if r.is_error() { Err(crate::io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } + } + + pub(crate) fn connect(&self) -> io::Result<()> { + let evt = unsafe { self.create_evt() }?; + let completion_token = + tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS }; + + let protocol = self.protocol.as_ptr(); + let mut conn_token = tcp4::ConnectionToken { completion_token }; + + let r = unsafe { ((*protocol).connect)(protocol, &mut conn_token) }; + if r.is_error() { + return Err(io::Error::from_raw_os_error(r.as_usize())); + } + + self.wait_for_flag(); + + if completion_token.status.is_error() { + Err(io::Error::from_raw_os_error(completion_token.status.as_usize())) + } else { + Ok(()) + } + } + + unsafe fn create_evt(&self) -> io::Result { + self.flag.store(false, Ordering::Relaxed); + helpers::OwnedEvent::new( + efi::EVT_NOTIFY_SIGNAL, + efi::TPL_CALLBACK, + Some(toggle_atomic_flag), + Some(unsafe { NonNull::new_unchecked(self.flag.as_ptr().cast()) }), + ) + } + + fn wait_for_flag(&self) { + while !self.flag.load(Ordering::Relaxed) { + let _ = self.poll(); + } + } + + fn poll(&self) -> io::Result<()> { + let protocol = self.protocol.as_ptr(); + let r = unsafe { ((*protocol).poll)(protocol) }; + + if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } + } +} + +extern "efiapi" fn toggle_atomic_flag(_: r_efi::efi::Event, ctx: *mut crate::ffi::c_void) { + let flag = unsafe { AtomicBool::from_ptr(ctx.cast()) }; + flag.store(true, Ordering::Relaxed); +} diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index 6ee3e0a8b6625..e47263348dbdb 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -653,7 +653,6 @@ pub(crate) struct ServiceProtocol { } impl ServiceProtocol { - #[expect(dead_code)] pub(crate) fn open(service_guid: r_efi::efi::Guid) -> io::Result { let handles = locate_handles(service_guid)?; @@ -670,7 +669,6 @@ impl ServiceProtocol { Err(io::const_error!(io::ErrorKind::NotFound, "no service binding protocol found")) } - #[expect(dead_code)] pub(crate) fn child_handle(&self) -> NonNull { self.child_handle } @@ -732,6 +730,10 @@ impl OwnedEvent { } } + pub(crate) fn as_ptr(&self) -> efi::Event { + self.0.as_ptr() + } + pub(crate) fn into_raw(self) -> *mut crate::ffi::c_void { let r = self.0.as_ptr(); crate::mem::forget(self); @@ -755,3 +757,7 @@ impl Drop for OwnedEvent { } } } + +pub(crate) const fn ipv4_to_r_efi(addr: crate::net::Ipv4Addr) -> efi::Ipv4Address { + efi::Ipv4Address { addr: addr.octets() } +} From 8e91013d69b610f94e84c294cd6f15a0eec4a249 Mon Sep 17 00:00:00 2001 From: yukang Date: Sat, 24 May 2025 02:30:23 +0800 Subject: [PATCH 2679/4206] Add LLVM link in appendix --- src/doc/rustc-dev-guide/src/appendix/compiler-lecture.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/rustc-dev-guide/src/appendix/compiler-lecture.md b/src/doc/rustc-dev-guide/src/appendix/compiler-lecture.md index dabd2f0870355..90c4097cc3e62 100644 --- a/src/doc/rustc-dev-guide/src/appendix/compiler-lecture.md +++ b/src/doc/rustc-dev-guide/src/appendix/compiler-lecture.md @@ -46,3 +46,4 @@ These are videos where various experts explain different parts of the compiler: ## Code Generation - [January 2019: Cranelift](https://www.youtube.com/watch?v=9OIA7DTFQWU) +- [December 2024: LLVM Developers' Meeting - Rust ❤️ LLVM](https://www.youtube.com/watch?v=Kqz-umsAnk8) \ No newline at end of file From 587653a2fcedea2a4e2dbccf86478ce237cabb98 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 22 May 2025 20:07:16 +0200 Subject: [PATCH 2680/4206] GetUserProfileDirectoryW is now documented to always store the size --- library/std/src/sys/pal/windows/os.rs | 2 -- src/tools/miri/src/shims/windows/env.rs | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs index 1ebbbec9e914f..f331282d2d72a 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/pal/windows/os.rs @@ -202,8 +202,6 @@ fn home_dir_crt() -> Option { |buf, mut sz| { // GetUserProfileDirectoryW does not quite use the usual protocol for // negotiating the buffer size, so we have to translate. - // FIXME(#141254): We rely on the *undocumented* property that this function will - // always set the size, not just on failure. match c::GetUserProfileDirectoryW( ptr::without_provenance_mut(CURRENT_PROCESS_TOKEN), buf, diff --git a/src/tools/miri/src/shims/windows/env.rs b/src/tools/miri/src/shims/windows/env.rs index 0cbabc52d2a5d..a7c26d601e502 100644 --- a/src/tools/miri/src/shims/windows/env.rs +++ b/src/tools/miri/src/shims/windows/env.rs @@ -230,7 +230,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(match directories::UserDirs::new() { Some(dirs) => { let home = dirs.home_dir(); - let size_avail = if this.ptr_is_null(size.ptr())? { + let size_avail = if this.ptr_is_null(buf)? { 0 // if the buf pointer is null, we can't write to it; `size` will be updated to the required length } else { this.read_scalar(&size)?.to_u32()? @@ -238,8 +238,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Of course we cannot use `windows_check_buffer_size` here since this uses // a different method for dealing with a too-small buffer than the other functions... let (success, len) = this.write_path_to_wide_str(home, buf, size_avail.into())?; - // The Windows docs just say that this is written on failure, but std relies on it - // always being written. Also see . + // As per , the size is always + // written, not just on failure. this.write_scalar(Scalar::from_u32(len.try_into().unwrap()), &size)?; if success { Scalar::from_i32(1) // return TRUE From 25c759127bc592e36ef17d4aa31649c520801f69 Mon Sep 17 00:00:00 2001 From: ijfjfj <158243190+zzzzzz8403@users.noreply.github.com> Date: Fri, 23 May 2025 09:03:38 -0400 Subject: [PATCH 2681/4206] Improve CONTRIBUTING.md grammar and clarity slight grammar changes for clarity --- CONTRIBUTING.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e155e253784aa..aadc7c48ea839 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,7 +5,7 @@ and we appreciate all of them. The best way to get started is by asking for help in the [#new members](https://rust-lang.zulipchat.com/#narrow/stream/122652-new-members) -Zulip stream. We have lots of docs below of how to get started on your own, but +Zulip stream. We have a lot of documentation below on how to get started on your own, but the Zulip stream is the best place to *ask* for help. Documentation for contributing to the compiler or tooling is located in the [Guide to Rustc @@ -14,7 +14,7 @@ standard library in the [Standard library developers Guide][std-dev-guide], comm ## Making changes to subtrees and submodules -For submodules, changes need to be made against the repository corresponding the +For submodules, changes need to be made against the repository corresponding to the submodule, and not the main `rust-lang/rust` repository. For subtrees, prefer sending a PR against the subtree's repository if it does @@ -25,7 +25,7 @@ rustc-dev-guide change that does not accompany a compiler change). The [rustc-dev-guide] is meant to help document how rustc –the Rust compiler– works, as well as to help new contributors get involved in rustc development. It is recommended -to read and understand the [rustc-dev-guide] before making a contribution. This guide +that you read and understand the [rustc-dev-guide] before making a contribution. This guide talks about the different bots in the Rust ecosystem, the Rust development tools, bootstrapping, the compiler architecture, source code representation, and more. @@ -33,7 +33,7 @@ bootstrapping, the compiler architecture, source code representation, and more. There are many ways you can get help when you're stuck. Rust has many platforms for this: [internals], [rust-zulip], and [rust-discord]. It is recommended to ask for help on -the [rust-zulip], but any of these platforms are a great way to seek help and even +the [rust-zulip], but any of these platforms are great ways to seek help and even find a mentor! You can learn more about asking questions and getting help in the [Asking Questions](https://rustc-dev-guide.rust-lang.org/getting-started.html#asking-questions) chapter of the [rustc-dev-guide]. From a7baf4bce491b50ec30c38895d5c1ec296c23ab5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 23 May 2025 15:35:32 +1000 Subject: [PATCH 2682/4206] Simplify the "is some" test in `TypeAliasPart::get`. The comparison against `text` seems to be unnecessary. --- src/librustdoc/html/render/write_shared.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index b2bbf4614bf45..fdeb4bc1f3ec0 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -653,7 +653,7 @@ impl TypeAliasPart { ) .to_string(); let type_alias_fqp = (*type_alias_fqp).iter().join("::"); - if Some(&text) == ret.last().map(|s: &AliasSerializableImpl| &s.text) { + if ret.last().map(|s: &AliasSerializableImpl| &s.text).is_some() { ret.last_mut() .expect("already established that ret.last() is Some()") .aliases From e01f40738fdf1bc7b89c39db347ee6cb8cff9048 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 23 May 2025 15:44:49 +1000 Subject: [PATCH 2683/4206] Move code inside the `else` in `TypeAliasPart::get`. This is a huge perf win for rustdoc on the `typenum` and `nalgebra` benchmarks, because the `else` branch doesn't get hit much. --- src/librustdoc/html/render/write_shared.rs | 62 ++++++++++++---------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index fdeb4bc1f3ec0..adb220d354785 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -623,35 +623,6 @@ impl TypeAliasPart { for &(type_alias_fqp, type_alias_item) in type_aliases { cx.id_map.borrow_mut().clear(); cx.deref_id_map.borrow_mut().clear(); - let target_did = impl_ - .inner_impl() - .trait_ - .as_ref() - .map(|trait_| trait_.def_id()) - .or_else(|| impl_.inner_impl().for_.def_id(&cx.shared.cache)); - let provided_methods; - let assoc_link = if let Some(target_did) = target_did { - provided_methods = impl_.inner_impl().provided_trait_methods(cx.tcx()); - AssocItemLink::GotoSource(ItemId::DefId(target_did), &provided_methods) - } else { - AssocItemLink::Anchor(None) - }; - let text = super::render_impl( - cx, - impl_, - type_alias_item, - assoc_link, - RenderMode::Normal, - None, - &[], - ImplRenderingParameters { - show_def_docs: true, - show_default_items: true, - show_non_assoc_items: true, - toggle_open_by_default: true, - }, - ) - .to_string(); let type_alias_fqp = (*type_alias_fqp).iter().join("::"); if ret.last().map(|s: &AliasSerializableImpl| &s.text).is_some() { ret.last_mut() @@ -659,6 +630,39 @@ impl TypeAliasPart { .aliases .push(type_alias_fqp); } else { + let target_did = impl_ + .inner_impl() + .trait_ + .as_ref() + .map(|trait_| trait_.def_id()) + .or_else(|| impl_.inner_impl().for_.def_id(&cx.shared.cache)); + let provided_methods; + let assoc_link = if let Some(target_did) = target_did { + provided_methods = + impl_.inner_impl().provided_trait_methods(cx.tcx()); + AssocItemLink::GotoSource( + ItemId::DefId(target_did), + &provided_methods, + ) + } else { + AssocItemLink::Anchor(None) + }; + let text = super::render_impl( + cx, + impl_, + type_alias_item, + assoc_link, + RenderMode::Normal, + None, + &[], + ImplRenderingParameters { + show_def_docs: true, + show_default_items: true, + show_non_assoc_items: true, + toggle_open_by_default: true, + }, + ) + .to_string(); ret.push(AliasSerializableImpl { text, trait_: trait_.clone(), From dfe8fe88f03e1d72b170b7cd056026e0a932c5be Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sat, 24 May 2025 07:48:22 +1000 Subject: [PATCH 2684/4206] Simplify things a little more. --- src/librustdoc/html/render/write_shared.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index adb220d354785..4f6e9abdbca06 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -611,7 +611,7 @@ impl TypeAliasPart { .impl_ .values() .flat_map(|AliasedTypeImpl { impl_, type_aliases }| { - let mut ret = Vec::new(); + let mut ret: Vec = Vec::new(); let trait_ = impl_ .inner_impl() .trait_ @@ -624,11 +624,8 @@ impl TypeAliasPart { cx.id_map.borrow_mut().clear(); cx.deref_id_map.borrow_mut().clear(); let type_alias_fqp = (*type_alias_fqp).iter().join("::"); - if ret.last().map(|s: &AliasSerializableImpl| &s.text).is_some() { - ret.last_mut() - .expect("already established that ret.last() is Some()") - .aliases - .push(type_alias_fqp); + if let Some(last) = ret.last_mut() { + last.aliases.push(type_alias_fqp); } else { let target_did = impl_ .inner_impl() From bcca611b359c74b71e798c2ee30f4695c6218bbf Mon Sep 17 00:00:00 2001 From: binarycat Date: Fri, 23 May 2025 17:43:19 -0500 Subject: [PATCH 2685/4206] rustdoc-gui test: apply suggestions from code review --- tests/rustdoc-gui/sidebar-mobile.goml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/rustdoc-gui/sidebar-mobile.goml b/tests/rustdoc-gui/sidebar-mobile.goml index 0596f84317481..6ddc07c6481c1 100644 --- a/tests/rustdoc-gui/sidebar-mobile.goml +++ b/tests/rustdoc-gui/sidebar-mobile.goml @@ -57,7 +57,8 @@ scroll-to: ".block.keyword li:nth-child(1)" compare-elements-position-near: (".block.keyword li:nth-child(1)", ".mobile-topbar", {"y": 544}) // Now checking the background color of the sidebar. -reload: +// Close the sidebar menu. +press-key: "Escape" show-text: true define-function: ( @@ -73,6 +74,8 @@ define-function: ( "background-color": |background|, "color": |color|, }) + // Make sure the sidebar is full width + compare-elements-size: (".sidebar", "body", ["width"]) // Close the sidebar menu. press-key: "Escape" }, From 9dd67e1104f381aa60baddfcb028303429ebccf9 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 24 May 2025 01:38:43 +0200 Subject: [PATCH 2686/4206] typo --- src/doc/rustc-dev-guide/src/tests/compiletest.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index 0ba078f0b49e7..50982f3bbdfb7 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md @@ -549,7 +549,7 @@ compiler to ICE, panic or crash in some other way, so that accidental fixes are tracked. This was formally done at but doing it inside the rust-lang/rust testsuite is more convenient. -It is imperative that a test in the suite causes rustc to ICE, panic or crash +It is imperative that a test in the suite causes rustc to ICE, panic, or crash in some other way. A test will "pass" if rustc exits with an exit status other than 1 or 0. From 145d2266d930d8d8b4119eb230590269d0626c05 Mon Sep 17 00:00:00 2001 From: dianqk Date: Thu, 22 May 2025 22:55:27 +0800 Subject: [PATCH 2687/4206] mir-opt: Create an indirect BB to add `StorageDead` --- .../src/early_otherwise_branch.rs | 20 ++++++++--- tests/mir-opt/early_otherwise_branch.rs | 31 ++++++++++++++++ ...anch.target_self.EarlyOtherwiseBranch.diff | 35 +++++++++++++++++++ 3 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 tests/mir-opt/early_otherwise_branch.target_self.EarlyOtherwiseBranch.diff diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index c7feb9e949b4d..e7cd74a1f543a 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -193,8 +193,20 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch { let eq_bb = patch.new_block(eq_switch); // Jump to it on the basis of the inequality comparison - let true_case = opt_data.destination; - let false_case = eq_bb; + let mut true_case = opt_data.destination; + let mut false_case = eq_bb; + // Create an indirect BB to add `StorageDead` If the jump target is itself. + for bb in [&mut false_case, &mut true_case].into_iter() { + if *bb == parent { + *bb = patch.new_block(BasicBlockData::new( + Some(Terminator { + kind: TerminatorKind::Goto { target: parent }, + source_info: bbs[parent].terminator().source_info, + }), + bbs[parent].is_cleanup, + )); + } + } patch.patch_terminator( parent, TerminatorKind::if_(Operand::Move(Place::from(comp_temp)), true_case, false_case), @@ -210,9 +222,9 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch { // Generate a StorageDead for comp_temp in each of the targets, since we moved it into // the switch - for bb in [false_case, true_case].iter() { + for bb in [false_case, true_case].into_iter() { patch.add_statement( - Location { block: *bb, statement_index: 0 }, + Location { block: bb, statement_index: 0 }, StatementKind::StorageDead(comp_temp), ); } diff --git a/tests/mir-opt/early_otherwise_branch.rs b/tests/mir-opt/early_otherwise_branch.rs index 382c38ceb3abb..93a11b663df2a 100644 --- a/tests/mir-opt/early_otherwise_branch.rs +++ b/tests/mir-opt/early_otherwise_branch.rs @@ -1,6 +1,10 @@ //@ test-mir-pass: EarlyOtherwiseBranch //@ compile-flags: -Zmir-enable-passes=+UnreachableEnumBranching +#![feature(custom_mir, core_intrinsics)] + +use std::intrinsics::mir::*; + enum Option2 { Some(T), None, @@ -124,6 +128,32 @@ fn opt5_failed_type(x: u32, y: u64) -> u32 { } } +// EMIT_MIR early_otherwise_branch.target_self.EarlyOtherwiseBranch.diff +#[custom_mir(dialect = "runtime")] +fn target_self(val: i32) { + // CHECK-LABEL: fn target_self( + mir! { + { + Goto(bb1) + } + bb1 = { + match val { + 0 => bb2, + _ => bb1, + } + } + bb2 = { + match val { + 0 => bb3, + _ => bb1, + } + } + bb3 = { + Return() + } + } +} + fn main() { opt1(None, Some(0)); opt2(None, Some(0)); @@ -131,4 +161,5 @@ fn main() { opt4(Option2::None, Option2::Some(0)); opt5(0, 0); opt5_failed(0, 0); + target_self(1); } diff --git a/tests/mir-opt/early_otherwise_branch.target_self.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.target_self.EarlyOtherwiseBranch.diff new file mode 100644 index 0000000000000..fbef5df9a531f --- /dev/null +++ b/tests/mir-opt/early_otherwise_branch.target_self.EarlyOtherwiseBranch.diff @@ -0,0 +1,35 @@ +- // MIR for `target_self` before EarlyOtherwiseBranch ++ // MIR for `target_self` after EarlyOtherwiseBranch + + fn target_self(_1: i32) -> () { + let mut _0: (); ++ let mut _2: bool; + + bb0: { + goto -> bb1; + } + + bb1: { +- switchInt(copy _1) -> [0: bb2, otherwise: bb1]; ++ StorageLive(_2); ++ _2 = Ne(copy _1, copy _1); ++ switchInt(move _2) -> [0: bb3, otherwise: bb4]; + } + + bb2: { +- switchInt(copy _1) -> [0: bb3, otherwise: bb1]; ++ return; + } + + bb3: { +- return; ++ StorageDead(_2); ++ switchInt(copy _1) -> [0: bb2, otherwise: bb1]; ++ } ++ ++ bb4: { ++ StorageDead(_2); ++ goto -> bb1; + } + } + From a56af95ed26f7c7bad8dd311dc26697770cd3263 Mon Sep 17 00:00:00 2001 From: jyn Date: Fri, 23 May 2025 23:26:29 -0400 Subject: [PATCH 2688/4206] document some -Z flags --- .../src/compiler-flags/eagerly-emit-delayed-bugs.md | 12 ++++++++++++ .../src/compiler-flags/track-diagnostics.md | 11 +++++++++++ .../src/compiler-flags/treat-err-as-bug.md | 13 +++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 src/doc/unstable-book/src/compiler-flags/eagerly-emit-delayed-bugs.md create mode 100644 src/doc/unstable-book/src/compiler-flags/track-diagnostics.md create mode 100644 src/doc/unstable-book/src/compiler-flags/treat-err-as-bug.md diff --git a/src/doc/unstable-book/src/compiler-flags/eagerly-emit-delayed-bugs.md b/src/doc/unstable-book/src/compiler-flags/eagerly-emit-delayed-bugs.md new file mode 100644 index 0000000000000..39f0c04a1b5ea --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/eagerly-emit-delayed-bugs.md @@ -0,0 +1,12 @@ +# `eagerly-emit-delayed-bugs` + +This feature is perma-unstable and has no tracking issue. + +------------------------ + +This flag converts all [`span_delayed_bug()`] calls to [`bug!`] calls, exiting the compiler immediately and allowing you to generate a backtrace of where the delayed bug occurred. +For full documentation, see [the rustc-dev-guide][dev-guide-delayed]. + +[`bug!`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/macro.bug.html +[`span_delayed_bug()`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.DiagCtxtHandle.html#method.span_delayed_bug +[dev-guide-delayed]: https://rustc-dev-guide.rust-lang.org/compiler-debugging.html#debugging-delayed-bugs diff --git a/src/doc/unstable-book/src/compiler-flags/track-diagnostics.md b/src/doc/unstable-book/src/compiler-flags/track-diagnostics.md new file mode 100644 index 0000000000000..486202144079d --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/track-diagnostics.md @@ -0,0 +1,11 @@ +# `track-diagnostics` + +This feature is perma-unstable and has no tracking issue. + +------------------------ + +This flag prints the source code span in the compiler where a diagnostic was generated, respecting [`#[track_caller]`][track_caller]. Note that this may be different from the place it was emitted. +For full documentation, see [the rustc-dev-guide][dev-guide-track-diagnostics]. + +[track_caller]: https://doc.rust-lang.org/reference/attributes/codegen.html#the-track_caller-attribute +[dev-guide-track-diagnostics]: https://rustc-dev-guide.rust-lang.org/compiler-debugging.html#getting-the-error-creation-location diff --git a/src/doc/unstable-book/src/compiler-flags/treat-err-as-bug.md b/src/doc/unstable-book/src/compiler-flags/treat-err-as-bug.md new file mode 100644 index 0000000000000..df7c380a50b77 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/treat-err-as-bug.md @@ -0,0 +1,13 @@ +# `treat-err-as-bug` + +This feature is perma-unstable and has no tracking issue. + +------------------------ + +This flag converts the selected error to a [`bug!`] call, exiting the compiler immediately and allowing you to generate a backtrace of where the error occurred. +For full documentation, see [the rustc-dev-guide][dev-guide-backtrace]. + +Note that the compiler automatically sets `RUST_BACKTRACE=1` for itself, and so you do not need to set it yourself when using this flag. + +[`bug!`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/macro.bug.html +[dev-guide-backtrace]: https://rustc-dev-guide.rust-lang.org/compiler-debugging.html#getting-a-backtrace-for-errors From 0524773b5d9f2460b706b83c275bb5b5c28e358c Mon Sep 17 00:00:00 2001 From: yanglsh Date: Sat, 24 May 2025 14:31:52 +0800 Subject: [PATCH 2689/4206] fix: `unit_arg` suggests wrongly for `Default::default` --- clippy_lints/src/default.rs | 18 ++---------------- clippy_lints/src/unit_types/unit_arg.rs | 16 +++++++++------- clippy_utils/src/lib.rs | 13 +++++++++++++ ...pty_blocks.fixed => unit_arg_fixable.fixed} | 6 ++++++ ...arg_empty_blocks.rs => unit_arg_fixable.rs} | 6 ++++++ ...y_blocks.stderr => unit_arg_fixable.stderr} | 18 +++++++++++++----- 6 files changed, 49 insertions(+), 28 deletions(-) rename tests/ui/{unit_arg_empty_blocks.fixed => unit_arg_fixable.fixed} (87%) rename tests/ui/{unit_arg_empty_blocks.rs => unit_arg_fixable.rs} (84%) rename tests/ui/{unit_arg_empty_blocks.stderr => unit_arg_fixable.stderr} (69%) diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 886c325b355fe..a48e4d2fbd57e 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -1,10 +1,9 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{has_drop, is_copy}; -use clippy_utils::{contains_name, get_parent_expr, in_automatically_derived, is_from_proc_macro}; +use clippy_utils::{contains_name, get_parent_expr, in_automatically_derived, is_expr_default, is_from_proc_macro}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; -use rustc_hir::def::Res; use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind, StructTailExpr}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; @@ -129,7 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { // only take bindings to identifiers && let PatKind::Binding(_, binding_id, ident, _) = local.pat.kind // only when assigning `... = Default::default()` - && is_expr_default(expr, cx) + && is_expr_default(cx, expr) && let binding_type = cx.typeck_results().node_type(binding_id) && let ty::Adt(adt, args) = *binding_type.kind() && adt.is_struct() @@ -251,19 +250,6 @@ impl<'tcx> LateLintPass<'tcx> for Default { } } -/// Checks if the given expression is the `default` method belonging to the `Default` trait. -fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool { - if let ExprKind::Call(fn_expr, []) = &expr.kind - && let ExprKind::Path(qpath) = &fn_expr.kind - && let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id) - { - // right hand side of assignment is `Default::default` - cx.tcx.is_diagnostic_item(sym::default_fn, def_id) - } else { - false - } -} - /// Returns the reassigned field and the assigning expression (right-hand side of assign). fn field_reassigned_by_stmt<'tcx>(this: &Stmt<'tcx>, binding_name: Symbol) -> Option<(Ident, &'tcx Expr<'tcx>)> { if let StmtKind::Semi(later_expr) = this.kind diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index 019ae16ca8591..e09b362800c0e 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::is_from_proc_macro; use clippy_utils::source::{SourceText, SpanRangeExt, indent_of, reindent_multiline}; +use clippy_utils::{is_expr_default, is_from_proc_macro}; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, MatchSource, Node, StmtKind}; use rustc_lint::LateContext; @@ -59,7 +59,7 @@ fn is_questionmark_desugar_marked_call(expr: &Expr<'_>) -> bool { } } -fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Expr<'_>]) { +fn lint_unit_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, args_to_recover: &[&'tcx Expr<'tcx>]) { let mut applicability = Applicability::MachineApplicable; let (singular, plural) = if args_to_recover.len() > 1 { ("", "s") @@ -102,9 +102,11 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp .iter() .filter_map(|arg| arg.span.get_source_text(cx)) .collect(); - let arg_snippets_without_empty_blocks: Vec<_> = args_to_recover + + // If the argument is an empty block or `Default::default()`, we can replace it with `()`. + let arg_snippets_without_redundant_exprs: Vec<_> = args_to_recover .iter() - .filter(|arg| !is_empty_block(arg)) + .filter(|arg| !is_empty_block(arg) && !is_expr_default(cx, arg)) .filter_map(|arg| arg.span.get_source_text(cx)) .collect(); @@ -114,10 +116,10 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp expr, &call_snippet, &arg_snippets, - &arg_snippets_without_empty_blocks, + &arg_snippets_without_redundant_exprs, ); - if arg_snippets_without_empty_blocks.is_empty() { + if arg_snippets_without_redundant_exprs.is_empty() { db.multipart_suggestion( format!("use {singular}unit literal{plural} instead"), args_to_recover @@ -127,7 +129,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp applicability, ); } else { - let plural = arg_snippets_without_empty_blocks.len() > 1; + let plural = arg_snippets_without_redundant_exprs.len() > 1; let empty_or_s = if plural { "s" } else { "" }; let it_or_them = if plural { "them" } else { "it" }; db.span_suggestion( diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 3a31917657103..f3cd22de5229b 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -3471,3 +3471,16 @@ pub fn desugar_await<'tcx>(expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { None } } + +/// Checks if the given expression is the `default` method belonging to the `Default` trait. +pub fn is_expr_default<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + if let ExprKind::Call(fn_expr, []) = &expr.kind + && let ExprKind::Path(qpath) = &fn_expr.kind + && let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id) + { + // right hand side of assignment is `Default::default` + cx.tcx.is_diagnostic_item(sym::default_fn, def_id) + } else { + false + } +} diff --git a/tests/ui/unit_arg_empty_blocks.fixed b/tests/ui/unit_arg_fixable.fixed similarity index 87% rename from tests/ui/unit_arg_empty_blocks.fixed rename to tests/ui/unit_arg_fixable.fixed index b045a33608d7c..7a25b93e5aee3 100644 --- a/tests/ui/unit_arg_empty_blocks.fixed +++ b/tests/ui/unit_arg_fixable.fixed @@ -32,3 +32,9 @@ fn taking_three_units(a: (), b: (), c: ()) {} fn main() { bad(); } + +fn issue14857() { + let fn_take_unit = |_: ()| {}; + fn_take_unit(()); + //~^ unit_arg +} diff --git a/tests/ui/unit_arg_empty_blocks.rs b/tests/ui/unit_arg_fixable.rs similarity index 84% rename from tests/ui/unit_arg_empty_blocks.rs rename to tests/ui/unit_arg_fixable.rs index ab305913f3f69..65152abbe7b82 100644 --- a/tests/ui/unit_arg_empty_blocks.rs +++ b/tests/ui/unit_arg_fixable.rs @@ -29,3 +29,9 @@ fn taking_three_units(a: (), b: (), c: ()) {} fn main() { bad(); } + +fn issue14857() { + let fn_take_unit = |_: ()| {}; + fn_take_unit(Default::default()); + //~^ unit_arg +} diff --git a/tests/ui/unit_arg_empty_blocks.stderr b/tests/ui/unit_arg_fixable.stderr similarity index 69% rename from tests/ui/unit_arg_empty_blocks.stderr rename to tests/ui/unit_arg_fixable.stderr index 2c686d58ecc1a..79afe67e57247 100644 --- a/tests/ui/unit_arg_empty_blocks.stderr +++ b/tests/ui/unit_arg_fixable.stderr @@ -1,5 +1,5 @@ error: passing a unit value to a function - --> tests/ui/unit_arg_empty_blocks.rs:16:5 + --> tests/ui/unit_arg_fixable.rs:16:5 | LL | foo({}); | ^^^^--^ @@ -10,7 +10,7 @@ LL | foo({}); = help: to override `-D warnings` add `#[allow(clippy::unit_arg)]` error: passing a unit value to a function - --> tests/ui/unit_arg_empty_blocks.rs:18:5 + --> tests/ui/unit_arg_fixable.rs:18:5 | LL | foo3({}, 2, 2); | ^^^^^--^^^^^^^ @@ -18,7 +18,7 @@ LL | foo3({}, 2, 2); | help: use a unit literal instead: `()` error: passing unit values to a function - --> tests/ui/unit_arg_empty_blocks.rs:20:5 + --> tests/ui/unit_arg_fixable.rs:20:5 | LL | taking_two_units({}, foo(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -30,7 +30,7 @@ LL ~ taking_two_units((), ()); | error: passing unit values to a function - --> tests/ui/unit_arg_empty_blocks.rs:22:5 + --> tests/ui/unit_arg_fixable.rs:22:5 | LL | taking_three_units({}, foo(0), foo(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -42,5 +42,13 @@ LL + foo(1); LL ~ taking_three_units((), (), ()); | -error: aborting due to 4 previous errors +error: passing a unit value to a function + --> tests/ui/unit_arg_fixable.rs:35:5 + | +LL | fn_take_unit(Default::default()); + | ^^^^^^^^^^^^^------------------^ + | | + | help: use a unit literal instead: `()` + +error: aborting due to 5 previous errors From 1758f07cb832e9a854f34af437878a10f22dae82 Mon Sep 17 00:00:00 2001 From: quininer Date: Thu, 8 May 2025 17:56:09 +0800 Subject: [PATCH 2690/4206] Enable xray support for Mac * https://maskray.me/blog/2023-06-18-port-llvm-xray-to-apple-systems * https://github.com/llvm/llvm-project/blob/llvmorg-20.1.4/clang/lib/Driver/XRayArgs.cpp#L31 --- compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs | 1 + compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs | 1 + tests/ui/instrument-xray/target-not-supported.rs | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs index d3e0a32c8b8fa..6587abb2ba7e4 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs @@ -22,6 +22,7 @@ pub(crate) fn target() -> Target { max_atomic_width: Some(128), // FIXME: The leak sanitizer currently fails the tests, see #88132. supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD, + supports_xray: true, ..opts }, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs index 2f868e38f1a51..64c1705478054 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs @@ -23,6 +23,7 @@ pub(crate) fn target() -> Target { | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::THREAD, + supports_xray: true, ..opts }, } diff --git a/tests/ui/instrument-xray/target-not-supported.rs b/tests/ui/instrument-xray/target-not-supported.rs index 2045913b186cd..697db6bd4b747 100644 --- a/tests/ui/instrument-xray/target-not-supported.rs +++ b/tests/ui/instrument-xray/target-not-supported.rs @@ -1,7 +1,7 @@ // Verifies that `-Z instrument-xray` cannot be used with unsupported targets, // //@ needs-llvm-components: x86 -//@ compile-flags: -Z instrument-xray --target x86_64-apple-darwin +//@ compile-flags: -Z instrument-xray --target x86_64-pc-windows-msvc #![feature(no_core)] #![no_core] From 8c7faa6ed154893fdbfcb128055b593102b4c6db Mon Sep 17 00:00:00 2001 From: dianqk Date: Sat, 24 May 2025 15:36:06 +0800 Subject: [PATCH 2691/4206] mir-opt: Do not create storage marks for temporary locals --- .../src/early_otherwise_branch.rs | 48 ++----------------- ...wise_branch.opt3.EarlyOtherwiseBranch.diff | 5 -- ...wise_branch.opt4.EarlyOtherwiseBranch.diff | 5 -- ...wise_branch.opt5.EarlyOtherwiseBranch.diff | 3 -- tests/mir-opt/early_otherwise_branch.rs | 2 + ...anch.target_self.EarlyOtherwiseBranch.diff | 9 +--- ...ement_tuple.opt2.EarlyOtherwiseBranch.diff | 5 -- 7 files changed, 8 insertions(+), 69 deletions(-) diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index e7cd74a1f543a..da88e5c698bfe 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -128,28 +128,20 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch { let mut patch = MirPatch::new(body); - let (second_discriminant_temp, second_operand) = if opt_data.need_hoist_discriminant { + let second_operand = if opt_data.need_hoist_discriminant { // create temp to store second discriminant in, `_s` in example above let second_discriminant_temp = patch.new_temp(opt_data.child_ty, opt_data.child_source.span); - patch.add_statement( - parent_end, - StatementKind::StorageLive(second_discriminant_temp), - ); - // create assignment of discriminant patch.add_assign( parent_end, Place::from(second_discriminant_temp), Rvalue::Discriminant(opt_data.child_place), ); - ( - Some(second_discriminant_temp), - Operand::Move(Place::from(second_discriminant_temp)), - ) + Operand::Move(Place::from(second_discriminant_temp)) } else { - (None, Operand::Copy(opt_data.child_place)) + Operand::Copy(opt_data.child_place) }; // create temp to store inequality comparison between the two discriminants, `_t` in @@ -157,7 +149,6 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch { let nequal = BinOp::Ne; let comp_res_type = nequal.ty(tcx, parent_ty, opt_data.child_ty); let comp_temp = patch.new_temp(comp_res_type, opt_data.child_source.span); - patch.add_statement(parent_end, StatementKind::StorageLive(comp_temp)); // create inequality comparison let comp_rvalue = @@ -193,42 +184,13 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch { let eq_bb = patch.new_block(eq_switch); // Jump to it on the basis of the inequality comparison - let mut true_case = opt_data.destination; - let mut false_case = eq_bb; - // Create an indirect BB to add `StorageDead` If the jump target is itself. - for bb in [&mut false_case, &mut true_case].into_iter() { - if *bb == parent { - *bb = patch.new_block(BasicBlockData::new( - Some(Terminator { - kind: TerminatorKind::Goto { target: parent }, - source_info: bbs[parent].terminator().source_info, - }), - bbs[parent].is_cleanup, - )); - } - } + let true_case = opt_data.destination; + let false_case = eq_bb; patch.patch_terminator( parent, TerminatorKind::if_(Operand::Move(Place::from(comp_temp)), true_case, false_case), ); - if let Some(second_discriminant_temp) = second_discriminant_temp { - // generate StorageDead for the second_discriminant_temp not in use anymore - patch.add_statement( - parent_end, - StatementKind::StorageDead(second_discriminant_temp), - ); - } - - // Generate a StorageDead for comp_temp in each of the targets, since we moved it into - // the switch - for bb in [false_case, true_case].into_iter() { - patch.add_statement( - Location { block: bb, statement_index: 0 }, - StatementKind::StorageDead(comp_temp), - ); - } - patch.apply(body); } diff --git a/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff index 7b94a4c2bf737..22ebe2f3f2974 100644 --- a/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff @@ -32,16 +32,12 @@ StorageDead(_4); _9 = discriminant((_3.0: Option2)); - switchInt(move _9) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb9]; -+ StorageLive(_12); + _12 = discriminant((_3.1: Option2)); -+ StorageLive(_13); + _13 = Ne(copy _9, move _12); -+ StorageDead(_12); + switchInt(move _13) -> [0: bb7, otherwise: bb1]; } bb1: { -+ StorageDead(_13); _0 = const 1_u32; - goto -> bb8; + goto -> bb5; @@ -100,7 +96,6 @@ + } + + bb7: { -+ StorageDead(_13); + switchInt(copy _9) -> [0: bb4, 1: bb3, 2: bb2, otherwise: bb6]; } } diff --git a/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff index f52795baef81b..0da0eb3c53cb3 100644 --- a/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff @@ -32,16 +32,12 @@ StorageDead(_4); _9 = discriminant((_3.0: Option2)); - switchInt(move _9) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb9]; -+ StorageLive(_12); + _12 = discriminant((_3.1: Option2)); -+ StorageLive(_13); + _13 = Ne(copy _9, move _12); -+ StorageDead(_12); + switchInt(move _13) -> [0: bb7, otherwise: bb1]; } bb1: { -+ StorageDead(_13); _0 = const 1_u32; - goto -> bb8; + goto -> bb5; @@ -100,7 +96,6 @@ + } + + bb7: { -+ StorageDead(_13); + switchInt(copy _9) -> [0: bb4, 1: bb3, 2: bb2, otherwise: bb6]; } } diff --git a/tests/mir-opt/early_otherwise_branch.opt5.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt5.EarlyOtherwiseBranch.diff index b7447ef0c4699..b13d21e2d7abe 100644 --- a/tests/mir-opt/early_otherwise_branch.opt5.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch.opt5.EarlyOtherwiseBranch.diff @@ -20,13 +20,11 @@ StorageDead(_5); StorageDead(_4); - switchInt(copy (_3.0: u32)) -> [1: bb2, 2: bb3, 3: bb4, otherwise: bb1]; -+ StorageLive(_6); + _6 = Ne(copy (_3.0: u32), copy (_3.1: u32)); + switchInt(move _6) -> [0: bb6, otherwise: bb1]; } bb1: { -+ StorageDead(_6); _0 = const 0_u32; - goto -> bb8; + goto -> bb5; @@ -70,7 +68,6 @@ - bb8: { - StorageDead(_3); - return; -+ StorageDead(_6); + switchInt(copy (_3.0: u32)) -> [1: bb4, 2: bb3, 3: bb2, otherwise: bb1]; } } diff --git a/tests/mir-opt/early_otherwise_branch.rs b/tests/mir-opt/early_otherwise_branch.rs index 93a11b663df2a..19a5d25de2dfb 100644 --- a/tests/mir-opt/early_otherwise_branch.rs +++ b/tests/mir-opt/early_otherwise_branch.rs @@ -132,6 +132,8 @@ fn opt5_failed_type(x: u32, y: u64) -> u32 { #[custom_mir(dialect = "runtime")] fn target_self(val: i32) { // CHECK-LABEL: fn target_self( + // CHECK: Ne( + // CHECK-NEXT: switchInt mir! { { Goto(bb1) diff --git a/tests/mir-opt/early_otherwise_branch.target_self.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.target_self.EarlyOtherwiseBranch.diff index fbef5df9a531f..4f70847bcdf88 100644 --- a/tests/mir-opt/early_otherwise_branch.target_self.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch.target_self.EarlyOtherwiseBranch.diff @@ -11,9 +11,8 @@ bb1: { - switchInt(copy _1) -> [0: bb2, otherwise: bb1]; -+ StorageLive(_2); + _2 = Ne(copy _1, copy _1); -+ switchInt(move _2) -> [0: bb3, otherwise: bb4]; ++ switchInt(move _2) -> [0: bb3, otherwise: bb1]; } bb2: { @@ -23,13 +22,7 @@ bb3: { - return; -+ StorageDead(_2); + switchInt(copy _1) -> [0: bb2, otherwise: bb1]; -+ } -+ -+ bb4: { -+ StorageDead(_2); -+ goto -> bb1; } } diff --git a/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff index 831d8cbb4d60b..e0878167e441b 100644 --- a/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff @@ -42,16 +42,12 @@ StorageDead(_5); _14 = discriminant((_4.0: Option2)); - switchInt(move _14) -> [0: bb2, 1: bb4, 2: bb6, otherwise: bb12]; -+ StorageLive(_18); + _18 = discriminant((_4.1: Option2)); -+ StorageLive(_19); + _19 = Ne(copy _14, move _18); -+ StorageDead(_18); + switchInt(move _19) -> [0: bb10, otherwise: bb1]; } bb1: { -+ StorageDead(_19); _0 = const 1_u32; - goto -> bb11; + goto -> bb8; @@ -134,7 +130,6 @@ + } + + bb10: { -+ StorageDead(_19); + switchInt(copy _14) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb9]; } } From 31ee8400004dd9850fa11cce311e412ceadd7062 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Thu, 8 May 2025 16:07:53 +0800 Subject: [PATCH 2692/4206] Add ui test func-pointer-issue-140491 Signed-off-by: xizheyin --- tests/ui/cast/func-pointer-issue-140491.rs | 7 +++++++ tests/ui/cast/func-pointer-issue-140491.stderr | 9 +++++++++ 2 files changed, 16 insertions(+) create mode 100644 tests/ui/cast/func-pointer-issue-140491.rs create mode 100644 tests/ui/cast/func-pointer-issue-140491.stderr diff --git a/tests/ui/cast/func-pointer-issue-140491.rs b/tests/ui/cast/func-pointer-issue-140491.rs new file mode 100644 index 0000000000000..d5d86a66f5a9c --- /dev/null +++ b/tests/ui/cast/func-pointer-issue-140491.rs @@ -0,0 +1,7 @@ +fn my_fn(event: &Event<'_>) {} + +struct Event<'a>(&'a ()); + +fn main() { + const ptr: &fn(&Event<'_>) = &my_fn as _; //~ ERROR non-primitive cast: `&for<'a, 'b> fn(&'a Event<'b>) {my_fn}` as `&for<'a, 'b> fn(&'a Event<'b>)` [E0605] +} diff --git a/tests/ui/cast/func-pointer-issue-140491.stderr b/tests/ui/cast/func-pointer-issue-140491.stderr new file mode 100644 index 0000000000000..ebd4b18502ec6 --- /dev/null +++ b/tests/ui/cast/func-pointer-issue-140491.stderr @@ -0,0 +1,9 @@ +error[E0605]: non-primitive cast: `&for<'a, 'b> fn(&'a Event<'b>) {my_fn}` as `&for<'a, 'b> fn(&'a Event<'b>)` + --> $DIR/func-pointer-issue-140491.rs:6:34 + | +LL | ..._>) = &my_fn as _; + | ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0605`. From 06e6c902045060a16c0260e59956d33c99cc7a96 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sat, 24 May 2025 17:06:11 +0800 Subject: [PATCH 2693/4206] rustdoc book: add argument explanation for `html_playground_url` Signed-off-by: xizheyin --- .../rustdoc/src/write-documentation/the-doc-attribute.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md index 45146993371f9..6ec93d1746c8f 100644 --- a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md +++ b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md @@ -88,8 +88,10 @@ on your documentation examples make requests to. ``` Now, when you press "run", the button will make a request to this domain. The request -URL will contain 2 query parameters: `code` and `edition` for the code in the documentation -and the Rust edition respectively. +URL will contain 3 query parameters: +1. `code` for the code in the documentation +2. `version` for the Rust channel, e.g. nightly, which is decided by whether `code` contain unstable features +3. `edition` for the Rust edition, e.g. 2024 If you don't use this attribute, there will be no run buttons. From f53473320a464240bb74cd00097909eba63e86d8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 24 May 2025 12:22:48 +0200 Subject: [PATCH 2694/4206] Update `askama` version to `0.14.0` in librustdoc --- Cargo.lock | 52 ++++++++++++++++++++++++--- src/librustdoc/Cargo.toml | 2 +- src/librustdoc/html/render/sidebar.rs | 2 +- 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 57157b32b9782..2f8e698dbe72e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -183,7 +183,20 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d4744ed2eef2645831b441d8f5459689ade2ab27c854488fbab1fbe94fce1a7" dependencies = [ - "askama_derive", + "askama_derive 0.13.1", + "itoa", + "percent-encoding", + "serde", + "serde_json", +] + +[[package]] +name = "askama" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4" +dependencies = [ + "askama_derive 0.14.0", "itoa", "percent-encoding", "serde", @@ -196,7 +209,24 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d661e0f57be36a5c14c48f78d09011e67e0cb618f269cca9f2fd8d15b68c46ac" dependencies = [ - "askama_parser", + "askama_parser 0.13.0", + "basic-toml", + "memchr", + "proc-macro2", + "quote", + "rustc-hash 2.1.1", + "serde", + "serde_derive", + "syn 2.0.101", +] + +[[package]] +name = "askama_derive" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f" +dependencies = [ + "askama_parser 0.14.0", "basic-toml", "memchr", "proc-macro2", @@ -219,6 +249,18 @@ dependencies = [ "winnow 0.7.10", ] +[[package]] +name = "askama_parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358" +dependencies = [ + "memchr", + "serde", + "serde_derive", + "winnow 0.7.10", +] + [[package]] name = "autocfg" version = "1.4.0" @@ -540,7 +582,7 @@ name = "clippy" version = "0.1.89" dependencies = [ "anstream", - "askama", + "askama 0.13.1", "cargo_metadata 0.18.1", "clippy_config", "clippy_lints", @@ -1389,7 +1431,7 @@ name = "generate-copyright" version = "0.1.0" dependencies = [ "anyhow", - "askama", + "askama 0.13.1", "cargo_metadata 0.18.1", "serde", "serde_json", @@ -4622,7 +4664,7 @@ name = "rustdoc" version = "0.0.0" dependencies = [ "arrayvec", - "askama", + "askama 0.14.0", "base64", "expect-test", "indexmap", diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index dbfdd8ebd167c..bba8e630bcc2b 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -9,7 +9,7 @@ path = "lib.rs" [dependencies] arrayvec = { version = "0.7", default-features = false } -askama = { version = "0.13", default-features = false, features = ["alloc", "config", "derive"] } +askama = { version = "0.14", default-features = false, features = ["alloc", "config", "derive"] } base64 = "0.21.7" itertools = "0.12" indexmap = "2" diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index a9029972d9630..361966325fb3c 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -127,7 +127,7 @@ pub(crate) mod filters { use askama::filters::Safe; use crate::html::escape::EscapeBodyTextWithWbr; - pub(crate) fn wrapped(v: T) -> askama::Result> + pub(crate) fn wrapped(v: T, _: V) -> askama::Result> where T: Display, { From 2885e5578e7b9ab6247015f0929ecc5b218c7588 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 24 May 2025 12:28:50 +0200 Subject: [PATCH 2695/4206] Update `askama` version to `0.14.0` in `generate-copyright` tool --- Cargo.lock | 2 +- src/tools/generate-copyright/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2f8e698dbe72e..76073224916f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1431,7 +1431,7 @@ name = "generate-copyright" version = "0.1.0" dependencies = [ "anyhow", - "askama 0.13.1", + "askama 0.14.0", "cargo_metadata 0.18.1", "serde", "serde_json", diff --git a/src/tools/generate-copyright/Cargo.toml b/src/tools/generate-copyright/Cargo.toml index ab76d0fc01e78..e420a450d422b 100644 --- a/src/tools/generate-copyright/Cargo.toml +++ b/src/tools/generate-copyright/Cargo.toml @@ -8,7 +8,7 @@ description = "Produces a manifest of all the copyrighted materials in the Rust [dependencies] anyhow = "1.0.65" -askama = "0.13.0" +askama = "0.14.0" cargo_metadata = "0.18.1" serde = { version = "1.0.147", features = ["derive"] } serde_json = "1.0.85" From a6438924c9bf059b4a15785ad60ea0710f5c9b4c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 24 May 2025 12:31:21 +0200 Subject: [PATCH 2696/4206] Update `askama` version to `0.14.0` in `citool` --- src/ci/citool/Cargo.lock | 12 ++++++------ src/ci/citool/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ci/citool/Cargo.lock b/src/ci/citool/Cargo.lock index 43321d12cafcd..571f18e7cf188 100644 --- a/src/ci/citool/Cargo.lock +++ b/src/ci/citool/Cargo.lock @@ -66,9 +66,9 @@ checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" [[package]] name = "askama" -version = "0.13.1" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4744ed2eef2645831b441d8f5459689ade2ab27c854488fbab1fbe94fce1a7" +checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4" dependencies = [ "askama_derive", "itoa", @@ -79,9 +79,9 @@ dependencies = [ [[package]] name = "askama_derive" -version = "0.13.1" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d661e0f57be36a5c14c48f78d09011e67e0cb618f269cca9f2fd8d15b68c46ac" +checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f" dependencies = [ "askama_parser", "basic-toml", @@ -96,9 +96,9 @@ dependencies = [ [[package]] name = "askama_parser" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf315ce6524c857bb129ff794935cf6d42c82a6cff60526fe2a63593de4d0d4f" +checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358" dependencies = [ "memchr", "serde", diff --git a/src/ci/citool/Cargo.toml b/src/ci/citool/Cargo.toml index 0e2aba3b9e3fc..f61243a4d712b 100644 --- a/src/ci/citool/Cargo.toml +++ b/src/ci/citool/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] anyhow = "1" -askama = "0.13" +askama = "0.14" clap = { version = "4.5", features = ["derive"] } csv = "1" diff = "0.1" From f63a9b2b9771583fad44e7ad982df430b7fc779b Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 24 May 2025 14:11:29 +0200 Subject: [PATCH 2697/4206] Enable `[issue-links]` and `[no-mentions]` in triagebot --- triagebot.toml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index fd7a861bc92dc..446e391bdaa72 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1425,3 +1425,12 @@ compiletest = [ [behind-upstream] days-threshold = 14 + +# Canonicalize issue numbers to avoid closing the wrong issue +# when commits are included in subtrees, as well as warning links in commits. +# Documentation at: https://forge.rust-lang.org/triagebot/issue-links.html +[issue-links] + +# Prevents mentions in commits to avoid users being spammed +# Documentation at: https://forge.rust-lang.org/triagebot/no-mentions.html +[no-mentions] From 947be5f4316088f44cf2db69d137fd9afbfd7723 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 17 Apr 2025 19:43:56 -0400 Subject: [PATCH 2698/4206] add CStr::display The implementation delegates to `::fmt`. Link: https://github.com/rust-lang/libs-team/issues/550 Link: https://github.com/rust-lang/rust/issues/139984. --- library/core/src/ffi/c_str.rs | 24 ++++++++++++++++++++++++ library/coretests/tests/ffi/cstr.rs | 6 ++++++ library/coretests/tests/lib.rs | 1 + 3 files changed, 31 insertions(+) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index ac07c645c0195..c2799fa0b5c14 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -659,6 +659,30 @@ impl CStr { // instead of doing it afterwards. str::from_utf8(self.to_bytes()) } + + /// Returns an object that implements [`Display`] for safely printing a [`CStr`] that may + /// contain non-Unicode data. + /// + /// Behaves as if `self` were first lossily converted to a `str`, with invalid UTF-8 presented + /// as the Unicode replacement character: �. + /// + /// [`Display`]: fmt::Display + /// + /// # Examples + /// + /// ``` + /// #![feature(cstr_display)] + /// + /// let cstr = c"Hello, world!"; + /// println!("{}", cstr.display()); + /// ``` + #[unstable(feature = "cstr_display", issue = "139984")] + #[must_use = "this does not display the `CStr`; \ + it returns an object that can be displayed"] + #[inline] + pub fn display(&self) -> impl fmt::Display { + crate::bstr::ByteStr::from_bytes(self.to_bytes()) + } } // `.to_bytes()` representations are compared instead of the inner `[c_char]`s, diff --git a/library/coretests/tests/ffi/cstr.rs b/library/coretests/tests/ffi/cstr.rs index 0d85b22c585a1..dc34240cd99d2 100644 --- a/library/coretests/tests/ffi/cstr.rs +++ b/library/coretests/tests/ffi/cstr.rs @@ -19,3 +19,9 @@ fn debug() { let s = c"abc\x01\x02\n\xE2\x80\xA6\xFF"; assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#); } + +#[test] +fn display() { + let s = c"\xf0\x28\x8c\xbc"; + assert_eq!(format!("{}", s.display()), "�(��"); +} diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index b13012009815c..693b14ef76209 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -23,6 +23,7 @@ #![feature(core_io_borrowed_buf)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] +#![feature(cstr_display)] #![feature(dec2flt)] #![feature(duration_constants)] #![feature(duration_constructors)] From 7b5a079368ae31f8bf59e84dcae976c6b3484b01 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Sat, 24 May 2025 08:34:16 -0400 Subject: [PATCH 2699/4206] Use C-string literals to reduce boilerplate Reduce boilerplate in doctests by replacing fallible function calls with literals. --- library/core/src/ffi/c_str.rs | 41 ++++++----------------------------- 1 file changed, 7 insertions(+), 34 deletions(-) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index ac07c645c0195..825402116e5b7 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -511,13 +511,8 @@ impl CStr { /// # Examples /// /// ``` - /// use std::ffi::CStr; - /// - /// let cstr = CStr::from_bytes_with_nul(b"foo\0").unwrap(); - /// assert_eq!(cstr.count_bytes(), 3); - /// - /// let cstr = CStr::from_bytes_with_nul(b"\0").unwrap(); - /// assert_eq!(cstr.count_bytes(), 0); + /// assert_eq!(c"foo".count_bytes(), 3); + /// assert_eq!(c"".count_bytes(), 0); /// ``` #[inline] #[must_use] @@ -533,19 +528,8 @@ impl CStr { /// # Examples /// /// ``` - /// use std::ffi::CStr; - /// # use std::ffi::FromBytesWithNulError; - /// - /// # fn main() { test().unwrap(); } - /// # fn test() -> Result<(), FromBytesWithNulError> { - /// let cstr = CStr::from_bytes_with_nul(b"foo\0")?; - /// assert!(!cstr.is_empty()); - /// - /// let empty_cstr = CStr::from_bytes_with_nul(b"\0")?; - /// assert!(empty_cstr.is_empty()); + /// assert!(!c"foo".is_empty()); /// assert!(c"".is_empty()); - /// # Ok(()) - /// # } /// ``` #[inline] #[stable(feature = "cstr_is_empty", since = "1.71.0")] @@ -569,10 +553,7 @@ impl CStr { /// # Examples /// /// ``` - /// use std::ffi::CStr; - /// - /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); - /// assert_eq!(cstr.to_bytes(), b"foo"); + /// assert_eq!(c"foo".to_bytes(), b"foo"); /// ``` #[inline] #[must_use = "this returns the result of the operation, \ @@ -598,10 +579,7 @@ impl CStr { /// # Examples /// /// ``` - /// use std::ffi::CStr; - /// - /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); - /// assert_eq!(cstr.to_bytes_with_nul(), b"foo\0"); + /// assert_eq!(c"foo".to_bytes_with_nul(), b"foo\0"); /// ``` #[inline] #[must_use = "this returns the result of the operation, \ @@ -623,10 +601,8 @@ impl CStr { /// /// ``` /// #![feature(cstr_bytes)] - /// use std::ffi::CStr; /// - /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); - /// assert!(cstr.bytes().eq(*b"foo")); + /// assert!(c"foo".bytes().eq(*b"foo")); /// ``` #[inline] #[unstable(feature = "cstr_bytes", issue = "112115")] @@ -645,10 +621,7 @@ impl CStr { /// # Examples /// /// ``` - /// use std::ffi::CStr; - /// - /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); - /// assert_eq!(cstr.to_str(), Ok("foo")); + /// assert_eq!(c"foo".to_str(), Ok("foo")); /// ``` #[stable(feature = "cstr_to_str", since = "1.4.0")] #[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")] From f0fb19ccc87e18402079fbe3106d8090cc8d9f64 Mon Sep 17 00:00:00 2001 From: beetrees Date: Sat, 24 May 2025 13:45:12 +0100 Subject: [PATCH 2700/4206] Add missing float libcalls to `compiler_builtins.rs` --- src/compiler_builtins.rs | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/compiler_builtins.rs b/src/compiler_builtins.rs index 5b6d0ef6ddf79..8886317c12b18 100644 --- a/src/compiler_builtins.rs +++ b/src/compiler_builtins.rs @@ -46,15 +46,49 @@ builtin_functions! { fn __rust_u128_mulo(a: u128, b: u128, oflow: &mut i32) -> u128; fn __rust_i128_mulo(a: i128, b: i128, oflow: &mut i32) -> i128; - // floats + // integer -> float fn __floattisf(i: i128) -> f32; fn __floattidf(i: i128) -> f64; fn __floatuntisf(i: u128) -> f32; fn __floatuntidf(i: u128) -> f64; + // float -> integer fn __fixsfti(f: f32) -> i128; fn __fixdfti(f: f64) -> i128; fn __fixunssfti(f: f32) -> u128; fn __fixunsdfti(f: f64) -> u128; + // float binops + fn fmodf(a: f32, b: f32) -> f32; + fn fmod(a: f64, b: f64) -> f64; + // Cranelift float libcalls + fn fmaf(a: f32, b: f32, c: f32) -> f32; + fn fma(a: f64, b: f64, c: f64) -> f64; + fn floorf(f: f32) -> f32; + fn floor(f: f64) -> f64; + fn ceilf(f: f32) -> f32; + fn ceil(f: f64) -> f64; + fn truncf(f: f32) -> f32; + fn trunc(f: f64) -> f64; + fn nearbyintf(f: f32) -> f32; + fn nearbyint(f: f64) -> f64; + // float intrinsics + fn __powisf2(a: f32, b: i32) -> f32; + fn __powidf2(a: f64, b: i32) -> f64; + fn powf(a: f32, b: f32) -> f32; + fn pow(a: f64, b: f64) -> f64; + fn expf(f: f32) -> f32; + fn exp(f: f64) -> f64; + fn exp2f(f: f32) -> f32; + fn exp2(f: f64) -> f64; + fn logf(f: f32) -> f32; + fn log(f: f64) -> f64; + fn log2f(f: f32) -> f32; + fn log2(f: f64) -> f64; + fn log10f(f: f32) -> f32; + fn log10(f: f64) -> f64; + fn sinf(f: f32) -> f32; + fn sin(f: f64) -> f64; + fn cosf(f: f32) -> f32; + fn cos(f: f64) -> f64; // allocator // NOTE: These need to be mentioned here despite not being part of compiler_builtins because From 87c425b9e1ce015c4e3dad7729e8d54bc7b6b27b Mon Sep 17 00:00:00 2001 From: beetrees Date: Fri, 23 May 2025 15:51:51 +0100 Subject: [PATCH 2701/4206] Add basic support for `f16`/`f128` values --- src/abi/pass_mode.rs | 2 ++ src/common.rs | 8 ++++---- src/value_and_place.rs | 14 +++++++++++++- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/abi/pass_mode.rs b/src/abi/pass_mode.rs index 06d89bc9ea7d7..6d8614aca6932 100644 --- a/src/abi/pass_mode.rs +++ b/src/abi/pass_mode.rs @@ -22,8 +22,10 @@ fn reg_to_abi_param(reg: Reg) -> AbiParam { (RegKind::Integer, 3..=4) => types::I32, (RegKind::Integer, 5..=8) => types::I64, (RegKind::Integer, 9..=16) => types::I128, + (RegKind::Float, 2) => types::F16, (RegKind::Float, 4) => types::F32, (RegKind::Float, 8) => types::F64, + (RegKind::Float, 16) => types::F128, (RegKind::Vector, size) => types::I8.by(u32::try_from(size).unwrap()).unwrap(), _ => unreachable!("{:?}", reg), }; diff --git a/src/common.rs b/src/common.rs index abe2972ba0cbd..2f11b2d2dcc1a 100644 --- a/src/common.rs +++ b/src/common.rs @@ -33,10 +33,10 @@ pub(crate) fn scalar_to_clif_type(tcx: TyCtxt<'_>, scalar: Scalar) -> Type { Integer::I128 => types::I128, }, Primitive::Float(float) => match float { - Float::F16 => unimplemented!("f16_f128"), + Float::F16 => types::F16, Float::F32 => types::F32, Float::F64 => types::F64, - Float::F128 => unimplemented!("f16_f128"), + Float::F128 => types::F128, }, // FIXME(erikdesjardins): handle non-default addrspace ptr sizes Primitive::Pointer(_) => pointer_ty(tcx), @@ -64,10 +64,10 @@ fn clif_type_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option types::I32, ty::Float(size) => match size { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => types::F16, FloatTy::F32 => types::F32, FloatTy::F64 => types::F64, - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => types::F128, }, ty::FnPtr(..) => pointer_ty(tcx), ty::RawPtr(pointee_ty, _) | ty::Ref(_, pointee_ty, _) => { diff --git a/src/value_and_place.rs b/src/value_and_place.rs index 0938c990514c2..cbfb215a892a4 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -325,7 +325,7 @@ impl<'tcx> CValue<'tcx> { const_val: ty::ScalarInt, ) -> CValue<'tcx> { assert_eq!(const_val.size(), layout.size, "{:#?}: {:?}", const_val, layout); - use cranelift_codegen::ir::immediates::{Ieee32, Ieee64}; + use cranelift_codegen::ir::immediates::{Ieee16, Ieee32, Ieee64, Ieee128}; let clif_ty = fx.clif_type(layout.ty).unwrap(); @@ -346,12 +346,24 @@ impl<'tcx> CValue<'tcx> { let raw_val = const_val.size().truncate(const_val.to_bits(layout.size)); fx.bcx.ins().iconst(clif_ty, raw_val as i64) } + ty::Float(FloatTy::F16) => { + fx.bcx.ins().f16const(Ieee16::with_bits(u16::try_from(const_val).unwrap())) + } ty::Float(FloatTy::F32) => { fx.bcx.ins().f32const(Ieee32::with_bits(u32::try_from(const_val).unwrap())) } ty::Float(FloatTy::F64) => { fx.bcx.ins().f64const(Ieee64::with_bits(u64::try_from(const_val).unwrap())) } + ty::Float(FloatTy::F128) => { + let value = fx + .bcx + .func + .dfg + .constants + .insert(Ieee128::with_bits(u128::try_from(const_val).unwrap()).into()); + fx.bcx.ins().f128const(value) + } _ => panic!( "CValue::const_val for non bool/char/float/integer/pointer type {:?} is not allowed", layout.ty From 27a9590d3db284a12143dafd03bf7343b59b6808 Mon Sep 17 00:00:00 2001 From: beetrees Date: Fri, 23 May 2025 15:51:51 +0100 Subject: [PATCH 2702/4206] Add `f16`/`f128` `+`/`-`/`*`/`/`/`%` support --- build_system/build_backend.rs | 2 +- src/base.rs | 11 +++++- src/codegen_f16_f128.rs | 64 +++++++++++++++++++++++++++++++++++ src/compiler_builtins.rs | 8 +++++ src/lib.rs | 4 +++ src/num.rs | 53 ++++++++++++++++++++++++++--- 6 files changed, 135 insertions(+), 7 deletions(-) create mode 100644 src/codegen_f16_f128.rs diff --git a/build_system/build_backend.rs b/build_system/build_backend.rs index 72bc422523d55..bf7cf1c0a346f 100644 --- a/build_system/build_backend.rs +++ b/build_system/build_backend.rs @@ -18,7 +18,7 @@ pub(crate) fn build_backend( let mut cmd = CG_CLIF.build(&bootstrap_host_compiler, dirs); let mut rustflags = rustflags_from_env("RUSTFLAGS"); - rustflags.push("-Zallow-features=rustc_private".to_owned()); + rustflags.push("-Zallow-features=rustc_private,f16,f128".to_owned()); rustflags_to_cmd_env(&mut cmd, "RUSTFLAGS", &rustflags); if env::var("CG_CLIF_EXPENSIVE_CHECKS").is_ok() { diff --git a/src/base.rs b/src/base.rs index c1f4c065ce03f..4617304105a5b 100644 --- a/src/base.rs +++ b/src/base.rs @@ -15,9 +15,9 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use crate::constant::ConstantCx; use crate::debuginfo::{FunctionDebugContext, TypeDebugContext}; -use crate::enable_verifier; use crate::prelude::*; use crate::pretty_clif::CommentWriter; +use crate::{codegen_f16_f128, enable_verifier}; pub(crate) struct CodegenedFunction { symbol_name: String, @@ -635,6 +635,15 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: let val = operand.load_scalar(fx); match layout.ty.kind() { ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout), + // FIXME(bytecodealliance/wasmtime#8312): Remove + // once backend lowerings have been added to + // Cranelift. + ty::Float(FloatTy::F16) => { + CValue::by_val(codegen_f16_f128::neg_f16(fx, val), layout) + } + ty::Float(FloatTy::F128) => { + CValue::by_val(codegen_f16_f128::neg_f128(fx, val), layout) + } ty::Float(_) => CValue::by_val(fx.bcx.ins().fneg(val), layout), _ => unreachable!("un op Neg for {:?}", layout.ty), } diff --git a/src/codegen_f16_f128.rs b/src/codegen_f16_f128.rs new file mode 100644 index 0000000000000..c6f0779b82db1 --- /dev/null +++ b/src/codegen_f16_f128.rs @@ -0,0 +1,64 @@ +use crate::prelude::*; + +pub(crate) fn f16_to_f32(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { + let (value, arg_ty) = + if fx.tcx.sess.target.vendor == "apple" && fx.tcx.sess.target.arch == "x86_64" { + ( + fx.bcx.ins().bitcast(types::I16, MemFlags::new(), value), + lib_call_arg_param(fx.tcx, types::I16, false), + ) + } else { + (value, AbiParam::new(types::F16)) + }; + fx.lib_call("__extendhfsf2", vec![arg_ty], vec![AbiParam::new(types::F32)], &[value])[0] +} + +pub(crate) fn f32_to_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { + let ret_ty = if fx.tcx.sess.target.vendor == "apple" && fx.tcx.sess.target.arch == "x86_64" { + types::I16 + } else { + types::F16 + }; + let ret = fx.lib_call( + "__truncsfhf2", + vec![AbiParam::new(types::F32)], + vec![AbiParam::new(ret_ty)], + &[value], + )[0]; + if ret_ty == types::I16 { fx.bcx.ins().bitcast(types::F16, MemFlags::new(), ret) } else { ret } +} + +pub(crate) fn codegen_f128_binop( + fx: &mut FunctionCx<'_, '_, '_>, + bin_op: BinOp, + lhs: Value, + rhs: Value, +) -> Value { + let name = match bin_op { + BinOp::Add => "__addtf3", + BinOp::Sub => "__subtf3", + BinOp::Mul => "__multf3", + BinOp::Div => "__divtf3", + _ => unreachable!("handled in `codegen_float_binop`"), + }; + fx.lib_call( + name, + vec![AbiParam::new(types::F128), AbiParam::new(types::F128)], + vec![AbiParam::new(types::F128)], + &[lhs, rhs], + )[0] +} + +pub(crate) fn neg_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { + let bits = fx.bcx.ins().bitcast(types::I16, MemFlags::new(), value); + let bits = fx.bcx.ins().bxor_imm(bits, 0x8000); + fx.bcx.ins().bitcast(types::F16, MemFlags::new(), bits) +} + +pub(crate) fn neg_f128(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { + let bits = fx.bcx.ins().bitcast(types::I128, MemFlags::new(), value); + let (low, high) = fx.bcx.ins().isplit(bits); + let high = fx.bcx.ins().bxor_imm(high, 0x8000_0000_0000_0000_u64 as i64); + let bits = fx.bcx.ins().iconcat(low, high); + fx.bcx.ins().bitcast(types::F128, MemFlags::new(), bits) +} diff --git a/src/compiler_builtins.rs b/src/compiler_builtins.rs index 8886317c12b18..0c75df845db0f 100644 --- a/src/compiler_builtins.rs +++ b/src/compiler_builtins.rs @@ -56,9 +56,17 @@ builtin_functions! { fn __fixdfti(f: f64) -> i128; fn __fixunssfti(f: f32) -> u128; fn __fixunsdfti(f: f64) -> u128; + // float -> float + fn __extendhfsf2(f: f16) -> f32; + fn __truncsfhf2(f: f32) -> f16; // float binops + fn __addtf3(a: f128, b: f128) -> f128; + fn __subtf3(a: f128, b: f128) -> f128; + fn __multf3(a: f128, b: f128) -> f128; + fn __divtf3(a: f128, b: f128) -> f128; fn fmodf(a: f32, b: f32) -> f32; fn fmod(a: f64, b: f64) -> f64; + fn fmodf128(a: f128, b: f128) -> f128; // Cranelift float libcalls fn fmaf(a: f32, b: f32, c: f32) -> f32; fn fma(a: f64, b: f64, c: f64) -> f64; diff --git a/src/lib.rs b/src/lib.rs index d41a808198cd2..03dfd495682cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,9 @@ #![cfg_attr(doc, feature(rustdoc_internals))] // Note: please avoid adding other feature gates where possible #![feature(rustc_private)] +// Only used to define intrinsics in `compiler_builtins.rs`. +#![feature(f16)] +#![feature(f128)] // Note: please avoid adding other feature gates where possible #![warn(rust_2018_idioms)] #![warn(unreachable_pub)] @@ -57,6 +60,7 @@ mod allocator; mod analyze; mod base; mod cast; +mod codegen_f16_f128; mod codegen_i128; mod common; mod compiler_builtins; diff --git a/src/num.rs b/src/num.rs index 90627f8060b8b..3ed276267de64 100644 --- a/src/num.rs +++ b/src/num.rs @@ -1,5 +1,6 @@ //! Various operations on integer and floating-point numbers +use crate::codegen_f16_f128; use crate::prelude::*; fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> IntCC { @@ -350,25 +351,60 @@ pub(crate) fn codegen_float_binop<'tcx>( let lhs = in_lhs.load_scalar(fx); let rhs = in_rhs.load_scalar(fx); + // FIXME(bytecodealliance/wasmtime#8312): Remove once backend lowerings have + // been added to Cranelift. + let (lhs, rhs) = if *in_lhs.layout().ty.kind() == ty::Float(FloatTy::F16) { + (codegen_f16_f128::f16_to_f32(fx, lhs), codegen_f16_f128::f16_to_f32(fx, rhs)) + } else { + (lhs, rhs) + }; let b = fx.bcx.ins(); let res = match bin_op { + // FIXME(bytecodealliance/wasmtime#8312): Remove once backend lowerings + // have been added to Cranelift. + BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div + if *in_lhs.layout().ty.kind() == ty::Float(FloatTy::F128) => + { + codegen_f16_f128::codegen_f128_binop(fx, bin_op, lhs, rhs) + } BinOp::Add => b.fadd(lhs, rhs), BinOp::Sub => b.fsub(lhs, rhs), BinOp::Mul => b.fmul(lhs, rhs), BinOp::Div => b.fdiv(lhs, rhs), BinOp::Rem => { - let (name, ty) = match in_lhs.layout().ty.kind() { - ty::Float(FloatTy::F32) => ("fmodf", types::F32), - ty::Float(FloatTy::F64) => ("fmod", types::F64), + let (name, ty, lhs, rhs) = match in_lhs.layout().ty.kind() { + ty::Float(FloatTy::F16) => ( + "fmodf", + types::F32, + // FIXME(bytecodealliance/wasmtime#8312): Already converted + // by the FIXME above. + // fx.bcx.ins().fpromote(types::F32, lhs), + // fx.bcx.ins().fpromote(types::F32, rhs), + lhs, + rhs, + ), + ty::Float(FloatTy::F32) => ("fmodf", types::F32, lhs, rhs), + ty::Float(FloatTy::F64) => ("fmod", types::F64, lhs, rhs), + ty::Float(FloatTy::F128) => ("fmodf128", types::F128, lhs, rhs), _ => bug!(), }; - fx.lib_call( + let ret_val = fx.lib_call( name, vec![AbiParam::new(ty), AbiParam::new(ty)], vec![AbiParam::new(ty)], &[lhs, rhs], - )[0] + )[0]; + + let ret_val = if *in_lhs.layout().ty.kind() == ty::Float(FloatTy::F16) { + // FIXME(bytecodealliance/wasmtime#8312): Use native Cranelift + // operation once Cranelift backend lowerings have been + // implemented. + codegen_f16_f128::f32_to_f16(fx, ret_val) + } else { + ret_val + }; + return CValue::by_val(ret_val, in_lhs.layout()); } BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => { let fltcc = match bin_op { @@ -386,6 +422,13 @@ pub(crate) fn codegen_float_binop<'tcx>( _ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs), }; + // FIXME(bytecodealliance/wasmtime#8312): Remove once backend lowerings have + // been added to Cranelift. + let res = if *in_lhs.layout().ty.kind() == ty::Float(FloatTy::F16) { + codegen_f16_f128::f32_to_f16(fx, res) + } else { + res + }; CValue::by_val(res, in_lhs.layout()) } From 38d48dbe083b680b54e39c2ead2a92d76001786c Mon Sep 17 00:00:00 2001 From: beetrees Date: Fri, 23 May 2025 15:51:51 +0100 Subject: [PATCH 2703/4206] Add `f16`/`f128` comparison support --- src/codegen_f16_f128.rs | 54 +++++++++++++++++++++++++ src/compiler_builtins.rs | 9 +++++ src/intrinsics/mod.rs | 87 ++++++++++++++++++++++++++++++++++++++++ src/num.rs | 17 +++++--- 4 files changed, 162 insertions(+), 5 deletions(-) diff --git a/src/codegen_f16_f128.rs b/src/codegen_f16_f128.rs index c6f0779b82db1..c570fbbd993d9 100644 --- a/src/codegen_f16_f128.rs +++ b/src/codegen_f16_f128.rs @@ -28,6 +28,42 @@ pub(crate) fn f32_to_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value if ret_ty == types::I16 { fx.bcx.ins().bitcast(types::F16, MemFlags::new(), ret) } else { ret } } +pub(crate) fn fcmp(fx: &mut FunctionCx<'_, '_, '_>, cc: FloatCC, lhs: Value, rhs: Value) -> Value { + let ty = fx.bcx.func.dfg.value_type(lhs); + match ty { + types::F32 | types::F64 => fx.bcx.ins().fcmp(cc, lhs, rhs), + types::F16 => { + let lhs = f16_to_f32(fx, lhs); + let rhs = f16_to_f32(fx, rhs); + fx.bcx.ins().fcmp(cc, lhs, rhs) + } + types::F128 => { + let (name, int_cc) = match cc { + FloatCC::Equal => ("__eqtf2", IntCC::Equal), + FloatCC::NotEqual => ("__netf2", IntCC::NotEqual), + FloatCC::LessThan => ("__lttf2", IntCC::SignedLessThan), + FloatCC::LessThanOrEqual => ("__letf2", IntCC::SignedLessThanOrEqual), + FloatCC::GreaterThan => ("__gttf2", IntCC::SignedGreaterThan), + FloatCC::GreaterThanOrEqual => ("__getf2", IntCC::SignedGreaterThanOrEqual), + _ => unreachable!("not currently used in rustc_codegen_cranelift: {cc:?}"), + }; + let res = fx.lib_call( + name, + vec![AbiParam::new(types::F128), AbiParam::new(types::F128)], + // FIXME(rust-lang/compiler-builtins#919): This should be `I64` on non-AArch64 + // architectures, but switching it before compiler-builtins is fixed causes test + // failures. + vec![AbiParam::new(types::I32)], + &[lhs, rhs], + )[0]; + let zero = fx.bcx.ins().iconst(types::I32, 0); + let res = fx.bcx.ins().icmp(int_cc, res, zero); + res + } + _ => unreachable!("{ty:?}"), + } +} + pub(crate) fn codegen_f128_binop( fx: &mut FunctionCx<'_, '_, '_>, bin_op: BinOp, @@ -62,3 +98,21 @@ pub(crate) fn neg_f128(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { let bits = fx.bcx.ins().iconcat(low, high); fx.bcx.ins().bitcast(types::F128, MemFlags::new(), bits) } + +pub(crate) fn fmin_f128(fx: &mut FunctionCx<'_, '_, '_>, a: Value, b: Value) -> Value { + fx.lib_call( + "fminimumf128", + vec![AbiParam::new(types::F128), AbiParam::new(types::F128)], + vec![AbiParam::new(types::F128)], + &[a, b], + )[0] +} + +pub(crate) fn fmax_f128(fx: &mut FunctionCx<'_, '_, '_>, a: Value, b: Value) -> Value { + fx.lib_call( + "fmaximumf128", + vec![AbiParam::new(types::F128), AbiParam::new(types::F128)], + vec![AbiParam::new(types::F128)], + &[a, b], + )[0] +} diff --git a/src/compiler_builtins.rs b/src/compiler_builtins.rs index 0c75df845db0f..017a1370abd75 100644 --- a/src/compiler_builtins.rs +++ b/src/compiler_builtins.rs @@ -67,6 +67,15 @@ builtin_functions! { fn fmodf(a: f32, b: f32) -> f32; fn fmod(a: f64, b: f64) -> f64; fn fmodf128(a: f128, b: f128) -> f128; + // float comparison + fn __eqtf2(a: f128, b: f128) -> i32; + fn __netf2(a: f128, b: f128) -> i32; + fn __lttf2(a: f128, b: f128) -> i32; + fn __letf2(a: f128, b: f128) -> i32; + fn __gttf2(a: f128, b: f128) -> i32; + fn __getf2(a: f128, b: f128) -> i32; + fn fminimumf128(a: f128, b: f128) -> f128; + fn fmaximumf128(a: f128, b: f128) -> f128; // Cranelift float libcalls fn fmaf(a: f32, b: f32, c: f32) -> f32; fn fma(a: f64, b: f64, c: f64) -> f64; diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index 7c18922d93cd3..6481d211234e2 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -27,6 +27,7 @@ use rustc_span::{Symbol, sym}; pub(crate) use self::llvm::codegen_llvm_intrinsic_call; use crate::cast::clif_intcast; +use crate::codegen_f16_f128; use crate::prelude::*; fn bug_on_incorrect_arg_count(intrinsic: impl std::fmt::Display) -> ! { @@ -1118,6 +1119,20 @@ fn codegen_regular_intrinsic_call<'tcx>( ret.write_cvalue(fx, old); } + sym::minimumf16 => { + intrinsic_args!(fx, args => (a, b); intrinsic); + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + + // FIXME(bytecodealliance/wasmtime#8312): Use `fmin` directly once + // Cranelift backend lowerings are implemented. + let a = codegen_f16_f128::f16_to_f32(fx, a); + let b = codegen_f16_f128::f16_to_f32(fx, b); + let val = fx.bcx.ins().fmin(a, b); + let val = codegen_f16_f128::f32_to_f16(fx, val); + let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f16)); + ret.write_cvalue(fx, val); + } sym::minimumf32 => { intrinsic_args!(fx, args => (a, b); intrinsic); let a = a.load_scalar(fx); @@ -1136,6 +1151,31 @@ fn codegen_regular_intrinsic_call<'tcx>( let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64)); ret.write_cvalue(fx, val); } + sym::minimumf128 => { + intrinsic_args!(fx, args => (a, b); intrinsic); + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + + // FIXME(bytecodealliance/wasmtime#8312): Use `fmin` once Cranelift + // backend lowerings are implemented. + let val = codegen_f16_f128::fmin_f128(fx, a, b); + let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f128)); + ret.write_cvalue(fx, val); + } + sym::maximumf16 => { + intrinsic_args!(fx, args => (a, b); intrinsic); + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + + // FIXME(bytecodealliance/wasmtime#8312): Use `fmax` directly once + // Cranelift backend lowerings are implemented. + let a = codegen_f16_f128::f16_to_f32(fx, a); + let b = codegen_f16_f128::f16_to_f32(fx, b); + let val = fx.bcx.ins().fmax(a, b); + let val = codegen_f16_f128::f32_to_f16(fx, val); + let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f16)); + ret.write_cvalue(fx, val); + } sym::maximumf32 => { intrinsic_args!(fx, args => (a, b); intrinsic); let a = a.load_scalar(fx); @@ -1154,7 +1194,27 @@ fn codegen_regular_intrinsic_call<'tcx>( let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64)); ret.write_cvalue(fx, val); } + sym::maximumf128 => { + intrinsic_args!(fx, args => (a, b); intrinsic); + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + + // FIXME(bytecodealliance/wasmtime#8312): Use `fmax` once Cranelift + // backend lowerings are implemented. + let val = codegen_f16_f128::fmax_f128(fx, a, b); + let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f128)); + ret.write_cvalue(fx, val); + } + + sym::minnumf16 => { + intrinsic_args!(fx, args => (a, b); intrinsic); + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + let val = crate::num::codegen_float_min(fx, a, b); + let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f16)); + ret.write_cvalue(fx, val); + } sym::minnumf32 => { intrinsic_args!(fx, args => (a, b); intrinsic); let a = a.load_scalar(fx); @@ -1173,6 +1233,24 @@ fn codegen_regular_intrinsic_call<'tcx>( let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64)); ret.write_cvalue(fx, val); } + sym::minnumf128 => { + intrinsic_args!(fx, args => (a, b); intrinsic); + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + + let val = crate::num::codegen_float_min(fx, a, b); + let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f128)); + ret.write_cvalue(fx, val); + } + sym::maxnumf16 => { + intrinsic_args!(fx, args => (a, b); intrinsic); + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + + let val = crate::num::codegen_float_max(fx, a, b); + let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f16)); + ret.write_cvalue(fx, val); + } sym::maxnumf32 => { intrinsic_args!(fx, args => (a, b); intrinsic); let a = a.load_scalar(fx); @@ -1191,6 +1269,15 @@ fn codegen_regular_intrinsic_call<'tcx>( let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64)); ret.write_cvalue(fx, val); } + sym::maxnumf128 => { + intrinsic_args!(fx, args => (a, b); intrinsic); + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + + let val = crate::num::codegen_float_max(fx, a, b); + let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f128)); + ret.write_cvalue(fx, val); + } sym::catch_unwind => { intrinsic_args!(fx, args => (f, data, catch_fn); intrinsic); diff --git a/src/num.rs b/src/num.rs index 3ed276267de64..f53045df6e799 100644 --- a/src/num.rs +++ b/src/num.rs @@ -416,7 +416,10 @@ pub(crate) fn codegen_float_binop<'tcx>( BinOp::Gt => FloatCC::GreaterThan, _ => unreachable!(), }; - let val = fx.bcx.ins().fcmp(fltcc, lhs, rhs); + // FIXME(bytecodealliance/wasmtime#8312): Replace with Cranelift + // `fcmp` once `f16`/`f128` backend lowerings have been added to + // Cranelift. + let val = codegen_f16_f128::fcmp(fx, fltcc, lhs, rhs); return CValue::by_val(val, fx.layout_of(fx.tcx.types.bool)); } _ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs), @@ -500,15 +503,19 @@ fn codegen_ptr_binop<'tcx>( // and `a.is_nan() ? b : (a <= b ? b : a)` for `maxnumf*`. NaN checks are done by comparing // a float against itself. Only in case of NaN is it not equal to itself. pub(crate) fn codegen_float_min(fx: &mut FunctionCx<'_, '_, '_>, a: Value, b: Value) -> Value { - let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a); - let a_ge_b = fx.bcx.ins().fcmp(FloatCC::GreaterThanOrEqual, a, b); + // FIXME(bytecodealliance/wasmtime#8312): Replace with Cranelift `fcmp` once + // `f16`/`f128` backend lowerings have been added to Cranelift. + let a_is_nan = codegen_f16_f128::fcmp(fx, FloatCC::NotEqual, a, a); + let a_ge_b = codegen_f16_f128::fcmp(fx, FloatCC::GreaterThanOrEqual, a, b); let temp = fx.bcx.ins().select(a_ge_b, b, a); fx.bcx.ins().select(a_is_nan, b, temp) } pub(crate) fn codegen_float_max(fx: &mut FunctionCx<'_, '_, '_>, a: Value, b: Value) -> Value { - let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a); - let a_le_b = fx.bcx.ins().fcmp(FloatCC::LessThanOrEqual, a, b); + // FIXME(bytecodealliance/wasmtime#8312): Replace with Cranelift `fcmp` once + // `f16`/`f128` backend lowerings have been added to Cranelift. + let a_is_nan = codegen_f16_f128::fcmp(fx, FloatCC::NotEqual, a, a); + let a_le_b = codegen_f16_f128::fcmp(fx, FloatCC::LessThanOrEqual, a, b); let temp = fx.bcx.ins().select(a_le_b, b, a); fx.bcx.ins().select(a_is_nan, b, temp) } From e46186f9944cf10c35b228e38ba6312903587896 Mon Sep 17 00:00:00 2001 From: beetrees Date: Fri, 23 May 2025 15:51:51 +0100 Subject: [PATCH 2704/4206] Add support for casting to and from `f16`/`f128` --- src/cast.rs | 21 ++++++- src/codegen_f16_f128.rs | 123 +++++++++++++++++++++++++++++++++++++++ src/compiler_builtins.rs | 19 ++++++ 3 files changed, 161 insertions(+), 2 deletions(-) diff --git a/src/cast.rs b/src/cast.rs index e2346324232fc..8a725680e7059 100644 --- a/src/cast.rs +++ b/src/cast.rs @@ -1,5 +1,6 @@ //! Various number casting functions +use crate::codegen_f16_f128; use crate::prelude::*; pub(crate) fn clif_intcast( @@ -36,6 +37,14 @@ pub(crate) fn clif_int_or_float_cast( ) -> Value { let from_ty = fx.bcx.func.dfg.value_type(from); + // FIXME(bytecodealliance/wasmtime#8312): Remove in favour of native + // Cranelift operations once Cranelift backends have lowerings for them. + if matches!(from_ty, types::F16 | types::F128) + || matches!(to_ty, types::F16 | types::F128) && from_ty != to_ty + { + return codegen_f16_f128::codegen_cast(fx, from, from_signed, to_ty, to_signed); + } + if from_ty.is_int() && to_ty.is_int() { // int-like -> int-like clif_intcast( @@ -58,8 +67,10 @@ pub(crate) fn clif_int_or_float_cast( "__float{sign}ti{flt}f", sign = if from_signed { "" } else { "un" }, flt = match to_ty { + types::F16 => "h", types::F32 => "s", types::F64 => "d", + types::F128 => "t", _ => unreachable!("{:?}", to_ty), }, ); @@ -90,8 +101,10 @@ pub(crate) fn clif_int_or_float_cast( "__fix{sign}{flt}fti", sign = if to_signed { "" } else { "uns" }, flt = match from_ty { + types::F16 => "h", types::F32 => "s", types::F64 => "d", + types::F128 => "t", _ => unreachable!("{:?}", to_ty), }, ); @@ -145,8 +158,12 @@ pub(crate) fn clif_int_or_float_cast( } else if from_ty.is_float() && to_ty.is_float() { // float -> float match (from_ty, to_ty) { - (types::F32, types::F64) => fx.bcx.ins().fpromote(types::F64, from), - (types::F64, types::F32) => fx.bcx.ins().fdemote(types::F32, from), + (types::F16, types::F32 | types::F64 | types::F128) + | (types::F32, types::F64 | types::F128) + | (types::F64, types::F128) => fx.bcx.ins().fpromote(to_ty, from), + (types::F128, types::F64 | types::F32 | types::F16) + | (types::F64, types::F32 | types::F16) + | (types::F32, types::F16) => fx.bcx.ins().fdemote(to_ty, from), _ => from, } } else { diff --git a/src/codegen_f16_f128.rs b/src/codegen_f16_f128.rs index c570fbbd993d9..a887341cec436 100644 --- a/src/codegen_f16_f128.rs +++ b/src/codegen_f16_f128.rs @@ -13,6 +13,11 @@ pub(crate) fn f16_to_f32(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value fx.lib_call("__extendhfsf2", vec![arg_ty], vec![AbiParam::new(types::F32)], &[value])[0] } +fn f16_to_f64(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { + let ret = f16_to_f32(fx, value); + fx.bcx.ins().fpromote(types::F64, ret) +} + pub(crate) fn f32_to_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { let ret_ty = if fx.tcx.sess.target.vendor == "apple" && fx.tcx.sess.target.arch == "x86_64" { types::I16 @@ -28,6 +33,21 @@ pub(crate) fn f32_to_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value if ret_ty == types::I16 { fx.bcx.ins().bitcast(types::F16, MemFlags::new(), ret) } else { ret } } +fn f64_to_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { + let ret_ty = if fx.tcx.sess.target.vendor == "apple" && fx.tcx.sess.target.arch == "x86_64" { + types::I16 + } else { + types::F16 + }; + let ret = fx.lib_call( + "__truncdfhf2", + vec![AbiParam::new(types::F64)], + vec![AbiParam::new(ret_ty)], + &[value], + )[0]; + if ret_ty == types::I16 { fx.bcx.ins().bitcast(types::F16, MemFlags::new(), ret) } else { ret } +} + pub(crate) fn fcmp(fx: &mut FunctionCx<'_, '_, '_>, cc: FloatCC, lhs: Value, rhs: Value) -> Value { let ty = fx.bcx.func.dfg.value_type(lhs); match ty { @@ -99,6 +119,109 @@ pub(crate) fn neg_f128(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { fx.bcx.ins().bitcast(types::F128, MemFlags::new(), bits) } +pub(crate) fn codegen_cast( + fx: &mut FunctionCx<'_, '_, '_>, + from: Value, + from_signed: bool, + to_ty: Type, + to_signed: bool, +) -> Value { + let from_ty = fx.bcx.func.dfg.value_type(from); + if from_ty.is_float() && to_ty.is_float() { + let name = match (from_ty, to_ty) { + (types::F16, types::F32) => return f16_to_f32(fx, from), + (types::F16, types::F64) => return f16_to_f64(fx, from), + (types::F16, types::F128) => "__extendhftf2", + (types::F32, types::F128) => "__extendsftf2", + (types::F64, types::F128) => "__extenddftf2", + (types::F128, types::F64) => "__trunctfdf2", + (types::F128, types::F32) => "__trunctfsf2", + (types::F128, types::F16) => "__trunctfhf2", + (types::F64, types::F16) => return f64_to_f16(fx, from), + (types::F32, types::F16) => return f32_to_f16(fx, from), + _ => unreachable!("{from_ty:?} -> {to_ty:?}"), + }; + fx.lib_call(name, vec![AbiParam::new(from_ty)], vec![AbiParam::new(to_ty)], &[from])[0] + } else if from_ty.is_int() && to_ty == types::F16 { + let res = clif_int_or_float_cast(fx, from, from_signed, types::F32, false); + f32_to_f16(fx, res) + } else if from_ty == types::F16 && to_ty.is_int() { + let from = f16_to_f32(fx, from); + clif_int_or_float_cast(fx, from, false, to_ty, to_signed) + } else if from_ty.is_int() && to_ty == types::F128 { + let (from, from_ty) = if from_ty.bits() < 32 { + (clif_int_or_float_cast(fx, from, from_signed, types::I32, from_signed), types::I32) + } else { + (from, from_ty) + }; + let name = format!( + "__float{sign}{size}itf", + sign = if from_signed { "" } else { "un" }, + size = match from_ty { + types::I32 => 's', + types::I64 => 'd', + types::I128 => 't', + _ => unreachable!("{from_ty:?}"), + }, + ); + fx.lib_call( + &name, + vec![lib_call_arg_param(fx.tcx, from_ty, from_signed)], + vec![AbiParam::new(to_ty)], + &[from], + )[0] + } else if from_ty == types::F128 && to_ty.is_int() { + let ret_ty = if to_ty.bits() < 32 { types::I32 } else { to_ty }; + let name = format!( + "__fix{sign}tf{size}i", + sign = if from_signed { "" } else { "un" }, + size = match ret_ty { + types::I32 => 's', + types::I64 => 'd', + types::I128 => 't', + _ => unreachable!("{from_ty:?}"), + }, + ); + let ret = + fx.lib_call(&name, vec![AbiParam::new(from_ty)], vec![AbiParam::new(to_ty)], &[from]) + [0]; + let val = if ret_ty == to_ty { + ret + } else { + let (min, max) = match (to_ty, to_signed) { + (types::I8, false) => (0, i64::from(u8::MAX)), + (types::I16, false) => (0, i64::from(u16::MAX)), + (types::I8, true) => (i64::from(i8::MIN as u32), i64::from(i8::MAX as u32)), + (types::I16, true) => (i64::from(i16::MIN as u32), i64::from(i16::MAX as u32)), + _ => unreachable!("{to_ty:?}"), + }; + let min_val = fx.bcx.ins().iconst(types::I32, min); + let max_val = fx.bcx.ins().iconst(types::I32, max); + + let val = if to_signed { + let has_underflow = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, ret, min); + let has_overflow = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThan, ret, max); + let bottom_capped = fx.bcx.ins().select(has_underflow, min_val, ret); + fx.bcx.ins().select(has_overflow, max_val, bottom_capped) + } else { + let has_overflow = fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan, ret, max); + fx.bcx.ins().select(has_overflow, max_val, ret) + }; + fx.bcx.ins().ireduce(to_ty, val) + }; + + if let Some(false) = fx.tcx.sess.opts.unstable_opts.saturating_float_casts { + return val; + } + + let is_not_nan = fcmp(fx, FloatCC::Equal, from, from); + let zero = type_zero_value(&mut fx.bcx, to_ty); + fx.bcx.ins().select(is_not_nan, val, zero) + } else { + unreachable!("{from_ty:?} -> {to_ty:?}"); + } +} + pub(crate) fn fmin_f128(fx: &mut FunctionCx<'_, '_, '_>, a: Value, b: Value) -> Value { fx.lib_call( "fminimumf128", diff --git a/src/compiler_builtins.rs b/src/compiler_builtins.rs index 017a1370abd75..d9cbffd7ae013 100644 --- a/src/compiler_builtins.rs +++ b/src/compiler_builtins.rs @@ -49,15 +49,34 @@ builtin_functions! { // integer -> float fn __floattisf(i: i128) -> f32; fn __floattidf(i: i128) -> f64; + fn __floatsitf(i: i32) -> f128; + fn __floatditf(i: i64) -> f128; + fn __floattitf(i: i128) -> f128; fn __floatuntisf(i: u128) -> f32; fn __floatuntidf(i: u128) -> f64; + fn __floatunsitf(i: u32) -> f128; + fn __floatunditf(i: u64) -> f128; + fn __floatuntitf(i: u128) -> f128; // float -> integer fn __fixsfti(f: f32) -> i128; fn __fixdfti(f: f64) -> i128; + fn __fixtfsi(f: f128) -> i32; + fn __fixtfdi(f: f128) -> i64; + fn __fixtfti(f: f128) -> i128; fn __fixunssfti(f: f32) -> u128; fn __fixunsdfti(f: f64) -> u128; + fn __fixunstfsi(f: f128) -> u32; + fn __fixunstfdi(f: f128) -> u64; + fn __fixunstfti(f: f128) -> u128; // float -> float fn __extendhfsf2(f: f16) -> f32; + fn __extendhftf2(f: f16) -> f128; + fn __extendsftf2(f: f32) -> f128; + fn __extenddftf2(f: f64) -> f128; + fn __trunctfdf2(f: f128) -> f64; + fn __trunctfsf2(f: f128) -> f32; + fn __trunctfhf2(f: f128) -> f16; + fn __truncdfhf2(f: f64) -> f16; fn __truncsfhf2(f: f32) -> f16; // float binops fn __addtf3(a: f128, b: f128) -> f128; From 2055f01323fbeada8857f9a0725c12567891c377 Mon Sep 17 00:00:00 2001 From: beetrees Date: Fri, 23 May 2025 15:51:51 +0100 Subject: [PATCH 2705/4206] Add `f16`/`f128` intrinsic support --- src/codegen_f16_f128.rs | 43 ++++++++++++++++++++++ src/compiler_builtins.rs | 15 ++++++++ src/intrinsics/mod.rs | 79 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 136 insertions(+), 1 deletion(-) diff --git a/src/codegen_f16_f128.rs b/src/codegen_f16_f128.rs index a887341cec436..1e202be1f1855 100644 --- a/src/codegen_f16_f128.rs +++ b/src/codegen_f16_f128.rs @@ -119,6 +119,41 @@ pub(crate) fn neg_f128(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { fx.bcx.ins().bitcast(types::F128, MemFlags::new(), bits) } +pub(crate) fn abs_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { + let bits = fx.bcx.ins().bitcast(types::I16, MemFlags::new(), value); + let bits = fx.bcx.ins().band_imm(bits, 0x7fff); + fx.bcx.ins().bitcast(types::F16, MemFlags::new(), bits) +} + +pub(crate) fn abs_f128(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { + let bits = fx.bcx.ins().bitcast(types::I128, MemFlags::new(), value); + let (low, high) = fx.bcx.ins().isplit(bits); + let high = fx.bcx.ins().band_imm(high, 0x7fff_ffff_ffff_ffff_u64 as i64); + let bits = fx.bcx.ins().iconcat(low, high); + fx.bcx.ins().bitcast(types::F128, MemFlags::new(), bits) +} + +pub(crate) fn copysign_f16(fx: &mut FunctionCx<'_, '_, '_>, lhs: Value, rhs: Value) -> Value { + let lhs = fx.bcx.ins().bitcast(types::I16, MemFlags::new(), lhs); + let rhs = fx.bcx.ins().bitcast(types::I16, MemFlags::new(), rhs); + let res = fx.bcx.ins().band_imm(lhs, 0x7fff); + let sign = fx.bcx.ins().band_imm(rhs, 0x8000); + let res = fx.bcx.ins().bor(res, sign); + fx.bcx.ins().bitcast(types::F16, MemFlags::new(), res) +} + +pub(crate) fn copysign_f128(fx: &mut FunctionCx<'_, '_, '_>, lhs: Value, rhs: Value) -> Value { + let lhs = fx.bcx.ins().bitcast(types::I128, MemFlags::new(), lhs); + let rhs = fx.bcx.ins().bitcast(types::I128, MemFlags::new(), rhs); + let (low, lhs_high) = fx.bcx.ins().isplit(lhs); + let (_, rhs_high) = fx.bcx.ins().isplit(rhs); + let high = fx.bcx.ins().band_imm(lhs_high, 0x7fff_ffff_ffff_ffff_u64 as i64); + let sign = fx.bcx.ins().band_imm(rhs_high, 0x8000_0000_0000_0000_u64 as i64); + let high = fx.bcx.ins().bor(high, sign); + let res = fx.bcx.ins().iconcat(low, high); + fx.bcx.ins().bitcast(types::F128, MemFlags::new(), res) +} + pub(crate) fn codegen_cast( fx: &mut FunctionCx<'_, '_, '_>, from: Value, @@ -222,6 +257,14 @@ pub(crate) fn codegen_cast( } } +pub(crate) fn fma_f16(fx: &mut FunctionCx<'_, '_, '_>, x: Value, y: Value, z: Value) -> Value { + let x = f16_to_f64(fx, x); + let y = f16_to_f64(fx, y); + let z = f16_to_f64(fx, z); + let res = fx.bcx.ins().fma(x, y, z); + f64_to_f16(fx, res) +} + pub(crate) fn fmin_f128(fx: &mut FunctionCx<'_, '_, '_>, a: Value, b: Value) -> Value { fx.lib_call( "fminimumf128", diff --git a/src/compiler_builtins.rs b/src/compiler_builtins.rs index d9cbffd7ae013..6eea19211fa1b 100644 --- a/src/compiler_builtins.rs +++ b/src/compiler_builtins.rs @@ -109,6 +109,8 @@ builtin_functions! { // float intrinsics fn __powisf2(a: f32, b: i32) -> f32; fn __powidf2(a: f64, b: i32) -> f64; + // FIXME(f16_f128): `compiler-builtins` doesn't currently support `__powitf2` on MSVC. + // fn __powitf2(a: f128, b: i32) -> f128; fn powf(a: f32, b: f32) -> f32; fn pow(a: f64, b: f64) -> f64; fn expf(f: f32) -> f32; @@ -125,6 +127,19 @@ builtin_functions! { fn sin(f: f64) -> f64; fn cosf(f: f32) -> f32; fn cos(f: f64) -> f64; + fn fmaf128(a: f128, b: f128, c: f128) -> f128; + fn floorf16(f: f16) -> f16; + fn floorf128(f: f128) -> f128; + fn ceilf16(f: f16) -> f16; + fn ceilf128(f: f128) -> f128; + fn truncf16(f: f16) -> f16; + fn truncf128(f: f128) -> f128; + fn rintf16(f: f16) -> f16; + fn rintf128(f: f128) -> f128; + fn sqrtf16(f: f16) -> f16; + fn sqrtf128(f: f128) -> f128; + // FIXME(f16_f128): Add other float intrinsics as compiler-builtins gains support (meaning they + // are available on all targets). // allocator // NOTE: These need to be mentioned here despite not being part of compiler_builtins because diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index 6481d211234e2..b21ca32c9a2e3 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -249,8 +249,10 @@ fn bool_to_zero_or_max_uint<'tcx>( let ty = fx.clif_type(ty).unwrap(); let int_ty = match ty { + types::F16 => types::I16, types::F32 => types::I32, types::F64 => types::I64, + types::F128 => types::I128, ty => ty, }; @@ -309,45 +311,83 @@ fn codegen_float_intrinsic_call<'tcx>( ret: CPlace<'tcx>, ) -> bool { let (name, arg_count, ty, clif_ty) = match intrinsic { + sym::expf16 => ("expf16", 1, fx.tcx.types.f16, types::F16), sym::expf32 => ("expf", 1, fx.tcx.types.f32, types::F32), sym::expf64 => ("exp", 1, fx.tcx.types.f64, types::F64), + sym::expf128 => ("expf128", 1, fx.tcx.types.f128, types::F128), + sym::exp2f16 => ("exp2f16", 1, fx.tcx.types.f16, types::F16), sym::exp2f32 => ("exp2f", 1, fx.tcx.types.f32, types::F32), sym::exp2f64 => ("exp2", 1, fx.tcx.types.f64, types::F64), + sym::exp2f128 => ("exp2f128", 1, fx.tcx.types.f128, types::F128), + sym::sqrtf16 => ("sqrtf16", 1, fx.tcx.types.f16, types::F16), sym::sqrtf32 => ("sqrtf", 1, fx.tcx.types.f32, types::F32), sym::sqrtf64 => ("sqrt", 1, fx.tcx.types.f64, types::F64), + sym::sqrtf128 => ("sqrtf128", 1, fx.tcx.types.f128, types::F128), + sym::powif16 => ("__powisf2", 2, fx.tcx.types.f16, types::F16), // compiler-builtins sym::powif32 => ("__powisf2", 2, fx.tcx.types.f32, types::F32), // compiler-builtins sym::powif64 => ("__powidf2", 2, fx.tcx.types.f64, types::F64), // compiler-builtins + sym::powif128 => ("__powitf2", 2, fx.tcx.types.f128, types::F128), // compiler-builtins + sym::powf16 => ("powf16", 2, fx.tcx.types.f16, types::F16), sym::powf32 => ("powf", 2, fx.tcx.types.f32, types::F32), sym::powf64 => ("pow", 2, fx.tcx.types.f64, types::F64), + sym::powf128 => ("powf128", 2, fx.tcx.types.f128, types::F128), + sym::logf16 => ("logf16", 1, fx.tcx.types.f16, types::F16), sym::logf32 => ("logf", 1, fx.tcx.types.f32, types::F32), sym::logf64 => ("log", 1, fx.tcx.types.f64, types::F64), + sym::logf128 => ("logf128", 1, fx.tcx.types.f128, types::F128), + sym::log2f16 => ("log2f16", 1, fx.tcx.types.f16, types::F16), sym::log2f32 => ("log2f", 1, fx.tcx.types.f32, types::F32), sym::log2f64 => ("log2", 1, fx.tcx.types.f64, types::F64), + sym::log2f128 => ("log2f128", 1, fx.tcx.types.f128, types::F128), + sym::log10f16 => ("log10f16", 1, fx.tcx.types.f16, types::F16), sym::log10f32 => ("log10f", 1, fx.tcx.types.f32, types::F32), sym::log10f64 => ("log10", 1, fx.tcx.types.f64, types::F64), + sym::log10f128 => ("log10f128", 1, fx.tcx.types.f128, types::F128), + sym::fabsf16 => ("fabsf16", 1, fx.tcx.types.f16, types::F16), sym::fabsf32 => ("fabsf", 1, fx.tcx.types.f32, types::F32), sym::fabsf64 => ("fabs", 1, fx.tcx.types.f64, types::F64), + sym::fabsf128 => ("fabsf128", 1, fx.tcx.types.f128, types::F128), + sym::fmaf16 => ("fmaf16", 3, fx.tcx.types.f16, types::F16), sym::fmaf32 => ("fmaf", 3, fx.tcx.types.f32, types::F32), sym::fmaf64 => ("fma", 3, fx.tcx.types.f64, types::F64), + sym::fmaf128 => ("fmaf128", 3, fx.tcx.types.f128, types::F128), // FIXME: calling `fma` from libc without FMA target feature uses expensive sofware emulation + sym::fmuladdf16 => ("fmaf16", 3, fx.tcx.types.f16, types::F16), // TODO: use cranelift intrinsic analogous to llvm.fmuladd.f16 sym::fmuladdf32 => ("fmaf", 3, fx.tcx.types.f32, types::F32), // TODO: use cranelift intrinsic analogous to llvm.fmuladd.f32 sym::fmuladdf64 => ("fma", 3, fx.tcx.types.f64, types::F64), // TODO: use cranelift intrinsic analogous to llvm.fmuladd.f64 + sym::fmuladdf128 => ("fmaf128", 3, fx.tcx.types.f128, types::F128), // TODO: use cranelift intrinsic analogous to llvm.fmuladd.f128 + sym::copysignf16 => ("copysignf16", 2, fx.tcx.types.f16, types::F16), sym::copysignf32 => ("copysignf", 2, fx.tcx.types.f32, types::F32), sym::copysignf64 => ("copysign", 2, fx.tcx.types.f64, types::F64), + sym::copysignf128 => ("copysignf128", 2, fx.tcx.types.f128, types::F128), + sym::floorf16 => ("floorf16", 1, fx.tcx.types.f16, types::F16), sym::floorf32 => ("floorf", 1, fx.tcx.types.f32, types::F32), sym::floorf64 => ("floor", 1, fx.tcx.types.f64, types::F64), + sym::floorf128 => ("floorf128", 1, fx.tcx.types.f128, types::F128), + sym::ceilf16 => ("ceilf16", 1, fx.tcx.types.f16, types::F16), sym::ceilf32 => ("ceilf", 1, fx.tcx.types.f32, types::F32), sym::ceilf64 => ("ceil", 1, fx.tcx.types.f64, types::F64), + sym::ceilf128 => ("ceilf128", 1, fx.tcx.types.f128, types::F128), + sym::truncf16 => ("truncf16", 1, fx.tcx.types.f16, types::F16), sym::truncf32 => ("truncf", 1, fx.tcx.types.f32, types::F32), sym::truncf64 => ("trunc", 1, fx.tcx.types.f64, types::F64), + sym::truncf128 => ("truncf128", 1, fx.tcx.types.f128, types::F128), + sym::round_ties_even_f16 => ("rintf16", 1, fx.tcx.types.f16, types::F16), sym::round_ties_even_f32 => ("rintf", 1, fx.tcx.types.f32, types::F32), sym::round_ties_even_f64 => ("rint", 1, fx.tcx.types.f64, types::F64), + sym::round_ties_even_f128 => ("rintf128", 1, fx.tcx.types.f128, types::F128), + sym::roundf16 => ("roundf16", 1, fx.tcx.types.f16, types::F16), sym::roundf32 => ("roundf", 1, fx.tcx.types.f32, types::F32), sym::roundf64 => ("round", 1, fx.tcx.types.f64, types::F64), + sym::roundf128 => ("roundf128", 1, fx.tcx.types.f128, types::F128), + sym::sinf16 => ("sinf16", 1, fx.tcx.types.f16, types::F16), sym::sinf32 => ("sinf", 1, fx.tcx.types.f32, types::F32), sym::sinf64 => ("sin", 1, fx.tcx.types.f64, types::F64), + sym::sinf128 => ("sinf128", 1, fx.tcx.types.f128, types::F128), + sym::cosf16 => ("cosf16", 1, fx.tcx.types.f16, types::F16), sym::cosf32 => ("cosf", 1, fx.tcx.types.f32, types::F32), sym::cosf64 => ("cos", 1, fx.tcx.types.f64, types::F64), + sym::cosf128 => ("cosf128", 1, fx.tcx.types.f128, types::F128), _ => return false, }; @@ -380,13 +420,26 @@ fn codegen_float_intrinsic_call<'tcx>( }; let layout = fx.layout_of(ty); + // FIXME(bytecodealliance/wasmtime#8312): Use native Cranelift operations + // for `f16` and `f128` once the lowerings have been implemented in Cranelift. let res = match intrinsic { + sym::fmaf16 | sym::fmuladdf16 => { + CValue::by_val(codegen_f16_f128::fma_f16(fx, args[0], args[1], args[2]), layout) + } sym::fmaf32 | sym::fmaf64 | sym::fmuladdf32 | sym::fmuladdf64 => { CValue::by_val(fx.bcx.ins().fma(args[0], args[1], args[2]), layout) } + sym::copysignf16 => { + CValue::by_val(codegen_f16_f128::copysign_f16(fx, args[0], args[1]), layout) + } + sym::copysignf128 => { + CValue::by_val(codegen_f16_f128::copysign_f128(fx, args[0], args[1]), layout) + } sym::copysignf32 | sym::copysignf64 => { CValue::by_val(fx.bcx.ins().fcopysign(args[0], args[1]), layout) } + sym::fabsf16 => CValue::by_val(codegen_f16_f128::abs_f16(fx, args[0]), layout), + sym::fabsf128 => CValue::by_val(codegen_f16_f128::abs_f128(fx, args[0]), layout), sym::fabsf32 | sym::fabsf64 | sym::floorf32 @@ -416,12 +469,36 @@ fn codegen_float_intrinsic_call<'tcx>( // These intrinsics aren't supported natively by Cranelift. // Lower them to a libcall. - sym::powif32 | sym::powif64 => { + sym::powif16 | sym::powif32 | sym::powif64 | sym::powif128 => { + let temp; + let (clif_ty, args) = if intrinsic == sym::powif16 { + temp = [codegen_f16_f128::f16_to_f32(fx, args[0]), args[1]]; + (types::F32, temp.as_slice()) + } else { + (clif_ty, args) + }; let input_tys: Vec<_> = vec![AbiParam::new(clif_ty), lib_call_arg_param(fx.tcx, types::I32, true)]; let ret_val = fx.lib_call(name, input_tys, vec![AbiParam::new(clif_ty)], &args)[0]; + let ret_val = if intrinsic == sym::powif16 { + codegen_f16_f128::f32_to_f16(fx, ret_val) + } else { + ret_val + }; CValue::by_val(ret_val, fx.layout_of(ty)) } + sym::powf16 => { + // FIXME(f16_f128): Rust `compiler-builtins` doesn't export `powf16` yet. + let x = codegen_f16_f128::f16_to_f32(fx, args[0]); + let y = codegen_f16_f128::f16_to_f32(fx, args[1]); + let ret_val = fx.lib_call( + "powf", + vec![AbiParam::new(types::F32), AbiParam::new(types::F32)], + vec![AbiParam::new(types::F32)], + &[x, y], + )[0]; + CValue::by_val(codegen_f16_f128::f32_to_f16(fx, ret_val), fx.layout_of(ty)) + } _ => { let input_tys: Vec<_> = args.iter().map(|_| AbiParam::new(clif_ty)).collect(); let ret_val = fx.lib_call(name, input_tys, vec![AbiParam::new(clif_ty)], &args)[0]; From 02195f56c718defd1df04a452530b14cc96155c9 Mon Sep 17 00:00:00 2001 From: beetrees Date: Fri, 23 May 2025 15:51:51 +0100 Subject: [PATCH 2706/4206] Enable tests and `compiler-builtins` for `f16`/`f128` --- build_system/build_sysroot.rs | 2 +- scripts/setup_rust_fork.sh | 2 +- scripts/test_rustc_tests.sh | 8 -------- src/lib.rs | 32 +++++++++++++++++++++++++++----- 4 files changed, 29 insertions(+), 15 deletions(-) diff --git a/build_system/build_sysroot.rs b/build_system/build_sysroot.rs index a6e956c51f134..00955998e703d 100644 --- a/build_system/build_sysroot.rs +++ b/build_system/build_sysroot.rs @@ -235,7 +235,7 @@ fn build_clif_sysroot_for_triple( compiler.rustflags.extend(rustflags); let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs); build_cmd.arg("--release"); - build_cmd.arg("--features").arg("backtrace panic-unwind compiler-builtins-no-f16-f128"); + build_cmd.arg("--features").arg("backtrace panic-unwind"); build_cmd.arg(format!("-Zroot-dir={}", STDLIB_SRC.to_path(dirs).display())); build_cmd.env("CARGO_PROFILE_RELEASE_DEBUG", "true"); build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif"); diff --git a/scripts/setup_rust_fork.sh b/scripts/setup_rust_fork.sh index ca6426f2ba9d3..532702bb1a469 100644 --- a/scripts/setup_rust_fork.sh +++ b/scripts/setup_rust_fork.sh @@ -43,7 +43,7 @@ verbose-tests = false # disabled bootstrap will crash trying to copy llvm tools for the bootstrap # compiler. llvm-tools = false -std-features = ["panic-unwind", "compiler-builtins-no-f16-f128"] +std-features = ["panic-unwind"] EOF diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index d014b6881ff4c..32c71f433b0ff 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -72,14 +72,6 @@ rm tests/ui/consts/precise-drop-with-coverage.rs rm tests/ui/issues/issue-85461.rs rm -r tests/ui/instrument-coverage/ -# missing f16/f128 support -rm tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs -rm tests/ui/asm/aarch64/type-f16.rs -rm tests/ui/float/conv-bits-runtime-const.rs -rm tests/ui/consts/const-eval/float_methods.rs -rm tests/ui/match/match-float.rs -rm tests/ui/float/target-has-reliable-nightly-float.rs - # optimization tests # ================== rm tests/ui/codegen/issue-28950.rs # depends on stack size optimizations diff --git a/src/lib.rs b/src/lib.rs index 03dfd495682cd..8ef623cde0057 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -201,14 +201,36 @@ impl CodegenBackend for CraneliftCodegenBackend { // FIXME do `unstable_target_features` properly let unstable_target_features = target_features.clone(); + // FIXME(f16_f128): LLVM 20 (currently used by `rustc`) passes `f128` in XMM registers on + // Windows, whereas LLVM 21+ and Cranelift pass it indirectly. This means that `f128` won't + // work when linking against a LLVM-built sysroot. + let has_reliable_f128 = !sess.target.is_like_windows; + let has_reliable_f16 = match &*sess.target.arch { + // FIXME(f16_f128): LLVM 20 does not support `f16` on s390x, meaning the required + // builtins are not available in `compiler-builtins`. + "s390x" => false, + // FIXME(f16_f128): `rustc_codegen_llvm` currently disables support on Windows GNU + // targets due to GCC using a different ABI than LLVM. Therefore `f16` won't be + // available when using a LLVM-built sysroot. + "x86_64" + if sess.target.os == "windows" + && sess.target.env == "gnu" + && sess.target.abi != "llvm" => + { + false + } + _ => true, + }; + TargetConfig { target_features, unstable_target_features, - // Cranelift does not yet support f16 or f128 - has_reliable_f16: false, - has_reliable_f16_math: false, - has_reliable_f128: false, - has_reliable_f128_math: false, + // `rustc_codegen_cranelift` polyfills functionality not yet + // available in Cranelift. + has_reliable_f16, + has_reliable_f16_math: has_reliable_f16, + has_reliable_f128, + has_reliable_f128_math: has_reliable_f128, } } From ec5e841957c2f0200496aa551823157d92a19cc5 Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Sat, 24 May 2025 15:12:14 +0200 Subject: [PATCH 2707/4206] ci: move PR job x86_64-gnu-tools to codebuild --- src/ci/github-actions/jobs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 2daa862460534..1d175bd97e6a1 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -123,7 +123,7 @@ pr: DOCKER_SCRIPT: x86_64-gnu-llvm.sh <<: *job-linux-16c - name: x86_64-gnu-tools - <<: *job-linux-16c + <<: *job-linux-36c-codebuild # Jobs that run when you perform a try build (@bors try) # These jobs automatically inherit envs.try, to avoid repeating From 9c234c03fd2d4121147a860ee3430f875fd6d2d2 Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Sat, 24 May 2025 06:22:49 -0700 Subject: [PATCH 2708/4206] Disable test on android because it doesn't have backtraces. --- tests/ui/panics/location-detail-unwrap-multiline.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/ui/panics/location-detail-unwrap-multiline.rs b/tests/ui/panics/location-detail-unwrap-multiline.rs index afe15a579c41c..56e1760d851bb 100644 --- a/tests/ui/panics/location-detail-unwrap-multiline.rs +++ b/tests/ui/panics/location-detail-unwrap-multiline.rs @@ -1,8 +1,9 @@ //@ run-fail //@ compile-flags: -Cstrip=none -Cdebuginfo=line-tables-only -Copt-level=0 //@ exec-env:RUST_BACKTRACE=1 -//@ regex-error-pattern: location-detail-unwrap-multiline\.rs:10(:10)?\n +//@ regex-error-pattern: location-detail-unwrap-multiline\.rs:11(:10)?\n //@ needs-unwind +//@ ignore-android FIXME #17520 fn main() { let opt: Option = None; From ebf39a54786ffb10a8ff5aec5504e4fbd29db19a Mon Sep 17 00:00:00 2001 From: yanglsh Date: Sat, 24 May 2025 21:10:46 +0800 Subject: [PATCH 2709/4206] fix: `unit_arg` wrongly handled macros --- clippy_lints/src/unit_types/unit_arg.rs | 54 ++++++++++++++++++------- clippy_utils/src/lib.rs | 3 +- tests/ui/unit_arg.rs | 24 +++++++++++ tests/ui/unit_arg.stderr | 23 ++++++++++- tests/ui/unit_arg_fixable.fixed | 30 ++++++++++++++ tests/ui/unit_arg_fixable.rs | 27 +++++++++++++ tests/ui/unit_arg_fixable.stderr | 46 ++++++++++++++++++++- 7 files changed, 188 insertions(+), 19 deletions(-) diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index e09b362800c0e..74b3331414c3c 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -1,9 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{SourceText, SpanRangeExt, indent_of, reindent_multiline}; +use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; +use clippy_utils::sugg::Sugg; use clippy_utils::{is_expr_default, is_from_proc_macro}; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, MatchSource, Node, StmtKind}; use rustc_lint::LateContext; +use rustc_span::SyntaxContext; use super::{UNIT_ARG, utils}; @@ -100,14 +102,16 @@ fn lint_unit_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, args_to_ let arg_snippets: Vec<_> = args_to_recover .iter() - .filter_map(|arg| arg.span.get_source_text(cx)) + // If the argument is from an expansion and is a `Default::default()`, we skip it + .filter(|arg| !arg.span.from_expansion() || !is_expr_default_nested(cx, arg)) + .filter_map(|arg| get_expr_snippet(cx, arg)) .collect(); // If the argument is an empty block or `Default::default()`, we can replace it with `()`. let arg_snippets_without_redundant_exprs: Vec<_> = args_to_recover .iter() - .filter(|arg| !is_empty_block(arg) && !is_expr_default(cx, arg)) - .filter_map(|arg| arg.span.get_source_text(cx)) + .filter(|arg| !is_expr_default_nested(cx, arg) && (arg.span.from_expansion() || !is_empty_block(arg))) + .filter_map(|arg| get_expr_snippet(cx, arg)) .collect(); if let Some(call_snippet) = expr.span.get_source_text(cx) { @@ -119,13 +123,17 @@ fn lint_unit_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, args_to_ &arg_snippets_without_redundant_exprs, ); - if arg_snippets_without_redundant_exprs.is_empty() { + if arg_snippets_without_redundant_exprs.is_empty() + && let suggestions = args_to_recover + .iter() + .filter(|arg| !arg.span.from_expansion() || !is_expr_default_nested(cx, arg)) + .map(|arg| (arg.span.parent_callsite().unwrap_or(arg.span), "()".to_string())) + .collect::>() + && !suggestions.is_empty() + { db.multipart_suggestion( format!("use {singular}unit literal{plural} instead"), - args_to_recover - .iter() - .map(|arg| (arg.span, "()".to_string())) - .collect::>(), + suggestions, applicability, ); } else { @@ -146,6 +154,22 @@ fn lint_unit_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, args_to_ ); } +fn is_expr_default_nested<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + is_expr_default(cx, expr) + || matches!(expr.kind, ExprKind::Block(block, _) + if block.expr.is_some() && is_expr_default_nested(cx, block.expr.unwrap())) +} + +fn get_expr_snippet<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option> { + let mut app = Applicability::MachineApplicable; + let snip = Sugg::hir_with_context(cx, expr, SyntaxContext::root(), "..", &mut app); + if app != Applicability::MachineApplicable { + return None; + } + + Some(snip) +} + fn is_empty_block(expr: &Expr<'_>) -> bool { matches!( expr.kind, @@ -164,17 +188,17 @@ fn fmt_stmts_and_call( cx: &LateContext<'_>, call_expr: &Expr<'_>, call_snippet: &str, - args_snippets: &[SourceText], - non_empty_block_args_snippets: &[SourceText], + args_snippets: &[Sugg<'_>], + non_empty_block_args_snippets: &[Sugg<'_>], ) -> String { let call_expr_indent = indent_of(cx, call_expr.span).unwrap_or(0); - let call_snippet_with_replacements = args_snippets - .iter() - .fold(call_snippet.to_owned(), |acc, arg| acc.replacen(arg.as_ref(), "()", 1)); + let call_snippet_with_replacements = args_snippets.iter().fold(call_snippet.to_owned(), |acc, arg| { + acc.replacen(&arg.to_string(), "()", 1) + }); let mut stmts_and_call = non_empty_block_args_snippets .iter() - .map(|it| it.as_ref().to_owned()) + .map(ToString::to_string) .collect::>(); stmts_and_call.push(call_snippet_with_replacements); stmts_and_call = stmts_and_call diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index f3cd22de5229b..4e588adf43ebd 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -3472,13 +3472,12 @@ pub fn desugar_await<'tcx>(expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { } } -/// Checks if the given expression is the `default` method belonging to the `Default` trait. +/// Checks if the given expression is a call to `Default::default()`. pub fn is_expr_default<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { if let ExprKind::Call(fn_expr, []) = &expr.kind && let ExprKind::Path(qpath) = &fn_expr.kind && let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id) { - // right hand side of assignment is `Default::default` cx.tcx.is_diagnostic_item(sym::default_fn, def_id) } else { false diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index 22a6a26dab626..4208efad6774d 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -151,3 +151,27 @@ fn main() { bad(); ok(); } + +fn issue14857() { + let fn_take_unit = |_: ()| {}; + fn some_other_fn(_: &i32) {} + + macro_rules! mac { + (def) => { + Default::default() + }; + (func $f:expr) => { + $f() + }; + (nonempty_block $e:expr) => {{ + some_other_fn(&$e); + $e + }}; + } + fn_take_unit(mac!(def)); + //~^ unit_arg + fn_take_unit(mac!(func Default::default)); + //~^ unit_arg + fn_take_unit(mac!(nonempty_block Default::default())); + //~^ unit_arg +} diff --git a/tests/ui/unit_arg.stderr b/tests/ui/unit_arg.stderr index 6c333d9792d4d..0dcfb02b9fa08 100644 --- a/tests/ui/unit_arg.stderr +++ b/tests/ui/unit_arg.stderr @@ -199,5 +199,26 @@ LL ~ foo(1); LL + Some(()) | -error: aborting due to 10 previous errors +error: passing a unit value to a function + --> tests/ui/unit_arg.rs:171:5 + | +LL | fn_take_unit(mac!(def)); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + +error: passing a unit value to a function + --> tests/ui/unit_arg.rs:173:5 + | +LL | fn_take_unit(mac!(func Default::default)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + +error: passing a unit value to a function + --> tests/ui/unit_arg.rs:175:5 + | +LL | fn_take_unit(mac!(nonempty_block Default::default())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + +error: aborting due to 13 previous errors diff --git a/tests/ui/unit_arg_fixable.fixed b/tests/ui/unit_arg_fixable.fixed index 7a25b93e5aee3..3ef6a953c729b 100644 --- a/tests/ui/unit_arg_fixable.fixed +++ b/tests/ui/unit_arg_fixable.fixed @@ -37,4 +37,34 @@ fn issue14857() { let fn_take_unit = |_: ()| {}; fn_take_unit(()); //~^ unit_arg + + fn some_other_fn(_: &i32) {} + + macro_rules! another_mac { + () => { + some_other_fn(&Default::default()) + }; + ($e:expr) => { + some_other_fn(&$e) + }; + } + + another_mac!(); + fn_take_unit(()); + //~^ unit_arg + another_mac!(1); + fn_take_unit(()); + //~^ unit_arg + + macro_rules! mac { + (nondef $e:expr) => { + $e + }; + (empty_block) => {{}}; + } + fn_take_unit(mac!(nondef ())); + //~^ unit_arg + mac!(empty_block); + fn_take_unit(()); + //~^ unit_arg } diff --git a/tests/ui/unit_arg_fixable.rs b/tests/ui/unit_arg_fixable.rs index 65152abbe7b82..097d51e9481c5 100644 --- a/tests/ui/unit_arg_fixable.rs +++ b/tests/ui/unit_arg_fixable.rs @@ -34,4 +34,31 @@ fn issue14857() { let fn_take_unit = |_: ()| {}; fn_take_unit(Default::default()); //~^ unit_arg + + fn some_other_fn(_: &i32) {} + + macro_rules! another_mac { + () => { + some_other_fn(&Default::default()) + }; + ($e:expr) => { + some_other_fn(&$e) + }; + } + + fn_take_unit(another_mac!()); + //~^ unit_arg + fn_take_unit(another_mac!(1)); + //~^ unit_arg + + macro_rules! mac { + (nondef $e:expr) => { + $e + }; + (empty_block) => {{}}; + } + fn_take_unit(mac!(nondef Default::default())); + //~^ unit_arg + fn_take_unit(mac!(empty_block)); + //~^ unit_arg } diff --git a/tests/ui/unit_arg_fixable.stderr b/tests/ui/unit_arg_fixable.stderr index 79afe67e57247..94063f02a3f15 100644 --- a/tests/ui/unit_arg_fixable.stderr +++ b/tests/ui/unit_arg_fixable.stderr @@ -50,5 +50,49 @@ LL | fn_take_unit(Default::default()); | | | help: use a unit literal instead: `()` -error: aborting due to 5 previous errors +error: passing a unit value to a function + --> tests/ui/unit_arg_fixable.rs:49:5 + | +LL | fn_take_unit(another_mac!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: move the expression in front of the call and replace it with the unit literal `()` + | +LL ~ another_mac!(); +LL ~ fn_take_unit(()); + | + +error: passing a unit value to a function + --> tests/ui/unit_arg_fixable.rs:51:5 + | +LL | fn_take_unit(another_mac!(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: move the expression in front of the call and replace it with the unit literal `()` + | +LL ~ another_mac!(1); +LL ~ fn_take_unit(()); + | + +error: passing a unit value to a function + --> tests/ui/unit_arg_fixable.rs:60:5 + | +LL | fn_take_unit(mac!(nondef Default::default())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^------------------^^ + | | + | help: use a unit literal instead: `()` + +error: passing a unit value to a function + --> tests/ui/unit_arg_fixable.rs:62:5 + | +LL | fn_take_unit(mac!(empty_block)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: move the expression in front of the call and replace it with the unit literal `()` + | +LL ~ mac!(empty_block); +LL ~ fn_take_unit(()); + | + +error: aborting due to 9 previous errors From 72386693b16aef949c9bc2fb96fb78c9ce91093c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 24 May 2025 15:06:08 +0200 Subject: [PATCH 2710/4206] intrinsics: reduce references to LLVM and update notes on where the implementations live --- library/core/src/intrinsics/mod.rs | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 23bafa778bc6b..439c8c1f9a1e6 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -1,7 +1,10 @@ //! Compiler intrinsics. //! -//! The corresponding definitions are in . -//! The corresponding const implementations are in . +//! These are the imports making intrinsics available to Rust code. The actual implementations live in the compiler. +//! Some of these intrinsics are lowered to MIR in . +//! The remaining intrinsics are implemented for the LLVM backend in +//! and , +//! and for const evaluation in . //! //! # Const intrinsics //! @@ -20,28 +23,14 @@ //! //! The volatile intrinsics provide operations intended to act on I/O //! memory, which are guaranteed to not be reordered by the compiler -//! across other volatile intrinsics. See the LLVM documentation on -//! [[volatile]]. -//! -//! [volatile]: https://llvm.org/docs/LangRef.html#volatile-memory-accesses +//! across other volatile intrinsics. See [`read_volatile`][ptr::read_volatile] +//! and [`write_volatile`][ptr::write_volatile]. //! //! # Atomics //! //! The atomic intrinsics provide common atomic operations on machine -//! words, with multiple possible memory orderings. They obey the same -//! semantics as C++11. See the LLVM documentation on [[atomics]]. -//! -//! [atomics]: https://llvm.org/docs/Atomics.html -//! -//! A quick refresher on memory ordering: -//! -//! * Acquire - a barrier for acquiring a lock. Subsequent reads and writes -//! take place after the barrier. -//! * Release - a barrier for releasing a lock. Preceding reads and writes -//! take place before the barrier. -//! * Sequentially consistent - sequentially consistent operations are -//! guaranteed to happen in order. This is the standard mode for working -//! with atomic types and is equivalent to Java's `volatile`. +//! words, with multiple possible memory orderings. See the +//! [atomic types][crate::sync::atomic] docs for details. //! //! # Unwinding //! From ff3341434def8b34e8027411c6b100a621b42085 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 24 May 2025 16:13:10 +0200 Subject: [PATCH 2711/4206] ScalarInt: support conversion with signed int types and cmp::Ordering --- .../rustc_const_eval/src/interpret/operand.rs | 2 +- .../rustc_middle/src/mir/interpret/value.rs | 10 ++-- compiler/rustc_middle/src/ty/consts/int.rs | 47 ++++++++++++++++++- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 36da9037e43d9..39755169e6cae 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -310,7 +310,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { let ty = tcx.ty_ordering_enum(None); let layout = tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)).unwrap(); - Self::from_scalar(Scalar::from_i8(c as i8), layout) + Self::from_scalar(Scalar::Int(c.into()), layout) } pub fn from_pair(a: Self, b: Self, cx: &(impl HasTypingEnv<'tcx> + HasTyCtxt<'tcx>)) -> Self { diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 9d462093b9ea1..7ba0e5b5e07e5 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -180,27 +180,27 @@ impl Scalar { #[inline] pub fn from_i8(i: i8) -> Self { - Self::from_int(i, Size::from_bits(8)) + Self::Int(i.into()) } #[inline] pub fn from_i16(i: i16) -> Self { - Self::from_int(i, Size::from_bits(16)) + Self::Int(i.into()) } #[inline] pub fn from_i32(i: i32) -> Self { - Self::from_int(i, Size::from_bits(32)) + Self::Int(i.into()) } #[inline] pub fn from_i64(i: i64) -> Self { - Self::from_int(i, Size::from_bits(64)) + Self::Int(i.into()) } #[inline] pub fn from_i128(i: i128) -> Self { - Self::from_int(i, Size::from_bits(128)) + Self::Int(i.into()) } #[inline] diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index 9f5e31d894cb3..9c9cd6953392a 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -422,9 +422,9 @@ macro_rules! from_scalar_int_for_x { impl From for $ty { #[inline] fn from(int: ScalarInt) -> Self { - // The `unwrap` cannot fail because to_bits (if it succeeds) + // The `unwrap` cannot fail because to_uint (if it succeeds) // is guaranteed to return a value that fits into the size. - int.to_bits(Size::from_bytes(size_of::<$ty>())) + int.to_uint(Size::from_bytes(size_of::<$ty>())) .try_into().unwrap() } } @@ -450,6 +450,49 @@ impl From for ScalarInt { } } +macro_rules! from_x_for_scalar_int_signed { + ($($ty:ty),*) => { + $( + impl From<$ty> for ScalarInt { + #[inline] + fn from(u: $ty) -> Self { + Self { + data: u128::from(u.cast_unsigned()), // go via the unsigned type of the same size + size: NonZero::new(size_of::<$ty>() as u8).unwrap(), + } + } + } + )* + } +} + +macro_rules! from_scalar_int_for_x_signed { + ($($ty:ty),*) => { + $( + impl From for $ty { + #[inline] + fn from(int: ScalarInt) -> Self { + // The `unwrap` cannot fail because to_int (if it succeeds) + // is guaranteed to return a value that fits into the size. + int.to_int(Size::from_bytes(size_of::<$ty>())) + .try_into().unwrap() + } + } + )* + } +} + +from_x_for_scalar_int_signed!(i8, i16, i32, i64, i128); +from_scalar_int_for_x_signed!(i8, i16, i32, i64, i128); + +impl From for ScalarInt { + #[inline] + fn from(c: std::cmp::Ordering) -> Self { + // Here we rely on `Ordering` having the same values in host and target! + ScalarInt::from(c as i8) + } +} + /// Error returned when a conversion from ScalarInt to char fails. #[derive(Debug)] pub struct CharTryFromScalarInt; From 1827bc0f39024c18e810feb42d203d68d8111a7c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 24 May 2025 15:42:07 +0200 Subject: [PATCH 2712/4206] rename internal panicking::try to catch_unwind --- library/std/src/panic.rs | 2 +- library/std/src/panicking.rs | 8 ++++---- src/tools/miri/src/shims/panic.rs | 10 +++++----- src/tools/miri/tests/fail/panic/bad_unwind.stderr | 4 ++-- .../miri/tests/fail/tail_calls/cc-mismatch.stderr | 8 ++++---- .../miri/tests/pass/backtrace/backtrace-api-v1.stderr | 8 ++++---- .../tests/pass/backtrace/backtrace-global-alloc.stderr | 8 ++++---- .../miri/tests/pass/backtrace/backtrace-std.stderr | 8 ++++---- 8 files changed, 28 insertions(+), 28 deletions(-) diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index f3b26ac64dfa3..234fb284a5904 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -356,7 +356,7 @@ pub use core::panic::abort_unwind; /// ``` #[stable(feature = "catch_unwind", since = "1.9.0")] pub fn catch_unwind R + UnwindSafe, R>(f: F) -> Result { - unsafe { panicking::r#try(f) } + unsafe { panicking::catch_unwind(f) } } /// Triggers a panic without invoking the panic hook. diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 4bfedf78366e7..7873049d20bfd 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -499,13 +499,13 @@ pub use realstd::rt::panic_count; /// Invoke a closure, capturing the cause of an unwinding panic if one occurs. #[cfg(feature = "panic_immediate_abort")] -pub unsafe fn r#try R>(f: F) -> Result> { +pub unsafe fn catch_unwind R>(f: F) -> Result> { Ok(f()) } /// Invoke a closure, capturing the cause of an unwinding panic if one occurs. #[cfg(not(feature = "panic_immediate_abort"))] -pub unsafe fn r#try R>(f: F) -> Result> { +pub unsafe fn catch_unwind R>(f: F) -> Result> { union Data { f: ManuallyDrop, r: ManuallyDrop, @@ -541,7 +541,7 @@ pub unsafe fn r#try R>(f: F) -> Result> let data_ptr = (&raw mut data) as *mut u8; // SAFETY: // - // Access to the union's fields: this is `std` and we know that the `r#try` + // Access to the union's fields: this is `std` and we know that the `catch_unwind` // intrinsic fills in the `r` or `p` union field based on its return value. // // The call to `intrinsics::catch_unwind` is made safe by: @@ -602,7 +602,7 @@ pub unsafe fn r#try R>(f: F) -> Result> // This function cannot be marked as `unsafe` because `intrinsics::catch_unwind` // expects normal function pointers. #[inline] - #[rustc_nounwind] // `intrinsic::r#try` requires catch fn to be nounwind + #[rustc_nounwind] // `intrinsic::catch_unwind` requires catch fn to be nounwind fn do_catch R, R>(data: *mut u8, payload: *mut u8) { // SAFETY: this is the responsibility of the caller, see above. // diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs index b5ed5ea837b3d..549d859a6e1e8 100644 --- a/src/tools/miri/src/shims/panic.rs +++ b/src/tools/miri/src/shims/panic.rs @@ -56,7 +56,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(()) } - /// Handles the `try` intrinsic, the underlying implementation of `std::panicking::try`. + /// Handles the `catch_unwind` intrinsic. fn handle_catch_unwind( &mut self, args: &[OpTy<'tcx>], @@ -66,7 +66,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); // Signature: - // fn r#try(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32 + // fn catch_unwind(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32 // Calls `try_fn` with `data` as argument. If that executes normally, returns 0. // If that unwinds, calls `catch_fn` with the first argument being `data` and // then second argument being a target-dependent `payload` (i.e. it is up to us to define @@ -120,14 +120,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // We only care about `catch_panic` if we're unwinding - if we're doing a normal // return, then we don't need to do anything special. if let (true, Some(catch_unwind)) = (unwinding, extra.catch_unwind.take()) { - // We've just popped a frame that was pushed by `try`, + // We've just popped a frame that was pushed by `catch_unwind`, // and we are unwinding, so we should catch that. trace!( "unwinding: found catch_panic frame during unwinding: {:?}", this.frame().instance() ); - // We set the return value of `try` to 1, since there was a panic. + // We set the return value of `catch_unwind` to 1, since there was a panic. this.write_scalar(Scalar::from_i32(1), &catch_unwind.dest)?; // The Thread's `panic_payload` holds what was passed to `miri_start_unwind`. @@ -142,7 +142,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ExternAbi::Rust, &[catch_unwind.data, payload], None, - // Directly return to caller of `try`. + // Directly return to caller of `catch_unwind`. StackPopCleanup::Goto { ret: catch_unwind.ret, // `catch_fn` must not unwind. diff --git a/src/tools/miri/tests/fail/panic/bad_unwind.stderr b/src/tools/miri/tests/fail/panic/bad_unwind.stderr index 6ba39e8f7e232..8c269eae62a7e 100644 --- a/src/tools/miri/tests/fail/panic/bad_unwind.stderr +++ b/src/tools/miri/tests/fail/panic/bad_unwind.stderr @@ -13,8 +13,8 @@ LL | std::panic::catch_unwind(|| unwind()).unwrap_err(); = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: = note: inside closure at tests/fail/panic/bad_unwind.rs:LL:CC - = note: inside `std::panicking::r#try::do_call::<{closure@tests/fail/panic/bad_unwind.rs:LL:CC}, ()>` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::panicking::r#try::<(), {closure@tests/fail/panic/bad_unwind.rs:LL:CC}>` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panicking::catch_unwind::do_call::<{closure@tests/fail/panic/bad_unwind.rs:LL:CC}, ()>` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panicking::catch_unwind::<(), {closure@tests/fail/panic/bad_unwind.rs:LL:CC}>` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::panic::catch_unwind::<{closure@tests/fail/panic/bad_unwind.rs:LL:CC}, ()>` at RUSTLIB/std/src/panic.rs:LL:CC note: inside `main` --> tests/fail/panic/bad_unwind.rs:LL:CC diff --git a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr index 61ddea644720f..589e30d632e20 100644 --- a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr +++ b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr @@ -11,12 +11,12 @@ LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; = note: inside `std::sys::backtrace::__rust_begin_short_backtrace::` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC = note: inside `std::ops::function::impls:: for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once` at RUSTLIB/core/src/ops/function.rs:LL:CC - = note: inside `std::panicking::r#try::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::panicking::r#try:: i32 + std::marker::Sync + std::panic::RefUnwindSafe>` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panicking::catch_unwind::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panicking::catch_unwind:: i32 + std::marker::Sync + std::panic::RefUnwindSafe>` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at RUSTLIB/std/src/panic.rs:LL:CC = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC - = note: inside `std::panicking::r#try::do_call::<{closure@std::rt::lang_start_internal::{closure#0}}, isize>` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::panicking::r#try::` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panicking::catch_unwind::do_call::<{closure@std::rt::lang_start_internal::{closure#0}}, isize>` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panicking::catch_unwind::` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::panic::catch_unwind::<{closure@std::rt::lang_start_internal::{closure#0}}, isize>` at RUSTLIB/std/src/panic.rs:LL:CC = note: inside `std::rt::lang_start_internal` at RUSTLIB/std/src/rt.rs:LL:CC = note: inside `std::rt::lang_start::<()>` at RUSTLIB/std/src/rt.rs:LL:CC diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr index 1ee5298f17d63..8e167dbadef6c 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr +++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr @@ -7,12 +7,12 @@ RUSTLIB/core/src/ops/function.rs:LL:CC (>::call_onc RUSTLIB/std/src/sys/backtrace.rs:LL:CC (std::sys::backtrace::__rust_begin_short_backtrace) RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start::{closure#0}) RUSTLIB/core/src/ops/function.rs:LL:CC (std::ops::function::impls::call_once) -RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) -RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try) +RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::catch_unwind::do_call) +RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::catch_unwind) RUSTLIB/std/src/panic.rs:LL:CC (std::panic::catch_unwind) RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start_internal::{closure#0}) -RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) -RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try) +RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::catch_unwind::do_call) +RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::catch_unwind) RUSTLIB/std/src/panic.rs:LL:CC (std::panic::catch_unwind) RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start_internal) RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start) diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr index 26cdee18e3c23..588bb85f35a4f 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr +++ b/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr @@ -8,17 +8,17 @@ at RUSTLIB/std/src/rt.rs:LL:CC 4: std::ops::function::impls::call_once at RUSTLIB/core/src/ops/function.rs:LL:CC - 5: std::panicking::r#try::do_call + 5: std::panicking::catch_unwind::do_call at RUSTLIB/std/src/panicking.rs:LL:CC - 6: std::panicking::r#try + 6: std::panicking::catch_unwind at RUSTLIB/std/src/panicking.rs:LL:CC 7: std::panic::catch_unwind at RUSTLIB/std/src/panic.rs:LL:CC 8: std::rt::lang_start_internal::{closure#0} at RUSTLIB/std/src/rt.rs:LL:CC - 9: std::panicking::r#try::do_call + 9: std::panicking::catch_unwind::do_call at RUSTLIB/std/src/panicking.rs:LL:CC - 10: std::panicking::r#try + 10: std::panicking::catch_unwind at RUSTLIB/std/src/panicking.rs:LL:CC 11: std::panic::catch_unwind at RUSTLIB/std/src/panic.rs:LL:CC diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr index d89ae3837b981..9c952755957b1 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr +++ b/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr @@ -16,17 +16,17 @@ at RUSTLIB/std/src/rt.rs:LL:CC 8: std::ops::function::impls::call_once at RUSTLIB/core/src/ops/function.rs:LL:CC - 9: std::panicking::r#try::do_call + 9: std::panicking::catch_unwind::do_call at RUSTLIB/std/src/panicking.rs:LL:CC - 10: std::panicking::r#try + 10: std::panicking::catch_unwind at RUSTLIB/std/src/panicking.rs:LL:CC 11: std::panic::catch_unwind at RUSTLIB/std/src/panic.rs:LL:CC 12: std::rt::lang_start_internal::{closure#0} at RUSTLIB/std/src/rt.rs:LL:CC - 13: std::panicking::r#try::do_call + 13: std::panicking::catch_unwind::do_call at RUSTLIB/std/src/panicking.rs:LL:CC - 14: std::panicking::r#try + 14: std::panicking::catch_unwind at RUSTLIB/std/src/panicking.rs:LL:CC 15: std::panic::catch_unwind at RUSTLIB/std/src/panic.rs:LL:CC From dd6d5e2b103c6c1424026e41984dc4d106c499f3 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Thu, 22 May 2025 19:02:12 -0400 Subject: [PATCH 2713/4206] Fix f128 intrinsics --- build_system/src/test.rs | 2 +- src/builder.rs | 19 +++++-- src/common.rs | 5 +- src/intrinsic/mod.rs | 108 +++++++++++++++++++++++++++++++++++---- 4 files changed, 116 insertions(+), 18 deletions(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index df4ac85233b02..df46bd1259f89 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -680,7 +680,7 @@ fn test_libcore(env: &Env, args: &TestArg) -> Result<(), String> { println!("[TEST] libcore"); let path = get_sysroot_dir().join("sysroot_src/library/coretests"); let _ = remove_dir_all(path.join("target")); - run_cargo_command(&[&"test"], Some(&path), env, args)?; + run_cargo_command(&[&"test", &"--release"], Some(&path), env, args)?; Ok(()) } diff --git a/src/builder.rs b/src/builder.rs index f54a1a941ea83..c7900ebcd6f46 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -4,8 +4,8 @@ use std::convert::TryFrom; use std::ops::Deref; use gccjit::{ - BinaryOp, Block, ComparisonOp, Context, Function, LValue, Location, RValue, ToRValue, Type, - UnaryOp, + BinaryOp, Block, ComparisonOp, Context, Function, FunctionType, LValue, Location, RValue, + ToRValue, Type, UnaryOp, }; use rustc_abi as abi; use rustc_abi::{Align, HasDataLayout, Size, TargetDataLayout, WrappingRange}; @@ -782,8 +782,19 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { return self.context.new_call(self.location, fmod, &[a, b]); } TypeKind::FP128 => { - let fmodl = self.context.get_builtin_function("fmodl"); - return self.context.new_call(self.location, fmodl, &[a, b]); + let f128_type = self.type_f128(); + let fmodf128 = self.context.new_function( + None, + FunctionType::Extern, + f128_type, + &[ + self.context.new_parameter(None, f128_type, "a"), + self.context.new_parameter(None, f128_type, "b"), + ], + "fmodf128", + false, + ); + return self.context.new_call(self.location, fmodf128, &[a, b]); } _ => (), } diff --git a/src/common.rs b/src/common.rs index cfa951ddf4b70..65f4788d90212 100644 --- a/src/common.rs +++ b/src/common.rs @@ -237,14 +237,15 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { // FIXME(antoyo): there's some issues with using the u128 code that follows, so hard-code // the paths for floating-point values. - if ty == self.float_type { + // TODO: Remove this code? + /*if ty == self.float_type { return self .context .new_rvalue_from_double(ty, f32::from_bits(data as u32) as f64); } if ty == self.double_type { return self.context.new_rvalue_from_double(ty, f64::from_bits(data as u64)); - } + }*/ let value = self.const_uint_big(self.type_ix(bitsize), data); let bytesize = layout.size(self).bytes(); diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index 8402d0c6fcf84..acecab35d7243 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -45,10 +45,8 @@ fn get_simple_intrinsic<'gcc, 'tcx>( let gcc_name = match name { sym::sqrtf32 => "sqrtf", sym::sqrtf64 => "sqrt", - sym::sqrtf128 => "sqrtl", sym::powif32 => "__builtin_powif", sym::powif64 => "__builtin_powi", - sym::powif128 => "__builtin_powil", sym::sinf32 => "sinf", sym::sinf64 => "sin", sym::cosf32 => "cosf", @@ -67,7 +65,6 @@ fn get_simple_intrinsic<'gcc, 'tcx>( sym::log2f64 => "log2", sym::fmaf32 => "fmaf", sym::fmaf64 => "fma", - sym::fmaf128 => "fmal", // FIXME: calling `fma` from libc without FMA target feature uses expensive software emulation sym::fmuladdf32 => "fmaf", // TODO: use gcc intrinsic analogous to llvm.fmuladd.f32 sym::fmuladdf64 => "fma", // TODO: use gcc intrinsic analogous to llvm.fmuladd.f64 @@ -75,29 +72,22 @@ fn get_simple_intrinsic<'gcc, 'tcx>( sym::fabsf64 => "fabs", sym::minnumf32 => "fminf", sym::minnumf64 => "fmin", - sym::minnumf128 => "fminl", sym::maxnumf32 => "fmaxf", sym::maxnumf64 => "fmax", - sym::maxnumf128 => "fmaxl", sym::copysignf32 => "copysignf", sym::copysignf64 => "copysign", sym::copysignf128 => "copysignl", sym::floorf32 => "floorf", sym::floorf64 => "floor", - sym::floorf128 => "floorl", sym::ceilf32 => "ceilf", sym::ceilf64 => "ceil", - sym::ceilf128 => "ceill", sym::truncf32 => "truncf", sym::truncf64 => "trunc", - sym::truncf128 => "truncl", // We match the LLVM backend and lower this to `rint`. sym::round_ties_even_f32 => "rintf", sym::round_ties_even_f64 => "rint", - sym::round_ties_even_f128 => "rintl", sym::roundf32 => "roundf", sym::roundf64 => "round", - sym::roundf128 => "roundl", sym::abort => "abort", _ => return None, }; @@ -170,6 +160,61 @@ fn get_simple_function<'gcc, 'tcx>( )) } +fn get_simple_function_f128<'gcc, 'tcx>( + cx: &CodegenCx<'gcc, 'tcx>, + name: Symbol, +) -> Option> { + if !cx.supports_f128_type { + return None; + } + + let f128_type = cx.type_f128(); + let func_name = match name { + sym::ceilf128 => "ceilf128", + sym::floorf128 => "floorf128", + sym::truncf128 => "truncf128", + sym::roundf128 => "roundf128", + sym::round_ties_even_f128 => "roundevenf128", + sym::sqrtf128 => "sqrtf128", + _ => return None, + }; + Some(cx.context.new_function( + None, + FunctionType::Extern, + f128_type, + &[cx.context.new_parameter(None, f128_type, "a")], + func_name, + false, + )) +} + +fn get_simple_function_f128_2args<'gcc, 'tcx>( + cx: &CodegenCx<'gcc, 'tcx>, + name: Symbol, +) -> Option> { + if !cx.supports_f128_type { + return None; + } + + let f128_type = cx.type_f128(); + let func_name = match name { + sym::maxnumf128 => "fmaxf128", + sym::minnumf128 => "fminf128", + _ => return None, + }; + Some(cx.context.new_function( + None, + FunctionType::Extern, + f128_type, + &[ + cx.context.new_parameter(None, f128_type, "a"), + cx.context.new_parameter(None, f128_type, "b"), + ], + func_name, + false, + )) +} + fn f16_builtin<'gcc, 'tcx>( cx: &CodegenCx<'gcc, 'tcx>, name: Symbol, @@ -232,7 +277,9 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); let simple = get_simple_intrinsic(self, name); - let simple_func = get_simple_function(self, name); + let simple_func = get_simple_function(self, name) + .or_else(|| get_simple_function_f128(self, name)) + .or_else(|| get_simple_function_f128_2args(self, name)); // FIXME(tempdragon): Re-enable `clippy::suspicious_else_formatting` if the following issue is solved: // https://github.com/rust-lang/rust-clippy/issues/12497 @@ -266,6 +313,45 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc | sym::round_ties_even_f16 | sym::sqrtf16 | sym::truncf16 => f16_builtin(self, name, args), + sym::fmaf128 => { + let f128_type = self.cx.type_f128(); + let func = self.cx.context.new_function( + None, + FunctionType::Extern, + f128_type, + &[ + self.cx.context.new_parameter(None, f128_type, "a"), + self.cx.context.new_parameter(None, f128_type, "b"), + self.cx.context.new_parameter(None, f128_type, "c"), + ], + "fmaf128", + false, + ); + self.cx.context.new_call( + self.location, + func, + &args.iter().map(|arg| arg.immediate()).collect::>(), + ) + } + sym::powif128 => { + let f128_type = self.cx.type_f128(); + let func = self.cx.context.new_function( + None, + FunctionType::Extern, + f128_type, + &[ + self.cx.context.new_parameter(None, f128_type, "a"), + self.cx.context.new_parameter(None, self.int_type, "b"), + ], + "__powitf2", + false, + ); + self.cx.context.new_call( + self.location, + func, + &args.iter().map(|arg| arg.immediate()).collect::>(), + ) + } sym::is_val_statically_known => { let a = args[0].immediate(); let builtin = self.context.get_builtin_function("__builtin_constant_p"); From e3adf1428b6c50303dfaa79e2ca724ff7a226b78 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Sat, 24 May 2025 15:27:31 +0000 Subject: [PATCH 2714/4206] Remove compiletest headers test --- tests/headers.rs | 34 ---------------------------------- 1 file changed, 34 deletions(-) delete mode 100644 tests/headers.rs diff --git a/tests/headers.rs b/tests/headers.rs deleted file mode 100644 index d1f986ef52632..0000000000000 --- a/tests/headers.rs +++ /dev/null @@ -1,34 +0,0 @@ -use regex::Regex; -use std::fs; -use walkdir::WalkDir; - -#[test] -fn old_test_headers() { - let old_headers = Regex::new( - r"^//( ?\[\w+\])? ?((check|build|run|ignore|aux|only|needs|rustc|unset|no|normalize|run|compile)-|edition|incremental|revisions).*", - ) - .unwrap(); - let mut failed = false; - - for entry in WalkDir::new("tests") { - let entry = entry.unwrap(); - let is_hidden_file = entry - .file_name() - .to_str() - .expect("non-UTF-8 file name") - .starts_with('.'); - if is_hidden_file || !entry.file_type().is_file() { - continue; - } - - let file = fs::read_to_string(entry.path()).unwrap_or_else(|err| panic!("{}: {err}", entry.path().display())); - - if let Some(header) = old_headers.find(&file) { - println!("Found header `{}` in {}", header.as_str(), entry.path().display()); - - failed = true; - } - } - - assert!(!failed, "use `//@foo` style test headers instead"); -} From f1d5cfea44007f2312c24442dff95951a7d51aff Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 24 May 2025 11:05:51 -0400 Subject: [PATCH 2715/4206] Skip the core test f16::test_total_cmp because it fails in debug mode even with cg_llvm --- build_system/src/test.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index df46bd1259f89..5ad75384e5eae 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -680,7 +680,15 @@ fn test_libcore(env: &Env, args: &TestArg) -> Result<(), String> { println!("[TEST] libcore"); let path = get_sysroot_dir().join("sysroot_src/library/coretests"); let _ = remove_dir_all(path.join("target")); - run_cargo_command(&[&"test", &"--release"], Some(&path), env, args)?; + // TODO(antoyo): run in release mode when we fix the failures. + // TODO(antoyo): remove the --skip f16::test_total_cmp when this issue is fixed: + // https://github.com/rust-lang/rust/issues/141503 + run_cargo_command( + &[&"test", &"--", &"--skip", &"f16::test_total_cmp"], + Some(&path), + env, + args, + )?; Ok(()) } From d0582aacc1442012717632c179f0bff522a11802 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Sat, 24 May 2025 19:16:01 +0200 Subject: [PATCH 2716/4206] Update `rustc_on_unimplemented` docs --- src/doc/rustc-dev-guide/src/diagnostics.md | 162 +++++++++++++-------- 1 file changed, 101 insertions(+), 61 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/diagnostics.md b/src/doc/rustc-dev-guide/src/diagnostics.md index 2f8f4b0ab8a0c..01e59c91904dd 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics.md +++ b/src/doc/rustc-dev-guide/src/diagnostics.md @@ -866,19 +866,17 @@ struct](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/json/struct (and sub-structs) for the JSON serialization. Don't confuse this with [`errors::Diag`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.Diag.html)! -## `#[rustc_on_unimplemented(...)]` +## `#[rustc_on_unimplemented]` -The `#[rustc_on_unimplemented]` attribute allows trait definitions to add specialized -notes to error messages when an implementation was expected but not found. -You can refer to the trait's generic arguments by name and to the resolved type using `Self`. - -For example: +This attribute allows trait definitions to modify error messages when an implementation was +expected but not found. The string literals in the attribute are format strings and can be +formatted with named parameters. See the Formatting +section below for what parameters are permitted. ```rust,ignore -#![feature(rustc_attrs)] - -#[rustc_on_unimplemented="an iterator over elements of type `{A}` \ - cannot be built from a collection of type `{Self}`"] +#[rustc_on_unimplemented(message = "an iterator over \ + elements of type `{A}` cannot be built from a \ + collection of type `{Self}`")] trait MyIterator { fn next(&mut self) -> A; } @@ -895,32 +893,26 @@ fn main() { When the user compiles this, they will see the following; ```txt -error[E0277]: the trait bound `&[{integer}]: MyIterator` is not satisfied - --> :14:5 +error[E0277]: an iterator over elements of type `char` cannot be built from a collection of type `&[{integer}]` + --> src/main.rs:13:19 | -14 | iterate_chars(&[1, 2, 3][..]); - | ^^^^^^^^^^^^^ an iterator over elements of type `char` cannot be built from a collection of type `&[{integer}]` +13 | iterate_chars(&[1, 2, 3][..]); + | ------------- ^^^^^^^^^^^^^^ the trait `MyIterator` is not implemented for `&[{integer}]` + | | + | required by a bound introduced by this call | - = help: the trait `MyIterator` is not implemented for `&[{integer}]` - = note: required by `iterate_chars` +note: required by a bound in `iterate_chars` ``` -`rustc_on_unimplemented` also supports advanced filtering for better targeting -of messages, as well as modifying specific parts of the error message. You -target the text of: - +You can modify the contents of: - the main error message (`message`) - the label (`label`) - - an extra note (`note`) + - the note(s) (`note`) For example, the following attribute ```rust,ignore -#[rustc_on_unimplemented( - message="message", - label="label", - note="note" -)] +#[rustc_on_unimplemented(message = "message", label = "label", note = "note")] trait MyIterator { fn next(&mut self) -> A; } @@ -930,45 +922,61 @@ Would generate the following output: ```text error[E0277]: message - --> :14:5 + --> :10:19 | -14 | iterate_chars(&[1, 2, 3][..]); - | ^^^^^^^^^^^^^ label +10 | iterate_chars(&[1, 2, 3][..]); + | ------------- ^^^^^^^^^^^^^^ label + | | + | required by a bound introduced by this call | - = note: note = help: the trait `MyIterator` is not implemented for `&[{integer}]` - = note: required by `iterate_chars` + = note: note +note: required by a bound in `iterate_chars` ``` +The functionality discussed so far is also available with +[`#[diagnostic::on_unimplemented]`](https://doc.rust-lang.org/nightly/reference/attributes/diagnostics.html#the-diagnosticon_unimplemented-attribute). +If you can, you should use that instead. + +### Filtering + To allow more targeted error messages, it is possible to filter the -application of these fields based on a variety of attributes when using -`on`: +application of these fields with `on`. +You can filter on the following boolean flags: - `crate_local`: whether the code causing the trait bound to not be fulfilled is part of the user's crate. This is used to avoid suggesting code changes that would require modifying a dependency. - - Any of the generic arguments that can be substituted in the text can be - referred by name as well for filtering, like `Rhs="i32"`, except for - `Self`. - - `_Self`: to filter only on a particular calculated trait resolution, like - `Self="std::iter::Iterator"`. This is needed because `Self` is a - keyword which cannot appear in attributes. - - `direct`: user-specified rather than derived obligation. - - `from_desugaring`: usable both as boolean (whether the flag is present) - or matching against a particular desugaring. The desugaring is identified - with its variant name in the `DesugaringKind` enum. - -For example, the `Iterator` trait can be annotated in the following way: + - `direct`: whether this is an user-specified rather than derived obligation. + - `from_desugaring`: whether we are in some kind of desugaring, like `?` + or a `try` block for example. This flag can also be matched on, see below. + +You can match on the following names and values, using `name = "value"`: + - `cause`: Match against one variant of the `ObligationCauseCode` + enum. Only `"MainFunctionType"` is supported. + - `from_desugaring`: Match against a particular variant of the `DesugaringKind` + enum. The desugaring is identified by its variant name, for example + `"QuestionMark"` for `?` desugaring or `"TryBlock"` for `try` blocks. + - `Self` and any generic arguments of the trait, like `Self = "alloc::string::String"` + or `Rhs="i32"`. + +The compiler can provide several values to match on, for example: + - the self_ty, pretty printed with and without type arguments resolved. + - `"{integral}"`, if self_ty is an integral of which the type is known. + - `"[]"`, `"[{ty}]"`, `"[{ty}; _]"`, `"[{ty}; $N]"` when applicable. + - references to said slices and arrays. + - `"fn"`, `"unsafe fn"` or `"#[target_feature] fn"` when self is a function. + - `"{integer}"` and `"{float}"` if the type is a number but we haven't inferred it yet. + - combinations of the above, like `"[{integral}; _]"`. + +For example, the `Iterator` trait can be filtered in the following way: ```rust,ignore #[rustc_on_unimplemented( - on( - _Self="&str", - note="call `.chars()` or `.as_bytes()` on `{Self}`" - ), - message="`{Self}` is not an iterator", - label="`{Self}` is not an iterator", - note="maybe try calling `.iter()` or a similar method" + on(Self = "&str", note = "call `.chars()` or `.as_bytes()` on `{Self}`"), + message = "`{Self}` is not an iterator", + label = "`{Self}` is not an iterator", + note = "maybe try calling `.iter()` or a similar method" )] pub trait Iterator {} ``` @@ -997,15 +1005,47 @@ error[E0277]: `&str` is not an iterator = note: required by `std::iter::IntoIterator::into_iter` ``` -If you need to filter on multiple attributes, you can use `all`, `any` or -`not` in the following way: +The `on` filter accepts `all`, `any` and `not` predicates similar to the `cfg` attribute: ```rust,ignore -#[rustc_on_unimplemented( - on( - all(_Self="&str", T="std::string::String"), - note="you can coerce a `{T}` into a `{Self}` by writing `&*variable`" - ) -)] -pub trait From: Sized { /* ... */ } +#[rustc_on_unimplemented(on( + all(Self = "&str", T = "alloc::string::String"), + note = "you can coerce a `{T}` into a `{Self}` by writing `&*variable`" +))] +pub trait From: Sized { + /* ... */ +} +``` + +### Formatting + +The string literals are format strings that accept parameters wrapped in braces +but positional and listed parameters and format specifiers are not accepted. +The following parameter names are valid: +- `Self` and all generic parameters of the trait. +- `This`: the name of the trait the attribute is on, without generics. +- `Trait`: the name of the "sugared" trait. See `TraitRefPrintSugared`. +- `ItemContext`: the kind of `hir::Node` we're in, things like `"an async block"`, + `"a function"`, `"an async function"`, etc. + +Something like: + +```rust,ignore +#![feature(rustc_attrs)] + +#[rustc_on_unimplemented(message = "Self = `{Self}`, \ + T = `{T}`, this = `{This}`, trait = `{Trait}`, \ + context = `{ItemContext}`")] +pub trait From: Sized { + fn from(x: T) -> Self; +} + +fn main() { + let x: i8 = From::from(42_i32); +} +``` + +Will format the message into +```text +"Self = `i8`, T = `i32`, this = `From`, trait = `From`, context = `a function`" ``` From 03af37302c09ad11024929186a7718f4dc87f5cc Mon Sep 17 00:00:00 2001 From: yanglsh Date: Sun, 25 May 2025 02:02:11 +0800 Subject: [PATCH 2717/4206] fix: `assign_op_pattern` FP on unstable const trait --- .../src/operators/assign_op_pattern.rs | 14 ++++++++- clippy_lints/src/operators/mod.rs | 2 +- clippy_utils/src/qualify_min_const_fn.rs | 3 +- tests/ui/assign_ops.fixed | 31 +++++++++++++++++++ tests/ui/assign_ops.rs | 31 +++++++++++++++++++ tests/ui/assign_ops.stderr | 24 +++++++------- 6 files changed, 90 insertions(+), 15 deletions(-) diff --git a/clippy_lints/src/operators/assign_op_pattern.rs b/clippy_lints/src/operators/assign_op_pattern.rs index 4be42267b14b3..9c6141d822263 100644 --- a/clippy_lints/src/operators/assign_op_pattern.rs +++ b/clippy_lints/src/operators/assign_op_pattern.rs @@ -1,8 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::Msrv; +use clippy_utils::qualify_min_const_fn::is_stable_const_fn; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::implements_trait; use clippy_utils::visitors::for_each_expr_without_closures; -use clippy_utils::{binop_traits, eq_expr_value, trait_ref_of_method}; +use clippy_utils::{binop_traits, eq_expr_value, is_in_const_context, trait_ref_of_method}; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir as hir; @@ -19,6 +21,7 @@ pub(super) fn check<'tcx>( expr: &'tcx hir::Expr<'_>, assignee: &'tcx hir::Expr<'_>, e: &'tcx hir::Expr<'_>, + msrv: Msrv, ) { if let hir::ExprKind::Binary(op, l, r) = &e.kind { let lint = |assignee: &hir::Expr<'_>, rhs: &hir::Expr<'_>| { @@ -40,6 +43,15 @@ pub(super) fn check<'tcx>( return; } } + + // Skip if the trait is not stable in const contexts + if is_in_const_context(cx) + && let Some(binop_id) = cx.tcx.associated_item_def_ids(trait_id).first() + && !is_stable_const_fn(cx, *binop_id, msrv) + { + return; + } + span_lint_and_then( cx, ASSIGN_OP_PATTERN, diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index d32c062cf56a7..2f4e8e9958868 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -919,7 +919,7 @@ impl<'tcx> LateLintPass<'tcx> for Operators { modulo_arithmetic::check(cx, e, bin_op, lhs, rhs, false); }, ExprKind::Assign(lhs, rhs, _) => { - assign_op_pattern::check(cx, e, lhs, rhs); + assign_op_pattern::check(cx, e, lhs, rhs, self.msrv); self_assignment::check(cx, e, lhs, rhs); }, ExprKind::Unary(op, arg) => { diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 45da266fd8a9a..2bf7eb703d4b0 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -393,7 +393,8 @@ fn check_terminator<'tcx>( } } -fn is_stable_const_fn(cx: &LateContext<'_>, def_id: DefId, msrv: Msrv) -> bool { +/// Checks if the given `def_id` is a stable const fn, in respect to the given MSRV. +pub fn is_stable_const_fn(cx: &LateContext<'_>, def_id: DefId, msrv: Msrv) -> bool { cx.tcx.is_const_fn(def_id) && cx .tcx diff --git a/tests/ui/assign_ops.fixed b/tests/ui/assign_ops.fixed index 429c20f95e919..3bc6885d7c3e6 100644 --- a/tests/ui/assign_ops.fixed +++ b/tests/ui/assign_ops.fixed @@ -1,5 +1,6 @@ #![allow(clippy::useless_vec)] #![warn(clippy::assign_op_pattern)] +#![feature(const_trait_impl, const_ops)] use core::num::Wrapping; use std::ops::{Mul, MulAssign}; @@ -73,3 +74,33 @@ impl MulAssign for Wrap { *self = *self * rhs } } + +mod issue14871 { + + use std::ops::{Add, AddAssign}; + + pub trait Number: Copy + Add + AddAssign { + const ZERO: Self; + const ONE: Self; + } + + #[const_trait] + pub trait NumberConstants { + fn constant(value: usize) -> Self; + } + + impl const NumberConstants for T + where + T: Number + ~const core::ops::Add, + { + fn constant(value: usize) -> Self { + let mut res = Self::ZERO; + let mut count = 0; + while count < value { + res = res + Self::ONE; + count += 1; + } + res + } + } +} diff --git a/tests/ui/assign_ops.rs b/tests/ui/assign_ops.rs index 480ff07f150ea..f1f8f9daff95e 100644 --- a/tests/ui/assign_ops.rs +++ b/tests/ui/assign_ops.rs @@ -1,5 +1,6 @@ #![allow(clippy::useless_vec)] #![warn(clippy::assign_op_pattern)] +#![feature(const_trait_impl, const_ops)] use core::num::Wrapping; use std::ops::{Mul, MulAssign}; @@ -73,3 +74,33 @@ impl MulAssign for Wrap { *self = *self * rhs } } + +mod issue14871 { + + use std::ops::{Add, AddAssign}; + + pub trait Number: Copy + Add + AddAssign { + const ZERO: Self; + const ONE: Self; + } + + #[const_trait] + pub trait NumberConstants { + fn constant(value: usize) -> Self; + } + + impl const NumberConstants for T + where + T: Number + ~const core::ops::Add, + { + fn constant(value: usize) -> Self { + let mut res = Self::ZERO; + let mut count = 0; + while count < value { + res = res + Self::ONE; + count += 1; + } + res + } + } +} diff --git a/tests/ui/assign_ops.stderr b/tests/ui/assign_ops.stderr index 881a333fbe4b9..c5e698b3ee118 100644 --- a/tests/ui/assign_ops.stderr +++ b/tests/ui/assign_ops.stderr @@ -1,5 +1,5 @@ error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:9:5 + --> tests/ui/assign_ops.rs:10:5 | LL | a = a + 1; | ^^^^^^^^^ help: replace it with: `a += 1` @@ -8,67 +8,67 @@ LL | a = a + 1; = help: to override `-D warnings` add `#[allow(clippy::assign_op_pattern)]` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:11:5 + --> tests/ui/assign_ops.rs:12:5 | LL | a = 1 + a; | ^^^^^^^^^ help: replace it with: `a += 1` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:13:5 + --> tests/ui/assign_ops.rs:14:5 | LL | a = a - 1; | ^^^^^^^^^ help: replace it with: `a -= 1` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:15:5 + --> tests/ui/assign_ops.rs:16:5 | LL | a = a * 99; | ^^^^^^^^^^ help: replace it with: `a *= 99` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:17:5 + --> tests/ui/assign_ops.rs:18:5 | LL | a = 42 * a; | ^^^^^^^^^^ help: replace it with: `a *= 42` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:19:5 + --> tests/ui/assign_ops.rs:20:5 | LL | a = a / 2; | ^^^^^^^^^ help: replace it with: `a /= 2` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:21:5 + --> tests/ui/assign_ops.rs:22:5 | LL | a = a % 5; | ^^^^^^^^^ help: replace it with: `a %= 5` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:23:5 + --> tests/ui/assign_ops.rs:24:5 | LL | a = a & 1; | ^^^^^^^^^ help: replace it with: `a &= 1` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:30:5 + --> tests/ui/assign_ops.rs:31:5 | LL | s = s + "bla"; | ^^^^^^^^^^^^^ help: replace it with: `s += "bla"` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:35:5 + --> tests/ui/assign_ops.rs:36:5 | LL | a = a + Wrapping(1u32); | ^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a += Wrapping(1u32)` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:38:5 + --> tests/ui/assign_ops.rs:39:5 | LL | v[0] = v[0] + v[1]; | ^^^^^^^^^^^^^^^^^^ help: replace it with: `v[0] += v[1]` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:51:5 + --> tests/ui/assign_ops.rs:52:5 | LL | buf = buf + cows.clone(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `buf += cows.clone()` From 843a45f384f3e285c8c60ac5780b19be88435538 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Sat, 24 May 2025 18:11:35 +0000 Subject: [PATCH 2718/4206] Consider consts in patterns as refutable --- clippy_utils/src/lib.rs | 14 ++++++++------ tests/ui/question_mark.fixed | 10 ++++++++++ tests/ui/question_mark.rs | 10 ++++++++++ 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 3a31917657103..42136fdbc51a8 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1565,10 +1565,10 @@ pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_ /// Returns `true` if a pattern is refutable. // TODO: should be implemented using rustc/mir_build/thir machinery pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { - fn is_enum_variant(cx: &LateContext<'_>, qpath: &QPath<'_>, id: HirId) -> bool { - matches!( + fn is_qpath_refutable(cx: &LateContext<'_>, qpath: &QPath<'_>, id: HirId) -> bool { + !matches!( cx.qpath_res(qpath, id), - Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(def::CtorOf::Variant, _), _) + Res::Def(DefKind::Struct, ..) | Res::Def(DefKind::Ctor(def::CtorOf::Struct, _), _) ) } @@ -1585,16 +1585,18 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { kind: PatExprKind::Path(qpath), hir_id, .. - }) => is_enum_variant(cx, qpath, *hir_id), + }) => is_qpath_refutable(cx, qpath, *hir_id), PatKind::Or(pats) => { // TODO: should be the honest check, that pats is exhaustive set are_refutable(cx, pats) }, PatKind::Tuple(pats, _) => are_refutable(cx, pats), PatKind::Struct(ref qpath, fields, _) => { - is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| field.pat)) + is_qpath_refutable(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| field.pat)) + }, + PatKind::TupleStruct(ref qpath, pats, _) => { + is_qpath_refutable(cx, qpath, pat.hir_id) || are_refutable(cx, pats) }, - PatKind::TupleStruct(ref qpath, pats, _) => is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats), PatKind::Slice(head, middle, tail) => { match &cx.typeck_results().node_type(pat.hir_id).kind() { rustc_ty::Slice(..) => { diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed index 507bc2b29d862..60dc1c101b6e6 100644 --- a/tests/ui/question_mark.fixed +++ b/tests/ui/question_mark.fixed @@ -443,3 +443,13 @@ fn issue_14615(a: MutexGuard>) -> Option { //~^^^ question_mark Some(format!("{a}")) } + +fn const_in_pattern(x: Option<(i32, i32)>) -> Option<()> { + const N: i32 = 0; + + let Some((x, N)) = x else { + return None; + }; + + None +} diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs index 64b51b849ede0..99d0122a98faf 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -539,3 +539,13 @@ fn issue_14615(a: MutexGuard>) -> Option { //~^^^ question_mark Some(format!("{a}")) } + +fn const_in_pattern(x: Option<(i32, i32)>) -> Option<()> { + const N: i32 = 0; + + let Some((x, N)) = x else { + return None; + }; + + None +} From 4bbcb47239d65893ca6ff6aa8da6266ee5396719 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 24 May 2025 20:19:30 +0200 Subject: [PATCH 2719/4206] fix zulip topic URL --- src/tools/miri/tests/many-seeds/reentrant-lock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/tests/many-seeds/reentrant-lock.rs b/src/tools/miri/tests/many-seeds/reentrant-lock.rs index 8a363179a9cc7..4c2dc463f4858 100644 --- a/src/tools/miri/tests/many-seeds/reentrant-lock.rs +++ b/src/tools/miri/tests/many-seeds/reentrant-lock.rs @@ -1,6 +1,6 @@ #![feature(reentrant_lock)] //! This is a regression test for -//! . +//! . use std::cell::Cell; use std::sync::ReentrantLock; From fa2bb599bcf36b5390d5c8156cba6bc980ddbfca Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Sat, 24 May 2025 19:50:11 +0200 Subject: [PATCH 2720/4206] Cleanup CodegenFnAttrFlags - Rename `USED` to `USED_COMPILER` to better reflect its behavior. - Reorder some items to group the used and allocator flags together - Renumber them without gaps --- compiler/rustc_codegen_gcc/src/consts.rs | 2 +- compiler/rustc_codegen_llvm/src/consts.rs | 4 +- .../src/back/symbol_export.rs | 2 +- .../rustc_codegen_ssa/src/codegen_attrs.rs | 4 +- .../src/middle/codegen_fn_attrs.rs | 45 +++++++++---------- compiler/rustc_passes/src/dead.rs | 2 +- compiler/rustc_passes/src/reachable.rs | 2 +- src/tools/miri/src/bin/miri.rs | 2 +- src/tools/miri/src/helpers.rs | 2 +- 9 files changed, 31 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index 033afc0f8fbf4..8aed04c836ac6 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -154,7 +154,7 @@ impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'gcc, 'tcx> { // TODO(antoyo): set link section. } - if attrs.flags.contains(CodegenFnAttrFlags::USED) + if attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) || attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) { self.add_used_global(global.to_rvalue()); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index bf81eb648f8ae..fe2f20273276a 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -527,7 +527,7 @@ impl<'ll> CodegenCx<'ll, '_> { base::set_variable_sanitizer_attrs(g, attrs); - if attrs.flags.contains(CodegenFnAttrFlags::USED) { + if attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) { // `USED` and `USED_LINKER` can't be used together. assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)); @@ -551,7 +551,7 @@ impl<'ll> CodegenCx<'ll, '_> { } if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) { // `USED` and `USED_LINKER` can't be used together. - assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED)); + assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)); self.add_used_global(g); } diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 96aec9769d2ca..e26f999773dc7 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -128,7 +128,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap, did: LocalDefId) -> CodegenFnAttrs { ) .emit(); } - codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED; + codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_COMPILER; } Some(_) => { tcx.dcx().emit_err(errors::ExpectedUsedSymbol { span: attr.span() }); @@ -220,7 +220,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { || tcx.sess.target.is_like_windows || tcx.sess.target.is_like_wasm); codegen_fn_attrs.flags |= if is_like_elf { - CodegenFnAttrFlags::USED + CodegenFnAttrFlags::USED_COMPILER } else { CodegenFnAttrFlags::USED_LINKER }; diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 00da1a6aeec7d..f21cf5fa45e69 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -96,49 +96,46 @@ bitflags::bitflags! { /// `#[cold]`: a hint to LLVM that this function, when called, is never on /// the hot path. const COLD = 1 << 0; - /// `#[rustc_allocator]`: a hint to LLVM that the pointer returned from this - /// function is never null and the function has no side effects other than allocating. - const ALLOCATOR = 1 << 1; - /// An indicator that function will never unwind. Will become obsolete - /// once C-unwind is fully stabilized. - const NEVER_UNWIND = 1 << 3; + /// `#[rustc_nounwind]`: An indicator that function will never unwind. + const NEVER_UNWIND = 1 << 1; /// `#[naked]`: an indicator to LLVM that no function prologue/epilogue /// should be generated. - const NAKED = 1 << 4; + const NAKED = 1 << 2; /// `#[no_mangle]`: an indicator that the function's name should be the same /// as its symbol. - const NO_MANGLE = 1 << 5; + const NO_MANGLE = 1 << 3; /// `#[rustc_std_internal_symbol]`: an indicator that this symbol is a /// "weird symbol" for the standard library in that it has slightly /// different linkage, visibility, and reachability rules. - const RUSTC_STD_INTERNAL_SYMBOL = 1 << 6; + const RUSTC_STD_INTERNAL_SYMBOL = 1 << 4; /// `#[thread_local]`: indicates a static is actually a thread local /// piece of memory - const THREAD_LOCAL = 1 << 8; - /// `#[used]`: indicates that LLVM can't eliminate this function (but the + const THREAD_LOCAL = 1 << 5; + /// `#[used(compiler)]`: indicates that LLVM can't eliminate this function (but the /// linker can!). - const USED = 1 << 9; + const USED_COMPILER = 1 << 6; + /// `#[used(linker)]`: + /// indicates that neither LLVM nor the linker will eliminate this function. + const USED_LINKER = 1 << 7; /// `#[track_caller]`: allow access to the caller location - const TRACK_CALLER = 1 << 10; + const TRACK_CALLER = 1 << 8; /// #[ffi_pure]: applies clang's `pure` attribute to a foreign function /// declaration. - const FFI_PURE = 1 << 11; + const FFI_PURE = 1 << 9; /// #[ffi_const]: applies clang's `const` attribute to a foreign function /// declaration. - const FFI_CONST = 1 << 12; - // (Bit 13 was used for `#[cmse_nonsecure_entry]`, but is now unused.) - // (Bit 14 was used for `#[coverage(off)]`, but is now unused.) - /// `#[used(linker)]`: - /// indicates that neither LLVM nor the linker will eliminate this function. - const USED_LINKER = 1 << 15; + const FFI_CONST = 1 << 10; + /// `#[rustc_allocator]`: a hint to LLVM that the pointer returned from this + /// function is never null and the function has no side effects other than allocating. + const ALLOCATOR = 1 << 11; /// `#[rustc_deallocator]`: a hint to LLVM that the function only deallocates memory. - const DEALLOCATOR = 1 << 16; + const DEALLOCATOR = 1 << 12; /// `#[rustc_reallocator]`: a hint to LLVM that the function only reallocates memory. - const REALLOCATOR = 1 << 17; + const REALLOCATOR = 1 << 13; /// `#[rustc_allocator_zeroed]`: a hint to LLVM that the function only allocates zeroed memory. - const ALLOCATOR_ZEROED = 1 << 18; + const ALLOCATOR_ZEROED = 1 << 14; /// `#[no_builtins]`: indicates that disable implicit builtin knowledge of functions for the function. - const NO_BUILTINS = 1 << 19; + const NO_BUILTINS = 1 << 15; } } rustc_data_structures::external_bitflags_debug! { CodegenFnAttrFlags } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 0060e726a8e05..6e5357d800743 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -707,7 +707,7 @@ fn has_allow_dead_code_or_lang_attr( // #[used], #[no_mangle], #[export_name], etc also keeps the item alive // forcefully, e.g., for placing it in a specific section. cg_attrs.contains_extern_indicator() - || cg_attrs.flags.contains(CodegenFnAttrFlags::USED) + || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) } } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index f0e8fa986feae..7e15267a953ba 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -427,7 +427,7 @@ fn has_custom_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { // FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by // `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their // `SymbolExportLevel::Rust` export level but may end up being exported in dylibs. - || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED) + || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) } diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 469fc26497035..7098ef5130dce 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -281,7 +281,7 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { } let codegen_fn_attrs = tcx.codegen_fn_attrs(local_def_id); if codegen_fn_attrs.contains_extern_indicator() - || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED) + || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) { Some(( diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index ff2ec1b3e60a8..6a6adc966a896 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -135,7 +135,7 @@ pub fn iter_exported_symbols<'tcx>( let codegen_attrs = tcx.codegen_fn_attrs(def_id); codegen_attrs.contains_extern_indicator() || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) - || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED) + || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) }; if exported { From 4ef35bcaef07871f286330c13783d8cc37f9c209 Mon Sep 17 00:00:00 2001 From: binarycat Date: Sat, 24 May 2025 14:15:20 -0500 Subject: [PATCH 2721/4206] rustdoc: use descriptive tooltip if doctest is conditionally ignored fixes https://github.com/rust-lang/rust/issues/141092 --- src/librustdoc/html/highlight.rs | 45 +++++++++++++++++++---- src/librustdoc/html/markdown.rs | 6 ++- tests/rustdoc/doctest/ignore-sometimes.rs | 23 ++++++++++++ 3 files changed, 64 insertions(+), 10 deletions(-) create mode 100644 tests/rustdoc/doctest/ignore-sometimes.rs diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 2db1ea8450ce1..f9d355cc0386d 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -6,7 +6,7 @@ //! Use the `render_with_highlighting` to highlight some rust code. use std::collections::VecDeque; -use std::fmt::{Display, Write}; +use std::fmt::{self, Display, Write}; use rustc_data_structures::fx::FxIndexMap; use rustc_lexer::{Cursor, FrontmatterAllowed, LiteralKind, TokenKind}; @@ -36,9 +36,10 @@ pub(crate) struct HrefContext<'a, 'tcx> { #[derive(Default)] pub(crate) struct DecorationInfo(pub(crate) FxIndexMap<&'static str, Vec<(u32, u32)>>); -#[derive(Eq, PartialEq, Clone, Copy)] +#[derive(Eq, PartialEq, Clone)] pub(crate) enum Tooltip { - Ignore, + IgnoreAll, + IgnoreSome(Vec), CompileFail, ShouldPanic, Edition(Edition), @@ -70,7 +71,7 @@ fn write_header( format_args!( "

", match tooltip { - Tooltip::Ignore => " ignore", + Tooltip::IgnoreAll | Tooltip::IgnoreSome(_) => " ignore", Tooltip::CompileFail => " compile_fail", Tooltip::ShouldPanic => " should_panic", Tooltip::Edition(_) => " edition", @@ -80,18 +81,46 @@ fn write_header( ); if tooltip != Tooltip::None { - let edition_code; + // variable for extending lifetimes of temporaries + let tmp; write_str( out, format_args!( "", match tooltip { - Tooltip::Ignore => "This example is not tested", + Tooltip::IgnoreAll => "This example is not tested", + Tooltip::IgnoreSome(platforms) => { + tmp = format!( + "This example is not tested on {}", + fmt::from_fn(|f| { + match platforms.len() { + 0 => unreachable!(), + 1 => f.write_str(&platforms[0]), + 2 => write!(f, "{} or {}", &platforms[0], &platforms[1]), + _ => { + for (i, plat) in platforms.iter().enumerate() { + match (platforms.len() - 2).cmp(&i) { + std::cmp::Ordering::Greater => { + write!(f, "{}, ", plat)? + } + std::cmp::Ordering::Equal => { + write!(f, "{}, or ", plat)? + } + std::cmp::Ordering::Less => f.write_str(&plat)?, + } + } + Ok(()) + } + } + }) + ); + &tmp + } Tooltip::CompileFail => "This example deliberately fails to compile", Tooltip::ShouldPanic => "This example panics", Tooltip::Edition(edition) => { - edition_code = format!("This example runs with edition {edition}"); - &edition_code + tmp = format!("This example runs with edition {edition}"); + &tmp } Tooltip::None => unreachable!(), } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index ad7dfafd90c7d..987b92fa4e231 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -320,8 +320,10 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { )) }); - let tooltip = if ignore != Ignore::None { - highlight::Tooltip::Ignore + let tooltip = if ignore == Ignore::All { + highlight::Tooltip::IgnoreAll + } else if let Ignore::Some(platforms) = ignore { + highlight::Tooltip::IgnoreSome(platforms) } else if compile_fail { highlight::Tooltip::CompileFail } else if should_panic { diff --git a/tests/rustdoc/doctest/ignore-sometimes.rs b/tests/rustdoc/doctest/ignore-sometimes.rs new file mode 100644 index 0000000000000..0f8586d221c15 --- /dev/null +++ b/tests/rustdoc/doctest/ignore-sometimes.rs @@ -0,0 +1,23 @@ +#![crate_name = "foo"] + +// test for https://github.com/rust-lang/rust/issues/141092 + +//@ has 'foo/fn.f.html' '//a[@title="This example is not tested on wasm"]' 'ⓘ' +/// Example +/// +/// ```ignore-wasm +/// let x = 1; +/// ``` +pub fn f() {} + +//@ has 'foo/fn.g.html' '//a[@title="This example is not tested on wasm or windows"]' 'ⓘ' +/// ```ignore-wasm,ignore-windows +/// let x = 1; +/// ``` +pub fn g() {} + +//@ has 'foo/fn.h.html' '//a[@title="This example is not tested on wasm, windows, or unix"]' 'ⓘ' +/// ```ignore-wasm,ignore-windows,ignore-unix +/// let x = 1; +/// ``` +pub fn h() {} From f674c809c8ec57e234cc0cb5cc844340927d193c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 24 May 2025 21:18:16 +0200 Subject: [PATCH 2722/4206] Update `askama` to `0.14.0` version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 2da350ba44e34..5584ded0a4aa8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ walkdir = "2.3" filetime = "0.2.9" itertools = "0.12" pulldown-cmark = { version = "0.11", default-features = false, features = ["html"] } -askama = { version = "0.13", default-features = false, features = ["alloc", "config", "derive"] } +askama = { version = "0.14", default-features = false, features = ["alloc", "config", "derive"] } # UI test dependencies if_chain = "1.0" From a3bd12b88aaf32b1036cdcb2ef3efe509dbebc15 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 24 May 2025 22:12:15 +0200 Subject: [PATCH 2723/4206] Path::with_extension: improve examples --- library/std/src/path.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 7959c63385816..0583ee1eb3274 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2743,12 +2743,27 @@ impl Path { /// /// let path = Path::new("foo.rs"); /// assert_eq!(path.with_extension("txt"), PathBuf::from("foo.txt")); + /// assert_eq!(path.with_extension(""), PathBuf::from("foo")); + /// ``` + /// + /// Handling multiple extensions: + /// + /// ``` + /// use std::path::{Path, PathBuf}; /// /// let path = Path::new("foo.tar.gz"); - /// assert_eq!(path.with_extension(""), PathBuf::from("foo.tar")); /// assert_eq!(path.with_extension("xz"), PathBuf::from("foo.tar.xz")); /// assert_eq!(path.with_extension("").with_extension("txt"), PathBuf::from("foo.txt")); /// ``` + /// + /// Adding an extension where one did not exist: + /// + /// ``` + /// use std::path::{Path, PathBuf}; + /// + /// let path = Path::new("foo"); + /// assert_eq!(path.with_extension("rs"), PathBuf::from("foo.rs")); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_extension>(&self, extension: S) -> PathBuf { self._with_extension(extension.as_ref()) From 248f4b2ad2b18ab322748cc62b3524c109206b98 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 24 May 2025 22:17:55 +0200 Subject: [PATCH 2724/4206] reduce clutter... too many imports --- library/std/src/path.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 0583ee1eb3274..87c5d6f0438de 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2739,30 +2739,30 @@ impl Path { /// # Examples /// /// ``` - /// use std::path::{Path, PathBuf}; + /// use std::path::Path; /// /// let path = Path::new("foo.rs"); - /// assert_eq!(path.with_extension("txt"), PathBuf::from("foo.txt")); - /// assert_eq!(path.with_extension(""), PathBuf::from("foo")); + /// assert_eq!(path.with_extension("txt"), Path::new("foo.txt")); + /// assert_eq!(path.with_extension(""), Path::new("foo")); /// ``` /// /// Handling multiple extensions: /// /// ``` - /// use std::path::{Path, PathBuf}; + /// use std::path::Path; /// /// let path = Path::new("foo.tar.gz"); - /// assert_eq!(path.with_extension("xz"), PathBuf::from("foo.tar.xz")); - /// assert_eq!(path.with_extension("").with_extension("txt"), PathBuf::from("foo.txt")); + /// assert_eq!(path.with_extension("xz"), Path::new("foo.tar.xz")); + /// assert_eq!(path.with_extension("").with_extension("txt"), Path::new("foo.txt")); /// ``` /// /// Adding an extension where one did not exist: /// /// ``` - /// use std::path::{Path, PathBuf}; + /// use std::path::Path; /// /// let path = Path::new("foo"); - /// assert_eq!(path.with_extension("rs"), PathBuf::from("foo.rs")); + /// assert_eq!(path.with_extension("rs"), Path::new("foo.rs")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_extension>(&self, extension: S) -> PathBuf { From fab206bf5852c532f85b9ad30f9eea8fc952e8e1 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Sat, 24 May 2025 22:33:11 +0200 Subject: [PATCH 2725/4206] make `OsString::new` and `PathBuf::new` unstably const --- library/std/src/ffi/os_str.rs | 3 ++- library/std/src/path.rs | 3 ++- library/std/src/sys/os_str/bytes.rs | 2 +- library/std/src/sys/os_str/wtf8.rs | 2 +- library/std/src/sys_common/wtf8.rs | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index ead4877512727..22308224a2f86 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -137,7 +137,8 @@ impl OsString { #[stable(feature = "rust1", since = "1.0.0")] #[must_use] #[inline] - pub fn new() -> OsString { + #[rustc_const_unstable(feature = "const_pathbuf_osstring_new", issue = "141520")] + pub const fn new() -> OsString { OsString { inner: Buf::from_string(String::new()) } } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 7959c63385816..3e347798ab998 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1191,7 +1191,8 @@ impl PathBuf { #[stable(feature = "rust1", since = "1.0.0")] #[must_use] #[inline] - pub fn new() -> PathBuf { + #[rustc_const_unstable(feature = "const_pathbuf_osstring_new", issue = "141520")] + pub const fn new() -> PathBuf { PathBuf { inner: OsString::new() } } diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs index 4a8808c923045..f8ab4543a3a52 100644 --- a/library/std/src/sys/os_str/bytes.rs +++ b/library/std/src/sys/os_str/bytes.rs @@ -115,7 +115,7 @@ impl Buf { } #[inline] - pub fn from_string(s: String) -> Buf { + pub const fn from_string(s: String) -> Buf { Buf { inner: s.into_bytes() } } diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs index 5174ea65d0cd9..4207a2db635fa 100644 --- a/library/std/src/sys/os_str/wtf8.rs +++ b/library/std/src/sys/os_str/wtf8.rs @@ -92,7 +92,7 @@ impl Buf { } #[inline] - pub fn from_string(s: String) -> Buf { + pub const fn from_string(s: String) -> Buf { Buf { inner: Wtf8Buf::from_string(s) } } diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index f9ec112b19747..50bde88b5a4c3 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -209,7 +209,7 @@ impl Wtf8Buf { /// /// Since WTF-8 is a superset of UTF-8, this always succeeds. #[inline] - pub fn from_string(string: String) -> Wtf8Buf { + pub const fn from_string(string: String) -> Wtf8Buf { Wtf8Buf { bytes: string.into_bytes(), is_known_utf8: true } } From 01503d0c1e43a23de92ad1577cbdceb7afe47dab Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Sat, 24 May 2025 20:22:58 +0200 Subject: [PATCH 2726/4206] Avoid extra path trimming in method not found error Method errors have an extra check that force trim paths whenever the normal string is longer than 10 characters, which can be quite unhelpful when multiple items have the same name (for example an `Error`). A user reported this force trimming as being quite unhelpful when they had a method error where the precise path of the `Error` mattered. The code uses `tcx.short_string` already to get the normal path, which tries to be clever around trimming paths if necessary, so there is no reason for this extra force trimming. --- compiler/rustc_hir_typeck/src/method/suggest.rs | 6 +----- .../crate-loading/multiple-dep-versions.stderr | 4 ++-- tests/ui/associated-types/issue-43924.stderr | 2 +- tests/ui/attributes/rustc_confusables.stderr | 6 +++--- tests/ui/empty/empty-struct-braces-expr.stderr | 4 ++-- .../multiline-removal-suggestion.svg | 10 +++++----- .../functions-closures/fn-help-with-err.stderr | 2 +- .../hrtb-doesnt-borrow-self-1.stderr | 2 +- .../hrtb-doesnt-borrow-self-2.stderr | 2 +- .../impl-trait/no-method-suggested-traits.stderr | 16 ++++++++-------- tests/ui/issues/issue-30123.stderr | 2 +- tests/ui/issues/issue-41880.stderr | 2 +- tests/ui/macros/missing-writer.stderr | 4 ++-- tests/ui/methods/issue-19521.stderr | 2 +- .../method-not-found-generic-arg-elision.stderr | 2 +- tests/ui/methods/receiver-equality.stderr | 2 +- tests/ui/methods/untrimmed-path-type.rs | 11 +++++++++++ tests/ui/methods/untrimmed-path-type.stderr | 9 +++++++++ tests/ui/mismatched_types/issue-36053-2.stderr | 2 +- tests/ui/nll/issue-57362-2.stderr | 2 +- .../nll/issue-57642-higher-ranked-subtype.stderr | 4 ++-- tests/ui/object-pointer-types.stderr | 2 +- .../mut-borrow-needed-by-trait.stderr | 4 ++-- tests/ui/suggestions/suggest-using-chars.stderr | 4 ++-- tests/ui/typeck/issue-31173.stderr | 2 +- ...boxed-closures-static-call-wrong-trait.stderr | 2 +- 26 files changed, 63 insertions(+), 47 deletions(-) create mode 100644 tests/ui/methods/untrimmed-path-type.rs create mode 100644 tests/ui/methods/untrimmed-path-type.stderr diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 342eed751a589..7b71f5de7569f 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -599,7 +599,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty); let mut ty_file = None; - let (mut ty_str, short_ty_str) = + let (ty_str, short_ty_str) = if trait_missing_method && let ty::Dynamic(predicates, _, _) = rcvr_ty.kind() { (predicates.to_string(), with_forced_trimmed_paths!(predicates.to_string())) } else { @@ -738,10 +738,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(within_macro_span, "due to this macro variable"); } - if short_ty_str.len() < ty_str.len() && ty_str.len() > 10 { - ty_str = short_ty_str; - } - if rcvr_ty.references_error() { err.downgrade_to_delayed_bug(); } diff --git a/tests/run-make/crate-loading/multiple-dep-versions.stderr b/tests/run-make/crate-loading/multiple-dep-versions.stderr index 6e1d6111b5810..dea08bb96c979 100644 --- a/tests/run-make/crate-loading/multiple-dep-versions.stderr +++ b/tests/run-make/crate-loading/multiple-dep-versions.stderr @@ -39,7 +39,7 @@ error[E0599]: no method named `foo` found for struct `dep_2_reexport::Type` in t --> replaced | LL | Type.foo(); - | ^^^ method not found in `Type` + | ^^^ method not found in `dep_2_reexport::Type` | note: there are multiple different versions of crate `dependency` in the dependency graph --> replaced @@ -63,7 +63,7 @@ error[E0599]: no function or associated item named `bar` found for struct `dep_2 --> replaced | LL | Type::bar(); - | ^^^ function or associated item not found in `Type` + | ^^^ function or associated item not found in `dep_2_reexport::Type` | note: there are multiple different versions of crate `dependency` in the dependency graph --> replaced diff --git a/tests/ui/associated-types/issue-43924.stderr b/tests/ui/associated-types/issue-43924.stderr index ab1a9511ec6c7..526f425b21e71 100644 --- a/tests/ui/associated-types/issue-43924.stderr +++ b/tests/ui/associated-types/issue-43924.stderr @@ -14,7 +14,7 @@ error[E0599]: no function or associated item named `default` found for trait obj --> $DIR/issue-43924.rs:14:39 | LL | assert_eq!(<() as Foo>::Out::default().to_string(), "false"); - | ^^^^^^^ function or associated item not found in `dyn ToString` + | ^^^^^^^ function or associated item not found in `(dyn ToString + 'static)` error: aborting due to 2 previous errors diff --git a/tests/ui/attributes/rustc_confusables.stderr b/tests/ui/attributes/rustc_confusables.stderr index 55c9219a08a84..aba384ff8ac83 100644 --- a/tests/ui/attributes/rustc_confusables.stderr +++ b/tests/ui/attributes/rustc_confusables.stderr @@ -42,13 +42,13 @@ error[E0599]: no method named `foo` found for struct `rustc_confusables_across_c --> $DIR/rustc_confusables.rs:15:7 | LL | x.foo(); - | ^^^ method not found in `BTreeSet` + | ^^^ method not found in `rustc_confusables_across_crate::BTreeSet` error[E0599]: no method named `push` found for struct `rustc_confusables_across_crate::BTreeSet` in the current scope --> $DIR/rustc_confusables.rs:17:7 | LL | x.push(); - | ^^^^ method not found in `BTreeSet` + | ^^^^ method not found in `rustc_confusables_across_crate::BTreeSet` | help: you might have meant to use `insert` | @@ -60,7 +60,7 @@ error[E0599]: no method named `test` found for struct `rustc_confusables_across_ --> $DIR/rustc_confusables.rs:20:7 | LL | x.test(); - | ^^^^ method not found in `BTreeSet` + | ^^^^ method not found in `rustc_confusables_across_crate::BTreeSet` error[E0599]: no method named `pulled` found for struct `rustc_confusables_across_crate::BTreeSet` in the current scope --> $DIR/rustc_confusables.rs:22:7 diff --git a/tests/ui/empty/empty-struct-braces-expr.stderr b/tests/ui/empty/empty-struct-braces-expr.stderr index 8ec8ecf46bf06..a176107a06e24 100644 --- a/tests/ui/empty/empty-struct-braces-expr.stderr +++ b/tests/ui/empty/empty-struct-braces-expr.stderr @@ -121,7 +121,7 @@ error[E0599]: no variant or associated item named `Empty3` found for enum `empty --> $DIR/empty-struct-braces-expr.rs:25:19 | LL | let xe3 = XE::Empty3; - | ^^^^^^ variant or associated item not found in `XE` + | ^^^^^^ variant or associated item not found in `empty_struct::XE` | help: there is a variant with a similar name | @@ -132,7 +132,7 @@ error[E0599]: no variant or associated item named `Empty3` found for enum `empty --> $DIR/empty-struct-braces-expr.rs:26:19 | LL | let xe3 = XE::Empty3(); - | ^^^^^^ variant or associated item not found in `XE` + | ^^^^^^ variant or associated item not found in `empty_struct::XE` | help: there is a variant with a similar name | diff --git a/tests/ui/error-emitter/multiline-removal-suggestion.svg b/tests/ui/error-emitter/multiline-removal-suggestion.svg index 95c7740f6995d..9c9bd163ecd49 100644 --- a/tests/ui/error-emitter/multiline-removal-suggestion.svg +++ b/tests/ui/error-emitter/multiline-removal-suggestion.svg @@ -1,4 +1,4 @@ - +
+ /// + /// This function always resolves `..` to the "lexical" parent. + /// That is "a/b/../c" will always resolve to `a/c` which can change the meaning of the path. + /// In particular, `a/c` and `a/b/../c` are distinct on many systems because `b` may be a symbolic link, so its parent isn’t `a`. + /// + ///
+ /// + /// [`path::absolute`](absolute) is an alternative that preserves `..`. + /// Or [`Path::canonicalize`] can be used to resolve any `..` by querying the filesystem. + #[unstable(feature = "normalize_lexically", issue = "134694")] + pub fn normalize_lexically(&self) -> Result { + let mut lexical = PathBuf::new(); + let mut iter = self.components().peekable(); + + // Find the root, if any, and add it to the lexical path. + // Here we treat the Windows path "C:\" as a single "root" even though + // `components` splits it into two: (Prefix, RootDir). + let root = match iter.peek() { + Some(Component::ParentDir) => return Err(NormalizeError), + Some(p @ Component::RootDir) | Some(p @ Component::CurDir) => { + lexical.push(p); + iter.next(); + lexical.as_os_str().len() + } + Some(Component::Prefix(prefix)) => { + lexical.push(prefix.as_os_str()); + iter.next(); + if let Some(p @ Component::RootDir) = iter.peek() { + lexical.push(p); + iter.next(); + } + lexical.as_os_str().len() + } + None => return Ok(PathBuf::new()), + Some(Component::Normal(_)) => 0, + }; + + for component in iter { + match component { + Component::RootDir => unreachable!(), + Component::Prefix(_) => return Err(NormalizeError), + Component::CurDir => continue, + Component::ParentDir => { + // It's an error if ParentDir causes us to go above the "root". + if lexical.as_os_str().len() == root { + return Err(NormalizeError); + } else { + lexical.pop(); + } + } + Component::Normal(path) => lexical.push(path), + } + } + Ok(lexical) + } + /// Reads a symbolic link, returning the file that the link points to. /// /// This is an alias to [`fs::read_link`]. @@ -3502,6 +3570,15 @@ impl Error for StripPrefixError { } } +#[unstable(feature = "normalize_lexically", issue = "134694")] +impl fmt::Display for NormalizeError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("parent reference `..` points outside of base directory") + } +} +#[unstable(feature = "normalize_lexically", issue = "134694")] +impl Error for NormalizeError {} + /// Makes the path absolute without accessing the filesystem. /// /// If the path is relative, the current directory is used as the base directory. diff --git a/library/std/tests/path.rs b/library/std/tests/path.rs index 87e0d226cbd31..781855a2d14aa 100644 --- a/library/std/tests/path.rs +++ b/library/std/tests/path.rs @@ -3,7 +3,8 @@ path_add_extension, path_file_prefix, maybe_uninit_slice, - os_string_pathbuf_leak + os_string_pathbuf_leak, + normalize_lexically )] use std::clone::CloneToUninit; @@ -2007,3 +2008,56 @@ fn test_embedded_newline() { assert_eq!(path.file_name(), Some(OsStr::new("foo\nbar"))); assert_eq!(path.to_str(), Some("foo\nbar")); } + +#[test] +fn normalize_lexically() { + #[track_caller] + fn check_ok(a: &str, b: &str) { + assert_eq!(Path::new(a).normalize_lexically().unwrap(), PathBuf::from(b)); + } + + #[track_caller] + fn check_err(a: &str) { + assert!(Path::new(a).normalize_lexically().is_err()); + } + + // Relative paths + check_ok("a", "a"); + check_ok("./a", "./a"); + check_ok("a/b/c", "a/b/c"); + check_ok("a/././b/./c/.", "a/b/c"); + check_ok("a/../c", "c"); + check_ok("./a/b", "./a/b"); + check_ok("a/../b/c/..", "b"); + + check_err(".."); + check_err("../.."); + check_err("a/../.."); + check_err("a/../../b"); + check_err("a/../../b/c"); + check_err("a/../b/../.."); + + // Check we don't escape the root or prefix + #[cfg(unix)] + { + check_err("/.."); + check_err("/a/../.."); + } + #[cfg(windows)] + { + check_err(r"C:\.."); + check_err(r"C:\a\..\.."); + + check_err(r"C:.."); + check_err(r"C:a\..\.."); + + check_err(r"\\server\share\.."); + check_err(r"\\server\share\a\..\.."); + + check_err(r"\.."); + check_err(r"\a\..\.."); + + check_err(r"\\?\UNC\server\share\.."); + check_err(r"\\?\UNC\server\share\a\..\.."); + } +} From d82e51b6404acda3db23639d3f03b62458c3516a Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Mon, 19 May 2025 00:05:13 +0200 Subject: [PATCH 2738/4206] Test that all interned symbols are referenced in Clippy sources --- clippy_utils/src/sym.rs | 1 - tests/symbols-used.rs | 81 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 tests/symbols-used.rs diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index f417530be3672..9a75b946001f9 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -132,7 +132,6 @@ generate! { enum_glob_use, enumerate, err, - error, exp, expect_err, expn_data, diff --git a/tests/symbols-used.rs b/tests/symbols-used.rs new file mode 100644 index 0000000000000..bc0456711fb2b --- /dev/null +++ b/tests/symbols-used.rs @@ -0,0 +1,81 @@ +// This test checks that all symbols defined in Clippy's `sym.rs` file +// are used in Clippy. Otherwise, it will fail with a list of symbols +// which are unused. +// +// This test is a no-op if run as part of the compiler test suite +// and will always succeed. + +use std::collections::HashSet; +use std::ffi::OsStr; +use std::fs; + +use regex::Regex; +use walkdir::{DirEntry, WalkDir}; + +const SYM_FILE: &str = "clippy_utils/src/sym.rs"; + +type Result = std::result::Result; +type AnyError = Box; + +#[test] +#[allow(clippy::case_sensitive_file_extension_comparisons)] +fn all_symbols_are_used() -> Result<()> { + if option_env!("RUSTC_TEST_SUITE").is_some() { + return Ok(()); + } + + // Load all symbols defined in `SYM_FILE`. + let content = fs::read_to_string(SYM_FILE)?; + let content = content + .split_once("generate! {") + .ok_or("cannot find symbols start")? + .1 + .split_once("\n}\n") + .ok_or("cannot find symbols end")? + .0; + let mut interned: HashSet = Regex::new(r"(?m)^ (\w+)") + .unwrap() + .captures_iter(content) + .map(|m| m[1].to_owned()) + .collect(); + + // Remove symbols used as `sym::*`. + let used_re = Regex::new(r"\bsym::(\w+)\b").unwrap(); + let rs_ext = OsStr::new("rs"); + for dir in ["clippy_lints", "clippy_lints_internal", "clippy_utils", "src"] { + for file in WalkDir::new(dir) + .into_iter() + .flatten() + .map(DirEntry::into_path) + .filter(|p| p.extension() == Some(rs_ext)) + { + for cap in used_re.captures_iter(&fs::read_to_string(file)?) { + interned.remove(&cap[1]); + } + } + } + + // Remove symbols used as part of paths. + let paths_re = Regex::new(r"path!\(([\w:]+)\)").unwrap(); + for path in [ + "clippy_utils/src/paths.rs", + "clippy_lints_internal/src/internal_paths.rs", + ] { + for cap in paths_re.captures_iter(&fs::read_to_string(path)?) { + for sym in cap[1].split("::") { + interned.remove(sym); + } + } + } + + let mut extra = interned.iter().collect::>(); + if !extra.is_empty() { + extra.sort_unstable(); + eprintln!("Unused symbols defined in {SYM_FILE}:"); + for sym in extra { + eprintln!(" - {sym}"); + } + Err(format!("extra symbols found — remove them {SYM_FILE}"))?; + } + Ok(()) +} From 7820d2caba4452e129c47389c302da7edb537404 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 25 May 2025 10:37:43 +0000 Subject: [PATCH 2739/4206] Don't use relation just to equate regions in response --- .../rustc_infer/src/infer/canonical/query_response.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index ec72e05494bef..e9cfc96ba508a 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -23,7 +23,7 @@ use crate::infer::canonical::{ QueryOutlivesConstraint, QueryRegionConstraints, QueryResponse, }; use crate::infer::region_constraints::{Constraint, RegionConstraintData}; -use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult}; +use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult, SubregionOrigin}; use crate::traits::query::NoSolution; use crate::traits::{ Obligation, ObligationCause, PredicateObligation, PredicateObligations, ScrubbedTraitError, @@ -593,10 +593,10 @@ impl<'tcx> InferCtxt<'tcx> { // no action needed } (GenericArgKind::Lifetime(v1), GenericArgKind::Lifetime(v2)) => { - obligations.extend( - self.at(cause, param_env) - .eq(DefineOpaqueTypes::Yes, v1, v2)? - .into_obligations(), + self.inner.borrow_mut().unwrap_region_constraints().make_eqregion( + SubregionOrigin::RelateRegionParamBound(cause.span, None), + v1, + v2, ); } (GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => { From 9a8cf3dd0c92afeaac7a83e8d178f1b002ac42b0 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 25 May 2025 10:37:58 +0000 Subject: [PATCH 2740/4206] Comment for not using select_in_new_trait_solver --- compiler/rustc_trait_selection/src/solve/select.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_trait_selection/src/solve/select.rs b/compiler/rustc_trait_selection/src/solve/select.rs index 1f3168fafb1da..21812c8017da3 100644 --- a/compiler/rustc_trait_selection/src/solve/select.rs +++ b/compiler/rustc_trait_selection/src/solve/select.rs @@ -15,6 +15,7 @@ use crate::solve::inspect::{self, ProofTreeInferCtxtExt}; #[extension(pub trait InferCtxtSelectExt<'tcx>)] impl<'tcx> InferCtxt<'tcx> { + /// Do not use this directly. This is called from [`crate::traits::SelectionContext::select`]. fn select_in_new_trait_solver( &self, obligation: &TraitObligation<'tcx>, From 3850b1faa2c55f250cfb91df0d8de70d3ed893bd Mon Sep 17 00:00:00 2001 From: Ross Sullivan Date: Sun, 25 May 2025 13:50:45 +0900 Subject: [PATCH 2741/4206] feat(unstable-book): Added unstable feature doc comments as feature descriptions --- src/tools/tidy/src/features.rs | 17 ++++++++++++++ src/tools/unstable-book-gen/src/main.rs | 23 ++++++++++++++----- src/tools/unstable-book-gen/src/stub-issue.md | 2 ++ .../unstable-book-gen/src/stub-no-issue.md | 2 ++ 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index fcd7943e6e0a8..6093e7fd2632f 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -54,6 +54,7 @@ pub struct Feature { pub tracking_issue: Option, pub file: PathBuf, pub line: usize, + pub description: Option, } impl Feature { fn tracking_issue_display(&self) -> impl fmt::Display { @@ -296,6 +297,7 @@ fn collect_lang_features_in(features: &mut Features, base: &Path, file: &str, ba let mut prev_names = vec![]; let lines = contents.lines().zip(1..); + let mut doc_comments: Vec = Vec::new(); for (line, line_number) in lines { let line = line.trim(); @@ -332,6 +334,13 @@ fn collect_lang_features_in(features: &mut Features, base: &Path, file: &str, ba continue; } + if in_feature_group { + if let Some(doc_comment) = line.strip_prefix("///") { + doc_comments.push(doc_comment.trim().to_string()); + continue; + } + } + let mut parts = line.split(','); let level = match parts.next().map(|l| l.trim().trim_start_matches('(')) { Some("unstable") => Status::Unstable, @@ -438,9 +447,15 @@ fn collect_lang_features_in(features: &mut Features, base: &Path, file: &str, ba tracking_issue, file: path.to_path_buf(), line: line_number, + description: if doc_comments.is_empty() { + None + } else { + Some(doc_comments.join(" ")) + }, }); } } + doc_comments.clear(); } } @@ -564,6 +579,7 @@ fn map_lib_features( tracking_issue: find_attr_val(line, "issue").and_then(handle_issue_none), file: file.to_path_buf(), line: i + 1, + description: None, }; mf(Ok((feature_name, feature)), file, i + 1); continue; @@ -600,6 +616,7 @@ fn map_lib_features( tracking_issue, file: file.to_path_buf(), line: i + 1, + description: None, }; if line.contains(']') { mf(Ok((feature_name, feature)), file, i + 1); diff --git a/src/tools/unstable-book-gen/src/main.rs b/src/tools/unstable-book-gen/src/main.rs index 6cbdc83d5b5ff..3343577296005 100644 --- a/src/tools/unstable-book-gen/src/main.rs +++ b/src/tools/unstable-book-gen/src/main.rs @@ -12,13 +12,18 @@ use tidy::unstable_book::{ collect_unstable_feature_names, }; -fn generate_stub_issue(path: &Path, name: &str, issue: u32) { - let content = format!(include_str!("stub-issue.md"), name = name, issue = issue); +fn generate_stub_issue(path: &Path, name: &str, issue: u32, description: &str) { + let content = format!( + include_str!("stub-issue.md"), + name = name, + issue = issue, + description = description + ); t!(write(path, content), path); } -fn generate_stub_no_issue(path: &Path, name: &str) { - let content = format!(include_str!("stub-no-issue.md"), name = name); +fn generate_stub_no_issue(path: &Path, name: &str, description: &str) { + let content = format!(include_str!("stub-no-issue.md"), name = name, description = description); t!(write(path, content), path); } @@ -58,11 +63,17 @@ fn generate_unstable_book_files(src: &Path, out: &Path, features: &Features) { let file_name = format!("{feature_name}.md"); let out_file_path = out.join(&file_name); let feature = &features[&feature_name_underscore]; + let description = feature.description.as_deref().unwrap_or_default(); if let Some(issue) = feature.tracking_issue { - generate_stub_issue(&out_file_path, &feature_name_underscore, issue.get()); + generate_stub_issue( + &out_file_path, + &feature_name_underscore, + issue.get(), + &description, + ); } else { - generate_stub_no_issue(&out_file_path, &feature_name_underscore); + generate_stub_no_issue(&out_file_path, &feature_name_underscore, &description); } } } diff --git a/src/tools/unstable-book-gen/src/stub-issue.md b/src/tools/unstable-book-gen/src/stub-issue.md index 8698fb7278f6a..f1e91b4ac172b 100644 --- a/src/tools/unstable-book-gen/src/stub-issue.md +++ b/src/tools/unstable-book-gen/src/stub-issue.md @@ -1,5 +1,7 @@ # `{name}` +{description} + The tracking issue for this feature is: [#{issue}] [#{issue}]: https://github.com/rust-lang/rust/issues/{issue} diff --git a/src/tools/unstable-book-gen/src/stub-no-issue.md b/src/tools/unstable-book-gen/src/stub-no-issue.md index 3da140633d0f7..3674d0048aeb1 100644 --- a/src/tools/unstable-book-gen/src/stub-no-issue.md +++ b/src/tools/unstable-book-gen/src/stub-no-issue.md @@ -1,5 +1,7 @@ # `{name}` +{description} + This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. ------------------------ From aa667f431710f1af461b3f3c263811ceaac603a7 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Sun, 25 May 2025 13:39:03 +0200 Subject: [PATCH 2742/4206] use the correct path to the function --- book/src/development/trait_checking.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/development/trait_checking.md b/book/src/development/trait_checking.md index 39ab44349b377..0c7e74ca69e8b 100644 --- a/book/src/development/trait_checking.md +++ b/book/src/development/trait_checking.md @@ -17,7 +17,7 @@ providing the `LateContext` (`cx`), our expression at hand, and the symbol of the trait in question: ```rust -use clippy_utils::implements_trait; +use clippy_utils::ty::implements_trait; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_span::symbol::sym; From 231e8cb34e6a2c549ffd1f0c69ff2521b0ccc3e9 Mon Sep 17 00:00:00 2001 From: jyn Date: Sat, 24 May 2025 19:59:20 -0400 Subject: [PATCH 2743/4206] add "Compiler environment variables" section to the unstable book --- src/doc/unstable-book/src/compiler-environment-variables.md | 1 + .../RUSTC_BOOTSTRAP.md} | 2 +- .../RUSTC_OVERRIDE_VERSION_STRING.md} | 0 src/doc/unstable-book/src/compiler-flags/allow-features.md | 2 +- src/tools/unstable-book-gen/src/SUMMARY.md | 2 ++ src/tools/unstable-book-gen/src/main.rs | 5 +++++ 6 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 src/doc/unstable-book/src/compiler-environment-variables.md rename src/doc/unstable-book/src/{compiler-flags/rustc-bootstrap.md => compiler-environment-variables/RUSTC_BOOTSTRAP.md} (98%) rename src/doc/unstable-book/src/{compiler-flags/rustc-override-version-string.md => compiler-environment-variables/RUSTC_OVERRIDE_VERSION_STRING.md} (100%) diff --git a/src/doc/unstable-book/src/compiler-environment-variables.md b/src/doc/unstable-book/src/compiler-environment-variables.md new file mode 100644 index 0000000000000..db912fdf3baca --- /dev/null +++ b/src/doc/unstable-book/src/compiler-environment-variables.md @@ -0,0 +1 @@ +# Compiler environment variables diff --git a/src/doc/unstable-book/src/compiler-flags/rustc-bootstrap.md b/src/doc/unstable-book/src/compiler-environment-variables/RUSTC_BOOTSTRAP.md similarity index 98% rename from src/doc/unstable-book/src/compiler-flags/rustc-bootstrap.md rename to src/doc/unstable-book/src/compiler-environment-variables/RUSTC_BOOTSTRAP.md index 1520b86341b2c..fed28a3326696 100644 --- a/src/doc/unstable-book/src/compiler-flags/rustc-bootstrap.md +++ b/src/doc/unstable-book/src/compiler-environment-variables/RUSTC_BOOTSTRAP.md @@ -14,7 +14,7 @@ Cargo disallows setting `cargo::rustc-env=RUSTC_BOOTSTRAP` in build scripts. Build systems can limit the features they enable with [`-Z allow-features=feature1,feature2`][Z-allow-features]. Crates can fully opt out of unstable features by using [`#![forbid(unstable_features)]`][unstable-features] at the crate root (or any other way of enabling lints, such as `-F unstable-features`). -[Z-allow-features]: ./allow-features.html +[Z-allow-features]: ../compiler-flags/allow-features.html [unstable-features]: ../../rustc/lints/listing/allowed-by-default.html#unstable-features ## Why does this environment variable exist? diff --git a/src/doc/unstable-book/src/compiler-flags/rustc-override-version-string.md b/src/doc/unstable-book/src/compiler-environment-variables/RUSTC_OVERRIDE_VERSION_STRING.md similarity index 100% rename from src/doc/unstable-book/src/compiler-flags/rustc-override-version-string.md rename to src/doc/unstable-book/src/compiler-environment-variables/RUSTC_OVERRIDE_VERSION_STRING.md diff --git a/src/doc/unstable-book/src/compiler-flags/allow-features.md b/src/doc/unstable-book/src/compiler-flags/allow-features.md index 84fa465c89b4b..49a41a8c5a310 100644 --- a/src/doc/unstable-book/src/compiler-flags/allow-features.md +++ b/src/doc/unstable-book/src/compiler-flags/allow-features.md @@ -11,4 +11,4 @@ Features are comma-separated, for example `-Z allow-features=ffi_pure,f16`. If the flag is present, any feature listed will be allowed and any feature not listed will be disallowed. Any unrecognized feature is ignored. -[`RUSTC_BOOTSTRAP`]: ./rustc-bootstrap.html +[`RUSTC_BOOTSTRAP`]: ../compiler-environment-variables/RUSTC_BOOTSTRAP.html diff --git a/src/tools/unstable-book-gen/src/SUMMARY.md b/src/tools/unstable-book-gen/src/SUMMARY.md index 933c928e2f090..fd4ea1dada621 100644 --- a/src/tools/unstable-book-gen/src/SUMMARY.md +++ b/src/tools/unstable-book-gen/src/SUMMARY.md @@ -1,5 +1,7 @@ [The Unstable Book](the-unstable-book.md) +- [Compiler environment variables](compiler-environment-variables.md) +{compiler_env_vars} - [Compiler flags](compiler-flags.md) {compiler_flags} - [Language features](language-features.md) diff --git a/src/tools/unstable-book-gen/src/main.rs b/src/tools/unstable-book-gen/src/main.rs index 6cbdc83d5b5ff..b9a2d313182fd 100644 --- a/src/tools/unstable-book-gen/src/main.rs +++ b/src/tools/unstable-book-gen/src/main.rs @@ -30,8 +30,12 @@ fn set_to_summary_str(set: &BTreeSet, dir: &str) -> String { fn generate_summary(path: &Path, lang_features: &Features, lib_features: &Features) { let compiler_flags = collect_unstable_book_section_file_names(&path.join("src/compiler-flags")); + let compiler_env_vars = + collect_unstable_book_section_file_names(&path.join("src/compiler-environment-variables")); let compiler_flags_str = set_to_summary_str(&compiler_flags, "compiler-flags"); + let compiler_env_vars_str = + set_to_summary_str(&compiler_env_vars, "compiler-environment-variables"); let unstable_lang_features = collect_unstable_feature_names(&lang_features); let unstable_lib_features = collect_unstable_feature_names(&lib_features); @@ -42,6 +46,7 @@ fn generate_summary(path: &Path, lang_features: &Features, lib_features: &Featur let summary_path = path.join("src/SUMMARY.md"); let content = format!( include_str!("SUMMARY.md"), + compiler_env_vars = compiler_env_vars_str, compiler_flags = compiler_flags_str, language_features = lang_features_str, library_features = lib_features_str From 5f857a9871240efe6e15ca94dd03e06b90c6413d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 9 May 2025 15:40:56 +0200 Subject: [PATCH 2744/4206] Rename `clean::Enum::variants` method into `non_stripped_variants` --- src/librustdoc/clean/types.rs | 2 +- src/librustdoc/html/render/print_item.rs | 2 +- src/librustdoc/html/render/sidebar.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 07ecd98f77596..f353ad5cf917e 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2107,7 +2107,7 @@ impl Enum { self.variants.iter().any(|f| f.is_stripped()) } - pub(crate) fn variants(&self) -> impl Iterator { + pub(crate) fn non_stripped_variants(&self) -> impl Iterator { self.variants.iter().filter(|v| !v.is_stripped()) } } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 39a631b637bd4..552e67c9f53d9 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1535,7 +1535,7 @@ fn print_tuple_struct_fields(cx: &Context<'_>, s: &[clean::Item]) -> impl Displa fn item_enum(cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) -> impl fmt::Display { fmt::from_fn(|w| { - let count_variants = e.variants().count(); + let count_variants = e.non_stripped_variants().count(); wrap_item(w, |w| { render_attributes_in_code(w, it, cx); write!( diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index 361966325fb3c..91540e06e3398 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -599,7 +599,7 @@ fn sidebar_enum<'a>( deref_id_map: &'a DefIdMap, ) { let mut variants = e - .variants() + .non_stripped_variants() .filter_map(|v| v.name) .map(|name| Link::new(format!("variant.{name}"), name.to_string())) .collect::>(); From 560aec13ba62c1a8fd7b2f9fbeada61096809613 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 9 May 2025 17:10:38 +0200 Subject: [PATCH 2745/4206] Unify rendering of type aliases without ADT items --- src/librustdoc/clean/types.rs | 13 + src/librustdoc/html/render/print_item.rs | 268 +++++++++--------- src/librustdoc/html/templates/item_union.html | 7 +- 3 files changed, 151 insertions(+), 137 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index f353ad5cf917e..98d57494dbe68 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -610,6 +610,9 @@ impl Item { UnionItem(ref union_) => Some(union_.has_stripped_entries()), EnumItem(ref enum_) => Some(enum_.has_stripped_entries()), VariantItem(ref v) => v.has_stripped_entries(), + TypeAliasItem(ref type_alias) => { + type_alias.inner_type.as_ref().and_then(|t| t.has_stripped_entries()) + } _ => None, } } @@ -2345,6 +2348,16 @@ pub(crate) enum TypeAliasInnerType { Struct { ctor_kind: Option, fields: Vec }, } +impl TypeAliasInnerType { + fn has_stripped_entries(&self) -> Option { + Some(match self { + Self::Enum { variants, .. } => variants.iter().any(|v| v.is_stripped()), + Self::Union { fields } => fields.iter().any(|f| f.is_stripped()), + Self::Struct { fields, .. } => fields.iter().any(|f| f.is_stripped()), + }) + } +} + #[derive(Clone, Debug)] pub(crate) struct TypeAlias { pub(crate) type_: Type, diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 552e67c9f53d9..616d89bca6a73 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1278,94 +1278,40 @@ fn item_type_alias(cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) -> match inner_type { clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive } => { - let variants_iter = || variants.iter().filter(|i| !i.is_stripped()); let ty = cx.tcx().type_of(it.def_id().unwrap()).instantiate_identity(); let enum_def_id = ty.ty_adt_def().unwrap().did(); - wrap_item(w, |w| { - let variants_len = variants.len(); - let variants_count = variants_iter().count(); - let has_stripped_entries = variants_len != variants_count; - - write!( - w, - "enum {}{}{}", - it.name.unwrap(), - t.generics.print(cx), - render_enum_fields( - cx, - Some(&t.generics), - variants, - variants_count, - has_stripped_entries, - *is_non_exhaustive, - enum_def_id, - ) - ) - })?; - write!(w, "{}", item_variants(cx, it, variants, enum_def_id))?; + DisplayEnum { + variants, + generics: &t.generics, + is_non_exhaustive: *is_non_exhaustive, + def_id: enum_def_id, + } + .render_into(cx, it, false, w)?; } clean::TypeAliasInnerType::Union { fields } => { - wrap_item(w, |w| { - let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); - let has_stripped_fields = fields.len() != fields_count; - - write!( - w, - "union {}{}{}", - it.name.unwrap(), - t.generics.print(cx), - render_struct_fields( - Some(&t.generics), - None, - fields, - "", - true, - has_stripped_fields, - cx, - ), - ) - })?; - write!(w, "{}", item_fields(cx, it, fields, None))?; + ItemUnion { cx, it, fields, generics: &t.generics, document_union: false } + .render_into(w)?; } clean::TypeAliasInnerType::Struct { ctor_kind, fields } => { - wrap_item(w, |w| { - let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); - let has_stripped_fields = fields.len() != fields_count; - - write!( - w, - "struct {}{}{}", - it.name.unwrap(), - t.generics.print(cx), - render_struct_fields( - Some(&t.generics), - *ctor_kind, - fields, - "", - true, - has_stripped_fields, - cx, - ), - ) - })?; - write!(w, "{}", item_fields(cx, it, fields, None))?; + DisplayStruct { ctor_kind: *ctor_kind, generics: &t.generics, fields } + .render_into(cx, it, false, w)?; } } + } else { + let def_id = it.item_id.expect_def_id(); + // Render any items associated directly to this alias, as otherwise they + // won't be visible anywhere in the docs. It would be nice to also show + // associated items from the aliased type (see discussion in #32077), but + // we need #14072 to make sense of the generics. + write!( + w, + "{}{}", + render_assoc_items(cx, it, def_id, AssocItemRender::All), + document_type_layout(cx, def_id) + )?; } - let def_id = it.item_id.expect_def_id(); - // Render any items associated directly to this alias, as otherwise they - // won't be visible anywhere in the docs. It would be nice to also show - // associated items from the aliased type (see discussion in #32077), but - // we need #14072 to make sense of the generics. - write!( - w, - "{}{}", - render_assoc_items(cx, it, def_id, AssocItemRender::All), - document_type_layout(cx, def_id) - )?; - // [RUSTDOCIMPL] type.impl // // Include type definitions from the alias target type. @@ -1463,50 +1409,53 @@ fn item_type_alias(cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) -> }) } -fn item_union(cx: &Context<'_>, it: &clean::Item, s: &clean::Union) -> impl fmt::Display { - item_template!( - #[template(path = "item_union.html")] - struct ItemUnion<'a, 'cx> { - cx: &'a Context<'cx>, - it: &'a clean::Item, - s: &'a clean::Union, - }, - methods = [document, document_type_layout, render_attributes_in_pre, render_assoc_items] - ); - - impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { - fn render_union(&self) -> impl Display { - render_union(self.it, Some(&self.s.generics), &self.s.fields, self.cx) - } +item_template!( + #[template(path = "item_union.html")] + struct ItemUnion<'a, 'cx> { + cx: &'a Context<'cx>, + it: &'a clean::Item, + fields: &'a [clean::Item], + generics: &'a clean::Generics, + document_union: bool, + }, + methods = [document, document_type_layout, render_attributes_in_pre, render_assoc_items] +); + +impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { + fn render_union(&self) -> impl Display { + render_union(self.it, Some(&self.generics), &self.fields, self.cx) + } - fn document_field(&self, field: &'a clean::Item) -> impl Display { - document(self.cx, field, Some(self.it), HeadingOffset::H3) - } + fn document_field(&self, field: &'a clean::Item) -> impl Display { + document(self.cx, field, Some(self.it), HeadingOffset::H3) + } - fn stability_field(&self, field: &clean::Item) -> Option { - field.stability_class(self.cx.tcx()) - } + fn stability_field(&self, field: &clean::Item) -> Option { + field.stability_class(self.cx.tcx()) + } - fn print_ty(&self, ty: &'a clean::Type) -> impl Display { - ty.print(self.cx) - } + fn print_ty(&self, ty: &'a clean::Type) -> impl Display { + ty.print(self.cx) + } - fn fields_iter( - &self, - ) -> iter::Peekable> { - self.s - .fields - .iter() - .filter_map(|f| match f.kind { - clean::StructFieldItem(ref ty) => Some((f, ty)), - _ => None, - }) - .peekable() - } + fn fields_iter( + &self, + ) -> iter::Peekable> { + self.fields + .iter() + .filter_map(|f| match f.kind { + clean::StructFieldItem(ref ty) => Some((f, ty)), + _ => None, + }) + .peekable() } +} +fn item_union(cx: &Context<'_>, it: &clean::Item, s: &clean::Union) -> impl fmt::Display { fmt::from_fn(|w| { - ItemUnion { cx, it, s }.render_into(w).unwrap(); + ItemUnion { cx, it, fields: &s.fields, generics: &s.generics, document_union: true } + .render_into(w) + .unwrap(); Ok(()) }) } @@ -1533,9 +1482,25 @@ fn print_tuple_struct_fields(cx: &Context<'_>, s: &[clean::Item]) -> impl Displa }) } -fn item_enum(cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) -> impl fmt::Display { - fmt::from_fn(|w| { - let count_variants = e.non_stripped_variants().count(); +struct DisplayEnum<'a> { + variants: &'a IndexVec, + generics: &'a clean::Generics, + is_non_exhaustive: bool, + def_id: DefId, +} + +impl<'a> DisplayEnum<'a> { + fn render_into( + self, + cx: &Context<'_>, + it: &clean::Item, + document_enum: bool, + w: &mut W, + ) -> fmt::Result { + let variants_count = self.variants.iter().filter(|i| !i.is_stripped()).count(); + let variants_len = self.variants.len(); + let has_stripped_entries = variants_len != variants_count; + wrap_item(w, |w| { render_attributes_in_code(w, it, cx); write!( @@ -1543,23 +1508,25 @@ fn item_enum(cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) -> impl fmt::D "{}enum {}{}{}", visibility_print_with_space(it, cx), it.name.unwrap(), - e.generics.print(cx), + self.generics.print(cx), render_enum_fields( cx, - Some(&e.generics), - &e.variants, - count_variants, - e.has_stripped_entries(), - it.is_non_exhaustive(), - it.def_id().unwrap(), + Some(self.generics), + self.variants, + variants_count, + has_stripped_entries, + self.is_non_exhaustive, + self.def_id, ), ) })?; - write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?; + if document_enum { + write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?; + } - if count_variants != 0 { - write!(w, "{}", item_variants(cx, it, &e.variants, it.def_id().unwrap()))?; + if variants_count != 0 { + write!(w, "{}", item_variants(cx, it, self.variants, self.def_id))?; } let def_id = it.item_id.expect_def_id(); write!( @@ -1568,6 +1535,18 @@ fn item_enum(cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) -> impl fmt::D render_assoc_items(cx, it, def_id, AssocItemRender::All), document_type_layout(cx, def_id) ) + } +} + +fn item_enum(cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) -> impl fmt::Display { + fmt::from_fn(|w| { + DisplayEnum { + variants: &e.variants, + generics: &e.generics, + is_non_exhaustive: it.is_non_exhaustive(), + def_id: it.def_id().unwrap(), + } + .render_into(cx, it, true, w) }) } @@ -1955,27 +1934,48 @@ fn item_constant( }) } -fn item_struct(cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) -> impl fmt::Display { - fmt::from_fn(|w| { +struct DisplayStruct<'a> { + ctor_kind: Option, + generics: &'a clean::Generics, + fields: &'a [clean::Item], +} + +impl<'a> DisplayStruct<'a> { + fn render_into( + self, + cx: &Context<'_>, + it: &clean::Item, + document_struct: bool, + w: &mut W, + ) -> fmt::Result { wrap_item(w, |w| { render_attributes_in_code(w, it, cx); write!( w, "{}", - render_struct(it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx) + render_struct(it, Some(self.generics), self.ctor_kind, self.fields, "", true, cx) ) })?; - let def_id = it.item_id.expect_def_id(); + if document_struct { + write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?; + } + let def_id = it.item_id.expect_def_id(); write!( w, - "{}{}{}{}", - document(cx, it, None, HeadingOffset::H2), - item_fields(cx, it, &s.fields, s.ctor_kind), + "{}{}{}", + item_fields(cx, it, self.fields, self.ctor_kind), render_assoc_items(cx, it, def_id, AssocItemRender::All), document_type_layout(cx, def_id), ) + } +} + +fn item_struct(cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) -> impl fmt::Display { + fmt::from_fn(|w| { + DisplayStruct { ctor_kind: s.ctor_kind, generics: &s.generics, fields: s.fields.as_slice() } + .render_into(cx, it, true, w) }) } diff --git a/src/librustdoc/html/templates/item_union.html b/src/librustdoc/html/templates/item_union.html index b1c1d5a63a03c..f3780fb4c5baa 100644 --- a/src/librustdoc/html/templates/item_union.html +++ b/src/librustdoc/html/templates/item_union.html @@ -2,15 +2,16 @@ {{ self.render_attributes_in_pre()|safe }} {{ self.render_union()|safe }}
-{{ self.document()|safe }} +{% if self.document_union %} + {{ self.document()|safe }} +{% endif %} {% if self.fields_iter().peek().is_some() %}

{# #} Fields§ {# #}

{% for (field, ty) in self.fields_iter() %} {% let name = field.name.expect("union field name") %} - {# #} + {# #} § {# #} {{ name }}: {{+ self.print_ty(ty)|safe }} {# #} From 4194745687ead479898587b85f1388635b3422e2 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 9 May 2025 17:36:32 +0200 Subject: [PATCH 2746/4206] Split `Item::attributes` method into three --- src/librustdoc/clean/types.rs | 145 ++++++++++++++++------------- src/librustdoc/html/render/mod.rs | 4 +- src/librustdoc/json/conversions.rs | 2 +- 3 files changed, 81 insertions(+), 70 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 98d57494dbe68..1766627ce392c 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -764,14 +764,11 @@ impl Item { Some(tcx.visibility(def_id)) } - pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Vec { + pub(crate) fn attributes_witout_repr(&self, tcx: TyCtxt<'_>, is_json: bool) -> Vec { const ALLOWED_ATTRIBUTES: &[Symbol] = &[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive]; - use rustc_abi::IntegerType; - - let mut attrs: Vec = self - .attrs + self.attrs .other_attrs .iter() .filter_map(|attr| { @@ -799,74 +796,88 @@ impl Item { None } }) - .collect(); + .collect() + } - // Add #[repr(...)] - if let Some(def_id) = self.def_id() - && let ItemType::Struct | ItemType::Enum | ItemType::Union = self.type_() - { - let adt = tcx.adt_def(def_id); - let repr = adt.repr(); - let mut out = Vec::new(); - if repr.c() { - out.push("C"); - } - if repr.transparent() { - // Render `repr(transparent)` iff the non-1-ZST field is public or at least one - // field is public in case all fields are 1-ZST fields. - let render_transparent = is_json - || cache.document_private - || adt - .all_fields() - .find(|field| { - let ty = - field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did)); - tcx.layout_of( - ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty), - ) - .is_ok_and(|layout| !layout.is_1zst()) - }) - .map_or_else( - || adt.all_fields().any(|field| field.vis.is_public()), - |field| field.vis.is_public(), - ); + pub(crate) fn attributes_and_repr( + &self, + tcx: TyCtxt<'_>, + cache: &Cache, + is_json: bool, + ) -> Vec { + let mut attrs = self.attributes_witout_repr(tcx, is_json); - if render_transparent { - out.push("transparent"); - } - } - if repr.simd() { - out.push("simd"); - } - let pack_s; - if let Some(pack) = repr.pack { - pack_s = format!("packed({})", pack.bytes()); - out.push(&pack_s); - } - let align_s; - if let Some(align) = repr.align { - align_s = format!("align({})", align.bytes()); - out.push(&align_s); - } - let int_s; - if let Some(int) = repr.int { - int_s = match int { - IntegerType::Pointer(is_signed) => { - format!("{}size", if is_signed { 'i' } else { 'u' }) - } - IntegerType::Fixed(size, is_signed) => { - format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8) - } - }; - out.push(&int_s); - } - if !out.is_empty() { - attrs.push(format!("#[repr({})]", out.join(", "))); - } + if let Some(repr_attr) = self.repr(tcx, cache) { + attrs.push(repr_attr); } attrs } + /// Returns a `#[repr(...)]` representation. + pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Option { + use rustc_abi::IntegerType; + + let def_id = self.def_id()?; + if !matches!(self.type_(), ItemType::Struct | ItemType::Enum | ItemType::Union) { + return None; + } + let adt = tcx.adt_def(def_id); + let repr = adt.repr(); + let mut out = Vec::new(); + if repr.c() { + out.push("C"); + } + if repr.transparent() { + // Render `repr(transparent)` iff the non-1-ZST field is public or at least one + // field is public in case all fields are 1-ZST fields. + let render_transparent = is_json + || cache.document_private + || adt + .all_fields() + .find(|field| { + let ty = field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did)); + tcx.layout_of( + ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty), + ) + .is_ok_and(|layout| !layout.is_1zst()) + }) + .map_or_else( + || adt.all_fields().any(|field| field.vis.is_public()), + |field| field.vis.is_public(), + ); + + if render_transparent { + out.push("transparent"); + } + } + if repr.simd() { + out.push("simd"); + } + let pack_s; + if let Some(pack) = repr.pack { + pack_s = format!("packed({})", pack.bytes()); + out.push(&pack_s); + } + let align_s; + if let Some(align) = repr.align { + align_s = format!("align({})", align.bytes()); + out.push(&align_s); + } + let int_s; + if let Some(int) = repr.int { + int_s = match int { + IntegerType::Pointer(is_signed) => { + format!("{}size", if is_signed { 'i' } else { 'u' }) + } + IntegerType::Fixed(size, is_signed) => { + format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8) + } + }; + out.push(&int_s); + } + if !out.is_empty() { Some(format!("#[repr({})]", out.join(", "))) } else { None } + } + pub fn is_doc_hidden(&self) -> bool { self.attrs.is_doc_hidden() } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 06cb9269cc87f..6b4fd3cd834a9 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1194,7 +1194,7 @@ fn render_assoc_item( // a whitespace prefix and newline. fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) -> impl fmt::Display { fmt::from_fn(move |f| { - for a in it.attributes(cx.tcx(), cx.cache(), false) { + for a in it.attributes_and_repr(cx.tcx(), cx.cache(), false) { writeln!(f, "{prefix}{a}")?; } Ok(()) @@ -1204,7 +1204,7 @@ fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) -> // When an attribute is rendered inside a tag, it is formatted using // a div to produce a newline after it. fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Context<'_>) { - for attr in it.attributes(cx.tcx(), cx.cache(), false) { + for attr in it.attributes_and_repr(cx.tcx(), cx.cache(), false) { write!(w, "
{attr}
").unwrap(); } } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 705f9b2202c60..bfcb794b89a27 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -40,7 +40,7 @@ impl JsonRenderer<'_> { }) .collect(); let docs = item.opt_doc_value(); - let attrs = item.attributes(self.tcx, self.cache(), true); + let attrs = item.attributes_and_repr(self.tcx, self.cache(), true); let span = item.span(self.tcx); let visibility = item.visibility(self.tcx); let clean::ItemInner { name, item_id, .. } = *item.inner; From eb9f05481be266598527ba9b5eb890cc56555733 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 9 May 2025 17:44:24 +0200 Subject: [PATCH 2747/4206] Rename the `document_*` argument/field into `is_type_alias` --- src/librustdoc/html/render/print_item.rs | 22 +++++++++---------- src/librustdoc/html/templates/item_union.html | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 616d89bca6a73..692e11b2689e3 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1287,15 +1287,15 @@ fn item_type_alias(cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) -> is_non_exhaustive: *is_non_exhaustive, def_id: enum_def_id, } - .render_into(cx, it, false, w)?; + .render_into(cx, it, true, w)?; } clean::TypeAliasInnerType::Union { fields } => { - ItemUnion { cx, it, fields, generics: &t.generics, document_union: false } + ItemUnion { cx, it, fields, generics: &t.generics, is_type_alias: true } .render_into(w)?; } clean::TypeAliasInnerType::Struct { ctor_kind, fields } => { DisplayStruct { ctor_kind: *ctor_kind, generics: &t.generics, fields } - .render_into(cx, it, false, w)?; + .render_into(cx, it, true, w)?; } } } else { @@ -1416,7 +1416,7 @@ item_template!( it: &'a clean::Item, fields: &'a [clean::Item], generics: &'a clean::Generics, - document_union: bool, + is_type_alias: bool, }, methods = [document, document_type_layout, render_attributes_in_pre, render_assoc_items] ); @@ -1453,7 +1453,7 @@ impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { fn item_union(cx: &Context<'_>, it: &clean::Item, s: &clean::Union) -> impl fmt::Display { fmt::from_fn(|w| { - ItemUnion { cx, it, fields: &s.fields, generics: &s.generics, document_union: true } + ItemUnion { cx, it, fields: &s.fields, generics: &s.generics, is_type_alias: false } .render_into(w) .unwrap(); Ok(()) @@ -1494,7 +1494,7 @@ impl<'a> DisplayEnum<'a> { self, cx: &Context<'_>, it: &clean::Item, - document_enum: bool, + is_type_alias: bool, w: &mut W, ) -> fmt::Result { let variants_count = self.variants.iter().filter(|i| !i.is_stripped()).count(); @@ -1521,7 +1521,7 @@ impl<'a> DisplayEnum<'a> { ) })?; - if document_enum { + if !is_type_alias { write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?; } @@ -1546,7 +1546,7 @@ fn item_enum(cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) -> impl fmt::D is_non_exhaustive: it.is_non_exhaustive(), def_id: it.def_id().unwrap(), } - .render_into(cx, it, true, w) + .render_into(cx, it, false, w) }) } @@ -1945,7 +1945,7 @@ impl<'a> DisplayStruct<'a> { self, cx: &Context<'_>, it: &clean::Item, - document_struct: bool, + is_type_alias: bool, w: &mut W, ) -> fmt::Result { wrap_item(w, |w| { @@ -1957,7 +1957,7 @@ impl<'a> DisplayStruct<'a> { ) })?; - if document_struct { + if !is_type_alias { write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?; } @@ -1975,7 +1975,7 @@ impl<'a> DisplayStruct<'a> { fn item_struct(cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) -> impl fmt::Display { fmt::from_fn(|w| { DisplayStruct { ctor_kind: s.ctor_kind, generics: &s.generics, fields: s.fields.as_slice() } - .render_into(cx, it, true, w) + .render_into(cx, it, false, w) }) } diff --git a/src/librustdoc/html/templates/item_union.html b/src/librustdoc/html/templates/item_union.html index f3780fb4c5baa..99a9bc874dd59 100644 --- a/src/librustdoc/html/templates/item_union.html +++ b/src/librustdoc/html/templates/item_union.html @@ -2,7 +2,7 @@ {{ self.render_attributes_in_pre()|safe }} {{ self.render_union()|safe }}